@effect-agent/testing 0.1.0-beta.42 → 0.1.0-beta.45
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.
- package/dist/certification.mjs +8 -8
- package/dist/certification.mjs.map +1 -1
- package/dist/chaos.d.mts +1 -1
- package/dist/chaos.mjs +5 -3
- package/dist/chaos.mjs.map +1 -1
- package/dist/code-executor.mjs.map +1 -1
- package/dist/deterministic-layers-CKyYxBhN.mjs.map +1 -1
- package/dist/docs-researcher.d.mts +1 -1
- package/dist/docs-researcher.mjs +3 -2
- package/dist/docs-researcher.mjs.map +1 -1
- package/dist/scripted-model-C2y0ztuj.mjs.map +1 -1
- package/dist/travel-planner.d.mts +2 -2
- package/dist/travel-planner.mjs +1 -1
- package/dist/travel-planner.mjs.map +1 -1
- package/package.json +1 -71
- package/src/certification.ts +110 -23
- package/src/chaos.ts +111 -3
- package/src/code-executor-conformance.ts +19 -0
- package/src/code-executor-substitute.ts +32 -0
- package/src/fixtures/docs-researcher/definition.ts +7 -0
- package/src/fixtures/docs-researcher/harness.ts +20 -1
- package/src/fixtures/docs-researcher/mcp.ts +14 -2
- package/src/fixtures/travel-planner/definition.ts +12 -0
- package/src/fixtures/travel-planner/deterministic-layers.ts +38 -0
- package/src/fixtures/travel-planner/phase3.ts +4 -0
- package/src/fixtures/travel-planner/phase4.ts +10 -0
- package/src/fixtures/travel-planner/phase5.ts +20 -0
- package/src/fixtures/travel-planner/phase6.ts +12 -0
- package/src/fixtures/travel-planner/scenarios.ts +2 -0
- package/src/fixtures/travel-planner/subagents-durable.ts +15 -2
- package/src/fixtures/travel-planner/subagents.ts +21 -0
- package/src/scripted-model.ts +18 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deterministic-layers-CKyYxBhN.mjs","names":[],"sources":["../src/fixtures/travel-planner/definition.ts","../src/fixtures/travel-planner/deterministic-layers.ts"],"sourcesContent":["import { Agent, AgentPolicy } from \"@effect-agent/core\";\nimport { Context, Effect, Schema } from \"effect\";\nimport { Tool, Toolkit } from \"effect/unstable/ai\";\n\nexport const AirportCode = Schema.NonEmptyString.pipe(\n Schema.brand(\"@effect-agent/testing/travel-planner/AirportCode\"),\n);\nexport type AirportCode = typeof AirportCode.Type;\n\nexport const QuoteId = Schema.NonEmptyString.pipe(\n Schema.brand(\"@effect-agent/testing/travel-planner/QuoteId\"),\n);\nexport type QuoteId = typeof QuoteId.Type;\n\nexport class TripRequest extends Schema.Class<TripRequest>(\"TripRequest\")({\n request: Schema.NonEmptyString,\n origin: AirportCode,\n destination: AirportCode,\n departOn: Schema.String,\n nights: Schema.Int.check(Schema.isGreaterThan(0)),\n travelers: Schema.Int.check(Schema.isGreaterThan(0)),\n budgetCents: Schema.Int.check(Schema.isGreaterThan(0)),\n currency: Schema.Literal(\"USD\"),\n}) {}\n\nexport class FlightQuery extends Schema.Class<FlightQuery>(\"FlightQuery\")({\n origin: AirportCode,\n destination: AirportCode,\n departOn: Schema.String,\n travelers: Schema.Int.check(Schema.isGreaterThan(0)),\n}) {}\n\nexport class LodgingQuery extends Schema.Class<LodgingQuery>(\"LodgingQuery\")({\n destination: AirportCode,\n departOn: Schema.String,\n nights: Schema.Int.check(Schema.isGreaterThan(0)),\n travelers: Schema.Int.check(Schema.isGreaterThan(0)),\n}) {}\n\nexport class ActivityQuery extends Schema.Class<ActivityQuery>(\"ActivityQuery\")({\n destination: AirportCode,\n departOn: Schema.String,\n nights: Schema.Int.check(Schema.isGreaterThan(0)),\n travelers: Schema.Int.check(Schema.isGreaterThan(0)),\n}) {}\n\nexport class FlightOption extends Schema.Class<FlightOption>(\"FlightOption\")({\n quoteId: QuoteId,\n flight: Schema.String,\n estimatedCents: Schema.Int.check(Schema.isGreaterThan(0)),\n currency: Schema.Literal(\"USD\"),\n}) {}\n\nexport class LodgingOption extends Schema.Class<LodgingOption>(\"LodgingOption\")({\n lodging: Schema.String,\n estimatedCents: Schema.Int.check(Schema.isGreaterThan(0)),\n currency: Schema.Literal(\"USD\"),\n}) {}\n\n/** A successful empty activity search is distinct from supplier unavailability. */\nexport class ActivitySearchResult extends Schema.Class<ActivitySearchResult>(\n \"ActivitySearchResult\",\n)({\n activities: Schema.Array(Schema.String),\n}) {}\n\nexport class Itinerary extends Schema.Class<Itinerary>(\"Itinerary\")({\n title: Schema.String,\n route: Schema.String,\n dates: Schema.String,\n flight: Schema.String,\n lodging: Schema.String,\n activities: Schema.Array(Schema.String),\n estimatedTotalCents: Schema.Int.check(Schema.isGreaterThan(0)),\n currency: Schema.Literal(\"USD\"),\n quoteId: QuoteId,\n assumptions: Schema.Array(Schema.String),\n unresolvedConstraints: Schema.Array(Schema.String),\n nextAction: Schema.Literal(\"review\"),\n}) {}\n\nexport class TravelPlan extends Schema.Class<TravelPlan>(\"TravelPlan\")({\n itineraries: Schema.Array(Itinerary),\n}) {}\n\nconst unavailableFields = { query: Schema.String, message: Schema.String };\nexport class FlightUnavailable extends Schema.TaggedError<FlightUnavailable>()(\n \"FlightUnavailable\",\n unavailableFields,\n) {}\nexport class LodgingUnavailable extends Schema.TaggedError<LodgingUnavailable>()(\n \"LodgingUnavailable\",\n unavailableFields,\n) {}\nexport class ActivityUnavailable extends Schema.TaggedError<ActivityUnavailable>()(\n \"ActivityUnavailable\",\n unavailableFields,\n) {}\nexport class GuidanceFailure extends Schema.TaggedError<GuidanceFailure>()(\"GuidanceFailure\", {\n message: Schema.String,\n}) {}\n\nexport class FlightCatalog extends Context.Service<\n FlightCatalog,\n { readonly search: (query: FlightQuery) => Effect.Effect<FlightOption, FlightUnavailable> }\n>()(\"@effect-agent/testing/travel-planner/FlightCatalog\") {}\nexport class LodgingCatalog extends Context.Service<\n LodgingCatalog,\n { readonly search: (query: LodgingQuery) => Effect.Effect<LodgingOption, LodgingUnavailable> }\n>()(\"@effect-agent/testing/travel-planner/LodgingCatalog\") {}\nexport class ActivityCatalog extends Context.Service<\n ActivityCatalog,\n {\n readonly search: (\n query: ActivityQuery,\n ) => Effect.Effect<ActivitySearchResult, ActivityUnavailable>;\n }\n>()(\"@effect-agent/testing/travel-planner/ActivityCatalog\") {}\nexport class TravelGuidance extends Context.Service<\n TravelGuidance,\n { readonly instructions: (input: TripRequest) => Effect.Effect<string, GuidanceFailure> }\n>()(\"@effect-agent/testing/travel-planner/TravelGuidance\") {}\n\nexport const SearchFlights = Tool.make(\"search_flights\", {\n parameters: FlightQuery,\n success: FlightOption,\n failure: FlightUnavailable,\n failureMode: \"error\",\n dependencies: [FlightCatalog],\n});\nexport const SearchLodging = Tool.make(\"search_lodging\", {\n parameters: LodgingQuery,\n success: LodgingOption,\n failure: LodgingUnavailable,\n failureMode: \"error\",\n dependencies: [LodgingCatalog],\n});\nexport const SearchActivities = Tool.make(\"search_activities\", {\n parameters: ActivityQuery,\n success: ActivitySearchResult,\n failure: ActivityUnavailable,\n failureMode: \"error\",\n dependencies: [ActivityCatalog],\n});\n\nexport const TravelPlannerToolkit = Toolkit.make(SearchFlights, SearchLodging, SearchActivities);\nexport const TravelPlannerToolkitLayer = TravelPlannerToolkit.toLayer({\n search_flights: (query) => Effect.flatMap(FlightCatalog, (catalog) => catalog.search(query)),\n search_lodging: (query) => Effect.flatMap(LodgingCatalog, (catalog) => catalog.search(query)),\n search_activities: (query) => Effect.flatMap(ActivityCatalog, (catalog) => catalog.search(query)),\n});\n\nexport const TravelPlanner = Agent.make(\"travel-planner\", {\n input: TripRequest,\n output: TravelPlan,\n instructions: (input) =>\n Effect.flatMap(TravelGuidance, (guidance) => guidance.instructions(input)),\n toolkit: TravelPlannerToolkit,\n policy: AgentPolicy.make({\n maxTurns: 2,\n maxToolCalls: 3,\n maxDuration: \"30 seconds\",\n toolConcurrency: 3,\n }),\n description: \"Build one review-only itinerary from bounded parallel deterministic searches.\",\n metadata: { deploymentClass: \"E\", phase: \"P1\" },\n});\n","import { ThreadId, IdGenerator, RunId, TurnId } from \"@effect-agent/core\";\nimport { ThreadHistory, RunContextPreparationPassthrough } from \"@effect-agent/engine\";\nimport { Context, Deferred, Effect, Layer, Option, Ref, Schema } from \"effect\";\n\nimport {\n ActivityCatalog,\n ActivitySearchResult,\n ActivityUnavailable,\n FlightCatalog,\n FlightOption,\n FlightUnavailable,\n LodgingCatalog,\n LodgingOption,\n LodgingUnavailable,\n QuoteId,\n TravelGuidance,\n TravelPlannerToolkit,\n TravelPlannerToolkitLayer,\n} from \"./definition.ts\";\n\nexport class CatalogLifecycleCounts extends Schema.Class<CatalogLifecycleCounts>(\n \"CatalogLifecycleCounts\",\n)({\n acquired: Schema.Natural,\n finalized: Schema.Natural,\n}) {}\nexport class CatalogLifecycle extends Context.Service<\n CatalogLifecycle,\n {\n readonly markAcquired: Effect.Effect<void>;\n readonly markFinalized: Effect.Effect<void>;\n readonly counts: Effect.Effect<CatalogLifecycleCounts>;\n }\n>()(\"@effect-agent/testing/travel-planner/CatalogLifecycle\") {\n static readonly layerNoDeps = Layer.effect(\n this,\n Effect.gen(function* () {\n const acquired = yield* Ref.make(0);\n const finalized = yield* Ref.make(0);\n return CatalogLifecycle.of({\n markAcquired: Ref.update(acquired, (n) => n + 1),\n markFinalized: Ref.update(finalized, (n) => n + 1),\n counts: Effect.all({ acquired: Ref.get(acquired), finalized: Ref.get(finalized) }).pipe(\n Effect.map((counts) => CatalogLifecycleCounts.make(counts)),\n ),\n });\n }),\n );\n}\n\nconst flight = FlightOption.make({\n quoteId: Schema.decodeSync(QuoteId)(\"quote-sfo-lhr-001\"),\n flight: \"EA 218 · nonstop · SFO 18:40 → LHR 13:05+1\",\n estimatedCents: 180_000,\n currency: \"USD\",\n});\nconst lodging = LodgingOption.make({\n lodging: \"Bloomsbury House · refundable studio · 4 nights\",\n estimatedCents: 104_000,\n currency: \"USD\",\n});\nconst activities = ActivitySearchResult.make({\n activities: [\"British Museum timed entry\", \"Thames evening walk\"],\n});\n\n/**\n * Deterministic controls for a Tool batch whose completions are released in a\n * caller-selected order. This is intentionally a test fixture: it uses no\n * clock or sleep and lets engine scheduler tests prove parallel starts and\n * declaration-order prompt materialization.\n */\nexport interface TravelPlannerCompletionControls {\n readonly flightStarted: Effect.Effect<void>;\n readonly lodgingStarted: Effect.Effect<void>;\n readonly activityStarted: Effect.Effect<void>;\n readonly releaseFlight: Effect.Effect<void>;\n readonly releaseLodging: Effect.Effect<void>;\n readonly releaseActivity: Effect.Effect<void>;\n}\n\nexport const ReverseCompletionToolkitLayer = Effect.gen(function* () {\n const flightStarted = yield* Deferred.make<void>();\n const lodgingStarted = yield* Deferred.make<void>();\n const activityStarted = yield* Deferred.make<void>();\n const releaseFlight = yield* Deferred.make<void>();\n const releaseLodging = yield* Deferred.make<void>();\n const releaseActivity = yield* Deferred.make<void>();\n const awaitRelease = <A>(\n started: Deferred.Deferred<void>,\n release: Deferred.Deferred<void>,\n value: A,\n ) =>\n Deferred.succeed(started, undefined).pipe(\n Effect.andThen(Deferred.await(release)),\n Effect.as(value),\n );\n return {\n controls: {\n flightStarted: Deferred.await(flightStarted),\n lodgingStarted: Deferred.await(lodgingStarted),\n activityStarted: Deferred.await(activityStarted),\n releaseFlight: Deferred.succeed(releaseFlight, undefined).pipe(Effect.asVoid),\n releaseLodging: Deferred.succeed(releaseLodging, undefined).pipe(Effect.asVoid),\n releaseActivity: Deferred.succeed(releaseActivity, undefined).pipe(Effect.asVoid),\n },\n layer: TravelPlannerToolkit.toLayer({\n search_flights: () => awaitRelease(flightStarted, releaseFlight, flight),\n search_lodging: () => awaitRelease(lodgingStarted, releaseLodging, lodging),\n search_activities: () => awaitRelease(activityStarted, releaseActivity, activities),\n }),\n };\n});\n\nexport const FlightCatalogLayer = Layer.effect(\n FlightCatalog,\n Effect.gen(function* () {\n const lifecycle = yield* CatalogLifecycle;\n yield* Effect.acquireRelease(lifecycle.markAcquired, () => lifecycle.markFinalized);\n return FlightCatalog.of({\n search: (query) =>\n query.origin === query.destination\n ? Effect.fail(\n FlightUnavailable.make({\n query: `${query.origin}-${query.destination}`,\n message: \"Origin and destination must differ.\",\n }),\n )\n : Effect.succeed(flight),\n });\n }),\n);\nexport const LodgingCatalogLayer = Layer.effect(\n LodgingCatalog,\n Effect.gen(function* () {\n const lifecycle = yield* CatalogLifecycle;\n yield* Effect.acquireRelease(lifecycle.markAcquired, () => lifecycle.markFinalized);\n return LodgingCatalog.of({\n search: (query) =>\n query.nights < 1\n ? Effect.fail(\n LodgingUnavailable.make({\n query: query.destination,\n message: \"At least one night is required.\",\n }),\n )\n : Effect.succeed(lodging),\n });\n }),\n);\nexport const ActivityCatalogLayer = Layer.effect(\n ActivityCatalog,\n Effect.gen(function* () {\n const lifecycle = yield* CatalogLifecycle;\n yield* Effect.acquireRelease(lifecycle.markAcquired, () => lifecycle.markFinalized);\n return ActivityCatalog.of({\n search: (query) =>\n query.destination === \"\"\n ? Effect.fail(\n ActivityUnavailable.make({\n query: query.destination,\n message: \"Destination is required.\",\n }),\n )\n : Effect.succeed(activities),\n });\n }),\n);\n/** Stable supplier-side booking identity, minted deterministically from the idempotency key. */\nexport const BookingRef = Schema.NonEmptyString.pipe(\n Schema.brand(\"@effect-agent/testing/travel-planner/BookingRef\"),\n);\nexport type BookingRef = typeof BookingRef.Type;\n\n/** The supplier desk operations the P5 booking Tools and Steps invoke. */\nexport const SupplierOperation = Schema.Literals([\n \"book-flight\",\n \"cancel-booking\",\n \"reserve-flight\",\n \"reserve-lodging\",\n \"issue-confirmation\",\n]);\nexport type SupplierOperation = typeof SupplierOperation.Type;\n\n/**\n * One row of external supplier truth. The desk deduplicates by `idempotencyKey` — replaying a\n * call with the same key returns this exact record without creating a second booking — which is\n * precisely the honesty model of DUR-010: the framework never makes an external call\n * exactly-once; the supplier's idempotency key does.\n */\nexport class SupplierBookingRecord extends Schema.Class<SupplierBookingRecord>(\n \"@effect-agent/testing/travel-planner/SupplierBookingRecord\",\n)({\n bookingRef: BookingRef,\n idempotencyKey: Schema.NonEmptyString,\n operation: SupplierOperation,\n detail: Schema.NonEmptyString,\n status: Schema.Literals([\"confirmed\", \"cancelled\"]),\n}) {}\n\nexport class SupplierUnavailable extends Schema.TaggedError<SupplierUnavailable>()(\n \"SupplierUnavailable\",\n { message: Schema.String },\n) {}\n\nexport interface SupplierBookRequest {\n readonly operation: SupplierOperation;\n readonly idempotencyKey: string;\n readonly detail: string;\n}\n\n/** Controls returned by an armed crash window (`holdAfterWrite`). */\nexport interface SupplierHoldControls {\n /** Resolves once the armed call has performed its supplier write and is blocked. */\n readonly held: Effect.Effect<void>;\n /** Releases the blocked call (tests that interrupt the Attempt never call this). */\n readonly release: Effect.Effect<void>;\n}\n\n/** The desk-internal idempotency key of one cancellation: cancel is idempotent by bookingRef. */\nexport const cancelBookingIdempotencyKey = (bookingRef: string): string =>\n `cancel-booking:${bookingRef}`;\n\n/** The deterministic bookingRef the desk mints for one idempotency key. */\nexport const supplierBookingRefFor = (idempotencyKey: string): BookingRef =>\n Schema.decodeSync(BookingRef)(`ref:${idempotencyKey}`);\n\ninterface SupplierHoldWindow {\n readonly held: Deferred.Deferred<void>;\n readonly release: Deferred.Deferred<void>;\n}\n\ninterface SupplierDeskState {\n readonly bookings: ReadonlyMap<string, SupplierBookingRecord>;\n readonly counts: ReadonlyMap<string, number>;\n readonly holds: ReadonlyMap<string, SupplierHoldWindow>;\n}\n\n/**\n * The deterministic in-memory supplier: an idempotency-keyed booking store with per-key call\n * counters and injectable crash windows.\n *\n * - `book`/`cancel` always count the call (at-least-once execution stays observable), then\n * dedupe the external effect by idempotency key — the supplier-side contract the P5 Tools and\n * Steps rely on.\n * - `holdAfterWrite` arms a one-shot crash window: the next call with that key performs its\n * supplier write, signals `held`, and never returns. Interrupting the Attempt at that point\n * models \"the external effect happened but no outcome was recorded\" without any wall clock.\n * - `bookings`/`lookup` expose external truth for the reconciler and for never-fabricate\n * assertions.\n */\nexport class SupplierBookingDesk extends Context.Service<\n SupplierBookingDesk,\n {\n readonly book: (\n request: SupplierBookRequest,\n ) => Effect.Effect<SupplierBookingRecord, SupplierUnavailable>;\n readonly cancel: (\n bookingRef: BookingRef,\n ) => Effect.Effect<SupplierBookingRecord, SupplierUnavailable>;\n readonly lookup: (\n idempotencyKey: string,\n ) => Effect.Effect<Option.Option<SupplierBookingRecord>>;\n readonly bookings: Effect.Effect<ReadonlyArray<SupplierBookingRecord>>;\n readonly callCount: (idempotencyKey: string) => Effect.Effect<number>;\n readonly holdAfterWrite: (idempotencyKey: string) => Effect.Effect<SupplierHoldControls>;\n }\n>()(\"@effect-agent/testing/travel-planner/SupplierBookingDesk\") {\n static readonly layer: Layer.Layer<SupplierBookingDesk> = Layer.effect(\n this,\n Effect.gen(function* () {\n const state = yield* Ref.make<SupplierDeskState>({\n bookings: new Map(),\n counts: new Map(),\n holds: new Map(),\n });\n\n const enterHold = (hold: Option.Option<SupplierHoldWindow>) =>\n Option.isSome(hold)\n ? Deferred.succeed(hold.value.held, undefined).pipe(\n Effect.andThen(Deferred.await(hold.value.release)),\n )\n : Effect.void;\n\n const book = (request: SupplierBookRequest) =>\n Ref.modify(state, (current) => {\n const counts = new Map(current.counts).set(\n request.idempotencyKey,\n (current.counts.get(request.idempotencyKey) ?? 0) + 1,\n );\n const existing = current.bookings.get(request.idempotencyKey);\n const record =\n existing ??\n SupplierBookingRecord.make({\n bookingRef: supplierBookingRefFor(request.idempotencyKey),\n idempotencyKey: request.idempotencyKey,\n operation: request.operation,\n detail: request.detail,\n status: \"confirmed\",\n });\n const bookings =\n existing === undefined\n ? new Map(current.bookings).set(request.idempotencyKey, record)\n : current.bookings;\n const hold = Option.fromNullishOr(current.holds.get(request.idempotencyKey));\n const holds = Option.isSome(hold)\n ? (() => {\n const next = new Map(current.holds);\n next.delete(request.idempotencyKey);\n return next;\n })()\n : current.holds;\n return [\n { record, hold },\n { bookings, counts, holds },\n ] as const;\n }).pipe(Effect.flatMap(({ hold, record }) => enterHold(hold).pipe(Effect.as(record))));\n\n const cancel = (bookingRef: BookingRef) =>\n Ref.modify(state, (current) => {\n const key = cancelBookingIdempotencyKey(bookingRef);\n const counts = new Map(current.counts).set(key, (current.counts.get(key) ?? 0) + 1);\n const existingEntry = [...current.bookings.entries()].find(\n ([, record]) => record.bookingRef === bookingRef,\n );\n if (existingEntry === undefined) {\n return [\n { record: Option.none<SupplierBookingRecord>(), hold: Option.none() },\n { ...current, counts },\n ] as const;\n }\n const [storeKey, existing] = existingEntry;\n const cancelled =\n existing.status === \"cancelled\"\n ? existing\n : SupplierBookingRecord.make({ ...existing, status: \"cancelled\" });\n const bookings = new Map(current.bookings).set(storeKey, cancelled);\n const hold = Option.fromNullishOr(current.holds.get(key));\n const holds = Option.isSome(hold)\n ? (() => {\n const next = new Map(current.holds);\n next.delete(key);\n return next;\n })()\n : current.holds;\n return [\n { record: Option.some(cancelled), hold },\n { bookings, counts, holds },\n ] as const;\n }).pipe(\n Effect.flatMap(({ hold, record }) =>\n Option.isNone(record)\n ? Effect.fail(\n SupplierUnavailable.make({\n message: `The supplier desk has no booking under ${bookingRef}.`,\n }),\n )\n : enterHold(hold).pipe(Effect.as(record.value)),\n ),\n );\n\n return SupplierBookingDesk.of({\n book,\n cancel,\n lookup: (idempotencyKey) =>\n Ref.get(state).pipe(\n Effect.map((current) => Option.fromNullishOr(current.bookings.get(idempotencyKey))),\n ),\n bookings: Ref.get(state).pipe(Effect.map((current) => [...current.bookings.values()])),\n callCount: (idempotencyKey) =>\n Ref.get(state).pipe(Effect.map((current) => current.counts.get(idempotencyKey) ?? 0)),\n holdAfterWrite: (idempotencyKey) =>\n Effect.gen(function* () {\n const held = yield* Deferred.make<void>();\n const release = yield* Deferred.make<void>();\n yield* Ref.update(state, (current) => ({\n ...current,\n holds: new Map(current.holds).set(idempotencyKey, { held, release }),\n }));\n return {\n held: Deferred.await(held),\n release: Deferred.succeed(release, undefined).pipe(Effect.asVoid),\n };\n }),\n });\n }),\n );\n}\n\nexport const TravelGuidanceLayer = Layer.succeed(\n TravelGuidance,\n TravelGuidance.of({\n instructions: (input) =>\n Effect.succeed(\n [\n \"You are the Effect Agent Travel Planner P1 interpreter fixture.\",\n `The user asked: ${input.request}`,\n \"Call search_flights, search_lodging, and search_activities exactly once in one Tool batch.\",\n \"Then return only a JSON object of exactly this shape, no prose:\",\n '{\"itineraries\": [{\"title\": \"<short itinerary name>\", \"route\": \"<origin-destination>\", \"dates\": \"<date range>\", \"flight\": \"<flight description from the Tool result>\", \"lodging\": \"<lodging description from the Tool result>\", \"activities\": [\"<activity>\", \"...\"], \"estimatedTotalCents\": <positive integer total in cents>, \"currency\": \"USD\", \"quoteId\": \"<quoteId from the flight Tool result>\", \"assumptions\": [\"<assumption>\", \"...\"], \"unresolvedConstraints\": [], \"nextAction\": \"review\"}]}',\n \"Use the Tool results verbatim; activity results may legitimately be an empty array.\",\n \"This is read-only planning. Require review before any mutation.\",\n ].join(\"\\n\"),\n ),\n }),\n);\nexport const DeterministicIdGeneratorLayer = Layer.effect(\n IdGenerator,\n Effect.gen(function* () {\n const thread = yield* Ref.make(0);\n const run = yield* Ref.make(0);\n const turn = yield* Ref.make(0);\n return IdGenerator.of({\n nextThreadId: Ref.updateAndGet(thread, (n) => n + 1).pipe(\n Effect.map((n) => Schema.decodeSync(ThreadId)(`thread-${n}`)),\n ),\n nextRunId: Ref.updateAndGet(run, (n) => n + 1).pipe(\n Effect.map((n) => Schema.decodeSync(RunId)(`run-${n}`)),\n ),\n nextTurnId: Ref.updateAndGet(turn, (n) => n + 1).pipe(\n Effect.map((n) => Schema.decodeSync(TurnId)(`turn-${n}`)),\n ),\n });\n }),\n);\nexport const TravelPlannerRuntimeLayer = Layer.mergeAll(\n RunContextPreparationPassthrough,\n ThreadHistory.layerTransient,\n TravelPlannerToolkitLayer,\n FlightCatalogLayer,\n LodgingCatalogLayer,\n ActivityCatalogLayer,\n TravelGuidanceLayer,\n DeterministicIdGeneratorLayer,\n).pipe(Layer.provide(CatalogLifecycle.layerNoDeps));\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"deterministic-layers-CKyYxBhN.mjs","names":[],"sources":["../src/fixtures/travel-planner/definition.ts","../src/fixtures/travel-planner/deterministic-layers.ts"],"sourcesContent":["import { Agent, AgentPolicy } from \"@effect-agent/core\";\nimport { Context, Effect, Schema } from \"effect\";\nimport { Tool, Toolkit } from \"effect/unstable/ai\";\n\nexport const AirportCode = Schema.NonEmptyString.pipe(\n Schema.brand(\"@effect-agent/testing/travel-planner/AirportCode\"),\n);\n\nexport type AirportCode = typeof AirportCode.Type;\n\nexport const QuoteId = Schema.NonEmptyString.pipe(\n Schema.brand(\"@effect-agent/testing/travel-planner/QuoteId\"),\n);\n\nexport type QuoteId = typeof QuoteId.Type;\n\nexport class TripRequest extends Schema.Class<TripRequest>(\"TripRequest\")({\n request: Schema.NonEmptyString,\n origin: AirportCode,\n destination: AirportCode,\n departOn: Schema.String,\n nights: Schema.Int.check(Schema.isGreaterThan(0)),\n travelers: Schema.Int.check(Schema.isGreaterThan(0)),\n budgetCents: Schema.Int.check(Schema.isGreaterThan(0)),\n currency: Schema.Literal(\"USD\"),\n}) {}\n\nexport class FlightQuery extends Schema.Class<FlightQuery>(\"FlightQuery\")({\n origin: AirportCode,\n destination: AirportCode,\n departOn: Schema.String,\n travelers: Schema.Int.check(Schema.isGreaterThan(0)),\n}) {}\n\nexport class LodgingQuery extends Schema.Class<LodgingQuery>(\"LodgingQuery\")({\n destination: AirportCode,\n departOn: Schema.String,\n nights: Schema.Int.check(Schema.isGreaterThan(0)),\n travelers: Schema.Int.check(Schema.isGreaterThan(0)),\n}) {}\n\nexport class ActivityQuery extends Schema.Class<ActivityQuery>(\"ActivityQuery\")({\n destination: AirportCode,\n departOn: Schema.String,\n nights: Schema.Int.check(Schema.isGreaterThan(0)),\n travelers: Schema.Int.check(Schema.isGreaterThan(0)),\n}) {}\n\nexport class FlightOption extends Schema.Class<FlightOption>(\"FlightOption\")({\n quoteId: QuoteId,\n flight: Schema.String,\n estimatedCents: Schema.Int.check(Schema.isGreaterThan(0)),\n currency: Schema.Literal(\"USD\"),\n}) {}\n\nexport class LodgingOption extends Schema.Class<LodgingOption>(\"LodgingOption\")({\n lodging: Schema.String,\n estimatedCents: Schema.Int.check(Schema.isGreaterThan(0)),\n currency: Schema.Literal(\"USD\"),\n}) {}\n\n/** A successful empty activity search is distinct from supplier unavailability. */\nexport class ActivitySearchResult extends Schema.Class<ActivitySearchResult>(\n \"ActivitySearchResult\",\n)({\n activities: Schema.Array(Schema.String),\n}) {}\n\nexport class Itinerary extends Schema.Class<Itinerary>(\"Itinerary\")({\n title: Schema.String,\n route: Schema.String,\n dates: Schema.String,\n flight: Schema.String,\n lodging: Schema.String,\n activities: Schema.Array(Schema.String),\n estimatedTotalCents: Schema.Int.check(Schema.isGreaterThan(0)),\n currency: Schema.Literal(\"USD\"),\n quoteId: QuoteId,\n assumptions: Schema.Array(Schema.String),\n unresolvedConstraints: Schema.Array(Schema.String),\n nextAction: Schema.Literal(\"review\"),\n}) {}\n\nexport class TravelPlan extends Schema.Class<TravelPlan>(\"TravelPlan\")({\n itineraries: Schema.Array(Itinerary),\n}) {}\n\nconst unavailableFields = { query: Schema.String, message: Schema.String };\n\nexport class FlightUnavailable extends Schema.TaggedError<FlightUnavailable>()(\n \"FlightUnavailable\",\n unavailableFields,\n) {}\n\nexport class LodgingUnavailable extends Schema.TaggedError<LodgingUnavailable>()(\n \"LodgingUnavailable\",\n unavailableFields,\n) {}\n\nexport class ActivityUnavailable extends Schema.TaggedError<ActivityUnavailable>()(\n \"ActivityUnavailable\",\n unavailableFields,\n) {}\n\nexport class GuidanceFailure extends Schema.TaggedError<GuidanceFailure>()(\"GuidanceFailure\", {\n message: Schema.String,\n}) {}\n\nexport class FlightCatalog extends Context.Service<\n FlightCatalog,\n { readonly search: (query: FlightQuery) => Effect.Effect<FlightOption, FlightUnavailable> }\n>()(\"@effect-agent/testing/travel-planner/FlightCatalog\") {}\n\nexport class LodgingCatalog extends Context.Service<\n LodgingCatalog,\n { readonly search: (query: LodgingQuery) => Effect.Effect<LodgingOption, LodgingUnavailable> }\n>()(\"@effect-agent/testing/travel-planner/LodgingCatalog\") {}\n\nexport class ActivityCatalog extends Context.Service<\n ActivityCatalog,\n {\n readonly search: (\n query: ActivityQuery,\n ) => Effect.Effect<ActivitySearchResult, ActivityUnavailable>;\n }\n>()(\"@effect-agent/testing/travel-planner/ActivityCatalog\") {}\n\nexport class TravelGuidance extends Context.Service<\n TravelGuidance,\n { readonly instructions: (input: TripRequest) => Effect.Effect<string, GuidanceFailure> }\n>()(\"@effect-agent/testing/travel-planner/TravelGuidance\") {}\n\nexport const SearchFlights = Tool.make(\"search_flights\", {\n parameters: FlightQuery,\n success: FlightOption,\n failure: FlightUnavailable,\n failureMode: \"error\",\n dependencies: [FlightCatalog],\n});\n\nexport const SearchLodging = Tool.make(\"search_lodging\", {\n parameters: LodgingQuery,\n success: LodgingOption,\n failure: LodgingUnavailable,\n failureMode: \"error\",\n dependencies: [LodgingCatalog],\n});\n\nexport const SearchActivities = Tool.make(\"search_activities\", {\n parameters: ActivityQuery,\n success: ActivitySearchResult,\n failure: ActivityUnavailable,\n failureMode: \"error\",\n dependencies: [ActivityCatalog],\n});\n\nexport const TravelPlannerToolkit = Toolkit.make(SearchFlights, SearchLodging, SearchActivities);\n\nexport const TravelPlannerToolkitLayer = TravelPlannerToolkit.toLayer({\n search_flights: (query) => Effect.flatMap(FlightCatalog, (catalog) => catalog.search(query)),\n search_lodging: (query) => Effect.flatMap(LodgingCatalog, (catalog) => catalog.search(query)),\n search_activities: (query) => Effect.flatMap(ActivityCatalog, (catalog) => catalog.search(query)),\n});\n\nexport const TravelPlanner = Agent.make(\"travel-planner\", {\n input: TripRequest,\n output: TravelPlan,\n instructions: (input) =>\n Effect.flatMap(TravelGuidance, (guidance) => guidance.instructions(input)),\n toolkit: TravelPlannerToolkit,\n policy: AgentPolicy.make({\n maxTurns: 2,\n maxToolCalls: 3,\n maxDuration: \"30 seconds\",\n toolConcurrency: 3,\n }),\n description: \"Build one review-only itinerary from bounded parallel deterministic searches.\",\n metadata: { deploymentClass: \"E\", phase: \"P1\" },\n});\n","import { ThreadId, IdGenerator, RunId, TurnId } from \"@effect-agent/core\";\nimport { ThreadHistory, RunContextPreparationPassthrough } from \"@effect-agent/engine\";\nimport { Context, Deferred, Effect, Layer, Option, Ref, Schema } from \"effect\";\n\nimport {\n ActivityCatalog,\n ActivitySearchResult,\n ActivityUnavailable,\n FlightCatalog,\n FlightOption,\n FlightUnavailable,\n LodgingCatalog,\n LodgingOption,\n LodgingUnavailable,\n QuoteId,\n TravelGuidance,\n TravelPlannerToolkit,\n TravelPlannerToolkitLayer,\n} from \"./definition.ts\";\n\nexport class CatalogLifecycleCounts extends Schema.Class<CatalogLifecycleCounts>(\n \"CatalogLifecycleCounts\",\n)({\n acquired: Schema.Natural,\n finalized: Schema.Natural,\n}) {}\n\nexport class CatalogLifecycle extends Context.Service<\n CatalogLifecycle,\n {\n readonly markAcquired: Effect.Effect<void>;\n readonly markFinalized: Effect.Effect<void>;\n readonly counts: Effect.Effect<CatalogLifecycleCounts>;\n }\n>()(\"@effect-agent/testing/travel-planner/CatalogLifecycle\") {\n static readonly layerNoDeps = Layer.effect(\n this,\n Effect.gen(function* () {\n const acquired = yield* Ref.make(0);\n const finalized = yield* Ref.make(0);\n\n return CatalogLifecycle.of({\n markAcquired: Ref.update(acquired, (n) => n + 1),\n markFinalized: Ref.update(finalized, (n) => n + 1),\n counts: Effect.all({ acquired: Ref.get(acquired), finalized: Ref.get(finalized) }).pipe(\n Effect.map((counts) => CatalogLifecycleCounts.make(counts)),\n ),\n });\n }),\n );\n}\n\nconst flight = FlightOption.make({\n quoteId: Schema.decodeSync(QuoteId)(\"quote-sfo-lhr-001\"),\n flight: \"EA 218 · nonstop · SFO 18:40 → LHR 13:05+1\",\n estimatedCents: 180_000,\n currency: \"USD\",\n});\n\nconst lodging = LodgingOption.make({\n lodging: \"Bloomsbury House · refundable studio · 4 nights\",\n estimatedCents: 104_000,\n currency: \"USD\",\n});\n\nconst activities = ActivitySearchResult.make({\n activities: [\"British Museum timed entry\", \"Thames evening walk\"],\n});\n\n/**\n * Deterministic controls for a Tool batch whose completions are released in a\n * caller-selected order. This is intentionally a test fixture: it uses no\n * clock or sleep and lets engine scheduler tests prove parallel starts and\n * declaration-order prompt materialization.\n */\nexport interface TravelPlannerCompletionControls {\n readonly flightStarted: Effect.Effect<void>;\n readonly lodgingStarted: Effect.Effect<void>;\n readonly activityStarted: Effect.Effect<void>;\n readonly releaseFlight: Effect.Effect<void>;\n readonly releaseLodging: Effect.Effect<void>;\n readonly releaseActivity: Effect.Effect<void>;\n}\n\nexport const ReverseCompletionToolkitLayer = Effect.gen(function* () {\n const flightStarted = yield* Deferred.make<void>();\n const lodgingStarted = yield* Deferred.make<void>();\n const activityStarted = yield* Deferred.make<void>();\n const releaseFlight = yield* Deferred.make<void>();\n const releaseLodging = yield* Deferred.make<void>();\n const releaseActivity = yield* Deferred.make<void>();\n\n const awaitRelease = <A>(\n started: Deferred.Deferred<void>,\n release: Deferred.Deferred<void>,\n value: A,\n ) =>\n Deferred.succeed(started, undefined).pipe(\n Effect.andThen(Deferred.await(release)),\n Effect.as(value),\n );\n\n return {\n controls: {\n flightStarted: Deferred.await(flightStarted),\n lodgingStarted: Deferred.await(lodgingStarted),\n activityStarted: Deferred.await(activityStarted),\n releaseFlight: Deferred.succeed(releaseFlight, undefined).pipe(Effect.asVoid),\n releaseLodging: Deferred.succeed(releaseLodging, undefined).pipe(Effect.asVoid),\n releaseActivity: Deferred.succeed(releaseActivity, undefined).pipe(Effect.asVoid),\n },\n layer: TravelPlannerToolkit.toLayer({\n search_flights: () => awaitRelease(flightStarted, releaseFlight, flight),\n search_lodging: () => awaitRelease(lodgingStarted, releaseLodging, lodging),\n search_activities: () => awaitRelease(activityStarted, releaseActivity, activities),\n }),\n };\n});\n\nexport const FlightCatalogLayer = Layer.effect(\n FlightCatalog,\n Effect.gen(function* () {\n const lifecycle = yield* CatalogLifecycle;\n\n yield* Effect.acquireRelease(lifecycle.markAcquired, () => lifecycle.markFinalized);\n\n return FlightCatalog.of({\n search: (query) =>\n query.origin === query.destination\n ? Effect.fail(\n FlightUnavailable.make({\n query: `${query.origin}-${query.destination}`,\n message: \"Origin and destination must differ.\",\n }),\n )\n : Effect.succeed(flight),\n });\n }),\n);\n\nexport const LodgingCatalogLayer = Layer.effect(\n LodgingCatalog,\n Effect.gen(function* () {\n const lifecycle = yield* CatalogLifecycle;\n\n yield* Effect.acquireRelease(lifecycle.markAcquired, () => lifecycle.markFinalized);\n\n return LodgingCatalog.of({\n search: (query) =>\n query.nights < 1\n ? Effect.fail(\n LodgingUnavailable.make({\n query: query.destination,\n message: \"At least one night is required.\",\n }),\n )\n : Effect.succeed(lodging),\n });\n }),\n);\n\nexport const ActivityCatalogLayer = Layer.effect(\n ActivityCatalog,\n Effect.gen(function* () {\n const lifecycle = yield* CatalogLifecycle;\n\n yield* Effect.acquireRelease(lifecycle.markAcquired, () => lifecycle.markFinalized);\n\n return ActivityCatalog.of({\n search: (query) =>\n query.destination === \"\"\n ? Effect.fail(\n ActivityUnavailable.make({\n query: query.destination,\n message: \"Destination is required.\",\n }),\n )\n : Effect.succeed(activities),\n });\n }),\n);\n\n/** Stable supplier-side booking identity, minted deterministically from the idempotency key. */\nexport const BookingRef = Schema.NonEmptyString.pipe(\n Schema.brand(\"@effect-agent/testing/travel-planner/BookingRef\"),\n);\n\nexport type BookingRef = typeof BookingRef.Type;\n\n/** The supplier desk operations the P5 booking Tools and Steps invoke. */\nexport const SupplierOperation = Schema.Literals([\n \"book-flight\",\n \"cancel-booking\",\n \"reserve-flight\",\n \"reserve-lodging\",\n \"issue-confirmation\",\n]);\n\nexport type SupplierOperation = typeof SupplierOperation.Type;\n\n/**\n * One row of external supplier truth. The desk deduplicates by `idempotencyKey` — replaying a\n * call with the same key returns this exact record without creating a second booking — which is\n * precisely the honesty model of DUR-010: the framework never makes an external call\n * exactly-once; the supplier's idempotency key does.\n */\nexport class SupplierBookingRecord extends Schema.Class<SupplierBookingRecord>(\n \"@effect-agent/testing/travel-planner/SupplierBookingRecord\",\n)({\n bookingRef: BookingRef,\n idempotencyKey: Schema.NonEmptyString,\n operation: SupplierOperation,\n detail: Schema.NonEmptyString,\n status: Schema.Literals([\"confirmed\", \"cancelled\"]),\n}) {}\n\nexport class SupplierUnavailable extends Schema.TaggedError<SupplierUnavailable>()(\n \"SupplierUnavailable\",\n { message: Schema.String },\n) {}\n\nexport interface SupplierBookRequest {\n readonly operation: SupplierOperation;\n readonly idempotencyKey: string;\n readonly detail: string;\n}\n\n/** Controls returned by an armed crash window (`holdAfterWrite`). */\nexport interface SupplierHoldControls {\n /** Resolves once the armed call has performed its supplier write and is blocked. */\n readonly held: Effect.Effect<void>;\n /** Releases the blocked call (tests that interrupt the Attempt never call this). */\n readonly release: Effect.Effect<void>;\n}\n\n/** The desk-internal idempotency key of one cancellation: cancel is idempotent by bookingRef. */\nexport const cancelBookingIdempotencyKey = (bookingRef: string): string =>\n `cancel-booking:${bookingRef}`;\n\n/** The deterministic bookingRef the desk mints for one idempotency key. */\nexport const supplierBookingRefFor = (idempotencyKey: string): BookingRef =>\n Schema.decodeSync(BookingRef)(`ref:${idempotencyKey}`);\n\ninterface SupplierHoldWindow {\n readonly held: Deferred.Deferred<void>;\n readonly release: Deferred.Deferred<void>;\n}\n\ninterface SupplierDeskState {\n readonly bookings: ReadonlyMap<string, SupplierBookingRecord>;\n readonly counts: ReadonlyMap<string, number>;\n readonly holds: ReadonlyMap<string, SupplierHoldWindow>;\n}\n\n/**\n * The deterministic in-memory supplier: an idempotency-keyed booking store with per-key call\n * counters and injectable crash windows.\n *\n * - `book`/`cancel` always count the call (at-least-once execution stays observable), then\n * dedupe the external effect by idempotency key — the supplier-side contract the P5 Tools and\n * Steps rely on.\n * - `holdAfterWrite` arms a one-shot crash window: the next call with that key performs its\n * supplier write, signals `held`, and never returns. Interrupting the Attempt at that point\n * models \"the external effect happened but no outcome was recorded\" without any wall clock.\n * - `bookings`/`lookup` expose external truth for the reconciler and for never-fabricate\n * assertions.\n */\nexport class SupplierBookingDesk extends Context.Service<\n SupplierBookingDesk,\n {\n readonly book: (\n request: SupplierBookRequest,\n ) => Effect.Effect<SupplierBookingRecord, SupplierUnavailable>;\n readonly cancel: (\n bookingRef: BookingRef,\n ) => Effect.Effect<SupplierBookingRecord, SupplierUnavailable>;\n readonly lookup: (\n idempotencyKey: string,\n ) => Effect.Effect<Option.Option<SupplierBookingRecord>>;\n readonly bookings: Effect.Effect<ReadonlyArray<SupplierBookingRecord>>;\n readonly callCount: (idempotencyKey: string) => Effect.Effect<number>;\n readonly holdAfterWrite: (idempotencyKey: string) => Effect.Effect<SupplierHoldControls>;\n }\n>()(\"@effect-agent/testing/travel-planner/SupplierBookingDesk\") {\n static readonly layer: Layer.Layer<SupplierBookingDesk> = Layer.effect(\n this,\n Effect.gen(function* () {\n const state = yield* Ref.make<SupplierDeskState>({\n bookings: new Map(),\n counts: new Map(),\n holds: new Map(),\n });\n\n const enterHold = (hold: Option.Option<SupplierHoldWindow>) =>\n Option.isSome(hold)\n ? Deferred.succeed(hold.value.held, undefined).pipe(\n Effect.andThen(Deferred.await(hold.value.release)),\n )\n : Effect.void;\n\n const book = (request: SupplierBookRequest) =>\n Ref.modify(state, (current) => {\n const counts = new Map(current.counts).set(\n request.idempotencyKey,\n (current.counts.get(request.idempotencyKey) ?? 0) + 1,\n );\n\n const existing = current.bookings.get(request.idempotencyKey);\n\n const record =\n existing ??\n SupplierBookingRecord.make({\n bookingRef: supplierBookingRefFor(request.idempotencyKey),\n idempotencyKey: request.idempotencyKey,\n operation: request.operation,\n detail: request.detail,\n status: \"confirmed\",\n });\n\n const bookings =\n existing === undefined\n ? new Map(current.bookings).set(request.idempotencyKey, record)\n : current.bookings;\n\n const hold = Option.fromNullishOr(current.holds.get(request.idempotencyKey));\n\n const holds = Option.isSome(hold)\n ? (() => {\n const next = new Map(current.holds);\n\n next.delete(request.idempotencyKey);\n\n return next;\n })()\n : current.holds;\n\n return [\n { record, hold },\n { bookings, counts, holds },\n ] as const;\n }).pipe(Effect.flatMap(({ hold, record }) => enterHold(hold).pipe(Effect.as(record))));\n\n const cancel = (bookingRef: BookingRef) =>\n Ref.modify(state, (current) => {\n const key = cancelBookingIdempotencyKey(bookingRef);\n const counts = new Map(current.counts).set(key, (current.counts.get(key) ?? 0) + 1);\n\n const existingEntry = [...current.bookings.entries()].find(\n ([, record]) => record.bookingRef === bookingRef,\n );\n\n if (existingEntry === undefined) {\n return [\n { record: Option.none<SupplierBookingRecord>(), hold: Option.none() },\n { ...current, counts },\n ] as const;\n }\n const [storeKey, existing] = existingEntry;\n\n const cancelled =\n existing.status === \"cancelled\"\n ? existing\n : SupplierBookingRecord.make({ ...existing, status: \"cancelled\" });\n\n const bookings = new Map(current.bookings).set(storeKey, cancelled);\n const hold = Option.fromNullishOr(current.holds.get(key));\n\n const holds = Option.isSome(hold)\n ? (() => {\n const next = new Map(current.holds);\n\n next.delete(key);\n\n return next;\n })()\n : current.holds;\n\n return [\n { record: Option.some(cancelled), hold },\n { bookings, counts, holds },\n ] as const;\n }).pipe(\n Effect.flatMap(({ hold, record }) =>\n Option.isNone(record)\n ? Effect.fail(\n SupplierUnavailable.make({\n message: `The supplier desk has no booking under ${bookingRef}.`,\n }),\n )\n : enterHold(hold).pipe(Effect.as(record.value)),\n ),\n );\n\n return SupplierBookingDesk.of({\n book,\n cancel,\n lookup: (idempotencyKey) =>\n Ref.get(state).pipe(\n Effect.map((current) => Option.fromNullishOr(current.bookings.get(idempotencyKey))),\n ),\n bookings: Ref.get(state).pipe(Effect.map((current) => [...current.bookings.values()])),\n callCount: (idempotencyKey) =>\n Ref.get(state).pipe(Effect.map((current) => current.counts.get(idempotencyKey) ?? 0)),\n holdAfterWrite: (idempotencyKey) =>\n Effect.gen(function* () {\n const held = yield* Deferred.make<void>();\n const release = yield* Deferred.make<void>();\n\n yield* Ref.update(state, (current) => ({\n ...current,\n holds: new Map(current.holds).set(idempotencyKey, { held, release }),\n }));\n\n return {\n held: Deferred.await(held),\n release: Deferred.succeed(release, undefined).pipe(Effect.asVoid),\n };\n }),\n });\n }),\n );\n}\n\nexport const TravelGuidanceLayer = Layer.succeed(\n TravelGuidance,\n TravelGuidance.of({\n instructions: (input) =>\n Effect.succeed(\n [\n \"You are the Effect Agent Travel Planner P1 interpreter fixture.\",\n `The user asked: ${input.request}`,\n \"Call search_flights, search_lodging, and search_activities exactly once in one Tool batch.\",\n \"Then return only a JSON object of exactly this shape, no prose:\",\n '{\"itineraries\": [{\"title\": \"<short itinerary name>\", \"route\": \"<origin-destination>\", \"dates\": \"<date range>\", \"flight\": \"<flight description from the Tool result>\", \"lodging\": \"<lodging description from the Tool result>\", \"activities\": [\"<activity>\", \"...\"], \"estimatedTotalCents\": <positive integer total in cents>, \"currency\": \"USD\", \"quoteId\": \"<quoteId from the flight Tool result>\", \"assumptions\": [\"<assumption>\", \"...\"], \"unresolvedConstraints\": [], \"nextAction\": \"review\"}]}',\n \"Use the Tool results verbatim; activity results may legitimately be an empty array.\",\n \"This is read-only planning. Require review before any mutation.\",\n ].join(\"\\n\"),\n ),\n }),\n);\n\nexport const DeterministicIdGeneratorLayer = Layer.effect(\n IdGenerator,\n Effect.gen(function* () {\n const thread = yield* Ref.make(0);\n const run = yield* Ref.make(0);\n const turn = yield* Ref.make(0);\n\n return IdGenerator.of({\n nextThreadId: Ref.updateAndGet(thread, (n) => n + 1).pipe(\n Effect.map((n) => Schema.decodeSync(ThreadId)(`thread-${n}`)),\n ),\n nextRunId: Ref.updateAndGet(run, (n) => n + 1).pipe(\n Effect.map((n) => Schema.decodeSync(RunId)(`run-${n}`)),\n ),\n nextTurnId: Ref.updateAndGet(turn, (n) => n + 1).pipe(\n Effect.map((n) => Schema.decodeSync(TurnId)(`turn-${n}`)),\n ),\n });\n }),\n);\n\nexport const TravelPlannerRuntimeLayer = Layer.mergeAll(\n RunContextPreparationPassthrough,\n ThreadHistory.layerTransient,\n TravelPlannerToolkitLayer,\n FlightCatalogLayer,\n LodgingCatalogLayer,\n ActivityCatalogLayer,\n TravelGuidanceLayer,\n DeterministicIdGeneratorLayer,\n).pipe(Layer.provide(CatalogLifecycle.layerNoDeps));\n"],"mappings":"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"}
|
|
@@ -197,7 +197,7 @@ interface DocsResearcherHarnessOptions {
|
|
|
197
197
|
}
|
|
198
198
|
/** One durable coordinator/summarizer pair with observable counters and MCP evidence. */
|
|
199
199
|
interface DocsResearcherHarness {
|
|
200
|
-
/**
|
|
200
|
+
/** Resolved registrations for the parent and child workers. */
|
|
201
201
|
readonly bindings: ReadonlyArray<ResolvedBinding>;
|
|
202
202
|
/** The validated MCP discovery the child toolkit registration was gated on. */
|
|
203
203
|
readonly discovery: McpDiscovery;
|
package/dist/docs-researcher.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as DeterministicIdGeneratorLayer } from "./deterministic-layers-CKyYxBhN.mjs";
|
|
2
|
-
import { Context, Effect,
|
|
2
|
+
import { Context, Effect, JsonPointer, Layer, Ref, Schema, Stream } from "effect";
|
|
3
3
|
import { LanguageModel, Model, Tool, Toolkit } from "effect/unstable/ai";
|
|
4
4
|
import { McpConnectionRequest, McpConnector, McpServerIdentity, McpToolkitMismatch, Redactor, Subagent, SubagentPolicy, SubagentReservationsMemoryLive, SubagentRuntime, connectMcp } from "@effect-agent/capabilities";
|
|
5
5
|
import { Agent, AgentPolicy } from "@effect-agent/core";
|
|
@@ -236,7 +236,8 @@ const flattenTopLevelRef = (schema) => {
|
|
|
236
236
|
const ref = schema["$ref"];
|
|
237
237
|
if (typeof ref !== "string") return decodeToolJsonSchema(schema);
|
|
238
238
|
const defs = decodeJsonSchemaDefinitions(schema["$defs"]);
|
|
239
|
-
const
|
|
239
|
+
const key = ref.startsWith("#/$defs/") ? JsonPointer.unescapeToken(ref.slice(8)) : void 0;
|
|
240
|
+
const resolved = key !== void 0 && Object.hasOwn(defs, key) ? defs[key] : void 0;
|
|
240
241
|
return decodeToolJsonSchema(resolved ?? schema);
|
|
241
242
|
};
|
|
242
243
|
const fetchDocumentOutputSchema = flattenTopLevelRef(Tool.getJsonSchemaFromSchema(FetchDocument.successSchema));
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"docs-researcher.mjs","names":[],"sources":["../src/fixtures/docs-researcher/definition.ts","../src/fixtures/docs-researcher/mcp.ts","../src/fixtures/docs-researcher/harness.ts"],"sourcesContent":["import { Subagent, SubagentPolicy, SubagentRuntime } from \"@effect-agent/capabilities\";\nimport { Agent, AgentPolicy } from \"@effect-agent/core\";\nimport type { RuntimeBinding } from \"@effect-agent/engine\";\nimport { Context, Effect, Schema } from \"effect\";\nimport { Tool, Toolkit } from \"effect/unstable/ai\";\n\n// ---------------------------------------------------------------------------\n// Docs Researcher (P7 internal agent #3, plan §6): a coordinator that\n// delegates per-document summarization to a doc-summarizer child through the\n// S2 durable delegation surface, with the child's content tools served —\n// and validated — through the MCP connector against a scripted MCP fixture.\n// The corpus, tools, and both Agent Definitions are deterministic fixtures in\n// the travel-planner style so DN tests (and any later DC assembly) reuse them.\n// ---------------------------------------------------------------------------\n\nexport const ResearchDocumentId = Schema.NonEmptyString.check(Schema.isMaxLength(64)).pipe(\n Schema.brand(\"@effect-agent/testing/docs-researcher/ResearchDocumentId\"),\n);\nexport type ResearchDocumentId = typeof ResearchDocumentId.Type;\n\nconst BoundedTitle = Schema.NonEmptyString.check(Schema.isMaxLength(120));\nconst BoundedBody = Schema.NonEmptyString.check(Schema.isMaxLength(16 * 1024));\n/** Bounded summary text: the ONLY child-derived text that may cross to the parent. */\nexport const BoundedSummary = Schema.NonEmptyString.check(Schema.isMaxLength(240));\n\nexport class DocumentQuery extends Schema.Class<DocumentQuery>(\"DocumentQuery\")({\n documentId: ResearchDocumentId,\n}) {}\n\n/** One bounded research document as the MCP content server exposes it. */\nexport class ResearchDocument extends Schema.Class<ResearchDocument>(\"ResearchDocument\")({\n documentId: ResearchDocumentId,\n title: BoundedTitle,\n body: BoundedBody,\n}) {}\n\nexport class DocumentUnavailable extends Schema.TaggedError<DocumentUnavailable>()(\n \"DocumentUnavailable\",\n {\n documentId: ResearchDocumentId,\n message: Schema.String,\n },\n) {}\n\n/** The content store behind the scripted MCP server. */\nexport class DocumentLibrary extends Context.Service<\n DocumentLibrary,\n {\n readonly fetch: (query: DocumentQuery) => Effect.Effect<ResearchDocument, DocumentUnavailable>;\n }\n>()(\"@effect-agent/testing/docs-researcher/DocumentLibrary\") {}\n\n/**\n * The one content tool the doc-summarizer child uses. Its authored JSON\n * schema is what MCP discovery must serve byte-for-byte: the scripted MCP\n * fixture derives its discovery entry from `Tool.getJsonSchema(FetchDocument)`\n * and `validateMcpDiscovery` re-derives and digests both sides (CAP-009).\n */\nexport const FetchDocument = Tool.make(\"fetch_document\", {\n description: \"Fetch one bounded research document by its identifier.\",\n parameters: DocumentQuery,\n success: ResearchDocument,\n failure: DocumentUnavailable,\n failureMode: \"error\",\n dependencies: [DocumentLibrary],\n});\n\nexport const DocContentToolkit = Toolkit.make(FetchDocument);\nexport const docContentToolkitLayer = DocContentToolkit.toLayer({\n fetch_document: (query) => Effect.flatMap(DocumentLibrary, (library) => library.fetch(query)),\n});\n\n// ---------------------------------------------------------------------------\n// Deterministic corpus. Every body deliberately embeds BOTH a secret marker\n// and a distinctive body phrase: the tests assert that neither ever reaches\n// the parent Thread, the parent prompts, or a redacted preview — only\n// the bounded summary crosses the delegation boundary (SUB-015, SEC-008).\n// ---------------------------------------------------------------------------\n\n/** Never allowed outside a child Thread or an unredacted fixture value. */\nexport const docsDocumentBodySecret = \"docs-vault-secret-771\";\n\nconst decodeDocumentId = Schema.decodeSync(ResearchDocumentId);\n\ninterface CorpusEntry {\n readonly document: ResearchDocument;\n readonly bodyPhrase: string;\n readonly summary: string;\n}\n\nconst corpusEntries = new Map<string, CorpusEntry>(\n [\n {\n documentId: \"durability-notes\",\n title: \"Durability protocol notes\",\n bodyPhrase: \"amber-ledger-passage\",\n summary:\n \"Settlement results are recorded exactly once while external side effects stay at-least-once.\",\n },\n {\n documentId: \"subagent-notes\",\n title: \"Subagent join notes\",\n bodyPhrase: \"cobalt-join-corridor\",\n summary: \"A parent joins only the verified settlement of its own established child.\",\n },\n ].map((entry) => [\n entry.documentId,\n {\n document: ResearchDocument.make({\n documentId: decodeDocumentId(entry.documentId),\n title: entry.title,\n body: `${entry.bodyPhrase}: internal working notes. ${docsDocumentBodySecret}. ${entry.summary} Raw notes stay inside the child Thread.`,\n }),\n bodyPhrase: entry.bodyPhrase,\n summary: entry.summary,\n },\n ]),\n);\n\n/** The corpus document ids in canonical fixture order. */\nexport const researchCorpusDocumentIds: ReadonlyArray<ResearchDocumentId> = [\n decodeDocumentId(\"durability-notes\"),\n decodeDocumentId(\"subagent-notes\"),\n];\n\nconst requireCorpusEntry = (documentId: string): CorpusEntry => {\n const entry = corpusEntries.get(documentId);\n if (entry === undefined) {\n throw new Error(`No deterministic corpus entry exists for document ${documentId}`);\n }\n return entry;\n};\n\n/** Deterministic library lookup shared by the scripted MCP content handlers. */\nexport const researchDocumentLookup = (\n query: DocumentQuery,\n): Effect.Effect<ResearchDocument, DocumentUnavailable> => {\n const entry = corpusEntries.get(query.documentId);\n return entry === undefined\n ? Effect.fail(\n DocumentUnavailable.make({\n documentId: query.documentId,\n message: \"No deterministic corpus entry exists for this document.\",\n }),\n )\n : Effect.succeed(entry.document);\n};\n\n/** The full fixture document (body includes the secret marker — child-side only). */\nexport const researchDocumentFor = (documentId: string): ResearchDocument =>\n requireCorpusEntry(documentId).document;\n\n/** The distinctive body phrase used by context-isolation assertions. */\nexport const documentBodyPhrase = (documentId: string): string =>\n requireCorpusEntry(documentId).bodyPhrase;\n\n// ---------------------------------------------------------------------------\n// Doc Summarizer: the child Agent Definition. Its toolkit is the authored\n// `DocContentToolkit`; the harness registers its worker Binding only after\n// MCP discovery validates that exact toolkit (mcp.ts).\n// ---------------------------------------------------------------------------\n\nexport class SummaryBrief extends Schema.Class<SummaryBrief>(\"SummaryBrief\")({\n documentId: ResearchDocumentId,\n focus: Schema.NonEmptyString,\n}) {}\n\nexport class DocumentSummary extends Schema.Class<DocumentSummary>(\"DocumentSummary\")({\n documentId: ResearchDocumentId,\n summary: BoundedSummary,\n}) {}\n\n/** The summary the scripted child writes after fetching the document. */\nexport const documentSummaryFor = (documentId: string): DocumentSummary =>\n DocumentSummary.make({\n documentId: requireCorpusEntry(documentId).document.documentId,\n summary: requireCorpusEntry(documentId).summary,\n });\n\nexport const encodedDocumentSummary = (documentId: string): string =>\n JSON.stringify(Schema.encodeSync(DocumentSummary)(documentSummaryFor(documentId)));\n\nexport const DocSummarizer = Agent.make(\"doc-summarizer\", {\n input: SummaryBrief,\n output: DocumentSummary,\n instructions:\n \"Fetch the briefed document with fetch_document exactly once, then return only a JSON document summary. Never copy raw notes or secrets into the summary.\",\n toolkit: DocContentToolkit,\n policy: AgentPolicy.make({\n maxTurns: 2,\n maxToolCalls: 1,\n maxDuration: \"30 seconds\",\n toolConcurrency: 1,\n }),\n description: \"Summarize one bounded research document fetched through MCP content tools.\",\n metadata: { deploymentClass: \"DN\", phase: \"P7\" },\n});\n\n// ---------------------------------------------------------------------------\n// Delegation Definition: the coordinator sees exactly one Tool with explicit\n// projections and finite bounds. `projectResult` is the declassification\n// boundary (SUB-015): only the bounded summary crosses; the fetched body —\n// secret marker included — stays in the child Thread.\n// ---------------------------------------------------------------------------\n\nexport class SummaryRequest extends Schema.Class<SummaryRequest>(\"SummaryRequest\")({\n documentId: ResearchDocumentId,\n}) {}\n\nexport class SummaryFinding extends Schema.Class<SummaryFinding>(\"SummaryFinding\")({\n documentId: ResearchDocumentId,\n summary: BoundedSummary,\n}) {}\n\nexport class DocumentSummaryFailed extends Schema.TaggedError<DocumentSummaryFailed>()(\n \"DocumentSummaryFailed\",\n {\n childErrorTag: Schema.NonEmptyString,\n },\n) {}\n\n/** Finite per-invocation bounds (SUB-009): one fetch per child, two children per Run. */\nexport const documentSummaryPolicy = SubagentPolicy.make({\n maxChildren: 2,\n maxConcurrency: 2,\n maxTurns: 2,\n maxToolCalls: 1,\n maxDuration: \"10 seconds\",\n});\n\nexport const delegateDocumentSummary = Subagent.define(\"delegate_document_summary\", {\n description:\n \"Summarize one research document through the doc-summarizer child and return a bounded finding.\",\n target: DocSummarizer,\n parameters: SummaryRequest,\n success: SummaryFinding,\n failure: DocumentSummaryFailed,\n prepareInput: (request) =>\n Effect.succeed(\n SummaryBrief.make({\n documentId: request.documentId,\n focus: \"summarize:durability-claims\",\n }),\n ),\n projectResult: (summary) =>\n Effect.succeed(\n SummaryFinding.make({\n documentId: summary.documentId,\n summary: summary.summary,\n }),\n ),\n policy: documentSummaryPolicy,\n});\n\n/** Total mapping from every expected child Run failure to the declared Tool failure (SUB-028). */\nexport const mapSummaryChildFailure = (failure: { readonly _tag: string }): DocumentSummaryFailed =>\n DocumentSummaryFailed.make({ childErrorTag: failure._tag });\n\n/** The exact digest strings the durable declaration AND host registration must share (SUB-023). */\nexport const docsSummarizerDigestStrings = {\n agent: \"50\".repeat(32),\n model: \"51\".repeat(32),\n tools: \"52\".repeat(32),\n} as const;\n\n/** Runtime wiring: the immutable delegation plus one explicit child Binding (S2 declaration). */\nexport const docsSummaryHandlersLayer = <Provider, ModelProvides, ModelRequires>(\n childBinding: RuntimeBinding<\n typeof SummaryBrief,\n typeof DocumentSummary,\n string,\n Toolkit.Tools<typeof DocContentToolkit>,\n Provider,\n ModelProvides,\n ModelRequires\n >,\n) =>\n SubagentRuntime.layer(delegateDocumentSummary, childBinding, {\n mapChildFailure: mapSummaryChildFailure,\n durable: { targetDigests: docsSummarizerDigestStrings },\n });\n\n// ---------------------------------------------------------------------------\n// Docs Researcher: the parent Agent Definition.\n// ---------------------------------------------------------------------------\n\nexport class ResearchRequest extends Schema.Class<ResearchRequest>(\"ResearchRequest\")({\n question: Schema.NonEmptyString,\n documentIds: Schema.Array(ResearchDocumentId).check(Schema.isMinLength(1)),\n}) {}\n\nexport class ResearchDigest extends Schema.Class<ResearchDigest>(\"ResearchDigest\")({\n findings: Schema.Array(SummaryFinding),\n nextAction: Schema.Literal(\"review\"),\n}) {}\n\n/** Parent-only transcript markers proving child context isolation (SUB-006/SUB-015). */\nexport const docsCoordinatorConfidentialMarker = \"docs-coordinator-vault-19x\";\nexport const docsMissionConfidentialMarker = \"docs-mission-dossier-42f\";\n\nexport const DocsResearcherToolkit = Toolkit.make(delegateDocumentSummary.tool);\n\nexport const DocsResearcher = Agent.make(\"docs-researcher\", {\n input: ResearchRequest,\n output: ResearchDigest,\n instructions: [\n \"You are the Effect Agent P7 docs-researcher coordinator.\",\n `Coordinator-only context: ${docsCoordinatorConfidentialMarker}.`,\n \"Call delegate_document_summary once per requested document in one Tool batch.\",\n \"Return only a JSON digest built from the delegated findings. This is read-only research.\",\n ].join(\"\\n\"),\n toolkit: DocsResearcherToolkit,\n policy: AgentPolicy.make({\n maxTurns: 2,\n maxToolCalls: 2,\n maxDuration: \"30 seconds\",\n toolConcurrency: 2,\n }),\n description: \"Coordinate per-document summarization through one declared delegation Tool.\",\n metadata: { deploymentClass: \"DN\", phase: \"P7\" },\n});\n\n/** The default two-document research mission. */\nexport const researchMissionRequest = ResearchRequest.make({\n question: `Summarize the durability and subagent notes; keep ${docsMissionConfidentialMarker} inside the coordinator thread.`,\n documentIds: researchCorpusDocumentIds,\n});\n\n/** The coordinator's expected final digest for the given documents. */\nexport const expectedResearchDigest = (\n documentIds: ReadonlyArray<string> = researchCorpusDocumentIds,\n): ResearchDigest =>\n ResearchDigest.make({\n findings: documentIds.map((documentId) => {\n const summary = documentSummaryFor(documentId);\n return SummaryFinding.make({\n documentId: summary.documentId,\n summary: summary.summary,\n });\n }),\n nextAction: \"review\",\n });\n","import {\n McpConnectionRequest,\n McpConnector,\n McpServerIdentity,\n McpToolkitMismatch,\n type McpConnection,\n} from \"@effect-agent/capabilities\";\nimport { Effect, JsonSchema, Layer, Schema } from \"effect\";\nimport { Tool } from \"effect/unstable/ai\";\nimport * as McpSchema from \"effect/unstable/ai/McpSchema\";\n\nimport { DocContentToolkit, FetchDocument } from \"./definition.ts\";\n\n// ---------------------------------------------------------------------------\n// Scripted MCP fixture: a deterministic `McpConnector` adapter that serves the\n// doc-summarizer's content tool. Discovery entries are DERIVED from the\n// authored Tool (`Tool.getJsonSchema`), so `validateMcpDiscovery` digesting\n// both sides is a real check, not a tautology; the mismatch and over-limit\n// connectors below serve deliberately wrong contracts so tests can pin the\n// fail-closed paths (CAP-009, SEC-013).\n// ---------------------------------------------------------------------------\n\n/** Framework-side hard bounds one docs-researcher assembly requests. */\nexport const docsMcpRequest = McpConnectionRequest.make({\n serverId: \"docs-content-mcp\",\n maxToolCount: 4,\n maxToolDescriptionBytes: 256,\n maxDiscoveryBytes: 16_384,\n connectTimeoutMillis: 1_000,\n});\n\nexport const docsMcpIdentity = McpServerIdentity.make({\n serverId: docsMcpRequest.serverId,\n implementation: McpSchema.Implementation.make({\n name: \"docs-researcher-content-fixture\",\n version: \"1.0.0\",\n }),\n});\n\n/**\n * `Tool.getJsonSchema` produces a `$ref`/`$defs`-shaped schema for\n * `FetchDocument`'s named, refined parameters type, but `McpSchema.Tool`'s\n * `inputSchema` requires a flat `{ type: \"object\", ... }` root — the shape a\n * real MCP server advertises on the wire. This inlines the single top-level\n * `$ref` so the derivation described above still holds byte-for-byte.\n */\nconst JsonSchemaDefinitions = Schema.Record(\n Schema.String,\n Schema.Record(Schema.String, Schema.Unknown),\n);\nconst decodeJsonSchemaDefinitions = Schema.decodeUnknownSync(JsonSchemaDefinitions);\nconst decodeToolJsonSchema = Schema.decodeUnknownSync(McpSchema.ToolJsonSchema);\n\nconst flattenTopLevelRef = (schema: JsonSchema.JsonSchema): McpSchema.ToolJsonSchema => {\n const ref = schema[\"$ref\"];\n if (typeof ref !== \"string\") {\n return decodeToolJsonSchema(schema);\n }\n\n const defs = decodeJsonSchemaDefinitions(schema[\"$defs\"]);\n const resolved = JsonSchema.resolve$ref(ref, defs);\n return decodeToolJsonSchema(resolved ?? schema);\n};\n\nconst fetchDocumentOutputSchema = flattenTopLevelRef(\n Tool.getJsonSchemaFromSchema(FetchDocument.successSchema),\n);\n\nconst discoveredFetchDocument = McpSchema.Tool.make({\n name: FetchDocument.name,\n description: \"Fetch one bounded research document by its identifier.\",\n inputSchema: flattenTopLevelRef(Tool.getJsonSchema(FetchDocument)),\n // `validateMcpDiscovery` only compares an `outputSchema` derived down to an\n // object type; mirror that so this fixture stays a real round-trip check.\n ...(fetchDocumentOutputSchema.type === \"object\"\n ? { outputSchema: fetchDocumentOutputSchema }\n : {}),\n});\n\nconst scriptedConnector = (tools: ReadonlyArray<McpSchema.Tool>): Layer.Layer<McpConnector> =>\n Layer.succeed(McpConnector)({\n connect: () =>\n Effect.acquireRelease(\n Effect.succeed({\n identity: docsMcpIdentity,\n capabilities: McpSchema.ServerCapabilities.make({}),\n tools,\n toolkit: DocContentToolkit,\n }),\n () => Effect.void,\n ),\n });\n\n/** The well-behaved scripted content server. */\nexport const docsMcpConnectorLayer: Layer.Layer<McpConnector> = scriptedConnector([\n discoveredFetchDocument,\n]);\n\n/** Serves a tool description exceeding `maxToolDescriptionBytes` (SEC-013 bound). */\nexport const docsMcpOversizedConnectorLayer: Layer.Layer<McpConnector> = scriptedConnector([\n McpSchema.Tool.make({\n name: discoveredFetchDocument.name,\n description: \"x\".repeat(1_024),\n inputSchema: discoveredFetchDocument.inputSchema,\n }),\n]);\n\n/** Serves a discovery schema that disagrees with the authored toolkit (drift fails closed). */\nexport const docsMcpMismatchedConnectorLayer: Layer.Layer<McpConnector> = scriptedConnector([\n McpSchema.Tool.make({\n name: discoveredFetchDocument.name,\n description: discoveredFetchDocument.description,\n inputSchema: { type: \"object\", properties: { url: { type: \"string\" } } },\n }),\n]);\n\nconst isJsonEqual = (left: unknown, right: unknown): boolean =>\n JSON.stringify(left) === JSON.stringify(right);\n\n/**\n * Bind DISCOVERY to AUTHORING: `validateMcpDiscovery` (inside `connectMcp`)\n * already proved the served discovery matches the connection's own Toolkit;\n * this check additionally proves that Toolkit is the exact toolkit the\n * doc-summarizer was AUTHORED against — same tool names, same derived JSON\n * schemas — so a connector cannot substitute a look-alike toolkit. The\n * docs-researcher harness runs it before any worker Binding registration and\n * fails closed on any drift.\n */\nexport const assertDiscoveryMatchesAuthoredToolkit = Effect.fn(\n \"DocsResearcher.assertDiscoveryMatchesAuthoredToolkit\",\n)(function* (connection: McpConnection): Effect.fn.Return<void, McpToolkitMismatch> {\n const authored = Object.values(DocContentToolkit.tools)\n .map((tool) => ({ name: tool.name, inputSchema: Tool.getJsonSchema(tool) }))\n .sort((left, right) => (left.name < right.name ? -1 : left.name > right.name ? 1 : 0));\n const discovered = Object.values(connection.toolkit.tools)\n .map((tool) => ({ name: tool.name, inputSchema: Tool.getJsonSchema(tool) }))\n .sort((left, right) => (left.name < right.name ? -1 : left.name > right.name ? 1 : 0));\n const matches =\n authored.length === discovered.length &&\n authored.every(\n (tool, index) =>\n tool.name === discovered[index]?.name &&\n isJsonEqual(tool.inputSchema, discovered[index]?.inputSchema),\n );\n if (!matches) {\n return yield* McpToolkitMismatch.make({\n serverId: connection.discovery.identity.serverId,\n message:\n \"The MCP-discovered toolkit does not match the doc-summarizer's authored content toolkit\",\n });\n }\n});\n\n/** Round-trip guard for encoded discovery values persisted as fixture evidence. */\nexport const DocsMcpDiscoveryEvidence = Schema.Struct({\n serverId: Schema.NonEmptyString,\n toolCount: Schema.Natural,\n encodedBytes: Schema.Natural,\n toolkitSchemaDigest: Schema.String,\n});\n","import {\n connectMcp,\n Redactor,\n SubagentReservationsMemoryLive,\n type McpDiscovery,\n type RedactedPreview,\n type RedactionError,\n} from \"@effect-agent/capabilities\";\nimport { Agent, type ThreadId } from \"@effect-agent/core\";\nimport {\n DefinitionDigests,\n DeploymentId,\n Digest,\n DurableWorkerBinding,\n Principal,\n ProducerId,\n type DurableSubmitOptions,\n type IdempotencyKey,\n type ResolvedBinding,\n} from \"@effect-agent/thread\";\nimport type { Crypto } from \"effect\";\nimport { Effect, Layer, Ref, Schema, Stream } from \"effect\";\nimport { LanguageModel, Model, type Response } from \"effect/unstable/ai\";\n\nimport { DeterministicIdGeneratorLayer } from \"../travel-planner/deterministic-layers.ts\";\nimport {\n DocsResearcher,\n DocSummarizer,\n DocumentLibrary,\n docContentToolkitLayer,\n docsSummaryHandlersLayer,\n encodedDocumentSummary,\n expectedResearchDigest,\n ResearchDigest,\n ResearchDocument,\n researchCorpusDocumentIds,\n researchDocumentFor,\n researchDocumentLookup,\n} from \"./definition.ts\";\nimport {\n assertDiscoveryMatchesAuthoredToolkit,\n docsMcpConnectorLayer,\n docsMcpRequest,\n} from \"./mcp.ts\";\n\n// ---------------------------------------------------------------------------\n// DN durable harness for the docs-researcher (P7 plan §6 agent #3), following\n// `makeDurableResearchHarness` conventions: invocation counters and captured\n// prompts live OUTSIDE the Model Layers so they survive Layer rebuilds across\n// Attempts and separate runtime handles over the same SQLite file.\n// ---------------------------------------------------------------------------\n\nexport const docsResearcherDeploymentId = Schema.decodeSync(DeploymentId)(\n \"docs-researcher-p7-deployment\",\n);\nexport const docsResearcherProducerId = Schema.decodeSync(ProducerId)(\n \"docs-researcher-p7-producer\",\n);\nexport const docsResearcherPrincipal = Schema.decodeSync(Principal)(\"docs-researcher-p7-principal\");\n\nconst digestOf = (pair: string) => Schema.decodeSync(Digest)(pair.repeat(32));\n\n/** Redacted, deterministic coordinator definition digests for this fixture version. */\nexport const docsCoordinatorDigests = DefinitionDigests.make({\n agent: digestOf(\"40\"),\n model: digestOf(\"41\"),\n tools: digestOf(\"42\"),\n});\n\n/** The child registration digests — byte-equal to `docsSummarizerDigestStrings` (SUB-023). */\nexport const docsSummarizerDigests = DefinitionDigests.make({\n agent: digestOf(\"50\"),\n model: digestOf(\"51\"),\n tools: digestOf(\"52\"),\n});\n\n/** Durable admission options for one docs-researcher Submission on one mission lane. */\nexport const docsResearcherSubmitOptions = (\n threadId: ThreadId,\n idempotencyKey: IdempotencyKey,\n): DurableSubmitOptions => ({\n threadId,\n principal: docsResearcherPrincipal,\n idempotencyKey,\n definitions: docsCoordinatorDigests,\n});\n\n/** The structural submit slice of the coordinator Binding (`DurableAgentRuntime.submit`). */\nexport const docsResearcherSubmitAgent = {\n definition: { id: DocsResearcher.id, input: DocsResearcher.input },\n} as const;\n\n/** The deterministic delegation Tool Call identity for one document. */\nexport const summarizeCallId = (documentId: string): string => `summarize-${documentId}`;\n\n/** The child's own scripted fetch Tool Call identity for one document. */\nexport const fetchCallId = (documentId: string): string => `fetch-${documentId}`;\n\nconst scriptedUsage = { inputTokens: { total: 96 }, outputTokens: { total: 64 } };\n\nconst summaryDelegationParts = (\n documentIds: ReadonlyArray<string>,\n): ReadonlyArray<Response.StreamPartEncoded> => [\n ...documentIds.map((documentId): Response.StreamPartEncoded => ({\n type: \"tool-call\",\n id: summarizeCallId(documentId),\n name: \"delegate_document_summary\",\n params: { documentId },\n providerExecuted: false,\n })),\n { type: \"finish\", reason: \"tool-calls\", usage: scriptedUsage },\n];\n\nconst digestParts = (\n documentIds: ReadonlyArray<string>,\n): ReadonlyArray<Response.StreamPartEncoded> => [\n { type: \"text-start\", id: \"digest\" },\n {\n type: \"text-delta\",\n id: \"digest\",\n delta: JSON.stringify(Schema.encodeSync(ResearchDigest)(expectedResearchDigest(documentIds))),\n },\n { type: \"text-end\", id: \"digest\" },\n { type: \"finish\", reason: \"stop\", usage: scriptedUsage },\n];\n\nconst fetchParts = (documentId: string): ReadonlyArray<Response.StreamPartEncoded> => [\n {\n type: \"tool-call\",\n id: fetchCallId(documentId),\n name: \"fetch_document\",\n params: { documentId },\n providerExecuted: false,\n },\n { type: \"finish\", reason: \"tool-calls\", usage: scriptedUsage },\n];\n\nconst summaryParts = (documentId: string): ReadonlyArray<Response.StreamPartEncoded> => [\n { type: \"text-start\", id: \"document-summary\" },\n { type: \"text-delta\", id: \"document-summary\", delta: encodedDocumentSummary(documentId) },\n { type: \"text-end\", id: \"document-summary\" },\n { type: \"finish\", reason: \"stop\", usage: scriptedUsage },\n];\n\n/**\n * One prompt-aware scripted model with externally observable counters. A DN\n * Attempt may resume on a fresh Layer build, so responses derive from the\n * committed history in the prompt — never from an in-Layer turn counter.\n */\nconst makeCountingModel = (\n name: string,\n decide: (promptJson: string) => Effect.Effect<ReadonlyArray<Response.StreamPartEncoded>>,\n) =>\n Effect.gen(function* () {\n const calls = yield* Ref.make(0);\n const prompts = yield* Ref.make<ReadonlyArray<string>>([]);\n const model = Model.make(\n \"scripted\",\n name,\n Layer.effect(\n LanguageModel.LanguageModel,\n LanguageModel.make({\n generateText: () => Effect.succeed([]),\n streamText: (request) =>\n Stream.unwrap(\n Effect.gen(function* () {\n yield* Ref.update(calls, (value) => value + 1);\n const promptJson = JSON.stringify(request.prompt);\n yield* Ref.update(prompts, (previous) => [...previous, promptJson]);\n return Stream.fromIterable(yield* decide(promptJson));\n }),\n ),\n }),\n ),\n );\n return { model, calls: Ref.get(calls), prompts: Ref.get(prompts) };\n });\n\n/** Optional overrides for one docs-researcher harness. */\nexport interface DocsResearcherHarnessOptions {\n /** Documents to research; defaults to the full two-document corpus. */\n readonly documentIds?: ReadonlyArray<string> | undefined;\n}\n\n/** One durable coordinator/summarizer pair with observable counters and MCP evidence. */\nexport interface DocsResearcherHarness {\n /** Host registrations for `NodeDurableRuntimeOptions.bindings` (parent + child). */\n readonly bindings: ReadonlyArray<ResolvedBinding>;\n /** The validated MCP discovery the child toolkit registration was gated on. */\n readonly discovery: McpDiscovery;\n /** Total coordinator model invocations across every Attempt and runtime handle. */\n readonly parentModelCalls: Effect.Effect<number>;\n /** JSON-encoded coordinator prompts in request order. */\n readonly parentPrompts: Effect.Effect<ReadonlyArray<string>>;\n /** Total summarizer model invocations across every Attempt and runtime handle. */\n readonly childModelCalls: Effect.Effect<number>;\n /** JSON-encoded summarizer prompts in request order (context-isolation evidence). */\n readonly childPrompts: Effect.Effect<ReadonlyArray<string>>;\n /** MCP content-tool handler executions for one document (external side-effect record). */\n readonly fetchInvocations: (documentId: string) => Effect.Effect<number>;\n}\n\n/**\n * Build the docs-researcher harness. Order matters and is the point: the\n * child's content toolkit is only registered as a worker Binding AFTER the\n * MCP connector's bounded discovery validated the authored toolkit\n * byte-for-byte (`connectMcp` + `assertDiscoveryMatchesAuthoredToolkit`), so\n * \"the tools the summarizer runs are the tools discovery served\" is enforced\n * at assembly, not assumed. Content-tool execution then flows through the\n * counting `DocumentLibrary` — the scripted MCP server's content store.\n */\nexport const makeDocsResearcherHarness = (options?: DocsResearcherHarnessOptions) =>\n Effect.gen(function* () {\n const documentIds = options?.documentIds ?? researchCorpusDocumentIds;\n\n // MCP discovery gate (CAP-009): bounded, digest-verified, fail-closed.\n const discovery = yield* Effect.scoped(\n Effect.gen(function* () {\n const connection = yield* connectMcp(docsMcpRequest);\n yield* assertDiscoveryMatchesAuthoredToolkit(connection);\n return connection.discovery;\n }),\n ).pipe(Effect.provide(docsMcpConnectorLayer));\n\n const fetchCounts = yield* Ref.make<ReadonlyMap<string, number>>(new Map());\n const libraryLayer = Layer.succeed(\n DocumentLibrary,\n DocumentLibrary.of({\n fetch: (query) =>\n Ref.update(fetchCounts, (current) =>\n new Map(current).set(query.documentId, (current.get(query.documentId) ?? 0) + 1),\n ).pipe(Effect.andThen(researchDocumentLookup(query))),\n }),\n );\n const childToolkitLayer = docContentToolkitLayer.pipe(Layer.provideMerge(libraryLayer));\n\n const childModel = yield* makeCountingModel(\"doc-summarizer-p7\", (promptJson) =>\n Effect.suspend(() => {\n const documentId = documentIds.find((candidate) => promptJson.includes(candidate));\n if (documentId === undefined) {\n return Effect.die(new Error(\"The summarizer prompt names no corpus document\"));\n }\n return Effect.succeed(\n promptJson.includes(fetchCallId(documentId))\n ? summaryParts(documentId)\n : fetchParts(documentId),\n );\n }),\n );\n const childBinding = Agent.withModel(DocSummarizer, childModel.model);\n\n const firstCallId = summarizeCallId(documentIds[0] ?? \"durability-notes\");\n const parentModel = yield* makeCountingModel(\"docs-researcher-p7\", (promptJson) =>\n Effect.succeed(\n promptJson.includes(firstCallId)\n ? digestParts(documentIds)\n : summaryDelegationParts(documentIds),\n ),\n );\n const parentBinding = Agent.withModel(DocsResearcher, parentModel.model);\n\n const delegationLayer = docsSummaryHandlersLayer(childBinding).pipe(\n Layer.provide(\n Layer.mergeAll(\n childToolkitLayer,\n SubagentReservationsMemoryLive,\n DeterministicIdGeneratorLayer,\n ),\n ),\n );\n\n const parentResolved: ResolvedBinding = yield* DurableWorkerBinding.make(\n parentBinding,\n docsCoordinatorDigests,\n ).pipe(Effect.provide(delegationLayer));\n const childResolved: ResolvedBinding = yield* DurableWorkerBinding.make(\n childBinding,\n docsSummarizerDigests,\n ).pipe(Effect.provide(childToolkitLayer));\n\n const harness: DocsResearcherHarness = {\n bindings: [parentResolved, childResolved],\n discovery,\n parentModelCalls: parentModel.calls,\n parentPrompts: parentModel.prompts,\n childModelCalls: childModel.calls,\n childPrompts: childModel.prompts,\n fetchInvocations: (documentId) =>\n Ref.get(fetchCounts).pipe(Effect.map((current) => current.get(documentId) ?? 0)),\n };\n return harness;\n });\n\nconst encodeResearchDocument = Schema.encodeEffect(ResearchDocument);\n\n/**\n * The audit-surface preview of one fetched document: the raw document —\n * secret marker and all — passes through the configured structural `Redactor`\n * before anything may quote it outside the child Thread (SEC-008,\n * CAP-013). Tests assert the preview keeps shape but no scalar content.\n */\nexport const redactedDocumentPreview = Effect.fn(\"DocsResearcher.redactedDocumentPreview\")(\n function* (documentId: string): Effect.fn.Return<RedactedPreview, RedactionError, Redactor> {\n const redactor = yield* Redactor;\n const encoded = yield* encodeResearchDocument(researchDocumentFor(documentId)).pipe(\n Effect.orDie,\n );\n return yield* redactor.redact(encoded);\n },\n);\n\n// Crypto is deliberately in the harness requirements (`connectMcp` digests\n// discovery): callers provide a platform Crypto Layer, keeping this fixture\n// platform-neutral.\nexport type DocsResearcherHarnessRequirements = Crypto.Crypto;\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"docs-researcher.mjs","names":[],"sources":["../src/fixtures/docs-researcher/definition.ts","../src/fixtures/docs-researcher/mcp.ts","../src/fixtures/docs-researcher/harness.ts"],"sourcesContent":["import { Subagent, SubagentPolicy, SubagentRuntime } from \"@effect-agent/capabilities\";\nimport { Agent, AgentPolicy } from \"@effect-agent/core\";\nimport type { RuntimeBinding } from \"@effect-agent/engine\";\nimport { Context, Effect, Schema } from \"effect\";\nimport { Tool, Toolkit } from \"effect/unstable/ai\";\n\n// ---------------------------------------------------------------------------\n// Docs Researcher (P7 internal agent #3, plan §6): a coordinator that\n// delegates per-document summarization to a doc-summarizer child through the\n// S2 durable delegation surface, with the child's content tools served —\n// and validated — through the MCP connector against a scripted MCP fixture.\n// The corpus, tools, and both Agent Definitions are deterministic fixtures in\n// the travel-planner style so DN tests (and any later DC assembly) reuse them.\n// ---------------------------------------------------------------------------\n\nexport const ResearchDocumentId = Schema.NonEmptyString.check(Schema.isMaxLength(64)).pipe(\n Schema.brand(\"@effect-agent/testing/docs-researcher/ResearchDocumentId\"),\n);\n\nexport type ResearchDocumentId = typeof ResearchDocumentId.Type;\n\nconst BoundedTitle = Schema.NonEmptyString.check(Schema.isMaxLength(120));\nconst BoundedBody = Schema.NonEmptyString.check(Schema.isMaxLength(16 * 1024));\n\n/** Bounded summary text: the ONLY child-derived text that may cross to the parent. */\nexport const BoundedSummary = Schema.NonEmptyString.check(Schema.isMaxLength(240));\n\nexport class DocumentQuery extends Schema.Class<DocumentQuery>(\"DocumentQuery\")({\n documentId: ResearchDocumentId,\n}) {}\n\n/** One bounded research document as the MCP content server exposes it. */\nexport class ResearchDocument extends Schema.Class<ResearchDocument>(\"ResearchDocument\")({\n documentId: ResearchDocumentId,\n title: BoundedTitle,\n body: BoundedBody,\n}) {}\n\nexport class DocumentUnavailable extends Schema.TaggedError<DocumentUnavailable>()(\n \"DocumentUnavailable\",\n {\n documentId: ResearchDocumentId,\n message: Schema.String,\n },\n) {}\n\n/** The content store behind the scripted MCP server. */\nexport class DocumentLibrary extends Context.Service<\n DocumentLibrary,\n {\n readonly fetch: (query: DocumentQuery) => Effect.Effect<ResearchDocument, DocumentUnavailable>;\n }\n>()(\"@effect-agent/testing/docs-researcher/DocumentLibrary\") {}\n\n/**\n * The one content tool the doc-summarizer child uses. Its authored JSON\n * schema is what MCP discovery must serve byte-for-byte: the scripted MCP\n * fixture derives its discovery entry from `Tool.getJsonSchema(FetchDocument)`\n * and `validateMcpDiscovery` re-derives and digests both sides (CAP-009).\n */\nexport const FetchDocument = Tool.make(\"fetch_document\", {\n description: \"Fetch one bounded research document by its identifier.\",\n parameters: DocumentQuery,\n success: ResearchDocument,\n failure: DocumentUnavailable,\n failureMode: \"error\",\n dependencies: [DocumentLibrary],\n});\n\nexport const DocContentToolkit = Toolkit.make(FetchDocument);\n\nexport const docContentToolkitLayer = DocContentToolkit.toLayer({\n fetch_document: (query) => Effect.flatMap(DocumentLibrary, (library) => library.fetch(query)),\n});\n\n// ---------------------------------------------------------------------------\n// Deterministic corpus. Every body deliberately embeds BOTH a secret marker\n// and a distinctive body phrase: the tests assert that neither ever reaches\n// the parent Thread, the parent prompts, or a redacted preview — only\n// the bounded summary crosses the delegation boundary (SUB-015, SEC-008).\n// ---------------------------------------------------------------------------\n\n/** Never allowed outside a child Thread or an unredacted fixture value. */\nexport const docsDocumentBodySecret = \"docs-vault-secret-771\";\n\nconst decodeDocumentId = Schema.decodeSync(ResearchDocumentId);\n\ninterface CorpusEntry {\n readonly document: ResearchDocument;\n readonly bodyPhrase: string;\n readonly summary: string;\n}\n\nconst corpusEntries = new Map<string, CorpusEntry>(\n [\n {\n documentId: \"durability-notes\",\n title: \"Durability protocol notes\",\n bodyPhrase: \"amber-ledger-passage\",\n summary:\n \"Settlement results are recorded exactly once while external side effects stay at-least-once.\",\n },\n {\n documentId: \"subagent-notes\",\n title: \"Subagent join notes\",\n bodyPhrase: \"cobalt-join-corridor\",\n summary: \"A parent joins only the verified settlement of its own established child.\",\n },\n ].map((entry) => [\n entry.documentId,\n {\n document: ResearchDocument.make({\n documentId: decodeDocumentId(entry.documentId),\n title: entry.title,\n body: `${entry.bodyPhrase}: internal working notes. ${docsDocumentBodySecret}. ${entry.summary} Raw notes stay inside the child Thread.`,\n }),\n bodyPhrase: entry.bodyPhrase,\n summary: entry.summary,\n },\n ]),\n);\n\n/** The corpus document ids in canonical fixture order. */\nexport const researchCorpusDocumentIds: ReadonlyArray<ResearchDocumentId> = [\n decodeDocumentId(\"durability-notes\"),\n decodeDocumentId(\"subagent-notes\"),\n];\n\nconst requireCorpusEntry = (documentId: string): CorpusEntry => {\n const entry = corpusEntries.get(documentId);\n\n if (entry === undefined) {\n throw new Error(`No deterministic corpus entry exists for document ${documentId}`);\n }\n\n return entry;\n};\n\n/** Deterministic library lookup shared by the scripted MCP content handlers. */\nexport const researchDocumentLookup = (\n query: DocumentQuery,\n): Effect.Effect<ResearchDocument, DocumentUnavailable> => {\n const entry = corpusEntries.get(query.documentId);\n\n return entry === undefined\n ? Effect.fail(\n DocumentUnavailable.make({\n documentId: query.documentId,\n message: \"No deterministic corpus entry exists for this document.\",\n }),\n )\n : Effect.succeed(entry.document);\n};\n\n/** The full fixture document (body includes the secret marker — child-side only). */\nexport const researchDocumentFor = (documentId: string): ResearchDocument =>\n requireCorpusEntry(documentId).document;\n\n/** The distinctive body phrase used by context-isolation assertions. */\nexport const documentBodyPhrase = (documentId: string): string =>\n requireCorpusEntry(documentId).bodyPhrase;\n\n// ---------------------------------------------------------------------------\n// Doc Summarizer: the child Agent Definition. Its toolkit is the authored\n// `DocContentToolkit`; the harness registers its worker Binding only after\n// MCP discovery validates that exact toolkit (mcp.ts).\n// ---------------------------------------------------------------------------\n\nexport class SummaryBrief extends Schema.Class<SummaryBrief>(\"SummaryBrief\")({\n documentId: ResearchDocumentId,\n focus: Schema.NonEmptyString,\n}) {}\n\nexport class DocumentSummary extends Schema.Class<DocumentSummary>(\"DocumentSummary\")({\n documentId: ResearchDocumentId,\n summary: BoundedSummary,\n}) {}\n\n/** The summary the scripted child writes after fetching the document. */\nexport const documentSummaryFor = (documentId: string): DocumentSummary =>\n DocumentSummary.make({\n documentId: requireCorpusEntry(documentId).document.documentId,\n summary: requireCorpusEntry(documentId).summary,\n });\n\nexport const encodedDocumentSummary = (documentId: string): string =>\n JSON.stringify(Schema.encodeSync(DocumentSummary)(documentSummaryFor(documentId)));\n\nexport const DocSummarizer = Agent.make(\"doc-summarizer\", {\n input: SummaryBrief,\n output: DocumentSummary,\n instructions:\n \"Fetch the briefed document with fetch_document exactly once, then return only a JSON document summary. Never copy raw notes or secrets into the summary.\",\n toolkit: DocContentToolkit,\n policy: AgentPolicy.make({\n maxTurns: 2,\n maxToolCalls: 1,\n maxDuration: \"30 seconds\",\n toolConcurrency: 1,\n }),\n description: \"Summarize one bounded research document fetched through MCP content tools.\",\n metadata: { deploymentClass: \"DN\", phase: \"P7\" },\n});\n\n// ---------------------------------------------------------------------------\n// Delegation Definition: the coordinator sees exactly one Tool with explicit\n// projections and finite bounds. `projectResult` is the declassification\n// boundary (SUB-015): only the bounded summary crosses; the fetched body —\n// secret marker included — stays in the child Thread.\n// ---------------------------------------------------------------------------\n\nexport class SummaryRequest extends Schema.Class<SummaryRequest>(\"SummaryRequest\")({\n documentId: ResearchDocumentId,\n}) {}\n\nexport class SummaryFinding extends Schema.Class<SummaryFinding>(\"SummaryFinding\")({\n documentId: ResearchDocumentId,\n summary: BoundedSummary,\n}) {}\n\nexport class DocumentSummaryFailed extends Schema.TaggedError<DocumentSummaryFailed>()(\n \"DocumentSummaryFailed\",\n {\n childErrorTag: Schema.NonEmptyString,\n },\n) {}\n\n/** Finite per-invocation bounds (SUB-009): one fetch per child, two children per Run. */\nexport const documentSummaryPolicy = SubagentPolicy.make({\n maxChildren: 2,\n maxConcurrency: 2,\n maxTurns: 2,\n maxToolCalls: 1,\n maxDuration: \"10 seconds\",\n});\n\nexport const delegateDocumentSummary = Subagent.define(\"delegate_document_summary\", {\n description:\n \"Summarize one research document through the doc-summarizer child and return a bounded finding.\",\n target: DocSummarizer,\n parameters: SummaryRequest,\n success: SummaryFinding,\n failure: DocumentSummaryFailed,\n prepareInput: (request) =>\n Effect.succeed(\n SummaryBrief.make({\n documentId: request.documentId,\n focus: \"summarize:durability-claims\",\n }),\n ),\n projectResult: (summary) =>\n Effect.succeed(\n SummaryFinding.make({\n documentId: summary.documentId,\n summary: summary.summary,\n }),\n ),\n policy: documentSummaryPolicy,\n});\n\n/** Total mapping from every expected child Run failure to the declared Tool failure (SUB-028). */\nexport const mapSummaryChildFailure = (failure: { readonly _tag: string }): DocumentSummaryFailed =>\n DocumentSummaryFailed.make({ childErrorTag: failure._tag });\n\n/** The exact digest strings the durable declaration AND host registration must share (SUB-023). */\nexport const docsSummarizerDigestStrings = {\n agent: \"50\".repeat(32),\n model: \"51\".repeat(32),\n tools: \"52\".repeat(32),\n} as const;\n\n/** Runtime wiring: the immutable delegation plus one explicit child Binding (S2 declaration). */\nexport const docsSummaryHandlersLayer = <Provider, ModelProvides, ModelRequires>(\n childBinding: RuntimeBinding<\n typeof SummaryBrief,\n typeof DocumentSummary,\n string,\n Toolkit.Tools<typeof DocContentToolkit>,\n Provider,\n ModelProvides,\n ModelRequires\n >,\n) =>\n SubagentRuntime.layer(delegateDocumentSummary, childBinding, {\n mapChildFailure: mapSummaryChildFailure,\n durable: { targetDigests: docsSummarizerDigestStrings },\n });\n\n// ---------------------------------------------------------------------------\n// Docs Researcher: the parent Agent Definition.\n// ---------------------------------------------------------------------------\n\nexport class ResearchRequest extends Schema.Class<ResearchRequest>(\"ResearchRequest\")({\n question: Schema.NonEmptyString,\n documentIds: Schema.Array(ResearchDocumentId).check(Schema.isMinLength(1)),\n}) {}\n\nexport class ResearchDigest extends Schema.Class<ResearchDigest>(\"ResearchDigest\")({\n findings: Schema.Array(SummaryFinding),\n nextAction: Schema.Literal(\"review\"),\n}) {}\n\n/** Parent-only transcript markers proving child context isolation (SUB-006/SUB-015). */\nexport const docsCoordinatorConfidentialMarker = \"docs-coordinator-vault-19x\";\nexport const docsMissionConfidentialMarker = \"docs-mission-dossier-42f\";\n\nexport const DocsResearcherToolkit = Toolkit.make(delegateDocumentSummary.tool);\n\nexport const DocsResearcher = Agent.make(\"docs-researcher\", {\n input: ResearchRequest,\n output: ResearchDigest,\n instructions: [\n \"You are the Effect Agent P7 docs-researcher coordinator.\",\n `Coordinator-only context: ${docsCoordinatorConfidentialMarker}.`,\n \"Call delegate_document_summary once per requested document in one Tool batch.\",\n \"Return only a JSON digest built from the delegated findings. This is read-only research.\",\n ].join(\"\\n\"),\n toolkit: DocsResearcherToolkit,\n policy: AgentPolicy.make({\n maxTurns: 2,\n maxToolCalls: 2,\n maxDuration: \"30 seconds\",\n toolConcurrency: 2,\n }),\n description: \"Coordinate per-document summarization through one declared delegation Tool.\",\n metadata: { deploymentClass: \"DN\", phase: \"P7\" },\n});\n\n/** The default two-document research mission. */\nexport const researchMissionRequest = ResearchRequest.make({\n question: `Summarize the durability and subagent notes; keep ${docsMissionConfidentialMarker} inside the coordinator thread.`,\n documentIds: researchCorpusDocumentIds,\n});\n\n/** The coordinator's expected final digest for the given documents. */\nexport const expectedResearchDigest = (\n documentIds: ReadonlyArray<string> = researchCorpusDocumentIds,\n): ResearchDigest =>\n ResearchDigest.make({\n findings: documentIds.map((documentId) => {\n const summary = documentSummaryFor(documentId);\n\n return SummaryFinding.make({\n documentId: summary.documentId,\n summary: summary.summary,\n });\n }),\n nextAction: \"review\",\n });\n","import {\n McpConnectionRequest,\n McpConnector,\n McpServerIdentity,\n McpToolkitMismatch,\n type McpConnection,\n} from \"@effect-agent/capabilities\";\nimport type { JsonSchema } from \"effect\";\nimport { Effect, JsonPointer, Layer, Schema } from \"effect\";\nimport { Tool } from \"effect/unstable/ai\";\nimport * as McpSchema from \"effect/unstable/ai/McpSchema\";\n\nimport { DocContentToolkit, FetchDocument } from \"./definition.ts\";\n\n// ---------------------------------------------------------------------------\n// Scripted MCP fixture: a deterministic `McpConnector` adapter that serves the\n// doc-summarizer's content tool. Discovery entries are DERIVED from the\n// authored Tool (`Tool.getJsonSchema`), so `validateMcpDiscovery` digesting\n// both sides is a real check, not a tautology; the mismatch and over-limit\n// connectors below serve deliberately wrong contracts so tests can pin the\n// fail-closed paths (CAP-009, SEC-013).\n// ---------------------------------------------------------------------------\n\n/** Framework-side hard bounds one docs-researcher assembly requests. */\nexport const docsMcpRequest = McpConnectionRequest.make({\n serverId: \"docs-content-mcp\",\n maxToolCount: 4,\n maxToolDescriptionBytes: 256,\n maxDiscoveryBytes: 16_384,\n connectTimeoutMillis: 1_000,\n});\n\nexport const docsMcpIdentity = McpServerIdentity.make({\n serverId: docsMcpRequest.serverId,\n implementation: McpSchema.Implementation.make({\n name: \"docs-researcher-content-fixture\",\n version: \"1.0.0\",\n }),\n});\n\n/**\n * `Tool.getJsonSchema` produces a `$ref`/`$defs`-shaped schema for\n * `FetchDocument`'s named, refined parameters type, but `McpSchema.Tool`'s\n * `inputSchema` requires a flat `{ type: \"object\", ... }` root — the shape a\n * real MCP server advertises on the wire. This inlines the single top-level\n * `$ref` so the derivation described above still holds byte-for-byte.\n */\nconst JsonSchemaDefinitions = Schema.Record(\n Schema.String,\n Schema.Record(Schema.String, Schema.Unknown),\n);\n\nconst decodeJsonSchemaDefinitions = Schema.decodeUnknownSync(JsonSchemaDefinitions);\nconst decodeToolJsonSchema = Schema.decodeUnknownSync(McpSchema.ToolJsonSchema);\n\nconst flattenTopLevelRef = (schema: JsonSchema.JsonSchema): McpSchema.ToolJsonSchema => {\n const ref = schema[\"$ref\"];\n\n if (typeof ref !== \"string\") {\n return decodeToolJsonSchema(schema);\n }\n\n const defs = decodeJsonSchemaDefinitions(schema[\"$defs\"]);\n\n const key = ref.startsWith(\"#/$defs/\")\n ? JsonPointer.unescapeToken(ref.slice(\"#/$defs/\".length))\n : undefined;\n\n const resolved = key !== undefined && Object.hasOwn(defs, key) ? defs[key] : undefined;\n\n return decodeToolJsonSchema(resolved ?? schema);\n};\n\nconst fetchDocumentOutputSchema = flattenTopLevelRef(\n Tool.getJsonSchemaFromSchema(FetchDocument.successSchema),\n);\n\nconst discoveredFetchDocument = McpSchema.Tool.make({\n name: FetchDocument.name,\n description: \"Fetch one bounded research document by its identifier.\",\n inputSchema: flattenTopLevelRef(Tool.getJsonSchema(FetchDocument)),\n // `validateMcpDiscovery` only compares an `outputSchema` derived down to an\n // object type; mirror that so this fixture stays a real round-trip check.\n ...(fetchDocumentOutputSchema.type === \"object\"\n ? { outputSchema: fetchDocumentOutputSchema }\n : {}),\n});\n\nconst scriptedConnector = (tools: ReadonlyArray<McpSchema.Tool>): Layer.Layer<McpConnector> =>\n Layer.succeed(McpConnector)({\n connect: () =>\n Effect.acquireRelease(\n Effect.succeed({\n identity: docsMcpIdentity,\n capabilities: McpSchema.ServerCapabilities.make({}),\n tools,\n toolkit: DocContentToolkit,\n }),\n () => Effect.void,\n ),\n });\n\n/** The well-behaved scripted content server. */\nexport const docsMcpConnectorLayer: Layer.Layer<McpConnector> = scriptedConnector([\n discoveredFetchDocument,\n]);\n\n/** Serves a tool description exceeding `maxToolDescriptionBytes` (SEC-013 bound). */\nexport const docsMcpOversizedConnectorLayer: Layer.Layer<McpConnector> = scriptedConnector([\n McpSchema.Tool.make({\n name: discoveredFetchDocument.name,\n description: \"x\".repeat(1_024),\n inputSchema: discoveredFetchDocument.inputSchema,\n }),\n]);\n\n/** Serves a discovery schema that disagrees with the authored toolkit (drift fails closed). */\nexport const docsMcpMismatchedConnectorLayer: Layer.Layer<McpConnector> = scriptedConnector([\n McpSchema.Tool.make({\n name: discoveredFetchDocument.name,\n description: discoveredFetchDocument.description,\n inputSchema: { type: \"object\", properties: { url: { type: \"string\" } } },\n }),\n]);\n\nconst isJsonEqual = (left: unknown, right: unknown): boolean =>\n JSON.stringify(left) === JSON.stringify(right);\n\n/**\n * Bind DISCOVERY to AUTHORING: `validateMcpDiscovery` (inside `connectMcp`)\n * already proved the served discovery matches the connection's own Toolkit;\n * this check additionally proves that Toolkit is the exact toolkit the\n * doc-summarizer was AUTHORED against — same tool names, same derived JSON\n * schemas — so a connector cannot substitute a look-alike toolkit. The\n * docs-researcher harness runs it before any worker Binding registration and\n * fails closed on any drift.\n */\nexport const assertDiscoveryMatchesAuthoredToolkit = Effect.fn(\n \"DocsResearcher.assertDiscoveryMatchesAuthoredToolkit\",\n)(function* (connection: McpConnection): Effect.fn.Return<void, McpToolkitMismatch> {\n const authored = Object.values(DocContentToolkit.tools)\n .map((tool) => ({ name: tool.name, inputSchema: Tool.getJsonSchema(tool) }))\n .sort((left, right) => (left.name < right.name ? -1 : left.name > right.name ? 1 : 0));\n\n const discovered = Object.values(connection.toolkit.tools)\n .map((tool) => ({ name: tool.name, inputSchema: Tool.getJsonSchema(tool) }))\n .sort((left, right) => (left.name < right.name ? -1 : left.name > right.name ? 1 : 0));\n\n const matches =\n authored.length === discovered.length &&\n authored.every(\n (tool, index) =>\n tool.name === discovered[index]?.name &&\n isJsonEqual(tool.inputSchema, discovered[index]?.inputSchema),\n );\n\n if (!matches) {\n return yield* McpToolkitMismatch.make({\n serverId: connection.discovery.identity.serverId,\n message:\n \"The MCP-discovered toolkit does not match the doc-summarizer's authored content toolkit\",\n });\n }\n});\n\n/** Round-trip guard for encoded discovery values persisted as fixture evidence. */\nexport const DocsMcpDiscoveryEvidence = Schema.Struct({\n serverId: Schema.NonEmptyString,\n toolCount: Schema.Natural,\n encodedBytes: Schema.Natural,\n toolkitSchemaDigest: Schema.String,\n});\n","import {\n connectMcp,\n Redactor,\n SubagentReservationsMemoryLive,\n type McpDiscovery,\n type RedactedPreview,\n type RedactionError,\n} from \"@effect-agent/capabilities\";\nimport { Agent, type ThreadId } from \"@effect-agent/core\";\nimport {\n DefinitionDigests,\n DeploymentId,\n Digest,\n DurableWorkerBinding,\n Principal,\n ProducerId,\n type DurableSubmitOptions,\n type IdempotencyKey,\n type ResolvedBinding,\n} from \"@effect-agent/thread\";\nimport type { Crypto } from \"effect\";\nimport { Effect, Layer, Ref, Schema, Stream } from \"effect\";\nimport { LanguageModel, Model, type Response } from \"effect/unstable/ai\";\n\nimport { DeterministicIdGeneratorLayer } from \"../travel-planner/deterministic-layers.ts\";\nimport {\n DocsResearcher,\n DocSummarizer,\n DocumentLibrary,\n docContentToolkitLayer,\n docsSummaryHandlersLayer,\n encodedDocumentSummary,\n expectedResearchDigest,\n ResearchDigest,\n ResearchDocument,\n researchCorpusDocumentIds,\n researchDocumentFor,\n researchDocumentLookup,\n} from \"./definition.ts\";\nimport {\n assertDiscoveryMatchesAuthoredToolkit,\n docsMcpConnectorLayer,\n docsMcpRequest,\n} from \"./mcp.ts\";\n\n// ---------------------------------------------------------------------------\n// DN durable harness for the docs-researcher (P7 plan §6 agent #3), following\n// `makeDurableResearchHarness` conventions: invocation counters and captured\n// prompts live OUTSIDE the Model Layers so they survive Layer rebuilds across\n// Attempts and separate runtime handles over the same SQLite file.\n// ---------------------------------------------------------------------------\n\nexport const docsResearcherDeploymentId = Schema.decodeSync(DeploymentId)(\n \"docs-researcher-p7-deployment\",\n);\n\nexport const docsResearcherProducerId = Schema.decodeSync(ProducerId)(\n \"docs-researcher-p7-producer\",\n);\n\nexport const docsResearcherPrincipal = Schema.decodeSync(Principal)(\"docs-researcher-p7-principal\");\n\nconst digestOf = (pair: string) => Schema.decodeSync(Digest)(pair.repeat(32));\n\n/** Redacted, deterministic coordinator definition digests for this fixture version. */\nexport const docsCoordinatorDigests = DefinitionDigests.make({\n agent: digestOf(\"40\"),\n model: digestOf(\"41\"),\n tools: digestOf(\"42\"),\n});\n\n/** The child registration digests — byte-equal to `docsSummarizerDigestStrings` (SUB-023). */\nexport const docsSummarizerDigests = DefinitionDigests.make({\n agent: digestOf(\"50\"),\n model: digestOf(\"51\"),\n tools: digestOf(\"52\"),\n});\n\n/** Durable admission options for one docs-researcher Submission on one mission lane. */\nexport const docsResearcherSubmitOptions = (\n threadId: ThreadId,\n idempotencyKey: IdempotencyKey,\n): DurableSubmitOptions => ({\n threadId,\n principal: docsResearcherPrincipal,\n idempotencyKey,\n definitions: docsCoordinatorDigests,\n});\n\n/** The structural submit slice of the coordinator Binding (`DurableAgentRuntime.submit`). */\nexport const docsResearcherSubmitAgent = {\n definition: { id: DocsResearcher.id, input: DocsResearcher.input },\n} as const;\n\n/** The deterministic delegation Tool Call identity for one document. */\nexport const summarizeCallId = (documentId: string): string => `summarize-${documentId}`;\n\n/** The child's own scripted fetch Tool Call identity for one document. */\nexport const fetchCallId = (documentId: string): string => `fetch-${documentId}`;\n\nconst scriptedUsage = { inputTokens: { total: 96 }, outputTokens: { total: 64 } };\n\nconst summaryDelegationParts = (\n documentIds: ReadonlyArray<string>,\n): ReadonlyArray<Response.StreamPartEncoded> => [\n ...documentIds.map((documentId): Response.StreamPartEncoded => ({\n type: \"tool-call\",\n id: summarizeCallId(documentId),\n name: \"delegate_document_summary\",\n params: { documentId },\n providerExecuted: false,\n })),\n { type: \"finish\", reason: \"tool-calls\", usage: scriptedUsage },\n];\n\nconst digestParts = (\n documentIds: ReadonlyArray<string>,\n): ReadonlyArray<Response.StreamPartEncoded> => [\n { type: \"text-start\", id: \"digest\" },\n {\n type: \"text-delta\",\n id: \"digest\",\n delta: JSON.stringify(Schema.encodeSync(ResearchDigest)(expectedResearchDigest(documentIds))),\n },\n { type: \"text-end\", id: \"digest\" },\n { type: \"finish\", reason: \"stop\", usage: scriptedUsage },\n];\n\nconst fetchParts = (documentId: string): ReadonlyArray<Response.StreamPartEncoded> => [\n {\n type: \"tool-call\",\n id: fetchCallId(documentId),\n name: \"fetch_document\",\n params: { documentId },\n providerExecuted: false,\n },\n { type: \"finish\", reason: \"tool-calls\", usage: scriptedUsage },\n];\n\nconst summaryParts = (documentId: string): ReadonlyArray<Response.StreamPartEncoded> => [\n { type: \"text-start\", id: \"document-summary\" },\n { type: \"text-delta\", id: \"document-summary\", delta: encodedDocumentSummary(documentId) },\n { type: \"text-end\", id: \"document-summary\" },\n { type: \"finish\", reason: \"stop\", usage: scriptedUsage },\n];\n\n/**\n * One prompt-aware scripted model with externally observable counters. A DN\n * Attempt may resume on a fresh Layer build, so responses derive from the\n * committed history in the prompt — never from an in-Layer turn counter.\n */\nconst makeCountingModel = (\n name: string,\n decide: (promptJson: string) => Effect.Effect<ReadonlyArray<Response.StreamPartEncoded>>,\n) =>\n Effect.gen(function* () {\n const calls = yield* Ref.make(0);\n const prompts = yield* Ref.make<ReadonlyArray<string>>([]);\n\n const model = Model.make(\n \"scripted\",\n name,\n Layer.effect(\n LanguageModel.LanguageModel,\n LanguageModel.make({\n generateText: () => Effect.succeed([]),\n streamText: (request) =>\n Stream.unwrap(\n Effect.gen(function* () {\n yield* Ref.update(calls, (value) => value + 1);\n const promptJson = JSON.stringify(request.prompt);\n\n yield* Ref.update(prompts, (previous) => [...previous, promptJson]);\n\n return Stream.fromIterable(yield* decide(promptJson));\n }),\n ),\n }),\n ),\n );\n\n return { model, calls: Ref.get(calls), prompts: Ref.get(prompts) };\n });\n\n/** Optional overrides for one docs-researcher harness. */\nexport interface DocsResearcherHarnessOptions {\n /** Documents to research; defaults to the full two-document corpus. */\n readonly documentIds?: ReadonlyArray<string> | undefined;\n}\n\n/** One durable coordinator/summarizer pair with observable counters and MCP evidence. */\nexport interface DocsResearcherHarness {\n /** Resolved registrations for the parent and child workers. */\n readonly bindings: ReadonlyArray<ResolvedBinding>;\n /** The validated MCP discovery the child toolkit registration was gated on. */\n readonly discovery: McpDiscovery;\n /** Total coordinator model invocations across every Attempt and runtime handle. */\n readonly parentModelCalls: Effect.Effect<number>;\n /** JSON-encoded coordinator prompts in request order. */\n readonly parentPrompts: Effect.Effect<ReadonlyArray<string>>;\n /** Total summarizer model invocations across every Attempt and runtime handle. */\n readonly childModelCalls: Effect.Effect<number>;\n /** JSON-encoded summarizer prompts in request order (context-isolation evidence). */\n readonly childPrompts: Effect.Effect<ReadonlyArray<string>>;\n /** MCP content-tool handler executions for one document (external side-effect record). */\n readonly fetchInvocations: (documentId: string) => Effect.Effect<number>;\n}\n\n/**\n * Build the docs-researcher harness. Order matters and is the point: the\n * child's content toolkit is only registered as a worker Binding AFTER the\n * MCP connector's bounded discovery validated the authored toolkit\n * byte-for-byte (`connectMcp` + `assertDiscoveryMatchesAuthoredToolkit`), so\n * \"the tools the summarizer runs are the tools discovery served\" is enforced\n * at assembly, not assumed. Content-tool execution then flows through the\n * counting `DocumentLibrary` — the scripted MCP server's content store.\n */\nexport const makeDocsResearcherHarness = (options?: DocsResearcherHarnessOptions) =>\n Effect.gen(function* () {\n const documentIds = options?.documentIds ?? researchCorpusDocumentIds;\n\n // MCP discovery gate (CAP-009): bounded, digest-verified, fail-closed.\n const discovery = yield* Effect.scoped(\n Effect.gen(function* () {\n const connection = yield* connectMcp(docsMcpRequest);\n\n yield* assertDiscoveryMatchesAuthoredToolkit(connection);\n\n return connection.discovery;\n }),\n ).pipe(Effect.provide(docsMcpConnectorLayer));\n\n const fetchCounts = yield* Ref.make<ReadonlyMap<string, number>>(new Map());\n\n const libraryLayer = Layer.succeed(\n DocumentLibrary,\n DocumentLibrary.of({\n fetch: (query) =>\n Ref.update(fetchCounts, (current) =>\n new Map(current).set(query.documentId, (current.get(query.documentId) ?? 0) + 1),\n ).pipe(Effect.andThen(researchDocumentLookup(query))),\n }),\n );\n\n const childToolkitLayer = docContentToolkitLayer.pipe(Layer.provideMerge(libraryLayer));\n\n const childModel = yield* makeCountingModel(\"doc-summarizer-p7\", (promptJson) =>\n Effect.suspend(() => {\n const documentId = documentIds.find((candidate) => promptJson.includes(candidate));\n\n if (documentId === undefined) {\n return Effect.die(new Error(\"The summarizer prompt names no corpus document\"));\n }\n\n return Effect.succeed(\n promptJson.includes(fetchCallId(documentId))\n ? summaryParts(documentId)\n : fetchParts(documentId),\n );\n }),\n );\n\n const childBinding = Agent.withModel(DocSummarizer, childModel.model);\n\n const firstCallId = summarizeCallId(documentIds[0] ?? \"durability-notes\");\n\n const parentModel = yield* makeCountingModel(\"docs-researcher-p7\", (promptJson) =>\n Effect.succeed(\n promptJson.includes(firstCallId)\n ? digestParts(documentIds)\n : summaryDelegationParts(documentIds),\n ),\n );\n\n const parentBinding = Agent.withModel(DocsResearcher, parentModel.model);\n\n const delegationLayer = docsSummaryHandlersLayer(childBinding).pipe(\n Layer.provide(\n Layer.mergeAll(\n childToolkitLayer,\n SubagentReservationsMemoryLive,\n DeterministicIdGeneratorLayer,\n ),\n ),\n );\n\n const parentResolved: ResolvedBinding = yield* DurableWorkerBinding.make(\n parentBinding,\n docsCoordinatorDigests,\n ).pipe(Effect.provide(delegationLayer));\n\n const childResolved: ResolvedBinding = yield* DurableWorkerBinding.make(\n childBinding,\n docsSummarizerDigests,\n ).pipe(Effect.provide(childToolkitLayer));\n\n const harness: DocsResearcherHarness = {\n bindings: [parentResolved, childResolved],\n discovery,\n parentModelCalls: parentModel.calls,\n parentPrompts: parentModel.prompts,\n childModelCalls: childModel.calls,\n childPrompts: childModel.prompts,\n fetchInvocations: (documentId) =>\n Ref.get(fetchCounts).pipe(Effect.map((current) => current.get(documentId) ?? 0)),\n };\n\n return harness;\n });\n\nconst encodeResearchDocument = Schema.encodeEffect(ResearchDocument);\n\n/**\n * The audit-surface preview of one fetched document: the raw document —\n * secret marker and all — passes through the configured structural `Redactor`\n * before anything may quote it outside the child Thread (SEC-008,\n * CAP-013). Tests assert the preview keeps shape but no scalar content.\n */\nexport const redactedDocumentPreview = Effect.fn(\"DocsResearcher.redactedDocumentPreview\")(\n function* (documentId: string): Effect.fn.Return<RedactedPreview, RedactionError, Redactor> {\n const redactor = yield* Redactor;\n\n const encoded = yield* encodeResearchDocument(researchDocumentFor(documentId)).pipe(\n Effect.orDie,\n );\n\n return yield* redactor.redact(encoded);\n },\n);\n\n// Crypto is deliberately in the harness requirements (`connectMcp` digests\n// discovery): callers provide a platform Crypto Layer, keeping this fixture\n// platform-neutral.\nexport type DocsResearcherHarnessRequirements = Crypto.Crypto;\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scripted-model-C2y0ztuj.mjs","names":[],"sources":["../src/scripted-model.ts"],"sourcesContent":["import { Context, Effect, Layer, Ref, Schema, Stream } from \"effect\";\nimport { AiError, LanguageModel, Response } from \"effect/unstable/ai\";\n\nconst ScriptedPartMetadata = Schema.Record(Schema.String, Schema.NullOr(Schema.Json));\nconst ScriptedPartBase = {\n metadata: Schema.optionalKey(ScriptedPartMetadata),\n};\nconst ScriptedToolCallPart = Schema.Struct({\n ...ScriptedPartBase,\n type: Schema.Literal(\"tool-call\"),\n id: Schema.String,\n name: Schema.String,\n params: Schema.Unknown,\n providerExecuted: Schema.optionalKey(Schema.Boolean),\n});\nconst ScriptedToolResultPart = Schema.Struct({\n ...ScriptedPartBase,\n type: Schema.Literal(\"tool-result\"),\n id: Schema.String,\n name: Schema.String,\n result: Schema.Unknown,\n isFailure: Schema.Boolean,\n providerExecuted: Schema.optionalKey(Schema.Boolean),\n preliminary: Schema.optionalKey(Schema.Boolean),\n});\n\n/**\n * Schema for encoded, non-streaming Effect AI response parts.\n *\n * Generic Tool payloads remain explicitly unknown here. `LanguageModel.make`\n * performs the toolkit-specific decode when the scripted response is consumed.\n */\nexport const ScriptedGeneratePart = Schema.Union([\n Schema.toEncoded(Response.TextPart),\n Schema.toEncoded(Response.ReasoningPart),\n Schema.toEncoded(Response.ReasoningDeltaPart),\n Schema.toEncoded(Response.ReasoningEndPart),\n ScriptedToolCallPart,\n ScriptedToolResultPart,\n Schema.toEncoded(Response.ToolApprovalRequestPart),\n Schema.toEncoded(Response.FilePart),\n Schema.toEncoded(Response.DocumentSourcePart),\n Schema.toEncoded(Response.UrlSourcePart),\n Schema.toEncoded(Response.ResponseMetadataPart),\n Schema.toEncoded(Response.FinishPart),\n]).annotate({ identifier: \"ScriptedGeneratePart\" });\nexport type ScriptedGeneratePart = typeof ScriptedGeneratePart.Type;\n\n/**\n * Schema for encoded Effect AI streaming response parts.\n */\nexport const ScriptedStreamPart = Schema.Union([\n Schema.toEncoded(Response.TextStartPart),\n Schema.toEncoded(Response.TextDeltaPart),\n Schema.toEncoded(Response.TextEndPart),\n Schema.toEncoded(Response.ReasoningStartPart),\n Schema.toEncoded(Response.ReasoningDeltaPart),\n Schema.toEncoded(Response.ReasoningEndPart),\n Schema.toEncoded(Response.ToolParamsStartPart),\n Schema.toEncoded(Response.ToolParamsDeltaPart),\n Schema.toEncoded(Response.ToolParamsEndPart),\n ScriptedToolCallPart,\n ScriptedToolResultPart,\n Schema.toEncoded(Response.ToolApprovalRequestPart),\n Schema.toEncoded(Response.FilePart),\n Schema.toEncoded(Response.DocumentSourcePart),\n Schema.toEncoded(Response.UrlSourcePart),\n Schema.toEncoded(Response.ResponseMetadataPart),\n Schema.toEncoded(Response.FinishPart),\n Schema.toEncoded(Response.ErrorPart),\n]).annotate({ identifier: \"ScriptedStreamPart\" });\nexport type ScriptedStreamPart = typeof ScriptedStreamPart.Type;\n\n/** Controls whether a scripted stream completes, fails, or waits for interruption. */\nexport const ScriptedStreamTermination = Schema.Union([\n Schema.TaggedStruct(\"Complete\", {}),\n Schema.TaggedStruct(\"Fail\", {\n description: Schema.String,\n }),\n Schema.TaggedStruct(\"Hang\", {}),\n]);\nexport type ScriptedStreamTermination = typeof ScriptedStreamTermination.Type;\n\n/** One non-streaming invocation and the encoded response parts it returns. */\nexport const ScriptedGenerateTurn = Schema.TaggedStruct(\"Generate\", {\n parts: Schema.Array(ScriptedGeneratePart),\n});\nexport type ScriptedGenerateTurn = typeof ScriptedGenerateTurn.Type;\n\n/** One streaming invocation with its encoded parts and terminal behavior. */\nexport const ScriptedStreamTurn = Schema.TaggedStruct(\"Stream\", {\n parts: Schema.Array(ScriptedStreamPart),\n termination: ScriptedStreamTermination,\n});\nexport type ScriptedStreamTurn = typeof ScriptedStreamTurn.Type;\n\n/**\n * Serializable grammar for one finite scripted provider invocation.\n */\nexport const ScriptedTurn = Schema.Union([ScriptedGenerateTurn, ScriptedStreamTurn]);\nexport type ScriptedTurn = typeof ScriptedTurn.Type;\n\nexport type ScriptedRequestKind = \"generate\" | \"stream\";\n\n/**\n * A request after Effect AI has normalized its prompt, tools, response format,\n * tool choice, span, and incremental-response fields.\n */\nexport interface ScriptedRequest {\n readonly kind: ScriptedRequestKind;\n readonly options: LanguageModel.ProviderOptions;\n}\n\n/** Optional request assertions and stream lifecycle effects for one scripted turn. */\nexport interface ScriptedTurnHooks {\n /** Runs against the normalized provider request before producing the response. */\n readonly assertRequest?: (\n request: LanguageModel.ProviderOptions,\n ) => Effect.Effect<void, AiError.AiError> | void;\n /** Runs immediately before the scripted stream begins emitting parts. */\n readonly onStreamStart?: Effect.Effect<void> | undefined;\n /** Runs when the scripted stream completes, fails, or is interrupted. */\n readonly onStreamFinalize?: Effect.Effect<void> | undefined;\n}\n\n/**\n * Runtime hooks are deliberately separate from the serializable turn grammar.\n */\nexport type ScriptedTurnInput = ScriptedTurn & ScriptedTurnHooks;\n\ninterface ScriptState {\n readonly remaining: ReadonlyArray<ScriptedTurnInput>;\n readonly requests: ReadonlyArray<ScriptedRequest>;\n}\n\nconst scriptedError = (method: string, description: string): AiError.AiError =>\n AiError.AiError.make({\n module: \"@effect-agent/testing/ScriptedModel\",\n method,\n reason: AiError.UnknownError.make({ description }),\n });\n\nconst runAssertion = Effect.fn(\"ScriptedModel.runAssertion\")((\n assertion: ScriptedTurnHooks[\"assertRequest\"],\n request: LanguageModel.ProviderOptions,\n): Effect.Effect<void, AiError.AiError> => {\n if (assertion === undefined) {\n return Effect.void;\n }\n return Effect.suspend(() => {\n const result = assertion(request);\n return Effect.isEffect(result) ? result : Effect.void;\n });\n});\n\nconst takeTurn = Effect.fn(\"ScriptedModel.takeTurn\")(\n (\n state: Ref.Ref<ScriptState>,\n kind: ScriptedRequestKind,\n options: LanguageModel.ProviderOptions,\n ): Effect.Effect<ScriptedTurnInput, AiError.AiError> =>\n Ref.modify(state, (current) => {\n const turn = current.remaining[0];\n if (turn === undefined) {\n return [\n undefined,\n {\n ...current,\n requests: [...current.requests, { kind, options }],\n },\n ] as const;\n }\n return [\n turn,\n {\n remaining: current.remaining.slice(1),\n requests: [...current.requests, { kind, options }],\n },\n ] as const;\n }).pipe(\n Effect.flatMap((turn) =>\n turn === undefined\n ? Effect.fail(scriptedError(kind, `Script exhausted before the ${kind} request`))\n : Effect.succeed(turn),\n ),\n ),\n);\n\nconst requireGenerateTurn = (\n turn: ScriptedTurnInput,\n): Effect.Effect<ScriptedGenerateTurn & ScriptedTurnHooks, AiError.AiError> =>\n turn._tag === \"Generate\"\n ? Effect.succeed(turn)\n : Effect.fail(scriptedError(\"generate\", `Expected a Generate turn but found ${turn._tag}`));\n\nconst requireStreamTurn = (\n turn: ScriptedTurnInput,\n): Effect.Effect<ScriptedStreamTurn & ScriptedTurnHooks, AiError.AiError> =>\n turn._tag === \"Stream\"\n ? Effect.succeed(turn)\n : Effect.fail(scriptedError(\"stream\", `Expected a Stream turn but found ${turn._tag}`));\n\nconst streamForTurn = (\n turn: ScriptedStreamTurn & ScriptedTurnHooks,\n): Stream.Stream<Response.StreamPartEncoded, AiError.AiError> => {\n let stream: Stream.Stream<Response.StreamPartEncoded, AiError.AiError> = Stream.fromIterable(\n turn.parts,\n );\n switch (turn.termination._tag) {\n case \"Complete\": {\n break;\n }\n case \"Fail\": {\n stream = stream.pipe(\n Stream.concat(Stream.fail(scriptedError(\"stream\", turn.termination.description))),\n );\n break;\n }\n case \"Hang\": {\n stream = stream.pipe(Stream.concat(Stream.never));\n break;\n }\n }\n if (turn.onStreamStart !== undefined) {\n stream = Stream.fromEffectDrain(turn.onStreamStart).pipe(Stream.concat(stream));\n }\n if (turn.onStreamFinalize !== undefined) {\n stream = stream.pipe(Stream.ensuring(turn.onStreamFinalize));\n }\n return stream;\n};\n\n/** Inspection service for a deterministic LanguageModel backed by finite scripted turns. */\nexport class ScriptedModel extends Context.Service<\n ScriptedModel,\n {\n /** Normalized provider requests captured in invocation order. */\n readonly requests: Effect.Effect<ReadonlyArray<ScriptedRequest>>;\n /** Number of scripted turns not yet consumed. */\n readonly remaining: Effect.Effect<number>;\n /** Fails with `AiError` when any scripted turns remain. */\n readonly assertExhausted: Effect.Effect<void, AiError.AiError>;\n }\n>()(\"@effect-agent/testing/ScriptedModel\") {\n /**\n * Provides the native Effect AI `LanguageModel` and this inspection service.\n * Supplying the extra inspection service does not add it to model-call\n * requirements. Each model invocation consumes one turn before assertion and\n * turn-kind validation.\n */\n static layer(\n turns: ReadonlyArray<ScriptedTurnInput>,\n ): Layer.Layer<LanguageModel.LanguageModel | ScriptedModel, never, never> {\n return Layer.effectContext(\n Effect.gen(function* () {\n const state = yield* Ref.make<ScriptState>({\n remaining: [...turns],\n requests: [],\n });\n\n const languageModel = yield* LanguageModel.make({\n generateText: (options) =>\n Effect.gen(function* () {\n const turn = yield* takeTurn(state, \"generate\", options);\n yield* runAssertion(turn.assertRequest, options);\n const generateTurn = yield* requireGenerateTurn(turn);\n return [...generateTurn.parts];\n }),\n streamText: (options) =>\n Stream.unwrap(\n Effect.gen(function* () {\n const turn = yield* takeTurn(state, \"stream\", options);\n yield* runAssertion(turn.assertRequest, options);\n const streamTurn = yield* requireStreamTurn(turn);\n return streamForTurn(streamTurn);\n }),\n ),\n });\n\n const inspection = ScriptedModel.of({\n requests: Ref.get(state).pipe(Effect.map((current) => current.requests)),\n remaining: Ref.get(state).pipe(Effect.map((current) => current.remaining.length)),\n assertExhausted: Ref.get(state).pipe(\n Effect.flatMap((current) =>\n current.remaining.length === 0\n ? Effect.void\n : Effect.fail(\n scriptedError(\n \"assertExhausted\",\n `${current.remaining.length} scripted turn(s) remain`,\n ),\n ),\n ),\n ),\n });\n\n return Context.make(LanguageModel.LanguageModel, languageModel).pipe(\n Context.add(ScriptedModel, inspection),\n );\n }),\n );\n }\n}\n"],"mappings":";;;AAGA,MAAM,uBAAuB,OAAO,OAAO,OAAO,QAAQ,OAAO,OAAO,OAAO,IAAI,CAAC;AACpF,MAAM,mBAAmB,EACvB,UAAU,OAAO,YAAY,oBAAoB,EACnD;AACA,MAAM,uBAAuB,OAAO,OAAO;CACzC,GAAG;CACH,MAAM,OAAO,QAAQ,WAAW;CAChC,IAAI,OAAO;CACX,MAAM,OAAO;CACb,QAAQ,OAAO;CACf,kBAAkB,OAAO,YAAY,OAAO,OAAO;AACrD,CAAC;AACD,MAAM,yBAAyB,OAAO,OAAO;CAC3C,GAAG;CACH,MAAM,OAAO,QAAQ,aAAa;CAClC,IAAI,OAAO;CACX,MAAM,OAAO;CACb,QAAQ,OAAO;CACf,WAAW,OAAO;CAClB,kBAAkB,OAAO,YAAY,OAAO,OAAO;CACnD,aAAa,OAAO,YAAY,OAAO,OAAO;AAChD,CAAC;;;;;;;AAQD,MAAa,uBAAuB,OAAO,MAAM;CAC/C,OAAO,UAAU,SAAS,QAAQ;CAClC,OAAO,UAAU,SAAS,aAAa;CACvC,OAAO,UAAU,SAAS,kBAAkB;CAC5C,OAAO,UAAU,SAAS,gBAAgB;CAC1C;CACA;CACA,OAAO,UAAU,SAAS,uBAAuB;CACjD,OAAO,UAAU,SAAS,QAAQ;CAClC,OAAO,UAAU,SAAS,kBAAkB;CAC5C,OAAO,UAAU,SAAS,aAAa;CACvC,OAAO,UAAU,SAAS,oBAAoB;CAC9C,OAAO,UAAU,SAAS,UAAU;AACtC,CAAC,CAAC,CAAC,SAAS,EAAE,YAAY,uBAAuB,CAAC;;;;AAMlD,MAAa,qBAAqB,OAAO,MAAM;CAC7C,OAAO,UAAU,SAAS,aAAa;CACvC,OAAO,UAAU,SAAS,aAAa;CACvC,OAAO,UAAU,SAAS,WAAW;CACrC,OAAO,UAAU,SAAS,kBAAkB;CAC5C,OAAO,UAAU,SAAS,kBAAkB;CAC5C,OAAO,UAAU,SAAS,gBAAgB;CAC1C,OAAO,UAAU,SAAS,mBAAmB;CAC7C,OAAO,UAAU,SAAS,mBAAmB;CAC7C,OAAO,UAAU,SAAS,iBAAiB;CAC3C;CACA;CACA,OAAO,UAAU,SAAS,uBAAuB;CACjD,OAAO,UAAU,SAAS,QAAQ;CAClC,OAAO,UAAU,SAAS,kBAAkB;CAC5C,OAAO,UAAU,SAAS,aAAa;CACvC,OAAO,UAAU,SAAS,oBAAoB;CAC9C,OAAO,UAAU,SAAS,UAAU;CACpC,OAAO,UAAU,SAAS,SAAS;AACrC,CAAC,CAAC,CAAC,SAAS,EAAE,YAAY,qBAAqB,CAAC;;AAIhD,MAAa,4BAA4B,OAAO,MAAM;CACpD,OAAO,aAAa,YAAY,CAAC,CAAC;CAClC,OAAO,aAAa,QAAQ,EAC1B,aAAa,OAAO,OACtB,CAAC;CACD,OAAO,aAAa,QAAQ,CAAC,CAAC;AAChC,CAAC;;AAID,MAAa,uBAAuB,OAAO,aAAa,YAAY,EAClE,OAAO,OAAO,MAAM,oBAAoB,EAC1C,CAAC;;AAID,MAAa,qBAAqB,OAAO,aAAa,UAAU;CAC9D,OAAO,OAAO,MAAM,kBAAkB;CACtC,aAAa;AACf,CAAC;;;;AAMD,MAAa,eAAe,OAAO,MAAM,CAAC,sBAAsB,kBAAkB,CAAC;AAoCnF,MAAM,iBAAiB,QAAgB,gBACrC,QAAQ,QAAQ,KAAK;CACnB,QAAQ;CACR;CACA,QAAQ,QAAQ,aAAa,KAAK,EAAE,YAAY,CAAC;AACnD,CAAC;AAEH,MAAM,eAAe,OAAO,GAAG,4BAA4B,CAAC,EAC1D,WACA,YACyC;CACzC,IAAI,cAAc,KAAA,GAChB,OAAO,OAAO;CAEhB,OAAO,OAAO,cAAc;EAC1B,MAAM,SAAS,UAAU,OAAO;EAChC,OAAO,OAAO,SAAS,MAAM,IAAI,SAAS,OAAO;CACnD,CAAC;AACH,CAAC;AAED,MAAM,WAAW,OAAO,GAAG,wBAAwB,CAAC,EAEhD,OACA,MACA,YAEA,IAAI,OAAO,QAAQ,YAAY;CAC7B,MAAM,OAAO,QAAQ,UAAU;CAC/B,IAAI,SAAS,KAAA,GACX,OAAO,CACL,KAAA,GACA;EACE,GAAG;EACH,UAAU,CAAC,GAAG,QAAQ,UAAU;GAAE;GAAM;EAAQ,CAAC;CACnD,CACF;CAEF,OAAO,CACL,MACA;EACE,WAAW,QAAQ,UAAU,MAAM,CAAC;EACpC,UAAU,CAAC,GAAG,QAAQ,UAAU;GAAE;GAAM;EAAQ,CAAC;CACnD,CACF;AACF,CAAC,CAAC,CAAC,KACD,OAAO,SAAS,SACd,SAAS,KAAA,IACL,OAAO,KAAK,cAAc,MAAM,+BAA+B,KAAK,SAAS,CAAC,IAC9E,OAAO,QAAQ,IAAI,CACzB,CACF,CACJ;AAEA,MAAM,uBACJ,SAEA,KAAK,SAAS,aACV,OAAO,QAAQ,IAAI,IACnB,OAAO,KAAK,cAAc,YAAY,sCAAsC,KAAK,MAAM,CAAC;AAE9F,MAAM,qBACJ,SAEA,KAAK,SAAS,WACV,OAAO,QAAQ,IAAI,IACnB,OAAO,KAAK,cAAc,UAAU,oCAAoC,KAAK,MAAM,CAAC;AAE1F,MAAM,iBACJ,SAC+D;CAC/D,IAAI,SAAqE,OAAO,aAC9E,KAAK,KACP;CACA,QAAQ,KAAK,YAAY,MAAzB;EACE,KAAK,YACH;EAEF,KAAK;GACH,SAAS,OAAO,KACd,OAAO,OAAO,OAAO,KAAK,cAAc,UAAU,KAAK,YAAY,WAAW,CAAC,CAAC,CAClF;GACA;EAEF,KAAK,QACH,SAAS,OAAO,KAAK,OAAO,OAAO,OAAO,KAAK,CAAC;CAGpD;CACA,IAAI,KAAK,kBAAkB,KAAA,GACzB,SAAS,OAAO,gBAAgB,KAAK,aAAa,CAAC,CAAC,KAAK,OAAO,OAAO,MAAM,CAAC;CAEhF,IAAI,KAAK,qBAAqB,KAAA,GAC5B,SAAS,OAAO,KAAK,OAAO,SAAS,KAAK,gBAAgB,CAAC;CAE7D,OAAO;AACT;;AAGA,IAAa,gBAAb,MAAa,sBAAsB,QAAQ,QAUzC,CAAC,CAAC,qCAAqC,CAAC,CAAC;;;;;;;CAOzC,OAAO,MACL,OACwE;EACxE,OAAO,MAAM,cACX,OAAO,IAAI,aAAa;GACtB,MAAM,QAAQ,OAAO,IAAI,KAAkB;IACzC,WAAW,CAAC,GAAG,KAAK;IACpB,UAAU,CAAC;GACb,CAAC;GAED,MAAM,gBAAgB,OAAO,cAAc,KAAK;IAC9C,eAAe,YACb,OAAO,IAAI,aAAa;KACtB,MAAM,OAAO,OAAO,SAAS,OAAO,YAAY,OAAO;KACvD,OAAO,aAAa,KAAK,eAAe,OAAO;KAE/C,OAAO,CAAC,IAAG,OADiB,oBAAoB,IAAI,EAAA,CAC5B,KAAK;IAC/B,CAAC;IACH,aAAa,YACX,OAAO,OACL,OAAO,IAAI,aAAa;KACtB,MAAM,OAAO,OAAO,SAAS,OAAO,UAAU,OAAO;KACrD,OAAO,aAAa,KAAK,eAAe,OAAO;KAC/C,MAAM,aAAa,OAAO,kBAAkB,IAAI;KAChD,OAAO,cAAc,UAAU;IACjC,CAAC,CACH;GACJ,CAAC;GAED,MAAM,aAAa,cAAc,GAAG;IAClC,UAAU,IAAI,IAAI,KAAK,CAAC,CAAC,KAAK,OAAO,KAAK,YAAY,QAAQ,QAAQ,CAAC;IACvE,WAAW,IAAI,IAAI,KAAK,CAAC,CAAC,KAAK,OAAO,KAAK,YAAY,QAAQ,UAAU,MAAM,CAAC;IAChF,iBAAiB,IAAI,IAAI,KAAK,CAAC,CAAC,KAC9B,OAAO,SAAS,YACd,QAAQ,UAAU,WAAW,IACzB,OAAO,OACP,OAAO,KACL,cACE,mBACA,GAAG,QAAQ,UAAU,OAAO,yBAC9B,CACF,CACN,CACF;GACF,CAAC;GAED,OAAO,QAAQ,KAAK,cAAc,eAAe,aAAa,CAAC,CAAC,KAC9D,QAAQ,IAAI,eAAe,UAAU,CACvC;EACF,CAAC,CACH;CACF;AACF"}
|
|
1
|
+
{"version":3,"file":"scripted-model-C2y0ztuj.mjs","names":[],"sources":["../src/scripted-model.ts"],"sourcesContent":["import { Context, Effect, Layer, Ref, Schema, Stream } from \"effect\";\nimport { AiError, LanguageModel, Response } from \"effect/unstable/ai\";\n\nconst ScriptedPartMetadata = Schema.Record(Schema.String, Schema.NullOr(Schema.Json));\n\nconst ScriptedPartBase = {\n metadata: Schema.optionalKey(ScriptedPartMetadata),\n};\n\nconst ScriptedToolCallPart = Schema.Struct({\n ...ScriptedPartBase,\n type: Schema.Literal(\"tool-call\"),\n id: Schema.String,\n name: Schema.String,\n params: Schema.Unknown,\n providerExecuted: Schema.optionalKey(Schema.Boolean),\n});\n\nconst ScriptedToolResultPart = Schema.Struct({\n ...ScriptedPartBase,\n type: Schema.Literal(\"tool-result\"),\n id: Schema.String,\n name: Schema.String,\n result: Schema.Unknown,\n isFailure: Schema.Boolean,\n providerExecuted: Schema.optionalKey(Schema.Boolean),\n preliminary: Schema.optionalKey(Schema.Boolean),\n});\n\n/**\n * Schema for encoded, non-streaming Effect AI response parts.\n *\n * Generic Tool payloads remain explicitly unknown here. `LanguageModel.make`\n * performs the toolkit-specific decode when the scripted response is consumed.\n */\nexport const ScriptedGeneratePart = Schema.Union([\n Schema.toEncoded(Response.TextPart),\n Schema.toEncoded(Response.ReasoningPart),\n Schema.toEncoded(Response.ReasoningDeltaPart),\n Schema.toEncoded(Response.ReasoningEndPart),\n ScriptedToolCallPart,\n ScriptedToolResultPart,\n Schema.toEncoded(Response.ToolApprovalRequestPart),\n Schema.toEncoded(Response.FilePart),\n Schema.toEncoded(Response.DocumentSourcePart),\n Schema.toEncoded(Response.UrlSourcePart),\n Schema.toEncoded(Response.ResponseMetadataPart),\n Schema.toEncoded(Response.FinishPart),\n]).annotate({ identifier: \"ScriptedGeneratePart\" });\n\nexport type ScriptedGeneratePart = typeof ScriptedGeneratePart.Type;\n\n/**\n * Schema for encoded Effect AI streaming response parts.\n */\nexport const ScriptedStreamPart = Schema.Union([\n Schema.toEncoded(Response.TextStartPart),\n Schema.toEncoded(Response.TextDeltaPart),\n Schema.toEncoded(Response.TextEndPart),\n Schema.toEncoded(Response.ReasoningStartPart),\n Schema.toEncoded(Response.ReasoningDeltaPart),\n Schema.toEncoded(Response.ReasoningEndPart),\n Schema.toEncoded(Response.ToolParamsStartPart),\n Schema.toEncoded(Response.ToolParamsDeltaPart),\n Schema.toEncoded(Response.ToolParamsEndPart),\n ScriptedToolCallPart,\n ScriptedToolResultPart,\n Schema.toEncoded(Response.ToolApprovalRequestPart),\n Schema.toEncoded(Response.FilePart),\n Schema.toEncoded(Response.DocumentSourcePart),\n Schema.toEncoded(Response.UrlSourcePart),\n Schema.toEncoded(Response.ResponseMetadataPart),\n Schema.toEncoded(Response.FinishPart),\n Schema.toEncoded(Response.ErrorPart),\n]).annotate({ identifier: \"ScriptedStreamPart\" });\n\nexport type ScriptedStreamPart = typeof ScriptedStreamPart.Type;\n\n/** Controls whether a scripted stream completes, fails, or waits for interruption. */\nexport const ScriptedStreamTermination = Schema.Union([\n Schema.TaggedStruct(\"Complete\", {}),\n Schema.TaggedStruct(\"Fail\", {\n description: Schema.String,\n }),\n Schema.TaggedStruct(\"Hang\", {}),\n]);\n\nexport type ScriptedStreamTermination = typeof ScriptedStreamTermination.Type;\n\n/** One non-streaming invocation and the encoded response parts it returns. */\nexport const ScriptedGenerateTurn = Schema.TaggedStruct(\"Generate\", {\n parts: Schema.Array(ScriptedGeneratePart),\n});\n\nexport type ScriptedGenerateTurn = typeof ScriptedGenerateTurn.Type;\n\n/** One streaming invocation with its encoded parts and terminal behavior. */\nexport const ScriptedStreamTurn = Schema.TaggedStruct(\"Stream\", {\n parts: Schema.Array(ScriptedStreamPart),\n termination: ScriptedStreamTermination,\n});\n\nexport type ScriptedStreamTurn = typeof ScriptedStreamTurn.Type;\n\n/**\n * Serializable grammar for one finite scripted provider invocation.\n */\nexport const ScriptedTurn = Schema.Union([ScriptedGenerateTurn, ScriptedStreamTurn]);\nexport type ScriptedTurn = typeof ScriptedTurn.Type;\n\nexport type ScriptedRequestKind = \"generate\" | \"stream\";\n\n/**\n * A request after Effect AI has normalized its prompt, tools, response format,\n * tool choice, span, and incremental-response fields.\n */\nexport interface ScriptedRequest {\n readonly kind: ScriptedRequestKind;\n readonly options: LanguageModel.ProviderOptions;\n}\n\n/** Optional request assertions and stream lifecycle effects for one scripted turn. */\nexport interface ScriptedTurnHooks {\n /** Runs against the normalized provider request before producing the response. */\n readonly assertRequest?: (\n request: LanguageModel.ProviderOptions,\n ) => Effect.Effect<void, AiError.AiError> | void;\n /** Runs immediately before the scripted stream begins emitting parts. */\n readonly onStreamStart?: Effect.Effect<void> | undefined;\n /** Runs when the scripted stream completes, fails, or is interrupted. */\n readonly onStreamFinalize?: Effect.Effect<void> | undefined;\n}\n\n/**\n * Runtime hooks are deliberately separate from the serializable turn grammar.\n */\nexport type ScriptedTurnInput = ScriptedTurn & ScriptedTurnHooks;\n\ninterface ScriptState {\n readonly remaining: ReadonlyArray<ScriptedTurnInput>;\n readonly requests: ReadonlyArray<ScriptedRequest>;\n}\n\nconst scriptedError = (method: string, description: string): AiError.AiError =>\n AiError.AiError.make({\n module: \"@effect-agent/testing/ScriptedModel\",\n method,\n reason: AiError.UnknownError.make({ description }),\n });\n\nconst runAssertion = Effect.fn(\"ScriptedModel.runAssertion\")((\n assertion: ScriptedTurnHooks[\"assertRequest\"],\n request: LanguageModel.ProviderOptions,\n): Effect.Effect<void, AiError.AiError> => {\n if (assertion === undefined) {\n return Effect.void;\n }\n\n return Effect.suspend(() => {\n const result = assertion(request);\n\n return Effect.isEffect(result) ? result : Effect.void;\n });\n});\n\nconst takeTurn = Effect.fn(\"ScriptedModel.takeTurn\")(\n (\n state: Ref.Ref<ScriptState>,\n kind: ScriptedRequestKind,\n options: LanguageModel.ProviderOptions,\n ): Effect.Effect<ScriptedTurnInput, AiError.AiError> =>\n Ref.modify(state, (current) => {\n const turn = current.remaining[0];\n\n if (turn === undefined) {\n return [\n undefined,\n {\n ...current,\n requests: [...current.requests, { kind, options }],\n },\n ] as const;\n }\n\n return [\n turn,\n {\n remaining: current.remaining.slice(1),\n requests: [...current.requests, { kind, options }],\n },\n ] as const;\n }).pipe(\n Effect.flatMap((turn) =>\n turn === undefined\n ? Effect.fail(scriptedError(kind, `Script exhausted before the ${kind} request`))\n : Effect.succeed(turn),\n ),\n ),\n);\n\nconst requireGenerateTurn = (\n turn: ScriptedTurnInput,\n): Effect.Effect<ScriptedGenerateTurn & ScriptedTurnHooks, AiError.AiError> =>\n turn._tag === \"Generate\"\n ? Effect.succeed(turn)\n : Effect.fail(scriptedError(\"generate\", `Expected a Generate turn but found ${turn._tag}`));\n\nconst requireStreamTurn = (\n turn: ScriptedTurnInput,\n): Effect.Effect<ScriptedStreamTurn & ScriptedTurnHooks, AiError.AiError> =>\n turn._tag === \"Stream\"\n ? Effect.succeed(turn)\n : Effect.fail(scriptedError(\"stream\", `Expected a Stream turn but found ${turn._tag}`));\n\nconst streamForTurn = (\n turn: ScriptedStreamTurn & ScriptedTurnHooks,\n): Stream.Stream<Response.StreamPartEncoded, AiError.AiError> => {\n let stream: Stream.Stream<Response.StreamPartEncoded, AiError.AiError> = Stream.fromIterable(\n turn.parts,\n );\n\n switch (turn.termination._tag) {\n case \"Complete\": {\n break;\n }\n case \"Fail\": {\n stream = stream.pipe(\n Stream.concat(Stream.fail(scriptedError(\"stream\", turn.termination.description))),\n );\n break;\n }\n case \"Hang\": {\n stream = stream.pipe(Stream.concat(Stream.never));\n break;\n }\n }\n if (turn.onStreamStart !== undefined) {\n stream = Stream.fromEffectDrain(turn.onStreamStart).pipe(Stream.concat(stream));\n }\n if (turn.onStreamFinalize !== undefined) {\n stream = stream.pipe(Stream.ensuring(turn.onStreamFinalize));\n }\n\n return stream;\n};\n\n/** Inspection service for a deterministic LanguageModel backed by finite scripted turns. */\nexport class ScriptedModel extends Context.Service<\n ScriptedModel,\n {\n /** Normalized provider requests captured in invocation order. */\n readonly requests: Effect.Effect<ReadonlyArray<ScriptedRequest>>;\n /** Number of scripted turns not yet consumed. */\n readonly remaining: Effect.Effect<number>;\n /** Fails with `AiError` when any scripted turns remain. */\n readonly assertExhausted: Effect.Effect<void, AiError.AiError>;\n }\n>()(\"@effect-agent/testing/ScriptedModel\") {\n /**\n * Provides the native Effect AI `LanguageModel` and this inspection service.\n * Supplying the extra inspection service does not add it to model-call\n * requirements. Each model invocation consumes one turn before assertion and\n * turn-kind validation.\n */\n static layer(\n turns: ReadonlyArray<ScriptedTurnInput>,\n ): Layer.Layer<LanguageModel.LanguageModel | ScriptedModel, never, never> {\n return Layer.effectContext(\n Effect.gen(function* () {\n const state = yield* Ref.make<ScriptState>({\n remaining: [...turns],\n requests: [],\n });\n\n const languageModel = yield* LanguageModel.make({\n generateText: (options) =>\n Effect.gen(function* () {\n const turn = yield* takeTurn(state, \"generate\", options);\n\n yield* runAssertion(turn.assertRequest, options);\n const generateTurn = yield* requireGenerateTurn(turn);\n\n return [...generateTurn.parts];\n }),\n streamText: (options) =>\n Stream.unwrap(\n Effect.gen(function* () {\n const turn = yield* takeTurn(state, \"stream\", options);\n\n yield* runAssertion(turn.assertRequest, options);\n const streamTurn = yield* requireStreamTurn(turn);\n\n return streamForTurn(streamTurn);\n }),\n ),\n });\n\n const inspection = ScriptedModel.of({\n requests: Ref.get(state).pipe(Effect.map((current) => current.requests)),\n remaining: Ref.get(state).pipe(Effect.map((current) => current.remaining.length)),\n assertExhausted: Ref.get(state).pipe(\n Effect.flatMap((current) =>\n current.remaining.length === 0\n ? Effect.void\n : Effect.fail(\n scriptedError(\n \"assertExhausted\",\n `${current.remaining.length} scripted turn(s) remain`,\n ),\n ),\n ),\n ),\n });\n\n return Context.make(LanguageModel.LanguageModel, languageModel).pipe(\n Context.add(ScriptedModel, inspection),\n );\n }),\n );\n }\n}\n"],"mappings":"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"}
|
|
@@ -1747,7 +1747,7 @@ interface DurableResearchHarnessOptions {
|
|
|
1747
1747
|
}
|
|
1748
1748
|
/** One durable coordinator/researcher pair with observable invocation counters. */
|
|
1749
1749
|
interface DurableResearchHarness {
|
|
1750
|
-
/** Host registrations for `
|
|
1750
|
+
/** Host registrations for `NodeDurableAgentRuntimeOptions.bindings` (parent + child). */
|
|
1751
1751
|
readonly bindings: ReadonlyArray<ResolvedBinding>;
|
|
1752
1752
|
/** Total coordinator model invocations across every Attempt and runtime handle. */
|
|
1753
1753
|
readonly parentModelCalls: Effect.Effect<number>;
|
|
@@ -1767,7 +1767,7 @@ interface DurableResearchHarness {
|
|
|
1767
1767
|
* guide, Turn 2 writes the report), and both worker Bindings captured with
|
|
1768
1768
|
* their requirement Contexts via `DurableWorkerBinding.make` under the exact
|
|
1769
1769
|
* fixture digests. The returned `bindings` are plain values: they can be
|
|
1770
|
-
* registered with several `
|
|
1770
|
+
* registered with several `NodeDurableAgentRuntime` stacks over the same SQLite
|
|
1771
1771
|
* file while the counters keep counting across all of them.
|
|
1772
1772
|
*/
|
|
1773
1773
|
declare const makeDurableResearchHarness: (options?: DurableResearchHarnessOptions) => Effect.Effect<DurableResearchHarness, never, never>;
|
package/dist/travel-planner.mjs
CHANGED
|
@@ -1232,7 +1232,7 @@ const durableDestinationResearchHandlersLayer = (childBinding) => SubagentRuntim
|
|
|
1232
1232
|
* guide, Turn 2 writes the report), and both worker Bindings captured with
|
|
1233
1233
|
* their requirement Contexts via `DurableWorkerBinding.make` under the exact
|
|
1234
1234
|
* fixture digests. The returned `bindings` are plain values: they can be
|
|
1235
|
-
* registered with several `
|
|
1235
|
+
* registered with several `NodeDurableAgentRuntime` stacks over the same SQLite
|
|
1236
1236
|
* file while the counters keep counting across all of them.
|
|
1237
1237
|
*/
|
|
1238
1238
|
const makeDurableResearchHarness = (options) => Effect.gen(function* () {
|