@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/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` | `unknown` | Input passed to this step |
136
- | `output` | `unknown` | Output produced by this step |
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/exporter.ts
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 HANDLED_ATTRS = new Set([
46
- "breadcrumb.span.type",
47
- "breadcrumb.input",
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 DROP_ATTRS = new Set([
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 hrTimeToISO(hrTime) {
83
- return new Date(hrTime[0] * 1e3 + hrTime[1] / 1e6).toISOString();
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(span) {
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 attrs = span.attributes;
166
- let input;
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: inferSpanType(span),
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
- input?: unknown;
4
- output?: unknown;
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
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../src/types.ts","../src/index.ts"],"sourcesContent":null,"mappings":";UAAiB,QAAA;EAAA,KAAA,CAAA,EAAA,OAAQ;EAYR,MAAA,CAAA,EAAA,OAAA;EAIA,KAAA,CAAA,EAAA,MAAW;EAIX,QAAA,CAAA,EAAA,MAAU;EAAA,YAAA,CAAA,EAAA,MAAA;EAAA,aACS,CAAA,EAAA,MAAA;EAAc,cAAa,CAAA,EAAA,MAAA;EAAC,eAAT,CAAA,EAAA,MAAA;EAAO,QAAc,CAAA,EAZ/D,MAY+D,CAAA,MAAA,EAAA,MAAA,GAAA,MAAA,GAAA,OAAA,CAAA;;AAG7D,UAZE,cAAA,CAYF;EAAc,GAAa,CAAA,IAAA,EAX9B,QAW8B,CAAA,EAAA,IAAA;;AAC5B,UATG,WAAA,CASH;EAAW,IACZ,CAAA,EAAA,KAAA,GAAA,MAAA,GAAA,WAAA,GAAA,MAAA;;AAAD,UANK,UAAA,CAML;oCALwB,mBAAmB,QAAQ,KAAK,QAAQ;mCAG7D,mBAAmB,QAAQ,cAC5B,cACT,QAAQ;;;ACTb;ADLiB,UCKA,WAAA,CDLc;EAId,MAAA,EAAA,MAAW;EAIX,OAAA,EAAA,MAAU;EAAA,QAAA,CAAA,EAAA,KAAA,GAAA;IACS,aAAA,CAAA,EAAA,MAAA;IAA2B,YAAA,CAAA,EAAA,MAAA;EAAC,CAAA;;AAAI,iBCOpD,IAAA,CDPoD,OAAA,ECOtC,WDPsC,CAAA,ECOxB,UDPwB"}
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
- input?: unknown;
4
- output?: unknown;
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
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","names":[],"sources":["../src/types.ts","../src/index.ts"],"sourcesContent":null,"mappings":";UAAiB,QAAA;EAAA,KAAA,CAAA,EAAA,OAAQ;EAYR,MAAA,CAAA,EAAA,OAAA;EAIA,KAAA,CAAA,EAAA,MAAW;EAIX,QAAA,CAAA,EAAA,MAAU;EAAA,YAAA,CAAA,EAAA,MAAA;EAAA,aACS,CAAA,EAAA,MAAA;EAAc,cAAa,CAAA,EAAA,MAAA;EAAC,eAAT,CAAA,EAAA,MAAA;EAAO,QAAc,CAAA,EAZ/D,MAY+D,CAAA,MAAA,EAAA,MAAA,GAAA,MAAA,GAAA,OAAA,CAAA;;AAG7D,UAZE,cAAA,CAYF;EAAc,GAAa,CAAA,IAAA,EAX9B,QAW8B,CAAA,EAAA,IAAA;;AAC5B,UATG,WAAA,CASH;EAAW,IACZ,CAAA,EAAA,KAAA,GAAA,MAAA,GAAA,WAAA,GAAA,MAAA;;AAAD,UANK,UAAA,CAML;oCALwB,mBAAmB,QAAQ,KAAK,QAAQ;mCAG7D,mBAAmB,QAAQ,cAC5B,cACT,QAAQ;;;ACTb;ADLiB,UCKA,WAAA,CDLc;EAId,MAAA,EAAA,MAAW;EAIX,OAAA,EAAA,MAAU;EAAA,QAAA,CAAA,EAAA,KAAA,GAAA;IACS,aAAA,CAAA,EAAA,MAAA;IAA2B,YAAA,CAAA,EAAA,MAAA;EAAC,CAAA;;AAAI,iBCOpD,IAAA,CDPoD,OAAA,ECOtC,WDPsC,CAAA,ECOxB,UDPwB"}
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"}