@probelabs/probe 0.6.0-rc224 → 0.6.0-rc225

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/cjs/index.cjs CHANGED
@@ -39321,11 +39321,12 @@ function createTools(configOptions) {
39321
39321
  return tools2;
39322
39322
  }
39323
39323
  function parseXmlToolCallWithThinking(xmlString, validTools) {
39324
- const { cleanedXmlString, recoveryResult } = processXmlWithThinkingAndRecovery(xmlString, validTools);
39324
+ const { cleanedXmlString, recoveryResult, thinkingContent } = processXmlWithThinkingAndRecovery(xmlString, validTools);
39325
39325
  if (recoveryResult) {
39326
- return recoveryResult;
39326
+ return { ...recoveryResult, thinkingContent };
39327
39327
  }
39328
- return parseXmlToolCall(cleanedXmlString, validTools);
39328
+ const toolCall = parseXmlToolCall(cleanedXmlString, validTools);
39329
+ return toolCall ? { ...toolCall, thinkingContent } : null;
39329
39330
  }
39330
39331
  var import_crypto2, implementToolDefinition, listFilesToolDefinition, searchFilesToolDefinition, listSkillsToolDefinition, useSkillToolDefinition, readImageToolDefinition;
39331
39332
  var init_tools = __esm({
@@ -85596,25 +85597,27 @@ function parseXmlMcpToolCall(xmlString, mcpToolNames = []) {
85596
85597
  function parseHybridXmlToolCall(xmlString, nativeTools = [], mcpBridge = null) {
85597
85598
  const nativeResult = parseNativeXmlToolWithThinking(xmlString, nativeTools);
85598
85599
  if (nativeResult) {
85599
- return { ...nativeResult, type: "native" };
85600
+ const { thinkingContent, ...rest } = nativeResult;
85601
+ return { ...rest, type: "native", thinkingContent };
85600
85602
  }
85601
85603
  if (mcpBridge) {
85602
85604
  const mcpResult = parseXmlMcpToolCall(xmlString, mcpBridge.getToolNames());
85603
85605
  if (mcpResult) {
85604
- return { ...mcpResult, type: "mcp" };
85606
+ const { thinkingContent } = processXmlWithThinkingAndRecovery(xmlString, []);
85607
+ return { ...mcpResult, type: "mcp", thinkingContent };
85605
85608
  }
85606
85609
  }
85607
85610
  return null;
85608
85611
  }
85609
85612
  function parseNativeXmlToolWithThinking(xmlString, validTools) {
85610
- const { cleanedXmlString, recoveryResult } = processXmlWithThinkingAndRecovery(xmlString, validTools);
85613
+ const { cleanedXmlString, recoveryResult, thinkingContent } = processXmlWithThinkingAndRecovery(xmlString, validTools);
85611
85614
  if (recoveryResult) {
85612
- return recoveryResult;
85615
+ return { ...recoveryResult, thinkingContent };
85613
85616
  }
85614
85617
  for (const toolName of validTools) {
85615
85618
  const result = parseNativeXmlTool(cleanedXmlString, toolName);
85616
85619
  if (result) {
85617
- return result;
85620
+ return { ...result, thinkingContent };
85618
85621
  }
85619
85622
  }
85620
85623
  return null;
@@ -96075,6 +96078,181 @@ var init_ProbeAgent = __esm({
96075
96078
  _filterMcpTools(mcpToolNames) {
96076
96079
  return mcpToolNames.filter((toolName) => this._isMcpToolAllowed(toolName));
96077
96080
  }
96081
+ /**
96082
+ * Check if tracer is AppTracer (expects sessionId as first param) vs SimpleAppTracer
96083
+ * @returns {boolean} - True if tracer is AppTracer style (requires sessionId)
96084
+ * @private
96085
+ */
96086
+ _isAppTracerStyle() {
96087
+ return this.tracer && typeof this.tracer.sessionSpans !== "undefined";
96088
+ }
96089
+ /**
96090
+ * Record an error classification event for telemetry
96091
+ * Provides unified error recording across all error types
96092
+ * @param {string} errorType - Error type (wrapped_tool, unrecognized_tool, no_tool_call, circuit_breaker)
96093
+ * @param {string} message - Error message
96094
+ * @param {Object} context - Additional context data
96095
+ * @param {number} iteration - Current iteration number
96096
+ * @private
96097
+ */
96098
+ _recordErrorTelemetry(errorType, message, context, iteration) {
96099
+ if (!this.tracer) return;
96100
+ if (this._isAppTracerStyle() && typeof this.tracer.recordErrorClassification === "function") {
96101
+ this.tracer.recordErrorClassification(this.sessionId, iteration, errorType, {
96102
+ message,
96103
+ context
96104
+ });
96105
+ } else if (typeof this.tracer.recordErrorEvent === "function") {
96106
+ this.tracer.recordErrorEvent(errorType, {
96107
+ message,
96108
+ context: { ...context, iteration }
96109
+ });
96110
+ } else {
96111
+ this.tracer.addEvent(`error.${errorType}`, {
96112
+ "error.type": errorType,
96113
+ "error.message": message,
96114
+ "error.recoverable": errorType !== "circuit_breaker",
96115
+ "error.context": JSON.stringify(context).substring(0, 1e3),
96116
+ "iteration": iteration
96117
+ });
96118
+ }
96119
+ }
96120
+ /**
96121
+ * Record AI thinking content for telemetry
96122
+ * @param {string} thinkingContent - The thinking content
96123
+ * @param {number} iteration - Current iteration number
96124
+ * @private
96125
+ */
96126
+ _recordThinkingTelemetry(thinkingContent, iteration) {
96127
+ if (!this.tracer || !thinkingContent) return;
96128
+ if (this._isAppTracerStyle() && typeof this.tracer.recordThinkingContent === "function") {
96129
+ this.tracer.recordThinkingContent(this.sessionId, iteration, thinkingContent);
96130
+ } else if (typeof this.tracer.recordThinkingContent === "function") {
96131
+ this.tracer.recordThinkingContent(thinkingContent, { iteration });
96132
+ } else {
96133
+ this.tracer.addEvent("ai.thinking", {
96134
+ "ai.thinking.content": thinkingContent.substring(0, 5e4),
96135
+ "ai.thinking.length": thinkingContent.length,
96136
+ "iteration": iteration
96137
+ });
96138
+ }
96139
+ }
96140
+ /**
96141
+ * Record AI tool decision for telemetry
96142
+ * @param {string} toolName - The tool name
96143
+ * @param {Object} params - Tool parameters
96144
+ * @param {number} responseLength - Length of AI response
96145
+ * @param {number} iteration - Current iteration number
96146
+ * @private
96147
+ */
96148
+ _recordToolDecisionTelemetry(toolName, params, responseLength, iteration) {
96149
+ if (!this.tracer) return;
96150
+ if (this._isAppTracerStyle() && typeof this.tracer.recordAIToolDecision === "function") {
96151
+ this.tracer.recordAIToolDecision(this.sessionId, iteration, toolName, params);
96152
+ } else if (typeof this.tracer.recordToolDecision === "function") {
96153
+ this.tracer.recordToolDecision(toolName, params, {
96154
+ iteration,
96155
+ "ai.tool_decision.raw_response_length": responseLength
96156
+ });
96157
+ } else {
96158
+ this.tracer.addEvent("ai.tool_decision", {
96159
+ "ai.tool_decision.name": toolName,
96160
+ "ai.tool_decision.params": JSON.stringify(params || {}).substring(0, 2e3),
96161
+ "ai.tool_decision.raw_response_length": responseLength,
96162
+ "iteration": iteration
96163
+ });
96164
+ }
96165
+ }
96166
+ /**
96167
+ * Record tool result for telemetry
96168
+ * @param {string} toolName - The tool name
96169
+ * @param {string|Object} result - Tool result
96170
+ * @param {boolean} success - Whether tool succeeded
96171
+ * @param {number} durationMs - Execution duration in milliseconds
96172
+ * @param {number} iteration - Current iteration number
96173
+ * @private
96174
+ */
96175
+ _recordToolResultTelemetry(toolName, result, success, durationMs, iteration) {
96176
+ if (!this.tracer) return;
96177
+ if (this._isAppTracerStyle() && typeof this.tracer.recordToolResult === "function") {
96178
+ this.tracer.recordToolResult(this.sessionId, iteration, toolName, result, success, durationMs);
96179
+ } else if (typeof this.tracer.recordToolResult === "function") {
96180
+ this.tracer.recordToolResult(toolName, result, success, durationMs, { iteration });
96181
+ } else {
96182
+ const resultStr = typeof result === "string" ? result : JSON.stringify(result || "");
96183
+ this.tracer.addEvent("tool.result", {
96184
+ "tool.name": toolName,
96185
+ "tool.result": resultStr.substring(0, 1e4),
96186
+ "tool.result.length": resultStr.length,
96187
+ "tool.duration_ms": durationMs,
96188
+ "tool.success": success,
96189
+ "iteration": iteration
96190
+ });
96191
+ }
96192
+ }
96193
+ /**
96194
+ * Record MCP tool lifecycle event for telemetry
96195
+ * @param {string} phase - 'start' or 'end'
96196
+ * @param {string} toolName - MCP tool name
96197
+ * @param {Object} params - Tool parameters (for start) or null (for end)
96198
+ * @param {number} iteration - Current iteration number
96199
+ * @param {Object} [endData] - Additional data for end phase (result, success, durationMs, error)
96200
+ * @private
96201
+ */
96202
+ _recordMcpToolTelemetry(phase, toolName, params, iteration, endData = null) {
96203
+ if (!this.tracer) return;
96204
+ if (phase === "start") {
96205
+ if (this._isAppTracerStyle() && typeof this.tracer.recordMcpToolStart === "function") {
96206
+ this.tracer.recordMcpToolStart(this.sessionId, iteration, toolName, "mcp", params);
96207
+ } else if (typeof this.tracer.recordMcpToolStart === "function") {
96208
+ this.tracer.recordMcpToolStart(toolName, "mcp", params, { iteration });
96209
+ } else {
96210
+ this.tracer.addEvent("mcp.tool.start", {
96211
+ "mcp.tool.name": toolName,
96212
+ "mcp.tool.server": "mcp",
96213
+ "mcp.tool.params": JSON.stringify(params || {}).substring(0, 2e3),
96214
+ "iteration": iteration
96215
+ });
96216
+ }
96217
+ } else if (phase === "end" && endData) {
96218
+ const { result, success, durationMs, error: error2 } = endData;
96219
+ if (this._isAppTracerStyle() && typeof this.tracer.recordMcpToolEnd === "function") {
96220
+ this.tracer.recordMcpToolEnd(this.sessionId, iteration, toolName, "mcp", result, success, durationMs, error2);
96221
+ } else if (typeof this.tracer.recordMcpToolEnd === "function") {
96222
+ this.tracer.recordMcpToolEnd(toolName, "mcp", result, success, durationMs, error2, { iteration });
96223
+ } else {
96224
+ const resultStr = typeof result === "string" ? result : JSON.stringify(result || "");
96225
+ this.tracer.addEvent("mcp.tool.end", {
96226
+ "mcp.tool.name": toolName,
96227
+ "mcp.tool.server": "mcp",
96228
+ "mcp.tool.result": resultStr.substring(0, 1e4),
96229
+ "mcp.tool.result.length": resultStr.length,
96230
+ "mcp.tool.duration_ms": durationMs,
96231
+ "mcp.tool.success": success,
96232
+ "mcp.tool.error": error2,
96233
+ "iteration": iteration
96234
+ });
96235
+ }
96236
+ }
96237
+ }
96238
+ /**
96239
+ * Record iteration lifecycle event for telemetry
96240
+ * @param {string} phase - 'end' (start is already handled elsewhere)
96241
+ * @param {number} iteration - Current iteration number
96242
+ * @param {Object} data - Additional iteration data
96243
+ * @private
96244
+ */
96245
+ _recordIterationTelemetry(phase, iteration, data2 = {}) {
96246
+ if (!this.tracer) return;
96247
+ if (typeof this.tracer.recordIterationEvent === "function") {
96248
+ this.tracer.recordIterationEvent(phase, iteration, data2);
96249
+ } else {
96250
+ this.tracer.addEvent(`iteration.${phase}`, {
96251
+ "iteration": iteration,
96252
+ ...data2
96253
+ });
96254
+ }
96255
+ }
96078
96256
  /**
96079
96257
  * Initialize the agent asynchronously (must be called after constructor)
96080
96258
  * This method initializes MCP and merges MCP tools into the tool list, and loads history from storage
@@ -98029,8 +98207,12 @@ You are working with a repository located at: ${searchDirectory}
98029
98207
  }
98030
98208
  const nativeTools = validTools;
98031
98209
  const parsedTool = this.mcpBridge && !options._disableTools ? parseHybridXmlToolCall(assistantResponseContent, nativeTools, this.mcpBridge) : parseXmlToolCallWithThinking(assistantResponseContent, validTools);
98210
+ if (parsedTool?.thinkingContent) {
98211
+ this._recordThinkingTelemetry(parsedTool.thinkingContent, currentIteration);
98212
+ }
98032
98213
  if (parsedTool) {
98033
98214
  const { toolName, params } = parsedTool;
98215
+ this._recordToolDecisionTelemetry(toolName, params, assistantResponseContent.length, currentIteration);
98034
98216
  if (this.debug) console.log(`[DEBUG] Parsed tool call: ${toolName} with params:`, params);
98035
98217
  if (toolName === "attempt_completion") {
98036
98218
  completionAttempted = true;
@@ -98107,6 +98289,8 @@ You are working with a repository located at: ${searchDirectory}
98107
98289
  } else {
98108
98290
  const { type } = parsedTool;
98109
98291
  if (type === "mcp" && this.mcpBridge && this.mcpBridge.isMcpTool(toolName)) {
98292
+ const mcpStartTime = Date.now();
98293
+ this._recordMcpToolTelemetry("start", toolName, params, currentIteration);
98110
98294
  try {
98111
98295
  if (this.debug) {
98112
98296
  console.error(`
@@ -98136,6 +98320,13 @@ You are working with a repository located at: ${searchDirectory}
98136
98320
  } catch (truncateError) {
98137
98321
  console.error(`[WARN] Tool output truncation failed: ${truncateError.message}`);
98138
98322
  }
98323
+ const mcpDurationMs = Date.now() - mcpStartTime;
98324
+ this._recordMcpToolTelemetry("end", toolName, null, currentIteration, {
98325
+ result: toolResultContent,
98326
+ success: true,
98327
+ durationMs: mcpDurationMs,
98328
+ error: null
98329
+ });
98139
98330
  if (this.debug) {
98140
98331
  const preview = toolResultContent.length > 500 ? toolResultContent.substring(0, 500) + "..." : toolResultContent;
98141
98332
  console.error(`[DEBUG] ========================================`);
@@ -98149,6 +98340,13 @@ You are working with a repository located at: ${searchDirectory}
98149
98340
  ${toolResultContent}
98150
98341
  </tool_result>` });
98151
98342
  } catch (error2) {
98343
+ const mcpDurationMs = Date.now() - mcpStartTime;
98344
+ this._recordMcpToolTelemetry("end", toolName, null, currentIteration, {
98345
+ result: null,
98346
+ success: false,
98347
+ durationMs: mcpDurationMs,
98348
+ error: error2.message
98349
+ });
98152
98350
  console.error(`Error executing MCP tool ${toolName}:`, error2);
98153
98351
  if (this.debug) {
98154
98352
  console.error(`[DEBUG] ========================================`);
@@ -98240,6 +98438,7 @@ ${errorXml}
98240
98438
  return await this.toolImplementations[toolName].execute(toolParams);
98241
98439
  };
98242
98440
  let toolResult;
98441
+ const toolStartTime = Date.now();
98243
98442
  try {
98244
98443
  if (this.tracer) {
98245
98444
  toolResult = await this.tracer.withSpan("tool.call", executeToolCall, {
@@ -98250,6 +98449,8 @@ ${errorXml}
98250
98449
  } else {
98251
98450
  toolResult = await executeToolCall();
98252
98451
  }
98452
+ const toolDurationMs = Date.now() - toolStartTime;
98453
+ this._recordToolResultTelemetry(toolName, toolResult, true, toolDurationMs, currentIteration);
98253
98454
  if (this.debug) {
98254
98455
  const resultPreview = typeof toolResult === "string" ? toolResult.length > 500 ? toolResult.substring(0, 500) + "..." : toolResult : toolResult ? JSON.stringify(toolResult, null, 2).substring(0, 500) + "..." : "No Result";
98255
98456
  console.error(`[DEBUG] ========================================`);
@@ -98306,6 +98507,20 @@ ${toolResultContent}
98306
98507
  role: "user",
98307
98508
  content: toolResultMessage
98308
98509
  });
98510
+ if (this.tracer) {
98511
+ if (typeof this.tracer.recordConversationTurn === "function") {
98512
+ this.tracer.recordConversationTurn("assistant", assistantResponseContent, {
98513
+ iteration: currentIteration,
98514
+ has_tool_call: true,
98515
+ tool_name: toolName
98516
+ });
98517
+ this.tracer.recordConversationTurn("tool_result", toolResultContent, {
98518
+ iteration: currentIteration,
98519
+ tool_name: toolName,
98520
+ tool_success: true
98521
+ });
98522
+ }
98523
+ }
98309
98524
  if (this.debug) {
98310
98525
  console.log(`[DEBUG] Tool ${toolName} executed successfully. Result length: ${typeof toolResult === "string" ? toolResult.length : JSON.stringify(toolResult).length}`);
98311
98526
  }
@@ -98376,6 +98591,7 @@ ${errorXml}
98376
98591
  if (this.debug) {
98377
98592
  console.log(`[DEBUG] Detected wrapped tool '${wrappedToolName}' in assistant response - wrong XML format.`);
98378
98593
  }
98594
+ this._recordErrorTelemetry("wrapped_tool", "Tool call wrapped in markdown", { toolName: wrappedToolName }, currentIteration);
98379
98595
  const toolError = new ParameterError(
98380
98596
  `Tool '${wrappedToolName}' found but in WRONG FORMAT - do not wrap tools in other XML tags.`,
98381
98597
  {
@@ -98401,6 +98617,7 @@ ${formatErrorForAI(toolError)}
98401
98617
  if (this.debug) {
98402
98618
  console.log(`[DEBUG] Detected unrecognized tool '${unrecognizedTool}' in assistant response.`);
98403
98619
  }
98620
+ this._recordErrorTelemetry("unrecognized_tool", `Unknown tool: ${unrecognizedTool}`, { toolName: unrecognizedTool, validTools }, currentIteration);
98404
98621
  const toolError = new ParameterError(`Tool '${unrecognizedTool}' is not available in this context.`, {
98405
98622
  suggestion: `Available tools: ${validTools.join(", ")}. Please use one of these tools instead.`
98406
98623
  });
@@ -98408,6 +98625,7 @@ ${formatErrorForAI(toolError)}
98408
98625
  ${formatErrorForAI(toolError)}
98409
98626
  </tool_result>`;
98410
98627
  } else {
98628
+ this._recordErrorTelemetry("no_tool_call", "AI response did not contain tool call", { responsePreview: assistantResponseContent.substring(0, 500) }, currentIteration);
98411
98629
  if (currentIteration >= maxIterations) {
98412
98630
  let cleanedResponse = assistantResponseContent;
98413
98631
  cleanedResponse = cleanedResponse.replace(/<thinking>[\s\S]*?<\/thinking>/gi, "").trim();
@@ -98483,6 +98701,7 @@ Note: <attempt_complete></attempt_complete> reuses your PREVIOUS assistant messa
98483
98701
  sameFormatErrorCount++;
98484
98702
  if (sameFormatErrorCount >= MAX_REPEATED_FORMAT_ERRORS) {
98485
98703
  const errorDesc = isWrapped ? "wrapped tool format" : unrecognizedTool;
98704
+ this._recordErrorTelemetry("circuit_breaker", "Format error limit exceeded", { formatErrorCount: sameFormatErrorCount, errorCategory }, currentIteration);
98486
98705
  console.error(`[ERROR] Format error category '${errorCategory}' repeated ${sameFormatErrorCount} times. Breaking loop early to prevent infinite iteration.`);
98487
98706
  finalResult = `Error: Unable to complete request. The AI model repeatedly used incorrect tool call format (${errorDesc}). Please try rephrasing your question or using a different model.`;
98488
98707
  break;
@@ -98496,6 +98715,10 @@ Note: <attempt_complete></attempt_complete> reuses your PREVIOUS assistant messa
98496
98715
  sameFormatErrorCount = 0;
98497
98716
  }
98498
98717
  }
98718
+ this._recordIterationTelemetry("end", currentIteration, {
98719
+ "iteration.completed": completionAttempted,
98720
+ "iteration.message_count": currentMessages.length
98721
+ });
98499
98722
  if (currentMessages.length > MAX_HISTORY_MESSAGES) {
98500
98723
  const messagesBefore = currentMessages.length;
98501
98724
  const systemMsg = currentMessages[0];
@@ -102836,6 +103059,183 @@ var init_simpleTelemetry = __esm({
102836
103059
  console.log("[Attributes]", attributes);
102837
103060
  }
102838
103061
  }
103062
+ /**
103063
+ * Hash content for deduplication/comparison purposes
103064
+ * @param {string} content - The content to hash
103065
+ * @returns {string} - Hex string hash
103066
+ */
103067
+ hashContent(content) {
103068
+ let hash = 0;
103069
+ const len = Math.min(content.length, 1e3);
103070
+ for (let i5 = 0; i5 < len; i5++) {
103071
+ hash = (hash << 5) - hash + content.charCodeAt(i5);
103072
+ hash |= 0;
103073
+ }
103074
+ return hash.toString(16);
103075
+ }
103076
+ /**
103077
+ * Record a conversation turn (assistant response or tool result)
103078
+ * @param {string} role - The role (assistant, tool_result)
103079
+ * @param {string} content - The turn content
103080
+ * @param {Object} metadata - Additional metadata
103081
+ */
103082
+ recordConversationTurn(role, content, metadata = {}) {
103083
+ if (!this.isEnabled()) return;
103084
+ this.addEvent(`conversation.turn.${role}`, {
103085
+ "session.id": this.sessionId,
103086
+ "conversation.role": role,
103087
+ "conversation.content": content.substring(0, 1e4),
103088
+ "conversation.content.length": content.length,
103089
+ "conversation.content.hash": this.hashContent(content),
103090
+ ...metadata
103091
+ });
103092
+ }
103093
+ /**
103094
+ * Record error events with classification
103095
+ * @param {string} errorType - The type of error (wrapped_tool, unrecognized_tool, no_tool_call, circuit_breaker, etc.)
103096
+ * @param {Object} errorDetails - Error details including message, stack, context
103097
+ */
103098
+ recordErrorEvent(errorType, errorDetails = {}) {
103099
+ if (!this.isEnabled()) return;
103100
+ this.addEvent(`error.${errorType}`, {
103101
+ "session.id": this.sessionId,
103102
+ "error.type": errorType,
103103
+ "error.message": errorDetails.message?.substring(0, 1e3) || null,
103104
+ "error.stack": errorDetails.stack?.substring(0, 2e3) || null,
103105
+ "error.recoverable": errorDetails.recoverable ?? true,
103106
+ "error.context": JSON.stringify(errorDetails.context || {}).substring(0, 1e3),
103107
+ ...Object.fromEntries(
103108
+ Object.entries(errorDetails).filter(([k5]) => !["message", "stack", "context", "recoverable"].includes(k5)).map(([k5, v5]) => [`error.${k5}`, v5])
103109
+ )
103110
+ });
103111
+ }
103112
+ /**
103113
+ * Record AI thinking/reasoning content
103114
+ * @param {string} thinkingContent - The thinking content from AI response
103115
+ * @param {Object} metadata - Additional metadata
103116
+ */
103117
+ recordThinkingContent(thinkingContent, metadata = {}) {
103118
+ if (!this.isEnabled() || !thinkingContent) return;
103119
+ this.addEvent("ai.thinking", {
103120
+ "session.id": this.sessionId,
103121
+ "ai.thinking.content": thinkingContent.substring(0, 5e4),
103122
+ "ai.thinking.length": thinkingContent.length,
103123
+ "ai.thinking.hash": this.hashContent(thinkingContent),
103124
+ ...metadata
103125
+ });
103126
+ }
103127
+ /**
103128
+ * Record AI tool call decision
103129
+ * @param {string} toolName - The tool name AI decided to call
103130
+ * @param {Object} params - The parameters AI provided
103131
+ * @param {Object} metadata - Additional metadata
103132
+ */
103133
+ recordToolDecision(toolName, params, metadata = {}) {
103134
+ if (!this.isEnabled()) return;
103135
+ this.addEvent("ai.tool_decision", {
103136
+ "session.id": this.sessionId,
103137
+ "ai.tool_decision.name": toolName,
103138
+ "ai.tool_decision.params": JSON.stringify(params || {}).substring(0, 2e3),
103139
+ ...metadata
103140
+ });
103141
+ }
103142
+ /**
103143
+ * Record tool result after execution
103144
+ * @param {string} toolName - The tool that was executed
103145
+ * @param {string|Object} result - The tool result
103146
+ * @param {boolean} success - Whether the tool succeeded
103147
+ * @param {number} durationMs - Execution duration in milliseconds
103148
+ * @param {Object} metadata - Additional metadata
103149
+ */
103150
+ recordToolResult(toolName, result, success, durationMs, metadata = {}) {
103151
+ if (!this.isEnabled()) return;
103152
+ const resultStr = typeof result === "string" ? result : JSON.stringify(result);
103153
+ this.addEvent("tool.result", {
103154
+ "session.id": this.sessionId,
103155
+ "tool.name": toolName,
103156
+ "tool.result": resultStr.substring(0, 1e4),
103157
+ "tool.result.length": resultStr.length,
103158
+ "tool.result.hash": this.hashContent(resultStr),
103159
+ "tool.duration_ms": durationMs,
103160
+ "tool.success": success,
103161
+ ...metadata
103162
+ });
103163
+ }
103164
+ /**
103165
+ * Record MCP tool execution start
103166
+ * @param {string} toolName - MCP tool name
103167
+ * @param {string} serverName - MCP server name
103168
+ * @param {Object} params - Tool parameters
103169
+ * @param {Object} metadata - Additional metadata
103170
+ */
103171
+ recordMcpToolStart(toolName, serverName, params, metadata = {}) {
103172
+ if (!this.isEnabled()) return;
103173
+ this.addEvent("mcp.tool.start", {
103174
+ "session.id": this.sessionId,
103175
+ "mcp.tool.name": toolName,
103176
+ "mcp.tool.server": serverName || "unknown",
103177
+ "mcp.tool.params": JSON.stringify(params || {}).substring(0, 2e3),
103178
+ ...metadata
103179
+ });
103180
+ }
103181
+ /**
103182
+ * Record MCP tool execution end
103183
+ * @param {string} toolName - MCP tool name
103184
+ * @param {string} serverName - MCP server name
103185
+ * @param {string|Object} result - Tool result
103186
+ * @param {boolean} success - Whether succeeded
103187
+ * @param {number} durationMs - Execution duration
103188
+ * @param {string} errorMessage - Error message if failed
103189
+ * @param {Object} metadata - Additional metadata
103190
+ */
103191
+ recordMcpToolEnd(toolName, serverName, result, success, durationMs, errorMessage = null, metadata = {}) {
103192
+ if (!this.isEnabled()) return;
103193
+ const resultStr = typeof result === "string" ? result : JSON.stringify(result || "");
103194
+ this.addEvent("mcp.tool.end", {
103195
+ "session.id": this.sessionId,
103196
+ "mcp.tool.name": toolName,
103197
+ "mcp.tool.server": serverName || "unknown",
103198
+ "mcp.tool.result": resultStr.substring(0, 1e4),
103199
+ "mcp.tool.result.length": resultStr.length,
103200
+ "mcp.tool.duration_ms": durationMs,
103201
+ "mcp.tool.success": success,
103202
+ "mcp.tool.error": errorMessage,
103203
+ ...metadata
103204
+ });
103205
+ }
103206
+ /**
103207
+ * Record iteration lifecycle event
103208
+ * @param {string} eventType - start or end
103209
+ * @param {number} iteration - Iteration number
103210
+ * @param {Object} data - Additional data
103211
+ */
103212
+ recordIterationEvent(eventType, iteration, data2 = {}) {
103213
+ if (!this.isEnabled()) return;
103214
+ this.addEvent(`iteration.${eventType}`, {
103215
+ "session.id": this.sessionId,
103216
+ "iteration": iteration,
103217
+ ...data2
103218
+ });
103219
+ }
103220
+ /**
103221
+ * Record per-turn token breakdown
103222
+ * @param {number} iteration - Iteration number
103223
+ * @param {Object} tokenData - Token metrics
103224
+ */
103225
+ recordTokenTurn(iteration, tokenData = {}) {
103226
+ if (!this.isEnabled()) return;
103227
+ this.addEvent("tokens.turn", {
103228
+ "session.id": this.sessionId,
103229
+ "iteration": iteration,
103230
+ "tokens.input": tokenData.inputTokens || 0,
103231
+ "tokens.output": tokenData.outputTokens || 0,
103232
+ "tokens.total": (tokenData.inputTokens || 0) + (tokenData.outputTokens || 0),
103233
+ "tokens.cache_read": tokenData.cacheReadTokens || 0,
103234
+ "tokens.cache_write": tokenData.cacheWriteTokens || 0,
103235
+ "tokens.context_used": tokenData.contextTokens || 0,
103236
+ "tokens.context_remaining": tokenData.maxContextTokens ? tokenData.maxContextTokens - (tokenData.contextTokens || 0) : null
103237
+ });
103238
+ }
102839
103239
  async withSpan(spanName, fn, attributes = {}) {
102840
103240
  if (!this.isEnabled()) {
102841
103241
  return fn();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@probelabs/probe",
3
- "version": "0.6.0-rc224",
3
+ "version": "0.6.0-rc225",
4
4
  "description": "Node.js wrapper for the probe code search tool",
5
5
  "main": "src/index.js",
6
6
  "module": "src/index.js",