@msm-core/mini 0.3.1 → 0.4.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/CHANGELOG.md +63 -0
- package/dist/adapters/redis-memory.d.ts +3 -0
- package/dist/adapters/redis-memory.d.ts.map +1 -1
- package/dist/adapters/redis-memory.js +6 -0
- package/dist/adapters/redis-memory.js.map +1 -1
- package/dist/adapters/redis-types.d.ts +2 -0
- package/dist/adapters/redis-types.d.ts.map +1 -1
- package/dist/brain/anthropic.d.ts.map +1 -1
- package/dist/brain/anthropic.js +3 -2
- package/dist/brain/anthropic.js.map +1 -1
- package/dist/brain/gemini.d.ts.map +1 -1
- package/dist/brain/gemini.js +2 -1
- package/dist/brain/gemini.js.map +1 -1
- package/dist/brain/ollama.d.ts.map +1 -1
- package/dist/brain/ollama.js +3 -2
- package/dist/brain/ollama.js.map +1 -1
- package/dist/brain/openai.d.ts.map +1 -1
- package/dist/brain/openai.js +2 -1
- package/dist/brain/openai.js.map +1 -1
- package/dist/brain/retry.d.ts +21 -0
- package/dist/brain/retry.d.ts.map +1 -0
- package/dist/brain/retry.js +63 -0
- package/dist/brain/retry.js.map +1 -0
- package/dist/core/loop.d.ts.map +1 -1
- package/dist/core/loop.js +101 -36
- package/dist/core/loop.js.map +1 -1
- package/dist/core/types.d.ts +26 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/definition/parser.d.ts.map +1 -1
- package/dist/definition/parser.js +5 -2
- package/dist/definition/parser.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/server.d.ts +24 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +90 -25
- package/dist/server.js.map +1 -1
- package/dist/tools/dedup.d.ts +7 -2
- package/dist/tools/dedup.d.ts.map +1 -1
- package/dist/tools/dedup.js +9 -9
- package/dist/tools/dedup.js.map +1 -1
- package/dist/tools/executor.d.ts +8 -4
- package/dist/tools/executor.d.ts.map +1 -1
- package/dist/tools/executor.js +62 -6
- package/dist/tools/executor.js.map +1 -1
- package/package.json +1 -1
package/dist/server.js
CHANGED
|
@@ -8,6 +8,11 @@
|
|
|
8
8
|
* The UTS api/server.ts proxies /chat → /v1/event on this server.
|
|
9
9
|
* All other msm-agent HTTP surface (dashboard etc.) is NOT replicated — keep it slim.
|
|
10
10
|
*
|
|
11
|
+
* Security posture: this server is designed to sit on localhost behind a
|
|
12
|
+
* trusted gateway. It still hard-validates its inputs: request bodies are
|
|
13
|
+
* size-capped and `guardsOverride` is whitelisted + type-checked so a caller
|
|
14
|
+
* can never disable the loop's safety guards with malformed values.
|
|
15
|
+
*
|
|
11
16
|
* @example
|
|
12
17
|
* const agentServer = createAgentServer(agent, { port: PORT + 1 });
|
|
13
18
|
* await agentServer.start();
|
|
@@ -15,10 +20,24 @@
|
|
|
15
20
|
* await agentServer.stop();
|
|
16
21
|
*/
|
|
17
22
|
import { createServer, } from "node:http";
|
|
18
|
-
|
|
23
|
+
class BodyTooLargeError extends Error {
|
|
24
|
+
constructor() {
|
|
25
|
+
super("Request body too large");
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function readBody(req, maxBytes) {
|
|
19
29
|
return new Promise((resolve, reject) => {
|
|
20
30
|
const chunks = [];
|
|
21
|
-
|
|
31
|
+
let received = 0;
|
|
32
|
+
req.on("data", (c) => {
|
|
33
|
+
received += c.length;
|
|
34
|
+
if (received > maxBytes) {
|
|
35
|
+
req.destroy();
|
|
36
|
+
reject(new BodyTooLargeError());
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
chunks.push(c);
|
|
40
|
+
});
|
|
22
41
|
req.on("end", () => {
|
|
23
42
|
try {
|
|
24
43
|
resolve(JSON.parse(Buffer.concat(chunks).toString("utf8")));
|
|
@@ -30,27 +49,66 @@ function readBody(req) {
|
|
|
30
49
|
req.on("error", reject);
|
|
31
50
|
});
|
|
32
51
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
52
|
+
/**
|
|
53
|
+
* Whitelist + type-check a guards override coming from the network.
|
|
54
|
+
*
|
|
55
|
+
* Without this, a malformed value silently DISABLES guards: resolveGuards
|
|
56
|
+
* merges with `??` (any non-nullish survives), and every guard comparison
|
|
57
|
+
* against a non-number is false — `5 >= "x"` never trips the iteration cap,
|
|
58
|
+
* `"x" > 0` turns the cost cap and timeout off entirely.
|
|
59
|
+
*
|
|
60
|
+
* Only known numeric keys with finite, non-negative values pass through.
|
|
61
|
+
*/
|
|
62
|
+
export function sanitizeGuardsOverride(raw) {
|
|
63
|
+
if (raw === null || typeof raw !== "object" || Array.isArray(raw)) {
|
|
64
|
+
return undefined;
|
|
65
|
+
}
|
|
66
|
+
const NUMERIC_KEYS = [
|
|
67
|
+
"maxIterations",
|
|
68
|
+
"costCapPerTask",
|
|
69
|
+
"timeoutMs",
|
|
70
|
+
"confidenceThreshold",
|
|
71
|
+
"maxToolCallsPerTask",
|
|
72
|
+
"maxConsecutiveFailures",
|
|
73
|
+
];
|
|
74
|
+
const out = {};
|
|
75
|
+
for (const key of NUMERIC_KEYS) {
|
|
76
|
+
const v = raw[key];
|
|
77
|
+
if (typeof v === "number" && Number.isFinite(v) && v >= 0) {
|
|
78
|
+
out[key] = v;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
return Object.keys(out).length > 0 ? out : undefined;
|
|
40
82
|
}
|
|
41
83
|
const START_TIME = Date.now();
|
|
42
84
|
export function createAgentServer(agent, opts) {
|
|
43
85
|
const host = opts.host ?? "127.0.0.1";
|
|
44
86
|
const port = opts.port;
|
|
87
|
+
const maxBodyBytes = opts.maxBodyBytes ?? 262_144;
|
|
88
|
+
const corsOrigin = opts.corsOrigin;
|
|
89
|
+
function json(res, status, body) {
|
|
90
|
+
const payload = JSON.stringify(body);
|
|
91
|
+
res.writeHead(status, {
|
|
92
|
+
"Content-Type": "application/json",
|
|
93
|
+
"Content-Length": Buffer.byteLength(payload),
|
|
94
|
+
...(corsOrigin ? { "Access-Control-Allow-Origin": corsOrigin } : {}),
|
|
95
|
+
});
|
|
96
|
+
res.end(payload);
|
|
97
|
+
}
|
|
45
98
|
const server = createServer(async (req, res) => {
|
|
46
99
|
const path = (req.url ?? "/").split("?")[0];
|
|
47
|
-
// CORS preflight
|
|
100
|
+
// CORS preflight — only when CORS is enabled
|
|
48
101
|
if (req.method === "OPTIONS") {
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
102
|
+
if (corsOrigin) {
|
|
103
|
+
res.writeHead(204, {
|
|
104
|
+
"Access-Control-Allow-Origin": corsOrigin,
|
|
105
|
+
"Access-Control-Allow-Methods": "POST, GET, OPTIONS",
|
|
106
|
+
"Access-Control-Allow-Headers": "Content-Type, Authorization",
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
res.writeHead(405);
|
|
111
|
+
}
|
|
54
112
|
res.end();
|
|
55
113
|
return;
|
|
56
114
|
}
|
|
@@ -64,10 +122,15 @@ export function createAgentServer(agent, opts) {
|
|
|
64
122
|
if (path === "/v1/event" && req.method === "POST") {
|
|
65
123
|
let body;
|
|
66
124
|
try {
|
|
67
|
-
body = (await readBody(req));
|
|
125
|
+
body = (await readBody(req, maxBodyBytes));
|
|
68
126
|
}
|
|
69
|
-
catch {
|
|
70
|
-
|
|
127
|
+
catch (err) {
|
|
128
|
+
if (err instanceof BodyTooLargeError) {
|
|
129
|
+
json(res, 413, { error: "Request body too large" });
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
json(res, 400, { error: "Invalid JSON body" });
|
|
133
|
+
}
|
|
71
134
|
return;
|
|
72
135
|
}
|
|
73
136
|
const sessionId = typeof body["sessionId"] === "string" ? body["sessionId"] : "";
|
|
@@ -87,12 +150,9 @@ export function createAgentServer(agent, opts) {
|
|
|
87
150
|
const agentType = (typeof bodyTenant?.["agentType"] === "string" ? bodyTenant["agentType"] : undefined) ??
|
|
88
151
|
(typeof req.headers["x-agent-type"] === "string" ? req.headers["x-agent-type"] : undefined);
|
|
89
152
|
const tenantContext = companyId && agentType ? { companyId, agentType } : undefined;
|
|
90
|
-
// Per-tenant guard overrides
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
body["guardsOverride"] !== null
|
|
94
|
-
? body["guardsOverride"]
|
|
95
|
-
: undefined;
|
|
153
|
+
// Per-tenant guard overrides — whitelisted + type-checked, so malformed
|
|
154
|
+
// values can't silently disable the loop's safety guards.
|
|
155
|
+
const guardsOverride = sanitizeGuardsOverride(body["guardsOverride"]);
|
|
96
156
|
const outcome = await agent.handle({
|
|
97
157
|
sessionId,
|
|
98
158
|
message: text,
|
|
@@ -113,8 +173,13 @@ export function createAgentServer(agent, opts) {
|
|
|
113
173
|
});
|
|
114
174
|
return {
|
|
115
175
|
start() {
|
|
116
|
-
return new Promise((resolve) => {
|
|
176
|
+
return new Promise((resolve, reject) => {
|
|
177
|
+
// Surface listen failures (EADDRINUSE etc.) as a rejected promise
|
|
178
|
+
// instead of an unhandled 'error' event crash.
|
|
179
|
+
const onError = (err) => reject(err);
|
|
180
|
+
server.once("error", onError);
|
|
117
181
|
server.listen(port, host, () => {
|
|
182
|
+
server.removeListener("error", onError);
|
|
118
183
|
console.log(`[AgentServer] listening on http://${host}:${port}`);
|
|
119
184
|
resolve();
|
|
120
185
|
});
|
package/dist/server.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/dedup.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Tool Dedup — Hash-based idempotency for tool calls.
|
|
3
3
|
*
|
|
4
|
-
* Deduplication key: SHA-256(toolName + JSON.stringify(sortedArgs))
|
|
4
|
+
* Deduplication key: SHA-256(toolName + "::" + JSON.stringify(sortedArgs))
|
|
5
5
|
* Stored in Redis as: {prefix}:session:{id}:tools:dedup hash field
|
|
6
6
|
* TTL: 5 minutes (configurable)
|
|
7
7
|
*/
|
|
@@ -14,7 +14,12 @@ type RedisLike = {
|
|
|
14
14
|
export declare function toolDedupKey(prefix: string, sessionId: string): string;
|
|
15
15
|
export declare function checkDedup(redis: RedisLike, dedupKey: string, hash: string): Promise<ToolResult | null>;
|
|
16
16
|
export declare function storeDedup(redis: RedisLike, dedupKey: string, hash: string, result: ToolResult, ttlSeconds: number): Promise<void>;
|
|
17
|
-
/**
|
|
17
|
+
/**
|
|
18
|
+
* Deterministic hash of a tool call (SHA-256, key-sorted args).
|
|
19
|
+
*
|
|
20
|
+
* Previously FNV-1a 32-bit — at 32 bits a same-session collision silently
|
|
21
|
+
* returns the WRONG cached tool result. node:crypto is dependency-free.
|
|
22
|
+
*/
|
|
18
23
|
export declare function hashToolCall(toolName: string, args: Record<string, unknown>): string;
|
|
19
24
|
export {};
|
|
20
25
|
//# sourceMappingURL=dedup.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dedup.d.ts","sourceRoot":"","sources":["../../src/tools/dedup.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;
|
|
1
|
+
{"version":3,"file":"dedup.d.ts","sourceRoot":"","sources":["../../src/tools/dedup.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAEnD,KAAK,SAAS,GAAG;IACf,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACzD,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAClE,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACxD,CAAC;AAEF,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAEtE;AAED,wBAAsB,UAAU,CAC9B,KAAK,EAAE,SAAS,EAChB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,GACX,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAQ5B;AAED,wBAAsB,UAAU,CAC9B,KAAK,EAAE,SAAS,EAChB,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,UAAU,EAClB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC,IAAI,CAAC,CAGf;AAED;;;;;GAKG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAIpF"}
|
package/dist/tools/dedup.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Tool Dedup — Hash-based idempotency for tool calls.
|
|
3
3
|
*
|
|
4
|
-
* Deduplication key: SHA-256(toolName + JSON.stringify(sortedArgs))
|
|
4
|
+
* Deduplication key: SHA-256(toolName + "::" + JSON.stringify(sortedArgs))
|
|
5
5
|
* Stored in Redis as: {prefix}:session:{id}:tools:dedup hash field
|
|
6
6
|
* TTL: 5 minutes (configurable)
|
|
7
7
|
*/
|
|
8
|
+
import { createHash } from "node:crypto";
|
|
8
9
|
export function toolDedupKey(prefix, sessionId) {
|
|
9
10
|
return `${prefix}:session:${sessionId}:tools:dedup`;
|
|
10
11
|
}
|
|
@@ -23,17 +24,16 @@ export async function storeDedup(redis, dedupKey, hash, result, ttlSeconds) {
|
|
|
23
24
|
await redis.hset(dedupKey, hash, JSON.stringify(result));
|
|
24
25
|
await redis.expire(dedupKey, ttlSeconds);
|
|
25
26
|
}
|
|
26
|
-
/**
|
|
27
|
+
/**
|
|
28
|
+
* Deterministic hash of a tool call (SHA-256, key-sorted args).
|
|
29
|
+
*
|
|
30
|
+
* Previously FNV-1a 32-bit — at 32 bits a same-session collision silently
|
|
31
|
+
* returns the WRONG cached tool result. node:crypto is dependency-free.
|
|
32
|
+
*/
|
|
27
33
|
export function hashToolCall(toolName, args) {
|
|
28
34
|
const sorted = sortKeys(args);
|
|
29
35
|
const str = toolName + "::" + JSON.stringify(sorted);
|
|
30
|
-
|
|
31
|
-
let h = 2166136261;
|
|
32
|
-
for (let i = 0; i < str.length; i++) {
|
|
33
|
-
h ^= str.charCodeAt(i);
|
|
34
|
-
h = (h * 16777619) >>> 0;
|
|
35
|
-
}
|
|
36
|
-
return h.toString(16).padStart(8, "0");
|
|
36
|
+
return createHash("sha256").update(str).digest("hex");
|
|
37
37
|
}
|
|
38
38
|
function sortKeys(obj) {
|
|
39
39
|
if (obj === null || typeof obj !== "object")
|
package/dist/tools/dedup.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dedup.js","sourceRoot":"","sources":["../../src/tools/dedup.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;
|
|
1
|
+
{"version":3,"file":"dedup.js","sourceRoot":"","sources":["../../src/tools/dedup.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AASzC,MAAM,UAAU,YAAY,CAAC,MAAc,EAAE,SAAiB;IAC5D,OAAO,GAAG,MAAM,YAAY,SAAS,cAAc,CAAC;AACtD,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,KAAgB,EAChB,QAAgB,EAChB,IAAY;IAEZ,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;IAChD,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IACzB,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAe,CAAC;IAC1C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,KAAgB,EAChB,QAAgB,EAChB,IAAY,EACZ,MAAkB,EAClB,UAAkB;IAElB,MAAM,KAAK,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;IACzD,MAAM,KAAK,CAAC,MAAM,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;AAC3C,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAAC,QAAgB,EAAE,IAA6B;IAC1E,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;IAC9B,MAAM,GAAG,GAAG,QAAQ,GAAG,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IACrD,OAAO,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AACxD,CAAC;AAED,SAAS,QAAQ,CAAC,GAAY;IAC5B,IAAI,GAAG,KAAK,IAAI,IAAI,OAAO,GAAG,KAAK,QAAQ;QAAE,OAAO,GAAG,CAAC;IACxD,IAAI,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC;QAAE,OAAO,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACjD,OAAO,MAAM,CAAC,WAAW,CACvB,MAAM,CAAC,OAAO,CAAC,GAA8B,CAAC;SAC3C,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC;SACtC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CACrC,CAAC;AACJ,CAAC"}
|
package/dist/tools/executor.d.ts
CHANGED
|
@@ -2,13 +2,15 @@
|
|
|
2
2
|
* Tool Executor — Validation, dedup, and execution pipeline.
|
|
3
3
|
*
|
|
4
4
|
* Pipeline per tool call:
|
|
5
|
-
* 1.
|
|
6
|
-
* 2.
|
|
7
|
-
*
|
|
5
|
+
* 1. Validate — check required parameters are present and typed
|
|
6
|
+
* 2. onBeforeTool hook — approval gate / audit / substitute / skip.
|
|
7
|
+
* Runs BEFORE dedup so cached results can never bypass the gate.
|
|
8
|
+
* requiresApproval tools fail closed (hook error or no hook → blocked).
|
|
9
|
+
* 3. Dedup — return cached result if same args seen in last 5 min
|
|
8
10
|
* 4. Execute — call tool.execute()
|
|
9
11
|
* 5. Cache — store result in dedup hash
|
|
10
12
|
*/
|
|
11
|
-
import type { Tool, ToolResult, ToolMeta } from "../core/types.js";
|
|
13
|
+
import type { Tool, ToolResult, ToolMeta, AgentHooks } from "../core/types.js";
|
|
12
14
|
type RedisLike = {
|
|
13
15
|
hget(key: string, field: string): Promise<string | null>;
|
|
14
16
|
hset(key: string, field: string, value: string): Promise<unknown>;
|
|
@@ -19,6 +21,8 @@ export interface ExecutorOptions {
|
|
|
19
21
|
redis: RedisLike;
|
|
20
22
|
redisPrefix: string;
|
|
21
23
|
dedupTtlSeconds: number;
|
|
24
|
+
/** Optional hooks — only onBeforeTool is used at this layer */
|
|
25
|
+
hooks?: Pick<AgentHooks, "onBeforeTool">;
|
|
22
26
|
}
|
|
23
27
|
export interface ExecutionResult {
|
|
24
28
|
result: ToolResult;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../src/tools/executor.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"executor.d.ts","sourceRoot":"","sources":["../../src/tools/executor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAG/E,KAAK,SAAS,GAAG;IACf,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACzD,IAAI,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IAClE,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACvD,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CAC1C,CAAC;AAEF,MAAM,WAAW,eAAe;IAC9B,KAAK,EAAE,SAAS,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,eAAe,EAAE,MAAM,CAAC;IACxB,+DAA+D;IAC/D,KAAK,CAAC,EAAE,IAAI,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC;CAC1C;AAED,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,UAAU,CAAC;IACnB,MAAM,EAAE,OAAO,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,wBAAsB,WAAW,CAC/B,IAAI,EAAE,IAAI,EACV,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,IAAI,EAAE,QAAQ,EACd,IAAI,EAAE,eAAe,GACpB,OAAO,CAAC,eAAe,CAAC,CAgG1B;AAqBD,oFAAoF;AACpF,wBAAgB,iBAAiB,CAC/B,KAAK,EAAE,IAAI,EAAE,GACZ,OAAO,kBAAkB,EAAE,cAAc,EAAE,CAS7C"}
|
package/dist/tools/executor.js
CHANGED
|
@@ -2,9 +2,11 @@
|
|
|
2
2
|
* Tool Executor — Validation, dedup, and execution pipeline.
|
|
3
3
|
*
|
|
4
4
|
* Pipeline per tool call:
|
|
5
|
-
* 1.
|
|
6
|
-
* 2.
|
|
7
|
-
*
|
|
5
|
+
* 1. Validate — check required parameters are present and typed
|
|
6
|
+
* 2. onBeforeTool hook — approval gate / audit / substitute / skip.
|
|
7
|
+
* Runs BEFORE dedup so cached results can never bypass the gate.
|
|
8
|
+
* requiresApproval tools fail closed (hook error or no hook → blocked).
|
|
9
|
+
* 3. Dedup — return cached result if same args seen in last 5 min
|
|
8
10
|
* 4. Execute — call tool.execute()
|
|
9
11
|
* 5. Cache — store result in dedup hash
|
|
10
12
|
*/
|
|
@@ -20,14 +22,68 @@ export async function executeTool(tool, params, meta, opts) {
|
|
|
20
22
|
durationMs: Date.now() - start,
|
|
21
23
|
};
|
|
22
24
|
}
|
|
23
|
-
// Step 2:
|
|
25
|
+
// Step 2: onBeforeTool hook — approval gate, audit, dry-run, etc.
|
|
26
|
+
// Runs BEFORE the dedup check so every call (including ones that would be
|
|
27
|
+
// served from cache) passes the gate — an approval/audit hook must never be
|
|
28
|
+
// bypassed by a cached result.
|
|
29
|
+
//
|
|
30
|
+
// Failure semantics: a throwing hook is "proceed" for ordinary tools, but
|
|
31
|
+
// FAIL-CLOSED for tools marked requiresApproval — if the approval system
|
|
32
|
+
// errors, a destructive tool must not run.
|
|
33
|
+
if (opts.hooks?.onBeforeTool) {
|
|
34
|
+
const directive = await opts.hooks
|
|
35
|
+
.onBeforeTool(tool.name, params, meta)
|
|
36
|
+
.catch(() => tool.requiresApproval
|
|
37
|
+
? { approvalFailed: true }
|
|
38
|
+
: "proceed");
|
|
39
|
+
if (typeof directive === "object" && "approvalFailed" in directive) {
|
|
40
|
+
return {
|
|
41
|
+
result: {
|
|
42
|
+
tool: tool.name,
|
|
43
|
+
status: "failed",
|
|
44
|
+
error: `Tool "${tool.name}" requires approval and the approval hook failed — execution blocked`,
|
|
45
|
+
},
|
|
46
|
+
cached: false,
|
|
47
|
+
durationMs: Date.now() - start,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
if (directive === "skip") {
|
|
51
|
+
return {
|
|
52
|
+
result: { tool: tool.name, status: "ok", result: { skipped: true } },
|
|
53
|
+
cached: false,
|
|
54
|
+
durationMs: Date.now() - start,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
if (typeof directive === "object" && "substituteResult" in directive) {
|
|
58
|
+
return {
|
|
59
|
+
result: directive.substituteResult,
|
|
60
|
+
cached: false,
|
|
61
|
+
durationMs: Date.now() - start,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
// "proceed" — fall through
|
|
65
|
+
}
|
|
66
|
+
else if (tool.requiresApproval) {
|
|
67
|
+
// requiresApproval is a contract, not decoration: with no approval hook
|
|
68
|
+
// configured the tool must not execute.
|
|
69
|
+
return {
|
|
70
|
+
result: {
|
|
71
|
+
tool: tool.name,
|
|
72
|
+
status: "failed",
|
|
73
|
+
error: `Tool "${tool.name}" requires approval but no onBeforeTool hook is configured`,
|
|
74
|
+
},
|
|
75
|
+
cached: false,
|
|
76
|
+
durationMs: Date.now() - start,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
// Step 3: Dedup check
|
|
24
80
|
const hash = hashToolCall(tool.name, params);
|
|
25
81
|
const dedupKey = toolDedupKey(opts.redisPrefix, meta.sessionId);
|
|
26
82
|
const cached = await checkDedup(opts.redis, dedupKey, hash);
|
|
27
83
|
if (cached) {
|
|
28
84
|
return { result: cached, cached: true, durationMs: Date.now() - start };
|
|
29
85
|
}
|
|
30
|
-
// Step
|
|
86
|
+
// Step 4: Execute
|
|
31
87
|
let result;
|
|
32
88
|
try {
|
|
33
89
|
result = await tool.execute(params, meta);
|
|
@@ -39,7 +95,7 @@ export async function executeTool(tool, params, meta, opts) {
|
|
|
39
95
|
error: err instanceof Error ? err.message : String(err),
|
|
40
96
|
};
|
|
41
97
|
}
|
|
42
|
-
// Step
|
|
98
|
+
// Step 5: Cache successful results only
|
|
43
99
|
if (result.status === "ok") {
|
|
44
100
|
await storeDedup(opts.redis, dedupKey, hash, result, opts.dedupTtlSeconds);
|
|
45
101
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"executor.js","sourceRoot":"","sources":["../../src/tools/executor.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"executor.js","sourceRoot":"","sources":["../../src/tools/executor.ts"],"names":[],"mappings":"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"}
|