feat: Add reconnection backoff, server start notifications, issue reporting, improved README

- Implement exponential backoff for SSE reconnection (1s → 30s max, no timeout)
- Update connection status indicator (green/orange/red dot)
- Reset backoff and reconnect immediately when server manually started
- Add Report Issue and Request Feature options to cog menu
- Add bugs field to package.json for native VS Code issue reporting
- Improve README with actual usage instructions and troubleshooting
- Fix status indicator to update properly on disconnect
- Close EventSource to prevent browser auto-reconnect interference
This commit is contained in:
B Harper
2025-11-20 12:06:50 +11:00
parent 78fbceb3f7
commit 9bfce15f44
11 changed files with 518 additions and 55 deletions
Vendored
BIN
View File
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 379 KiB

+68 -8
View File
@@ -1,13 +1,73 @@
# What
This extension provides VSCode Github Copilot Aagent a `HumanAgent_Chat` MCP tool that forces AI assistants to communicate through a human agent instead of giving direct responses. When an AI uses this tool, it opens a chat session where humans can respond in real-time.
# HumanAgent MCP
## Why
The AI Agent is encouraged to discuss with you before running off to do its own thing - if its part way through iterating through on a problem it can stop and ask you a question - it reduces requests considerably, helps avoid runaway agent, allows you to manage multiple VSCode agents working in multiple workspaces from one web page. Allows you to append useful reminders to each response.
Forces GitHub Copilot to chat with you before acting. Stops runaway agents, reduces wasted API calls, lets you manage multiple workspaces from one interface.
## How it works
Just install it and its ready to go.
For more information see https://github.com/3DTek-xyz/HumanAgent-MCP/blob/master/README-Additional.md
## Installation
1. Install from VS Code Marketplace
2. Copilot automatically gets the `HumanAgent_Chat` tool
3. Done - no configuration needed
## How to Use
### Basic Workflow
1. **Ask Copilot to do something** - Copilot will use the HumanAgent_Chat tool
2. **Chat panel opens** - Green dot = connected, shows Copilot's message
3. **You respond** - Type your answer, click Send (or use Quick Replies)
4. **Copilot continues** - Gets your response and proceeds with the task
### VS Code Interface
**Chat Panel** (left sidebar):
- Green dot = connected to server
- Red dot = disconnected (auto-reconnects)
- Quick Replies = common responses like "Yes Please Proceed"
- Text input = always enabled, send button only active when Copilot is waiting
**Cog Menu** (⚙️):
- Show Status - check server state
- Name This Chat - set session name
- Open Web View - manage all workspaces in browser
- Configure MCP - start/stop/restart server
- Report Issue / Request Feature - GitHub links
### Web Interface
Open from cog menu → **Open Web View**
Access all workspace chats in one browser tab at `http://localhost:3737/HumanAgent`
- See all conversations
- Switch between workspaces
- Append reminders to your responses
### Connection Status
- Auto-reconnects with exponential backoff (1s → 2s → 4s → 8s → 16s → 30s max)
- Manually starting server resets reconnection immediately
- No timeout - will retry forever
## Troubleshooting
**Red dot / disconnected:**
- Cog menu → Configure MCP → Start Server
- Check VS Code Output panel for errors
**Server won't start:**
- Check port 3737 not in use: `lsof -i :3737`
- Restart VS Code
**Copilot not using the tool:**
- Tool registers automatically on startup
- Try: "Use HumanAgent_Chat to discuss this with me"
## Development
Press F5 to debug - dev mode uses port 3738, production uses 3737. No conflicts.
## More Info
See [README-Additional.md](README-Additional.md) for technical details
## Demo
+4 -1
View File
@@ -2,12 +2,15 @@
"name": "humanagent-mcp",
"displayName": "HumanAgent MCP",
"description": "MCP server for chatting with a human agent",
"version": "0.0.13",
"version": "0.0.14",
"publisher": "3DTek-xyz",
"repository": {
"type": "git",
"url": "https://github.com/3DTek-xyz/HumanAgent-MCP.git"
},
"bugs": {
"url": "https://github.com/3DTek-xyz/HumanAgent-MCP/issues"
},
"engines": {
"vscode": "^1.105.0"
},
+191
View File
@@ -778,3 +778,194 @@
2025-11-19T04:29:21.690Z - RESPONSE ENDPOINT CALLED - RequestID: 4-1763524368377
2025-11-19T04:29:57.436Z - RESPONSE ENDPOINT CALLED - RequestID: 5-1763526575920
2025-11-19T04:32:45.235Z - RESPONSE ENDPOINT CALLED - RequestID: 3-1763526722087
2025-11-19T04:33:48.134Z - RESPONSE ENDPOINT CALLED - RequestID: 4-1763526819438
2025-11-19T04:34:16.012Z - RESPONSE ENDPOINT CALLED - RequestID: 5-1763526845435
2025-11-19T04:34:57.910Z - RESPONSE ENDPOINT CALLED - RequestID: 6-1763526872411
2025-11-19T04:35:30.329Z - RESPONSE ENDPOINT CALLED - RequestID: 7-1763526912183
2025-11-19T04:42:49.067Z - RESPONSE ENDPOINT CALLED - RequestID: 8-1763526959059
2025-11-19T04:45:04.786Z - RESPONSE ENDPOINT CALLED - RequestID: 3-1763527451877
2025-11-19T04:49:47.000Z - RESPONSE ENDPOINT CALLED - RequestID: 3-1763527716744
2025-11-19T04:55:16.435Z - RESPONSE ENDPOINT CALLED - RequestID: 4-1763527861868
2025-11-19T04:59:50.456Z - RESPONSE ENDPOINT CALLED - RequestID: 5-1763528376951
2025-11-19T05:01:19.407Z - RESPONSE ENDPOINT CALLED - RequestID: 6-1763528462801
2025-11-19T05:04:42.383Z - RESPONSE ENDPOINT CALLED - RequestID: 7-1763528577693
2025-11-19T05:06:29.667Z - RESPONSE ENDPOINT CALLED - RequestID: 8-1763528696961
2025-11-19T05:07:24.608Z - RESPONSE ENDPOINT CALLED - RequestID: 9-1763528801381
2025-11-19T05:08:14.209Z - RESPONSE ENDPOINT CALLED - RequestID: 10-1763528854833
2025-11-19T05:12:13.762Z - RESPONSE ENDPOINT CALLED - RequestID: 11-1763529008920
2025-11-19T05:19:05.309Z - RESPONSE ENDPOINT CALLED - RequestID: 12-1763529536141
2025-11-19T05:20:58.609Z - RESPONSE ENDPOINT CALLED - RequestID: 13-1763529557247
2025-11-19T05:21:24.226Z - RESPONSE ENDPOINT CALLED - RequestID: 14-1763529676333
2025-11-19T05:23:58.629Z - RESPONSE ENDPOINT CALLED - RequestID: 15-1763529742758
2025-11-19T05:24:58.350Z - RESPONSE ENDPOINT CALLED - RequestID: 16-1763529855270
2025-11-19T05:26:59.273Z - RESPONSE ENDPOINT CALLED - RequestID: 17-1763529950545
2025-11-19T05:27:26.007Z - RESPONSE ENDPOINT CALLED - RequestID: 18-1763530027487
2025-11-19T05:32:43.864Z - RESPONSE ENDPOINT CALLED - RequestID: 19-1763530155910
2025-11-19T05:34:02.832Z - RESPONSE ENDPOINT CALLED - RequestID: 20-1763530392944
2025-11-19T05:35:37.296Z - RESPONSE ENDPOINT CALLED - RequestID: 21-1763530459824
2025-11-19T05:36:48.254Z - RESPONSE ENDPOINT CALLED - RequestID: 22-1763530562725
2025-11-19T05:37:03.432Z - RESPONSE ENDPOINT CALLED - RequestID: 23-1763530616447
2025-11-19T05:38:49.736Z - RESPONSE ENDPOINT CALLED - RequestID: 24-1763530641355
2025-11-19T05:43:18.272Z - RESPONSE ENDPOINT CALLED - RequestID: 25-1763530976990
2025-11-19T05:43:55.025Z - RESPONSE ENDPOINT CALLED - RequestID: 26-1763531008352
2025-11-19T05:44:47.170Z - RESPONSE ENDPOINT CALLED - RequestID: 27-1763531044237
2025-11-19T05:46:39.445Z - RESPONSE ENDPOINT CALLED - RequestID: 28-1763531167181
2025-11-19T05:47:41.254Z - RESPONSE ENDPOINT CALLED - RequestID: 29-1763531207378
2025-11-19T05:48:56.742Z - RESPONSE ENDPOINT CALLED - RequestID: 30-1763531284022
2025-11-19T05:51:01.388Z - RESPONSE ENDPOINT CALLED - RequestID: 31-1763531349420
2025-11-19T05:51:49.445Z - RESPONSE ENDPOINT CALLED - RequestID: 32-1763531470730
2025-11-19T05:52:10.855Z - RESPONSE ENDPOINT CALLED - RequestID: 33-1763531518577
2025-11-19T05:53:56.343Z - RESPONSE ENDPOINT CALLED - RequestID: 34-1763531573352
2025-11-19T05:54:49.345Z - RESPONSE ENDPOINT CALLED - RequestID: 35-1763531650439
2025-11-19T05:55:15.471Z - RESPONSE ENDPOINT CALLED - RequestID: 36-1763531699205
2025-11-19T05:57:32.926Z - RESPONSE ENDPOINT CALLED - RequestID: 37-1763531789516
2025-11-19T05:59:07.146Z - RESPONSE ENDPOINT CALLED - RequestID: 38-1763531863167
2025-11-19T06:01:20.500Z - RESPONSE ENDPOINT CALLED - RequestID: 39-1763532006609
2025-11-19T06:03:26.499Z - RESPONSE ENDPOINT CALLED - RequestID: 40-1763532091039
2025-11-19T06:07:16.659Z - RESPONSE ENDPOINT CALLED - RequestID: 41-1763532229913
2025-11-19T06:08:22.324Z - RESPONSE ENDPOINT CALLED - RequestID: 42-1763532481534
2025-11-19T06:09:50.729Z - RESPONSE ENDPOINT CALLED - RequestID: 43-1763532512158
2025-11-19T06:10:20.481Z - RESPONSE ENDPOINT CALLED - RequestID: 44-1763532601928
2025-11-19T06:16:59.293Z - RESPONSE ENDPOINT CALLED - RequestID: 45-1763532836868
2025-11-19T06:18:41.715Z - RESPONSE ENDPOINT CALLED - RequestID: 46-1763533052927
2025-11-19T06:22:59.308Z - RESPONSE ENDPOINT CALLED - RequestID: 47-1763533369141
2025-11-19T06:26:41.436Z - RESPONSE ENDPOINT CALLED - RequestID: 48-1763533404832
2025-11-19T06:28:55.389Z - RESPONSE ENDPOINT CALLED - RequestID: 49-1763533650222
2025-11-19T06:29:46.242Z - RESPONSE ENDPOINT CALLED - RequestID: 50-1763533751783
2025-11-19T06:30:58.430Z - RESPONSE ENDPOINT CALLED - RequestID: 51-1763533810706
2025-11-19T06:31:53.669Z - RESPONSE ENDPOINT CALLED - RequestID: 52-1763533903911
2025-11-19T06:32:57.297Z - RESPONSE ENDPOINT CALLED - RequestID: 53-1763533925834
2025-11-19T06:34:23.028Z - RESPONSE ENDPOINT CALLED - RequestID: 54-1763533987917
2025-11-19T06:36:53.700Z - RESPONSE ENDPOINT CALLED - RequestID: 55-1763534074733
2025-11-19T06:37:48.746Z - RESPONSE ENDPOINT CALLED - RequestID: 56-1763534245667
2025-11-19T06:39:28.879Z - RESPONSE ENDPOINT CALLED - RequestID: 57-1763534323294
2025-11-19T06:40:15.185Z - RESPONSE ENDPOINT CALLED - RequestID: 58-1763534405032
2025-11-19T06:42:03.705Z - RESPONSE ENDPOINT CALLED - RequestID: 59-1763534427529
2025-11-19T06:42:29.829Z - RESPONSE ENDPOINT CALLED - RequestID: 60-1763534536644
2025-11-19T06:46:47.931Z - RESPONSE ENDPOINT CALLED - RequestID: 61-1763534562112
2025-11-19T06:48:01.522Z - RESPONSE ENDPOINT CALLED - RequestID: 62-1763534819187
2025-11-19T06:49:09.371Z - RESPONSE ENDPOINT CALLED - RequestID: 63-1763534892654
2025-11-19T06:50:01.028Z - RESPONSE ENDPOINT CALLED - RequestID: 64-1763534958161
2025-11-19T06:50:40.898Z - RESPONSE ENDPOINT CALLED - RequestID: 65-1763535021144
2025-11-19T06:52:14.106Z - RESPONSE ENDPOINT CALLED - RequestID: 66-1763535065297
2025-11-19T06:53:15.775Z - RESPONSE ENDPOINT CALLED - RequestID: 67-1763535149720
2025-11-19T06:55:25.120Z - RESPONSE ENDPOINT CALLED - RequestID: 68-1763535249396
2025-11-19T06:56:19.622Z - RESPONSE ENDPOINT CALLED - RequestID: 69-1763535334209
2025-11-19T06:57:31.059Z - RESPONSE ENDPOINT CALLED - RequestID: 70-1763535430753
2025-11-19T06:57:59.741Z - RESPONSE ENDPOINT CALLED - RequestID: 71-1763535474468
2025-11-19T08:44:00.119Z - RESPONSE ENDPOINT CALLED - RequestID: 72-1763535564494
2025-11-19T08:44:21.339Z - RESPONSE ENDPOINT CALLED - RequestID: 3-1763541857967
2025-11-19T08:45:05.334Z - RESPONSE ENDPOINT CALLED - RequestID: 4-1763541892164
2025-11-19T08:47:09.867Z - RESPONSE ENDPOINT CALLED - RequestID: 5-1763542007214
2025-11-19T08:49:21.690Z - RESPONSE ENDPOINT CALLED - RequestID: 6-1763542141507
2025-11-19T08:50:01.921Z - RESPONSE ENDPOINT CALLED - RequestID: 7-1763542173722
2025-11-19T08:52:57.598Z - RESPONSE ENDPOINT CALLED - RequestID: 8-1763542309601
2025-11-19T08:53:30.662Z - RESPONSE ENDPOINT CALLED - RequestID: 9-1763542397476
2025-11-19T08:55:02.059Z - RESPONSE ENDPOINT CALLED - RequestID: 10-1763542459775
2025-11-19T08:56:38.094Z - RESPONSE ENDPOINT CALLED - RequestID: 11-1763542588136
2025-11-19T08:57:46.774Z - RESPONSE ENDPOINT CALLED - RequestID: 12-1763542629436
2025-11-19T08:58:12.370Z - RESPONSE ENDPOINT CALLED - RequestID: 13-1763542676505
2025-11-19T08:59:43.388Z - RESPONSE ENDPOINT CALLED - RequestID: 14-1763542773907
2025-11-19T09:02:44.331Z - RESPONSE ENDPOINT CALLED - RequestID: 15-1763542960322
2025-11-19T09:03:40.040Z - RESPONSE ENDPOINT CALLED - RequestID: 16-1763542979028
2025-11-19T09:05:39.675Z - RESPONSE ENDPOINT CALLED - RequestID: 17-1763543104064
2025-11-19T09:08:32.499Z - RESPONSE ENDPOINT CALLED - RequestID: 18-1763543258846
2025-11-19T09:09:47.437Z - RESPONSE ENDPOINT CALLED - RequestID: 19-1763543320605
2025-11-19T09:10:42.324Z - RESPONSE ENDPOINT CALLED - RequestID: 20-1763543396400
2025-11-19T09:11:09.702Z - RESPONSE ENDPOINT CALLED - RequestID: 21-1763543456136
2025-11-19T09:12:31.519Z - RESPONSE ENDPOINT CALLED - RequestID: 22-1763543491254
2025-11-19T09:14:25.136Z - RESPONSE ENDPOINT CALLED - RequestID: 23-1763543562040
2025-11-19T09:15:49.128Z - RESPONSE ENDPOINT CALLED - RequestID: 24-1763543688599
2025-11-19T09:16:20.816Z - RESPONSE ENDPOINT CALLED - RequestID: 25-1763543766068
2025-11-19T09:18:55.824Z - RESPONSE ENDPOINT CALLED - RequestID: 26-1763543827719
2025-11-19T09:19:59.438Z - RESPONSE ENDPOINT CALLED - RequestID: 27-1763543948652
2025-11-19T09:20:10.054Z - RESPONSE ENDPOINT CALLED - RequestID: 28-1763544008080
2025-11-19T09:22:28.814Z - RESPONSE ENDPOINT CALLED - RequestID: 29-1763544123183
2025-11-19T09:23:12.876Z - RESPONSE ENDPOINT CALLED - RequestID: 30-1763544179186
2025-11-19T09:25:23.109Z - RESPONSE ENDPOINT CALLED - RequestID: 31-1763544220049
2025-11-19T09:26:06.061Z - RESPONSE ENDPOINT CALLED - RequestID: 32-1763544345418
2025-11-19T09:28:18.087Z - RESPONSE ENDPOINT CALLED - RequestID: 33-1763544459317
2025-11-19T09:29:30.957Z - RESPONSE ENDPOINT CALLED - RequestID: 34-1763544517243
2025-11-19T09:30:42.612Z - RESPONSE ENDPOINT CALLED - RequestID: 35-1763544582928
2025-11-19T09:33:30.240Z - RESPONSE ENDPOINT CALLED - RequestID: 36-1763544694667
2025-11-19T09:34:36.716Z - RESPONSE ENDPOINT CALLED - RequestID: 37-1763544851336
2025-11-19T09:36:00.376Z - RESPONSE ENDPOINT CALLED - RequestID: 38-1763544920027
2025-11-19T09:37:12.837Z - RESPONSE ENDPOINT CALLED - RequestID: 39-1763545005402
2025-11-19T09:39:04.091Z - RESPONSE ENDPOINT CALLED - RequestID: 40-1763545057908
2025-11-19T09:40:20.777Z - RESPONSE ENDPOINT CALLED - RequestID: 41-1763545196157
2025-11-19T09:40:51.375Z - RESPONSE ENDPOINT CALLED - RequestID: 42-1763545233558
2025-11-19T09:43:38.208Z - RESPONSE ENDPOINT CALLED - RequestID: 43-1763545338775
2025-11-19T09:44:58.607Z - RESPONSE ENDPOINT CALLED - RequestID: 44-1763545471392
2025-11-19T09:45:35.982Z - RESPONSE ENDPOINT CALLED - RequestID: 45-1763545523406
2025-11-19T09:46:35.672Z - RESPONSE ENDPOINT CALLED - RequestID: 46-1763545576024
2025-11-19T09:47:44.198Z - RESPONSE ENDPOINT CALLED - RequestID: 47-1763545616106
2025-11-19T09:49:49.743Z - RESPONSE ENDPOINT CALLED - RequestID: 48-1763545704123
2025-11-19T09:51:12.886Z - RESPONSE ENDPOINT CALLED - RequestID: 49-1763545861099
2025-11-19T09:52:32.298Z - RESPONSE ENDPOINT CALLED - RequestID: 50-1763545890279
2025-11-19T09:54:45.555Z - RESPONSE ENDPOINT CALLED - RequestID: 51-1763546054209
2025-11-19T09:55:34.779Z - RESPONSE ENDPOINT CALLED - RequestID: 52-1763546098453
2025-11-19T09:56:21.993Z - RESPONSE ENDPOINT CALLED - RequestID: 53-1763546142824
2025-11-19T09:57:29.675Z - RESPONSE ENDPOINT CALLED - RequestID: 54-1763546204281
2025-11-19T09:58:10.026Z - RESPONSE ENDPOINT CALLED - RequestID: 55-1763546260063
2025-11-19T09:59:17.253Z - RESPONSE ENDPOINT CALLED - RequestID: 56-1763546300732
2025-11-19T09:59:55.499Z - RESPONSE ENDPOINT CALLED - RequestID: 57-1763546367439
2025-11-19T10:08:47.884Z - RESPONSE ENDPOINT CALLED - RequestID: 58-1763546915203
2025-11-19T10:09:45.771Z - RESPONSE ENDPOINT CALLED - RequestID: 59-1763546957364
2025-11-19T10:10:32.461Z - RESPONSE ENDPOINT CALLED - RequestID: 60-1763546994227
2025-11-19T10:11:18.173Z - RESPONSE ENDPOINT CALLED - RequestID: 61-1763547058787
2025-11-19T10:13:13.127Z - RESPONSE ENDPOINT CALLED - RequestID: 62-1763547097631
2025-11-19T10:13:54.779Z - RESPONSE ENDPOINT CALLED - RequestID: 63-1763547217769
2025-11-19T10:15:41.739Z - RESPONSE ENDPOINT CALLED - RequestID: 64-1763547322095
2025-11-19T10:17:50.587Z - RESPONSE ENDPOINT CALLED - RequestID: 65-1763547358685
2025-11-19T10:20:27.752Z - RESPONSE ENDPOINT CALLED - RequestID: 66-1763547609570
2025-11-19T10:23:34.759Z - RESPONSE ENDPOINT CALLED - RequestID: 67-1763547636532
2025-11-19T10:33:20.859Z - RESPONSE ENDPOINT CALLED - RequestID: 3-1763548391770
2025-11-19T10:34:12.648Z - RESPONSE ENDPOINT CALLED - RequestID: 4-1763548410172
2025-11-19T10:35:45.765Z - RESPONSE ENDPOINT CALLED - RequestID: 3-1763548538365
2025-11-19T10:36:12.704Z - RESPONSE ENDPOINT CALLED - RequestID: 4-1763548557506
2025-11-19T10:37:27.017Z - RESPONSE ENDPOINT CALLED - RequestID: 5-1763548590890
2025-11-19T10:39:46.306Z - RESPONSE ENDPOINT CALLED - RequestID: 6-1763548726461
2025-11-19T21:45:54.510Z - RESPONSE ENDPOINT CALLED - RequestID: 3-1763588690585
2025-11-19T21:48:37.449Z - RESPONSE ENDPOINT CALLED - RequestID: 4-1763588788581
2025-11-19T21:49:28.708Z - RESPONSE ENDPOINT CALLED - RequestID: 5-1763588935093
2025-11-19T21:50:22.203Z - RESPONSE ENDPOINT CALLED - RequestID: 6-1763588987898
2025-11-19T21:51:20.790Z - RESPONSE ENDPOINT CALLED - RequestID: 7-1763589037769
2025-11-19T21:53:07.762Z - RESPONSE ENDPOINT CALLED - RequestID: 8-1763589095090
2025-11-19T21:54:43.612Z - RESPONSE ENDPOINT CALLED - RequestID: 9-1763589204404
2025-11-19T21:57:07.919Z - RESPONSE ENDPOINT CALLED - RequestID: 10-1763589296875
2025-11-19T21:58:36.437Z - RESPONSE ENDPOINT CALLED - RequestID: 11-1763589457589
2025-11-19T21:59:37.813Z - RESPONSE ENDPOINT CALLED - RequestID: 12-1763589534887
2025-11-19T22:00:44.814Z - RESPONSE ENDPOINT CALLED - RequestID: 13-1763589596478
2025-11-19T22:01:27.653Z - RESPONSE ENDPOINT CALLED - RequestID: 14-1763589662696
2025-11-19T22:02:18.985Z - RESPONSE ENDPOINT CALLED - RequestID: 15-1763589708160
2025-11-19T22:05:49.938Z - RESPONSE ENDPOINT CALLED - RequestID: 16-1763589775471
2025-11-19T22:09:01.630Z - RESPONSE ENDPOINT CALLED - RequestID: 17-1763589970915
2025-11-19T22:11:34.703Z - RESPONSE ENDPOINT CALLED - RequestID: 18-1763590154658
2025-11-19T22:17:21.026Z - RESPONSE ENDPOINT CALLED - RequestID: 19-1763590464990
2025-11-19T22:18:11.331Z - RESPONSE ENDPOINT CALLED - RequestID: 20-1763590652454
2025-11-19T22:19:33.533Z - RESPONSE ENDPOINT CALLED - RequestID: 21-1763590713436
2025-11-19T22:21:39.021Z - RESPONSE ENDPOINT CALLED - RequestID: 22-1763590830807
2025-11-19T22:23:07.848Z - RESPONSE ENDPOINT CALLED - RequestID: 23-1763590968266
2025-11-19T22:24:28.895Z - RESPONSE ENDPOINT CALLED - RequestID: 3-1763591024982
2025-11-19T22:25:39.328Z - RESPONSE ENDPOINT CALLED - RequestID: 4-1763591108976
2025-11-19T22:26:05.856Z - RESPONSE ENDPOINT CALLED - RequestID: 24-1763591140051
2025-11-19T22:28:02.420Z - RESPONSE ENDPOINT CALLED - RequestID: 5-1763591157359
2025-11-19T22:30:03.717Z - RESPONSE ENDPOINT CALLED - RequestID: 6-1763591314014
2025-11-19T22:32:06.688Z - RESPONSE ENDPOINT CALLED - RequestID: 3-1763591499382
2025-11-19T22:32:21.140Z - RESPONSE ENDPOINT CALLED - RequestID: 4-1763591532471
2025-11-19T22:37:45.607Z - RESPONSE ENDPOINT CALLED - RequestID: 7-1763591415766
2025-11-19T22:39:27.868Z - RESPONSE ENDPOINT CALLED - RequestID: 25-1763591299640
2025-11-19T22:44:07.100Z - RESPONSE ENDPOINT CALLED - RequestID: 3-1763592071629
2025-11-19T22:50:36.327Z - RESPONSE ENDPOINT CALLED - RequestID: 3-1763592630513
2025-11-19T22:51:50.138Z - RESPONSE ENDPOINT CALLED - RequestID: 4-1763592645010
2025-11-19T22:54:09.849Z - RESPONSE ENDPOINT CALLED - RequestID: 5-1763592745152
2025-11-19T22:57:41.548Z - RESPONSE ENDPOINT CALLED - RequestID: 6-1763592881661
2025-11-19T22:58:29.548Z - RESPONSE ENDPOINT CALLED - RequestID: 7-1763593071008
2025-11-19T23:02:06.029Z - RESPONSE ENDPOINT CALLED - RequestID: 8-1763593228438
2025-11-19T23:03:03.239Z - RESPONSE ENDPOINT CALLED - RequestID: 9-1763593335464
2025-11-19T23:03:48.859Z - RESPONSE ENDPOINT CALLED - RequestID: 10-1763593421887
2025-11-19T23:04:14.385Z - RESPONSE ENDPOINT CALLED - RequestID: 11-1763593442536
2025-11-20T00:57:40.643Z - RESPONSE ENDPOINT CALLED - RequestID: 3-1763600226770
2025-11-20T00:59:12.862Z - RESPONSE ENDPOINT CALLED - RequestID: 4-1763600290621
2025-11-20T01:00:22.818Z - RESPONSE ENDPOINT CALLED - RequestID: 5-1763600364506
2025-11-20T01:06:31.582Z - RESPONSE ENDPOINT CALLED - RequestID: 3-1763600774684
+63 -18
View File
@@ -12,6 +12,7 @@ let chatTreeProvider: ChatTreeProvider;
let mcpConfigManager: McpConfigManager;
let workspaceSessionId: string;
let serverManager: ServerManager;
let SERVER_PORT: number; // Dynamic port: 3738 for dev, 3737 for production
// MCP Server Definition Provider for VS Code native MCP integration
class HumanAgentMcpProvider implements vscode.McpServerDefinitionProvider {
@@ -19,11 +20,11 @@ class HumanAgentMcpProvider implements vscode.McpServerDefinitionProvider {
readonly onDidChangeMcpServerDefinitions = this._onDidChangeMcpServerDefinitions.event;
private serverVersion: string = Date.now().toString();
constructor(private sessionId: string) {}
constructor(private sessionId: string, private port: number) {}
provideMcpServerDefinitions(token: vscode.CancellationToken): vscode.ProviderResult<vscode.McpHttpServerDefinition[]> {
// Use separate endpoint for MCP tools to avoid SSE conflicts with webview
const serverUrl = `http://127.0.0.1:3737/mcp-tools?sessionId=${this.sessionId}`;
const serverUrl = `http://127.0.0.1:${this.port}/mcp-tools?sessionId=${this.sessionId}`;
const serverUri = vscode.Uri.parse(serverUrl);
const server = new vscode.McpHttpServerDefinition('HumanAgent MCP', serverUri, {}, this.serverVersion);
console.log(`HumanAgent MCP: Using separate MCP tools endpoint to avoid SSE conflicts (version: ${this.serverVersion})`);
@@ -111,17 +112,21 @@ async function restoreSessionName(context: vscode.ExtensionContext, sessionId: s
}
export async function activate(context: vscode.ExtensionContext) {
console.log('HumanAgent MCP extension is now active!');
console.log('HumanAgent MCP extension activated!');
// Determine port based on extension mode (dev vs production)
SERVER_PORT = context.extensionMode === vscode.ExtensionMode.Development ? 3738 : 3737;
console.log(`Using port ${SERVER_PORT} (${context.extensionMode === vscode.ExtensionMode.Development ? 'development' : 'production'} mode);`);
// Generate or retrieve persistent workspace session ID
workspaceSessionId = getWorkspaceSessionId(context);
// Initialize MCP Configuration Manager
const workspaceRoot = vscode.workspace.workspaceFolders?.[0]?.uri.fsPath;
mcpConfigManager = new McpConfigManager(workspaceRoot, context.extensionPath);
mcpConfigManager = new McpConfigManager(workspaceRoot, context.extensionPath, SERVER_PORT);
// Initialize and register VS Code native MCP provider
mcpProvider = new HumanAgentMcpProvider(workspaceSessionId);
mcpProvider = new HumanAgentMcpProvider(workspaceSessionId, SERVER_PORT);
context.subscriptions.push(vscode.lm.registerMcpServerDefinitionProvider('humanagent-mcp.server', mcpProvider));
console.log('HumanAgent MCP: Registered MCP server definition provider');
@@ -144,7 +149,7 @@ export async function activate(context: vscode.ExtensionContext) {
const serverOptions: any = {
serverPath: serverPath,
port: 3737,
port: SERVER_PORT,
host: '127.0.0.1',
loggingEnabled: loggingEnabled,
loggingLevel: loggingLevel
@@ -208,7 +213,7 @@ export async function activate(context: vscode.ExtensionContext) {
});
// Initialize Chat Webview Provider (no internal server dependency)
const chatWebviewProvider = new ChatWebviewProvider(context.extensionUri, null, mcpConfigManager, workspaceSessionId, context, mcpProvider);
const chatWebviewProvider = new ChatWebviewProvider(context.extensionUri, null, mcpConfigManager, workspaceSessionId, context, mcpProvider, SERVER_PORT);
context.subscriptions.push(
vscode.window.registerWebviewViewProvider(ChatWebviewProvider.viewType, chatWebviewProvider)
);
@@ -255,6 +260,8 @@ export async function activate(context: vscode.ExtensionContext) {
const success = await serverManager.ensureServerRunning();
if (success) {
vscode.window.showInformationMessage('HumanAgent MCP Server started successfully!');
// Notify webview to reset reconnection backoff and try immediately
chatWebviewProvider.notifyServerStarted();
} else {
vscode.window.showErrorMessage('Failed to start HumanAgent MCP Server. Check the logs for details.');
}
@@ -265,11 +272,47 @@ export async function activate(context: vscode.ExtensionContext) {
const stopServerCommand = vscode.commands.registerCommand('humanagent-mcp.stopServer', async () => {
try {
const success = await serverManager.stopServer();
if (success) {
// First try HTTP shutdown endpoint (works from any VS Code window or client)
try {
const http = require('http');
const options = {
hostname: '127.0.0.1',
port: SERVER_PORT,
path: '/shutdown',
method: 'POST',
timeout: 5000
};
await new Promise<void>((resolve, reject) => {
const req = http.request(options, (res: any) => {
let data = '';
res.on('data', (chunk: any) => data += chunk);
res.on('end', () => {
if (res.statusCode === 200) {
resolve();
} else {
reject(new Error(`HTTP ${res.statusCode}`));
}
});
});
req.on('error', reject);
req.on('timeout', () => {
req.destroy();
reject(new Error('Request timeout'));
});
req.end();
});
vscode.window.showInformationMessage('HumanAgent MCP Server stopped successfully!');
} else {
vscode.window.showWarningMessage('Server may not have been running or failed to stop cleanly.');
} catch (httpError) {
// Fallback to PID kill if HTTP fails
console.log('HTTP shutdown failed, trying PID kill:', httpError);
const success = await serverManager.stopServer();
if (success) {
vscode.window.showInformationMessage('HumanAgent MCP Server stopped successfully!');
} else {
vscode.window.showWarningMessage('Server may not have been running or failed to stop cleanly.');
}
}
} catch (error) {
vscode.window.showErrorMessage(`Failed to stop server: ${error}`);
@@ -283,6 +326,8 @@ export async function activate(context: vscode.ExtensionContext) {
const success = await serverManager.ensureServerRunning();
if (success) {
vscode.window.showInformationMessage('HumanAgent MCP Server restarted successfully!');
// Notify webview to reset reconnection backoff and try immediately
chatWebviewProvider.notifyServerStarted();
} else {
vscode.window.showErrorMessage('Failed to restart HumanAgent MCP Server. Check the logs for details.');
}
@@ -410,7 +455,7 @@ async function isPortInUse(port: number): Promise<boolean> {
// Check if MCP server is accessible and responding with retry
async function isServerAccessible(): Promise<boolean> {
try {
const response = await fetch('http://127.0.0.1:3737/sessions', {
const response = await fetch(`http://127.0.0.1:${SERVER_PORT}/sessions`, {
method: 'GET',
signal: AbortSignal.timeout(5000) // 5 second timeout
});
@@ -422,7 +467,7 @@ async function isServerAccessible(): Promise<boolean> {
await new Promise(resolve => setTimeout(resolve, 3000));
try {
const retryResponse = await fetch('http://127.0.0.1:3737/sessions', {
const retryResponse = await fetch(`http://127.0.0.1:${SERVER_PORT}/sessions`, {
method: 'GET',
signal: AbortSignal.timeout(5000)
});
@@ -442,7 +487,7 @@ async function isServerAccessible(): Promise<boolean> {
// Check if session exists on server by testing a simple MCP call with retry
async function validateSessionWithServer(sessionId: string): Promise<boolean> {
try {
const response = await fetch('http://127.0.0.1:3737/mcp', {
const response = await fetch(`http://127.0.0.1:${SERVER_PORT}/mcp`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
@@ -466,7 +511,7 @@ async function validateSessionWithServer(sessionId: string): Promise<boolean> {
await new Promise(resolve => setTimeout(resolve, 3000));
try {
const retryResponse = await fetch('http://127.0.0.1:3737/mcp', {
const retryResponse = await fetch(`http://127.0.0.1:${SERVER_PORT}/mcp`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
@@ -516,7 +561,7 @@ async function registerSessionWithStandaloneServer(sessionId: string, forceRereg
};
try {
const response = await fetch('http://127.0.0.1:3737/sessions/register', {
const response = await fetch(`http://127.0.0.1:${SERVER_PORT}/sessions/register`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(requestBody)
@@ -536,7 +581,7 @@ async function registerSessionWithStandaloneServer(sessionId: string, forceRereg
await new Promise(resolve => setTimeout(resolve, 3000));
try {
const retryResponse = await fetch('http://127.0.0.1:3737/sessions/register', {
const retryResponse = await fetch(`http://127.0.0.1:${SERVER_PORT}/sessions/register`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(requestBody)
@@ -560,7 +605,7 @@ async function registerSessionWithStandaloneServer(sessionId: string, forceRereg
// Unregister session with standalone server via HTTP
async function unregisterSessionWithStandaloneServer(sessionId: string): Promise<void> {
try {
const response = await fetch('http://127.0.0.1:3737/sessions/unregister', {
const response = await fetch(`http://127.0.0.1:${SERVER_PORT}/sessions/unregister`, {
method: 'DELETE',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ sessionId })
+3 -3
View File
@@ -20,7 +20,7 @@ export class McpConfigManager {
private static readonly SERVER_NAME = 'humanagent-mcp';
private static readonly GLOBAL_CONFIG_KEY = 'mcp.servers';
constructor(private workspaceRoot?: string, private extensionPath?: string) {
constructor(private workspaceRoot?: string, private extensionPath?: string, private port: number = 3737) {
if (!extensionPath) {
throw new Error('Extension path is required');
}
@@ -71,7 +71,7 @@ export class McpConfigManager {
// Configure our MCP server (HTTP transport) - no sessionId in URL
const serverConfig: any = {
type: 'http',
url: 'http://127.0.0.1:3737/mcp'
url: `http://127.0.0.1:${this.port}/mcp`
};
// Add our server to the config
@@ -98,7 +98,7 @@ export class McpConfigManager {
// Configure our MCP server (HTTP transport) - no sessionId in URL
const serverConfig: any = {
type: 'http',
url: 'http://127.0.0.1:3737/mcp'
url: `http://127.0.0.1:${this.port}/mcp`
};
// Get current global MCP servers configuration
+3 -1
View File
@@ -15,7 +15,9 @@ class StandaloneMcpServer {
// Use the parent directory of the dist folder as workspace path
// This ensures log file is created where it can be properly cleared
const workspacePath = require('path').resolve(__dirname, '..');
this.server = new McpServer(undefined, workspacePath);
// Get port from environment variable (set by ServerManager)
const port = process.env.HUMANAGENT_MCP_PORT ? parseInt(process.env.HUMANAGENT_MCP_PORT) : undefined;
this.server = new McpServer(undefined, workspacePath, port);
}
async start(): Promise<void> {
+91 -4
View File
@@ -127,8 +127,11 @@ export class McpServer extends EventEmitter {
private sseClients: Map<string, http.ServerResponse> = new Map(); // Per-session SSE connections (VS Code webviews)
private webInterfaceConnections: Set<http.ServerResponse> = new Set(); // Web interface connections (all browsers)
constructor(private sessionId?: string, private workspacePath?: string) {
constructor(private sessionId?: string, private workspacePath?: string, port?: number) {
super();
if (port) {
this.port = port;
}
this.debugLogger = new DebugLogger(this.workspacePath);
this.chatManager = new ChatManager(this.debugLogger); // Initialize centralized chat management with logging
@@ -583,6 +586,10 @@ export class McpServer extends EventEmitter {
// Session management, response, tools, reload, messages, and chat endpoints
await this.handleSessionEndpoint(req, res);
return;
} else if (req.url === '/shutdown' && req.method === 'POST') {
// Server shutdown endpoint - allows any client to gracefully stop the server
await this.handleShutdownEndpoint(req, res);
return;
} else {
this.debugLogger.log('HTTP', `404 - Invalid endpoint: ${req.url}`);
res.statusCode = 404;
@@ -822,6 +829,30 @@ export class McpServer extends EventEmitter {
res.end('Method Not Allowed');
}
private async handleShutdownEndpoint(req: http.IncomingMessage, res: http.ServerResponse): Promise<void> {
this.debugLogger.log('INFO', 'Shutdown request received via HTTP');
try {
// Send success response immediately before shutting down
res.statusCode = 200;
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify({ success: true, message: 'Server shutting down...' }));
// Give response time to send before stopping
setTimeout(async () => {
this.debugLogger.log('INFO', 'Initiating server shutdown...');
await this.stop();
process.exit(0);
}, 500);
} catch (error) {
this.debugLogger.log('ERROR', 'Shutdown error:', error);
res.statusCode = 500;
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify({ success: false, error: String(error) }));
}
}
private async handleMcpToolsEndpoint(req: http.IncomingMessage, res: http.ServerResponse, reqUrl: URL): Promise<void> {
// MCP tools endpoint - handles MCP protocol for VS Code extension without SSE conflicts
this.debugLogger.log('HTTP', `MCP Tools: ${req.method} ${req.url}`);
@@ -1260,6 +1291,9 @@ export class McpServer extends EventEmitter {
padding: 10px 15px;
background-color: var(--vscode-panel-background);
border-bottom: 1px solid var(--vscode-border);
display: flex;
justify-content: space-between;
align-items: center;
}
.header h1 {
@@ -1267,6 +1301,29 @@ export class McpServer extends EventEmitter {
font-weight: 600;
}
.shutdown-button {
background-color: #d73a49;
color: white;
border: none;
border-radius: 4px;
padding: 6px 12px;
cursor: pointer;
font-size: 12px;
display: flex;
align-items: center;
gap: 6px;
transition: background-color 0.2s;
}
.shutdown-button:hover {
background-color: #cb2431;
}
.shutdown-button svg {
width: 16px;
height: 16px;
}
.tabs-container {
display: flex;
background-color: var(--vscode-panel-background);
@@ -1485,6 +1542,12 @@ export class McpServer extends EventEmitter {
<div class="container">
<div class="header">
<h1><span class="status-indicator"></span>HumanAgent Multi-Session Chat</h1>
<button class="shutdown-button" onclick="shutdownServer()" title="Stop Server">
<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
<path d="M8 0a1 1 0 0 1 1 1v6a1 1 0 1 1-2 0V1a1 1 0 0 1 1-1z"/>
<path d="M11.5 3.5a5 5 0 1 1-7 0 1 1 0 0 1 1.4-1.4 3 3 0 1 0 4.2 0 1 1 0 0 1 1.4 1.4z"/>
</svg>
</button>
</div>
<div class="tabs-container" id="tabs">
@@ -1522,6 +1585,30 @@ export class McpServer extends EventEmitter {
// Web interface is stateless - gets pending requests from server state
// Server shutdown function
async function shutdownServer() {
if (!confirm('Are you sure you want to stop the server? This will disconnect all clients.')) {
return;
}
try {
const response = await fetch('/shutdown', {
method: 'POST',
headers: { 'Content-Type': 'application/json' }
});
if (response.ok) {
alert('Server is shutting down...');
// Close the window after a moment
setTimeout(() => window.close(), 1000);
} else {
alert('Failed to stop server: ' + response.statusText);
}
} catch (error) {
alert('Error stopping server: ' + error.message);
}
}
// Tab switching
document.getElementById('tabs').addEventListener('click', (e) => {
if (e.target.classList.contains('tab')) {
@@ -1692,11 +1779,11 @@ export class McpServer extends EventEmitter {
} catch (error) {
console.error('Failed to send response:', error);
addMessageToUI(sessionId, 'assistant', \`Error: \${error.message}\`, null, null);
} finally {
// Re-enable send button
// Re-enable button only on error since we won't get SSE state update
button.disabled = false;
textarea.focus();
}
// Note: Button is re-enabled by SSE 'waiting_for_response' state, not here
textarea.focus();
}
function addMessageToUI(sessionId, role, content, source, timestamp) {
+3 -1
View File
@@ -184,7 +184,9 @@ export class ServerManager {
...process.env,
// Pass logging configuration from extension settings
HUMANAGENT_LOGGING_ENABLED: this.options.loggingEnabled ? 'true' : 'false',
HUMANAGENT_LOGGING_LEVEL: this.options.loggingLevel || 'INFO'
HUMANAGENT_LOGGING_LEVEL: this.options.loggingLevel || 'INFO',
// Pass port to standalone server
HUMANAGENT_MCP_PORT: this.options.port.toString()
}
});
+92 -19
View File
@@ -27,7 +27,8 @@ export class ChatWebviewProvider implements vscode.WebviewViewProvider {
mcpConfigManager?: McpConfigManager,
private readonly workspaceSessionId?: string,
private readonly context?: vscode.ExtensionContext,
private readonly mcpProvider?: any
private readonly mcpProvider?: any,
private readonly port: number = 3737
) {
this.mcpServer = mcpServer;
this.mcpConfigManager = mcpConfigManager;
@@ -117,6 +118,14 @@ export class ChatWebviewProvider implements vscode.WebviewViewProvider {
this.updateWebview();
}
public notifyServerStarted() {
if (this._view) {
this._view.webview.postMessage({
type: 'serverStarted'
});
}
}
resolveWebviewView(webviewView: vscode.WebviewView, context: vscode.WebviewViewResolveContext, _token: vscode.CancellationToken) {
this._view = webviewView;
@@ -181,7 +190,7 @@ export class ChatWebviewProvider implements vscode.WebviewViewProvider {
responseBody.images = images;
}
const response = await fetch('http://localhost:3737/response', {
const response = await fetch(`http://localhost:${this.port}/response`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
@@ -279,7 +288,7 @@ export class ChatWebviewProvider implements vscode.WebviewViewProvider {
}
// Get current tool configuration from server - NO FALLBACKS!
const response = await fetch('http://localhost:3737/tools');
const response = await fetch(`http://localhost:${this.port}/tools`);
if (!response.ok) {
throw new Error(`Failed to fetch tools from server: ${response.status}`);
}
@@ -406,6 +415,12 @@ export class ChatWebviewProvider implements vscode.WebviewViewProvider {
case 'openWebView':
await this.openWebInterface();
break;
case 'reportIssue':
vscode.env.openExternal(vscode.Uri.parse('https://github.com/3DTek-xyz/HumanAgent-MCP/issues/new'));
break;
case 'requestFeature':
vscode.env.openExternal(vscode.Uri.parse('https://github.com/3DTek-xyz/HumanAgent-MCP/issues/new'));
break;
}
// Update status after action
@@ -443,7 +458,7 @@ export class ChatWebviewProvider implements vscode.WebviewViewProvider {
}
// Send session name to server
const response = await fetch('http://localhost:3737/sessions/name', {
const response = await fetch(`http://localhost:${this.port}/sessions/name`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
@@ -495,7 +510,7 @@ export class ChatWebviewProvider implements vscode.WebviewViewProvider {
private async openWebInterface() {
try {
const webUrl = 'http://localhost:3737/HumanAgent';
const webUrl = `http://localhost:${this.port}/HumanAgent`;
// Open in external browser
await vscode.env.openExternal(vscode.Uri.parse(webUrl));
@@ -788,7 +803,7 @@ export class ChatWebviewProvider implements vscode.WebviewViewProvider {
<div class="input-area">
<div class="input-container">
<input type="text" class="message-input" id="messageInput" placeholder="Type your response..." ${hasPendingResponse ? '' : 'disabled'}>
<input type="text" class="message-input" id="messageInput" placeholder="Type your response...">
<select class="quick-replies" id="quickReplies" onchange="selectQuickReply()" ${hasPendingResponse ? '' : 'disabled'}>
<option value="">Quick Replies...</option>
<option value="Yes Please Proceed">Yes Please Proceed</option>
@@ -968,13 +983,12 @@ export class ChatWebviewProvider implements vscode.WebviewViewProvider {
{ text: '📊 Show Status', action: 'requestServerStatus' },
{ text: window.overrideFileExists ? '📁 Recreate Override File' : '📁 Create Override File', action: 'overridePrompt' },
{ text: '📝 Name This Chat', action: 'nameSession' },
{ text: '🌐 Open Web View', action: 'openWebView' }
{ text: '🌐 Open Web View', action: 'openWebView' },
{ text: '⚙️ Configure MCP', action: 'configure' },
{ text: '🐛 Report Issue', action: 'reportIssue' },
{ text: '💡 Request Feature', action: 'requestFeature' }
];
// Override file changes require VS Code restart/reload to take effect
options.push({ text: '⚙️ Configure MCP', action: 'configure' });
return options;
}
@@ -1025,12 +1039,49 @@ export class ChatWebviewProvider implements vscode.WebviewViewProvider {
// Update override file existence and refresh cog menu
window.overrideFileExists = message.exists;
console.log('Updated overrideFileExists to:', message.exists);
} else if (message.type === 'serverStarted') {
// Server was manually started - reset backoff and reconnect immediately
console.log('🚀 Server started - resetting reconnection backoff and reconnecting immediately');
reconnectAttempts = 0;
if (reconnectTimeout) {
clearTimeout(reconnectTimeout);
}
connectionInProgress = false;
setupSSEConnection();
}
});
// Set up SSE connection for real-time server events
let currentEventSource = null;
let connectionInProgress = false;
let reconnectAttempts = 0;
let reconnectTimeout = null;
const MAX_RECONNECT_DELAY = 30000; // 30 seconds max
const BASE_RECONNECT_DELAY = 1000; // Start at 1 second
function updateConnectionStatus(connected, error = false) {
const statusElement = document.getElementById('server-status-text');
const statusDot = document.querySelector('.status-dot');
if (statusElement) {
if (connected) {
statusElement.textContent = 'HumanAgent MCP Server (Connected)';
if (statusDot) statusDot.style.backgroundColor = '#4caf50';
} else if (error) {
statusElement.textContent = 'HumanAgent MCP Server (Disconnected)';
if (statusDot) statusDot.style.backgroundColor = '#f44336';
} else {
statusElement.textContent = 'HumanAgent MCP Server (Connecting...)';
if (statusDot) statusDot.style.backgroundColor = '#ff9800';
}
}
}
function getReconnectDelay() {
// Exponential backoff: 1s, 2s, 4s, 8s, 16s, 30s, 30s, ...
const delay = Math.min(BASE_RECONNECT_DELAY * Math.pow(2, reconnectAttempts), MAX_RECONNECT_DELAY);
return delay;
}
function setupSSEConnection() {
if (connectionInProgress) {
@@ -1048,7 +1099,7 @@ export class ChatWebviewProvider implements vscode.WebviewViewProvider {
}
console.log('Setting up SSE connection to MCP server for session:', sessionId);
const eventSource = new EventSource(\`http://localhost:3737/mcp?sessionId=\${sessionId}\`);
const eventSource = new EventSource(\`http://localhost:${this.port}/mcp?sessionId=\${sessionId}\`);
currentEventSource = eventSource;
// Enhanced connection health monitoring
@@ -1072,7 +1123,12 @@ export class ChatWebviewProvider implements vscode.WebviewViewProvider {
console.error(' - Reconnecting...');
eventSource.close();
connectionInProgress = false;
setTimeout(setupSSEConnection, 1000);
updateConnectionStatus(false, true);
const delay = getReconnectDelay();
reconnectAttempts++;
console.log('🔄 Reconnecting after heartbeat timeout in ' + (delay/1000) + 's (attempt #' + reconnectAttempts + ')...');
if (reconnectTimeout) clearTimeout(reconnectTimeout);
reconnectTimeout = setTimeout(setupSSEConnection, delay);
}, 25000); // Timeout after 25 seconds (2.5x heartbeat interval)
}
@@ -1084,6 +1140,8 @@ export class ChatWebviewProvider implements vscode.WebviewViewProvider {
connectionStartTime = Date.now();
messageCount = 0;
connectionInProgress = false; // Connection successful, allow future connections
reconnectAttempts = 0; // Reset backoff on successful connection
updateConnectionStatus(true);
resetHeartbeatTimeout();
};
@@ -1131,10 +1189,25 @@ export class ChatWebviewProvider implements vscode.WebviewViewProvider {
const stateNames = ['CONNECTING', 'OPEN', 'CLOSED'];
console.error(' EventSource state:', stateNames[eventSource.readyState] || 'UNKNOWN');
// Reset connection state and try to reconnect after 5 seconds
// CRITICAL: Close the EventSource to prevent automatic browser reconnection
eventSource.close();
// Update status to disconnected
updateConnectionStatus(false, true);
// Reset connection state and try to reconnect with exponential backoff
connectionInProgress = false;
console.log('🔄 Reconnecting SSE in 5 seconds...');
setTimeout(setupSSEConnection, 5000);
const delay = getReconnectDelay();
reconnectAttempts++;
console.log('🔄 Reconnecting SSE in ' + (delay/1000) + 's (attempt #' + reconnectAttempts + ')...');
// Clear any existing reconnect timeout
if (reconnectTimeout) {
clearTimeout(reconnectTimeout);
}
reconnectTimeout = setTimeout(setupSSEConnection, delay);
};
} catch (error) {
@@ -1188,9 +1261,9 @@ export class ChatWebviewProvider implements vscode.WebviewViewProvider {
// Clear pending request
currentPendingRequestId = null;
// Disable input controls
// Disable send button and quick replies (but keep text input enabled)
const quickReplies = document.getElementById('quickReplies');
if (messageInput && sendButton) {
if (sendButton) {
sendButton.disabled = true;
quickReplies.disabled = true;
}
@@ -1245,7 +1318,7 @@ export class ChatWebviewProvider implements vscode.WebviewViewProvider {
// Load conversation history from server
async function loadConversationHistory() {
try {
const response = await fetch('http://127.0.0.1:3737/sessions/${this.workspaceSessionId}/messages');
const response = await fetch('http://127.0.0.1:${this.port}/sessions/${this.workspaceSessionId}/messages');
if (response.ok) {
const data = await response.json();
const messagesContainer = document.getElementById('messages');