@agentproto/runtime 0.3.0 → 0.5.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 +1 -1
- package/dist/config.d.ts +8 -0
- package/dist/config.mjs.map +1 -1
- package/dist/index.d.ts +873 -113
- package/dist/index.mjs +10749 -4795
- package/dist/index.mjs.map +1 -1
- package/dist/providers-store.mjs +6 -0
- package/dist/providers-store.mjs.map +1 -1
- package/dist/resume-strategies.d.ts +84 -6
- package/dist/resume-strategies.mjs +93 -2
- package/dist/resume-strategies.mjs.map +1 -1
- package/dist/spawn-defaults-d5gAhNkV.d.ts +61 -0
- package/package.json +19 -4
package/dist/index.d.ts
CHANGED
|
@@ -3,35 +3,178 @@ import { B as BuildHeartbeatAgent } from './heartbeat-COGpMrJS.js';
|
|
|
3
3
|
export { H as HeartbeatAgent, a as HeartbeatRunner, R as RuntimeEvent, b as RuntimeEvents, p as parseDuration } from './heartbeat-COGpMrJS.js';
|
|
4
4
|
import { AcpMcpServer } from '@agentproto/acp';
|
|
5
5
|
import { ChildProcess } from 'node:child_process';
|
|
6
|
+
import { D as DeclaredAdapterOption } from './spawn-defaults-d5gAhNkV.js';
|
|
6
7
|
import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
|
|
7
|
-
import { AdapterHandle, AdapterLister } from '@agentproto/
|
|
8
|
+
import { AdapterHandle, SetupField, AdapterResolver, AdapterLister, AdapterEntry } from '@agentproto/provider-kit';
|
|
9
|
+
import { SandboxProvider } from '@agentproto/sandbox';
|
|
8
10
|
import { WorkspaceFs } from './workspace-fs.js';
|
|
9
11
|
export { createWorkspaceFs } from './workspace-fs.js';
|
|
10
12
|
export { ConversationMeta, ConversationStore, ConversationTurn, fileConversationStore } from './conversations.js';
|
|
13
|
+
import { ProviderPreset } from '@agentproto/provider-presets';
|
|
14
|
+
import { StepCache } from '@agentproto/workflow-runtime';
|
|
11
15
|
export { PROVIDER_ENV_VARS, ProviderEntry, ProvidersFile, injectProviderKeysIntoEnv, loadProviders, providerEnvVar, providersPath, removeProviderKey, setProviderKey } from './providers-store.js';
|
|
12
16
|
|
|
17
|
+
/**
|
|
18
|
+
* Per-session JSONL record of a completed `command_execute` invocation
|
|
19
|
+
* (and cron's `kind: "command"` action jobs, which share the same
|
|
20
|
+
* allowlist + `runCommand` path — see cron-scheduler.ts's "one
|
|
21
|
+
* enforcement path, not two" comment).
|
|
22
|
+
*
|
|
23
|
+
* Each call gets its OWN `kind: "command"` session, minted via
|
|
24
|
+
* `SessionsRegistry.recordCommand` — same as an agent-cli or PTY session,
|
|
25
|
+
* so it shows up in `session_list` / `command_list` for free instead of
|
|
26
|
+
* needing a bespoke query surface. Its result is stored at the exact
|
|
27
|
+
* per-id path an agent-cli session's structured transcript already uses:
|
|
28
|
+
* `~/.agentproto/sessions/<id>/events.jsonl` (see transcript-writer.ts).
|
|
29
|
+
* A command session's file holds exactly one line — there's no seq/turn
|
|
30
|
+
* machinery to reconstruct because the call is already finished by the
|
|
31
|
+
* time this is written.
|
|
32
|
+
*
|
|
33
|
+
* This module only knows how to read/write that one line; minting the
|
|
34
|
+
* session itself (and deciding the file's base directory) is
|
|
35
|
+
* `sessions.ts`'s job via `recordCommand`.
|
|
36
|
+
*/
|
|
37
|
+
interface CommandLogEntry {
|
|
38
|
+
ts: string;
|
|
39
|
+
command: string;
|
|
40
|
+
args: string[];
|
|
41
|
+
cwd: string;
|
|
42
|
+
exitCode: number;
|
|
43
|
+
signal: string | null;
|
|
44
|
+
durationMs: number;
|
|
45
|
+
stdout: string;
|
|
46
|
+
stderr: string;
|
|
47
|
+
truncated?: boolean;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Per-session usage snapshot — the single place that decides a session's
|
|
52
|
+
* `costUsd` and where that number came from.
|
|
53
|
+
*
|
|
54
|
+
* Two cost sources feed a session:
|
|
55
|
+
* - an adapter's own usage reader (`readUsage`, e.g. hermes reads its
|
|
56
|
+
* state.db) or an ACP `usage_update` that carries a `cost` block — these
|
|
57
|
+
* are authoritative, tagged `source: "adapter"`.
|
|
58
|
+
* - raw input/output token counts with NO adapter cost (ACP adapters like
|
|
59
|
+
* claude-code / mastracode that report tokens but not dollars) — here we
|
|
60
|
+
* price them ourselves against agentproto's in-repo LLM pricing catalog,
|
|
61
|
+
* tagged `source: "computed"`.
|
|
62
|
+
*
|
|
63
|
+
* When tokens exist but the model is absent from the catalog we NEVER
|
|
64
|
+
* fabricate a price: `costUsd` is left undefined and the snapshot is tagged
|
|
65
|
+
* `source: "no-pricing"`. A session with neither cost nor tokens is
|
|
66
|
+
* `source: "none"`.
|
|
67
|
+
*
|
|
68
|
+
* This module is pure (the catalog lookup is injected) so the decision tree is
|
|
69
|
+
* unit-testable without building the whole model catalog.
|
|
70
|
+
*/
|
|
71
|
+
/** Where a session's `costUsd` came from — see the module doc. */
|
|
72
|
+
type UsageSource = "adapter" | "computed" | "no-pricing" | "none";
|
|
73
|
+
/** Per-token USD prices for a model (per 1M tokens), the subset of the
|
|
74
|
+
* catalog's `LLMPricing` this module needs. */
|
|
75
|
+
interface TokenPricing {
|
|
76
|
+
inputPer1M: number;
|
|
77
|
+
outputPer1M: number;
|
|
78
|
+
}
|
|
79
|
+
/** Pluggable pricing accessor — defaults to the in-repo catalog's
|
|
80
|
+
* `resolvePricing`, overridable in tests. Returns undefined for an
|
|
81
|
+
* unknown model (the caller then tags `no-pricing`). */
|
|
82
|
+
type PricingResolver = (model: string) => TokenPricing | undefined;
|
|
83
|
+
/** Raw signals gathered over a turn, handed to `deriveSessionUsage`. */
|
|
84
|
+
interface UsageComputeInput {
|
|
85
|
+
/** Requested model id — needed to look up per-token prices. */
|
|
86
|
+
model?: string;
|
|
87
|
+
/** Cost the adapter reported directly (readUsage or usage_update.cost).
|
|
88
|
+
* Present → authoritative, wins over token-based computation. */
|
|
89
|
+
adapterCostUsd?: number;
|
|
90
|
+
tokensIn?: number;
|
|
91
|
+
tokensOut?: number;
|
|
92
|
+
contextSize?: number;
|
|
93
|
+
contextUsed?: number;
|
|
94
|
+
}
|
|
95
|
+
/** The resolved usage snapshot — the shape `session_usage` returns and the
|
|
96
|
+
* durable `usage_snapshot` transcript record carries. Cost/token fields are
|
|
97
|
+
* omitted when absent so a missing value never reads as a measured zero. */
|
|
98
|
+
interface SessionUsage {
|
|
99
|
+
model?: string;
|
|
100
|
+
costUsd?: number;
|
|
101
|
+
tokensIn?: number;
|
|
102
|
+
tokensOut?: number;
|
|
103
|
+
contextSize?: number;
|
|
104
|
+
contextUsed?: number;
|
|
105
|
+
source: UsageSource;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Decide a session's usage snapshot + cost source from the raw signals.
|
|
109
|
+
*
|
|
110
|
+
* Priority: an adapter-reported cost wins; else price the tokens against the
|
|
111
|
+
* catalog; else `none`. Never fabricates a price for an unpriced model.
|
|
112
|
+
*/
|
|
113
|
+
declare function deriveSessionUsage(input: UsageComputeInput, resolve?: PricingResolver): SessionUsage;
|
|
114
|
+
/** Descriptor-shaped fields `projectSessionUsage` reads. */
|
|
115
|
+
interface UsageDescriptorFields {
|
|
116
|
+
model?: string;
|
|
117
|
+
costUsd?: number;
|
|
118
|
+
tokensIn?: number;
|
|
119
|
+
tokensOut?: number;
|
|
120
|
+
contextSize?: number;
|
|
121
|
+
contextUsed?: number;
|
|
122
|
+
usageSource?: UsageSource;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Project a session descriptor's persisted usage fields into the
|
|
126
|
+
* `session_usage` response shape. Omits absent fields; defaults an
|
|
127
|
+
* unstamped `usageSource` to `"none"`.
|
|
128
|
+
*/
|
|
129
|
+
declare function projectSessionUsage(desc: UsageDescriptorFields): SessionUsage;
|
|
130
|
+
|
|
13
131
|
/**
|
|
14
132
|
* In-process pub/sub bus for session lifecycle events. Separate from
|
|
15
133
|
* RuntimeEvents (global daemon bus) — session events are scoped to
|
|
16
134
|
* individual sessions and fire at turn-level granularity.
|
|
17
135
|
*
|
|
18
|
-
* Consumers: EventRing (
|
|
136
|
+
* Consumers: EventRing (session_events_poll cursor), WebhookNotifier
|
|
19
137
|
* (fire-and-forget HTTP), RoutineRunner (state machine fan-in),
|
|
20
|
-
* and
|
|
138
|
+
* and session_monitor MCP tool (long-poll multiplexed).
|
|
21
139
|
*/
|
|
22
|
-
type SessionEventType = "session:turn-end" | "session:awaiting-input" | "session:exited" | "session:command-done" | "policy:passed" | "policy:failed" | "policy:commit-ready" | "policy:committed";
|
|
140
|
+
type SessionEventType = "session:turn-end" | "session:awaiting-input" | "session:exited" | "session:command-done" | "policy:passed" | "policy:failed" | "policy:commit-ready" | "policy:committed" | "cron:fired" | "cron:succeeded" | "cron:failed";
|
|
141
|
+
/**
|
|
142
|
+
* Structured detail on why a session is awaiting input, when derivable.
|
|
143
|
+
* `source: "structured"` — a driver-reported ACP-style prompt (e.g. a tool
|
|
144
|
+
* permission request with real options). `source: "heuristic"` — a
|
|
145
|
+
* best-effort guess from the tail of the transcript (trailing "?" plus
|
|
146
|
+
* an optional enumerated option list) for drivers that don't report
|
|
147
|
+
* structured prompts. Absent entirely when neither could be determined —
|
|
148
|
+
* callers still have the plain `awaitingInput` boolean in that case.
|
|
149
|
+
*/
|
|
150
|
+
interface SessionAwaitingQuestion {
|
|
151
|
+
text: string;
|
|
152
|
+
options?: string[];
|
|
153
|
+
source: "structured" | "heuristic";
|
|
154
|
+
}
|
|
23
155
|
interface SessionTurnEndEvent {
|
|
24
156
|
type: "session:turn-end";
|
|
25
157
|
sessionId: string;
|
|
26
158
|
awaitingInput: boolean;
|
|
27
159
|
label?: string;
|
|
28
160
|
ts: string;
|
|
161
|
+
question?: SessionAwaitingQuestion;
|
|
162
|
+
/**
|
|
163
|
+
* The adapter's stream `turn-end` reason, when the driver reports one
|
|
164
|
+
* (e.g. `"completed"`, `"cancelled"`, `"max_turns"`, or
|
|
165
|
+
* `"watchdog-timeout"` when the ACP client's turn-idle watchdog fired
|
|
166
|
+
* because the adapter went silent — see
|
|
167
|
+
* `@agentproto/acp/client`'s `AcpClientOptions.turnIdleTimeoutMs`).
|
|
168
|
+
* Absent for drivers that don't report a reason.
|
|
169
|
+
*/
|
|
170
|
+
reason?: string;
|
|
29
171
|
}
|
|
30
172
|
interface SessionAwaitingInputEvent {
|
|
31
173
|
type: "session:awaiting-input";
|
|
32
174
|
sessionId: string;
|
|
33
175
|
label?: string;
|
|
34
176
|
ts: string;
|
|
177
|
+
question?: SessionAwaitingQuestion;
|
|
35
178
|
}
|
|
36
179
|
interface SessionExitedEvent {
|
|
37
180
|
type: "session:exited";
|
|
@@ -41,8 +184,8 @@ interface SessionExitedEvent {
|
|
|
41
184
|
label?: string;
|
|
42
185
|
ts: string;
|
|
43
186
|
}
|
|
44
|
-
/** Emitted when
|
|
45
|
-
* returned by the
|
|
187
|
+
/** Emitted when command_execute finishes. commandId matches the id
|
|
188
|
+
* returned by the command_execute MCP tool. */
|
|
46
189
|
interface SessionCommandDoneEvent {
|
|
47
190
|
type: "session:command-done";
|
|
48
191
|
sessionId: string;
|
|
@@ -68,7 +211,7 @@ interface PolicyFailedEvent {
|
|
|
68
211
|
/**
|
|
69
212
|
* Emitted by the supervisor (WP5) when a `then:"commit"` policy's gate passes
|
|
70
213
|
* but `requireHumanAck` is set: the commit is staged-and-ready but NOT yet
|
|
71
|
-
* executed. Carries the exact paths + message that `
|
|
214
|
+
* executed. Carries the exact paths + message that `policy_ack(approve:true)`
|
|
72
215
|
* will commit. The policy sits in `awaiting-ack` until acked.
|
|
73
216
|
*/
|
|
74
217
|
interface PolicyCommitReadyEvent {
|
|
@@ -81,7 +224,7 @@ interface PolicyCommitReadyEvent {
|
|
|
81
224
|
}
|
|
82
225
|
/** Emitted by the supervisor (WP5) when a `then:"commit"` policy has actually
|
|
83
226
|
* committed — either directly (requireHumanAck:false) or after an approving
|
|
84
|
-
* `
|
|
227
|
+
* `policy_ack`. Carries the resulting commit sha. */
|
|
85
228
|
interface PolicyCommittedEvent {
|
|
86
229
|
type: "policy:committed";
|
|
87
230
|
policyId: string;
|
|
@@ -91,7 +234,30 @@ interface PolicyCommittedEvent {
|
|
|
91
234
|
message: string;
|
|
92
235
|
ts: string;
|
|
93
236
|
}
|
|
94
|
-
|
|
237
|
+
/** Emitted by CronScheduler when a job fires (before the action runs). */
|
|
238
|
+
interface CronFiredEvent {
|
|
239
|
+
type: "cron:fired";
|
|
240
|
+
jobId: string;
|
|
241
|
+
label?: string;
|
|
242
|
+
ts: string;
|
|
243
|
+
}
|
|
244
|
+
/** Emitted by CronScheduler when a job action completes successfully. */
|
|
245
|
+
interface CronSucceededEvent {
|
|
246
|
+
type: "cron:succeeded";
|
|
247
|
+
jobId: string;
|
|
248
|
+
label?: string;
|
|
249
|
+
summary: string;
|
|
250
|
+
ts: string;
|
|
251
|
+
}
|
|
252
|
+
/** Emitted by CronScheduler when a job action fails. */
|
|
253
|
+
interface CronFailedEvent {
|
|
254
|
+
type: "cron:failed";
|
|
255
|
+
jobId: string;
|
|
256
|
+
label?: string;
|
|
257
|
+
error: string;
|
|
258
|
+
ts: string;
|
|
259
|
+
}
|
|
260
|
+
type SessionEvent = SessionTurnEndEvent | SessionAwaitingInputEvent | SessionExitedEvent | SessionCommandDoneEvent | PolicyPassedEvent | PolicyFailedEvent | PolicyCommitReadyEvent | PolicyCommittedEvent | CronFiredEvent | CronSucceededEvent | CronFailedEvent;
|
|
95
261
|
interface SessionEventBus {
|
|
96
262
|
emit(ev: SessionEvent): void;
|
|
97
263
|
/** Subscribe to a specific event type. Returns an unsubscribe fn. */
|
|
@@ -103,26 +269,40 @@ interface SessionEventBus {
|
|
|
103
269
|
}
|
|
104
270
|
|
|
105
271
|
/**
|
|
106
|
-
*
|
|
107
|
-
*
|
|
272
|
+
* A per-session observer — the pluggable seam behind the runtime's transcript
|
|
273
|
+
* tap. `sessions.ts` drives one observer per turn (prompt in, each stream event,
|
|
274
|
+
* the turn-boundary usage snapshot, close). The transcript writer is the first
|
|
275
|
+
* and, today, only member; additional observers (e.g. a Langfuse session tracer)
|
|
276
|
+
* attach without touching the turn loop.
|
|
108
277
|
*
|
|
109
|
-
* The
|
|
110
|
-
*
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
278
|
+
* The method set is exactly the subset of `TranscriptWriter` the session loop
|
|
279
|
+
* calls, so `TranscriptWriter` IS a `SessionObserver` (see transcript-writer.ts).
|
|
280
|
+
*/
|
|
281
|
+
|
|
282
|
+
interface SessionObserver {
|
|
283
|
+
/** Record the outgoing message that opens a new turn. */
|
|
284
|
+
recordPrompt(sessionId: string, message: unknown): void;
|
|
285
|
+
/** Record one structured stream event (text-delta, tool-call, usage_update, …). */
|
|
286
|
+
recordEvent(sessionId: string, evt: AgentStreamEvent): void;
|
|
287
|
+
/** Record the durable turn-boundary / exit usage snapshot. */
|
|
288
|
+
recordUsageSnapshot(sessionId: string, usage: SessionUsage): void;
|
|
289
|
+
/** Flush and close this session's stream. Idempotent, fire-and-forget. */
|
|
290
|
+
close(sessionId: string): Promise<void>;
|
|
291
|
+
/** Close every open session stream (synchronous shutdown path). */
|
|
292
|
+
closeAll(): Promise<void>;
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* Fan a `SessionObserver` out over many. Each `record*` call is forwarded to
|
|
296
|
+
* every member in order; `close`/`closeAll` await all members.
|
|
119
297
|
*
|
|
120
|
-
*
|
|
121
|
-
*
|
|
122
|
-
*
|
|
123
|
-
*
|
|
124
|
-
*
|
|
298
|
+
* Every individual member call is isolated in try/catch so one throwing observer
|
|
299
|
+
* can neither break its siblings nor propagate into the turn loop — the
|
|
300
|
+
* transcript writer is effectively infallible today, but a future network-backed
|
|
301
|
+
* observer (a Langfuse sink) must never be able to throw a turn. Failures are
|
|
302
|
+
* swallowed here (no logging dependency at this layer); observers that need
|
|
303
|
+
* visibility into their own failures own that internally.
|
|
125
304
|
*/
|
|
305
|
+
declare function composeSessionObservers(observers: readonly SessionObserver[]): SessionObserver;
|
|
126
306
|
|
|
127
307
|
/**
|
|
128
308
|
* Minimal shape we need from a driver-agent-cli session — kept as a
|
|
@@ -132,6 +312,12 @@ interface SessionEventBus {
|
|
|
132
312
|
*/
|
|
133
313
|
interface AgentSessionLike {
|
|
134
314
|
sessionId: string;
|
|
315
|
+
/** OS-level process id of the spawned child, when the driver owns a
|
|
316
|
+
* real subprocess. Mirrored onto `SessionDescriptor.pid` at
|
|
317
|
+
* `spawnAgent` time so `processAlive` can be computed without
|
|
318
|
+
* adapter-specific forensics. Undefined for drivers that don't
|
|
319
|
+
* expose a process (e.g. a future non-subprocess transport). */
|
|
320
|
+
pid?: number;
|
|
135
321
|
send(message: unknown): AsyncIterable<AgentStreamEvent>;
|
|
136
322
|
cancel(): Promise<void>;
|
|
137
323
|
close(): Promise<void>;
|
|
@@ -165,7 +351,15 @@ type PtyFactory = (opts: PtyFactoryOptions) => PtyProcess;
|
|
|
165
351
|
interface AgentStreamEvent {
|
|
166
352
|
kind: string;
|
|
167
353
|
text?: string;
|
|
354
|
+
/** Correlates a "tool-call" with its later "tool-result" (and an
|
|
355
|
+
* "agent-prompt" with the permission it's asking about) — see
|
|
356
|
+
* @agentproto/acp's `StreamEvent`. */
|
|
357
|
+
toolCallId?: string;
|
|
168
358
|
toolName?: string;
|
|
359
|
+
/** Tool-call input, e.g. an ACP `tool_call`'s `arguments` — see @agentproto/acp's `StreamEvent`. */
|
|
360
|
+
arguments?: unknown;
|
|
361
|
+
/** Tool-call output, e.g. an ACP `tool_call_update`'s `result` — see @agentproto/acp's `StreamEvent`. */
|
|
362
|
+
result?: unknown;
|
|
169
363
|
isError?: boolean;
|
|
170
364
|
reason?: string;
|
|
171
365
|
error?: {
|
|
@@ -173,6 +367,35 @@ interface AgentStreamEvent {
|
|
|
173
367
|
code?: number;
|
|
174
368
|
data?: unknown;
|
|
175
369
|
};
|
|
370
|
+
/** Structured options offered by an "agent-prompt" event (e.g. an ACP
|
|
371
|
+
* `requestPermission` callback surfaced as a clarifying question rather
|
|
372
|
+
* than auto-answered). Typed `unknown` — like `@agentproto/acp`'s own
|
|
373
|
+
* `StreamEvent["options"]` — so this structural type stays assignable
|
|
374
|
+
* from any driver's runtime session without a hard dependency on its
|
|
375
|
+
* exact option shape (`{optionId,name,kind}` for ACP, or whatever a
|
|
376
|
+
* future driver reports); `normalizeAgentPromptOptions` narrows it
|
|
377
|
+
* defensively at the one place it's consumed. */
|
|
378
|
+
options?: unknown;
|
|
379
|
+
/** "plan" event entries — see @agentproto/acp's `StreamEvent`'s `plan` kind. */
|
|
380
|
+
entries?: Array<{
|
|
381
|
+
content: string;
|
|
382
|
+
priority: string;
|
|
383
|
+
status: string;
|
|
384
|
+
}>;
|
|
385
|
+
/** "usage_update" context-window size (tokens). */
|
|
386
|
+
size?: number;
|
|
387
|
+
/** "usage_update" tokens currently in context. */
|
|
388
|
+
used?: number;
|
|
389
|
+
/** "usage_update" cumulative session cost, when the adapter reports one. */
|
|
390
|
+
cost?: {
|
|
391
|
+
amount: number;
|
|
392
|
+
currency: string;
|
|
393
|
+
};
|
|
394
|
+
/** "usage_update" cumulative input/output token counts, when the adapter
|
|
395
|
+
* reports them (lets the daemon price a session whose adapter gives tokens
|
|
396
|
+
* but no `cost`). */
|
|
397
|
+
tokensIn?: number;
|
|
398
|
+
tokensOut?: number;
|
|
176
399
|
}
|
|
177
400
|
type SessionKind = "terminal" | "agent-cli" | "command" | "browser";
|
|
178
401
|
type SessionStatus = "starting" | "running" | "exited" | "killed" | "error";
|
|
@@ -191,6 +414,19 @@ interface SessionDescriptor {
|
|
|
191
414
|
/** Last time anything was written to stdout/stderr. Lets the UI
|
|
192
415
|
* spot stuck sessions ("running for 2h, last output 12min ago"). */
|
|
193
416
|
lastOutputAt?: string;
|
|
417
|
+
/** Last time ANY adapter-process activity was observed — ACP
|
|
418
|
+
* JSON-RPC traffic, protocol-level events, not just ring-buffer
|
|
419
|
+
* output lines. Stays current during long tool-call chains where
|
|
420
|
+
* `lastOutputAt` goes stale. Updated on incoming session/update
|
|
421
|
+
* notifications AND on outbound RPC calls. ISO 8601. */
|
|
422
|
+
lastActivityAt?: string;
|
|
423
|
+
/** Whether the underlying OS process is still alive. Computed via
|
|
424
|
+
* `process.kill(pid, 0)` at read time (list()/get()) — cheap,
|
|
425
|
+
* zero-overhead, standard POSIX check. Absent when `pid` is null
|
|
426
|
+
* (no process to check). Never persisted — recomputed fresh on
|
|
427
|
+
* every read since it's a live OS query, stale the instant it's
|
|
428
|
+
* written to disk. */
|
|
429
|
+
processAlive?: boolean;
|
|
194
430
|
/** Free-text label the spawner can attach (e.g. conversation id,
|
|
195
431
|
* operator name) so the UI can group/filter. */
|
|
196
432
|
label?: string;
|
|
@@ -222,6 +458,16 @@ interface SessionDescriptor {
|
|
|
222
458
|
/** Cumulative input / output token counts (same source + cadence as costUsd). */
|
|
223
459
|
tokensIn?: number;
|
|
224
460
|
tokensOut?: number;
|
|
461
|
+
/** Context-window size + tokens-in-context from the latest `usage_update`
|
|
462
|
+
* event (ACP adapters that report a context window). Refreshed live as
|
|
463
|
+
* usage_update events arrive, not just at turn-end. */
|
|
464
|
+
contextSize?: number;
|
|
465
|
+
contextUsed?: number;
|
|
466
|
+
/** Where `costUsd` came from — `"adapter"` (adapter's own reader or a
|
|
467
|
+
* usage_update cost block), `"computed"` (tokens × in-repo catalog price),
|
|
468
|
+
* `"no-pricing"` (tokens present but the model isn't in the catalog — cost
|
|
469
|
+
* deliberately left undefined), or `"none"`. Stamped at each turn-end. */
|
|
470
|
+
usageSource?: UsageSource;
|
|
225
471
|
/** ACP-level session id (the adapter's own handle — claude-code's
|
|
226
472
|
* conversation id, hermes' chat id, …). Set at spawnAgent time
|
|
227
473
|
* from `agentSession.sessionId`. Survives across daemon restarts
|
|
@@ -249,20 +495,42 @@ interface SessionDescriptor {
|
|
|
249
495
|
resumeMetadata?: Record<string, string>;
|
|
250
496
|
/** Set by the orchestration layer when the agent emits an
|
|
251
497
|
* "awaiting-input" turn-end. Cleared on the next turn start.
|
|
252
|
-
* Used by `
|
|
498
|
+
* Used by `session_monitor` to fast-return without subscribing. */
|
|
253
499
|
awaitingInput?: boolean;
|
|
500
|
+
/**
|
|
501
|
+
* Structured detail on WHY the session is awaiting input, when it can be
|
|
502
|
+
* determined — lets an orchestrator distinguish "blocked on a real
|
|
503
|
+
* question" from "just finished a turn" without re-reading raw output.
|
|
504
|
+
* `source: "structured"` comes from a driver-reported ACP-style prompt
|
|
505
|
+
* (`AgentStreamEvent.options`, e.g. a tool permission request);
|
|
506
|
+
* `source: "heuristic"` is a best-effort guess from the tail of the
|
|
507
|
+
* transcript (trailing "?" + an optional enumerated option list) for
|
|
508
|
+
* drivers that don't report structured prompts. Cleared alongside
|
|
509
|
+
* `awaitingInput` on the next turn start. */
|
|
510
|
+
awaitingQuestion?: SessionAwaitingQuestion;
|
|
254
511
|
/** Count of turns that have fully completed (turn-end emitted) on this
|
|
255
|
-
* session. Lets `
|
|
512
|
+
* session. Lets `session_monitor` fast-return for a session that already
|
|
256
513
|
* finished its turn before the wait subscribed — a fast turn that ends
|
|
257
514
|
* in "completed" (not "awaiting-input") leaves no other persisted
|
|
258
515
|
* signal (status stays "running", busy clears). 0 = never ran a turn,
|
|
259
516
|
* so a freshly-spawned idle session is NOT mistaken for done. */
|
|
260
517
|
turnsCompleted?: number;
|
|
261
518
|
/** True while a turn is actively running (mirror of the internal
|
|
262
|
-
* runtime `busy` flag). Lets `
|
|
519
|
+
* runtime `busy` flag). Lets `session_monitor` distinguish "idle after a
|
|
263
520
|
* finished turn" from "mid-turn" so it doesn't fast-return a stale
|
|
264
521
|
* turn-end while the NEXT turn is still generating. */
|
|
265
522
|
busy?: boolean;
|
|
523
|
+
/** What the in-flight turn is currently blocked on, when classifiable
|
|
524
|
+
* from the pending tool call: a spawned sub-agent (`agent_start`) or a
|
|
525
|
+
* shell/terminal command. Deliberately NO "user" variant — waiting on
|
|
526
|
+
* the user is already covered by `awaitingInput`/`awaitingQuestion`.
|
|
527
|
+
* Set on tool-call, cleared on the MATCHING tool-result (guarded by
|
|
528
|
+
* `pendingToolCallId`), at turn start, and in the turn's finally. */
|
|
529
|
+
blockedOn?: "subagent" | "command";
|
|
530
|
+
/** toolCallId of the tool-call that set `blockedOn`. A tool-result only
|
|
531
|
+
* clears `blockedOn` when its toolCallId matches — so a nested or
|
|
532
|
+
* interleaved tool finishing first can't clear the flag early. */
|
|
533
|
+
pendingToolCallId?: string;
|
|
266
534
|
/** Session id of the orchestrator that spawned this session, set when
|
|
267
535
|
* the spawn arrived via the scoped orchestrator sub-gateway (the
|
|
268
536
|
* token carried the spawner's identity). Absent for direct `/mcp`
|
|
@@ -276,6 +544,17 @@ interface SessionDescriptor {
|
|
|
276
544
|
* Treated as 0 when absent (legacy rows / direct spawns that predate
|
|
277
545
|
* WP4). */
|
|
278
546
|
depth?: number;
|
|
547
|
+
/** Id of the most recently-completed `kind: "command"` session spawned
|
|
548
|
+
* with the same `cwd`, found at spawn time — see `recordCommand` and
|
|
549
|
+
* `findPriorCommandSessionId`. Deliberately a REFERENCE, not copied
|
|
550
|
+
* content: a new session's own ring buffer / structured transcript
|
|
551
|
+
* never gets a prior command_execute's stdout/stderr spliced in, it
|
|
552
|
+
* just gets told where to look (`command_log_tail({sessionId})` or
|
|
553
|
+
* `agent_export`/`command_list` resolve the id into the full record).
|
|
554
|
+
* Set on `spawnAgent`/`spawnPty` when the registry already has a
|
|
555
|
+
* matching command session; absent otherwise (including for legacy
|
|
556
|
+
* rows persisted before this field existed). */
|
|
557
|
+
priorCommandSessionId?: string;
|
|
279
558
|
/** Adapter id that drives this session (e.g. "camofox", "bureau"). */
|
|
280
559
|
browserAdapterId?: string;
|
|
281
560
|
/** Port the browser service listens on. */
|
|
@@ -284,6 +563,16 @@ interface SessionDescriptor {
|
|
|
284
563
|
browserBaseUrl?: string;
|
|
285
564
|
/** Execution location — "local" (default) or "cloud". */
|
|
286
565
|
browserLocation?: "local" | "cloud";
|
|
566
|
+
/** True when this agent-cli session is running inside a sandbox (`agent_start.sandbox`)
|
|
567
|
+
* rather than as a local subprocess — there's no local PID to check, so
|
|
568
|
+
* `processAlive` never applies (it's already absent whenever `pid` is null). */
|
|
569
|
+
remote?: boolean;
|
|
570
|
+
/** Provider-assigned sandbox id (`BootedSandbox.sandboxId`), when `remote` is true. */
|
|
571
|
+
sandboxId?: string;
|
|
572
|
+
/** What session close does to the box (PR3 lifecycle) — `"kill"` (the
|
|
573
|
+
* default, ephemeral) or `"pause"` (keeps `sandboxId` reconnectable via
|
|
574
|
+
* `agent_start.sandbox.reuse`). Only set when `remote` is true. */
|
|
575
|
+
sandboxTeardown?: "kill" | "pause";
|
|
287
576
|
}
|
|
288
577
|
interface SessionsRegistry {
|
|
289
578
|
spawn(input: SpawnSessionInput): SessionDescriptor;
|
|
@@ -306,25 +595,66 @@ interface SessionsRegistry {
|
|
|
306
595
|
* `attachPty(id, ...)`. Throws when the registry was constructed
|
|
307
596
|
* without a `spawnPty` factory (node-pty optional dep missing). */
|
|
308
597
|
spawnPty(input: SpawnPtyInput): SessionDescriptor;
|
|
598
|
+
/** Register a COMPLETED `command_execute` (or cron `kind:"command"`
|
|
599
|
+
* action) invocation as its own `kind: "command"` session. Unlike
|
|
600
|
+
* `spawn`/`spawnAgent`/`spawnPty`, there's no live process to track —
|
|
601
|
+
* the command already ran to completion via `runCommand` before this
|
|
602
|
+
* is called — so the descriptor is minted already "finished"
|
|
603
|
+
* (status exited/error, startedAt backdated by `durationMs`,
|
|
604
|
+
* endedAt now) and its full result is written to that session's own
|
|
605
|
+
* `events.jsonl` (see command-log.ts), the same per-id path an
|
|
606
|
+
* agent-cli session's structured transcript uses. Synchronous: the
|
|
607
|
+
* descriptor (and its id) is available immediately, the JSONL write
|
|
608
|
+
* itself is fire-and-forget internally. */
|
|
609
|
+
recordCommand(input: RecordCommandInput): SessionDescriptor;
|
|
610
|
+
/** Read back a `kind:"command"` session's full logged result (the
|
|
611
|
+
* `CommandLogEntry` `recordCommand` wrote). Resolves to null when the
|
|
612
|
+
* session isn't a command session or has no recorded entry. Routed
|
|
613
|
+
* through the registry (rather than callers importing
|
|
614
|
+
* `readCommandLogEntry` directly) so the read always targets the same
|
|
615
|
+
* base directory `recordCommand` wrote to — that dir is test-overridable
|
|
616
|
+
* (`transcriptDir`) and callers outside sessions.ts have no other way
|
|
617
|
+
* to know it. */
|
|
618
|
+
readCommandLog(sessionId: string): Promise<CommandLogEntry | null>;
|
|
309
619
|
/** Register an already-running browser service adapter as a tracked
|
|
310
620
|
* session (kind="browser"). Idempotent by identity — each call
|
|
311
621
|
* mints a fresh session id. The `stop` callback is invoked by
|
|
312
622
|
* `kill()` best-effort. */
|
|
313
623
|
registerBrowser(input: RegisterBrowserInput): SessionDescriptor;
|
|
314
624
|
/** Send a follow-up turn to a live agent session. Throws when the
|
|
315
|
-
* session is missing, not an agent-cli kind,
|
|
316
|
-
*
|
|
317
|
-
*
|
|
625
|
+
* session is missing, not an agent-cli kind, dead (exited/killed/
|
|
626
|
+
* error and unresumable — `SessionNotAliveError`), or busy
|
|
627
|
+
* (mid-turn). The events stream into the existing ring buffer +
|
|
628
|
+
* line emitter so /stream consumers see them as they arrive. */
|
|
318
629
|
sendPrompt(id: string, message: unknown): Promise<void>;
|
|
319
|
-
/** Fire-and-forget variant of `sendPrompt
|
|
320
|
-
*
|
|
321
|
-
*
|
|
322
|
-
*
|
|
323
|
-
*
|
|
324
|
-
*
|
|
325
|
-
*
|
|
326
|
-
*
|
|
327
|
-
|
|
630
|
+
/** Fire-and-forget variant of `sendPrompt` for the TURN ITSELF only.
|
|
631
|
+
* Admission (resume attempt + the missing/wrong-kind/dead/busy
|
|
632
|
+
* checks `sendPrompt` throws) is AWAITED before this resolves, so a
|
|
633
|
+
* dead or busy session rejects instead of silently reporting
|
|
634
|
+
* success — only resolves once the turn has actually started.
|
|
635
|
+
* Errors during the turn's own execution (network drop, child died
|
|
636
|
+
* mid-turn) are pushed into the ring buffer as `[error]` lines so
|
|
637
|
+
* `/stream` subscribers see them. Used by the web UI's chat input
|
|
638
|
+
* and MCP `agent_prompt`, where a long turn would otherwise freeze
|
|
639
|
+
* the caller.
|
|
640
|
+
*
|
|
641
|
+
* `opts.interrupt` lets a caller redirect a mid-turn session instead
|
|
642
|
+
* of hitting the busy rejection: the in-flight turn is cancelled
|
|
643
|
+
* (`agentSession.cancel()`), admission waits for that turn to
|
|
644
|
+
* actually settle (busy flips false — no fixed sleep), then the new
|
|
645
|
+
* prompt is admitted + fired on the SAME live session. Ignored
|
|
646
|
+
* (identical to the default) when the session is idle. Omitted or
|
|
647
|
+
* `false` reproduces today's mid-turn rejection byte-for-byte. */
|
|
648
|
+
enqueuePrompt(id: string, message: unknown, opts?: {
|
|
649
|
+
interrupt?: boolean;
|
|
650
|
+
}): Promise<void>;
|
|
651
|
+
/** Stamp `lastActivityAt` on a live agent-cli session's descriptor
|
|
652
|
+
* and schedule a debounced persist. Called from the `onActivity`
|
|
653
|
+
* callback threaded down through the driver → ACP client, which
|
|
654
|
+
* fires on ANY adapter-process traffic (not just ring-buffer
|
|
655
|
+
* output) — see `SessionDescriptor.lastActivityAt`. No-op when the
|
|
656
|
+
* id is unknown (session already forgotten). */
|
|
657
|
+
pulseActivity(id: string): void;
|
|
328
658
|
list(): SessionDescriptor[];
|
|
329
659
|
get(id: string): SessionDescriptor | undefined;
|
|
330
660
|
/** Subscribe to a session's output. Returns an unsubscribe fn.
|
|
@@ -448,6 +778,18 @@ interface SpawnAgentInput {
|
|
|
448
778
|
tokensIn?: number;
|
|
449
779
|
tokensOut?: number;
|
|
450
780
|
} | null>;
|
|
781
|
+
/** Opt this session into Langfuse tracing (prompt/completion + tool spans +
|
|
782
|
+
* tokens/cost). Effective opt-in is `trace ?? opts.langfuseTracingDefault ?? false`. */
|
|
783
|
+
trace?: boolean;
|
|
784
|
+
/** True when `agentSession` is a `SandboxAgentSessionProxy` (`agent_start.sandbox`)
|
|
785
|
+
* rather than a local subprocess-backed session — stamped onto the descriptor
|
|
786
|
+
* as `remote` since there's no local PID to report. */
|
|
787
|
+
remote?: boolean;
|
|
788
|
+
/** Provider-assigned sandbox id, when `remote` is true. */
|
|
789
|
+
sandboxId?: string;
|
|
790
|
+
/** What session close does to the box, when `remote` is true — see
|
|
791
|
+
* `SessionDescriptor.sandboxTeardown`. */
|
|
792
|
+
sandboxTeardown?: "kill" | "pause";
|
|
451
793
|
}
|
|
452
794
|
interface SpawnSessionInput {
|
|
453
795
|
kind: SessionKind;
|
|
@@ -491,6 +833,24 @@ interface SpawnPtyInput {
|
|
|
491
833
|
name?: string;
|
|
492
834
|
label?: string;
|
|
493
835
|
}
|
|
836
|
+
interface RecordCommandInput {
|
|
837
|
+
workspaceSlug: string;
|
|
838
|
+
/** Working directory the command actually ran in (post cwd-anchoring).
|
|
839
|
+
* Matched against a fresh session's cwd by `findPriorCommandSessionId`. */
|
|
840
|
+
cwd: string;
|
|
841
|
+
command: string;
|
|
842
|
+
args: string[];
|
|
843
|
+
/** Fields mirror `command-tools.ts`'s `ExecuteResult` — kept inline here
|
|
844
|
+
* (rather than importing that type) so sessions.ts has no dependency
|
|
845
|
+
* on command-tools.ts. */
|
|
846
|
+
exitCode: number;
|
|
847
|
+
signal: string | null;
|
|
848
|
+
durationMs: number;
|
|
849
|
+
stdout: string;
|
|
850
|
+
stderr: string;
|
|
851
|
+
truncated?: boolean;
|
|
852
|
+
label?: string;
|
|
853
|
+
}
|
|
494
854
|
|
|
495
855
|
/**
|
|
496
856
|
* MCP tools that expose browser service adapters (Camofox, Bureau, …) to
|
|
@@ -499,7 +859,7 @@ interface SpawnPtyInput {
|
|
|
499
859
|
* for fs/exec/agent-cli.
|
|
500
860
|
*
|
|
501
861
|
* Five tools:
|
|
502
|
-
*
|
|
862
|
+
* browser_adapter_list discover available browser adapter ids + metadata
|
|
503
863
|
* start_browser ensure a browser adapter is up, register as a session
|
|
504
864
|
* stop_browser kill a running browser session
|
|
505
865
|
* list_browsers browse alive/recent browser sessions
|
|
@@ -575,7 +935,7 @@ type BrowserAdapterLister = () => {
|
|
|
575
935
|
config?: unknown[];
|
|
576
936
|
}[];
|
|
577
937
|
/**
|
|
578
|
-
* Family-specific descriptor surfaced in the kit-path `
|
|
938
|
+
* Family-specific descriptor surfaced in the kit-path `browser_adapter_list`
|
|
579
939
|
* response. Fields match the legacy lister shape so the tool output is
|
|
580
940
|
* unchanged regardless of which path is active.
|
|
581
941
|
*/
|
|
@@ -593,7 +953,7 @@ interface BrowserAdapterInfo {
|
|
|
593
953
|
* `TunnelRegistry` (multi-tunnel general surface) can share the same
|
|
594
954
|
* provider contract without creating a circular dep.
|
|
595
955
|
*
|
|
596
|
-
* The tunnel family is the FIRST consumer of `@agentproto/
|
|
956
|
+
* The tunnel family is the FIRST consumer of `@agentproto/provider-kit`:
|
|
597
957
|
* {@link TunnelProviderHandle} extends the kit's generic `AdapterHandle`
|
|
598
958
|
* (slug/name/version/description/requiresSetup/check) with the
|
|
599
959
|
* tunnel-specific `capabilities` + the existing `start`/`stop` lifecycle.
|
|
@@ -775,16 +1135,37 @@ declare class TunnelRegistry {
|
|
|
775
1135
|
* third-party secrets) merged with descriptor-carried config (named's
|
|
776
1136
|
* hostname/tunnelId/credentialsFile), descriptor taking precedence.
|
|
777
1137
|
*/
|
|
778
|
-
|
|
1138
|
+
protected credsForDescriptor(desc: TunnelDescriptor): Promise<TunnelCreds>;
|
|
779
1139
|
private findEntryByIdOrName;
|
|
780
1140
|
private schedulePersist;
|
|
781
1141
|
private persistNow;
|
|
782
1142
|
private loadFromDisk;
|
|
783
1143
|
}
|
|
784
1144
|
|
|
1145
|
+
/**
|
|
1146
|
+
* Fire-and-forget webhook notifier for session lifecycle events.
|
|
1147
|
+
*
|
|
1148
|
+
* Each session can register its own `notifyUrl` (via `agent_start`).
|
|
1149
|
+
* A global URL can be set via `AGENTPROTO_NOTIFY_URL` env var or
|
|
1150
|
+
* `~/.agentproto/notify.json` (env wins). Both are POSTed when an event
|
|
1151
|
+
* fires — the union of per-session + global URLs, deduplicated.
|
|
1152
|
+
*
|
|
1153
|
+
* Retry policy: one retry after 2 s on network error. No retry on 4xx/5xx.
|
|
1154
|
+
* Timeout: 10 s per attempt. All errors are swallowed — the notifier never
|
|
1155
|
+
* throws into the session's hot path.
|
|
1156
|
+
*/
|
|
1157
|
+
|
|
1158
|
+
interface WebhookNotifier {
|
|
1159
|
+
/** Register a per-session URL (called from agent_start). */
|
|
1160
|
+
register(sessionId: string, url: string): void;
|
|
1161
|
+
unregister(sessionId: string): void;
|
|
1162
|
+
/** Handler to wire into SessionEventBus.onAny. Fire-and-forget. */
|
|
1163
|
+
onSessionEvent(ev: SessionEvent): void;
|
|
1164
|
+
}
|
|
1165
|
+
|
|
785
1166
|
/**
|
|
786
1167
|
* Cursor-based ring buffer for session events. Bridges the in-process
|
|
787
|
-
* SessionEventBus (push) to the
|
|
1168
|
+
* SessionEventBus (push) to the session_events_poll MCP tool (pull).
|
|
788
1169
|
*
|
|
789
1170
|
* Capacity default: 1 000 events. Oldest entry dropped on overflow —
|
|
790
1171
|
* callers that lag beyond the cap see a gap in their cursor but never
|
|
@@ -845,9 +1226,9 @@ interface EventRing {
|
|
|
845
1226
|
*
|
|
846
1227
|
* Trigger: session:turn-end on the watched session(s).
|
|
847
1228
|
* Gate: optional shell command via the same allowlist + cwd-anchor as
|
|
848
|
-
*
|
|
1229
|
+
* command_execute. exit 0 = pass.
|
|
849
1230
|
* Action (then:"emit"): emits policy:passed / policy:failed on the bus
|
|
850
|
-
* (readable via
|
|
1231
|
+
* (readable via session_events_poll).
|
|
851
1232
|
*
|
|
852
1233
|
* WP5 (then:"commit"): on a GREEN gate, prepare a host-side git commit in the
|
|
853
1234
|
* watched session's cwd — `git add -- <explicit paths>` then `git commit -m
|
|
@@ -859,7 +1240,7 @@ interface EventRing {
|
|
|
859
1240
|
* "nothing to commit" is treated as SUCCESS (idempotent re-commit after a
|
|
860
1241
|
* restart). `requireHumanAck` defaults to TRUE: the gate-green transition goes
|
|
861
1242
|
* to `awaiting-ack` and emits `policy:commit-ready` (paths + message) instead of
|
|
862
|
-
* committing; the commit runs only on `
|
|
1243
|
+
* committing; the commit runs only on `policy_ack(approve:true)` →
|
|
863
1244
|
* `policy:committed` (+ sha) → done; `approve:false` → cancelled. With
|
|
864
1245
|
* `requireHumanAck:false` the commit runs directly at the green gate.
|
|
865
1246
|
* onFail (WP2): when gate fails, re-prompts the session(s) (sendPrompt) up to
|
|
@@ -913,7 +1294,10 @@ interface ShellGateSpec {
|
|
|
913
1294
|
command: string;
|
|
914
1295
|
args?: string[];
|
|
915
1296
|
/** Working directory for the gate command. Defaults to the watched
|
|
916
|
-
* session's cwd
|
|
1297
|
+
* session's own cwd (trusted as-is — it was already an explicit,
|
|
1298
|
+
* vetted choice made at `agent_start` time). When given explicitly,
|
|
1299
|
+
* anchored to that session's cwd (not the daemon's boot workspace)
|
|
1300
|
+
* so a stray/injected value can't escape it. */
|
|
917
1301
|
cwd?: string;
|
|
918
1302
|
timeoutMs?: number;
|
|
919
1303
|
}
|
|
@@ -970,7 +1354,7 @@ interface CommitSpec {
|
|
|
970
1354
|
/**
|
|
971
1355
|
* Human-in-the-loop gate before the commit actually runs. Default TRUE:
|
|
972
1356
|
* the green gate transitions to `awaiting-ack` + emits `policy:commit-ready`
|
|
973
|
-
* and waits for `
|
|
1357
|
+
* and waits for `policy_ack`. Set false to commit directly at the green gate.
|
|
974
1358
|
*/
|
|
975
1359
|
requireHumanAck?: boolean;
|
|
976
1360
|
}
|
|
@@ -1073,6 +1457,15 @@ interface CompletionPolicySupervisor {
|
|
|
1073
1457
|
*/
|
|
1074
1458
|
ack(policyId: string, approve: boolean): Promise<PolicyRunState | undefined>;
|
|
1075
1459
|
list(): PolicyRunState[];
|
|
1460
|
+
/**
|
|
1461
|
+
* Subscribe to policy settlements — fired whenever a policy transitions
|
|
1462
|
+
* into a terminal state (done / blocked / cancelled) OR into awaiting-ack.
|
|
1463
|
+
* Used by the `/policies/:id/wait` long-poll to block until a policy
|
|
1464
|
+
* resolves without reimplementing the state machine's event surface.
|
|
1465
|
+
* Returns an unsubscribe fn. The callback receives the policyId; read
|
|
1466
|
+
* the full state via `getStatus(policyId)`.
|
|
1467
|
+
*/
|
|
1468
|
+
onSettle(cb: (policyId: string) => void): () => void;
|
|
1076
1469
|
/**
|
|
1077
1470
|
* Sync flush of the policy snapshot to disk. Call from the daemon
|
|
1078
1471
|
* stop() path — mirrors sessions.shutdown().
|
|
@@ -1080,34 +1473,13 @@ interface CompletionPolicySupervisor {
|
|
|
1080
1473
|
shutdown(): void;
|
|
1081
1474
|
}
|
|
1082
1475
|
|
|
1083
|
-
/**
|
|
1084
|
-
* Fire-and-forget webhook notifier for session lifecycle events.
|
|
1085
|
-
*
|
|
1086
|
-
* Each session can register its own `notifyUrl` (via `start_agent_session`).
|
|
1087
|
-
* A global URL can be set via `AGENTPROTO_NOTIFY_URL` env var or
|
|
1088
|
-
* `~/.agentproto/notify.json` (env wins). Both are POSTed when an event
|
|
1089
|
-
* fires — the union of per-session + global URLs, deduplicated.
|
|
1090
|
-
*
|
|
1091
|
-
* Retry policy: one retry after 2 s on network error. No retry on 4xx/5xx.
|
|
1092
|
-
* Timeout: 10 s per attempt. All errors are swallowed — the notifier never
|
|
1093
|
-
* throws into the session's hot path.
|
|
1094
|
-
*/
|
|
1095
|
-
|
|
1096
|
-
interface WebhookNotifier {
|
|
1097
|
-
/** Register a per-session URL (called from start_agent_session). */
|
|
1098
|
-
register(sessionId: string, url: string): void;
|
|
1099
|
-
unregister(sessionId: string): void;
|
|
1100
|
-
/** Handler to wire into SessionEventBus.onAny. Fire-and-forget. */
|
|
1101
|
-
onSessionEvent(ev: SessionEvent): void;
|
|
1102
|
-
}
|
|
1103
|
-
|
|
1104
1476
|
/**
|
|
1105
1477
|
* Orchestrator sub-gateway (ADR §4.2 / WP2) — the security primitive
|
|
1106
1478
|
* that lets a spawned agent become a *scoped* orchestrator without
|
|
1107
1479
|
* handing it the daemon's full toolset.
|
|
1108
1480
|
*
|
|
1109
|
-
* The plain `/mcp` endpoint registers EVERY tool (
|
|
1110
|
-
* fs_*, remote_*,
|
|
1481
|
+
* The plain `/mcp` endpoint registers EVERY tool (command_execute,
|
|
1482
|
+
* fs_*, remote_*, mcp_import, terminals, driver CRUD) and bypasses auth
|
|
1111
1483
|
* on loopback — pointing a child at it would be a privilege handout.
|
|
1112
1484
|
* This module builds a second, scoped MCP server that registers ONLY a
|
|
1113
1485
|
* curated orchestration allowlist, gated by an unguessable per-child
|
|
@@ -1126,21 +1498,20 @@ interface WebhookNotifier {
|
|
|
1126
1498
|
* The curated set of tools a scoped child orchestrator may call.
|
|
1127
1499
|
*
|
|
1128
1500
|
* INCLUDED — the orchestration primitives:
|
|
1129
|
-
*
|
|
1130
|
-
*
|
|
1131
|
-
*
|
|
1132
|
-
*
|
|
1133
|
-
*
|
|
1134
|
-
*
|
|
1501
|
+
* agent_start, agent_prompt, agent_output, agent_kill,
|
|
1502
|
+
* session_monitor, session_events_poll (spawn + drive + fan-in)
|
|
1503
|
+
* session_list, session_tree (observe). NB: list is NOT yet scoped
|
|
1504
|
+
* to the child's own subtree — that subtree filter is WP4
|
|
1505
|
+
* (parentSessionId/depth). For WP2 it is exposed daemon-wide;
|
|
1506
|
+
* documented debt.
|
|
1135
1507
|
*
|
|
1136
1508
|
* EXCLUDED — the danger surface (each a separate trust boundary):
|
|
1137
|
-
*
|
|
1138
|
-
*
|
|
1139
|
-
*
|
|
1140
|
-
*
|
|
1141
|
-
*
|
|
1142
|
-
*
|
|
1143
|
-
* doctype specs).
|
|
1509
|
+
* command_execute, terminal/PTY tools (raw shell), file_* /
|
|
1510
|
+
* directory_* tools, remote_* (publish the daemon to the internet),
|
|
1511
|
+
* mcp_import / mcp_discovered_* / mcp_imported_* (widen the daemon's
|
|
1512
|
+
* own MCP surface), and driver CRUD (create_/delete_/update_driver —
|
|
1513
|
+
* these never register here because the scoped server is built with
|
|
1514
|
+
* no doctype specs).
|
|
1144
1515
|
*/
|
|
1145
1516
|
declare const DEFAULT_ORCHESTRATOR_TOOLS: readonly string[];
|
|
1146
1517
|
interface OrchestratorScope {
|
|
@@ -1169,6 +1540,18 @@ interface OrchestratorScope {
|
|
|
1169
1540
|
/** Max concurrently-alive children the owning orchestrator may spawn
|
|
1170
1541
|
* before further spawns are rejected. */
|
|
1171
1542
|
maxChildren: number;
|
|
1543
|
+
/**
|
|
1544
|
+
* Name of the resolved role that owns this scope (spawn-role-
|
|
1545
|
+
* profiles / privilege lattice). This is the "parent role" the
|
|
1546
|
+
* `canSpawn` gate checks against when this scope is used to spawn a
|
|
1547
|
+
* further child (`session-spawn.ts`). Defaults to `"supervisor"` at
|
|
1548
|
+
* mint time when the caller doesn't say — every role that can reach
|
|
1549
|
+
* `orchestrator: true` today resolves to supervisor (executor's
|
|
1550
|
+
* `toolPolicy.delegation: "deny"` already excludes it from ever
|
|
1551
|
+
* minting a scope), so this preserves #214 behaviour exactly until a
|
|
1552
|
+
* custom role is actually granted delegation.
|
|
1553
|
+
*/
|
|
1554
|
+
role: string;
|
|
1172
1555
|
}
|
|
1173
1556
|
/**
|
|
1174
1557
|
* Narrow a caller-requested tool list to ⊆ a ceiling subset.
|
|
@@ -1197,6 +1580,9 @@ interface MintScopeOptions {
|
|
|
1197
1580
|
maxDepth?: number;
|
|
1198
1581
|
/** Per-orchestrator alive-child quota (default DEFAULT_MAX_CHILDREN). */
|
|
1199
1582
|
maxChildren?: number;
|
|
1583
|
+
/** Name of the resolved role that owns this scope. Default
|
|
1584
|
+
* `"supervisor"` — see `OrchestratorScope.role`. */
|
|
1585
|
+
role?: string;
|
|
1200
1586
|
}
|
|
1201
1587
|
interface ScopeTokenRegistry {
|
|
1202
1588
|
/** Mint a fresh scope-token. See `MintScopeOptions`. */
|
|
@@ -1228,16 +1614,21 @@ interface OrchestratorGatewayDeps {
|
|
|
1228
1614
|
listAgentAdapters?: AgentAdapterLister;
|
|
1229
1615
|
/** Orchestrator injector (WP3/WP4). When wired, a child orchestrator
|
|
1230
1616
|
* driving the scoped server can itself spawn sub-orchestrators
|
|
1231
|
-
* (`orchestrator: true` on its `
|
|
1617
|
+
* (`orchestrator: true` on its `agent_start`) — the new
|
|
1232
1618
|
* token inherits depth+1 and is bounded by the caller's tools
|
|
1233
1619
|
* (non-re-grant). Omitted → recursion injection is unavailable on
|
|
1234
1620
|
* the scoped surface (a child can still spawn plain sub-agents). */
|
|
1235
1621
|
orchestratorInjector?: OrchestratorInjector;
|
|
1236
1622
|
/** Optional webhook notifier — same singleton as the root /mcp server.
|
|
1237
|
-
* When provided, per-session notifyUrl values from
|
|
1623
|
+
* When provided, per-session notifyUrl values from agent_start
|
|
1238
1624
|
* are registered on spawn and unregistered on exit, so child
|
|
1239
1625
|
* orchestrators spawning through this scoped gateway also fire webhooks. */
|
|
1240
1626
|
webhookNotifier?: WebhookNotifier;
|
|
1627
|
+
/** Forwarded to `registerSessionTools` — the daemon's own plain `/mcp`
|
|
1628
|
+
* gateway URL, defaulted onto `hermes` `agent_start` spawns issued
|
|
1629
|
+
* through this scoped sub-gateway that pass no `mcpServers`. See
|
|
1630
|
+
* `RegisterAgentToolsOptions.daemonMcpUrl`. */
|
|
1631
|
+
daemonMcpUrl?: string;
|
|
1241
1632
|
}
|
|
1242
1633
|
type OrchestratorMcpServerFactory = (scope: OrchestratorScope) => Promise<McpServer>;
|
|
1243
1634
|
/**
|
|
@@ -1310,37 +1701,109 @@ type OrchestratorInjector = (opts?: {
|
|
|
1310
1701
|
/** Override the per-orchestrator child quota for the minted scope
|
|
1311
1702
|
* (clamped to the caller's). Root-only knob. */
|
|
1312
1703
|
maxChildren?: number;
|
|
1704
|
+
/** Name of the resolved role for the session THIS scope is being
|
|
1705
|
+
* minted for (i.e. the session becoming an orchestrator) — becomes
|
|
1706
|
+
* `OrchestratorScope.role`, the "parent role" a future spawn
|
|
1707
|
+
* through this scope is gated against. Default `"supervisor"`. */
|
|
1708
|
+
role?: string;
|
|
1313
1709
|
}) => OrchestratorInjection;
|
|
1314
1710
|
/**
|
|
1315
1711
|
* Build the orchestrator injector. Closed over the gateway's
|
|
1316
1712
|
* scope-token registry + session-event bus + HTTP port. Returns a
|
|
1317
|
-
* function that the `
|
|
1713
|
+
* function that the `agent_start` handler calls when its
|
|
1318
1714
|
* `orchestrator` field is set.
|
|
1319
1715
|
*/
|
|
1320
1716
|
declare function createOrchestratorInjector(deps: OrchestratorInjectorDeps): OrchestratorInjector;
|
|
1321
1717
|
|
|
1322
1718
|
/**
|
|
1323
|
-
*
|
|
1719
|
+
* Shared types for pluggable sandbox providers.
|
|
1720
|
+
*
|
|
1721
|
+
* The sandbox family is a `@agentproto/provider-kit` consumer, same shape as
|
|
1722
|
+
* the tunnel family (`remote-providers/types.ts`): {@link SandboxProviderHandle}
|
|
1723
|
+
* extends the kit's generic `AdapterHandle` (slug/name/version/description/
|
|
1724
|
+
* requiresSetup/check) with the AIP-36 capability namespace and the concrete
|
|
1725
|
+
* `@agentproto/sandbox` `SandboxProvider` (`boot()`) the handle wraps.
|
|
1726
|
+
*/
|
|
1727
|
+
|
|
1728
|
+
/**
|
|
1729
|
+
* Declared capabilities of a sandbox provider — pure metadata, surfaced in
|
|
1730
|
+
* `list_sandbox_providers`. Never carries secrets. Namespace mirrors AIP-36
|
|
1731
|
+
* SANDBOX.md (`network.egress`, `mounts`, `lifecycle.pause_after_idle`,
|
|
1732
|
+
* `read_only`, `limits.timeout_ms`).
|
|
1733
|
+
*/
|
|
1734
|
+
interface SandboxProviderCapabilities {
|
|
1735
|
+
/** Sandbox can be given a network egress allowlist (AIP-36 `network.egress`). */
|
|
1736
|
+
networkEgress: boolean;
|
|
1737
|
+
/** Sandbox supports mounting external filesystems (AIP-36 `mounts`). */
|
|
1738
|
+
mounts: boolean;
|
|
1739
|
+
/** Sandbox can be paused (not just killed) between turns (AIP-36 `lifecycle.pause_after_idle`). */
|
|
1740
|
+
lifecyclePause: boolean;
|
|
1741
|
+
/** Sandbox can be started read-only (AIP-36 `read_only`). */
|
|
1742
|
+
readOnly: boolean;
|
|
1743
|
+
/** Hard cap on `limits.timeout_ms`, when the provider enforces one. */
|
|
1744
|
+
maxTimeoutMs?: number;
|
|
1745
|
+
}
|
|
1746
|
+
/**
|
|
1747
|
+
* A sandbox provider as an adapter-kit handle. Rides on the kit's generic
|
|
1748
|
+
* {@link AdapterHandle} and adds the sandbox-specific `capabilities` plus
|
|
1749
|
+
* the `@agentproto/sandbox` `SandboxProvider` the handle wraps — the thing
|
|
1750
|
+
* `createSandboxAgentSessionHost` actually boots.
|
|
1751
|
+
*/
|
|
1752
|
+
interface SandboxProviderHandle extends AdapterHandle {
|
|
1753
|
+
readonly provider: SandboxProvider;
|
|
1754
|
+
readonly capabilities: SandboxProviderCapabilities;
|
|
1755
|
+
/**
|
|
1756
|
+
* Credential fields this provider accepts via `setup_sandbox_provider`
|
|
1757
|
+
* (e.g. e2b's `apiKey`). Omit (or empty) when the provider needs no
|
|
1758
|
+
* credentials (e.g. `local`).
|
|
1759
|
+
*/
|
|
1760
|
+
readonly setupFields?: readonly SetupField[];
|
|
1761
|
+
}
|
|
1762
|
+
|
|
1763
|
+
/**
|
|
1764
|
+
* Sandbox family on top of `@agentproto/provider-kit` — mirrors
|
|
1765
|
+
* `tunnel-adapters.ts`. This module is the entire bridge between the
|
|
1766
|
+
* generic kit and `@agentproto/sandbox`'s `SandboxProvider` concept: it
|
|
1767
|
+
* contributes nothing the kit already owns (catalog/status/creds/ledger/
|
|
1768
|
+
* list/MCP-tool plumbing); it only supplies the sandbox-family `TInfo`
|
|
1769
|
+
* (`SandboxAdapterInfo`), the static `SANDBOX_CATALOG`, and the resolver
|
|
1770
|
+
* that maps a catalog slug to a concrete {@link SandboxProviderHandle}
|
|
1771
|
+
* (`./sandbox-providers/registry.js`).
|
|
1324
1772
|
*
|
|
1325
|
-
*
|
|
1326
|
-
*
|
|
1327
|
-
*
|
|
1328
|
-
*
|
|
1329
|
-
*
|
|
1330
|
-
*
|
|
1331
|
-
*
|
|
1332
|
-
*
|
|
1333
|
-
* POST /heartbeat/tick — force-fire one heartbeat tick
|
|
1773
|
+
* Kit primitives used:
|
|
1774
|
+
* - `makeCredsStore` → per-slug 0600 creds under `~/.agentproto/sandbox-creds/`
|
|
1775
|
+
* - `makeSetupLedger` → `~/.agentproto/setup/<slug>.json`
|
|
1776
|
+
* - `makeAdapterResolver` → wraps the throwing `load` into null-on-miss
|
|
1777
|
+
* - `makeAdapterLister` → catalog → status-classified `AdapterEntry[]`
|
|
1778
|
+
* - `makeListTool` → registers `list_sandbox_providers`
|
|
1779
|
+
* - `makeSetupTool` → registers `setup_sandbox_provider` (multi-field
|
|
1780
|
+
* form: e2b's `apiKey`, sensitive)
|
|
1334
1781
|
*
|
|
1335
|
-
*
|
|
1336
|
-
*
|
|
1337
|
-
*
|
|
1782
|
+
* This is pure additive plumbing (introspection + setup) — it does NOT wire
|
|
1783
|
+
* a `sandbox` field into `agent_start`. That lands in a follow-up PR; the
|
|
1784
|
+
* `resolveSandboxProvider`/`listSandboxProviders` overrides below exist now
|
|
1785
|
+
* so that later wiring can inject the same resolver/lister this module
|
|
1786
|
+
* builds by default, mirroring `resolveAgentAdapter`/`listAgentAdapters`.
|
|
1338
1787
|
*
|
|
1339
|
-
*
|
|
1340
|
-
*
|
|
1341
|
-
*
|
|
1788
|
+
* Security: `toSandboxInfo` exposes only `capabilities` — never a cred
|
|
1789
|
+
* value (Appendix B). The setup tool's fields are marked SENSITIVE and the
|
|
1790
|
+
* result NEVER echoes any field value back.
|
|
1342
1791
|
*/
|
|
1343
1792
|
|
|
1793
|
+
/**
|
|
1794
|
+
* Family descriptor (`TInfo`). Pure metadata surfaced in
|
|
1795
|
+
* `list_sandbox_providers`. The kit's `AdapterEntry` already carries
|
|
1796
|
+
* slug/name/description/status/version, so the only sandbox-specific field
|
|
1797
|
+
* is the declared capability set. NEVER carries a cred value.
|
|
1798
|
+
*/
|
|
1799
|
+
interface SandboxAdapterInfo {
|
|
1800
|
+
capabilities: SandboxProviderCapabilities;
|
|
1801
|
+
}
|
|
1802
|
+
/** Resolve a sandbox provider slug to a handle, or null when unavailable. */
|
|
1803
|
+
type SandboxProviderResolver = AdapterResolver<SandboxProviderHandle>;
|
|
1804
|
+
/** List every sandbox provider with its live status + capabilities. */
|
|
1805
|
+
type SandboxProviderLister = AdapterLister<SandboxAdapterInfo>;
|
|
1806
|
+
|
|
1344
1807
|
/**
|
|
1345
1808
|
* Pluggable adapter resolver — keeps the runtime package free of any
|
|
1346
1809
|
* @agentproto/cli dep. The host (cli `serve`, playground, embedding
|
|
@@ -1361,12 +1824,36 @@ type AgentAdapterResolver = (slug: string) => Promise<{
|
|
|
1361
1824
|
startSession(opts: {
|
|
1362
1825
|
cwd: string;
|
|
1363
1826
|
resumeSessionId?: string;
|
|
1364
|
-
/**
|
|
1827
|
+
/**
|
|
1828
|
+
* Manifest-declared mode id forwarded from `agent_start` (AIP-45
|
|
1829
|
+
* `AgentCliHandle.modes` — e.g. claude-code's `plan` /
|
|
1830
|
+
* `accept-edits` / `bypass-permissions`, codex's `read-only`,
|
|
1831
|
+
* mastracode/opencode's `plan`). Applied at spawn time via
|
|
1832
|
+
* `composeSpawn`'s mode patch (`bin_args_append` / `env`) — BEFORE
|
|
1833
|
+
* the child process is exec'd, unlike `model`/`effort` below.
|
|
1834
|
+
* Adapters with no declared `modes` (e.g. hermes) ignore it; an
|
|
1835
|
+
* unknown id for an adapter that DOES declare modes throws
|
|
1836
|
+
* `RuntimeConfigError` (composeSpawn validates against the
|
|
1837
|
+
* manifest, so a typo fails the spawn rather than silently no-op).
|
|
1838
|
+
*/
|
|
1839
|
+
mode?: string;
|
|
1840
|
+
/**
|
|
1841
|
+
* Manifest-declared option id → value map forwarded from
|
|
1842
|
+
* `agent_start` (AIP-45 `AgentCliHandle.options` — e.g. hermes'
|
|
1843
|
+
* `skills`). Applied at spawn time via `composeSpawn`'s option
|
|
1844
|
+
* patches (`bin_args_prepend` / `bin_args_template` /
|
|
1845
|
+
* `bin_args_append_when_true` / `env`), validated against each
|
|
1846
|
+
* option's declared `type`/`enum`/`min`/`max`. An id the adapter
|
|
1847
|
+
* doesn't declare throws `RuntimeConfigError` (composeSpawn
|
|
1848
|
+
* validates against the manifest, same as an unknown `mode`).
|
|
1849
|
+
*/
|
|
1850
|
+
options?: Record<string, boolean | number | string>;
|
|
1851
|
+
/** Model identifier forwarded from `agent_start`. For ACP
|
|
1365
1852
|
* adapters this is applied via session/set_config_option after
|
|
1366
1853
|
* newSession (the ACP wrapper does not forward CLI args to claude).
|
|
1367
1854
|
* Adapters that don't support model selection ignore it. */
|
|
1368
1855
|
model?: string;
|
|
1369
|
-
/** Effort level forwarded from `
|
|
1856
|
+
/** Effort level forwarded from `agent_start`. Effort is
|
|
1370
1857
|
* model-dependent — same label ≠ same budget across models; defaults
|
|
1371
1858
|
* differ by model. Omit to keep the model's own default. Applied
|
|
1372
1859
|
* via session/set_config_option on ACP adapters; others ignore it. */
|
|
@@ -1377,6 +1864,12 @@ type AgentAdapterResolver = (slug: string) => Promise<{
|
|
|
1377
1864
|
* a host-chosen scoped toolset (e.g. the daemon's own orchestration
|
|
1378
1865
|
* gateway). Adapters that don't model MCP mounting ignore it. */
|
|
1379
1866
|
mcpServers?: AcpMcpServer[];
|
|
1867
|
+
/** Called on any adapter-process activity (ACP JSON-RPC traffic in
|
|
1868
|
+
* either direction) — forwarded to the driver's
|
|
1869
|
+
* `runtime.start({ onActivity })`. The caller (agent_start's MCP
|
|
1870
|
+
* handler, POST /sessions/agent) wires this to pulse
|
|
1871
|
+
* `SessionDescriptor.lastActivityAt` via `registry.pulseActivity(id)`. */
|
|
1872
|
+
onActivity?: () => void;
|
|
1380
1873
|
}): Promise<AgentSessionLike>;
|
|
1381
1874
|
/** Display label for the descriptor's `command` field. */
|
|
1382
1875
|
commandPreview?: string;
|
|
@@ -1386,7 +1879,30 @@ type AgentAdapterResolver = (slug: string) => Promise<{
|
|
|
1386
1879
|
tokensIn?: number;
|
|
1387
1880
|
tokensOut?: number;
|
|
1388
1881
|
} | null>;
|
|
1882
|
+
/** AIP-45 `options[]` this adapter's manifest declares (id + type only —
|
|
1883
|
+
* no spawn internals). Lets `session-spawn.ts` fold a config-level
|
|
1884
|
+
* `defaults.skills` list into `options.skills` using the shape the
|
|
1885
|
+
* manifest actually declared (e.g. hermes' comma-joined string),
|
|
1886
|
+
* instead of guessing. Omitted/empty ⇒ the skills normalization is a
|
|
1887
|
+
* documented no-op for that adapter (e.g. claude-code, which
|
|
1888
|
+
* auto-discovers skills and declares no such option). */
|
|
1889
|
+
declaredOptions?: readonly DeclaredAdapterOption[];
|
|
1389
1890
|
} | null>;
|
|
1891
|
+
/**
|
|
1892
|
+
* UI-safe projection of an AIP-45 `modes[]` entry as surfaced by
|
|
1893
|
+
* `adapter_list`. Mirrors `@agentproto/cli`'s `AdapterMode` without
|
|
1894
|
+
* importing it (the runtime deliberately carries no cli dep — see the
|
|
1895
|
+
* `AgentAdapterLister` note above). Spawn internals (`bin_args_*`, `env`)
|
|
1896
|
+
* are intentionally omitted; `status` is normalised to `"active"` by the
|
|
1897
|
+
* lister when the manifest omits it, so a declared mode is never
|
|
1898
|
+
* silently statusless.
|
|
1899
|
+
*/
|
|
1900
|
+
interface AdapterListMode {
|
|
1901
|
+
id: string;
|
|
1902
|
+
description?: string;
|
|
1903
|
+
status: "active" | "noop" | "planned";
|
|
1904
|
+
status_note?: string;
|
|
1905
|
+
}
|
|
1390
1906
|
/**
|
|
1391
1907
|
* Compact adapter metadata for the discovery endpoints. Independent
|
|
1392
1908
|
* of the resolver function above — hosts that can list installed
|
|
@@ -1401,6 +1917,10 @@ interface AdapterListEntry {
|
|
|
1401
1917
|
protocol: string;
|
|
1402
1918
|
streaming: boolean;
|
|
1403
1919
|
packageName: string;
|
|
1920
|
+
/** Declared operation modes with their honest support status, so a
|
|
1921
|
+
* client can see e.g. hermes' `lean` mode is a measured no-op instead
|
|
1922
|
+
* of being silently accepted. Empty when the adapter declares none. */
|
|
1923
|
+
modes: AdapterListMode[];
|
|
1404
1924
|
}
|
|
1405
1925
|
type AgentAdapterLister = () => Promise<AdapterListEntry[]>;
|
|
1406
1926
|
interface AuthOptions {
|
|
@@ -1487,7 +2007,7 @@ interface InboundWatcher {
|
|
|
1487
2007
|
}
|
|
1488
2008
|
|
|
1489
2009
|
/**
|
|
1490
|
-
* Browser family on top of `@agentproto/
|
|
2010
|
+
* Browser family on top of `@agentproto/provider-kit` — Phase 3 (lightest
|
|
1491
2011
|
* adoption: no creds, no wizard, no catalog file).
|
|
1492
2012
|
*
|
|
1493
2013
|
* Provides the kit-compatible types (`BrowserAdapterHandle`) and the
|
|
@@ -1530,6 +2050,138 @@ declare function makeBrowserAdapterLister(opts: {
|
|
|
1530
2050
|
resolveBrowserAdapter?: BrowserAdapterResolver;
|
|
1531
2051
|
}): AdapterLister<BrowserAdapterInfo>;
|
|
1532
2052
|
|
|
2053
|
+
/**
|
|
2054
|
+
* Turns a raw tool-call name + args (and its eventual result) into a short,
|
|
2055
|
+
* human-readable line for ring-buffer / CLI / transcript rendering. Without
|
|
2056
|
+
* this, every tool call renders as a bare `[tool] view` with no args and no
|
|
2057
|
+
* outcome — this module is the one place that knows how to summarize both.
|
|
2058
|
+
*/
|
|
2059
|
+
/** A one-line human summary of a tool call, e.g. `read src/foo.ts` or `⏰ wake in 30s — checking CI`. */
|
|
2060
|
+
declare function formatToolCall(toolName: string, args: unknown): string;
|
|
2061
|
+
/**
|
|
2062
|
+
* A short outcome line for a completed tool call, or `null` when there's
|
|
2063
|
+
* nothing useful to show (e.g. an empty/void result). `toolName` is
|
|
2064
|
+
* accepted for parity with `formatToolCall` and future bespoke result
|
|
2065
|
+
* formatting, but generic text extraction covers today's cases.
|
|
2066
|
+
*/
|
|
2067
|
+
declare function formatToolResult(toolName: string | undefined, result: unknown, isError: boolean): string | null;
|
|
2068
|
+
|
|
2069
|
+
/**
|
|
2070
|
+
* Dependency-injection surface for MCP credential resolution.
|
|
2071
|
+
*
|
|
2072
|
+
* `packages/runtime` intentionally does NOT depend on `@agentproto/auth`;
|
|
2073
|
+
* the daemon bootstrap (e.g. `packages/cli`) can set a broker-backed
|
|
2074
|
+
* resolver here, and `session-spawn.ts` will call it when an `mcpServers`
|
|
2075
|
+
* entry carries `credentialRef`. Errors from the hook are treated as
|
|
2076
|
+
* non-fatal by the caller.
|
|
2077
|
+
*/
|
|
2078
|
+
interface McpCredentialDeps {
|
|
2079
|
+
/** Resolve brokered headers for an `mcpServers` entry that names a
|
|
2080
|
+
* `credentialRef`. The returned headers are merged ON TOP of the
|
|
2081
|
+
* entry's static `headers` so brokered auth wins on collision. */
|
|
2082
|
+
resolveMcpCredentialHeaders?: (o: {
|
|
2083
|
+
credentialRef: string;
|
|
2084
|
+
signal?: AbortSignal;
|
|
2085
|
+
}) => Promise<Record<string, string> | undefined>;
|
|
2086
|
+
/** Resolve a single named secret (an env-var-shaped slug — e.g. a sandbox
|
|
2087
|
+
* spec's `env.passthrough` / `env.auth.state.env` entries) to its raw
|
|
2088
|
+
* value. Distinct from `resolveMcpCredentialHeaders` above (which
|
|
2089
|
+
* resolves an MCP `credentialRef` PATH into Authorization-style
|
|
2090
|
+
* headers): this is the `SecretResolver` shape `agent_start`'s sandbox
|
|
2091
|
+
* branch (`session-spawn.ts`) passes to `@agentproto/sandbox`'s
|
|
2092
|
+
* `SandboxSecretsConfig.resolver` — so a booted sandbox's env is filled
|
|
2093
|
+
* from the same host-injected broker as every other secret, never a
|
|
2094
|
+
* bare `process.env` read at the call site. Returns null when the slug
|
|
2095
|
+
* can't be resolved (missing/unconfigured). */
|
|
2096
|
+
resolveSandboxSecret?: (slug: string) => Promise<string | null>;
|
|
2097
|
+
}
|
|
2098
|
+
declare function setMcpCredentialDeps(d: McpCredentialDeps): void;
|
|
2099
|
+
declare function getMcpCredentialDeps(): McpCredentialDeps;
|
|
2100
|
+
|
|
2101
|
+
/**
|
|
2102
|
+
* Provider-preset family on top of `@agentproto/provider-kit` — the *thin,
|
|
2103
|
+
* honest* lister (Option B). Unlike tunnels/sandboxes/eval-reporters, presets
|
|
2104
|
+
* are bundled static data with no binary to install, no package to resolve, and
|
|
2105
|
+
* no setup ledger: their only "setup" is an ambient API-key env var. So this
|
|
2106
|
+
* module does NOT use `makeAdapterResolver` / `makeAdapterLister` / the wizard
|
|
2107
|
+
* (all install-oriented, a forced fit). It reuses only `makeListTool` — the one
|
|
2108
|
+
* kit primitive that's genuinely about "JSON a lister's output as an MCP tool."
|
|
2109
|
+
*
|
|
2110
|
+
* Status is derived honestly from the daemon's own environment (the env agents
|
|
2111
|
+
* spawn into), not the CLI caller's:
|
|
2112
|
+
* "ready" — `process.env[preset.keyEnv]` is set (key available to spawn)
|
|
2113
|
+
* "available" — key absent (preset known, usable once the env var is provided)
|
|
2114
|
+
*
|
|
2115
|
+
* There is no "supported" state: presets ship in-repo, so they're always at
|
|
2116
|
+
* least "available." `version` is the literal "built-in".
|
|
2117
|
+
*
|
|
2118
|
+
* Security (Appendix B): `PresetInfo` carries only `keyEnv` (the env-var NAME),
|
|
2119
|
+
* never a key value. The list tool never returns creds — there are none to
|
|
2120
|
+
* return; keys live in the operator's environment, not a creds store.
|
|
2121
|
+
*/
|
|
2122
|
+
|
|
2123
|
+
/**
|
|
2124
|
+
* Manifest-declared AIP-45 preset, the minimum the catalog needs to merge
|
|
2125
|
+
* an adapter-contributed preset into the listing. Mirrors
|
|
2126
|
+
* `AgentCliPresetDeclaration`'s fields without importing
|
|
2127
|
+
* `@agentproto/driver-agent-cli` into the runtime package (same structural-
|
|
2128
|
+
* type pattern as `DeclaredAdapterOption` in spawn-defaults.ts).
|
|
2129
|
+
*/
|
|
2130
|
+
interface DeclaredAdapterPreset {
|
|
2131
|
+
id: string;
|
|
2132
|
+
label: string;
|
|
2133
|
+
description?: string;
|
|
2134
|
+
schemaFlavor: ProviderPreset["schemaFlavor"];
|
|
2135
|
+
baseUrl: string;
|
|
2136
|
+
keyEnv: string;
|
|
2137
|
+
scrubEnv?: string[];
|
|
2138
|
+
defaultModel?: string;
|
|
2139
|
+
homepage?: string;
|
|
2140
|
+
}
|
|
2141
|
+
/**
|
|
2142
|
+
* Family descriptor surfaced as `AdapterEntry.info`. User-facing preset facts
|
|
2143
|
+
* only — no cred values (there are none in the registry), no adapter projection
|
|
2144
|
+
* detail (`scrubEnv` stays internal to adapter manifests).
|
|
2145
|
+
*/
|
|
2146
|
+
interface PresetInfo {
|
|
2147
|
+
/** API schema flavor — which adapter family can consume this preset. */
|
|
2148
|
+
schemaFlavor: ProviderPreset["schemaFlavor"];
|
|
2149
|
+
/** Base URL the client hits. */
|
|
2150
|
+
baseUrl: string;
|
|
2151
|
+
/** Env-var NAME holding the API key (never the value). */
|
|
2152
|
+
keyEnv: string;
|
|
2153
|
+
/** Conventional default model id, if any. */
|
|
2154
|
+
defaultModel?: string;
|
|
2155
|
+
/** Homepage/docs URL. */
|
|
2156
|
+
homepage?: string;
|
|
2157
|
+
}
|
|
2158
|
+
/**
|
|
2159
|
+
* Normalize a manifest-declared preset into the canonical `ProviderPreset`
|
|
2160
|
+
* shape the catalog lists. `scrubEnv` defaults to empty (an adapter that
|
|
2161
|
+
* scrubs in code may omit it); `description` defaults to empty. Pure.
|
|
2162
|
+
*/
|
|
2163
|
+
declare function declaredPresetToProviderPreset(decl: DeclaredAdapterPreset): ProviderPreset;
|
|
2164
|
+
/**
|
|
2165
|
+
* Map the static preset registry → status-classified catalog entries, reading
|
|
2166
|
+
* the daemon's environment for key presence. Pure (no I/O) save the `process`
|
|
2167
|
+
* .env read; safe to call on every list invocation.
|
|
2168
|
+
*
|
|
2169
|
+
* `adapterPresets` — manifest-declared presets contributed by loaded adapters
|
|
2170
|
+
* (Stage 3 AIP-45 `presets` field). Merged AFTER the built-in registry and
|
|
2171
|
+
* deduped by id: an adapter-declared id that collides with a built-in is
|
|
2172
|
+
* ignored (the registry is the source of truth for canonical providers), so
|
|
2173
|
+
* an adapter can't silently override moonshot/openrouter facts. The live
|
|
2174
|
+
* wiring that reads each adapter's `.presets` and passes them here is Stage 4;
|
|
2175
|
+
* today this is the tested seam.
|
|
2176
|
+
*/
|
|
2177
|
+
declare function listPresets(env?: Record<string, string | undefined>, adapterPresets?: readonly DeclaredAdapterPreset[]): AdapterEntry<PresetInfo>[];
|
|
2178
|
+
|
|
2179
|
+
/** A journal-file StepCache scoped to one cacheKey. Best-effort: read/parse
|
|
2180
|
+
* failures degrade to "no cache" (a miss), never throw into the run. */
|
|
2181
|
+
declare function createFileStepCache(cacheKey: string, opts?: {
|
|
2182
|
+
dir?: string;
|
|
2183
|
+
}): StepCache;
|
|
2184
|
+
|
|
1533
2185
|
/**
|
|
1534
2186
|
* `.agentproto/` config dir — runtime-managed state at the root of
|
|
1535
2187
|
* every workspace. Mirrors the `.git/` model: user-content stays at
|
|
@@ -1648,6 +2300,90 @@ declare function readRuntimeMeta(workspace: string): Promise<{
|
|
|
1648
2300
|
*/
|
|
1649
2301
|
declare function sweepStaleRuntimeMetas(workspaces: readonly string[], currentWorkspace: string): Promise<string[]>;
|
|
1650
2302
|
|
|
2303
|
+
/**
|
|
2304
|
+
* MCP tools for event-driven orchestration:
|
|
2305
|
+
* - session_events_poll — cheap cursor-based snapshot of session events
|
|
2306
|
+
* - session_monitor — multiplexed long-poll (1 call for N sessions)
|
|
2307
|
+
*
|
|
2308
|
+
* These complement the existing per-session waitForTurnEnd inside
|
|
2309
|
+
* agent_output. The new tools handle multi-session fan-in
|
|
2310
|
+
* and external-client retrigger without burning polling tokens.
|
|
2311
|
+
*/
|
|
2312
|
+
|
|
2313
|
+
/**
|
|
2314
|
+
* Event kind a session wait can target. Mirrors the `session_monitor`
|
|
2315
|
+
* `event` parameter. `turn-end` also matches `awaiting-input` (both
|
|
2316
|
+
* signal end-of-turn), matching the MCP tool's semantics.
|
|
2317
|
+
*/
|
|
2318
|
+
type SessionWaitEvent = "turn-end" | "awaiting-input" | "exited" | "any";
|
|
2319
|
+
/**
|
|
2320
|
+
* Result of a single-session wait. On a hit, carries the session id, the
|
|
2321
|
+
* matched event (ring-bus form, without the `session:` prefix), the
|
|
2322
|
+
* session's current status, and whether it's awaiting input. On a
|
|
2323
|
+
* timeout, `timedOut: true` and the watched id list.
|
|
2324
|
+
*/
|
|
2325
|
+
interface SessionWaitResult {
|
|
2326
|
+
timedOut?: boolean;
|
|
2327
|
+
sessionId?: string;
|
|
2328
|
+
event?: string;
|
|
2329
|
+
source?: "ring" | "state" | "bus";
|
|
2330
|
+
awaitingInput?: boolean;
|
|
2331
|
+
status?: string;
|
|
2332
|
+
turnsCompleted?: number;
|
|
2333
|
+
sessionIds?: string[];
|
|
2334
|
+
since?: number;
|
|
2335
|
+
/** Structured awaiting-input question (harness-parity). Surface on
|
|
2336
|
+
* turn-end / awaiting-input matches so callers (MCP session_monitor +
|
|
2337
|
+
* REST /sessions/:id/wait) can read the question without a separate
|
|
2338
|
+
* transcript fetch. Mirrors desc.awaitingQuestion / ev.question. */
|
|
2339
|
+
question?: SessionAwaitingQuestion;
|
|
2340
|
+
}
|
|
2341
|
+
/**
|
|
2342
|
+
* Block until one of the listed sessions fires a matching lifecycle event
|
|
2343
|
+
* (turn-end / awaiting-input / exited / any), or until `timeoutMs` elapses.
|
|
2344
|
+
*
|
|
2345
|
+
* This is the single-session-capable core that the MCP `session_monitor`
|
|
2346
|
+
* tool and the REST `GET /sessions/:id/wait` route both call. The MCP tool
|
|
2347
|
+
* passes N ids (multiplexed fan-in); the REST route passes exactly one.
|
|
2348
|
+
* The semantics are identical: race-free cursor replay → synchronous
|
|
2349
|
+
* already-in-target-state check → bus long-poll → timeout.
|
|
2350
|
+
*
|
|
2351
|
+
* `since` is an EventRing cursor: when provided, already-emitted matching
|
|
2352
|
+
* events for the watched sessions that occurred after that cursor are
|
|
2353
|
+
* returned immediately (race-free replay) before subscribing to the bus.
|
|
2354
|
+
*/
|
|
2355
|
+
declare function monitorSessionWait(opts: {
|
|
2356
|
+
registry: SessionsRegistry;
|
|
2357
|
+
sessionEvents: SessionEventBus;
|
|
2358
|
+
eventRing: EventRing;
|
|
2359
|
+
sessionIds: string[];
|
|
2360
|
+
event?: SessionWaitEvent;
|
|
2361
|
+
timeoutMs?: number;
|
|
2362
|
+
since?: number;
|
|
2363
|
+
}): Promise<SessionWaitResult>;
|
|
2364
|
+
/**
|
|
2365
|
+
* Block until the named policy's status transitions out of the active
|
|
2366
|
+
* `watching` / `queued` / `gating` / `nudging` states — i.e. reaches
|
|
2367
|
+
* `done`, `blocked`, `awaiting-ack`, or `cancelled` — then return the
|
|
2368
|
+
* full PolicyRunState. Returns `{ timedOut: true }` on timeout.
|
|
2369
|
+
*
|
|
2370
|
+
* Hooks into the supervisor's `onSettle` callback (the single reliable
|
|
2371
|
+
* signal — some terminal transitions like `cancel()` / `ack(false)` /
|
|
2372
|
+
* single-session-exit emit no SessionEventBus event). The MCP
|
|
2373
|
+
* `policy_status` tool and the REST `GET /policies/:id/wait` route both
|
|
2374
|
+
* delegate here, so the wait semantics are shared across transports.
|
|
2375
|
+
*/
|
|
2376
|
+
declare function monitorPolicyWait(opts: {
|
|
2377
|
+
supervisor: CompletionPolicySupervisor;
|
|
2378
|
+
policyId: string;
|
|
2379
|
+
timeoutMs?: number;
|
|
2380
|
+
}): Promise<{
|
|
2381
|
+
timedOut: true;
|
|
2382
|
+
} | {
|
|
2383
|
+
timedOut: false;
|
|
2384
|
+
state: PolicyRunState;
|
|
2385
|
+
}>;
|
|
2386
|
+
|
|
1651
2387
|
/**
|
|
1652
2388
|
* @agentproto/runtime — long-running gateway around an agentproto
|
|
1653
2389
|
* workspace dir.
|
|
@@ -1703,18 +2439,18 @@ interface CreateGatewayOptions {
|
|
|
1703
2439
|
* Without this, /sessions still works for raw `argv` spawns. */
|
|
1704
2440
|
resolveAgentAdapter?: AgentAdapterResolver;
|
|
1705
2441
|
/** Optional adapter lister — when provided, enables
|
|
1706
|
-
* `GET /adapters` HTTP route + `
|
|
2442
|
+
* `GET /adapters` HTTP route + `adapter_list` MCP tool so UIs
|
|
1707
2443
|
* can discover what's installed on the host. */
|
|
1708
2444
|
listAgentAdapters?: AgentAdapterLister;
|
|
1709
2445
|
/** Optional browser adapter resolver — when provided, enables the
|
|
1710
2446
|
* `start_browser` MCP tool (launches Camofox / Bureau / Chromium). */
|
|
1711
2447
|
resolveBrowserAdapter?: BrowserAdapterResolver;
|
|
1712
2448
|
/** Optional browser adapter lister — when provided, enables the
|
|
1713
|
-
* `
|
|
2449
|
+
* `browser_adapter_list` MCP tool. */
|
|
1714
2450
|
listBrowserAdapters?: BrowserAdapterLister;
|
|
1715
2451
|
/** Optional PTY factory (node-pty wrapper, typically from the cli
|
|
1716
2452
|
* layer's `loadNodePtyFactory()`). When provided, enables
|
|
1717
|
-
* `POST /sessions/terminal`, the `
|
|
2453
|
+
* `POST /sessions/terminal`, the `terminal_start` MCP
|
|
1718
2454
|
* tool family, and the `/sessions/:id/pty` WebSocket. Without it,
|
|
1719
2455
|
* those routes return 501 / the MCP tools aren't registered. */
|
|
1720
2456
|
spawnPty?: PtyFactory;
|
|
@@ -1731,6 +2467,30 @@ interface CreateGatewayOptions {
|
|
|
1731
2467
|
/** When true, drop the localhost-wildcard defaults — only the
|
|
1732
2468
|
* explicit `allowedOrigins` list is honoured. */
|
|
1733
2469
|
strictOrigins?: boolean;
|
|
2470
|
+
/**
|
|
2471
|
+
* Opt-in deferred/lazy MCP tool loading (harness-parity item 3, see
|
|
2472
|
+
* `deferred-tools.ts`). When set, every root-gateway tool outside
|
|
2473
|
+
* `alwaysOn` registers but starts disabled — excluded from the first
|
|
2474
|
+
* `tools/list` — until the always-on `tool_search` meta-tool pulls it
|
|
2475
|
+
* in by keyword. Omitted (default) → every tool is eagerly enabled,
|
|
2476
|
+
* identical to pre-existing behaviour. Does not affect the scoped
|
|
2477
|
+
* `/mcp/orchestrator` sub-gateway, which already exposes a small
|
|
2478
|
+
* curated allowlist (`DEFAULT_ORCHESTRATOR_TOOLS`).
|
|
2479
|
+
*/
|
|
2480
|
+
deferredTools?: {
|
|
2481
|
+
alwaysOn?: readonly string[];
|
|
2482
|
+
};
|
|
2483
|
+
/**
|
|
2484
|
+
* Optional sandbox provider resolver — overrides the sandbox family's
|
|
2485
|
+
* default resolver (built-ins + `@agentproto/sandbox-<slug>` dynamic
|
|
2486
|
+
* import) used by `list_sandbox_providers` / `setup_sandbox_provider`
|
|
2487
|
+
* AND `agent_start.sandbox`. Mirrors `resolveAgentAdapter`'s injection
|
|
2488
|
+
* shape.
|
|
2489
|
+
*/
|
|
2490
|
+
resolveSandboxProvider?: SandboxProviderResolver;
|
|
2491
|
+
/** Optional sandbox provider lister — mirrors `listAgentAdapters`.
|
|
2492
|
+
* Overrides the default catalog-driven lister behind `list_sandbox_providers`. */
|
|
2493
|
+
listSandboxProviders?: SandboxProviderLister;
|
|
1734
2494
|
}
|
|
1735
2495
|
interface GatewayHandle {
|
|
1736
2496
|
url: string;
|
|
@@ -1774,4 +2534,4 @@ interface GatewayHandle {
|
|
|
1774
2534
|
*/
|
|
1775
2535
|
declare function createGateway(opts: CreateGatewayOptions): Promise<GatewayHandle>;
|
|
1776
2536
|
|
|
1777
|
-
export { type AdapterListEntry, type AgentAdapterLister, type AgentAdapterResolver, type AgentSessionLike, type AgentStreamEvent, type BrowserAdapterHandle, type BrowserAdapterInfo, type BrowserAdapterLister, type BrowserAdapterResolver, BuildHeartbeatAgent, type CreateGatewayOptions, DEFAULT_ORCHESTRATOR_TOOLS, type GatewayHandle, type InboundWatcher, type OrchestratorGatewayDeps, type OrchestratorInjection, type OrchestratorInjector, type OrchestratorInjectorDeps, type OrchestratorMcpServerFactory, type OrchestratorScope, type RegisterBrowserInput, type RegisterSessionInput, type RuntimeMeta, type ScopeTokenRegistry, type SessionDescriptor, type SessionKind, type SessionStatus, type SessionsRegistry, type SpawnAgentInput, type SpawnSessionInput, type TunnelDescriptor, type TunnelProvider, type TunnelStatus, type WatcherDescriptor, type WatcherStartInput, WorkspaceFs, createGateway, createOrchestratorInjector, createOrchestratorMcpServerFactory, createScopeTokenRegistry, daemonRegistryDir, makeBrowserAdapterLister, narrowOrchestratorTools, readDaemonRegistry, readRuntimeMeta, sweepStaleDaemonRegistry, sweepStaleRuntimeMetas, unlinkDaemonRegistryEntry, unlinkRuntimeMeta, writeDaemonRegistryEntry };
|
|
2537
|
+
export { type AdapterListEntry, type AgentAdapterLister, type AgentAdapterResolver, type AgentSessionLike, type AgentStreamEvent, type AttachPolicyInput, type BrowserAdapterHandle, type BrowserAdapterInfo, type BrowserAdapterLister, type BrowserAdapterResolver, BuildHeartbeatAgent, type CommitSpec, type CompletionPolicySupervisor, type CreateGatewayOptions, DEFAULT_ORCHESTRATOR_TOOLS, type DeclaredAdapterPreset, type GateSpec, type GatewayHandle, type InboundWatcher, type JudgeGateSpec, type McpCredentialDeps, type OnFailSpec, type OrchestratorGatewayDeps, type OrchestratorInjection, type OrchestratorInjector, type OrchestratorInjectorDeps, type OrchestratorMcpServerFactory, type OrchestratorScope, type PolicyRunState, type PolicyRunStatus, type PresetInfo, type PricingResolver, type RegisterBrowserInput, type RegisterSessionInput, type RuntimeMeta, type SandboxAdapterInfo, type SandboxProviderCapabilities, type SandboxProviderHandle, type SandboxProviderLister, type SandboxProviderResolver, type ScopeTokenRegistry, type SessionDescriptor, type SessionKind, type SessionObserver, type SessionStatus, type SessionUsage, type SessionWaitEvent, type SessionWaitResult, type SessionsRegistry, type ShellGateSpec, type SpawnAgentInput, type SpawnSessionInput, type TokenPricing, type TunnelDescriptor, type TunnelProvider, type TunnelStatus, type UsageComputeInput, type UsageSource, type WatcherDescriptor, type WatcherStartInput, WorkspaceFs, composeSessionObservers, createFileStepCache, createGateway, createOrchestratorInjector, createOrchestratorMcpServerFactory, createScopeTokenRegistry, daemonRegistryDir, declaredPresetToProviderPreset, deriveSessionUsage, formatToolCall, formatToolResult, getMcpCredentialDeps, listPresets, makeBrowserAdapterLister, monitorPolicyWait, monitorSessionWait, narrowOrchestratorTools, projectSessionUsage, readDaemonRegistry, readRuntimeMeta, setMcpCredentialDeps, sweepStaleDaemonRegistry, sweepStaleRuntimeMetas, unlinkDaemonRegistryEntry, unlinkRuntimeMeta, writeDaemonRegistryEntry };
|