@ato-sdk/js 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -8
- package/dist/agent.d.mts +23 -0
- package/dist/agent.d.ts +23 -0
- package/dist/agent.js +319 -0
- package/dist/agent.mjs +124 -0
- package/package.json +10 -4
package/README.md
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
# @
|
|
1
|
+
# @ato-sdk/js
|
|
2
2
|
|
|
3
3
|
Auto-capture LLM traces for [ATO](https://agentictool.ai). Works with Anthropic, OpenAI, and any LLM provider.
|
|
4
4
|
|
|
5
5
|
## Install
|
|
6
6
|
|
|
7
7
|
```bash
|
|
8
|
-
npm install @
|
|
8
|
+
npm install @ato-sdk/js
|
|
9
9
|
```
|
|
10
10
|
|
|
11
11
|
## Quick Start
|
|
12
12
|
|
|
13
13
|
```typescript
|
|
14
|
-
import { init } from '@
|
|
14
|
+
import { init } from '@ato-sdk/js';
|
|
15
15
|
|
|
16
16
|
// Initialize with your ATO API key
|
|
17
17
|
init({ apiKey: 'your-ato-api-key' });
|
|
@@ -21,7 +21,7 @@ init({ apiKey: 'your-ato-api-key' });
|
|
|
21
21
|
|
|
22
22
|
```typescript
|
|
23
23
|
import Anthropic from '@anthropic-ai/sdk';
|
|
24
|
-
import { wrapAnthropic } from '@
|
|
24
|
+
import { wrapAnthropic } from '@ato-sdk/js/anthropic';
|
|
25
25
|
|
|
26
26
|
const client = wrapAnthropic(new Anthropic());
|
|
27
27
|
|
|
@@ -37,7 +37,7 @@ const msg = await client.messages.create({
|
|
|
37
37
|
|
|
38
38
|
```typescript
|
|
39
39
|
import OpenAI from 'openai';
|
|
40
|
-
import { wrapOpenAI } from '@
|
|
40
|
+
import { wrapOpenAI } from '@ato-sdk/js/openai';
|
|
41
41
|
|
|
42
42
|
const client = wrapOpenAI(new OpenAI());
|
|
43
43
|
|
|
@@ -81,8 +81,8 @@ init({
|
|
|
81
81
|
For custom LLM providers:
|
|
82
82
|
|
|
83
83
|
```typescript
|
|
84
|
-
import { capture, generateTraceId } from '@
|
|
85
|
-
import { calculateCost } from '@
|
|
84
|
+
import { capture, generateTraceId } from '@ato-sdk/js';
|
|
85
|
+
import { calculateCost } from '@ato-sdk/js';
|
|
86
86
|
|
|
87
87
|
capture({
|
|
88
88
|
id: generateTraceId(),
|
|
@@ -105,7 +105,7 @@ capture({
|
|
|
105
105
|
Built-in pricing for 60+ models:
|
|
106
106
|
|
|
107
107
|
```typescript
|
|
108
|
-
import { calculateCost } from '@
|
|
108
|
+
import { calculateCost } from '@ato-sdk/js';
|
|
109
109
|
|
|
110
110
|
calculateCost('claude-sonnet-4-6', 1000, 500); // $0.0105
|
|
111
111
|
calculateCost('gpt-4o', 1000, 500); // $0.0075
|
package/dist/agent.d.mts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export { A as AtoConfig, a as AtoTrace, M as MODEL_PRICING, c as calculateCost, g as getClient, i as init } from './pricing-DnUk84wO.mjs';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* ATO wrapper for the Claude Agent SDK
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* import { Agent } from 'claude-agent-sdk';
|
|
8
|
+
* import { wrapAgent } from '@ato-sdk/js/agent';
|
|
9
|
+
*
|
|
10
|
+
* const agent = wrapAgent(new Agent({ model: 'claude-sonnet-4-6' }));
|
|
11
|
+
* // All agent runs are now auto-traced
|
|
12
|
+
* const result = await agent.run('Fix the failing tests');
|
|
13
|
+
*/
|
|
14
|
+
type AgentInstance = {
|
|
15
|
+
run: (...args: any[]) => any;
|
|
16
|
+
[key: string]: any;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Wrap a Claude Agent SDK instance to auto-capture traces
|
|
20
|
+
*/
|
|
21
|
+
declare function wrapAgent<T extends AgentInstance>(agent: T): T;
|
|
22
|
+
|
|
23
|
+
export { wrapAgent };
|
package/dist/agent.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export { A as AtoConfig, a as AtoTrace, M as MODEL_PRICING, c as calculateCost, g as getClient, i as init } from './pricing-DnUk84wO.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* ATO wrapper for the Claude Agent SDK
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* import { Agent } from 'claude-agent-sdk';
|
|
8
|
+
* import { wrapAgent } from '@ato-sdk/js/agent';
|
|
9
|
+
*
|
|
10
|
+
* const agent = wrapAgent(new Agent({ model: 'claude-sonnet-4-6' }));
|
|
11
|
+
* // All agent runs are now auto-traced
|
|
12
|
+
* const result = await agent.run('Fix the failing tests');
|
|
13
|
+
*/
|
|
14
|
+
type AgentInstance = {
|
|
15
|
+
run: (...args: any[]) => any;
|
|
16
|
+
[key: string]: any;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Wrap a Claude Agent SDK instance to auto-capture traces
|
|
20
|
+
*/
|
|
21
|
+
declare function wrapAgent<T extends AgentInstance>(agent: T): T;
|
|
22
|
+
|
|
23
|
+
export { wrapAgent };
|
package/dist/agent.js
ADDED
|
@@ -0,0 +1,319 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/agent.ts
|
|
21
|
+
var agent_exports = {};
|
|
22
|
+
__export(agent_exports, {
|
|
23
|
+
MODEL_PRICING: () => MODEL_PRICING,
|
|
24
|
+
calculateCost: () => calculateCost,
|
|
25
|
+
getClient: () => getClient,
|
|
26
|
+
init: () => init,
|
|
27
|
+
wrapAgent: () => wrapAgent
|
|
28
|
+
});
|
|
29
|
+
module.exports = __toCommonJS(agent_exports);
|
|
30
|
+
|
|
31
|
+
// src/client.ts
|
|
32
|
+
var SDK_VERSION = "0.1.0";
|
|
33
|
+
var DEFAULT_ENDPOINT = "https://api.agentictool.ai";
|
|
34
|
+
var DEFAULT_FLUSH_INTERVAL = 5e3;
|
|
35
|
+
var DEFAULT_MAX_BATCH_SIZE = 50;
|
|
36
|
+
var globalClient = null;
|
|
37
|
+
var AtoClient = class {
|
|
38
|
+
constructor(config = {}) {
|
|
39
|
+
this.queue = [];
|
|
40
|
+
this.timer = null;
|
|
41
|
+
this.config = {
|
|
42
|
+
endpoint: DEFAULT_ENDPOINT,
|
|
43
|
+
batching: true,
|
|
44
|
+
flushInterval: DEFAULT_FLUSH_INTERVAL,
|
|
45
|
+
maxBatchSize: DEFAULT_MAX_BATCH_SIZE,
|
|
46
|
+
debug: false,
|
|
47
|
+
localOnly: false,
|
|
48
|
+
...config
|
|
49
|
+
};
|
|
50
|
+
if (this.config.batching && !this.config.localOnly) {
|
|
51
|
+
this.timer = setInterval(() => this.flush(), this.config.flushInterval);
|
|
52
|
+
if (this.timer && typeof this.timer === "object" && "unref" in this.timer) {
|
|
53
|
+
this.timer.unref();
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Record a trace
|
|
59
|
+
*/
|
|
60
|
+
capture(trace) {
|
|
61
|
+
if (this.config.defaultTags) {
|
|
62
|
+
trace.tags = [...trace.tags || [], ...this.config.defaultTags];
|
|
63
|
+
}
|
|
64
|
+
if (this.config.defaultMetadata) {
|
|
65
|
+
trace.metadata = { ...this.config.defaultMetadata, ...trace.metadata };
|
|
66
|
+
}
|
|
67
|
+
if (this.config.sessionId && !trace.sessionId) {
|
|
68
|
+
trace.sessionId = this.config.sessionId;
|
|
69
|
+
}
|
|
70
|
+
if (this.config.userId && !trace.userId) {
|
|
71
|
+
trace.userId = this.config.userId;
|
|
72
|
+
}
|
|
73
|
+
if (this.config.debug) {
|
|
74
|
+
console.log("[ato]", JSON.stringify(trace, null, 2));
|
|
75
|
+
}
|
|
76
|
+
if (this.config.localOnly) return;
|
|
77
|
+
this.queue.push(trace);
|
|
78
|
+
if (!this.config.batching || this.queue.length >= this.config.maxBatchSize) {
|
|
79
|
+
this.flush();
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Flush pending traces to ATO Cloud
|
|
84
|
+
*/
|
|
85
|
+
async flush() {
|
|
86
|
+
if (this.queue.length === 0) return;
|
|
87
|
+
const traces = this.queue.splice(0);
|
|
88
|
+
const payload = {
|
|
89
|
+
traces,
|
|
90
|
+
sdk: "@ato/sdk",
|
|
91
|
+
sdkVersion: SDK_VERSION,
|
|
92
|
+
sentAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
93
|
+
};
|
|
94
|
+
try {
|
|
95
|
+
const headers = {
|
|
96
|
+
"Content-Type": "application/json"
|
|
97
|
+
};
|
|
98
|
+
if (this.config.apiKey) {
|
|
99
|
+
headers["Authorization"] = `Bearer ${this.config.apiKey}`;
|
|
100
|
+
}
|
|
101
|
+
const res = await fetch(`${this.config.endpoint}/api/analytics/ingest`, {
|
|
102
|
+
method: "POST",
|
|
103
|
+
headers,
|
|
104
|
+
body: JSON.stringify(payload)
|
|
105
|
+
});
|
|
106
|
+
if (!res.ok && this.config.debug) {
|
|
107
|
+
console.error("[ato] Failed to send traces:", res.status, await res.text());
|
|
108
|
+
}
|
|
109
|
+
} catch (err) {
|
|
110
|
+
if (this.config.debug) {
|
|
111
|
+
console.error("[ato] Failed to send traces:", err);
|
|
112
|
+
}
|
|
113
|
+
this.queue.unshift(...traces);
|
|
114
|
+
if (this.queue.length > 1e3) {
|
|
115
|
+
this.queue.splice(0, this.queue.length - 500);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Shutdown — flush remaining traces
|
|
121
|
+
*/
|
|
122
|
+
async shutdown() {
|
|
123
|
+
if (this.timer) {
|
|
124
|
+
clearInterval(this.timer);
|
|
125
|
+
this.timer = null;
|
|
126
|
+
}
|
|
127
|
+
await this.flush();
|
|
128
|
+
}
|
|
129
|
+
getConfig() {
|
|
130
|
+
return { ...this.config };
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
function init(config = {}) {
|
|
134
|
+
globalClient = new AtoClient(config);
|
|
135
|
+
return globalClient;
|
|
136
|
+
}
|
|
137
|
+
function getClient() {
|
|
138
|
+
if (!globalClient) {
|
|
139
|
+
globalClient = new AtoClient();
|
|
140
|
+
}
|
|
141
|
+
return globalClient;
|
|
142
|
+
}
|
|
143
|
+
function generateTraceId() {
|
|
144
|
+
return `ato_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// src/pricing.ts
|
|
148
|
+
var MODEL_PRICING = {
|
|
149
|
+
// Anthropic
|
|
150
|
+
"claude-opus-4-6": { input: 15, output: 75, cached: 1.5 },
|
|
151
|
+
"claude-sonnet-4-6": { input: 3, output: 15, cached: 0.3 },
|
|
152
|
+
"claude-haiku-4-5": { input: 0.8, output: 4, cached: 0.08 },
|
|
153
|
+
"claude-sonnet-4-5": { input: 3, output: 15, cached: 0.3 },
|
|
154
|
+
"claude-3-5-sonnet": { input: 3, output: 15, cached: 0.3 },
|
|
155
|
+
"claude-3-5-haiku": { input: 0.8, output: 4, cached: 0.08 },
|
|
156
|
+
"claude-3-opus": { input: 15, output: 75, cached: 1.5 },
|
|
157
|
+
"claude-3-sonnet": { input: 3, output: 15 },
|
|
158
|
+
"claude-3-haiku": { input: 0.25, output: 1.25 },
|
|
159
|
+
// OpenAI
|
|
160
|
+
"gpt-4o": { input: 2.5, output: 10, cached: 1.25 },
|
|
161
|
+
"gpt-4o-mini": { input: 0.15, output: 0.6, cached: 0.075 },
|
|
162
|
+
"gpt-4-turbo": { input: 10, output: 30 },
|
|
163
|
+
"gpt-4": { input: 30, output: 60 },
|
|
164
|
+
"gpt-3.5-turbo": { input: 0.5, output: 1.5 },
|
|
165
|
+
"o1": { input: 15, output: 60, cached: 7.5 },
|
|
166
|
+
"o1-mini": { input: 3, output: 12, cached: 1.5 },
|
|
167
|
+
"o1-pro": { input: 150, output: 600 },
|
|
168
|
+
"o3": { input: 10, output: 40, cached: 2.5 },
|
|
169
|
+
"o3-mini": { input: 1.1, output: 4.4, cached: 0.55 },
|
|
170
|
+
"o4-mini": { input: 1.1, output: 4.4, cached: 0.275 },
|
|
171
|
+
"gpt-4.1": { input: 2, output: 8, cached: 0.5 },
|
|
172
|
+
"gpt-4.1-mini": { input: 0.4, output: 1.6, cached: 0.1 },
|
|
173
|
+
"gpt-4.1-nano": { input: 0.1, output: 0.4, cached: 0.025 },
|
|
174
|
+
// Google
|
|
175
|
+
"gemini-2.5-pro": { input: 1.25, output: 10 },
|
|
176
|
+
"gemini-2.5-flash": { input: 0.15, output: 0.6 },
|
|
177
|
+
"gemini-2.0-flash": { input: 0.1, output: 0.4 },
|
|
178
|
+
"gemini-1.5-pro": { input: 1.25, output: 5 },
|
|
179
|
+
"gemini-1.5-flash": { input: 0.075, output: 0.3 },
|
|
180
|
+
// Mistral
|
|
181
|
+
"mistral-large": { input: 2, output: 6 },
|
|
182
|
+
"mistral-small": { input: 0.2, output: 0.6 },
|
|
183
|
+
"codestral": { input: 0.3, output: 0.9 },
|
|
184
|
+
// Groq (inference pricing)
|
|
185
|
+
"llama-3.3-70b": { input: 0.59, output: 0.79 },
|
|
186
|
+
"llama-3.1-8b": { input: 0.05, output: 0.08 },
|
|
187
|
+
"mixtral-8x7b": { input: 0.24, output: 0.24 },
|
|
188
|
+
// Cohere
|
|
189
|
+
"command-r-plus": { input: 2.5, output: 10 },
|
|
190
|
+
"command-r": { input: 0.15, output: 0.6 }
|
|
191
|
+
};
|
|
192
|
+
function calculateCost(model, inputTokens, outputTokens, cachedTokens = 0) {
|
|
193
|
+
const pricing = MODEL_PRICING[model] || Object.entries(MODEL_PRICING).find(
|
|
194
|
+
([key]) => model.startsWith(key)
|
|
195
|
+
)?.[1];
|
|
196
|
+
if (!pricing) return 0;
|
|
197
|
+
const inputCost = (inputTokens - cachedTokens) / 1e6 * pricing.input;
|
|
198
|
+
const outputCost = outputTokens / 1e6 * pricing.output;
|
|
199
|
+
const cachedCost = pricing.cached ? cachedTokens / 1e6 * pricing.cached : 0;
|
|
200
|
+
return inputCost + outputCost + cachedCost;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
// src/agent.ts
|
|
204
|
+
function wrapAgent(agent) {
|
|
205
|
+
const originalRun = agent.run.bind(agent);
|
|
206
|
+
agent.run = async function(...args) {
|
|
207
|
+
const prompt = typeof args[0] === "string" ? args[0] : args[0]?.prompt || "";
|
|
208
|
+
const start = Date.now();
|
|
209
|
+
let totalInputTokens = 0;
|
|
210
|
+
let totalOutputTokens = 0;
|
|
211
|
+
let totalCachedTokens = 0;
|
|
212
|
+
let model = agent.model || "claude-sonnet-4-6";
|
|
213
|
+
let toolCalls = 0;
|
|
214
|
+
let status = "success";
|
|
215
|
+
let error;
|
|
216
|
+
try {
|
|
217
|
+
const result = originalRun(...args);
|
|
218
|
+
if (result && Symbol.asyncIterator in result) {
|
|
219
|
+
const originalIterator = result[Symbol.asyncIterator].bind(result);
|
|
220
|
+
result[Symbol.asyncIterator] = async function* () {
|
|
221
|
+
for await (const message of originalIterator()) {
|
|
222
|
+
if (message.type === "usage" || message.usage) {
|
|
223
|
+
const usage = message.usage || message;
|
|
224
|
+
totalInputTokens += usage.input_tokens || 0;
|
|
225
|
+
totalOutputTokens += usage.output_tokens || 0;
|
|
226
|
+
totalCachedTokens += usage.cache_read_input_tokens || 0;
|
|
227
|
+
}
|
|
228
|
+
if (message.type === "tool_use" || message.type === "tool_call") {
|
|
229
|
+
toolCalls++;
|
|
230
|
+
}
|
|
231
|
+
if (message.model) {
|
|
232
|
+
model = message.model;
|
|
233
|
+
}
|
|
234
|
+
yield message;
|
|
235
|
+
}
|
|
236
|
+
captureAgentTrace({
|
|
237
|
+
start,
|
|
238
|
+
model,
|
|
239
|
+
prompt,
|
|
240
|
+
totalInputTokens,
|
|
241
|
+
totalOutputTokens,
|
|
242
|
+
totalCachedTokens,
|
|
243
|
+
toolCalls,
|
|
244
|
+
status,
|
|
245
|
+
error
|
|
246
|
+
});
|
|
247
|
+
};
|
|
248
|
+
return result;
|
|
249
|
+
}
|
|
250
|
+
const awaited = await result;
|
|
251
|
+
if (awaited?.usage) {
|
|
252
|
+
totalInputTokens = awaited.usage.input_tokens || 0;
|
|
253
|
+
totalOutputTokens = awaited.usage.output_tokens || 0;
|
|
254
|
+
totalCachedTokens = awaited.usage.cache_read_input_tokens || 0;
|
|
255
|
+
}
|
|
256
|
+
if (awaited?.model) model = awaited.model;
|
|
257
|
+
if (awaited?.tool_calls) toolCalls = awaited.tool_calls;
|
|
258
|
+
captureAgentTrace({
|
|
259
|
+
start,
|
|
260
|
+
model,
|
|
261
|
+
prompt,
|
|
262
|
+
totalInputTokens,
|
|
263
|
+
totalOutputTokens,
|
|
264
|
+
totalCachedTokens,
|
|
265
|
+
toolCalls,
|
|
266
|
+
status,
|
|
267
|
+
error
|
|
268
|
+
});
|
|
269
|
+
return awaited;
|
|
270
|
+
} catch (err) {
|
|
271
|
+
status = "error";
|
|
272
|
+
error = err.message || String(err);
|
|
273
|
+
captureAgentTrace({
|
|
274
|
+
start,
|
|
275
|
+
model,
|
|
276
|
+
prompt,
|
|
277
|
+
totalInputTokens,
|
|
278
|
+
totalOutputTokens,
|
|
279
|
+
totalCachedTokens,
|
|
280
|
+
toolCalls,
|
|
281
|
+
status,
|
|
282
|
+
error
|
|
283
|
+
});
|
|
284
|
+
throw err;
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
return agent;
|
|
288
|
+
}
|
|
289
|
+
function captureAgentTrace(params) {
|
|
290
|
+
const duration = Date.now() - params.start;
|
|
291
|
+
const trace = {
|
|
292
|
+
id: generateTraceId(),
|
|
293
|
+
provider: "anthropic-agent",
|
|
294
|
+
model: params.model,
|
|
295
|
+
inputTokens: params.totalInputTokens,
|
|
296
|
+
outputTokens: params.totalOutputTokens,
|
|
297
|
+
cachedTokens: params.totalCachedTokens,
|
|
298
|
+
totalTokens: params.totalInputTokens + params.totalOutputTokens,
|
|
299
|
+
costUsd: calculateCost(params.model, params.totalInputTokens, params.totalOutputTokens, params.totalCachedTokens),
|
|
300
|
+
durationMs: duration,
|
|
301
|
+
status: params.status,
|
|
302
|
+
error: params.error,
|
|
303
|
+
metadata: {
|
|
304
|
+
type: "agent-session",
|
|
305
|
+
prompt: params.prompt.slice(0, 200),
|
|
306
|
+
toolCalls: params.toolCalls
|
|
307
|
+
},
|
|
308
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
309
|
+
};
|
|
310
|
+
getClient().capture(trace);
|
|
311
|
+
}
|
|
312
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
313
|
+
0 && (module.exports = {
|
|
314
|
+
MODEL_PRICING,
|
|
315
|
+
calculateCost,
|
|
316
|
+
getClient,
|
|
317
|
+
init,
|
|
318
|
+
wrapAgent
|
|
319
|
+
});
|
package/dist/agent.mjs
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MODEL_PRICING,
|
|
3
|
+
calculateCost,
|
|
4
|
+
generateTraceId,
|
|
5
|
+
getClient,
|
|
6
|
+
init
|
|
7
|
+
} from "./chunk-Q2LJUUHK.mjs";
|
|
8
|
+
|
|
9
|
+
// src/agent.ts
|
|
10
|
+
function wrapAgent(agent) {
|
|
11
|
+
const originalRun = agent.run.bind(agent);
|
|
12
|
+
agent.run = async function(...args) {
|
|
13
|
+
const prompt = typeof args[0] === "string" ? args[0] : args[0]?.prompt || "";
|
|
14
|
+
const start = Date.now();
|
|
15
|
+
let totalInputTokens = 0;
|
|
16
|
+
let totalOutputTokens = 0;
|
|
17
|
+
let totalCachedTokens = 0;
|
|
18
|
+
let model = agent.model || "claude-sonnet-4-6";
|
|
19
|
+
let toolCalls = 0;
|
|
20
|
+
let status = "success";
|
|
21
|
+
let error;
|
|
22
|
+
try {
|
|
23
|
+
const result = originalRun(...args);
|
|
24
|
+
if (result && Symbol.asyncIterator in result) {
|
|
25
|
+
const originalIterator = result[Symbol.asyncIterator].bind(result);
|
|
26
|
+
result[Symbol.asyncIterator] = async function* () {
|
|
27
|
+
for await (const message of originalIterator()) {
|
|
28
|
+
if (message.type === "usage" || message.usage) {
|
|
29
|
+
const usage = message.usage || message;
|
|
30
|
+
totalInputTokens += usage.input_tokens || 0;
|
|
31
|
+
totalOutputTokens += usage.output_tokens || 0;
|
|
32
|
+
totalCachedTokens += usage.cache_read_input_tokens || 0;
|
|
33
|
+
}
|
|
34
|
+
if (message.type === "tool_use" || message.type === "tool_call") {
|
|
35
|
+
toolCalls++;
|
|
36
|
+
}
|
|
37
|
+
if (message.model) {
|
|
38
|
+
model = message.model;
|
|
39
|
+
}
|
|
40
|
+
yield message;
|
|
41
|
+
}
|
|
42
|
+
captureAgentTrace({
|
|
43
|
+
start,
|
|
44
|
+
model,
|
|
45
|
+
prompt,
|
|
46
|
+
totalInputTokens,
|
|
47
|
+
totalOutputTokens,
|
|
48
|
+
totalCachedTokens,
|
|
49
|
+
toolCalls,
|
|
50
|
+
status,
|
|
51
|
+
error
|
|
52
|
+
});
|
|
53
|
+
};
|
|
54
|
+
return result;
|
|
55
|
+
}
|
|
56
|
+
const awaited = await result;
|
|
57
|
+
if (awaited?.usage) {
|
|
58
|
+
totalInputTokens = awaited.usage.input_tokens || 0;
|
|
59
|
+
totalOutputTokens = awaited.usage.output_tokens || 0;
|
|
60
|
+
totalCachedTokens = awaited.usage.cache_read_input_tokens || 0;
|
|
61
|
+
}
|
|
62
|
+
if (awaited?.model) model = awaited.model;
|
|
63
|
+
if (awaited?.tool_calls) toolCalls = awaited.tool_calls;
|
|
64
|
+
captureAgentTrace({
|
|
65
|
+
start,
|
|
66
|
+
model,
|
|
67
|
+
prompt,
|
|
68
|
+
totalInputTokens,
|
|
69
|
+
totalOutputTokens,
|
|
70
|
+
totalCachedTokens,
|
|
71
|
+
toolCalls,
|
|
72
|
+
status,
|
|
73
|
+
error
|
|
74
|
+
});
|
|
75
|
+
return awaited;
|
|
76
|
+
} catch (err) {
|
|
77
|
+
status = "error";
|
|
78
|
+
error = err.message || String(err);
|
|
79
|
+
captureAgentTrace({
|
|
80
|
+
start,
|
|
81
|
+
model,
|
|
82
|
+
prompt,
|
|
83
|
+
totalInputTokens,
|
|
84
|
+
totalOutputTokens,
|
|
85
|
+
totalCachedTokens,
|
|
86
|
+
toolCalls,
|
|
87
|
+
status,
|
|
88
|
+
error
|
|
89
|
+
});
|
|
90
|
+
throw err;
|
|
91
|
+
}
|
|
92
|
+
};
|
|
93
|
+
return agent;
|
|
94
|
+
}
|
|
95
|
+
function captureAgentTrace(params) {
|
|
96
|
+
const duration = Date.now() - params.start;
|
|
97
|
+
const trace = {
|
|
98
|
+
id: generateTraceId(),
|
|
99
|
+
provider: "anthropic-agent",
|
|
100
|
+
model: params.model,
|
|
101
|
+
inputTokens: params.totalInputTokens,
|
|
102
|
+
outputTokens: params.totalOutputTokens,
|
|
103
|
+
cachedTokens: params.totalCachedTokens,
|
|
104
|
+
totalTokens: params.totalInputTokens + params.totalOutputTokens,
|
|
105
|
+
costUsd: calculateCost(params.model, params.totalInputTokens, params.totalOutputTokens, params.totalCachedTokens),
|
|
106
|
+
durationMs: duration,
|
|
107
|
+
status: params.status,
|
|
108
|
+
error: params.error,
|
|
109
|
+
metadata: {
|
|
110
|
+
type: "agent-session",
|
|
111
|
+
prompt: params.prompt.slice(0, 200),
|
|
112
|
+
toolCalls: params.toolCalls
|
|
113
|
+
},
|
|
114
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
115
|
+
};
|
|
116
|
+
getClient().capture(trace);
|
|
117
|
+
}
|
|
118
|
+
export {
|
|
119
|
+
MODEL_PRICING,
|
|
120
|
+
calculateCost,
|
|
121
|
+
getClient,
|
|
122
|
+
init,
|
|
123
|
+
wrapAgent
|
|
124
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ato-sdk/js",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Auto-capture LLM traces for ATO — works with Anthropic, OpenAI, and any LLM provider",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
@@ -20,14 +20,19 @@
|
|
|
20
20
|
"import": "./dist/openai.mjs",
|
|
21
21
|
"require": "./dist/openai.js",
|
|
22
22
|
"types": "./dist/openai.d.ts"
|
|
23
|
+
},
|
|
24
|
+
"./agent": {
|
|
25
|
+
"import": "./dist/agent.mjs",
|
|
26
|
+
"require": "./dist/agent.js",
|
|
27
|
+
"types": "./dist/agent.d.ts"
|
|
23
28
|
}
|
|
24
29
|
},
|
|
25
30
|
"files": [
|
|
26
31
|
"dist"
|
|
27
32
|
],
|
|
28
33
|
"scripts": {
|
|
29
|
-
"build": "tsup src/index.ts src/anthropic.ts src/openai.ts --format cjs,esm --dts --clean",
|
|
30
|
-
"dev": "tsup src/index.ts src/anthropic.ts src/openai.ts --format cjs,esm --dts --watch"
|
|
34
|
+
"build": "tsup src/index.ts src/anthropic.ts src/openai.ts src/agent.ts --format cjs,esm --dts --clean",
|
|
35
|
+
"dev": "tsup src/index.ts src/anthropic.ts src/openai.ts src/agent.ts --format cjs,esm --dts --watch"
|
|
31
36
|
},
|
|
32
37
|
"keywords": [
|
|
33
38
|
"ato",
|
|
@@ -58,6 +63,7 @@
|
|
|
58
63
|
},
|
|
59
64
|
"peerDependenciesMeta": {
|
|
60
65
|
"@anthropic-ai/sdk": { "optional": true },
|
|
61
|
-
"openai": { "optional": true }
|
|
66
|
+
"openai": { "optional": true },
|
|
67
|
+
"claude-agent-sdk": { "optional": true }
|
|
62
68
|
}
|
|
63
69
|
}
|