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.
- package/README.md +2 -0
- package/dist/adapter/AcodeSdkAdapter.d.ts +2 -0
- package/dist/adapter/AcodeSdkAdapter.js +3 -3
- package/dist/index.js +1 -1
- package/dist/remote-desktop/computer-use-backend.d.ts +111 -0
- package/dist/remote-desktop/computer-use-backend.js +1 -0
- package/dist/remote-desktop/types.d.ts +79 -0
- package/dist/routes/computer.d.ts +1 -0
- package/dist/routes/computer.js +2 -0
- package/dist/routes/file-change-diff.d.ts +27 -0
- package/dist/routes/file-change-diff.js +5 -0
- package/dist/routes/instance.js +2 -2
- package/dist/routes/pty.d.ts +2 -2
- package/dist/routes/pty.js +3 -3
- package/dist/routes/task-context.js +1 -1
- package/dist/routes/terminal.js +28 -28
- package/dist/services/auto-register.d.ts +1 -1
- package/dist/services/auto-register.js +1 -1
- package/dist/services/instance-features.d.ts +10 -0
- package/dist/services/instance-features.js +2 -0
- package/dist/services/sdk-tool-file-change-recorder.d.ts +12 -0
- package/dist/services/sdk-tool-file-change-recorder.js +2 -0
- package/dist/services/workspace-files.js +1 -1
- package/dist/services/workspaceTaskChangeWatcher.d.ts +9 -1
- package/dist/services/workspaceTaskChangeWatcher.js +3 -1
- package/package/acode/dist/built-in-file-tools.d.ts +4 -0
- package/package/acode/dist/built-in-file-tools.js +2 -2
- package/package/acode/dist/runtime.d.ts +13 -0
- package/package/acode/dist/runtime.js +18 -18
- package/package/aws-client-agent-mcp/README.md +2 -2
- package/package/aws-client-agent-mcp/dist/agent-client.d.ts +14 -4
- package/package/aws-client-agent-mcp/dist/agent-client.js +1 -1
- package/package/aws-client-agent-mcp/dist/agent-client.test.js +36 -36
- package/package/aws-client-agent-mcp/dist/config.js +1 -1
- package/package/aws-client-agent-mcp/dist/config.test.js +2 -2
- package/package/aws-client-agent-mcp/dist/mcp-server.d.ts +2 -0
- package/package/aws-client-agent-mcp/dist/mcp-server.js +21 -21
- package/package/aws-client-agent-mcp/dist/mcp-server.test.js +35 -36
- package/package/aws-client-agent-mcp/dist/mcp-tools.d.ts +6 -0
- package/package/aws-client-agent-mcp/dist/mcp-tools.js +25 -5
- package/package/aws-client-agent-mcp/dist/mcp-tools.test.js +17 -1
- package/package/aws-client-agent-mcp/dist/runtime-launch-binding.test.js +1 -1
- package/package/aws-client-agent-mcp/dist/types.d.ts +14 -12
- package/package/aws-client-agent-mcp/dist/websocket-client.js +1 -1
- package/package.json +3 -2
- 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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
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, "
|
|
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?.
|
|
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, "
|
|
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, "
|
|
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, "
|
|
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, "
|
|
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, "
|
|
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, "
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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?.
|
|
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, "
|
|
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.
|
|
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
|
-
|
|
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, "
|
|
675
|
+
Reflect.set(client, "projectId", "demo");
|
|
676
676
|
Reflect.set(client, "agentConfig", {
|
|
677
677
|
roleName: "test-role",
|
|
678
|
-
|
|
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
|
-
|
|
689
|
+
projectId: "demo",
|
|
690
690
|
};
|
|
691
691
|
const groups = {
|
|
692
692
|
groups: [
|
|
693
693
|
{
|
|
694
694
|
id: "project:demo",
|
|
695
|
-
|
|
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
|
-
|
|
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, "
|
|
732
|
+
Reflect.set(client, "projectId", "demo");
|
|
733
733
|
Reflect.set(client, "agentConfig", {
|
|
734
734
|
roleName: "test-role",
|
|
735
|
-
|
|
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
|
-
|
|
746
|
+
projectId: "demo",
|
|
747
747
|
};
|
|
748
748
|
const groups = {
|
|
749
749
|
groups: [
|
|
750
750
|
{
|
|
751
751
|
id: "project:demo",
|
|
752
|
-
|
|
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
|
-
|
|
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
|
|
790
|
+
it("should update projectId when receiving profile with projectId", () => {
|
|
791
791
|
const client = new AgentClient();
|
|
792
|
-
Reflect.set(client, "
|
|
792
|
+
Reflect.set(client, "projectId", null);
|
|
793
793
|
const profile = createProfileInfo({
|
|
794
|
-
|
|
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, "
|
|
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,
|
|
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.
|
|
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.
|
|
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';
|