@probelabs/probe 0.6.0-rc296 → 0.6.0-rc298

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.
@@ -118,6 +118,38 @@ export interface ProbeAgentOptions {
118
118
  negotiatedTimeoutMaxPerRequest?: number;
119
119
  }
120
120
 
121
+ /**
122
+ * Emitted when the negotiated timeout observer grants a time extension.
123
+ * Parent processes should listen to this event and extend their own deadlines accordingly.
124
+ */
125
+ export interface TimeoutExtendedEvent {
126
+ /** Duration of the granted extension in milliseconds */
127
+ grantedMs: number;
128
+ /** Reason the observer granted the extension */
129
+ reason: string;
130
+ /** Number of extensions used so far */
131
+ extensionsUsed: number;
132
+ /** Number of extensions remaining */
133
+ extensionsRemaining: number;
134
+ /** Total extra time granted across all extensions in ms */
135
+ totalExtraTimeMs: number;
136
+ /** Remaining budget for future extensions in ms */
137
+ budgetRemainingMs: number;
138
+ }
139
+
140
+ /**
141
+ * Emitted when the negotiated timeout observer declines an extension and begins wind-down.
142
+ * After this event, the agent will produce its final answer and no more extensions will be granted.
143
+ */
144
+ export interface TimeoutWindingDownEvent {
145
+ /** Reason the observer declined the extension */
146
+ reason: string;
147
+ /** Number of extensions used before declining */
148
+ extensionsUsed: number;
149
+ /** Total extra time granted across all extensions in ms */
150
+ totalExtraTimeMs: number;
151
+ }
152
+
121
153
  /**
122
154
  * Tool execution event data
123
155
  */
@@ -2759,7 +2759,7 @@ export class ProbeAgent {
2759
2759
  }
2760
2760
 
2761
2761
  // Initialize the MCP XML bridge
2762
- this.mcpBridge = new MCPXmlBridge({ debug: this.debug });
2762
+ this.mcpBridge = new MCPXmlBridge({ debug: this.debug, agentEvents: this.events });
2763
2763
  await this.mcpBridge.initialize(mcpConfig);
2764
2764
 
2765
2765
  const mcpToolNames = this.mcpBridge.getToolNames();
@@ -3847,6 +3847,18 @@ or
3847
3847
  active_tools_count: activeToolsList.length,
3848
3848
  });
3849
3849
  }
3850
+
3851
+ // Notify the parent that the agent extended its timeout (#522).
3852
+ // The parent can listen to this event and extend its own deadline
3853
+ // (e.g., adjust Promise.race timeout) instead of killing the agent.
3854
+ this.events.emit('timeout.extended', {
3855
+ grantedMs,
3856
+ reason: decision.reason || 'work in progress',
3857
+ extensionsUsed: negotiatedTimeoutState.extensionsUsed,
3858
+ extensionsRemaining: negotiatedTimeoutState.maxRequests - negotiatedTimeoutState.extensionsUsed,
3859
+ totalExtraTimeMs: negotiatedTimeoutState.totalExtraTimeMs,
3860
+ budgetRemainingMs: remainingBudgetMs - grantedMs,
3861
+ });
3850
3862
  } else {
3851
3863
  // Observer decided not to extend — two-phase graceful stop
3852
3864
  if (this.debug) {
@@ -3863,6 +3875,13 @@ or
3863
3875
  });
3864
3876
  }
3865
3877
 
3878
+ // Notify the parent that the agent is winding down — no more extensions (#522)
3879
+ this.events.emit('timeout.windingDown', {
3880
+ reason: decision.reason || 'observer declined',
3881
+ extensionsUsed: negotiatedTimeoutState.extensionsUsed,
3882
+ totalExtraTimeMs: negotiatedTimeoutState.totalExtraTimeMs,
3883
+ });
3884
+
3866
3885
  await this._initiateGracefulStop(gracefulTimeoutState, `observer declined: ${decision.reason}`);
3867
3886
  }
3868
3887
  };
@@ -164,6 +164,8 @@ export class MCPClientManager {
164
164
  this.debug = options.debug || process.env.DEBUG_MCP === '1';
165
165
  this.config = null;
166
166
  this.tracer = options.tracer || null;
167
+ // Optional event emitter for broadcasting tool call lifecycle to the agent (#522)
168
+ this.agentEvents = options.agentEvents || null;
167
169
  }
168
170
 
169
171
  /**
@@ -452,6 +454,7 @@ export class MCPClientManager {
452
454
  }
453
455
 
454
456
  const startTime = Date.now();
457
+ const toolCallId = `mcp-${toolName}-${startTime}`;
455
458
 
456
459
  // Record tool call start
457
460
  this.recordMcpEvent('tool.call_started', {
@@ -460,6 +463,17 @@ export class MCPClientManager {
460
463
  originalToolName: tool.originalName
461
464
  });
462
465
 
466
+ // Emit toolCall event so the agent's activeTools map tracks MCP tool calls (#522)
467
+ if (this.agentEvents) {
468
+ this.agentEvents.emit('toolCall', {
469
+ toolCallId,
470
+ name: toolName,
471
+ args,
472
+ status: 'started',
473
+ timestamp: new Date().toISOString(),
474
+ });
475
+ }
476
+
463
477
  try {
464
478
  if (this.debug) {
465
479
  console.error(`[MCP DEBUG] Calling ${toolName} with args:`, JSON.stringify(args, null, 2));
@@ -502,6 +516,16 @@ export class MCPClientManager {
502
516
  durationMs
503
517
  });
504
518
 
519
+ // Emit toolCall completion so agent's activeTools removes this entry (#522)
520
+ if (this.agentEvents) {
521
+ this.agentEvents.emit('toolCall', {
522
+ toolCallId,
523
+ name: toolName,
524
+ status: 'completed',
525
+ timestamp: new Date().toISOString(),
526
+ });
527
+ }
528
+
505
529
  return result;
506
530
  } catch (error) {
507
531
  const durationMs = Date.now() - startTime;
@@ -521,6 +545,16 @@ export class MCPClientManager {
521
545
  isTimeout: error.message.includes('timeout')
522
546
  });
523
547
 
548
+ // Emit toolCall error so agent's activeTools removes this entry (#522)
549
+ if (this.agentEvents) {
550
+ this.agentEvents.emit('toolCall', {
551
+ toolCallId,
552
+ name: toolName,
553
+ status: 'error',
554
+ timestamp: new Date().toISOString(),
555
+ });
556
+ }
557
+
524
558
  throw error;
525
559
  }
526
560
  }
@@ -36,6 +36,7 @@ export class MCPXmlBridge {
36
36
  constructor(options = {}) {
37
37
  this.debug = options.debug || false;
38
38
  this.tracer = options.tracer || null;
39
+ this.agentEvents = options.agentEvents || null;
39
40
  this.mcpTools = {};
40
41
  this.mcpManager = null;
41
42
  this.toolDescriptions = {};
@@ -84,7 +85,7 @@ export class MCPXmlBridge {
84
85
  console.error('[MCP DEBUG] Initializing MCP client manager...');
85
86
  }
86
87
 
87
- this.mcpManager = new MCPClientManager({ debug: this.debug, tracer: this.tracer });
88
+ this.mcpManager = new MCPClientManager({ debug: this.debug, tracer: this.tracer, agentEvents: this.agentEvents });
88
89
  const result = await this.mcpManager.initialize(mcpConfigs);
89
90
 
90
91
  // Get tools from the manager (already in Vercel format)