Remove silent timeout fallback - implement explicit timeout handling

- Removed hidden 300-second default timeout that created unpredictable behavior
- Tool now waits indefinitely if no timeout specified (explicit behavior)
- When timeout IS provided via params.timeout, uses that value exactly
- Tool overrides can still configure workspace-specific timeouts as before
- No more silent fallbacks - behavior is now explicit and predictable
This commit is contained in:
B Harper
2025-10-25 11:43:35 +11:00
parent d846f0895b
commit a19312c2df
2 changed files with 25 additions and 22 deletions
+2 -2
View File
@@ -7,11 +7,11 @@
[X] There should be an SSE sent to website when chat is named to force it to update the name.
[X] Consider reminding AI to allways use this method for replies in each response unless some keyword is included - we can add this to the outgoing chat messages and just strip it from what we show in the chat log?
[X] We should look for and exlude and tool named "example_custom_tool" from the /tools endpoint as it should not be advertised as a real tool to the AI
[X] The updates / overrides seem to be advertised @ /tools though the Configure tools screen on vs code doesnt show that the new description - the ai reports when asked the original description not one recently read in by the reload override method - look here for possible help: https://code.visualstudio.com/blogs/2025/05/12/agent-mode-meets-mcp - FIXED: Implemented onDidChangeMcpServerDefinitions event system to trigger VS Code tool refresh on override file changes and startup
[ ] The updates / overrides seem to be advertised @ /tools though the Configure tools screen on vs code doesnt show that the new description.
[X] The message formatting from the ai, cariagge returns etc are not observed by the website - its just a big string in one paragraph. Can we fix this? AI message formatting looks fine in vscode interface. WEB INTERFACE STILL SHOWS EVERYTHING ON ONE LINE.
[X] When sending a message from VS code it looses some history of the chat - seems to keep its own messages but looses old ai agent messages and any from the web client.
[ ] Consider how a user might also interact from their mobile phone. Dont want to do port forwarding and setting up web servers etc. How about using telegram as an interface - could this work? Look into it.
[ ] Would be great if I could paste in an image or screen shot - Copilot agent allows this in the vscode plugin.
[ ] put an option in the MCP.json and the global setup to change the default timout to a new value
[X] put an option in the MCP.json and the global setup to change the default timout to a new value - FIXED: Removed silent 300-second fallback, now waits indefinitely if no timeout specified, or uses explicit timeout from tool params/overrides
[X] Getting chat friendly name on startup seems to be failing "[Extension Host] Failed to restore session name: TypeError: fetch failed (at console.<anonymous> (file:///Applications/Visual%20Studio%20Code.app/Contents/Resources/app/out/vs/workbench/api/node/extensionHostProcess.js:203:32117))" - FIXED: Moved session name restoration to after server startup with retry logic
[ ] Publish Extension - WHEN ALL ELSE IS DONE!
+23 -20
View File
@@ -1677,8 +1677,8 @@ export class McpServer extends EventEmitter {
private async handleHumanAgentChatTool(messageId: string, params: HumanAgentChatToolParams, sessionId?: string, toolName?: string): Promise<McpMessage> {
this.debugLogger.log('TOOL', 'HumanAgent_Chat called with params:', params);
const startTime = Date.now();
const timeout = (params.timeout || 300) * 1000; // Convert to milliseconds
this.debugLogger.log('TOOL', `Using timeout: ${timeout}ms (${timeout/1000}s)`);
const timeoutMs = params.timeout ? params.timeout * 1000 : null; // Convert to milliseconds or null for no timeout
this.debugLogger.log('TOOL', `Using timeout: ${timeoutMs ? `${timeoutMs}ms (${timeoutMs/1000}s)` : 'no timeout (wait indefinitely)'}`);
// Generate unique request ID for tracking this specific request
const requestId = `${messageId}-${Date.now()}`;
@@ -1690,23 +1690,26 @@ export class McpServer extends EventEmitter {
// Wait for human response
return new Promise((resolve) => {
// Set up timeout
const timeoutHandle = setTimeout(() => {
// Remove from ChatManager - find which session it belongs to
const pendingRequestInfo = this.chatManager.findPendingRequest(requestId);
if (pendingRequestInfo) {
this.chatManager.removePendingRequest(pendingRequestInfo.sessionId, requestId);
}
this.debugLogger.log('TOOL', `Request ${requestId} timed out after ${timeout/1000}s`);
resolve({
id: messageId,
type: 'response',
error: {
code: -32603,
message: `Human response timeout after ${params.timeout || 300} seconds`
// Set up timeout only if specified
let timeoutHandle: NodeJS.Timeout | null = null;
if (timeoutMs) {
timeoutHandle = setTimeout(() => {
// Remove from ChatManager - find which session it belongs to
const pendingRequestInfo = this.chatManager.findPendingRequest(requestId);
if (pendingRequestInfo) {
this.chatManager.removePendingRequest(pendingRequestInfo.sessionId, requestId);
}
});
}, timeout);
this.debugLogger.log('TOOL', `Request ${requestId} timed out after ${timeoutMs/1000}s`);
resolve({
id: messageId,
type: 'response',
error: {
code: -32603,
message: `Human response timeout after ${params.timeout} seconds`
}
});
}, timeoutMs);
}
// Store the pending request using the extracted session ID
const sessionToUse = sessionId || params.sessionId || 'default';
@@ -1737,7 +1740,7 @@ export class McpServer extends EventEmitter {
this.chatManager.addPendingRequest(sessionToUse, requestId, { ...params, toolName: toolName || 'HumanAgent_Chat' });
this.requestResolvers.set(requestId, {
resolve: (response: string) => {
clearTimeout(timeoutHandle);
if (timeoutHandle) { clearTimeout(timeoutHandle); }
const responseTime = Date.now() - startTime;
this.debugLogger.log('TOOL', `Request ${requestId} completed with response:`, response);
@@ -1768,7 +1771,7 @@ export class McpServer extends EventEmitter {
});
},
reject: (error: Error) => {
clearTimeout(timeoutHandle);
if (timeoutHandle) { clearTimeout(timeoutHandle); }
this.debugLogger.log('TOOL', `Request ${requestId} rejected:`, error);
resolve({
id: messageId,