@yielded/agent-testing 0.1.0-beta.173 → 0.1.0-beta.174

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.
@@ -129,6 +129,7 @@ const requireDestinationFacts = (destination: string): DestinationFacts => {
129
129
  const facts = guideFacts.get(destination);
130
130
 
131
131
  if (facts === undefined) {
132
+ // oxlint-disable-next-line effect/no-untyped-throw, effect/no-native-error -- Synchronous deterministic fixture lookup rejects programmer-supplied destination configuration.
132
133
  throw new Error(`No deterministic guide entry exists for destination ${destination}`);
133
134
  }
134
135
 
@@ -229,17 +230,16 @@ export const destinationResearchDelegation = Subagent.make("delegate_destination
229
230
  parameters: DestinationResearchRequest,
230
231
  success: DestinationResearchFindings,
231
232
  failure: DestinationResearchFailed,
232
- prepareInput: (request) =>
233
- Effect.gen(function* () {
234
- const gate = yield* ResearchDispatchGate;
233
+ prepareInput: Effect.fnUntraced(function* (request) {
234
+ const gate = yield* ResearchDispatchGate;
235
235
 
236
- yield* gate.awaitDispatch(request.destination);
236
+ yield* gate.awaitDispatch(request.destination);
237
237
 
238
- return DestinationBrief.make({
239
- destination: request.destination,
240
- focus: `research:${request.focus}`,
241
- });
242
- }),
238
+ return DestinationBrief.make({
239
+ destination: request.destination,
240
+ focus: `research:${request.focus}`,
241
+ });
242
+ }),
243
243
  // The explicit declassification boundary (SUB-015): only the advisory
244
244
  // crosses to the parent; guide highlights stay in the child Thread.
245
245
  projectResult: (report) =>
@@ -466,82 +466,85 @@ const researcherReportParts = (destination: string): ReadonlyArray<Response.Stre
466
466
  * finalization is observed per child — the same acquire/release counting the
467
467
  * catalog Layers use to prove interruption reaches every finalizer.
468
468
  */
469
- export const makeDestinationResearcherModel = (destinations: ReadonlyArray<string>) =>
470
- Effect.gen(function* () {
471
- const lifecycle = yield* CatalogLifecycle;
472
- const prompts = yield* Ref.make<ReadonlyArray<string>>([]);
473
- const gates = new Map<string, ResearcherGates>();
474
-
475
- for (const destination of destinations) {
476
- gates.set(destination, {
477
- started: yield* Deferred.make<void>(),
478
- release: yield* Deferred.make<void>(),
479
- });
480
- }
481
-
482
- const gatesFor = (destination: string): Effect.Effect<ResearcherGates> =>
483
- Effect.suspend(() => {
484
- const entry = gates.get(destination);
485
-
486
- return entry === undefined
487
- ? Effect.die(new Error(`No researcher gates exist for destination ${destination}`))
488
- : Effect.succeed(entry);
489
- });
490
-
491
- const controls: DestinationResearcherControls = {
492
- awaitStarted: (destination) =>
493
- gatesFor(destination).pipe(Effect.flatMap((entry) => Deferred.await(entry.started))),
494
- release: (destination) =>
495
- gatesFor(destination).pipe(
496
- Effect.flatMap((entry) => Deferred.succeed(entry.release, undefined)),
497
- Effect.asVoid,
498
- ),
499
- prompts: Ref.get(prompts),
500
- };
501
-
502
- const model = Model.make(
503
- "scripted",
504
- "destination-researcher-scripted",
505
- Layer.effect(
506
- LanguageModel.LanguageModel,
507
- Effect.gen(function* () {
508
- yield* Effect.acquireRelease(lifecycle.markAcquired, () => lifecycle.markFinalized);
509
- const turn = yield* Ref.make(0);
510
-
511
- return yield* LanguageModel.make({
512
- generateText: () => Effect.succeed([]),
513
- streamText: (options) =>
514
- Stream.unwrap(
515
- Effect.gen(function* () {
516
- const promptJson = JSON.stringify(options.prompt.content);
517
-
518
- const destination = destinations.find((candidate) =>
519
- promptJson.includes(candidate),
520
- );
469
+ export const makeDestinationResearcherModel = Effect.fnUntraced(function* (
470
+ destinations: ReadonlyArray<string>,
471
+ ) {
472
+ const lifecycle = yield* CatalogLifecycle;
473
+ const prompts = yield* Ref.make<ReadonlyArray<string>>([]);
474
+ const gates = new Map<string, ResearcherGates>();
475
+
476
+ for (const destination of destinations) {
477
+ gates.set(destination, {
478
+ started: yield* Deferred.make<void>(),
479
+ release: yield* Deferred.make<void>(),
480
+ });
481
+ }
521
482
 
522
- if (destination === undefined) {
523
- return yield* Effect.die(
524
- new Error("The researcher prompt names no scripted destination"),
525
- );
526
- }
527
- const entry = yield* gatesFor(destination);
528
- const index = yield* Ref.getAndUpdate(turn, (value) => value + 1);
529
-
530
- if (index === 0) {
531
- yield* Ref.update(prompts, (previous) => [...previous, promptJson]);
532
- yield* Deferred.succeed(entry.started, undefined);
533
-
534
- return Stream.fromIterable(researcherLookupParts(destination));
535
- }
536
- yield* Deferred.await(entry.release);
537
-
538
- return Stream.fromIterable(researcherReportParts(destination));
539
- }),
540
- ),
541
- });
542
- }),
483
+ const gatesFor = (destination: string): Effect.Effect<ResearcherGates> =>
484
+ Effect.suspend(() => {
485
+ const entry = gates.get(destination);
486
+
487
+ return entry === undefined
488
+ ? // oxlint-disable-next-line effect/no-native-error -- Missing fixture gate is a native test assertion defect.
489
+ Effect.die(new Error(`No researcher gates exist for destination ${destination}`))
490
+ : Effect.succeed(entry);
491
+ });
492
+
493
+ const controls: DestinationResearcherControls = {
494
+ awaitStarted: (destination) =>
495
+ gatesFor(destination).pipe(Effect.flatMap((entry) => Deferred.await(entry.started))),
496
+ release: (destination) =>
497
+ gatesFor(destination).pipe(
498
+ Effect.flatMap((entry) => Deferred.succeed(entry.release, undefined)),
499
+ Effect.asVoid,
543
500
  ),
544
- );
501
+ prompts: Ref.get(prompts),
502
+ };
503
+
504
+ const model = Model.make(
505
+ "scripted",
506
+ "destination-researcher-scripted",
507
+ Layer.effect(
508
+ LanguageModel.LanguageModel,
509
+ Effect.gen(function* () {
510
+ yield* Effect.acquireRelease(lifecycle.markAcquired, () => lifecycle.markFinalized);
511
+ const turn = yield* Ref.make(0);
512
+
513
+ return yield* LanguageModel.make({
514
+ generateText: () => Effect.succeed([]),
515
+ streamText: (options) =>
516
+ Stream.unwrap(
517
+ Effect.gen(function* () {
518
+ const promptJson = JSON.stringify(options.prompt.content);
519
+
520
+ const destination = destinations.find((candidate) =>
521
+ promptJson.includes(candidate),
522
+ );
523
+
524
+ if (destination === undefined) {
525
+ return yield* Effect.die(
526
+ // oxlint-disable-next-line effect/no-native-error -- Deterministic model fixture assertion remains a native defect.
527
+ new Error("The researcher prompt names no scripted destination"),
528
+ );
529
+ }
530
+ const entry = yield* gatesFor(destination);
531
+ const index = yield* Ref.getAndUpdate(turn, (value) => value + 1);
532
+
533
+ if (index === 0) {
534
+ yield* Ref.update(prompts, (previous) => [...previous, promptJson]);
535
+ yield* Deferred.succeed(entry.started, undefined);
536
+
537
+ return Stream.fromIterable(researcherLookupParts(destination));
538
+ }
539
+ yield* Deferred.await(entry.release);
540
+
541
+ return Stream.fromIterable(researcherReportParts(destination));
542
+ }),
543
+ ),
544
+ });
545
+ }),
546
+ ),
547
+ );
545
548
 
546
- return { controls, model };
547
- });
549
+ return { controls, model };
550
+ });