@probelabs/probe 0.6.0-rc299 → 0.6.0-rc300

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.
@@ -38,6 +38,7 @@ import { existsSync } from 'fs';
38
38
  import { readFile, stat, readdir } from 'fs/promises';
39
39
  import { resolve, isAbsolute, dirname, basename, normalize, sep } from 'path';
40
40
  import { TokenCounter } from './tokenCounter.js';
41
+ import { truncateForSpan } from './simpleTelemetry.js';
41
42
  import { InMemoryStorageAdapter } from './storage/InMemoryStorageAdapter.js';
42
43
  import { HookManager, HOOK_TYPES } from './hooks/HookManager.js';
43
44
  import { SUPPORTED_IMAGE_EXTENSIONS, IMAGE_MIME_TYPES, isFormatSupportedByProvider } from './imageConfig.js';
@@ -4327,9 +4328,7 @@ Double-check your response based on the criteria above. If everything looks good
4327
4328
 
4328
4329
  let aiResult;
4329
4330
  if (this.tracer) {
4330
- const inputPreview = message.length > 1000
4331
- ? message.substring(0, 1000) + '... [truncated]'
4332
- : message;
4331
+ const inputPreview = truncateForSpan(message, 4096);
4333
4332
 
4334
4333
  aiResult = await this.tracer.withSpan('ai.request', executeAIRequest, {
4335
4334
  'ai.model': this.model,
@@ -4340,6 +4339,12 @@ Double-check your response based on the criteria above. If everything looks good
4340
4339
  'max_tokens': maxResponseTokens,
4341
4340
  'temperature': 0.3,
4342
4341
  'message_count': currentMessages.length
4342
+ }, (span, result) => {
4343
+ const text = result?.finalText || '';
4344
+ span.setAttributes({
4345
+ 'ai.output': truncateForSpan(text),
4346
+ 'ai.output_length': text.length
4347
+ });
4343
4348
  });
4344
4349
  } else {
4345
4350
  aiResult = await executeAIRequest();
@@ -2,6 +2,21 @@ import { existsSync, mkdirSync, createWriteStream } from 'fs';
2
2
  import { dirname } from 'path';
3
3
  import { patchConsole } from './otelLogBridge.js';
4
4
 
5
+ /**
6
+ * Truncate text for span attributes, preserving head and tail for context.
7
+ * For text <= maxLen, returns as-is. For longer text, shows first half and
8
+ * last half of the budget with a separator indicating omitted chars.
9
+ * @param {string} text - The text to truncate
10
+ * @param {number} [maxLen=4096] - Maximum output length
11
+ * @returns {string} The truncated text
12
+ */
13
+ export function truncateForSpan(text, maxLen = 4096) {
14
+ if (!text || text.length <= maxLen) return text || '';
15
+ const half = Math.floor((maxLen - 40) / 2); // 40 chars reserved for separator
16
+ const omitted = text.length - half * 2;
17
+ return text.substring(0, half) + `\n... [${omitted} chars omitted] ...\n` + text.substring(text.length - half);
18
+ }
19
+
5
20
  /**
6
21
  * Simple telemetry implementation for probe-agent
7
22
  * This provides basic tracing functionality without complex OpenTelemetry dependencies
@@ -463,7 +478,7 @@ export class SimpleAppTracer {
463
478
  });
464
479
  }
465
480
 
466
- async withSpan(spanName, fn, attributes = {}) {
481
+ async withSpan(spanName, fn, attributes = {}, onResult = null) {
467
482
  if (!this.isEnabled()) {
468
483
  return fn();
469
484
  }
@@ -476,12 +491,19 @@ export class SimpleAppTracer {
476
491
  try {
477
492
  const result = await fn();
478
493
  span.setStatus('OK');
494
+ if (onResult) {
495
+ try {
496
+ onResult(span, result);
497
+ } catch (_) {
498
+ // Don't let span enrichment errors break the flow
499
+ }
500
+ }
479
501
  return result;
480
502
  } catch (error) {
481
503
  span.setStatus('ERROR');
482
- span.addEvent('exception', {
504
+ span.addEvent('exception', {
483
505
  'exception.message': error.message,
484
- 'exception.stack': error.stack
506
+ 'exception.stack': error.stack
485
507
  });
486
508
  throw error;
487
509
  } finally {
@@ -13,6 +13,7 @@ import { searchSchema, querySchema, extractSchema, delegateSchema, analyzeAllSch
13
13
  import { existsSync } from 'fs';
14
14
  import { formatErrorForAI } from '../utils/error-types.js';
15
15
  import { annotateOutputWithHashes } from './hashline.js';
16
+ import { truncateForSpan } from '../agent/simpleTelemetry.js';
16
17
 
17
18
  /**
18
19
  * Auto-quote search query terms that contain mixed case or underscores.
@@ -551,6 +552,12 @@ export const searchTool = (options = {}) => {
551
552
  ? await options.tracer.withSpan('search.delegate', runDelegation, {
552
553
  'search.query': searchQuery,
553
554
  'search.path': searchPath
555
+ }, (span, result) => {
556
+ const text = typeof result === 'string' ? result : '';
557
+ span.setAttributes({
558
+ 'search.delegate.output': truncateForSpan(text),
559
+ 'search.delegate.output_length': text.length
560
+ });
554
561
  })
555
562
  : await runDelegation();
556
563