@effect-agent/testing 0.1.0-beta.85 → 0.1.0-beta.87

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (39) hide show
  1. package/dist/Certification.d.mts +12 -11
  2. package/dist/Certification.mjs +77 -40
  3. package/dist/Certification.mjs.map +1 -1
  4. package/dist/Chaos.d.mts +5 -5
  5. package/dist/Chaos.mjs +20 -20
  6. package/dist/Chaos.mjs.map +1 -1
  7. package/dist/CodeExecutorConformance.d.mts +2 -2
  8. package/dist/CodeExecutorConformance.mjs +2 -2
  9. package/dist/CodeExecutorConformance.mjs.map +1 -1
  10. package/dist/CodeExecutorSubstitute.d.mts +2 -2
  11. package/dist/CodeExecutorSubstitute.mjs +2 -2
  12. package/dist/CodeExecutorSubstitute.mjs.map +1 -1
  13. package/dist/DocsResearcher.d.mts +14 -14
  14. package/dist/DocsResearcher.mjs +15 -15
  15. package/dist/DocsResearcher.mjs.map +1 -1
  16. package/dist/TravelPlanner.d.mts +20 -21
  17. package/dist/TravelPlanner.mjs +18 -18
  18. package/dist/TravelPlanner.mjs.map +1 -1
  19. package/dist/{deterministic-layers-Eka0fMZq.mjs → deterministic-layers-D5owIoke.mjs} +8 -8
  20. package/dist/deterministic-layers-D5owIoke.mjs.map +1 -0
  21. package/package.json +1 -1
  22. package/src/Certification.ts +149 -97
  23. package/src/Chaos.ts +21 -31
  24. package/src/CodeExecutorConformance.ts +3 -3
  25. package/src/CodeExecutorSubstitute.ts +3 -3
  26. package/src/fixtures/docs-researcher/definition.ts +6 -6
  27. package/src/fixtures/docs-researcher/harness.ts +9 -13
  28. package/src/fixtures/docs-researcher/mcp.ts +3 -3
  29. package/src/fixtures/travel-planner/definition.ts +2 -2
  30. package/src/fixtures/travel-planner/deterministic-layers.ts +5 -5
  31. package/src/fixtures/travel-planner/phase2.ts +2 -2
  32. package/src/fixtures/travel-planner/phase3.ts +5 -5
  33. package/src/fixtures/travel-planner/phase4.ts +8 -8
  34. package/src/fixtures/travel-planner/phase5.ts +9 -13
  35. package/src/fixtures/travel-planner/phase6.ts +7 -7
  36. package/src/fixtures/travel-planner/subagents-durable.ts +11 -13
  37. package/src/fixtures/travel-planner/subagents.ts +6 -6
  38. package/src/internal/certification-report.ts +25 -0
  39. package/dist/deterministic-layers-Eka0fMZq.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"CodeExecutorSubstitute.mjs","names":[],"sources":["../src/CodeExecutorSubstitute.ts"],"sourcesContent":["import {\n CodeExecutionHost,\n CodeExecutionProtocolError,\n CodeExecutionResourceUse,\n CodeExecutionResult,\n CodeExecutionTimeoutError,\n CodeExecutor,\n type CodeExecutorExecute,\n CodeExecutorUnsupportedError,\n CodeHostCall,\n CodeHostCallLimitError,\n CodeHostCallResult,\n CodeOutputLimitError,\n CodeProgramFailedError,\n CodeSourceError,\n type CodeExecutionLimits,\n type CodeExecutionNamespace,\n type CodeExecutionRequest,\n} from \"@effect-agent/sandbox/CodeExecutor\";\nimport { SandboxImplementation } from \"@effect-agent/sandbox/Sandbox\";\nimport { Clock, Duration, Effect, Fiber, Layer, Option, Queue, Schema } from \"effect\";\n\n/**\n * The deterministic in-process executor substitute (C1 of ADR-0017). It runs\n * the generated program on the host JavaScript engine with best-effort global\n * shadowing only, so it self-identifies as `unisolated` and is never a\n * security boundary (CAP-010, CAP-015). It exists to prove the public\n * `CodeExecutor` contract and to drive deterministic capability tests.\n */\nexport const inProcessCodeExecutorImplementation = SandboxImplementation.make({\n isolation: \"unisolated\",\n identity: \"in-process-javascript\",\n});\n\n// These two caps mirror the wire schema bounds (`BoundedLogs` is at most\n// 4096 lines of at most 16 KiB each): capture must stay inside what\n// `CodeExecutionResult` can carry. A line over the per-line cap is truncated\n// with an explicit `…` marker; exceeding either the byte budget or the line\n// cap fails the pass typed.\nconst MAX_LOG_LINES = 4_096;\nconst MAX_LOG_LINE_CHARACTERS = 16_000;\nconst MAX_THROWN_CHARACTERS = 4_000;\n\nconst utf8ByteLength = (value: string): number => new TextEncoder().encode(value).byteLength;\n\n/**\n * Ambient globals shadowed inside the harness. Shadowing blocks the obvious\n * identifier paths only; a determined program can still escape, which is\n * exactly why this executor reports `unisolated` and the isolated network and\n * CPU enforcement conformance cases run only against isolated adapters.\n */\nconst shadowedGlobals = [\n \"fetch\",\n \"process\",\n \"require\",\n \"module\",\n \"exports\",\n \"global\",\n \"globalThis\",\n \"XMLHttpRequest\",\n \"WebSocket\",\n \"Deno\",\n \"Bun\",\n] as const;\n\nclass LogLimitSignal {\n constructor(readonly observed: number) {}\n}\n\nclass EvaluationThrew {\n constructor(readonly inner: unknown) {}\n}\n\nclass NotAFunction {\n constructor(readonly actual: string) {}\n}\n\ninterface LogCapture {\n readonly lines: Array<string>;\n bytes: number;\n}\n\n/**\n * Total, defect-free rendering of untrusted values: a hostile Proxy can throw\n * from property access, `toString`, and `Symbol.toPrimitive`, and an expected\n * program failure must never escape the typed channel as a defect while its\n * diagnostics are being serialized.\n */\nconst formatLogValue = (value: unknown): string => {\n try {\n if (typeof value === \"string\") {\n return value;\n }\n\n return JSON.stringify(value) ?? String(value);\n } catch {\n try {\n return String(value);\n } catch {\n return \"[unprintable value]\";\n }\n }\n};\n\nconst makeConsole = (capture: LogCapture, limits: CodeExecutionLimits) => {\n const write = (...values: ReadonlyArray<unknown>): void => {\n const joined = values.map(formatLogValue).join(\" \");\n\n const line =\n joined.length > MAX_LOG_LINE_CHARACTERS\n ? `${joined.slice(0, MAX_LOG_LINE_CHARACTERS - 1)}…`\n : joined;\n\n const bytes = utf8ByteLength(line);\n\n if (capture.lines.length >= MAX_LOG_LINES || capture.bytes + bytes > limits.maxLogBytes) {\n throw new LogLimitSignal(capture.bytes + bytes);\n }\n capture.lines.push(line);\n capture.bytes += bytes;\n };\n\n return { debug: write, error: write, info: write, log: write, warn: write };\n};\n\ninterface PendingHostCall {\n readonly namespace: string;\n readonly method: string;\n readonly argument: unknown;\n readonly resolve: (value: unknown) => void;\n readonly reject: (reason: unknown) => void;\n}\n\nconst buildNamespaceObject = (\n namespace: CodeExecutionNamespace,\n offer: (pending: PendingHostCall) => void,\n): Record<string, unknown> => {\n const methods: Record<string, unknown> = {};\n\n for (const method of namespace.methods) {\n methods[method] = (argument: unknown) =>\n new Promise((resolve, reject) => {\n offer({ namespace: namespace.name, method, argument, resolve, reject });\n });\n }\n\n return methods;\n};\n\nconst boundedText = (value: unknown): string => {\n try {\n const text = value instanceof Error ? `${value.name}: ${value.message}` : formatLogValue(value);\n\n return text.slice(0, MAX_THROWN_CHARACTERS);\n } catch {\n return \"[unserializable thrown value]\";\n }\n};\n\n/** Schema decoding of hostile values may itself throw through trap getters. */\nconst safeDecodeJson = (value: unknown): Option.Option<Schema.Json> => {\n try {\n return Schema.decodeUnknownOption(Schema.Json)(value);\n } catch {\n return Option.none();\n }\n};\n\nconst decodeJsonText = Schema.decodeUnknownOption(Schema.fromJsonString(Schema.Json));\n\n/** Own serialized result text before bounding and decoding its detached JSON snapshot. */\nconst serializeJson = (value: unknown): Option.Option<string> => {\n const decoded = safeDecodeJson(value);\n\n if (Option.isNone(decoded)) return Option.none();\n try {\n return Option.fromUndefinedOr(JSON.stringify(decoded.value));\n } catch {\n return Option.none();\n }\n};\n\nconst boundedThrown = (value: unknown): Schema.Json => {\n const decoded = safeDecodeJson(value);\n\n if (Option.isSome(decoded)) {\n try {\n const encoded = JSON.stringify(decoded.value);\n\n if (encoded !== undefined && encoded.length <= MAX_THROWN_CHARACTERS) {\n const snapshot = decodeJsonText(encoded);\n\n if (Option.isSome(snapshot)) return snapshot.value;\n }\n } catch {\n // fall through to the bounded string form\n }\n }\n\n return boundedText(value);\n};\n\nconst encodedJsonByteLength = (value: Schema.Json): number | undefined => {\n try {\n const encoded = JSON.stringify(value);\n\n return encoded === undefined ? undefined : utf8ByteLength(encoded);\n } catch {\n return undefined;\n }\n};\n\n/** Host outcomes are protocol input; a hostile value must not defect mid-decode. */\nconst decodeHostOutcome = (value: unknown): Option.Option<CodeHostCallResult> => {\n try {\n return Schema.decodeUnknownOption(CodeHostCallResult)(value);\n } catch {\n return Option.none();\n }\n};\n\nconst validateRequest = (\n request: CodeExecutionRequest,\n): Effect.Effect<void, CodeExecutorUnsupportedError | CodeSourceError> =>\n Effect.gen(function* () {\n if (request.network._tag !== \"NetworkDisabled\") {\n return yield* CodeExecutorUnsupportedError.make({\n implementation: inProcessCodeExecutorImplementation,\n feature: \"network\",\n message:\n \"The unisolated in-process executor cannot enforce an egress allowlist; only NetworkDisabled is accepted, and even that is shadowed rather than enforced\",\n });\n }\n if (request.limits.cpuMillis !== undefined) {\n return yield* CodeExecutorUnsupportedError.make({\n implementation: inProcessCodeExecutorImplementation,\n feature: \"cpu-limit\",\n message:\n \"The unisolated in-process executor shares the host engine and cannot enforce a CPU limit\",\n });\n }\n const reservedNames = new Set<string>([...shadowedGlobals, \"console\"]);\n const seen = new Set<string>();\n\n for (const namespace of request.namespaces) {\n if (reservedNames.has(namespace.name) || seen.has(namespace.name)) {\n return yield* CodeExecutorUnsupportedError.make({\n implementation: inProcessCodeExecutorImplementation,\n feature: \"namespaces\",\n message: `Namespace ${namespace.name} collides with a harness binding or another namespace`,\n });\n }\n seen.add(namespace.name);\n }\n const sourceBytes = utf8ByteLength(request.source);\n\n if (sourceBytes > request.limits.maxSourceBytes) {\n return yield* CodeSourceError.make({\n implementation: inProcessCodeExecutorImplementation,\n reason: \"oversized\",\n message: `Source is ${sourceBytes} bytes; the request allows ${request.limits.maxSourceBytes}`,\n });\n }\n });\n\nconst serveHostCalls = (\n host: CodeExecutionHost[\"Service\"],\n queue: Queue.Queue<PendingHostCall>,\n limits: CodeExecutionLimits,\n capture: LogCapture,\n counter: { calls: number },\n): Effect.Effect<\n never,\n CodeHostCallLimitError | CodeOutputLimitError | CodeExecutionProtocolError\n> =>\n Effect.gen(function* () {\n while (true) {\n const pending = yield* Queue.take(queue);\n\n counter.calls += 1;\n if (counter.calls > limits.maxHostCalls) {\n return yield* CodeHostCallLimitError.make({\n implementation: inProcessCodeExecutorImplementation,\n limit: limits.maxHostCalls,\n logs: [...capture.lines],\n });\n }\n const argument = safeDecodeJson(pending.argument);\n\n if (Option.isNone(argument)) {\n pending.reject(new TypeError(\"host call arguments must be JSON values\"));\n continue;\n }\n const argumentBytes = encodedJsonByteLength(argument.value);\n\n if (argumentBytes === undefined || argumentBytes > limits.maxHostCallArgumentBytes) {\n return yield* CodeOutputLimitError.make({\n implementation: inProcessCodeExecutorImplementation,\n surface: \"host-call-argument\",\n limit: limits.maxHostCallArgumentBytes,\n observed: argumentBytes ?? 0,\n logs: [...capture.lines],\n });\n }\n\n const rawOutcome = yield* host.call(\n CodeHostCall.make({\n namespace: pending.namespace,\n method: pending.method,\n argument: argument.value,\n }),\n );\n\n const outcome = decodeHostOutcome(rawOutcome);\n\n if (Option.isNone(outcome)) {\n return yield* CodeExecutionProtocolError.make({\n implementation: inProcessCodeExecutorImplementation,\n message: \"The execution host returned a value outside the CodeHostCallResult schema\",\n });\n }\n if (outcome.value._tag === \"CodeHostCallFailure\") {\n pending.reject(outcome.value.error);\n continue;\n }\n const resultBytes = encodedJsonByteLength(outcome.value.value);\n\n if (resultBytes === undefined || resultBytes > limits.maxHostCallResultBytes) {\n return yield* CodeOutputLimitError.make({\n implementation: inProcessCodeExecutorImplementation,\n surface: \"host-call-result\",\n limit: limits.maxHostCallResultBytes,\n observed: resultBytes ?? 0,\n logs: [...capture.lines],\n });\n }\n pending.resolve(outcome.value.value);\n }\n });\n\nconst classifyProgramFailure = (\n thrown: unknown,\n limits: CodeExecutionLimits,\n capture: LogCapture,\n): CodeOutputLimitError | CodeSourceError | CodeProgramFailedError => {\n let inner = thrown;\n let reason: \"threw\" | \"rejected\" = \"rejected\";\n\n try {\n const evaluationThrew = thrown instanceof EvaluationThrew;\n\n inner = evaluationThrew ? thrown.inner : thrown;\n if (inner instanceof LogLimitSignal) {\n return CodeOutputLimitError.make({\n implementation: inProcessCodeExecutorImplementation,\n surface: \"logs\",\n limit: limits.maxLogBytes,\n observed: inner.observed,\n logs: [...capture.lines],\n });\n }\n if (inner instanceof NotAFunction) {\n return CodeSourceError.make({\n implementation: inProcessCodeExecutorImplementation,\n reason: \"not-a-function\",\n message: `The source expression evaluated to ${inner.actual}; it must evaluate to one async function`,\n });\n }\n // Async body throws become rejections: exception-like values read as `threw`,\n // while plain values such as uncaught host failure envelopes read as `rejected`.\n reason = evaluationThrew || inner instanceof Error ? \"threw\" : \"rejected\";\n } catch {\n // A program-owned Proxy can throw from instanceof's prototype lookup. Keep\n // that failure inside the same guarded diagnostic boundary as its value.\n }\n\n return CodeProgramFailedError.make({\n implementation: inProcessCodeExecutorImplementation,\n reason,\n thrown: boundedThrown(inner),\n message: boundedText(inner),\n logs: [...capture.lines],\n });\n};\n\nconst executeInProcess: CodeExecutorExecute = Effect.fn(\"InProcessCodeExecutor.execute\")(\n function* (request) {\n yield* validateRequest(request);\n const host = yield* CodeExecutionHost;\n const capture: LogCapture = { lines: [], bytes: 0 };\n const counter = { calls: 0 };\n const queue = yield* Queue.unbounded<PendingHostCall>();\n\n const factory = yield* Effect.try({\n try: () =>\n // This substitute intentionally evaluates authored test programs in-process and reports\n // an `unisolated` posture. Real adapters own the security boundary and never use this path.\n // oxlint-disable-next-line typescript/no-implied-eval\n new Function(\n ...shadowedGlobals,\n \"console\",\n ...request.namespaces.map((namespace) => namespace.name),\n `\"use strict\";\\nreturn (\\n${request.source}\\n);`,\n ),\n catch: (cause) =>\n CodeSourceError.make({\n implementation: inProcessCodeExecutorImplementation,\n reason: \"invalid\",\n message: boundedText(cause),\n }),\n });\n\n const harnessConsole = makeConsole(capture, request.limits);\n // Admission is enforced at call creation, not only at the single-consumer\n // dequeue: a burst of unawaited calls can enqueue at most one entry past\n // the cap (the entry the server fails the pass on); everything beyond is\n // rejected synchronously, so the queue stays bounded against hostile\n // programs.\n let issuedHostCalls = 0;\n\n const namespaceObjects = request.namespaces.map((namespace) =>\n buildNamespaceObject(namespace, (pending) => {\n issuedHostCalls += 1;\n if (issuedHostCalls > request.limits.maxHostCalls + 1) {\n pending.reject(new Error(`host-call limit of ${request.limits.maxHostCalls} exceeded`));\n\n return;\n }\n Queue.offerUnsafe(queue, pending);\n }),\n );\n\n const concurrency = request.limits.maxHostCallConcurrency ?? 4;\n\n const server = yield* Effect.all(\n Array.from({ length: concurrency }, () =>\n serveHostCalls(host, queue, request.limits, capture, counter),\n ),\n { concurrency, discard: true },\n ).pipe(Effect.andThen(Effect.never), Effect.forkScoped);\n\n const program = Effect.tryPromise({\n try: async () => {\n let candidate: unknown;\n\n try {\n candidate = factory(\n ...shadowedGlobals.map(() => undefined),\n harnessConsole,\n ...namespaceObjects,\n );\n } catch (cause) {\n throw new EvaluationThrew(cause);\n }\n if (typeof candidate !== \"function\") {\n throw new EvaluationThrew(new NotAFunction(typeof candidate));\n }\n let outcome: unknown;\n\n try {\n outcome = candidate();\n } catch (cause) {\n throw new EvaluationThrew(cause);\n }\n\n return await Promise.resolve(outcome);\n },\n catch: (thrown) => classifyProgramFailure(thrown, request.limits, capture),\n });\n\n const startedAt = yield* Clock.currentTimeMillis;\n\n // The wall-clock deadline interrupts only at asynchronous suspension\n // points: a synchronous runaway shares the host thread and cannot be\n // stopped in-process — exactly why the platform CPU enforcement cases\n // belong to isolated adapters only (testing spec §8.1). The server fiber\n // is interrupted when the pass settles so no host call outlives the\n // program that issued it.\n const returned = yield* Effect.raceFirst(program, Fiber.join(server)).pipe(\n Effect.timeoutOrElse({\n duration: request.limits.maxWallTime,\n orElse: () =>\n CodeExecutionTimeoutError.make({\n implementation: inProcessCodeExecutorImplementation,\n kind: \"wall-clock\",\n maxWallTime: request.limits.maxWallTime,\n logs: [...capture.lines],\n }),\n }),\n Effect.ensuring(Fiber.interrupt(server)),\n );\n\n const finishedAt = yield* Clock.currentTimeMillis;\n\n // An unawaited burst can outrun the server: the program may return before\n // the over-limit entry is dequeued, so the admission counter is the\n // authority — a pass that ISSUED more calls than the cap fails even when\n // its promise settled first.\n if (issuedHostCalls > request.limits.maxHostCalls) {\n return yield* CodeHostCallLimitError.make({\n implementation: inProcessCodeExecutorImplementation,\n limit: request.limits.maxHostCalls,\n logs: [...capture.lines],\n });\n }\n\n const nonJsonResult = () =>\n CodeProgramFailedError.make({\n implementation: inProcessCodeExecutorImplementation,\n reason: \"non-json-result\",\n thrown: null,\n message: \"The program must return a JSON value\",\n logs: [...capture.lines],\n });\n\n const encoded = serializeJson(returned);\n\n if (Option.isNone(encoded)) return yield* nonJsonResult();\n const resultBytes = utf8ByteLength(encoded.value);\n\n if (resultBytes > request.limits.maxResultBytes) {\n return yield* CodeOutputLimitError.make({\n implementation: inProcessCodeExecutorImplementation,\n surface: \"result\",\n limit: request.limits.maxResultBytes,\n observed: resultBytes,\n logs: [...capture.lines],\n });\n }\n const decoded = decodeJsonText(encoded.value);\n\n if (Option.isNone(decoded)) return yield* nonJsonResult();\n\n return CodeExecutionResult.make({\n implementation: inProcessCodeExecutorImplementation,\n value: decoded.value,\n logs: [...capture.lines],\n resourceUse: CodeExecutionResourceUse.make({\n wallTime: Duration.millis(Math.max(0, finishedAt - startedAt)),\n hostCalls: counter.calls,\n logBytes: capture.bytes,\n resultBytes,\n }),\n });\n },\n);\n\n/**\n * Layer providing the unisolated in-process `CodeExecutor` substitute. The\n * per-pass `CodeExecutionHost` stays in the caller's requirement channel, the\n * same as every real adapter.\n */\nexport const inProcessCodeExecutorLayer: Layer.Layer<CodeExecutor> = Layer.succeed(CodeExecutor)(\n CodeExecutor.of({ execute: executeInProcess }),\n);\n"],"mappings":"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"}
1
+ {"version":3,"file":"CodeExecutorSubstitute.mjs","names":[],"sources":["../src/CodeExecutorSubstitute.ts"],"sourcesContent":["import { Clock, Duration, Effect, Fiber, Layer, Option, Queue, Schema } from \"effect\";\nimport {\n CodeExecutionHost,\n CodeExecutionProtocolError,\n CodeExecutionResourceUse,\n CodeExecutionResult,\n CodeExecutionTimeoutError,\n CodeExecutor,\n type CodeExecutorExecute,\n CodeExecutorUnsupportedError,\n CodeHostCall,\n CodeHostCallLimitError,\n CodeHostCallResult,\n CodeOutputLimitError,\n CodeProgramFailedError,\n CodeSourceError,\n type CodeExecutionLimits,\n type CodeExecutionNamespace,\n type CodeExecutionRequest,\n} from \"effect-agent/code-executor\";\nimport { SandboxImplementation } from \"effect-agent/sandbox\";\n\n/**\n * The deterministic in-process executor substitute (C1 of ADR-0017). It runs\n * the generated program on the host JavaScript engine with best-effort global\n * shadowing only, so it self-identifies as `unisolated` and is never a\n * security boundary (CAP-010, CAP-015). It exists to prove the public\n * `CodeExecutor` contract and to drive deterministic capability tests.\n */\nexport const inProcessCodeExecutorImplementation = SandboxImplementation.make({\n isolation: \"unisolated\",\n identity: \"in-process-javascript\",\n});\n\n// These two caps mirror the wire schema bounds (`BoundedLogs` is at most\n// 4096 lines of at most 16 KiB each): capture must stay inside what\n// `CodeExecutionResult` can carry. A line over the per-line cap is truncated\n// with an explicit `…` marker; exceeding either the byte budget or the line\n// cap fails the pass typed.\nconst MAX_LOG_LINES = 4_096;\nconst MAX_LOG_LINE_CHARACTERS = 16_000;\nconst MAX_THROWN_CHARACTERS = 4_000;\n\nconst utf8ByteLength = (value: string): number => new TextEncoder().encode(value).byteLength;\n\n/**\n * Ambient globals shadowed inside the harness. Shadowing blocks the obvious\n * identifier paths only; a determined program can still escape, which is\n * exactly why this executor reports `unisolated` and the isolated network and\n * CPU enforcement conformance cases run only against isolated adapters.\n */\nconst shadowedGlobals = [\n \"fetch\",\n \"process\",\n \"require\",\n \"module\",\n \"exports\",\n \"global\",\n \"globalThis\",\n \"XMLHttpRequest\",\n \"WebSocket\",\n \"Deno\",\n \"Bun\",\n] as const;\n\nclass LogLimitSignal {\n constructor(readonly observed: number) {}\n}\n\nclass EvaluationThrew {\n constructor(readonly inner: unknown) {}\n}\n\nclass NotAFunction {\n constructor(readonly actual: string) {}\n}\n\ninterface LogCapture {\n readonly lines: Array<string>;\n bytes: number;\n}\n\n/**\n * Total, defect-free rendering of untrusted values: a hostile Proxy can throw\n * from property access, `toString`, and `Symbol.toPrimitive`, and an expected\n * program failure must never escape the typed channel as a defect while its\n * diagnostics are being serialized.\n */\nconst formatLogValue = (value: unknown): string => {\n try {\n if (typeof value === \"string\") {\n return value;\n }\n\n return JSON.stringify(value) ?? String(value);\n } catch {\n try {\n return String(value);\n } catch {\n return \"[unprintable value]\";\n }\n }\n};\n\nconst makeConsole = (capture: LogCapture, limits: CodeExecutionLimits) => {\n const write = (...values: ReadonlyArray<unknown>): void => {\n const joined = values.map(formatLogValue).join(\" \");\n\n const line =\n joined.length > MAX_LOG_LINE_CHARACTERS\n ? `${joined.slice(0, MAX_LOG_LINE_CHARACTERS - 1)}…`\n : joined;\n\n const bytes = utf8ByteLength(line);\n\n if (capture.lines.length >= MAX_LOG_LINES || capture.bytes + bytes > limits.maxLogBytes) {\n throw new LogLimitSignal(capture.bytes + bytes);\n }\n capture.lines.push(line);\n capture.bytes += bytes;\n };\n\n return { debug: write, error: write, info: write, log: write, warn: write };\n};\n\ninterface PendingHostCall {\n readonly namespace: string;\n readonly method: string;\n readonly argument: unknown;\n readonly resolve: (value: unknown) => void;\n readonly reject: (reason: unknown) => void;\n}\n\nconst buildNamespaceObject = (\n namespace: CodeExecutionNamespace,\n offer: (pending: PendingHostCall) => void,\n): Record<string, unknown> => {\n const methods: Record<string, unknown> = {};\n\n for (const method of namespace.methods) {\n methods[method] = (argument: unknown) =>\n new Promise((resolve, reject) => {\n offer({ namespace: namespace.name, method, argument, resolve, reject });\n });\n }\n\n return methods;\n};\n\nconst boundedText = (value: unknown): string => {\n try {\n const text = value instanceof Error ? `${value.name}: ${value.message}` : formatLogValue(value);\n\n return text.slice(0, MAX_THROWN_CHARACTERS);\n } catch {\n return \"[unserializable thrown value]\";\n }\n};\n\n/** Schema decoding of hostile values may itself throw through trap getters. */\nconst safeDecodeJson = (value: unknown): Option.Option<Schema.Json> => {\n try {\n return Schema.decodeUnknownOption(Schema.Json)(value);\n } catch {\n return Option.none();\n }\n};\n\nconst decodeJsonText = Schema.decodeUnknownOption(Schema.fromJsonString(Schema.Json));\n\n/** Own serialized result text before bounding and decoding its detached JSON snapshot. */\nconst serializeJson = (value: unknown): Option.Option<string> => {\n const decoded = safeDecodeJson(value);\n\n if (Option.isNone(decoded)) return Option.none();\n try {\n return Option.fromUndefinedOr(JSON.stringify(decoded.value));\n } catch {\n return Option.none();\n }\n};\n\nconst boundedThrown = (value: unknown): Schema.Json => {\n const decoded = safeDecodeJson(value);\n\n if (Option.isSome(decoded)) {\n try {\n const encoded = JSON.stringify(decoded.value);\n\n if (encoded !== undefined && encoded.length <= MAX_THROWN_CHARACTERS) {\n const snapshot = decodeJsonText(encoded);\n\n if (Option.isSome(snapshot)) return snapshot.value;\n }\n } catch {\n // fall through to the bounded string form\n }\n }\n\n return boundedText(value);\n};\n\nconst encodedJsonByteLength = (value: Schema.Json): number | undefined => {\n try {\n const encoded = JSON.stringify(value);\n\n return encoded === undefined ? undefined : utf8ByteLength(encoded);\n } catch {\n return undefined;\n }\n};\n\n/** Host outcomes are protocol input; a hostile value must not defect mid-decode. */\nconst decodeHostOutcome = (value: unknown): Option.Option<CodeHostCallResult> => {\n try {\n return Schema.decodeUnknownOption(CodeHostCallResult)(value);\n } catch {\n return Option.none();\n }\n};\n\nconst validateRequest = (\n request: CodeExecutionRequest,\n): Effect.Effect<void, CodeExecutorUnsupportedError | CodeSourceError> =>\n Effect.gen(function* () {\n if (request.network._tag !== \"NetworkDisabled\") {\n return yield* CodeExecutorUnsupportedError.make({\n implementation: inProcessCodeExecutorImplementation,\n feature: \"network\",\n message:\n \"The unisolated in-process executor cannot enforce an egress allowlist; only NetworkDisabled is accepted, and even that is shadowed rather than enforced\",\n });\n }\n if (request.limits.cpuMillis !== undefined) {\n return yield* CodeExecutorUnsupportedError.make({\n implementation: inProcessCodeExecutorImplementation,\n feature: \"cpu-limit\",\n message:\n \"The unisolated in-process executor shares the host engine and cannot enforce a CPU limit\",\n });\n }\n const reservedNames = new Set<string>([...shadowedGlobals, \"console\"]);\n const seen = new Set<string>();\n\n for (const namespace of request.namespaces) {\n if (reservedNames.has(namespace.name) || seen.has(namespace.name)) {\n return yield* CodeExecutorUnsupportedError.make({\n implementation: inProcessCodeExecutorImplementation,\n feature: \"namespaces\",\n message: `Namespace ${namespace.name} collides with a harness binding or another namespace`,\n });\n }\n seen.add(namespace.name);\n }\n const sourceBytes = utf8ByteLength(request.source);\n\n if (sourceBytes > request.limits.maxSourceBytes) {\n return yield* CodeSourceError.make({\n implementation: inProcessCodeExecutorImplementation,\n reason: \"oversized\",\n message: `Source is ${sourceBytes} bytes; the request allows ${request.limits.maxSourceBytes}`,\n });\n }\n });\n\nconst serveHostCalls = (\n host: CodeExecutionHost[\"Service\"],\n queue: Queue.Queue<PendingHostCall>,\n limits: CodeExecutionLimits,\n capture: LogCapture,\n counter: { calls: number },\n): Effect.Effect<\n never,\n CodeHostCallLimitError | CodeOutputLimitError | CodeExecutionProtocolError\n> =>\n Effect.gen(function* () {\n while (true) {\n const pending = yield* Queue.take(queue);\n\n counter.calls += 1;\n if (counter.calls > limits.maxHostCalls) {\n return yield* CodeHostCallLimitError.make({\n implementation: inProcessCodeExecutorImplementation,\n limit: limits.maxHostCalls,\n logs: [...capture.lines],\n });\n }\n const argument = safeDecodeJson(pending.argument);\n\n if (Option.isNone(argument)) {\n pending.reject(new TypeError(\"host call arguments must be JSON values\"));\n continue;\n }\n const argumentBytes = encodedJsonByteLength(argument.value);\n\n if (argumentBytes === undefined || argumentBytes > limits.maxHostCallArgumentBytes) {\n return yield* CodeOutputLimitError.make({\n implementation: inProcessCodeExecutorImplementation,\n surface: \"host-call-argument\",\n limit: limits.maxHostCallArgumentBytes,\n observed: argumentBytes ?? 0,\n logs: [...capture.lines],\n });\n }\n\n const rawOutcome = yield* host.call(\n CodeHostCall.make({\n namespace: pending.namespace,\n method: pending.method,\n argument: argument.value,\n }),\n );\n\n const outcome = decodeHostOutcome(rawOutcome);\n\n if (Option.isNone(outcome)) {\n return yield* CodeExecutionProtocolError.make({\n implementation: inProcessCodeExecutorImplementation,\n message: \"The execution host returned a value outside the CodeHostCallResult schema\",\n });\n }\n if (outcome.value._tag === \"CodeHostCallFailure\") {\n pending.reject(outcome.value.error);\n continue;\n }\n const resultBytes = encodedJsonByteLength(outcome.value.value);\n\n if (resultBytes === undefined || resultBytes > limits.maxHostCallResultBytes) {\n return yield* CodeOutputLimitError.make({\n implementation: inProcessCodeExecutorImplementation,\n surface: \"host-call-result\",\n limit: limits.maxHostCallResultBytes,\n observed: resultBytes ?? 0,\n logs: [...capture.lines],\n });\n }\n pending.resolve(outcome.value.value);\n }\n });\n\nconst classifyProgramFailure = (\n thrown: unknown,\n limits: CodeExecutionLimits,\n capture: LogCapture,\n): CodeOutputLimitError | CodeSourceError | CodeProgramFailedError => {\n let inner = thrown;\n let reason: \"threw\" | \"rejected\" = \"rejected\";\n\n try {\n const evaluationThrew = thrown instanceof EvaluationThrew;\n\n inner = evaluationThrew ? thrown.inner : thrown;\n if (inner instanceof LogLimitSignal) {\n return CodeOutputLimitError.make({\n implementation: inProcessCodeExecutorImplementation,\n surface: \"logs\",\n limit: limits.maxLogBytes,\n observed: inner.observed,\n logs: [...capture.lines],\n });\n }\n if (inner instanceof NotAFunction) {\n return CodeSourceError.make({\n implementation: inProcessCodeExecutorImplementation,\n reason: \"not-a-function\",\n message: `The source expression evaluated to ${inner.actual}; it must evaluate to one async function`,\n });\n }\n // Async body throws become rejections: exception-like values read as `threw`,\n // while plain values such as uncaught host failure envelopes read as `rejected`.\n reason = evaluationThrew || inner instanceof Error ? \"threw\" : \"rejected\";\n } catch {\n // A program-owned Proxy can throw from instanceof's prototype lookup. Keep\n // that failure inside the same guarded diagnostic boundary as its value.\n }\n\n return CodeProgramFailedError.make({\n implementation: inProcessCodeExecutorImplementation,\n reason,\n thrown: boundedThrown(inner),\n message: boundedText(inner),\n logs: [...capture.lines],\n });\n};\n\nconst executeInProcess: CodeExecutorExecute = Effect.fn(\"InProcessCodeExecutor.execute\")(\n function* (request) {\n yield* validateRequest(request);\n const host = yield* CodeExecutionHost;\n const capture: LogCapture = { lines: [], bytes: 0 };\n const counter = { calls: 0 };\n const queue = yield* Queue.unbounded<PendingHostCall>();\n\n const factory = yield* Effect.try({\n try: () =>\n // This substitute intentionally evaluates authored test programs in-process and reports\n // an `unisolated` posture. Real adapters own the security boundary and never use this path.\n // oxlint-disable-next-line typescript/no-implied-eval\n new Function(\n ...shadowedGlobals,\n \"console\",\n ...request.namespaces.map((namespace) => namespace.name),\n `\"use strict\";\\nreturn (\\n${request.source}\\n);`,\n ),\n catch: (cause) =>\n CodeSourceError.make({\n implementation: inProcessCodeExecutorImplementation,\n reason: \"invalid\",\n message: boundedText(cause),\n }),\n });\n\n const harnessConsole = makeConsole(capture, request.limits);\n // Admission is enforced at call creation, not only at the single-consumer\n // dequeue: a burst of unawaited calls can enqueue at most one entry past\n // the cap (the entry the server fails the pass on); everything beyond is\n // rejected synchronously, so the queue stays bounded against hostile\n // programs.\n let issuedHostCalls = 0;\n\n const namespaceObjects = request.namespaces.map((namespace) =>\n buildNamespaceObject(namespace, (pending) => {\n issuedHostCalls += 1;\n if (issuedHostCalls > request.limits.maxHostCalls + 1) {\n pending.reject(new Error(`host-call limit of ${request.limits.maxHostCalls} exceeded`));\n\n return;\n }\n Queue.offerUnsafe(queue, pending);\n }),\n );\n\n const concurrency = request.limits.maxHostCallConcurrency ?? 4;\n\n const server = yield* Effect.all(\n Array.from({ length: concurrency }, () =>\n serveHostCalls(host, queue, request.limits, capture, counter),\n ),\n { concurrency, discard: true },\n ).pipe(Effect.andThen(Effect.never), Effect.forkScoped);\n\n const program = Effect.tryPromise({\n try: async () => {\n let candidate: unknown;\n\n try {\n candidate = factory(\n ...shadowedGlobals.map(() => undefined),\n harnessConsole,\n ...namespaceObjects,\n );\n } catch (cause) {\n throw new EvaluationThrew(cause);\n }\n if (typeof candidate !== \"function\") {\n throw new EvaluationThrew(new NotAFunction(typeof candidate));\n }\n let outcome: unknown;\n\n try {\n outcome = candidate();\n } catch (cause) {\n throw new EvaluationThrew(cause);\n }\n\n return await Promise.resolve(outcome);\n },\n catch: (thrown) => classifyProgramFailure(thrown, request.limits, capture),\n });\n\n const startedAt = yield* Clock.currentTimeMillis;\n\n // The wall-clock deadline interrupts only at asynchronous suspension\n // points: a synchronous runaway shares the host thread and cannot be\n // stopped in-process — exactly why the platform CPU enforcement cases\n // belong to isolated adapters only (testing spec §8.1). The server fiber\n // is interrupted when the pass settles so no host call outlives the\n // program that issued it.\n const returned = yield* Effect.raceFirst(program, Fiber.join(server)).pipe(\n Effect.timeoutOrElse({\n duration: request.limits.maxWallTime,\n orElse: () =>\n CodeExecutionTimeoutError.make({\n implementation: inProcessCodeExecutorImplementation,\n kind: \"wall-clock\",\n maxWallTime: request.limits.maxWallTime,\n logs: [...capture.lines],\n }),\n }),\n Effect.ensuring(Fiber.interrupt(server)),\n );\n\n const finishedAt = yield* Clock.currentTimeMillis;\n\n // An unawaited burst can outrun the server: the program may return before\n // the over-limit entry is dequeued, so the admission counter is the\n // authority — a pass that ISSUED more calls than the cap fails even when\n // its promise settled first.\n if (issuedHostCalls > request.limits.maxHostCalls) {\n return yield* CodeHostCallLimitError.make({\n implementation: inProcessCodeExecutorImplementation,\n limit: request.limits.maxHostCalls,\n logs: [...capture.lines],\n });\n }\n\n const nonJsonResult = () =>\n CodeProgramFailedError.make({\n implementation: inProcessCodeExecutorImplementation,\n reason: \"non-json-result\",\n thrown: null,\n message: \"The program must return a JSON value\",\n logs: [...capture.lines],\n });\n\n const encoded = serializeJson(returned);\n\n if (Option.isNone(encoded)) return yield* nonJsonResult();\n const resultBytes = utf8ByteLength(encoded.value);\n\n if (resultBytes > request.limits.maxResultBytes) {\n return yield* CodeOutputLimitError.make({\n implementation: inProcessCodeExecutorImplementation,\n surface: \"result\",\n limit: request.limits.maxResultBytes,\n observed: resultBytes,\n logs: [...capture.lines],\n });\n }\n const decoded = decodeJsonText(encoded.value);\n\n if (Option.isNone(decoded)) return yield* nonJsonResult();\n\n return CodeExecutionResult.make({\n implementation: inProcessCodeExecutorImplementation,\n value: decoded.value,\n logs: [...capture.lines],\n resourceUse: CodeExecutionResourceUse.make({\n wallTime: Duration.millis(Math.max(0, finishedAt - startedAt)),\n hostCalls: counter.calls,\n logBytes: capture.bytes,\n resultBytes,\n }),\n });\n },\n);\n\n/**\n * Layer providing the unisolated in-process `CodeExecutor` substitute. The\n * per-pass `CodeExecutionHost` stays in the caller's requirement channel, the\n * same as every real adapter.\n */\nexport const inProcessCodeExecutorLayer: Layer.Layer<CodeExecutor> = Layer.succeed(CodeExecutor)(\n CodeExecutor.of({ execute: executeInProcess }),\n);\n"],"mappings":"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"}
@@ -1,16 +1,16 @@
1
1
  import { Context, Crypto, Effect, Layer, Schema } from "effect";
2
2
  import { Tool, Toolkit } from "effect/unstable/ai";
3
- import * as Subagent from "@effect-agent/capabilities/Subagent";
4
- import { SubagentPolicy } from "@effect-agent/capabilities/Subagent";
5
- import * as Agent from "@effect-agent/core/Agent";
6
- import { ThreadId } from "@effect-agent/core/Identifiers";
7
- import { ResolvedBinding } from "@effect-agent/thread/AgentRegistration";
8
- import { DurableSubmitOptions } from "@effect-agent/thread/DurableAgentRuntime";
9
- import { DefinitionDigests } from "@effect-agent/thread/Records";
10
- import { IdempotencyKey } from "@effect-agent/thread/SubmissionLedger";
11
- import { RuntimeBinding } from "@effect-agent/engine/AgentRuntime";
12
- import { McpConnection, McpConnectionRequest, McpConnector, McpDiscovery, McpServerIdentity, McpToolkitMismatch } from "@effect-agent/capabilities/Mcp";
13
- import { RedactionError, Redactor } from "@effect-agent/capabilities/Redaction";
3
+ import * as Agent from "effect-agent/agent";
4
+ import { ResolvedBinding } from "effect-agent/agent-registration";
5
+ import { DurableSubmitOptions } from "effect-agent/durable-agent-runtime";
6
+ import { ThreadId } from "effect-agent/identifiers";
7
+ import { DefinitionDigests } from "effect-agent/records";
8
+ import * as Subagent from "effect-agent/subagent";
9
+ import { SubagentPolicy } from "effect-agent/subagent";
10
+ import { IdempotencyKey } from "effect-agent/submission-ledger";
11
+ import { RuntimeBinding } from "effect-agent/agent-runtime";
12
+ import { McpConnection, McpConnectionRequest, McpConnector, McpDiscovery, McpServerIdentity, McpToolkitMismatch } from "effect-agent/mcp";
13
+ import { RedactionError, Redactor } from "effect-agent/redaction";
14
14
  //#region src/fixtures/docs-researcher/definition.d.ts
15
15
  declare const ResearchDocumentId: Schema.brand<Schema.NonEmptyString, "@effect-agent/testing/docs-researcher/ResearchDocumentId">;
16
16
  type ResearchDocumentId = typeof ResearchDocumentId.Type;
@@ -165,7 +165,7 @@ declare const DocsResearcherToolkit: Toolkit.Toolkit<{
165
165
  readonly success: typeof SummaryFinding;
166
166
  readonly failure: Subagent.SubagentToolFailure<typeof DocumentSummaryFailed>;
167
167
  readonly failureMode: "error";
168
- }, import("@effect-agent/engine/AgentRuntime").AgentSpawner | import("@effect-agent/core/IdGenerator").IdGenerator | import("@effect-agent/engine/RunEventSink").RunEventSink | import("@effect-agent/engine/AgentRuntime").SubagentDurability>;
168
+ }, import("effect-agent/agent-runtime").AgentSpawner | import("effect-agent/run-event-sink").RunEventSink | import("effect-agent/agent-runtime").SubagentDurability>;
169
169
  }>;
170
170
  declare const DocsResearcher: Agent.Definition<typeof ResearchRequest, typeof ResearchDigest, string, Toolkit.Toolkit<{
171
171
  readonly delegate_document_summary: Tool.Tool<"delegate_document_summary", {
@@ -173,7 +173,7 @@ declare const DocsResearcher: Agent.Definition<typeof ResearchRequest, typeof Re
173
173
  readonly success: typeof SummaryFinding;
174
174
  readonly failure: Subagent.SubagentToolFailure<typeof DocumentSummaryFailed>;
175
175
  readonly failureMode: "error";
176
- }, import("@effect-agent/engine/AgentRuntime").AgentSpawner | import("@effect-agent/core/IdGenerator").IdGenerator | import("@effect-agent/engine/RunEventSink").RunEventSink | import("@effect-agent/engine/AgentRuntime").SubagentDurability>;
176
+ }, import("effect-agent/agent-runtime").AgentSpawner | import("effect-agent/run-event-sink").RunEventSink | import("effect-agent/agent-runtime").SubagentDurability>;
177
177
  }>, undefined, undefined, undefined> & {
178
178
  readonly id: import("effect/Brand").Brand<"@effect-agent/core/AgentId"> & "docs-researcher";
179
179
  };
@@ -234,7 +234,7 @@ interface DocsResearcherHarness {
234
234
  * at assembly, not assumed. Content-tool execution then flows through the
235
235
  * counting `DocumentLibrary` — the scripted MCP server's content store.
236
236
  */
237
- declare const makeDocsResearcherHarness: (options?: DocsResearcherHarnessOptions) => Effect.Effect<DocsResearcherHarness, import("@effect-agent/capabilities/Mcp").McpConnectionError | import("@effect-agent/capabilities/Mcp").McpDiscoveryLimitExceeded | import("@effect-agent/capabilities/Mcp").McpToolkitMismatch, Crypto.Crypto>;
237
+ declare const makeDocsResearcherHarness: (options?: DocsResearcherHarnessOptions) => Effect.Effect<DocsResearcherHarness, import("effect-agent/mcp").McpConnectionError | import("effect-agent/mcp").McpDiscoveryLimitExceeded | import("effect-agent/mcp").McpToolkitMismatch, Crypto.Crypto>;
238
238
  /**
239
239
  * The audit-surface preview of one fetched document: the raw document —
240
240
  * secret marker and all — passes through the configured structural `Redactor`
@@ -1,19 +1,19 @@
1
- import { a as DeterministicIdGeneratorLayer } from "./deterministic-layers-Eka0fMZq.mjs";
1
+ import { a as DeterministicIdGeneratorLayer } from "./deterministic-layers-D5owIoke.mjs";
2
2
  import { Context, Effect, JsonPointer, Layer, Ref, Schema, Stream } from "effect";
3
3
  import { LanguageModel, Model, Tool, Toolkit } from "effect/unstable/ai";
4
- import * as Subagent from "@effect-agent/capabilities/Subagent";
5
- import { SubagentPolicy, SubagentRuntime } from "@effect-agent/capabilities/Subagent";
6
- import { SubagentReservationsMemoryLive } from "@effect-agent/capabilities/SubagentReservations";
7
- import * as Agent from "@effect-agent/core/Agent";
8
- import { AgentPolicy } from "@effect-agent/core/AgentPolicy";
9
- import "@effect-agent/core/Identifiers";
10
- import { DurableWorkerBinding } from "@effect-agent/thread/AgentRegistration";
11
- import "@effect-agent/thread/DurableAgentRuntime";
12
- import { DefinitionDigests, DeploymentId, Digest, ProducerId } from "@effect-agent/thread/Records";
13
- import { Principal } from "@effect-agent/thread/SubmissionLedger";
14
- import "@effect-agent/engine/AgentRuntime";
15
- import { McpConnectionRequest, McpConnector, McpServerIdentity, McpToolkitMismatch, connectMcp } from "@effect-agent/capabilities/Mcp";
16
- import { Redactor } from "@effect-agent/capabilities/Redaction";
4
+ import * as Agent from "effect-agent/agent";
5
+ import { AgentPolicy } from "effect-agent/agent-policy";
6
+ import { DurableWorkerBinding } from "effect-agent/agent-registration";
7
+ import "effect-agent/durable-agent-runtime";
8
+ import "effect-agent/identifiers";
9
+ import { DefinitionDigests, DeploymentId, Digest, ProducerId } from "effect-agent/records";
10
+ import * as Subagent from "effect-agent/subagent";
11
+ import { SubagentPolicy } from "effect-agent/subagent";
12
+ import { SubagentReservationsMemoryLive } from "effect-agent/subagent-reservations";
13
+ import { Principal } from "effect-agent/submission-ledger";
14
+ import "effect-agent/agent-runtime";
15
+ import { McpConnectionRequest, McpConnector, McpServerIdentity, McpToolkitMismatch, connectMcp } from "effect-agent/mcp";
16
+ import { Redactor } from "effect-agent/redaction";
17
17
  import * as McpSchema from "effect/unstable/ai/McpSchema";
18
18
  //#region src/fixtures/docs-researcher/definition.ts
19
19
  const ResearchDocumentId = Schema.NonEmptyString.check(Schema.isMaxLength(64)).pipe(Schema.brand("@effect-agent/testing/docs-researcher/ResearchDocumentId"));
@@ -161,7 +161,7 @@ const docsSummarizerDigestStrings = {
161
161
  tools: "52".repeat(32)
162
162
  };
163
163
  /** Runtime wiring: the immutable delegation plus one explicit child Binding (S2 declaration). */
164
- const docsSummaryHandlersLayer = (childBinding) => SubagentRuntime.layer(delegateDocumentSummary, childBinding, {
164
+ const docsSummaryHandlersLayer = (childBinding) => Subagent.layer(delegateDocumentSummary, childBinding, {
165
165
  mapChildFailure: mapSummaryChildFailure,
166
166
  durable: { targetDigests: docsSummarizerDigestStrings }
167
167
  });
@@ -1 +1 @@
1
- {"version":3,"file":"DocsResearcher.mjs","names":[],"sources":["../src/fixtures/docs-researcher/definition.ts","../src/fixtures/docs-researcher/mcp.ts","../src/fixtures/docs-researcher/harness.ts"],"sourcesContent":["import * as Subagent from \"@effect-agent/capabilities/Subagent\";\nimport { SubagentPolicy, SubagentRuntime } from \"@effect-agent/capabilities/Subagent\";\nimport * as Agent from \"@effect-agent/core/Agent\";\nimport { AgentPolicy } from \"@effect-agent/core/AgentPolicy\";\nimport { type RuntimeBinding } from \"@effect-agent/engine/AgentRuntime\";\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/Mcp\";\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 { connectMcp, type McpDiscovery } from \"@effect-agent/capabilities/Mcp\";\nimport {\n Redactor,\n type RedactedPreview,\n type RedactionError,\n} from \"@effect-agent/capabilities/Redaction\";\nimport { SubagentReservationsMemoryLive } from \"@effect-agent/capabilities/SubagentReservations\";\nimport * as Agent from \"@effect-agent/core/Agent\";\nimport { type ThreadId } from \"@effect-agent/core/Identifiers\";\nimport { DurableWorkerBinding, type ResolvedBinding } from \"@effect-agent/thread/AgentRegistration\";\nimport { type DurableSubmitOptions } from \"@effect-agent/thread/DurableAgentRuntime\";\nimport { DefinitionDigests, DeploymentId, Digest, ProducerId } from \"@effect-agent/thread/Records\";\nimport { Principal, type IdempotencyKey } from \"@effect-agent/thread/SubmissionLedger\";\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
+ {"version":3,"file":"DocsResearcher.mjs","names":[],"sources":["../src/fixtures/docs-researcher/definition.ts","../src/fixtures/docs-researcher/mcp.ts","../src/fixtures/docs-researcher/harness.ts"],"sourcesContent":["import { Context, Effect, Schema } from \"effect\";\nimport * as Agent from \"effect-agent/agent\";\nimport { AgentPolicy } from \"effect-agent/agent-policy\";\nimport { type RuntimeBinding } from \"effect-agent/agent-runtime\";\nimport * as Subagent from \"effect-agent/subagent\";\nimport { SubagentPolicy } from \"effect-agent/subagent\";\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 Subagent.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 type { JsonSchema } from \"effect\";\nimport { Effect, JsonPointer, Layer, Schema } from \"effect\";\nimport {\n McpConnectionRequest,\n McpConnector,\n McpServerIdentity,\n McpToolkitMismatch,\n type McpConnection,\n} from \"effect-agent/mcp\";\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 type { Crypto } from \"effect\";\nimport { Effect, Layer, Ref, Schema, Stream } from \"effect\";\nimport * as Agent from \"effect-agent/agent\";\nimport { DurableWorkerBinding, type ResolvedBinding } from \"effect-agent/agent-registration\";\nimport { type DurableSubmitOptions } from \"effect-agent/durable-agent-runtime\";\nimport { type ThreadId } from \"effect-agent/identifiers\";\nimport { connectMcp, type McpDiscovery } from \"effect-agent/mcp\";\nimport { DefinitionDigests, DeploymentId, Digest, ProducerId } from \"effect-agent/records\";\nimport { Redactor, type RedactedPreview, type RedactionError } from \"effect-agent/redaction\";\nimport { SubagentReservationsMemoryLive } from \"effect-agent/subagent-reservations\";\nimport { Principal, type IdempotencyKey } from \"effect-agent/submission-ledger\";\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,21 +1,20 @@
1
1
  import { f as ScriptedTurnInput, r as ScriptedModel } from "./ScriptedModel-DAvxIiud.mjs";
2
2
  import { Context, Effect, Layer, Option, Schema } from "effect";
3
3
  import { LanguageModel, Model, Response, Tool, Toolkit } from "effect/unstable/ai";
4
- import * as Subagent from "@effect-agent/capabilities/Subagent";
5
- import { SubagentPolicy } from "@effect-agent/capabilities/Subagent";
6
- import * as Agent from "@effect-agent/core/Agent";
7
- import { ThreadId } from "@effect-agent/core/Identifiers";
8
- import { IdGenerator } from "@effect-agent/core/IdGenerator";
9
- import { DurableStep, DurableStepError } from "@effect-agent/engine/DurableStep";
10
- import { ResolvedBinding } from "@effect-agent/thread/AgentRegistration";
11
- import { DurableSubmitOptions, Receipt } from "@effect-agent/thread/DurableAgentRuntime";
12
- import { CanonicalBatch, CanonicalRecordEnvelope, DefinitionDigests, ProducerId } from "@effect-agent/thread/Records";
13
- import { IdempotencyKey } from "@effect-agent/thread/SubmissionLedger";
14
- import { ThreadCheckpoint } from "@effect-agent/thread/ThreadStore";
15
- import { ToolReconciler } from "@effect-agent/thread/ToolReconciler";
16
- import { RuntimeBinding } from "@effect-agent/engine/AgentRuntime";
17
- import { ThreadHistory } from "@effect-agent/engine/ThreadHistory";
18
- import { ThreadProjection } from "@effect-agent/thread/ThreadProjection";
4
+ import * as Agent from "effect-agent/agent";
5
+ import { ResolvedBinding } from "effect-agent/agent-registration";
6
+ import { DurableSubmitOptions, Receipt } from "effect-agent/durable-agent-runtime";
7
+ import { DurableStep, DurableStepError } from "effect-agent/durable-step";
8
+ import { ThreadId } from "effect-agent/identifiers";
9
+ import { CanonicalBatch, CanonicalRecordEnvelope, DefinitionDigests, ProducerId } from "effect-agent/records";
10
+ import * as Subagent from "effect-agent/subagent";
11
+ import { SubagentPolicy } from "effect-agent/subagent";
12
+ import { IdempotencyKey } from "effect-agent/submission-ledger";
13
+ import { ThreadCheckpoint } from "effect-agent/thread-store";
14
+ import { ToolReconciler } from "effect-agent/tool-reconciler";
15
+ import { RuntimeBinding } from "effect-agent/agent-runtime";
16
+ import { ThreadHistory } from "effect-agent/thread-history";
17
+ import { ThreadProjection } from "effect-agent/thread-projection";
19
18
  //#region src/fixtures/travel-planner/definition.d.ts
20
19
  declare const AirportCode: Schema.brand<Schema.NonEmptyString, "@effect-agent/testing/travel-planner/AirportCode">;
21
20
  type AirportCode = typeof AirportCode.Type;
@@ -332,8 +331,8 @@ declare class SupplierBookingDesk extends SupplierBookingDesk_base {
332
331
  static readonly layer: Layer.Layer<SupplierBookingDesk>;
333
332
  }
334
333
  declare const TravelGuidanceLayer: Layer.Layer<TravelGuidance, never, never>;
335
- declare const DeterministicIdGeneratorLayer: Layer.Layer<IdGenerator, never, never>;
336
- declare const TravelPlannerRuntimeLayer: Layer.Layer<ActivityCatalog | FlightCatalog | IdGenerator | LodgingCatalog | import("@effect-agent/engine/RunOptions").RunContextPreparation | ThreadHistory | TravelGuidance | import("effect/unstable/ai/Tool").HandlersFor<{
334
+ declare const DeterministicIdGeneratorLayer: Layer.Layer<never, never, never>;
335
+ declare const TravelPlannerRuntimeLayer: Layer.Layer<ActivityCatalog | FlightCatalog | LodgingCatalog | import("effect-agent/run-options").RunContextPreparation | import("effect-agent/thread").Store | ThreadHistory | TravelGuidance | import("effect/unstable/ai/Tool").HandlersFor<{
337
336
  readonly search_activities: import("effect/unstable/ai/Tool").Tool<"search_activities", {
338
337
  readonly parameters: typeof ActivityQuery;
339
338
  readonly success: typeof ActivitySearchResult;
@@ -1267,7 +1266,7 @@ declare const TravelCoordinatorToolkit: Toolkit.Toolkit<{
1267
1266
  readonly success: typeof DestinationResearchFindings;
1268
1267
  readonly failure: Subagent.SubagentToolFailure<typeof DestinationResearchFailed>;
1269
1268
  readonly failureMode: "error";
1270
- }, import("@effect-agent/engine/AgentRuntime").AgentSpawner | import("@effect-agent/core/IdGenerator").IdGenerator | import("@effect-agent/engine/RunEventSink").RunEventSink | import("@effect-agent/engine/AgentRuntime").SubagentDurability>;
1269
+ }, import("effect-agent/agent-runtime").AgentSpawner | import("effect-agent/run-event-sink").RunEventSink | import("effect-agent/agent-runtime").SubagentDurability>;
1271
1270
  }>;
1272
1271
  declare const TravelCoordinator: Agent.Definition<typeof ResearchMission, typeof DestinationShortlist, string, Toolkit.Toolkit<{
1273
1272
  readonly delegate_destination_research: Tool.Tool<"delegate_destination_research", {
@@ -1275,7 +1274,7 @@ declare const TravelCoordinator: Agent.Definition<typeof ResearchMission, typeof
1275
1274
  readonly success: typeof DestinationResearchFindings;
1276
1275
  readonly failure: Subagent.SubagentToolFailure<typeof DestinationResearchFailed>;
1277
1276
  readonly failureMode: "error";
1278
- }, import("@effect-agent/engine/AgentRuntime").AgentSpawner | import("@effect-agent/core/IdGenerator").IdGenerator | import("@effect-agent/engine/RunEventSink").RunEventSink | import("@effect-agent/engine/AgentRuntime").SubagentDurability>;
1277
+ }, import("effect-agent/agent-runtime").AgentSpawner | import("effect-agent/run-event-sink").RunEventSink | import("effect-agent/agent-runtime").SubagentDurability>;
1279
1278
  }>, undefined, undefined, undefined> & {
1280
1279
  readonly id: import("effect/Brand").Brand<"@effect-agent/core/AgentId"> & "travel-coordinator";
1281
1280
  };
@@ -1601,7 +1600,7 @@ declare const s2CoordinatorSubmitAgent: {
1601
1600
  * evidence in the S2 tests checks the ledger reservation rows and the
1602
1601
  * canonical `SubagentJoined.finalAccounting` against exactly this value.
1603
1602
  */
1604
- declare const durableResearchAllocation: import("@effect-agent/core/SubagentContract").SubagentReservationAmounts;
1603
+ declare const durableResearchAllocation: import("effect-agent/subagent-contract").SubagentReservationAmounts;
1605
1604
  /** The one scripted delegation Tool Call id of the durable coordinator Run. */
1606
1605
  declare const durableResearchCallId = "research-lhr-1";
1607
1606
  /** The child's own scripted guide-lookup Tool Call id. */
@@ -1627,7 +1626,7 @@ declare const makeInvocationCountingModel: (name: string, script: (call: number)
1627
1626
  prompts: Effect.Effect<readonly string[], never, never>;
1628
1627
  }, never, never>;
1629
1628
  /** Runtime wiring for the durable slice: the S1 delegation plus the S2 digest declaration. */
1630
- declare const durableDestinationResearchHandlersLayer: <Provider, ModelProvides, ModelRequires>(childBinding: RuntimeBinding<typeof DestinationBrief, typeof DestinationReport, string, Toolkit.Tools<typeof DestinationResearcherToolkit>, Provider, ModelProvides, ModelRequires>) => Layer.Layer<import("effect/unstable/ai/Tool").Handler<"delegate_destination_research">, never, import("@effect-agent/capabilities/Subagent").SubagentLayerRequirements<typeof DestinationBrief, typeof DestinationReport, string, {
1629
+ declare const durableDestinationResearchHandlersLayer: <Provider, ModelProvides, ModelRequires>(childBinding: RuntimeBinding<typeof DestinationBrief, typeof DestinationReport, string, Toolkit.Tools<typeof DestinationResearcherToolkit>, Provider, ModelProvides, ModelRequires>) => Layer.Layer<import("effect/unstable/ai/Tool").Handler<"delegate_destination_research">, never, Subagent.SubagentLayerRequirements<typeof DestinationBrief, typeof DestinationReport, string, {
1631
1630
  readonly lookup_destination: import("effect/unstable/ai/Tool").Tool<"lookup_destination", {
1632
1631
  readonly parameters: typeof DestinationQuery;
1633
1632
  readonly success: typeof DestinationFacts;