@agentplat/inference-control 0.3.0-beta.2 → 0.3.0-beta.4

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 (150) hide show
  1. package/README.md +360 -0
  2. package/dist/anytime-semantic-guarantees.d.ts +216 -0
  3. package/dist/anytime-semantic-guarantees.d.ts.map +1 -0
  4. package/dist/anytime-semantic-guarantees.js +817 -0
  5. package/dist/anytime-semantic-guarantees.js.map +1 -0
  6. package/dist/assessor-ensemble-contracts.d.ts +145 -0
  7. package/dist/assessor-ensemble-contracts.d.ts.map +1 -0
  8. package/dist/assessor-ensemble-contracts.js +29 -0
  9. package/dist/assessor-ensemble-contracts.js.map +1 -0
  10. package/dist/assessor-ensemble-runtime.d.ts +55 -0
  11. package/dist/assessor-ensemble-runtime.d.ts.map +1 -0
  12. package/dist/assessor-ensemble-runtime.js +308 -0
  13. package/dist/assessor-ensemble-runtime.js.map +1 -0
  14. package/dist/assessor-ensemble-validation.d.ts +12 -0
  15. package/dist/assessor-ensemble-validation.d.ts.map +1 -0
  16. package/dist/assessor-ensemble-validation.js +156 -0
  17. package/dist/assessor-ensemble-validation.js.map +1 -0
  18. package/dist/assessor-ensemble.d.ts +4 -0
  19. package/dist/assessor-ensemble.d.ts.map +1 -0
  20. package/dist/assessor-ensemble.js +4 -0
  21. package/dist/assessor-ensemble.js.map +1 -0
  22. package/dist/cognitive-adapters.d.ts +92 -0
  23. package/dist/cognitive-adapters.d.ts.map +1 -0
  24. package/dist/cognitive-adapters.js +263 -0
  25. package/dist/cognitive-adapters.js.map +1 -0
  26. package/dist/context-integrity-analyzers.d.ts +35 -0
  27. package/dist/context-integrity-analyzers.d.ts.map +1 -0
  28. package/dist/context-integrity-analyzers.js +387 -0
  29. package/dist/context-integrity-analyzers.js.map +1 -0
  30. package/dist/context-integrity-contracts.d.ts +304 -0
  31. package/dist/context-integrity-contracts.d.ts.map +1 -0
  32. package/dist/context-integrity-contracts.js +24 -0
  33. package/dist/context-integrity-contracts.js.map +1 -0
  34. package/dist/context-integrity-model.d.ts +25 -0
  35. package/dist/context-integrity-model.d.ts.map +1 -0
  36. package/dist/context-integrity-model.js +192 -0
  37. package/dist/context-integrity-model.js.map +1 -0
  38. package/dist/context-integrity-portable-agent.d.ts +79 -0
  39. package/dist/context-integrity-portable-agent.d.ts.map +1 -0
  40. package/dist/context-integrity-portable-agent.js +511 -0
  41. package/dist/context-integrity-portable-agent.js.map +1 -0
  42. package/dist/context-integrity-role-alignment.d.ts +28 -0
  43. package/dist/context-integrity-role-alignment.d.ts.map +1 -0
  44. package/dist/context-integrity-role-alignment.js +95 -0
  45. package/dist/context-integrity-role-alignment.js.map +1 -0
  46. package/dist/context-integrity-runtime.d.ts +95 -0
  47. package/dist/context-integrity-runtime.d.ts.map +1 -0
  48. package/dist/context-integrity-runtime.js +1512 -0
  49. package/dist/context-integrity-runtime.js.map +1 -0
  50. package/dist/context-integrity.d.ts +5 -0
  51. package/dist/context-integrity.d.ts.map +1 -0
  52. package/dist/context-integrity.js +5 -0
  53. package/dist/context-integrity.js.map +1 -0
  54. package/dist/governed-role-evolution.d.ts +172 -0
  55. package/dist/governed-role-evolution.d.ts.map +1 -0
  56. package/dist/governed-role-evolution.js +613 -0
  57. package/dist/governed-role-evolution.js.map +1 -0
  58. package/dist/heterogeneous-agent-composition.d.ts +96 -0
  59. package/dist/heterogeneous-agent-composition.d.ts.map +1 -0
  60. package/dist/heterogeneous-agent-composition.js +512 -0
  61. package/dist/heterogeneous-agent-composition.js.map +1 -0
  62. package/dist/index.d.ts +21 -13
  63. package/dist/index.d.ts.map +1 -1
  64. package/dist/index.js +21 -13
  65. package/dist/index.js.map +1 -1
  66. package/dist/intervention-adapters.d.ts +29 -0
  67. package/dist/intervention-adapters.d.ts.map +1 -0
  68. package/dist/intervention-adapters.js +107 -0
  69. package/dist/intervention-adapters.js.map +1 -0
  70. package/dist/intervention-contracts.d.ts +311 -0
  71. package/dist/intervention-contracts.d.ts.map +1 -0
  72. package/dist/intervention-contracts.js +28 -0
  73. package/dist/intervention-contracts.js.map +1 -0
  74. package/dist/intervention-runtime.d.ts +86 -0
  75. package/dist/intervention-runtime.d.ts.map +1 -0
  76. package/dist/intervention-runtime.js +958 -0
  77. package/dist/intervention-runtime.js.map +1 -0
  78. package/dist/intervention-validation.d.ts +27 -0
  79. package/dist/intervention-validation.d.ts.map +1 -0
  80. package/dist/intervention-validation.js +273 -0
  81. package/dist/intervention-validation.js.map +1 -0
  82. package/dist/intervention.d.ts +6 -0
  83. package/dist/intervention.d.ts.map +1 -0
  84. package/dist/intervention.js +6 -0
  85. package/dist/intervention.js.map +1 -0
  86. package/dist/model.d.ts +18 -0
  87. package/dist/model.d.ts.map +1 -1
  88. package/dist/model.js +60 -2
  89. package/dist/model.js.map +1 -1
  90. package/dist/operational-cognitive-control.d.ts +208 -0
  91. package/dist/operational-cognitive-control.d.ts.map +1 -0
  92. package/dist/operational-cognitive-control.js +590 -0
  93. package/dist/operational-cognitive-control.js.map +1 -0
  94. package/dist/portable-agent.d.ts +50 -0
  95. package/dist/portable-agent.d.ts.map +1 -0
  96. package/dist/portable-agent.js +243 -0
  97. package/dist/portable-agent.js.map +1 -0
  98. package/dist/reference-controllers.d.ts +121 -0
  99. package/dist/reference-controllers.d.ts.map +1 -0
  100. package/dist/reference-controllers.js +411 -0
  101. package/dist/reference-controllers.js.map +1 -0
  102. package/dist/role-alignment-portable-agent.d.ts +145 -0
  103. package/dist/role-alignment-portable-agent.d.ts.map +1 -0
  104. package/dist/role-alignment-portable-agent.js +484 -0
  105. package/dist/role-alignment-portable-agent.js.map +1 -0
  106. package/dist/role-alignment.d.ts +226 -0
  107. package/dist/role-alignment.d.ts.map +1 -0
  108. package/dist/role-alignment.js +1074 -0
  109. package/dist/role-alignment.js.map +1 -0
  110. package/dist/role-realignment-portable-agent.d.ts +163 -0
  111. package/dist/role-realignment-portable-agent.d.ts.map +1 -0
  112. package/dist/role-realignment-portable-agent.js +634 -0
  113. package/dist/role-realignment-portable-agent.js.map +1 -0
  114. package/dist/role-realignment.d.ts +368 -0
  115. package/dist/role-realignment.d.ts.map +1 -0
  116. package/dist/role-realignment.js +1609 -0
  117. package/dist/role-realignment.js.map +1 -0
  118. package/dist/semantic-alignment-assessors.d.ts +12 -0
  119. package/dist/semantic-alignment-assessors.d.ts.map +1 -0
  120. package/dist/semantic-alignment-assessors.js +55 -0
  121. package/dist/semantic-alignment-assessors.js.map +1 -0
  122. package/dist/semantic-alignment-contracts.d.ts +385 -0
  123. package/dist/semantic-alignment-contracts.d.ts.map +1 -0
  124. package/dist/semantic-alignment-contracts.js +16 -0
  125. package/dist/semantic-alignment-contracts.js.map +1 -0
  126. package/dist/semantic-alignment-memory.d.ts +53 -0
  127. package/dist/semantic-alignment-memory.d.ts.map +1 -0
  128. package/dist/semantic-alignment-memory.js +170 -0
  129. package/dist/semantic-alignment-memory.js.map +1 -0
  130. package/dist/semantic-alignment-runtime.d.ts +67 -0
  131. package/dist/semantic-alignment-runtime.d.ts.map +1 -0
  132. package/dist/semantic-alignment-runtime.js +778 -0
  133. package/dist/semantic-alignment-runtime.js.map +1 -0
  134. package/dist/semantic-alignment-validation.d.ts +31 -0
  135. package/dist/semantic-alignment-validation.d.ts.map +1 -0
  136. package/dist/semantic-alignment-validation.js +477 -0
  137. package/dist/semantic-alignment-validation.js.map +1 -0
  138. package/dist/semantic-alignment.d.ts +8 -0
  139. package/dist/semantic-alignment.d.ts.map +1 -0
  140. package/dist/semantic-alignment.js +8 -0
  141. package/dist/semantic-alignment.js.map +1 -0
  142. package/dist/semantic-horizon-budget.d.ts +118 -0
  143. package/dist/semantic-horizon-budget.d.ts.map +1 -0
  144. package/dist/semantic-horizon-budget.js +536 -0
  145. package/dist/semantic-horizon-budget.js.map +1 -0
  146. package/dist/semantic-metric-engine.d.ts +96 -0
  147. package/dist/semantic-metric-engine.d.ts.map +1 -0
  148. package/dist/semantic-metric-engine.js +396 -0
  149. package/dist/semantic-metric-engine.js.map +1 -0
  150. package/package.json +79 -7
@@ -0,0 +1,958 @@
1
+ import { sha256Hex } from "./sha256.js";
2
+ import { HETEROGENEOUS_INFERENCE_INTERVENTION_STATE_FORMAT_V1, } from "./intervention-contracts.js";
3
+ import { assertInferenceInterventionAdapterDescriptorV1, assertInferenceInterventionBindingV1, assertInferenceInterventionPolicyV1, createInferenceInterventionReconciliationRequestV1, createInferenceInterventionTransformationRequestV1, createRepresentationInterventionRequestV1, digestInferenceInterventionV1, verifyInferenceInterventionTransformationReceiptV1, verifyInferenceInterventionReconciliationReceiptV1, verifyRepresentationInterventionReceiptV1, } from "./intervention-validation.js";
4
+ const encoder = new TextEncoder();
5
+ const digestText = (value) => `sha256:${sha256Hex(encoder.encode(value))}`;
6
+ const keyFor = (b) => `inference-intervention:${b.missionId}:${b.agentId}:${b.sessionId}:${b.roleId}:${b.modelOrAdapterId}`;
7
+ export const INFERENCE_INTERVENTION_PAYLOAD_LIMITS_V1 = Object.freeze({
8
+ maximumInputBytes: 1_048_576,
9
+ maximumContextItems: 64,
10
+ maximumContextItemBytes: 262_144,
11
+ maximumContextBytes: 2_097_152,
12
+ maximumModalityParts: 32,
13
+ maximumPayloadHandleBytes: 2_048,
14
+ maximumRoleReinforcementBytes: 65_536,
15
+ maximumReasonCodes: 32,
16
+ maximumReasonCodeBytes: 256,
17
+ maximumEvidenceDigests: 32,
18
+ maximumOutputBytes: 4_194_304,
19
+ maximumTokenBytes: 65_536,
20
+ maximumTokenCount: 8_192,
21
+ });
22
+ export class InMemoryInferenceInterventionStateStoreV1 {
23
+ records = new Map();
24
+ anchors = new Map();
25
+ async read(key) {
26
+ return this.records.get(key) ?? null;
27
+ }
28
+ async readAnchor(key) {
29
+ return this.anchors.get(key) ?? null;
30
+ }
31
+ async compareAndSet(change) {
32
+ const prior = this.records.get(change.stateKey) ?? null;
33
+ if ((prior?.revision ?? null) !== change.expectedRevision ||
34
+ (prior?.stateDigest ?? null) !== change.expectedStateDigest)
35
+ return false;
36
+ this.records.set(change.stateKey, change.next);
37
+ this.anchors.set(change.stateKey, {
38
+ revision: change.next.revision,
39
+ interventionsUsed: change.next.interventionsUsed,
40
+ representationRequestsUsed: change.next.representationRequestsUsed,
41
+ });
42
+ return true;
43
+ }
44
+ }
45
+ class SidecarAmbiguousError extends Error {
46
+ requestDigest;
47
+ constructor(requestDigest) {
48
+ super("representation_sidecar_ambiguous");
49
+ this.requestDigest = requestDigest;
50
+ }
51
+ }
52
+ export class HeterogeneousInferenceInterventionRuntimeV1 {
53
+ options;
54
+ store;
55
+ monotonicAnchor;
56
+ constructor(options) {
57
+ this.options = options;
58
+ assertInferenceInterventionBindingV1(options.binding);
59
+ assertInferenceInterventionPolicyV1(options.policy);
60
+ assertInferenceInterventionAdapterDescriptorV1(options.adapter.descriptor);
61
+ this.store =
62
+ options.store ?? new InMemoryInferenceInterventionStateStoreV1();
63
+ this.monotonicAnchor =
64
+ options.monotonicAnchor ??
65
+ this.store;
66
+ if (typeof this.monotonicAnchor.readAnchor !== "function")
67
+ throw new TypeError("external_monotonic_anchor_required");
68
+ if (!options.assessors.length)
69
+ throw new TypeError("at_least_one_assessor_required");
70
+ for (const assessor of options.assessors)
71
+ this.assertPort(assessor.assessorId, assessor.assessorVersion, assessor.assessorImplementationDigest, "assessor");
72
+ if (options.transformer)
73
+ this.assertPort(options.transformer.transformerId, options.transformer.transformerVersion, options.transformer.transformerImplementationDigest, "transformer");
74
+ if (options.reconciler)
75
+ this.assertPort(options.reconciler.reconcilerId, options.reconciler.reconcilerVersion, options.reconciler.reconcilerImplementationDigest, "reconciler");
76
+ const capabilities = new Set(options.adapter.descriptor.capabilities);
77
+ for (const required of options.policy.requiredCapabilities)
78
+ if (!capabilities.has(required))
79
+ throw new TypeError(`required_capability_unavailable:${required}`);
80
+ if (options.policy.requiredCapabilities.includes("representation_intervention") &&
81
+ !options.sidecar)
82
+ throw new TypeError("required_representation_sidecar_unavailable");
83
+ }
84
+ get bindingDigest() {
85
+ return this.options.binding.bindingDigest;
86
+ }
87
+ get policyDigest() {
88
+ return this.options.policy.policyDigest;
89
+ }
90
+ async verifyOperationGate(input) {
91
+ const invocation = this.makeInvocation({
92
+ invocationId: input.operationId,
93
+ step: input.step,
94
+ logicalTimeMs: input.logicalTimeMs,
95
+ input: input.payload,
96
+ context: [],
97
+ roleReinforcement: null,
98
+ requireRepresentationReceipt: false,
99
+ }, "action");
100
+ const state = await this.store.read(keyFor(this.options.binding));
101
+ await this.validateState(state, invocation);
102
+ const invocationDigest = this.invocationDigest(invocation);
103
+ return Boolean(state &&
104
+ state.stateDigest === input.stateDigest &&
105
+ state.activeInvocation === null &&
106
+ state.unresolvedEffect === null &&
107
+ state.lastInvocation?.invocationId === input.operationId &&
108
+ state.lastInvocation.invocationDigest === invocationDigest &&
109
+ state.lastInvocation.executionDomain === "action" &&
110
+ state.lastInvocation.step === input.step &&
111
+ (state.lastInvocation.decision === "allowed") === input.allowed);
112
+ }
113
+ async invoke(raw) {
114
+ const original = this.makeInvocation(raw, "inference");
115
+ const needsRepresentation = original.requireRepresentationReceipt ||
116
+ original.policy.requiredCapabilities.includes("representation_intervention");
117
+ const reserved = await this.prepare(original, needsRepresentation);
118
+ if ("result" in reserved)
119
+ return reserved.result;
120
+ const { prepared, plan } = reserved;
121
+ let effective = original;
122
+ let receipt = null;
123
+ const assessments = [...plan.assessments];
124
+ try {
125
+ if (plan.trigger) {
126
+ effective = await this.transform(original, plan.trigger);
127
+ const transformedPlan = await this.assessInvocation(effective);
128
+ assessments.push(...transformedPlan.assessments);
129
+ if (transformedPlan.blocked || transformedPlan.trigger)
130
+ return this.finish(prepared, original, assessments, null, null, true, transformedPlan.trigger !== null, transformedPlan.clear);
131
+ }
132
+ if (needsRepresentation)
133
+ receipt = await this.requestRepresentation(effective);
134
+ const providerResult = await this.options.adapter.invoke(effective);
135
+ const output = providerResult.tokens
136
+ ? await this.collectTokens(effective, providerResult.tokens, assessments)
137
+ : this.validateBufferedOutput(providerResult.output ?? "");
138
+ const finalValues = await this.assess(effective, {
139
+ kind: "output",
140
+ content: output,
141
+ contentDigest: digestText(output),
142
+ });
143
+ assessments.push(...finalValues);
144
+ const finalOutcome = this.outcome(finalValues);
145
+ if (finalOutcome.blocked || finalOutcome.intervened)
146
+ return this.finish(prepared, original, assessments, null, receipt, true, finalOutcome.intervened, finalOutcome.clear);
147
+ return this.finish(prepared, original, assessments, output, receipt, false, false, finalOutcome.clear);
148
+ }
149
+ catch (error) {
150
+ if (error instanceof SidecarAmbiguousError) {
151
+ await this.finishAmbiguous(prepared, original, assessments, error.requestDigest);
152
+ throw error;
153
+ }
154
+ const outcome = this.outcome(assessments);
155
+ await this.finish(prepared, original, assessments, null, receipt, true, outcome.intervened, 0);
156
+ throw error;
157
+ }
158
+ }
159
+ async gateOperation(input) {
160
+ const capability = input.kind === "tool" ? "tool_gate" : "action_gate";
161
+ if (!this.options.adapter.descriptor.capabilities.includes(capability))
162
+ throw new TypeError(`${capability}_unavailable_before_dispatch`);
163
+ const original = this.makeInvocation({
164
+ invocationId: input.operationId,
165
+ step: input.step,
166
+ logicalTimeMs: input.logicalTimeMs,
167
+ input: input.payload,
168
+ context: [],
169
+ roleReinforcement: null,
170
+ requireRepresentationReceipt: false,
171
+ }, input.kind);
172
+ const reserved = await this.prepare(original, false, input.kind);
173
+ if ("result" in reserved)
174
+ return {
175
+ allowed: reserved.result.decision === "allowed",
176
+ assessments: reserved.result.assessments,
177
+ state: reserved.result.state,
178
+ };
179
+ const assessments = [...reserved.plan.assessments];
180
+ // Operation gates never return a rewritten payload. Allowing after an
181
+ // advisory rewrite could let the caller dispatch the original risky value.
182
+ const blocked = reserved.plan.trigger !== null;
183
+ const result = await this.finish(reserved.prepared, original, assessments, null, null, blocked, false, 0);
184
+ return Object.freeze({
185
+ allowed: result.decision === "allowed",
186
+ assessments: result.assessments,
187
+ state: result.state,
188
+ });
189
+ }
190
+ async gateCheckpoint(input) {
191
+ const capability = input.kind === "input" ? "pre_input_filter" : "output_gate";
192
+ if (!this.options.adapter.descriptor.capabilities.includes(capability))
193
+ throw new TypeError(`${capability}_unavailable_at_checkpoint`);
194
+ const representation = input.kind === "input" &&
195
+ this.options.adapter.descriptor.capabilities.includes("representation_intervention");
196
+ const original = this.makeInvocation({
197
+ invocationId: input.operationId,
198
+ step: input.step,
199
+ logicalTimeMs: input.logicalTimeMs,
200
+ input: input.payload,
201
+ context: [],
202
+ roleReinforcement: null,
203
+ requireRepresentationReceipt: representation,
204
+ }, "inference");
205
+ const reserved = await this.prepare(original, representation, input.kind);
206
+ if ("result" in reserved)
207
+ return Object.freeze({
208
+ allowed: reserved.result.decision === "allowed",
209
+ assessments: reserved.result.assessments,
210
+ state: reserved.result.state,
211
+ });
212
+ let receipt = null;
213
+ try {
214
+ if (representation)
215
+ receipt = await this.requestRepresentation(original);
216
+ }
217
+ catch (error) {
218
+ if (error instanceof SidecarAmbiguousError) {
219
+ const blocked = await this.finishAmbiguous(reserved.prepared, original, reserved.plan.assessments, error.requestDigest);
220
+ return Object.freeze({
221
+ allowed: false,
222
+ assessments: blocked.assessments,
223
+ state: blocked.state,
224
+ });
225
+ }
226
+ const blocked = await this.finish(reserved.prepared, original, [...reserved.plan.assessments], null, null, true, false, 0);
227
+ return Object.freeze({
228
+ allowed: false,
229
+ assessments: blocked.assessments,
230
+ state: blocked.state,
231
+ });
232
+ }
233
+ const result = await this.finish(reserved.prepared, original, [...reserved.plan.assessments], null, receipt, reserved.plan.trigger !== null, representation, 0);
234
+ return Object.freeze({
235
+ allowed: result.decision === "allowed",
236
+ assessments: result.assessments,
237
+ state: result.state,
238
+ });
239
+ }
240
+ async reconcile(input) {
241
+ const port = this.options.reconciler;
242
+ if (!port)
243
+ throw new TypeError("reconciliation_port_required");
244
+ const key = keyFor(this.options.binding);
245
+ const prior = await this.store.read(key);
246
+ const validationInvocation = {
247
+ invocationId: input.invocationId,
248
+ executionDomain: input.executionDomain,
249
+ binding: this.options.binding,
250
+ policy: this.options.policy,
251
+ step: input.step,
252
+ logicalTimeMs: input.logicalTimeMs,
253
+ input: "",
254
+ inputDigest: digestText(""),
255
+ context: [],
256
+ roleReinforcement: null,
257
+ requireRepresentationReceipt: false,
258
+ };
259
+ await this.validateState(prior, validationInvocation);
260
+ if (!prior?.unresolvedEffect)
261
+ throw new TypeError("no_unresolved_effect");
262
+ const effect = prior.unresolvedEffect;
263
+ if (effect.kind === "retry_authorized")
264
+ throw new TypeError("intervention_retry_already_authorized");
265
+ if (effect.invocationId !== input.invocationId ||
266
+ effect.invocationDigest !== input.invocationDigest ||
267
+ effect.executionDomain !== input.executionDomain ||
268
+ effect.step !== input.step)
269
+ throw new TypeError("reconciliation_invocation_mismatch");
270
+ if (!Number.isSafeInteger(input.logicalTimeMs) ||
271
+ input.logicalTimeMs < prior.logicalTimeHighWaterMs)
272
+ throw new TypeError("reconciliation_logical_time_replay");
273
+ const request = createInferenceInterventionReconciliationRequestV1({
274
+ schemaVersion: 1,
275
+ stateKey: key,
276
+ bindingDigest: this.options.binding.bindingDigest,
277
+ policyDigest: this.options.policy.policyDigest,
278
+ invocationId: effect.invocationId,
279
+ invocationDigest: effect.invocationDigest,
280
+ executionDomain: effect.executionDomain,
281
+ step: effect.step,
282
+ unresolvedKind: effect.kind,
283
+ sidecarRequestDigest: effect.sidecarRequestDigest,
284
+ resolution: input.resolution,
285
+ authorizationDigest: input.authorizationDigest,
286
+ reconciledAtLogicalMs: input.logicalTimeMs,
287
+ });
288
+ const receipt = await port.reconcile(request);
289
+ verifyInferenceInterventionReconciliationReceiptV1(request, receipt, port);
290
+ const retryAuthorized = input.resolution === "confirmed_not_applied";
291
+ const unsigned = retryAuthorized
292
+ ? {
293
+ ...prior,
294
+ revision: prior.revision + 1,
295
+ logicalTimeHighWaterMs: input.logicalTimeMs,
296
+ lastInvocationDigest: prior.activeInvocation === null ? null : prior.lastInvocationDigest,
297
+ activeInvocation: {
298
+ invocationId: effect.invocationId,
299
+ invocationDigest: effect.invocationDigest,
300
+ executionDomain: effect.executionDomain,
301
+ step: effect.step,
302
+ },
303
+ lastInvocation: prior.activeInvocation === null ? null : prior.lastInvocation,
304
+ unresolvedEffect: {
305
+ ...effect,
306
+ kind: "retry_authorized",
307
+ },
308
+ }
309
+ : {
310
+ ...prior,
311
+ revision: prior.revision + 1,
312
+ logicalTimeHighWaterMs: input.logicalTimeMs,
313
+ lastInvocationDigest: effect.invocationDigest,
314
+ activeInvocation: null,
315
+ lastInvocation: {
316
+ invocationId: effect.invocationId,
317
+ invocationDigest: effect.invocationDigest,
318
+ executionDomain: effect.executionDomain,
319
+ step: effect.step,
320
+ decision: "blocked",
321
+ outputDigest: null,
322
+ },
323
+ unresolvedEffect: null,
324
+ };
325
+ const { stateDigest: _oldDigest, ...withoutDigest } = unsigned;
326
+ const next = Object.freeze({
327
+ ...withoutDigest,
328
+ stateDigest: digestInferenceInterventionV1("state", withoutDigest),
329
+ });
330
+ if (!(await this.cas(prior, next)))
331
+ throw new Error("reconciliation_state_commit_conflict");
332
+ return next;
333
+ }
334
+ async prepare(original, representation, operationKind) {
335
+ const key = keyFor(original.binding);
336
+ for (let attempt = 0; attempt < original.policy.budget.maximumCasAttempts; attempt++) {
337
+ const prior = await this.store.read(key);
338
+ await this.validateState(prior, original);
339
+ const replay = this.replay(prior, original);
340
+ if (replay)
341
+ return { result: replay };
342
+ const isAuthorizedRetry = prior?.unresolvedEffect?.kind === "retry_authorized";
343
+ let preparedPrior = prior;
344
+ if (isAuthorizedRetry) {
345
+ const reclaimed = this.state(prior, original, 0, 0, 0, prior.activeInvocation, null);
346
+ if (!(await this.cas(prior, reclaimed)))
347
+ continue;
348
+ preparedPrior = reclaimed;
349
+ }
350
+ else {
351
+ if (prior?.unresolvedEffect)
352
+ throw new TypeError("intervention_reconciliation_required");
353
+ this.assertFresh(prior, original);
354
+ }
355
+ const plan = operationKind
356
+ ? await this.assessOperation(original, operationKind)
357
+ : await this.assessInvocation(original);
358
+ const unavailableModify = plan.trigger &&
359
+ !operationKind &&
360
+ (!this.options.transformer ||
361
+ !this.options.adapter.descriptor.capabilities.includes("trusted_transformation"));
362
+ const interventionUnavailable = plan.trigger &&
363
+ ((preparedPrior?.interventionsUsed ?? 0) >=
364
+ original.policy.budget.maximumInterventions ||
365
+ (preparedPrior?.cooldownUntilLogicalMs ?? 0) >
366
+ original.logicalTimeMs);
367
+ const representationUnavailable = representation &&
368
+ ((preparedPrior?.representationRequestsUsed ?? 0) >=
369
+ original.policy.budget.maximumRepresentationRequests ||
370
+ !this.options.sidecar ||
371
+ !this.options.adapter.descriptor.capabilities.includes("representation_intervention"));
372
+ if (plan.blocked ||
373
+ unavailableModify ||
374
+ interventionUnavailable ||
375
+ representationUnavailable) {
376
+ const terminal = this.state(preparedPrior, original, 0, 0, plan.clear, null, {
377
+ decision: "blocked",
378
+ outputDigest: null,
379
+ });
380
+ if (await this.cas(preparedPrior, terminal))
381
+ return {
382
+ result: Object.freeze({
383
+ decision: "blocked",
384
+ output: null,
385
+ outputDigest: null,
386
+ receipt: null,
387
+ assessments: Object.freeze(plan.assessments),
388
+ state: terminal,
389
+ }),
390
+ };
391
+ continue;
392
+ }
393
+ if (isAuthorizedRetry)
394
+ return { prepared: preparedPrior, plan };
395
+ const prepared = this.state(preparedPrior, original, plan.trigger ? 1 : 0, representation ? 1 : 0, plan.clear, {
396
+ invocationId: original.invocationId,
397
+ invocationDigest: this.invocationDigest(original),
398
+ executionDomain: original.executionDomain,
399
+ step: original.step,
400
+ }, null);
401
+ if (await this.cas(preparedPrior, prepared))
402
+ return { prepared, plan };
403
+ }
404
+ throw new Error("inference_intervention_cas_retry_exhausted");
405
+ }
406
+ async assessOperation(invocation, kind) {
407
+ const signal = {
408
+ kind,
409
+ content: invocation.input,
410
+ contentDigest: invocation.inputDigest,
411
+ };
412
+ const assessments = await this.assess(invocation, signal);
413
+ const outcome = this.outcome(assessments);
414
+ const assessment = assessments.find((value) => value.decision === "modify" ||
415
+ value.riskBps >= invocation.policy.thresholds.interventionRiskBps);
416
+ return {
417
+ assessments,
418
+ blocked: outcome.blocked,
419
+ trigger: assessment ? { signal, assessment } : null,
420
+ clear: outcome.clear,
421
+ };
422
+ }
423
+ async transform(original, trigger) {
424
+ const transformer = this.options.transformer;
425
+ const request = createInferenceInterventionTransformationRequestV1({
426
+ schemaVersion: 1,
427
+ bindingDigest: original.binding.bindingDigest,
428
+ policyDigest: original.policy.policyDigest,
429
+ inputDigest: original.inputDigest,
430
+ signalDigest: trigger.signal.contentDigest,
431
+ assessmentDigest: trigger.assessment.assessmentDigest,
432
+ });
433
+ const changed = await transformer.transform({
434
+ request,
435
+ source: original.input,
436
+ context: original.context,
437
+ modalityParts: original.modalityParts ?? [],
438
+ });
439
+ const effective = {
440
+ ...original,
441
+ input: changed.input,
442
+ inputDigest: digestText(changed.input),
443
+ context: changed.context ?? original.context,
444
+ modalityParts: changed.modalityParts ?? original.modalityParts,
445
+ };
446
+ this.validatePayload(effective);
447
+ verifyInferenceInterventionTransformationReceiptV1(request, changed.receipt, transformer, this.transformedManifestDigest(effective));
448
+ return effective;
449
+ }
450
+ async assessInvocation(invocation) {
451
+ const signals = [
452
+ {
453
+ kind: "input",
454
+ content: invocation.input,
455
+ contentDigest: invocation.inputDigest,
456
+ },
457
+ ...invocation.context.map((content) => ({
458
+ kind: "context",
459
+ content,
460
+ contentDigest: digestText(content),
461
+ })),
462
+ ...(invocation.modalityParts ?? []).map((part) => ({
463
+ kind: "multimodal_input",
464
+ content: part.payloadHandle ?? part.contentDigest,
465
+ contentDigest: part.contentDigest,
466
+ })),
467
+ ];
468
+ const assessments = [];
469
+ let blocked = false, trigger = null, clear = 0;
470
+ for (const signal of signals) {
471
+ const values = await this.assess(invocation, signal);
472
+ assessments.push(...values);
473
+ const outcome = this.outcome(values);
474
+ blocked ||= outcome.blocked;
475
+ clear += outcome.clear;
476
+ if (!trigger) {
477
+ const assessment = values.find((value) => value.decision === "modify" ||
478
+ value.riskBps >= invocation.policy.thresholds.interventionRiskBps);
479
+ if (assessment)
480
+ trigger = { signal, assessment };
481
+ }
482
+ }
483
+ return { assessments, blocked, trigger, clear };
484
+ }
485
+ async collectTokens(invocation, tokens, assessments) {
486
+ if (!this.options.adapter.descriptor.capabilities.includes("token_assessment"))
487
+ throw new TypeError("token_assessment_hook_unavailable_before_stream");
488
+ let output = "", window = "", count = 0, totalTokens = 0, totalBytes = 0;
489
+ const examine = async (kind, content) => {
490
+ const values = await this.assess(invocation, {
491
+ kind,
492
+ content,
493
+ contentDigest: digestText(content),
494
+ });
495
+ assessments.push(...values);
496
+ const outcome = this.outcome(values);
497
+ if (outcome.blocked || outcome.intervened)
498
+ throw new Error(`stream_${kind}_intervention_required`);
499
+ };
500
+ for await (const token of tokens) {
501
+ const tokenBytes = typeof token === "string" ? encoder.encode(token).byteLength : -1;
502
+ totalTokens++;
503
+ totalBytes += Math.max(0, tokenBytes);
504
+ if (tokenBytes < 0 ||
505
+ tokenBytes >
506
+ INFERENCE_INTERVENTION_PAYLOAD_LIMITS_V1.maximumTokenBytes ||
507
+ totalTokens >
508
+ INFERENCE_INTERVENTION_PAYLOAD_LIMITS_V1.maximumTokenCount ||
509
+ totalBytes > INFERENCE_INTERVENTION_PAYLOAD_LIMITS_V1.maximumOutputBytes)
510
+ throw new TypeError("stream_output_limits_exceeded");
511
+ output += token;
512
+ window += token;
513
+ count++;
514
+ await examine("token", token);
515
+ if (count >= invocation.policy.maximumWindowTokens) {
516
+ await examine("window", window);
517
+ window = "";
518
+ count = 0;
519
+ }
520
+ }
521
+ if (window)
522
+ await examine("window", window);
523
+ return output;
524
+ }
525
+ validateBufferedOutput(output) {
526
+ if (typeof output !== "string" ||
527
+ encoder.encode(output).byteLength >
528
+ INFERENCE_INTERVENTION_PAYLOAD_LIMITS_V1.maximumOutputBytes)
529
+ throw new TypeError("buffered_output_limits_exceeded");
530
+ return output;
531
+ }
532
+ async requestRepresentation(invocation) {
533
+ const sidecar = this.options.sidecar;
534
+ const request = createRepresentationInterventionRequestV1({
535
+ schemaVersion: 1,
536
+ requestId: `${invocation.invocationId}:representation`,
537
+ bindingDigest: invocation.binding.bindingDigest,
538
+ policyDigest: invocation.policy.policyDigest,
539
+ inputDigest: invocation.inputDigest,
540
+ step: invocation.step,
541
+ requestedAtLogicalMs: invocation.logicalTimeMs,
542
+ });
543
+ const controller = new AbortController();
544
+ let timer;
545
+ let timedOut = false;
546
+ try {
547
+ const timeout = new Promise((_, reject) => {
548
+ timer = setTimeout(() => {
549
+ timedOut = true;
550
+ reject(new SidecarAmbiguousError(request.requestDigest));
551
+ controller.abort("representation_sidecar_timeout");
552
+ }, invocation.policy.sidecarTimeoutMs);
553
+ });
554
+ const receipt = await Promise.race([
555
+ sidecar.intervene(request, { signal: controller.signal }),
556
+ timeout,
557
+ ]);
558
+ if (timedOut)
559
+ throw new SidecarAmbiguousError(request.requestDigest);
560
+ try {
561
+ verifyRepresentationInterventionReceiptV1(request, receipt, sidecar);
562
+ }
563
+ catch {
564
+ throw new SidecarAmbiguousError(request.requestDigest);
565
+ }
566
+ if (receipt.result !== "applied")
567
+ throw new Error("representation_intervention_not_applied");
568
+ return receipt;
569
+ }
570
+ catch (error) {
571
+ if (timedOut ||
572
+ error instanceof SidecarAmbiguousError ||
573
+ (error instanceof Error &&
574
+ error.message === "representation_intervention_not_applied"))
575
+ throw timedOut
576
+ ? new SidecarAmbiguousError(request.requestDigest)
577
+ : error;
578
+ // A transport failure cannot prove whether a remote sidecar applied work.
579
+ throw new SidecarAmbiguousError(request.requestDigest);
580
+ }
581
+ finally {
582
+ if (timer !== undefined)
583
+ clearTimeout(timer);
584
+ }
585
+ }
586
+ async finishAmbiguous(prepared, original, assessments, requestDigest) {
587
+ const effect = {
588
+ kind: "sidecar_ambiguous",
589
+ invocationId: original.invocationId,
590
+ invocationDigest: this.invocationDigest(original),
591
+ executionDomain: original.executionDomain,
592
+ step: original.step,
593
+ sidecarRequestDigest: requestDigest,
594
+ };
595
+ const terminal = this.state(prepared, original, 0, 0, 0, null, { decision: "blocked", outputDigest: null }, effect);
596
+ if (!(await this.cas(prepared, terminal)))
597
+ throw new Error("terminal_state_commit_conflict");
598
+ return Object.freeze({
599
+ decision: "blocked",
600
+ output: null,
601
+ outputDigest: null,
602
+ receipt: null,
603
+ assessments: Object.freeze([...assessments]),
604
+ state: terminal,
605
+ });
606
+ }
607
+ async finish(prepared, original, assessments, output, receipt, blocked, extraIntervention, clear) {
608
+ const canCount = extraIntervention &&
609
+ prepared.interventionsUsed <
610
+ original.policy.budget.maximumInterventions &&
611
+ prepared.cooldownUntilLogicalMs <= original.logicalTimeMs;
612
+ const terminal = this.state(prepared, original, canCount ? 1 : 0, 0, clear, null, {
613
+ decision: blocked ? "blocked" : "allowed",
614
+ outputDigest: output === null ? null : digestText(output),
615
+ });
616
+ if (!(await this.cas(prepared, terminal)))
617
+ throw new Error("terminal_state_commit_conflict");
618
+ return Object.freeze({
619
+ decision: blocked ? "blocked" : "allowed",
620
+ output: blocked ? null : output,
621
+ outputDigest: blocked || output === null ? null : digestText(output),
622
+ receipt,
623
+ assessments: Object.freeze([...assessments]),
624
+ state: terminal,
625
+ });
626
+ }
627
+ async assess(invocation, signal) {
628
+ const values = await Promise.all(this.options.assessors.map((port) => port.assess({
629
+ binding: invocation.binding,
630
+ policy: invocation.policy,
631
+ step: invocation.step,
632
+ signal,
633
+ })));
634
+ for (let i = 0; i < values.length; i++)
635
+ this.verifyAssessment(values[i], this.options.assessors[i]);
636
+ return values;
637
+ }
638
+ verifyAssessment(value, port) {
639
+ const limits = INFERENCE_INTERVENTION_PAYLOAD_LIMITS_V1;
640
+ if (!value ||
641
+ value.schemaVersion !== 1 ||
642
+ value.assessorId !== port.assessorId ||
643
+ value.assessorVersion !== port.assessorVersion ||
644
+ value.assessorImplementationDigest !==
645
+ port.assessorImplementationDigest ||
646
+ !["allow", "modify", "block", "unavailable"].includes(value.decision) ||
647
+ [value.riskBps, value.uncertaintyBps, value.roleCoherenceBps].some((v) => !Number.isSafeInteger(v) || v < 0 || v > 10_000) ||
648
+ value.reasonCodes.length > limits.maximumReasonCodes ||
649
+ value.evidenceDigests.length > limits.maximumEvidenceDigests ||
650
+ value.reasonCodes.some((reason) => typeof reason !== "string" ||
651
+ reason.length === 0 ||
652
+ encoder.encode(reason).byteLength > limits.maximumReasonCodeBytes ||
653
+ /[\u0000-\u001f\u007f]/u.test(reason)) ||
654
+ value.evidenceDigests.some((digest) => !/^sha256:[0-9a-f]{64}$/.test(digest)))
655
+ throw new TypeError("invalid_assessment");
656
+ const { assessmentDigest, ...unsigned } = value;
657
+ if (assessmentDigest !== digestInferenceInterventionV1("assessment", unsigned))
658
+ throw new TypeError("assessment_digest_mismatch");
659
+ }
660
+ outcome(values) {
661
+ const t = this.options.policy.thresholds;
662
+ return {
663
+ blocked: values.some((v) => v.decision === "block" ||
664
+ v.decision === "unavailable" ||
665
+ v.riskBps >= t.blockRiskBps ||
666
+ v.uncertaintyBps > t.maximumUncertaintyBps ||
667
+ v.roleCoherenceBps < t.minimumRoleCoherenceBps),
668
+ intervened: values.some((v) => v.decision === "modify" || v.riskBps >= t.interventionRiskBps),
669
+ clear: values.filter((v) => v.decision === "allow" && v.riskBps < t.interventionRiskBps).length,
670
+ };
671
+ }
672
+ makeInvocation(raw, executionDomain) {
673
+ const invocation = {
674
+ ...raw,
675
+ executionDomain,
676
+ binding: this.options.binding,
677
+ policy: this.options.policy,
678
+ inputDigest: digestText(raw.input),
679
+ };
680
+ if (!Number.isSafeInteger(invocation.step) ||
681
+ invocation.step < 1 ||
682
+ invocation.step > invocation.policy.maximumStep ||
683
+ !Number.isSafeInteger(invocation.logicalTimeMs) ||
684
+ invocation.logicalTimeMs < 0 ||
685
+ typeof invocation.invocationId !== "string" ||
686
+ invocation.invocationId.length === 0)
687
+ throw new TypeError("invalid_invocation_identity_or_step");
688
+ this.validatePayload(invocation);
689
+ return invocation;
690
+ }
691
+ validatePayload(invocation) {
692
+ const limits = INFERENCE_INTERVENTION_PAYLOAD_LIMITS_V1;
693
+ if (typeof invocation.input !== "string" ||
694
+ encoder.encode(invocation.input).byteLength > limits.maximumInputBytes ||
695
+ invocation.context.length > limits.maximumContextItems ||
696
+ invocation.context.some((item) => typeof item !== "string" ||
697
+ encoder.encode(item).byteLength > limits.maximumContextItemBytes) ||
698
+ invocation.context.reduce((sum, item) => sum + encoder.encode(item).byteLength, 0) > limits.maximumContextBytes ||
699
+ (invocation.modalityParts?.length ?? 0) > limits.maximumModalityParts ||
700
+ (invocation.roleReinforcement !== null &&
701
+ (typeof invocation.roleReinforcement !== "string" ||
702
+ encoder.encode(invocation.roleReinforcement).byteLength >
703
+ limits.maximumRoleReinforcementBytes)))
704
+ throw new TypeError("inference_payload_limits_exceeded");
705
+ for (const part of invocation.modalityParts ?? [])
706
+ if (!["text", "image", "audio", "video", "sensor"].includes(part.kind) ||
707
+ !/^sha256:[0-9a-f]{64}$/.test(part.contentDigest) ||
708
+ (part.payloadHandle !== undefined &&
709
+ (typeof part.payloadHandle !== "string" ||
710
+ encoder.encode(part.payloadHandle).byteLength >
711
+ limits.maximumPayloadHandleBytes ||
712
+ /[\u0000-\u001f\u007f]/u.test(part.payloadHandle))))
713
+ throw new TypeError("invalid_multimodal_part");
714
+ }
715
+ transformedManifestDigest(invocation) {
716
+ return digestInferenceInterventionV1("transformed-manifest", {
717
+ inputDigest: invocation.inputDigest,
718
+ contextDigests: invocation.context.map(digestText),
719
+ modalities: (invocation.modalityParts ?? []).map((part) => ({
720
+ kind: part.kind,
721
+ contentDigest: part.contentDigest,
722
+ payloadHandleDigest: part.payloadHandle === undefined
723
+ ? null
724
+ : digestText(part.payloadHandle),
725
+ })),
726
+ });
727
+ }
728
+ invocationDigest(i) {
729
+ return digestInferenceInterventionV1(`invocation-${i.executionDomain}`, {
730
+ invocationId: i.invocationId,
731
+ executionDomain: i.executionDomain,
732
+ bindingDigest: i.binding.bindingDigest,
733
+ policyDigest: i.policy.policyDigest,
734
+ inputDigest: i.inputDigest,
735
+ contextDigests: i.context.map(digestText),
736
+ modalityManifestDigest: digestInferenceInterventionV1("modalities", (i.modalityParts ?? []).map((p) => ({
737
+ kind: p.kind,
738
+ contentDigest: p.contentDigest,
739
+ payloadHandleDigest: p.payloadHandle === undefined ? null : digestText(p.payloadHandle),
740
+ }))),
741
+ roleReinforcementDigest: i.roleReinforcement === null ? null : digestText(i.roleReinforcement),
742
+ step: i.step,
743
+ logicalTimeMs: i.logicalTimeMs,
744
+ });
745
+ }
746
+ replay(prior, invocation) {
747
+ const digest = this.invocationDigest(invocation);
748
+ if (prior?.activeInvocation) {
749
+ if (prior.activeInvocation.invocationId !== invocation.invocationId)
750
+ throw new TypeError("inference_invocation_pending");
751
+ if (prior.activeInvocation.invocationDigest !== digest ||
752
+ prior.activeInvocation.step !== invocation.step ||
753
+ prior.activeInvocation.executionDomain !== invocation.executionDomain)
754
+ throw new TypeError("conflicting_invocation_id");
755
+ if (prior.unresolvedEffect?.kind === "retry_authorized")
756
+ return null;
757
+ throw new TypeError("intervention_reconciliation_required");
758
+ }
759
+ if (prior?.lastInvocation?.invocationId === invocation.invocationId) {
760
+ if (prior.lastInvocation.invocationDigest !== digest ||
761
+ prior.lastInvocation.step !== invocation.step ||
762
+ prior.lastInvocation.executionDomain !== invocation.executionDomain)
763
+ throw new TypeError("conflicting_invocation_id");
764
+ return Object.freeze({
765
+ decision: prior.lastInvocation.decision,
766
+ output: null,
767
+ outputDigest: prior.lastInvocation.outputDigest,
768
+ receipt: null,
769
+ assessments: Object.freeze([]),
770
+ state: prior,
771
+ });
772
+ }
773
+ return null;
774
+ }
775
+ assertFresh(prior, invocation) {
776
+ if (!prior)
777
+ return;
778
+ if (invocation.step <= prior.stepHighWater ||
779
+ invocation.logicalTimeMs < prior.logicalTimeHighWaterMs)
780
+ throw new TypeError("stale_step_or_logical_time_replay");
781
+ }
782
+ async validateState(prior, invocation) {
783
+ const anchor = await this.monotonicAnchor.readAnchor(keyFor(invocation.binding));
784
+ if (!prior) {
785
+ if (anchor)
786
+ throw new TypeError("durable_state_missing_below_anchor");
787
+ return;
788
+ }
789
+ const { stateDigest, ...unsigned } = prior;
790
+ const integers = [
791
+ prior.revision,
792
+ prior.logicalTimeHighWaterMs,
793
+ prior.stepHighWater,
794
+ prior.fence,
795
+ prior.interventionsUsed,
796
+ prior.representationRequestsUsed,
797
+ prior.cooldownUntilLogicalMs,
798
+ prior.consecutiveClearAssessments,
799
+ ];
800
+ const stateShape = [
801
+ "activeInvocation",
802
+ "adapterDescriptorDigest",
803
+ "bindingDigest",
804
+ "consecutiveClearAssessments",
805
+ "cooldownUntilLogicalMs",
806
+ "fence",
807
+ "format",
808
+ "interventionsUsed",
809
+ "lastInvocation",
810
+ "lastInvocationDigest",
811
+ "logicalTimeHighWaterMs",
812
+ "policyDigest",
813
+ "representationRequestsUsed",
814
+ "revision",
815
+ "schemaVersion",
816
+ "stateDigest",
817
+ "stateKey",
818
+ "stepHighWater",
819
+ "unresolvedEffect",
820
+ ]
821
+ .sort()
822
+ .join("|");
823
+ const validActive = prior.activeInvocation === null ||
824
+ (Object.keys(prior.activeInvocation).sort().join("|") ===
825
+ "executionDomain|invocationDigest|invocationId|step" &&
826
+ typeof prior.activeInvocation.invocationId === "string" &&
827
+ ["inference", "tool", "action"].includes(prior.activeInvocation.executionDomain) &&
828
+ /^sha256:[0-9a-f]{64}$/.test(prior.activeInvocation.invocationDigest) &&
829
+ Number.isSafeInteger(prior.activeInvocation.step) &&
830
+ prior.activeInvocation.step >= 1);
831
+ const validLast = prior.lastInvocation === null ||
832
+ (Object.keys(prior.lastInvocation).sort().join("|") ===
833
+ "decision|executionDomain|invocationDigest|invocationId|outputDigest|step" &&
834
+ typeof prior.lastInvocation.invocationId === "string" &&
835
+ ["inference", "tool", "action"].includes(prior.lastInvocation.executionDomain) &&
836
+ /^sha256:[0-9a-f]{64}$/.test(prior.lastInvocation.invocationDigest) &&
837
+ Number.isSafeInteger(prior.lastInvocation.step) &&
838
+ prior.lastInvocation.step >= 1 &&
839
+ ["allowed", "blocked"].includes(prior.lastInvocation.decision) &&
840
+ (prior.lastInvocation.outputDigest === null ||
841
+ /^sha256:[0-9a-f]{64}$/.test(prior.lastInvocation.outputDigest)));
842
+ const validUnresolved = prior.unresolvedEffect === null ||
843
+ (Object.keys(prior.unresolvedEffect).sort().join("|") ===
844
+ "executionDomain|invocationDigest|invocationId|kind|sidecarRequestDigest|step" &&
845
+ ["prepared_crash", "sidecar_ambiguous", "retry_authorized"].includes(prior.unresolvedEffect.kind) &&
846
+ ["inference", "tool", "action"].includes(prior.unresolvedEffect.executionDomain) &&
847
+ /^sha256:[0-9a-f]{64}$/.test(prior.unresolvedEffect.invocationDigest) &&
848
+ (prior.unresolvedEffect.sidecarRequestDigest === null ||
849
+ /^sha256:[0-9a-f]{64}$/.test(prior.unresolvedEffect.sidecarRequestDigest)));
850
+ const currentStep = prior.activeInvocation?.step ?? prior.lastInvocation?.step ?? 0;
851
+ if (Object.keys(prior).sort().join("|") !== stateShape ||
852
+ stateDigest !== digestInferenceInterventionV1("state", unsigned) ||
853
+ prior.format !== HETEROGENEOUS_INFERENCE_INTERVENTION_STATE_FORMAT_V1 ||
854
+ prior.schemaVersion !== 1 ||
855
+ prior.stateKey !== keyFor(invocation.binding) ||
856
+ prior.bindingDigest !== invocation.binding.bindingDigest ||
857
+ prior.policyDigest !== invocation.policy.policyDigest ||
858
+ prior.adapterDescriptorDigest !==
859
+ this.options.adapter.descriptor.descriptorDigest ||
860
+ prior.fence !== invocation.binding.fence ||
861
+ integers.some((value) => !Number.isSafeInteger(value) || value < 0) ||
862
+ prior.revision < 1 ||
863
+ !validActive ||
864
+ !validLast ||
865
+ !validUnresolved ||
866
+ prior.stepHighWater !== currentStep ||
867
+ prior.lastInvocationDigest !==
868
+ (prior.lastInvocation?.invocationDigest ?? null) ||
869
+ (prior.activeInvocation !== null) !==
870
+ (prior.unresolvedEffect?.kind === "prepared_crash" ||
871
+ prior.unresolvedEffect?.kind === "retry_authorized") ||
872
+ prior.interventionsUsed > invocation.policy.budget.maximumInterventions ||
873
+ prior.representationRequestsUsed >
874
+ invocation.policy.budget.maximumRepresentationRequests ||
875
+ (prior.activeInvocation !== null &&
876
+ prior.lastInvocation !== null &&
877
+ prior.activeInvocation.step <= prior.lastInvocation.step) ||
878
+ (anchor !== null &&
879
+ (prior.revision < anchor.revision ||
880
+ prior.interventionsUsed < anchor.interventionsUsed ||
881
+ prior.representationRequestsUsed < anchor.representationRequestsUsed)))
882
+ throw new TypeError("invalid_durable_intervention_state");
883
+ }
884
+ state(prior, i, interventionDelta, representationDelta, clear, active, terminal, unresolved) {
885
+ const invocationDigest = this.invocationDigest(i);
886
+ const unresolvedEffect = unresolved !== undefined
887
+ ? unresolved
888
+ : active
889
+ ? {
890
+ kind: "prepared_crash",
891
+ invocationId: active.invocationId,
892
+ invocationDigest: active.invocationDigest,
893
+ executionDomain: active.executionDomain,
894
+ step: active.step,
895
+ sidecarRequestDigest: null,
896
+ }
897
+ : terminal
898
+ ? null
899
+ : (prior?.unresolvedEffect ?? null);
900
+ const unsigned = {
901
+ format: HETEROGENEOUS_INFERENCE_INTERVENTION_STATE_FORMAT_V1,
902
+ schemaVersion: 1,
903
+ stateKey: keyFor(i.binding),
904
+ bindingDigest: i.binding.bindingDigest,
905
+ policyDigest: i.policy.policyDigest,
906
+ adapterDescriptorDigest: this.options.adapter.descriptor.descriptorDigest,
907
+ revision: (prior?.revision ?? 0) + 1,
908
+ logicalTimeHighWaterMs: Math.max(prior?.logicalTimeHighWaterMs ?? 0, i.logicalTimeMs),
909
+ stepHighWater: Math.max(prior?.stepHighWater ?? 0, i.step),
910
+ fence: i.binding.fence,
911
+ interventionsUsed: (prior?.interventionsUsed ?? 0) + interventionDelta,
912
+ representationRequestsUsed: (prior?.representationRequestsUsed ?? 0) + representationDelta,
913
+ cooldownUntilLogicalMs: interventionDelta
914
+ ? i.logicalTimeMs + i.policy.budget.cooldownLogicalMs
915
+ : (prior?.cooldownUntilLogicalMs ?? 0),
916
+ consecutiveClearAssessments: clear
917
+ ? (prior?.consecutiveClearAssessments ?? 0) + clear
918
+ : 0,
919
+ lastInvocationDigest: terminal
920
+ ? invocationDigest
921
+ : (prior?.lastInvocationDigest ?? null),
922
+ activeInvocation: active,
923
+ lastInvocation: terminal
924
+ ? {
925
+ invocationId: i.invocationId,
926
+ invocationDigest,
927
+ executionDomain: i.executionDomain,
928
+ step: i.step,
929
+ decision: terminal.decision,
930
+ outputDigest: terminal.outputDigest,
931
+ }
932
+ : (prior?.lastInvocation ?? null),
933
+ unresolvedEffect,
934
+ };
935
+ return Object.freeze({
936
+ ...unsigned,
937
+ stateDigest: digestInferenceInterventionV1("state", unsigned),
938
+ });
939
+ }
940
+ cas(prior, next) {
941
+ return this.store.compareAndSet({
942
+ stateKey: next.stateKey,
943
+ expectedRevision: prior?.revision ?? null,
944
+ expectedStateDigest: prior?.stateDigest ?? null,
945
+ next,
946
+ });
947
+ }
948
+ assertPort(id, version, digest, kind) {
949
+ if (typeof id !== "string" ||
950
+ id.length === 0 ||
951
+ !Number.isSafeInteger(version) ||
952
+ version < 1 ||
953
+ typeof digest !== "string" ||
954
+ !/^sha256:[0-9a-f]{64}$/.test(digest))
955
+ throw new TypeError(`invalid_${kind}_identity`);
956
+ }
957
+ }
958
+ //# sourceMappingURL=intervention-runtime.js.map