@agent-compose/sdk 0.8.1 → 0.8.3
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/dist/agent/__tests__/perf-sampler.test.d.ts +10 -0
- package/dist/agent/agent-context.d.ts +1 -1
- package/dist/agent/agent-loop.d.ts +5 -1
- package/dist/agent/desktop-open.d.ts +184 -0
- package/dist/agent/perf-sampler.d.ts +99 -0
- package/dist/agent/services-manifest.d.ts +88 -0
- package/dist/agent/services-restore.d.ts +58 -0
- package/dist/client.d.ts +189 -15
- package/dist/display.d.ts +17 -0
- package/dist/index.d.ts +14 -5
- package/dist/index.js +1625 -120
- package/dist/runtimes/_cli-agent.d.ts +372 -2
- package/dist/runtimes/claude-code.d.ts +12 -0
- package/dist/runtimes/codex.buildcommand.test.d.ts +9 -0
- package/dist/runtimes/codex.d.ts +8 -0
- package/dist/runtimes/openai-desktop.js +1555 -120
- package/dist/runtimes/session-env.test.d.ts +14 -0
- package/dist/sandbox/sizes.d.ts +120 -30
- package/dist/sandbox.d.ts +1 -1
- package/dist/types/api-conversations.d.ts +476 -1
- package/dist/types/api-factory.d.ts +164 -7
- package/dist/types/api-runs.d.ts +23 -1
- package/dist/types/protocol.d.ts +32 -1
- package/dist/types/runtime.d.ts +120 -0
- package/dist/types/workflow-metadata.d.ts +6 -5
- package/package.json +1 -1
- package/src/agent/agent-context.ts +128 -28
- package/src/agent/agent-loop.ts +10 -3
- package/src/agent/desktop-open.ts +418 -0
- package/src/agent/perf-sampler.ts +202 -0
- package/src/agent/services-manifest.ts +356 -0
- package/src/agent/services-restore.ts +195 -0
- package/src/client.ts +384 -32
- package/src/display.ts +44 -1
- package/src/index.ts +74 -7
- package/src/runtimes/_cli-agent.ts +1160 -67
- package/src/runtimes/claude-code.ts +187 -12
- package/src/runtimes/codex.ts +65 -2
- package/src/sandbox/providers/e2b.ts +8 -4
- package/src/sandbox/providers/local.ts +16 -4
- package/src/sandbox/sizes.ts +127 -44
- package/src/sandbox.ts +8 -0
- package/src/types/api-conversations.ts +461 -2
- package/src/types/api-factory.ts +165 -7
- package/src/types/api-runs.ts +25 -1
- package/src/types/protocol.ts +30 -1
- package/src/types/runtime.ts +122 -0
- package/src/types/workflow-metadata.ts +6 -5
|
@@ -180,6 +180,46 @@ export interface FactoryFileSearchResult {
|
|
|
180
180
|
/** True when more directories matched than the server's folder bound. */
|
|
181
181
|
folders_truncated?: boolean;
|
|
182
182
|
}
|
|
183
|
+
/** One file row of `GET /factories/:slug/files` — the flat recursive
|
|
184
|
+
* listing. Same row shape live and at a pinned head; rows arrive
|
|
185
|
+
* camelCase on the wire (mirrors `FactoryFileSearchRow`). */
|
|
186
|
+
export interface FactoryFileListRow {
|
|
187
|
+
id: string;
|
|
188
|
+
path: string;
|
|
189
|
+
sizeBytes: number;
|
|
190
|
+
contentType: string | null;
|
|
191
|
+
contentHash: string;
|
|
192
|
+
deletedAt: string | null;
|
|
193
|
+
createdAt: string;
|
|
194
|
+
updatedAt: string;
|
|
195
|
+
}
|
|
196
|
+
export interface ListFactoryFilesOptions {
|
|
197
|
+
factorySlug?: string;
|
|
198
|
+
/** Only paths under this prefix. */
|
|
199
|
+
prefix?: string;
|
|
200
|
+
/** Path cursor from a prior page's `nextCursor`. */
|
|
201
|
+
cursor?: string;
|
|
202
|
+
limit?: number;
|
|
203
|
+
/** List AS OF a drive branch (e.g. a session's `session-<uuid>`). */
|
|
204
|
+
branch?: string;
|
|
205
|
+
/** Browse-at-head: a retained 64-hex commit of the MAIN drive (or, with
|
|
206
|
+
* `branch`, a pin of that graph branch). The server answers 410
|
|
207
|
+
* `at_unavailable` for a garbage-collected/unknown head. */
|
|
208
|
+
at?: string;
|
|
209
|
+
}
|
|
210
|
+
/** One page of `GET /factories/:slug/files`. */
|
|
211
|
+
export interface FactoryFileListPage {
|
|
212
|
+
data: FactoryFileListRow[];
|
|
213
|
+
hasMore: boolean;
|
|
214
|
+
/** Pass as `cursor` to fetch the next page; null on the last page. */
|
|
215
|
+
nextCursor: string | null;
|
|
216
|
+
/** The pinned head this page was read at — non-null exactly when the
|
|
217
|
+
* request carried `at`. `committedAt` is RFC3339 or null (unknown). */
|
|
218
|
+
at: {
|
|
219
|
+
head: string;
|
|
220
|
+
committedAt: string | null;
|
|
221
|
+
} | null;
|
|
222
|
+
}
|
|
183
223
|
export interface FactoryFileWriteResult {
|
|
184
224
|
path: string;
|
|
185
225
|
contentHash: string;
|
|
@@ -216,6 +256,27 @@ export interface FactoryRow {
|
|
|
216
256
|
createdAt: string;
|
|
217
257
|
updatedAt: string;
|
|
218
258
|
}
|
|
259
|
+
/** GET /factories/:slug/perf-summary — team-level sandbox perf aggregates
|
|
260
|
+
* over a window (session_perf_rollups). Aggregate-only by design: sessions
|
|
261
|
+
* are member-gated, so no conversation ids appear here; per-session detail
|
|
262
|
+
* is the member-gated perf-history surface. */
|
|
263
|
+
export interface FactoryPerfSummary {
|
|
264
|
+
/** The aggregated window, ISO 8601. */
|
|
265
|
+
from: string;
|
|
266
|
+
to: string;
|
|
267
|
+
/** Distinct sessions with any rollup bucket in the window. */
|
|
268
|
+
sessions: number;
|
|
269
|
+
/** Rollup buckets (15-min) in the window. */
|
|
270
|
+
buckets: number;
|
|
271
|
+
/** Guest samples folded into those buckets. */
|
|
272
|
+
samples: number;
|
|
273
|
+
cpu_busy_p95_max: number | null;
|
|
274
|
+
mem_used_p95_max: number | null;
|
|
275
|
+
disk_used_p95_max: number | null;
|
|
276
|
+
load1_max: number | null;
|
|
277
|
+
/** Total seconds any session sat ≥90% on a resource, summed. */
|
|
278
|
+
saturated_seconds: number;
|
|
279
|
+
}
|
|
219
280
|
export interface CreateFactoryInput {
|
|
220
281
|
slug: string;
|
|
221
282
|
name: string;
|
|
@@ -257,6 +318,48 @@ export interface SecretListEntry {
|
|
|
257
318
|
createdAt: string;
|
|
258
319
|
updatedAt: string;
|
|
259
320
|
}
|
|
321
|
+
/** One SESSION secret on the wire (metadata only — values are write-only).
|
|
322
|
+
* `kind` 'value' = a session-own secret; 'factory' = an attachment by name
|
|
323
|
+
* to the session factory's secret tier. `ownerUserId` is the user who set
|
|
324
|
+
* it — only the owner or a team admin may replace/remove it. */
|
|
325
|
+
export interface SessionSecretEntry {
|
|
326
|
+
secretKey: string;
|
|
327
|
+
kind: "value" | "factory";
|
|
328
|
+
ownerUserId: string;
|
|
329
|
+
/** Delivery mode (vault v2): 'injected' = the session env file;
|
|
330
|
+
* 'brokered' = an egress-ruleset header — the value never enters the
|
|
331
|
+
* sandbox (call the host WITHOUT auth headers; the platform adds them). */
|
|
332
|
+
delivery: "injected" | "brokered";
|
|
333
|
+
/** Brokered entries: the API host the header rides on. */
|
|
334
|
+
brokerHost: string | null;
|
|
335
|
+
/** Non-null = an ephemeral use-and-scrub copy, and when its TTL lapses. */
|
|
336
|
+
ephemeralExpiresAt: string | null;
|
|
337
|
+
createdAt: string;
|
|
338
|
+
updatedAt: string;
|
|
339
|
+
}
|
|
340
|
+
/** One entry of a session-secret set: a literal value, or a factory
|
|
341
|
+
* attachment by name (`source: "factory"`). */
|
|
342
|
+
export type SessionSecretInput = {
|
|
343
|
+
key: string;
|
|
344
|
+
value: string;
|
|
345
|
+
} | {
|
|
346
|
+
key: string;
|
|
347
|
+
source: "factory";
|
|
348
|
+
};
|
|
349
|
+
/** A freshly minted vault link (session secret request). `url` is the
|
|
350
|
+
* single-use page a session writer opens to provide the named values. */
|
|
351
|
+
export interface SessionSecretRequestCreated {
|
|
352
|
+
requestId: string;
|
|
353
|
+
url: string;
|
|
354
|
+
expiresAt: string;
|
|
355
|
+
}
|
|
356
|
+
/** A vault link's polled status. */
|
|
357
|
+
export interface SessionSecretRequestStatus {
|
|
358
|
+
requestId: string;
|
|
359
|
+
status: "pending" | "fulfilled" | "cancelled" | "expired";
|
|
360
|
+
keys: string[];
|
|
361
|
+
expiresAt: string;
|
|
362
|
+
}
|
|
260
363
|
export interface CreateApiKeyInput {
|
|
261
364
|
name?: string;
|
|
262
365
|
scopes?: string[];
|
|
@@ -284,6 +387,25 @@ export interface ApiKey {
|
|
|
284
387
|
export interface ApiKeyCreated extends ApiKey {
|
|
285
388
|
key: string;
|
|
286
389
|
}
|
|
390
|
+
/** Options for `GET /api-keys` — the list is bounded and keyset-paginated
|
|
391
|
+
* (every run step / session boot mints a key row, so "all keys ever" is
|
|
392
|
+
* unbounded by construction). */
|
|
393
|
+
export interface ListApiKeysOptions {
|
|
394
|
+
/** Page size, 1–200 (server default 100). */
|
|
395
|
+
limit?: number;
|
|
396
|
+
/** `active` = unrevoked + unexpired only; `all` (default) includes
|
|
397
|
+
* revoked/expired history. */
|
|
398
|
+
status?: "active" | "all";
|
|
399
|
+
/** Opaque cursor from a previous page's `nextCursor`. */
|
|
400
|
+
cursor?: string;
|
|
401
|
+
}
|
|
402
|
+
/** One page of `GET /api-keys`. */
|
|
403
|
+
export interface ApiKeyPage {
|
|
404
|
+
data: ApiKey[];
|
|
405
|
+
hasMore: boolean;
|
|
406
|
+
/** Pass as `cursor` to fetch the next page; null on the last page. */
|
|
407
|
+
nextCursor: string | null;
|
|
408
|
+
}
|
|
287
409
|
/** Single rollup row from `GET /api/v1/usage`. */
|
|
288
410
|
export interface UsageRollupRow {
|
|
289
411
|
eventType: string;
|
|
@@ -300,7 +422,10 @@ export interface UsageResponse {
|
|
|
300
422
|
to: string | null;
|
|
301
423
|
}
|
|
302
424
|
/** One drive-directory ⇄ GitHub-repo link (`/factories/:slug/repo-links`).
|
|
303
|
-
*
|
|
425
|
+
* Multi-branch model: ONE link row per (repo, branch); sibling branches
|
|
426
|
+
* of a repo occupy sibling `base@<branch>` placements. Event delivery is
|
|
427
|
+
* app-level (the platform GitHub App's own webhook) or polling — there
|
|
428
|
+
* is no per-repo webhook setup (retired 2026-08-18). */
|
|
304
429
|
export interface DriveRepoLink {
|
|
305
430
|
id: string;
|
|
306
431
|
factoryId: string;
|
|
@@ -310,25 +435,57 @@ export interface DriveRepoLink {
|
|
|
310
435
|
provider: string;
|
|
311
436
|
/** "org/repo". */
|
|
312
437
|
repoFullName: string;
|
|
313
|
-
/** The GitHub branch
|
|
438
|
+
/** The GitHub branch this link's placement syncs with. */
|
|
314
439
|
trackedBranch: string;
|
|
315
440
|
connectorGrantId: string | null;
|
|
316
441
|
/** v1 links are always 'write' (the round trip is the feature). */
|
|
317
442
|
access: "read" | "write";
|
|
443
|
+
/** HOW events reach this link. "app": the platform GitHub App's own
|
|
444
|
+
* registered webhook delivers every installed repo's events (zero
|
|
445
|
+
* per-repo setup). "polling": no app webhook configured — the sweep
|
|
446
|
+
* alone. */
|
|
447
|
+
eventDelivery: "app" | "polling";
|
|
448
|
+
/** When an app-signed GitHub delivery last PROVED event delivery
|
|
449
|
+
* reaches this link; null = unproven. */
|
|
450
|
+
webhookVerifiedAt: string | null;
|
|
451
|
+
/** Two-way sync: drive edits under the prefix push back to the tracked
|
|
452
|
+
* branch. ON by default for new links. */
|
|
453
|
+
pushOutEnabled: boolean;
|
|
454
|
+
/** Follow-all mode (stamped identically on every sibling link of one
|
|
455
|
+
* repo): pushes to NEW branches auto-link them; GitHub branch deletes
|
|
456
|
+
* auto-unlink. False = explicit selection. */
|
|
457
|
+
followAllBranches: boolean;
|
|
458
|
+
/** Branches follow-all could NOT link (with the reason) — stamped on
|
|
459
|
+
* the repo's PRIMARY link row only; empty everywhere else. */
|
|
460
|
+
autoLinkSkips: Array<{
|
|
461
|
+
branch: string;
|
|
462
|
+
reason: string;
|
|
463
|
+
at: string;
|
|
464
|
+
}>;
|
|
318
465
|
lastSyncedGitSha: string | null;
|
|
319
466
|
lastSyncedAcgCommit: string | null;
|
|
320
|
-
syncState: "idle" | "syncing" | "diverged" | "reauth_required";
|
|
321
|
-
|
|
467
|
+
syncState: "idle" | "syncing" | "pushing" | "error" | "conflict" | "diverged" | "reauth_required";
|
|
468
|
+
/** Human-readable detail when syncState is 'error' or 'conflict'. */
|
|
469
|
+
syncError: string | null;
|
|
322
470
|
createdBy: string | null;
|
|
323
471
|
lastSyncedAt: string | null;
|
|
324
472
|
createdAt: string;
|
|
325
473
|
}
|
|
326
474
|
/** Input for `POST /factories/:slug/repo-links`. Requires the drive to be
|
|
327
|
-
* graph-authoritative (ADR-0058 Phase 4 promoted) — 409 otherwise.
|
|
475
|
+
* graph-authoritative (ADR-0058 Phase 4 promoted) — 409 otherwise.
|
|
476
|
+
* At most one of `followAllBranches` / `trackedBranches`; omitting BOTH
|
|
477
|
+
* is the follow-all default. Follow-all links EVERY
|
|
478
|
+
* branch — default branch primary at the plain `dirPrefix` — and keeps
|
|
479
|
+
* following live (new branches auto-link on push, deleted branches
|
|
480
|
+
* auto-unlink; capped at 100 branches). Explicit `trackedBranches`:
|
|
481
|
+
* index 0 is the PRIMARY and keeps the plain placement; every additional
|
|
482
|
+
* branch lands at the sibling `dirPrefix@<sanitized-branch>` placement. */
|
|
328
483
|
export interface CreateDriveRepoLinkInput {
|
|
329
484
|
dirPrefix: string;
|
|
330
485
|
repoFullName: string;
|
|
331
|
-
|
|
486
|
+
trackedBranches?: string[];
|
|
487
|
+
followAllBranches?: boolean;
|
|
332
488
|
connectorGrantId: string;
|
|
333
|
-
|
|
489
|
+
/** Two-way sync ("push-out") — defaults to TRUE for new links. */
|
|
490
|
+
pushOut?: boolean;
|
|
334
491
|
}
|
package/dist/types/api-runs.d.ts
CHANGED
|
@@ -262,6 +262,27 @@ export interface RunFundingResponse {
|
|
|
262
262
|
truncated: boolean;
|
|
263
263
|
};
|
|
264
264
|
}
|
|
265
|
+
/** One step's attested platform token totals — `GET
|
|
266
|
+
* /workflows/:id/step-usage`. Derived server-side from the spend ledger
|
|
267
|
+
* by step time window (steps run serially, so every gateway call falls in
|
|
268
|
+
* exactly one). Steps with no ledger rows are absent from the list. */
|
|
269
|
+
export interface RunStepUsage {
|
|
270
|
+
stepIndex: number;
|
|
271
|
+
costUsd: number;
|
|
272
|
+
promptTokens: number;
|
|
273
|
+
completionTokens: number;
|
|
274
|
+
cacheReadTokens: number;
|
|
275
|
+
cacheCreationTokens: number;
|
|
276
|
+
calls: number;
|
|
277
|
+
}
|
|
278
|
+
/** `GET /workflows/:id/step-usage`. Empty `steps` is an honest answer: a
|
|
279
|
+
* legacy run with no ledger rows, or a run funded outside the platform
|
|
280
|
+
* lane (that money is never metered — ADR-0048). */
|
|
281
|
+
export interface RunStepUsageResponse {
|
|
282
|
+
object: "run.step_usage";
|
|
283
|
+
runId: string;
|
|
284
|
+
steps: RunStepUsage[];
|
|
285
|
+
}
|
|
265
286
|
/** One row from the factory runs list (`GET /factories/:slug/runs`) — the
|
|
266
287
|
* summary shape, a strict subset of what the route returns. */
|
|
267
288
|
export interface RunListEntry {
|
|
@@ -283,7 +304,8 @@ export interface ListRunsOptions {
|
|
|
283
304
|
factorySlug?: string;
|
|
284
305
|
/** Substring match on the registered workflow name (`metadata._workflow`). */
|
|
285
306
|
workflow?: string;
|
|
286
|
-
/** Substring match across title / task title / branch
|
|
307
|
+
/** Substring match across title / task title / branch — or an exact run
|
|
308
|
+
* id (full UUID). */
|
|
287
309
|
search?: string;
|
|
288
310
|
outcome?: string;
|
|
289
311
|
sort?: "newest" | "oldest" | "fastest" | "slowest";
|
package/dist/types/protocol.d.ts
CHANGED
|
@@ -113,7 +113,38 @@ export interface AgentMessagePlan extends AgentMessageBase {
|
|
|
113
113
|
status: "pending" | "in_progress" | "completed";
|
|
114
114
|
}[];
|
|
115
115
|
}
|
|
116
|
-
|
|
116
|
+
/** A harness `<task-notification>` announcing a BACKGROUND task stopped —
|
|
117
|
+
* an async Agent spawn finishing, a background command exiting, a workflow
|
|
118
|
+
* completing. claude-code injects these as user-role text blocks; the
|
|
119
|
+
* normaliser parses them into structure so downstream can complete the
|
|
120
|
+
* spawning call's card (status, final report, usage) instead of dropping
|
|
121
|
+
* the only completion evidence a background subagent ever emits. Internal
|
|
122
|
+
* plumbing in the raw block (output-file paths, resume hints) is
|
|
123
|
+
* deliberately NOT forwarded — renderers must never see it. Additive
|
|
124
|
+
* kind: existing producers never emit it. */
|
|
125
|
+
export interface AgentMessageTaskNotification extends AgentMessageBase {
|
|
126
|
+
type: "task_notification";
|
|
127
|
+
/** The harness's background task id (`<task-id>`). */
|
|
128
|
+
taskId: string;
|
|
129
|
+
/** The SPAWNING tool_use id (`<tool-use-id>`) when the notification names
|
|
130
|
+
* one — the correlation key back to the Agent/Task call. */
|
|
131
|
+
toolUseId?: string;
|
|
132
|
+
/** Terminal status word — "completed" | "failed" | "stopped" | "killed"
|
|
133
|
+
* (verbatim from the harness; "finished" when the block carried none). */
|
|
134
|
+
status: string;
|
|
135
|
+
/** One-line what-happened ("Agent \"…\" finished"), collapsed + clamped. */
|
|
136
|
+
summary: string;
|
|
137
|
+
/** The task's final report (`<result>`), entity-unescaped and clamped.
|
|
138
|
+
* Absent when the notification carried none. */
|
|
139
|
+
report?: string;
|
|
140
|
+
/** The completion's usage block, when carried. */
|
|
141
|
+
usage?: {
|
|
142
|
+
tokens?: number;
|
|
143
|
+
toolUses?: number;
|
|
144
|
+
durationMs?: number;
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
export type AgentMessage = AgentMessageInit | AgentMessageText | AgentMessageTextDelta | AgentMessageThinking | AgentMessageToolUse | AgentMessageToolResult | AgentMessageDone | AgentMessageError | AgentMessageUsage | AgentMessageUsageDelta | AgentMessagePlan | AgentMessageTaskNotification;
|
|
117
148
|
/** Status block the agent emits to signal iteration completion or blockers. */
|
|
118
149
|
export interface AgentStatus {
|
|
119
150
|
summary: string;
|
package/dist/types/runtime.d.ts
CHANGED
|
@@ -12,6 +12,33 @@ export interface McpServerConfig {
|
|
|
12
12
|
args?: string[];
|
|
13
13
|
env?: Record<string, string>;
|
|
14
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* Exit-event push (the completion DOORBELL, v0.10.43). When set, the durable
|
|
17
|
+
* detached transport's in-guest wrapper fires ONE best-effort HTTP POST
|
|
18
|
+
* announcing `{ turnId, exitCode }` immediately AFTER the exit sentinel is
|
|
19
|
+
* durably written — so the server can verify-and-harvest at event latency
|
|
20
|
+
* instead of the watchdog's poll cadence.
|
|
21
|
+
*
|
|
22
|
+
* THE PUSH IS A DOORBELL, NEVER A VERDICT: the durable file stays the only
|
|
23
|
+
* truth; the push's arrival triggers verification against it, its absence
|
|
24
|
+
* means nothing (the poll ladder is the unchanged backstop), and a lost /
|
|
25
|
+
* duplicate / spoofed push must be harmless. Accordingly the wrapper never
|
|
26
|
+
* blocks sentinel-writing on the push (sentinel first, push after; failures
|
|
27
|
+
* are invisible to the runner lifecycle).
|
|
28
|
+
*
|
|
29
|
+
* Auth: `tokenEnv` NAMES a guest env var (e.g. the cloud session's
|
|
30
|
+
* `AGENT_COMPOSE_API_KEY`) — the wrapper reads it at push time, so the
|
|
31
|
+
* credential never appears in the generated script text or any log.
|
|
32
|
+
*/
|
|
33
|
+
export interface TurnExitNotify {
|
|
34
|
+
/** Absolute URL of the server's turn-exit-event endpoint. */
|
|
35
|
+
url: string;
|
|
36
|
+
/** The bridge turn id this runner executes (rides the POST body). */
|
|
37
|
+
turnId: string;
|
|
38
|
+
/** Guest env var holding the bearer credential. A name that is not a
|
|
39
|
+
* plain env identifier disables the push (never risks shell injection). */
|
|
40
|
+
tokenEnv: string;
|
|
41
|
+
}
|
|
15
42
|
/** Options passed to a runtime when creating a ModelExecutionContract. */
|
|
16
43
|
export interface RuntimeOptions {
|
|
17
44
|
allowedTools?: string[];
|
|
@@ -47,7 +74,33 @@ export interface RuntimeOptions {
|
|
|
47
74
|
type: "json_schema";
|
|
48
75
|
schema: Record<string, unknown>;
|
|
49
76
|
};
|
|
77
|
+
/** Exit-event doorbell config (cloud sessions) — see `TurnExitNotify`.
|
|
78
|
+
* Absent ⇒ no push; the durable transport behaves exactly as before. */
|
|
79
|
+
turnExitNotify?: TurnExitNotify;
|
|
80
|
+
/** $HOME-relative path of a shell env file the CLI process sources at
|
|
81
|
+
* launch (cloud sessions: the platform-managed session-secrets file,
|
|
82
|
+
* `SESSION_ENV_FILE_RELPATH`). Sourced fresh at EVERY turn launch, so a
|
|
83
|
+
* rewrite between turns lands on the next turn without a VM recycle.
|
|
84
|
+
* Absent ⇒ nothing is sourced (local/BYOM runs never read a user's own
|
|
85
|
+
* dotfiles by surprise). Must be a plain relative path — no quotes, no
|
|
86
|
+
* `..`; the runtime validates and drops anything else. */
|
|
87
|
+
sessionEnvFile?: string;
|
|
88
|
+
/** ABSOLUTE guest path of a per-turn model-credential shell fragment
|
|
89
|
+
* (cloud subscription sessions: the server ships the TURN ACTOR's own
|
|
90
|
+
* subscription credential there before dispatching the turn). Sourced at
|
|
91
|
+
* launch AFTER `sessionEnvFile`, so the turn's credential always wins —
|
|
92
|
+
* each turn runs on its actor's plan, never a baked or session-wide one.
|
|
93
|
+
* Absent ⇒ nothing extra is sourced. Must be a plain absolute path — no
|
|
94
|
+
* quotes, no `..`; the runtime validates and drops anything else. */
|
|
95
|
+
credEnvFile?: string;
|
|
50
96
|
}
|
|
97
|
+
/** Three-valued liveness verdict for a runtime's CURRENT turn, read from
|
|
98
|
+
* DURABLE guest state (heartbeat file, stdout file, exit sentinel, pid) over
|
|
99
|
+
* a fresh short exec — never from the health of any long-lived stream.
|
|
100
|
+
* `probe-failed` (exec timeout, transport fault, unparseable output) is
|
|
101
|
+
* NEVER evidence of death: the caller tracks it separately and only many
|
|
102
|
+
* consecutive failures escalate to a sandbox-unreachable verdict. */
|
|
103
|
+
export type RunnerLivenessVerdict = "alive" | "dead" | "probe-failed";
|
|
51
104
|
/** Runtime-normalized result of running pre-tool processors. */
|
|
52
105
|
export type ToolCallGateResult = {
|
|
53
106
|
kind: "allow";
|
|
@@ -114,6 +167,73 @@ export interface ModelExecutionContract {
|
|
|
114
167
|
* `captureCheckpoint` is omitted, this is never called.
|
|
115
168
|
*/
|
|
116
169
|
restoreCheckpoint?(blob: unknown): void;
|
|
170
|
+
/**
|
|
171
|
+
* Durable liveness probe for the CURRENT turn (2026-08-15 incident, turn
|
|
172
|
+
* 18dc5261: a silently wedged tail stream blinded the executor's
|
|
173
|
+
* process-grep probe to a turn that had FINISHED into its durable file —
|
|
174
|
+
* ten minutes of "no evidence" over a completed answer). Runtimes that run
|
|
175
|
+
* the detached durable transport implement this by reading the guest's
|
|
176
|
+
* durable trio — heartbeat file, stdout size, exit sentinel, pid — over a
|
|
177
|
+
* fresh short exec. The executor's evidence ticker prefers this over its
|
|
178
|
+
* generic process-grep probe.
|
|
179
|
+
*
|
|
180
|
+
* Contract: resolves fast (the implementation carries its own explicit
|
|
181
|
+
* exec timeout) and never throws — faults map to "probe-failed". Null
|
|
182
|
+
* means NO durable probe exists right now (boot phase before the runner
|
|
183
|
+
* launched, a transport without durable files): the caller keeps whatever
|
|
184
|
+
* fallback probe it already had; null is never a verdict.
|
|
185
|
+
*/
|
|
186
|
+
probeTurnLiveness?(): Promise<RunnerLivenessVerdict | null>;
|
|
187
|
+
/**
|
|
188
|
+
* DOORBELL, NEVER A VERDICT (exit-event push, v0.10.43): wake the current
|
|
189
|
+
* turn's durable watchdog NOW so it runs its normal verification pass —
|
|
190
|
+
* durable probe, then harvest-on-sentinel / honest no-sentinel death —
|
|
191
|
+
* immediately instead of at the next poll interval. Carries NO information
|
|
192
|
+
* of its own: a nudge for a live turn verifies alive and is a no-op; a
|
|
193
|
+
* spurious / duplicate / stale nudge is harmless; the poll ladder is the
|
|
194
|
+
* unchanged backstop when no nudge arrives. Never throws; a nudge while no
|
|
195
|
+
* watchdog is armed is remembered for the next arm (or dropped at turn
|
|
196
|
+
* start — a new turn owes nothing to the previous turn's doorbell).
|
|
197
|
+
*/
|
|
198
|
+
nudgeTurnProbe?(): void;
|
|
199
|
+
/**
|
|
200
|
+
* RESUME HANDOFF, NEVER A KILL (redispatch-carries-session, 2026-08-15
|
|
201
|
+
* forensics): mark the CURRENT turn's in-guest runner as handed off — the
|
|
202
|
+
* caller intends a successor turn to RESUME the same guest session, so
|
|
203
|
+
* abort/early-exit must unwind the transport WITHOUT reaping the detached
|
|
204
|
+
* process tree or deleting its durable files (heartbeat included — the
|
|
205
|
+
* park path's busy signal keeps reading it). Without this, "stop
|
|
206
|
+
* consuming" and "kill the guest tree" are fused on the abort seam, and a
|
|
207
|
+
* supersede-then-resume would destroy the very session it resumes.
|
|
208
|
+
* One-way for the runner instance; a runtime without a detachable guest
|
|
209
|
+
* (single-exec transports, ACP) simply omits the method — its abort
|
|
210
|
+
* semantics are unchanged and the caller falls back to kill semantics.
|
|
211
|
+
*/
|
|
212
|
+
detachGuest?(): void;
|
|
213
|
+
/**
|
|
214
|
+
* Deliver ONE user message INTO the currently running turn (the cloud
|
|
215
|
+
* analogue of `inboxStream` for runtimes whose agent loop lives in a
|
|
216
|
+
* detached in-guest CLI). The message rides a durable per-turn inbox
|
|
217
|
+
* file; the guest-side feeder forwards it to the CLI's stdin, where a
|
|
218
|
+
* steering-capable harness folds it into the live turn at the next safe
|
|
219
|
+
* boundary. Four-valued and honest:
|
|
220
|
+
* - "delivered" — the guest feeder forwarded the message to the CLI's
|
|
221
|
+
* stdin BEFORE the turn's terminal result: the running turn saw it.
|
|
222
|
+
* Only this verdict may advance any answered watermark.
|
|
223
|
+
* - "pending" — the append landed in the durable inbox but the ack
|
|
224
|
+
* window exhausted before the feeder forwarded it (guest exit 5: the
|
|
225
|
+
* CLI is not draining stdin mid-step — a long single tool call — or
|
|
226
|
+
* the guest is crawling). NOT seen yet; leave it owed. The line stays
|
|
227
|
+
* appended, so the CLI may still read it when the current step
|
|
228
|
+
* finishes — callers may narrate that bound but must never advance a
|
|
229
|
+
* watermark on it.
|
|
230
|
+
* - "closed" — the turn ended (guest exit 4 / exec fault) before
|
|
231
|
+
* the message was consumed: it was NOT seen; leave it owed.
|
|
232
|
+
* - "unsupported" — no live stream-input turn exists right now (boot
|
|
233
|
+
* phase, a spec/transport without stream input, ACP path).
|
|
234
|
+
* Calls are serialized per turn; never throws.
|
|
235
|
+
*/
|
|
236
|
+
injectUserMessage?(text: string): Promise<"delivered" | "pending" | "closed" | "unsupported">;
|
|
117
237
|
sendMessage(opts: {
|
|
118
238
|
prompt: string;
|
|
119
239
|
sessionId?: string;
|
|
@@ -146,11 +146,12 @@ export interface InvokePolicy {
|
|
|
146
146
|
* today; kept as its own object so finer controls (disk, gpu, …) can be
|
|
147
147
|
* added later without reshaping `WorkflowMetadata`. */
|
|
148
148
|
export interface SandboxResources {
|
|
149
|
-
/** Machine hardware SKU
|
|
150
|
-
*
|
|
151
|
-
* provider specs at create time
|
|
152
|
-
*
|
|
153
|
-
*
|
|
149
|
+
/** Machine hardware SKU. The vocabulary is `SANDBOX_SIZES` in
|
|
150
|
+
* `sandbox/sizes.ts` — the single source; do not restate it here or
|
|
151
|
+
* anywhere else. Maps to provider specs at create time: Vercel takes the
|
|
152
|
+
* vCPU count and allocates RAM at 2048 MB/vCPU; E2B has no create-time
|
|
153
|
+
* cpu/mem knob at all, so the size selects a PRE-BUILT per-size template
|
|
154
|
+
* (`E2B_TEMPLATE_SIZES`). Omit → `DEFAULT_SANDBOX_SIZE`. */
|
|
154
155
|
size?: SandboxSize;
|
|
155
156
|
/** Sandbox provider this workflow's runs execute on — `"vercel"` or
|
|
156
157
|
* `"e2b"`. Optional and additive: omit and the run resolves to the
|
package/package.json
CHANGED