@anureo/sdk 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +162 -65
- package/package.json +29 -24
- package/src/adapter/identity.d.ts +41 -0
- package/src/adapter/identity.js +71 -0
- package/src/client-options.d.ts +71 -0
- package/src/client-options.js +0 -0
- package/src/client.d.ts +106 -0
- package/src/client.js +254 -0
- package/src/diagnostics/errors.d.ts +15 -0
- package/src/diagnostics/errors.js +59 -0
- package/src/diagnostics/events.d.ts +46 -0
- package/src/diagnostics/events.js +47 -0
- package/src/diagnostics.d.ts +20 -0
- package/src/diagnostics.js +56 -0
- package/src/errors.d.ts +48 -0
- package/src/errors.js +63 -0
- package/src/index.d.ts +27 -0
- package/src/index.js +23 -0
- package/src/lifecycle/approval.d.ts +16 -0
- package/src/lifecycle/approval.js +18 -0
- package/src/lifecycle/deferred.d.ts +10 -0
- package/src/lifecycle/deferred.js +12 -0
- package/src/lifecycle/errors.d.ts +18 -0
- package/src/lifecycle/errors.js +45 -0
- package/src/lifecycle/events.d.ts +35 -0
- package/src/lifecycle/events.js +141 -0
- package/src/lifecycle/execution-observation.d.ts +33 -0
- package/src/lifecycle/execution-observation.js +0 -0
- package/src/lifecycle/immutable.d.ts +12 -0
- package/src/lifecycle/immutable.js +28 -0
- package/src/lifecycle/input.d.ts +9 -0
- package/src/lifecycle/input.js +19 -0
- package/src/lifecycle/interactions.d.ts +129 -0
- package/src/lifecycle/interactions.js +282 -0
- package/src/lifecycle/limits.d.ts +7 -0
- package/src/lifecycle/limits.js +13 -0
- package/src/lifecycle/result.d.ts +77 -0
- package/src/lifecycle/result.js +213 -0
- package/src/lifecycle/value.d.ts +4 -0
- package/src/lifecycle/value.js +5 -0
- package/src/ports.d.ts +224 -0
- package/src/ports.js +0 -0
- package/src/privacy/file-change-limits.d.ts +20 -0
- package/src/privacy/file-change-limits.js +124 -0
- package/src/privacy/secrets.d.ts +205 -0
- package/src/privacy/secrets.js +564 -0
- package/src/process.d.ts +92 -0
- package/src/process.js +331 -0
- package/src/queue.d.ts +143 -0
- package/src/queue.js +266 -0
- package/src/request.d.ts +28 -0
- package/src/request.js +81 -0
- package/src/requests/guard.d.ts +15 -0
- package/src/requests/guard.js +93 -0
- package/src/session.d.ts +459 -0
- package/src/session.js +1135 -0
- package/src/structured-output/adapter.d.ts +8 -0
- package/src/structured-output/adapter.js +54 -0
- package/src/structured-output/bridge.d.ts +81 -0
- package/src/structured-output/bridge.js +274 -0
- package/src/structured-output/errors.d.ts +17 -0
- package/src/structured-output/errors.js +31 -0
- package/src/structured-output/limits.d.ts +19 -0
- package/src/structured-output/limits.js +0 -0
- package/src/structured-output/schema.d.ts +20 -0
- package/src/structured-output/schema.js +122 -0
- package/src/structured-output/session.d.ts +329 -0
- package/src/structured-output/session.js +846 -0
- package/src/structured-output/stdio.mjs +83 -0
- package/src/structured-output/tool.d.ts +38 -0
- package/src/structured-output/tool.js +34 -0
- package/src/turn.d.ts +75 -0
- package/src/turn.js +95 -0
- package/src/types.d.ts +62 -0
- package/src/types.js +0 -0
- package/dist/diagnostics.d.ts +0 -15
- package/dist/diagnostics.js +0 -34
- package/dist/errors.d.ts +0 -15
- package/dist/file-change-limits.d.ts +0 -5
- package/dist/identity.d.ts +0 -13
- package/dist/index.d.ts +0 -8
- package/dist/index.js +0 -1474
- package/dist/interactions.d.ts +0 -20
- package/dist/ports.d.ts +0 -66
- package/dist/process.d.ts +0 -34
- package/dist/process.js +0 -191
- package/dist/queue.d.ts +0 -36
- package/dist/queue.js +0 -166
- package/dist/runtime.d.ts +0 -85
- package/dist/secrets.d.ts +0 -28
package/src/ports.d.ts
ADDED
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
import type { AhpEventPayload, AhpMethod, AhpRequestMap, AhpResultMap, Capabilities, HarnessError, InitializeParams, InitializeResult, InteractionRequested, InteractionResponse, JsonSchema, SessionBinding, SessionOpenParams } from '@anureo/protocol';
|
|
2
|
+
import type { QueueLimits } from "./queue.js";
|
|
3
|
+
/**
|
|
4
|
+
* Deliver an interaction answer or cancellation to the native peer. Adapters supply this callback to
|
|
5
|
+
* the sink's requestInteraction. InteractionRegistry.deliverResponse invokes it with an answer;
|
|
6
|
+
* cancelPending invokes it with null and a reason on expiry/cancellation/teardown.
|
|
7
|
+
* Session.requestInteraction also calls it directly when rejecting closed, unsupported or handler
|
|
8
|
+
* capacity admission. Resolve once native delivery or cancellation is confirmed by the adapter.
|
|
9
|
+
* Reject delivery failures and mark uncertain outcomes so the SDK can report them without retrying
|
|
10
|
+
* a response that might already have been accepted.
|
|
11
|
+
*/
|
|
12
|
+
export type NativeInteractionResponder = (response: InteractionResponse | null, reason?: string) => Promise<void>;
|
|
13
|
+
/** Session.request and BackendSession.execute use these methods; Client handles initialize/session-open separately through HarnessAdapter. */
|
|
14
|
+
export type SessionMethod = Exclude<AhpMethod, 'initialize' | 'session/open'>;
|
|
15
|
+
/** Supply the execution and item identities for a native event. IDs in scope and payload must agree. */
|
|
16
|
+
export interface EventScope {
|
|
17
|
+
/** Execution identity needed for item/usage events whose payload carries no turn ID. */
|
|
18
|
+
turnId?: string;
|
|
19
|
+
/** Optional item identity; must agree with an item payload's own ID. */
|
|
20
|
+
itemId?: string;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Publish events and settle interactions through the sink received by HarnessAdapter.openSession.
|
|
24
|
+
* OutputSession.open supplies adapter callbacks that route events through structured-output policy
|
|
25
|
+
* before delivering them to Session. Await publication calls to preserve source order. Report
|
|
26
|
+
* observation failures through fail and release native resources through the adapter's disposal.
|
|
27
|
+
*/
|
|
28
|
+
export interface SessionEventSink {
|
|
29
|
+
/**
|
|
30
|
+
* Project final JSON synchronously for privacy. Session supplies this hook to
|
|
31
|
+
* OutputSession.publishOutput, which revalidates the returned text against the schema.
|
|
32
|
+
* Projection or validation failure turns the native success into a failed terminal result.
|
|
33
|
+
*/
|
|
34
|
+
projectOutput?(text: string): string;
|
|
35
|
+
/**
|
|
36
|
+
* Publish an association between a submission and its native execution. Successful publication
|
|
37
|
+
* can resolve Session.submit before the native receipt. Invalid or conflicting bindings fail
|
|
38
|
+
* publication. PiBackendSession.beginTurn awaits this before processing later turn events.
|
|
39
|
+
*/
|
|
40
|
+
bindSubmission(submissionId: string, turnId: string): Promise<void>;
|
|
41
|
+
/**
|
|
42
|
+
* Admit a detached event for ordered processing. Await this call before sending a dependent event.
|
|
43
|
+
* Structured-output policy can hold events until a binding arrives. Admission can throw or reject.
|
|
44
|
+
* Queued processing failures reject and end observation.
|
|
45
|
+
*/
|
|
46
|
+
emit(event: AhpEventPayload, scope?: EventScope): Promise<void>;
|
|
47
|
+
/** Attempt event admission without waiting. False reports immediate failure. True allows later processing failure to end observation. */
|
|
48
|
+
tryEmit(event: AhpEventPayload, scope?: EventScope): boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Register a native request and the callback that delivers its answer or cancellation. Session
|
|
51
|
+
* publishes interaction/requested before scheduling a configured host handler. Manual answers
|
|
52
|
+
* arrive through Session.request. Resolve with the answer after delivery and settlement
|
|
53
|
+
* publication. Admission failures, cancellation and expiry reject. If native delivery and
|
|
54
|
+
* publication of its unknown outcome both fail, the pending answer can remain unresolved.
|
|
55
|
+
* Keep native callback resources available through settlement or adapter teardown.
|
|
56
|
+
*/
|
|
57
|
+
requestInteraction(request: InteractionRequested, responder: NativeInteractionResponder): Promise<InteractionResponse>;
|
|
58
|
+
/**
|
|
59
|
+
* Report settlement already completed by the native peer. Session publishes the result without
|
|
60
|
+
* invoking the responder and rejects the pending requestInteraction, including for a responded
|
|
61
|
+
* outcome, because there is no answer value. Unknown or resolved IDs are ignored. A publication
|
|
62
|
+
* failure rejects this call.
|
|
63
|
+
*/
|
|
64
|
+
resolveInteraction(result: AhpResultMap['interaction/respond']): Promise<void>;
|
|
65
|
+
/**
|
|
66
|
+
* Report observation loss. The first call on an open Session ends observation, cancels pending
|
|
67
|
+
* interactions and attempts backend cleanup. Session suppresses backend disposal rejection.
|
|
68
|
+
* Native execution stop remains unconfirmed.
|
|
69
|
+
*/
|
|
70
|
+
fail(cause: unknown): Promise<void>;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Inspect the candidate decision returned by StructuredOutputToolDefinition.execute to native tool
|
|
74
|
+
* adapters. OutputSession.submitCandidate checks and retains accepted candidates. Acceptance is
|
|
75
|
+
* provisional: final privacy/schema validation occurs at terminal publication. Rejection carries
|
|
76
|
+
* safe retry/terminal policy; infrastructure failure can reject the callback promise instead.
|
|
77
|
+
*/
|
|
78
|
+
export type StructuredOutputToolResult = {
|
|
79
|
+
accepted: true;
|
|
80
|
+
} | {
|
|
81
|
+
accepted: false;
|
|
82
|
+
error: HarnessError;
|
|
83
|
+
};
|
|
84
|
+
/**
|
|
85
|
+
* Present this tool to the native agent and invoke execute for candidate calls. OutputSession.prepareOutput
|
|
86
|
+
* passes the definition to a native StructuredOutputToolPort before input dispatch. The adapter
|
|
87
|
+
* consumes acceptance or safe failure. Each callback captures its submission, so a late call cannot
|
|
88
|
+
* satisfy a replacement input. Native tool registration/cleanup remains the adapter's responsibility.
|
|
89
|
+
*/
|
|
90
|
+
export interface StructuredOutputToolDefinition {
|
|
91
|
+
/** Native tool name supplied by the output wrapper; keep it stable when presenting the tool. */
|
|
92
|
+
name: string;
|
|
93
|
+
/** Model-facing instructions supplied by the output wrapper. */
|
|
94
|
+
description: string;
|
|
95
|
+
/** Candidate schema whose constraints the native tool presentation must preserve. */
|
|
96
|
+
schema: JsonSchema;
|
|
97
|
+
/** Native tool calls await candidate validation/retention; resolve a decision, or reject an infrastructure failure. Acceptance does not settle Turn.result. */
|
|
98
|
+
execute(value: unknown): Promise<StructuredOutputToolResult>;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Implement session-scoped native tool registration on a BackendSession. OutputSession.prepareOutput
|
|
102
|
+
* awaits installation before dispatch. OutputSession.completeTurn, reject and release disable the
|
|
103
|
+
* tool on completion, definite rejection or teardown. Finish changes before resolving.
|
|
104
|
+
*/
|
|
105
|
+
export interface StructuredOutputToolPort {
|
|
106
|
+
/**
|
|
107
|
+
* OutputSession replaces the tool or disables it with undefined. Resolve when native registration
|
|
108
|
+
* changes complete; setup rejection prevents input dispatch, while teardown rejection reports cleanup failure.
|
|
109
|
+
*/
|
|
110
|
+
configure(tool?: StructuredOutputToolDefinition): Promise<void>;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Return an owned native session from HarnessAdapter.openSession. OutputSession.open adopts it; Client then
|
|
114
|
+
* attaches the wrapper to Session. Session.executeRequest awaits wrapper execute and
|
|
115
|
+
* Session.disposeBackend awaits wrapper disposal, which releases the native backend. Receipt promises
|
|
116
|
+
* and sink events can settle independently; adapters must preserve that distinction.
|
|
117
|
+
*/
|
|
118
|
+
export interface BackendSession {
|
|
119
|
+
/** Optional native tool registration used by OutputSession.prepareOutput when native outputSchema support is absent. */
|
|
120
|
+
readonly structuredOutputTool?: StructuredOutputToolPort;
|
|
121
|
+
/** Optional attachment snapshot; Session.attach restores its active execution observations after checking its binding. */
|
|
122
|
+
readonly state?: import('@anureo/protocol').SessionState;
|
|
123
|
+
/** Session.attach requires the requested session/adapter/configuration IDs, then adopts this binding's nativeRef. */
|
|
124
|
+
readonly binding: SessionBinding;
|
|
125
|
+
/** Session-specific capabilities adopted at attachment, after output projection; may differ from initialization capabilities. */
|
|
126
|
+
readonly capabilities: Capabilities;
|
|
127
|
+
/**
|
|
128
|
+
* OutputSession.execute invokes the native backend after policy setup and request validation.
|
|
129
|
+
* Resolve a native receipt/result or reject a safe failure with unknown-outcome metadata when
|
|
130
|
+
* acceptance is uncertain; neither wrapper nor Session automatically retries native dispatch.
|
|
131
|
+
*/
|
|
132
|
+
execute<M extends SessionMethod>(method: M, params: AhpRequestMap[M]): Promise<AhpResultMap[M]>;
|
|
133
|
+
/** OutputSession.dispose awaits native handle release; implementations must be idempotent and reject cleanup failure without claiming execution stopped. */
|
|
134
|
+
dispose(): Promise<void>;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Implement native negotiation, session acquisition and client-wide cleanup for ClientOptions.adapter.
|
|
138
|
+
* Client invokes these operations through its structured-output wrapper. Release partially acquired
|
|
139
|
+
* native resources if setup fails. Be prepared to dispose after failed negotiation or while
|
|
140
|
+
* negotiation or a native open is still in flight, since a host can stop waiting first.
|
|
141
|
+
*/
|
|
142
|
+
export interface HarnessAdapter {
|
|
143
|
+
/**
|
|
144
|
+
* Select a bridge transport reachable by the native session, or return undefined to disable MCP
|
|
145
|
+
* fallback. OutputSession.open calls this synchronously when initialization lacks native
|
|
146
|
+
* outputSchema support. Opt in when native open can consume session-scoped MCP configuration.
|
|
147
|
+
* A throw rejects session setup.
|
|
148
|
+
*/
|
|
149
|
+
outputBridgeTransport?(params: SessionOpenParams): 'http' | 'stdio' | undefined;
|
|
150
|
+
/** Client.initialize awaits negotiation through its wrapper, validates the result and stores capabilities; reject incompatible contracts/native setup failure. */
|
|
151
|
+
initialize(params: InitializeParams): Promise<InitializeResult>;
|
|
152
|
+
/**
|
|
153
|
+
* OutputSession.open supplies detached params and forwarding sink callbacks. Resolve an owned
|
|
154
|
+
* backend; callbacks may run before it resolves. Reject setup failure after releasing partially
|
|
155
|
+
* acquired native resources; the wrapper/Session release backends that arrive after caller teardown.
|
|
156
|
+
*/
|
|
157
|
+
openSession(params: SessionOpenParams, sink: SessionEventSink): Promise<BackendSession>;
|
|
158
|
+
/** The output wrapper invokes this after session cleanup attempts; release client-wide native resources or reject release failure. */
|
|
159
|
+
dispose(): Promise<void>;
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Hosts supply these hooks/budgets through ClientOptions.runtime. Client consumes ID/wait policy;
|
|
163
|
+
* Session consumes publication, interaction and privacy policy. Hooks can perform host-owned effects,
|
|
164
|
+
* but do not transfer native execution ownership. Callback failures propagate through their invoking
|
|
165
|
+
* operation; hosts must arrange any cleanup needed by their callbacks.
|
|
166
|
+
*/
|
|
167
|
+
export interface RuntimeOptions {
|
|
168
|
+
/**
|
|
169
|
+
* Generate nonempty, collision-free IDs synchronously; defaults to randomUUID. Client session helpers
|
|
170
|
+
* and Session request/stream allocation invoke this; allocation failures propagate to their callers.
|
|
171
|
+
*/
|
|
172
|
+
createId?: () => string;
|
|
173
|
+
/**
|
|
174
|
+
* Supply public ISO timestamps for Session.publish. Defaults to new Date().toISOString().
|
|
175
|
+
* An invalid timestamp or throw fails publication. Interaction expiry uses wall-clock time.
|
|
176
|
+
*/
|
|
177
|
+
now?: () => string;
|
|
178
|
+
/**
|
|
179
|
+
* Default wait for initialization, session requests, submission association and native interaction
|
|
180
|
+
* responders, in milliseconds. Defaults to 30_000. Per-call waits can override the operation
|
|
181
|
+
* wait. Turn.result has a separate 30-second default.
|
|
182
|
+
*/
|
|
183
|
+
requestTimeoutMs?: number;
|
|
184
|
+
/**
|
|
185
|
+
* Default session attachment wait in milliseconds; defaults to 120_000. Per-call waits override it;
|
|
186
|
+
* abort/expiry does not abandon late backend cleanup.
|
|
187
|
+
*/
|
|
188
|
+
openTimeoutMs?: number;
|
|
189
|
+
/**
|
|
190
|
+
* Bound actionable interaction lifetime in milliseconds. Defaults to 600_000.
|
|
191
|
+
* An earlier native expiry takes precedence.
|
|
192
|
+
*/
|
|
193
|
+
interactionTimeoutMs?: number;
|
|
194
|
+
/**
|
|
195
|
+
* Separate caps for pending/settling interactions and live automatic handlers; each defaults to 32.
|
|
196
|
+
* Aborted host work retains its slot until settled.
|
|
197
|
+
*/
|
|
198
|
+
maxPendingInteractions?: number;
|
|
199
|
+
/**
|
|
200
|
+
* Retained idempotency-outcome count per session; defaults to 1024.
|
|
201
|
+
* Session.admitRequestCapacity never evicts unsettled requests.
|
|
202
|
+
*/
|
|
203
|
+
requestCacheSize?: number;
|
|
204
|
+
/**
|
|
205
|
+
* Set maxEvents, maxBytes and maxFrameBytes for session and structured-output event buffering.
|
|
206
|
+
* Their defaults are 2048 events, 16 MiB buffered and 8 MiB per frame. Observer queues use
|
|
207
|
+
* EventSubscriptionOptions.
|
|
208
|
+
*/
|
|
209
|
+
queue?: QueueLimits;
|
|
210
|
+
/**
|
|
211
|
+
* Persist irreversible privacy metadata synchronously before accepting a new marked secret.
|
|
212
|
+
* Session registers this hook with SecretRedactor. SecretRedactor.rememberScalar invokes it before
|
|
213
|
+
* retaining a new marked value during InteractionRegistry.respond's pre-delivery check.
|
|
214
|
+
* A throw prevents native response delivery and leaves earlier persisted values in place.
|
|
215
|
+
*/
|
|
216
|
+
onMarkedSecret?: (binding: Readonly<SessionBinding>, value: string) => void;
|
|
217
|
+
/**
|
|
218
|
+
* Apply host privacy metadata, including secrets retained across processes, to a native history page.
|
|
219
|
+
* Session.executeRequest invokes/awaits this after local history redaction, then validates/freezes
|
|
220
|
+
* the returned history/read page for its caller. Host I/O is allowed; throws/rejection fail the
|
|
221
|
+
* history request without SDK retries.
|
|
222
|
+
*/
|
|
223
|
+
redactHistory?: (binding: Readonly<SessionBinding>, page: AhpResultMap["history/read"]) => AhpResultMap["history/read"] | Promise<AhpResultMap["history/read"]>;
|
|
224
|
+
}
|
package/src/ports.js
ADDED
|
File without changes
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Item } from '@anureo/protocol';
|
|
2
|
+
/**
|
|
3
|
+
* boundMaterial caps available materials across every file in one tool-call item. Existing
|
|
4
|
+
* unavailable metadata does not consume this count; excess available materials are omitted.
|
|
5
|
+
*/
|
|
6
|
+
export declare const FILE_CHANGE_MATERIAL_LIMIT = 50;
|
|
7
|
+
/**
|
|
8
|
+
* Per-item UTF-8 text budget used by boundFileChangeItem.
|
|
9
|
+
* Canonical material reserves bytes before mirrors; JSON keys and item metadata are outside the cap.
|
|
10
|
+
*/
|
|
11
|
+
export declare const FILE_CHANGE_TEXT_LIMIT: number;
|
|
12
|
+
/**
|
|
13
|
+
* Bound a tool call's file-change evidence without mutating the input. Items without fileChanges
|
|
14
|
+
* and non-tool items pass through by identity. Canonical material consumes the shared byte budget
|
|
15
|
+
* before input, output, raw and extensions, in that order. Overflow sets x-anureo/fileChangesTruncated.
|
|
16
|
+
* Only loss of canonical material downgrades a change's completeness and existing stat accuracy.
|
|
17
|
+
* SecretRedactor.toolCall calls this after redaction, so live events and history get the same
|
|
18
|
+
* retention rules. Callers own protocol validation and publication.
|
|
19
|
+
*/
|
|
20
|
+
export declare function boundFileChangeItem(item: Item): Item;
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* boundMaterial caps available materials across every file in one tool-call item. Existing
|
|
3
|
+
* unavailable metadata does not consume this count; excess available materials are omitted.
|
|
4
|
+
*/
|
|
5
|
+
export const FILE_CHANGE_MATERIAL_LIMIT = 50;
|
|
6
|
+
/**
|
|
7
|
+
* Per-item UTF-8 text budget used by boundFileChangeItem.
|
|
8
|
+
* Canonical material reserves bytes before mirrors; JSON keys and item metadata are outside the cap.
|
|
9
|
+
*/
|
|
10
|
+
export const FILE_CHANGE_TEXT_LIMIT = 256 * 1024;
|
|
11
|
+
/**
|
|
12
|
+
* Bound a tool call's file-change evidence without mutating the input. Items without fileChanges
|
|
13
|
+
* and non-tool items pass through by identity. Canonical material consumes the shared byte budget
|
|
14
|
+
* before input, output, raw and extensions, in that order. Overflow sets x-anureo/fileChangesTruncated.
|
|
15
|
+
* Only loss of canonical material downgrades a change's completeness and existing stat accuracy.
|
|
16
|
+
* SecretRedactor.toolCall calls this after redaction, so live events and history get the same
|
|
17
|
+
* retention rules. Callers own protocol validation and publication.
|
|
18
|
+
*/
|
|
19
|
+
export function boundFileChangeItem(item) {
|
|
20
|
+
if (item.type !== 'toolCall' || item.fileChanges === undefined)
|
|
21
|
+
return item;
|
|
22
|
+
const budget = {
|
|
23
|
+
bytes: FILE_CHANGE_TEXT_LIMIT,
|
|
24
|
+
materials: 0,
|
|
25
|
+
truncated: false,
|
|
26
|
+
encoder: new TextEncoder(),
|
|
27
|
+
};
|
|
28
|
+
const fileChanges = item.fileChanges.map(change => boundChange(change, budget));
|
|
29
|
+
const result = { ...item, fileChanges };
|
|
30
|
+
if (item.input !== undefined)
|
|
31
|
+
result.input = boundMirror(item.input, budget);
|
|
32
|
+
if (item.output !== undefined)
|
|
33
|
+
result.output = boundMirror(item.output, budget);
|
|
34
|
+
if (item.raw !== undefined)
|
|
35
|
+
result.raw = boundMirror(item.raw, budget);
|
|
36
|
+
if (item.extensions)
|
|
37
|
+
result.extensions = boundMirror(item.extensions, budget);
|
|
38
|
+
if (budget.truncated)
|
|
39
|
+
result.extensions = { ...result.extensions, 'x-anureo/fileChangesTruncated': true };
|
|
40
|
+
return result;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* boundMaterial and boundMirror use this shared accounting rather than independent budgets. Return
|
|
44
|
+
* text within the remaining UTF-8 allowance and debit it. Overflow sets the sticky truncation flag
|
|
45
|
+
* and keeps only complete newline-terminated lines, dropping any split UTF-8 character with its line.
|
|
46
|
+
* Debit only the retained prefix, leaving unused bytes available to later material or mirrors.
|
|
47
|
+
*/
|
|
48
|
+
function takeText(budget, value) {
|
|
49
|
+
const encoded = budget.encoder.encode(value);
|
|
50
|
+
if (encoded.byteLength <= budget.bytes) {
|
|
51
|
+
budget.bytes -= encoded.byteLength;
|
|
52
|
+
return { value, complete: true };
|
|
53
|
+
}
|
|
54
|
+
const decoded = new TextDecoder().decode(encoded.subarray(0, budget.bytes));
|
|
55
|
+
const prefix = decoded.slice(0, decoded.lastIndexOf('\n') + 1);
|
|
56
|
+
budget.bytes -= budget.encoder.encode(prefix).byteLength;
|
|
57
|
+
budget.truncated = true;
|
|
58
|
+
return { value: prefix, complete: false };
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* boundChange calls this in source order with the item-wide budget. Return retained material and a
|
|
62
|
+
* partial flag, omitting material beyond the count cap. An empty retained patch becomes unavailable.
|
|
63
|
+
* Replacement sides must both fit to remain usable. Their consumed bytes stay reserved even when
|
|
64
|
+
* the replacement becomes unavailable metadata.
|
|
65
|
+
*/
|
|
66
|
+
function boundMaterial(material, budget) {
|
|
67
|
+
if (material.format === 'unavailable')
|
|
68
|
+
return { material, partial: false };
|
|
69
|
+
if (++budget.materials > FILE_CHANGE_MATERIAL_LIMIT) {
|
|
70
|
+
budget.truncated = true;
|
|
71
|
+
return { partial: true };
|
|
72
|
+
}
|
|
73
|
+
if (material.format === 'unified') {
|
|
74
|
+
const patch = takeText(budget, material.patch);
|
|
75
|
+
return {
|
|
76
|
+
material: patch.value ? { ...material, patch: patch.value } : { format: 'unavailable', reason: 'tooLarge' },
|
|
77
|
+
partial: !patch.complete,
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
const oldText = material.oldText === null ? null : takeText(budget, material.oldText);
|
|
81
|
+
const newText = takeText(budget, material.newText);
|
|
82
|
+
if ((oldText !== null && !oldText.complete) || !newText.complete) {
|
|
83
|
+
return { material: { format: 'unavailable', reason: 'tooLarge' }, partial: true };
|
|
84
|
+
}
|
|
85
|
+
return { material: { ...material, oldText: oldText === null ? null : oldText.value, newText: newText.value }, partial: false };
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* boundFileChangeItem maps canonical changes through this before traversing mirrors. Retain material
|
|
89
|
+
* in order and downgrade completeness/stat accuracy when a cap discards content; keep a metadata placeholder
|
|
90
|
+
* when all supplied material was omitted. Only the shared budget is mutated, never the source change.
|
|
91
|
+
*/
|
|
92
|
+
function boundChange(change, budget) {
|
|
93
|
+
let partial = false;
|
|
94
|
+
const materials = [];
|
|
95
|
+
for (const material of change.materials) {
|
|
96
|
+
const retained = boundMaterial(material, budget);
|
|
97
|
+
partial ||= retained.partial;
|
|
98
|
+
if (retained.material)
|
|
99
|
+
materials.push(retained.material);
|
|
100
|
+
}
|
|
101
|
+
if (!materials.length && change.materials.length)
|
|
102
|
+
materials.push({ format: 'unavailable', reason: 'tooLarge' });
|
|
103
|
+
const result = { ...change, materials };
|
|
104
|
+
if (partial) {
|
|
105
|
+
result.completeness = 'partial';
|
|
106
|
+
if (change.stats)
|
|
107
|
+
result.stats = { ...change.stats, accuracy: 'partial' };
|
|
108
|
+
}
|
|
109
|
+
return result;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* boundFileChangeItem invokes this for input, output, raw and extensions after canonical material.
|
|
113
|
+
* Return recursively bounded JSON without changing keys or scalar types. String values consume the
|
|
114
|
+
* remaining budget in traversal order; only the shared budget is mutated.
|
|
115
|
+
*/
|
|
116
|
+
function boundMirror(value, budget) {
|
|
117
|
+
if (typeof value === 'string')
|
|
118
|
+
return takeText(budget, value).value;
|
|
119
|
+
if (Array.isArray(value))
|
|
120
|
+
return value.map(entry => boundMirror(entry, budget));
|
|
121
|
+
if (value && typeof value === 'object')
|
|
122
|
+
return Object.fromEntries(Object.entries(value).map(([key, child]) => [key, boundMirror(child, budget)]));
|
|
123
|
+
return value;
|
|
124
|
+
}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import type { Capabilities, AhpEventPayload, AhpMethod, AhpResultMap, GoalState, HistoryPage, InteractionRequested, InteractionResponse, Item, JsonValue, SessionState } from "@anureo/protocol";
|
|
2
|
+
/**
|
|
3
|
+
* Register explicitly marked answers before projecting content for public observation.
|
|
4
|
+
* This root-exported implementation helper is owned by Session, which installs registration in
|
|
5
|
+
* InteractionRegistry's pre-response callback and projects events and request results. Direct
|
|
6
|
+
* consumers own the same registration/publication order. Secrets and pending prefixes stay in
|
|
7
|
+
* memory; the optional synchronous hook owns persistence. No native resources are acquired.
|
|
8
|
+
*/
|
|
9
|
+
export declare class SecretRedactor {
|
|
10
|
+
private readonly onRemember?;
|
|
11
|
+
/**
|
|
12
|
+
* Create an empty in-memory registry with an optional synchronous persistence hook. Session
|
|
13
|
+
* forwards runtime.onMarkedSecret here; rememberScalar invokes it before accepting each new value.
|
|
14
|
+
* Construction only retains the hook. The host owns persistence and any effects its hook performs.
|
|
15
|
+
*/
|
|
16
|
+
constructor(onRemember?: ((secret: string) => void) | undefined);
|
|
17
|
+
/**
|
|
18
|
+
* Register answers marked secret/writeOnly by the request before exposing or delivering them.
|
|
19
|
+
* Marked containers contribute their scalar descendants. Numbers and booleans register by string
|
|
20
|
+
* value, while empty strings, null and duplicates are ignored. At most 128 distinct values and
|
|
21
|
+
* 64 KiB of UTF-8 text are retained. Exceeding either cap throws a HarnessSdkError with code
|
|
22
|
+
* BACKPRESSURE_EXCEEDED. Hook exceptions also propagate, leaving earlier registrations intact.
|
|
23
|
+
* Schema traversal stops beyond depth 32, with the request schema at depth zero.
|
|
24
|
+
* Session installs this as InteractionRegistry's pre-response check. InteractionRegistry.respond
|
|
25
|
+
* invokes it after validation and rejects on failure before looking up a replay or starting native
|
|
26
|
+
* delivery. Direct consumers own validation and delivery.
|
|
27
|
+
*/
|
|
28
|
+
rememberResponse(request: InteractionRequested, response: InteractionResponse): void;
|
|
29
|
+
/**
|
|
30
|
+
* Replace complete secret matches with [redacted], preferring the longest match at each position.
|
|
31
|
+
* Unmatched trailing prefixes are emitted without retaining stream state. Session.projectOutput
|
|
32
|
+
* and Session.projectSubmissionStatus use this before exposure. OutputSession.publishOutput
|
|
33
|
+
* revalidates JSON returned through projectOutput and converts schema failures into failed turns.
|
|
34
|
+
*/
|
|
35
|
+
text(value: string): string;
|
|
36
|
+
/**
|
|
37
|
+
* Project an ordered text chunk, withholding a possible trailing secret prefix until the next chunk.
|
|
38
|
+
* Complete matches win even when a longer secret is incomplete. event scopes streams by turn/item
|
|
39
|
+
* and discards pending prefixes on item/completed, whose snapshot carries authoritative full text.
|
|
40
|
+
* Direct consumers must use distinct ordered keys; this method has no flush/reset operation, so
|
|
41
|
+
* they must discard the redactor when they no longer need its retained prefixes and secrets.
|
|
42
|
+
*/
|
|
43
|
+
delta(stream: string, value: string): string;
|
|
44
|
+
/**
|
|
45
|
+
* Return recursively projected JSON without mutating the input. Marked numbers and booleans become
|
|
46
|
+
* the string [redacted]. If projected keys collide, the last entry in traversal order wins.
|
|
47
|
+
* Session.projectSubmissionStatus selects receipt and error content. Direct callers should also
|
|
48
|
+
* pass only content fields to preserve protocol identity.
|
|
49
|
+
*/
|
|
50
|
+
json(value: JsonValue): JsonValue;
|
|
51
|
+
/**
|
|
52
|
+
* Project configuration annotations and values without modifying validation constraints or
|
|
53
|
+
* property names. Return the original value when no configuration is advertised. state uses this
|
|
54
|
+
* for session snapshots; the caller owns storing or publishing the result.
|
|
55
|
+
*/
|
|
56
|
+
capabilities(value: Capabilities): Capabilities;
|
|
57
|
+
/**
|
|
58
|
+
* Return a new outer value with projected goal JSON and unchanged native goal metadata.
|
|
59
|
+
* state and result call this before exposing goal content; no session state is written here.
|
|
60
|
+
*/
|
|
61
|
+
goal(value: GoalState): GoalState;
|
|
62
|
+
/**
|
|
63
|
+
* Project content-bearing state fields while preserving bindings, protocol enums and revisions; no
|
|
64
|
+
* session bookkeeping is changed. Session.snapshot calls this on reads; event and result use it
|
|
65
|
+
* for state/config observations. Session freezes reads and validates/stores request results;
|
|
66
|
+
* direct consumers retain responsibility for validation and publication.
|
|
67
|
+
*/
|
|
68
|
+
state(value: SessionState): SessionState;
|
|
69
|
+
/**
|
|
70
|
+
* Project a validated configuration or goal result according to its method. Other results pass
|
|
71
|
+
* through by identity. Session.projectRequestResult routes history to history() and calls this
|
|
72
|
+
* for other projectable results. Session.executeRequest stores projected configuration or goal
|
|
73
|
+
* state and validates and freezes the returned result. Direct callers own validation and storage.
|
|
74
|
+
*/
|
|
75
|
+
result<M extends AhpMethod>(method: M, value: AhpResultMap[M]): AhpResultMap[M];
|
|
76
|
+
/**
|
|
77
|
+
* Project validated item content without changing protocol identity or registering new secrets.
|
|
78
|
+
* Tool-call file changes additionally use the shared material/mirror budget. event uses this for
|
|
79
|
+
* snapshots and validated patches; history applies it to each native entry. Direct consumers
|
|
80
|
+
* must validate item shape first, as Session and deltaValue do for their respective input paths.
|
|
81
|
+
*/
|
|
82
|
+
item(item: Item): Item;
|
|
83
|
+
/**
|
|
84
|
+
* Project public request content while preserving identifiers, answer keys and protocol alternatives.
|
|
85
|
+
* event calls this after Session.requestInteraction applies protocol publicInteraction; direct
|
|
86
|
+
* consumers must likewise apply protocol privacy rules first. If a privatePayload is supplied
|
|
87
|
+
* directly, this method projects its JSON content and retains the field. InteractionRegistry
|
|
88
|
+
* retains the native request for response validation and marked-field lookup.
|
|
89
|
+
*/
|
|
90
|
+
interaction(request: InteractionRequested): InteractionRequested;
|
|
91
|
+
/**
|
|
92
|
+
* Project validated events in publication order, clearing an item's buffered prefix on completion.
|
|
93
|
+
* Supply turnId to isolate reused item IDs across turns. Omission uses an item-only stream key.
|
|
94
|
+
* Session.publish invokes this after lifecycle admission and before retaining/publishing results.
|
|
95
|
+
* An invalid Item-shaped patch throws ProtocolValidationError and rejects Session.emit, which
|
|
96
|
+
* starts observation teardown. Direct consumers own event validation, ordering and publication.
|
|
97
|
+
* Completed snapshots supply authoritative item content.
|
|
98
|
+
*/
|
|
99
|
+
event(event: AhpEventPayload, turnId?: string): AhpEventPayload;
|
|
100
|
+
/**
|
|
101
|
+
* Project a prevalidated history page using live items' privacy/retention rules, preserving
|
|
102
|
+
* pagination and execution identities. The input must already be validated; no history is fetched
|
|
103
|
+
* here. Session.projectRequestResult calls this before executeRequest awaits the optional host
|
|
104
|
+
* redactHistory hook, validates and freezes the result; host-hook rejection fails that request.
|
|
105
|
+
*/
|
|
106
|
+
history(page: HistoryPage): HistoryPage;
|
|
107
|
+
private readonly values;
|
|
108
|
+
private readonly streams;
|
|
109
|
+
private secretBytes;
|
|
110
|
+
/**
|
|
111
|
+
* rememberResponse and fromSchema call this before a response can be sent. Recursively retain marked
|
|
112
|
+
* scalar values within session budgets; invoke the host hook before accepting each new value.
|
|
113
|
+
* Capacity or hook failures throw to InteractionRegistry.respond before native delivery; values
|
|
114
|
+
* already accepted during the traversal remain registered, with no rollback of host effects.
|
|
115
|
+
*/
|
|
116
|
+
private remember;
|
|
117
|
+
/**
|
|
118
|
+
* Accept a new nonempty scalar only after capacity checks and the synchronous persistence hook
|
|
119
|
+
* succeed. remember preserves traversal order, so a later failure never rolls back earlier values;
|
|
120
|
+
* a failed hook leaves this value unregistered and retryable.
|
|
121
|
+
*/
|
|
122
|
+
private rememberScalar;
|
|
123
|
+
/**
|
|
124
|
+
* Resolve a reference beginning with #/ against the original request schema. Decode JSON Pointer
|
|
125
|
+
* escapes and follow object keys. A missing key or non-object intermediate yields undefined.
|
|
126
|
+
* fromSchema checks the returned node's shape before visiting it.
|
|
127
|
+
*/
|
|
128
|
+
private resolveLocalReference;
|
|
129
|
+
/**
|
|
130
|
+
* rememberResponse calls this for elicitation/dynamicTool schemas; recursive branches pass marked
|
|
131
|
+
* values to remember. Collect marked values through bounded local schema traversal, including
|
|
132
|
+
* referenced and sibling rules; does not validate response values or fetch references. Visit
|
|
133
|
+
* references before siblings because registration order determines host-hook and budget failures.
|
|
134
|
+
* Stop beyond depth 32; registration failures propagate without undoing earlier registrations.
|
|
135
|
+
*/
|
|
136
|
+
private fromSchema;
|
|
137
|
+
/**
|
|
138
|
+
* fromSchema calls this between reference and array/composition visits. Register declared
|
|
139
|
+
* properties before additional ones, sharing the next-depth context and propagating registration
|
|
140
|
+
* failures. Even a declared non-schema property excludes that key from additionalProperties.
|
|
141
|
+
*/
|
|
142
|
+
private rememberObjectProperties;
|
|
143
|
+
/**
|
|
144
|
+
* fromSchema visits array elements in order under the same items schema and next-depth context.
|
|
145
|
+
* Tuple arrays and absent items rules contribute no registrations. Registration failures propagate.
|
|
146
|
+
*/
|
|
147
|
+
private rememberArrayItems;
|
|
148
|
+
/**
|
|
149
|
+
* fromSchema visits composition branches after reference, object and array rules. Visit every
|
|
150
|
+
* schema branch in keyword and array order without selecting a validation match. Registration
|
|
151
|
+
* failures stop the remaining visits.
|
|
152
|
+
*/
|
|
153
|
+
private rememberComposedSchemas;
|
|
154
|
+
/**
|
|
155
|
+
* text consumes the complete scan; delta stores a stream scan's pending prefix for the next chunk.
|
|
156
|
+
* Return longest complete matches as redactions. Stream mode withholds an unmatched trailing
|
|
157
|
+
* prefix so it cannot leak before the next chunk arrives; complete mode emits that prefix.
|
|
158
|
+
* This scan reads registered secrets but changes no stream or registration state.
|
|
159
|
+
*/
|
|
160
|
+
private scan;
|
|
161
|
+
/**
|
|
162
|
+
* capabilities calls this for config-option schemas before exposing state. Project schema
|
|
163
|
+
* annotations/defaults recursively while preserving constraints and property names; privacy must not
|
|
164
|
+
* silently change validation rules. Object schemas are copied and boolean schemas pass through.
|
|
165
|
+
*/
|
|
166
|
+
private schema;
|
|
167
|
+
/**
|
|
168
|
+
* item maps user-message content through this projection. Project content-bearing input block fields
|
|
169
|
+
* while preserving modality and protocol structure; return a detached outer block without loading
|
|
170
|
+
* files or fetching URLs. item returns the block in the public user message.
|
|
171
|
+
*/
|
|
172
|
+
private input;
|
|
173
|
+
/**
|
|
174
|
+
* toolCall merges these fields into projected tool-call items before bounding file-change material.
|
|
175
|
+
* Project tool image paths/prompts only; image identity and other native metadata remain
|
|
176
|
+
* authoritative. Return only the image field (or no fields) without reading or modifying an image.
|
|
177
|
+
*/
|
|
178
|
+
private toolImage;
|
|
179
|
+
/**
|
|
180
|
+
* toolCall maps fileChanges through this before boundFileChangeItem enforces retention.
|
|
181
|
+
* Project change paths and material text while preserving source metadata; the caller subsequently
|
|
182
|
+
* applies the shared retention budget. Return copied text material without applying patches or
|
|
183
|
+
* changing unavailable-material metadata.
|
|
184
|
+
*/
|
|
185
|
+
private fileChange;
|
|
186
|
+
/**
|
|
187
|
+
* item delegates tool content projection here after extensions have been projected. Redact every
|
|
188
|
+
* content field before enforcing the shared file-change budget so accounting measures projected
|
|
189
|
+
* text. Return the bounded snapshot without changing native identity or source material.
|
|
190
|
+
*/
|
|
191
|
+
private toolCall;
|
|
192
|
+
/**
|
|
193
|
+
* itemDelta calls this for JSON-valued payloads before Session retains or publishes the event.
|
|
194
|
+
* A patch object with type or fileChanges must pass Item validation before item projection.
|
|
195
|
+
* Item-shaped validation failures throw ProtocolValidationError. Other values receive ordinary
|
|
196
|
+
* JSON projection.
|
|
197
|
+
*/
|
|
198
|
+
private deltaValue;
|
|
199
|
+
/**
|
|
200
|
+
* event projects delta text before validating/projecting an optional JSON value. A malformed patch
|
|
201
|
+
* throws after any prefix update, as publication fails through Session.emit; no buffered state is
|
|
202
|
+
* rolled back. Non-Item JSON still receives ordinary content projection.
|
|
203
|
+
*/
|
|
204
|
+
private itemDelta;
|
|
205
|
+
}
|