@effect-agent/testing 0.1.0-beta.6 → 0.1.0-beta.60

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 (54) hide show
  1. package/dist/Certification.d.mts +105 -0
  2. package/dist/Certification.mjs +590 -0
  3. package/dist/Certification.mjs.map +1 -0
  4. package/dist/Chaos.d.mts +126 -0
  5. package/dist/Chaos.mjs +755 -0
  6. package/dist/Chaos.mjs.map +1 -0
  7. package/dist/CodeExecutorConformance.d.mts +33 -0
  8. package/dist/CodeExecutorConformance.mjs +231 -0
  9. package/dist/CodeExecutorConformance.mjs.map +1 -0
  10. package/dist/CodeExecutorSubstitute.d.mts +21 -0
  11. package/dist/CodeExecutorSubstitute.mjs +364 -0
  12. package/dist/CodeExecutorSubstitute.mjs.map +1 -0
  13. package/dist/DocsResearcher.d.mts +270 -0
  14. package/dist/DocsResearcher.mjs +490 -0
  15. package/dist/DocsResearcher.mjs.map +1 -0
  16. package/dist/ScriptedModel-DAvxIiud.d.mts +220 -0
  17. package/dist/ScriptedModel.d.mts +2 -0
  18. package/dist/ScriptedModel.mjs +155 -0
  19. package/dist/ScriptedModel.mjs.map +1 -0
  20. package/dist/TravelPlanner.d.mts +1665 -0
  21. package/dist/TravelPlanner.mjs +1958 -0
  22. package/dist/TravelPlanner.mjs.map +1 -0
  23. package/dist/deterministic-layers-Eka0fMZq.mjs +358 -0
  24. package/dist/deterministic-layers-Eka0fMZq.mjs.map +1 -0
  25. package/dist/index.d.mts +2 -3378
  26. package/dist/index.mjs +2 -4766
  27. package/dist/rolldown-runtime-D7D4PA-g.mjs +13 -0
  28. package/package.json +1 -48
  29. package/src/{certification.ts → Certification.ts} +251 -115
  30. package/src/{chaos.ts → Chaos.ts} +246 -122
  31. package/src/{code-executor-conformance.ts → CodeExecutorConformance.ts} +29 -6
  32. package/src/{code-executor-substitute.ts → CodeExecutorSubstitute.ts} +104 -42
  33. package/src/{fixtures/docs-researcher/index.ts → DocsResearcher.ts} +68 -5
  34. package/src/{scripted-model.ts → ScriptedModel.ts} +22 -25
  35. package/src/TravelPlanner.ts +232 -0
  36. package/src/fixtures/docs-researcher/definition.ts +19 -10
  37. package/src/fixtures/docs-researcher/harness.ts +41 -30
  38. package/src/fixtures/docs-researcher/mcp.ts +49 -3
  39. package/src/fixtures/travel-planner/definition.ts +15 -2
  40. package/src/fixtures/travel-planner/deterministic-layers.ts +47 -4
  41. package/src/fixtures/travel-planner/phase2.ts +4 -3
  42. package/src/fixtures/travel-planner/phase3.ts +18 -37
  43. package/src/fixtures/travel-planner/phase4.ts +23 -36
  44. package/src/fixtures/travel-planner/phase5.ts +38 -41
  45. package/src/fixtures/travel-planner/phase6.ts +182 -84
  46. package/src/fixtures/travel-planner/phase7.ts +4 -102
  47. package/src/fixtures/travel-planner/scenarios.ts +3 -4
  48. package/src/fixtures/travel-planner/subagents-durable.ts +33 -57
  49. package/src/fixtures/travel-planner/subagents.ts +35 -13
  50. package/src/index.ts +1 -11
  51. package/dist/index.mjs.map +0 -1
  52. package/src/code-executor-conformance.d.ts +0 -30
  53. package/src/fixtures/travel-planner/index.ts +0 -11
  54. package/src/fixtures/warehouse/index.ts +0 -412
@@ -0,0 +1,490 @@
1
+ import { a as DeterministicIdGeneratorLayer } from "./deterministic-layers-Eka0fMZq.mjs";
2
+ import { Context, Effect, JsonPointer, Layer, Ref, Schema, Stream } from "effect";
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";
17
+ import * as McpSchema from "effect/unstable/ai/McpSchema";
18
+ //#region src/fixtures/docs-researcher/definition.ts
19
+ const ResearchDocumentId = Schema.NonEmptyString.check(Schema.isMaxLength(64)).pipe(Schema.brand("@effect-agent/testing/docs-researcher/ResearchDocumentId"));
20
+ const BoundedTitle = Schema.NonEmptyString.check(Schema.isMaxLength(120));
21
+ const BoundedBody = Schema.NonEmptyString.check(Schema.isMaxLength(16384));
22
+ /** Bounded summary text: the ONLY child-derived text that may cross to the parent. */
23
+ const BoundedSummary = Schema.NonEmptyString.check(Schema.isMaxLength(240));
24
+ var DocumentQuery = class extends Schema.Class("DocumentQuery")({ documentId: ResearchDocumentId }) {};
25
+ /** One bounded research document as the MCP content server exposes it. */
26
+ var ResearchDocument = class extends Schema.Class("ResearchDocument")({
27
+ documentId: ResearchDocumentId,
28
+ title: BoundedTitle,
29
+ body: BoundedBody
30
+ }) {};
31
+ var DocumentUnavailable = class extends Schema.TaggedError()("DocumentUnavailable", {
32
+ documentId: ResearchDocumentId,
33
+ message: Schema.String
34
+ }) {};
35
+ /** The content store behind the scripted MCP server. */
36
+ var DocumentLibrary = class extends Context.Service()("@effect-agent/testing/docs-researcher/DocumentLibrary") {};
37
+ /**
38
+ * The one content tool the doc-summarizer child uses. Its authored JSON
39
+ * schema is what MCP discovery must serve byte-for-byte: the scripted MCP
40
+ * fixture derives its discovery entry from `Tool.getJsonSchema(FetchDocument)`
41
+ * and `validateMcpDiscovery` re-derives and digests both sides (CAP-009).
42
+ */
43
+ const FetchDocument = Tool.make("fetch_document", {
44
+ description: "Fetch one bounded research document by its identifier.",
45
+ parameters: DocumentQuery,
46
+ success: ResearchDocument,
47
+ failure: DocumentUnavailable,
48
+ failureMode: "error",
49
+ dependencies: [DocumentLibrary]
50
+ });
51
+ const DocContentToolkit = Toolkit.make(FetchDocument);
52
+ const docContentToolkitLayer = DocContentToolkit.toLayer({ fetch_document: (query) => Effect.flatMap(DocumentLibrary, (library) => library.fetch(query)) });
53
+ /** Never allowed outside a child Thread or an unredacted fixture value. */
54
+ const docsDocumentBodySecret = "docs-vault-secret-771";
55
+ const decodeDocumentId = Schema.decodeSync(ResearchDocumentId);
56
+ const corpusEntries = new Map([{
57
+ documentId: "durability-notes",
58
+ title: "Durability protocol notes",
59
+ bodyPhrase: "amber-ledger-passage",
60
+ summary: "Settlement results are recorded exactly once while external side effects stay at-least-once."
61
+ }, {
62
+ documentId: "subagent-notes",
63
+ title: "Subagent join notes",
64
+ bodyPhrase: "cobalt-join-corridor",
65
+ summary: "A parent joins only the verified settlement of its own established child."
66
+ }].map((entry) => [entry.documentId, {
67
+ document: ResearchDocument.make({
68
+ documentId: decodeDocumentId(entry.documentId),
69
+ title: entry.title,
70
+ body: `${entry.bodyPhrase}: internal working notes. ${docsDocumentBodySecret}. ${entry.summary} Raw notes stay inside the child Thread.`
71
+ }),
72
+ bodyPhrase: entry.bodyPhrase,
73
+ summary: entry.summary
74
+ }]));
75
+ /** The corpus document ids in canonical fixture order. */
76
+ const researchCorpusDocumentIds = [decodeDocumentId("durability-notes"), decodeDocumentId("subagent-notes")];
77
+ const requireCorpusEntry = (documentId) => {
78
+ const entry = corpusEntries.get(documentId);
79
+ if (entry === void 0) throw new Error(`No deterministic corpus entry exists for document ${documentId}`);
80
+ return entry;
81
+ };
82
+ /** Deterministic library lookup shared by the scripted MCP content handlers. */
83
+ const researchDocumentLookup = (query) => {
84
+ const entry = corpusEntries.get(query.documentId);
85
+ return entry === void 0 ? Effect.fail(DocumentUnavailable.make({
86
+ documentId: query.documentId,
87
+ message: "No deterministic corpus entry exists for this document."
88
+ })) : Effect.succeed(entry.document);
89
+ };
90
+ /** The full fixture document (body includes the secret marker — child-side only). */
91
+ const researchDocumentFor = (documentId) => requireCorpusEntry(documentId).document;
92
+ /** The distinctive body phrase used by context-isolation assertions. */
93
+ const documentBodyPhrase = (documentId) => requireCorpusEntry(documentId).bodyPhrase;
94
+ var SummaryBrief = class extends Schema.Class("SummaryBrief")({
95
+ documentId: ResearchDocumentId,
96
+ focus: Schema.NonEmptyString
97
+ }) {};
98
+ var DocumentSummary = class extends Schema.Class("DocumentSummary")({
99
+ documentId: ResearchDocumentId,
100
+ summary: BoundedSummary
101
+ }) {};
102
+ /** The summary the scripted child writes after fetching the document. */
103
+ const documentSummaryFor = (documentId) => DocumentSummary.make({
104
+ documentId: requireCorpusEntry(documentId).document.documentId,
105
+ summary: requireCorpusEntry(documentId).summary
106
+ });
107
+ const encodedDocumentSummary = (documentId) => JSON.stringify(Schema.encodeSync(DocumentSummary)(documentSummaryFor(documentId)));
108
+ const DocSummarizer = Agent.make("doc-summarizer", {
109
+ input: SummaryBrief,
110
+ output: DocumentSummary,
111
+ instructions: "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.",
112
+ toolkit: DocContentToolkit,
113
+ policy: AgentPolicy.make({
114
+ maxTurns: 2,
115
+ maxToolCalls: 1,
116
+ maxDuration: "30 seconds",
117
+ toolConcurrency: 1
118
+ }),
119
+ description: "Summarize one bounded research document fetched through MCP content tools.",
120
+ metadata: {
121
+ deploymentClass: "DN",
122
+ phase: "P7"
123
+ }
124
+ });
125
+ var SummaryRequest = class extends Schema.Class("SummaryRequest")({ documentId: ResearchDocumentId }) {};
126
+ var SummaryFinding = class extends Schema.Class("SummaryFinding")({
127
+ documentId: ResearchDocumentId,
128
+ summary: BoundedSummary
129
+ }) {};
130
+ var DocumentSummaryFailed = class extends Schema.TaggedError()("DocumentSummaryFailed", { childErrorTag: Schema.NonEmptyString }) {};
131
+ /** Finite per-invocation bounds (SUB-009): one fetch per child, two children per Run. */
132
+ const documentSummaryPolicy = SubagentPolicy.make({
133
+ maxChildren: 2,
134
+ maxConcurrency: 2,
135
+ maxTurns: 2,
136
+ maxToolCalls: 1,
137
+ maxDuration: "10 seconds"
138
+ });
139
+ const delegateDocumentSummary = Subagent.define("delegate_document_summary", {
140
+ description: "Summarize one research document through the doc-summarizer child and return a bounded finding.",
141
+ target: DocSummarizer,
142
+ parameters: SummaryRequest,
143
+ success: SummaryFinding,
144
+ failure: DocumentSummaryFailed,
145
+ prepareInput: (request) => Effect.succeed(SummaryBrief.make({
146
+ documentId: request.documentId,
147
+ focus: "summarize:durability-claims"
148
+ })),
149
+ projectResult: (summary) => Effect.succeed(SummaryFinding.make({
150
+ documentId: summary.documentId,
151
+ summary: summary.summary
152
+ })),
153
+ policy: documentSummaryPolicy
154
+ });
155
+ /** Total mapping from every expected child Run failure to the declared Tool failure (SUB-028). */
156
+ const mapSummaryChildFailure = (failure) => DocumentSummaryFailed.make({ childErrorTag: failure._tag });
157
+ /** The exact digest strings the durable declaration AND host registration must share (SUB-023). */
158
+ const docsSummarizerDigestStrings = {
159
+ agent: "50".repeat(32),
160
+ model: "51".repeat(32),
161
+ tools: "52".repeat(32)
162
+ };
163
+ /** Runtime wiring: the immutable delegation plus one explicit child Binding (S2 declaration). */
164
+ const docsSummaryHandlersLayer = (childBinding) => SubagentRuntime.layer(delegateDocumentSummary, childBinding, {
165
+ mapChildFailure: mapSummaryChildFailure,
166
+ durable: { targetDigests: docsSummarizerDigestStrings }
167
+ });
168
+ var ResearchRequest = class extends Schema.Class("ResearchRequest")({
169
+ question: Schema.NonEmptyString,
170
+ documentIds: Schema.Array(ResearchDocumentId).check(Schema.isMinLength(1))
171
+ }) {};
172
+ var ResearchDigest = class extends Schema.Class("ResearchDigest")({
173
+ findings: Schema.Array(SummaryFinding),
174
+ nextAction: Schema.Literal("review")
175
+ }) {};
176
+ /** Parent-only transcript markers proving child context isolation (SUB-006/SUB-015). */
177
+ const docsCoordinatorConfidentialMarker = "docs-coordinator-vault-19x";
178
+ const docsMissionConfidentialMarker = "docs-mission-dossier-42f";
179
+ const DocsResearcherToolkit = Toolkit.make(delegateDocumentSummary.tool);
180
+ const DocsResearcher = Agent.make("docs-researcher", {
181
+ input: ResearchRequest,
182
+ output: ResearchDigest,
183
+ instructions: [
184
+ "You are the Effect Agent P7 docs-researcher coordinator.",
185
+ `Coordinator-only context: ${docsCoordinatorConfidentialMarker}.`,
186
+ "Call delegate_document_summary once per requested document in one Tool batch.",
187
+ "Return only a JSON digest built from the delegated findings. This is read-only research."
188
+ ].join("\n"),
189
+ toolkit: DocsResearcherToolkit,
190
+ policy: AgentPolicy.make({
191
+ maxTurns: 2,
192
+ maxToolCalls: 2,
193
+ maxDuration: "30 seconds",
194
+ toolConcurrency: 2
195
+ }),
196
+ description: "Coordinate per-document summarization through one declared delegation Tool.",
197
+ metadata: {
198
+ deploymentClass: "DN",
199
+ phase: "P7"
200
+ }
201
+ });
202
+ /** The default two-document research mission. */
203
+ const researchMissionRequest = ResearchRequest.make({
204
+ question: `Summarize the durability and subagent notes; keep ${docsMissionConfidentialMarker} inside the coordinator thread.`,
205
+ documentIds: researchCorpusDocumentIds
206
+ });
207
+ /** The coordinator's expected final digest for the given documents. */
208
+ const expectedResearchDigest = (documentIds = researchCorpusDocumentIds) => ResearchDigest.make({
209
+ findings: documentIds.map((documentId) => {
210
+ const summary = documentSummaryFor(documentId);
211
+ return SummaryFinding.make({
212
+ documentId: summary.documentId,
213
+ summary: summary.summary
214
+ });
215
+ }),
216
+ nextAction: "review"
217
+ });
218
+ //#endregion
219
+ //#region src/fixtures/docs-researcher/mcp.ts
220
+ /** Framework-side hard bounds one docs-researcher assembly requests. */
221
+ const docsMcpRequest = McpConnectionRequest.make({
222
+ serverId: "docs-content-mcp",
223
+ maxToolCount: 4,
224
+ maxToolDescriptionBytes: 256,
225
+ maxDiscoveryBytes: 16384,
226
+ connectTimeoutMillis: 1e3
227
+ });
228
+ const docsMcpIdentity = McpServerIdentity.make({
229
+ serverId: docsMcpRequest.serverId,
230
+ implementation: McpSchema.Implementation.make({
231
+ name: "docs-researcher-content-fixture",
232
+ version: "1.0.0"
233
+ })
234
+ });
235
+ /**
236
+ * `Tool.getJsonSchema` produces a `$ref`/`$defs`-shaped schema for
237
+ * `FetchDocument`'s named, refined parameters type, but `McpSchema.Tool`'s
238
+ * `inputSchema` requires a flat `{ type: "object", ... }` root — the shape a
239
+ * real MCP server advertises on the wire. This inlines the single top-level
240
+ * `$ref` so the derivation described above still holds byte-for-byte.
241
+ */
242
+ const JsonSchemaDefinitions = Schema.Record(Schema.String, Schema.Record(Schema.String, Schema.Unknown));
243
+ const decodeJsonSchemaDefinitions = Schema.decodeUnknownSync(JsonSchemaDefinitions);
244
+ const decodeToolJsonSchema = Schema.decodeUnknownSync(McpSchema.ToolJsonSchema);
245
+ const flattenTopLevelRef = (schema) => {
246
+ const ref = schema["$ref"];
247
+ if (typeof ref !== "string") return decodeToolJsonSchema(schema);
248
+ const defs = decodeJsonSchemaDefinitions(schema["$defs"]);
249
+ const key = ref.startsWith("#/$defs/") ? JsonPointer.unescapeToken(ref.slice(8)) : void 0;
250
+ const resolved = key !== void 0 && Object.hasOwn(defs, key) ? defs[key] : void 0;
251
+ return decodeToolJsonSchema(resolved ?? schema);
252
+ };
253
+ const fetchDocumentOutputSchema = flattenTopLevelRef(Tool.getJsonSchemaFromSchema(FetchDocument.successSchema));
254
+ const discoveredFetchDocument = McpSchema.Tool.make({
255
+ name: FetchDocument.name,
256
+ description: "Fetch one bounded research document by its identifier.",
257
+ inputSchema: flattenTopLevelRef(Tool.getJsonSchema(FetchDocument)),
258
+ ...fetchDocumentOutputSchema.type === "object" ? { outputSchema: fetchDocumentOutputSchema } : {}
259
+ });
260
+ const scriptedConnector = (tools) => Layer.succeed(McpConnector)({ connect: () => Effect.acquireRelease(Effect.succeed({
261
+ identity: docsMcpIdentity,
262
+ capabilities: McpSchema.ServerCapabilities.make({}),
263
+ tools,
264
+ toolkit: DocContentToolkit
265
+ }), () => Effect.void) });
266
+ /** The well-behaved scripted content server. */
267
+ const docsMcpConnectorLayer = scriptedConnector([discoveredFetchDocument]);
268
+ /** Serves a tool description exceeding `maxToolDescriptionBytes` (SEC-013 bound). */
269
+ const docsMcpOversizedConnectorLayer = scriptedConnector([McpSchema.Tool.make({
270
+ name: discoveredFetchDocument.name,
271
+ description: "x".repeat(1024),
272
+ inputSchema: discoveredFetchDocument.inputSchema
273
+ })]);
274
+ /** Serves a discovery schema that disagrees with the authored toolkit (drift fails closed). */
275
+ const docsMcpMismatchedConnectorLayer = scriptedConnector([McpSchema.Tool.make({
276
+ name: discoveredFetchDocument.name,
277
+ description: discoveredFetchDocument.description,
278
+ inputSchema: {
279
+ type: "object",
280
+ properties: { url: { type: "string" } }
281
+ }
282
+ })]);
283
+ const isJsonEqual = (left, right) => JSON.stringify(left) === JSON.stringify(right);
284
+ /**
285
+ * Bind DISCOVERY to AUTHORING: `validateMcpDiscovery` (inside `connectMcp`)
286
+ * already proved the served discovery matches the connection's own Toolkit;
287
+ * this check additionally proves that Toolkit is the exact toolkit the
288
+ * doc-summarizer was AUTHORED against — same tool names, same derived JSON
289
+ * schemas — so a connector cannot substitute a look-alike toolkit. The
290
+ * docs-researcher harness runs it before any worker Binding registration and
291
+ * fails closed on any drift.
292
+ */
293
+ const assertDiscoveryMatchesAuthoredToolkit = Effect.fn("DocsResearcher.assertDiscoveryMatchesAuthoredToolkit")(function* (connection) {
294
+ const authored = Object.values(DocContentToolkit.tools).map((tool) => ({
295
+ name: tool.name,
296
+ inputSchema: Tool.getJsonSchema(tool)
297
+ })).sort((left, right) => left.name < right.name ? -1 : left.name > right.name ? 1 : 0);
298
+ const discovered = Object.values(connection.toolkit.tools).map((tool) => ({
299
+ name: tool.name,
300
+ inputSchema: Tool.getJsonSchema(tool)
301
+ })).sort((left, right) => left.name < right.name ? -1 : left.name > right.name ? 1 : 0);
302
+ if (!(authored.length === discovered.length && authored.every((tool, index) => tool.name === discovered[index]?.name && isJsonEqual(tool.inputSchema, discovered[index]?.inputSchema)))) return yield* McpToolkitMismatch.make({
303
+ serverId: connection.discovery.identity.serverId,
304
+ message: "The MCP-discovered toolkit does not match the doc-summarizer's authored content toolkit"
305
+ });
306
+ });
307
+ /** Round-trip guard for encoded discovery values persisted as fixture evidence. */
308
+ const DocsMcpDiscoveryEvidence = Schema.Struct({
309
+ serverId: Schema.NonEmptyString,
310
+ toolCount: Schema.Natural,
311
+ encodedBytes: Schema.Natural,
312
+ toolkitSchemaDigest: Schema.String
313
+ });
314
+ //#endregion
315
+ //#region src/fixtures/docs-researcher/harness.ts
316
+ const docsResearcherDeploymentId = Schema.decodeSync(DeploymentId)("docs-researcher-p7-deployment");
317
+ const docsResearcherProducerId = Schema.decodeSync(ProducerId)("docs-researcher-p7-producer");
318
+ const docsResearcherPrincipal = Schema.decodeSync(Principal)("docs-researcher-p7-principal");
319
+ const digestOf = (pair) => Schema.decodeSync(Digest)(pair.repeat(32));
320
+ /** Redacted, deterministic coordinator definition digests for this fixture version. */
321
+ const docsCoordinatorDigests = DefinitionDigests.make({
322
+ agent: digestOf("40"),
323
+ model: digestOf("41"),
324
+ tools: digestOf("42")
325
+ });
326
+ /** The child registration digests — byte-equal to `docsSummarizerDigestStrings` (SUB-023). */
327
+ const docsSummarizerDigests = DefinitionDigests.make({
328
+ agent: digestOf("50"),
329
+ model: digestOf("51"),
330
+ tools: digestOf("52")
331
+ });
332
+ /** Durable admission options for one docs-researcher Submission on one mission lane. */
333
+ const docsResearcherSubmitOptions = (threadId, idempotencyKey) => ({
334
+ threadId,
335
+ principal: docsResearcherPrincipal,
336
+ idempotencyKey,
337
+ definitions: docsCoordinatorDigests
338
+ });
339
+ /** The structural submit slice of the coordinator Binding (`DurableAgentRuntime.submit`). */
340
+ const docsResearcherSubmitAgent = { definition: {
341
+ id: DocsResearcher.id,
342
+ input: DocsResearcher.input
343
+ } };
344
+ /** The deterministic delegation Tool Call identity for one document. */
345
+ const summarizeCallId = (documentId) => `summarize-${documentId}`;
346
+ /** The child's own scripted fetch Tool Call identity for one document. */
347
+ const fetchCallId = (documentId) => `fetch-${documentId}`;
348
+ const scriptedUsage = {
349
+ inputTokens: { total: 96 },
350
+ outputTokens: { total: 64 }
351
+ };
352
+ const summaryDelegationParts = (documentIds) => [...documentIds.map((documentId) => ({
353
+ type: "tool-call",
354
+ id: summarizeCallId(documentId),
355
+ name: "delegate_document_summary",
356
+ params: { documentId },
357
+ providerExecuted: false
358
+ })), {
359
+ type: "finish",
360
+ reason: "tool-calls",
361
+ usage: scriptedUsage
362
+ }];
363
+ const digestParts = (documentIds) => [
364
+ {
365
+ type: "text-start",
366
+ id: "digest"
367
+ },
368
+ {
369
+ type: "text-delta",
370
+ id: "digest",
371
+ delta: JSON.stringify(Schema.encodeSync(ResearchDigest)(expectedResearchDigest(documentIds)))
372
+ },
373
+ {
374
+ type: "text-end",
375
+ id: "digest"
376
+ },
377
+ {
378
+ type: "finish",
379
+ reason: "stop",
380
+ usage: scriptedUsage
381
+ }
382
+ ];
383
+ const fetchParts = (documentId) => [{
384
+ type: "tool-call",
385
+ id: fetchCallId(documentId),
386
+ name: "fetch_document",
387
+ params: { documentId },
388
+ providerExecuted: false
389
+ }, {
390
+ type: "finish",
391
+ reason: "tool-calls",
392
+ usage: scriptedUsage
393
+ }];
394
+ const summaryParts = (documentId) => [
395
+ {
396
+ type: "text-start",
397
+ id: "document-summary"
398
+ },
399
+ {
400
+ type: "text-delta",
401
+ id: "document-summary",
402
+ delta: encodedDocumentSummary(documentId)
403
+ },
404
+ {
405
+ type: "text-end",
406
+ id: "document-summary"
407
+ },
408
+ {
409
+ type: "finish",
410
+ reason: "stop",
411
+ usage: scriptedUsage
412
+ }
413
+ ];
414
+ /**
415
+ * One prompt-aware scripted model with externally observable counters. A DN
416
+ * Attempt may resume on a fresh Layer build, so responses derive from the
417
+ * committed history in the prompt — never from an in-Layer turn counter.
418
+ */
419
+ const makeCountingModel = (name, decide) => Effect.gen(function* () {
420
+ const calls = yield* Ref.make(0);
421
+ const prompts = yield* Ref.make([]);
422
+ return {
423
+ model: Model.make("scripted", name, Layer.effect(LanguageModel.LanguageModel, LanguageModel.make({
424
+ generateText: () => Effect.succeed([]),
425
+ streamText: (request) => Stream.unwrap(Effect.gen(function* () {
426
+ yield* Ref.update(calls, (value) => value + 1);
427
+ const promptJson = JSON.stringify(request.prompt);
428
+ yield* Ref.update(prompts, (previous) => [...previous, promptJson]);
429
+ return Stream.fromIterable(yield* decide(promptJson));
430
+ }))
431
+ }))),
432
+ calls: Ref.get(calls),
433
+ prompts: Ref.get(prompts)
434
+ };
435
+ });
436
+ /**
437
+ * Build the docs-researcher harness. Order matters and is the point: the
438
+ * child's content toolkit is only registered as a worker Binding AFTER the
439
+ * MCP connector's bounded discovery validated the authored toolkit
440
+ * byte-for-byte (`connectMcp` + `assertDiscoveryMatchesAuthoredToolkit`), so
441
+ * "the tools the summarizer runs are the tools discovery served" is enforced
442
+ * at assembly, not assumed. Content-tool execution then flows through the
443
+ * counting `DocumentLibrary` — the scripted MCP server's content store.
444
+ */
445
+ const makeDocsResearcherHarness = (options) => Effect.gen(function* () {
446
+ const documentIds = options?.documentIds ?? researchCorpusDocumentIds;
447
+ const discovery = yield* Effect.scoped(Effect.gen(function* () {
448
+ const connection = yield* connectMcp(docsMcpRequest);
449
+ yield* assertDiscoveryMatchesAuthoredToolkit(connection);
450
+ return connection.discovery;
451
+ })).pipe(Effect.provide(docsMcpConnectorLayer));
452
+ const fetchCounts = yield* Ref.make(/* @__PURE__ */ new Map());
453
+ const libraryLayer = Layer.succeed(DocumentLibrary, DocumentLibrary.of({ fetch: (query) => Ref.update(fetchCounts, (current) => new Map(current).set(query.documentId, (current.get(query.documentId) ?? 0) + 1)).pipe(Effect.andThen(researchDocumentLookup(query))) }));
454
+ const childToolkitLayer = docContentToolkitLayer.pipe(Layer.provideMerge(libraryLayer));
455
+ const childModel = yield* makeCountingModel("doc-summarizer-p7", (promptJson) => Effect.suspend(() => {
456
+ const documentId = documentIds.find((candidate) => promptJson.includes(candidate));
457
+ if (documentId === void 0) return Effect.die(/* @__PURE__ */ new Error("The summarizer prompt names no corpus document"));
458
+ return Effect.succeed(promptJson.includes(fetchCallId(documentId)) ? summaryParts(documentId) : fetchParts(documentId));
459
+ }));
460
+ const childBinding = Agent.withModel(DocSummarizer, childModel.model);
461
+ const firstCallId = summarizeCallId(documentIds[0] ?? "durability-notes");
462
+ const parentModel = yield* makeCountingModel("docs-researcher-p7", (promptJson) => Effect.succeed(promptJson.includes(firstCallId) ? digestParts(documentIds) : summaryDelegationParts(documentIds)));
463
+ const parentBinding = Agent.withModel(DocsResearcher, parentModel.model);
464
+ const delegationLayer = docsSummaryHandlersLayer(childBinding).pipe(Layer.provide(Layer.mergeAll(childToolkitLayer, SubagentReservationsMemoryLive, DeterministicIdGeneratorLayer)));
465
+ return {
466
+ bindings: [yield* DurableWorkerBinding.make(parentBinding, docsCoordinatorDigests).pipe(Effect.provide(delegationLayer)), yield* DurableWorkerBinding.make(childBinding, docsSummarizerDigests).pipe(Effect.provide(childToolkitLayer))],
467
+ discovery,
468
+ parentModelCalls: parentModel.calls,
469
+ parentPrompts: parentModel.prompts,
470
+ childModelCalls: childModel.calls,
471
+ childPrompts: childModel.prompts,
472
+ fetchInvocations: (documentId) => Ref.get(fetchCounts).pipe(Effect.map((current) => current.get(documentId) ?? 0))
473
+ };
474
+ });
475
+ const encodeResearchDocument = Schema.encodeEffect(ResearchDocument);
476
+ /**
477
+ * The audit-surface preview of one fetched document: the raw document —
478
+ * secret marker and all — passes through the configured structural `Redactor`
479
+ * before anything may quote it outside the child Thread (SEC-008,
480
+ * CAP-013). Tests assert the preview keeps shape but no scalar content.
481
+ */
482
+ const redactedDocumentPreview = Effect.fn("DocsResearcher.redactedDocumentPreview")(function* (documentId) {
483
+ const redactor = yield* Redactor;
484
+ const encoded = yield* encodeResearchDocument(researchDocumentFor(documentId)).pipe(Effect.orDie);
485
+ return yield* redactor.redact(encoded);
486
+ });
487
+ //#endregion
488
+ export { BoundedSummary, DocContentToolkit, DocSummarizer, DocsMcpDiscoveryEvidence, DocsResearcher, DocsResearcherToolkit, DocumentLibrary, DocumentQuery, DocumentSummary, DocumentSummaryFailed, DocumentUnavailable, FetchDocument, ResearchDigest, ResearchDocument, ResearchDocumentId, ResearchRequest, SummaryBrief, SummaryFinding, SummaryRequest, assertDiscoveryMatchesAuthoredToolkit, delegateDocumentSummary, docContentToolkitLayer, docsCoordinatorConfidentialMarker, docsCoordinatorDigests, docsDocumentBodySecret, docsMcpConnectorLayer, docsMcpIdentity, docsMcpMismatchedConnectorLayer, docsMcpOversizedConnectorLayer, docsMcpRequest, docsMissionConfidentialMarker, docsResearcherDeploymentId, docsResearcherPrincipal, docsResearcherProducerId, docsResearcherSubmitAgent, docsResearcherSubmitOptions, docsSummarizerDigestStrings, docsSummarizerDigests, docsSummaryHandlersLayer, documentBodyPhrase, documentSummaryFor, documentSummaryPolicy, encodedDocumentSummary, expectedResearchDigest, fetchCallId, makeDocsResearcherHarness, mapSummaryChildFailure, redactedDocumentPreview, researchCorpusDocumentIds, researchDocumentFor, researchDocumentLookup, researchMissionRequest, summarizeCallId };
489
+
490
+ //# sourceMappingURL=DocsResearcher.mjs.map
@@ -0,0 +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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"}