@breadcrumb-sdk/core 0.0.2 → 0.0.3
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/LICENSE +661 -0
- package/README.md +20 -2
- package/dist/index.cjs +216 -110
- package/dist/index.d.cts +22 -3
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +22 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +216 -110
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -130,10 +130,24 @@ span.set({
|
|
|
130
130
|
|
|
131
131
|
All fields are optional. `null` and `undefined` are ignored.
|
|
132
132
|
|
|
133
|
+
For `input`, passing a `Message[]` array renders the conversation with role labels in the UI — the same way AI SDK spans appear:
|
|
134
|
+
|
|
135
|
+
```ts
|
|
136
|
+
import type { Message } from "@breadcrumb-sdk/core";
|
|
137
|
+
|
|
138
|
+
span.set({
|
|
139
|
+
input: [
|
|
140
|
+
{ role: "system", content: "You are a helpful assistant." },
|
|
141
|
+
{ role: "user", content: "What is TypeScript?" },
|
|
142
|
+
] satisfies Message[],
|
|
143
|
+
output: "TypeScript is a typed superset of JavaScript.",
|
|
144
|
+
});
|
|
145
|
+
```
|
|
146
|
+
|
|
133
147
|
| Field | Type | Description |
|
|
134
148
|
|-------|------|-------------|
|
|
135
|
-
| `input` | `
|
|
136
|
-
| `output` | `
|
|
149
|
+
| `input` | `string \| Message[] \| object` | Input passed to this step |
|
|
150
|
+
| `output` | `string \| object` | Output produced by this step |
|
|
137
151
|
| `model` | `string` | Model name, e.g. `"gpt-4o"` |
|
|
138
152
|
| `provider` | `string` | Provider, e.g. `"openai"` |
|
|
139
153
|
| `input_tokens` | `number` | Input token count |
|
|
@@ -141,3 +155,7 @@ All fields are optional. `null` and `undefined` are ignored.
|
|
|
141
155
|
| `input_cost_usd` | `number` | Input cost in USD |
|
|
142
156
|
| `output_cost_usd` | `number` | Output cost in USD |
|
|
143
157
|
| `metadata` | `Record<string, string \| number \| boolean>` | Any extra data |
|
|
158
|
+
|
|
159
|
+
## License
|
|
160
|
+
|
|
161
|
+
AGPL-3.0 — see [LICENSE](./LICENSE) for details.
|
package/dist/index.cjs
CHANGED
|
@@ -27,7 +27,38 @@ const __opentelemetry_sdk_trace_node = __toESM(require("@opentelemetry/sdk-trace
|
|
|
27
27
|
const __opentelemetry_sdk_trace_base = __toESM(require("@opentelemetry/sdk-trace-base"));
|
|
28
28
|
const __opentelemetry_core = __toESM(require("@opentelemetry/core"));
|
|
29
29
|
|
|
30
|
-
//#region src/
|
|
30
|
+
//#region src/mappers/utils.ts
|
|
31
|
+
function tryJson(s) {
|
|
32
|
+
try {
|
|
33
|
+
return JSON.parse(s);
|
|
34
|
+
} catch {
|
|
35
|
+
return void 0;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function strAttr(attrs, ...keys) {
|
|
39
|
+
for (const key of keys) {
|
|
40
|
+
const v = attrs[key];
|
|
41
|
+
if (typeof v === "string" && v !== "") return v;
|
|
42
|
+
}
|
|
43
|
+
return void 0;
|
|
44
|
+
}
|
|
45
|
+
function intAttr(attrs, ...keys) {
|
|
46
|
+
for (const key of keys) {
|
|
47
|
+
const v = attrs[key];
|
|
48
|
+
if (typeof v === "number") return Math.round(v);
|
|
49
|
+
}
|
|
50
|
+
return void 0;
|
|
51
|
+
}
|
|
52
|
+
function floatAttr(attrs, ...keys) {
|
|
53
|
+
for (const key of keys) {
|
|
54
|
+
const v = attrs[key];
|
|
55
|
+
if (typeof v === "number") return v;
|
|
56
|
+
}
|
|
57
|
+
return void 0;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
//#endregion
|
|
61
|
+
//#region src/mappers/ai-sdk.ts
|
|
31
62
|
const LLM_SPAN_NAMES = new Set([
|
|
32
63
|
"ai.generateText",
|
|
33
64
|
"ai.generateText.doGenerate",
|
|
@@ -42,18 +73,15 @@ const TOOL_SPAN_NAMES = new Set([
|
|
|
42
73
|
"ai.toolExecution",
|
|
43
74
|
"ai.executeToolCall"
|
|
44
75
|
]);
|
|
45
|
-
const
|
|
46
|
-
"
|
|
47
|
-
"
|
|
48
|
-
"breadcrumb.output",
|
|
49
|
-
"breadcrumb.model",
|
|
50
|
-
"breadcrumb.provider",
|
|
51
|
-
"breadcrumb.input_tokens",
|
|
52
|
-
"breadcrumb.output_tokens",
|
|
53
|
-
"breadcrumb.input_cost_usd",
|
|
54
|
-
"breadcrumb.output_cost_usd",
|
|
76
|
+
const HANDLED = new Set([
|
|
77
|
+
"resource.name",
|
|
78
|
+
"ai.prompt",
|
|
55
79
|
"ai.prompt.messages",
|
|
56
80
|
"ai.response.text",
|
|
81
|
+
"ai.response.toolCalls",
|
|
82
|
+
"ai.toolCall.name",
|
|
83
|
+
"ai.toolCall.args",
|
|
84
|
+
"ai.toolCall.result",
|
|
57
85
|
"ai.model.id",
|
|
58
86
|
"ai.model.provider",
|
|
59
87
|
"ai.response.model",
|
|
@@ -68,61 +96,25 @@ const HANDLED_ATTRS = new Set([
|
|
|
68
96
|
"ai.response.providerMetadata",
|
|
69
97
|
"ai.response.finishReason"
|
|
70
98
|
]);
|
|
71
|
-
const
|
|
99
|
+
const DROP = new Set([
|
|
72
100
|
"operation.name",
|
|
73
|
-
"resource.name",
|
|
74
101
|
"ai.operationId",
|
|
75
102
|
"ai.telemetry.functionId",
|
|
76
103
|
"gen_ai.response.finish_reasons",
|
|
77
104
|
"gen_ai.response.id",
|
|
78
105
|
"gen_ai.response.model",
|
|
79
106
|
"ai.response.id",
|
|
80
|
-
"ai.response.timestamp"
|
|
107
|
+
"ai.response.timestamp",
|
|
108
|
+
"ai.prompt.tools",
|
|
109
|
+
"ai.prompt.toolChoice",
|
|
110
|
+
"ai.toolCall.id"
|
|
81
111
|
]);
|
|
82
|
-
function
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
function spanStatus(span) {
|
|
86
|
-
return span.status.code === __opentelemetry_api.SpanStatusCode.ERROR ? "error" : "ok";
|
|
87
|
-
}
|
|
88
|
-
function strAttr(span, ...keys) {
|
|
89
|
-
for (const key of keys) {
|
|
90
|
-
const v = span.attributes[key];
|
|
91
|
-
if (typeof v === "string" && v !== "") return v;
|
|
92
|
-
}
|
|
93
|
-
return void 0;
|
|
94
|
-
}
|
|
95
|
-
function intAttr(span, ...keys) {
|
|
96
|
-
for (const key of keys) {
|
|
97
|
-
const v = span.attributes[key];
|
|
98
|
-
if (typeof v === "number") return Math.round(v);
|
|
99
|
-
}
|
|
100
|
-
return void 0;
|
|
101
|
-
}
|
|
102
|
-
function floatAttr(span, ...keys) {
|
|
103
|
-
for (const key of keys) {
|
|
104
|
-
const v = span.attributes[key];
|
|
105
|
-
if (typeof v === "number") return v;
|
|
106
|
-
}
|
|
107
|
-
return void 0;
|
|
108
|
-
}
|
|
109
|
-
function tryJson(s) {
|
|
110
|
-
try {
|
|
111
|
-
return JSON.parse(s);
|
|
112
|
-
} catch {
|
|
113
|
-
return void 0;
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
function inferSpanType(span) {
|
|
117
|
-
const explicit = span.attributes["breadcrumb.span.type"];
|
|
118
|
-
if (typeof explicit === "string" && explicit !== "") return explicit;
|
|
119
|
-
if (LLM_SPAN_NAMES.has(span.name)) return "llm";
|
|
120
|
-
if (TOOL_SPAN_NAMES.has(span.name)) return "tool";
|
|
112
|
+
function inferType(spanName) {
|
|
113
|
+
if (LLM_SPAN_NAMES.has(spanName)) return "llm";
|
|
114
|
+
if (TOOL_SPAN_NAMES.has(spanName)) return "tool";
|
|
121
115
|
return "custom";
|
|
122
116
|
}
|
|
123
|
-
function extractCost(
|
|
124
|
-
const raw = span.attributes["ai.response.providerMetadata"];
|
|
125
|
-
if (typeof raw !== "string") return {};
|
|
117
|
+
function extractCost(raw) {
|
|
126
118
|
try {
|
|
127
119
|
const parsed = tryJson(raw);
|
|
128
120
|
if (!parsed || typeof parsed !== "object") return {};
|
|
@@ -143,6 +135,159 @@ function extractCost(span) {
|
|
|
143
135
|
} catch {}
|
|
144
136
|
return {};
|
|
145
137
|
}
|
|
138
|
+
function mapAiSdk(span) {
|
|
139
|
+
const attrs = span.attributes;
|
|
140
|
+
const result = {};
|
|
141
|
+
const toolCallName = strAttr(attrs, "ai.toolCall.name");
|
|
142
|
+
const resourceName = strAttr(attrs, "resource.name");
|
|
143
|
+
if (toolCallName) result.name = toolCallName;
|
|
144
|
+
else if (resourceName) result.name = resourceName;
|
|
145
|
+
result.type = inferType(span.name);
|
|
146
|
+
const toolArgs = attrs["ai.toolCall.args"];
|
|
147
|
+
const aiMessages = attrs["ai.prompt.messages"];
|
|
148
|
+
const aiPrompt = attrs["ai.prompt"];
|
|
149
|
+
if (typeof toolArgs === "string") result.input = tryJson(toolArgs) ?? toolArgs;
|
|
150
|
+
else if (typeof aiMessages === "string") result.input = tryJson(aiMessages) ?? aiMessages;
|
|
151
|
+
else if (typeof aiPrompt === "string") {
|
|
152
|
+
const parsed = tryJson(aiPrompt);
|
|
153
|
+
if (parsed && typeof parsed === "object") {
|
|
154
|
+
const messages = [];
|
|
155
|
+
if (parsed["system"]) messages.push({
|
|
156
|
+
role: "system",
|
|
157
|
+
content: parsed["system"]
|
|
158
|
+
});
|
|
159
|
+
if (Array.isArray(parsed["messages"])) messages.push(...parsed["messages"]);
|
|
160
|
+
else if (parsed["prompt"] !== void 0) messages.push({
|
|
161
|
+
role: "user",
|
|
162
|
+
content: parsed["prompt"]
|
|
163
|
+
});
|
|
164
|
+
result.input = messages.length > 0 ? messages : parsed;
|
|
165
|
+
} else result.input = aiPrompt;
|
|
166
|
+
}
|
|
167
|
+
const toolResult = attrs["ai.toolCall.result"];
|
|
168
|
+
const aiText = attrs["ai.response.text"];
|
|
169
|
+
const aiToolCalls = attrs["ai.response.toolCalls"];
|
|
170
|
+
if (typeof toolResult === "string") result.output = tryJson(toolResult) ?? toolResult;
|
|
171
|
+
else if (typeof aiText === "string") result.output = aiText;
|
|
172
|
+
else if (typeof aiToolCalls === "string") {
|
|
173
|
+
const parsed = tryJson(aiToolCalls);
|
|
174
|
+
if (Array.isArray(parsed)) result.output = parsed.map((tc) => ({
|
|
175
|
+
...tc,
|
|
176
|
+
input: typeof tc["input"] === "string" ? tryJson(tc["input"]) ?? tc["input"] : tc["input"]
|
|
177
|
+
}));
|
|
178
|
+
else result.output = parsed ?? aiToolCalls;
|
|
179
|
+
}
|
|
180
|
+
const model = strAttr(attrs, "ai.model.id", "ai.response.model", "gen_ai.request.model");
|
|
181
|
+
if (model) result.model = model;
|
|
182
|
+
const provider = strAttr(attrs, "ai.model.provider", "gen_ai.system");
|
|
183
|
+
if (provider) result.provider = provider;
|
|
184
|
+
const input_tokens = intAttr(attrs, "ai.usage.inputTokens", "ai.usage.promptTokens", "gen_ai.usage.input_tokens");
|
|
185
|
+
if (input_tokens != null) result.input_tokens = input_tokens;
|
|
186
|
+
const output_tokens = intAttr(attrs, "ai.usage.outputTokens", "ai.usage.completionTokens", "gen_ai.usage.output_tokens");
|
|
187
|
+
if (output_tokens != null) result.output_tokens = output_tokens;
|
|
188
|
+
const providerMeta = attrs["ai.response.providerMetadata"];
|
|
189
|
+
if (typeof providerMeta === "string") {
|
|
190
|
+
const cost = extractCost(providerMeta);
|
|
191
|
+
if (cost.input_cost_usd != null) result.input_cost_usd = cost.input_cost_usd;
|
|
192
|
+
if (cost.output_cost_usd != null) result.output_cost_usd = cost.output_cost_usd;
|
|
193
|
+
}
|
|
194
|
+
const metadata = {};
|
|
195
|
+
const finishReason = attrs["ai.response.finishReason"];
|
|
196
|
+
if (typeof finishReason === "string" && finishReason !== "") metadata["finish_reason"] = finishReason;
|
|
197
|
+
for (const [k, v] of Object.entries(attrs)) {
|
|
198
|
+
if (v == null) continue;
|
|
199
|
+
if (HANDLED.has(k) || DROP.has(k)) continue;
|
|
200
|
+
if (k.startsWith("ai.settings.") || k.startsWith("ai.request.headers.")) continue;
|
|
201
|
+
if (k.startsWith("ai.telemetry.metadata.")) {
|
|
202
|
+
metadata[k.slice(22)] = String(v);
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
if (k.startsWith("ai.") || k.startsWith("gen_ai.")) metadata[k] = String(v);
|
|
206
|
+
}
|
|
207
|
+
if (Object.keys(metadata).length > 0) result.metadata = metadata;
|
|
208
|
+
return result;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
//#endregion
|
|
212
|
+
//#region src/mappers/breadcrumb.ts
|
|
213
|
+
const VALID_TYPES = new Set([
|
|
214
|
+
"llm",
|
|
215
|
+
"tool",
|
|
216
|
+
"retrieval",
|
|
217
|
+
"step",
|
|
218
|
+
"custom"
|
|
219
|
+
]);
|
|
220
|
+
function mapBreadcrumb(span) {
|
|
221
|
+
const attrs = span.attributes;
|
|
222
|
+
const result = {};
|
|
223
|
+
const explicitType = attrs["breadcrumb.span.type"];
|
|
224
|
+
if (typeof explicitType === "string" && VALID_TYPES.has(explicitType)) result.type = explicitType;
|
|
225
|
+
const rawInput = attrs["breadcrumb.input"];
|
|
226
|
+
if (rawInput != null) result.input = typeof rawInput === "string" ? tryJson(rawInput) ?? rawInput : rawInput;
|
|
227
|
+
const rawOutput = attrs["breadcrumb.output"];
|
|
228
|
+
if (rawOutput != null) result.output = typeof rawOutput === "string" ? tryJson(rawOutput) ?? rawOutput : rawOutput;
|
|
229
|
+
const model = strAttr(attrs, "breadcrumb.model");
|
|
230
|
+
if (model) result.model = model;
|
|
231
|
+
const provider = strAttr(attrs, "breadcrumb.provider");
|
|
232
|
+
if (provider) result.provider = provider;
|
|
233
|
+
const input_tokens = intAttr(attrs, "breadcrumb.input_tokens");
|
|
234
|
+
if (input_tokens != null) result.input_tokens = input_tokens;
|
|
235
|
+
const output_tokens = intAttr(attrs, "breadcrumb.output_tokens");
|
|
236
|
+
if (output_tokens != null) result.output_tokens = output_tokens;
|
|
237
|
+
const input_cost_usd = floatAttr(attrs, "breadcrumb.input_cost_usd");
|
|
238
|
+
if (input_cost_usd != null) result.input_cost_usd = input_cost_usd;
|
|
239
|
+
const output_cost_usd = floatAttr(attrs, "breadcrumb.output_cost_usd");
|
|
240
|
+
if (output_cost_usd != null) result.output_cost_usd = output_cost_usd;
|
|
241
|
+
const metadata = {};
|
|
242
|
+
for (const [k, v] of Object.entries(attrs)) {
|
|
243
|
+
if (v == null) continue;
|
|
244
|
+
if (k.startsWith("breadcrumb.meta.")) metadata[k.slice(16)] = String(v);
|
|
245
|
+
}
|
|
246
|
+
if (Object.keys(metadata).length > 0) result.metadata = metadata;
|
|
247
|
+
return result;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
//#endregion
|
|
251
|
+
//#region src/exporter.ts
|
|
252
|
+
const MAPPER_NAMESPACES = [
|
|
253
|
+
"ai.",
|
|
254
|
+
"gen_ai.",
|
|
255
|
+
"breadcrumb.",
|
|
256
|
+
"resource.name"
|
|
257
|
+
];
|
|
258
|
+
const GLOBAL_DROP = new Set(["operation.name"]);
|
|
259
|
+
function hrTimeToISO(hrTime) {
|
|
260
|
+
return new Date(hrTime[0] * 1e3 + hrTime[1] / 1e6).toISOString();
|
|
261
|
+
}
|
|
262
|
+
function spanStatus(span) {
|
|
263
|
+
return span.status.code === __opentelemetry_api.SpanStatusCode.ERROR ? "error" : "ok";
|
|
264
|
+
}
|
|
265
|
+
function mergeMappers(span) {
|
|
266
|
+
const aiSdk = mapAiSdk(span);
|
|
267
|
+
const bc = mapBreadcrumb(span);
|
|
268
|
+
return {
|
|
269
|
+
...aiSdk,
|
|
270
|
+
...bc,
|
|
271
|
+
metadata: aiSdk.metadata || bc.metadata ? {
|
|
272
|
+
...aiSdk.metadata,
|
|
273
|
+
...bc.metadata
|
|
274
|
+
} : void 0
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
function passthroughMetadata(span, existing) {
|
|
278
|
+
const extra = {};
|
|
279
|
+
for (const [k, v] of Object.entries(span.attributes)) {
|
|
280
|
+
if (v == null) continue;
|
|
281
|
+
const handled = MAPPER_NAMESPACES.some((ns) => k === ns || k.startsWith(ns));
|
|
282
|
+
if (handled || GLOBAL_DROP.has(k)) continue;
|
|
283
|
+
extra[k] = String(v);
|
|
284
|
+
}
|
|
285
|
+
if (Object.keys(extra).length === 0) return existing || void 0;
|
|
286
|
+
return {
|
|
287
|
+
...extra,
|
|
288
|
+
...existing
|
|
289
|
+
};
|
|
290
|
+
}
|
|
146
291
|
var BreadcrumbSpanExporter = class {
|
|
147
292
|
constructor(apiKey, baseUrl) {
|
|
148
293
|
this.apiKey = apiKey;
|
|
@@ -162,74 +307,35 @@ var BreadcrumbSpanExporter = class {
|
|
|
162
307
|
}
|
|
163
308
|
_mapSpan(span) {
|
|
164
309
|
const ctx = span.spanContext();
|
|
165
|
-
const
|
|
166
|
-
|
|
167
|
-
const bcInput = attrs["breadcrumb.input"];
|
|
168
|
-
const aiMessages = attrs["ai.prompt.messages"];
|
|
169
|
-
if (bcInput != null) input = typeof bcInput === "string" ? tryJson(bcInput) ?? bcInput : bcInput;
|
|
170
|
-
else if (typeof aiMessages === "string") input = tryJson(aiMessages) ?? aiMessages;
|
|
171
|
-
let output;
|
|
172
|
-
const bcOutput = attrs["breadcrumb.output"];
|
|
173
|
-
const aiText = attrs["ai.response.text"];
|
|
174
|
-
if (bcOutput != null) output = typeof bcOutput === "string" ? tryJson(bcOutput) ?? bcOutput : bcOutput;
|
|
175
|
-
else if (typeof aiText === "string") output = aiText;
|
|
176
|
-
const model = strAttr(span, "breadcrumb.model", "ai.model.id", "ai.response.model", "gen_ai.request.model");
|
|
177
|
-
const provider = strAttr(span, "breadcrumb.provider", "ai.model.provider", "gen_ai.system");
|
|
178
|
-
const input_tokens = intAttr(span, "breadcrumb.input_tokens", "ai.usage.inputTokens", "ai.usage.promptTokens", "gen_ai.usage.input_tokens");
|
|
179
|
-
const output_tokens = intAttr(span, "breadcrumb.output_tokens", "ai.usage.outputTokens", "ai.usage.completionTokens", "gen_ai.usage.output_tokens");
|
|
180
|
-
let input_cost_usd = floatAttr(span, "breadcrumb.input_cost_usd");
|
|
181
|
-
let output_cost_usd = floatAttr(span, "breadcrumb.output_cost_usd");
|
|
182
|
-
if (input_cost_usd == null && output_cost_usd == null) {
|
|
183
|
-
const cost = extractCost(span);
|
|
184
|
-
input_cost_usd = cost.input_cost_usd;
|
|
185
|
-
output_cost_usd = cost.output_cost_usd;
|
|
186
|
-
}
|
|
187
|
-
const metadata = {};
|
|
188
|
-
for (const [k, v] of Object.entries(attrs)) {
|
|
189
|
-
if (v == null) continue;
|
|
190
|
-
if (HANDLED_ATTRS.has(k) || DROP_ATTRS.has(k)) continue;
|
|
191
|
-
if (k.startsWith("ai.settings.")) continue;
|
|
192
|
-
if (k.startsWith("ai.request.headers.")) continue;
|
|
193
|
-
if (k.startsWith("breadcrumb.")) {
|
|
194
|
-
if (k.startsWith("breadcrumb.meta.")) metadata[k.slice(16)] = String(v);
|
|
195
|
-
continue;
|
|
196
|
-
}
|
|
197
|
-
if (k.startsWith("ai.telemetry.metadata.")) {
|
|
198
|
-
metadata[k.slice(22)] = String(v);
|
|
199
|
-
continue;
|
|
200
|
-
}
|
|
201
|
-
if (k === "ai.response.finishReason") {
|
|
202
|
-
metadata["finish_reason"] = String(v);
|
|
203
|
-
continue;
|
|
204
|
-
}
|
|
205
|
-
metadata[k] = String(v);
|
|
206
|
-
}
|
|
310
|
+
const mapped = mergeMappers(span);
|
|
311
|
+
const metadata = passthroughMetadata(span, mapped.metadata);
|
|
207
312
|
return {
|
|
208
313
|
id: ctx.spanId,
|
|
209
314
|
trace_id: ctx.traceId,
|
|
210
315
|
parent_span_id: span.parentSpanId || void 0,
|
|
211
|
-
name: span.name,
|
|
212
|
-
type:
|
|
316
|
+
name: mapped.name ?? span.name,
|
|
317
|
+
type: mapped.type ?? "custom",
|
|
213
318
|
start_time: hrTimeToISO(span.startTime),
|
|
214
319
|
end_time: hrTimeToISO(span.endTime),
|
|
215
320
|
status: spanStatus(span),
|
|
216
321
|
status_message: span.status.message || void 0,
|
|
217
|
-
input: input !== void 0 ? input : void 0,
|
|
218
|
-
output: output !== void 0 ? output : void 0,
|
|
219
|
-
provider,
|
|
220
|
-
model,
|
|
221
|
-
input_tokens,
|
|
222
|
-
output_tokens,
|
|
223
|
-
input_cost_usd,
|
|
224
|
-
output_cost_usd,
|
|
225
|
-
metadata: Object.keys(metadata).length > 0 ? metadata : void 0
|
|
322
|
+
input: mapped.input !== void 0 ? mapped.input : void 0,
|
|
323
|
+
output: mapped.output !== void 0 ? mapped.output : void 0,
|
|
324
|
+
provider: mapped.provider,
|
|
325
|
+
model: mapped.model,
|
|
326
|
+
input_tokens: mapped.input_tokens,
|
|
327
|
+
output_tokens: mapped.output_tokens,
|
|
328
|
+
input_cost_usd: mapped.input_cost_usd,
|
|
329
|
+
output_cost_usd: mapped.output_cost_usd,
|
|
330
|
+
metadata: metadata && Object.keys(metadata).length > 0 ? metadata : void 0
|
|
226
331
|
};
|
|
227
332
|
}
|
|
228
333
|
async _sendTrace(span) {
|
|
229
334
|
const ctx = span.spanContext();
|
|
335
|
+
const mapped = mergeMappers(span);
|
|
230
336
|
await this._post("/v1/traces", {
|
|
231
337
|
id: ctx.traceId,
|
|
232
|
-
name: span.name,
|
|
338
|
+
name: mapped.name ?? span.name,
|
|
233
339
|
start_time: hrTimeToISO(span.startTime),
|
|
234
340
|
end_time: hrTimeToISO(span.endTime),
|
|
235
341
|
status: spanStatus(span),
|
package/dist/index.d.cts
CHANGED
|
@@ -1,7 +1,25 @@
|
|
|
1
1
|
//#region src/types.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* A single message in a conversation. Pass an array of these as `input` to
|
|
4
|
+
* display the conversation in the Breadcrumb UI the same way LLM spans appear.
|
|
5
|
+
*/
|
|
6
|
+
interface Message {
|
|
7
|
+
role: "system" | "user" | "assistant" | "tool";
|
|
8
|
+
content: string;
|
|
9
|
+
}
|
|
2
10
|
interface SpanData {
|
|
3
|
-
|
|
4
|
-
|
|
11
|
+
/**
|
|
12
|
+
* The input to this step. Use a plain string for simple inputs, or a
|
|
13
|
+
* `Message[]` array for conversation-style inputs — the UI renders both
|
|
14
|
+
* with role labels (system / user / assistant).
|
|
15
|
+
* Any other JSON-serializable value is also accepted and shown as raw data.
|
|
16
|
+
*/
|
|
17
|
+
input?: string | Message[] | Record<string, unknown>;
|
|
18
|
+
/**
|
|
19
|
+
* The output from this step. Use a plain string for text outputs.
|
|
20
|
+
* Any JSON-serializable value is accepted.
|
|
21
|
+
*/
|
|
22
|
+
output?: string | Record<string, unknown>;
|
|
5
23
|
model?: string;
|
|
6
24
|
provider?: string;
|
|
7
25
|
input_tokens?: number;
|
|
@@ -21,6 +39,7 @@ interface Breadcrumb {
|
|
|
21
39
|
span<T>(name: string, fn: (span: BreadcrumbSpan) => Promise<T>, options?: SpanOptions): Promise<T>;
|
|
22
40
|
} //#endregion
|
|
23
41
|
//#region src/index.d.ts
|
|
42
|
+
|
|
24
43
|
//# sourceMappingURL=types.d.ts.map
|
|
25
44
|
interface InitOptions {
|
|
26
45
|
apiKey: string;
|
|
@@ -35,5 +54,5 @@ declare function init(options: InitOptions): Breadcrumb;
|
|
|
35
54
|
//#endregion
|
|
36
55
|
//# sourceMappingURL=index.d.ts.map
|
|
37
56
|
|
|
38
|
-
export { Breadcrumb, BreadcrumbSpan, InitOptions, SpanOptions, init };
|
|
57
|
+
export { Breadcrumb, BreadcrumbSpan, InitOptions, Message, SpanData, SpanOptions, init };
|
|
39
58
|
//# sourceMappingURL=index.d.cts.map
|
package/dist/index.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/types.ts","../src/index.ts"],"sourcesContent":null,"mappings":";
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/types.ts","../src/index.ts"],"sourcesContent":null,"mappings":";;;;;UAIiB,OAAA;EAAA,IAAA,EAAA,QAAO,GAAA,MAAA,GAAA,WAAA,GAAA,MAAA;EAKP,OAAA,EAAA,MAAQ;;AAON,UAPF,QAAA,CAOE;EAAO;;;AAYP;AAGnB;AAIA;EAIiB,KAAA,CAAA,EAAA,MAAU,GAvBR,OAuBQ,EAAA,GAvBI,MAuBJ,CAAA,MAAA,EAAA,OAAA,CAAA;EAAA;;;;EACmC,MAAc,CAAA,EAAA,MAAA,GAnBxD,MAmBwD,CAAA,MAAA,EAAA,OAAA,CAAA;EAAC,KAAT,CAAA,EAAA,MAAA;EAAO,QAG5D,CAAA,EAAA,MAAA;EAAc,YAAa,CAAA,EAAA,MAAA;EAAC,aAAT,CAAA,EAAA,MAAA;EAAO,cAC3B,CAAA,EAAA,MAAA;EAAW,eACZ,CAAA,EAAA,MAAA;EAAC,QAAT,CAAA,EAjBQ,MAiBR,CAAA,MAAA,EAAA,MAAA,GAAA,MAAA,GAAA,OAAA,CAAA;AAAO;UAdK,cAAA;YACL;;ACfK,UDkBA,WAAA,CClBW;EAWZ,IAAA,CAAA,EAAI,KAAA,GAAA,MAAA,GAAA,WAAA,GAAA,MAAA;;AAAU,UDWb,UAAA,CCXa;EAAW,KAAG,CAAA,CAAA,CAAA,CAAA,IAAA,EAAA,MAAA,EAAA,EAAA,EAAA,CAAA,IAAA,EDYR,cCZQ,EAAA,GDYW,OCZX,CDYmB,CCZnB,CAAA,CAAA,EDYwB,OCZxB,CDYgC,CCZhC,CAAA;EAAU,IAAA,CAAA,CAAA,CAAA,CAAA,IAAA,EAAA,MAAA,EAAA,EAAA,EAAA,CAAA,IAAA,EDevC,cCfuC,EAAA,GDepB,OCfoB,CDeZ,CCfY,CAAA,EAAA,OAAA,CAAA,EDgBxC,WChBwC,CAAA,EDiBjD,OCjBiD,CDiBzC,CCjByC,CAAA;;;;;UAXrC,WAAA;;;EDbA,QAAA,CAAA,EAAO,KAAA,GAAA;IAKP,aAAQ,CAAA,EAAA,MAAA;IAAA,YAAA,CAAA,EAAA,MAAA;EAAA,CAAA;;AAYL,iBCOJ,IAAA,CDPI,OAAA,ECOU,WDPV,CAAA,ECOwB,UDPxB"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,25 @@
|
|
|
1
1
|
//#region src/types.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* A single message in a conversation. Pass an array of these as `input` to
|
|
4
|
+
* display the conversation in the Breadcrumb UI the same way LLM spans appear.
|
|
5
|
+
*/
|
|
6
|
+
interface Message {
|
|
7
|
+
role: "system" | "user" | "assistant" | "tool";
|
|
8
|
+
content: string;
|
|
9
|
+
}
|
|
2
10
|
interface SpanData {
|
|
3
|
-
|
|
4
|
-
|
|
11
|
+
/**
|
|
12
|
+
* The input to this step. Use a plain string for simple inputs, or a
|
|
13
|
+
* `Message[]` array for conversation-style inputs — the UI renders both
|
|
14
|
+
* with role labels (system / user / assistant).
|
|
15
|
+
* Any other JSON-serializable value is also accepted and shown as raw data.
|
|
16
|
+
*/
|
|
17
|
+
input?: string | Message[] | Record<string, unknown>;
|
|
18
|
+
/**
|
|
19
|
+
* The output from this step. Use a plain string for text outputs.
|
|
20
|
+
* Any JSON-serializable value is accepted.
|
|
21
|
+
*/
|
|
22
|
+
output?: string | Record<string, unknown>;
|
|
5
23
|
model?: string;
|
|
6
24
|
provider?: string;
|
|
7
25
|
input_tokens?: number;
|
|
@@ -21,6 +39,7 @@ interface Breadcrumb {
|
|
|
21
39
|
span<T>(name: string, fn: (span: BreadcrumbSpan) => Promise<T>, options?: SpanOptions): Promise<T>;
|
|
22
40
|
} //#endregion
|
|
23
41
|
//#region src/index.d.ts
|
|
42
|
+
|
|
24
43
|
//# sourceMappingURL=types.d.ts.map
|
|
25
44
|
interface InitOptions {
|
|
26
45
|
apiKey: string;
|
|
@@ -35,5 +54,5 @@ declare function init(options: InitOptions): Breadcrumb;
|
|
|
35
54
|
//#endregion
|
|
36
55
|
//# sourceMappingURL=index.d.ts.map
|
|
37
56
|
|
|
38
|
-
export { Breadcrumb, BreadcrumbSpan, InitOptions, SpanOptions, init };
|
|
57
|
+
export { Breadcrumb, BreadcrumbSpan, InitOptions, Message, SpanData, SpanOptions, init };
|
|
39
58
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/types.ts","../src/index.ts"],"sourcesContent":null,"mappings":";
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/types.ts","../src/index.ts"],"sourcesContent":null,"mappings":";;;;;UAIiB,OAAA;EAAA,IAAA,EAAA,QAAO,GAAA,MAAA,GAAA,WAAA,GAAA,MAAA;EAKP,OAAA,EAAA,MAAQ;;AAON,UAPF,QAAA,CAOE;EAAO;;;AAYP;AAGnB;AAIA;EAIiB,KAAA,CAAA,EAAA,MAAU,GAvBR,OAuBQ,EAAA,GAvBI,MAuBJ,CAAA,MAAA,EAAA,OAAA,CAAA;EAAA;;;;EACmC,MAAc,CAAA,EAAA,MAAA,GAnBxD,MAmBwD,CAAA,MAAA,EAAA,OAAA,CAAA;EAAC,KAAT,CAAA,EAAA,MAAA;EAAO,QAG5D,CAAA,EAAA,MAAA;EAAc,YAAa,CAAA,EAAA,MAAA;EAAC,aAAT,CAAA,EAAA,MAAA;EAAO,cAC3B,CAAA,EAAA,MAAA;EAAW,eACZ,CAAA,EAAA,MAAA;EAAC,QAAT,CAAA,EAjBQ,MAiBR,CAAA,MAAA,EAAA,MAAA,GAAA,MAAA,GAAA,OAAA,CAAA;AAAO;UAdK,cAAA;YACL;;ACfK,UDkBA,WAAA,CClBW;EAWZ,IAAA,CAAA,EAAI,KAAA,GAAA,MAAA,GAAA,WAAA,GAAA,MAAA;;AAAU,UDWb,UAAA,CCXa;EAAW,KAAG,CAAA,CAAA,CAAA,CAAA,IAAA,EAAA,MAAA,EAAA,EAAA,EAAA,CAAA,IAAA,EDYR,cCZQ,EAAA,GDYW,OCZX,CDYmB,CCZnB,CAAA,CAAA,EDYwB,OCZxB,CDYgC,CCZhC,CAAA;EAAU,IAAA,CAAA,CAAA,CAAA,CAAA,IAAA,EAAA,MAAA,EAAA,EAAA,EAAA,CAAA,IAAA,EDevC,cCfuC,EAAA,GDepB,OCfoB,CDeZ,CCfY,CAAA,EAAA,OAAA,CAAA,EDgBxC,WChBwC,CAAA,EDiBjD,OCjBiD,CDiBzC,CCjByC,CAAA;;;;;UAXrC,WAAA;;;EDbA,QAAA,CAAA,EAAO,KAAA,GAAA;IAKP,aAAQ,CAAA,EAAA,MAAA;IAAA,YAAA,CAAA,EAAA,MAAA;EAAA,CAAA;;AAYL,iBCOJ,IAAA,CDPI,OAAA,ECOU,WDPV,CAAA,ECOwB,UDPxB"}
|