aws-runtime-bridge 1.7.50 → 1.8.0

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 (63) hide show
  1. package/dist/adapter/AcodeSdkAdapter.d.ts +30 -3
  2. package/dist/adapter/AcodeSdkAdapter.d.ts.map +1 -1
  3. package/dist/adapter/AcodeSdkAdapter.js +427 -105
  4. package/dist/adapter/AcodeSdkAdapter.test.js +1093 -86
  5. package/dist/adapter/ClaudeSdkAdapter.test.js +31 -8
  6. package/dist/adapter/CodexSdkAdapter.d.ts.map +1 -1
  7. package/dist/adapter/CodexSdkAdapter.js +2 -0
  8. package/dist/adapter/OpencodeSdkAdapter.d.ts.map +1 -1
  9. package/dist/adapter/OpencodeSdkAdapter.js +2 -0
  10. package/dist/adapter/SdkProviderSpi.d.ts.map +1 -1
  11. package/dist/adapter/adapter.test.js +2 -2
  12. package/dist/adapter/idle-poll-loop.d.ts +4 -4
  13. package/dist/adapter/idle-poll-loop.d.ts.map +1 -1
  14. package/dist/adapter/idle-poll-loop.js +3 -3
  15. package/dist/adapter/idle-poll-loop.test.js +15 -1
  16. package/dist/adapter/types.d.ts +25 -6
  17. package/dist/adapter/types.d.ts.map +1 -1
  18. package/dist/adapter/types.js +221 -110
  19. package/dist/adapter/types.test.js +10 -3
  20. package/dist/routes/instance.d.ts.map +1 -1
  21. package/dist/routes/instance.js +6 -7
  22. package/dist/routes/runtime-binding.js +2 -2
  23. package/dist/routes/terminal.d.ts +20 -5
  24. package/dist/routes/terminal.d.ts.map +1 -1
  25. package/dist/routes/terminal.js +420 -170
  26. package/dist/routes/terminal.test.js +380 -208
  27. package/dist/services/mcp-launch-binding-queue.d.ts +1 -0
  28. package/dist/services/mcp-launch-binding-queue.d.ts.map +1 -1
  29. package/dist/services/mcp-launch-binding-queue.js +8 -2
  30. package/dist/services/mcp-launch-binding-queue.test.js +47 -4
  31. package/dist/services/session-output.d.ts +10 -6
  32. package/dist/services/session-output.d.ts.map +1 -1
  33. package/dist/services/session-output.js +29 -14
  34. package/dist/services/session-output.test.js +93 -39
  35. package/package/acode/dist/built-in-file-tools.d.ts +1 -1
  36. package/package/acode/dist/built-in-file-tools.d.ts.map +1 -1
  37. package/package/acode/dist/built-in-file-tools.js +388 -50
  38. package/package/acode/dist/runtime.d.ts +11 -3
  39. package/package/acode/dist/runtime.d.ts.map +1 -1
  40. package/package/acode/dist/runtime.js +902 -190
  41. package/package/acode/dist/types.d.ts +18 -5
  42. package/package/acode/dist/types.d.ts.map +1 -1
  43. package/package/aws-client-agent-mcp/dist/mcp-server.d.ts.map +1 -1
  44. package/package/aws-client-agent-mcp/dist/mcp-server.js +3 -2
  45. package/package/aws-client-agent-mcp/dist/mcp-server.js.map +1 -1
  46. package/package/aws-client-agent-mcp/dist/mcp-server.test.js +11 -9
  47. package/package/aws-client-agent-mcp/dist/mcp-server.test.js.map +1 -1
  48. package/package/aws-client-agent-mcp/dist/runtime-launch-binding.d.ts.map +1 -1
  49. package/package/aws-client-agent-mcp/dist/runtime-launch-binding.js +1 -0
  50. package/package/aws-client-agent-mcp/dist/runtime-launch-binding.js.map +1 -1
  51. package/package/aws-client-agent-mcp/dist/status-reporter.d.ts +2 -0
  52. package/package/aws-client-agent-mcp/dist/status-reporter.d.ts.map +1 -1
  53. package/package/aws-client-agent-mcp/dist/status-reporter.js +31 -3
  54. package/package/aws-client-agent-mcp/dist/status-reporter.js.map +1 -1
  55. package/package/aws-client-agent-mcp/dist/types.d.ts +1 -1
  56. package/package/aws-client-agent-mcp/dist/types.d.ts.map +1 -1
  57. package/package/aws-client-agent-mcp/dist/types.js.map +1 -1
  58. package/package/aws-client-agent-mcp/dist/websocket-client.d.ts.map +1 -1
  59. package/package/aws-client-agent-mcp/dist/websocket-client.js +2 -0
  60. package/package/aws-client-agent-mcp/dist/websocket-client.js.map +1 -1
  61. package/package/aws-client-agent-mcp/dist/websocket-client.test.js +43 -0
  62. package/package/aws-client-agent-mcp/dist/websocket-client.test.js.map +1 -1
  63. package/package.json +1 -1
@@ -24,6 +24,7 @@ export interface ClaimedMcpLaunchBinding extends McpLaunchBinding {
24
24
  schedulerBaseUrl?: string;
25
25
  }
26
26
  export interface McpLaunchBindingClaimRequest {
27
+ agentId?: unknown;
27
28
  workspacePath: unknown;
28
29
  serverUrl?: unknown;
29
30
  }
@@ -1 +1 @@
1
- {"version":3,"file":"mcp-launch-binding-queue.d.ts","sourceRoot":"","sources":["../../src/services/mcp-launch-binding-queue.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,uBAAwB,SAAQ,gBAAgB;IAC/D,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,4BAA4B;IAC3C,aAAa,EAAE,OAAO,CAAC;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AA2DD,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,qBAAqB,GAAG,gBAAgB,GAAG,IAAI,CA+B7F;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,4BAA4B,GAAG,uBAAuB,GAAG,IAAI,CA0C3G;AAED,wBAAgB,qBAAqB,CAAC,aAAa,EAAE,OAAO,GAAG,MAAM,CAOpE;AAED,wBAAgB,2BAA2B,IAAI,IAAI,CAElD"}
1
+ {"version":3,"file":"mcp-launch-binding-queue.d.ts","sourceRoot":"","sources":["../../src/services/mcp-launch-binding-queue.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,uBAAwB,SAAQ,gBAAgB;IAC/D,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,4BAA4B;IAC3C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,aAAa,EAAE,OAAO,CAAC;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AA2DD,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,qBAAqB,GAAG,gBAAgB,GAAG,IAAI,CA+B7F;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,4BAA4B,GAAG,uBAAuB,GAAG,IAAI,CAkD3G;AAED,wBAAgB,qBAAqB,CAAC,aAAa,EAAE,OAAO,GAAG,MAAM,CAOpE;AAED,wBAAgB,2BAA2B,IAAI,IAAI,CAElD"}
@@ -80,18 +80,24 @@ export function enqueueMcpLaunchBinding(input) {
80
80
  }
81
81
  export function claimMcpLaunchBinding(request) {
82
82
  pruneExpiredBindings();
83
+ const requestedAgentId = String(request.agentId || "").trim();
83
84
  const workspaceKey = normalizeWorkspacePath(request.workspacePath);
84
85
  const serverKey = normalizeSchedulerOrigin(request.serverUrl);
85
86
  if (!workspaceKey) {
86
87
  return null;
87
88
  }
88
- let bindingIndex = launchBindings.findIndex((binding) => normalizeWorkspacePath(binding.workspacePath) === workspaceKey &&
89
+ const serverMatches = launchBindings
90
+ .map((binding, index) => ({ binding, index }))
91
+ .filter(({ binding }) => (!requestedAgentId || binding.agentId === requestedAgentId) &&
92
+ normalizeWorkspacePath(binding.workspacePath) === workspaceKey &&
89
93
  serverKey &&
90
94
  normalizeSchedulerOrigin(binding.serverUrl || binding.schedulerBaseUrl) === serverKey);
95
+ let bindingIndex = serverMatches.length === 1 ? serverMatches[0]?.index ?? -1 : -1;
91
96
  if (bindingIndex < 0) {
92
97
  const workspaceMatches = launchBindings
93
98
  .map((binding, index) => ({ binding, index }))
94
- .filter(({ binding }) => normalizeWorkspacePath(binding.workspacePath) === workspaceKey);
99
+ .filter(({ binding }) => (!requestedAgentId || binding.agentId === requestedAgentId) &&
100
+ normalizeWorkspacePath(binding.workspacePath) === workspaceKey);
95
101
  if (workspaceMatches.length === 1) {
96
102
  bindingIndex = workspaceMatches[0]?.index ?? -1;
97
103
  }
@@ -4,7 +4,7 @@ describe('mcp launch binding queue', () => {
4
4
  afterEach(() => {
5
5
  clearMcpLaunchBindingQueues();
6
6
  });
7
- it('claims same-workspace same-server bindings from the front of the queue', () => {
7
+ it('claims same-workspace same-server bindings by agent id', () => {
8
8
  const firstBinding = enqueueMcpLaunchBinding({
9
9
  agentId: 'agent-a',
10
10
  workspacePath: 'C:/repo/demo',
@@ -23,10 +23,12 @@ describe('mcp launch binding queue', () => {
23
23
  });
24
24
  expect(getMcpLaunchQueueSize('C:/repo/demo')).toBe(2);
25
25
  const first = claimMcpLaunchBinding({
26
+ agentId: 'agent-a',
26
27
  workspacePath: 'C:/repo/demo',
27
28
  serverUrl: 'ws://server-a:7380/ws/agent',
28
29
  });
29
30
  const second = claimMcpLaunchBinding({
31
+ agentId: 'agent-b',
30
32
  workspacePath: 'C:/repo/demo',
31
33
  serverUrl: 'ws://server-a:7380/ws/agent',
32
34
  });
@@ -36,19 +38,43 @@ describe('mcp launch binding queue', () => {
36
38
  expect(second?.runtimeAccessToken).toBe('token-b');
37
39
  expect(getMcpLaunchQueueSize('C:/repo/demo')).toBe(0);
38
40
  });
39
- it('claims by workspace path and server URL regardless of agent id', () => {
41
+ it('does not claim another agent token from the same workspace and server', () => {
40
42
  const binding = enqueueMcpLaunchBinding({
41
43
  agentId: 'agent-a',
42
44
  workspacePath: 'C:/repo/demo',
43
45
  serverUrl: 'ws://server:7380/ws/agent',
44
46
  });
45
47
  expect(claimMcpLaunchBinding({
48
+ agentId: 'agent-b',
46
49
  workspacePath: 'C:/repo/demo',
47
50
  serverUrl: 'ws://server:7380/ws/agent',
48
- })?.agentId).toBe('agent-a');
51
+ })).toBeNull();
49
52
  expect(binding?.agentId).toBe('agent-a');
53
+ expect(getMcpLaunchQueueSize('C:/repo/demo')).toBe(1);
54
+ });
55
+ it('skips older same-workspace bindings when claiming a later agent token', () => {
56
+ enqueueMcpLaunchBinding({
57
+ agentId: 'agent-a',
58
+ workspacePath: 'C:/repo/demo',
59
+ serverUrl: 'ws://server:7380/ws/agent',
60
+ runtimeAccessToken: 'token-a',
61
+ });
62
+ enqueueMcpLaunchBinding({
63
+ agentId: 'agent-b',
64
+ workspacePath: 'C:/repo/demo',
65
+ serverUrl: 'ws://server:7380/ws/agent',
66
+ runtimeAccessToken: 'token-b',
67
+ });
68
+ const claimed = claimMcpLaunchBinding({
69
+ agentId: 'agent-b',
70
+ workspacePath: 'C:/repo/demo',
71
+ serverUrl: 'ws://server:7380/ws/agent',
72
+ });
73
+ expect(claimed?.agentId).toBe('agent-b');
74
+ expect(claimed?.runtimeAccessToken).toBe('token-b');
75
+ expect(getMcpLaunchQueueSize('C:/repo/demo')).toBe(1);
50
76
  });
51
- it('ignores explicit binding id and claims the first matching queue entry', () => {
77
+ it('allows legacy claim without agent id only when one binding matches', () => {
52
78
  const binding = enqueueMcpLaunchBinding({
53
79
  agentId: 'agent-a',
54
80
  workspacePath: 'C:/repo/demo',
@@ -60,6 +86,23 @@ describe('mcp launch binding queue', () => {
60
86
  })?.agentId).toBe('agent-a');
61
87
  expect(binding?.id).toBeTruthy();
62
88
  });
89
+ it('rejects legacy claim without agent id when same-workspace same-server bindings are ambiguous', () => {
90
+ enqueueMcpLaunchBinding({
91
+ agentId: 'agent-a',
92
+ workspacePath: 'C:/repo/demo',
93
+ serverUrl: 'ws://server:7380/ws/agent',
94
+ });
95
+ enqueueMcpLaunchBinding({
96
+ agentId: 'agent-b',
97
+ workspacePath: 'C:/repo/demo',
98
+ serverUrl: 'ws://server:7380/ws/agent',
99
+ });
100
+ expect(claimMcpLaunchBinding({
101
+ workspacePath: 'C:/repo/demo',
102
+ serverUrl: 'ws://server:7380/ws/agent',
103
+ })).toBeNull();
104
+ expect(getMcpLaunchQueueSize('C:/repo/demo')).toBe(2);
105
+ });
63
106
  it('matches by server URL as well as workspace path', () => {
64
107
  const firstBinding = enqueueMcpLaunchBinding({ agentId: 'agent-a', workspacePath: 'C:/repo/demo', serverUrl: 'ws://server-a:7380/ws/agent' });
65
108
  const secondBinding = enqueueMcpLaunchBinding({ agentId: 'agent-b', workspacePath: 'C:/repo/demo', serverUrl: 'ws://server-b:7380/ws/agent' });
@@ -3,7 +3,8 @@
3
3
  *
4
4
  * 管理终端会话的输出缓冲和刷新机制
5
5
  */
6
- import type { Session } from '../types.js';
6
+ import type { AxiosResponse } from "axios";
7
+ import type { Session } from "../types.js";
7
8
  interface RuntimeStatusActionInfo {
8
9
  actionType?: string;
9
10
  actionLabel?: string;
@@ -11,6 +12,9 @@ interface RuntimeStatusActionInfo {
11
12
  actionResult?: string;
12
13
  actionId?: string;
13
14
  }
15
+ export interface RuntimeCallbackAuthOptions {
16
+ runtimeAccessToken?: string;
17
+ }
14
18
  /** 活跃会话存储 */
15
19
  export declare const sessions: Map<string, Session>;
16
20
  /**
@@ -24,9 +28,7 @@ export declare const sessions: Map<string, Session>;
24
28
  export declare function sendStatus(agentId: string, sessionId: string | null, status: string, actionInfo?: RuntimeStatusActionInfo, usage?: {
25
29
  inputTokens: number;
26
30
  outputTokens: number;
27
- }): Promise<void | {
28
- data: unknown;
29
- }>;
31
+ }, authOptions?: RuntimeCallbackAuthOptions): Promise<AxiosResponse<unknown> | undefined>;
30
32
  /**
31
33
  * 发送输出到调度器
32
34
  *
@@ -35,7 +37,9 @@ export declare function sendStatus(agentId: string, sessionId: string | null, st
35
37
  * @param sessionId - 会话 ID
36
38
  * @param seq - 序列号
37
39
  */
38
- export declare function sendOutput(agentId: string, output: string, sessionId: string, seq: number): Promise<void>;
40
+ export declare function sendOutput(agentId: string, output: string, sessionId: string, seq: number, metadata?: {
41
+ sourceEventType?: string;
42
+ }, authOptions?: RuntimeCallbackAuthOptions): Promise<void>;
39
43
  /**
40
44
  * 发送 AskUserQuestion 事件到调度器。
41
45
  *
@@ -43,7 +47,7 @@ export declare function sendOutput(agentId: string, output: string, sessionId: s
43
47
  * @param sessionId - SDK 会话 ID
44
48
  * @param questions - 结构化问题列表
45
49
  */
46
- export declare function sendQuestionRequest(agentId: string, sessionId: string, questions: unknown[]): Promise<void>;
50
+ export declare function sendQuestionRequest(agentId: string, sessionId: string, questions: unknown[], authOptions?: RuntimeCallbackAuthOptions): Promise<void>;
47
51
  export interface RuntimeFileChangedPayload {
48
52
  bridgeBaseUrl?: string;
49
53
  workspacePath: string;
@@ -1 +1 @@
1
- {"version":3,"file":"session-output.d.ts","sourceRoot":"","sources":["../../src/services/session-output.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAG3C,UAAU,uBAAuB;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAcD,aAAa;AACb,eAAO,MAAM,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAa,CAAC;AAExD;;;;;;;GAOG;AACH,wBAAsB,UAAU,CAC9B,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,MAAM,EAAE,MAAM,EACd,UAAU,CAAC,EAAE,uBAAuB,EACpC,KAAK,CAAC,EAAE;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GACpD,OAAO,CAAC,IAAI,GAAG;IAAE,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC,CAuBnC;AAED;;;;;;;GAOG;AACH,wBAAsB,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAU/G;AAED;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAUjH;AAED,MAAM,WAAW,yBAAyB;IACxC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,yBAAyB,GAAG,OAAO,CAAC,IAAI,CAAC,CAUvF;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAgBzE;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAa3D;AAED;;;;GAIG;AACH,wBAAsB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAqCzE"}
1
+ {"version":3,"file":"session-output.d.ts","sourceRoot":"","sources":["../../src/services/session-output.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAE3C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAI3C,UAAU,uBAAuB;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,0BAA0B;IACzC,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAmBD,aAAa;AACb,eAAO,MAAM,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAa,CAAC;AAExD;;;;;;;GAOG;AACH,wBAAsB,UAAU,CAC9B,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,MAAM,EAAE,MAAM,EACd,UAAU,CAAC,EAAE,uBAAuB,EACpC,KAAK,CAAC,EAAE;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,EACrD,WAAW,CAAC,EAAE,0BAA0B,GACvC,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC,GAAG,SAAS,CAAC,CA0C7C;AAED;;;;;;;GAOG;AACH,wBAAsB,UAAU,CAC9B,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,EACX,QAAQ,CAAC,EAAE;IAAE,eAAe,CAAC,EAAE,MAAM,CAAA;CAAE,EACvC,WAAW,CAAC,EAAE,0BAA0B,GACvC,OAAO,CAAC,IAAI,CAAC,CAcf;AAED;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,OAAO,EAAE,EACpB,WAAW,CAAC,EAAE,0BAA0B,GACvC,OAAO,CAAC,IAAI,CAAC,CAcf;AAED,MAAM,WAAW,yBAAyB;IACxC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAAC,IAAI,CAAC,CAcf;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAgBzE;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAa3D;AAED;;;;GAIG;AACH,wBAAsB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAqCzE"}
@@ -3,12 +3,15 @@
3
3
  *
4
4
  * 管理终端会话的输出缓冲和刷新机制
5
5
  */
6
- import axios from 'axios';
7
- import { schedulerBaseUrl } from '../config.js';
8
- import { getRuntimeAccessToken } from './runtime-binding.js';
9
- function runtimeAuthHeaders() {
10
- const token = getRuntimeAccessToken(undefined, schedulerBaseUrl) || getRuntimeAccessToken();
11
- return token ? { 'X-Runtime-Token': token } : undefined;
6
+ import axios from "axios";
7
+ import { schedulerBaseUrl } from "../config.js";
8
+ import { logger } from "../utils/logger.js";
9
+ import { getRuntimeAccessToken } from "./runtime-binding.js";
10
+ function runtimeAuthHeaders(options) {
11
+ const token = options?.runtimeAccessToken ||
12
+ getRuntimeAccessToken(undefined, schedulerBaseUrl) ||
13
+ getRuntimeAccessToken();
14
+ return token ? { "X-Runtime-Token": token } : undefined;
12
15
  }
13
16
  /** 输出刷新防抖时间:合并启动期高频小块输出,降低 HTTP/WebSocket 压力。 */
14
17
  const OUTPUT_FLUSH_DEBOUNCE_MS = 100;
@@ -26,7 +29,7 @@ export const sessions = new Map();
26
29
  * @param status - 状态
27
30
  * @param actionInfo - 可选的动作详情
28
31
  */
29
- export async function sendStatus(agentId, sessionId, status, actionInfo, usage) {
32
+ export async function sendStatus(agentId, sessionId, status, actionInfo, usage, authOptions) {
30
33
  const payload = { agentId, sessionId, status };
31
34
  // 添加细粒度动作信息
32
35
  if (actionInfo) {
@@ -46,11 +49,23 @@ export async function sendStatus(agentId, sessionId, status, actionInfo, usage)
46
49
  payload.inputTokens = usage.inputTokens;
47
50
  payload.outputTokens = usage.outputTokens;
48
51
  }
49
- const headers = runtimeAuthHeaders();
52
+ const headers = runtimeAuthHeaders(authOptions);
50
53
  if (!headers) {
54
+ logger.warn("Skip runtime status callback because runtime token is missing", { agentId, sessionId, status });
55
+ return undefined;
56
+ }
57
+ try {
58
+ return await axios.post(`${schedulerBaseUrl}/api/runtime/callback/status`, payload, { headers });
59
+ }
60
+ catch (error) {
61
+ logger.warn("Runtime status callback failed", {
62
+ agentId,
63
+ sessionId,
64
+ status,
65
+ error,
66
+ });
51
67
  return undefined;
52
68
  }
53
- return axios.post(`${schedulerBaseUrl}/api/runtime/callback/status`, payload, { headers }).catch(() => undefined);
54
69
  }
55
70
  /**
56
71
  * 发送输出到调度器
@@ -60,13 +75,13 @@ export async function sendStatus(agentId, sessionId, status, actionInfo, usage)
60
75
  * @param sessionId - 会话 ID
61
76
  * @param seq - 序列号
62
77
  */
63
- export async function sendOutput(agentId, output, sessionId, seq) {
78
+ export async function sendOutput(agentId, output, sessionId, seq, metadata, authOptions) {
64
79
  try {
65
- const headers = runtimeAuthHeaders();
80
+ const headers = runtimeAuthHeaders(authOptions);
66
81
  if (!headers) {
67
82
  return;
68
83
  }
69
- await axios.post(`${schedulerBaseUrl}/api/runtime/callback/output`, { agentId, output, sessionId, seq }, { headers });
84
+ await axios.post(`${schedulerBaseUrl}/api/runtime/callback/output`, { agentId, output, sessionId, seq, ...metadata }, { headers });
70
85
  }
71
86
  catch {
72
87
  // ignore transient callback failures
@@ -79,9 +94,9 @@ export async function sendOutput(agentId, output, sessionId, seq) {
79
94
  * @param sessionId - SDK 会话 ID
80
95
  * @param questions - 结构化问题列表
81
96
  */
82
- export async function sendQuestionRequest(agentId, sessionId, questions) {
97
+ export async function sendQuestionRequest(agentId, sessionId, questions, authOptions) {
83
98
  try {
84
- const headers = runtimeAuthHeaders();
99
+ const headers = runtimeAuthHeaders(authOptions);
85
100
  if (!headers) {
86
101
  return;
87
102
  }
@@ -1,12 +1,29 @@
1
1
  /**
2
2
  * Session Output 服务单元测试
3
3
  */
4
- import { afterEach, describe, expect, it } from 'vitest';
5
- import { appendSessionOutput, sessions } from './session-output.js';
4
+ import axios from "axios";
5
+ import { afterEach, describe, expect, it, vi } from "vitest";
6
+ import { logger } from "../utils/logger.js";
7
+ import { appendSessionOutput, sendOutput, sendStatus, sessions, } from "./session-output.js";
8
+ vi.mock("axios", () => ({
9
+ default: {
10
+ post: vi.fn(),
11
+ },
12
+ }));
13
+ vi.mock("./runtime-binding.js", () => ({
14
+ getRuntimeAccessToken: vi.fn(() => "runtime-token"),
15
+ }));
16
+ vi.mock("../utils/logger.js", () => ({
17
+ logger: {
18
+ warn: vi.fn(),
19
+ },
20
+ }));
21
+ const mockedAxiosPost = axios.post;
22
+ const mockedLogger = vi.mocked(logger);
6
23
  const createSession = (overrides = {}) => ({
7
- agentId: 'agent-1',
8
- workspacePath: 'D:/workspace',
9
- outputBuffer: '',
24
+ agentId: "agent-1",
25
+ workspacePath: "D:/workspace",
26
+ outputBuffer: "",
10
27
  flushTimer: null,
11
28
  flushInFlight: null,
12
29
  seq: 0,
@@ -14,22 +31,23 @@ const createSession = (overrides = {}) => ({
14
31
  });
15
32
  afterEach(() => {
16
33
  sessions.clear();
34
+ vi.clearAllMocks();
17
35
  });
18
- describe('session-output service', () => {
19
- it('manages sessions map correctly', () => {
20
- sessions.set('session-1', createSession());
36
+ describe("session-output service", () => {
37
+ it("manages sessions map correctly", () => {
38
+ sessions.set("session-1", createSession());
21
39
  expect(sessions.size).toBe(1);
22
- expect(sessions.has('session-1')).toBe(true);
23
- const session = sessions.get('session-1');
40
+ expect(sessions.has("session-1")).toBe(true);
41
+ const session = sessions.get("session-1");
24
42
  if (session)
25
- session.outputBuffer = 'test output';
26
- expect(sessions.get('session-1')?.outputBuffer).toBe('test output');
27
- sessions.delete('session-1');
43
+ session.outputBuffer = "test output";
44
+ expect(sessions.get("session-1")?.outputBuffer).toBe("test output");
45
+ sessions.delete("session-1");
28
46
  expect(sessions.size).toBe(0);
29
47
  });
30
- it('finds session by agentId', () => {
31
- sessions.set('session-1', createSession({ agentId: 'agent-1' }));
32
- sessions.set('session-2', createSession({ agentId: 'agent-2' }));
48
+ it("finds session by agentId", () => {
49
+ sessions.set("session-1", createSession({ agentId: "agent-1" }));
50
+ sessions.set("session-2", createSession({ agentId: "agent-2" }));
33
51
  const findByAgentId = (agentId) => {
34
52
  for (const [id, session] of sessions) {
35
53
  if (session.agentId === agentId)
@@ -37,46 +55,82 @@ describe('session-output service', () => {
37
55
  }
38
56
  return null;
39
57
  };
40
- expect(findByAgentId('agent-1')).toBe('session-1');
41
- expect(findByAgentId('agent-3')).toBe(null);
58
+ expect(findByAgentId("agent-1")).toBe("session-1");
59
+ expect(findByAgentId("agent-3")).toBe(null);
42
60
  });
43
- it('accumulates output correctly', () => {
44
- sessions.set('session-1', createSession());
45
- appendSessionOutput('session-1', 'line1\n');
46
- appendSessionOutput('session-1', 'line2\n');
47
- expect(sessions.get('session-1')?.outputBuffer).toBe('line1\nline2\n');
61
+ it("accumulates output correctly", () => {
62
+ sessions.set("session-1", createSession());
63
+ appendSessionOutput("session-1", "line1\n");
64
+ appendSessionOutput("session-1", "line2\n");
65
+ expect(sessions.get("session-1")?.outputBuffer).toBe("line1\nline2\n");
48
66
  });
49
- it('bounds pending SDK output so callback failures cannot grow memory without limit', () => {
50
- sessions.set('session-bounded', createSession());
51
- appendSessionOutput('session-bounded', 'a'.repeat(70 * 1024));
52
- const output = sessions.get('session-bounded')?.outputBuffer ?? '';
67
+ it("bounds pending SDK output so callback failures cannot grow memory without limit", () => {
68
+ sessions.set("session-bounded", createSession());
69
+ appendSessionOutput("session-bounded", "a".repeat(70 * 1024));
70
+ const output = sessions.get("session-bounded")?.outputBuffer ?? "";
53
71
  expect(output.length).toBeLessThanOrEqual(64 * 1024);
54
- expect(output).toContain('AgentsWorkStudio: omitted');
55
- expect(output.endsWith('a')).toBe(true);
72
+ expect(output).toContain("AgentsWorkStudio: omitted");
73
+ expect(output.endsWith("a")).toBe(true);
56
74
  });
57
- it('increments sequence correctly', () => {
75
+ it("increments sequence correctly", () => {
58
76
  const session = createSession();
59
- sessions.set('session-1', session);
77
+ sessions.set("session-1", session);
60
78
  session.seq += 1;
61
79
  expect(session.seq).toBe(1);
62
80
  session.seq += 1;
63
81
  expect(session.seq).toBe(2);
64
82
  });
65
- it('builds correct status payload', () => {
83
+ it("builds correct status payload", () => {
66
84
  const buildStatusPayload = (agentId, sessionId, status) => ({
67
85
  agentId,
68
86
  sessionId,
69
87
  status,
70
88
  });
71
- expect(buildStatusPayload('agent-1', 'session-1', 'running')).toEqual({
72
- agentId: 'agent-1',
73
- sessionId: 'session-1',
74
- status: 'running',
89
+ expect(buildStatusPayload("agent-1", "session-1", "running")).toEqual({
90
+ agentId: "agent-1",
91
+ sessionId: "session-1",
92
+ status: "running",
75
93
  });
76
- expect(buildStatusPayload('agent-1', null, 'stopped')).toEqual({
77
- agentId: 'agent-1',
94
+ expect(buildStatusPayload("agent-1", null, "stopped")).toEqual({
95
+ agentId: "agent-1",
78
96
  sessionId: null,
79
- status: 'stopped',
97
+ status: "stopped",
80
98
  });
81
99
  });
100
+ it("does not throw when runtime status callback fails", async () => {
101
+ mockedAxiosPost.mockRejectedValueOnce(new Error("scheduler unavailable"));
102
+ await expect(sendStatus("agent-1", "session-1", "waiting_input")).resolves.toBeUndefined();
103
+ expect(mockedAxiosPost).toHaveBeenCalledWith(expect.stringContaining("/api/runtime/callback/status"), {
104
+ agentId: "agent-1",
105
+ sessionId: "session-1",
106
+ status: "waiting_input",
107
+ }, { headers: { "X-Runtime-Token": "runtime-token" } });
108
+ expect(mockedLogger.warn).toHaveBeenCalledWith("Runtime status callback failed", expect.objectContaining({
109
+ agentId: "agent-1",
110
+ sessionId: "session-1",
111
+ status: "waiting_input",
112
+ }));
113
+ });
114
+ it("uses explicit runtime callback token before persisted binding token", async () => {
115
+ mockedAxiosPost.mockResolvedValueOnce({ data: { ok: true } });
116
+ await sendStatus("agent-1", "session-1", "waiting_input", undefined, undefined, {
117
+ runtimeAccessToken: "session-runtime-token",
118
+ });
119
+ expect(mockedAxiosPost).toHaveBeenCalledWith(expect.stringContaining("/api/runtime/callback/status"), {
120
+ agentId: "agent-1",
121
+ sessionId: "session-1",
122
+ status: "waiting_input",
123
+ }, { headers: { "X-Runtime-Token": "session-runtime-token" } });
124
+ });
125
+ it("sends structured source event metadata with SDK output chunks", async () => {
126
+ mockedAxiosPost.mockResolvedValueOnce({ data: { ok: true } });
127
+ await sendOutput("agent-1", "answer chunk", "session-1", 7, { sourceEventType: "text_delta" }, { runtimeAccessToken: "session-runtime-token" });
128
+ expect(mockedAxiosPost).toHaveBeenCalledWith(expect.stringContaining("/api/runtime/callback/output"), {
129
+ agentId: "agent-1",
130
+ output: "answer chunk",
131
+ sessionId: "session-1",
132
+ seq: 7,
133
+ sourceEventType: "text_delta",
134
+ }, { headers: { "X-Runtime-Token": "session-runtime-token" } });
135
+ });
82
136
  });
@@ -5,7 +5,7 @@ export type JsonObject = {
5
5
  [key: string]: JsonValue;
6
6
  };
7
7
  export interface ACodeBuiltInTool {
8
- kind: 'builtin';
8
+ kind: "builtin";
9
9
  toolName: string;
10
10
  exposedName: string;
11
11
  description: string;
@@ -1 +1 @@
1
- {"version":3,"file":"built-in-file-tools.d.ts","sourceRoot":"","sources":["../src/built-in-file-tools.ts"],"names":[],"mappings":"AAIA,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,IAAI,GAAG,SAAS,EAAE,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAC;AACtG,MAAM,MAAM,UAAU,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAC;AAEtD,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,SAAS,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,UAAU,CAAC;IACxB,OAAO,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC7C;AAwPD,wBAAgB,sBAAsB,CAAC,gBAAgB,EAAE,MAAM,GAAG,gBAAgB,EAAE,CAEnF"}
1
+ {"version":3,"file":"built-in-file-tools.d.ts","sourceRoot":"","sources":["../src/built-in-file-tools.ts"],"names":[],"mappings":"AAKA,MAAM,MAAM,SAAS,GACjB,MAAM,GACN,MAAM,GACN,OAAO,GACP,IAAI,GACJ,SAAS,EAAE,GACX;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAC;AACjC,MAAM,MAAM,UAAU,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAC;AAEtD,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,SAAS,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,UAAU,CAAC;IACxB,OAAO,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CAC7C;AAyvBD,wBAAgB,sBAAsB,CACpC,gBAAgB,EAAE,MAAM,GACvB,gBAAgB,EAAE,CAOpB"}