@effect-agent/testing 0.1.0-beta.38 → 0.1.0-beta.40

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 (44) hide show
  1. package/dist/certification.d.mts +102 -0
  2. package/dist/certification.mjs +561 -0
  3. package/dist/certification.mjs.map +1 -0
  4. package/dist/chaos.d.mts +124 -0
  5. package/dist/chaos.mjs +739 -0
  6. package/dist/chaos.mjs.map +1 -0
  7. package/dist/code-executor.d.mts +48 -0
  8. package/dist/code-executor.mjs +565 -0
  9. package/dist/code-executor.mjs.map +1 -0
  10. package/dist/deterministic-layers-CKyYxBhN.mjs +354 -0
  11. package/dist/deterministic-layers-CKyYxBhN.mjs.map +1 -0
  12. package/dist/docs-researcher.d.mts +254 -0
  13. package/dist/docs-researcher.mjs +479 -0
  14. package/dist/docs-researcher.mjs.map +1 -0
  15. package/dist/index.d.mts +2 -2947
  16. package/dist/index.mjs +2 -4913
  17. package/dist/scripted-model-C2y0ztuj.mjs +167 -0
  18. package/dist/scripted-model-C2y0ztuj.mjs.map +1 -0
  19. package/dist/scripted-model-dOa_e0-n.d.mts +677 -0
  20. package/dist/travel-planner.d.mts +1767 -0
  21. package/dist/travel-planner.mjs +2103 -0
  22. package/dist/travel-planner.mjs.map +1 -0
  23. package/package.json +34 -11
  24. package/src/certification.ts +71 -61
  25. package/src/chaos.ts +58 -71
  26. package/src/code-executor.ts +3 -0
  27. package/src/docs-researcher.ts +2 -0
  28. package/src/fixtures/docs-researcher/definition.ts +7 -7
  29. package/src/fixtures/docs-researcher/harness.ts +12 -14
  30. package/src/fixtures/docs-researcher/index.ts +1 -1
  31. package/src/fixtures/travel-planner/definition.ts +1 -1
  32. package/src/fixtures/travel-planner/deterministic-layers.ts +7 -4
  33. package/src/fixtures/travel-planner/phase2.ts +1 -1
  34. package/src/fixtures/travel-planner/phase3.ts +14 -18
  35. package/src/fixtures/travel-planner/phase4.ts +7 -7
  36. package/src/fixtures/travel-planner/phase5.ts +5 -5
  37. package/src/fixtures/travel-planner/phase6.ts +30 -29
  38. package/src/fixtures/travel-planner/subagents-durable.ts +6 -6
  39. package/src/fixtures/travel-planner/subagents.ts +4 -4
  40. package/src/index.ts +1 -10
  41. package/src/travel-planner.ts +2 -0
  42. package/dist/index.mjs.map +0 -1
  43. package/src/code-executor-conformance.d.ts +0 -30
  44. package/src/fixtures/warehouse/index.ts +0 -412
package/src/chaos.ts CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  import {
8
8
  Agent,
9
9
  AgentPolicy,
10
- ConversationId,
10
+ ThreadId,
11
11
  IdGenerator,
12
12
  RunId,
13
13
  ToolCallId,
@@ -17,17 +17,15 @@ import {
17
17
  import { DurableStep, DurableStepError, ToolExecutionClass } from "@effect-agent/engine";
18
18
  import {
19
19
  AbortCommand,
20
- AgentBindingResolver,
21
20
  ApprovalDecisionCommand,
22
- ConversationExportRequest,
23
- ConversationStore,
21
+ ThreadExportRequest,
22
+ ThreadStore,
24
23
  DefinitionDigests,
25
24
  Digest,
26
25
  DurableAgentRuntime,
27
26
  DurableRuntimeConfig,
28
27
  DurableRuntimeFailpointError,
29
28
  DurableRuntimeFailpointLocation,
30
- DurableRuntimeFailpointTestControl,
31
29
  DurableWorkerBinding,
32
30
  IdempotencyKey,
33
31
  ObligationThresholds,
@@ -38,8 +36,8 @@ import {
38
36
  SubmissionLedger,
39
37
  SubmissionLookupById,
40
38
  UnknownResolutionCommand,
41
- childConversationIdFor,
42
- verifyConversationInvariants,
39
+ childThreadIdFor,
40
+ verifyThreadInvariants,
43
41
  type CanonicalRecordEnvelope,
44
42
  type BatchId,
45
43
  type DurableBindingFailure,
@@ -51,7 +49,8 @@ import {
51
49
  type Settlement,
52
50
  type SubmissionSnapshot,
53
51
  type UnknownResolution,
54
- } from "@effect-agent/session";
52
+ } from "@effect-agent/thread";
53
+ import { DurableRuntimeFailpointTestControl } from "@effect-agent/thread/testing";
55
54
  import { Cause, Effect, Exit, Layer, Option, Ref, Schema, Stream } from "effect";
56
55
  import { FastCheck } from "effect/testing";
57
56
  import {
@@ -69,7 +68,7 @@ import {
69
68
  * deterministic runner that drives the durable coordinator over whatever adapter pair the test
70
69
  * provides. Every plan ends in the SAME claims the crash matrices make:
71
70
  *
72
- * 1. `verifyConversationInvariants` in convergence mode over every touched Conversation (the
71
+ * 1. `verifyThreadInvariants` in convergence mode over every touched Thread (the
73
72
  * shared WP1 checker — one set of claims for admin verify, certification, chaos, and soak);
74
73
  * 2. `scanObligations` returning ZERO entries (everything settled; nothing invisibly stuck);
75
74
  * 3. supplier non-fabrication wherever the deterministic desk was in play (durability §10: no
@@ -152,10 +151,10 @@ export class ChaosPlan extends Schema.Class<ChaosPlan>("@effect-agent/testing/Ch
152
151
  export class ChaosLaneReport extends Schema.Class<ChaosLaneReport>(
153
152
  "@effect-agent/testing/ChaosLaneReport",
154
153
  )({
155
- conversationId: ConversationId,
154
+ threadId: ThreadId,
156
155
  kind: ChaosScenarioKind,
157
156
  submissionCount: Schema.Int.check(Schema.isGreaterThanOrEqualTo(0)),
158
- /** Verdict of `verifyConversationInvariants` in convergence mode. */
157
+ /** Verdict of `verifyThreadInvariants` in convergence mode. */
159
158
  verified: Schema.Boolean,
160
159
  }) {}
161
160
 
@@ -217,13 +216,12 @@ const laneArbitrary: FastCheck.Arbitrary<GeneratedLane> = FastCheck.constantFrom
217
216
  "approval",
218
217
  "join",
219
218
  "delegation",
220
- ).chain(
221
- (kind): FastCheck.Arbitrary<GeneratedLane> =>
222
- kind === "join"
223
- ? FastCheck.integer({ min: 2, max: 3 }).map((depth): GeneratedLane => ({ kind, depth }))
224
- : kind === "plain"
225
- ? FastCheck.integer({ min: 1, max: 2 }).map((depth): GeneratedLane => ({ kind, depth }))
226
- : FastCheck.constant<GeneratedLane>({ kind, depth: 1 }),
219
+ ).chain((kind): FastCheck.Arbitrary<GeneratedLane> =>
220
+ kind === "join"
221
+ ? FastCheck.integer({ min: 2, max: 3 }).map((depth): GeneratedLane => ({ kind, depth }))
222
+ : kind === "plain"
223
+ ? FastCheck.integer({ min: 1, max: 2 }).map((depth): GeneratedLane => ({ kind, depth }))
224
+ : FastCheck.constant<GeneratedLane>({ kind, depth: 1 }),
227
225
  );
228
226
 
229
227
  interface ChaosPlanShape {
@@ -371,7 +369,7 @@ const policy = AgentPolicy.make({
371
369
  const PlainInput = Schema.Struct({ question: Schema.String });
372
370
  const PlainOutput = Schema.Struct({ answer: Schema.String });
373
371
 
374
- const plainDefinition = Agent.define("chaos-plain", {
372
+ const plainDefinition = Agent.make("chaos-plain", {
375
373
  input: PlainInput,
376
374
  output: PlainOutput,
377
375
  instructions: "Answer as JSON.",
@@ -385,7 +383,7 @@ const BookUncertain = Tool.make("book", {
385
383
  success: Schema.Struct({ confirmation: Schema.String }),
386
384
  });
387
385
  const bookTools = Toolkit.make(BookUncertain);
388
- const bookDefinition = Agent.define("chaos-book", {
386
+ const bookDefinition = Agent.make("chaos-book", {
389
387
  input: PlainInput,
390
388
  output: PlainOutput,
391
389
  instructions: "Book it.",
@@ -399,7 +397,7 @@ const BookApproval = Tool.make("book", {
399
397
  needsApproval: true,
400
398
  });
401
399
  const approvalTools = Toolkit.make(BookApproval);
402
- const approvalDefinition = Agent.define("chaos-approval", {
400
+ const approvalDefinition = Agent.make("chaos-approval", {
403
401
  input: PlainInput,
404
402
  output: PlainOutput,
405
403
  instructions: "Book after approval.",
@@ -414,7 +412,7 @@ const Itinerary = Tool.make("itinerary", {
414
412
  dependencies: [DurableStep],
415
413
  }).annotate(ToolExecutionClass, "uncertain");
416
414
  const itineraryTools = Toolkit.make(Itinerary);
417
- const itineraryDefinition = Agent.define("chaos-itinerary", {
415
+ const itineraryDefinition = Agent.make("chaos-itinerary", {
418
416
  input: PlainInput,
419
417
  output: PlainOutput,
420
418
  instructions: "Reserve the itinerary.",
@@ -422,7 +420,7 @@ const itineraryDefinition = Agent.define("chaos-itinerary", {
422
420
  policy,
423
421
  });
424
422
 
425
- const childDefinition = Agent.define("chaos-child", {
423
+ const childDefinition = Agent.make("chaos-child", {
426
424
  input: PlainInput,
427
425
  output: PlainOutput,
428
426
  instructions: "Answer as JSON.",
@@ -457,7 +455,7 @@ const chaosDelegation = Subagent.define("delegate_chaos", {
457
455
  }),
458
456
  });
459
457
 
460
- const coordinatorDefinition = Agent.define("chaos-coordinator", {
458
+ const coordinatorDefinition = Agent.make("chaos-coordinator", {
461
459
  input: Schema.Struct({ mission: Schema.String }),
462
460
  output: Schema.Struct({ report: Schema.String }),
463
461
  instructions: "Delegate, then report as JSON.",
@@ -487,7 +485,7 @@ const childLaneDigests = (lane: number): DefinitionDigests => {
487
485
  };
488
486
 
489
487
  const CHAOS_PRINCIPAL = Schema.decodeSync(Principal)("principal-chaos");
490
- const decodeConversationId = Schema.decodeSync(ConversationId);
488
+ const decodeThreadId = Schema.decodeSync(ThreadId);
491
489
  const decodeIdempotencyKey = Schema.decodeSync(IdempotencyKey);
492
490
  const decodeToolCallId = Schema.decodeSync(ToolCallId);
493
491
  const decodeRunId = Schema.decodeSync(RunId);
@@ -503,7 +501,7 @@ const chaosIdentifiers = Layer.effect(
503
501
  Effect.map((value) => decode(`${prefix}-${value}`)),
504
502
  );
505
503
  return {
506
- nextConversationId: next(decodeConversationId, "chaos-fixture-conversation"),
504
+ nextThreadId: next(decodeThreadId, "chaos-fixture-thread"),
507
505
  nextRunId: next(decodeRunId, "chaos-fixture-run"),
508
506
  nextTurnId: next(decodeTurnId, "chaos-fixture-turn"),
509
507
  };
@@ -573,7 +571,7 @@ const tolerateTyped = <A, E, R>(
573
571
  interface LaneFixture {
574
572
  readonly index: number;
575
573
  readonly kind: ChaosScenarioKind;
576
- readonly conversationId: ConversationId;
574
+ readonly threadId: ThreadId;
577
575
  readonly ref: string;
578
576
  readonly deskInPlay: boolean;
579
577
  readonly submissionIndexes: ReadonlyArray<number>;
@@ -583,7 +581,7 @@ interface LaneFixture {
583
581
  ) => ReadonlyArray<
584
582
  Effect.Effect<ReadonlyArray<Settlement>, DurableWorkerFailure | DurableBindingFailure>
585
583
  >;
586
- readonly childConversationOf: (firstReceipt: Receipt) => ConversationId | undefined;
584
+ readonly childThreadOf: (firstReceipt: Receipt) => ThreadId | undefined;
587
585
  }
588
586
 
589
587
  interface SubmissionState {
@@ -627,14 +625,14 @@ const makeLaneFixture = Effect.fn("Chaos.makeLaneFixture")(function* (
627
625
  desk: ChaosDesk,
628
626
  ) {
629
627
  const runtime = yield* DurableAgentRuntime;
630
- const conversationId = decodeConversationId(`chaos-${plan.seed}-lane-${laneIndex}`);
628
+ const threadId = decodeThreadId(`chaos-${plan.seed}-lane-${laneIndex}`);
631
629
  const ref = `ref-l${laneIndex}`;
632
630
  const script = scriptFor(kind, ref);
633
631
  const model = promptScriptedModel(`chaos-${kind}-${laneIndex}`, script);
634
632
  const digests = laneDigests(laneIndex);
635
633
 
636
634
  const submitOptionsFor = (flatIndex: number) => ({
637
- conversationId,
635
+ threadId,
638
636
  principal: CHAOS_PRINCIPAL,
639
637
  idempotencyKey: decodeIdempotencyKey(`chaos-${plan.seed}-s${flatIndex}`),
640
638
  definitions: digests,
@@ -655,33 +653,28 @@ const makeLaneFixture = Effect.fn("Chaos.makeLaneFixture")(function* (
655
653
  ): LaneFixture => ({
656
654
  index: laneIndex,
657
655
  kind,
658
- conversationId,
656
+ threadId,
659
657
  ref,
660
658
  deskInPlay,
661
659
  submissionIndexes,
662
660
  submitOne,
663
661
  drives: () => [drive],
664
- childConversationOf: () => undefined,
662
+ childThreadOf: () => undefined,
665
663
  });
666
664
 
667
665
  switch (kind) {
668
666
  case "plain":
669
667
  case "join": {
670
668
  const agent = Agent.withModel(plainDefinition, model);
671
- return plainLaneFixture(
672
- false,
673
- runtime.processConversation(agent, conversationId),
674
- (flatIndex) =>
675
- runtime.submit(agent, { question: `chaos ${flatIndex}` }, submitOptionsFor(flatIndex)),
669
+ return plainLaneFixture(false, runtime.processThread(agent, threadId), (flatIndex) =>
670
+ runtime.submit(agent, { question: `chaos ${flatIndex}` }, submitOptionsFor(flatIndex)),
676
671
  );
677
672
  }
678
673
  case "uncertain-tool": {
679
674
  const agent = Agent.withModel(bookDefinition, model);
680
675
  return plainLaneFixture(
681
676
  true,
682
- runtime
683
- .processConversation(agent, conversationId)
684
- .pipe(Effect.provide(bookToolLayerFor(bookTools))),
677
+ runtime.processThread(agent, threadId).pipe(Effect.provide(bookToolLayerFor(bookTools))),
685
678
  (flatIndex) =>
686
679
  runtime.submit(agent, { question: `chaos ${flatIndex}` }, submitOptionsFor(flatIndex)),
687
680
  );
@@ -691,7 +684,7 @@ const makeLaneFixture = Effect.fn("Chaos.makeLaneFixture")(function* (
691
684
  return plainLaneFixture(
692
685
  true,
693
686
  runtime
694
- .processConversation(agent, conversationId)
687
+ .processThread(agent, threadId)
695
688
  .pipe(Effect.provide(bookToolLayerFor(approvalTools))),
696
689
  (flatIndex) =>
697
690
  runtime.submit(agent, { question: `chaos ${flatIndex}` }, submitOptionsFor(flatIndex)),
@@ -718,7 +711,7 @@ const makeLaneFixture = Effect.fn("Chaos.makeLaneFixture")(function* (
718
711
  });
719
712
  return plainLaneFixture(
720
713
  true,
721
- runtime.processConversation(agent, conversationId).pipe(Effect.provide(toolLayer)),
714
+ runtime.processThread(agent, threadId).pipe(Effect.provide(toolLayer)),
722
715
  (flatIndex) =>
723
716
  runtime.submit(agent, { question: `chaos ${flatIndex}` }, submitOptionsFor(flatIndex)),
724
717
  );
@@ -741,15 +734,12 @@ const makeLaneFixture = Effect.fn("Chaos.makeLaneFixture")(function* (
741
734
  childBinding,
742
735
  childLaneDigests(laneIndex),
743
736
  );
744
- const resolver = AgentBindingResolver.fromBindings([parentResolved, childResolved]);
745
- const driveResolved = (conversation: ConversationId) =>
746
- runtime
747
- .processConversationResolved(conversation)
748
- .pipe(Effect.provideService(AgentBindingResolver, resolver));
737
+ const bindings = [parentResolved, childResolved];
738
+ const driveResolved = (thread: ThreadId) => runtime.processThreadResolved(thread, bindings);
749
739
  const fixture: LaneFixture = {
750
740
  index: laneIndex,
751
741
  kind,
752
- conversationId,
742
+ threadId,
753
743
  ref,
754
744
  deskInPlay: false,
755
745
  submissionIndexes,
@@ -762,21 +752,18 @@ const makeLaneFixture = Effect.fn("Chaos.makeLaneFixture")(function* (
762
752
  drives: (firstReceipt) => {
763
753
  const drives: Array<
764
754
  Effect.Effect<ReadonlyArray<Settlement>, DurableWorkerFailure | DurableBindingFailure>
765
- > = [driveResolved(conversationId)];
755
+ > = [driveResolved(threadId)];
766
756
  if (firstReceipt !== undefined) {
767
757
  drives.push(
768
758
  driveResolved(
769
- childConversationIdFor(
770
- firstReceipt.submissionId,
771
- decodeToolCallId(DELEGATE_CALL_ID),
772
- ),
759
+ childThreadIdFor(firstReceipt.submissionId, decodeToolCallId(DELEGATE_CALL_ID)),
773
760
  ),
774
761
  );
775
762
  }
776
763
  return drives;
777
764
  },
778
- childConversationOf: (firstReceipt) =>
779
- childConversationIdFor(firstReceipt.submissionId, decodeToolCallId(DELEGATE_CALL_ID)),
765
+ childThreadOf: (firstReceipt) =>
766
+ childThreadIdFor(firstReceipt.submissionId, decodeToolCallId(DELEGATE_CALL_ID)),
780
767
  };
781
768
  return fixture;
782
769
  }
@@ -902,7 +889,7 @@ const submissionIdsNamedBy = (
902
889
  payload._tag === "SubmissionSettled" ||
903
890
  payload._tag === "AbortRequested"
904
891
  ) {
905
- named.add(payload.submissionId);
892
+ if (payload.submissionId !== undefined) named.add(payload.submissionId);
906
893
  }
907
894
  }
908
895
  return named;
@@ -968,7 +955,7 @@ export const runChaosPlan = Effect.fn("Chaos.runChaosPlan")(function* (
968
955
  ) {
969
956
  const runtime = yield* DurableAgentRuntime;
970
957
  const ledger = yield* SubmissionLedger;
971
- const store = yield* ConversationStore;
958
+ const store = yield* ThreadStore;
972
959
  const config = yield* DurableRuntimeConfig;
973
960
  const failpoints = yield* DurableRuntimeFailpointTestControl;
974
961
  const random = mulberry32(plan.seed);
@@ -1036,7 +1023,7 @@ export const runChaosPlan = Effect.fn("Chaos.runChaosPlan")(function* (
1036
1023
  }
1037
1024
 
1038
1025
  // Admission chaos: pending submissions retry under the active arm until a Receipt lands;
1039
- // the identical (conversation, principal, key) triple reattaches, never duplicates.
1026
+ // the identical (thread, principal, key) triple reattaches, never duplicates.
1040
1027
  for (const state of states) {
1041
1028
  if (state.receipt !== undefined) continue;
1042
1029
  const receipt = yield* tolerateTyped(state.lane.submitOne(state.flatIndex));
@@ -1106,20 +1093,20 @@ export const runChaosPlan = Effect.fn("Chaos.runChaosPlan")(function* (
1106
1093
  });
1107
1094
  }
1108
1095
 
1109
- // Final claims: the shared invariant checker per touched Conversation, in convergence mode,
1096
+ // Final claims: the shared invariant checker per touched Thread, in convergence mode,
1110
1097
  // with the full digest chain (single known producer), plus the desk non-fabrication sweep.
1111
1098
  const produced = yield* desk.produced;
1112
1099
  const laneReports: Array<ChaosLaneReport> = [];
1113
- const verifyConversation = Effect.fn("Chaos.verifyConversation")(function* (
1114
- conversationId: ConversationId,
1100
+ const verifyThread = Effect.fn("Chaos.verifyThread")(function* (
1101
+ threadId: ThreadId,
1115
1102
  kind: ChaosScenarioKind,
1116
1103
  deskInPlay: boolean,
1117
1104
  ) {
1118
- const exported = yield* store.export(ConversationExportRequest.make({ conversationId })).pipe(
1105
+ const exported = yield* store.export(ThreadExportRequest.make({ threadId })).pipe(
1119
1106
  Effect.mapError((error) =>
1120
1107
  ChaosConvergenceFailure.make({
1121
1108
  seed: plan.seed,
1122
- message: `export of ${conversationId} failed: ${String(error)}`,
1109
+ message: `export of ${threadId} failed: ${String(error)}`,
1123
1110
  }),
1124
1111
  ),
1125
1112
  );
@@ -1138,7 +1125,7 @@ export const runChaosPlan = Effect.fn("Chaos.runChaosPlan")(function* (
1138
1125
  const batchProducers = new Map<BatchId, ProducerId>(
1139
1126
  exported.records.map((envelope) => [envelope.batchId, config.producerId]),
1140
1127
  );
1141
- const report = yield* verifyConversationInvariants({
1128
+ const report = yield* verifyThreadInvariants({
1142
1129
  export: exported,
1143
1130
  submissions: rows,
1144
1131
  batchProducers,
@@ -1151,7 +1138,7 @@ export const runChaosPlan = Effect.fn("Chaos.runChaosPlan")(function* (
1151
1138
  .join("; ");
1152
1139
  return yield* ChaosConvergenceFailure.make({
1153
1140
  seed: plan.seed,
1154
- message: `invariants failed for ${conversationId} (${kind}): ${failed}`,
1141
+ message: `invariants failed for ${threadId} (${kind}): ${failed}`,
1155
1142
  });
1156
1143
  }
1157
1144
  if (deskInPlay) {
@@ -1159,7 +1146,7 @@ export const runChaosPlan = Effect.fn("Chaos.runChaosPlan")(function* (
1159
1146
  }
1160
1147
  laneReports.push(
1161
1148
  ChaosLaneReport.make({
1162
- conversationId,
1149
+ threadId,
1163
1150
  kind,
1164
1151
  submissionCount: rows.length,
1165
1152
  verified: report.ok,
@@ -1168,18 +1155,18 @@ export const runChaosPlan = Effect.fn("Chaos.runChaosPlan")(function* (
1168
1155
  });
1169
1156
 
1170
1157
  for (const lane of lanes) {
1171
- yield* verifyConversation(lane.conversationId, lane.kind, lane.deskInPlay);
1172
- // Delegation lanes: verify every materialized child Conversation too.
1158
+ yield* verifyThread(lane.threadId, lane.kind, lane.deskInPlay);
1159
+ // Delegation lanes: verify every materialized child Thread too.
1173
1160
  for (const flatIndex of lane.submissionIndexes) {
1174
1161
  const receipt = states[flatIndex]?.receipt;
1175
1162
  if (receipt === undefined) continue;
1176
- const child = lane.childConversationOf(receipt);
1163
+ const child = lane.childThreadOf(receipt);
1177
1164
  if (child === undefined) continue;
1178
1165
  const childExport = yield* Effect.exit(
1179
- store.export(ConversationExportRequest.make({ conversationId: child })),
1166
+ store.export(ThreadExportRequest.make({ threadId: child })),
1180
1167
  );
1181
1168
  if (Exit.isSuccess(childExport) && childExport.value.records.length > 0) {
1182
- yield* verifyConversation(child, "plain", false);
1169
+ yield* verifyThread(child, "plain", false);
1183
1170
  }
1184
1171
  }
1185
1172
  }
@@ -0,0 +1,3 @@
1
+ /** CodeExecutor adapter conformance and the deterministic in-process substitute. */
2
+ export * from "./code-executor-conformance.ts";
3
+ export * from "./code-executor-substitute.ts";
@@ -0,0 +1,2 @@
1
+ /** Shared Docs Researcher definitions and MCP delegation fixtures. */
2
+ export * from "./fixtures/docs-researcher/index.ts";
@@ -73,11 +73,11 @@ export const docContentToolkitLayer = DocContentToolkit.toLayer({
73
73
  // ---------------------------------------------------------------------------
74
74
  // Deterministic corpus. Every body deliberately embeds BOTH a secret marker
75
75
  // and a distinctive body phrase: the tests assert that neither ever reaches
76
- // the parent Conversation, the parent prompts, or a redacted preview — only
76
+ // the parent Thread, the parent prompts, or a redacted preview — only
77
77
  // the bounded summary crosses the delegation boundary (SUB-015, SEC-008).
78
78
  // ---------------------------------------------------------------------------
79
79
 
80
- /** Never allowed outside a child Conversation or an unredacted fixture value. */
80
+ /** Never allowed outside a child Thread or an unredacted fixture value. */
81
81
  export const docsDocumentBodySecret = "docs-vault-secret-771";
82
82
 
83
83
  const decodeDocumentId = Schema.decodeSync(ResearchDocumentId);
@@ -109,7 +109,7 @@ const corpusEntries = new Map<string, CorpusEntry>(
109
109
  document: ResearchDocument.make({
110
110
  documentId: decodeDocumentId(entry.documentId),
111
111
  title: entry.title,
112
- body: `${entry.bodyPhrase}: internal working notes. ${docsDocumentBodySecret}. ${entry.summary} Raw notes stay inside the child Conversation.`,
112
+ body: `${entry.bodyPhrase}: internal working notes. ${docsDocumentBodySecret}. ${entry.summary} Raw notes stay inside the child Thread.`,
113
113
  }),
114
114
  bodyPhrase: entry.bodyPhrase,
115
115
  summary: entry.summary,
@@ -180,7 +180,7 @@ export const documentSummaryFor = (documentId: string): DocumentSummary =>
180
180
  export const encodedDocumentSummary = (documentId: string): string =>
181
181
  JSON.stringify(Schema.encodeSync(DocumentSummary)(documentSummaryFor(documentId)));
182
182
 
183
- export const DocSummarizer = Agent.define("doc-summarizer", {
183
+ export const DocSummarizer = Agent.make("doc-summarizer", {
184
184
  input: SummaryBrief,
185
185
  output: DocumentSummary,
186
186
  instructions:
@@ -200,7 +200,7 @@ export const DocSummarizer = Agent.define("doc-summarizer", {
200
200
  // Delegation Definition: the coordinator sees exactly one Tool with explicit
201
201
  // projections and finite bounds. `projectResult` is the declassification
202
202
  // boundary (SUB-015): only the bounded summary crosses; the fetched body —
203
- // secret marker included — stays in the child Conversation.
203
+ // secret marker included — stays in the child Thread.
204
204
  // ---------------------------------------------------------------------------
205
205
 
206
206
  export class SummaryRequest extends Schema.Class<SummaryRequest>("SummaryRequest")({
@@ -300,7 +300,7 @@ export const docsMissionConfidentialMarker = "docs-mission-dossier-42f";
300
300
 
301
301
  export const DocsResearcherToolkit = Toolkit.make(delegateDocumentSummary.tool);
302
302
 
303
- export const DocsResearcher = Agent.define("docs-researcher", {
303
+ export const DocsResearcher = Agent.make("docs-researcher", {
304
304
  input: ResearchRequest,
305
305
  output: ResearchDigest,
306
306
  instructions: [
@@ -322,7 +322,7 @@ export const DocsResearcher = Agent.define("docs-researcher", {
322
322
 
323
323
  /** The default two-document research mission. */
324
324
  export const researchMissionRequest = ResearchRequest.make({
325
- question: `Summarize the durability and subagent notes; keep ${docsMissionConfidentialMarker} inside the coordinator conversation.`,
325
+ question: `Summarize the durability and subagent notes; keep ${docsMissionConfidentialMarker} inside the coordinator thread.`,
326
326
  documentIds: researchCorpusDocumentIds,
327
327
  });
328
328
 
@@ -6,7 +6,7 @@ import {
6
6
  type RedactedPreview,
7
7
  type RedactionError,
8
8
  } from "@effect-agent/capabilities";
9
- import { Agent, type ConversationId } from "@effect-agent/core";
9
+ import { Agent, type ThreadId } from "@effect-agent/core";
10
10
  import {
11
11
  DefinitionDigests,
12
12
  DeploymentId,
@@ -17,7 +17,7 @@ import {
17
17
  type DurableSubmitOptions,
18
18
  type IdempotencyKey,
19
19
  type ResolvedBinding,
20
- } from "@effect-agent/session";
20
+ } from "@effect-agent/thread";
21
21
  import type { Crypto } from "effect";
22
22
  import { Effect, Layer, Ref, Schema, Stream } from "effect";
23
23
  import { LanguageModel, Model, type Response } from "effect/unstable/ai";
@@ -76,10 +76,10 @@ export const docsSummarizerDigests = DefinitionDigests.make({
76
76
 
77
77
  /** Durable admission options for one docs-researcher Submission on one mission lane. */
78
78
  export const docsResearcherSubmitOptions = (
79
- conversationId: ConversationId,
79
+ threadId: ThreadId,
80
80
  idempotencyKey: IdempotencyKey,
81
81
  ): DurableSubmitOptions => ({
82
- conversationId,
82
+ threadId,
83
83
  principal: docsResearcherPrincipal,
84
84
  idempotencyKey,
85
85
  definitions: docsCoordinatorDigests,
@@ -101,15 +101,13 @@ const scriptedUsage = { inputTokens: { total: 96 }, outputTokens: { total: 64 }
101
101
  const summaryDelegationParts = (
102
102
  documentIds: ReadonlyArray<string>,
103
103
  ): ReadonlyArray<Response.StreamPartEncoded> => [
104
- ...documentIds.map(
105
- (documentId): Response.StreamPartEncoded => ({
106
- type: "tool-call",
107
- id: summarizeCallId(documentId),
108
- name: "delegate_document_summary",
109
- params: { documentId },
110
- providerExecuted: false,
111
- }),
112
- ),
104
+ ...documentIds.map((documentId): Response.StreamPartEncoded => ({
105
+ type: "tool-call",
106
+ id: summarizeCallId(documentId),
107
+ name: "delegate_document_summary",
108
+ params: { documentId },
109
+ providerExecuted: false,
110
+ })),
113
111
  { type: "finish", reason: "tool-calls", usage: scriptedUsage },
114
112
  ];
115
113
 
@@ -298,7 +296,7 @@ const encodeResearchDocument = Schema.encodeEffect(ResearchDocument);
298
296
  /**
299
297
  * The audit-surface preview of one fetched document: the raw document —
300
298
  * secret marker and all — passes through the configured structural `Redactor`
301
- * before anything may quote it outside the child Conversation (SEC-008,
299
+ * before anything may quote it outside the child Thread (SEC-008,
302
300
  * CAP-013). Tests assert the preview keeps shape but no scalar content.
303
301
  */
304
302
  export const redactedDocumentPreview = Effect.fn("DocsResearcher.redactedDocumentPreview")(
@@ -7,7 +7,7 @@
7
7
  //
8
8
  // 1. MCP discovery and Agent authoring do not meet in the type system. The
9
9
  // connector's validated Toolkit arrives as `Toolkit.Any`, while
10
- // `Agent.define` needs the statically typed toolkit — so the binding
10
+ // `Agent.make` needs the statically typed toolkit — so the binding
11
11
  // between "what discovery served" and "what the child was authored
12
12
  // against" had to be re-proved by hand (`assertDiscoveryMatchesAuthoredToolkit`
13
13
  // re-deriving `Tool.getJsonSchema` on both sides). A framework helper that
@@ -150,7 +150,7 @@ export const TravelPlannerToolkitLayer = TravelPlannerToolkit.toLayer({
150
150
  search_activities: (query) => Effect.flatMap(ActivityCatalog, (catalog) => catalog.search(query)),
151
151
  });
152
152
 
153
- export const TravelPlanner = Agent.define("travel-planner", {
153
+ export const TravelPlanner = Agent.make("travel-planner", {
154
154
  input: TripRequest,
155
155
  output: TravelPlan,
156
156
  instructions: (input) =>
@@ -1,4 +1,5 @@
1
- import { ConversationId, IdGenerator, RunId, TurnId } from "@effect-agent/core";
1
+ import { ThreadId, IdGenerator, RunId, TurnId } from "@effect-agent/core";
2
+ import { ThreadHistory, RunContextPreparationPassthrough } from "@effect-agent/engine";
2
3
  import { Context, Deferred, Effect, Layer, Option, Ref, Schema } from "effect";
3
4
 
4
5
  import {
@@ -405,12 +406,12 @@ export const TravelGuidanceLayer = Layer.succeed(
405
406
  export const DeterministicIdGeneratorLayer = Layer.effect(
406
407
  IdGenerator,
407
408
  Effect.gen(function* () {
408
- const conversation = yield* Ref.make(0);
409
+ const thread = yield* Ref.make(0);
409
410
  const run = yield* Ref.make(0);
410
411
  const turn = yield* Ref.make(0);
411
412
  return IdGenerator.of({
412
- nextConversationId: Ref.updateAndGet(conversation, (n) => n + 1).pipe(
413
- Effect.map((n) => Schema.decodeSync(ConversationId)(`conversation-${n}`)),
413
+ nextThreadId: Ref.updateAndGet(thread, (n) => n + 1).pipe(
414
+ Effect.map((n) => Schema.decodeSync(ThreadId)(`thread-${n}`)),
414
415
  ),
415
416
  nextRunId: Ref.updateAndGet(run, (n) => n + 1).pipe(
416
417
  Effect.map((n) => Schema.decodeSync(RunId)(`run-${n}`)),
@@ -422,6 +423,8 @@ export const DeterministicIdGeneratorLayer = Layer.effect(
422
423
  }),
423
424
  );
424
425
  export const TravelPlannerRuntimeLayer = Layer.mergeAll(
426
+ RunContextPreparationPassthrough,
427
+ ThreadHistory.layerTransient,
425
428
  TravelPlannerToolkitLayer,
426
429
  FlightCatalogLayer,
427
430
  LodgingCatalogLayer,
@@ -75,7 +75,7 @@ export const TravelPlannerPhase2ToolkitLayer = TravelPlannerPhase2Toolkit.toLaye
75
75
  Effect.flatMap(ItineraryHoldGateway, (gateway) => gateway.hold(request)),
76
76
  });
77
77
 
78
- export const TravelPlannerPhase2 = Agent.define("travel-planner-phase-2", {
78
+ export const TravelPlannerPhase2 = Agent.make("travel-planner-phase-2", {
79
79
  input: TripRequest,
80
80
  output: TravelPlan,
81
81
  instructions: (input) =>