Motivation
physim folded 3 of 4 runtime stream generators onto streamAgentTurn (physim#70, physim PR #71 — merged, 86/86 eval green). The 4th — sandbox-sdk (runSandboxSdkAgent) — could not fold, and the reason is a set of gaps in the turn primitive itself. physim is the motivating consumer; this issue tracks growing the primitive so that fold becomes possible.
Gaps (from PR #71's documented evidence)
1. Task semantics. The sandbox runtime drives box.streamTask(message, options) — an autonomous multi-turn task, not one prompt→stream. It needs per-turn options the turn primitive does not carry today: sessionId, turnId, model, backend profile, and maxTurns. streamAgentTurn is currently single streamPrompt(prompt, { signal }). Add a task mode (e.g. a { kind: 'box', ... } / streamTask variant) that carries these.
2. Tool-part preservation. The substrate's mapSandboxEvent intentionally drops tool parts ("no guessed tool-part shapes"). The sandbox UI needs tool_call / tool_result events with semantic failure detection. Add an opt-in that preserves and emits tool-call/tool-result events through RuntimeStreamEvent rather than dropping them.
3. Pre-terminal event injection. The sandbox runtime inspects parse state before done to run a mid-stream noop-retry, and inserts vault-sync events before done. The current sealed terminal envelope forbids emitting events before the terminal. Allow pre-terminal event injection (or a non-sealed terminal) so consumers can interleave retry/sync events.
Acceptance
physim's runSandboxSdkAgent folds onto the primitive with no loss of: tool_call/tool_result events, the mid-stream noop-retry, or the vault-sync-before-done behavior — and its bespoke streamTask→AgentEvent parser deletes (the last of the 4 in physim#70).
Refs
Motivation
physim folded 3 of 4 runtime stream generators onto
streamAgentTurn(physim#70, physim PR #71 — merged, 86/86 eval green). The 4th — sandbox-sdk (runSandboxSdkAgent) — could not fold, and the reason is a set of gaps in the turn primitive itself. physim is the motivating consumer; this issue tracks growing the primitive so that fold becomes possible.Gaps (from PR #71's documented evidence)
1. Task semantics. The sandbox runtime drives
box.streamTask(message, options)— an autonomous multi-turn task, not one prompt→stream. It needs per-turn options the turn primitive does not carry today:sessionId,turnId,model, backendprofile, andmaxTurns.streamAgentTurnis currently singlestreamPrompt(prompt, { signal }). Add a task mode (e.g. a{ kind: 'box', ... }/streamTaskvariant) that carries these.2. Tool-part preservation. The substrate's
mapSandboxEventintentionally drops tool parts ("no guessed tool-part shapes"). The sandbox UI needstool_call/tool_resultevents with semantic failure detection. Add an opt-in that preserves and emits tool-call/tool-result events throughRuntimeStreamEventrather than dropping them.3. Pre-terminal event injection. The sandbox runtime inspects parse state before
doneto run a mid-stream noop-retry, and inserts vault-sync events beforedone. The current sealed terminal envelope forbids emitting events before the terminal. Allow pre-terminal event injection (or a non-sealed terminal) so consumers can interleave retry/sync events.Acceptance
physim's
runSandboxSdkAgentfolds onto the primitive with no loss of:tool_call/tool_resultevents, the mid-stream noop-retry, or the vault-sync-before-donebehavior — and its bespokestreamTask→AgentEventparser deletes (the last of the 4 in physim#70).Refs