@neurameter/core 0.1.5 → 0.1.6
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/dist/index.cjs +6 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +35 -1
- package/dist/index.d.ts +35 -1
- package/dist/index.js +6 -6
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
'use strict';var
|
|
1
|
+
'use strict';var f={"gpt-4o":128e3,"gpt-4o-mini":128e3,"gpt-4.1":1e6,"gpt-4.1-mini":1e6,o1:2e5,"o3-mini":2e5,"claude-sonnet-4-20250514":2e5,"claude-haiku-4-5-20251001":2e5,"claude-opus-4-20250514":2e5,"claude-sonnet-4":2e5,"claude-haiku-4":2e5,"claude-opus-4":2e5};function C(t){if(typeof t!="string"){let e=typeof t=="object"?JSON.stringify(t):String(t??"");return Math.ceil(e.length/4)}return Math.ceil(t.length/4)}function _(t,e){let r=b(e),o=0,n=0,i=0;for(let a of t){let c=C(a.content);a.role==="system"?o+=c:a.role==="tool"?i+=c:n+=c;}let s=o+n+i;return {estimatedInputTokens:s,modelContextLimit:r,utilizationPercent:r>0?s/r:0,messageCount:t.length,systemPromptTokens:o,conversationTokens:n,toolResultTokens:i}}function b(t){if(f[t]!==void 0)return f[t];for(let[e,r]of Object.entries(f))if(t.startsWith(e))return r;return 128e3}function d(t,e){let r=0,o=t.inputTokens-(t.cachedTokens??0);if(o>0&&(r+=y(o*e.inputPricePerMToken,1e6)),t.cachedTokens&&t.cachedTokens>0){let n=e.cachedInputPricePerMToken??e.inputPricePerMToken;r+=y(t.cachedTokens*n,1e6);}if(t.outputTokens>0&&(r+=y(t.outputTokens*e.outputPricePerMToken,1e6)),t.reasoningTokens&&t.reasoningTokens>0){let n=e.reasoningPricePerMToken??e.outputPricePerMToken;r+=y(t.reasoningTokens*n,1e6);}return r}function y(t,e){let r=Math.trunc(t/e);return (t-r*e)*2>=e?r+1:r}var S={openai:{"gpt-4o":{inputPricePerMToken:25e5,outputPricePerMToken:1e7,cachedInputPricePerMToken:125e4},"gpt-4o-mini":{inputPricePerMToken:15e4,outputPricePerMToken:6e5,cachedInputPricePerMToken:75e3},"gpt-4.1":{inputPricePerMToken:2e6,outputPricePerMToken:8e6,cachedInputPricePerMToken:5e5},"gpt-4.1-mini":{inputPricePerMToken:4e5,outputPricePerMToken:16e5,cachedInputPricePerMToken:1e5},o1:{inputPricePerMToken:15e6,outputPricePerMToken:6e7,reasoningPricePerMToken:6e7,cachedInputPricePerMToken:75e5},"o3-mini":{inputPricePerMToken:11e5,outputPricePerMToken:44e5,reasoningPricePerMToken:44e5,cachedInputPricePerMToken:55e4}},anthropic:{"claude-sonnet-4-20250514":{inputPricePerMToken:3e6,outputPricePerMToken:15e6,cachedInputPricePerMToken:3e5},"claude-haiku-4-5-20251001":{inputPricePerMToken:8e5,outputPricePerMToken:4e6,cachedInputPricePerMToken:8e4},"claude-opus-4-20250514":{inputPricePerMToken:15e6,outputPricePerMToken:75e6,cachedInputPricePerMToken:15e5}},google:{"gemini-2.5-pro":{inputPricePerMToken:125e4,outputPricePerMToken:1e7,cachedInputPricePerMToken:315e3},"gemini-2.5-flash":{inputPricePerMToken:15e4,outputPricePerMToken:6e5,cachedInputPricePerMToken:37500},"gemini-2.0-flash":{inputPricePerMToken:1e5,outputPricePerMToken:4e5,cachedInputPricePerMToken:25e3},"gemini-1.5-pro":{inputPricePerMToken:125e4,outputPricePerMToken:5e6,cachedInputPricePerMToken:315e3},"gemini-1.5-flash":{inputPricePerMToken:75e3,outputPricePerMToken:3e5,cachedInputPricePerMToken:18750}},groq:{"llama-3.3-70b-versatile":{inputPricePerMToken:59e4,outputPricePerMToken:79e4},"llama-3.1-8b-instant":{inputPricePerMToken:5e4,outputPricePerMToken:8e4},"llama-3-70b":{inputPricePerMToken:59e4,outputPricePerMToken:79e4},"mixtral-8x7b":{inputPricePerMToken:24e4,outputPricePerMToken:24e4},"gemma2-9b-it":{inputPricePerMToken:2e5,outputPricePerMToken:2e5}},mistral:{"mistral-large":{inputPricePerMToken:2e6,outputPricePerMToken:6e6},"mistral-small":{inputPricePerMToken:2e5,outputPricePerMToken:6e5},codestral:{inputPricePerMToken:3e5,outputPricePerMToken:9e5},"mistral-embed":{inputPricePerMToken:1e5,outputPricePerMToken:0},"open-mistral-nemo":{inputPricePerMToken:15e4,outputPricePerMToken:15e4}}};function p(t,e){let r=S[t];if(r){if(r[e])return r[e];for(let o of Object.keys(r))if(e.startsWith(o))return r[o]}}var g=class extends Error{rule;current;threshold;suggestion;constructor(e,r){super(`NeuraMeter guard: ${e.ruleType} exceeded (${e.currentValue} > ${e.threshold})`),this.name="NeuraMeterGuardError",this.rule=e.ruleType,this.current=e.currentValue,this.threshold=e.threshold,this.suggestion=r;}};function M(t,e,r){let o=t.mode??"notify",n=[],i=_(e.messages,e.model);if(t.maxInputTokens&&i.estimatedInputTokens>t.maxInputTokens&&n.push({ruleType:"input_tokens",currentValue:i.estimatedInputTokens,threshold:t.maxInputTokens,isHard:false}),t.maxInputTokensHard&&i.estimatedInputTokens>t.maxInputTokensHard&&n.push({ruleType:"input_tokens",currentValue:i.estimatedInputTokens,threshold:t.maxInputTokensHard,isHard:true}),t.maxContextUtilization&&i.utilizationPercent>t.maxContextUtilization&&n.push({ruleType:"context_utilization",currentValue:i.utilizationPercent,threshold:t.maxContextUtilization,isHard:false}),t.maxContextUtilizationHard&&i.utilizationPercent>t.maxContextUtilizationHard&&n.push({ruleType:"context_utilization",currentValue:i.utilizationPercent,threshold:t.maxContextUtilizationHard,isHard:true}),t.maxCostPerCall||t.maxCostPerCallHard){let c=p(e.provider,e.model);if(c){let u=d({inputTokens:i.estimatedInputTokens,outputTokens:0},c)/1e6;t.maxCostPerCall&&u>t.maxCostPerCall&&n.push({ruleType:"cost_per_call",currentValue:u,threshold:t.maxCostPerCall,isHard:false}),t.maxCostPerCallHard&&u>t.maxCostPerCallHard&&n.push({ruleType:"cost_per_call",currentValue:u,threshold:t.maxCostPerCallHard,isHard:true});}}t.maxCostPerHour&&r!==void 0&&r>t.maxCostPerHour&&n.push({ruleType:"cost_per_hour",currentValue:r,threshold:t.maxCostPerHour,isHard:o==="block"});let s=z(n,i);if(n.length===0)return {decision:"allow",triggeredRules:n,contextAnalysis:i,suggestion:s};let a=n.some(c=>c.isHard);switch(o){case "notify":return {decision:"notify",triggeredRules:n,contextAnalysis:i,suggestion:s};case "block":return a?{decision:"block",triggeredRules:n,contextAnalysis:i,suggestion:s}:{decision:"notify",triggeredRules:n,contextAnalysis:i,suggestion:s};case "auto-optimize":return {decision:"notify",triggeredRules:n,contextAnalysis:i,suggestion:s};default:return {decision:"allow",triggeredRules:n,contextAnalysis:i,suggestion:s}}}function z(t,e){if(t.length===0)return "";let r=[];for(let o of t)switch(o.ruleType){case "context_utilization":if(e.conversationTokens>e.systemPromptTokens){let n=Math.round(e.conversationTokens/e.estimatedInputTokens*100);r.push(`Summarize conversation history to save ~${n}% of input tokens`);}break;case "input_tokens":r.push(`Reduce input tokens from ${e.estimatedInputTokens.toLocaleString()} to under ${o.threshold.toLocaleString()}`);break;case "cost_per_call":r.push("Consider using a cheaper model (e.g., gpt-4o-mini or claude-haiku)");break;case "cost_per_hour":r.push(`Hourly cost limit exceeded ($${o.currentValue.toFixed(2)} > $${o.threshold.toFixed(2)}). Throttle or pause agent calls`);break}return r.join(". ")||"Review guard thresholds or optimize context usage"}var h=class{traceId;agentName;customerId;taskName;tags;recordFn;constructor(e,r){this.traceId=crypto.randomUUID(),this.agentName=e.agentName,this.customerId=e.customerId,this.taskName=e.taskName,this.tags=e.tags,this.recordFn=r;}span(e){let r=crypto.randomUUID(),o=p(e.provider,e.model),n=o?d(e.usage,o):0;return this.recordFn({traceId:this.traceId,spanId:r,parentSpanId:e.parentSpanId,agentName:e.agentName??this.agentName,taskName:e.taskName??this.taskName,customerId:this.customerId,provider:e.provider,model:e.model,inputTokens:e.usage.inputTokens,outputTokens:e.usage.outputTokens,reasoningTokens:e.usage.reasoningTokens,cachedTokens:e.usage.cachedTokens,costMicrodollars:n,latencyMs:e.latencyMs,tags:{...this.tags,...e.tags}}),r}};function I(t,e){switch(t){case "context_utilization":return `${e.toFixed(1)}%`;case "cost_per_call":case "cost_per_hour":case "budget":return `$${e.toFixed(4)}`;case "input_tokens":return e.toLocaleString();default:return String(e)}}function N(t){return t.split("_").map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(" ")}function O(t){let e=[{type:"header",text:{type:"plain_text",text:":warning: NeuraMeter Guard Alert",emoji:true}},{type:"section",fields:[{type:"mrkdwn",text:`*Agent:*
|
|
2
2
|
${t.agentName}`},{type:"mrkdwn",text:`*Rule Triggered:*
|
|
3
|
-
${
|
|
4
|
-
${
|
|
5
|
-
${
|
|
6
|
-
${t.suggestion}`}}),e.push({type:"context",elements:[{type:"mrkdwn",text:`Sent by NeuraMeter at ${new Date().toISOString()}`}]}),{text:t.text,blocks:e}}async function
|
|
7
|
-
exports.MODEL_CONTEXT_LIMITS=
|
|
3
|
+
${N(t.ruleType)}`},{type:"mrkdwn",text:`*Current Value:*
|
|
4
|
+
${I(t.ruleType,t.currentValue)}`},{type:"mrkdwn",text:`*Threshold:*
|
|
5
|
+
${I(t.ruleType,t.threshold)}`}]}];return t.suggestion&&e.push({type:"section",text:{type:"mrkdwn",text:`*Suggestion:*
|
|
6
|
+
${t.suggestion}`}}),e.push({type:"context",elements:[{type:"mrkdwn",text:`Sent by NeuraMeter at ${new Date().toISOString()}`}]}),{text:t.text,blocks:e}}async function x(t,e){try{let r=O(e);await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(r)});}catch{}}var U=50,A=5e3,k=class{apiKey;projectId;endpoint;batchSize;flushIntervalMs;guards;buffer=[];guardBuffer=[];timer=null;flushing=false;hourlyCosts=new Map;orgId;constructor(e){this.apiKey=e.apiKey,this.projectId=e.projectId,this.endpoint=e.endpoint??"https://neurameter-ingestion.neurameter.workers.dev",this.batchSize=e.batchSize??U,this.flushIntervalMs=e.flushIntervalMs??A,this.guards=e.guards;let r=this.apiKey.split("_");this.orgId=r.length>=3?r[1]:"unknown",this.startAutoFlush();}startTrace(e){return new h(e,r=>this.record(r))}getHourlyCostDollars(e){let r=Date.now()-36e5,n=(this.hourlyCosts.get(e)??[]).filter(s=>s.timestamp>r);return this.hourlyCosts.set(e,n),n.reduce((s,a)=>s+a.costMicrodollars,0)/1e6}trackHourlyCost(e,r){let o=this.hourlyCosts.get(e)??[];o.push({costMicrodollars:r,timestamp:Date.now()}),this.hourlyCosts.set(e,o);}checkGuards(e){if(!this.guards)return null;let r=this.getHourlyCostDollars(e.agentName),o=M(this.guards,e,r);if(o.triggeredRules.length>0&&(this.recordGuardEvent({eventId:crypto.randomUUID(),timestamp:new Date().toISOString(),agentName:e.agentName,guardMode:this.guards.mode??"notify",decision:o.decision,triggeredRules:o.triggeredRules,contextAnalysis:o.contextAnalysis??void 0,suggestion:o.suggestion}),this.guards.notifySlackWebhook))for(let n of o.triggeredRules)x(this.guards.notifySlackWebhook,{text:`NeuraMeter guard triggered: ${n.ruleType} for agent "${e.agentName}" (${n.currentValue} > ${n.threshold})`,agentName:e.agentName,ruleType:n.ruleType,currentValue:n.currentValue,threshold:n.threshold,suggestion:o.suggestion});if(o.decision==="block"){let n=o.triggeredRules.find(i=>i.isHard);if(n)throw new g(n,o.suggestion??"")}return o}async runAutoOptimize(e){if(!this.guards?.onOptimize||e.guardResult.triggeredRules.length===0)return null;let r=e.guardResult.triggeredRules[0],o={type:r.ruleType,suggestion:e.guardResult.suggestion??"",metrics:{messages:e.messages,model:e.model,currentValue:r.currentValue,threshold:r.threshold}};try{let n=await this.guards.onOptimize(o),i=p("openai",n.model??e.model),s=e.guardResult.contextAnalysis?.estimatedInputTokens??0,a=i?d({inputTokens:s,outputTokens:0},i)/1e6:0;return this.recordGuardEvent({eventId:crypto.randomUUID(),timestamp:new Date().toISOString(),agentName:e.agentName,guardMode:"auto-optimize",decision:n.action==="retry"?"optimized":n.action==="block"?"block":"notify",triggeredRules:e.guardResult.triggeredRules,contextAnalysis:e.guardResult.contextAnalysis??void 0,optimization:{action:n.action,tokensBefore:s,costBefore:a,description:e.guardResult.suggestion},suggestion:e.guardResult.suggestion}),n}catch{return {action:"notify"}}}record(e){let r={...e,eventId:crypto.randomUUID(),timestamp:new Date().toISOString(),orgId:this.orgId,projectId:this.projectId,cost:e.costMicrodollars/1e6};this.buffer.push(r),e.agentName&&e.costMicrodollars>0&&this.trackHourlyCost(e.agentName,e.costMicrodollars),this.buffer.length>=this.batchSize&&this.flush();}recordGuardEvent(e){this.guardBuffer.push(e);}async flush(){if(!(this.buffer.length===0&&this.guardBuffer.length===0||this.flushing)){if(this.flushing=true,this.buffer.length>0){let e=this.buffer.splice(0,this.batchSize);try{(await fetch(`${this.endpoint}/v1/events`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`},body:JSON.stringify({batch:e})})).ok||this.buffer.unshift(...e);}catch{this.buffer.unshift(...e);}}if(this.guardBuffer.length>0){let e=this.guardBuffer.splice(0,this.batchSize);try{await fetch(`${this.endpoint}/v1/guard-events`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`},body:JSON.stringify({batch:e})});}catch{}}this.flushing=false;}}async destroy(){this.timer&&(clearInterval(this.timer),this.timer=null),await this.flush();}startAutoFlush(){this.timer=setInterval(()=>{this.flush();},this.flushIntervalMs),this.timer&&typeof this.timer=="object"&&"unref"in this.timer&&this.timer.unref();}};async function E(t,e,r,o,n){let i=new Date;i.setDate(i.getDate()-7);let{data:s}=await t.from("cost_events").select("cost_microdollars").eq("org_id",e).eq("agent_name",r).gte("event_timestamp",i.toISOString());if(s&&s.length>=5){let a=s.reduce((l,u)=>l+u.cost_microdollars/1e6,0)/s.length,c=Math.max(0,a-o);return {baselineCost:a,saving:c,commission:c*.1,method:"B"}}if(n!==void 0&&n>o){let a=n-o;return {baselineCost:n,saving:a,commission:a*.1,method:"A"}}return {baselineCost:0,saving:0,commission:0,method:"A"}}function v(t){return {inputTokens:t.prompt_tokens??0,outputTokens:t.completion_tokens??0,reasoningTokens:t.completion_tokens_details?.reasoning_tokens??0,cachedTokens:t.prompt_tokens_details?.cached_tokens??0}}function H(t,e,r){let o=t[Symbol.asyncIterator].bind(t);return new Proxy(t,{get(n,i,s){return i===Symbol.asyncIterator?function(){let a=o(),c=null,l=r;return {async next(){let u=await a.next();if(u.done)c&&e(c,l);else {let m=u.value;m.model&&(l=m.model),m.usage&&(c=v(m.usage));}return u},async return(u){return c&&e(c,l),a.return?a.return(u):{done:true,value:void 0}},async throw(u){return a.throw?a.throw(u):Promise.reject(u)}}}:Reflect.get(n,i,s)}})}function G(t,e){let r=new k({apiKey:e.apiKey,projectId:e.projectId,endpoint:e.endpoint??"https://meter.neuria.tech"}),o=e.agentName??"default",n=t.chat.completions.create.bind(t.chat.completions);function i(s,a,c){let l=p("openai",a),u=l?d(s,l):0;r.record({traceId:crypto.randomUUID(),spanId:crypto.randomUUID(),agentName:o,provider:"openai",model:a,inputTokens:s.inputTokens,outputTokens:s.outputTokens,reasoningTokens:s.reasoningTokens??0,cachedTokens:s.cachedTokens??0,costMicrodollars:u,latencyMs:c});}return t.chat.completions.create=async s=>{let a=Date.now(),c=s.model,l=s.stream===true;l&&!s.stream_options&&(s={...s,stream_options:{include_usage:true}});let u=await n(s);if(l&&u&&typeof u=="object"&&Symbol.asyncIterator in u)return H(u,(P,R)=>{let w=Date.now()-a;i(P,R,w);},c);let m=Date.now()-a,T=u;if(T.usage){let P=v(T.usage);i(P,T.model??c,m);}return u},t.__neurameter=r,t.__neurameter_destroy=()=>r.destroy(),t}
|
|
7
|
+
exports.MODEL_CONTEXT_LIMITS=f;exports.NeuraMeter=k;exports.NeuraMeterGuardError=g;exports.Trace=h;exports.analyzeContext=_;exports.calculateCostMicrodollars=d;exports.calculateSaving=E;exports.checkGuards=M;exports.estimateTokens=C;exports.getModelContextLimit=b;exports.getModelPricing=p;exports.sendSlackNotification=x;exports.withNeuraMeter=G;//# sourceMappingURL=index.cjs.map
|
|
8
8
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/context.ts","../src/cost.ts","../src/pricing.ts","../src/guards.ts","../src/trace.ts","../src/slack.ts","../src/meter.ts"],"names":["MODEL_CONTEXT_LIMITS","estimateTokens","content","str","analyzeContext","messages","model","modelLimit","getModelContextLimit","systemTokens","conversationTokens","toolResultTokens","msg","tokens","total","key","limit","calculateCostMicrodollars","usage","pricing","totalMicrodollars","effectiveInputTokens","integerDivRound","cachedPrice","reasoningPrice","numerator","denominator","quotient","PRICING","getModelPricing","provider","providerPricing","NeuraMeterGuardError","rule","suggestion","checkGuards","config","params","hourlyCostDollars","mode","triggeredRules","contextAnalysis","estimatedDollars","generateSuggestion","hasHardViolation","r","rules","ctx","parts","savingPct","Trace","opts","recordFn","spanId","costMicrodollars","formatValue","ruleType","value","formatRuleType","word","buildSlackPayload","message","blocks","sendSlackNotification","webhookUrl","payload","DEFAULT_BATCH_SIZE","DEFAULT_FLUSH_INTERVAL_MS","NeuraMeter","event","agentName","oneHourAgo","recent","e","entries","result","hardRule","primaryRule","optimizeEvent","tokensBefore","costBefore","fullEvent","batch","guardBatch"],"mappings":"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","file":"index.cjs","sourcesContent":["export interface ContextAnalysis {\n estimatedInputTokens: number;\n modelContextLimit: number;\n utilizationPercent: number;\n messageCount: number;\n systemPromptTokens: number;\n conversationTokens: number;\n toolResultTokens: number;\n}\n\nexport interface Message {\n role: string;\n content: string | unknown;\n}\n\n/**\n * Model context window limits (tokens).\n */\nexport const MODEL_CONTEXT_LIMITS: Record<string, number> = {\n 'gpt-4o': 128_000,\n 'gpt-4o-mini': 128_000,\n 'gpt-4.1': 1_000_000,\n 'gpt-4.1-mini': 1_000_000,\n 'o1': 200_000,\n 'o3-mini': 200_000,\n 'claude-sonnet-4-20250514': 200_000,\n 'claude-haiku-4-5-20251001': 200_000,\n 'claude-opus-4-20250514': 200_000,\n // Aliases for prefix matching\n 'claude-sonnet-4': 200_000,\n 'claude-haiku-4': 200_000,\n 'claude-opus-4': 200_000,\n};\n\n/**\n * Estimate token count from a string.\n * Uses a simple heuristic: ~4 chars per token for English,\n * ~1.5 chars per token for CJK/mixed content.\n * This is intentionally fast (<1ms) for SDK use.\n */\nexport function estimateTokens(content: string | unknown): number {\n if (typeof content !== 'string') {\n // For non-string content (e.g., tool_use blocks), serialize and estimate\n const str = typeof content === 'object' ? JSON.stringify(content) : String(content ?? '');\n return Math.ceil(str.length / 4);\n }\n // Simple heuristic: average of ~4 chars/token\n return Math.ceil(content.length / 4);\n}\n\n/**\n * Analyze context window utilization for a set of messages.\n */\nexport function analyzeContext(messages: Message[], model: string): ContextAnalysis {\n const modelLimit = getModelContextLimit(model);\n let systemTokens = 0;\n let conversationTokens = 0;\n let toolResultTokens = 0;\n\n for (const msg of messages) {\n const tokens = estimateTokens(msg.content);\n if (msg.role === 'system') {\n systemTokens += tokens;\n } else if (msg.role === 'tool') {\n toolResultTokens += tokens;\n } else {\n conversationTokens += tokens;\n }\n }\n\n const total = systemTokens + conversationTokens + toolResultTokens;\n\n return {\n estimatedInputTokens: total,\n modelContextLimit: modelLimit,\n utilizationPercent: modelLimit > 0 ? total / modelLimit : 0,\n messageCount: messages.length,\n systemPromptTokens: systemTokens,\n conversationTokens,\n toolResultTokens,\n };\n}\n\n/**\n * Get model context limit with prefix matching fallback.\n */\nexport function getModelContextLimit(model: string): number {\n if (MODEL_CONTEXT_LIMITS[model] !== undefined) {\n return MODEL_CONTEXT_LIMITS[model]!;\n }\n // Prefix match for versioned model names\n for (const [key, limit] of Object.entries(MODEL_CONTEXT_LIMITS)) {\n if (model.startsWith(key)) return limit;\n }\n return 128_000; // Default fallback\n}\n","import type { ModelPricing, TokenUsage } from './types';\n\n/**\n * Calculate cost in microdollars using integer arithmetic only.\n *\n * Pricing values are stored as microdollars per million tokens.\n * Formula: tokens * pricePerMToken / 1_000_000\n * (result is already in microdollars since price is in microdollars)\n *\n * To avoid floating-point, we compute:\n * cost = Math.round(tokens * pricePerMToken / 1_000_000)\n *\n * Since pricePerMToken is already an integer (microdollars per 1M tokens),\n * and tokens is an integer, the only division is by 1_000_000.\n * We use Math.round to get the nearest integer microdollar.\n */\nexport function calculateCostMicrodollars(\n usage: TokenUsage,\n pricing: ModelPricing,\n): number {\n let totalMicrodollars = 0;\n\n // Input tokens cost\n const effectiveInputTokens = usage.inputTokens - (usage.cachedTokens ?? 0);\n if (effectiveInputTokens > 0) {\n totalMicrodollars += integerDivRound(\n effectiveInputTokens * pricing.inputPricePerMToken,\n 1_000_000,\n );\n }\n\n // Cached tokens cost (discounted rate)\n if (usage.cachedTokens && usage.cachedTokens > 0) {\n const cachedPrice = pricing.cachedInputPricePerMToken ?? pricing.inputPricePerMToken;\n totalMicrodollars += integerDivRound(\n usage.cachedTokens * cachedPrice,\n 1_000_000,\n );\n }\n\n // Output tokens cost\n if (usage.outputTokens > 0) {\n totalMicrodollars += integerDivRound(\n usage.outputTokens * pricing.outputPricePerMToken,\n 1_000_000,\n );\n }\n\n // Reasoning tokens cost\n if (usage.reasoningTokens && usage.reasoningTokens > 0) {\n const reasoningPrice = pricing.reasoningPricePerMToken ?? pricing.outputPricePerMToken;\n totalMicrodollars += integerDivRound(\n usage.reasoningTokens * reasoningPrice,\n 1_000_000,\n );\n }\n\n return totalMicrodollars;\n}\n\n/**\n * Integer division with rounding (avoids floating-point).\n * Computes Math.round(numerator / denominator) using only integer ops.\n */\nfunction integerDivRound(numerator: number, denominator: number): number {\n const quotient = Math.trunc(numerator / denominator);\n const remainder = numerator - quotient * denominator;\n // Round: if remainder >= half the denominator, round up\n if (remainder * 2 >= denominator) {\n return quotient + 1;\n }\n return quotient;\n}\n","import type { ModelPricing } from './types';\n\n/**\n * Built-in pricing data — microdollars per million tokens.\n * e.g. $2.50 per 1M tokens = 2_500_000 microdollars per 1M tokens\n */\nconst PRICING: Record<string, Record<string, ModelPricing>> = {\n openai: {\n 'gpt-4o': {\n inputPricePerMToken: 2_500_000,\n outputPricePerMToken: 10_000_000,\n cachedInputPricePerMToken: 1_250_000,\n },\n 'gpt-4o-mini': {\n inputPricePerMToken: 150_000,\n outputPricePerMToken: 600_000,\n cachedInputPricePerMToken: 75_000,\n },\n 'gpt-4.1': {\n inputPricePerMToken: 2_000_000,\n outputPricePerMToken: 8_000_000,\n cachedInputPricePerMToken: 500_000,\n },\n 'gpt-4.1-mini': {\n inputPricePerMToken: 400_000,\n outputPricePerMToken: 1_600_000,\n cachedInputPricePerMToken: 100_000,\n },\n o1: {\n inputPricePerMToken: 15_000_000,\n outputPricePerMToken: 60_000_000,\n reasoningPricePerMToken: 60_000_000,\n cachedInputPricePerMToken: 7_500_000,\n },\n 'o3-mini': {\n inputPricePerMToken: 1_100_000,\n outputPricePerMToken: 4_400_000,\n reasoningPricePerMToken: 4_400_000,\n cachedInputPricePerMToken: 550_000,\n },\n },\n anthropic: {\n 'claude-sonnet-4-20250514': {\n inputPricePerMToken: 3_000_000,\n outputPricePerMToken: 15_000_000,\n cachedInputPricePerMToken: 300_000,\n },\n 'claude-haiku-4-5-20251001': {\n inputPricePerMToken: 800_000,\n outputPricePerMToken: 4_000_000,\n cachedInputPricePerMToken: 80_000,\n },\n 'claude-opus-4-20250514': {\n inputPricePerMToken: 15_000_000,\n outputPricePerMToken: 75_000_000,\n cachedInputPricePerMToken: 1_500_000,\n },\n },\n google: {\n 'gemini-2.5-pro': {\n inputPricePerMToken: 1_250_000,\n outputPricePerMToken: 10_000_000,\n cachedInputPricePerMToken: 315_000,\n },\n 'gemini-2.5-flash': {\n inputPricePerMToken: 150_000,\n outputPricePerMToken: 600_000,\n cachedInputPricePerMToken: 37_500,\n },\n 'gemini-2.0-flash': {\n inputPricePerMToken: 100_000,\n outputPricePerMToken: 400_000,\n cachedInputPricePerMToken: 25_000,\n },\n 'gemini-1.5-pro': {\n inputPricePerMToken: 1_250_000,\n outputPricePerMToken: 5_000_000,\n cachedInputPricePerMToken: 315_000,\n },\n 'gemini-1.5-flash': {\n inputPricePerMToken: 75_000,\n outputPricePerMToken: 300_000,\n cachedInputPricePerMToken: 18_750,\n },\n },\n groq: {\n 'llama-3.3-70b-versatile': {\n inputPricePerMToken: 590_000,\n outputPricePerMToken: 790_000,\n },\n 'llama-3.1-8b-instant': {\n inputPricePerMToken: 50_000,\n outputPricePerMToken: 80_000,\n },\n 'llama-3-70b': {\n inputPricePerMToken: 590_000,\n outputPricePerMToken: 790_000,\n },\n 'mixtral-8x7b': {\n inputPricePerMToken: 240_000,\n outputPricePerMToken: 240_000,\n },\n 'gemma2-9b-it': {\n inputPricePerMToken: 200_000,\n outputPricePerMToken: 200_000,\n },\n },\n mistral: {\n 'mistral-large': {\n inputPricePerMToken: 2_000_000,\n outputPricePerMToken: 6_000_000,\n },\n 'mistral-small': {\n inputPricePerMToken: 200_000,\n outputPricePerMToken: 600_000,\n },\n 'codestral': {\n inputPricePerMToken: 300_000,\n outputPricePerMToken: 900_000,\n },\n 'mistral-embed': {\n inputPricePerMToken: 100_000,\n outputPricePerMToken: 0,\n },\n 'open-mistral-nemo': {\n inputPricePerMToken: 150_000,\n outputPricePerMToken: 150_000,\n },\n },\n};\n\nexport function getModelPricing(\n provider: string,\n model: string,\n): ModelPricing | undefined {\n const providerPricing = PRICING[provider];\n if (!providerPricing) return undefined;\n\n // Exact match first\n if (providerPricing[model]) return providerPricing[model];\n\n // Prefix match: e.g. \"gpt-4o-mini-2024-07-18\" → \"gpt-4o-mini\"\n for (const key of Object.keys(providerPricing)) {\n if (model.startsWith(key)) return providerPricing[key];\n }\n\n return undefined;\n}\n","import type { ContextAnalysis, Message } from './context';\nimport { analyzeContext } from './context';\nimport { calculateCostMicrodollars } from './cost';\nimport { getModelPricing } from './pricing';\n\nexport type GuardMode = 'notify' | 'block' | 'auto-optimize';\nexport type GuardDecision = 'allow' | 'notify' | 'block' | 'optimized';\n\nexport interface GuardsConfig {\n maxInputTokens?: number;\n maxInputTokensHard?: number;\n maxContextUtilization?: number;\n maxContextUtilizationHard?: number;\n maxCostPerCall?: number;\n maxCostPerCallHard?: number;\n maxCostPerHour?: number;\n mode?: GuardMode;\n notifySlackWebhook?: string;\n notifyDashboard?: boolean;\n onOptimize?: (event: OptimizeEvent) => Promise<OptimizeResult>;\n}\n\nexport interface TriggeredRule {\n ruleType: 'input_tokens' | 'cost_per_call' | 'cost_per_hour' | 'context_utilization' | 'budget';\n currentValue: number;\n threshold: number;\n isHard: boolean;\n}\n\nexport interface GuardCheckResult {\n decision: GuardDecision;\n triggeredRules: TriggeredRule[];\n contextAnalysis: ContextAnalysis | null;\n suggestion?: string;\n}\n\nexport interface GuardEvent {\n eventId: string;\n timestamp: string;\n agentName: string;\n guardMode: GuardMode;\n decision: GuardDecision;\n triggeredRules: TriggeredRule[];\n contextAnalysis?: ContextAnalysis;\n optimization?: {\n action: 'retry' | 'notify' | 'block';\n tokensBefore: number;\n tokensAfter?: number;\n costBefore: number;\n costAfter?: number;\n description?: string;\n };\n suggestion?: string;\n}\n\nexport interface OptimizeEvent {\n type: 'context_utilization' | 'cost_per_call' | 'input_tokens';\n suggestion: string;\n metrics: {\n messages?: Message[];\n model?: string;\n currentValue: number;\n threshold: number;\n };\n}\n\nexport interface OptimizeResult {\n action: 'retry' | 'notify' | 'block';\n messages?: Message[];\n model?: string;\n}\n\n/**\n * Error thrown when guard mode is 'block' and a hard limit is exceeded.\n */\nexport class NeuraMeterGuardError extends Error {\n readonly rule: string;\n readonly current: number;\n readonly threshold: number;\n readonly suggestion: string;\n\n constructor(rule: TriggeredRule, suggestion: string) {\n super(`NeuraMeter guard: ${rule.ruleType} exceeded (${rule.currentValue} > ${rule.threshold})`);\n this.name = 'NeuraMeterGuardError';\n this.rule = rule.ruleType;\n this.current = rule.currentValue;\n this.threshold = rule.threshold;\n this.suggestion = suggestion;\n }\n}\n\n/**\n * Check guard rules before an API call.\n * Returns the decision and any triggered rules.\n */\nexport function checkGuards(\n config: GuardsConfig,\n params: {\n messages: Message[];\n model: string;\n provider: string;\n agentName: string;\n },\n hourlyCostDollars?: number,\n): GuardCheckResult {\n const mode = config.mode ?? 'notify';\n const triggeredRules: TriggeredRule[] = [];\n\n // Context analysis\n const contextAnalysis = analyzeContext(params.messages, params.model);\n\n // Check input tokens\n if (config.maxInputTokens && contextAnalysis.estimatedInputTokens > config.maxInputTokens) {\n triggeredRules.push({\n ruleType: 'input_tokens',\n currentValue: contextAnalysis.estimatedInputTokens,\n threshold: config.maxInputTokens,\n isHard: false,\n });\n }\n if (config.maxInputTokensHard && contextAnalysis.estimatedInputTokens > config.maxInputTokensHard) {\n triggeredRules.push({\n ruleType: 'input_tokens',\n currentValue: contextAnalysis.estimatedInputTokens,\n threshold: config.maxInputTokensHard,\n isHard: true,\n });\n }\n\n // Check context utilization\n if (config.maxContextUtilization && contextAnalysis.utilizationPercent > config.maxContextUtilization) {\n triggeredRules.push({\n ruleType: 'context_utilization',\n currentValue: contextAnalysis.utilizationPercent,\n threshold: config.maxContextUtilization,\n isHard: false,\n });\n }\n if (config.maxContextUtilizationHard && contextAnalysis.utilizationPercent > config.maxContextUtilizationHard) {\n triggeredRules.push({\n ruleType: 'context_utilization',\n currentValue: contextAnalysis.utilizationPercent,\n threshold: config.maxContextUtilizationHard,\n isHard: true,\n });\n }\n\n // Check estimated cost per call\n if (config.maxCostPerCall || config.maxCostPerCallHard) {\n const pricing = getModelPricing(params.provider, params.model);\n if (pricing) {\n const estimatedCost = calculateCostMicrodollars(\n { inputTokens: contextAnalysis.estimatedInputTokens, outputTokens: 0 },\n pricing,\n );\n const estimatedDollars = estimatedCost / 1_000_000;\n\n if (config.maxCostPerCall && estimatedDollars > config.maxCostPerCall) {\n triggeredRules.push({\n ruleType: 'cost_per_call',\n currentValue: estimatedDollars,\n threshold: config.maxCostPerCall,\n isHard: false,\n });\n }\n if (config.maxCostPerCallHard && estimatedDollars > config.maxCostPerCallHard) {\n triggeredRules.push({\n ruleType: 'cost_per_call',\n currentValue: estimatedDollars,\n threshold: config.maxCostPerCallHard,\n isHard: true,\n });\n }\n }\n }\n\n // Check cost per hour\n if (config.maxCostPerHour && hourlyCostDollars !== undefined && hourlyCostDollars > config.maxCostPerHour) {\n triggeredRules.push({\n ruleType: 'cost_per_hour',\n currentValue: hourlyCostDollars,\n threshold: config.maxCostPerHour,\n isHard: mode === 'block',\n });\n }\n\n // Generate suggestion\n const suggestion = generateSuggestion(triggeredRules, contextAnalysis);\n\n // Determine decision based on mode\n if (triggeredRules.length === 0) {\n return { decision: 'allow', triggeredRules, contextAnalysis, suggestion };\n }\n\n const hasHardViolation = triggeredRules.some((r) => r.isHard);\n\n switch (mode) {\n case 'notify':\n return { decision: 'notify', triggeredRules, contextAnalysis, suggestion };\n\n case 'block':\n if (hasHardViolation) {\n return { decision: 'block', triggeredRules, contextAnalysis, suggestion };\n }\n return { decision: 'notify', triggeredRules, contextAnalysis, suggestion };\n\n case 'auto-optimize':\n return { decision: 'notify', triggeredRules, contextAnalysis, suggestion };\n\n default:\n return { decision: 'allow', triggeredRules, contextAnalysis, suggestion };\n }\n}\n\nfunction generateSuggestion(rules: TriggeredRule[], ctx: ContextAnalysis): string {\n if (rules.length === 0) return '';\n\n const parts: string[] = [];\n\n for (const rule of rules) {\n switch (rule.ruleType) {\n case 'context_utilization':\n if (ctx.conversationTokens > ctx.systemPromptTokens) {\n const savingPct = Math.round((ctx.conversationTokens / ctx.estimatedInputTokens) * 100);\n parts.push(`Summarize conversation history to save ~${savingPct}% of input tokens`);\n }\n break;\n case 'input_tokens':\n parts.push(`Reduce input tokens from ${ctx.estimatedInputTokens.toLocaleString()} to under ${rule.threshold.toLocaleString()}`);\n break;\n case 'cost_per_call':\n parts.push('Consider using a cheaper model (e.g., gpt-4o-mini or claude-haiku)');\n break;\n case 'cost_per_hour':\n parts.push(`Hourly cost limit exceeded ($${rule.currentValue.toFixed(2)} > $${rule.threshold.toFixed(2)}). Throttle or pause agent calls`);\n break;\n }\n }\n\n return parts.join('. ') || 'Review guard thresholds or optimize context usage';\n}\n","import type { CostEvent, Provider, TraceOptions, TokenUsage } from './types';\nimport { calculateCostMicrodollars } from './cost';\nimport { getModelPricing } from './pricing';\n\nexport class Trace {\n readonly traceId: string;\n private readonly agentName: string;\n private readonly customerId?: string;\n private readonly taskName?: string;\n private readonly tags?: Record<string, string>;\n private readonly recordFn: (event: Omit<CostEvent, 'eventId' | 'timestamp' | 'orgId' | 'projectId' | 'cost'>) => void;\n\n constructor(\n opts: TraceOptions,\n recordFn: (event: Omit<CostEvent, 'eventId' | 'timestamp' | 'orgId' | 'projectId' | 'cost'>) => void,\n ) {\n this.traceId = crypto.randomUUID();\n this.agentName = opts.agentName;\n this.customerId = opts.customerId;\n this.taskName = opts.taskName;\n this.tags = opts.tags;\n this.recordFn = recordFn;\n }\n\n span(opts: {\n provider: Provider;\n model: string;\n usage: TokenUsage;\n latencyMs: number;\n parentSpanId?: string;\n agentName?: string;\n taskName?: string;\n tags?: Record<string, string>;\n }): string {\n const spanId = crypto.randomUUID();\n const pricing = getModelPricing(opts.provider, opts.model);\n const costMicrodollars = pricing\n ? calculateCostMicrodollars(opts.usage, pricing)\n : 0;\n\n this.recordFn({\n traceId: this.traceId,\n spanId,\n parentSpanId: opts.parentSpanId,\n agentName: opts.agentName ?? this.agentName,\n taskName: opts.taskName ?? this.taskName,\n customerId: this.customerId,\n provider: opts.provider,\n model: opts.model,\n inputTokens: opts.usage.inputTokens,\n outputTokens: opts.usage.outputTokens,\n reasoningTokens: opts.usage.reasoningTokens,\n cachedTokens: opts.usage.cachedTokens,\n costMicrodollars,\n latencyMs: opts.latencyMs,\n tags: { ...this.tags, ...opts.tags },\n });\n\n return spanId;\n }\n}\n","/**\n * Slack notification utility for NeuraMeter guard alerts.\n * Sends Block Kit formatted messages via incoming webhooks.\n */\n\nexport interface SlackMessage {\n /** Plain text fallback */\n text: string;\n /** Name of the agent that triggered the guard */\n agentName: string;\n /** Type of guard rule triggered (e.g. 'context_utilization', 'input_tokens') */\n ruleType: string;\n /** Current value that exceeded the threshold */\n currentValue: number;\n /** Configured threshold that was exceeded */\n threshold: number;\n /** Optimization suggestion from the guard system */\n suggestion?: string;\n}\n\n/**\n * Format a value for display based on the rule type.\n */\nfunction formatValue(ruleType: string, value: number): string {\n switch (ruleType) {\n case 'context_utilization':\n return `${value.toFixed(1)}%`;\n case 'cost_per_call':\n case 'cost_per_hour':\n case 'budget':\n return `$${value.toFixed(4)}`;\n case 'input_tokens':\n return value.toLocaleString();\n default:\n return String(value);\n }\n}\n\n/**\n * Format a rule type string for human-readable display.\n */\nfunction formatRuleType(ruleType: string): string {\n return ruleType\n .split('_')\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(' ');\n}\n\n/**\n * Build a Slack Block Kit payload for a guard alert.\n */\nfunction buildSlackPayload(message: SlackMessage): object {\n const blocks: object[] = [\n {\n type: 'header',\n text: {\n type: 'plain_text',\n text: `:warning: NeuraMeter Guard Alert`,\n emoji: true,\n },\n },\n {\n type: 'section',\n fields: [\n {\n type: 'mrkdwn',\n text: `*Agent:*\\n${message.agentName}`,\n },\n {\n type: 'mrkdwn',\n text: `*Rule Triggered:*\\n${formatRuleType(message.ruleType)}`,\n },\n {\n type: 'mrkdwn',\n text: `*Current Value:*\\n${formatValue(message.ruleType, message.currentValue)}`,\n },\n {\n type: 'mrkdwn',\n text: `*Threshold:*\\n${formatValue(message.ruleType, message.threshold)}`,\n },\n ],\n },\n ];\n\n if (message.suggestion) {\n blocks.push({\n type: 'section',\n text: {\n type: 'mrkdwn',\n text: `*Suggestion:*\\n${message.suggestion}`,\n },\n });\n }\n\n blocks.push({\n type: 'context',\n elements: [\n {\n type: 'mrkdwn',\n text: `Sent by NeuraMeter at ${new Date().toISOString()}`,\n },\n ],\n });\n\n return {\n text: message.text,\n blocks,\n };\n}\n\n/**\n * Send a Slack notification via an incoming webhook.\n * Fire-and-forget: errors are silently caught and do not propagate.\n *\n * @param webhookUrl - Slack incoming webhook URL\n * @param message - Structured alert message\n */\nexport async function sendSlackNotification(\n webhookUrl: string,\n message: SlackMessage,\n): Promise<void> {\n try {\n const payload = buildSlackPayload(message);\n await fetch(webhookUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n });\n } catch {\n // Fire-and-forget: silently ignore errors\n }\n}\n","import type { CostEvent, NeuraMeterConfig, TraceOptions } from './types';\nimport type { GuardsConfig, GuardCheckResult, GuardEvent, OptimizeEvent, OptimizeResult } from './guards';\nimport { checkGuards, NeuraMeterGuardError } from './guards';\nimport type { Message } from './context';\nimport { Trace } from './trace';\nimport { calculateCostMicrodollars } from './cost';\nimport { getModelPricing } from './pricing';\nimport { sendSlackNotification } from './slack';\n\nconst DEFAULT_BATCH_SIZE = 50;\nconst DEFAULT_FLUSH_INTERVAL_MS = 5_000;\n\n/** Tracks cost accumulated within a rolling 1-hour window per agent. */\ninterface HourlyCostEntry {\n costMicrodollars: number;\n timestamp: number;\n}\n\nexport class NeuraMeter {\n private readonly apiKey: string;\n private readonly projectId: string;\n private readonly endpoint: string;\n private readonly batchSize: number;\n private readonly flushIntervalMs: number;\n readonly guards: GuardsConfig | undefined;\n\n private buffer: CostEvent[] = [];\n private guardBuffer: GuardEvent[] = [];\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private timer: any = null;\n private flushing = false;\n\n /** Rolling hourly cost tracking per agent for maxCostPerHour guard */\n private hourlyCosts: Map<string, HourlyCostEntry[]> = new Map();\n\n /** Extracted from API key format: nm_{orgId}_{secret} */\n private readonly orgId: string;\n\n constructor(config: NeuraMeterConfig) {\n this.apiKey = config.apiKey;\n this.projectId = config.projectId;\n this.endpoint = config.endpoint ?? 'https://neurameter-ingestion.neurameter.workers.dev';\n this.batchSize = config.batchSize ?? DEFAULT_BATCH_SIZE;\n this.flushIntervalMs = config.flushIntervalMs ?? DEFAULT_FLUSH_INTERVAL_MS;\n this.guards = config.guards;\n\n // Extract orgId from API key (format: nm_{orgId}_{secret})\n const parts = this.apiKey.split('_');\n this.orgId = parts.length >= 3 ? parts[1]! : 'unknown';\n\n this.startAutoFlush();\n }\n\n startTrace(opts: TraceOptions): Trace {\n return new Trace(opts, (event) => this.record(event));\n }\n\n /**\n * Get rolling hourly cost for an agent (in dollars).\n */\n getHourlyCostDollars(agentName: string): number {\n const oneHourAgo = Date.now() - 3_600_000;\n const entries = this.hourlyCosts.get(agentName) ?? [];\n // Prune old entries\n const recent = entries.filter((e) => e.timestamp > oneHourAgo);\n this.hourlyCosts.set(agentName, recent);\n const totalMicro = recent.reduce((s, e) => s + e.costMicrodollars, 0);\n return totalMicro / 1_000_000;\n }\n\n /**\n * Track cost for hourly rate limiting.\n */\n private trackHourlyCost(agentName: string, costMicrodollars: number): void {\n const entries = this.hourlyCosts.get(agentName) ?? [];\n entries.push({ costMicrodollars, timestamp: Date.now() });\n this.hourlyCosts.set(agentName, entries);\n }\n\n /**\n * Check guard rules before an API call.\n * Returns the check result. In block mode, may throw NeuraMeterGuardError.\n */\n checkGuards(params: {\n messages: Message[];\n model: string;\n provider: string;\n agentName: string;\n }): GuardCheckResult | null {\n if (!this.guards) return null;\n\n const hourlyCostDollars = this.getHourlyCostDollars(params.agentName);\n const result = checkGuards(this.guards, params, hourlyCostDollars);\n\n // Record guard event (async, fire-and-forget)\n if (result.triggeredRules.length > 0) {\n this.recordGuardEvent({\n eventId: crypto.randomUUID(),\n timestamp: new Date().toISOString(),\n agentName: params.agentName,\n guardMode: this.guards.mode ?? 'notify',\n decision: result.decision,\n triggeredRules: result.triggeredRules,\n contextAnalysis: result.contextAnalysis ?? undefined,\n suggestion: result.suggestion,\n });\n\n // Send Slack notification if configured (async, fire-and-forget)\n if (this.guards.notifySlackWebhook) {\n for (const rule of result.triggeredRules) {\n void sendSlackNotification(this.guards.notifySlackWebhook, {\n text: `NeuraMeter guard triggered: ${rule.ruleType} for agent \"${params.agentName}\" (${rule.currentValue} > ${rule.threshold})`,\n agentName: params.agentName,\n ruleType: rule.ruleType,\n currentValue: rule.currentValue,\n threshold: rule.threshold,\n suggestion: result.suggestion,\n });\n }\n }\n }\n\n // In block mode with hard violation, throw\n if (result.decision === 'block') {\n const hardRule = result.triggeredRules.find((r) => r.isHard);\n if (hardRule) {\n throw new NeuraMeterGuardError(hardRule, result.suggestion ?? '');\n }\n }\n\n return result;\n }\n\n /**\n * Run auto-optimize flow: calls the onOptimize callback and returns the result.\n * Used by SDK wrappers when mode is 'auto-optimize' and thresholds are exceeded.\n */\n async runAutoOptimize(params: {\n guardResult: GuardCheckResult;\n messages: Message[];\n model: string;\n agentName: string;\n }): Promise<OptimizeResult | null> {\n if (!this.guards?.onOptimize || params.guardResult.triggeredRules.length === 0) {\n return null;\n }\n\n const primaryRule = params.guardResult.triggeredRules[0]!;\n const optimizeEvent: OptimizeEvent = {\n type: primaryRule.ruleType as OptimizeEvent['type'],\n suggestion: params.guardResult.suggestion ?? '',\n metrics: {\n messages: params.messages,\n model: params.model,\n currentValue: primaryRule.currentValue,\n threshold: primaryRule.threshold,\n },\n };\n\n try {\n const result = await this.guards.onOptimize(optimizeEvent);\n\n // Record optimization in guard event\n const pricing = getModelPricing(\n 'openai', // Best effort — wrappers will provide actual provider\n result.model ?? params.model,\n );\n const tokensBefore = params.guardResult.contextAnalysis?.estimatedInputTokens ?? 0;\n const costBefore = pricing\n ? calculateCostMicrodollars({ inputTokens: tokensBefore, outputTokens: 0 }, pricing) / 1_000_000\n : 0;\n\n this.recordGuardEvent({\n eventId: crypto.randomUUID(),\n timestamp: new Date().toISOString(),\n agentName: params.agentName,\n guardMode: 'auto-optimize',\n decision: result.action === 'retry' ? 'optimized' : result.action === 'block' ? 'block' : 'notify',\n triggeredRules: params.guardResult.triggeredRules,\n contextAnalysis: params.guardResult.contextAnalysis ?? undefined,\n optimization: {\n action: result.action,\n tokensBefore,\n costBefore,\n description: params.guardResult.suggestion,\n },\n suggestion: params.guardResult.suggestion,\n });\n\n return result;\n } catch {\n // If onOptimize fails, fall through to notify\n return { action: 'notify' };\n }\n }\n\n record(event: Omit<CostEvent, 'eventId' | 'timestamp' | 'orgId' | 'projectId' | 'cost'>): void {\n const fullEvent: CostEvent = {\n ...event,\n eventId: crypto.randomUUID(),\n timestamp: new Date().toISOString(),\n orgId: this.orgId,\n projectId: this.projectId,\n cost: event.costMicrodollars / 1_000_000,\n };\n\n this.buffer.push(fullEvent);\n\n // Track hourly cost for rate limiting\n if (event.agentName && event.costMicrodollars > 0) {\n this.trackHourlyCost(event.agentName, event.costMicrodollars);\n }\n\n if (this.buffer.length >= this.batchSize) {\n void this.flush();\n }\n }\n\n private recordGuardEvent(event: GuardEvent): void {\n this.guardBuffer.push(event);\n // Flush guard events alongside regular events\n }\n\n async flush(): Promise<void> {\n if ((this.buffer.length === 0 && this.guardBuffer.length === 0) || this.flushing) return;\n\n this.flushing = true;\n\n // Flush cost events\n if (this.buffer.length > 0) {\n const batch = this.buffer.splice(0, this.batchSize);\n try {\n const response = await fetch(`${this.endpoint}/v1/events`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.apiKey}`,\n },\n body: JSON.stringify({ batch }),\n });\n if (!response.ok) {\n this.buffer.unshift(...batch);\n }\n } catch {\n this.buffer.unshift(...batch);\n }\n }\n\n // Flush guard events\n if (this.guardBuffer.length > 0) {\n const guardBatch = this.guardBuffer.splice(0, this.batchSize);\n try {\n await fetch(`${this.endpoint}/v1/guard-events`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.apiKey}`,\n },\n body: JSON.stringify({ batch: guardBatch }),\n });\n } catch {\n // Fire-and-forget for guard events\n }\n }\n\n this.flushing = false;\n }\n\n async destroy(): Promise<void> {\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n await this.flush();\n }\n\n private startAutoFlush(): void {\n this.timer = setInterval(() => {\n void this.flush();\n }, this.flushIntervalMs);\n\n if (this.timer && typeof this.timer === 'object' && 'unref' in this.timer) {\n (this.timer as { unref: () => void }).unref();\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/context.ts","../src/cost.ts","../src/pricing.ts","../src/guards.ts","../src/trace.ts","../src/slack.ts","../src/meter.ts","../src/savings.ts","../src/openai.ts"],"names":["MODEL_CONTEXT_LIMITS","estimateTokens","content","str","analyzeContext","messages","model","modelLimit","getModelContextLimit","systemTokens","conversationTokens","toolResultTokens","msg","tokens","total","key","limit","calculateCostMicrodollars","usage","pricing","totalMicrodollars","effectiveInputTokens","integerDivRound","cachedPrice","reasoningPrice","numerator","denominator","quotient","PRICING","getModelPricing","provider","providerPricing","NeuraMeterGuardError","rule","suggestion","checkGuards","config","params","hourlyCostDollars","mode","triggeredRules","contextAnalysis","estimatedDollars","generateSuggestion","hasHardViolation","r","rules","ctx","parts","savingPct","Trace","opts","recordFn","spanId","costMicrodollars","formatValue","ruleType","value","formatRuleType","word","buildSlackPayload","message","blocks","sendSlackNotification","webhookUrl","payload","DEFAULT_BATCH_SIZE","DEFAULT_FLUSH_INTERVAL_MS","NeuraMeter","event","agentName","oneHourAgo","recent","e","entries","result","hardRule","primaryRule","optimizeEvent","tokensBefore","costBefore","fullEvent","batch","guardBatch","calculateSaving","supabase","orgId","actualCost","sevenDaysAgo","data","avgCost","sum","saving","extractUsage","wrapStream","stream","onDone","requestModel","originalIterator","target","prop","receiver","iter","capturedUsage","capturedModel","chunk","err","withNeuraMeter","client","meter","originalCreate","recordEvent","latencyMs","startTime","isStream","resolvedModel","response"],"mappings":"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","file":"index.cjs","sourcesContent":["export interface ContextAnalysis {\n estimatedInputTokens: number;\n modelContextLimit: number;\n utilizationPercent: number;\n messageCount: number;\n systemPromptTokens: number;\n conversationTokens: number;\n toolResultTokens: number;\n}\n\nexport interface Message {\n role: string;\n content: string | unknown;\n}\n\n/**\n * Model context window limits (tokens).\n */\nexport const MODEL_CONTEXT_LIMITS: Record<string, number> = {\n 'gpt-4o': 128_000,\n 'gpt-4o-mini': 128_000,\n 'gpt-4.1': 1_000_000,\n 'gpt-4.1-mini': 1_000_000,\n 'o1': 200_000,\n 'o3-mini': 200_000,\n 'claude-sonnet-4-20250514': 200_000,\n 'claude-haiku-4-5-20251001': 200_000,\n 'claude-opus-4-20250514': 200_000,\n // Aliases for prefix matching\n 'claude-sonnet-4': 200_000,\n 'claude-haiku-4': 200_000,\n 'claude-opus-4': 200_000,\n};\n\n/**\n * Estimate token count from a string.\n * Uses a simple heuristic: ~4 chars per token for English,\n * ~1.5 chars per token for CJK/mixed content.\n * This is intentionally fast (<1ms) for SDK use.\n */\nexport function estimateTokens(content: string | unknown): number {\n if (typeof content !== 'string') {\n // For non-string content (e.g., tool_use blocks), serialize and estimate\n const str = typeof content === 'object' ? JSON.stringify(content) : String(content ?? '');\n return Math.ceil(str.length / 4);\n }\n // Simple heuristic: average of ~4 chars/token\n return Math.ceil(content.length / 4);\n}\n\n/**\n * Analyze context window utilization for a set of messages.\n */\nexport function analyzeContext(messages: Message[], model: string): ContextAnalysis {\n const modelLimit = getModelContextLimit(model);\n let systemTokens = 0;\n let conversationTokens = 0;\n let toolResultTokens = 0;\n\n for (const msg of messages) {\n const tokens = estimateTokens(msg.content);\n if (msg.role === 'system') {\n systemTokens += tokens;\n } else if (msg.role === 'tool') {\n toolResultTokens += tokens;\n } else {\n conversationTokens += tokens;\n }\n }\n\n const total = systemTokens + conversationTokens + toolResultTokens;\n\n return {\n estimatedInputTokens: total,\n modelContextLimit: modelLimit,\n utilizationPercent: modelLimit > 0 ? total / modelLimit : 0,\n messageCount: messages.length,\n systemPromptTokens: systemTokens,\n conversationTokens,\n toolResultTokens,\n };\n}\n\n/**\n * Get model context limit with prefix matching fallback.\n */\nexport function getModelContextLimit(model: string): number {\n if (MODEL_CONTEXT_LIMITS[model] !== undefined) {\n return MODEL_CONTEXT_LIMITS[model]!;\n }\n // Prefix match for versioned model names\n for (const [key, limit] of Object.entries(MODEL_CONTEXT_LIMITS)) {\n if (model.startsWith(key)) return limit;\n }\n return 128_000; // Default fallback\n}\n","import type { ModelPricing, TokenUsage } from './types';\n\n/**\n * Calculate cost in microdollars using integer arithmetic only.\n *\n * Pricing values are stored as microdollars per million tokens.\n * Formula: tokens * pricePerMToken / 1_000_000\n * (result is already in microdollars since price is in microdollars)\n *\n * To avoid floating-point, we compute:\n * cost = Math.round(tokens * pricePerMToken / 1_000_000)\n *\n * Since pricePerMToken is already an integer (microdollars per 1M tokens),\n * and tokens is an integer, the only division is by 1_000_000.\n * We use Math.round to get the nearest integer microdollar.\n */\nexport function calculateCostMicrodollars(\n usage: TokenUsage,\n pricing: ModelPricing,\n): number {\n let totalMicrodollars = 0;\n\n // Input tokens cost\n const effectiveInputTokens = usage.inputTokens - (usage.cachedTokens ?? 0);\n if (effectiveInputTokens > 0) {\n totalMicrodollars += integerDivRound(\n effectiveInputTokens * pricing.inputPricePerMToken,\n 1_000_000,\n );\n }\n\n // Cached tokens cost (discounted rate)\n if (usage.cachedTokens && usage.cachedTokens > 0) {\n const cachedPrice = pricing.cachedInputPricePerMToken ?? pricing.inputPricePerMToken;\n totalMicrodollars += integerDivRound(\n usage.cachedTokens * cachedPrice,\n 1_000_000,\n );\n }\n\n // Output tokens cost\n if (usage.outputTokens > 0) {\n totalMicrodollars += integerDivRound(\n usage.outputTokens * pricing.outputPricePerMToken,\n 1_000_000,\n );\n }\n\n // Reasoning tokens cost\n if (usage.reasoningTokens && usage.reasoningTokens > 0) {\n const reasoningPrice = pricing.reasoningPricePerMToken ?? pricing.outputPricePerMToken;\n totalMicrodollars += integerDivRound(\n usage.reasoningTokens * reasoningPrice,\n 1_000_000,\n );\n }\n\n return totalMicrodollars;\n}\n\n/**\n * Integer division with rounding (avoids floating-point).\n * Computes Math.round(numerator / denominator) using only integer ops.\n */\nfunction integerDivRound(numerator: number, denominator: number): number {\n const quotient = Math.trunc(numerator / denominator);\n const remainder = numerator - quotient * denominator;\n // Round: if remainder >= half the denominator, round up\n if (remainder * 2 >= denominator) {\n return quotient + 1;\n }\n return quotient;\n}\n","import type { ModelPricing } from './types';\n\n/**\n * Built-in pricing data — microdollars per million tokens.\n * e.g. $2.50 per 1M tokens = 2_500_000 microdollars per 1M tokens\n */\nconst PRICING: Record<string, Record<string, ModelPricing>> = {\n openai: {\n 'gpt-4o': {\n inputPricePerMToken: 2_500_000,\n outputPricePerMToken: 10_000_000,\n cachedInputPricePerMToken: 1_250_000,\n },\n 'gpt-4o-mini': {\n inputPricePerMToken: 150_000,\n outputPricePerMToken: 600_000,\n cachedInputPricePerMToken: 75_000,\n },\n 'gpt-4.1': {\n inputPricePerMToken: 2_000_000,\n outputPricePerMToken: 8_000_000,\n cachedInputPricePerMToken: 500_000,\n },\n 'gpt-4.1-mini': {\n inputPricePerMToken: 400_000,\n outputPricePerMToken: 1_600_000,\n cachedInputPricePerMToken: 100_000,\n },\n o1: {\n inputPricePerMToken: 15_000_000,\n outputPricePerMToken: 60_000_000,\n reasoningPricePerMToken: 60_000_000,\n cachedInputPricePerMToken: 7_500_000,\n },\n 'o3-mini': {\n inputPricePerMToken: 1_100_000,\n outputPricePerMToken: 4_400_000,\n reasoningPricePerMToken: 4_400_000,\n cachedInputPricePerMToken: 550_000,\n },\n },\n anthropic: {\n 'claude-sonnet-4-20250514': {\n inputPricePerMToken: 3_000_000,\n outputPricePerMToken: 15_000_000,\n cachedInputPricePerMToken: 300_000,\n },\n 'claude-haiku-4-5-20251001': {\n inputPricePerMToken: 800_000,\n outputPricePerMToken: 4_000_000,\n cachedInputPricePerMToken: 80_000,\n },\n 'claude-opus-4-20250514': {\n inputPricePerMToken: 15_000_000,\n outputPricePerMToken: 75_000_000,\n cachedInputPricePerMToken: 1_500_000,\n },\n },\n google: {\n 'gemini-2.5-pro': {\n inputPricePerMToken: 1_250_000,\n outputPricePerMToken: 10_000_000,\n cachedInputPricePerMToken: 315_000,\n },\n 'gemini-2.5-flash': {\n inputPricePerMToken: 150_000,\n outputPricePerMToken: 600_000,\n cachedInputPricePerMToken: 37_500,\n },\n 'gemini-2.0-flash': {\n inputPricePerMToken: 100_000,\n outputPricePerMToken: 400_000,\n cachedInputPricePerMToken: 25_000,\n },\n 'gemini-1.5-pro': {\n inputPricePerMToken: 1_250_000,\n outputPricePerMToken: 5_000_000,\n cachedInputPricePerMToken: 315_000,\n },\n 'gemini-1.5-flash': {\n inputPricePerMToken: 75_000,\n outputPricePerMToken: 300_000,\n cachedInputPricePerMToken: 18_750,\n },\n },\n groq: {\n 'llama-3.3-70b-versatile': {\n inputPricePerMToken: 590_000,\n outputPricePerMToken: 790_000,\n },\n 'llama-3.1-8b-instant': {\n inputPricePerMToken: 50_000,\n outputPricePerMToken: 80_000,\n },\n 'llama-3-70b': {\n inputPricePerMToken: 590_000,\n outputPricePerMToken: 790_000,\n },\n 'mixtral-8x7b': {\n inputPricePerMToken: 240_000,\n outputPricePerMToken: 240_000,\n },\n 'gemma2-9b-it': {\n inputPricePerMToken: 200_000,\n outputPricePerMToken: 200_000,\n },\n },\n mistral: {\n 'mistral-large': {\n inputPricePerMToken: 2_000_000,\n outputPricePerMToken: 6_000_000,\n },\n 'mistral-small': {\n inputPricePerMToken: 200_000,\n outputPricePerMToken: 600_000,\n },\n 'codestral': {\n inputPricePerMToken: 300_000,\n outputPricePerMToken: 900_000,\n },\n 'mistral-embed': {\n inputPricePerMToken: 100_000,\n outputPricePerMToken: 0,\n },\n 'open-mistral-nemo': {\n inputPricePerMToken: 150_000,\n outputPricePerMToken: 150_000,\n },\n },\n};\n\nexport function getModelPricing(\n provider: string,\n model: string,\n): ModelPricing | undefined {\n const providerPricing = PRICING[provider];\n if (!providerPricing) return undefined;\n\n // Exact match first\n if (providerPricing[model]) return providerPricing[model];\n\n // Prefix match: e.g. \"gpt-4o-mini-2024-07-18\" → \"gpt-4o-mini\"\n for (const key of Object.keys(providerPricing)) {\n if (model.startsWith(key)) return providerPricing[key];\n }\n\n return undefined;\n}\n","import type { ContextAnalysis, Message } from './context';\nimport { analyzeContext } from './context';\nimport { calculateCostMicrodollars } from './cost';\nimport { getModelPricing } from './pricing';\n\nexport type GuardMode = 'notify' | 'block' | 'auto-optimize';\nexport type GuardDecision = 'allow' | 'notify' | 'block' | 'optimized';\n\nexport interface GuardsConfig {\n maxInputTokens?: number;\n maxInputTokensHard?: number;\n maxContextUtilization?: number;\n maxContextUtilizationHard?: number;\n maxCostPerCall?: number;\n maxCostPerCallHard?: number;\n maxCostPerHour?: number;\n mode?: GuardMode;\n notifySlackWebhook?: string;\n notifyDashboard?: boolean;\n onOptimize?: (event: OptimizeEvent) => Promise<OptimizeResult>;\n}\n\nexport interface TriggeredRule {\n ruleType: 'input_tokens' | 'cost_per_call' | 'cost_per_hour' | 'context_utilization' | 'budget';\n currentValue: number;\n threshold: number;\n isHard: boolean;\n}\n\nexport interface GuardCheckResult {\n decision: GuardDecision;\n triggeredRules: TriggeredRule[];\n contextAnalysis: ContextAnalysis | null;\n suggestion?: string;\n}\n\nexport interface GuardEvent {\n eventId: string;\n timestamp: string;\n agentName: string;\n guardMode: GuardMode;\n decision: GuardDecision;\n triggeredRules: TriggeredRule[];\n contextAnalysis?: ContextAnalysis;\n optimization?: {\n action: 'retry' | 'notify' | 'block';\n tokensBefore: number;\n tokensAfter?: number;\n costBefore: number;\n costAfter?: number;\n description?: string;\n };\n suggestion?: string;\n}\n\nexport interface OptimizeEvent {\n type: 'context_utilization' | 'cost_per_call' | 'input_tokens';\n suggestion: string;\n metrics: {\n messages?: Message[];\n model?: string;\n currentValue: number;\n threshold: number;\n };\n}\n\nexport interface OptimizeResult {\n action: 'retry' | 'notify' | 'block';\n messages?: Message[];\n model?: string;\n}\n\n/**\n * Error thrown when guard mode is 'block' and a hard limit is exceeded.\n */\nexport class NeuraMeterGuardError extends Error {\n readonly rule: string;\n readonly current: number;\n readonly threshold: number;\n readonly suggestion: string;\n\n constructor(rule: TriggeredRule, suggestion: string) {\n super(`NeuraMeter guard: ${rule.ruleType} exceeded (${rule.currentValue} > ${rule.threshold})`);\n this.name = 'NeuraMeterGuardError';\n this.rule = rule.ruleType;\n this.current = rule.currentValue;\n this.threshold = rule.threshold;\n this.suggestion = suggestion;\n }\n}\n\n/**\n * Check guard rules before an API call.\n * Returns the decision and any triggered rules.\n */\nexport function checkGuards(\n config: GuardsConfig,\n params: {\n messages: Message[];\n model: string;\n provider: string;\n agentName: string;\n },\n hourlyCostDollars?: number,\n): GuardCheckResult {\n const mode = config.mode ?? 'notify';\n const triggeredRules: TriggeredRule[] = [];\n\n // Context analysis\n const contextAnalysis = analyzeContext(params.messages, params.model);\n\n // Check input tokens\n if (config.maxInputTokens && contextAnalysis.estimatedInputTokens > config.maxInputTokens) {\n triggeredRules.push({\n ruleType: 'input_tokens',\n currentValue: contextAnalysis.estimatedInputTokens,\n threshold: config.maxInputTokens,\n isHard: false,\n });\n }\n if (config.maxInputTokensHard && contextAnalysis.estimatedInputTokens > config.maxInputTokensHard) {\n triggeredRules.push({\n ruleType: 'input_tokens',\n currentValue: contextAnalysis.estimatedInputTokens,\n threshold: config.maxInputTokensHard,\n isHard: true,\n });\n }\n\n // Check context utilization\n if (config.maxContextUtilization && contextAnalysis.utilizationPercent > config.maxContextUtilization) {\n triggeredRules.push({\n ruleType: 'context_utilization',\n currentValue: contextAnalysis.utilizationPercent,\n threshold: config.maxContextUtilization,\n isHard: false,\n });\n }\n if (config.maxContextUtilizationHard && contextAnalysis.utilizationPercent > config.maxContextUtilizationHard) {\n triggeredRules.push({\n ruleType: 'context_utilization',\n currentValue: contextAnalysis.utilizationPercent,\n threshold: config.maxContextUtilizationHard,\n isHard: true,\n });\n }\n\n // Check estimated cost per call\n if (config.maxCostPerCall || config.maxCostPerCallHard) {\n const pricing = getModelPricing(params.provider, params.model);\n if (pricing) {\n const estimatedCost = calculateCostMicrodollars(\n { inputTokens: contextAnalysis.estimatedInputTokens, outputTokens: 0 },\n pricing,\n );\n const estimatedDollars = estimatedCost / 1_000_000;\n\n if (config.maxCostPerCall && estimatedDollars > config.maxCostPerCall) {\n triggeredRules.push({\n ruleType: 'cost_per_call',\n currentValue: estimatedDollars,\n threshold: config.maxCostPerCall,\n isHard: false,\n });\n }\n if (config.maxCostPerCallHard && estimatedDollars > config.maxCostPerCallHard) {\n triggeredRules.push({\n ruleType: 'cost_per_call',\n currentValue: estimatedDollars,\n threshold: config.maxCostPerCallHard,\n isHard: true,\n });\n }\n }\n }\n\n // Check cost per hour\n if (config.maxCostPerHour && hourlyCostDollars !== undefined && hourlyCostDollars > config.maxCostPerHour) {\n triggeredRules.push({\n ruleType: 'cost_per_hour',\n currentValue: hourlyCostDollars,\n threshold: config.maxCostPerHour,\n isHard: mode === 'block',\n });\n }\n\n // Generate suggestion\n const suggestion = generateSuggestion(triggeredRules, contextAnalysis);\n\n // Determine decision based on mode\n if (triggeredRules.length === 0) {\n return { decision: 'allow', triggeredRules, contextAnalysis, suggestion };\n }\n\n const hasHardViolation = triggeredRules.some((r) => r.isHard);\n\n switch (mode) {\n case 'notify':\n return { decision: 'notify', triggeredRules, contextAnalysis, suggestion };\n\n case 'block':\n if (hasHardViolation) {\n return { decision: 'block', triggeredRules, contextAnalysis, suggestion };\n }\n return { decision: 'notify', triggeredRules, contextAnalysis, suggestion };\n\n case 'auto-optimize':\n return { decision: 'notify', triggeredRules, contextAnalysis, suggestion };\n\n default:\n return { decision: 'allow', triggeredRules, contextAnalysis, suggestion };\n }\n}\n\nfunction generateSuggestion(rules: TriggeredRule[], ctx: ContextAnalysis): string {\n if (rules.length === 0) return '';\n\n const parts: string[] = [];\n\n for (const rule of rules) {\n switch (rule.ruleType) {\n case 'context_utilization':\n if (ctx.conversationTokens > ctx.systemPromptTokens) {\n const savingPct = Math.round((ctx.conversationTokens / ctx.estimatedInputTokens) * 100);\n parts.push(`Summarize conversation history to save ~${savingPct}% of input tokens`);\n }\n break;\n case 'input_tokens':\n parts.push(`Reduce input tokens from ${ctx.estimatedInputTokens.toLocaleString()} to under ${rule.threshold.toLocaleString()}`);\n break;\n case 'cost_per_call':\n parts.push('Consider using a cheaper model (e.g., gpt-4o-mini or claude-haiku)');\n break;\n case 'cost_per_hour':\n parts.push(`Hourly cost limit exceeded ($${rule.currentValue.toFixed(2)} > $${rule.threshold.toFixed(2)}). Throttle or pause agent calls`);\n break;\n }\n }\n\n return parts.join('. ') || 'Review guard thresholds or optimize context usage';\n}\n","import type { CostEvent, Provider, TraceOptions, TokenUsage } from './types';\nimport { calculateCostMicrodollars } from './cost';\nimport { getModelPricing } from './pricing';\n\nexport class Trace {\n readonly traceId: string;\n private readonly agentName: string;\n private readonly customerId?: string;\n private readonly taskName?: string;\n private readonly tags?: Record<string, string>;\n private readonly recordFn: (event: Omit<CostEvent, 'eventId' | 'timestamp' | 'orgId' | 'projectId' | 'cost'>) => void;\n\n constructor(\n opts: TraceOptions,\n recordFn: (event: Omit<CostEvent, 'eventId' | 'timestamp' | 'orgId' | 'projectId' | 'cost'>) => void,\n ) {\n this.traceId = crypto.randomUUID();\n this.agentName = opts.agentName;\n this.customerId = opts.customerId;\n this.taskName = opts.taskName;\n this.tags = opts.tags;\n this.recordFn = recordFn;\n }\n\n span(opts: {\n provider: Provider;\n model: string;\n usage: TokenUsage;\n latencyMs: number;\n parentSpanId?: string;\n agentName?: string;\n taskName?: string;\n tags?: Record<string, string>;\n }): string {\n const spanId = crypto.randomUUID();\n const pricing = getModelPricing(opts.provider, opts.model);\n const costMicrodollars = pricing\n ? calculateCostMicrodollars(opts.usage, pricing)\n : 0;\n\n this.recordFn({\n traceId: this.traceId,\n spanId,\n parentSpanId: opts.parentSpanId,\n agentName: opts.agentName ?? this.agentName,\n taskName: opts.taskName ?? this.taskName,\n customerId: this.customerId,\n provider: opts.provider,\n model: opts.model,\n inputTokens: opts.usage.inputTokens,\n outputTokens: opts.usage.outputTokens,\n reasoningTokens: opts.usage.reasoningTokens,\n cachedTokens: opts.usage.cachedTokens,\n costMicrodollars,\n latencyMs: opts.latencyMs,\n tags: { ...this.tags, ...opts.tags },\n });\n\n return spanId;\n }\n}\n","/**\n * Slack notification utility for NeuraMeter guard alerts.\n * Sends Block Kit formatted messages via incoming webhooks.\n */\n\nexport interface SlackMessage {\n /** Plain text fallback */\n text: string;\n /** Name of the agent that triggered the guard */\n agentName: string;\n /** Type of guard rule triggered (e.g. 'context_utilization', 'input_tokens') */\n ruleType: string;\n /** Current value that exceeded the threshold */\n currentValue: number;\n /** Configured threshold that was exceeded */\n threshold: number;\n /** Optimization suggestion from the guard system */\n suggestion?: string;\n}\n\n/**\n * Format a value for display based on the rule type.\n */\nfunction formatValue(ruleType: string, value: number): string {\n switch (ruleType) {\n case 'context_utilization':\n return `${value.toFixed(1)}%`;\n case 'cost_per_call':\n case 'cost_per_hour':\n case 'budget':\n return `$${value.toFixed(4)}`;\n case 'input_tokens':\n return value.toLocaleString();\n default:\n return String(value);\n }\n}\n\n/**\n * Format a rule type string for human-readable display.\n */\nfunction formatRuleType(ruleType: string): string {\n return ruleType\n .split('_')\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(' ');\n}\n\n/**\n * Build a Slack Block Kit payload for a guard alert.\n */\nfunction buildSlackPayload(message: SlackMessage): object {\n const blocks: object[] = [\n {\n type: 'header',\n text: {\n type: 'plain_text',\n text: `:warning: NeuraMeter Guard Alert`,\n emoji: true,\n },\n },\n {\n type: 'section',\n fields: [\n {\n type: 'mrkdwn',\n text: `*Agent:*\\n${message.agentName}`,\n },\n {\n type: 'mrkdwn',\n text: `*Rule Triggered:*\\n${formatRuleType(message.ruleType)}`,\n },\n {\n type: 'mrkdwn',\n text: `*Current Value:*\\n${formatValue(message.ruleType, message.currentValue)}`,\n },\n {\n type: 'mrkdwn',\n text: `*Threshold:*\\n${formatValue(message.ruleType, message.threshold)}`,\n },\n ],\n },\n ];\n\n if (message.suggestion) {\n blocks.push({\n type: 'section',\n text: {\n type: 'mrkdwn',\n text: `*Suggestion:*\\n${message.suggestion}`,\n },\n });\n }\n\n blocks.push({\n type: 'context',\n elements: [\n {\n type: 'mrkdwn',\n text: `Sent by NeuraMeter at ${new Date().toISOString()}`,\n },\n ],\n });\n\n return {\n text: message.text,\n blocks,\n };\n}\n\n/**\n * Send a Slack notification via an incoming webhook.\n * Fire-and-forget: errors are silently caught and do not propagate.\n *\n * @param webhookUrl - Slack incoming webhook URL\n * @param message - Structured alert message\n */\nexport async function sendSlackNotification(\n webhookUrl: string,\n message: SlackMessage,\n): Promise<void> {\n try {\n const payload = buildSlackPayload(message);\n await fetch(webhookUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n });\n } catch {\n // Fire-and-forget: silently ignore errors\n }\n}\n","import type { CostEvent, NeuraMeterConfig, TraceOptions } from './types';\nimport type { GuardsConfig, GuardCheckResult, GuardEvent, OptimizeEvent, OptimizeResult } from './guards';\nimport { checkGuards, NeuraMeterGuardError } from './guards';\nimport type { Message } from './context';\nimport { Trace } from './trace';\nimport { calculateCostMicrodollars } from './cost';\nimport { getModelPricing } from './pricing';\nimport { sendSlackNotification } from './slack';\n\nconst DEFAULT_BATCH_SIZE = 50;\nconst DEFAULT_FLUSH_INTERVAL_MS = 5_000;\n\n/** Tracks cost accumulated within a rolling 1-hour window per agent. */\ninterface HourlyCostEntry {\n costMicrodollars: number;\n timestamp: number;\n}\n\nexport class NeuraMeter {\n private readonly apiKey: string;\n private readonly projectId: string;\n private readonly endpoint: string;\n private readonly batchSize: number;\n private readonly flushIntervalMs: number;\n readonly guards: GuardsConfig | undefined;\n\n private buffer: CostEvent[] = [];\n private guardBuffer: GuardEvent[] = [];\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private timer: any = null;\n private flushing = false;\n\n /** Rolling hourly cost tracking per agent for maxCostPerHour guard */\n private hourlyCosts: Map<string, HourlyCostEntry[]> = new Map();\n\n /** Extracted from API key format: nm_{orgId}_{secret} */\n private readonly orgId: string;\n\n constructor(config: NeuraMeterConfig) {\n this.apiKey = config.apiKey;\n this.projectId = config.projectId;\n this.endpoint = config.endpoint ?? 'https://neurameter-ingestion.neurameter.workers.dev';\n this.batchSize = config.batchSize ?? DEFAULT_BATCH_SIZE;\n this.flushIntervalMs = config.flushIntervalMs ?? DEFAULT_FLUSH_INTERVAL_MS;\n this.guards = config.guards;\n\n // Extract orgId from API key (format: nm_{orgId}_{secret})\n const parts = this.apiKey.split('_');\n this.orgId = parts.length >= 3 ? parts[1]! : 'unknown';\n\n this.startAutoFlush();\n }\n\n startTrace(opts: TraceOptions): Trace {\n return new Trace(opts, (event) => this.record(event));\n }\n\n /**\n * Get rolling hourly cost for an agent (in dollars).\n */\n getHourlyCostDollars(agentName: string): number {\n const oneHourAgo = Date.now() - 3_600_000;\n const entries = this.hourlyCosts.get(agentName) ?? [];\n // Prune old entries\n const recent = entries.filter((e) => e.timestamp > oneHourAgo);\n this.hourlyCosts.set(agentName, recent);\n const totalMicro = recent.reduce((s, e) => s + e.costMicrodollars, 0);\n return totalMicro / 1_000_000;\n }\n\n /**\n * Track cost for hourly rate limiting.\n */\n private trackHourlyCost(agentName: string, costMicrodollars: number): void {\n const entries = this.hourlyCosts.get(agentName) ?? [];\n entries.push({ costMicrodollars, timestamp: Date.now() });\n this.hourlyCosts.set(agentName, entries);\n }\n\n /**\n * Check guard rules before an API call.\n * Returns the check result. In block mode, may throw NeuraMeterGuardError.\n */\n checkGuards(params: {\n messages: Message[];\n model: string;\n provider: string;\n agentName: string;\n }): GuardCheckResult | null {\n if (!this.guards) return null;\n\n const hourlyCostDollars = this.getHourlyCostDollars(params.agentName);\n const result = checkGuards(this.guards, params, hourlyCostDollars);\n\n // Record guard event (async, fire-and-forget)\n if (result.triggeredRules.length > 0) {\n this.recordGuardEvent({\n eventId: crypto.randomUUID(),\n timestamp: new Date().toISOString(),\n agentName: params.agentName,\n guardMode: this.guards.mode ?? 'notify',\n decision: result.decision,\n triggeredRules: result.triggeredRules,\n contextAnalysis: result.contextAnalysis ?? undefined,\n suggestion: result.suggestion,\n });\n\n // Send Slack notification if configured (async, fire-and-forget)\n if (this.guards.notifySlackWebhook) {\n for (const rule of result.triggeredRules) {\n void sendSlackNotification(this.guards.notifySlackWebhook, {\n text: `NeuraMeter guard triggered: ${rule.ruleType} for agent \"${params.agentName}\" (${rule.currentValue} > ${rule.threshold})`,\n agentName: params.agentName,\n ruleType: rule.ruleType,\n currentValue: rule.currentValue,\n threshold: rule.threshold,\n suggestion: result.suggestion,\n });\n }\n }\n }\n\n // In block mode with hard violation, throw\n if (result.decision === 'block') {\n const hardRule = result.triggeredRules.find((r) => r.isHard);\n if (hardRule) {\n throw new NeuraMeterGuardError(hardRule, result.suggestion ?? '');\n }\n }\n\n return result;\n }\n\n /**\n * Run auto-optimize flow: calls the onOptimize callback and returns the result.\n * Used by SDK wrappers when mode is 'auto-optimize' and thresholds are exceeded.\n */\n async runAutoOptimize(params: {\n guardResult: GuardCheckResult;\n messages: Message[];\n model: string;\n agentName: string;\n }): Promise<OptimizeResult | null> {\n if (!this.guards?.onOptimize || params.guardResult.triggeredRules.length === 0) {\n return null;\n }\n\n const primaryRule = params.guardResult.triggeredRules[0]!;\n const optimizeEvent: OptimizeEvent = {\n type: primaryRule.ruleType as OptimizeEvent['type'],\n suggestion: params.guardResult.suggestion ?? '',\n metrics: {\n messages: params.messages,\n model: params.model,\n currentValue: primaryRule.currentValue,\n threshold: primaryRule.threshold,\n },\n };\n\n try {\n const result = await this.guards.onOptimize(optimizeEvent);\n\n // Record optimization in guard event\n const pricing = getModelPricing(\n 'openai', // Best effort — wrappers will provide actual provider\n result.model ?? params.model,\n );\n const tokensBefore = params.guardResult.contextAnalysis?.estimatedInputTokens ?? 0;\n const costBefore = pricing\n ? calculateCostMicrodollars({ inputTokens: tokensBefore, outputTokens: 0 }, pricing) / 1_000_000\n : 0;\n\n this.recordGuardEvent({\n eventId: crypto.randomUUID(),\n timestamp: new Date().toISOString(),\n agentName: params.agentName,\n guardMode: 'auto-optimize',\n decision: result.action === 'retry' ? 'optimized' : result.action === 'block' ? 'block' : 'notify',\n triggeredRules: params.guardResult.triggeredRules,\n contextAnalysis: params.guardResult.contextAnalysis ?? undefined,\n optimization: {\n action: result.action,\n tokensBefore,\n costBefore,\n description: params.guardResult.suggestion,\n },\n suggestion: params.guardResult.suggestion,\n });\n\n return result;\n } catch {\n // If onOptimize fails, fall through to notify\n return { action: 'notify' };\n }\n }\n\n record(event: Omit<CostEvent, 'eventId' | 'timestamp' | 'orgId' | 'projectId' | 'cost'>): void {\n const fullEvent: CostEvent = {\n ...event,\n eventId: crypto.randomUUID(),\n timestamp: new Date().toISOString(),\n orgId: this.orgId,\n projectId: this.projectId,\n cost: event.costMicrodollars / 1_000_000,\n };\n\n this.buffer.push(fullEvent);\n\n // Track hourly cost for rate limiting\n if (event.agentName && event.costMicrodollars > 0) {\n this.trackHourlyCost(event.agentName, event.costMicrodollars);\n }\n\n if (this.buffer.length >= this.batchSize) {\n void this.flush();\n }\n }\n\n private recordGuardEvent(event: GuardEvent): void {\n this.guardBuffer.push(event);\n // Flush guard events alongside regular events\n }\n\n async flush(): Promise<void> {\n if ((this.buffer.length === 0 && this.guardBuffer.length === 0) || this.flushing) return;\n\n this.flushing = true;\n\n // Flush cost events\n if (this.buffer.length > 0) {\n const batch = this.buffer.splice(0, this.batchSize);\n try {\n const response = await fetch(`${this.endpoint}/v1/events`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.apiKey}`,\n },\n body: JSON.stringify({ batch }),\n });\n if (!response.ok) {\n this.buffer.unshift(...batch);\n }\n } catch {\n this.buffer.unshift(...batch);\n }\n }\n\n // Flush guard events\n if (this.guardBuffer.length > 0) {\n const guardBatch = this.guardBuffer.splice(0, this.batchSize);\n try {\n await fetch(`${this.endpoint}/v1/guard-events`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.apiKey}`,\n },\n body: JSON.stringify({ batch: guardBatch }),\n });\n } catch {\n // Fire-and-forget for guard events\n }\n }\n\n this.flushing = false;\n }\n\n async destroy(): Promise<void> {\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n await this.flush();\n }\n\n private startAutoFlush(): void {\n this.timer = setInterval(() => {\n void this.flush();\n }, this.flushIntervalMs);\n\n if (this.timer && typeof this.timer === 'object' && 'unref' in this.timer) {\n (this.timer as { unref: () => void }).unref();\n }\n }\n}\n","export async function calculateSaving(\n supabase: any,\n orgId: string,\n agentName: string,\n actualCost: number,\n costBefore?: number\n): Promise<{\n baselineCost: number;\n saving: number;\n commission: number;\n method: 'A' | 'B';\n}> {\n // B方式: 過去7日間の同エージェント平均コストを取得\n const sevenDaysAgo = new Date();\n sevenDaysAgo.setDate(sevenDaysAgo.getDate() - 7);\n\n const { data } = await supabase\n .from('cost_events')\n .select('cost_microdollars')\n .eq('org_id', orgId)\n .eq('agent_name', agentName)\n .gte('event_timestamp', sevenDaysAgo.toISOString());\n\n if (data && data.length >= 5) {\n const avgCost =\n data.reduce(\n (sum: number, e: any) => sum + e.cost_microdollars / 1_000_000,\n 0\n ) / data.length;\n const saving = Math.max(0, avgCost - actualCost);\n return {\n baselineCost: avgCost,\n saving,\n commission: saving * 0.1,\n method: 'B',\n };\n }\n\n // A方式: データ不足の場合はcostBeforeで代用\n if (costBefore !== undefined && costBefore > actualCost) {\n const saving = costBefore - actualCost;\n return {\n baselineCost: costBefore,\n saving,\n commission: saving * 0.1,\n method: 'A',\n };\n }\n\n return { baselineCost: 0, saving: 0, commission: 0, method: 'A' };\n}\n","// ---------------------------------------------------------------------------\n// @neurameter/core – OpenAI client wrapper\n// ---------------------------------------------------------------------------\n// Wraps an OpenAI client instance so that every chat.completions.create()\n// call is automatically tracked in NeuraMeter — no proxy required.\n//\n// import OpenAI from 'openai';\n// import { withNeuraMeter } from '@neurameter/core';\n//\n// const openai = withNeuraMeter(new OpenAI(), {\n// apiKey: 'nm_xxx',\n// projectId: 'proj_xxx',\n// });\n// ---------------------------------------------------------------------------\n\nimport type { WithNeuraMeterConfig, TokenUsage } from './types';\nimport { NeuraMeter } from './meter';\nimport { getModelPricing } from './pricing';\nimport { calculateCostMicrodollars } from './cost';\n\n// ---------------------------------------------------------------------------\n// Minimal OpenAI-compatible types (avoids importing the openai package)\n// ---------------------------------------------------------------------------\n\n/** Subset of OpenAI usage response fields we need. */\ninterface OpenAIUsage {\n prompt_tokens?: number;\n completion_tokens?: number;\n prompt_tokens_details?: { cached_tokens?: number };\n completion_tokens_details?: { reasoning_tokens?: number };\n}\n\n/** Subset of a non-streaming chat completion response. */\ninterface ChatCompletion {\n usage?: OpenAIUsage;\n model?: string;\n [key: string]: unknown;\n}\n\n/** A single streamed chunk. */\ninterface ChatCompletionChunk {\n usage?: OpenAIUsage | null;\n model?: string;\n [key: string]: unknown;\n}\n\n/** Params passed to chat.completions.create(). */\ninterface CreateParams {\n model: string;\n stream?: boolean;\n stream_options?: { include_usage?: boolean };\n [key: string]: unknown;\n}\n\n// ---------------------------------------------------------------------------\n// Usage extraction helper\n// ---------------------------------------------------------------------------\n\nfunction extractUsage(usage: OpenAIUsage): TokenUsage {\n return {\n inputTokens: usage.prompt_tokens ?? 0,\n outputTokens: usage.completion_tokens ?? 0,\n reasoningTokens: usage.completion_tokens_details?.reasoning_tokens ?? 0,\n cachedTokens: usage.prompt_tokens_details?.cached_tokens ?? 0,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Stream wrapper\n// ---------------------------------------------------------------------------\n\n/**\n * Wraps an async-iterable stream, yielding all chunks transparently while\n * capturing the usage data from the final chunk.\n */\nfunction wrapStream(\n stream: AsyncIterable<ChatCompletionChunk> & Record<string, unknown>,\n onDone: (usage: TokenUsage, model: string) => void,\n requestModel: string,\n): typeof stream {\n const originalIterator = stream[Symbol.asyncIterator].bind(stream);\n\n // Create a proxy so all other properties/methods (e.g. toReadableStream(),\n // controller, response) still work.\n return new Proxy(stream, {\n get(target, prop, receiver) {\n if (prop === Symbol.asyncIterator) {\n return function () {\n const iter = originalIterator();\n let capturedUsage: TokenUsage | null = null;\n let capturedModel = requestModel;\n\n return {\n async next() {\n const result = await iter.next();\n if (!result.done) {\n const chunk = result.value as ChatCompletionChunk;\n if (chunk.model) capturedModel = chunk.model;\n if (chunk.usage) {\n capturedUsage = extractUsage(chunk.usage);\n }\n } else {\n // Stream finished — record the event\n if (capturedUsage) {\n onDone(capturedUsage, capturedModel);\n }\n }\n return result;\n },\n async return(value?: unknown) {\n if (capturedUsage) onDone(capturedUsage, capturedModel);\n return iter.return ? iter.return(value) : { done: true as const, value: undefined };\n },\n async throw(err?: unknown) {\n return iter.throw ? iter.throw(err) : Promise.reject(err);\n },\n };\n };\n }\n return Reflect.get(target, prop, receiver);\n },\n });\n}\n\n// ---------------------------------------------------------------------------\n// withNeuraMeter\n// ---------------------------------------------------------------------------\n\n/**\n * Wraps an OpenAI client so that every `chat.completions.create()` call is\n * automatically tracked in NeuraMeter.\n *\n * @param client An OpenAI client instance (from the `openai` npm package)\n * @param config NeuraMeter configuration\n * @returns The same client with cost tracking enabled\n */\nexport function withNeuraMeter<\n T extends { chat: { completions: { create: (...args: unknown[]) => unknown } } },\n>(client: T, config: WithNeuraMeterConfig): T {\n const meter = new NeuraMeter({\n apiKey: config.apiKey,\n projectId: config.projectId,\n endpoint: config.endpoint ?? 'https://meter.neuria.tech',\n });\n\n const agentName = config.agentName ?? 'default';\n\n // Save the original create method\n const originalCreate = client.chat.completions.create.bind(\n client.chat.completions,\n ) as (params: CreateParams) => Promise<ChatCompletion | AsyncIterable<ChatCompletionChunk>>;\n\n // Helper to record a cost event\n function recordEvent(usage: TokenUsage, model: string, latencyMs: number): void {\n const pricing = getModelPricing('openai', model);\n const costMicrodollars = pricing\n ? calculateCostMicrodollars(usage, pricing)\n : 0;\n\n meter.record({\n traceId: crypto.randomUUID(),\n spanId: crypto.randomUUID(),\n agentName,\n provider: 'openai',\n model,\n inputTokens: usage.inputTokens,\n outputTokens: usage.outputTokens,\n reasoningTokens: usage.reasoningTokens ?? 0,\n cachedTokens: usage.cachedTokens ?? 0,\n costMicrodollars,\n latencyMs,\n });\n }\n\n // Override create\n (client.chat.completions as Record<string, unknown>).create = async (\n params: CreateParams,\n ): Promise<unknown> => {\n const startTime = Date.now();\n const model = params.model;\n const isStream = params.stream === true;\n\n // Auto-inject stream_options for usage reporting\n if (isStream && !params.stream_options) {\n params = { ...params, stream_options: { include_usage: true } };\n }\n\n const result = await originalCreate(params);\n\n if (isStream && result && typeof result === 'object' && Symbol.asyncIterator in result) {\n // Streaming — wrap the async iterable\n return wrapStream(\n result as AsyncIterable<ChatCompletionChunk> & Record<string, unknown>,\n (usage, resolvedModel) => {\n const latencyMs = Date.now() - startTime;\n recordEvent(usage, resolvedModel, latencyMs);\n },\n model,\n );\n }\n\n // Non-streaming — extract usage immediately\n const latencyMs = Date.now() - startTime;\n const response = result as ChatCompletion;\n if (response.usage) {\n const usage = extractUsage(response.usage);\n recordEvent(usage, response.model ?? model, latencyMs);\n }\n\n return result;\n };\n\n // Attach destroy method for cleanup\n (client as Record<string, unknown>).__neurameter = meter;\n (client as Record<string, unknown>).__neurameter_destroy = () => meter.destroy();\n\n return client;\n}\n"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -174,6 +174,17 @@ interface TokenUsage {
|
|
|
174
174
|
reasoningTokens?: number;
|
|
175
175
|
cachedTokens?: number;
|
|
176
176
|
}
|
|
177
|
+
/** Configuration for withNeuraMeter() OpenAI client wrapper. */
|
|
178
|
+
interface WithNeuraMeterConfig {
|
|
179
|
+
/** NeuraMeter API key (format: nm_{orgId}_{secret}) */
|
|
180
|
+
apiKey: string;
|
|
181
|
+
/** NeuraMeter project ID */
|
|
182
|
+
projectId: string;
|
|
183
|
+
/** Agent name for cost events (default: 'default') */
|
|
184
|
+
agentName?: string;
|
|
185
|
+
/** NeuraMeter ingestion endpoint (default: 'https://meter.neuria.tech') */
|
|
186
|
+
endpoint?: string;
|
|
187
|
+
}
|
|
177
188
|
|
|
178
189
|
declare class Trace {
|
|
179
190
|
readonly traceId: string;
|
|
@@ -292,4 +303,27 @@ interface SlackMessage {
|
|
|
292
303
|
*/
|
|
293
304
|
declare function sendSlackNotification(webhookUrl: string, message: SlackMessage): Promise<void>;
|
|
294
305
|
|
|
295
|
-
|
|
306
|
+
declare function calculateSaving(supabase: any, orgId: string, agentName: string, actualCost: number, costBefore?: number): Promise<{
|
|
307
|
+
baselineCost: number;
|
|
308
|
+
saving: number;
|
|
309
|
+
commission: number;
|
|
310
|
+
method: 'A' | 'B';
|
|
311
|
+
}>;
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Wraps an OpenAI client so that every `chat.completions.create()` call is
|
|
315
|
+
* automatically tracked in NeuraMeter.
|
|
316
|
+
*
|
|
317
|
+
* @param client An OpenAI client instance (from the `openai` npm package)
|
|
318
|
+
* @param config NeuraMeter configuration
|
|
319
|
+
* @returns The same client with cost tracking enabled
|
|
320
|
+
*/
|
|
321
|
+
declare function withNeuraMeter<T extends {
|
|
322
|
+
chat: {
|
|
323
|
+
completions: {
|
|
324
|
+
create: (...args: unknown[]) => unknown;
|
|
325
|
+
};
|
|
326
|
+
};
|
|
327
|
+
}>(client: T, config: WithNeuraMeterConfig): T;
|
|
328
|
+
|
|
329
|
+
export { type ContextAnalysis, type CostEvent, type GuardCheckResult, type GuardDecision, type GuardEvent, type GuardMode, type GuardsConfig, MODEL_CONTEXT_LIMITS, type Message, type ModelPricing, NeuraMeter, type NeuraMeterConfig, NeuraMeterGuardError, type OptimizeEvent, type OptimizeResult, type Provider, type SlackMessage, type TokenUsage, Trace, type TraceOptions, type TriggeredRule, type WithNeuraMeterConfig, analyzeContext, calculateCostMicrodollars, calculateSaving, checkGuards, estimateTokens, getModelContextLimit, getModelPricing, sendSlackNotification, withNeuraMeter };
|
package/dist/index.d.ts
CHANGED
|
@@ -174,6 +174,17 @@ interface TokenUsage {
|
|
|
174
174
|
reasoningTokens?: number;
|
|
175
175
|
cachedTokens?: number;
|
|
176
176
|
}
|
|
177
|
+
/** Configuration for withNeuraMeter() OpenAI client wrapper. */
|
|
178
|
+
interface WithNeuraMeterConfig {
|
|
179
|
+
/** NeuraMeter API key (format: nm_{orgId}_{secret}) */
|
|
180
|
+
apiKey: string;
|
|
181
|
+
/** NeuraMeter project ID */
|
|
182
|
+
projectId: string;
|
|
183
|
+
/** Agent name for cost events (default: 'default') */
|
|
184
|
+
agentName?: string;
|
|
185
|
+
/** NeuraMeter ingestion endpoint (default: 'https://meter.neuria.tech') */
|
|
186
|
+
endpoint?: string;
|
|
187
|
+
}
|
|
177
188
|
|
|
178
189
|
declare class Trace {
|
|
179
190
|
readonly traceId: string;
|
|
@@ -292,4 +303,27 @@ interface SlackMessage {
|
|
|
292
303
|
*/
|
|
293
304
|
declare function sendSlackNotification(webhookUrl: string, message: SlackMessage): Promise<void>;
|
|
294
305
|
|
|
295
|
-
|
|
306
|
+
declare function calculateSaving(supabase: any, orgId: string, agentName: string, actualCost: number, costBefore?: number): Promise<{
|
|
307
|
+
baselineCost: number;
|
|
308
|
+
saving: number;
|
|
309
|
+
commission: number;
|
|
310
|
+
method: 'A' | 'B';
|
|
311
|
+
}>;
|
|
312
|
+
|
|
313
|
+
/**
|
|
314
|
+
* Wraps an OpenAI client so that every `chat.completions.create()` call is
|
|
315
|
+
* automatically tracked in NeuraMeter.
|
|
316
|
+
*
|
|
317
|
+
* @param client An OpenAI client instance (from the `openai` npm package)
|
|
318
|
+
* @param config NeuraMeter configuration
|
|
319
|
+
* @returns The same client with cost tracking enabled
|
|
320
|
+
*/
|
|
321
|
+
declare function withNeuraMeter<T extends {
|
|
322
|
+
chat: {
|
|
323
|
+
completions: {
|
|
324
|
+
create: (...args: unknown[]) => unknown;
|
|
325
|
+
};
|
|
326
|
+
};
|
|
327
|
+
}>(client: T, config: WithNeuraMeterConfig): T;
|
|
328
|
+
|
|
329
|
+
export { type ContextAnalysis, type CostEvent, type GuardCheckResult, type GuardDecision, type GuardEvent, type GuardMode, type GuardsConfig, MODEL_CONTEXT_LIMITS, type Message, type ModelPricing, NeuraMeter, type NeuraMeterConfig, NeuraMeterGuardError, type OptimizeEvent, type OptimizeResult, type Provider, type SlackMessage, type TokenUsage, Trace, type TraceOptions, type TriggeredRule, type WithNeuraMeterConfig, analyzeContext, calculateCostMicrodollars, calculateSaving, checkGuards, estimateTokens, getModelContextLimit, getModelPricing, sendSlackNotification, withNeuraMeter };
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
var
|
|
1
|
+
var f={"gpt-4o":128e3,"gpt-4o-mini":128e3,"gpt-4.1":1e6,"gpt-4.1-mini":1e6,o1:2e5,"o3-mini":2e5,"claude-sonnet-4-20250514":2e5,"claude-haiku-4-5-20251001":2e5,"claude-opus-4-20250514":2e5,"claude-sonnet-4":2e5,"claude-haiku-4":2e5,"claude-opus-4":2e5};function C(t){if(typeof t!="string"){let e=typeof t=="object"?JSON.stringify(t):String(t??"");return Math.ceil(e.length/4)}return Math.ceil(t.length/4)}function _(t,e){let r=b(e),o=0,n=0,i=0;for(let a of t){let c=C(a.content);a.role==="system"?o+=c:a.role==="tool"?i+=c:n+=c;}let s=o+n+i;return {estimatedInputTokens:s,modelContextLimit:r,utilizationPercent:r>0?s/r:0,messageCount:t.length,systemPromptTokens:o,conversationTokens:n,toolResultTokens:i}}function b(t){if(f[t]!==void 0)return f[t];for(let[e,r]of Object.entries(f))if(t.startsWith(e))return r;return 128e3}function d(t,e){let r=0,o=t.inputTokens-(t.cachedTokens??0);if(o>0&&(r+=y(o*e.inputPricePerMToken,1e6)),t.cachedTokens&&t.cachedTokens>0){let n=e.cachedInputPricePerMToken??e.inputPricePerMToken;r+=y(t.cachedTokens*n,1e6);}if(t.outputTokens>0&&(r+=y(t.outputTokens*e.outputPricePerMToken,1e6)),t.reasoningTokens&&t.reasoningTokens>0){let n=e.reasoningPricePerMToken??e.outputPricePerMToken;r+=y(t.reasoningTokens*n,1e6);}return r}function y(t,e){let r=Math.trunc(t/e);return (t-r*e)*2>=e?r+1:r}var S={openai:{"gpt-4o":{inputPricePerMToken:25e5,outputPricePerMToken:1e7,cachedInputPricePerMToken:125e4},"gpt-4o-mini":{inputPricePerMToken:15e4,outputPricePerMToken:6e5,cachedInputPricePerMToken:75e3},"gpt-4.1":{inputPricePerMToken:2e6,outputPricePerMToken:8e6,cachedInputPricePerMToken:5e5},"gpt-4.1-mini":{inputPricePerMToken:4e5,outputPricePerMToken:16e5,cachedInputPricePerMToken:1e5},o1:{inputPricePerMToken:15e6,outputPricePerMToken:6e7,reasoningPricePerMToken:6e7,cachedInputPricePerMToken:75e5},"o3-mini":{inputPricePerMToken:11e5,outputPricePerMToken:44e5,reasoningPricePerMToken:44e5,cachedInputPricePerMToken:55e4}},anthropic:{"claude-sonnet-4-20250514":{inputPricePerMToken:3e6,outputPricePerMToken:15e6,cachedInputPricePerMToken:3e5},"claude-haiku-4-5-20251001":{inputPricePerMToken:8e5,outputPricePerMToken:4e6,cachedInputPricePerMToken:8e4},"claude-opus-4-20250514":{inputPricePerMToken:15e6,outputPricePerMToken:75e6,cachedInputPricePerMToken:15e5}},google:{"gemini-2.5-pro":{inputPricePerMToken:125e4,outputPricePerMToken:1e7,cachedInputPricePerMToken:315e3},"gemini-2.5-flash":{inputPricePerMToken:15e4,outputPricePerMToken:6e5,cachedInputPricePerMToken:37500},"gemini-2.0-flash":{inputPricePerMToken:1e5,outputPricePerMToken:4e5,cachedInputPricePerMToken:25e3},"gemini-1.5-pro":{inputPricePerMToken:125e4,outputPricePerMToken:5e6,cachedInputPricePerMToken:315e3},"gemini-1.5-flash":{inputPricePerMToken:75e3,outputPricePerMToken:3e5,cachedInputPricePerMToken:18750}},groq:{"llama-3.3-70b-versatile":{inputPricePerMToken:59e4,outputPricePerMToken:79e4},"llama-3.1-8b-instant":{inputPricePerMToken:5e4,outputPricePerMToken:8e4},"llama-3-70b":{inputPricePerMToken:59e4,outputPricePerMToken:79e4},"mixtral-8x7b":{inputPricePerMToken:24e4,outputPricePerMToken:24e4},"gemma2-9b-it":{inputPricePerMToken:2e5,outputPricePerMToken:2e5}},mistral:{"mistral-large":{inputPricePerMToken:2e6,outputPricePerMToken:6e6},"mistral-small":{inputPricePerMToken:2e5,outputPricePerMToken:6e5},codestral:{inputPricePerMToken:3e5,outputPricePerMToken:9e5},"mistral-embed":{inputPricePerMToken:1e5,outputPricePerMToken:0},"open-mistral-nemo":{inputPricePerMToken:15e4,outputPricePerMToken:15e4}}};function p(t,e){let r=S[t];if(r){if(r[e])return r[e];for(let o of Object.keys(r))if(e.startsWith(o))return r[o]}}var g=class extends Error{rule;current;threshold;suggestion;constructor(e,r){super(`NeuraMeter guard: ${e.ruleType} exceeded (${e.currentValue} > ${e.threshold})`),this.name="NeuraMeterGuardError",this.rule=e.ruleType,this.current=e.currentValue,this.threshold=e.threshold,this.suggestion=r;}};function M(t,e,r){let o=t.mode??"notify",n=[],i=_(e.messages,e.model);if(t.maxInputTokens&&i.estimatedInputTokens>t.maxInputTokens&&n.push({ruleType:"input_tokens",currentValue:i.estimatedInputTokens,threshold:t.maxInputTokens,isHard:false}),t.maxInputTokensHard&&i.estimatedInputTokens>t.maxInputTokensHard&&n.push({ruleType:"input_tokens",currentValue:i.estimatedInputTokens,threshold:t.maxInputTokensHard,isHard:true}),t.maxContextUtilization&&i.utilizationPercent>t.maxContextUtilization&&n.push({ruleType:"context_utilization",currentValue:i.utilizationPercent,threshold:t.maxContextUtilization,isHard:false}),t.maxContextUtilizationHard&&i.utilizationPercent>t.maxContextUtilizationHard&&n.push({ruleType:"context_utilization",currentValue:i.utilizationPercent,threshold:t.maxContextUtilizationHard,isHard:true}),t.maxCostPerCall||t.maxCostPerCallHard){let c=p(e.provider,e.model);if(c){let u=d({inputTokens:i.estimatedInputTokens,outputTokens:0},c)/1e6;t.maxCostPerCall&&u>t.maxCostPerCall&&n.push({ruleType:"cost_per_call",currentValue:u,threshold:t.maxCostPerCall,isHard:false}),t.maxCostPerCallHard&&u>t.maxCostPerCallHard&&n.push({ruleType:"cost_per_call",currentValue:u,threshold:t.maxCostPerCallHard,isHard:true});}}t.maxCostPerHour&&r!==void 0&&r>t.maxCostPerHour&&n.push({ruleType:"cost_per_hour",currentValue:r,threshold:t.maxCostPerHour,isHard:o==="block"});let s=z(n,i);if(n.length===0)return {decision:"allow",triggeredRules:n,contextAnalysis:i,suggestion:s};let a=n.some(c=>c.isHard);switch(o){case "notify":return {decision:"notify",triggeredRules:n,contextAnalysis:i,suggestion:s};case "block":return a?{decision:"block",triggeredRules:n,contextAnalysis:i,suggestion:s}:{decision:"notify",triggeredRules:n,contextAnalysis:i,suggestion:s};case "auto-optimize":return {decision:"notify",triggeredRules:n,contextAnalysis:i,suggestion:s};default:return {decision:"allow",triggeredRules:n,contextAnalysis:i,suggestion:s}}}function z(t,e){if(t.length===0)return "";let r=[];for(let o of t)switch(o.ruleType){case "context_utilization":if(e.conversationTokens>e.systemPromptTokens){let n=Math.round(e.conversationTokens/e.estimatedInputTokens*100);r.push(`Summarize conversation history to save ~${n}% of input tokens`);}break;case "input_tokens":r.push(`Reduce input tokens from ${e.estimatedInputTokens.toLocaleString()} to under ${o.threshold.toLocaleString()}`);break;case "cost_per_call":r.push("Consider using a cheaper model (e.g., gpt-4o-mini or claude-haiku)");break;case "cost_per_hour":r.push(`Hourly cost limit exceeded ($${o.currentValue.toFixed(2)} > $${o.threshold.toFixed(2)}). Throttle or pause agent calls`);break}return r.join(". ")||"Review guard thresholds or optimize context usage"}var h=class{traceId;agentName;customerId;taskName;tags;recordFn;constructor(e,r){this.traceId=crypto.randomUUID(),this.agentName=e.agentName,this.customerId=e.customerId,this.taskName=e.taskName,this.tags=e.tags,this.recordFn=r;}span(e){let r=crypto.randomUUID(),o=p(e.provider,e.model),n=o?d(e.usage,o):0;return this.recordFn({traceId:this.traceId,spanId:r,parentSpanId:e.parentSpanId,agentName:e.agentName??this.agentName,taskName:e.taskName??this.taskName,customerId:this.customerId,provider:e.provider,model:e.model,inputTokens:e.usage.inputTokens,outputTokens:e.usage.outputTokens,reasoningTokens:e.usage.reasoningTokens,cachedTokens:e.usage.cachedTokens,costMicrodollars:n,latencyMs:e.latencyMs,tags:{...this.tags,...e.tags}}),r}};function I(t,e){switch(t){case "context_utilization":return `${e.toFixed(1)}%`;case "cost_per_call":case "cost_per_hour":case "budget":return `$${e.toFixed(4)}`;case "input_tokens":return e.toLocaleString();default:return String(e)}}function N(t){return t.split("_").map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(" ")}function O(t){let e=[{type:"header",text:{type:"plain_text",text:":warning: NeuraMeter Guard Alert",emoji:true}},{type:"section",fields:[{type:"mrkdwn",text:`*Agent:*
|
|
2
2
|
${t.agentName}`},{type:"mrkdwn",text:`*Rule Triggered:*
|
|
3
|
-
${
|
|
4
|
-
${
|
|
5
|
-
${
|
|
6
|
-
${t.suggestion}`}}),e.push({type:"context",elements:[{type:"mrkdwn",text:`Sent by NeuraMeter at ${new Date().toISOString()}`}]}),{text:t.text,blocks:e}}async function
|
|
7
|
-
export{
|
|
3
|
+
${N(t.ruleType)}`},{type:"mrkdwn",text:`*Current Value:*
|
|
4
|
+
${I(t.ruleType,t.currentValue)}`},{type:"mrkdwn",text:`*Threshold:*
|
|
5
|
+
${I(t.ruleType,t.threshold)}`}]}];return t.suggestion&&e.push({type:"section",text:{type:"mrkdwn",text:`*Suggestion:*
|
|
6
|
+
${t.suggestion}`}}),e.push({type:"context",elements:[{type:"mrkdwn",text:`Sent by NeuraMeter at ${new Date().toISOString()}`}]}),{text:t.text,blocks:e}}async function x(t,e){try{let r=O(e);await fetch(t,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(r)});}catch{}}var U=50,A=5e3,k=class{apiKey;projectId;endpoint;batchSize;flushIntervalMs;guards;buffer=[];guardBuffer=[];timer=null;flushing=false;hourlyCosts=new Map;orgId;constructor(e){this.apiKey=e.apiKey,this.projectId=e.projectId,this.endpoint=e.endpoint??"https://neurameter-ingestion.neurameter.workers.dev",this.batchSize=e.batchSize??U,this.flushIntervalMs=e.flushIntervalMs??A,this.guards=e.guards;let r=this.apiKey.split("_");this.orgId=r.length>=3?r[1]:"unknown",this.startAutoFlush();}startTrace(e){return new h(e,r=>this.record(r))}getHourlyCostDollars(e){let r=Date.now()-36e5,n=(this.hourlyCosts.get(e)??[]).filter(s=>s.timestamp>r);return this.hourlyCosts.set(e,n),n.reduce((s,a)=>s+a.costMicrodollars,0)/1e6}trackHourlyCost(e,r){let o=this.hourlyCosts.get(e)??[];o.push({costMicrodollars:r,timestamp:Date.now()}),this.hourlyCosts.set(e,o);}checkGuards(e){if(!this.guards)return null;let r=this.getHourlyCostDollars(e.agentName),o=M(this.guards,e,r);if(o.triggeredRules.length>0&&(this.recordGuardEvent({eventId:crypto.randomUUID(),timestamp:new Date().toISOString(),agentName:e.agentName,guardMode:this.guards.mode??"notify",decision:o.decision,triggeredRules:o.triggeredRules,contextAnalysis:o.contextAnalysis??void 0,suggestion:o.suggestion}),this.guards.notifySlackWebhook))for(let n of o.triggeredRules)x(this.guards.notifySlackWebhook,{text:`NeuraMeter guard triggered: ${n.ruleType} for agent "${e.agentName}" (${n.currentValue} > ${n.threshold})`,agentName:e.agentName,ruleType:n.ruleType,currentValue:n.currentValue,threshold:n.threshold,suggestion:o.suggestion});if(o.decision==="block"){let n=o.triggeredRules.find(i=>i.isHard);if(n)throw new g(n,o.suggestion??"")}return o}async runAutoOptimize(e){if(!this.guards?.onOptimize||e.guardResult.triggeredRules.length===0)return null;let r=e.guardResult.triggeredRules[0],o={type:r.ruleType,suggestion:e.guardResult.suggestion??"",metrics:{messages:e.messages,model:e.model,currentValue:r.currentValue,threshold:r.threshold}};try{let n=await this.guards.onOptimize(o),i=p("openai",n.model??e.model),s=e.guardResult.contextAnalysis?.estimatedInputTokens??0,a=i?d({inputTokens:s,outputTokens:0},i)/1e6:0;return this.recordGuardEvent({eventId:crypto.randomUUID(),timestamp:new Date().toISOString(),agentName:e.agentName,guardMode:"auto-optimize",decision:n.action==="retry"?"optimized":n.action==="block"?"block":"notify",triggeredRules:e.guardResult.triggeredRules,contextAnalysis:e.guardResult.contextAnalysis??void 0,optimization:{action:n.action,tokensBefore:s,costBefore:a,description:e.guardResult.suggestion},suggestion:e.guardResult.suggestion}),n}catch{return {action:"notify"}}}record(e){let r={...e,eventId:crypto.randomUUID(),timestamp:new Date().toISOString(),orgId:this.orgId,projectId:this.projectId,cost:e.costMicrodollars/1e6};this.buffer.push(r),e.agentName&&e.costMicrodollars>0&&this.trackHourlyCost(e.agentName,e.costMicrodollars),this.buffer.length>=this.batchSize&&this.flush();}recordGuardEvent(e){this.guardBuffer.push(e);}async flush(){if(!(this.buffer.length===0&&this.guardBuffer.length===0||this.flushing)){if(this.flushing=true,this.buffer.length>0){let e=this.buffer.splice(0,this.batchSize);try{(await fetch(`${this.endpoint}/v1/events`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`},body:JSON.stringify({batch:e})})).ok||this.buffer.unshift(...e);}catch{this.buffer.unshift(...e);}}if(this.guardBuffer.length>0){let e=this.guardBuffer.splice(0,this.batchSize);try{await fetch(`${this.endpoint}/v1/guard-events`,{method:"POST",headers:{"Content-Type":"application/json",Authorization:`Bearer ${this.apiKey}`},body:JSON.stringify({batch:e})});}catch{}}this.flushing=false;}}async destroy(){this.timer&&(clearInterval(this.timer),this.timer=null),await this.flush();}startAutoFlush(){this.timer=setInterval(()=>{this.flush();},this.flushIntervalMs),this.timer&&typeof this.timer=="object"&&"unref"in this.timer&&this.timer.unref();}};async function E(t,e,r,o,n){let i=new Date;i.setDate(i.getDate()-7);let{data:s}=await t.from("cost_events").select("cost_microdollars").eq("org_id",e).eq("agent_name",r).gte("event_timestamp",i.toISOString());if(s&&s.length>=5){let a=s.reduce((l,u)=>l+u.cost_microdollars/1e6,0)/s.length,c=Math.max(0,a-o);return {baselineCost:a,saving:c,commission:c*.1,method:"B"}}if(n!==void 0&&n>o){let a=n-o;return {baselineCost:n,saving:a,commission:a*.1,method:"A"}}return {baselineCost:0,saving:0,commission:0,method:"A"}}function v(t){return {inputTokens:t.prompt_tokens??0,outputTokens:t.completion_tokens??0,reasoningTokens:t.completion_tokens_details?.reasoning_tokens??0,cachedTokens:t.prompt_tokens_details?.cached_tokens??0}}function H(t,e,r){let o=t[Symbol.asyncIterator].bind(t);return new Proxy(t,{get(n,i,s){return i===Symbol.asyncIterator?function(){let a=o(),c=null,l=r;return {async next(){let u=await a.next();if(u.done)c&&e(c,l);else {let m=u.value;m.model&&(l=m.model),m.usage&&(c=v(m.usage));}return u},async return(u){return c&&e(c,l),a.return?a.return(u):{done:true,value:void 0}},async throw(u){return a.throw?a.throw(u):Promise.reject(u)}}}:Reflect.get(n,i,s)}})}function G(t,e){let r=new k({apiKey:e.apiKey,projectId:e.projectId,endpoint:e.endpoint??"https://meter.neuria.tech"}),o=e.agentName??"default",n=t.chat.completions.create.bind(t.chat.completions);function i(s,a,c){let l=p("openai",a),u=l?d(s,l):0;r.record({traceId:crypto.randomUUID(),spanId:crypto.randomUUID(),agentName:o,provider:"openai",model:a,inputTokens:s.inputTokens,outputTokens:s.outputTokens,reasoningTokens:s.reasoningTokens??0,cachedTokens:s.cachedTokens??0,costMicrodollars:u,latencyMs:c});}return t.chat.completions.create=async s=>{let a=Date.now(),c=s.model,l=s.stream===true;l&&!s.stream_options&&(s={...s,stream_options:{include_usage:true}});let u=await n(s);if(l&&u&&typeof u=="object"&&Symbol.asyncIterator in u)return H(u,(P,R)=>{let w=Date.now()-a;i(P,R,w);},c);let m=Date.now()-a,T=u;if(T.usage){let P=v(T.usage);i(P,T.model??c,m);}return u},t.__neurameter=r,t.__neurameter_destroy=()=>r.destroy(),t}
|
|
7
|
+
export{f as MODEL_CONTEXT_LIMITS,k as NeuraMeter,g as NeuraMeterGuardError,h as Trace,_ as analyzeContext,d as calculateCostMicrodollars,E as calculateSaving,M as checkGuards,C as estimateTokens,b as getModelContextLimit,p as getModelPricing,x as sendSlackNotification,G as withNeuraMeter};//# sourceMappingURL=index.js.map
|
|
8
8
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/context.ts","../src/cost.ts","../src/pricing.ts","../src/guards.ts","../src/trace.ts","../src/slack.ts","../src/meter.ts"],"names":["MODEL_CONTEXT_LIMITS","estimateTokens","content","str","analyzeContext","messages","model","modelLimit","getModelContextLimit","systemTokens","conversationTokens","toolResultTokens","msg","tokens","total","key","limit","calculateCostMicrodollars","usage","pricing","totalMicrodollars","effectiveInputTokens","integerDivRound","cachedPrice","reasoningPrice","numerator","denominator","quotient","PRICING","getModelPricing","provider","providerPricing","NeuraMeterGuardError","rule","suggestion","checkGuards","config","params","hourlyCostDollars","mode","triggeredRules","contextAnalysis","estimatedDollars","generateSuggestion","hasHardViolation","r","rules","ctx","parts","savingPct","Trace","opts","recordFn","spanId","costMicrodollars","formatValue","ruleType","value","formatRuleType","word","buildSlackPayload","message","blocks","sendSlackNotification","webhookUrl","payload","DEFAULT_BATCH_SIZE","DEFAULT_FLUSH_INTERVAL_MS","NeuraMeter","event","agentName","oneHourAgo","recent","e","entries","result","hardRule","primaryRule","optimizeEvent","tokensBefore","costBefore","fullEvent","batch","guardBatch"],"mappings":"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","file":"index.js","sourcesContent":["export interface ContextAnalysis {\n estimatedInputTokens: number;\n modelContextLimit: number;\n utilizationPercent: number;\n messageCount: number;\n systemPromptTokens: number;\n conversationTokens: number;\n toolResultTokens: number;\n}\n\nexport interface Message {\n role: string;\n content: string | unknown;\n}\n\n/**\n * Model context window limits (tokens).\n */\nexport const MODEL_CONTEXT_LIMITS: Record<string, number> = {\n 'gpt-4o': 128_000,\n 'gpt-4o-mini': 128_000,\n 'gpt-4.1': 1_000_000,\n 'gpt-4.1-mini': 1_000_000,\n 'o1': 200_000,\n 'o3-mini': 200_000,\n 'claude-sonnet-4-20250514': 200_000,\n 'claude-haiku-4-5-20251001': 200_000,\n 'claude-opus-4-20250514': 200_000,\n // Aliases for prefix matching\n 'claude-sonnet-4': 200_000,\n 'claude-haiku-4': 200_000,\n 'claude-opus-4': 200_000,\n};\n\n/**\n * Estimate token count from a string.\n * Uses a simple heuristic: ~4 chars per token for English,\n * ~1.5 chars per token for CJK/mixed content.\n * This is intentionally fast (<1ms) for SDK use.\n */\nexport function estimateTokens(content: string | unknown): number {\n if (typeof content !== 'string') {\n // For non-string content (e.g., tool_use blocks), serialize and estimate\n const str = typeof content === 'object' ? JSON.stringify(content) : String(content ?? '');\n return Math.ceil(str.length / 4);\n }\n // Simple heuristic: average of ~4 chars/token\n return Math.ceil(content.length / 4);\n}\n\n/**\n * Analyze context window utilization for a set of messages.\n */\nexport function analyzeContext(messages: Message[], model: string): ContextAnalysis {\n const modelLimit = getModelContextLimit(model);\n let systemTokens = 0;\n let conversationTokens = 0;\n let toolResultTokens = 0;\n\n for (const msg of messages) {\n const tokens = estimateTokens(msg.content);\n if (msg.role === 'system') {\n systemTokens += tokens;\n } else if (msg.role === 'tool') {\n toolResultTokens += tokens;\n } else {\n conversationTokens += tokens;\n }\n }\n\n const total = systemTokens + conversationTokens + toolResultTokens;\n\n return {\n estimatedInputTokens: total,\n modelContextLimit: modelLimit,\n utilizationPercent: modelLimit > 0 ? total / modelLimit : 0,\n messageCount: messages.length,\n systemPromptTokens: systemTokens,\n conversationTokens,\n toolResultTokens,\n };\n}\n\n/**\n * Get model context limit with prefix matching fallback.\n */\nexport function getModelContextLimit(model: string): number {\n if (MODEL_CONTEXT_LIMITS[model] !== undefined) {\n return MODEL_CONTEXT_LIMITS[model]!;\n }\n // Prefix match for versioned model names\n for (const [key, limit] of Object.entries(MODEL_CONTEXT_LIMITS)) {\n if (model.startsWith(key)) return limit;\n }\n return 128_000; // Default fallback\n}\n","import type { ModelPricing, TokenUsage } from './types';\n\n/**\n * Calculate cost in microdollars using integer arithmetic only.\n *\n * Pricing values are stored as microdollars per million tokens.\n * Formula: tokens * pricePerMToken / 1_000_000\n * (result is already in microdollars since price is in microdollars)\n *\n * To avoid floating-point, we compute:\n * cost = Math.round(tokens * pricePerMToken / 1_000_000)\n *\n * Since pricePerMToken is already an integer (microdollars per 1M tokens),\n * and tokens is an integer, the only division is by 1_000_000.\n * We use Math.round to get the nearest integer microdollar.\n */\nexport function calculateCostMicrodollars(\n usage: TokenUsage,\n pricing: ModelPricing,\n): number {\n let totalMicrodollars = 0;\n\n // Input tokens cost\n const effectiveInputTokens = usage.inputTokens - (usage.cachedTokens ?? 0);\n if (effectiveInputTokens > 0) {\n totalMicrodollars += integerDivRound(\n effectiveInputTokens * pricing.inputPricePerMToken,\n 1_000_000,\n );\n }\n\n // Cached tokens cost (discounted rate)\n if (usage.cachedTokens && usage.cachedTokens > 0) {\n const cachedPrice = pricing.cachedInputPricePerMToken ?? pricing.inputPricePerMToken;\n totalMicrodollars += integerDivRound(\n usage.cachedTokens * cachedPrice,\n 1_000_000,\n );\n }\n\n // Output tokens cost\n if (usage.outputTokens > 0) {\n totalMicrodollars += integerDivRound(\n usage.outputTokens * pricing.outputPricePerMToken,\n 1_000_000,\n );\n }\n\n // Reasoning tokens cost\n if (usage.reasoningTokens && usage.reasoningTokens > 0) {\n const reasoningPrice = pricing.reasoningPricePerMToken ?? pricing.outputPricePerMToken;\n totalMicrodollars += integerDivRound(\n usage.reasoningTokens * reasoningPrice,\n 1_000_000,\n );\n }\n\n return totalMicrodollars;\n}\n\n/**\n * Integer division with rounding (avoids floating-point).\n * Computes Math.round(numerator / denominator) using only integer ops.\n */\nfunction integerDivRound(numerator: number, denominator: number): number {\n const quotient = Math.trunc(numerator / denominator);\n const remainder = numerator - quotient * denominator;\n // Round: if remainder >= half the denominator, round up\n if (remainder * 2 >= denominator) {\n return quotient + 1;\n }\n return quotient;\n}\n","import type { ModelPricing } from './types';\n\n/**\n * Built-in pricing data — microdollars per million tokens.\n * e.g. $2.50 per 1M tokens = 2_500_000 microdollars per 1M tokens\n */\nconst PRICING: Record<string, Record<string, ModelPricing>> = {\n openai: {\n 'gpt-4o': {\n inputPricePerMToken: 2_500_000,\n outputPricePerMToken: 10_000_000,\n cachedInputPricePerMToken: 1_250_000,\n },\n 'gpt-4o-mini': {\n inputPricePerMToken: 150_000,\n outputPricePerMToken: 600_000,\n cachedInputPricePerMToken: 75_000,\n },\n 'gpt-4.1': {\n inputPricePerMToken: 2_000_000,\n outputPricePerMToken: 8_000_000,\n cachedInputPricePerMToken: 500_000,\n },\n 'gpt-4.1-mini': {\n inputPricePerMToken: 400_000,\n outputPricePerMToken: 1_600_000,\n cachedInputPricePerMToken: 100_000,\n },\n o1: {\n inputPricePerMToken: 15_000_000,\n outputPricePerMToken: 60_000_000,\n reasoningPricePerMToken: 60_000_000,\n cachedInputPricePerMToken: 7_500_000,\n },\n 'o3-mini': {\n inputPricePerMToken: 1_100_000,\n outputPricePerMToken: 4_400_000,\n reasoningPricePerMToken: 4_400_000,\n cachedInputPricePerMToken: 550_000,\n },\n },\n anthropic: {\n 'claude-sonnet-4-20250514': {\n inputPricePerMToken: 3_000_000,\n outputPricePerMToken: 15_000_000,\n cachedInputPricePerMToken: 300_000,\n },\n 'claude-haiku-4-5-20251001': {\n inputPricePerMToken: 800_000,\n outputPricePerMToken: 4_000_000,\n cachedInputPricePerMToken: 80_000,\n },\n 'claude-opus-4-20250514': {\n inputPricePerMToken: 15_000_000,\n outputPricePerMToken: 75_000_000,\n cachedInputPricePerMToken: 1_500_000,\n },\n },\n google: {\n 'gemini-2.5-pro': {\n inputPricePerMToken: 1_250_000,\n outputPricePerMToken: 10_000_000,\n cachedInputPricePerMToken: 315_000,\n },\n 'gemini-2.5-flash': {\n inputPricePerMToken: 150_000,\n outputPricePerMToken: 600_000,\n cachedInputPricePerMToken: 37_500,\n },\n 'gemini-2.0-flash': {\n inputPricePerMToken: 100_000,\n outputPricePerMToken: 400_000,\n cachedInputPricePerMToken: 25_000,\n },\n 'gemini-1.5-pro': {\n inputPricePerMToken: 1_250_000,\n outputPricePerMToken: 5_000_000,\n cachedInputPricePerMToken: 315_000,\n },\n 'gemini-1.5-flash': {\n inputPricePerMToken: 75_000,\n outputPricePerMToken: 300_000,\n cachedInputPricePerMToken: 18_750,\n },\n },\n groq: {\n 'llama-3.3-70b-versatile': {\n inputPricePerMToken: 590_000,\n outputPricePerMToken: 790_000,\n },\n 'llama-3.1-8b-instant': {\n inputPricePerMToken: 50_000,\n outputPricePerMToken: 80_000,\n },\n 'llama-3-70b': {\n inputPricePerMToken: 590_000,\n outputPricePerMToken: 790_000,\n },\n 'mixtral-8x7b': {\n inputPricePerMToken: 240_000,\n outputPricePerMToken: 240_000,\n },\n 'gemma2-9b-it': {\n inputPricePerMToken: 200_000,\n outputPricePerMToken: 200_000,\n },\n },\n mistral: {\n 'mistral-large': {\n inputPricePerMToken: 2_000_000,\n outputPricePerMToken: 6_000_000,\n },\n 'mistral-small': {\n inputPricePerMToken: 200_000,\n outputPricePerMToken: 600_000,\n },\n 'codestral': {\n inputPricePerMToken: 300_000,\n outputPricePerMToken: 900_000,\n },\n 'mistral-embed': {\n inputPricePerMToken: 100_000,\n outputPricePerMToken: 0,\n },\n 'open-mistral-nemo': {\n inputPricePerMToken: 150_000,\n outputPricePerMToken: 150_000,\n },\n },\n};\n\nexport function getModelPricing(\n provider: string,\n model: string,\n): ModelPricing | undefined {\n const providerPricing = PRICING[provider];\n if (!providerPricing) return undefined;\n\n // Exact match first\n if (providerPricing[model]) return providerPricing[model];\n\n // Prefix match: e.g. \"gpt-4o-mini-2024-07-18\" → \"gpt-4o-mini\"\n for (const key of Object.keys(providerPricing)) {\n if (model.startsWith(key)) return providerPricing[key];\n }\n\n return undefined;\n}\n","import type { ContextAnalysis, Message } from './context';\nimport { analyzeContext } from './context';\nimport { calculateCostMicrodollars } from './cost';\nimport { getModelPricing } from './pricing';\n\nexport type GuardMode = 'notify' | 'block' | 'auto-optimize';\nexport type GuardDecision = 'allow' | 'notify' | 'block' | 'optimized';\n\nexport interface GuardsConfig {\n maxInputTokens?: number;\n maxInputTokensHard?: number;\n maxContextUtilization?: number;\n maxContextUtilizationHard?: number;\n maxCostPerCall?: number;\n maxCostPerCallHard?: number;\n maxCostPerHour?: number;\n mode?: GuardMode;\n notifySlackWebhook?: string;\n notifyDashboard?: boolean;\n onOptimize?: (event: OptimizeEvent) => Promise<OptimizeResult>;\n}\n\nexport interface TriggeredRule {\n ruleType: 'input_tokens' | 'cost_per_call' | 'cost_per_hour' | 'context_utilization' | 'budget';\n currentValue: number;\n threshold: number;\n isHard: boolean;\n}\n\nexport interface GuardCheckResult {\n decision: GuardDecision;\n triggeredRules: TriggeredRule[];\n contextAnalysis: ContextAnalysis | null;\n suggestion?: string;\n}\n\nexport interface GuardEvent {\n eventId: string;\n timestamp: string;\n agentName: string;\n guardMode: GuardMode;\n decision: GuardDecision;\n triggeredRules: TriggeredRule[];\n contextAnalysis?: ContextAnalysis;\n optimization?: {\n action: 'retry' | 'notify' | 'block';\n tokensBefore: number;\n tokensAfter?: number;\n costBefore: number;\n costAfter?: number;\n description?: string;\n };\n suggestion?: string;\n}\n\nexport interface OptimizeEvent {\n type: 'context_utilization' | 'cost_per_call' | 'input_tokens';\n suggestion: string;\n metrics: {\n messages?: Message[];\n model?: string;\n currentValue: number;\n threshold: number;\n };\n}\n\nexport interface OptimizeResult {\n action: 'retry' | 'notify' | 'block';\n messages?: Message[];\n model?: string;\n}\n\n/**\n * Error thrown when guard mode is 'block' and a hard limit is exceeded.\n */\nexport class NeuraMeterGuardError extends Error {\n readonly rule: string;\n readonly current: number;\n readonly threshold: number;\n readonly suggestion: string;\n\n constructor(rule: TriggeredRule, suggestion: string) {\n super(`NeuraMeter guard: ${rule.ruleType} exceeded (${rule.currentValue} > ${rule.threshold})`);\n this.name = 'NeuraMeterGuardError';\n this.rule = rule.ruleType;\n this.current = rule.currentValue;\n this.threshold = rule.threshold;\n this.suggestion = suggestion;\n }\n}\n\n/**\n * Check guard rules before an API call.\n * Returns the decision and any triggered rules.\n */\nexport function checkGuards(\n config: GuardsConfig,\n params: {\n messages: Message[];\n model: string;\n provider: string;\n agentName: string;\n },\n hourlyCostDollars?: number,\n): GuardCheckResult {\n const mode = config.mode ?? 'notify';\n const triggeredRules: TriggeredRule[] = [];\n\n // Context analysis\n const contextAnalysis = analyzeContext(params.messages, params.model);\n\n // Check input tokens\n if (config.maxInputTokens && contextAnalysis.estimatedInputTokens > config.maxInputTokens) {\n triggeredRules.push({\n ruleType: 'input_tokens',\n currentValue: contextAnalysis.estimatedInputTokens,\n threshold: config.maxInputTokens,\n isHard: false,\n });\n }\n if (config.maxInputTokensHard && contextAnalysis.estimatedInputTokens > config.maxInputTokensHard) {\n triggeredRules.push({\n ruleType: 'input_tokens',\n currentValue: contextAnalysis.estimatedInputTokens,\n threshold: config.maxInputTokensHard,\n isHard: true,\n });\n }\n\n // Check context utilization\n if (config.maxContextUtilization && contextAnalysis.utilizationPercent > config.maxContextUtilization) {\n triggeredRules.push({\n ruleType: 'context_utilization',\n currentValue: contextAnalysis.utilizationPercent,\n threshold: config.maxContextUtilization,\n isHard: false,\n });\n }\n if (config.maxContextUtilizationHard && contextAnalysis.utilizationPercent > config.maxContextUtilizationHard) {\n triggeredRules.push({\n ruleType: 'context_utilization',\n currentValue: contextAnalysis.utilizationPercent,\n threshold: config.maxContextUtilizationHard,\n isHard: true,\n });\n }\n\n // Check estimated cost per call\n if (config.maxCostPerCall || config.maxCostPerCallHard) {\n const pricing = getModelPricing(params.provider, params.model);\n if (pricing) {\n const estimatedCost = calculateCostMicrodollars(\n { inputTokens: contextAnalysis.estimatedInputTokens, outputTokens: 0 },\n pricing,\n );\n const estimatedDollars = estimatedCost / 1_000_000;\n\n if (config.maxCostPerCall && estimatedDollars > config.maxCostPerCall) {\n triggeredRules.push({\n ruleType: 'cost_per_call',\n currentValue: estimatedDollars,\n threshold: config.maxCostPerCall,\n isHard: false,\n });\n }\n if (config.maxCostPerCallHard && estimatedDollars > config.maxCostPerCallHard) {\n triggeredRules.push({\n ruleType: 'cost_per_call',\n currentValue: estimatedDollars,\n threshold: config.maxCostPerCallHard,\n isHard: true,\n });\n }\n }\n }\n\n // Check cost per hour\n if (config.maxCostPerHour && hourlyCostDollars !== undefined && hourlyCostDollars > config.maxCostPerHour) {\n triggeredRules.push({\n ruleType: 'cost_per_hour',\n currentValue: hourlyCostDollars,\n threshold: config.maxCostPerHour,\n isHard: mode === 'block',\n });\n }\n\n // Generate suggestion\n const suggestion = generateSuggestion(triggeredRules, contextAnalysis);\n\n // Determine decision based on mode\n if (triggeredRules.length === 0) {\n return { decision: 'allow', triggeredRules, contextAnalysis, suggestion };\n }\n\n const hasHardViolation = triggeredRules.some((r) => r.isHard);\n\n switch (mode) {\n case 'notify':\n return { decision: 'notify', triggeredRules, contextAnalysis, suggestion };\n\n case 'block':\n if (hasHardViolation) {\n return { decision: 'block', triggeredRules, contextAnalysis, suggestion };\n }\n return { decision: 'notify', triggeredRules, contextAnalysis, suggestion };\n\n case 'auto-optimize':\n return { decision: 'notify', triggeredRules, contextAnalysis, suggestion };\n\n default:\n return { decision: 'allow', triggeredRules, contextAnalysis, suggestion };\n }\n}\n\nfunction generateSuggestion(rules: TriggeredRule[], ctx: ContextAnalysis): string {\n if (rules.length === 0) return '';\n\n const parts: string[] = [];\n\n for (const rule of rules) {\n switch (rule.ruleType) {\n case 'context_utilization':\n if (ctx.conversationTokens > ctx.systemPromptTokens) {\n const savingPct = Math.round((ctx.conversationTokens / ctx.estimatedInputTokens) * 100);\n parts.push(`Summarize conversation history to save ~${savingPct}% of input tokens`);\n }\n break;\n case 'input_tokens':\n parts.push(`Reduce input tokens from ${ctx.estimatedInputTokens.toLocaleString()} to under ${rule.threshold.toLocaleString()}`);\n break;\n case 'cost_per_call':\n parts.push('Consider using a cheaper model (e.g., gpt-4o-mini or claude-haiku)');\n break;\n case 'cost_per_hour':\n parts.push(`Hourly cost limit exceeded ($${rule.currentValue.toFixed(2)} > $${rule.threshold.toFixed(2)}). Throttle or pause agent calls`);\n break;\n }\n }\n\n return parts.join('. ') || 'Review guard thresholds or optimize context usage';\n}\n","import type { CostEvent, Provider, TraceOptions, TokenUsage } from './types';\nimport { calculateCostMicrodollars } from './cost';\nimport { getModelPricing } from './pricing';\n\nexport class Trace {\n readonly traceId: string;\n private readonly agentName: string;\n private readonly customerId?: string;\n private readonly taskName?: string;\n private readonly tags?: Record<string, string>;\n private readonly recordFn: (event: Omit<CostEvent, 'eventId' | 'timestamp' | 'orgId' | 'projectId' | 'cost'>) => void;\n\n constructor(\n opts: TraceOptions,\n recordFn: (event: Omit<CostEvent, 'eventId' | 'timestamp' | 'orgId' | 'projectId' | 'cost'>) => void,\n ) {\n this.traceId = crypto.randomUUID();\n this.agentName = opts.agentName;\n this.customerId = opts.customerId;\n this.taskName = opts.taskName;\n this.tags = opts.tags;\n this.recordFn = recordFn;\n }\n\n span(opts: {\n provider: Provider;\n model: string;\n usage: TokenUsage;\n latencyMs: number;\n parentSpanId?: string;\n agentName?: string;\n taskName?: string;\n tags?: Record<string, string>;\n }): string {\n const spanId = crypto.randomUUID();\n const pricing = getModelPricing(opts.provider, opts.model);\n const costMicrodollars = pricing\n ? calculateCostMicrodollars(opts.usage, pricing)\n : 0;\n\n this.recordFn({\n traceId: this.traceId,\n spanId,\n parentSpanId: opts.parentSpanId,\n agentName: opts.agentName ?? this.agentName,\n taskName: opts.taskName ?? this.taskName,\n customerId: this.customerId,\n provider: opts.provider,\n model: opts.model,\n inputTokens: opts.usage.inputTokens,\n outputTokens: opts.usage.outputTokens,\n reasoningTokens: opts.usage.reasoningTokens,\n cachedTokens: opts.usage.cachedTokens,\n costMicrodollars,\n latencyMs: opts.latencyMs,\n tags: { ...this.tags, ...opts.tags },\n });\n\n return spanId;\n }\n}\n","/**\n * Slack notification utility for NeuraMeter guard alerts.\n * Sends Block Kit formatted messages via incoming webhooks.\n */\n\nexport interface SlackMessage {\n /** Plain text fallback */\n text: string;\n /** Name of the agent that triggered the guard */\n agentName: string;\n /** Type of guard rule triggered (e.g. 'context_utilization', 'input_tokens') */\n ruleType: string;\n /** Current value that exceeded the threshold */\n currentValue: number;\n /** Configured threshold that was exceeded */\n threshold: number;\n /** Optimization suggestion from the guard system */\n suggestion?: string;\n}\n\n/**\n * Format a value for display based on the rule type.\n */\nfunction formatValue(ruleType: string, value: number): string {\n switch (ruleType) {\n case 'context_utilization':\n return `${value.toFixed(1)}%`;\n case 'cost_per_call':\n case 'cost_per_hour':\n case 'budget':\n return `$${value.toFixed(4)}`;\n case 'input_tokens':\n return value.toLocaleString();\n default:\n return String(value);\n }\n}\n\n/**\n * Format a rule type string for human-readable display.\n */\nfunction formatRuleType(ruleType: string): string {\n return ruleType\n .split('_')\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(' ');\n}\n\n/**\n * Build a Slack Block Kit payload for a guard alert.\n */\nfunction buildSlackPayload(message: SlackMessage): object {\n const blocks: object[] = [\n {\n type: 'header',\n text: {\n type: 'plain_text',\n text: `:warning: NeuraMeter Guard Alert`,\n emoji: true,\n },\n },\n {\n type: 'section',\n fields: [\n {\n type: 'mrkdwn',\n text: `*Agent:*\\n${message.agentName}`,\n },\n {\n type: 'mrkdwn',\n text: `*Rule Triggered:*\\n${formatRuleType(message.ruleType)}`,\n },\n {\n type: 'mrkdwn',\n text: `*Current Value:*\\n${formatValue(message.ruleType, message.currentValue)}`,\n },\n {\n type: 'mrkdwn',\n text: `*Threshold:*\\n${formatValue(message.ruleType, message.threshold)}`,\n },\n ],\n },\n ];\n\n if (message.suggestion) {\n blocks.push({\n type: 'section',\n text: {\n type: 'mrkdwn',\n text: `*Suggestion:*\\n${message.suggestion}`,\n },\n });\n }\n\n blocks.push({\n type: 'context',\n elements: [\n {\n type: 'mrkdwn',\n text: `Sent by NeuraMeter at ${new Date().toISOString()}`,\n },\n ],\n });\n\n return {\n text: message.text,\n blocks,\n };\n}\n\n/**\n * Send a Slack notification via an incoming webhook.\n * Fire-and-forget: errors are silently caught and do not propagate.\n *\n * @param webhookUrl - Slack incoming webhook URL\n * @param message - Structured alert message\n */\nexport async function sendSlackNotification(\n webhookUrl: string,\n message: SlackMessage,\n): Promise<void> {\n try {\n const payload = buildSlackPayload(message);\n await fetch(webhookUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n });\n } catch {\n // Fire-and-forget: silently ignore errors\n }\n}\n","import type { CostEvent, NeuraMeterConfig, TraceOptions } from './types';\nimport type { GuardsConfig, GuardCheckResult, GuardEvent, OptimizeEvent, OptimizeResult } from './guards';\nimport { checkGuards, NeuraMeterGuardError } from './guards';\nimport type { Message } from './context';\nimport { Trace } from './trace';\nimport { calculateCostMicrodollars } from './cost';\nimport { getModelPricing } from './pricing';\nimport { sendSlackNotification } from './slack';\n\nconst DEFAULT_BATCH_SIZE = 50;\nconst DEFAULT_FLUSH_INTERVAL_MS = 5_000;\n\n/** Tracks cost accumulated within a rolling 1-hour window per agent. */\ninterface HourlyCostEntry {\n costMicrodollars: number;\n timestamp: number;\n}\n\nexport class NeuraMeter {\n private readonly apiKey: string;\n private readonly projectId: string;\n private readonly endpoint: string;\n private readonly batchSize: number;\n private readonly flushIntervalMs: number;\n readonly guards: GuardsConfig | undefined;\n\n private buffer: CostEvent[] = [];\n private guardBuffer: GuardEvent[] = [];\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private timer: any = null;\n private flushing = false;\n\n /** Rolling hourly cost tracking per agent for maxCostPerHour guard */\n private hourlyCosts: Map<string, HourlyCostEntry[]> = new Map();\n\n /** Extracted from API key format: nm_{orgId}_{secret} */\n private readonly orgId: string;\n\n constructor(config: NeuraMeterConfig) {\n this.apiKey = config.apiKey;\n this.projectId = config.projectId;\n this.endpoint = config.endpoint ?? 'https://neurameter-ingestion.neurameter.workers.dev';\n this.batchSize = config.batchSize ?? DEFAULT_BATCH_SIZE;\n this.flushIntervalMs = config.flushIntervalMs ?? DEFAULT_FLUSH_INTERVAL_MS;\n this.guards = config.guards;\n\n // Extract orgId from API key (format: nm_{orgId}_{secret})\n const parts = this.apiKey.split('_');\n this.orgId = parts.length >= 3 ? parts[1]! : 'unknown';\n\n this.startAutoFlush();\n }\n\n startTrace(opts: TraceOptions): Trace {\n return new Trace(opts, (event) => this.record(event));\n }\n\n /**\n * Get rolling hourly cost for an agent (in dollars).\n */\n getHourlyCostDollars(agentName: string): number {\n const oneHourAgo = Date.now() - 3_600_000;\n const entries = this.hourlyCosts.get(agentName) ?? [];\n // Prune old entries\n const recent = entries.filter((e) => e.timestamp > oneHourAgo);\n this.hourlyCosts.set(agentName, recent);\n const totalMicro = recent.reduce((s, e) => s + e.costMicrodollars, 0);\n return totalMicro / 1_000_000;\n }\n\n /**\n * Track cost for hourly rate limiting.\n */\n private trackHourlyCost(agentName: string, costMicrodollars: number): void {\n const entries = this.hourlyCosts.get(agentName) ?? [];\n entries.push({ costMicrodollars, timestamp: Date.now() });\n this.hourlyCosts.set(agentName, entries);\n }\n\n /**\n * Check guard rules before an API call.\n * Returns the check result. In block mode, may throw NeuraMeterGuardError.\n */\n checkGuards(params: {\n messages: Message[];\n model: string;\n provider: string;\n agentName: string;\n }): GuardCheckResult | null {\n if (!this.guards) return null;\n\n const hourlyCostDollars = this.getHourlyCostDollars(params.agentName);\n const result = checkGuards(this.guards, params, hourlyCostDollars);\n\n // Record guard event (async, fire-and-forget)\n if (result.triggeredRules.length > 0) {\n this.recordGuardEvent({\n eventId: crypto.randomUUID(),\n timestamp: new Date().toISOString(),\n agentName: params.agentName,\n guardMode: this.guards.mode ?? 'notify',\n decision: result.decision,\n triggeredRules: result.triggeredRules,\n contextAnalysis: result.contextAnalysis ?? undefined,\n suggestion: result.suggestion,\n });\n\n // Send Slack notification if configured (async, fire-and-forget)\n if (this.guards.notifySlackWebhook) {\n for (const rule of result.triggeredRules) {\n void sendSlackNotification(this.guards.notifySlackWebhook, {\n text: `NeuraMeter guard triggered: ${rule.ruleType} for agent \"${params.agentName}\" (${rule.currentValue} > ${rule.threshold})`,\n agentName: params.agentName,\n ruleType: rule.ruleType,\n currentValue: rule.currentValue,\n threshold: rule.threshold,\n suggestion: result.suggestion,\n });\n }\n }\n }\n\n // In block mode with hard violation, throw\n if (result.decision === 'block') {\n const hardRule = result.triggeredRules.find((r) => r.isHard);\n if (hardRule) {\n throw new NeuraMeterGuardError(hardRule, result.suggestion ?? '');\n }\n }\n\n return result;\n }\n\n /**\n * Run auto-optimize flow: calls the onOptimize callback and returns the result.\n * Used by SDK wrappers when mode is 'auto-optimize' and thresholds are exceeded.\n */\n async runAutoOptimize(params: {\n guardResult: GuardCheckResult;\n messages: Message[];\n model: string;\n agentName: string;\n }): Promise<OptimizeResult | null> {\n if (!this.guards?.onOptimize || params.guardResult.triggeredRules.length === 0) {\n return null;\n }\n\n const primaryRule = params.guardResult.triggeredRules[0]!;\n const optimizeEvent: OptimizeEvent = {\n type: primaryRule.ruleType as OptimizeEvent['type'],\n suggestion: params.guardResult.suggestion ?? '',\n metrics: {\n messages: params.messages,\n model: params.model,\n currentValue: primaryRule.currentValue,\n threshold: primaryRule.threshold,\n },\n };\n\n try {\n const result = await this.guards.onOptimize(optimizeEvent);\n\n // Record optimization in guard event\n const pricing = getModelPricing(\n 'openai', // Best effort — wrappers will provide actual provider\n result.model ?? params.model,\n );\n const tokensBefore = params.guardResult.contextAnalysis?.estimatedInputTokens ?? 0;\n const costBefore = pricing\n ? calculateCostMicrodollars({ inputTokens: tokensBefore, outputTokens: 0 }, pricing) / 1_000_000\n : 0;\n\n this.recordGuardEvent({\n eventId: crypto.randomUUID(),\n timestamp: new Date().toISOString(),\n agentName: params.agentName,\n guardMode: 'auto-optimize',\n decision: result.action === 'retry' ? 'optimized' : result.action === 'block' ? 'block' : 'notify',\n triggeredRules: params.guardResult.triggeredRules,\n contextAnalysis: params.guardResult.contextAnalysis ?? undefined,\n optimization: {\n action: result.action,\n tokensBefore,\n costBefore,\n description: params.guardResult.suggestion,\n },\n suggestion: params.guardResult.suggestion,\n });\n\n return result;\n } catch {\n // If onOptimize fails, fall through to notify\n return { action: 'notify' };\n }\n }\n\n record(event: Omit<CostEvent, 'eventId' | 'timestamp' | 'orgId' | 'projectId' | 'cost'>): void {\n const fullEvent: CostEvent = {\n ...event,\n eventId: crypto.randomUUID(),\n timestamp: new Date().toISOString(),\n orgId: this.orgId,\n projectId: this.projectId,\n cost: event.costMicrodollars / 1_000_000,\n };\n\n this.buffer.push(fullEvent);\n\n // Track hourly cost for rate limiting\n if (event.agentName && event.costMicrodollars > 0) {\n this.trackHourlyCost(event.agentName, event.costMicrodollars);\n }\n\n if (this.buffer.length >= this.batchSize) {\n void this.flush();\n }\n }\n\n private recordGuardEvent(event: GuardEvent): void {\n this.guardBuffer.push(event);\n // Flush guard events alongside regular events\n }\n\n async flush(): Promise<void> {\n if ((this.buffer.length === 0 && this.guardBuffer.length === 0) || this.flushing) return;\n\n this.flushing = true;\n\n // Flush cost events\n if (this.buffer.length > 0) {\n const batch = this.buffer.splice(0, this.batchSize);\n try {\n const response = await fetch(`${this.endpoint}/v1/events`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.apiKey}`,\n },\n body: JSON.stringify({ batch }),\n });\n if (!response.ok) {\n this.buffer.unshift(...batch);\n }\n } catch {\n this.buffer.unshift(...batch);\n }\n }\n\n // Flush guard events\n if (this.guardBuffer.length > 0) {\n const guardBatch = this.guardBuffer.splice(0, this.batchSize);\n try {\n await fetch(`${this.endpoint}/v1/guard-events`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.apiKey}`,\n },\n body: JSON.stringify({ batch: guardBatch }),\n });\n } catch {\n // Fire-and-forget for guard events\n }\n }\n\n this.flushing = false;\n }\n\n async destroy(): Promise<void> {\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n await this.flush();\n }\n\n private startAutoFlush(): void {\n this.timer = setInterval(() => {\n void this.flush();\n }, this.flushIntervalMs);\n\n if (this.timer && typeof this.timer === 'object' && 'unref' in this.timer) {\n (this.timer as { unref: () => void }).unref();\n }\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/context.ts","../src/cost.ts","../src/pricing.ts","../src/guards.ts","../src/trace.ts","../src/slack.ts","../src/meter.ts","../src/savings.ts","../src/openai.ts"],"names":["MODEL_CONTEXT_LIMITS","estimateTokens","content","str","analyzeContext","messages","model","modelLimit","getModelContextLimit","systemTokens","conversationTokens","toolResultTokens","msg","tokens","total","key","limit","calculateCostMicrodollars","usage","pricing","totalMicrodollars","effectiveInputTokens","integerDivRound","cachedPrice","reasoningPrice","numerator","denominator","quotient","PRICING","getModelPricing","provider","providerPricing","NeuraMeterGuardError","rule","suggestion","checkGuards","config","params","hourlyCostDollars","mode","triggeredRules","contextAnalysis","estimatedDollars","generateSuggestion","hasHardViolation","r","rules","ctx","parts","savingPct","Trace","opts","recordFn","spanId","costMicrodollars","formatValue","ruleType","value","formatRuleType","word","buildSlackPayload","message","blocks","sendSlackNotification","webhookUrl","payload","DEFAULT_BATCH_SIZE","DEFAULT_FLUSH_INTERVAL_MS","NeuraMeter","event","agentName","oneHourAgo","recent","e","entries","result","hardRule","primaryRule","optimizeEvent","tokensBefore","costBefore","fullEvent","batch","guardBatch","calculateSaving","supabase","orgId","actualCost","sevenDaysAgo","data","avgCost","sum","saving","extractUsage","wrapStream","stream","onDone","requestModel","originalIterator","target","prop","receiver","iter","capturedUsage","capturedModel","chunk","err","withNeuraMeter","client","meter","originalCreate","recordEvent","latencyMs","startTime","isStream","resolvedModel","response"],"mappings":"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","file":"index.js","sourcesContent":["export interface ContextAnalysis {\n estimatedInputTokens: number;\n modelContextLimit: number;\n utilizationPercent: number;\n messageCount: number;\n systemPromptTokens: number;\n conversationTokens: number;\n toolResultTokens: number;\n}\n\nexport interface Message {\n role: string;\n content: string | unknown;\n}\n\n/**\n * Model context window limits (tokens).\n */\nexport const MODEL_CONTEXT_LIMITS: Record<string, number> = {\n 'gpt-4o': 128_000,\n 'gpt-4o-mini': 128_000,\n 'gpt-4.1': 1_000_000,\n 'gpt-4.1-mini': 1_000_000,\n 'o1': 200_000,\n 'o3-mini': 200_000,\n 'claude-sonnet-4-20250514': 200_000,\n 'claude-haiku-4-5-20251001': 200_000,\n 'claude-opus-4-20250514': 200_000,\n // Aliases for prefix matching\n 'claude-sonnet-4': 200_000,\n 'claude-haiku-4': 200_000,\n 'claude-opus-4': 200_000,\n};\n\n/**\n * Estimate token count from a string.\n * Uses a simple heuristic: ~4 chars per token for English,\n * ~1.5 chars per token for CJK/mixed content.\n * This is intentionally fast (<1ms) for SDK use.\n */\nexport function estimateTokens(content: string | unknown): number {\n if (typeof content !== 'string') {\n // For non-string content (e.g., tool_use blocks), serialize and estimate\n const str = typeof content === 'object' ? JSON.stringify(content) : String(content ?? '');\n return Math.ceil(str.length / 4);\n }\n // Simple heuristic: average of ~4 chars/token\n return Math.ceil(content.length / 4);\n}\n\n/**\n * Analyze context window utilization for a set of messages.\n */\nexport function analyzeContext(messages: Message[], model: string): ContextAnalysis {\n const modelLimit = getModelContextLimit(model);\n let systemTokens = 0;\n let conversationTokens = 0;\n let toolResultTokens = 0;\n\n for (const msg of messages) {\n const tokens = estimateTokens(msg.content);\n if (msg.role === 'system') {\n systemTokens += tokens;\n } else if (msg.role === 'tool') {\n toolResultTokens += tokens;\n } else {\n conversationTokens += tokens;\n }\n }\n\n const total = systemTokens + conversationTokens + toolResultTokens;\n\n return {\n estimatedInputTokens: total,\n modelContextLimit: modelLimit,\n utilizationPercent: modelLimit > 0 ? total / modelLimit : 0,\n messageCount: messages.length,\n systemPromptTokens: systemTokens,\n conversationTokens,\n toolResultTokens,\n };\n}\n\n/**\n * Get model context limit with prefix matching fallback.\n */\nexport function getModelContextLimit(model: string): number {\n if (MODEL_CONTEXT_LIMITS[model] !== undefined) {\n return MODEL_CONTEXT_LIMITS[model]!;\n }\n // Prefix match for versioned model names\n for (const [key, limit] of Object.entries(MODEL_CONTEXT_LIMITS)) {\n if (model.startsWith(key)) return limit;\n }\n return 128_000; // Default fallback\n}\n","import type { ModelPricing, TokenUsage } from './types';\n\n/**\n * Calculate cost in microdollars using integer arithmetic only.\n *\n * Pricing values are stored as microdollars per million tokens.\n * Formula: tokens * pricePerMToken / 1_000_000\n * (result is already in microdollars since price is in microdollars)\n *\n * To avoid floating-point, we compute:\n * cost = Math.round(tokens * pricePerMToken / 1_000_000)\n *\n * Since pricePerMToken is already an integer (microdollars per 1M tokens),\n * and tokens is an integer, the only division is by 1_000_000.\n * We use Math.round to get the nearest integer microdollar.\n */\nexport function calculateCostMicrodollars(\n usage: TokenUsage,\n pricing: ModelPricing,\n): number {\n let totalMicrodollars = 0;\n\n // Input tokens cost\n const effectiveInputTokens = usage.inputTokens - (usage.cachedTokens ?? 0);\n if (effectiveInputTokens > 0) {\n totalMicrodollars += integerDivRound(\n effectiveInputTokens * pricing.inputPricePerMToken,\n 1_000_000,\n );\n }\n\n // Cached tokens cost (discounted rate)\n if (usage.cachedTokens && usage.cachedTokens > 0) {\n const cachedPrice = pricing.cachedInputPricePerMToken ?? pricing.inputPricePerMToken;\n totalMicrodollars += integerDivRound(\n usage.cachedTokens * cachedPrice,\n 1_000_000,\n );\n }\n\n // Output tokens cost\n if (usage.outputTokens > 0) {\n totalMicrodollars += integerDivRound(\n usage.outputTokens * pricing.outputPricePerMToken,\n 1_000_000,\n );\n }\n\n // Reasoning tokens cost\n if (usage.reasoningTokens && usage.reasoningTokens > 0) {\n const reasoningPrice = pricing.reasoningPricePerMToken ?? pricing.outputPricePerMToken;\n totalMicrodollars += integerDivRound(\n usage.reasoningTokens * reasoningPrice,\n 1_000_000,\n );\n }\n\n return totalMicrodollars;\n}\n\n/**\n * Integer division with rounding (avoids floating-point).\n * Computes Math.round(numerator / denominator) using only integer ops.\n */\nfunction integerDivRound(numerator: number, denominator: number): number {\n const quotient = Math.trunc(numerator / denominator);\n const remainder = numerator - quotient * denominator;\n // Round: if remainder >= half the denominator, round up\n if (remainder * 2 >= denominator) {\n return quotient + 1;\n }\n return quotient;\n}\n","import type { ModelPricing } from './types';\n\n/**\n * Built-in pricing data — microdollars per million tokens.\n * e.g. $2.50 per 1M tokens = 2_500_000 microdollars per 1M tokens\n */\nconst PRICING: Record<string, Record<string, ModelPricing>> = {\n openai: {\n 'gpt-4o': {\n inputPricePerMToken: 2_500_000,\n outputPricePerMToken: 10_000_000,\n cachedInputPricePerMToken: 1_250_000,\n },\n 'gpt-4o-mini': {\n inputPricePerMToken: 150_000,\n outputPricePerMToken: 600_000,\n cachedInputPricePerMToken: 75_000,\n },\n 'gpt-4.1': {\n inputPricePerMToken: 2_000_000,\n outputPricePerMToken: 8_000_000,\n cachedInputPricePerMToken: 500_000,\n },\n 'gpt-4.1-mini': {\n inputPricePerMToken: 400_000,\n outputPricePerMToken: 1_600_000,\n cachedInputPricePerMToken: 100_000,\n },\n o1: {\n inputPricePerMToken: 15_000_000,\n outputPricePerMToken: 60_000_000,\n reasoningPricePerMToken: 60_000_000,\n cachedInputPricePerMToken: 7_500_000,\n },\n 'o3-mini': {\n inputPricePerMToken: 1_100_000,\n outputPricePerMToken: 4_400_000,\n reasoningPricePerMToken: 4_400_000,\n cachedInputPricePerMToken: 550_000,\n },\n },\n anthropic: {\n 'claude-sonnet-4-20250514': {\n inputPricePerMToken: 3_000_000,\n outputPricePerMToken: 15_000_000,\n cachedInputPricePerMToken: 300_000,\n },\n 'claude-haiku-4-5-20251001': {\n inputPricePerMToken: 800_000,\n outputPricePerMToken: 4_000_000,\n cachedInputPricePerMToken: 80_000,\n },\n 'claude-opus-4-20250514': {\n inputPricePerMToken: 15_000_000,\n outputPricePerMToken: 75_000_000,\n cachedInputPricePerMToken: 1_500_000,\n },\n },\n google: {\n 'gemini-2.5-pro': {\n inputPricePerMToken: 1_250_000,\n outputPricePerMToken: 10_000_000,\n cachedInputPricePerMToken: 315_000,\n },\n 'gemini-2.5-flash': {\n inputPricePerMToken: 150_000,\n outputPricePerMToken: 600_000,\n cachedInputPricePerMToken: 37_500,\n },\n 'gemini-2.0-flash': {\n inputPricePerMToken: 100_000,\n outputPricePerMToken: 400_000,\n cachedInputPricePerMToken: 25_000,\n },\n 'gemini-1.5-pro': {\n inputPricePerMToken: 1_250_000,\n outputPricePerMToken: 5_000_000,\n cachedInputPricePerMToken: 315_000,\n },\n 'gemini-1.5-flash': {\n inputPricePerMToken: 75_000,\n outputPricePerMToken: 300_000,\n cachedInputPricePerMToken: 18_750,\n },\n },\n groq: {\n 'llama-3.3-70b-versatile': {\n inputPricePerMToken: 590_000,\n outputPricePerMToken: 790_000,\n },\n 'llama-3.1-8b-instant': {\n inputPricePerMToken: 50_000,\n outputPricePerMToken: 80_000,\n },\n 'llama-3-70b': {\n inputPricePerMToken: 590_000,\n outputPricePerMToken: 790_000,\n },\n 'mixtral-8x7b': {\n inputPricePerMToken: 240_000,\n outputPricePerMToken: 240_000,\n },\n 'gemma2-9b-it': {\n inputPricePerMToken: 200_000,\n outputPricePerMToken: 200_000,\n },\n },\n mistral: {\n 'mistral-large': {\n inputPricePerMToken: 2_000_000,\n outputPricePerMToken: 6_000_000,\n },\n 'mistral-small': {\n inputPricePerMToken: 200_000,\n outputPricePerMToken: 600_000,\n },\n 'codestral': {\n inputPricePerMToken: 300_000,\n outputPricePerMToken: 900_000,\n },\n 'mistral-embed': {\n inputPricePerMToken: 100_000,\n outputPricePerMToken: 0,\n },\n 'open-mistral-nemo': {\n inputPricePerMToken: 150_000,\n outputPricePerMToken: 150_000,\n },\n },\n};\n\nexport function getModelPricing(\n provider: string,\n model: string,\n): ModelPricing | undefined {\n const providerPricing = PRICING[provider];\n if (!providerPricing) return undefined;\n\n // Exact match first\n if (providerPricing[model]) return providerPricing[model];\n\n // Prefix match: e.g. \"gpt-4o-mini-2024-07-18\" → \"gpt-4o-mini\"\n for (const key of Object.keys(providerPricing)) {\n if (model.startsWith(key)) return providerPricing[key];\n }\n\n return undefined;\n}\n","import type { ContextAnalysis, Message } from './context';\nimport { analyzeContext } from './context';\nimport { calculateCostMicrodollars } from './cost';\nimport { getModelPricing } from './pricing';\n\nexport type GuardMode = 'notify' | 'block' | 'auto-optimize';\nexport type GuardDecision = 'allow' | 'notify' | 'block' | 'optimized';\n\nexport interface GuardsConfig {\n maxInputTokens?: number;\n maxInputTokensHard?: number;\n maxContextUtilization?: number;\n maxContextUtilizationHard?: number;\n maxCostPerCall?: number;\n maxCostPerCallHard?: number;\n maxCostPerHour?: number;\n mode?: GuardMode;\n notifySlackWebhook?: string;\n notifyDashboard?: boolean;\n onOptimize?: (event: OptimizeEvent) => Promise<OptimizeResult>;\n}\n\nexport interface TriggeredRule {\n ruleType: 'input_tokens' | 'cost_per_call' | 'cost_per_hour' | 'context_utilization' | 'budget';\n currentValue: number;\n threshold: number;\n isHard: boolean;\n}\n\nexport interface GuardCheckResult {\n decision: GuardDecision;\n triggeredRules: TriggeredRule[];\n contextAnalysis: ContextAnalysis | null;\n suggestion?: string;\n}\n\nexport interface GuardEvent {\n eventId: string;\n timestamp: string;\n agentName: string;\n guardMode: GuardMode;\n decision: GuardDecision;\n triggeredRules: TriggeredRule[];\n contextAnalysis?: ContextAnalysis;\n optimization?: {\n action: 'retry' | 'notify' | 'block';\n tokensBefore: number;\n tokensAfter?: number;\n costBefore: number;\n costAfter?: number;\n description?: string;\n };\n suggestion?: string;\n}\n\nexport interface OptimizeEvent {\n type: 'context_utilization' | 'cost_per_call' | 'input_tokens';\n suggestion: string;\n metrics: {\n messages?: Message[];\n model?: string;\n currentValue: number;\n threshold: number;\n };\n}\n\nexport interface OptimizeResult {\n action: 'retry' | 'notify' | 'block';\n messages?: Message[];\n model?: string;\n}\n\n/**\n * Error thrown when guard mode is 'block' and a hard limit is exceeded.\n */\nexport class NeuraMeterGuardError extends Error {\n readonly rule: string;\n readonly current: number;\n readonly threshold: number;\n readonly suggestion: string;\n\n constructor(rule: TriggeredRule, suggestion: string) {\n super(`NeuraMeter guard: ${rule.ruleType} exceeded (${rule.currentValue} > ${rule.threshold})`);\n this.name = 'NeuraMeterGuardError';\n this.rule = rule.ruleType;\n this.current = rule.currentValue;\n this.threshold = rule.threshold;\n this.suggestion = suggestion;\n }\n}\n\n/**\n * Check guard rules before an API call.\n * Returns the decision and any triggered rules.\n */\nexport function checkGuards(\n config: GuardsConfig,\n params: {\n messages: Message[];\n model: string;\n provider: string;\n agentName: string;\n },\n hourlyCostDollars?: number,\n): GuardCheckResult {\n const mode = config.mode ?? 'notify';\n const triggeredRules: TriggeredRule[] = [];\n\n // Context analysis\n const contextAnalysis = analyzeContext(params.messages, params.model);\n\n // Check input tokens\n if (config.maxInputTokens && contextAnalysis.estimatedInputTokens > config.maxInputTokens) {\n triggeredRules.push({\n ruleType: 'input_tokens',\n currentValue: contextAnalysis.estimatedInputTokens,\n threshold: config.maxInputTokens,\n isHard: false,\n });\n }\n if (config.maxInputTokensHard && contextAnalysis.estimatedInputTokens > config.maxInputTokensHard) {\n triggeredRules.push({\n ruleType: 'input_tokens',\n currentValue: contextAnalysis.estimatedInputTokens,\n threshold: config.maxInputTokensHard,\n isHard: true,\n });\n }\n\n // Check context utilization\n if (config.maxContextUtilization && contextAnalysis.utilizationPercent > config.maxContextUtilization) {\n triggeredRules.push({\n ruleType: 'context_utilization',\n currentValue: contextAnalysis.utilizationPercent,\n threshold: config.maxContextUtilization,\n isHard: false,\n });\n }\n if (config.maxContextUtilizationHard && contextAnalysis.utilizationPercent > config.maxContextUtilizationHard) {\n triggeredRules.push({\n ruleType: 'context_utilization',\n currentValue: contextAnalysis.utilizationPercent,\n threshold: config.maxContextUtilizationHard,\n isHard: true,\n });\n }\n\n // Check estimated cost per call\n if (config.maxCostPerCall || config.maxCostPerCallHard) {\n const pricing = getModelPricing(params.provider, params.model);\n if (pricing) {\n const estimatedCost = calculateCostMicrodollars(\n { inputTokens: contextAnalysis.estimatedInputTokens, outputTokens: 0 },\n pricing,\n );\n const estimatedDollars = estimatedCost / 1_000_000;\n\n if (config.maxCostPerCall && estimatedDollars > config.maxCostPerCall) {\n triggeredRules.push({\n ruleType: 'cost_per_call',\n currentValue: estimatedDollars,\n threshold: config.maxCostPerCall,\n isHard: false,\n });\n }\n if (config.maxCostPerCallHard && estimatedDollars > config.maxCostPerCallHard) {\n triggeredRules.push({\n ruleType: 'cost_per_call',\n currentValue: estimatedDollars,\n threshold: config.maxCostPerCallHard,\n isHard: true,\n });\n }\n }\n }\n\n // Check cost per hour\n if (config.maxCostPerHour && hourlyCostDollars !== undefined && hourlyCostDollars > config.maxCostPerHour) {\n triggeredRules.push({\n ruleType: 'cost_per_hour',\n currentValue: hourlyCostDollars,\n threshold: config.maxCostPerHour,\n isHard: mode === 'block',\n });\n }\n\n // Generate suggestion\n const suggestion = generateSuggestion(triggeredRules, contextAnalysis);\n\n // Determine decision based on mode\n if (triggeredRules.length === 0) {\n return { decision: 'allow', triggeredRules, contextAnalysis, suggestion };\n }\n\n const hasHardViolation = triggeredRules.some((r) => r.isHard);\n\n switch (mode) {\n case 'notify':\n return { decision: 'notify', triggeredRules, contextAnalysis, suggestion };\n\n case 'block':\n if (hasHardViolation) {\n return { decision: 'block', triggeredRules, contextAnalysis, suggestion };\n }\n return { decision: 'notify', triggeredRules, contextAnalysis, suggestion };\n\n case 'auto-optimize':\n return { decision: 'notify', triggeredRules, contextAnalysis, suggestion };\n\n default:\n return { decision: 'allow', triggeredRules, contextAnalysis, suggestion };\n }\n}\n\nfunction generateSuggestion(rules: TriggeredRule[], ctx: ContextAnalysis): string {\n if (rules.length === 0) return '';\n\n const parts: string[] = [];\n\n for (const rule of rules) {\n switch (rule.ruleType) {\n case 'context_utilization':\n if (ctx.conversationTokens > ctx.systemPromptTokens) {\n const savingPct = Math.round((ctx.conversationTokens / ctx.estimatedInputTokens) * 100);\n parts.push(`Summarize conversation history to save ~${savingPct}% of input tokens`);\n }\n break;\n case 'input_tokens':\n parts.push(`Reduce input tokens from ${ctx.estimatedInputTokens.toLocaleString()} to under ${rule.threshold.toLocaleString()}`);\n break;\n case 'cost_per_call':\n parts.push('Consider using a cheaper model (e.g., gpt-4o-mini or claude-haiku)');\n break;\n case 'cost_per_hour':\n parts.push(`Hourly cost limit exceeded ($${rule.currentValue.toFixed(2)} > $${rule.threshold.toFixed(2)}). Throttle or pause agent calls`);\n break;\n }\n }\n\n return parts.join('. ') || 'Review guard thresholds or optimize context usage';\n}\n","import type { CostEvent, Provider, TraceOptions, TokenUsage } from './types';\nimport { calculateCostMicrodollars } from './cost';\nimport { getModelPricing } from './pricing';\n\nexport class Trace {\n readonly traceId: string;\n private readonly agentName: string;\n private readonly customerId?: string;\n private readonly taskName?: string;\n private readonly tags?: Record<string, string>;\n private readonly recordFn: (event: Omit<CostEvent, 'eventId' | 'timestamp' | 'orgId' | 'projectId' | 'cost'>) => void;\n\n constructor(\n opts: TraceOptions,\n recordFn: (event: Omit<CostEvent, 'eventId' | 'timestamp' | 'orgId' | 'projectId' | 'cost'>) => void,\n ) {\n this.traceId = crypto.randomUUID();\n this.agentName = opts.agentName;\n this.customerId = opts.customerId;\n this.taskName = opts.taskName;\n this.tags = opts.tags;\n this.recordFn = recordFn;\n }\n\n span(opts: {\n provider: Provider;\n model: string;\n usage: TokenUsage;\n latencyMs: number;\n parentSpanId?: string;\n agentName?: string;\n taskName?: string;\n tags?: Record<string, string>;\n }): string {\n const spanId = crypto.randomUUID();\n const pricing = getModelPricing(opts.provider, opts.model);\n const costMicrodollars = pricing\n ? calculateCostMicrodollars(opts.usage, pricing)\n : 0;\n\n this.recordFn({\n traceId: this.traceId,\n spanId,\n parentSpanId: opts.parentSpanId,\n agentName: opts.agentName ?? this.agentName,\n taskName: opts.taskName ?? this.taskName,\n customerId: this.customerId,\n provider: opts.provider,\n model: opts.model,\n inputTokens: opts.usage.inputTokens,\n outputTokens: opts.usage.outputTokens,\n reasoningTokens: opts.usage.reasoningTokens,\n cachedTokens: opts.usage.cachedTokens,\n costMicrodollars,\n latencyMs: opts.latencyMs,\n tags: { ...this.tags, ...opts.tags },\n });\n\n return spanId;\n }\n}\n","/**\n * Slack notification utility for NeuraMeter guard alerts.\n * Sends Block Kit formatted messages via incoming webhooks.\n */\n\nexport interface SlackMessage {\n /** Plain text fallback */\n text: string;\n /** Name of the agent that triggered the guard */\n agentName: string;\n /** Type of guard rule triggered (e.g. 'context_utilization', 'input_tokens') */\n ruleType: string;\n /** Current value that exceeded the threshold */\n currentValue: number;\n /** Configured threshold that was exceeded */\n threshold: number;\n /** Optimization suggestion from the guard system */\n suggestion?: string;\n}\n\n/**\n * Format a value for display based on the rule type.\n */\nfunction formatValue(ruleType: string, value: number): string {\n switch (ruleType) {\n case 'context_utilization':\n return `${value.toFixed(1)}%`;\n case 'cost_per_call':\n case 'cost_per_hour':\n case 'budget':\n return `$${value.toFixed(4)}`;\n case 'input_tokens':\n return value.toLocaleString();\n default:\n return String(value);\n }\n}\n\n/**\n * Format a rule type string for human-readable display.\n */\nfunction formatRuleType(ruleType: string): string {\n return ruleType\n .split('_')\n .map((word) => word.charAt(0).toUpperCase() + word.slice(1))\n .join(' ');\n}\n\n/**\n * Build a Slack Block Kit payload for a guard alert.\n */\nfunction buildSlackPayload(message: SlackMessage): object {\n const blocks: object[] = [\n {\n type: 'header',\n text: {\n type: 'plain_text',\n text: `:warning: NeuraMeter Guard Alert`,\n emoji: true,\n },\n },\n {\n type: 'section',\n fields: [\n {\n type: 'mrkdwn',\n text: `*Agent:*\\n${message.agentName}`,\n },\n {\n type: 'mrkdwn',\n text: `*Rule Triggered:*\\n${formatRuleType(message.ruleType)}`,\n },\n {\n type: 'mrkdwn',\n text: `*Current Value:*\\n${formatValue(message.ruleType, message.currentValue)}`,\n },\n {\n type: 'mrkdwn',\n text: `*Threshold:*\\n${formatValue(message.ruleType, message.threshold)}`,\n },\n ],\n },\n ];\n\n if (message.suggestion) {\n blocks.push({\n type: 'section',\n text: {\n type: 'mrkdwn',\n text: `*Suggestion:*\\n${message.suggestion}`,\n },\n });\n }\n\n blocks.push({\n type: 'context',\n elements: [\n {\n type: 'mrkdwn',\n text: `Sent by NeuraMeter at ${new Date().toISOString()}`,\n },\n ],\n });\n\n return {\n text: message.text,\n blocks,\n };\n}\n\n/**\n * Send a Slack notification via an incoming webhook.\n * Fire-and-forget: errors are silently caught and do not propagate.\n *\n * @param webhookUrl - Slack incoming webhook URL\n * @param message - Structured alert message\n */\nexport async function sendSlackNotification(\n webhookUrl: string,\n message: SlackMessage,\n): Promise<void> {\n try {\n const payload = buildSlackPayload(message);\n await fetch(webhookUrl, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n });\n } catch {\n // Fire-and-forget: silently ignore errors\n }\n}\n","import type { CostEvent, NeuraMeterConfig, TraceOptions } from './types';\nimport type { GuardsConfig, GuardCheckResult, GuardEvent, OptimizeEvent, OptimizeResult } from './guards';\nimport { checkGuards, NeuraMeterGuardError } from './guards';\nimport type { Message } from './context';\nimport { Trace } from './trace';\nimport { calculateCostMicrodollars } from './cost';\nimport { getModelPricing } from './pricing';\nimport { sendSlackNotification } from './slack';\n\nconst DEFAULT_BATCH_SIZE = 50;\nconst DEFAULT_FLUSH_INTERVAL_MS = 5_000;\n\n/** Tracks cost accumulated within a rolling 1-hour window per agent. */\ninterface HourlyCostEntry {\n costMicrodollars: number;\n timestamp: number;\n}\n\nexport class NeuraMeter {\n private readonly apiKey: string;\n private readonly projectId: string;\n private readonly endpoint: string;\n private readonly batchSize: number;\n private readonly flushIntervalMs: number;\n readonly guards: GuardsConfig | undefined;\n\n private buffer: CostEvent[] = [];\n private guardBuffer: GuardEvent[] = [];\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private timer: any = null;\n private flushing = false;\n\n /** Rolling hourly cost tracking per agent for maxCostPerHour guard */\n private hourlyCosts: Map<string, HourlyCostEntry[]> = new Map();\n\n /** Extracted from API key format: nm_{orgId}_{secret} */\n private readonly orgId: string;\n\n constructor(config: NeuraMeterConfig) {\n this.apiKey = config.apiKey;\n this.projectId = config.projectId;\n this.endpoint = config.endpoint ?? 'https://neurameter-ingestion.neurameter.workers.dev';\n this.batchSize = config.batchSize ?? DEFAULT_BATCH_SIZE;\n this.flushIntervalMs = config.flushIntervalMs ?? DEFAULT_FLUSH_INTERVAL_MS;\n this.guards = config.guards;\n\n // Extract orgId from API key (format: nm_{orgId}_{secret})\n const parts = this.apiKey.split('_');\n this.orgId = parts.length >= 3 ? parts[1]! : 'unknown';\n\n this.startAutoFlush();\n }\n\n startTrace(opts: TraceOptions): Trace {\n return new Trace(opts, (event) => this.record(event));\n }\n\n /**\n * Get rolling hourly cost for an agent (in dollars).\n */\n getHourlyCostDollars(agentName: string): number {\n const oneHourAgo = Date.now() - 3_600_000;\n const entries = this.hourlyCosts.get(agentName) ?? [];\n // Prune old entries\n const recent = entries.filter((e) => e.timestamp > oneHourAgo);\n this.hourlyCosts.set(agentName, recent);\n const totalMicro = recent.reduce((s, e) => s + e.costMicrodollars, 0);\n return totalMicro / 1_000_000;\n }\n\n /**\n * Track cost for hourly rate limiting.\n */\n private trackHourlyCost(agentName: string, costMicrodollars: number): void {\n const entries = this.hourlyCosts.get(agentName) ?? [];\n entries.push({ costMicrodollars, timestamp: Date.now() });\n this.hourlyCosts.set(agentName, entries);\n }\n\n /**\n * Check guard rules before an API call.\n * Returns the check result. In block mode, may throw NeuraMeterGuardError.\n */\n checkGuards(params: {\n messages: Message[];\n model: string;\n provider: string;\n agentName: string;\n }): GuardCheckResult | null {\n if (!this.guards) return null;\n\n const hourlyCostDollars = this.getHourlyCostDollars(params.agentName);\n const result = checkGuards(this.guards, params, hourlyCostDollars);\n\n // Record guard event (async, fire-and-forget)\n if (result.triggeredRules.length > 0) {\n this.recordGuardEvent({\n eventId: crypto.randomUUID(),\n timestamp: new Date().toISOString(),\n agentName: params.agentName,\n guardMode: this.guards.mode ?? 'notify',\n decision: result.decision,\n triggeredRules: result.triggeredRules,\n contextAnalysis: result.contextAnalysis ?? undefined,\n suggestion: result.suggestion,\n });\n\n // Send Slack notification if configured (async, fire-and-forget)\n if (this.guards.notifySlackWebhook) {\n for (const rule of result.triggeredRules) {\n void sendSlackNotification(this.guards.notifySlackWebhook, {\n text: `NeuraMeter guard triggered: ${rule.ruleType} for agent \"${params.agentName}\" (${rule.currentValue} > ${rule.threshold})`,\n agentName: params.agentName,\n ruleType: rule.ruleType,\n currentValue: rule.currentValue,\n threshold: rule.threshold,\n suggestion: result.suggestion,\n });\n }\n }\n }\n\n // In block mode with hard violation, throw\n if (result.decision === 'block') {\n const hardRule = result.triggeredRules.find((r) => r.isHard);\n if (hardRule) {\n throw new NeuraMeterGuardError(hardRule, result.suggestion ?? '');\n }\n }\n\n return result;\n }\n\n /**\n * Run auto-optimize flow: calls the onOptimize callback and returns the result.\n * Used by SDK wrappers when mode is 'auto-optimize' and thresholds are exceeded.\n */\n async runAutoOptimize(params: {\n guardResult: GuardCheckResult;\n messages: Message[];\n model: string;\n agentName: string;\n }): Promise<OptimizeResult | null> {\n if (!this.guards?.onOptimize || params.guardResult.triggeredRules.length === 0) {\n return null;\n }\n\n const primaryRule = params.guardResult.triggeredRules[0]!;\n const optimizeEvent: OptimizeEvent = {\n type: primaryRule.ruleType as OptimizeEvent['type'],\n suggestion: params.guardResult.suggestion ?? '',\n metrics: {\n messages: params.messages,\n model: params.model,\n currentValue: primaryRule.currentValue,\n threshold: primaryRule.threshold,\n },\n };\n\n try {\n const result = await this.guards.onOptimize(optimizeEvent);\n\n // Record optimization in guard event\n const pricing = getModelPricing(\n 'openai', // Best effort — wrappers will provide actual provider\n result.model ?? params.model,\n );\n const tokensBefore = params.guardResult.contextAnalysis?.estimatedInputTokens ?? 0;\n const costBefore = pricing\n ? calculateCostMicrodollars({ inputTokens: tokensBefore, outputTokens: 0 }, pricing) / 1_000_000\n : 0;\n\n this.recordGuardEvent({\n eventId: crypto.randomUUID(),\n timestamp: new Date().toISOString(),\n agentName: params.agentName,\n guardMode: 'auto-optimize',\n decision: result.action === 'retry' ? 'optimized' : result.action === 'block' ? 'block' : 'notify',\n triggeredRules: params.guardResult.triggeredRules,\n contextAnalysis: params.guardResult.contextAnalysis ?? undefined,\n optimization: {\n action: result.action,\n tokensBefore,\n costBefore,\n description: params.guardResult.suggestion,\n },\n suggestion: params.guardResult.suggestion,\n });\n\n return result;\n } catch {\n // If onOptimize fails, fall through to notify\n return { action: 'notify' };\n }\n }\n\n record(event: Omit<CostEvent, 'eventId' | 'timestamp' | 'orgId' | 'projectId' | 'cost'>): void {\n const fullEvent: CostEvent = {\n ...event,\n eventId: crypto.randomUUID(),\n timestamp: new Date().toISOString(),\n orgId: this.orgId,\n projectId: this.projectId,\n cost: event.costMicrodollars / 1_000_000,\n };\n\n this.buffer.push(fullEvent);\n\n // Track hourly cost for rate limiting\n if (event.agentName && event.costMicrodollars > 0) {\n this.trackHourlyCost(event.agentName, event.costMicrodollars);\n }\n\n if (this.buffer.length >= this.batchSize) {\n void this.flush();\n }\n }\n\n private recordGuardEvent(event: GuardEvent): void {\n this.guardBuffer.push(event);\n // Flush guard events alongside regular events\n }\n\n async flush(): Promise<void> {\n if ((this.buffer.length === 0 && this.guardBuffer.length === 0) || this.flushing) return;\n\n this.flushing = true;\n\n // Flush cost events\n if (this.buffer.length > 0) {\n const batch = this.buffer.splice(0, this.batchSize);\n try {\n const response = await fetch(`${this.endpoint}/v1/events`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.apiKey}`,\n },\n body: JSON.stringify({ batch }),\n });\n if (!response.ok) {\n this.buffer.unshift(...batch);\n }\n } catch {\n this.buffer.unshift(...batch);\n }\n }\n\n // Flush guard events\n if (this.guardBuffer.length > 0) {\n const guardBatch = this.guardBuffer.splice(0, this.batchSize);\n try {\n await fetch(`${this.endpoint}/v1/guard-events`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n Authorization: `Bearer ${this.apiKey}`,\n },\n body: JSON.stringify({ batch: guardBatch }),\n });\n } catch {\n // Fire-and-forget for guard events\n }\n }\n\n this.flushing = false;\n }\n\n async destroy(): Promise<void> {\n if (this.timer) {\n clearInterval(this.timer);\n this.timer = null;\n }\n await this.flush();\n }\n\n private startAutoFlush(): void {\n this.timer = setInterval(() => {\n void this.flush();\n }, this.flushIntervalMs);\n\n if (this.timer && typeof this.timer === 'object' && 'unref' in this.timer) {\n (this.timer as { unref: () => void }).unref();\n }\n }\n}\n","export async function calculateSaving(\n supabase: any,\n orgId: string,\n agentName: string,\n actualCost: number,\n costBefore?: number\n): Promise<{\n baselineCost: number;\n saving: number;\n commission: number;\n method: 'A' | 'B';\n}> {\n // B方式: 過去7日間の同エージェント平均コストを取得\n const sevenDaysAgo = new Date();\n sevenDaysAgo.setDate(sevenDaysAgo.getDate() - 7);\n\n const { data } = await supabase\n .from('cost_events')\n .select('cost_microdollars')\n .eq('org_id', orgId)\n .eq('agent_name', agentName)\n .gte('event_timestamp', sevenDaysAgo.toISOString());\n\n if (data && data.length >= 5) {\n const avgCost =\n data.reduce(\n (sum: number, e: any) => sum + e.cost_microdollars / 1_000_000,\n 0\n ) / data.length;\n const saving = Math.max(0, avgCost - actualCost);\n return {\n baselineCost: avgCost,\n saving,\n commission: saving * 0.1,\n method: 'B',\n };\n }\n\n // A方式: データ不足の場合はcostBeforeで代用\n if (costBefore !== undefined && costBefore > actualCost) {\n const saving = costBefore - actualCost;\n return {\n baselineCost: costBefore,\n saving,\n commission: saving * 0.1,\n method: 'A',\n };\n }\n\n return { baselineCost: 0, saving: 0, commission: 0, method: 'A' };\n}\n","// ---------------------------------------------------------------------------\n// @neurameter/core – OpenAI client wrapper\n// ---------------------------------------------------------------------------\n// Wraps an OpenAI client instance so that every chat.completions.create()\n// call is automatically tracked in NeuraMeter — no proxy required.\n//\n// import OpenAI from 'openai';\n// import { withNeuraMeter } from '@neurameter/core';\n//\n// const openai = withNeuraMeter(new OpenAI(), {\n// apiKey: 'nm_xxx',\n// projectId: 'proj_xxx',\n// });\n// ---------------------------------------------------------------------------\n\nimport type { WithNeuraMeterConfig, TokenUsage } from './types';\nimport { NeuraMeter } from './meter';\nimport { getModelPricing } from './pricing';\nimport { calculateCostMicrodollars } from './cost';\n\n// ---------------------------------------------------------------------------\n// Minimal OpenAI-compatible types (avoids importing the openai package)\n// ---------------------------------------------------------------------------\n\n/** Subset of OpenAI usage response fields we need. */\ninterface OpenAIUsage {\n prompt_tokens?: number;\n completion_tokens?: number;\n prompt_tokens_details?: { cached_tokens?: number };\n completion_tokens_details?: { reasoning_tokens?: number };\n}\n\n/** Subset of a non-streaming chat completion response. */\ninterface ChatCompletion {\n usage?: OpenAIUsage;\n model?: string;\n [key: string]: unknown;\n}\n\n/** A single streamed chunk. */\ninterface ChatCompletionChunk {\n usage?: OpenAIUsage | null;\n model?: string;\n [key: string]: unknown;\n}\n\n/** Params passed to chat.completions.create(). */\ninterface CreateParams {\n model: string;\n stream?: boolean;\n stream_options?: { include_usage?: boolean };\n [key: string]: unknown;\n}\n\n// ---------------------------------------------------------------------------\n// Usage extraction helper\n// ---------------------------------------------------------------------------\n\nfunction extractUsage(usage: OpenAIUsage): TokenUsage {\n return {\n inputTokens: usage.prompt_tokens ?? 0,\n outputTokens: usage.completion_tokens ?? 0,\n reasoningTokens: usage.completion_tokens_details?.reasoning_tokens ?? 0,\n cachedTokens: usage.prompt_tokens_details?.cached_tokens ?? 0,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Stream wrapper\n// ---------------------------------------------------------------------------\n\n/**\n * Wraps an async-iterable stream, yielding all chunks transparently while\n * capturing the usage data from the final chunk.\n */\nfunction wrapStream(\n stream: AsyncIterable<ChatCompletionChunk> & Record<string, unknown>,\n onDone: (usage: TokenUsage, model: string) => void,\n requestModel: string,\n): typeof stream {\n const originalIterator = stream[Symbol.asyncIterator].bind(stream);\n\n // Create a proxy so all other properties/methods (e.g. toReadableStream(),\n // controller, response) still work.\n return new Proxy(stream, {\n get(target, prop, receiver) {\n if (prop === Symbol.asyncIterator) {\n return function () {\n const iter = originalIterator();\n let capturedUsage: TokenUsage | null = null;\n let capturedModel = requestModel;\n\n return {\n async next() {\n const result = await iter.next();\n if (!result.done) {\n const chunk = result.value as ChatCompletionChunk;\n if (chunk.model) capturedModel = chunk.model;\n if (chunk.usage) {\n capturedUsage = extractUsage(chunk.usage);\n }\n } else {\n // Stream finished — record the event\n if (capturedUsage) {\n onDone(capturedUsage, capturedModel);\n }\n }\n return result;\n },\n async return(value?: unknown) {\n if (capturedUsage) onDone(capturedUsage, capturedModel);\n return iter.return ? iter.return(value) : { done: true as const, value: undefined };\n },\n async throw(err?: unknown) {\n return iter.throw ? iter.throw(err) : Promise.reject(err);\n },\n };\n };\n }\n return Reflect.get(target, prop, receiver);\n },\n });\n}\n\n// ---------------------------------------------------------------------------\n// withNeuraMeter\n// ---------------------------------------------------------------------------\n\n/**\n * Wraps an OpenAI client so that every `chat.completions.create()` call is\n * automatically tracked in NeuraMeter.\n *\n * @param client An OpenAI client instance (from the `openai` npm package)\n * @param config NeuraMeter configuration\n * @returns The same client with cost tracking enabled\n */\nexport function withNeuraMeter<\n T extends { chat: { completions: { create: (...args: unknown[]) => unknown } } },\n>(client: T, config: WithNeuraMeterConfig): T {\n const meter = new NeuraMeter({\n apiKey: config.apiKey,\n projectId: config.projectId,\n endpoint: config.endpoint ?? 'https://meter.neuria.tech',\n });\n\n const agentName = config.agentName ?? 'default';\n\n // Save the original create method\n const originalCreate = client.chat.completions.create.bind(\n client.chat.completions,\n ) as (params: CreateParams) => Promise<ChatCompletion | AsyncIterable<ChatCompletionChunk>>;\n\n // Helper to record a cost event\n function recordEvent(usage: TokenUsage, model: string, latencyMs: number): void {\n const pricing = getModelPricing('openai', model);\n const costMicrodollars = pricing\n ? calculateCostMicrodollars(usage, pricing)\n : 0;\n\n meter.record({\n traceId: crypto.randomUUID(),\n spanId: crypto.randomUUID(),\n agentName,\n provider: 'openai',\n model,\n inputTokens: usage.inputTokens,\n outputTokens: usage.outputTokens,\n reasoningTokens: usage.reasoningTokens ?? 0,\n cachedTokens: usage.cachedTokens ?? 0,\n costMicrodollars,\n latencyMs,\n });\n }\n\n // Override create\n (client.chat.completions as Record<string, unknown>).create = async (\n params: CreateParams,\n ): Promise<unknown> => {\n const startTime = Date.now();\n const model = params.model;\n const isStream = params.stream === true;\n\n // Auto-inject stream_options for usage reporting\n if (isStream && !params.stream_options) {\n params = { ...params, stream_options: { include_usage: true } };\n }\n\n const result = await originalCreate(params);\n\n if (isStream && result && typeof result === 'object' && Symbol.asyncIterator in result) {\n // Streaming — wrap the async iterable\n return wrapStream(\n result as AsyncIterable<ChatCompletionChunk> & Record<string, unknown>,\n (usage, resolvedModel) => {\n const latencyMs = Date.now() - startTime;\n recordEvent(usage, resolvedModel, latencyMs);\n },\n model,\n );\n }\n\n // Non-streaming — extract usage immediately\n const latencyMs = Date.now() - startTime;\n const response = result as ChatCompletion;\n if (response.usage) {\n const usage = extractUsage(response.usage);\n recordEvent(usage, response.model ?? model, latencyMs);\n }\n\n return result;\n };\n\n // Attach destroy method for cleanup\n (client as Record<string, unknown>).__neurameter = meter;\n (client as Record<string, unknown>).__neurameter_destroy = () => meter.destroy();\n\n return client;\n}\n"]}
|