aws-runtime-bridge 1.9.102 → 1.9.103

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.
Files changed (46) hide show
  1. package/README.md +2 -0
  2. package/dist/adapter/AcodeSdkAdapter.d.ts +2 -0
  3. package/dist/adapter/AcodeSdkAdapter.js +3 -3
  4. package/dist/index.js +1 -1
  5. package/dist/remote-desktop/computer-use-backend.d.ts +111 -0
  6. package/dist/remote-desktop/computer-use-backend.js +1 -0
  7. package/dist/remote-desktop/types.d.ts +79 -0
  8. package/dist/routes/computer.d.ts +1 -0
  9. package/dist/routes/computer.js +2 -0
  10. package/dist/routes/file-change-diff.d.ts +27 -0
  11. package/dist/routes/file-change-diff.js +5 -0
  12. package/dist/routes/instance.js +2 -2
  13. package/dist/routes/pty.d.ts +2 -2
  14. package/dist/routes/pty.js +3 -3
  15. package/dist/routes/task-context.js +1 -1
  16. package/dist/routes/terminal.js +28 -28
  17. package/dist/services/auto-register.d.ts +1 -1
  18. package/dist/services/auto-register.js +1 -1
  19. package/dist/services/instance-features.d.ts +10 -0
  20. package/dist/services/instance-features.js +2 -0
  21. package/dist/services/sdk-tool-file-change-recorder.d.ts +12 -0
  22. package/dist/services/sdk-tool-file-change-recorder.js +2 -0
  23. package/dist/services/workspace-files.js +1 -1
  24. package/dist/services/workspaceTaskChangeWatcher.d.ts +9 -1
  25. package/dist/services/workspaceTaskChangeWatcher.js +3 -1
  26. package/package/acode/dist/built-in-file-tools.d.ts +4 -0
  27. package/package/acode/dist/built-in-file-tools.js +2 -2
  28. package/package/acode/dist/runtime.d.ts +13 -0
  29. package/package/acode/dist/runtime.js +18 -18
  30. package/package/aws-client-agent-mcp/README.md +2 -2
  31. package/package/aws-client-agent-mcp/dist/agent-client.d.ts +14 -4
  32. package/package/aws-client-agent-mcp/dist/agent-client.js +1 -1
  33. package/package/aws-client-agent-mcp/dist/agent-client.test.js +36 -36
  34. package/package/aws-client-agent-mcp/dist/config.js +1 -1
  35. package/package/aws-client-agent-mcp/dist/config.test.js +2 -2
  36. package/package/aws-client-agent-mcp/dist/mcp-server.d.ts +2 -0
  37. package/package/aws-client-agent-mcp/dist/mcp-server.js +21 -21
  38. package/package/aws-client-agent-mcp/dist/mcp-server.test.js +35 -36
  39. package/package/aws-client-agent-mcp/dist/mcp-tools.d.ts +6 -0
  40. package/package/aws-client-agent-mcp/dist/mcp-tools.js +25 -5
  41. package/package/aws-client-agent-mcp/dist/mcp-tools.test.js +17 -1
  42. package/package/aws-client-agent-mcp/dist/runtime-launch-binding.test.js +1 -1
  43. package/package/aws-client-agent-mcp/dist/types.d.ts +14 -12
  44. package/package/aws-client-agent-mcp/dist/websocket-client.js +1 -1
  45. package/package.json +3 -2
  46. package/scripts/ensure-playwright-browser.mjs +118 -0
@@ -1,2 +1,2 @@
1
- import{configManager as g}from"./config.js";import{MESSAGE_POLL_INTERVAL_MS as p}from"./constants.js";import{HttpClient as m}from"./http-client.js";import{logger as s,setMcpNodeLogSink as C,updateStartupLogIdentity as f}from"./logger.js";import{claimRuntimeLaunchBinding as I}from"./runtime-launch-binding.js";import{StatusReporter as y}from"./status-reporter.js";import{WebSocketClient as u}from"./websocket-client.js";class _{wsClient;httpClient;agentConfig;serverConfig;agentId=null;displayName=null;projectName=null;isRunning=!1;isDegradedMode=!1;messageHandler=null;profileHandler=null;pollTimer=null;statusReporter=null;newCharacterHandler=null;runtimeTokenRefreshTimer=null;cachedProfile=null;constructor(){g.loadConfig(),this.agentConfig=g.getAgentConfig(),this.serverConfig=g.getServerConfig(),this.wsClient=new u(this.serverConfig),this.httpClient=new m(this.serverConfig),this.setupWebSocketListeners()}async initialize(){const e=await I(this.agentConfig,this.serverConfig);if(!e){this.serverConfig.runtimeBridgeBaseUrl=void 0;return}g.applyRuntimeLaunchBinding(e),this.agentConfig=g.getAgentConfig(),this.serverConfig=g.getServerConfig(),this.wsClient=new u(this.serverConfig),this.httpClient=new m(this.serverConfig),this.setupWebSocketListeners()}setupWebSocketListeners(){this.wsClient.on("directMessage",e=>{this.handleIncomingDm(e)}),this.wsClient.on("groupMessage",e=>{this.handleIncomingGroup(e)}),this.wsClient.on("profileInfo",e=>{s.info(`[AgentClient] WebSocket profileInfo \u4E8B\u4EF6\u89E6\u53D1\uFF0CdisplayName: ${e.displayName}`),this.handleProfileInfo(e)}),this.wsClient.on("agentStatus",e=>{s.info(`[AgentClient] WebSocket agentStatus \u4E8B\u4EF6\u89E6\u53D1: ${e.status}`)}),this.wsClient.on("disconnected",(e,t)=>{const n=t?.toString()||"";s.warn("[AgentClient] WebSocket \u65AD\u5F00\u8FDE\u63A5: code=%s, reason=%s, agentId=%s, \u6B63\u5728\u81EA\u52A8\u91CD\u8FDE",e,n,this.agentId)}),this.wsClient.on("error",e=>{s.error("[AgentClient] WebSocket \u9519\u8BEF: %s, stack=%s",e.message,e.stack)}),this.wsClient.on("reconnectFailed",()=>{s.error("[AgentClient] \u91CD\u8FDE\u5931\u8D25\uFF08\u5DF2\u8FBE\u91CD\u8BD5\u4E0A\u9650\uFF09\uFF0C\u505C\u6B62\u6D88\u606F\u5FAA\u73AF, agentId=%s",this.agentId),this.stop()})}async register(){return s.info("[AgentClient] \u6B63\u5728\u6CE8\u518C Agent..."),this.hasPresetAgentId()?await this.registerWithExistingAgentId():await this.registerAsNewAgent()}hasPresetAgentId(){return!!(this.agentConfig.agentId&&this.agentConfig.agentId.trim().length>0)}async registerWithExistingAgentId(){const e=this.agentConfig.agentId;if(!e)throw new Error("Preset agentId is missing");this.agentId=e.trim();let t;try{t=await this.getProfileByAgentId(this.agentId)}catch(i){throw s.error("[AgentClient] getProfileByAgentId \u5931\u8D25 (presetAgentId=%s): %s",this.agentId,i instanceof Error?i.message:String(i)),i}this.displayName=t.displayName,this.projectName=t.projectName||null,s.info(`[AgentClient] \u4F7F\u7528\u9884\u8BBE AgentID \u7ED1\u5B9A\u5B9E\u4F8B: ${this.displayName} (${this.agentId})`),s.info(`[AgentClient] \u6240\u5C5E\u9879\u76EE: ${this.projectName||"(\u672A\u8BBE\u7F6E)"}`);try{await this.wsClient.connect(this.agentId)}catch(i){throw s.error("[AgentClient] WebSocket \u8FDE\u63A5\u5931\u8D25 (agentId=%s): %s",this.agentId,i instanceof Error?i.message:String(i)),i}s.info("[AgentClient] WebSocket \u8FDE\u63A5\u5DF2\u5EFA\u7ACB\uFF0CAgent \u73B0\u5728\u5DF2\u4E0A\u7EBF"),this.initializeStatusReporter();const n=await this.getProfileByAgentId(this.agentId);return this.displayName=n.displayName,this.projectName=n.projectName||null,f(n.roleName||"unknown-role",n.instanceName||this.agentId),{agentId:this.agentId,displayName:this.displayName,status:n.isOnline?"online":"offline",projectName:n.projectName,workspacePath:n.workspacePath,runtimeStatus:n.runtimeStatus,runtimeSessionId:n.runtimeSessionId}}async registerAsNewAgent(){const e=await this.httpClient.callTool("register",{roleName:this.agentConfig.roleName,projectName:this.agentConfig.projectName,workspacePath:this.agentConfig.workspacePath,prompt:this.agentConfig.prompt,runtimeBridgeBaseUrl:this.serverConfig.runtimeBridgeBaseUrl}),t=e.agentId;if(!t)throw new Error("Registration failed: agentId was not returned");return this.agentId=t,this.displayName=e.displayName,this.projectName=e.projectName||null,f(this.agentConfig.roleName||"unknown-role",e.instanceName||t),s.info(`[AgentClient] \u6CE8\u518C\u6210\u529F: ${this.displayName} (${this.agentId})`),s.info(`[AgentClient] \u72B6\u6001: ${e.status}`),s.info(`[AgentClient] \u6240\u5C5E\u9879\u76EE: ${this.projectName||"(\u672A\u8BBE\u7F6E)"}`),await this.wsClient.connect(this.agentId),s.info("[AgentClient] WebSocket \u8FDE\u63A5\u5DF2\u5EFA\u7ACB\uFF0CAgent \u73B0\u5728\u5DF2\u4E0A\u7EBF"),this.initializeStatusReporter(),e.isExisting===!1&&this.newCharacterHandler&&this.newCharacterHandler(),e}async unregister(){s.info("[AgentClient] \u6B63\u5728\u6CE8\u9500 Agent..."),this.agentId&&await this.httpClient.callTool("unregister",{agentId:this.agentId}),this.stopRuntimeTokenRefresh(),this.wsClient.disconnect(),this.agentId=null,this.displayName=null,this.projectName=null,this.isRunning=!1,s.info("[AgentClient] \u5DF2\u6CE8\u9500")}async discoverColleagues(){return await this.httpClient.callTool("discover_colleague",{agentId:this.agentId})}async discoverGroupRooms(){return this.ensureRegistered(),await this.httpClient.callTool("discover_group_rooms",{agentId:this.agentId})}async hireColleague(e){return this.ensureRegistered(),await this.httpClient.callTool("hire_colleague",{agentId:this.agentId,...e})}async hireColleaguesBatch(e){return this.ensureRegistered(),await this.httpClient.callTool("hire_colleagues_batch",{agentId:this.agentId,...e})}async callAgentScopedTool(e,t){return this.ensureRegistered(),await this.httpClient.callTool(e,{agentId:this.agentId,...t})}async reportMemoryStats(e){await this.callAgentScopedTool("report_memory_stats",{memoryStats:e})}async sendGroupMessage(e,t,n){this.ensureRegistered();const i=t||this.projectName||this.agentConfig.projectName;return await this.httpClient.callTool("send_group_message",{agentId:this.agentId,projectName:i,roomId:n,content:e})}async sendDirectMessage(e,t,n=!1,i,r){this.ensureRegistered();const a={agentId:this.agentId,targetId:e,content:t,requireReply:n,waitReply:n,replyToCallId:i};if(typeof r=="number"&&r>0&&(a.timeoutMs=r),n){const h=typeof r=="number"&&r>0?r+3e4:0;return await this.httpClient.callToolOnce("send_dm",a,h)}return await this.httpClient.callTool("send_dm",a)}async sendCallAndWaitReply(e,t,n=6e4){const i=await this.sendDirectMessage(e,t,!0,void 0,n);if(i.reply)return i.reply;throw new Error("No reply received for call-style direct message before timeout")}async replyToCall(e,t,n){return await this.sendDirectMessage(t,n,!1,e)}async getDmHistory(e,t=50,n){this.ensureRegistered();const i={agentId:this.agentId,targetUserId:e,limit:t};return n&&(i.since=n),await this.httpClient.callTool("get_dm_history",i)}async getGroupHistory(e=50,t,n){if(this.ensureRegistered(),t){const o={projectName:this.projectName||this.agentConfig.projectName,roomId:t,limit:e};return n&&(o.since=n),await this.httpClient.callTool("get_group_history",o)}const i=await this.discoverGroupRooms(),r=this.projectName||this.agentConfig.projectName,a=this.collectRoomIds(i,r);if(a.length===0)return{messages:[],count:0};const c=(await Promise.all(a.map(async o=>{const l={projectName:r,roomId:o,limit:e};return n&&(l.since=n),await this.httpClient.callTool("get_group_history",l)}))).flatMap(o=>o.messages).sort((o,l)=>new Date(o.timestamp).getTime()-new Date(l.timestamp).getTime());return{messages:c,count:c.length}}async fetchUnreadMessages(e={}){this.ensureRegistered();const t=this.projectName||this.agentConfig.projectName,n={agentId:this.agentId,blockIfEmpty:e.blockIfEmpty??!1};e.since&&(n.since=e.since),e.blockTimeoutMs&&e.blockTimeoutMs>0&&(n.blockTimeoutMs=e.blockTimeoutMs);const i=e.includePipelineTasks?"poll_message":"get_dm_messages",r=await this.fetchDirectMessagesWithRecovery(i,n),a=await this.discoverGroupRooms(),h=this.collectRoomIds(a,t),c=await Promise.all(h.map(async o=>{const l={agentId:this.agentId,projectName:t,roomId:o};e.since&&(l.since=e.since);try{return await this.httpClient.callTool("get_group_messages",l)}catch(d){return s.warn("[AgentClient] \u8DF3\u8FC7\u7FA4\u623F\u95F4\u672A\u8BFB\u8865\u62C9\u5931\u8D25: roomId=%s, error=%s",o,d instanceof Error?d.message:String(d)),{messages:[],currentReadPos:0,hasMore:!1}}}));return{directMessages:Array.isArray(r.messages)?r.messages:[],groupMessages:c.flatMap(o=>this.normalizeGroupMessages(o)).sort((o,l)=>new Date(o.timestamp).getTime()-new Date(l.timestamp).getTime())}}async fetchBrowserListenerEvents(){const e=this.serverConfig.runtimeBridgeBaseUrl,t=this.agentId;if(!e||!t)return s.info("[AgentClient] fetchBrowserListenerEvents \u8DF3\u8FC7: bridgeBaseUrl=%s, agentId=%s",e||"(\u7A7A)",t||"(\u7A7A)"),[];try{const n=`${e}/runtime/browser-listeners/${encodeURIComponent(t)}/events`,i=this.serverConfig.runtimeAccessToken||"";s.debug("[AgentClient] \u62C9\u53D6\u76D1\u542C\u5668\u4E8B\u4EF6: url=%s, tokenLen=%d",n,i.length);const r=await fetch(n,{method:"GET",headers:{"X-Runtime-Token":i},signal:AbortSignal.timeout(3e3)});if(!r.ok)return s.warn("[AgentClient] \u62C9\u53D6\u76D1\u542C\u5668\u4E8B\u4EF6\u5931\u8D25: HTTP %s, url=%s",r.status,n),[];const a=await r.json();return!a.ok||!Array.isArray(a.events)?(s.warn("[AgentClient] \u62C9\u53D6\u76D1\u542C\u5668\u4E8B\u4EF6\u54CD\u5E94\u5F02\u5E38: ok=%s, eventsType=%s",a.ok,Array.isArray(a.events)?"array":typeof a.events),[]):(s.debug("[AgentClient] \u62C9\u53D6\u76D1\u542C\u5668\u4E8B\u4EF6\u6210\u529F: %d \u6761\u4E8B\u4EF6",a.events.length),a.events)}catch(n){return s.warn("[AgentClient] \u62C9\u53D6\u76D1\u542C\u5668\u4E8B\u4EF6\u5F02\u5E38: %s",n instanceof Error?n.message:String(n)),[]}}async fetchDirectMessagesWithRecovery(e,t){if(e==="poll_message")try{return await this.httpClient.callToolOnce(e,t)}catch(n){if(this.isRecoverableLongPollError(n))return s.warn("[AgentClient] poll_message \u5355\u6B21\u957F\u8F6E\u8BE2\u8D85\u65F6\uFF0C\u6309\u7A7A\u7ED3\u679C\u9000\u907F\u540E\u7EE7\u7EED\u7B49\u5F85:",n),{messages:[]};throw n}return await this.httpClient.callTool(e,t)}isRecoverableLongPollError(e){return e instanceof Error?/MCP tool poll_message call failed: 503(?:\s|$)/.test(e.message)||/MCP tool poll_message timed out after \d+ms/.test(e.message):!1}normalizeGroupMessages(e){return Array.isArray(e.messages)?e.messages.filter(t=>!!(t&&typeof t=="object"&&typeof t.msgId=="number"&&typeof t.senderId=="string"&&typeof t.content=="string"&&typeof t.timestamp=="string")):[]}collectRoomIds(e,t){const n=e.groups.filter(i=>i.projectName===t).map(i=>i.id);return Array.from(new Set(n))}async getProfile(){this.ensureRegistered();const e=this.agentId;if(!e)throw new Error("Agent is not registered");return{...await this.getProfileByAgentId(e),describe:this.agentConfig.describe}}async getProfileByAgentId(e){return await this.httpClient.callTool("get_profile",{agentId:e})}async getMyTasks(){return this.ensureRegistered(),await this.httpClient.callTool("my_task",{agentId:this.agentId})}async createTaskInstanceComment(e){this.ensureRegistered();const t={agentId:this.agentId,...e};return await this.httpClient.callTool("create_task_instance_comment",t)}async submitTaskResult(e,t,n){this.ensureRegistered();const i={agentId:this.agentId,nodeId:e,outputPayload:t};return n&&Array.isArray(n)&&n.length>0&&(i.changeLog=n),await this.httpClient.callTool("submit_task_result",i)}async startTaskRollback(e){return this.ensureRegistered(),await this.httpClient.callTool("start_task_rollback",{agentId:this.agentId,...e})}async finishTaskRollback(e){return this.ensureRegistered(),await this.httpClient.callTool("finish_task_rollback",{agentId:this.agentId,...e})}async rejectTask(e,t){return this.ensureRegistered(),await this.httpClient.callTool("reject_task",{agentId:this.agentId,nodeId:e,reason:t})}async terminateTask(e,t){return this.ensureRegistered(),await this.httpClient.callTool("terminate_task",{agentId:this.agentId,taskInstanceId:e,reason:t})}start(e,t){if(this.isRunning){s.warn("[AgentClient] \u6D88\u606F\u5FAA\u73AF\u5DF2\u5728\u8FD0\u884C\u4E2D");return}this.isDegradedMode||this.ensureRegistered(),this.messageHandler=e,this.profileHandler=t?.profileHandler||null,this.isRunning=!0,s.info(`[AgentClient] start() \u88AB\u8C03\u7528\uFF0CcachedProfile: ${this.cachedProfile?"\u5B58\u5728":"\u4E0D\u5B58\u5728"}, profileHandler: ${this.profileHandler?"\u5DF2\u8BBE\u7F6E":"\u672A\u8BBE\u7F6E"}, \u964D\u7EA7\u6A21\u5F0F: ${this.isDegradedMode?"\u662F":"\u5426"}`),this.cachedProfile&&this.profileHandler&&(s.info(`[AgentClient] \u5904\u7406\u7F13\u5B58\u7684 Profile \u4FE1\u606F: ${this.cachedProfile.displayName}`),this.profileHandler(this.cachedProfile),this.cachedProfile=null),t?.pollMode??!1?(s.warn("[AgentClient] \u542F\u52A8\u6D88\u606F\u4E3B\u5FAA\u73AF\uFF08HTTP\u8F6E\u8BE2\u6A21\u5F0F - \u4E0D\u63A8\u8350\uFF09"),this.messageLoop()):s.info("[AgentClient] \u542F\u52A8\u6D88\u606F\u4E3B\u5FAA\u73AF\uFF08WebSocket\u63A8\u9001\u6A21\u5F0F - \u63A8\u8350\uFF09")}stop(){this.isRunning=!1,this.pollTimer&&(clearTimeout(this.pollTimer),this.pollTimer=null),this.stopRuntimeTokenRefresh(),s.info("[AgentClient] \u6D88\u606F\u4E3B\u5FAA\u73AF\u5DF2\u505C\u6B62")}async messageLoop(){for(;this.isRunning;)try{await this.delay(p)}catch(e){s.error("[AgentClient] \u6D88\u606F\u5FAA\u73AF\u9519\u8BEF:",e),await this.delay(5e3)}}handleIncomingDm(e){e.senderId!==this.agentId&&this.processMessage(e)}handleIncomingGroup(e){e.senderId!==this.agentId&&this.processMessage(e)}handleProfileInfo(e){s.info(`[AgentClient] \u6536\u5230 Profile \u4FE1\u606F: ${e.displayName} (${e.roleName})`),e.projectName&&(this.projectName=e.projectName,s.info(`[AgentClient] \u66F4\u65B0\u6240\u5C5E\u9879\u76EE: ${this.projectName}`)),e.roleName&&e.roleName!==this.agentConfig.roleName&&(s.info(`[AgentClient] \u540C\u6B65\u89D2\u8272\u540D: "${this.agentConfig.roleName||"(\u7A7A)"}" -> "${e.roleName}"`),this.agentConfig.roleName=e.roleName),e.roleName&&f(e.roleName,e.instanceName||this.agentId||""),this.profileHandler?this.profileHandler(e):(s.info("[AgentClient] profileHandler \u672A\u8BBE\u7F6E\uFF0C\u7F13\u5B58 Profile \u4FE1\u606F"),this.cachedProfile=e)}async processMessage(e){if(!this.messageHandler)return;const t=typeof e.msgId=="string";s.info(`[AgentClient] \u6536\u5230${t?"\u79C1\u4FE1":"\u7FA4\u6D88\u606F"}\u6765\u81EA ${e.senderName}: ${e.content.substring(0,50)}...`);try{const n=await this.messageHandler(e);if(t){const i=e;i.requireReply&&i.callId&&await this.replyToCall(i.callId,i.senderId,n||"\u5DF2\u6536\u5230\u6D88\u606F\uFF0C\u6B63\u5728\u5904\u7406\u4E2D...")}}catch(n){const i=typeof e.msgId=="string";if(s.error("[AgentClient] \u5904\u7406\u6D88\u606F\u5931\u8D25: type=%s, senderId=%s, senderName=%s, msgId=%s, error=%s",i?"\u79C1\u4FE1":"\u7FA4\u6D88\u606F",e.senderId,e.senderName,e.msgId,n instanceof Error?n.message:String(n)),i){const r=e;r.requireReply&&r.callId&&await this.replyToCall(r.callId,r.senderId,`\u5904\u7406\u5931\u8D25: ${n}`)}}}ensureRegistered(){if(!this.agentId)throw new Error("Agent is not registered")}delay(e){return new Promise(t=>{this.pollTimer=setTimeout(t,e)})}onNewCharacter(e){this.newCharacterHandler=e}getState(){return{agentId:this.agentId,displayName:this.displayName,projectName:this.projectName,isConnected:this.wsClient.isConnected(),isRunning:this.isRunning}}getAgentConfig(){return this.agentConfig}reloadConfig(){g.loadConfig(),this.agentConfig=g.getAgentConfig(),s.info(`[AgentClient] \u914D\u7F6E\u5DF2\u91CD\u65B0\u52A0\u8F7D\uFF0C\u89D2\u8272: ${this.agentConfig.roleName}`)}enterDegradedMode(){this.isDegradedMode=!0,s.warn("[AgentClient] \u8FDB\u5165\u964D\u7EA7\u6A21\u5F0F\uFF0C\u5C06\u5728\u540E\u53F0\u6301\u7EED\u5C1D\u8BD5\u91CD\u8FDE")}exitDegradedMode(){this.isDegradedMode=!1,s.info("[AgentClient] \u9000\u51FA\u964D\u7EA7\u6A21\u5F0F")}isInDegradedMode(){return this.isDegradedMode}async retryRegistrationInBackground(e,t){let n=0;(async()=>{for(;this.isDegradedMode;)try{s.info(`[AgentClient] \u964D\u7EA7\u6A21\u5F0F\uFF1A\u5C1D\u8BD5\u91CD\u65B0\u6CE8\u518C (${n+1}/${t===-1?"\u65E0\u9650":t})`);const r=await this.register();s.info(`[AgentClient] \u964D\u7EA7\u6A21\u5F0F\uFF1A\u6CE8\u518C\u6210\u529F - ${r.displayName} (${r.agentId})`),this.exitDegradedMode(),this.messageHandler&&this.start(this.messageHandler);return}catch(r){n++;const a=r instanceof Error?r.message:String(r);if(s.warn(`[AgentClient] \u964D\u7EA7\u6A21\u5F0F\uFF1A\u6CE8\u518C\u5931\u8D25 (${n}/${t===-1?"\u65E0\u9650":t}): ${a}`),t>0&&n>=t){s.error("[AgentClient] \u964D\u7EA7\u6A21\u5F0F\uFF1A\u8FBE\u5230\u6700\u5927\u91CD\u8BD5\u6B21\u6570\uFF0C\u505C\u6B62\u91CD\u8FDE"),this.isDegradedMode=!1;return}await new Promise(h=>setTimeout(h,e))}})().catch(r=>{s.error("[AgentClient] \u964D\u7EA7\u6A21\u5F0F\u540E\u53F0\u91CD\u8BD5\u5FAA\u73AF\u5F02\u5E38\u9000\u51FA: error=%s, stack=%s",r instanceof Error?r.message:String(r),r instanceof Error?r.stack:"(no stack)")})}initializeStatusReporter(){if(!this.agentId){s.warn("[AgentClient] \u65E0\u6CD5\u521D\u59CB\u5316\u72B6\u6001\u62A5\u544A\u5668\uFF1AagentId \u4E3A\u7A7A");return}this.statusReporter=new y({agentId:this.agentId,sendStatusUpdate:e=>{this.wsClient.send({type:"AGENT_STATUS",data:e,timestamp:new Date().toISOString()})}}),C(e=>this.reportMcpNodeLog(e)),this.startRuntimeTokenRefresh(),s.info("[AgentClient] \u72B6\u6001\u62A5\u544A\u5668\u5DF2\u521D\u59CB\u5316")}startRuntimeTokenRefresh(){this.stopRuntimeTokenRefresh();const e=this.serverConfig.runtimeTokenRefreshIntervalMs;if(!e||e<=0){s.warn("[AgentClient] runtimeTokenRefreshIntervalMs \u672A\u914D\u7F6E\u6216\u65E0\u6548\uFF0C\u8DF3\u8FC7\u4E3B\u52A8\u7EED\u671F");return}const t=this.agentId;if(!t){s.warn("[AgentClient] agentId \u4E3A\u7A7A\uFF0C\u8DF3\u8FC7\u4E3B\u52A8\u7EED\u671F");return}this.runtimeTokenRefreshTimer=setInterval(async()=>{try{await this.httpClient.refreshRuntimeAccessToken(t)&&s.info("[AgentClient] runtimeAccessToken \u5DF2\u4E3B\u52A8\u7EED\u671F")}catch(n){s.warn("[AgentClient] \u4E3B\u52A8\u7EED\u671F runtimeAccessToken \u5931\u8D25: %s",n instanceof Error?n.message:String(n)),n instanceof Error&&n.stack&&s.warn("[AgentClient] \u4E3B\u52A8\u7EED\u671F\u5F02\u5E38\u5806\u6808:",n.stack)}},e),s.info(`[AgentClient] runtime token \u4E3B\u52A8\u7EED\u671F\u5DF2\u542F\u52A8\uFF0C\u95F4\u9694 ${e}ms`)}stopRuntimeTokenRefresh(){this.runtimeTokenRefreshTimer&&(clearInterval(this.runtimeTokenRefreshTimer),this.runtimeTokenRefreshTimer=null)}reportMcpNodeLog(e){const t=this.wsClient;!this.agentId||!this.wsClient.isConnected()||typeof t.sendMcpNodeLog!="function"||t.sendMcpNodeLog(e)}getStatusReporter(){return this.statusReporter}}export{_ as AgentClient};
1
+ import{configManager as g}from"./config.js";import{MESSAGE_POLL_INTERVAL_MS as m}from"./constants.js";import{HttpClient as u}from"./http-client.js";import{logger as s,setMcpNodeLogSink as C,updateStartupLogIdentity as f}from"./logger.js";import{claimRuntimeLaunchBinding as I}from"./runtime-launch-binding.js";import{StatusReporter as y}from"./status-reporter.js";import{WebSocketClient as p}from"./websocket-client.js";class N{wsClient;httpClient;agentConfig;serverConfig;agentId=null;displayName=null;projectId=null;isRunning=!1;isDegradedMode=!1;messageHandler=null;profileHandler=null;configHandler=null;pollTimer=null;statusReporter=null;newCharacterHandler=null;runtimeTokenRefreshTimer=null;cachedProfile=null;constructor(){g.loadConfig(),this.agentConfig=g.getAgentConfig(),this.serverConfig=g.getServerConfig(),this.wsClient=new p(this.serverConfig),this.httpClient=new u(this.serverConfig),this.setupWebSocketListeners()}async initialize(){const e=await I(this.agentConfig,this.serverConfig);if(!e){this.serverConfig.runtimeBridgeBaseUrl=void 0;return}g.applyRuntimeLaunchBinding(e),this.agentConfig=g.getAgentConfig(),this.serverConfig=g.getServerConfig(),this.wsClient=new p(this.serverConfig),this.httpClient=new u(this.serverConfig),this.setupWebSocketListeners()}setupWebSocketListeners(){this.wsClient.on("directMessage",e=>{this.handleIncomingDm(e)}),this.wsClient.on("groupMessage",e=>{this.handleIncomingGroup(e)}),this.wsClient.on("profileInfo",e=>{s.info(`[AgentClient] WebSocket profileInfo \u4E8B\u4EF6\u89E6\u53D1\uFF0CdisplayName: ${e.displayName}`),this.handleProfileInfo(e)}),this.wsClient.on("agentConfig",e=>{s.info("[AgentClient] WebSocket agentConfig \u4E8B\u4EF6\u89E6\u53D1"),this.configHandler&&this.configHandler(e??{})}),this.wsClient.on("agentStatus",e=>{s.info(`[AgentClient] WebSocket agentStatus \u4E8B\u4EF6\u89E6\u53D1: ${e.status}`)}),this.wsClient.on("disconnected",(e,t)=>{const n=t?.toString()||"";s.warn("[AgentClient] WebSocket \u65AD\u5F00\u8FDE\u63A5: code=%s, reason=%s, agentId=%s, \u6B63\u5728\u81EA\u52A8\u91CD\u8FDE",e,n,this.agentId)}),this.wsClient.on("error",e=>{s.error("[AgentClient] WebSocket \u9519\u8BEF: %s, stack=%s",e.message,e.stack)}),this.wsClient.on("reconnectFailed",()=>{s.error("[AgentClient] \u91CD\u8FDE\u5931\u8D25\uFF08\u5DF2\u8FBE\u91CD\u8BD5\u4E0A\u9650\uFF09\uFF0C\u505C\u6B62\u6D88\u606F\u5FAA\u73AF, agentId=%s",this.agentId),this.stop()})}async register(){return s.info("[AgentClient] \u6B63\u5728\u6CE8\u518C Agent..."),this.hasPresetAgentId()?await this.registerWithExistingAgentId():await this.registerAsNewAgent()}hasPresetAgentId(){return!!(this.agentConfig.agentId&&this.agentConfig.agentId.trim().length>0)}async registerWithExistingAgentId(){const e=this.agentConfig.agentId;if(!e)throw new Error("Preset agentId is missing");this.agentId=e.trim();let t;try{t=await this.getProfileByAgentId(this.agentId)}catch(i){throw s.error("[AgentClient] getProfileByAgentId \u5931\u8D25 (presetAgentId=%s): %s",this.agentId,i instanceof Error?i.message:String(i)),i}this.displayName=t.displayName,this.projectId=t.projectId||null,s.info(`[AgentClient] \u4F7F\u7528\u9884\u8BBE AgentID \u7ED1\u5B9A\u5B9E\u4F8B: ${this.displayName} (${this.agentId})`),s.info(`[AgentClient] \u6240\u5C5E\u9879\u76EE: ${this.projectId||"(\u672A\u8BBE\u7F6E)"}`);try{await this.wsClient.connect(this.agentId)}catch(i){throw s.error("[AgentClient] WebSocket \u8FDE\u63A5\u5931\u8D25 (agentId=%s): %s",this.agentId,i instanceof Error?i.message:String(i)),i}s.info("[AgentClient] WebSocket \u8FDE\u63A5\u5DF2\u5EFA\u7ACB\uFF0CAgent \u73B0\u5728\u5DF2\u4E0A\u7EBF"),this.initializeStatusReporter();const n=await this.getProfileByAgentId(this.agentId);return this.displayName=n.displayName,this.projectId=n.projectId||null,f(n.roleName||"unknown-role",n.instanceName||this.agentId),{agentId:this.agentId,displayName:this.displayName,status:n.isOnline?"online":"offline",projectId:n.projectId,workspacePath:n.workspacePath,runtimeStatus:n.runtimeStatus,runtimeSessionId:n.runtimeSessionId}}async registerAsNewAgent(){const e=await this.httpClient.callTool("register",{roleName:this.agentConfig.roleName,projectId:this.agentConfig.projectId,workspacePath:this.agentConfig.workspacePath,prompt:this.agentConfig.prompt,runtimeBridgeBaseUrl:this.serverConfig.runtimeBridgeBaseUrl}),t=e.agentId;if(!t)throw new Error("Registration failed: agentId was not returned");return this.agentId=t,this.displayName=e.displayName,this.projectId=e.projectId||null,f(this.agentConfig.roleName||"unknown-role",e.instanceName||t),s.info(`[AgentClient] \u6CE8\u518C\u6210\u529F: ${this.displayName} (${this.agentId})`),s.info(`[AgentClient] \u72B6\u6001: ${e.status}`),s.info(`[AgentClient] \u6240\u5C5E\u9879\u76EE: ${this.projectId||"(\u672A\u8BBE\u7F6E)"}`),await this.wsClient.connect(this.agentId),s.info("[AgentClient] WebSocket \u8FDE\u63A5\u5DF2\u5EFA\u7ACB\uFF0CAgent \u73B0\u5728\u5DF2\u4E0A\u7EBF"),this.initializeStatusReporter(),e.isExisting===!1&&this.newCharacterHandler&&this.newCharacterHandler(),e}async unregister(){s.info("[AgentClient] \u6B63\u5728\u6CE8\u9500 Agent..."),this.agentId&&await this.httpClient.callTool("unregister",{agentId:this.agentId}),this.stopRuntimeTokenRefresh(),this.wsClient.disconnect(),this.agentId=null,this.displayName=null,this.projectId=null,this.isRunning=!1,s.info("[AgentClient] \u5DF2\u6CE8\u9500")}async discoverColleagues(){return await this.httpClient.callTool("discover_colleague",{agentId:this.agentId})}async discoverGroupRooms(){return this.ensureRegistered(),await this.httpClient.callTool("discover_group_rooms",{agentId:this.agentId})}async hireColleague(e){return this.ensureRegistered(),await this.httpClient.callTool("hire_colleague",{agentId:this.agentId,...e})}async hireColleaguesBatch(e){return this.ensureRegistered(),await this.httpClient.callTool("hire_colleagues_batch",{agentId:this.agentId,...e})}async callAgentScopedTool(e,t){return this.ensureRegistered(),await this.httpClient.callTool(e,{agentId:this.agentId,...t})}async reportMemoryStats(e){await this.callAgentScopedTool("report_memory_stats",{memoryStats:e})}async sendGroupMessage(e,t,n){this.ensureRegistered();const i=t||this.projectId||this.agentConfig.projectId;return await this.httpClient.callTool("send_group_message",{agentId:this.agentId,projectId:i,roomId:n,content:e})}async sendDirectMessage(e,t,n=!1,i,r){this.ensureRegistered();const a={agentId:this.agentId,targetId:e,content:t,requireReply:n,waitReply:n,replyToCallId:i};if(typeof r=="number"&&r>0&&(a.timeoutMs=r),n){const d=typeof r=="number"&&r>0?r+3e4:0;return await this.httpClient.callToolOnce("send_dm",a,d)}return await this.httpClient.callTool("send_dm",a)}async sendCallAndWaitReply(e,t,n=6e4){const i=await this.sendDirectMessage(e,t,!0,void 0,n);if(i.reply)return i.reply;throw new Error("No reply received for call-style direct message before timeout")}async replyToCall(e,t,n){return await this.sendDirectMessage(t,n,!1,e)}async getDmHistory(e,t=50,n){this.ensureRegistered();const i={agentId:this.agentId,targetUserId:e,limit:t};return n&&(i.since=n),await this.httpClient.callTool("get_dm_history",i)}async getGroupHistory(e=50,t,n){if(this.ensureRegistered(),t){const o={projectId:this.projectId||this.agentConfig.projectId,roomId:t,limit:e};return n&&(o.since=n),await this.httpClient.callTool("get_group_history",o)}const i=await this.discoverGroupRooms(),r=this.projectId||this.agentConfig.projectId,a=this.collectRoomIds(i,r);if(a.length===0)return{messages:[],count:0};const h=(await Promise.all(a.map(async o=>{const l={projectId:r,roomId:o,limit:e};return n&&(l.since=n),await this.httpClient.callTool("get_group_history",l)}))).flatMap(o=>o.messages).sort((o,l)=>new Date(o.timestamp).getTime()-new Date(l.timestamp).getTime());return{messages:h,count:h.length}}async fetchUnreadMessages(e={}){this.ensureRegistered();const t=this.projectId||this.agentConfig.projectId,n={agentId:this.agentId,blockIfEmpty:e.blockIfEmpty??!1};e.since&&(n.since=e.since),e.blockTimeoutMs&&e.blockTimeoutMs>0&&(n.blockTimeoutMs=e.blockTimeoutMs);const i=e.includePipelineTasks?"poll_message":"get_dm_messages",r=await this.fetchDirectMessagesWithRecovery(i,n),a=await this.discoverGroupRooms(),d=this.collectRoomIds(a,t),h=await Promise.all(d.map(async o=>{const l={agentId:this.agentId,projectId:t,roomId:o};e.since&&(l.since=e.since);try{return await this.httpClient.callTool("get_group_messages",l)}catch(c){return s.warn("[AgentClient] \u8DF3\u8FC7\u7FA4\u623F\u95F4\u672A\u8BFB\u8865\u62C9\u5931\u8D25: roomId=%s, error=%s",o,c instanceof Error?c.message:String(c)),{messages:[],currentReadPos:0,hasMore:!1}}}));return{directMessages:Array.isArray(r.messages)?r.messages:[],groupMessages:h.flatMap(o=>this.normalizeGroupMessages(o)).sort((o,l)=>new Date(o.timestamp).getTime()-new Date(l.timestamp).getTime())}}async fetchBrowserListenerEvents(){const e=this.serverConfig.runtimeBridgeBaseUrl,t=this.agentId;if(!e||!t)return s.info("[AgentClient] fetchBrowserListenerEvents \u8DF3\u8FC7: bridgeBaseUrl=%s, agentId=%s",e||"(\u7A7A)",t||"(\u7A7A)"),[];try{const n=`${e}/runtime/browser-listeners/${encodeURIComponent(t)}/events`,i=this.serverConfig.runtimeAccessToken||"";s.debug("[AgentClient] \u62C9\u53D6\u76D1\u542C\u5668\u4E8B\u4EF6: url=%s, tokenLen=%d",n,i.length);const r=await fetch(n,{method:"GET",headers:{"X-Runtime-Token":i},signal:AbortSignal.timeout(3e3)});if(!r.ok)return s.warn("[AgentClient] \u62C9\u53D6\u76D1\u542C\u5668\u4E8B\u4EF6\u5931\u8D25: HTTP %s, url=%s",r.status,n),[];const a=await r.json();return!a.ok||!Array.isArray(a.events)?(s.warn("[AgentClient] \u62C9\u53D6\u76D1\u542C\u5668\u4E8B\u4EF6\u54CD\u5E94\u5F02\u5E38: ok=%s, eventsType=%s",a.ok,Array.isArray(a.events)?"array":typeof a.events),[]):(s.debug("[AgentClient] \u62C9\u53D6\u76D1\u542C\u5668\u4E8B\u4EF6\u6210\u529F: %d \u6761\u4E8B\u4EF6",a.events.length),a.events)}catch(n){return s.warn("[AgentClient] \u62C9\u53D6\u76D1\u542C\u5668\u4E8B\u4EF6\u5F02\u5E38: %s",n instanceof Error?n.message:String(n)),[]}}async fetchDirectMessagesWithRecovery(e,t){if(e==="poll_message")try{return await this.httpClient.callToolOnce(e,t)}catch(n){if(this.isRecoverableLongPollError(n))return s.warn("[AgentClient] poll_message \u5355\u6B21\u957F\u8F6E\u8BE2\u8D85\u65F6\uFF0C\u6309\u7A7A\u7ED3\u679C\u9000\u907F\u540E\u7EE7\u7EED\u7B49\u5F85:",n),{messages:[]};throw n}return await this.httpClient.callTool(e,t)}isRecoverableLongPollError(e){return e instanceof Error?/MCP tool poll_message call failed: 503(?:\s|$)/.test(e.message)||/MCP tool poll_message timed out after \d+ms/.test(e.message):!1}normalizeGroupMessages(e){return Array.isArray(e.messages)?e.messages.filter(t=>!!(t&&typeof t=="object"&&typeof t.msgId=="number"&&typeof t.senderId=="string"&&typeof t.content=="string"&&typeof t.timestamp=="string")):[]}collectRoomIds(e,t){const n=e.groups.filter(i=>i.projectId===t).map(i=>i.id);return Array.from(new Set(n))}async getProfile(){this.ensureRegistered();const e=this.agentId;if(!e)throw new Error("Agent is not registered");return{...await this.getProfileByAgentId(e),describe:this.agentConfig.describe}}async getProfileByAgentId(e){return await this.httpClient.callTool("get_profile",{agentId:e})}async getMyTasks(){return this.ensureRegistered(),await this.httpClient.callTool("my_task",{agentId:this.agentId})}async createTaskInstanceComment(e){this.ensureRegistered();const t={agentId:this.agentId,...e};return await this.httpClient.callTool("create_task_instance_comment",t)}async submitTaskResult(e,t,n){this.ensureRegistered();const i={agentId:this.agentId,nodeId:e,outputPayload:t};return n&&Array.isArray(n)&&n.length>0&&(i.changeLog=n),await this.httpClient.callTool("submit_task_result",i)}async startTaskRollback(e){return this.ensureRegistered(),await this.httpClient.callTool("start_task_rollback",{agentId:this.agentId,...e})}async finishTaskRollback(e){return this.ensureRegistered(),await this.httpClient.callTool("finish_task_rollback",{agentId:this.agentId,...e})}async rejectTask(e,t){return this.ensureRegistered(),await this.httpClient.callTool("reject_task",{agentId:this.agentId,nodeId:e,reason:t})}async terminateTask(e,t){return this.ensureRegistered(),await this.httpClient.callTool("terminate_task",{agentId:this.agentId,taskInstanceId:e,reason:t})}async getDebugLogConfig(){return await this.httpClient.callTool("get_debug_log_config",{agentId:this.agentId})}async queryDebugLogs(e){return this.ensureRegistered(),await this.httpClient.callTool("query_debug_logs",{...e})}async queryFileChangesHistory(e){return this.ensureRegistered(),await this.httpClient.callTool("query_file_changes_history",{...e})}start(e,t){if(this.isRunning){s.warn("[AgentClient] \u6D88\u606F\u5FAA\u73AF\u5DF2\u5728\u8FD0\u884C\u4E2D");return}this.isDegradedMode||this.ensureRegistered(),this.messageHandler=e,this.profileHandler=t?.profileHandler||null,this.configHandler=t?.configHandler||null,this.isRunning=!0,s.info(`[AgentClient] start() \u88AB\u8C03\u7528\uFF0CcachedProfile: ${this.cachedProfile?"\u5B58\u5728":"\u4E0D\u5B58\u5728"}, profileHandler: ${this.profileHandler?"\u5DF2\u8BBE\u7F6E":"\u672A\u8BBE\u7F6E"}, \u964D\u7EA7\u6A21\u5F0F: ${this.isDegradedMode?"\u662F":"\u5426"}`),this.cachedProfile&&this.profileHandler&&(s.info(`[AgentClient] \u5904\u7406\u7F13\u5B58\u7684 Profile \u4FE1\u606F: ${this.cachedProfile.displayName}`),this.profileHandler(this.cachedProfile),this.cachedProfile=null),t?.pollMode??!1?(s.warn("[AgentClient] \u542F\u52A8\u6D88\u606F\u4E3B\u5FAA\u73AF\uFF08HTTP\u8F6E\u8BE2\u6A21\u5F0F - \u4E0D\u63A8\u8350\uFF09"),this.messageLoop()):s.info("[AgentClient] \u542F\u52A8\u6D88\u606F\u4E3B\u5FAA\u73AF\uFF08WebSocket\u63A8\u9001\u6A21\u5F0F - \u63A8\u8350\uFF09")}stop(){this.isRunning=!1,this.pollTimer&&(clearTimeout(this.pollTimer),this.pollTimer=null),this.stopRuntimeTokenRefresh(),s.info("[AgentClient] \u6D88\u606F\u4E3B\u5FAA\u73AF\u5DF2\u505C\u6B62")}async messageLoop(){for(;this.isRunning;)try{await this.delay(m)}catch(e){s.error("[AgentClient] \u6D88\u606F\u5FAA\u73AF\u9519\u8BEF:",e),await this.delay(5e3)}}handleIncomingDm(e){e.senderId!==this.agentId&&this.processMessage(e)}handleIncomingGroup(e){e.senderId!==this.agentId&&this.processMessage(e)}handleProfileInfo(e){s.info(`[AgentClient] \u6536\u5230 Profile \u4FE1\u606F: ${e.displayName} (${e.roleName})`),e.projectId&&(this.projectId=e.projectId,s.info(`[AgentClient] \u66F4\u65B0\u6240\u5C5E\u9879\u76EE: ${this.projectId}`)),e.roleName&&e.roleName!==this.agentConfig.roleName&&(s.info(`[AgentClient] \u540C\u6B65\u89D2\u8272\u540D: "${this.agentConfig.roleName||"(\u7A7A)"}" -> "${e.roleName}"`),this.agentConfig.roleName=e.roleName),e.roleName&&f(e.roleName,e.instanceName||this.agentId||""),this.profileHandler?this.profileHandler(e):(s.info("[AgentClient] profileHandler \u672A\u8BBE\u7F6E\uFF0C\u7F13\u5B58 Profile \u4FE1\u606F"),this.cachedProfile=e)}async processMessage(e){if(!this.messageHandler)return;const t=typeof e.msgId=="string";s.info(`[AgentClient] \u6536\u5230${t?"\u79C1\u4FE1":"\u7FA4\u6D88\u606F"}\u6765\u81EA ${e.senderName}: ${e.content.substring(0,50)}...`);try{const n=await this.messageHandler(e);if(t){const i=e;i.requireReply&&i.callId&&await this.replyToCall(i.callId,i.senderId,n||"\u5DF2\u6536\u5230\u6D88\u606F\uFF0C\u6B63\u5728\u5904\u7406\u4E2D...")}}catch(n){const i=typeof e.msgId=="string";if(s.error("[AgentClient] \u5904\u7406\u6D88\u606F\u5931\u8D25: type=%s, senderId=%s, senderName=%s, msgId=%s, error=%s",i?"\u79C1\u4FE1":"\u7FA4\u6D88\u606F",e.senderId,e.senderName,e.msgId,n instanceof Error?n.message:String(n)),i){const r=e;r.requireReply&&r.callId&&await this.replyToCall(r.callId,r.senderId,`\u5904\u7406\u5931\u8D25: ${n}`)}}}ensureRegistered(){if(!this.agentId)throw new Error("Agent is not registered")}delay(e){return new Promise(t=>{this.pollTimer=setTimeout(t,e)})}onNewCharacter(e){this.newCharacterHandler=e}getState(){return{agentId:this.agentId,displayName:this.displayName,projectId:this.projectId,isConnected:this.wsClient.isConnected(),isRunning:this.isRunning}}getAgentConfig(){return this.agentConfig}getServerConfig(){return this.serverConfig}reloadConfig(){g.loadConfig(),this.agentConfig=g.getAgentConfig(),s.info(`[AgentClient] \u914D\u7F6E\u5DF2\u91CD\u65B0\u52A0\u8F7D\uFF0C\u89D2\u8272: ${this.agentConfig.roleName}`)}enterDegradedMode(){this.isDegradedMode=!0,s.warn("[AgentClient] \u8FDB\u5165\u964D\u7EA7\u6A21\u5F0F\uFF0C\u5C06\u5728\u540E\u53F0\u6301\u7EED\u5C1D\u8BD5\u91CD\u8FDE")}exitDegradedMode(){this.isDegradedMode=!1,s.info("[AgentClient] \u9000\u51FA\u964D\u7EA7\u6A21\u5F0F")}isInDegradedMode(){return this.isDegradedMode}async retryRegistrationInBackground(e,t){let n=0;(async()=>{for(;this.isDegradedMode;)try{s.info(`[AgentClient] \u964D\u7EA7\u6A21\u5F0F\uFF1A\u5C1D\u8BD5\u91CD\u65B0\u6CE8\u518C (${n+1}/${t===-1?"\u65E0\u9650":t})`);const r=await this.register();s.info(`[AgentClient] \u964D\u7EA7\u6A21\u5F0F\uFF1A\u6CE8\u518C\u6210\u529F - ${r.displayName} (${r.agentId})`),this.exitDegradedMode(),this.messageHandler&&this.start(this.messageHandler);return}catch(r){n++;const a=r instanceof Error?r.message:String(r);if(s.warn(`[AgentClient] \u964D\u7EA7\u6A21\u5F0F\uFF1A\u6CE8\u518C\u5931\u8D25 (${n}/${t===-1?"\u65E0\u9650":t}): ${a}`),t>0&&n>=t){s.error("[AgentClient] \u964D\u7EA7\u6A21\u5F0F\uFF1A\u8FBE\u5230\u6700\u5927\u91CD\u8BD5\u6B21\u6570\uFF0C\u505C\u6B62\u91CD\u8FDE"),this.isDegradedMode=!1;return}await new Promise(d=>setTimeout(d,e))}})().catch(r=>{s.error("[AgentClient] \u964D\u7EA7\u6A21\u5F0F\u540E\u53F0\u91CD\u8BD5\u5FAA\u73AF\u5F02\u5E38\u9000\u51FA: error=%s, stack=%s",r instanceof Error?r.message:String(r),r instanceof Error?r.stack:"(no stack)")})}initializeStatusReporter(){if(!this.agentId){s.warn("[AgentClient] \u65E0\u6CD5\u521D\u59CB\u5316\u72B6\u6001\u62A5\u544A\u5668\uFF1AagentId \u4E3A\u7A7A");return}this.statusReporter=new y({agentId:this.agentId,sendStatusUpdate:e=>{this.wsClient.send({type:"AGENT_STATUS",data:e,timestamp:new Date().toISOString()})}}),C(e=>this.reportMcpNodeLog(e)),this.startRuntimeTokenRefresh(),s.info("[AgentClient] \u72B6\u6001\u62A5\u544A\u5668\u5DF2\u521D\u59CB\u5316")}startRuntimeTokenRefresh(){this.stopRuntimeTokenRefresh();const e=this.serverConfig.runtimeTokenRefreshIntervalMs;if(!e||e<=0){s.warn("[AgentClient] runtimeTokenRefreshIntervalMs \u672A\u914D\u7F6E\u6216\u65E0\u6548\uFF0C\u8DF3\u8FC7\u4E3B\u52A8\u7EED\u671F");return}const t=this.agentId;if(!t){s.warn("[AgentClient] agentId \u4E3A\u7A7A\uFF0C\u8DF3\u8FC7\u4E3B\u52A8\u7EED\u671F");return}this.runtimeTokenRefreshTimer=setInterval(async()=>{try{await this.httpClient.refreshRuntimeAccessToken(t)&&s.info("[AgentClient] runtimeAccessToken \u5DF2\u4E3B\u52A8\u7EED\u671F")}catch(n){s.warn("[AgentClient] \u4E3B\u52A8\u7EED\u671F runtimeAccessToken \u5931\u8D25: %s",n instanceof Error?n.message:String(n)),n instanceof Error&&n.stack&&s.warn("[AgentClient] \u4E3B\u52A8\u7EED\u671F\u5F02\u5E38\u5806\u6808:",n.stack)}},e),s.info(`[AgentClient] runtime token \u4E3B\u52A8\u7EED\u671F\u5DF2\u542F\u52A8\uFF0C\u95F4\u9694 ${e}ms`)}stopRuntimeTokenRefresh(){this.runtimeTokenRefreshTimer&&(clearInterval(this.runtimeTokenRefreshTimer),this.runtimeTokenRefreshTimer=null)}reportMcpNodeLog(e){const t=this.wsClient;!this.agentId||!this.wsClient.isConnected()||typeof t.sendMcpNodeLog!="function"||t.sendMcpNodeLog(e)}getStatusReporter(){return this.statusReporter}}export{N as AgentClient};
2
2
 
@@ -63,7 +63,7 @@ describe("AgentClient", () => {
63
63
  agentId: "agent-new-123",
64
64
  displayName: "test-role-A1B2",
65
65
  status: "online",
66
- projectName: "test-project",
66
+ projectId: "test-project",
67
67
  };
68
68
  Reflect.set(client, "httpClient", {
69
69
  callTool: async () => registerResult,
@@ -86,7 +86,7 @@ describe("AgentClient", () => {
86
86
  const profileInfo = createProfileInfo({
87
87
  id: "preset-agent-456",
88
88
  displayName: "Backend Expert-X7Y8",
89
- projectName: "demo",
89
+ projectId: "demo",
90
90
  workspacePath: "/workspace/demo",
91
91
  });
92
92
  Reflect.set(client, "httpClient", {
@@ -113,7 +113,7 @@ describe("AgentClient", () => {
113
113
  const offlineProfile = createProfileInfo({
114
114
  id: "preset-agent-456",
115
115
  displayName: "Backend Expert-X7Y8",
116
- projectName: "demo",
116
+ projectId: "demo",
117
117
  workspacePath: "/workspace/demo",
118
118
  isOnline: false,
119
119
  onlineSince: null,
@@ -121,7 +121,7 @@ describe("AgentClient", () => {
121
121
  const onlineProfile = createProfileInfo({
122
122
  id: "preset-agent-456",
123
123
  displayName: "Backend Expert-X7Y8",
124
- projectName: "demo",
124
+ projectId: "demo",
125
125
  workspacePath: "/workspace/demo",
126
126
  isOnline: true,
127
127
  });
@@ -150,7 +150,7 @@ describe("AgentClient", () => {
150
150
  assert.equal(getProfileCallCount, 2);
151
151
  assert.equal(result.agentId, "preset-agent-456");
152
152
  assert.equal(result.status, "online");
153
- assert.equal(result.projectName, "demo");
153
+ assert.equal(result.projectId, "demo");
154
154
  assert.equal(result.workspacePath, "/workspace/demo");
155
155
  });
156
156
  it("should throw error when registration fails without agentId", async () => {
@@ -191,7 +191,7 @@ describe("AgentClient", () => {
191
191
  it("should send group message with correct parameters", async () => {
192
192
  const client = new AgentClient();
193
193
  Reflect.set(client, "agentId", "agent-1");
194
- Reflect.set(client, "projectName", "demo");
194
+ Reflect.set(client, "projectId", "demo");
195
195
  let capturedArgs;
196
196
  Reflect.set(client, "httpClient", {
197
197
  callTool: async (_toolName, args) => {
@@ -201,7 +201,7 @@ describe("AgentClient", () => {
201
201
  });
202
202
  await client.sendGroupMessage("hello group", "demo", "project:demo");
203
203
  assert.equal(capturedArgs?.agentId, "agent-1");
204
- assert.equal(capturedArgs?.projectName, "demo");
204
+ assert.equal(capturedArgs?.projectId, "demo");
205
205
  assert.equal(capturedArgs?.roomId, "project:demo");
206
206
  assert.equal(capturedArgs?.content, "hello group");
207
207
  });
@@ -295,7 +295,7 @@ describe("AgentClient", () => {
295
295
  it("should call poll_message when pipeline task notifications are enabled", async () => {
296
296
  const client = new AgentClient();
297
297
  Reflect.set(client, "agentId", "agent-1");
298
- Reflect.set(client, "projectName", "demo");
298
+ Reflect.set(client, "projectId", "demo");
299
299
  const calledTools = [];
300
300
  const mockCallPoll1 = async (toolName) => {
301
301
  calledTools.push(toolName);
@@ -318,7 +318,7 @@ describe("AgentClient", () => {
318
318
  it("should recover server poll_message 503 as empty result for local retry", async () => {
319
319
  const client = new AgentClient();
320
320
  Reflect.set(client, "agentId", "agent-1");
321
- Reflect.set(client, "projectName", "demo");
321
+ Reflect.set(client, "projectId", "demo");
322
322
  const calledTools = [];
323
323
  const mockCallPoll2 = async (toolName) => {
324
324
  calledTools.push(toolName);
@@ -341,7 +341,7 @@ describe("AgentClient", () => {
341
341
  it("should recover client poll_message timeout as empty result for local retry", async () => {
342
342
  const client = new AgentClient();
343
343
  Reflect.set(client, "agentId", "agent-1");
344
- Reflect.set(client, "projectName", "demo");
344
+ Reflect.set(client, "projectId", "demo");
345
345
  const calledTools = [];
346
346
  const mockCallPoll3 = async (toolName) => {
347
347
  calledTools.push(toolName);
@@ -364,7 +364,7 @@ describe("AgentClient", () => {
364
364
  it("should not recover non-poll_message 503 errors", async () => {
365
365
  const client = new AgentClient();
366
366
  Reflect.set(client, "agentId", "agent-1");
367
- Reflect.set(client, "projectName", "demo");
367
+ Reflect.set(client, "projectId", "demo");
368
368
  Reflect.set(client, "httpClient", {
369
369
  callTool: async (toolName) => {
370
370
  if (toolName === "get_dm_messages") {
@@ -378,7 +378,7 @@ describe("AgentClient", () => {
378
378
  it("should not recover poll_message non-503 errors", async () => {
379
379
  const client = new AgentClient();
380
380
  Reflect.set(client, "agentId", "agent-1");
381
- Reflect.set(client, "projectName", "demo");
381
+ Reflect.set(client, "projectId", "demo");
382
382
  const mockCallPoll5 = async (toolName) => {
383
383
  if (toolName === "poll_message") {
384
384
  throw new Error("MCP tool poll_message call failed: 500 Internal Server Error");
@@ -394,7 +394,7 @@ describe("AgentClient", () => {
394
394
  it("should keep get_dm_messages for non-claiming message fetches", async () => {
395
395
  const client = new AgentClient();
396
396
  Reflect.set(client, "agentId", "agent-1");
397
- Reflect.set(client, "projectName", "demo");
397
+ Reflect.set(client, "projectId", "demo");
398
398
  const calledTools = [];
399
399
  Reflect.set(client, "httpClient", {
400
400
  callTool: async (toolName) => {
@@ -421,7 +421,7 @@ describe("AgentClient", () => {
421
421
  groups: [
422
422
  {
423
423
  id: "project:demo",
424
- projectName: "demo",
424
+ projectId: "demo",
425
425
  roomType: "project",
426
426
  scopeRefId: "demo",
427
427
  name: "demo group",
@@ -454,7 +454,7 @@ describe("AgentClient", () => {
454
454
  id: "agent-new",
455
455
  displayName: "Backend Dev-NEW",
456
456
  roleName: "backend-developer",
457
- projectName: "demo",
457
+ projectId: "demo",
458
458
  workspacePath: "/workspace/new",
459
459
  runtimeBridgeBaseUrl: "http://127.0.0.1:18081",
460
460
  runtimeStatus: "stopped",
@@ -477,7 +477,7 @@ describe("AgentClient", () => {
477
477
  const client = new AgentClient();
478
478
  Reflect.set(client, "agentId", "agent-1");
479
479
  const batchArgs = {
480
- projectName: "demo",
480
+ projectId: "demo",
481
481
  items: [
482
482
  {
483
483
  roleName: "backend-developer",
@@ -496,7 +496,7 @@ describe("AgentClient", () => {
496
496
  };
497
497
  const expectedResult = {
498
498
  batchId: "batch-1",
499
- projectName: "demo",
499
+ projectId: "demo",
500
500
  summary: {
501
501
  total: 2,
502
502
  approved: 1,
@@ -513,7 +513,7 @@ describe("AgentClient", () => {
513
513
  id: "agent-new-1",
514
514
  displayName: "Backend Dev-A",
515
515
  roleName: "backend-developer",
516
- projectName: "demo",
516
+ projectId: "demo",
517
517
  workspacePath: "/workspace/backend-a",
518
518
  },
519
519
  },
@@ -537,7 +537,7 @@ describe("AgentClient", () => {
537
537
  const result = await client.hireColleaguesBatch(batchArgs);
538
538
  assert.equal(capturedToolName, "hire_colleagues_batch");
539
539
  assert.equal(capturedArgs?.agentId, "agent-1");
540
- assert.equal(capturedArgs?.projectName, "demo");
540
+ assert.equal(capturedArgs?.projectId, "demo");
541
541
  assert.deepEqual(capturedArgs?.items, batchArgs.items);
542
542
  assert.deepEqual(result, expectedResult);
543
543
  });
@@ -572,7 +572,7 @@ describe("AgentClient", () => {
572
572
  const client = new AgentClient();
573
573
  Reflect.set(client, "agentId", "agent-1");
574
574
  Reflect.set(client, "displayName", "Agent One");
575
- Reflect.set(client, "projectName", "demo");
575
+ Reflect.set(client, "projectId", "demo");
576
576
  Reflect.set(client, "isRunning", false);
577
577
  Reflect.set(client, "wsClient", {
578
578
  isConnected: () => true,
@@ -580,7 +580,7 @@ describe("AgentClient", () => {
580
580
  const state = client.getState();
581
581
  assert.equal(state.agentId, "agent-1");
582
582
  assert.equal(state.displayName, "Agent One");
583
- assert.equal(state.projectName, "demo");
583
+ assert.equal(state.projectId, "demo");
584
584
  assert.equal(state.isConnected, true);
585
585
  assert.equal(state.isRunning, false);
586
586
  });
@@ -661,7 +661,7 @@ describe("AgentClient", () => {
661
661
  senderName: "Self",
662
662
  content: "self group message",
663
663
  timestamp: new Date().toISOString(),
664
- projectName: "demo",
664
+ projectId: "demo",
665
665
  };
666
666
  const handleIncomingGroup = Reflect.get(client, "handleIncomingGroup");
667
667
  handleIncomingGroup.call(client, selfGroupMessage);
@@ -672,10 +672,10 @@ describe("AgentClient", () => {
672
672
  it("should ignore malformed group message responses instead of returning undefined entries", async () => {
673
673
  const client = new AgentClient();
674
674
  Reflect.set(client, "agentId", "agent-self");
675
- Reflect.set(client, "projectName", "demo");
675
+ Reflect.set(client, "projectId", "demo");
676
676
  Reflect.set(client, "agentConfig", {
677
677
  roleName: "test-role",
678
- projectName: "demo",
678
+ projectId: "demo",
679
679
  workspacePath: "/workspace/demo",
680
680
  prompt: "",
681
681
  describe: "",
@@ -686,13 +686,13 @@ describe("AgentClient", () => {
686
686
  senderName: "Other",
687
687
  content: "hello",
688
688
  timestamp: new Date().toISOString(),
689
- projectName: "demo",
689
+ projectId: "demo",
690
690
  };
691
691
  const groups = {
692
692
  groups: [
693
693
  {
694
694
  id: "project:demo",
695
- projectName: "demo",
695
+ projectId: "demo",
696
696
  roomType: "project",
697
697
  scopeRefId: "demo",
698
698
  name: "demo 公共群聊",
@@ -700,7 +700,7 @@ describe("AgentClient", () => {
700
700
  },
701
701
  {
702
702
  id: "inner_group:g-1",
703
- projectName: "demo",
703
+ projectId: "demo",
704
704
  roomType: "inner_group",
705
705
  scopeRefId: "g-1",
706
706
  name: "小组",
@@ -729,10 +729,10 @@ describe("AgentClient", () => {
729
729
  it("should keep other room messages when one room unread fetch throws", async () => {
730
730
  const client = new AgentClient();
731
731
  Reflect.set(client, "agentId", "agent-self");
732
- Reflect.set(client, "projectName", "demo");
732
+ Reflect.set(client, "projectId", "demo");
733
733
  Reflect.set(client, "agentConfig", {
734
734
  roleName: "test-role",
735
- projectName: "demo",
735
+ projectId: "demo",
736
736
  workspacePath: "/workspace/demo",
737
737
  prompt: "",
738
738
  describe: "",
@@ -743,13 +743,13 @@ describe("AgentClient", () => {
743
743
  senderName: "Other",
744
744
  content: "restored after restart",
745
745
  timestamp: new Date().toISOString(),
746
- projectName: "demo",
746
+ projectId: "demo",
747
747
  };
748
748
  const groups = {
749
749
  groups: [
750
750
  {
751
751
  id: "project:demo",
752
- projectName: "demo",
752
+ projectId: "demo",
753
753
  roomType: "project",
754
754
  scopeRefId: "demo",
755
755
  name: "demo 公共群聊",
@@ -757,7 +757,7 @@ describe("AgentClient", () => {
757
757
  },
758
758
  {
759
759
  id: "inner_group:g-1",
760
- projectName: "demo",
760
+ projectId: "demo",
761
761
  roomType: "inner_group",
762
762
  scopeRefId: "g-1",
763
763
  name: "小组",
@@ -787,16 +787,16 @@ describe("AgentClient", () => {
787
787
  });
788
788
  });
789
789
  describe("project name update from profile", () => {
790
- it("should update projectName when receiving profile with projectName", () => {
790
+ it("should update projectId when receiving profile with projectId", () => {
791
791
  const client = new AgentClient();
792
- Reflect.set(client, "projectName", null);
792
+ Reflect.set(client, "projectId", null);
793
793
  const profile = createProfileInfo({
794
- projectName: "server-assigned-project",
794
+ projectId: "server-assigned-project",
795
795
  });
796
796
  Reflect.set(client, "profileHandler", null);
797
797
  const handleProfileInfo = Reflect.get(client, "handleProfileInfo");
798
798
  handleProfileInfo.call(client, profile);
799
- assert.equal(Reflect.get(client, "projectName"), "server-assigned-project");
799
+ assert.equal(Reflect.get(client, "projectId"), "server-assigned-project");
800
800
  });
801
801
  });
802
802
  });
@@ -1,2 +1,2 @@
1
- import{logger as o}from"./logger.js";const T="ws://localhost:8080/ws/agent",u=3e3,_=9e3,A=200,m=3e4,C=1e3,R=-1,d=12*60*60*1e3,v=12e4,I=`http://127.0.0.1:${process.env.AWS_RUNTIME_BRIDGE_PORT||"18081"}`;function i(n){return n.replace(/^((?:https?|wss?):\/\/(?:\[[^\]]+\]|[^/:?#]+):\d+):\d+(?=\/|$)/i,"$1")}function c(n){const t=n.toLowerCase();return t==="localhost"||t==="::1"||t==="[::1]"?"127.0.0.1":t}function h(n){const t=String(n||"").trim();if(!t)return;const r=i(t);try{const e=new URL(r);return e.protocol==="ws:"?e.protocol="http:":e.protocol==="wss:"?e.protocol="https:":e.protocol=e.protocol.toLowerCase(),e.hostname=c(e.hostname),e.origin}catch{return r.replace(/\/+$/,"")}}function S(n){const t=String(n||"").trim();if(!t)return;const r=i(t);try{const e=new URL(r);return e.protocol==="http:"?e.protocol="ws:":e.protocol==="https:"?e.protocol="wss:":e.protocol!=="ws:"&&e.protocol!=="wss:"&&(e.protocol="ws:"),e.hostname=c(e.hostname),e.pathname=e.pathname.includes("/ws/agent")?e.pathname:`${e.pathname.replace(/\/$/,"")}/ws/agent`,e.search="",e.hash="",e.toString()}catch{const e=h(r);return e?`${e}/ws/agent`.replace(/^http:/,"ws:").replace(/^https:/,"wss:"):void 0}}function E(n){const t=String(n||"").trim();if(!t)return;const r=i(t);try{const e=new URL(r);return e.protocol==="ws:"?e.protocol="http:":e.protocol==="wss:"?e.protocol="https:":e.protocol!=="http:"&&e.protocol!=="https:"&&(e.protocol="http:"),e.hostname=c(e.hostname),e.pathname=e.pathname.includes("/mcp/call")?e.pathname:`${e.pathname.replace(/\/$/,"")}/mcp/call`,e.search="",e.hash="",e.toString()}catch{const e=h(r);return e?`${e}/mcp/call`:void 0}}class U{agentConfig=null;serverConfig=null;loadConfig(){const t=process.env.AWS_WORKSPACE_PATH||process.cwd();this.agentConfig={roleName:process.env.AWS_ROLE_NAME||"",agentId:process.env.AWS_AGENT_ID||void 0,projectName:process.env.AWS_PROJECT_NAME||"default",workspacePath:t,prompt:process.env.AWS_PROMPT||"",describe:""},o.info("[Config] MCP \u5BA2\u6237\u7AEF\u914D\u7F6E\u5DF2\u52A0\u8F7D"),o.info(`[Config] \u5DE5\u4F5C\u76EE\u5F55: ${this.agentConfig.workspacePath}`),o.info(`[Config] \u9879\u76EE\u540D: ${this.agentConfig.projectName}`),this.agentConfig.agentId&&o.info(`[Config] \u9884\u8BBE AgentID: ${this.agentConfig.agentId}`),this.serverConfig={serverUrl:process.env.AWS_SERVER_URL||T,heartbeatInterval:parseInt(process.env.AWS_HEARTBEAT_INTERVAL||String(u),10),heartbeatTimeout:parseInt(process.env.AWS_HEARTBEAT_TIMEOUT||String(_),10),reconnectInterval:A,reconnectMaxInterval:this.parsePositiveIntegerEnv("AWS_RECONNECT_MAX_INTERVAL",m),reconnectJitterMs:this.parsePositiveIntegerEnv("AWS_RECONNECT_JITTER_MS",C),maxReconnectAttempts:R,userId:process.env.AWS_USER_ID||void 0,runtimeBridgeBaseUrl:process.env.AWS_RUNTIME_BRIDGE_BASE_URL||I,mcpHttpUrl:process.env.AWS_MCP_HTTP_URL||void 0,runtimeTokenRefreshIntervalMs:this.parseRuntimeTokenRefreshInterval(),mcpHttpRequestTimeoutMs:this.parsePositiveIntegerEnv("AWS_MCP_HTTP_REQUEST_TIMEOUT_MS",v)},o.info(`[Config] \u670D\u52A1\u5668\u5730\u5740: ${this.serverConfig.serverUrl}`)}applyRuntimeLaunchBinding(t){if(!this.agentConfig||!this.serverConfig)throw new Error("Configuration is not loaded. Call loadConfig() first.");const r=String(t.agentId||"").trim();r&&(this.agentConfig.agentId=r);const e=String(t.workspacePath||"").trim();e&&(this.agentConfig.workspacePath=e);const s=String(t.runtimeAccessToken||"").trim();s&&(this.serverConfig.runtimeAccessToken=s);const a=String(t.runtimeAccessTokenExpiresAt||"").trim();a&&(this.serverConfig.runtimeAccessTokenExpiresAt=a);const p=String(t.userId||"").trim();p&&(this.serverConfig.userId=p);const l=S(t.serverUrl||t.schedulerBaseUrl);l&&(this.serverConfig.serverUrl=l);const f=E(t.mcpHttpUrl);if(f)this.serverConfig.mcpHttpUrl=f;else if(t.schedulerBaseUrl){const g=E(t.schedulerBaseUrl);g&&(this.serverConfig.mcpHttpUrl=g)}o.info(`[Config] \u5DF2\u5E94\u7528 runtime-bridge \u542F\u52A8\u7ED1\u5B9A: agentId=${this.agentConfig.agentId||"(\u7A7A)"}`)}parseRuntimeTokenRefreshInterval(){return this.parsePositiveIntegerEnv("AWS_RUNTIME_TOKEN_REFRESH_INTERVAL_MS",d)}parsePositiveIntegerEnv(t,r){const e=process.env[t];if(!e||!e.trim())return r;const s=Number.parseInt(e,10);return!Number.isFinite(s)||s<=0?(o.warn(`[Config] ${t} \u65E0\u6548\uFF0C\u4F7F\u7528\u9ED8\u8BA4\u503C ${r}ms`),r):s}updateRuntimeAccessToken(t){if(!this.serverConfig)return!1;const r=t.trim();return!r||r===this.serverConfig.runtimeAccessToken?!1:(this.serverConfig.runtimeAccessToken=r,o.info("[Config] runtimeAccessToken \u5DF2\u66F4\u65B0\uFF08401 \u6062\u590D\uFF09"),!0)}getAgentConfig(){if(!this.agentConfig)throw new Error("Configuration is not loaded. Call loadConfig() first.");return this.agentConfig}getServerConfig(){if(!this.serverConfig)throw new Error("Configuration is not loaded. Call loadConfig() first.");return this.serverConfig}}const M=new U;export{U as ConfigManager,M as configManager};
1
+ import{logger as o}from"./logger.js";const T="ws://localhost:8080/ws/agent",u=3e3,_=9e3,A=200,C=3e4,m=1e3,R=-1,d=12*60*60*1e3,I=12e4,v=`http://127.0.0.1:${process.env.AWS_RUNTIME_BRIDGE_PORT||"18081"}`;function i(n){return n.replace(/^((?:https?|wss?):\/\/(?:\[[^\]]+\]|[^/:?#]+):\d+):\d+(?=\/|$)/i,"$1")}function c(n){const t=n.toLowerCase();return t==="localhost"||t==="::1"||t==="[::1]"?"127.0.0.1":t}function h(n){const t=String(n||"").trim();if(!t)return;const r=i(t);try{const e=new URL(r);return e.protocol==="ws:"?e.protocol="http:":e.protocol==="wss:"?e.protocol="https:":e.protocol=e.protocol.toLowerCase(),e.hostname=c(e.hostname),e.origin}catch{return r.replace(/\/+$/,"")}}function S(n){const t=String(n||"").trim();if(!t)return;const r=i(t);try{const e=new URL(r);return e.protocol==="http:"?e.protocol="ws:":e.protocol==="https:"?e.protocol="wss:":e.protocol!=="ws:"&&e.protocol!=="wss:"&&(e.protocol="ws:"),e.hostname=c(e.hostname),e.pathname=e.pathname.includes("/ws/agent")?e.pathname:`${e.pathname.replace(/\/$/,"")}/ws/agent`,e.search="",e.hash="",e.toString()}catch{const e=h(r);return e?`${e}/ws/agent`.replace(/^http:/,"ws:").replace(/^https:/,"wss:"):void 0}}function E(n){const t=String(n||"").trim();if(!t)return;const r=i(t);try{const e=new URL(r);return e.protocol==="ws:"?e.protocol="http:":e.protocol==="wss:"?e.protocol="https:":e.protocol!=="http:"&&e.protocol!=="https:"&&(e.protocol="http:"),e.hostname=c(e.hostname),e.pathname=e.pathname.includes("/mcp/call")?e.pathname:`${e.pathname.replace(/\/$/,"")}/mcp/call`,e.search="",e.hash="",e.toString()}catch{const e=h(r);return e?`${e}/mcp/call`:void 0}}class U{agentConfig=null;serverConfig=null;loadConfig(){const t=process.env.AWS_WORKSPACE_PATH||process.cwd();this.agentConfig={roleName:process.env.AWS_ROLE_NAME||"",agentId:process.env.AWS_AGENT_ID||void 0,projectId:process.env.AWS_PROJECT_NAME||"default",workspacePath:t,prompt:process.env.AWS_PROMPT||"",describe:""},o.info("[Config] MCP \u5BA2\u6237\u7AEF\u914D\u7F6E\u5DF2\u52A0\u8F7D"),o.info(`[Config] \u5DE5\u4F5C\u76EE\u5F55: ${this.agentConfig.workspacePath}`),o.info(`[Config] \u9879\u76EE\u540D: ${this.agentConfig.projectId}`),this.agentConfig.agentId&&o.info(`[Config] \u9884\u8BBE AgentID: ${this.agentConfig.agentId}`),this.serverConfig={serverUrl:process.env.AWS_SERVER_URL||T,heartbeatInterval:parseInt(process.env.AWS_HEARTBEAT_INTERVAL||String(u),10),heartbeatTimeout:parseInt(process.env.AWS_HEARTBEAT_TIMEOUT||String(_),10),reconnectInterval:A,reconnectMaxInterval:this.parsePositiveIntegerEnv("AWS_RECONNECT_MAX_INTERVAL",C),reconnectJitterMs:this.parsePositiveIntegerEnv("AWS_RECONNECT_JITTER_MS",m),maxReconnectAttempts:R,userId:process.env.AWS_USER_ID||void 0,runtimeBridgeBaseUrl:process.env.AWS_RUNTIME_BRIDGE_BASE_URL||v,mcpHttpUrl:process.env.AWS_MCP_HTTP_URL||void 0,runtimeTokenRefreshIntervalMs:this.parseRuntimeTokenRefreshInterval(),mcpHttpRequestTimeoutMs:this.parsePositiveIntegerEnv("AWS_MCP_HTTP_REQUEST_TIMEOUT_MS",I)},o.info(`[Config] \u670D\u52A1\u5668\u5730\u5740: ${this.serverConfig.serverUrl}`)}applyRuntimeLaunchBinding(t){if(!this.agentConfig||!this.serverConfig)throw new Error("Configuration is not loaded. Call loadConfig() first.");const r=String(t.agentId||"").trim();r&&(this.agentConfig.agentId=r);const e=String(t.workspacePath||"").trim();e&&(this.agentConfig.workspacePath=e);const s=String(t.runtimeAccessToken||"").trim();s&&(this.serverConfig.runtimeAccessToken=s);const a=String(t.runtimeAccessTokenExpiresAt||"").trim();a&&(this.serverConfig.runtimeAccessTokenExpiresAt=a);const p=String(t.userId||"").trim();p&&(this.serverConfig.userId=p);const l=S(t.serverUrl||t.schedulerBaseUrl);l&&(this.serverConfig.serverUrl=l);const f=E(t.mcpHttpUrl);if(f)this.serverConfig.mcpHttpUrl=f;else if(t.schedulerBaseUrl){const g=E(t.schedulerBaseUrl);g&&(this.serverConfig.mcpHttpUrl=g)}o.info(`[Config] \u5DF2\u5E94\u7528 runtime-bridge \u542F\u52A8\u7ED1\u5B9A: agentId=${this.agentConfig.agentId||"(\u7A7A)"}`)}parseRuntimeTokenRefreshInterval(){return this.parsePositiveIntegerEnv("AWS_RUNTIME_TOKEN_REFRESH_INTERVAL_MS",d)}parsePositiveIntegerEnv(t,r){const e=process.env[t];if(!e||!e.trim())return r;const s=Number.parseInt(e,10);return!Number.isFinite(s)||s<=0?(o.warn(`[Config] ${t} \u65E0\u6548\uFF0C\u4F7F\u7528\u9ED8\u8BA4\u503C ${r}ms`),r):s}updateRuntimeAccessToken(t){if(!this.serverConfig)return!1;const r=t.trim();return!r||r===this.serverConfig.runtimeAccessToken?!1:(this.serverConfig.runtimeAccessToken=r,o.info("[Config] runtimeAccessToken \u5DF2\u66F4\u65B0\uFF08401 \u6062\u590D\uFF09"),!0)}getAgentConfig(){if(!this.agentConfig)throw new Error("Configuration is not loaded. Call loadConfig() first.");return this.agentConfig}getServerConfig(){if(!this.serverConfig)throw new Error("Configuration is not loaded. Call loadConfig() first.");return this.serverConfig}}const M=new U;export{U as ConfigManager,M as configManager};
2
2
 
@@ -27,7 +27,7 @@ describe('ConfigManager', () => {
27
27
  const agentConfig = configManager.getAgentConfig();
28
28
  const serverConfig = configManager.getServerConfig();
29
29
  assert.equal(agentConfig.roleName, '');
30
- assert.equal(agentConfig.projectName, 'default');
30
+ assert.equal(agentConfig.projectId, 'default');
31
31
  assert.equal(serverConfig.serverUrl, 'ws://localhost:8080/ws/agent');
32
32
  assert.equal(serverConfig.heartbeatInterval, 3000);
33
33
  assert.equal(serverConfig.mcpHttpRequestTimeoutMs, 120000);
@@ -71,7 +71,7 @@ describe('ConfigManager', () => {
71
71
  process.env.AWS_PROJECT_NAME = 'my-project';
72
72
  configManager.loadConfig();
73
73
  const agentConfig = configManager.getAgentConfig();
74
- assert.equal(agentConfig.projectName, 'my-project');
74
+ assert.equal(agentConfig.projectId, 'my-project');
75
75
  });
76
76
  it('loads prompt from env', () => {
77
77
  process.env.AWS_PROMPT = 'You are a helpful assistant';
@@ -49,6 +49,8 @@ export declare class McpServer {
49
49
  constructor();
50
50
  private setupHandlers;
51
51
 
52
+ private buildToolResultContent;
53
+
52
54
  private handleToolCall;
53
55
 
54
56
  private executeToolCall;