@probelabs/probe 0.6.0-rc223 → 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-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 +421 -8
- package/build/agent/mcp/xmlBridge.js +10 -7
- package/build/agent/simpleTelemetry.js +198 -0
- package/build/agent/tools.js +8 -5
- package/build/delegate.js +17 -0
- package/cjs/agent/ProbeAgent.cjs +244 -8
- package/cjs/agent/simpleTelemetry.cjs +177 -0
- package/cjs/index.cjs +421 -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/src/delegate.js +17 -0
- package/bin/binaries/probe-v0.6.0-rc223-aarch64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc223-aarch64-unknown-linux-musl.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc223-x86_64-apple-darwin.tar.gz +0 -0
- package/bin/binaries/probe-v0.6.0-rc223-x86_64-pc-windows-msvc.zip +0 -0
- package/bin/binaries/probe-v0.6.0-rc223-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/build/delegate.js
CHANGED
|
@@ -385,6 +385,23 @@ export async function delegate({
|
|
|
385
385
|
throw new Error('Task parameter is required and must be a string');
|
|
386
386
|
}
|
|
387
387
|
|
|
388
|
+
// Support runtime timeout override via environment variables when timeout not explicitly passed
|
|
389
|
+
// This allows operators to configure delegation timeouts without code changes
|
|
390
|
+
// Priority: DELEGATION_TIMEOUT_MS (milliseconds) > DELEGATION_TIMEOUT_SECONDS > DELEGATION_TIMEOUT (seconds)
|
|
391
|
+
const hasExplicitTimeout = Object.prototype.hasOwnProperty.call(arguments?.[0] ?? {}, 'timeout');
|
|
392
|
+
if (!hasExplicitTimeout) {
|
|
393
|
+
const envTimeoutMs = parseInt(process.env.DELEGATION_TIMEOUT_MS || '', 10);
|
|
394
|
+
const envTimeoutSeconds = parseInt(
|
|
395
|
+
process.env.DELEGATION_TIMEOUT_SECONDS || process.env.DELEGATION_TIMEOUT || '',
|
|
396
|
+
10
|
|
397
|
+
);
|
|
398
|
+
if (!Number.isNaN(envTimeoutMs) && envTimeoutMs > 0) {
|
|
399
|
+
timeout = Math.max(1, Math.ceil(envTimeoutMs / 1000));
|
|
400
|
+
} else if (!Number.isNaN(envTimeoutSeconds) && envTimeoutSeconds > 0) {
|
|
401
|
+
timeout = Math.max(1, envTimeoutSeconds);
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
|
|
388
405
|
// Use provided manager or fall back to default singleton
|
|
389
406
|
const manager = delegationManager || defaultDelegationManager;
|
|
390
407
|
|
package/cjs/agent/ProbeAgent.cjs
CHANGED
|
@@ -33164,6 +33164,19 @@ async function delegate({
|
|
|
33164
33164
|
if (!task || typeof task !== "string") {
|
|
33165
33165
|
throw new Error("Task parameter is required and must be a string");
|
|
33166
33166
|
}
|
|
33167
|
+
const hasExplicitTimeout = Object.prototype.hasOwnProperty.call(arguments?.[0] ?? {}, "timeout");
|
|
33168
|
+
if (!hasExplicitTimeout) {
|
|
33169
|
+
const envTimeoutMs = parseInt(process.env.DELEGATION_TIMEOUT_MS || "", 10);
|
|
33170
|
+
const envTimeoutSeconds = parseInt(
|
|
33171
|
+
process.env.DELEGATION_TIMEOUT_SECONDS || process.env.DELEGATION_TIMEOUT || "",
|
|
33172
|
+
10
|
|
33173
|
+
);
|
|
33174
|
+
if (!Number.isNaN(envTimeoutMs) && envTimeoutMs > 0) {
|
|
33175
|
+
timeout = Math.max(1, Math.ceil(envTimeoutMs / 1e3));
|
|
33176
|
+
} else if (!Number.isNaN(envTimeoutSeconds) && envTimeoutSeconds > 0) {
|
|
33177
|
+
timeout = Math.max(1, envTimeoutSeconds);
|
|
33178
|
+
}
|
|
33179
|
+
}
|
|
33167
33180
|
const manager = delegationManager || defaultDelegationManager;
|
|
33168
33181
|
const sessionId = (0, import_crypto2.randomUUID)();
|
|
33169
33182
|
const startTime = Date.now();
|
|
@@ -49538,11 +49551,12 @@ function createTools(configOptions) {
|
|
|
49538
49551
|
return tools2;
|
|
49539
49552
|
}
|
|
49540
49553
|
function parseXmlToolCallWithThinking(xmlString, validTools) {
|
|
49541
|
-
const { cleanedXmlString, recoveryResult } = processXmlWithThinkingAndRecovery(xmlString, validTools);
|
|
49554
|
+
const { cleanedXmlString, recoveryResult, thinkingContent } = processXmlWithThinkingAndRecovery(xmlString, validTools);
|
|
49542
49555
|
if (recoveryResult) {
|
|
49543
|
-
return recoveryResult;
|
|
49556
|
+
return { ...recoveryResult, thinkingContent };
|
|
49544
49557
|
}
|
|
49545
|
-
|
|
49558
|
+
const toolCall = parseXmlToolCall(cleanedXmlString, validTools);
|
|
49559
|
+
return toolCall ? { ...toolCall, thinkingContent } : null;
|
|
49546
49560
|
}
|
|
49547
49561
|
var import_crypto4, implementToolDefinition, listFilesToolDefinition, searchFilesToolDefinition, listSkillsToolDefinition, useSkillToolDefinition, readImageToolDefinition;
|
|
49548
49562
|
var init_tools2 = __esm({
|
|
@@ -88837,25 +88851,27 @@ function parseXmlMcpToolCall(xmlString, mcpToolNames = []) {
|
|
|
88837
88851
|
function parseHybridXmlToolCall(xmlString, nativeTools = [], mcpBridge = null) {
|
|
88838
88852
|
const nativeResult = parseNativeXmlToolWithThinking(xmlString, nativeTools);
|
|
88839
88853
|
if (nativeResult) {
|
|
88840
|
-
|
|
88854
|
+
const { thinkingContent, ...rest } = nativeResult;
|
|
88855
|
+
return { ...rest, type: "native", thinkingContent };
|
|
88841
88856
|
}
|
|
88842
88857
|
if (mcpBridge) {
|
|
88843
88858
|
const mcpResult = parseXmlMcpToolCall(xmlString, mcpBridge.getToolNames());
|
|
88844
88859
|
if (mcpResult) {
|
|
88845
|
-
|
|
88860
|
+
const { thinkingContent } = processXmlWithThinkingAndRecovery(xmlString, []);
|
|
88861
|
+
return { ...mcpResult, type: "mcp", thinkingContent };
|
|
88846
88862
|
}
|
|
88847
88863
|
}
|
|
88848
88864
|
return null;
|
|
88849
88865
|
}
|
|
88850
88866
|
function parseNativeXmlToolWithThinking(xmlString, validTools) {
|
|
88851
|
-
const { cleanedXmlString, recoveryResult } = processXmlWithThinkingAndRecovery(xmlString, validTools);
|
|
88867
|
+
const { cleanedXmlString, recoveryResult, thinkingContent } = processXmlWithThinkingAndRecovery(xmlString, validTools);
|
|
88852
88868
|
if (recoveryResult) {
|
|
88853
|
-
return recoveryResult;
|
|
88869
|
+
return { ...recoveryResult, thinkingContent };
|
|
88854
88870
|
}
|
|
88855
88871
|
for (const toolName of validTools) {
|
|
88856
88872
|
const result = parseNativeXmlTool(cleanedXmlString, toolName);
|
|
88857
88873
|
if (result) {
|
|
88858
|
-
return result;
|
|
88874
|
+
return { ...result, thinkingContent };
|
|
88859
88875
|
}
|
|
88860
88876
|
}
|
|
88861
88877
|
return null;
|
|
@@ -99316,6 +99332,181 @@ var init_ProbeAgent = __esm({
|
|
|
99316
99332
|
_filterMcpTools(mcpToolNames) {
|
|
99317
99333
|
return mcpToolNames.filter((toolName) => this._isMcpToolAllowed(toolName));
|
|
99318
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
|
+
}
|
|
99319
99510
|
/**
|
|
99320
99511
|
* Initialize the agent asynchronously (must be called after constructor)
|
|
99321
99512
|
* This method initializes MCP and merges MCP tools into the tool list, and loads history from storage
|
|
@@ -101270,8 +101461,12 @@ You are working with a repository located at: ${searchDirectory}
|
|
|
101270
101461
|
}
|
|
101271
101462
|
const nativeTools = validTools;
|
|
101272
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
|
+
}
|
|
101273
101467
|
if (parsedTool) {
|
|
101274
101468
|
const { toolName, params } = parsedTool;
|
|
101469
|
+
this._recordToolDecisionTelemetry(toolName, params, assistantResponseContent.length, currentIteration);
|
|
101275
101470
|
if (this.debug) console.log(`[DEBUG] Parsed tool call: ${toolName} with params:`, params);
|
|
101276
101471
|
if (toolName === "attempt_completion") {
|
|
101277
101472
|
completionAttempted = true;
|
|
@@ -101348,6 +101543,8 @@ You are working with a repository located at: ${searchDirectory}
|
|
|
101348
101543
|
} else {
|
|
101349
101544
|
const { type } = parsedTool;
|
|
101350
101545
|
if (type === "mcp" && this.mcpBridge && this.mcpBridge.isMcpTool(toolName)) {
|
|
101546
|
+
const mcpStartTime = Date.now();
|
|
101547
|
+
this._recordMcpToolTelemetry("start", toolName, params, currentIteration);
|
|
101351
101548
|
try {
|
|
101352
101549
|
if (this.debug) {
|
|
101353
101550
|
console.error(`
|
|
@@ -101377,6 +101574,13 @@ You are working with a repository located at: ${searchDirectory}
|
|
|
101377
101574
|
} catch (truncateError) {
|
|
101378
101575
|
console.error(`[WARN] Tool output truncation failed: ${truncateError.message}`);
|
|
101379
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
|
+
});
|
|
101380
101584
|
if (this.debug) {
|
|
101381
101585
|
const preview = toolResultContent.length > 500 ? toolResultContent.substring(0, 500) + "..." : toolResultContent;
|
|
101382
101586
|
console.error(`[DEBUG] ========================================`);
|
|
@@ -101390,6 +101594,13 @@ You are working with a repository located at: ${searchDirectory}
|
|
|
101390
101594
|
${toolResultContent}
|
|
101391
101595
|
</tool_result>` });
|
|
101392
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
|
+
});
|
|
101393
101604
|
console.error(`Error executing MCP tool ${toolName}:`, error2);
|
|
101394
101605
|
if (this.debug) {
|
|
101395
101606
|
console.error(`[DEBUG] ========================================`);
|
|
@@ -101481,6 +101692,7 @@ ${errorXml}
|
|
|
101481
101692
|
return await this.toolImplementations[toolName].execute(toolParams);
|
|
101482
101693
|
};
|
|
101483
101694
|
let toolResult;
|
|
101695
|
+
const toolStartTime = Date.now();
|
|
101484
101696
|
try {
|
|
101485
101697
|
if (this.tracer) {
|
|
101486
101698
|
toolResult = await this.tracer.withSpan("tool.call", executeToolCall, {
|
|
@@ -101491,6 +101703,8 @@ ${errorXml}
|
|
|
101491
101703
|
} else {
|
|
101492
101704
|
toolResult = await executeToolCall();
|
|
101493
101705
|
}
|
|
101706
|
+
const toolDurationMs = Date.now() - toolStartTime;
|
|
101707
|
+
this._recordToolResultTelemetry(toolName, toolResult, true, toolDurationMs, currentIteration);
|
|
101494
101708
|
if (this.debug) {
|
|
101495
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";
|
|
101496
101710
|
console.error(`[DEBUG] ========================================`);
|
|
@@ -101547,6 +101761,20 @@ ${toolResultContent}
|
|
|
101547
101761
|
role: "user",
|
|
101548
101762
|
content: toolResultMessage
|
|
101549
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
|
+
}
|
|
101550
101778
|
if (this.debug) {
|
|
101551
101779
|
console.log(`[DEBUG] Tool ${toolName} executed successfully. Result length: ${typeof toolResult === "string" ? toolResult.length : JSON.stringify(toolResult).length}`);
|
|
101552
101780
|
}
|
|
@@ -101617,6 +101845,7 @@ ${errorXml}
|
|
|
101617
101845
|
if (this.debug) {
|
|
101618
101846
|
console.log(`[DEBUG] Detected wrapped tool '${wrappedToolName}' in assistant response - wrong XML format.`);
|
|
101619
101847
|
}
|
|
101848
|
+
this._recordErrorTelemetry("wrapped_tool", "Tool call wrapped in markdown", { toolName: wrappedToolName }, currentIteration);
|
|
101620
101849
|
const toolError = new ParameterError(
|
|
101621
101850
|
`Tool '${wrappedToolName}' found but in WRONG FORMAT - do not wrap tools in other XML tags.`,
|
|
101622
101851
|
{
|
|
@@ -101642,6 +101871,7 @@ ${formatErrorForAI(toolError)}
|
|
|
101642
101871
|
if (this.debug) {
|
|
101643
101872
|
console.log(`[DEBUG] Detected unrecognized tool '${unrecognizedTool}' in assistant response.`);
|
|
101644
101873
|
}
|
|
101874
|
+
this._recordErrorTelemetry("unrecognized_tool", `Unknown tool: ${unrecognizedTool}`, { toolName: unrecognizedTool, validTools }, currentIteration);
|
|
101645
101875
|
const toolError = new ParameterError(`Tool '${unrecognizedTool}' is not available in this context.`, {
|
|
101646
101876
|
suggestion: `Available tools: ${validTools.join(", ")}. Please use one of these tools instead.`
|
|
101647
101877
|
});
|
|
@@ -101649,6 +101879,7 @@ ${formatErrorForAI(toolError)}
|
|
|
101649
101879
|
${formatErrorForAI(toolError)}
|
|
101650
101880
|
</tool_result>`;
|
|
101651
101881
|
} else {
|
|
101882
|
+
this._recordErrorTelemetry("no_tool_call", "AI response did not contain tool call", { responsePreview: assistantResponseContent.substring(0, 500) }, currentIteration);
|
|
101652
101883
|
if (currentIteration >= maxIterations) {
|
|
101653
101884
|
let cleanedResponse = assistantResponseContent;
|
|
101654
101885
|
cleanedResponse = cleanedResponse.replace(/<thinking>[\s\S]*?<\/thinking>/gi, "").trim();
|
|
@@ -101724,6 +101955,7 @@ Note: <attempt_complete></attempt_complete> reuses your PREVIOUS assistant messa
|
|
|
101724
101955
|
sameFormatErrorCount++;
|
|
101725
101956
|
if (sameFormatErrorCount >= MAX_REPEATED_FORMAT_ERRORS) {
|
|
101726
101957
|
const errorDesc = isWrapped ? "wrapped tool format" : unrecognizedTool;
|
|
101958
|
+
this._recordErrorTelemetry("circuit_breaker", "Format error limit exceeded", { formatErrorCount: sameFormatErrorCount, errorCategory }, currentIteration);
|
|
101727
101959
|
console.error(`[ERROR] Format error category '${errorCategory}' repeated ${sameFormatErrorCount} times. Breaking loop early to prevent infinite iteration.`);
|
|
101728
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.`;
|
|
101729
101961
|
break;
|
|
@@ -101737,6 +101969,10 @@ Note: <attempt_complete></attempt_complete> reuses your PREVIOUS assistant messa
|
|
|
101737
101969
|
sameFormatErrorCount = 0;
|
|
101738
101970
|
}
|
|
101739
101971
|
}
|
|
101972
|
+
this._recordIterationTelemetry("end", currentIteration, {
|
|
101973
|
+
"iteration.completed": completionAttempted,
|
|
101974
|
+
"iteration.message_count": currentMessages.length
|
|
101975
|
+
});
|
|
101740
101976
|
if (currentMessages.length > MAX_HISTORY_MESSAGES) {
|
|
101741
101977
|
const messagesBefore = currentMessages.length;
|
|
101742
101978
|
const systemMsg = currentMessages[0];
|