@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/bin/binaries/probe-v0.6.0-rc225-aarch64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc225-aarch64-unknown-linux-musl.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc225-x86_64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/{probe-v0.6.0-rc224-x86_64-pc-windows-msvc.zip → probe-v0.6.0-rc225-x86_64-pc-windows-msvc.zip} +0 -0
- package/bin/binaries/probe-v0.6.0-rc225-x86_64-unknown-linux-musl.tar.gz +0 -0
- package/build/agent/ProbeAgent.js +279 -3
- package/build/agent/index.js +408 -8
- package/build/agent/mcp/xmlBridge.js +10 -7
- package/build/agent/simpleTelemetry.js +198 -0
- package/build/agent/tools.js +8 -5
- package/cjs/agent/ProbeAgent.cjs +231 -8
- package/cjs/agent/simpleTelemetry.cjs +177 -0
- package/cjs/index.cjs +408 -8
- package/package.json +1 -1
- package/src/agent/ProbeAgent.js +279 -3
- package/src/agent/mcp/xmlBridge.js +10 -7
- package/src/agent/simpleTelemetry.js +198 -0
- package/src/agent/tools.js +8 -5
- package/bin/binaries/probe-v0.6.0-rc224-aarch64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc224-aarch64-unknown-linux-musl.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc224-x86_64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc224-x86_64-unknown-linux-musl.tar.gz +0 -0
|
@@ -264,6 +264,204 @@ export class SimpleAppTracer {
|
|
|
264
264
|
}
|
|
265
265
|
}
|
|
266
266
|
|
|
267
|
+
/**
|
|
268
|
+
* Hash content for deduplication/comparison purposes
|
|
269
|
+
* @param {string} content - The content to hash
|
|
270
|
+
* @returns {string} - Hex string hash
|
|
271
|
+
*/
|
|
272
|
+
hashContent(content) {
|
|
273
|
+
let hash = 0;
|
|
274
|
+
const len = Math.min(content.length, 1000);
|
|
275
|
+
for (let i = 0; i < len; i++) {
|
|
276
|
+
hash = ((hash << 5) - hash) + content.charCodeAt(i);
|
|
277
|
+
hash |= 0; // Convert to 32-bit integer
|
|
278
|
+
}
|
|
279
|
+
return hash.toString(16);
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/**
|
|
283
|
+
* Record a conversation turn (assistant response or tool result)
|
|
284
|
+
* @param {string} role - The role (assistant, tool_result)
|
|
285
|
+
* @param {string} content - The turn content
|
|
286
|
+
* @param {Object} metadata - Additional metadata
|
|
287
|
+
*/
|
|
288
|
+
recordConversationTurn(role, content, metadata = {}) {
|
|
289
|
+
if (!this.isEnabled()) return;
|
|
290
|
+
|
|
291
|
+
this.addEvent(`conversation.turn.${role}`, {
|
|
292
|
+
'session.id': this.sessionId,
|
|
293
|
+
'conversation.role': role,
|
|
294
|
+
'conversation.content': content.substring(0, 10000),
|
|
295
|
+
'conversation.content.length': content.length,
|
|
296
|
+
'conversation.content.hash': this.hashContent(content),
|
|
297
|
+
...metadata
|
|
298
|
+
});
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Record error events with classification
|
|
303
|
+
* @param {string} errorType - The type of error (wrapped_tool, unrecognized_tool, no_tool_call, circuit_breaker, etc.)
|
|
304
|
+
* @param {Object} errorDetails - Error details including message, stack, context
|
|
305
|
+
*/
|
|
306
|
+
recordErrorEvent(errorType, errorDetails = {}) {
|
|
307
|
+
if (!this.isEnabled()) return;
|
|
308
|
+
|
|
309
|
+
this.addEvent(`error.${errorType}`, {
|
|
310
|
+
'session.id': this.sessionId,
|
|
311
|
+
'error.type': errorType,
|
|
312
|
+
'error.message': errorDetails.message?.substring(0, 1000) || null,
|
|
313
|
+
'error.stack': errorDetails.stack?.substring(0, 2000) || null,
|
|
314
|
+
'error.recoverable': errorDetails.recoverable ?? true,
|
|
315
|
+
'error.context': JSON.stringify(errorDetails.context || {}).substring(0, 1000),
|
|
316
|
+
...Object.fromEntries(
|
|
317
|
+
Object.entries(errorDetails)
|
|
318
|
+
.filter(([k]) => !['message', 'stack', 'context', 'recoverable'].includes(k))
|
|
319
|
+
.map(([k, v]) => [`error.${k}`, v])
|
|
320
|
+
)
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* Record AI thinking/reasoning content
|
|
326
|
+
* @param {string} thinkingContent - The thinking content from AI response
|
|
327
|
+
* @param {Object} metadata - Additional metadata
|
|
328
|
+
*/
|
|
329
|
+
recordThinkingContent(thinkingContent, metadata = {}) {
|
|
330
|
+
if (!this.isEnabled() || !thinkingContent) return;
|
|
331
|
+
|
|
332
|
+
this.addEvent('ai.thinking', {
|
|
333
|
+
'session.id': this.sessionId,
|
|
334
|
+
'ai.thinking.content': thinkingContent.substring(0, 50000),
|
|
335
|
+
'ai.thinking.length': thinkingContent.length,
|
|
336
|
+
'ai.thinking.hash': this.hashContent(thinkingContent),
|
|
337
|
+
...metadata
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Record AI tool call decision
|
|
343
|
+
* @param {string} toolName - The tool name AI decided to call
|
|
344
|
+
* @param {Object} params - The parameters AI provided
|
|
345
|
+
* @param {Object} metadata - Additional metadata
|
|
346
|
+
*/
|
|
347
|
+
recordToolDecision(toolName, params, metadata = {}) {
|
|
348
|
+
if (!this.isEnabled()) return;
|
|
349
|
+
|
|
350
|
+
this.addEvent('ai.tool_decision', {
|
|
351
|
+
'session.id': this.sessionId,
|
|
352
|
+
'ai.tool_decision.name': toolName,
|
|
353
|
+
'ai.tool_decision.params': JSON.stringify(params || {}).substring(0, 2000),
|
|
354
|
+
...metadata
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Record tool result after execution
|
|
360
|
+
* @param {string} toolName - The tool that was executed
|
|
361
|
+
* @param {string|Object} result - The tool result
|
|
362
|
+
* @param {boolean} success - Whether the tool succeeded
|
|
363
|
+
* @param {number} durationMs - Execution duration in milliseconds
|
|
364
|
+
* @param {Object} metadata - Additional metadata
|
|
365
|
+
*/
|
|
366
|
+
recordToolResult(toolName, result, success, durationMs, metadata = {}) {
|
|
367
|
+
if (!this.isEnabled()) return;
|
|
368
|
+
|
|
369
|
+
const resultStr = typeof result === 'string' ? result : JSON.stringify(result);
|
|
370
|
+
this.addEvent('tool.result', {
|
|
371
|
+
'session.id': this.sessionId,
|
|
372
|
+
'tool.name': toolName,
|
|
373
|
+
'tool.result': resultStr.substring(0, 10000),
|
|
374
|
+
'tool.result.length': resultStr.length,
|
|
375
|
+
'tool.result.hash': this.hashContent(resultStr),
|
|
376
|
+
'tool.duration_ms': durationMs,
|
|
377
|
+
'tool.success': success,
|
|
378
|
+
...metadata
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* Record MCP tool execution start
|
|
384
|
+
* @param {string} toolName - MCP tool name
|
|
385
|
+
* @param {string} serverName - MCP server name
|
|
386
|
+
* @param {Object} params - Tool parameters
|
|
387
|
+
* @param {Object} metadata - Additional metadata
|
|
388
|
+
*/
|
|
389
|
+
recordMcpToolStart(toolName, serverName, params, metadata = {}) {
|
|
390
|
+
if (!this.isEnabled()) return;
|
|
391
|
+
|
|
392
|
+
this.addEvent('mcp.tool.start', {
|
|
393
|
+
'session.id': this.sessionId,
|
|
394
|
+
'mcp.tool.name': toolName,
|
|
395
|
+
'mcp.tool.server': serverName || 'unknown',
|
|
396
|
+
'mcp.tool.params': JSON.stringify(params || {}).substring(0, 2000),
|
|
397
|
+
...metadata
|
|
398
|
+
});
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* Record MCP tool execution end
|
|
403
|
+
* @param {string} toolName - MCP tool name
|
|
404
|
+
* @param {string} serverName - MCP server name
|
|
405
|
+
* @param {string|Object} result - Tool result
|
|
406
|
+
* @param {boolean} success - Whether succeeded
|
|
407
|
+
* @param {number} durationMs - Execution duration
|
|
408
|
+
* @param {string} errorMessage - Error message if failed
|
|
409
|
+
* @param {Object} metadata - Additional metadata
|
|
410
|
+
*/
|
|
411
|
+
recordMcpToolEnd(toolName, serverName, result, success, durationMs, errorMessage = null, metadata = {}) {
|
|
412
|
+
if (!this.isEnabled()) return;
|
|
413
|
+
|
|
414
|
+
const resultStr = typeof result === 'string' ? result : JSON.stringify(result || '');
|
|
415
|
+
this.addEvent('mcp.tool.end', {
|
|
416
|
+
'session.id': this.sessionId,
|
|
417
|
+
'mcp.tool.name': toolName,
|
|
418
|
+
'mcp.tool.server': serverName || 'unknown',
|
|
419
|
+
'mcp.tool.result': resultStr.substring(0, 10000),
|
|
420
|
+
'mcp.tool.result.length': resultStr.length,
|
|
421
|
+
'mcp.tool.duration_ms': durationMs,
|
|
422
|
+
'mcp.tool.success': success,
|
|
423
|
+
'mcp.tool.error': errorMessage,
|
|
424
|
+
...metadata
|
|
425
|
+
});
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* Record iteration lifecycle event
|
|
430
|
+
* @param {string} eventType - start or end
|
|
431
|
+
* @param {number} iteration - Iteration number
|
|
432
|
+
* @param {Object} data - Additional data
|
|
433
|
+
*/
|
|
434
|
+
recordIterationEvent(eventType, iteration, data = {}) {
|
|
435
|
+
if (!this.isEnabled()) return;
|
|
436
|
+
|
|
437
|
+
this.addEvent(`iteration.${eventType}`, {
|
|
438
|
+
'session.id': this.sessionId,
|
|
439
|
+
'iteration': iteration,
|
|
440
|
+
...data
|
|
441
|
+
});
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
/**
|
|
445
|
+
* Record per-turn token breakdown
|
|
446
|
+
* @param {number} iteration - Iteration number
|
|
447
|
+
* @param {Object} tokenData - Token metrics
|
|
448
|
+
*/
|
|
449
|
+
recordTokenTurn(iteration, tokenData = {}) {
|
|
450
|
+
if (!this.isEnabled()) return;
|
|
451
|
+
|
|
452
|
+
this.addEvent('tokens.turn', {
|
|
453
|
+
'session.id': this.sessionId,
|
|
454
|
+
'iteration': iteration,
|
|
455
|
+
'tokens.input': tokenData.inputTokens || 0,
|
|
456
|
+
'tokens.output': tokenData.outputTokens || 0,
|
|
457
|
+
'tokens.total': (tokenData.inputTokens || 0) + (tokenData.outputTokens || 0),
|
|
458
|
+
'tokens.cache_read': tokenData.cacheReadTokens || 0,
|
|
459
|
+
'tokens.cache_write': tokenData.cacheWriteTokens || 0,
|
|
460
|
+
'tokens.context_used': tokenData.contextTokens || 0,
|
|
461
|
+
'tokens.context_remaining': tokenData.maxContextTokens ? (tokenData.maxContextTokens - (tokenData.contextTokens || 0)) : null
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
|
|
267
465
|
async withSpan(spanName, fn, attributes = {}) {
|
|
268
466
|
if (!this.isEnabled()) {
|
|
269
467
|
return fn();
|
package/build/agent/tools.js
CHANGED
|
@@ -270,13 +270,16 @@ User: Analyze the diagram in docs/architecture.svg
|
|
|
270
270
|
*/
|
|
271
271
|
export function parseXmlToolCallWithThinking(xmlString, validTools) {
|
|
272
272
|
// Use the shared processing logic
|
|
273
|
-
const { cleanedXmlString, recoveryResult } = processXmlWithThinkingAndRecovery(xmlString, validTools);
|
|
274
|
-
|
|
275
|
-
// If recovery found an attempt_complete pattern, return it
|
|
273
|
+
const { cleanedXmlString, recoveryResult, thinkingContent } = processXmlWithThinkingAndRecovery(xmlString, validTools);
|
|
274
|
+
|
|
275
|
+
// If recovery found an attempt_complete pattern, return it with thinking content
|
|
276
276
|
if (recoveryResult) {
|
|
277
|
-
return recoveryResult;
|
|
277
|
+
return { ...recoveryResult, thinkingContent };
|
|
278
278
|
}
|
|
279
279
|
|
|
280
280
|
// Otherwise, use the original parseXmlToolCall function to parse the cleaned XML string
|
|
281
|
-
|
|
281
|
+
const toolCall = parseXmlToolCall(cleanedXmlString, validTools);
|
|
282
|
+
|
|
283
|
+
// Return tool call with thinking content attached
|
|
284
|
+
return toolCall ? { ...toolCall, thinkingContent } : null;
|
|
282
285
|
}
|
package/cjs/agent/ProbeAgent.cjs
CHANGED
|
@@ -49551,11 +49551,12 @@ function createTools(configOptions) {
|
|
|
49551
49551
|
return tools2;
|
|
49552
49552
|
}
|
|
49553
49553
|
function parseXmlToolCallWithThinking(xmlString, validTools) {
|
|
49554
|
-
const { cleanedXmlString, recoveryResult } = processXmlWithThinkingAndRecovery(xmlString, validTools);
|
|
49554
|
+
const { cleanedXmlString, recoveryResult, thinkingContent } = processXmlWithThinkingAndRecovery(xmlString, validTools);
|
|
49555
49555
|
if (recoveryResult) {
|
|
49556
|
-
return recoveryResult;
|
|
49556
|
+
return { ...recoveryResult, thinkingContent };
|
|
49557
49557
|
}
|
|
49558
|
-
|
|
49558
|
+
const toolCall = parseXmlToolCall(cleanedXmlString, validTools);
|
|
49559
|
+
return toolCall ? { ...toolCall, thinkingContent } : null;
|
|
49559
49560
|
}
|
|
49560
49561
|
var import_crypto4, implementToolDefinition, listFilesToolDefinition, searchFilesToolDefinition, listSkillsToolDefinition, useSkillToolDefinition, readImageToolDefinition;
|
|
49561
49562
|
var init_tools2 = __esm({
|
|
@@ -88850,25 +88851,27 @@ function parseXmlMcpToolCall(xmlString, mcpToolNames = []) {
|
|
|
88850
88851
|
function parseHybridXmlToolCall(xmlString, nativeTools = [], mcpBridge = null) {
|
|
88851
88852
|
const nativeResult = parseNativeXmlToolWithThinking(xmlString, nativeTools);
|
|
88852
88853
|
if (nativeResult) {
|
|
88853
|
-
|
|
88854
|
+
const { thinkingContent, ...rest } = nativeResult;
|
|
88855
|
+
return { ...rest, type: "native", thinkingContent };
|
|
88854
88856
|
}
|
|
88855
88857
|
if (mcpBridge) {
|
|
88856
88858
|
const mcpResult = parseXmlMcpToolCall(xmlString, mcpBridge.getToolNames());
|
|
88857
88859
|
if (mcpResult) {
|
|
88858
|
-
|
|
88860
|
+
const { thinkingContent } = processXmlWithThinkingAndRecovery(xmlString, []);
|
|
88861
|
+
return { ...mcpResult, type: "mcp", thinkingContent };
|
|
88859
88862
|
}
|
|
88860
88863
|
}
|
|
88861
88864
|
return null;
|
|
88862
88865
|
}
|
|
88863
88866
|
function parseNativeXmlToolWithThinking(xmlString, validTools) {
|
|
88864
|
-
const { cleanedXmlString, recoveryResult } = processXmlWithThinkingAndRecovery(xmlString, validTools);
|
|
88867
|
+
const { cleanedXmlString, recoveryResult, thinkingContent } = processXmlWithThinkingAndRecovery(xmlString, validTools);
|
|
88865
88868
|
if (recoveryResult) {
|
|
88866
|
-
return recoveryResult;
|
|
88869
|
+
return { ...recoveryResult, thinkingContent };
|
|
88867
88870
|
}
|
|
88868
88871
|
for (const toolName of validTools) {
|
|
88869
88872
|
const result = parseNativeXmlTool(cleanedXmlString, toolName);
|
|
88870
88873
|
if (result) {
|
|
88871
|
-
return result;
|
|
88874
|
+
return { ...result, thinkingContent };
|
|
88872
88875
|
}
|
|
88873
88876
|
}
|
|
88874
88877
|
return null;
|
|
@@ -99329,6 +99332,181 @@ var init_ProbeAgent = __esm({
|
|
|
99329
99332
|
_filterMcpTools(mcpToolNames) {
|
|
99330
99333
|
return mcpToolNames.filter((toolName) => this._isMcpToolAllowed(toolName));
|
|
99331
99334
|
}
|
|
99335
|
+
/**
|
|
99336
|
+
* Check if tracer is AppTracer (expects sessionId as first param) vs SimpleAppTracer
|
|
99337
|
+
* @returns {boolean} - True if tracer is AppTracer style (requires sessionId)
|
|
99338
|
+
* @private
|
|
99339
|
+
*/
|
|
99340
|
+
_isAppTracerStyle() {
|
|
99341
|
+
return this.tracer && typeof this.tracer.sessionSpans !== "undefined";
|
|
99342
|
+
}
|
|
99343
|
+
/**
|
|
99344
|
+
* Record an error classification event for telemetry
|
|
99345
|
+
* Provides unified error recording across all error types
|
|
99346
|
+
* @param {string} errorType - Error type (wrapped_tool, unrecognized_tool, no_tool_call, circuit_breaker)
|
|
99347
|
+
* @param {string} message - Error message
|
|
99348
|
+
* @param {Object} context - Additional context data
|
|
99349
|
+
* @param {number} iteration - Current iteration number
|
|
99350
|
+
* @private
|
|
99351
|
+
*/
|
|
99352
|
+
_recordErrorTelemetry(errorType, message, context, iteration) {
|
|
99353
|
+
if (!this.tracer) return;
|
|
99354
|
+
if (this._isAppTracerStyle() && typeof this.tracer.recordErrorClassification === "function") {
|
|
99355
|
+
this.tracer.recordErrorClassification(this.sessionId, iteration, errorType, {
|
|
99356
|
+
message,
|
|
99357
|
+
context
|
|
99358
|
+
});
|
|
99359
|
+
} else if (typeof this.tracer.recordErrorEvent === "function") {
|
|
99360
|
+
this.tracer.recordErrorEvent(errorType, {
|
|
99361
|
+
message,
|
|
99362
|
+
context: { ...context, iteration }
|
|
99363
|
+
});
|
|
99364
|
+
} else {
|
|
99365
|
+
this.tracer.addEvent(`error.${errorType}`, {
|
|
99366
|
+
"error.type": errorType,
|
|
99367
|
+
"error.message": message,
|
|
99368
|
+
"error.recoverable": errorType !== "circuit_breaker",
|
|
99369
|
+
"error.context": JSON.stringify(context).substring(0, 1e3),
|
|
99370
|
+
"iteration": iteration
|
|
99371
|
+
});
|
|
99372
|
+
}
|
|
99373
|
+
}
|
|
99374
|
+
/**
|
|
99375
|
+
* Record AI thinking content for telemetry
|
|
99376
|
+
* @param {string} thinkingContent - The thinking content
|
|
99377
|
+
* @param {number} iteration - Current iteration number
|
|
99378
|
+
* @private
|
|
99379
|
+
*/
|
|
99380
|
+
_recordThinkingTelemetry(thinkingContent, iteration) {
|
|
99381
|
+
if (!this.tracer || !thinkingContent) return;
|
|
99382
|
+
if (this._isAppTracerStyle() && typeof this.tracer.recordThinkingContent === "function") {
|
|
99383
|
+
this.tracer.recordThinkingContent(this.sessionId, iteration, thinkingContent);
|
|
99384
|
+
} else if (typeof this.tracer.recordThinkingContent === "function") {
|
|
99385
|
+
this.tracer.recordThinkingContent(thinkingContent, { iteration });
|
|
99386
|
+
} else {
|
|
99387
|
+
this.tracer.addEvent("ai.thinking", {
|
|
99388
|
+
"ai.thinking.content": thinkingContent.substring(0, 5e4),
|
|
99389
|
+
"ai.thinking.length": thinkingContent.length,
|
|
99390
|
+
"iteration": iteration
|
|
99391
|
+
});
|
|
99392
|
+
}
|
|
99393
|
+
}
|
|
99394
|
+
/**
|
|
99395
|
+
* Record AI tool decision for telemetry
|
|
99396
|
+
* @param {string} toolName - The tool name
|
|
99397
|
+
* @param {Object} params - Tool parameters
|
|
99398
|
+
* @param {number} responseLength - Length of AI response
|
|
99399
|
+
* @param {number} iteration - Current iteration number
|
|
99400
|
+
* @private
|
|
99401
|
+
*/
|
|
99402
|
+
_recordToolDecisionTelemetry(toolName, params, responseLength, iteration) {
|
|
99403
|
+
if (!this.tracer) return;
|
|
99404
|
+
if (this._isAppTracerStyle() && typeof this.tracer.recordAIToolDecision === "function") {
|
|
99405
|
+
this.tracer.recordAIToolDecision(this.sessionId, iteration, toolName, params);
|
|
99406
|
+
} else if (typeof this.tracer.recordToolDecision === "function") {
|
|
99407
|
+
this.tracer.recordToolDecision(toolName, params, {
|
|
99408
|
+
iteration,
|
|
99409
|
+
"ai.tool_decision.raw_response_length": responseLength
|
|
99410
|
+
});
|
|
99411
|
+
} else {
|
|
99412
|
+
this.tracer.addEvent("ai.tool_decision", {
|
|
99413
|
+
"ai.tool_decision.name": toolName,
|
|
99414
|
+
"ai.tool_decision.params": JSON.stringify(params || {}).substring(0, 2e3),
|
|
99415
|
+
"ai.tool_decision.raw_response_length": responseLength,
|
|
99416
|
+
"iteration": iteration
|
|
99417
|
+
});
|
|
99418
|
+
}
|
|
99419
|
+
}
|
|
99420
|
+
/**
|
|
99421
|
+
* Record tool result for telemetry
|
|
99422
|
+
* @param {string} toolName - The tool name
|
|
99423
|
+
* @param {string|Object} result - Tool result
|
|
99424
|
+
* @param {boolean} success - Whether tool succeeded
|
|
99425
|
+
* @param {number} durationMs - Execution duration in milliseconds
|
|
99426
|
+
* @param {number} iteration - Current iteration number
|
|
99427
|
+
* @private
|
|
99428
|
+
*/
|
|
99429
|
+
_recordToolResultTelemetry(toolName, result, success, durationMs, iteration) {
|
|
99430
|
+
if (!this.tracer) return;
|
|
99431
|
+
if (this._isAppTracerStyle() && typeof this.tracer.recordToolResult === "function") {
|
|
99432
|
+
this.tracer.recordToolResult(this.sessionId, iteration, toolName, result, success, durationMs);
|
|
99433
|
+
} else if (typeof this.tracer.recordToolResult === "function") {
|
|
99434
|
+
this.tracer.recordToolResult(toolName, result, success, durationMs, { iteration });
|
|
99435
|
+
} else {
|
|
99436
|
+
const resultStr = typeof result === "string" ? result : JSON.stringify(result || "");
|
|
99437
|
+
this.tracer.addEvent("tool.result", {
|
|
99438
|
+
"tool.name": toolName,
|
|
99439
|
+
"tool.result": resultStr.substring(0, 1e4),
|
|
99440
|
+
"tool.result.length": resultStr.length,
|
|
99441
|
+
"tool.duration_ms": durationMs,
|
|
99442
|
+
"tool.success": success,
|
|
99443
|
+
"iteration": iteration
|
|
99444
|
+
});
|
|
99445
|
+
}
|
|
99446
|
+
}
|
|
99447
|
+
/**
|
|
99448
|
+
* Record MCP tool lifecycle event for telemetry
|
|
99449
|
+
* @param {string} phase - 'start' or 'end'
|
|
99450
|
+
* @param {string} toolName - MCP tool name
|
|
99451
|
+
* @param {Object} params - Tool parameters (for start) or null (for end)
|
|
99452
|
+
* @param {number} iteration - Current iteration number
|
|
99453
|
+
* @param {Object} [endData] - Additional data for end phase (result, success, durationMs, error)
|
|
99454
|
+
* @private
|
|
99455
|
+
*/
|
|
99456
|
+
_recordMcpToolTelemetry(phase, toolName, params, iteration, endData = null) {
|
|
99457
|
+
if (!this.tracer) return;
|
|
99458
|
+
if (phase === "start") {
|
|
99459
|
+
if (this._isAppTracerStyle() && typeof this.tracer.recordMcpToolStart === "function") {
|
|
99460
|
+
this.tracer.recordMcpToolStart(this.sessionId, iteration, toolName, "mcp", params);
|
|
99461
|
+
} else if (typeof this.tracer.recordMcpToolStart === "function") {
|
|
99462
|
+
this.tracer.recordMcpToolStart(toolName, "mcp", params, { iteration });
|
|
99463
|
+
} else {
|
|
99464
|
+
this.tracer.addEvent("mcp.tool.start", {
|
|
99465
|
+
"mcp.tool.name": toolName,
|
|
99466
|
+
"mcp.tool.server": "mcp",
|
|
99467
|
+
"mcp.tool.params": JSON.stringify(params || {}).substring(0, 2e3),
|
|
99468
|
+
"iteration": iteration
|
|
99469
|
+
});
|
|
99470
|
+
}
|
|
99471
|
+
} else if (phase === "end" && endData) {
|
|
99472
|
+
const { result, success, durationMs, error: error2 } = endData;
|
|
99473
|
+
if (this._isAppTracerStyle() && typeof this.tracer.recordMcpToolEnd === "function") {
|
|
99474
|
+
this.tracer.recordMcpToolEnd(this.sessionId, iteration, toolName, "mcp", result, success, durationMs, error2);
|
|
99475
|
+
} else if (typeof this.tracer.recordMcpToolEnd === "function") {
|
|
99476
|
+
this.tracer.recordMcpToolEnd(toolName, "mcp", result, success, durationMs, error2, { iteration });
|
|
99477
|
+
} else {
|
|
99478
|
+
const resultStr = typeof result === "string" ? result : JSON.stringify(result || "");
|
|
99479
|
+
this.tracer.addEvent("mcp.tool.end", {
|
|
99480
|
+
"mcp.tool.name": toolName,
|
|
99481
|
+
"mcp.tool.server": "mcp",
|
|
99482
|
+
"mcp.tool.result": resultStr.substring(0, 1e4),
|
|
99483
|
+
"mcp.tool.result.length": resultStr.length,
|
|
99484
|
+
"mcp.tool.duration_ms": durationMs,
|
|
99485
|
+
"mcp.tool.success": success,
|
|
99486
|
+
"mcp.tool.error": error2,
|
|
99487
|
+
"iteration": iteration
|
|
99488
|
+
});
|
|
99489
|
+
}
|
|
99490
|
+
}
|
|
99491
|
+
}
|
|
99492
|
+
/**
|
|
99493
|
+
* Record iteration lifecycle event for telemetry
|
|
99494
|
+
* @param {string} phase - 'end' (start is already handled elsewhere)
|
|
99495
|
+
* @param {number} iteration - Current iteration number
|
|
99496
|
+
* @param {Object} data - Additional iteration data
|
|
99497
|
+
* @private
|
|
99498
|
+
*/
|
|
99499
|
+
_recordIterationTelemetry(phase, iteration, data2 = {}) {
|
|
99500
|
+
if (!this.tracer) return;
|
|
99501
|
+
if (typeof this.tracer.recordIterationEvent === "function") {
|
|
99502
|
+
this.tracer.recordIterationEvent(phase, iteration, data2);
|
|
99503
|
+
} else {
|
|
99504
|
+
this.tracer.addEvent(`iteration.${phase}`, {
|
|
99505
|
+
"iteration": iteration,
|
|
99506
|
+
...data2
|
|
99507
|
+
});
|
|
99508
|
+
}
|
|
99509
|
+
}
|
|
99332
99510
|
/**
|
|
99333
99511
|
* Initialize the agent asynchronously (must be called after constructor)
|
|
99334
99512
|
* This method initializes MCP and merges MCP tools into the tool list, and loads history from storage
|
|
@@ -101283,8 +101461,12 @@ You are working with a repository located at: ${searchDirectory}
|
|
|
101283
101461
|
}
|
|
101284
101462
|
const nativeTools = validTools;
|
|
101285
101463
|
const parsedTool = this.mcpBridge && !options._disableTools ? parseHybridXmlToolCall(assistantResponseContent, nativeTools, this.mcpBridge) : parseXmlToolCallWithThinking(assistantResponseContent, validTools);
|
|
101464
|
+
if (parsedTool?.thinkingContent) {
|
|
101465
|
+
this._recordThinkingTelemetry(parsedTool.thinkingContent, currentIteration);
|
|
101466
|
+
}
|
|
101286
101467
|
if (parsedTool) {
|
|
101287
101468
|
const { toolName, params } = parsedTool;
|
|
101469
|
+
this._recordToolDecisionTelemetry(toolName, params, assistantResponseContent.length, currentIteration);
|
|
101288
101470
|
if (this.debug) console.log(`[DEBUG] Parsed tool call: ${toolName} with params:`, params);
|
|
101289
101471
|
if (toolName === "attempt_completion") {
|
|
101290
101472
|
completionAttempted = true;
|
|
@@ -101361,6 +101543,8 @@ You are working with a repository located at: ${searchDirectory}
|
|
|
101361
101543
|
} else {
|
|
101362
101544
|
const { type } = parsedTool;
|
|
101363
101545
|
if (type === "mcp" && this.mcpBridge && this.mcpBridge.isMcpTool(toolName)) {
|
|
101546
|
+
const mcpStartTime = Date.now();
|
|
101547
|
+
this._recordMcpToolTelemetry("start", toolName, params, currentIteration);
|
|
101364
101548
|
try {
|
|
101365
101549
|
if (this.debug) {
|
|
101366
101550
|
console.error(`
|
|
@@ -101390,6 +101574,13 @@ You are working with a repository located at: ${searchDirectory}
|
|
|
101390
101574
|
} catch (truncateError) {
|
|
101391
101575
|
console.error(`[WARN] Tool output truncation failed: ${truncateError.message}`);
|
|
101392
101576
|
}
|
|
101577
|
+
const mcpDurationMs = Date.now() - mcpStartTime;
|
|
101578
|
+
this._recordMcpToolTelemetry("end", toolName, null, currentIteration, {
|
|
101579
|
+
result: toolResultContent,
|
|
101580
|
+
success: true,
|
|
101581
|
+
durationMs: mcpDurationMs,
|
|
101582
|
+
error: null
|
|
101583
|
+
});
|
|
101393
101584
|
if (this.debug) {
|
|
101394
101585
|
const preview = toolResultContent.length > 500 ? toolResultContent.substring(0, 500) + "..." : toolResultContent;
|
|
101395
101586
|
console.error(`[DEBUG] ========================================`);
|
|
@@ -101403,6 +101594,13 @@ You are working with a repository located at: ${searchDirectory}
|
|
|
101403
101594
|
${toolResultContent}
|
|
101404
101595
|
</tool_result>` });
|
|
101405
101596
|
} catch (error2) {
|
|
101597
|
+
const mcpDurationMs = Date.now() - mcpStartTime;
|
|
101598
|
+
this._recordMcpToolTelemetry("end", toolName, null, currentIteration, {
|
|
101599
|
+
result: null,
|
|
101600
|
+
success: false,
|
|
101601
|
+
durationMs: mcpDurationMs,
|
|
101602
|
+
error: error2.message
|
|
101603
|
+
});
|
|
101406
101604
|
console.error(`Error executing MCP tool ${toolName}:`, error2);
|
|
101407
101605
|
if (this.debug) {
|
|
101408
101606
|
console.error(`[DEBUG] ========================================`);
|
|
@@ -101494,6 +101692,7 @@ ${errorXml}
|
|
|
101494
101692
|
return await this.toolImplementations[toolName].execute(toolParams);
|
|
101495
101693
|
};
|
|
101496
101694
|
let toolResult;
|
|
101695
|
+
const toolStartTime = Date.now();
|
|
101497
101696
|
try {
|
|
101498
101697
|
if (this.tracer) {
|
|
101499
101698
|
toolResult = await this.tracer.withSpan("tool.call", executeToolCall, {
|
|
@@ -101504,6 +101703,8 @@ ${errorXml}
|
|
|
101504
101703
|
} else {
|
|
101505
101704
|
toolResult = await executeToolCall();
|
|
101506
101705
|
}
|
|
101706
|
+
const toolDurationMs = Date.now() - toolStartTime;
|
|
101707
|
+
this._recordToolResultTelemetry(toolName, toolResult, true, toolDurationMs, currentIteration);
|
|
101507
101708
|
if (this.debug) {
|
|
101508
101709
|
const resultPreview = typeof toolResult === "string" ? toolResult.length > 500 ? toolResult.substring(0, 500) + "..." : toolResult : toolResult ? JSON.stringify(toolResult, null, 2).substring(0, 500) + "..." : "No Result";
|
|
101509
101710
|
console.error(`[DEBUG] ========================================`);
|
|
@@ -101560,6 +101761,20 @@ ${toolResultContent}
|
|
|
101560
101761
|
role: "user",
|
|
101561
101762
|
content: toolResultMessage
|
|
101562
101763
|
});
|
|
101764
|
+
if (this.tracer) {
|
|
101765
|
+
if (typeof this.tracer.recordConversationTurn === "function") {
|
|
101766
|
+
this.tracer.recordConversationTurn("assistant", assistantResponseContent, {
|
|
101767
|
+
iteration: currentIteration,
|
|
101768
|
+
has_tool_call: true,
|
|
101769
|
+
tool_name: toolName
|
|
101770
|
+
});
|
|
101771
|
+
this.tracer.recordConversationTurn("tool_result", toolResultContent, {
|
|
101772
|
+
iteration: currentIteration,
|
|
101773
|
+
tool_name: toolName,
|
|
101774
|
+
tool_success: true
|
|
101775
|
+
});
|
|
101776
|
+
}
|
|
101777
|
+
}
|
|
101563
101778
|
if (this.debug) {
|
|
101564
101779
|
console.log(`[DEBUG] Tool ${toolName} executed successfully. Result length: ${typeof toolResult === "string" ? toolResult.length : JSON.stringify(toolResult).length}`);
|
|
101565
101780
|
}
|
|
@@ -101630,6 +101845,7 @@ ${errorXml}
|
|
|
101630
101845
|
if (this.debug) {
|
|
101631
101846
|
console.log(`[DEBUG] Detected wrapped tool '${wrappedToolName}' in assistant response - wrong XML format.`);
|
|
101632
101847
|
}
|
|
101848
|
+
this._recordErrorTelemetry("wrapped_tool", "Tool call wrapped in markdown", { toolName: wrappedToolName }, currentIteration);
|
|
101633
101849
|
const toolError = new ParameterError(
|
|
101634
101850
|
`Tool '${wrappedToolName}' found but in WRONG FORMAT - do not wrap tools in other XML tags.`,
|
|
101635
101851
|
{
|
|
@@ -101655,6 +101871,7 @@ ${formatErrorForAI(toolError)}
|
|
|
101655
101871
|
if (this.debug) {
|
|
101656
101872
|
console.log(`[DEBUG] Detected unrecognized tool '${unrecognizedTool}' in assistant response.`);
|
|
101657
101873
|
}
|
|
101874
|
+
this._recordErrorTelemetry("unrecognized_tool", `Unknown tool: ${unrecognizedTool}`, { toolName: unrecognizedTool, validTools }, currentIteration);
|
|
101658
101875
|
const toolError = new ParameterError(`Tool '${unrecognizedTool}' is not available in this context.`, {
|
|
101659
101876
|
suggestion: `Available tools: ${validTools.join(", ")}. Please use one of these tools instead.`
|
|
101660
101877
|
});
|
|
@@ -101662,6 +101879,7 @@ ${formatErrorForAI(toolError)}
|
|
|
101662
101879
|
${formatErrorForAI(toolError)}
|
|
101663
101880
|
</tool_result>`;
|
|
101664
101881
|
} else {
|
|
101882
|
+
this._recordErrorTelemetry("no_tool_call", "AI response did not contain tool call", { responsePreview: assistantResponseContent.substring(0, 500) }, currentIteration);
|
|
101665
101883
|
if (currentIteration >= maxIterations) {
|
|
101666
101884
|
let cleanedResponse = assistantResponseContent;
|
|
101667
101885
|
cleanedResponse = cleanedResponse.replace(/<thinking>[\s\S]*?<\/thinking>/gi, "").trim();
|
|
@@ -101737,6 +101955,7 @@ Note: <attempt_complete></attempt_complete> reuses your PREVIOUS assistant messa
|
|
|
101737
101955
|
sameFormatErrorCount++;
|
|
101738
101956
|
if (sameFormatErrorCount >= MAX_REPEATED_FORMAT_ERRORS) {
|
|
101739
101957
|
const errorDesc = isWrapped ? "wrapped tool format" : unrecognizedTool;
|
|
101958
|
+
this._recordErrorTelemetry("circuit_breaker", "Format error limit exceeded", { formatErrorCount: sameFormatErrorCount, errorCategory }, currentIteration);
|
|
101740
101959
|
console.error(`[ERROR] Format error category '${errorCategory}' repeated ${sameFormatErrorCount} times. Breaking loop early to prevent infinite iteration.`);
|
|
101741
101960
|
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.`;
|
|
101742
101961
|
break;
|
|
@@ -101750,6 +101969,10 @@ Note: <attempt_complete></attempt_complete> reuses your PREVIOUS assistant messa
|
|
|
101750
101969
|
sameFormatErrorCount = 0;
|
|
101751
101970
|
}
|
|
101752
101971
|
}
|
|
101972
|
+
this._recordIterationTelemetry("end", currentIteration, {
|
|
101973
|
+
"iteration.completed": completionAttempted,
|
|
101974
|
+
"iteration.message_count": currentMessages.length
|
|
101975
|
+
});
|
|
101753
101976
|
if (currentMessages.length > MAX_HISTORY_MESSAGES) {
|
|
101754
101977
|
const messagesBefore = currentMessages.length;
|
|
101755
101978
|
const systemMsg = currentMessages[0];
|