@agent-compose/sdk 0.6.0 → 0.8.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/README.md +66 -39
- package/dist/agent/__tests__/runtime-json-schema.test.d.ts +10 -0
- package/dist/agent/agent-context.d.ts +21 -1
- package/dist/agent/agent-loop.d.ts +24 -1
- package/dist/client.d.ts +338 -534
- package/dist/directives.d.ts +112 -0
- package/dist/display.d.ts +242 -0
- package/dist/errors.d.ts +24 -1
- package/dist/index.d.ts +34 -13
- package/dist/index.js +2984 -861
- package/dist/pause/wrappers.d.ts +31 -9
- package/dist/processors/ask-human.d.ts +30 -0
- package/dist/processors/ask-human.test.d.ts +1 -0
- package/dist/processors/index.d.ts +1 -0
- package/dist/runtimes/_acp-client.d.ts +46 -1
- package/dist/runtimes/_cli-agent.d.ts +58 -4
- package/dist/runtimes/_jsonl-guard.d.ts +103 -0
- package/dist/runtimes/amp.d.ts +2 -2
- package/dist/runtimes/claude-code.d.ts +59 -0
- package/dist/runtimes/claude-code.test.d.ts +14 -0
- package/dist/runtimes/claude.d.ts +16 -0
- package/dist/runtimes/claude.test.d.ts +8 -0
- package/dist/runtimes/codex.d.ts +9 -3
- package/dist/runtimes/cursor.d.ts +9 -0
- package/dist/runtimes/droid.d.ts +9 -0
- package/dist/runtimes/jsonl-guard.test.d.ts +19 -0
- package/dist/runtimes/openai-desktop.js +2922 -861
- package/dist/runtimes/opencode.d.ts +25 -0
- package/dist/runtimes/vercel.js +22 -1
- package/dist/sandbox/devbox.d.ts +42 -0
- package/dist/sandbox/exec-stream.d.ts +14 -0
- package/dist/sandbox/network-policy.d.ts +100 -0
- package/dist/sandbox/provider-def.d.ts +79 -0
- package/dist/sandbox/providers/desktop.d.ts +10 -0
- package/dist/sandbox/providers/e2b.d.ts +17 -0
- package/dist/sandbox/providers/local.d.ts +11 -0
- package/dist/sandbox/providers/vercel.d.ts +18 -0
- package/dist/sandbox/registry.d.ts +45 -0
- package/dist/sandbox/sizes.d.ts +68 -0
- package/dist/sandbox.d.ts +24 -299
- package/dist/step-invocation/__tests__/foreground-recovery.test.d.ts +1 -0
- package/dist/step-invocation/invoker.d.ts +24 -1
- package/dist/step-invocation/protocol.d.ts +13 -0
- package/dist/types/api-compliance.d.ts +71 -0
- package/dist/types/api-conversations.d.ts +492 -0
- package/dist/types/api-factory.d.ts +309 -0
- package/dist/types/api-projects.d.ts +131 -0
- package/dist/types/api-runs.d.ts +377 -0
- package/dist/types/api-scopes.d.ts +102 -0
- package/dist/types/conversation-stream.d.ts +191 -0
- package/dist/types/execution-context.d.ts +12 -2
- package/dist/types/protocol.d.ts +30 -1
- package/dist/types/sandbox-environment.d.ts +8 -5
- package/dist/types/sandbox.d.ts +79 -0
- package/dist/types/workflow-metadata.d.ts +33 -8
- package/dist/types/workflow-plan.d.ts +10 -0
- package/dist/types/workflow.d.ts +18 -193
- package/dist/utils/bundler.d.ts +12 -1
- package/dist/utils/errors.d.ts +9 -1
- package/dist/workflow-steps/index.d.ts +1 -1
- package/dist/workflow-steps/observability.d.ts +8 -1
- package/dist/workflow-steps/runner.d.ts +3 -3
- package/dist/workflow-steps/step.d.ts +15 -1
- package/dist/workflow-steps/types.d.ts +19 -5
- package/dist/workflow-steps/workflow.d.ts +22 -1
- package/dist/workflows/engine.d.ts +3 -2
- package/dist/workflows/invoke-child.d.ts +2 -2
- package/package.json +1 -1
- package/src/agent/agent-context.ts +206 -16
- package/src/agent/agent-loop.ts +40 -4
- package/src/agent/run-agent.ts +9 -1
- package/src/client.ts +909 -621
- package/src/directives.ts +184 -0
- package/src/display.ts +788 -0
- package/src/errors.ts +39 -0
- package/src/index.ts +117 -10
- package/src/pause/wrappers.ts +44 -9
- package/src/processors/ask-human.ts +136 -0
- package/src/processors/index.ts +5 -0
- package/src/runtimes/_acp-client.ts +72 -3
- package/src/runtimes/_cli-agent.ts +171 -38
- package/src/runtimes/_jsonl-guard.ts +219 -0
- package/src/runtimes/claude-code.ts +246 -0
- package/src/runtimes/claude.ts +32 -2
- package/src/runtimes/codex.ts +55 -3
- package/src/runtimes/cursor.ts +59 -0
- package/src/runtimes/droid.ts +63 -0
- package/src/runtimes/openai-desktop.ts +59 -14
- package/src/runtimes/opencode.ts +61 -0
- package/src/sandbox/devbox.ts +48 -0
- package/src/sandbox/exec-stream.ts +48 -0
- package/src/sandbox/network-policy.ts +181 -0
- package/src/sandbox/provider-def.ts +94 -0
- package/src/sandbox/providers/desktop.ts +57 -0
- package/src/sandbox/providers/e2b.ts +354 -0
- package/src/sandbox/providers/local.ts +106 -0
- package/src/sandbox/providers/vercel.ts +331 -0
- package/src/sandbox/registry.ts +198 -0
- package/src/sandbox/sizes.ts +95 -0
- package/src/sandbox.ts +59 -1263
- package/src/step-invocation/invoker.ts +319 -34
- package/src/step-invocation/protocol.ts +19 -0
- package/src/types/api-compliance.ts +79 -0
- package/src/types/api-conversations.ts +522 -0
- package/src/types/api-factory.ts +336 -0
- package/src/types/api-projects.ts +140 -0
- package/src/types/api-runs.ts +412 -0
- package/src/types/api-scopes.ts +102 -0
- package/src/types/conversation-stream.ts +231 -0
- package/src/types/execution-context.ts +10 -2
- package/src/types/protocol.ts +33 -0
- package/src/types/sandbox-environment.ts +28 -9
- package/src/types/sandbox.ts +78 -0
- package/src/types/workflow-metadata.ts +35 -8
- package/src/types/workflow-plan.ts +11 -0
- package/src/types/workflow.ts +25 -280
- package/src/utils/bundler.ts +32 -5
- package/src/utils/errors.ts +34 -2
- package/src/workflow-steps/index.ts +1 -0
- package/src/workflow-steps/observability.ts +19 -8
- package/src/workflow-steps/runner.ts +4 -4
- package/src/workflow-steps/step.ts +49 -1
- package/src/workflow-steps/types.ts +20 -5
- package/src/workflow-steps/workflow.ts +22 -1
- package/src/workflows/engine.ts +3 -2
- package/src/workflows/invoke-child.ts +2 -2
package/dist/pause/wrappers.d.ts
CHANGED
|
@@ -1,26 +1,29 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* The
|
|
3
|
-
* closure over `ctx.pause`:
|
|
2
|
+
* The three opinionated pause wrappers (ADR-0006 §"SDK surface", ADR-0042),
|
|
3
|
+
* each a thin closure over `ctx.pause`:
|
|
4
4
|
*
|
|
5
5
|
* - `sleep` — a lightweight timed pause; resolves on its own TTL,
|
|
6
6
|
* skips the snapshot, returns void.
|
|
7
7
|
* - `waitForEvent` — pause until an event resumes by correlation key.
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
8
|
+
* - `requestDecision` — a typed human/agent decision (wire `kind:
|
|
9
|
+
* "decision"`): the prompt/options/approvers ride
|
|
10
|
+
* `payload` for the dashboard's answer UI, and the
|
|
11
|
+
* resume value is the frozen `{ decision: string }`
|
|
12
|
+
* convention. `approvers` travel as RAW member refs
|
|
13
|
+
* (user ids or emails) — the SERVER resolves them
|
|
14
|
+
* against the team roster at pause-insert time and
|
|
15
|
+
* stamps the gate-bearing snapshots (ADR-0042 §2).
|
|
13
16
|
*
|
|
14
17
|
* Built from a `PauseFn` so the wrapper logic lives in one place and the step
|
|
15
18
|
* runner just spreads them onto the context next to `pause`.
|
|
16
19
|
*/
|
|
17
|
-
import
|
|
20
|
+
import { z } from "zod";
|
|
18
21
|
import type { StepPauseRequest } from "../step-invocation/types.js";
|
|
19
22
|
import type { PauseRequest } from "./pause-core.js";
|
|
20
23
|
/** The public `ctx.pause` callable (always `kind: "custom"`). */
|
|
21
24
|
export type PauseFn = <T = unknown>(req: PauseRequest<T>) => Promise<T>;
|
|
22
25
|
/** Internal: pause with an explicit wire `kind`. The wrappers stamp
|
|
23
|
-
* `sleep`/`event` through this; the public `ctx.pause` is always
|
|
26
|
+
* `decision`/`sleep`/`event` through this; the public `ctx.pause` is always
|
|
24
27
|
* `custom` and never exposes it. */
|
|
25
28
|
export type KindedPauseFn = <T = unknown>(req: PauseRequest<T>, kind: StepPauseRequest["kind"]) => Promise<T>;
|
|
26
29
|
export interface WaitForEventRequest<T> {
|
|
@@ -30,8 +33,27 @@ export interface WaitForEventRequest<T> {
|
|
|
30
33
|
schema?: z.ZodType<T>;
|
|
31
34
|
ttlMs?: number;
|
|
32
35
|
}
|
|
36
|
+
export interface DecisionRequest {
|
|
37
|
+
prompt: string;
|
|
38
|
+
/** Choices the decision UI offers as buttons; free text is always open. */
|
|
39
|
+
options?: Array<string | {
|
|
40
|
+
label: string;
|
|
41
|
+
value: string;
|
|
42
|
+
}>;
|
|
43
|
+
/** Team member refs (user ids or emails, ≤ 10) — with any named, ONLY a
|
|
44
|
+
* named approver may resolve the decision, and each gets an Activity
|
|
45
|
+
* ping. Resolution is server-side at pause creation. */
|
|
46
|
+
approvers?: string[];
|
|
47
|
+
/** DecisionDraft artifact rendered alongside the prompt. */
|
|
48
|
+
draft?: Record<string, unknown>;
|
|
49
|
+
ttlMs?: number;
|
|
50
|
+
correlationKey?: string;
|
|
51
|
+
}
|
|
33
52
|
export interface PauseWrappers {
|
|
34
53
|
sleep(durationMs: number): Promise<void>;
|
|
35
54
|
waitForEvent<T = unknown>(req: WaitForEventRequest<T>): Promise<T>;
|
|
55
|
+
requestDecision(req: DecisionRequest): Promise<{
|
|
56
|
+
decision: string;
|
|
57
|
+
}>;
|
|
36
58
|
}
|
|
37
59
|
export declare function buildPauseWrappers(pause: KindedPauseFn): PauseWrappers;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Ask-human processor (ADR-0028).
|
|
3
|
+
*
|
|
4
|
+
* Makes "ask a human" a FIRST-CLASS agent affordance: when the agent calls the
|
|
5
|
+
* built-in `AskUserQuestion` tool, this short-circuits it into a SERVER pause
|
|
6
|
+
* (`requestPauseAndAwait`) — the run freezes (compute stops), the question +
|
|
7
|
+
* options land on the human's pause feed, and the human's answer comes back as
|
|
8
|
+
* the tool result. No `agentc pause` CLI for the model to remember, and no
|
|
9
|
+
* dependency on prompt discipline: the moment the agent asks, the run pauses.
|
|
10
|
+
*
|
|
11
|
+
* Loud by construction — the danger this fixes is a pause that SILENTLY doesn't
|
|
12
|
+
* happen (a stale in-sandbox CLI, a non-E2B substrate, an auth error) letting
|
|
13
|
+
* the agent proceed as if it had an answer:
|
|
14
|
+
* - pause cannot be created (server reject) → `Verdict.abort` ENDS the agent
|
|
15
|
+
* loop with a WorkflowError. The run fails loud; it never guesses an answer.
|
|
16
|
+
* - pause expires / is cancelled → the tool result says NO answer came and to
|
|
17
|
+
* not assume one.
|
|
18
|
+
*
|
|
19
|
+
* Lives in the shared `gateToolCall` chain, so one implementation covers every
|
|
20
|
+
* runtime (the Claude Agent SDK `PreToolUse` hook and the ACP permission path).
|
|
21
|
+
* No run credential in the env (local / non-sandbox) → no-op: `AskUserQuestion`
|
|
22
|
+
* passes through untouched so a dev invocation isn't hard-failed.
|
|
23
|
+
*/
|
|
24
|
+
import type { Processor } from "./processor.js";
|
|
25
|
+
import type { GatePauseConnection } from "./gate-pause.js";
|
|
26
|
+
/** The Claude built-in tool an agent uses to ask the user a question. */
|
|
27
|
+
export declare const ASK_USER_QUESTION_TOOL = "AskUserQuestion";
|
|
28
|
+
export declare function createAskHumanProcessor(opts?: {
|
|
29
|
+
connection?: GatePauseConnection;
|
|
30
|
+
}): Processor;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -4,3 +4,4 @@ export { runProcessorChain } from "./runner.js";
|
|
|
4
4
|
export { denyTools, humanApproval, requireScope, redactPattern, } from "./builtins.js";
|
|
5
5
|
export { createGatePauseProcessor } from "./gate-pause.js";
|
|
6
6
|
export type { GatePausePolicy, GatePauseApproval, GatePauseConnection } from "./gate-pause.js";
|
|
7
|
+
export { createAskHumanProcessor, ASK_USER_QUESTION_TOOL } from "./ask-human.js";
|
|
@@ -37,6 +37,26 @@ import type { ToolCallGateResult } from "../types/runtime.js";
|
|
|
37
37
|
* ACP wire change — never silently. The package version is pinned separately
|
|
38
38
|
* in package.json; this integer is the real compatibility gate (ADR-0020). */
|
|
39
39
|
export declare const ACP_PROTOCOL_VERSION = 1;
|
|
40
|
+
/** Session-lifecycle capabilities the agent advertised at `initialize`,
|
|
41
|
+
* surfaced (not discarded) so callers can pick a resume strategy
|
|
42
|
+
* (ADR-0037 §3). The in-sandbox CLI-agent runtimes ignore both — they
|
|
43
|
+
* resume via the CLI's own on-disk rollout (ADR-0020 Q4); the bridge
|
|
44
|
+
* daemon attempts `session/resume` only when `resume` is true. */
|
|
45
|
+
export interface AcpSessionCaps {
|
|
46
|
+
/** Agent supports `session/load` — full-history replay as
|
|
47
|
+
* `agent_message_chunk`s. Deliberately NOT used for resume: replaying
|
|
48
|
+
* history would re-emit the transcript as new parts and duplicate the
|
|
49
|
+
* conversation (ADR-0037 alternative D). */
|
|
50
|
+
loadSession: boolean;
|
|
51
|
+
/** Agent supports `session/resume` — context restore with NO replay. */
|
|
52
|
+
resume: boolean;
|
|
53
|
+
}
|
|
54
|
+
/** One entry of the agent's slash-command palette, as announced by the ACP
|
|
55
|
+
* `available_commands_update` session notification. */
|
|
56
|
+
export interface AcpAvailableCommand {
|
|
57
|
+
name: string;
|
|
58
|
+
description: string;
|
|
59
|
+
}
|
|
40
60
|
/** Collaborators `AcpClientPeer` needs from `CliAgentRunner`, kept as a small
|
|
41
61
|
* injected surface so the peer stays transport-agnostic and unit-testable. */
|
|
42
62
|
export interface AcpClientPeerDeps {
|
|
@@ -57,6 +77,14 @@ export interface AcpClientPeerDeps {
|
|
|
57
77
|
/** Turn-scoped abort signal from `sendMessage`. On abort the peer sends
|
|
58
78
|
* `session/cancel` for the live session. */
|
|
59
79
|
signal?: AbortSignal;
|
|
80
|
+
/** The agent announced (or changed) its slash-command palette — an ACP
|
|
81
|
+
* `available_commands_update` session NOTIFICATION, which can arrive at
|
|
82
|
+
* any time (typically right after session/new, outside any prompt), so
|
|
83
|
+
* it rides a callback rather than the per-turn message stream. Each call
|
|
84
|
+
* carries the ENTIRE palette (replace semantics). Optional: the
|
|
85
|
+
* in-sandbox runtimes ignore it; the bridge daemon reports it to the
|
|
86
|
+
* server for composer autocomplete. */
|
|
87
|
+
onAvailableCommands?: (commands: AcpAvailableCommand[]) => void;
|
|
60
88
|
}
|
|
61
89
|
/**
|
|
62
90
|
* Map ONE ACP `session/update` to zero-or-more `AgentMessage`s. The single
|
|
@@ -100,10 +128,14 @@ export declare class AcpClientPeer {
|
|
|
100
128
|
* Negotiate the wire protocol at `initialize`. Pins `protocolVersion` to
|
|
101
129
|
* integer 1 and advertises NO fs / terminal capabilities. Returns the
|
|
102
130
|
* version the agent negotiated — `CliAgentRunner` compares it to
|
|
103
|
-
* `ACP_PROTOCOL_VERSION` to decide ACP-path vs. legacy-JSONL fallback
|
|
131
|
+
* `ACP_PROTOCOL_VERSION` to decide ACP-path vs. legacy-JSONL fallback —
|
|
132
|
+
* plus the agent's advertised session-lifecycle capabilities (`caps`),
|
|
133
|
+
* which the bridge daemon caches as `agent_sessions.resume_supported`
|
|
134
|
+
* (ADR-0037 §3). Absent capability blocks mean "not supported".
|
|
104
135
|
*/
|
|
105
136
|
initialize(): Promise<{
|
|
106
137
|
protocolVersion: number;
|
|
138
|
+
caps: AcpSessionCaps;
|
|
107
139
|
}>;
|
|
108
140
|
/**
|
|
109
141
|
* Start a session and return its id (threaded back onto the synthesised
|
|
@@ -113,6 +145,19 @@ export declare class AcpClientPeer {
|
|
|
113
145
|
* in the manual live step).
|
|
114
146
|
*/
|
|
115
147
|
startSession(cwd: string): Promise<string>;
|
|
148
|
+
/**
|
|
149
|
+
* Resume an existing session by id — ACP `session/resume` (ADR-0037 §3).
|
|
150
|
+
* ADDITIVE and opt-in: the in-sandbox CLI-agent runtimes never call this
|
|
151
|
+
* (their resume path is the CLI's own persisted rollout, see
|
|
152
|
+
* `startSession`); the bridge daemon calls it only when `initialize`
|
|
153
|
+
* advertised `caps.resume`. Unlike `session/load` there is NO history
|
|
154
|
+
* replay — the agent restores its internal context and returns nothing,
|
|
155
|
+
* so nothing is re-emitted through the caller's part sink. Throws on an
|
|
156
|
+
* unknown/expired session id (JSON-RPC error from the agent) — the caller
|
|
157
|
+
* marks the durable row stale and falls back to `startSession` + full
|
|
158
|
+
* re-render. `this.sessionId` is only adopted on success.
|
|
159
|
+
*/
|
|
160
|
+
resumeSession(cwd: string, acpSessionId: string): Promise<void>;
|
|
116
161
|
/**
|
|
117
162
|
* Drive one `session/prompt` turn, yielding `AgentMessage`s as the agent
|
|
118
163
|
* streams `session/update` notifications. Resolves the generator when the
|
|
@@ -27,6 +27,21 @@ import type { AgentMessage, ModelExecutionContract, RuntimeOptions, SandboxProvi
|
|
|
27
27
|
import type { ProcessorContext, ToolCall } from "../processors/processor.js";
|
|
28
28
|
/** Single-quote a value for safe interpolation into a `sh -c` command line. */
|
|
29
29
|
export declare function shellQuote(value: string): string;
|
|
30
|
+
/**
|
|
31
|
+
* A UNIQUE per-turn prompt path. Uniqueness is load-bearing, not cosmetic:
|
|
32
|
+
* E2B's envd cannot overwrite an existing non-root file in /tmp — it opens
|
|
33
|
+
* with O_CREAT as root (then chowns to the user), and the sandbox kernel's
|
|
34
|
+
* `fs.protected_regular` policy denies O_CREAT opens by a non-owner of an
|
|
35
|
+
* existing file in a sticky world-writable directory — so ANY reused path
|
|
36
|
+
* fails with "error opening file: … permission denied" on every turn after
|
|
37
|
+
* the first (same boot or across suspend/resume; reproduced against e2b
|
|
38
|
+
* 2.30.5). Cloud sessions construct a fresh runner per turn, so an
|
|
39
|
+
* iteration counter alone reuses `…-0.in` per conversation — the exact
|
|
40
|
+
* production failure. The timestamp+counter+random suffix is collision-proof
|
|
41
|
+
* across runner instances AND concurrent turns in one sandbox; the readable
|
|
42
|
+
* prefix (kind/agent/iteration) stays for debugging.
|
|
43
|
+
*/
|
|
44
|
+
export declare function uniquePromptPath(kind: string, agentId: string, iteration: number): string;
|
|
30
45
|
/** Hard deadline (ms) for the ACP `initialize` handshake AND the prompt turn.
|
|
31
46
|
* `peer.initialize()` resolves only when the agent answers; a real CLI that
|
|
32
47
|
* never speaks ACP (or blocks on stdin) would otherwise hang forever and the
|
|
@@ -34,6 +49,15 @@ export declare function shellQuote(value: string): string;
|
|
|
34
49
|
* route to JSONL exactly like a handshake error. Overridable via the env for
|
|
35
50
|
* ops tuning; defaults sane. */
|
|
36
51
|
export declare const ACP_HANDSHAKE_TIMEOUT_MS: number;
|
|
52
|
+
/** Idle deadline for a PROMPT TURN (distinct from the handshake gate above). A
|
|
53
|
+
* turn is killed only if it goes fully SILENT for this long — the deadline is
|
|
54
|
+
* re-armed on every streamed message, so a long, *streaming* turn never trips
|
|
55
|
+
* it. This must be generous: a reasoning model (GLM, gpt-5-codex) can think for
|
|
56
|
+
* tens of seconds between tool calls with no wire activity, which is NOT a hang.
|
|
57
|
+
* The 10s handshake timeout was far too tight here and killed live GLM turns
|
|
58
|
+
* mid-report. Only a genuinely wedged CLI (the Gemini-style hang) should trip
|
|
59
|
+
* this. Overridable via the env for ops tuning. */
|
|
60
|
+
export declare const ACP_TURN_IDLE_TIMEOUT_MS: number;
|
|
37
61
|
/** Readiness gate for the LIVE ACP attempt. The duplex-stdin transport in
|
|
38
62
|
* `spawnAcpProcess` is now real (`commands.spawnDuplex` on the local provider),
|
|
39
63
|
* so the agent's `initialize` request bytes are delivered and the handshake can
|
|
@@ -45,6 +69,13 @@ export declare const ACP_HANDSHAKE_TIMEOUT_MS: number;
|
|
|
45
69
|
* implements duplex) falls back to JSONL cleanly via the capability check in
|
|
46
70
|
* `sendMessage`. */
|
|
47
71
|
export declare const ACP_TRANSPORT_READY = true;
|
|
72
|
+
/** Reasoning-effort level a CLI turn may carry (T2 session effort). The
|
|
73
|
+
* per-CLI mapping lives in each spec's `buildCommand` — Claude Code takes a
|
|
74
|
+
* thinking-token budget via `MAX_THINKING_TOKENS`, codex takes
|
|
75
|
+
* `-c model_reasoning_effort=<level>`. Specs without a real knob
|
|
76
|
+
* (opencode/droid/cursor) never receive one: the server hides + rejects
|
|
77
|
+
* effort for those runtimes. */
|
|
78
|
+
export type CliReasoningEffort = "low" | "medium" | "high";
|
|
48
79
|
/** Per-CLI behaviour. The base owns the lifecycle (init/done/error) and the
|
|
49
80
|
* transport (spawn + JSONL parse); a spec owns the CLI-specific bits. */
|
|
50
81
|
export interface CliAgentSpec {
|
|
@@ -69,12 +100,15 @@ export interface CliAgentSpec {
|
|
|
69
100
|
* JSONL user message for a `--stream-json-input` CLI (amp). */
|
|
70
101
|
promptPayload(prompt: string): string;
|
|
71
102
|
/** Build the one-shot shell command for a turn. `promptPath` is a file in the
|
|
72
|
-
* sandbox holding `promptPayload(prompt)`; `sessionId` continues a thread.
|
|
103
|
+
* sandbox holding `promptPayload(prompt)`; `sessionId` continues a thread.
|
|
104
|
+
* `effort` is present only when the caller configured a reasoning effort
|
|
105
|
+
* AND the spec has a real knob for it (see `CliReasoningEffort`). */
|
|
73
106
|
buildCommand(args: {
|
|
74
107
|
promptPath: string;
|
|
75
108
|
sessionId?: string;
|
|
76
109
|
model?: string;
|
|
77
110
|
cwd?: string;
|
|
111
|
+
effort?: CliReasoningEffort;
|
|
78
112
|
}): string;
|
|
79
113
|
/** Map one parsed JSONL stdout event to `AgentMessage`s. The base emits
|
|
80
114
|
* `init`/`done`/`error` lifecycle itself, so a spec maps only content +
|
|
@@ -105,6 +139,7 @@ export declare class CliAgentRunner implements ModelExecutionContract {
|
|
|
105
139
|
private readonly options;
|
|
106
140
|
private readonly spec;
|
|
107
141
|
private readonly configModel?;
|
|
142
|
+
private readonly configEffort?;
|
|
108
143
|
readonly kind: string;
|
|
109
144
|
/** Whether the live ACP path will actually run for this runner: the spec
|
|
110
145
|
* declares an `acp` invocation, the transport is ready, AND the live provider
|
|
@@ -146,7 +181,7 @@ export declare class CliAgentRunner implements ModelExecutionContract {
|
|
|
146
181
|
* exercising the real `sendMessageAcp` even while the production default is
|
|
147
182
|
* dormant. Not a public API. */
|
|
148
183
|
private acpTransportReady;
|
|
149
|
-
constructor(sandbox: SandboxProvider, options: RuntimeOptions, spec: CliAgentSpec, configModel?: string | undefined);
|
|
184
|
+
constructor(sandbox: SandboxProvider, options: RuntimeOptions, spec: CliAgentSpec, configModel?: string | undefined, configEffort?: CliReasoningEffort | undefined);
|
|
150
185
|
/** TEST-ONLY: flip the live-ACP readiness gate on for this runner instance so
|
|
151
186
|
* the ACP lifecycle / fallback tests can exercise `sendMessageAcp` while the
|
|
152
187
|
* production default (`ACP_TRANSPORT_READY`) stays dormant. Not part of the
|
|
@@ -231,11 +266,30 @@ export declare class CliAgentRunner implements ModelExecutionContract {
|
|
|
231
266
|
private spawnAcpProcess;
|
|
232
267
|
/**
|
|
233
268
|
* Legacy JSONL transport (the version-mismatch fallback, ADR-0020 increment
|
|
234
|
-
* 5 retires it)
|
|
269
|
+
* 5 retires it) — and the ONLY transport on server→sandbox providers (no
|
|
270
|
+
* `spawnDuplex`, so ACP never engages). Write the prompt to a file, run the
|
|
235
271
|
* one-shot command, line-buffer stdout, `mapEvent` each parsed line, and cap
|
|
236
272
|
* with the runner-synthesised `done`. Does NOT re-yield `init` (the caller
|
|
237
273
|
* already did).
|
|
274
|
+
*
|
|
275
|
+
* Deadline + termination semantics (both load-bearing on the server→E2B
|
|
276
|
+
* cloud-session path):
|
|
277
|
+
* - `timeoutMs: 0` disables the PROVIDER's own command deadline. E2B's
|
|
278
|
+
* `CommandStartOpts` defaults to 60s — a fraction of a real coding
|
|
279
|
+
* turn — and connect-web normalises `<= 0` to "no deadline" (the same
|
|
280
|
+
* idiom `launchStep` uses for the hours-long step runner). The local
|
|
281
|
+
* and Vercel providers already treat 0/absent as "no deadline". The
|
|
282
|
+
* turn's deadline belongs to the CALLER: the abort signal here, the
|
|
283
|
+
* bridge waiter's idle/absolute caps, or the in-VM step deadline.
|
|
284
|
+
* - Abort and early generator exit KILL the in-sandbox CLI process via
|
|
285
|
+
* the provider's kill-capable background handle (`runBackground` —
|
|
286
|
+
* present on E2B, the provider every server-driven turn runs on), so a
|
|
287
|
+
* cancelled/timed-out/superseded turn can never leave an orphan agent
|
|
288
|
+
* mutating the working tree. Providers without `runBackground` (local
|
|
289
|
+
* child_process, Vercel) fall back to `commands.run`: no kill handle,
|
|
290
|
+
* abort only stops consumption — the pre-ACP behaviour of the in-VM
|
|
291
|
+
* JSONL fallback, bounded by the sandbox VM's own lifetime.
|
|
238
292
|
*/
|
|
239
293
|
private sendMessageJsonl;
|
|
240
294
|
}
|
|
241
|
-
export declare function createCliAgentRuntime(spec: CliAgentSpec, configModel?: string): import("../index.js").AgentRuntime<SandboxProvider>;
|
|
295
|
+
export declare function createCliAgentRuntime(spec: CliAgentSpec, configModel?: string, configEffort?: CliReasoningEffort): import("../index.js").AgentRuntime<SandboxProvider>;
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSONL frame guard — keeps oversized lines OFF the server→sandbox command
|
|
3
|
+
* stream.
|
|
4
|
+
*
|
|
5
|
+
* The live failure this exists for: a cloud session's turn stream rides
|
|
6
|
+
* `sandbox.commands.run` over E2B's connect-web gRPC command stream, and that
|
|
7
|
+
* transport dies at the wire on large payloads — connect-web throws
|
|
8
|
+
* `13: [internal] protocol error: received unsupported compressed output`
|
|
9
|
+
* the moment an envelope arrives with the compressed flag set
|
|
10
|
+
* (@connectrpc/connect-web connect-transport.js), which is what E2B's edge
|
|
11
|
+
* does to it on big frames. A single `claude` stream-json event echoing a
|
|
12
|
+
* whole Read file (hundreds of KB on ONE JSONL line) is exactly such a
|
|
13
|
+
* payload: the stream faults mid-turn, the platform classifies it as a
|
|
14
|
+
* protocol transport fault (server cloud-executor.ts), recycles the VM, and
|
|
15
|
+
* the turn's work is lost.
|
|
16
|
+
*
|
|
17
|
+
* The structural fix: the full content is already durable INSIDE the sandbox
|
|
18
|
+
* (the file on disk, the CLI's own session transcript), so the wire never
|
|
19
|
+
* needs it. A tiny dependency-free node filter runs in-sandbox, piped after
|
|
20
|
+
* the CLI, and rewrites any oversized JSONL line before it can reach the
|
|
21
|
+
* vulnerable stream: long strings inside the event are truncated with an
|
|
22
|
+
* EXPLICIT elision marker (a silent cut is how models and humans end up
|
|
23
|
+
* trusting hallucinated file contents), and a line that cannot be capped
|
|
24
|
+
* structurally is hard-truncated so the stream survives at the cost of that
|
|
25
|
+
* one event. The prompt travels the other direction over `files.write` —
|
|
26
|
+
* E2B's envd HTTP API, a different transport documented immune to this
|
|
27
|
+
* failure (see the `files.read` comment in sandbox/providers/e2b.ts) — and
|
|
28
|
+
* the guard script itself is delivered the same immune way.
|
|
29
|
+
*
|
|
30
|
+
* Exit codes: piping would normally replace the CLI's exit code with the
|
|
31
|
+
* filter's, so the wrapper prints a per-turn random sentinel line carrying
|
|
32
|
+
* `$?` after the CLI exits and the filter re-raises it as its own exit code.
|
|
33
|
+
* EOF without a sentinel means the producer died abnormally (killed
|
|
34
|
+
* mid-pipe) — the filter exits JSONL_GUARD_NO_SENTINEL_EXIT so a crashed CLI
|
|
35
|
+
* can never masquerade as a clean turn.
|
|
36
|
+
*
|
|
37
|
+
* `capJsonlLine` is deliberately SELF-CONTAINED (no imports, no captured
|
|
38
|
+
* helpers): `jsonlGuardScript()` embeds it via `Function.prototype.toString`
|
|
39
|
+
* so the exact logic the unit tests pin is the logic that runs in-sandbox —
|
|
40
|
+
* one implementation, two call sites.
|
|
41
|
+
*/
|
|
42
|
+
/** Trigger threshold: a JSONL line at or under this many bytes passes
|
|
43
|
+
* through byte-identical; over it, the guard rewrites. Chosen well under
|
|
44
|
+
* whatever E2B's edge chokes on (the observed kills were multi-hundred-KB
|
|
45
|
+
* single lines) while comfortably above any sane tool result. */
|
|
46
|
+
export declare const JSONL_GUARD_LINE_CAP_BYTES: number;
|
|
47
|
+
/** How many bytes of an oversized string survive elision (the head — tool
|
|
48
|
+
* output fronts-loads the signal: file starts, command output starts). */
|
|
49
|
+
export declare const JSONL_GUARD_KEEP_BYTES: number;
|
|
50
|
+
/** The guard's exit code when its stdin hit EOF WITHOUT the exit sentinel:
|
|
51
|
+
* the producer pipeline died abnormally (killed / crashed sh), so the turn
|
|
52
|
+
* must surface as an error, never a clean done. */
|
|
53
|
+
export declare const JSONL_GUARD_NO_SENTINEL_EXIT = 121;
|
|
54
|
+
/** Stable prefix of the elision marker appended to every truncated string.
|
|
55
|
+
* Exported so consumers/tests can detect an elided payload; a unit test
|
|
56
|
+
* pins that `capJsonlLine`'s embedded copy matches this constant. */
|
|
57
|
+
export declare const JSONL_ELISION_MARKER_PREFIX = "[agent-compose: PAYLOAD ELIDED IN TRANSIT";
|
|
58
|
+
/**
|
|
59
|
+
* Cap one JSONL line to at most `maxBytes` bytes.
|
|
60
|
+
*
|
|
61
|
+
* - At or under `maxBytes`: returned byte-identical (never re-serialized).
|
|
62
|
+
* - Over it and parseable as a JSON object/array: every string longer than
|
|
63
|
+
* `keepBytes` is truncated to its first `keepBytes` bytes plus an honest
|
|
64
|
+
* elision marker telling the reader the full content still exists in the
|
|
65
|
+
* sandbox and how to get it. If the result still exceeds `maxBytes`
|
|
66
|
+
* (many big strings), the per-string budget shrinks 8× and then 64× before
|
|
67
|
+
* giving up.
|
|
68
|
+
* - Unparseable, or uncappable even at the smallest budget: hard byte
|
|
69
|
+
* truncation to `maxBytes`. The line stops being valid JSON, so the
|
|
70
|
+
* consumer's parse skips it — one event lost, stream alive (strictly
|
|
71
|
+
* better than the whole turn dying).
|
|
72
|
+
*
|
|
73
|
+
* SELF-CONTAINED by contract: no imports, no outer-scope references except
|
|
74
|
+
* globals (`Buffer`, `JSON`) — `jsonlGuardScript()` ships `this.toString()`
|
|
75
|
+
* into the sandbox. Keep it that way.
|
|
76
|
+
*/
|
|
77
|
+
export declare function capJsonlLine(line: string, maxBytes: number, keepBytes: number): string;
|
|
78
|
+
/**
|
|
79
|
+
* The in-sandbox filter's source: a dependency-free node script that
|
|
80
|
+
* line-buffers stdin, re-emits every line through `capJsonlLine`, and turns
|
|
81
|
+
* the exit sentinel into its own exit code.
|
|
82
|
+
*
|
|
83
|
+
* node <script> <sentinel> <maxBytes> <keepBytes>
|
|
84
|
+
*/
|
|
85
|
+
export declare function jsonlGuardScript(): string;
|
|
86
|
+
/**
|
|
87
|
+
* Wrap a turn command so its stdout crosses the command stream through the
|
|
88
|
+
* guard. Self-deciding in-sandbox: when `node` is absent (a bare sandbox a
|
|
89
|
+
* self-provisioned CLI runs on), the command runs unguarded — the pre-guard
|
|
90
|
+
* status quo — instead of failing every turn.
|
|
91
|
+
*
|
|
92
|
+
* The command runs in a SUBSHELL so a `$?`-carrying sentinel line always
|
|
93
|
+
* prints after it exits, however it exits (a brace group would let a shell
|
|
94
|
+
* `exit` skip the printf). stderr stays un-piped — the provider's stderr
|
|
95
|
+
* accumulation is unchanged.
|
|
96
|
+
*/
|
|
97
|
+
export declare function wrapJsonlCommand(args: {
|
|
98
|
+
cmd: string;
|
|
99
|
+
guardPath: string;
|
|
100
|
+
sentinel: string;
|
|
101
|
+
maxBytes: number;
|
|
102
|
+
keepBytes: number;
|
|
103
|
+
}): string;
|
package/dist/runtimes/amp.d.ts
CHANGED
|
@@ -18,6 +18,6 @@ export interface AmpRuntimeConfig {
|
|
|
18
18
|
/** Amp uses its configured model; reserved for forward-compatibility. */
|
|
19
19
|
model?: string;
|
|
20
20
|
}
|
|
21
|
-
export declare function createAmpRuntime(config?: AmpRuntimeConfig): import("../index.js").AgentRuntime<import("../
|
|
22
|
-
declare const _default: import("../index.js").AgentRuntime<import("../
|
|
21
|
+
export declare function createAmpRuntime(config?: AmpRuntimeConfig): import("../index.js").AgentRuntime<import("../sandbox.js").SandboxProvider>;
|
|
22
|
+
declare const _default: import("../index.js").AgentRuntime<import("../sandbox.js").SandboxProvider>;
|
|
23
23
|
export default _default;
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Claude Code CLI runtime — drives the `claude` coding CLI headless INSIDE
|
|
3
|
+
* the sandbox (`claude -p --output-format stream-json`) and maps its JSONL
|
|
4
|
+
* event stream onto the AgentMessage contract.
|
|
5
|
+
*
|
|
6
|
+
* This is a different mechanism from `claudeRuntime` (claude.ts): that one
|
|
7
|
+
* drives the Anthropic Agent SDK in the CALLING process, which makes it
|
|
8
|
+
* unusable wherever the caller is the server (a cloud session's turns) —
|
|
9
|
+
* "never execute user-provided source in the server process". This runtime
|
|
10
|
+
* is a CLI-agent spec like codex/opencode: the agent loop runs entirely
|
|
11
|
+
* in-sandbox and we only stream-parse the events it prints, so the
|
|
12
|
+
* server→sandbox cloud-executor path can host it (CLOUD_SESSION_RUNTIMES).
|
|
13
|
+
*
|
|
14
|
+
* Transports, mirroring codexSpec exactly:
|
|
15
|
+
* - ACP: the Zed adapter (`npx @zed-industries/claude-code-acp`) — the SAME
|
|
16
|
+
* pinned adapter the local bridge daemon launches (cli/src/bridge/acp.ts
|
|
17
|
+
* imports the pin from here). Engages only where the provider exposes
|
|
18
|
+
* `commands.spawnDuplex` (the in-VM/local view); the server→sandbox
|
|
19
|
+
* E2B/Vercel view has no duplex, so cloud-session turns always drive the
|
|
20
|
+
* JSONL path below. Cold start: the adapter is npx-fetched on first
|
|
21
|
+
* launch (~10-30s once per sandbox lifetime; node/npm are in the
|
|
22
|
+
* agent-env image).
|
|
23
|
+
* - JSONL: `claude -p --output-format stream-json --verbose`, resume via
|
|
24
|
+
* `--resume <session_id>`. The `claude` binary is BAKED into the
|
|
25
|
+
* `agent-env-<size>` E2B image at /usr/local/bin/claude
|
|
26
|
+
* (infra/e2b-template/build.ts), so there is no install cold-start on the
|
|
27
|
+
* platform path; the `install` below is the bare-sandbox fallback.
|
|
28
|
+
*
|
|
29
|
+
* Auth (in-sandbox env, in the CLI's own precedence order):
|
|
30
|
+
* - `CLAUDE_CODE_OAUTH_TOKEN` — a user subscription (BYOS setup-token /
|
|
31
|
+
* OAuth grant); rides the user's plan directly against Anthropic.
|
|
32
|
+
* - `ANTHROPIC_API_KEY` (+ `ANTHROPIC_BASE_URL`) — an API key; for cloud
|
|
33
|
+
* sessions this is the gateway-minted session virtual key pointed at the
|
|
34
|
+
* token-metering gateway's Anthropic passthrough (ADR-0039).
|
|
35
|
+
*/
|
|
36
|
+
import { type CliAgentSpec, type CliReasoningEffort } from "./_cli-agent.js";
|
|
37
|
+
/** Pinned Claude Code ACP adapter (Zed's npm shim — `claude` has no native
|
|
38
|
+
* ACP mode). Pinned EXACT, not a range: the adapter's README warns of
|
|
39
|
+
* breaking changes; bump deliberately and re-verify a live turn. The local
|
|
40
|
+
* bridge daemon (cli/src/bridge/acp.ts) imports this same pin so both
|
|
41
|
+
* executors launch the identical adapter. Verified against 0.16.2. */
|
|
42
|
+
export declare const CLAUDE_CODE_ACP_ADAPTER = "@zed-industries/claude-code-acp@0.16.2";
|
|
43
|
+
/** Extended-thinking token budget per effort level — Claude Code's real knob
|
|
44
|
+
* is the `MAX_THINKING_TOKENS` env var (its documented settings env), set
|
|
45
|
+
* per invocation below. Values mirror the platform turn loop's
|
|
46
|
+
* `EFFORT_BUDGET_TOKENS` (server model-client) so "high" means the same
|
|
47
|
+
* thing in a channel and in a claude-code session. */
|
|
48
|
+
export declare const CLAUDE_CODE_THINKING_TOKENS: Record<CliReasoningEffort, number>;
|
|
49
|
+
export declare const claudeCodeSpec: CliAgentSpec;
|
|
50
|
+
export interface ClaudeCodeRuntimeConfig {
|
|
51
|
+
/** Claude model id (`--model`). Omit to use the CLI's configured default. */
|
|
52
|
+
model?: string;
|
|
53
|
+
/** Extended-thinking effort (`MAX_THINKING_TOKENS`). Omit for the CLI's
|
|
54
|
+
* default behaviour (no forced budget). */
|
|
55
|
+
effort?: CliReasoningEffort;
|
|
56
|
+
}
|
|
57
|
+
export declare function createClaudeCodeRuntime(config?: ClaudeCodeRuntimeConfig): import("../index.js").AgentRuntime<import("../sandbox.js").SandboxProvider>;
|
|
58
|
+
declare const _default: import("../index.js").AgentRuntime<import("../sandbox.js").SandboxProvider>;
|
|
59
|
+
export default _default;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* claude-code CLI-agent spec — the in-sandbox `claude -p --output-format
|
|
3
|
+
* stream-json` transport for cloud sessions (the cloud-hostable counterpart
|
|
4
|
+
* of the in-process `claudeRuntime`).
|
|
5
|
+
*
|
|
6
|
+
* - buildCommand: headless stream-json invocation, stdin prompt, resume
|
|
7
|
+
* via --resume, cwd via `cd`, IS_SANDBOX=1 (root-user permission skip);
|
|
8
|
+
* - mapEvent: assistant content blocks → text/thinking/tool_use, user
|
|
9
|
+
* tool_result echoes → tool_result, result → usage on success and an
|
|
10
|
+
* honest STRING error on failure;
|
|
11
|
+
* - the ACP invocation pins the SAME Zed adapter the local bridge daemon
|
|
12
|
+
* launches, so both executors drive one adapter version.
|
|
13
|
+
*/
|
|
14
|
+
export {};
|
|
@@ -30,6 +30,22 @@ export interface ClaudeRuntimeConfig {
|
|
|
30
30
|
* `agentc init`; default `"all"` makes them usable. Pass `[]` to disable. */
|
|
31
31
|
skills?: string[] | "all";
|
|
32
32
|
}
|
|
33
|
+
/** Bounded tail of the Claude Code process's stderr. The Agent SDK's
|
|
34
|
+
* process-exit error carries ONLY the exit code ("Claude Code process
|
|
35
|
+
* exited with code 1") — the CLI's actual complaint goes to stderr, which
|
|
36
|
+
* query() surfaces exclusively through the `stderr` callback. Without
|
|
37
|
+
* capturing it, a startup failure (bad flag, root refusal, dead config)
|
|
38
|
+
* reaches the run card as an uninformative exit code. Same 2000-char cap
|
|
39
|
+
* as the CLI-agent runtimes' exit-code tail (_cli-agent.ts). */
|
|
40
|
+
export declare const STDERR_TAIL_CAP = 2000;
|
|
41
|
+
export declare class StderrTail {
|
|
42
|
+
private buf;
|
|
43
|
+
append(data: string): void;
|
|
44
|
+
/** The captured tail, trimmed — empty string when nothing was written. */
|
|
45
|
+
get text(): string;
|
|
46
|
+
/** Suffix an error message with the tail (no-op when stderr was silent). */
|
|
47
|
+
decorate(message: string): string;
|
|
48
|
+
}
|
|
33
49
|
export declare class ClaudeRunner implements ModelExecutionContract {
|
|
34
50
|
private readonly options;
|
|
35
51
|
private readonly config;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ClaudeRunner stderr-tail capture — the Agent SDK's process-exit error
|
|
3
|
+
* ("Claude Code process exited with code 1") carries no detail; the CLI's
|
|
4
|
+
* actual complaint goes to stderr, surfaced only through query()'s `stderr`
|
|
5
|
+
* callback. The runner must capture a bounded tail and attach it to the
|
|
6
|
+
* error message so a startup failure is diagnosable from the run card.
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
package/dist/runtimes/codex.d.ts
CHANGED
|
@@ -12,7 +12,10 @@
|
|
|
12
12
|
* Verified against codex-cli 0.124.0: `codex exec --json` + resume-by-thread,
|
|
13
13
|
* with the command_execution / reasoning / agent_message item shapes below.
|
|
14
14
|
*/
|
|
15
|
-
import { type CliAgentSpec } from "./_cli-agent.js";
|
|
15
|
+
import { type CliAgentSpec, type CliReasoningEffort } from "./_cli-agent.js";
|
|
16
|
+
/** True when an error-item message is a known codex advisory (log-level
|
|
17
|
+
* noise), not a real error. Exported for tests. */
|
|
18
|
+
export declare function isCodexAdvisoryNoise(text: string): boolean;
|
|
16
19
|
/** Exported for the fixture-based parity tests (ADR-0020): the legacy JSONL
|
|
17
20
|
* `mapEvent` is the golden the ACP normaliser is asserted equal to. Not part
|
|
18
21
|
* of the public runtime surface — `createCodexRuntime` stays the entry point. */
|
|
@@ -20,7 +23,10 @@ export declare const codexSpec: CliAgentSpec;
|
|
|
20
23
|
export interface CodexRuntimeConfig {
|
|
21
24
|
/** Codex model id (`-m`). Omit to use the codex CLI's configured default. */
|
|
22
25
|
model?: string;
|
|
26
|
+
/** Reasoning effort (`-c model_reasoning_effort=<level>`). Omit to use the
|
|
27
|
+
* codex CLI's configured default. */
|
|
28
|
+
effort?: CliReasoningEffort;
|
|
23
29
|
}
|
|
24
|
-
export declare function createCodexRuntime(config?: CodexRuntimeConfig): import("../index.js").AgentRuntime<import("../
|
|
25
|
-
declare const _default: import("../index.js").AgentRuntime<import("../
|
|
30
|
+
export declare function createCodexRuntime(config?: CodexRuntimeConfig): import("../index.js").AgentRuntime<import("../sandbox.js").SandboxProvider>;
|
|
31
|
+
declare const _default: import("../index.js").AgentRuntime<import("../sandbox.js").SandboxProvider>;
|
|
26
32
|
export default _default;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type CliAgentSpec } from "./_cli-agent.js";
|
|
2
|
+
export declare const cursorSpec: CliAgentSpec;
|
|
3
|
+
export interface CursorRuntimeConfig {
|
|
4
|
+
/** Cursor model id; ACP mode ignores it (account default) — applies to the `-p` fallback. */
|
|
5
|
+
model?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function createCursorRuntime(config?: CursorRuntimeConfig): import("../index.js").AgentRuntime<import("../sandbox.js").SandboxProvider>;
|
|
8
|
+
declare const _default: import("../index.js").AgentRuntime<import("../sandbox.js").SandboxProvider>;
|
|
9
|
+
export default _default;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type CliAgentSpec } from "./_cli-agent.js";
|
|
2
|
+
export declare const droidSpec: CliAgentSpec;
|
|
3
|
+
export interface DroidRuntimeConfig {
|
|
4
|
+
/** `custom:<displayName>-<index>` matching the provisioned settings.json. */
|
|
5
|
+
model?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function createDroidRuntime(config?: DroidRuntimeConfig): import("../index.js").AgentRuntime<import("../sandbox.js").SandboxProvider>;
|
|
8
|
+
declare const _default: import("../index.js").AgentRuntime<import("../sandbox.js").SandboxProvider>;
|
|
9
|
+
export default _default;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSONL frame guard — the canary for the session-machine recycling failure.
|
|
3
|
+
*
|
|
4
|
+
* The live incident: a cloud session's turn stream rides `commands.run` over
|
|
5
|
+
* E2B's connect-web gRPC command stream, and a single multi-hundred-KB JSONL
|
|
6
|
+
* line (a `claude` stream-json event echoing a whole Read file) kills that
|
|
7
|
+
* stream with `13: [internal] protocol error: received unsupported compressed
|
|
8
|
+
* output` — the platform recycles the VM and the turn's work is lost.
|
|
9
|
+
*
|
|
10
|
+
* These tests pin the fix at three altitudes:
|
|
11
|
+
* 1. `capJsonlLine` (unit) — the shared cap logic.
|
|
12
|
+
* 2. The GENERATED guard script, executed by a REAL `node` subprocess —
|
|
13
|
+
* the exact bytes that run in-sandbox, including the exit-code sentinel.
|
|
14
|
+
* 3. The runner end-to-end through `makeLocalSandboxProvider` — a real
|
|
15
|
+
* `sh` pipeline: a synthetic oversized tool_result crosses the command
|
|
16
|
+
* boundary UN-FATALLY, arrives with the elision marker, and the turn
|
|
17
|
+
* completes with `done`.
|
|
18
|
+
*/
|
|
19
|
+
export {};
|