Summary
After a reload, a sub-agent's child tool-call cards render without their input: the turn-state snapshot never persists the child call's arguments, so the frontend mapper has nothing to restore.
Problem
Live, subagent_tool_call carries args and the row shows the tool input (and a degraded generic tool name can be given a search label from query). After a thread reload the same cards come back from the persisted snapshot with no input at all.
Neither persisted shape carries the payload (app/src/types/turnState.ts):
export interface PersistedSubagentToolCall {
callId; toolName; status; iteration?; elapsedMs?; outputChars?;
displayName?; detail?; failure?; output?; // no args / input
}
// PersistedSubagentTranscriptItem, kind: 'tool'
{ iteration?; callId; toolName; status; elapsedMs?; outputChars?; displayName?; detail?; failure? }
The only args field in that file is PersistedToolTimelineEntry.argsBuffer, which belongs to the parent timeline. So subagentToolCallFromPersisted assigning no args (app/src/store/chatRuntimeSlice.ts, subagentActivityFromPersisted) is not a mapper bug — the data never leaves the core.
Repro: delegate to a sub-agent that calls a tool with visible arguments → let it finish → reload the thread → expand the sub-agent card → the child tool row has no input.
Solution
Rust: persist the child call's arguments in the turn-state mirror (src/openhuman/threads/turn_state/ — where subagent_tool_call events are written into the snapshot's subagent.toolCalls), as an optional field mirroring the parent's argsBuffer semantics (bounded size). Frontend: add the optional field to PersistedSubagentToolCall / the transcript tool item and copy it through in subagentToolCallFromPersisted — a one-line change once the field exists.
Acceptance criteria
Related
Summary
After a reload, a sub-agent's child tool-call cards render without their input: the turn-state snapshot never persists the child call's arguments, so the frontend mapper has nothing to restore.
Problem
Live,
subagent_tool_callcarriesargsand the row shows the tool input (and a degraded generictoolname can be given a search label fromquery). After a thread reload the same cards come back from the persisted snapshot with no input at all.Neither persisted shape carries the payload (
app/src/types/turnState.ts):The only
argsfield in that file isPersistedToolTimelineEntry.argsBuffer, which belongs to the parent timeline. SosubagentToolCallFromPersistedassigning noargs(app/src/store/chatRuntimeSlice.ts,subagentActivityFromPersisted) is not a mapper bug — the data never leaves the core.Repro: delegate to a sub-agent that calls a tool with visible arguments → let it finish → reload the thread → expand the sub-agent card → the child tool row has no input.
Solution
Rust: persist the child call's arguments in the turn-state mirror (
src/openhuman/threads/turn_state/— wheresubagent_tool_callevents are written into the snapshot'ssubagent.toolCalls), as an optional field mirroring the parent'sargsBuffersemantics (bounded size). Frontend: add the optional field toPersistedSubagentToolCall/ the transcripttoolitem and copy it through insubagentToolCallFromPersisted— a one-line change once the field exists.Acceptance criteria
toolname still derives its search label from the restoredquery.subagentActivityFromPersistedrestoringargs..github/workflows/ci-lite.yml).Related
chatRuntimeSlice.ts— "Restore persisted child tool arguments"); confirmed there as a core-side gap outside that PR's scope.