@loopingai/core 0.1.1 → 0.2.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 +131 -15
- package/dist/a2a/card.d.ts +35 -0
- package/dist/a2a/card.d.ts.map +1 -1
- package/dist/a2a/card.js +41 -3
- package/dist/a2a/card.js.map +1 -1
- package/dist/a2a/context.d.ts +9 -3
- package/dist/a2a/context.d.ts.map +1 -1
- package/dist/a2a/context.js +11 -4
- package/dist/a2a/context.js.map +1 -1
- package/dist/a2a/index.d.ts +1 -1
- package/dist/a2a/index.d.ts.map +1 -1
- package/dist/a2a/index.js +1 -1
- package/dist/a2a/index.js.map +1 -1
- package/dist/a2a/notify.d.ts +11 -2
- package/dist/a2a/notify.d.ts.map +1 -1
- package/dist/a2a/notify.js +12 -3
- package/dist/a2a/notify.js.map +1 -1
- package/dist/a2a/verify.d.ts +23 -2
- package/dist/a2a/verify.d.ts.map +1 -1
- package/dist/a2a/verify.js +26 -3
- package/dist/a2a/verify.js.map +1 -1
- package/dist/agent/history.d.ts +15 -0
- package/dist/agent/history.d.ts.map +1 -1
- package/dist/agent/history.js +17 -0
- package/dist/agent/history.js.map +1 -1
- package/dist/agent/index.d.ts +1 -1
- package/dist/agent/index.d.ts.map +1 -1
- package/dist/agent/index.js +1 -1
- package/dist/agent/index.js.map +1 -1
- package/dist/contract/index.d.ts +1 -1
- package/dist/contract/index.d.ts.map +1 -1
- package/dist/contract/index.js.map +1 -1
- package/dist/contract/plugin.d.ts +86 -3
- package/dist/contract/plugin.d.ts.map +1 -1
- package/dist/contract/plugin.js.map +1 -1
- package/dist/db/db.d.ts +32 -14
- package/dist/db/db.d.ts.map +1 -1
- package/dist/db/db.js.map +1 -1
- package/dist/env.d.ts +10 -2
- package/dist/env.d.ts.map +1 -1
- package/dist/env.js +10 -2
- package/dist/env.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/runtime/index.d.ts +28 -3
- package/dist/runtime/index.d.ts.map +1 -1
- package/dist/runtime/index.js +39 -3
- package/dist/runtime/index.js.map +1 -1
- package/dist/subagent/workspace.d.ts +21 -0
- package/dist/subagent/workspace.d.ts.map +1 -1
- package/dist/subagent/workspace.js +80 -5
- package/dist/subagent/workspace.js.map +1 -1
- package/dist/testing/auth.d.ts +23 -0
- package/dist/testing/auth.d.ts.map +1 -1
- package/dist/testing/auth.js +11 -3
- package/dist/testing/auth.js.map +1 -1
- package/dist/testing/fixtures.d.ts +21 -0
- package/dist/testing/fixtures.d.ts.map +1 -1
- package/dist/testing/fixtures.js +21 -0
- package/dist/testing/fixtures.js.map +1 -1
- package/dist/testing/node.d.ts +23 -0
- package/dist/testing/node.d.ts.map +1 -1
- package/dist/testing/node.js +23 -0
- package/dist/testing/node.js.map +1 -1
- package/dist/testing/vcr-spec.d.ts +4 -4
- package/dist/testing/vcr-spec.d.ts.map +1 -1
- package/dist/testing/vcr-spec.js +32 -11
- package/dist/testing/vcr-spec.js.map +1 -1
- package/dist/worker/index.d.ts +142 -3
- package/dist/worker/index.d.ts.map +1 -1
- package/dist/worker/index.js +152 -29
- package/dist/worker/index.js.map +1 -1
- package/package.json +12 -4
package/dist/runtime/index.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { resolveConfig } from "../config.js";
|
|
2
2
|
import { PLUGIN_CONTRACT_VERSION } from "../contract/plugin.js";
|
|
3
|
+
import { memoryWorkspaceBacking } from "../subagent/workspace.js";
|
|
3
4
|
import { makeSubtaskTypes } from "../subtasks/subtask-types.js";
|
|
4
5
|
import { collectToolFamilies } from "./tool-families.js";
|
|
5
6
|
export { buildRecipeTools, collectToolFamilies } from "./tool-families.js";
|
|
@@ -43,6 +44,14 @@ export function createAgentRuntime(options) {
|
|
|
43
44
|
const displacementListeners = plugins.flatMap((p) => p.onMessagesDisplaced
|
|
44
45
|
? [{ key: p.key, notify: p.onMessagesDisplaced.bind(p) }]
|
|
45
46
|
: []);
|
|
47
|
+
const turnGates = plugins.flatMap((p) => p.shouldHandleTurn ? [{ key: p.key, gate: p.shouldHandleTurn.bind(p) }] : []);
|
|
48
|
+
// At most one backend: two would mean two answers to "where did that file go".
|
|
49
|
+
const backings = plugins.flatMap((p) => p.workspaceBacking ? [{ key: p.key, make: p.workspaceBacking.bind(p) }] : []);
|
|
50
|
+
if (backings.length > 1) {
|
|
51
|
+
throw new RuntimeSetupError(`plugins ${backings.map((b) => `"${b.key}"`).join(" and ")} both declare a ` +
|
|
52
|
+
"workspaceBacking — an execution has one workspace, so only one plugin may back it");
|
|
53
|
+
}
|
|
54
|
+
const workspaceBacking = backings[0]?.make ?? memoryWorkspaceBacking;
|
|
46
55
|
const secrets = [
|
|
47
56
|
...new Set(plugins.flatMap((p) => [...(p.requires?.secrets ?? [])]))
|
|
48
57
|
];
|
|
@@ -50,13 +59,14 @@ export function createAgentRuntime(options) {
|
|
|
50
59
|
...new Set(plugins.flatMap((p) => [...(p.requires?.bindings ?? [])]))
|
|
51
60
|
];
|
|
52
61
|
if (options.env) {
|
|
62
|
+
const env = options.env;
|
|
53
63
|
const missing = [];
|
|
54
64
|
for (const plugin of plugins) {
|
|
55
65
|
for (const name of [
|
|
56
66
|
...(plugin.requires?.secrets ?? []),
|
|
57
67
|
...(plugin.requires?.bindings ?? [])
|
|
58
68
|
]) {
|
|
59
|
-
const value =
|
|
69
|
+
const value = env[name];
|
|
60
70
|
if (value === undefined || value === null || value === "") {
|
|
61
71
|
missing.push(`${name} (required by "${plugin.key}")`);
|
|
62
72
|
}
|
|
@@ -87,12 +97,16 @@ export function createAgentRuntime(options) {
|
|
|
87
97
|
policy,
|
|
88
98
|
stores,
|
|
89
99
|
requirements: { secrets, bindings },
|
|
100
|
+
workspaceBacking,
|
|
90
101
|
pluginForType,
|
|
91
|
-
mainAgentTools() {
|
|
102
|
+
async mainAgentTools(ctx) {
|
|
92
103
|
const tools = {};
|
|
104
|
+
// Sequential rather than fanned out: this is a handful of plugins reading
|
|
105
|
+
// one session, and merging in declaration order is what makes a name
|
|
106
|
+
// collision resolve the same way on every call.
|
|
93
107
|
for (const plugin of plugins) {
|
|
94
108
|
if (plugin.mainAgentTools)
|
|
95
|
-
Object.assign(tools, plugin.mainAgentTools());
|
|
109
|
+
Object.assign(tools, await plugin.mainAgentTools(ctx));
|
|
96
110
|
}
|
|
97
111
|
return tools;
|
|
98
112
|
},
|
|
@@ -104,6 +118,28 @@ export function createAgentRuntime(options) {
|
|
|
104
118
|
}
|
|
105
119
|
return blocks.join("\n\n");
|
|
106
120
|
},
|
|
121
|
+
async shouldHandleTurn(ctx) {
|
|
122
|
+
if (turnGates.length === 0)
|
|
123
|
+
return true;
|
|
124
|
+
// Same `allSettled` + `async`-wrapped-callback discipline as
|
|
125
|
+
// `onMessagesDisplaced` below, and for the same two reasons: every gate is
|
|
126
|
+
// consulted even when one throws, and a gate that throws *synchronously*
|
|
127
|
+
// (reading a binding before its first await) is caught rather than
|
|
128
|
+
// escaping past the aggregation.
|
|
129
|
+
//
|
|
130
|
+
// A rejection resolves to `true`. That is not leniency — it is the only
|
|
131
|
+
// safe default here. A wrong reply is noise the user sees and ignores; a
|
|
132
|
+
// wrong silence is invisible to the person who needed an answer, so a
|
|
133
|
+
// broken gate must degrade to "run the turn" and never to a mute agent.
|
|
134
|
+
const results = await Promise.allSettled(turnGates.map(async (g) => g.gate(ctx)));
|
|
135
|
+
return results.every((result, i) => {
|
|
136
|
+
if (result.status === "rejected") {
|
|
137
|
+
console.warn(`[runtime] plugin "${turnGates[i].key}" turn gate failed, handling the turn`, result.reason);
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
140
|
+
return result.value;
|
|
141
|
+
});
|
|
142
|
+
},
|
|
107
143
|
async onMessagesDisplaced(messages) {
|
|
108
144
|
// allSettled, not all: `all` rejects at the first listener to throw and
|
|
109
145
|
// stops awaiting the rest, so every other plugin's write is still in
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/runtime/index.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,aAAa,EAGd,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,uBAAuB,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/runtime/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -48,6 +48,27 @@ export interface WorkspaceBacking {
|
|
|
48
48
|
fileCount: number;
|
|
49
49
|
}>;
|
|
50
50
|
}
|
|
51
|
+
/**
|
|
52
|
+
* An in-memory {@link WorkspaceBacking} — the fallback when no installed plugin
|
|
53
|
+
* declares one.
|
|
54
|
+
*
|
|
55
|
+
* Deliberately **not durable**, and that is the honest behaviour rather than a
|
|
56
|
+
* shortcut: a durable stand-in would have to invent a storage layout that a real
|
|
57
|
+
* backend would then have to migrate away from. An agent that delegates file
|
|
58
|
+
* work installs a backend; one that does not never writes a file, and pays
|
|
59
|
+
* nothing for the option. What this buys is that `createAgentRuntime` composes
|
|
60
|
+
* without a workspace plugin at all, so `SubagentRuntime.workspaceBacking` can
|
|
61
|
+
* stay required and a host never writes a null check.
|
|
62
|
+
*
|
|
63
|
+
* Scoped per call, so each execution gets its own map, exactly as a facet's own
|
|
64
|
+
* SQLite would give it its own tables. Contents are lost on isolate eviction —
|
|
65
|
+
* the resumable runner treats a lost workspace as a resumable state everywhere
|
|
66
|
+
* it matters.
|
|
67
|
+
*
|
|
68
|
+
* Signature matches {@link AgentPlugin.workspaceBacking}; both arguments are
|
|
69
|
+
* ignored.
|
|
70
|
+
*/
|
|
71
|
+
export declare function memoryWorkspaceBacking(_sql?: SqlStorage, _name?: () => string | undefined): WorkspaceBacking;
|
|
51
72
|
/** Per-file byte ceiling — safely under the 2 MB Durable Object SQLite row limit. */
|
|
52
73
|
export declare const WORKSPACE_MAX_FILE_BYTES: number;
|
|
53
74
|
/** Max number of files in one workspace — a cheap guard against runaway writes. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../../src/subagent/workspace.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,WAAW,eAAe;IAC9B,wDAAwD;IACxD,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC3C,+EAA+E;IAC/E,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpD,sDAAsD;IACtD,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACvC,yDAAyD;IACzD,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACvC,8EAA8E;IAC9E,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC;IAC9C,iFAAiF;IACjF,QAAQ,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAC7C,yDAAyD;IACzD,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACxD;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAAC;IACvC,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC/C,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxD,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACvC,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3C,OAAO,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,cAAc,EAAE,CAAC,CAAC;IAC1D,gBAAgB,IAAI,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACpD;AAED,qFAAqF;AACrF,eAAO,MAAM,wBAAwB,QAAa,CAAC;AACnD,mFAAmF;AACnF,eAAO,MAAM,mBAAmB,MAAM,CAAC;AAEvC,qBAAa,mBAAoB,SAAQ,KAAK;gBAChC,OAAO,EAAE,MAAM;CAI5B;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,gBAAgB,GAAG,eAAe,
|
|
1
|
+
{"version":3,"file":"workspace.d.ts","sourceRoot":"","sources":["../../src/subagent/workspace.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,WAAW,eAAe;IAC9B,wDAAwD;IACxD,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC3C,+EAA+E;IAC/E,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACpD,sDAAsD;IACtD,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACvC,yDAAyD;IACzD,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACvC,8EAA8E;IAC9E,IAAI,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAAC;IAC9C,iFAAiF;IACjF,QAAQ,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAC7C,yDAAyD;IACzD,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACxD;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,SAAS,CAAC;IACvC,IAAI,EAAE,MAAM,CAAC;CACd;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC/C,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxD,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACvC,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3C,OAAO,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,SAAS,cAAc,EAAE,CAAC,CAAC;IAC1D,gBAAgB,IAAI,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CACpD;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,sBAAsB,CACpC,IAAI,CAAC,EAAE,UAAU,EACjB,KAAK,CAAC,EAAE,MAAM,MAAM,GAAG,SAAS,GAC/B,gBAAgB,CA2ClB;AAOD,qFAAqF;AACrF,eAAO,MAAM,wBAAwB,QAAa,CAAC;AACnD,mFAAmF;AACnF,eAAO,MAAM,mBAAmB,MAAM,CAAC;AAEvC,qBAAa,mBAAoB,SAAQ,KAAK;gBAChC,OAAO,EAAE,MAAM;CAI5B;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,EAAE,EAAE,gBAAgB,GAAG,eAAe,CAsDzE"}
|
|
@@ -1,3 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* An in-memory {@link WorkspaceBacking} — the fallback when no installed plugin
|
|
3
|
+
* declares one.
|
|
4
|
+
*
|
|
5
|
+
* Deliberately **not durable**, and that is the honest behaviour rather than a
|
|
6
|
+
* shortcut: a durable stand-in would have to invent a storage layout that a real
|
|
7
|
+
* backend would then have to migrate away from. An agent that delegates file
|
|
8
|
+
* work installs a backend; one that does not never writes a file, and pays
|
|
9
|
+
* nothing for the option. What this buys is that `createAgentRuntime` composes
|
|
10
|
+
* without a workspace plugin at all, so `SubagentRuntime.workspaceBacking` can
|
|
11
|
+
* stay required and a host never writes a null check.
|
|
12
|
+
*
|
|
13
|
+
* Scoped per call, so each execution gets its own map, exactly as a facet's own
|
|
14
|
+
* SQLite would give it its own tables. Contents are lost on isolate eviction —
|
|
15
|
+
* the resumable runner treats a lost workspace as a resumable state everywhere
|
|
16
|
+
* it matters.
|
|
17
|
+
*
|
|
18
|
+
* Signature matches {@link AgentPlugin.workspaceBacking}; both arguments are
|
|
19
|
+
* ignored.
|
|
20
|
+
*/
|
|
21
|
+
export function memoryWorkspaceBacking(_sql, _name) {
|
|
22
|
+
const files = new Map();
|
|
23
|
+
/** Immediate children of `dir`, as `readDir` reports them. */
|
|
24
|
+
const entriesUnder = (dir) => {
|
|
25
|
+
const prefix = dir === "" ? "" : `${dir}/`;
|
|
26
|
+
const seen = new Map();
|
|
27
|
+
for (const [path, content] of files) {
|
|
28
|
+
if (!path.startsWith(prefix))
|
|
29
|
+
continue;
|
|
30
|
+
const rest = path.slice(prefix.length);
|
|
31
|
+
if (rest === "")
|
|
32
|
+
continue;
|
|
33
|
+
const slash = rest.indexOf("/");
|
|
34
|
+
if (slash === -1) {
|
|
35
|
+
seen.set(path, {
|
|
36
|
+
path,
|
|
37
|
+
type: "file",
|
|
38
|
+
size: new TextEncoder().encode(content).length
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
// A directory exists only because something under it does, so report it
|
|
43
|
+
// once and say nothing about its size.
|
|
44
|
+
const child = `${prefix}${rest.slice(0, slash)}`;
|
|
45
|
+
seen.set(child, { path: child, type: "directory", size: 0 });
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return [...seen.values()];
|
|
49
|
+
};
|
|
50
|
+
return {
|
|
51
|
+
readFile: async (path) => files.get(normalize(path)) ?? null,
|
|
52
|
+
writeFile: async (path, content) => {
|
|
53
|
+
files.set(normalize(path), content);
|
|
54
|
+
},
|
|
55
|
+
// Directories are implied by their contents, so a path with anything under
|
|
56
|
+
// it exists even though nothing ever created it.
|
|
57
|
+
exists: async (path) => {
|
|
58
|
+
const key = normalize(path);
|
|
59
|
+
return files.has(key) || entriesUnder(key).length > 0;
|
|
60
|
+
},
|
|
61
|
+
deleteFile: async (path) => files.delete(normalize(path)),
|
|
62
|
+
readDir: async (dir) => entriesUnder(normalize(dir ?? "")),
|
|
63
|
+
getWorkspaceInfo: async () => ({ fileCount: files.size })
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
/** Strip the leading/trailing slashes that would otherwise key two paths apart. */
|
|
67
|
+
function normalize(path) {
|
|
68
|
+
return path.replace(/^\/+|\/+$/g, "");
|
|
69
|
+
}
|
|
1
70
|
/** Per-file byte ceiling — safely under the 2 MB Durable Object SQLite row limit. */
|
|
2
71
|
export const WORKSPACE_MAX_FILE_BYTES = 512 * 1024;
|
|
3
72
|
/** Max number of files in one workspace — a cheap guard against runaway writes. */
|
|
@@ -23,11 +92,17 @@ export function makeWorkspaceHandle(ws) {
|
|
|
23
92
|
if (bytes > WORKSPACE_MAX_FILE_BYTES) {
|
|
24
93
|
throw new WorkspaceLimitError(`file "${path}" is ${bytes} bytes, over the ${WORKSPACE_MAX_FILE_BYTES}-byte limit`);
|
|
25
94
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
95
|
+
// The cap bounds how many files exist, so it may only refuse a write that
|
|
96
|
+
// *creates* one. `exists` is the wrong question: it is true for a
|
|
97
|
+
// directory too (filesystem semantics, which every real backing has), so
|
|
98
|
+
// at the cap a write to `notes` — with `notes/a.txt` present — read as an
|
|
99
|
+
// overwrite and added a 201st file. `readFile` returning null is the only
|
|
100
|
+
// honest test for "there is no file here", and it runs solely when the
|
|
101
|
+
// workspace is already full, so the ordinary write still costs one call.
|
|
102
|
+
const { fileCount } = await ws.getWorkspaceInfo();
|
|
103
|
+
if (fileCount >= WORKSPACE_MAX_FILES &&
|
|
104
|
+
(await ws.readFile(path)) === null) {
|
|
105
|
+
throw new WorkspaceLimitError(`workspace already holds ${fileCount} files (max ${WORKSPACE_MAX_FILES})`);
|
|
31
106
|
}
|
|
32
107
|
await ws.writeFile(path, content);
|
|
33
108
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspace.js","sourceRoot":"","sources":["../../src/subagent/workspace.ts"],"names":[],"mappings":"AAmDA,qFAAqF;AACrF,MAAM,CAAC,MAAM,wBAAwB,GAAG,GAAG,GAAG,IAAI,CAAC;AACnD,mFAAmF;AACnF,MAAM,CAAC,MAAM,mBAAmB,GAAG,GAAG,CAAC;AAEvC,MAAM,OAAO,mBAAoB,SAAQ,KAAK;IAC5C,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;IACpC,CAAC;CACF;AAED;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CAAC,EAAoB;IACtD,MAAM,UAAU,GAAG,CAAC,CAAS,EAAU,EAAE,CAAC,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;IAE7E,OAAO;QACL,IAAI,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,EAAE,CAAC,QAAQ,CAAC,IAAI,CAAC;QAEjC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE,OAAO;YACvB,MAAM,KAAK,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;YAClC,IAAI,KAAK,GAAG,wBAAwB,EAAE,CAAC;gBACrC,MAAM,IAAI,mBAAmB,CAC3B,SAAS,IAAI,QAAQ,KAAK,oBAAoB,wBAAwB,aAAa,CACpF,CAAC;YACJ,CAAC;YACD,
|
|
1
|
+
{"version":3,"file":"workspace.js","sourceRoot":"","sources":["../../src/subagent/workspace.ts"],"names":[],"mappings":"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"}
|
package/dist/testing/auth.d.ts
CHANGED
|
@@ -1,4 +1,13 @@
|
|
|
1
1
|
export interface GatewayTokenOptions {
|
|
2
|
+
/**
|
|
3
|
+
* Who the token is for. Defaults to an agent at the default RPC path
|
|
4
|
+
* (`${AGENT_ORIGIN}${A2A_RPC_PATH}`), which is what a gateway mints: the
|
|
5
|
+
* agent's **endpoint**, not its origin.
|
|
6
|
+
*
|
|
7
|
+
* Pass this explicitly when a spec mounts an agent somewhere else — an agent
|
|
8
|
+
* at `/proactive/a2a` expects that string and refuses this default, which is
|
|
9
|
+
* the whole point of scoping the audience to the endpoint.
|
|
10
|
+
*/
|
|
2
11
|
audience?: string;
|
|
3
12
|
issuer?: string;
|
|
4
13
|
/** Relative string ("5m"), absolute epoch seconds, or Date. Past values expire the token. */
|
|
@@ -6,7 +15,21 @@ export interface GatewayTokenOptions {
|
|
|
6
15
|
identity?: Record<string, unknown>;
|
|
7
16
|
/** Claim the identity is carried in. Defaults to core's `IDENTITY_CLAIM`. */
|
|
8
17
|
identityClaim?: string;
|
|
18
|
+
/**
|
|
19
|
+
* Which agent on the target origin this token authorizes, defaulting to
|
|
20
|
+
* `"main"`.
|
|
21
|
+
*
|
|
22
|
+
* The tenants of one deployment share an endpoint and therefore an audience,
|
|
23
|
+
* so this claim is the only thing distinguishing them. Set it to a *different*
|
|
24
|
+
* tenant than the request addresses to exercise the replay case; set it to
|
|
25
|
+
* `""` to mint a token carrying no tenant at all, which is rejected.
|
|
26
|
+
*/
|
|
27
|
+
tenant?: string;
|
|
28
|
+
/** Claim the tenant is carried in. Defaults to core's `TENANT_CLAIM`. */
|
|
29
|
+
tenantClaim?: string;
|
|
9
30
|
}
|
|
31
|
+
/** The tenant `makeGatewayToken` authorizes unless a spec says otherwise. */
|
|
32
|
+
export declare const TEST_TENANT = "main";
|
|
10
33
|
/** Sign a short-lived EdDSA gateway JWT using the test gateway key. */
|
|
11
34
|
export declare function makeGatewayToken(options?: GatewayTokenOptions): Promise<string>;
|
|
12
35
|
//# sourceMappingURL=auth.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/testing/auth.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"auth.d.ts","sourceRoot":"","sources":["../../src/testing/auth.ts"],"names":[],"mappings":"AASA,MAAM,WAAW,mBAAmB;IAClC;;;;;;;;OAQG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,6FAA6F;IAC7F,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IACnC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACnC,6EAA6E;IAC7E,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB;;;;;;;;OAQG;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,yEAAyE;IACzE,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,6EAA6E;AAC7E,eAAO,MAAM,WAAW,SAAS,CAAC;AAElC,uEAAuE;AACvE,wBAAsB,gBAAgB,CACpC,OAAO,GAAE,mBAAwB,GAChC,OAAO,CAAC,MAAM,CAAC,CAwBjB"}
|
package/dist/testing/auth.js
CHANGED
|
@@ -1,16 +1,24 @@
|
|
|
1
1
|
import { importJWK, SignJWT } from "jose";
|
|
2
|
-
import { IDENTITY_CLAIM } from "../a2a/verify.js";
|
|
2
|
+
import { IDENTITY_CLAIM, TENANT_CLAIM } from "../a2a/verify.js";
|
|
3
|
+
import { A2A_RPC_PATH } from "../a2a/card.js";
|
|
3
4
|
import { TEST_GATEWAY_PRIVATE_JWK, GATEWAY_ORIGIN, AGENT_ORIGIN } from "./fixtures.js";
|
|
5
|
+
/** The tenant `makeGatewayToken` authorizes unless a spec says otherwise. */
|
|
6
|
+
export const TEST_TENANT = "main";
|
|
4
7
|
/** Sign a short-lived EdDSA gateway JWT using the test gateway key. */
|
|
5
8
|
export async function makeGatewayToken(options = {}) {
|
|
6
9
|
const privateKey = await importJWK(TEST_GATEWAY_PRIVATE_JWK, "EdDSA");
|
|
10
|
+
const tenant = options.tenant ?? TEST_TENANT;
|
|
7
11
|
return new SignJWT({
|
|
8
12
|
[options.identityClaim ?? IDENTITY_CLAIM]: options.identity ?? {
|
|
9
13
|
key: "custom:1:test-agent",
|
|
10
14
|
name: "Test Agent",
|
|
11
15
|
kind: "custom",
|
|
12
16
|
workspaceId: 1
|
|
13
|
-
}
|
|
17
|
+
},
|
|
18
|
+
// An empty tenant omits the claim entirely rather than signing `""` — that
|
|
19
|
+
// is the "gateway too old to scope its tokens" case, and it must be
|
|
20
|
+
// rejected rather than treated as a wildcard.
|
|
21
|
+
...(tenant ? { [options.tenantClaim ?? TENANT_CLAIM]: tenant } : {})
|
|
14
22
|
})
|
|
15
23
|
.setProtectedHeader({
|
|
16
24
|
alg: "EdDSA",
|
|
@@ -18,7 +26,7 @@ export async function makeGatewayToken(options = {}) {
|
|
|
18
26
|
jku: `${GATEWAY_ORIGIN}/.well-known/jwks.json`
|
|
19
27
|
})
|
|
20
28
|
.setIssuer(options.issuer ?? GATEWAY_ORIGIN)
|
|
21
|
-
.setAudience(options.audience ?? AGENT_ORIGIN)
|
|
29
|
+
.setAudience(options.audience ?? `${AGENT_ORIGIN}${A2A_RPC_PATH}`)
|
|
22
30
|
.setExpirationTime(options.expiresIn ?? "5m")
|
|
23
31
|
.sign(privateKey);
|
|
24
32
|
}
|
package/dist/testing/auth.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/testing/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/testing/auth.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,MAAM,CAAC;AAC1C,OAAO,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAChE,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EACL,wBAAwB,EACxB,cAAc,EACd,YAAY,EACb,MAAM,eAAe,CAAC;AAiCvB,6EAA6E;AAC7E,MAAM,CAAC,MAAM,WAAW,GAAG,MAAM,CAAC;AAElC,uEAAuE;AACvE,MAAM,CAAC,KAAK,UAAU,gBAAgB,CACpC,UAA+B,EAAE;IAEjC,MAAM,UAAU,GAAG,MAAM,SAAS,CAAC,wBAAwB,EAAE,OAAO,CAAC,CAAC;IACtE,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,WAAW,CAAC;IAC7C,OAAO,IAAI,OAAO,CAAC;QACjB,CAAC,OAAO,CAAC,aAAa,IAAI,cAAc,CAAC,EAAE,OAAO,CAAC,QAAQ,IAAI;YAC7D,GAAG,EAAE,qBAAqB;YAC1B,IAAI,EAAE,YAAY;YAClB,IAAI,EAAE,QAAQ;YACd,WAAW,EAAE,CAAC;SACf;QACD,2EAA2E;QAC3E,oEAAoE;QACpE,8CAA8C;QAC9C,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,OAAO,CAAC,WAAW,IAAI,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACrE,CAAC;SACC,kBAAkB,CAAC;QAClB,GAAG,EAAE,OAAO;QACZ,GAAG,EAAE,wBAAwB,CAAC,GAAG;QACjC,GAAG,EAAE,GAAG,cAAc,wBAAwB;KAC/C,CAAC;SACD,SAAS,CAAC,OAAO,CAAC,MAAM,IAAI,cAAc,CAAC;SAC3C,WAAW,CAAC,OAAO,CAAC,QAAQ,IAAI,GAAG,YAAY,GAAG,YAAY,EAAE,CAAC;SACjE,iBAAiB,CAAC,OAAO,CAAC,SAAS,IAAI,IAAI,CAAC;SAC5C,IAAI,CAAC,UAAU,CAAC,CAAC;AACtB,CAAC"}
|
|
@@ -1,3 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@loopingai/core/testing/fixtures` — the **realm-neutral** slice of the
|
|
3
|
+
* harness: fixed keys, origins, and task/message builders.
|
|
4
|
+
*
|
|
5
|
+
* Its own subpath because it is the one part a consumer's `vitest.config.ts`
|
|
6
|
+
* needs, and that file runs in **Node**. The `/testing` barrel pulls in
|
|
7
|
+
* `cloudflare:test` (DO helpers) and `vitest` (the VCR spec hooks), so importing
|
|
8
|
+
* it from a config fails at load with `ERR_UNSUPPORTED_ESM_URL_SCHEME` before a
|
|
9
|
+
* single test runs. Nothing here imports either, so it is safe from a config, a
|
|
10
|
+
* spec, or a plain Node script.
|
|
11
|
+
*
|
|
12
|
+
* Seeding the required secrets from these values is the intended use:
|
|
13
|
+
*
|
|
14
|
+
* ```ts
|
|
15
|
+
* // vitest.config.ts
|
|
16
|
+
* import { GATEWAY_ORIGIN, TEST_AGENT_PRIVATE_JWK } from "@loopingai/core/testing/fixtures";
|
|
17
|
+
*
|
|
18
|
+
* process.env.A2A_SIGNING_KEY ??= JSON.stringify(TEST_AGENT_PRIVATE_JWK);
|
|
19
|
+
* process.env.GATEWAY_ORIGINS ??= JSON.stringify([GATEWAY_ORIGIN]);
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
1
22
|
import { type JWK } from "jose";
|
|
2
23
|
import { type Message, type Task, type TaskState } from "@a2a-js/sdk";
|
|
3
24
|
/** The gateway origin used in all tests. Must match vitest.config.ts and the MockAgent setup. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fixtures.d.ts","sourceRoot":"","sources":["../../src/testing/fixtures.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,GAAG,EAAE,MAAM,MAAM,CAAC;AAChC,OAAO,EAAQ,KAAK,OAAO,EAAE,KAAK,IAAI,EAAE,KAAK,SAAS,EAAE,MAAM,aAAa,CAAC;AAE5E,iGAAiG;AACjG,eAAO,MAAM,cAAc,yBAAyB,CAAC;AAErD,6EAA6E;AAC7E,eAAO,MAAM,YAAY,qBAAqB,CAAC;AAE/C,kEAAkE;AAClE,eAAO,MAAM,sBAAsB,EAAE,GAAG,GAAG;IAAE,GAAG,EAAE,MAAM,CAAA;CAMvD,CAAC;AAEF,mEAAmE;AACnE,eAAO,MAAM,wBAAwB,EAAE,GAAG,GAAG;IAAE,GAAG,EAAE,MAAM,CAAA;CAMzD,CAAC;AAEF,oFAAoF;AACpF,wBAAgB,iBAAiB,IAAI,MAAM,CAG1C;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CACxB,KAAK,EAAE,SAAS,EAChB,OAAO,CAAC,EAAE,OAAO,GAChB,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAE7B;AAED,gEAAgE;AAChE,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EACZ,SAAS,SAAK,EACd,MAAM,SAAK,GACV,OAAO,CAkBT;AAED,iDAAiD;AACjD,wBAAgB,QAAQ,CACtB,EAAE,EAAE,MAAM,EACV,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,SAAS,EAChB,OAAO,CAAC,EAAE,OAAO,GAChB,IAAI,CASN"}
|
|
1
|
+
{"version":3,"file":"fixtures.d.ts","sourceRoot":"","sources":["../../src/testing/fixtures.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,EAAE,KAAK,GAAG,EAAE,MAAM,MAAM,CAAC;AAChC,OAAO,EAAQ,KAAK,OAAO,EAAE,KAAK,IAAI,EAAE,KAAK,SAAS,EAAE,MAAM,aAAa,CAAC;AAE5E,iGAAiG;AACjG,eAAO,MAAM,cAAc,yBAAyB,CAAC;AAErD,6EAA6E;AAC7E,eAAO,MAAM,YAAY,qBAAqB,CAAC;AAE/C,kEAAkE;AAClE,eAAO,MAAM,sBAAsB,EAAE,GAAG,GAAG;IAAE,GAAG,EAAE,MAAM,CAAA;CAMvD,CAAC;AAEF,mEAAmE;AACnE,eAAO,MAAM,wBAAwB,EAAE,GAAG,GAAG;IAAE,GAAG,EAAE,MAAM,CAAA;CAMzD,CAAC;AAEF,oFAAoF;AACpF,wBAAgB,iBAAiB,IAAI,MAAM,CAG1C;AAED;;;;GAIG;AACH,wBAAgB,UAAU,CACxB,KAAK,EAAE,SAAS,EAChB,OAAO,CAAC,EAAE,OAAO,GAChB,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAE7B;AAED,gEAAgE;AAChE,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,MAAM,EACZ,SAAS,SAAK,EACd,MAAM,SAAK,GACV,OAAO,CAkBT;AAED,iDAAiD;AACjD,wBAAgB,QAAQ,CACtB,EAAE,EAAE,MAAM,EACV,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,SAAS,EAChB,OAAO,CAAC,EAAE,OAAO,GAChB,IAAI,CASN"}
|
package/dist/testing/fixtures.js
CHANGED
|
@@ -1,3 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `@loopingai/core/testing/fixtures` — the **realm-neutral** slice of the
|
|
3
|
+
* harness: fixed keys, origins, and task/message builders.
|
|
4
|
+
*
|
|
5
|
+
* Its own subpath because it is the one part a consumer's `vitest.config.ts`
|
|
6
|
+
* needs, and that file runs in **Node**. The `/testing` barrel pulls in
|
|
7
|
+
* `cloudflare:test` (DO helpers) and `vitest` (the VCR spec hooks), so importing
|
|
8
|
+
* it from a config fails at load with `ERR_UNSUPPORTED_ESM_URL_SCHEME` before a
|
|
9
|
+
* single test runs. Nothing here imports either, so it is safe from a config, a
|
|
10
|
+
* spec, or a plain Node script.
|
|
11
|
+
*
|
|
12
|
+
* Seeding the required secrets from these values is the intended use:
|
|
13
|
+
*
|
|
14
|
+
* ```ts
|
|
15
|
+
* // vitest.config.ts
|
|
16
|
+
* import { GATEWAY_ORIGIN, TEST_AGENT_PRIVATE_JWK } from "@loopingai/core/testing/fixtures";
|
|
17
|
+
*
|
|
18
|
+
* process.env.A2A_SIGNING_KEY ??= JSON.stringify(TEST_AGENT_PRIVATE_JWK);
|
|
19
|
+
* process.env.GATEWAY_ORIGINS ??= JSON.stringify([GATEWAY_ORIGIN]);
|
|
20
|
+
* ```
|
|
21
|
+
*/
|
|
1
22
|
import {} from "jose";
|
|
2
23
|
import { Role } from "@a2a-js/sdk";
|
|
3
24
|
/** The gateway origin used in all tests. Must match vitest.config.ts and the MockAgent setup. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fixtures.js","sourceRoot":"","sources":["../../src/testing/fixtures.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,MAAM,MAAM,CAAC;AAChC,OAAO,EAAE,IAAI,EAA2C,MAAM,aAAa,CAAC;AAE5E,iGAAiG;AACjG,MAAM,CAAC,MAAM,cAAc,GAAG,sBAAsB,CAAC;AAErD,6EAA6E;AAC7E,MAAM,CAAC,MAAM,YAAY,GAAG,kBAAkB,CAAC;AAE/C,kEAAkE;AAClE,MAAM,CAAC,MAAM,sBAAsB,GAA0B;IAC3D,GAAG,EAAE,SAAS;IACd,CAAC,EAAE,6CAA6C;IAChD,CAAC,EAAE,6CAA6C;IAChD,GAAG,EAAE,KAAK;IACV,GAAG,EAAE,kBAAkB;CACxB,CAAC;AAEF,mEAAmE;AACnE,MAAM,CAAC,MAAM,wBAAwB,GAA0B;IAC7D,GAAG,EAAE,SAAS;IACd,CAAC,EAAE,6CAA6C;IAChD,CAAC,EAAE,6CAA6C;IAChD,GAAG,EAAE,KAAK;IACV,GAAG,EAAE,eAAe;CACrB,CAAC;AAEF,oFAAoF;AACpF,MAAM,UAAU,iBAAiB;IAC/B,MAAM,EAAE,CAAC,EAAE,EAAE,EAAE,GAAG,GAAG,EAAE,GAAG,wBAAwB,CAAC;IACnD,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;AAC1E,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,UAAU,CACxB,KAAgB,EAChB,OAAiB;IAEjB,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC;AACjE,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,gBAAgB,CAC9B,SAAiB,EACjB,IAAY,EACZ,SAAS,GAAG,EAAE,EACd,MAAM,GAAG,EAAE;IAEX,OAAO;QACL,SAAS;QACT,SAAS;QACT,MAAM;QACN,IAAI,EAAE,IAAI,CAAC,UAAU;QACrB,KAAK,EAAE;YACL;gBACE,OAAO,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE;gBACvC,QAAQ,EAAE,SAAS;gBACnB,QAAQ,EAAE,EAAE;gBACZ,SAAS,EAAE,YAAY;aACxB;SACF;QACD,QAAQ,EAAE,SAAS;QACnB,UAAU,EAAE,EAAE;QACd,gBAAgB,EAAE,EAAE;KACrB,CAAC;AACJ,CAAC;AAED,iDAAiD;AACjD,MAAM,UAAU,QAAQ,CACtB,EAAU,EACV,SAAiB,EACjB,KAAgB,EAChB,OAAiB;IAEjB,OAAO;QACL,EAAE;QACF,SAAS;QACT,MAAM,EAAE,UAAU,CAAC,KAAK,EAAE,OAAO,CAAC;QAClC,SAAS,EAAE,EAAE;QACb,OAAO,EAAE,EAAE;QACX,QAAQ,EAAE,SAAS;KACpB,CAAC;AACJ,CAAC"}
|
|
1
|
+
{"version":3,"file":"fixtures.js","sourceRoot":"","sources":["../../src/testing/fixtures.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,OAAO,EAAY,MAAM,MAAM,CAAC;AAChC,OAAO,EAAE,IAAI,EAA2C,MAAM,aAAa,CAAC;AAE5E,iGAAiG;AACjG,MAAM,CAAC,MAAM,cAAc,GAAG,sBAAsB,CAAC;AAErD,6EAA6E;AAC7E,MAAM,CAAC,MAAM,YAAY,GAAG,kBAAkB,CAAC;AAE/C,kEAAkE;AAClE,MAAM,CAAC,MAAM,sBAAsB,GAA0B;IAC3D,GAAG,EAAE,SAAS;IACd,CAAC,EAAE,6CAA6C;IAChD,CAAC,EAAE,6CAA6C;IAChD,GAAG,EAAE,KAAK;IACV,GAAG,EAAE,kBAAkB;CACxB,CAAC;AAEF,mEAAmE;AACnE,MAAM,CAAC,MAAM,wBAAwB,GAA0B;IAC7D,GAAG,EAAE,SAAS;IACd,CAAC,EAAE,6CAA6C;IAChD,CAAC,EAAE,6CAA6C;IAChD,GAAG,EAAE,KAAK;IACV,GAAG,EAAE,eAAe;CACrB,CAAC;AAEF,oFAAoF;AACpF,MAAM,UAAU,iBAAiB;IAC/B,MAAM,EAAE,CAAC,EAAE,EAAE,EAAE,GAAG,GAAG,EAAE,GAAG,wBAAwB,CAAC;IACnD,OAAO,IAAI,CAAC,SAAS,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,GAAG,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,CAAC;AAC1E,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,UAAU,CACxB,KAAgB,EAChB,OAAiB;IAEjB,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,EAAE,CAAC;AACjE,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,gBAAgB,CAC9B,SAAiB,EACjB,IAAY,EACZ,SAAS,GAAG,EAAE,EACd,MAAM,GAAG,EAAE;IAEX,OAAO;QACL,SAAS;QACT,SAAS;QACT,MAAM;QACN,IAAI,EAAE,IAAI,CAAC,UAAU;QACrB,KAAK,EAAE;YACL;gBACE,OAAO,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,EAAE;gBACvC,QAAQ,EAAE,SAAS;gBACnB,QAAQ,EAAE,EAAE;gBACZ,SAAS,EAAE,YAAY;aACxB;SACF;QACD,QAAQ,EAAE,SAAS;QACnB,UAAU,EAAE,EAAE;QACd,gBAAgB,EAAE,EAAE;KACrB,CAAC;AACJ,CAAC;AAED,iDAAiD;AACjD,MAAM,UAAU,QAAQ,CACtB,EAAU,EACV,SAAiB,EACjB,KAAgB,EAChB,OAAiB;IAEjB,OAAO;QACL,EAAE;QACF,SAAS;QACT,MAAM,EAAE,UAAU,CAAC,KAAK,EAAE,OAAO,CAAC;QAClC,SAAS,EAAE,EAAE;QACb,OAAO,EAAE,EAAE;QACX,QAAQ,EAAE,SAAS;KACpB,CAAC;AACJ,CAAC"}
|
package/dist/testing/node.d.ts
CHANGED
|
@@ -12,8 +12,31 @@
|
|
|
12
12
|
* ```ts
|
|
13
13
|
* // vitest.config.ts
|
|
14
14
|
* import { createVcrAgent } from "@loopingai/core/testing/node";
|
|
15
|
+
*
|
|
16
|
+
* export default defineConfig({
|
|
17
|
+
* plugins: [cloudflareTest({ miniflare: { fetchMock: createVcrAgent({ … }) } })],
|
|
18
|
+
* test: { globalSetup: ["@loopingai/core/testing/vcr-global-setup"] }
|
|
19
|
+
* });
|
|
15
20
|
* ```
|
|
16
21
|
*
|
|
22
|
+
* ## Two version constraints, both of which fail unreadably
|
|
23
|
+
*
|
|
24
|
+
* **1. `@cloudflare/vitest-pool-workers` must be `^0.18`.** The recorder is
|
|
25
|
+
* installed as Miniflare's `fetchMock`, and that option **does not exist in
|
|
26
|
+
* Miniflare 5**, which pool `0.19`+ depends on — only `outboundService` remains.
|
|
27
|
+
* On a newer pool the option is silently ignored rather than rejected, so
|
|
28
|
+
* `disableNetConnect()` never takes effect, every request goes to the real
|
|
29
|
+
* network, and each one fails as `internal error; reference = …` naming nothing.
|
|
30
|
+
* That is why the peer range is pinned rather than open.
|
|
31
|
+
*
|
|
32
|
+
* **2. Your `undici` must be the copy Miniflare uses.** `fetchMock` is an undici
|
|
33
|
+
* `MockAgent` and Miniflare validates it against *its own* undici, so two copies
|
|
34
|
+
* in one `node_modules` fail with `Input not instance of MockAgent`. Miniflare
|
|
35
|
+
* pins an exact version (7.28.0 at the time of writing) and this package's
|
|
36
|
+
* `undici` peer range tracks it. Check with
|
|
37
|
+
* `ls node_modules/miniflare/node_modules/undici` — anything there means a
|
|
38
|
+
* second copy, and the fix is to align yours rather than to debug the message.
|
|
39
|
+
*
|
|
17
40
|
* For the common case — wiring cassette flush/teardown — you do not need this
|
|
18
41
|
* subpath at all. Point `globalSetup` at
|
|
19
42
|
* `@loopingai/core/testing/vcr-global-setup`, which is this module's `setup`/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../src/testing/node.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"node.d.ts","sourceRoot":"","sources":["../../src/testing/node.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAEH,OAAO,EACL,cAAc,EACd,QAAQ,EACR,QAAQ,EACR,KAAK,qBAAqB,EAC3B,MAAM,UAAU,CAAC;AAElB,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC"}
|
package/dist/testing/node.js
CHANGED
|
@@ -12,8 +12,31 @@
|
|
|
12
12
|
* ```ts
|
|
13
13
|
* // vitest.config.ts
|
|
14
14
|
* import { createVcrAgent } from "@loopingai/core/testing/node";
|
|
15
|
+
*
|
|
16
|
+
* export default defineConfig({
|
|
17
|
+
* plugins: [cloudflareTest({ miniflare: { fetchMock: createVcrAgent({ … }) } })],
|
|
18
|
+
* test: { globalSetup: ["@loopingai/core/testing/vcr-global-setup"] }
|
|
19
|
+
* });
|
|
15
20
|
* ```
|
|
16
21
|
*
|
|
22
|
+
* ## Two version constraints, both of which fail unreadably
|
|
23
|
+
*
|
|
24
|
+
* **1. `@cloudflare/vitest-pool-workers` must be `^0.18`.** The recorder is
|
|
25
|
+
* installed as Miniflare's `fetchMock`, and that option **does not exist in
|
|
26
|
+
* Miniflare 5**, which pool `0.19`+ depends on — only `outboundService` remains.
|
|
27
|
+
* On a newer pool the option is silently ignored rather than rejected, so
|
|
28
|
+
* `disableNetConnect()` never takes effect, every request goes to the real
|
|
29
|
+
* network, and each one fails as `internal error; reference = …` naming nothing.
|
|
30
|
+
* That is why the peer range is pinned rather than open.
|
|
31
|
+
*
|
|
32
|
+
* **2. Your `undici` must be the copy Miniflare uses.** `fetchMock` is an undici
|
|
33
|
+
* `MockAgent` and Miniflare validates it against *its own* undici, so two copies
|
|
34
|
+
* in one `node_modules` fail with `Input not instance of MockAgent`. Miniflare
|
|
35
|
+
* pins an exact version (7.28.0 at the time of writing) and this package's
|
|
36
|
+
* `undici` peer range tracks it. Check with
|
|
37
|
+
* `ls node_modules/miniflare/node_modules/undici` — anything there means a
|
|
38
|
+
* second copy, and the fix is to align yours rather than to debug the message.
|
|
39
|
+
*
|
|
17
40
|
* For the common case — wiring cassette flush/teardown — you do not need this
|
|
18
41
|
* subpath at all. Point `globalSetup` at
|
|
19
42
|
* `@loopingai/core/testing/vcr-global-setup`, which is this module's `setup`/
|
package/dist/testing/node.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"node.js","sourceRoot":"","sources":["../../src/testing/node.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"node.js","sourceRoot":"","sources":["../../src/testing/node.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AAEH,OAAO,EACL,cAAc,EACd,QAAQ,EACR,QAAQ,EAET,MAAM,UAAU,CAAC;AAElB,OAAO,EAAE,kBAAkB,EAAE,gBAAgB,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { RunnerTestCase } from "vitest";
|
|
2
2
|
/**
|
|
3
|
-
* Cassette filename for a test: `kebab(<
|
|
4
|
-
* then each describe level then the test name, all kebab-cased and
|
|
5
|
-
* `--`, plus `.snapshot.json`. Example:
|
|
6
|
-
* `
|
|
3
|
+
* Cassette filename for a test: `kebab(<project-relative path, minus
|
|
4
|
+
* .spec.ts>)` then each describe level then the test name, all kebab-cased and
|
|
5
|
+
* joined by `--`, plus `.snapshot.json`. Example:
|
|
6
|
+
* `test-arc-agi-recorded--arc-recorded-real-api--plays-a-real-game.snapshot.json`.
|
|
7
7
|
* Exported for debugging / the cassette-rename step.
|
|
8
8
|
*/
|
|
9
9
|
export declare function cassetteNameFor(task: RunnerTestCase): string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vcr-spec.d.ts","sourceRoot":"","sources":["../../src/testing/vcr-spec.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAmB,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"vcr-spec.d.ts","sourceRoot":"","sources":["../../src/testing/vcr-spec.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAmB,MAAM,QAAQ,CAAC;AAkD9D;;;;;;GAMG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,cAAc,GAAG,MAAM,CAW5D;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,IAAI,IAAI,CA8BrC"}
|
package/dist/testing/vcr-spec.js
CHANGED
|
@@ -20,17 +20,38 @@ function isFileTask(suite) {
|
|
|
20
20
|
return typeof suite.filepath === "string";
|
|
21
21
|
}
|
|
22
22
|
/**
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
23
|
+
* The spec's path relative to the project root.
|
|
24
|
+
*
|
|
25
|
+
* Vitest already computes this as `file.name`, which is the whole answer: it is
|
|
26
|
+
* stable across machines and checkouts, and it is *unique per spec file*, which
|
|
27
|
+
* is what a cassette name has to be.
|
|
28
|
+
*
|
|
29
|
+
* Deriving it from `filepath` instead — by stripping a leading `test/` or
|
|
30
|
+
* `src/` — got this wrong twice. Splitting on a segment that never matched
|
|
31
|
+
* returned the absolute path unchanged, so a cassette was named after the
|
|
32
|
+
* developer's home directory; and stripping *both* roots collapsed
|
|
33
|
+
* `test/api.spec.ts` and `src/api.spec.ts` onto one name, which for a store
|
|
34
|
+
* keyed solely by filename means one recording silently overwrites the other
|
|
35
|
+
* and playback serves the wrong responses.
|
|
36
|
+
*
|
|
37
|
+
* The fallback is only for a runner that does not populate `name`; a bare
|
|
38
|
+
* filename can still collide, but it is strictly better than an absolute path
|
|
39
|
+
* and nothing here reaches it.
|
|
40
|
+
*/
|
|
41
|
+
function relativeSpecPath(file) {
|
|
42
|
+
if (typeof file.name === "string" && file.name !== "")
|
|
43
|
+
return file.name;
|
|
44
|
+
return file.filepath.replace(/\\/g, "/").split("/").pop();
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Cassette filename for a test: `kebab(<project-relative path, minus
|
|
48
|
+
* .spec.ts>)` then each describe level then the test name, all kebab-cased and
|
|
49
|
+
* joined by `--`, plus `.snapshot.json`. Example:
|
|
50
|
+
* `test-arc-agi-recorded--arc-recorded-real-api--plays-a-real-game.snapshot.json`.
|
|
27
51
|
* Exported for debugging / the cassette-rename step.
|
|
28
52
|
*/
|
|
29
53
|
export function cassetteNameFor(task) {
|
|
30
|
-
const rel = task.file.
|
|
31
|
-
.split(/[\\/]test[\\/]/)
|
|
32
|
-
.pop()
|
|
33
|
-
.replace(/\.spec\.ts$/, "");
|
|
54
|
+
const rel = relativeSpecPath(task.file).replace(/\.spec\.ts$/, "");
|
|
34
55
|
const suites = [];
|
|
35
56
|
let suite = task.suite;
|
|
36
57
|
while (suite && !isFileTask(suite)) {
|
|
@@ -52,9 +73,9 @@ export function setupRecording() {
|
|
|
52
73
|
method: "POST"
|
|
53
74
|
});
|
|
54
75
|
if (res.status === 404) {
|
|
55
|
-
throw new Error(`No VCR cassette "${cassette}". Record it with \`
|
|
56
|
-
`(add
|
|
57
|
-
`
|
|
76
|
+
throw new Error(`No VCR cassette "${cassette}". Record it with \`RECORD=1\` ` +
|
|
77
|
+
`(add \`-t "${ctx.task.name}"\` to record only this test), which needs ` +
|
|
78
|
+
`whatever real credentials the recorded API calls require.`);
|
|
58
79
|
}
|
|
59
80
|
if (res.status === 409) {
|
|
60
81
|
throw new Error(`VCR cassette "${cassette}" could not activate: another recorded test is ` +
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"vcr-spec.js","sourceRoot":"","sources":["../../src/testing/vcr-spec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAE/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAErD;;;;;;;;;;GAUG;AAEH,MAAM,KAAK,GAAG,CAAC,CAAS,EAAU,EAAE,CAClC,CAAC;KACE,WAAW,EAAE;KACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;KAC3B,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;AAE7B,kFAAkF;AAClF,SAAS,UAAU,CAAC,KAAsB;IACxC,OAAO,OAAQ,KAA+B,CAAC,QAAQ,KAAK,QAAQ,CAAC;AACvE,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAAC,IAAoB;IAClD,MAAM,GAAG,GAAG,
|
|
1
|
+
{"version":3,"file":"vcr-spec.js","sourceRoot":"","sources":["../../src/testing/vcr-spec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAE/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,iBAAiB,CAAC;AAErD;;;;;;;;;;GAUG;AAEH,MAAM,KAAK,GAAG,CAAC,CAAS,EAAU,EAAE,CAClC,CAAC;KACE,WAAW,EAAE;KACb,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;KAC3B,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;AAE7B,kFAAkF;AAClF,SAAS,UAAU,CAAC,KAAsB;IACxC,OAAO,OAAQ,KAA+B,CAAC,QAAQ,KAAK,QAAQ,CAAC;AACvE,CAAC;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,SAAS,gBAAgB,CAAC,IAA4B;IACpD,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,IAAI,IAAI,CAAC,IAAI,KAAK,EAAE;QAAE,OAAO,IAAI,CAAC,IAAI,CAAC;IACxE,OAAO,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAG,CAAC;AAC7D,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAAC,IAAoB;IAClD,MAAM,GAAG,GAAG,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,aAAa,EAAE,EAAE,CAAC,CAAC;IAEnE,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,KAAK,GAAgC,IAAI,CAAC,KAAK,CAAC;IACpD,OAAO,KAAK,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,EAAE,CAAC;QACnC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QAC3B,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC;IACtB,CAAC;IAED,OAAO,CAAC,GAAG,EAAE,GAAG,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,gBAAgB,CAAC;AAC9E,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,cAAc;IAC5B,UAAU,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QACvB,MAAM,QAAQ,GAAG,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC3C,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,GAAG,kBAAkB,iBAAiB,QAAQ,EAAE,EAAE;YACxE,MAAM,EAAE,MAAM;SACf,CAAC,CAAC;QACH,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YACvB,MAAM,IAAI,KAAK,CACb,oBAAoB,QAAQ,iCAAiC;gBAC3D,cAAc,GAAG,CAAC,IAAI,CAAC,IAAI,6CAA6C;gBACxE,2DAA2D,CAC9D,CAAC;QACJ,CAAC;QACD,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YACvB,MAAM,IAAI,KAAK,CACb,iBAAiB,QAAQ,iDAAiD;gBACxE,iEAAiE;gBACjE,kCAAkC,CACrC,CAAC;QACJ,CAAC;QACD,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;YACZ,MAAM,IAAI,KAAK,CACb,mCAAmC,GAAG,CAAC,MAAM,iBAAiB,QAAQ,IAAI,CAC3E,CAAC;QACJ,CAAC;IACH,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,KAAK,IAAI,EAAE;QACnB,MAAM,KAAK,CAAC,GAAG,kBAAkB,UAAU,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IACnE,CAAC,CAAC,CAAC;AACL,CAAC"}
|