aws-runtime-bridge 1.8.1 → 1.8.2
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 +64 -6
- package/dist/adapter/AcodeSdkAdapter.test.js +129 -0
- package/dist/adapter/OpencodeSdkAdapter.js +1 -1
- package/dist/routes/runtime-binding.d.ts.map +1 -1
- package/dist/routes/runtime-binding.js +36 -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/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
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AcodeSdkAdapter.d.ts","sourceRoot":"","sources":["../../src/adapter/AcodeSdkAdapter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"AcodeSdkAdapter.d.ts","sourceRoot":"","sources":["../../src/adapter/AcodeSdkAdapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -11,7 +11,7 @@ import { v4 as uuidv4 } from "uuid";
|
|
|
11
11
|
import { getAcodeConfigFile, getAcodeSkillsDir, getRuntimeHomeDir, } from "../config.js";
|
|
12
12
|
import { getReleasedAcodeEntryPath } from "../services/acode-package.js";
|
|
13
13
|
import { IdlePollLoop } from "./idle-poll-loop.js";
|
|
14
|
-
import { getCanonicalMcpDetail, getToolActionInfo
|
|
14
|
+
import { getCanonicalMcpDetail, getToolActionInfo } from "./types.js";
|
|
15
15
|
const ACODE_AUTO_POLL_PROMPT = [
|
|
16
16
|
"Continue the AgentsWork message loop now.",
|
|
17
17
|
"You MUST call the exact MCP tool named aws-mcp__poll_message as your next action and wait for the next assigned message or task.",
|
|
@@ -46,6 +46,9 @@ function toUsage(value) {
|
|
|
46
46
|
const usage = value;
|
|
47
47
|
const inputTokens = toFiniteTokenCount(usage.inputTokens, usage.input_tokens, usage.promptTokens, usage.prompt_tokens);
|
|
48
48
|
const outputTokens = toFiniteTokenCount(usage.outputTokens, usage.output_tokens, usage.completionTokens, usage.completion_tokens);
|
|
49
|
+
if (inputTokens === 0 && outputTokens === 0) {
|
|
50
|
+
return undefined;
|
|
51
|
+
}
|
|
49
52
|
return {
|
|
50
53
|
inputTokens,
|
|
51
54
|
outputTokens,
|
|
@@ -60,6 +63,9 @@ function toFiniteTokenCount(...values) {
|
|
|
60
63
|
}
|
|
61
64
|
return 0;
|
|
62
65
|
}
|
|
66
|
+
function toEstimatedContextTokens(data) {
|
|
67
|
+
return toFiniteTokenCount(data.estimatedContextTokens, data.contextTokens, data.context_tokens, data.contextUsedTokens, data.context_used_tokens);
|
|
68
|
+
}
|
|
63
69
|
/**
|
|
64
70
|
* Check whether an ACode turn_complete event represents a failed turn.
|
|
65
71
|
* Main flow: only explicit failed=true prevents error status from being reset to waiting_input.
|
|
@@ -83,6 +89,30 @@ function isAcodeSemanticToolAction(actionType) {
|
|
|
83
89
|
actionType === "write_file" ||
|
|
84
90
|
actionType === "bash");
|
|
85
91
|
}
|
|
92
|
+
function hasPollingMessages(result) {
|
|
93
|
+
const parsed = parseToolResultObject(result);
|
|
94
|
+
if (!parsed) {
|
|
95
|
+
return typeof result === "string" && result.trim().length > 0;
|
|
96
|
+
}
|
|
97
|
+
return [parsed.directMessages, parsed.groupMessages, parsed.messages].some((value) => Array.isArray(value) && value.length > 0);
|
|
98
|
+
}
|
|
99
|
+
function parseToolResultObject(result) {
|
|
100
|
+
if (result && typeof result === "object" && !Array.isArray(result)) {
|
|
101
|
+
return result;
|
|
102
|
+
}
|
|
103
|
+
if (typeof result !== "string" || !result.trim()) {
|
|
104
|
+
return undefined;
|
|
105
|
+
}
|
|
106
|
+
try {
|
|
107
|
+
const parsed = JSON.parse(result);
|
|
108
|
+
return parsed && typeof parsed === "object" && !Array.isArray(parsed)
|
|
109
|
+
? parsed
|
|
110
|
+
: undefined;
|
|
111
|
+
}
|
|
112
|
+
catch {
|
|
113
|
+
return undefined;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
86
116
|
export class AcodeSdkAdapter extends EventEmitter {
|
|
87
117
|
constructor() {
|
|
88
118
|
super(...arguments);
|
|
@@ -113,7 +143,9 @@ export class AcodeSdkAdapter extends EventEmitter {
|
|
|
113
143
|
try {
|
|
114
144
|
await entry.runtime.start();
|
|
115
145
|
session.status = "waiting_input";
|
|
116
|
-
this.emit("status-change", sessionId, "waiting_input"
|
|
146
|
+
this.emit("status-change", sessionId, "waiting_input", {
|
|
147
|
+
usage: entry.adapterSession.totalUsage,
|
|
148
|
+
});
|
|
117
149
|
if (config.initialPrompt?.trim()) {
|
|
118
150
|
this.startInitialPromptTurn(sessionId, config.initialPrompt);
|
|
119
151
|
}
|
|
@@ -305,6 +337,14 @@ export class AcodeSdkAdapter extends EventEmitter {
|
|
|
305
337
|
return;
|
|
306
338
|
}
|
|
307
339
|
if (event.type === "ai_request") {
|
|
340
|
+
const estimatedTokens = toEstimatedContextTokens(event.data);
|
|
341
|
+
if (estimatedTokens > 0) {
|
|
342
|
+
entry.adapterSession.totalUsage.inputTokens = estimatedTokens;
|
|
343
|
+
entry.adapterSession.totalUsage.outputTokens = 0;
|
|
344
|
+
this.emit("status-change", event.sessionId, entry.adapterSession.status, {
|
|
345
|
+
usage: entry.adapterSession.totalUsage,
|
|
346
|
+
});
|
|
347
|
+
}
|
|
308
348
|
this.emitProviderEvent(event, "ai_request", {
|
|
309
349
|
model: typeof event.data.model === "string" ? event.data.model : undefined,
|
|
310
350
|
endpoint: typeof event.data.endpoint === "string"
|
|
@@ -431,7 +471,9 @@ export class AcodeSdkAdapter extends EventEmitter {
|
|
|
431
471
|
const server = typeof event.data.server === "string" ? event.data.server : "mcp";
|
|
432
472
|
const tool = typeof event.data.tool === "string" ? event.data.tool : "";
|
|
433
473
|
const toolName = server && tool ? `${server}__${tool}` : tool || server;
|
|
434
|
-
const toolInput = event.data.arguments &&
|
|
474
|
+
const toolInput = event.data.arguments &&
|
|
475
|
+
typeof event.data.arguments === "object" &&
|
|
476
|
+
!Array.isArray(event.data.arguments)
|
|
435
477
|
? event.data.arguments
|
|
436
478
|
: undefined;
|
|
437
479
|
const actionInfo = getToolActionInfo(toolName, toolInput);
|
|
@@ -439,7 +481,8 @@ export class AcodeSdkAdapter extends EventEmitter {
|
|
|
439
481
|
entry.autoPollObservedPollingTool = true;
|
|
440
482
|
}
|
|
441
483
|
const actionDetail = isAcodeSemanticToolAction(actionInfo.actionType)
|
|
442
|
-
? actionInfo.actionDetail ||
|
|
484
|
+
? actionInfo.actionDetail ||
|
|
485
|
+
toAcodeMcpActionDetail(undefined, server, tool)
|
|
443
486
|
: toAcodeMcpActionDetail(actionInfo.actionDetail, server, tool);
|
|
444
487
|
const toolUseId = typeof event.data.toolUseId === "string"
|
|
445
488
|
? event.data.toolUseId
|
|
@@ -459,8 +502,12 @@ export class AcodeSdkAdapter extends EventEmitter {
|
|
|
459
502
|
? event.data.result
|
|
460
503
|
: JSON.stringify(event.data.result ?? ""),
|
|
461
504
|
});
|
|
462
|
-
|
|
463
|
-
|
|
505
|
+
const status = actionInfo.actionType === "idle" &&
|
|
506
|
+
!hasPollingMessages(event.data.result)
|
|
507
|
+
? "waiting_input"
|
|
508
|
+
: "thinking";
|
|
509
|
+
entry.adapterSession.status = status;
|
|
510
|
+
this.emit("status-change", event.sessionId, status);
|
|
464
511
|
return;
|
|
465
512
|
}
|
|
466
513
|
const status = actionInfo.actionType === "idle" ? "waiting_input" : "tool_using";
|
|
@@ -469,6 +516,17 @@ export class AcodeSdkAdapter extends EventEmitter {
|
|
|
469
516
|
this.emit("status-change", event.sessionId, status, eventData);
|
|
470
517
|
return;
|
|
471
518
|
}
|
|
519
|
+
if (event.type === "session_started") {
|
|
520
|
+
const estimatedTokens = toEstimatedContextTokens(event.data);
|
|
521
|
+
if (estimatedTokens > 0) {
|
|
522
|
+
entry.adapterSession.totalUsage.inputTokens = estimatedTokens;
|
|
523
|
+
entry.adapterSession.totalUsage.outputTokens = 0;
|
|
524
|
+
this.emit("status-change", event.sessionId, entry.adapterSession.status, {
|
|
525
|
+
usage: entry.adapterSession.totalUsage,
|
|
526
|
+
});
|
|
527
|
+
}
|
|
528
|
+
return;
|
|
529
|
+
}
|
|
472
530
|
this.emitProviderEvent(event, "thinking", {
|
|
473
531
|
text: JSON.stringify(event.data),
|
|
474
532
|
});
|
|
@@ -121,6 +121,65 @@ class PollMessageStatusRuntime extends EventEmitter {
|
|
|
121
121
|
async abort() { }
|
|
122
122
|
async stop() { }
|
|
123
123
|
}
|
|
124
|
+
class EmptyPollResultRuntime extends EventEmitter {
|
|
125
|
+
constructor(config) {
|
|
126
|
+
super();
|
|
127
|
+
this.config = config;
|
|
128
|
+
}
|
|
129
|
+
async start() { }
|
|
130
|
+
async submit(_message) {
|
|
131
|
+
this.emit("event", {
|
|
132
|
+
type: "mcp_status",
|
|
133
|
+
sessionId: this.config.sessionId,
|
|
134
|
+
timestamp: new Date(0).toISOString(),
|
|
135
|
+
data: { action: "call_tool", server: "aws-mcp", tool: "poll_message" },
|
|
136
|
+
});
|
|
137
|
+
this.emit("event", {
|
|
138
|
+
type: "mcp_status",
|
|
139
|
+
sessionId: this.config.sessionId,
|
|
140
|
+
timestamp: new Date(0).toISOString(),
|
|
141
|
+
data: {
|
|
142
|
+
action: "tool_result",
|
|
143
|
+
server: "aws-mcp",
|
|
144
|
+
tool: "poll_message",
|
|
145
|
+
result: JSON.stringify({ directMessages: [], groupMessages: [] }),
|
|
146
|
+
},
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
async abort() { }
|
|
150
|
+
async stop() { }
|
|
151
|
+
}
|
|
152
|
+
class PollResultWithMessageRuntime extends EventEmitter {
|
|
153
|
+
constructor(config) {
|
|
154
|
+
super();
|
|
155
|
+
this.config = config;
|
|
156
|
+
}
|
|
157
|
+
async start() { }
|
|
158
|
+
async submit(_message) {
|
|
159
|
+
this.emit("event", {
|
|
160
|
+
type: "mcp_status",
|
|
161
|
+
sessionId: this.config.sessionId,
|
|
162
|
+
timestamp: new Date(0).toISOString(),
|
|
163
|
+
data: { action: "call_tool", server: "aws-mcp", tool: "poll_message" },
|
|
164
|
+
});
|
|
165
|
+
this.emit("event", {
|
|
166
|
+
type: "mcp_status",
|
|
167
|
+
sessionId: this.config.sessionId,
|
|
168
|
+
timestamp: new Date(0).toISOString(),
|
|
169
|
+
data: {
|
|
170
|
+
action: "tool_result",
|
|
171
|
+
server: "aws-mcp",
|
|
172
|
+
tool: "poll_message",
|
|
173
|
+
result: JSON.stringify({
|
|
174
|
+
directMessages: [{ senderName: "User", content: "ping" }],
|
|
175
|
+
groupMessages: [],
|
|
176
|
+
}),
|
|
177
|
+
},
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
async abort() { }
|
|
181
|
+
async stop() { }
|
|
182
|
+
}
|
|
124
183
|
class CommandStatusRuntime extends EventEmitter {
|
|
125
184
|
constructor(config) {
|
|
126
185
|
super();
|
|
@@ -156,6 +215,7 @@ class AiRequestRuntime extends EventEmitter {
|
|
|
156
215
|
messageCount: 3,
|
|
157
216
|
toolCount: 2,
|
|
158
217
|
lastUserMessagePreview: "inspect status",
|
|
218
|
+
estimatedContextTokens: 6800,
|
|
159
219
|
requestBody: '{"model":"test-model"}',
|
|
160
220
|
},
|
|
161
221
|
});
|
|
@@ -620,7 +680,11 @@ describe("AcodeSdkAdapter turn completion state", () => {
|
|
|
620
680
|
const adapter = new AcodeSdkAdapter();
|
|
621
681
|
adapter.setRuntimeConstructorForTest(ResponseBodyTurnCompleteRuntime);
|
|
622
682
|
const events = [];
|
|
683
|
+
const statuses = [];
|
|
623
684
|
adapter.on("event", (event) => events.push(event));
|
|
685
|
+
adapter.on("status-change", (_sessionId, status, actionInfo) => {
|
|
686
|
+
statuses.push({ status, usage: actionInfo?.usage });
|
|
687
|
+
});
|
|
624
688
|
await adapter.startSession("session-response-body", {
|
|
625
689
|
command: "acode",
|
|
626
690
|
workingDirectory: process.cwd(),
|
|
@@ -822,6 +886,63 @@ describe("AcodeSdkAdapter turn completion state", () => {
|
|
|
822
886
|
});
|
|
823
887
|
expect(adapter.getSessionStatus("session-poll-message")).toBe("waiting_input");
|
|
824
888
|
});
|
|
889
|
+
it("keeps empty poll_message results in waiting_input instead of showing stuck thinking", async () => {
|
|
890
|
+
const adapter = new AcodeSdkAdapter();
|
|
891
|
+
adapter.setRuntimeConstructorForTest(EmptyPollResultRuntime);
|
|
892
|
+
const events = [];
|
|
893
|
+
const statuses = [];
|
|
894
|
+
adapter.on("event", (event) => events.push(event));
|
|
895
|
+
adapter.on("status-change", (_sessionId, status) => statuses.push(status));
|
|
896
|
+
await adapter.startSession("session-empty-poll-result", {
|
|
897
|
+
command: "acode",
|
|
898
|
+
workingDirectory: process.cwd(),
|
|
899
|
+
autoAccept: true,
|
|
900
|
+
extraMcpServers: {},
|
|
901
|
+
envOverrides: {},
|
|
902
|
+
});
|
|
903
|
+
await adapter.sendMessage("session-empty-poll-result", "listen");
|
|
904
|
+
expect(events.map((event) => event.type)).toEqual([
|
|
905
|
+
"tool_use_start",
|
|
906
|
+
"tool_use_end",
|
|
907
|
+
]);
|
|
908
|
+
expect(statuses).toEqual([
|
|
909
|
+
"starting",
|
|
910
|
+
"waiting_input",
|
|
911
|
+
"thinking",
|
|
912
|
+
"waiting_input",
|
|
913
|
+
"waiting_input",
|
|
914
|
+
]);
|
|
915
|
+
expect(adapter.getSessionStatus("session-empty-poll-result")).toBe("waiting_input");
|
|
916
|
+
});
|
|
917
|
+
it("shows thinking after poll_message returns actual messages to process", async () => {
|
|
918
|
+
const adapter = new AcodeSdkAdapter();
|
|
919
|
+
adapter.setRuntimeConstructorForTest(PollResultWithMessageRuntime);
|
|
920
|
+
const events = [];
|
|
921
|
+
const statuses = [];
|
|
922
|
+
adapter.on("event", (event) => events.push(event));
|
|
923
|
+
adapter.on("status-change", (_sessionId, status) => statuses.push(status));
|
|
924
|
+
await adapter.startSession("session-poll-result-with-message", {
|
|
925
|
+
command: "acode",
|
|
926
|
+
workingDirectory: process.cwd(),
|
|
927
|
+
autoAccept: true,
|
|
928
|
+
extraMcpServers: {},
|
|
929
|
+
envOverrides: {},
|
|
930
|
+
});
|
|
931
|
+
await adapter.sendMessage("session-poll-result-with-message", "listen");
|
|
932
|
+
expect(events.map((event) => event.type)).toEqual([
|
|
933
|
+
"tool_use_start",
|
|
934
|
+
"tool_use_end",
|
|
935
|
+
]);
|
|
936
|
+
expect(statuses).toEqual([
|
|
937
|
+
"starting",
|
|
938
|
+
"waiting_input",
|
|
939
|
+
"thinking",
|
|
940
|
+
"waiting_input",
|
|
941
|
+
"thinking",
|
|
942
|
+
"waiting_input",
|
|
943
|
+
]);
|
|
944
|
+
expect(adapter.getSessionStatus("session-poll-result-with-message")).toBe("waiting_input");
|
|
945
|
+
});
|
|
825
946
|
it("forwards ACode command status as thinking without changing session status", async () => {
|
|
826
947
|
const adapter = new AcodeSdkAdapter();
|
|
827
948
|
adapter.setRuntimeConstructorForTest(CommandStatusRuntime);
|
|
@@ -852,7 +973,11 @@ describe("AcodeSdkAdapter turn completion state", () => {
|
|
|
852
973
|
const adapter = new AcodeSdkAdapter();
|
|
853
974
|
adapter.setRuntimeConstructorForTest(AiRequestRuntime);
|
|
854
975
|
const events = [];
|
|
976
|
+
const statuses = [];
|
|
855
977
|
adapter.on("event", (event) => events.push(event));
|
|
978
|
+
adapter.on("status-change", (_sessionId, status, actionInfo) => {
|
|
979
|
+
statuses.push({ status, usage: actionInfo?.usage });
|
|
980
|
+
});
|
|
856
981
|
await adapter.startSession("session-ai-request", {
|
|
857
982
|
command: "acode",
|
|
858
983
|
workingDirectory: process.cwd(),
|
|
@@ -874,6 +999,10 @@ describe("AcodeSdkAdapter turn completion state", () => {
|
|
|
874
999
|
requestBody: '{"model":"test-model"}',
|
|
875
1000
|
},
|
|
876
1001
|
});
|
|
1002
|
+
expect(statuses).toContainEqual({
|
|
1003
|
+
status: "thinking",
|
|
1004
|
+
usage: { inputTokens: 6800, outputTokens: 0 },
|
|
1005
|
+
});
|
|
877
1006
|
});
|
|
878
1007
|
it("forwards ACode thinking deltas as realtime thinking provider events", async () => {
|
|
879
1008
|
const adapter = new AcodeSdkAdapter();
|
|
@@ -517,7 +517,7 @@ export class OpencodeSdkAdapter extends EventEmitter {
|
|
|
517
517
|
data: { usage: session.adapterSession.totalUsage },
|
|
518
518
|
});
|
|
519
519
|
session.adapterSession.status = 'waiting_input';
|
|
520
|
-
this.emit('status-change', sessionId, 'waiting_input');
|
|
520
|
+
this.emit('status-change', sessionId, 'waiting_input', { usage: session.adapterSession.totalUsage });
|
|
521
521
|
this.startIdleDetection(sessionId);
|
|
522
522
|
break;
|
|
523
523
|
}
|
|
@@ -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();
|
|
@@ -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
|
|
@@ -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":"AAaA,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,CAyC7F;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;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG;IAAE,kBAAkB,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAM1F"}
|
|
@@ -2,6 +2,12 @@ import path from "node:path";
|
|
|
2
2
|
import { schedulerBaseUrl as defaultSchedulerBaseUrl } from "../config.js";
|
|
3
3
|
import { getRuntimeAccessToken, loadRuntimeBinding, normalizeSchedulerBaseUrl } from "./runtime-binding.js";
|
|
4
4
|
const LAUNCH_BINDING_TTL_MS = 5 * 60 * 1000;
|
|
5
|
+
/**
|
|
6
|
+
* 每个 agent 最新的 MCP session token 缓存。
|
|
7
|
+
* key = agentId,value = { runtimeAccessToken, updatedAt }
|
|
8
|
+
* 当 /runtime/start 入队新 binding 时更新,供 MCP node 401 后刷新使用。
|
|
9
|
+
*/
|
|
10
|
+
const latestAgentTokens = new Map();
|
|
5
11
|
const launchBindings = [];
|
|
6
12
|
function normalizeWorkspacePath(workspacePath) {
|
|
7
13
|
const raw = String(workspacePath || "").trim();
|
|
@@ -76,6 +82,14 @@ export function enqueueMcpLaunchBinding(input) {
|
|
|
76
82
|
enqueuedAt: new Date().toISOString(),
|
|
77
83
|
};
|
|
78
84
|
launchBindings.push(binding);
|
|
85
|
+
// 缓存最新 token,供 MCP node 401 后刷新
|
|
86
|
+
const tokenValue = binding.runtimeAccessToken;
|
|
87
|
+
if (tokenValue) {
|
|
88
|
+
latestAgentTokens.set(agentId, {
|
|
89
|
+
runtimeAccessToken: tokenValue,
|
|
90
|
+
updatedAt: Date.now(),
|
|
91
|
+
});
|
|
92
|
+
}
|
|
79
93
|
return binding;
|
|
80
94
|
}
|
|
81
95
|
export function claimMcpLaunchBinding(request) {
|
|
@@ -131,3 +145,14 @@ export function getMcpLaunchQueueSize(workspacePath) {
|
|
|
131
145
|
export function clearMcpLaunchBindingQueues() {
|
|
132
146
|
launchBindings.splice(0, launchBindings.length);
|
|
133
147
|
}
|
|
148
|
+
/**
|
|
149
|
+
* 获取指定 agent 的最新 MCP session token。
|
|
150
|
+
* 供 MCP node 在 401 后向 bridge 查询最新 token 使用。
|
|
151
|
+
*/
|
|
152
|
+
export function getLatestAgentToken(agentId) {
|
|
153
|
+
const cached = latestAgentTokens.get(agentId);
|
|
154
|
+
if (!cached || !cached.runtimeAccessToken) {
|
|
155
|
+
return null;
|
|
156
|
+
}
|
|
157
|
+
return { runtimeAccessToken: cached.runtimeAccessToken };
|
|
158
|
+
}
|
|
@@ -33,6 +33,7 @@ export declare class ACodeRuntime extends EventEmitter {
|
|
|
33
33
|
private requestChatCompletion;
|
|
34
34
|
private readChatCompletionStream;
|
|
35
35
|
private handleToolCalls;
|
|
36
|
+
private callMcpToolWithTimeout;
|
|
36
37
|
private appendSyntheticMultimodalUserMessage;
|
|
37
38
|
private appendToolFailureResult;
|
|
38
39
|
private connectMcpServers;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAiB3C,OAAO,KAAK,EAOV,kBAAkB,EAEnB,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../src/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAiB3C,OAAO,KAAK,EAOV,kBAAkB,EAEnB,MAAM,YAAY,CAAC;AAuoCpB,qBAAa,YAAa,SAAQ,YAAY;IAmChC,OAAO,CAAC,QAAQ,CAAC,MAAM;IAlCnC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAe;IAEvC,OAAO,CAAC,KAAK,CAoBX;IAEF,OAAO,CAAC,eAAe,CAAgC;IAEvD,OAAO,CAAC,WAAW,CAAoC;IAEvD,OAAO,CAAC,UAAU,CAAS;IAE3B,OAAO,CAAC,cAAc,CAAS;IAE/B,OAAO,CAAC,sBAAsB,CAAS;gBAEV,MAAM,EAAE,kBAAkB;IAevD,OAAO,CAAC,cAAc;IAatB;;;;OAIG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAyF5B;;;;OAIG;IACG,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAM9B,aAAa;IA2E3B,oDAAoD;IAC9C,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAM5B,uCAAuC;IACjC,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IA8B3B,OAAO,CAAC,kBAAkB;YAaZ,YAAY;YAoEZ,qBAAqB;YA4JrB,wBAAwB;YA6ExB,eAAe;YAoJf,sBAAsB;YAqCtB,oCAAoC;IAkBlD,OAAO,CAAC,uBAAuB;YAuBjB,iBAAiB;IA2C/B,OAAO,CAAC,kBAAkB;YA2BZ,oBAAoB;CAiBnC"}
|