Something went wrong. Try again.
source dump of claude code forked from oppi.li/claude-code
Something went wrong. Try again.
4.3 kB · 121 lines
TypeScript
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122import type { TaskStateBase } from '../../Task.js'import type { AgentToolResult } from '../../tools/AgentTool/agentToolUtils.js'import type { AgentDefinition } from '../../tools/AgentTool/loadAgentsDir.js'import type { Message } from '../../types/message.js'import type { PermissionMode } from '../../utils/permissions/PermissionMode.js'import type { AgentProgress } from '../LocalAgentTask/LocalAgentTask.js'
/** * Teammate identity stored in task state. * Same shape as TeammateContext (runtime) but stored as plain data. * TeammateContext is for AsyncLocalStorage; this is for AppState persistence. */export type TeammateIdentity = { agentId: string // e.g., "researcher@my-team" agentName: string // e.g., "researcher" teamName: string color?: string planModeRequired: boolean parentSessionId: string // Leader's session ID}
export type InProcessTeammateTaskState = TaskStateBase & { type: 'in_process_teammate'
// Identity as sub-object (matches TeammateContext shape for consistency) // Stored as plain data in AppState, NOT a reference to AsyncLocalStorage identity: TeammateIdentity
// Execution prompt: string // Optional model override for this teammate model?: string // Optional: Only set if teammate uses a specific agent definition // Many teammates run as general-purpose agents without a predefined definition selectedAgent?: AgentDefinition abortController?: AbortController // Runtime only, not serialized to disk - kills WHOLE teammate currentWorkAbortController?: AbortController // Runtime only - aborts current turn without killing teammate unregisterCleanup?: () => void // Runtime only
// Plan mode approval tracking (planModeRequired is in identity) awaitingPlanApproval: boolean
// Permission mode for this teammate (cycled independently via Shift+Tab when viewing) permissionMode: PermissionMode
// State error?: string result?: AgentToolResult // Reuse existing type since teammates run via runAgent() progress?: AgentProgress
// Conversation history for zoomed view (NOT mailbox messages) // Mailbox messages are stored separately in teamContext.inProcessMailboxes messages?: Message[]
// Tool use IDs currently being executed (for animation in transcript view) inProgressToolUseIDs?: Set<string>
// Queue of user messages to deliver when viewing teammate transcript pendingUserMessages: string[]
// UI: random spinner verbs (stable across re-renders, shared between components) spinnerVerb?: string pastTenseVerb?: string
// Lifecycle isIdle: boolean shutdownRequested: boolean
// Callbacks to notify when teammate becomes idle (runtime only) // Used by leader to efficiently wait without polling onIdleCallbacks?: Array<() => void>
// Progress tracking (for computing deltas in notifications) lastReportedToolCount: number lastReportedTokenCount: number}
export function isInProcessTeammateTask( task: unknown,): task is InProcessTeammateTaskState { return ( typeof task === 'object' && task !== null && 'type' in task && task.type === 'in_process_teammate' )}
/** * Cap on the number of messages kept in task.messages (the AppState UI mirror). * * task.messages exists purely for the zoomed transcript dialog, which only * needs recent context. The full conversation lives in the local allMessages * array (inProcessRunner) and on disk at the agent transcript path. * * BQ analysis (round 9, 2026-03-20) showed ~20MB RSS per agent at 500+ turn * sessions and ~125MB per concurrent agent in swarm bursts. Whale session * 9a990de8 launched 292 agents in 2 minutes and reached 36.8GB. The dominant * cost is this array holding a second full copy of every message. */export const TEAMMATE_MESSAGES_UI_CAP = 50
/** * Append an item to a message array, capping the result at * TEAMMATE_MESSAGES_UI_CAP entries by dropping the oldest. Always returns * a new array (AppState immutability). */export function appendCappedMessage<T>( prev: readonly T[] | undefined, item: T,): T[] { if (prev === undefined || prev.length === 0) { return [item] } if (prev.length >= TEAMMATE_MESSAGES_UI_CAP) { const next = prev.slice(-(TEAMMATE_MESSAGES_UI_CAP - 1)) next.push(item) return next } return [...prev, item]}