@minpeter/pss-runtime 0.1.0-next.0 → 0.1.0-next.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +223 -191
- package/dist/agent-child-runs.js +16 -0
- package/dist/agent-child-runs.js.map +1 -0
- package/dist/agent-host-capabilities.js +9 -0
- package/dist/agent-host-capabilities.js.map +1 -0
- package/dist/agent-host-session-store.js +12 -0
- package/dist/agent-host-session-store.js.map +1 -0
- package/dist/agent-loop.js +59 -35
- package/dist/agent-loop.js.map +1 -1
- package/dist/agent-namespace.js +24 -0
- package/dist/agent-namespace.js.map +1 -0
- package/dist/agent-options.d.ts +35 -0
- package/dist/agent-options.js +16 -0
- package/dist/agent-options.js.map +1 -0
- package/dist/agent-resume.js +143 -0
- package/dist/agent-resume.js.map +1 -0
- package/dist/agent-session-entry.d.ts +13 -0
- package/dist/agent-validation.js +35 -0
- package/dist/agent-validation.js.map +1 -0
- package/dist/agent.d.ts +8 -33
- package/dist/agent.js +131 -55
- package/dist/agent.js.map +1 -1
- package/dist/child-session-cleanups.js +61 -0
- package/dist/child-session-cleanups.js.map +1 -0
- package/dist/execution/host.js +14 -0
- package/dist/execution/host.js.map +1 -0
- package/dist/execution/index.d.ts +4 -0
- package/dist/execution/index.js +3 -0
- package/dist/execution/memory-notifications.js +54 -0
- package/dist/execution/memory-notifications.js.map +1 -0
- package/dist/execution/memory-state.js +34 -0
- package/dist/execution/memory-state.js.map +1 -0
- package/dist/execution/memory-store.js +203 -0
- package/dist/execution/memory-store.js.map +1 -0
- package/dist/execution/memory.d.ts +7 -0
- package/dist/execution/memory.js +28 -0
- package/dist/execution/memory.js.map +1 -0
- package/dist/execution/run.js +55 -0
- package/dist/execution/run.js.map +1 -0
- package/dist/execution/types.d.ts +155 -0
- package/dist/index.d.ts +9 -10
- package/dist/index.js +1 -6
- package/dist/llm-tool-execution.d.ts +35 -0
- package/dist/llm-tool-execution.js +126 -0
- package/dist/llm-tool-execution.js.map +1 -0
- package/dist/llm.d.ts +11 -15
- package/dist/llm.js +5 -9
- package/dist/llm.js.map +1 -1
- package/dist/plugins.d.ts +20 -0
- package/dist/plugins.js +14 -0
- package/dist/plugins.js.map +1 -0
- package/dist/session/events.d.ts +26 -20
- package/dist/session/input-normalization.js +66 -0
- package/dist/session/input-normalization.js.map +1 -0
- package/dist/session/input.d.ts +0 -4
- package/dist/session/mapping.js +1 -2
- package/dist/session/mapping.js.map +1 -1
- package/dist/session/run.js +1 -0
- package/dist/session/run.js.map +1 -1
- package/dist/session/runtime-input.js +20 -58
- package/dist/session/runtime-input.js.map +1 -1
- package/dist/session/session-errors.js +18 -0
- package/dist/session/session-errors.js.map +1 -0
- package/dist/session/session-events.js +59 -0
- package/dist/session/session-events.js.map +1 -0
- package/dist/session/session-execution.js +88 -0
- package/dist/session/session-execution.js.map +1 -0
- package/dist/session/session-kill.js +23 -0
- package/dist/session/session-kill.js.map +1 -0
- package/dist/session/session-notification.js +58 -0
- package/dist/session/session-notification.js.map +1 -0
- package/dist/session/session-runtime-drain.js +22 -0
- package/dist/session/session-runtime-drain.js.map +1 -0
- package/dist/session/session-state.js +102 -0
- package/dist/session/session-state.js.map +1 -0
- package/dist/session/session-turn-error.js +35 -0
- package/dist/session/session-turn-error.js.map +1 -0
- package/dist/session/session-turn-processor.js +135 -0
- package/dist/session/session-turn-processor.js.map +1 -0
- package/dist/session/session.js +125 -335
- package/dist/session/session.js.map +1 -1
- package/dist/session/snapshot.js +5 -31
- package/dist/session/snapshot.js.map +1 -1
- package/dist/session/store/file.d.ts +1 -0
- package/dist/session/store/file.js +14 -0
- package/dist/session/store/file.js.map +1 -1
- package/dist/session/store/memory.d.ts +1 -0
- package/dist/session/store/memory.js +5 -0
- package/dist/session/store/memory.js.map +1 -1
- package/dist/session/store/types.d.ts +1 -0
- package/dist/subagent-background-child-run-state.js +51 -0
- package/dist/subagent-background-child-run-state.js.map +1 -0
- package/dist/subagent-background-child-run.js +103 -0
- package/dist/subagent-background-child-run.js.map +1 -0
- package/dist/subagent-background-in-process.js +98 -0
- package/dist/subagent-background-in-process.js.map +1 -0
- package/dist/subagent-background-notification-inbox.js +106 -0
- package/dist/subagent-background-notification-inbox.js.map +1 -0
- package/dist/subagent-background-notify.js +136 -0
- package/dist/subagent-background-notify.js.map +1 -0
- package/dist/subagent-background-resume-group.js +99 -0
- package/dist/subagent-background-resume-group.js.map +1 -0
- package/dist/subagent-background-runner.js +115 -0
- package/dist/subagent-background-runner.js.map +1 -0
- package/dist/subagent-background-schedule.js +43 -0
- package/dist/subagent-background-schedule.js.map +1 -0
- package/dist/subagent-child-run.js +68 -0
- package/dist/subagent-child-run.js.map +1 -0
- package/dist/subagent-job-cancel.js +84 -0
- package/dist/subagent-job-cancel.js.map +1 -0
- package/dist/subagent-job-observer.js +19 -0
- package/dist/subagent-job-observer.js.map +1 -0
- package/dist/subagent-job-output.js +87 -0
- package/dist/subagent-job-output.js.map +1 -0
- package/dist/subagent-job-state.js +66 -0
- package/dist/subagent-job-state.js.map +1 -0
- package/dist/subagent-jobs.js +96 -0
- package/dist/subagent-jobs.js.map +1 -0
- package/dist/subagent-prompt-schema.js +114 -0
- package/dist/subagent-prompt-schema.js.map +1 -0
- package/dist/subagent-run.js +111 -0
- package/dist/subagent-run.js.map +1 -0
- package/dist/subagents.js +125 -0
- package/dist/subagents.js.map +1 -0
- package/package.json +11 -6
- package/dist/plugins/compaction.d.ts +0 -15
- package/dist/plugins/compaction.js +0 -98
- package/dist/plugins/compaction.js.map +0 -1
- package/dist/plugins/index.d.ts +0 -5
- package/dist/plugins/index.js +0 -5
- package/dist/plugins/memory.d.ts +0 -11
- package/dist/plugins/memory.js +0 -146
- package/dist/plugins/memory.js.map +0 -1
- package/dist/plugins/runner.d.ts +0 -1
- package/dist/plugins/runner.js +0 -83
- package/dist/plugins/runner.js.map +0 -1
- package/dist/plugins/scope.js +0 -13
- package/dist/plugins/scope.js.map +0 -1
- package/dist/plugins/sessions.d.ts +0 -12
- package/dist/plugins/sessions.js +0 -34
- package/dist/plugins/sessions.js.map +0 -1
- package/dist/plugins/tool-hook-handlers.js +0 -77
- package/dist/plugins/tool-hook-handlers.js.map +0 -1
- package/dist/plugins/tool-hook-results.js +0 -64
- package/dist/plugins/tool-hook-results.js.map +0 -1
- package/dist/plugins/tool-hooks.js +0 -111
- package/dist/plugins/tool-hooks.js.map +0 -1
- package/dist/plugins/types.d.ts +0 -105
- package/dist/plugins/types.js +0 -20
- package/dist/plugins/types.js.map +0 -1
- package/dist/session/lifecycle.d.ts +0 -12
- package/dist/session/lifecycle.js +0 -126
- package/dist/session/lifecycle.js.map +0 -1
- package/dist/session/overlay-anchor.js +0 -151
- package/dist/session/overlay-anchor.js.map +0 -1
- package/dist/session/overlay.js +0 -141
- package/dist/session/overlay.js.map +0 -1
- package/dist/session/snapshot.d.ts +0 -1
- /package/dist/{agent-loop.d.ts → session/history.d.ts} +0 -0
- /package/dist/session/{runtime-input.d.ts → session-execution.d.ts} +0 -0
- /package/dist/{plugins/scope.d.ts → session/session-state.d.ts} +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session.js","names":["#inputQueue","#internalLlm","#llm","#onPluginError","#persistence","#plugins","#overlays","#killed","#ensureLoaded","#drainInputQueue","#activeRuntimeInput","#activeRun","#activeAbort","#expireActiveOverlays","#loaded","#loadPromise","#loadSessionState","#replaceWithStoredSession","#storeVersion","#history","#pluginState","#compactions","#running","#processQueuedInput","#withSteeringPlacement","#pluginLifecycle","#withRuntimeInputWindow","#commitHistory","#drainRuntimeInput","#invokeLlm","#summarizeForPlugins","#createPluginScope"],"sources":["../../src/session/session.ts"],"sourcesContent":["import type { ModelMessage } from \"ai\";\nimport { runAgentLoop } from \"../agent-loop\";\nimport type { Llm, LlmOutput } from \"../llm\";\nimport type { ResolvedAgentPlugins } from \"../plugins/runner\";\nimport {\n type AgentPluginScope,\n runWithAgentPluginScope,\n} from \"../plugins/scope\";\nimport type { UserInput } from \"./events\";\nimport { ModelMessageHistory } from \"./history\";\nimport type { AgentInput } from \"./input\";\nimport {\n type AgentPluginErrorHandler,\n type AgentSessionLifecycle,\n createRuntimeInputStepLifecycle,\n runPluginAfterTurnHandlers,\n runPluginBeforeTurnHandlers,\n} from \"./lifecycle\";\nimport { SessionOverlayState } from \"./overlay\";\nimport type { AgentRun } from \"./run\";\nimport { BufferedAgentRun } from \"./run\";\nimport {\n addRuntimeInput,\n closeRuntimeInput,\n createRuntimeInputState,\n normalizeAgentInput,\n type RuntimeInputPlacement,\n type RuntimeInputState,\n shiftRuntimeInput,\n} from \"./runtime-input\";\nimport {\n type AgentCompactionOverlay,\n decodeStoredSessionSnapshot,\n encodeSessionSnapshot,\n} from \"./snapshot\";\nimport type { SessionStore } from \"./store/types\";\n\nexport type { AgentInput, SessionInput, UserInput } from \"./input\";\nexport type { AgentRun } from \"./run\";\n\ninterface SessionPersistenceOptions {\n readonly key: string;\n readonly store: SessionStore;\n}\n\ninterface QueuedInput {\n readonly input: UserInput;\n readonly run: BufferedAgentRun;\n readonly runtimeInput: RuntimeInputState;\n}\n\nexport class AgentSession {\n readonly #inputQueue: QueuedInput[] = [];\n readonly #internalLlm: Llm;\n readonly #llm: Llm;\n readonly #onPluginError?: AgentPluginErrorHandler;\n readonly #persistence: SessionPersistenceOptions;\n readonly #plugins?: ResolvedAgentPlugins;\n #activeAbort?: AbortController;\n #activeRun?: BufferedAgentRun;\n #activeRuntimeInput?: RuntimeInputState;\n #history = new ModelMessageHistory();\n #killed = false;\n #loadPromise?: Promise<void>;\n #loaded = false;\n #pluginState: Record<string, unknown> = {};\n #compactions: AgentCompactionOverlay[] = [];\n readonly #overlays = new SessionOverlayState();\n #running = false;\n #storeVersion: string | undefined;\n\n constructor(\n llm: Llm,\n persistence: SessionPersistenceOptions,\n plugins?: ResolvedAgentPlugins,\n internalLlm: Llm = llm,\n onPluginError?: AgentPluginErrorHandler\n ) {\n this.#internalLlm = internalLlm;\n this.#onPluginError = onPluginError;\n this.#persistence = persistence;\n this.#plugins = plugins;\n this.#llm = llm;\n }\n\n async send(input: AgentInput): Promise<AgentRun> {\n if (this.#killed) {\n throw sessionKilledError();\n }\n\n await this.#ensureLoaded();\n\n if (this.#killed) {\n throw sessionKilledError();\n }\n\n const runtimeInput = createRuntimeInputState();\n const acceptedInput = normalizeAgentInput(input);\n const run = new BufferedAgentRun();\n run.emit(acceptedInput);\n this.#inputQueue.push({\n input: structuredClone(acceptedInput),\n run,\n runtimeInput,\n });\n this.#drainInputQueue().catch((error: unknown) => {\n run.emit({ type: \"turn-error\", message: errorMessage(error) });\n run.close();\n });\n return run;\n }\n\n async steer(input: AgentInput): Promise<AgentRun> {\n if (this.#killed) {\n throw sessionKilledError();\n }\n\n const runtimeInput = this.#activeRuntimeInput;\n const run = this.#activeRun;\n if (!(runtimeInput && run)) {\n return this.send(input);\n }\n\n await addRuntimeInput(runtimeInput, input);\n return run;\n }\n\n async overlay(input: AgentInput): Promise<AgentRun> {\n if (this.#killed) {\n throw sessionKilledError();\n }\n\n await this.#ensureLoaded();\n\n if (this.#killed) {\n throw sessionKilledError();\n }\n\n const activeRun = this.#activeRun;\n if (activeRun) {\n const placement =\n this.#activeRuntimeInput?.steerPlacement ??\n this.#activeRuntimeInput?.placement ??\n \"step-end\";\n const entry = this.#overlays.appendActiveOverlay(input, placement);\n if (!entry) {\n throw new Error(\"Active overlay frame is unavailable.\");\n }\n activeRun.emit({\n input: entry.summary,\n placement: entry.placement,\n type: \"overlay-accepted\",\n });\n return activeRun;\n }\n\n const entry = this.#overlays.appendPendingOverlay(input);\n const run = new BufferedAgentRun();\n run.emit({\n input: entry.summary,\n placement: entry.placement,\n type: \"overlay-accepted\",\n });\n run.close();\n return run;\n }\n\n interrupt(): void {\n this.#activeAbort?.abort();\n }\n\n kill(): void {\n if (this.#killed) {\n return;\n }\n\n this.#killed = true;\n this.#expireActiveOverlays(\"kill\");\n this.#activeAbort?.abort();\n closeRuntimeInput(this.#activeRuntimeInput, sessionKilledError().message);\n\n while (this.#inputQueue.length > 0) {\n const item = this.#inputQueue.shift();\n closeRuntimeInput(item?.runtimeInput, sessionKilledError().message);\n item?.run.emit({\n type: \"turn-error\",\n message: sessionKilledError().message,\n });\n item?.run.close(undefined, sessionKilledError().message);\n }\n }\n\n async #ensureLoaded(): Promise<void> {\n if (this.#loaded) {\n return;\n }\n\n this.#loadPromise ??= this.#loadSessionState();\n try {\n await this.#loadPromise;\n } catch (error) {\n this.#loadPromise = undefined;\n throw error;\n }\n }\n\n async #loadSessionState(): Promise<void> {\n if (this.#loaded) {\n return;\n }\n\n await this.#replaceWithStoredSession();\n this.#loaded = true;\n }\n\n async #replaceWithStoredSession(): Promise<void> {\n const stored = await this.#persistence.store.load(this.#persistence.key);\n this.#storeVersion = stored?.version;\n const snapshot = decodeStoredSessionSnapshot(stored);\n this.#history = new ModelMessageHistory(snapshot.history);\n this.#pluginState = structuredClone(snapshot.pluginState);\n this.#compactions = structuredClone(snapshot.compactions);\n }\n\n async #drainInputQueue(): Promise<void> {\n if (this.#running) {\n return;\n }\n\n this.#running = true;\n try {\n while (!this.#killed && this.#inputQueue.length > 0) {\n const item = this.#inputQueue.shift();\n if (item) {\n await this.#processQueuedInput(item);\n }\n }\n } finally {\n this.#running = false;\n }\n }\n\n async #processQueuedInput({\n input,\n run,\n runtimeInput,\n }: QueuedInput): Promise<void> {\n const activeAbort = new AbortController();\n this.#activeAbort = activeAbort;\n const historySnapshot = this.#history.modelSnapshot();\n this.#overlays.startTurn(input, historySnapshot);\n this.#activeRun = run;\n this.#activeRuntimeInput = runtimeInput;\n\n try {\n await this.#withSteeringPlacement(\n runtimeInput,\n \"turn-start\",\n async () => {\n await runPluginBeforeTurnHandlers(this.#pluginLifecycle(), {\n input,\n runtimeInput,\n signal: activeAbort.signal,\n });\n }\n );\n await this.#withRuntimeInputWindow(\n runtimeInput,\n \"turn-start\",\n async () => {\n await run.emitBoundary({ type: \"turn-start\" });\n }\n );\n this.#history.appendUserInput(input);\n await this.#commitHistory();\n await this.#drainRuntimeInput(run, runtimeInput, \"turn-start\");\n\n const result = await runAgentLoop({\n emit: async (event) => {\n if (event.type === \"step-start\" || event.type === \"step-end\") {\n await this.#withRuntimeInputWindow(\n runtimeInput,\n event.type,\n async () => {\n await run.emitBoundary(event);\n }\n );\n const overlayInputAdded =\n event.type === \"step-end\" &&\n this.#overlays.consumeStepEndOverlayInputAdded();\n const runtimeInputAdded = await this.#drainRuntimeInput(\n run,\n runtimeInput,\n event.type\n );\n\n if (event.type === \"step-end\") {\n return {\n overlayInputAdded,\n runtimeInputAdded,\n };\n }\n return;\n }\n\n run.emit(event);\n },\n history: this.#history,\n stepLifecycle: createRuntimeInputStepLifecycle({\n lifecycle: this.#pluginLifecycle(),\n runtimeInput,\n withSteeringPlacement: (placement, callback) =>\n this.#withSteeringPlacement(runtimeInput, placement, callback),\n }),\n llm: (context) => this.#invokeLlm(context),\n signal: activeAbort.signal,\n });\n\n await this.#commitHistory();\n const terminalEvent = result === \"aborted\" ? \"turn-abort\" : \"turn-end\";\n closeRuntimeInput(runtimeInput, terminalEvent);\n this.#expireActiveOverlays(terminalEvent);\n this.#activeRuntimeInput = undefined;\n this.#activeRun = undefined;\n const pluginHandlersRan = await runPluginAfterTurnHandlers(\n this.#pluginLifecycle(),\n {\n input,\n result,\n signal: activeAbort.signal,\n }\n );\n if (pluginHandlersRan) {\n await this.#commitHistory();\n }\n run.emit({ type: terminalEvent });\n } catch (error) {\n if (error instanceof SessionCommitConflictError) {\n run.emit({ type: \"turn-error\", message: error.message });\n closeRuntimeInput(runtimeInput, \"a session commit conflict\");\n this.#expireActiveOverlays(\"turn-error\");\n this.#activeAbort = undefined;\n return;\n }\n\n this.#history.rollback(historySnapshot);\n try {\n await this.#commitHistory();\n } catch (rollbackError) {\n run.emit({\n type: \"turn-error\",\n message: `${errorMessage(error)}; history rollback persistence failed: ${errorMessage(\n rollbackError\n )}`,\n });\n closeRuntimeInput(runtimeInput, \"turn-error\");\n this.#expireActiveOverlays(\"turn-error\");\n this.#activeAbort = undefined;\n return;\n }\n run.emit({ type: \"turn-error\", message: errorMessage(error) });\n closeRuntimeInput(runtimeInput, \"turn-error\");\n this.#expireActiveOverlays(\"turn-error\");\n } finally {\n closeRuntimeInput(runtimeInput);\n this.#activeAbort = undefined;\n this.#activeRun = undefined;\n this.#activeRuntimeInput = undefined;\n this.#overlays.resetActiveTurn();\n run.close(undefined, runtimeInput.closedReason);\n }\n }\n\n async #commitHistory(): Promise<void> {\n const result = await this.#persistence.store.commit(\n this.#persistence.key,\n {\n state: encodeSessionSnapshot({\n compactions: this.#compactions,\n history: this.#history.modelSnapshot(),\n pluginState: this.#pluginState,\n }),\n },\n { expectedVersion: this.#storeVersion ?? null }\n );\n\n if (!result.ok) {\n await this.#replaceWithStoredSession();\n throw new SessionCommitConflictError(this.#persistence.key);\n }\n\n this.#storeVersion = result.version;\n }\n\n #createPluginScope(signal: AbortSignal): AgentPluginScope {\n return {\n eventHandlers: this.#plugins?.eventHandlers,\n getCompactions: () => structuredClone(this.#compactions),\n getPluginState: (pluginName) => this.#pluginState[pluginName],\n history: () => this.#history.modelSnapshot(),\n sessionKey: this.#persistence.key,\n overlay: (input) => this.overlay(input),\n setCompactions: (compactions) => {\n this.#compactions = structuredClone([...compactions]);\n },\n setPluginState: (pluginName, state) => {\n this.#pluginState = {\n ...this.#pluginState,\n [pluginName]: structuredClone(state),\n };\n },\n signal,\n steer: (input) => this.steer(input),\n summarize: (messages) => this.#summarizeForPlugins(messages, signal),\n };\n }\n\n #pluginLifecycle(): AgentSessionLifecycle {\n return {\n createScope: (signal) => this.#createPluginScope(signal),\n history: () => this.#history.modelSnapshot(),\n onPluginError: this.#onPluginError,\n plugins: this.#plugins,\n sessionKey: this.#persistence.key,\n overlaySession: (input) => this.overlay(input),\n steerCurrentRun: async (runtimeInput, input) => {\n await addRuntimeInput(runtimeInput, input);\n if (!this.#activeRun) {\n throw new Error(\"Agent plugin steering requires an active run.\");\n }\n return this.#activeRun;\n },\n steerSession: (input) => this.steer(input),\n };\n }\n\n #invokeLlm({\n history,\n signal,\n }: {\n readonly history: readonly ModelMessage[];\n readonly signal?: AbortSignal;\n }): Promise<LlmOutput> {\n const activeSignal = signal ?? new AbortController().signal;\n const invoke = async () => {\n let transformedHistory = history;\n for (const transform of this.#plugins?.contextTransforms ?? []) {\n transformedHistory = await transform({\n history: transformedHistory,\n sessionKey: this.#persistence.key,\n signal: activeSignal,\n });\n }\n\n const modelHistory = this.#overlays.compose(transformedHistory, history);\n this.#overlays.markInferenceStarted();\n return this.#llm({\n history: modelHistory,\n signal: activeSignal,\n });\n };\n\n return runWithAgentPluginScope(\n this.#createPluginScope(activeSignal),\n invoke\n );\n }\n\n async #summarizeForPlugins(\n messages: readonly ModelMessage[],\n signal: AbortSignal\n ): Promise<string> {\n const output = await this.#internalLlm({\n history: [\n {\n content:\n \"Summarize these earlier session messages for future model context.\",\n role: \"system\",\n },\n ...messages,\n ],\n signal,\n });\n return outputToText(output) || `Summarized ${messages.length} messages.`;\n }\n\n async #withRuntimeInputWindow<T>(\n runtimeInput: RuntimeInputState,\n placement: RuntimeInputPlacement,\n callback: () => Promise<T>\n ): Promise<T> {\n const previousSteerPlacement = runtimeInput.steerPlacement;\n runtimeInput.placement = placement;\n runtimeInput.steerPlacement = placement;\n try {\n return await callback();\n } finally {\n runtimeInput.placement = undefined;\n runtimeInput.steerPlacement = previousSteerPlacement;\n }\n }\n\n async #withSteeringPlacement<T>(\n runtimeInput: RuntimeInputState,\n placement: RuntimeInputPlacement,\n callback: () => Promise<T>\n ): Promise<T> {\n const previousSteerPlacement = runtimeInput.steerPlacement;\n runtimeInput.steerPlacement = placement;\n try {\n return await callback();\n } finally {\n runtimeInput.steerPlacement = previousSteerPlacement;\n }\n }\n\n async #drainRuntimeInput(\n run: BufferedAgentRun,\n runtimeInput: RuntimeInputState,\n placement: RuntimeInputPlacement\n ): Promise<boolean> {\n let added = false;\n let next = shiftRuntimeInput(runtimeInput, placement);\n while (next) {\n added = true;\n run.emit({ type: \"runtime-input\", input: next.input, placement });\n this.#history.appendUserInput(next.input);\n await this.#commitHistory();\n next = shiftRuntimeInput(runtimeInput, placement);\n }\n\n return added;\n }\n\n #expireActiveOverlays(\n reason: \"kill\" | \"turn-abort\" | \"turn-end\" | \"turn-error\"\n ): void {\n const event = this.#overlays.expireActiveFrame(reason);\n if (!event) {\n return;\n }\n\n this.#activeRun?.emit(event);\n }\n}\n\nfunction errorMessage(error: unknown): string {\n if (error instanceof Error) {\n return error.message;\n }\n\n return String(error);\n}\n\nfunction outputToText(output: LlmOutput): string {\n const parts: string[] = [];\n for (const message of output) {\n if (message.role !== \"assistant\") {\n continue;\n }\n\n if (typeof message.content === \"string\") {\n parts.push(message.content);\n continue;\n }\n\n for (const part of message.content) {\n if (part.type === \"text\") {\n parts.push(part.text);\n }\n }\n }\n\n return parts.join(\"\\n\").trim();\n}\n\nfunction sessionKilledError(): Error {\n return new Error(\"Session killed\");\n}\n\nclass SessionCommitConflictError extends Error {\n constructor(key: string) {\n super(`Session ${JSON.stringify(key)} commit conflict`);\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"session.js","names":["#events","#execution","#inputQueue","#llm","#pendingRuntimeInputs","#sessionKey","#state","#activeAbort","#killed","#deletePromise","#drainInputQueue","#activeRun","#activeRuntimeInput","#activeTurnId","#enqueuePendingRuntimeInput","#runToCloseOnKill","#running"],"sources":["../../src/session/session.ts"],"sourcesContent":["import type { RuntimeLlm } from \"../llm\";\nimport type { AgentPlugin } from \"../plugins\";\nimport type { AgentEvent } from \"./events\";\nimport type { AgentInput, UserInput } from \"./input\";\nimport { normalizeAgentInput } from \"./input-normalization\";\nimport { type AgentRun, BufferedAgentRun } from \"./run\";\nimport {\n addSteeringInput,\n createRuntimeInputState,\n type QueuedInput,\n type QueuedRuntimeInput,\n queueRuntimeInput,\n type RuntimeInputPlacement,\n type RuntimeInputState,\n} from \"./runtime-input\";\nimport { sessionKilledError, sessionTerminalError } from \"./session-errors\";\nimport { SessionEventDispatcher } from \"./session-events\";\nimport type { SessionExecutionOptions } from \"./session-execution\";\nimport { closeKilledRuntimeInputs } from \"./session-kill\";\nimport {\n type NotifyOptions,\n queueSessionNotification,\n startSessionQueueDrain,\n} from \"./session-notification\";\nimport { type SessionPersistenceOptions, SessionState } from \"./session-state\";\nimport { processQueuedInput } from \"./session-turn-processor\";\n\nexport type { AgentInput, SessionInput, UserInput } from \"./input\";\nexport type { AgentRun } from \"./run\";\nexport type { NotifyOptions } from \"./session-notification\";\n\nexport class AgentSession {\n readonly #events: SessionEventDispatcher;\n readonly #execution: SessionExecutionOptions;\n readonly #inputQueue: QueuedInput[] = [];\n readonly #llm: RuntimeLlm;\n readonly #pendingRuntimeInputs: QueuedRuntimeInput[] = [];\n readonly #sessionKey: string;\n readonly #state: SessionState;\n #activeAbort?: AbortController;\n #activeRun?: BufferedAgentRun;\n #activeRuntimeInput?: RuntimeInputState;\n #activeTurnId?: string;\n #deletePromise?: Promise<void>;\n #killed = false;\n #running = false;\n #runToCloseOnKill?: BufferedAgentRun;\n\n constructor(\n llm: RuntimeLlm,\n persistence: SessionPersistenceOptions,\n plugins: readonly AgentPlugin[] = [],\n execution: SessionExecutionOptions = {}\n ) {\n this.#llm = llm;\n this.#execution = execution;\n this.#sessionKey = persistence.key;\n this.#state = new SessionState(persistence);\n this.#events = new SessionEventDispatcher({\n history: () => this.#state.modelSnapshot(),\n plugins,\n signal: () => this.#activeAbort?.signal,\n });\n }\n\n async send(input: AgentInput): Promise<AgentRun> {\n if (this.#killed || this.#deletePromise) {\n throw sessionTerminalError(this.#killed);\n }\n\n await this.#state.ensureLoaded();\n\n if (this.#killed || this.#deletePromise) {\n throw sessionTerminalError(this.#killed);\n }\n\n const runtimeInput = createRuntimeInputState(\n this.#pendingRuntimeInputs.splice(0)\n );\n const acceptedInput = normalizeAgentInput(input);\n const run = new BufferedAgentRun();\n await this.#events.emitRunEvent(run, acceptedInput);\n this.#inputQueue.push({\n initialEvents: [],\n input: structuredClone(acceptedInput),\n preUserRuntimeInputs: [],\n run,\n runtimeInput,\n });\n startSessionQueueDrain(run, () => this.#drainInputQueue());\n return run;\n }\n\n async notify(\n input: AgentInput,\n options: NotifyOptions = {}\n ): Promise<AgentRun> {\n if (this.#killed || this.#deletePromise) {\n throw sessionTerminalError(this.#killed);\n }\n\n await this.#state.ensureLoaded();\n\n if (this.#killed || this.#deletePromise) {\n throw sessionTerminalError(this.#killed);\n }\n\n return queueSessionNotification(input, options, {\n activeRun: this.#activeRun,\n activeRuntimeInput: this.#activeRuntimeInput,\n drain: () => this.#drainInputQueue(),\n inputQueue: this.#inputQueue,\n pendingRuntimeInputs: this.#pendingRuntimeInputs,\n });\n }\n\n async steer(input: AgentInput): Promise<AgentRun> {\n if (this.#killed || this.#deletePromise) {\n throw sessionTerminalError(this.#killed);\n }\n\n const runtimeInput = this.#activeRuntimeInput;\n const run = this.#activeRun;\n if (!(runtimeInput && run)) {\n return this.send(input);\n }\n\n await addSteeringInput(runtimeInput, input);\n return run;\n }\n\n interrupt(): void {\n this.#activeAbort?.abort();\n }\n\n currentTurnId(): string | undefined {\n return this.#activeTurnId;\n }\n\n delete(): Promise<void> {\n if (!this.#deletePromise) {\n this.kill();\n this.#deletePromise = this.#state.delete().catch((error: unknown) => {\n this.#deletePromise = undefined;\n throw error;\n });\n }\n return this.#deletePromise;\n }\n\n enqueueRuntimeInput(\n input: UserInput,\n placement: RuntimeInputPlacement = \"turn-start\"\n ): void {\n if (this.#killed) {\n return;\n }\n\n const runtimeInput = this.#activeRuntimeInput;\n if (runtimeInput && !runtimeInput.closedReason) {\n if (placement === \"turn-start\" && runtimeInput.placement !== placement) {\n this.#enqueuePendingRuntimeInput({ input, placement });\n return;\n }\n\n queueRuntimeInput(runtimeInput, { input, placement });\n return;\n }\n\n this.#enqueuePendingRuntimeInput({ input, placement });\n }\n\n emitObserverEvent(event: AgentEvent): Promise<void> {\n return this.#events.emitObserverEvent(this.#activeRun, event);\n }\n\n #enqueuePendingRuntimeInput(input: QueuedRuntimeInput): void {\n const queuedTurn = this.#inputQueue[0];\n if (input.placement === \"turn-start\" && queuedTurn) {\n queueRuntimeInput(queuedTurn.runtimeInput, input);\n return;\n }\n\n this.#pendingRuntimeInputs.push(input);\n }\n\n kill(): void {\n if (this.#killed) {\n return;\n }\n\n this.#killed = true;\n const killedError = sessionKilledError();\n this.#pendingRuntimeInputs.length = 0;\n this.#activeAbort?.abort();\n closeKilledRuntimeInputs({\n activeRuntimeInput: this.#activeRuntimeInput,\n inputQueue: this.#inputQueue,\n message: killedError.message,\n runToClose: this.#runToCloseOnKill ?? this.#activeRun,\n });\n }\n\n async #drainInputQueue(): Promise<void> {\n if (this.#running) {\n return;\n }\n\n this.#running = true;\n try {\n while (!this.#killed && this.#inputQueue.length > 0) {\n const item = this.#inputQueue.shift();\n if (item) {\n await processQueuedInput({\n activate: ({ abort, run, runtimeInput, turnId }) => {\n this.#activeAbort = abort;\n this.#activeRun = run;\n this.#activeRuntimeInput = runtimeInput;\n this.#activeTurnId = turnId;\n this.#runToCloseOnKill = run;\n },\n deactivateRun: () => {\n this.#activeRun = undefined;\n this.#activeRuntimeInput = undefined;\n },\n events: this.#events,\n execution: this.#execution,\n item,\n llm: this.#llm,\n release: () => {\n this.#activeAbort = undefined;\n this.#activeRun = undefined;\n this.#activeRuntimeInput = undefined;\n this.#activeTurnId = undefined;\n this.#runToCloseOnKill = undefined;\n },\n sessionKey: this.#sessionKey,\n state: this.#state,\n });\n }\n }\n } finally {\n this.#running = false;\n }\n }\n}\n"],"mappings":"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"}
|
package/dist/session/snapshot.js
CHANGED
|
@@ -1,45 +1,19 @@
|
|
|
1
1
|
//#region src/session/snapshot.ts
|
|
2
|
-
function encodeSessionSnapshot(
|
|
2
|
+
function encodeSessionSnapshot(history) {
|
|
3
3
|
return {
|
|
4
|
-
|
|
5
|
-
history: structuredClone(
|
|
6
|
-
pluginState: structuredClone({ ...state.pluginState ?? {} }),
|
|
7
|
-
schemaVersion: 2
|
|
4
|
+
schemaVersion: 1,
|
|
5
|
+
history: structuredClone(history)
|
|
8
6
|
};
|
|
9
7
|
}
|
|
10
8
|
function decodeStoredSessionSnapshot(stored) {
|
|
11
|
-
if (!stored) return
|
|
9
|
+
if (!stored) return [];
|
|
12
10
|
const snapshot = stored.state;
|
|
13
|
-
if (isSessionSnapshotV1(snapshot)) return
|
|
14
|
-
...emptySnapshotState(),
|
|
15
|
-
history: structuredClone(snapshot.history)
|
|
16
|
-
};
|
|
17
|
-
if (isSessionSnapshotV2(snapshot)) return {
|
|
18
|
-
compactions: structuredClone(snapshot.compactions),
|
|
19
|
-
history: structuredClone(snapshot.history),
|
|
20
|
-
pluginState: structuredClone(snapshot.pluginState)
|
|
21
|
-
};
|
|
11
|
+
if (isSessionSnapshotV1(snapshot)) return structuredClone(snapshot.history);
|
|
22
12
|
throw new Error("Unsupported stored session state");
|
|
23
13
|
}
|
|
24
|
-
function emptySnapshotState() {
|
|
25
|
-
return {
|
|
26
|
-
compactions: [],
|
|
27
|
-
history: [],
|
|
28
|
-
pluginState: {}
|
|
29
|
-
};
|
|
30
|
-
}
|
|
31
14
|
function isSessionSnapshotV1(value) {
|
|
32
15
|
return value !== null && typeof value === "object" && "schemaVersion" in value && value.schemaVersion === 1 && "history" in value && Array.isArray(value.history);
|
|
33
16
|
}
|
|
34
|
-
function isSessionSnapshotV2(value) {
|
|
35
|
-
return value !== null && typeof value === "object" && "schemaVersion" in value && value.schemaVersion === 2 && "history" in value && Array.isArray(value.history) && "pluginState" in value && isRecord(value.pluginState) && "compactions" in value && Array.isArray(value.compactions) && value.compactions.every(isCompactionOverlay);
|
|
36
|
-
}
|
|
37
|
-
function isCompactionOverlay(value) {
|
|
38
|
-
return value !== null && typeof value === "object" && "createdAt" in value && typeof value.createdAt === "string" && "endIndex" in value && typeof value.endIndex === "number" && "id" in value && typeof value.id === "string" && "startIndex" in value && typeof value.startIndex === "number" && "summary" in value && typeof value.summary === "string";
|
|
39
|
-
}
|
|
40
|
-
function isRecord(value) {
|
|
41
|
-
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
42
|
-
}
|
|
43
17
|
//#endregion
|
|
44
18
|
export { decodeStoredSessionSnapshot, encodeSessionSnapshot };
|
|
45
19
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"snapshot.js","names":[],"sources":["../../src/session/snapshot.ts"],"sourcesContent":["import type { ModelMessage } from \"ai\";\nimport type { StoredSession } from \"./store/types\";\n\nexport interface AgentSessionSnapshotV1 {\n readonly history: ModelMessage[];\n readonly schemaVersion: 1;\n}\n\nexport
|
|
1
|
+
{"version":3,"file":"snapshot.js","names":[],"sources":["../../src/session/snapshot.ts"],"sourcesContent":["import type { ModelMessage } from \"ai\";\nimport type { StoredSession } from \"./store/types\";\n\nexport interface AgentSessionSnapshotV1 {\n readonly history: ModelMessage[];\n readonly schemaVersion: 1;\n}\n\nexport function encodeSessionSnapshot(\n history: ModelMessage[]\n): AgentSessionSnapshotV1 {\n return { schemaVersion: 1, history: structuredClone(history) };\n}\n\nexport function decodeStoredSessionSnapshot(\n stored: StoredSession | null\n): ModelMessage[] {\n if (!stored) {\n return [];\n }\n\n const snapshot = stored.state;\n if (isSessionSnapshotV1(snapshot)) {\n return structuredClone(snapshot.history);\n }\n\n throw new Error(\"Unsupported stored session state\");\n}\n\nfunction isSessionSnapshotV1(value: unknown): value is AgentSessionSnapshotV1 {\n return (\n value !== null &&\n typeof value === \"object\" &&\n \"schemaVersion\" in value &&\n value.schemaVersion === 1 &&\n \"history\" in value &&\n Array.isArray(value.history)\n );\n}\n"],"mappings":";AAQA,SAAgB,sBACd,SACwB;CACxB,OAAO;EAAE,eAAe;EAAG,SAAS,gBAAgB,OAAO;CAAE;AAC/D;AAEA,SAAgB,4BACd,QACgB;CAChB,IAAI,CAAC,QACH,OAAO,CAAC;CAGV,MAAM,WAAW,OAAO;CACxB,IAAI,oBAAoB,QAAQ,GAC9B,OAAO,gBAAgB,SAAS,OAAO;CAGzC,MAAM,IAAI,MAAM,kCAAkC;AACpD;AAEA,SAAS,oBAAoB,OAAiD;CAC5E,OACE,UAAU,QACV,OAAO,UAAU,YACjB,mBAAmB,SACnB,MAAM,kBAAkB,KACxB,aAAa,SACb,MAAM,QAAQ,MAAM,OAAO;AAE/B"}
|
|
@@ -8,6 +8,7 @@ declare class FileSessionStore implements SessionStore {
|
|
|
8
8
|
commit(key: string, next: SessionStoreCommit, options: {
|
|
9
9
|
expectedVersion: string | null;
|
|
10
10
|
}): Promise<CommitResult>;
|
|
11
|
+
delete(key: string): Promise<void>;
|
|
11
12
|
}
|
|
12
13
|
//#endregion
|
|
13
14
|
export { FileSessionStore };
|
|
@@ -57,6 +57,20 @@ var FileSessionStore = class {
|
|
|
57
57
|
});
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
|
+
async delete(key) {
|
|
61
|
+
const file = this.#fileForKey(key);
|
|
62
|
+
const lockDirectory = `${file}.lock`;
|
|
63
|
+
await mkdir(dirname(file), { recursive: true });
|
|
64
|
+
await acquireFileLock(lockDirectory);
|
|
65
|
+
try {
|
|
66
|
+
await rm(file, { force: true });
|
|
67
|
+
} finally {
|
|
68
|
+
await rm(lockDirectory, {
|
|
69
|
+
force: true,
|
|
70
|
+
recursive: true
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
}
|
|
60
74
|
#fileForKey(key) {
|
|
61
75
|
return join(this.#directory, `${Buffer.from(key).toString("base64url")}.json`);
|
|
62
76
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"file.js","names":["#directory","#fileForKey"],"sources":["../../../src/session/store/file.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { mkdir, readFile, rename, rm, stat, writeFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport { setTimeout } from \"node:timers/promises\";\nimport type {\n CommitResult,\n SessionStore,\n SessionStoreCommit,\n StoredSession,\n} from \"./types\";\n\nconst LOCK_POLL_INTERVAL_MS = 10;\nconst LOCK_STALE_AFTER_MS = 30_000;\nconst LOCK_TIMEOUT_MS = 5000;\n\nexport class FileSessionStore implements SessionStore {\n readonly #directory: string;\n\n constructor(directory: string) {\n this.#directory = directory;\n }\n\n async load(key: string): Promise<StoredSession | null> {\n const file = this.#fileForKey(key);\n\n try {\n const parsed = JSON.parse(await readFile(file, \"utf8\")) as unknown;\n return parseStoredFileSession(parsed, file);\n } catch (error) {\n if (isNodeError(error) && error.code === \"ENOENT\") {\n return null;\n }\n if (error instanceof SyntaxError) {\n throw new Error(\n `Invalid FileSessionStore file ${JSON.stringify(\n file\n )}: invalid JSON (${error.message})`\n );\n }\n throw error;\n }\n }\n\n async commit(\n key: string,\n next: SessionStoreCommit,\n options: { expectedVersion: string | null }\n ): Promise<CommitResult> {\n const file = this.#fileForKey(key);\n const lockDirectory = `${file}.lock`;\n await mkdir(dirname(file), { recursive: true });\n await acquireFileLock(lockDirectory);\n try {\n const current = await this.load(key);\n const currentVersion = current?.version ?? null;\n\n if (options.expectedVersion !== currentVersion) {\n return { ok: false, reason: \"conflict\" };\n }\n\n const version = String((Number(current?.version ?? \"0\") || 0) + 1);\n const payload: StoredSession = structuredClone({\n state: next.state,\n version,\n });\n const tempFile = `${file}.${process.pid}.${randomUUID()}.tmp`;\n\n try {\n await writeFile(\n tempFile,\n `${JSON.stringify(payload, null, 2)}\\n`,\n \"utf8\"\n );\n await rename(tempFile, file);\n } catch (error) {\n await rm(tempFile, { force: true }).catch(() => undefined);\n throw error;\n }\n\n return { ok: true, version };\n } finally {\n await rm(lockDirectory, { force: true, recursive: true });\n }\n }\n\n #fileForKey(key: string): string {\n return join(\n this.#directory,\n `${Buffer.from(key).toString(\"base64url\")}.json`\n );\n }\n}\n\nfunction parseStoredFileSession(value: unknown, file: string): StoredSession {\n if (value === null || typeof value !== \"object\") {\n throw new Error(\n `Invalid FileSessionStore file ${JSON.stringify(\n file\n )}: expected an object`\n );\n }\n\n const candidate = value as Partial<StoredSession>;\n if (typeof candidate.version !== \"string\" || !(\"state\" in candidate)) {\n throw new Error(\n `Invalid FileSessionStore file ${JSON.stringify(\n file\n )}: expected state and string version`\n );\n }\n\n return structuredClone({\n state: candidate.state,\n version: candidate.version,\n });\n}\n\nfunction isNodeError(error: unknown): error is NodeJS.ErrnoException {\n return error instanceof Error && \"code\" in error;\n}\n\nasync function acquireFileLock(lockDirectory: string): Promise<void> {\n const startedAt = Date.now();\n while (Date.now() - startedAt < LOCK_TIMEOUT_MS) {\n try {\n await mkdir(lockDirectory);\n return;\n } catch (error) {\n if (!(isNodeError(error) && error.code === \"EEXIST\")) {\n throw error;\n }\n await removeStaleLock(lockDirectory);\n }\n\n await setTimeout(LOCK_POLL_INTERVAL_MS);\n }\n\n throw new Error(\n `Timed out waiting for FileSessionStore lock ${JSON.stringify(\n lockDirectory\n )}`\n );\n}\n\nasync function removeStaleLock(lockDirectory: string): Promise<void> {\n try {\n const stats = await stat(lockDirectory);\n if (Date.now() - stats.mtimeMs < LOCK_STALE_AFTER_MS) {\n return;\n }\n await rm(lockDirectory, { force: true, recursive: true });\n } catch (error) {\n if (isNodeError(error) && error.code === \"ENOENT\") {\n return;\n }\n throw error;\n }\n}\n"],"mappings":";;;;;AAWA,MAAM,wBAAwB;AAC9B,MAAM,sBAAsB;AAC5B,MAAM,kBAAkB;AAExB,IAAa,mBAAb,MAAsD;CACpD;CAEA,YAAY,WAAmB;EAC7B,KAAKA,aAAa;CACpB;CAEA,MAAM,KAAK,KAA4C;EACrD,MAAM,OAAO,KAAKC,YAAY,GAAG;EAEjC,IAAI;GAEF,OAAO,uBADQ,KAAK,MAAM,MAAM,SAAS,MAAM,MAAM,CAClB,GAAG,IAAI;EAC5C,SAAS,OAAO;GACd,IAAI,YAAY,KAAK,KAAK,MAAM,SAAS,UACvC,OAAO;GAET,IAAI,iBAAiB,aACnB,MAAM,IAAI,MACR,iCAAiC,KAAK,UACpC,IACF,EAAE,kBAAkB,MAAM,QAAQ,EACpC;GAEF,MAAM;EACR;CACF;CAEA,MAAM,OACJ,KACA,MACA,SACuB;EACvB,MAAM,OAAO,KAAKA,YAAY,GAAG;EACjC,MAAM,gBAAgB,GAAG,KAAK;EAC9B,MAAM,MAAM,QAAQ,IAAI,GAAG,EAAE,WAAW,KAAK,CAAC;EAC9C,MAAM,gBAAgB,aAAa;EACnC,IAAI;GACF,MAAM,UAAU,MAAM,KAAK,KAAK,GAAG;GACnC,MAAM,iBAAiB,SAAS,WAAW;GAE3C,IAAI,QAAQ,oBAAoB,gBAC9B,OAAO;IAAE,IAAI;IAAO,QAAQ;GAAW;GAGzC,MAAM,UAAU,QAAQ,OAAO,SAAS,WAAW,GAAG,KAAK,KAAK,CAAC;GACjE,MAAM,UAAyB,gBAAgB;IAC7C,OAAO,KAAK;IACZ;GACF,CAAC;GACD,MAAM,WAAW,GAAG,KAAK,GAAG,QAAQ,IAAI,GAAG,WAAW,EAAE;GAExD,IAAI;IACF,MAAM,UACJ,UACA,GAAG,KAAK,UAAU,SAAS,MAAM,CAAC,EAAE,KACpC,MACF;IACA,MAAM,OAAO,UAAU,IAAI;GAC7B,SAAS,OAAO;IACd,MAAM,GAAG,UAAU,EAAE,OAAO,KAAK,CAAC,EAAE,YAAY,KAAA,CAAS;IACzD,MAAM;GACR;GAEA,OAAO;IAAE,IAAI;IAAM;GAAQ;EAC7B,UAAU;GACR,MAAM,GAAG,eAAe;IAAE,OAAO;IAAM,WAAW;GAAK,CAAC;EAC1D;CACF;CAEA,YAAY,KAAqB;EAC/B,OAAO,KACL,KAAKD,YACL,GAAG,OAAO,KAAK,GAAG,EAAE,SAAS,WAAW,EAAE,MAC5C;CACF;AACF;AAEA,SAAS,uBAAuB,OAAgB,MAA6B;CAC3E,IAAI,UAAU,QAAQ,OAAO,UAAU,UACrC,MAAM,IAAI,MACR,iCAAiC,KAAK,UACpC,IACF,EAAE,qBACJ;CAGF,MAAM,YAAY;CAClB,IAAI,OAAO,UAAU,YAAY,YAAY,EAAE,WAAW,YACxD,MAAM,IAAI,MACR,iCAAiC,KAAK,UACpC,IACF,EAAE,oCACJ;CAGF,OAAO,gBAAgB;EACrB,OAAO,UAAU;EACjB,SAAS,UAAU;CACrB,CAAC;AACH;AAEA,SAAS,YAAY,OAAgD;CACnE,OAAO,iBAAiB,SAAS,UAAU;AAC7C;AAEA,eAAe,gBAAgB,eAAsC;CACnE,MAAM,YAAY,KAAK,IAAI;CAC3B,OAAO,KAAK,IAAI,IAAI,YAAY,iBAAiB;EAC/C,IAAI;GACF,MAAM,MAAM,aAAa;GACzB;EACF,SAAS,OAAO;GACd,IAAI,EAAE,YAAY,KAAK,KAAK,MAAM,SAAS,WACzC,MAAM;GAER,MAAM,gBAAgB,aAAa;EACrC;EAEA,MAAM,WAAW,qBAAqB;CACxC;CAEA,MAAM,IAAI,MACR,+CAA+C,KAAK,UAClD,aACF,GACF;AACF;AAEA,eAAe,gBAAgB,eAAsC;CACnE,IAAI;EACF,MAAM,QAAQ,MAAM,KAAK,aAAa;EACtC,IAAI,KAAK,IAAI,IAAI,MAAM,UAAU,qBAC/B;EAEF,MAAM,GAAG,eAAe;GAAE,OAAO;GAAM,WAAW;EAAK,CAAC;CAC1D,SAAS,OAAO;EACd,IAAI,YAAY,KAAK,KAAK,MAAM,SAAS,UACvC;EAEF,MAAM;CACR;AACF"}
|
|
1
|
+
{"version":3,"file":"file.js","names":["#directory","#fileForKey"],"sources":["../../../src/session/store/file.ts"],"sourcesContent":["import { randomUUID } from \"node:crypto\";\nimport { mkdir, readFile, rename, rm, stat, writeFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport { setTimeout } from \"node:timers/promises\";\nimport type {\n CommitResult,\n SessionStore,\n SessionStoreCommit,\n StoredSession,\n} from \"./types\";\n\nconst LOCK_POLL_INTERVAL_MS = 10;\nconst LOCK_STALE_AFTER_MS = 30_000;\nconst LOCK_TIMEOUT_MS = 5000;\n\nexport class FileSessionStore implements SessionStore {\n readonly #directory: string;\n\n constructor(directory: string) {\n this.#directory = directory;\n }\n\n async load(key: string): Promise<StoredSession | null> {\n const file = this.#fileForKey(key);\n\n try {\n const parsed = JSON.parse(await readFile(file, \"utf8\")) as unknown;\n return parseStoredFileSession(parsed, file);\n } catch (error) {\n if (isNodeError(error) && error.code === \"ENOENT\") {\n return null;\n }\n if (error instanceof SyntaxError) {\n throw new Error(\n `Invalid FileSessionStore file ${JSON.stringify(\n file\n )}: invalid JSON (${error.message})`\n );\n }\n throw error;\n }\n }\n\n async commit(\n key: string,\n next: SessionStoreCommit,\n options: { expectedVersion: string | null }\n ): Promise<CommitResult> {\n const file = this.#fileForKey(key);\n const lockDirectory = `${file}.lock`;\n await mkdir(dirname(file), { recursive: true });\n await acquireFileLock(lockDirectory);\n try {\n const current = await this.load(key);\n const currentVersion = current?.version ?? null;\n\n if (options.expectedVersion !== currentVersion) {\n return { ok: false, reason: \"conflict\" };\n }\n\n const version = String((Number(current?.version ?? \"0\") || 0) + 1);\n const payload: StoredSession = structuredClone({\n state: next.state,\n version,\n });\n const tempFile = `${file}.${process.pid}.${randomUUID()}.tmp`;\n\n try {\n await writeFile(\n tempFile,\n `${JSON.stringify(payload, null, 2)}\\n`,\n \"utf8\"\n );\n await rename(tempFile, file);\n } catch (error) {\n await rm(tempFile, { force: true }).catch(() => undefined);\n throw error;\n }\n\n return { ok: true, version };\n } finally {\n await rm(lockDirectory, { force: true, recursive: true });\n }\n }\n\n async delete(key: string): Promise<void> {\n const file = this.#fileForKey(key);\n const lockDirectory = `${file}.lock`;\n await mkdir(dirname(file), { recursive: true });\n await acquireFileLock(lockDirectory);\n try {\n await rm(file, { force: true });\n } finally {\n await rm(lockDirectory, { force: true, recursive: true });\n }\n }\n\n #fileForKey(key: string): string {\n return join(\n this.#directory,\n `${Buffer.from(key).toString(\"base64url\")}.json`\n );\n }\n}\n\nfunction parseStoredFileSession(value: unknown, file: string): StoredSession {\n if (value === null || typeof value !== \"object\") {\n throw new Error(\n `Invalid FileSessionStore file ${JSON.stringify(\n file\n )}: expected an object`\n );\n }\n\n const candidate = value as Partial<StoredSession>;\n if (typeof candidate.version !== \"string\" || !(\"state\" in candidate)) {\n throw new Error(\n `Invalid FileSessionStore file ${JSON.stringify(\n file\n )}: expected state and string version`\n );\n }\n\n return structuredClone({\n state: candidate.state,\n version: candidate.version,\n });\n}\n\nfunction isNodeError(error: unknown): error is NodeJS.ErrnoException {\n return error instanceof Error && \"code\" in error;\n}\n\nasync function acquireFileLock(lockDirectory: string): Promise<void> {\n const startedAt = Date.now();\n while (Date.now() - startedAt < LOCK_TIMEOUT_MS) {\n try {\n await mkdir(lockDirectory);\n return;\n } catch (error) {\n if (!(isNodeError(error) && error.code === \"EEXIST\")) {\n throw error;\n }\n await removeStaleLock(lockDirectory);\n }\n\n await setTimeout(LOCK_POLL_INTERVAL_MS);\n }\n\n throw new Error(\n `Timed out waiting for FileSessionStore lock ${JSON.stringify(\n lockDirectory\n )}`\n );\n}\n\nasync function removeStaleLock(lockDirectory: string): Promise<void> {\n try {\n const stats = await stat(lockDirectory);\n if (Date.now() - stats.mtimeMs < LOCK_STALE_AFTER_MS) {\n return;\n }\n await rm(lockDirectory, { force: true, recursive: true });\n } catch (error) {\n if (isNodeError(error) && error.code === \"ENOENT\") {\n return;\n }\n throw error;\n }\n}\n"],"mappings":"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"}
|
|
@@ -4,6 +4,7 @@ import { CommitResult, SessionStore, SessionStoreCommit, StoredSession } from ".
|
|
|
4
4
|
declare class MemorySessionStore implements SessionStore {
|
|
5
5
|
#private;
|
|
6
6
|
load(key: string): Promise<StoredSession | null>;
|
|
7
|
+
delete(key: string): Promise<void>;
|
|
7
8
|
commit(key: string, next: SessionStoreCommit, options: {
|
|
8
9
|
expectedVersion: string | null;
|
|
9
10
|
}): Promise<CommitResult>;
|
|
@@ -6,6 +6,11 @@ var MemorySessionStore = class {
|
|
|
6
6
|
const stored = this.#sessions.get(key);
|
|
7
7
|
return Promise.resolve(stored ? structuredClone(stored) : null);
|
|
8
8
|
}
|
|
9
|
+
delete(key) {
|
|
10
|
+
this.#sessions.delete(key);
|
|
11
|
+
this.#versions.delete(key);
|
|
12
|
+
return Promise.resolve();
|
|
13
|
+
}
|
|
9
14
|
commit(key, next, options) {
|
|
10
15
|
const currentVersion = this.#sessions.get(key)?.version ?? null;
|
|
11
16
|
if (options.expectedVersion !== currentVersion) return Promise.resolve({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"memory.js","names":["#sessions","#versions"],"sources":["../../../src/session/store/memory.ts"],"sourcesContent":["import type {\n CommitResult,\n SessionStore,\n SessionStoreCommit,\n StoredSession,\n} from \"./types\";\n\nexport class MemorySessionStore implements SessionStore {\n readonly #sessions = new Map<string, StoredSession>();\n readonly #versions = new Map<string, number>();\n\n load(key: string): Promise<StoredSession | null> {\n const stored = this.#sessions.get(key);\n return Promise.resolve(stored ? structuredClone(stored) : null);\n }\n\n commit(\n key: string,\n next: SessionStoreCommit,\n options: { expectedVersion: string | null }\n ): Promise<CommitResult> {\n const current = this.#sessions.get(key);\n const currentVersion = current?.version ?? null;\n\n if (options.expectedVersion !== currentVersion) {\n return Promise.resolve({ ok: false, reason: \"conflict\" });\n }\n\n const versionNumber = (this.#versions.get(key) ?? 0) + 1;\n const version = String(versionNumber);\n this.#versions.set(key, versionNumber);\n this.#sessions.set(key, structuredClone({ state: next.state, version }));\n return Promise.resolve({ ok: true, version });\n }\n}\n"],"mappings":";AAOA,IAAa,qBAAb,MAAwD;CACtD,4BAAqB,IAAI,IAA2B;CACpD,4BAAqB,IAAI,IAAoB;CAE7C,KAAK,KAA4C;EAC/C,MAAM,SAAS,KAAKA,UAAU,IAAI,GAAG;EACrC,OAAO,QAAQ,QAAQ,SAAS,gBAAgB,MAAM,IAAI,IAAI;CAChE;CAEA,OACE,KACA,MACA,SACuB;EAEvB,MAAM,iBADU,
|
|
1
|
+
{"version":3,"file":"memory.js","names":["#sessions","#versions"],"sources":["../../../src/session/store/memory.ts"],"sourcesContent":["import type {\n CommitResult,\n SessionStore,\n SessionStoreCommit,\n StoredSession,\n} from \"./types\";\n\nexport class MemorySessionStore implements SessionStore {\n readonly #sessions = new Map<string, StoredSession>();\n readonly #versions = new Map<string, number>();\n\n load(key: string): Promise<StoredSession | null> {\n const stored = this.#sessions.get(key);\n return Promise.resolve(stored ? structuredClone(stored) : null);\n }\n\n delete(key: string): Promise<void> {\n this.#sessions.delete(key);\n this.#versions.delete(key);\n return Promise.resolve();\n }\n\n commit(\n key: string,\n next: SessionStoreCommit,\n options: { expectedVersion: string | null }\n ): Promise<CommitResult> {\n const current = this.#sessions.get(key);\n const currentVersion = current?.version ?? null;\n\n if (options.expectedVersion !== currentVersion) {\n return Promise.resolve({ ok: false, reason: \"conflict\" });\n }\n\n const versionNumber = (this.#versions.get(key) ?? 0) + 1;\n const version = String(versionNumber);\n this.#versions.set(key, versionNumber);\n this.#sessions.set(key, structuredClone({ state: next.state, version }));\n return Promise.resolve({ ok: true, version });\n }\n}\n"],"mappings":";AAOA,IAAa,qBAAb,MAAwD;CACtD,4BAAqB,IAAI,IAA2B;CACpD,4BAAqB,IAAI,IAAoB;CAE7C,KAAK,KAA4C;EAC/C,MAAM,SAAS,KAAKA,UAAU,IAAI,GAAG;EACrC,OAAO,QAAQ,QAAQ,SAAS,gBAAgB,MAAM,IAAI,IAAI;CAChE;CAEA,OAAO,KAA4B;EACjC,KAAKA,UAAU,OAAO,GAAG;EACzB,KAAKC,UAAU,OAAO,GAAG;EACzB,OAAO,QAAQ,QAAQ;CACzB;CAEA,OACE,KACA,MACA,SACuB;EAEvB,MAAM,iBADU,KAAKD,UAAU,IAAI,GACN,GAAG,WAAW;EAE3C,IAAI,QAAQ,oBAAoB,gBAC9B,OAAO,QAAQ,QAAQ;GAAE,IAAI;GAAO,QAAQ;EAAW,CAAC;EAG1D,MAAM,iBAAiB,KAAKC,UAAU,IAAI,GAAG,KAAK,KAAK;EACvD,MAAM,UAAU,OAAO,aAAa;EACpC,KAAKA,UAAU,IAAI,KAAK,aAAa;EACrC,KAAKD,UAAU,IAAI,KAAK,gBAAgB;GAAE,OAAO,KAAK;GAAO;EAAQ,CAAC,CAAC;EACvE,OAAO,QAAQ,QAAQ;GAAE,IAAI;GAAM;EAAQ,CAAC;CAC9C;AACF"}
|
|
@@ -18,6 +18,7 @@ interface SessionStore {
|
|
|
18
18
|
commit(key: string, next: SessionStoreCommit, options: {
|
|
19
19
|
expectedVersion: ExpectedSessionVersion;
|
|
20
20
|
}): Promise<CommitResult>;
|
|
21
|
+
delete(key: string): Promise<void>;
|
|
21
22
|
load(key: string): Promise<StoredSession | null>;
|
|
22
23
|
}
|
|
23
24
|
//#endregion
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
//#region src/subagent-background-child-run-state.ts
|
|
2
|
+
function durableBackgroundChildRunState({ delegateToolCallId, description, groupId, parentSessionKey, prompt, subagent }) {
|
|
3
|
+
return {
|
|
4
|
+
...delegateToolCallId ? { delegateToolCallId } : {},
|
|
5
|
+
...description ? { description } : {},
|
|
6
|
+
...groupId ? { groupId } : {},
|
|
7
|
+
kind: "background-subagent",
|
|
8
|
+
...parentSessionKey ? { parentSessionKey } : {},
|
|
9
|
+
prompt: structuredClone(prompt),
|
|
10
|
+
subagent: subagent ?? "subagent"
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
function readDurableBackgroundChildRunState(checkpoint) {
|
|
14
|
+
const state = checkpoint?.runtimeState;
|
|
15
|
+
if (!isRecord(state) || state.kind !== "background-subagent") return null;
|
|
16
|
+
if (!isAgentInput(state.prompt) || typeof state.subagent !== "string") return null;
|
|
17
|
+
return {
|
|
18
|
+
...typeof state.delegateToolCallId === "string" ? { delegateToolCallId: state.delegateToolCallId } : {},
|
|
19
|
+
...typeof state.description === "string" ? { description: state.description } : {},
|
|
20
|
+
...typeof state.groupId === "string" ? { groupId: state.groupId } : {},
|
|
21
|
+
kind: "background-subagent",
|
|
22
|
+
...typeof state.parentSessionKey === "string" ? { parentSessionKey: state.parentSessionKey } : {},
|
|
23
|
+
prompt: state.prompt,
|
|
24
|
+
subagent: state.subagent
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
function isAgentInput(value) {
|
|
28
|
+
return typeof value === "string" || isStringArray(value) || isUserInput(value) || isMessageContent(value);
|
|
29
|
+
}
|
|
30
|
+
function isUserInput(value) {
|
|
31
|
+
if (!isRecord(value)) return false;
|
|
32
|
+
if (value.type === "user-text") return typeof value.text === "string" || isStringArray(value.text);
|
|
33
|
+
return value.type === "user-message" && isMessageContent(value.content);
|
|
34
|
+
}
|
|
35
|
+
function isMessageContent(value) {
|
|
36
|
+
return Array.isArray(value) && value.every(isMessageContentPart);
|
|
37
|
+
}
|
|
38
|
+
function isMessageContentPart(value) {
|
|
39
|
+
if (!isRecord(value) || typeof value.type !== "string") return false;
|
|
40
|
+
return value.type === "text" || value.type === "image" || value.type === "file";
|
|
41
|
+
}
|
|
42
|
+
function isRecord(value) {
|
|
43
|
+
return typeof value === "object" && value !== null;
|
|
44
|
+
}
|
|
45
|
+
function isStringArray(value) {
|
|
46
|
+
return Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
47
|
+
}
|
|
48
|
+
//#endregion
|
|
49
|
+
export { durableBackgroundChildRunState, readDurableBackgroundChildRunState };
|
|
50
|
+
|
|
51
|
+
//# sourceMappingURL=subagent-background-child-run-state.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subagent-background-child-run-state.js","names":[],"sources":["../src/subagent-background-child-run-state.ts"],"sourcesContent":["import type { RunCheckpoint } from \"./execution/types\";\nimport type { AgentInput } from \"./session/input\";\n\nexport interface DurableBackgroundChildRunState {\n readonly delegateToolCallId?: string;\n readonly description?: string;\n readonly groupId?: string;\n readonly kind: \"background-subagent\";\n readonly parentSessionKey?: string;\n readonly prompt: AgentInput;\n readonly subagent: string;\n}\n\nexport function durableBackgroundChildRunState({\n delegateToolCallId,\n description,\n groupId,\n parentSessionKey,\n prompt,\n subagent,\n}: {\n readonly delegateToolCallId?: string;\n readonly description?: string;\n readonly groupId?: string;\n readonly parentSessionKey?: string;\n readonly prompt: AgentInput;\n readonly subagent?: string;\n}): DurableBackgroundChildRunState {\n return {\n ...(delegateToolCallId ? { delegateToolCallId } : {}),\n ...(description ? { description } : {}),\n ...(groupId ? { groupId } : {}),\n kind: \"background-subagent\",\n ...(parentSessionKey ? { parentSessionKey } : {}),\n prompt: structuredClone(prompt),\n subagent: subagent ?? \"subagent\",\n };\n}\n\nexport function readDurableBackgroundChildRunState(\n checkpoint: RunCheckpoint | null\n): DurableBackgroundChildRunState | null {\n const state = checkpoint?.runtimeState;\n if (!isRecord(state) || state.kind !== \"background-subagent\") {\n return null;\n }\n\n if (!isAgentInput(state.prompt) || typeof state.subagent !== \"string\") {\n return null;\n }\n\n return {\n ...(typeof state.delegateToolCallId === \"string\"\n ? { delegateToolCallId: state.delegateToolCallId }\n : {}),\n ...(typeof state.description === \"string\"\n ? { description: state.description }\n : {}),\n ...(typeof state.groupId === \"string\" ? { groupId: state.groupId } : {}),\n kind: \"background-subagent\",\n ...(typeof state.parentSessionKey === \"string\"\n ? { parentSessionKey: state.parentSessionKey }\n : {}),\n prompt: state.prompt,\n subagent: state.subagent,\n };\n}\n\nfunction isAgentInput(value: unknown): value is AgentInput {\n return (\n typeof value === \"string\" ||\n isStringArray(value) ||\n isUserInput(value) ||\n isMessageContent(value)\n );\n}\n\nfunction isUserInput(value: unknown): boolean {\n if (!isRecord(value)) {\n return false;\n }\n\n if (value.type === \"user-text\") {\n return typeof value.text === \"string\" || isStringArray(value.text);\n }\n\n return value.type === \"user-message\" && isMessageContent(value.content);\n}\n\nfunction isMessageContent(value: unknown): boolean {\n return Array.isArray(value) && value.every(isMessageContentPart);\n}\n\nfunction isMessageContentPart(value: unknown): boolean {\n if (!isRecord(value) || typeof value.type !== \"string\") {\n return false;\n }\n\n return (\n value.type === \"text\" || value.type === \"image\" || value.type === \"file\"\n );\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction isStringArray(value: unknown): value is readonly string[] {\n return (\n Array.isArray(value) && value.every((item) => typeof item === \"string\")\n );\n}\n"],"mappings":";AAaA,SAAgB,+BAA+B,EAC7C,oBACA,aACA,SACA,kBACA,QACA,YAQiC;CACjC,OAAO;EACL,GAAI,qBAAqB,EAAE,mBAAmB,IAAI,CAAC;EACnD,GAAI,cAAc,EAAE,YAAY,IAAI,CAAC;EACrC,GAAI,UAAU,EAAE,QAAQ,IAAI,CAAC;EAC7B,MAAM;EACN,GAAI,mBAAmB,EAAE,iBAAiB,IAAI,CAAC;EAC/C,QAAQ,gBAAgB,MAAM;EAC9B,UAAU,YAAY;CACxB;AACF;AAEA,SAAgB,mCACd,YACuC;CACvC,MAAM,QAAQ,YAAY;CAC1B,IAAI,CAAC,SAAS,KAAK,KAAK,MAAM,SAAS,uBACrC,OAAO;CAGT,IAAI,CAAC,aAAa,MAAM,MAAM,KAAK,OAAO,MAAM,aAAa,UAC3D,OAAO;CAGT,OAAO;EACL,GAAI,OAAO,MAAM,uBAAuB,WACpC,EAAE,oBAAoB,MAAM,mBAAmB,IAC/C,CAAC;EACL,GAAI,OAAO,MAAM,gBAAgB,WAC7B,EAAE,aAAa,MAAM,YAAY,IACjC,CAAC;EACL,GAAI,OAAO,MAAM,YAAY,WAAW,EAAE,SAAS,MAAM,QAAQ,IAAI,CAAC;EACtE,MAAM;EACN,GAAI,OAAO,MAAM,qBAAqB,WAClC,EAAE,kBAAkB,MAAM,iBAAiB,IAC3C,CAAC;EACL,QAAQ,MAAM;EACd,UAAU,MAAM;CAClB;AACF;AAEA,SAAS,aAAa,OAAqC;CACzD,OACE,OAAO,UAAU,YACjB,cAAc,KAAK,KACnB,YAAY,KAAK,KACjB,iBAAiB,KAAK;AAE1B;AAEA,SAAS,YAAY,OAAyB;CAC5C,IAAI,CAAC,SAAS,KAAK,GACjB,OAAO;CAGT,IAAI,MAAM,SAAS,aACjB,OAAO,OAAO,MAAM,SAAS,YAAY,cAAc,MAAM,IAAI;CAGnE,OAAO,MAAM,SAAS,kBAAkB,iBAAiB,MAAM,OAAO;AACxE;AAEA,SAAS,iBAAiB,OAAyB;CACjD,OAAO,MAAM,QAAQ,KAAK,KAAK,MAAM,MAAM,oBAAoB;AACjE;AAEA,SAAS,qBAAqB,OAAyB;CACrD,IAAI,CAAC,SAAS,KAAK,KAAK,OAAO,MAAM,SAAS,UAC5C,OAAO;CAGT,OACE,MAAM,SAAS,UAAU,MAAM,SAAS,WAAW,MAAM,SAAS;AAEtE;AAEA,SAAS,SAAS,OAAkD;CAClE,OAAO,OAAO,UAAU,YAAY,UAAU;AAChD;AAEA,SAAS,cAAc,OAA4C;CACjE,OACE,MAAM,QAAQ,KAAK,KAAK,MAAM,OAAO,SAAS,OAAO,SAAS,QAAQ;AAE1E"}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { durableBackgroundChildRunState } from "./subagent-background-child-run-state.js";
|
|
2
|
+
//#region src/subagent-background-child-run.ts
|
|
3
|
+
function createBackgroundTaskId() {
|
|
4
|
+
return `bg_${crypto.randomUUID().replaceAll("-", "")}`;
|
|
5
|
+
}
|
|
6
|
+
async function createDurableBackgroundTaskId({ delegateToolCallId, prompt, sessionKey }) {
|
|
7
|
+
const digestInput = backgroundSubagentDedupeKey({
|
|
8
|
+
delegateToolCallId,
|
|
9
|
+
prompt,
|
|
10
|
+
sessionKey
|
|
11
|
+
});
|
|
12
|
+
const digest = await crypto.subtle.digest("SHA-256", new TextEncoder().encode(digestInput));
|
|
13
|
+
return `bg_${[...new Uint8Array(digest.slice(0, 16))].map((byte) => byte.toString(16).padStart(2, "0")).join("")}`;
|
|
14
|
+
}
|
|
15
|
+
async function getBackgroundChildRun({ delegateToolCallId, executionHost, prompt, sessionKey }) {
|
|
16
|
+
if (!executionHost) return;
|
|
17
|
+
const dedupeKey = backgroundSubagentDedupeKey({
|
|
18
|
+
delegateToolCallId,
|
|
19
|
+
prompt,
|
|
20
|
+
sessionKey
|
|
21
|
+
});
|
|
22
|
+
return await executionHost.store.runs.getByDedupeKey(dedupeKey) ?? void 0;
|
|
23
|
+
}
|
|
24
|
+
async function getOrCreateBackgroundChildRun(input) {
|
|
25
|
+
if (!input.executionHost) return;
|
|
26
|
+
const id = input.publicTaskId ?? createBackgroundTaskId();
|
|
27
|
+
const dedupeKey = backgroundSubagentDedupeKey(input);
|
|
28
|
+
return await input.executionHost.store.transaction(async (tx) => {
|
|
29
|
+
const existing = await tx.runs.getByDedupeKey(dedupeKey);
|
|
30
|
+
if (existing) return existing;
|
|
31
|
+
const parentRunId = input.parentRunId ?? input.parentSessionKey ?? input.sessionKey;
|
|
32
|
+
const runtimeState = durableBackgroundChildRunState(input);
|
|
33
|
+
const run = {
|
|
34
|
+
checkpointVersion: 0,
|
|
35
|
+
dedupeKey,
|
|
36
|
+
kind: "background-subagent",
|
|
37
|
+
...input.ownerNamespace ? { ownerNamespace: input.ownerNamespace } : {},
|
|
38
|
+
parentRunId,
|
|
39
|
+
publicTaskId: id,
|
|
40
|
+
rootRunId: parentRunId,
|
|
41
|
+
runId: `background:${id}`,
|
|
42
|
+
sessionKey: `${input.sessionKey}:task:${id}`,
|
|
43
|
+
status: "queued"
|
|
44
|
+
};
|
|
45
|
+
await tx.runs.create(run);
|
|
46
|
+
await tx.checkpoints.append({
|
|
47
|
+
checkpointId: crypto.randomUUID(),
|
|
48
|
+
phase: "before-child-run",
|
|
49
|
+
runId: run.runId,
|
|
50
|
+
runtimeState,
|
|
51
|
+
sessionSnapshot: {},
|
|
52
|
+
version: 1
|
|
53
|
+
}, { expectedVersion: 0 });
|
|
54
|
+
await tx.checkpoints.append({
|
|
55
|
+
checkpointId: crypto.randomUUID(),
|
|
56
|
+
childRunId: run.runId,
|
|
57
|
+
phase: "child-linked",
|
|
58
|
+
runId: run.runId,
|
|
59
|
+
runtimeState,
|
|
60
|
+
sessionSnapshot: {},
|
|
61
|
+
version: 2
|
|
62
|
+
}, { expectedVersion: 1 });
|
|
63
|
+
return await tx.runs.get(run.runId) ?? run;
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
async function updateBackgroundRunStatus(job, status) {
|
|
67
|
+
if (!(job.executionHost && job.childRunId)) return true;
|
|
68
|
+
return await job.executionHost.store.transaction(async (tx) => {
|
|
69
|
+
const run = await tx.runs.get(job.childRunId ?? "");
|
|
70
|
+
if (!run || isTerminalBackgroundRunStatus(run.status)) return false;
|
|
71
|
+
if (job.childRunLeaseId && run.lease?.leaseId !== job.childRunLeaseId) return false;
|
|
72
|
+
await tx.runs.update({
|
|
73
|
+
...run,
|
|
74
|
+
output: job.result ?? run.output,
|
|
75
|
+
status
|
|
76
|
+
});
|
|
77
|
+
return true;
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
async function cancelBackgroundChildRun({ executionHost, runId }) {
|
|
81
|
+
return await executionHost.store.transaction(async (tx) => {
|
|
82
|
+
const run = await tx.runs.get(runId);
|
|
83
|
+
if (!run || isTerminalBackgroundRunStatus(run.status)) return run;
|
|
84
|
+
return await tx.runs.update({
|
|
85
|
+
...run,
|
|
86
|
+
status: "cancelled"
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
function childRunStatus(result) {
|
|
91
|
+
if (result === "aborted") return "cancelled";
|
|
92
|
+
return result;
|
|
93
|
+
}
|
|
94
|
+
function backgroundSubagentDedupeKey({ delegateToolCallId, prompt, sessionKey }) {
|
|
95
|
+
return `background-subagent:${sessionKey}:${delegateToolCallId ?? "unknown"}:${JSON.stringify(prompt)}`;
|
|
96
|
+
}
|
|
97
|
+
function isTerminalBackgroundRunStatus(status) {
|
|
98
|
+
return status === "cancelled" || status === "completed" || status === "error";
|
|
99
|
+
}
|
|
100
|
+
//#endregion
|
|
101
|
+
export { cancelBackgroundChildRun, childRunStatus, createBackgroundTaskId, createDurableBackgroundTaskId, getBackgroundChildRun, getOrCreateBackgroundChildRun, updateBackgroundRunStatus };
|
|
102
|
+
|
|
103
|
+
//# sourceMappingURL=subagent-background-child-run.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subagent-background-child-run.js","names":[],"sources":["../src/subagent-background-child-run.ts"],"sourcesContent":["import type { ExecutionHost, RunRecord, RunStatus } from \"./execution/types\";\nimport type { AgentInput } from \"./session/input\";\nimport { durableBackgroundChildRunState } from \"./subagent-background-child-run-state\";\nimport type { SubagentJob } from \"./subagent-types\";\n\ninterface BackgroundChildRunInput {\n readonly delegateToolCallId?: string;\n readonly description?: string;\n readonly executionHost?: ExecutionHost;\n readonly groupId?: string;\n readonly ownerNamespace?: string;\n readonly parentRunId?: string;\n readonly parentSessionKey?: string;\n readonly prompt: AgentInput;\n readonly publicTaskId?: string;\n readonly sessionKey: string;\n readonly subagent?: string;\n}\n\nexport function createBackgroundTaskId(): string {\n return `bg_${crypto.randomUUID().replaceAll(\"-\", \"\")}`;\n}\n\nexport async function createDurableBackgroundTaskId({\n delegateToolCallId,\n prompt,\n sessionKey,\n}: Pick<\n BackgroundChildRunInput,\n \"delegateToolCallId\" | \"prompt\" | \"sessionKey\"\n>): Promise<string> {\n const digestInput = backgroundSubagentDedupeKey({\n delegateToolCallId,\n prompt,\n sessionKey,\n });\n const digest = await crypto.subtle.digest(\n \"SHA-256\",\n new TextEncoder().encode(digestInput)\n );\n const bytes = [...new Uint8Array(digest.slice(0, 16))];\n const hex = bytes.map((byte) => byte.toString(16).padStart(2, \"0\")).join(\"\");\n return `bg_${hex}`;\n}\n\nexport async function getBackgroundChildRun({\n delegateToolCallId,\n executionHost,\n prompt,\n sessionKey,\n}: BackgroundChildRunInput): Promise<RunRecord | undefined> {\n if (!executionHost) {\n return;\n }\n\n const dedupeKey = backgroundSubagentDedupeKey({\n delegateToolCallId,\n prompt,\n sessionKey,\n });\n return (\n (await executionHost.store.runs.getByDedupeKey(dedupeKey)) ?? undefined\n );\n}\n\nexport async function getOrCreateBackgroundChildRun(\n input: BackgroundChildRunInput\n): Promise<RunRecord | undefined> {\n if (!input.executionHost) {\n return;\n }\n\n const id = input.publicTaskId ?? createBackgroundTaskId();\n const dedupeKey = backgroundSubagentDedupeKey(input);\n return await input.executionHost.store.transaction(async (tx) => {\n const existing = await tx.runs.getByDedupeKey(dedupeKey);\n if (existing) {\n return existing;\n }\n\n const parentRunId =\n input.parentRunId ?? input.parentSessionKey ?? input.sessionKey;\n const runtimeState = durableBackgroundChildRunState(input);\n const run: RunRecord = {\n checkpointVersion: 0,\n dedupeKey,\n kind: \"background-subagent\",\n ...(input.ownerNamespace ? { ownerNamespace: input.ownerNamespace } : {}),\n parentRunId,\n publicTaskId: id,\n rootRunId: parentRunId,\n runId: `background:${id}`,\n sessionKey: `${input.sessionKey}:task:${id}`,\n status: \"queued\",\n };\n await tx.runs.create(run);\n await tx.checkpoints.append(\n {\n checkpointId: crypto.randomUUID(),\n phase: \"before-child-run\",\n runId: run.runId,\n runtimeState,\n sessionSnapshot: {},\n version: 1,\n },\n { expectedVersion: 0 }\n );\n await tx.checkpoints.append(\n {\n checkpointId: crypto.randomUUID(),\n childRunId: run.runId,\n phase: \"child-linked\",\n runId: run.runId,\n runtimeState,\n sessionSnapshot: {},\n version: 2,\n },\n { expectedVersion: 1 }\n );\n return (await tx.runs.get(run.runId)) ?? run;\n });\n}\n\nexport async function updateBackgroundRunStatus(\n job: SubagentJob,\n status: Extract<RunStatus, \"cancelled\" | \"completed\" | \"error\">\n): Promise<boolean> {\n if (!(job.executionHost && job.childRunId)) {\n return true;\n }\n\n return await job.executionHost.store.transaction(async (tx) => {\n const run = await tx.runs.get(job.childRunId ?? \"\");\n if (!run || isTerminalBackgroundRunStatus(run.status)) {\n return false;\n }\n if (job.childRunLeaseId && run.lease?.leaseId !== job.childRunLeaseId) {\n return false;\n }\n\n await tx.runs.update({\n ...run,\n output: job.result ?? run.output,\n status,\n });\n return true;\n });\n}\n\nexport async function cancelBackgroundChildRun({\n executionHost,\n runId,\n}: {\n readonly executionHost: ExecutionHost;\n readonly runId: string;\n}): Promise<RunRecord | null> {\n return await executionHost.store.transaction(async (tx) => {\n const run = await tx.runs.get(runId);\n if (!run || isTerminalBackgroundRunStatus(run.status)) {\n return run;\n }\n\n return await tx.runs.update({ ...run, status: \"cancelled\" });\n });\n}\n\nexport function childRunStatus(\n result: Exclude<SubagentJob[\"status\"], \"cancelled\" | \"pending\" | \"running\">\n): Extract<RunStatus, \"cancelled\" | \"completed\" | \"error\"> {\n if (result === \"aborted\") {\n return \"cancelled\";\n }\n\n return result;\n}\n\nfunction backgroundSubagentDedupeKey({\n delegateToolCallId,\n prompt,\n sessionKey,\n}: {\n readonly delegateToolCallId?: string;\n readonly prompt: AgentInput;\n readonly sessionKey: string;\n}): string {\n return `background-subagent:${sessionKey}:${delegateToolCallId ?? \"unknown\"}:${JSON.stringify(prompt)}`;\n}\n\nfunction isTerminalBackgroundRunStatus(status: RunStatus): boolean {\n return status === \"cancelled\" || status === \"completed\" || status === \"error\";\n}\n"],"mappings":";;AAmBA,SAAgB,yBAAiC;CAC/C,OAAO,MAAM,OAAO,WAAW,EAAE,WAAW,KAAK,EAAE;AACrD;AAEA,eAAsB,8BAA8B,EAClD,oBACA,QACA,cAIkB;CAClB,MAAM,cAAc,4BAA4B;EAC9C;EACA;EACA;CACF,CAAC;CACD,MAAM,SAAS,MAAM,OAAO,OAAO,OACjC,WACA,IAAI,YAAY,EAAE,OAAO,WAAW,CACtC;CAGA,OAAO,MADK,CADG,GAAG,IAAI,WAAW,OAAO,MAAM,GAAG,EAAE,CAAC,CACpC,EAAE,KAAK,SAAS,KAAK,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC,EAAE,KAAK,EAC1D;AACjB;AAEA,eAAsB,sBAAsB,EAC1C,oBACA,eACA,QACA,cAC0D;CAC1D,IAAI,CAAC,eACH;CAGF,MAAM,YAAY,4BAA4B;EAC5C;EACA;EACA;CACF,CAAC;CACD,OACG,MAAM,cAAc,MAAM,KAAK,eAAe,SAAS,KAAM,KAAA;AAElE;AAEA,eAAsB,8BACpB,OACgC;CAChC,IAAI,CAAC,MAAM,eACT;CAGF,MAAM,KAAK,MAAM,gBAAgB,uBAAuB;CACxD,MAAM,YAAY,4BAA4B,KAAK;CACnD,OAAO,MAAM,MAAM,cAAc,MAAM,YAAY,OAAO,OAAO;EAC/D,MAAM,WAAW,MAAM,GAAG,KAAK,eAAe,SAAS;EACvD,IAAI,UACF,OAAO;EAGT,MAAM,cACJ,MAAM,eAAe,MAAM,oBAAoB,MAAM;EACvD,MAAM,eAAe,+BAA+B,KAAK;EACzD,MAAM,MAAiB;GACrB,mBAAmB;GACnB;GACA,MAAM;GACN,GAAI,MAAM,iBAAiB,EAAE,gBAAgB,MAAM,eAAe,IAAI,CAAC;GACvE;GACA,cAAc;GACd,WAAW;GACX,OAAO,cAAc;GACrB,YAAY,GAAG,MAAM,WAAW,QAAQ;GACxC,QAAQ;EACV;EACA,MAAM,GAAG,KAAK,OAAO,GAAG;EACxB,MAAM,GAAG,YAAY,OACnB;GACE,cAAc,OAAO,WAAW;GAChC,OAAO;GACP,OAAO,IAAI;GACX;GACA,iBAAiB,CAAC;GAClB,SAAS;EACX,GACA,EAAE,iBAAiB,EAAE,CACvB;EACA,MAAM,GAAG,YAAY,OACnB;GACE,cAAc,OAAO,WAAW;GAChC,YAAY,IAAI;GAChB,OAAO;GACP,OAAO,IAAI;GACX;GACA,iBAAiB,CAAC;GAClB,SAAS;EACX,GACA,EAAE,iBAAiB,EAAE,CACvB;EACA,OAAQ,MAAM,GAAG,KAAK,IAAI,IAAI,KAAK,KAAM;CAC3C,CAAC;AACH;AAEA,eAAsB,0BACpB,KACA,QACkB;CAClB,IAAI,EAAE,IAAI,iBAAiB,IAAI,aAC7B,OAAO;CAGT,OAAO,MAAM,IAAI,cAAc,MAAM,YAAY,OAAO,OAAO;EAC7D,MAAM,MAAM,MAAM,GAAG,KAAK,IAAI,IAAI,cAAc,EAAE;EAClD,IAAI,CAAC,OAAO,8BAA8B,IAAI,MAAM,GAClD,OAAO;EAET,IAAI,IAAI,mBAAmB,IAAI,OAAO,YAAY,IAAI,iBACpD,OAAO;EAGT,MAAM,GAAG,KAAK,OAAO;GACnB,GAAG;GACH,QAAQ,IAAI,UAAU,IAAI;GAC1B;EACF,CAAC;EACD,OAAO;CACT,CAAC;AACH;AAEA,eAAsB,yBAAyB,EAC7C,eACA,SAI4B;CAC5B,OAAO,MAAM,cAAc,MAAM,YAAY,OAAO,OAAO;EACzD,MAAM,MAAM,MAAM,GAAG,KAAK,IAAI,KAAK;EACnC,IAAI,CAAC,OAAO,8BAA8B,IAAI,MAAM,GAClD,OAAO;EAGT,OAAO,MAAM,GAAG,KAAK,OAAO;GAAE,GAAG;GAAK,QAAQ;EAAY,CAAC;CAC7D,CAAC;AACH;AAEA,SAAgB,eACd,QACyD;CACzD,IAAI,WAAW,WACb,OAAO;CAGT,OAAO;AACT;AAEA,SAAS,4BAA4B,EACnC,oBACA,QACA,cAKS;CACT,OAAO,uBAAuB,WAAW,GAAG,sBAAsB,UAAU,GAAG,KAAK,UAAU,MAAM;AACtG;AAEA,SAAS,8BAA8B,QAA4B;CACjE,OAAO,WAAW,eAAe,WAAW,eAAe,WAAW;AACxE"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { cancelBackgroundChildRun } from "./subagent-background-child-run.js";
|
|
2
|
+
import { backgroundCancelledLaunchOutput, backgroundLaunchOutput, backgroundReplayOutput, backgroundRunJobStatus } from "./subagent-job-state.js";
|
|
3
|
+
import { registerBackgroundJobGroup } from "./subagent-background-notify.js";
|
|
4
|
+
import { runBackgroundJob } from "./subagent-background-runner.js";
|
|
5
|
+
//#region src/subagent-background-in-process.ts
|
|
6
|
+
async function startInProcessBackgroundJob({ abortSignal, childRun, delegateToolCallId, description, executionHost, groupId, groups, id, jobs, parentRunId, parentSession, parentSessionKey, ownerNamespace, prompt, registerCleanup, sessionKey, subagent }) {
|
|
7
|
+
const subagentName = subagent.name ?? "subagent";
|
|
8
|
+
const claimedChildRun = childRun ? await claimBackgroundChildRun({
|
|
9
|
+
executionHost,
|
|
10
|
+
run: childRun,
|
|
11
|
+
subagent: subagentName
|
|
12
|
+
}) : void 0;
|
|
13
|
+
if (claimedChildRun?.replay) return claimedChildRun.replay;
|
|
14
|
+
if (abortSignal.aborted) {
|
|
15
|
+
if (executionHost && claimedChildRun?.run) await cancelBackgroundChildRun({
|
|
16
|
+
executionHost,
|
|
17
|
+
runId: claimedChildRun.run.runId
|
|
18
|
+
});
|
|
19
|
+
return backgroundCancelledLaunchOutput({
|
|
20
|
+
id,
|
|
21
|
+
subagent: subagent.name
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
const childSessionKey = claimedChildRun?.run.sessionKey ?? `${sessionKey}:task:${id}`;
|
|
25
|
+
const childSession = subagent.session(childSessionKey);
|
|
26
|
+
const abort = () => childSession.interrupt();
|
|
27
|
+
abortSignal.addEventListener("abort", abort, { once: true });
|
|
28
|
+
const cleanup = () => childSession.delete();
|
|
29
|
+
const unregisterCleanup = registerCleanup(cleanup);
|
|
30
|
+
const job = {
|
|
31
|
+
abort,
|
|
32
|
+
childRunId: claimedChildRun?.run.runId,
|
|
33
|
+
childRunLeaseId: claimedChildRun?.run.lease?.leaseId,
|
|
34
|
+
cleanup,
|
|
35
|
+
dedupeKey: claimedChildRun?.run.dedupeKey,
|
|
36
|
+
description,
|
|
37
|
+
id,
|
|
38
|
+
delegateToolCallId,
|
|
39
|
+
executionHost,
|
|
40
|
+
ownerNamespace,
|
|
41
|
+
parentSessionKey,
|
|
42
|
+
parentRunId,
|
|
43
|
+
promise: Promise.resolve(),
|
|
44
|
+
groupId,
|
|
45
|
+
sessionKey: childSessionKey,
|
|
46
|
+
settled: false,
|
|
47
|
+
status: "pending",
|
|
48
|
+
subagent: subagentName,
|
|
49
|
+
unregisterCleanup
|
|
50
|
+
};
|
|
51
|
+
jobs.set(id, job);
|
|
52
|
+
registerBackgroundJobGroup({
|
|
53
|
+
groupId,
|
|
54
|
+
groups,
|
|
55
|
+
job
|
|
56
|
+
});
|
|
57
|
+
await parentSession.emitObserverEvent({
|
|
58
|
+
description,
|
|
59
|
+
delegateToolCallId,
|
|
60
|
+
run_in_background: true,
|
|
61
|
+
subagent: subagentName,
|
|
62
|
+
task_id: id,
|
|
63
|
+
type: "subagent-job-start"
|
|
64
|
+
});
|
|
65
|
+
job.status = "running";
|
|
66
|
+
job.promise = runBackgroundJob({
|
|
67
|
+
childSession,
|
|
68
|
+
groups,
|
|
69
|
+
jobs,
|
|
70
|
+
job,
|
|
71
|
+
parentSession,
|
|
72
|
+
prompt
|
|
73
|
+
}).finally(() => {
|
|
74
|
+
abortSignal.removeEventListener("abort", abort);
|
|
75
|
+
job.settled = true;
|
|
76
|
+
});
|
|
77
|
+
return backgroundLaunchOutput(job);
|
|
78
|
+
}
|
|
79
|
+
async function claimBackgroundChildRun({ executionHost, run, subagent }) {
|
|
80
|
+
if (!executionHost) return { run };
|
|
81
|
+
const claim = await executionHost.store.runs.claim(run.runId, {
|
|
82
|
+
attempt: (run.lease?.attempt ?? 0) + 1,
|
|
83
|
+
leaseId: crypto.randomUUID(),
|
|
84
|
+
leaseMs: 3e5,
|
|
85
|
+
nowMs: Date.now()
|
|
86
|
+
});
|
|
87
|
+
if (claim.ok) return { run: claim.record };
|
|
88
|
+
const status = backgroundRunJobStatus((await executionHost.store.runs.get(run.runId))?.status) ?? "pending";
|
|
89
|
+
return { replay: backgroundReplayOutput({
|
|
90
|
+
id: run.publicTaskId ?? run.runId,
|
|
91
|
+
status,
|
|
92
|
+
subagent
|
|
93
|
+
}) };
|
|
94
|
+
}
|
|
95
|
+
//#endregion
|
|
96
|
+
export { startInProcessBackgroundJob };
|
|
97
|
+
|
|
98
|
+
//# sourceMappingURL=subagent-background-in-process.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subagent-background-in-process.js","names":[],"sources":["../src/subagent-background-in-process.ts"],"sourcesContent":["import type { ExecutionHost, RunRecord } from \"./execution/types\";\nimport type { AgentInput } from \"./session/input\";\nimport { cancelBackgroundChildRun } from \"./subagent-background-child-run\";\nimport { registerBackgroundJobGroup } from \"./subagent-background-notify\";\nimport { runBackgroundJob } from \"./subagent-background-runner\";\nimport {\n backgroundCancelledLaunchOutput,\n backgroundLaunchOutput,\n backgroundReplayOutput,\n backgroundRunJobStatus,\n} from \"./subagent-job-state\";\nimport type {\n RuntimeInputSink,\n Subagent,\n SubagentJob,\n SubagentJobGroup,\n} from \"./subagent-types\";\n\nexport async function startInProcessBackgroundJob({\n abortSignal,\n childRun,\n delegateToolCallId,\n description,\n executionHost,\n groupId,\n groups,\n id,\n jobs,\n parentRunId,\n parentSession,\n parentSessionKey,\n ownerNamespace,\n prompt,\n registerCleanup,\n sessionKey,\n subagent,\n}: {\n readonly abortSignal: AbortSignal;\n readonly childRun?: RunRecord;\n readonly delegateToolCallId?: string;\n readonly description?: string;\n readonly executionHost?: ExecutionHost;\n readonly groupId?: string;\n readonly groups: Map<string, SubagentJobGroup>;\n readonly id: string;\n readonly jobs: Map<string, SubagentJob>;\n readonly parentRunId?: string;\n readonly parentSession: RuntimeInputSink;\n readonly parentSessionKey?: string;\n readonly ownerNamespace?: string;\n readonly prompt: AgentInput;\n readonly registerCleanup: (cleanup: () => Promise<void>) => () => void;\n readonly sessionKey: string;\n readonly subagent: Subagent;\n}) {\n const subagentName = subagent.name ?? \"subagent\";\n const claimedChildRun = childRun\n ? await claimBackgroundChildRun({\n executionHost,\n run: childRun,\n subagent: subagentName,\n })\n : undefined;\n if (claimedChildRun?.replay) {\n return claimedChildRun.replay;\n }\n if (abortSignal.aborted) {\n if (executionHost && claimedChildRun?.run) {\n await cancelBackgroundChildRun({\n executionHost,\n runId: claimedChildRun.run.runId,\n });\n }\n return backgroundCancelledLaunchOutput({ id, subagent: subagent.name });\n }\n\n const childSessionKey =\n claimedChildRun?.run.sessionKey ?? `${sessionKey}:task:${id}`;\n const childSession = subagent.session(childSessionKey);\n const abort = () => childSession.interrupt();\n abortSignal.addEventListener(\"abort\", abort, { once: true });\n const cleanup = () => childSession.delete();\n const unregisterCleanup = registerCleanup(cleanup);\n const job: SubagentJob = {\n abort,\n childRunId: claimedChildRun?.run.runId,\n childRunLeaseId: claimedChildRun?.run.lease?.leaseId,\n cleanup,\n dedupeKey: claimedChildRun?.run.dedupeKey,\n description,\n id,\n delegateToolCallId,\n executionHost,\n ownerNamespace,\n parentSessionKey,\n parentRunId,\n promise: Promise.resolve(),\n groupId,\n sessionKey: childSessionKey,\n settled: false,\n status: \"pending\",\n subagent: subagentName,\n unregisterCleanup,\n };\n jobs.set(id, job);\n registerBackgroundJobGroup({ groupId, groups, job });\n await parentSession.emitObserverEvent({\n description,\n delegateToolCallId,\n run_in_background: true,\n subagent: subagentName,\n task_id: id,\n type: \"subagent-job-start\",\n });\n job.status = \"running\";\n job.promise = runBackgroundJob({\n childSession,\n groups,\n jobs,\n job,\n parentSession,\n prompt,\n }).finally(() => {\n abortSignal.removeEventListener(\"abort\", abort);\n job.settled = true;\n });\n\n return backgroundLaunchOutput(job);\n}\n\nasync function claimBackgroundChildRun({\n executionHost,\n run,\n subagent,\n}: {\n readonly executionHost: ExecutionHost | undefined;\n readonly run: RunRecord;\n readonly subagent: string;\n}): Promise<\n | { readonly replay?: never; readonly run: RunRecord }\n | {\n readonly replay: ReturnType<typeof backgroundReplayOutput>;\n readonly run?: never;\n }\n> {\n if (!executionHost) {\n return { run };\n }\n\n const claim = await executionHost.store.runs.claim(run.runId, {\n attempt: (run.lease?.attempt ?? 0) + 1,\n leaseId: crypto.randomUUID(),\n leaseMs: 300_000,\n nowMs: Date.now(),\n });\n if (claim.ok) {\n return { run: claim.record };\n }\n\n const latestRun = await executionHost.store.runs.get(run.runId);\n const status = backgroundRunJobStatus(latestRun?.status) ?? \"pending\";\n return {\n replay: backgroundReplayOutput({\n id: run.publicTaskId ?? run.runId,\n status,\n subagent,\n }),\n };\n}\n"],"mappings":";;;;;AAkBA,eAAsB,4BAA4B,EAChD,aACA,UACA,oBACA,aACA,eACA,SACA,QACA,IACA,MACA,aACA,eACA,kBACA,gBACA,QACA,iBACA,YACA,YAmBC;CACD,MAAM,eAAe,SAAS,QAAQ;CACtC,MAAM,kBAAkB,WACpB,MAAM,wBAAwB;EAC5B;EACA,KAAK;EACL,UAAU;CACZ,CAAC,IACD,KAAA;CACJ,IAAI,iBAAiB,QACnB,OAAO,gBAAgB;CAEzB,IAAI,YAAY,SAAS;EACvB,IAAI,iBAAiB,iBAAiB,KACpC,MAAM,yBAAyB;GAC7B;GACA,OAAO,gBAAgB,IAAI;EAC7B,CAAC;EAEH,OAAO,gCAAgC;GAAE;GAAI,UAAU,SAAS;EAAK,CAAC;CACxE;CAEA,MAAM,kBACJ,iBAAiB,IAAI,cAAc,GAAG,WAAW,QAAQ;CAC3D,MAAM,eAAe,SAAS,QAAQ,eAAe;CACrD,MAAM,cAAc,aAAa,UAAU;CAC3C,YAAY,iBAAiB,SAAS,OAAO,EAAE,MAAM,KAAK,CAAC;CAC3D,MAAM,gBAAgB,aAAa,OAAO;CAC1C,MAAM,oBAAoB,gBAAgB,OAAO;CACjD,MAAM,MAAmB;EACvB;EACA,YAAY,iBAAiB,IAAI;EACjC,iBAAiB,iBAAiB,IAAI,OAAO;EAC7C;EACA,WAAW,iBAAiB,IAAI;EAChC;EACA;EACA;EACA;EACA;EACA;EACA;EACA,SAAS,QAAQ,QAAQ;EACzB;EACA,YAAY;EACZ,SAAS;EACT,QAAQ;EACR,UAAU;EACV;CACF;CACA,KAAK,IAAI,IAAI,GAAG;CAChB,2BAA2B;EAAE;EAAS;EAAQ;CAAI,CAAC;CACnD,MAAM,cAAc,kBAAkB;EACpC;EACA;EACA,mBAAmB;EACnB,UAAU;EACV,SAAS;EACT,MAAM;CACR,CAAC;CACD,IAAI,SAAS;CACb,IAAI,UAAU,iBAAiB;EAC7B;EACA;EACA;EACA;EACA;EACA;CACF,CAAC,EAAE,cAAc;EACf,YAAY,oBAAoB,SAAS,KAAK;EAC9C,IAAI,UAAU;CAChB,CAAC;CAED,OAAO,uBAAuB,GAAG;AACnC;AAEA,eAAe,wBAAwB,EACrC,eACA,KACA,YAWA;CACA,IAAI,CAAC,eACH,OAAO,EAAE,IAAI;CAGf,MAAM,QAAQ,MAAM,cAAc,MAAM,KAAK,MAAM,IAAI,OAAO;EAC5D,UAAU,IAAI,OAAO,WAAW,KAAK;EACrC,SAAS,OAAO,WAAW;EAC3B,SAAS;EACT,OAAO,KAAK,IAAI;CAClB,CAAC;CACD,IAAI,MAAM,IACR,OAAO,EAAE,KAAK,MAAM,OAAO;CAI7B,MAAM,SAAS,wBAAuB,MADd,cAAc,MAAM,KAAK,IAAI,IAAI,KAAK,IACb,MAAM,KAAK;CAC5D,OAAO,EACL,QAAQ,uBAAuB;EAC7B,IAAI,IAAI,gBAAgB,IAAI;EAC5B;EACA;CACF,CAAC,EACH;AACF"}
|