@adhd/agent-plugin-budget 0.2.1 → 0.2.2
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 +15 -0
- package/index.cjs +7 -9
- package/index.js +529 -703
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
## 0.2.2 (2026-09-26)
|
|
2
|
+
|
|
3
|
+
### 🚀 Features
|
|
4
|
+
|
|
5
|
+
- **vite-plugins:** absorb perf/test-resolve-fix — test-time @adhd/* source resolution ([3e344506](https://github.com/PseudoSky/adhd/commit/3e344506))
|
|
6
|
+
|
|
7
|
+
### 🩹 Fixes
|
|
8
|
+
|
|
9
|
+
- **vite:** restore import.meta.url in CJS output under vite 8 ([7916e639](https://github.com/PseudoSky/adhd/commit/7916e639))
|
|
10
|
+
- **nx:** finish the ESLint v9 flat-config migration and unblock the gate ([53f4ff3e](https://github.com/PseudoSky/adhd/commit/53f4ff3e))
|
|
11
|
+
|
|
12
|
+
### ❤️ Thank You
|
|
13
|
+
|
|
14
|
+
- pseudosky
|
|
15
|
+
|
|
1
16
|
## 0.2.1 (2026-09-24)
|
|
2
17
|
|
|
3
18
|
This was a version bump only for agent-plugin-budget to align it with other projects, there were no code changes.
|
package/index.cjs
CHANGED
|
@@ -1,29 +1,27 @@
|
|
|
1
|
-
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const u=require("zod"),M=require("@adhd/agent-base-types");function b(c){const t=/^P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+(?:\.\d+)?)S)?)?$/,e=c.match(t);if(!e)throw new Error(`invalid ISO 8601 duration: ${c}`);const[,o,s,n,i,r,a]=e;let l=0;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)}const y=["context","inputTokens","outputTokens","calls","wallClock","modelMs","cost","toolCalls","errors","consecutiveErrors","responseSize"],_=new Set(["toolCalls","errors","consecutiveErrors"]),A=u.z.object({field:u.z.enum(y),maximum:u.z.number().min(0).optional(),contextWindowFraction:u.z.number().min(0).max(1).optional(),window:u.z.string().optional(),scope:u.z.enum(["task","session","agent","global"]).optional(),mode:u.z.enum(["warning","block"]).optional(),message:u.z.string().optional()}).superRefine((c,t)=>{if(c.field==="context"){const e=c.maximum!==void 0,o=c.contextWindowFraction!==void 0;e===o&&t.addIssue({code:u.z.ZodIssueCode.custom,path:["contextWindowFraction"],message:"cap field 'context' requires exactly one of 'maximum' or 'contextWindowFraction'"}),c.window!==void 0&&t.addIssue({code:u.z.ZodIssueCode.custom,path:["window"],message:"cap field 'context' rejects 'window' — a windowed peak is meaningless; windowed cumulative volume is expressible via 'inputTokens'/'outputTokens' + 'window'"})}else(c.field==="errors"||c.field==="consecutiveErrors")&&(c.window!==void 0&&t.addIssue({code:u.z.ZodIssueCode.custom,path:["window"],message:`cap field '${c.field}' rejects 'window' — windowed error budgets are not expressible this wave`}),c.scope!==void 0&&c.scope!=="task"&&t.addIssue({code:u.z.ZodIssueCode.custom,path:["scope"],message:`cap field '${c.field}' is counted per-task in memory (no task_usage column) — only 'task' scope is expressible this wave`})),c.window!==void 0&&(c.scope===void 0||c.scope==="task")&&t.addIssue({code:u.z.ZodIssueCode.custom,path:["scope"],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'`}),c.contextWindowFraction!==void 0&&t.addIssue({code:u.z.ZodIssueCode.custom,path:["contextWindowFraction"],message:`'contextWindowFraction' is only valid on cap field 'context' (got '${c.field}')`}),c.maximum===void 0&&t.addIssue({code:u.z.ZodIssueCode.custom,path:["maximum"],message:`cap field '${c.field}' requires a 'maximum'`})}),g=u.z.object({caps:u.z.array(A).optional(),mode:u.z.enum(["warning","block"]).optional(),costPerInputToken:u.z.number().min(0).optional(),costPerOutputToken:u.z.number().min(0).optional(),costPerCacheReadToken:u.z.number().min(0).optional(),costPerCacheWriteToken:u.z.number().min(0).optional(),scope:u.z.enum(["task","session","agent","global"]).optional()}),x=g.partial().superRefine((c,t)=>{const e=c.caps??[];for(const[o,s]of e.entries())s.field==="context"&&t.addIssue({code:u.z.ZodIssueCode.custom,path:["caps",o,"field"],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"})}),S=u.z.object({defaults:g.optional(),agent:u.z.object({default:g.optional(),overrides:u.z.record(u.z.string(),g.partial()).optional().default({})}).optional(),provider:u.z.object({default:g.optional(),overrides:u.z.record(u.z.string(),g.partial()).optional().default({})}).optional(),tool:u.z.object({default:x.optional(),overrides:u.z.record(u.z.string(),x).optional().default({})}).optional()}),O=u.z.object({}).passthrough(),P={maxInputTokens:{field:"inputTokens"},maxOutputTokens:{field:"outputTokens"},maxModelCalls:{field:"calls"},maxWallClockMs:{field:"wallClock"},maxModelMs:{field:"modelMs"},maxCostUSD:{field:"cost"},maxTokensPer24h:{field:"inputTokens",window:"PT24H"},maxCalls:{field:"toolCalls"}};function I(c){const t=[],e={};for(const[n,i]of Object.entries(c)){const r=P[n];if(r&&typeof i=="number"){const a={field:r.field,maximum:i};r.window&&(a.window=r.window),t.push(a)}else(n==="scope"||n==="mode"||n==="costPerInputToken"||n==="costPerOutputToken"||n==="costPerCacheReadToken"||n==="costPerCacheWriteToken"||n==="message")&&(e[n]=i)}t.length>0&&(e.caps=t);const o=e.scope,s=o==="task"||o==="session"||o==="agent"||o==="global"?o:void 0;for(const n of t)n.window!==void 0&&n.scope===void 0&&(n.scope=s??"global");return g.parse(e)}const w=c=>`legacy 'tokens' budget cap detected (${c}): cap field 'tokens' is removed; use 'context' (peak request input) or 'inputTokens'/'outputTokens' (windowed volume)`;function z(c){const t=c??{};if(typeof t.maxTotalTokens=="number")throw new Error(w("flat 'maxTotalTokens'"));const e=s=>{if(typeof s!="object"||s===null)return;const n=s;if(typeof n.maxTotalTokens=="number")throw new Error(w("structured 'maxTotalTokens'"));const i=n.caps;if(Array.isArray(i)){for(const r of i)if(typeof r=="object"&&r!==null&&r.field==="tokens")throw new Error(w("caps[].field === 'tokens'"))}},o=s=>{if(typeof s!="object"||s===null)return;const n=s;e(n),"default"in n&&e(n.default);const i=n.overrides;if(typeof i=="object"&&i!==null)for(const r of Object.values(i))e(r)};e(t.defaults),o(t.agent),o(t.provider),o(t.tool)}function $(c){z(c);const t=c;if(t.defaults!==void 0||t.agent!==void 0||t.provider!==void 0||t.tool!==void 0){const e=S.parse(c);return{defaults:e.defaults??g.parse({}),agent:e.agent??{overrides:{}},provider:e.provider??{overrides:{}},tool:e.tool??{overrides:{}}}}return{defaults:I(t),agent:{overrides:{}},provider:{overrides:{}},tool:{overrides:{}}}}function v(c,t,e,o){return{isEnforcementError:!0,code:"BUDGET_EXCEEDED",message:o??`${c} limit is ${t}, current value is ${Math.round(e)}`}}function R(c,t,e){return{isToolWarning:!0,toolName:c,callId:t,message:e}}function L(c,t){var o;let e=0;for(const s of c){e+=((o=s.content)==null?void 0:o.length)??0;for(const n of s.toolCalls??[])e+=JSON.stringify(n.arguments??{}).length;for(const n of s.toolResults??[])e+=JSON.stringify(n.result??null).length}for(const s of t)e+=JSON.stringify({name:s.name,description:s.description,inputSchema:s.inputSchema}).length;return Math.ceil(e/4)}class W{constructor(t,e,o=0,s=0,n=0,i=0){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=new Map}install(t){this.hooks=t,t.register("task:start",e=>{try{this.onTaskStart(e)}catch{}}),t.register("pre:model_request",e=>{try{this.onPreModelRequest(e)}catch{}}),t.register("post:model_response",e=>{try{this.onPostModelResponse(e)}catch{}}),t.register("post:tool_call",e=>{try{this.onPostToolCall(e)}catch{}}),t.register("task:completed",e=>{try{this.onTerminal(e.executionContext.taskId)}catch{}}),t.register("task:failed",e=>{try{this.onTerminal(e.executionContext.taskId)}catch{}}),t.register("task:cancelled",e=>{try{this.onTerminal(e.executionContext.taskId)}catch{}}),t.registerEnforcement("pre:model_request",e=>this.enforcePreModel(e)),t.registerEnforcement("pre:tool_call",e=>this.enforcePreTool(e)),t.register("transform:tool_result",e=>{try{this.enforceResponseSize(e)}catch{}})}onTaskStart(t){var i,r;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";this.accumulators.set(e,{taskId:e,sessionId:o??void 0,agentName:s,providerType:n,startedAtMs:Date.now(),uncachedInputTokens:0,cacheReadTokens:0,cacheCreationTokens:0,inputTokens:0,outputTokens:0,peakContextTokens:0,modelCalls:0,totalModelMs:0,toolCalls:new Map,errors:0,consecutiveErrors:0})}onPreModelRequest(t){const e=this.accumulators.get(t.executionContext.taskId);e&&(e.modelCallStartMs=Date.now())}onPostModelResponse(t){const e=this.accumulators.get(t.executionContext.taskId);if(!e)return;const o=t.tokenUsage;if(o){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;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)}e.modelCalls+=1,e.modelCallStartMs!==void 0&&(e.totalModelMs+=Date.now()-e.modelCallStartMs,e.modelCallStartMs=void 0)}onTerminal(t){this.accumulators.delete(t)}onPostToolCall(t){const e=this.accumulators.get(t.executionContext.taskId);e&&(t.isError?(e.errors+=1,e.consecutiveErrors+=1):e.consecutiveErrors=0)}mergeDim(t){let e={caps:[]};for(const o of t)o&&(e={caps:[...e.caps??[],...o.caps??[]],mode:o.mode??e.mode,costPerInputToken:o.costPerInputToken??e.costPerInputToken,costPerOutputToken:o.costPerOutputToken??e.costPerOutputToken,costPerCacheReadToken:o.costPerCacheReadToken??e.costPerCacheReadToken,costPerCacheWriteToken:o.costPerCacheWriteToken??e.costPerCacheWriteToken,scope:o.scope??e.scope});return e}resolveCaps(t,e,o){var f,d,k;const s=this.cfg.defaults,n=this.cfg.agent,i=this.cfg.provider,r=this.cfg.tool;if(o){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]);return{caps:h.caps??[],mode:h.mode,scope:h.scope}}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([s,n==null?void 0:n.default,a,i==null?void 0:i.default,l]);return{caps:p.caps??[],mode:p.mode,scope:p.scope}}queryScopeTotals(t,e,o,s){const n=this.accumulators.get(t),i=n?{inputTokens:n.inputTokens,outputTokens:n.outputTokens,modelCalls:n.modelCalls,peakContextTokens:n.peakContextTokens}:{inputTokens:0,outputTokens:0,modelCalls:0,peakContextTokens:0};if(s==="task"||!this.db)return i;try{const r=this.db;let a;if(s==="session"&&e?a=r.prepare(`SELECT
|
|
1
|
+
Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:`Module`}});let e=require("zod"),t=require("@adhd/agent-base-types");function n(e){let t=e.match(/^P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+(?:\.\d+)?)S)?)?$/);if(!t)throw Error(`invalid ISO 8601 duration: ${e}`);let[,n,r,i,a,o,s]=t,c=0;return n&&(c+=parseInt(n)*365.25*864e5),r&&(c+=parseInt(r)*30.44*864e5),i&&(c+=parseInt(i)*864e5),a&&(c+=parseInt(a)*36e5),o&&(c+=parseInt(o)*6e4),s&&(c+=parseFloat(s)*1e3),Math.round(c)}var r=[`context`,`inputTokens`,`outputTokens`,`calls`,`wallClock`,`modelMs`,`cost`,`toolCalls`,`errors`,`consecutiveErrors`,`responseSize`],i=new Set([`toolCalls`,`errors`,`consecutiveErrors`]),a=e.z.object({field:e.z.enum(r),maximum:e.z.number().min(0).optional(),contextWindowFraction:e.z.number().min(0).max(1).optional(),window:e.z.string().optional(),scope:e.z.enum([`task`,`session`,`agent`,`global`]).optional(),mode:e.z.enum([`warning`,`block`]).optional(),message:e.z.string().optional()}).superRefine((t,n)=>{t.field===`context`?(t.maximum!==void 0==(t.contextWindowFraction!==void 0)&&n.addIssue({code:e.z.ZodIssueCode.custom,path:[`contextWindowFraction`],message:`cap field 'context' requires exactly one of 'maximum' or 'contextWindowFraction'`}),t.window!==void 0&&n.addIssue({code:e.z.ZodIssueCode.custom,path:[`window`],message:`cap field 'context' rejects 'window' — a windowed peak is meaningless; windowed cumulative volume is expressible via 'inputTokens'/'outputTokens' + 'window'`})):((t.field===`errors`||t.field===`consecutiveErrors`)&&(t.window!==void 0&&n.addIssue({code:e.z.ZodIssueCode.custom,path:[`window`],message:`cap field '${t.field}' rejects 'window' — windowed error budgets are not expressible this wave`}),t.scope!==void 0&&t.scope!==`task`&&n.addIssue({code:e.z.ZodIssueCode.custom,path:[`scope`],message:`cap field '${t.field}' is counted per-task in memory (no task_usage column) — only 'task' scope is expressible this wave`})),t.window!==void 0&&(t.scope===void 0||t.scope===`task`)&&n.addIssue({code:e.z.ZodIssueCode.custom,path:[`scope`],message:`cap field '${t.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'`}),t.contextWindowFraction!==void 0&&n.addIssue({code:e.z.ZodIssueCode.custom,path:[`contextWindowFraction`],message:`'contextWindowFraction' is only valid on cap field 'context' (got '${t.field}')`}),t.maximum===void 0&&n.addIssue({code:e.z.ZodIssueCode.custom,path:[`maximum`],message:`cap field '${t.field}' requires a 'maximum'`}))}),o=e.z.object({caps:e.z.array(a).optional(),mode:e.z.enum([`warning`,`block`]).optional(),costPerInputToken:e.z.number().min(0).optional(),costPerOutputToken:e.z.number().min(0).optional(),costPerCacheReadToken:e.z.number().min(0).optional(),costPerCacheWriteToken:e.z.number().min(0).optional(),scope:e.z.enum([`task`,`session`,`agent`,`global`]).optional()}),s=o.partial().superRefine((t,n)=>{let r=t.caps??[];for(let[t,i]of r.entries())i.field===`context`&&n.addIssue({code:e.z.ZodIssueCode.custom,path:[`caps`,t,`field`],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`})}),c=e.z.object({defaults:o.optional(),agent:e.z.object({default:o.optional(),overrides:e.z.record(e.z.string(),o.partial()).optional().default({})}).optional(),provider:e.z.object({default:o.optional(),overrides:e.z.record(e.z.string(),o.partial()).optional().default({})}).optional(),tool:e.z.object({default:s.optional(),overrides:e.z.record(e.z.string(),s).optional().default({})}).optional()}),l=e.z.object({}).passthrough(),u={maxInputTokens:{field:`inputTokens`},maxOutputTokens:{field:`outputTokens`},maxModelCalls:{field:`calls`},maxWallClockMs:{field:`wallClock`},maxModelMs:{field:`modelMs`},maxCostUSD:{field:`cost`},maxTokensPer24h:{field:`inputTokens`,window:`PT24H`},maxCalls:{field:`toolCalls`}};function d(e){let t=[],n={};for(let[r,i]of Object.entries(e)){let e=u[r];if(e&&typeof i==`number`){let n={field:e.field,maximum:i};e.window&&(n.window=e.window),t.push(n)}else(r===`scope`||r===`mode`||r===`costPerInputToken`||r===`costPerOutputToken`||r===`costPerCacheReadToken`||r===`costPerCacheWriteToken`||r===`message`)&&(n[r]=i)}t.length>0&&(n.caps=t);let r=n.scope,i=r===`task`||r===`session`||r===`agent`||r===`global`?r:void 0;for(let e of t)e.window!==void 0&&e.scope===void 0&&(e.scope=i??`global`);return o.parse(n)}var f=e=>`legacy 'tokens' budget cap detected (${e}): cap field 'tokens' is removed; use 'context' (peak request input) or 'inputTokens'/'outputTokens' (windowed volume)`;function p(e){let t=e??{};if(typeof t.maxTotalTokens==`number`)throw Error(f(`flat 'maxTotalTokens'`));let n=e=>{if(typeof e!=`object`||!e)return;let t=e;if(typeof t.maxTotalTokens==`number`)throw Error(f(`structured 'maxTotalTokens'`));let n=t.caps;if(Array.isArray(n)){for(let e of n)if(typeof e==`object`&&e&&e.field===`tokens`)throw Error(f(`caps[].field === 'tokens'`))}},r=e=>{if(typeof e!=`object`||!e)return;let t=e;n(t),`default`in t&&n(t.default);let r=t.overrides;if(typeof r==`object`&&r)for(let e of Object.values(r))n(e)};n(t.defaults),r(t.agent),r(t.provider),r(t.tool)}function m(e){p(e);let t=e;if(t.defaults!==void 0||t.agent!==void 0||t.provider!==void 0||t.tool!==void 0){let t=c.parse(e);return{defaults:t.defaults??o.parse({}),agent:t.agent??{overrides:{}},provider:t.provider??{overrides:{}},tool:t.tool??{overrides:{}}}}return{defaults:d(t),agent:{overrides:{}},provider:{overrides:{}},tool:{overrides:{}}}}function h(e,t,n,r){return{isEnforcementError:!0,code:`BUDGET_EXCEEDED`,message:r??`${e} limit is ${t}, current value is ${Math.round(n)}`}}function g(e,t,n){return{isToolWarning:!0,toolName:e,callId:t,message:n}}function _(e,t){let n=0;for(let t of e){n+=t.content?.length??0;for(let e of t.toolCalls??[])n+=JSON.stringify(e.arguments??{}).length;for(let e of t.toolResults??[])n+=JSON.stringify(e.result??null).length}for(let e of t)n+=JSON.stringify({name:e.name,description:e.description,inputSchema:e.inputSchema}).length;return Math.ceil(n/4)}var v=class{constructor(e,t,n=0,r=0,i=0,a=0){this.db=e,this.cfg=t,this.costPerInput=n,this.costPerOutput=r,this.costPerCacheRead=i,this.costPerCacheWrite=a,this.name=`agent-mcp-budget`,this.accumulators=new Map}install(e){this.hooks=e,e.register(`task:start`,e=>{try{this.onTaskStart(e)}catch{}}),e.register(`pre:model_request`,e=>{try{this.onPreModelRequest(e)}catch{}}),e.register(`post:model_response`,e=>{try{this.onPostModelResponse(e)}catch{}}),e.register(`post:tool_call`,e=>{try{this.onPostToolCall(e)}catch{}}),e.register(`task:completed`,e=>{try{this.onTerminal(e.executionContext.taskId)}catch{}}),e.register(`task:failed`,e=>{try{this.onTerminal(e.executionContext.taskId)}catch{}}),e.register(`task:cancelled`,e=>{try{this.onTerminal(e.executionContext.taskId)}catch{}}),e.registerEnforcement(`pre:model_request`,e=>this.enforcePreModel(e)),e.registerEnforcement(`pre:tool_call`,e=>this.enforcePreTool(e)),e.register(`transform:tool_result`,e=>{try{this.enforceResponseSize(e)}catch{}})}onTaskStart(e){let{taskId:t,sessionId:n,agentName:r}=e.executionContext,i=e.executionContext.agentDefinition?.provider?.type??`unknown`;this.accumulators.set(t,{taskId:t,sessionId:n??void 0,agentName:r,providerType:i,startedAtMs:Date.now(),uncachedInputTokens:0,cacheReadTokens:0,cacheCreationTokens:0,inputTokens:0,outputTokens:0,peakContextTokens:0,modelCalls:0,totalModelMs:0,toolCalls:new Map,errors:0,consecutiveErrors:0})}onPreModelRequest(e){let t=this.accumulators.get(e.executionContext.taskId);t&&(t.modelCallStartMs=Date.now())}onPostModelResponse(e){let t=this.accumulators.get(e.executionContext.taskId);if(!t)return;let n=e.tokenUsage;if(n){let e=n.inputTokens??0,r=n.cacheReadTokens??0,i=n.cacheCreationTokens??0,a=n.uncachedInputTokens!==void 0||n.cacheReadTokens!==void 0||n.cacheCreationTokens!==void 0?n.uncachedInputTokens??Math.max(0,e-r-i):e;t.uncachedInputTokens+=a,t.cacheReadTokens+=r,t.cacheCreationTokens+=i,t.inputTokens+=a+r+i,t.outputTokens+=n.outputTokens??0,t.peakContextTokens=Math.max(t.peakContextTokens,e)}t.modelCalls+=1,t.modelCallStartMs!==void 0&&(t.totalModelMs+=Date.now()-t.modelCallStartMs,t.modelCallStartMs=void 0)}onTerminal(e){this.accumulators.delete(e)}onPostToolCall(e){let t=this.accumulators.get(e.executionContext.taskId);t&&(e.isError?(t.errors+=1,t.consecutiveErrors+=1):t.consecutiveErrors=0)}mergeDim(e){let t={caps:[]};for(let n of e)n&&(t={caps:[...t.caps??[],...n.caps??[]],mode:n.mode??t.mode,costPerInputToken:n.costPerInputToken??t.costPerInputToken,costPerOutputToken:n.costPerOutputToken??t.costPerOutputToken,costPerCacheReadToken:n.costPerCacheReadToken??t.costPerCacheReadToken,costPerCacheWriteToken:n.costPerCacheWriteToken??t.costPerCacheWriteToken,scope:n.scope??t.scope});return t}resolveCaps(e,t,n){let r=this.cfg.defaults,i=this.cfg.agent,a=this.cfg.provider,o=this.cfg.tool;if(n){let e=o?.overrides?.[n],t=this.mergeDim([r,o?.default,e]);return{caps:t.caps??[],mode:t.mode,scope:t.scope}}let s=i?.overrides?.[e],c=a?.overrides?.[t],l=this.mergeDim([r,i?.default,s,a?.default,c]);return{caps:l.caps??[],mode:l.mode,scope:l.scope}}queryScopeTotals(e,t,n,r){let i=this.accumulators.get(e),a=i?{inputTokens:i.inputTokens,outputTokens:i.outputTokens,modelCalls:i.modelCalls,peakContextTokens:i.peakContextTokens}:{inputTokens:0,outputTokens:0,modelCalls:0,peakContextTokens:0};if(r===`task`||!this.db)return a;try{let i=this.db,o;if(r===`session`&&t?o=i.prepare(`SELECT
|
|
2
2
|
COALESCE(SUM(tu.input_tokens), 0) AS input,
|
|
3
3
|
COALESCE(SUM(tu.output_tokens), 0) AS output,
|
|
4
4
|
COALESCE(SUM(tu.model_calls), 0) AS calls,
|
|
5
5
|
COALESCE(MAX(tu.peak_context_tokens), 0) AS peak
|
|
6
6
|
FROM task_usage tu
|
|
7
7
|
JOIN tasks t ON tu.task_id = t.id
|
|
8
|
-
WHERE t.session_id = ? AND tu.task_id != ?`).get(e
|
|
8
|
+
WHERE t.session_id = ? AND tu.task_id != ?`).get(t,e):r===`agent`?o=i.prepare(`SELECT
|
|
9
9
|
COALESCE(SUM(input_tokens), 0) AS input,
|
|
10
10
|
COALESCE(SUM(output_tokens), 0) AS output,
|
|
11
11
|
COALESCE(SUM(model_calls), 0) AS calls,
|
|
12
12
|
COALESCE(MAX(peak_context_tokens), 0) AS peak
|
|
13
13
|
FROM task_usage
|
|
14
|
-
WHERE agent_name = ? AND task_id != ?`).get(
|
|
14
|
+
WHERE agent_name = ? AND task_id != ?`).get(n,e):r===`global`&&(o=i.prepare(`SELECT
|
|
15
15
|
COALESCE(SUM(input_tokens), 0) AS input,
|
|
16
16
|
COALESCE(SUM(output_tokens), 0) AS output,
|
|
17
17
|
COALESCE(SUM(model_calls), 0) AS calls,
|
|
18
18
|
COALESCE(MAX(peak_context_tokens), 0) AS peak
|
|
19
19
|
FROM task_usage
|
|
20
|
-
WHERE task_id != ?`).get(
|
|
20
|
+
WHERE task_id != ?`).get(e)),o)return{inputTokens:(o.input??0)+a.inputTokens,outputTokens:(o.output??0)+a.outputTokens,modelCalls:(o.calls??0)+a.modelCalls,peakContextTokens:Math.max(o.peak??0,a.peakContextTokens)}}catch{}return a}queryWindowTokens(e,t,n,r){if(!this.db)return 0;try{let i=this.db,a=new Date(Date.now()-n).toISOString(),o;if(e===`session`){let e=r?` AND tu.task_id != ?`:``,n=[t,a];r&&n.push(r),o=i.prepare(`SELECT COALESCE(SUM(tu.input_tokens + tu.output_tokens), 0) AS total
|
|
21
21
|
FROM task_usage tu
|
|
22
22
|
JOIN tasks t ON tu.task_id = t.id
|
|
23
|
-
WHERE t.session_id = ? AND tu.created_at >= ?${
|
|
23
|
+
WHERE t.session_id = ? AND tu.created_at >= ?${e}`).get(...n)}else if(e===`agent`){let e=r?` AND task_id != ?`:``,n=[t,a];r&&n.push(r),o=i.prepare(`SELECT COALESCE(SUM(input_tokens + output_tokens), 0) AS total
|
|
24
24
|
FROM task_usage
|
|
25
|
-
WHERE agent_name = ? AND created_at >= ?${
|
|
25
|
+
WHERE agent_name = ? AND created_at >= ?${e}`).get(...n)}else if(e===`global`){let e=r?` AND task_id != ?`:``,t=[a];r&&t.push(r),o=i.prepare(`SELECT COALESCE(SUM(input_tokens + output_tokens), 0) AS total
|
|
26
26
|
FROM task_usage
|
|
27
|
-
WHERE created_at >= ?${
|
|
28
|
-
|
|
29
|
-
[truncated: response was ${l} chars, limited to ${p.maximum}. ${p.message??"Use offset/limit or shell paging tools for full content."}]`}),r.content=m}break}}}const E=({db:c,config:t})=>{var r,a,l,p;const e=$(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;return new W(c,e,o,s,n,i)};exports.configSchema=O;exports.createPlugin=E;exports.default=E;exports.pluginConfigSchema=S;
|
|
27
|
+
WHERE created_at >= ?${e}`).get(...t)}return o?.total??0}catch{return 0}}buildSnapshot(e,t,r,i,a,o,s=0){let c={};c.inputTokens=t.inputTokens,c.outputTokens=t.outputTokens,c.calls=t.modelCalls,c.wallClock=Date.now()-t.startedAtMs,c.modelMs=t.totalModelMs,c.context=Math.max(t.peakContextTokens,s),c.errors=t.errors,c.consecutiveErrors=t.consecutiveErrors,c.cost=t.uncachedInputTokens*this.costPerInput+t.cacheReadTokens*this.costPerCacheRead+t.cacheCreationTokens*this.costPerCacheWrite+t.outputTokens*this.costPerOutput;let l=new Set,u=new Map;for(let t of e){let e=t.scope??o??`task`;if(e!==`task`&&l.add(e),t.window){let r=`${e}:${t.window}`;u.has(r)||u.set(r,{scope:e,windowMs:n(t.window)})}}for(let e of l){let t=this.queryScopeTotals(r,i,a,e);c[`${e}:inputTokens`]=t.inputTokens,c[`${e}:outputTokens`]=t.outputTokens,c[`${e}:calls`]=t.modelCalls,c[`${e}:context`]=Math.max(t.peakContextTokens,s)}for(let[e,{scope:t,windowMs:n}]of u){let o=``;t===`session`?o=i??``:t===`agent`&&(o=a??``),c[e]=this.queryWindowTokens(t,o,n,r)}return c}getSnapshotValue(e,t,n){let r=t.scope??n??`task`,i;i=t.window||r===`task`?``:`${r}:`;let a;switch(t.field){case`inputTokens`:a=e[`${i}inputTokens`]??e.inputTokens;break;case`outputTokens`:a=e[`${i}outputTokens`]??e.outputTokens;break;case`context`:a=e[`${i}context`]??e.context;break;case`calls`:a=e[`${i}calls`]??e.calls;break;case`wallClock`:a=e.wallClock;break;case`modelMs`:a=e.modelMs;break;case`cost`:a=e.cost;break;case`toolCalls`:a=0;break;case`errors`:a=e.errors;break;case`consecutiveErrors`:a=e.consecutiveErrors;break;default:a=0}return t.window&&(a+=e[`${r}:${t.window}`]??0),a}async emitBudgetEvent(e,t,n,r,i,a){this.hooks&&await this.hooks.emit(e,{executionContext:t,field:n.field,maximum:i,current:r,message:a??n.message??`${n.field} limit is ${i}, current value is ${Math.round(r)}`})}resolveCapLimit(e,n){if(e.maximum!==void 0)return e.maximum;let r=n.agentDefinition.provider;return Math.floor((0,t.contextWindowFor)(r.model)*(e.contextWindowFraction??0))}async evaluateCap(e,t,n,r,i){let a=this.resolveCapLimit(e,n),o=this.getSnapshotValue(t,e,i);if(!(o<a)){if((e.mode??r??`warning`)===`warning`){await this.emitBudgetEvent(`budget:warning`,n,e,o,a);return}throw await this.emitBudgetEvent(`budget:block`,n,e,o,a),h(e.field,a,o,e.message)}}async enforcePreModel(e){let{taskId:t,sessionId:n,agentName:r}=e.executionContext,a=e.executionContext.agentDefinition?.provider?.type??`unknown`,o=this.accumulators.get(t);if(!o)return;let{caps:s,mode:c,scope:l}=this.resolveCaps(r,a),u=s.filter(e=>!i.has(e.field));if(u.length===0)return;let d=this.buildSnapshot(u,o,t,n,r,l,_(e.messages,e.tools));for(let t of u)await this.evaluateCap(t,d,e.executionContext,c,l)}async enforcePreTool(e){let{toolName:t,callId:n,executionContext:r}=e,{caps:i,mode:a,scope:o}=this.resolveCaps(r.agentName,``,t),s=this.accumulators.get(r.taskId);if(!s)return;let c=i.filter(e=>e.field!==`context`);if(c.length===0)return;let l=s.toolCalls.get(t)??0,u=this.buildSnapshot(c,s,r.taskId,r.sessionId,r.agentName,o);for(let e of c){let i=this.resolveCapLimit(e,r),s=e.field===`toolCalls`?l:this.getSnapshotValue(u,e,o);if(s>=i){let o=e.message??`tool "${t}": ${e.field} limit is ${i}, current value is ${Math.round(s)}`;throw(e.mode??a??`warning`)===`warning`?(await this.emitBudgetEvent(`budget:warning`,r,e,s,i,o),g(t,n,o)):(await this.emitBudgetEvent(`budget:block`,r,e,s,i,o),h(`tool:${t}:${e.field}`,i,s,e.message))}}s.toolCalls.set(t,l+1)}enforceResponseSize(e){let{toolName:t,result:n}=e;if(typeof n!=`object`||!n)return;let{caps:r,mode:i}=this.resolveCaps(``,``,t),a=r.filter(e=>e.field===`responseSize`);if(a.length===0)return;let o=n,s=o.content;if(!Array.isArray(s))return;let c=0;for(let e of s)if(typeof e==`object`&&e){let t=e;t.type===`text`&&(c+=(t.text??``).length)}for(let t of a){let n=this.resolveCapLimit(t,e.executionContext);if(!(c<=n)){if((t.mode??i??`warning`)===`block`)o.content=[{type:`text`,text:t.message??`Response size (${c} chars) exceeds limit of ${n}. Use offset/limit or shell paging tools instead.`}],e.isError=!0;else{let e=n,r=[];for(let t of s){if(typeof t!=`object`||!t){r.push(t);continue}let n=t;if(n.type!==`text`){r.push(t);continue}let i=n.text??``;if(i.length<=e)r.push(t),e-=i.length;else{r.push({type:`text`,text:i.slice(0,e)});break}}r.push({type:`text`,text:`\n\n[truncated: response was ${c} chars, limited to ${t.maximum}. ${t.message??`Use offset/limit or shell paging tools for full content.`}]`}),o.content=r}break}}}},y=({db:e,config:t})=>{let n=m(t),r=n.defaults?.costPerInputToken??0;return new v(e,n,r,n.defaults?.costPerOutputToken??0,n.defaults?.costPerCacheReadToken??r,n.defaults?.costPerCacheWriteToken??r)};exports.configSchema=l,exports.createPlugin=y,exports.default=y,exports.pluginConfigSchema=c;
|