skyloom 1.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/.github/workflows/ci.yml +36 -0
- package/CONVERSION_PLAN.md +191 -0
- package/README.md +67 -0
- package/dist/agents/dew.d.ts +15 -0
- package/dist/agents/dew.d.ts.map +1 -0
- package/dist/agents/dew.js +74 -0
- package/dist/agents/dew.js.map +1 -0
- package/dist/agents/fair.d.ts +15 -0
- package/dist/agents/fair.d.ts.map +1 -0
- package/dist/agents/fair.js +106 -0
- package/dist/agents/fair.js.map +1 -0
- package/dist/agents/fog.d.ts +15 -0
- package/dist/agents/fog.d.ts.map +1 -0
- package/dist/agents/fog.js +52 -0
- package/dist/agents/fog.js.map +1 -0
- package/dist/agents/frost.d.ts +15 -0
- package/dist/agents/frost.d.ts.map +1 -0
- package/dist/agents/frost.js +54 -0
- package/dist/agents/frost.js.map +1 -0
- package/dist/agents/rain.d.ts +15 -0
- package/dist/agents/rain.d.ts.map +1 -0
- package/dist/agents/rain.js +54 -0
- package/dist/agents/rain.js.map +1 -0
- package/dist/agents/snow.d.ts +27 -0
- package/dist/agents/snow.d.ts.map +1 -0
- package/dist/agents/snow.js +226 -0
- package/dist/agents/snow.js.map +1 -0
- package/dist/cli/main.d.ts +7 -0
- package/dist/cli/main.d.ts.map +1 -0
- package/dist/cli/main.js +402 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/mode.d.ts +17 -0
- package/dist/cli/mode.d.ts.map +1 -0
- package/dist/cli/mode.js +56 -0
- package/dist/cli/mode.js.map +1 -0
- package/dist/core/agent.d.ts +174 -0
- package/dist/core/agent.d.ts.map +1 -0
- package/dist/core/agent.js +1332 -0
- package/dist/core/agent.js.map +1 -0
- package/dist/core/agent_helpers.d.ts +51 -0
- package/dist/core/agent_helpers.d.ts.map +1 -0
- package/dist/core/agent_helpers.js +477 -0
- package/dist/core/agent_helpers.js.map +1 -0
- package/dist/core/bus.d.ts +99 -0
- package/dist/core/bus.d.ts.map +1 -0
- package/dist/core/bus.js +191 -0
- package/dist/core/bus.js.map +1 -0
- package/dist/core/cache.d.ts +63 -0
- package/dist/core/cache.d.ts.map +1 -0
- package/dist/core/cache.js +121 -0
- package/dist/core/cache.js.map +1 -0
- package/dist/core/checkpoint.d.ts +19 -0
- package/dist/core/checkpoint.d.ts.map +1 -0
- package/dist/core/checkpoint.js +120 -0
- package/dist/core/checkpoint.js.map +1 -0
- package/dist/core/circuit_breaker.d.ts +46 -0
- package/dist/core/circuit_breaker.d.ts.map +1 -0
- package/dist/core/circuit_breaker.js +99 -0
- package/dist/core/circuit_breaker.js.map +1 -0
- package/dist/core/config.d.ts +97 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +281 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/constants.d.ts +78 -0
- package/dist/core/constants.d.ts.map +1 -0
- package/dist/core/constants.js +84 -0
- package/dist/core/constants.js.map +1 -0
- package/dist/core/factory.d.ts +63 -0
- package/dist/core/factory.d.ts.map +1 -0
- package/dist/core/factory.js +537 -0
- package/dist/core/factory.js.map +1 -0
- package/dist/core/icons.d.ts +28 -0
- package/dist/core/icons.d.ts.map +1 -0
- package/dist/core/icons.js +86 -0
- package/dist/core/icons.js.map +1 -0
- package/dist/core/index.d.ts +29 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +54 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/llm.d.ts +121 -0
- package/dist/core/llm.d.ts.map +1 -0
- package/dist/core/llm.js +532 -0
- package/dist/core/llm.js.map +1 -0
- package/dist/core/logger.d.ts +57 -0
- package/dist/core/logger.d.ts.map +1 -0
- package/dist/core/logger.js +122 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/mcp.d.ts +190 -0
- package/dist/core/mcp.d.ts.map +1 -0
- package/dist/core/mcp.js +822 -0
- package/dist/core/mcp.js.map +1 -0
- package/dist/core/mcp_server.d.ts +26 -0
- package/dist/core/mcp_server.d.ts.map +1 -0
- package/dist/core/mcp_server.js +211 -0
- package/dist/core/mcp_server.js.map +1 -0
- package/dist/core/memory.d.ts +190 -0
- package/dist/core/memory.d.ts.map +1 -0
- package/dist/core/memory.js +988 -0
- package/dist/core/memory.js.map +1 -0
- package/dist/core/middleware.d.ts +114 -0
- package/dist/core/middleware.d.ts.map +1 -0
- package/dist/core/middleware.js +248 -0
- package/dist/core/middleware.js.map +1 -0
- package/dist/core/pipelines.d.ts +87 -0
- package/dist/core/pipelines.d.ts.map +1 -0
- package/dist/core/pipelines.js +301 -0
- package/dist/core/pipelines.js.map +1 -0
- package/dist/core/profile.d.ts +23 -0
- package/dist/core/profile.d.ts.map +1 -0
- package/dist/core/profile.js +289 -0
- package/dist/core/profile.js.map +1 -0
- package/dist/core/router.d.ts +24 -0
- package/dist/core/router.d.ts.map +1 -0
- package/dist/core/router.js +111 -0
- package/dist/core/router.js.map +1 -0
- package/dist/core/schemas.d.ts +82 -0
- package/dist/core/schemas.d.ts.map +1 -0
- package/dist/core/schemas.js +200 -0
- package/dist/core/schemas.js.map +1 -0
- package/dist/core/semantic.d.ts +92 -0
- package/dist/core/semantic.d.ts.map +1 -0
- package/dist/core/semantic.js +175 -0
- package/dist/core/semantic.js.map +1 -0
- package/dist/core/skill.d.ts +68 -0
- package/dist/core/skill.d.ts.map +1 -0
- package/dist/core/skill.js +350 -0
- package/dist/core/skill.js.map +1 -0
- package/dist/core/tool.d.ts +99 -0
- package/dist/core/tool.d.ts.map +1 -0
- package/dist/core/tool.js +341 -0
- package/dist/core/tool.js.map +1 -0
- package/dist/core/tool_router.d.ts +29 -0
- package/dist/core/tool_router.d.ts.map +1 -0
- package/dist/core/tool_router.js +172 -0
- package/dist/core/tool_router.js.map +1 -0
- package/dist/core/workspace.d.ts +48 -0
- package/dist/core/workspace.d.ts.map +1 -0
- package/dist/core/workspace.js +179 -0
- package/dist/core/workspace.js.map +1 -0
- package/dist/plugins/loader.d.ts +17 -0
- package/dist/plugins/loader.d.ts.map +1 -0
- package/dist/plugins/loader.js +96 -0
- package/dist/plugins/loader.js.map +1 -0
- package/dist/skills/loader.d.ts +9 -0
- package/dist/skills/loader.d.ts.map +1 -0
- package/dist/skills/loader.js +78 -0
- package/dist/skills/loader.js.map +1 -0
- package/dist/tools/builtin.d.ts +10 -0
- package/dist/tools/builtin.d.ts.map +1 -0
- package/dist/tools/builtin.js +414 -0
- package/dist/tools/builtin.js.map +1 -0
- package/dist/tools/computer.d.ts +12 -0
- package/dist/tools/computer.d.ts.map +1 -0
- package/dist/tools/computer.js +326 -0
- package/dist/tools/computer.js.map +1 -0
- package/dist/tools/delegate.d.ts +10 -0
- package/dist/tools/delegate.d.ts.map +1 -0
- package/dist/tools/delegate.js +45 -0
- package/dist/tools/delegate.js.map +1 -0
- package/dist/web/server.d.ts +5 -0
- package/dist/web/server.d.ts.map +1 -0
- package/dist/web/server.js +647 -0
- package/dist/web/server.js.map +1 -0
- package/dist/web/tts.d.ts +33 -0
- package/dist/web/tts.d.ts.map +1 -0
- package/dist/web/tts.js +69 -0
- package/dist/web/tts.js.map +1 -0
- package/package.json +60 -0
- package/scripts/install.js +48 -0
- package/scripts/link.js +10 -0
- package/setup.bat +79 -0
- package/skill-test-ty2fOA/test.md +10 -0
- package/src/agents/dew.ts +70 -0
- package/src/agents/fair.ts +102 -0
- package/src/agents/fog.ts +48 -0
- package/src/agents/frost.ts +50 -0
- package/src/agents/rain.ts +50 -0
- package/src/agents/snow.ts +239 -0
- package/src/cli/main.ts +405 -0
- package/src/cli/mode.ts +58 -0
- package/src/core/agent.ts +1506 -0
- package/src/core/agent_helpers.ts +461 -0
- package/src/core/bus.ts +221 -0
- package/src/core/cache.ts +153 -0
- package/src/core/checkpoint.ts +94 -0
- package/src/core/circuit_breaker.ts +119 -0
- package/src/core/config.ts +341 -0
- package/src/core/constants.ts +95 -0
- package/src/core/factory.ts +627 -0
- package/src/core/icons.ts +53 -0
- package/src/core/index.ts +31 -0
- package/src/core/llm.ts +724 -0
- package/src/core/logger.ts +144 -0
- package/src/core/mcp.ts +953 -0
- package/src/core/mcp_server.ts +176 -0
- package/src/core/memory.ts +1169 -0
- package/src/core/middleware.ts +350 -0
- package/src/core/pipelines.ts +424 -0
- package/src/core/profile.ts +255 -0
- package/src/core/router.ts +124 -0
- package/src/core/schemas.ts +282 -0
- package/src/core/semantic.ts +211 -0
- package/src/core/skill.ts +342 -0
- package/src/core/tool.ts +427 -0
- package/src/core/tool_router.ts +193 -0
- package/src/core/workspace.ts +150 -0
- package/src/plugins/loader.ts +66 -0
- package/src/skills/loader.ts +46 -0
- package/src/sql.js.d.ts +29 -0
- package/src/tools/builtin.ts +382 -0
- package/src/tools/computer.ts +269 -0
- package/src/tools/delegate.ts +49 -0
- package/src/web/server.ts +634 -0
- package/src/web/tts.ts +93 -0
- package/tests/bus.test.ts +121 -0
- package/tests/icons.test.ts +45 -0
- package/tests/router.test.ts +86 -0
- package/tests/schemas.test.ts +51 -0
- package/tests/semantic.test.ts +83 -0
- package/tests/setup.ts +10 -0
- package/tests/skill.test.ts +172 -0
- package/tests/tool.test.ts +108 -0
- package/tests/tool_router.test.ts +71 -0
- package/tsconfig.json +37 -0
- package/vitest.config.ts +17 -0
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Middleware/interceptor chain for tool execution.
|
|
3
|
+
*
|
|
4
|
+
* Provides ACL (access control), rate limiting, and audit logging
|
|
5
|
+
* as composable hooks around Tool.execute().
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { Event, EventType, MessageBus } from './bus';
|
|
9
|
+
import { getLogger } from './logger';
|
|
10
|
+
|
|
11
|
+
const logger = getLogger('middleware');
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Middleware protocol/interface for tool execution hooks.
|
|
15
|
+
*/
|
|
16
|
+
export interface Middleware {
|
|
17
|
+
/**
|
|
18
|
+
* Called before tool execution.
|
|
19
|
+
* @returns [allowed, reason] tuple
|
|
20
|
+
*/
|
|
21
|
+
pre(toolName: string, agentName: string | null, kwargs: Record<string, any>): Promise<[boolean, string | null]>;
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Called after tool execution (success or failure).
|
|
25
|
+
*/
|
|
26
|
+
post(
|
|
27
|
+
toolName: string,
|
|
28
|
+
agentName: string | null,
|
|
29
|
+
kwargs: Record<string, any>,
|
|
30
|
+
result: string,
|
|
31
|
+
success: boolean,
|
|
32
|
+
durationMs: number
|
|
33
|
+
): Promise<void>;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* ACL rule for per-agent tool access control.
|
|
38
|
+
*/
|
|
39
|
+
interface ACLRule {
|
|
40
|
+
allowedTools: Set<string>;
|
|
41
|
+
deniedTools: Set<string>;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Access-control list middleware.
|
|
46
|
+
*
|
|
47
|
+
* Controls which agents can call which tools. When `allowByDefault` is
|
|
48
|
+
* True (default), only explicitly denied tools are blocked; when False,
|
|
49
|
+
* only explicitly allowed tools are permitted.
|
|
50
|
+
*/
|
|
51
|
+
export class ACLMiddleware implements Middleware {
|
|
52
|
+
private allowByDefault: boolean;
|
|
53
|
+
private rules: Map<string, ACLRule> = new Map();
|
|
54
|
+
|
|
55
|
+
constructor(allowByDefault: boolean = true) {
|
|
56
|
+
this.allowByDefault = allowByDefault;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Explicitly allow an agent to call specific tools.
|
|
61
|
+
*/
|
|
62
|
+
allow(agentName: string, ...toolNames: string[]): void {
|
|
63
|
+
let rule = this.rules.get(agentName);
|
|
64
|
+
if (!rule) {
|
|
65
|
+
rule = { allowedTools: new Set(), deniedTools: new Set() };
|
|
66
|
+
this.rules.set(agentName, rule);
|
|
67
|
+
}
|
|
68
|
+
for (const t of toolNames) {
|
|
69
|
+
rule.allowedTools.add(t);
|
|
70
|
+
rule.deniedTools.delete(t);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Explicitly deny an agent from calling specific tools.
|
|
76
|
+
*/
|
|
77
|
+
deny(agentName: string, ...toolNames: string[]): void {
|
|
78
|
+
let rule = this.rules.get(agentName);
|
|
79
|
+
if (!rule) {
|
|
80
|
+
rule = { allowedTools: new Set(), deniedTools: new Set() };
|
|
81
|
+
this.rules.set(agentName, rule);
|
|
82
|
+
}
|
|
83
|
+
for (const t of toolNames) {
|
|
84
|
+
rule.deniedTools.add(t);
|
|
85
|
+
rule.allowedTools.delete(t);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* Remove all ACL rules for an agent.
|
|
91
|
+
*/
|
|
92
|
+
removeRules(agentName: string): void {
|
|
93
|
+
this.rules.delete(agentName);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
async pre(
|
|
97
|
+
toolName: string,
|
|
98
|
+
agentName: string | null,
|
|
99
|
+
_kwargs: Record<string, any>
|
|
100
|
+
): Promise<[boolean, string | null]> {
|
|
101
|
+
if (agentName === null) {
|
|
102
|
+
return this.allowByDefault ? [true, null] : [false, 'agent_name is required'];
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const rule = this.rules.get(agentName);
|
|
106
|
+
if (!rule) {
|
|
107
|
+
return this.allowByDefault ? [true, null] : [false, `agent '${agentName}' has no ACL rules`];
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (rule.deniedTools.has(toolName)) {
|
|
111
|
+
return [false, `agent '${agentName}' is not allowed to call '${toolName}'`];
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
if (!this.allowByDefault && !rule.allowedTools.has(toolName)) {
|
|
115
|
+
return [false, `agent '${agentName}' is not allowed to call '${toolName}'`];
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
return [true, null];
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async post(
|
|
122
|
+
_toolName: string,
|
|
123
|
+
_agentName: string | null,
|
|
124
|
+
_kwargs: Record<string, any>,
|
|
125
|
+
_result: string,
|
|
126
|
+
_success: boolean,
|
|
127
|
+
_durationMs: number
|
|
128
|
+
): Promise<void> {
|
|
129
|
+
// No-op
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Sliding-window rate limiter per tool.
|
|
135
|
+
*
|
|
136
|
+
* Limits the number of calls to each tool within a rolling time window.
|
|
137
|
+
* Per-tool overrides can be set via `setLimit()`.
|
|
138
|
+
*/
|
|
139
|
+
export class RateLimitMiddleware implements Middleware {
|
|
140
|
+
private defaultMaxCalls: number;
|
|
141
|
+
private defaultWindow: number;
|
|
142
|
+
private calls: Map<string, number[]> = new Map();
|
|
143
|
+
private overrides: Map<string, [number, number]> = new Map();
|
|
144
|
+
|
|
145
|
+
constructor(maxCalls: number = 30, windowSeconds: number = 60.0) {
|
|
146
|
+
this.defaultMaxCalls = maxCalls;
|
|
147
|
+
this.defaultWindow = windowSeconds;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Set a per-tool rate limit override.
|
|
152
|
+
*/
|
|
153
|
+
setLimit(toolName: string, maxCalls: number, windowSeconds: number): void {
|
|
154
|
+
this.overrides.set(toolName, [maxCalls, windowSeconds]);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Clear all recorded calls and overrides.
|
|
159
|
+
*/
|
|
160
|
+
clear(): void {
|
|
161
|
+
this.calls.clear();
|
|
162
|
+
this.overrides.clear();
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
async pre(
|
|
166
|
+
toolName: string,
|
|
167
|
+
_agentName: string | null,
|
|
168
|
+
_kwargs: Record<string, any>
|
|
169
|
+
): Promise<[boolean, string | null]> {
|
|
170
|
+
const [maxCalls, window] = this.overrides.get(toolName) || [
|
|
171
|
+
this.defaultMaxCalls,
|
|
172
|
+
this.defaultWindow,
|
|
173
|
+
];
|
|
174
|
+
|
|
175
|
+
const now = performance.now() / 1000; // Convert to seconds
|
|
176
|
+
const cutoff = now - window;
|
|
177
|
+
|
|
178
|
+
let calls = this.calls.get(toolName) || [];
|
|
179
|
+
calls = calls.filter(t => t > cutoff);
|
|
180
|
+
|
|
181
|
+
if (calls.length > 0) {
|
|
182
|
+
this.calls.set(toolName, calls);
|
|
183
|
+
} else {
|
|
184
|
+
this.calls.delete(toolName);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
if (calls.length >= maxCalls) {
|
|
188
|
+
const remaining = Math.ceil(calls[0] + window - now);
|
|
189
|
+
return [
|
|
190
|
+
false,
|
|
191
|
+
`rate limit exceeded for '${toolName}': ${maxCalls} calls per ${window}s window (retry in ~${remaining}s)`,
|
|
192
|
+
];
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
calls.push(now);
|
|
196
|
+
this.calls.set(toolName, calls);
|
|
197
|
+
return [true, null];
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
async post(
|
|
201
|
+
_toolName: string,
|
|
202
|
+
_agentName: string | null,
|
|
203
|
+
_kwargs: Record<string, any>,
|
|
204
|
+
_result: string,
|
|
205
|
+
_success: boolean,
|
|
206
|
+
_durationMs: number
|
|
207
|
+
): Promise<void> {
|
|
208
|
+
// No-op
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Audit-logging middleware.
|
|
214
|
+
*
|
|
215
|
+
* Publishes tool-call events to the message bus with timing,
|
|
216
|
+
* agent identity, success/failure, and truncated result preview.
|
|
217
|
+
*/
|
|
218
|
+
export class AuditMiddleware implements Middleware {
|
|
219
|
+
private bus: MessageBus | null;
|
|
220
|
+
|
|
221
|
+
constructor(bus?: MessageBus | null) {
|
|
222
|
+
this.bus = bus || null;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
async pre(
|
|
226
|
+
_toolName: string,
|
|
227
|
+
_agentName: string | null,
|
|
228
|
+
_kwargs: Record<string, any>
|
|
229
|
+
): Promise<[boolean, string | null]> {
|
|
230
|
+
return [true, null];
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
async post(
|
|
234
|
+
toolName: string,
|
|
235
|
+
agentName: string | null,
|
|
236
|
+
kwargs: Record<string, any>,
|
|
237
|
+
result: string,
|
|
238
|
+
success: boolean,
|
|
239
|
+
durationMs: number
|
|
240
|
+
): Promise<void> {
|
|
241
|
+
if (!this.bus) {
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
// Truncate args and result for safety
|
|
246
|
+
const safeArgs: Record<string, any> = {};
|
|
247
|
+
for (const [k, v] of Object.entries(kwargs)) {
|
|
248
|
+
if (typeof v === 'string') {
|
|
249
|
+
safeArgs[k] = v.slice(0, 200);
|
|
250
|
+
} else if (typeof v === 'number' || typeof v === 'boolean') {
|
|
251
|
+
safeArgs[k] = v;
|
|
252
|
+
} else {
|
|
253
|
+
safeArgs[k] = String(v).slice(0, 200);
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
const safeResult = (result || '').slice(0, 500);
|
|
258
|
+
|
|
259
|
+
try {
|
|
260
|
+
this.bus.addEvent(
|
|
261
|
+
new Event(EventType.TOOL_CALL, agentName || 'unknown', null, {
|
|
262
|
+
tool: toolName,
|
|
263
|
+
args: safeArgs,
|
|
264
|
+
success,
|
|
265
|
+
duration_ms: Math.round(durationMs * 10) / 10,
|
|
266
|
+
result_preview: safeResult,
|
|
267
|
+
})
|
|
268
|
+
);
|
|
269
|
+
} catch (err) {
|
|
270
|
+
logger.warn('audit_log_failed', { tool: toolName, error: String(err) });
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Chain of middleware hooks applied around tool execution.
|
|
277
|
+
*
|
|
278
|
+
* Pre-hooks run in registration order; if any returns `[False, reason]`
|
|
279
|
+
* the chain short-circuits and the tool is denied.
|
|
280
|
+
* Post-hooks always run on success *or* failure.
|
|
281
|
+
*/
|
|
282
|
+
export class MiddlewareChain {
|
|
283
|
+
private middlewares: Middleware[] = [];
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Register a middleware instance.
|
|
287
|
+
* Pre-hooks run in add() order.
|
|
288
|
+
*/
|
|
289
|
+
add(middleware: Middleware): void {
|
|
290
|
+
this.middlewares.push(middleware);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
/**
|
|
294
|
+
* Run all pre-hooks in order.
|
|
295
|
+
*/
|
|
296
|
+
async runPre(
|
|
297
|
+
toolName: string,
|
|
298
|
+
agentName: string | null,
|
|
299
|
+
kwargs: Record<string, any>
|
|
300
|
+
): Promise<[boolean, string | null]> {
|
|
301
|
+
for (const mw of this.middlewares) {
|
|
302
|
+
const [allowed, reason] = await mw.pre(toolName, agentName, kwargs);
|
|
303
|
+
if (!allowed) {
|
|
304
|
+
return [false, reason];
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
return [true, null];
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
/**
|
|
311
|
+
* Run all post-hooks.
|
|
312
|
+
*/
|
|
313
|
+
async runPost(
|
|
314
|
+
toolName: string,
|
|
315
|
+
agentName: string | null,
|
|
316
|
+
kwargs: Record<string, any>,
|
|
317
|
+
result: string,
|
|
318
|
+
success: boolean,
|
|
319
|
+
durationMs: number
|
|
320
|
+
): Promise<void> {
|
|
321
|
+
for (const mw of this.middlewares) {
|
|
322
|
+
try {
|
|
323
|
+
await mw.post(toolName, agentName, kwargs, result, success, durationMs);
|
|
324
|
+
} catch (err) {
|
|
325
|
+
logger.warn('middleware_post_failed', {
|
|
326
|
+
middleware: mw.constructor.name,
|
|
327
|
+
tool: toolName,
|
|
328
|
+
error: String(err),
|
|
329
|
+
});
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
// Global middleware chain
|
|
336
|
+
let globalChain: MiddlewareChain | null = null;
|
|
337
|
+
|
|
338
|
+
/**
|
|
339
|
+
* Set the global middleware chain used by Tool.execute().
|
|
340
|
+
*/
|
|
341
|
+
export function setMiddlewareChain(chain: MiddlewareChain | null): void {
|
|
342
|
+
globalChain = chain;
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Get the global middleware chain, or null.
|
|
347
|
+
*/
|
|
348
|
+
export function getMiddlewareChain(): MiddlewareChain | null {
|
|
349
|
+
return globalChain;
|
|
350
|
+
}
|