@adhd/agent-plugin-budget 0.0.7 โ†’ 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,43 @@
1
+ ## 0.2.0 (2026-08-11)
2
+
3
+
4
+ ### ๐Ÿš€ Features
5
+
6
+ - **agent-plugin-budget:** rename tokens cap to context with peak semantics + contextWindowFraction (Packet B, BUG-AGENTMCP-009)
7
+
8
+ - **agent-plugin-budget:** add errors/consecutiveErrors caps + reject tool-scoped context (Packet C, plan ยง8.9)
9
+
10
+
11
+ ### ๐Ÿฉน Fixes
12
+
13
+ - **apigen-cli:** restore 2768 files mass-deleted by 0117eb22 (BUG-APIGEN-052)
14
+
15
+ - **agent-plugin-budget:** cache-weighted cost enforcement (BUG-AGENTMCP-008)
16
+
17
+ - **agent-plugin-budget:** honor cap.mode on the model path with budget:warning/budget:block events (Packet A)
18
+
19
+ - **agent-plugin-budget:** emit budget:block on tool path; add typecheck targets (Packet A review F1/F5)
20
+
21
+ - **agent-plugin-budget:** reject windowed caps at task scope (F2 fold-in โ€” silent no-op class, plan ยง8.9-precedent)
22
+
23
+
24
+ ### โค๏ธ Thank You
25
+
26
+ - parity-harness-self-test
27
+ - pseudosky
28
+
29
+ ## 0.0.7 (2026-07-25)
30
+
31
+
32
+ ### ๐Ÿ”ฅ Performance
33
+
34
+ - **test:** bound vitest thread pools to curb CPU oversubscription (DEBT-TEST-CPU-OVERSUBSCRIBED-001)
35
+
36
+
37
+ ### โค๏ธ Thank You
38
+
39
+ - pseudosky
40
+
1
41
  ## 0.0.6 (2026-07-24)
2
42
 
3
43
  This was a version bump only for agent-plugin-budget to align it with other projects, there were no code changes.
package/README.md CHANGED
@@ -165,12 +165,16 @@ For the `cost` field, set token prices on the defaults dimension:
165
165
  "defaults": {
166
166
  "costPerInputToken": 0.000003,
167
167
  "costPerOutputToken": 0.000015,
168
+ "costPerCacheReadToken": 0.0000003,
169
+ "costPerCacheWriteToken": 0.00000375,
168
170
  "caps": [{ "field": "cost", "maximum": 0.1 }]
169
171
  }
170
172
  }
171
173
  ```
172
174
 
173
- Cost = `inputTokens ร— costPerInputToken + outputTokens ร— costPerOutputToken`.
175
+ Cost = `uncachedInputTokens ร— costPerInputToken + cacheReadTokens ร— costPerCacheReadToken + cacheCreationTokens ร— costPerCacheWriteToken + outputTokens ร— costPerOutputToken`.
176
+
177
+ `costPerCacheReadToken` and `costPerCacheWriteToken` default to `costPerInputToken` when unset, so a config that only sets the two flat rates bills every input token at the flat input rate โ€” identical to the pre-cache-aware behavior. To match a model's real rate card (e.g. DeepSeek: input `$0.14/M`, cache-read `$0.0028/M`), copy the per-class rates from the provider rate card; on cache-warm runs most input is cache-read, and billing it at the flat input rate over-counts spend by up to ~50x.
174
178
 
175
179
  ## Backward compat (flat format)
176
180
 
package/index.cjs CHANGED
@@ -1,26 +1,29 @@
1
- "use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const p=require("zod");function E(f){const e=/^P(?:(\d+)Y)?(?:(\d+)M)?(?:(\d+)D)?(?:T(?:(\d+)H)?(?:(\d+)M)?(?:(\d+(?:\.\d+)?)S)?)?$/,t=f.match(e);if(!t)throw new Error(`invalid ISO 8601 duration: ${f}`);const[,o,s,i,n,a,c]=t;let r=0;return o&&(r+=parseInt(o)*365.25*864e5),s&&(r+=parseInt(s)*30.44*864e5),i&&(r+=parseInt(i)*864e5),n&&(r+=parseInt(n)*36e5),a&&(r+=parseInt(a)*6e4),c&&(r+=parseFloat(c)*1e3),Math.round(r)}const w=["tokens","inputTokens","outputTokens","calls","wallClock","modelMs","cost","toolCalls","responseSize"],b=p.z.object({field:p.z.enum(w),maximum:p.z.number().min(0),window:p.z.string().optional(),scope:p.z.enum(["task","session","agent","global"]).optional(),mode:p.z.enum(["warning","block"]).optional(),message:p.z.string().optional()}),g=p.z.object({caps:p.z.array(b).optional(),mode:p.z.enum(["warning","block"]).optional(),costPerInputToken:p.z.number().min(0).optional(),costPerOutputToken:p.z.number().min(0).optional(),scope:p.z.enum(["task","session","agent","global"]).optional()}),T=p.z.object({defaults:g.optional(),agent:p.z.object({default:g.optional(),overrides:p.z.record(p.z.string(),g.partial()).optional().default({})}).optional(),provider:p.z.object({default:g.optional(),overrides:p.z.record(p.z.string(),g.partial()).optional().default({})}).optional(),tool:p.z.object({default:g.optional(),overrides:p.z.record(p.z.string(),g.partial()).optional().default({})}).optional()}),x=p.z.object({}).passthrough(),_={maxInputTokens:{field:"inputTokens"},maxOutputTokens:{field:"outputTokens"},maxTotalTokens:{field:"tokens"},maxModelCalls:{field:"calls"},maxWallClockMs:{field:"wallClock"},maxModelMs:{field:"modelMs"},maxCostUSD:{field:"cost"},maxTokensPer24h:{field:"tokens",window:"PT24H"},maxCalls:{field:"toolCalls"}};function v(f){const e=[],t={};for(const[o,s]of Object.entries(f)){const i=_[o];if(i&&typeof s=="number"){const n={field:i.field,maximum:s};i.window&&(n.window=i.window),e.push(n)}else(o==="scope"||o==="mode"||o==="costPerInputToken"||o==="costPerOutputToken"||o==="message")&&(t[o]=s)}return e.length>0&&(t.caps=e),g.parse(t)}function O(f){const e=f;if(e.defaults!==void 0||e.agent!==void 0||e.provider!==void 0||e.tool!==void 0){const t=T.parse(f);return{defaults:t.defaults??g.parse({}),agent:t.agent??{overrides:{}},provider:t.provider??{overrides:{}},tool:t.tool??{overrides:{}}}}return{defaults:v(e),agent:{overrides:{}},provider:{overrides:{}},tool:{overrides:{}}}}function S(f,e,t,o){return{isEnforcementError:!0,code:"BUDGET_EXCEEDED",message:o??`${f} limit is ${e}, current value is ${Math.round(t)}`}}function A(f,e,t){return{isToolWarning:!0,toolName:f,callId:e,message:t}}class y{constructor(e,t,o=0,s=0){this.db=e,this.cfg=t,this.costPerInput=o,this.costPerOutput=s,this.name="agent-mcp-budget",this.accumulators=new Map}install(e){e.register("task:start",t=>{try{this.onTaskStart(t)}catch{}}),e.register("pre:model_request",t=>{try{this.onPreModelRequest(t)}catch{}}),e.register("post:model_response",t=>{try{this.onPostModelResponse(t)}catch{}}),e.register("task:completed",t=>{try{this.onTerminal(t.executionContext.taskId)}catch{}}),e.register("task:failed",t=>{try{this.onTerminal(t.executionContext.taskId)}catch{}}),e.register("task:cancelled",t=>{try{this.onTerminal(t.executionContext.taskId)}catch{}}),e.registerEnforcement("pre:model_request",t=>this.enforcePreModel(t)),e.registerEnforcement("pre:tool_call",t=>this.enforcePreTool(t)),e.register("transform:tool_result",t=>{try{this.enforceResponseSize(t)}catch{}})}onTaskStart(e){var n,a;const{taskId:t,sessionId:o,agentName:s}=e.executionContext,i=((a=(n=e.executionContext.agentDefinition)==null?void 0:n.provider)==null?void 0:a.type)??"unknown";this.accumulators.set(t,{taskId:t,sessionId:o??void 0,agentName:s,providerType:i,startedAtMs:Date.now(),inputTokens:0,outputTokens:0,modelCalls:0,totalModelMs:0,toolCalls:new Map})}onPreModelRequest(e){const t=this.accumulators.get(e.executionContext.taskId);t&&(t.modelCallStartMs=Date.now())}onPostModelResponse(e){const t=this.accumulators.get(e.executionContext.taskId);if(!t)return;const o=e.tokenUsage;o&&(t.inputTokens+=o.inputTokens??0,t.outputTokens+=o.outputTokens??0),t.modelCalls+=1,t.modelCallStartMs!==void 0&&(t.totalModelMs+=Date.now()-t.modelCallStartMs,t.modelCallStartMs=void 0)}onTerminal(e){this.accumulators.delete(e)}mergeDim(e){let t={caps:[]};for(const o of e)o&&(t={caps:[...t.caps??[],...o.caps??[]],mode:o.mode??t.mode,costPerInputToken:o.costPerInputToken??t.costPerInputToken,costPerOutputToken:o.costPerOutputToken??t.costPerOutputToken,scope:o.scope??t.scope});return t}resolveCaps(e,t,o){var u,m,d;const s=this.cfg.defaults,i=this.cfg.agent,n=this.cfg.provider,a=this.cfg.tool;if(o){const k=(u=a==null?void 0:a.overrides)==null?void 0:u[o],h=this.mergeDim([s,a==null?void 0:a.default,k]);return{caps:h.caps??[],mode:h.mode,scope:h.scope}}const c=(m=i==null?void 0:i.overrides)==null?void 0:m[e],r=(d=n==null?void 0:n.overrides)==null?void 0:d[t],l=this.mergeDim([s,i==null?void 0:i.default,c,n==null?void 0:n.default,r]);return{caps:l.caps??[],mode:l.mode,scope:l.scope}}queryScopeTotals(e,t,o,s){const i=this.accumulators.get(e),n=i?{inputTokens:i.inputTokens,outputTokens:i.outputTokens,modelCalls:i.modelCalls}:{inputTokens:0,outputTokens:0,modelCalls:0};if(s==="task"||!this.db)return n;try{const a=this.db;let c;if(s==="session"&&t?c=a.prepare(`SELECT
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
2
2
  COALESCE(SUM(tu.input_tokens), 0) AS input,
3
3
  COALESCE(SUM(tu.output_tokens), 0) AS output,
4
- COALESCE(SUM(tu.model_calls), 0) AS calls
4
+ COALESCE(SUM(tu.model_calls), 0) AS calls,
5
+ COALESCE(MAX(tu.peak_context_tokens), 0) AS peak
5
6
  FROM task_usage tu
6
7
  JOIN tasks t ON tu.task_id = t.id
7
- WHERE t.session_id = ? AND tu.task_id != ?`).get(t,e):s==="agent"?c=a.prepare(`SELECT
8
+ WHERE t.session_id = ? AND tu.task_id != ?`).get(e,t):s==="agent"?a=r.prepare(`SELECT
8
9
  COALESCE(SUM(input_tokens), 0) AS input,
9
10
  COALESCE(SUM(output_tokens), 0) AS output,
10
- COALESCE(SUM(model_calls), 0) AS calls
11
+ COALESCE(SUM(model_calls), 0) AS calls,
12
+ COALESCE(MAX(peak_context_tokens), 0) AS peak
11
13
  FROM task_usage
12
- WHERE agent_name = ? AND task_id != ?`).get(o,e):s==="global"&&(c=a.prepare(`SELECT
14
+ WHERE agent_name = ? AND task_id != ?`).get(o,t):s==="global"&&(a=r.prepare(`SELECT
13
15
  COALESCE(SUM(input_tokens), 0) AS input,
14
16
  COALESCE(SUM(output_tokens), 0) AS output,
15
- COALESCE(SUM(model_calls), 0) AS calls
17
+ COALESCE(SUM(model_calls), 0) AS calls,
18
+ COALESCE(MAX(peak_context_tokens), 0) AS peak
16
19
  FROM task_usage
17
- WHERE task_id != ?`).get(e)),c)return{inputTokens:(c.input??0)+n.inputTokens,outputTokens:(c.output??0)+n.outputTokens,modelCalls:(c.calls??0)+n.modelCalls}}catch{}return n}queryWindowTokens(e,t,o,s){if(!this.db)return 0;try{const i=this.db,n=new Date(Date.now()-o).toISOString();let a;if(e==="session"){const c=s?" AND tu.task_id != ?":"",r=[t,n];s&&r.push(s),a=i.prepare(`SELECT COALESCE(SUM(tu.input_tokens + tu.output_tokens), 0) AS total
20
+ WHERE task_id != ?`).get(t)),a)return{inputTokens:(a.input??0)+i.inputTokens,outputTokens:(a.output??0)+i.outputTokens,modelCalls:(a.calls??0)+i.modelCalls,peakContextTokens:Math.max(a.peak??0,i.peakContextTokens)}}catch{}return i}queryWindowTokens(t,e,o,s){if(!this.db)return 0;try{const n=this.db,i=new Date(Date.now()-o).toISOString();let r;if(t==="session"){const a=s?" AND tu.task_id != ?":"",l=[e,i];s&&l.push(s),r=n.prepare(`SELECT COALESCE(SUM(tu.input_tokens + tu.output_tokens), 0) AS total
18
21
  FROM task_usage tu
19
22
  JOIN tasks t ON tu.task_id = t.id
20
- WHERE t.session_id = ? AND tu.created_at >= ?${c}`).get(...r)}else if(e==="agent"){const c=s?" AND task_id != ?":"",r=[t,n];s&&r.push(s),a=i.prepare(`SELECT COALESCE(SUM(input_tokens + output_tokens), 0) AS total
23
+ WHERE t.session_id = ? AND tu.created_at >= ?${a}`).get(...l)}else if(t==="agent"){const a=s?" AND task_id != ?":"",l=[e,i];s&&l.push(s),r=n.prepare(`SELECT COALESCE(SUM(input_tokens + output_tokens), 0) AS total
21
24
  FROM task_usage
22
- WHERE agent_name = ? AND created_at >= ?${c}`).get(...r)}else if(e==="global"){const c=s?" AND task_id != ?":"",r=[n];s&&r.push(s),a=i.prepare(`SELECT COALESCE(SUM(input_tokens + output_tokens), 0) AS total
25
+ WHERE agent_name = ? AND created_at >= ?${a}`).get(...l)}else if(t==="global"){const a=s?" AND task_id != ?":"",l=[i];s&&l.push(s),r=n.prepare(`SELECT COALESCE(SUM(input_tokens + output_tokens), 0) AS total
23
26
  FROM task_usage
24
- WHERE created_at >= ?${c}`).get(...r)}return(a==null?void 0:a.total)??0}catch{return 0}}buildSnapshot(e,t,o,s,i,n){const a={};a.inputTokens=t.inputTokens,a.outputTokens=t.outputTokens,a.calls=t.modelCalls,a.wallClock=Date.now()-t.startedAtMs,a.modelMs=t.totalModelMs,a.cost=t.inputTokens*this.costPerInput+t.outputTokens*this.costPerOutput;const c=new Set,r=new Map;for(const l of e){const u=l.scope??n??"task";if(u!=="task"&&c.add(u),l.window){const m=`${u}:${l.window}`;r.has(m)||r.set(m,{scope:u,windowMs:E(l.window)})}}for(const l of c){const u=this.queryScopeTotals(o,s,i,l);a[`${l}:inputTokens`]=u.inputTokens,a[`${l}:outputTokens`]=u.outputTokens,a[`${l}:calls`]=u.modelCalls}for(const[l,{scope:u,windowMs:m}]of r){let d="";u==="session"?d=s??"":u==="agent"&&(d=i??""),a[l]=this.queryWindowTokens(u,d,m,o)}return a}getSnapshotValue(e,t,o){const s=t.scope??o??"task";let i;t.window?i="":i=s!=="task"?`${s}:`:"";let n;switch(t.field){case"inputTokens":n=e[`${i}inputTokens`]??e.inputTokens;break;case"outputTokens":n=e[`${i}outputTokens`]??e.outputTokens;break;case"tokens":n=(e[`${i}inputTokens`]??e.inputTokens)+(e[`${i}outputTokens`]??e.outputTokens);break;case"calls":n=e[`${i}calls`]??e.calls;break;case"wallClock":n=e.wallClock;break;case"modelMs":n=e.modelMs;break;case"cost":n=e.cost;break;case"toolCalls":n=0;break;default:n=0}return t.window&&(n+=e[`${s}:${t.window}`]??0),n}evaluateCap(e,t,o){const s=this.getSnapshotValue(t,e,o);if(s>=e.maximum)throw S(e.field,e.maximum,s,e.message)}enforcePreModel(e){var u,m;const{taskId:t,sessionId:o,agentName:s}=e.executionContext,i=((m=(u=e.executionContext.agentDefinition)==null?void 0:u.provider)==null?void 0:m.type)??"unknown",n=this.accumulators.get(t);if(!n)return;const{caps:a,scope:c}=this.resolveCaps(s,i),r=a.filter(d=>d.field!=="toolCalls");if(r.length===0)return;const l=this.buildSnapshot(r,n,t,o,s,c);for(const d of r)this.evaluateCap(d,l)}enforcePreTool(e){const{toolName:t,callId:o,executionContext:s}=e,{caps:i,mode:n,scope:a}=this.resolveCaps(s.agentName,"",t),c=this.accumulators.get(s.taskId);if(!c||i.length===0)return;const r=c.toolCalls.get(t)??0,l=this.buildSnapshot(i,c,s.taskId,s.sessionId,s.agentName,a);for(const u of i){const m=u.field==="toolCalls"?r:this.getSnapshotValue(l,u,a);if(m>=u.maximum){const d=u.message??`tool "${t}": ${u.field} limit is ${u.maximum}, current value is ${Math.round(m)}`;throw(u.mode??n??"warning")==="warning"?A(t,o,d):S(`tool:${t}:${u.field}`,u.maximum,m,u.message)}}c.toolCalls.set(t,r+1)}enforceResponseSize(e){const{toolName:t,result:o}=e;if(typeof o!="object"||o===null)return;const{caps:s,mode:i}=this.resolveCaps("","",t),n=s.filter(l=>l.field==="responseSize");if(n.length===0)return;const a=o,c=a.content;if(!Array.isArray(c))return;let r=0;for(const l of c)if(typeof l=="object"&&l!==null){const u=l;u.type==="text"&&(r+=(u.text??"").length)}for(const l of n){if(r<=l.maximum)continue;if((l.mode??i??"warning")==="block")a.content=[{type:"text",text:l.message??`Response size (${r} chars) exceeds limit of ${l.maximum}. Use offset/limit or shell paging tools instead.`}],e.isError=!0;else{let m=l.maximum;const d=[];for(const k of c){if(typeof k!="object"||k===null){d.push(k);continue}const h=k;if(h.type!=="text"){d.push(k);continue}const C=h.text??"";if(C.length<=m)d.push(k),m-=C.length;else{d.push({type:"text",text:C.slice(0,m)});break}}d.push({type:"text",text:`
27
+ WHERE created_at >= ?${a}`).get(...l)}return(r==null?void 0:r.total)??0}catch{return 0}}buildSnapshot(t,e,o,s,n,i,r=0){const a={};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;const l=new Set,p=new Map;for(const f of t){const d=f.scope??i??"task";if(d!=="task"&&l.add(d),f.window){const k=`${d}:${f.window}`;p.has(k)||p.set(k,{scope:d,windowMs:b(f.window)})}}for(const f of l){const d=this.queryScopeTotals(o,s,n,f);a[`${f}:inputTokens`]=d.inputTokens,a[`${f}:outputTokens`]=d.outputTokens,a[`${f}:calls`]=d.modelCalls,a[`${f}:context`]=Math.max(d.peakContextTokens,r)}for(const[f,{scope:d,windowMs:k}]of p){let m="";d==="session"?m=s??"":d==="agent"&&(m=n??""),a[f]=this.queryWindowTokens(d,m,k,o)}return a}getSnapshotValue(t,e,o){const s=e.scope??o??"task";let n;e.window?n="":n=s!=="task"?`${s}:`:"";let i;switch(e.field){case"inputTokens":i=t[`${n}inputTokens`]??t.inputTokens;break;case"outputTokens":i=t[`${n}outputTokens`]??t.outputTokens;break;case"context":i=t[`${n}context`]??t.context;break;case"calls":i=t[`${n}calls`]??t.calls;break;case"wallClock":i=t.wallClock;break;case"modelMs":i=t.modelMs;break;case"cost":i=t.cost;break;case"toolCalls":i=0;break;case"errors":i=t.errors;break;case"consecutiveErrors":i=t.consecutiveErrors;break;default:i=0}return e.window&&(i+=t[`${s}:${e.window}`]??0),i}async emitBudgetEvent(t,e,o,s,n,i){this.hooks&&await this.hooks.emit(t,{executionContext:e,field:o.field,maximum:n,current:s,message:i??o.message??`${o.field} limit is ${n}, current value is ${Math.round(s)}`})}resolveCapLimit(t,e){if(t.maximum!==void 0)return t.maximum;const o=e.agentDefinition.provider;return Math.floor(M.contextWindowFor(o.model)*(t.contextWindowFraction??0))}async evaluateCap(t,e,o,s,n){const i=this.resolveCapLimit(t,o),r=this.getSnapshotValue(e,t,n);if(r<i)return;if((t.mode??s??"warning")==="warning"){await this.emitBudgetEvent("budget:warning",o,t,r,i);return}throw await this.emitBudgetEvent("budget:block",o,t,r,i),v(t.field,i,r,t.message)}async enforcePreModel(t){var d,k;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);if(!i)return;const{caps:r,mode:a,scope:l}=this.resolveCaps(s,n),p=r.filter(m=>!_.has(m.field));if(p.length===0)return;const f=this.buildSnapshot(p,i,e,o,s,l,L(t.messages,t.tools));for(const m of p)await this.evaluateCap(m,f,t.executionContext,a,l)}async enforcePreTool(t){const{toolName:e,callId:o,executionContext:s}=t,{caps:n,mode:i,scope:r}=this.resolveCaps(s.agentName,"",e),a=this.accumulators.get(s.taskId);if(!a)return;const l=n.filter(d=>d.field!=="context");if(l.length===0)return;const p=a.toolCalls.get(e)??0,f=this.buildSnapshot(l,a,s.taskId,s.sessionId,s.agentName,r);for(const d of l){const k=this.resolveCapLimit(d,s),m=d.field==="toolCalls"?p:this.getSnapshotValue(f,d,r);if(m>=k){const h=d.message??`tool "${e}": ${d.field} limit is ${k}, current value is ${Math.round(m)}`;throw(d.mode??i??"warning")==="warning"?(await this.emitBudgetEvent("budget:warning",s,d,m,k,h),R(e,o,h)):(await this.emitBudgetEvent("budget:block",s,d,m,k,h),v(`tool:${e}:${d.field}`,k,m,d.message))}}a.toolCalls.set(e,p+1)}enforceResponseSize(t){const{toolName:e,result:o}=t;if(typeof o!="object"||o===null)return;const{caps:s,mode:n}=this.resolveCaps("","",e),i=s.filter(p=>p.field==="responseSize");if(i.length===0)return;const r=o,a=r.content;if(!Array.isArray(a))return;let l=0;for(const p of a)if(typeof p=="object"&&p!==null){const f=p;f.type==="text"&&(l+=(f.text??"").length)}for(const p of i){const f=this.resolveCapLimit(p,t.executionContext);if(l<=f)continue;if((p.mode??n??"warning")==="block")r.content=[{type:"text",text:p.message??`Response size (${l} chars) exceeds limit of ${f}. Use offset/limit or shell paging tools instead.`}],t.isError=!0;else{let k=f;const m=[];for(const h of a){if(typeof h!="object"||h===null){m.push(h);continue}const C=h;if(C.type!=="text"){m.push(h);continue}const T=C.text??"";if(T.length<=k)m.push(h),k-=T.length;else{m.push({type:"text",text:T.slice(0,k)});break}}m.push({type:"text",text:`
25
28
 
26
- [truncated: response was ${r} chars, limited to ${l.maximum}. ${l.message??"Use offset/limit or shell paging tools for full content."}]`}),a.content=d}break}}}const M=({db:f,config:e})=>{var i,n;const t=O(e),o=((i=t.defaults)==null?void 0:i.costPerInputToken)??0,s=((n=t.defaults)==null?void 0:n.costPerOutputToken)??0;return new y(f,t,o,s)};exports.configSchema=x;exports.createPlugin=M;exports.default=M;exports.pluginConfigSchema=T;
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;
package/index.d.ts CHANGED
@@ -1,9 +1,20 @@
1
1
  import { PluginFactory } from '@adhd/agent-base-types';
2
2
  import { z } from 'zod';
3
3
 
4
+ /**
5
+ * Cap schema. `maximum` is optional at the base level because a `context` cap may
6
+ * instead use `contextWindowFraction` (0..1 of the model's true window); the
7
+ * superRefine below enforces the cross-field invariants:
8
+ * - `context` requires EXACTLY ONE of `maximum` / `contextWindowFraction`;
9
+ * - `context` REJECTS `window` (a windowed PEAK is meaningless; windowed
10
+ * cumulative volume is expressible via `inputTokens`/`outputTokens` + `window`);
11
+ * - non-`context` fields REJECT `contextWindowFraction` and REQUIRE `maximum`;
12
+ * - `errors`/`consecutiveErrors` REJECT `window` and non-task `scope`
13
+ * (Packet C โ€” windowed/scoped error budgets are not expressible this wave).
14
+ */
4
15
  declare const capSchema: z.ZodObject<{
5
16
  field: z.ZodEnum<{
6
- tokens: "tokens";
17
+ context: "context";
7
18
  inputTokens: "inputTokens";
8
19
  outputTokens: "outputTokens";
9
20
  calls: "calls";
@@ -11,9 +22,12 @@ declare const capSchema: z.ZodObject<{
11
22
  modelMs: "modelMs";
12
23
  cost: "cost";
13
24
  toolCalls: "toolCalls";
25
+ errors: "errors";
26
+ consecutiveErrors: "consecutiveErrors";
14
27
  responseSize: "responseSize";
15
28
  }>;
16
- maximum: z.ZodNumber;
29
+ maximum: z.ZodOptional<z.ZodNumber>;
30
+ contextWindowFraction: z.ZodOptional<z.ZodNumber>;
17
31
  window: z.ZodOptional<z.ZodString>;
18
32
  scope: z.ZodOptional<z.ZodEnum<{
19
33
  task: "task";
@@ -32,7 +46,7 @@ export declare const pluginConfigSchema: z.ZodObject<{
32
46
  defaults: z.ZodOptional<z.ZodObject<{
33
47
  caps: z.ZodOptional<z.ZodArray<z.ZodObject<{
34
48
  field: z.ZodEnum<{
35
- tokens: "tokens";
49
+ context: "context";
36
50
  inputTokens: "inputTokens";
37
51
  outputTokens: "outputTokens";
38
52
  calls: "calls";
@@ -40,9 +54,12 @@ export declare const pluginConfigSchema: z.ZodObject<{
40
54
  modelMs: "modelMs";
41
55
  cost: "cost";
42
56
  toolCalls: "toolCalls";
57
+ errors: "errors";
58
+ consecutiveErrors: "consecutiveErrors";
43
59
  responseSize: "responseSize";
44
60
  }>;
45
- maximum: z.ZodNumber;
61
+ maximum: z.ZodOptional<z.ZodNumber>;
62
+ contextWindowFraction: z.ZodOptional<z.ZodNumber>;
46
63
  window: z.ZodOptional<z.ZodString>;
47
64
  scope: z.ZodOptional<z.ZodEnum<{
48
65
  task: "task";
@@ -62,6 +79,8 @@ export declare const pluginConfigSchema: z.ZodObject<{
62
79
  }>>;
63
80
  costPerInputToken: z.ZodOptional<z.ZodNumber>;
64
81
  costPerOutputToken: z.ZodOptional<z.ZodNumber>;
82
+ costPerCacheReadToken: z.ZodOptional<z.ZodNumber>;
83
+ costPerCacheWriteToken: z.ZodOptional<z.ZodNumber>;
65
84
  scope: z.ZodOptional<z.ZodEnum<{
66
85
  task: "task";
67
86
  session: "session";
@@ -73,7 +92,7 @@ export declare const pluginConfigSchema: z.ZodObject<{
73
92
  default: z.ZodOptional<z.ZodObject<{
74
93
  caps: z.ZodOptional<z.ZodArray<z.ZodObject<{
75
94
  field: z.ZodEnum<{
76
- tokens: "tokens";
95
+ context: "context";
77
96
  inputTokens: "inputTokens";
78
97
  outputTokens: "outputTokens";
79
98
  calls: "calls";
@@ -81,9 +100,12 @@ export declare const pluginConfigSchema: z.ZodObject<{
81
100
  modelMs: "modelMs";
82
101
  cost: "cost";
83
102
  toolCalls: "toolCalls";
103
+ errors: "errors";
104
+ consecutiveErrors: "consecutiveErrors";
84
105
  responseSize: "responseSize";
85
106
  }>;
86
- maximum: z.ZodNumber;
107
+ maximum: z.ZodOptional<z.ZodNumber>;
108
+ contextWindowFraction: z.ZodOptional<z.ZodNumber>;
87
109
  window: z.ZodOptional<z.ZodString>;
88
110
  scope: z.ZodOptional<z.ZodEnum<{
89
111
  task: "task";
@@ -103,6 +125,8 @@ export declare const pluginConfigSchema: z.ZodObject<{
103
125
  }>>;
104
126
  costPerInputToken: z.ZodOptional<z.ZodNumber>;
105
127
  costPerOutputToken: z.ZodOptional<z.ZodNumber>;
128
+ costPerCacheReadToken: z.ZodOptional<z.ZodNumber>;
129
+ costPerCacheWriteToken: z.ZodOptional<z.ZodNumber>;
106
130
  scope: z.ZodOptional<z.ZodEnum<{
107
131
  task: "task";
108
132
  session: "session";
@@ -113,7 +137,7 @@ export declare const pluginConfigSchema: z.ZodObject<{
113
137
  overrides: z.ZodDefault<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
114
138
  caps: z.ZodOptional<z.ZodOptional<z.ZodArray<z.ZodObject<{
115
139
  field: z.ZodEnum<{
116
- tokens: "tokens";
140
+ context: "context";
117
141
  inputTokens: "inputTokens";
118
142
  outputTokens: "outputTokens";
119
143
  calls: "calls";
@@ -121,9 +145,12 @@ export declare const pluginConfigSchema: z.ZodObject<{
121
145
  modelMs: "modelMs";
122
146
  cost: "cost";
123
147
  toolCalls: "toolCalls";
148
+ errors: "errors";
149
+ consecutiveErrors: "consecutiveErrors";
124
150
  responseSize: "responseSize";
125
151
  }>;
126
- maximum: z.ZodNumber;
152
+ maximum: z.ZodOptional<z.ZodNumber>;
153
+ contextWindowFraction: z.ZodOptional<z.ZodNumber>;
127
154
  window: z.ZodOptional<z.ZodString>;
128
155
  scope: z.ZodOptional<z.ZodEnum<{
129
156
  task: "task";
@@ -143,6 +170,8 @@ export declare const pluginConfigSchema: z.ZodObject<{
143
170
  }>>>;
144
171
  costPerInputToken: z.ZodOptional<z.ZodOptional<z.ZodNumber>>;
145
172
  costPerOutputToken: z.ZodOptional<z.ZodOptional<z.ZodNumber>>;
173
+ costPerCacheReadToken: z.ZodOptional<z.ZodOptional<z.ZodNumber>>;
174
+ costPerCacheWriteToken: z.ZodOptional<z.ZodOptional<z.ZodNumber>>;
146
175
  scope: z.ZodOptional<z.ZodOptional<z.ZodEnum<{
147
176
  task: "task";
148
177
  session: "session";
@@ -155,7 +184,7 @@ export declare const pluginConfigSchema: z.ZodObject<{
155
184
  default: z.ZodOptional<z.ZodObject<{
156
185
  caps: z.ZodOptional<z.ZodArray<z.ZodObject<{
157
186
  field: z.ZodEnum<{
158
- tokens: "tokens";
187
+ context: "context";
159
188
  inputTokens: "inputTokens";
160
189
  outputTokens: "outputTokens";
161
190
  calls: "calls";
@@ -163,9 +192,12 @@ export declare const pluginConfigSchema: z.ZodObject<{
163
192
  modelMs: "modelMs";
164
193
  cost: "cost";
165
194
  toolCalls: "toolCalls";
195
+ errors: "errors";
196
+ consecutiveErrors: "consecutiveErrors";
166
197
  responseSize: "responseSize";
167
198
  }>;
168
- maximum: z.ZodNumber;
199
+ maximum: z.ZodOptional<z.ZodNumber>;
200
+ contextWindowFraction: z.ZodOptional<z.ZodNumber>;
169
201
  window: z.ZodOptional<z.ZodString>;
170
202
  scope: z.ZodOptional<z.ZodEnum<{
171
203
  task: "task";
@@ -185,6 +217,8 @@ export declare const pluginConfigSchema: z.ZodObject<{
185
217
  }>>;
186
218
  costPerInputToken: z.ZodOptional<z.ZodNumber>;
187
219
  costPerOutputToken: z.ZodOptional<z.ZodNumber>;
220
+ costPerCacheReadToken: z.ZodOptional<z.ZodNumber>;
221
+ costPerCacheWriteToken: z.ZodOptional<z.ZodNumber>;
188
222
  scope: z.ZodOptional<z.ZodEnum<{
189
223
  task: "task";
190
224
  session: "session";
@@ -195,7 +229,7 @@ export declare const pluginConfigSchema: z.ZodObject<{
195
229
  overrides: z.ZodDefault<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
196
230
  caps: z.ZodOptional<z.ZodOptional<z.ZodArray<z.ZodObject<{
197
231
  field: z.ZodEnum<{
198
- tokens: "tokens";
232
+ context: "context";
199
233
  inputTokens: "inputTokens";
200
234
  outputTokens: "outputTokens";
201
235
  calls: "calls";
@@ -203,9 +237,12 @@ export declare const pluginConfigSchema: z.ZodObject<{
203
237
  modelMs: "modelMs";
204
238
  cost: "cost";
205
239
  toolCalls: "toolCalls";
240
+ errors: "errors";
241
+ consecutiveErrors: "consecutiveErrors";
206
242
  responseSize: "responseSize";
207
243
  }>;
208
- maximum: z.ZodNumber;
244
+ maximum: z.ZodOptional<z.ZodNumber>;
245
+ contextWindowFraction: z.ZodOptional<z.ZodNumber>;
209
246
  window: z.ZodOptional<z.ZodString>;
210
247
  scope: z.ZodOptional<z.ZodEnum<{
211
248
  task: "task";
@@ -225,6 +262,8 @@ export declare const pluginConfigSchema: z.ZodObject<{
225
262
  }>>>;
226
263
  costPerInputToken: z.ZodOptional<z.ZodOptional<z.ZodNumber>>;
227
264
  costPerOutputToken: z.ZodOptional<z.ZodOptional<z.ZodNumber>>;
265
+ costPerCacheReadToken: z.ZodOptional<z.ZodOptional<z.ZodNumber>>;
266
+ costPerCacheWriteToken: z.ZodOptional<z.ZodOptional<z.ZodNumber>>;
228
267
  scope: z.ZodOptional<z.ZodOptional<z.ZodEnum<{
229
268
  task: "task";
230
269
  session: "session";
@@ -235,9 +274,9 @@ export declare const pluginConfigSchema: z.ZodObject<{
235
274
  }, z.core.$strip>>;
236
275
  tool: z.ZodOptional<z.ZodObject<{
237
276
  default: z.ZodOptional<z.ZodObject<{
238
- caps: z.ZodOptional<z.ZodArray<z.ZodObject<{
277
+ caps: z.ZodOptional<z.ZodOptional<z.ZodArray<z.ZodObject<{
239
278
  field: z.ZodEnum<{
240
- tokens: "tokens";
279
+ context: "context";
241
280
  inputTokens: "inputTokens";
242
281
  outputTokens: "outputTokens";
243
282
  calls: "calls";
@@ -245,9 +284,12 @@ export declare const pluginConfigSchema: z.ZodObject<{
245
284
  modelMs: "modelMs";
246
285
  cost: "cost";
247
286
  toolCalls: "toolCalls";
287
+ errors: "errors";
288
+ consecutiveErrors: "consecutiveErrors";
248
289
  responseSize: "responseSize";
249
290
  }>;
250
- maximum: z.ZodNumber;
291
+ maximum: z.ZodOptional<z.ZodNumber>;
292
+ contextWindowFraction: z.ZodOptional<z.ZodNumber>;
251
293
  window: z.ZodOptional<z.ZodString>;
252
294
  scope: z.ZodOptional<z.ZodEnum<{
253
295
  task: "task";
@@ -260,24 +302,26 @@ export declare const pluginConfigSchema: z.ZodObject<{
260
302
  block: "block";
261
303
  }>>;
262
304
  message: z.ZodOptional<z.ZodString>;
263
- }, z.core.$strip>>>;
264
- mode: z.ZodOptional<z.ZodEnum<{
305
+ }, z.core.$strip>>>>;
306
+ mode: z.ZodOptional<z.ZodOptional<z.ZodEnum<{
265
307
  warning: "warning";
266
308
  block: "block";
267
- }>>;
268
- costPerInputToken: z.ZodOptional<z.ZodNumber>;
269
- costPerOutputToken: z.ZodOptional<z.ZodNumber>;
270
- scope: z.ZodOptional<z.ZodEnum<{
309
+ }>>>;
310
+ costPerInputToken: z.ZodOptional<z.ZodOptional<z.ZodNumber>>;
311
+ costPerOutputToken: z.ZodOptional<z.ZodOptional<z.ZodNumber>>;
312
+ costPerCacheReadToken: z.ZodOptional<z.ZodOptional<z.ZodNumber>>;
313
+ costPerCacheWriteToken: z.ZodOptional<z.ZodOptional<z.ZodNumber>>;
314
+ scope: z.ZodOptional<z.ZodOptional<z.ZodEnum<{
271
315
  task: "task";
272
316
  session: "session";
273
317
  agent: "agent";
274
318
  global: "global";
275
- }>>;
319
+ }>>>;
276
320
  }, z.core.$strip>>;
277
321
  overrides: z.ZodDefault<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
278
322
  caps: z.ZodOptional<z.ZodOptional<z.ZodArray<z.ZodObject<{
279
323
  field: z.ZodEnum<{
280
- tokens: "tokens";
324
+ context: "context";
281
325
  inputTokens: "inputTokens";
282
326
  outputTokens: "outputTokens";
283
327
  calls: "calls";
@@ -285,9 +329,12 @@ export declare const pluginConfigSchema: z.ZodObject<{
285
329
  modelMs: "modelMs";
286
330
  cost: "cost";
287
331
  toolCalls: "toolCalls";
332
+ errors: "errors";
333
+ consecutiveErrors: "consecutiveErrors";
288
334
  responseSize: "responseSize";
289
335
  }>;
290
- maximum: z.ZodNumber;
336
+ maximum: z.ZodOptional<z.ZodNumber>;
337
+ contextWindowFraction: z.ZodOptional<z.ZodNumber>;
291
338
  window: z.ZodOptional<z.ZodString>;
292
339
  scope: z.ZodOptional<z.ZodEnum<{
293
340
  task: "task";
@@ -307,6 +354,8 @@ export declare const pluginConfigSchema: z.ZodObject<{
307
354
  }>>>;
308
355
  costPerInputToken: z.ZodOptional<z.ZodOptional<z.ZodNumber>>;
309
356
  costPerOutputToken: z.ZodOptional<z.ZodOptional<z.ZodNumber>>;
357
+ costPerCacheReadToken: z.ZodOptional<z.ZodOptional<z.ZodNumber>>;
358
+ costPerCacheWriteToken: z.ZodOptional<z.ZodOptional<z.ZodNumber>>;
310
359
  scope: z.ZodOptional<z.ZodOptional<z.ZodEnum<{
311
360
  task: "task";
312
361
  session: "session";