effect-agent 0.1.0-beta.96 → 0.1.0-beta.97

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 (102) hide show
  1. package/dist/{DurableAgentRuntime-BGwGUIT-.mjs → DurableAgentRuntime-DbUvZHDZ.mjs} +34 -30
  2. package/dist/DurableAgentRuntime-DbUvZHDZ.mjs.map +1 -0
  3. package/dist/{EventSource-tCO_dAff.d.mts → EventSource-D6PAAEyK.d.mts} +3 -3
  4. package/dist/{PreparedInputAdmission-CFSddiT8.d.mts → PreparedInputAdmission-omMbwd--.d.mts} +4 -4
  5. package/dist/{Records-BEz5IFUu.mjs → Records-BAutSSnJ.mjs} +3 -1
  6. package/dist/Records-BAutSSnJ.mjs.map +1 -0
  7. package/dist/{Records-CMByd1eD.d.mts → Records-CV49DgQK.d.mts} +37 -9
  8. package/dist/{RunJournal-B_fxe57c.mjs → RunJournal-DRRRZmG7.mjs} +2 -2
  9. package/dist/{RunJournal-B_fxe57c.mjs.map → RunJournal-DRRRZmG7.mjs.map} +1 -1
  10. package/dist/{Schedule-BxCfnYr0.d.mts → Schedule-DePbGfgd.d.mts} +2 -2
  11. package/dist/{Scheduling-BW6BD_TP.mjs → Scheduling-C3QpYn0W.mjs} +2 -2
  12. package/dist/{Scheduling-BW6BD_TP.mjs.map → Scheduling-C3QpYn0W.mjs.map} +1 -1
  13. package/dist/{Subscription-CrTIQKZR.d.mts → Subscription-BR_8Cxh3.d.mts} +3 -3
  14. package/dist/{SubscriptionInput-BVOeFF1L.d.mts → SubscriptionInput-B95sQbuk.d.mts} +3 -3
  15. package/dist/{agent-registration-BTa5vmQF.mjs → agent-registration-CXGDwvJH.mjs} +151 -26
  16. package/dist/agent-registration-CXGDwvJH.mjs.map +1 -0
  17. package/dist/durable/ActivityStore.d.mts +1 -1
  18. package/dist/durable/ActivityStore.mjs +1 -1
  19. package/dist/durable/Admin.d.mts +1 -1
  20. package/dist/durable/Admin.mjs +1 -1
  21. package/dist/durable/AgentRegistration.d.mts +2 -2
  22. package/dist/durable/AgentRegistration.mjs +3 -2
  23. package/dist/durable/AgentRegistration.mjs.map +1 -1
  24. package/dist/durable/Certification.d.mts +1 -1
  25. package/dist/durable/CommittedActivity.d.mts +1 -1
  26. package/dist/durable/CommittedActivity.mjs +1 -1
  27. package/dist/durable/Digest.d.mts +1 -1
  28. package/dist/durable/Digest.mjs +1 -1
  29. package/dist/durable/DurableAgentRuntime.d.mts +1 -1
  30. package/dist/durable/DurableAgentRuntime.mjs +1 -1
  31. package/dist/durable/EventSource.d.mts +1 -1
  32. package/dist/durable/EventSource.mjs +1 -1
  33. package/dist/durable/GitHubWorkflowSource.d.mts +3 -3
  34. package/dist/durable/GitHubWorkflowSource.mjs +1 -1
  35. package/dist/durable/MessageDelivery.d.mts +3 -3
  36. package/dist/durable/MessageDelivery.mjs +1 -1
  37. package/dist/durable/MessageDeliveryStoreConformance.d.mts +1 -1
  38. package/dist/durable/MessageDeliveryStoreConformance.mjs +1 -1
  39. package/dist/durable/PersistentHistory.d.mts +1 -1
  40. package/dist/durable/PersistentHistory.mjs +2 -2
  41. package/dist/durable/PreparedInputAdmission.d.mts +1 -1
  42. package/dist/durable/Records.d.mts +1 -1
  43. package/dist/durable/Records.mjs +1 -1
  44. package/dist/durable/Recovery.d.mts +1 -1
  45. package/dist/durable/Recovery.mjs +1 -1
  46. package/dist/durable/RunJournal.d.mts +1 -1
  47. package/dist/durable/RunJournal.mjs +1 -1
  48. package/dist/durable/Schedule.d.mts +1 -1
  49. package/dist/durable/Schedule.mjs +1 -1
  50. package/dist/durable/ScheduleStoreConformance.d.mts +1 -1
  51. package/dist/durable/ScheduleStoreConformance.mjs +1 -1
  52. package/dist/durable/ScheduleTransition.d.mts +1 -1
  53. package/dist/durable/ScheduleTransition.mjs +1 -1
  54. package/dist/durable/Scheduling.d.mts +2 -2
  55. package/dist/durable/Scheduling.mjs +1 -1
  56. package/dist/durable/SqlStorageV2Upgrade.d.mts +2 -2
  57. package/dist/durable/SqlStorageV2Upgrade.mjs +1 -1
  58. package/dist/durable/SqlSubscriptionStore.d.mts +2 -2
  59. package/dist/durable/SqlSubscriptionStore.mjs +1 -1
  60. package/dist/durable/SubmissionLedger.d.mts +1 -1
  61. package/dist/durable/SubmissionLedger.mjs +1 -1
  62. package/dist/durable/SubmissionLedgerConformance.d.mts +1 -1
  63. package/dist/durable/SubmissionLedgerConformance.mjs +1 -1
  64. package/dist/durable/SubmissionStatus.d.mts +1 -1
  65. package/dist/durable/Subscription.d.mts +1 -1
  66. package/dist/durable/Subscription.mjs +1 -1
  67. package/dist/durable/SubscriptionInput.d.mts +1 -1
  68. package/dist/durable/SubscriptionInput.mjs +2 -2
  69. package/dist/durable/SubscriptionStoreConformance.d.mts +1 -1
  70. package/dist/durable/SubscriptionStoreConformance.mjs +1 -1
  71. package/dist/durable/SubscriptionTools.d.mts +3 -3
  72. package/dist/durable/SubscriptionTransition.d.mts +1 -1
  73. package/dist/durable/SubscriptionTransition.mjs +1 -1
  74. package/dist/durable/Subscriptions.d.mts +5 -5
  75. package/dist/durable/Subscriptions.mjs +1 -1
  76. package/dist/durable/ThreadContextHistory.d.mts +1 -1
  77. package/dist/durable/ThreadContextHistory.mjs +1 -1
  78. package/dist/durable/ThreadContextHistoryProjection.d.mts +1 -1
  79. package/dist/durable/ThreadContextHistoryProjection.mjs +1 -1
  80. package/dist/durable/ThreadInvariants.d.mts +1 -1
  81. package/dist/durable/ThreadInvariants.mjs +1 -1
  82. package/dist/durable/ThreadProjection.d.mts +1 -1
  83. package/dist/durable/ThreadProjection.mjs +1 -1
  84. package/dist/durable/ThreadProjectionMaintenance.d.mts +1 -1
  85. package/dist/durable/ThreadStore.d.mts +1 -1
  86. package/dist/durable/ThreadStore.mjs +1 -1
  87. package/dist/durable/ThreadStoreConformance.d.mts +1 -1
  88. package/dist/durable/ThreadStoreConformance.mjs +1 -1
  89. package/dist/durable/ToolReconciler.mjs +1 -1
  90. package/dist/durable/WorkerHost.d.mts +1 -1
  91. package/dist/index.d.mts +6 -6
  92. package/dist/index.mjs +4 -4
  93. package/package.json +1 -1
  94. package/src/durable/AgentRegistration.ts +1 -0
  95. package/src/durable/DurableAgentRuntime.ts +3 -1
  96. package/src/durable/Records.ts +2 -0
  97. package/src/durable/internal/agent-registration.ts +274 -36
  98. package/src/durable/internal/messaging-host.ts +2 -5
  99. package/src/durable/internal/worker-host.ts +119 -85
  100. package/dist/DurableAgentRuntime-BGwGUIT-.mjs.map +0 -1
  101. package/dist/Records-BEz5IFUu.mjs.map +0 -1
  102. package/dist/agent-registration-BTa5vmQF.mjs.map +0 -1
@@ -1,4 +1,13 @@
1
- import { type Crypto, type Option, type Scope, Context, Effect, Layer, Schema } from "effect";
1
+ import {
2
+ type Crypto,
3
+ type Option,
4
+ type Scope,
5
+ Array,
6
+ Context,
7
+ Effect,
8
+ Layer,
9
+ Schema,
10
+ } from "effect";
2
11
  import { Tool } from "effect/unstable/ai";
3
12
 
4
13
  import type * as Agent from "../../core/Agent.ts";
@@ -30,7 +39,7 @@ import {
30
39
  DefinitionDigestInput,
31
40
  DefinitionDigests,
32
41
  ReplayContract,
33
- type PersistedJson,
42
+ PersistedJson,
34
43
  } from "../Records.ts";
35
44
  import type { Claim, Settlement } from "../SubmissionLedger.ts";
36
45
 
@@ -88,10 +97,34 @@ export interface ReplayVersions {
88
97
  * manifest from the original release for work admitted before replay contracts were retained.
89
98
  * Its original declarations must hash to that admission; a bare old digest is not a manifest.
90
99
  */
100
+ const ToolReplayDeclaration = Schema.Struct({
101
+ version: PersistedJson,
102
+ parameters: PersistedJson,
103
+ success: PersistedJson,
104
+ failure: PersistedJson,
105
+ failureMode: Schema.String,
106
+ needsApproval: Schema.Union([Schema.Boolean, Schema.Literal("dynamic")]),
107
+ executionClass: Schema.String,
108
+ executionKind: Schema.String,
109
+ });
110
+
111
+ const AgentReplayDeclaration = Schema.Struct({
112
+ version: PersistedJson,
113
+ id: AgentId,
114
+ input: PersistedJson,
115
+ output: PersistedJson,
116
+ updates: Schema.NullOr(PersistedJson),
117
+ completion: Schema.NullOr(Schema.Struct({ tool: Schema.String, required: Schema.Boolean })),
118
+ completionFromTools: Schema.Array(Schema.String),
119
+ disposition: Schema.NullOr(PersistedJson),
120
+ });
121
+
91
122
  export class BindingManifest extends Schema.Class<BindingManifest>("BindingManifest")({
92
123
  agentId: AgentId,
93
124
  definitions: DefinitionDigestInput,
94
125
  replay: ReplayContract,
126
+ agentContract: Schema.optionalKey(AgentReplayDeclaration),
127
+ toolContracts: Schema.optionalKey(Schema.Record(Schema.String, ToolReplayDeclaration)),
95
128
  }) {}
96
129
 
97
130
  export const makeBindingManifest = Effect.fn("AgentRegistration.makeBindingManifest")(function* (
@@ -154,6 +187,7 @@ export const makeBindingManifest = Effect.fn("AgentRegistration.makeBindingManif
154
187
  });
155
188
 
156
189
  const agent = yield* digestJson(contracts.agent);
190
+ const agentBehavior = yield* digestJson({ ...contracts.agent, input: null });
157
191
 
158
192
  const tools = yield* Effect.forEach(contracts.tools, ({ name, contract }) =>
159
193
  digestJson(contract).pipe(Effect.map((digest) => [name, digest] as const)),
@@ -162,37 +196,249 @@ export const makeBindingManifest = Effect.fn("AgentRegistration.makeBindingManif
162
196
  return BindingManifest.make({
163
197
  agentId: definition.id,
164
198
  definitions,
165
- replay: ReplayContract.make({ agent, tools: Object.fromEntries(tools) }),
199
+ replay: ReplayContract.make({ agent, agentBehavior, tools: Object.fromEntries(tools) }),
200
+ agentContract: contracts.agent,
201
+ toolContracts: Object.fromEntries(
202
+ contracts.tools.map(({ name, contract }) => [name, contract]),
203
+ ),
166
204
  });
167
205
  });
168
206
 
207
+ const jsonEqual = Schema.toEquivalence(PersistedJson);
208
+
209
+ // JSON Schema generation can widen object openness without changing an Effect codec.
210
+ // Prove only this widening; all other codec changes still require an exact contract.
211
+ const schemasCompatible = (previous: PersistedJson, current: PersistedJson): boolean => {
212
+ if (jsonEqual(previous, current)) return true;
213
+
214
+ const hasNegativeSchema = (value: PersistedJson): boolean => {
215
+ if (Array.isArray<PersistedJson>(value)) return value.some(hasNegativeSchema);
216
+ if (value === null || typeof value !== "object") return false;
217
+
218
+ return Object.entries(value).some(
219
+ ([key, child]) =>
220
+ key === "oneOf" ||
221
+ key === "maxContains" ||
222
+ key === "unevaluatedProperties" ||
223
+ key === "unevaluatedItems" ||
224
+ key === "if" ||
225
+ key === "then" ||
226
+ key === "else" ||
227
+ key === "$dynamicRef" ||
228
+ key === "$recursiveRef" ||
229
+ (key === "not" && !jsonEqual(child, {})) ||
230
+ hasNegativeSchema(child),
231
+ );
232
+ };
233
+
234
+ if (hasNegativeSchema(previous) || hasNegativeSchema(current)) return false;
235
+
236
+ const compare = (before: PersistedJson, after: PersistedJson): boolean => {
237
+ if (jsonEqual(before, after)) return true;
238
+ if (
239
+ before === null ||
240
+ typeof before !== "object" ||
241
+ Array.isArray<PersistedJson>(before) ||
242
+ after === null ||
243
+ typeof after !== "object" ||
244
+ Array.isArray<PersistedJson>(after)
245
+ )
246
+ return false;
247
+ if (Object.keys(before).length !== Object.keys(after).length) return false;
248
+
249
+ return Object.entries(before).every(([key, value]) => {
250
+ if (!Object.hasOwn(after, key)) return false;
251
+ const next = after[key]!;
252
+
253
+ if (jsonEqual(value, next)) return true;
254
+ if (key === "additionalProperties") return value === false && next === true;
255
+ if (key === "items") return compare(value, next);
256
+ if (
257
+ (key === "anyOf" || key === "allOf") &&
258
+ Array.isArray<PersistedJson>(value) &&
259
+ Array.isArray<PersistedJson>(next)
260
+ )
261
+ return (
262
+ value.length === next.length &&
263
+ value.every((entry, index) => compare(entry, next[index]!))
264
+ );
265
+ if (
266
+ (key === "properties" || key === "$defs" || key === "definitions") &&
267
+ value !== null &&
268
+ typeof value === "object" &&
269
+ !Array.isArray<PersistedJson>(value) &&
270
+ next !== null &&
271
+ typeof next === "object" &&
272
+ !Array.isArray<PersistedJson>(next)
273
+ )
274
+ return (
275
+ Object.keys(value).length === Object.keys(next).length &&
276
+ Object.entries(value).every(
277
+ ([name, schema]) => Object.hasOwn(next, name) && compare(schema, next[name]!),
278
+ )
279
+ );
280
+
281
+ return false;
282
+ });
283
+ };
284
+
285
+ return compare(previous, current);
286
+ };
287
+
288
+ /** Compile audited declaration data once, without acquiring an executable or rewriting receipts.
289
+ * Full input schemas stay in registration metadata, never in each admission's replay contract. */
290
+ export const compileBindingManifest = Effect.fn("AgentRegistration.compileBindingManifest")(
291
+ function* (
292
+ definition: Agent.AnyDefinition,
293
+ definitions: DefinitionDigestInput,
294
+ versions: ReplayVersions,
295
+ retained: ReadonlyArray<BindingManifest> = [],
296
+ ): Effect.fn.Return<
297
+ Pick<ResolvedBinding, "digests" | "manifest" | "retainedManifests" | "acceptsInput">,
298
+ DigestError,
299
+ Crypto.Crypto
300
+ > {
301
+ const manifest = yield* makeBindingManifest(definition, definitions, versions);
302
+
303
+ const validContract = Effect.fnUntraced(function* (entry: BindingManifest) {
304
+ if (entry.agentContract === undefined) return undefined;
305
+ if (
306
+ entry.agentContract.id !== entry.agentId ||
307
+ (yield* digestJson(entry.agentContract)) !== entry.replay.agent ||
308
+ (entry.replay.agentBehavior !== undefined &&
309
+ (yield* digestJson({ ...entry.agentContract, input: null })) !==
310
+ entry.replay.agentBehavior)
311
+ )
312
+ return yield* DigestError.make({
313
+ message: "A manifest's Agent contract does not match its replay digest",
314
+ });
315
+
316
+ return entry.agentContract;
317
+ });
318
+
319
+ const current = manifest.agentContract!;
320
+ const acceptsInput = Schema.is(Schema.toEncoded(definition.input));
321
+
322
+ const validateTools = Effect.fnUntraced(function* (entry: BindingManifest) {
323
+ for (const [name, contract] of Object.entries(entry.toolContracts ?? {}))
324
+ if ((yield* digestJson(contract)) !== entry.replay.tools[name])
325
+ return yield* DigestError.make({
326
+ message: "A manifest's Tool contract does not match its replay digest",
327
+ });
328
+ });
329
+
330
+ const digests = yield* digestDefinitions(manifest.definitions);
331
+
332
+ const retainedManifests = yield* Effect.forEach(
333
+ retained,
334
+ Effect.fnUntraced(function* (entry) {
335
+ if (entry.agentId !== manifest.agentId)
336
+ return yield* DigestError.make({
337
+ message: "A retained manifest belongs to another Agent",
338
+ });
339
+ const previous = yield* validContract(entry);
340
+
341
+ yield* validateTools(entry);
342
+
343
+ const compatible =
344
+ previous !== undefined &&
345
+ jsonEqual(
346
+ { ...previous, input: null, output: null, updates: null, disposition: null },
347
+ { ...current, input: null, output: null, updates: null, disposition: null },
348
+ ) &&
349
+ schemasCompatible(previous.output, current.output) &&
350
+ schemasCompatible(previous.updates, current.updates) &&
351
+ schemasCompatible(previous.disposition, current.disposition);
352
+
353
+ const compatibleTools: Record<string, string> = {};
354
+
355
+ for (const [name, oldTool] of Object.entries(entry.toolContracts ?? {})) {
356
+ const newTool = manifest.toolContracts?.[name];
357
+
358
+ if (
359
+ newTool !== undefined &&
360
+ jsonEqual(
361
+ { ...oldTool, parameters: null, success: null, failure: null },
362
+ { ...newTool, parameters: null, success: null, failure: null },
363
+ ) &&
364
+ schemasCompatible(oldTool.parameters, newTool.parameters) &&
365
+ schemasCompatible(oldTool.success, newTool.success) &&
366
+ schemasCompatible(oldTool.failure, newTool.failure)
367
+ )
368
+ compatibleTools[name] = manifest.replay.tools[name]!;
369
+ }
370
+
371
+ return {
372
+ digests: yield* digestDefinitions(entry.definitions),
373
+ replay: entry.replay,
374
+ compatibleTools,
375
+ ...(compatible ? { compatibleAgent: manifest.replay.agent } : {}),
376
+ };
377
+ }),
378
+ );
379
+
380
+ return {
381
+ digests: DefinitionDigests.make({ ...digests, replay: manifest.replay }),
382
+ manifest,
383
+ retainedManifests,
384
+ acceptsInput: (input: PersistedJson) => {
385
+ // Async checks and defective guards cannot establish synchronous replay proof.
386
+ try {
387
+ return acceptsInput(input);
388
+ } catch {
389
+ return false;
390
+ }
391
+ },
392
+ };
393
+ },
394
+ );
395
+
169
396
  const replaySupports = (
170
397
  current: ReplayContract,
171
398
  retained: ReplayContract,
172
399
  requiredTools?: ReadonlyArray<string>,
400
+ inputCompatible = false,
401
+ compatibleTools: Readonly<Record<string, string>> = {},
173
402
  ): boolean =>
174
- current.agent === retained.agent &&
403
+ (current.agent === retained.agent || inputCompatible) &&
175
404
  (requiredTools ?? Object.keys(retained.tools)).every(
176
- (name) => retained.tools[name] !== undefined && current.tools[name] === retained.tools[name],
405
+ (name) =>
406
+ retained.tools[name] !== undefined &&
407
+ (current.tools[name] === retained.tools[name] ||
408
+ (current.tools[name] !== undefined && compatibleTools[name] === current.tools[name])),
177
409
  );
178
410
 
179
411
  /** Resolve executable code only. Admission, delivery, lineage and receipt comparisons stay exact. */
180
412
  export const bindingSupports = (
181
- binding: Pick<ResolvedBinding, "digests" | "retainedManifests">,
413
+ binding: Pick<ResolvedBinding, "digests" | "retainedManifests" | "acceptsInput">,
182
414
  digests: DefinitionDigests,
183
415
  requiredTools?: ReadonlyArray<string>,
416
+ input?: PersistedJson,
184
417
  ): boolean => {
185
418
  if (definitionDigestsEqual(binding.digests, digests)) return true;
186
419
 
187
- const retained =
188
- digests.replay ??
189
- binding.retainedManifests?.find((entry) => definitionDigestsEqual(entry.digests, digests))
190
- ?.replay;
420
+ const manifest = binding.retainedManifests?.find(
421
+ (entry) =>
422
+ definitionDigestsEqual(entry.digests, digests) ||
423
+ definitionDigestsEqual({ ...entry.digests, replay: entry.replay }, digests),
424
+ );
425
+
426
+ const retained = digests.replay ?? manifest?.replay;
191
427
 
192
428
  return (
193
429
  binding.digests.replay !== undefined &&
194
430
  retained !== undefined &&
195
- replaySupports(binding.digests.replay, retained, requiredTools)
431
+ replaySupports(
432
+ binding.digests.replay,
433
+ retained,
434
+ requiredTools,
435
+ input !== undefined &&
436
+ binding.acceptsInput?.(input) === true &&
437
+ ((binding.digests.replay.agentBehavior !== undefined &&
438
+ binding.digests.replay.agentBehavior === retained.agentBehavior) ||
439
+ manifest?.compatibleAgent === binding.digests.replay.agent),
440
+ manifest?.compatibleTools,
441
+ )
196
442
  );
197
443
  };
198
444
 
@@ -327,9 +573,14 @@ const backgroundReports = (definition: Agent.AnyDefinition) => [
327
573
  export interface ResolvedBinding extends CapturedBinding {
328
574
  readonly digests: DefinitionDigests;
329
575
  readonly manifest?: BindingManifest;
576
+ /** Current encoded input guard, acquired without executable services. */
577
+ readonly acceptsInput?: (input: PersistedJson) => boolean;
330
578
  readonly retainedManifests?: ReadonlyArray<{
331
579
  readonly digests: DefinitionDigests;
332
580
  readonly replay: ReplayContract;
581
+ readonly compatibleTools?: Readonly<Record<string, string>>;
582
+ /** Original declarations prove unchanged semantics and output/completion contracts. */
583
+ readonly compatibleAgent?: string;
333
584
  }>;
334
585
  }
335
586
 
@@ -429,6 +680,7 @@ export const resolveWorkerBinding = (
429
680
  agentId: AgentId,
430
681
  digests: DefinitionDigests,
431
682
  requiredTools?: ReadonlyArray<string>,
683
+ input?: PersistedJson,
432
684
  ): Effect.Effect<ResolvedBinding, DurableBindingFailure> => {
433
685
  const registered = bindings.filter((binding) => binding.agentId === agentId);
434
686
 
@@ -444,7 +696,7 @@ export const resolveWorkerBinding = (
444
696
 
445
697
  const compatible =
446
698
  exact ??
447
- (registered.length === 1 && bindingSupports(registered[0]!, digests, requiredTools)
699
+ (registered.length === 1 && bindingSupports(registered[0]!, digests, requiredTools, input)
448
700
  ? registered[0]
449
701
  : undefined);
450
702
 
@@ -632,8 +884,8 @@ const compileRegistration = <Entry extends AgentRegistration>(
632
884
  try: () => registrationDefinitions(entry),
633
885
  catch: () =>
634
886
  DigestError.make({ message: "Agent update schema has no serializable wire contract" }),
635
- }).pipe(Effect.flatMap(digestDefinitions)),
636
- (digests) =>
887
+ }),
888
+ (definitions) =>
637
889
  Effect.gen(function* () {
638
890
  const binding = yield* capture(
639
891
  entry.model === undefined ? entry.agent : { definition: entry.agent, model: entry.model },
@@ -645,32 +897,18 @@ const compileRegistration = <Entry extends AgentRegistration>(
645
897
  ...backgroundReports(binding.definition),
646
898
  ]);
647
899
 
648
- if (entry.continuity === undefined) return { ...binding, digests, reporting };
649
-
650
- const manifest = yield* makeBindingManifest(
651
- binding.definition,
652
- registrationDefinitions(entry),
653
- entry.continuity.versions,
654
- );
655
-
656
- const retainedManifests = yield* Effect.forEach(
657
- entry.continuity.retainedManifests ?? [],
658
- (retained) =>
659
- retained.agentId === binding.agentId
660
- ? digestDefinitions(retained.definitions).pipe(
661
- Effect.map((digests) => ({ digests, replay: retained.replay })),
662
- )
663
- : Effect.fail(
664
- DigestError.make({ message: "A retained manifest belongs to another Agent" }),
665
- ),
666
- );
900
+ if (entry.continuity === undefined)
901
+ return { ...binding, digests: yield* digestDefinitions(definitions), reporting };
667
902
 
668
903
  return {
669
904
  ...binding,
670
- digests: DefinitionDigests.make({ ...digests, replay: manifest.replay }),
905
+ ...(yield* compileBindingManifest(
906
+ binding.definition,
907
+ definitions,
908
+ entry.continuity.versions,
909
+ entry.continuity.retainedManifests,
910
+ )),
671
911
  reporting,
672
- manifest,
673
- retainedManifests,
674
912
  };
675
913
  }),
676
914
  // The erased descriptor accepts arbitrary provided services. Restore the concrete entry's
@@ -103,10 +103,7 @@ export const makeMessagingRuntime = Effect.fn("MessagingHost.make")(function* (
103
103
 
104
104
  if (created?._tag !== "ThreadCreated") return yield* failure("context", "not-found");
105
105
 
106
- const matching = deps.bindings.filter(
107
- (binding) =>
108
- binding.agentId === created.agentId && bindingSupports(binding, created.definitions),
109
- );
106
+ const matching = deps.bindings.filter((binding) => binding.agentId === created.agentId);
110
107
 
111
108
  if (matching.length !== 1) return yield* failure("context", "binding-mismatch");
112
109
 
@@ -310,7 +307,7 @@ export const makeMessagingRuntime = Effect.fn("MessagingHost.make")(function* (
310
307
  !Schema.is(MessageAdmission)(metadata) ||
311
308
  metadata.peerName !== request.name ||
312
309
  saved.envelope.agentId !== target.agentId ||
313
- !bindingSupports(target, saved.envelope.definitions) ||
310
+ !bindingSupports(target, saved.envelope.definitions, undefined, saved.envelope.input) ||
314
311
  !sameJson(saved.envelope.input, input) ||
315
312
  (inReplyTo === undefined || metadata.inReplyTo === undefined
316
313
  ? inReplyTo !== metadata.inReplyTo