Subagents don't receive the context the planner was given
When the planner delegates, it passes the workflow YAML structurally — call_workflow_agent and call_job_code_agent in services/global_chat/subagent_caller.py pull the job body and adaptor straight out of the YAML and put them in the payload. Nothing else travels that way. Attachments are appended to the planner's own user message by _format_attachments_for_content (services/global_chat/router.py:234), and the only thing that reaches job_chat is the planner's message field, which the planner writes itself. So a user who attaches a run log and asks why the last two steps failed gets a job_chat call that either contains the planner's paraphrase of the log or nothing about it at all. We don't want LLM relaying here. The log should arrive at the subagent as the same bytes the user attached, the way the YAML does.
The same call has two other things missing. call_job_agent never sets subagent: True and never sets top-level workflow_yaml — it puts the YAML in context["workflow_yaml"], which Payload.from_dict doesn't read. So planner-invoked job_chat runs with the production scope prompt ("You ONLY help with job code… tell them to navigate to the workflow overview"), with no <workflow_structure> block and no inspect_job_code tool, while the router's direct route sets both correctly. That weakens the planner exactly where it should be strongest, and it undercuts any prompt change we make about reading other steps. Separately, because the enriched content is what gets written to history (services/job_chat/job_chat.py:485), an attached log becomes a permanent part of the conversation and is re-sent on every later turn with nothing marking it as belonging to an earlier run.
Example tests
- Planner route debug ("why did the last two steps fail?") with a log attachment. Assert the
job_chat payloads contain the log content verbatim, not a paraphrase.
- Planner-invoked
job_chat on a multi-step workflow. Assert it runs in subagent mode with inspect_job_code available, and does not tell the user to navigate to the workflow overview.
- Attach a log on turn one, then ask an unrelated question on turn two. The log should not be re-sent, and a stale log should not be described as the current run.
Possible solutions
- Pass attachments through
subagent_caller as structured payload fields, the same way the YAML is passed, so the subagent gets the original content rather than the planner's summary.
- Set
subagent: True and top-level workflow_yaml on call_job_agent payloads so the planner path matches the router path.
- Keep attachments out of persisted history and re-attach per turn, with a cap and a visible truncation note for very large logs and dataclips.
- Once attachments arrive structurally, optionally map them to
job_chat's context.log/input/output so the typed prompt blocks are used. Worth testing whether the wrapper changes anything before assuming it does.
- Align the attachment type strings in the acceptance specs with what
PAYLOAD_SPEC.md documents, so tests exercise the real payload shape.
Subagents don't receive the context the planner was given
When the planner delegates, it passes the workflow YAML structurally —
call_workflow_agentandcall_job_code_agentinservices/global_chat/subagent_caller.pypull the job body and adaptor straight out of the YAML and put them in the payload. Nothing else travels that way. Attachments are appended to the planner's own user message by_format_attachments_for_content(services/global_chat/router.py:234), and the only thing that reachesjob_chatis the planner'smessagefield, which the planner writes itself. So a user who attaches a run log and asks why the last two steps failed gets ajob_chatcall that either contains the planner's paraphrase of the log or nothing about it at all. We don't want LLM relaying here. The log should arrive at the subagent as the same bytes the user attached, the way the YAML does.The same call has two other things missing.
call_job_agentnever setssubagent: Trueand never sets top-levelworkflow_yaml— it puts the YAML incontext["workflow_yaml"], whichPayload.from_dictdoesn't read. So planner-invokedjob_chatruns with the production scope prompt ("You ONLY help with job code… tell them to navigate to the workflow overview"), with no<workflow_structure>block and noinspect_job_codetool, while the router's direct route sets both correctly. That weakens the planner exactly where it should be strongest, and it undercuts any prompt change we make about reading other steps. Separately, because the enriched content is what gets written to history (services/job_chat/job_chat.py:485), an attached log becomes a permanent part of the conversation and is re-sent on every later turn with nothing marking it as belonging to an earlier run.Example tests
job_chatpayloads contain the log content verbatim, not a paraphrase.job_chaton a multi-step workflow. Assert it runs in subagent mode withinspect_job_codeavailable, and does not tell the user to navigate to the workflow overview.Possible solutions
subagent_calleras structured payload fields, the same way the YAML is passed, so the subagent gets the original content rather than the planner's summary.subagent: Trueand top-levelworkflow_yamloncall_job_agentpayloads so the planner path matches the router path.job_chat'scontext.log/input/outputso the typed prompt blocks are used. Worth testing whether the wrapper changes anything before assuming it does.PAYLOAD_SPEC.mddocuments, so tests exercise the real payload shape.