aws-runtime-bridge 1.8.6 → 1.8.7
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.map +1 -1
- package/dist/adapter/AcodeSdkAdapter.js +98 -6
- package/dist/adapter/AcodeSdkAdapter.test.js +313 -2
- package/dist/adapter/OpencodeSdkAdapter.js +1 -1
- package/dist/adapter/types.d.ts.map +1 -1
- package/dist/adapter/types.js +7 -3
- package/dist/config.d.ts +2 -3
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +9 -10
- package/dist/config.test.js +1 -22
- package/dist/routes/ai-sources.js +5 -1
- package/dist/routes/ai-sources.test.js +21 -0
- package/dist/routes/instance.test.js +1 -70
- package/dist/routes/runtime-binding.d.ts.map +1 -1
- package/dist/routes/runtime-binding.js +36 -1
- package/dist/routes/terminal.d.ts +2 -0
- package/dist/routes/terminal.d.ts.map +1 -1
- package/dist/routes/terminal.js +109 -7
- package/dist/routes/terminal.test.js +118 -1
- package/dist/services/mcp-launch-binding-queue.d.ts +7 -0
- package/dist/services/mcp-launch-binding-queue.d.ts.map +1 -1
- package/dist/services/mcp-launch-binding-queue.js +25 -0
- package/dist/services/session-output.d.ts +7 -3
- package/dist/services/session-output.d.ts.map +1 -1
- package/package/acode/dist/runtime.d.ts +1 -0
- package/package/acode/dist/runtime.d.ts.map +1 -1
- package/package/acode/dist/runtime.js +265 -31
- package/package/acode/dist/types.d.ts +1 -1
- package/package/acode/dist/types.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/config.d.ts +4 -0
- package/package/aws-client-agent-mcp/dist/config.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/config.js +15 -0
- package/package/aws-client-agent-mcp/dist/config.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/http-client.d.ts +10 -0
- package/package/aws-client-agent-mcp/dist/http-client.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/http-client.js +79 -1
- package/package/aws-client-agent-mcp/dist/http-client.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/http-client.test.js +129 -265
- package/package/aws-client-agent-mcp/dist/http-client.test.js.map +1 -1
- package/package.json +1 -1
package/dist/config.d.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
export declare const port: number;
|
|
8
8
|
/** 默认调度器基础 URL */
|
|
9
9
|
export declare const DEFAULT_SCHEDULER_BASE_URL = "http://localhost:8080";
|
|
10
|
-
export type SchedulerBaseUrlSource = "env" | "single-auto-register-target" | "
|
|
10
|
+
export type SchedulerBaseUrlSource = "request" | "env" | "single-auto-register-target" | "default" | "ambiguous-auto-register-targets";
|
|
11
11
|
export interface SchedulerBaseUrlResolution {
|
|
12
12
|
url: string;
|
|
13
13
|
source: SchedulerBaseUrlSource;
|
|
@@ -20,8 +20,7 @@ export interface SchedulerBaseUrlResolution {
|
|
|
20
20
|
export declare function resolveSchedulerBaseUrl(): SchedulerBaseUrlResolution;
|
|
21
21
|
/**
|
|
22
22
|
* 解析调度中心基础 URL。
|
|
23
|
-
*
|
|
24
|
-
* 服务端请求携带的 scheduler 地址仅作为本机无配置时的兜底,避免 Docker 容器内地址覆盖机器实例配置。
|
|
23
|
+
* 主流程:服务端请求携带的 scheduler 地址优先;再读显式环境变量;最后回退到单个自动注册目标或默认值。
|
|
25
24
|
*/
|
|
26
25
|
export declare function resolveSchedulerBaseUrlFrom(requestSchedulerBaseUrl: unknown): SchedulerBaseUrlResolution;
|
|
27
26
|
/** 调度器基础 URL(兼容旧导入;请求处理应优先调用 resolveSchedulerBaseUrl 获取最新值) */
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,WAAW;AACX,eAAO,MAAM,IAAI,EAAE,MAElB,CAAC;AAEF,kBAAkB;AAClB,eAAO,MAAM,0BAA0B,0BAA0B,CAAC;AAElE,MAAM,MAAM,sBAAsB,GAC9B,KAAK,GACL,6BAA6B,GAC7B,SAAS,GACT,
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/config.js
CHANGED
|
@@ -80,10 +80,17 @@ export function resolveSchedulerBaseUrl() {
|
|
|
80
80
|
}
|
|
81
81
|
/**
|
|
82
82
|
* 解析调度中心基础 URL。
|
|
83
|
-
*
|
|
84
|
-
* 服务端请求携带的 scheduler 地址仅作为本机无配置时的兜底,避免 Docker 容器内地址覆盖机器实例配置。
|
|
83
|
+
* 主流程:服务端请求携带的 scheduler 地址优先;再读显式环境变量;最后回退到单个自动注册目标或默认值。
|
|
85
84
|
*/
|
|
86
85
|
export function resolveSchedulerBaseUrlFrom(requestSchedulerBaseUrl) {
|
|
86
|
+
const normalizedRequestSchedulerBaseUrl = normalizeSchedulerHttpBaseUrl(requestSchedulerBaseUrl);
|
|
87
|
+
if (normalizedRequestSchedulerBaseUrl) {
|
|
88
|
+
return {
|
|
89
|
+
url: normalizedRequestSchedulerBaseUrl,
|
|
90
|
+
source: "request",
|
|
91
|
+
ambiguousTargetUrls: [],
|
|
92
|
+
};
|
|
93
|
+
}
|
|
87
94
|
const envSchedulerBaseUrl = normalizeSchedulerHttpBaseUrl(process.env.AWS_RUNTIME_SCHEDULER_BASE_URL);
|
|
88
95
|
if (envSchedulerBaseUrl) {
|
|
89
96
|
return {
|
|
@@ -100,14 +107,6 @@ export function resolveSchedulerBaseUrlFrom(requestSchedulerBaseUrl) {
|
|
|
100
107
|
ambiguousTargetUrls: [],
|
|
101
108
|
};
|
|
102
109
|
}
|
|
103
|
-
const normalizedRequestSchedulerBaseUrl = normalizeSchedulerHttpBaseUrl(requestSchedulerBaseUrl);
|
|
104
|
-
if (normalizedRequestSchedulerBaseUrl) {
|
|
105
|
-
return {
|
|
106
|
-
url: normalizedRequestSchedulerBaseUrl,
|
|
107
|
-
source: "request",
|
|
108
|
-
ambiguousTargetUrls: [],
|
|
109
|
-
};
|
|
110
|
-
}
|
|
111
110
|
if (autoRegisterTargetUrls.length > 1) {
|
|
112
111
|
return {
|
|
113
112
|
url: DEFAULT_SCHEDULER_BASE_URL,
|
package/dist/config.test.js
CHANGED
|
@@ -42,33 +42,12 @@ afterEach(() => {
|
|
|
42
42
|
}
|
|
43
43
|
});
|
|
44
44
|
describe("scheduler base URL resolution", () => {
|
|
45
|
-
it("keeps
|
|
45
|
+
it("keeps scheduler URL supplied by the server request as the highest priority", async () => {
|
|
46
46
|
const runtimeHome = createRuntimeHome();
|
|
47
47
|
useRuntimeHome(runtimeHome);
|
|
48
48
|
process.env.AWS_RUNTIME_SCHEDULER_BASE_URL = "http://env.local:7380";
|
|
49
49
|
writeBridgeConfig(runtimeHome, [{ serverUrl: "http://target.local:7380" }]);
|
|
50
50
|
const { resolveSchedulerBaseUrlFrom } = await import("./config.js");
|
|
51
|
-
expect(resolveSchedulerBaseUrlFrom("http://server.local:7380/api")).toEqual({
|
|
52
|
-
url: "http://env.local:7380",
|
|
53
|
-
source: "env",
|
|
54
|
-
ambiguousTargetUrls: [],
|
|
55
|
-
});
|
|
56
|
-
});
|
|
57
|
-
it("keeps a single auto-register target before the server request URL", async () => {
|
|
58
|
-
const runtimeHome = createRuntimeHome();
|
|
59
|
-
useRuntimeHome(runtimeHome);
|
|
60
|
-
writeBridgeConfig(runtimeHome, [{ serverUrl: "http://target.local:7380/api" }]);
|
|
61
|
-
const { resolveSchedulerBaseUrlFrom } = await import("./config.js");
|
|
62
|
-
expect(resolveSchedulerBaseUrlFrom("http://server.local:7380/api")).toEqual({
|
|
63
|
-
url: "http://target.local:7380",
|
|
64
|
-
source: "single-auto-register-target",
|
|
65
|
-
ambiguousTargetUrls: [],
|
|
66
|
-
});
|
|
67
|
-
});
|
|
68
|
-
it("uses scheduler URL supplied by the server request when local bridge config is absent", async () => {
|
|
69
|
-
const runtimeHome = createRuntimeHome();
|
|
70
|
-
useRuntimeHome(runtimeHome);
|
|
71
|
-
const { resolveSchedulerBaseUrlFrom } = await import("./config.js");
|
|
72
51
|
expect(resolveSchedulerBaseUrlFrom("http://server.local:7380/api")).toEqual({
|
|
73
52
|
url: "http://server.local:7380",
|
|
74
53
|
source: "request",
|
|
@@ -59,7 +59,7 @@ async function fetchRemoteModelList(baseUrl, apiKey) {
|
|
|
59
59
|
return normalizeListedModels(anthropicResponse.data);
|
|
60
60
|
}
|
|
61
61
|
aiSourcesRouter.post('/cc-switch/apply-ai-sources', validateToken, async (req, res) => {
|
|
62
|
-
const { agentId, template, ccSwitchEnabledTools, acodeTemplateId, claudecodeTemplateId, codexTemplateId, opencodeTemplateId, acode, claudecode, codex, opencode, } = req.body || {};
|
|
62
|
+
const { agentId, template, ccSwitchEnabledTools, acodeTemplateId, claudecodeTemplateId, codexTemplateId, opencodeTemplateId, acodeModelEffort, claudecodeModelEffort, codexModelEffort, opencodeModelEffort, acode, claudecode, codex, opencode, } = req.body || {};
|
|
63
63
|
if (!agentId) {
|
|
64
64
|
res.status(400).json({ error: 'agentId is required' });
|
|
65
65
|
return;
|
|
@@ -81,6 +81,10 @@ aiSourcesRouter.post('/cc-switch/apply-ai-sources', validateToken, async (req, r
|
|
|
81
81
|
claudecodeTemplateId: String(claudecodeTemplateId || ''),
|
|
82
82
|
codexTemplateId: String(codexTemplateId || ''),
|
|
83
83
|
opencodeTemplateId: String(opencodeTemplateId || ''),
|
|
84
|
+
acodeModelEffort: String(acodeModelEffort || ''),
|
|
85
|
+
claudecodeModelEffort: String(claudecodeModelEffort || ''),
|
|
86
|
+
codexModelEffort: String(codexModelEffort || ''),
|
|
87
|
+
opencodeModelEffort: String(opencodeModelEffort || ''),
|
|
84
88
|
generatedFromUnifiedTemplate: appliedSummary.generatedFromUnifiedTemplate,
|
|
85
89
|
applied: appliedSummary.applied,
|
|
86
90
|
skippedTools: appliedSummary.skippedTools,
|
|
@@ -76,6 +76,14 @@ function buildModelListCandidates(baseUrl, protocol) {
|
|
|
76
76
|
: [`${normalizedBaseUrl}/models`, `${normalizedBaseUrl}/v1/models`];
|
|
77
77
|
return [...openAiCandidates, `${normalizedBaseUrl}/v1/models`];
|
|
78
78
|
}
|
|
79
|
+
function buildApplyAiSourcesResponse(body) {
|
|
80
|
+
return {
|
|
81
|
+
acodeModelEffort: String(body.acodeModelEffort || ''),
|
|
82
|
+
claudecodeModelEffort: String(body.claudecodeModelEffort || ''),
|
|
83
|
+
codexModelEffort: String(body.codexModelEffort || ''),
|
|
84
|
+
opencodeModelEffort: String(body.opencodeModelEffort || ''),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
79
87
|
describe('ai source unified config generation', () => {
|
|
80
88
|
it('builds tool-specific configs from unified template fields', () => {
|
|
81
89
|
assert.deepEqual(buildUnifiedToolConfig({
|
|
@@ -145,4 +153,17 @@ describe('ai source unified config generation', () => {
|
|
|
145
153
|
model: 'gpt-test',
|
|
146
154
|
}).opencode.provider.default.options.baseURL).toBe('https://octopus.721579.xyz/v1');
|
|
147
155
|
});
|
|
156
|
+
it('echoes selected model effort metadata in apply-ai-sources responses', () => {
|
|
157
|
+
expect(buildApplyAiSourcesResponse({
|
|
158
|
+
acodeModelEffort: 'xhigh',
|
|
159
|
+
claudecodeModelEffort: 'high',
|
|
160
|
+
codexModelEffort: 'max',
|
|
161
|
+
opencodeModelEffort: 'high',
|
|
162
|
+
})).toEqual({
|
|
163
|
+
acodeModelEffort: 'xhigh',
|
|
164
|
+
claudecodeModelEffort: 'high',
|
|
165
|
+
codexModelEffort: 'max',
|
|
166
|
+
opencodeModelEffort: 'high',
|
|
167
|
+
});
|
|
168
|
+
});
|
|
148
169
|
});
|
|
@@ -40,8 +40,6 @@ vi.mock('node:child_process', async (importOriginal) => ({
|
|
|
40
40
|
afterEach(() => {
|
|
41
41
|
vi.useRealTimers();
|
|
42
42
|
vi.clearAllMocks();
|
|
43
|
-
delete process.env.AWS_RUNTIME_SCHEDULER_BASE_URL;
|
|
44
|
-
delete process.env.AWS_TEST_HOME;
|
|
45
43
|
});
|
|
46
44
|
function mockSpawnResult(exitCode, stdoutText = '', stderrText = '') {
|
|
47
45
|
spawnMock.mockImplementationOnce(() => {
|
|
@@ -295,7 +293,7 @@ describe('instance route validation', () => {
|
|
|
295
293
|
});
|
|
296
294
|
expect(status).not.toHaveBeenCalled();
|
|
297
295
|
});
|
|
298
|
-
it('
|
|
296
|
+
it('uses scheduler base URL supplied by server ping request before local bridge config', async () => {
|
|
299
297
|
process.env.AWS_RUNTIME_SCHEDULER_BASE_URL = 'http://localhost:8080';
|
|
300
298
|
const { default: axios } = await import('axios');
|
|
301
299
|
const { getRuntimeAccessToken } = await import('../services/runtime-binding.js');
|
|
@@ -309,34 +307,6 @@ describe('instance route validation', () => {
|
|
|
309
307
|
const status = vi.fn(() => ({ json }));
|
|
310
308
|
const header = vi.fn((name) => (name === 'X-Scheduler-Base-Url' ? 'http://server.local:7380/api' : ''));
|
|
311
309
|
await handler?.({ header }, { json, status }, vi.fn());
|
|
312
|
-
expect(getRuntimeAccessToken).toHaveBeenCalledWith(undefined, 'http://localhost:8080');
|
|
313
|
-
expect(axios.get).toHaveBeenCalledWith('http://localhost:8080/api/runtime/ping', {
|
|
314
|
-
headers: { 'X-Runtime-Token': 'stale-runtime-token-123456' },
|
|
315
|
-
});
|
|
316
|
-
expect(json).toHaveBeenCalledWith({
|
|
317
|
-
ok: true,
|
|
318
|
-
runtimeBridge: 'healthy',
|
|
319
|
-
schedulerReachable: true,
|
|
320
|
-
tokenRefreshed: false,
|
|
321
|
-
schedulerBaseUrl: 'http://localhost:8080',
|
|
322
|
-
});
|
|
323
|
-
expect(status).not.toHaveBeenCalled();
|
|
324
|
-
});
|
|
325
|
-
it('uses scheduler base URL supplied by server ping request when bridge has no local scheduler config', async () => {
|
|
326
|
-
delete process.env.AWS_RUNTIME_SCHEDULER_BASE_URL;
|
|
327
|
-
process.env.AWS_TEST_HOME = `${process.cwd()}/.vitest-empty-bridge-home`;
|
|
328
|
-
const { default: axios } = await import('axios');
|
|
329
|
-
const { getRuntimeAccessToken } = await import('../services/runtime-binding.js');
|
|
330
|
-
const { instanceRouter } = await import('./instance.js');
|
|
331
|
-
vi.mocked(getRuntimeAccessToken).mockReturnValue('stale-runtime-token-123456');
|
|
332
|
-
vi.mocked(axios.get).mockReset();
|
|
333
|
-
vi.mocked(axios.get).mockResolvedValueOnce({ status: 200 });
|
|
334
|
-
const handler = instanceRouter.stack.find((layer) => layer.route?.path === '/ping')?.route?.stack[1]?.handle;
|
|
335
|
-
expect(handler).toBeTypeOf('function');
|
|
336
|
-
const json = vi.fn();
|
|
337
|
-
const status = vi.fn(() => ({ json }));
|
|
338
|
-
const header = vi.fn((name) => (name === 'X-Scheduler-Base-Url' ? 'http://server.local:7380/api' : ''));
|
|
339
|
-
await handler?.({ header }, { json, status }, vi.fn());
|
|
340
310
|
expect(getRuntimeAccessToken).toHaveBeenCalledWith(undefined, 'http://server.local:7380');
|
|
341
311
|
expect(axios.get).toHaveBeenCalledWith('http://server.local:7380/api/runtime/ping', {
|
|
342
312
|
headers: { 'X-Runtime-Token': 'stale-runtime-token-123456' },
|
|
@@ -350,45 +320,6 @@ describe('instance route validation', () => {
|
|
|
350
320
|
});
|
|
351
321
|
expect(status).not.toHaveBeenCalled();
|
|
352
322
|
});
|
|
353
|
-
it('keeps single auto-register scheduler config before server ping request header', async () => {
|
|
354
|
-
delete process.env.AWS_RUNTIME_SCHEDULER_BASE_URL;
|
|
355
|
-
const fs = await import('node:fs');
|
|
356
|
-
const path = await import('node:path');
|
|
357
|
-
const testHome = path.join(process.cwd(), '.vitest-single-target-bridge-home');
|
|
358
|
-
const configDir = path.join(testHome, '.aws-bridge');
|
|
359
|
-
fs.rmSync(testHome, { recursive: true, force: true });
|
|
360
|
-
fs.mkdirSync(configDir, { recursive: true });
|
|
361
|
-
fs.writeFileSync(path.join(configDir, 'config.json'), JSON.stringify({
|
|
362
|
-
autoRegisterTargets: [
|
|
363
|
-
{ serverUrl: 'http://bridge-config.local:7380/api' },
|
|
364
|
-
],
|
|
365
|
-
}), 'utf-8');
|
|
366
|
-
process.env.AWS_TEST_HOME = testHome;
|
|
367
|
-
const { default: axios } = await import('axios');
|
|
368
|
-
const { getRuntimeAccessToken } = await import('../services/runtime-binding.js');
|
|
369
|
-
const { instanceRouter } = await import('./instance.js');
|
|
370
|
-
vi.mocked(getRuntimeAccessToken).mockReturnValue('stale-runtime-token-123456');
|
|
371
|
-
vi.mocked(axios.get).mockReset();
|
|
372
|
-
vi.mocked(axios.get).mockResolvedValueOnce({ status: 200 });
|
|
373
|
-
const handler = instanceRouter.stack.find((layer) => layer.route?.path === '/ping')?.route?.stack[1]?.handle;
|
|
374
|
-
expect(handler).toBeTypeOf('function');
|
|
375
|
-
const json = vi.fn();
|
|
376
|
-
const status = vi.fn(() => ({ json }));
|
|
377
|
-
const header = vi.fn((name) => (name === 'X-Scheduler-Base-Url' ? 'http://server.local:7380/api' : ''));
|
|
378
|
-
await handler?.({ header }, { json, status }, vi.fn());
|
|
379
|
-
expect(getRuntimeAccessToken).toHaveBeenCalledWith(undefined, 'http://bridge-config.local:7380');
|
|
380
|
-
expect(axios.get).toHaveBeenCalledWith('http://bridge-config.local:7380/api/runtime/ping', {
|
|
381
|
-
headers: { 'X-Runtime-Token': 'stale-runtime-token-123456' },
|
|
382
|
-
});
|
|
383
|
-
expect(json).toHaveBeenCalledWith({
|
|
384
|
-
ok: true,
|
|
385
|
-
runtimeBridge: 'healthy',
|
|
386
|
-
schedulerReachable: true,
|
|
387
|
-
tokenRefreshed: false,
|
|
388
|
-
schedulerBaseUrl: 'http://bridge-config.local:7380',
|
|
389
|
-
});
|
|
390
|
-
expect(status).not.toHaveBeenCalled();
|
|
391
|
-
});
|
|
392
323
|
it('explains ambiguous auto-register scheduler targets without picking the first one', async () => {
|
|
393
324
|
const { buildAmbiguousSchedulerBaseUrlResponse } = await import('./instance.js');
|
|
394
325
|
const response = buildAmbiguousSchedulerBaseUrlResponse([
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime-binding.d.ts","sourceRoot":"","sources":["../../src/routes/runtime-binding.ts"],"names":[],"mappings":"AAmBA,eAAO,MAAM,oBAAoB,4CAAW,CAAC;AAE7C,MAAM,WAAW,wBAAwB;IACvC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,0BAA0B,CAAC,EAAE,OAAO,CAAC;CACtC;AAED,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,OAAO,CAAC;IACjB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,wBAAwB,GAC9B,yBAAyB,CAM3B;
|
|
1
|
+
{"version":3,"file":"runtime-binding.d.ts","sourceRoot":"","sources":["../../src/routes/runtime-binding.ts"],"names":[],"mappings":"AAmBA,eAAO,MAAM,oBAAoB,4CAAW,CAAC;AAE7C,MAAM,WAAW,wBAAwB;IACvC,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,0BAA0B,CAAC,EAAE,OAAO,CAAC;CACtC;AAED,MAAM,WAAW,yBAAyB;IACxC,OAAO,EAAE,OAAO,CAAC;IACjB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;;GAGG;AACH,wBAAgB,0BAA0B,CACxC,KAAK,EAAE,wBAAwB,GAC9B,yBAAyB,CAM3B;AAgPD,wBAAgB,6BAA6B,IAAI,IAAI,CAapD"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Router } from "express";
|
|
2
2
|
import { validateToken } from "../middleware/auth.js";
|
|
3
|
-
import { claimMcpLaunchBinding, getMcpLaunchQueueSize } from "../services/mcp-launch-binding-queue.js";
|
|
3
|
+
import { claimMcpLaunchBinding, getLatestAgentToken, getMcpLaunchQueueSize } from "../services/mcp-launch-binding-queue.js";
|
|
4
4
|
import { clearRuntimeBinding, getRuntimeAccessToken, getRuntimeBindingPublicState, getRuntimePairingCode, hasRuntimeBinding, saveRuntimeBinding, validateRuntimeBindingToken, validateRuntimePairingCode, } from "../services/runtime-binding.js";
|
|
5
5
|
import { createLogger } from "../utils/logger.js";
|
|
6
6
|
const log = createLogger("runtime-binding-route");
|
|
@@ -133,6 +133,41 @@ runtimeBindingRouter.post("/binding/claim-agent", (req, res) => {
|
|
|
133
133
|
remainingQueueSize: getMcpLaunchQueueSize(workspacePath),
|
|
134
134
|
});
|
|
135
135
|
});
|
|
136
|
+
/**
|
|
137
|
+
* MCP node 在 401 后向 bridge 查询最新 session token 的端点。
|
|
138
|
+
* 仅接受本地回环请求,仅返回缓存中最新的 token。
|
|
139
|
+
*/
|
|
140
|
+
runtimeBindingRouter.post("/binding/refresh-token", (req, res) => {
|
|
141
|
+
if (!isLoopbackRequest(req)) {
|
|
142
|
+
res.status(403).json({ ok: false, error: "loopback request required" });
|
|
143
|
+
return;
|
|
144
|
+
}
|
|
145
|
+
const { agentId, currentToken } = req.body || {};
|
|
146
|
+
const normalizedAgentId = String(agentId || "").trim();
|
|
147
|
+
if (!normalizedAgentId) {
|
|
148
|
+
res.status(400).json({ ok: false, error: "agentId is required" });
|
|
149
|
+
return;
|
|
150
|
+
}
|
|
151
|
+
const latest = getLatestAgentToken(normalizedAgentId);
|
|
152
|
+
if (!latest) {
|
|
153
|
+
res.status(404).json({ ok: false, error: "no cached token for agent" });
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
// 如果最新 token 与当前 token 相同,说明服务端已撤销,bridge 侧没有更新的
|
|
157
|
+
const normalizedCurrent = String(currentToken || "").trim();
|
|
158
|
+
if (normalizedCurrent && latest.runtimeAccessToken === normalizedCurrent) {
|
|
159
|
+
res.status(409).json({
|
|
160
|
+
ok: false,
|
|
161
|
+
error: "token_unchanged",
|
|
162
|
+
message: "Bridge cached token is the same as current; token may be revoked server-side",
|
|
163
|
+
});
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
res.json({
|
|
167
|
+
ok: true,
|
|
168
|
+
runtimeAccessToken: latest.runtimeAccessToken,
|
|
169
|
+
});
|
|
170
|
+
});
|
|
136
171
|
runtimeBindingRouter.post("/binding/issue", validateToken, (req, res) => {
|
|
137
172
|
const { accessToken, instanceId, userId, schedulerBaseUrl } = req.body || {};
|
|
138
173
|
const nextToken = String(accessToken || "").trim();
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import { TextDecoder } from "node:util";
|
|
8
8
|
import { type AdapterSessionConfig, type ProviderEvent, type RuntimeStatusActionInfo } from "../adapter/index.js";
|
|
9
|
+
import { type RuntimeOutputMetadata } from "../services/session-output.js";
|
|
9
10
|
import type { PersistedSession } from "../types.js";
|
|
10
11
|
export declare const terminalRouter: import("express-serve-static-core").Router;
|
|
11
12
|
export interface SdkSessionEntry {
|
|
@@ -91,6 +92,7 @@ export declare function buildClaudeCodeLaunchConfig(savedClaudeConfig: {
|
|
|
91
92
|
*/
|
|
92
93
|
export declare function buildToolResultTimelineActionInfo(event: ProviderEvent): RuntimeStatusActionInfo | undefined;
|
|
93
94
|
export declare function formatSdkOutputEvent(event: ProviderEvent): string | undefined;
|
|
95
|
+
export declare function buildSdkOutputMetadata(event: ProviderEvent): RuntimeOutputMetadata;
|
|
94
96
|
/**
|
|
95
97
|
* 主干流程:把 provider 事件转换为面板运行状态。
|
|
96
98
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"terminal.d.ts","sourceRoot":"","sources":["../../src/routes/terminal.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAKxC,OAAO,EAOL,KAAK,oBAAoB,EAEzB,KAAK,aAAa,EAClB,KAAK,uBAAuB,
|
|
1
|
+
{"version":3,"file":"terminal.d.ts","sourceRoot":"","sources":["../../src/routes/terminal.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAKxC,OAAO,EAOL,KAAK,oBAAoB,EAEzB,KAAK,aAAa,EAClB,KAAK,uBAAuB,EAG7B,MAAM,qBAAqB,CAAC;AAS7B,OAAO,EAIL,KAAK,qBAAqB,EAC3B,MAAM,+BAA+B,CAAC;AASvC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpD,eAAO,MAAM,cAAc,4CAAW,CAAC;AAIvC,MAAM,WAAW,eAAe;IAC9B,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,oBAAoB,CAAC;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,wBAAwB,CAAC,EAAE,MAAM,CAAC;IAClC,yBAAyB,CAAC,EAAE,MAAM,CAAC;IACnC,0BAA0B,CAAC,EAAE,MAAM,CAAC;CACrC;AAGD,eAAO,MAAM,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,CAAa,CAAC;AAMnE,wBAAgB,wBAAwB,CAAC,UAAU,CAAC,EAAE,uBAAuB;;;cAa5E;AA0BD,wBAAgB,2BAA2B,CACzC,aAAa,EAAE,MAAM,EACrB,GAAG,OAAa,GACf,MAAM,CAoBR;AAED,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAW/D;AAED,wBAAgB,kCAAkC,CAChD,UAAU,EAAE,MAAM,EAClB,SAAS,SAA+C,GACvD,MAAM,CAER;AAED,wBAAgB,oCAAoC,CAClD,SAAS,SAAyC,GACjD,MAAM,CAIR;AAcD;;GAEG;AACH,wBAAgB,6BAA6B,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAIpE;AAED;;;GAGG;AACH,wBAAgB,6BAA6B,CAC3C,QAAQ,GAAE,MAAM,CAAC,QAA2B,EAC5C,GAAG,GAAE,MAAM,CAAC,UAAwB,GACnC,MAAM,CAQR;AAED;;GAEG;AACH,wBAAgB,2BAA2B,CACzC,QAAQ,SAAkC,GACzC,WAAW,CAMb;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,EAAE,WAAW,EACpB,KAAK,CAAC,EAAE,MAAM,EACd,GAAG,UAAQ,GACV,MAAM,CAQR;AAED;;GAEG;AACH,wBAAgB,kCAAkC,CAChD,OAAO,EAAE,MAAM,GACd,MAAM,GAAG,IAAI,GAAG,SAAS,CAmB3B;AAmDD;;;GAGG;AACH,wBAAgB,8BAA8B,CAC5C,aAAa,CAAC,EAAE,MAAM,EACtB,oBAAoB,CAAC,EAAE,MAAM,GAC5B,MAAM,CAOR;AAED,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,EAAE,OAAO,CAAC;IAClB,MAAM,EAAE,YAAY,GAAG,aAAa,GAAG,UAAU,GAAG,qBAAqB,CAAC;CAC3E;AAED;;;GAGG;AACH,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,IAAI,CAAC,gBAAgB,EAAE,KAAK,CAAC,GACpC,OAAO,CAAC,IAAI,CAAC,gBAAgB,EAAE,SAAS,CAAC,CAAC,EAC5C,YAAY,GAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAA0B,GACxD,6BAA6B,CAc/B;AA2BD;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,gBAAgB,EAAE,MAAM,GAAG,MAAM,CAErE;AAmOD,wBAAgB,eAAe,CAC7B,OAAO,EAAE,MAAM,EACf,aAAa,EAAE,MAAM,GAAG,SAAS,EACjC,OAAO,EAAE,MAAM,CAAC,UAAU,EAC1B,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACrC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CA+BxB;AAYD;;;GAGG;AACH,wBAAsB,sBAAsB,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,CAAC,MAAM,CAAC,CAY5E;AAED,MAAM,WAAW,sBAAsB;IACrC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED;;GAEG;AACH,wBAAgB,2BAA2B,CACzC,iBAAiB,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAE,GAAG,IAAI,GAAG,SAAS,EACvE,mBAAmB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5C,sBAAsB,CAyBxB;AAoDD;;;GAGG;AACH,wBAAgB,iCAAiC,CAC/C,KAAK,EAAE,aAAa,GACnB,uBAAuB,GAAG,SAAS,CAyCrC;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,GAAG,SAAS,CAwB7E;AAED,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,aAAa,GACnB,qBAAqB,CAYvB;AAsJD;;;;;GAKG;AACH,wBAAgB,qCAAqC,CAAC,KAAK,EAAE,aAAa,GACtE;IACE,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,uBAAuB,CAAC;CACtC,GACD,SAAS,CAyEZ;AAsBD,wBAAgB,oBAAoB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAE7D"}
|
package/dist/routes/terminal.js
CHANGED
|
@@ -573,6 +573,111 @@ export function formatSdkOutputEvent(event) {
|
|
|
573
573
|
}
|
|
574
574
|
return undefined;
|
|
575
575
|
}
|
|
576
|
+
export function buildSdkOutputMetadata(event) {
|
|
577
|
+
const logMessage = formatSdkLogMessage(event);
|
|
578
|
+
return {
|
|
579
|
+
sourceEventType: event.type,
|
|
580
|
+
logCategory: "acode",
|
|
581
|
+
...(logMessage
|
|
582
|
+
? {
|
|
583
|
+
logLevel: event.type === "error" ? "error" : "info",
|
|
584
|
+
logMessage,
|
|
585
|
+
}
|
|
586
|
+
: {}),
|
|
587
|
+
};
|
|
588
|
+
}
|
|
589
|
+
function formatSdkLogMessage(event) {
|
|
590
|
+
if (event.type === "ai_request") {
|
|
591
|
+
const model = event.data.model || "unknown-model";
|
|
592
|
+
const endpoint = event.data.endpoint ? ` @ ${event.data.endpoint}` : "";
|
|
593
|
+
const toolCount = typeof event.data.toolCount === "number"
|
|
594
|
+
? `, tools=${event.data.toolCount}`
|
|
595
|
+
: "";
|
|
596
|
+
return `AI request started: ${model}${endpoint}${toolCount}`;
|
|
597
|
+
}
|
|
598
|
+
if (event.type === "tool_use_start") {
|
|
599
|
+
return formatSdkToolLogMessage(event, "开始");
|
|
600
|
+
}
|
|
601
|
+
if (event.type === "tool_use_end") {
|
|
602
|
+
return formatSdkToolLogMessage(event, "完成");
|
|
603
|
+
}
|
|
604
|
+
if (event.type === "turn_complete") {
|
|
605
|
+
const finishReason = event.data.finishReason
|
|
606
|
+
? `, finish=${event.data.finishReason}`
|
|
607
|
+
: "";
|
|
608
|
+
return `Turn completed${finishReason}`;
|
|
609
|
+
}
|
|
610
|
+
if (event.type === "session_complete") {
|
|
611
|
+
return `Session completed: exitCode=${event.data.exitCode ?? 0}`;
|
|
612
|
+
}
|
|
613
|
+
if (event.type === "error") {
|
|
614
|
+
return event.data.text || "ACode runtime error";
|
|
615
|
+
}
|
|
616
|
+
return undefined;
|
|
617
|
+
}
|
|
618
|
+
function formatSdkToolLogMessage(event, phaseLabel) {
|
|
619
|
+
const actionInfo = getToolActionInfo(event.data.toolName, event.data.toolInput);
|
|
620
|
+
const actionLabel = event.data.actionLabel || actionInfo.actionLabel || "调用工具";
|
|
621
|
+
const detail = resolveSdkToolLogDetail(event, actionInfo);
|
|
622
|
+
return detail
|
|
623
|
+
? `${phaseLabel}${actionLabel}: ${detail}`
|
|
624
|
+
: `${phaseLabel}${actionLabel}: ${event.data.actionDetail || event.data.toolName || "tool"}`;
|
|
625
|
+
}
|
|
626
|
+
function resolveSdkToolLogDetail(event, actionInfo) {
|
|
627
|
+
const input = event.data.toolInput;
|
|
628
|
+
if (actionInfo.actionType === "bash") {
|
|
629
|
+
return getCommandDisplayDetail(input) || event.data.actionDetail || actionInfo.actionDetail;
|
|
630
|
+
}
|
|
631
|
+
if (actionInfo.actionType === "read_file" ||
|
|
632
|
+
actionInfo.actionType === "edit_file" ||
|
|
633
|
+
actionInfo.actionType === "write_file") {
|
|
634
|
+
return getFileDisplayDetail(input) || event.data.actionDetail || actionInfo.actionDetail;
|
|
635
|
+
}
|
|
636
|
+
return event.data.actionDetail || actionInfo.actionDetail;
|
|
637
|
+
}
|
|
638
|
+
function getCommandDisplayDetail(input) {
|
|
639
|
+
const command = firstDisplayString(input?.command, input?.cmd);
|
|
640
|
+
if (command)
|
|
641
|
+
return command;
|
|
642
|
+
if (Array.isArray(input?.argv)) {
|
|
643
|
+
const argv = input.argv
|
|
644
|
+
.map((item) => String(item ?? "").trim())
|
|
645
|
+
.filter(Boolean)
|
|
646
|
+
.join(" ");
|
|
647
|
+
return argv ? redactTransientClipboardPastePaths(argv) : undefined;
|
|
648
|
+
}
|
|
649
|
+
return firstDisplayString(input?.args);
|
|
650
|
+
}
|
|
651
|
+
function getFileDisplayDetail(input) {
|
|
652
|
+
const paths = displayStringList(input?.paths);
|
|
653
|
+
if (paths.length > 0) {
|
|
654
|
+
return paths.length === 1
|
|
655
|
+
? paths[0]
|
|
656
|
+
: `${paths.length}个文件: ${paths.join(", ")}`;
|
|
657
|
+
}
|
|
658
|
+
return firstDisplayString(input?.file_path, input?.filePath, input?.path, input?.target_file, input?.targetFile);
|
|
659
|
+
}
|
|
660
|
+
function firstDisplayString(...values) {
|
|
661
|
+
for (const value of values) {
|
|
662
|
+
if (typeof value === "string" && value.trim()) {
|
|
663
|
+
return redactTransientClipboardPastePaths(value.trim());
|
|
664
|
+
}
|
|
665
|
+
if (Array.isArray(value)) {
|
|
666
|
+
const first = displayStringList(value)[0];
|
|
667
|
+
if (first)
|
|
668
|
+
return first;
|
|
669
|
+
}
|
|
670
|
+
}
|
|
671
|
+
return undefined;
|
|
672
|
+
}
|
|
673
|
+
function displayStringList(value) {
|
|
674
|
+
if (!Array.isArray(value))
|
|
675
|
+
return [];
|
|
676
|
+
return value
|
|
677
|
+
.map((item) => (typeof item === "string" ? item.trim() : ""))
|
|
678
|
+
.filter(Boolean)
|
|
679
|
+
.map((item) => redactTransientClipboardPastePaths(item));
|
|
680
|
+
}
|
|
576
681
|
function formatAiRequestDetail(data) {
|
|
577
682
|
const lines = [
|
|
578
683
|
data.model ? `模型: ${data.model}` : undefined,
|
|
@@ -617,6 +722,7 @@ export function resolveRuntimeStatusFromProviderEvent(event) {
|
|
|
617
722
|
}
|
|
618
723
|
if (event.type === "tool_use_start") {
|
|
619
724
|
const inferredAction = getToolActionInfo(event.data.toolName, event.data.toolInput);
|
|
725
|
+
const actionDetail = resolveSdkToolLogDetail(event, inferredAction);
|
|
620
726
|
if (event.data.actionType === "idle" ||
|
|
621
727
|
inferredAction.actionType === "idle") {
|
|
622
728
|
return {
|
|
@@ -624,9 +730,7 @@ export function resolveRuntimeStatusFromProviderEvent(event) {
|
|
|
624
730
|
actionInfo: {
|
|
625
731
|
actionType: event.data.actionType || inferredAction.actionType,
|
|
626
732
|
actionLabel: event.data.actionLabel || inferredAction.actionLabel,
|
|
627
|
-
actionDetail: event.data.actionDetail ||
|
|
628
|
-
inferredAction.actionDetail ||
|
|
629
|
-
event.data.toolName,
|
|
733
|
+
actionDetail: actionDetail || event.data.actionDetail || inferredAction.actionDetail || event.data.toolName,
|
|
630
734
|
actionId: event.data.actionId || event.data.toolUseId,
|
|
631
735
|
},
|
|
632
736
|
};
|
|
@@ -636,9 +740,7 @@ export function resolveRuntimeStatusFromProviderEvent(event) {
|
|
|
636
740
|
actionInfo: {
|
|
637
741
|
actionType: event.data.actionType || inferredAction.actionType,
|
|
638
742
|
actionLabel: event.data.actionLabel || inferredAction.actionLabel,
|
|
639
|
-
actionDetail: event.data.actionDetail ||
|
|
640
|
-
inferredAction.actionDetail ||
|
|
641
|
-
event.data.toolName,
|
|
743
|
+
actionDetail: actionDetail || event.data.actionDetail || inferredAction.actionDetail || event.data.toolName,
|
|
642
744
|
actionId: event.data.actionId || event.data.toolUseId,
|
|
643
745
|
},
|
|
644
746
|
};
|
|
@@ -670,7 +772,7 @@ function forwardSdkOutputEvent(event, entry) {
|
|
|
670
772
|
return;
|
|
671
773
|
}
|
|
672
774
|
entry.seq += 1;
|
|
673
|
-
void sendOutput(entry.agentId, output, event.sessionId, entry.seq,
|
|
775
|
+
void sendOutput(entry.agentId, output, event.sessionId, entry.seq, buildSdkOutputMetadata(event), { runtimeAccessToken: entry.runtimeAccessToken });
|
|
674
776
|
}
|
|
675
777
|
export function resolveSdkProviderId(command) {
|
|
676
778
|
return resolveSdkProviderIdByCommand(command);
|
|
@@ -3,7 +3,7 @@ import os from "node:os";
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { describe, expect, it } from "vitest";
|
|
5
5
|
import { SDK_PROVIDER_DEFINITIONS } from "../adapter/SdkProviderSpi.js";
|
|
6
|
-
import { buildAcodeCommandOutputPath, buildClaudeCodeLaunchConfig, buildRuntimeEnv, buildToolResultTimelineActionInfo, countTerminalOutputLines, createTerminalOutputDecoder, decodeTerminalOutputChunk, evaluatePersistedSessionReuse, formatCommandInactivityTimeoutNotice, formatCommandOutputSpilloverNotice, formatTerminalPrompt, formatSdkOutputEvent, normalizeTerminalCommandInput, parseTerminalDirectoryChangeTarget, resolveSdkInputMessage, resolveTerminalOutputEncoding, resolveSdkProviderId, resolveSdkSessionDisplayStatus, resolveRuntimeStatusFromProviderEvent, resolveStatusChangeUsage, } from "./terminal.js";
|
|
6
|
+
import { buildAcodeCommandOutputPath, buildClaudeCodeLaunchConfig, buildRuntimeEnv, buildSdkOutputMetadata, buildToolResultTimelineActionInfo, countTerminalOutputLines, createTerminalOutputDecoder, decodeTerminalOutputChunk, evaluatePersistedSessionReuse, formatCommandInactivityTimeoutNotice, formatCommandOutputSpilloverNotice, formatTerminalPrompt, formatSdkOutputEvent, normalizeTerminalCommandInput, parseTerminalDirectoryChangeTarget, resolveSdkInputMessage, resolveTerminalOutputEncoding, resolveSdkProviderId, resolveSdkSessionDisplayStatus, resolveRuntimeStatusFromProviderEvent, resolveStatusChangeUsage, } from "./terminal.js";
|
|
7
7
|
describe("terminal route validation", () => {
|
|
8
8
|
it("requires agentId and workspacePath for start", () => {
|
|
9
9
|
const validateStartRequest = (body) => {
|
|
@@ -377,6 +377,44 @@ describe("SDK status usage forwarding", () => {
|
|
|
377
377
|
},
|
|
378
378
|
});
|
|
379
379
|
});
|
|
380
|
+
it("includes file paths and commands in tool status action details", () => {
|
|
381
|
+
expect(resolveRuntimeStatusFromProviderEvent({
|
|
382
|
+
type: "tool_use_start",
|
|
383
|
+
sessionId: "session-1",
|
|
384
|
+
timestamp: new Date(0).toISOString(),
|
|
385
|
+
data: {
|
|
386
|
+
toolName: "builtin/read_file",
|
|
387
|
+
toolInput: { path: "src/views/App.vue" },
|
|
388
|
+
toolUseId: "tool-read",
|
|
389
|
+
},
|
|
390
|
+
})).toEqual({
|
|
391
|
+
status: "tool_using",
|
|
392
|
+
actionInfo: {
|
|
393
|
+
actionType: "read_file",
|
|
394
|
+
actionLabel: "读取文件",
|
|
395
|
+
actionDetail: "src/views/App.vue",
|
|
396
|
+
actionId: "tool-read",
|
|
397
|
+
},
|
|
398
|
+
});
|
|
399
|
+
expect(resolveRuntimeStatusFromProviderEvent({
|
|
400
|
+
type: "tool_use_start",
|
|
401
|
+
sessionId: "session-1",
|
|
402
|
+
timestamp: new Date(0).toISOString(),
|
|
403
|
+
data: {
|
|
404
|
+
toolName: "bash",
|
|
405
|
+
toolInput: { command: "npm run test:agent-timeline-panel" },
|
|
406
|
+
toolUseId: "tool-bash",
|
|
407
|
+
},
|
|
408
|
+
})).toEqual({
|
|
409
|
+
status: "tool_using",
|
|
410
|
+
actionInfo: {
|
|
411
|
+
actionType: "bash",
|
|
412
|
+
actionLabel: "执行命令",
|
|
413
|
+
actionDetail: "npm run test:agent-timeline-panel",
|
|
414
|
+
actionId: "tool-bash",
|
|
415
|
+
},
|
|
416
|
+
});
|
|
417
|
+
});
|
|
380
418
|
});
|
|
381
419
|
describe("SDK output forwarding", () => {
|
|
382
420
|
it("formats assistant text provider events for the terminal output callback path", () => {
|
|
@@ -425,6 +463,85 @@ describe("SDK output forwarding", () => {
|
|
|
425
463
|
};
|
|
426
464
|
expect(formatSdkOutputEvent(requestEvent)).toBe("\r\n[ACode] 正在请求模型 test-model:inspect status\r\n");
|
|
427
465
|
});
|
|
466
|
+
it("builds ACode log metadata for output callbacks", () => {
|
|
467
|
+
const requestEvent = {
|
|
468
|
+
type: "ai_request",
|
|
469
|
+
sessionId: "session-1",
|
|
470
|
+
timestamp: new Date(0).toISOString(),
|
|
471
|
+
data: { model: "test-model", endpoint: "openai-compatible", toolCount: 2 },
|
|
472
|
+
};
|
|
473
|
+
const errorEvent = {
|
|
474
|
+
type: "error",
|
|
475
|
+
sessionId: "session-1",
|
|
476
|
+
timestamp: new Date(0).toISOString(),
|
|
477
|
+
data: { text: "provider failed" },
|
|
478
|
+
};
|
|
479
|
+
expect(buildSdkOutputMetadata(requestEvent)).toEqual({
|
|
480
|
+
sourceEventType: "ai_request",
|
|
481
|
+
logCategory: "acode",
|
|
482
|
+
logLevel: "info",
|
|
483
|
+
logMessage: "AI request started: test-model @ openai-compatible, tools=2",
|
|
484
|
+
});
|
|
485
|
+
expect(buildSdkOutputMetadata(errorEvent)).toEqual({
|
|
486
|
+
sourceEventType: "error",
|
|
487
|
+
logCategory: "acode",
|
|
488
|
+
logLevel: "error",
|
|
489
|
+
logMessage: "provider failed",
|
|
490
|
+
});
|
|
491
|
+
});
|
|
492
|
+
it("does not mark streaming text chunks as standalone ACode log rows", () => {
|
|
493
|
+
const metadata = buildSdkOutputMetadata({
|
|
494
|
+
type: "text_delta",
|
|
495
|
+
sessionId: "session-1",
|
|
496
|
+
data: { text: "word" },
|
|
497
|
+
});
|
|
498
|
+
expect(metadata).toEqual({
|
|
499
|
+
sourceEventType: "text_delta",
|
|
500
|
+
logCategory: "acode",
|
|
501
|
+
});
|
|
502
|
+
});
|
|
503
|
+
it("includes file paths and commands in ACode tool log metadata", () => {
|
|
504
|
+
const readEvent = {
|
|
505
|
+
type: "tool_use_start",
|
|
506
|
+
sessionId: "session-1",
|
|
507
|
+
timestamp: new Date(0).toISOString(),
|
|
508
|
+
data: {
|
|
509
|
+
toolName: "read_file",
|
|
510
|
+
toolInput: { path: "src/index.ts" },
|
|
511
|
+
},
|
|
512
|
+
};
|
|
513
|
+
const editEvent = {
|
|
514
|
+
type: "tool_use_start",
|
|
515
|
+
sessionId: "session-1",
|
|
516
|
+
timestamp: new Date(0).toISOString(),
|
|
517
|
+
data: {
|
|
518
|
+
toolName: "edit",
|
|
519
|
+
toolInput: { file_path: "src/app.ts" },
|
|
520
|
+
},
|
|
521
|
+
};
|
|
522
|
+
const writeEvent = {
|
|
523
|
+
type: "tool_use_end",
|
|
524
|
+
sessionId: "session-1",
|
|
525
|
+
timestamp: new Date(0).toISOString(),
|
|
526
|
+
data: {
|
|
527
|
+
toolName: "write_file",
|
|
528
|
+
toolInput: { path: "src/new-file.ts" },
|
|
529
|
+
},
|
|
530
|
+
};
|
|
531
|
+
const bashEvent = {
|
|
532
|
+
type: "tool_use_start",
|
|
533
|
+
sessionId: "session-1",
|
|
534
|
+
timestamp: new Date(0).toISOString(),
|
|
535
|
+
data: {
|
|
536
|
+
toolName: "bash",
|
|
537
|
+
toolInput: { command: "npm run build -- --mode production" },
|
|
538
|
+
},
|
|
539
|
+
};
|
|
540
|
+
expect(buildSdkOutputMetadata(readEvent).logMessage).toBe("开始读取文件: src/index.ts");
|
|
541
|
+
expect(buildSdkOutputMetadata(editEvent).logMessage).toBe("开始编辑文件: src/app.ts");
|
|
542
|
+
expect(buildSdkOutputMetadata(writeEvent).logMessage).toBe("完成写入文件: src/new-file.ts");
|
|
543
|
+
expect(buildSdkOutputMetadata(bashEvent).logMessage).toBe("开始执行命令: npm run build -- --mode production");
|
|
544
|
+
});
|
|
428
545
|
});
|
|
429
546
|
describe("SDK tool result timeline action info", () => {
|
|
430
547
|
it("keeps MCP tool results on MCP timeline events", () => {
|
|
@@ -32,4 +32,11 @@ export declare function enqueueMcpLaunchBinding(input: McpLaunchBindingInput): M
|
|
|
32
32
|
export declare function claimMcpLaunchBinding(request: McpLaunchBindingClaimRequest): ClaimedMcpLaunchBinding | null;
|
|
33
33
|
export declare function getMcpLaunchQueueSize(workspacePath: unknown): number;
|
|
34
34
|
export declare function clearMcpLaunchBindingQueues(): void;
|
|
35
|
+
/**
|
|
36
|
+
* 获取指定 agent 的最新 MCP session token。
|
|
37
|
+
* 供 MCP node 在 401 后向 bridge 查询最新 token 使用。
|
|
38
|
+
*/
|
|
39
|
+
export declare function getLatestAgentToken(agentId: string): {
|
|
40
|
+
runtimeAccessToken: string;
|
|
41
|
+
} | null;
|
|
35
42
|
//# sourceMappingURL=mcp-launch-binding-queue.d.ts.map
|