aws-runtime-bridge 1.9.98 → 1.9.100

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 (120) hide show
  1. package/dist/adapter/AcodeSdkAdapter.d.ts +7 -1
  2. package/dist/adapter/AcodeSdkAdapter.js +5 -5
  3. package/dist/adapter/ClaudeSdkAdapter.d.ts +4 -0
  4. package/dist/adapter/ClaudeSdkAdapter.js +2 -2
  5. package/dist/adapter/CodexSdkAdapter.d.ts +2 -0
  6. package/dist/adapter/CodexSdkAdapter.js +3 -3
  7. package/dist/adapter/OpencodeSdkAdapter.d.ts +2 -0
  8. package/dist/adapter/OpencodeSdkAdapter.js +2 -2
  9. package/dist/adapter/idle-poll-loop.d.ts +4 -1
  10. package/dist/adapter/idle-poll-loop.js +1 -1
  11. package/dist/adapter/types.d.ts +4 -2
  12. package/dist/browser/browser-pool.d.ts +73 -0
  13. package/dist/browser/browser-pool.js +2 -0
  14. package/dist/browser/browser-profile-store.d.ts +28 -0
  15. package/dist/browser/browser-profile-store.js +2 -0
  16. package/dist/browser/built-in-browser-tools.d.ts +27 -0
  17. package/dist/browser/built-in-browser-tools.js +2 -0
  18. package/dist/browser/element-locator.d.ts +24 -0
  19. package/dist/browser/element-locator.js +2 -0
  20. package/dist/browser/element-picker.d.ts +17 -0
  21. package/dist/browser/element-picker.js +2 -0
  22. package/dist/browser/input-dispatcher.d.ts +34 -0
  23. package/dist/browser/input-dispatcher.js +2 -0
  24. package/dist/browser/listener-store.d.ts +32 -0
  25. package/dist/browser/listener-store.js +2 -0
  26. package/dist/browser/page-listener-manager.d.ts +106 -0
  27. package/dist/browser/page-listener-manager.js +307 -0
  28. package/dist/browser/page-listener-types.d.ts +90 -0
  29. package/dist/browser/page-listener-types.js +1 -0
  30. package/dist/browser/screencast-manager.d.ts +42 -0
  31. package/dist/browser/screencast-manager.js +2 -0
  32. package/dist/browser/snapshot-serializer.d.ts +15 -0
  33. package/dist/browser/snapshot-serializer.js +5 -0
  34. package/dist/browser/ssrf-guard.d.ts +15 -0
  35. package/dist/browser/ssrf-guard.js +2 -0
  36. package/dist/browser/stealth.d.ts +7 -0
  37. package/dist/browser/stealth.js +173 -0
  38. package/dist/browser/step-archive.d.ts +52 -0
  39. package/dist/browser/step-archive.js +2 -0
  40. package/dist/browser/types.d.ts +192 -0
  41. package/dist/browser/types.js +2 -0
  42. package/dist/browser/ws-server.d.ts +67 -0
  43. package/dist/browser/ws-server.js +2 -0
  44. package/dist/index.js +1 -1
  45. package/dist/middleware/auth.d.ts +2 -0
  46. package/dist/middleware/auth.js +1 -1
  47. package/dist/remote-desktop/computer-control.d.ts +30 -0
  48. package/dist/remote-desktop/computer-control.js +2 -0
  49. package/dist/remote-desktop/coords.d.ts +13 -0
  50. package/dist/remote-desktop/coords.js +2 -0
  51. package/dist/remote-desktop/frame-backpressure.d.ts +7 -0
  52. package/dist/remote-desktop/frame-backpressure.js +2 -0
  53. package/dist/remote-desktop/index.d.ts +7 -0
  54. package/dist/remote-desktop/index.js +4 -0
  55. package/dist/remote-desktop/input-backends/interface.d.ts +17 -0
  56. package/dist/remote-desktop/input-backends/interface.js +1 -0
  57. package/dist/remote-desktop/input-backends/key-map.d.ts +2 -0
  58. package/dist/remote-desktop/input-backends/key-map.js +2 -0
  59. package/dist/remote-desktop/input-dispatcher.d.ts +11 -0
  60. package/dist/remote-desktop/input-dispatcher.js +2 -0
  61. package/dist/remote-desktop/permission-manager.d.ts +7 -0
  62. package/dist/remote-desktop/permission-manager.js +2 -0
  63. package/dist/remote-desktop/screen-capture.d.ts +27 -0
  64. package/dist/remote-desktop/screen-capture.js +2 -0
  65. package/dist/remote-desktop/session-manager.d.ts +59 -0
  66. package/dist/remote-desktop/session-manager.js +2 -0
  67. package/dist/remote-desktop/system-backend.d.ts +65 -0
  68. package/dist/remote-desktop/system-backend.js +5 -0
  69. package/dist/remote-desktop/types.d.ts +68 -0
  70. package/dist/remote-desktop/types.js +1 -0
  71. package/dist/remote-desktop/ui-automation.d.ts +48 -0
  72. package/dist/remote-desktop/ui-automation.js +31 -0
  73. package/dist/remote-desktop/win32-api.d.ts +29 -0
  74. package/dist/remote-desktop/win32-api.js +2 -0
  75. package/dist/routes/background-tasks.d.ts +2 -0
  76. package/dist/routes/background-tasks.js +2 -0
  77. package/dist/routes/browser-listeners.d.ts +2 -0
  78. package/dist/routes/browser-listeners.js +2 -0
  79. package/dist/routes/browser-sessions.d.ts +2 -0
  80. package/dist/routes/browser-sessions.js +2 -0
  81. package/dist/routes/pty.js +3 -3
  82. package/dist/routes/terminal.js +30 -30
  83. package/dist/services/agent-pty-manager.d.ts +22 -0
  84. package/dist/services/agent-pty-manager.js +5 -0
  85. package/dist/services/browser-session-manager.d.ts +55 -0
  86. package/dist/services/browser-session-manager.js +12 -0
  87. package/dist/services/cli-commands.d.ts +4 -0
  88. package/dist/services/cli-commands.js +5 -5
  89. package/package/acode/dist/await-complete-tool.d.ts +17 -0
  90. package/package/acode/dist/await-complete-tool.js +21 -0
  91. package/package/acode/dist/background-command-manager.d.ts +148 -0
  92. package/package/acode/dist/background-command-manager.js +8 -0
  93. package/package/acode/dist/background-command-store.d.ts +46 -0
  94. package/package/acode/dist/background-command-store.js +2 -0
  95. package/package/acode/dist/background-command-tools.d.ts +5 -0
  96. package/package/acode/dist/background-command-tools.js +18 -0
  97. package/package/acode/dist/background-output-ringbuffer.d.ts +23 -0
  98. package/package/acode/dist/background-output-ringbuffer.js +3 -0
  99. package/package/acode/dist/built-in-file-tools.d.ts +8 -1
  100. package/package/acode/dist/built-in-file-tools.js +2 -2
  101. package/package/acode/dist/compaction.js +6 -6
  102. package/package/acode/dist/index.d.ts +1 -0
  103. package/package/acode/dist/index.js +1 -1
  104. package/package/acode/dist/runtime.d.ts +6 -0
  105. package/package/acode/dist/runtime.js +27 -27
  106. package/package/acode/dist/sub-agent-tools.d.ts +0 -1
  107. package/package/acode/dist/sub-agent-tools.js +11 -28
  108. package/package/acode/dist/terminal-tool.d.ts +7 -0
  109. package/package/acode/dist/terminal-tool.js +2 -0
  110. package/package/acode/dist/terminal-types.d.ts +38 -0
  111. package/package/acode/dist/terminal-types.js +1 -0
  112. package/package/acode/dist/types.d.ts +10 -1
  113. package/package/aws-client-agent-mcp/dist/agent-client.d.ts +3 -1
  114. package/package/aws-client-agent-mcp/dist/agent-client.js +1 -1
  115. package/package/aws-client-agent-mcp/dist/logger.d.ts +2 -0
  116. package/package/aws-client-agent-mcp/dist/logger.js +1 -1
  117. package/package/aws-client-agent-mcp/dist/mcp-server.d.ts +8 -0
  118. package/package/aws-client-agent-mcp/dist/mcp-server.js +30 -19
  119. package/package/aws-client-agent-mcp/dist/types.d.ts +25 -0
  120. package/package.json +6 -2
@@ -0,0 +1,7 @@
1
+
2
+ import type { ACodeBuiltInTool } from "./built-in-file-tools.js";
3
+ import type { TerminalManager } from "./terminal-types.js";
4
+ export interface TerminalToolDeps {
5
+ terminalManager?: TerminalManager;
6
+ }
7
+ export declare function createTerminalTool(agentId: string, deps: TerminalToolDeps): ACodeBuiltInTool;
@@ -0,0 +1,2 @@
1
+ const a=["create","write","read","kill","resize"],u='Open a persistent interactive terminal (real PTY) for commands that require stdin input or need to keep state (cwd/env) across multiple commands.\nExamples: ssh to a remote host, git push that prompts for credentials, entering a remote shell, or a multi-step shell workflow.\nUse action=create to start a shell session (returns session_id), action=write to send keystrokes/commands (must end with \\n to execute), action=read to get incremental output since last read (status=running|exited; needs_input hints the program is waiting for input), action=kill to terminate, action=resize to adjust size.\nFor non-interactive one-shot commands use the Bash tool; for long-running non-interactive builds/servers use Bash with run_in_background.\n\nAVOID entering interactive pagers (less/man/more/most) or full-screen TUIs (vim/nano/top/htop) inside this terminal \u2014 they wait for keystrokes that block agent progress. Prefer non-interactive alternatives: `git --no-pager log`, `git --no-pager diff`, `man <topic> | cat`, `cat <file>`, `head -n 200 <file>`, `grep -n <pattern> <file>`. If you DO enter a pager by accident, send `q` (to quit) immediately via action=write; if you see "(press RETURN)" / "Press ENTER to continue" hints, send a single `\\r` to dismiss them.';function p(c,d){const i=d.terminalManager;return{kind:"builtin",toolName:"Terminal",exposedName:"Terminal",description:u,inputSchema:{type:"object",properties:{action:{type:"string",enum:[...a],description:"create=new terminal session; write=send input/command (end with \\n); read=incremental output since last read; kill=terminate session; resize=adjust terminal size"},session_id:{type:"string",description:"Session id returned by action=create"},command:{type:"string",description:"For create: optional initial command (e.g. 'ssh user@host'). For write: text to send; MUST end with \\n to execute (e.g. 'ls -la\\n'). For password prompts send '<password>\\n'."},cwd:{type:"string",description:"create: initial working directory (must be within allowed workspace roots)"},shell:{type:"string",enum:["auto","bash","sh","zsh","fish","pwsh","powershell","cmd"],default:"auto",description:"create: login shell to spawn. 'auto' lets the bridge pick the platform default (Windows\u2192pwsh/powershell/cmd, Unix\u2192$SHELL/bash); recommended to avoid 'File not found' on Windows where bash is absent."},timeout_ms:{type:"number",description:"Reserved. Terminal sessions persist; an idle session is reclaimed after 30min of no agent activity. Long-running non-interactive commands should use Bash run_in_background instead."},cols:{type:"number",default:120,description:"terminal columns"},rows:{type:"number",default:30,description:"terminal rows"},read_lines:{type:"number",default:200,description:"read: max lines to return (tail); excess marked truncated"}},required:["action"],additionalProperties:!1},async execute(e){if(!i)return{error:"Terminal \u672A\u542F\u7528\uFF1Abridge \u672A\u6CE8\u5165 terminalManager"};const s=String(e.action??"");try{switch(s){case"create":{const t=typeof e.shell=="string"&&e.shell.trim()?e.shell.trim():"auto",n=typeof e.cwd=="string"&&e.cwd.trim()?e.cwd.trim():process.cwd(),r=typeof e.cols=="number"?e.cols:120,l=typeof e.rows=="number"?e.rows:30,m=typeof e.command=="string"?e.command:"",o=i.create({agentId:c,shell:t,cwd:n,cols:r,rows:l,preCommand:m});return{session_id:o.id,pid:o.pid??null,status:"running"}}case"write":{const t=String(e.session_id??"");if(!t)return{error:"write \u9700\u8981 session_id"};const n=typeof e.command=="string"?e.command:"";return i.write(t,n),{ok:!0}}case"read":{const t=String(e.session_id??"");if(!t)return{error:"read \u9700\u8981 session_id"};const n=typeof e.read_lines=="number"?e.read_lines:200;return i.read(t,{lines:n})}case"kill":{const t=String(e.session_id??"");return t?(i.kill(t),{ok:!0}):{error:"kill \u9700\u8981 session_id"}}case"resize":{const t=String(e.session_id??"");if(!t)return{error:"resize \u9700\u8981 session_id"};const n=typeof e.cols=="number"?e.cols:120,r=typeof e.rows=="number"?e.rows:30;return i.resize(t,n,r),{ok:!0}}default:return{error:`\u672A\u77E5 action: ${s}\uFF08\u5141\u8BB8\uFF1A${a.join(", ")}\uFF09`}}}catch(t){const n=t instanceof Error?t.message:String(t);return{error:`Terminal.${s} \u5931\u8D25\uFF1A${n}`}}}}}export{p as createTerminalTool};
2
+
@@ -0,0 +1,38 @@
1
+
2
+ export type TerminalAction = "create" | "write" | "read" | "kill" | "resize";
3
+ export interface TerminalCreateOpts {
4
+ agentId: string;
5
+
6
+ shell?: string;
7
+
8
+ cwd: string;
9
+ cols?: number;
10
+ rows?: number;
11
+
12
+ preCommand?: string;
13
+ }
14
+ export interface TerminalReadOpts {
15
+
16
+ lines?: number;
17
+ }
18
+ export interface TerminalReadResult {
19
+ status: "running" | "exited" | "closed";
20
+ exit_code: number | null;
21
+
22
+ output: string;
23
+
24
+ needs_input: boolean;
25
+ truncated: boolean;
26
+ }
27
+ export interface TerminalManager {
28
+ create(opts: TerminalCreateOpts): {
29
+ id: string;
30
+ pid: number | undefined;
31
+ };
32
+ write(id: string, data: string): void;
33
+ read(id: string, opts: TerminalReadOpts): TerminalReadResult;
34
+ kill(id: string): void;
35
+ resize(id: string, cols: number, rows: number): void;
36
+
37
+ killByAgent?(agentId: string): void;
38
+ }
@@ -1,6 +1,7 @@
1
1
  import type { SubAgentManager } from "./sub-agent-manager.js";
2
2
  import type { SubAgentType } from "./sub-agent-types.js";
3
3
  import type { ACodeMcpConnection } from "./runtime.js";
4
+ import type { TerminalManager } from "./terminal-types.js";
4
5
  export interface ACodeMcpServerSpec {
5
6
  type?: "stdio" | "sse" | "http";
6
7
  command?: string;
@@ -57,7 +58,7 @@ export interface ACodeSkillGroup {
57
58
  exists: boolean;
58
59
  skills: ACodeSkillMetadata[];
59
60
  }
60
- export type ACodeEventType = "session_started" | "startup_phase" | "ai_request" | "thinking_delta" | "assistant_delta" | "command_output" | "command_status" | "mcp_status" | "skill_status" | "warning" | "turn_complete" | "session_complete" | "context_compaction" | "question_request" | "error";
61
+ export type ACodeEventType = "session_started" | "startup_phase" | "ai_request" | "thinking_delta" | "assistant_delta" | "command_output" | "command_status" | "mcp_status" | "skill_status" | "warning" | "turn_complete" | "session_complete" | "context_compaction" | "question_request" | "error" | "background_command_completed";
61
62
  export interface ACodeEvent {
62
63
  type: ACodeEventType;
63
64
  sessionId: string;
@@ -120,6 +121,8 @@ export interface ACodeRuntimeConfig {
120
121
 
121
122
  subAgentManager?: SubAgentManager;
122
123
 
124
+ terminalManager?: TerminalManager;
125
+
123
126
  sharedMcpConnections?: ACodeMcpConnection[];
124
127
 
125
128
  subAgentModel?: string;
@@ -129,6 +132,8 @@ export interface ACodeRuntimeConfig {
129
132
  subagentType?: SubAgentType;
130
133
 
131
134
  onFileChange?: import("./built-in-file-tools.js").OnAgentFileChange;
135
+
136
+ extraBuiltInTools?: import("./built-in-file-tools.js").ACodeBuiltInTool[];
132
137
  }
133
138
  export interface ACodeResolvedProviderConfig {
134
139
  model: string;
@@ -142,6 +147,10 @@ export interface ACodeResolvedProviderConfig {
142
147
 
143
148
  requestTotalTimeoutMs: number;
144
149
  requestRetryCount: number;
150
+
151
+ requestFirstByteTimeoutMs: number;
152
+
153
+ requestStreamIdleTimeoutMs: number;
145
154
  mcpToolTimeoutMs: number;
146
155
  mcpPollingToolTimeoutMs: number;
147
156
  supportsImageInput: boolean;
@@ -1,7 +1,7 @@
1
1
 
2
2
  import type { MemoryStats } from "./memory-store.js";
3
3
  import { StatusReporter } from "./status-reporter.js";
4
- import type { AgentConfig, DirectMessage, DmHistoryResponse, FetchUnreadMessagesOptions, FinishTaskRollbackArgs, GroupHistoryResponse, GroupRoomsResponse, HireBatchResult, HireColleagueArgs, HireColleaguesBatchArgs, HiredColleagueResult, MessageHandler, OnlineListResponse, ProfileInfo, RegisterResult, SendDmResult, SendMessageResult, StartTaskRollbackArgs, TaskInstanceCommentArgs, UnreadMessagesResult } from "./types.js";
4
+ import type { AgentConfig, BrowserListenerEvent, DirectMessage, DmHistoryResponse, FetchUnreadMessagesOptions, FinishTaskRollbackArgs, GroupHistoryResponse, GroupRoomsResponse, HireBatchResult, HireColleagueArgs, HireColleaguesBatchArgs, HiredColleagueResult, MessageHandler, OnlineListResponse, ProfileInfo, RegisterResult, SendDmResult, SendMessageResult, StartTaskRollbackArgs, TaskInstanceCommentArgs, UnreadMessagesResult } from "./types.js";
5
5
  export type ProfileHandler = (profile: ProfileInfo) => void;
6
6
  export declare class AgentClient {
7
7
  private wsClient;
@@ -61,6 +61,8 @@ export declare class AgentClient {
61
61
 
62
62
  fetchUnreadMessages(options?: FetchUnreadMessagesOptions): Promise<UnreadMessagesResult>;
63
63
 
64
+ fetchBrowserListenerEvents(): Promise<BrowserListenerEvent[]>;
65
+
64
66
  private fetchDirectMessagesWithRecovery;
65
67
 
66
68
  private isRecoverableLongPollError;
@@ -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 o={agentId:this.agentId,targetId:e,content:t,requireReply:n,waitReply:n,replyToCallId:i};if(typeof r=="number"&&r>0&&(o.timeoutMs=r),n){const h=typeof r=="number"&&r>0?r+3e4:0;return await this.httpClient.callToolOnce("send_dm",o,h)}return await this.httpClient.callTool("send_dm",o)}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 a={projectName:this.projectName||this.agentConfig.projectName,roomId:t,limit:e};return n&&(a.since=n),await this.httpClient.callTool("get_group_history",a)}const i=await this.discoverGroupRooms(),r=this.projectName||this.agentConfig.projectName,o=this.collectRoomIds(i,r);if(o.length===0)return{messages:[],count:0};const c=(await Promise.all(o.map(async a=>{const l={projectName:r,roomId:a,limit:e};return n&&(l.since=n),await this.httpClient.callTool("get_group_history",l)}))).flatMap(a=>a.messages).sort((a,l)=>new Date(a.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),o=await this.discoverGroupRooms(),h=this.collectRoomIds(o,t),c=await Promise.all(h.map(async a=>{const l={agentId:this.agentId,projectName:t,roomId:a};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",a,d instanceof Error?d.message:String(d)),{messages:[],currentReadPos:0,hasMore:!1}}}));return{directMessages:Array.isArray(r.messages)?r.messages:[],groupMessages:c.flatMap(a=>this.normalizeGroupMessages(a)).sort((a,l)=>new Date(a.timestamp).getTime()-new Date(l.timestamp).getTime())}}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 o=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}): ${o}`),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 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};
2
2
 
@@ -24,6 +24,8 @@ export declare function updateStartupLogIdentity(roleName: string, instanceName:
24
24
 
25
25
  export declare function setMcpNodeLogSink(sink: McpNodeLogSink | null): void;
26
26
  export declare const logger: {
27
+
28
+ debug: (..._args: unknown[]) => void;
27
29
  info: (...args: unknown[]) => void;
28
30
  warn: (...args: unknown[]) => void;
29
31
  error: (...args: unknown[]) => void;
@@ -1,3 +1,3 @@
1
1
  import*as l from"node:fs";import*as m from"node:os";import*as i from"node:path";import{format as p}from"node:util";const d=new Date,E=new Set(["0","false","off","no"]),S=200,L="aws-mcp-node";let t,c=null,g=null;const u=[];function s(e,n=2){return String(e).padStart(n,"0")}function M(e){return`${e.getFullYear()}-${s(e.getMonth()+1)}`}function N(e){return[s(e.getDate()),"-",s(e.getHours()),s(e.getMinutes()),s(e.getSeconds()),s(e.getMilliseconds(),3)].join("")}function _(e){const n=new RegExp("[\0-]","g");return e.replace(/[<>:"/\\|?*]/g,"_").replace(n,"_").replace(/\s+/g," ").trim().replace(/[. ]+$/g,"")||"workspace"}function h(e={}){const n=e.logDir||i.join(e.homeDir||m.homedir(),".aws-bridge","log"),r=_(e.roleName||process.env.AWS_ROLE_NAME||"unknown-role"),o=_(e.instanceName||process.env.AWS_AGENT_ID||"unknown-instance"),a=e.startupTime||d,w=M(a),D=`${N(a)}.log`;return i.join(n,"agent",L,`${r}-${o}`,w,D)}function F(){if(t!==void 0)return t;const e=String(process.env.AWS_MCP_FILE_LOG||"").trim().toLowerCase();if(E.has(e))return t=null,null;try{return c=process.env.AWS_MCP_LOG_DIR||void 0||i.join(m.homedir(),".aws-bridge","log"),t=h({logDir:c,roleName:process.env.AWS_ROLE_NAME||void 0,instanceName:process.env.AWS_AGENT_ID||void 0}),l.mkdirSync(i.dirname(t),{recursive:!0}),t}catch(n){return t=null,c=null,console.warn("[Logger] \u65E0\u6CD5\u521B\u5EFA MCP \u542F\u52A8\u65E5\u5FD7\u6587\u4EF6:",n),null}}function $(e,n){if(t==null||!c)return;const r=t,o=h({logDir:c,roleName:e,instanceName:n,startupTime:d});if(r!==o)try{l.mkdirSync(i.dirname(o),{recursive:!0}),l.renameSync(r,o),t=o,console.log(`[Logger] MCP \u542F\u52A8\u65E5\u5FD7\u8DEF\u5F84\u5DF2\u66F4\u65B0: ${r} -> ${o}`);const a=i.join(c,"agent",L);A(i.dirname(r),a)}catch(a){console.warn("[Logger] \u65E0\u6CD5\u66F4\u65B0 MCP \u542F\u52A8\u65E5\u5FD7\u8EAB\u4EFD\u6807\u8BC6:",a)}}function A(e,n){let r=i.normalize(e);const o=i.normalize(n),a=i.parse(r).root;for(;r!==o&&r!==a;){try{l.rmdirSync(r)}catch{break}r=i.dirname(r)}}function P(e,n){if(t===void 0)return;const r=t;if(!r)return;const o=`${new Date().toISOString()} [${e.toUpperCase()}] ${p(...n)}
2
- `;try{l.appendFileSync(r,o,"utf8")}catch(a){t=null,console.warn("[Logger] \u65E0\u6CD5\u5199\u5165 MCP \u542F\u52A8\u65E5\u5FD7\u6587\u4EF6:",a)}}function f(e,n){const r={level:e,message:p(...n),timestamp:new Date().toISOString()};switch(e){case"info":console.error(...n);break;case"warn":console.warn(...n);break;case"error":console.error(...n);break}P(e,n),C(r)}function I(e){if(g=e,!!e)for(const n of u)e(n)}function C(e){u.push(e),u.length>S&&u.splice(0,u.length-S),g&&g(e)}const O={info:(...e)=>f("info",e),warn:(...e)=>f("warn",e),error:(...e)=>f("error",e)};export{h as buildStartupLogFilePath,N as formatLogFileTimestamp,M as formatLogYearMonth,F as initializeStartupLogFile,O as logger,_ as sanitizeLogFileNameSegment,I as setMcpNodeLogSink,$ as updateStartupLogIdentity};
2
+ `;try{l.appendFileSync(r,o,"utf8")}catch(a){t=null,console.warn("[Logger] \u65E0\u6CD5\u5199\u5165 MCP \u542F\u52A8\u65E5\u5FD7\u6587\u4EF6:",a)}}function f(e,n){const r={level:e,message:p(...n),timestamp:new Date().toISOString()};switch(e){case"info":console.error(...n);break;case"warn":console.warn(...n);break;case"error":console.error(...n);break}P(e,n),C(r)}function I(e){if(g=e,!!e)for(const n of u)e(n)}function C(e){u.push(e),u.length>S&&u.splice(0,u.length-S),g&&g(e)}const O={debug:(...e)=>{},info:(...e)=>f("info",e),warn:(...e)=>f("warn",e),error:(...e)=>f("error",e)};export{h as buildStartupLogFilePath,N as formatLogFileTimestamp,M as formatLogYearMonth,F as initializeStartupLogFile,O as logger,_ as sanitizeLogFileNameSegment,I as setMcpNodeLogSink,$ as updateStartupLogIdentity};
3
3
 
@@ -159,6 +159,12 @@ export declare class McpServer {
159
159
  private handleGetMessage;
160
160
 
161
161
  private hydrateUnreadMessagesFromServer;
162
+
163
+ private hydrateBrowserListenerEvents;
164
+
165
+ private buildListenerEventNotification;
166
+
167
+ private formatChangeType;
162
168
  private handleGetDmHistory;
163
169
  private handleGetGroupHistory;
164
170
  private handleSubmitTaskResult;
@@ -182,6 +188,8 @@ export declare class McpServer {
182
188
  private sanitizeAgentIdForTodoFile;
183
189
 
184
190
  private buildTodoReminderNotification;
191
+
192
+ private buildBackgroundTaskNotification;
185
193
  start(): Promise<void>;
186
194
 
187
195
  private startLeaseRenewal;