@warpmetrics/warp 0.0.17 → 0.0.19
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 +35 -2
- package/package.json +1 -1
- package/src/core/transport.js +2 -2
- package/src/core/warp.js +13 -7
- package/src/index.d.ts +39 -0
- package/src/trace/group.js +2 -0
- package/src/trace/run.js +2 -0
- package/src/trace/trace.js +7 -2
package/README.md
CHANGED
|
@@ -14,7 +14,7 @@ npm install @warpmetrics/warp
|
|
|
14
14
|
|
|
15
15
|
```js
|
|
16
16
|
import OpenAI from 'openai';
|
|
17
|
-
import { warp, run, group, call, outcome } from '@warpmetrics/warp';
|
|
17
|
+
import { warp, run, group, call, trace, outcome } from '@warpmetrics/warp';
|
|
18
18
|
|
|
19
19
|
const openai = warp(new OpenAI(), { apiKey: 'wm_...' });
|
|
20
20
|
|
|
@@ -90,6 +90,38 @@ call(r, response);
|
|
|
90
90
|
call(g, response, { label: 'extract' }); // with opts
|
|
91
91
|
```
|
|
92
92
|
|
|
93
|
+
### `trace(target, data)`
|
|
94
|
+
|
|
95
|
+
Manually record an LLM call for providers not wrapped by `warp()`.
|
|
96
|
+
|
|
97
|
+
```js
|
|
98
|
+
trace(r, {
|
|
99
|
+
provider: 'google',
|
|
100
|
+
model: 'gemini-2.0-flash',
|
|
101
|
+
messages: [{ role: 'user', content: 'Hello' }],
|
|
102
|
+
response: 'Hi there!',
|
|
103
|
+
tokens: { prompt: 10, completion: 5 },
|
|
104
|
+
latency: 230,
|
|
105
|
+
cost: 0.0001,
|
|
106
|
+
});
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
| Field | Type | Required | Description |
|
|
110
|
+
|---|---|---|---|
|
|
111
|
+
| `provider` | `string` | Yes | Provider name (e.g. `"google"`, `"cohere"`) |
|
|
112
|
+
| `model` | `string` | Yes | Model identifier |
|
|
113
|
+
| `messages` | `any` | No | Request messages/input |
|
|
114
|
+
| `response` | `string` | No | Response text |
|
|
115
|
+
| `tools` | `string[]` | No | Tool names available |
|
|
116
|
+
| `toolCalls` | `{ id, name, arguments }[]` | No | Tool calls made |
|
|
117
|
+
| `tokens` | `{ prompt?, completion?, total? }` | No | Token usage |
|
|
118
|
+
| `latency` | `number` | No | Duration in milliseconds |
|
|
119
|
+
| `timestamp` | `string` | No | ISO 8601 timestamp (auto-generated if omitted) |
|
|
120
|
+
| `status` | `string` | No | `"success"` (default) or `"error"` |
|
|
121
|
+
| `error` | `string` | No | Error message |
|
|
122
|
+
| `cost` | `number` | No | Cost in USD |
|
|
123
|
+
| `opts` | `Record<string, any>` | No | Custom metadata |
|
|
124
|
+
|
|
93
125
|
### `outcome(target, name, opts?)`
|
|
94
126
|
|
|
95
127
|
Record an outcome on any tracked target.
|
|
@@ -110,11 +142,12 @@ const r2 = run(a, 'Code Review');
|
|
|
110
142
|
|
|
111
143
|
### `ref(target)`
|
|
112
144
|
|
|
113
|
-
Resolve any target (run, group, or LLM response) to its string ID.
|
|
145
|
+
Resolve any target (run, group, outcome, act, or LLM response) to its string ID. Also accepts raw ID strings (e.g. `"wm_run_..."` loaded from a database) and registers them locally.
|
|
114
146
|
|
|
115
147
|
```js
|
|
116
148
|
ref(r) // 'wm_run_01jkx3ndek0gh4r5tmqp9a3bcv'
|
|
117
149
|
ref(response) // 'wm_call_01jkx3ndef8mn2q7kpvhc4e9ws'
|
|
150
|
+
ref('wm_run_01jkx3ndek0gh4r5tmqp9a3bcv') // adopts and returns the ID
|
|
118
151
|
```
|
|
119
152
|
|
|
120
153
|
### `flush()`
|
package/package.json
CHANGED
package/src/core/transport.js
CHANGED
|
@@ -166,7 +166,7 @@ export function logRun(data) {
|
|
|
166
166
|
label: data.label,
|
|
167
167
|
opts: data.opts || null,
|
|
168
168
|
refId: data.refId || null,
|
|
169
|
-
|
|
169
|
+
startedAt: data.startedAt || new Date().toISOString(),
|
|
170
170
|
});
|
|
171
171
|
}
|
|
172
172
|
|
|
@@ -175,7 +175,7 @@ export function logGroup(data) {
|
|
|
175
175
|
id: data.id,
|
|
176
176
|
label: data.label,
|
|
177
177
|
opts: data.opts || null,
|
|
178
|
-
|
|
178
|
+
startedAt: data.startedAt || new Date().toISOString(),
|
|
179
179
|
});
|
|
180
180
|
}
|
|
181
181
|
|
package/src/core/warp.js
CHANGED
|
@@ -32,13 +32,14 @@ function createInterceptor(originalFn, context, provider) {
|
|
|
32
32
|
|
|
33
33
|
try {
|
|
34
34
|
const result = await originalFn.apply(context, args);
|
|
35
|
-
const
|
|
35
|
+
const duration = Date.now() - start;
|
|
36
36
|
|
|
37
37
|
if (stream) {
|
|
38
38
|
return wrapStream(result, { callId, provider, model, messages, tools, start });
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
const ext = provider.extract(result);
|
|
42
|
+
const endedAt = new Date().toISOString();
|
|
42
43
|
|
|
43
44
|
responseRegistry.set(result, {
|
|
44
45
|
id: callId,
|
|
@@ -47,8 +48,9 @@ function createInterceptor(originalFn, context, provider) {
|
|
|
47
48
|
response: ext.response,
|
|
48
49
|
tools: tools ? tools.map(t => t.function?.name || t.name).filter(Boolean) : null,
|
|
49
50
|
toolCalls: ext.toolCalls,
|
|
50
|
-
tokens: ext.tokens,
|
|
51
|
-
|
|
51
|
+
tokens: ext.tokens, duration,
|
|
52
|
+
startedAt: new Date(start).toISOString(),
|
|
53
|
+
endedAt,
|
|
52
54
|
status: 'success',
|
|
53
55
|
},
|
|
54
56
|
});
|
|
@@ -56,13 +58,15 @@ function createInterceptor(originalFn, context, provider) {
|
|
|
56
58
|
return result;
|
|
57
59
|
} catch (error) {
|
|
58
60
|
const errorResult = { _warpError: true };
|
|
61
|
+
const duration = Date.now() - start;
|
|
59
62
|
responseRegistry.set(errorResult, {
|
|
60
63
|
id: callId,
|
|
61
64
|
data: {
|
|
62
65
|
id: callId, provider: provider.name, model, messages,
|
|
63
66
|
error: error.message,
|
|
64
|
-
|
|
65
|
-
|
|
67
|
+
duration,
|
|
68
|
+
startedAt: new Date(start).toISOString(),
|
|
69
|
+
endedAt: new Date().toISOString(),
|
|
66
70
|
status: 'error',
|
|
67
71
|
},
|
|
68
72
|
});
|
|
@@ -95,6 +99,7 @@ function wrapStream(stream, ctx) {
|
|
|
95
99
|
? ctx.provider.normalizeUsage(usage)
|
|
96
100
|
: { prompt: 0, completion: 0, total: 0 };
|
|
97
101
|
|
|
102
|
+
const duration = Date.now() - ctx.start;
|
|
98
103
|
responseRegistry.set(wrapped, {
|
|
99
104
|
id: ctx.callId,
|
|
100
105
|
data: {
|
|
@@ -102,8 +107,9 @@ function wrapStream(stream, ctx) {
|
|
|
102
107
|
response: content,
|
|
103
108
|
tools: ctx.tools ? ctx.tools.map(t => t.function?.name || t.name).filter(Boolean) : null,
|
|
104
109
|
tokens,
|
|
105
|
-
|
|
106
|
-
|
|
110
|
+
duration,
|
|
111
|
+
startedAt: new Date(ctx.start).toISOString(),
|
|
112
|
+
endedAt: new Date().toISOString(),
|
|
107
113
|
status: 'success',
|
|
108
114
|
},
|
|
109
115
|
});
|
package/src/index.d.ts
CHANGED
|
@@ -47,6 +47,45 @@ export function group(target: Run | Group | string, label: string, opts?: Record
|
|
|
47
47
|
/** Track an LLM call by linking a response to a run or group. */
|
|
48
48
|
export function call(target: Run | Group | string, response: object, opts?: Record<string, any>): void;
|
|
49
49
|
|
|
50
|
+
export interface TraceData {
|
|
51
|
+
/** Provider name (e.g. "google", "cohere"). */
|
|
52
|
+
provider: string;
|
|
53
|
+
/** Model identifier. */
|
|
54
|
+
model: string;
|
|
55
|
+
/** Request messages/input. */
|
|
56
|
+
messages?: any;
|
|
57
|
+
/** Response text. */
|
|
58
|
+
response?: string;
|
|
59
|
+
/** Tool names available. */
|
|
60
|
+
tools?: string[];
|
|
61
|
+
/** Tool calls made. */
|
|
62
|
+
toolCalls?: { id?: string; name: string; arguments?: string }[];
|
|
63
|
+
/** Token usage. */
|
|
64
|
+
tokens?: { prompt?: number; completion?: number; total?: number };
|
|
65
|
+
/** Duration in milliseconds. */
|
|
66
|
+
duration?: number;
|
|
67
|
+
/** ISO 8601 timestamp of when the call started. */
|
|
68
|
+
startedAt?: string;
|
|
69
|
+
/** ISO 8601 timestamp of when the call ended (auto-generated if omitted). */
|
|
70
|
+
endedAt?: string;
|
|
71
|
+
/** "success" (default) or "error". */
|
|
72
|
+
status?: string;
|
|
73
|
+
/** Error message. */
|
|
74
|
+
error?: string;
|
|
75
|
+
/** Cost in USD. */
|
|
76
|
+
cost?: number;
|
|
77
|
+
/** Custom metadata. */
|
|
78
|
+
opts?: Record<string, any>;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export interface Call {
|
|
82
|
+
readonly id: string;
|
|
83
|
+
readonly _type: 'call';
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/** Manually record an LLM call for providers not wrapped by warp(). */
|
|
87
|
+
export function trace(target: Run | Group | string, data: TraceData): Call | undefined;
|
|
88
|
+
|
|
50
89
|
/** Record an outcome on any tracked target. Returns an Outcome handle for use with act(). */
|
|
51
90
|
export function outcome(
|
|
52
91
|
target: Run | Group | object | string,
|
package/src/trace/group.js
CHANGED
|
@@ -14,6 +14,7 @@ import { logGroup, logLink, getConfig } from '../core/transport.js';
|
|
|
14
14
|
* @returns {{ readonly id: string, readonly _type: 'group' }}
|
|
15
15
|
*/
|
|
16
16
|
export function group(target, label, opts) {
|
|
17
|
+
const startedAt = new Date().toISOString();
|
|
17
18
|
const targetId = getRef(target);
|
|
18
19
|
if (!targetId) {
|
|
19
20
|
if (getConfig().debug) console.warn('[warpmetrics] group() — target not recognised.');
|
|
@@ -29,6 +30,7 @@ export function group(target, label, opts) {
|
|
|
29
30
|
label,
|
|
30
31
|
opts: opts || null,
|
|
31
32
|
parentId: targetId,
|
|
33
|
+
startedAt,
|
|
32
34
|
groups: [],
|
|
33
35
|
calls: [],
|
|
34
36
|
};
|
package/src/trace/run.js
CHANGED
|
@@ -14,6 +14,7 @@ import { logRun, getConfig } from '../core/transport.js';
|
|
|
14
14
|
* @returns {{ readonly id: string, readonly _type: 'run' }}
|
|
15
15
|
*/
|
|
16
16
|
export function run(labelOrRef, labelOrOpts, maybeOpts) {
|
|
17
|
+
const startedAt = new Date().toISOString();
|
|
17
18
|
let refId = null;
|
|
18
19
|
let label, opts;
|
|
19
20
|
|
|
@@ -37,6 +38,7 @@ export function run(labelOrRef, labelOrOpts, maybeOpts) {
|
|
|
37
38
|
label,
|
|
38
39
|
opts,
|
|
39
40
|
refId,
|
|
41
|
+
startedAt,
|
|
40
42
|
groups: [],
|
|
41
43
|
calls: [],
|
|
42
44
|
};
|
package/src/trace/trace.js
CHANGED
|
@@ -26,6 +26,10 @@ export function trace(target, data) {
|
|
|
26
26
|
|
|
27
27
|
const id = generateId('call');
|
|
28
28
|
|
|
29
|
+
const endedAt = data.endedAt || data.timestamp || new Date().toISOString();
|
|
30
|
+
const duration = data.duration ?? data.latency ?? null;
|
|
31
|
+
const startedAt = data.startedAt || (duration != null ? new Date(new Date(endedAt).getTime() - duration).toISOString() : endedAt);
|
|
32
|
+
|
|
29
33
|
const event = {
|
|
30
34
|
id,
|
|
31
35
|
provider: data.provider,
|
|
@@ -35,8 +39,9 @@ export function trace(target, data) {
|
|
|
35
39
|
tools: data.tools || null,
|
|
36
40
|
toolCalls: data.toolCalls || null,
|
|
37
41
|
tokens: data.tokens || null,
|
|
38
|
-
|
|
39
|
-
|
|
42
|
+
duration,
|
|
43
|
+
startedAt,
|
|
44
|
+
endedAt,
|
|
40
45
|
status: data.status || 'success',
|
|
41
46
|
};
|
|
42
47
|
|