Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
97 commits
Select commit Hold shift + click to select a range
f27344a
Add standalone ACP protocol client and session runtime
brennanb2025 Oct 3, 2026
d09c278
Protect ACP transport teardown from late stream errors
brennanb2025 Oct 3, 2026
c3aa650
Retire incoming ACP request ids before publishing responses
brennanb2025 Oct 3, 2026
cdad7d2
Narrow ACP configuration requests and transport message types
brennanb2025 Oct 3, 2026
2ae4ab5
Remove redundant ACP request handler return unions
brennanb2025 Oct 3, 2026
e30b885
Keep ACP waits caller-owned and preserve protocol extensions
brennanb2025 Oct 3, 2026
e8d37ec
Preserve open ACP decisions through prompt completion
brennanb2025 Oct 3, 2026
23b927e
Move the turn message ordinals and the turn-row revision to the neutr…
brennanb2025 Oct 4, 2026
8a42c33
Admit one provider event's writes as one transition, and let rows be …
brennanb2025 Oct 4, 2026
7ad901b
Recover message ordinals from the journal's highest place, and forget…
brennanb2025 Oct 4, 2026
620b8d7
Spell the subagent thread's message slot without spreading an identit…
brennanb2025 Oct 4, 2026
e892640
Add a provider timeline grammar and a shared assembler that decides a…
brennanb2025 Oct 4, 2026
9408e43
Fix the types and the exhaustive event switch CI reported for the ass…
brennanb2025 Oct 4, 2026
c491688
Let the journal decide stream lifetimes, request reuse, named sends a…
brennanb2025 Oct 4, 2026
a9dbaaa
Type the unbound assembler helper's drain as the void it reports
brennanb2025 Oct 4, 2026
50c93fb
Bound the rows kept for a continued anonymous message and the stopped…
brennanb2025 Oct 4, 2026
ca7f95c
Translate ACP session traffic into shared timeline events
brennanb2025 Oct 4, 2026
99138f1
Preserve fixture answer linkage and handle all typed ACP updates
brennanb2025 Oct 4, 2026
c484c9b
Keep replay chunks and long-turn tool snapshots bounded
brennanb2025 Oct 4, 2026
fa85fc3
Forward ACP joins to the journal-derived timeline assembler
brennanb2025 Oct 4, 2026
c4a072d
Use exact ACP prompt identity and recover incomplete timeline replay
brennanb2025 Oct 4, 2026
19b4c7e
Detect short and Unicode home paths in encoded ACP fixtures
brennanb2025 Oct 4, 2026
33fda9b
Use generic privacy patterns for ACP fixtures
brennanb2025 Oct 4, 2026
85b0403
Merge remote-tracking branch 'origin/brennanb2025/acp-d1-protocol' in…
brennanb2025 Oct 4, 2026
d52d38b
Translate Grok background work into durable task rows
brennanb2025 Oct 4, 2026
b4e29e0
Recover background task origin from its persisted launch tool
brennanb2025 Oct 4, 2026
efe2df4
Restate background task fallback from its terminal evidence
brennanb2025 Oct 4, 2026
d400e03
Require session identity on Grok task notifications
brennanb2025 Oct 4, 2026
23866ed
Honor explicit Grok task completion without an exit code
brennanb2025 Oct 4, 2026
d0e8a07
Match the background reset test to the final timeline grammar
brennanb2025 Oct 4, 2026
71430ae
Give task completion fixtures a specific evidence type
brennanb2025 Oct 4, 2026
01bd038
Settle ACP background tasks from live and replayed evidence
brennanb2025 Oct 4, 2026
dec3ecb
Honor background task outcomes carried by replayed tool results
brennanb2025 Oct 4, 2026
6be3555
Merge origin/main into the timeline transitions branch
brennanb2025 Oct 4, 2026
f91d2cc
Merge branch 'brennanb2025/acp-c1a-timeline-transitions' into brennan…
brennanb2025 Oct 4, 2026
a687297
Merge remote-tracking branch 'origin/main' into brennanb2025/acp-c1-t…
brennanb2025 Oct 4, 2026
ebb07e6
Keep the journal store under its line limit after the main merge
brennanb2025 Oct 5, 2026
b613dc2
Merge branch 'brennanb2025/acp-c1a-timeline-transitions' into brennan…
brennanb2025 Oct 5, 2026
5e09cb4
Merge remote-tracking branch 'origin/brennanb2025/acp-c1-timeline-ass…
brennanb2025 Oct 5, 2026
acfb0a7
Merge origin/main into the timeline transitions branch
brennanb2025 Oct 5, 2026
9d7c542
Merge remote-tracking branch 'origin/main' into brennanb2025/acp-d1-p…
brennanb2025 Oct 5, 2026
2ee87fb
Merge remote-tracking branch 'origin/main' into brennanb2025/acp-c1a-…
brennanb2025 Oct 5, 2026
03b9f2f
Drop the provider item reference, join index and identity schemes fro…
brennanb2025 Oct 5, 2026
7d04877
Write a resolved settlement in one transaction through enqueueRows
brennanb2025 Oct 5, 2026
e1c3ccd
Drop the transition's landing report; keep the turn-row write fire-an…
brennanb2025 Oct 5, 2026
f3f2ccc
Generate open ACP enums and check the generated schema offline
brennanb2025 Oct 5, 2026
0db8b0c
Land the ACP runtime contract the agent adapters use
brennanb2025 Oct 5, 2026
a197ba1
Merge remote-tracking branch 'origin/brennanb2025/acp-c1a-timeline-tr…
brennanb2025 Oct 5, 2026
a4df9df
Run a transition's steps as a prefix; drop the paced flag and resolve…
brennanb2025 Oct 5, 2026
2faf837
Rebuild the timeline assembler on one admission-order state
brennanb2025 Oct 5, 2026
85c7fe5
Merge remote-tracking branch 'origin/brennanb2025/acp-c1a-timeline-tr…
brennanb2025 Oct 5, 2026
9c58983
Answer every agent request after an ACP cancel
brennanb2025 Oct 5, 2026
6e9d0c0
Cover new running work in a turn the sweep ended
brennanb2025 Oct 5, 2026
fc8541f
Run a transition's steps in one queued write that loops over them
brennanb2025 Oct 5, 2026
f6e7219
Merge remote-tracking branch 'origin/brennanb2025/acp-c1a-timeline-tr…
brennanb2025 Oct 5, 2026
88490e5
Let each ACP request handler own its answer after a cancel
brennanb2025 Oct 5, 2026
1f4cab0
End a turn another writer settled the way the provider's end does
brennanb2025 Oct 5, 2026
ccbcfab
Merge remote-tracking branch 'origin/brennanb2025/acp-c1-timeline-ass…
brennanb2025 Oct 5, 2026
cce1d94
Merge remote-tracking branch 'origin/brennanb2025/acp-d1-protocol' in…
brennanb2025 Oct 5, 2026
8b4b497
Adopt ACP load history only into an empty journal, chosen by the tran…
brennanb2025 Oct 5, 2026
430d820
Leave a stopped turn's running tools to the agent's own end
brennanb2025 Oct 5, 2026
d22b154
Pin that a stopped turn's running tools hold budget until the agent's…
brennanb2025 Oct 5, 2026
76948c6
Merge remote-tracking branch 'origin/main' into brennanb2025/acp-c1-t…
brennanb2025 Oct 5, 2026
1c49877
Type the stopped turn's tool progress update as a tool body
brennanb2025 Oct 5, 2026
9fcb954
List every event the assembler hands to the decision step
brennanb2025 Oct 5, 2026
a902a0f
Merge remote-tracking branch 'origin/brennanb2025/acp-c1-timeline-ass…
brennanb2025 Oct 5, 2026
cf9d0ee
Say why a Grok turn failed, and keep task rows in Grok's own words
brennanb2025 Oct 5, 2026
e88bbf0
Read a monitor from Grok's exact output prefix
brennanb2025 Oct 5, 2026
ad7678c
Word a failed Grok turn in Grok's own text, not as a refused message
brennanb2025 Oct 5, 2026
7aa40a9
Register the ACP schema verify step in the PR preflight phase test
brennanb2025 Oct 5, 2026
cc38107
Merge remote-tracking branch 'origin/brennanb2025/acp-d1-protocol' in…
brennanb2025 Oct 5, 2026
c4655b4
Read ACP permissions, session events and prompt errors through the pr…
brennanb2025 Oct 5, 2026
ff08986
Merge remote-tracking branch 'origin/main' into brennanb2025/acp-c1a-…
brennanb2025 Oct 5, 2026
06e664b
Merge remote-tracking branch 'origin/main' into brennanb2025/acp-c1-t…
brennanb2025 Oct 5, 2026
98e7403
Merge origin/main into acp-d2-translation
brennanb2025 Oct 5, 2026
ad8ebbd
Merge remote-tracking branch 'origin/brennanb2025/acp-c1a-timeline-tr…
brennanb2025 Oct 5, 2026
c1f0c7a
Merge acp-c1-timeline-assembler (main merged) into acp-d2-translation
brennanb2025 Oct 5, 2026
879f74a
refactor(native-chat): drop saved-history adoption from the timeline …
brennanb2025 Oct 5, 2026
d012bc2
Merge remote-tracking branch 'origin/brennanb2025/acp-c1-timeline-ass…
brennanb2025 Oct 5, 2026
0f4be81
refactor(acp): drop session/load history adoption from the translator
brennanb2025 Oct 5, 2026
58c3dd5
refactor(native-chat): a pending input is only Orca's send now
brennanb2025 Oct 5, 2026
d40fd03
Merge remote-tracking branch 'origin/brennanb2025/acp-c1-timeline-ass…
brennanb2025 Oct 5, 2026
2802460
test(acp): keep the task-result status table on live frames
brennanb2025 Oct 5, 2026
e996bb1
Merge origin/main into acp-c1a-timeline-transitions
brennanb2025 Oct 5, 2026
a59276f
Merge remote-tracking branch 'origin/brennanb2025/acp-c1a-timeline-tr…
brennanb2025 Oct 5, 2026
5c4a89f
Merge remote-tracking branch 'origin/brennanb2025/acp-c1-timeline-ass…
brennanb2025 Oct 5, 2026
503e483
Merge 8127d9478218 into acp-c1a-timeline-transitions
brennanb2025 Oct 6, 2026
eba27a3
Use current provider handles in transition tests
brennanb2025 Oct 6, 2026
bbd96e1
Merge eba27a3c784e into acp-c1-timeline-assembler
brennanb2025 Oct 6, 2026
a7d8bcb
Use current provider handles in timeline fixtures
brennanb2025 Oct 6, 2026
63f79a9
Merge a7d8bcbb64fb into acp-d2-translation
brennanb2025 Oct 6, 2026
503ebe4
Require the ACP directory in the runtime import check
brennanb2025 Oct 6, 2026
383b0dc
Merge 08a970a3f117 into acp-c1a-timeline-transitions
brennanb2025 Oct 6, 2026
b5b0068
Merge 383b0dc2c420 into acp-c1-timeline-assembler
brennanb2025 Oct 6, 2026
bb93479
Merge b5b0068f885c into acp-d2-translation
brennanb2025 Oct 6, 2026
67e12c3
Merge current main and landed protocol client into translation branch
brennanb2025 Oct 6, 2026
9bd27f9
Merge landed timeline assembler and current main into ACP translation…
brennanb2025 Oct 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions src/main/acp/acp-background-task-timeline.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { BoundedMap } from '../../shared/bounded-map'
import { backgroundTaskJournalBody } from '../../shared/native-chat-background-task-row'
import type { NativeChatBackgroundTaskBlock } from '../../shared/native-chat-types'
import {
boundInlineText,
DEFAULT_JOURNAL_PAYLOAD_LIMITS
} from '../native-chat/agent-session-journal/journal-payload-bounds'
import type {
ProviderTimelineEvent,
ProviderTimelineJoin
} from '../native-chat/agent-session-timeline/provider-timeline-event'
import type { AcpBackgroundTaskUpdate } from './acp-dialects/acp-dialect'

/** Partial provider snapshots only; the assembler owns settlement and durable placement. A task
* the bound evicted (128 others updated since) loses its earlier label, parent tool and output
* file on its next update; its row keeps the turn it was placed in. */
export class AcpBackgroundTaskTimeline {
private readonly snapshots = new BoundedMap<string, NativeChatBackgroundTaskBlock>({
maxEntries: 128,
maxBytes: 1024 * 1024,
sizeOf: (block, key) => Buffer.byteLength(key) + Buffer.byteLength(JSON.stringify(block))
})

constructor(private readonly toolTurn: (callId: string) => string | undefined) {}

translate(
updates: AcpBackgroundTaskUpdate[],
join: ProviderTimelineJoin
): ProviderTimelineEvent[] {
return updates.map((update) => {
const { fallbackLabel, fallbackKind, ...fields } = update
const previous = this.snapshots.get(update.taskId)
const block: NativeChatBackgroundTaskBlock = {
type: 'background-task',
...previous,
...fields,
kind: update.kind ?? previous?.kind ?? fallbackKind ?? 'unknown',
label: update.label ?? previous?.label ?? fallbackLabel ?? update.taskId,
state: update.state
}
for (const key of ['label', 'summary', 'error', 'outputFile'] as const) {
const text = block[key]
if (text !== undefined) {
block[key] = boundInlineText(text, DEFAULT_JOURNAL_PAYLOAD_LIMITS).text
}
}
this.snapshots.set(block.taskId, block)
const turn = block.parentToolUseId ? this.toolTurn(block.parentToolUseId) : undefined
return {
type: 'item.update',
item: `background-task:${block.taskId}`,
body: backgroundTaskJournalBody(block),
join: { ...join, ...(turn === undefined ? {} : { turn }) }
}
})
}
}
69 changes: 69 additions & 0 deletions src/main/acp/acp-context-usage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import { z } from 'zod'
import type { AgentSessionContextUsage } from '../../shared/agent-session-context-usage'
import type {
ProviderTimelineEvent,
ProviderTimelineJoin
} from '../native-chat/agent-session-timeline/provider-timeline-event'
import type { AcpDialect } from './acp-dialects/acp-dialect'
import type { SessionUpdate, UsageUpdate } from './generated/acp-protocol.generated'

export class AcpContextTimeline {
private window?: { tokens: number; capturedAt: number }

models(
models: unknown,
at: number,
dialect: AcpDialect,
join: ProviderTimelineJoin
): ProviderTimelineEvent[] {
const tokens = dialect.contextWindow?.(models)
return tokens === undefined ? [] : this.update({ window: { tokens, capturedAt: at } }, join)
}

update(usage: AgentSessionContextUsage, join: ProviderTimelineJoin): ProviderTimelineEvent[] {
this.window = usage.window ?? this.window
return [
{
type: 'context.usage',
usage: { ...usage, ...(this.window ? { window: this.window } : {}) },
join
}
]
}

/** Replayed history is dropped except what it says about the context window. */
history(
update: SessionUpdate | undefined,
usage: AgentSessionContextUsage | undefined,
at: number,
join: ProviderTimelineJoin
): ProviderTimelineEvent[] {
const events = usage ? this.update(usage, join) : []
if (update?.sessionUpdate === 'usage_update') {
events.push({ type: 'context.usage', usage: acpWindowUsage(update, at), join })
}
return events
}
}

export function acpWindowUsage(update: UsageUpdate, at: number): AgentSessionContextUsage {
return {
window: { tokens: update.size, capturedAt: at },
used: {
kind: 'estimate',
capturedAt: at,
usage: {
inputTokens: update.used,
cacheReadInputTokens: 0,
cacheCreationInputTokens: 0,
outputTokens: 0
}
}
}
}

export const acpNotificationEnvelopeSchema = z.looseObject({
sessionId: z.string(),
update: z.looseObject({ sessionUpdate: z.string() }),
_meta: z.looseObject({ isReplay: z.boolean().optional() }).nullish()
})
54 changes: 54 additions & 0 deletions src/main/acp/acp-dialects/acp-dialect.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import type { AgentSessionContextUsage } from '../../../shared/agent-session-context-usage'
import type { AgentJournalToolCallItem } from '../../../shared/agent-session-journal-types'
import type { AgentSessionPromptResponse } from '../../../shared/agent-session-question-answer'
import type { NativeChatBackgroundTaskBlock } from '../../../shared/native-chat-types'
import type { ProviderTimelineRequestBody } from '../../native-chat/agent-session-timeline/provider-timeline-event'
import type { AcpAgentError } from '../acp-errors'
import type { ToolCallUpdate } from '../generated/acp-protocol.generated'

export type AcpRequestPresentation = {
body: ProviderTimelineRequestBody
reply(response: AgentSessionPromptResponse | null): unknown
}

export type AcpBackgroundTaskUpdate = Pick<NativeChatBackgroundTaskBlock, 'taskId' | 'state'> &
Partial<Omit<NativeChatBackgroundTaskBlock, 'type' | 'taskId' | 'state'>> & {
/** Used only until a provider description is known. */
fallbackLabel?: string
/** Used only until a frame names the task's kind. */
fallbackKind?: NativeChatBackgroundTaskBlock['kind']
}

export type AcpDialectNotification =
| { disposition: 'ignore' }
| {
disposition: 'map'
turn?: string
replay?: boolean
at?: number
started?: boolean
end?: { stopReason: string; durationMs?: number; failureDetail?: string }
/** The provider's own words for why `turn` failed, sent apart from its end. */
failureDetail?: string
usage?: AgentSessionContextUsage
backgroundTasks?: AcpBackgroundTaskUpdate[]
}

/** Hooks interpret extensions; lifecycle and row identity stay shared. */
export type AcpDialect = {
injectedPromptIdentity?: true
toolName?(update: ToolCallUpdate): string | undefined
toolBackgroundTasks?(
update: ToolCallUpdate,
tool: AgentJournalToolCallItem
): AcpBackgroundTaskUpdate[]
notification?(method: string, params: unknown, at: number): AcpDialectNotification | undefined
contextWindow?(models: unknown): number | undefined
request?(method: string, params: unknown): AcpRequestPresentation | undefined
/** The provider's words in a `session/prompt` error answer, when its message is generic. */
promptErrorDetail?(error: AcpAgentError): string | undefined
/** The row for a failed turn the provider gave no words for. */
failedTurnText?(stopReason: string): string
}

export const GENERIC_ACP_DIALECT: AcpDialect = {}
184 changes: 184 additions & 0 deletions src/main/acp/acp-dialects/grok-background-tasks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
import { z } from 'zod'
import type { AgentJournalToolCallItem } from '../../../shared/agent-session-journal-types'
import {
isSettledBackgroundTaskState,
normalizeBackgroundTaskKind
} from '../../../shared/native-chat-background-task-row'
import type { NativeChatBackgroundTaskBlock } from '../../../shared/native-chat-types'
import type { ToolCallUpdate } from '../generated/acp-protocol.generated'
import type { AcpBackgroundTaskUpdate, AcpDialectNotification } from './acp-dialect'

const taskSchema = z.object({
task_id: z.string().min(1),
command: z.string().optional(),
description: z.string().nullish(),
monitor_description: z.string().nullish(),
display_command: z.string().nullish(),
output_file: z.string().optional(),
summary: z.string().optional(),
error: z.string().optional(),
output: z.string().optional(),
kind: z.string().optional(),
task_type: z.string().optional(),
exit_code: z.number().int().nullish(),
signal: z.union([z.string(), z.number()]).nullish(),
explicitly_killed: z.boolean().optional()
})
const backgroundedSchema = taskSchema.extend({
sessionUpdate: z.literal('task_backgrounded'),
tool_call_id: z.string().optional()
})
const completedSchema = z.object({
sessionUpdate: z.literal('task_completed'),
task_snapshot: taskSchema
})
const startedOutputSchema = taskSchema.extend({ type: z.literal('BackgroundTaskStarted') })
const taskResultSchema = taskSchema.extend({
status: z.string().optional(),
outcome: z.string().optional()
})
const resultOutputSchema = z.object({
type: z.enum(['TaskOutput', 'KillTask']),
Result: taskResultSchema.optional(),
MultiResult: z.object({ results: z.array(taskResultSchema) }).optional()
})
type GrokTask = z.infer<typeof taskSchema>
/** Grok's output reads name a monitor only by this command prefix. */
const MONITOR_COMMAND = /^\[monitor[:\]]/

function completedState(task: GrokTask): NativeChatBackgroundTaskBlock['state'] {
return task.explicitly_killed
? 'idle'
: task.signal != null || task.error?.trim() || (task.exit_code != null && task.exit_code !== 0)
? 'blocked'
: 'done'
}

function resultState(
task: z.infer<typeof taskResultSchema>
): NativeChatBackgroundTaskBlock['state'] | undefined {
if (task.explicitly_killed || ['killed', 'stopped', 'cancelled'].includes(task.status ?? '')) {
return 'idle'
}
if (task.error?.trim() || ['failed', 'error'].includes(task.status ?? '')) {
return 'blocked'
}
if (
task.exit_code != null ||
task.signal != null ||
['completed', 'success', 'succeeded'].includes(task.status ?? '')
) {
return completedState(task)
}
return ['pending', 'running'].includes(task.status ?? '') ? 'working' : undefined
}

function snapshot(
task: GrokTask,
state: NativeChatBackgroundTaskBlock['state']
): AcpBackgroundTaskUpdate {
const kind = task.kind ?? task.task_type
const monitor =
kind === 'monitor' ||
task.monitor_description != null ||
MONITOR_COMMAND.test(task.command ?? '')
const label = task.monitor_description?.trim() || task.description?.trim()
const fallbackLabel = task.display_command?.trim() || task.command?.trim()
const settled = isSettledBackgroundTaskState(state)
return {
taskId: task.task_id,
state,
...(monitor
? { kind: 'monitor' as const }
: kind !== undefined
? {
kind:
kind === 'bash' || kind === 'shell' || task.command !== undefined
? ('command' as const)
: normalizeBackgroundTaskKind(kind)
}
: task.command !== undefined
? { fallbackKind: 'command' as const }
: {}),
...(label ? { label } : fallbackLabel ? { fallbackLabel } : {}),
...(task.output_file === undefined ? {} : { outputFile: task.output_file }),
// A running task's summary is Grok's "Background task <id> started", not the task's result.
...(settled ? { summary: task.summary ?? '' } : {}),
...(task.error === undefined && !settled ? {} : { error: task.error ?? '' })
}
}

const taskInputSchema = z.object({
description: z.string().optional(),
command: z.string().optional(),
task_id: z.string().trim().min(1).optional(),
task_ids: z.array(z.string().trim().min(1)).optional()
})

export function grokToolBackgroundTasks(
update: ToolCallUpdate,
tool: AgentJournalToolCallItem
): AcpBackgroundTaskUpdate[] {
const result = resultOutputSchema.safeParse(update.rawOutput)
if (result.success) {
const tasks =
result.data.MultiResult?.results ?? (result.data.Result ? [result.data.Result] : [])
return tasks.flatMap((task) => {
if (result.data.type === 'KillTask') {
return update.status === 'completed' && task.outcome === 'killed'
? [snapshot(task, 'idle')]
: []
}
const state = resultState(task)
return state && !task.command?.startsWith('[subagent:') ? [snapshot(task, state)] : []
})
}
const input = taskInputSchema.safeParse(tool.input)
if (tool.name === 'kill_command_or_subagent' && update.status === 'completed' && input.success) {
// Inference: a successful kill call settles its named tasks without a completion notice.
return [
...new Set([
...(input.data.task_ids ?? []),
...(input.data.task_id ? [input.data.task_id] : [])
])
].map((taskId) => ({ taskId, state: 'idle', summary: '', error: '' }))
}
const parsed = startedOutputSchema.safeParse(update.rawOutput)
return parsed.success
? [
{
...snapshot({ ...(input.success ? input.data : {}), ...parsed.data }, 'working'),
parentToolUseId: update.toolCallId
}
]
: []
}

export function grokBackgroundTaskNotification(
canonicalMethod: string,
params: unknown
): AcpDialectNotification | undefined {
if (!['x.ai/task_backgrounded', 'x.ai/task_completed'].includes(canonicalMethod)) {
return undefined
}
const parsed = z
.object({ sessionId: z.string(), update: z.union([backgroundedSchema, completedSchema]) })
.safeParse(params)
if (!parsed.success) {
return { disposition: 'ignore' }
}
const update = parsed.data.update
if (update.sessionUpdate === 'task_backgrounded') {
return {
disposition: 'map',
backgroundTasks: [
{
...snapshot(update, update.monitor_description != null ? 'monitoring' : 'working'),
...(update.tool_call_id === undefined ? {} : { parentToolUseId: update.tool_call_id })
}
]
}
}
const task = update.task_snapshot
return { disposition: 'map', backgroundTasks: [snapshot(task, completedState(task))] }
}
Loading
Loading