aws-runtime-bridge 1.2.1 → 1.3.1
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/ClaudeSdkAdapter.d.ts +1 -0
- package/dist/adapter/ClaudeSdkAdapter.d.ts.map +1 -1
- package/dist/adapter/ClaudeSdkAdapter.js +7 -3
- package/dist/adapter/ClaudeSdkAdapter.test.js +2 -2
- package/dist/adapter/CodexSdkAdapter.d.ts.map +1 -1
- package/dist/adapter/CodexSdkAdapter.js +7 -4
- package/dist/adapter/CodexSdkAdapter.test.js +4 -2
- package/dist/adapter/OpencodeSdkAdapter.d.ts +2 -0
- package/dist/adapter/OpencodeSdkAdapter.d.ts.map +1 -1
- package/dist/adapter/OpencodeSdkAdapter.js +15 -1
- package/dist/adapter/OpencodeSdkAdapter.test.js +5 -0
- package/dist/routes/runtime-binding.d.ts.map +1 -1
- package/dist/routes/runtime-binding.js +8 -13
- package/dist/routes/terminal.js +2 -5
- package/dist/routes/terminal.test.js +3 -4
- package/dist/services/auto-register.d.ts +6 -0
- package/dist/services/auto-register.d.ts.map +1 -1
- package/dist/services/auto-register.js +63 -1
- package/dist/services/aws-client-agent-mcp.d.ts.map +1 -1
- package/dist/services/aws-client-agent-mcp.js +4 -4
- package/dist/services/aws-client-agent-mcp.test.js +14 -0
- package/dist/services/mcp-launch-binding-queue.d.ts +0 -2
- package/dist/services/mcp-launch-binding-queue.d.ts.map +1 -1
- package/dist/services/mcp-launch-binding-queue.js +44 -16
- package/dist/services/mcp-launch-binding-queue.test.js +42 -37
- package/dist/services/runtime-binding.d.ts +1 -0
- package/dist/services/runtime-binding.d.ts.map +1 -1
- package/dist/services/runtime-binding.js +39 -5
- package/dist/services/runtime-binding.test.d.ts +2 -0
- package/dist/services/runtime-binding.test.d.ts.map +1 -0
- package/dist/services/runtime-binding.test.js +11 -0
- package/package/aws-client-agent-mcp/dist/agent-client.d.ts +1 -0
- package/package/aws-client-agent-mcp/dist/agent-client.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/agent-client.js +12 -0
- package/package/aws-client-agent-mcp/dist/agent-client.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/agent-client.test.js +31 -0
- package/package/aws-client-agent-mcp/dist/agent-client.test.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/config.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/config.js +96 -13
- package/package/aws-client-agent-mcp/dist/config.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/config.test.js +26 -8
- package/package/aws-client-agent-mcp/dist/config.test.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/constants.d.ts +0 -1
- package/package/aws-client-agent-mcp/dist/constants.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/constants.js +0 -1
- package/package/aws-client-agent-mcp/dist/constants.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/http-client.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/http-client.js +49 -13
- package/package/aws-client-agent-mcp/dist/http-client.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/http-client.test.js +40 -13
- package/package/aws-client-agent-mcp/dist/http-client.test.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/index.js +11 -6
- package/package/aws-client-agent-mcp/dist/index.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/logger.d.ts +11 -1
- package/package/aws-client-agent-mcp/dist/logger.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/logger.js +91 -6
- package/package/aws-client-agent-mcp/dist/logger.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/logger.test.d.ts +2 -0
- package/package/aws-client-agent-mcp/dist/logger.test.d.ts.map +1 -0
- package/package/aws-client-agent-mcp/dist/logger.test.js +27 -0
- package/package/aws-client-agent-mcp/dist/logger.test.js.map +1 -0
- 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 +18 -14
- package/package/aws-client-agent-mcp/dist/runtime-launch-binding.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/runtime-launch-binding.test.js +51 -21
- package/package/aws-client-agent-mcp/dist/runtime-launch-binding.test.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/types.d.ts +3 -2
- 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 +1 -0
- package/package/aws-client-agent-mcp/dist/websocket-client.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/websocket-client.js +18 -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 +53 -2
- package/package/aws-client-agent-mcp/dist/websocket-client.test.js.map +1 -1
- package/package.json +1 -1
|
@@ -72,6 +72,7 @@ export declare class ClaudeSdkAdapter extends EventEmitter implements BaseProvid
|
|
|
72
72
|
private sendIdlePrompt;
|
|
73
73
|
private isTaskPollingIdleCommand;
|
|
74
74
|
private isMessagePollingIdleCommand;
|
|
75
|
+
private buildMessagePollingIdlePrompt;
|
|
75
76
|
/**
|
|
76
77
|
* 执行空闲命令(支持 [enter], [wait:n] 等 token)
|
|
77
78
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ClaudeSdkAdapter.d.ts","sourceRoot":"","sources":["../../src/adapter/ClaudeSdkAdapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAKtC,OAAO,KAAK,EACV,mBAAmB,EACnB,oBAAoB,EAGpB,mBAAmB,EACnB,aAAa,EACd,MAAM,YAAY,CAAC;AAwHpB;;GAEG;AACH,qBAAa,gBAAiB,SAAQ,YAAa,YAAW,mBAAmB;IAC/E,QAAQ,CAAC,UAAU,iBAAiB;IACpC,QAAQ,CAAC,WAAW,iBAAiB;IAErC,OAAO,CAAC,QAAQ,CAA0C;IAC1D,OAAO,CAAC,UAAU,CAAoC;IACtD,OAAO,CAAC,YAAY,CAAuD;IAC3E,OAAO,CAAC,gBAAgB,CAA2C;IACnE,OAAO,CAAC,SAAS,CAAiB;IAGlC,OAAO,CAAC,kBAAkB,CAGZ;IAGd,OAAO,CAAC,gBAAgB,CAGV;IAGd,OAAO,CAAC,gBAAgB,CAAkC;IAG1D,OAAO,CAAC,eAAe,CAA0D;IAGjF,OAAO,CAAC,gBAAgB,CAAkC;IAIpD,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC;IAyF5E,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAwCpE;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAmDrB,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAYnE,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAqBrF,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAOlD,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA+BxD,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,mBAAmB,EAAE;IAIzD,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAItC,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAI3D,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAI9D,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAIpD,OAAO,IAAI,IAAI;IAoBf,OAAO,CAAC,YAAY,CAAiF;IACrG,OAAO,CAAC,UAAU,CAA0C;IAC5D,OAAO,CAAC,cAAc,CAAkC;IAExD;;OAEG;IACH,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE;QAAE,gBAAgB,EAAE,MAAM,CAAC;QAAC,eAAe,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IASzG;;OAEG;IACH,OAAO,CAAC,kBAAkB;IAuB1B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAQzB;;OAEG;IACH,OAAO,CAAC,cAAc;IAuCtB;;OAEG;IACH,OAAO,CAAC,cAAc;IAqBtB,OAAO,CAAC,wBAAwB;IAShC,OAAO,CAAC,2BAA2B;
|
|
1
|
+
{"version":3,"file":"ClaudeSdkAdapter.d.ts","sourceRoot":"","sources":["../../src/adapter/ClaudeSdkAdapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -413,9 +413,9 @@ export class ClaudeSdkAdapter extends EventEmitter {
|
|
|
413
413
|
if (commands.idleInputCommand) {
|
|
414
414
|
// 解析空闲命令,提取实际要执行的指令
|
|
415
415
|
const command = commands.idleInputCommand;
|
|
416
|
-
// 如果空闲命令包含 poll_message
|
|
416
|
+
// 如果空闲命令包含 poll_message/get_message,引导 AI 进入阻塞式消息轮询。
|
|
417
417
|
if (this.isMessagePollingIdleCommand(command)) {
|
|
418
|
-
this.sendIdlePrompt(sessionId,
|
|
418
|
+
this.sendIdlePrompt(sessionId, this.buildMessagePollingIdlePrompt());
|
|
419
419
|
}
|
|
420
420
|
else {
|
|
421
421
|
// 其他命令,直接作为消息发送给 AI
|
|
@@ -457,7 +457,11 @@ export class ClaudeSdkAdapter extends EventEmitter {
|
|
|
457
457
|
if (!normalized) {
|
|
458
458
|
return false;
|
|
459
459
|
}
|
|
460
|
-
|
|
460
|
+
const lower = normalized.toLowerCase();
|
|
461
|
+
return lower.includes('poll_message') || lower.includes('get_message') || normalized.includes('取消息');
|
|
462
|
+
}
|
|
463
|
+
buildMessagePollingIdlePrompt() {
|
|
464
|
+
return '请调用 poll_message 工具阻塞等待新消息;收到消息后再处理消息内容。';
|
|
461
465
|
}
|
|
462
466
|
/**
|
|
463
467
|
* 执行空闲命令(支持 [enter], [wait:n] 等 token)
|
|
@@ -34,7 +34,7 @@ describe('ClaudeSdkAdapter', () => {
|
|
|
34
34
|
expect(sentPrompts).toHaveLength(0);
|
|
35
35
|
expect(sendIdlePrompt).not.toHaveBeenCalled();
|
|
36
36
|
});
|
|
37
|
-
it('
|
|
37
|
+
it('starts a blocking poll turn for poll_message-style idle commands', async () => {
|
|
38
38
|
vi.useFakeTimers();
|
|
39
39
|
const adapter = new ClaudeSdkAdapter();
|
|
40
40
|
const sentPrompts = [];
|
|
@@ -61,7 +61,7 @@ describe('ClaudeSdkAdapter', () => {
|
|
|
61
61
|
await vi.advanceTimersByTimeAsync(1000);
|
|
62
62
|
expect(sentPrompts).toHaveLength(0);
|
|
63
63
|
await vi.advanceTimersByTimeAsync(600);
|
|
64
|
-
expect(sentPrompts).toEqual(['
|
|
64
|
+
expect(sentPrompts).toEqual(['请调用 poll_message 工具阻塞等待新消息;收到消息后再处理消息内容。']);
|
|
65
65
|
});
|
|
66
66
|
it('still auto-wakes Claude for regular idle commands', async () => {
|
|
67
67
|
vi.useFakeTimers();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CodexSdkAdapter.d.ts","sourceRoot":"","sources":["../../src/adapter/CodexSdkAdapter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAiB3C,OAAO,KAAK,EAEV,oBAAoB,EACpB,mBAAmB,EACnB,mBAAmB,EAEnB,aAAa,EAEd,MAAM,YAAY,CAAC;AAgRpB,qBAAa,eAAgB,SAAQ,YAAa,YAAW,mBAAmB;IAC9E,QAAQ,CAAC,UAAU,WAAW;IAC9B,QAAQ,CAAC,WAAW,WAAW;IAE/B,OAAO,CAAC,QAAQ,CAAwC;IAElD,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC;IAkE5E,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAqC9D,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAKrE,kBAAkB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAI7F,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE;QAAE,gBAAgB,EAAE,MAAM,CAAC;QAAC,eAAe,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAanG,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKlD,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBlD,aAAa,CACjB,SAAS,EAAE,MAAM,EACjB,iBAAiB,EAAE,MAAM,EACzB,MAAM,EAAE,oBAAoB,GAC3B,OAAO,CAAC,IAAI,CAAC;IA2BhB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,mBAAmB,EAAE;IAIzD,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAItC,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAK3D,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAI9D,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAIrD,OAAO,IAAI,IAAI;IAOf,OAAO,CAAC,iBAAiB;IA8BzB,OAAO,CAAC,wBAAwB;IAYhC,OAAO,CAAC,kBAAkB;YAqCZ,OAAO;IAiCrB,OAAO,CAAC,iBAAiB;IAgCzB,OAAO,CAAC,gBAAgB;IA+ExB,OAAO,CAAC,aAAa;IAgBrB,OAAO,CAAC,kBAAkB;IAe1B,OAAO,CAAC,kBAAkB;IAuD1B,OAAO,CAAC,YAAY;IA2BpB,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,kBAAkB;
|
|
1
|
+
{"version":3,"file":"CodexSdkAdapter.d.ts","sourceRoot":"","sources":["../../src/adapter/CodexSdkAdapter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAiB3C,OAAO,KAAK,EAEV,oBAAoB,EACpB,mBAAmB,EACnB,mBAAmB,EAEnB,aAAa,EAEd,MAAM,YAAY,CAAC;AAgRpB,qBAAa,eAAgB,SAAQ,YAAa,YAAW,mBAAmB;IAC9E,QAAQ,CAAC,UAAU,WAAW;IAC9B,QAAQ,CAAC,WAAW,WAAW;IAE/B,OAAO,CAAC,QAAQ,CAAwC;IAElD,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC;IAkE5E,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAqC9D,gBAAgB,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAKrE,kBAAkB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAI7F,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE;QAAE,gBAAgB,EAAE,MAAM,CAAC;QAAC,eAAe,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAanG,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAKlD,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAmBlD,aAAa,CACjB,SAAS,EAAE,MAAM,EACjB,iBAAiB,EAAE,MAAM,EACzB,MAAM,EAAE,oBAAoB,GAC3B,OAAO,CAAC,IAAI,CAAC;IA2BhB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,mBAAmB,EAAE;IAIzD,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAItC,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAK3D,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAI9D,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAIrD,OAAO,IAAI,IAAI;IAOf,OAAO,CAAC,iBAAiB;IA8BzB,OAAO,CAAC,wBAAwB;IAYhC,OAAO,CAAC,kBAAkB;YAqCZ,OAAO;IAiCrB,OAAO,CAAC,iBAAiB;IAgCzB,OAAO,CAAC,gBAAgB;IA+ExB,OAAO,CAAC,aAAa;IAgBrB,OAAO,CAAC,kBAAkB;IAe1B,OAAO,CAAC,kBAAkB;IAuD1B,OAAO,CAAC,YAAY;IA2BpB,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,kBAAkB;IAa1B,OAAO,CAAC,iBAAiB;IAQzB,OAAO,CAAC,cAAc;YAcR,cAAc;IAuB5B,OAAO,CAAC,YAAY;IAQpB,OAAO,CAAC,2BAA2B;CAOpC"}
|
|
@@ -687,8 +687,6 @@ export class CodexSdkAdapter extends EventEmitter {
|
|
|
687
687
|
const session = this.sessions.get(sessionId);
|
|
688
688
|
if (!session?.idleCommands?.idleInputCommand)
|
|
689
689
|
return;
|
|
690
|
-
if (this.isMessagePollingIdleCommand(session.idleCommands.idleInputCommand))
|
|
691
|
-
return;
|
|
692
690
|
session.lastActivityAt = Date.now();
|
|
693
691
|
const timer = setInterval(() => {
|
|
694
692
|
this.checkIdleState(sessionId);
|
|
@@ -739,12 +737,17 @@ export class CodexSdkAdapter extends EventEmitter {
|
|
|
739
737
|
}
|
|
740
738
|
}
|
|
741
739
|
toIdlePrompt(command) {
|
|
742
|
-
|
|
740
|
+
const trimmed = command.trim();
|
|
741
|
+
if (this.isMessagePollingIdleCommand(trimmed)) {
|
|
742
|
+
return '请调用 poll_message 工具阻塞等待新消息;收到消息后再处理消息内容。';
|
|
743
|
+
}
|
|
744
|
+
return trimmed;
|
|
743
745
|
}
|
|
744
746
|
isMessagePollingIdleCommand(command) {
|
|
745
747
|
const normalized = command.trim();
|
|
746
748
|
if (!normalized)
|
|
747
749
|
return false;
|
|
748
|
-
|
|
750
|
+
const lower = normalized.toLowerCase();
|
|
751
|
+
return lower.includes('poll_message') || lower.includes('get_message') || normalized.includes('取消息');
|
|
749
752
|
}
|
|
750
753
|
}
|
|
@@ -177,7 +177,7 @@ describe('CodexSdkAdapter', () => {
|
|
|
177
177
|
expect(runMessages).toContain('continue');
|
|
178
178
|
expect(adapter.getConversation('session-1').some((message) => message.content === 'continue')).toBe(false);
|
|
179
179
|
});
|
|
180
|
-
it('
|
|
180
|
+
it('starts a blocking poll turn for poll_message-style idle commands', async () => {
|
|
181
181
|
vi.useFakeTimers();
|
|
182
182
|
const adapter = new CodexSdkAdapter();
|
|
183
183
|
await adapter.startSession('session-1', {
|
|
@@ -202,8 +202,10 @@ describe('CodexSdkAdapter', () => {
|
|
|
202
202
|
idleInputCommand: 'system: 醒来了吗?使用get_profile获取自己的信息,继续未完成的任务或使用poll_message阻塞获取消息',
|
|
203
203
|
nonInputCommand: '',
|
|
204
204
|
});
|
|
205
|
-
await vi.advanceTimersByTimeAsync(
|
|
205
|
+
await vi.advanceTimersByTimeAsync(1000);
|
|
206
206
|
expect(runMessages).toHaveLength(0);
|
|
207
|
+
await vi.advanceTimersByTimeAsync(600);
|
|
208
|
+
expect(runMessages).toEqual(['请调用 poll_message 工具阻塞等待新消息;收到消息后再处理消息内容。']);
|
|
207
209
|
const userMessages = adapter.getConversation('session-1').filter((message) => message.role === 'user');
|
|
208
210
|
expect(userMessages).toHaveLength(0);
|
|
209
211
|
});
|
|
@@ -41,5 +41,7 @@ export declare class OpencodeSdkAdapter extends EventEmitter implements BaseProv
|
|
|
41
41
|
private startIdleDetection;
|
|
42
42
|
private stopIdleDetection;
|
|
43
43
|
private checkIdleState;
|
|
44
|
+
private toIdlePrompt;
|
|
45
|
+
private isMessagePollingIdleCommand;
|
|
44
46
|
}
|
|
45
47
|
//# sourceMappingURL=OpencodeSdkAdapter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"OpencodeSdkAdapter.d.ts","sourceRoot":"","sources":["../../src/adapter/OpencodeSdkAdapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAa3C,OAAO,KAAK,EACV,mBAAmB,EACnB,oBAAoB,EAGpB,mBAAmB,EACnB,aAAa,EACd,MAAM,YAAY,CAAC;AA4FpB,qBAAa,kBAAmB,SAAQ,YAAa,YAAW,mBAAmB;IACjF,QAAQ,CAAC,UAAU,cAAc;IACjC,QAAQ,CAAC,WAAW,cAAc;IAElC,OAAO,CAAC,QAAQ,CAA2C;IAErD,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC;IA+H5E,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAwC9D,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAqBnE,kBAAkB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAI7F,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE;QAAE,gBAAgB,EAAE,MAAM,CAAC;QAAC,eAAe,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAOnG,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAclD,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA4BxD,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,mBAAmB,EAAE;IAIzD,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAItC,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAI3D,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAI9D,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAOpD,OAAO,IAAI,IAAI;YAaD,aAAa;IAmB3B,OAAO,CAAC,YAAY;YAYN,UAAU;IAuBxB,OAAO,CAAC,mBAAmB;IA6H3B,OAAO,CAAC,gBAAgB;IA6GxB,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,kBAAkB;IAW1B,OAAO,CAAC,iBAAiB;IAQzB,OAAO,CAAC,cAAc;
|
|
1
|
+
{"version":3,"file":"OpencodeSdkAdapter.d.ts","sourceRoot":"","sources":["../../src/adapter/OpencodeSdkAdapter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAa3C,OAAO,KAAK,EACV,mBAAmB,EACnB,oBAAoB,EAGpB,mBAAmB,EACnB,aAAa,EACd,MAAM,YAAY,CAAC;AA4FpB,qBAAa,kBAAmB,SAAQ,YAAa,YAAW,mBAAmB;IACjF,QAAQ,CAAC,UAAU,cAAc;IACjC,QAAQ,CAAC,WAAW,cAAc;IAElC,OAAO,CAAC,QAAQ,CAA2C;IAErD,YAAY,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,oBAAoB,GAAG,OAAO,CAAC,IAAI,CAAC;IA+H5E,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAwC9D,gBAAgB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC;IAqBnE,kBAAkB,CAAC,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAI7F,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE;QAAE,gBAAgB,EAAE,MAAM,CAAC;QAAC,eAAe,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI;IAOnG,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAclD,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA4BxD,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,mBAAmB,EAAE;IAIzD,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAItC,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAI3D,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAI9D,aAAa,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAOpD,OAAO,IAAI,IAAI;YAaD,aAAa;IAmB3B,OAAO,CAAC,YAAY;YAYN,UAAU;IAuBxB,OAAO,CAAC,mBAAmB;IA6H3B,OAAO,CAAC,gBAAgB;IA6GxB,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,kBAAkB;IAW1B,OAAO,CAAC,iBAAiB;IAQzB,OAAO,CAAC,cAAc;IAStB,OAAO,CAAC,YAAY;IAQpB,OAAO,CAAC,2BAA2B;CAOpC"}
|
|
@@ -616,7 +616,21 @@ export class OpencodeSdkAdapter extends EventEmitter {
|
|
|
616
616
|
return;
|
|
617
617
|
if (!session.idleCommands?.idleInputCommand)
|
|
618
618
|
return;
|
|
619
|
-
void this.sendMessage(sessionId, session.idleCommands.idleInputCommand);
|
|
619
|
+
void this.sendMessage(sessionId, this.toIdlePrompt(session.idleCommands.idleInputCommand));
|
|
620
620
|
this.stopIdleDetection(sessionId);
|
|
621
621
|
}
|
|
622
|
+
toIdlePrompt(command) {
|
|
623
|
+
const trimmed = command.trim();
|
|
624
|
+
if (this.isMessagePollingIdleCommand(trimmed)) {
|
|
625
|
+
return '请调用 poll_message 工具阻塞等待新消息;收到消息后再处理消息内容。';
|
|
626
|
+
}
|
|
627
|
+
return trimmed;
|
|
628
|
+
}
|
|
629
|
+
isMessagePollingIdleCommand(command) {
|
|
630
|
+
const normalized = command.trim();
|
|
631
|
+
if (!normalized)
|
|
632
|
+
return false;
|
|
633
|
+
const lower = normalized.toLowerCase();
|
|
634
|
+
return lower.includes('poll_message') || lower.includes('get_message') || normalized.includes('取消息');
|
|
635
|
+
}
|
|
622
636
|
}
|
|
@@ -11,4 +11,9 @@ describe('OpencodeSdkAdapter', () => {
|
|
|
11
11
|
expect(adapter.hasSession('missing-session')).toBe(false);
|
|
12
12
|
expect(adapter.getSessionStatus('missing-session')).toBeUndefined();
|
|
13
13
|
});
|
|
14
|
+
it('normalizes poll_message-style idle commands into a blocking poll prompt', () => {
|
|
15
|
+
const adapter = new OpencodeSdkAdapter();
|
|
16
|
+
const prompt = Reflect.get(adapter, 'toIdlePrompt').call(adapter, 'system: 醒来了吗?使用get_profile获取自己的信息,继续未完成的任务或使用poll_message阻塞获取消息');
|
|
17
|
+
expect(prompt).toBe('请调用 poll_message 工具阻塞等待新消息;收到消息后再处理消息内容。');
|
|
18
|
+
});
|
|
14
19
|
});
|
|
@@ -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;
|
|
1
|
+
{"version":3,"file":"runtime-binding.d.ts","sourceRoot":"","sources":["../../src/routes/runtime-binding.ts"],"names":[],"mappings":"AAmBA,eAAO,MAAM,oBAAoB,4CAAW,CAAC;AAgO7C,wBAAgB,6BAA6B,IAAI,IAAI,CAapD"}
|
|
@@ -2,7 +2,7 @@ import { Router } from "express";
|
|
|
2
2
|
import { clearRuntimeBinding, getRuntimeAccessToken, getRuntimeBindingPublicState, getRuntimePairingCode, hasRuntimeBinding, saveRuntimeBinding, validateRuntimeBindingToken, validateRuntimePairingCode, } from "../services/runtime-binding.js";
|
|
3
3
|
import { validateToken } from "../middleware/auth.js";
|
|
4
4
|
import { runtimeToken } from "../config.js";
|
|
5
|
-
import { requestRuntimeAccessTokenRefresh } from "../services/auto-register.js";
|
|
5
|
+
import { requestRuntimeAccessTokenRefresh, requestRuntimeAccessTokenRefreshForServer } from "../services/auto-register.js";
|
|
6
6
|
import { claimMcpLaunchBinding, getMcpLaunchQueueSize } from "../services/mcp-launch-binding-queue.js";
|
|
7
7
|
import { createLogger } from "../utils/logger.js";
|
|
8
8
|
const log = createLogger("runtime-binding-route");
|
|
@@ -84,7 +84,10 @@ runtimeBindingRouter.post("/binding/request-token", async (req, res) => {
|
|
|
84
84
|
});
|
|
85
85
|
return;
|
|
86
86
|
}
|
|
87
|
-
const
|
|
87
|
+
const requestedServerUrl = serverUrl || schedulerBaseUrl;
|
|
88
|
+
const result = requestedServerUrl
|
|
89
|
+
? await requestRuntimeAccessTokenRefreshForServer(String(requestedServerUrl))
|
|
90
|
+
: await requestRuntimeAccessTokenRefresh();
|
|
88
91
|
if (!result.success || !result.runtimeAccessToken) {
|
|
89
92
|
res.status(400).json({
|
|
90
93
|
ok: false,
|
|
@@ -103,15 +106,7 @@ runtimeBindingRouter.post("/binding/claim-agent", (req, res) => {
|
|
|
103
106
|
res.status(403).json({ ok: false, error: "loopback request required" });
|
|
104
107
|
return;
|
|
105
108
|
}
|
|
106
|
-
const {
|
|
107
|
-
if (!agentId || !String(agentId).trim()) {
|
|
108
|
-
res.status(400).json({ ok: false, error: "agentId is required" });
|
|
109
|
-
return;
|
|
110
|
-
}
|
|
111
|
-
if (!bindingId || !String(bindingId).trim()) {
|
|
112
|
-
res.status(400).json({ ok: false, error: "bindingId is required" });
|
|
113
|
-
return;
|
|
114
|
-
}
|
|
109
|
+
const { workspacePath, serverUrl } = req.body || {};
|
|
115
110
|
if (!workspacePath || !String(workspacePath).trim()) {
|
|
116
111
|
res.status(400).json({ ok: false, error: "workspacePath is required" });
|
|
117
112
|
return;
|
|
@@ -120,11 +115,11 @@ runtimeBindingRouter.post("/binding/claim-agent", (req, res) => {
|
|
|
120
115
|
res.status(400).json({ ok: false, error: "serverUrl is required" });
|
|
121
116
|
return;
|
|
122
117
|
}
|
|
123
|
-
const claimed = claimMcpLaunchBinding({
|
|
118
|
+
const claimed = claimMcpLaunchBinding({ workspacePath, serverUrl });
|
|
124
119
|
if (!claimed) {
|
|
125
120
|
res.status(404).json({
|
|
126
121
|
ok: false,
|
|
127
|
-
error: "launch binding not found",
|
|
122
|
+
error: "launch binding not found for workspacePath and serverUrl",
|
|
128
123
|
queueSize: getMcpLaunchQueueSize(workspacePath),
|
|
129
124
|
});
|
|
130
125
|
return;
|
package/dist/routes/terminal.js
CHANGED
|
@@ -80,7 +80,7 @@ terminalRouter.post('/start', validateToken, async (req, res) => {
|
|
|
80
80
|
});
|
|
81
81
|
// SDK 模式
|
|
82
82
|
if (mode === 'sdk') {
|
|
83
|
-
await startSdkSession(req, res
|
|
83
|
+
await startSdkSession(req, res);
|
|
84
84
|
return;
|
|
85
85
|
}
|
|
86
86
|
// PTY 模式(原有逻辑)
|
|
@@ -110,7 +110,6 @@ terminalRouter.post('/start', validateToken, async (req, res) => {
|
|
|
110
110
|
env: {
|
|
111
111
|
...process.env,
|
|
112
112
|
AWS_AGENT_ID: String(agentId),
|
|
113
|
-
AWS_MCP_LAUNCH_BINDING_ID: queuedBinding?.id || '',
|
|
114
113
|
AWS_MCP_CLAIM_LAUNCH_BINDING: 'true',
|
|
115
114
|
},
|
|
116
115
|
});
|
|
@@ -176,14 +175,13 @@ terminalRouter.post('/start', validateToken, async (req, res) => {
|
|
|
176
175
|
workspacePath,
|
|
177
176
|
command: actualCommand,
|
|
178
177
|
mode: 'pty',
|
|
179
|
-
mcpLaunchBindingId: queuedBinding?.id,
|
|
180
178
|
});
|
|
181
179
|
});
|
|
182
180
|
/**
|
|
183
181
|
* 启动 SDK 会话
|
|
184
182
|
* 支持 MCP 配置和空闲命令
|
|
185
183
|
*/
|
|
186
|
-
async function startSdkSession(req, res
|
|
184
|
+
async function startSdkSession(req, res) {
|
|
187
185
|
const { agentId, workspacePath, command, autoAccept = true, initialPrompt,
|
|
188
186
|
// MCP 配置 - 加载 aws-client-agent-mcp
|
|
189
187
|
mcpConfigPath, extraMcpServers,
|
|
@@ -213,7 +211,6 @@ async function startSdkSession(req, res, mcpLaunchBindingId) {
|
|
|
213
211
|
envOverrides: {
|
|
214
212
|
AWS_AGENT_ID: String(agentId),
|
|
215
213
|
AWS_WORKSPACE_PATH: String(workspacePath),
|
|
216
|
-
AWS_MCP_LAUNCH_BINDING_ID: mcpLaunchBindingId || '',
|
|
217
214
|
AWS_MCP_CLAIM_LAUNCH_BINDING: 'true',
|
|
218
215
|
},
|
|
219
216
|
};
|
|
@@ -56,15 +56,14 @@ describe('terminal configuration', () => {
|
|
|
56
56
|
expect(getShellConfig('linux').shell).toBe('bash');
|
|
57
57
|
});
|
|
58
58
|
it('builds correct terminal environment', () => {
|
|
59
|
-
const buildTerminalEnv = (agentId,
|
|
59
|
+
const buildTerminalEnv = (agentId, baseEnv) => ({
|
|
60
60
|
...baseEnv,
|
|
61
61
|
AWS_AGENT_ID: agentId,
|
|
62
|
-
AWS_MCP_LAUNCH_BINDING_ID: bindingId,
|
|
63
62
|
AWS_MCP_CLAIM_LAUNCH_BINDING: 'true',
|
|
64
63
|
});
|
|
65
|
-
const env = buildTerminalEnv('agent-123',
|
|
64
|
+
const env = buildTerminalEnv('agent-123', { PATH: '/usr/bin' });
|
|
66
65
|
expect(env.AWS_AGENT_ID).toBe('agent-123');
|
|
67
|
-
expect(env.AWS_MCP_LAUNCH_BINDING_ID).
|
|
66
|
+
expect(env.AWS_MCP_LAUNCH_BINDING_ID).toBeUndefined();
|
|
68
67
|
expect(env.AWS_MCP_CLAIM_LAUNCH_BINDING).toBe('true');
|
|
69
68
|
});
|
|
70
69
|
});
|
|
@@ -75,6 +75,12 @@ export declare function requestRuntimeAccessTokenRefresh(): Promise<{
|
|
|
75
75
|
updated?: boolean;
|
|
76
76
|
error?: string;
|
|
77
77
|
}>;
|
|
78
|
+
export declare function requestRuntimeAccessTokenRefreshForServer(serverBaseUrl: string): Promise<{
|
|
79
|
+
success: boolean;
|
|
80
|
+
runtimeAccessToken?: string;
|
|
81
|
+
updated?: boolean;
|
|
82
|
+
error?: string;
|
|
83
|
+
}>;
|
|
78
84
|
export declare function unregister(): Promise<boolean>;
|
|
79
85
|
/**
|
|
80
86
|
* 获取注册状态
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auto-register.d.ts","sourceRoot":"","sources":["../../src/services/auto-register.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;
|
|
1
|
+
{"version":3,"file":"auto-register.d.ts","sourceRoot":"","sources":["../../src/services/auto-register.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAiDH;;GAEG;AACH,UAAU,kBAAkB;IAC1B,eAAe;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,oBAAoB;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oCAAoC;IACpC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mCAAmC;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,0BAA0B;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,oBAAoB;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW;IACX,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW;IACX,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa;IACb,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,yCAAyC;IACzC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4BAA4B;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mCAAmC;IACnC,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,aAAa;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iBAAiB;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAwBD,wBAAgB,2BAA2B,IAAI,MAAM,EAAE,CAEtD;AAiED;;GAEG;AACH,wBAAgB,6BAA6B,IAAI,MAAM,CAGtD;AAyJD;;;;;;GAMG;AACH,wBAAgB,UAAU,IAAI,kBAAkB,CA2C/C;AAED,wBAAgB,WAAW,IAAI,kBAAkB,EAAE,CA0ClD;AA4OD;;;;;;;;;;GAUG;AACH,wBAAsB,YAAY,CAChC,YAAY,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,GACzC,OAAO,CAAC,OAAO,CAAC,CAalB;AAyHD;;GAEG;AACH,wBAAsB,gCAAgC,IAAI,OAAO,CAAC;IAChE,OAAO,EAAE,OAAO,CAAC;IACjB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC,CAqED;AAED,wBAAsB,yCAAyC,CAC7D,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC;IACT,OAAO,EAAE,OAAO,CAAC;IACjB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC,CA2ED;AAED,wBAAsB,UAAU,IAAI,OAAO,CAAC,OAAO,CAAC,CAuBnD;AAED;;GAEG;AACH,wBAAgB,oBAAoB;gBA14BtB,OAAO;iBACN,MAAM;mBACJ,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;kBACvB,IAAI;YACV,MAAM;EAw4Bf;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,OAAO,CAEtC;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,MAAM,GAAG,SAAS,CAElD;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,oBAAoB,IAAI,OAAO,CAAC;IACpD,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC,CA2ED"}
|
|
@@ -13,7 +13,7 @@ import path from "node:path";
|
|
|
13
13
|
import fs from "node:fs";
|
|
14
14
|
import { logger } from "../utils/logger.js";
|
|
15
15
|
import { schedulerBaseUrl, runtimeToken } from "../config.js";
|
|
16
|
-
import { getRuntimeAccessToken, getRuntimeBindingPublicState, loadRuntimeBinding, saveRuntimeBinding, } from "./runtime-binding.js";
|
|
16
|
+
import { getRuntimeAccessToken, getRuntimeBindingPublicState, loadRuntimeBinding, normalizeSchedulerBaseUrl, saveRuntimeBinding, saveScopedRuntimeAccessToken, } from "./runtime-binding.js";
|
|
17
17
|
// 默认配置
|
|
18
18
|
const DEFAULT_CONFIG = {
|
|
19
19
|
enabled: false,
|
|
@@ -37,6 +37,9 @@ function normalizeOptionalString(value) {
|
|
|
37
37
|
const normalized = String(value).trim();
|
|
38
38
|
return normalized || undefined;
|
|
39
39
|
}
|
|
40
|
+
function normalizeSchedulerHttpBaseUrl(value) {
|
|
41
|
+
return normalizeSchedulerBaseUrl(value);
|
|
42
|
+
}
|
|
40
43
|
function normalizeOptionalBoolean(value) {
|
|
41
44
|
if (typeof value === "boolean") {
|
|
42
45
|
return value;
|
|
@@ -649,6 +652,65 @@ export async function requestRuntimeAccessTokenRefresh() {
|
|
|
649
652
|
return { success: false, error: message };
|
|
650
653
|
}
|
|
651
654
|
}
|
|
655
|
+
export async function requestRuntimeAccessTokenRefreshForServer(serverBaseUrl) {
|
|
656
|
+
const targetServerUrl = normalizeSchedulerHttpBaseUrl(serverBaseUrl);
|
|
657
|
+
if (!targetServerUrl) {
|
|
658
|
+
return { success: false, error: "serverUrl is required for runtime token refresh" };
|
|
659
|
+
}
|
|
660
|
+
const config = loadConfigs().find((item) => normalizeSchedulerHttpBaseUrl(item.serverUrl) === targetServerUrl) || loadPrimaryLifecycleConfig();
|
|
661
|
+
if (!config.userKey) {
|
|
662
|
+
return {
|
|
663
|
+
success: false,
|
|
664
|
+
error: "userKey is required for runtime token refresh",
|
|
665
|
+
};
|
|
666
|
+
}
|
|
667
|
+
const state = getRuntimeBindingPublicState();
|
|
668
|
+
const localIp = getLocalIpAddress(targetServerUrl);
|
|
669
|
+
const runtimeBridgePort = process.env.AWS_RUNTIME_BRIDGE_PORT || 18081;
|
|
670
|
+
const runtimeBridgeBaseUrl = `http://${config.registerIp || config.virtualIp || localIp}:${runtimeBridgePort}`;
|
|
671
|
+
try {
|
|
672
|
+
const response = await axios.post(`${targetServerUrl}/api/instances/runtime-tokens/refresh`, {
|
|
673
|
+
tenantId: config.tenantId,
|
|
674
|
+
userKey: config.userKey,
|
|
675
|
+
instanceId: state.instanceId,
|
|
676
|
+
instanceName: config.instanceName,
|
|
677
|
+
runtimeBridgeBaseUrl,
|
|
678
|
+
}, {
|
|
679
|
+
headers: {
|
|
680
|
+
"Content-Type": "application/json",
|
|
681
|
+
"X-Runtime-Token": runtimeToken,
|
|
682
|
+
},
|
|
683
|
+
timeout: 10000,
|
|
684
|
+
});
|
|
685
|
+
if (!response.data.success || !response.data.runtimeAccessToken) {
|
|
686
|
+
return {
|
|
687
|
+
success: false,
|
|
688
|
+
error: response.data.message ||
|
|
689
|
+
"scheduler did not return runtimeAccessToken",
|
|
690
|
+
};
|
|
691
|
+
}
|
|
692
|
+
const userId = response.data.userId || config.userKey;
|
|
693
|
+
const previousToken = getRuntimeAccessToken(userId, targetServerUrl);
|
|
694
|
+
const updated = previousToken !== response.data.runtimeAccessToken;
|
|
695
|
+
saveScopedRuntimeAccessToken({
|
|
696
|
+
userId,
|
|
697
|
+
serverBaseUrl: targetServerUrl,
|
|
698
|
+
accessToken: response.data.runtimeAccessToken,
|
|
699
|
+
});
|
|
700
|
+
return {
|
|
701
|
+
success: true,
|
|
702
|
+
runtimeAccessToken: response.data.runtimeAccessToken,
|
|
703
|
+
updated,
|
|
704
|
+
};
|
|
705
|
+
}
|
|
706
|
+
catch (error) {
|
|
707
|
+
const err = error;
|
|
708
|
+
const message = err.response?.data
|
|
709
|
+
? JSON.stringify(err.response.data)
|
|
710
|
+
: err.message;
|
|
711
|
+
return { success: false, error: message };
|
|
712
|
+
}
|
|
713
|
+
}
|
|
652
714
|
export async function unregister() {
|
|
653
715
|
if (!registrationState.registered || !registrationState.instanceId) {
|
|
654
716
|
logger.info("[AutoRegister] 实例未注册,无需注销");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"aws-client-agent-mcp.d.ts","sourceRoot":"","sources":["../../src/services/aws-client-agent-mcp.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"aws-client-agent-mcp.d.ts","sourceRoot":"","sources":["../../src/services/aws-client-agent-mcp.ts"],"names":[],"mappings":"AAyBA,eAAO,MAAM,mBAAmB,YAAY,CAAC;AAsB7C,MAAM,WAAW,uBAAuB;IACtC,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;CAChB;AAED,MAAM,WAAW,kBAAmB,SAAQ,iBAAiB;IAC3D,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC7B;AAED,MAAM,WAAW,sCAAsC;IACrD,MAAM,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,OAAO,CAAC;IACvC,OAAO,CAAC,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;CAC/B;AAED,MAAM,WAAW,sCAAsC;IACrD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,GAAG,CAAC,EAAE,MAAM,MAAM,CAAC;CACpB;AAaD,MAAM,WAAW,kBAAmB,SAAQ,iBAAiB;IAC3D,MAAM,EAAE,UAAU,GAAG,SAAS,GAAG,QAAQ,CAAC;CAC3C;AAuBD,wBAAgB,sBAAsB,IAAI,MAAM,CAE/C;AAgLD,wBAAgB,+BAA+B,CAC7C,OAAO,GAAE,sCAA2C,GACnD,MAAM,GAAG,IAAI,CAoDf;AA2ED,wBAAgB,+BAA+B,CAC7C,OAAO,GAAE,sCAA2C,GACnD,kBAAkB,CAEpB;AAED,wBAAgB,gCAAgC,CAC9C,OAAO,GAAE,sCAA2C,GACnD,kBAAkB,CAsBpB;AAED,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,uBAAuB,GAC7B,kBAAkB,CA0BpB;AAED,wBAAgB,+BAA+B,IAAI,IAAI,CAgBtD"}
|
|
@@ -4,10 +4,9 @@ import path from "node:path";
|
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import { getRuntimeHomeDir, port, schedulerBaseUrl } from "../config.js";
|
|
6
6
|
import { logger } from "../utils/logger.js";
|
|
7
|
-
import { getRuntimeAccessToken, loadRuntimeBinding, } from "./runtime-binding.js";
|
|
7
|
+
import { getRuntimeAccessToken, loadRuntimeBinding, normalizeSchedulerBaseUrl, } from "./runtime-binding.js";
|
|
8
8
|
export const AWS_MCP_SERVER_NAME = "aws-mcp";
|
|
9
9
|
const AWS_MCP_ALLOWED_ENV_KEYS = [
|
|
10
|
-
"AWS_INTERNAL_API_KEY",
|
|
11
10
|
"AWS_PROJECT_NAME",
|
|
12
11
|
"AWS_PROMPT",
|
|
13
12
|
"AWS_ROLE_NAME",
|
|
@@ -236,7 +235,7 @@ function parseAwsClientAgentMcpArgs(raw) {
|
|
|
236
235
|
return [];
|
|
237
236
|
}
|
|
238
237
|
function toWebSocketUrl(baseUrl) {
|
|
239
|
-
const url = new URL("/ws/agent", baseUrl);
|
|
238
|
+
const url = new URL("/ws/agent", normalizeSchedulerBaseUrl(baseUrl) || baseUrl);
|
|
240
239
|
if (url.protocol === "https:") {
|
|
241
240
|
url.protocol = "wss:";
|
|
242
241
|
}
|
|
@@ -246,7 +245,7 @@ function toWebSocketUrl(baseUrl) {
|
|
|
246
245
|
return url.toString();
|
|
247
246
|
}
|
|
248
247
|
function toMcpHttpUrl(baseUrl) {
|
|
249
|
-
return new URL("/mcp/call", baseUrl).toString();
|
|
248
|
+
return new URL("/mcp/call", normalizeSchedulerBaseUrl(baseUrl) || baseUrl).toString();
|
|
250
249
|
}
|
|
251
250
|
function resolveSchedulerBaseUrlForMcp() {
|
|
252
251
|
const envSchedulerBaseUrl = String(process.env.AWS_RUNTIME_SCHEDULER_BASE_URL || "").trim();
|
|
@@ -297,6 +296,7 @@ export function buildAwsMcpServerConfig(input) {
|
|
|
297
296
|
AWS_SERVER_URL: env.AWS_SERVER_URL || toWebSocketUrl(effectiveSchedulerBaseUrl),
|
|
298
297
|
AWS_MCP_HTTP_URL: env.AWS_MCP_HTTP_URL || toMcpHttpUrl(effectiveSchedulerBaseUrl),
|
|
299
298
|
AWS_RUNTIME_BRIDGE_BASE_URL: env.AWS_RUNTIME_BRIDGE_BASE_URL || `http://127.0.0.1:${port}`,
|
|
299
|
+
AWS_MCP_CLAIM_LAUNCH_BINDING: env.AWS_MCP_CLAIM_LAUNCH_BINDING || "true",
|
|
300
300
|
...(issuedRuntimeAccessToken
|
|
301
301
|
? { AWS_RUNTIME_ACCESS_TOKEN: issuedRuntimeAccessToken }
|
|
302
302
|
: {}),
|
|
@@ -216,6 +216,20 @@ describe('aws-client-agent-mcp service', () => {
|
|
|
216
216
|
expect(config.env.AWS_RUNTIME_CALLBACK_TOKEN).toBeUndefined();
|
|
217
217
|
expect(config.env.CUSTOM_SECRET).toBeUndefined();
|
|
218
218
|
});
|
|
219
|
+
it('repairs duplicated scheduler ports when building MCP URLs', async () => {
|
|
220
|
+
process.env.AWS_CLIENT_AGENT_MCP_COMMAND = 'aws-client-agent-mcp';
|
|
221
|
+
process.env.AWS_RUNTIME_HOME_DIR = mkdtempSync(path.join(os.tmpdir(), 'aws-mcp-config-'));
|
|
222
|
+
process.env.AWS_RUNTIME_SCHEDULER_BASE_URL = 'http://127.0.0.1:8080:8080';
|
|
223
|
+
process.env.AWS_SERVER_URL = '';
|
|
224
|
+
process.env.AWS_MCP_HTTP_URL = '';
|
|
225
|
+
const mod = await import('./aws-client-agent-mcp.js');
|
|
226
|
+
const config = mod.buildAwsMcpServerConfig({
|
|
227
|
+
agentId: 'agent-1',
|
|
228
|
+
workspacePath: '/workspace/demo',
|
|
229
|
+
});
|
|
230
|
+
expect(config.env.AWS_SERVER_URL).toBe('ws://127.0.0.1:8080/ws/agent');
|
|
231
|
+
expect(config.env.AWS_MCP_HTTP_URL).toBe('http://127.0.0.1:8080/mcp/call');
|
|
232
|
+
});
|
|
219
233
|
it('ignores malformed AWS_CLIENT_AGENT_MCP_ARGS JSON', async () => {
|
|
220
234
|
process.env.AWS_CLIENT_AGENT_MCP_COMMAND = 'custom-aws-client-agent-mcp';
|
|
221
235
|
process.env.AWS_CLIENT_AGENT_MCP_ARGS = '{bad json';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-launch-binding-queue.d.ts","sourceRoot":"","sources":["../../src/services/mcp-launch-binding-queue.ts"],"names":[],"mappings":"
|
|
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;AAmDD,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,5 +1,7 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
-
import {
|
|
2
|
+
import { schedulerBaseUrl as defaultSchedulerBaseUrl } from "../config.js";
|
|
3
|
+
import { getRuntimeAccessToken, loadRuntimeBinding, normalizeSchedulerBaseUrl } from "./runtime-binding.js";
|
|
4
|
+
const LAUNCH_BINDING_TTL_MS = 5 * 60 * 1000;
|
|
3
5
|
const launchBindings = [];
|
|
4
6
|
function normalizeWorkspacePath(workspacePath) {
|
|
5
7
|
const raw = String(workspacePath || "").trim();
|
|
@@ -11,57 +13,82 @@ function normalizeWorkspacePath(workspacePath) {
|
|
|
11
13
|
function normalizeOptionalUrl(value) {
|
|
12
14
|
return String(value || "").trim();
|
|
13
15
|
}
|
|
14
|
-
function
|
|
15
|
-
const raw = String(serverUrl || "").trim();
|
|
16
|
+
function normalizeSchedulerOrigin(serverUrl) {
|
|
17
|
+
const raw = normalizeSchedulerBaseUrl(serverUrl) || String(serverUrl || "").trim();
|
|
16
18
|
if (!raw) {
|
|
17
19
|
return "";
|
|
18
20
|
}
|
|
19
21
|
try {
|
|
20
22
|
const url = new URL(raw);
|
|
21
|
-
url.protocol
|
|
23
|
+
if (url.protocol === "ws:") {
|
|
24
|
+
url.protocol = "http:";
|
|
25
|
+
}
|
|
26
|
+
else if (url.protocol === "wss:") {
|
|
27
|
+
url.protocol = "https:";
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
url.protocol = url.protocol.toLowerCase();
|
|
31
|
+
}
|
|
22
32
|
url.hostname = url.hostname.toLowerCase();
|
|
23
|
-
|
|
24
|
-
return url.toString().replace(/\/+$/, "");
|
|
33
|
+
return url.origin;
|
|
25
34
|
}
|
|
26
35
|
catch {
|
|
27
36
|
return raw.replace(/\/+$/, "").toLowerCase();
|
|
28
37
|
}
|
|
29
38
|
}
|
|
39
|
+
function pruneExpiredBindings(now = Date.now()) {
|
|
40
|
+
for (let index = launchBindings.length - 1; index >= 0; index -= 1) {
|
|
41
|
+
const enqueuedAt = Date.parse(launchBindings[index]?.enqueuedAt || "");
|
|
42
|
+
if (!Number.isFinite(enqueuedAt) || now - enqueuedAt > LAUNCH_BINDING_TTL_MS) {
|
|
43
|
+
launchBindings.splice(index, 1);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
30
47
|
function createBindingId(agentId) {
|
|
31
48
|
return `${agentId}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 8)}`;
|
|
32
49
|
}
|
|
33
50
|
export function enqueueMcpLaunchBinding(input) {
|
|
51
|
+
pruneExpiredBindings();
|
|
34
52
|
const agentId = String(input.agentId || "").trim();
|
|
35
53
|
const workspaceKey = normalizeWorkspacePath(input.workspacePath);
|
|
36
54
|
if (!agentId || !workspaceKey) {
|
|
37
55
|
return null;
|
|
38
56
|
}
|
|
57
|
+
const runtimeState = loadRuntimeBinding();
|
|
58
|
+
const schedulerUrl = normalizeSchedulerBaseUrl(input.serverUrl || input.schedulerBaseUrl || runtimeState.schedulerBaseUrl || defaultSchedulerBaseUrl) || normalizeOptionalUrl(input.serverUrl || input.schedulerBaseUrl || runtimeState.schedulerBaseUrl || defaultSchedulerBaseUrl);
|
|
59
|
+
const schedulerBindingBaseUrl = normalizeSchedulerBaseUrl(input.schedulerBaseUrl || runtimeState.schedulerBaseUrl || defaultSchedulerBaseUrl) || normalizeOptionalUrl(input.schedulerBaseUrl || runtimeState.schedulerBaseUrl || defaultSchedulerBaseUrl);
|
|
39
60
|
const binding = {
|
|
40
61
|
id: createBindingId(agentId),
|
|
41
62
|
agentId,
|
|
42
63
|
workspacePath: path.resolve(String(input.workspacePath)),
|
|
43
|
-
serverUrl:
|
|
64
|
+
serverUrl: schedulerUrl,
|
|
44
65
|
mcpHttpUrl: normalizeOptionalUrl(input.mcpHttpUrl),
|
|
45
66
|
runtimeAccessToken: normalizeOptionalUrl(input.runtimeAccessToken),
|
|
46
67
|
userId: normalizeOptionalUrl(input.userId),
|
|
47
|
-
schedulerBaseUrl:
|
|
68
|
+
schedulerBaseUrl: schedulerBindingBaseUrl,
|
|
48
69
|
enqueuedAt: new Date().toISOString(),
|
|
49
70
|
};
|
|
50
71
|
launchBindings.push(binding);
|
|
51
72
|
return binding;
|
|
52
73
|
}
|
|
53
74
|
export function claimMcpLaunchBinding(request) {
|
|
54
|
-
|
|
55
|
-
const bindingId = String(request.bindingId || "").trim();
|
|
75
|
+
pruneExpiredBindings();
|
|
56
76
|
const workspaceKey = normalizeWorkspacePath(request.workspacePath);
|
|
57
|
-
const serverKey =
|
|
58
|
-
if (!
|
|
77
|
+
const serverKey = normalizeSchedulerOrigin(request.serverUrl);
|
|
78
|
+
if (!workspaceKey) {
|
|
59
79
|
return null;
|
|
60
80
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
81
|
+
let bindingIndex = launchBindings.findIndex((binding) => normalizeWorkspacePath(binding.workspacePath) === workspaceKey &&
|
|
82
|
+
serverKey &&
|
|
83
|
+
normalizeSchedulerOrigin(binding.serverUrl || binding.schedulerBaseUrl) === serverKey);
|
|
84
|
+
if (bindingIndex < 0) {
|
|
85
|
+
const workspaceMatches = launchBindings
|
|
86
|
+
.map((binding, index) => ({ binding, index }))
|
|
87
|
+
.filter(({ binding }) => normalizeWorkspacePath(binding.workspacePath) === workspaceKey);
|
|
88
|
+
if (workspaceMatches.length === 1) {
|
|
89
|
+
bindingIndex = workspaceMatches[0]?.index ?? -1;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
65
92
|
if (bindingIndex < 0) {
|
|
66
93
|
return null;
|
|
67
94
|
}
|
|
@@ -81,6 +108,7 @@ export function claimMcpLaunchBinding(request) {
|
|
|
81
108
|
};
|
|
82
109
|
}
|
|
83
110
|
export function getMcpLaunchQueueSize(workspacePath) {
|
|
111
|
+
pruneExpiredBindings();
|
|
84
112
|
const workspaceKey = normalizeWorkspacePath(workspacePath);
|
|
85
113
|
if (!workspaceKey) {
|
|
86
114
|
return 0;
|