Files
orca/src/shared/structured-agent-session-agent-status.ts
T
Brennan Benson 1f702e91fb feat(native-chat): publish the host's child records to the status summary and the chat strip
The status summary and the background-task channel now read a session's child
records from the host's canonical store, through the status sink its row
landed in, and derive the legacy task and subagent shapes from the same views.
The parent row folds its child-work liveness from those records at ingest,
not from the summary's task list. The adapters no longer push their task DTO
to clients: the onBackgroundTasksChanged path is gone, and a child-work ingest
is what republishes both the summary and the strip. Finished children stay
listed until the session's own next turn starts. A reader that predates child
views never receives a roster whose rows are all settled.
2026-09-29 00:59:47 -07:00

50 lines
2.2 KiB
TypeScript

import type { AgentSessionStatusSummary } from './agent-session-wire'
import { foldAgentLeadStatus } from './agent-lead-status-fold'
import {
agentChildWorkLiveness,
type AgentChildWorkLivenessCandidate
} from './agent-status-child-work-liveness'
import type { AgentMainAgentStatus, AgentStatusState, AgentWorkingMode } from './agent-status-types'
import type { StructuredAgentSessionProjectedStatus } from './structured-agent-session-projection'
export type StructuredAgentSessionAgentStatus = {
state: AgentStatusState
workingMode?: AgentWorkingMode
/** The main agent's own state and last-turn verdict, before child work is folded in. The caller
* stamps the clock: this projection has no view of when the main agent's state first appeared. */
mainAgent: Omit<AgentMainAgentStatus, 'stateStartedAt'>
}
/** The lead state one projected session status stands for, before child work is folded in. */
function structuredAgentSessionLeadState(
status: StructuredAgentSessionProjectedStatus
): 'working' | 'blocked' | 'done' {
return status === 'working' ? 'working' : status === 'attention' ? 'blocked' : 'done'
}
/** The agent-status state one structured session summary stands for, with its live child
* work folded in the same way the hook lane folds a subagent roster. Shared across the
* process boundary so `worktree ps`, mobile and the sidebar cannot disagree about one session.
* `childWork` is the host's child records (or their views); only an older host's summary, which
* publishes none, is read by its live background tasks. */
export function structuredAgentSessionAgentStatus(
summary: Pick<AgentSessionStatusSummary, 'turnOutcome'> & {
status: StructuredAgentSessionProjectedStatus
childWork?: readonly AgentChildWorkLivenessCandidate[]
}
): StructuredAgentSessionAgentStatus {
const leadState = structuredAgentSessionLeadState(summary.status)
const resolution = foldAgentLeadStatus({
leadState,
childWorkLiveness: agentChildWorkLiveness(summary.childWork)
})
return {
state: resolution.stateName,
...(resolution.workingMode ? { workingMode: resolution.workingMode } : {}),
mainAgent: {
state: leadState,
...(leadState === 'done' && summary.turnOutcome ? { outcome: summary.turnOutcome } : {})
}
}
}