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.
- package/dist/adapter/AcodeSdkAdapter.d.ts +30 -3
- package/dist/adapter/AcodeSdkAdapter.d.ts.map +1 -1
- package/dist/adapter/AcodeSdkAdapter.js +427 -105
- package/dist/adapter/AcodeSdkAdapter.test.js +1093 -86
- package/dist/adapter/ClaudeSdkAdapter.test.js +31 -8
- package/dist/adapter/CodexSdkAdapter.d.ts.map +1 -1
- package/dist/adapter/CodexSdkAdapter.js +2 -0
- package/dist/adapter/OpencodeSdkAdapter.d.ts.map +1 -1
- package/dist/adapter/OpencodeSdkAdapter.js +2 -0
- package/dist/adapter/SdkProviderSpi.d.ts.map +1 -1
- package/dist/adapter/adapter.test.js +2 -2
- package/dist/adapter/idle-poll-loop.d.ts +4 -4
- package/dist/adapter/idle-poll-loop.d.ts.map +1 -1
- package/dist/adapter/idle-poll-loop.js +3 -3
- package/dist/adapter/idle-poll-loop.test.js +15 -1
- package/dist/adapter/types.d.ts +25 -6
- package/dist/adapter/types.d.ts.map +1 -1
- package/dist/adapter/types.js +221 -110
- package/dist/adapter/types.test.js +10 -3
- package/dist/routes/instance.d.ts.map +1 -1
- package/dist/routes/instance.js +6 -7
- package/dist/routes/runtime-binding.js +2 -2
- package/dist/routes/terminal.d.ts +20 -5
- package/dist/routes/terminal.d.ts.map +1 -1
- package/dist/routes/terminal.js +420 -170
- package/dist/routes/terminal.test.js +380 -208
- package/dist/services/mcp-launch-binding-queue.d.ts +1 -0
- package/dist/services/mcp-launch-binding-queue.d.ts.map +1 -1
- package/dist/services/mcp-launch-binding-queue.js +8 -2
- package/dist/services/mcp-launch-binding-queue.test.js +47 -4
- package/dist/services/session-output.d.ts +10 -6
- package/dist/services/session-output.d.ts.map +1 -1
- package/dist/services/session-output.js +29 -14
- package/dist/services/session-output.test.js +93 -39
- package/package/acode/dist/built-in-file-tools.d.ts +1 -1
- package/package/acode/dist/built-in-file-tools.d.ts.map +1 -1
- package/package/acode/dist/built-in-file-tools.js +388 -50
- package/package/acode/dist/runtime.d.ts +11 -3
- package/package/acode/dist/runtime.d.ts.map +1 -1
- package/package/acode/dist/runtime.js +902 -190
- package/package/acode/dist/types.d.ts +18 -5
- package/package/acode/dist/types.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/mcp-server.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/mcp-server.js +3 -2
- package/package/aws-client-agent-mcp/dist/mcp-server.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/mcp-server.test.js +11 -9
- package/package/aws-client-agent-mcp/dist/mcp-server.test.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/runtime-launch-binding.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/runtime-launch-binding.js +1 -0
- package/package/aws-client-agent-mcp/dist/runtime-launch-binding.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/status-reporter.d.ts +2 -0
- package/package/aws-client-agent-mcp/dist/status-reporter.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/status-reporter.js +31 -3
- package/package/aws-client-agent-mcp/dist/status-reporter.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/types.d.ts +1 -1
- package/package/aws-client-agent-mcp/dist/types.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/types.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/websocket-client.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/websocket-client.js +2 -0
- package/package/aws-client-agent-mcp/dist/websocket-client.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/websocket-client.test.js +43 -0
- package/package/aws-client-agent-mcp/dist/websocket-client.test.js.map +1 -1
- package/package.json +1 -1
|
@@ -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,
|
|
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
|
-
|
|
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 }) =>
|
|
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
|
|
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('
|
|
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
|
-
})
|
|
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('
|
|
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 {
|
|
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<
|
|
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
|
|
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;
|
|
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
|
|
7
|
-
import { schedulerBaseUrl } from
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
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
|
|
5
|
-
import {
|
|
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:
|
|
8
|
-
workspacePath:
|
|
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(
|
|
19
|
-
it(
|
|
20
|
-
sessions.set(
|
|
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(
|
|
23
|
-
const session = sessions.get(
|
|
40
|
+
expect(sessions.has("session-1")).toBe(true);
|
|
41
|
+
const session = sessions.get("session-1");
|
|
24
42
|
if (session)
|
|
25
|
-
session.outputBuffer =
|
|
26
|
-
expect(sessions.get(
|
|
27
|
-
sessions.delete(
|
|
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(
|
|
31
|
-
sessions.set(
|
|
32
|
-
sessions.set(
|
|
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(
|
|
41
|
-
expect(findByAgentId(
|
|
58
|
+
expect(findByAgentId("agent-1")).toBe("session-1");
|
|
59
|
+
expect(findByAgentId("agent-3")).toBe(null);
|
|
42
60
|
});
|
|
43
|
-
it(
|
|
44
|
-
sessions.set(
|
|
45
|
-
appendSessionOutput(
|
|
46
|
-
appendSessionOutput(
|
|
47
|
-
expect(sessions.get(
|
|
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(
|
|
50
|
-
sessions.set(
|
|
51
|
-
appendSessionOutput(
|
|
52
|
-
const output = sessions.get(
|
|
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(
|
|
55
|
-
expect(output.endsWith(
|
|
72
|
+
expect(output).toContain("AgentsWorkStudio: omitted");
|
|
73
|
+
expect(output.endsWith("a")).toBe(true);
|
|
56
74
|
});
|
|
57
|
-
it(
|
|
75
|
+
it("increments sequence correctly", () => {
|
|
58
76
|
const session = createSession();
|
|
59
|
-
sessions.set(
|
|
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(
|
|
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(
|
|
72
|
-
agentId:
|
|
73
|
-
sessionId:
|
|
74
|
-
status:
|
|
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(
|
|
77
|
-
agentId:
|
|
94
|
+
expect(buildStatusPayload("agent-1", null, "stopped")).toEqual({
|
|
95
|
+
agentId: "agent-1",
|
|
78
96
|
sessionId: null,
|
|
79
|
-
status:
|
|
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
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"built-in-file-tools.d.ts","sourceRoot":"","sources":["../src/built-in-file-tools.ts"],"names":[],"mappings":"
|
|
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"}
|