@synadia-ai/agent-fabric 0.0.0-stage → 0.1.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.
@@ -0,0 +1,1529 @@
1
+ import { RequestInterceptor, AgentServiceExtraEndpoint, AgentService } from '@synadia-ai/agent-service';
2
+ import { AgentId, PromptInterceptor, Agents, Logger, AgentToolsExtension, SenderInfo, Agent, 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
+ /**
169
+ * The served prompt's trace as a run's input carries it, in this key
170
+ * order. Wire form: the same keys and order in both packages.
171
+ */
172
+ interface DurableTrace {
173
+ readonly thread_id: string;
174
+ readonly root_id: string;
175
+ }
176
+ /**
177
+ * The run id that joins a durable run to the task that started it:
178
+ * `<thread_id>-<tool call id>`, the active trace's thread and the model's
179
+ * tool-call id, with every character of the tool-call id outside
180
+ * `[A-Za-z0-9_-]` replaced by `_`. Pass it as the run id when the run is
181
+ * started; the run's children and generations keep it as their prefix.
182
+ *
183
+ * `undefined` outside a traced prompt handler: there is no served thread to
184
+ * name. Pick a run id of your own then; that run joins no task.
185
+ *
186
+ * Throws {@link NatsAgentError} when the tool-call id is empty, longer than
187
+ * the trace accepts (`TOOL_CALL_ID_MAX` code points) or not valid Unicode.
188
+ */
189
+ declare function durableRunId(toolCallId: string): string | undefined;
190
+ /**
191
+ * The active trace as `{ thread_id, root_id }`, for the run's input under a
192
+ * key of your choosing; {@link durableHeaders} turns it back into the
193
+ * proxy's headers inside a step. `undefined` outside a traced prompt
194
+ * handler.
195
+ *
196
+ * Unlike `traceHeaders()`, it counts no model turn: it starts no model call.
197
+ */
198
+ declare function durableTrace(): DurableTrace | undefined;
199
+ /**
200
+ * The two headers the model proxy reads, `X-Synadia-Thread-ID` and
201
+ * `X-Synadia-Root-ID`, from a trace a run's input carries, for a model call
202
+ * inside a step. The call then lands on the thread that started the run.
203
+ *
204
+ * The input is read back from the run's journal, so it is checked as
205
+ * untrusted: `{}` unless both ids have the shape of a thread id. `{}` for
206
+ * `undefined` or `null` as well, so a run started outside a traced handler
207
+ * makes its model calls without the headers.
208
+ */
209
+ declare function durableHeaders(trace: DurableTrace | null | undefined): Record<string, string>;
210
+ /**
211
+ * Run `fn` inside the trace a run's input carries, as the prompt's handler
212
+ * ran inside it: a prompt sent to another agent from `fn` writes its edge
213
+ * under the thread that started the run, in the same tree, and
214
+ * `traceHeaders()` inside `fn` gives the same two headers as
215
+ * {@link durableHeaders}. For a step of a durable run, which a worker runs
216
+ * outside the prompt's async scope.
217
+ *
218
+ * `turnCount` is how many model calls the run has made so far; it becomes
219
+ * the turn count hint of any edge `fn` writes. A `traceHeaders()` call
220
+ * inside `fn` counts one more, as it does in a handler.
221
+ *
222
+ * A trace that is missing or not shaped like thread ids binds nothing: `fn`
223
+ * runs as it would outside a traced handler. Throws {@link NatsAgentError}
224
+ * when `turnCount` is not a whole number, 0 or more.
225
+ */
226
+ declare function withDurableTrace<T>(trace: DurableTrace | null | undefined, turnCount: number, fn: () => T): T;
227
+
228
+ declare const SERVED_RECORD_VERSION = 1;
229
+ /**
230
+ * The version of a record that carries a `reason`: the schema's version 2
231
+ * added the field. A record without one stays version 1, byte for byte what
232
+ * it was.
233
+ */
234
+ declare const SERVED_RECORD_REASON_VERSION = 2;
235
+ /**
236
+ * The harnesses whose plugins write `served` records: the ones that cannot
237
+ * put the fabric's headers on their own model calls. PI can, and writes
238
+ * none. The value is what the proxy files the harness's calls under
239
+ * (the fabric's design, §8.1).
240
+ */
241
+ type Harness = "claude" | "openclaw";
242
+ /** `start` when the prompt arrives, `end` when the turn is over. */
243
+ type ServedPhase = "start" | "end";
244
+ /** How the turn ended: answered, failed, or expired on the request's TTL. */
245
+ type ServedStatus = "ok" | "error" | "timeout";
246
+ /**
247
+ * How a prompt ended when the model did not end it with its own reply, on
248
+ * `end` only; absent when the model replied. `final_text`: the plugin sent
249
+ * the turn's final text as the reply (status `ok`); `no_reply`: the turn
250
+ * ended with no reply and no final text; `shutdown`: the plugin stopped
251
+ * with the prompt open; `delivery`: the prompt could not be handed to the
252
+ * harness; `expired`: the prompt outlived the plugin's limit (status
253
+ * `timeout`).
254
+ */
255
+ type ServedReason = "final_text" | "no_reply" | "shutdown" | "delivery" | "expired";
256
+ /** Longest accepted harness thread id, in Unicode code points. */
257
+ declare const HARNESS_THREAD_ID_MAX = 256;
258
+ /**
259
+ * `true` iff `value` can be the harness thread id a served record names:
260
+ * a non-empty string of at most {@link HARNESS_THREAD_ID_MAX} code points
261
+ * — counted as the Python package's `len()` counts, not in UTF-16 units —
262
+ * with no whitespace or control character (the class the SDK holds a
263
+ * subject token to: the id is matched against a header value the proxy
264
+ * saw, and a header value can never hold those) and no lone surrogate,
265
+ * which has no UTF-8 form. Claude Code's session id and OpenClaw's 32-hex
266
+ * trace id pass; the packages accept exactly the same ids.
267
+ */
268
+ declare function validHarnessThreadId(value: unknown): value is string;
269
+ /** Now, in unix seconds — the served record's `ts` resolution. */
270
+ declare function unixSeconds(): number;
271
+ /** One built served record: its wire bytes and the id that de-duplicates it. */
272
+ interface BuiltServedRecord {
273
+ readonly recordId: string;
274
+ readonly payload: Uint8Array;
275
+ }
276
+ /**
277
+ * One served record, ready to publish. The record id comes back alongside
278
+ * the payload: the publisher signs with it as the `Agent-Sender` nonce,
279
+ * which the SDK's signed publish also stamps as `Nats-Msg-Id`, so body,
280
+ * header and message id carry one id and a stream de-duplicates a record
281
+ * it already stored. Its 32 hex characters fit the nonce's
282
+ * `[A-Za-z0-9_-]{1,64}`.
283
+ *
284
+ * `agent` is the plugin's own identity, the executing agent, in canonical
285
+ * `{account}.{user}` form — the same identity that signs the record.
286
+ * `threadId` and `rootId` are the served prompt's, from its scope.
287
+ * `harnessThreadId` is the harness's own id, bare — never prefixed — and
288
+ * must pass {@link validHarnessThreadId}. `status` is required on `end`
289
+ * and must be absent on `start`. `ts` is unix seconds: when the prompt
290
+ * arrived for `start`, when the turn ended for `end`; now by default.
291
+ * `reason` ({@link ServedReason}) says how an `end` came about when the
292
+ * model did not reply itself; it is refused on `start`, like `status`, and
293
+ * a record that carries it is version {@link SERVED_RECORD_REASON_VERSION}.
294
+ *
295
+ * Throws `Error` for a record the contract would refuse, so a plugin's
296
+ * mistake is its own and never a malformed record on the wire.
297
+ */
298
+ declare function buildServedRecord(agent: AgentId, threadId: string, rootId: string, harness: Harness, harnessThreadId: string, phase: ServedPhase, status?: ServedStatus, ts?: number, reason?: ServedReason): BuiltServedRecord;
299
+ interface ServedPublisherOptions {
300
+ /**
301
+ * The plugin's own client: it signs every record as its identity, which
302
+ * is also the record's `agent`. Without a signer nothing is published —
303
+ * an unsigned record cannot be attributed — the publisher warns once and
304
+ * each record owed counts as dropped.
305
+ */
306
+ readonly agents: Agents;
307
+ /**
308
+ * Where the records go: the edge subject, the same the plugin's tracing
309
+ * runs with. {@link DEFAULT_EDGE_SUBJECT} by default.
310
+ */
311
+ readonly subject?: string;
312
+ /** Where a refused binding or a failed publish is reported; the console by default. */
313
+ readonly logger?: Logger;
314
+ }
315
+ /**
316
+ * One prompt's served pair. `bind` names the harness thread id once and
317
+ * publishes `start`, stamped with the prompt's arrival — the moment
318
+ * {@link ServedPublisher.beginTurn} was called — however late the id
319
+ * becomes known; `settle` records the outcome when the turn ends and
320
+ * publishes `end` if the id is known. An id bound after settling is
321
+ * refused: the pair is the turn's window, not something to backfill. Both
322
+ * are synchronous and return at once; the records go out behind them.
323
+ */
324
+ interface ServedTurn {
325
+ /**
326
+ * The harness's own id for this prompt's turn, bare. An unusable id
327
+ * (see {@link validHarnessThreadId}) is refused with a warning and the
328
+ * prompt gets no pair; a second binding is ignored, with a warning when
329
+ * it names another id.
330
+ */
331
+ bind(harnessThreadId: string): void;
332
+ /**
333
+ * End the turn. `atMs` is the turn's end in milliseconds since the epoch,
334
+ * as the plugin's events report it; now by default. `reason` is how the
335
+ * prompt ended when the model did not reply itself ({@link ServedReason}),
336
+ * carried on `end`. A second call does nothing.
337
+ */
338
+ settle(status: ServedStatus, atMs?: number, reason?: ServedReason): void;
339
+ }
340
+ /**
341
+ * Publishes served records through the plugin's client, one after another
342
+ * in the order they were due, so a pair's `end` never overtakes its
343
+ * `start` on the wire and two prompts' pairs interleave as they happened.
344
+ * See {@link servedPublisher}.
345
+ */
346
+ declare class ServedPublisher {
347
+ #private;
348
+ constructor(options: ServedPublisherOptions);
349
+ /** Where the records go. */
350
+ get subject(): string;
351
+ /**
352
+ * Start a prompt's pair: `scope` is the served prompt's trace scope —
353
+ * the one the fabric's request interceptor bound around the handler,
354
+ * `activeTrace()` inside it — and `harness` the one whose id `bind` will
355
+ * name. The arrival, `start`'s `ts`, is now.
356
+ */
357
+ beginTurn(scope: TraceScope, harness: Harness): ServedTurn;
358
+ /**
359
+ * Publish one signed record, after every record handed over before it.
360
+ * Fail-open and asynchronous: the returned promise never rejects and
361
+ * nothing awaits it on the prompt path. A record that cannot go out — no
362
+ * signer, a client already closed, a publish that threw — is logged and
363
+ * counts as dropped; one that went out counts as published. Every record
364
+ * moves the process-wide {@link traceRecordCounts}.
365
+ */
366
+ publish(scope: TraceScope, harness: Harness, harnessThreadId: string, phase: ServedPhase, status: ServedStatus | undefined, ts: number, reason?: ServedReason): Promise<void>;
367
+ /**
368
+ * Resolves once every record handed to `publish` so far has been signed
369
+ * and handed to the connection, or dropped. For shutdown and tests.
370
+ */
371
+ flush(): Promise<void>;
372
+ }
373
+ /**
374
+ * The served records' publisher for a harness plugin's add-on, over the
375
+ * plugin's own client: `agents.publishSigned` with the record id as nonce,
376
+ * on `subject` ({@link DEFAULT_EDGE_SUBJECT} by default), the records in
377
+ * the order they were due, every one counted on the process-wide
378
+ * {@link traceRecordCounts}. Per served prompt the add-on calls
379
+ * {@link ServedPublisher.beginTurn} with the prompt's scope, `bind`s the
380
+ * harness's id once it knows it, and `settle`s with the outcome;
381
+ * {@link ServedPublisher.flush} before the plugin stops.
382
+ */
383
+ declare function servedPublisher(options: ServedPublisherOptions): ServedPublisher;
384
+
385
+ /** Prefix of the expanded reference token. */
386
+ declare const REFERENCE_PREFIX = "sp-ref:";
387
+ declare const SHORT_REFERENCE_PREFIX = "sp-r1:";
388
+ /**
389
+ * The service metadata key an agent that reads the references it is handed
390
+ * registers, with the value `"true"` (the SDK's `extraMetadata`). A caller
391
+ * hands a reference, and grants read on it, only to an agent that says so.
392
+ * In the style of the protocol's `attachments_ok`.
393
+ */
394
+ declare const READS_REFERENCES_KEY = "scratchpad_refs_ok";
395
+ /** The served prompt's thread and root, as `activeTrace()` reports them. */
396
+ interface TraceIds {
397
+ readonly threadId: string;
398
+ readonly rootId: string;
399
+ }
400
+ /**
401
+ * The principal ScratchPad grants to: the two halves of an agent identity,
402
+ * `<account>.<user>`, both public NKEYs on the fabric.
403
+ */
404
+ interface Grantee {
405
+ readonly account: string;
406
+ readonly user: string;
407
+ }
408
+ /**
409
+ * How a grant came about. `first-hand`: the agent granted an agent it
410
+ * handed the reference itself — the verified caller of its reply, or the
411
+ * agent it prompted with a reference of its own. `on-request`: the agent
412
+ * granted an agent because another agent asked it to (`grant-request.ts`).
413
+ * Only a first-hand grant entitles its holder to ask for another agent, or
414
+ * access could be relayed from agent to agent without end.
415
+ */
416
+ type GrantKind = "first-hand" | "on-request";
417
+ type MaybePromise<T> = T | Promise<T>;
418
+ /**
419
+ * What the policy needs of the agent's ScratchPad: its own volume, and a
420
+ * ledger of the read grants it made. ScratchPad knows the grants but not
421
+ * how they came about; that is the agent's own knowledge, so the
422
+ * implementation keeps the ledger.
423
+ */
424
+ interface ScratchPad {
425
+ /** Resolve reference metadata through the implementation's authenticated client. */
426
+ resolveReference?(reference: string, trace?: TraceIds): MaybePromise<{
427
+ readonly creator: string;
428
+ }>;
429
+ /** Whether `reference` points into this agent's own volume, where it may grant. */
430
+ owns(reference: string): MaybePromise<boolean>;
431
+ /**
432
+ * Grant `grantee` read on the one path `reference` names, until the
433
+ * grant's expiry, and note it in the ledger as `kind` (`first-hand` when
434
+ * not given). Only for a reference into this agent's own volume. `trace`
435
+ * and `toolCallId` label the grant, so it shows under the served prompt
436
+ * and the tool call that caused it.
437
+ */
438
+ grantRead(reference: string, grantee: Grantee, trace: TraceIds | undefined, toolCallId?: string, kind?: GrantKind): MaybePromise<void>;
439
+ /**
440
+ * The live grant this agent made to `grantee` on what `reference` points
441
+ * at, by kind; `undefined` when there is none or it has expired. A
442
+ * first-hand grant still running is not hidden by a later one made on
443
+ * request.
444
+ */
445
+ granted(reference: string, grantee: Grantee): MaybePromise<GrantKind | undefined>;
446
+ }
447
+ /** Every reference token in `text`, in order, repeats included. */
448
+ declare function findReferences(text: string): string[];
449
+ /**
450
+ * `text` with reference tokens taken out — every one, or only those in
451
+ * `only` — and the trailing spaces and extra blank lines that leaves
452
+ * behind tidied away.
453
+ */
454
+ declare function removeReferences(text: string, only?: ReadonlyArray<string>): string;
455
+ /**
456
+ * The prompt address of the agent that made `reference`, as the token says;
457
+ * `undefined` for a token that names none or does not decode.
458
+ */
459
+ declare function referenceCreator(reference: string): string | undefined;
460
+ /** Whether an agent's registration metadata says it reads references. */
461
+ declare function readsReferences(metadata: Readonly<Record<string, string>>): boolean;
462
+ /**
463
+ * The grantee behind an identity as discovery or a verified sender reports
464
+ * it. Throws for anything that is not `<account>.<user>`.
465
+ */
466
+ declare function granteeFromIdentity(identity: string): Grantee;
467
+
468
+ /** What the requester sends (`sp-grant-request.json`). */
469
+ interface GrantRequest {
470
+ /** The reference, exactly as the requester was given it. */
471
+ readonly reference: string;
472
+ /** The identity, `<account>.<user>`, of the agent that should be able to read it. */
473
+ readonly grantee: string;
474
+ /**
475
+ * The requester's served thread and the tool call the handoff belongs to,
476
+ * so the creator's grant shows under the call that caused it. Labels
477
+ * only, never authority.
478
+ */
479
+ readonly trace?: {
480
+ readonly thread_id: string;
481
+ readonly root_id: string;
482
+ readonly tool_call_id?: string;
483
+ };
484
+ }
485
+ /** What the creator answers (`sp-grant-reply.json`). */
486
+ type GrantReply = {
487
+ readonly granted: true;
488
+ } | {
489
+ readonly granted: false;
490
+ readonly reason: string;
491
+ };
492
+ /** The name of the creator's extra endpoint, and the verb of its subject. */
493
+ declare const GRANT_REQUEST_ENDPOINT = "sp-grant";
494
+ /**
495
+ * How long the requester waits for the creator's answer. The creator runs
496
+ * one ScratchPad operation before it answers, so longer than the SDK's two
497
+ * seconds for a signed request.
498
+ */
499
+ declare const DEFAULT_GRANT_REQUEST_TIMEOUT_MS = 10000;
500
+ /**
501
+ * Where the agent at `promptAddress` takes grant requests: the same subject
502
+ * with the verb changed. Derived, never taken from what another agent says,
503
+ * so a request only ever goes to the creator's own subject. Throws for a
504
+ * subject that is not a prompt address.
505
+ */
506
+ declare function grantSubject(promptAddress: string): string;
507
+ /** A request's bytes, as both packages write them: the schema's key order. */
508
+ declare function encodeGrantRequest(request: GrantRequest): string;
509
+ /** A reply's bytes, as both packages write them. */
510
+ declare function encodeGrantReply(reply: GrantReply): string;
511
+ interface RequestGrantOptions {
512
+ /** How long to wait for the answer. Default {@link DEFAULT_GRANT_REQUEST_TIMEOUT_MS}. */
513
+ readonly timeoutMs?: number;
514
+ }
515
+ /**
516
+ * The requester's side: ask the agent at `creatorAddress` to grant what
517
+ * `request` names, signed as `agents`' identity. Never throws: no answer,
518
+ * or an answer that is not a grant, is a refusal with its reason in words.
519
+ */
520
+ declare function requestGrant(agents: Agents, creatorAddress: string, request: GrantRequest, options?: RequestGrantOptions): Promise<GrantReply>;
521
+ /**
522
+ * The creator's rule, for a requester whose signature verified. `requester`
523
+ * is that verified sender ID; `payload` the request's body. Never throws.
524
+ * {@link grantRequestEndpoint} runs it after the SDK's `SenderGate`; a host
525
+ * that takes grant requests some other way must verify the sender first.
526
+ */
527
+ declare function answerGrantRequest(requester: string, payload: string, scratchPad: ScratchPad, logger?: Logger): Promise<GrantReply>;
528
+ interface GrantRequestEndpointOptions {
529
+ /** This agent's own prompt address; the endpoint sits next to it. */
530
+ readonly promptAddress: string;
531
+ /** This agent's ScratchPad: the volume it may grant on, and its ledger. */
532
+ readonly scratchPad: ScratchPad;
533
+ /** Refusals at `info`, failures at `error`. Default: silent. */
534
+ readonly logger?: Logger;
535
+ }
536
+ /**
537
+ * The creator's side, as an extra endpoint for the agent's `AgentService`
538
+ * (`extraEndpoints: [grantRequestEndpoint({ ... })]`): it answers every
539
+ * grant request by the rule at the top of this file. Several instances of
540
+ * one agent share the work, in the `agents` queue group.
541
+ */
542
+ declare function grantRequestEndpoint(options: GrantRequestEndpointOptions): AgentServiceExtraEndpoint;
543
+
544
+ /** The field `discover_agents` entries get. */
545
+ declare const READS_SCRATCHPAD_REFERENCES_FIELD = "reads_scratchpad_references";
546
+ interface ScratchPadExtensionOptions {
547
+ /** The agent's own ScratchPad, behind the port. */
548
+ readonly scratchPad: ScratchPad;
549
+ /**
550
+ * The client grant requests are signed and sent with, and creators are
551
+ * looked up through: the one `AgentTools` runs on, with the agent's
552
+ * signer.
553
+ */
554
+ readonly agents: Agents;
555
+ /** How long a lookup of a creator waits; unset, the SDK's discovery default. */
556
+ readonly discoverTimeoutMs?: number;
557
+ /** How long a creator's answer is waited for. Default 10 seconds. */
558
+ readonly grantRequestTimeoutMs?: number;
559
+ }
560
+ /** The extension; build it with {@link scratchPadExtension}. */
561
+ declare class ScratchPadExtension implements AgentToolsExtension {
562
+ #private;
563
+ /**
564
+ * For the agent's `AgentService` (`interceptors: [...]`): remembers the
565
+ * references in every prompt it serves.
566
+ */
567
+ readonly requestInterceptor: RequestInterceptor;
568
+ constructor(options: ScratchPadExtensionOptions);
569
+ /**
570
+ * Note the references in `text` as given to this agent: what it
571
+ * committed, or received some way the hooks do not see.
572
+ */
573
+ remember(text: string): void;
574
+ /**
575
+ * The reply side: before a reply carrying `reference`, this agent's own,
576
+ * goes out, remember it and grant the served prompt's sender read on it,
577
+ * first-hand — only a sender whose signature verified, since a grant
578
+ * names a principal and an unsigned claim proves none. `true` when
579
+ * granted, so the reference may go into the reply; `false` for a sender
580
+ * that did not verify. Throws when the reference is not this agent's own
581
+ * or the grant fails. The commit itself stays the agent's.
582
+ */
583
+ grantCaller(reference: string, sender: SenderInfo | undefined): Promise<boolean>;
584
+ /** The discovery fields hook. */
585
+ discoveryFields(agent: Agent): Record<string, unknown>;
586
+ /** The prompt rewrite hook. */
587
+ beforePrompt(ctx: AgentToolsPromptContext): Promise<AgentToolsPromptRewrite | void>;
588
+ /** The reply look hook. */
589
+ afterReply(ctx: AgentToolsReplyContext): void;
590
+ }
591
+ /** The ScratchPad extension for `AgentTools` (`extensions: [...]`). */
592
+ declare function scratchPadExtension(options: ScratchPadExtensionOptions): ScratchPadExtension;
593
+
594
+ /**
595
+ * The agent's ScratchPad: the {@link ScratchPad} port, which the rules for
596
+ * references run on, and the commit and read the agent makes itself.
597
+ */
598
+ interface ScratchPadClient extends ScratchPad {
599
+ /**
600
+ * Publish `text` at `path` in this agent's volume, retained for ten
601
+ * minutes, and return the reference token the CLI made for it.
602
+ */
603
+ commit(text: string, path: string, trace: TraceIds | undefined): Promise<string>;
604
+ /** Fetch the exact content a reference token names, as text. */
605
+ read(reference: string, trace: TraceIds | undefined): Promise<string>;
606
+ }
607
+ interface SpCliScratchPadOptions {
608
+ /**
609
+ * The volume this agent writes to, by name: letters and digits only. The
610
+ * deployment provisions it for the agent's account and user; the first
611
+ * commit creates it.
612
+ */
613
+ readonly volume: string;
614
+ /**
615
+ * The agent's own connection source: `sp` authenticates the same way. It
616
+ * takes a URL with a credentials file; it reads no NATS context, and an
617
+ * nkey seed alone is not a form it accepts.
618
+ */
619
+ readonly nats: NatsConnectionSource;
620
+ /** The `sp` binary. Default `sp` on PATH. */
621
+ readonly bin?: string;
622
+ /**
623
+ * A private directory for the CLI's workspace; created if missing, and
624
+ * used by its real path. Keep it across restarts: it records the volume
625
+ * and any command still to finish. Default `scratchpad-<volume>` under
626
+ * the temp directory.
627
+ */
628
+ readonly dir?: string;
629
+ /** How long a read grant lasts, in seconds. Default and ceiling ten minutes. */
630
+ readonly grantTtlS?: number;
631
+ /**
632
+ * This agent's prompt address, written into every reference it makes, so
633
+ * an agent handed one knows whom to ask before passing it on. A commit
634
+ * needs it.
635
+ */
636
+ readonly creator?: string;
637
+ }
638
+ /** The `sp` binary when none is given: the one on PATH. */
639
+ declare const DEFAULT_SP_BIN = "sp";
640
+ /**
641
+ * How long a read grant lasts at most: long enough for the receiving agent
642
+ * to read what it was handed when it starts on the prompt, short enough
643
+ * that the access does not outlive the task. A grant also never outlives
644
+ * the reference it is on.
645
+ */
646
+ declare const DEFAULT_GRANT_TTL_S = 600;
647
+ /**
648
+ * A refusal or failure from `sp`: its error code, and whether the outcome
649
+ * is unknown — a mutation that may still have taken effect.
650
+ */
651
+ declare class ScratchPadError extends Error {
652
+ readonly code: string;
653
+ readonly unknown: boolean;
654
+ constructor(message: string, code: string, unknown: boolean);
655
+ }
656
+ /**
657
+ * Commit, read and grant by reference, through one `sp` binary and one
658
+ * volume: the {@link ScratchPadClient} an agent hands to
659
+ * `scratchPadExtension()` and `grantRequestEndpoint()` and commits and reads
660
+ * with itself.
661
+ */
662
+ declare function spCliScratchPad(options: SpCliScratchPadOptions): ScratchPadClient;
663
+ /** The variables {@link scratchPadFromEnv} reads. */
664
+ declare const SCRATCHPAD_VOLUME_VAR = "SCRATCHPAD_VOLUME";
665
+ declare const SCRATCHPAD_BIN_VAR = "SCRATCHPAD_BIN";
666
+ declare const SCRATCHPAD_DIR_VAR = "SCRATCHPAD_DIR";
667
+ declare const SCRATCHPAD_GRANT_TTL_S_VAR = "SCRATCHPAD_GRANT_TTL_S";
668
+ /** What {@link scratchPadFromEnv} takes besides the environment. */
669
+ interface ScratchPadFromEnvOptions {
670
+ /** This agent's prompt address, written into every reference it makes. */
671
+ readonly creator?: string;
672
+ /**
673
+ * The agent's connection source, when it is not the environment's
674
+ * `NATS_CONTEXT`, or `NATS_CREDS` with `NATS_URL`.
675
+ */
676
+ readonly nats?: NatsConnectionSource;
677
+ }
678
+ /**
679
+ * The agent's ScratchPad as the environment configures it, or `undefined`
680
+ * when `SCRATCHPAD_VOLUME` is unset: ScratchPad off. Reads
681
+ * `SCRATCHPAD_VOLUME`, `SCRATCHPAD_BIN`, `SCRATCHPAD_DIR` and
682
+ * `SCRATCHPAD_GRANT_TTL_S`, and, unless `options.nats` is given, the
683
+ * connection the agent's own configuration reads: `NATS_CREDS` with
684
+ * `NATS_URL` (default `nats://127.0.0.1:4222`), or `NATS_CONTEXT`, which
685
+ * `sp` cannot use. An empty variable counts as unset. Throws for a grant TTL
686
+ * that is not a positive number, and, like {@link spCliScratchPad}, for a
687
+ * connection `sp` cannot use: a NATS context without credentials, or no
688
+ * credentials at all.
689
+ */
690
+ declare function scratchPadFromEnv(env?: Readonly<Record<string, string | undefined>>, options?: ScratchPadFromEnvOptions): ScratchPadClient | undefined;
691
+
692
+ /** The §9 code the guard refuses with. */
693
+ declare const LOOP_GUARD_CODE = 409;
694
+ /** The description the refused caller sees, for `rootId`. */
695
+ declare function loopGuardDescription(rootId: string): string;
696
+ interface LoopGuard {
697
+ /** For the service, after the fabric's tracing interceptor. */
698
+ readonly requestInterceptor: RequestInterceptor;
699
+ /** For the plugin's client, next to the fabric's prompt interceptor. */
700
+ readonly promptInterceptor: PromptInterceptor;
701
+ /**
702
+ * For the add-on's `aroundToolCall`: runs `run` once, synchronously, and
703
+ * returns its value untouched, a promise included. `scope` is the served
704
+ * request's, the one tracing bound around its handler; with another or
705
+ * none the call is only run.
706
+ */
707
+ aroundToolCall<T>(scope: TraceScope | undefined, run: () => T): T;
708
+ /** `true` while a served request of tree `rootId` is open. */
709
+ serving(rootId: string): boolean;
710
+ /** `true` while a served request of tree `rootId` waits on a call it made. */
711
+ waiting(rootId: string): boolean;
712
+ }
713
+ declare function loopGuard(): LoopGuard;
714
+
715
+ declare const CODES: readonly ["ok", "invalid", "unauthenticated", "denied", "not_found", "exists", "conflict", "fenced", "intent_changed", "capacity", "summary_limit", "closed", "epoch_changed", "expired", "corrupt", "incomplete", "busy", "unknown", "unavailable", "internal"];
716
+ type Code = (typeof CODES)[number];
717
+ type ContentID = string;
718
+ interface Principal {
719
+ account: string;
720
+ user: string;
721
+ }
722
+ interface Trace {
723
+ thread_id?: string;
724
+ root_id?: string;
725
+ tool_call_id?: string;
726
+ }
727
+ interface Action {
728
+ operation_id: string;
729
+ trace: Trace;
730
+ }
731
+ interface Target {
732
+ volume: string;
733
+ creation_id: string;
734
+ }
735
+ interface Head {
736
+ generation: number;
737
+ root: ContentID;
738
+ }
739
+ interface Writer {
740
+ slot: number;
741
+ generation: number;
742
+ }
743
+ interface RetentionIntent {
744
+ enabled: boolean;
745
+ slot: number;
746
+ generation: number;
747
+ until: number;
748
+ }
749
+ interface RetentionHandle {
750
+ slot: number;
751
+ generation: number;
752
+ }
753
+ interface GrantHandle {
754
+ slot: number;
755
+ generation: number;
756
+ }
757
+ interface RetentionOrigin {
758
+ writer: Writer;
759
+ number: number;
760
+ }
761
+ interface Command {
762
+ creation_id: string;
763
+ writer: Writer;
764
+ number: number;
765
+ operation_id: string;
766
+ base: Head;
767
+ root: ContentID;
768
+ trace: Trace;
769
+ retention: RetentionIntent;
770
+ }
771
+ interface Receipt {
772
+ volume: string;
773
+ principal: Principal;
774
+ command: Command;
775
+ head: Head;
776
+ retention: RetentionHandle;
777
+ }
778
+ interface WriterSlot {
779
+ generation: number;
780
+ number: number;
781
+ principal?: Principal;
782
+ write: boolean;
783
+ receipt?: Receipt;
784
+ }
785
+ interface RetentionValue {
786
+ root: ContentID;
787
+ until: number;
788
+ origin: RetentionOrigin;
789
+ }
790
+ interface RetentionSlot {
791
+ generation: number;
792
+ pin?: RetentionValue;
793
+ }
794
+ interface GrantValue {
795
+ principal: Principal;
796
+ root: ContentID;
797
+ path: string;
798
+ directory: boolean;
799
+ retention: RetentionHandle;
800
+ until: number;
801
+ }
802
+ interface GrantSlot {
803
+ generation: number;
804
+ grant?: GrantValue;
805
+ }
806
+ interface VolumeView {
807
+ target: Target;
808
+ owner: Principal;
809
+ head: Head;
810
+ revision: number;
811
+ closed: boolean;
812
+ epoch: number;
813
+ objects: number;
814
+ bytes: number;
815
+ writers: WriterSlot[];
816
+ retentions: RetentionSlot[];
817
+ grants: GrantSlot[];
818
+ }
819
+ interface Limits {
820
+ object_bytes: number;
821
+ read_bytes: number;
822
+ control_bytes: number;
823
+ reply_bytes: number;
824
+ writers: number;
825
+ retentions: number;
826
+ grants: number;
827
+ grant_seconds: number;
828
+ }
829
+ interface ReservedScope {
830
+ volume: string;
831
+ objects: number;
832
+ bytes: number;
833
+ }
834
+ interface Info {
835
+ principal: Principal;
836
+ scopes: ReservedScope[];
837
+ limits: Limits;
838
+ }
839
+ interface ContentObject {
840
+ kind: "chnk" | "fobj" | "tree";
841
+ id: ContentID;
842
+ }
843
+ interface ObjectSpec {
844
+ object: ContentObject;
845
+ length: number;
846
+ }
847
+ type AllocationState = "reserved" | "verifying" | "verified" | "refused";
848
+ interface ObjectProgress extends ObjectSpec {
849
+ state: AllocationState;
850
+ next: number;
851
+ code: Code;
852
+ }
853
+ interface PrepareRequest {
854
+ target: Target;
855
+ objects: ObjectSpec[];
856
+ }
857
+ interface PrepareResult {
858
+ epoch: number;
859
+ objects: ObjectProgress[];
860
+ }
861
+ interface VerifyRequest {
862
+ target: Target;
863
+ epoch: number;
864
+ objects: ContentObject[];
865
+ }
866
+ interface VerifyResult {
867
+ epoch: number;
868
+ objects: ObjectProgress[];
869
+ }
870
+ interface PutRequest {
871
+ target: Target;
872
+ object: ContentObject;
873
+ epoch: number;
874
+ }
875
+ interface CreateRequest {
876
+ volume: string;
877
+ action: Action;
878
+ }
879
+ interface PublishRequest {
880
+ target: Target;
881
+ command: Command;
882
+ }
883
+ interface RetainRequest {
884
+ target: Target;
885
+ slot: number;
886
+ generation: number;
887
+ root: ContentID;
888
+ until: number;
889
+ action: Action;
890
+ }
891
+ interface ReleaseRequest {
892
+ target: Target;
893
+ handle: RetentionHandle;
894
+ }
895
+ interface GrantIssueRequest {
896
+ target: Target;
897
+ slot: number;
898
+ generation: number;
899
+ principal: Principal;
900
+ root: ContentID;
901
+ path: string;
902
+ retention: RetentionHandle;
903
+ until: number;
904
+ action: Action;
905
+ }
906
+ interface RevokeRequest {
907
+ target: Target;
908
+ handle: GrantHandle;
909
+ action: Action;
910
+ }
911
+ interface PathRequest {
912
+ target: Target;
913
+ root: ContentID;
914
+ path: string;
915
+ trace: Trace;
916
+ }
917
+ interface ReadRequest extends PathRequest {
918
+ offset: number;
919
+ length: number;
920
+ }
921
+ interface ListRequest extends PathRequest {
922
+ offset: number;
923
+ limit: number;
924
+ }
925
+ interface Stat {
926
+ type: "file" | "directory" | "symlink";
927
+ object: ContentID;
928
+ size: number;
929
+ sha256: string;
930
+ executable: boolean;
931
+ link_target?: string;
932
+ }
933
+ interface Entry {
934
+ name: string;
935
+ type: "file" | "directory" | "symlink";
936
+ object: ContentID;
937
+ executable: boolean;
938
+ link_target?: string;
939
+ }
940
+ interface ListResult {
941
+ entries: Entry[];
942
+ next: number;
943
+ done: boolean;
944
+ }
945
+ interface ReadResult {
946
+ stat: Stat;
947
+ offset: number;
948
+ data: Uint8Array;
949
+ }
950
+ interface MaintenanceRequest {
951
+ target: Target;
952
+ revision: number;
953
+ }
954
+ interface CollectionReport {
955
+ inventory_objects: number;
956
+ inventory_bytes: number;
957
+ live_objects: number;
958
+ live_bytes: number;
959
+ candidate_objects: number;
960
+ candidate_bytes: number;
961
+ delete_objects: number;
962
+ }
963
+ interface CollectionResult {
964
+ volume: VolumeView;
965
+ collection: CollectionReport;
966
+ }
967
+
968
+ interface Reference {
969
+ version: 2;
970
+ creator: string;
971
+ account: string;
972
+ target: Target;
973
+ root: string;
974
+ generation: number;
975
+ path: string;
976
+ retention: RetentionHandle;
977
+ expires_at: number;
978
+ }
979
+ declare function encodeReference(reference: Reference): string;
980
+ declare function decodeReference(token: string): Reference;
981
+
982
+ interface ShortReference {
983
+ route: string;
984
+ creation_id: string;
985
+ retention: RetentionHandle;
986
+ path_index: number;
987
+ }
988
+ interface ReferenceSpec {
989
+ creator: string;
990
+ paths: string[];
991
+ }
992
+ interface ResolvedReference {
993
+ short: string;
994
+ expanded: Reference;
995
+ }
996
+ interface ReferenceCapabilities {
997
+ enabled: boolean;
998
+ version: number;
999
+ prefix: string;
1000
+ token_bytes: number;
1001
+ paths_per_retention: number;
1002
+ max_intent_bytes: number;
1003
+ max_metadata_bytes: number;
1004
+ }
1005
+ interface ReferencePublishRequest extends PublishRequest {
1006
+ reference: ReferenceSpec;
1007
+ }
1008
+ interface ReferencePublishResult {
1009
+ receipt: Receipt;
1010
+ references: ResolvedReference[];
1011
+ }
1012
+ interface ReferenceResolveRequest {
1013
+ reference: string;
1014
+ trace: Trace;
1015
+ }
1016
+ interface ReferenceStatResult {
1017
+ reference: ResolvedReference;
1018
+ stat: Stat;
1019
+ }
1020
+ /** Decode the locator only. The service verifies its metadata verifier. */
1021
+ declare function decodeShortReference(token: string): ShortReference;
1022
+ interface ReferenceRetainRequest {
1023
+ retain: RetainRequest;
1024
+ reference: ReferenceSpec;
1025
+ }
1026
+ interface ReferenceRetainResult {
1027
+ volume: VolumeView;
1028
+ references: ResolvedReference[];
1029
+ }
1030
+
1031
+ interface RequestOptions {
1032
+ signal?: AbortSignal;
1033
+ }
1034
+ interface TransportOptions {
1035
+ timeoutMs?: number;
1036
+ }
1037
+ /** One request per operation on a borrowed NATS connection. No retry or identity override. */
1038
+ declare class ScratchPadTransport {
1039
+ private readonly nc;
1040
+ readonly timeoutMs: number;
1041
+ constructor(nc: NatsConnection, options?: TransportOptions);
1042
+ private within;
1043
+ private exchange;
1044
+ private control;
1045
+ private matching;
1046
+ private view;
1047
+ info(options?: RequestOptions): Promise<Info>;
1048
+ createVolume(request: CreateRequest, options?: RequestOptions): Promise<VolumeView>;
1049
+ getVolume(target: Target, options?: RequestOptions): Promise<VolumeView>;
1050
+ prepare(request: PrepareRequest, options?: RequestOptions): Promise<PrepareResult>;
1051
+ putPrepared(request: PutRequest, data: Uint8Array, options?: RequestOptions): Promise<void>;
1052
+ verify(request: VerifyRequest, options?: RequestOptions): Promise<VerifyResult>;
1053
+ publish(request: PublishRequest, options?: RequestOptions): Promise<Receipt>;
1054
+ /** Unknown reference verbs on older services return invalid. Other failures propagate. */
1055
+ referenceInfo(options?: RequestOptions): Promise<ReferenceCapabilities | undefined>;
1056
+ private referencePublication;
1057
+ referencePublish(request: ReferencePublishRequest, options?: RequestOptions): Promise<ReferencePublishResult>;
1058
+ referenceReceipt(request: ReferencePublishRequest, options?: RequestOptions): Promise<ReferencePublishResult>;
1059
+ referenceResolve(request: ReferenceResolveRequest, options?: RequestOptions): Promise<ResolvedReference>;
1060
+ referenceStat(request: ReferenceResolveRequest, options?: RequestOptions): Promise<ReferenceStatResult>;
1061
+ referenceRetain(request: ReferenceRetainRequest, options?: RequestOptions): Promise<ReferenceRetainResult>;
1062
+ resetWriter(target: Target, writer: Writer, options?: RequestOptions): Promise<Writer>;
1063
+ retain(request: RetainRequest, options?: RequestOptions): Promise<VolumeView>;
1064
+ release(request: ReleaseRequest, options?: RequestOptions): Promise<VolumeView>;
1065
+ issueGrant(request: GrantIssueRequest, options?: RequestOptions): Promise<GrantHandle>;
1066
+ revokeGrant(request: RevokeRequest, options?: RequestOptions): Promise<VolumeView>;
1067
+ stat(request: PathRequest, options?: RequestOptions): Promise<Stat>;
1068
+ list(request: ListRequest, options?: RequestOptions): Promise<ListResult>;
1069
+ read(request: ReadRequest, options?: RequestOptions): Promise<ReadResult>;
1070
+ closeVolume(request: MaintenanceRequest, options?: RequestOptions): Promise<VolumeView>;
1071
+ planCollection(request: MaintenanceRequest, options?: RequestOptions): Promise<CollectionReport>;
1072
+ applyCollection(request: MaintenanceRequest, options?: RequestOptions): Promise<CollectionResult>;
1073
+ }
1074
+
1075
+ declare const DEFAULT_READ_LIMIT_BYTES: number;
1076
+ interface ScratchPadReaderOptions {
1077
+ nc: NatsConnection;
1078
+ timeoutMs?: number;
1079
+ }
1080
+ interface ReadBytesOptions {
1081
+ limitBytes?: number;
1082
+ trace?: TraceIds;
1083
+ }
1084
+ /** Authenticated reads through a borrowed NATS connection; no workspace needed. */
1085
+ declare class ScratchPadReader {
1086
+ protected readonly transport: ScratchPadTransport;
1087
+ readonly principal: Principal;
1088
+ private readonly expansions;
1089
+ constructor(transport: ScratchPadTransport, principal: Principal);
1090
+ protected reference(token: string): Reference;
1091
+ protected checkedReference(reference: Reference): Reference;
1092
+ private checkDeadline;
1093
+ protected cacheReference(pair: ResolvedReference): void;
1094
+ /** Expand either form for programmatic use. Metadata supplies no read authority. */
1095
+ resolveReference(token: string, trace?: TraceIds): Promise<Reference>;
1096
+ private openFile;
1097
+ private chunks;
1098
+ /** Returns bytes only after size, logical digest and canonical file identity agree. */
1099
+ readBytes(token: string, options?: ReadBytesOptions): Promise<Uint8Array>;
1100
+ /** Bytes are provisional until iteration completes without error. Consume to EOF
1101
+ * and publish a downloaded file only after success; early cancellation is unverified.
1102
+ * The caller must set an explicit whole-file size allowance.
1103
+ */
1104
+ readStream(token: string, options: ReadBytesOptions & {
1105
+ limitBytes: number;
1106
+ }): AsyncGenerator<Uint8Array>;
1107
+ read(reference: string, trace?: TraceIds): Promise<string>;
1108
+ }
1109
+ declare function scratchPadReader(options: ScratchPadReaderOptions): Promise<ScratchPadReader>;
1110
+
1111
+ /** One private local database, exclusively owned for the client's lifetime. */
1112
+ declare class WorkspaceStore {
1113
+ private readonly db;
1114
+ private readonly directory;
1115
+ private poisoned;
1116
+ private closed;
1117
+ private constructor();
1118
+ static open(directory: string): Promise<WorkspaceStore>;
1119
+ private usable;
1120
+ load(): unknown;
1121
+ save(state: unknown, afterRemote?: boolean, clearObjects?: boolean): void;
1122
+ clearObjects(): void;
1123
+ putObject(ordinal: number, object: ContentObject, data: Uint8Array): void;
1124
+ objects(): ObjectSpec[];
1125
+ bytes(object: ContentObject): Uint8Array;
1126
+ close(): void;
1127
+ }
1128
+
1129
+ interface NativeScratchPadOptions extends ScratchPadReaderOptions {
1130
+ /** Private directory on a persistent local filesystem. One client owns it at a time. */
1131
+ dir: string;
1132
+ volume: string;
1133
+ /** Prompt address used only to route Fabric grant requests. It is not authentication. */
1134
+ creator: string;
1135
+ ttlSeconds?: number;
1136
+ }
1137
+ interface PublishOptions {
1138
+ operationId: string;
1139
+ ttlSeconds?: number;
1140
+ trace?: TraceIds;
1141
+ }
1142
+ interface PublishResult {
1143
+ reference: string;
1144
+ receipt: Receipt;
1145
+ }
1146
+ interface RecoveryResult {
1147
+ kind: string;
1148
+ reference?: string;
1149
+ receipt?: Receipt;
1150
+ }
1151
+ interface Publication {
1152
+ kind: "publish";
1153
+ command: Command;
1154
+ path: string;
1155
+ ttl: number;
1156
+ expiry_revision?: number;
1157
+ reference?: ReferenceSpec;
1158
+ }
1159
+ interface Granted {
1160
+ request: GrantIssueRequest;
1161
+ handle: GrantHandle;
1162
+ kind: GrantKind;
1163
+ }
1164
+ type Control = {
1165
+ kind: "grant";
1166
+ request: GrantIssueRequest;
1167
+ provenance: GrantKind;
1168
+ } | {
1169
+ kind: "release";
1170
+ request: ReleaseRequest;
1171
+ } | {
1172
+ kind: "close" | "apply";
1173
+ request: MaintenanceRequest;
1174
+ };
1175
+ type Pending = Publication | Control | {
1176
+ kind: "reset";
1177
+ writer: Writer;
1178
+ };
1179
+ interface State {
1180
+ version: 1;
1181
+ principal: Principal;
1182
+ volume: string;
1183
+ creator: string;
1184
+ creation: Action;
1185
+ target?: Target;
1186
+ writer?: Writer;
1187
+ next: number;
1188
+ pending?: Pending;
1189
+ last?: PublishResult & {
1190
+ path: string;
1191
+ ttl: number;
1192
+ resolved?: ResolvedReference;
1193
+ };
1194
+ grants: Granted[];
1195
+ }
1196
+ /** A native writer and Fabric adapter. It borrows the caller's authenticated connection. */
1197
+ declare class NativeScratchPad extends ScratchPadReader implements ScratchPadClient {
1198
+ private readonly store;
1199
+ private state;
1200
+ private readonly scope;
1201
+ private readonly ttl;
1202
+ private tail;
1203
+ private closing;
1204
+ private closePromise?;
1205
+ constructor(transport: ScratchPadTransport, store: WorkspaceStore, state: State, scope: ReservedScope, ttl: number);
1206
+ private run;
1207
+ private save;
1208
+ private change;
1209
+ private target;
1210
+ private ensureTarget;
1211
+ private initialize;
1212
+ private reset;
1213
+ /** Explicitly abandon writer recovery, fencing the exact generation observed by describe(). */
1214
+ resetWriter(options: {
1215
+ expectedGeneration: number;
1216
+ target?: Target;
1217
+ }): Promise<Writer>;
1218
+ describe(): Promise<{
1219
+ volume: VolumeView;
1220
+ pending?: string;
1221
+ }>;
1222
+ recover(): Promise<RecoveryResult>;
1223
+ private recoverPending;
1224
+ publishBytes(bytes: Uint8Array, path: string, options: PublishOptions): Promise<PublishResult>;
1225
+ /** A publication replaces the head with one file at path. Older references keep their retained roots. */
1226
+ publishStream(source: AsyncIterable<Uint8Array> | Iterable<Uint8Array>, path: string, options: PublishOptions): Promise<PublishResult>;
1227
+ private publish;
1228
+ private samePublication;
1229
+ private resumePublish;
1230
+ private fenceExpired;
1231
+ private accept;
1232
+ private upload;
1233
+ commit(value: string, path: string, trace: TraceIds | undefined): Promise<string>;
1234
+ owns(token: string): boolean | Promise<boolean>;
1235
+ granted(token: string, grantee: Grantee): GrantKind | undefined | Promise<GrantKind | undefined>;
1236
+ grantRead(token: string, grantee: Grantee, trace?: TraceIds, toolCallId?: string, kind?: GrantKind): Promise<void>;
1237
+ /** Release a completed handoff. Refuses while any live grant names its retention. */
1238
+ release(token: string): Promise<void>;
1239
+ /** Collect unreferenced content in this client's own maintenance interval. */
1240
+ maintain(): Promise<VolumeView>;
1241
+ private maintainInternal;
1242
+ private control;
1243
+ close(): Promise<void>;
1244
+ }
1245
+ /** Construct a native client without creating a remote volume until first use. */
1246
+ declare function nativeScratchPad(options: NativeScratchPadOptions): Promise<NativeScratchPad>;
1247
+ /** Environment configuration for SDK agents, using their existing connection. */
1248
+ declare function nativeScratchPadFromEnv(env: Readonly<Record<string, string | undefined>>, options: ScratchPadReaderOptions & {
1249
+ creator: string;
1250
+ }): Promise<NativeScratchPad | undefined>;
1251
+
1252
+ /** A failed request. `unknown` means a mutation may already have taken effect. */
1253
+ declare class NativeScratchPadError extends Error {
1254
+ readonly code: Code;
1255
+ readonly unknown: boolean;
1256
+ readonly local: boolean;
1257
+ constructor(code: Code, message: string, options?: {
1258
+ unknown?: boolean;
1259
+ local?: boolean;
1260
+ cause?: unknown;
1261
+ });
1262
+ }
1263
+
1264
+ /** The one setting: the edge subject, in the config entry's `options`. */
1265
+ declare const EDGE_SUBJECT_OPTION = "edgeSubject";
1266
+ /** The same setting as a variable, read when the option is not given. */
1267
+ declare const EDGE_SUBJECT_VAR = "SYNADIA_FABRIC_EDGE_SUBJECT";
1268
+ /**
1269
+ * The edge subject an add-on runs with: the config entry's
1270
+ * `options.edgeSubject` when the key is there (`null` is propagate-only:
1271
+ * lineage without records), else `SYNADIA_FABRIC_EDGE_SUBJECT` when set,
1272
+ * else the fabric's default. The value is returned as given; the package
1273
+ * validates it (`assertValidTraceOptions`) and throws for one that can
1274
+ * never be published to, which stops the add-on's factory — the plugin
1275
+ * then logs the error and starts plain, so a misconfigured subject is
1276
+ * visible at start rather than as a warning on every prompt.
1277
+ */
1278
+ declare function resolveEdgeSubject(options: Readonly<Record<string, unknown>>, env?: NodeJS.ProcessEnv): string | null;
1279
+
1280
+ /**
1281
+ * The harnesses that expose this extension point. Named apart from the
1282
+ * served record's `Harness` (`served.ts`), which is the proxy's word for a
1283
+ * harness, not the plugin's.
1284
+ */
1285
+ type PluginHarness = "pi" | "openclaw" | "claude-code";
1286
+ /** The plugin's resolved settings, as the factory sees them before connect. */
1287
+ interface AgentExtensionSettings {
1288
+ /** The address tokens: `agents.prompt.<token>.<owner>.<name>`. */
1289
+ readonly owner: string;
1290
+ /**
1291
+ * The name token as configured. The plugin checks it for a collision once
1292
+ * on the bus and may suffix it; the definitive address is
1293
+ * `service.subject.prompt` in `started()`.
1294
+ */
1295
+ readonly name: string;
1296
+ readonly senderIdentity: "off" | "signed";
1297
+ readonly minSenderTrust: "any" | "signed";
1298
+ /** Where the plugin keeps its files, when it has such a directory. */
1299
+ readonly stateDir?: string;
1300
+ /** The plugin's configuration as read, unknown keys included; read-only. */
1301
+ readonly config: Readonly<Record<string, unknown>>;
1302
+ }
1303
+ /** What the plugin knows when it loads the module, before it connects. */
1304
+ interface AgentExtensionContext {
1305
+ readonly harness: PluginHarness;
1306
+ readonly plugin: {
1307
+ readonly name: string;
1308
+ readonly version: string;
1309
+ };
1310
+ readonly settings: AgentExtensionSettings;
1311
+ /** The `options` of this module's config entry, verbatim; `{}` when the variable named it. */
1312
+ readonly options: Readonly<Record<string, unknown>>;
1313
+ /** The plugin's logger, in the SDK's `Logger` shape. */
1314
+ readonly logger: Logger;
1315
+ }
1316
+ /** A served prompt, as the harness's events name it. */
1317
+ interface ServedRequest {
1318
+ /** The plugin's id for the request, unique in the process. */
1319
+ readonly id: string;
1320
+ /** The envelope's fields the protocol does not define (§5.6), as decoded. */
1321
+ readonly extras: Readonly<Record<string, unknown>>;
1322
+ /** The verified sender's id, when the signature verified. */
1323
+ readonly caller?: string;
1324
+ /** Claude Code only: the session the prompt was delivered to, when known. */
1325
+ readonly sessionId?: string;
1326
+ }
1327
+ type Outcome = "ok" | "error" | "timeout";
1328
+ /**
1329
+ * Claude Code: how a prompt ended when the model did not end it with its
1330
+ * own reply, `promptEnded`'s fourth argument; absent when it did.
1331
+ * `final_text`: the turn ended without a reply and the plugin sent the
1332
+ * turn's final text as the reply (outcome `ok`); `no_reply`: no reply and
1333
+ * no final text; `shutdown`: the plugin stopped with the prompt open;
1334
+ * `delivery`: the prompt could not be handed to the harness (all three
1335
+ * `error`); `expired`: the prompt outlived the plugin's limit (`timeout`).
1336
+ * The same values as the served record's `reason`.
1337
+ */
1338
+ type EndReason = "final_text" | "no_reply" | "shutdown" | "delivery" | "expired";
1339
+ /**
1340
+ * The harness's events. A notification is called and forgotten; a wrapper
1341
+ * is called by the plugin around one of its own steps and must call `run`
1342
+ * once, synchronously, and return its value, a promise included. A wrapper
1343
+ * may be an async function: the plugin still takes `run`'s own value, and
1344
+ * the wrapper must call `run` once, before its first `await`, so the step
1345
+ * keeps its timing. Every harness calls the first three; PI also
1346
+ * `aroundInject` and `providerHeaders`, OpenClaw `aroundDispatch`, Claude
1347
+ * Code `sessionStarted` and `turnStopped`. One shape serves all three.
1348
+ */
1349
+ interface HarnessEvents {
1350
+ /** Inside the prompt handler, after every interceptor ran. */
1351
+ promptAccepted?(request: ServedRequest): void;
1352
+ /**
1353
+ * When the plugin settles the request. Claude Code passes `reason` when
1354
+ * the model did not end the prompt with its own reply.
1355
+ */
1356
+ promptEnded?(request: ServedRequest, outcome: Outcome, atMs: number, reason?: EndReason): void;
1357
+ /** Around every agent-tool call, with the request the model works in. */
1358
+ aroundToolCall?<T>(request: ServedRequest | undefined, toolName: string, run: () => T): T;
1359
+ /** PI: around the hand-over of the prompt to PI's loop (`pi.sendUserMessage()`). */
1360
+ aroundInject?<T>(request: ServedRequest, run: () => T): T;
1361
+ /** PI: headers to add to a provider request while `request` is PI's active turn. */
1362
+ providerHeaders?(request: ServedRequest): Readonly<Record<string, string>> | undefined;
1363
+ /**
1364
+ * OpenClaw: around the turn's dispatch
1365
+ * (`dispatchInboundDirectDmWithRuntime()`). Asynchronous: the extension
1366
+ * calls `run` once and returns its promise.
1367
+ */
1368
+ aroundDispatch?<T>(request: ServedRequest, run: () => Promise<T>): Promise<T>;
1369
+ /** Claude Code: a session started, from its hook. */
1370
+ sessionStarted?(sessionId: string, source: string): void;
1371
+ /** Claude Code: a turn stopped, from its hook. */
1372
+ turnStopped?(sessionId: string | undefined, atMs: number): void;
1373
+ }
1374
+ /** The live handles, once the plugin is on the bus. */
1375
+ interface AgentExtensionHandles {
1376
+ readonly agents: Agents;
1377
+ readonly service: AgentService;
1378
+ }
1379
+ /** What the factory returns. */
1380
+ interface AgentExtension {
1381
+ readonly name: string;
1382
+ /** For the plugin's `Agents` client: `new Agents({ interceptors })`. */
1383
+ readonly promptInterceptors?: ReadonlyArray<PromptInterceptor>;
1384
+ /** For the plugin's `AgentService`, before the plugin's own interceptors. */
1385
+ readonly requestInterceptors?: ReadonlyArray<RequestInterceptor>;
1386
+ /** For the plugin's `AgentService`: `heartbeatExtras`. */
1387
+ readonly heartbeatExtras?: () => Readonly<Record<string, unknown>>;
1388
+ /** For the plugin's `AgentTools`: `extensions`. */
1389
+ readonly toolExtensions?: ReadonlyArray<AgentToolsExtension>;
1390
+ /**
1391
+ * Keys for the service's registration metadata, read once before the
1392
+ * service starts. A key is one or more of `A-Z a-z 0-9 _ - .`, a value a
1393
+ * string; anything else fails the plugin's start. The plugin's own keys
1394
+ * and the protocol's registration keys win over an entry of the same name
1395
+ * (`agents/EXTENSIONS.md` in `synadia-agents`, from #218).
1396
+ */
1397
+ readonly metadata?: Readonly<Record<string, string>>;
1398
+ /** After the service started. Awaited, bounded by the plugin. */
1399
+ started?(handles: AgentExtensionHandles): void | Promise<void>;
1400
+ /** Before the plugin stops its service. Awaited, bounded by the plugin. */
1401
+ stopping?(): void | Promise<void>;
1402
+ /** The harness's events. */
1403
+ readonly events?: HarnessEvents;
1404
+ }
1405
+ /** The module's one default export. */
1406
+ type AgentExtensionFactory = (ctx: AgentExtensionContext) => AgentExtension | Promise<AgentExtension>;
1407
+
1408
+ /** The config entry's option that holds ScratchPad's settings. */
1409
+ declare const SCRATCHPAD_OPTION = "scratchpad";
1410
+ /**
1411
+ * The variables `scripts/sp` reads. The connection has names of its own,
1412
+ * not `NATS_URL` and `NATS_CREDS`, which a plugin may read as its own
1413
+ * connection (OpenClaw's does) and which the add-on therefore never sets.
1414
+ */
1415
+ declare const SP_VARS: {
1416
+ readonly url: "SP_NATS_URL";
1417
+ readonly creds: "SP_NATS_CREDS";
1418
+ readonly dir: "SCRATCHPAD_DIR";
1419
+ readonly volume: "SCRATCHPAD_VOLUME";
1420
+ readonly creator: "SP_CREATOR";
1421
+ readonly threadId: "SP_THREAD_ID";
1422
+ readonly rootId: "SP_ROOT_ID";
1423
+ readonly callerAccount: "SP_CALLER_ACCOUNT";
1424
+ readonly callerUser: "SP_CALLER_USER";
1425
+ readonly grants: "SP_GRANTS_FILE";
1426
+ };
1427
+ /** What ScratchPad was resolved to at start. */
1428
+ interface ScratchPadSettings {
1429
+ readonly url: string;
1430
+ readonly creds: string;
1431
+ readonly volume: string;
1432
+ /** Unset when neither a setting nor the plugin's state directory gives one. */
1433
+ readonly dir?: string;
1434
+ /**
1435
+ * The file `scripts/sp` records its grants in, beside the workspace:
1436
+ * `<dir>.grants`. Unset without a workspace, and then the grants the
1437
+ * model makes do not entitle anyone to a grant request.
1438
+ */
1439
+ readonly grants?: string;
1440
+ }
1441
+ type Env = Record<string, string | undefined>;
1442
+ /**
1443
+ * ScratchPad's settings as the options, the environment and the plugin's
1444
+ * NATS context give them, or `undefined` when ScratchPad is off: no volume,
1445
+ * or a connection `sp` cannot use, which is logged.
1446
+ */
1447
+ declare function resolveScratchPad(ctx: AgentExtensionContext, env: Env): Promise<ScratchPadSettings | undefined>;
1448
+ /** Sets the start-time variables. */
1449
+ declare function exportScratchPad(settings: ScratchPadSettings, env: Env): void;
1450
+ /**
1451
+ * The per-prompt variables, keyed to one request at a time: `enter` sets
1452
+ * them for a request, `leave` clears them only if that request still holds
1453
+ * them, so the end of a prompt never clears the next one's.
1454
+ */
1455
+ declare class ServedPromptEnv {
1456
+ #private;
1457
+ private readonly env;
1458
+ constructor(env: Env);
1459
+ enter(request: ServedRequest, scope: TraceScope | undefined): void;
1460
+ leave(request: ServedRequest): void;
1461
+ }
1462
+ /**
1463
+ * The sp binary an add-on ships for this machine in `skillDir` (its
1464
+ * `skill/scratchpad`), or `SCRATCHPAD_BIN`; `undefined` on a platform it is
1465
+ * not built for. The add-on's own grants run it directly, with the flags
1466
+ * `scripts/sp` would add.
1467
+ */
1468
+ declare function spBinary(env: Env, skillDir: string): string | undefined;
1469
+ /**
1470
+ * The fabric package's ScratchPad extension, for the plugin's `AgentTools`
1471
+ * and its service, before it can exist: it needs the plugin's `Agents`
1472
+ * client and this agent's address, which arrive in `started()`, after the
1473
+ * factory returned its hooks. Until then it keeps the prompts it serves, to
1474
+ * remember their references once it is built.
1475
+ *
1476
+ * One addition to the extension: the harness's model publishes with
1477
+ * `scripts/sp`, which the extension does not see, and the extension hands on
1478
+ * only what the agent was given. So a reference into its own volume is remembered as
1479
+ * given before the prompt rewrite looks, exactly as an SDK-built agent
1480
+ * remembers what it commits.
1481
+ */
1482
+ declare class ScratchPadHandOn implements AgentToolsExtension {
1483
+ #private;
1484
+ readonly requestInterceptor: RequestInterceptor;
1485
+ /**
1486
+ * Builds the extension, once the plugin's client is on the bus. Given the
1487
+ * plugin's service, also answers grant requests for what this agent
1488
+ * published, on the endpoint an SDK-built agent serves them on
1489
+ * (`grantRequestEndpoint`), added through the service's own
1490
+ * `addEndpoint`, since the plugin builds its service before the add-on
1491
+ * could name an extra endpoint. Several instances of one agent share the
1492
+ * work, as an SDK-built agent's do.
1493
+ */
1494
+ start(options: {
1495
+ readonly scratchPad: ScratchPad;
1496
+ readonly agents: Agents;
1497
+ readonly service?: AgentService;
1498
+ readonly logger?: Logger;
1499
+ }): void;
1500
+ discoveryFields(agent: Agent): Record<string, unknown>;
1501
+ beforePrompt(ctx: AgentToolsPromptContext): Promise<AgentToolsPromptRewrite | void>;
1502
+ afterReply(ctx: AgentToolsReplyContext): void;
1503
+ }
1504
+ /**
1505
+ * The ScratchPad port over the add-on's packaged sp, for its own grants and
1506
+ * the grant requests it answers, with the grants `scripts/sp` recorded.
1507
+ */
1508
+ declare function spPort(settings: ScratchPadSettings, creator: string, env: Env, skillDir: string): ScratchPad | undefined;
1509
+ /** One grant `scripts/sp` recorded. */
1510
+ interface RecordedGrant {
1511
+ readonly expiresAt: number;
1512
+ readonly grantee: Grantee;
1513
+ readonly reference: string;
1514
+ }
1515
+ /** The grants recorded in `file`; none when it does not exist. Malformed lines are skipped. */
1516
+ declare function readRecordedGrants(file: string): RecordedGrant[];
1517
+ /**
1518
+ * `port`, whose ledger also holds the grants `scripts/sp` recorded in `file`.
1519
+ * The wrapper grants only to the served prompt's caller, the agent the
1520
+ * harness's model handed its reply to, so each is first-hand, as an
1521
+ * SDK-built agent's grant to the caller of its reply is: its holder may ask
1522
+ * for one more agent. A first-hand grant of the port's own comes first;
1523
+ * the port's answer stands when nothing live is recorded. The reference
1524
+ * must be the one granted on, token for token, as the requester was given
1525
+ * it. `now` is seconds since the epoch.
1526
+ */
1527
+ declare function withRecordedGrants(port: ScratchPad, file: string, now?: () => number): ScratchPad;
1528
+
1529
+ export { type AgentExtension, type AgentExtensionContext, type AgentExtensionFactory, type AgentExtensionHandles, type AgentExtensionSettings, type BuiltEdgeRecord, type BuiltServedRecord, 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 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 LoopGuard, 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 RequestGrantOptions, SCRATCHPAD_BIN_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 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, activeTrace, answerGrantRequest, assertValidTraceOptions, bindActiveTrace, buildEdgeRecord, buildServedRecord, countTraceRecordDropped, countTraceRecordPublished, decodeReference, decodeShortReference, durableHeaders, durableRunId, durableTrace, encodeGrantReply, encodeGrantRequest, encodeReference, exportScratchPad, fabricTracing, findReferences, grantRequestEndpoint, grantSubject, granteeFromIdentity, isThreadId, loopGuard, loopGuardDescription, nativeScratchPad, nativeScratchPadFromEnv, randomThreadId, readRecordedGrants, readsReferences, referenceCreator, removeReferences, requestGrant, resolveEdgeSubject, resolveScratchPad, scratchPadExtension, scratchPadFromEnv, scratchPadReader, servedPublisher, spBinary, spCliScratchPad, spPort, traceHeaders, traceRecordCounts, unixSeconds, validHarnessThreadId, validToolCallId, withDurableTrace, withRecordedGrants };