refactor: remove intervene_soft/hard dispatch actions, simplify to new_chat and continue
linuztx committed
Mar 15, 2026 at 23:21 UTC
3868c85aee1f62d16054c149732ac9afa67d92e4
4 files changed
+18
-57
plugins/_email_integration/helpers/dispatcher.py
+1
-3
@@ -24,7 +24,7 @@ CTX_EMAIL_ATTACHMENTS = "_email_response_attachments"
24
25
BODY_PREVIEW_MAX_CHARS: int = 2000
26
27
-DispatchAction = Literal["new_chat", "continue_chat", "intervene_soft", "intervene_hard"]
27
+DispatchAction = Literal["new_chat", "continue_chat"]
28
29
30
@dataclass
@@ -96,8 +96,6 @@ def parse_dispatcher_response(response: str) -> DispatchDecision:
96
action_map: dict[str, DispatchAction] = {
97
"NEW_CHAT": "new_chat",
98
"CONTINUE": "continue_chat",
99
- "INTERVENE_SOFT": "intervene_soft",
100
- "INTERVENE_HARD": "intervene_hard",
99
}
100
action = action_map.get(action_raw, "new_chat")
101
return DispatchDecision(action=action, context_id=ctx_id, reason=reason)
plugins/_email_integration/helpers/handler.py
+17
-45
@@ -152,28 +152,23 @@ async def _dispatch_message(agent: Agent, handler_cfg: dict, msg: InboundMessage
152
for chat in existing:
153
if chat["thread_id"] == thread_id:
154
await _route_to_chat(
155
- agent, handler_cfg, msg, chat["context_id"], "continue_chat",
155
+ agent, handler_cfg, msg, chat["context_id"],
156
)
157
return
158
159
# Dispatcher AI decides
160
decision = await _call_dispatcher(agent, handler_cfg, msg, existing)
161
162
- if decision.action == "new_chat":
163
- await _start_new_chat(agent, handler_cfg, msg)
164
- elif decision.action in ("continue_chat", "intervene_soft", "intervene_hard"):
162
+ if decision.action == "continue_chat" and decision.context_id:
163
ctx = AgentContext.get(decision.context_id)
166
- if not ctx:
167
- PrintStyle.warning(
168
- f"Dispatcher referenced unknown context {decision.context_id}, starting new chat"
169
- )
170
- await _start_new_chat(agent, handler_cfg, msg)
171
- else:
172
- await _route_to_chat(
173
- agent, handler_cfg, msg, decision.context_id, decision.action,
174
- )
175
- else:
176
- await _start_new_chat(agent, handler_cfg, msg)
164
+ if ctx:
165
+ await _route_to_chat(agent, handler_cfg, msg, decision.context_id)
166
+ return
167
+ PrintStyle.warning(
168
+ f"Dispatcher referenced unknown context {decision.context_id}, starting new chat"
169
+ )
170
+
171
+ await _start_new_chat(agent, handler_cfg, msg)
172
173
174
async def _call_dispatcher(
@@ -253,7 +248,6 @@ async def _route_to_chat(
248
handler_cfg: dict,
249
msg: InboundMessage,
250
context_id: str,
256
- action: disp.DispatchAction,
251
):
252
context = AgentContext.get(context_id)
253
if not context:
@@ -263,37 +257,15 @@ async def _route_to_chat(
257
if msg.references:
258
context.data[disp.CTX_EMAIL_REFERENCES] = msg.references
259
266
- if action == "intervene_soft":
267
- soft_msg = agent.read_prompt(
268
- "fw.email.intervene_soft.md",
269
- sender=msg.sender,
270
- subject=msg.subject,
271
- body=msg.body,
272
- )
273
- mq.add(context, soft_msg, msg.attachments)
274
- PrintStyle.info(f"Email: queued soft intervention for chat {context_id}")
275
-
276
- elif action == "intervene_hard":
277
- user_msg = _build_user_message(agent, msg, handler_cfg)
278
- system_ctx = agent.read_prompt("fw.email.system_context.md")
279
- mq.log_user_message(context, user_msg, msg.attachments or [], source=" (email)")
280
- context.communicate(UserMessage(
281
- message=user_msg,
282
- system_message=[system_ctx],
283
- attachments=msg.attachments,
284
- ))
285
- PrintStyle.info(f"Email: hard intervention on chat {context_id}")
286
-
287
- else:
288
- user_msg = _build_user_message(agent, msg, handler_cfg)
289
- mq.log_user_message(context, user_msg, msg.attachments or [], source=" (email)")
290
- context.communicate(UserMessage(
291
- message=user_msg,
292
- attachments=msg.attachments,
293
- ))
294
- PrintStyle.info(f"Email: continuing chat {context_id}")
260
+ user_msg = _build_user_message(agent, msg, handler_cfg)
261
+ mq.log_user_message(context, user_msg, msg.attachments or [], source=" (email)")
262
+ context.communicate(UserMessage(
263
+ message=user_msg,
264
+ attachments=msg.attachments,
265
+ ))
266
267
save_tmp_chat(context)
268
+ PrintStyle.info(f"Email: continuing chat {context_id}")
269
270
271
# ------------------------------------------------------------------
plugins/_email_integration/prompts/fw.email.dispatcher_system.md
-4
@@ -3,8 +3,6 @@ You receive: the new email (sender, subject, body) and a list of existing chats
3
4
Rules:
5
- If the email content clearly relates to an existing chat (same topic, same sender), reply with CONTINUE and that chat's context_id
6
-- If the email is a status question or low-priority follow-up on a running chat, reply with INTERVENE_SOFT and the context_id — the agent will receive it after current step
7
-- If the email is urgent and requires immediate attention on a running chat, reply with INTERVENE_HARD and the context_id
6
- Otherwise reply with NEW_CHAT
7
8
Use conversation history to determine topic relevance when matching emails to chats.
@@ -15,5 +13,3 @@ ACTION context_id reason
13
Examples:
14
NEW_CHAT _ new request from user
15
CONTINUE ctx_abc123 same sender discussing AWS deployment
18
-INTERVENE_SOFT ctx_abc123 user asking for status update
19
-INTERVENE_HARD ctx_abc123 urgent correction needed
plugins/_email_integration/prompts/fw.email.intervene_soft.md
deleted
-5
@@ -1,5 +0,0 @@
1
-[Email from {{sender}}] user following up, respond and continue current work
2
-
3
-Subject: {{subject}}
4
-
5
-{{body}}