@cef-ai/testing 0.1.0

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 (78) hide show
  1. package/README.md +132 -0
  2. package/dist/harness/clock.d.ts +26 -0
  3. package/dist/harness/clock.d.ts.map +1 -0
  4. package/dist/harness/clock.js +17 -0
  5. package/dist/harness/clock.js.map +1 -0
  6. package/dist/harness/cubby.d.ts +57 -0
  7. package/dist/harness/cubby.d.ts.map +1 -0
  8. package/dist/harness/cubby.js +94 -0
  9. package/dist/harness/cubby.js.map +1 -0
  10. package/dist/harness/dispatch.d.ts +31 -0
  11. package/dist/harness/dispatch.d.ts.map +1 -0
  12. package/dist/harness/dispatch.js +37 -0
  13. package/dist/harness/dispatch.js.map +1 -0
  14. package/dist/harness/fetch-mock.d.ts +43 -0
  15. package/dist/harness/fetch-mock.d.ts.map +1 -0
  16. package/dist/harness/fetch-mock.js +58 -0
  17. package/dist/harness/fetch-mock.js.map +1 -0
  18. package/dist/harness/lifecycle.d.ts +29 -0
  19. package/dist/harness/lifecycle.d.ts.map +1 -0
  20. package/dist/harness/lifecycle.js +37 -0
  21. package/dist/harness/lifecycle.js.map +1 -0
  22. package/dist/harness/model-mock.d.ts +49 -0
  23. package/dist/harness/model-mock.d.ts.map +1 -0
  24. package/dist/harness/model-mock.js +56 -0
  25. package/dist/harness/model-mock.js.map +1 -0
  26. package/dist/harness/publish.d.ts +29 -0
  27. package/dist/harness/publish.d.ts.map +1 -0
  28. package/dist/harness/publish.js +20 -0
  29. package/dist/harness/publish.js.map +1 -0
  30. package/dist/harness/replay.d.ts +32 -0
  31. package/dist/harness/replay.d.ts.map +1 -0
  32. package/dist/harness/replay.js +72 -0
  33. package/dist/harness/replay.js.map +1 -0
  34. package/dist/harness/snapshot.d.ts +44 -0
  35. package/dist/harness/snapshot.d.ts.map +1 -0
  36. package/dist/harness/snapshot.js +58 -0
  37. package/dist/harness/snapshot.js.map +1 -0
  38. package/dist/index.d.ts +9 -0
  39. package/dist/index.d.ts.map +1 -0
  40. package/dist/index.js +4 -0
  41. package/dist/index.js.map +1 -0
  42. package/dist/peers/from-marketplace.d.ts +19 -0
  43. package/dist/peers/from-marketplace.d.ts.map +1 -0
  44. package/dist/peers/from-marketplace.js +22 -0
  45. package/dist/peers/from-marketplace.js.map +1 -0
  46. package/dist/peers/mock-agent.d.ts +108 -0
  47. package/dist/peers/mock-agent.d.ts.map +1 -0
  48. package/dist/peers/mock-agent.js +113 -0
  49. package/dist/peers/mock-agent.js.map +1 -0
  50. package/dist/platform/event-runtime.d.ts +28 -0
  51. package/dist/platform/event-runtime.d.ts.map +1 -0
  52. package/dist/platform/event-runtime.js +38 -0
  53. package/dist/platform/event-runtime.js.map +1 -0
  54. package/dist/platform/orchestrator.d.ts +86 -0
  55. package/dist/platform/orchestrator.d.ts.map +1 -0
  56. package/dist/platform/orchestrator.js +164 -0
  57. package/dist/platform/orchestrator.js.map +1 -0
  58. package/dist/platform/runtime.d.ts +66 -0
  59. package/dist/platform/runtime.d.ts.map +1 -0
  60. package/dist/platform/runtime.js +116 -0
  61. package/dist/platform/runtime.js.map +1 -0
  62. package/dist/platform/targeting.d.ts +29 -0
  63. package/dist/platform/targeting.d.ts.map +1 -0
  64. package/dist/platform/targeting.js +64 -0
  65. package/dist/platform/targeting.js.map +1 -0
  66. package/dist/platform/vault.d.ts +185 -0
  67. package/dist/platform/vault.d.ts.map +1 -0
  68. package/dist/platform/vault.js +200 -0
  69. package/dist/platform/vault.js.map +1 -0
  70. package/dist/test-agent.d.ts +137 -0
  71. package/dist/test-agent.d.ts.map +1 -0
  72. package/dist/test-agent.js +223 -0
  73. package/dist/test-agent.js.map +1 -0
  74. package/dist/test-platform.d.ts +167 -0
  75. package/dist/test-platform.d.ts.map +1 -0
  76. package/dist/test-platform.js +352 -0
  77. package/dist/test-platform.js.map +1 -0
  78. package/package.json +28 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../src/platform/runtime.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Runtime targeting evaluator.
3
+ *
4
+ * Mirrors the build-time validator: `targeting.engagements[]` is sorted by
5
+ * `priority` (lower = higher priority), then within the top-priority tier
6
+ * a weighted-random selection picks one (per `prototype.md` §"Targeting on
7
+ * the Manifest body" and the legacy `Deployment.Engagements` evaluator).
8
+ *
9
+ * The simulator treats `limit` rules as advisory in v1 — daily UTC caps
10
+ * are persistence-heavy and out of scope for the in-memory test platform.
11
+ * Production targeting honours them via the Redis-backed counter; tests
12
+ * that need to assert limit behaviour should use mock platform options.
13
+ */
14
+ import type { Targeting } from "@cef-ai/agent-sdk";
15
+ /**
16
+ * Pick an engagement id from `targeting.engagements[]` against the runtime
17
+ * settings. Settings are accepted for parity with prototype.md (future
18
+ * predicate-based rules) but are unused by the v1 priority/weight vocabulary.
19
+ *
20
+ * Selection algorithm:
21
+ * 1. Resolve every entry's `(priority, weight)` (defaults: 0, 100).
22
+ * 2. Group by priority; pick the lowest priority value (highest priority).
23
+ * 3. Within that tier, weighted-random pick by `weight`.
24
+ *
25
+ * Throws when `targeting.engagements[]` is empty — the caller should have
26
+ * defaulted it during config validation.
27
+ */
28
+ export declare function evaluateTargeting(targeting: Targeting, _settings: Record<string, unknown>, rng?: () => number): string;
29
+ //# sourceMappingURL=targeting.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"targeting.d.ts","sourceRoot":"","sources":["../../src/platform/targeting.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAQ,SAAS,EAAuB,MAAM,mBAAmB,CAAC;AAyB9E;;;;;;;;;;;;GAYG;AACH,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,SAAS,EACpB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAClC,GAAG,GAAE,MAAM,MAAoB,GAC9B,MAAM,CAmBR"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Runtime targeting evaluator.
3
+ *
4
+ * Mirrors the build-time validator: `targeting.engagements[]` is sorted by
5
+ * `priority` (lower = higher priority), then within the top-priority tier
6
+ * a weighted-random selection picks one (per `prototype.md` §"Targeting on
7
+ * the Manifest body" and the legacy `Deployment.Engagements` evaluator).
8
+ *
9
+ * The simulator treats `limit` rules as advisory in v1 — daily UTC caps
10
+ * are persistence-heavy and out of scope for the in-memory test platform.
11
+ * Production targeting honours them via the Redis-backed counter; tests
12
+ * that need to assert limit behaviour should use mock platform options.
13
+ */
14
+ const DEFAULT_PRIORITY = 0;
15
+ const DEFAULT_WEIGHT = 100;
16
+ function resolveRules(rules) {
17
+ let priority = DEFAULT_PRIORITY;
18
+ let weight = DEFAULT_WEIGHT;
19
+ for (const r of rules ?? []) {
20
+ if (r.name === "priority")
21
+ priority = r.value;
22
+ else if (r.name === "weight")
23
+ weight = r.value;
24
+ }
25
+ return { priority, weight };
26
+ }
27
+ function resolve(entry) {
28
+ return { id: entry.id, ...resolveRules(entry.rules) };
29
+ }
30
+ /**
31
+ * Pick an engagement id from `targeting.engagements[]` against the runtime
32
+ * settings. Settings are accepted for parity with prototype.md (future
33
+ * predicate-based rules) but are unused by the v1 priority/weight vocabulary.
34
+ *
35
+ * Selection algorithm:
36
+ * 1. Resolve every entry's `(priority, weight)` (defaults: 0, 100).
37
+ * 2. Group by priority; pick the lowest priority value (highest priority).
38
+ * 3. Within that tier, weighted-random pick by `weight`.
39
+ *
40
+ * Throws when `targeting.engagements[]` is empty — the caller should have
41
+ * defaulted it during config validation.
42
+ */
43
+ export function evaluateTargeting(targeting, _settings, rng = Math.random) {
44
+ if (!targeting.engagements || targeting.engagements.length === 0) {
45
+ throw new Error("[targeting] targeting.engagements is empty");
46
+ }
47
+ const resolved = targeting.engagements.map(resolve);
48
+ resolved.sort((a, b) => a.priority - b.priority);
49
+ const top = resolved[0].priority;
50
+ const tier = resolved.filter((r) => r.priority === top);
51
+ if (tier.length === 1)
52
+ return tier[0].id;
53
+ const totalWeight = tier.reduce((s, r) => s + Math.max(0, r.weight), 0);
54
+ if (totalWeight <= 0)
55
+ return tier[0].id;
56
+ let pick = rng() * totalWeight;
57
+ for (const r of tier) {
58
+ pick -= Math.max(0, r.weight);
59
+ if (pick <= 0)
60
+ return r.id;
61
+ }
62
+ return tier[tier.length - 1].id;
63
+ }
64
+ //# sourceMappingURL=targeting.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"targeting.js","sourceRoot":"","sources":["../../src/platform/targeting.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,MAAM,gBAAgB,GAAG,CAAC,CAAC;AAC3B,MAAM,cAAc,GAAG,GAAG,CAAC;AAQ3B,SAAS,YAAY,CAAC,KAAyB;IAC7C,IAAI,QAAQ,GAAG,gBAAgB,CAAC;IAChC,IAAI,MAAM,GAAG,cAAc,CAAC;IAC5B,KAAK,MAAM,CAAC,IAAI,KAAK,IAAI,EAAE,EAAE,CAAC;QAC5B,IAAI,CAAC,CAAC,IAAI,KAAK,UAAU;YAAE,QAAQ,GAAG,CAAC,CAAC,KAAK,CAAC;aACzC,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ;YAAE,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC;IACjD,CAAC;IACD,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC;AAC9B,CAAC;AAED,SAAS,OAAO,CAAC,KAA0B;IACzC,OAAO,EAAE,EAAE,EAAE,KAAK,CAAC,EAAE,EAAE,GAAG,YAAY,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;AACxD,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,iBAAiB,CAC/B,SAAoB,EACpB,SAAkC,EAClC,MAAoB,IAAI,CAAC,MAAM;IAE/B,IAAI,CAAC,SAAS,CAAC,WAAW,IAAI,SAAS,CAAC,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACjE,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;IAChE,CAAC;IACD,MAAM,QAAQ,GAAG,SAAS,CAAC,WAAW,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACpD,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC;IACjD,MAAM,GAAG,GAAG,QAAQ,CAAC,CAAC,CAAE,CAAC,QAAQ,CAAC;IAClC,MAAM,IAAI,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,KAAK,GAAG,CAAC,CAAC;IAExD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC,CAAC,CAAE,CAAC,EAAE,CAAC;IAE1C,MAAM,WAAW,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC;IACxE,IAAI,WAAW,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC,CAAC,CAAE,CAAC,EAAE,CAAC;IACzC,IAAI,IAAI,GAAG,GAAG,EAAE,GAAG,WAAW,CAAC;IAC/B,KAAK,MAAM,CAAC,IAAI,IAAI,EAAE,CAAC;QACrB,IAAI,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC;QAC9B,IAAI,IAAI,IAAI,CAAC;YAAE,OAAO,CAAC,CAAC,EAAE,CAAC;IAC7B,CAAC;IACD,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,CAAE,CAAC,EAAE,CAAC;AACnC,CAAC"}
@@ -0,0 +1,185 @@
1
+ /**
2
+ * In-memory implementation of the vault-sdk surface for the multi-agent
3
+ * simulator.
4
+ *
5
+ * Provides the same shape app-side test code uses against the real
6
+ * vault-sdk — `vault.scope(...).publish/subscribe/stream`,
7
+ * `vault.agents.connect/disconnect/get/list`, `vault.jobs.list/get` — so
8
+ * fixtures can exercise an entire flow without a real vault server.
9
+ *
10
+ * Internally, every publish:
11
+ * 1. is recorded in the per-vault event log (powers `stream(ctx).events.list`);
12
+ * 2. is routed through the {@link EventRuntime} to subscribed agents;
13
+ * 3. is broadcast to any open `subscribe()` async iterators.
14
+ *
15
+ * The vault exposes a small `_terminate` back-channel used by `ctx.close()`
16
+ * inside the runtime. It's prefixed with `_` to mark it as platform-internal,
17
+ * not part of the public vault-sdk surface.
18
+ */
19
+ import type { EngagementMeta, Event, Targeting } from "@cef-ai/agent-sdk";
20
+ import type { TestCubby } from "../harness/cubby.js";
21
+ import type { EventRuntime } from "./event-runtime.js";
22
+ import type { Job, JobsFilter, Orchestrator } from "./orchestrator.js";
23
+ /**
24
+ * Per-engagement entry on a connection's manifest. Mirrors the shape an
25
+ * agent class exposes via {@link EngagementMeta} but lives at the engagement
26
+ * level rather than the agent level (per ADR-019).
27
+ */
28
+ export interface ConnectionEngagement {
29
+ id: string;
30
+ goal?: string;
31
+ /** Event type → method name on the engagement's instance. */
32
+ events: EngagementMeta["events"];
33
+ /** Method names for `@OnStart` / `@OnClose` (if declared). */
34
+ lifecycle?: EngagementMeta["lifecycle"];
35
+ }
36
+ /**
37
+ * Connection-level manifest. An agent contains multiple engagements (per
38
+ * ADR-019); `targeting` picks one at Job creation. Single-engagement agents
39
+ * collapse to one entry with id `"default"`.
40
+ */
41
+ export interface ConnectionManifest {
42
+ engagements: ConnectionEngagement[];
43
+ targeting: Targeting;
44
+ }
45
+ /**
46
+ * A live agent registration on the vault. The simulator stores the actual
47
+ * agent instance plus its synthesised manifest; production would only
48
+ * carry the manifest cid + connection token.
49
+ */
50
+ export interface AgentConnection {
51
+ agentId: string;
52
+ /**
53
+ * Engagement-aware manifest. Synthesised from a class's
54
+ * `ENGAGEMENT_METADATA` (single-engagement shorthand) or from a
55
+ * `mockAgent({...})` descriptor / multi-engagement registration. Dispatch
56
+ * code looks up handlers via `manifest.engagements[engagementId]` after
57
+ * targeting picks an engagement at Job creation.
58
+ */
59
+ manifest: ConnectionManifest;
60
+ /**
61
+ * Per-engagement instance map. Each value is the JS object whose methods
62
+ * are invoked when an event fires for that engagement.
63
+ */
64
+ engagementInstances: Record<string, object>;
65
+ /** Per-alias cubbies — populated lazily; kept on the vault platform. */
66
+ cubbies: Map<string, TestCubby>;
67
+ /** Frozen settings record visible to handlers via `ctx.settings`. */
68
+ settings: Record<string, unknown>;
69
+ }
70
+ /**
71
+ * Event as recorded in the vault log. Augments the SDK `Event` shape with
72
+ * the routing metadata (`vaultId`, `scope`, `context`) the simulator
73
+ * partitions on. ADR-019 H5: events are partitioned by user identity, with
74
+ * `vaultId` carrying the publishing user id so two users sharing a scope
75
+ * + context still see disjoint streams.
76
+ */
77
+ export interface VaultEvent extends Event<unknown> {
78
+ vaultId: string;
79
+ scope: string;
80
+ context: string;
81
+ }
82
+ export interface VaultPublishOptions {
83
+ /** Conversation/job context key. Defaults to the vault's default scope. */
84
+ context?: string;
85
+ /** Override the publisher identifier. Defaults to `"app"`. */
86
+ from?: string;
87
+ }
88
+ export interface VaultStream {
89
+ events: {
90
+ /** Synchronous read of all events recorded against `(scope, ctx)`. */
91
+ list(filter?: {
92
+ types?: string[];
93
+ }): VaultEvent[];
94
+ };
95
+ }
96
+ export interface VaultScope {
97
+ /**
98
+ * Publish an event. Resolves only after all directly-routed handlers
99
+ * (and any chained publishes they trigger) have settled — `await` is the
100
+ * test's drain primitive.
101
+ */
102
+ publish(eventType: string, payload: unknown, opts?: VaultPublishOptions): Promise<{
103
+ eventId: string;
104
+ }>;
105
+ /**
106
+ * Subscribe to live events on this scope. Returns an async iterable that
107
+ * yields each new {@link VaultEvent}. Optional `context` filter.
108
+ */
109
+ subscribe(opts?: {
110
+ context?: string;
111
+ }): AsyncIterable<VaultEvent>;
112
+ /**
113
+ * Open a "stream" view rooted at `(scope, context)`. Today only
114
+ * `events.list()` is implemented — enough for assertions in fixtures.
115
+ */
116
+ stream(context: string): VaultStream;
117
+ }
118
+ export interface VaultAgentsApi {
119
+ connect(opts: {
120
+ agentId: string;
121
+ manifestCid?: string;
122
+ settings?: Record<string, unknown>;
123
+ }): Promise<AgentConnection>;
124
+ disconnect(agentId: string): Promise<void>;
125
+ get(agentId: string): AgentConnection | undefined;
126
+ list(): AgentConnection[];
127
+ }
128
+ export interface VaultJobsApi {
129
+ list(filter?: JobsFilter): Job[];
130
+ get(jobId: string): Job | undefined;
131
+ }
132
+ export interface Vault {
133
+ vaultId: string;
134
+ scope(name: string): VaultScope;
135
+ agents: VaultAgentsApi;
136
+ jobs: VaultJobsApi;
137
+ /**
138
+ * Internal: terminate a job on the orchestrator. Exposed for the runtime's
139
+ * `ctx.close()` plumbing — not part of the public vault-sdk surface.
140
+ */
141
+ _terminate(jobId: string, reason: string, connection?: AgentConnection): Promise<void>;
142
+ }
143
+ export interface VaultOptions {
144
+ /**
145
+ * The user id this vault belongs to. ADR-019 H5: each user gets its own
146
+ * vault instance, and `vaultId` is stamped onto every published event so
147
+ * downstream filters partition correctly.
148
+ */
149
+ vaultId: string;
150
+ /** Default `scope` and `context` used when callers omit them. */
151
+ defaultScope?: string;
152
+ defaultContext?: string;
153
+ eventRuntime: EventRuntime;
154
+ orchestrator: Orchestrator;
155
+ clock: () => number;
156
+ /**
157
+ * Resolves the manifest + per-engagement instances for `agentId` at connect
158
+ * time. The platform owns this map (since classes need to be instantiated),
159
+ * so the vault delegates rather than reaching into the platform globals.
160
+ */
161
+ resolveAgent(agentId: string): {
162
+ manifest: ConnectionManifest;
163
+ engagementInstances: Record<string, object>;
164
+ } | undefined;
165
+ /**
166
+ * Per-`(user, agent)` cubbies — owned by the platform. The vault is given
167
+ * its own user's slice and binds each connection to its alias map without
168
+ * copying. Per the contract's instanceID derivation
169
+ * (`sha256(vaultId + "/" + scope + "/" + agentId + "/" + alias)`), cubby
170
+ * state is naturally partitioned by user.
171
+ */
172
+ cubbies: Map<string, Map<string, TestCubby>>;
173
+ /**
174
+ * Shared, append-only event log across all per-user vaults on the platform.
175
+ * Each event carries `vaultId`, so per-user `stream()` calls filter to
176
+ * only their own slice.
177
+ */
178
+ events: VaultEvent[];
179
+ }
180
+ /** Per-user accessor returned from `platform.user(id)` (ADR-019 H5). */
181
+ export interface UserAccessor {
182
+ vault: Vault;
183
+ }
184
+ export declare function createVault(opts: VaultOptions): Vault;
185
+ //# sourceMappingURL=vault.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vault.d.ts","sourceRoot":"","sources":["../../src/platform/vault.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,200 @@
1
+ /**
2
+ * In-memory implementation of the vault-sdk surface for the multi-agent
3
+ * simulator.
4
+ *
5
+ * Provides the same shape app-side test code uses against the real
6
+ * vault-sdk — `vault.scope(...).publish/subscribe/stream`,
7
+ * `vault.agents.connect/disconnect/get/list`, `vault.jobs.list/get` — so
8
+ * fixtures can exercise an entire flow without a real vault server.
9
+ *
10
+ * Internally, every publish:
11
+ * 1. is recorded in the per-vault event log (powers `stream(ctx).events.list`);
12
+ * 2. is routed through the {@link EventRuntime} to subscribed agents;
13
+ * 3. is broadcast to any open `subscribe()` async iterators.
14
+ *
15
+ * The vault exposes a small `_terminate` back-channel used by `ctx.close()`
16
+ * inside the runtime. It's prefixed with `_` to mark it as platform-internal,
17
+ * not part of the public vault-sdk surface.
18
+ */
19
+ export function createVault(opts) {
20
+ const { vaultId, defaultScope: _defaultScope = "default", defaultContext = "default", eventRuntime, orchestrator, clock, resolveAgent, cubbies, events, } = opts;
21
+ const connections = new Map();
22
+ /** Open `subscribe()` async iterators on this user's vault, keyed by scope name. */
23
+ const subscribers = new Map();
24
+ function makeScope(scopeName) {
25
+ return {
26
+ async publish(eventType, payload, publishOpts) {
27
+ const event = {
28
+ id: `evt-${randomHex(8)}`,
29
+ type: eventType,
30
+ ts: clock(),
31
+ from: publishOpts?.from ?? "app",
32
+ payload,
33
+ vaultId,
34
+ scope: scopeName,
35
+ context: publishOpts?.context ?? defaultContext,
36
+ };
37
+ events.push(event);
38
+ // Notify async-iterator subscribers first so `for await` consumers
39
+ // see the event before any handler-published downstream events.
40
+ const subs = subscribers.get(scopeName);
41
+ if (subs) {
42
+ for (const s of subs) {
43
+ if (!s.contextFilter || s.contextFilter === event.context) {
44
+ s.push(event);
45
+ }
46
+ }
47
+ }
48
+ // Route through the orchestrator (sequential per event-runtime).
49
+ // Only this user's connections receive the event — cross-user
50
+ // routing is NOT a thing in the simulator.
51
+ await eventRuntime.publish(event, connections.values());
52
+ return { eventId: event.id };
53
+ },
54
+ subscribe(subOpts) {
55
+ return makeAsyncIterable(scopeName, subOpts?.context, subscribers);
56
+ },
57
+ stream(context) {
58
+ return {
59
+ events: {
60
+ list(filter) {
61
+ return events.filter((e) => {
62
+ // Partition by vaultId so two users on the same scope +
63
+ // context see disjoint streams.
64
+ if (e.vaultId !== vaultId)
65
+ return false;
66
+ if (e.scope !== scopeName)
67
+ return false;
68
+ if (e.context !== context)
69
+ return false;
70
+ if (filter?.types && !filter.types.includes(e.type)) {
71
+ return false;
72
+ }
73
+ return true;
74
+ });
75
+ },
76
+ },
77
+ };
78
+ },
79
+ };
80
+ }
81
+ const vault = {
82
+ vaultId,
83
+ scope: makeScope,
84
+ agents: {
85
+ async connect(connectOpts) {
86
+ if (connections.has(connectOpts.agentId)) {
87
+ throw new Error(`[vault] agent "${connectOpts.agentId}" is already connected`);
88
+ }
89
+ const resolved = resolveAgent(connectOpts.agentId);
90
+ if (!resolved) {
91
+ throw new Error(`[vault] unknown agentId "${connectOpts.agentId}" — register it via testPlatform({ agents: ... })`);
92
+ }
93
+ if (!cubbies.has(connectOpts.agentId)) {
94
+ cubbies.set(connectOpts.agentId, new Map());
95
+ }
96
+ const conn = {
97
+ agentId: connectOpts.agentId,
98
+ manifest: resolved.manifest,
99
+ engagementInstances: resolved.engagementInstances,
100
+ cubbies: cubbies.get(connectOpts.agentId),
101
+ settings: connectOpts.settings ?? {},
102
+ };
103
+ connections.set(connectOpts.agentId, conn);
104
+ return conn;
105
+ },
106
+ async disconnect(agentId) {
107
+ connections.delete(agentId);
108
+ // Job state is preserved (terminal jobs stay queryable for
109
+ // assertions). Production would tear them down on disconnect; the
110
+ // simulator deliberately keeps history accessible.
111
+ },
112
+ get(agentId) {
113
+ return connections.get(agentId);
114
+ },
115
+ list() {
116
+ return [...connections.values()];
117
+ },
118
+ },
119
+ jobs: {
120
+ list: (f) => orchestrator.list({ ...f, vaultId }),
121
+ get: (id) => {
122
+ const job = orchestrator.get(id);
123
+ // Per-user `vault.jobs.get(id)` only sees this user's jobs.
124
+ return job && job.vaultId === vaultId ? job : undefined;
125
+ },
126
+ },
127
+ async _terminate(jobId, reason, connection) {
128
+ await orchestrator.terminate(jobId, reason, connection);
129
+ },
130
+ };
131
+ return vault;
132
+ }
133
+ /* -------------------------------------------------------------------------- */
134
+ /* Helpers */
135
+ /* -------------------------------------------------------------------------- */
136
+ /**
137
+ * Build a push-driven async iterable for `subscribe()`. New events arriving
138
+ * via `push(event)` resolve the next `for await` step; `end()` ends the
139
+ * stream. Backpressure is unbounded — fine for tests.
140
+ */
141
+ function makeAsyncIterable(scopeName, contextFilter, registry) {
142
+ return {
143
+ [Symbol.asyncIterator]() {
144
+ const queue = [];
145
+ let resolveNext;
146
+ let ended = false;
147
+ const sub = {
148
+ contextFilter,
149
+ push(event) {
150
+ if (resolveNext) {
151
+ const r = resolveNext;
152
+ resolveNext = undefined;
153
+ r({ value: event, done: false });
154
+ }
155
+ else {
156
+ queue.push(event);
157
+ }
158
+ },
159
+ end() {
160
+ ended = true;
161
+ if (resolveNext) {
162
+ const r = resolveNext;
163
+ resolveNext = undefined;
164
+ r({ value: undefined, done: true });
165
+ }
166
+ },
167
+ };
168
+ let set = registry.get(scopeName);
169
+ if (!set) {
170
+ set = new Set();
171
+ registry.set(scopeName, set);
172
+ }
173
+ set.add(sub);
174
+ return {
175
+ async next() {
176
+ if (queue.length > 0) {
177
+ return { value: queue.shift(), done: false };
178
+ }
179
+ if (ended) {
180
+ return { value: undefined, done: true };
181
+ }
182
+ return new Promise((resolve) => {
183
+ resolveNext = resolve;
184
+ });
185
+ },
186
+ async return() {
187
+ set.delete(sub);
188
+ ended = true;
189
+ return { value: undefined, done: true };
190
+ },
191
+ };
192
+ },
193
+ };
194
+ }
195
+ function randomHex(bytes) {
196
+ const buf = new Uint8Array(bytes);
197
+ globalThis.crypto.getRandomValues(buf);
198
+ return Array.from(buf, (b) => b.toString(16).padStart(2, "0")).join("");
199
+ }
200
+ //# sourceMappingURL=vault.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vault.js","sourceRoot":"","sources":["../../src/platform/vault.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,137 @@
1
+ /**
2
+ * `testAgent` — the single-agent simulator-mode harness.
3
+ *
4
+ * Wires together the pieces in `./harness/*` to produce a deterministic,
5
+ * in-process environment for an agent class:
6
+ *
7
+ * - dispatch a single event and capture its publishes;
8
+ * - drive `@OnStart` / `@OnClose` lifecycle hooks;
9
+ * - back `ctx.cubby` with per-alias in-memory SQLite (with optional
10
+ * migration directories);
11
+ * - back `ctx.fetch` with a URL-pattern mock;
12
+ * - back `ctx.models[alias]` with stubs or expectation builders;
13
+ * - thread an injectable clock through everything timestamp-related.
14
+ *
15
+ * Public surface mirrors `agent-sdk.md` §9. Two `close` concerns are
16
+ * separated: `harness.close(reason)` is the lifecycle hook, while
17
+ * `harness.dispose()` releases test resources (SQLite handles).
18
+ *
19
+ * Per ADR-019 H4 the harness is engagement-aware:
20
+ * - single-class shorthand `testAgent(SomeClass, opts)` produces one
21
+ * engagement with id `"default"` (or `meta.id` from `@Engagement` if set)
22
+ * — equivalent to the pre-H4 behaviour for back-compat;
23
+ * - multi-engagement form `testAgent({ engagements: [...], targeting? }, opts)`
24
+ * accepts multiple source classes plus a targeting decision table; the
25
+ * harness evaluates targeting on first dispatch (or first start/close),
26
+ * pins the chosen engagement for the harness's life, and routes to that
27
+ * engagement's instance.
28
+ */
29
+ import { type CubbyHandle, type ModelHandle, type OnCloseReason, type Targeting } from "@cef-ai/agent-sdk";
30
+ import type Database from "better-sqlite3";
31
+ import { type PublishedEvent } from "./harness/publish.js";
32
+ import { type FetchMock } from "./harness/fetch-mock.js";
33
+ import { type ModelMockHandle } from "./harness/model-mock.js";
34
+ import { type HarnessSnapshot } from "./harness/snapshot.js";
35
+ import { type ReplayResult } from "./harness/replay.js";
36
+ /**
37
+ * Spec for a cubby alias. The plain-string form is shorthand for
38
+ * `{ alias }` with no migrations — handy for tests that drive schema
39
+ * via raw `harness.cubby(alias).exec(...)` calls.
40
+ */
41
+ export type CubbySpec = string | {
42
+ alias: string;
43
+ migrations?: string;
44
+ };
45
+ export interface TestHarnessOptions {
46
+ /** Seed `ctx.settings`. Frozen on installation. */
47
+ settings?: Record<string, unknown>;
48
+ /** Per-alias SQLite cubbies to make available via `ctx.cubby`. */
49
+ cubbies?: CubbySpec[];
50
+ /** Seed `ctx.models[alias]`. Accepts plain stubs or `createModelMock()` handles. */
51
+ models?: Record<string, ModelHandle | ModelMockHandle>;
52
+ /** Initial wall-clock time in unix-millis. Defaults to `Date.now()`. */
53
+ clock?: {
54
+ now?: number;
55
+ };
56
+ }
57
+ /**
58
+ * Result published during a `dispatch()` call (or any other ctx.publish
59
+ * invocation, e.g. from start/close hooks).
60
+ */
61
+ export type { PublishedEvent };
62
+ export type { HarnessSnapshot, ReplayResult };
63
+ /** Agent class with `@OnEvent` / `@OnStart` / `@OnClose` decorators. */
64
+ export type AgentCtor = new (...args: unknown[]) => Record<string, unknown>;
65
+ /** Multi-engagement form for `testAgent({ engagements: [...] }, opts)`. */
66
+ export interface TestAgentMultiSpec {
67
+ engagements: Array<{
68
+ id: string;
69
+ source: AgentCtor;
70
+ goal?: string;
71
+ }>;
72
+ /** Targeting decision table; defaults to `{ rules: [], default: <first id> }`. */
73
+ targeting?: Targeting;
74
+ }
75
+ export interface TestHarness {
76
+ /** Drive a single event through the agent. Returns publishes from this call only. */
77
+ dispatch(input: {
78
+ type: string;
79
+ payload?: unknown;
80
+ from?: string;
81
+ }): Promise<PublishedEvent[]>;
82
+ /** All publishes captured since harness construction. */
83
+ published: PublishedEvent[];
84
+ /** Look up a cubby by alias. Throws if the alias was not declared. */
85
+ cubby(alias: string): CubbyHandle;
86
+ /**
87
+ * Run `fn` with both the public {@link CubbyHandle} surface and the
88
+ * underlying `better-sqlite3` database. Useful for tests that need
89
+ * synchronous, prepared-statement-style assertions without the async
90
+ * `query` indirection.
91
+ */
92
+ runInCubby<T>(alias: string, fn: (handle: CubbyHandle, raw: Database.Database) => T | Promise<T>): Promise<T>;
93
+ /** Snapshot every cubby + the published log + the clock. See {@link HarnessSnapshot}. */
94
+ snapshot(): HarnessSnapshot;
95
+ /** Restore a previously captured snapshot. Mutates in place. */
96
+ restore(snap: HarnessSnapshot): void;
97
+ /**
98
+ * Replay a JSONL fixture of platform events through the harness. Each
99
+ * line must be a JSON object with at least a `type` field; `payload` and
100
+ * `from` are forwarded.
101
+ */
102
+ replay(jsonlPath: string): Promise<ReplayResult>;
103
+ /** Run the agent's `@OnStart` hook, transitioning to `started`. */
104
+ start(): Promise<void>;
105
+ /** Run the agent's `@OnClose` hook with `reason`, transitioning to `closed`. */
106
+ close(reason?: OnCloseReason | string): Promise<void>;
107
+ /** Externally observable lifecycle state. */
108
+ lifecycle: {
109
+ state: "idle" | "started" | "closed";
110
+ terminalReason?: OnCloseReason | string;
111
+ };
112
+ /**
113
+ * The engagement id this harness is bound to. For single-class harnesses
114
+ * this is set at construction (matching the class's `@Engagement(id)` or
115
+ * `"default"`). For multi-engagement harnesses this is `undefined` until
116
+ * the first dispatch / start / close, when targeting picks one.
117
+ */
118
+ engagement: string | undefined;
119
+ /** Move the harness clock forward by `ms`. */
120
+ advanceTime(ms: number): void;
121
+ /** Read the current harness clock. */
122
+ now(): number;
123
+ /** URL-pattern fetch mock attached to `ctx.fetch`. */
124
+ fetchMock(): FetchMock;
125
+ /** Map of model handles attached to `ctx.models`. */
126
+ models: Record<string, ModelHandle | ModelMockHandle>;
127
+ /** Release SQLite handles and other test resources. Idempotent. */
128
+ dispose(): void;
129
+ }
130
+ /**
131
+ * Build a `testAgent` harness for either a single agent class or a
132
+ * multi-engagement spec. The two overloads share the same {@link TestHarness}
133
+ * surface.
134
+ */
135
+ export declare function testAgent(AgentClass: AgentCtor, opts?: TestHarnessOptions): TestHarness;
136
+ export declare function testAgent(spec: TestAgentMultiSpec, opts?: TestHarnessOptions): TestHarness;
137
+ //# sourceMappingURL=test-agent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-agent.d.ts","sourceRoot":"","sources":["../src/test-agent.ts"],"names":[],"mappings":"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"}