Successful subagent completion messages bypass the completion-context token limit
What issue are you seeing?
Component and source
Codex core multi-agent V1 and V2 on current main:
- Commit: cbfd999db78cb088d2bd89b52051efe6f44555a4
- Component: codex-rs/core and codex-rs/protocol
- Platform/model/subscription: independent; the problem occurs before the parent model request is constructed
Actual behavior
Successful subagent completion messages are forwarded into the parent agent's model-visible context without any size limit.
Codex defines a 1,000-token completion-message budget in session_prefix.rs. However, only errored completions are truncated. AgentStatus::Completed(Some(message)) clones the entire final message unchanged:
In MultiAgent V2, this unbounded string is placed in InterAgentCommunication and delivered to the parent:
It is then copied unchanged into a model-visible ResponseItem::AgentMessage:
ContextManager::process_item truncates function and custom-tool outputs, but explicitly clones AgentMessage unchanged:
The legacy MultiAgent V1 path has the same problem because it serializes the complete AgentStatus into a SubagentNotification:
Impact
A subagent returning a sufficiently large final answer can inject a single item larger than the intended completion budget, and potentially larger than the parent's remaining context window. This can cause excessive context growth, premature compaction, or context_length_exceeded on the parent's next request.
The existing test covers truncation of errored completions only:
What steps can reproduce the bug?
This can be reproduced deterministically with a regression test beside the existing error-completion test:
~~~rust
#[test]
fn successful_completion_message_stays_below_completion_budget() {
let message = format_inter_agent_completion_message(
AgentPath::root(),
AgentPath::try_from("/root/worker").expect("valid agent path"),
&AgentStatus::Completed(Some("large subagent result ".repeat(20_000))),
)
.expect("completed status should produce a completion message");
assert!(
approx_token_count(&message) < COMPLETION_MESSAGE_MAX_TOKENS,
"successful completion contained {} tokens",
approx_token_count(&message),
);
}
~~~
The assertion currently fails because the complete successful result is returned unchanged.
A higher-level reproduction is:
- Start a parent task with multi-agent support enabled.
- Spawn a child agent whose final response exceeds 10,000 tokens.
- Wait for the child to complete.
- Inspect the parent's next model request or normalized conversation history.
- Observe that the entire child result is present in a single AgentMessage without truncation or spill handling.
What is the expected behavior?
All model-visible subagent completion messages should have a hard size limit.
At minimum:
- Successful completions should honor COMPLETION_MESSAGE_MAX_TOKENS, just as error completions do.
- The same limit should apply consistently to MultiAgent V1 and V2.
- Truncated messages should contain an explicit marker explaining that content was omitted.
- If the full result must remain accessible, the bounded parent message should reference the child thread or a stored artifact instead of embedding the entire result.
- Integration coverage should verify that the actual message delivered to the parent remains bounded.
Additional information
This is related to the broader context-hygiene concern in #40493, which mentions bounding successful subagent completion forwarding.
This report is intentionally narrower and provides a deterministic source-level reproduction: a single successful completion bypasses the explicit 1,000-token completion-message budget. It does not depend on cumulative tool-output growth or recursive session-state reads.
A possible fix is to truncate or spill successful completion payloads before constructing either InterAgentCompletionMessage or SubagentNotification, while preserving a bounded reference to the child thread for retrieving the full result.