@synadia-ai/agent-fabric 0.0.0-stage → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +33 -0
- package/LICENSE +201 -0
- package/README.md +288 -2
- package/THIRD_PARTY_NOTICES +23 -0
- package/dist/cli.cjs +681 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.js +679 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.cjs +5729 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +1778 -0
- package/dist/index.d.ts +1778 -0
- package/dist/index.js +5628 -0
- package/dist/index.js.map +1 -0
- package/examples/answer-questions.mjs +33 -0
- package/examples/ask.mjs +22 -0
- package/examples/every.mjs +28 -0
- package/examples/list-agents.mjs +21 -0
- package/examples/prompt.mjs +25 -0
- package/package.json +87 -4
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,1778 @@
|
|
|
1
|
+
import { RequestInterceptor, AgentServiceExtraEndpoint, AgentService } from '@synadia-ai/agent-service';
|
|
2
|
+
import { AgentId, PromptInterceptor, PromptOptions, QueryEvent, StreamMessage, PromptStream, Agents, Agent, Logger, AgentToolsExtension, SenderInfo, AgentToolsPromptContext, AgentToolsPromptRewrite, AgentToolsReplyContext, NatsConnectionSource } from '@synadia-ai/agents';
|
|
3
|
+
import { NatsConnection } from '@nats-io/nats-core';
|
|
4
|
+
|
|
5
|
+
declare const EDGE_RECORD_VERSION = 1;
|
|
6
|
+
/** Default subject edge records are published to — the tenant-side short
|
|
7
|
+
* form; the account's import qualifies it to `TRACE.{account}.edges`. */
|
|
8
|
+
declare const DEFAULT_EDGE_SUBJECT = "TRACE.edges";
|
|
9
|
+
/** The envelope fields that carry the lineage to the receiver. */
|
|
10
|
+
declare const THREAD_ID_FIELD = "thread_id";
|
|
11
|
+
declare const ROOT_ID_FIELD = "root_id";
|
|
12
|
+
/** The headers an agent stamps on its model requests (see {@link traceHeaders}). */
|
|
13
|
+
declare const THREAD_ID_HEADER = "X-Synadia-Thread-ID";
|
|
14
|
+
declare const ROOT_ID_HEADER = "X-Synadia-Root-ID";
|
|
15
|
+
/**
|
|
16
|
+
* Tracing configuration for {@link fabricTracing}; `{}` takes every
|
|
17
|
+
* default.
|
|
18
|
+
*/
|
|
19
|
+
interface TraceOptions {
|
|
20
|
+
/**
|
|
21
|
+
* Where edge records are published. `null` selects propagate-only mode
|
|
22
|
+
* — mint IDs and forward lineage, but publish no edge records.
|
|
23
|
+
*/
|
|
24
|
+
readonly edgeSubject?: string | null;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Throws {@link NatsAgentError} when `options.edgeSubject` names a subject
|
|
28
|
+
* that can never be published to: empty, an empty token, whitespace or
|
|
29
|
+
* NUL, or a wildcard. Publishing is fail-open, so without this check a
|
|
30
|
+
* misconfigured subject would only ever show up as a warning on every
|
|
31
|
+
* prompt; checking where the options are accepted makes it fail at
|
|
32
|
+
* construction instead.
|
|
33
|
+
*/
|
|
34
|
+
declare function assertValidTraceOptions(options: TraceOptions | undefined): void;
|
|
35
|
+
/**
|
|
36
|
+
* How many trace records this process has published and dropped so far —
|
|
37
|
+
* `edge` records today, counted from process start. Process-wide, not per
|
|
38
|
+
* client: the records are written by whichever client a prompt handler
|
|
39
|
+
* happens to use, while the agent service that owns the heartbeat is
|
|
40
|
+
* another object; one counter for the process is the one they share. The
|
|
41
|
+
* host reports both numbers as `records_published` and `records_dropped`
|
|
42
|
+
* in its heartbeat's extras (`fabricTracing().heartbeatExtras`), so
|
|
43
|
+
* whoever consumes the heartbeat knows how many records this process
|
|
44
|
+
* failed to publish.
|
|
45
|
+
*/
|
|
46
|
+
interface TraceRecordCounts {
|
|
47
|
+
/**
|
|
48
|
+
* Records handed to the connection for publishing. Handed, not
|
|
49
|
+
* delivered: a record lost after that — a reconnect buffer that
|
|
50
|
+
* overflowed, a process that exited before the flush — is not seen
|
|
51
|
+
* here. The counts cover what this process could observe; nothing past
|
|
52
|
+
* the connection is visible to them.
|
|
53
|
+
*/
|
|
54
|
+
readonly published: number;
|
|
55
|
+
/**
|
|
56
|
+
* Records that were due but never went out: no identity to sign them
|
|
57
|
+
* with, or a publish that threw. "Due" means the prompt the record
|
|
58
|
+
* describes actually went out — a prompt never iterated or rejected by
|
|
59
|
+
* validation owes no record and counts nothing. A record in
|
|
60
|
+
* propagate-only mode (`edgeSubject: null`) is never due either.
|
|
61
|
+
*/
|
|
62
|
+
readonly dropped: number;
|
|
63
|
+
}
|
|
64
|
+
/** Count one trace record published. Called by the edge publisher. */
|
|
65
|
+
declare function countTraceRecordPublished(): void;
|
|
66
|
+
/** Count one trace record dropped. Called by the edge publisher. */
|
|
67
|
+
declare function countTraceRecordDropped(): void;
|
|
68
|
+
/** A snapshot of the process-wide {@link TraceRecordCounts}. */
|
|
69
|
+
declare function traceRecordCounts(): TraceRecordCounts;
|
|
70
|
+
/** Identity of the prompt execution running in the current async context. */
|
|
71
|
+
interface TraceScope {
|
|
72
|
+
/** This execution's own thread ID — the parent of any thread it spawns. */
|
|
73
|
+
readonly threadId: string;
|
|
74
|
+
/** The tree's root thread ID, inherited unchanged; equals `threadId` on a root. */
|
|
75
|
+
readonly rootId: string;
|
|
76
|
+
/**
|
|
77
|
+
* Where in this execution any thread it spawns next was sent out: how
|
|
78
|
+
* many times it has stamped trace headers on a model request so far.
|
|
79
|
+
* Deliberately mutable and shared — work spawned inside the handler
|
|
80
|
+
* holds the same scope object, so its turns count against this
|
|
81
|
+
* execution.
|
|
82
|
+
*/
|
|
83
|
+
turnCountHint: number;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Run `fn` with `scope` as the ambient execution (what the host
|
|
87
|
+
* interceptor does around a prompt handler). AsyncLocalStorage restores
|
|
88
|
+
* the previous binding on exit, so nothing leaks into the next request.
|
|
89
|
+
*/
|
|
90
|
+
declare function bindActiveTrace<T>(scope: TraceScope, fn: () => T): T;
|
|
91
|
+
/** The ambient {@link TraceScope}, or `undefined` outside a bound handler. */
|
|
92
|
+
declare function activeTrace(): TraceScope | undefined;
|
|
93
|
+
/**
|
|
94
|
+
* Headers for every model request this execution issues.
|
|
95
|
+
*
|
|
96
|
+
* An agent stamps these on each completion request so the model proxy
|
|
97
|
+
* files the call under the right thread and tree without seeing any NATS
|
|
98
|
+
* traffic. Hierarchy is the edge records' job, so the proxy needs no
|
|
99
|
+
* parent or tool-call header.
|
|
100
|
+
*
|
|
101
|
+
* `{}` outside a traced handler, so harness code needs no plumbing and
|
|
102
|
+
* degrades to nothing.
|
|
103
|
+
*
|
|
104
|
+
* Each call counts against this execution: the running total is recorded
|
|
105
|
+
* on the edge of any thread it spawns afterwards.
|
|
106
|
+
*/
|
|
107
|
+
declare function traceHeaders(): Record<string, string>;
|
|
108
|
+
/** Length in hex characters of a thread ID — 128 bits. */
|
|
109
|
+
declare const THREAD_ID_HEX_LEN = 32;
|
|
110
|
+
/**
|
|
111
|
+
* `true` iff `value` has the shape of a thread ID: exactly
|
|
112
|
+
* {@link THREAD_ID_HEX_LEN} lowercase hex characters. Ids arriving on the
|
|
113
|
+
* wire are untrusted input that ends up in the headers an agent stamps on
|
|
114
|
+
* its model requests, so a receiver adopts nothing that is not shaped
|
|
115
|
+
* exactly like what the packages mint.
|
|
116
|
+
*/
|
|
117
|
+
declare function isThreadId(value: string): boolean;
|
|
118
|
+
declare function randomThreadId(): string;
|
|
119
|
+
/** Longest accepted tool call id, in Unicode code points. */
|
|
120
|
+
declare const TOOL_CALL_ID_MAX = 256;
|
|
121
|
+
declare function validToolCallId(toolCallId: string): boolean;
|
|
122
|
+
/** One built edge record: its wire bytes and the id that de-duplicates it. */
|
|
123
|
+
interface BuiltEdgeRecord {
|
|
124
|
+
readonly recordId: string;
|
|
125
|
+
readonly payload: Uint8Array;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* One edge record, ready to publish. The record id comes back alongside
|
|
129
|
+
* the payload: the publisher signs with it as the `Agent-Sender` nonce,
|
|
130
|
+
* which the SDK's signed publish also stamps as `Nats-Msg-Id`, so body,
|
|
131
|
+
* header and message id carry one id and a stream de-duplicates a record
|
|
132
|
+
* it already stored. Its 32 hex characters fit the nonce's
|
|
133
|
+
* `[A-Za-z0-9_-]{1,64}`.
|
|
134
|
+
*
|
|
135
|
+
* `agent` is the writer — the caller that spawned the thread, the parent
|
|
136
|
+
* side of the edge — in canonical `{account}.{user}` form. It is the same
|
|
137
|
+
* identity that signs the record's `Agent-Sender` header, so a consumer
|
|
138
|
+
* can cross-check the body against the verified header.
|
|
139
|
+
*/
|
|
140
|
+
declare function buildEdgeRecord(agent: AgentId, threadId: string, parentId: string | null, rootId: string, toolCallId: string | null, turnCountHint: number): BuiltEdgeRecord;
|
|
141
|
+
|
|
142
|
+
/** The key of `PromptOptions.context` the caller interceptor reads the tool call ID from. */
|
|
143
|
+
declare const TOOL_CALL_ID_CONTEXT_KEY = "toolCallId";
|
|
144
|
+
/** What {@link fabricTracing} returns: the SDK's three hooks, ready to pass in. */
|
|
145
|
+
interface FabricTracing {
|
|
146
|
+
/** For the caller: `new Agents({ ..., interceptors: [tracing.promptInterceptor] })`. */
|
|
147
|
+
readonly promptInterceptor: PromptInterceptor;
|
|
148
|
+
/** For the host: `new AgentService({ ..., interceptors: [tracing.requestInterceptor] })`. */
|
|
149
|
+
readonly requestInterceptor: RequestInterceptor;
|
|
150
|
+
/**
|
|
151
|
+
* For the host: `new AgentService({ ..., heartbeatExtras: tracing.heartbeatExtras })`.
|
|
152
|
+
* `records_published` and `records_dropped` — the process-wide
|
|
153
|
+
* {@link traceRecordCounts} — read fresh for every heartbeat and status
|
|
154
|
+
* reply. `{}` in propagate-only mode, which publishes no records and
|
|
155
|
+
* would otherwise report a constant 0/0 that looks like a healthy zero.
|
|
156
|
+
*/
|
|
157
|
+
readonly heartbeatExtras: () => Readonly<Record<string, unknown>>;
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Tracing for an agent on the fabric, as the protocol SDK's hooks.
|
|
161
|
+
*
|
|
162
|
+
* Throws `NatsAgentError` for an `edgeSubject` that can never be published
|
|
163
|
+
* to (see {@link assertValidTraceOptions}). `options.edgeSubject` defaults
|
|
164
|
+
* to {@link DEFAULT_EDGE_SUBJECT}; `null` is propagate-only mode.
|
|
165
|
+
*/
|
|
166
|
+
declare function fabricTracing(options?: TraceOptions): FabricTracing;
|
|
167
|
+
|
|
168
|
+
/** The inbox prefix a caller's permissions allow it to receive on. */
|
|
169
|
+
declare const CALLER_INBOX_PREFIX = "_INBOX.agents";
|
|
170
|
+
/** What `ask()` replies to a question from the agent when no `onQuery` is given. */
|
|
171
|
+
declare const CANNOT_ANSWER = "The caller is a command line and cannot answer; continue with your best judgement.";
|
|
172
|
+
/** How long `list()` and `find()` listen for agents, by default. */
|
|
173
|
+
declare const DEFAULT_DISCOVER_TIMEOUT_MS = 1000;
|
|
174
|
+
/** The variables {@link fabricCallerFromEnv} reads. */
|
|
175
|
+
declare const NATS_URL_VAR = "NATS_URL";
|
|
176
|
+
declare const NATS_CREDS_VAR = "NATS_CREDS";
|
|
177
|
+
/**
|
|
178
|
+
* Why a caller could not be set up, could not find its agent, or has no
|
|
179
|
+
* root for a prompt: `config` (a missing or invalid setting), `connect`
|
|
180
|
+
* (no connection), `identity` (the server would not say who the creds
|
|
181
|
+
* file is), `not-found`, `ambiguous`, `not-sent` (the prompt ended before
|
|
182
|
+
* it went out, so it has no root).
|
|
183
|
+
*/
|
|
184
|
+
type FabricCallerErrorReason = "config" | "connect" | "identity" | "not-found" | "ambiguous" | "not-sent";
|
|
185
|
+
/** A caller's own error: a missing setting, no connection, no identity, or no such agent. */
|
|
186
|
+
declare class FabricCallerError extends Error {
|
|
187
|
+
readonly reason: FabricCallerErrorReason;
|
|
188
|
+
constructor(reason: FabricCallerErrorReason, message: string);
|
|
189
|
+
}
|
|
190
|
+
interface FabricCallerOptions {
|
|
191
|
+
/** The path to the creds file. */
|
|
192
|
+
readonly creds: string;
|
|
193
|
+
/**
|
|
194
|
+
* The server's URL, as the console showed it next to the creds file.
|
|
195
|
+
* Default: `NATS_URL`. There is no built-in default.
|
|
196
|
+
*/
|
|
197
|
+
readonly url?: string;
|
|
198
|
+
/** The client's name, on the connection and in its identity. */
|
|
199
|
+
readonly name?: string;
|
|
200
|
+
/** Where the edge records go; `null` publishes none. Default: tracing's. */
|
|
201
|
+
readonly edgeSubject?: TraceOptions["edgeSubject"];
|
|
202
|
+
}
|
|
203
|
+
/** A prompt on its way: its stream, and the root of the task it starts. */
|
|
204
|
+
interface CallerPrompt {
|
|
205
|
+
/** The SDK's `PromptStream`, passed through: iterate it for the reply. */
|
|
206
|
+
readonly stream: CallerStream;
|
|
207
|
+
/**
|
|
208
|
+
* The root id of the task the prompt starts. Resolves at the stream's
|
|
209
|
+
* first iteration, before any chunk arrives; await it after iteration
|
|
210
|
+
* has begun, never before. Rejects with a {@link FabricCallerError}
|
|
211
|
+
* (`not-sent`), or the stream's own error, when the prompt ends before
|
|
212
|
+
* it goes out: cancelled, refused before it was sent, or failed.
|
|
213
|
+
*/
|
|
214
|
+
readonly rootId: Promise<string>;
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* The SDK's `PromptStream`, with the prompt's root settled when iteration
|
|
218
|
+
* ends or fails before the prompt went out. The messages are the SDK's,
|
|
219
|
+
* unchanged.
|
|
220
|
+
*/
|
|
221
|
+
declare class CallerStream implements AsyncIterable<StreamMessage> {
|
|
222
|
+
#private;
|
|
223
|
+
constructor(inner: PromptStream, sink: RootSink);
|
|
224
|
+
/** The subject the prompt is published to. */
|
|
225
|
+
get subject(): string;
|
|
226
|
+
/** Stop the stream, as `PromptStream.cancel()`. */
|
|
227
|
+
cancel(): void;
|
|
228
|
+
[Symbol.asyncIterator](): AsyncIterator<StreamMessage>;
|
|
229
|
+
}
|
|
230
|
+
interface AskOptions extends PromptOptions {
|
|
231
|
+
/**
|
|
232
|
+
* Answers a question the agent asks mid-reply. Without it, or when it
|
|
233
|
+
* answers with nothing but whitespace, the agent is told the caller
|
|
234
|
+
* cannot answer and goes on.
|
|
235
|
+
*/
|
|
236
|
+
readonly onQuery?: (query: QueryEvent) => string | Promise<string>;
|
|
237
|
+
}
|
|
238
|
+
/** The whole reply to a prompt, and the root of the task it started. */
|
|
239
|
+
interface CallerReply {
|
|
240
|
+
readonly text: string;
|
|
241
|
+
readonly rootId: string;
|
|
242
|
+
}
|
|
243
|
+
interface FabricCaller {
|
|
244
|
+
/** The SDK's client, for anything beyond. */
|
|
245
|
+
readonly agents: Agents;
|
|
246
|
+
/** The URL the caller connected to. */
|
|
247
|
+
readonly url: string;
|
|
248
|
+
/** The agents on the fabric. */
|
|
249
|
+
list(opts?: {
|
|
250
|
+
readonly timeoutMs?: number;
|
|
251
|
+
}): Promise<Agent[]>;
|
|
252
|
+
/**
|
|
253
|
+
* One agent: by its prompt address, else by its kind when exactly one
|
|
254
|
+
* agent has it. Throws {@link FabricCallerError} naming what is there.
|
|
255
|
+
*/
|
|
256
|
+
find(who: string, opts?: {
|
|
257
|
+
readonly timeoutMs?: number;
|
|
258
|
+
}): Promise<Agent>;
|
|
259
|
+
/**
|
|
260
|
+
* Prompt an agent: an address, a kind, or an `Agent` this caller's
|
|
261
|
+
* `list()` or `find()` returned.
|
|
262
|
+
*/
|
|
263
|
+
prompt(who: string | Agent, text: string, options?: PromptOptions): Promise<CallerPrompt>;
|
|
264
|
+
/** Prompt an agent and wait for the whole reply. */
|
|
265
|
+
ask(who: string | Agent, text: string, options?: AskOptions): Promise<CallerReply>;
|
|
266
|
+
/** Close the client and the connection, then wipe the credentials. */
|
|
267
|
+
close(): Promise<void>;
|
|
268
|
+
}
|
|
269
|
+
/** Settles a prompt's root once: the first call wins. Internal. */
|
|
270
|
+
interface RootSink {
|
|
271
|
+
resolve(rootId: string): void;
|
|
272
|
+
reject(err: unknown): void;
|
|
273
|
+
}
|
|
274
|
+
/** Connect a caller with a creds file. */
|
|
275
|
+
declare function fabricCaller(options: FabricCallerOptions): Promise<FabricCaller>;
|
|
276
|
+
/** {@link fabricCaller} from `NATS_URL` and `NATS_CREDS`. */
|
|
277
|
+
declare function fabricCallerFromEnv(options?: Omit<FabricCallerOptions, "creds" | "url">): Promise<FabricCaller>;
|
|
278
|
+
/**
|
|
279
|
+
* The rule {@link FabricCaller.find} applies: the agent whose prompt address
|
|
280
|
+
* is `who`, else the one agent of kind `who`; otherwise an error that names
|
|
281
|
+
* what is there.
|
|
282
|
+
*/
|
|
283
|
+
declare function pickAgent(found: ReadonlyArray<Agent>, who: string): Agent;
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* The served prompt's trace as a run's input carries it, in this key
|
|
287
|
+
* order. Wire form: the same keys and order in both packages.
|
|
288
|
+
*/
|
|
289
|
+
interface DurableTrace {
|
|
290
|
+
readonly thread_id: string;
|
|
291
|
+
readonly root_id: string;
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* The run id that joins a durable run to the task that started it:
|
|
295
|
+
* `<thread_id>-<tool call id>`, the active trace's thread and the model's
|
|
296
|
+
* tool-call id, with every character of the tool-call id outside
|
|
297
|
+
* `[A-Za-z0-9_-]` replaced by `_`. Pass it as the run id when the run is
|
|
298
|
+
* started; the run's children and generations keep it as their prefix.
|
|
299
|
+
*
|
|
300
|
+
* `undefined` outside a traced prompt handler: there is no served thread to
|
|
301
|
+
* name. Pick a run id of your own then; that run joins no task.
|
|
302
|
+
*
|
|
303
|
+
* Throws {@link NatsAgentError} when the tool-call id is empty, longer than
|
|
304
|
+
* the trace accepts (`TOOL_CALL_ID_MAX` code points) or not valid Unicode.
|
|
305
|
+
*/
|
|
306
|
+
declare function durableRunId(toolCallId: string): string | undefined;
|
|
307
|
+
/**
|
|
308
|
+
* The active trace as `{ thread_id, root_id }`, for the run's input under a
|
|
309
|
+
* key of your choosing; {@link durableHeaders} turns it back into the
|
|
310
|
+
* proxy's headers inside a step. `undefined` outside a traced prompt
|
|
311
|
+
* handler.
|
|
312
|
+
*
|
|
313
|
+
* Unlike `traceHeaders()`, it counts no model turn: it starts no model call.
|
|
314
|
+
*/
|
|
315
|
+
declare function durableTrace(): DurableTrace | undefined;
|
|
316
|
+
/**
|
|
317
|
+
* The two headers the model proxy reads, `X-Synadia-Thread-ID` and
|
|
318
|
+
* `X-Synadia-Root-ID`, from a trace a run's input carries, for a model call
|
|
319
|
+
* inside a step. The call then lands on the thread that started the run.
|
|
320
|
+
*
|
|
321
|
+
* The input is read back from the run's journal, so it is checked as
|
|
322
|
+
* untrusted: `{}` unless both ids have the shape of a thread id. `{}` for
|
|
323
|
+
* `undefined` or `null` as well, so a run started outside a traced handler
|
|
324
|
+
* makes its model calls without the headers.
|
|
325
|
+
*/
|
|
326
|
+
declare function durableHeaders(trace: DurableTrace | null | undefined): Record<string, string>;
|
|
327
|
+
/**
|
|
328
|
+
* Run `fn` inside the trace a run's input carries, as the prompt's handler
|
|
329
|
+
* ran inside it: a prompt sent to another agent from `fn` writes its edge
|
|
330
|
+
* under the thread that started the run, in the same tree, and
|
|
331
|
+
* `traceHeaders()` inside `fn` gives the same two headers as
|
|
332
|
+
* {@link durableHeaders}. For a step of a durable run, which a worker runs
|
|
333
|
+
* outside the prompt's async scope.
|
|
334
|
+
*
|
|
335
|
+
* `turnCount` is how many model calls the run has made so far; it becomes
|
|
336
|
+
* the turn count hint of any edge `fn` writes. A `traceHeaders()` call
|
|
337
|
+
* inside `fn` counts one more, as it does in a handler.
|
|
338
|
+
*
|
|
339
|
+
* A trace that is missing or not shaped like thread ids binds nothing: `fn`
|
|
340
|
+
* runs as it would outside a traced handler. Throws {@link NatsAgentError}
|
|
341
|
+
* when `turnCount` is not a whole number, 0 or more.
|
|
342
|
+
*/
|
|
343
|
+
declare function withDurableTrace<T>(trace: DurableTrace | null | undefined, turnCount: number, fn: () => T): T;
|
|
344
|
+
|
|
345
|
+
declare const SERVED_RECORD_VERSION = 1;
|
|
346
|
+
/**
|
|
347
|
+
* The version of a record that carries a `reason`: the schema's version 2
|
|
348
|
+
* added the field. A record without one stays version 1, byte for byte what
|
|
349
|
+
* it was.
|
|
350
|
+
*/
|
|
351
|
+
declare const SERVED_RECORD_REASON_VERSION = 2;
|
|
352
|
+
/**
|
|
353
|
+
* The harnesses whose plugins write `served` records: the ones that cannot
|
|
354
|
+
* put the fabric's headers on their own model calls. PI can, and writes
|
|
355
|
+
* none. The value is what the proxy files the harness's calls under
|
|
356
|
+
* (the fabric's design, §8.1).
|
|
357
|
+
*/
|
|
358
|
+
type Harness = "claude" | "openclaw";
|
|
359
|
+
/** `start` when the prompt arrives, `end` when the turn is over. */
|
|
360
|
+
type ServedPhase = "start" | "end";
|
|
361
|
+
/** How the turn ended: answered, failed, or expired on the request's TTL. */
|
|
362
|
+
type ServedStatus = "ok" | "error" | "timeout";
|
|
363
|
+
/**
|
|
364
|
+
* How a prompt ended when the model did not end it with its own reply, on
|
|
365
|
+
* `end` only; absent when the model replied. `final_text`: the plugin sent
|
|
366
|
+
* the turn's final text as the reply (status `ok`); `no_reply`: the turn
|
|
367
|
+
* ended with no reply and no final text; `shutdown`: the plugin stopped
|
|
368
|
+
* with the prompt open; `delivery`: the prompt could not be handed to the
|
|
369
|
+
* harness; `expired`: the prompt outlived the plugin's limit (status
|
|
370
|
+
* `timeout`).
|
|
371
|
+
*/
|
|
372
|
+
type ServedReason = "final_text" | "no_reply" | "shutdown" | "delivery" | "expired";
|
|
373
|
+
/** Longest accepted harness thread id, in Unicode code points. */
|
|
374
|
+
declare const HARNESS_THREAD_ID_MAX = 256;
|
|
375
|
+
/**
|
|
376
|
+
* `true` iff `value` can be the harness thread id a served record names:
|
|
377
|
+
* a non-empty string of at most {@link HARNESS_THREAD_ID_MAX} code points
|
|
378
|
+
* — counted as the Python package's `len()` counts, not in UTF-16 units —
|
|
379
|
+
* with no whitespace or control character (the class the SDK holds a
|
|
380
|
+
* subject token to: the id is matched against a header value the proxy
|
|
381
|
+
* saw, and a header value can never hold those) and no lone surrogate,
|
|
382
|
+
* which has no UTF-8 form. Claude Code's session id and OpenClaw's 32-hex
|
|
383
|
+
* trace id pass; the packages accept exactly the same ids.
|
|
384
|
+
*/
|
|
385
|
+
declare function validHarnessThreadId(value: unknown): value is string;
|
|
386
|
+
/** Now, in unix seconds — the served record's `ts` resolution. */
|
|
387
|
+
declare function unixSeconds(): number;
|
|
388
|
+
/** One built served record: its wire bytes and the id that de-duplicates it. */
|
|
389
|
+
interface BuiltServedRecord {
|
|
390
|
+
readonly recordId: string;
|
|
391
|
+
readonly payload: Uint8Array;
|
|
392
|
+
}
|
|
393
|
+
/**
|
|
394
|
+
* One served record, ready to publish. The record id comes back alongside
|
|
395
|
+
* the payload: the publisher signs with it as the `Agent-Sender` nonce,
|
|
396
|
+
* which the SDK's signed publish also stamps as `Nats-Msg-Id`, so body,
|
|
397
|
+
* header and message id carry one id and a stream de-duplicates a record
|
|
398
|
+
* it already stored. Its 32 hex characters fit the nonce's
|
|
399
|
+
* `[A-Za-z0-9_-]{1,64}`.
|
|
400
|
+
*
|
|
401
|
+
* `agent` is the plugin's own identity, the executing agent, in canonical
|
|
402
|
+
* `{account}.{user}` form — the same identity that signs the record.
|
|
403
|
+
* `threadId` and `rootId` are the served prompt's, from its scope.
|
|
404
|
+
* `harnessThreadId` is the harness's own id, bare — never prefixed — and
|
|
405
|
+
* must pass {@link validHarnessThreadId}. `status` is required on `end`
|
|
406
|
+
* and must be absent on `start`. `ts` is unix seconds: when the prompt
|
|
407
|
+
* arrived for `start`, when the turn ended for `end`; now by default.
|
|
408
|
+
* `reason` ({@link ServedReason}) says how an `end` came about when the
|
|
409
|
+
* model did not reply itself; it is refused on `start`, like `status`, and
|
|
410
|
+
* a record that carries it is version {@link SERVED_RECORD_REASON_VERSION}.
|
|
411
|
+
*
|
|
412
|
+
* Throws `Error` for a record the contract would refuse, so a plugin's
|
|
413
|
+
* mistake is its own and never a malformed record on the wire.
|
|
414
|
+
*/
|
|
415
|
+
declare function buildServedRecord(agent: AgentId, threadId: string, rootId: string, harness: Harness, harnessThreadId: string, phase: ServedPhase, status?: ServedStatus, ts?: number, reason?: ServedReason): BuiltServedRecord;
|
|
416
|
+
interface ServedPublisherOptions {
|
|
417
|
+
/**
|
|
418
|
+
* The plugin's own client: it signs every record as its identity, which
|
|
419
|
+
* is also the record's `agent`. Without a signer nothing is published —
|
|
420
|
+
* an unsigned record cannot be attributed — the publisher warns once and
|
|
421
|
+
* each record owed counts as dropped.
|
|
422
|
+
*/
|
|
423
|
+
readonly agents: Agents;
|
|
424
|
+
/**
|
|
425
|
+
* Where the records go: the edge subject, the same the plugin's tracing
|
|
426
|
+
* runs with. {@link DEFAULT_EDGE_SUBJECT} by default.
|
|
427
|
+
*/
|
|
428
|
+
readonly subject?: string;
|
|
429
|
+
/** Where a refused binding or a failed publish is reported; the console by default. */
|
|
430
|
+
readonly logger?: Logger;
|
|
431
|
+
}
|
|
432
|
+
/**
|
|
433
|
+
* One prompt's served pair. `bind` names the harness thread id once and
|
|
434
|
+
* publishes `start`, stamped with the prompt's arrival — the moment
|
|
435
|
+
* {@link ServedPublisher.beginTurn} was called — however late the id
|
|
436
|
+
* becomes known; `settle` records the outcome when the turn ends and
|
|
437
|
+
* publishes `end` if the id is known. An id bound after settling is
|
|
438
|
+
* refused: the pair is the turn's window, not something to backfill. Both
|
|
439
|
+
* are synchronous and return at once; the records go out behind them.
|
|
440
|
+
*/
|
|
441
|
+
interface ServedTurn {
|
|
442
|
+
/**
|
|
443
|
+
* The harness's own id for this prompt's turn, bare. An unusable id
|
|
444
|
+
* (see {@link validHarnessThreadId}) is refused with a warning and the
|
|
445
|
+
* prompt gets no pair; a second binding is ignored, with a warning when
|
|
446
|
+
* it names another id.
|
|
447
|
+
*/
|
|
448
|
+
bind(harnessThreadId: string): void;
|
|
449
|
+
/**
|
|
450
|
+
* End the turn. `atMs` is the turn's end in milliseconds since the epoch,
|
|
451
|
+
* as the plugin's events report it; now by default. `reason` is how the
|
|
452
|
+
* prompt ended when the model did not reply itself ({@link ServedReason}),
|
|
453
|
+
* carried on `end`. A second call does nothing.
|
|
454
|
+
*/
|
|
455
|
+
settle(status: ServedStatus, atMs?: number, reason?: ServedReason): void;
|
|
456
|
+
}
|
|
457
|
+
/**
|
|
458
|
+
* Publishes served records through the plugin's client, one after another
|
|
459
|
+
* in the order they were due, so a pair's `end` never overtakes its
|
|
460
|
+
* `start` on the wire and two prompts' pairs interleave as they happened.
|
|
461
|
+
* See {@link servedPublisher}.
|
|
462
|
+
*/
|
|
463
|
+
declare class ServedPublisher {
|
|
464
|
+
#private;
|
|
465
|
+
constructor(options: ServedPublisherOptions);
|
|
466
|
+
/** Where the records go. */
|
|
467
|
+
get subject(): string;
|
|
468
|
+
/**
|
|
469
|
+
* Start a prompt's pair: `scope` is the served prompt's trace scope —
|
|
470
|
+
* the one the fabric's request interceptor bound around the handler,
|
|
471
|
+
* `activeTrace()` inside it — and `harness` the one whose id `bind` will
|
|
472
|
+
* name. The arrival, `start`'s `ts`, is now.
|
|
473
|
+
*/
|
|
474
|
+
beginTurn(scope: TraceScope, harness: Harness): ServedTurn;
|
|
475
|
+
/**
|
|
476
|
+
* Publish one signed record, after every record handed over before it.
|
|
477
|
+
* Fail-open and asynchronous: the returned promise never rejects and
|
|
478
|
+
* nothing awaits it on the prompt path. A record that cannot go out — no
|
|
479
|
+
* signer, a client already closed, a publish that threw — is logged and
|
|
480
|
+
* counts as dropped; one that went out counts as published. Every record
|
|
481
|
+
* moves the process-wide {@link traceRecordCounts}.
|
|
482
|
+
*/
|
|
483
|
+
publish(scope: TraceScope, harness: Harness, harnessThreadId: string, phase: ServedPhase, status: ServedStatus | undefined, ts: number, reason?: ServedReason): Promise<void>;
|
|
484
|
+
/**
|
|
485
|
+
* Resolves once every record handed to `publish` so far has been signed
|
|
486
|
+
* and handed to the connection, or dropped. For shutdown and tests.
|
|
487
|
+
*/
|
|
488
|
+
flush(): Promise<void>;
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* The served records' publisher for a harness plugin's add-on, over the
|
|
492
|
+
* plugin's own client: `agents.publishSigned` with the record id as nonce,
|
|
493
|
+
* on `subject` ({@link DEFAULT_EDGE_SUBJECT} by default), the records in
|
|
494
|
+
* the order they were due, every one counted on the process-wide
|
|
495
|
+
* {@link traceRecordCounts}. Per served prompt the add-on calls
|
|
496
|
+
* {@link ServedPublisher.beginTurn} with the prompt's scope, `bind`s the
|
|
497
|
+
* harness's id once it knows it, and `settle`s with the outcome;
|
|
498
|
+
* {@link ServedPublisher.flush} before the plugin stops.
|
|
499
|
+
*/
|
|
500
|
+
declare function servedPublisher(options: ServedPublisherOptions): ServedPublisher;
|
|
501
|
+
|
|
502
|
+
/** Prefix of the expanded reference token. */
|
|
503
|
+
declare const REFERENCE_PREFIX = "sp-ref:";
|
|
504
|
+
declare const SHORT_REFERENCE_PREFIX = "sp-r1:";
|
|
505
|
+
/**
|
|
506
|
+
* The service metadata key an agent that reads the references it is handed
|
|
507
|
+
* registers, with the value `"true"` (the SDK's `extraMetadata`). A caller
|
|
508
|
+
* hands a reference, and grants read on it, only to an agent that says so.
|
|
509
|
+
* In the style of the protocol's `attachments_ok`.
|
|
510
|
+
*/
|
|
511
|
+
declare const READS_REFERENCES_KEY = "scratchpad_refs_ok";
|
|
512
|
+
/** The served prompt's thread and root, as `activeTrace()` reports them. */
|
|
513
|
+
interface TraceIds {
|
|
514
|
+
readonly threadId: string;
|
|
515
|
+
readonly rootId: string;
|
|
516
|
+
}
|
|
517
|
+
/**
|
|
518
|
+
* The principal ScratchPad grants to: the two halves of an agent identity,
|
|
519
|
+
* `<account>.<user>`, both public NKEYs on the fabric.
|
|
520
|
+
*/
|
|
521
|
+
interface Grantee {
|
|
522
|
+
readonly account: string;
|
|
523
|
+
readonly user: string;
|
|
524
|
+
}
|
|
525
|
+
/**
|
|
526
|
+
* How a grant came about. `first-hand`: the agent granted an agent it
|
|
527
|
+
* handed the reference itself — the verified caller of its reply, or the
|
|
528
|
+
* agent it prompted with a reference of its own. `on-request`: the agent
|
|
529
|
+
* granted an agent because another agent asked it to (`grant-request.ts`).
|
|
530
|
+
* Only a first-hand grant entitles its holder to ask for another agent, or
|
|
531
|
+
* access could be relayed from agent to agent without end.
|
|
532
|
+
*/
|
|
533
|
+
type GrantKind = "first-hand" | "on-request";
|
|
534
|
+
type MaybePromise<T> = T | Promise<T>;
|
|
535
|
+
/**
|
|
536
|
+
* What the policy needs of the agent's ScratchPad: its own volume, and a
|
|
537
|
+
* ledger of the read grants it made. ScratchPad knows the grants but not
|
|
538
|
+
* how they came about; that is the agent's own knowledge, so the
|
|
539
|
+
* implementation keeps the ledger.
|
|
540
|
+
*/
|
|
541
|
+
interface ScratchPad {
|
|
542
|
+
/** Resolve reference metadata through the implementation's authenticated client. */
|
|
543
|
+
resolveReference?(reference: string, trace?: TraceIds): MaybePromise<{
|
|
544
|
+
readonly creator: string;
|
|
545
|
+
}>;
|
|
546
|
+
/** Whether `reference` points into this agent's own volume, where it may grant. */
|
|
547
|
+
owns(reference: string): MaybePromise<boolean>;
|
|
548
|
+
/**
|
|
549
|
+
* Grant `grantee` read on the one path `reference` names, until the
|
|
550
|
+
* grant's expiry, and note it in the ledger as `kind` (`first-hand` when
|
|
551
|
+
* not given). Only for a reference into this agent's own volume. `trace`
|
|
552
|
+
* and `toolCallId` label the grant, so it shows under the served prompt
|
|
553
|
+
* and the tool call that caused it.
|
|
554
|
+
*/
|
|
555
|
+
grantRead(reference: string, grantee: Grantee, trace: TraceIds | undefined, toolCallId?: string, kind?: GrantKind): MaybePromise<void>;
|
|
556
|
+
/**
|
|
557
|
+
* The live grant this agent made to `grantee` on what `reference` points
|
|
558
|
+
* at, by kind; `undefined` when there is none or it has expired. A
|
|
559
|
+
* first-hand grant still running is not hidden by a later one made on
|
|
560
|
+
* request.
|
|
561
|
+
*/
|
|
562
|
+
granted(reference: string, grantee: Grantee): MaybePromise<GrantKind | undefined>;
|
|
563
|
+
}
|
|
564
|
+
/** Every reference token in `text`, in order, repeats included. */
|
|
565
|
+
declare function findReferences(text: string): string[];
|
|
566
|
+
/**
|
|
567
|
+
* `text` with reference tokens taken out — every one, or only those in
|
|
568
|
+
* `only` — and the trailing spaces and extra blank lines that leaves
|
|
569
|
+
* behind tidied away.
|
|
570
|
+
*/
|
|
571
|
+
declare function removeReferences(text: string, only?: ReadonlyArray<string>): string;
|
|
572
|
+
/**
|
|
573
|
+
* The prompt address of the agent that made `reference`, as the token says;
|
|
574
|
+
* `undefined` for a token that names none or does not decode.
|
|
575
|
+
*/
|
|
576
|
+
declare function referenceCreator(reference: string): string | undefined;
|
|
577
|
+
/** Whether an agent's registration metadata says it reads references. */
|
|
578
|
+
declare function readsReferences(metadata: Readonly<Record<string, string>>): boolean;
|
|
579
|
+
/**
|
|
580
|
+
* The grantee behind an identity as discovery or a verified sender reports
|
|
581
|
+
* it. Throws for anything that is not `<account>.<user>`.
|
|
582
|
+
*/
|
|
583
|
+
declare function granteeFromIdentity(identity: string): Grantee;
|
|
584
|
+
|
|
585
|
+
/** What the requester sends (`sp-grant-request.json`). */
|
|
586
|
+
interface GrantRequest {
|
|
587
|
+
/** The reference, exactly as the requester was given it. */
|
|
588
|
+
readonly reference: string;
|
|
589
|
+
/** The identity, `<account>.<user>`, of the agent that should be able to read it. */
|
|
590
|
+
readonly grantee: string;
|
|
591
|
+
/**
|
|
592
|
+
* The requester's served thread and the tool call the handoff belongs to,
|
|
593
|
+
* so the creator's grant shows under the call that caused it. Labels
|
|
594
|
+
* only, never authority.
|
|
595
|
+
*/
|
|
596
|
+
readonly trace?: {
|
|
597
|
+
readonly thread_id: string;
|
|
598
|
+
readonly root_id: string;
|
|
599
|
+
readonly tool_call_id?: string;
|
|
600
|
+
};
|
|
601
|
+
}
|
|
602
|
+
/** What the creator answers (`sp-grant-reply.json`). */
|
|
603
|
+
type GrantReply = {
|
|
604
|
+
readonly granted: true;
|
|
605
|
+
} | {
|
|
606
|
+
readonly granted: false;
|
|
607
|
+
readonly reason: string;
|
|
608
|
+
};
|
|
609
|
+
/** The name of the creator's extra endpoint, and the verb of its subject. */
|
|
610
|
+
declare const GRANT_REQUEST_ENDPOINT = "sp-grant";
|
|
611
|
+
/**
|
|
612
|
+
* How long the requester waits for the creator's answer. The creator runs
|
|
613
|
+
* one ScratchPad operation before it answers, so longer than the SDK's two
|
|
614
|
+
* seconds for a signed request.
|
|
615
|
+
*/
|
|
616
|
+
declare const DEFAULT_GRANT_REQUEST_TIMEOUT_MS = 10000;
|
|
617
|
+
/**
|
|
618
|
+
* Where the agent at `promptAddress` takes grant requests: the same subject
|
|
619
|
+
* with the verb changed. Derived, never taken from what another agent says,
|
|
620
|
+
* so a request only ever goes to the creator's own subject. Throws for a
|
|
621
|
+
* subject that is not a prompt address.
|
|
622
|
+
*/
|
|
623
|
+
declare function grantSubject(promptAddress: string): string;
|
|
624
|
+
/** A request's bytes, as both packages write them: the schema's key order. */
|
|
625
|
+
declare function encodeGrantRequest(request: GrantRequest): string;
|
|
626
|
+
/** A reply's bytes, as both packages write them. */
|
|
627
|
+
declare function encodeGrantReply(reply: GrantReply): string;
|
|
628
|
+
interface RequestGrantOptions {
|
|
629
|
+
/** How long to wait for the answer. Default {@link DEFAULT_GRANT_REQUEST_TIMEOUT_MS}. */
|
|
630
|
+
readonly timeoutMs?: number;
|
|
631
|
+
}
|
|
632
|
+
/**
|
|
633
|
+
* The requester's side: ask the agent at `creatorAddress` to grant what
|
|
634
|
+
* `request` names, signed as `agents`' identity. Never throws: no answer,
|
|
635
|
+
* or an answer that is not a grant, is a refusal with its reason in words.
|
|
636
|
+
*/
|
|
637
|
+
declare function requestGrant(agents: Agents, creatorAddress: string, request: GrantRequest, options?: RequestGrantOptions): Promise<GrantReply>;
|
|
638
|
+
/**
|
|
639
|
+
* The creator's rule, for a requester whose signature verified. `requester`
|
|
640
|
+
* is that verified sender ID; `payload` the request's body. Never throws.
|
|
641
|
+
* {@link grantRequestEndpoint} runs it after the SDK's `SenderGate`; a host
|
|
642
|
+
* that takes grant requests some other way must verify the sender first.
|
|
643
|
+
*/
|
|
644
|
+
declare function answerGrantRequest(requester: string, payload: string, scratchPad: ScratchPad, logger?: Logger): Promise<GrantReply>;
|
|
645
|
+
interface GrantRequestEndpointOptions {
|
|
646
|
+
/** This agent's own prompt address; the endpoint sits next to it. */
|
|
647
|
+
readonly promptAddress: string;
|
|
648
|
+
/** This agent's ScratchPad: the volume it may grant on, and its ledger. */
|
|
649
|
+
readonly scratchPad: ScratchPad;
|
|
650
|
+
/** Refusals at `info`, failures at `error`. Default: silent. */
|
|
651
|
+
readonly logger?: Logger;
|
|
652
|
+
}
|
|
653
|
+
/**
|
|
654
|
+
* The creator's side, as an extra endpoint for the agent's `AgentService`
|
|
655
|
+
* (`extraEndpoints: [grantRequestEndpoint({ ... })]`): it answers every
|
|
656
|
+
* grant request by the rule at the top of this file. Several instances of
|
|
657
|
+
* one agent share the work, in the `agents` queue group.
|
|
658
|
+
*/
|
|
659
|
+
declare function grantRequestEndpoint(options: GrantRequestEndpointOptions): AgentServiceExtraEndpoint;
|
|
660
|
+
|
|
661
|
+
/** The field `discover_agents` entries get. */
|
|
662
|
+
declare const READS_SCRATCHPAD_REFERENCES_FIELD = "reads_scratchpad_references";
|
|
663
|
+
interface ScratchPadExtensionOptions {
|
|
664
|
+
/** The agent's own ScratchPad, behind the port. */
|
|
665
|
+
readonly scratchPad: ScratchPad;
|
|
666
|
+
/**
|
|
667
|
+
* The client grant requests are signed and sent with, and creators are
|
|
668
|
+
* looked up through: the one `AgentTools` runs on, with the agent's
|
|
669
|
+
* signer.
|
|
670
|
+
*/
|
|
671
|
+
readonly agents: Agents;
|
|
672
|
+
/** How long a lookup of a creator waits; unset, the SDK's discovery default. */
|
|
673
|
+
readonly discoverTimeoutMs?: number;
|
|
674
|
+
/** How long a creator's answer is waited for. Default 10 seconds. */
|
|
675
|
+
readonly grantRequestTimeoutMs?: number;
|
|
676
|
+
}
|
|
677
|
+
/** The extension; build it with {@link scratchPadExtension}. */
|
|
678
|
+
declare class ScratchPadExtension implements AgentToolsExtension {
|
|
679
|
+
#private;
|
|
680
|
+
/**
|
|
681
|
+
* For the agent's `AgentService` (`interceptors: [...]`): remembers the
|
|
682
|
+
* references in every prompt it serves.
|
|
683
|
+
*/
|
|
684
|
+
readonly requestInterceptor: RequestInterceptor;
|
|
685
|
+
constructor(options: ScratchPadExtensionOptions);
|
|
686
|
+
/**
|
|
687
|
+
* Note the references in `text` as given to this agent: what it
|
|
688
|
+
* committed, or received some way the hooks do not see.
|
|
689
|
+
*/
|
|
690
|
+
remember(text: string): void;
|
|
691
|
+
/**
|
|
692
|
+
* The reply side: before a reply carrying `reference`, this agent's own,
|
|
693
|
+
* goes out, remember it and grant the served prompt's sender read on it,
|
|
694
|
+
* first-hand — only a sender whose signature verified, since a grant
|
|
695
|
+
* names a principal and an unsigned claim proves none. `true` when
|
|
696
|
+
* granted, so the reference may go into the reply; `false` for a sender
|
|
697
|
+
* that did not verify. Throws when the reference is not this agent's own
|
|
698
|
+
* or the grant fails. The commit itself stays the agent's.
|
|
699
|
+
*/
|
|
700
|
+
grantCaller(reference: string, sender: SenderInfo | undefined): Promise<boolean>;
|
|
701
|
+
/** The discovery fields hook. */
|
|
702
|
+
discoveryFields(agent: Agent): Record<string, unknown>;
|
|
703
|
+
/** The prompt rewrite hook. */
|
|
704
|
+
beforePrompt(ctx: AgentToolsPromptContext): Promise<AgentToolsPromptRewrite | void>;
|
|
705
|
+
/** The reply look hook. */
|
|
706
|
+
afterReply(ctx: AgentToolsReplyContext): void;
|
|
707
|
+
}
|
|
708
|
+
/** The ScratchPad extension for `AgentTools` (`extensions: [...]`). */
|
|
709
|
+
declare function scratchPadExtension(options: ScratchPadExtensionOptions): ScratchPadExtension;
|
|
710
|
+
|
|
711
|
+
/**
|
|
712
|
+
* The agent's ScratchPad: the {@link ScratchPad} port, which the rules for
|
|
713
|
+
* references run on, and the commit and read the agent makes itself.
|
|
714
|
+
*/
|
|
715
|
+
interface ScratchPadClient extends ScratchPad {
|
|
716
|
+
/**
|
|
717
|
+
* Publish `text` at `path` in this agent's volume, retained for ten
|
|
718
|
+
* minutes, and return the reference token the CLI made for it.
|
|
719
|
+
*/
|
|
720
|
+
commit(text: string, path: string, trace: TraceIds | undefined): Promise<string>;
|
|
721
|
+
/** Fetch the exact content a reference token names, as text. */
|
|
722
|
+
read(reference: string, trace: TraceIds | undefined): Promise<string>;
|
|
723
|
+
}
|
|
724
|
+
interface SpCliScratchPadOptions {
|
|
725
|
+
/**
|
|
726
|
+
* The volume this agent writes to, by name: letters and digits only. The
|
|
727
|
+
* deployment provisions it for the agent's account and user; the first
|
|
728
|
+
* commit creates it.
|
|
729
|
+
*/
|
|
730
|
+
readonly volume?: string;
|
|
731
|
+
/** Exact public creation descriptor, imported by sp init. Requires a persistent dir. */
|
|
732
|
+
readonly bootstrapFile?: string;
|
|
733
|
+
/**
|
|
734
|
+
* The agent's own connection source: `sp` authenticates the same way. It
|
|
735
|
+
* takes a URL with a credentials file; it reads no NATS context, and an
|
|
736
|
+
* nkey seed alone is not a form it accepts.
|
|
737
|
+
*/
|
|
738
|
+
readonly nats: NatsConnectionSource;
|
|
739
|
+
/** The `sp` binary. Default `sp` on PATH. */
|
|
740
|
+
readonly bin?: string;
|
|
741
|
+
/**
|
|
742
|
+
* A private directory for the CLI's workspace; created if missing, and
|
|
743
|
+
* used by its real path. Keep it across restarts: it records the volume
|
|
744
|
+
* and any command still to finish. Default `scratchpad-<volume>` under
|
|
745
|
+
* the temp directory.
|
|
746
|
+
*/
|
|
747
|
+
readonly dir?: string;
|
|
748
|
+
/** How long a read grant lasts, in seconds. Default and ceiling ten minutes. */
|
|
749
|
+
readonly grantTtlS?: number;
|
|
750
|
+
/**
|
|
751
|
+
* This agent's prompt address, written into every reference it makes, so
|
|
752
|
+
* an agent handed one knows whom to ask before passing it on. A commit
|
|
753
|
+
* needs it.
|
|
754
|
+
*/
|
|
755
|
+
readonly creator?: string;
|
|
756
|
+
}
|
|
757
|
+
/** The `sp` binary when none is given: the one on PATH. */
|
|
758
|
+
declare const DEFAULT_SP_BIN = "sp";
|
|
759
|
+
/**
|
|
760
|
+
* How long a read grant lasts at most: long enough for the receiving agent
|
|
761
|
+
* to read what it was handed when it starts on the prompt, short enough
|
|
762
|
+
* that the access does not outlive the task. A grant also never outlives
|
|
763
|
+
* the reference it is on.
|
|
764
|
+
*/
|
|
765
|
+
declare const DEFAULT_GRANT_TTL_S = 600;
|
|
766
|
+
/**
|
|
767
|
+
* A refusal or failure from `sp`: its error code, and whether the outcome
|
|
768
|
+
* is unknown — a mutation that may still have taken effect.
|
|
769
|
+
*/
|
|
770
|
+
declare class ScratchPadError extends Error {
|
|
771
|
+
readonly code: string;
|
|
772
|
+
readonly unknown: boolean;
|
|
773
|
+
constructor(message: string, code: string, unknown: boolean);
|
|
774
|
+
}
|
|
775
|
+
/**
|
|
776
|
+
* Commit, read and grant by reference, through one `sp` binary and one
|
|
777
|
+
* volume: the {@link ScratchPadClient} an agent hands to
|
|
778
|
+
* `scratchPadExtension()` and `grantRequestEndpoint()` and commits and reads
|
|
779
|
+
* with itself.
|
|
780
|
+
*/
|
|
781
|
+
declare function spCliScratchPad(options: SpCliScratchPadOptions): ScratchPadClient;
|
|
782
|
+
/** The variables {@link scratchPadFromEnv} reads. */
|
|
783
|
+
declare const SCRATCHPAD_VOLUME_VAR = "SCRATCHPAD_VOLUME";
|
|
784
|
+
declare const SCRATCHPAD_BOOTSTRAP_FILE_VAR = "SCRATCHPAD_BOOTSTRAP_FILE";
|
|
785
|
+
declare const SCRATCHPAD_BIN_VAR = "SCRATCHPAD_BIN";
|
|
786
|
+
declare const SCRATCHPAD_DIR_VAR = "SCRATCHPAD_DIR";
|
|
787
|
+
declare const SCRATCHPAD_GRANT_TTL_S_VAR = "SCRATCHPAD_GRANT_TTL_S";
|
|
788
|
+
/** What {@link scratchPadFromEnv} takes besides the environment. */
|
|
789
|
+
interface ScratchPadFromEnvOptions {
|
|
790
|
+
/** This agent's prompt address, written into every reference it makes. */
|
|
791
|
+
readonly creator?: string;
|
|
792
|
+
/**
|
|
793
|
+
* The agent's connection source, when it is not the environment's
|
|
794
|
+
* `NATS_CONTEXT`, or `NATS_CREDS` with `NATS_URL`.
|
|
795
|
+
*/
|
|
796
|
+
readonly nats?: NatsConnectionSource;
|
|
797
|
+
}
|
|
798
|
+
/**
|
|
799
|
+
* The agent's ScratchPad as the environment configures it, or `undefined`
|
|
800
|
+
* when both `SCRATCHPAD_VOLUME` and `SCRATCHPAD_BOOTSTRAP_FILE` are unset. Reads
|
|
801
|
+
* `SCRATCHPAD_VOLUME`, `SCRATCHPAD_BIN`, `SCRATCHPAD_DIR` and
|
|
802
|
+
* `SCRATCHPAD_GRANT_TTL_S`, and, unless `options.nats` is given, the
|
|
803
|
+
* connection the agent's own configuration reads: `NATS_CREDS` with
|
|
804
|
+
* `NATS_URL` (default `nats://127.0.0.1:4222`), or `NATS_CONTEXT`, which
|
|
805
|
+
* `sp` cannot use. An empty variable counts as unset. Throws for a grant TTL
|
|
806
|
+
* that is not a positive number, and, like {@link spCliScratchPad}, for a
|
|
807
|
+
* connection `sp` cannot use: a NATS context without credentials, or no
|
|
808
|
+
* credentials at all.
|
|
809
|
+
*/
|
|
810
|
+
declare function scratchPadFromEnv(env?: Readonly<Record<string, string | undefined>>, options?: ScratchPadFromEnvOptions): ScratchPadClient | undefined;
|
|
811
|
+
|
|
812
|
+
/** The §9 code the guard refuses with. */
|
|
813
|
+
declare const LOOP_GUARD_CODE = 409;
|
|
814
|
+
/** The description the refused caller sees, for `rootId`. */
|
|
815
|
+
declare function loopGuardDescription(rootId: string): string;
|
|
816
|
+
interface LoopGuard {
|
|
817
|
+
/** For the service, after the fabric's tracing interceptor. */
|
|
818
|
+
readonly requestInterceptor: RequestInterceptor;
|
|
819
|
+
/** For the plugin's client, next to the fabric's prompt interceptor. */
|
|
820
|
+
readonly promptInterceptor: PromptInterceptor;
|
|
821
|
+
/**
|
|
822
|
+
* For the add-on's `aroundToolCall`: runs `run` once, synchronously, and
|
|
823
|
+
* returns its value untouched, a promise included. `scope` is the served
|
|
824
|
+
* request's, the one tracing bound around its handler; with another or
|
|
825
|
+
* none the call is only run.
|
|
826
|
+
*/
|
|
827
|
+
aroundToolCall<T>(scope: TraceScope | undefined, run: () => T): T;
|
|
828
|
+
/** `true` while a served request of tree `rootId` is open. */
|
|
829
|
+
serving(rootId: string): boolean;
|
|
830
|
+
/** `true` while a served request of tree `rootId` waits on a call it made. */
|
|
831
|
+
waiting(rootId: string): boolean;
|
|
832
|
+
}
|
|
833
|
+
declare function loopGuard(): LoopGuard;
|
|
834
|
+
|
|
835
|
+
declare const CODES: readonly ["ok", "invalid", "unauthenticated", "denied", "not_found", "exists", "conflict", "fenced", "generation_retired", "intent_changed", "capacity", "summary_limit", "closed", "epoch_changed", "expired", "corrupt", "incomplete", "busy", "unknown", "unavailable", "internal"];
|
|
836
|
+
type Code = (typeof CODES)[number];
|
|
837
|
+
type ContentID = string;
|
|
838
|
+
interface Principal {
|
|
839
|
+
account: string;
|
|
840
|
+
user: string;
|
|
841
|
+
}
|
|
842
|
+
interface Trace {
|
|
843
|
+
thread_id?: string;
|
|
844
|
+
root_id?: string;
|
|
845
|
+
tool_call_id?: string;
|
|
846
|
+
}
|
|
847
|
+
interface Action {
|
|
848
|
+
operation_id: string;
|
|
849
|
+
trace: Trace;
|
|
850
|
+
}
|
|
851
|
+
interface Target {
|
|
852
|
+
volume: string;
|
|
853
|
+
creation_id: string;
|
|
854
|
+
}
|
|
855
|
+
interface Head {
|
|
856
|
+
generation: number;
|
|
857
|
+
root: ContentID;
|
|
858
|
+
}
|
|
859
|
+
interface Writer {
|
|
860
|
+
slot: number;
|
|
861
|
+
generation: number;
|
|
862
|
+
}
|
|
863
|
+
interface RetentionIntent {
|
|
864
|
+
enabled: boolean;
|
|
865
|
+
slot: number;
|
|
866
|
+
generation: number;
|
|
867
|
+
until: number;
|
|
868
|
+
}
|
|
869
|
+
interface RetentionHandle {
|
|
870
|
+
slot: number;
|
|
871
|
+
generation: number;
|
|
872
|
+
}
|
|
873
|
+
interface GrantHandle {
|
|
874
|
+
slot: number;
|
|
875
|
+
generation: number;
|
|
876
|
+
}
|
|
877
|
+
interface RetentionOrigin {
|
|
878
|
+
writer: Writer;
|
|
879
|
+
number: number;
|
|
880
|
+
}
|
|
881
|
+
interface Command {
|
|
882
|
+
creation_id: string;
|
|
883
|
+
writer: Writer;
|
|
884
|
+
number: number;
|
|
885
|
+
operation_id: string;
|
|
886
|
+
base: Head;
|
|
887
|
+
root: ContentID;
|
|
888
|
+
trace: Trace;
|
|
889
|
+
remove_path?: string;
|
|
890
|
+
retention: RetentionIntent;
|
|
891
|
+
}
|
|
892
|
+
interface Receipt {
|
|
893
|
+
volume: string;
|
|
894
|
+
principal: Principal;
|
|
895
|
+
command: Command;
|
|
896
|
+
head: Head;
|
|
897
|
+
retention: RetentionHandle;
|
|
898
|
+
}
|
|
899
|
+
interface WriterSlot {
|
|
900
|
+
generation: number;
|
|
901
|
+
number: number;
|
|
902
|
+
principal?: Principal;
|
|
903
|
+
write: boolean;
|
|
904
|
+
receipt?: Receipt;
|
|
905
|
+
}
|
|
906
|
+
interface RetentionValue {
|
|
907
|
+
root: ContentID;
|
|
908
|
+
until: number;
|
|
909
|
+
origin: RetentionOrigin;
|
|
910
|
+
}
|
|
911
|
+
interface RetentionSlot {
|
|
912
|
+
generation: number;
|
|
913
|
+
pin?: RetentionValue;
|
|
914
|
+
}
|
|
915
|
+
interface GrantValue {
|
|
916
|
+
principal: Principal;
|
|
917
|
+
root: ContentID;
|
|
918
|
+
path: string;
|
|
919
|
+
directory: boolean;
|
|
920
|
+
retention: RetentionHandle;
|
|
921
|
+
until: number;
|
|
922
|
+
}
|
|
923
|
+
interface GrantSlot {
|
|
924
|
+
generation: number;
|
|
925
|
+
grant?: GrantValue;
|
|
926
|
+
}
|
|
927
|
+
interface VolumeView {
|
|
928
|
+
target: Target;
|
|
929
|
+
owner: Principal;
|
|
930
|
+
head: Head;
|
|
931
|
+
revision: number;
|
|
932
|
+
closed: boolean;
|
|
933
|
+
epoch: number;
|
|
934
|
+
objects: number;
|
|
935
|
+
bytes: number;
|
|
936
|
+
writers: WriterSlot[];
|
|
937
|
+
retentions: RetentionSlot[];
|
|
938
|
+
grants: GrantSlot[];
|
|
939
|
+
lifetime?: LifetimeView;
|
|
940
|
+
}
|
|
941
|
+
interface AdmissionBinding {
|
|
942
|
+
slot: number;
|
|
943
|
+
generation: number;
|
|
944
|
+
operation_id: string;
|
|
945
|
+
}
|
|
946
|
+
interface LifetimeView {
|
|
947
|
+
admission: AdmissionBinding;
|
|
948
|
+
phase: "active" | "shrinking" | "expiring";
|
|
949
|
+
expires_at: number;
|
|
950
|
+
grace_until: number;
|
|
951
|
+
max_lease_seconds: number;
|
|
952
|
+
grace_seconds: number;
|
|
953
|
+
recovery_reads: boolean;
|
|
954
|
+
reserve_objects: number;
|
|
955
|
+
reserve_bytes: number;
|
|
956
|
+
}
|
|
957
|
+
interface RenewRequest {
|
|
958
|
+
target: Target;
|
|
959
|
+
until: number;
|
|
960
|
+
}
|
|
961
|
+
interface RemovalRequest {
|
|
962
|
+
target: Target;
|
|
963
|
+
command: Command;
|
|
964
|
+
}
|
|
965
|
+
interface RemovalPlan extends RemovalRequest {
|
|
966
|
+
slot: number;
|
|
967
|
+
generation: number;
|
|
968
|
+
sequence: number;
|
|
969
|
+
added_objects: number;
|
|
970
|
+
added_bytes: number;
|
|
971
|
+
}
|
|
972
|
+
interface VolumeReleaseRequest {
|
|
973
|
+
target: Target;
|
|
974
|
+
operation_id: string;
|
|
975
|
+
end_promises: boolean;
|
|
976
|
+
}
|
|
977
|
+
interface ReleaseEffects {
|
|
978
|
+
objects: number;
|
|
979
|
+
bytes: number;
|
|
980
|
+
retentions: number;
|
|
981
|
+
read_grants: number;
|
|
982
|
+
access_slots: number;
|
|
983
|
+
references: number;
|
|
984
|
+
}
|
|
985
|
+
interface VolumeReleasePlan {
|
|
986
|
+
request: VolumeReleaseRequest;
|
|
987
|
+
incarnation: string;
|
|
988
|
+
slot: number;
|
|
989
|
+
generation: number;
|
|
990
|
+
sequence: number;
|
|
991
|
+
head: Head;
|
|
992
|
+
effects: ReleaseEffects;
|
|
993
|
+
}
|
|
994
|
+
interface VolumeReleaseResult {
|
|
995
|
+
target: Target;
|
|
996
|
+
slot: number;
|
|
997
|
+
generation: number;
|
|
998
|
+
operation_id: string;
|
|
999
|
+
disposed: boolean;
|
|
1000
|
+
capacity_returned: boolean;
|
|
1001
|
+
}
|
|
1002
|
+
interface Limits {
|
|
1003
|
+
object_bytes: number;
|
|
1004
|
+
read_bytes: number;
|
|
1005
|
+
control_bytes: number;
|
|
1006
|
+
reply_bytes: number;
|
|
1007
|
+
writers: number;
|
|
1008
|
+
retentions: number;
|
|
1009
|
+
grants: number;
|
|
1010
|
+
grant_seconds: number;
|
|
1011
|
+
}
|
|
1012
|
+
interface ReservedScope {
|
|
1013
|
+
volume: string;
|
|
1014
|
+
objects: number;
|
|
1015
|
+
bytes: number;
|
|
1016
|
+
admission?: AdmissionBinding;
|
|
1017
|
+
}
|
|
1018
|
+
interface Info {
|
|
1019
|
+
principal: Principal;
|
|
1020
|
+
scopes: ReservedScope[];
|
|
1021
|
+
limits: Limits;
|
|
1022
|
+
}
|
|
1023
|
+
interface ContentObject {
|
|
1024
|
+
kind: "chnk" | "fobj" | "tree";
|
|
1025
|
+
id: ContentID;
|
|
1026
|
+
}
|
|
1027
|
+
interface ObjectSpec {
|
|
1028
|
+
object: ContentObject;
|
|
1029
|
+
length: number;
|
|
1030
|
+
}
|
|
1031
|
+
type AllocationState = "reserved" | "verifying" | "verified" | "refused";
|
|
1032
|
+
interface ObjectProgress extends ObjectSpec {
|
|
1033
|
+
state: AllocationState;
|
|
1034
|
+
next: number;
|
|
1035
|
+
code: Code;
|
|
1036
|
+
}
|
|
1037
|
+
interface PrepareRequest {
|
|
1038
|
+
target: Target;
|
|
1039
|
+
objects: ObjectSpec[];
|
|
1040
|
+
}
|
|
1041
|
+
interface PrepareResult {
|
|
1042
|
+
epoch: number;
|
|
1043
|
+
objects: ObjectProgress[];
|
|
1044
|
+
}
|
|
1045
|
+
interface VerifyRequest {
|
|
1046
|
+
target: Target;
|
|
1047
|
+
epoch: number;
|
|
1048
|
+
objects: ContentObject[];
|
|
1049
|
+
}
|
|
1050
|
+
interface VerifyResult {
|
|
1051
|
+
epoch: number;
|
|
1052
|
+
objects: ObjectProgress[];
|
|
1053
|
+
}
|
|
1054
|
+
interface PutRequest {
|
|
1055
|
+
target: Target;
|
|
1056
|
+
object: ContentObject;
|
|
1057
|
+
epoch: number;
|
|
1058
|
+
}
|
|
1059
|
+
interface CreateRequest {
|
|
1060
|
+
volume: string;
|
|
1061
|
+
action: Action;
|
|
1062
|
+
admission?: AdmissionBinding;
|
|
1063
|
+
}
|
|
1064
|
+
interface PublishRequest {
|
|
1065
|
+
target: Target;
|
|
1066
|
+
command: Command;
|
|
1067
|
+
}
|
|
1068
|
+
interface RetainRequest {
|
|
1069
|
+
target: Target;
|
|
1070
|
+
slot: number;
|
|
1071
|
+
generation: number;
|
|
1072
|
+
root: ContentID;
|
|
1073
|
+
until: number;
|
|
1074
|
+
action: Action;
|
|
1075
|
+
}
|
|
1076
|
+
interface ReleaseRequest {
|
|
1077
|
+
target: Target;
|
|
1078
|
+
handle: RetentionHandle;
|
|
1079
|
+
}
|
|
1080
|
+
interface GrantIssueRequest {
|
|
1081
|
+
target: Target;
|
|
1082
|
+
slot: number;
|
|
1083
|
+
generation: number;
|
|
1084
|
+
principal: Principal;
|
|
1085
|
+
root: ContentID;
|
|
1086
|
+
path: string;
|
|
1087
|
+
retention: RetentionHandle;
|
|
1088
|
+
until: number;
|
|
1089
|
+
action: Action;
|
|
1090
|
+
}
|
|
1091
|
+
interface RevokeRequest {
|
|
1092
|
+
target: Target;
|
|
1093
|
+
handle: GrantHandle;
|
|
1094
|
+
action: Action;
|
|
1095
|
+
}
|
|
1096
|
+
interface PathRequest {
|
|
1097
|
+
target: Target;
|
|
1098
|
+
root: ContentID;
|
|
1099
|
+
path: string;
|
|
1100
|
+
trace: Trace;
|
|
1101
|
+
}
|
|
1102
|
+
interface ReadRequest extends PathRequest {
|
|
1103
|
+
offset: number;
|
|
1104
|
+
length: number;
|
|
1105
|
+
}
|
|
1106
|
+
interface ListRequest extends PathRequest {
|
|
1107
|
+
offset: number;
|
|
1108
|
+
limit: number;
|
|
1109
|
+
}
|
|
1110
|
+
interface Stat {
|
|
1111
|
+
type: "file" | "directory" | "symlink";
|
|
1112
|
+
object: ContentID;
|
|
1113
|
+
size: number;
|
|
1114
|
+
sha256: string;
|
|
1115
|
+
executable: boolean;
|
|
1116
|
+
link_target?: string;
|
|
1117
|
+
}
|
|
1118
|
+
interface Entry {
|
|
1119
|
+
name: string;
|
|
1120
|
+
type: "file" | "directory" | "symlink";
|
|
1121
|
+
object: ContentID;
|
|
1122
|
+
executable: boolean;
|
|
1123
|
+
link_target?: string;
|
|
1124
|
+
}
|
|
1125
|
+
interface ListResult {
|
|
1126
|
+
entries: Entry[];
|
|
1127
|
+
next: number;
|
|
1128
|
+
done: boolean;
|
|
1129
|
+
}
|
|
1130
|
+
interface ReadResult {
|
|
1131
|
+
stat: Stat;
|
|
1132
|
+
offset: number;
|
|
1133
|
+
data: Uint8Array;
|
|
1134
|
+
}
|
|
1135
|
+
interface MaintenanceRequest {
|
|
1136
|
+
target: Target;
|
|
1137
|
+
revision: number;
|
|
1138
|
+
}
|
|
1139
|
+
interface CollectionReport {
|
|
1140
|
+
inventory_objects: number;
|
|
1141
|
+
inventory_bytes: number;
|
|
1142
|
+
live_objects: number;
|
|
1143
|
+
live_bytes: number;
|
|
1144
|
+
candidate_objects: number;
|
|
1145
|
+
candidate_bytes: number;
|
|
1146
|
+
delete_objects: number;
|
|
1147
|
+
}
|
|
1148
|
+
interface CollectionResult {
|
|
1149
|
+
volume: VolumeView;
|
|
1150
|
+
collection: CollectionReport;
|
|
1151
|
+
}
|
|
1152
|
+
|
|
1153
|
+
interface Reference {
|
|
1154
|
+
version: 2;
|
|
1155
|
+
creator: string;
|
|
1156
|
+
account: string;
|
|
1157
|
+
target: Target;
|
|
1158
|
+
root: string;
|
|
1159
|
+
generation: number;
|
|
1160
|
+
path: string;
|
|
1161
|
+
retention: RetentionHandle;
|
|
1162
|
+
expires_at: number;
|
|
1163
|
+
}
|
|
1164
|
+
declare function encodeReference(reference: Reference): string;
|
|
1165
|
+
declare function decodeReference(token: string): Reference;
|
|
1166
|
+
|
|
1167
|
+
interface ShortReference {
|
|
1168
|
+
route: string;
|
|
1169
|
+
creation_id: string;
|
|
1170
|
+
retention: RetentionHandle;
|
|
1171
|
+
path_index: number;
|
|
1172
|
+
}
|
|
1173
|
+
interface ReferenceSpec {
|
|
1174
|
+
creator: string;
|
|
1175
|
+
paths: string[];
|
|
1176
|
+
}
|
|
1177
|
+
interface ResolvedReference {
|
|
1178
|
+
short: string;
|
|
1179
|
+
expanded: Reference;
|
|
1180
|
+
}
|
|
1181
|
+
interface ReferenceCapabilities {
|
|
1182
|
+
enabled: boolean;
|
|
1183
|
+
version: number;
|
|
1184
|
+
prefix: string;
|
|
1185
|
+
token_bytes: number;
|
|
1186
|
+
paths_per_retention: number;
|
|
1187
|
+
max_intent_bytes: number;
|
|
1188
|
+
max_metadata_bytes: number;
|
|
1189
|
+
}
|
|
1190
|
+
interface ReferencePublishRequest extends PublishRequest {
|
|
1191
|
+
reference: ReferenceSpec;
|
|
1192
|
+
}
|
|
1193
|
+
interface ReferencePublishResult {
|
|
1194
|
+
receipt: Receipt;
|
|
1195
|
+
references: ResolvedReference[];
|
|
1196
|
+
}
|
|
1197
|
+
interface ReferenceResolveRequest {
|
|
1198
|
+
reference: string;
|
|
1199
|
+
trace: Trace;
|
|
1200
|
+
}
|
|
1201
|
+
interface ReferenceStatResult {
|
|
1202
|
+
reference: ResolvedReference;
|
|
1203
|
+
stat: Stat;
|
|
1204
|
+
}
|
|
1205
|
+
/** Decode the locator only. The service verifies its metadata verifier. */
|
|
1206
|
+
declare function decodeShortReference(token: string): ShortReference;
|
|
1207
|
+
interface ReferenceRetainRequest {
|
|
1208
|
+
retain: RetainRequest;
|
|
1209
|
+
reference: ReferenceSpec;
|
|
1210
|
+
}
|
|
1211
|
+
interface ReferenceRetainResult {
|
|
1212
|
+
volume: VolumeView;
|
|
1213
|
+
references: ResolvedReference[];
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1216
|
+
interface RequestOptions {
|
|
1217
|
+
signal?: AbortSignal;
|
|
1218
|
+
}
|
|
1219
|
+
interface TransportOptions {
|
|
1220
|
+
timeoutMs?: number;
|
|
1221
|
+
}
|
|
1222
|
+
/** One request per operation on a borrowed NATS connection. No retry or identity override. */
|
|
1223
|
+
declare class ScratchPadTransport {
|
|
1224
|
+
private readonly nc;
|
|
1225
|
+
readonly timeoutMs: number;
|
|
1226
|
+
constructor(nc: NatsConnection, options?: TransportOptions);
|
|
1227
|
+
private within;
|
|
1228
|
+
private exchange;
|
|
1229
|
+
private control;
|
|
1230
|
+
private matching;
|
|
1231
|
+
private view;
|
|
1232
|
+
info(options?: RequestOptions): Promise<Info>;
|
|
1233
|
+
createVolume(request: CreateRequest, options?: RequestOptions): Promise<VolumeView>;
|
|
1234
|
+
renewLease(request: RenewRequest, options?: RequestOptions): Promise<VolumeView>;
|
|
1235
|
+
planRemoval(request: RemovalRequest, options?: RequestOptions): Promise<RemovalPlan>;
|
|
1236
|
+
applyRemoval(plan: RemovalPlan, options?: RequestOptions): Promise<Receipt>;
|
|
1237
|
+
planVolumeRelease(request: VolumeReleaseRequest, options?: RequestOptions): Promise<VolumeReleasePlan>;
|
|
1238
|
+
applyVolumeRelease(plan: VolumeReleasePlan, options?: RequestOptions): Promise<VolumeReleaseResult>;
|
|
1239
|
+
getVolume(target: Target, options?: RequestOptions): Promise<VolumeView>;
|
|
1240
|
+
prepare(request: PrepareRequest, options?: RequestOptions): Promise<PrepareResult>;
|
|
1241
|
+
putPrepared(request: PutRequest, data: Uint8Array, options?: RequestOptions): Promise<void>;
|
|
1242
|
+
verify(request: VerifyRequest, options?: RequestOptions): Promise<VerifyResult>;
|
|
1243
|
+
publish(request: PublishRequest, options?: RequestOptions): Promise<Receipt>;
|
|
1244
|
+
/** Unknown reference verbs on older services return invalid. Other failures propagate. */
|
|
1245
|
+
referenceInfo(options?: RequestOptions): Promise<ReferenceCapabilities | undefined>;
|
|
1246
|
+
private referencePublication;
|
|
1247
|
+
referencePublish(request: ReferencePublishRequest, options?: RequestOptions): Promise<ReferencePublishResult>;
|
|
1248
|
+
referenceReceipt(request: ReferencePublishRequest, options?: RequestOptions): Promise<ReferencePublishResult>;
|
|
1249
|
+
referenceResolve(request: ReferenceResolveRequest, options?: RequestOptions): Promise<ResolvedReference>;
|
|
1250
|
+
referenceStat(request: ReferenceResolveRequest, options?: RequestOptions): Promise<ReferenceStatResult>;
|
|
1251
|
+
referenceRetain(request: ReferenceRetainRequest, options?: RequestOptions): Promise<ReferenceRetainResult>;
|
|
1252
|
+
resetWriter(target: Target, writer: Writer, options?: RequestOptions): Promise<Writer>;
|
|
1253
|
+
retain(request: RetainRequest, options?: RequestOptions): Promise<VolumeView>;
|
|
1254
|
+
release(request: ReleaseRequest, options?: RequestOptions): Promise<VolumeView>;
|
|
1255
|
+
issueGrant(request: GrantIssueRequest, options?: RequestOptions): Promise<GrantHandle>;
|
|
1256
|
+
revokeGrant(request: RevokeRequest, options?: RequestOptions): Promise<VolumeView>;
|
|
1257
|
+
stat(request: PathRequest, options?: RequestOptions): Promise<Stat>;
|
|
1258
|
+
list(request: ListRequest, options?: RequestOptions): Promise<ListResult>;
|
|
1259
|
+
read(request: ReadRequest, options?: RequestOptions): Promise<ReadResult>;
|
|
1260
|
+
closeVolume(request: MaintenanceRequest, options?: RequestOptions): Promise<VolumeView>;
|
|
1261
|
+
planCollection(request: MaintenanceRequest, options?: RequestOptions): Promise<CollectionReport>;
|
|
1262
|
+
applyCollection(request: MaintenanceRequest, options?: RequestOptions): Promise<CollectionResult>;
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1265
|
+
declare const DEFAULT_READ_LIMIT_BYTES: number;
|
|
1266
|
+
interface ScratchPadReaderOptions {
|
|
1267
|
+
nc: NatsConnection;
|
|
1268
|
+
timeoutMs?: number;
|
|
1269
|
+
}
|
|
1270
|
+
interface ReadBytesOptions {
|
|
1271
|
+
limitBytes?: number;
|
|
1272
|
+
trace?: TraceIds;
|
|
1273
|
+
}
|
|
1274
|
+
/** Authenticated reads through a borrowed NATS connection; no workspace needed. */
|
|
1275
|
+
declare class ScratchPadReader {
|
|
1276
|
+
protected readonly transport: ScratchPadTransport;
|
|
1277
|
+
readonly principal: Principal;
|
|
1278
|
+
private readonly expansions;
|
|
1279
|
+
constructor(transport: ScratchPadTransport, principal: Principal);
|
|
1280
|
+
protected reference(token: string): Reference;
|
|
1281
|
+
protected checkedReference(reference: Reference): Reference;
|
|
1282
|
+
private checkDeadline;
|
|
1283
|
+
protected cacheReference(pair: ResolvedReference): void;
|
|
1284
|
+
/** Expand either form for programmatic use. Metadata supplies no read authority. */
|
|
1285
|
+
resolveReference(token: string, trace?: TraceIds): Promise<Reference>;
|
|
1286
|
+
private openFile;
|
|
1287
|
+
private chunks;
|
|
1288
|
+
/** Returns bytes only after size, logical digest and canonical file identity agree. */
|
|
1289
|
+
readBytes(token: string, options?: ReadBytesOptions): Promise<Uint8Array>;
|
|
1290
|
+
/** Bytes are provisional until iteration completes without error. Consume to EOF
|
|
1291
|
+
* and publish a downloaded file only after success; early cancellation is unverified.
|
|
1292
|
+
* The caller must set an explicit whole-file size allowance.
|
|
1293
|
+
*/
|
|
1294
|
+
readStream(token: string, options: ReadBytesOptions & {
|
|
1295
|
+
limitBytes: number;
|
|
1296
|
+
}): AsyncGenerator<Uint8Array>;
|
|
1297
|
+
read(reference: string, trace?: TraceIds): Promise<string>;
|
|
1298
|
+
}
|
|
1299
|
+
declare function scratchPadReader(options: ScratchPadReaderOptions): Promise<ScratchPadReader>;
|
|
1300
|
+
|
|
1301
|
+
/** One private local database, exclusively owned for the client's lifetime. */
|
|
1302
|
+
declare class WorkspaceStore {
|
|
1303
|
+
private readonly db;
|
|
1304
|
+
private readonly directory;
|
|
1305
|
+
private poisoned;
|
|
1306
|
+
private closed;
|
|
1307
|
+
private constructor();
|
|
1308
|
+
static open(directory: string): Promise<WorkspaceStore>;
|
|
1309
|
+
private usable;
|
|
1310
|
+
load(): unknown;
|
|
1311
|
+
save(state: unknown, afterRemote?: boolean, clearObjects?: boolean): void;
|
|
1312
|
+
clearObjects(): void;
|
|
1313
|
+
putObject(ordinal: number, object: ContentObject, data: Uint8Array): void;
|
|
1314
|
+
objects(): ObjectSpec[];
|
|
1315
|
+
bytes(object: ContentObject): Uint8Array;
|
|
1316
|
+
close(): void;
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
interface NativeScratchPadOptions extends ScratchPadReaderOptions {
|
|
1320
|
+
/** Private directory on a persistent local filesystem. One client owns it at a time. */
|
|
1321
|
+
dir: string;
|
|
1322
|
+
/** Required unless bootstrapFile supplies the exact volume. */
|
|
1323
|
+
volume?: string;
|
|
1324
|
+
/** Public descriptor file. Never a credentials file or an adoption target. */
|
|
1325
|
+
bootstrapFile?: string;
|
|
1326
|
+
/** Prompt address used only to route Fabric grant requests. It is not authentication. */
|
|
1327
|
+
creator: string;
|
|
1328
|
+
ttlSeconds?: number;
|
|
1329
|
+
}
|
|
1330
|
+
interface PublishOptions {
|
|
1331
|
+
operationId: string;
|
|
1332
|
+
ttlSeconds?: number;
|
|
1333
|
+
trace?: TraceIds;
|
|
1334
|
+
}
|
|
1335
|
+
interface PublishResult {
|
|
1336
|
+
reference: string;
|
|
1337
|
+
receipt: Receipt;
|
|
1338
|
+
}
|
|
1339
|
+
/** Capacity returned can be known even when this release request's acceptance is unknown. */
|
|
1340
|
+
type VolumeReleaseOutcome = VolumeReleaseResult & {
|
|
1341
|
+
acceptance_unknown?: true;
|
|
1342
|
+
};
|
|
1343
|
+
interface RecoveryResult {
|
|
1344
|
+
kind: string;
|
|
1345
|
+
reference?: string;
|
|
1346
|
+
receipt?: Receipt;
|
|
1347
|
+
volume?: VolumeView;
|
|
1348
|
+
release?: VolumeReleaseOutcome;
|
|
1349
|
+
}
|
|
1350
|
+
interface Publication {
|
|
1351
|
+
kind: "publish";
|
|
1352
|
+
command: Command;
|
|
1353
|
+
path: string;
|
|
1354
|
+
ttl: number;
|
|
1355
|
+
expiry_revision?: number;
|
|
1356
|
+
reference?: ReferenceSpec;
|
|
1357
|
+
}
|
|
1358
|
+
interface Granted {
|
|
1359
|
+
request: GrantIssueRequest;
|
|
1360
|
+
handle: GrantHandle;
|
|
1361
|
+
kind: GrantKind;
|
|
1362
|
+
}
|
|
1363
|
+
type Control = {
|
|
1364
|
+
kind: "grant";
|
|
1365
|
+
request: GrantIssueRequest;
|
|
1366
|
+
provenance: GrantKind;
|
|
1367
|
+
} | {
|
|
1368
|
+
kind: "release";
|
|
1369
|
+
request: ReleaseRequest;
|
|
1370
|
+
} | {
|
|
1371
|
+
kind: "close" | "apply";
|
|
1372
|
+
request: MaintenanceRequest;
|
|
1373
|
+
};
|
|
1374
|
+
type Lifecycle = {
|
|
1375
|
+
kind: "renew";
|
|
1376
|
+
request: RenewRequest;
|
|
1377
|
+
} | {
|
|
1378
|
+
kind: "remove";
|
|
1379
|
+
plan: RemovalPlan;
|
|
1380
|
+
} | {
|
|
1381
|
+
kind: "volume_release";
|
|
1382
|
+
plan: VolumeReleasePlan;
|
|
1383
|
+
fence_accepted?: true;
|
|
1384
|
+
};
|
|
1385
|
+
type Pending = Publication | Control | Lifecycle | {
|
|
1386
|
+
kind: "reset";
|
|
1387
|
+
writer: Writer;
|
|
1388
|
+
};
|
|
1389
|
+
interface State {
|
|
1390
|
+
version: 1;
|
|
1391
|
+
principal: Principal;
|
|
1392
|
+
volume: string;
|
|
1393
|
+
creator: string;
|
|
1394
|
+
creation: Action;
|
|
1395
|
+
admission?: AdmissionBinding;
|
|
1396
|
+
target?: Target;
|
|
1397
|
+
writer?: Writer;
|
|
1398
|
+
next: number;
|
|
1399
|
+
pending?: Pending;
|
|
1400
|
+
renewal?: RenewRequest;
|
|
1401
|
+
last?: PublishResult & {
|
|
1402
|
+
path: string;
|
|
1403
|
+
ttl: number;
|
|
1404
|
+
resolved?: ResolvedReference;
|
|
1405
|
+
};
|
|
1406
|
+
grants: Granted[];
|
|
1407
|
+
removal?: Receipt;
|
|
1408
|
+
disposal?: VolumeReleaseResult;
|
|
1409
|
+
disposal_plan?: VolumeReleasePlan;
|
|
1410
|
+
release_acceptance_unknown?: true;
|
|
1411
|
+
}
|
|
1412
|
+
/** A native writer and Fabric adapter. It borrows the caller's authenticated connection. */
|
|
1413
|
+
declare class NativeScratchPad extends ScratchPadReader implements ScratchPadClient {
|
|
1414
|
+
private readonly store;
|
|
1415
|
+
private state;
|
|
1416
|
+
private readonly scope;
|
|
1417
|
+
private readonly ttl;
|
|
1418
|
+
private tail;
|
|
1419
|
+
private closing;
|
|
1420
|
+
private closePromise?;
|
|
1421
|
+
constructor(transport: ScratchPadTransport, store: WorkspaceStore, state: State, scope: ReservedScope | undefined, ttl: number);
|
|
1422
|
+
private run;
|
|
1423
|
+
private save;
|
|
1424
|
+
private change;
|
|
1425
|
+
private target;
|
|
1426
|
+
private ensureTarget;
|
|
1427
|
+
private initialize;
|
|
1428
|
+
private reset;
|
|
1429
|
+
/** Explicitly abandon writer recovery, fencing the exact generation observed by describe(). */
|
|
1430
|
+
resetWriter(options: {
|
|
1431
|
+
expectedGeneration: number;
|
|
1432
|
+
target?: Target;
|
|
1433
|
+
}): Promise<Writer>;
|
|
1434
|
+
describe(): Promise<{
|
|
1435
|
+
volume: VolumeView;
|
|
1436
|
+
pending?: string;
|
|
1437
|
+
}>;
|
|
1438
|
+
/** Save an absolute deadline before sending it. Retries never extend it implicitly. */
|
|
1439
|
+
renewLease(until: number): Promise<VolumeView>;
|
|
1440
|
+
private resumeRenewal;
|
|
1441
|
+
/** Read-only plan for an initialized writer. The caller chooses the path to remove. */
|
|
1442
|
+
planRemoval(path: string, options: {
|
|
1443
|
+
operationId: string;
|
|
1444
|
+
trace?: TraceIds;
|
|
1445
|
+
}): Promise<RemovalPlan>;
|
|
1446
|
+
applyRemoval(plan: RemovalPlan): Promise<Receipt>;
|
|
1447
|
+
/** Lists every promise affected. EndPromises must be explicitly true to authorize release. */
|
|
1448
|
+
planVolumeRelease(options: {
|
|
1449
|
+
operationId: string;
|
|
1450
|
+
endPromises?: boolean;
|
|
1451
|
+
}): Promise<VolumeReleasePlan>;
|
|
1452
|
+
applyVolumeRelease(plan: VolumeReleasePlan): Promise<VolumeReleaseOutcome>;
|
|
1453
|
+
private beginLifecycle;
|
|
1454
|
+
private lifecycle;
|
|
1455
|
+
private releaseFenced;
|
|
1456
|
+
private releaseOutcome;
|
|
1457
|
+
private finishRelease;
|
|
1458
|
+
recover(): Promise<RecoveryResult>;
|
|
1459
|
+
private recoverPending;
|
|
1460
|
+
publishBytes(bytes: Uint8Array, path: string, options: PublishOptions): Promise<PublishResult>;
|
|
1461
|
+
/** A publication replaces the head with one file at path. Older references keep their retained roots. */
|
|
1462
|
+
publishStream(source: AsyncIterable<Uint8Array> | Iterable<Uint8Array>, path: string, options: PublishOptions): Promise<PublishResult>;
|
|
1463
|
+
private publish;
|
|
1464
|
+
private samePublication;
|
|
1465
|
+
private resumePublish;
|
|
1466
|
+
private fenceExpired;
|
|
1467
|
+
private accept;
|
|
1468
|
+
private upload;
|
|
1469
|
+
commit(value: string, path: string, trace: TraceIds | undefined): Promise<string>;
|
|
1470
|
+
owns(token: string): boolean | Promise<boolean>;
|
|
1471
|
+
granted(token: string, grantee: Grantee): GrantKind | undefined | Promise<GrantKind | undefined>;
|
|
1472
|
+
grantRead(token: string, grantee: Grantee, trace?: TraceIds, toolCallId?: string, kind?: GrantKind): Promise<void>;
|
|
1473
|
+
/** Release a completed handoff. Refuses while any live grant names its retention. */
|
|
1474
|
+
release(token: string): Promise<void>;
|
|
1475
|
+
/** Collect unreferenced content in this client's own maintenance interval. */
|
|
1476
|
+
maintain(): Promise<VolumeView>;
|
|
1477
|
+
private maintainInternal;
|
|
1478
|
+
private control;
|
|
1479
|
+
close(): Promise<void>;
|
|
1480
|
+
}
|
|
1481
|
+
/** Construct a native client without creating a remote volume until first use. */
|
|
1482
|
+
declare function nativeScratchPad(options: NativeScratchPadOptions): Promise<NativeScratchPad>;
|
|
1483
|
+
/** A volume or bootstrap file enables the native client on its existing connection. */
|
|
1484
|
+
declare function nativeScratchPadFromEnv(env: Readonly<Record<string, string | undefined>>, options: ScratchPadReaderOptions & {
|
|
1485
|
+
creator: string;
|
|
1486
|
+
}): Promise<NativeScratchPad | undefined>;
|
|
1487
|
+
|
|
1488
|
+
/** A failed request. `unknown` means a mutation may already have taken effect. */
|
|
1489
|
+
declare class NativeScratchPadError extends Error {
|
|
1490
|
+
readonly code: Code;
|
|
1491
|
+
readonly unknown: boolean;
|
|
1492
|
+
readonly local: boolean;
|
|
1493
|
+
constructor(code: Code, message: string, options?: {
|
|
1494
|
+
unknown?: boolean;
|
|
1495
|
+
local?: boolean;
|
|
1496
|
+
cause?: unknown;
|
|
1497
|
+
});
|
|
1498
|
+
}
|
|
1499
|
+
|
|
1500
|
+
/** The descriptor selects an exact creation request; it supplies no authority. */
|
|
1501
|
+
interface ScratchPadBootstrap {
|
|
1502
|
+
version: 1;
|
|
1503
|
+
principal: Principal;
|
|
1504
|
+
volume: string;
|
|
1505
|
+
admission: AdmissionBinding;
|
|
1506
|
+
creation: Action;
|
|
1507
|
+
}
|
|
1508
|
+
declare const MAX_BOOTSTRAP_BYTES = 4096;
|
|
1509
|
+
declare function decodeScratchPadBootstrap(data: Uint8Array | string): ScratchPadBootstrap;
|
|
1510
|
+
|
|
1511
|
+
/** The one setting: the edge subject, in the config entry's `options`. */
|
|
1512
|
+
declare const EDGE_SUBJECT_OPTION = "edgeSubject";
|
|
1513
|
+
/** The same setting as a variable, read when the option is not given. */
|
|
1514
|
+
declare const EDGE_SUBJECT_VAR = "SYNADIA_FABRIC_EDGE_SUBJECT";
|
|
1515
|
+
/**
|
|
1516
|
+
* The edge subject an add-on runs with: the config entry's
|
|
1517
|
+
* `options.edgeSubject` when the key is there (`null` is propagate-only:
|
|
1518
|
+
* lineage without records), else `SYNADIA_FABRIC_EDGE_SUBJECT` when set,
|
|
1519
|
+
* else the fabric's default. The value is returned as given; the package
|
|
1520
|
+
* validates it (`assertValidTraceOptions`) and throws for one that can
|
|
1521
|
+
* never be published to, which stops the add-on's factory — the plugin
|
|
1522
|
+
* then logs the error and starts plain, so a misconfigured subject is
|
|
1523
|
+
* visible at start rather than as a warning on every prompt.
|
|
1524
|
+
*/
|
|
1525
|
+
declare function resolveEdgeSubject(options: Readonly<Record<string, unknown>>, env?: NodeJS.ProcessEnv): string | null;
|
|
1526
|
+
|
|
1527
|
+
/**
|
|
1528
|
+
* The harnesses that expose this extension point. Named apart from the
|
|
1529
|
+
* served record's `Harness` (`served.ts`), which is the proxy's word for a
|
|
1530
|
+
* harness, not the plugin's.
|
|
1531
|
+
*/
|
|
1532
|
+
type PluginHarness = "pi" | "openclaw" | "claude-code";
|
|
1533
|
+
/** The plugin's resolved settings, as the factory sees them before connect. */
|
|
1534
|
+
interface AgentExtensionSettings {
|
|
1535
|
+
/** The address tokens: `agents.prompt.<token>.<owner>.<name>`. */
|
|
1536
|
+
readonly owner: string;
|
|
1537
|
+
/**
|
|
1538
|
+
* The name token as configured. The plugin checks it for a collision once
|
|
1539
|
+
* on the bus and may suffix it; the definitive address is
|
|
1540
|
+
* `service.subject.prompt` in `started()`.
|
|
1541
|
+
*/
|
|
1542
|
+
readonly name: string;
|
|
1543
|
+
readonly senderIdentity: "off" | "signed";
|
|
1544
|
+
readonly minSenderTrust: "any" | "signed";
|
|
1545
|
+
/** Where the plugin keeps its files, when it has such a directory. */
|
|
1546
|
+
readonly stateDir?: string;
|
|
1547
|
+
/** The plugin's configuration as read, unknown keys included; read-only. */
|
|
1548
|
+
readonly config: Readonly<Record<string, unknown>>;
|
|
1549
|
+
}
|
|
1550
|
+
/** What the plugin knows when it loads the module, before it connects. */
|
|
1551
|
+
interface AgentExtensionContext {
|
|
1552
|
+
readonly harness: PluginHarness;
|
|
1553
|
+
readonly plugin: {
|
|
1554
|
+
readonly name: string;
|
|
1555
|
+
readonly version: string;
|
|
1556
|
+
};
|
|
1557
|
+
readonly settings: AgentExtensionSettings;
|
|
1558
|
+
/** The `options` of this module's config entry, verbatim; `{}` when the variable named it. */
|
|
1559
|
+
readonly options: Readonly<Record<string, unknown>>;
|
|
1560
|
+
/** The plugin's logger, in the SDK's `Logger` shape. */
|
|
1561
|
+
readonly logger: Logger;
|
|
1562
|
+
}
|
|
1563
|
+
/** A served prompt, as the harness's events name it. */
|
|
1564
|
+
interface ServedRequest {
|
|
1565
|
+
/** The plugin's id for the request, unique in the process. */
|
|
1566
|
+
readonly id: string;
|
|
1567
|
+
/** The envelope's fields the protocol does not define (§5.6), as decoded. */
|
|
1568
|
+
readonly extras: Readonly<Record<string, unknown>>;
|
|
1569
|
+
/** The verified sender's id, when the signature verified. */
|
|
1570
|
+
readonly caller?: string;
|
|
1571
|
+
/** Claude Code only: the session the prompt was delivered to, when known. */
|
|
1572
|
+
readonly sessionId?: string;
|
|
1573
|
+
}
|
|
1574
|
+
type Outcome = "ok" | "error" | "timeout";
|
|
1575
|
+
/**
|
|
1576
|
+
* Claude Code: how a prompt ended when the model did not end it with its
|
|
1577
|
+
* own reply, `promptEnded`'s fourth argument; absent when it did.
|
|
1578
|
+
* `final_text`: the turn ended without a reply and the plugin sent the
|
|
1579
|
+
* turn's final text as the reply (outcome `ok`); `no_reply`: no reply and
|
|
1580
|
+
* no final text; `shutdown`: the plugin stopped with the prompt open;
|
|
1581
|
+
* `delivery`: the prompt could not be handed to the harness (all three
|
|
1582
|
+
* `error`); `expired`: the prompt outlived the plugin's limit (`timeout`).
|
|
1583
|
+
* The same values as the served record's `reason`.
|
|
1584
|
+
*/
|
|
1585
|
+
type EndReason = "final_text" | "no_reply" | "shutdown" | "delivery" | "expired";
|
|
1586
|
+
/**
|
|
1587
|
+
* The harness's events. A notification is called and forgotten; a wrapper
|
|
1588
|
+
* is called by the plugin around one of its own steps and must call `run`
|
|
1589
|
+
* once, synchronously, and return its value, a promise included. A wrapper
|
|
1590
|
+
* may be an async function: the plugin still takes `run`'s own value, and
|
|
1591
|
+
* the wrapper must call `run` once, before its first `await`, so the step
|
|
1592
|
+
* keeps its timing. Every harness calls the first three; PI also
|
|
1593
|
+
* `aroundInject` and `providerHeaders`, OpenClaw `aroundDispatch`, Claude
|
|
1594
|
+
* Code `sessionStarted` and `turnStopped`. One shape serves all three.
|
|
1595
|
+
*/
|
|
1596
|
+
interface HarnessEvents {
|
|
1597
|
+
/** Inside the prompt handler, after every interceptor ran. */
|
|
1598
|
+
promptAccepted?(request: ServedRequest): void;
|
|
1599
|
+
/**
|
|
1600
|
+
* When the plugin settles the request. Claude Code passes `reason` when
|
|
1601
|
+
* the model did not end the prompt with its own reply.
|
|
1602
|
+
*/
|
|
1603
|
+
promptEnded?(request: ServedRequest, outcome: Outcome, atMs: number, reason?: EndReason): void;
|
|
1604
|
+
/** Around every agent-tool call, with the request the model works in. */
|
|
1605
|
+
aroundToolCall?<T>(request: ServedRequest | undefined, toolName: string, run: () => T): T;
|
|
1606
|
+
/** PI: around the hand-over of the prompt to PI's loop (`pi.sendUserMessage()`). */
|
|
1607
|
+
aroundInject?<T>(request: ServedRequest, run: () => T): T;
|
|
1608
|
+
/** PI: headers to add to a provider request while `request` is PI's active turn. */
|
|
1609
|
+
providerHeaders?(request: ServedRequest): Readonly<Record<string, string>> | undefined;
|
|
1610
|
+
/**
|
|
1611
|
+
* OpenClaw: around the turn's dispatch
|
|
1612
|
+
* (`dispatchInboundDirectDmWithRuntime()`). Asynchronous: the extension
|
|
1613
|
+
* calls `run` once and returns its promise.
|
|
1614
|
+
*/
|
|
1615
|
+
aroundDispatch?<T>(request: ServedRequest, run: () => Promise<T>): Promise<T>;
|
|
1616
|
+
/** Claude Code: a session started, from its hook. */
|
|
1617
|
+
sessionStarted?(sessionId: string, source: string): void;
|
|
1618
|
+
/** Claude Code: a turn stopped, from its hook. */
|
|
1619
|
+
turnStopped?(sessionId: string | undefined, atMs: number): void;
|
|
1620
|
+
}
|
|
1621
|
+
/** The live handles, once the plugin is on the bus. */
|
|
1622
|
+
interface AgentExtensionHandles {
|
|
1623
|
+
readonly agents: Agents;
|
|
1624
|
+
readonly service: AgentService;
|
|
1625
|
+
}
|
|
1626
|
+
/** What the factory returns. */
|
|
1627
|
+
interface AgentExtension {
|
|
1628
|
+
readonly name: string;
|
|
1629
|
+
/** For the plugin's `Agents` client: `new Agents({ interceptors })`. */
|
|
1630
|
+
readonly promptInterceptors?: ReadonlyArray<PromptInterceptor>;
|
|
1631
|
+
/** For the plugin's `AgentService`, before the plugin's own interceptors. */
|
|
1632
|
+
readonly requestInterceptors?: ReadonlyArray<RequestInterceptor>;
|
|
1633
|
+
/** For the plugin's `AgentService`: `heartbeatExtras`. */
|
|
1634
|
+
readonly heartbeatExtras?: () => Readonly<Record<string, unknown>>;
|
|
1635
|
+
/** For the plugin's `AgentTools`: `extensions`. */
|
|
1636
|
+
readonly toolExtensions?: ReadonlyArray<AgentToolsExtension>;
|
|
1637
|
+
/**
|
|
1638
|
+
* Keys for the service's registration metadata, read once before the
|
|
1639
|
+
* service starts. A key is one or more of `A-Z a-z 0-9 _ - .`, a value a
|
|
1640
|
+
* string; anything else fails the plugin's start. The plugin's own keys
|
|
1641
|
+
* and the protocol's registration keys win over an entry of the same name
|
|
1642
|
+
* (`agents/EXTENSIONS.md` in `synadia-agents`, from #218).
|
|
1643
|
+
*/
|
|
1644
|
+
readonly metadata?: Readonly<Record<string, string>>;
|
|
1645
|
+
/** After the service started. Awaited, bounded by the plugin. */
|
|
1646
|
+
started?(handles: AgentExtensionHandles): void | Promise<void>;
|
|
1647
|
+
/** Before the plugin stops its service. Awaited, bounded by the plugin. */
|
|
1648
|
+
stopping?(): void | Promise<void>;
|
|
1649
|
+
/** The harness's events. */
|
|
1650
|
+
readonly events?: HarnessEvents;
|
|
1651
|
+
}
|
|
1652
|
+
/** The module's one default export. */
|
|
1653
|
+
type AgentExtensionFactory = (ctx: AgentExtensionContext) => AgentExtension | Promise<AgentExtension>;
|
|
1654
|
+
|
|
1655
|
+
/** The config entry's option that holds ScratchPad's settings. */
|
|
1656
|
+
declare const SCRATCHPAD_OPTION = "scratchpad";
|
|
1657
|
+
/**
|
|
1658
|
+
* The variables `scripts/sp` reads. The connection has names of its own,
|
|
1659
|
+
* not `NATS_URL` and `NATS_CREDS`, which a plugin may read as its own
|
|
1660
|
+
* connection (OpenClaw's does) and which the add-on therefore never sets.
|
|
1661
|
+
*/
|
|
1662
|
+
declare const SP_VARS: {
|
|
1663
|
+
readonly url: "SP_NATS_URL";
|
|
1664
|
+
readonly creds: "SP_NATS_CREDS";
|
|
1665
|
+
readonly dir: "SCRATCHPAD_DIR";
|
|
1666
|
+
readonly volume: "SCRATCHPAD_VOLUME";
|
|
1667
|
+
readonly bootstrapFile: "SCRATCHPAD_BOOTSTRAP_FILE";
|
|
1668
|
+
readonly creator: "SP_CREATOR";
|
|
1669
|
+
readonly threadId: "SP_THREAD_ID";
|
|
1670
|
+
readonly rootId: "SP_ROOT_ID";
|
|
1671
|
+
readonly callerAccount: "SP_CALLER_ACCOUNT";
|
|
1672
|
+
readonly callerUser: "SP_CALLER_USER";
|
|
1673
|
+
readonly grants: "SP_GRANTS_FILE";
|
|
1674
|
+
};
|
|
1675
|
+
/** What ScratchPad was resolved to at start. */
|
|
1676
|
+
interface ScratchPadSettings {
|
|
1677
|
+
readonly url: string;
|
|
1678
|
+
readonly creds: string;
|
|
1679
|
+
readonly volume: string;
|
|
1680
|
+
readonly bootstrapFile?: string;
|
|
1681
|
+
/** Unset when neither a setting nor the plugin's state directory gives one. */
|
|
1682
|
+
readonly dir?: string;
|
|
1683
|
+
/**
|
|
1684
|
+
* The file `scripts/sp` records its grants in, beside the workspace:
|
|
1685
|
+
* `<dir>.grants`. Unset without a workspace, and then the grants the
|
|
1686
|
+
* model makes do not entitle anyone to a grant request.
|
|
1687
|
+
*/
|
|
1688
|
+
readonly grants?: string;
|
|
1689
|
+
}
|
|
1690
|
+
type Env = Record<string, string | undefined>;
|
|
1691
|
+
/**
|
|
1692
|
+
* ScratchPad's settings as the options, the environment and the plugin's
|
|
1693
|
+
* NATS context give them, or `undefined` when ScratchPad is off: no volume,
|
|
1694
|
+
* or a connection `sp` cannot use, which is logged.
|
|
1695
|
+
*/
|
|
1696
|
+
declare function resolveScratchPad(ctx: AgentExtensionContext, env: Env): Promise<ScratchPadSettings | undefined>;
|
|
1697
|
+
/** Sets the start-time variables. */
|
|
1698
|
+
declare function exportScratchPad(settings: ScratchPadSettings, env: Env): void;
|
|
1699
|
+
/**
|
|
1700
|
+
* The per-prompt variables, keyed to one request at a time: `enter` sets
|
|
1701
|
+
* them for a request, `leave` clears them only if that request still holds
|
|
1702
|
+
* them, so the end of a prompt never clears the next one's.
|
|
1703
|
+
*/
|
|
1704
|
+
declare class ServedPromptEnv {
|
|
1705
|
+
#private;
|
|
1706
|
+
private readonly env;
|
|
1707
|
+
constructor(env: Env);
|
|
1708
|
+
enter(request: ServedRequest, scope: TraceScope | undefined): void;
|
|
1709
|
+
leave(request: ServedRequest): void;
|
|
1710
|
+
}
|
|
1711
|
+
/**
|
|
1712
|
+
* The sp binary an add-on ships for this machine in `skillDir` (its
|
|
1713
|
+
* `skill/scratchpad`), or `SCRATCHPAD_BIN`; `undefined` on a platform it is
|
|
1714
|
+
* not built for. The add-on's own grants run it directly, with the flags
|
|
1715
|
+
* `scripts/sp` would add.
|
|
1716
|
+
*/
|
|
1717
|
+
declare function spBinary(env: Env, skillDir: string): string | undefined;
|
|
1718
|
+
/**
|
|
1719
|
+
* The fabric package's ScratchPad extension, for the plugin's `AgentTools`
|
|
1720
|
+
* and its service, before it can exist: it needs the plugin's `Agents`
|
|
1721
|
+
* client and this agent's address, which arrive in `started()`, after the
|
|
1722
|
+
* factory returned its hooks. Until then it keeps the prompts it serves, to
|
|
1723
|
+
* remember their references once it is built.
|
|
1724
|
+
*
|
|
1725
|
+
* One addition to the extension: the harness's model publishes with
|
|
1726
|
+
* `scripts/sp`, which the extension does not see, and the extension hands on
|
|
1727
|
+
* only what the agent was given. So a reference into its own volume is remembered as
|
|
1728
|
+
* given before the prompt rewrite looks, exactly as an SDK-built agent
|
|
1729
|
+
* remembers what it commits.
|
|
1730
|
+
*/
|
|
1731
|
+
declare class ScratchPadHandOn implements AgentToolsExtension {
|
|
1732
|
+
#private;
|
|
1733
|
+
readonly requestInterceptor: RequestInterceptor;
|
|
1734
|
+
/**
|
|
1735
|
+
* Builds the extension, once the plugin's client is on the bus. Given the
|
|
1736
|
+
* plugin's service, also answers grant requests for what this agent
|
|
1737
|
+
* published, on the endpoint an SDK-built agent serves them on
|
|
1738
|
+
* (`grantRequestEndpoint`), added through the service's own
|
|
1739
|
+
* `addEndpoint`, since the plugin builds its service before the add-on
|
|
1740
|
+
* could name an extra endpoint. Several instances of one agent share the
|
|
1741
|
+
* work, as an SDK-built agent's do.
|
|
1742
|
+
*/
|
|
1743
|
+
start(options: {
|
|
1744
|
+
readonly scratchPad: ScratchPad;
|
|
1745
|
+
readonly agents: Agents;
|
|
1746
|
+
readonly service?: AgentService;
|
|
1747
|
+
readonly logger?: Logger;
|
|
1748
|
+
}): void;
|
|
1749
|
+
discoveryFields(agent: Agent): Record<string, unknown>;
|
|
1750
|
+
beforePrompt(ctx: AgentToolsPromptContext): Promise<AgentToolsPromptRewrite | void>;
|
|
1751
|
+
afterReply(ctx: AgentToolsReplyContext): void;
|
|
1752
|
+
}
|
|
1753
|
+
/**
|
|
1754
|
+
* The ScratchPad port over the add-on's packaged sp, for its own grants and
|
|
1755
|
+
* the grant requests it answers, with the grants `scripts/sp` recorded.
|
|
1756
|
+
*/
|
|
1757
|
+
declare function spPort(settings: ScratchPadSettings, creator: string, env: Env, skillDir: string): ScratchPad | undefined;
|
|
1758
|
+
/** One grant `scripts/sp` recorded. */
|
|
1759
|
+
interface RecordedGrant {
|
|
1760
|
+
readonly expiresAt: number;
|
|
1761
|
+
readonly grantee: Grantee;
|
|
1762
|
+
readonly reference: string;
|
|
1763
|
+
}
|
|
1764
|
+
/** The grants recorded in `file`; none when it does not exist. Malformed lines are skipped. */
|
|
1765
|
+
declare function readRecordedGrants(file: string): RecordedGrant[];
|
|
1766
|
+
/**
|
|
1767
|
+
* `port`, whose ledger also holds the grants `scripts/sp` recorded in `file`.
|
|
1768
|
+
* The wrapper grants only to the served prompt's caller, the agent the
|
|
1769
|
+
* harness's model handed its reply to, so each is first-hand, as an
|
|
1770
|
+
* SDK-built agent's grant to the caller of its reply is: its holder may ask
|
|
1771
|
+
* for one more agent. A first-hand grant of the port's own comes first;
|
|
1772
|
+
* the port's answer stands when nothing live is recorded. The reference
|
|
1773
|
+
* must be the one granted on, token for token, as the requester was given
|
|
1774
|
+
* it. `now` is seconds since the epoch.
|
|
1775
|
+
*/
|
|
1776
|
+
declare function withRecordedGrants(port: ScratchPad, file: string, now?: () => number): ScratchPad;
|
|
1777
|
+
|
|
1778
|
+
export { type AdmissionBinding, type AgentExtension, type AgentExtensionContext, type AgentExtensionFactory, type AgentExtensionHandles, type AgentExtensionSettings, type AskOptions, type BuiltEdgeRecord, type BuiltServedRecord, CALLER_INBOX_PREFIX, CANNOT_ANSWER, type CallerPrompt, type CallerReply, CallerStream, DEFAULT_DISCOVER_TIMEOUT_MS, DEFAULT_EDGE_SUBJECT, DEFAULT_GRANT_REQUEST_TIMEOUT_MS, DEFAULT_GRANT_TTL_S, DEFAULT_READ_LIMIT_BYTES, DEFAULT_SP_BIN, type DurableTrace, EDGE_RECORD_VERSION, EDGE_SUBJECT_OPTION, EDGE_SUBJECT_VAR, type EndReason, type FabricCaller, FabricCallerError, type FabricCallerErrorReason, type FabricCallerOptions, type FabricTracing, GRANT_REQUEST_ENDPOINT, type GrantKind, type GrantReply, type GrantRequest, type GrantRequestEndpointOptions, type Grantee, HARNESS_THREAD_ID_MAX, type Harness, type HarnessEvents, LOOP_GUARD_CODE, type LifetimeView, type LoopGuard, MAX_BOOTSTRAP_BYTES, NATS_CREDS_VAR, NATS_URL_VAR, NativeScratchPad, NativeScratchPadError, type NativeScratchPadOptions, type Outcome, type PluginHarness, type PublishOptions, type PublishResult, READS_REFERENCES_KEY, READS_SCRATCHPAD_REFERENCES_FIELD, REFERENCE_PREFIX, ROOT_ID_FIELD, ROOT_ID_HEADER, type ReadBytesOptions, type RecordedGrant, type RecoveryResult, type Reference, type ReleaseEffects, type RemovalPlan, type RemovalRequest, type RenewRequest, type RequestGrantOptions, SCRATCHPAD_BIN_VAR, SCRATCHPAD_BOOTSTRAP_FILE_VAR, SCRATCHPAD_DIR_VAR, SCRATCHPAD_GRANT_TTL_S_VAR, SCRATCHPAD_OPTION, SCRATCHPAD_VOLUME_VAR, SERVED_RECORD_REASON_VERSION, SERVED_RECORD_VERSION, SHORT_REFERENCE_PREFIX, SP_VARS, type ScratchPad, type ScratchPadBootstrap, type ScratchPadClient, ScratchPadError, ScratchPadExtension, type ScratchPadExtensionOptions, type ScratchPadFromEnvOptions, ScratchPadHandOn, ScratchPadReader, type ScratchPadReaderOptions, type ScratchPadSettings, type ServedPhase, ServedPromptEnv, ServedPublisher, type ServedPublisherOptions, type ServedReason, type ServedRequest, type ServedStatus, type ServedTurn, type ShortReference, type SpCliScratchPadOptions, THREAD_ID_FIELD, THREAD_ID_HEADER, THREAD_ID_HEX_LEN, TOOL_CALL_ID_CONTEXT_KEY, TOOL_CALL_ID_MAX, type TraceIds, type TraceOptions, type TraceRecordCounts, type TraceScope, type VolumeReleaseOutcome, type VolumeReleasePlan, type VolumeReleaseRequest, type VolumeReleaseResult, activeTrace, answerGrantRequest, assertValidTraceOptions, bindActiveTrace, buildEdgeRecord, buildServedRecord, countTraceRecordDropped, countTraceRecordPublished, decodeReference, decodeScratchPadBootstrap, decodeShortReference, durableHeaders, durableRunId, durableTrace, encodeGrantReply, encodeGrantRequest, encodeReference, exportScratchPad, fabricCaller, fabricCallerFromEnv, fabricTracing, findReferences, grantRequestEndpoint, grantSubject, granteeFromIdentity, isThreadId, loopGuard, loopGuardDescription, nativeScratchPad, nativeScratchPadFromEnv, pickAgent, randomThreadId, readRecordedGrants, readsReferences, referenceCreator, removeReferences, requestGrant, resolveEdgeSubject, resolveScratchPad, scratchPadExtension, scratchPadFromEnv, scratchPadReader, servedPublisher, spBinary, spCliScratchPad, spPort, traceHeaders, traceRecordCounts, unixSeconds, validHarnessThreadId, validToolCallId, withDurableTrace, withRecordedGrants };
|