@zhin.js/testing 1.0.4 → 1.0.5
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 +28 -1
- package/lib/fake-clock.d.ts +7 -2
- package/lib/fake-clock.d.ts.map +1 -1
- package/lib/fake-clock.js +15 -4
- package/lib/fake-clock.js.map +1 -1
- package/lib/fake-hosts.d.ts +1 -1
- package/lib/fake-hosts.d.ts.map +1 -1
- package/lib/fake-plugin.d.ts +37 -4
- package/lib/fake-plugin.d.ts.map +1 -1
- package/lib/fake-plugin.js +57 -4
- package/lib/fake-plugin.js.map +1 -1
- package/lib/fake-runners.d.ts +51 -3
- package/lib/fake-runners.d.ts.map +1 -1
- package/lib/fake-runners.js +92 -1
- package/lib/fake-runners.js.map +1 -1
- package/lib/index.d.ts +16 -8
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +9 -5
- package/lib/index.js.map +1 -1
- package/lib/test-module-runtime.d.ts +1 -1
- package/lib/test-module-runtime.d.ts.map +1 -1
- package/lib/test-module-runtime.js +1 -1
- package/lib/test-module-runtime.js.map +1 -1
- package/package.json +14 -12
- package/src/fake-clock.ts +14 -4
- package/src/fake-hosts.ts +1 -1
- package/src/fake-plugin.ts +71 -5
- package/src/fake-runners.ts +144 -4
- package/src/index.ts +17 -8
- package/src/test-module-runtime.ts +2 -2
package/README.md
CHANGED
|
@@ -3,6 +3,18 @@
|
|
|
3
3
|
The kit has two layers: typed **fakes** for fast unit tests (no `as never`, below), and
|
|
4
4
|
`PluginTestKit` for integration tests through the real Plugin Runtime (the rest of this file).
|
|
5
5
|
|
|
6
|
+
## Install
|
|
7
|
+
|
|
8
|
+
```sh
|
|
9
|
+
pnpm add -D @zhin.js/testing
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
`zhin.js`, `@zhin.js/runtime` and `@zhin.js/tool` are peer dependencies; the kit ships no
|
|
13
|
+
`@zhin.js/*` copy of its own and resolves core, commands, adapters and the Plugin Runtime through the
|
|
14
|
+
plugin's `zhin.js`, so tests run on the same single stack as a real bot. pnpm and npm install
|
|
15
|
+
missing peers; with yarn 1 run `yarn add -D zhin.js @zhin.js/runtime @zhin.js/tool @zhin.js/testing`.
|
|
16
|
+
Upgrade it together with `zhin.js`.
|
|
17
|
+
|
|
6
18
|
## Fakes for unit tests
|
|
7
19
|
|
|
8
20
|
```ts
|
|
@@ -26,8 +38,18 @@ expect(message.replies).toEqual(['ok']);
|
|
|
26
38
|
`Scope`, `DisposeStack` and `GenerationHandoffStack`, plus the real owner-bound
|
|
27
39
|
`databaseHostToken`, `scheduleHostToken` and `outboundHostToken` facades over in-memory hosts
|
|
28
40
|
(`FakeDatabaseRootHost`, `FakeScheduleRootHost` driven by a `FakeClock`, `FakeOutboundRootHost`).
|
|
41
|
+
- `runPluginSetup` validates `config` against the plugin's declared `config` schema, applies its
|
|
42
|
+
defaults and keeps only declared top-level fields, like the Runtime (throws
|
|
43
|
+
`PluginConfigValidationError`). Pass `validateConfig: false` to hand `config` to `setup()` verbatim.
|
|
44
|
+
`resolvePluginConfig(definition, input)` returns the resolved view without running setup.
|
|
45
|
+
- `runTool(fake, tool, input, { message })` runs an Agent tool (a definition, or a local name
|
|
46
|
+
registered via `addTool()`): executable `inputSchema` parsing and `adapter` binding as in the
|
|
47
|
+
Runtime, with `origin`/`principal` derived from a fake message. No approval or policy enforcement.
|
|
29
48
|
- `runCommand`, `runMiddleware`, `runHandler` execute convention-directory definitions against the
|
|
30
49
|
fake. `runCommand` calls `execute()` directly: no routing, parameter parsing, `permit` or admission.
|
|
50
|
+
Pass `source` (the command's `index.ts` path or `new URL('../commands/echo/[text]/index.ts', import.meta.url)`)
|
|
51
|
+
to apply the Runtime's convention-path check first: a layout the Runtime rejects, such as
|
|
52
|
+
`commands/term/[word]/[...definition]`, throws instead of passing.
|
|
31
53
|
- `fakeOf<T>(partial)` replaces `{ ... } as never` for narrow collaborators and event payloads.
|
|
32
54
|
- The fakes do not run the renderer or outbound middleware; use `PluginTestKit` to verify the send chain.
|
|
33
55
|
|
|
@@ -74,7 +96,8 @@ The example requires the mounted plugin to provide `suite checkin`. Roles are su
|
|
|
74
96
|
the fixture; this verifies command admission, not a platform's real role projection. `permissions` is
|
|
75
97
|
the real PermissionHost used by the IM runtime.
|
|
76
98
|
|
|
77
|
-
|
|
99
|
+
Pass `createConfigDocument(path)` from `@zhin.js/config-file` as `config` to run on a real configuration file;
|
|
100
|
+
edit the file and call `reloadSource(path)` to apply it, as the CLI's file watcher would. Omitting `config` creates an empty v2 application. The kit does not read a user's configuration file
|
|
78
101
|
or infer instance mounts from `package.json#zhin.plugins`; pass the disposable application's v2
|
|
79
102
|
declaration explicitly when testing child instances.
|
|
80
103
|
|
|
@@ -91,6 +114,10 @@ write files or send real messages. Never point it at a production app or include
|
|
|
91
114
|
- `reloadSource(absolutePath)` submits a changed file to the real HMR coordinator and reports `reloaded`,
|
|
92
115
|
`unchanged`, `failed` or `restart-required`, with the committed generation. Edit the test app first.
|
|
93
116
|
A process restart requirement latches the native coordinator; close this kit and create a new one.
|
|
117
|
+
- `messageDiagnostics` is the same bounded, body-free reader the Console serves at
|
|
118
|
+
`GET /api/messages/diagnostics`; use it to assert route, dispatch status and delivery outcomes.
|
|
119
|
+
- `snapshots` is the committed-snapshot authority the Console routes read (task center, permission
|
|
120
|
+
explanation). Mount a real route on it to test a Console flow; do not publish through it.
|
|
94
121
|
- `patchConfig()` uses normal composition/validation. Invalid patches reject and keep the prior generation.
|
|
95
122
|
- `installResources()` installs host-owned public resources, such as a Database Host, Schedule Host or
|
|
96
123
|
a test HTML renderer. The library does not invent storage or a scheduler implementation.
|
package/lib/fake-clock.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { PluginId, ScheduleHost, ScheduleJobRegistration } from '
|
|
1
|
+
import type { PluginId, ScheduleHost, ScheduleJobRegistration } from 'zhin.js/plugin-runtime';
|
|
2
2
|
/** Controllable wall clock. It never touches the real `Date` or timers. */
|
|
3
3
|
export declare class FakeClock {
|
|
4
4
|
#private;
|
|
@@ -7,7 +7,12 @@ export declare class FakeClock {
|
|
|
7
7
|
date(): Date;
|
|
8
8
|
/** Jump without firing anything (like setting the system time). */
|
|
9
9
|
set(time: number | Date): void;
|
|
10
|
-
/**
|
|
10
|
+
/**
|
|
11
|
+
* Move forward and run every cron job that became due, in time order.
|
|
12
|
+
*
|
|
13
|
+
* The clock always ends at the target time, even when a job throws. After a failure the error
|
|
14
|
+
* is rethrown and the remaining jobs due inside the same window are NOT run (they are skipped, not deferred).
|
|
15
|
+
*/
|
|
11
16
|
advance(ms: number): Promise<void>;
|
|
12
17
|
/** @internal */
|
|
13
18
|
onAdvance(listener: (from: number, to: number) => Promise<void>): () => void;
|
package/lib/fake-clock.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fake-clock.d.ts","sourceRoot":"","sources":["../src/fake-clock.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,uBAAuB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"fake-clock.d.ts","sourceRoot":"","sources":["../src/fake-clock.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,YAAY,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AAE9F,2EAA2E;AAC3E,qBAAa,SAAS;;gBAIR,KAAK,GAAE,MAAM,GAAG,IAAoC;IAIhE,GAAG,IAAI,MAAM;IACb,IAAI,IAAI,IAAI;IAEZ,mEAAmE;IACnE,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,IAAI;IAE9B;;;;;OAKG;IACG,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAWxC,gBAAgB;IAChB,SAAS,CAAC,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,MAAM,IAAI;CAI7E;AAyBD,6FAA6F;AAC7F,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAY/D;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,KAAK,CAAC,EAAE,QAAQ,CAAC;CAC3B;AAID;;;GAGG;AACH,qBAAa,oBAAqB,YAAW,YAAY;;IAG3C,QAAQ,CAAC,KAAK,EAAE,SAAS;gBAAhB,KAAK,EAAE,SAAS;IAarC,QAAQ,CAAC,GAAG,EAAE,uBAAuB,GAAG,MAAM,IAAI;IAMlD,IAAI,IAAI,SAAS,gBAAgB,EAAE;IAKnC,sFAAsF;IAChF,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAKzC"}
|
package/lib/fake-clock.js
CHANGED
|
@@ -9,15 +9,24 @@ export class FakeClock {
|
|
|
9
9
|
date() { return new Date(this.#now); }
|
|
10
10
|
/** Jump without firing anything (like setting the system time). */
|
|
11
11
|
set(time) { this.#now = typeof time === 'number' ? time : time.getTime(); }
|
|
12
|
-
/**
|
|
12
|
+
/**
|
|
13
|
+
* Move forward and run every cron job that became due, in time order.
|
|
14
|
+
*
|
|
15
|
+
* The clock always ends at the target time, even when a job throws. After a failure the error
|
|
16
|
+
* is rethrown and the remaining jobs due inside the same window are NOT run (they are skipped, not deferred).
|
|
17
|
+
*/
|
|
13
18
|
async advance(ms) {
|
|
14
19
|
if (!(ms >= 0))
|
|
15
20
|
throw new RangeError('FakeClock.advance requires a non-negative duration');
|
|
16
21
|
const from = this.#now;
|
|
17
22
|
const to = from + ms;
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
23
|
+
try {
|
|
24
|
+
for (const listener of [...this.#listeners])
|
|
25
|
+
await listener(from, to);
|
|
26
|
+
}
|
|
27
|
+
finally {
|
|
28
|
+
this.#now = to;
|
|
29
|
+
}
|
|
21
30
|
}
|
|
22
31
|
/** @internal */
|
|
23
32
|
onAdvance(listener) {
|
|
@@ -74,6 +83,8 @@ export class FakeScheduleRootHost {
|
|
|
74
83
|
clock.onAdvance(async (from, to) => {
|
|
75
84
|
for (let t = Math.floor(from / 1000) * 1000 + 1000; t <= to; t += 1000) {
|
|
76
85
|
const date = new Date(t);
|
|
86
|
+
// A job firing at `t` must observe `t` (e.g. to decide what is due), not the advance() start.
|
|
87
|
+
clock.set(t);
|
|
77
88
|
for (const job of [...this.#jobs]) {
|
|
78
89
|
if (this.#jobs.has(job) && job.isActive?.() !== false && job.matches(date))
|
|
79
90
|
await job.execute();
|
package/lib/fake-clock.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fake-clock.js","sourceRoot":"","sources":["../src/fake-clock.ts"],"names":[],"mappings":"AAEA,2EAA2E;AAC3E,MAAM,OAAO,SAAS;IACpB,IAAI,CAAS;IACJ,UAAU,GAAG,IAAI,GAAG,EAA+C,CAAC;IAE7E,YAAY,QAAuB,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QAC9D,IAAI,CAAC,IAAI,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;IAClE,CAAC;IAED,GAAG,KAAa,OAAO,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IACnC,IAAI,KAAW,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAE5C,mEAAmE;IACnE,GAAG,CAAC,IAAmB,IAAU,IAAI,CAAC,IAAI,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IAEhG
|
|
1
|
+
{"version":3,"file":"fake-clock.js","sourceRoot":"","sources":["../src/fake-clock.ts"],"names":[],"mappings":"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"}
|
package/lib/fake-hosts.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { DatabaseHost, DatabaseHostModel, DeliveryTarget, OutboundEditInput, OutboundReactionInput, OutboundRecallInput, OutboundRootHost, OutboundSendInput, OutboundTypingInput, PersistentStatePort, PluginId } from '
|
|
1
|
+
import type { DatabaseHost, DatabaseHostModel, DeliveryTarget, OutboundEditInput, OutboundReactionInput, OutboundRecallInput, OutboundRootHost, OutboundSendInput, OutboundTypingInput, PersistentStatePort, PluginId } from 'zhin.js/plugin-runtime';
|
|
2
2
|
type Row = Record<string, unknown>;
|
|
3
3
|
/**
|
|
4
4
|
* Process-wide in-memory Database Host. Tables appear on `define()` (plugins define in `setup`);
|
package/lib/fake-hosts.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fake-hosts.d.ts","sourceRoot":"","sources":["../src/fake-hosts.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,YAAY,EAAE,iBAAiB,EAAyB,cAAc,EACtE,iBAAiB,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,iBAAiB,EAClG,mBAAmB,EAAE,mBAAmB,EAAE,QAAQ,EACnD,MAAM,
|
|
1
|
+
{"version":3,"file":"fake-hosts.d.ts","sourceRoot":"","sources":["../src/fake-hosts.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,YAAY,EAAE,iBAAiB,EAAyB,cAAc,EACtE,iBAAiB,EAAE,qBAAqB,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,iBAAiB,EAClG,mBAAmB,EAAE,mBAAmB,EAAE,QAAQ,EACnD,MAAM,wBAAwB,CAAC;AAEhC,KAAK,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AA0DnC;;;;GAIG;AACH,qBAAa,oBAAqB,YAAW,YAAY;;IACvD,QAAQ,CAAC,OAAO,YAAY;IAC5B,OAAO,UAAQ;IACf,QAAQ,CAAC,KAAK,EAAE,mBAAmB,CAAqB;IAExD,QAAQ,CAAC,MAAM;oBAAiB,MAAM,KAAG,iBAAiB,GAAG,SAAS;MAA6B;IAEnG,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI;IAGhE,MAAM,IAAI,SAAS,MAAM,EAAE;IAC3B,cAAc,IAAI,SAAS;IACrB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IACtB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAC3B,qDAAqD;IACrD,MAAM,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,EAAE;CACzC;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,aAAa,GAAG,gBAAgB,GAAG,QAAQ,GAAG,MAAM,GAAG,QAAQ,CAAC;IACvG,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,iFAAiF;IACjF,QAAQ,CAAC,SAAS,CAAC,EAAE,QAAQ,CAAC;IAC9B,QAAQ,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED;;;;GAIG;AACH,qBAAa,oBAAqB,YAAW,gBAAgB;;IAC3D,QAAQ,CAAC,KAAK,EAAE,gBAAgB,EAAE,CAAM;IAIxC,oDAAoD;IACpD,QAAQ,CAAC,KAAK,GAAE,OAA4C,GAAG,IAAI;IAanE,IAAI,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IACtD,UAAU,CAAC,MAAM,EAAE,cAAc,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAGjG,WAAW,CAAC,KAAK,EAAE,qBAAqB,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAC3D,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAC7C,MAAM,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IACvD,IAAI,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAChD,MAAM,CAAC,KAAK,EAAE,mBAAmB,GAAG,OAAO,CAAC,IAAI,CAAC;IACvD,WAAW,CAAC,CAAC,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;CACxD"}
|
package/lib/fake-plugin.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { DisposeStack, GenerationHandoffStack, PluginDatabaseHost, PluginOutboundHost, PluginScheduleHost, Scope, type FeatureId, type PluginDefinition, type PluginId, type PluginSetupContext, type Token } from '
|
|
2
|
-
import type { CapabilityContext } from '
|
|
1
|
+
import { DisposeStack, GenerationHandoffStack, PluginDatabaseHost, PluginOutboundHost, PluginScheduleHost, Scope, type FeatureId, type PluginDefinition, type PluginId, type PluginSetupContext, type Token } from 'zhin.js/plugin-runtime';
|
|
2
|
+
import type { CapabilityContext } from 'zhin.js';
|
|
3
3
|
import { FakeClock, FakeScheduleRootHost } from './fake-clock.js';
|
|
4
4
|
import { FakeDatabaseRootHost, FakeOutboundRootHost, type FakeOutboundCall } from './fake-hosts.js';
|
|
5
5
|
/** A typed `token -> value` binding; create with {@link fakeResource}. */
|
|
@@ -78,6 +78,39 @@ export declare class FakePlugin<TConfig = unknown> {
|
|
|
78
78
|
dispose(): Promise<void>;
|
|
79
79
|
}
|
|
80
80
|
export declare function createFakePlugin<TConfig = unknown>(options?: FakePluginOptions<TConfig>): FakePlugin<TConfig>;
|
|
81
|
-
|
|
82
|
-
|
|
81
|
+
export interface RunPluginSetupOptions<TConfig = unknown> extends Omit<FakePluginOptions<TConfig>, 'name' | 'config'> {
|
|
82
|
+
/**
|
|
83
|
+
* Raw plugin configuration, as a user would write it under the instance key in `zhin.config.yml`.
|
|
84
|
+
* When the definition declares `config`, it is validated and defaulted like the real Runtime does.
|
|
85
|
+
*/
|
|
86
|
+
readonly config?: Partial<TConfig>;
|
|
87
|
+
/**
|
|
88
|
+
* Validate `config` against `definition.config` and apply its defaults (default `true`).
|
|
89
|
+
* Set `false` to pass `config` to `setup()` verbatim, as earlier versions of `runPluginSetup` did.
|
|
90
|
+
*/
|
|
91
|
+
readonly validateConfig?: boolean;
|
|
92
|
+
}
|
|
93
|
+
/** Thrown by {@link runPluginSetup} / {@link resolvePluginConfig} when config fails the plugin's schema. */
|
|
94
|
+
export declare class PluginConfigValidationError extends TypeError {
|
|
95
|
+
readonly plugin: string;
|
|
96
|
+
/** Human-readable `instancePath message` lines, same wording as Runtime startup errors. */
|
|
97
|
+
readonly issues: readonly string[];
|
|
98
|
+
readonly name = "PluginConfigValidationError";
|
|
99
|
+
constructor(plugin: string,
|
|
100
|
+
/** Human-readable `instancePath message` lines, same wording as Runtime startup errors. */
|
|
101
|
+
issues: readonly string[]);
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Resolve the config view `setup()` would receive from the real Runtime: validate `input` against
|
|
105
|
+
* `definition.config`, fill schema defaults, and keep only the top-level fields the schema declares.
|
|
106
|
+
* Without a declared `config` schema the input is returned unchanged (`{}` when omitted).
|
|
107
|
+
*/
|
|
108
|
+
export declare function resolvePluginConfig<TConfig = unknown>(definition: Pick<PluginDefinition<TConfig>, 'name' | 'config'>, input?: unknown): TConfig;
|
|
109
|
+
/**
|
|
110
|
+
* Create a fake and run `definition.setup()` in one step. Call `dispose()` when done.
|
|
111
|
+
*
|
|
112
|
+
* When the plugin declares a `config` schema, `options.config` is validated and defaulted first
|
|
113
|
+
* (throws {@link PluginConfigValidationError}); pass `validateConfig: false` to opt out.
|
|
114
|
+
*/
|
|
115
|
+
export declare function runPluginSetup<TConfig = unknown>(definition: PluginDefinition<TConfig>, options?: RunPluginSetupOptions<TConfig>): Promise<FakePlugin<TConfig>>;
|
|
83
116
|
//# sourceMappingURL=fake-plugin.d.ts.map
|
package/lib/fake-plugin.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fake-plugin.d.ts","sourceRoot":"","sources":["../src/fake-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,kBAAkB,EAChG,KAAK,EACS,KAAK,SAAS,EAAE,KAAK,gBAAgB,EAAE,KAAK,QAAQ,EAClE,KAAK,kBAAkB,EAAE,KAAK,KAAK,EACpC,MAAM,
|
|
1
|
+
{"version":3,"file":"fake-plugin.d.ts","sourceRoot":"","sources":["../src/fake-plugin.ts"],"names":[],"mappings":"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"}
|
package/lib/fake-plugin.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { DisposeStack, GenerationHandoffStack, PluginDatabaseHost, PluginOutboundHost, PluginScheduleHost, Scope, databaseHostToken, outboundHostToken, qualifyPluginResourceName, rootPluginId, scheduleHostToken, } from '
|
|
1
|
+
import { DisposeStack, GenerationHandoffStack, PluginDatabaseHost, PluginOutboundHost, PluginScheduleHost, Scope, databaseHostToken, outboundHostToken, qualifyPluginResourceName, rootPluginId, scheduleHostToken, } from 'zhin.js/plugin-runtime';
|
|
2
|
+
import { parsePluginConfigSchema } from '@zhin.js/runtime';
|
|
2
3
|
import { FakeClock, FakeScheduleRootHost } from './fake-clock.js';
|
|
3
4
|
import { FakeDatabaseRootHost, FakeOutboundRootHost } from './fake-hosts.js';
|
|
4
5
|
/** Bind a value to a token with the token's own type, so tests need no cast. */
|
|
@@ -82,6 +83,7 @@ export class FakePlugin {
|
|
|
82
83
|
signal: this.signal, owner, generation: this.generation,
|
|
83
84
|
config: this.config,
|
|
84
85
|
use: (token) => this.resources.use(token),
|
|
86
|
+
has: (token) => this.resources.has(token),
|
|
85
87
|
project: (feature) => {
|
|
86
88
|
if (!this.projections.has(feature))
|
|
87
89
|
throw new Error(`Missing Feature projection ${feature}`);
|
|
@@ -121,9 +123,60 @@ export class FakePlugin {
|
|
|
121
123
|
export function createFakePlugin(options) {
|
|
122
124
|
return new FakePlugin(options);
|
|
123
125
|
}
|
|
124
|
-
/**
|
|
125
|
-
export
|
|
126
|
-
|
|
126
|
+
/** Thrown by {@link runPluginSetup} / {@link resolvePluginConfig} when config fails the plugin's schema. */
|
|
127
|
+
export class PluginConfigValidationError extends TypeError {
|
|
128
|
+
plugin;
|
|
129
|
+
issues;
|
|
130
|
+
name = 'PluginConfigValidationError';
|
|
131
|
+
constructor(plugin,
|
|
132
|
+
/** Human-readable `instancePath message` lines, same wording as Runtime startup errors. */
|
|
133
|
+
issues) {
|
|
134
|
+
super(`Invalid config for plugin ${plugin}:\n ${issues.join('\n ')}`);
|
|
135
|
+
this.plugin = plugin;
|
|
136
|
+
this.issues = issues;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Resolve the config view `setup()` would receive from the real Runtime: validate `input` against
|
|
141
|
+
* `definition.config`, fill schema defaults, and keep only the top-level fields the schema declares.
|
|
142
|
+
* Without a declared `config` schema the input is returned unchanged (`{}` when omitted).
|
|
143
|
+
*/
|
|
144
|
+
export function resolvePluginConfig(definition, input) {
|
|
145
|
+
if (!definition.config)
|
|
146
|
+
return (input ?? {});
|
|
147
|
+
const schema = definition.config.toJsonSchema();
|
|
148
|
+
const { value, errors } = parsePluginConfigSchema(schema, input);
|
|
149
|
+
if (errors.length) {
|
|
150
|
+
throw new PluginConfigValidationError(definition.name, errors.map((error) => {
|
|
151
|
+
const params = error.params;
|
|
152
|
+
const detail = typeof params?.additionalProperty === 'string'
|
|
153
|
+
? ` (additionalProperty: ${params.additionalProperty})`
|
|
154
|
+
: Array.isArray(params?.allowedValues) ? ` (allowedValues: ${JSON.stringify(params.allowedValues)})` : '';
|
|
155
|
+
const path = error.instancePath.replace(/^\/candidate/, '');
|
|
156
|
+
return `${path || '/'} ${error.message ?? error.keyword}${detail}`;
|
|
157
|
+
}));
|
|
158
|
+
}
|
|
159
|
+
// The Runtime re-picks a plugin's own top-level fields (see config-composer `pickOwnFields`).
|
|
160
|
+
const properties = schema.properties && typeof schema.properties === 'object' && !Array.isArray(schema.properties)
|
|
161
|
+
? Object.keys(schema.properties)
|
|
162
|
+
: [];
|
|
163
|
+
const record = value && typeof value === 'object' ? value : {};
|
|
164
|
+
const view = {};
|
|
165
|
+
for (const key of properties)
|
|
166
|
+
if (Object.hasOwn(record, key))
|
|
167
|
+
view[key] = record[key];
|
|
168
|
+
return view;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Create a fake and run `definition.setup()` in one step. Call `dispose()` when done.
|
|
172
|
+
*
|
|
173
|
+
* When the plugin declares a `config` schema, `options.config` is validated and defaulted first
|
|
174
|
+
* (throws {@link PluginConfigValidationError}); pass `validateConfig: false` to opt out.
|
|
175
|
+
*/
|
|
176
|
+
export async function runPluginSetup(definition, options = {}) {
|
|
177
|
+
const { validateConfig = true, config, ...rest } = options;
|
|
178
|
+
const resolved = validateConfig ? resolvePluginConfig(definition, config) : config;
|
|
179
|
+
const fake = new FakePlugin({ ...rest, ...(resolved === undefined ? {} : { config: resolved }), name: definition.name });
|
|
127
180
|
await fake.setup(definition);
|
|
128
181
|
return fake;
|
|
129
182
|
}
|
package/lib/fake-plugin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fake-plugin.js","sourceRoot":"","sources":["../src/fake-plugin.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,YAAY,EAAE,sBAAsB,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,kBAAkB,EAChG,KAAK,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,yBAAyB,EAAE,YAAY,EAAE,iBAAiB,GAGxG,MAAM,
|
|
1
|
+
{"version":3,"file":"fake-plugin.js","sourceRoot":"","sources":["../src/fake-plugin.ts"],"names":[],"mappings":"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"}
|
package/lib/fake-runners.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import type { CommandContext, CommandDefinition, CommandMessage, CommandParameterValue } from '
|
|
2
|
-
import type { HandlerDefinition } from '
|
|
3
|
-
import type { MiddlewareDefinition } from '
|
|
1
|
+
import type { CommandContext, CommandDefinition, CommandMessage, CommandParameterValue } from 'zhin.js/command';
|
|
2
|
+
import type { HandlerDefinition } from 'zhin.js/handler';
|
|
3
|
+
import type { MiddlewareDefinition } from 'zhin.js/middleware';
|
|
4
|
+
import { type AgentToolDefinition, type ToolExecutionContext, type ToolInvocationOrigin, type ToolInvocationPolicy, type ToolQuestionPort } from '@zhin.js/tool';
|
|
5
|
+
import type { OperationClientPort } from 'zhin.js';
|
|
4
6
|
import type { FakePlugin } from './fake-plugin.js';
|
|
5
7
|
/** Inbound message with recorded replies. */
|
|
6
8
|
export interface FakeMessage extends CommandMessage {
|
|
@@ -27,12 +29,21 @@ export interface RunCommandOptions<TInput extends CommandMessage = FakeMessage>
|
|
|
27
29
|
readonly options?: Readonly<Record<string, CommandParameterValue>>;
|
|
28
30
|
readonly segments?: CommandContext['segments'];
|
|
29
31
|
readonly interaction?: CommandContext['interaction'];
|
|
32
|
+
/**
|
|
33
|
+
* Where the command lives: its `commands/.../index.ts` file (or directory), as a path or a
|
|
34
|
+
* `file:` URL such as `new URL('../commands/echo/[text]/index.ts', import.meta.url)`. When set,
|
|
35
|
+
* the definition first goes through the Runtime's convention-path check (`bindCommandSource`
|
|
36
|
+
* from `zhin.js/command`): a layout the Runtime would reject, e.g. `commands/term/[word]/[...rest]`,
|
|
37
|
+
* throws here too, and the directory parameter is bound as in the Runtime.
|
|
38
|
+
*/
|
|
39
|
+
readonly source?: string | URL;
|
|
30
40
|
}
|
|
31
41
|
/** Build the context a command receives from the fake plugin; usable for direct `execute()` calls. */
|
|
32
42
|
export declare function createCommandContext<TConfig, TInput extends CommandMessage = FakeMessage>(fake: FakePlugin<TConfig>, options?: RunCommandOptions<TInput>): CommandContext<TConfig, TInput, string | undefined>;
|
|
33
43
|
/**
|
|
34
44
|
* Execute a command definition against the fake. This calls `execute()` directly: it does NOT run
|
|
35
45
|
* route matching, parameter parsing, `permit`, or admission. Use `PluginTestKit` for those.
|
|
46
|
+
* Pass `source` to apply the Runtime's convention-path check first.
|
|
36
47
|
*/
|
|
37
48
|
export declare function runCommand<TConfig, TResult, TInput extends CommandMessage = FakeMessage>(fake: FakePlugin<TConfig>, definition: CommandDefinition<TConfig, TResult, TInput, string | undefined>, options?: RunCommandOptions<TInput>): Promise<TResult>;
|
|
38
49
|
export interface RunMiddlewareResult {
|
|
@@ -44,4 +55,41 @@ export interface RunMiddlewareResult {
|
|
|
44
55
|
export declare function runMiddleware<TConfig, TInput = FakeMessage>(fake: FakePlugin<TConfig>, definition: MiddlewareDefinition<TInput, TConfig, string | undefined>, input?: TInput): Promise<RunMiddlewareResult>;
|
|
45
56
|
/** Execute a handler's `handle()` with `this` bound to a capability context. */
|
|
46
57
|
export declare function runHandler<TConfig>(fake: FakePlugin<TConfig>, definition: HandlerDefinition, ...args: unknown[]): Promise<void>;
|
|
58
|
+
export interface RunToolOptions {
|
|
59
|
+
/**
|
|
60
|
+
* Derive `origin` (`kind: 'im'`) and `principal` from an inbound message, so a tool sees the same
|
|
61
|
+
* conversation the command tests use. Explicit `origin` / `principal` win.
|
|
62
|
+
*/
|
|
63
|
+
readonly message?: CommandMessage;
|
|
64
|
+
/** Default: `{ kind: 'im', platform: 'test', endpoint: 'test', scope: 'group', sceneId: 'test-group' }`. */
|
|
65
|
+
readonly origin?: ToolInvocationOrigin;
|
|
66
|
+
readonly principal?: ToolExecutionContext['principal'];
|
|
67
|
+
/** Default: no permissions, attended, network disabled. */
|
|
68
|
+
readonly policy?: Partial<ToolInvocationPolicy>;
|
|
69
|
+
readonly question?: ToolQuestionPort;
|
|
70
|
+
/** Native client port; required when the tool declares `adapter`. */
|
|
71
|
+
readonly client?: OperationClientPort;
|
|
72
|
+
readonly traceId?: string;
|
|
73
|
+
readonly turnId?: string;
|
|
74
|
+
readonly sessionKey?: string;
|
|
75
|
+
readonly signal?: AbortSignal;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Map an inbound message to the Agent tool origin shape (`platform` / `endpoint` / `scope` / `sceneId`),
|
|
79
|
+
* with the same rules as the Agent's IM turn context (`clientAdapter` wins over the endpoint adapter).
|
|
80
|
+
*/
|
|
81
|
+
export declare function toolOriginFromMessage(message: CommandMessage): ToolInvocationOrigin;
|
|
82
|
+
/** Build the context an Agent tool's `execute()` receives, shaped like the real ToolIndex builds it. */
|
|
83
|
+
export declare function createToolContext<TConfig, TAdapter extends string | undefined = undefined>(fake: FakePlugin<TConfig>, options?: RunToolOptions): ToolExecutionContext<TConfig, TAdapter>;
|
|
84
|
+
/**
|
|
85
|
+
* Execute an Agent tool against the fake, the way the Runtime's tool index does: the input is parsed
|
|
86
|
+
* by an executable `inputSchema` (e.g. Zod; JSON Schema inputs pass through unchanged, as in the
|
|
87
|
+
* Runtime), an `adapter`-bound tool requires a matching `client`, then `execute()` runs.
|
|
88
|
+
* It does NOT run model discovery, approval, permission or policy enforcement; use an Agent
|
|
89
|
+
* integration test for those.
|
|
90
|
+
*
|
|
91
|
+
* `tool` is a definition (e.g. the default export of `tools/<name>/index.ts`) or the local name of a
|
|
92
|
+
* tool registered through `addTool()` during `runPluginSetup`.
|
|
93
|
+
*/
|
|
94
|
+
export declare function runTool<TResult = unknown, TConfig = unknown, TInput = unknown>(fake: FakePlugin<TConfig>, tool: AgentToolDefinition<TInput, TResult, TConfig, string | undefined> | string, input?: unknown, options?: RunToolOptions): Promise<TResult>;
|
|
47
95
|
//# sourceMappingURL=fake-runners.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fake-runners.d.ts","sourceRoot":"","sources":["../src/fake-runners.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,cAAc,EAAE,iBAAiB,EAAE,cAAc,EAAE,qBAAqB,EACzE,MAAM,
|
|
1
|
+
{"version":3,"file":"fake-runners.d.ts","sourceRoot":"","sources":["../src/fake-runners.ts"],"names":[],"mappings":"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"}
|
package/lib/fake-runners.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { parseToolInputSchema, } from '@zhin.js/tool';
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
1
3
|
export function createFakeMessage(init = {}) {
|
|
2
4
|
const replies = [];
|
|
3
5
|
const conversation = {
|
|
@@ -36,9 +38,20 @@ export function createCommandContext(fake, options = {}) {
|
|
|
36
38
|
/**
|
|
37
39
|
* Execute a command definition against the fake. This calls `execute()` directly: it does NOT run
|
|
38
40
|
* route matching, parameter parsing, `permit`, or admission. Use `PluginTestKit` for those.
|
|
41
|
+
* Pass `source` to apply the Runtime's convention-path check first.
|
|
39
42
|
*/
|
|
40
43
|
export async function runCommand(fake, definition, options) {
|
|
41
|
-
|
|
44
|
+
const command = options?.source === undefined ? definition : await bindSource(definition, options.source);
|
|
45
|
+
return command.execute(createCommandContext(fake, options));
|
|
46
|
+
}
|
|
47
|
+
async function bindSource(definition, source) {
|
|
48
|
+
const path = source instanceof URL || source.startsWith('file:') ? fileURLToPath(source) : source;
|
|
49
|
+
// Loaded on demand, so an older zhin.js (unmet peer) only fails here, with an actionable message.
|
|
50
|
+
const command = await import('zhin.js/command');
|
|
51
|
+
if (typeof command.bindCommandSource !== 'function') {
|
|
52
|
+
throw new Error('runCommand({ source }) needs a newer zhin.js whose zhin.js/command exports bindCommandSource; upgrade zhin.js');
|
|
53
|
+
}
|
|
54
|
+
return command.bindCommandSource(definition, path).definition;
|
|
42
55
|
}
|
|
43
56
|
/** Execute an inbound or outbound middleware's `handle()`; `next` records whether it was called. */
|
|
44
57
|
export async function runMiddleware(fake, definition, input = createFakeMessage()) {
|
|
@@ -57,4 +70,82 @@ export async function runHandler(fake, definition, ...args) {
|
|
|
57
70
|
const context = fake.capabilityContext();
|
|
58
71
|
await definition.handle.call(context, ...args);
|
|
59
72
|
}
|
|
73
|
+
/**
|
|
74
|
+
* Map an inbound message to the Agent tool origin shape (`platform` / `endpoint` / `scope` / `sceneId`),
|
|
75
|
+
* with the same rules as the Agent's IM turn context (`clientAdapter` wins over the endpoint adapter).
|
|
76
|
+
*/
|
|
77
|
+
export function toolOriginFromMessage(message) {
|
|
78
|
+
const { conversation } = message;
|
|
79
|
+
return Object.freeze({
|
|
80
|
+
kind: 'im',
|
|
81
|
+
platform: message.clientAdapter ?? conversation.endpoint.adapter,
|
|
82
|
+
endpoint: conversation.endpoint.id,
|
|
83
|
+
scope: conversation.kind,
|
|
84
|
+
sceneId: conversation.id,
|
|
85
|
+
...(message.id === undefined ? {} : { messageId: message.id }),
|
|
86
|
+
...(conversation.threadId === undefined ? {} : { threadId: conversation.threadId }),
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
/** Build the context an Agent tool's `execute()` receives, shaped like the real ToolIndex builds it. */
|
|
90
|
+
export function createToolContext(fake, options = {}) {
|
|
91
|
+
const message = options.message;
|
|
92
|
+
const sender = message?.sender;
|
|
93
|
+
const policy = options.policy ?? {};
|
|
94
|
+
const context = {
|
|
95
|
+
...fake.capabilityContext(),
|
|
96
|
+
signal: options.signal ?? fake.signal,
|
|
97
|
+
traceId: options.traceId ?? 'test-trace',
|
|
98
|
+
turnId: options.turnId ?? 'test-turn',
|
|
99
|
+
sessionKey: options.sessionKey ?? (message
|
|
100
|
+
? `${message.conversation.endpoint.adapter}:${message.conversation.endpoint.id}:${message.conversation.kind}:${message.conversation.id}`
|
|
101
|
+
: 'test-session'),
|
|
102
|
+
origin: Object.freeze({ ...(options.origin ?? (message ? toolOriginFromMessage(message) : {
|
|
103
|
+
kind: 'im', platform: 'test', endpoint: 'test', scope: 'group', sceneId: 'test-group',
|
|
104
|
+
})) }),
|
|
105
|
+
principal: Object.freeze({ ...(options.principal ?? {
|
|
106
|
+
subjectId: sender?.id ?? 'test-user',
|
|
107
|
+
...(sender?.name === undefined ? {} : { displayName: sender.name }),
|
|
108
|
+
roles: sender?.roles ?? [],
|
|
109
|
+
}) }),
|
|
110
|
+
policy: Object.freeze({
|
|
111
|
+
permissions: Object.freeze([...(policy.permissions ?? [])]),
|
|
112
|
+
unattended: policy.unattended ?? false,
|
|
113
|
+
network: Object.freeze({ enabled: false, ...policy.network }),
|
|
114
|
+
...(policy.shell ? { shell: Object.freeze({ ...policy.shell }) } : {}),
|
|
115
|
+
...(policy.filesystem ? { filesystem: Object.freeze({ ...policy.filesystem }) } : {}),
|
|
116
|
+
}),
|
|
117
|
+
...(options.question ? { question: options.question } : {}),
|
|
118
|
+
};
|
|
119
|
+
Object.defineProperty(context, '$client', { enumerable: true, get: () => options.client?.get() });
|
|
120
|
+
return Object.freeze(context);
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Execute an Agent tool against the fake, the way the Runtime's tool index does: the input is parsed
|
|
124
|
+
* by an executable `inputSchema` (e.g. Zod; JSON Schema inputs pass through unchanged, as in the
|
|
125
|
+
* Runtime), an `adapter`-bound tool requires a matching `client`, then `execute()` runs.
|
|
126
|
+
* It does NOT run model discovery, approval, permission or policy enforcement; use an Agent
|
|
127
|
+
* integration test for those.
|
|
128
|
+
*
|
|
129
|
+
* `tool` is a definition (e.g. the default export of `tools/<name>/index.ts`) or the local name of a
|
|
130
|
+
* tool registered through `addTool()` during `runPluginSetup`.
|
|
131
|
+
*/
|
|
132
|
+
export async function runTool(fake, tool, input, options = {}) {
|
|
133
|
+
const definition = typeof tool === 'string' ? registeredTool(fake, tool) : tool;
|
|
134
|
+
const name = typeof tool === 'string' ? tool : 'tool';
|
|
135
|
+
const parsed = parseToolInputSchema(definition.inputSchema, input ?? {});
|
|
136
|
+
if (!parsed.ok)
|
|
137
|
+
throw new TypeError(`Invalid Agent Tool input for ${name}: ${parsed.error}`);
|
|
138
|
+
if (definition.adapter && options.client?.adapter !== definition.adapter) {
|
|
139
|
+
throw new Error(`Agent Tool ${name} requires adapter ${definition.adapter}`);
|
|
140
|
+
}
|
|
141
|
+
return await definition.execute(parsed.data, createToolContext(fake, options));
|
|
142
|
+
}
|
|
143
|
+
function registeredTool(fake, localName) {
|
|
144
|
+
const found = fake.features.find(feature => feature.kind === 'tool' && feature.localName === localName);
|
|
145
|
+
if (!found) {
|
|
146
|
+
const known = fake.features.filter(feature => feature.kind === 'tool').map(feature => feature.localName);
|
|
147
|
+
throw new Error(`No tool "${localName}" was registered through addTool()${known.length ? `; registered: ${known.join(', ')}` : ''}`);
|
|
148
|
+
}
|
|
149
|
+
return found.definition;
|
|
150
|
+
}
|
|
60
151
|
//# sourceMappingURL=fake-runners.js.map
|
package/lib/fake-runners.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fake-runners.js","sourceRoot":"","sources":["../src/fake-runners.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"fake-runners.js","sourceRoot":"","sources":["../src/fake-runners.ts"],"names":[],"mappings":"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"}
|
package/lib/index.d.ts
CHANGED
|
@@ -1,17 +1,21 @@
|
|
|
1
|
-
import { type AdapterSegmentPolicy, type EndpointIncomingMessage } from '
|
|
2
|
-
import { ImRuntime, type ConversationAddress, type MessageDispatchResult, type SendContent } from '
|
|
3
|
-
import { type ConversationRef, type DeliveryReceipt } from '
|
|
4
|
-
import { type ConfigPatch, type PluginId, type RuntimeConfigDocument } from '
|
|
5
|
-
import { type ModuleRuntime, type RootResourceInstaller } from '@zhin.js/runtime';
|
|
1
|
+
import { type AdapterSegmentPolicy, type EndpointIncomingMessage } from 'zhin.js/adapter';
|
|
2
|
+
import { ImRuntime, type ConversationAddress, type MessageDispatchResult, type RuntimeMessageDiagnosticsReader, type SendContent } from 'zhin.js/core/runtime';
|
|
3
|
+
import { type ConversationRef, type DeliveryReceipt } from 'zhin.js';
|
|
4
|
+
import { type ConfigDocumentPort, type ConfigPatch, type PluginId, type RuntimeConfigDocument } from 'zhin.js/plugin-runtime';
|
|
5
|
+
import { RootRuntime, type ModuleRuntime, type RootResourceInstaller } from '@zhin.js/runtime';
|
|
6
6
|
export { FakeClock, FakeScheduleRootHost, parseCron, type FakeScheduledJob } from './fake-clock.js';
|
|
7
7
|
export { FakeDatabaseRootHost, FakeOutboundRootHost, type FakeOutboundCall } from './fake-hosts.js';
|
|
8
|
-
export { FakePlugin, createFakePlugin, runPluginSetup, fakeResource, type FakePluginOptions, type FakeResource, type FakeRegisteredFeature } from './fake-plugin.js';
|
|
8
|
+
export { FakePlugin, createFakePlugin, runPluginSetup, resolvePluginConfig, PluginConfigValidationError, fakeResource, type FakePluginOptions, type RunPluginSetupOptions, type FakeResource, type FakeRegisteredFeature } from './fake-plugin.js';
|
|
9
9
|
export { fakeOf } from './partial.js';
|
|
10
|
-
export { createFakeMessage, createCommandContext, runCommand, runMiddleware, runHandler, type FakeMessage, type FakeMessageInit, type RunCommandOptions, type RunMiddlewareResult } from './fake-runners.js';
|
|
10
|
+
export { createFakeMessage, createCommandContext, runCommand, runMiddleware, runHandler, createToolContext, runTool, toolOriginFromMessage, type FakeMessage, type RunToolOptions, type FakeMessageInit, type RunCommandOptions, type RunMiddlewareResult } from './fake-runners.js';
|
|
11
11
|
export interface PluginTestKitOptions {
|
|
12
12
|
/** A real, disposable test app with its own package.json, plugin entry, dependencies and mounts. */
|
|
13
13
|
readonly projectRoot: string;
|
|
14
|
-
|
|
14
|
+
/**
|
|
15
|
+
* A v2 document, or a file-backed document such as `createConfigDocument(path)` from
|
|
16
|
+
* `@zhin.js/config-file` when the test must share the same file authority as `zhin start`.
|
|
17
|
+
*/
|
|
18
|
+
readonly config?: RuntimeConfigDocument | ConfigDocumentPort;
|
|
15
19
|
/** Adapter names reserved for synthetic transports, default: ['test']. */
|
|
16
20
|
readonly endpoints?: readonly string[];
|
|
17
21
|
/** Default endpoint renders HTML and buttons as text; override to verify negotiated capabilities. */
|
|
@@ -54,6 +58,10 @@ export declare class PluginTestKit {
|
|
|
54
58
|
static create(options: PluginTestKitOptions): Promise<PluginTestKit>;
|
|
55
59
|
/** The same PermissionHost consumed by real command admission. */
|
|
56
60
|
get permissions(): ImRuntime['permissionHost'];
|
|
61
|
+
/** The same bounded, body-free reader the Console serves at `GET /api/messages/diagnostics`. */
|
|
62
|
+
get messageDiagnostics(): RuntimeMessageDiagnosticsReader;
|
|
63
|
+
/** The committed-snapshot authority Console routes read (tasks, permissions); read-only use in tests. */
|
|
64
|
+
get snapshots(): RootRuntime['snapshots'];
|
|
57
65
|
get generation(): number;
|
|
58
66
|
get deliveries(): readonly TestDelivery[];
|
|
59
67
|
clearDeliveries(): void;
|
package/lib/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAyC,KAAK,oBAAoB,EACxB,KAAK,uBAAuB,EAA4B,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/lib/index.js
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { realpath } from 'node:fs/promises';
|
|
2
2
|
import { resolve } from 'node:path';
|
|
3
|
-
import { defineAdapter } from '
|
|
4
|
-
import { ImRuntime } from '
|
|
5
|
-
import { rootPluginId } from '
|
|
3
|
+
import { defineAdapter } from 'zhin.js/adapter';
|
|
4
|
+
import { ImRuntime } from 'zhin.js/core/runtime';
|
|
5
|
+
import { rootPluginId } from 'zhin.js/plugin-runtime';
|
|
6
6
|
import { NativeDevelopmentModuleRuntime, NodePackageResolver, RootRuntime } from '@zhin.js/runtime';
|
|
7
7
|
import { captureDeliveryValue } from './delivery-capture.js';
|
|
8
8
|
import { withTestEndpoints } from './test-module-runtime.js';
|
|
9
9
|
export { FakeClock, FakeScheduleRootHost, parseCron } from './fake-clock.js';
|
|
10
10
|
export { FakeDatabaseRootHost, FakeOutboundRootHost } from './fake-hosts.js';
|
|
11
|
-
export { FakePlugin, createFakePlugin, runPluginSetup, fakeResource } from './fake-plugin.js';
|
|
11
|
+
export { FakePlugin, createFakePlugin, runPluginSetup, resolvePluginConfig, PluginConfigValidationError, fakeResource } from './fake-plugin.js';
|
|
12
12
|
export { fakeOf } from './partial.js';
|
|
13
|
-
export { createFakeMessage, createCommandContext, runCommand, runMiddleware, runHandler } from './fake-runners.js';
|
|
13
|
+
export { createFakeMessage, createCommandContext, runCommand, runMiddleware, runHandler, createToolContext, runTool, toolOriginFromMessage } from './fake-runners.js';
|
|
14
14
|
/**
|
|
15
15
|
* Owns a test IM host and synthetic transports. Every operation enters the real Root Runtime.
|
|
16
16
|
* It does not install dependencies or replace providers. Discovered plugins still execute normally;
|
|
@@ -88,6 +88,10 @@ export class PluginTestKit {
|
|
|
88
88
|
}
|
|
89
89
|
/** The same PermissionHost consumed by real command admission. */
|
|
90
90
|
get permissions() { return this.#im.permissionHost; }
|
|
91
|
+
/** The same bounded, body-free reader the Console serves at `GET /api/messages/diagnostics`. */
|
|
92
|
+
get messageDiagnostics() { return this.#im.messageDiagnostics; }
|
|
93
|
+
/** The committed-snapshot authority Console routes read (tasks, permissions); read-only use in tests. */
|
|
94
|
+
get snapshots() { return this.#root.snapshots; }
|
|
91
95
|
get generation() { return this.#root.snapshot.generation; }
|
|
92
96
|
get deliveries() { return Object.freeze(this.#attempts.map(item => captureDeliveryValue(item))); }
|
|
93
97
|
clearDeliveries() { this.#attempts.splice(0); }
|
package/lib/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,aAAa,EACmF,MAAM,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AdapterDefinition } from '
|
|
1
|
+
import type { AdapterDefinition } from 'zhin.js/adapter';
|
|
2
2
|
import type { ModuleRuntime } from '@zhin.js/runtime';
|
|
3
3
|
/** Only the test application's setup is decorated; discovery and module caching stay native. */
|
|
4
4
|
export declare function withTestEndpoints(delegate: ModuleRuntime, rootEntry: string, endpoints: ReadonlyMap<string, AdapterDefinition>): ModuleRuntime;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test-module-runtime.d.ts","sourceRoot":"","sources":["../src/test-module-runtime.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"test-module-runtime.d.ts","sourceRoot":"","sources":["../src/test-module-runtime.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAEtD,gGAAgG;AAChG,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,aAAa,EACvB,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,WAAW,CAAC,MAAM,EAAE,iBAAiB,CAAC,GAChD,aAAa,CA2Bf"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { resolve } from 'node:path';
|
|
2
|
-
import { definePlugin } from '
|
|
2
|
+
import { definePlugin } from 'zhin.js/plugin-runtime';
|
|
3
3
|
/** Only the test application's setup is decorated; discovery and module caching stay native. */
|
|
4
4
|
export function withTestEndpoints(delegate, rootEntry, endpoints) {
|
|
5
5
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test-module-runtime.js","sourceRoot":"","sources":["../src/test-module-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,YAAY,EAAyB,MAAM,
|
|
1
|
+
{"version":3,"file":"test-module-runtime.js","sourceRoot":"","sources":["../src/test-module-runtime.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhin.js/testing",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"description": "Real Plugin Runtime integration fixtures with synthetic IM endpoints",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./lib/index.js",
|
|
@@ -16,21 +16,23 @@
|
|
|
16
16
|
"src",
|
|
17
17
|
"README.md"
|
|
18
18
|
],
|
|
19
|
-
"
|
|
20
|
-
"
|
|
21
|
-
"@zhin.js/
|
|
22
|
-
"@zhin.js/
|
|
23
|
-
"@zhin.js/feature-kit": "1.1.6",
|
|
24
|
-
"@zhin.js/handler": "1.1.6",
|
|
25
|
-
"@zhin.js/middleware": "1.1.7",
|
|
26
|
-
"@zhin.js/im-contract": "1.1.4",
|
|
27
|
-
"@zhin.js/plugin-runtime": "1.1.15",
|
|
28
|
-
"@zhin.js/runtime": "1.1.9"
|
|
19
|
+
"peerDependencies": {
|
|
20
|
+
"zhin.js": "^1.1.12",
|
|
21
|
+
"@zhin.js/runtime": "^1.1.10",
|
|
22
|
+
"@zhin.js/tool": "^1.1.8"
|
|
29
23
|
},
|
|
30
24
|
"devDependencies": {
|
|
31
25
|
"@types/node": "^26.1.2",
|
|
32
26
|
"typescript": "^6.0.3",
|
|
33
|
-
"vitest": "^4.1.10"
|
|
27
|
+
"vitest": "^4.1.10",
|
|
28
|
+
"@zhin.js/command": "1.1.9",
|
|
29
|
+
"@zhin.js/adapter": "1.1.21",
|
|
30
|
+
"@zhin.js/middleware": "1.1.8",
|
|
31
|
+
"@zhin.js/core": "1.1.47",
|
|
32
|
+
"@zhin.js/plugin-runtime": "1.1.15",
|
|
33
|
+
"@zhin.js/runtime": "1.1.10",
|
|
34
|
+
"@zhin.js/tool": "1.1.8",
|
|
35
|
+
"zhin.js": "1.1.12"
|
|
34
36
|
},
|
|
35
37
|
"engines": {
|
|
36
38
|
"node": ">=22.19.0"
|
package/src/fake-clock.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { PluginId, ScheduleHost, ScheduleJobRegistration } from '
|
|
1
|
+
import type { PluginId, ScheduleHost, ScheduleJobRegistration } from 'zhin.js/plugin-runtime';
|
|
2
2
|
|
|
3
3
|
/** Controllable wall clock. It never touches the real `Date` or timers. */
|
|
4
4
|
export class FakeClock {
|
|
@@ -15,13 +15,21 @@ export class FakeClock {
|
|
|
15
15
|
/** Jump without firing anything (like setting the system time). */
|
|
16
16
|
set(time: number | Date): void { this.#now = typeof time === 'number' ? time : time.getTime(); }
|
|
17
17
|
|
|
18
|
-
/**
|
|
18
|
+
/**
|
|
19
|
+
* Move forward and run every cron job that became due, in time order.
|
|
20
|
+
*
|
|
21
|
+
* The clock always ends at the target time, even when a job throws. After a failure the error
|
|
22
|
+
* is rethrown and the remaining jobs due inside the same window are NOT run (they are skipped, not deferred).
|
|
23
|
+
*/
|
|
19
24
|
async advance(ms: number): Promise<void> {
|
|
20
25
|
if (!(ms >= 0)) throw new RangeError('FakeClock.advance requires a non-negative duration');
|
|
21
26
|
const from = this.#now;
|
|
22
27
|
const to = from + ms;
|
|
23
|
-
|
|
24
|
-
|
|
28
|
+
try {
|
|
29
|
+
for (const listener of [...this.#listeners]) await listener(from, to);
|
|
30
|
+
} finally {
|
|
31
|
+
this.#now = to;
|
|
32
|
+
}
|
|
25
33
|
}
|
|
26
34
|
|
|
27
35
|
/** @internal */
|
|
@@ -89,6 +97,8 @@ export class FakeScheduleRootHost implements ScheduleHost {
|
|
|
89
97
|
clock.onAdvance(async (from, to) => {
|
|
90
98
|
for (let t = Math.floor(from / 1000) * 1000 + 1000; t <= to; t += 1000) {
|
|
91
99
|
const date = new Date(t);
|
|
100
|
+
// A job firing at `t` must observe `t` (e.g. to decide what is due), not the advance() start.
|
|
101
|
+
clock.set(t);
|
|
92
102
|
for (const job of [...this.#jobs]) {
|
|
93
103
|
if (this.#jobs.has(job) && job.isActive?.() !== false && job.matches(date)) await job.execute();
|
|
94
104
|
}
|
package/src/fake-hosts.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type {
|
|
|
3
3
|
DatabaseHost, DatabaseHostModel, DatabaseHostSelection, DeliveryTarget, JsonValue,
|
|
4
4
|
OutboundEditInput, OutboundReactionInput, OutboundRecallInput, OutboundRootHost, OutboundSendInput,
|
|
5
5
|
OutboundTypingInput, PersistentStatePort, PluginId, StateRecord, StateScope,
|
|
6
|
-
} from '
|
|
6
|
+
} from 'zhin.js/plugin-runtime';
|
|
7
7
|
|
|
8
8
|
type Row = Record<string, unknown>;
|
|
9
9
|
const matches = (row: Row, query: Row): boolean => Object.entries(query).every(([k, v]) => row[k] === v);
|
package/src/fake-plugin.ts
CHANGED
|
@@ -3,8 +3,9 @@ import {
|
|
|
3
3
|
Scope, databaseHostToken, outboundHostToken, qualifyPluginResourceName, rootPluginId, scheduleHostToken,
|
|
4
4
|
type Dispose, type FeatureId, type PluginDefinition, type PluginId, type PluginNodeSnapshot,
|
|
5
5
|
type PluginSetupContext, type Token,
|
|
6
|
-
} from '
|
|
7
|
-
import type { CapabilityContext } from '
|
|
6
|
+
} from 'zhin.js/plugin-runtime';
|
|
7
|
+
import type { CapabilityContext } from 'zhin.js';
|
|
8
|
+
import { parsePluginConfigSchema } from '@zhin.js/runtime';
|
|
8
9
|
import { FakeClock, FakeScheduleRootHost } from './fake-clock.js';
|
|
9
10
|
import { FakeDatabaseRootHost, FakeOutboundRootHost, type FakeOutboundCall } from './fake-hosts.js';
|
|
10
11
|
|
|
@@ -118,6 +119,7 @@ export class FakePlugin<TConfig = unknown> {
|
|
|
118
119
|
signal: this.signal, owner, generation: this.generation,
|
|
119
120
|
config: this.config as Readonly<TConfig>,
|
|
120
121
|
use: <T>(token: Token<T>): T => this.resources.use(token),
|
|
122
|
+
has: (token: Token<unknown>): boolean => this.resources.has(token),
|
|
121
123
|
project: <T>(feature: FeatureId): T => {
|
|
122
124
|
if (!this.projections.has(feature)) throw new Error(`Missing Feature projection ${feature}`);
|
|
123
125
|
return this.projections.get(feature) as T;
|
|
@@ -160,12 +162,76 @@ export function createFakePlugin<TConfig = unknown>(options?: FakePluginOptions<
|
|
|
160
162
|
return new FakePlugin(options);
|
|
161
163
|
}
|
|
162
164
|
|
|
163
|
-
|
|
165
|
+
export interface RunPluginSetupOptions<TConfig = unknown> extends Omit<FakePluginOptions<TConfig>, 'name' | 'config'> {
|
|
166
|
+
/**
|
|
167
|
+
* Raw plugin configuration, as a user would write it under the instance key in `zhin.config.yml`.
|
|
168
|
+
* When the definition declares `config`, it is validated and defaulted like the real Runtime does.
|
|
169
|
+
*/
|
|
170
|
+
readonly config?: Partial<TConfig>;
|
|
171
|
+
/**
|
|
172
|
+
* Validate `config` against `definition.config` and apply its defaults (default `true`).
|
|
173
|
+
* Set `false` to pass `config` to `setup()` verbatim, as earlier versions of `runPluginSetup` did.
|
|
174
|
+
*/
|
|
175
|
+
readonly validateConfig?: boolean;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/** Thrown by {@link runPluginSetup} / {@link resolvePluginConfig} when config fails the plugin's schema. */
|
|
179
|
+
export class PluginConfigValidationError extends TypeError {
|
|
180
|
+
override readonly name = 'PluginConfigValidationError';
|
|
181
|
+
constructor(
|
|
182
|
+
readonly plugin: string,
|
|
183
|
+
/** Human-readable `instancePath message` lines, same wording as Runtime startup errors. */
|
|
184
|
+
readonly issues: readonly string[],
|
|
185
|
+
) {
|
|
186
|
+
super(`Invalid config for plugin ${plugin}:\n ${issues.join('\n ')}`);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Resolve the config view `setup()` would receive from the real Runtime: validate `input` against
|
|
192
|
+
* `definition.config`, fill schema defaults, and keep only the top-level fields the schema declares.
|
|
193
|
+
* Without a declared `config` schema the input is returned unchanged (`{}` when omitted).
|
|
194
|
+
*/
|
|
195
|
+
export function resolvePluginConfig<TConfig = unknown>(
|
|
196
|
+
definition: Pick<PluginDefinition<TConfig>, 'name' | 'config'>,
|
|
197
|
+
input?: unknown,
|
|
198
|
+
): TConfig {
|
|
199
|
+
if (!definition.config) return (input ?? {}) as TConfig;
|
|
200
|
+
const schema = definition.config.toJsonSchema();
|
|
201
|
+
const { value, errors } = parsePluginConfigSchema(schema, input);
|
|
202
|
+
if (errors.length) {
|
|
203
|
+
throw new PluginConfigValidationError(definition.name, errors.map((error) => {
|
|
204
|
+
const params = error.params as Record<string, unknown> | undefined;
|
|
205
|
+
const detail = typeof params?.additionalProperty === 'string'
|
|
206
|
+
? ` (additionalProperty: ${params.additionalProperty})`
|
|
207
|
+
: Array.isArray(params?.allowedValues) ? ` (allowedValues: ${JSON.stringify(params.allowedValues)})` : '';
|
|
208
|
+
const path = error.instancePath.replace(/^\/candidate/, '');
|
|
209
|
+
return `${path || '/'} ${error.message ?? error.keyword}${detail}`;
|
|
210
|
+
}));
|
|
211
|
+
}
|
|
212
|
+
// The Runtime re-picks a plugin's own top-level fields (see config-composer `pickOwnFields`).
|
|
213
|
+
const properties = schema.properties && typeof schema.properties === 'object' && !Array.isArray(schema.properties)
|
|
214
|
+
? Object.keys(schema.properties)
|
|
215
|
+
: [];
|
|
216
|
+
const record = value && typeof value === 'object' ? value as Record<string, unknown> : {};
|
|
217
|
+
const view: Record<string, unknown> = {};
|
|
218
|
+
for (const key of properties) if (Object.hasOwn(record, key)) view[key] = record[key];
|
|
219
|
+
return view as TConfig;
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Create a fake and run `definition.setup()` in one step. Call `dispose()` when done.
|
|
224
|
+
*
|
|
225
|
+
* When the plugin declares a `config` schema, `options.config` is validated and defaulted first
|
|
226
|
+
* (throws {@link PluginConfigValidationError}); pass `validateConfig: false` to opt out.
|
|
227
|
+
*/
|
|
164
228
|
export async function runPluginSetup<TConfig = unknown>(
|
|
165
229
|
definition: PluginDefinition<TConfig>,
|
|
166
|
-
options
|
|
230
|
+
options: RunPluginSetupOptions<TConfig> = {},
|
|
167
231
|
): Promise<FakePlugin<TConfig>> {
|
|
168
|
-
const
|
|
232
|
+
const { validateConfig = true, config, ...rest } = options;
|
|
233
|
+
const resolved = validateConfig ? resolvePluginConfig(definition, config) : config as TConfig | undefined;
|
|
234
|
+
const fake = new FakePlugin<TConfig>({ ...rest, ...(resolved === undefined ? {} : { config: resolved }), name: definition.name });
|
|
169
235
|
await fake.setup(definition);
|
|
170
236
|
return fake;
|
|
171
237
|
}
|
package/src/fake-runners.ts
CHANGED
|
@@ -1,11 +1,18 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
CommandContext, CommandDefinition, CommandMessage, CommandParameterValue,
|
|
3
|
-
} from '
|
|
4
|
-
import type { HandlerContext, HandlerDefinition } from '
|
|
3
|
+
} from 'zhin.js/command';
|
|
4
|
+
import type { HandlerContext, HandlerDefinition } from 'zhin.js/handler';
|
|
5
5
|
import type {
|
|
6
6
|
MiddlewareContext, MiddlewareDefinition, MiddlewareNext,
|
|
7
|
-
} from '
|
|
7
|
+
} from 'zhin.js/middleware';
|
|
8
|
+
import {
|
|
9
|
+
parseToolInputSchema,
|
|
10
|
+
type AgentToolDefinition, type ToolExecutionContext, type ToolInvocationOrigin,
|
|
11
|
+
type ToolInvocationPolicy, type ToolQuestionPort,
|
|
12
|
+
} from '@zhin.js/tool';
|
|
13
|
+
import type { OperationClientPort } from 'zhin.js';
|
|
8
14
|
import type { FakePlugin } from './fake-plugin.js';
|
|
15
|
+
import { fileURLToPath } from 'node:url';
|
|
9
16
|
|
|
10
17
|
/** Inbound message with recorded replies. */
|
|
11
18
|
export interface FakeMessage extends CommandMessage {
|
|
@@ -45,6 +52,14 @@ export interface RunCommandOptions<TInput extends CommandMessage = FakeMessage>
|
|
|
45
52
|
readonly options?: Readonly<Record<string, CommandParameterValue>>;
|
|
46
53
|
readonly segments?: CommandContext['segments'];
|
|
47
54
|
readonly interaction?: CommandContext['interaction'];
|
|
55
|
+
/**
|
|
56
|
+
* Where the command lives: its `commands/.../index.ts` file (or directory), as a path or a
|
|
57
|
+
* `file:` URL such as `new URL('../commands/echo/[text]/index.ts', import.meta.url)`. When set,
|
|
58
|
+
* the definition first goes through the Runtime's convention-path check (`bindCommandSource`
|
|
59
|
+
* from `zhin.js/command`): a layout the Runtime would reject, e.g. `commands/term/[word]/[...rest]`,
|
|
60
|
+
* throws here too, and the directory parameter is bound as in the Runtime.
|
|
61
|
+
*/
|
|
62
|
+
readonly source?: string | URL;
|
|
48
63
|
}
|
|
49
64
|
|
|
50
65
|
/** Build the context a command receives from the fake plugin; usable for direct `execute()` calls. */
|
|
@@ -74,13 +89,27 @@ export function createCommandContext<TConfig, TInput extends CommandMessage = Fa
|
|
|
74
89
|
/**
|
|
75
90
|
* Execute a command definition against the fake. This calls `execute()` directly: it does NOT run
|
|
76
91
|
* route matching, parameter parsing, `permit`, or admission. Use `PluginTestKit` for those.
|
|
92
|
+
* Pass `source` to apply the Runtime's convention-path check first.
|
|
77
93
|
*/
|
|
78
94
|
export async function runCommand<TConfig, TResult, TInput extends CommandMessage = FakeMessage>(
|
|
79
95
|
fake: FakePlugin<TConfig>,
|
|
80
96
|
definition: CommandDefinition<TConfig, TResult, TInput, string | undefined>,
|
|
81
97
|
options?: RunCommandOptions<TInput>,
|
|
82
98
|
): Promise<TResult> {
|
|
83
|
-
|
|
99
|
+
const command = options?.source === undefined ? definition : await bindSource(definition, options.source);
|
|
100
|
+
return command.execute(createCommandContext(fake, options));
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async function bindSource<T extends CommandDefinition<never, unknown, never, string | undefined>>(
|
|
104
|
+
definition: T, source: string | URL,
|
|
105
|
+
): Promise<T> {
|
|
106
|
+
const path = source instanceof URL || source.startsWith('file:') ? fileURLToPath(source) : source;
|
|
107
|
+
// Loaded on demand, so an older zhin.js (unmet peer) only fails here, with an actionable message.
|
|
108
|
+
const command: Partial<typeof import('zhin.js/command')> = await import('zhin.js/command');
|
|
109
|
+
if (typeof command.bindCommandSource !== 'function') {
|
|
110
|
+
throw new Error('runCommand({ source }) needs a newer zhin.js whose zhin.js/command exports bindCommandSource; upgrade zhin.js');
|
|
111
|
+
}
|
|
112
|
+
return command.bindCommandSource(definition as never, path).definition as unknown as T;
|
|
84
113
|
}
|
|
85
114
|
|
|
86
115
|
export interface RunMiddlewareResult {
|
|
@@ -115,3 +144,114 @@ export async function runHandler<TConfig>(
|
|
|
115
144
|
const context: HandlerContext<TConfig> = fake.capabilityContext();
|
|
116
145
|
await definition.handle.call(context as HandlerContext, ...args);
|
|
117
146
|
}
|
|
147
|
+
|
|
148
|
+
export interface RunToolOptions {
|
|
149
|
+
/**
|
|
150
|
+
* Derive `origin` (`kind: 'im'`) and `principal` from an inbound message, so a tool sees the same
|
|
151
|
+
* conversation the command tests use. Explicit `origin` / `principal` win.
|
|
152
|
+
*/
|
|
153
|
+
readonly message?: CommandMessage;
|
|
154
|
+
/** Default: `{ kind: 'im', platform: 'test', endpoint: 'test', scope: 'group', sceneId: 'test-group' }`. */
|
|
155
|
+
readonly origin?: ToolInvocationOrigin;
|
|
156
|
+
readonly principal?: ToolExecutionContext['principal'];
|
|
157
|
+
/** Default: no permissions, attended, network disabled. */
|
|
158
|
+
readonly policy?: Partial<ToolInvocationPolicy>;
|
|
159
|
+
readonly question?: ToolQuestionPort;
|
|
160
|
+
/** Native client port; required when the tool declares `adapter`. */
|
|
161
|
+
readonly client?: OperationClientPort;
|
|
162
|
+
readonly traceId?: string;
|
|
163
|
+
readonly turnId?: string;
|
|
164
|
+
readonly sessionKey?: string;
|
|
165
|
+
readonly signal?: AbortSignal;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Map an inbound message to the Agent tool origin shape (`platform` / `endpoint` / `scope` / `sceneId`),
|
|
170
|
+
* with the same rules as the Agent's IM turn context (`clientAdapter` wins over the endpoint adapter).
|
|
171
|
+
*/
|
|
172
|
+
export function toolOriginFromMessage(message: CommandMessage): ToolInvocationOrigin {
|
|
173
|
+
const { conversation } = message;
|
|
174
|
+
return Object.freeze({
|
|
175
|
+
kind: 'im' as const,
|
|
176
|
+
platform: message.clientAdapter ?? conversation.endpoint.adapter,
|
|
177
|
+
endpoint: conversation.endpoint.id,
|
|
178
|
+
scope: conversation.kind,
|
|
179
|
+
sceneId: conversation.id,
|
|
180
|
+
...(message.id === undefined ? {} : { messageId: message.id }),
|
|
181
|
+
...(conversation.threadId === undefined ? {} : { threadId: conversation.threadId }),
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/** Build the context an Agent tool's `execute()` receives, shaped like the real ToolIndex builds it. */
|
|
186
|
+
export function createToolContext<TConfig, TAdapter extends string | undefined = undefined>(
|
|
187
|
+
fake: FakePlugin<TConfig>,
|
|
188
|
+
options: RunToolOptions = {},
|
|
189
|
+
): ToolExecutionContext<TConfig, TAdapter> {
|
|
190
|
+
const message = options.message;
|
|
191
|
+
const sender = message?.sender;
|
|
192
|
+
const policy = options.policy ?? {};
|
|
193
|
+
const context = {
|
|
194
|
+
...fake.capabilityContext(),
|
|
195
|
+
signal: options.signal ?? fake.signal,
|
|
196
|
+
traceId: options.traceId ?? 'test-trace',
|
|
197
|
+
turnId: options.turnId ?? 'test-turn',
|
|
198
|
+
sessionKey: options.sessionKey ?? (message
|
|
199
|
+
? `${message.conversation.endpoint.adapter}:${message.conversation.endpoint.id}:${message.conversation.kind}:${message.conversation.id}`
|
|
200
|
+
: 'test-session'),
|
|
201
|
+
origin: Object.freeze({ ...(options.origin ?? (message ? toolOriginFromMessage(message) : {
|
|
202
|
+
kind: 'im', platform: 'test', endpoint: 'test', scope: 'group', sceneId: 'test-group',
|
|
203
|
+
})) }) as ToolInvocationOrigin,
|
|
204
|
+
principal: Object.freeze({ ...(options.principal ?? {
|
|
205
|
+
subjectId: sender?.id ?? 'test-user',
|
|
206
|
+
...(sender?.name === undefined ? {} : { displayName: sender.name }),
|
|
207
|
+
roles: sender?.roles ?? [],
|
|
208
|
+
}) }),
|
|
209
|
+
policy: Object.freeze({
|
|
210
|
+
permissions: Object.freeze([...(policy.permissions ?? [])]),
|
|
211
|
+
unattended: policy.unattended ?? false,
|
|
212
|
+
network: Object.freeze({ enabled: false, ...policy.network }),
|
|
213
|
+
...(policy.shell ? { shell: Object.freeze({ ...policy.shell }) } : {}),
|
|
214
|
+
...(policy.filesystem ? { filesystem: Object.freeze({ ...policy.filesystem }) } : {}),
|
|
215
|
+
}),
|
|
216
|
+
...(options.question ? { question: options.question } : {}),
|
|
217
|
+
} as ToolExecutionContext<TConfig, TAdapter>;
|
|
218
|
+
Object.defineProperty(context, '$client', { enumerable: true, get: () => options.client?.get() });
|
|
219
|
+
return Object.freeze(context);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Execute an Agent tool against the fake, the way the Runtime's tool index does: the input is parsed
|
|
224
|
+
* by an executable `inputSchema` (e.g. Zod; JSON Schema inputs pass through unchanged, as in the
|
|
225
|
+
* Runtime), an `adapter`-bound tool requires a matching `client`, then `execute()` runs.
|
|
226
|
+
* It does NOT run model discovery, approval, permission or policy enforcement; use an Agent
|
|
227
|
+
* integration test for those.
|
|
228
|
+
*
|
|
229
|
+
* `tool` is a definition (e.g. the default export of `tools/<name>/index.ts`) or the local name of a
|
|
230
|
+
* tool registered through `addTool()` during `runPluginSetup`.
|
|
231
|
+
*/
|
|
232
|
+
export async function runTool<TResult = unknown, TConfig = unknown, TInput = unknown>(
|
|
233
|
+
fake: FakePlugin<TConfig>,
|
|
234
|
+
tool: AgentToolDefinition<TInput, TResult, TConfig, string | undefined> | string,
|
|
235
|
+
input?: unknown,
|
|
236
|
+
options: RunToolOptions = {},
|
|
237
|
+
): Promise<TResult> {
|
|
238
|
+
const definition = typeof tool === 'string' ? registeredTool<TInput, TResult, TConfig>(fake, tool) : tool;
|
|
239
|
+
const name = typeof tool === 'string' ? tool : 'tool';
|
|
240
|
+
const parsed = parseToolInputSchema(definition.inputSchema, input ?? {});
|
|
241
|
+
if (!parsed.ok) throw new TypeError(`Invalid Agent Tool input for ${name}: ${parsed.error}`);
|
|
242
|
+
if (definition.adapter && options.client?.adapter !== definition.adapter) {
|
|
243
|
+
throw new Error(`Agent Tool ${name} requires adapter ${definition.adapter}`);
|
|
244
|
+
}
|
|
245
|
+
return await definition.execute(parsed.data, createToolContext<TConfig, string | undefined>(fake, options));
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
function registeredTool<TInput, TResult, TConfig>(
|
|
249
|
+
fake: FakePlugin<TConfig>, localName: string,
|
|
250
|
+
): AgentToolDefinition<TInput, TResult, TConfig, string | undefined> {
|
|
251
|
+
const found = fake.features.find(feature => feature.kind === 'tool' && feature.localName === localName);
|
|
252
|
+
if (!found) {
|
|
253
|
+
const known = fake.features.filter(feature => feature.kind === 'tool').map(feature => feature.localName);
|
|
254
|
+
throw new Error(`No tool "${localName}" was registered through addTool()${known.length ? `; registered: ${known.join(', ')}` : ''}`);
|
|
255
|
+
}
|
|
256
|
+
return found.definition as AgentToolDefinition<TInput, TResult, TConfig, string | undefined>;
|
|
257
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { realpath } from 'node:fs/promises';
|
|
2
2
|
import { resolve } from 'node:path';
|
|
3
3
|
import { defineAdapter, type AdapterDefinition, type AdapterSegmentPolicy,
|
|
4
|
-
type EndpointIdentity, type EndpointEventSink, type EndpointIncomingMessage, type EndpointSendRequest } from '
|
|
4
|
+
type EndpointIdentity, type EndpointEventSink, type EndpointIncomingMessage, type EndpointSendRequest } from 'zhin.js/adapter';
|
|
5
5
|
import { ImRuntime, type ConversationAddress, type MessageDispatchResult,
|
|
6
|
-
type SendContent } from '
|
|
7
|
-
import { type ConversationRef, type DeliveryReceipt } from '
|
|
8
|
-
import { rootPluginId, type ConfigPatch, type PluginId, type RuntimeConfigDocument } from '
|
|
6
|
+
type RuntimeMessageDiagnosticsReader, type SendContent } from 'zhin.js/core/runtime';
|
|
7
|
+
import { type ConversationRef, type DeliveryReceipt } from 'zhin.js';
|
|
8
|
+
import { rootPluginId, type ConfigDocumentPort, type ConfigPatch, type PluginId, type RuntimeConfigDocument } from 'zhin.js/plugin-runtime';
|
|
9
9
|
import { NativeDevelopmentModuleRuntime, NodePackageResolver, RootRuntime,
|
|
10
10
|
type ModuleRuntime, type RootResourceInstaller } from '@zhin.js/runtime';
|
|
11
11
|
import { captureDeliveryValue } from './delivery-capture.js';
|
|
@@ -13,16 +13,21 @@ import { withTestEndpoints } from './test-module-runtime.js';
|
|
|
13
13
|
|
|
14
14
|
export { FakeClock, FakeScheduleRootHost, parseCron, type FakeScheduledJob } from './fake-clock.js';
|
|
15
15
|
export { FakeDatabaseRootHost, FakeOutboundRootHost, type FakeOutboundCall } from './fake-hosts.js';
|
|
16
|
-
export { FakePlugin, createFakePlugin, runPluginSetup, fakeResource,
|
|
17
|
-
type FakePluginOptions, type FakeResource, type FakeRegisteredFeature } from './fake-plugin.js';
|
|
16
|
+
export { FakePlugin, createFakePlugin, runPluginSetup, resolvePluginConfig, PluginConfigValidationError, fakeResource,
|
|
17
|
+
type FakePluginOptions, type RunPluginSetupOptions, type FakeResource, type FakeRegisteredFeature } from './fake-plugin.js';
|
|
18
18
|
export { fakeOf } from './partial.js';
|
|
19
19
|
export { createFakeMessage, createCommandContext, runCommand, runMiddleware, runHandler,
|
|
20
|
-
|
|
20
|
+
createToolContext, runTool, toolOriginFromMessage,
|
|
21
|
+
type FakeMessage, type RunToolOptions, type FakeMessageInit, type RunCommandOptions, type RunMiddlewareResult } from './fake-runners.js';
|
|
21
22
|
|
|
22
23
|
export interface PluginTestKitOptions {
|
|
23
24
|
/** A real, disposable test app with its own package.json, plugin entry, dependencies and mounts. */
|
|
24
25
|
readonly projectRoot: string;
|
|
25
|
-
|
|
26
|
+
/**
|
|
27
|
+
* A v2 document, or a file-backed document such as `createConfigDocument(path)` from
|
|
28
|
+
* `@zhin.js/config-file` when the test must share the same file authority as `zhin start`.
|
|
29
|
+
*/
|
|
30
|
+
readonly config?: RuntimeConfigDocument | ConfigDocumentPort;
|
|
26
31
|
/** Adapter names reserved for synthetic transports, default: ['test']. */
|
|
27
32
|
readonly endpoints?: readonly string[];
|
|
28
33
|
/** Default endpoint renders HTML and buttons as text; override to verify negotiated capabilities. */
|
|
@@ -125,6 +130,10 @@ export class PluginTestKit {
|
|
|
125
130
|
|
|
126
131
|
/** The same PermissionHost consumed by real command admission. */
|
|
127
132
|
get permissions(): ImRuntime['permissionHost'] { return this.#im.permissionHost; }
|
|
133
|
+
/** The same bounded, body-free reader the Console serves at `GET /api/messages/diagnostics`. */
|
|
134
|
+
get messageDiagnostics(): RuntimeMessageDiagnosticsReader { return this.#im.messageDiagnostics; }
|
|
135
|
+
/** The committed-snapshot authority Console routes read (tasks, permissions); read-only use in tests. */
|
|
136
|
+
get snapshots(): RootRuntime['snapshots'] { return this.#root.snapshots; }
|
|
128
137
|
get generation(): number { return this.#root.snapshot.generation; }
|
|
129
138
|
get deliveries(): readonly TestDelivery[] { return Object.freeze(this.#attempts.map(item => captureDeliveryValue(item))); }
|
|
130
139
|
clearDeliveries(): void { this.#attempts.splice(0); }
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { resolve } from 'node:path';
|
|
2
|
-
import { definePlugin, type PluginDefinition } from '
|
|
3
|
-
import type { AdapterDefinition } from '
|
|
2
|
+
import { definePlugin, type PluginDefinition } from 'zhin.js/plugin-runtime';
|
|
3
|
+
import type { AdapterDefinition } from 'zhin.js/adapter';
|
|
4
4
|
import type { ModuleRuntime } from '@zhin.js/runtime';
|
|
5
5
|
|
|
6
6
|
/** Only the test application's setup is decorated; discovery and module caching stay native. */
|