Add active-turn steering (#3394)

* feat(agents): add active-turn steering

Let users choose whether an immediate prompt interrupts or joins the active turn. The daemon owns exact-turn admission, provider delivery, safe fallback, and canonical timeline identity while queueing remains client-side.

* fix(agents): stabilize steering history and replay QA

* fix(agents): preserve steering timeline order

* fix(agents): reconcile resumed provider history

* fix(agents): serialize steering with cancellation

* test(agents): prove Claude multi-tool steering

* test(agents): force explicit history hydration

* fix(agents): flush output before steer admission
This commit is contained in:
Mohamed Boudra
2026-08-16 13:58:40 +02:00
committed by GitHub
parent 16120ebff1
commit 42245d139a
69 changed files with 5203 additions and 269 deletions
+4
View File
@@ -97,6 +97,7 @@ export const ar: TranslationResources = {
interruptAgent: "عامل المقاطعة",
queueMessage: "رسالة قائمة الانتظار",
sendAndInterrupt: "إرسال ومقاطعة",
sendAndSteer: "إرسال وتوجيه",
sendMessage: "أرسل رسالة",
queue: "طابور",
send: "يرسل",
@@ -1826,10 +1827,13 @@ export const ar: TranslationResources = {
descriptions: {
interrupt:
"عند تشغيل الوكيل، يوقف Enter التشغيل. Command/Ctrl+Enter يضيف إلى قائمة الانتظار.",
steer:
"عند تشغيل الوكيل، يوجّه Enter الجولة النشطة. يضيف Command/Ctrl+Enter إلى قائمة الانتظار.",
queue: "عند تشغيل الوكيل، يضيف Enter إلى قائمة الانتظار. Command/Ctrl+Enter يرسل.",
},
options: {
interrupt: "مقاطعة",
steer: "توجيه",
queue: "طابور",
},
},
+4
View File
@@ -94,6 +94,7 @@ export const en = {
interruptAgent: "Interrupt agent",
queueMessage: "Queue message",
sendAndInterrupt: "Send and interrupt",
sendAndSteer: "Send and steer",
sendMessage: "Send message",
queue: "Queue",
send: "Send",
@@ -1890,10 +1891,13 @@ export const en = {
label: "Default send",
descriptions: {
interrupt: "When the agent is running, Enter interrupts. Command/Ctrl+Enter queues.",
steer:
"When the agent is running, Enter steers the active turn. Command/Ctrl+Enter queues.",
queue: "When the agent is running, Enter queues. Command/Ctrl+Enter submits.",
},
options: {
interrupt: "Interrupt",
steer: "Steer",
queue: "Queue",
},
},
+4
View File
@@ -97,6 +97,7 @@ export const es: TranslationResources = {
interruptAgent: "agente de interrupción",
queueMessage: "mensaje de cola",
sendAndInterrupt: "Enviar e interrumpir",
sendAndSteer: "Enviar y orientar",
sendMessage: "enviar mensaje",
queue: "Cola",
send: "Enviar",
@@ -1871,11 +1872,14 @@ export const es: TranslationResources = {
descriptions: {
interrupt:
"Cuando el agente se está ejecutando, Enter interrumpe. Command/Ctrl+Enter pone en cola.",
steer:
"Cuando el agente se está ejecutando, Enter dirige el turno activo. Command/Ctrl+Enter pone en cola.",
queue:
"Cuando el agente se está ejecutando, Enter pone en cola. Command/Ctrl+Enter envía.",
},
options: {
interrupt: "Interrumpir",
steer: "Dirigir",
queue: "Cola",
},
},
+4
View File
@@ -99,6 +99,7 @@ export const fr: TranslationResources = {
interruptAgent: "Agent d'interruption",
queueMessage: "Message de file d'attente",
sendAndInterrupt: "Envoyer et interrompre",
sendAndSteer: "Envoyer et guider",
sendMessage: "Envoyer un message",
queue: "File d'attente",
send: "Envoyer",
@@ -1874,11 +1875,14 @@ export const fr: TranslationResources = {
descriptions: {
interrupt:
"Lorsque l'agent est en cours d'exécution, Entrée interrompt. Commande/Ctrl+Entrée met en file d'attente.",
steer:
"Lorsque l’agent est en cours d’exécution, Entrée oriente le tour actif. Commande/Ctrl+Entrée met en file d’attente.",
queue:
"Lorsque l'agent est en cours d'exécution, Entrée met en file d'attente. Commande/Ctrl+Entrée envoie.",
},
options: {
interrupt: "Interrompre",
steer: "Orienter",
queue: "File d'attente",
},
},
+4
View File
@@ -97,6 +97,7 @@ export const ja: TranslationResources = {
interruptAgent: "エージェントを中断",
queueMessage: "メッセージをキューに追加",
sendAndInterrupt: "送信して中断",
sendAndSteer: "送信して指示を追加",
sendMessage: "メッセージを送信",
queue: "キュー",
send: "送信",
@@ -1841,10 +1842,13 @@ export const ja: TranslationResources = {
label: "デフォルトの送信",
descriptions: {
interrupt: "エージェント実行中、Enterで中断します。Command/Ctrl+Enterでキューに追加。",
steer:
"エージェント実行中、Enterで現在のターンに指示を送ります。Command/Ctrl+Enterでキューに追加。",
queue: "エージェント実行中、Enterでキューに追加します。Command/Ctrl+Enterで送信。",
},
options: {
interrupt: "中断",
steer: "指示",
queue: "キュー",
},
},
+4
View File
@@ -97,6 +97,7 @@ export const ko: TranslationResources = {
interruptAgent: "에이전트 중단",
queueMessage: "메시지 대기열에 추가",
sendAndInterrupt: "보내고 중단",
sendAndSteer: "보내고 지시 추가",
sendMessage: "메시지 보내기",
queue: "대기열",
send: "보내기",
@@ -1836,11 +1837,14 @@ export const ko: TranslationResources = {
descriptions: {
interrupt:
"에이전트가 실행 중일 때 Enter는 중단합니다. Command/Ctrl+Enter는 대기열에 추가합니다.",
steer:
"에이전트가 실행 중일 때 Enter는 현재 턴에 지시합니다. Command/Ctrl+Enter는 대기열에 추가합니다.",
queue:
"에이전트가 실행 중일 때 Enter는 대기열에 추가합니다. Command/Ctrl+Enter는 제출합니다.",
},
options: {
interrupt: "중단",
steer: "지시",
queue: "대기열",
},
},
+4
View File
@@ -97,6 +97,7 @@ export const ptBR: TranslationResources = {
interruptAgent: "Interromper agente",
queueMessage: "Enfileirar mensagem",
sendAndInterrupt: "Enviar e interromper",
sendAndSteer: "Enviar e orientar",
sendMessage: "Enviar mensagem",
queue: "Fila",
send: "Enviar",
@@ -1856,10 +1857,13 @@ export const ptBR: TranslationResources = {
descriptions: {
interrupt:
"Quando o agente está em execução, Enter interrompe. Command/Ctrl+Enter enfileira.",
steer:
"Quando o agente está em execução, Enter orienta o turno ativo. Command/Ctrl+Enter enfileira.",
queue: "Quando o agente está em execução, Enter enfileira. Command/Ctrl+Enter envia.",
},
options: {
interrupt: "Interromper",
steer: "Orientar",
queue: "Fila",
},
},
+4
View File
@@ -97,6 +97,7 @@ export const ru: TranslationResources = {
interruptAgent: "Агент прерываний",
queueMessage: "Сообщение в очереди",
sendAndInterrupt: "Отправить и прервать",
sendAndSteer: "Отправить и направить",
sendMessage: "Отправить сообщение",
queue: "Очередь",
send: "Отправлять",
@@ -1860,10 +1861,13 @@ export const ru: TranslationResources = {
label: "Отправка по умолчанию",
descriptions: {
interrupt: "Когда агент работает, Enter прерывает. Command/Ctrl+Enter ставит в очередь.",
steer:
"Когда агент работает, Enter направляет текущий ход. Command/Ctrl+Enter ставит в очередь.",
queue: "Когда агент работает, Enter ставит в очередь. Command/Ctrl+Enter отправляет.",
},
options: {
interrupt: "Прерывать",
steer: "Направить",
queue: "Очередь",
},
},
+3
View File
@@ -97,6 +97,7 @@ export const zhCN: TranslationResources = {
interruptAgent: "中断 Agent",
queueMessage: "消息排队",
sendAndInterrupt: "发送并中断",
sendAndSteer: "发送并引导",
sendMessage: "发送消息",
queue: "排队",
send: "发送",
@@ -1804,10 +1805,12 @@ export const zhCN: TranslationResources = {
label: "默认发送",
descriptions: {
interrupt: "Agent 运行时,Enter 会中断。Command/Ctrl+Enter 会排队。",
steer: "Agent 运行时,Enter 会引导当前回合。Command/Ctrl+Enter 会排队。",
queue: "Agent 运行时,Enter 会排队。Command/Ctrl+Enter 会提交。",
},
options: {
interrupt: "中断",
steer: "引导",
queue: "排队",
},
},