@respan/cli 0.7.0 → 0.7.2

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.
@@ -258,6 +258,7 @@ function stringToSpanId(s) {
258
258
  function toOtlpPayload(spans) {
259
259
  const otlpSpans = spans.map((span) => {
260
260
  const attrs = {};
261
+ if (span.session_identifier) attrs["respan.sessions.session_identifier"] = span.session_identifier;
261
262
  if (span.thread_identifier) attrs["respan.threads.thread_identifier"] = span.thread_identifier;
262
263
  if (span.customer_identifier) attrs["respan.customer_params.customer_identifier"] = span.customer_identifier;
263
264
  if (span.span_workflow_name) attrs["traceloop.workflow.name"] = span.span_workflow_name;
@@ -318,7 +319,7 @@ function toOtlpPayload(spans) {
318
319
  })
319
320
  },
320
321
  scopeSpans: [{
321
- scope: { name: "respan-cli-hooks", version: "0.7.0" },
322
+ scope: { name: "respan-cli-hooks", version: "0.7.1" },
322
323
  spans: otlpSpans
323
324
  }]
324
325
  }]
@@ -438,6 +439,34 @@ function detectModel(hookData) {
438
439
  const llmReq = hookData.llm_request ?? {};
439
440
  return String(llmReq.model ?? "") || "gemini-cli";
440
441
  }
442
+ function buildToolSpan(detail, idx, traceUniqueId, rootSpanId, safeId, turnTs, workflowName, beginTime, endTime) {
443
+ const toolName = detail?.name ?? "";
444
+ const toolArgs = detail?.args ?? detail?.input ?? {};
445
+ const toolOutput = detail?.output ?? "";
446
+ const displayName = toolName ? toolDisplayName(toolName) : `Call ${idx + 1}`;
447
+ const toolInputStr = toolName ? formatToolInput(toolName, toolArgs) : "";
448
+ const toolMeta = {};
449
+ if (toolName) toolMeta.tool_name = toolName;
450
+ if (detail?.error) toolMeta.error = detail.error;
451
+ const toolStart = detail?.start_time ?? beginTime;
452
+ const toolEnd = detail?.end_time ?? endTime;
453
+ const toolLat = latencySeconds(toolStart, toolEnd);
454
+ return {
455
+ trace_unique_id: traceUniqueId,
456
+ span_unique_id: `gcli_${safeId}_${turnTs}_tool_${idx + 1}`,
457
+ span_parent_id: rootSpanId,
458
+ span_name: `Tool: ${displayName}`,
459
+ span_workflow_name: workflowName,
460
+ span_path: toolName ? `tool_${toolName}` : "tool_call",
461
+ provider_id: "",
462
+ metadata: toolMeta,
463
+ input: toolInputStr,
464
+ output: truncate(toolOutput, MAX_CHARS),
465
+ timestamp: toolEnd,
466
+ start_time: toolStart,
467
+ ...toolLat !== void 0 ? { latency: toolLat } : {}
468
+ };
469
+ }
441
470
  function buildSpans(hookData, outputText, tokens, config, startTimeIso, toolTurns, toolDetails, thoughtsTokens, textRounds, roundStartTimes) {
442
471
  const spans = [];
443
472
  const sessionId = String(hookData.session_id ?? "");
@@ -464,6 +493,7 @@ function buildSpans(hookData, outputText, tokens, config, startTimeIso, toolTurn
464
493
  const metadata = buildMetadata(config, baseMeta);
465
494
  spans.push({
466
495
  trace_unique_id: traceUniqueId,
496
+ session_identifier: threadId,
467
497
  thread_identifier: threadId,
468
498
  customer_identifier: customerId,
469
499
  span_unique_id: rootSpanId,
@@ -519,33 +549,7 @@ function buildSpans(hookData, outputText, tokens, config, startTimeIso, toolTurn
519
549
  }
520
550
  if (r < rounds.length - 1) {
521
551
  while (toolIdx < toolDetails.length) {
522
- const detail = toolDetails[toolIdx];
523
- const toolName = detail?.name ?? "";
524
- const toolArgs = detail?.args ?? detail?.input ?? {};
525
- const toolOutput = detail?.output ?? "";
526
- const displayName = toolName ? toolDisplayName(toolName) : `Call ${toolIdx + 1}`;
527
- const toolInputStr = toolName ? formatToolInput(toolName, toolArgs) : "";
528
- const toolMeta = {};
529
- if (toolName) toolMeta.tool_name = toolName;
530
- if (detail?.error) toolMeta.error = detail.error;
531
- const toolStart = detail?.start_time ?? beginTime;
532
- const toolEnd = detail?.end_time ?? endTime;
533
- const toolLat = latencySeconds(toolStart, toolEnd);
534
- spans.push({
535
- trace_unique_id: traceUniqueId,
536
- span_unique_id: `gcli_${safeId}_${turnTs}_tool_${toolIdx + 1}`,
537
- span_parent_id: rootSpanId,
538
- span_name: `Tool: ${displayName}`,
539
- span_workflow_name: workflowName,
540
- span_path: toolName ? `tool_${toolName}` : "tool_call",
541
- provider_id: "",
542
- metadata: toolMeta,
543
- input: toolInputStr,
544
- output: truncate(toolOutput, MAX_CHARS),
545
- timestamp: toolEnd,
546
- start_time: toolStart,
547
- ...toolLat !== void 0 ? { latency: toolLat } : {}
548
- });
552
+ spans.push(buildToolSpan(toolDetails[toolIdx], toolIdx, traceUniqueId, rootSpanId, safeId, turnTs, workflowName, beginTime, endTime));
549
553
  toolIdx++;
550
554
  const nextDetail = toolDetails[toolIdx];
551
555
  if (nextDetail && roundStarts[r + 1] && nextDetail.start_time && nextDetail.start_time > roundStarts[r + 1]) break;
@@ -553,33 +557,7 @@ function buildSpans(hookData, outputText, tokens, config, startTimeIso, toolTurn
553
557
  }
554
558
  }
555
559
  while (toolIdx < toolDetails.length) {
556
- const detail = toolDetails[toolIdx];
557
- const toolName = detail?.name ?? "";
558
- const toolArgs = detail?.args ?? detail?.input ?? {};
559
- const toolOutput = detail?.output ?? "";
560
- const displayName = toolName ? toolDisplayName(toolName) : `Call ${toolIdx + 1}`;
561
- const toolInputStr = toolName ? formatToolInput(toolName, toolArgs) : "";
562
- const toolMeta = {};
563
- if (toolName) toolMeta.tool_name = toolName;
564
- if (detail?.error) toolMeta.error = detail.error;
565
- const toolStart = detail?.start_time ?? beginTime;
566
- const toolEnd = detail?.end_time ?? endTime;
567
- const toolLat = latencySeconds(toolStart, toolEnd);
568
- spans.push({
569
- trace_unique_id: traceUniqueId,
570
- span_unique_id: `gcli_${safeId}_${turnTs}_tool_${toolIdx + 1}`,
571
- span_parent_id: rootSpanId,
572
- span_name: `Tool: ${displayName}`,
573
- span_workflow_name: workflowName,
574
- span_path: toolName ? `tool_${toolName}` : "tool_call",
575
- provider_id: "",
576
- metadata: toolMeta,
577
- input: toolInputStr,
578
- output: truncate(toolOutput, MAX_CHARS),
579
- timestamp: toolEnd,
580
- start_time: toolStart,
581
- ...toolLat !== void 0 ? { latency: toolLat } : {}
582
- });
560
+ spans.push(buildToolSpan(toolDetails[toolIdx], toolIdx, traceUniqueId, rootSpanId, safeId, turnTs, workflowName, beginTime, endTime));
583
561
  toolIdx++;
584
562
  }
585
563
  if (thoughtsTokens > 0) {
@@ -142,6 +142,36 @@ function detectModel(hookData) {
142
142
  return String(llmReq.model ?? '') || 'gemini-cli';
143
143
  }
144
144
  // ── Span construction ─────────────────────────────────────────────
145
+ function buildToolSpan(detail, idx, traceUniqueId, rootSpanId, safeId, turnTs, workflowName, beginTime, endTime) {
146
+ const toolName = detail?.name ?? '';
147
+ const toolArgs = detail?.args ?? detail?.input ?? {};
148
+ const toolOutput = detail?.output ?? '';
149
+ const displayName = toolName ? toolDisplayName(toolName) : `Call ${idx + 1}`;
150
+ const toolInputStr = toolName ? formatToolInput(toolName, toolArgs) : '';
151
+ const toolMeta = {};
152
+ if (toolName)
153
+ toolMeta.tool_name = toolName;
154
+ if (detail?.error)
155
+ toolMeta.error = detail.error;
156
+ const toolStart = detail?.start_time ?? beginTime;
157
+ const toolEnd = detail?.end_time ?? endTime;
158
+ const toolLat = latencySeconds(toolStart, toolEnd);
159
+ return {
160
+ trace_unique_id: traceUniqueId,
161
+ span_unique_id: `gcli_${safeId}_${turnTs}_tool_${idx + 1}`,
162
+ span_parent_id: rootSpanId,
163
+ span_name: `Tool: ${displayName}`,
164
+ span_workflow_name: workflowName,
165
+ span_path: toolName ? `tool_${toolName}` : 'tool_call',
166
+ provider_id: '',
167
+ metadata: toolMeta,
168
+ input: toolInputStr,
169
+ output: truncate(toolOutput, MAX_CHARS),
170
+ timestamp: toolEnd,
171
+ start_time: toolStart,
172
+ ...(toolLat !== undefined ? { latency: toolLat } : {}),
173
+ };
174
+ }
145
175
  function buildSpans(hookData, outputText, tokens, config, startTimeIso, toolTurns, toolDetails, thoughtsTokens, textRounds, roundStartTimes) {
146
176
  const spans = [];
147
177
  const sessionId = String(hookData.session_id ?? '');
@@ -171,6 +201,7 @@ function buildSpans(hookData, outputText, tokens, config, startTimeIso, toolTurn
171
201
  // Root span
172
202
  spans.push({
173
203
  trace_unique_id: traceUniqueId,
204
+ session_identifier: threadId,
174
205
  thread_identifier: threadId,
175
206
  customer_identifier: customerId,
176
207
  span_unique_id: rootSpanId,
@@ -233,76 +264,18 @@ function buildSpans(hookData, outputText, tokens, config, startTimeIso, toolTurn
233
264
  }
234
265
  // Tool spans that come after this round (before next round)
235
266
  if (r < rounds.length - 1) {
236
- // Emit all tools between this round and the next
237
267
  while (toolIdx < toolDetails.length) {
238
- const detail = toolDetails[toolIdx];
239
- const toolName = detail?.name ?? '';
240
- const toolArgs = detail?.args ?? detail?.input ?? {};
241
- const toolOutput = detail?.output ?? '';
242
- const displayName = toolName ? toolDisplayName(toolName) : `Call ${toolIdx + 1}`;
243
- const toolInputStr = toolName ? formatToolInput(toolName, toolArgs) : '';
244
- const toolMeta = {};
245
- if (toolName)
246
- toolMeta.tool_name = toolName;
247
- if (detail?.error)
248
- toolMeta.error = detail.error;
249
- const toolStart = detail?.start_time ?? beginTime;
250
- const toolEnd = detail?.end_time ?? endTime;
251
- const toolLat = latencySeconds(toolStart, toolEnd);
252
- spans.push({
253
- trace_unique_id: traceUniqueId,
254
- span_unique_id: `gcli_${safeId}_${turnTs}_tool_${toolIdx + 1}`,
255
- span_parent_id: rootSpanId,
256
- span_name: `Tool: ${displayName}`,
257
- span_workflow_name: workflowName,
258
- span_path: toolName ? `tool_${toolName}` : 'tool_call',
259
- provider_id: '',
260
- metadata: toolMeta,
261
- input: toolInputStr,
262
- output: truncate(toolOutput, MAX_CHARS),
263
- timestamp: toolEnd,
264
- start_time: toolStart,
265
- ...(toolLat !== undefined ? { latency: toolLat } : {}),
266
- });
268
+ spans.push(buildToolSpan(toolDetails[toolIdx], toolIdx, traceUniqueId, rootSpanId, safeId, turnTs, workflowName, beginTime, endTime));
267
269
  toolIdx++;
268
- // If next tool starts after next round's start time, break — it belongs to a later gap
269
270
  const nextDetail = toolDetails[toolIdx];
270
271
  if (nextDetail && roundStarts[r + 1] && nextDetail.start_time && nextDetail.start_time > roundStarts[r + 1])
271
272
  break;
272
273
  }
273
274
  }
274
275
  }
275
- // Any remaining tools not yet emitted (e.g. only one round but tools exist)
276
+ // Any remaining tools not yet emitted
276
277
  while (toolIdx < toolDetails.length) {
277
- const detail = toolDetails[toolIdx];
278
- const toolName = detail?.name ?? '';
279
- const toolArgs = detail?.args ?? detail?.input ?? {};
280
- const toolOutput = detail?.output ?? '';
281
- const displayName = toolName ? toolDisplayName(toolName) : `Call ${toolIdx + 1}`;
282
- const toolInputStr = toolName ? formatToolInput(toolName, toolArgs) : '';
283
- const toolMeta = {};
284
- if (toolName)
285
- toolMeta.tool_name = toolName;
286
- if (detail?.error)
287
- toolMeta.error = detail.error;
288
- const toolStart = detail?.start_time ?? beginTime;
289
- const toolEnd = detail?.end_time ?? endTime;
290
- const toolLat = latencySeconds(toolStart, toolEnd);
291
- spans.push({
292
- trace_unique_id: traceUniqueId,
293
- span_unique_id: `gcli_${safeId}_${turnTs}_tool_${toolIdx + 1}`,
294
- span_parent_id: rootSpanId,
295
- span_name: `Tool: ${displayName}`,
296
- span_workflow_name: workflowName,
297
- span_path: toolName ? `tool_${toolName}` : 'tool_call',
298
- provider_id: '',
299
- metadata: toolMeta,
300
- input: toolInputStr,
301
- output: truncate(toolOutput, MAX_CHARS),
302
- timestamp: toolEnd,
303
- start_time: toolStart,
304
- ...(toolLat !== undefined ? { latency: toolLat } : {}),
305
- });
278
+ spans.push(buildToolSpan(toolDetails[toolIdx], toolIdx, traceUniqueId, rootSpanId, safeId, turnTs, workflowName, beginTime, endTime));
306
279
  toolIdx++;
307
280
  }
308
281
  // Reasoning span
@@ -15,6 +15,7 @@ export interface SpanData {
15
15
  span_name: string;
16
16
  span_workflow_name: string;
17
17
  span_path?: string;
18
+ session_identifier?: string;
18
19
  thread_identifier?: string;
19
20
  customer_identifier?: string;
20
21
  model?: string;
@@ -315,6 +315,8 @@ export function toOtlpPayload(spans) {
315
315
  // Build OTEL-compatible attributes from SpanData fields
316
316
  const attrs = {};
317
317
  // Respan-specific attributes
318
+ if (span.session_identifier)
319
+ attrs['respan.sessions.session_identifier'] = span.session_identifier;
318
320
  if (span.thread_identifier)
319
321
  attrs['respan.threads.thread_identifier'] = span.thread_identifier;
320
322
  if (span.customer_identifier)
@@ -395,7 +397,7 @@ export function toOtlpPayload(spans) {
395
397
  }),
396
398
  },
397
399
  scopeSpans: [{
398
- scope: { name: 'respan-cli-hooks', version: '0.7.0' },
400
+ scope: { name: 'respan-cli-hooks', version: '0.7.1' },
399
401
  spans: otlpSpans,
400
402
  }],
401
403
  }],
@@ -3,6 +3,8 @@ export declare const DEFAULT_BASE_URL = "https://api.respan.ai/api";
3
3
  export declare const integrateFlags: {
4
4
  local: import("@oclif/core/interfaces").BooleanFlag<boolean>;
5
5
  global: import("@oclif/core/interfaces").BooleanFlag<boolean>;
6
+ enable: import("@oclif/core/interfaces").BooleanFlag<boolean>;
7
+ disable: import("@oclif/core/interfaces").BooleanFlag<boolean>;
6
8
  'project-id': import("@oclif/core/interfaces").OptionFlag<string | undefined, import("@oclif/core/interfaces").CustomOptions>;
7
9
  'base-url': import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
8
10
  attrs: import("@oclif/core/interfaces").OptionFlag<string, import("@oclif/core/interfaces").CustomOptions>;
@@ -19,6 +19,16 @@ export const integrateFlags = {
19
19
  default: false,
20
20
  exclusive: ['local'],
21
21
  }),
22
+ enable: Flags.boolean({
23
+ description: 'Enable tracing (default)',
24
+ default: false,
25
+ exclusive: ['disable'],
26
+ }),
27
+ disable: Flags.boolean({
28
+ description: 'Disable tracing',
29
+ default: false,
30
+ exclusive: ['enable'],
31
+ }),
22
32
  'project-id': Flags.string({
23
33
  description: 'Respan project ID (added to metadata / resource attributes)',
24
34
  env: 'RESPAN_PROJECT_ID',