@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.
- package/README.md +132 -0
- package/dist/harness/clock.d.ts +26 -0
- package/dist/harness/clock.d.ts.map +1 -0
- package/dist/harness/clock.js +17 -0
- package/dist/harness/clock.js.map +1 -0
- package/dist/harness/cubby.d.ts +57 -0
- package/dist/harness/cubby.d.ts.map +1 -0
- package/dist/harness/cubby.js +94 -0
- package/dist/harness/cubby.js.map +1 -0
- package/dist/harness/dispatch.d.ts +31 -0
- package/dist/harness/dispatch.d.ts.map +1 -0
- package/dist/harness/dispatch.js +37 -0
- package/dist/harness/dispatch.js.map +1 -0
- package/dist/harness/fetch-mock.d.ts +43 -0
- package/dist/harness/fetch-mock.d.ts.map +1 -0
- package/dist/harness/fetch-mock.js +58 -0
- package/dist/harness/fetch-mock.js.map +1 -0
- package/dist/harness/lifecycle.d.ts +29 -0
- package/dist/harness/lifecycle.d.ts.map +1 -0
- package/dist/harness/lifecycle.js +37 -0
- package/dist/harness/lifecycle.js.map +1 -0
- package/dist/harness/model-mock.d.ts +49 -0
- package/dist/harness/model-mock.d.ts.map +1 -0
- package/dist/harness/model-mock.js +56 -0
- package/dist/harness/model-mock.js.map +1 -0
- package/dist/harness/publish.d.ts +29 -0
- package/dist/harness/publish.d.ts.map +1 -0
- package/dist/harness/publish.js +20 -0
- package/dist/harness/publish.js.map +1 -0
- package/dist/harness/replay.d.ts +32 -0
- package/dist/harness/replay.d.ts.map +1 -0
- package/dist/harness/replay.js +72 -0
- package/dist/harness/replay.js.map +1 -0
- package/dist/harness/snapshot.d.ts +44 -0
- package/dist/harness/snapshot.d.ts.map +1 -0
- package/dist/harness/snapshot.js +58 -0
- package/dist/harness/snapshot.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/peers/from-marketplace.d.ts +19 -0
- package/dist/peers/from-marketplace.d.ts.map +1 -0
- package/dist/peers/from-marketplace.js +22 -0
- package/dist/peers/from-marketplace.js.map +1 -0
- package/dist/peers/mock-agent.d.ts +108 -0
- package/dist/peers/mock-agent.d.ts.map +1 -0
- package/dist/peers/mock-agent.js +113 -0
- package/dist/peers/mock-agent.js.map +1 -0
- package/dist/platform/event-runtime.d.ts +28 -0
- package/dist/platform/event-runtime.d.ts.map +1 -0
- package/dist/platform/event-runtime.js +38 -0
- package/dist/platform/event-runtime.js.map +1 -0
- package/dist/platform/orchestrator.d.ts +86 -0
- package/dist/platform/orchestrator.d.ts.map +1 -0
- package/dist/platform/orchestrator.js +164 -0
- package/dist/platform/orchestrator.js.map +1 -0
- package/dist/platform/runtime.d.ts +66 -0
- package/dist/platform/runtime.d.ts.map +1 -0
- package/dist/platform/runtime.js +116 -0
- package/dist/platform/runtime.js.map +1 -0
- package/dist/platform/targeting.d.ts +29 -0
- package/dist/platform/targeting.d.ts.map +1 -0
- package/dist/platform/targeting.js +64 -0
- package/dist/platform/targeting.js.map +1 -0
- package/dist/platform/vault.d.ts +185 -0
- package/dist/platform/vault.d.ts.map +1 -0
- package/dist/platform/vault.js +200 -0
- package/dist/platform/vault.js.map +1 -0
- package/dist/test-agent.d.ts +137 -0
- package/dist/test-agent.d.ts.map +1 -0
- package/dist/test-agent.js +223 -0
- package/dist/test-agent.js.map +1 -0
- package/dist/test-platform.d.ts +167 -0
- package/dist/test-platform.d.ts.map +1 -0
- package/dist/test-platform.js +352 -0
- package/dist/test-platform.js.map +1 -0
- package/package.json +28 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Typed model mocks for `ctx.models[alias]`.
|
|
3
|
+
*
|
|
4
|
+
* Two ways to use:
|
|
5
|
+
*
|
|
6
|
+
* 1. Plain stub — pass any object that implements `ModelHandle` (i.e.
|
|
7
|
+
* `{ infer, stream }`) directly via `opts.models`. Simplest path,
|
|
8
|
+
* good for one-off inputs.
|
|
9
|
+
*
|
|
10
|
+
* 2. Expectation form — `createModelMock()` returns a {@link ModelMockHandle}
|
|
11
|
+
* with `.expect(input).respond(output)`. The next `infer` call
|
|
12
|
+
* whose input deep-equals an expectation returns its output. Used
|
|
13
|
+
* via `harness.models.<alias>.expect(...)` after construction.
|
|
14
|
+
*
|
|
15
|
+
* Expectations are matched by `JSON.stringify` deep-equality. That covers
|
|
16
|
+
* the typical "send-this-prompt → return-this-text" case without pulling
|
|
17
|
+
* in a deep-equal library; richer matching (regex, partial-match) lives
|
|
18
|
+
* outside D1.
|
|
19
|
+
*/
|
|
20
|
+
import type { ModelHandle } from "@cef-ai/agent-sdk";
|
|
21
|
+
/**
|
|
22
|
+
* Mock handle returned by {@link createModelMock}. Behaves as a real
|
|
23
|
+
* `ModelHandle` for handler code, plus exposes `.expect()` and `.calls`
|
|
24
|
+
* for tests.
|
|
25
|
+
*/
|
|
26
|
+
export interface ModelMockHandle extends ModelHandle {
|
|
27
|
+
/** Register an expected input → output pair. Most-recent wins on duplicates. */
|
|
28
|
+
expect(input: unknown): {
|
|
29
|
+
respond: (output: unknown) => void;
|
|
30
|
+
};
|
|
31
|
+
/** Recorded invocations. */
|
|
32
|
+
calls: Array<{
|
|
33
|
+
method: "infer" | "stream";
|
|
34
|
+
input: unknown;
|
|
35
|
+
}>;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Build an expectation-style model mock. The same handle satisfies the
|
|
39
|
+
* runtime's `ModelHandle` shape so it can be passed via `opts.models`
|
|
40
|
+
* unchanged.
|
|
41
|
+
*/
|
|
42
|
+
export declare function createModelMock(): ModelMockHandle;
|
|
43
|
+
/**
|
|
44
|
+
* Type-guard: does `m` look like a `ModelHandle`? Used by the harness to
|
|
45
|
+
* accept both expectation-style mocks and plain stubs in `opts.models`
|
|
46
|
+
* without forcing the user to wrap them.
|
|
47
|
+
*/
|
|
48
|
+
export declare function isModelHandle(m: unknown): m is ModelHandle;
|
|
49
|
+
//# sourceMappingURL=model-mock.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-mock.d.ts","sourceRoot":"","sources":["../../src/harness/model-mock.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAErD;;;;GAIG;AACH,MAAM,WAAW,eAAgB,SAAQ,WAAW;IAClD,gFAAgF;IAChF,MAAM,CAAC,KAAK,EAAE,OAAO,GAAG;QAAE,OAAO,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,IAAI,CAAA;KAAE,CAAC;IAC/D,4BAA4B;IAC5B,KAAK,EAAE,KAAK,CAAC;QAAE,MAAM,EAAE,OAAO,GAAG,QAAQ,CAAC;QAAC,KAAK,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;CAC9D;AAED;;;;GAIG;AACH,wBAAgB,eAAe,IAAI,eAAe,CAyCjD;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,IAAI,WAAW,CAM1D"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build an expectation-style model mock. The same handle satisfies the
|
|
3
|
+
* runtime's `ModelHandle` shape so it can be passed via `opts.models`
|
|
4
|
+
* unchanged.
|
|
5
|
+
*/
|
|
6
|
+
export function createModelMock() {
|
|
7
|
+
const expectations = [];
|
|
8
|
+
const calls = [];
|
|
9
|
+
const findOutput = (input) => {
|
|
10
|
+
// Walk in reverse so a later `.expect()` call shadows an earlier one
|
|
11
|
+
// when the same input is registered twice — the typical test pattern.
|
|
12
|
+
for (let i = expectations.length - 1; i >= 0; i--) {
|
|
13
|
+
const e = expectations[i];
|
|
14
|
+
if (JSON.stringify(e.input) === JSON.stringify(input)) {
|
|
15
|
+
return e.output;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
throw new Error(`[modelMock] no expectation for input ${JSON.stringify(input)}`);
|
|
19
|
+
};
|
|
20
|
+
return {
|
|
21
|
+
calls,
|
|
22
|
+
expect(input) {
|
|
23
|
+
return {
|
|
24
|
+
respond(output) {
|
|
25
|
+
expectations.push({ input, output });
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
},
|
|
29
|
+
async infer(input) {
|
|
30
|
+
calls.push({ method: "infer", input });
|
|
31
|
+
return findOutput(input);
|
|
32
|
+
},
|
|
33
|
+
async *stream(input) {
|
|
34
|
+
calls.push({ method: "stream", input });
|
|
35
|
+
const output = findOutput(input);
|
|
36
|
+
if (Array.isArray(output)) {
|
|
37
|
+
for (const c of output)
|
|
38
|
+
yield c;
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
yield output;
|
|
42
|
+
}
|
|
43
|
+
},
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Type-guard: does `m` look like a `ModelHandle`? Used by the harness to
|
|
48
|
+
* accept both expectation-style mocks and plain stubs in `opts.models`
|
|
49
|
+
* without forcing the user to wrap them.
|
|
50
|
+
*/
|
|
51
|
+
export function isModelHandle(m) {
|
|
52
|
+
return (typeof m === "object" &&
|
|
53
|
+
m !== null &&
|
|
54
|
+
typeof m.infer === "function");
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=model-mock.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model-mock.js","sourceRoot":"","sources":["../../src/harness/model-mock.ts"],"names":[],"mappings":"AAiCA;;;;GAIG;AACH,MAAM,UAAU,eAAe;IAC7B,MAAM,YAAY,GAA+C,EAAE,CAAC;IACpE,MAAM,KAAK,GAA6B,EAAE,CAAC;IAE3C,MAAM,UAAU,GAAG,CAAC,KAAc,EAAW,EAAE;QAC7C,qEAAqE;QACrE,sEAAsE;QACtE,KAAK,IAAI,CAAC,GAAG,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YAClD,MAAM,CAAC,GAAG,YAAY,CAAC,CAAC,CAAE,CAAC;YAC3B,IAAI,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC;gBACtD,OAAO,CAAC,CAAC,MAAM,CAAC;YAClB,CAAC;QACH,CAAC;QACD,MAAM,IAAI,KAAK,CACb,wCAAwC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAChE,CAAC;IACJ,CAAC,CAAC;IAEF,OAAO;QACL,KAAK;QACL,MAAM,CAAC,KAAK;YACV,OAAO;gBACL,OAAO,CAAC,MAAM;oBACZ,YAAY,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;gBACvC,CAAC;aACF,CAAC;QACJ,CAAC;QACD,KAAK,CAAC,KAAK,CAAc,KAAc;YACrC,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;YACvC,OAAO,UAAU,CAAC,KAAK,CAAM,CAAC;QAChC,CAAC;QACD,KAAK,CAAC,CAAC,MAAM,CAAc,KAAc;YACvC,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;YACxC,MAAM,MAAM,GAAG,UAAU,CAAC,KAAK,CAAC,CAAC;YACjC,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC1B,KAAK,MAAM,CAAC,IAAI,MAAM;oBAAE,MAAM,CAAM,CAAC;YACvC,CAAC;iBAAM,CAAC;gBACN,MAAM,MAAW,CAAC;YACpB,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,CAAU;IACtC,OAAO,CACL,OAAO,CAAC,KAAK,QAAQ;QACrB,CAAC,KAAK,IAAI;QACV,OAAQ,CAAyB,CAAC,KAAK,KAAK,UAAU,CACvD,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Capture-only `ctx.publish` collector for the test harness.
|
|
3
|
+
*
|
|
4
|
+
* The harness intercepts published events into a plain array (no router,
|
|
5
|
+
* no peer dispatch) so tests can assert against `harness.published`
|
|
6
|
+
* directly. Every entry is timestamped with the harness clock, so
|
|
7
|
+
* `advanceTime` shows up in assertions.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* A single captured publish call.
|
|
11
|
+
*/
|
|
12
|
+
export interface PublishedEvent {
|
|
13
|
+
type: string;
|
|
14
|
+
payload: unknown;
|
|
15
|
+
/** Stamped from the harness clock at publish time. */
|
|
16
|
+
ts: number;
|
|
17
|
+
}
|
|
18
|
+
export interface PublishCollector {
|
|
19
|
+
/** Backing array — exposed by the harness as `harness.published`. */
|
|
20
|
+
events: PublishedEvent[];
|
|
21
|
+
/** Drop-in for `ctx.publish`; matches the SDK's signature. */
|
|
22
|
+
publish: (type: string, payload: unknown) => Promise<void>;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Build a publish collector. `now()` is injected so the same clock
|
|
26
|
+
* driving event dispatch also stamps captured publishes.
|
|
27
|
+
*/
|
|
28
|
+
export declare function createPublishCollector(now: () => number): PublishCollector;
|
|
29
|
+
//# sourceMappingURL=publish.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"publish.d.ts","sourceRoot":"","sources":["../../src/harness/publish.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,sDAAsD;IACtD,EAAE,EAAE,MAAM,CAAC;CACZ;AAED,MAAM,WAAW,gBAAgB;IAC/B,qEAAqE;IACrE,MAAM,EAAE,cAAc,EAAE,CAAC;IACzB,8DAA8D;IAC9D,OAAO,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5D;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,MAAM,GAAG,gBAAgB,CAM1E"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Capture-only `ctx.publish` collector for the test harness.
|
|
3
|
+
*
|
|
4
|
+
* The harness intercepts published events into a plain array (no router,
|
|
5
|
+
* no peer dispatch) so tests can assert against `harness.published`
|
|
6
|
+
* directly. Every entry is timestamped with the harness clock, so
|
|
7
|
+
* `advanceTime` shows up in assertions.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Build a publish collector. `now()` is injected so the same clock
|
|
11
|
+
* driving event dispatch also stamps captured publishes.
|
|
12
|
+
*/
|
|
13
|
+
export function createPublishCollector(now) {
|
|
14
|
+
const events = [];
|
|
15
|
+
const publish = async (type, payload) => {
|
|
16
|
+
events.push({ type, payload, ts: now() });
|
|
17
|
+
};
|
|
18
|
+
return { events, publish };
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=publish.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"publish.js","sourceRoot":"","sources":["../../src/harness/publish.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAmBH;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CAAC,GAAiB;IACtD,MAAM,MAAM,GAAqB,EAAE,CAAC;IACpC,MAAM,OAAO,GAAG,KAAK,EAAE,IAAY,EAAE,OAAgB,EAAiB,EAAE;QACtE,MAAM,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,EAAE,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC;IAC5C,CAAC,CAAC;IACF,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC;AAC7B,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { TestCubby } from "./cubby.js";
|
|
2
|
+
import type { PublishedEvent } from "./publish.js";
|
|
3
|
+
export interface ReplayResult {
|
|
4
|
+
/** Events the agent published during this replay only (not including pre-replay state). */
|
|
5
|
+
published: PublishedEvent[];
|
|
6
|
+
/**
|
|
7
|
+
* Per-cubby table-rowcount summary: `{ alias: { tableName: rowCount } }`.
|
|
8
|
+
* Includes every user table (sqlite internal tables are filtered out).
|
|
9
|
+
*/
|
|
10
|
+
cubbyState: Record<string, Record<string, number>>;
|
|
11
|
+
/** Wall-clock duration (`Date.now()` deltas, not the harness clock). */
|
|
12
|
+
durationMs: number;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Minimal harness surface `runReplay` needs. Kept structural so we don't
|
|
16
|
+
* import the full `TestHarness` type and create a circular reference.
|
|
17
|
+
*/
|
|
18
|
+
export interface ReplayHarness {
|
|
19
|
+
dispatch(input: {
|
|
20
|
+
type: string;
|
|
21
|
+
payload?: unknown;
|
|
22
|
+
from?: string;
|
|
23
|
+
}): Promise<PublishedEvent[]>;
|
|
24
|
+
published: PublishedEvent[];
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Drive a JSONL fixture through `harness.dispatch`. Blank lines are
|
|
28
|
+
* skipped. Each non-blank line must parse to an object with at least a
|
|
29
|
+
* `type` field; `payload` and `from` are forwarded verbatim.
|
|
30
|
+
*/
|
|
31
|
+
export declare function runReplay(harness: ReplayHarness, jsonlPath: string, cubbies: Map<string, TestCubby>): Promise<ReplayResult>;
|
|
32
|
+
//# sourceMappingURL=replay.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"replay.d.ts","sourceRoot":"","sources":["../../src/harness/replay.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEnD,MAAM,WAAW,YAAY;IAC3B,2FAA2F;IAC3F,SAAS,EAAE,cAAc,EAAE,CAAC;IAC5B;;;OAGG;IACH,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACnD,wEAAwE;IACxE,UAAU,EAAE,MAAM,CAAC;CACpB;AAED;;;GAGG;AACH,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,KAAK,EAAE;QACd,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,CAAC,EAAE,OAAO,CAAC;QAClB,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC;IAC9B,SAAS,EAAE,cAAc,EAAE,CAAC;CAC7B;AAED;;;;GAIG;AACH,wBAAsB,SAAS,CAC7B,OAAO,EAAE,aAAa,EACtB,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,GAC9B,OAAO,CAAC,YAAY,CAAC,CAmDvB"}
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSONL fixture replay for the test harness.
|
|
3
|
+
*
|
|
4
|
+
* Reads a newline-delimited JSON file of platform-event envelopes (the
|
|
5
|
+
* format `prototype.md` §4 specifies for `<scope>/<context>/events/N-events.json`)
|
|
6
|
+
* and dispatches each through the harness, producing a quick at-a-glance
|
|
7
|
+
* summary of cubby row counts plus the events the agent emitted in
|
|
8
|
+
* response.
|
|
9
|
+
*
|
|
10
|
+
* Replay reuses `harness.dispatch`, which synthesizes fresh `id`/`ts`
|
|
11
|
+
* fields. We deliberately don't preserve the recorded ones — replay
|
|
12
|
+
* verifies *behavior* against a sequence of inputs, not exact metadata
|
|
13
|
+
* fidelity. If a future use case needs that, we can add a private
|
|
14
|
+
* `dispatchRaw` that takes a full Event envelope.
|
|
15
|
+
*
|
|
16
|
+
* `cubbyState` is a per-cubby table-rowcount summary: useful as a smoke
|
|
17
|
+
* check ("did the replay populate `history.messages` to N rows?") without
|
|
18
|
+
* forcing every test to write its own assertion query.
|
|
19
|
+
*/
|
|
20
|
+
import fs from "node:fs";
|
|
21
|
+
import readline from "node:readline";
|
|
22
|
+
/**
|
|
23
|
+
* Drive a JSONL fixture through `harness.dispatch`. Blank lines are
|
|
24
|
+
* skipped. Each non-blank line must parse to an object with at least a
|
|
25
|
+
* `type` field; `payload` and `from` are forwarded verbatim.
|
|
26
|
+
*/
|
|
27
|
+
export async function runReplay(harness, jsonlPath, cubbies) {
|
|
28
|
+
const start = Date.now();
|
|
29
|
+
const beforeLen = harness.published.length;
|
|
30
|
+
const stream = fs.createReadStream(jsonlPath, { encoding: "utf8" });
|
|
31
|
+
const rl = readline.createInterface({ input: stream, crlfDelay: Infinity });
|
|
32
|
+
let lineNo = 0;
|
|
33
|
+
for await (const line of rl) {
|
|
34
|
+
lineNo += 1;
|
|
35
|
+
if (!line.trim())
|
|
36
|
+
continue;
|
|
37
|
+
let event;
|
|
38
|
+
try {
|
|
39
|
+
event = JSON.parse(line);
|
|
40
|
+
}
|
|
41
|
+
catch (err) {
|
|
42
|
+
throw new Error(`[replay] invalid JSON on line ${lineNo} of ${jsonlPath}: ${err.message}`);
|
|
43
|
+
}
|
|
44
|
+
if (typeof event.type !== "string") {
|
|
45
|
+
throw new Error(`[replay] line ${lineNo}: missing or non-string "type" field`);
|
|
46
|
+
}
|
|
47
|
+
await harness.dispatch({
|
|
48
|
+
type: event.type,
|
|
49
|
+
payload: event.payload,
|
|
50
|
+
from: typeof event.from === "string" ? event.from : undefined,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
const cubbyState = {};
|
|
54
|
+
for (const [alias, c] of cubbies) {
|
|
55
|
+
const tables = c.raw
|
|
56
|
+
.prepare("SELECT name FROM sqlite_master WHERE type='table' AND name NOT LIKE 'sqlite_%'")
|
|
57
|
+
.all();
|
|
58
|
+
cubbyState[alias] = {};
|
|
59
|
+
for (const t of tables) {
|
|
60
|
+
// Identifier is sourced from sqlite_master, not user input; double-quote
|
|
61
|
+
// for safety against tables whose names happen to be SQL keywords.
|
|
62
|
+
const row = c.raw
|
|
63
|
+
.prepare(`SELECT count(*) AS n FROM "${t.name}"`)
|
|
64
|
+
.get();
|
|
65
|
+
cubbyState[alias][t.name] = row.n;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
const published = harness.published.slice(beforeLen);
|
|
69
|
+
const durationMs = Date.now() - start;
|
|
70
|
+
return { published, cubbyState, durationMs };
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=replay.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"replay.js","sourceRoot":"","sources":["../../src/harness/replay.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,QAAQ,MAAM,eAAe,CAAC;AA6BrC;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,OAAsB,EACtB,SAAiB,EACjB,OAA+B;IAE/B,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACzB,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC,MAAM,CAAC;IAE3C,MAAM,MAAM,GAAG,EAAE,CAAC,gBAAgB,CAAC,SAAS,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC;IACpE,MAAM,EAAE,GAAG,QAAQ,CAAC,eAAe,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC;IAC5E,IAAI,MAAM,GAAG,CAAC,CAAC;IACf,IAAI,KAAK,EAAE,MAAM,IAAI,IAAI,EAAE,EAAE,CAAC;QAC5B,MAAM,IAAI,CAAC,CAAC;QACZ,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;YAAE,SAAS;QAC3B,IAAI,KAA4D,CAAC;QACjE,IAAI,CAAC;YACH,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAiB,CAAC;QAC3C,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,IAAI,KAAK,CACb,iCAAiC,MAAM,OAAO,SAAS,KAAM,GAAa,CAAC,OAAO,EAAE,CACrF,CAAC;QACJ,CAAC;QACD,IAAI,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACnC,MAAM,IAAI,KAAK,CACb,iBAAiB,MAAM,sCAAsC,CAC9D,CAAC;QACJ,CAAC;QACD,MAAM,OAAO,CAAC,QAAQ,CAAC;YACrB,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,OAAO,EAAE,KAAK,CAAC,OAAO;YACtB,IAAI,EAAE,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS;SAC9D,CAAC,CAAC;IACL,CAAC;IAED,MAAM,UAAU,GAA2C,EAAE,CAAC;IAC9D,KAAK,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,OAAO,EAAE,CAAC;QACjC,MAAM,MAAM,GAAG,CAAC,CAAC,GAAG;aACjB,OAAO,CACN,gFAAgF,CACjF;aACA,GAAG,EAA6B,CAAC;QACpC,UAAU,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;QACvB,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;YACvB,yEAAyE;YACzE,mEAAmE;YACnE,MAAM,GAAG,GAAG,CAAC,CAAC,GAAG;iBACd,OAAO,CAAC,8BAA8B,CAAC,CAAC,IAAI,GAAG,CAAC;iBAChD,GAAG,EAAmB,CAAC;YAC1B,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;QACpC,CAAC;IACH,CAAC;IAED,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;IACrD,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;IACtC,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,CAAC;AAC/C,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-memory snapshot/restore for the test harness.
|
|
3
|
+
*
|
|
4
|
+
* `captureSnapshot` serializes every cubby's SQLite database (via
|
|
5
|
+
* `db.serialize()`), shallow-copies the published-events array, and
|
|
6
|
+
* records the clock. `restoreSnapshot` rehydrates each cubby from its
|
|
7
|
+
* buffer, replaces the published array contents in place, and resets the
|
|
8
|
+
* clock — leaving the `TestHarness` object identity (and any references
|
|
9
|
+
* agents already hold) intact.
|
|
10
|
+
*
|
|
11
|
+
* Useful for fixture reuse: build a database state once, snapshot, then
|
|
12
|
+
* restore between scenarios without re-running migrations or replaying
|
|
13
|
+
* setup events.
|
|
14
|
+
*/
|
|
15
|
+
import Database from "better-sqlite3";
|
|
16
|
+
import type { TestCubby } from "./cubby.js";
|
|
17
|
+
import type { PublishedEvent } from "./publish.js";
|
|
18
|
+
export interface HarnessSnapshot {
|
|
19
|
+
/** Per-alias serialized SQLite databases (via `better-sqlite3`'s `serialize()`). */
|
|
20
|
+
cubbies: Record<string, Buffer>;
|
|
21
|
+
/** Shallow copy of `harness.published` at snapshot time. */
|
|
22
|
+
published: PublishedEvent[];
|
|
23
|
+
/** Clock value (`harness.now()`) at snapshot time. */
|
|
24
|
+
clockNow: number;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Build a snapshot of the harness state. Cubby buffers are independent
|
|
28
|
+
* copies — subsequent writes to the harness do not mutate the snapshot.
|
|
29
|
+
*/
|
|
30
|
+
export declare function captureSnapshot(cubbies: Map<string, TestCubby>, published: PublishedEvent[], clockNow: number): HarnessSnapshot;
|
|
31
|
+
/**
|
|
32
|
+
* Restore the harness to a previously captured snapshot.
|
|
33
|
+
*
|
|
34
|
+
* - Cubbies present in `snap.cubbies` are reloaded from their buffers.
|
|
35
|
+
* Aliases not in the snapshot are left untouched (so a snapshot taken
|
|
36
|
+
* before a cubby was added doesn't accidentally drop it).
|
|
37
|
+
* - The `published` array is mutated in place (length cleared, entries
|
|
38
|
+
* re-pushed) so callers holding a reference to `harness.published`
|
|
39
|
+
* observe the rollback without rebinding.
|
|
40
|
+
* - `setClockNow` is invoked so the injected clock advances backward.
|
|
41
|
+
*/
|
|
42
|
+
export declare function restoreSnapshot(cubbies: Map<string, TestCubby>, published: PublishedEvent[], setClockNow: (n: number) => void, snap: HarnessSnapshot): void;
|
|
43
|
+
export { Database };
|
|
44
|
+
//# sourceMappingURL=snapshot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snapshot.d.ts","sourceRoot":"","sources":["../../src/harness/snapshot.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AACtC,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAEnD,MAAM,WAAW,eAAe;IAC9B,oFAAoF;IACpF,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,4DAA4D;IAC5D,SAAS,EAAE,cAAc,EAAE,CAAC;IAC5B,sDAAsD;IACtD,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,EAC/B,SAAS,EAAE,cAAc,EAAE,EAC3B,QAAQ,EAAE,MAAM,GACf,eAAe,CAWjB;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,eAAe,CAC7B,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,EAC/B,SAAS,EAAE,cAAc,EAAE,EAC3B,WAAW,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,IAAI,EAChC,IAAI,EAAE,eAAe,GACpB,IAAI,CASN;AAID,OAAO,EAAE,QAAQ,EAAE,CAAC"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* In-memory snapshot/restore for the test harness.
|
|
3
|
+
*
|
|
4
|
+
* `captureSnapshot` serializes every cubby's SQLite database (via
|
|
5
|
+
* `db.serialize()`), shallow-copies the published-events array, and
|
|
6
|
+
* records the clock. `restoreSnapshot` rehydrates each cubby from its
|
|
7
|
+
* buffer, replaces the published array contents in place, and resets the
|
|
8
|
+
* clock — leaving the `TestHarness` object identity (and any references
|
|
9
|
+
* agents already hold) intact.
|
|
10
|
+
*
|
|
11
|
+
* Useful for fixture reuse: build a database state once, snapshot, then
|
|
12
|
+
* restore between scenarios without re-running migrations or replaying
|
|
13
|
+
* setup events.
|
|
14
|
+
*/
|
|
15
|
+
import Database from "better-sqlite3";
|
|
16
|
+
/**
|
|
17
|
+
* Build a snapshot of the harness state. Cubby buffers are independent
|
|
18
|
+
* copies — subsequent writes to the harness do not mutate the snapshot.
|
|
19
|
+
*/
|
|
20
|
+
export function captureSnapshot(cubbies, published, clockNow) {
|
|
21
|
+
const out = {};
|
|
22
|
+
for (const [alias, c] of cubbies) {
|
|
23
|
+
out[alias] = c.serialize();
|
|
24
|
+
}
|
|
25
|
+
return {
|
|
26
|
+
cubbies: out,
|
|
27
|
+
// Copy each entry so post-snapshot mutation can't leak back.
|
|
28
|
+
published: published.map((e) => ({ ...e })),
|
|
29
|
+
clockNow,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Restore the harness to a previously captured snapshot.
|
|
34
|
+
*
|
|
35
|
+
* - Cubbies present in `snap.cubbies` are reloaded from their buffers.
|
|
36
|
+
* Aliases not in the snapshot are left untouched (so a snapshot taken
|
|
37
|
+
* before a cubby was added doesn't accidentally drop it).
|
|
38
|
+
* - The `published` array is mutated in place (length cleared, entries
|
|
39
|
+
* re-pushed) so callers holding a reference to `harness.published`
|
|
40
|
+
* observe the rollback without rebinding.
|
|
41
|
+
* - `setClockNow` is invoked so the injected clock advances backward.
|
|
42
|
+
*/
|
|
43
|
+
export function restoreSnapshot(cubbies, published, setClockNow, snap) {
|
|
44
|
+
for (const [alias, buf] of Object.entries(snap.cubbies)) {
|
|
45
|
+
const c = cubbies.get(alias);
|
|
46
|
+
if (!c)
|
|
47
|
+
continue;
|
|
48
|
+
c.loadFromBuffer(buf);
|
|
49
|
+
}
|
|
50
|
+
published.length = 0;
|
|
51
|
+
for (const e of snap.published)
|
|
52
|
+
published.push({ ...e });
|
|
53
|
+
setClockNow(snap.clockNow);
|
|
54
|
+
}
|
|
55
|
+
// `Database` is re-exported for tests that want to instantiate a buffer
|
|
56
|
+
// directly without pulling in a separate import.
|
|
57
|
+
export { Database };
|
|
58
|
+
//# sourceMappingURL=snapshot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snapshot.js","sourceRoot":"","sources":["../../src/harness/snapshot.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,OAAO,QAAQ,MAAM,gBAAgB,CAAC;AAatC;;;GAGG;AACH,MAAM,UAAU,eAAe,CAC7B,OAA+B,EAC/B,SAA2B,EAC3B,QAAgB;IAEhB,MAAM,GAAG,GAA2B,EAAE,CAAC;IACvC,KAAK,MAAM,CAAC,KAAK,EAAE,CAAC,CAAC,IAAI,OAAO,EAAE,CAAC;QACjC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,CAAC;IAC7B,CAAC;IACD,OAAO;QACL,OAAO,EAAE,GAAG;QACZ,6DAA6D;QAC7D,SAAS,EAAE,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;QAC3C,QAAQ;KACT,CAAC;AACJ,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,eAAe,CAC7B,OAA+B,EAC/B,SAA2B,EAC3B,WAAgC,EAChC,IAAqB;IAErB,KAAK,MAAM,CAAC,KAAK,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QACxD,MAAM,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAC7B,IAAI,CAAC,CAAC;YAAE,SAAS;QACjB,CAAC,CAAC,cAAc,CAAC,GAAG,CAAC,CAAC;IACxB,CAAC;IACD,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC;IACrB,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,SAAS;QAAE,SAAS,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;IACzD,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AAC7B,CAAC;AAED,wEAAwE;AACxE,iDAAiD;AACjD,OAAO,EAAE,QAAQ,EAAE,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { testAgent } from "./test-agent.js";
|
|
2
|
+
export type { TestHarness, TestHarnessOptions, TestAgentMultiSpec, AgentCtor, PublishedEvent, CubbySpec, HarnessSnapshot, ReplayResult, } from "./test-agent.js";
|
|
3
|
+
export { createModelMock } from "./harness/model-mock.js";
|
|
4
|
+
export type { ModelMockHandle } from "./harness/model-mock.js";
|
|
5
|
+
export type { FetchMock, FetchMatcher } from "./harness/fetch-mock.js";
|
|
6
|
+
export { testPlatform, testWallet, mockAgent, fromMarketplace, } from "./test-platform.js";
|
|
7
|
+
export type { TestPlatform, TestPlatformOptions, TestUser, TestWallet, UserAccessor, AgentClass, AgentSource, AgentRegistration, SingleAgentRegistration, MultiEngagementSpec, PlatformCubbySpec, AgentConnection, ConnectionEngagement, ConnectionManifest, Vault, VaultEvent, VaultScope, VaultStream, MockAgentDescriptor, MockAgentSpec, MockAgentSingleSpec, MockAgentMultiEngagementSpec, MockEngagementSpec, MockEngagementDescriptor, MockSettingSpec, Activity, ActivityStatus, Job, JobsFilter, JobState, } from "./test-platform.js";
|
|
8
|
+
export type { Rule, Targeting, TargetingEngagement, } from "@cef-ai/agent-sdk";
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,YAAY,EACV,WAAW,EACX,kBAAkB,EAClB,kBAAkB,EAClB,SAAS,EACT,cAAc,EACd,SAAS,EACT,eAAe,EACf,YAAY,GACb,MAAM,iBAAiB,CAAC;AAEzB,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,YAAY,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAE/D,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEvE,OAAO,EACL,YAAY,EACZ,UAAU,EACV,SAAS,EACT,eAAe,GAChB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EACV,YAAY,EACZ,mBAAmB,EACnB,QAAQ,EACR,UAAU,EACV,YAAY,EACZ,UAAU,EACV,WAAW,EACX,iBAAiB,EACjB,uBAAuB,EACvB,mBAAmB,EACnB,iBAAiB,EACjB,eAAe,EACf,oBAAoB,EACpB,kBAAkB,EAClB,KAAK,EACL,UAAU,EACV,UAAU,EACV,WAAW,EACX,mBAAmB,EACnB,aAAa,EACb,mBAAmB,EACnB,4BAA4B,EAC5B,kBAAkB,EAClB,wBAAwB,EACxB,eAAe,EACf,QAAQ,EACR,cAAc,EACd,GAAG,EACH,UAAU,EACV,QAAQ,GACT,MAAM,oBAAoB,CAAC;AAG5B,YAAY,EACV,IAAI,EACJ,SAAS,EACT,mBAAmB,GACpB,MAAM,mBAAmB,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAY5C,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAK1D,OAAO,EACL,YAAY,EACZ,UAAU,EACV,SAAS,EACT,eAAe,GAChB,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `fromMarketplace(url)` — placeholder peer source that, in v2, will pull a
|
|
3
|
+
* published agent bundle from the CEF marketplace and load it into the
|
|
4
|
+
* simulator. v1 throws a clear error so test authors discover the limit
|
|
5
|
+
* immediately.
|
|
6
|
+
*
|
|
7
|
+
* Per the SDK plan (Task D4), the marker shape is reserved here so future
|
|
8
|
+
* work can add a `__fromMarketplace: true` descriptor without churning
|
|
9
|
+
* import paths in user tests.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* v1: not implemented. Throws synchronously with a self-explanatory message
|
|
13
|
+
* that names the URL the test attempted to load.
|
|
14
|
+
*
|
|
15
|
+
* v2 (future): fetch the bundle, materialise the agent class, and return a
|
|
16
|
+
* `MarketplaceAgentDescriptor` the platform recognises.
|
|
17
|
+
*/
|
|
18
|
+
export declare function fromMarketplace(url: string): never;
|
|
19
|
+
//# sourceMappingURL=from-marketplace.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"from-marketplace.d.ts","sourceRoot":"","sources":["../../src/peers/from-marketplace.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,KAAK,CAKlD"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `fromMarketplace(url)` — placeholder peer source that, in v2, will pull a
|
|
3
|
+
* published agent bundle from the CEF marketplace and load it into the
|
|
4
|
+
* simulator. v1 throws a clear error so test authors discover the limit
|
|
5
|
+
* immediately.
|
|
6
|
+
*
|
|
7
|
+
* Per the SDK plan (Task D4), the marker shape is reserved here so future
|
|
8
|
+
* work can add a `__fromMarketplace: true` descriptor without churning
|
|
9
|
+
* import paths in user tests.
|
|
10
|
+
*/
|
|
11
|
+
/**
|
|
12
|
+
* v1: not implemented. Throws synchronously with a self-explanatory message
|
|
13
|
+
* that names the URL the test attempted to load.
|
|
14
|
+
*
|
|
15
|
+
* v2 (future): fetch the bundle, materialise the agent class, and return a
|
|
16
|
+
* `MarketplaceAgentDescriptor` the platform recognises.
|
|
17
|
+
*/
|
|
18
|
+
export function fromMarketplace(url) {
|
|
19
|
+
throw new Error(`[testPlatform] fromMarketplace("${url}") is not implemented in simulator mode (v1). ` +
|
|
20
|
+
`Use a typed Agent class or mockAgent() instead.`);
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=from-marketplace.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"from-marketplace.js","sourceRoot":"","sources":["../../src/peers/from-marketplace.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAAC,GAAW;IACzC,MAAM,IAAI,KAAK,CACb,mCAAmC,GAAG,gDAAgD;QACpF,iDAAiD,CACpD,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `mockAgent({...})` — a lightweight, decoratorless agent peer for the
|
|
3
|
+
* multi-agent test platform.
|
|
4
|
+
*
|
|
5
|
+
* Use it when a test only needs a peer that publishes/echoes a fixed set of
|
|
6
|
+
* events; it's the "stunt double" alongside real, decorator-using agent
|
|
7
|
+
* classes. The `on` map plays the same role as `@OnEvent`: keys are event
|
|
8
|
+
* types, values are async handler functions invoked with the same
|
|
9
|
+
* `(event, ctx)` shape the runtime uses. `start` / `close` mirror the
|
|
10
|
+
* `@OnStart` / `@OnClose` lifecycle hooks.
|
|
11
|
+
*
|
|
12
|
+
* Two equivalent spec shapes (ADR-019 H4):
|
|
13
|
+
*
|
|
14
|
+
* - Single-engagement shorthand: `mockAgent({ agentId, on, onStart?, onClose? })`
|
|
15
|
+
* — produces one engagement with id `"default"`.
|
|
16
|
+
* - Multi-engagement form: `mockAgent({ agentId, engagements: [...], targeting?, settings? })`
|
|
17
|
+
* — each engagement has its own `on`/`onStart`/`onClose`; `targeting`
|
|
18
|
+
* selects one at Job creation.
|
|
19
|
+
*
|
|
20
|
+
* Internally `testPlatform` recognises the descriptor by its
|
|
21
|
+
* `__mockAgent: true` tag and consumes a uniform normalised shape so dispatch
|
|
22
|
+
* code is unaware of single-vs-multi or class-vs-mock.
|
|
23
|
+
*/
|
|
24
|
+
import type { Context, Event, EngagementMeta, Targeting } from "@cef-ai/agent-sdk";
|
|
25
|
+
/**
|
|
26
|
+
* Handler signatures the mock peer accepts. Mirrors the shape an
|
|
27
|
+
* `@OnEvent` method has (event, ctx) — `void` and `Promise<void>` are both
|
|
28
|
+
* fine since the runtime always awaits.
|
|
29
|
+
*/
|
|
30
|
+
export type MockEventHandler = (event: Event<unknown>, ctx: Context) => unknown | Promise<unknown>;
|
|
31
|
+
/** Optional lifecycle hook for `mockAgent`. */
|
|
32
|
+
export type MockLifecycleHandler = (ctx: Context, reason?: string) => unknown | Promise<unknown>;
|
|
33
|
+
/** Settings schema entry (mirrors AgentConfig.settings shape). */
|
|
34
|
+
export interface MockSettingSpec {
|
|
35
|
+
key: string;
|
|
36
|
+
type: "string" | "number" | "url" | "secret";
|
|
37
|
+
required?: boolean;
|
|
38
|
+
default?: unknown;
|
|
39
|
+
}
|
|
40
|
+
/** Single-engagement shorthand. */
|
|
41
|
+
export interface MockAgentSingleSpec {
|
|
42
|
+
/** Stable agent id; matches what the platform connects under. */
|
|
43
|
+
agentId: string;
|
|
44
|
+
/** Map of event type → handler. Keys become the engagement's `handles`. */
|
|
45
|
+
on?: Record<string, MockEventHandler>;
|
|
46
|
+
/** Optional `@OnStart` equivalent. */
|
|
47
|
+
onStart?: MockLifecycleHandler;
|
|
48
|
+
/** Optional `@OnClose` equivalent. */
|
|
49
|
+
onClose?: MockLifecycleHandler;
|
|
50
|
+
/** Forward-looking: declared output types. The simulator does not enforce. */
|
|
51
|
+
publishes?: string[];
|
|
52
|
+
}
|
|
53
|
+
/** Per-engagement entry inside a multi-engagement mock spec. */
|
|
54
|
+
export interface MockEngagementSpec {
|
|
55
|
+
id: string;
|
|
56
|
+
goal?: string;
|
|
57
|
+
on?: Record<string, MockEventHandler>;
|
|
58
|
+
onStart?: MockLifecycleHandler;
|
|
59
|
+
onClose?: MockLifecycleHandler;
|
|
60
|
+
}
|
|
61
|
+
/** Multi-engagement form (ADR-019 H4). */
|
|
62
|
+
export interface MockAgentMultiEngagementSpec {
|
|
63
|
+
agentId: string;
|
|
64
|
+
engagements: MockEngagementSpec[];
|
|
65
|
+
/** Targeting decision table; defaults to `{ rules: [], default: <first id> }`. */
|
|
66
|
+
targeting?: Targeting;
|
|
67
|
+
/** Settings schema (forward-looking; simulator does not enforce). */
|
|
68
|
+
settings?: MockSettingSpec[];
|
|
69
|
+
}
|
|
70
|
+
/** Union accepted by `mockAgent(...)`. */
|
|
71
|
+
export type MockAgentSpec = MockAgentSingleSpec | MockAgentMultiEngagementSpec;
|
|
72
|
+
/**
|
|
73
|
+
* Per-engagement materialised entry on a {@link MockAgentDescriptor}. The
|
|
74
|
+
* `instance` is a synthetic object whose method names match `meta.events` /
|
|
75
|
+
* `meta.lifecycle` so the runtime can dispatch uniformly with class-based
|
|
76
|
+
* agents.
|
|
77
|
+
*/
|
|
78
|
+
export interface MockEngagementDescriptor {
|
|
79
|
+
id: string;
|
|
80
|
+
goal?: string;
|
|
81
|
+
instance: Record<string, unknown>;
|
|
82
|
+
meta: EngagementMeta;
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Marker descriptor returned by {@link mockAgent}. The `__mockAgent` tag is
|
|
86
|
+
* how the platform tells a class peer apart from a mock peer at registration
|
|
87
|
+
* time. The descriptor exposes a normalised, post-validation shape so
|
|
88
|
+
* downstream consumers don't have to discriminate single vs multi.
|
|
89
|
+
*/
|
|
90
|
+
export interface MockAgentDescriptor {
|
|
91
|
+
readonly __mockAgent: true;
|
|
92
|
+
agentId: string;
|
|
93
|
+
engagements: MockEngagementDescriptor[];
|
|
94
|
+
targeting: Targeting;
|
|
95
|
+
settings?: MockSettingSpec[];
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Build a {@link MockAgentDescriptor} from a spec. The returned object is
|
|
99
|
+
* what callers pass into `testPlatform({ agents: { foo: mockAgent({...}) } })`.
|
|
100
|
+
*
|
|
101
|
+
* The single-engagement shorthand is normalised to a one-element
|
|
102
|
+
* `engagements` array with id `"default"` and a degenerate targeting table,
|
|
103
|
+
* so consumers always see the same shape.
|
|
104
|
+
*/
|
|
105
|
+
export declare function mockAgent(spec: MockAgentSpec): MockAgentDescriptor;
|
|
106
|
+
/** Type-guard used by `testPlatform` to dispatch on source kind. */
|
|
107
|
+
export declare function isMockAgentDescriptor(value: unknown): value is MockAgentDescriptor;
|
|
108
|
+
//# sourceMappingURL=mock-agent.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mock-agent.d.ts","sourceRoot":"","sources":["../../src/peers/mock-agent.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,KAAK,EACV,OAAO,EACP,KAAK,EACL,cAAc,EACd,SAAS,EACV,MAAM,mBAAmB,CAAC;AAE3B;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,GAAG,CAC7B,KAAK,EAAE,KAAK,CAAC,OAAO,CAAC,EACrB,GAAG,EAAE,OAAO,KACT,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;AAEhC,+CAA+C;AAC/C,MAAM,MAAM,oBAAoB,GAAG,CACjC,GAAG,EAAE,OAAO,EACZ,MAAM,CAAC,EAAE,MAAM,KACZ,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;AAEhC,kEAAkE;AAClE,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,KAAK,GAAG,QAAQ,CAAC;IAC7C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,mCAAmC;AACnC,MAAM,WAAW,mBAAmB;IAClC,iEAAiE;IACjE,OAAO,EAAE,MAAM,CAAC;IAChB,2EAA2E;IAC3E,EAAE,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IACtC,sCAAsC;IACtC,OAAO,CAAC,EAAE,oBAAoB,CAAC;IAC/B,sCAAsC;IACtC,OAAO,CAAC,EAAE,oBAAoB,CAAC;IAC/B,8EAA8E;IAC9E,SAAS,CAAC,EAAE,MAAM,EAAE,CAAC;CACtB;AAED,gEAAgE;AAChE,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,gBAAgB,CAAC,CAAC;IACtC,OAAO,CAAC,EAAE,oBAAoB,CAAC;IAC/B,OAAO,CAAC,EAAE,oBAAoB,CAAC;CAChC;AAED,0CAA0C;AAC1C,MAAM,WAAW,4BAA4B;IAC3C,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,kBAAkB,EAAE,CAAC;IAClC,kFAAkF;IAClF,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,qEAAqE;IACrE,QAAQ,CAAC,EAAE,eAAe,EAAE,CAAC;CAC9B;AAED,0CAA0C;AAC1C,MAAM,MAAM,aAAa,GAAG,mBAAmB,GAAG,4BAA4B,CAAC;AAE/E;;;;;GAKG;AACH,MAAM,WAAW,wBAAwB;IACvC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAClC,IAAI,EAAE,cAAc,CAAC;CACtB;AAED;;;;;GAKG;AACH,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,WAAW,EAAE,IAAI,CAAC;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,wBAAwB,EAAE,CAAC;IACxC,SAAS,EAAE,SAAS,CAAC;IACrB,QAAQ,CAAC,EAAE,eAAe,EAAE,CAAC;CAC9B;AAiDD;;;;;;;GAOG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,aAAa,GAAG,mBAAmB,CAgElE;AAED,oEAAoE;AACpE,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,OAAO,GACb,KAAK,IAAI,mBAAmB,CAM9B"}
|