@robota-sdk/agent-session-analytics 3.0.0-beta.86 → 3.0.0-beta.88
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +28 -1
- package/README.md +3 -3
- package/dist/node/index.cjs +1 -1
- package/dist/node/index.d.cts +5 -5
- package/dist/node/index.d.cts.map +1 -1
- package/dist/node/index.d.ts +5 -5
- package/dist/node/index.d.ts.map +1 -1
- package/dist/node/index.js +1 -1
- package/dist/node/index.js.map +1 -1
- package/package.json +12 -13
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
# @robota-sdk/agent-session-analytics
|
|
2
2
|
|
|
3
|
+
## 3.0.0-beta.88
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- @robota-sdk/agent-core@3.0.0-beta.88
|
|
8
|
+
- @robota-sdk/agent-interface-analytics@3.0.0-beta.88
|
|
9
|
+
- @robota-sdk/agent-interface-session@3.0.0-beta.88
|
|
10
|
+
|
|
11
|
+
## 3.0.0-beta.87
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- Release the migrated Robota product with its public SDK namespace, robota command, compatible SDK exports, internal product configuration, and verified CLI startup and delivery corrections.
|
|
16
|
+
- Updated dependencies
|
|
17
|
+
- Updated dependencies [66af868]
|
|
18
|
+
- Updated dependencies [7d9cc66]
|
|
19
|
+
- Updated dependencies [7d9cc66]
|
|
20
|
+
- Updated dependencies [7d9cc66]
|
|
21
|
+
- Updated dependencies [7d9cc66]
|
|
22
|
+
- Updated dependencies [7d9cc66]
|
|
23
|
+
- Updated dependencies [7d9cc66]
|
|
24
|
+
- Updated dependencies [7d9cc66]
|
|
25
|
+
- Updated dependencies [7d9cc66]
|
|
26
|
+
- @robota-sdk/agent-core@3.0.0-beta.87
|
|
27
|
+
- @robota-sdk/agent-interface-analytics@3.0.0-beta.87
|
|
28
|
+
- @robota-sdk/agent-interface-session@3.0.0-beta.87
|
|
29
|
+
|
|
3
30
|
## 3.0.0-beta.86
|
|
4
31
|
|
|
5
32
|
### Patch Changes
|
|
@@ -155,7 +182,7 @@
|
|
|
155
182
|
with an advisor. Sending history to a destination (provider type and endpoint host) the main model
|
|
156
183
|
does not already use needs a one-time consent per destination, kept in the user settings file; a
|
|
157
184
|
refusal is remembered for the session. The organization's `allowedProviders` applies, and
|
|
158
|
-
`
|
|
185
|
+
`PRODUCT_DISABLE_ADVISOR=1` turns it off completely. In-process subagents inherit the advisor, bound
|
|
159
186
|
to their own conversation; child-process subagents do not get it.
|
|
160
187
|
|
|
161
188
|
**`@robota-sdk/agent-framework` is `major` for one reason: `ICommandHostSessionAccess` gains a
|
package/README.md
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
# @robota-sdk/agent-session-analytics
|
|
2
2
|
|
|
3
|
-
Timing and usage analysis over persisted
|
|
3
|
+
Timing and usage analysis over persisted agent session records.
|
|
4
4
|
|
|
5
5
|
Given session records, it computes per-turn timing intervals (LLM wait vs. tool execution), attributes
|
|
6
6
|
token usage and cost to the source that spent it (main thread, subagents, background tasks, tools,
|
|
7
7
|
commands, skills), aggregates cross-session personal usage into
|
|
8
8
|
complete local-calendar days, projects usage into OpenTelemetry (OTLP) payloads, and renders text
|
|
9
9
|
reports. Everything is a pure function: no file I/O, no `process.*`, no network. Callers load the
|
|
10
|
-
records and write or send the output;
|
|
10
|
+
records and write or send the output; a host CLI's `usage` command is one such caller.
|
|
11
11
|
|
|
12
12
|
## Installation
|
|
13
13
|
|
|
@@ -57,7 +57,7 @@ process.stdout.write(formatUsageReport(summarizeUsageBySource(record)) + '\n');
|
|
|
57
57
|
### OTLP export
|
|
58
58
|
|
|
59
59
|
These build OTLP/JSON payloads from session records; sending them to a collector is the caller's job
|
|
60
|
-
(`
|
|
60
|
+
(a host CLI's `usage export` command does it). The payloads are content-free: no prompt or reply text, no session
|
|
61
61
|
identity.
|
|
62
62
|
|
|
63
63
|
| Export | Description |
|
package/dist/node/index.cjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require("@robota-sdk/agent-core");function t(e,t){return new Date(t).getTime()-new Date(e).getTime()}function n(e){return new Date(e).toISOString()}function r(e,r,i,a,o,s){return{kind:e,fromType:r,toType:i,fromTimestamp:n(a),toTimestamp:n(o),durationMs:t(a,o),turnIndex:s}}function i(e){let t=[],n=0,i=0;for(;i<e.length;){let a=e[i];if(!a){i++;continue}if(a.category===`chat`&&a.type===`user`){n++;let o=a.timestamp,s=!1,c=null,l=i+1;for(;l<e.length;){let i=e[l];if(!i){l++;continue}if(i.category===`chat`&&i.type===`user`)break;if(i.category===`event`&&i.type===`tool-start`){s?c!==null&&t.push(r(`llm_between_tools`,`tool-end`,`tool-start`,c,i.timestamp,n)):(t.push(r(`user_to_first_tool`,`user`,`tool-start`,o,i.timestamp,n)),s=!0),c=null,l++;continue}if(i.category===`event`&&i.type===`tool-end`){let a=e[l-1];a&&a.category===`event`&&a.type===`tool-start`&&t.push(r(`tool_exec`,`tool-start`,`tool-end`,a.timestamp,i.timestamp,n)),c=i.timestamp,l++;continue}if(i.category===`event`&&i.type===`tool-summary`){c!==null&&t.push(r(`llm_final_response`,`tool-end`,`tool-summary`,c,i.timestamp,n)),l++;continue}if(i.category===`chat`&&i.type===`assistant`){s?c!==null&&t.push(r(`llm_final_response`,`tool-end`,`assistant`,c,i.timestamp,n)):t.push(r(`user_to_assistant`,`user`,`assistant`,o,i.timestamp,n)),l++;break}l++}i=l}else i++}return t}function a(e){let t=e.filter(e=>e.kind===`user_to_first_tool`||e.kind===`user_to_assistant`||e.kind===`llm_between_tools`||e.kind===`llm_final_response`),n=e.filter(e=>e.kind===`tool_exec`),r=e.filter(e=>e.kind===`user_to_assistant`),i=e=>e.length?Math.round(e.reduce((e,t)=>e+t.durationMs,0)/e.length):0,a=e=>e.length?Math.max(...e.map(e=>e.durationMs)):0;return{llmWaitMs:{avg:i(t),max:a(t),total:t.reduce((e,t)=>e+t.durationMs,0),count:t.length},toolExecMs:{avg:i(n),max:a(n),median:(e=>{if(!e.length)return 0;let t=[...e].sort((e,t)=>e.durationMs-t.durationMs),n=Math.floor(t.length/2);return t.length%2==0?Math.round(((t[n-1]?.durationMs??0)+(t[n]?.durationMs??0))/2):t[n]?.durationMs??0})(n),count:n.length},userToAssistantMs:{avg:i(r),max:a(r),count:r.length}}}function o(e){let t=i(e.history??[]),n=t.filter(e=>e.durationMs>=1e4);return{sessionId:e.id,cwd:e.cwd,createdAt:e.createdAt,totalIntervals:t.length,intervals:t,slowIntervals:n,stats:a(t)}}function s(e){let t=e.flatMap(e=>e.intervals.filter(e=>e.kind===`user_to_first_tool`||e.kind===`user_to_assistant`||e.kind===`llm_between_tools`||e.kind===`llm_final_response`)),n=e.flatMap(e=>e.intervals.filter(e=>e.kind===`tool_exec`)),r=t.length?Math.round(t.reduce((e,t)=>e+t.durationMs,0)/t.length):0,i=n.length?Math.round(n.reduce((e,t)=>e+t.durationMs,0)/n.length):0,a=0,o=``,s=0,c=``;for(let t of e)for(let e of t.intervals)e.durationMs>a&&(a=e.durationMs,o=t.sessionId,s=e.turnIndex,c=e.kind);let l=e.map(e=>e.createdAt).sort();return{sessionCount:e.length,fromDate:l[0]??``,toDate:l[l.length-1]??``,avgLlmResponseMs:r,avgToolExecMs:i,maxSingleDelayMs:a,maxSingleDelaySession:o,maxSingleDelayTurn:s,maxSingleDelayKind:c}}function c(e){return e>=1e6?`${(e/1e6).toFixed(1)}M`:e>=1e3?`${(e/1e3).toFixed(1)}K`:`${e}`}function l(e,t){return`${t?``:`~`}$${e.toFixed(4)}`}function u(e){let t=[];if(t.push(`Token usage — session ${e.sessionId}`),t.push(` total ${c(e.totalTokens)} (prompt ${c(e.promptTokens)} · completion ${c(e.completionTokens)})`),t.push(` cost ${l(e.costUsd,e.costExact)}`),e.bySource.length===0)t.push(` (no usage recorded)`);else{t.push(` by source (most tokens first):`);for(let n of e.bySource)t.push(` ${n.label.padEnd(24)} ${String(n.percentage).padStart(5)}% ${c(n.totalTokens).padStart(7)} ${l(n.costUsd,n.costExact).padStart(10)} (${n.turns} turn${n.turns===1?``:`s`})`);e.topConsumer&&t.push(` top consumer: ${e.topConsumer.label} (${e.topConsumer.percentage}%)`)}if(e.timeline.length>0){t.push(` trace (per turn, sub-turn spans):`);for(let n of e.timeline){t.push(` turn ${n.turnIndex} — ${n.label} · ${d(n.totalDurationMs)} across ${n.spans.length} op${n.spans.length===1?``:`s`}`);for(let e of n.spans)t.push(` ${e.op.padEnd(22)} ${d(e.durationMs).padStart(8)}`)}}return t.join(`
|
|
2
2
|
`)}function d(e){return e>=1e3?`${(e/1e3).toFixed(1)}s`:`${e}ms`}function f(e){return new Date(e).toLocaleString(`sv-SE`,{timeZoneName:`short`}).slice(0,16)}function p(e){return{user_to_first_tool:`user → tool-start`,user_to_assistant:`user → assistant`,tool_exec:`tool-start → tool-end`,llm_between_tools:`tool-end → tool-start`,llm_final_response:`tool-end → assistant/summary`}[e.kind]??e.kind}function m(e){let{stats:t}=e,n=t.llmWaitMs.total+t.toolExecMs.avg*t.toolExecMs.count;if(n===0)return`Verdict: No timing data available.`;let r=Math.round(t.llmWaitMs.total/n*100);return`Verdict: LLM API wait ${r}% | Code processing ${100-r}%`}function h(e){let t=[],{stats:n}=e;if(t.push(`Session: ${e.sessionId}`),t.push(`Created: ${f(e.createdAt)} | cwd: ${e.cwd}`),t.push(``),t.push(`Timing Summary:`),n.llmWaitMs.count>0&&t.push(` LLM API wait ${d(n.llmWaitMs.avg).padStart(8)} avg | ${d(n.llmWaitMs.max).padStart(8)} max`),n.toolExecMs.count>0&&t.push(` Tool execution ${d(n.toolExecMs.avg).padStart(8)} avg | ${d(n.toolExecMs.median).padStart(8)} median`),n.userToAssistantMs.count>0&&t.push(` user → assistant ${d(n.userToAssistantMs.avg).padStart(8)} avg`),n.llmWaitMs.count===0&&n.toolExecMs.count===0&&t.push(` (no intervals computed — session may have no history)`),e.slowIntervals.length>0){t.push(``),t.push(`Slow intervals (>10s):`);for(let n of e.slowIntervals)t.push(` turn ${n.turnIndex} ${p(n).padEnd(32)} ${d(n.durationMs).padStart(8)}`)}return t.push(``),t.push(m(e)),t.join(`
|
|
3
3
|
`)}function g(e){let t=[];return t.push(`Analyzed ${e.sessionCount} sessions (${f(e.fromDate)} ~ ${f(e.toDate)})`),t.push(` Avg LLM response: ${d(e.avgLlmResponseMs)}`),t.push(` Avg tool exec: ${d(e.avgToolExecMs)}`),e.maxSingleDelayMs>0&&t.push(` Max single delay: ${d(e.maxSingleDelayMs)} (${e.maxSingleDelaySession}, turn ${e.maxSingleDelayTurn}, ${e.maxSingleDelayKind})`),t.join(`
|
|
4
|
-
`)}const _={scope:`main`,label:`main thread`};function v(e){return`${e.scope}:${e.id??``}`}function y(e){return e.label??(e.id?`${e.scope} ${e.id}`:e.scope)}function ee(e){return e.type===`usage-summary`&&typeof e.data==`object`&&e.data!==null}function te(e){if(e.type!==`span`||typeof e.data!=`object`||e.data===null)return!1;let t=e.data;return typeof t.spanId==`string`&&typeof t.op==`string`&&typeof t.durationMs==`number`}function b(e,t){return t<=0?0:Math.round(e/t*1e3)/10}function x(e){let t=new Map,n=0,r=0,i=0,a=0,o=!0,s=[],c=[],l=e=>{c.length!==0&&(s.push({turnIndex:s.length,source:e,label:y(e),spans:c,totalDurationMs:c.reduce((e,t)=>e+t.durationMs,0)}),c=[])};for(let s of e.history??[]){if(te(s)){let e=s.data;c.push({spanId:e.spanId,op:e.op,durationMs:e.durationMs});continue}if(!ee(s))continue;let e=s.data,u=e.source??_,d=v(u),f=e.promptTokens??0,p=e.completionTokens??0,m=e.totalTokens,h=e.costUsd??0;n+=f,r+=p,i+=m,a+=h,o=!1;let g=t.get(d);g?(g.promptTokens+=f,g.completionTokens+=p,g.totalTokens+=m,g.turns+=1,g.costUsd+=h,g.costExact=!1):t.set(d,{key:d,source:u,label:y(u),promptTokens:f,completionTokens:p,totalTokens:m,turns:1,percentage:0,costUsd:h,costExact:!1}),l(u)}l(_);let u=[...t.values()].map(e=>({...e,percentage:b(e.totalTokens,i)})).sort((e,t)=>t.totalTokens-e.totalTokens);return{sessionId:e.id,totalTokens:i,promptTokens:n,completionTokens:r,costUsd:a,costExact:o,bySource:u,...u[0]?{topConsumer:u[0]}:{},timeline:s}}function S(e){return typeof e==`object`&&!!e&&!Array.isArray(e)&&!(e instanceof Date)}function C(e){return typeof e==`string`&&e.length>0?e:void 0}function w(e){return typeof e==`number`&&Number.isFinite(e)&&e>=0}function T(e){return e===`unknown`||e===`estimated`||e===`exact`}function ne(e){return(e.promptTokens===void 0||w(e.promptTokens))&&(e.completionTokens===void 0||w(e.completionTokens))}function re(e){let t=e.costStatus;return T(t)?t===`unknown`?e.costUsd===void 0:w(e.costUsd):!1}function ie(e){return w(e.totalTokens)&&w(e.contextUsedTokens)&&w(e.contextMaxTokens)&&w(e.contextUsedPercentage)}function ae(e){return e===`cli`||e===`desktop-app`||e===`browser`||e===`remote`||e===`attach`||e===`unknown`}function E(e){if(!S(e))return;let t=e.scope;if(t!==`main`&&t!==`subagent`&&t!==`background`&&t!==`tool`&&t!==`command`&&t!==`skill`)return;let n=C(e.id),r=C(e.label);return{scope:t,...n?{id:n}:{},...r?{label:r}:{}}}function D(e){if(!S(e)||e.kind!==`exact`&&e.kind!==`estimated`||e.scope!==`turn`||!ne(e)||!re(e)||!ie(e)||!T(e.costStatus))return;let t=E(e.source);return{kind:e.kind,scope:`turn`,totalTokens:e.totalTokens,contextUsedTokens:e.contextUsedTokens,contextMaxTokens:e.contextMaxTokens,contextUsedPercentage:e.contextUsedPercentage,costStatus:e.costStatus===`exact`?`estimated`:e.costStatus,...w(e.promptTokens)?{promptTokens:e.promptTokens}:{},...w(e.completionTokens)?{completionTokens:e.completionTokens}:{},...w(e.costUsd)?{costUsd:e.costUsd}:{},...t?{source:t}:{}}}function O(e){if(!S(e))return;let t=C(e.providerId),n=C(e.modelId),{promptTokens:r,completionTokens:i,totalTokens:a,costStatus:o,costUsd:s}=e;if(!(!t||!n||!w(r)||!w(i)||!w(a)||o!==`unknown`&&o!==`estimated`||(o===`estimated`?!w(s):s!==void 0)))return{providerId:t,modelId:n,promptTokens:r,completionTokens:i,totalTokens:a,costStatus:o,...o===`estimated`&&w(s)?{costUsd:s}:{}}}function k(e){if(!Array.isArray(e)||e.length===0)return;let t=e.map(O);return t.every(e=>e!==void 0)?t:void 0}function A(e){if(!S(e))return;let t=C(e.usageObservationId),n=C(e.turnId),r=e.outcome;if(!t||!n||r!==`success`&&r!==`failure`&&r!==`interrupted`)return;let i=e.surface,a=E(e.source),o=D(e.usage),s=k(e.modelShares);return{usageObservationId:t,turnId:n,outcome:r,...C(e.modelId)?{modelId:C(e.modelId)}:{},...C(e.providerId)?{providerId:C(e.providerId)}:{},...s?{modelShares:s}:{},...ae(i)?{surface:i}:{},...a?{source:a}:{},...o?{usage:o}:{}}}function j(e){let t=new Date(e.timestamp);return Number.isNaN(t.getTime())?void 0:t}function M(e){let t=[],n=e.history??[],r=new Set,i=n.flatMap((e,t)=>{if(e.type!==`usage-summary`)return[];let n=D(e.data);return n?[{id:e.id,index:t,usage:n}]:[]});for(let[e,t]of n.entries()){if(t.type!==`usage-observation`)continue;let n=A(t.data);if(!n?.usage)continue;let a=JSON.stringify(n.usage),o=i.map((e,t)=>({candidate:e,index:t})).filter(({candidate:e})=>JSON.stringify(e.usage)===a).sort((t,n)=>Math.abs(t.candidate.index-e)-Math.abs(n.candidate.index-e))[0];o&&(r.add(o.candidate.id),i.splice(o.index,1))}for(let i of n){let n=j(i);if(!n)continue;let a=i.type===`usage-observation`?A(i.data):void 0;if(a){t.push({id:a.usageObservationId,sessionId:e.id,at:n,legacy:!1,observation:a});continue}if(i.type!==`usage-summary`||r.has(i.id))continue;let o=D(i.data);if(!o)continue;let s=`legacy:${e.id}:${i.id}`;t.push({id:s,sessionId:e.id,at:n,legacy:!0,observation:{usageObservationId:s,turnId:`legacy:${i.id}`,outcome:`success`,usage:o,...o.source?{source:o.source}:{},surface:`unknown`}})}return t}function N(e){let t=[];for(let n of e.history??[]){let r=n.data;if(n.type!==`tool-start`||!S(r))continue;let i=C(r.toolName),a=j(n);!i||!a||t.push({id:`tool:${e.id}:${n.id}`,sessionId:e.id,key:`tool:${i}`,label:i,kind:`tool`,at:a})}for(let n of e.skillActivationEvents??[]){if(n.status!==`started`)continue;let r=new Date(n.timestamp);Number.isNaN(r.getTime())||t.push({id:`activation:${e.id}:${n.timestamp}:${n.source}:${n.qualifiedName??n.skillName}:${n.invocation}`,sessionId:e.id,key:n.qualifiedName??`${n.source}:${n.skillName}`,label:n.qualifiedName??n.skillName,kind:n.source,at:r})}return t}function P(){return{sessions:new Set,observations:0,turns:0,promptTokens:0,completionTokens:0,totalTokens:0,costUsd:0,hasUnknownCost:!1,hasEstimatedCost:!1,unpricedTurns:0}}function F(e,t){let n=new Intl.DateTimeFormat(`en-CA`,{timeZone:t,year:`numeric`,month:`2-digit`,day:`2-digit`}).formatToParts(e),r=e=>n.find(t=>t.type===e)?.value??``;return`${r(`year`)}-${r(`month`)}-${r(`day`)}`}function oe(e,t,n){let[r,i,a]=F(e,t).split(`-`).map(Number),o=new Date(Date.UTC(r,i-1,a));return Array.from({length:n},(e,t)=>{let r=new Date(o);return r.setUTCDate(r.getUTCDate()-(n-t-1)),r.toISOString().slice(0,10)})}function se(e){let t=new Map;for(let n of e){let e=t.get(n.key);t.set(n.key,{item:n,count:(e?.count??0)+1})}return[...t.values()].map(({item:e,count:t})=>({key:e.key,label:e.label,kind:e.kind,count:t})).sort((e,t)=>t.count-e.count||e.key.localeCompare(t.key))}function I(e,t){let n=t.observation.usage;e.sessions.add(t.sessionId),e.observations+=1;let r=!t.legacy&&t.observation.source?.scope!==`tool`;r&&(e.turns+=1),e.promptTokens+=n?.promptTokens??0,e.completionTokens+=n?.completionTokens??0,e.totalTokens+=n?.totalTokens??0,e.costUsd+=n?.costUsd??0,n?.costStatus===`estimated`?e.hasEstimatedCost=!0:(e.hasUnknownCost=!0,r&&(e.unpricedTurns+=1))}function L(e,t){let n=[];for(let r of e){let e=r.observation.modelShares;if(e===void 0){n.push(r);continue}let i=new Map;for(let n of e){let e=t(n),a=i.get(e)?.observation.usage,o=r.observation.usage,s=n.costStatus===`unknown`||a?.costStatus===`unknown`?`unknown`:`estimated`;i.set(e,{...r,observation:{...r.observation,providerId:n.providerId,modelId:n.modelId,usage:{kind:o?.kind??`estimated`,scope:`turn`,contextUsedTokens:o?.contextUsedTokens??0,contextMaxTokens:o?.contextMaxTokens??0,contextUsedPercentage:o?.contextUsedPercentage??0,promptTokens:(a?.promptTokens??0)+n.promptTokens,completionTokens:(a?.completionTokens??0)+n.completionTokens,totalTokens:(a?.totalTokens??0)+n.totalTokens,costStatus:s,...s===`estimated`&&{costUsd:(a?.costUsd??0)+(n.costUsd??0)}}}})}n.push(...i.values())}return z(n,e=>t(e.observation))}function R(e){return{sessions:e.sessions.size,turns:e.turns,promptTokens:e.promptTokens,completionTokens:e.completionTokens,totalTokens:e.totalTokens,costUsd:e.costUsd,costStatus:e.hasEstimatedCost?`estimated`:`unknown`,...e.unpricedTurns>0?{unpricedTurns:e.unpricedTurns}:{}}}function z(e,t){let n=new Map;for(let r of e){let e=t(r),i=n.get(e)??P();I(i,r),n.set(e,i)}return[...n.entries()].map(([e,t])=>({key:e,label:e,frozen:R(t),sessionIds:[...t.sessions].sort()})).map(({key:e,label:t,frozen:n,sessionIds:r})=>({key:e,label:t,turns:n.turns,promptTokens:n.promptTokens,completionTokens:n.completionTokens,totalTokens:n.totalTokens,costUsd:n.costUsd,costStatus:n.costStatus,sessionIds:r})).sort((e,t)=>t.totalTokens-e.totalTokens||e.key.localeCompare(t.key))}function B(e){return e?e.id?`${e.scope}:${e.id}`:e.scope:`unknown`}function V(e,t,n){return e.getTime()<=t.now.getTime()&&n.has(F(e,t.request.timezone))}function H(e,t){let n=[],r=[],i=new Set,a=new Set,o=0,s=0;for(let c of e.records){for(let r of M(c))if(V(r.at,e,t)){if(i.has(r.id)){o+=1;continue}i.add(r.id),n.push(r),r.legacy&&(s+=1)}for(let n of N(c))!V(n.at,e,t)||a.has(n.id)||(a.add(n.id),r.push(n))}return{observations:n,activities:r,duplicateObservations:o,legacyObservations:s}}function U(e){let t=new Map,n=(e,n)=>{let r=n.getTime(),i=t.get(e);(i===void 0||r<i)&&t.set(e,r)};for(let t of e.observations)n(t.sessionId,t.at);for(let t of e.activities)n(t.sessionId,t.at);let r={};for(let[e,n]of t)r[e]=new Date(n).toISOString();return r}function W(e,t,n){let r=P(),i=new Map(t.map(e=>[e,P()]));for(let t of n.observations)I(r,t),I(i.get(F(t.at,e.request.timezone)),t);for(let t of n.activities)r.sessions.add(t.sessionId),i.get(F(t.at,e.request.timezone))?.sessions.add(t.sessionId);return{totals:r,byDay:i}}function G(e){let t=e.request.period===`30d`?30:7,n=oe(e.now,e.request.timezone,t),r=H(e,new Set(n)),{totals:i,byDay:a}=W(e,n,r),o=r.observations;return{schemaVersion:1,generatedAt:e.now.toISOString(),period:e.request.period,timezone:e.request.timezone,interval:{startDate:n[0],endDate:n.at(-1)},totals:R(i),daily:n.map((e,t)=>({date:e,partial:t===n.length-1,totals:R(a.get(e)),sessionIds:[...a.get(e).sessions].sort()})),byModel:L(o,e=>e.modelId??`unknown`),byProvider:L(o,e=>e.providerId??`unknown`),bySurface:z(o,e=>e.observation.surface??`unknown`),bySource:z(o,e=>B(e.observation.source)),byActivity:se(r.activities),sessionIds:[...i.sessions].sort(),sessionFirstSeen:U(r),coverage:{validSessions:e.records.length,corruptSessions:e.corruptSessionIds?.length??0,unsupportedSessions:e.unsupportedSessionIds?.length??0,duplicateObservations:r.duplicateObservations,legacyObservations:r.legacyObservations,unknownModelObservations:o.filter(e=>!e.observation.modelId&&!e.observation.modelShares).length,unknownProviderObservations:o.filter(e=>!e.observation.providerId&&!e.observation.modelShares).length,unknownSurfaceObservations:o.filter(e=>!e.observation.surface||e.observation.surface===`unknown`).length,corruptSessionIds:[...e.corruptSessionIds??[]].sort(),unsupportedSessionIds:[...e.unsupportedSessionIds??[]].sort()}}}const ce=(1n<<64n)-1n,K=/^(?!0{32}$)[0-9a-f]{32}$/,q=/^(?!0{16}$)[0-9a-f]{16}$/,le=[`promptExecutionStartedAt`,`promptExecutionEndedAt`,`promptExecutionOutcome`,`promptExecutionTraceId`,`promptExecutionSpanId`];function J(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function Y(e,t){e.set(t,(e.get(t)??0)+1)}function X(e){if(typeof e!=`string`)return;let t=new Date(e);if(Number.isNaN(t.getTime())||t.toISOString()!==e)return;let n=BigInt(t.getTime())*1000000n;return n>=0n&&n<=ce?n:void 0}function ue(e){let t=X(e.promptExecutionStartedAt),n=X(e.promptExecutionEndedAt),r=e.promptExecutionOutcome,i=e.promptExecutionTraceId,a=e.promptExecutionSpanId;if(!(t===void 0||n===void 0||t>n||r!==`success`&&r!==`failure`&&r!==`interrupted`||typeof i!=`string`||!K.test(i)||typeof a!=`string`||!q.test(a)||typeof e.usageObservationId!=`string`||e.usageObservationId.length===0||e.turnId!==e.usageObservationId||e.outcome!==`success`&&e.outcome!==`failure`&&e.outcome!==`interrupted`))return{traceId:i,spanId:a,name:`robota.prompt_execution`,kind:1,startTimeUnixNano:String(t),endTimeUnixNano:String(n),attributes:[{key:`robota.prompt.outcome`,value:{stringValue:r}}],status:{code:r===`success`?1:r===`failure`?2:0}}}function de(e,t){if(!J(e))return;let n=e.traceId,r=e.parentSpanId,i=e.spanId,a=X(e.startedAt),o=X(e.endedAt),s=e.outcome;if(!(typeof n!=`string`||!K.test(n)||typeof r!=`string`||!q.test(r)||typeof i!=`string`||!q.test(i)||a===void 0||o===void 0||a>o||s!==`success`&&s!==`failure`&&s!==`interrupted`||t===`provider`&&(!Number.isSafeInteger(e.round)||e.round<1)))return{traceId:n,parentSpanId:r,spanId:i,name:t===`provider`?`robota.provider_call`:`robota.tool_body`,kind:1,startTimeUnixNano:String(a),endTimeUnixNano:String(o),attributes:[{key:t===`provider`?`robota.provider.outcome`:`robota.tool.outcome`,value:{stringValue:s}}],status:{code:s===`success`?1:s===`failure`?2:0}}}function fe(e){if(!J(e))return;let t=e.traceId,n=e.spanId;return typeof t==`string`&&K.test(t)&&typeof n==`string`&&q.test(n)?`${t}:${n}`:void 0}function Z(e){return typeof e==`number`&&Number.isSafeInteger(e)&&e>=0}function pe(t,n,r,i){if(!J(n)||n.disposition===void 0)return r.legacy+=1,t;if(n.disposition!==`invoked`)return r.invalid+=1,t;i.invoked+=1;let a=n.usageProvenance;if(a===`partial`)return r.partial+=1,i.unknownCost+=1,t;if(a===`absent`||a===void 0)return r.absent+=1,i.unknownCost+=1,t;let o=n.promptTokens,s=n.completionTokens,c=n.totalTokens;if(a!==`complete`||!Z(o)||!Z(s)||!Number.isSafeInteger(o+s)||c!==o+s)return r.invalid+=1,i.unknownCost+=1,t;i.completeUsage+=1,i.inputTokens+=o,i.outputTokens+=s;let l=[...t.attributes,{key:`robota.provider.usage.input_tokens`,value:{intValue:String(o)}},{key:`robota.provider.usage.output_tokens`,value:{intValue:String(s)}}],u=n.modelId,d=typeof u==`string`&&u.length>0&&u.length<=128&&[...u].every(e=>e.charCodeAt(0)>=32)?(0,e.calculateModelCost)(u,o,s):void 0;return d===void 0||!Number.isFinite(d)||d<0?i.unknownCost+=1:(i.estimatedCostUsd+=d,typeof u==`string`&&Object.hasOwn(e.MODEL_PRICES,u)?i.exactPriceMatches+=1:i.familyPriceMatches+=1,l.push({key:`robota.provider.cost.usd.estimated`,value:{doubleValue:d}})),{...t,attributes:l}}function Q(e,t){let n=[],r=new Map,i=new Map;for(let t of e)for(let e of t.history??[]){if(e.type!==`usage-observation`)continue;let a=e.data,o=J(a)?a.usageObservationId:void 0,s=J(a)?a.promptExecutionTraceId:void 0,c=typeof o==`string`&&o.length>0?JSON.stringify([t.id,o]):void 0,l=typeof s==`string`&&K.test(s)?s:void 0;c&&Y(r,c),l&&Y(i,l),n.push({record:t,data:a,observationKey:c,traceId:l})}let a=[],o=new Map,s=0,c=0,l=0;for(let e of n){if(e.observationKey&&(r.get(e.observationKey)??0)>1||e.traceId&&(i.get(e.traceId)??0)>1){l+=1;continue}let t=e.data;if(!J(t)){c+=1;continue}if(le.every(e=>t[e]===void 0)){s+=1;continue}let n=ue(t);if(!n){c+=1;continue}a.push(n);let u=o.get(e.record)??new Map;u.set(n.traceId,n),o.set(e.record,u)}let u=[],d=new Map;for(let t of e)for(let e of t.history??[]){let n=e.type===`provider-call-trace`?`provider`:e.type===`tool-body-trace`?`tool`:void 0;if(!n)continue;let r=fe(e.data),i=de(e.data,n);r&&Y(d,r),u.push({record:t,span:i,identity:r,kind:n,data:e.data})}let f={provider:{exported:0,invalid:0,orphaned:0,duplicate:0},tool:{exported:0,invalid:0,orphaned:0,duplicate:0}},p={legacy:0,invalid:0,partial:0,absent:0,nonInvoked:0},m={invoked:0,completeUsage:0,inputTokens:0,outputTokens:0,estimatedCostUsd:0,unknownCost:0,exactPriceMatches:0,familyPriceMatches:0};for(let e of u){let{span:t}=e,n=f[e.kind];if(e.identity&&(d.get(e.identity)??0)>1){n.duplicate+=1;continue}if(!t){n.invalid+=1;continue}let r=o.get(e.record)?.get(t.traceId);if(!r||t.parentSpanId!==r.spanId||t.spanId===r.spanId){n.orphaned+=1;continue}if(BigInt(t.startTimeUnixNano)<BigInt(r.startTimeUnixNano)||BigInt(t.endTimeUnixNano)>BigInt(r.endTimeUnixNano)){n.invalid+=1;continue}if(e.kind===`provider`&&J(e.data)&&(e.data.disposition===`cache-hit`||e.data.disposition===`preflight-refused`)){p.nonInvoked+=1,(e.data.promptTokens!==void 0||e.data.completionTokens!==void 0||e.data.totalTokens!==void 0||e.data.usageProvenance===`complete`)&&(p.invalid+=1);continue}a.push(e.kind===`provider`?pe(t,e.data,p,m):t),n.exported+=1}return{payload:{resourceSpans:a.length?[{resource:{attributes:[{key:`service.name`,value:{stringValue:`robota`}},{key:`service.version`,value:{stringValue:t}}]},scopeSpans:[{scope:{name:`@robota-sdk/agent-session-analytics`},spans:a}]}]:[]},coverage:{exported:a.length-f.provider.exported-f.tool.exported,missing:s,invalid:c,duplicate:l,providerChildren:f.provider,providerUsage:p,toolChildren:f.tool},callMetrics:m}}function me(e,t,n){let r=new Set,i=0,a=0,o=0,s=0,c=0,l=0,u=0,d=0;for(let t of e)for(let e of M(t)){if(r.has(e.id))continue;r.add(e.id),e.legacy||(i+=1);let t=e.observation.usage;if(!t){u+=1,c+=1;continue}a+=t.totalTokens,o+=t.promptTokens??0,s+=t.completionTokens??0,(t.promptTokens===void 0||t.completionTokens===void 0)&&(c+=1),t.costStatus===`unknown`||t.costUsd===void 0?u+=1:(l+=t.costUsd,t.costStatus===`estimated`&&(d+=1))}let f=Q(e,n),p=f.callMetrics,m=String(BigInt(t.getTime())*1000000n),h=(e,t,n)=>({name:e,unit:t,gauge:{dataPoints:[{timeUnixNano:m,asDouble:n}]}});return{resourceMetrics:[{resource:{attributes:[{key:`service.name`,value:{stringValue:`robota`}},{key:`service.version`,value:{stringValue:n}}]},scopeMetrics:[{scope:{name:`@robota-sdk/agent-session-analytics`},metrics:[h(`robota.session.count`,`{session}`,e.length),h(`robota.turn.count`,`{turn}`,i),h(`robota.token.total`,`{token}`,a),h(`robota.token.input.known`,`{token}`,o),h(`robota.token.output.known`,`{token}`,s),h(`robota.token.split_unknown_observations`,`{observation}`,c),h(`robota.cost.usd.known`,`USD`,l),h(`robota.cost.unknown_observations`,`{observation}`,u),h(`robota.cost.estimated_observations`,`{observation}`,d),h(`robota.provider_call.count`,`{call}`,p.invoked),h(`robota.provider_call.usage.complete_count`,`{call}`,p.completeUsage),h(`robota.provider_call.token.input.known`,`{token}`,p.inputTokens),h(`robota.provider_call.token.output.known`,`{token}`,p.outputTokens),h(`robota.provider_call.cost.usd.estimated`,`USD`,p.estimatedCostUsd),h(`robota.provider_call.cost.unknown_count`,`{call}`,p.unknownCost),h(`robota.provider_call.usage.partial_count`,`{call}`,f.coverage.providerUsage.partial),h(`robota.provider_call.usage.invalid_count`,`{call}`,f.coverage.providerUsage.invalid),h(`robota.provider_call.usage.legacy_count`,`{call}`,f.coverage.providerUsage.legacy),h(`robota.provider_call.price.exact_id_count`,`{call}`,p.exactPriceMatches),h(`robota.provider_call.price.family_fallback_count`,`{call}`,p.familyPriceMatches)]}]}]}}const he=(1n<<64n)-1n;function ge(e){let t=e.getTime();if(!Number.isSafeInteger(t)||t<0)throw RangeError(`OTLP log observation time must be a valid post-epoch date.`);let n=BigInt(t)*1000000n;if(n>he)throw RangeError(`OTLP log observation time is out of range.`);return String(n)}function _e(e,t,n){let r=Q(e,t),i=r.payload.resourceSpans[0]?.scopeSpans[0]?.spans??[];if(i.length===0)return{exported:0,coverage:r.coverage,payload:{resourceLogs:[]}};let a=ge(n),o=i.map(e=>{let t=e.attributes.find(e=>e.key===`robota.prompt.outcome`||e.key===`robota.provider.outcome`||e.key===`robota.tool.outcome`),n=e.name===`robota.prompt_execution`?`robota.prompt_execution.completed`:e.name===`robota.provider_call`?`robota.provider_call.completed`:`robota.tool_body.completed`,r=e.status.code===1?9:e.status.code===2?17:13,i=r===9?`INFO`:r===17?`ERROR`:`WARN`;return{timeUnixNano:e.endTimeUnixNano,observedTimeUnixNano:a,severityNumber:r,severityText:i,eventName:n,traceId:e.traceId,spanId:e.spanId,attributes:t&&`stringValue`in t.value?[{key:t.key,value:{stringValue:t.value.stringValue}}]:[]}});return{exported:o.length,coverage:r.coverage,payload:{resourceLogs:[{resource:r.payload.resourceSpans[0].resource,scopeLogs:[{scope:{name:`@robota-sdk/agent-session-analytics`},logRecords:o}]}]}}}function $(e,t){return[``,e,...t.length===0?[`(none)`]:t.map(e=>`${e.label} ${e.turns} turns ${e.totalTokens} tokens cost ${e.costStatus===`unknown`?`unknown`:`$${e.costUsd.toFixed(4)}`}`)]}function ve(e){let t=e.totals.costStatus===`unknown`?`unknown`:`$${e.totals.costUsd.toFixed(4)} (${e.totals.costStatus})`;return[`Personal usage — ${e.period} (${e.timezone})`,`${e.interval.startDate} → ${e.interval.endDate}`,`Sessions ${e.totals.sessions} · Turns ${e.totals.turns} · Tokens ${e.totals.totalTokens} (${e.totals.promptTokens} input / ${e.totals.completionTokens} output) · Cost ${t}`,``,`Daily usage`,...e.daily.map(e=>`${e.date}${e.partial?` (partial)`:``} ${e.totals.turns} turns ${e.totals.totalTokens} tokens`),...$(`By model`,e.byModel),...$(`By provider`,e.byProvider),...$(`By surface`,e.bySurface),...$(`By source`,e.bySource),``,`Activity`,...e.byActivity.length===0?[`(none)`]:e.byActivity.map(e=>`${e.kind}:${e.label} ${e.count} calls`),``,`Coverage: legacy ${e.coverage.legacyObservations}, corrupt ${e.coverage.corruptSessions}, unsupported ${e.coverage.unsupportedSessions}, duplicates ${e.coverage.duplicateObservations}`,`Local estimates from recorded sessions; costs are not an invoice.`].join(`
|
|
4
|
+
`)}const _={scope:`main`,label:`main thread`};function v(e){return`${e.scope}:${e.id??``}`}function y(e){return e.label??(e.id?`${e.scope} ${e.id}`:e.scope)}function ee(e){return e.type===`usage-summary`&&typeof e.data==`object`&&e.data!==null}function te(e){if(e.type!==`span`||typeof e.data!=`object`||e.data===null)return!1;let t=e.data;return typeof t.spanId==`string`&&typeof t.op==`string`&&typeof t.durationMs==`number`}function b(e,t){return t<=0?0:Math.round(e/t*1e3)/10}function x(e){let t=new Map,n=0,r=0,i=0,a=0,o=!0,s=[],c=[],l=e=>{c.length!==0&&(s.push({turnIndex:s.length,source:e,label:y(e),spans:c,totalDurationMs:c.reduce((e,t)=>e+t.durationMs,0)}),c=[])};for(let s of e.history??[]){if(te(s)){let e=s.data;c.push({spanId:e.spanId,op:e.op,durationMs:e.durationMs});continue}if(!ee(s))continue;let e=s.data,u=e.source??_,d=v(u),f=e.promptTokens??0,p=e.completionTokens??0,m=e.totalTokens,h=e.costUsd??0;n+=f,r+=p,i+=m,a+=h,o=!1;let g=t.get(d);g?(g.promptTokens+=f,g.completionTokens+=p,g.totalTokens+=m,g.turns+=1,g.costUsd+=h,g.costExact=!1):t.set(d,{key:d,source:u,label:y(u),promptTokens:f,completionTokens:p,totalTokens:m,turns:1,percentage:0,costUsd:h,costExact:!1}),l(u)}l(_);let u=[...t.values()].map(e=>({...e,percentage:b(e.totalTokens,i)})).sort((e,t)=>t.totalTokens-e.totalTokens);return{sessionId:e.id,totalTokens:i,promptTokens:n,completionTokens:r,costUsd:a,costExact:o,bySource:u,...u[0]?{topConsumer:u[0]}:{},timeline:s}}function S(e){return typeof e==`object`&&!!e&&!Array.isArray(e)&&!(e instanceof Date)}function C(e){return typeof e==`string`&&e.length>0?e:void 0}function w(e){return typeof e==`number`&&Number.isFinite(e)&&e>=0}function T(e){return e===`unknown`||e===`estimated`||e===`exact`}function ne(e){return(e.promptTokens===void 0||w(e.promptTokens))&&(e.completionTokens===void 0||w(e.completionTokens))}function re(e){let t=e.costStatus;return T(t)?t===`unknown`?e.costUsd===void 0:w(e.costUsd):!1}function ie(e){return w(e.totalTokens)&&w(e.contextUsedTokens)&&w(e.contextMaxTokens)&&w(e.contextUsedPercentage)}function ae(e){return e===`cli`||e===`desktop-app`||e===`browser`||e===`remote`||e===`attach`||e===`unknown`}function E(e){if(!S(e))return;let t=e.scope;if(t!==`main`&&t!==`subagent`&&t!==`background`&&t!==`tool`&&t!==`command`&&t!==`skill`)return;let n=C(e.id),r=C(e.label);return{scope:t,...n?{id:n}:{},...r?{label:r}:{}}}function D(e){if(!S(e)||e.kind!==`exact`&&e.kind!==`estimated`||e.scope!==`turn`||!ne(e)||!re(e)||!ie(e)||!T(e.costStatus))return;let t=E(e.source);return{kind:e.kind,scope:`turn`,totalTokens:e.totalTokens,contextUsedTokens:e.contextUsedTokens,contextMaxTokens:e.contextMaxTokens,contextUsedPercentage:e.contextUsedPercentage,costStatus:e.costStatus===`exact`?`estimated`:e.costStatus,...w(e.promptTokens)?{promptTokens:e.promptTokens}:{},...w(e.completionTokens)?{completionTokens:e.completionTokens}:{},...w(e.costUsd)?{costUsd:e.costUsd}:{},...t?{source:t}:{}}}function O(e){if(!S(e))return;let t=C(e.providerId),n=C(e.modelId),{promptTokens:r,completionTokens:i,totalTokens:a,costStatus:o,costUsd:s}=e;if(!(!t||!n||!w(r)||!w(i)||!w(a)||o!==`unknown`&&o!==`estimated`||(o===`estimated`?!w(s):s!==void 0)))return{providerId:t,modelId:n,promptTokens:r,completionTokens:i,totalTokens:a,costStatus:o,...o===`estimated`&&w(s)?{costUsd:s}:{}}}function k(e){if(!Array.isArray(e)||e.length===0)return;let t=e.map(O);return t.every(e=>e!==void 0)?t:void 0}function A(e){if(!S(e))return;let t=C(e.usageObservationId),n=C(e.turnId),r=e.outcome;if(!t||!n||r!==`success`&&r!==`failure`&&r!==`interrupted`)return;let i=e.surface,a=E(e.source),o=D(e.usage),s=k(e.modelShares);return{usageObservationId:t,turnId:n,outcome:r,...C(e.modelId)?{modelId:C(e.modelId)}:{},...C(e.providerId)?{providerId:C(e.providerId)}:{},...s?{modelShares:s}:{},...ae(i)?{surface:i}:{},...a?{source:a}:{},...o?{usage:o}:{}}}function j(e){let t=new Date(e.timestamp);return Number.isNaN(t.getTime())?void 0:t}function M(e){let t=[],n=e.history??[],r=new Set,i=n.flatMap((e,t)=>{if(e.type!==`usage-summary`)return[];let n=D(e.data);return n?[{id:e.id,index:t,usage:n}]:[]});for(let[e,t]of n.entries()){if(t.type!==`usage-observation`)continue;let n=A(t.data);if(!n?.usage)continue;let a=JSON.stringify(n.usage),o=i.map((e,t)=>({candidate:e,index:t})).filter(({candidate:e})=>JSON.stringify(e.usage)===a).sort((t,n)=>Math.abs(t.candidate.index-e)-Math.abs(n.candidate.index-e))[0];o&&(r.add(o.candidate.id),i.splice(o.index,1))}for(let i of n){let n=j(i);if(!n)continue;let a=i.type===`usage-observation`?A(i.data):void 0;if(a){t.push({id:a.usageObservationId,sessionId:e.id,at:n,legacy:!1,observation:a});continue}if(i.type!==`usage-summary`||r.has(i.id))continue;let o=D(i.data);if(!o)continue;let s=`legacy:${e.id}:${i.id}`;t.push({id:s,sessionId:e.id,at:n,legacy:!0,observation:{usageObservationId:s,turnId:`legacy:${i.id}`,outcome:`success`,usage:o,...o.source?{source:o.source}:{},surface:`unknown`}})}return t}function N(e){let t=[];for(let n of e.history??[]){let r=n.data;if(n.type!==`tool-start`||!S(r))continue;let i=C(r.toolName),a=j(n);!i||!a||t.push({id:`tool:${e.id}:${n.id}`,sessionId:e.id,key:`tool:${i}`,label:i,kind:`tool`,at:a})}for(let n of e.skillActivationEvents??[]){if(n.status!==`started`)continue;let r=new Date(n.timestamp);Number.isNaN(r.getTime())||t.push({id:`activation:${e.id}:${n.timestamp}:${n.source}:${n.qualifiedName??n.skillName}:${n.invocation}`,sessionId:e.id,key:n.qualifiedName??`${n.source}:${n.skillName}`,label:n.qualifiedName??n.skillName,kind:n.source,at:r})}return t}function P(){return{sessions:new Set,observations:0,turns:0,promptTokens:0,completionTokens:0,totalTokens:0,costUsd:0,hasUnknownCost:!1,hasEstimatedCost:!1,unpricedTurns:0}}function F(e,t){let n=new Intl.DateTimeFormat(`en-CA`,{timeZone:t,year:`numeric`,month:`2-digit`,day:`2-digit`}).formatToParts(e),r=e=>n.find(t=>t.type===e)?.value??``;return`${r(`year`)}-${r(`month`)}-${r(`day`)}`}function oe(e,t,n){let[r,i,a]=F(e,t).split(`-`).map(Number),o=new Date(Date.UTC(r,i-1,a));return Array.from({length:n},(e,t)=>{let r=new Date(o);return r.setUTCDate(r.getUTCDate()-(n-t-1)),r.toISOString().slice(0,10)})}function se(e){let t=new Map;for(let n of e){let e=t.get(n.key);t.set(n.key,{item:n,count:(e?.count??0)+1})}return[...t.values()].map(({item:e,count:t})=>({key:e.key,label:e.label,kind:e.kind,count:t})).sort((e,t)=>t.count-e.count||e.key.localeCompare(t.key))}function I(e,t){let n=t.observation.usage;e.sessions.add(t.sessionId),e.observations+=1;let r=!t.legacy&&t.observation.source?.scope!==`tool`;r&&(e.turns+=1),e.promptTokens+=n?.promptTokens??0,e.completionTokens+=n?.completionTokens??0,e.totalTokens+=n?.totalTokens??0,e.costUsd+=n?.costUsd??0,n?.costStatus===`estimated`?e.hasEstimatedCost=!0:(e.hasUnknownCost=!0,r&&(e.unpricedTurns+=1))}function L(e,t){let n=[];for(let r of e){let e=r.observation.modelShares;if(e===void 0){n.push(r);continue}let i=new Map;for(let n of e){let e=t(n),a=i.get(e)?.observation.usage,o=r.observation.usage,s=n.costStatus===`unknown`||a?.costStatus===`unknown`?`unknown`:`estimated`;i.set(e,{...r,observation:{...r.observation,providerId:n.providerId,modelId:n.modelId,usage:{kind:o?.kind??`estimated`,scope:`turn`,contextUsedTokens:o?.contextUsedTokens??0,contextMaxTokens:o?.contextMaxTokens??0,contextUsedPercentage:o?.contextUsedPercentage??0,promptTokens:(a?.promptTokens??0)+n.promptTokens,completionTokens:(a?.completionTokens??0)+n.completionTokens,totalTokens:(a?.totalTokens??0)+n.totalTokens,costStatus:s,...s===`estimated`&&{costUsd:(a?.costUsd??0)+(n.costUsd??0)}}}})}n.push(...i.values())}return z(n,e=>t(e.observation))}function R(e){return{sessions:e.sessions.size,turns:e.turns,promptTokens:e.promptTokens,completionTokens:e.completionTokens,totalTokens:e.totalTokens,costUsd:e.costUsd,costStatus:e.hasEstimatedCost?`estimated`:`unknown`,...e.unpricedTurns>0?{unpricedTurns:e.unpricedTurns}:{}}}function z(e,t){let n=new Map;for(let r of e){let e=t(r),i=n.get(e)??P();I(i,r),n.set(e,i)}return[...n.entries()].map(([e,t])=>({key:e,label:e,frozen:R(t),sessionIds:[...t.sessions].sort()})).map(({key:e,label:t,frozen:n,sessionIds:r})=>({key:e,label:t,turns:n.turns,promptTokens:n.promptTokens,completionTokens:n.completionTokens,totalTokens:n.totalTokens,costUsd:n.costUsd,costStatus:n.costStatus,sessionIds:r})).sort((e,t)=>t.totalTokens-e.totalTokens||e.key.localeCompare(t.key))}function B(e){return e?e.id?`${e.scope}:${e.id}`:e.scope:`unknown`}function V(e,t,n){return e.getTime()<=t.now.getTime()&&n.has(F(e,t.request.timezone))}function H(e,t){let n=[],r=[],i=new Set,a=new Set,o=0,s=0;for(let c of e.records){for(let r of M(c))if(V(r.at,e,t)){if(i.has(r.id)){o+=1;continue}i.add(r.id),n.push(r),r.legacy&&(s+=1)}for(let n of N(c))!V(n.at,e,t)||a.has(n.id)||(a.add(n.id),r.push(n))}return{observations:n,activities:r,duplicateObservations:o,legacyObservations:s}}function U(e){let t=new Map,n=(e,n)=>{let r=n.getTime(),i=t.get(e);(i===void 0||r<i)&&t.set(e,r)};for(let t of e.observations)n(t.sessionId,t.at);for(let t of e.activities)n(t.sessionId,t.at);let r={};for(let[e,n]of t)r[e]=new Date(n).toISOString();return r}function W(e,t,n){let r=P(),i=new Map(t.map(e=>[e,P()]));for(let t of n.observations)I(r,t),I(i.get(F(t.at,e.request.timezone)),t);for(let t of n.activities)r.sessions.add(t.sessionId),i.get(F(t.at,e.request.timezone))?.sessions.add(t.sessionId);return{totals:r,byDay:i}}function G(e){let t=e.request.period===`30d`?30:7,n=oe(e.now,e.request.timezone,t),r=H(e,new Set(n)),{totals:i,byDay:a}=W(e,n,r),o=r.observations;return{schemaVersion:1,generatedAt:e.now.toISOString(),period:e.request.period,timezone:e.request.timezone,interval:{startDate:n[0],endDate:n.at(-1)},totals:R(i),daily:n.map((e,t)=>({date:e,partial:t===n.length-1,totals:R(a.get(e)),sessionIds:[...a.get(e).sessions].sort()})),byModel:L(o,e=>e.modelId??`unknown`),byProvider:L(o,e=>e.providerId??`unknown`),bySurface:z(o,e=>e.observation.surface??`unknown`),bySource:z(o,e=>B(e.observation.source)),byActivity:se(r.activities),sessionIds:[...i.sessions].sort(),sessionFirstSeen:U(r),coverage:{validSessions:e.records.length,corruptSessions:e.corruptSessionIds?.length??0,unsupportedSessions:e.unsupportedSessionIds?.length??0,duplicateObservations:r.duplicateObservations,legacyObservations:r.legacyObservations,unknownModelObservations:o.filter(e=>!e.observation.modelId&&!e.observation.modelShares).length,unknownProviderObservations:o.filter(e=>!e.observation.providerId&&!e.observation.modelShares).length,unknownSurfaceObservations:o.filter(e=>!e.observation.surface||e.observation.surface===`unknown`).length,corruptSessionIds:[...e.corruptSessionIds??[]].sort(),unsupportedSessionIds:[...e.unsupportedSessionIds??[]].sort()}}}const ce=(1n<<64n)-1n,K=/^(?!0{32}$)[0-9a-f]{32}$/,q=/^(?!0{16}$)[0-9a-f]{16}$/,le=[`promptExecutionStartedAt`,`promptExecutionEndedAt`,`promptExecutionOutcome`,`promptExecutionTraceId`,`promptExecutionSpanId`];function J(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function Y(e,t){e.set(t,(e.get(t)??0)+1)}function X(e){if(typeof e!=`string`)return;let t=new Date(e);if(Number.isNaN(t.getTime())||t.toISOString()!==e)return;let n=BigInt(t.getTime())*1000000n;return n>=0n&&n<=ce?n:void 0}function ue(e){let t=X(e.promptExecutionStartedAt),n=X(e.promptExecutionEndedAt),r=e.promptExecutionOutcome,i=e.promptExecutionTraceId,a=e.promptExecutionSpanId;if(!(t===void 0||n===void 0||t>n||r!==`success`&&r!==`failure`&&r!==`interrupted`||typeof i!=`string`||!K.test(i)||typeof a!=`string`||!q.test(a)||typeof e.usageObservationId!=`string`||e.usageObservationId.length===0||e.turnId!==e.usageObservationId||e.outcome!==`success`&&e.outcome!==`failure`&&e.outcome!==`interrupted`))return{traceId:i,spanId:a,name:`agent.prompt_execution`,kind:1,startTimeUnixNano:String(t),endTimeUnixNano:String(n),attributes:[{key:`agent.prompt.outcome`,value:{stringValue:r}}],status:{code:r===`success`?1:r===`failure`?2:0}}}function de(e,t){if(!J(e))return;let n=e.traceId,r=e.parentSpanId,i=e.spanId,a=X(e.startedAt),o=X(e.endedAt),s=e.outcome;if(!(typeof n!=`string`||!K.test(n)||typeof r!=`string`||!q.test(r)||typeof i!=`string`||!q.test(i)||a===void 0||o===void 0||a>o||s!==`success`&&s!==`failure`&&s!==`interrupted`||t===`provider`&&(!Number.isSafeInteger(e.round)||e.round<1)))return{traceId:n,parentSpanId:r,spanId:i,name:t===`provider`?`agent.provider_call`:`agent.tool_body`,kind:1,startTimeUnixNano:String(a),endTimeUnixNano:String(o),attributes:[{key:t===`provider`?`agent.provider.outcome`:`agent.tool.outcome`,value:{stringValue:s}}],status:{code:s===`success`?1:s===`failure`?2:0}}}function fe(e){if(!J(e))return;let t=e.traceId,n=e.spanId;return typeof t==`string`&&K.test(t)&&typeof n==`string`&&q.test(n)?`${t}:${n}`:void 0}function Z(e){return typeof e==`number`&&Number.isSafeInteger(e)&&e>=0}function pe(t,n,r,i){if(!J(n)||n.disposition===void 0)return r.legacy+=1,t;if(n.disposition!==`invoked`)return r.invalid+=1,t;i.invoked+=1;let a=n.usageProvenance;if(a===`partial`)return r.partial+=1,i.unknownCost+=1,t;if(a===`absent`||a===void 0)return r.absent+=1,i.unknownCost+=1,t;let o=n.promptTokens,s=n.completionTokens,c=n.totalTokens;if(a!==`complete`||!Z(o)||!Z(s)||!Number.isSafeInteger(o+s)||c!==o+s)return r.invalid+=1,i.unknownCost+=1,t;i.completeUsage+=1,i.inputTokens+=o,i.outputTokens+=s;let l=[...t.attributes,{key:`agent.provider.usage.input_tokens`,value:{intValue:String(o)}},{key:`agent.provider.usage.output_tokens`,value:{intValue:String(s)}}],u=n.modelId,d=typeof u==`string`&&u.length>0&&u.length<=128&&[...u].every(e=>e.charCodeAt(0)>=32)?(0,e.calculateModelCost)(u,o,s):void 0;return d===void 0||!Number.isFinite(d)||d<0?i.unknownCost+=1:(i.estimatedCostUsd+=d,typeof u==`string`&&Object.hasOwn(e.MODEL_PRICES,u)?i.exactPriceMatches+=1:i.familyPriceMatches+=1,l.push({key:`agent.provider.cost.usd.estimated`,value:{doubleValue:d}})),{...t,attributes:l}}function Q(e,t,n){let r=[],i=new Map,a=new Map;for(let t of e)for(let e of t.history??[]){if(e.type!==`usage-observation`)continue;let n=e.data,o=J(n)?n.usageObservationId:void 0,s=J(n)?n.promptExecutionTraceId:void 0,c=typeof o==`string`&&o.length>0?JSON.stringify([t.id,o]):void 0,l=typeof s==`string`&&K.test(s)?s:void 0;c&&Y(i,c),l&&Y(a,l),r.push({record:t,data:n,observationKey:c,traceId:l})}let o=[],s=new Map,c=0,l=0,u=0;for(let e of r){if(e.observationKey&&(i.get(e.observationKey)??0)>1||e.traceId&&(a.get(e.traceId)??0)>1){u+=1;continue}let t=e.data;if(!J(t)){l+=1;continue}if(le.every(e=>t[e]===void 0)){c+=1;continue}let n=ue(t);if(!n){l+=1;continue}o.push(n);let r=s.get(e.record)??new Map;r.set(n.traceId,n),s.set(e.record,r)}let d=[],f=new Map;for(let t of e)for(let e of t.history??[]){let n=e.type===`provider-call-trace`?`provider`:e.type===`tool-body-trace`?`tool`:void 0;if(!n)continue;let r=fe(e.data),i=de(e.data,n);r&&Y(f,r),d.push({record:t,span:i,identity:r,kind:n,data:e.data})}let p={provider:{exported:0,invalid:0,orphaned:0,duplicate:0},tool:{exported:0,invalid:0,orphaned:0,duplicate:0}},m={legacy:0,invalid:0,partial:0,absent:0,nonInvoked:0},h={invoked:0,completeUsage:0,inputTokens:0,outputTokens:0,estimatedCostUsd:0,unknownCost:0,exactPriceMatches:0,familyPriceMatches:0};for(let e of d){let{span:t}=e,n=p[e.kind];if(e.identity&&(f.get(e.identity)??0)>1){n.duplicate+=1;continue}if(!t){n.invalid+=1;continue}let r=s.get(e.record)?.get(t.traceId);if(!r||t.parentSpanId!==r.spanId||t.spanId===r.spanId){n.orphaned+=1;continue}if(BigInt(t.startTimeUnixNano)<BigInt(r.startTimeUnixNano)||BigInt(t.endTimeUnixNano)>BigInt(r.endTimeUnixNano)){n.invalid+=1;continue}if(e.kind===`provider`&&J(e.data)&&(e.data.disposition===`cache-hit`||e.data.disposition===`preflight-refused`)){m.nonInvoked+=1,(e.data.promptTokens!==void 0||e.data.completionTokens!==void 0||e.data.totalTokens!==void 0||e.data.usageProvenance===`complete`)&&(m.invalid+=1);continue}o.push(e.kind===`provider`?pe(t,e.data,m,h):t),n.exported+=1}return{payload:{resourceSpans:o.length?[{resource:{attributes:[{key:`service.name`,value:{stringValue:n}},{key:`service.version`,value:{stringValue:t}}]},scopeSpans:[{scope:{name:`@robota-sdk/agent-session-analytics`},spans:o}]}]:[]},coverage:{exported:o.length-p.provider.exported-p.tool.exported,missing:c,invalid:l,duplicate:u,providerChildren:p.provider,providerUsage:m,toolChildren:p.tool},callMetrics:h}}function me(e,t,n,r){let i=new Set,a=0,o=0,s=0,c=0,l=0,u=0,d=0,f=0;for(let t of e)for(let e of M(t)){if(i.has(e.id))continue;i.add(e.id),e.legacy||(a+=1);let t=e.observation.usage;if(!t){d+=1,l+=1;continue}o+=t.totalTokens,s+=t.promptTokens??0,c+=t.completionTokens??0,(t.promptTokens===void 0||t.completionTokens===void 0)&&(l+=1),t.costStatus===`unknown`||t.costUsd===void 0?d+=1:(u+=t.costUsd,t.costStatus===`estimated`&&(f+=1))}let p=Q(e,n,r),m=p.callMetrics,h=String(BigInt(t.getTime())*1000000n),g=(e,t,n)=>({name:e,unit:t,gauge:{dataPoints:[{timeUnixNano:h,asDouble:n}]}});return{resourceMetrics:[{resource:{attributes:[{key:`service.name`,value:{stringValue:r}},{key:`service.version`,value:{stringValue:n}}]},scopeMetrics:[{scope:{name:`@robota-sdk/agent-session-analytics`},metrics:[g(`agent.session.count`,`{session}`,e.length),g(`agent.turn.count`,`{turn}`,a),g(`agent.token.total`,`{token}`,o),g(`agent.token.input.known`,`{token}`,s),g(`agent.token.output.known`,`{token}`,c),g(`agent.token.split_unknown_observations`,`{observation}`,l),g(`agent.cost.usd.known`,`USD`,u),g(`agent.cost.unknown_observations`,`{observation}`,d),g(`agent.cost.estimated_observations`,`{observation}`,f),g(`agent.provider_call.count`,`{call}`,m.invoked),g(`agent.provider_call.usage.complete_count`,`{call}`,m.completeUsage),g(`agent.provider_call.token.input.known`,`{token}`,m.inputTokens),g(`agent.provider_call.token.output.known`,`{token}`,m.outputTokens),g(`agent.provider_call.cost.usd.estimated`,`USD`,m.estimatedCostUsd),g(`agent.provider_call.cost.unknown_count`,`{call}`,m.unknownCost),g(`agent.provider_call.usage.partial_count`,`{call}`,p.coverage.providerUsage.partial),g(`agent.provider_call.usage.invalid_count`,`{call}`,p.coverage.providerUsage.invalid),g(`agent.provider_call.usage.legacy_count`,`{call}`,p.coverage.providerUsage.legacy),g(`agent.provider_call.price.exact_id_count`,`{call}`,m.exactPriceMatches),g(`agent.provider_call.price.family_fallback_count`,`{call}`,m.familyPriceMatches)]}]}]}}const he=(1n<<64n)-1n;function ge(e){let t=e.getTime();if(!Number.isSafeInteger(t)||t<0)throw RangeError(`OTLP log observation time must be a valid post-epoch date.`);let n=BigInt(t)*1000000n;if(n>he)throw RangeError(`OTLP log observation time is out of range.`);return String(n)}function _e(e,t,n,r){let i=Q(e,t,r),a=i.payload.resourceSpans[0]?.scopeSpans[0]?.spans??[];if(a.length===0)return{exported:0,coverage:i.coverage,payload:{resourceLogs:[]}};let o=ge(n),s=a.map(e=>{let t=e.attributes.find(e=>e.key===`agent.prompt.outcome`||e.key===`agent.provider.outcome`||e.key===`agent.tool.outcome`),n=e.name===`agent.prompt_execution`?`agent.prompt_execution.completed`:e.name===`agent.provider_call`?`agent.provider_call.completed`:`agent.tool_body.completed`,r=e.status.code===1?9:e.status.code===2?17:13,i=r===9?`INFO`:r===17?`ERROR`:`WARN`;return{timeUnixNano:e.endTimeUnixNano,observedTimeUnixNano:o,severityNumber:r,severityText:i,eventName:n,traceId:e.traceId,spanId:e.spanId,attributes:t&&`stringValue`in t.value?[{key:t.key,value:{stringValue:t.value.stringValue}}]:[]}});return{exported:s.length,coverage:i.coverage,payload:{resourceLogs:[{resource:i.payload.resourceSpans[0].resource,scopeLogs:[{scope:{name:`@robota-sdk/agent-session-analytics`},logRecords:s}]}]}}}function $(e,t){return[``,e,...t.length===0?[`(none)`]:t.map(e=>`${e.label} ${e.turns} turns ${e.totalTokens} tokens cost ${e.costStatus===`unknown`?`unknown`:`$${e.costUsd.toFixed(4)}`}`)]}function ve(e){let t=e.totals.costStatus===`unknown`?`unknown`:`$${e.totals.costUsd.toFixed(4)} (${e.totals.costStatus})`;return[`Personal usage — ${e.period} (${e.timezone})`,`${e.interval.startDate} → ${e.interval.endDate}`,`Sessions ${e.totals.sessions} · Turns ${e.totals.turns} · Tokens ${e.totals.totalTokens} (${e.totals.promptTokens} input / ${e.totals.completionTokens} output) · Cost ${t}`,``,`Daily usage`,...e.daily.map(e=>`${e.date}${e.partial?` (partial)`:``} ${e.totals.turns} turns ${e.totals.totalTokens} tokens`),...$(`By model`,e.byModel),...$(`By provider`,e.byProvider),...$(`By surface`,e.bySurface),...$(`By source`,e.bySource),``,`Activity`,...e.byActivity.length===0?[`(none)`]:e.byActivity.map(e=>`${e.kind}:${e.label} ${e.count} calls`),``,`Coverage: legacy ${e.coverage.legacyObservations}, corrupt ${e.coverage.corruptSessions}, unsupported ${e.coverage.unsupportedSessions}, duplicates ${e.coverage.duplicateObservations}`,`Local estimates from recorded sessions; costs are not an invoice.`].join(`
|
|
5
5
|
`)}exports.aggregateReports=s,exports.analyzeSession=o,exports.computeTimingIntervals=i,exports.createOtlpPromptEvents=_e,exports.createOtlpPromptRootTraces=Q,exports.createOtlpUsageSnapshot=me,exports.formatAggregateReport=g,exports.formatPersonalUsageReport=ve,exports.formatSingleSession=h,exports.formatUsageReport=u,exports.gapMs=t,exports.summarizePersonalUsage=G,exports.summarizeUsageBySource=x;
|
package/dist/node/index.d.cts
CHANGED
|
@@ -114,7 +114,7 @@ declare function summarizePersonalUsage(input: IPersonalUsageSnapshot): IPersona
|
|
|
114
114
|
//#endregion
|
|
115
115
|
//#region src/otlp-usage-snapshot.d.ts
|
|
116
116
|
/** A non-additive, content-free snapshot. Consumers must read the latest Gauge, not sum exports. */
|
|
117
|
-
declare function createOtlpUsageSnapshot(records: readonly IInteractiveSessionRecord[], at: Date, version: string): {
|
|
117
|
+
declare function createOtlpUsageSnapshot(records: readonly IInteractiveSessionRecord[], at: Date, version: string, serviceName: string): {
|
|
118
118
|
resourceMetrics: unknown[];
|
|
119
119
|
};
|
|
120
120
|
//#endregion
|
|
@@ -123,7 +123,7 @@ interface IOtlpSpan {
|
|
|
123
123
|
readonly traceId: string;
|
|
124
124
|
readonly spanId: string;
|
|
125
125
|
readonly parentSpanId?: string;
|
|
126
|
-
readonly name: '
|
|
126
|
+
readonly name: 'agent.prompt_execution' | 'agent.provider_call' | 'agent.tool_body';
|
|
127
127
|
readonly kind: 1;
|
|
128
128
|
readonly startTimeUnixNano: string;
|
|
129
129
|
readonly endTimeUnixNano: string;
|
|
@@ -195,14 +195,14 @@ interface IAcceptedProviderCallMetrics {
|
|
|
195
195
|
readonly familyPriceMatches: number;
|
|
196
196
|
}
|
|
197
197
|
/** Project only proven canonical prompt roots; never infer spans from legacy usage or tool events. */
|
|
198
|
-
declare function createOtlpPromptRootTraces(records: readonly IInteractiveSessionRecord[], version: string): {
|
|
198
|
+
declare function createOtlpPromptRootTraces(records: readonly IInteractiveSessionRecord[], version: string, serviceName: string): {
|
|
199
199
|
readonly payload: IOtlpPromptRootTraces;
|
|
200
200
|
readonly coverage: IPromptRootTraceCoverage;
|
|
201
201
|
readonly callMetrics: IAcceptedProviderCallMetrics;
|
|
202
202
|
};
|
|
203
203
|
//#endregion
|
|
204
204
|
//#region src/otlp-prompt-events.d.ts
|
|
205
|
-
type TEventName = '
|
|
205
|
+
type TEventName = 'agent.prompt_execution.completed' | 'agent.provider_call.completed' | 'agent.tool_body.completed';
|
|
206
206
|
interface IOtlpLogRecord {
|
|
207
207
|
readonly timeUnixNano: string;
|
|
208
208
|
readonly observedTimeUnixNano: string;
|
|
@@ -237,7 +237,7 @@ interface IOtlpPromptEvents {
|
|
|
237
237
|
}[];
|
|
238
238
|
}
|
|
239
239
|
/** Explicit local OTLP log projection of canonical prompt completion events. */
|
|
240
|
-
declare function createOtlpPromptEvents(records: readonly IInteractiveSessionRecord[], version: string, observedAt: Date): {
|
|
240
|
+
declare function createOtlpPromptEvents(records: readonly IInteractiveSessionRecord[], version: string, observedAt: Date, serviceName: string): {
|
|
241
241
|
readonly exported: number;
|
|
242
242
|
readonly coverage: IPromptRootTraceCoverage;
|
|
243
243
|
readonly payload: IOtlpPromptEvents;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../../src/types.ts","../../src/analyze.ts","../../src/usage.ts","../../src/report.ts","../../src/personal-usage.ts","../../src/otlp-usage-snapshot.ts","../../src/otlp-prompt-root-traces.ts","../../src/otlp-prompt-events.ts","../../src/personal-usage-format.ts"],"mappings":";;;;;KAWY,wBAAwB,KAClC;KAIU;UAOK;EACf,MAAM;EACN;EACA;EACA;EACA;EACA;EACA;;UAGe;EACf;IAAa;IAAa;IAAa;IAAe;;EACtD;IAAc;IAAa;IAAa;IAAgB;;EACxD;IAAqB;IAAa;IAAa;;;UAGhC;EACf;EACA;EACA;EACA;EACA,WAAW;EACX,eAAe;EACf,OAAO;;UAGQ;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;;;iBCtCc,MAAM,eAAe,MAAM,aAAa;;;;;;;;iBAkCxC,uBAAuB,kBAAkB,kBAAkB;;iBA6K3D,eAAe,QAAQ,wBAAwB;;iBAiB/C,iBAAiB,kBAAkB,yBAAyB;;;;KC9MhE,sBAAsB,KAAK;;;;;;;;;;;;;;;;;;iBAqDvB,uBAAuB,OAAO,sBAAsB;;;;;;;;iBCnEpD,kBAAkB,QAAQ;iBAiE1B,oBAAoB,QAAQ;iBA0C5B,sBAAsB,WAAW;;;UC9GhC;WACN,SAAS;WACT,KAAK;WACL,kBAAkB;WAClB;WACA;;iBAgRK,uBAAuB,OAAO,yBAAyB;;;;iBCpSvD,wBACd,kBAAkB,6BAClB,IAAI,MACJ;EACG;;;;
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../../src/types.ts","../../src/analyze.ts","../../src/usage.ts","../../src/report.ts","../../src/personal-usage.ts","../../src/otlp-usage-snapshot.ts","../../src/otlp-prompt-root-traces.ts","../../src/otlp-prompt-events.ts","../../src/personal-usage-format.ts"],"mappings":";;;;;KAWY,wBAAwB,KAClC;KAIU;UAOK;EACf,MAAM;EACN;EACA;EACA;EACA;EACA;EACA;;UAGe;EACf;IAAa;IAAa;IAAa;IAAe;;EACtD;IAAc;IAAa;IAAa;IAAgB;;EACxD;IAAqB;IAAa;IAAa;;;UAGhC;EACf;EACA;EACA;EACA;EACA,WAAW;EACX,eAAe;EACf,OAAO;;UAGQ;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;;;iBCtCc,MAAM,eAAe,MAAM,aAAa;;;;;;;;iBAkCxC,uBAAuB,kBAAkB,kBAAkB;;iBA6K3D,eAAe,QAAQ,wBAAwB;;iBAiB/C,iBAAiB,kBAAkB,yBAAyB;;;;KC9MhE,sBAAsB,KAAK;;;;;;;;;;;;;;;;;;iBAqDvB,uBAAuB,OAAO,sBAAsB;;;;;;;;iBCnEpD,kBAAkB,QAAQ;iBAiE1B,oBAAoB,QAAQ;iBA0C5B,sBAAsB,WAAW;;;UC9GhC;WACN,SAAS;WACT,KAAK;WACL,kBAAkB;WAClB;WACA;;iBAgRK,uBAAuB,OAAO,yBAAyB;;;;iBCpSvD,wBACd,kBAAkB,6BAClB,IAAI,MACJ,iBACA;EACG;;;;UCWK;WACC;WACA;WACA;WACA;WACA;WACA;WACA;WACA;aACE;aACA;eAAkB;;eAAmC;;eAAgC;;;WAEvF;aAAmB;;;UAGb;WACN;aACE;eACE;iBACE;iBACA;mBAAkB;;;;aAGtB;eACE;iBAAkB;;eAClB,gBAAgB;;;;UAKd;WACN;WACA;WACA;WACA;WACA;aACE;aACA;aACA;aACA;;WAEF;aACE;aACA;aACA;aACA;aACA;;WAEF;aACE;aACA;aACA;aACA;;;UAII;WACN;WACA;WACA;WACA;WACA;WACA;WACA;WACA;;;iBA6KK,2BACd,kBAAkB,6BAClB,iBACA;WACY,SAAS;WAAgC,UAAU;WAAmC,aAAa;;;;KClQ5G;UAKK;WACC;WACA;WACA;WACA;WACA,WAAW;WACX;WACA;WACA;aACE;aACA;eAAkB;;;;UAId;WACN;aACE;eACE;iBACE;iBACA;mBAAkB;;;;aAGtB;eACE;iBAAkB;;eAClB,qBAAqB;;;;;iBAkBpB,uBACd,kBAAkB,6BAClB,iBACA,YAAY,MACZ;WAES;WACA,UAAU;WACV,SAAS;;;;;iBCvCJ,0BAA0B,QAAQ"}
|
package/dist/node/index.d.ts
CHANGED
|
@@ -114,7 +114,7 @@ declare function summarizePersonalUsage(input: IPersonalUsageSnapshot): IPersona
|
|
|
114
114
|
//#endregion
|
|
115
115
|
//#region src/otlp-usage-snapshot.d.ts
|
|
116
116
|
/** A non-additive, content-free snapshot. Consumers must read the latest Gauge, not sum exports. */
|
|
117
|
-
declare function createOtlpUsageSnapshot(records: readonly IInteractiveSessionRecord[], at: Date, version: string): {
|
|
117
|
+
declare function createOtlpUsageSnapshot(records: readonly IInteractiveSessionRecord[], at: Date, version: string, serviceName: string): {
|
|
118
118
|
resourceMetrics: unknown[];
|
|
119
119
|
};
|
|
120
120
|
//#endregion
|
|
@@ -123,7 +123,7 @@ interface IOtlpSpan {
|
|
|
123
123
|
readonly traceId: string;
|
|
124
124
|
readonly spanId: string;
|
|
125
125
|
readonly parentSpanId?: string;
|
|
126
|
-
readonly name: '
|
|
126
|
+
readonly name: 'agent.prompt_execution' | 'agent.provider_call' | 'agent.tool_body';
|
|
127
127
|
readonly kind: 1;
|
|
128
128
|
readonly startTimeUnixNano: string;
|
|
129
129
|
readonly endTimeUnixNano: string;
|
|
@@ -195,14 +195,14 @@ interface IAcceptedProviderCallMetrics {
|
|
|
195
195
|
readonly familyPriceMatches: number;
|
|
196
196
|
}
|
|
197
197
|
/** Project only proven canonical prompt roots; never infer spans from legacy usage or tool events. */
|
|
198
|
-
declare function createOtlpPromptRootTraces(records: readonly IInteractiveSessionRecord[], version: string): {
|
|
198
|
+
declare function createOtlpPromptRootTraces(records: readonly IInteractiveSessionRecord[], version: string, serviceName: string): {
|
|
199
199
|
readonly payload: IOtlpPromptRootTraces;
|
|
200
200
|
readonly coverage: IPromptRootTraceCoverage;
|
|
201
201
|
readonly callMetrics: IAcceptedProviderCallMetrics;
|
|
202
202
|
};
|
|
203
203
|
//#endregion
|
|
204
204
|
//#region src/otlp-prompt-events.d.ts
|
|
205
|
-
type TEventName = '
|
|
205
|
+
type TEventName = 'agent.prompt_execution.completed' | 'agent.provider_call.completed' | 'agent.tool_body.completed';
|
|
206
206
|
interface IOtlpLogRecord {
|
|
207
207
|
readonly timeUnixNano: string;
|
|
208
208
|
readonly observedTimeUnixNano: string;
|
|
@@ -237,7 +237,7 @@ interface IOtlpPromptEvents {
|
|
|
237
237
|
}[];
|
|
238
238
|
}
|
|
239
239
|
/** Explicit local OTLP log projection of canonical prompt completion events. */
|
|
240
|
-
declare function createOtlpPromptEvents(records: readonly IInteractiveSessionRecord[], version: string, observedAt: Date): {
|
|
240
|
+
declare function createOtlpPromptEvents(records: readonly IInteractiveSessionRecord[], version: string, observedAt: Date, serviceName: string): {
|
|
241
241
|
readonly exported: number;
|
|
242
242
|
readonly coverage: IPromptRootTraceCoverage;
|
|
243
243
|
readonly payload: IOtlpPromptEvents;
|
package/dist/node/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/types.ts","../../src/analyze.ts","../../src/usage.ts","../../src/report.ts","../../src/personal-usage.ts","../../src/otlp-usage-snapshot.ts","../../src/otlp-prompt-root-traces.ts","../../src/otlp-prompt-events.ts","../../src/personal-usage-format.ts"],"mappings":";;;;;KAWY,wBAAwB,KAClC;KAIU;UAOK;EACf,MAAM;EACN;EACA;EACA;EACA;EACA;EACA;;UAGe;EACf;IAAa;IAAa;IAAa;IAAe;;EACtD;IAAc;IAAa;IAAa;IAAgB;;EACxD;IAAqB;IAAa;IAAa;;;UAGhC;EACf;EACA;EACA;EACA;EACA,WAAW;EACX,eAAe;EACf,OAAO;;UAGQ;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;;;iBCtCc,MAAM,eAAe,MAAM,aAAa;;;;;;;;iBAkCxC,uBAAuB,kBAAkB,kBAAkB;;iBA6K3D,eAAe,QAAQ,wBAAwB;;iBAiB/C,iBAAiB,kBAAkB,yBAAyB;;;;KC9MhE,sBAAsB,KAAK;;;;;;;;;;;;;;;;;;iBAqDvB,uBAAuB,OAAO,sBAAsB;;;;;;;;iBCnEpD,kBAAkB,QAAQ;iBAiE1B,oBAAoB,QAAQ;iBA0C5B,sBAAsB,WAAW;;;UC9GhC;WACN,SAAS;WACT,KAAK;WACL,kBAAkB;WAClB;WACA;;iBAgRK,uBAAuB,OAAO,yBAAyB;;;;iBCpSvD,wBACd,kBAAkB,6BAClB,IAAI,MACJ;EACG;;;;
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../../src/types.ts","../../src/analyze.ts","../../src/usage.ts","../../src/report.ts","../../src/personal-usage.ts","../../src/otlp-usage-snapshot.ts","../../src/otlp-prompt-root-traces.ts","../../src/otlp-prompt-events.ts","../../src/personal-usage-format.ts"],"mappings":";;;;;KAWY,wBAAwB,KAClC;KAIU;UAOK;EACf,MAAM;EACN;EACA;EACA;EACA;EACA;EACA;;UAGe;EACf;IAAa;IAAa;IAAa;IAAe;;EACtD;IAAc;IAAa;IAAa;IAAgB;;EACxD;IAAqB;IAAa;IAAa;;;UAGhC;EACf;EACA;EACA;EACA;EACA,WAAW;EACX,eAAe;EACf,OAAO;;UAGQ;EACf;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;;;iBCtCc,MAAM,eAAe,MAAM,aAAa;;;;;;;;iBAkCxC,uBAAuB,kBAAkB,kBAAkB;;iBA6K3D,eAAe,QAAQ,wBAAwB;;iBAiB/C,iBAAiB,kBAAkB,yBAAyB;;;;KC9MhE,sBAAsB,KAAK;;;;;;;;;;;;;;;;;;iBAqDvB,uBAAuB,OAAO,sBAAsB;;;;;;;;iBCnEpD,kBAAkB,QAAQ;iBAiE1B,oBAAoB,QAAQ;iBA0C5B,sBAAsB,WAAW;;;UC9GhC;WACN,SAAS;WACT,KAAK;WACL,kBAAkB;WAClB;WACA;;iBAgRK,uBAAuB,OAAO,yBAAyB;;;;iBCpSvD,wBACd,kBAAkB,6BAClB,IAAI,MACJ,iBACA;EACG;;;;UCWK;WACC;WACA;WACA;WACA;WACA;WACA;WACA;WACA;aACE;aACA;eAAkB;;eAAmC;;eAAgC;;;WAEvF;aAAmB;;;UAGb;WACN;aACE;eACE;iBACE;iBACA;mBAAkB;;;;aAGtB;eACE;iBAAkB;;eAClB,gBAAgB;;;;UAKd;WACN;WACA;WACA;WACA;WACA;aACE;aACA;aACA;aACA;;WAEF;aACE;aACA;aACA;aACA;aACA;;WAEF;aACE;aACA;aACA;aACA;;;UAII;WACN;WACA;WACA;WACA;WACA;WACA;WACA;WACA;;;iBA6KK,2BACd,kBAAkB,6BAClB,iBACA;WACY,SAAS;WAAgC,UAAU;WAAmC,aAAa;;;;KClQ5G;UAKK;WACC;WACA;WACA;WACA;WACA,WAAW;WACX;WACA;WACA;aACE;aACA;eAAkB;;;;UAId;WACN;aACE;eACE;iBACE;iBACA;mBAAkB;;;;aAGtB;eACE;iBAAkB;;eAClB,qBAAqB;;;;;iBAkBpB,uBACd,kBAAkB,6BAClB,iBACA,YAAY,MACZ;WAES;WACA,UAAU;WACV,SAAS;;;;;iBCvCJ,0BAA0B,QAAQ"}
|
package/dist/node/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import{MODEL_PRICES as e,calculateModelCost as t}from"@robota-sdk/agent-core";function n(e,t){return new Date(t).getTime()-new Date(e).getTime()}function r(e){return new Date(e).toISOString()}function i(e,t,i,a,o,s){return{kind:e,fromType:t,toType:i,fromTimestamp:r(a),toTimestamp:r(o),durationMs:n(a,o),turnIndex:s}}function a(e){let t=[],n=0,r=0;for(;r<e.length;){let a=e[r];if(!a){r++;continue}if(a.category===`chat`&&a.type===`user`){n++;let o=a.timestamp,s=!1,c=null,l=r+1;for(;l<e.length;){let r=e[l];if(!r){l++;continue}if(r.category===`chat`&&r.type===`user`)break;if(r.category===`event`&&r.type===`tool-start`){s?c!==null&&t.push(i(`llm_between_tools`,`tool-end`,`tool-start`,c,r.timestamp,n)):(t.push(i(`user_to_first_tool`,`user`,`tool-start`,o,r.timestamp,n)),s=!0),c=null,l++;continue}if(r.category===`event`&&r.type===`tool-end`){let a=e[l-1];a&&a.category===`event`&&a.type===`tool-start`&&t.push(i(`tool_exec`,`tool-start`,`tool-end`,a.timestamp,r.timestamp,n)),c=r.timestamp,l++;continue}if(r.category===`event`&&r.type===`tool-summary`){c!==null&&t.push(i(`llm_final_response`,`tool-end`,`tool-summary`,c,r.timestamp,n)),l++;continue}if(r.category===`chat`&&r.type===`assistant`){s?c!==null&&t.push(i(`llm_final_response`,`tool-end`,`assistant`,c,r.timestamp,n)):t.push(i(`user_to_assistant`,`user`,`assistant`,o,r.timestamp,n)),l++;break}l++}r=l}else r++}return t}function o(e){let t=e.filter(e=>e.kind===`user_to_first_tool`||e.kind===`user_to_assistant`||e.kind===`llm_between_tools`||e.kind===`llm_final_response`),n=e.filter(e=>e.kind===`tool_exec`),r=e.filter(e=>e.kind===`user_to_assistant`),i=e=>e.length?Math.round(e.reduce((e,t)=>e+t.durationMs,0)/e.length):0,a=e=>e.length?Math.max(...e.map(e=>e.durationMs)):0;return{llmWaitMs:{avg:i(t),max:a(t),total:t.reduce((e,t)=>e+t.durationMs,0),count:t.length},toolExecMs:{avg:i(n),max:a(n),median:(e=>{if(!e.length)return 0;let t=[...e].sort((e,t)=>e.durationMs-t.durationMs),n=Math.floor(t.length/2);return t.length%2==0?Math.round(((t[n-1]?.durationMs??0)+(t[n]?.durationMs??0))/2):t[n]?.durationMs??0})(n),count:n.length},userToAssistantMs:{avg:i(r),max:a(r),count:r.length}}}function s(e){let t=a(e.history??[]),n=t.filter(e=>e.durationMs>=1e4);return{sessionId:e.id,cwd:e.cwd,createdAt:e.createdAt,totalIntervals:t.length,intervals:t,slowIntervals:n,stats:o(t)}}function c(e){let t=e.flatMap(e=>e.intervals.filter(e=>e.kind===`user_to_first_tool`||e.kind===`user_to_assistant`||e.kind===`llm_between_tools`||e.kind===`llm_final_response`)),n=e.flatMap(e=>e.intervals.filter(e=>e.kind===`tool_exec`)),r=t.length?Math.round(t.reduce((e,t)=>e+t.durationMs,0)/t.length):0,i=n.length?Math.round(n.reduce((e,t)=>e+t.durationMs,0)/n.length):0,a=0,o=``,s=0,c=``;for(let t of e)for(let e of t.intervals)e.durationMs>a&&(a=e.durationMs,o=t.sessionId,s=e.turnIndex,c=e.kind);let l=e.map(e=>e.createdAt).sort();return{sessionCount:e.length,fromDate:l[0]??``,toDate:l[l.length-1]??``,avgLlmResponseMs:r,avgToolExecMs:i,maxSingleDelayMs:a,maxSingleDelaySession:o,maxSingleDelayTurn:s,maxSingleDelayKind:c}}function l(e){return e>=1e6?`${(e/1e6).toFixed(1)}M`:e>=1e3?`${(e/1e3).toFixed(1)}K`:`${e}`}function u(e,t){return`${t?``:`~`}$${e.toFixed(4)}`}function d(e){let t=[];if(t.push(`Token usage — session ${e.sessionId}`),t.push(` total ${l(e.totalTokens)} (prompt ${l(e.promptTokens)} · completion ${l(e.completionTokens)})`),t.push(` cost ${u(e.costUsd,e.costExact)}`),e.bySource.length===0)t.push(` (no usage recorded)`);else{t.push(` by source (most tokens first):`);for(let n of e.bySource)t.push(` ${n.label.padEnd(24)} ${String(n.percentage).padStart(5)}% ${l(n.totalTokens).padStart(7)} ${u(n.costUsd,n.costExact).padStart(10)} (${n.turns} turn${n.turns===1?``:`s`})`);e.topConsumer&&t.push(` top consumer: ${e.topConsumer.label} (${e.topConsumer.percentage}%)`)}if(e.timeline.length>0){t.push(` trace (per turn, sub-turn spans):`);for(let n of e.timeline){t.push(` turn ${n.turnIndex} — ${n.label} · ${f(n.totalDurationMs)} across ${n.spans.length} op${n.spans.length===1?``:`s`}`);for(let e of n.spans)t.push(` ${e.op.padEnd(22)} ${f(e.durationMs).padStart(8)}`)}}return t.join(`
|
|
2
2
|
`)}function f(e){return e>=1e3?`${(e/1e3).toFixed(1)}s`:`${e}ms`}function p(e){return new Date(e).toLocaleString(`sv-SE`,{timeZoneName:`short`}).slice(0,16)}function m(e){return{user_to_first_tool:`user → tool-start`,user_to_assistant:`user → assistant`,tool_exec:`tool-start → tool-end`,llm_between_tools:`tool-end → tool-start`,llm_final_response:`tool-end → assistant/summary`}[e.kind]??e.kind}function h(e){let{stats:t}=e,n=t.llmWaitMs.total+t.toolExecMs.avg*t.toolExecMs.count;if(n===0)return`Verdict: No timing data available.`;let r=Math.round(t.llmWaitMs.total/n*100);return`Verdict: LLM API wait ${r}% | Code processing ${100-r}%`}function g(e){let t=[],{stats:n}=e;if(t.push(`Session: ${e.sessionId}`),t.push(`Created: ${p(e.createdAt)} | cwd: ${e.cwd}`),t.push(``),t.push(`Timing Summary:`),n.llmWaitMs.count>0&&t.push(` LLM API wait ${f(n.llmWaitMs.avg).padStart(8)} avg | ${f(n.llmWaitMs.max).padStart(8)} max`),n.toolExecMs.count>0&&t.push(` Tool execution ${f(n.toolExecMs.avg).padStart(8)} avg | ${f(n.toolExecMs.median).padStart(8)} median`),n.userToAssistantMs.count>0&&t.push(` user → assistant ${f(n.userToAssistantMs.avg).padStart(8)} avg`),n.llmWaitMs.count===0&&n.toolExecMs.count===0&&t.push(` (no intervals computed — session may have no history)`),e.slowIntervals.length>0){t.push(``),t.push(`Slow intervals (>10s):`);for(let n of e.slowIntervals)t.push(` turn ${n.turnIndex} ${m(n).padEnd(32)} ${f(n.durationMs).padStart(8)}`)}return t.push(``),t.push(h(e)),t.join(`
|
|
3
3
|
`)}function ee(e){let t=[];return t.push(`Analyzed ${e.sessionCount} sessions (${p(e.fromDate)} ~ ${p(e.toDate)})`),t.push(` Avg LLM response: ${f(e.avgLlmResponseMs)}`),t.push(` Avg tool exec: ${f(e.avgToolExecMs)}`),e.maxSingleDelayMs>0&&t.push(` Max single delay: ${f(e.maxSingleDelayMs)} (${e.maxSingleDelaySession}, turn ${e.maxSingleDelayTurn}, ${e.maxSingleDelayKind})`),t.join(`
|
|
4
|
-
`)}const _={scope:`main`,label:`main thread`};function te(e){return`${e.scope}:${e.id??``}`}function v(e){return e.label??(e.id?`${e.scope} ${e.id}`:e.scope)}function ne(e){return e.type===`usage-summary`&&typeof e.data==`object`&&e.data!==null}function re(e){if(e.type!==`span`||typeof e.data!=`object`||e.data===null)return!1;let t=e.data;return typeof t.spanId==`string`&&typeof t.op==`string`&&typeof t.durationMs==`number`}function y(e,t){return t<=0?0:Math.round(e/t*1e3)/10}function b(e){let t=new Map,n=0,r=0,i=0,a=0,o=!0,s=[],c=[],l=e=>{c.length!==0&&(s.push({turnIndex:s.length,source:e,label:v(e),spans:c,totalDurationMs:c.reduce((e,t)=>e+t.durationMs,0)}),c=[])};for(let s of e.history??[]){if(re(s)){let e=s.data;c.push({spanId:e.spanId,op:e.op,durationMs:e.durationMs});continue}if(!ne(s))continue;let e=s.data,u=e.source??_,d=te(u),f=e.promptTokens??0,p=e.completionTokens??0,m=e.totalTokens,h=e.costUsd??0;n+=f,r+=p,i+=m,a+=h,o=!1;let g=t.get(d);g?(g.promptTokens+=f,g.completionTokens+=p,g.totalTokens+=m,g.turns+=1,g.costUsd+=h,g.costExact=!1):t.set(d,{key:d,source:u,label:v(u),promptTokens:f,completionTokens:p,totalTokens:m,turns:1,percentage:0,costUsd:h,costExact:!1}),l(u)}l(_);let u=[...t.values()].map(e=>({...e,percentage:y(e.totalTokens,i)})).sort((e,t)=>t.totalTokens-e.totalTokens);return{sessionId:e.id,totalTokens:i,promptTokens:n,completionTokens:r,costUsd:a,costExact:o,bySource:u,...u[0]?{topConsumer:u[0]}:{},timeline:s}}function x(e){return typeof e==`object`&&!!e&&!Array.isArray(e)&&!(e instanceof Date)}function S(e){return typeof e==`string`&&e.length>0?e:void 0}function C(e){return typeof e==`number`&&Number.isFinite(e)&&e>=0}function w(e){return e===`unknown`||e===`estimated`||e===`exact`}function ie(e){return(e.promptTokens===void 0||C(e.promptTokens))&&(e.completionTokens===void 0||C(e.completionTokens))}function T(e){let t=e.costStatus;return w(t)?t===`unknown`?e.costUsd===void 0:C(e.costUsd):!1}function E(e){return C(e.totalTokens)&&C(e.contextUsedTokens)&&C(e.contextMaxTokens)&&C(e.contextUsedPercentage)}function D(e){return e===`cli`||e===`desktop-app`||e===`browser`||e===`remote`||e===`attach`||e===`unknown`}function O(e){if(!x(e))return;let t=e.scope;if(t!==`main`&&t!==`subagent`&&t!==`background`&&t!==`tool`&&t!==`command`&&t!==`skill`)return;let n=S(e.id),r=S(e.label);return{scope:t,...n?{id:n}:{},...r?{label:r}:{}}}function k(e){if(!x(e)||e.kind!==`exact`&&e.kind!==`estimated`||e.scope!==`turn`||!ie(e)||!T(e)||!E(e)||!w(e.costStatus))return;let t=O(e.source);return{kind:e.kind,scope:`turn`,totalTokens:e.totalTokens,contextUsedTokens:e.contextUsedTokens,contextMaxTokens:e.contextMaxTokens,contextUsedPercentage:e.contextUsedPercentage,costStatus:e.costStatus===`exact`?`estimated`:e.costStatus,...C(e.promptTokens)?{promptTokens:e.promptTokens}:{},...C(e.completionTokens)?{completionTokens:e.completionTokens}:{},...C(e.costUsd)?{costUsd:e.costUsd}:{},...t?{source:t}:{}}}function ae(e){if(!x(e))return;let t=S(e.providerId),n=S(e.modelId),{promptTokens:r,completionTokens:i,totalTokens:a,costStatus:o,costUsd:s}=e;if(!(!t||!n||!C(r)||!C(i)||!C(a)||o!==`unknown`&&o!==`estimated`||(o===`estimated`?!C(s):s!==void 0)))return{providerId:t,modelId:n,promptTokens:r,completionTokens:i,totalTokens:a,costStatus:o,...o===`estimated`&&C(s)?{costUsd:s}:{}}}function oe(e){if(!Array.isArray(e)||e.length===0)return;let t=e.map(ae);return t.every(e=>e!==void 0)?t:void 0}function A(e){if(!x(e))return;let t=S(e.usageObservationId),n=S(e.turnId),r=e.outcome;if(!t||!n||r!==`success`&&r!==`failure`&&r!==`interrupted`)return;let i=e.surface,a=O(e.source),o=k(e.usage),s=oe(e.modelShares);return{usageObservationId:t,turnId:n,outcome:r,...S(e.modelId)?{modelId:S(e.modelId)}:{},...S(e.providerId)?{providerId:S(e.providerId)}:{},...s?{modelShares:s}:{},...D(i)?{surface:i}:{},...a?{source:a}:{},...o?{usage:o}:{}}}function j(e){let t=new Date(e.timestamp);return Number.isNaN(t.getTime())?void 0:t}function M(e){let t=[],n=e.history??[],r=new Set,i=n.flatMap((e,t)=>{if(e.type!==`usage-summary`)return[];let n=k(e.data);return n?[{id:e.id,index:t,usage:n}]:[]});for(let[e,t]of n.entries()){if(t.type!==`usage-observation`)continue;let n=A(t.data);if(!n?.usage)continue;let a=JSON.stringify(n.usage),o=i.map((e,t)=>({candidate:e,index:t})).filter(({candidate:e})=>JSON.stringify(e.usage)===a).sort((t,n)=>Math.abs(t.candidate.index-e)-Math.abs(n.candidate.index-e))[0];o&&(r.add(o.candidate.id),i.splice(o.index,1))}for(let i of n){let n=j(i);if(!n)continue;let a=i.type===`usage-observation`?A(i.data):void 0;if(a){t.push({id:a.usageObservationId,sessionId:e.id,at:n,legacy:!1,observation:a});continue}if(i.type!==`usage-summary`||r.has(i.id))continue;let o=k(i.data);if(!o)continue;let s=`legacy:${e.id}:${i.id}`;t.push({id:s,sessionId:e.id,at:n,legacy:!0,observation:{usageObservationId:s,turnId:`legacy:${i.id}`,outcome:`success`,usage:o,...o.source?{source:o.source}:{},surface:`unknown`}})}return t}function se(e){let t=[];for(let n of e.history??[]){let r=n.data;if(n.type!==`tool-start`||!x(r))continue;let i=S(r.toolName),a=j(n);!i||!a||t.push({id:`tool:${e.id}:${n.id}`,sessionId:e.id,key:`tool:${i}`,label:i,kind:`tool`,at:a})}for(let n of e.skillActivationEvents??[]){if(n.status!==`started`)continue;let r=new Date(n.timestamp);Number.isNaN(r.getTime())||t.push({id:`activation:${e.id}:${n.timestamp}:${n.source}:${n.qualifiedName??n.skillName}:${n.invocation}`,sessionId:e.id,key:n.qualifiedName??`${n.source}:${n.skillName}`,label:n.qualifiedName??n.skillName,kind:n.source,at:r})}return t}function N(){return{sessions:new Set,observations:0,turns:0,promptTokens:0,completionTokens:0,totalTokens:0,costUsd:0,hasUnknownCost:!1,hasEstimatedCost:!1,unpricedTurns:0}}function P(e,t){let n=new Intl.DateTimeFormat(`en-CA`,{timeZone:t,year:`numeric`,month:`2-digit`,day:`2-digit`}).formatToParts(e),r=e=>n.find(t=>t.type===e)?.value??``;return`${r(`year`)}-${r(`month`)}-${r(`day`)}`}function ce(e,t,n){let[r,i,a]=P(e,t).split(`-`).map(Number),o=new Date(Date.UTC(r,i-1,a));return Array.from({length:n},(e,t)=>{let r=new Date(o);return r.setUTCDate(r.getUTCDate()-(n-t-1)),r.toISOString().slice(0,10)})}function F(e){let t=new Map;for(let n of e){let e=t.get(n.key);t.set(n.key,{item:n,count:(e?.count??0)+1})}return[...t.values()].map(({item:e,count:t})=>({key:e.key,label:e.label,kind:e.kind,count:t})).sort((e,t)=>t.count-e.count||e.key.localeCompare(t.key))}function I(e,t){let n=t.observation.usage;e.sessions.add(t.sessionId),e.observations+=1;let r=!t.legacy&&t.observation.source?.scope!==`tool`;r&&(e.turns+=1),e.promptTokens+=n?.promptTokens??0,e.completionTokens+=n?.completionTokens??0,e.totalTokens+=n?.totalTokens??0,e.costUsd+=n?.costUsd??0,n?.costStatus===`estimated`?e.hasEstimatedCost=!0:(e.hasUnknownCost=!0,r&&(e.unpricedTurns+=1))}function L(e,t){let n=[];for(let r of e){let e=r.observation.modelShares;if(e===void 0){n.push(r);continue}let i=new Map;for(let n of e){let e=t(n),a=i.get(e)?.observation.usage,o=r.observation.usage,s=n.costStatus===`unknown`||a?.costStatus===`unknown`?`unknown`:`estimated`;i.set(e,{...r,observation:{...r.observation,providerId:n.providerId,modelId:n.modelId,usage:{kind:o?.kind??`estimated`,scope:`turn`,contextUsedTokens:o?.contextUsedTokens??0,contextMaxTokens:o?.contextMaxTokens??0,contextUsedPercentage:o?.contextUsedPercentage??0,promptTokens:(a?.promptTokens??0)+n.promptTokens,completionTokens:(a?.completionTokens??0)+n.completionTokens,totalTokens:(a?.totalTokens??0)+n.totalTokens,costStatus:s,...s===`estimated`&&{costUsd:(a?.costUsd??0)+(n.costUsd??0)}}}})}n.push(...i.values())}return z(n,e=>t(e.observation))}function R(e){return{sessions:e.sessions.size,turns:e.turns,promptTokens:e.promptTokens,completionTokens:e.completionTokens,totalTokens:e.totalTokens,costUsd:e.costUsd,costStatus:e.hasEstimatedCost?`estimated`:`unknown`,...e.unpricedTurns>0?{unpricedTurns:e.unpricedTurns}:{}}}function z(e,t){let n=new Map;for(let r of e){let e=t(r),i=n.get(e)??N();I(i,r),n.set(e,i)}return[...n.entries()].map(([e,t])=>({key:e,label:e,frozen:R(t),sessionIds:[...t.sessions].sort()})).map(({key:e,label:t,frozen:n,sessionIds:r})=>({key:e,label:t,turns:n.turns,promptTokens:n.promptTokens,completionTokens:n.completionTokens,totalTokens:n.totalTokens,costUsd:n.costUsd,costStatus:n.costStatus,sessionIds:r})).sort((e,t)=>t.totalTokens-e.totalTokens||e.key.localeCompare(t.key))}function B(e){return e?e.id?`${e.scope}:${e.id}`:e.scope:`unknown`}function V(e,t,n){return e.getTime()<=t.now.getTime()&&n.has(P(e,t.request.timezone))}function H(e,t){let n=[],r=[],i=new Set,a=new Set,o=0,s=0;for(let c of e.records){for(let r of M(c))if(V(r.at,e,t)){if(i.has(r.id)){o+=1;continue}i.add(r.id),n.push(r),r.legacy&&(s+=1)}for(let n of se(c))!V(n.at,e,t)||a.has(n.id)||(a.add(n.id),r.push(n))}return{observations:n,activities:r,duplicateObservations:o,legacyObservations:s}}function U(e){let t=new Map,n=(e,n)=>{let r=n.getTime(),i=t.get(e);(i===void 0||r<i)&&t.set(e,r)};for(let t of e.observations)n(t.sessionId,t.at);for(let t of e.activities)n(t.sessionId,t.at);let r={};for(let[e,n]of t)r[e]=new Date(n).toISOString();return r}function W(e,t,n){let r=N(),i=new Map(t.map(e=>[e,N()]));for(let t of n.observations)I(r,t),I(i.get(P(t.at,e.request.timezone)),t);for(let t of n.activities)r.sessions.add(t.sessionId),i.get(P(t.at,e.request.timezone))?.sessions.add(t.sessionId);return{totals:r,byDay:i}}function le(e){let t=e.request.period===`30d`?30:7,n=ce(e.now,e.request.timezone,t),r=H(e,new Set(n)),{totals:i,byDay:a}=W(e,n,r),o=r.observations;return{schemaVersion:1,generatedAt:e.now.toISOString(),period:e.request.period,timezone:e.request.timezone,interval:{startDate:n[0],endDate:n.at(-1)},totals:R(i),daily:n.map((e,t)=>({date:e,partial:t===n.length-1,totals:R(a.get(e)),sessionIds:[...a.get(e).sessions].sort()})),byModel:L(o,e=>e.modelId??`unknown`),byProvider:L(o,e=>e.providerId??`unknown`),bySurface:z(o,e=>e.observation.surface??`unknown`),bySource:z(o,e=>B(e.observation.source)),byActivity:F(r.activities),sessionIds:[...i.sessions].sort(),sessionFirstSeen:U(r),coverage:{validSessions:e.records.length,corruptSessions:e.corruptSessionIds?.length??0,unsupportedSessions:e.unsupportedSessionIds?.length??0,duplicateObservations:r.duplicateObservations,legacyObservations:r.legacyObservations,unknownModelObservations:o.filter(e=>!e.observation.modelId&&!e.observation.modelShares).length,unknownProviderObservations:o.filter(e=>!e.observation.providerId&&!e.observation.modelShares).length,unknownSurfaceObservations:o.filter(e=>!e.observation.surface||e.observation.surface===`unknown`).length,corruptSessionIds:[...e.corruptSessionIds??[]].sort(),unsupportedSessionIds:[...e.unsupportedSessionIds??[]].sort()}}}const ue=(1n<<64n)-1n,G=/^(?!0{32}$)[0-9a-f]{32}$/,K=/^(?!0{16}$)[0-9a-f]{16}$/,de=[`promptExecutionStartedAt`,`promptExecutionEndedAt`,`promptExecutionOutcome`,`promptExecutionTraceId`,`promptExecutionSpanId`];function q(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function J(e,t){e.set(t,(e.get(t)??0)+1)}function Y(e){if(typeof e!=`string`)return;let t=new Date(e);if(Number.isNaN(t.getTime())||t.toISOString()!==e)return;let n=BigInt(t.getTime())*1000000n;return n>=0n&&n<=ue?n:void 0}function fe(e){let t=Y(e.promptExecutionStartedAt),n=Y(e.promptExecutionEndedAt),r=e.promptExecutionOutcome,i=e.promptExecutionTraceId,a=e.promptExecutionSpanId;if(!(t===void 0||n===void 0||t>n||r!==`success`&&r!==`failure`&&r!==`interrupted`||typeof i!=`string`||!G.test(i)||typeof a!=`string`||!K.test(a)||typeof e.usageObservationId!=`string`||e.usageObservationId.length===0||e.turnId!==e.usageObservationId||e.outcome!==`success`&&e.outcome!==`failure`&&e.outcome!==`interrupted`))return{traceId:i,spanId:a,name:`robota.prompt_execution`,kind:1,startTimeUnixNano:String(t),endTimeUnixNano:String(n),attributes:[{key:`robota.prompt.outcome`,value:{stringValue:r}}],status:{code:r===`success`?1:r===`failure`?2:0}}}function pe(e,t){if(!q(e))return;let n=e.traceId,r=e.parentSpanId,i=e.spanId,a=Y(e.startedAt),o=Y(e.endedAt),s=e.outcome;if(!(typeof n!=`string`||!G.test(n)||typeof r!=`string`||!K.test(r)||typeof i!=`string`||!K.test(i)||a===void 0||o===void 0||a>o||s!==`success`&&s!==`failure`&&s!==`interrupted`||t===`provider`&&(!Number.isSafeInteger(e.round)||e.round<1)))return{traceId:n,parentSpanId:r,spanId:i,name:t===`provider`?`robota.provider_call`:`robota.tool_body`,kind:1,startTimeUnixNano:String(a),endTimeUnixNano:String(o),attributes:[{key:t===`provider`?`robota.provider.outcome`:`robota.tool.outcome`,value:{stringValue:s}}],status:{code:s===`success`?1:s===`failure`?2:0}}}function me(e){if(!q(e))return;let t=e.traceId,n=e.spanId;return typeof t==`string`&&G.test(t)&&typeof n==`string`&&K.test(n)?`${t}:${n}`:void 0}function X(e){return typeof e==`number`&&Number.isSafeInteger(e)&&e>=0}function he(n,r,i,a){if(!q(r)||r.disposition===void 0)return i.legacy+=1,n;if(r.disposition!==`invoked`)return i.invalid+=1,n;a.invoked+=1;let o=r.usageProvenance;if(o===`partial`)return i.partial+=1,a.unknownCost+=1,n;if(o===`absent`||o===void 0)return i.absent+=1,a.unknownCost+=1,n;let s=r.promptTokens,c=r.completionTokens,l=r.totalTokens;if(o!==`complete`||!X(s)||!X(c)||!Number.isSafeInteger(s+c)||l!==s+c)return i.invalid+=1,a.unknownCost+=1,n;a.completeUsage+=1,a.inputTokens+=s,a.outputTokens+=c;let u=[...n.attributes,{key:`robota.provider.usage.input_tokens`,value:{intValue:String(s)}},{key:`robota.provider.usage.output_tokens`,value:{intValue:String(c)}}],d=r.modelId,f=typeof d==`string`&&d.length>0&&d.length<=128&&[...d].every(e=>e.charCodeAt(0)>=32)?t(d,s,c):void 0;return f===void 0||!Number.isFinite(f)||f<0?a.unknownCost+=1:(a.estimatedCostUsd+=f,typeof d==`string`&&Object.hasOwn(e,d)?a.exactPriceMatches+=1:a.familyPriceMatches+=1,u.push({key:`robota.provider.cost.usd.estimated`,value:{doubleValue:f}})),{...n,attributes:u}}function Z(e,t){let n=[],r=new Map,i=new Map;for(let t of e)for(let e of t.history??[]){if(e.type!==`usage-observation`)continue;let a=e.data,o=q(a)?a.usageObservationId:void 0,s=q(a)?a.promptExecutionTraceId:void 0,c=typeof o==`string`&&o.length>0?JSON.stringify([t.id,o]):void 0,l=typeof s==`string`&&G.test(s)?s:void 0;c&&J(r,c),l&&J(i,l),n.push({record:t,data:a,observationKey:c,traceId:l})}let a=[],o=new Map,s=0,c=0,l=0;for(let e of n){if(e.observationKey&&(r.get(e.observationKey)??0)>1||e.traceId&&(i.get(e.traceId)??0)>1){l+=1;continue}let t=e.data;if(!q(t)){c+=1;continue}if(de.every(e=>t[e]===void 0)){s+=1;continue}let n=fe(t);if(!n){c+=1;continue}a.push(n);let u=o.get(e.record)??new Map;u.set(n.traceId,n),o.set(e.record,u)}let u=[],d=new Map;for(let t of e)for(let e of t.history??[]){let n=e.type===`provider-call-trace`?`provider`:e.type===`tool-body-trace`?`tool`:void 0;if(!n)continue;let r=me(e.data),i=pe(e.data,n);r&&J(d,r),u.push({record:t,span:i,identity:r,kind:n,data:e.data})}let f={provider:{exported:0,invalid:0,orphaned:0,duplicate:0},tool:{exported:0,invalid:0,orphaned:0,duplicate:0}},p={legacy:0,invalid:0,partial:0,absent:0,nonInvoked:0},m={invoked:0,completeUsage:0,inputTokens:0,outputTokens:0,estimatedCostUsd:0,unknownCost:0,exactPriceMatches:0,familyPriceMatches:0};for(let e of u){let{span:t}=e,n=f[e.kind];if(e.identity&&(d.get(e.identity)??0)>1){n.duplicate+=1;continue}if(!t){n.invalid+=1;continue}let r=o.get(e.record)?.get(t.traceId);if(!r||t.parentSpanId!==r.spanId||t.spanId===r.spanId){n.orphaned+=1;continue}if(BigInt(t.startTimeUnixNano)<BigInt(r.startTimeUnixNano)||BigInt(t.endTimeUnixNano)>BigInt(r.endTimeUnixNano)){n.invalid+=1;continue}if(e.kind===`provider`&&q(e.data)&&(e.data.disposition===`cache-hit`||e.data.disposition===`preflight-refused`)){p.nonInvoked+=1,(e.data.promptTokens!==void 0||e.data.completionTokens!==void 0||e.data.totalTokens!==void 0||e.data.usageProvenance===`complete`)&&(p.invalid+=1);continue}a.push(e.kind===`provider`?he(t,e.data,p,m):t),n.exported+=1}return{payload:{resourceSpans:a.length?[{resource:{attributes:[{key:`service.name`,value:{stringValue:`robota`}},{key:`service.version`,value:{stringValue:t}}]},scopeSpans:[{scope:{name:`@robota-sdk/agent-session-analytics`},spans:a}]}]:[]},coverage:{exported:a.length-f.provider.exported-f.tool.exported,missing:s,invalid:c,duplicate:l,providerChildren:f.provider,providerUsage:p,toolChildren:f.tool},callMetrics:m}}function ge(e,t,n){let r=new Set,i=0,a=0,o=0,s=0,c=0,l=0,u=0,d=0;for(let t of e)for(let e of M(t)){if(r.has(e.id))continue;r.add(e.id),e.legacy||(i+=1);let t=e.observation.usage;if(!t){u+=1,c+=1;continue}a+=t.totalTokens,o+=t.promptTokens??0,s+=t.completionTokens??0,(t.promptTokens===void 0||t.completionTokens===void 0)&&(c+=1),t.costStatus===`unknown`||t.costUsd===void 0?u+=1:(l+=t.costUsd,t.costStatus===`estimated`&&(d+=1))}let f=Z(e,n),p=f.callMetrics,m=String(BigInt(t.getTime())*1000000n),h=(e,t,n)=>({name:e,unit:t,gauge:{dataPoints:[{timeUnixNano:m,asDouble:n}]}});return{resourceMetrics:[{resource:{attributes:[{key:`service.name`,value:{stringValue:`robota`}},{key:`service.version`,value:{stringValue:n}}]},scopeMetrics:[{scope:{name:`@robota-sdk/agent-session-analytics`},metrics:[h(`robota.session.count`,`{session}`,e.length),h(`robota.turn.count`,`{turn}`,i),h(`robota.token.total`,`{token}`,a),h(`robota.token.input.known`,`{token}`,o),h(`robota.token.output.known`,`{token}`,s),h(`robota.token.split_unknown_observations`,`{observation}`,c),h(`robota.cost.usd.known`,`USD`,l),h(`robota.cost.unknown_observations`,`{observation}`,u),h(`robota.cost.estimated_observations`,`{observation}`,d),h(`robota.provider_call.count`,`{call}`,p.invoked),h(`robota.provider_call.usage.complete_count`,`{call}`,p.completeUsage),h(`robota.provider_call.token.input.known`,`{token}`,p.inputTokens),h(`robota.provider_call.token.output.known`,`{token}`,p.outputTokens),h(`robota.provider_call.cost.usd.estimated`,`USD`,p.estimatedCostUsd),h(`robota.provider_call.cost.unknown_count`,`{call}`,p.unknownCost),h(`robota.provider_call.usage.partial_count`,`{call}`,f.coverage.providerUsage.partial),h(`robota.provider_call.usage.invalid_count`,`{call}`,f.coverage.providerUsage.invalid),h(`robota.provider_call.usage.legacy_count`,`{call}`,f.coverage.providerUsage.legacy),h(`robota.provider_call.price.exact_id_count`,`{call}`,p.exactPriceMatches),h(`robota.provider_call.price.family_fallback_count`,`{call}`,p.familyPriceMatches)]}]}]}}const _e=(1n<<64n)-1n;function Q(e){let t=e.getTime();if(!Number.isSafeInteger(t)||t<0)throw RangeError(`OTLP log observation time must be a valid post-epoch date.`);let n=BigInt(t)*1000000n;if(n>_e)throw RangeError(`OTLP log observation time is out of range.`);return String(n)}function ve(e,t,n){let r=Z(e,t),i=r.payload.resourceSpans[0]?.scopeSpans[0]?.spans??[];if(i.length===0)return{exported:0,coverage:r.coverage,payload:{resourceLogs:[]}};let a=Q(n),o=i.map(e=>{let t=e.attributes.find(e=>e.key===`robota.prompt.outcome`||e.key===`robota.provider.outcome`||e.key===`robota.tool.outcome`),n=e.name===`robota.prompt_execution`?`robota.prompt_execution.completed`:e.name===`robota.provider_call`?`robota.provider_call.completed`:`robota.tool_body.completed`,r=e.status.code===1?9:e.status.code===2?17:13,i=r===9?`INFO`:r===17?`ERROR`:`WARN`;return{timeUnixNano:e.endTimeUnixNano,observedTimeUnixNano:a,severityNumber:r,severityText:i,eventName:n,traceId:e.traceId,spanId:e.spanId,attributes:t&&`stringValue`in t.value?[{key:t.key,value:{stringValue:t.value.stringValue}}]:[]}});return{exported:o.length,coverage:r.coverage,payload:{resourceLogs:[{resource:r.payload.resourceSpans[0].resource,scopeLogs:[{scope:{name:`@robota-sdk/agent-session-analytics`},logRecords:o}]}]}}}function $(e,t){return[``,e,...t.length===0?[`(none)`]:t.map(e=>`${e.label} ${e.turns} turns ${e.totalTokens} tokens cost ${e.costStatus===`unknown`?`unknown`:`$${e.costUsd.toFixed(4)}`}`)]}function ye(e){let t=e.totals.costStatus===`unknown`?`unknown`:`$${e.totals.costUsd.toFixed(4)} (${e.totals.costStatus})`;return[`Personal usage — ${e.period} (${e.timezone})`,`${e.interval.startDate} → ${e.interval.endDate}`,`Sessions ${e.totals.sessions} · Turns ${e.totals.turns} · Tokens ${e.totals.totalTokens} (${e.totals.promptTokens} input / ${e.totals.completionTokens} output) · Cost ${t}`,``,`Daily usage`,...e.daily.map(e=>`${e.date}${e.partial?` (partial)`:``} ${e.totals.turns} turns ${e.totals.totalTokens} tokens`),...$(`By model`,e.byModel),...$(`By provider`,e.byProvider),...$(`By surface`,e.bySurface),...$(`By source`,e.bySource),``,`Activity`,...e.byActivity.length===0?[`(none)`]:e.byActivity.map(e=>`${e.kind}:${e.label} ${e.count} calls`),``,`Coverage: legacy ${e.coverage.legacyObservations}, corrupt ${e.coverage.corruptSessions}, unsupported ${e.coverage.unsupportedSessions}, duplicates ${e.coverage.duplicateObservations}`,`Local estimates from recorded sessions; costs are not an invoice.`].join(`
|
|
4
|
+
`)}const _={scope:`main`,label:`main thread`};function te(e){return`${e.scope}:${e.id??``}`}function v(e){return e.label??(e.id?`${e.scope} ${e.id}`:e.scope)}function ne(e){return e.type===`usage-summary`&&typeof e.data==`object`&&e.data!==null}function re(e){if(e.type!==`span`||typeof e.data!=`object`||e.data===null)return!1;let t=e.data;return typeof t.spanId==`string`&&typeof t.op==`string`&&typeof t.durationMs==`number`}function y(e,t){return t<=0?0:Math.round(e/t*1e3)/10}function b(e){let t=new Map,n=0,r=0,i=0,a=0,o=!0,s=[],c=[],l=e=>{c.length!==0&&(s.push({turnIndex:s.length,source:e,label:v(e),spans:c,totalDurationMs:c.reduce((e,t)=>e+t.durationMs,0)}),c=[])};for(let s of e.history??[]){if(re(s)){let e=s.data;c.push({spanId:e.spanId,op:e.op,durationMs:e.durationMs});continue}if(!ne(s))continue;let e=s.data,u=e.source??_,d=te(u),f=e.promptTokens??0,p=e.completionTokens??0,m=e.totalTokens,h=e.costUsd??0;n+=f,r+=p,i+=m,a+=h,o=!1;let g=t.get(d);g?(g.promptTokens+=f,g.completionTokens+=p,g.totalTokens+=m,g.turns+=1,g.costUsd+=h,g.costExact=!1):t.set(d,{key:d,source:u,label:v(u),promptTokens:f,completionTokens:p,totalTokens:m,turns:1,percentage:0,costUsd:h,costExact:!1}),l(u)}l(_);let u=[...t.values()].map(e=>({...e,percentage:y(e.totalTokens,i)})).sort((e,t)=>t.totalTokens-e.totalTokens);return{sessionId:e.id,totalTokens:i,promptTokens:n,completionTokens:r,costUsd:a,costExact:o,bySource:u,...u[0]?{topConsumer:u[0]}:{},timeline:s}}function x(e){return typeof e==`object`&&!!e&&!Array.isArray(e)&&!(e instanceof Date)}function S(e){return typeof e==`string`&&e.length>0?e:void 0}function C(e){return typeof e==`number`&&Number.isFinite(e)&&e>=0}function w(e){return e===`unknown`||e===`estimated`||e===`exact`}function ie(e){return(e.promptTokens===void 0||C(e.promptTokens))&&(e.completionTokens===void 0||C(e.completionTokens))}function T(e){let t=e.costStatus;return w(t)?t===`unknown`?e.costUsd===void 0:C(e.costUsd):!1}function E(e){return C(e.totalTokens)&&C(e.contextUsedTokens)&&C(e.contextMaxTokens)&&C(e.contextUsedPercentage)}function D(e){return e===`cli`||e===`desktop-app`||e===`browser`||e===`remote`||e===`attach`||e===`unknown`}function O(e){if(!x(e))return;let t=e.scope;if(t!==`main`&&t!==`subagent`&&t!==`background`&&t!==`tool`&&t!==`command`&&t!==`skill`)return;let n=S(e.id),r=S(e.label);return{scope:t,...n?{id:n}:{},...r?{label:r}:{}}}function k(e){if(!x(e)||e.kind!==`exact`&&e.kind!==`estimated`||e.scope!==`turn`||!ie(e)||!T(e)||!E(e)||!w(e.costStatus))return;let t=O(e.source);return{kind:e.kind,scope:`turn`,totalTokens:e.totalTokens,contextUsedTokens:e.contextUsedTokens,contextMaxTokens:e.contextMaxTokens,contextUsedPercentage:e.contextUsedPercentage,costStatus:e.costStatus===`exact`?`estimated`:e.costStatus,...C(e.promptTokens)?{promptTokens:e.promptTokens}:{},...C(e.completionTokens)?{completionTokens:e.completionTokens}:{},...C(e.costUsd)?{costUsd:e.costUsd}:{},...t?{source:t}:{}}}function ae(e){if(!x(e))return;let t=S(e.providerId),n=S(e.modelId),{promptTokens:r,completionTokens:i,totalTokens:a,costStatus:o,costUsd:s}=e;if(!(!t||!n||!C(r)||!C(i)||!C(a)||o!==`unknown`&&o!==`estimated`||(o===`estimated`?!C(s):s!==void 0)))return{providerId:t,modelId:n,promptTokens:r,completionTokens:i,totalTokens:a,costStatus:o,...o===`estimated`&&C(s)?{costUsd:s}:{}}}function oe(e){if(!Array.isArray(e)||e.length===0)return;let t=e.map(ae);return t.every(e=>e!==void 0)?t:void 0}function A(e){if(!x(e))return;let t=S(e.usageObservationId),n=S(e.turnId),r=e.outcome;if(!t||!n||r!==`success`&&r!==`failure`&&r!==`interrupted`)return;let i=e.surface,a=O(e.source),o=k(e.usage),s=oe(e.modelShares);return{usageObservationId:t,turnId:n,outcome:r,...S(e.modelId)?{modelId:S(e.modelId)}:{},...S(e.providerId)?{providerId:S(e.providerId)}:{},...s?{modelShares:s}:{},...D(i)?{surface:i}:{},...a?{source:a}:{},...o?{usage:o}:{}}}function j(e){let t=new Date(e.timestamp);return Number.isNaN(t.getTime())?void 0:t}function M(e){let t=[],n=e.history??[],r=new Set,i=n.flatMap((e,t)=>{if(e.type!==`usage-summary`)return[];let n=k(e.data);return n?[{id:e.id,index:t,usage:n}]:[]});for(let[e,t]of n.entries()){if(t.type!==`usage-observation`)continue;let n=A(t.data);if(!n?.usage)continue;let a=JSON.stringify(n.usage),o=i.map((e,t)=>({candidate:e,index:t})).filter(({candidate:e})=>JSON.stringify(e.usage)===a).sort((t,n)=>Math.abs(t.candidate.index-e)-Math.abs(n.candidate.index-e))[0];o&&(r.add(o.candidate.id),i.splice(o.index,1))}for(let i of n){let n=j(i);if(!n)continue;let a=i.type===`usage-observation`?A(i.data):void 0;if(a){t.push({id:a.usageObservationId,sessionId:e.id,at:n,legacy:!1,observation:a});continue}if(i.type!==`usage-summary`||r.has(i.id))continue;let o=k(i.data);if(!o)continue;let s=`legacy:${e.id}:${i.id}`;t.push({id:s,sessionId:e.id,at:n,legacy:!0,observation:{usageObservationId:s,turnId:`legacy:${i.id}`,outcome:`success`,usage:o,...o.source?{source:o.source}:{},surface:`unknown`}})}return t}function se(e){let t=[];for(let n of e.history??[]){let r=n.data;if(n.type!==`tool-start`||!x(r))continue;let i=S(r.toolName),a=j(n);!i||!a||t.push({id:`tool:${e.id}:${n.id}`,sessionId:e.id,key:`tool:${i}`,label:i,kind:`tool`,at:a})}for(let n of e.skillActivationEvents??[]){if(n.status!==`started`)continue;let r=new Date(n.timestamp);Number.isNaN(r.getTime())||t.push({id:`activation:${e.id}:${n.timestamp}:${n.source}:${n.qualifiedName??n.skillName}:${n.invocation}`,sessionId:e.id,key:n.qualifiedName??`${n.source}:${n.skillName}`,label:n.qualifiedName??n.skillName,kind:n.source,at:r})}return t}function N(){return{sessions:new Set,observations:0,turns:0,promptTokens:0,completionTokens:0,totalTokens:0,costUsd:0,hasUnknownCost:!1,hasEstimatedCost:!1,unpricedTurns:0}}function P(e,t){let n=new Intl.DateTimeFormat(`en-CA`,{timeZone:t,year:`numeric`,month:`2-digit`,day:`2-digit`}).formatToParts(e),r=e=>n.find(t=>t.type===e)?.value??``;return`${r(`year`)}-${r(`month`)}-${r(`day`)}`}function ce(e,t,n){let[r,i,a]=P(e,t).split(`-`).map(Number),o=new Date(Date.UTC(r,i-1,a));return Array.from({length:n},(e,t)=>{let r=new Date(o);return r.setUTCDate(r.getUTCDate()-(n-t-1)),r.toISOString().slice(0,10)})}function F(e){let t=new Map;for(let n of e){let e=t.get(n.key);t.set(n.key,{item:n,count:(e?.count??0)+1})}return[...t.values()].map(({item:e,count:t})=>({key:e.key,label:e.label,kind:e.kind,count:t})).sort((e,t)=>t.count-e.count||e.key.localeCompare(t.key))}function I(e,t){let n=t.observation.usage;e.sessions.add(t.sessionId),e.observations+=1;let r=!t.legacy&&t.observation.source?.scope!==`tool`;r&&(e.turns+=1),e.promptTokens+=n?.promptTokens??0,e.completionTokens+=n?.completionTokens??0,e.totalTokens+=n?.totalTokens??0,e.costUsd+=n?.costUsd??0,n?.costStatus===`estimated`?e.hasEstimatedCost=!0:(e.hasUnknownCost=!0,r&&(e.unpricedTurns+=1))}function L(e,t){let n=[];for(let r of e){let e=r.observation.modelShares;if(e===void 0){n.push(r);continue}let i=new Map;for(let n of e){let e=t(n),a=i.get(e)?.observation.usage,o=r.observation.usage,s=n.costStatus===`unknown`||a?.costStatus===`unknown`?`unknown`:`estimated`;i.set(e,{...r,observation:{...r.observation,providerId:n.providerId,modelId:n.modelId,usage:{kind:o?.kind??`estimated`,scope:`turn`,contextUsedTokens:o?.contextUsedTokens??0,contextMaxTokens:o?.contextMaxTokens??0,contextUsedPercentage:o?.contextUsedPercentage??0,promptTokens:(a?.promptTokens??0)+n.promptTokens,completionTokens:(a?.completionTokens??0)+n.completionTokens,totalTokens:(a?.totalTokens??0)+n.totalTokens,costStatus:s,...s===`estimated`&&{costUsd:(a?.costUsd??0)+(n.costUsd??0)}}}})}n.push(...i.values())}return z(n,e=>t(e.observation))}function R(e){return{sessions:e.sessions.size,turns:e.turns,promptTokens:e.promptTokens,completionTokens:e.completionTokens,totalTokens:e.totalTokens,costUsd:e.costUsd,costStatus:e.hasEstimatedCost?`estimated`:`unknown`,...e.unpricedTurns>0?{unpricedTurns:e.unpricedTurns}:{}}}function z(e,t){let n=new Map;for(let r of e){let e=t(r),i=n.get(e)??N();I(i,r),n.set(e,i)}return[...n.entries()].map(([e,t])=>({key:e,label:e,frozen:R(t),sessionIds:[...t.sessions].sort()})).map(({key:e,label:t,frozen:n,sessionIds:r})=>({key:e,label:t,turns:n.turns,promptTokens:n.promptTokens,completionTokens:n.completionTokens,totalTokens:n.totalTokens,costUsd:n.costUsd,costStatus:n.costStatus,sessionIds:r})).sort((e,t)=>t.totalTokens-e.totalTokens||e.key.localeCompare(t.key))}function B(e){return e?e.id?`${e.scope}:${e.id}`:e.scope:`unknown`}function V(e,t,n){return e.getTime()<=t.now.getTime()&&n.has(P(e,t.request.timezone))}function H(e,t){let n=[],r=[],i=new Set,a=new Set,o=0,s=0;for(let c of e.records){for(let r of M(c))if(V(r.at,e,t)){if(i.has(r.id)){o+=1;continue}i.add(r.id),n.push(r),r.legacy&&(s+=1)}for(let n of se(c))!V(n.at,e,t)||a.has(n.id)||(a.add(n.id),r.push(n))}return{observations:n,activities:r,duplicateObservations:o,legacyObservations:s}}function U(e){let t=new Map,n=(e,n)=>{let r=n.getTime(),i=t.get(e);(i===void 0||r<i)&&t.set(e,r)};for(let t of e.observations)n(t.sessionId,t.at);for(let t of e.activities)n(t.sessionId,t.at);let r={};for(let[e,n]of t)r[e]=new Date(n).toISOString();return r}function W(e,t,n){let r=N(),i=new Map(t.map(e=>[e,N()]));for(let t of n.observations)I(r,t),I(i.get(P(t.at,e.request.timezone)),t);for(let t of n.activities)r.sessions.add(t.sessionId),i.get(P(t.at,e.request.timezone))?.sessions.add(t.sessionId);return{totals:r,byDay:i}}function le(e){let t=e.request.period===`30d`?30:7,n=ce(e.now,e.request.timezone,t),r=H(e,new Set(n)),{totals:i,byDay:a}=W(e,n,r),o=r.observations;return{schemaVersion:1,generatedAt:e.now.toISOString(),period:e.request.period,timezone:e.request.timezone,interval:{startDate:n[0],endDate:n.at(-1)},totals:R(i),daily:n.map((e,t)=>({date:e,partial:t===n.length-1,totals:R(a.get(e)),sessionIds:[...a.get(e).sessions].sort()})),byModel:L(o,e=>e.modelId??`unknown`),byProvider:L(o,e=>e.providerId??`unknown`),bySurface:z(o,e=>e.observation.surface??`unknown`),bySource:z(o,e=>B(e.observation.source)),byActivity:F(r.activities),sessionIds:[...i.sessions].sort(),sessionFirstSeen:U(r),coverage:{validSessions:e.records.length,corruptSessions:e.corruptSessionIds?.length??0,unsupportedSessions:e.unsupportedSessionIds?.length??0,duplicateObservations:r.duplicateObservations,legacyObservations:r.legacyObservations,unknownModelObservations:o.filter(e=>!e.observation.modelId&&!e.observation.modelShares).length,unknownProviderObservations:o.filter(e=>!e.observation.providerId&&!e.observation.modelShares).length,unknownSurfaceObservations:o.filter(e=>!e.observation.surface||e.observation.surface===`unknown`).length,corruptSessionIds:[...e.corruptSessionIds??[]].sort(),unsupportedSessionIds:[...e.unsupportedSessionIds??[]].sort()}}}const ue=(1n<<64n)-1n,G=/^(?!0{32}$)[0-9a-f]{32}$/,K=/^(?!0{16}$)[0-9a-f]{16}$/,de=[`promptExecutionStartedAt`,`promptExecutionEndedAt`,`promptExecutionOutcome`,`promptExecutionTraceId`,`promptExecutionSpanId`];function q(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function J(e,t){e.set(t,(e.get(t)??0)+1)}function Y(e){if(typeof e!=`string`)return;let t=new Date(e);if(Number.isNaN(t.getTime())||t.toISOString()!==e)return;let n=BigInt(t.getTime())*1000000n;return n>=0n&&n<=ue?n:void 0}function fe(e){let t=Y(e.promptExecutionStartedAt),n=Y(e.promptExecutionEndedAt),r=e.promptExecutionOutcome,i=e.promptExecutionTraceId,a=e.promptExecutionSpanId;if(!(t===void 0||n===void 0||t>n||r!==`success`&&r!==`failure`&&r!==`interrupted`||typeof i!=`string`||!G.test(i)||typeof a!=`string`||!K.test(a)||typeof e.usageObservationId!=`string`||e.usageObservationId.length===0||e.turnId!==e.usageObservationId||e.outcome!==`success`&&e.outcome!==`failure`&&e.outcome!==`interrupted`))return{traceId:i,spanId:a,name:`agent.prompt_execution`,kind:1,startTimeUnixNano:String(t),endTimeUnixNano:String(n),attributes:[{key:`agent.prompt.outcome`,value:{stringValue:r}}],status:{code:r===`success`?1:r===`failure`?2:0}}}function pe(e,t){if(!q(e))return;let n=e.traceId,r=e.parentSpanId,i=e.spanId,a=Y(e.startedAt),o=Y(e.endedAt),s=e.outcome;if(!(typeof n!=`string`||!G.test(n)||typeof r!=`string`||!K.test(r)||typeof i!=`string`||!K.test(i)||a===void 0||o===void 0||a>o||s!==`success`&&s!==`failure`&&s!==`interrupted`||t===`provider`&&(!Number.isSafeInteger(e.round)||e.round<1)))return{traceId:n,parentSpanId:r,spanId:i,name:t===`provider`?`agent.provider_call`:`agent.tool_body`,kind:1,startTimeUnixNano:String(a),endTimeUnixNano:String(o),attributes:[{key:t===`provider`?`agent.provider.outcome`:`agent.tool.outcome`,value:{stringValue:s}}],status:{code:s===`success`?1:s===`failure`?2:0}}}function me(e){if(!q(e))return;let t=e.traceId,n=e.spanId;return typeof t==`string`&&G.test(t)&&typeof n==`string`&&K.test(n)?`${t}:${n}`:void 0}function X(e){return typeof e==`number`&&Number.isSafeInteger(e)&&e>=0}function he(n,r,i,a){if(!q(r)||r.disposition===void 0)return i.legacy+=1,n;if(r.disposition!==`invoked`)return i.invalid+=1,n;a.invoked+=1;let o=r.usageProvenance;if(o===`partial`)return i.partial+=1,a.unknownCost+=1,n;if(o===`absent`||o===void 0)return i.absent+=1,a.unknownCost+=1,n;let s=r.promptTokens,c=r.completionTokens,l=r.totalTokens;if(o!==`complete`||!X(s)||!X(c)||!Number.isSafeInteger(s+c)||l!==s+c)return i.invalid+=1,a.unknownCost+=1,n;a.completeUsage+=1,a.inputTokens+=s,a.outputTokens+=c;let u=[...n.attributes,{key:`agent.provider.usage.input_tokens`,value:{intValue:String(s)}},{key:`agent.provider.usage.output_tokens`,value:{intValue:String(c)}}],d=r.modelId,f=typeof d==`string`&&d.length>0&&d.length<=128&&[...d].every(e=>e.charCodeAt(0)>=32)?t(d,s,c):void 0;return f===void 0||!Number.isFinite(f)||f<0?a.unknownCost+=1:(a.estimatedCostUsd+=f,typeof d==`string`&&Object.hasOwn(e,d)?a.exactPriceMatches+=1:a.familyPriceMatches+=1,u.push({key:`agent.provider.cost.usd.estimated`,value:{doubleValue:f}})),{...n,attributes:u}}function Z(e,t,n){let r=[],i=new Map,a=new Map;for(let t of e)for(let e of t.history??[]){if(e.type!==`usage-observation`)continue;let n=e.data,o=q(n)?n.usageObservationId:void 0,s=q(n)?n.promptExecutionTraceId:void 0,c=typeof o==`string`&&o.length>0?JSON.stringify([t.id,o]):void 0,l=typeof s==`string`&&G.test(s)?s:void 0;c&&J(i,c),l&&J(a,l),r.push({record:t,data:n,observationKey:c,traceId:l})}let o=[],s=new Map,c=0,l=0,u=0;for(let e of r){if(e.observationKey&&(i.get(e.observationKey)??0)>1||e.traceId&&(a.get(e.traceId)??0)>1){u+=1;continue}let t=e.data;if(!q(t)){l+=1;continue}if(de.every(e=>t[e]===void 0)){c+=1;continue}let n=fe(t);if(!n){l+=1;continue}o.push(n);let r=s.get(e.record)??new Map;r.set(n.traceId,n),s.set(e.record,r)}let d=[],f=new Map;for(let t of e)for(let e of t.history??[]){let n=e.type===`provider-call-trace`?`provider`:e.type===`tool-body-trace`?`tool`:void 0;if(!n)continue;let r=me(e.data),i=pe(e.data,n);r&&J(f,r),d.push({record:t,span:i,identity:r,kind:n,data:e.data})}let p={provider:{exported:0,invalid:0,orphaned:0,duplicate:0},tool:{exported:0,invalid:0,orphaned:0,duplicate:0}},m={legacy:0,invalid:0,partial:0,absent:0,nonInvoked:0},h={invoked:0,completeUsage:0,inputTokens:0,outputTokens:0,estimatedCostUsd:0,unknownCost:0,exactPriceMatches:0,familyPriceMatches:0};for(let e of d){let{span:t}=e,n=p[e.kind];if(e.identity&&(f.get(e.identity)??0)>1){n.duplicate+=1;continue}if(!t){n.invalid+=1;continue}let r=s.get(e.record)?.get(t.traceId);if(!r||t.parentSpanId!==r.spanId||t.spanId===r.spanId){n.orphaned+=1;continue}if(BigInt(t.startTimeUnixNano)<BigInt(r.startTimeUnixNano)||BigInt(t.endTimeUnixNano)>BigInt(r.endTimeUnixNano)){n.invalid+=1;continue}if(e.kind===`provider`&&q(e.data)&&(e.data.disposition===`cache-hit`||e.data.disposition===`preflight-refused`)){m.nonInvoked+=1,(e.data.promptTokens!==void 0||e.data.completionTokens!==void 0||e.data.totalTokens!==void 0||e.data.usageProvenance===`complete`)&&(m.invalid+=1);continue}o.push(e.kind===`provider`?he(t,e.data,m,h):t),n.exported+=1}return{payload:{resourceSpans:o.length?[{resource:{attributes:[{key:`service.name`,value:{stringValue:n}},{key:`service.version`,value:{stringValue:t}}]},scopeSpans:[{scope:{name:`@robota-sdk/agent-session-analytics`},spans:o}]}]:[]},coverage:{exported:o.length-p.provider.exported-p.tool.exported,missing:c,invalid:l,duplicate:u,providerChildren:p.provider,providerUsage:m,toolChildren:p.tool},callMetrics:h}}function ge(e,t,n,r){let i=new Set,a=0,o=0,s=0,c=0,l=0,u=0,d=0,f=0;for(let t of e)for(let e of M(t)){if(i.has(e.id))continue;i.add(e.id),e.legacy||(a+=1);let t=e.observation.usage;if(!t){d+=1,l+=1;continue}o+=t.totalTokens,s+=t.promptTokens??0,c+=t.completionTokens??0,(t.promptTokens===void 0||t.completionTokens===void 0)&&(l+=1),t.costStatus===`unknown`||t.costUsd===void 0?d+=1:(u+=t.costUsd,t.costStatus===`estimated`&&(f+=1))}let p=Z(e,n,r),m=p.callMetrics,h=String(BigInt(t.getTime())*1000000n),g=(e,t,n)=>({name:e,unit:t,gauge:{dataPoints:[{timeUnixNano:h,asDouble:n}]}});return{resourceMetrics:[{resource:{attributes:[{key:`service.name`,value:{stringValue:r}},{key:`service.version`,value:{stringValue:n}}]},scopeMetrics:[{scope:{name:`@robota-sdk/agent-session-analytics`},metrics:[g(`agent.session.count`,`{session}`,e.length),g(`agent.turn.count`,`{turn}`,a),g(`agent.token.total`,`{token}`,o),g(`agent.token.input.known`,`{token}`,s),g(`agent.token.output.known`,`{token}`,c),g(`agent.token.split_unknown_observations`,`{observation}`,l),g(`agent.cost.usd.known`,`USD`,u),g(`agent.cost.unknown_observations`,`{observation}`,d),g(`agent.cost.estimated_observations`,`{observation}`,f),g(`agent.provider_call.count`,`{call}`,m.invoked),g(`agent.provider_call.usage.complete_count`,`{call}`,m.completeUsage),g(`agent.provider_call.token.input.known`,`{token}`,m.inputTokens),g(`agent.provider_call.token.output.known`,`{token}`,m.outputTokens),g(`agent.provider_call.cost.usd.estimated`,`USD`,m.estimatedCostUsd),g(`agent.provider_call.cost.unknown_count`,`{call}`,m.unknownCost),g(`agent.provider_call.usage.partial_count`,`{call}`,p.coverage.providerUsage.partial),g(`agent.provider_call.usage.invalid_count`,`{call}`,p.coverage.providerUsage.invalid),g(`agent.provider_call.usage.legacy_count`,`{call}`,p.coverage.providerUsage.legacy),g(`agent.provider_call.price.exact_id_count`,`{call}`,m.exactPriceMatches),g(`agent.provider_call.price.family_fallback_count`,`{call}`,m.familyPriceMatches)]}]}]}}const _e=(1n<<64n)-1n;function Q(e){let t=e.getTime();if(!Number.isSafeInteger(t)||t<0)throw RangeError(`OTLP log observation time must be a valid post-epoch date.`);let n=BigInt(t)*1000000n;if(n>_e)throw RangeError(`OTLP log observation time is out of range.`);return String(n)}function ve(e,t,n,r){let i=Z(e,t,r),a=i.payload.resourceSpans[0]?.scopeSpans[0]?.spans??[];if(a.length===0)return{exported:0,coverage:i.coverage,payload:{resourceLogs:[]}};let o=Q(n),s=a.map(e=>{let t=e.attributes.find(e=>e.key===`agent.prompt.outcome`||e.key===`agent.provider.outcome`||e.key===`agent.tool.outcome`),n=e.name===`agent.prompt_execution`?`agent.prompt_execution.completed`:e.name===`agent.provider_call`?`agent.provider_call.completed`:`agent.tool_body.completed`,r=e.status.code===1?9:e.status.code===2?17:13,i=r===9?`INFO`:r===17?`ERROR`:`WARN`;return{timeUnixNano:e.endTimeUnixNano,observedTimeUnixNano:o,severityNumber:r,severityText:i,eventName:n,traceId:e.traceId,spanId:e.spanId,attributes:t&&`stringValue`in t.value?[{key:t.key,value:{stringValue:t.value.stringValue}}]:[]}});return{exported:s.length,coverage:i.coverage,payload:{resourceLogs:[{resource:i.payload.resourceSpans[0].resource,scopeLogs:[{scope:{name:`@robota-sdk/agent-session-analytics`},logRecords:s}]}]}}}function $(e,t){return[``,e,...t.length===0?[`(none)`]:t.map(e=>`${e.label} ${e.turns} turns ${e.totalTokens} tokens cost ${e.costStatus===`unknown`?`unknown`:`$${e.costUsd.toFixed(4)}`}`)]}function ye(e){let t=e.totals.costStatus===`unknown`?`unknown`:`$${e.totals.costUsd.toFixed(4)} (${e.totals.costStatus})`;return[`Personal usage — ${e.period} (${e.timezone})`,`${e.interval.startDate} → ${e.interval.endDate}`,`Sessions ${e.totals.sessions} · Turns ${e.totals.turns} · Tokens ${e.totals.totalTokens} (${e.totals.promptTokens} input / ${e.totals.completionTokens} output) · Cost ${t}`,``,`Daily usage`,...e.daily.map(e=>`${e.date}${e.partial?` (partial)`:``} ${e.totals.turns} turns ${e.totals.totalTokens} tokens`),...$(`By model`,e.byModel),...$(`By provider`,e.byProvider),...$(`By surface`,e.bySurface),...$(`By source`,e.bySource),``,`Activity`,...e.byActivity.length===0?[`(none)`]:e.byActivity.map(e=>`${e.kind}:${e.label} ${e.count} calls`),``,`Coverage: legacy ${e.coverage.legacyObservations}, corrupt ${e.coverage.corruptSessions}, unsupported ${e.coverage.unsupportedSessions}, duplicates ${e.coverage.duplicateObservations}`,`Local estimates from recorded sessions; costs are not an invoice.`].join(`
|
|
5
5
|
`)}export{c as aggregateReports,s as analyzeSession,a as computeTimingIntervals,ve as createOtlpPromptEvents,Z as createOtlpPromptRootTraces,ge as createOtlpUsageSnapshot,ee as formatAggregateReport,ye as formatPersonalUsageReport,g as formatSingleSession,d as formatUsageReport,n as gapMs,le as summarizePersonalUsage,b as summarizeUsageBySource};
|
|
6
6
|
//# sourceMappingURL=index.js.map
|
package/dist/node/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":["sourceKey","isRecord","MAX_UINT64"],"sources":["../../src/analyze.ts","../../src/report.ts","../../src/usage.ts","../../src/personal-usage-decode.ts","../../src/personal-usage.ts","../../src/otlp-prompt-root-traces.ts","../../src/otlp-usage-snapshot.ts","../../src/otlp-prompt-events.ts","../../src/personal-usage-format.ts"],"sourcesContent":["/**\n * Session-log timing-interval computation and aggregation.\n *\n * Operates on canonical history entries (`IHistoryEntry`); persisted timestamps arrive as ISO\n * strings at runtime (JSON has no Date), so all timestamp math goes through `new Date(...)`.\n */\n\nimport type {\n IAggregateReport,\n TSessionAnalysisInput,\n ISessionTimingReport,\n ITimingInterval,\n ITimingStats,\n TIntervalKind,\n} from './types.js';\nimport type { IHistoryEntry } from '@robota-sdk/agent-core';\n\nconst SLOW_THRESHOLD_MS = 10_000;\n\n/** Gap in milliseconds between two timestamps (ISO string or Date). */\nexport function gapMs(from: string | Date, to: string | Date): number {\n return new Date(to).getTime() - new Date(from).getTime();\n}\n\nfunction toIso(value: string | Date): string {\n return new Date(value).toISOString();\n}\n\nfunction makeInterval(\n kind: TIntervalKind,\n fromType: string,\n toType: string,\n fromTimestamp: string | Date,\n toTimestamp: string | Date,\n turnIndex: number,\n): ITimingInterval {\n return {\n kind,\n fromType,\n toType,\n fromTimestamp: toIso(fromTimestamp),\n toTimestamp: toIso(toTimestamp),\n durationMs: gapMs(fromTimestamp, toTimestamp),\n turnIndex,\n };\n}\n\n/**\n * Compute timing intervals from a history entry array.\n *\n * Strategy: scan the timeline turn by turn. A \"turn\" starts with a user message. After user, we\n * expect zero or more tool-start → tool-end cycles, optionally a tool-summary, then an assistant\n * message.\n */\nexport function computeTimingIntervals(history: readonly IHistoryEntry[]): ITimingInterval[] {\n const intervals: ITimingInterval[] = [];\n let turnIndex = 0;\n\n let i = 0;\n while (i < history.length) {\n const entry = history[i];\n if (!entry) {\n i++;\n continue;\n }\n\n if (entry.category === 'chat' && entry.type === 'user') {\n turnIndex++;\n const userTs = entry.timestamp;\n let foundFirstTool = false;\n let lastToolEndTs: IHistoryEntry['timestamp'] | null = null;\n let j = i + 1;\n\n while (j < history.length) {\n const next = history[j];\n if (!next) {\n j++;\n continue;\n }\n\n if (next.category === 'chat' && next.type === 'user') {\n break;\n }\n\n if (next.category === 'event' && next.type === 'tool-start') {\n if (!foundFirstTool) {\n intervals.push(\n makeInterval(\n 'user_to_first_tool',\n 'user',\n 'tool-start',\n userTs,\n next.timestamp,\n turnIndex,\n ),\n );\n foundFirstTool = true;\n } else if (lastToolEndTs !== null) {\n intervals.push(\n makeInterval(\n 'llm_between_tools',\n 'tool-end',\n 'tool-start',\n lastToolEndTs,\n next.timestamp,\n turnIndex,\n ),\n );\n }\n lastToolEndTs = null;\n j++;\n continue;\n }\n\n if (next.category === 'event' && next.type === 'tool-end') {\n const prev = history[j - 1];\n if (prev && prev.category === 'event' && prev.type === 'tool-start') {\n intervals.push(\n makeInterval(\n 'tool_exec',\n 'tool-start',\n 'tool-end',\n prev.timestamp,\n next.timestamp,\n turnIndex,\n ),\n );\n }\n lastToolEndTs = next.timestamp;\n j++;\n continue;\n }\n\n if (next.category === 'event' && next.type === 'tool-summary') {\n if (lastToolEndTs !== null) {\n intervals.push(\n makeInterval(\n 'llm_final_response',\n 'tool-end',\n 'tool-summary',\n lastToolEndTs,\n next.timestamp,\n turnIndex,\n ),\n );\n }\n j++;\n continue;\n }\n\n if (next.category === 'chat' && next.type === 'assistant') {\n if (!foundFirstTool) {\n intervals.push(\n makeInterval(\n 'user_to_assistant',\n 'user',\n 'assistant',\n userTs,\n next.timestamp,\n turnIndex,\n ),\n );\n } else if (lastToolEndTs !== null) {\n intervals.push(\n makeInterval(\n 'llm_final_response',\n 'tool-end',\n 'assistant',\n lastToolEndTs,\n next.timestamp,\n turnIndex,\n ),\n );\n }\n j++;\n break;\n }\n\n j++;\n }\n\n i = j;\n } else {\n i++;\n }\n }\n\n return intervals;\n}\n\nfunction computeStats(intervals: ITimingInterval[]): ITimingStats {\n const llm = intervals.filter(\n (iv) =>\n iv.kind === 'user_to_first_tool' ||\n iv.kind === 'user_to_assistant' ||\n iv.kind === 'llm_between_tools' ||\n iv.kind === 'llm_final_response',\n );\n const tool = intervals.filter((iv) => iv.kind === 'tool_exec');\n const direct = intervals.filter((iv) => iv.kind === 'user_to_assistant');\n\n const avg = (arr: ITimingInterval[]): number =>\n arr.length ? Math.round(arr.reduce((s, iv) => s + iv.durationMs, 0) / arr.length) : 0;\n const max = (arr: ITimingInterval[]): number =>\n arr.length ? Math.max(...arr.map((iv) => iv.durationMs)) : 0;\n const median = (arr: ITimingInterval[]): number => {\n if (!arr.length) return 0;\n const sorted = [...arr].sort((a, b) => a.durationMs - b.durationMs);\n const mid = Math.floor(sorted.length / 2);\n return sorted.length % 2 === 0\n ? Math.round(((sorted[mid - 1]?.durationMs ?? 0) + (sorted[mid]?.durationMs ?? 0)) / 2)\n : (sorted[mid]?.durationMs ?? 0);\n };\n\n return {\n llmWaitMs: {\n avg: avg(llm),\n max: max(llm),\n total: llm.reduce((s, iv) => s + iv.durationMs, 0),\n count: llm.length,\n },\n toolExecMs: { avg: avg(tool), max: max(tool), median: median(tool), count: tool.length },\n userToAssistantMs: { avg: avg(direct), max: max(direct), count: direct.length },\n };\n}\n\n/** Compute the timing report for a single session record. */\nexport function analyzeSession(record: TSessionAnalysisInput): ISessionTimingReport {\n const history = record.history ?? [];\n const intervals = computeTimingIntervals(history);\n const slowIntervals = intervals.filter((iv) => iv.durationMs >= SLOW_THRESHOLD_MS);\n\n return {\n sessionId: record.id,\n cwd: record.cwd,\n createdAt: record.createdAt,\n totalIntervals: intervals.length,\n intervals,\n slowIntervals,\n stats: computeStats(intervals),\n };\n}\n\n/** Aggregate multiple single-session reports into a fleet-level summary. */\nexport function aggregateReports(reports: readonly ISessionTimingReport[]): IAggregateReport {\n const llmIntervals = reports.flatMap((r) =>\n r.intervals.filter(\n (iv) =>\n iv.kind === 'user_to_first_tool' ||\n iv.kind === 'user_to_assistant' ||\n iv.kind === 'llm_between_tools' ||\n iv.kind === 'llm_final_response',\n ),\n );\n const toolIntervals = reports.flatMap((r) => r.intervals.filter((iv) => iv.kind === 'tool_exec'));\n\n const avgLlmResponseMs = llmIntervals.length\n ? Math.round(llmIntervals.reduce((s, iv) => s + iv.durationMs, 0) / llmIntervals.length)\n : 0;\n const avgToolExecMs = toolIntervals.length\n ? Math.round(toolIntervals.reduce((s, iv) => s + iv.durationMs, 0) / toolIntervals.length)\n : 0;\n\n let maxSingleDelayMs = 0;\n let maxSingleDelaySession = '';\n let maxSingleDelayTurn = 0;\n let maxSingleDelayKind = '';\n\n for (const r of reports) {\n for (const iv of r.intervals) {\n if (iv.durationMs > maxSingleDelayMs) {\n maxSingleDelayMs = iv.durationMs;\n maxSingleDelaySession = r.sessionId;\n maxSingleDelayTurn = iv.turnIndex;\n maxSingleDelayKind = iv.kind;\n }\n }\n }\n\n const dates = reports.map((r) => r.createdAt).sort();\n\n return {\n sessionCount: reports.length,\n fromDate: dates[0] ?? '',\n toDate: dates[dates.length - 1] ?? '',\n avgLlmResponseMs,\n avgToolExecMs,\n maxSingleDelayMs,\n maxSingleDelaySession,\n maxSingleDelayTurn,\n maxSingleDelayKind,\n };\n}\n","/**\n * Text report formatters for session timing analysis. Pure — every function returns a string;\n * callers (e.g. a CLI command) own writing to stdout.\n */\n\nimport type { IAggregateReport, ISessionTimingReport, ITimingInterval } from './types.js';\nimport type { IUsageBySourceReport } from './usage.js';\n\nfunction fmtTokens(n: number): string {\n if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;\n if (n >= 1_000) return `${(n / 1_000).toFixed(1)}K`;\n return `${n}`;\n}\n\n/** SELFHOST-004: `~` marks an estimate or incomplete aggregate, never an invoice amount. */\nfunction fmtCost(usd: number, exact: boolean): string {\n return `${exact ? '' : '~'}$${usd.toFixed(4)}`;\n}\n\n/**\n * ANALYTICS-001 + SELFHOST-004: render a per-source token+cost breakdown and the per-operation span\n * timeline — which part of the session burned the most tokens/cost, and where the wall-clock went.\n * Pure; the caller owns writing it (the headless CLI path for the TUI/GUI trace/cost view).\n */\nexport function formatUsageReport(report: IUsageBySourceReport): string {\n const lines: string[] = [];\n lines.push(`Token usage — session ${report.sessionId}`);\n lines.push(\n ` total ${fmtTokens(report.totalTokens)} (prompt ${fmtTokens(report.promptTokens)} · completion ${fmtTokens(report.completionTokens)})`,\n );\n lines.push(` cost ${fmtCost(report.costUsd, report.costExact)}`);\n if (report.bySource.length === 0) {\n lines.push(' (no usage recorded)');\n } else {\n lines.push(' by source (most tokens first):');\n for (const s of report.bySource) {\n lines.push(\n ` ${s.label.padEnd(24)} ${String(s.percentage).padStart(5)}% ${fmtTokens(s.totalTokens).padStart(7)} ${fmtCost(s.costUsd, s.costExact).padStart(10)} (${s.turns} turn${s.turns === 1 ? '' : 's'})`,\n );\n }\n if (report.topConsumer) {\n lines.push(` top consumer: ${report.topConsumer.label} (${report.topConsumer.percentage}%)`);\n }\n }\n\n // SELFHOST-004: the span timeline — sub-turn operations grouped under their owning turn.\n if (report.timeline.length > 0) {\n lines.push(' trace (per turn, sub-turn spans):');\n for (const turn of report.timeline) {\n lines.push(\n ` turn ${turn.turnIndex} — ${turn.label} · ${fmtMs(turn.totalDurationMs)} across ${turn.spans.length} op${turn.spans.length === 1 ? '' : 's'}`,\n );\n for (const span of turn.spans) {\n lines.push(` ${span.op.padEnd(22)} ${fmtMs(span.durationMs).padStart(8)}`);\n }\n }\n }\n return lines.join('\\n');\n}\n\nfunction fmtMs(ms: number): string {\n if (ms >= 1000) return `${(ms / 1000).toFixed(1)}s`;\n return `${ms}ms`;\n}\n\nfunction fmtDate(iso: string): string {\n return new Date(iso).toLocaleString('sv-SE', { timeZoneName: 'short' }).slice(0, 16);\n}\n\nfunction intervalLabel(iv: ITimingInterval): string {\n const map: Record<string, string> = {\n user_to_first_tool: 'user → tool-start',\n user_to_assistant: 'user → assistant',\n tool_exec: 'tool-start → tool-end',\n llm_between_tools: 'tool-end → tool-start',\n llm_final_response: 'tool-end → assistant/summary',\n };\n return map[iv.kind] ?? iv.kind;\n}\n\nfunction verdictLine(report: ISessionTimingReport): string {\n const { stats } = report;\n const totalMs = stats.llmWaitMs.total + stats.toolExecMs.avg * stats.toolExecMs.count;\n if (totalMs === 0) return 'Verdict: No timing data available.';\n const llmPct = Math.round((stats.llmWaitMs.total / totalMs) * 100);\n const toolPct = 100 - llmPct;\n return `Verdict: LLM API wait ${llmPct}% | Code processing ${toolPct}%`;\n}\n\nexport function formatSingleSession(report: ISessionTimingReport): string {\n const lines: string[] = [];\n const { stats } = report;\n\n lines.push(`Session: ${report.sessionId}`);\n lines.push(`Created: ${fmtDate(report.createdAt)} | cwd: ${report.cwd}`);\n lines.push('');\n lines.push('Timing Summary:');\n\n if (stats.llmWaitMs.count > 0) {\n lines.push(\n ` LLM API wait ${fmtMs(stats.llmWaitMs.avg).padStart(8)} avg | ${fmtMs(stats.llmWaitMs.max).padStart(8)} max`,\n );\n }\n if (stats.toolExecMs.count > 0) {\n lines.push(\n ` Tool execution ${fmtMs(stats.toolExecMs.avg).padStart(8)} avg | ${fmtMs(stats.toolExecMs.median).padStart(8)} median`,\n );\n }\n if (stats.userToAssistantMs.count > 0) {\n lines.push(` user → assistant ${fmtMs(stats.userToAssistantMs.avg).padStart(8)} avg`);\n }\n if (stats.llmWaitMs.count === 0 && stats.toolExecMs.count === 0) {\n lines.push(' (no intervals computed — session may have no history)');\n }\n\n if (report.slowIntervals.length > 0) {\n lines.push('');\n lines.push('Slow intervals (>10s):');\n for (const iv of report.slowIntervals) {\n lines.push(\n ` turn ${iv.turnIndex} ${intervalLabel(iv).padEnd(32)} ${fmtMs(iv.durationMs).padStart(8)}`,\n );\n }\n }\n\n lines.push('');\n lines.push(verdictLine(report));\n\n return lines.join('\\n');\n}\n\nexport function formatAggregateReport(aggregate: IAggregateReport): string {\n const lines: string[] = [];\n lines.push(\n `Analyzed ${aggregate.sessionCount} sessions (${fmtDate(aggregate.fromDate)} ~ ${fmtDate(aggregate.toDate)})`,\n );\n lines.push(` Avg LLM response: ${fmtMs(aggregate.avgLlmResponseMs)}`);\n lines.push(` Avg tool exec: ${fmtMs(aggregate.avgToolExecMs)}`);\n if (aggregate.maxSingleDelayMs > 0) {\n lines.push(\n ` Max single delay: ${fmtMs(aggregate.maxSingleDelayMs)} (${aggregate.maxSingleDelaySession}, turn ${aggregate.maxSingleDelayTurn}, ${aggregate.maxSingleDelayKind})`,\n );\n }\n return lines.join('\\n');\n}\n","/**\n * ANALYTICS-001: source-attributed token-usage analysis over a session record.\n *\n * The main session history records one `usage-summary` history entry per turn (an `IUsageSnapshot`,\n * created in agent-framework). This reducer aggregates those snapshots into a per-source breakdown —\n * answering \"which part of the session burned the most tokens?\" — so it can be reported to the user\n * and asserted by the testing framework (budget gates). Pure: no I/O, no process concerns.\n */\n\nimport type { IHistoryEntry } from '@robota-sdk/agent-core';\nimport type {\n ISpanEntry,\n IUsageSnapshot,\n IUsageSource,\n IUsageSourceTotals,\n IRunTraceSpan,\n IRunTraceTurn,\n IUsageBySourceReport,\n} from '@robota-sdk/agent-interface-analytics';\nimport type { IInteractiveSessionRecord } from '@robota-sdk/agent-interface-session';\n\n// SELFHOST-004: the trace/cost read-model is a boundary contract owned by `agent-interface-analytics`\n// (it crosses the sidecar boundary via a TServerMessage carrier). Re-exported here for consumers that\n// import it alongside the reducer that produces it.\nexport type {\n IUsageSourceTotals,\n IRunTraceSpan,\n IRunTraceTurn,\n IUsageBySourceReport,\n} from '@robota-sdk/agent-interface-analytics';\n\n/** The `type` of the per-turn usage history entry (agent-framework `createUsageSummaryEntry`). */\nconst USAGE_SUMMARY_ENTRY_TYPE = 'usage-summary';\n\n/** The `type` of the per-operation span history entry (agent-framework `createSpanEntry`). */\nconst SPAN_ENTRY_TYPE = 'span';\n\n/** SSOT-derived projection the usage reducer reads. */\nexport type TUsageAnalysisInput = Pick<IInteractiveSessionRecord, 'id' | 'history'>;\n\n/** The main thread is the implicit source when a usage snapshot carries none. */\nconst MAIN_THREAD_SOURCE: IUsageSource = { scope: 'main', label: 'main thread' };\n\nfunction sourceKey(source: IUsageSource): string {\n return `${source.scope}:${source.id ?? ''}`;\n}\n\nfunction sourceLabel(source: IUsageSource): string {\n return source.label ?? (source.id ? `${source.scope} ${source.id}` : source.scope);\n}\n\nfunction isUsageSummaryEntry(entry: IHistoryEntry): entry is IHistoryEntry<IUsageSnapshot> {\n return (\n entry.type === USAGE_SUMMARY_ENTRY_TYPE && typeof entry.data === 'object' && entry.data !== null\n );\n}\n\nfunction isSpanEntry(entry: IHistoryEntry): entry is IHistoryEntry<ISpanEntry> {\n if (entry.type !== SPAN_ENTRY_TYPE || typeof entry.data !== 'object' || entry.data === null) {\n return false;\n }\n const data = entry.data as Partial<ISpanEntry>;\n return (\n typeof data.spanId === 'string' &&\n typeof data.op === 'string' &&\n typeof data.durationMs === 'number'\n );\n}\n\nfunction roundPercentage(part: number, whole: number): number {\n if (whole <= 0) return 0;\n return Math.round((part / whole) * 1000) / 10;\n}\n\n/**\n * Aggregate a session's `usage-summary` entries into a per-source token+cost breakdown AND assemble\n * the per-operation span timeline (SELFHOST-004).\n *\n * Token/cost: usage snapshots with no `source` are attributed to the main thread; sources are grouped\n * by `<scope>:<id>` and sorted by total tokens descending with the top consumer surfaced. Cost sums\n * each turn's known `IUsageSnapshot.costUsd` (unpriced turns contribute 0). Historical `exact`\n * snapshots were local price-table estimates, so they cannot certify billed cost.\n *\n * Timeline: history is a chronological timeline where each turn ends with its `usage-summary` entry,\n * so the `span` entries that appear before a given usage-summary are the sub-turn spans of THAT turn.\n * The reducer walks in order, buffering spans, and flushes the buffer as the turn's spans at each\n * usage-summary boundary — grouping sub-turn spans under their owning turn. Spans after the last\n * usage-summary (an in-progress turn) form a trailing timeline entry. Pure: no I/O, stays within the\n * declared `agent-core`, `agent-interface-analytics` and `agent-interface-session` dependencies\n * (NO `agent-plugin` read — enforcement lives elsewhere).\n */\nexport function summarizeUsageBySource(input: TUsageAnalysisInput): IUsageBySourceReport {\n const totalsByKey = new Map<string, IUsageSourceTotals>();\n let sessionPrompt = 0;\n let sessionCompletion = 0;\n let sessionTotal = 0;\n let sessionCost = 0;\n let sessionCostExact = true;\n\n const timeline: IRunTraceTurn[] = [];\n let pendingSpans: IRunTraceSpan[] = [];\n\n const flushTurn = (source: IUsageSource): void => {\n if (pendingSpans.length === 0) return;\n timeline.push({\n turnIndex: timeline.length,\n source,\n label: sourceLabel(source),\n spans: pendingSpans,\n totalDurationMs: pendingSpans.reduce((sum, span) => sum + span.durationMs, 0),\n });\n pendingSpans = [];\n };\n\n for (const entry of input.history ?? []) {\n if (isSpanEntry(entry)) {\n const span = entry.data as ISpanEntry;\n pendingSpans.push({ spanId: span.spanId, op: span.op, durationMs: span.durationMs });\n continue;\n }\n if (!isUsageSummaryEntry(entry)) continue;\n\n const snapshot = entry.data as IUsageSnapshot;\n const source = snapshot.source ?? MAIN_THREAD_SOURCE;\n const key = sourceKey(source);\n const prompt = snapshot.promptTokens ?? 0;\n const completion = snapshot.completionTokens ?? 0;\n const total = snapshot.totalTokens;\n // Historical `exact` labels were local price-table estimates, not billed values. Preserve the\n // amount while keeping the aggregate's exactness claim false.\n const turnCost = snapshot.costUsd ?? 0;\n const turnPriced = false;\n\n sessionPrompt += prompt;\n sessionCompletion += completion;\n sessionTotal += total;\n sessionCost += turnCost;\n if (!turnPriced) sessionCostExact = false;\n\n const existing = totalsByKey.get(key);\n if (existing) {\n existing.promptTokens += prompt;\n existing.completionTokens += completion;\n existing.totalTokens += total;\n existing.turns += 1;\n existing.costUsd += turnCost;\n if (!turnPriced) existing.costExact = false;\n } else {\n totalsByKey.set(key, {\n key,\n source,\n label: sourceLabel(source),\n promptTokens: prompt,\n completionTokens: completion,\n totalTokens: total,\n turns: 1,\n percentage: 0,\n costUsd: turnCost,\n costExact: turnPriced,\n });\n }\n\n // The usage-summary marks the turn boundary: the buffered spans belong to THIS turn.\n flushTurn(source);\n }\n\n // Spans of an in-progress turn (no usage summary yet) form a trailing timeline entry.\n flushTurn(MAIN_THREAD_SOURCE);\n\n const bySource = [...totalsByKey.values()]\n .map((totals) => ({ ...totals, percentage: roundPercentage(totals.totalTokens, sessionTotal) }))\n .sort((left, right) => right.totalTokens - left.totalTokens);\n\n return {\n sessionId: input.id,\n totalTokens: sessionTotal,\n promptTokens: sessionPrompt,\n completionTokens: sessionCompletion,\n costUsd: sessionCost,\n costExact: sessionCostExact,\n bySource,\n ...(bySource[0] ? { topConsumer: bySource[0] } : {}),\n timeline,\n };\n}\n","import type { IHistoryEntry, IUniversalObjectValue, TUniversalValue } from '@robota-sdk/agent-core';\nimport type {\n IPersonalUsageActivity,\n IUsageModelShare,\n IUsageObservation,\n IUsageSnapshot,\n IUsageSource,\n} from '@robota-sdk/agent-interface-analytics';\nimport type { IInteractiveSessionRecord } from '@robota-sdk/agent-interface-session';\n\nexport interface INormalizedObservation {\n readonly id: string;\n readonly sessionId: string;\n readonly at: Date;\n readonly legacy: boolean;\n readonly observation: IUsageObservation;\n}\n\nexport interface INormalizedActivity {\n readonly id: string;\n readonly sessionId: string;\n readonly key: string;\n readonly label: string;\n readonly kind: IPersonalUsageActivity['kind'];\n readonly at: Date;\n}\n\nfunction isRecord(value: TUniversalValue): value is IUniversalObjectValue {\n return (\n typeof value === 'object' && value !== null && !Array.isArray(value) && !(value instanceof Date)\n );\n}\n\nfunction optionalString(value: TUniversalValue): string | undefined {\n return typeof value === 'string' && value.length > 0 ? value : undefined;\n}\n\nfunction isMetric(value: TUniversalValue): value is number {\n return typeof value === 'number' && Number.isFinite(value) && value >= 0;\n}\n\nfunction isCostStatus(value: TUniversalValue): value is IUsageSnapshot['costStatus'] {\n return value === 'unknown' || value === 'estimated' || value === 'exact';\n}\n\nfunction hasValidOptionalMetrics(value: IUniversalObjectValue): boolean {\n return (\n (value['promptTokens'] === undefined || isMetric(value['promptTokens'])) &&\n (value['completionTokens'] === undefined || isMetric(value['completionTokens']))\n );\n}\n\nfunction hasValidCost(value: IUniversalObjectValue): boolean {\n const status = value['costStatus'];\n if (!isCostStatus(status)) return false;\n return status === 'unknown' ? value['costUsd'] === undefined : isMetric(value['costUsd']);\n}\n\ntype TRequiredUsageMetrics = {\n readonly totalTokens: number;\n readonly contextUsedTokens: number;\n readonly contextMaxTokens: number;\n readonly contextUsedPercentage: number;\n};\n\nfunction hasRequiredMetrics(\n value: IUniversalObjectValue,\n): value is IUniversalObjectValue & TRequiredUsageMetrics {\n return (\n isMetric(value['totalTokens']) &&\n isMetric(value['contextUsedTokens']) &&\n isMetric(value['contextMaxTokens']) &&\n isMetric(value['contextUsedPercentage'])\n );\n}\n\nfunction isUsageSurface(\n value: TUniversalValue,\n): value is NonNullable<IUsageObservation['surface']> {\n return (\n value === 'cli' ||\n value === 'desktop-app' ||\n value === 'browser' ||\n value === 'remote' ||\n value === 'attach' ||\n value === 'unknown'\n );\n}\n\nfunction usageSource(value: TUniversalValue): IUsageSource | undefined {\n if (!isRecord(value)) return undefined;\n const scope = value['scope'];\n if (\n scope !== 'main' &&\n scope !== 'subagent' &&\n scope !== 'background' &&\n scope !== 'tool' &&\n scope !== 'command' &&\n scope !== 'skill'\n ) {\n return undefined;\n }\n const id = optionalString(value['id']);\n const label = optionalString(value['label']);\n return { scope, ...(id ? { id } : {}), ...(label ? { label } : {}) };\n}\n\nfunction usageSnapshot(value: TUniversalValue): IUsageSnapshot | undefined {\n if (!isRecord(value)) return undefined;\n if (value['kind'] !== 'exact' && value['kind'] !== 'estimated') return undefined;\n if (value['scope'] !== 'turn' || !hasValidOptionalMetrics(value) || !hasValidCost(value)) {\n return undefined;\n }\n if (!hasRequiredMetrics(value) || !isCostStatus(value['costStatus'])) {\n return undefined;\n }\n const source = usageSource(value['source']);\n return {\n kind: value['kind'],\n scope: 'turn',\n totalTokens: value['totalTokens'],\n contextUsedTokens: value['contextUsedTokens'],\n contextMaxTokens: value['contextMaxTokens'],\n contextUsedPercentage: value['contextUsedPercentage'],\n // Historical `exact` meant a local price-table calculation, not an invoice.\n costStatus: value['costStatus'] === 'exact' ? 'estimated' : value['costStatus'],\n ...(isMetric(value['promptTokens']) ? { promptTokens: value['promptTokens'] } : {}),\n ...(isMetric(value['completionTokens']) ? { completionTokens: value['completionTokens'] } : {}),\n ...(isMetric(value['costUsd']) ? { costUsd: value['costUsd'] } : {}),\n ...(source ? { source } : {}),\n };\n}\n\nfunction modelShare(value: TUniversalValue): IUsageModelShare | undefined {\n if (!isRecord(value)) return undefined;\n const providerId = optionalString(value['providerId']);\n const modelId = optionalString(value['modelId']);\n const { promptTokens, completionTokens, totalTokens, costStatus, costUsd } = value;\n if (\n !providerId ||\n !modelId ||\n !isMetric(promptTokens) ||\n !isMetric(completionTokens) ||\n !isMetric(totalTokens) ||\n (costStatus !== 'unknown' && costStatus !== 'estimated') ||\n (costStatus === 'estimated' ? !isMetric(costUsd) : costUsd !== undefined)\n ) {\n return undefined;\n }\n return {\n providerId,\n modelId,\n promptTokens,\n completionTokens,\n totalTokens,\n costStatus,\n ...(costStatus === 'estimated' && isMetric(costUsd) ? { costUsd } : {}),\n };\n}\n\n/** Every share, or none: a partly readable split would misstate what each model spent. */\nfunction modelShares(value: TUniversalValue): IUsageModelShare[] | undefined {\n if (!Array.isArray(value) || value.length === 0) return undefined;\n const shares = value.map(modelShare);\n return shares.every((share) => share !== undefined) ? (shares as IUsageModelShare[]) : undefined;\n}\n\nfunction decodeObservation(value: TUniversalValue): IUsageObservation | undefined {\n if (!isRecord(value)) return undefined;\n const usageObservationId = optionalString(value['usageObservationId']);\n const turnId = optionalString(value['turnId']);\n const outcome = value['outcome'];\n if (\n !usageObservationId ||\n !turnId ||\n (outcome !== 'success' && outcome !== 'failure' && outcome !== 'interrupted')\n ) {\n return undefined;\n }\n const surface = value['surface'];\n const source = usageSource(value['source']);\n const usage = usageSnapshot(value['usage']);\n const shares = modelShares(value['modelShares']);\n return {\n usageObservationId,\n turnId,\n outcome,\n ...(optionalString(value['modelId']) ? { modelId: optionalString(value['modelId']) } : {}),\n ...(optionalString(value['providerId'])\n ? { providerId: optionalString(value['providerId']) }\n : {}),\n ...(shares ? { modelShares: shares } : {}),\n ...(isUsageSurface(surface) ? { surface } : {}),\n ...(source ? { source } : {}),\n ...(usage ? { usage } : {}),\n };\n}\n\nfunction entryDate(entry: IHistoryEntry): Date | undefined {\n const at = new Date(entry.timestamp);\n return Number.isNaN(at.getTime()) ? undefined : at;\n}\n\nexport function normalizeRecord(record: IInteractiveSessionRecord): INormalizedObservation[] {\n const observations: INormalizedObservation[] = [];\n const history = record.history ?? [];\n const shadowedLegacyIds = new Set<string>();\n const unmatchedLegacy = history.flatMap((entry, index) => {\n if (entry.type !== 'usage-summary') return [];\n const usage = usageSnapshot(entry.data as TUniversalValue);\n return usage ? [{ id: entry.id, index, usage }] : [];\n });\n for (const [canonicalIndex, entry] of history.entries()) {\n if (entry.type !== 'usage-observation') continue;\n const canonical = decodeObservation(entry.data as TUniversalValue);\n if (!canonical?.usage) continue;\n const canonicalKey = JSON.stringify(canonical.usage);\n const candidates = unmatchedLegacy\n .map((candidate, index) => ({ candidate, index }))\n .filter(({ candidate }) => JSON.stringify(candidate.usage) === canonicalKey)\n .sort(\n (left, right) =>\n Math.abs(left.candidate.index - canonicalIndex) -\n Math.abs(right.candidate.index - canonicalIndex),\n );\n const match = candidates[0];\n if (!match) continue;\n shadowedLegacyIds.add(match.candidate.id);\n unmatchedLegacy.splice(match.index, 1);\n }\n for (const entry of history) {\n const at = entryDate(entry);\n if (!at) continue;\n const observation =\n entry.type === 'usage-observation'\n ? decodeObservation(entry.data as TUniversalValue)\n : undefined;\n if (observation) {\n observations.push({\n id: observation.usageObservationId,\n sessionId: record.id,\n at,\n legacy: false,\n observation,\n });\n continue;\n }\n if (entry.type !== 'usage-summary' || shadowedLegacyIds.has(entry.id)) continue;\n const usage = usageSnapshot(entry.data as TUniversalValue);\n if (!usage) continue;\n const id = `legacy:${record.id}:${entry.id}`;\n observations.push({\n id,\n sessionId: record.id,\n at,\n legacy: true,\n observation: {\n usageObservationId: id,\n turnId: `legacy:${entry.id}`,\n outcome: 'success',\n usage,\n ...(usage.source ? { source: usage.source } : {}),\n surface: 'unknown',\n },\n });\n }\n return observations;\n}\n\nexport function normalizeActivities(record: IInteractiveSessionRecord): INormalizedActivity[] {\n const activities: INormalizedActivity[] = [];\n for (const entry of record.history ?? []) {\n const data = entry.data as TUniversalValue;\n if (entry.type !== 'tool-start' || !isRecord(data)) continue;\n const toolName = optionalString(data['toolName']);\n const at = entryDate(entry);\n if (!toolName || !at) continue;\n activities.push({\n id: `tool:${record.id}:${entry.id}`,\n sessionId: record.id,\n key: `tool:${toolName}`,\n label: toolName,\n kind: 'tool',\n at,\n });\n }\n // Activation history mirrors this canonical source and is intentionally not counted again.\n for (const event of record.skillActivationEvents ?? []) {\n if (event.status !== 'started') continue;\n const at = new Date(event.timestamp);\n if (Number.isNaN(at.getTime())) continue;\n activities.push({\n id: `activation:${record.id}:${event.timestamp}:${event.source}:${event.qualifiedName ?? event.skillName}:${event.invocation}`,\n sessionId: record.id,\n key: event.qualifiedName ?? `${event.source}:${event.skillName}`,\n label: event.qualifiedName ?? event.skillName,\n kind: event.source,\n at,\n });\n }\n return activities;\n}\n","import {\n normalizeActivities,\n normalizeRecord,\n type INormalizedActivity,\n type INormalizedObservation,\n} from './personal-usage-decode.js';\n\nimport type {\n IPersonalUsageDimension,\n IPersonalUsageActivity,\n IPersonalUsageReport,\n IPersonalUsageRequest,\n IPersonalUsageTotals,\n IUsageSource,\n} from '@robota-sdk/agent-interface-analytics';\nimport type { IInteractiveSessionRecord } from '@robota-sdk/agent-interface-session';\n\nconst SHORT_PERIOD_DAYS = 7;\nconst LONG_PERIOD_DAYS = 30;\nconst ISO_DATE_LENGTH = 'YYYY-MM-DD'.length;\n\nexport interface IPersonalUsageSnapshot {\n readonly request: IPersonalUsageRequest;\n readonly now: Date;\n readonly records: readonly IInteractiveSessionRecord[];\n readonly corruptSessionIds?: readonly string[];\n readonly unsupportedSessionIds?: readonly string[];\n}\n\ninterface IMutableTotals {\n sessions: Set<string>;\n observations: number;\n turns: number;\n promptTokens: number;\n completionTokens: number;\n totalTokens: number;\n costUsd: number;\n hasUnknownCost: boolean;\n hasEstimatedCost: boolean;\n /** Turns (not advisor/tool shares) whose cost could not be priced; a subset of `hasUnknownCost`. */\n unpricedTurns: number;\n}\n\nfunction createMutableTotals(): IMutableTotals {\n return {\n sessions: new Set<string>(),\n observations: 0,\n turns: 0,\n promptTokens: 0,\n completionTokens: 0,\n totalTokens: 0,\n costUsd: 0,\n hasUnknownCost: false,\n hasEstimatedCost: false,\n unpricedTurns: 0,\n };\n}\n\nfunction dateKey(date: Date, timezone: string): string {\n const parts = new Intl.DateTimeFormat('en-CA', {\n timeZone: timezone,\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n }).formatToParts(date);\n const part = (type: Intl.DateTimeFormatPartTypes): string =>\n parts.find((candidate) => candidate.type === type)?.value ?? '';\n return `${part('year')}-${part('month')}-${part('day')}`;\n}\n\nfunction calendarKeys(now: Date, timezone: string, count: number): string[] {\n // First resolve the current LOCAL date (also validates the IANA timezone), then perform date-only\n // arithmetic in UTC. Subtracting 24-hour instants can skip a local calendar date during the first\n // hour after a spring-forward transition; date-only arithmetic cannot.\n const [year, month, day] = dateKey(now, timezone).split('-').map(Number);\n const localDate = new Date(Date.UTC(year!, month! - 1, day!));\n return Array.from({ length: count }, (_, index) => {\n const value = new Date(localDate);\n value.setUTCDate(value.getUTCDate() - (count - index - 1));\n return value.toISOString().slice(0, ISO_DATE_LENGTH);\n });\n}\n\nfunction activityDimensions(items: readonly INormalizedActivity[]): IPersonalUsageActivity[] {\n const counts = new Map<string, { item: INormalizedActivity; count: number }>();\n for (const item of items) {\n const current = counts.get(item.key);\n counts.set(item.key, { item, count: (current?.count ?? 0) + 1 });\n }\n return [...counts.values()]\n .map(({ item, count }) => ({\n key: item.key,\n label: item.label,\n kind: item.kind,\n count,\n }))\n .sort((left, right) => right.count - left.count || left.key.localeCompare(right.key));\n}\n\nfunction addObservation(target: IMutableTotals, item: INormalizedObservation): void {\n const usage = item.observation.usage;\n target.sessions.add(item.sessionId);\n target.observations += 1;\n // A consulted model's usage (the advisor, a tool source) belongs to the turn that consulted it;\n // it adds tokens and cost, not a turn.\n const isTurn = !item.legacy && item.observation.source?.scope !== 'tool';\n if (isTurn) target.turns += 1;\n target.promptTokens += usage?.promptTokens ?? 0;\n target.completionTokens += usage?.completionTokens ?? 0;\n target.totalTokens += usage?.totalTokens ?? 0;\n target.costUsd += usage?.costUsd ?? 0;\n if (usage?.costStatus === 'estimated') {\n target.hasEstimatedCost = true;\n } else {\n target.hasUnknownCost = true;\n if (isTurn) target.unpricedTurns += 1;\n }\n}\n\n/**\n * Group a turn by model or provider. A turn that ran on more than one model is split by its shares,\n * so each model is charged only what it spent; the turn still counts once in every group it touched.\n */\nfunction modelDimensions(\n items: readonly INormalizedObservation[],\n keyOf: (share: { providerId?: string; modelId?: string }) => string,\n): IPersonalUsageDimension[] {\n const parts: INormalizedObservation[] = [];\n for (const item of items) {\n const shares = item.observation.modelShares;\n if (shares === undefined) {\n parts.push(item);\n continue;\n }\n const byKey = new Map<string, INormalizedObservation>();\n for (const share of shares) {\n const key = keyOf(share);\n const current = byKey.get(key)?.observation.usage;\n const usage = item.observation.usage;\n const costStatus =\n share.costStatus === 'unknown' || current?.costStatus === 'unknown'\n ? ('unknown' as const)\n : ('estimated' as const);\n byKey.set(key, {\n ...item,\n observation: {\n ...item.observation,\n providerId: share.providerId,\n modelId: share.modelId,\n usage: {\n kind: usage?.kind ?? 'estimated',\n scope: 'turn',\n contextUsedTokens: usage?.contextUsedTokens ?? 0,\n contextMaxTokens: usage?.contextMaxTokens ?? 0,\n contextUsedPercentage: usage?.contextUsedPercentage ?? 0,\n promptTokens: (current?.promptTokens ?? 0) + share.promptTokens,\n completionTokens: (current?.completionTokens ?? 0) + share.completionTokens,\n totalTokens: (current?.totalTokens ?? 0) + share.totalTokens,\n costStatus,\n ...(costStatus === 'estimated' && {\n costUsd: (current?.costUsd ?? 0) + (share.costUsd ?? 0),\n }),\n },\n },\n });\n }\n parts.push(...byKey.values());\n }\n return dimensions(parts, (item) => keyOf(item.observation));\n}\n\nfunction freezeTotals(totals: IMutableTotals): IPersonalUsageTotals {\n return {\n sessions: totals.sessions.size,\n turns: totals.turns,\n promptTokens: totals.promptTokens,\n completionTokens: totals.completionTokens,\n totalTokens: totals.totalTokens,\n costUsd: totals.costUsd,\n // `costUsd` already sums every priced turn regardless of what else in the aggregate is unpriced,\n // so one unpriced observation (a legacy row, an unknown model, an unpriced advisor call) must never\n // by itself turn an otherwise-priced total into `unknown` — only the absence of ANY priced turn does.\n costStatus: totals.hasEstimatedCost ? 'estimated' : 'unknown',\n ...(totals.unpricedTurns > 0 ? { unpricedTurns: totals.unpricedTurns } : {}),\n };\n}\n\nfunction dimensions(\n items: readonly INormalizedObservation[],\n keyOf: (item: INormalizedObservation) => string,\n): IPersonalUsageDimension[] {\n const groups = new Map<string, IMutableTotals>();\n for (const item of items) {\n const key = keyOf(item);\n const totals = groups.get(key) ?? createMutableTotals();\n addObservation(totals, item);\n groups.set(key, totals);\n }\n return [...groups.entries()]\n .map(([key, totals]) => {\n const frozen = freezeTotals(totals);\n return { key, label: key, frozen, sessionIds: [...totals.sessions].sort() };\n })\n .map(({ key, label, frozen, sessionIds }) => ({\n key,\n label,\n turns: frozen.turns,\n promptTokens: frozen.promptTokens,\n completionTokens: frozen.completionTokens,\n totalTokens: frozen.totalTokens,\n costUsd: frozen.costUsd,\n costStatus: frozen.costStatus,\n sessionIds,\n }))\n .sort(\n (left, right) => right.totalTokens - left.totalTokens || left.key.localeCompare(right.key),\n );\n}\n\nfunction sourceKey(source: IUsageSource | undefined): string {\n if (!source) return 'unknown';\n return source.id ? `${source.scope}:${source.id}` : source.scope;\n}\n\ninterface ISelectedUsage {\n readonly observations: INormalizedObservation[];\n readonly activities: INormalizedActivity[];\n readonly duplicateObservations: number;\n readonly legacyObservations: number;\n}\n\nfunction isIncluded(at: Date, input: IPersonalUsageSnapshot, dates: ReadonlySet<string>): boolean {\n return at.getTime() <= input.now.getTime() && dates.has(dateKey(at, input.request.timezone));\n}\n\nfunction selectUsage(input: IPersonalUsageSnapshot, dates: ReadonlySet<string>): ISelectedUsage {\n const observations: INormalizedObservation[] = [];\n const activities: INormalizedActivity[] = [];\n const seenObservations = new Set<string>();\n const seenActivities = new Set<string>();\n let duplicateObservations = 0;\n let legacyObservations = 0;\n for (const record of input.records) {\n for (const item of normalizeRecord(record)) {\n if (!isIncluded(item.at, input, dates)) continue;\n if (seenObservations.has(item.id)) {\n duplicateObservations += 1;\n continue;\n }\n seenObservations.add(item.id);\n observations.push(item);\n if (item.legacy) legacyObservations += 1;\n }\n for (const activity of normalizeActivities(record)) {\n if (!isIncluded(activity.at, input, dates) || seenActivities.has(activity.id)) continue;\n seenActivities.add(activity.id);\n activities.push(activity);\n }\n }\n return { observations, activities, duplicateObservations, legacyObservations };\n}\n\n/**\n * The earliest included observation or activity time for each session, ISO-formatted. A timestamp,\n * not content — the one thing this report can say about a session outside a GUI's own local listing.\n */\nfunction firstSeenBySession(selection: ISelectedUsage): Record<string, string> {\n const earliest = new Map<string, number>();\n const note = (sessionId: string, at: Date): void => {\n const time = at.getTime();\n const current = earliest.get(sessionId);\n if (current === undefined || time < current) earliest.set(sessionId, time);\n };\n for (const item of selection.observations) note(item.sessionId, item.at);\n for (const activity of selection.activities) note(activity.sessionId, activity.at);\n const result: Record<string, string> = {};\n for (const [sessionId, time] of earliest) result[sessionId] = new Date(time).toISOString();\n return result;\n}\n\nfunction accumulateUsage(\n input: IPersonalUsageSnapshot,\n keys: readonly string[],\n selection: ISelectedUsage,\n): { totals: IMutableTotals; byDay: Map<string, IMutableTotals> } {\n const totals = createMutableTotals();\n const byDay = new Map(keys.map((key) => [key, createMutableTotals()]));\n for (const item of selection.observations) {\n addObservation(totals, item);\n addObservation(byDay.get(dateKey(item.at, input.request.timezone))!, item);\n }\n for (const activity of selection.activities) {\n totals.sessions.add(activity.sessionId);\n byDay.get(dateKey(activity.at, input.request.timezone))?.sessions.add(activity.sessionId);\n }\n return { totals, byDay };\n}\n\nexport function summarizePersonalUsage(input: IPersonalUsageSnapshot): IPersonalUsageReport {\n const count = input.request.period === '30d' ? LONG_PERIOD_DAYS : SHORT_PERIOD_DAYS;\n const keys = calendarKeys(input.now, input.request.timezone, count);\n const selection = selectUsage(input, new Set(keys));\n const { totals, byDay } = accumulateUsage(input, keys, selection);\n const selected = selection.observations;\n\n return {\n schemaVersion: 1,\n generatedAt: input.now.toISOString(),\n period: input.request.period,\n timezone: input.request.timezone,\n interval: { startDate: keys[0]!, endDate: keys.at(-1)! },\n totals: freezeTotals(totals),\n daily: keys.map((date, index) => ({\n date,\n partial: index === keys.length - 1,\n totals: freezeTotals(byDay.get(date)!),\n sessionIds: [...byDay.get(date)!.sessions].sort(),\n })),\n byModel: modelDimensions(selected, (share) => share.modelId ?? 'unknown'),\n byProvider: modelDimensions(selected, (share) => share.providerId ?? 'unknown'),\n bySurface: dimensions(selected, (item) => item.observation.surface ?? 'unknown'),\n bySource: dimensions(selected, (item) => sourceKey(item.observation.source)),\n byActivity: activityDimensions(selection.activities),\n sessionIds: [...totals.sessions].sort(),\n sessionFirstSeen: firstSeenBySession(selection),\n coverage: {\n validSessions: input.records.length,\n corruptSessions: input.corruptSessionIds?.length ?? 0,\n unsupportedSessions: input.unsupportedSessionIds?.length ?? 0,\n duplicateObservations: selection.duplicateObservations,\n legacyObservations: selection.legacyObservations,\n unknownModelObservations: selected.filter(\n (item) => !item.observation.modelId && !item.observation.modelShares,\n ).length,\n unknownProviderObservations: selected.filter(\n (item) => !item.observation.providerId && !item.observation.modelShares,\n ).length,\n unknownSurfaceObservations: selected.filter(\n (item) => !item.observation.surface || item.observation.surface === 'unknown',\n ).length,\n corruptSessionIds: [...(input.corruptSessionIds ?? [])].sort(),\n unsupportedSessionIds: [...(input.unsupportedSessionIds ?? [])].sort(),\n },\n };\n}\n","import { calculateModelCost, MODEL_PRICES } from '@robota-sdk/agent-core';\n\nimport type { IInteractiveSessionRecord } from '@robota-sdk/agent-interface-session';\n\nconst MAX_UINT64 = (1n << 64n) - 1n;\nconst TRACE_ID = /^(?!0{32}$)[0-9a-f]{32}$/;\nconst SPAN_ID = /^(?!0{16}$)[0-9a-f]{16}$/;\nconst ROOT_FIELDS = [\n 'promptExecutionStartedAt',\n 'promptExecutionEndedAt',\n 'promptExecutionOutcome',\n 'promptExecutionTraceId',\n 'promptExecutionSpanId',\n] as const;\n\ninterface ICandidate {\n readonly record: IInteractiveSessionRecord;\n readonly data: unknown;\n readonly observationKey?: string;\n readonly traceId?: string;\n}\n\ninterface IOtlpSpan {\n readonly traceId: string;\n readonly spanId: string;\n readonly parentSpanId?: string;\n readonly name: 'robota.prompt_execution' | 'robota.provider_call' | 'robota.tool_body';\n readonly kind: 1;\n readonly startTimeUnixNano: string;\n readonly endTimeUnixNano: string;\n readonly attributes: readonly {\n readonly key: string;\n readonly value: { readonly stringValue: string } | { readonly intValue: string } | { readonly doubleValue: number };\n }[];\n readonly status: { readonly code: number };\n}\n\nexport interface IOtlpPromptRootTraces {\n readonly resourceSpans: readonly {\n readonly resource: {\n readonly attributes: readonly {\n readonly key: string;\n readonly value: { readonly stringValue: string };\n }[];\n };\n readonly scopeSpans: readonly {\n readonly scope: { readonly name: string };\n readonly spans: readonly IOtlpSpan[];\n }[];\n }[];\n}\n\nexport interface IPromptRootTraceCoverage {\n readonly exported: number;\n readonly missing: number;\n readonly invalid: number;\n readonly duplicate: number;\n readonly providerChildren: {\n readonly exported: number;\n readonly invalid: number;\n readonly orphaned: number;\n readonly duplicate: number;\n };\n readonly providerUsage: {\n readonly legacy: number;\n readonly invalid: number;\n readonly partial: number;\n readonly absent: number;\n readonly nonInvoked: number;\n };\n readonly toolChildren: {\n readonly exported: number;\n readonly invalid: number;\n readonly orphaned: number;\n readonly duplicate: number;\n };\n}\n\nexport interface IAcceptedProviderCallMetrics {\n readonly invoked: number;\n readonly completeUsage: number;\n readonly inputTokens: number;\n readonly outputTokens: number;\n readonly estimatedCostUsd: number;\n readonly unknownCost: number;\n readonly exactPriceMatches: number;\n readonly familyPriceMatches: number;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction count<K>(map: Map<K, number>, key: K): void {\n map.set(key, (map.get(key) ?? 0) + 1);\n}\n\nfunction otlpUnixNano(value: unknown): bigint | undefined {\n if (typeof value !== 'string') return undefined;\n const date = new Date(value);\n if (Number.isNaN(date.getTime()) || date.toISOString() !== value) return undefined;\n const nanos = BigInt(date.getTime()) * 1_000_000n;\n return nanos >= 0n && nanos <= MAX_UINT64 ? nanos : undefined;\n}\n\nfunction rootSpan(data: Record<string, unknown>): IOtlpSpan | undefined {\n const started = otlpUnixNano(data['promptExecutionStartedAt']);\n const ended = otlpUnixNano(data['promptExecutionEndedAt']);\n const outcome = data['promptExecutionOutcome'];\n const traceId = data['promptExecutionTraceId'];\n const spanId = data['promptExecutionSpanId'];\n if (\n started === undefined ||\n ended === undefined ||\n started > ended ||\n (outcome !== 'success' && outcome !== 'failure' && outcome !== 'interrupted') ||\n typeof traceId !== 'string' ||\n !TRACE_ID.test(traceId) ||\n typeof spanId !== 'string' ||\n !SPAN_ID.test(spanId) ||\n typeof data['usageObservationId'] !== 'string' ||\n data['usageObservationId'].length === 0 ||\n data['turnId'] !== data['usageObservationId'] ||\n (data['outcome'] !== 'success' &&\n data['outcome'] !== 'failure' &&\n data['outcome'] !== 'interrupted')\n ) {\n return undefined;\n }\n return {\n traceId,\n spanId,\n name: 'robota.prompt_execution',\n kind: 1,\n startTimeUnixNano: String(started),\n endTimeUnixNano: String(ended),\n attributes: [{ key: 'robota.prompt.outcome', value: { stringValue: outcome } }],\n status: { code: outcome === 'success' ? 1 : outcome === 'failure' ? 2 : 0 },\n };\n}\n\nfunction childSpan(data: unknown, kind: 'provider' | 'tool'): IOtlpSpan | undefined {\n if (!isRecord(data)) return undefined;\n const traceId = data['traceId'];\n const parentSpanId = data['parentSpanId'];\n const spanId = data['spanId'];\n const started = otlpUnixNano(data['startedAt']);\n const ended = otlpUnixNano(data['endedAt']);\n const outcome = data['outcome'];\n if (\n typeof traceId !== 'string' ||\n !TRACE_ID.test(traceId) ||\n typeof parentSpanId !== 'string' ||\n !SPAN_ID.test(parentSpanId) ||\n typeof spanId !== 'string' ||\n !SPAN_ID.test(spanId) ||\n started === undefined ||\n ended === undefined ||\n started > ended ||\n (outcome !== 'success' && outcome !== 'failure' && outcome !== 'interrupted') ||\n (kind === 'provider' && (!Number.isSafeInteger(data['round']) || (data['round'] as number) < 1))\n ) {\n return undefined;\n }\n return {\n traceId,\n parentSpanId,\n spanId,\n name: kind === 'provider' ? 'robota.provider_call' : 'robota.tool_body',\n kind: 1,\n startTimeUnixNano: String(started),\n endTimeUnixNano: String(ended),\n attributes: [\n {\n key: kind === 'provider' ? 'robota.provider.outcome' : 'robota.tool.outcome',\n value: { stringValue: outcome },\n },\n ],\n status: { code: outcome === 'success' ? 1 : outcome === 'failure' ? 2 : 0 },\n };\n}\n\nfunction childIdentity(data: unknown): string | undefined {\n if (!isRecord(data)) return undefined;\n const traceId = data['traceId'];\n const spanId = data['spanId'];\n return typeof traceId === 'string' &&\n TRACE_ID.test(traceId) &&\n typeof spanId === 'string' &&\n SPAN_ID.test(spanId)\n ? `${traceId}:${spanId}`\n : undefined;\n}\n\nfunction validToken(value: unknown): value is number {\n return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0;\n}\n\nfunction enrichProviderSpan(\n span: IOtlpSpan,\n data: unknown,\n usageCoverage: { legacy: number; invalid: number; partial: number; absent: number },\n metrics: { -readonly [K in keyof IAcceptedProviderCallMetrics]: number },\n): IOtlpSpan {\n if (!isRecord(data) || data['disposition'] === undefined) {\n usageCoverage.legacy += 1;\n return span;\n }\n if (data['disposition'] !== 'invoked') {\n usageCoverage.invalid += 1;\n return span;\n }\n metrics.invoked += 1;\n const provenance = data['usageProvenance'];\n if (provenance === 'partial') {\n usageCoverage.partial += 1;\n metrics.unknownCost += 1;\n return span;\n }\n if (provenance === 'absent' || provenance === undefined) {\n usageCoverage.absent += 1;\n metrics.unknownCost += 1;\n return span;\n }\n const input = data['promptTokens'];\n const output = data['completionTokens'];\n const total = data['totalTokens'];\n if (\n provenance !== 'complete' || !validToken(input) || !validToken(output) ||\n !Number.isSafeInteger(input + output) || total !== input + output\n ) {\n usageCoverage.invalid += 1;\n metrics.unknownCost += 1;\n return span;\n }\n metrics.completeUsage += 1;\n metrics.inputTokens += input;\n metrics.outputTokens += output;\n const attrs: IOtlpSpan['attributes'][number][] = [\n ...span.attributes,\n { key: 'robota.provider.usage.input_tokens', value: { intValue: String(input) } },\n { key: 'robota.provider.usage.output_tokens', value: { intValue: String(output) } },\n ];\n const model = data['modelId'];\n const estimated = typeof model === 'string' && model.length > 0 && model.length <= 128 &&\n [...model].every((char) => char.charCodeAt(0) >= 32)\n ? calculateModelCost(model, input, output) : undefined;\n if (estimated === undefined || !Number.isFinite(estimated) || estimated < 0) {\n metrics.unknownCost += 1;\n } else {\n metrics.estimatedCostUsd += estimated;\n if (typeof model === 'string' && Object.hasOwn(MODEL_PRICES, model)) metrics.exactPriceMatches += 1;\n else metrics.familyPriceMatches += 1;\n attrs.push({ key: 'robota.provider.cost.usd.estimated', value: { doubleValue: estimated } });\n }\n return { ...span, attributes: attrs };\n}\n\n/** Project only proven canonical prompt roots; never infer spans from legacy usage or tool events. */\nexport function createOtlpPromptRootTraces(\n records: readonly IInteractiveSessionRecord[],\n version: string,\n): { readonly payload: IOtlpPromptRootTraces; readonly coverage: IPromptRootTraceCoverage; readonly callMetrics: IAcceptedProviderCallMetrics } {\n const candidates: ICandidate[] = [];\n const observationCounts = new Map<string, number>();\n const traceCounts = new Map<string, number>();\n for (const record of records) {\n for (const entry of record.history ?? []) {\n if (entry.type !== 'usage-observation') continue;\n const data: unknown = entry.data;\n const observationId = isRecord(data) ? data['usageObservationId'] : undefined;\n const traceId = isRecord(data) ? data['promptExecutionTraceId'] : undefined;\n const observationKey =\n typeof observationId === 'string' && observationId.length > 0\n ? JSON.stringify([record.id, observationId])\n : undefined;\n const validTraceId =\n typeof traceId === 'string' && TRACE_ID.test(traceId) ? traceId : undefined;\n if (observationKey) count(observationCounts, observationKey);\n if (validTraceId) count(traceCounts, validTraceId);\n candidates.push({ record, data, observationKey, traceId: validTraceId });\n }\n }\n\n const spans: IOtlpSpan[] = [];\n const rootsByRecord = new Map<IInteractiveSessionRecord, Map<string, IOtlpSpan>>();\n let missing = 0;\n let invalid = 0;\n let duplicate = 0;\n for (const candidate of candidates) {\n if (\n (candidate.observationKey && (observationCounts.get(candidate.observationKey) ?? 0) > 1) ||\n (candidate.traceId && (traceCounts.get(candidate.traceId) ?? 0) > 1)\n ) {\n duplicate += 1;\n continue;\n }\n const data = candidate.data;\n if (!isRecord(data)) {\n invalid += 1;\n continue;\n }\n if (ROOT_FIELDS.every((field) => data[field] === undefined)) {\n missing += 1;\n continue;\n }\n const span = rootSpan(data);\n if (!span) {\n invalid += 1;\n continue;\n }\n spans.push(span);\n const recordRoots = rootsByRecord.get(candidate.record) ?? new Map<string, IOtlpSpan>();\n recordRoots.set(span.traceId, span);\n rootsByRecord.set(candidate.record, recordRoots);\n }\n\n const children: {\n readonly record: IInteractiveSessionRecord;\n readonly span: IOtlpSpan | undefined;\n readonly identity: string | undefined;\n readonly kind: 'provider' | 'tool';\n readonly data: unknown;\n }[] = [];\n const childCounts = new Map<string, number>();\n for (const record of records) {\n for (const entry of record.history ?? []) {\n const kind =\n entry.type === 'provider-call-trace'\n ? 'provider'\n : entry.type === 'tool-body-trace'\n ? 'tool'\n : undefined;\n if (!kind) continue;\n const identity = childIdentity(entry.data);\n const span = childSpan(entry.data, kind);\n if (identity) count(childCounts, identity);\n children.push({ record, span, identity, kind, data: entry.data });\n }\n }\n const coverageByKind = {\n provider: { exported: 0, invalid: 0, orphaned: 0, duplicate: 0 },\n tool: { exported: 0, invalid: 0, orphaned: 0, duplicate: 0 },\n };\n const providerUsage = { legacy: 0, invalid: 0, partial: 0, absent: 0, nonInvoked: 0 };\n const callMetrics = {\n invoked: 0, completeUsage: 0, inputTokens: 0, outputTokens: 0,\n estimatedCostUsd: 0, unknownCost: 0, exactPriceMatches: 0, familyPriceMatches: 0,\n };\n for (const child of children) {\n const { span } = child;\n const coverage = coverageByKind[child.kind];\n if (child.identity && (childCounts.get(child.identity) ?? 0) > 1) {\n coverage.duplicate += 1;\n continue;\n }\n if (!span) {\n coverage.invalid += 1;\n continue;\n }\n const root = rootsByRecord.get(child.record)?.get(span.traceId);\n if (!root || span.parentSpanId !== root.spanId || span.spanId === root.spanId) {\n coverage.orphaned += 1;\n continue;\n }\n if (\n BigInt(span.startTimeUnixNano) < BigInt(root.startTimeUnixNano) ||\n BigInt(span.endTimeUnixNano) > BigInt(root.endTimeUnixNano)\n ) {\n coverage.invalid += 1;\n continue;\n }\n if (child.kind === 'provider' && isRecord(child.data) &&\n (child.data['disposition'] === 'cache-hit' || child.data['disposition'] === 'preflight-refused')) {\n providerUsage.nonInvoked += 1;\n if (child.data['promptTokens'] !== undefined || child.data['completionTokens'] !== undefined ||\n child.data['totalTokens'] !== undefined || child.data['usageProvenance'] === 'complete') {\n providerUsage.invalid += 1;\n }\n continue;\n }\n spans.push(child.kind === 'provider'\n ? enrichProviderSpan(span, child.data, providerUsage, callMetrics)\n : span);\n coverage.exported += 1;\n }\n\n return {\n payload: {\n resourceSpans: spans.length\n ? [\n {\n resource: {\n attributes: [\n { key: 'service.name', value: { stringValue: 'robota' } },\n { key: 'service.version', value: { stringValue: version } },\n ],\n },\n scopeSpans: [{ scope: { name: '@robota-sdk/agent-session-analytics' }, spans }],\n },\n ]\n : [],\n },\n coverage: {\n exported: spans.length - coverageByKind.provider.exported - coverageByKind.tool.exported,\n missing,\n invalid,\n duplicate,\n providerChildren: coverageByKind.provider,\n providerUsage,\n toolChildren: coverageByKind.tool,\n },\n callMetrics,\n };\n}\n","import { createOtlpPromptRootTraces } from './otlp-prompt-root-traces.js';\nimport { normalizeRecord } from './personal-usage-decode.js';\n\nimport type { IInteractiveSessionRecord } from '@robota-sdk/agent-interface-session';\n\n/** A non-additive, content-free snapshot. Consumers must read the latest Gauge, not sum exports. */\nexport function createOtlpUsageSnapshot(\n records: readonly IInteractiveSessionRecord[],\n at: Date,\n version: string,\n): { resourceMetrics: unknown[] } {\n const seen = new Set<string>();\n let turns = 0;\n let totalTokens = 0;\n let inputTokens = 0;\n let outputTokens = 0;\n let unknownTokenSplitObservations = 0;\n let knownCost = 0;\n let unknownCostObservations = 0;\n let estimatedCostObservations = 0;\n\n for (const record of records) {\n for (const item of normalizeRecord(record)) {\n if (seen.has(item.id)) continue;\n seen.add(item.id);\n if (!item.legacy) turns += 1;\n const usage = item.observation.usage;\n if (!usage) {\n unknownCostObservations += 1;\n unknownTokenSplitObservations += 1;\n continue;\n }\n totalTokens += usage.totalTokens;\n inputTokens += usage.promptTokens ?? 0;\n outputTokens += usage.completionTokens ?? 0;\n if (usage.promptTokens === undefined || usage.completionTokens === undefined) {\n unknownTokenSplitObservations += 1;\n }\n if (usage.costStatus === 'unknown' || usage.costUsd === undefined) {\n unknownCostObservations += 1;\n } else {\n knownCost += usage.costUsd;\n if (usage.costStatus === 'estimated') estimatedCostObservations += 1;\n }\n }\n }\n // The trace projection is the single accepted-call selector: parent/time/duplicate checks must\n // agree between traces and metrics. These are separate non-additive Gauges, never turn totals.\n const acceptedCalls = createOtlpPromptRootTraces(records, version);\n const calls = acceptedCalls.callMetrics;\n\n const timeUnixNano = String(BigInt(at.getTime()) * 1_000_000n);\n const gauge = (name: string, unit: string, value: number) => ({\n name,\n unit,\n gauge: { dataPoints: [{ timeUnixNano, asDouble: value }] },\n });\n\n return {\n resourceMetrics: [\n {\n resource: {\n attributes: [\n { key: 'service.name', value: { stringValue: 'robota' } },\n { key: 'service.version', value: { stringValue: version } },\n ],\n },\n scopeMetrics: [\n {\n scope: { name: '@robota-sdk/agent-session-analytics' },\n metrics: [\n gauge('robota.session.count', '{session}', records.length),\n gauge('robota.turn.count', '{turn}', turns),\n gauge('robota.token.total', '{token}', totalTokens),\n gauge('robota.token.input.known', '{token}', inputTokens),\n gauge('robota.token.output.known', '{token}', outputTokens),\n gauge(\n 'robota.token.split_unknown_observations',\n '{observation}',\n unknownTokenSplitObservations,\n ),\n gauge('robota.cost.usd.known', 'USD', knownCost),\n gauge('robota.cost.unknown_observations', '{observation}', unknownCostObservations),\n gauge(\n 'robota.cost.estimated_observations',\n '{observation}',\n estimatedCostObservations,\n ),\n gauge('robota.provider_call.count', '{call}', calls.invoked),\n gauge('robota.provider_call.usage.complete_count', '{call}', calls.completeUsage),\n gauge('robota.provider_call.token.input.known', '{token}', calls.inputTokens),\n gauge('robota.provider_call.token.output.known', '{token}', calls.outputTokens),\n gauge('robota.provider_call.cost.usd.estimated', 'USD', calls.estimatedCostUsd),\n gauge('robota.provider_call.cost.unknown_count', '{call}', calls.unknownCost),\n gauge('robota.provider_call.usage.partial_count', '{call}', acceptedCalls.coverage.providerUsage.partial),\n gauge('robota.provider_call.usage.invalid_count', '{call}', acceptedCalls.coverage.providerUsage.invalid),\n gauge('robota.provider_call.usage.legacy_count', '{call}', acceptedCalls.coverage.providerUsage.legacy),\n gauge('robota.provider_call.price.exact_id_count', '{call}', calls.exactPriceMatches),\n gauge('robota.provider_call.price.family_fallback_count', '{call}', calls.familyPriceMatches),\n ],\n },\n ],\n },\n ],\n };\n}\n","import { createOtlpPromptRootTraces } from './otlp-prompt-root-traces.js';\n\nimport type { IPromptRootTraceCoverage } from './otlp-prompt-root-traces.js';\nimport type { IInteractiveSessionRecord } from '@robota-sdk/agent-interface-session';\n\ntype TEventName =\n | 'robota.prompt_execution.completed'\n | 'robota.provider_call.completed'\n | 'robota.tool_body.completed';\n\ninterface IOtlpLogRecord {\n readonly timeUnixNano: string;\n readonly observedTimeUnixNano: string;\n readonly severityNumber: 9 | 13 | 17;\n readonly severityText: 'INFO' | 'WARN' | 'ERROR';\n readonly eventName: TEventName;\n readonly traceId: string;\n readonly spanId: string;\n readonly attributes: readonly {\n readonly key: string;\n readonly value: { readonly stringValue: string };\n }[];\n}\n\nexport interface IOtlpPromptEvents {\n readonly resourceLogs: readonly {\n readonly resource: {\n readonly attributes: readonly {\n readonly key: string;\n readonly value: { readonly stringValue: string };\n }[];\n };\n readonly scopeLogs: readonly {\n readonly scope: { readonly name: string };\n readonly logRecords: readonly IOtlpLogRecord[];\n }[];\n }[];\n}\n\nconst MAX_UINT64 = (1n << 64n) - 1n;\n\nfunction observedUnixNano(observedAt: Date): string {\n const millis = observedAt.getTime();\n if (!Number.isSafeInteger(millis) || millis < 0) {\n throw new RangeError('OTLP log observation time must be a valid post-epoch date.');\n }\n const nanos = BigInt(millis) * 1_000_000n;\n if (nanos > MAX_UINT64) throw new RangeError('OTLP log observation time is out of range.');\n return String(nanos);\n}\n\n/** Explicit local OTLP log projection of canonical prompt completion events. */\nexport function createOtlpPromptEvents(\n records: readonly IInteractiveSessionRecord[],\n version: string,\n observedAt: Date,\n): {\n readonly exported: number;\n readonly coverage: IPromptRootTraceCoverage;\n readonly payload: IOtlpPromptEvents;\n} {\n const traces = createOtlpPromptRootTraces(records, version);\n const spans = traces.payload.resourceSpans[0]?.scopeSpans[0]?.spans ?? [];\n if (spans.length === 0) {\n return { exported: 0, coverage: traces.coverage, payload: { resourceLogs: [] } };\n }\n const observedTimeUnixNano = observedUnixNano(observedAt);\n const logRecords: IOtlpLogRecord[] = spans.map((span) => {\n const outcomeAttribute = span.attributes.find((attribute) =>\n attribute.key === 'robota.prompt.outcome' ||\n attribute.key === 'robota.provider.outcome' ||\n attribute.key === 'robota.tool.outcome');\n const eventName: TEventName =\n span.name === 'robota.prompt_execution'\n ? 'robota.prompt_execution.completed'\n : span.name === 'robota.provider_call'\n ? 'robota.provider_call.completed'\n : 'robota.tool_body.completed';\n const severityNumber = span.status.code === 1 ? 9 : span.status.code === 2 ? 17 : 13;\n const severityText = severityNumber === 9 ? 'INFO' : severityNumber === 17 ? 'ERROR' : 'WARN';\n return {\n timeUnixNano: span.endTimeUnixNano,\n observedTimeUnixNano,\n severityNumber,\n severityText,\n eventName,\n traceId: span.traceId,\n spanId: span.spanId,\n attributes: outcomeAttribute && 'stringValue' in outcomeAttribute.value\n ? [{ key: outcomeAttribute.key, value: { stringValue: outcomeAttribute.value.stringValue } }]\n : [],\n };\n });\n return {\n exported: logRecords.length,\n coverage: traces.coverage,\n payload: {\n resourceLogs: [\n {\n resource: traces.payload.resourceSpans[0]!.resource,\n scopeLogs: [\n {\n scope: { name: '@robota-sdk/agent-session-analytics' },\n logRecords,\n },\n ],\n },\n ],\n },\n };\n}\n","import type {\n IPersonalUsageDimension,\n IPersonalUsageReport,\n} from '@robota-sdk/agent-interface-analytics';\n\nconst COST_DECIMAL_PLACES = 4;\n\nfunction dimensionLines(title: string, values: readonly IPersonalUsageDimension[]): string[] {\n return [\n '',\n title,\n ...(values.length === 0\n ? ['(none)']\n : values.map(\n (value) =>\n `${value.label} ${value.turns} turns ${value.totalTokens} tokens cost ${value.costStatus === 'unknown' ? 'unknown' : `$${value.costUsd.toFixed(COST_DECIMAL_PLACES)}`}`,\n )),\n ];\n}\n\n/** Render the provider-neutral personal-usage report for the terminal surface. */\nexport function formatPersonalUsageReport(report: IPersonalUsageReport): string {\n const cost =\n report.totals.costStatus === 'unknown'\n ? 'unknown'\n : `$${report.totals.costUsd.toFixed(COST_DECIMAL_PLACES)} (${report.totals.costStatus})`;\n return [\n `Personal usage — ${report.period} (${report.timezone})`,\n `${report.interval.startDate} → ${report.interval.endDate}`,\n `Sessions ${report.totals.sessions} · Turns ${report.totals.turns} · Tokens ${report.totals.totalTokens} (${report.totals.promptTokens} input / ${report.totals.completionTokens} output) · Cost ${cost}`,\n '',\n 'Daily usage',\n ...report.daily.map(\n (day) =>\n `${day.date}${day.partial ? ' (partial)' : ''} ${day.totals.turns} turns ${day.totals.totalTokens} tokens`,\n ),\n ...dimensionLines('By model', report.byModel),\n ...dimensionLines('By provider', report.byProvider),\n ...dimensionLines('By surface', report.bySurface),\n ...dimensionLines('By source', report.bySource),\n '',\n 'Activity',\n ...(report.byActivity.length === 0\n ? ['(none)']\n : report.byActivity.map(\n (activity) => `${activity.kind}:${activity.label} ${activity.count} calls`,\n )),\n '',\n `Coverage: legacy ${report.coverage.legacyObservations}, corrupt ${report.coverage.corruptSessions}, unsupported ${report.coverage.unsupportedSessions}, duplicates ${report.coverage.duplicateObservations}`,\n 'Local estimates from recorded sessions; costs are not an invoice.',\n ].join('\\n');\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":["sourceKey","isRecord","MAX_UINT64"],"sources":["../../src/analyze.ts","../../src/report.ts","../../src/usage.ts","../../src/personal-usage-decode.ts","../../src/personal-usage.ts","../../src/otlp-prompt-root-traces.ts","../../src/otlp-usage-snapshot.ts","../../src/otlp-prompt-events.ts","../../src/personal-usage-format.ts"],"sourcesContent":["/**\n * Session-log timing-interval computation and aggregation.\n *\n * Operates on canonical history entries (`IHistoryEntry`); persisted timestamps arrive as ISO\n * strings at runtime (JSON has no Date), so all timestamp math goes through `new Date(...)`.\n */\n\nimport type {\n IAggregateReport,\n TSessionAnalysisInput,\n ISessionTimingReport,\n ITimingInterval,\n ITimingStats,\n TIntervalKind,\n} from './types.js';\nimport type { IHistoryEntry } from '@robota-sdk/agent-core';\n\nconst SLOW_THRESHOLD_MS = 10_000;\n\n/** Gap in milliseconds between two timestamps (ISO string or Date). */\nexport function gapMs(from: string | Date, to: string | Date): number {\n return new Date(to).getTime() - new Date(from).getTime();\n}\n\nfunction toIso(value: string | Date): string {\n return new Date(value).toISOString();\n}\n\nfunction makeInterval(\n kind: TIntervalKind,\n fromType: string,\n toType: string,\n fromTimestamp: string | Date,\n toTimestamp: string | Date,\n turnIndex: number,\n): ITimingInterval {\n return {\n kind,\n fromType,\n toType,\n fromTimestamp: toIso(fromTimestamp),\n toTimestamp: toIso(toTimestamp),\n durationMs: gapMs(fromTimestamp, toTimestamp),\n turnIndex,\n };\n}\n\n/**\n * Compute timing intervals from a history entry array.\n *\n * Strategy: scan the timeline turn by turn. A \"turn\" starts with a user message. After user, we\n * expect zero or more tool-start → tool-end cycles, optionally a tool-summary, then an assistant\n * message.\n */\nexport function computeTimingIntervals(history: readonly IHistoryEntry[]): ITimingInterval[] {\n const intervals: ITimingInterval[] = [];\n let turnIndex = 0;\n\n let i = 0;\n while (i < history.length) {\n const entry = history[i];\n if (!entry) {\n i++;\n continue;\n }\n\n if (entry.category === 'chat' && entry.type === 'user') {\n turnIndex++;\n const userTs = entry.timestamp;\n let foundFirstTool = false;\n let lastToolEndTs: IHistoryEntry['timestamp'] | null = null;\n let j = i + 1;\n\n while (j < history.length) {\n const next = history[j];\n if (!next) {\n j++;\n continue;\n }\n\n if (next.category === 'chat' && next.type === 'user') {\n break;\n }\n\n if (next.category === 'event' && next.type === 'tool-start') {\n if (!foundFirstTool) {\n intervals.push(\n makeInterval(\n 'user_to_first_tool',\n 'user',\n 'tool-start',\n userTs,\n next.timestamp,\n turnIndex,\n ),\n );\n foundFirstTool = true;\n } else if (lastToolEndTs !== null) {\n intervals.push(\n makeInterval(\n 'llm_between_tools',\n 'tool-end',\n 'tool-start',\n lastToolEndTs,\n next.timestamp,\n turnIndex,\n ),\n );\n }\n lastToolEndTs = null;\n j++;\n continue;\n }\n\n if (next.category === 'event' && next.type === 'tool-end') {\n const prev = history[j - 1];\n if (prev && prev.category === 'event' && prev.type === 'tool-start') {\n intervals.push(\n makeInterval(\n 'tool_exec',\n 'tool-start',\n 'tool-end',\n prev.timestamp,\n next.timestamp,\n turnIndex,\n ),\n );\n }\n lastToolEndTs = next.timestamp;\n j++;\n continue;\n }\n\n if (next.category === 'event' && next.type === 'tool-summary') {\n if (lastToolEndTs !== null) {\n intervals.push(\n makeInterval(\n 'llm_final_response',\n 'tool-end',\n 'tool-summary',\n lastToolEndTs,\n next.timestamp,\n turnIndex,\n ),\n );\n }\n j++;\n continue;\n }\n\n if (next.category === 'chat' && next.type === 'assistant') {\n if (!foundFirstTool) {\n intervals.push(\n makeInterval(\n 'user_to_assistant',\n 'user',\n 'assistant',\n userTs,\n next.timestamp,\n turnIndex,\n ),\n );\n } else if (lastToolEndTs !== null) {\n intervals.push(\n makeInterval(\n 'llm_final_response',\n 'tool-end',\n 'assistant',\n lastToolEndTs,\n next.timestamp,\n turnIndex,\n ),\n );\n }\n j++;\n break;\n }\n\n j++;\n }\n\n i = j;\n } else {\n i++;\n }\n }\n\n return intervals;\n}\n\nfunction computeStats(intervals: ITimingInterval[]): ITimingStats {\n const llm = intervals.filter(\n (iv) =>\n iv.kind === 'user_to_first_tool' ||\n iv.kind === 'user_to_assistant' ||\n iv.kind === 'llm_between_tools' ||\n iv.kind === 'llm_final_response',\n );\n const tool = intervals.filter((iv) => iv.kind === 'tool_exec');\n const direct = intervals.filter((iv) => iv.kind === 'user_to_assistant');\n\n const avg = (arr: ITimingInterval[]): number =>\n arr.length ? Math.round(arr.reduce((s, iv) => s + iv.durationMs, 0) / arr.length) : 0;\n const max = (arr: ITimingInterval[]): number =>\n arr.length ? Math.max(...arr.map((iv) => iv.durationMs)) : 0;\n const median = (arr: ITimingInterval[]): number => {\n if (!arr.length) return 0;\n const sorted = [...arr].sort((a, b) => a.durationMs - b.durationMs);\n const mid = Math.floor(sorted.length / 2);\n return sorted.length % 2 === 0\n ? Math.round(((sorted[mid - 1]?.durationMs ?? 0) + (sorted[mid]?.durationMs ?? 0)) / 2)\n : (sorted[mid]?.durationMs ?? 0);\n };\n\n return {\n llmWaitMs: {\n avg: avg(llm),\n max: max(llm),\n total: llm.reduce((s, iv) => s + iv.durationMs, 0),\n count: llm.length,\n },\n toolExecMs: { avg: avg(tool), max: max(tool), median: median(tool), count: tool.length },\n userToAssistantMs: { avg: avg(direct), max: max(direct), count: direct.length },\n };\n}\n\n/** Compute the timing report for a single session record. */\nexport function analyzeSession(record: TSessionAnalysisInput): ISessionTimingReport {\n const history = record.history ?? [];\n const intervals = computeTimingIntervals(history);\n const slowIntervals = intervals.filter((iv) => iv.durationMs >= SLOW_THRESHOLD_MS);\n\n return {\n sessionId: record.id,\n cwd: record.cwd,\n createdAt: record.createdAt,\n totalIntervals: intervals.length,\n intervals,\n slowIntervals,\n stats: computeStats(intervals),\n };\n}\n\n/** Aggregate multiple single-session reports into a fleet-level summary. */\nexport function aggregateReports(reports: readonly ISessionTimingReport[]): IAggregateReport {\n const llmIntervals = reports.flatMap((r) =>\n r.intervals.filter(\n (iv) =>\n iv.kind === 'user_to_first_tool' ||\n iv.kind === 'user_to_assistant' ||\n iv.kind === 'llm_between_tools' ||\n iv.kind === 'llm_final_response',\n ),\n );\n const toolIntervals = reports.flatMap((r) => r.intervals.filter((iv) => iv.kind === 'tool_exec'));\n\n const avgLlmResponseMs = llmIntervals.length\n ? Math.round(llmIntervals.reduce((s, iv) => s + iv.durationMs, 0) / llmIntervals.length)\n : 0;\n const avgToolExecMs = toolIntervals.length\n ? Math.round(toolIntervals.reduce((s, iv) => s + iv.durationMs, 0) / toolIntervals.length)\n : 0;\n\n let maxSingleDelayMs = 0;\n let maxSingleDelaySession = '';\n let maxSingleDelayTurn = 0;\n let maxSingleDelayKind = '';\n\n for (const r of reports) {\n for (const iv of r.intervals) {\n if (iv.durationMs > maxSingleDelayMs) {\n maxSingleDelayMs = iv.durationMs;\n maxSingleDelaySession = r.sessionId;\n maxSingleDelayTurn = iv.turnIndex;\n maxSingleDelayKind = iv.kind;\n }\n }\n }\n\n const dates = reports.map((r) => r.createdAt).sort();\n\n return {\n sessionCount: reports.length,\n fromDate: dates[0] ?? '',\n toDate: dates[dates.length - 1] ?? '',\n avgLlmResponseMs,\n avgToolExecMs,\n maxSingleDelayMs,\n maxSingleDelaySession,\n maxSingleDelayTurn,\n maxSingleDelayKind,\n };\n}\n","/**\n * Text report formatters for session timing analysis. Pure — every function returns a string;\n * callers (e.g. a CLI command) own writing to stdout.\n */\n\nimport type { IAggregateReport, ISessionTimingReport, ITimingInterval } from './types.js';\nimport type { IUsageBySourceReport } from './usage.js';\n\nfunction fmtTokens(n: number): string {\n if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;\n if (n >= 1_000) return `${(n / 1_000).toFixed(1)}K`;\n return `${n}`;\n}\n\n/** SELFHOST-004: `~` marks an estimate or incomplete aggregate, never an invoice amount. */\nfunction fmtCost(usd: number, exact: boolean): string {\n return `${exact ? '' : '~'}$${usd.toFixed(4)}`;\n}\n\n/**\n * ANALYTICS-001 + SELFHOST-004: render a per-source token+cost breakdown and the per-operation span\n * timeline — which part of the session burned the most tokens/cost, and where the wall-clock went.\n * Pure; the caller owns writing it (the headless CLI path for the TUI/GUI trace/cost view).\n */\nexport function formatUsageReport(report: IUsageBySourceReport): string {\n const lines: string[] = [];\n lines.push(`Token usage — session ${report.sessionId}`);\n lines.push(\n ` total ${fmtTokens(report.totalTokens)} (prompt ${fmtTokens(report.promptTokens)} · completion ${fmtTokens(report.completionTokens)})`,\n );\n lines.push(` cost ${fmtCost(report.costUsd, report.costExact)}`);\n if (report.bySource.length === 0) {\n lines.push(' (no usage recorded)');\n } else {\n lines.push(' by source (most tokens first):');\n for (const s of report.bySource) {\n lines.push(\n ` ${s.label.padEnd(24)} ${String(s.percentage).padStart(5)}% ${fmtTokens(s.totalTokens).padStart(7)} ${fmtCost(s.costUsd, s.costExact).padStart(10)} (${s.turns} turn${s.turns === 1 ? '' : 's'})`,\n );\n }\n if (report.topConsumer) {\n lines.push(` top consumer: ${report.topConsumer.label} (${report.topConsumer.percentage}%)`);\n }\n }\n\n // SELFHOST-004: the span timeline — sub-turn operations grouped under their owning turn.\n if (report.timeline.length > 0) {\n lines.push(' trace (per turn, sub-turn spans):');\n for (const turn of report.timeline) {\n lines.push(\n ` turn ${turn.turnIndex} — ${turn.label} · ${fmtMs(turn.totalDurationMs)} across ${turn.spans.length} op${turn.spans.length === 1 ? '' : 's'}`,\n );\n for (const span of turn.spans) {\n lines.push(` ${span.op.padEnd(22)} ${fmtMs(span.durationMs).padStart(8)}`);\n }\n }\n }\n return lines.join('\\n');\n}\n\nfunction fmtMs(ms: number): string {\n if (ms >= 1000) return `${(ms / 1000).toFixed(1)}s`;\n return `${ms}ms`;\n}\n\nfunction fmtDate(iso: string): string {\n return new Date(iso).toLocaleString('sv-SE', { timeZoneName: 'short' }).slice(0, 16);\n}\n\nfunction intervalLabel(iv: ITimingInterval): string {\n const map: Record<string, string> = {\n user_to_first_tool: 'user → tool-start',\n user_to_assistant: 'user → assistant',\n tool_exec: 'tool-start → tool-end',\n llm_between_tools: 'tool-end → tool-start',\n llm_final_response: 'tool-end → assistant/summary',\n };\n return map[iv.kind] ?? iv.kind;\n}\n\nfunction verdictLine(report: ISessionTimingReport): string {\n const { stats } = report;\n const totalMs = stats.llmWaitMs.total + stats.toolExecMs.avg * stats.toolExecMs.count;\n if (totalMs === 0) return 'Verdict: No timing data available.';\n const llmPct = Math.round((stats.llmWaitMs.total / totalMs) * 100);\n const toolPct = 100 - llmPct;\n return `Verdict: LLM API wait ${llmPct}% | Code processing ${toolPct}%`;\n}\n\nexport function formatSingleSession(report: ISessionTimingReport): string {\n const lines: string[] = [];\n const { stats } = report;\n\n lines.push(`Session: ${report.sessionId}`);\n lines.push(`Created: ${fmtDate(report.createdAt)} | cwd: ${report.cwd}`);\n lines.push('');\n lines.push('Timing Summary:');\n\n if (stats.llmWaitMs.count > 0) {\n lines.push(\n ` LLM API wait ${fmtMs(stats.llmWaitMs.avg).padStart(8)} avg | ${fmtMs(stats.llmWaitMs.max).padStart(8)} max`,\n );\n }\n if (stats.toolExecMs.count > 0) {\n lines.push(\n ` Tool execution ${fmtMs(stats.toolExecMs.avg).padStart(8)} avg | ${fmtMs(stats.toolExecMs.median).padStart(8)} median`,\n );\n }\n if (stats.userToAssistantMs.count > 0) {\n lines.push(` user → assistant ${fmtMs(stats.userToAssistantMs.avg).padStart(8)} avg`);\n }\n if (stats.llmWaitMs.count === 0 && stats.toolExecMs.count === 0) {\n lines.push(' (no intervals computed — session may have no history)');\n }\n\n if (report.slowIntervals.length > 0) {\n lines.push('');\n lines.push('Slow intervals (>10s):');\n for (const iv of report.slowIntervals) {\n lines.push(\n ` turn ${iv.turnIndex} ${intervalLabel(iv).padEnd(32)} ${fmtMs(iv.durationMs).padStart(8)}`,\n );\n }\n }\n\n lines.push('');\n lines.push(verdictLine(report));\n\n return lines.join('\\n');\n}\n\nexport function formatAggregateReport(aggregate: IAggregateReport): string {\n const lines: string[] = [];\n lines.push(\n `Analyzed ${aggregate.sessionCount} sessions (${fmtDate(aggregate.fromDate)} ~ ${fmtDate(aggregate.toDate)})`,\n );\n lines.push(` Avg LLM response: ${fmtMs(aggregate.avgLlmResponseMs)}`);\n lines.push(` Avg tool exec: ${fmtMs(aggregate.avgToolExecMs)}`);\n if (aggregate.maxSingleDelayMs > 0) {\n lines.push(\n ` Max single delay: ${fmtMs(aggregate.maxSingleDelayMs)} (${aggregate.maxSingleDelaySession}, turn ${aggregate.maxSingleDelayTurn}, ${aggregate.maxSingleDelayKind})`,\n );\n }\n return lines.join('\\n');\n}\n","/**\n * ANALYTICS-001: source-attributed token-usage analysis over a session record.\n *\n * The main session history records one `usage-summary` history entry per turn (an `IUsageSnapshot`,\n * created in agent-framework). This reducer aggregates those snapshots into a per-source breakdown —\n * answering \"which part of the session burned the most tokens?\" — so it can be reported to the user\n * and asserted by the testing framework (budget gates). Pure: no I/O, no process concerns.\n */\n\nimport type { IHistoryEntry } from '@robota-sdk/agent-core';\nimport type {\n ISpanEntry,\n IUsageSnapshot,\n IUsageSource,\n IUsageSourceTotals,\n IRunTraceSpan,\n IRunTraceTurn,\n IUsageBySourceReport,\n} from '@robota-sdk/agent-interface-analytics';\nimport type { IInteractiveSessionRecord } from '@robota-sdk/agent-interface-session';\n\n// SELFHOST-004: the trace/cost read-model is a boundary contract owned by `agent-interface-analytics`\n// (it crosses the sidecar boundary via a TServerMessage carrier). Re-exported here for consumers that\n// import it alongside the reducer that produces it.\nexport type {\n IUsageSourceTotals,\n IRunTraceSpan,\n IRunTraceTurn,\n IUsageBySourceReport,\n} from '@robota-sdk/agent-interface-analytics';\n\n/** The `type` of the per-turn usage history entry (agent-framework `createUsageSummaryEntry`). */\nconst USAGE_SUMMARY_ENTRY_TYPE = 'usage-summary';\n\n/** The `type` of the per-operation span history entry (agent-framework `createSpanEntry`). */\nconst SPAN_ENTRY_TYPE = 'span';\n\n/** SSOT-derived projection the usage reducer reads. */\nexport type TUsageAnalysisInput = Pick<IInteractiveSessionRecord, 'id' | 'history'>;\n\n/** The main thread is the implicit source when a usage snapshot carries none. */\nconst MAIN_THREAD_SOURCE: IUsageSource = { scope: 'main', label: 'main thread' };\n\nfunction sourceKey(source: IUsageSource): string {\n return `${source.scope}:${source.id ?? ''}`;\n}\n\nfunction sourceLabel(source: IUsageSource): string {\n return source.label ?? (source.id ? `${source.scope} ${source.id}` : source.scope);\n}\n\nfunction isUsageSummaryEntry(entry: IHistoryEntry): entry is IHistoryEntry<IUsageSnapshot> {\n return (\n entry.type === USAGE_SUMMARY_ENTRY_TYPE && typeof entry.data === 'object' && entry.data !== null\n );\n}\n\nfunction isSpanEntry(entry: IHistoryEntry): entry is IHistoryEntry<ISpanEntry> {\n if (entry.type !== SPAN_ENTRY_TYPE || typeof entry.data !== 'object' || entry.data === null) {\n return false;\n }\n const data = entry.data as Partial<ISpanEntry>;\n return (\n typeof data.spanId === 'string' &&\n typeof data.op === 'string' &&\n typeof data.durationMs === 'number'\n );\n}\n\nfunction roundPercentage(part: number, whole: number): number {\n if (whole <= 0) return 0;\n return Math.round((part / whole) * 1000) / 10;\n}\n\n/**\n * Aggregate a session's `usage-summary` entries into a per-source token+cost breakdown AND assemble\n * the per-operation span timeline (SELFHOST-004).\n *\n * Token/cost: usage snapshots with no `source` are attributed to the main thread; sources are grouped\n * by `<scope>:<id>` and sorted by total tokens descending with the top consumer surfaced. Cost sums\n * each turn's known `IUsageSnapshot.costUsd` (unpriced turns contribute 0). Historical `exact`\n * snapshots were local price-table estimates, so they cannot certify billed cost.\n *\n * Timeline: history is a chronological timeline where each turn ends with its `usage-summary` entry,\n * so the `span` entries that appear before a given usage-summary are the sub-turn spans of THAT turn.\n * The reducer walks in order, buffering spans, and flushes the buffer as the turn's spans at each\n * usage-summary boundary — grouping sub-turn spans under their owning turn. Spans after the last\n * usage-summary (an in-progress turn) form a trailing timeline entry. Pure: no I/O, stays within the\n * declared `agent-core`, `agent-interface-analytics` and `agent-interface-session` dependencies\n * (NO `agent-plugin` read — enforcement lives elsewhere).\n */\nexport function summarizeUsageBySource(input: TUsageAnalysisInput): IUsageBySourceReport {\n const totalsByKey = new Map<string, IUsageSourceTotals>();\n let sessionPrompt = 0;\n let sessionCompletion = 0;\n let sessionTotal = 0;\n let sessionCost = 0;\n let sessionCostExact = true;\n\n const timeline: IRunTraceTurn[] = [];\n let pendingSpans: IRunTraceSpan[] = [];\n\n const flushTurn = (source: IUsageSource): void => {\n if (pendingSpans.length === 0) return;\n timeline.push({\n turnIndex: timeline.length,\n source,\n label: sourceLabel(source),\n spans: pendingSpans,\n totalDurationMs: pendingSpans.reduce((sum, span) => sum + span.durationMs, 0),\n });\n pendingSpans = [];\n };\n\n for (const entry of input.history ?? []) {\n if (isSpanEntry(entry)) {\n const span = entry.data as ISpanEntry;\n pendingSpans.push({ spanId: span.spanId, op: span.op, durationMs: span.durationMs });\n continue;\n }\n if (!isUsageSummaryEntry(entry)) continue;\n\n const snapshot = entry.data as IUsageSnapshot;\n const source = snapshot.source ?? MAIN_THREAD_SOURCE;\n const key = sourceKey(source);\n const prompt = snapshot.promptTokens ?? 0;\n const completion = snapshot.completionTokens ?? 0;\n const total = snapshot.totalTokens;\n // Historical `exact` labels were local price-table estimates, not billed values. Preserve the\n // amount while keeping the aggregate's exactness claim false.\n const turnCost = snapshot.costUsd ?? 0;\n const turnPriced = false;\n\n sessionPrompt += prompt;\n sessionCompletion += completion;\n sessionTotal += total;\n sessionCost += turnCost;\n if (!turnPriced) sessionCostExact = false;\n\n const existing = totalsByKey.get(key);\n if (existing) {\n existing.promptTokens += prompt;\n existing.completionTokens += completion;\n existing.totalTokens += total;\n existing.turns += 1;\n existing.costUsd += turnCost;\n if (!turnPriced) existing.costExact = false;\n } else {\n totalsByKey.set(key, {\n key,\n source,\n label: sourceLabel(source),\n promptTokens: prompt,\n completionTokens: completion,\n totalTokens: total,\n turns: 1,\n percentage: 0,\n costUsd: turnCost,\n costExact: turnPriced,\n });\n }\n\n // The usage-summary marks the turn boundary: the buffered spans belong to THIS turn.\n flushTurn(source);\n }\n\n // Spans of an in-progress turn (no usage summary yet) form a trailing timeline entry.\n flushTurn(MAIN_THREAD_SOURCE);\n\n const bySource = [...totalsByKey.values()]\n .map((totals) => ({ ...totals, percentage: roundPercentage(totals.totalTokens, sessionTotal) }))\n .sort((left, right) => right.totalTokens - left.totalTokens);\n\n return {\n sessionId: input.id,\n totalTokens: sessionTotal,\n promptTokens: sessionPrompt,\n completionTokens: sessionCompletion,\n costUsd: sessionCost,\n costExact: sessionCostExact,\n bySource,\n ...(bySource[0] ? { topConsumer: bySource[0] } : {}),\n timeline,\n };\n}\n","import type { IHistoryEntry, IUniversalObjectValue, TUniversalValue } from '@robota-sdk/agent-core';\nimport type {\n IPersonalUsageActivity,\n IUsageModelShare,\n IUsageObservation,\n IUsageSnapshot,\n IUsageSource,\n} from '@robota-sdk/agent-interface-analytics';\nimport type { IInteractiveSessionRecord } from '@robota-sdk/agent-interface-session';\n\nexport interface INormalizedObservation {\n readonly id: string;\n readonly sessionId: string;\n readonly at: Date;\n readonly legacy: boolean;\n readonly observation: IUsageObservation;\n}\n\nexport interface INormalizedActivity {\n readonly id: string;\n readonly sessionId: string;\n readonly key: string;\n readonly label: string;\n readonly kind: IPersonalUsageActivity['kind'];\n readonly at: Date;\n}\n\nfunction isRecord(value: TUniversalValue): value is IUniversalObjectValue {\n return (\n typeof value === 'object' && value !== null && !Array.isArray(value) && !(value instanceof Date)\n );\n}\n\nfunction optionalString(value: TUniversalValue): string | undefined {\n return typeof value === 'string' && value.length > 0 ? value : undefined;\n}\n\nfunction isMetric(value: TUniversalValue): value is number {\n return typeof value === 'number' && Number.isFinite(value) && value >= 0;\n}\n\nfunction isCostStatus(value: TUniversalValue): value is IUsageSnapshot['costStatus'] {\n return value === 'unknown' || value === 'estimated' || value === 'exact';\n}\n\nfunction hasValidOptionalMetrics(value: IUniversalObjectValue): boolean {\n return (\n (value['promptTokens'] === undefined || isMetric(value['promptTokens'])) &&\n (value['completionTokens'] === undefined || isMetric(value['completionTokens']))\n );\n}\n\nfunction hasValidCost(value: IUniversalObjectValue): boolean {\n const status = value['costStatus'];\n if (!isCostStatus(status)) return false;\n return status === 'unknown' ? value['costUsd'] === undefined : isMetric(value['costUsd']);\n}\n\ntype TRequiredUsageMetrics = {\n readonly totalTokens: number;\n readonly contextUsedTokens: number;\n readonly contextMaxTokens: number;\n readonly contextUsedPercentage: number;\n};\n\nfunction hasRequiredMetrics(\n value: IUniversalObjectValue,\n): value is IUniversalObjectValue & TRequiredUsageMetrics {\n return (\n isMetric(value['totalTokens']) &&\n isMetric(value['contextUsedTokens']) &&\n isMetric(value['contextMaxTokens']) &&\n isMetric(value['contextUsedPercentage'])\n );\n}\n\nfunction isUsageSurface(\n value: TUniversalValue,\n): value is NonNullable<IUsageObservation['surface']> {\n return (\n value === 'cli' ||\n value === 'desktop-app' ||\n value === 'browser' ||\n value === 'remote' ||\n value === 'attach' ||\n value === 'unknown'\n );\n}\n\nfunction usageSource(value: TUniversalValue): IUsageSource | undefined {\n if (!isRecord(value)) return undefined;\n const scope = value['scope'];\n if (\n scope !== 'main' &&\n scope !== 'subagent' &&\n scope !== 'background' &&\n scope !== 'tool' &&\n scope !== 'command' &&\n scope !== 'skill'\n ) {\n return undefined;\n }\n const id = optionalString(value['id']);\n const label = optionalString(value['label']);\n return { scope, ...(id ? { id } : {}), ...(label ? { label } : {}) };\n}\n\nfunction usageSnapshot(value: TUniversalValue): IUsageSnapshot | undefined {\n if (!isRecord(value)) return undefined;\n if (value['kind'] !== 'exact' && value['kind'] !== 'estimated') return undefined;\n if (value['scope'] !== 'turn' || !hasValidOptionalMetrics(value) || !hasValidCost(value)) {\n return undefined;\n }\n if (!hasRequiredMetrics(value) || !isCostStatus(value['costStatus'])) {\n return undefined;\n }\n const source = usageSource(value['source']);\n return {\n kind: value['kind'],\n scope: 'turn',\n totalTokens: value['totalTokens'],\n contextUsedTokens: value['contextUsedTokens'],\n contextMaxTokens: value['contextMaxTokens'],\n contextUsedPercentage: value['contextUsedPercentage'],\n // Historical `exact` meant a local price-table calculation, not an invoice.\n costStatus: value['costStatus'] === 'exact' ? 'estimated' : value['costStatus'],\n ...(isMetric(value['promptTokens']) ? { promptTokens: value['promptTokens'] } : {}),\n ...(isMetric(value['completionTokens']) ? { completionTokens: value['completionTokens'] } : {}),\n ...(isMetric(value['costUsd']) ? { costUsd: value['costUsd'] } : {}),\n ...(source ? { source } : {}),\n };\n}\n\nfunction modelShare(value: TUniversalValue): IUsageModelShare | undefined {\n if (!isRecord(value)) return undefined;\n const providerId = optionalString(value['providerId']);\n const modelId = optionalString(value['modelId']);\n const { promptTokens, completionTokens, totalTokens, costStatus, costUsd } = value;\n if (\n !providerId ||\n !modelId ||\n !isMetric(promptTokens) ||\n !isMetric(completionTokens) ||\n !isMetric(totalTokens) ||\n (costStatus !== 'unknown' && costStatus !== 'estimated') ||\n (costStatus === 'estimated' ? !isMetric(costUsd) : costUsd !== undefined)\n ) {\n return undefined;\n }\n return {\n providerId,\n modelId,\n promptTokens,\n completionTokens,\n totalTokens,\n costStatus,\n ...(costStatus === 'estimated' && isMetric(costUsd) ? { costUsd } : {}),\n };\n}\n\n/** Every share, or none: a partly readable split would misstate what each model spent. */\nfunction modelShares(value: TUniversalValue): IUsageModelShare[] | undefined {\n if (!Array.isArray(value) || value.length === 0) return undefined;\n const shares = value.map(modelShare);\n return shares.every((share) => share !== undefined) ? (shares as IUsageModelShare[]) : undefined;\n}\n\nfunction decodeObservation(value: TUniversalValue): IUsageObservation | undefined {\n if (!isRecord(value)) return undefined;\n const usageObservationId = optionalString(value['usageObservationId']);\n const turnId = optionalString(value['turnId']);\n const outcome = value['outcome'];\n if (\n !usageObservationId ||\n !turnId ||\n (outcome !== 'success' && outcome !== 'failure' && outcome !== 'interrupted')\n ) {\n return undefined;\n }\n const surface = value['surface'];\n const source = usageSource(value['source']);\n const usage = usageSnapshot(value['usage']);\n const shares = modelShares(value['modelShares']);\n return {\n usageObservationId,\n turnId,\n outcome,\n ...(optionalString(value['modelId']) ? { modelId: optionalString(value['modelId']) } : {}),\n ...(optionalString(value['providerId'])\n ? { providerId: optionalString(value['providerId']) }\n : {}),\n ...(shares ? { modelShares: shares } : {}),\n ...(isUsageSurface(surface) ? { surface } : {}),\n ...(source ? { source } : {}),\n ...(usage ? { usage } : {}),\n };\n}\n\nfunction entryDate(entry: IHistoryEntry): Date | undefined {\n const at = new Date(entry.timestamp);\n return Number.isNaN(at.getTime()) ? undefined : at;\n}\n\nexport function normalizeRecord(record: IInteractiveSessionRecord): INormalizedObservation[] {\n const observations: INormalizedObservation[] = [];\n const history = record.history ?? [];\n const shadowedLegacyIds = new Set<string>();\n const unmatchedLegacy = history.flatMap((entry, index) => {\n if (entry.type !== 'usage-summary') return [];\n const usage = usageSnapshot(entry.data as TUniversalValue);\n return usage ? [{ id: entry.id, index, usage }] : [];\n });\n for (const [canonicalIndex, entry] of history.entries()) {\n if (entry.type !== 'usage-observation') continue;\n const canonical = decodeObservation(entry.data as TUniversalValue);\n if (!canonical?.usage) continue;\n const canonicalKey = JSON.stringify(canonical.usage);\n const candidates = unmatchedLegacy\n .map((candidate, index) => ({ candidate, index }))\n .filter(({ candidate }) => JSON.stringify(candidate.usage) === canonicalKey)\n .sort(\n (left, right) =>\n Math.abs(left.candidate.index - canonicalIndex) -\n Math.abs(right.candidate.index - canonicalIndex),\n );\n const match = candidates[0];\n if (!match) continue;\n shadowedLegacyIds.add(match.candidate.id);\n unmatchedLegacy.splice(match.index, 1);\n }\n for (const entry of history) {\n const at = entryDate(entry);\n if (!at) continue;\n const observation =\n entry.type === 'usage-observation'\n ? decodeObservation(entry.data as TUniversalValue)\n : undefined;\n if (observation) {\n observations.push({\n id: observation.usageObservationId,\n sessionId: record.id,\n at,\n legacy: false,\n observation,\n });\n continue;\n }\n if (entry.type !== 'usage-summary' || shadowedLegacyIds.has(entry.id)) continue;\n const usage = usageSnapshot(entry.data as TUniversalValue);\n if (!usage) continue;\n const id = `legacy:${record.id}:${entry.id}`;\n observations.push({\n id,\n sessionId: record.id,\n at,\n legacy: true,\n observation: {\n usageObservationId: id,\n turnId: `legacy:${entry.id}`,\n outcome: 'success',\n usage,\n ...(usage.source ? { source: usage.source } : {}),\n surface: 'unknown',\n },\n });\n }\n return observations;\n}\n\nexport function normalizeActivities(record: IInteractiveSessionRecord): INormalizedActivity[] {\n const activities: INormalizedActivity[] = [];\n for (const entry of record.history ?? []) {\n const data = entry.data as TUniversalValue;\n if (entry.type !== 'tool-start' || !isRecord(data)) continue;\n const toolName = optionalString(data['toolName']);\n const at = entryDate(entry);\n if (!toolName || !at) continue;\n activities.push({\n id: `tool:${record.id}:${entry.id}`,\n sessionId: record.id,\n key: `tool:${toolName}`,\n label: toolName,\n kind: 'tool',\n at,\n });\n }\n // Activation history mirrors this canonical source and is intentionally not counted again.\n for (const event of record.skillActivationEvents ?? []) {\n if (event.status !== 'started') continue;\n const at = new Date(event.timestamp);\n if (Number.isNaN(at.getTime())) continue;\n activities.push({\n id: `activation:${record.id}:${event.timestamp}:${event.source}:${event.qualifiedName ?? event.skillName}:${event.invocation}`,\n sessionId: record.id,\n key: event.qualifiedName ?? `${event.source}:${event.skillName}`,\n label: event.qualifiedName ?? event.skillName,\n kind: event.source,\n at,\n });\n }\n return activities;\n}\n","import {\n normalizeActivities,\n normalizeRecord,\n type INormalizedActivity,\n type INormalizedObservation,\n} from './personal-usage-decode.js';\n\nimport type {\n IPersonalUsageDimension,\n IPersonalUsageActivity,\n IPersonalUsageReport,\n IPersonalUsageRequest,\n IPersonalUsageTotals,\n IUsageSource,\n} from '@robota-sdk/agent-interface-analytics';\nimport type { IInteractiveSessionRecord } from '@robota-sdk/agent-interface-session';\n\nconst SHORT_PERIOD_DAYS = 7;\nconst LONG_PERIOD_DAYS = 30;\nconst ISO_DATE_LENGTH = 'YYYY-MM-DD'.length;\n\nexport interface IPersonalUsageSnapshot {\n readonly request: IPersonalUsageRequest;\n readonly now: Date;\n readonly records: readonly IInteractiveSessionRecord[];\n readonly corruptSessionIds?: readonly string[];\n readonly unsupportedSessionIds?: readonly string[];\n}\n\ninterface IMutableTotals {\n sessions: Set<string>;\n observations: number;\n turns: number;\n promptTokens: number;\n completionTokens: number;\n totalTokens: number;\n costUsd: number;\n hasUnknownCost: boolean;\n hasEstimatedCost: boolean;\n /** Turns (not advisor/tool shares) whose cost could not be priced; a subset of `hasUnknownCost`. */\n unpricedTurns: number;\n}\n\nfunction createMutableTotals(): IMutableTotals {\n return {\n sessions: new Set<string>(),\n observations: 0,\n turns: 0,\n promptTokens: 0,\n completionTokens: 0,\n totalTokens: 0,\n costUsd: 0,\n hasUnknownCost: false,\n hasEstimatedCost: false,\n unpricedTurns: 0,\n };\n}\n\nfunction dateKey(date: Date, timezone: string): string {\n const parts = new Intl.DateTimeFormat('en-CA', {\n timeZone: timezone,\n year: 'numeric',\n month: '2-digit',\n day: '2-digit',\n }).formatToParts(date);\n const part = (type: Intl.DateTimeFormatPartTypes): string =>\n parts.find((candidate) => candidate.type === type)?.value ?? '';\n return `${part('year')}-${part('month')}-${part('day')}`;\n}\n\nfunction calendarKeys(now: Date, timezone: string, count: number): string[] {\n // First resolve the current LOCAL date (also validates the IANA timezone), then perform date-only\n // arithmetic in UTC. Subtracting 24-hour instants can skip a local calendar date during the first\n // hour after a spring-forward transition; date-only arithmetic cannot.\n const [year, month, day] = dateKey(now, timezone).split('-').map(Number);\n const localDate = new Date(Date.UTC(year!, month! - 1, day!));\n return Array.from({ length: count }, (_, index) => {\n const value = new Date(localDate);\n value.setUTCDate(value.getUTCDate() - (count - index - 1));\n return value.toISOString().slice(0, ISO_DATE_LENGTH);\n });\n}\n\nfunction activityDimensions(items: readonly INormalizedActivity[]): IPersonalUsageActivity[] {\n const counts = new Map<string, { item: INormalizedActivity; count: number }>();\n for (const item of items) {\n const current = counts.get(item.key);\n counts.set(item.key, { item, count: (current?.count ?? 0) + 1 });\n }\n return [...counts.values()]\n .map(({ item, count }) => ({\n key: item.key,\n label: item.label,\n kind: item.kind,\n count,\n }))\n .sort((left, right) => right.count - left.count || left.key.localeCompare(right.key));\n}\n\nfunction addObservation(target: IMutableTotals, item: INormalizedObservation): void {\n const usage = item.observation.usage;\n target.sessions.add(item.sessionId);\n target.observations += 1;\n // A consulted model's usage (the advisor, a tool source) belongs to the turn that consulted it;\n // it adds tokens and cost, not a turn.\n const isTurn = !item.legacy && item.observation.source?.scope !== 'tool';\n if (isTurn) target.turns += 1;\n target.promptTokens += usage?.promptTokens ?? 0;\n target.completionTokens += usage?.completionTokens ?? 0;\n target.totalTokens += usage?.totalTokens ?? 0;\n target.costUsd += usage?.costUsd ?? 0;\n if (usage?.costStatus === 'estimated') {\n target.hasEstimatedCost = true;\n } else {\n target.hasUnknownCost = true;\n if (isTurn) target.unpricedTurns += 1;\n }\n}\n\n/**\n * Group a turn by model or provider. A turn that ran on more than one model is split by its shares,\n * so each model is charged only what it spent; the turn still counts once in every group it touched.\n */\nfunction modelDimensions(\n items: readonly INormalizedObservation[],\n keyOf: (share: { providerId?: string; modelId?: string }) => string,\n): IPersonalUsageDimension[] {\n const parts: INormalizedObservation[] = [];\n for (const item of items) {\n const shares = item.observation.modelShares;\n if (shares === undefined) {\n parts.push(item);\n continue;\n }\n const byKey = new Map<string, INormalizedObservation>();\n for (const share of shares) {\n const key = keyOf(share);\n const current = byKey.get(key)?.observation.usage;\n const usage = item.observation.usage;\n const costStatus =\n share.costStatus === 'unknown' || current?.costStatus === 'unknown'\n ? ('unknown' as const)\n : ('estimated' as const);\n byKey.set(key, {\n ...item,\n observation: {\n ...item.observation,\n providerId: share.providerId,\n modelId: share.modelId,\n usage: {\n kind: usage?.kind ?? 'estimated',\n scope: 'turn',\n contextUsedTokens: usage?.contextUsedTokens ?? 0,\n contextMaxTokens: usage?.contextMaxTokens ?? 0,\n contextUsedPercentage: usage?.contextUsedPercentage ?? 0,\n promptTokens: (current?.promptTokens ?? 0) + share.promptTokens,\n completionTokens: (current?.completionTokens ?? 0) + share.completionTokens,\n totalTokens: (current?.totalTokens ?? 0) + share.totalTokens,\n costStatus,\n ...(costStatus === 'estimated' && {\n costUsd: (current?.costUsd ?? 0) + (share.costUsd ?? 0),\n }),\n },\n },\n });\n }\n parts.push(...byKey.values());\n }\n return dimensions(parts, (item) => keyOf(item.observation));\n}\n\nfunction freezeTotals(totals: IMutableTotals): IPersonalUsageTotals {\n return {\n sessions: totals.sessions.size,\n turns: totals.turns,\n promptTokens: totals.promptTokens,\n completionTokens: totals.completionTokens,\n totalTokens: totals.totalTokens,\n costUsd: totals.costUsd,\n // `costUsd` already sums every priced turn regardless of what else in the aggregate is unpriced,\n // so one unpriced observation (a legacy row, an unknown model, an unpriced advisor call) must never\n // by itself turn an otherwise-priced total into `unknown` — only the absence of ANY priced turn does.\n costStatus: totals.hasEstimatedCost ? 'estimated' : 'unknown',\n ...(totals.unpricedTurns > 0 ? { unpricedTurns: totals.unpricedTurns } : {}),\n };\n}\n\nfunction dimensions(\n items: readonly INormalizedObservation[],\n keyOf: (item: INormalizedObservation) => string,\n): IPersonalUsageDimension[] {\n const groups = new Map<string, IMutableTotals>();\n for (const item of items) {\n const key = keyOf(item);\n const totals = groups.get(key) ?? createMutableTotals();\n addObservation(totals, item);\n groups.set(key, totals);\n }\n return [...groups.entries()]\n .map(([key, totals]) => {\n const frozen = freezeTotals(totals);\n return { key, label: key, frozen, sessionIds: [...totals.sessions].sort() };\n })\n .map(({ key, label, frozen, sessionIds }) => ({\n key,\n label,\n turns: frozen.turns,\n promptTokens: frozen.promptTokens,\n completionTokens: frozen.completionTokens,\n totalTokens: frozen.totalTokens,\n costUsd: frozen.costUsd,\n costStatus: frozen.costStatus,\n sessionIds,\n }))\n .sort(\n (left, right) => right.totalTokens - left.totalTokens || left.key.localeCompare(right.key),\n );\n}\n\nfunction sourceKey(source: IUsageSource | undefined): string {\n if (!source) return 'unknown';\n return source.id ? `${source.scope}:${source.id}` : source.scope;\n}\n\ninterface ISelectedUsage {\n readonly observations: INormalizedObservation[];\n readonly activities: INormalizedActivity[];\n readonly duplicateObservations: number;\n readonly legacyObservations: number;\n}\n\nfunction isIncluded(at: Date, input: IPersonalUsageSnapshot, dates: ReadonlySet<string>): boolean {\n return at.getTime() <= input.now.getTime() && dates.has(dateKey(at, input.request.timezone));\n}\n\nfunction selectUsage(input: IPersonalUsageSnapshot, dates: ReadonlySet<string>): ISelectedUsage {\n const observations: INormalizedObservation[] = [];\n const activities: INormalizedActivity[] = [];\n const seenObservations = new Set<string>();\n const seenActivities = new Set<string>();\n let duplicateObservations = 0;\n let legacyObservations = 0;\n for (const record of input.records) {\n for (const item of normalizeRecord(record)) {\n if (!isIncluded(item.at, input, dates)) continue;\n if (seenObservations.has(item.id)) {\n duplicateObservations += 1;\n continue;\n }\n seenObservations.add(item.id);\n observations.push(item);\n if (item.legacy) legacyObservations += 1;\n }\n for (const activity of normalizeActivities(record)) {\n if (!isIncluded(activity.at, input, dates) || seenActivities.has(activity.id)) continue;\n seenActivities.add(activity.id);\n activities.push(activity);\n }\n }\n return { observations, activities, duplicateObservations, legacyObservations };\n}\n\n/**\n * The earliest included observation or activity time for each session, ISO-formatted. A timestamp,\n * not content — the one thing this report can say about a session outside a GUI's own local listing.\n */\nfunction firstSeenBySession(selection: ISelectedUsage): Record<string, string> {\n const earliest = new Map<string, number>();\n const note = (sessionId: string, at: Date): void => {\n const time = at.getTime();\n const current = earliest.get(sessionId);\n if (current === undefined || time < current) earliest.set(sessionId, time);\n };\n for (const item of selection.observations) note(item.sessionId, item.at);\n for (const activity of selection.activities) note(activity.sessionId, activity.at);\n const result: Record<string, string> = {};\n for (const [sessionId, time] of earliest) result[sessionId] = new Date(time).toISOString();\n return result;\n}\n\nfunction accumulateUsage(\n input: IPersonalUsageSnapshot,\n keys: readonly string[],\n selection: ISelectedUsage,\n): { totals: IMutableTotals; byDay: Map<string, IMutableTotals> } {\n const totals = createMutableTotals();\n const byDay = new Map(keys.map((key) => [key, createMutableTotals()]));\n for (const item of selection.observations) {\n addObservation(totals, item);\n addObservation(byDay.get(dateKey(item.at, input.request.timezone))!, item);\n }\n for (const activity of selection.activities) {\n totals.sessions.add(activity.sessionId);\n byDay.get(dateKey(activity.at, input.request.timezone))?.sessions.add(activity.sessionId);\n }\n return { totals, byDay };\n}\n\nexport function summarizePersonalUsage(input: IPersonalUsageSnapshot): IPersonalUsageReport {\n const count = input.request.period === '30d' ? LONG_PERIOD_DAYS : SHORT_PERIOD_DAYS;\n const keys = calendarKeys(input.now, input.request.timezone, count);\n const selection = selectUsage(input, new Set(keys));\n const { totals, byDay } = accumulateUsage(input, keys, selection);\n const selected = selection.observations;\n\n return {\n schemaVersion: 1,\n generatedAt: input.now.toISOString(),\n period: input.request.period,\n timezone: input.request.timezone,\n interval: { startDate: keys[0]!, endDate: keys.at(-1)! },\n totals: freezeTotals(totals),\n daily: keys.map((date, index) => ({\n date,\n partial: index === keys.length - 1,\n totals: freezeTotals(byDay.get(date)!),\n sessionIds: [...byDay.get(date)!.sessions].sort(),\n })),\n byModel: modelDimensions(selected, (share) => share.modelId ?? 'unknown'),\n byProvider: modelDimensions(selected, (share) => share.providerId ?? 'unknown'),\n bySurface: dimensions(selected, (item) => item.observation.surface ?? 'unknown'),\n bySource: dimensions(selected, (item) => sourceKey(item.observation.source)),\n byActivity: activityDimensions(selection.activities),\n sessionIds: [...totals.sessions].sort(),\n sessionFirstSeen: firstSeenBySession(selection),\n coverage: {\n validSessions: input.records.length,\n corruptSessions: input.corruptSessionIds?.length ?? 0,\n unsupportedSessions: input.unsupportedSessionIds?.length ?? 0,\n duplicateObservations: selection.duplicateObservations,\n legacyObservations: selection.legacyObservations,\n unknownModelObservations: selected.filter(\n (item) => !item.observation.modelId && !item.observation.modelShares,\n ).length,\n unknownProviderObservations: selected.filter(\n (item) => !item.observation.providerId && !item.observation.modelShares,\n ).length,\n unknownSurfaceObservations: selected.filter(\n (item) => !item.observation.surface || item.observation.surface === 'unknown',\n ).length,\n corruptSessionIds: [...(input.corruptSessionIds ?? [])].sort(),\n unsupportedSessionIds: [...(input.unsupportedSessionIds ?? [])].sort(),\n },\n };\n}\n","import { calculateModelCost, MODEL_PRICES } from '@robota-sdk/agent-core';\n\nimport type { IInteractiveSessionRecord } from '@robota-sdk/agent-interface-session';\n\nconst MAX_UINT64 = (1n << 64n) - 1n;\nconst TRACE_ID = /^(?!0{32}$)[0-9a-f]{32}$/;\nconst SPAN_ID = /^(?!0{16}$)[0-9a-f]{16}$/;\nconst ROOT_FIELDS = [\n 'promptExecutionStartedAt',\n 'promptExecutionEndedAt',\n 'promptExecutionOutcome',\n 'promptExecutionTraceId',\n 'promptExecutionSpanId',\n] as const;\n\ninterface ICandidate {\n readonly record: IInteractiveSessionRecord;\n readonly data: unknown;\n readonly observationKey?: string;\n readonly traceId?: string;\n}\n\ninterface IOtlpSpan {\n readonly traceId: string;\n readonly spanId: string;\n readonly parentSpanId?: string;\n readonly name: 'agent.prompt_execution' | 'agent.provider_call' | 'agent.tool_body';\n readonly kind: 1;\n readonly startTimeUnixNano: string;\n readonly endTimeUnixNano: string;\n readonly attributes: readonly {\n readonly key: string;\n readonly value: { readonly stringValue: string } | { readonly intValue: string } | { readonly doubleValue: number };\n }[];\n readonly status: { readonly code: number };\n}\n\nexport interface IOtlpPromptRootTraces {\n readonly resourceSpans: readonly {\n readonly resource: {\n readonly attributes: readonly {\n readonly key: string;\n readonly value: { readonly stringValue: string };\n }[];\n };\n readonly scopeSpans: readonly {\n readonly scope: { readonly name: string };\n readonly spans: readonly IOtlpSpan[];\n }[];\n }[];\n}\n\nexport interface IPromptRootTraceCoverage {\n readonly exported: number;\n readonly missing: number;\n readonly invalid: number;\n readonly duplicate: number;\n readonly providerChildren: {\n readonly exported: number;\n readonly invalid: number;\n readonly orphaned: number;\n readonly duplicate: number;\n };\n readonly providerUsage: {\n readonly legacy: number;\n readonly invalid: number;\n readonly partial: number;\n readonly absent: number;\n readonly nonInvoked: number;\n };\n readonly toolChildren: {\n readonly exported: number;\n readonly invalid: number;\n readonly orphaned: number;\n readonly duplicate: number;\n };\n}\n\nexport interface IAcceptedProviderCallMetrics {\n readonly invoked: number;\n readonly completeUsage: number;\n readonly inputTokens: number;\n readonly outputTokens: number;\n readonly estimatedCostUsd: number;\n readonly unknownCost: number;\n readonly exactPriceMatches: number;\n readonly familyPriceMatches: number;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction count<K>(map: Map<K, number>, key: K): void {\n map.set(key, (map.get(key) ?? 0) + 1);\n}\n\nfunction otlpUnixNano(value: unknown): bigint | undefined {\n if (typeof value !== 'string') return undefined;\n const date = new Date(value);\n if (Number.isNaN(date.getTime()) || date.toISOString() !== value) return undefined;\n const nanos = BigInt(date.getTime()) * 1_000_000n;\n return nanos >= 0n && nanos <= MAX_UINT64 ? nanos : undefined;\n}\n\nfunction rootSpan(data: Record<string, unknown>): IOtlpSpan | undefined {\n const started = otlpUnixNano(data['promptExecutionStartedAt']);\n const ended = otlpUnixNano(data['promptExecutionEndedAt']);\n const outcome = data['promptExecutionOutcome'];\n const traceId = data['promptExecutionTraceId'];\n const spanId = data['promptExecutionSpanId'];\n if (\n started === undefined ||\n ended === undefined ||\n started > ended ||\n (outcome !== 'success' && outcome !== 'failure' && outcome !== 'interrupted') ||\n typeof traceId !== 'string' ||\n !TRACE_ID.test(traceId) ||\n typeof spanId !== 'string' ||\n !SPAN_ID.test(spanId) ||\n typeof data['usageObservationId'] !== 'string' ||\n data['usageObservationId'].length === 0 ||\n data['turnId'] !== data['usageObservationId'] ||\n (data['outcome'] !== 'success' &&\n data['outcome'] !== 'failure' &&\n data['outcome'] !== 'interrupted')\n ) {\n return undefined;\n }\n return {\n traceId,\n spanId,\n name: 'agent.prompt_execution',\n kind: 1,\n startTimeUnixNano: String(started),\n endTimeUnixNano: String(ended),\n attributes: [{ key: 'agent.prompt.outcome', value: { stringValue: outcome } }],\n status: { code: outcome === 'success' ? 1 : outcome === 'failure' ? 2 : 0 },\n };\n}\n\nfunction childSpan(data: unknown, kind: 'provider' | 'tool'): IOtlpSpan | undefined {\n if (!isRecord(data)) return undefined;\n const traceId = data['traceId'];\n const parentSpanId = data['parentSpanId'];\n const spanId = data['spanId'];\n const started = otlpUnixNano(data['startedAt']);\n const ended = otlpUnixNano(data['endedAt']);\n const outcome = data['outcome'];\n if (\n typeof traceId !== 'string' ||\n !TRACE_ID.test(traceId) ||\n typeof parentSpanId !== 'string' ||\n !SPAN_ID.test(parentSpanId) ||\n typeof spanId !== 'string' ||\n !SPAN_ID.test(spanId) ||\n started === undefined ||\n ended === undefined ||\n started > ended ||\n (outcome !== 'success' && outcome !== 'failure' && outcome !== 'interrupted') ||\n (kind === 'provider' && (!Number.isSafeInteger(data['round']) || (data['round'] as number) < 1))\n ) {\n return undefined;\n }\n return {\n traceId,\n parentSpanId,\n spanId,\n name: kind === 'provider' ? 'agent.provider_call' : 'agent.tool_body',\n kind: 1,\n startTimeUnixNano: String(started),\n endTimeUnixNano: String(ended),\n attributes: [\n {\n key: kind === 'provider' ? 'agent.provider.outcome' : 'agent.tool.outcome',\n value: { stringValue: outcome },\n },\n ],\n status: { code: outcome === 'success' ? 1 : outcome === 'failure' ? 2 : 0 },\n };\n}\n\nfunction childIdentity(data: unknown): string | undefined {\n if (!isRecord(data)) return undefined;\n const traceId = data['traceId'];\n const spanId = data['spanId'];\n return typeof traceId === 'string' &&\n TRACE_ID.test(traceId) &&\n typeof spanId === 'string' &&\n SPAN_ID.test(spanId)\n ? `${traceId}:${spanId}`\n : undefined;\n}\n\nfunction validToken(value: unknown): value is number {\n return typeof value === 'number' && Number.isSafeInteger(value) && value >= 0;\n}\n\nfunction enrichProviderSpan(\n span: IOtlpSpan,\n data: unknown,\n usageCoverage: { legacy: number; invalid: number; partial: number; absent: number },\n metrics: { -readonly [K in keyof IAcceptedProviderCallMetrics]: number },\n): IOtlpSpan {\n if (!isRecord(data) || data['disposition'] === undefined) {\n usageCoverage.legacy += 1;\n return span;\n }\n if (data['disposition'] !== 'invoked') {\n usageCoverage.invalid += 1;\n return span;\n }\n metrics.invoked += 1;\n const provenance = data['usageProvenance'];\n if (provenance === 'partial') {\n usageCoverage.partial += 1;\n metrics.unknownCost += 1;\n return span;\n }\n if (provenance === 'absent' || provenance === undefined) {\n usageCoverage.absent += 1;\n metrics.unknownCost += 1;\n return span;\n }\n const input = data['promptTokens'];\n const output = data['completionTokens'];\n const total = data['totalTokens'];\n if (\n provenance !== 'complete' || !validToken(input) || !validToken(output) ||\n !Number.isSafeInteger(input + output) || total !== input + output\n ) {\n usageCoverage.invalid += 1;\n metrics.unknownCost += 1;\n return span;\n }\n metrics.completeUsage += 1;\n metrics.inputTokens += input;\n metrics.outputTokens += output;\n const attrs: IOtlpSpan['attributes'][number][] = [\n ...span.attributes,\n { key: 'agent.provider.usage.input_tokens', value: { intValue: String(input) } },\n { key: 'agent.provider.usage.output_tokens', value: { intValue: String(output) } },\n ];\n const model = data['modelId'];\n const estimated = typeof model === 'string' && model.length > 0 && model.length <= 128 &&\n [...model].every((char) => char.charCodeAt(0) >= 32)\n ? calculateModelCost(model, input, output) : undefined;\n if (estimated === undefined || !Number.isFinite(estimated) || estimated < 0) {\n metrics.unknownCost += 1;\n } else {\n metrics.estimatedCostUsd += estimated;\n if (typeof model === 'string' && Object.hasOwn(MODEL_PRICES, model)) metrics.exactPriceMatches += 1;\n else metrics.familyPriceMatches += 1;\n attrs.push({ key: 'agent.provider.cost.usd.estimated', value: { doubleValue: estimated } });\n }\n return { ...span, attributes: attrs };\n}\n\n/** Project only proven canonical prompt roots; never infer spans from legacy usage or tool events. */\nexport function createOtlpPromptRootTraces(\n records: readonly IInteractiveSessionRecord[],\n version: string,\n serviceName: string,\n): { readonly payload: IOtlpPromptRootTraces; readonly coverage: IPromptRootTraceCoverage; readonly callMetrics: IAcceptedProviderCallMetrics } {\n const candidates: ICandidate[] = [];\n const observationCounts = new Map<string, number>();\n const traceCounts = new Map<string, number>();\n for (const record of records) {\n for (const entry of record.history ?? []) {\n if (entry.type !== 'usage-observation') continue;\n const data: unknown = entry.data;\n const observationId = isRecord(data) ? data['usageObservationId'] : undefined;\n const traceId = isRecord(data) ? data['promptExecutionTraceId'] : undefined;\n const observationKey =\n typeof observationId === 'string' && observationId.length > 0\n ? JSON.stringify([record.id, observationId])\n : undefined;\n const validTraceId =\n typeof traceId === 'string' && TRACE_ID.test(traceId) ? traceId : undefined;\n if (observationKey) count(observationCounts, observationKey);\n if (validTraceId) count(traceCounts, validTraceId);\n candidates.push({ record, data, observationKey, traceId: validTraceId });\n }\n }\n\n const spans: IOtlpSpan[] = [];\n const rootsByRecord = new Map<IInteractiveSessionRecord, Map<string, IOtlpSpan>>();\n let missing = 0;\n let invalid = 0;\n let duplicate = 0;\n for (const candidate of candidates) {\n if (\n (candidate.observationKey && (observationCounts.get(candidate.observationKey) ?? 0) > 1) ||\n (candidate.traceId && (traceCounts.get(candidate.traceId) ?? 0) > 1)\n ) {\n duplicate += 1;\n continue;\n }\n const data = candidate.data;\n if (!isRecord(data)) {\n invalid += 1;\n continue;\n }\n if (ROOT_FIELDS.every((field) => data[field] === undefined)) {\n missing += 1;\n continue;\n }\n const span = rootSpan(data);\n if (!span) {\n invalid += 1;\n continue;\n }\n spans.push(span);\n const recordRoots = rootsByRecord.get(candidate.record) ?? new Map<string, IOtlpSpan>();\n recordRoots.set(span.traceId, span);\n rootsByRecord.set(candidate.record, recordRoots);\n }\n\n const children: {\n readonly record: IInteractiveSessionRecord;\n readonly span: IOtlpSpan | undefined;\n readonly identity: string | undefined;\n readonly kind: 'provider' | 'tool';\n readonly data: unknown;\n }[] = [];\n const childCounts = new Map<string, number>();\n for (const record of records) {\n for (const entry of record.history ?? []) {\n const kind =\n entry.type === 'provider-call-trace'\n ? 'provider'\n : entry.type === 'tool-body-trace'\n ? 'tool'\n : undefined;\n if (!kind) continue;\n const identity = childIdentity(entry.data);\n const span = childSpan(entry.data, kind);\n if (identity) count(childCounts, identity);\n children.push({ record, span, identity, kind, data: entry.data });\n }\n }\n const coverageByKind = {\n provider: { exported: 0, invalid: 0, orphaned: 0, duplicate: 0 },\n tool: { exported: 0, invalid: 0, orphaned: 0, duplicate: 0 },\n };\n const providerUsage = { legacy: 0, invalid: 0, partial: 0, absent: 0, nonInvoked: 0 };\n const callMetrics = {\n invoked: 0, completeUsage: 0, inputTokens: 0, outputTokens: 0,\n estimatedCostUsd: 0, unknownCost: 0, exactPriceMatches: 0, familyPriceMatches: 0,\n };\n for (const child of children) {\n const { span } = child;\n const coverage = coverageByKind[child.kind];\n if (child.identity && (childCounts.get(child.identity) ?? 0) > 1) {\n coverage.duplicate += 1;\n continue;\n }\n if (!span) {\n coverage.invalid += 1;\n continue;\n }\n const root = rootsByRecord.get(child.record)?.get(span.traceId);\n if (!root || span.parentSpanId !== root.spanId || span.spanId === root.spanId) {\n coverage.orphaned += 1;\n continue;\n }\n if (\n BigInt(span.startTimeUnixNano) < BigInt(root.startTimeUnixNano) ||\n BigInt(span.endTimeUnixNano) > BigInt(root.endTimeUnixNano)\n ) {\n coverage.invalid += 1;\n continue;\n }\n if (child.kind === 'provider' && isRecord(child.data) &&\n (child.data['disposition'] === 'cache-hit' || child.data['disposition'] === 'preflight-refused')) {\n providerUsage.nonInvoked += 1;\n if (child.data['promptTokens'] !== undefined || child.data['completionTokens'] !== undefined ||\n child.data['totalTokens'] !== undefined || child.data['usageProvenance'] === 'complete') {\n providerUsage.invalid += 1;\n }\n continue;\n }\n spans.push(child.kind === 'provider'\n ? enrichProviderSpan(span, child.data, providerUsage, callMetrics)\n : span);\n coverage.exported += 1;\n }\n\n return {\n payload: {\n resourceSpans: spans.length\n ? [\n {\n resource: {\n attributes: [\n { key: 'service.name', value: { stringValue: serviceName } },\n { key: 'service.version', value: { stringValue: version } },\n ],\n },\n scopeSpans: [{ scope: { name: '@robota-sdk/agent-session-analytics' }, spans }],\n },\n ]\n : [],\n },\n coverage: {\n exported: spans.length - coverageByKind.provider.exported - coverageByKind.tool.exported,\n missing,\n invalid,\n duplicate,\n providerChildren: coverageByKind.provider,\n providerUsage,\n toolChildren: coverageByKind.tool,\n },\n callMetrics,\n };\n}\n","import { createOtlpPromptRootTraces } from './otlp-prompt-root-traces.js';\nimport { normalizeRecord } from './personal-usage-decode.js';\n\nimport type { IInteractiveSessionRecord } from '@robota-sdk/agent-interface-session';\n\n/** A non-additive, content-free snapshot. Consumers must read the latest Gauge, not sum exports. */\nexport function createOtlpUsageSnapshot(\n records: readonly IInteractiveSessionRecord[],\n at: Date,\n version: string,\n serviceName: string,\n): { resourceMetrics: unknown[] } {\n const seen = new Set<string>();\n let turns = 0;\n let totalTokens = 0;\n let inputTokens = 0;\n let outputTokens = 0;\n let unknownTokenSplitObservations = 0;\n let knownCost = 0;\n let unknownCostObservations = 0;\n let estimatedCostObservations = 0;\n\n for (const record of records) {\n for (const item of normalizeRecord(record)) {\n if (seen.has(item.id)) continue;\n seen.add(item.id);\n if (!item.legacy) turns += 1;\n const usage = item.observation.usage;\n if (!usage) {\n unknownCostObservations += 1;\n unknownTokenSplitObservations += 1;\n continue;\n }\n totalTokens += usage.totalTokens;\n inputTokens += usage.promptTokens ?? 0;\n outputTokens += usage.completionTokens ?? 0;\n if (usage.promptTokens === undefined || usage.completionTokens === undefined) {\n unknownTokenSplitObservations += 1;\n }\n if (usage.costStatus === 'unknown' || usage.costUsd === undefined) {\n unknownCostObservations += 1;\n } else {\n knownCost += usage.costUsd;\n if (usage.costStatus === 'estimated') estimatedCostObservations += 1;\n }\n }\n }\n // The trace projection is the single accepted-call selector: parent/time/duplicate checks must\n // agree between traces and metrics. These are separate non-additive Gauges, never turn totals.\n const acceptedCalls = createOtlpPromptRootTraces(records, version, serviceName);\n const calls = acceptedCalls.callMetrics;\n\n const timeUnixNano = String(BigInt(at.getTime()) * 1_000_000n);\n const gauge = (name: string, unit: string, value: number) => ({\n name,\n unit,\n gauge: { dataPoints: [{ timeUnixNano, asDouble: value }] },\n });\n\n return {\n resourceMetrics: [\n {\n resource: {\n attributes: [\n { key: 'service.name', value: { stringValue: serviceName } },\n { key: 'service.version', value: { stringValue: version } },\n ],\n },\n scopeMetrics: [\n {\n scope: { name: '@robota-sdk/agent-session-analytics' },\n metrics: [\n gauge('agent.session.count', '{session}', records.length),\n gauge('agent.turn.count', '{turn}', turns),\n gauge('agent.token.total', '{token}', totalTokens),\n gauge('agent.token.input.known', '{token}', inputTokens),\n gauge('agent.token.output.known', '{token}', outputTokens),\n gauge(\n 'agent.token.split_unknown_observations',\n '{observation}',\n unknownTokenSplitObservations,\n ),\n gauge('agent.cost.usd.known', 'USD', knownCost),\n gauge('agent.cost.unknown_observations', '{observation}', unknownCostObservations),\n gauge(\n 'agent.cost.estimated_observations',\n '{observation}',\n estimatedCostObservations,\n ),\n gauge('agent.provider_call.count', '{call}', calls.invoked),\n gauge('agent.provider_call.usage.complete_count', '{call}', calls.completeUsage),\n gauge('agent.provider_call.token.input.known', '{token}', calls.inputTokens),\n gauge('agent.provider_call.token.output.known', '{token}', calls.outputTokens),\n gauge('agent.provider_call.cost.usd.estimated', 'USD', calls.estimatedCostUsd),\n gauge('agent.provider_call.cost.unknown_count', '{call}', calls.unknownCost),\n gauge('agent.provider_call.usage.partial_count', '{call}', acceptedCalls.coverage.providerUsage.partial),\n gauge('agent.provider_call.usage.invalid_count', '{call}', acceptedCalls.coverage.providerUsage.invalid),\n gauge('agent.provider_call.usage.legacy_count', '{call}', acceptedCalls.coverage.providerUsage.legacy),\n gauge('agent.provider_call.price.exact_id_count', '{call}', calls.exactPriceMatches),\n gauge('agent.provider_call.price.family_fallback_count', '{call}', calls.familyPriceMatches),\n ],\n },\n ],\n },\n ],\n };\n}\n","import { createOtlpPromptRootTraces } from './otlp-prompt-root-traces.js';\n\nimport type { IPromptRootTraceCoverage } from './otlp-prompt-root-traces.js';\nimport type { IInteractiveSessionRecord } from '@robota-sdk/agent-interface-session';\n\ntype TEventName =\n | 'agent.prompt_execution.completed'\n | 'agent.provider_call.completed'\n | 'agent.tool_body.completed';\n\ninterface IOtlpLogRecord {\n readonly timeUnixNano: string;\n readonly observedTimeUnixNano: string;\n readonly severityNumber: 9 | 13 | 17;\n readonly severityText: 'INFO' | 'WARN' | 'ERROR';\n readonly eventName: TEventName;\n readonly traceId: string;\n readonly spanId: string;\n readonly attributes: readonly {\n readonly key: string;\n readonly value: { readonly stringValue: string };\n }[];\n}\n\nexport interface IOtlpPromptEvents {\n readonly resourceLogs: readonly {\n readonly resource: {\n readonly attributes: readonly {\n readonly key: string;\n readonly value: { readonly stringValue: string };\n }[];\n };\n readonly scopeLogs: readonly {\n readonly scope: { readonly name: string };\n readonly logRecords: readonly IOtlpLogRecord[];\n }[];\n }[];\n}\n\nconst MAX_UINT64 = (1n << 64n) - 1n;\n\nfunction observedUnixNano(observedAt: Date): string {\n const millis = observedAt.getTime();\n if (!Number.isSafeInteger(millis) || millis < 0) {\n throw new RangeError('OTLP log observation time must be a valid post-epoch date.');\n }\n const nanos = BigInt(millis) * 1_000_000n;\n if (nanos > MAX_UINT64) throw new RangeError('OTLP log observation time is out of range.');\n return String(nanos);\n}\n\n/** Explicit local OTLP log projection of canonical prompt completion events. */\nexport function createOtlpPromptEvents(\n records: readonly IInteractiveSessionRecord[],\n version: string,\n observedAt: Date,\n serviceName: string,\n): {\n readonly exported: number;\n readonly coverage: IPromptRootTraceCoverage;\n readonly payload: IOtlpPromptEvents;\n} {\n const traces = createOtlpPromptRootTraces(records, version, serviceName);\n const spans = traces.payload.resourceSpans[0]?.scopeSpans[0]?.spans ?? [];\n if (spans.length === 0) {\n return { exported: 0, coverage: traces.coverage, payload: { resourceLogs: [] } };\n }\n const observedTimeUnixNano = observedUnixNano(observedAt);\n const logRecords: IOtlpLogRecord[] = spans.map((span) => {\n const outcomeAttribute = span.attributes.find((attribute) =>\n attribute.key === 'agent.prompt.outcome' ||\n attribute.key === 'agent.provider.outcome' ||\n attribute.key === 'agent.tool.outcome');\n const eventName: TEventName =\n span.name === 'agent.prompt_execution'\n ? 'agent.prompt_execution.completed'\n : span.name === 'agent.provider_call'\n ? 'agent.provider_call.completed'\n : 'agent.tool_body.completed';\n const severityNumber = span.status.code === 1 ? 9 : span.status.code === 2 ? 17 : 13;\n const severityText = severityNumber === 9 ? 'INFO' : severityNumber === 17 ? 'ERROR' : 'WARN';\n return {\n timeUnixNano: span.endTimeUnixNano,\n observedTimeUnixNano,\n severityNumber,\n severityText,\n eventName,\n traceId: span.traceId,\n spanId: span.spanId,\n attributes: outcomeAttribute && 'stringValue' in outcomeAttribute.value\n ? [{ key: outcomeAttribute.key, value: { stringValue: outcomeAttribute.value.stringValue } }]\n : [],\n };\n });\n return {\n exported: logRecords.length,\n coverage: traces.coverage,\n payload: {\n resourceLogs: [\n {\n resource: traces.payload.resourceSpans[0]!.resource,\n scopeLogs: [\n {\n scope: { name: '@robota-sdk/agent-session-analytics' },\n logRecords,\n },\n ],\n },\n ],\n },\n };\n}\n","import type {\n IPersonalUsageDimension,\n IPersonalUsageReport,\n} from '@robota-sdk/agent-interface-analytics';\n\nconst COST_DECIMAL_PLACES = 4;\n\nfunction dimensionLines(title: string, values: readonly IPersonalUsageDimension[]): string[] {\n return [\n '',\n title,\n ...(values.length === 0\n ? ['(none)']\n : values.map(\n (value) =>\n `${value.label} ${value.turns} turns ${value.totalTokens} tokens cost ${value.costStatus === 'unknown' ? 'unknown' : `$${value.costUsd.toFixed(COST_DECIMAL_PLACES)}`}`,\n )),\n ];\n}\n\n/** Render the provider-neutral personal-usage report for the terminal surface. */\nexport function formatPersonalUsageReport(report: IPersonalUsageReport): string {\n const cost =\n report.totals.costStatus === 'unknown'\n ? 'unknown'\n : `$${report.totals.costUsd.toFixed(COST_DECIMAL_PLACES)} (${report.totals.costStatus})`;\n return [\n `Personal usage — ${report.period} (${report.timezone})`,\n `${report.interval.startDate} → ${report.interval.endDate}`,\n `Sessions ${report.totals.sessions} · Turns ${report.totals.turns} · Tokens ${report.totals.totalTokens} (${report.totals.promptTokens} input / ${report.totals.completionTokens} output) · Cost ${cost}`,\n '',\n 'Daily usage',\n ...report.daily.map(\n (day) =>\n `${day.date}${day.partial ? ' (partial)' : ''} ${day.totals.turns} turns ${day.totals.totalTokens} tokens`,\n ),\n ...dimensionLines('By model', report.byModel),\n ...dimensionLines('By provider', report.byProvider),\n ...dimensionLines('By surface', report.bySurface),\n ...dimensionLines('By source', report.bySource),\n '',\n 'Activity',\n ...(report.byActivity.length === 0\n ? ['(none)']\n : report.byActivity.map(\n (activity) => `${activity.kind}:${activity.label} ${activity.count} calls`,\n )),\n '',\n `Coverage: legacy ${report.coverage.legacyObservations}, corrupt ${report.coverage.corruptSessions}, unsupported ${report.coverage.unsupportedSessions}, duplicates ${report.coverage.duplicateObservations}`,\n 'Local estimates from recorded sessions; costs are not an invoice.',\n ].join('\\n');\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@robota-sdk/agent-session-analytics",
|
|
3
|
-
"version": "3.0.0-beta.
|
|
3
|
+
"version": "3.0.0-beta.88",
|
|
4
4
|
"description": "Session-log timing analysis and reporting for the Robota SDK (analyzeSession, aggregateReports, report formatters)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/node/index.js",
|
|
@@ -31,15 +31,6 @@
|
|
|
31
31
|
},
|
|
32
32
|
"./package.json": "./package.json"
|
|
33
33
|
},
|
|
34
|
-
"repository": {
|
|
35
|
-
"type": "git",
|
|
36
|
-
"url": "https://github.com/woojubb/robota.git",
|
|
37
|
-
"directory": "packages/agent-session-analytics"
|
|
38
|
-
},
|
|
39
|
-
"homepage": "https://docs.robota.io/en/packages/agent-session-analytics/",
|
|
40
|
-
"bugs": {
|
|
41
|
-
"url": "https://github.com/woojubb/robota/issues"
|
|
42
|
-
},
|
|
43
34
|
"engines": {
|
|
44
35
|
"node": ">=22.12.0"
|
|
45
36
|
},
|
|
@@ -48,9 +39,9 @@
|
|
|
48
39
|
"CHANGELOG.md"
|
|
49
40
|
],
|
|
50
41
|
"dependencies": {
|
|
51
|
-
"@robota-sdk/agent-core": "3.0.0-beta.
|
|
52
|
-
"@robota-sdk/agent-interface-analytics": "3.0.0-beta.
|
|
53
|
-
"@robota-sdk/agent-interface-session": "3.0.0-beta.
|
|
42
|
+
"@robota-sdk/agent-core": "3.0.0-beta.88",
|
|
43
|
+
"@robota-sdk/agent-interface-analytics": "3.0.0-beta.88",
|
|
44
|
+
"@robota-sdk/agent-interface-session": "3.0.0-beta.88"
|
|
54
45
|
},
|
|
55
46
|
"devDependencies": {
|
|
56
47
|
"rimraf": "^5.0.10",
|
|
@@ -65,6 +56,14 @@
|
|
|
65
56
|
"volta": {
|
|
66
57
|
"extends": "../../package.json"
|
|
67
58
|
},
|
|
59
|
+
"repository": {
|
|
60
|
+
"type": "git",
|
|
61
|
+
"url": "https://github.com/woojubb/robota"
|
|
62
|
+
},
|
|
63
|
+
"bugs": {
|
|
64
|
+
"url": "https://github.com/woojubb/robota/issues"
|
|
65
|
+
},
|
|
66
|
+
"homepage": "https://robota.io/",
|
|
68
67
|
"scripts": {
|
|
69
68
|
"build": "rimraf dist && tsdown",
|
|
70
69
|
"build:js": "pnpm run build",
|