@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.
Files changed (90) hide show
  1. package/README.md +162 -65
  2. package/package.json +29 -24
  3. package/src/adapter/identity.d.ts +41 -0
  4. package/src/adapter/identity.js +71 -0
  5. package/src/client-options.d.ts +71 -0
  6. package/src/client-options.js +0 -0
  7. package/src/client.d.ts +106 -0
  8. package/src/client.js +254 -0
  9. package/src/diagnostics/errors.d.ts +15 -0
  10. package/src/diagnostics/errors.js +59 -0
  11. package/src/diagnostics/events.d.ts +46 -0
  12. package/src/diagnostics/events.js +47 -0
  13. package/src/diagnostics.d.ts +20 -0
  14. package/src/diagnostics.js +56 -0
  15. package/src/errors.d.ts +48 -0
  16. package/src/errors.js +63 -0
  17. package/src/index.d.ts +27 -0
  18. package/src/index.js +23 -0
  19. package/src/lifecycle/approval.d.ts +16 -0
  20. package/src/lifecycle/approval.js +18 -0
  21. package/src/lifecycle/deferred.d.ts +10 -0
  22. package/src/lifecycle/deferred.js +12 -0
  23. package/src/lifecycle/errors.d.ts +18 -0
  24. package/src/lifecycle/errors.js +45 -0
  25. package/src/lifecycle/events.d.ts +35 -0
  26. package/src/lifecycle/events.js +141 -0
  27. package/src/lifecycle/execution-observation.d.ts +33 -0
  28. package/src/lifecycle/execution-observation.js +0 -0
  29. package/src/lifecycle/immutable.d.ts +12 -0
  30. package/src/lifecycle/immutable.js +28 -0
  31. package/src/lifecycle/input.d.ts +9 -0
  32. package/src/lifecycle/input.js +19 -0
  33. package/src/lifecycle/interactions.d.ts +129 -0
  34. package/src/lifecycle/interactions.js +282 -0
  35. package/src/lifecycle/limits.d.ts +7 -0
  36. package/src/lifecycle/limits.js +13 -0
  37. package/src/lifecycle/result.d.ts +77 -0
  38. package/src/lifecycle/result.js +213 -0
  39. package/src/lifecycle/value.d.ts +4 -0
  40. package/src/lifecycle/value.js +5 -0
  41. package/src/ports.d.ts +224 -0
  42. package/src/ports.js +0 -0
  43. package/src/privacy/file-change-limits.d.ts +20 -0
  44. package/src/privacy/file-change-limits.js +124 -0
  45. package/src/privacy/secrets.d.ts +205 -0
  46. package/src/privacy/secrets.js +564 -0
  47. package/src/process.d.ts +92 -0
  48. package/src/process.js +331 -0
  49. package/src/queue.d.ts +143 -0
  50. package/src/queue.js +266 -0
  51. package/src/request.d.ts +28 -0
  52. package/src/request.js +81 -0
  53. package/src/requests/guard.d.ts +15 -0
  54. package/src/requests/guard.js +93 -0
  55. package/src/session.d.ts +459 -0
  56. package/src/session.js +1135 -0
  57. package/src/structured-output/adapter.d.ts +8 -0
  58. package/src/structured-output/adapter.js +54 -0
  59. package/src/structured-output/bridge.d.ts +81 -0
  60. package/src/structured-output/bridge.js +274 -0
  61. package/src/structured-output/errors.d.ts +17 -0
  62. package/src/structured-output/errors.js +31 -0
  63. package/src/structured-output/limits.d.ts +19 -0
  64. package/src/structured-output/limits.js +0 -0
  65. package/src/structured-output/schema.d.ts +20 -0
  66. package/src/structured-output/schema.js +122 -0
  67. package/src/structured-output/session.d.ts +329 -0
  68. package/src/structured-output/session.js +846 -0
  69. package/src/structured-output/stdio.mjs +83 -0
  70. package/src/structured-output/tool.d.ts +38 -0
  71. package/src/structured-output/tool.js +34 -0
  72. package/src/turn.d.ts +75 -0
  73. package/src/turn.js +95 -0
  74. package/src/types.d.ts +62 -0
  75. package/src/types.js +0 -0
  76. package/dist/diagnostics.d.ts +0 -15
  77. package/dist/diagnostics.js +0 -34
  78. package/dist/errors.d.ts +0 -15
  79. package/dist/file-change-limits.d.ts +0 -5
  80. package/dist/identity.d.ts +0 -13
  81. package/dist/index.d.ts +0 -8
  82. package/dist/index.js +0 -1474
  83. package/dist/interactions.d.ts +0 -20
  84. package/dist/ports.d.ts +0 -66
  85. package/dist/process.d.ts +0 -34
  86. package/dist/process.js +0 -191
  87. package/dist/queue.d.ts +0 -36
  88. package/dist/queue.js +0 -166
  89. package/dist/runtime.d.ts +0 -85
  90. 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
+ }