@jini-ai/daemon 0.5.3 → 0.6.0
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/CHANGELOG.md +4 -0
- package/dist/agent-executor/contracts.d.ts +45 -14
- package/dist/agent-executor/contracts.js +0 -9
- package/dist/agent-executor/event-translation.d.ts +2 -2
- package/dist/agent-executor/event-translation.js +0 -2
- package/dist/agent-executor/events.d.ts +26 -6
- package/dist/agent-executor/events.js +198 -11
- package/dist/agent-executor/handoff.d.ts +1 -1
- package/dist/agent-executor/handoff.js +0 -1
- package/dist/agent-executor/index.d.ts +1 -1
- package/dist/agent-executor/launch.d.ts +1 -1
- package/dist/agent-executor/launch.js +47 -3
- package/dist/agent-executor/mcp-bridge.d.ts +2 -2
- package/dist/agent-executor/mcp-bridge.js +19 -8
- package/dist/agent-executor/model-receipts.d.ts +6 -0
- package/dist/agent-executor/model-receipts.js +26 -0
- package/dist/agent-executor.d.ts +7 -1665
- package/dist/agent-executor.js +7 -3007
- package/dist/core/read-only-tools.d.ts +130 -0
- package/dist/core/read-only-tools.js +115 -0
- package/dist/core/tool-audit.d.ts +131 -0
- package/dist/core/tool-audit.js +113 -0
- package/dist/http/active-context.d.ts +2 -2
- package/dist/http/agents.d.ts +8 -2
- package/dist/http/agents.js +6 -2
- package/dist/http/component-catalog.d.ts +2 -2
- package/dist/http/connectors.d.ts +17 -17
- package/dist/http/daemon-status.d.ts +2 -2
- package/dist/http/db-ops.d.ts +3 -3
- package/dist/http/delegated-tools.d.ts +1 -1
- package/dist/http/delegated-tools.js +1 -1
- package/dist/http/frontend-sessions.d.ts +1 -1
- package/dist/http/health.d.ts +6 -6
- package/dist/http/host-tools.d.ts +2 -2
- package/dist/http/index.d.ts +2 -2
- package/dist/http/index.js +1 -1
- package/dist/http/media.d.ts +4 -4
- package/dist/http/memory.d.ts +15 -15
- package/dist/http/remote-run-events.d.ts +2 -2
- package/dist/http/research.d.ts +1 -1
- package/dist/http/route-manifest.js +2 -2
- package/dist/http/routines.d.ts +7 -7
- package/dist/http/run-credentials.d.ts +2 -2
- package/dist/http/run-credentials.js +2 -2
- package/dist/http/runs.d.ts +31 -6
- package/dist/http/runs.js +36 -1
- package/dist/http/terminals.d.ts +6 -6
- package/dist/http/tool-catalog.d.ts +2 -2
- package/dist/http/xai.d.ts +6 -6
- package/dist/index.d.ts +75 -571
- package/dist/index.js +75 -571
- package/dist/read-only-tools.d.ts +1 -129
- package/dist/read-only-tools.js +2 -114
- package/dist/run-credentials.d.ts +47 -23
- package/dist/run-credentials.js +24 -8
- package/dist/scheduler.d.ts +5 -0
- package/dist/scheduler.js +13 -1
- package/dist/session-coordination.d.ts +58 -24
- package/dist/session-coordination.js +40 -12
- package/dist/store/event-log/sqlite.js +3 -3
- package/dist/surface-exchanges.d.ts +207 -61
- package/dist/surface-exchanges.js +167 -20
- package/dist/tool-audit.d.ts +1 -113
- package/dist/tool-audit.js +2 -94
- package/dist/tool-recovery/diagnostics.d.ts +132 -0
- package/dist/tool-recovery/diagnostics.js +110 -0
- package/dist/tool-recovery/federated-refusal.d.ts +92 -0
- package/dist/tool-recovery/federated-refusal.js +152 -0
- package/dist/tool-recovery/index.d.ts +6 -0
- package/dist/tool-recovery/index.js +6 -0
- package/dist/tool-recovery/recovery.d.ts +49 -0
- package/dist/tool-recovery/recovery.js +419 -0
- package/dist/tool-recovery/redaction.d.ts +166 -0
- package/dist/tool-recovery/redaction.js +192 -0
- package/dist/tool-recovery/stack.d.ts +69 -0
- package/dist/tool-recovery/stack.js +62 -0
- package/package.json +35 -12
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
## 0.5.4 — pending release
|
|
2
|
+
|
|
3
|
+
- Re-export the canonical core surface-exchange contracts and parameter constants. Store and ask/report behavior are unchanged; requires core 0.4.2.
|
|
4
|
+
|
|
1
5
|
## 0.5.3 — 2026-10-06
|
|
2
6
|
|
|
3
7
|
- Message attachments reach every runtime: new `prepareMessageAttachments` / `messageContentWithImages` (+ `MessageAttachmentImage`, `MessageAttachmentSource`, `MessageAttachmentReader`) turn claimed refs into image pixels for providers and a file notice for non-images.
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import type { MessageAttachmentImage } from '../attachment-content.js';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
2
|
+
import type { spawn as nodeSpawn, ChildProcess } from 'node:child_process';
|
|
3
|
+
import type { Principal } from '@jini-ai/core';
|
|
4
|
+
import type { RunAgentPayload, RunErrorPayload } from '@jini-ai/protocol';
|
|
5
|
+
import type { applyAgentLaunchEnv, ensureAgentCapabilities, resolveModelForLaunch, getAgentDef, resolveAgentLaunch, attachAcpSession, attachPiRpcSession, prepareAgentLogFile, preparePromptFileForAgent, AcpMcpServerInput, AcpPermissionHandler, PromptAugmenter } from '@jini-ai/agent-runtime';
|
|
6
|
+
import type { createCommandInvocation, listProcessSnapshots, ProcessSnapshot, StopProcessesResult } from '@jini-ai/platform';
|
|
7
|
+
import type { RunByteJournal } from '../continuation/journal.js';
|
|
8
|
+
import type { RunRetrySideEffectState } from '../run/core/index.js';
|
|
9
|
+
import type { ToolExecutor } from '../tool-executor.js';
|
|
10
|
+
import type { RunLifecycle } from '../run-lifecycle.js';
|
|
11
11
|
/**
|
|
12
12
|
* A parsed, loosely-typed event as produced by one of `@jini-ai/agent-runtime`'s
|
|
13
13
|
* four stream-parser factories — each parser's `onEvent` callback receives
|
|
@@ -90,7 +90,7 @@ export type AgentRuntimeEventTranslation = {
|
|
|
90
90
|
readonly kind: 'ignored';
|
|
91
91
|
};
|
|
92
92
|
/** Machine-readable failure reasons `run()` can reject with — every one is preceded by a `lifecycle.finish({status:'failed'})` call (see index.ts module doc's Invariant section). */
|
|
93
|
-
export type AgentExecutorErrorCode = 'AGENT_PERMISSION_MODE_INVALID' | 'AGENT_NOT_FOUND' | 'AGENT_RUNTIME_UNSUPPORTED' | 'AGENT_BINARY_NOT_RESOLVED' | 'AGENT_SPAWN_FAILED' | 'AGENT_PROMPT_TOO_LARGE';
|
|
93
|
+
export type AgentExecutorErrorCode = 'AGENT_MODEL_UNRESOLVED' | 'AGENT_PERMISSION_MODE_INVALID' | 'AGENT_NOT_FOUND' | 'AGENT_RUNTIME_UNSUPPORTED' | 'AGENT_BINARY_NOT_RESOLVED' | 'AGENT_SPAWN_FAILED' | 'AGENT_PROMPT_TOO_LARGE';
|
|
94
94
|
/** Thrown by `AgentExecutor.run()` on every failure path — never a bare `Error`, so callers can branch on `.code` instead of parsing `.message`. */
|
|
95
95
|
export declare class AgentExecutorError extends Error {
|
|
96
96
|
readonly code: AgentExecutorErrorCode;
|
|
@@ -194,7 +194,27 @@ export interface AgentExecutor {
|
|
|
194
194
|
* `lifecycle.finish()` before this rejects (see index.ts module doc's Invariant).
|
|
195
195
|
*/
|
|
196
196
|
run(requiredArgs: Pick<AgentExecutorRunInput, "runId" | "agentId" | "prompt" | "cwd">, optionalArgs?: Pick<AgentExecutorRunInput, "model" | "reasoning" | "permissionMode" | "imagePaths" | "imageContents" | "extraAllowedDirs" | "uploadRoot" | "credentialEnv" | "env" | "resumeSessionId" | "newSessionId" | "disallowedTools" | "allowedTools" | "settingSources" | "settings">): Promise<void>;
|
|
197
|
+
/**
|
|
198
|
+
* Delivers a message the human sent while `runId` is going straight into its live agent process
|
|
199
|
+
* (see {@link UserMessageDelivery} for each outcome). A stream-json agent is interrupted first and
|
|
200
|
+
* gets the message once the CLI acknowledges the interrupt, so this settles in milliseconds (at
|
|
201
|
+
* most `INTERRUPT_ACK_TIMEOUT_MS`); it never waits on the agent's reply.
|
|
202
|
+
*/
|
|
203
|
+
sendUserMessage(requiredArgs: {
|
|
204
|
+
readonly runId: string;
|
|
205
|
+
readonly text: string;
|
|
206
|
+
}): Promise<UserMessageDelivery>;
|
|
197
207
|
}
|
|
208
|
+
/**
|
|
209
|
+
* What {@link AgentExecutor.sendUserMessage} did with a mid-run message:
|
|
210
|
+
* - `'delivered'` — the running turn was interrupted and the message written into the live
|
|
211
|
+
* session; the agent answers it next, in the same process and session.
|
|
212
|
+
* - `'unsupported'` — the run is live, but its agent has no way to take input mid-run (its prompt
|
|
213
|
+
* is plain text or an RPC request). The host should interrupt and send it as the next turn.
|
|
214
|
+
* - `'not-running'` — no live process will accept it: an unknown run, a finished one, or one whose
|
|
215
|
+
* last turn already ended and closed stdin. The run is ending; the host should send it next.
|
|
216
|
+
*/
|
|
217
|
+
export type UserMessageDelivery = 'delivered' | 'unsupported' | 'not-running';
|
|
198
218
|
/** Process discovery is a getter; process collection and stopping accept explicit host inputs. */
|
|
199
219
|
export type CollectProcessTreePidsPort = (args: {
|
|
200
220
|
readonly processes: ProcessSnapshot[];
|
|
@@ -212,11 +232,11 @@ export interface TerminateChildTreeDeps {
|
|
|
212
232
|
* Which step reported a contained failure through `onCleanupFailure` (SEC-007).
|
|
213
233
|
*
|
|
214
234
|
* The first three come from {@link terminateChildTreeBestEffort} (process-tree teardown). The last
|
|
215
|
-
*
|
|
216
|
-
*
|
|
217
|
-
* transition, and
|
|
235
|
+
* three cover tool cancellation, staged-file removal and the host's own `classifyFailure`.
|
|
236
|
+
* These fallible steps between a child's `'close'` and `finish()` must never prevent the terminal
|
|
237
|
+
* transition, and none may fail silently either. See each close handler.
|
|
218
238
|
*/
|
|
219
|
-
export type AgentCleanupFailurePhase = 'cancel' | 'acp-attach-failure' | 'pi-rpc-attach-failure' | 'staged-file-cleanup' | 'failure-classification';
|
|
239
|
+
export type AgentCleanupFailurePhase = 'cancel' | 'acp-attach-failure' | 'pi-rpc-attach-failure' | 'tool-cancellation' | 'staged-file-cleanup' | 'failure-classification';
|
|
220
240
|
export interface AgentCleanupFailureContext {
|
|
221
241
|
readonly runId: string;
|
|
222
242
|
readonly phase: AgentCleanupFailurePhase;
|
|
@@ -237,6 +257,8 @@ export interface StdinCloseHandle {
|
|
|
237
257
|
closeStdinOnce(): void;
|
|
238
258
|
/** Journals a sent-to-stdin byte chunk, queued through the same FIFO {@link wireChildLifecycle} already uses for emitted events. No-op when no journal was configured (see `CreateAgentExecutorOptions.journal`). */
|
|
239
259
|
recordSentBytes(content: string): void;
|
|
260
|
+
/** Interrupts this child's turn, then writes a mid-run user message into its open stdin — see {@link AgentExecutor.sendUserMessage}. */
|
|
261
|
+
sendUserMessage(text: string): Promise<UserMessageDelivery>;
|
|
240
262
|
}
|
|
241
263
|
/**
|
|
242
264
|
* Gap 3 (capability-routed continuation transport) — host-owned config for the
|
|
@@ -374,6 +396,13 @@ export interface McpJsonInjectionOptions {
|
|
|
374
396
|
readonly removeDir?: ({ path }: {
|
|
375
397
|
readonly path: string;
|
|
376
398
|
}) => Promise<void>;
|
|
399
|
+
/** `'codex-toml'` only. Links the run home's sessions/archived_sessions to the operator's
|
|
400
|
+
* persistent rollout store. Config and auth remain isolated and are removed after the run.
|
|
401
|
+
* @default Native mkdir (0700) and directory symlinks; errors fail staging before spawn. */
|
|
402
|
+
readonly linkSessionStore?: (required: {
|
|
403
|
+
runHome: string;
|
|
404
|
+
sourceHome: string;
|
|
405
|
+
}, optional?: {}) => Promise<void>;
|
|
377
406
|
}
|
|
378
407
|
/** One `.mcp.json` `mcpServers` entry — the shape Claude Code's own config schema expects. */
|
|
379
408
|
export interface McpJsonServerEntry {
|
|
@@ -543,6 +572,8 @@ export interface FailureClassificationContext {
|
|
|
543
572
|
export type ClassifyFailure = (context: FailureClassificationContext) => boolean | Promise<boolean>;
|
|
544
573
|
export interface CreateAgentExecutorOptions {
|
|
545
574
|
readonly lifecycle: RunLifecycle;
|
|
575
|
+
/** Resolves/pins the concrete starting model against the actual launch scope. */
|
|
576
|
+
readonly resolveModelForLaunch?: typeof resolveModelForLaunch;
|
|
546
577
|
/** @default the real `@jini-ai/agent-runtime` registry lookup */
|
|
547
578
|
readonly getAgentDef?: typeof getAgentDef;
|
|
548
579
|
/** @default the real `@jini-ai/agent-runtime` launch resolver */
|
|
@@ -1,12 +1,3 @@
|
|
|
1
|
-
import {} from 'node:child_process';
|
|
2
|
-
import {} from '@jini-ai/core';
|
|
3
|
-
import {} from '@jini-ai/protocol';
|
|
4
|
-
import {} from '@jini-ai/agent-runtime';
|
|
5
|
-
import {} from '@jini-ai/platform';
|
|
6
|
-
import {} from '../continuation/journal.js';
|
|
7
|
-
import {} from '../run/core/index.js';
|
|
8
|
-
import {} from '../tool-executor.js';
|
|
9
|
-
import {} from '../run-lifecycle.js';
|
|
10
1
|
export const SUPPORTED_STREAM_FORMATS = [
|
|
11
2
|
'claude-stream-json',
|
|
12
3
|
'json-event-stream',
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
1
|
+
import type { RunAgentPayload, RunErrorPayload } from '@jini-ai/protocol';
|
|
2
|
+
import type { AgentRuntimeEventTranslation } from './contracts.js';
|
|
3
3
|
/**
|
|
4
4
|
* Narrows a parsed `usage` event's `usage` sub-object (`{input_tokens?, output_tokens?}`) — the one
|
|
5
5
|
* piece of {@link translateUsagePayload} with real nested branching (an optional container holding
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { ModelCatalogSnapshot } from '@jini-ai/agent-runtime';
|
|
2
|
+
import type { ChildProcess } from 'node:child_process';
|
|
2
3
|
import { attachAcpSession, attachPiRpcSession, type AcpPermissionHandler, type RuntimeAgentDef } from '@jini-ai/agent-runtime';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
4
|
+
import type { RunByteJournal } from '../continuation/journal.js';
|
|
5
|
+
import type { RunLifecycle } from '../run-lifecycle.js';
|
|
6
|
+
import type { ChildDrivenStreamFormat, TerminateChildTreeDeps, AgentCleanupFailureContext, StdinCloseHandle, ContinuationOptions, McpBridgeDelivery, ClassifyFailure, FailBeforeSpawn } from './contracts.js';
|
|
6
7
|
/** Default sink when a host does not supply `onCleanupFailure`: still observable, never silent. Redacted per SEC-007 (a spawn/permission error can embed paths/host detail). */
|
|
7
8
|
export declare function defaultCleanupFailureSink(context: AgentCleanupFailureContext): void;
|
|
8
9
|
/**
|
|
@@ -22,6 +23,8 @@ export declare function defaultCleanupFailureSink(context: AgentCleanupFailureCo
|
|
|
22
23
|
*/
|
|
23
24
|
export declare const DEFAULT_BUFFERED_STDOUT_MAX_BYTES: number;
|
|
24
25
|
interface WireChildLifecycleContext extends TerminateChildTreeDeps {
|
|
26
|
+
readonly startingModel?: string;
|
|
27
|
+
readonly modelCatalog?: ModelCatalogSnapshot;
|
|
25
28
|
readonly runId: string;
|
|
26
29
|
readonly def: RuntimeAgentDef;
|
|
27
30
|
readonly streamFormat: ChildDrivenStreamFormat;
|
|
@@ -115,6 +118,21 @@ interface WireChildLifecycleContext extends TerminateChildTreeDeps {
|
|
|
115
118
|
* @overallScore 100/100
|
|
116
119
|
*/
|
|
117
120
|
export declare function wireChildLifecycle(ctx: WireChildLifecycleContext): StdinCloseHandle;
|
|
121
|
+
/**
|
|
122
|
+
* Whether a def's live process can take another user message mid-run: only a stream-json stdin
|
|
123
|
+
* transport keeps stdin open for more JSONL user lines (see `RuntimeAgentDef.promptInputFormat`).
|
|
124
|
+
* Deliberately not `resolveContinuationTransport`: that answers how a tool result gets back, and
|
|
125
|
+
* reports `'mcp-callback'` for Claude even though its stdin takes user lines all the same.
|
|
126
|
+
*/
|
|
127
|
+
export declare function acceptsMidRunUserMessages({ def }: {
|
|
128
|
+
readonly def: RuntimeAgentDef;
|
|
129
|
+
}): boolean;
|
|
130
|
+
/**
|
|
131
|
+
* How long a mid-run message waits for the CLI to acknowledge its interrupt before being written
|
|
132
|
+
* anyway. Claude Code acks within milliseconds (it answers before the aborted turn's own result);
|
|
133
|
+
* the ceiling only bounds an agent that ignores control requests.
|
|
134
|
+
*/
|
|
135
|
+
export declare const INTERRUPT_ACK_TIMEOUT_MS = 5000;
|
|
118
136
|
/**
|
|
119
137
|
* Writes the initial user turn to the child's stdin per `def.promptInputFormat`
|
|
120
138
|
* (both branches only run for `promptViaStdin: true` defs — the only shape
|
|
@@ -122,8 +140,8 @@ export declare function wireChildLifecycle(ctx: WireChildLifecycleContext): Stdi
|
|
|
122
140
|
* - `'text'` (default): the raw prompt buffer, then stdin is closed —
|
|
123
141
|
* matches `RuntimeAgentDef.promptInputFormat`'s own doc.
|
|
124
142
|
* - `'stream-json'`: one JSONL line wrapping the prompt as an Anthropic
|
|
125
|
-
* user message; stdin is deliberately left open
|
|
126
|
-
*
|
|
143
|
+
* user message; stdin is deliberately left open so a message the human
|
|
144
|
+
* sends mid-run can follow it (`StdinCloseHandle.sendUserMessage`), and
|
|
127
145
|
* {@link wireChildLifecycle}'s `turn_end` handling closes it once the
|
|
128
146
|
* agent's own stream reports the turn ended.
|
|
129
147
|
* @param def - The resolved agent def (only `.promptInputFormat` is read).
|
|
@@ -141,6 +159,7 @@ interface RunAcpDispatchInput {
|
|
|
141
159
|
readonly prompt: string;
|
|
142
160
|
readonly cwd: string;
|
|
143
161
|
readonly model: string | undefined;
|
|
162
|
+
readonly modelCatalog?: ModelCatalogSnapshot;
|
|
144
163
|
readonly imagePaths: readonly string[];
|
|
145
164
|
readonly envFormat: 'array' | 'map' | undefined;
|
|
146
165
|
readonly mcpBridge: McpBridgeDelivery | null;
|
|
@@ -168,6 +187,7 @@ interface RunPiRpcDispatchInput {
|
|
|
168
187
|
readonly prompt: string;
|
|
169
188
|
readonly cwd: string;
|
|
170
189
|
readonly model: string | undefined;
|
|
190
|
+
readonly modelCatalog?: ModelCatalogSnapshot;
|
|
171
191
|
readonly imagePaths: readonly string[];
|
|
172
192
|
readonly uploadRoot: string | undefined;
|
|
173
193
|
}
|
|
@@ -1,18 +1,15 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { createModelReceiptTracker } from './model-receipts.js';
|
|
1
3
|
import { messageContentWithImages } from '../attachment-content.js';
|
|
2
|
-
import {} from 'node:child_process';
|
|
3
4
|
import { redactSecrets, } from '@jini-ai/core';
|
|
4
|
-
import {} from '@jini-ai/protocol';
|
|
5
5
|
import { createClaudeStreamHandler, createCopilotStreamHandler, createJsonEventStreamHandler, createQoderStreamHandler, attachAcpSession, attachPiRpcSession, } from '@jini-ai/agent-runtime';
|
|
6
6
|
import { collectProcessTreePids, listProcessSnapshots, stopProcesses, } from '@jini-ai/platform';
|
|
7
7
|
import { classifyRunCloseStatus, } from '../close-status.js';
|
|
8
8
|
import { resolveContinuationTransport, } from '../continuation/continuation-transport.js';
|
|
9
|
-
import {} from '../continuation/journal.js';
|
|
10
9
|
import { resultContent, } from '../delegated-tool-bridge.js';
|
|
11
10
|
import { extractResultMedia, } from '../tool-result-media.js';
|
|
12
|
-
import {} from '../run-lifecycle.js';
|
|
13
|
-
import {} from './contracts.js';
|
|
14
11
|
import { translateAgentRuntimeEvent, translateAcpError, applyAgentTranslationSideEffects, } from './event-translation.js';
|
|
15
|
-
import { errorMessage, } from './values.js';
|
|
12
|
+
import { errorMessage, isRecord, } from './values.js';
|
|
16
13
|
import { MCP_BRIDGE_UNAVAILABLE, unavailableJiniBridgeStatus, bridgeUnavailableMessage, } from './mcp-bridge.js';
|
|
17
14
|
/** Carry PID only on structured status so the host can record its OS start identity early.
|
|
18
15
|
* A PID alone is never proof of death; hosts verify PID reuse before native continuation. */
|
|
@@ -72,7 +69,7 @@ export function defaultCleanupFailureSink(context) {
|
|
|
72
69
|
/**
|
|
73
70
|
* Reports a contained post-close failure through the host's sink, absorbing a throwing sink.
|
|
74
71
|
*
|
|
75
|
-
* A diagnostic sink is host code too, and the whole point of
|
|
72
|
+
* A diagnostic sink is host code too, and the whole point of these callers is that nothing
|
|
76
73
|
* between `'close'` and `finish()` can strand the run — a sink that throws must not reintroduce
|
|
77
74
|
* exactly that. Same reasoning `run-lifecycle.ts`'s `handleInactivityTimeout` already applies to its
|
|
78
75
|
* own `onInternalError`.
|
|
@@ -260,6 +257,7 @@ function bufferedStdoutTruncationNotice(droppedBytes, maxBytes) {
|
|
|
260
257
|
*/
|
|
261
258
|
export function wireChildLifecycle(ctx) {
|
|
262
259
|
const { runId, def, streamFormat, child, lifecycle, journal, continuation, classifyFailure } = ctx;
|
|
260
|
+
const modelReceipt = createModelReceiptTracker(ctx.startingModel, ctx.modelCatalog?.models);
|
|
263
261
|
let stdinClosed = false;
|
|
264
262
|
let cancelRequested = false;
|
|
265
263
|
let emitQueue = Promise.resolve();
|
|
@@ -276,6 +274,37 @@ export function wireChildLifecycle(ctx) {
|
|
|
276
274
|
// consumed by a turn-end injection decision. See `ContinuationOptions`'s doc for why this is
|
|
277
275
|
// only ever acted on when a host has explicitly allowlisted the tool's name.
|
|
278
276
|
let pendingToolUse;
|
|
277
|
+
// Observe the canonical lifecycle, including delegated calls that bypass the CLI parser.
|
|
278
|
+
// A single latest tool_use cannot represent parallel tools at an interrupt boundary.
|
|
279
|
+
const unresolvedToolCalls = new Set();
|
|
280
|
+
const interruptedToolCalls = new Set();
|
|
281
|
+
const toolSubscription = lifecycle.stream({ runId, onEvent: (event) => {
|
|
282
|
+
if (event.kind !== 'agent')
|
|
283
|
+
return;
|
|
284
|
+
if (event.payload.type === 'tool_use')
|
|
285
|
+
unresolvedToolCalls.add(event.payload.id);
|
|
286
|
+
if (event.payload.type === 'tool_result')
|
|
287
|
+
unresolvedToolCalls.delete(event.payload.toolUseId);
|
|
288
|
+
} }).catch(error => {
|
|
289
|
+
// Observing tools is fallible I/O too: report it, but never strand close/finish on a replay
|
|
290
|
+
// failure or leave an unhandled rejection while the child is still running.
|
|
291
|
+
reportPostCloseFailure(ctx.onCleanupFailure, { runId, phase: 'tool-cancellation', pid: child.pid, error });
|
|
292
|
+
return null;
|
|
293
|
+
});
|
|
294
|
+
/** Run on the same FIFO as parsed results, after the aborted segment has drained.
|
|
295
|
+
* O(t) in unresolved calls; completed results are never replaced with cancellation. */
|
|
296
|
+
async function cancelUnresolvedToolCalls(ids) {
|
|
297
|
+
await toolSubscription;
|
|
298
|
+
for (const toolUseId of ids ?? [...unresolvedToolCalls]) {
|
|
299
|
+
if (!unresolvedToolCalls.has(toolUseId))
|
|
300
|
+
continue;
|
|
301
|
+
await lifecycle.emit({ runId, input: { event: 'agent', data: {
|
|
302
|
+
type: 'tool_result', toolUseId, content: 'Tool execution cancelled.', isError: true,
|
|
303
|
+
} } }).catch(error => {
|
|
304
|
+
reportPostCloseFailure(ctx.onCleanupFailure, { runId, phase: 'tool-cancellation', pid: child.pid, error });
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
}
|
|
279
308
|
// Bridge guard (see `expectsJiniBridge`): checked on the first init frame only. Once the bridge is
|
|
280
309
|
// found unavailable, the child is being stopped and nothing it still prints is forwarded.
|
|
281
310
|
let bridgeChecked = !ctx.expectsJiniBridge;
|
|
@@ -306,12 +335,43 @@ export function wireChildLifecycle(ctx) {
|
|
|
306
335
|
}
|
|
307
336
|
});
|
|
308
337
|
}
|
|
338
|
+
if (ctx.startingModel)
|
|
339
|
+
enqueueEmit(() => lifecycle.emit({ runId, input: { event: 'agent', data: { type: 'status', label: 'starting_model', model: ctx.startingModel } } }));
|
|
309
340
|
function closeStdinOnce() {
|
|
310
341
|
if (stdinClosed)
|
|
311
342
|
return;
|
|
312
343
|
stdinClosed = true;
|
|
313
344
|
child.stdin?.end();
|
|
314
345
|
}
|
|
346
|
+
// Mid-run interrupts (see `sendUserMessage` below): each sent `interrupt` control request waits
|
|
347
|
+
// here, by request id, for the CLI's `control_response`. Settled with `true` on the ack, `false`
|
|
348
|
+
// when the process exits first. Bounded by the mid-run messages in flight on this one run.
|
|
349
|
+
const pendingInterruptAcks = new Map();
|
|
350
|
+
// Set once this run has interrupted its agent: from then on a turn the interrupt aborted
|
|
351
|
+
// (`aborted_*` stop reason) is not the run's last — the message that follows starts a new one.
|
|
352
|
+
let interruptSent = false;
|
|
353
|
+
// stdout carry-over for spotting acks; only filled while an interrupt waits for one.
|
|
354
|
+
let ackScanBuffer = '';
|
|
355
|
+
/** Resolves every waiting interrupt whose `control_response` is in this stdout chunk. @complexity O(chunk length). */
|
|
356
|
+
function scanForInterruptAcks(text) {
|
|
357
|
+
if (pendingInterruptAcks.size === 0)
|
|
358
|
+
return;
|
|
359
|
+
ackScanBuffer += text;
|
|
360
|
+
const lines = ackScanBuffer.split('\n');
|
|
361
|
+
ackScanBuffer = lines.pop() ?? '';
|
|
362
|
+
for (const line of lines) {
|
|
363
|
+
if (!line.includes('"control_response"'))
|
|
364
|
+
continue;
|
|
365
|
+
const requestId = controlResponseRequestId({ line: line });
|
|
366
|
+
const settle = requestId === undefined ? undefined : pendingInterruptAcks.get(requestId);
|
|
367
|
+
if (!settle)
|
|
368
|
+
continue;
|
|
369
|
+
pendingInterruptAcks.delete(requestId);
|
|
370
|
+
settle(true);
|
|
371
|
+
}
|
|
372
|
+
if (pendingInterruptAcks.size === 0)
|
|
373
|
+
ackScanBuffer = '';
|
|
374
|
+
}
|
|
315
375
|
/**
|
|
316
376
|
* Writes a structured (never string-concatenated — see `ContinuationOptions`'s doc on the
|
|
317
377
|
* prompt-injection stakes here) tool_result JSONL line, mirroring the shape
|
|
@@ -331,6 +391,21 @@ export function wireChildLifecycle(ctx) {
|
|
|
331
391
|
if (journal)
|
|
332
392
|
enqueueEmit(() => journal.record({ runId: runId, entry: sentJournalEntry(content) }));
|
|
333
393
|
}
|
|
394
|
+
/**
|
|
395
|
+
* Whether a `turn_end` leaves stdin open for a live agent that takes mid-run messages, because
|
|
396
|
+
* the run is not over: a `tool_use` stop (the CLI runs the tool itself and carries on, and a
|
|
397
|
+
* message sent while the tool runs must still reach it), any end while an interrupt still waits
|
|
398
|
+
* for its ack (the message is about to be written), and the end of a turn an interrupt aborted
|
|
399
|
+
* (the message written after it starts the next turn). Every other end closes stdin, so the CLI
|
|
400
|
+
* exits once it has answered everything written before EOF.
|
|
401
|
+
*/
|
|
402
|
+
function keepsStdinOpenAfterTurnEnd(stopReason) {
|
|
403
|
+
if (!acceptsMidRunUserMessages({ def: def }))
|
|
404
|
+
return false;
|
|
405
|
+
if (stopReason === 'tool_use' || pendingInterruptAcks.size > 0)
|
|
406
|
+
return true;
|
|
407
|
+
return interruptSent && stopReason !== undefined && stopReason.startsWith('aborted');
|
|
408
|
+
}
|
|
334
409
|
/**
|
|
335
410
|
* Decides, per `turn_end`, whether to auto-resolve a pending tool_use through the injected
|
|
336
411
|
* `ToolExecutor` and keep stdin open (gap 3), or close stdin exactly as every version of this
|
|
@@ -338,6 +413,11 @@ export function wireChildLifecycle(ctx) {
|
|
|
338
413
|
* unconfigured or the pending tool isn't allowlisted).
|
|
339
414
|
*/
|
|
340
415
|
function handleTurnEnd(stopReason) {
|
|
416
|
+
if (stopReason?.startsWith('aborted'))
|
|
417
|
+
enqueueEmit(async () => {
|
|
418
|
+
await cancelUnresolvedToolCalls([...interruptedToolCalls]);
|
|
419
|
+
interruptedToolCalls.clear();
|
|
420
|
+
});
|
|
341
421
|
const toolUse = pendingToolUse;
|
|
342
422
|
const shouldInject = stopReason === 'tool_use' &&
|
|
343
423
|
toolUse !== undefined &&
|
|
@@ -345,7 +425,8 @@ export function wireChildLifecycle(ctx) {
|
|
|
345
425
|
resolveContinuationTransport({ def: def }) === 'stdin-injection' &&
|
|
346
426
|
continuation.autonomousToolNames.has(toolUse.name);
|
|
347
427
|
if (!shouldInject) {
|
|
348
|
-
|
|
428
|
+
if (!keepsStdinOpenAfterTurnEnd(stopReason))
|
|
429
|
+
closeStdinOnce();
|
|
349
430
|
return;
|
|
350
431
|
}
|
|
351
432
|
pendingToolUse = undefined;
|
|
@@ -399,6 +480,9 @@ export function wireChildLifecycle(ctx) {
|
|
|
399
480
|
return;
|
|
400
481
|
const translation = translateAgentRuntimeEvent({ rawEvent: rawEvent });
|
|
401
482
|
if (translation.kind === 'agent') {
|
|
483
|
+
const receipt = modelReceipt(translation.payload);
|
|
484
|
+
if (receipt)
|
|
485
|
+
enqueueEmit(() => lifecycle.emit({ runId, input: { event: 'agent', data: receipt } }));
|
|
402
486
|
if (translation.sessionId !== undefined)
|
|
403
487
|
capturedSessionId = translation.sessionId;
|
|
404
488
|
if (!bridgeChecked && translation.payload.type === 'status' && translation.payload.label === 'initializing') {
|
|
@@ -495,6 +579,9 @@ export function wireChildLifecycle(ctx) {
|
|
|
495
579
|
return;
|
|
496
580
|
}
|
|
497
581
|
enqueueEmit(() => lifecycle.emit({ runId: runId, input: { event: 'stdout', data: { chunk: text } } }));
|
|
582
|
+
// Before the parser: an ack and the aborted turn's end can share a chunk, and the turn end must
|
|
583
|
+
// see that no interrupt is still waiting (see `keepsStdinOpenAfterTurnEnd`).
|
|
584
|
+
scanForInterruptAcks(text);
|
|
498
585
|
// Non-null: `streamHandler` is only ever null when `streamFormat === 'plain'` (see its
|
|
499
586
|
// construction above), the branch this statement is provably unreachable from.
|
|
500
587
|
streamHandler.feed({ chunk: text });
|
|
@@ -520,6 +607,9 @@ export function wireChildLifecycle(ctx) {
|
|
|
520
607
|
void terminateChildTreeBestEffort(ctx, child, runId, 'cancel', ctx.onCleanupFailure);
|
|
521
608
|
} });
|
|
522
609
|
child.on('close', (code, signal) => {
|
|
610
|
+
for (const settle of pendingInterruptAcks.values())
|
|
611
|
+
settle(false);
|
|
612
|
+
pendingInterruptAcks.clear();
|
|
523
613
|
void (async () => {
|
|
524
614
|
// Not wrapped in try/catch: all 4 supported parser factories'
|
|
525
615
|
// flush() implementations already internally guard their own
|
|
@@ -534,6 +624,11 @@ export function wireChildLifecycle(ctx) {
|
|
|
534
624
|
// `finish()`'s `'end'` event, exactly like every live-path emit already is.
|
|
535
625
|
flushBufferedStdout();
|
|
536
626
|
await emitQueue;
|
|
627
|
+
if (cancelRequested)
|
|
628
|
+
await cancelUnresolvedToolCalls();
|
|
629
|
+
const subscribedTools = await toolSubscription;
|
|
630
|
+
if (subscribedTools?.kind === 'ok')
|
|
631
|
+
subscribedTools.unsubscribe();
|
|
537
632
|
unsubscribeCancel();
|
|
538
633
|
// Both of the next two steps are guarded: neither a failed cleanup nor a rejecting host
|
|
539
634
|
// classifier may prevent the terminal transition below — see each helper's own doc.
|
|
@@ -552,14 +647,92 @@ export function wireChildLifecycle(ctx) {
|
|
|
552
647
|
await lifecycle.finish({ runId, status, code, signal: signal ?? null, resumable }, { ...(capturedSessionId !== undefined ? { sessionRef: capturedSessionId } : {}) });
|
|
553
648
|
})();
|
|
554
649
|
});
|
|
650
|
+
/**
|
|
651
|
+
* A mid-run message: first an `interrupt` control request on the still-open stdin, so the agent
|
|
652
|
+
* stops generating (or abandons the tool it is running) at once instead of finishing its whole
|
|
653
|
+
* reply; then, once the CLI acknowledges, the message as the next user line, which the CLI
|
|
654
|
+
* answers straight away in the same session; then the run's own `user_message` event through the
|
|
655
|
+
* same FIFO as the agent's output, so the message sits in the stream where it took effect.
|
|
656
|
+
* An ack that never comes (an agent that ignores control requests) only delays the write by
|
|
657
|
+
* {@link INTERRUPT_ACK_TIMEOUT_MS}: the CLI then folds the line in at its next step. Once
|
|
658
|
+
* `turn_end` has closed stdin, or the process exits before the ack, there is no session left to
|
|
659
|
+
* reach — `'not-running'`.
|
|
660
|
+
*/
|
|
661
|
+
async function sendUserMessage(text) {
|
|
662
|
+
if (!acceptsMidRunUserMessages({ def: def }))
|
|
663
|
+
return 'unsupported';
|
|
664
|
+
const stdin = child.stdin;
|
|
665
|
+
if (stdinClosed || !stdin)
|
|
666
|
+
return 'not-running';
|
|
667
|
+
const requestId = `jini-interrupt-${randomUUID()}`;
|
|
668
|
+
interruptSent = true;
|
|
669
|
+
// Capture before requesting the interrupt. Its result can precede the acknowledgement, or
|
|
670
|
+
// arrive after the next segment starts: neither ordering may cancel that segment's new tools.
|
|
671
|
+
enqueueEmit(async () => {
|
|
672
|
+
await toolSubscription;
|
|
673
|
+
for (const id of interruptedToolCalls)
|
|
674
|
+
if (!unresolvedToolCalls.has(id))
|
|
675
|
+
interruptedToolCalls.delete(id);
|
|
676
|
+
for (const id of unresolvedToolCalls)
|
|
677
|
+
interruptedToolCalls.add(id);
|
|
678
|
+
});
|
|
679
|
+
const acked = new Promise((resolve) => pendingInterruptAcks.set(requestId, resolve));
|
|
680
|
+
stdin.write(`${JSON.stringify({ type: 'control_request', request_id: requestId, request: { subtype: 'interrupt' } })}\n`, 'utf8');
|
|
681
|
+
let timer;
|
|
682
|
+
const timedOut = new Promise((resolve) => {
|
|
683
|
+
timer = setTimeout(() => resolve(true), INTERRUPT_ACK_TIMEOUT_MS);
|
|
684
|
+
});
|
|
685
|
+
const processAlive = await Promise.race([acked, timedOut]);
|
|
686
|
+
clearTimeout(timer);
|
|
687
|
+
pendingInterruptAcks.delete(requestId);
|
|
688
|
+
if (!processAlive || stdinClosed)
|
|
689
|
+
return 'not-running';
|
|
690
|
+
stdin.write(`${JSON.stringify(streamJsonUserMessage({ content: [{ type: 'text', text: text }] }))}\n`, 'utf8');
|
|
691
|
+
if (journal)
|
|
692
|
+
enqueueEmit(() => journal.record({ runId: runId, entry: sentJournalEntry(text) }));
|
|
693
|
+
enqueueEmit(() => lifecycle.emit({ runId: runId, input: { event: 'agent', data: { type: 'user_message', id: randomUUID(), text: text } } }));
|
|
694
|
+
return 'delivered';
|
|
695
|
+
}
|
|
555
696
|
return {
|
|
556
697
|
closeStdinOnce,
|
|
557
698
|
recordSentBytes(content) {
|
|
558
699
|
if (journal)
|
|
559
700
|
enqueueEmit(() => journal.record({ runId: runId, entry: sentJournalEntry(content) }));
|
|
560
701
|
},
|
|
702
|
+
sendUserMessage,
|
|
561
703
|
};
|
|
562
704
|
}
|
|
705
|
+
/**
|
|
706
|
+
* Whether a def's live process can take another user message mid-run: only a stream-json stdin
|
|
707
|
+
* transport keeps stdin open for more JSONL user lines (see `RuntimeAgentDef.promptInputFormat`).
|
|
708
|
+
* Deliberately not `resolveContinuationTransport`: that answers how a tool result gets back, and
|
|
709
|
+
* reports `'mcp-callback'` for Claude even though its stdin takes user lines all the same.
|
|
710
|
+
*/
|
|
711
|
+
export function acceptsMidRunUserMessages({ def }) {
|
|
712
|
+
return def.promptViaStdin === true && def.promptInputFormat === 'stream-json';
|
|
713
|
+
}
|
|
714
|
+
/**
|
|
715
|
+
* How long a mid-run message waits for the CLI to acknowledge its interrupt before being written
|
|
716
|
+
* anyway. Claude Code acks within milliseconds (it answers before the aborted turn's own result);
|
|
717
|
+
* the ceiling only bounds an agent that ignores control requests.
|
|
718
|
+
*/
|
|
719
|
+
export const INTERRUPT_ACK_TIMEOUT_MS = 5_000;
|
|
720
|
+
/** The `request_id` of a stream-json `control_response` line, or `undefined` for anything else. */
|
|
721
|
+
function controlResponseRequestId({ line }) {
|
|
722
|
+
try {
|
|
723
|
+
const parsed = JSON.parse(line);
|
|
724
|
+
if (!isRecord(parsed) || parsed.type !== 'control_response' || !isRecord(parsed.response))
|
|
725
|
+
return undefined;
|
|
726
|
+
return typeof parsed.response.request_id === 'string' ? parsed.response.request_id : undefined;
|
|
727
|
+
}
|
|
728
|
+
catch {
|
|
729
|
+
return undefined;
|
|
730
|
+
}
|
|
731
|
+
}
|
|
732
|
+
/** The stream-json stdin envelope for one user message — the initial prompt and every mid-run one. */
|
|
733
|
+
function streamJsonUserMessage({ content }) {
|
|
734
|
+
return { type: 'user', message: { role: 'user', content: content } };
|
|
735
|
+
}
|
|
563
736
|
/**
|
|
564
737
|
* Wires an ACP child to a run. Unlike the JSON-stream path, ACP owns the
|
|
565
738
|
* prompt protocol and reports its parsed events through `attachAcpSession`'s
|
|
@@ -570,6 +743,7 @@ export function wireChildLifecycle(ctx) {
|
|
|
570
743
|
* success.
|
|
571
744
|
*/
|
|
572
745
|
function wireAcpLifecycle(ctx) {
|
|
746
|
+
const modelReceipt = createModelReceiptTracker(ctx.model, ctx.modelCatalog?.models);
|
|
573
747
|
const { runId, agentId, child, lifecycle, journal, classifyFailure } = ctx;
|
|
574
748
|
let cancelRequested = false;
|
|
575
749
|
let emitQueue = Promise.resolve();
|
|
@@ -589,6 +763,8 @@ function wireAcpLifecycle(ctx) {
|
|
|
589
763
|
}
|
|
590
764
|
});
|
|
591
765
|
}
|
|
766
|
+
if (ctx.model)
|
|
767
|
+
enqueueEmit(() => lifecycle.emit({ runId, input: { event: 'agent', data: { type: 'status', label: 'starting_model', model: ctx.model } } }));
|
|
592
768
|
child.stdout?.on('data', (chunk) => {
|
|
593
769
|
const text = chunk.toString('utf8');
|
|
594
770
|
if (journal)
|
|
@@ -632,6 +808,9 @@ function wireAcpLifecycle(ctx) {
|
|
|
632
808
|
if (event === 'agent') {
|
|
633
809
|
const translation = translateAgentRuntimeEvent({ rawEvent: payload });
|
|
634
810
|
if (translation.kind === 'agent') {
|
|
811
|
+
const receipt = modelReceipt(translation.payload);
|
|
812
|
+
if (receipt)
|
|
813
|
+
enqueueEmit(() => lifecycle.emit({ runId, input: { event: 'agent', data: receipt } }));
|
|
635
814
|
applyAgentTranslationSideEffects({ payload: translation.payload, sessionId: translation.sessionId, sink: {
|
|
636
815
|
onSessionId: ({ sessionId }) => { capturedSessionId = sessionId; },
|
|
637
816
|
onToolCall: () => { toolCallSeen = true; },
|
|
@@ -674,6 +853,7 @@ function wireAcpLifecycle(ctx) {
|
|
|
674
853
|
* multi-turn tool continuation, resumable session ids, etc.).
|
|
675
854
|
*/
|
|
676
855
|
function wirePiRpcLifecycle(ctx) {
|
|
856
|
+
const modelReceipt = createModelReceiptTracker(ctx.model, ctx.modelCatalog?.models);
|
|
677
857
|
const { runId, agentId, child, lifecycle, journal, classifyFailure } = ctx;
|
|
678
858
|
let cancelRequested = false;
|
|
679
859
|
let emitQueue = Promise.resolve();
|
|
@@ -693,6 +873,8 @@ function wirePiRpcLifecycle(ctx) {
|
|
|
693
873
|
}
|
|
694
874
|
});
|
|
695
875
|
}
|
|
876
|
+
if (ctx.model)
|
|
877
|
+
enqueueEmit(() => lifecycle.emit({ runId, input: { event: 'agent', data: { type: 'status', label: 'starting_model', model: ctx.model } } }));
|
|
696
878
|
child.stdout?.on('data', (chunk) => {
|
|
697
879
|
const text = chunk.toString('utf8');
|
|
698
880
|
if (journal)
|
|
@@ -735,6 +917,9 @@ function wirePiRpcLifecycle(ctx) {
|
|
|
735
917
|
session = ctx.attachPiRpcSession({ child: ctx.child, prompt: ctx.prompt, send({ payload }) {
|
|
736
918
|
const translation = translateAgentRuntimeEvent({ rawEvent: payload });
|
|
737
919
|
if (translation.kind === 'agent') {
|
|
920
|
+
const receipt = modelReceipt(translation.payload);
|
|
921
|
+
if (receipt)
|
|
922
|
+
enqueueEmit(() => lifecycle.emit({ runId, input: { event: 'agent', data: receipt } }));
|
|
738
923
|
if (translation.sessionId !== undefined)
|
|
739
924
|
capturedSessionId = translation.sessionId;
|
|
740
925
|
if (translation.payload.type === 'tool_use') {
|
|
@@ -759,8 +944,8 @@ function wirePiRpcLifecycle(ctx) {
|
|
|
759
944
|
* - `'text'` (default): the raw prompt buffer, then stdin is closed —
|
|
760
945
|
* matches `RuntimeAgentDef.promptInputFormat`'s own doc.
|
|
761
946
|
* - `'stream-json'`: one JSONL line wrapping the prompt as an Anthropic
|
|
762
|
-
* user message; stdin is deliberately left open
|
|
763
|
-
*
|
|
947
|
+
* user message; stdin is deliberately left open so a message the human
|
|
948
|
+
* sends mid-run can follow it (`StdinCloseHandle.sendUserMessage`), and
|
|
764
949
|
* {@link wireChildLifecycle}'s `turn_end` handling closes it once the
|
|
765
950
|
* agent's own stream reports the turn ended.
|
|
766
951
|
* @param def - The resolved agent def (only `.promptInputFormat` is read).
|
|
@@ -775,7 +960,7 @@ export function writePromptToStdin(def, child, prompt, handle) {
|
|
|
775
960
|
if (!stdin)
|
|
776
961
|
return;
|
|
777
962
|
if (def.promptInputFormat === 'stream-json') {
|
|
778
|
-
const line = JSON.stringify({
|
|
963
|
+
const line = JSON.stringify(streamJsonUserMessage({ content: messageContentWithImages({ prompt, images: handle.imageContents ?? [] }, {}) }));
|
|
779
964
|
stdin.write(`${line}\n`, 'utf8');
|
|
780
965
|
handle.recordSentBytes(prompt);
|
|
781
966
|
return;
|
|
@@ -795,6 +980,7 @@ export async function runAcpDispatch({ input, deps }) {
|
|
|
795
980
|
prompt: input.prompt,
|
|
796
981
|
cwd: input.cwd,
|
|
797
982
|
model: input.model,
|
|
983
|
+
...(input.modelCatalog ? { modelCatalog: input.modelCatalog } : {}),
|
|
798
984
|
imagePaths: input.imagePaths,
|
|
799
985
|
envFormat: input.envFormat,
|
|
800
986
|
// Mechanism 2 of 5 — see `WireAcpLifecycleContext.mcpServers`. `undefined` for any def that
|
|
@@ -831,6 +1017,7 @@ export async function runPiRpcDispatch({ input, deps }) {
|
|
|
831
1017
|
prompt: input.prompt,
|
|
832
1018
|
cwd: input.cwd,
|
|
833
1019
|
model: input.model,
|
|
1020
|
+
...(input.modelCatalog ? { modelCatalog: input.modelCatalog } : {}),
|
|
834
1021
|
imagePaths: input.imagePaths,
|
|
835
1022
|
uploadRoot: input.uploadRoot,
|
|
836
1023
|
attachPiRpcSession: deps.attachPiRpcSession,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { RuntimeAgentDef, RuntimeLockHold } from '@jini-ai/agent-runtime';
|
|
2
2
|
/**
|
|
3
3
|
* Phase 7: acquires a `runtimeLock` def's process-global mutex before `buildArgs` runs — see
|
|
4
4
|
* `RuntimeLock`'s own doc for the concrete race. A no-op (`undefined`) for the 23 of 24 defs with no
|
|
@@ -89,7 +89,7 @@
|
|
|
89
89
|
* a second, independently-built (and rejected) classifier that once lived in
|
|
90
90
|
* this module.
|
|
91
91
|
*/
|
|
92
|
-
export { type SupportedStreamFormat, type AgentExecutorCompatibility, type AgentRuntimeEventTranslation, type AgentExecutorErrorCode, AgentExecutorError, type AgentExecutorRunInput, type AgentExecutor, type CollectProcessTreePidsPort, type StopProcessesPort, type AgentCleanupFailurePhase, type AgentCleanupFailureContext, type ContinuationOptions, type McpJsonInjectionOptions, type McpBridgeDelivery, type PreparedCodexHome, type PreparedClaudeConfigDir, type ClaudeConfigDirSeams, type ClaudeConfigDirIsolationOptions, type FailureClassificationContext, type ClassifyFailure, type CreateAgentExecutorOptions, type SystemPromptOverlayDelivery, type PreparedSystemPromptOverlayFile, type SpawnAgentChildProcessResult, } from './contracts.js';
|
|
92
|
+
export { type SupportedStreamFormat, type AgentExecutorCompatibility, type AgentRuntimeEventTranslation, type AgentExecutorErrorCode, AgentExecutorError, type AgentExecutorRunInput, type AgentExecutor, type UserMessageDelivery, type CollectProcessTreePidsPort, type StopProcessesPort, type AgentCleanupFailurePhase, type AgentCleanupFailureContext, type ContinuationOptions, type McpJsonInjectionOptions, type McpBridgeDelivery, type PreparedCodexHome, type PreparedClaudeConfigDir, type ClaudeConfigDirSeams, type ClaudeConfigDirIsolationOptions, type FailureClassificationContext, type ClassifyFailure, type CreateAgentExecutorOptions, type SystemPromptOverlayDelivery, type PreparedSystemPromptOverlayFile, type SpawnAgentChildProcessResult, } from './contracts.js';
|
|
93
93
|
export { isSupportedStreamFormat, assessAgentExecutorCompatibility, isAgentExecutorSupported, resolveDefAndStreamFormat, resolveImageDeliveryAndArgvBudget, resolveRunEnv, resolveLaunch, stagePromptFile, stageLogFile, computeChildEnv, computeRuntimeContext, buildAgentBuildArgsOptions, resolveSystemPromptOverlayDelivery, buildRunArgs, prepareSystemPromptOverlayFileIfNeeded, guardWindowsCommandLineBudget, spawnAgentChildProcess, isStdinDrivenFormat, confirmChildSpawned, createAgentExecutor, } from './launch.js';
|
|
94
94
|
export { extractUsageTokens, translateStatusEvent, translateToolResultEvent, translateErrorEvent, translateTurnEndEvent, translateAgentRuntimeEvent, applyAgentTranslationSideEffects, } from './event-translation.js';
|
|
95
95
|
export { MCP_BRIDGE_UNAVAILABLE, unavailableJiniBridgeStatus, buildMcpJsonServerEntry, mergeMcpJsonContent, buildAcpMcpBridgeServers, mergeEnvContentMcpConfig, mergeEnvContentInstructions, buildCodexMcpServerToml, buildCodexHomeConfigToml, resolveSourceCodexHomeDir, buildMcpBridgeDelivery, resolveSourceClaudeConfigDir, resolveMcpBridgeForRun, writeMcpJsonIfNeeded, prepareCodexHomeIfNeeded, prepareClaudeConfigDirIfNeeded, } from './mcp-bridge.js';
|
|
@@ -370,6 +370,6 @@ export declare function confirmChildSpawned({ input, deps }: {
|
|
|
370
370
|
* @complexity `run()`'s own setup is O(1); steady-state cost is the chosen stream parser's.
|
|
371
371
|
* @overallScore 100/100
|
|
372
372
|
*/
|
|
373
|
-
export declare function createAgentExecutor(requiredArgs: Pick<CreateAgentExecutorOptions, "lifecycle">, optionalArgs?: Pick<CreateAgentExecutorOptions, "getAgentDef" | "resolveAgentLaunch" | "ensureAgentCapabilities" | "applyAgentLaunchEnv" | "createCommandInvocation" | "spawn" | "attachAcpSession" | "acpPermissionHandler" | "attachPiRpcSession" | "preparePromptFileForAgent" | "prepareAgentLogFile" | "listProcessSnapshots" | "collectProcessTreePids" | "stopProcesses" | "onCleanupFailure" | "journal" | "continuation" | "classifyFailure" | "mcpJsonInjection" | "claudeConfigDirIsolation" | "claudeConfigDirIsolationEnabled" | "bufferedStdoutMaxBytes" | "promptAugmenter">): AgentExecutor;
|
|
373
|
+
export declare function createAgentExecutor(requiredArgs: Pick<CreateAgentExecutorOptions, "lifecycle">, optionalArgs?: Pick<CreateAgentExecutorOptions, "getAgentDef" | "resolveAgentLaunch" | "resolveModelForLaunch" | "ensureAgentCapabilities" | "applyAgentLaunchEnv" | "createCommandInvocation" | "spawn" | "attachAcpSession" | "acpPermissionHandler" | "attachPiRpcSession" | "preparePromptFileForAgent" | "prepareAgentLogFile" | "listProcessSnapshots" | "collectProcessTreePids" | "stopProcesses" | "onCleanupFailure" | "journal" | "continuation" | "classifyFailure" | "mcpJsonInjection" | "claudeConfigDirIsolation" | "claudeConfigDirIsolationEnabled" | "bufferedStdoutMaxBytes" | "promptAugmenter">): AgentExecutor;
|
|
374
374
|
export {};
|
|
375
375
|
//# sourceMappingURL=launch.d.ts.map
|