@effect-agent/testing 0.1.0-beta.8 → 0.1.0-beta.81
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Certification.d.mts +105 -0
- package/dist/Certification.mjs +592 -0
- package/dist/Certification.mjs.map +1 -0
- package/dist/Chaos.d.mts +126 -0
- package/dist/Chaos.mjs +755 -0
- package/dist/Chaos.mjs.map +1 -0
- package/dist/CodeExecutorConformance.d.mts +33 -0
- package/dist/CodeExecutorConformance.mjs +231 -0
- package/dist/CodeExecutorConformance.mjs.map +1 -0
- package/dist/CodeExecutorSubstitute.d.mts +21 -0
- package/dist/CodeExecutorSubstitute.mjs +368 -0
- package/dist/CodeExecutorSubstitute.mjs.map +1 -0
- package/dist/DocsResearcher.d.mts +270 -0
- package/dist/DocsResearcher.mjs +490 -0
- package/dist/DocsResearcher.mjs.map +1 -0
- package/dist/ScriptedModel-DAvxIiud.d.mts +220 -0
- package/dist/ScriptedModel.d.mts +2 -0
- package/dist/ScriptedModel.mjs +155 -0
- package/dist/ScriptedModel.mjs.map +1 -0
- package/dist/TravelPlanner.d.mts +1665 -0
- package/dist/TravelPlanner.mjs +1963 -0
- package/dist/TravelPlanner.mjs.map +1 -0
- package/dist/deterministic-layers-Eka0fMZq.mjs +358 -0
- package/dist/deterministic-layers-Eka0fMZq.mjs.map +1 -0
- package/dist/index.d.mts +2 -3406
- package/dist/index.mjs +2 -4771
- package/dist/rolldown-runtime-D7D4PA-g.mjs +13 -0
- package/package.json +1 -48
- package/src/{certification.ts → Certification.ts} +251 -117
- package/src/{chaos.ts → Chaos.ts} +246 -122
- package/src/{code-executor-conformance.ts → CodeExecutorConformance.ts} +29 -6
- package/src/{code-executor-substitute.ts → CodeExecutorSubstitute.ts} +112 -45
- package/src/{fixtures/docs-researcher/index.ts → DocsResearcher.ts} +68 -5
- package/src/{scripted-model.ts → ScriptedModel.ts} +22 -25
- package/src/TravelPlanner.ts +232 -0
- package/src/fixtures/docs-researcher/definition.ts +19 -10
- package/src/fixtures/docs-researcher/harness.ts +41 -30
- package/src/fixtures/docs-researcher/mcp.ts +49 -3
- package/src/fixtures/travel-planner/definition.ts +15 -2
- package/src/fixtures/travel-planner/deterministic-layers.ts +47 -4
- package/src/fixtures/travel-planner/phase2.ts +4 -3
- package/src/fixtures/travel-planner/phase3.ts +18 -41
- package/src/fixtures/travel-planner/phase4.ts +23 -36
- package/src/fixtures/travel-planner/phase5.ts +38 -41
- package/src/fixtures/travel-planner/phase6.ts +187 -84
- package/src/fixtures/travel-planner/phase7.ts +4 -102
- package/src/fixtures/travel-planner/scenarios.ts +3 -4
- package/src/fixtures/travel-planner/subagents-durable.ts +33 -57
- package/src/fixtures/travel-planner/subagents.ts +35 -13
- package/src/index.ts +1 -11
- package/dist/index.mjs.map +0 -1
- package/src/code-executor-conformance.d.ts +0 -30
- package/src/fixtures/travel-planner/index.ts +0 -11
- package/src/fixtures/warehouse/index.ts +0 -412
|
@@ -1,33 +1,29 @@
|
|
|
1
1
|
import {
|
|
2
2
|
delegationAllocationFromPolicy,
|
|
3
|
-
SubagentReservationsMemoryLive,
|
|
4
3
|
SubagentRuntime,
|
|
5
|
-
} from "@effect-agent/capabilities";
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
ProducerId,
|
|
15
|
-
type DurableSubmitOptions,
|
|
16
|
-
type IdempotencyKey,
|
|
17
|
-
type ResolvedBinding,
|
|
18
|
-
} from "@effect-agent/session";
|
|
4
|
+
} from "@effect-agent/capabilities/Subagent";
|
|
5
|
+
import { SubagentReservationsMemoryLive } from "@effect-agent/capabilities/SubagentReservations";
|
|
6
|
+
import * as Agent from "@effect-agent/core/Agent";
|
|
7
|
+
import { type ThreadId } from "@effect-agent/core/Identifiers";
|
|
8
|
+
import { type RuntimeBinding } from "@effect-agent/engine/AgentRuntime";
|
|
9
|
+
import { DurableWorkerBinding, type ResolvedBinding } from "@effect-agent/thread/AgentRegistration";
|
|
10
|
+
import { type DurableSubmitOptions } from "@effect-agent/thread/DurableAgentRuntime";
|
|
11
|
+
import { DefinitionDigests, DeploymentId, Digest, ProducerId } from "@effect-agent/thread/Records";
|
|
12
|
+
import { Principal, type IdempotencyKey } from "@effect-agent/thread/SubmissionLedger";
|
|
19
13
|
import { Effect, Layer, Ref, Schema, Stream } from "effect";
|
|
20
14
|
import { LanguageModel, Model, type Response, type Toolkit } from "effect/unstable/ai";
|
|
21
15
|
|
|
22
16
|
import { DeterministicIdGeneratorLayer } from "./deterministic-layers.ts";
|
|
23
|
-
import {
|
|
17
|
+
import type {
|
|
24
18
|
DestinationBrief,
|
|
19
|
+
DestinationReport,
|
|
20
|
+
DestinationResearcherToolkit,
|
|
21
|
+
} from "./subagents.ts";
|
|
22
|
+
import {
|
|
25
23
|
DestinationFacts,
|
|
26
24
|
DestinationGuide,
|
|
27
25
|
DestinationRecommendation,
|
|
28
|
-
DestinationReport,
|
|
29
26
|
DestinationResearcher,
|
|
30
|
-
DestinationResearcherToolkit,
|
|
31
27
|
DestinationResearcherToolkitLayer,
|
|
32
28
|
destinationLookup,
|
|
33
29
|
destinationReportFor,
|
|
@@ -40,46 +36,15 @@ import {
|
|
|
40
36
|
TravelCoordinator,
|
|
41
37
|
} from "./subagents.ts";
|
|
42
38
|
|
|
43
|
-
|
|
44
|
-
// S2 durability profile (spec/subagents.md §17): the S1 coordinator →
|
|
45
|
-
// destination-researcher delegation re-run as ACCEPTED WORK on the Node/SQLite
|
|
46
|
-
// runtime. The claim is `DN` durable attached Subagents only: establishment
|
|
47
|
-
// and join are replay-safe by construction (SUB-016/SUB-019), a completed
|
|
48
|
-
// child is never re-executed on a lost join acknowledgment, and NO claim of
|
|
49
|
-
// exactly-once child external effects is made (rule 8; an unresolved ordinary
|
|
50
|
-
// child Tool blocks as an Unknown Outcome instead, SUB-021). Cloudflare
|
|
51
|
-
// equivalence is P6 scope and explicitly not claimed here.
|
|
52
|
-
// ---------------------------------------------------------------------------
|
|
53
|
-
|
|
54
|
-
export class TravelPlannerSubagentDurabilityProfile extends Schema.Class<TravelPlannerSubagentDurabilityProfile>(
|
|
55
|
-
"@effect-agent/testing/travel-planner/TravelPlannerSubagentDurabilityProfile",
|
|
56
|
-
)({
|
|
57
|
-
deploymentClass: Schema.Literal("DN"),
|
|
58
|
-
durableAttachedSubagents: Schema.Literal(true),
|
|
59
|
-
canonicalSchemaVersion: Schema.Literal(1),
|
|
60
|
-
/** Establishment/join replay converges on one child Receipt, Conversation, and join batch. */
|
|
61
|
-
subagentReplaySafe: Schema.Literal(true),
|
|
62
|
-
/** Never claimed (rule 8): child ordinary Tools stop at Unknown Outcomes, they do not replay. */
|
|
63
|
-
childExternalEffectsExactlyOnce: Schema.Literal(false),
|
|
64
|
-
/** The same conformance suite under DO eviction/alarms is P6 scope (spec §17 `DC`). */
|
|
65
|
-
cloudflareEquivalence: Schema.Literal(false),
|
|
66
|
-
}) {}
|
|
67
|
-
|
|
68
|
-
export const s2TravelPlannerProfile = TravelPlannerSubagentDurabilityProfile.make({
|
|
69
|
-
deploymentClass: "DN",
|
|
70
|
-
durableAttachedSubagents: true,
|
|
71
|
-
canonicalSchemaVersion: 1,
|
|
72
|
-
subagentReplaySafe: true,
|
|
73
|
-
childExternalEffectsExactlyOnce: false,
|
|
74
|
-
cloudflareEquivalence: false,
|
|
75
|
-
});
|
|
76
|
-
|
|
39
|
+
/** Registered coordinator and researcher bindings for durable delegation tests. */
|
|
77
40
|
export const s2TravelPlannerDeploymentId = Schema.decodeSync(DeploymentId)(
|
|
78
41
|
"travel-planner-s2-deployment",
|
|
79
42
|
);
|
|
43
|
+
|
|
80
44
|
export const s2TravelPlannerProducerId = Schema.decodeSync(ProducerId)(
|
|
81
45
|
"travel-planner-s2-producer",
|
|
82
46
|
);
|
|
47
|
+
|
|
83
48
|
export const s2TravelPlannerPrincipal = Schema.decodeSync(Principal)("travel-planner-s2-principal");
|
|
84
49
|
|
|
85
50
|
const digestOf = (character: string) => Schema.decodeSync(Digest)(character.repeat(64));
|
|
@@ -94,7 +59,7 @@ export const s2CoordinatorDigests = DefinitionDigests.make({
|
|
|
94
59
|
/**
|
|
95
60
|
* The exact child Binding digest strings the application declares on
|
|
96
61
|
* `SubagentRuntimeOptions.durable.targetDigests` AND the host registers with
|
|
97
|
-
* the
|
|
62
|
+
* the host's binding array for the researcher Binding. The coordinator
|
|
98
63
|
* stores and verifies them byte-for-byte (SUB-023); a host registration under
|
|
99
64
|
* different strings is a `ChildCompatibilityFailure`, never a substitution.
|
|
100
65
|
*/
|
|
@@ -112,10 +77,10 @@ export const s2ResearcherDigests = DefinitionDigests.make({
|
|
|
112
77
|
|
|
113
78
|
/** Durable admission options for one coordinator Submission on one mission lane. */
|
|
114
79
|
export const s2TravelPlannerSubmitOptions = (
|
|
115
|
-
|
|
80
|
+
threadId: ThreadId,
|
|
116
81
|
idempotencyKey: IdempotencyKey,
|
|
117
82
|
): DurableSubmitOptions => ({
|
|
118
|
-
|
|
83
|
+
threadId,
|
|
119
84
|
principal: s2TravelPlannerPrincipal,
|
|
120
85
|
idempotencyKey,
|
|
121
86
|
definitions: s2CoordinatorDigests,
|
|
@@ -166,6 +131,7 @@ export const durableResearchShortlist = (destination: string): DestinationShortl
|
|
|
166
131
|
*/
|
|
167
132
|
export const encodedDestinationFacts = (destination: string): unknown => {
|
|
168
133
|
const report = destinationReportFor(destination);
|
|
134
|
+
|
|
169
135
|
return Schema.encodeSync(DestinationFacts)(
|
|
170
136
|
DestinationFacts.make({
|
|
171
137
|
destination: report.destination,
|
|
@@ -193,6 +159,7 @@ export const makeInvocationCountingModel = (
|
|
|
193
159
|
Effect.gen(function* () {
|
|
194
160
|
const calls = yield* Ref.make(0);
|
|
195
161
|
const prompts = yield* Ref.make<ReadonlyArray<string>>([]);
|
|
162
|
+
|
|
196
163
|
const model = Model.make(
|
|
197
164
|
"scripted",
|
|
198
165
|
name,
|
|
@@ -204,16 +171,19 @@ export const makeInvocationCountingModel = (
|
|
|
204
171
|
Stream.unwrap(
|
|
205
172
|
Effect.gen(function* () {
|
|
206
173
|
const call = yield* Ref.getAndUpdate(calls, (value) => value + 1);
|
|
174
|
+
|
|
207
175
|
yield* Ref.update(prompts, (previous) => [
|
|
208
176
|
...previous,
|
|
209
177
|
JSON.stringify(request.prompt.content),
|
|
210
178
|
]);
|
|
179
|
+
|
|
211
180
|
return Stream.fromIterable(script(call));
|
|
212
181
|
}),
|
|
213
182
|
),
|
|
214
183
|
}),
|
|
215
184
|
),
|
|
216
185
|
);
|
|
186
|
+
|
|
217
187
|
return { model, calls: Ref.get(calls), prompts: Ref.get(prompts) };
|
|
218
188
|
});
|
|
219
189
|
|
|
@@ -304,7 +274,7 @@ export interface DurableResearchHarnessOptions {
|
|
|
304
274
|
|
|
305
275
|
/** One durable coordinator/researcher pair with observable invocation counters. */
|
|
306
276
|
export interface DurableResearchHarness {
|
|
307
|
-
/** Host registrations for `
|
|
277
|
+
/** Host registrations for `NodeDurableAgentRuntimeOptions.bindings` (parent + child). */
|
|
308
278
|
readonly bindings: ReadonlyArray<ResolvedBinding>;
|
|
309
279
|
/** Total coordinator model invocations across every Attempt and runtime handle. */
|
|
310
280
|
readonly parentModelCalls: Effect.Effect<number>;
|
|
@@ -325,7 +295,7 @@ export interface DurableResearchHarness {
|
|
|
325
295
|
* guide, Turn 2 writes the report), and both worker Bindings captured with
|
|
326
296
|
* their requirement Contexts via `DurableWorkerBinding.make` under the exact
|
|
327
297
|
* fixture digests. The returned `bindings` are plain values: they can be
|
|
328
|
-
* registered with several `
|
|
298
|
+
* registered with several `NodeDurableAgentRuntime` stacks over the same SQLite
|
|
329
299
|
* file while the counters keep counting across all of them.
|
|
330
300
|
*/
|
|
331
301
|
export const makeDurableResearchHarness = (options?: DurableResearchHarnessOptions) =>
|
|
@@ -334,6 +304,7 @@ export const makeDurableResearchHarness = (options?: DurableResearchHarnessOptio
|
|
|
334
304
|
const focus = options?.focus ?? "museums";
|
|
335
305
|
|
|
336
306
|
const guideInvocations = yield* Ref.make(0);
|
|
307
|
+
|
|
337
308
|
const guideLayer = Layer.succeed(
|
|
338
309
|
DestinationGuide,
|
|
339
310
|
DestinationGuide.of({
|
|
@@ -343,6 +314,7 @@ export const makeDurableResearchHarness = (options?: DurableResearchHarnessOptio
|
|
|
343
314
|
),
|
|
344
315
|
}),
|
|
345
316
|
);
|
|
317
|
+
|
|
346
318
|
const childToolkitLayer = DestinationResearcherToolkitLayer.pipe(
|
|
347
319
|
Layer.provideMerge(guideLayer),
|
|
348
320
|
);
|
|
@@ -350,6 +322,7 @@ export const makeDurableResearchHarness = (options?: DurableResearchHarnessOptio
|
|
|
350
322
|
const childModel = yield* makeInvocationCountingModel("destination-researcher-s2", (call) =>
|
|
351
323
|
call === 0 ? researcherLookupParts(destination) : researcherReportParts(destination),
|
|
352
324
|
);
|
|
325
|
+
|
|
353
326
|
const childBinding = Agent.withModel(DestinationResearcher, childModel.model);
|
|
354
327
|
|
|
355
328
|
const parentModel = yield* makeInvocationCountingModel("travel-coordinator-s2", (call) =>
|
|
@@ -357,6 +330,7 @@ export const makeDurableResearchHarness = (options?: DurableResearchHarnessOptio
|
|
|
357
330
|
? delegationTurnParts(durableResearchCallId, destination, focus)
|
|
358
331
|
: shortlistParts(durableResearchShortlist(destination)),
|
|
359
332
|
);
|
|
333
|
+
|
|
360
334
|
const parentBinding = Agent.withModel(TravelCoordinator, parentModel.model);
|
|
361
335
|
|
|
362
336
|
const delegationLayer = durableDestinationResearchHandlersLayer(childBinding).pipe(
|
|
@@ -374,6 +348,7 @@ export const makeDurableResearchHarness = (options?: DurableResearchHarnessOptio
|
|
|
374
348
|
parentBinding,
|
|
375
349
|
s2CoordinatorDigests,
|
|
376
350
|
).pipe(Effect.provide(delegationLayer));
|
|
351
|
+
|
|
377
352
|
const childResolved: ResolvedBinding = yield* DurableWorkerBinding.make(
|
|
378
353
|
childBinding,
|
|
379
354
|
options?.childRegistrationDigests ?? s2ResearcherDigests,
|
|
@@ -387,5 +362,6 @@ export const makeDurableResearchHarness = (options?: DurableResearchHarnessOptio
|
|
|
387
362
|
childPrompts: childModel.prompts,
|
|
388
363
|
guideInvocations: Ref.get(guideInvocations),
|
|
389
364
|
};
|
|
365
|
+
|
|
390
366
|
return harness;
|
|
391
367
|
});
|
|
@@ -1,17 +1,18 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
1
|
+
import * as Subagent from "@effect-agent/capabilities/Subagent";
|
|
2
|
+
import { SubagentPolicy, SubagentRuntime } from "@effect-agent/capabilities/Subagent";
|
|
3
|
+
import * as Agent from "@effect-agent/core/Agent";
|
|
4
|
+
import { AgentPolicy } from "@effect-agent/core/AgentPolicy";
|
|
5
|
+
import { type RuntimeBinding } from "@effect-agent/engine/AgentRuntime";
|
|
4
6
|
import { Context, Deferred, Effect, Layer, Ref, Schema, Stream } from "effect";
|
|
5
7
|
import { LanguageModel, Model, type Response, Tool, Toolkit } from "effect/unstable/ai";
|
|
6
8
|
|
|
7
|
-
import type { ScriptedTurnInput } from "../../
|
|
9
|
+
import type { ScriptedTurnInput } from "../../ScriptedModel.ts";
|
|
8
10
|
import { AirportCode } from "./definition.ts";
|
|
9
11
|
import { CatalogLifecycle } from "./deterministic-layers.ts";
|
|
10
12
|
|
|
11
13
|
// ---------------------------------------------------------------------------
|
|
12
|
-
// Destination Researcher: the S1 specialist child Agent
|
|
13
|
-
//
|
|
14
|
-
// delegation"). The researcher is a normal Agent with one deterministic
|
|
14
|
+
// Destination Researcher: the S1 specialist child Agent.
|
|
15
|
+
// The researcher is a normal Agent with one deterministic
|
|
15
16
|
// travel-service Tool; it never becomes a second child loop (SUB-001/003).
|
|
16
17
|
// ---------------------------------------------------------------------------
|
|
17
18
|
|
|
@@ -51,6 +52,7 @@ export const LookupDestination = Tool.make("lookup_destination", {
|
|
|
51
52
|
});
|
|
52
53
|
|
|
53
54
|
export const DestinationResearcherToolkit = Toolkit.make(LookupDestination);
|
|
55
|
+
|
|
54
56
|
export const DestinationResearcherToolkitLayer = DestinationResearcherToolkit.toLayer({
|
|
55
57
|
lookup_destination: (query) => Effect.flatMap(DestinationGuide, (guide) => guide.lookup(query)),
|
|
56
58
|
});
|
|
@@ -66,7 +68,7 @@ export class DestinationReport extends Schema.Class<DestinationReport>("Destinat
|
|
|
66
68
|
advisory: Schema.NonEmptyString,
|
|
67
69
|
}) {}
|
|
68
70
|
|
|
69
|
-
export const DestinationResearcher = Agent.
|
|
71
|
+
export const DestinationResearcher = Agent.make("destination-researcher", {
|
|
70
72
|
input: DestinationBrief,
|
|
71
73
|
output: DestinationReport,
|
|
72
74
|
instructions:
|
|
@@ -112,6 +114,7 @@ export const destinationLookup = (
|
|
|
112
114
|
query: DestinationQuery,
|
|
113
115
|
): Effect.Effect<DestinationFacts, DestinationGuideUnavailable> => {
|
|
114
116
|
const facts = guideFacts.get(query.destination);
|
|
117
|
+
|
|
115
118
|
return facts === undefined
|
|
116
119
|
? Effect.fail(
|
|
117
120
|
DestinationGuideUnavailable.make({
|
|
@@ -124,15 +127,18 @@ export const destinationLookup = (
|
|
|
124
127
|
|
|
125
128
|
const requireDestinationFacts = (destination: string): DestinationFacts => {
|
|
126
129
|
const facts = guideFacts.get(destination);
|
|
130
|
+
|
|
127
131
|
if (facts === undefined) {
|
|
128
132
|
throw new Error(`No deterministic guide entry exists for destination ${destination}`);
|
|
129
133
|
}
|
|
134
|
+
|
|
130
135
|
return facts;
|
|
131
136
|
};
|
|
132
137
|
|
|
133
138
|
/** The report the scripted researcher writes after consulting the guide. */
|
|
134
139
|
export const destinationReportFor = (destination: string): DestinationReport => {
|
|
135
140
|
const facts = requireDestinationFacts(destination);
|
|
141
|
+
|
|
136
142
|
return DestinationReport.make({
|
|
137
143
|
destination: facts.destination,
|
|
138
144
|
highlights: facts.highlights,
|
|
@@ -147,7 +153,9 @@ export const DestinationGuideLayer = Layer.effect(
|
|
|
147
153
|
DestinationGuide,
|
|
148
154
|
Effect.gen(function* () {
|
|
149
155
|
const lifecycle = yield* CatalogLifecycle;
|
|
156
|
+
|
|
150
157
|
yield* Effect.acquireRelease(lifecycle.markAcquired, () => lifecycle.markFinalized);
|
|
158
|
+
|
|
151
159
|
return DestinationGuide.of({ lookup: destinationLookup });
|
|
152
160
|
}),
|
|
153
161
|
);
|
|
@@ -159,7 +167,7 @@ export const DestinationResearchSupportLayer = Layer.mergeAll(
|
|
|
159
167
|
);
|
|
160
168
|
|
|
161
169
|
// ---------------------------------------------------------------------------
|
|
162
|
-
// Delegation Definition
|
|
170
|
+
// Delegation Definition: the coordinator sees exactly
|
|
163
171
|
// one Effect AI Tool with explicit input/result projections and finite bounds.
|
|
164
172
|
// ---------------------------------------------------------------------------
|
|
165
173
|
|
|
@@ -189,7 +197,7 @@ export class DestinationResearchFailed extends Schema.TaggedError<DestinationRes
|
|
|
189
197
|
* this gate before the handler reserves budget or spawns, so tests can order
|
|
190
198
|
* concurrent delegation preflights without sleeps. It also keeps the
|
|
191
199
|
* projection's construction requirements honestly visible in the handler
|
|
192
|
-
* Layer's `R
|
|
200
|
+
* Layer's `R`. The open Layer never waits.
|
|
193
201
|
*/
|
|
194
202
|
export class ResearchDispatchGate extends Context.Service<
|
|
195
203
|
ResearchDispatchGate,
|
|
@@ -224,14 +232,16 @@ export const destinationResearchDelegation = Subagent.define("delegate_destinati
|
|
|
224
232
|
prepareInput: (request) =>
|
|
225
233
|
Effect.gen(function* () {
|
|
226
234
|
const gate = yield* ResearchDispatchGate;
|
|
235
|
+
|
|
227
236
|
yield* gate.awaitDispatch(request.destination);
|
|
237
|
+
|
|
228
238
|
return DestinationBrief.make({
|
|
229
239
|
destination: request.destination,
|
|
230
240
|
focus: `research:${request.focus}`,
|
|
231
241
|
});
|
|
232
242
|
}),
|
|
233
243
|
// The explicit declassification boundary (SUB-015): only the advisory
|
|
234
|
-
// crosses to the parent; guide highlights stay in the child
|
|
244
|
+
// crosses to the parent; guide highlights stay in the child Thread.
|
|
235
245
|
projectResult: (report) =>
|
|
236
246
|
Effect.succeed(
|
|
237
247
|
DestinationResearchFindings.make({
|
|
@@ -292,7 +302,7 @@ export const missionConfidentialMarker = "traveler-dossier-19f";
|
|
|
292
302
|
|
|
293
303
|
export const TravelCoordinatorToolkit = Toolkit.make(destinationResearchDelegation.tool);
|
|
294
304
|
|
|
295
|
-
export const TravelCoordinator = Agent.
|
|
305
|
+
export const TravelCoordinator = Agent.make("travel-coordinator", {
|
|
296
306
|
input: ResearchMission,
|
|
297
307
|
output: DestinationShortlist,
|
|
298
308
|
instructions: [
|
|
@@ -314,7 +324,7 @@ export const TravelCoordinator = Agent.define("travel-coordinator", {
|
|
|
314
324
|
});
|
|
315
325
|
|
|
316
326
|
export const researchMission = Schema.decodeSync(ResearchMission)({
|
|
317
|
-
request: `Shortlist one September culture city; keep ${missionConfidentialMarker} inside the coordinator
|
|
327
|
+
request: `Shortlist one September culture city; keep ${missionConfidentialMarker} inside the coordinator thread.`,
|
|
318
328
|
candidates: ["LHR", "CDG"],
|
|
319
329
|
});
|
|
320
330
|
|
|
@@ -461,19 +471,23 @@ export const makeDestinationResearcherModel = (destinations: ReadonlyArray<strin
|
|
|
461
471
|
const lifecycle = yield* CatalogLifecycle;
|
|
462
472
|
const prompts = yield* Ref.make<ReadonlyArray<string>>([]);
|
|
463
473
|
const gates = new Map<string, ResearcherGates>();
|
|
474
|
+
|
|
464
475
|
for (const destination of destinations) {
|
|
465
476
|
gates.set(destination, {
|
|
466
477
|
started: yield* Deferred.make<void>(),
|
|
467
478
|
release: yield* Deferred.make<void>(),
|
|
468
479
|
});
|
|
469
480
|
}
|
|
481
|
+
|
|
470
482
|
const gatesFor = (destination: string): Effect.Effect<ResearcherGates> =>
|
|
471
483
|
Effect.suspend(() => {
|
|
472
484
|
const entry = gates.get(destination);
|
|
485
|
+
|
|
473
486
|
return entry === undefined
|
|
474
487
|
? Effect.die(new Error(`No researcher gates exist for destination ${destination}`))
|
|
475
488
|
: Effect.succeed(entry);
|
|
476
489
|
});
|
|
490
|
+
|
|
477
491
|
const controls: DestinationResearcherControls = {
|
|
478
492
|
awaitStarted: (destination) =>
|
|
479
493
|
gatesFor(destination).pipe(Effect.flatMap((entry) => Deferred.await(entry.started))),
|
|
@@ -484,6 +498,7 @@ export const makeDestinationResearcherModel = (destinations: ReadonlyArray<strin
|
|
|
484
498
|
),
|
|
485
499
|
prompts: Ref.get(prompts),
|
|
486
500
|
};
|
|
501
|
+
|
|
487
502
|
const model = Model.make(
|
|
488
503
|
"scripted",
|
|
489
504
|
"destination-researcher-scripted",
|
|
@@ -492,15 +507,18 @@ export const makeDestinationResearcherModel = (destinations: ReadonlyArray<strin
|
|
|
492
507
|
Effect.gen(function* () {
|
|
493
508
|
yield* Effect.acquireRelease(lifecycle.markAcquired, () => lifecycle.markFinalized);
|
|
494
509
|
const turn = yield* Ref.make(0);
|
|
510
|
+
|
|
495
511
|
return yield* LanguageModel.make({
|
|
496
512
|
generateText: () => Effect.succeed([]),
|
|
497
513
|
streamText: (options) =>
|
|
498
514
|
Stream.unwrap(
|
|
499
515
|
Effect.gen(function* () {
|
|
500
516
|
const promptJson = JSON.stringify(options.prompt.content);
|
|
517
|
+
|
|
501
518
|
const destination = destinations.find((candidate) =>
|
|
502
519
|
promptJson.includes(candidate),
|
|
503
520
|
);
|
|
521
|
+
|
|
504
522
|
if (destination === undefined) {
|
|
505
523
|
return yield* Effect.die(
|
|
506
524
|
new Error("The researcher prompt names no scripted destination"),
|
|
@@ -508,12 +526,15 @@ export const makeDestinationResearcherModel = (destinations: ReadonlyArray<strin
|
|
|
508
526
|
}
|
|
509
527
|
const entry = yield* gatesFor(destination);
|
|
510
528
|
const index = yield* Ref.getAndUpdate(turn, (value) => value + 1);
|
|
529
|
+
|
|
511
530
|
if (index === 0) {
|
|
512
531
|
yield* Ref.update(prompts, (previous) => [...previous, promptJson]);
|
|
513
532
|
yield* Deferred.succeed(entry.started, undefined);
|
|
533
|
+
|
|
514
534
|
return Stream.fromIterable(researcherLookupParts(destination));
|
|
515
535
|
}
|
|
516
536
|
yield* Deferred.await(entry.release);
|
|
537
|
+
|
|
517
538
|
return Stream.fromIterable(researcherReportParts(destination));
|
|
518
539
|
}),
|
|
519
540
|
),
|
|
@@ -521,5 +542,6 @@ export const makeDestinationResearcherModel = (destinations: ReadonlyArray<strin
|
|
|
521
542
|
}),
|
|
522
543
|
),
|
|
523
544
|
);
|
|
545
|
+
|
|
524
546
|
return { controls, model };
|
|
525
547
|
});
|
package/src/index.ts
CHANGED
|
@@ -1,11 +1 @@
|
|
|
1
|
-
export * from "./
|
|
2
|
-
export * from "./chaos.ts";
|
|
3
|
-
export * from "./code-executor-conformance.ts";
|
|
4
|
-
export * from "./code-executor-substitute.ts";
|
|
5
|
-
export * from "./fixtures/docs-researcher/index.ts";
|
|
6
|
-
export * from "./fixtures/travel-planner/index.ts";
|
|
7
|
-
// The warehouse fixture is NOT re-exported here: it depends on
|
|
8
|
-
// `@effect/sql-sqlite-node` (`node:sqlite`), which workerd consumers of this
|
|
9
|
-
// barrel (the Cloudflare certification suites) cannot load. Import it
|
|
10
|
-
// directly from `@effect-agent/testing/src/fixtures/warehouse/index.ts`.
|
|
11
|
-
export * from "./scripted-model.ts";
|
|
1
|
+
export * as ScriptedModel from "./ScriptedModel.ts";
|