@agent-compose/sdk 0.8.3 → 0.8.5

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.
Files changed (44) hide show
  1. package/dist/agent/agent-context.d.ts +9 -1
  2. package/dist/agent/agent-loop.d.ts +14 -1
  3. package/dist/client.d.ts +171 -33
  4. package/dist/directives.d.ts +14 -0
  5. package/dist/generated/verb-synopsis.d.ts +34 -0
  6. package/dist/index.d.ts +7 -5
  7. package/dist/index.js +1043 -41
  8. package/dist/runtimes/_cli-agent.d.ts +118 -0
  9. package/dist/runtimes/claude-code.d.ts +31 -1
  10. package/dist/runtimes/openai-desktop.d.ts +50 -0
  11. package/dist/runtimes/openai-desktop.js +1065 -59
  12. package/dist/runtimes/openai-desktop.test.d.ts +20 -0
  13. package/dist/runtimes/tool-pulse.test.d.ts +17 -0
  14. package/dist/sandbox/devbox.d.ts +5 -5
  15. package/dist/sandbox/registry.d.ts +12 -0
  16. package/dist/sandbox/sizes.d.ts +11 -5
  17. package/dist/sandbox.d.ts +2 -2
  18. package/dist/step-invocation/types.d.ts +1 -1
  19. package/dist/types/api-conversations.d.ts +85 -12
  20. package/dist/types/api-factory.d.ts +111 -1
  21. package/dist/types/conversation-stream.d.ts +22 -1
  22. package/dist/types/protocol.d.ts +130 -1
  23. package/dist/types/runtime.d.ts +71 -0
  24. package/package.json +1 -1
  25. package/src/agent/agent-context.ts +43 -9
  26. package/src/agent/agent-loop.ts +14 -3
  27. package/src/agent/desktop-open.ts +13 -1
  28. package/src/client.ts +256 -38
  29. package/src/directives.ts +21 -1
  30. package/src/generated/verb-synopsis.ts +544 -0
  31. package/src/index.ts +20 -5
  32. package/src/runtimes/_cli-agent.ts +333 -22
  33. package/src/runtimes/claude-code.ts +260 -14
  34. package/src/runtimes/openai-desktop.ts +82 -19
  35. package/src/sandbox/devbox.ts +5 -5
  36. package/src/sandbox/providers/e2b.ts +89 -17
  37. package/src/sandbox/registry.ts +19 -1
  38. package/src/sandbox/sizes.ts +11 -5
  39. package/src/sandbox.ts +2 -1
  40. package/src/types/api-conversations.ts +65 -13
  41. package/src/types/api-factory.ts +121 -1
  42. package/src/types/conversation-stream.ts +24 -1
  43. package/src/types/protocol.ts +127 -1
  44. package/src/types/runtime.ts +63 -0
@@ -147,6 +147,128 @@ export interface AgentMessageTaskNotification extends AgentMessageBase {
147
147
  usage?: { tokens?: number; toolUses?: number; durationMs?: number };
148
148
  }
149
149
 
150
+ /** One entry of a harness workflow's live progress feed — the
151
+ * `workflow_progress` array claude-code's `system`/`task_progress` events
152
+ * carry for its in-harness Workflow tool (the dynamic-workflow
153
+ * orchestrator). `phase` entries are the script's declared phases (seeded
154
+ * up front, 1-based `index`); `agent` entries are the spawned workflow
155
+ * agents, updated in place as they queue → run → settle. Preview text the
156
+ * harness includes (prompt/result previews) is internal plumbing and is
157
+ * deliberately NOT forwarded — same rule as task notifications. */
158
+ export type WorkflowProgressEntry =
159
+ | { kind: "phase"; index: number; title: string }
160
+ | {
161
+ kind: "agent"; index: number; label: string;
162
+ /** Lifecycle: `start` (spawned) / `progress` (heartbeat) are live;
163
+ * `done` / `error` are settled. Verbatim from the harness. */
164
+ state: "start" | "progress" | "done" | "error";
165
+ phaseIndex?: number; phaseTitle?: string;
166
+ model?: string; agentId?: string;
167
+ /** Self-reported usage so far (cumulative for this agent). */
168
+ tokens?: number; toolCalls?: number; durationMs?: number;
169
+ /** Epoch ms the agent actually started (for live elapsed). */
170
+ startedAt?: number;
171
+ /** The failure message when `state: "error"`, clamped. */
172
+ error?: string;
173
+ /** Replayed from a resume cache — settled instantly, no fresh spend. */
174
+ cached?: true;
175
+ /** Skipped by the user (workflow dialog) — an error state that is
176
+ * not a failure. */
177
+ skipped?: true;
178
+ };
179
+
180
+ /** LIVE progress of a harness BACKGROUND task (claude-code
181
+ * `system`/`task_progress`). For the in-harness Workflow tool the message
182
+ * carries the CUMULATIVE `workflow_progress` entry array (the harness
183
+ * re-sends the whole picture: state changes immediately, heartbeats
184
+ * throttled ~10s), so a consumer treats the latest message as
185
+ * authoritative per entry `(kind, index)`. A plain background AGENT task
186
+ * (Task tool, run_in_background) heartbeats on the same event with NO
187
+ * workflow entries — forwarded with `workflow: []` as liveness evidence
188
+ * so the platform can declare the running task as session background
189
+ * work; its completion evidence rides `task_notification`. `toolUseId`
190
+ * names the spawning call — the correlation key to its card. Additive
191
+ * kind: existing producers never emit it. */
192
+ export interface AgentMessageTaskProgress extends AgentMessageBase {
193
+ type: "task_progress";
194
+ /** The harness's background task id. */
195
+ taskId: string;
196
+ /** The SPAWNING Workflow/Task call's tool_use id, when carried. */
197
+ toolUseId?: string;
198
+ /** The task's cumulative usage totals so far. */
199
+ usage?: { tokens?: number; toolUses?: number; durationMs?: number };
200
+ /** The cumulative workflow progress entries — EMPTY for a plain
201
+ * background Agent-task heartbeat (only Workflow tasks carry entries). */
202
+ workflow: WorkflowProgressEntry[];
203
+ }
204
+
205
+ /** HARNESS-authored notice text — content the CLI composed itself rather
206
+ * than the model speaking: slash-command stdout, model/skills advisories,
207
+ * queued-input notes. claude-code marks these structurally (assistant
208
+ * events whose `message.model` is `"<synthetic>"`), and the normaliser
209
+ * forwards them under this kind so downstream persists them as collapsed
210
+ * system notices instead of agent prose (the 2026-08-22 "(session model)"
211
+ * / skills-reminder leak: harness plumbing rendered as message content).
212
+ * Additive kind: existing producers never emit it. */
213
+ export interface AgentMessageHarnessNotice extends AgentMessageBase {
214
+ type: "harness_notice";
215
+ text: string;
216
+ }
217
+
218
+ /** Context-compaction lifecycle — the harness summarizing its own
219
+ * conversation to reclaim context. Mapped 1:1 from claude-code's wire
220
+ * (verified live on 2.1.212, the baked sandbox pin, and 2.1.241 — both
221
+ * emit the identical shapes, `/compact` and auto alike):
222
+ *
223
+ * `system`/`status` `{status:"compacting"}` → phase "start"
224
+ * `system`/`status` `{status:null, compact_result, → phase "settled"
225
+ * compact_error?}`
226
+ * `system`/`compact_boundary` `{compact_metadata: → phase "boundary"
227
+ * {trigger, pre_tokens, post_tokens,
228
+ * cumulative_dropped_tokens, duration_ms, …}}`
229
+ *
230
+ * Order on the wire: start → settled → (fresh init) → boundary → the
231
+ * continuation summary as a SYNTHETIC user message (never forwarded — it
232
+ * quotes conversation content verbatim). "boundary" only follows a
233
+ * successful settle and only on the turn the compaction ran (verified: it
234
+ * does NOT replay on later resumes). A compaction can span MINUTES of
235
+ * otherwise-silent stream — the whole point of forwarding it is that
236
+ * downstream can show the silence as work (the 2026-08-23 dead-air
237
+ * incident: 94% auto-compact read as a dead session). Additive kind:
238
+ * existing producers never emit it. */
239
+ export interface AgentMessageCompaction extends AgentMessageBase {
240
+ type: "compaction";
241
+ phase: "start" | "settled" | "boundary";
242
+ /** settled: how it ended. Absent on start/boundary (a boundary IS a
243
+ * success by construction — the harness only emits it after one). */
244
+ result?: "success" | "failed";
245
+ /** settled+failed: the harness's own reason, clamped. */
246
+ error?: string;
247
+ /** boundary: what initiated the compaction. */
248
+ trigger?: "auto" | "manual";
249
+ /** boundary: context tokens before / after, dropped total, wall time. */
250
+ preTokens?: number;
251
+ postTokens?: number;
252
+ droppedTokens?: number;
253
+ durationMs?: number;
254
+ }
255
+
256
+ /** A user-role message landing INSIDE a subagent's thread — the delivered
257
+ * form of a steer (the parent's `SendMessage` to a RUNNING child, queued
258
+ * "for delivery at its next tool round") or any other message the harness
259
+ * folds into a child's conversation mid-flight. Emitted ONLY with sidechain
260
+ * attribution: `parentToolUseId` (the spawning Agent/Task call's tool_use
261
+ * id) is REQUIRED — an unattributed user event is the parent's own prompt
262
+ * echo, which stays unmapped as before. Lets renderers show the steer as a
263
+ * user-role message inside the child's mini-session instead of leaving it
264
+ * an opaque SendMessage tool call on the parent only (task #97, owner
265
+ * directive 2026-08-27). Additive kind: existing producers never emit it. */
266
+ export interface AgentMessageSubagentUserMessage extends AgentMessageBase {
267
+ type: "subagent_user_message";
268
+ text: string;
269
+ parentToolUseId: string;
270
+ }
271
+
150
272
  export type AgentMessage =
151
273
  | AgentMessageInit
152
274
  | AgentMessageText
@@ -159,7 +281,11 @@ export type AgentMessage =
159
281
  | AgentMessageUsage
160
282
  | AgentMessageUsageDelta
161
283
  | AgentMessagePlan
162
- | AgentMessageTaskNotification;
284
+ | AgentMessageTaskNotification
285
+ | AgentMessageTaskProgress
286
+ | AgentMessageHarnessNotice
287
+ | AgentMessageCompaction
288
+ | AgentMessageSubagentUserMessage;
163
289
 
164
290
  /** Status block the agent emits to signal iteration completion or blockers. */
165
291
  export interface AgentStatus {
@@ -94,6 +94,16 @@ export interface RuntimeOptions {
94
94
  * Absent ⇒ nothing extra is sourced. Must be a plain absolute path — no
95
95
  * quotes, no `..`; the runtime validates and drops anything else. */
96
96
  credEnvFile?: string;
97
+ /** Durable launch report (boot-time turn adoption): called by the durable
98
+ * detached transport the moment its in-guest runner exists — with the
99
+ * guest prompt path (every durable file derives from it), the exit
100
+ * sentinel string, and the detached wrapper's pid. The caller stamps
101
+ * these on the turn row so a SUCCESSOR process (a deploy roll's new
102
+ * server) can re-attach to the runner's durable `.out` without this
103
+ * process's memory. Fired once per detached launch (a retry with a fresh
104
+ * runner fires again with the new paths); never on transports without
105
+ * durable files. Must not throw — the transport calls it inline. */
106
+ onDetachedLaunch?: (info: { promptPath: string; sentinel: string; pid: number }) => void;
97
107
  }
98
108
 
99
109
  /** Three-valued liveness verdict for a runtime's CURRENT turn, read from
@@ -182,6 +192,21 @@ export interface ModelExecutionContract {
182
192
  * fallback probe it already had; null is never a verdict.
183
193
  */
184
194
  probeTurnLiveness?(): Promise<RunnerLivenessVerdict | null>;
195
+ /**
196
+ * TELEMETRY, NEVER A VERDICT (tool-run pulse, 2026-08-29): the newest
197
+ * tool-run pulse the durable liveness probe carried — the guest
198
+ * heartbeat's sample of the runner's own session (aggregate CPU jiffies,
199
+ * written bytes, live process count) plus the guest clock it was read
200
+ * against. The executor's evidence ticker peeks it AFTER its liveness
201
+ * check and compares successive samples: counters ADVANCING is proof a
202
+ * long silent foreground tool is working, fanned to clients as a live
203
+ * `tool_pulse` frame. Never probes on its own; null before any probe or
204
+ * on a transport without the pulse file. No liveness decision may ever
205
+ * read it.
206
+ */
207
+ peekTurnPulse?(): {
208
+ atMs: number; cpuJiffies: number; ioBytes: number; procs: number; guestNowMs: number;
209
+ } | null;
185
210
  /**
186
211
  * DOORBELL, NEVER A VERDICT (exit-event push, v0.10.43): wake the current
187
212
  * turn's durable watchdog NOW so it runs its normal verification pass —
@@ -232,6 +257,44 @@ export interface ModelExecutionContract {
232
257
  * Calls are serialized per turn; never throws.
233
258
  */
234
259
  injectUserMessage?(text: string): Promise<"delivered" | "pending" | "closed" | "unsupported">;
260
+ /**
261
+ * Request an in-band STEP INTERRUPT of the currently running turn — the
262
+ * ESC equivalent. Where `injectUserMessage` queues content for the turn
263
+ * loop's next boundary, this rides the same durable inbox but carries a
264
+ * control line the CLI handles immediately, mid-step included: the
265
+ * running tool call aborts, the run ends within ~100ms, and the guest
266
+ * session stays resumable with the whole turn context (verified live
267
+ * against claude 2.1.236). Verdicts mirror `injectUserMessage`; only
268
+ * "delivered" means the CLI got the control line — callers escalate
269
+ * anything else (and "unsupported": no stream-input turn, or a runtime
270
+ * with no in-band interrupt, e.g. codex) to kill semantics, which stay
271
+ * honest because thread stores are durable and the successor turn
272
+ * resumes them. Never throws.
273
+ */
274
+ interruptTurn?(): Promise<"delivered" | "pending" | "closed" | "unsupported">;
275
+ /**
276
+ * Guest pid of the CURRENT turn's detached runner wrapper (the setsid
277
+ * process-group leader recorded at launch), or null when no detached
278
+ * durable-transport runner is live (boot phase, ACP path, single-exec
279
+ * transports). Advisory identity, NEVER a liveness verdict: the platform
280
+ * reads it to DECLARE harness-reported background work (an in-harness
281
+ * Workflow task) against the process tree that hosts it, so the park
282
+ * machinery can verify the tree from `/proc/<pid>` later. Runtimes
283
+ * without a detached guest simply omit the method.
284
+ */
285
+ currentRunnerPid?(): number | null;
286
+ /**
287
+ * Durable byte offset of the CURRENT turn's `.out` file just past the
288
+ * last line whose messages have ALL been yielded to the consumer — the
289
+ * safe harvest watermark for boot-time turn adoption. Null when no
290
+ * durable-transport turn is live, or before the first line completes.
291
+ * The contract is deliberately one line BEHIND the parse cursor: a
292
+ * caller that persists parts after each yielded message may stamp this
293
+ * offset at any time and a successor re-parses AT MOST the line whose
294
+ * parts were mid-persist (the same crash window the workflow tailer's
295
+ * flush-before-advance ordering accepts). Advisory, never a verdict.
296
+ */
297
+ currentTurnDurableOffset?(): number | null;
235
298
  sendMessage(opts: {
236
299
  prompt: string;
237
300
  sessionId?: string;