@adhd/agent-plugin-budget 0.1.0 → 0.2.1
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 +32 -0
- package/README.md +5 -1
- package/index.cjs +14 -11
- package/index.d.ts +73 -24
- package/index.js +498 -262
- package/package.json +20 -2
package/index.js
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
|
-
import { z as
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
import { z as u } from "zod";
|
|
2
|
+
import { contextWindowFor as S } from "@adhd/agent-base-types";
|
|
3
|
+
function E(c) {
|
|
4
|
+
const t = /^P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+(?:\.\d+)?)S)?)?$/, e = c.match(t);
|
|
5
|
+
if (!e)
|
|
6
|
+
throw new Error(`invalid ISO 8601 duration: ${c}`);
|
|
7
|
+
const [, o, s, n, i, r, a] = e;
|
|
8
|
+
let l = 0;
|
|
9
|
+
return o && (l += parseInt(o) * 365.25 * 864e5), s && (l += parseInt(s) * 30.44 * 864e5), n && (l += parseInt(n) * 864e5), i && (l += parseInt(i) * 36e5), r && (l += parseInt(r) * 6e4), a && (l += parseFloat(a) * 1e3), Math.round(l);
|
|
9
10
|
}
|
|
10
|
-
const
|
|
11
|
-
"
|
|
11
|
+
const M = [
|
|
12
|
+
"context",
|
|
12
13
|
"inputTokens",
|
|
13
14
|
"outputTokens",
|
|
14
15
|
"calls",
|
|
@@ -16,268 +17,417 @@ const E = [
|
|
|
16
17
|
"modelMs",
|
|
17
18
|
"cost",
|
|
18
19
|
"toolCalls",
|
|
20
|
+
"errors",
|
|
21
|
+
"consecutiveErrors",
|
|
19
22
|
"responseSize"
|
|
20
|
-
],
|
|
21
|
-
field:
|
|
22
|
-
maximum:
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
23
|
+
], b = /* @__PURE__ */ new Set(["toolCalls", "errors", "consecutiveErrors"]), y = u.object({
|
|
24
|
+
field: u.enum(M),
|
|
25
|
+
maximum: u.number().min(0).optional(),
|
|
26
|
+
contextWindowFraction: u.number().min(0).max(1).optional(),
|
|
27
|
+
window: u.string().optional(),
|
|
28
|
+
scope: u.enum(["task", "session", "agent", "global"]).optional(),
|
|
29
|
+
mode: u.enum(["warning", "block"]).optional(),
|
|
30
|
+
message: u.string().optional()
|
|
31
|
+
}).superRefine((c, t) => {
|
|
32
|
+
if (c.field === "context") {
|
|
33
|
+
const e = c.maximum !== void 0, o = c.contextWindowFraction !== void 0;
|
|
34
|
+
e === o && t.addIssue({
|
|
35
|
+
code: u.ZodIssueCode.custom,
|
|
36
|
+
path: ["contextWindowFraction"],
|
|
37
|
+
message: "cap field 'context' requires exactly one of 'maximum' or 'contextWindowFraction'"
|
|
38
|
+
}), c.window !== void 0 && t.addIssue({
|
|
39
|
+
code: u.ZodIssueCode.custom,
|
|
40
|
+
path: ["window"],
|
|
41
|
+
message: "cap field 'context' rejects 'window' — a windowed peak is meaningless; windowed cumulative volume is expressible via 'inputTokens'/'outputTokens' + 'window'"
|
|
42
|
+
});
|
|
43
|
+
} else
|
|
44
|
+
(c.field === "errors" || c.field === "consecutiveErrors") && (c.window !== void 0 && t.addIssue({
|
|
45
|
+
code: u.ZodIssueCode.custom,
|
|
46
|
+
path: ["window"],
|
|
47
|
+
message: `cap field '${c.field}' rejects 'window' — windowed error budgets are not expressible this wave`
|
|
48
|
+
}), c.scope !== void 0 && c.scope !== "task" && t.addIssue({
|
|
49
|
+
code: u.ZodIssueCode.custom,
|
|
50
|
+
path: ["scope"],
|
|
51
|
+
message: `cap field '${c.field}' is counted per-task in memory (no task_usage column) — only 'task' scope is expressible this wave`
|
|
52
|
+
})), c.window !== void 0 && (c.scope === void 0 || c.scope === "task") && t.addIssue({
|
|
53
|
+
code: u.ZodIssueCode.custom,
|
|
54
|
+
path: ["scope"],
|
|
55
|
+
message: `cap field '${c.field}' carries 'window' but resolves to 'task' scope, where windowed caps are a silent no-op (no task-level window query); set an explicit 'scope': 'session' | 'agent' | 'global'`
|
|
56
|
+
}), c.contextWindowFraction !== void 0 && t.addIssue({
|
|
57
|
+
code: u.ZodIssueCode.custom,
|
|
58
|
+
path: ["contextWindowFraction"],
|
|
59
|
+
message: `'contextWindowFraction' is only valid on cap field 'context' (got '${c.field}')`
|
|
60
|
+
}), c.maximum === void 0 && t.addIssue({
|
|
61
|
+
code: u.ZodIssueCode.custom,
|
|
62
|
+
path: ["maximum"],
|
|
63
|
+
message: `cap field '${c.field}' requires a 'maximum'`
|
|
64
|
+
});
|
|
65
|
+
}), g = u.object({
|
|
66
|
+
caps: u.array(y).optional(),
|
|
67
|
+
mode: u.enum(["warning", "block"]).optional(),
|
|
68
|
+
costPerInputToken: u.number().min(0).optional(),
|
|
69
|
+
costPerOutputToken: u.number().min(0).optional(),
|
|
70
|
+
// Cache-weighted cost rates (BUG-AGENTMCP-008). Default = costPerInputToken when
|
|
71
|
+
// unset, so a config without them bills every input token at the flat input rate —
|
|
72
|
+
// byte-for-byte identical to the pre-fix behavior.
|
|
73
|
+
costPerCacheReadToken: u.number().min(0).optional(),
|
|
74
|
+
costPerCacheWriteToken: u.number().min(0).optional(),
|
|
75
|
+
scope: u.enum(["task", "session", "agent", "global"]).optional()
|
|
76
|
+
}), x = g.partial().superRefine((c, t) => {
|
|
77
|
+
const e = c.caps ?? [];
|
|
78
|
+
for (const [o, s] of e.entries())
|
|
79
|
+
s.field === "context" && t.addIssue({
|
|
80
|
+
code: u.ZodIssueCode.custom,
|
|
81
|
+
path: ["caps", o, "field"],
|
|
82
|
+
message: "cap field 'context' is only valid at model scope — a tool-scoped 'context' cap is a silent no-op (enforced on the model path, invisible to tool overrides); place it in 'defaults'/'agent'/'provider' instead"
|
|
83
|
+
});
|
|
84
|
+
}), _ = u.object({
|
|
34
85
|
defaults: g.optional(),
|
|
35
|
-
agent:
|
|
86
|
+
agent: u.object({
|
|
36
87
|
default: g.optional(),
|
|
37
|
-
overrides:
|
|
88
|
+
overrides: u.record(u.string(), g.partial()).optional().default({})
|
|
38
89
|
}).optional(),
|
|
39
|
-
provider:
|
|
90
|
+
provider: u.object({
|
|
40
91
|
default: g.optional(),
|
|
41
|
-
overrides:
|
|
92
|
+
overrides: u.record(u.string(), g.partial()).optional().default({})
|
|
42
93
|
}).optional(),
|
|
43
|
-
tool:
|
|
44
|
-
default:
|
|
45
|
-
overrides:
|
|
94
|
+
tool: u.object({
|
|
95
|
+
default: x.optional(),
|
|
96
|
+
overrides: u.record(u.string(), x).optional().default({})
|
|
46
97
|
}).optional()
|
|
47
|
-
}),
|
|
98
|
+
}), N = u.object({}).passthrough(), A = {
|
|
48
99
|
maxInputTokens: { field: "inputTokens" },
|
|
49
100
|
maxOutputTokens: { field: "outputTokens" },
|
|
50
|
-
maxTotalTokens: { field: "tokens" },
|
|
51
101
|
maxModelCalls: { field: "calls" },
|
|
52
102
|
maxWallClockMs: { field: "wallClock" },
|
|
53
103
|
maxModelMs: { field: "modelMs" },
|
|
54
104
|
maxCostUSD: { field: "cost" },
|
|
55
|
-
maxTokensPer24h: { field: "
|
|
105
|
+
maxTokensPer24h: { field: "inputTokens", window: "PT24H" },
|
|
56
106
|
maxCalls: { field: "toolCalls" }
|
|
57
107
|
};
|
|
58
|
-
function
|
|
59
|
-
const
|
|
60
|
-
for (const [
|
|
61
|
-
const
|
|
62
|
-
if (
|
|
63
|
-
const
|
|
64
|
-
|
|
108
|
+
function O(c) {
|
|
109
|
+
const t = [], e = {};
|
|
110
|
+
for (const [n, i] of Object.entries(c)) {
|
|
111
|
+
const r = A[n];
|
|
112
|
+
if (r && typeof i == "number") {
|
|
113
|
+
const a = { field: r.field, maximum: i };
|
|
114
|
+
r.window && (a.window = r.window), t.push(a);
|
|
65
115
|
} else
|
|
66
|
-
(
|
|
116
|
+
(n === "scope" || n === "mode" || n === "costPerInputToken" || n === "costPerOutputToken" || n === "costPerCacheReadToken" || n === "costPerCacheWriteToken" || n === "message") && (e[n] = i);
|
|
67
117
|
}
|
|
68
|
-
|
|
118
|
+
t.length > 0 && (e.caps = t);
|
|
119
|
+
const o = e.scope, s = o === "task" || o === "session" || o === "agent" || o === "global" ? o : void 0;
|
|
120
|
+
for (const n of t)
|
|
121
|
+
n.window !== void 0 && n.scope === void 0 && (n.scope = s ?? "global");
|
|
122
|
+
return g.parse(e);
|
|
69
123
|
}
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
124
|
+
const w = (c) => `legacy 'tokens' budget cap detected (${c}): cap field 'tokens' is removed; use 'context' (peak request input) or 'inputTokens'/'outputTokens' (windowed volume)`;
|
|
125
|
+
function P(c) {
|
|
126
|
+
const t = c ?? {};
|
|
127
|
+
if (typeof t.maxTotalTokens == "number")
|
|
128
|
+
throw new Error(w("flat 'maxTotalTokens'"));
|
|
129
|
+
const e = (s) => {
|
|
130
|
+
if (typeof s != "object" || s === null)
|
|
131
|
+
return;
|
|
132
|
+
const n = s;
|
|
133
|
+
if (typeof n.maxTotalTokens == "number")
|
|
134
|
+
throw new Error(w("structured 'maxTotalTokens'"));
|
|
135
|
+
const i = n.caps;
|
|
136
|
+
if (Array.isArray(i)) {
|
|
137
|
+
for (const r of i)
|
|
138
|
+
if (typeof r == "object" && r !== null && r.field === "tokens")
|
|
139
|
+
throw new Error(w("caps[].field === 'tokens'"));
|
|
140
|
+
}
|
|
141
|
+
}, o = (s) => {
|
|
142
|
+
if (typeof s != "object" || s === null)
|
|
143
|
+
return;
|
|
144
|
+
const n = s;
|
|
145
|
+
e(n), "default" in n && e(n.default);
|
|
146
|
+
const i = n.overrides;
|
|
147
|
+
if (typeof i == "object" && i !== null)
|
|
148
|
+
for (const r of Object.values(i))
|
|
149
|
+
e(r);
|
|
150
|
+
};
|
|
151
|
+
e(t.defaults), o(t.agent), o(t.provider), o(t.tool);
|
|
152
|
+
}
|
|
153
|
+
function I(c) {
|
|
154
|
+
P(c);
|
|
155
|
+
const t = c;
|
|
156
|
+
if (t.defaults !== void 0 || t.agent !== void 0 || t.provider !== void 0 || t.tool !== void 0) {
|
|
157
|
+
const e = _.parse(c);
|
|
74
158
|
return {
|
|
75
|
-
defaults:
|
|
76
|
-
agent:
|
|
77
|
-
provider:
|
|
78
|
-
tool:
|
|
159
|
+
defaults: e.defaults ?? g.parse({}),
|
|
160
|
+
agent: e.agent ?? { overrides: {} },
|
|
161
|
+
provider: e.provider ?? { overrides: {} },
|
|
162
|
+
tool: e.tool ?? { overrides: {} }
|
|
79
163
|
};
|
|
80
164
|
}
|
|
81
165
|
return {
|
|
82
|
-
defaults:
|
|
166
|
+
defaults: O(t),
|
|
83
167
|
agent: { overrides: {} },
|
|
84
168
|
provider: { overrides: {} },
|
|
85
169
|
tool: { overrides: {} }
|
|
86
170
|
};
|
|
87
171
|
}
|
|
88
|
-
function
|
|
172
|
+
function v(c, t, e, o) {
|
|
89
173
|
return {
|
|
90
174
|
isEnforcementError: !0,
|
|
91
175
|
code: "BUDGET_EXCEEDED",
|
|
92
|
-
message: o ?? `${
|
|
176
|
+
message: o ?? `${c} limit is ${t}, current value is ${Math.round(e)}`
|
|
93
177
|
};
|
|
94
178
|
}
|
|
95
|
-
function
|
|
96
|
-
return { isToolWarning: !0, toolName:
|
|
179
|
+
function $(c, t, e) {
|
|
180
|
+
return { isToolWarning: !0, toolName: c, callId: t, message: e };
|
|
181
|
+
}
|
|
182
|
+
function R(c, t) {
|
|
183
|
+
var o;
|
|
184
|
+
let e = 0;
|
|
185
|
+
for (const s of c) {
|
|
186
|
+
e += ((o = s.content) == null ? void 0 : o.length) ?? 0;
|
|
187
|
+
for (const n of s.toolCalls ?? [])
|
|
188
|
+
e += JSON.stringify(n.arguments ?? {}).length;
|
|
189
|
+
for (const n of s.toolResults ?? [])
|
|
190
|
+
e += JSON.stringify(n.result ?? null).length;
|
|
191
|
+
}
|
|
192
|
+
for (const s of t)
|
|
193
|
+
e += JSON.stringify({
|
|
194
|
+
name: s.name,
|
|
195
|
+
description: s.description,
|
|
196
|
+
inputSchema: s.inputSchema
|
|
197
|
+
}).length;
|
|
198
|
+
return Math.ceil(e / 4);
|
|
97
199
|
}
|
|
98
|
-
class
|
|
99
|
-
constructor(
|
|
100
|
-
this.db =
|
|
200
|
+
class L {
|
|
201
|
+
constructor(t, e, o = 0, s = 0, n = 0, i = 0) {
|
|
202
|
+
this.db = t, this.cfg = e, this.costPerInput = o, this.costPerOutput = s, this.costPerCacheRead = n, this.costPerCacheWrite = i, this.name = "agent-mcp-budget", this.accumulators = /* @__PURE__ */ new Map();
|
|
101
203
|
}
|
|
102
|
-
install(
|
|
103
|
-
|
|
204
|
+
install(t) {
|
|
205
|
+
this.hooks = t, t.register("task:start", (e) => {
|
|
206
|
+
try {
|
|
207
|
+
this.onTaskStart(e);
|
|
208
|
+
} catch {
|
|
209
|
+
}
|
|
210
|
+
}), t.register("pre:model_request", (e) => {
|
|
104
211
|
try {
|
|
105
|
-
this.
|
|
212
|
+
this.onPreModelRequest(e);
|
|
106
213
|
} catch {
|
|
107
214
|
}
|
|
108
|
-
}),
|
|
215
|
+
}), t.register("post:model_response", (e) => {
|
|
109
216
|
try {
|
|
110
|
-
this.
|
|
217
|
+
this.onPostModelResponse(e);
|
|
111
218
|
} catch {
|
|
112
219
|
}
|
|
113
|
-
}),
|
|
220
|
+
}), t.register("post:tool_call", (e) => {
|
|
114
221
|
try {
|
|
115
|
-
this.
|
|
222
|
+
this.onPostToolCall(e);
|
|
116
223
|
} catch {
|
|
117
224
|
}
|
|
118
|
-
}),
|
|
225
|
+
}), t.register("task:completed", (e) => {
|
|
119
226
|
try {
|
|
120
|
-
this.onTerminal(
|
|
227
|
+
this.onTerminal(e.executionContext.taskId);
|
|
121
228
|
} catch {
|
|
122
229
|
}
|
|
123
|
-
}),
|
|
230
|
+
}), t.register("task:failed", (e) => {
|
|
124
231
|
try {
|
|
125
|
-
this.onTerminal(
|
|
232
|
+
this.onTerminal(e.executionContext.taskId);
|
|
126
233
|
} catch {
|
|
127
234
|
}
|
|
128
|
-
}),
|
|
235
|
+
}), t.register("task:cancelled", (e) => {
|
|
129
236
|
try {
|
|
130
|
-
this.onTerminal(
|
|
237
|
+
this.onTerminal(e.executionContext.taskId);
|
|
131
238
|
} catch {
|
|
132
239
|
}
|
|
133
|
-
}),
|
|
240
|
+
}), t.registerEnforcement(
|
|
134
241
|
"pre:model_request",
|
|
135
|
-
(
|
|
136
|
-
),
|
|
242
|
+
(e) => this.enforcePreModel(e)
|
|
243
|
+
), t.registerEnforcement("pre:tool_call", (e) => this.enforcePreTool(e)), t.register("transform:tool_result", (e) => {
|
|
137
244
|
try {
|
|
138
|
-
this.enforceResponseSize(
|
|
245
|
+
this.enforceResponseSize(e);
|
|
139
246
|
} catch {
|
|
140
247
|
}
|
|
141
248
|
});
|
|
142
249
|
}
|
|
143
250
|
// ── Observational handlers ────────────────────────────────────────────────
|
|
144
|
-
onTaskStart(
|
|
145
|
-
var
|
|
146
|
-
const { taskId:
|
|
147
|
-
this.accumulators.set(
|
|
148
|
-
taskId:
|
|
251
|
+
onTaskStart(t) {
|
|
252
|
+
var i, r;
|
|
253
|
+
const { taskId: e, sessionId: o, agentName: s } = t.executionContext, n = ((r = (i = t.executionContext.agentDefinition) == null ? void 0 : i.provider) == null ? void 0 : r.type) ?? "unknown";
|
|
254
|
+
this.accumulators.set(e, {
|
|
255
|
+
taskId: e,
|
|
149
256
|
sessionId: o ?? void 0,
|
|
150
257
|
agentName: s,
|
|
151
|
-
providerType:
|
|
258
|
+
providerType: n,
|
|
152
259
|
startedAtMs: Date.now(),
|
|
260
|
+
uncachedInputTokens: 0,
|
|
261
|
+
cacheReadTokens: 0,
|
|
262
|
+
cacheCreationTokens: 0,
|
|
153
263
|
inputTokens: 0,
|
|
154
264
|
outputTokens: 0,
|
|
265
|
+
peakContextTokens: 0,
|
|
155
266
|
modelCalls: 0,
|
|
156
267
|
totalModelMs: 0,
|
|
157
|
-
toolCalls: /* @__PURE__ */ new Map()
|
|
268
|
+
toolCalls: /* @__PURE__ */ new Map(),
|
|
269
|
+
errors: 0,
|
|
270
|
+
consecutiveErrors: 0
|
|
158
271
|
});
|
|
159
272
|
}
|
|
160
|
-
onPreModelRequest(
|
|
161
|
-
const
|
|
162
|
-
|
|
273
|
+
onPreModelRequest(t) {
|
|
274
|
+
const e = this.accumulators.get(t.executionContext.taskId);
|
|
275
|
+
e && (e.modelCallStartMs = Date.now());
|
|
163
276
|
}
|
|
164
|
-
onPostModelResponse(
|
|
165
|
-
const
|
|
166
|
-
if (!
|
|
277
|
+
onPostModelResponse(t) {
|
|
278
|
+
const e = this.accumulators.get(t.executionContext.taskId);
|
|
279
|
+
if (!e)
|
|
167
280
|
return;
|
|
168
|
-
const o =
|
|
169
|
-
|
|
281
|
+
const o = t.tokenUsage;
|
|
282
|
+
if (o) {
|
|
283
|
+
const s = o.inputTokens ?? 0, n = o.cacheReadTokens ?? 0, i = o.cacheCreationTokens ?? 0, a = o.uncachedInputTokens !== void 0 || o.cacheReadTokens !== void 0 || o.cacheCreationTokens !== void 0 ? o.uncachedInputTokens ?? Math.max(0, s - n - i) : s;
|
|
284
|
+
e.uncachedInputTokens += a, e.cacheReadTokens += n, e.cacheCreationTokens += i, e.inputTokens += a + n + i, e.outputTokens += o.outputTokens ?? 0, e.peakContextTokens = Math.max(e.peakContextTokens, s);
|
|
285
|
+
}
|
|
286
|
+
e.modelCalls += 1, e.modelCallStartMs !== void 0 && (e.totalModelMs += Date.now() - e.modelCallStartMs, e.modelCallStartMs = void 0);
|
|
287
|
+
}
|
|
288
|
+
onTerminal(t) {
|
|
289
|
+
this.accumulators.delete(t);
|
|
170
290
|
}
|
|
171
|
-
|
|
172
|
-
|
|
291
|
+
/**
|
|
292
|
+
* Packet C — error counters (plan §3): the ONLY place the error budget
|
|
293
|
+
* changes. Fires at post:tool_call, which the orchestrator emits exclusively
|
|
294
|
+
* for EXECUTED tools (orchestrator.ts Phase 2 map, post:tool_call emit). A
|
|
295
|
+
* call soft-blocked by an IToolWarning at pre:tool_call is injected as a
|
|
296
|
+
* warningResult and SKIPPED (orchestrator.ts:619-626, filter at 645-647) —
|
|
297
|
+
* it never reaches Phase 2 and never emits post:tool_call. That is the
|
|
298
|
+
* non-self-amplifying guarantee: a warning-mode errors cap's own warnings are
|
|
299
|
+
* never counted, so the counter cannot feed itself.
|
|
300
|
+
*
|
|
301
|
+
* Thrown-errors-only (owner lean, plan §3): `isError` is true at this
|
|
302
|
+
* boundary only when the tool's callTool THREW (orchestrator.ts:718);
|
|
303
|
+
* error-shaped non-throwing results are indistinguishable from success here.
|
|
304
|
+
*/
|
|
305
|
+
onPostToolCall(t) {
|
|
306
|
+
const e = this.accumulators.get(t.executionContext.taskId);
|
|
307
|
+
e && (t.isError ? (e.errors += 1, e.consecutiveErrors += 1) : e.consecutiveErrors = 0);
|
|
173
308
|
}
|
|
174
309
|
// ── Config resolution ─────────────────────────────────────────────────────
|
|
175
|
-
mergeDim(
|
|
176
|
-
let
|
|
177
|
-
for (const o of
|
|
178
|
-
o && (
|
|
179
|
-
caps: [...
|
|
180
|
-
mode: o.mode ??
|
|
181
|
-
costPerInputToken: o.costPerInputToken ??
|
|
182
|
-
costPerOutputToken: o.costPerOutputToken ??
|
|
183
|
-
|
|
310
|
+
mergeDim(t) {
|
|
311
|
+
let e = { caps: [] };
|
|
312
|
+
for (const o of t)
|
|
313
|
+
o && (e = {
|
|
314
|
+
caps: [...e.caps ?? [], ...o.caps ?? []],
|
|
315
|
+
mode: o.mode ?? e.mode,
|
|
316
|
+
costPerInputToken: o.costPerInputToken ?? e.costPerInputToken,
|
|
317
|
+
costPerOutputToken: o.costPerOutputToken ?? e.costPerOutputToken,
|
|
318
|
+
costPerCacheReadToken: o.costPerCacheReadToken ?? e.costPerCacheReadToken,
|
|
319
|
+
costPerCacheWriteToken: o.costPerCacheWriteToken ?? e.costPerCacheWriteToken,
|
|
320
|
+
scope: o.scope ?? e.scope
|
|
184
321
|
});
|
|
185
|
-
return
|
|
322
|
+
return e;
|
|
186
323
|
}
|
|
187
|
-
resolveCaps(
|
|
188
|
-
var
|
|
189
|
-
const s = this.cfg.defaults,
|
|
324
|
+
resolveCaps(t, e, o) {
|
|
325
|
+
var f, d, k;
|
|
326
|
+
const s = this.cfg.defaults, n = this.cfg.agent, i = this.cfg.provider, r = this.cfg.tool;
|
|
190
327
|
if (o) {
|
|
191
|
-
const
|
|
328
|
+
const m = (f = r == null ? void 0 : r.overrides) == null ? void 0 : f[o], h = this.mergeDim([s, r == null ? void 0 : r.default, m]);
|
|
192
329
|
return {
|
|
193
330
|
caps: h.caps ?? [],
|
|
194
331
|
mode: h.mode,
|
|
195
332
|
scope: h.scope
|
|
196
333
|
};
|
|
197
334
|
}
|
|
198
|
-
const
|
|
335
|
+
const a = (d = n == null ? void 0 : n.overrides) == null ? void 0 : d[t], l = (k = i == null ? void 0 : i.overrides) == null ? void 0 : k[e], p = this.mergeDim([
|
|
199
336
|
s,
|
|
200
|
-
a == null ? void 0 : a.default,
|
|
201
|
-
c,
|
|
202
337
|
n == null ? void 0 : n.default,
|
|
203
|
-
|
|
338
|
+
a,
|
|
339
|
+
i == null ? void 0 : i.default,
|
|
340
|
+
l
|
|
204
341
|
]);
|
|
205
|
-
return { caps:
|
|
342
|
+
return { caps: p.caps ?? [], mode: p.mode, scope: p.scope };
|
|
206
343
|
}
|
|
207
344
|
// ── Scope-aware DB queries ────────────────────────────────────────────────
|
|
208
|
-
queryScopeTotals(
|
|
209
|
-
const
|
|
210
|
-
inputTokens:
|
|
211
|
-
outputTokens:
|
|
212
|
-
modelCalls:
|
|
213
|
-
|
|
345
|
+
queryScopeTotals(t, e, o, s) {
|
|
346
|
+
const n = this.accumulators.get(t), i = n ? {
|
|
347
|
+
inputTokens: n.inputTokens,
|
|
348
|
+
outputTokens: n.outputTokens,
|
|
349
|
+
modelCalls: n.modelCalls,
|
|
350
|
+
peakContextTokens: n.peakContextTokens
|
|
351
|
+
} : {
|
|
352
|
+
inputTokens: 0,
|
|
353
|
+
outputTokens: 0,
|
|
354
|
+
modelCalls: 0,
|
|
355
|
+
peakContextTokens: 0
|
|
356
|
+
};
|
|
214
357
|
if (s === "task" || !this.db)
|
|
215
|
-
return
|
|
358
|
+
return i;
|
|
216
359
|
try {
|
|
217
|
-
const
|
|
218
|
-
let
|
|
219
|
-
if (s === "session" &&
|
|
360
|
+
const r = this.db;
|
|
361
|
+
let a;
|
|
362
|
+
if (s === "session" && e ? a = r.prepare(
|
|
220
363
|
`SELECT
|
|
221
364
|
COALESCE(SUM(tu.input_tokens), 0) AS input,
|
|
222
365
|
COALESCE(SUM(tu.output_tokens), 0) AS output,
|
|
223
|
-
COALESCE(SUM(tu.model_calls), 0) AS calls
|
|
366
|
+
COALESCE(SUM(tu.model_calls), 0) AS calls,
|
|
367
|
+
COALESCE(MAX(tu.peak_context_tokens), 0) AS peak
|
|
224
368
|
FROM task_usage tu
|
|
225
369
|
JOIN tasks t ON tu.task_id = t.id
|
|
226
370
|
WHERE t.session_id = ? AND tu.task_id != ?`
|
|
227
|
-
).get(
|
|
371
|
+
).get(e, t) : s === "agent" ? a = r.prepare(
|
|
228
372
|
`SELECT
|
|
229
373
|
COALESCE(SUM(input_tokens), 0) AS input,
|
|
230
374
|
COALESCE(SUM(output_tokens), 0) AS output,
|
|
231
|
-
COALESCE(SUM(model_calls), 0) AS calls
|
|
375
|
+
COALESCE(SUM(model_calls), 0) AS calls,
|
|
376
|
+
COALESCE(MAX(peak_context_tokens), 0) AS peak
|
|
232
377
|
FROM task_usage
|
|
233
378
|
WHERE agent_name = ? AND task_id != ?`
|
|
234
|
-
).get(o,
|
|
379
|
+
).get(o, t) : s === "global" && (a = r.prepare(
|
|
235
380
|
`SELECT
|
|
236
381
|
COALESCE(SUM(input_tokens), 0) AS input,
|
|
237
382
|
COALESCE(SUM(output_tokens), 0) AS output,
|
|
238
|
-
COALESCE(SUM(model_calls), 0) AS calls
|
|
383
|
+
COALESCE(SUM(model_calls), 0) AS calls,
|
|
384
|
+
COALESCE(MAX(peak_context_tokens), 0) AS peak
|
|
239
385
|
FROM task_usage
|
|
240
386
|
WHERE task_id != ?`
|
|
241
|
-
).get(
|
|
387
|
+
).get(t)), a)
|
|
242
388
|
return {
|
|
243
|
-
inputTokens: (
|
|
244
|
-
outputTokens: (
|
|
245
|
-
modelCalls: (
|
|
389
|
+
inputTokens: (a.input ?? 0) + i.inputTokens,
|
|
390
|
+
outputTokens: (a.output ?? 0) + i.outputTokens,
|
|
391
|
+
modelCalls: (a.calls ?? 0) + i.modelCalls,
|
|
392
|
+
// Scoped context = MAX over the scope's task set of peak_context_tokens,
|
|
393
|
+
// with the current task's in-memory peak folded in (it is a member of the
|
|
394
|
+
// set; the queries above exclude it by `task_id != ?`).
|
|
395
|
+
peakContextTokens: Math.max(a.peak ?? 0, i.peakContextTokens)
|
|
246
396
|
};
|
|
247
397
|
} catch {
|
|
248
398
|
}
|
|
249
|
-
return
|
|
399
|
+
return i;
|
|
250
400
|
}
|
|
251
|
-
queryWindowTokens(
|
|
401
|
+
queryWindowTokens(t, e, o, s) {
|
|
252
402
|
if (!this.db)
|
|
253
403
|
return 0;
|
|
254
404
|
try {
|
|
255
|
-
const
|
|
256
|
-
let
|
|
257
|
-
if (
|
|
258
|
-
const
|
|
259
|
-
s &&
|
|
405
|
+
const n = this.db, i = new Date(Date.now() - o).toISOString();
|
|
406
|
+
let r;
|
|
407
|
+
if (t === "session") {
|
|
408
|
+
const a = s ? " AND tu.task_id != ?" : "", l = [e, i];
|
|
409
|
+
s && l.push(s), r = n.prepare(
|
|
260
410
|
`SELECT COALESCE(SUM(tu.input_tokens + tu.output_tokens), 0) AS total
|
|
261
411
|
FROM task_usage tu
|
|
262
412
|
JOIN tasks t ON tu.task_id = t.id
|
|
263
|
-
WHERE t.session_id = ? AND tu.created_at >= ?${
|
|
264
|
-
).get(...
|
|
265
|
-
} else if (
|
|
266
|
-
const
|
|
267
|
-
s &&
|
|
413
|
+
WHERE t.session_id = ? AND tu.created_at >= ?${a}`
|
|
414
|
+
).get(...l);
|
|
415
|
+
} else if (t === "agent") {
|
|
416
|
+
const a = s ? " AND task_id != ?" : "", l = [e, i];
|
|
417
|
+
s && l.push(s), r = n.prepare(
|
|
268
418
|
`SELECT COALESCE(SUM(input_tokens + output_tokens), 0) AS total
|
|
269
419
|
FROM task_usage
|
|
270
|
-
WHERE agent_name = ? AND created_at >= ?${
|
|
271
|
-
).get(...
|
|
272
|
-
} else if (
|
|
273
|
-
const
|
|
274
|
-
s &&
|
|
420
|
+
WHERE agent_name = ? AND created_at >= ?${a}`
|
|
421
|
+
).get(...l);
|
|
422
|
+
} else if (t === "global") {
|
|
423
|
+
const a = s ? " AND task_id != ?" : "", l = [i];
|
|
424
|
+
s && l.push(s), r = n.prepare(
|
|
275
425
|
`SELECT COALESCE(SUM(input_tokens + output_tokens), 0) AS total
|
|
276
426
|
FROM task_usage
|
|
277
|
-
WHERE created_at >= ?${
|
|
278
|
-
).get(...
|
|
427
|
+
WHERE created_at >= ?${a}`
|
|
428
|
+
).get(...l);
|
|
279
429
|
}
|
|
280
|
-
return (
|
|
430
|
+
return (r == null ? void 0 : r.total) ?? 0;
|
|
281
431
|
} catch {
|
|
282
432
|
return 0;
|
|
283
433
|
}
|
|
@@ -292,189 +442,275 @@ class O {
|
|
|
292
442
|
* W = number of unique (scope, window) pairs across all caps
|
|
293
443
|
*
|
|
294
444
|
* Independent of cap count, agent count, session count, or history depth.
|
|
445
|
+
*
|
|
446
|
+
* `requestEstimate` (tokens) is the tools-aware estimate of the PENDING
|
|
447
|
+
* request, computed on the model path; it feeds the 'context' enforcement
|
|
448
|
+
* value = max(provider-reported peak, estimate) per owner ruling 4.
|
|
295
449
|
*/
|
|
296
|
-
buildSnapshot(
|
|
297
|
-
const
|
|
298
|
-
|
|
299
|
-
const
|
|
300
|
-
for (const
|
|
301
|
-
const
|
|
302
|
-
if (
|
|
303
|
-
const
|
|
304
|
-
|
|
305
|
-
scope:
|
|
306
|
-
windowMs:
|
|
450
|
+
buildSnapshot(t, e, o, s, n, i, r = 0) {
|
|
451
|
+
const a = {};
|
|
452
|
+
a.inputTokens = e.inputTokens, a.outputTokens = e.outputTokens, a.calls = e.modelCalls, a.wallClock = Date.now() - e.startedAtMs, a.modelMs = e.totalModelMs, a.context = Math.max(e.peakContextTokens, r), a.errors = e.errors, a.consecutiveErrors = e.consecutiveErrors, a.cost = e.uncachedInputTokens * this.costPerInput + e.cacheReadTokens * this.costPerCacheRead + e.cacheCreationTokens * this.costPerCacheWrite + e.outputTokens * this.costPerOutput;
|
|
453
|
+
const l = /* @__PURE__ */ new Set(), p = /* @__PURE__ */ new Map();
|
|
454
|
+
for (const f of t) {
|
|
455
|
+
const d = f.scope ?? i ?? "task";
|
|
456
|
+
if (d !== "task" && l.add(d), f.window) {
|
|
457
|
+
const k = `${d}:${f.window}`;
|
|
458
|
+
p.has(k) || p.set(k, {
|
|
459
|
+
scope: d,
|
|
460
|
+
windowMs: E(f.window)
|
|
307
461
|
});
|
|
308
462
|
}
|
|
309
463
|
}
|
|
310
|
-
for (const
|
|
311
|
-
const
|
|
312
|
-
|
|
464
|
+
for (const f of l) {
|
|
465
|
+
const d = this.queryScopeTotals(o, s, n, f);
|
|
466
|
+
a[`${f}:inputTokens`] = d.inputTokens, a[`${f}:outputTokens`] = d.outputTokens, a[`${f}:calls`] = d.modelCalls, a[`${f}:context`] = Math.max(
|
|
467
|
+
d.peakContextTokens,
|
|
468
|
+
r
|
|
469
|
+
);
|
|
313
470
|
}
|
|
314
|
-
for (const [
|
|
315
|
-
let
|
|
316
|
-
|
|
471
|
+
for (const [f, { scope: d, windowMs: k }] of p) {
|
|
472
|
+
let m = "";
|
|
473
|
+
d === "session" ? m = s ?? "" : d === "agent" && (m = n ?? ""), a[f] = this.queryWindowTokens(d, m, k, o);
|
|
317
474
|
}
|
|
318
|
-
return
|
|
475
|
+
return a;
|
|
319
476
|
}
|
|
320
|
-
getSnapshotValue(
|
|
321
|
-
const s =
|
|
322
|
-
let a;
|
|
323
|
-
t.window ? a = "" : a = s !== "task" ? `${s}:` : "";
|
|
477
|
+
getSnapshotValue(t, e, o) {
|
|
478
|
+
const s = e.scope ?? o ?? "task";
|
|
324
479
|
let n;
|
|
325
|
-
|
|
480
|
+
e.window ? n = "" : n = s !== "task" ? `${s}:` : "";
|
|
481
|
+
let i;
|
|
482
|
+
switch (e.field) {
|
|
326
483
|
case "inputTokens":
|
|
327
|
-
|
|
484
|
+
i = t[`${n}inputTokens`] ?? t.inputTokens;
|
|
328
485
|
break;
|
|
329
486
|
case "outputTokens":
|
|
330
|
-
|
|
487
|
+
i = t[`${n}outputTokens`] ?? t.outputTokens;
|
|
331
488
|
break;
|
|
332
|
-
case "
|
|
333
|
-
|
|
489
|
+
case "context":
|
|
490
|
+
i = t[`${n}context`] ?? t.context;
|
|
334
491
|
break;
|
|
335
492
|
case "calls":
|
|
336
|
-
|
|
493
|
+
i = t[`${n}calls`] ?? t.calls;
|
|
337
494
|
break;
|
|
338
495
|
case "wallClock":
|
|
339
|
-
|
|
496
|
+
i = t.wallClock;
|
|
340
497
|
break;
|
|
341
498
|
case "modelMs":
|
|
342
|
-
|
|
499
|
+
i = t.modelMs;
|
|
343
500
|
break;
|
|
344
501
|
case "cost":
|
|
345
|
-
|
|
502
|
+
i = t.cost;
|
|
346
503
|
break;
|
|
347
504
|
case "toolCalls":
|
|
348
|
-
|
|
505
|
+
i = 0;
|
|
506
|
+
break;
|
|
507
|
+
case "errors":
|
|
508
|
+
i = t.errors;
|
|
509
|
+
break;
|
|
510
|
+
case "consecutiveErrors":
|
|
511
|
+
i = t.consecutiveErrors;
|
|
349
512
|
break;
|
|
350
513
|
default:
|
|
351
|
-
|
|
514
|
+
i = 0;
|
|
352
515
|
}
|
|
353
|
-
return
|
|
516
|
+
return e.window && (i += t[`${s}:${e.window}`] ?? 0), i;
|
|
354
517
|
}
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
518
|
+
/**
|
|
519
|
+
* Emit a `budget:*` notification event for an exceeded cap. Pure notification
|
|
520
|
+
* layer (owner ruling 7): HookRegistry.emit swallows handler errors and is a
|
|
521
|
+
* no-op when no handler is registered, so emission can never affect
|
|
522
|
+
* enforcement. `message` defaults to cap.message, then the standard
|
|
523
|
+
* `"<field> limit is <limit>, current value is <current>"` string — the
|
|
524
|
+
* same resolution `makeEnforcementError` uses, so the block event's message
|
|
525
|
+
* always matches the error the orchestrator sees.
|
|
526
|
+
*
|
|
527
|
+
* `limit` is the RESOLVED cap limit (`maximum`, or the context-window-derived
|
|
528
|
+
* limit for `contextWindowFraction` caps) — the payload must report the real
|
|
529
|
+
* number the cap trips at, not an undefined `maximum`.
|
|
530
|
+
*/
|
|
531
|
+
async emitBudgetEvent(t, e, o, s, n, i) {
|
|
532
|
+
this.hooks && await this.hooks.emit(t, {
|
|
533
|
+
executionContext: e,
|
|
534
|
+
field: o.field,
|
|
535
|
+
maximum: n,
|
|
536
|
+
current: s,
|
|
537
|
+
message: i ?? o.message ?? `${o.field} limit is ${n}, current value is ${Math.round(
|
|
538
|
+
s
|
|
539
|
+
)}`
|
|
540
|
+
});
|
|
541
|
+
}
|
|
542
|
+
/**
|
|
543
|
+
* Resolve a cap's numeric limit. A `context` cap configured via
|
|
544
|
+
* `contextWindowFraction` has no `maximum`: the limit is
|
|
545
|
+
* `contextWindowFor(modelId) * fraction` (128K fallback for unknown models).
|
|
546
|
+
* Every other cap carries an explicit `maximum` (schema-enforced).
|
|
547
|
+
*/
|
|
548
|
+
resolveCapLimit(t, e) {
|
|
549
|
+
if (t.maximum !== void 0)
|
|
550
|
+
return t.maximum;
|
|
551
|
+
const o = e.agentDefinition.provider;
|
|
552
|
+
return Math.floor(
|
|
553
|
+
S(o.model) * (t.contextWindowFraction ?? 0)
|
|
554
|
+
);
|
|
555
|
+
}
|
|
556
|
+
/**
|
|
557
|
+
* Evaluate a single cap against the snapshot. Mode resolution matches the
|
|
558
|
+
* tool path (`cap.mode ?? dimMode ?? 'warning'`, owner ruling 5): warning
|
|
559
|
+
* (the default) emits `budget:warning` and resolves — the run continues;
|
|
560
|
+
* block emits `budget:block` BEFORE throwing the enforcement error.
|
|
561
|
+
*/
|
|
562
|
+
async evaluateCap(t, e, o, s, n) {
|
|
563
|
+
const i = this.resolveCapLimit(t, o), r = this.getSnapshotValue(e, t, n);
|
|
564
|
+
if (r < i)
|
|
565
|
+
return;
|
|
566
|
+
if ((t.mode ?? s ?? "warning") === "warning") {
|
|
567
|
+
await this.emitBudgetEvent("budget:warning", o, t, r, i);
|
|
568
|
+
return;
|
|
569
|
+
}
|
|
570
|
+
throw await this.emitBudgetEvent("budget:block", o, t, r, i), v(t.field, i, r, t.message);
|
|
359
571
|
}
|
|
360
572
|
// ── Enforcement: pre:model_request ────────────────────────────────────────
|
|
361
|
-
enforcePreModel(
|
|
362
|
-
var
|
|
363
|
-
const { taskId:
|
|
364
|
-
if (!
|
|
573
|
+
async enforcePreModel(t) {
|
|
574
|
+
var d, k;
|
|
575
|
+
const { taskId: e, sessionId: o, agentName: s } = t.executionContext, n = ((k = (d = t.executionContext.agentDefinition) == null ? void 0 : d.provider) == null ? void 0 : k.type) ?? "unknown", i = this.accumulators.get(e);
|
|
576
|
+
if (!i)
|
|
365
577
|
return;
|
|
366
|
-
const { caps:
|
|
367
|
-
|
|
578
|
+
const { caps: r, mode: a, scope: l } = this.resolveCaps(
|
|
579
|
+
s,
|
|
580
|
+
n
|
|
581
|
+
), p = r.filter(
|
|
582
|
+
(m) => !b.has(m.field)
|
|
583
|
+
);
|
|
584
|
+
if (p.length === 0)
|
|
368
585
|
return;
|
|
369
|
-
const
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
586
|
+
const f = this.buildSnapshot(
|
|
587
|
+
p,
|
|
588
|
+
i,
|
|
589
|
+
e,
|
|
373
590
|
o,
|
|
374
591
|
s,
|
|
375
|
-
|
|
592
|
+
l,
|
|
593
|
+
R(t.messages, t.tools)
|
|
376
594
|
);
|
|
377
|
-
for (const
|
|
378
|
-
this.evaluateCap(
|
|
595
|
+
for (const m of p)
|
|
596
|
+
await this.evaluateCap(m, f, t.executionContext, a, l);
|
|
379
597
|
}
|
|
380
598
|
// ── Enforcement: pre:tool_call ────────────────────────────────────────────
|
|
381
|
-
enforcePreTool(
|
|
382
|
-
const { toolName:
|
|
383
|
-
caps:
|
|
384
|
-
mode:
|
|
385
|
-
scope:
|
|
386
|
-
} = this.resolveCaps(s.agentName, "",
|
|
387
|
-
if (!
|
|
599
|
+
async enforcePreTool(t) {
|
|
600
|
+
const { toolName: e, callId: o, executionContext: s } = t, {
|
|
601
|
+
caps: n,
|
|
602
|
+
mode: i,
|
|
603
|
+
scope: r
|
|
604
|
+
} = this.resolveCaps(s.agentName, "", e), a = this.accumulators.get(s.taskId);
|
|
605
|
+
if (!a)
|
|
606
|
+
return;
|
|
607
|
+
const l = n.filter((d) => d.field !== "context");
|
|
608
|
+
if (l.length === 0)
|
|
388
609
|
return;
|
|
389
|
-
const
|
|
610
|
+
const p = a.toolCalls.get(e) ?? 0, f = this.buildSnapshot(
|
|
611
|
+
l,
|
|
390
612
|
a,
|
|
391
|
-
c,
|
|
392
613
|
s.taskId,
|
|
393
614
|
s.sessionId,
|
|
394
615
|
s.agentName,
|
|
395
|
-
|
|
616
|
+
r
|
|
396
617
|
);
|
|
397
|
-
for (const
|
|
398
|
-
const m =
|
|
399
|
-
if (m >=
|
|
400
|
-
const
|
|
401
|
-
throw (
|
|
402
|
-
|
|
403
|
-
|
|
618
|
+
for (const d of l) {
|
|
619
|
+
const k = this.resolveCapLimit(d, s), m = d.field === "toolCalls" ? p : this.getSnapshotValue(f, d, r);
|
|
620
|
+
if (m >= k) {
|
|
621
|
+
const h = d.message ?? `tool "${e}": ${d.field} limit is ${k}, current value is ${Math.round(m)}`;
|
|
622
|
+
throw (d.mode ?? i ?? "warning") === "warning" ? (await this.emitBudgetEvent(
|
|
623
|
+
"budget:warning",
|
|
624
|
+
s,
|
|
625
|
+
d,
|
|
626
|
+
m,
|
|
627
|
+
k,
|
|
628
|
+
h
|
|
629
|
+
), $(e, o, h)) : (await this.emitBudgetEvent(
|
|
630
|
+
"budget:block",
|
|
631
|
+
s,
|
|
632
|
+
d,
|
|
633
|
+
m,
|
|
634
|
+
k,
|
|
635
|
+
h
|
|
636
|
+
), v(
|
|
637
|
+
`tool:${e}:${d.field}`,
|
|
638
|
+
k,
|
|
404
639
|
m,
|
|
405
|
-
|
|
406
|
-
);
|
|
640
|
+
d.message
|
|
641
|
+
));
|
|
407
642
|
}
|
|
408
643
|
}
|
|
409
|
-
|
|
644
|
+
a.toolCalls.set(e, p + 1);
|
|
410
645
|
}
|
|
411
646
|
// ── Enforcement: transform:tool_result (response size) ────────────────────
|
|
412
|
-
enforceResponseSize(
|
|
413
|
-
const { toolName:
|
|
647
|
+
enforceResponseSize(t) {
|
|
648
|
+
const { toolName: e, result: o } = t;
|
|
414
649
|
if (typeof o != "object" || o === null)
|
|
415
650
|
return;
|
|
416
|
-
const { caps: s, mode:
|
|
417
|
-
if (
|
|
651
|
+
const { caps: s, mode: n } = this.resolveCaps("", "", e), i = s.filter((p) => p.field === "responseSize");
|
|
652
|
+
if (i.length === 0)
|
|
418
653
|
return;
|
|
419
|
-
const
|
|
420
|
-
if (!Array.isArray(
|
|
654
|
+
const r = o, a = r.content;
|
|
655
|
+
if (!Array.isArray(a))
|
|
421
656
|
return;
|
|
422
|
-
let
|
|
423
|
-
for (const
|
|
424
|
-
if (typeof
|
|
425
|
-
const
|
|
426
|
-
|
|
657
|
+
let l = 0;
|
|
658
|
+
for (const p of a)
|
|
659
|
+
if (typeof p == "object" && p !== null) {
|
|
660
|
+
const f = p;
|
|
661
|
+
f.type === "text" && (l += (f.text ?? "").length);
|
|
427
662
|
}
|
|
428
|
-
for (const
|
|
429
|
-
|
|
663
|
+
for (const p of i) {
|
|
664
|
+
const f = this.resolveCapLimit(p, t.executionContext);
|
|
665
|
+
if (l <= f)
|
|
430
666
|
continue;
|
|
431
|
-
if ((
|
|
432
|
-
|
|
667
|
+
if ((p.mode ?? n ?? "warning") === "block")
|
|
668
|
+
r.content = [
|
|
433
669
|
{
|
|
434
670
|
type: "text",
|
|
435
|
-
text:
|
|
671
|
+
text: p.message ?? `Response size (${l} chars) exceeds limit of ${f}. Use offset/limit or shell paging tools instead.`
|
|
436
672
|
}
|
|
437
|
-
],
|
|
673
|
+
], t.isError = !0;
|
|
438
674
|
else {
|
|
439
|
-
let
|
|
440
|
-
const
|
|
441
|
-
for (const
|
|
442
|
-
if (typeof
|
|
443
|
-
|
|
675
|
+
let k = f;
|
|
676
|
+
const m = [];
|
|
677
|
+
for (const h of a) {
|
|
678
|
+
if (typeof h != "object" || h === null) {
|
|
679
|
+
m.push(h);
|
|
444
680
|
continue;
|
|
445
681
|
}
|
|
446
|
-
const
|
|
447
|
-
if (
|
|
448
|
-
|
|
682
|
+
const C = h;
|
|
683
|
+
if (C.type !== "text") {
|
|
684
|
+
m.push(h);
|
|
449
685
|
continue;
|
|
450
686
|
}
|
|
451
|
-
const
|
|
452
|
-
if (
|
|
453
|
-
|
|
687
|
+
const T = C.text ?? "";
|
|
688
|
+
if (T.length <= k)
|
|
689
|
+
m.push(h), k -= T.length;
|
|
454
690
|
else {
|
|
455
|
-
|
|
691
|
+
m.push({ type: "text", text: T.slice(0, k) });
|
|
456
692
|
break;
|
|
457
693
|
}
|
|
458
694
|
}
|
|
459
|
-
|
|
695
|
+
m.push({
|
|
460
696
|
type: "text",
|
|
461
697
|
text: `
|
|
462
698
|
|
|
463
|
-
[truncated: response was ${
|
|
464
|
-
}),
|
|
699
|
+
[truncated: response was ${l} chars, limited to ${p.maximum}. ${p.message ?? "Use offset/limit or shell paging tools for full content."}]`
|
|
700
|
+
}), r.content = m;
|
|
465
701
|
}
|
|
466
702
|
break;
|
|
467
703
|
}
|
|
468
704
|
}
|
|
469
705
|
}
|
|
470
|
-
const
|
|
471
|
-
var a,
|
|
472
|
-
const
|
|
473
|
-
return new
|
|
706
|
+
const j = ({ db: c, config: t }) => {
|
|
707
|
+
var r, a, l, p;
|
|
708
|
+
const e = I(t), o = ((r = e.defaults) == null ? void 0 : r.costPerInputToken) ?? 0, s = ((a = e.defaults) == null ? void 0 : a.costPerOutputToken) ?? 0, n = ((l = e.defaults) == null ? void 0 : l.costPerCacheReadToken) ?? o, i = ((p = e.defaults) == null ? void 0 : p.costPerCacheWriteToken) ?? o;
|
|
709
|
+
return new L(c, e, o, s, n, i);
|
|
474
710
|
};
|
|
475
711
|
export {
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
712
|
+
N as configSchema,
|
|
713
|
+
j as createPlugin,
|
|
714
|
+
j as default,
|
|
715
|
+
_ as pluginConfigSchema
|
|
480
716
|
};
|