aws-runtime-bridge 1.9.0 → 1.9.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/AcodeSdkAdapter.d.ts +2 -0
- package/dist/adapter/AcodeSdkAdapter.d.ts.map +1 -1
- package/dist/adapter/AcodeSdkAdapter.js +84 -18
- package/dist/adapter/AcodeSdkAdapter.test.js +275 -13
- package/dist/adapter/acode-tool-names.d.ts +16 -0
- package/dist/adapter/acode-tool-names.d.ts.map +1 -0
- package/dist/adapter/acode-tool-names.js +37 -0
- package/dist/adapter/acode-tool-names.test.d.ts +2 -0
- package/dist/adapter/acode-tool-names.test.d.ts.map +1 -0
- package/dist/adapter/acode-tool-names.test.js +28 -0
- package/dist/adapter/types.d.ts +22 -3
- package/dist/adapter/types.d.ts.map +1 -1
- package/dist/adapter/types.js +2 -1
- package/dist/routes/git.d.ts +10 -0
- package/dist/routes/git.d.ts.map +1 -1
- package/dist/routes/git.js +37 -3
- package/dist/routes/git.test.js +47 -1
- package/dist/routes/sessions.d.ts +1 -1
- package/dist/routes/sessions.d.ts.map +1 -1
- package/dist/routes/sessions.js +11 -4
- package/dist/routes/sessions.test.js +3 -0
- package/dist/routes/terminal.d.ts +28 -8
- package/dist/routes/terminal.d.ts.map +1 -1
- package/dist/routes/terminal.js +260 -44
- package/dist/routes/terminal.stop-options.test.d.ts +2 -0
- package/dist/routes/terminal.stop-options.test.d.ts.map +1 -0
- package/dist/routes/terminal.stop-options.test.js +39 -0
- package/dist/routes/terminal.test.js +87 -4
- package/dist/services/session-output.d.ts +5 -0
- package/dist/services/session-output.d.ts.map +1 -1
- package/package/acode/dist/built-in-file-tools.d.ts +5 -1
- package/package/acode/dist/built-in-file-tools.d.ts.map +1 -1
- package/package/acode/dist/built-in-file-tools.js +14 -203
- package/package/acode/dist/builtins/commandArtifacts.d.ts +25 -0
- package/package/acode/dist/builtins/commandArtifacts.d.ts.map +1 -0
- package/package/acode/dist/builtins/commandArtifacts.js +77 -0
- package/package/acode/dist/builtins/commandOutputEvents.d.ts +21 -0
- package/package/acode/dist/builtins/commandOutputEvents.d.ts.map +1 -0
- package/package/acode/dist/builtins/commandOutputEvents.js +56 -0
- package/package/acode/dist/builtins/shellCommandPreparation.d.ts +15 -0
- package/package/acode/dist/builtins/shellCommandPreparation.d.ts.map +1 -0
- package/package/acode/dist/builtins/shellCommandPreparation.js +44 -0
- package/package/acode/dist/builtins/shellCommandResult.d.ts +30 -0
- package/package/acode/dist/builtins/shellCommandResult.d.ts.map +1 -0
- package/package/acode/dist/builtins/shellCommandResult.js +71 -0
- package/package/acode/dist/builtins/shellCommandRunner.d.ts +14 -0
- package/package/acode/dist/builtins/shellCommandRunner.d.ts.map +1 -0
- package/package/acode/dist/builtins/shellCommandRunner.js +114 -0
- package/package/acode/dist/builtins/shellOutputDecoder.d.ts +5 -0
- package/package/acode/dist/builtins/shellOutputDecoder.d.ts.map +1 -0
- package/package/acode/dist/builtins/shellOutputDecoder.js +30 -0
- package/package/acode/dist/mcpToolNames.d.ts +11 -0
- package/package/acode/dist/mcpToolNames.d.ts.map +1 -0
- package/package/acode/dist/mcpToolNames.js +17 -0
- package/package/acode/dist/runtime.d.ts +19 -0
- package/package/acode/dist/runtime.d.ts.map +1 -1
- package/package/acode/dist/runtime.js +233 -35
- package/package/acode/dist/types.d.ts +1 -1
- package/package/acode/dist/types.d.ts.map +1 -1
- package/package/acode/package.json +1 -1
- package/package/aws-client-agent-mcp/dist/mcp-server.d.ts +3 -3
- package/package/aws-client-agent-mcp/dist/mcp-server.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/mcp-server.js +10 -7
- package/package/aws-client-agent-mcp/dist/mcp-server.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/mcp-server.test.js +47 -0
- package/package/aws-client-agent-mcp/dist/mcp-server.test.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/mcp-tools.d.ts +1 -36
- package/package/aws-client-agent-mcp/dist/mcp-tools.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/mcp-tools.js +3 -169
- package/package/aws-client-agent-mcp/dist/mcp-tools.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/mcp-tools.test.d.ts +2 -0
- package/package/aws-client-agent-mcp/dist/mcp-tools.test.d.ts.map +1 -0
- package/package/aws-client-agent-mcp/dist/mcp-tools.test.js +45 -0
- package/package/aws-client-agent-mcp/dist/mcp-tools.test.js.map +1 -0
- package/package/aws-client-agent-mcp/dist/memory-tools.d.ts +11 -0
- package/package/aws-client-agent-mcp/dist/memory-tools.d.ts.map +1 -0
- package/package/aws-client-agent-mcp/dist/memory-tools.js +144 -0
- package/package/aws-client-agent-mcp/dist/memory-tools.js.map +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 +1 -0
- package/package/aws-client-agent-mcp/dist/websocket-client.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/websocket-client.test.js +43 -3
- package/package/aws-client-agent-mcp/dist/websocket-client.test.js.map +1 -1
- package/package.json +1 -1
|
@@ -17,6 +17,7 @@ type ACodeRuntimeInstance = {
|
|
|
17
17
|
start(): Promise<void>;
|
|
18
18
|
submit(message: string): Promise<void>;
|
|
19
19
|
abort(): Promise<void>;
|
|
20
|
+
resetContext?(): Promise<void>;
|
|
20
21
|
stop(): Promise<void>;
|
|
21
22
|
};
|
|
22
23
|
type ACodeRuntimeConstructor = new (config: {
|
|
@@ -44,6 +45,7 @@ export declare class AcodeSdkAdapter extends EventEmitter implements BaseProvide
|
|
|
44
45
|
sendMessage(sessionId: string, message: string): Promise<void>;
|
|
45
46
|
sendConfirmation(_sessionId: string, _accept: boolean): Promise<void>;
|
|
46
47
|
abortCurrentTurn(sessionId: string): Promise<void>;
|
|
48
|
+
resetContext(sessionId: string): Promise<void>;
|
|
47
49
|
terminateSession(sessionId: string): Promise<void>;
|
|
48
50
|
getConversation(sessionId: string): ConversationMessage[];
|
|
49
51
|
hasSession(sessionId: string): boolean;
|
|
@@ -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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"}
|
|
@@ -10,6 +10,7 @@ import { pathToFileURL } from "node:url";
|
|
|
10
10
|
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
|
+
import { isMessagePollingIdleCommand, isPollMessageToolDescriptor, } from "./acode-tool-names.js";
|
|
13
14
|
import { IdlePollLoop } from "./idle-poll-loop.js";
|
|
14
15
|
import { getCanonicalMcpDetail, getToolActionInfo } from "./types.js";
|
|
15
16
|
const ACODE_AUTO_POLL_PROMPT = [
|
|
@@ -24,15 +25,6 @@ const ACODE_AUTO_POLL_DELAY_MS = 250;
|
|
|
24
25
|
// avoid busy-looping when the same failure recurs on every retry.
|
|
25
26
|
const ACODE_AUTO_POLL_FAILURE_DELAY_MS = 2000;
|
|
26
27
|
const ACODE_MESSAGE_POLLING_IDLE_PROMPT = "系统提醒:当前工作已完成或运行时已进入空闲状态。请立即调用 poll_message 工具阻塞等待新消息和流程线任务提醒;收到流程任务提醒后调用 my_task 查看已由后台静默抢占的任务详情并直接处理;完成任务后调用 submit_task_result 提交结果,然后继续 poll_message。";
|
|
27
|
-
function isMessagePollingIdleCommand(command) {
|
|
28
|
-
const normalized = command.trim();
|
|
29
|
-
if (!normalized)
|
|
30
|
-
return false;
|
|
31
|
-
const lower = normalized.toLowerCase();
|
|
32
|
-
return (lower.includes("poll_message") ||
|
|
33
|
-
lower.includes("get_message") ||
|
|
34
|
-
normalized.includes("取消息"));
|
|
35
|
-
}
|
|
36
28
|
function getAcodePackageEntryPath() {
|
|
37
29
|
return path.resolve(getReleasedAcodeEntryPath());
|
|
38
30
|
}
|
|
@@ -66,6 +58,24 @@ function toFiniteTokenCount(...values) {
|
|
|
66
58
|
function toEstimatedContextTokens(data) {
|
|
67
59
|
return toFiniteTokenCount(data.estimatedContextTokens, data.contextTokens, data.context_tokens, data.contextUsedTokens, data.context_used_tokens);
|
|
68
60
|
}
|
|
61
|
+
function toCommandOutputStream(value) {
|
|
62
|
+
if (value === "stderr" || value === "mixed") {
|
|
63
|
+
return value;
|
|
64
|
+
}
|
|
65
|
+
return "stdout";
|
|
66
|
+
}
|
|
67
|
+
function toStringRecord(value) {
|
|
68
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
const headers = {};
|
|
72
|
+
for (const [key, headerValue] of Object.entries(value)) {
|
|
73
|
+
if (typeof headerValue === "string") {
|
|
74
|
+
headers[key] = headerValue;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return Object.keys(headers).length > 0 ? headers : undefined;
|
|
78
|
+
}
|
|
69
79
|
/**
|
|
70
80
|
* Check whether an ACode turn_complete event represents a failed turn.
|
|
71
81
|
* Main flow: only explicit failed=true prevents error status from being reset to waiting_input.
|
|
@@ -194,6 +204,31 @@ export class AcodeSdkAdapter extends EventEmitter {
|
|
|
194
204
|
async abortCurrentTurn(sessionId) {
|
|
195
205
|
await this.requireSession(sessionId).runtime.abort();
|
|
196
206
|
}
|
|
207
|
+
async resetContext(sessionId) {
|
|
208
|
+
const entry = this.requireSession(sessionId);
|
|
209
|
+
this.cancelScheduledAutoPoll(entry);
|
|
210
|
+
entry.failedTurnRecoveryScheduled = false;
|
|
211
|
+
entry.autoPollActive = false;
|
|
212
|
+
entry.autoPollObservedPollingTool = false;
|
|
213
|
+
entry.autoPollObservedAssistantText = false;
|
|
214
|
+
entry.stopAutoPollAfterCurrentTurn = false;
|
|
215
|
+
entry.idlePollLoop?.stop();
|
|
216
|
+
if (!entry.runtime.resetContext) {
|
|
217
|
+
throw new Error("ACode runtime does not support context reset");
|
|
218
|
+
}
|
|
219
|
+
await entry.runtime.resetContext();
|
|
220
|
+
entry.adapterSession.messages = [];
|
|
221
|
+
entry.adapterSession.totalUsage = { inputTokens: 0, outputTokens: 0 };
|
|
222
|
+
entry.adapterSession.status = "waiting_input";
|
|
223
|
+
this.emit("status-change", sessionId, "waiting_input", {
|
|
224
|
+
usage: entry.adapterSession.totalUsage,
|
|
225
|
+
});
|
|
226
|
+
if (entry.config.initialPrompt?.trim()) {
|
|
227
|
+
this.startInitialPromptTurn(sessionId, entry.config.initialPrompt);
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
this.armIdleLoopOrAutoPoll(sessionId);
|
|
231
|
+
}
|
|
197
232
|
async terminateSession(sessionId) {
|
|
198
233
|
const entry = this.sessions.get(sessionId);
|
|
199
234
|
if (!entry) {
|
|
@@ -336,6 +371,23 @@ export class AcodeSdkAdapter extends EventEmitter {
|
|
|
336
371
|
this.emitProviderEvent(event, "thinking", { text });
|
|
337
372
|
return;
|
|
338
373
|
}
|
|
374
|
+
if (event.type === "command_output") {
|
|
375
|
+
this.emitProviderEvent(event, "command_output", {
|
|
376
|
+
text: typeof event.data.text === "string" ? event.data.text : "",
|
|
377
|
+
stream: toCommandOutputStream(event.data.stream),
|
|
378
|
+
sequence: typeof event.data.sequence === "number"
|
|
379
|
+
? event.data.sequence
|
|
380
|
+
: undefined,
|
|
381
|
+
cwd: typeof event.data.cwd === "string" ? event.data.cwd : undefined,
|
|
382
|
+
commandLineCount: typeof event.data.commandLineCount === "number"
|
|
383
|
+
? event.data.commandLineCount
|
|
384
|
+
: undefined,
|
|
385
|
+
commandFilePath: typeof event.data.commandFilePath === "string"
|
|
386
|
+
? event.data.commandFilePath
|
|
387
|
+
: undefined,
|
|
388
|
+
});
|
|
389
|
+
return;
|
|
390
|
+
}
|
|
339
391
|
if (event.type === "ai_request") {
|
|
340
392
|
const estimatedTokens = toEstimatedContextTokens(event.data);
|
|
341
393
|
if (estimatedTokens > 0) {
|
|
@@ -350,6 +402,13 @@ export class AcodeSdkAdapter extends EventEmitter {
|
|
|
350
402
|
endpoint: typeof event.data.endpoint === "string"
|
|
351
403
|
? event.data.endpoint
|
|
352
404
|
: undefined,
|
|
405
|
+
requestMethod: typeof event.data.requestMethod === "string"
|
|
406
|
+
? event.data.requestMethod
|
|
407
|
+
: undefined,
|
|
408
|
+
requestUrl: typeof event.data.requestUrl === "string"
|
|
409
|
+
? event.data.requestUrl
|
|
410
|
+
: undefined,
|
|
411
|
+
requestHeaders: toStringRecord(event.data.requestHeaders),
|
|
353
412
|
stream: typeof event.data.stream === "boolean"
|
|
354
413
|
? event.data.stream
|
|
355
414
|
: undefined,
|
|
@@ -459,8 +518,7 @@ export class AcodeSdkAdapter extends EventEmitter {
|
|
|
459
518
|
// the session status.
|
|
460
519
|
if (!event.data.action && Array.isArray(event.data.tools)) {
|
|
461
520
|
const tools = event.data.tools;
|
|
462
|
-
const hasPollMessage = tools.some((tool) =>
|
|
463
|
-
tool.name.includes("poll_message"));
|
|
521
|
+
const hasPollMessage = tools.some((tool) => isPollMessageToolDescriptor(tool));
|
|
464
522
|
if (!hasPollMessage) {
|
|
465
523
|
const message = "ACode runtime is not exposing a poll_message tool. The LLM cannot call poll_message. " +
|
|
466
524
|
"Please configure an MCP server that provides poll_message (e.g. aws-mcp) in the dashboard panel for this runtime.";
|
|
@@ -549,7 +607,7 @@ export class AcodeSdkAdapter extends EventEmitter {
|
|
|
549
607
|
return;
|
|
550
608
|
}
|
|
551
609
|
if (entry.idleCommands?.idleInputCommand) {
|
|
552
|
-
entry.
|
|
610
|
+
this.getIdlePollLoop(entry).start();
|
|
553
611
|
return;
|
|
554
612
|
}
|
|
555
613
|
this.scheduleAutoPoll(sessionId);
|
|
@@ -562,12 +620,14 @@ export class AcodeSdkAdapter extends EventEmitter {
|
|
|
562
620
|
getStatus: () => this.sessions.get(sessionId)?.adapterSession.status,
|
|
563
621
|
getCommand: () => this.sessions.get(sessionId)?.idleCommands?.idleInputCommand,
|
|
564
622
|
isPollingCommand: (command) => isMessagePollingIdleCommand(command),
|
|
565
|
-
dispatchPollingPrompt: () => this.submitAutoPollPrompt(sessionId, ACODE_MESSAGE_POLLING_IDLE_PROMPT
|
|
623
|
+
dispatchPollingPrompt: () => this.submitAutoPollPrompt(sessionId, ACODE_MESSAGE_POLLING_IDLE_PROMPT, {
|
|
624
|
+
keepWaitingStatus: true,
|
|
625
|
+
}),
|
|
566
626
|
dispatchRegularIdleCommand: (command) => this.submitAutoPollPrompt(sessionId, command),
|
|
567
627
|
});
|
|
568
628
|
return entry.idlePollLoop;
|
|
569
629
|
}
|
|
570
|
-
submitAutoPollPrompt(sessionId, prompt) {
|
|
630
|
+
submitAutoPollPrompt(sessionId, prompt, options) {
|
|
571
631
|
const entry = this.sessions.get(sessionId);
|
|
572
632
|
if (!entry || this.isTerminalStatus(entry.adapterSession.status))
|
|
573
633
|
return;
|
|
@@ -575,8 +635,10 @@ export class AcodeSdkAdapter extends EventEmitter {
|
|
|
575
635
|
entry.autoPollObservedPollingTool = false;
|
|
576
636
|
entry.autoPollObservedAssistantText = false;
|
|
577
637
|
entry.stopAutoPollAfterCurrentTurn = false;
|
|
578
|
-
|
|
579
|
-
|
|
638
|
+
if (!options?.keepWaitingStatus) {
|
|
639
|
+
entry.adapterSession.status = "thinking";
|
|
640
|
+
this.emit("status-change", sessionId, "thinking");
|
|
641
|
+
}
|
|
580
642
|
void entry.runtime
|
|
581
643
|
.submit(prompt)
|
|
582
644
|
.catch((error) => {
|
|
@@ -642,7 +704,9 @@ export class AcodeSdkAdapter extends EventEmitter {
|
|
|
642
704
|
return;
|
|
643
705
|
}
|
|
644
706
|
currentEntry.autoPollTimer = undefined;
|
|
645
|
-
this.submitAutoPollPrompt(sessionId, ACODE_AUTO_POLL_PROMPT
|
|
707
|
+
this.submitAutoPollPrompt(sessionId, ACODE_AUTO_POLL_PROMPT, {
|
|
708
|
+
keepWaitingStatus: true,
|
|
709
|
+
});
|
|
646
710
|
}, delayMs);
|
|
647
711
|
}
|
|
648
712
|
cancelScheduledAutoPoll(entry) {
|
|
@@ -707,7 +771,9 @@ export class AcodeSdkAdapter extends EventEmitter {
|
|
|
707
771
|
this.getIdlePollLoop(currentEntry).start();
|
|
708
772
|
}
|
|
709
773
|
else {
|
|
710
|
-
this.submitAutoPollPrompt(sessionId, ACODE_AUTO_POLL_PROMPT
|
|
774
|
+
this.submitAutoPollPrompt(sessionId, ACODE_AUTO_POLL_PROMPT, {
|
|
775
|
+
keepWaitingStatus: true,
|
|
776
|
+
});
|
|
711
777
|
}
|
|
712
778
|
}, ACODE_AUTO_POLL_FAILURE_DELAY_MS);
|
|
713
779
|
}
|
|
@@ -211,6 +211,12 @@ class AiRequestRuntime extends EventEmitter {
|
|
|
211
211
|
data: {
|
|
212
212
|
model: "test-model",
|
|
213
213
|
endpoint: "https://example.invalid/v1/chat/completions",
|
|
214
|
+
requestMethod: "POST",
|
|
215
|
+
requestUrl: "https://example.invalid/v1/chat/completions",
|
|
216
|
+
requestHeaders: {
|
|
217
|
+
"Content-Type": "application/json",
|
|
218
|
+
Authorization: "Bearer ***",
|
|
219
|
+
},
|
|
214
220
|
stream: true,
|
|
215
221
|
messageCount: 3,
|
|
216
222
|
toolCount: 2,
|
|
@@ -257,6 +263,30 @@ class AssistantDeltaRuntime extends EventEmitter {
|
|
|
257
263
|
async abort() { }
|
|
258
264
|
async stop() { }
|
|
259
265
|
}
|
|
266
|
+
class CommandOutputRuntime extends EventEmitter {
|
|
267
|
+
constructor(config) {
|
|
268
|
+
super();
|
|
269
|
+
this.config = config;
|
|
270
|
+
}
|
|
271
|
+
async start() { }
|
|
272
|
+
async submit(_message) {
|
|
273
|
+
this.emit("event", {
|
|
274
|
+
type: "command_output",
|
|
275
|
+
sessionId: this.config.sessionId,
|
|
276
|
+
timestamp: new Date(0).toISOString(),
|
|
277
|
+
data: {
|
|
278
|
+
text: "live command output",
|
|
279
|
+
stream: "stdout",
|
|
280
|
+
sequence: 2,
|
|
281
|
+
cwd: "/repo",
|
|
282
|
+
commandLineCount: 1,
|
|
283
|
+
commandFilePath: "/repo/.agentswork/acode/cmd-dist/run.cmd",
|
|
284
|
+
},
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
async abort() { }
|
|
288
|
+
async stop() { }
|
|
289
|
+
}
|
|
260
290
|
class ResponseBodyTurnCompleteRuntime extends EventEmitter {
|
|
261
291
|
constructor(config) {
|
|
262
292
|
super();
|
|
@@ -297,6 +327,36 @@ class ProviderUsageTurnCompleteRuntime extends EventEmitter {
|
|
|
297
327
|
async abort() { }
|
|
298
328
|
async stop() { }
|
|
299
329
|
}
|
|
330
|
+
class ResettableRuntime extends EventEmitter {
|
|
331
|
+
constructor(config) {
|
|
332
|
+
super();
|
|
333
|
+
this.config = config;
|
|
334
|
+
}
|
|
335
|
+
async start() { }
|
|
336
|
+
async submit(_message) {
|
|
337
|
+
this.emit("event", {
|
|
338
|
+
type: "assistant_delta",
|
|
339
|
+
sessionId: this.config.sessionId,
|
|
340
|
+
timestamp: new Date(0).toISOString(),
|
|
341
|
+
data: { text: "done" },
|
|
342
|
+
});
|
|
343
|
+
this.emit("event", {
|
|
344
|
+
type: "turn_complete",
|
|
345
|
+
sessionId: this.config.sessionId,
|
|
346
|
+
timestamp: new Date(0).toISOString(),
|
|
347
|
+
data: { usage: { inputTokens: 7, outputTokens: 3 } },
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
async resetContext() {
|
|
351
|
+
ResettableRuntime.resetCalls += 1;
|
|
352
|
+
}
|
|
353
|
+
async abort() { }
|
|
354
|
+
async stop() {
|
|
355
|
+
ResettableRuntime.stopCalls += 1;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
ResettableRuntime.resetCalls = 0;
|
|
359
|
+
ResettableRuntime.stopCalls = 0;
|
|
300
360
|
class ThinkingThenAssistantDeltaRuntime extends EventEmitter {
|
|
301
361
|
constructor(config) {
|
|
302
362
|
super();
|
|
@@ -643,6 +703,58 @@ class DifferentlyNamedMcpRuntime extends EventEmitter {
|
|
|
643
703
|
async abort() { }
|
|
644
704
|
async stop() { }
|
|
645
705
|
}
|
|
706
|
+
class FakePollMessageToolRuntime extends EventEmitter {
|
|
707
|
+
constructor(config) {
|
|
708
|
+
super();
|
|
709
|
+
this.config = config;
|
|
710
|
+
}
|
|
711
|
+
async start() {
|
|
712
|
+
this.emit("event", {
|
|
713
|
+
type: "mcp_status",
|
|
714
|
+
sessionId: this.config.sessionId,
|
|
715
|
+
timestamp: new Date(0).toISOString(),
|
|
716
|
+
data: {
|
|
717
|
+
tools: [
|
|
718
|
+
{
|
|
719
|
+
name: "other-mcp__not_poll_message",
|
|
720
|
+
source: "other-mcp.not_poll_message",
|
|
721
|
+
},
|
|
722
|
+
],
|
|
723
|
+
},
|
|
724
|
+
});
|
|
725
|
+
}
|
|
726
|
+
async submit(_message) { }
|
|
727
|
+
async abort() { }
|
|
728
|
+
async stop() { }
|
|
729
|
+
}
|
|
730
|
+
class DeferredInitialThenRegularIdleRuntime extends EventEmitter {
|
|
731
|
+
constructor(config) {
|
|
732
|
+
super();
|
|
733
|
+
this.config = config;
|
|
734
|
+
}
|
|
735
|
+
async start() { }
|
|
736
|
+
async submit(message) {
|
|
737
|
+
DeferredInitialThenRegularIdleRuntime.submitMessages.push(message);
|
|
738
|
+
if (DeferredInitialThenRegularIdleRuntime.submitMessages.length !== 1) {
|
|
739
|
+
return;
|
|
740
|
+
}
|
|
741
|
+
await new Promise((resolve) => {
|
|
742
|
+
DeferredInitialThenRegularIdleRuntime.completeInitialTurn = () => {
|
|
743
|
+
this.emit("event", {
|
|
744
|
+
type: "turn_complete",
|
|
745
|
+
sessionId: this.config.sessionId,
|
|
746
|
+
timestamp: new Date(0).toISOString(),
|
|
747
|
+
data: { usage: { inputTokens: 1, outputTokens: 1 } },
|
|
748
|
+
});
|
|
749
|
+
DeferredInitialThenRegularIdleRuntime.completeInitialTurn = undefined;
|
|
750
|
+
resolve();
|
|
751
|
+
};
|
|
752
|
+
});
|
|
753
|
+
}
|
|
754
|
+
async abort() { }
|
|
755
|
+
async stop() { }
|
|
756
|
+
}
|
|
757
|
+
DeferredInitialThenRegularIdleRuntime.submitMessages = [];
|
|
646
758
|
describe("AcodeSdkAdapter turn completion state", () => {
|
|
647
759
|
it("keeps error status for failed turn_complete events", () => {
|
|
648
760
|
expect(isFailedAcodeTurnComplete({ failed: true })).toBe(true);
|
|
@@ -730,6 +842,46 @@ describe("AcodeSdkAdapter turn completion state", () => {
|
|
|
730
842
|
usage: { inputTokens: 31, outputTokens: 58 },
|
|
731
843
|
});
|
|
732
844
|
});
|
|
845
|
+
it("resets ACode context in place without terminating the SDK session", async () => {
|
|
846
|
+
vi.useFakeTimers();
|
|
847
|
+
ResettableRuntime.resetCalls = 0;
|
|
848
|
+
ResettableRuntime.stopCalls = 0;
|
|
849
|
+
const adapter = new AcodeSdkAdapter();
|
|
850
|
+
adapter.setRuntimeConstructorForTest(ResettableRuntime);
|
|
851
|
+
const statuses = [];
|
|
852
|
+
adapter.on("status-change", (_sessionId, status, actionInfo) => {
|
|
853
|
+
statuses.push({ status, usage: actionInfo?.usage });
|
|
854
|
+
});
|
|
855
|
+
try {
|
|
856
|
+
await adapter.startSession("session-reset-context", {
|
|
857
|
+
command: "acode",
|
|
858
|
+
workingDirectory: process.cwd(),
|
|
859
|
+
autoAccept: true,
|
|
860
|
+
extraMcpServers: {},
|
|
861
|
+
envOverrides: {},
|
|
862
|
+
});
|
|
863
|
+
await adapter.sendMessage("session-reset-context", "finish work");
|
|
864
|
+
expect(adapter.getConversation("session-reset-context")).toHaveLength(2);
|
|
865
|
+
expect(statuses.at(-1)).toEqual({
|
|
866
|
+
status: "waiting_input",
|
|
867
|
+
usage: { inputTokens: 7, outputTokens: 3 },
|
|
868
|
+
});
|
|
869
|
+
await adapter.resetContext("session-reset-context");
|
|
870
|
+
expect(ResettableRuntime.resetCalls).toBe(1);
|
|
871
|
+
expect(ResettableRuntime.stopCalls).toBe(0);
|
|
872
|
+
expect(adapter.hasSession("session-reset-context")).toBe(true);
|
|
873
|
+
expect(adapter.getSessionStatus("session-reset-context")).toBe("waiting_input");
|
|
874
|
+
expect(adapter.getConversation("session-reset-context")).toEqual([]);
|
|
875
|
+
expect(statuses.at(-1)).toEqual({
|
|
876
|
+
status: "waiting_input",
|
|
877
|
+
usage: { inputTokens: 0, outputTokens: 0 },
|
|
878
|
+
});
|
|
879
|
+
}
|
|
880
|
+
finally {
|
|
881
|
+
vi.useRealTimers();
|
|
882
|
+
adapter.cleanup();
|
|
883
|
+
}
|
|
884
|
+
});
|
|
733
885
|
it("maps ACode MCP status events to tool_using instead of thinking", async () => {
|
|
734
886
|
const adapter = new AcodeSdkAdapter();
|
|
735
887
|
adapter.setRuntimeConstructorForTest(McpStatusRuntime);
|
|
@@ -992,6 +1144,12 @@ describe("AcodeSdkAdapter turn completion state", () => {
|
|
|
992
1144
|
data: {
|
|
993
1145
|
model: "test-model",
|
|
994
1146
|
endpoint: "https://example.invalid/v1/chat/completions",
|
|
1147
|
+
requestMethod: "POST",
|
|
1148
|
+
requestUrl: "https://example.invalid/v1/chat/completions",
|
|
1149
|
+
requestHeaders: {
|
|
1150
|
+
"Content-Type": "application/json",
|
|
1151
|
+
Authorization: "Bearer ***",
|
|
1152
|
+
},
|
|
995
1153
|
stream: true,
|
|
996
1154
|
messageCount: 3,
|
|
997
1155
|
toolCount: 2,
|
|
@@ -1042,6 +1200,32 @@ describe("AcodeSdkAdapter turn completion state", () => {
|
|
|
1042
1200
|
data: { text: "answer chunk" },
|
|
1043
1201
|
});
|
|
1044
1202
|
});
|
|
1203
|
+
it("forwards ACode command output as ordered realtime provider events", async () => {
|
|
1204
|
+
const adapter = new AcodeSdkAdapter();
|
|
1205
|
+
adapter.setRuntimeConstructorForTest(CommandOutputRuntime);
|
|
1206
|
+
const events = [];
|
|
1207
|
+
adapter.on("event", (event) => events.push(event));
|
|
1208
|
+
await adapter.startSession("session-command-output", {
|
|
1209
|
+
command: "acode",
|
|
1210
|
+
workingDirectory: process.cwd(),
|
|
1211
|
+
autoAccept: true,
|
|
1212
|
+
extraMcpServers: {},
|
|
1213
|
+
envOverrides: {},
|
|
1214
|
+
});
|
|
1215
|
+
await adapter.sendMessage("session-command-output", "run command");
|
|
1216
|
+
expect(events).toHaveLength(1);
|
|
1217
|
+
expect(events[0]).toMatchObject({
|
|
1218
|
+
type: "command_output",
|
|
1219
|
+
data: {
|
|
1220
|
+
text: "live command output",
|
|
1221
|
+
stream: "stdout",
|
|
1222
|
+
sequence: 2,
|
|
1223
|
+
cwd: "/repo",
|
|
1224
|
+
commandLineCount: 1,
|
|
1225
|
+
commandFilePath: "/repo/.agentswork/acode/cmd-dist/run.cmd",
|
|
1226
|
+
},
|
|
1227
|
+
});
|
|
1228
|
+
});
|
|
1045
1229
|
it("preserves realtime thinking then answer delta order", async () => {
|
|
1046
1230
|
const adapter = new AcodeSdkAdapter();
|
|
1047
1231
|
adapter.setRuntimeConstructorForTest(ThinkingThenAssistantDeltaRuntime);
|
|
@@ -1146,6 +1330,43 @@ describe("AcodeSdkAdapter turn completion state", () => {
|
|
|
1146
1330
|
expect(statuses).toEqual(["starting", "waiting_input", "thinking"]);
|
|
1147
1331
|
expect(adapter.getSessionStatus("session-initial-prompt")).toBe("thinking");
|
|
1148
1332
|
});
|
|
1333
|
+
it("runs regular idle commands configured while ACode is still busy", async () => {
|
|
1334
|
+
vi.useFakeTimers();
|
|
1335
|
+
DeferredInitialThenRegularIdleRuntime.submitMessages = [];
|
|
1336
|
+
DeferredInitialThenRegularIdleRuntime.completeInitialTurn = undefined;
|
|
1337
|
+
const adapter = new AcodeSdkAdapter();
|
|
1338
|
+
adapter.setRuntimeConstructorForTest(DeferredInitialThenRegularIdleRuntime);
|
|
1339
|
+
try {
|
|
1340
|
+
await adapter.startSession("session-regular-idle-busy-config", {
|
|
1341
|
+
command: "acode",
|
|
1342
|
+
workingDirectory: process.cwd(),
|
|
1343
|
+
autoAccept: true,
|
|
1344
|
+
initialPrompt: "bootstrap current task",
|
|
1345
|
+
extraMcpServers: {},
|
|
1346
|
+
envOverrides: {},
|
|
1347
|
+
});
|
|
1348
|
+
expect(DeferredInitialThenRegularIdleRuntime.submitMessages).toEqual([
|
|
1349
|
+
"bootstrap current task",
|
|
1350
|
+
]);
|
|
1351
|
+
expect(adapter.getSessionStatus("session-regular-idle-busy-config")).toBe("thinking");
|
|
1352
|
+
adapter.setIdleCommands("session-regular-idle-busy-config", {
|
|
1353
|
+
idleInputCommand: "continue after idle",
|
|
1354
|
+
nonInputCommand: "",
|
|
1355
|
+
});
|
|
1356
|
+
const completeInitialTurn = DeferredInitialThenRegularIdleRuntime.completeInitialTurn;
|
|
1357
|
+
expect(completeInitialTurn).toBeDefined();
|
|
1358
|
+
completeInitialTurn?.();
|
|
1359
|
+
await vi.advanceTimersByTimeAsync(1500);
|
|
1360
|
+
expect(DeferredInitialThenRegularIdleRuntime.submitMessages).toEqual([
|
|
1361
|
+
"bootstrap current task",
|
|
1362
|
+
"continue after idle",
|
|
1363
|
+
]);
|
|
1364
|
+
}
|
|
1365
|
+
finally {
|
|
1366
|
+
vi.useRealTimers();
|
|
1367
|
+
adapter.cleanup();
|
|
1368
|
+
}
|
|
1369
|
+
});
|
|
1149
1370
|
it("continues the message loop by auto-submitting poll_message after a completed turn", async () => {
|
|
1150
1371
|
vi.useFakeTimers();
|
|
1151
1372
|
AutoPollRuntime.submitMessages = [];
|
|
@@ -1171,8 +1392,6 @@ describe("AcodeSdkAdapter turn completion state", () => {
|
|
|
1171
1392
|
"waiting_input",
|
|
1172
1393
|
"thinking",
|
|
1173
1394
|
"waiting_input",
|
|
1174
|
-
"thinking",
|
|
1175
|
-
"waiting_input",
|
|
1176
1395
|
]);
|
|
1177
1396
|
expect(adapter.getSessionStatus("session-auto-poll")).toBe("waiting_input");
|
|
1178
1397
|
}
|
|
@@ -1181,6 +1400,31 @@ describe("AcodeSdkAdapter turn completion state", () => {
|
|
|
1181
1400
|
adapter.cleanup();
|
|
1182
1401
|
}
|
|
1183
1402
|
});
|
|
1403
|
+
it("keeps waiting_input while dispatching an auto-poll prompt", async () => {
|
|
1404
|
+
vi.useFakeTimers();
|
|
1405
|
+
DeferredInitialPromptRuntime.submitCalls = 0;
|
|
1406
|
+
const adapter = new AcodeSdkAdapter();
|
|
1407
|
+
adapter.setRuntimeConstructorForTest(DeferredInitialPromptRuntime);
|
|
1408
|
+
const statuses = [];
|
|
1409
|
+
adapter.on("status-change", (_sessionId, status) => statuses.push(status));
|
|
1410
|
+
try {
|
|
1411
|
+
await adapter.startSession("session-auto-poll-pending", {
|
|
1412
|
+
command: "acode",
|
|
1413
|
+
workingDirectory: process.cwd(),
|
|
1414
|
+
autoAccept: true,
|
|
1415
|
+
extraMcpServers: {},
|
|
1416
|
+
envOverrides: {},
|
|
1417
|
+
});
|
|
1418
|
+
await vi.advanceTimersByTimeAsync(250);
|
|
1419
|
+
expect(DeferredInitialPromptRuntime.submitCalls).toBe(1);
|
|
1420
|
+
expect(adapter.getSessionStatus("session-auto-poll-pending")).toBe("waiting_input");
|
|
1421
|
+
expect(statuses).toEqual(["starting", "waiting_input"]);
|
|
1422
|
+
}
|
|
1423
|
+
finally {
|
|
1424
|
+
vi.useRealTimers();
|
|
1425
|
+
adapter.cleanup();
|
|
1426
|
+
}
|
|
1427
|
+
});
|
|
1184
1428
|
it("stops re-arming auto-poll when the model answers without calling poll_message", async () => {
|
|
1185
1429
|
vi.useFakeTimers();
|
|
1186
1430
|
NonPollingAutoPollRuntime.submitMessages = [];
|
|
@@ -1324,17 +1568,12 @@ describe("AcodeSdkAdapter turn completion state", () => {
|
|
|
1324
1568
|
});
|
|
1325
1569
|
await vi.advanceTimersByTimeAsync(250);
|
|
1326
1570
|
// Status sequence: starting -> waiting_input (startSession) ->
|
|
1327
|
-
//
|
|
1328
|
-
//
|
|
1329
|
-
//
|
|
1571
|
+
// waiting_input (poll turn completes and re-arms the loop). The
|
|
1572
|
+
// auto-poll prompt stays in waiting_input so a slow or missing
|
|
1573
|
+
// poll_message tool event cannot leave the dashboard on thinking.
|
|
1330
1574
|
expect(AutoPollRuntime.submitMessages).toHaveLength(1);
|
|
1331
1575
|
expect(AutoPollRuntime.submitMessages[0]).toContain("poll_message");
|
|
1332
|
-
expect(statuses).toEqual([
|
|
1333
|
-
"starting",
|
|
1334
|
-
"waiting_input",
|
|
1335
|
-
"thinking",
|
|
1336
|
-
"waiting_input",
|
|
1337
|
-
]);
|
|
1576
|
+
expect(statuses).toEqual(["starting", "waiting_input", "waiting_input"]);
|
|
1338
1577
|
expect(adapter.getSessionStatus("session-r1-no-initial")).toBe("waiting_input");
|
|
1339
1578
|
}
|
|
1340
1579
|
finally {
|
|
@@ -1368,7 +1607,6 @@ describe("AcodeSdkAdapter turn completion state", () => {
|
|
|
1368
1607
|
expect(statuses).toEqual([
|
|
1369
1608
|
"starting",
|
|
1370
1609
|
"waiting_input",
|
|
1371
|
-
"thinking",
|
|
1372
1610
|
"error",
|
|
1373
1611
|
"waiting_input",
|
|
1374
1612
|
]);
|
|
@@ -1408,7 +1646,6 @@ describe("AcodeSdkAdapter turn completion state", () => {
|
|
|
1408
1646
|
expect(statuses).toEqual([
|
|
1409
1647
|
"starting",
|
|
1410
1648
|
"waiting_input",
|
|
1411
|
-
"thinking",
|
|
1412
1649
|
"error",
|
|
1413
1650
|
"waiting_input",
|
|
1414
1651
|
]);
|
|
@@ -1557,6 +1794,31 @@ describe("AcodeSdkAdapter turn completion state", () => {
|
|
|
1557
1794
|
adapter.cleanup();
|
|
1558
1795
|
}
|
|
1559
1796
|
});
|
|
1797
|
+
it("does not treat tools that only contain poll_message as a real listener", async () => {
|
|
1798
|
+
const adapter = new AcodeSdkAdapter();
|
|
1799
|
+
adapter.setRuntimeConstructorForTest(FakePollMessageToolRuntime);
|
|
1800
|
+
const events = [];
|
|
1801
|
+
const consoleWarn = vi
|
|
1802
|
+
.spyOn(console, "warn")
|
|
1803
|
+
.mockImplementation(() => undefined);
|
|
1804
|
+
adapter.on("event", (event) => events.push(event));
|
|
1805
|
+
try {
|
|
1806
|
+
await adapter.startSession("session-r3-fake-poll-message", {
|
|
1807
|
+
command: "acode",
|
|
1808
|
+
workingDirectory: process.cwd(),
|
|
1809
|
+
autoAccept: true,
|
|
1810
|
+
extraMcpServers: {},
|
|
1811
|
+
envOverrides: {},
|
|
1812
|
+
});
|
|
1813
|
+
expect(events.find((event) => event.type === "error")).toBeUndefined();
|
|
1814
|
+
expect(consoleWarn).toHaveBeenCalled();
|
|
1815
|
+
expect(String(consoleWarn.mock.calls[0]?.[0] ?? "")).toContain("poll_message");
|
|
1816
|
+
}
|
|
1817
|
+
finally {
|
|
1818
|
+
consoleWarn.mockRestore();
|
|
1819
|
+
adapter.cleanup();
|
|
1820
|
+
}
|
|
1821
|
+
});
|
|
1560
1822
|
it("does not log a warning when the MCP server is named differently but still exposes poll_message (R3 user-scenario)", async () => {
|
|
1561
1823
|
// Reproduces the production scenario from the bug report: the user
|
|
1562
1824
|
// configures the AWS MCP under a non-default name (e.g. 'aws-mcp-server'
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Main flow: normalize common MCP separators, then use the final segment as
|
|
3
|
+
* the semantic tool name exposed to the agent.
|
|
4
|
+
*/
|
|
5
|
+
export declare function getSemanticToolName(toolName: string): string;
|
|
6
|
+
/**
|
|
7
|
+
* Main flow: detect free-form idle guidance that asks the agent to enter the
|
|
8
|
+
* message-polling loop.
|
|
9
|
+
*/
|
|
10
|
+
export declare function isMessagePollingIdleCommand(command: string): boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Main flow: validate startup MCP tool descriptors against the exact
|
|
13
|
+
* poll_message semantic tool name instead of substring matching.
|
|
14
|
+
*/
|
|
15
|
+
export declare function isPollMessageToolDescriptor(tool: Readonly<Record<string, unknown>>): boolean;
|
|
16
|
+
//# sourceMappingURL=acode-tool-names.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"acode-tool-names.d.ts","sourceRoot":"","sources":["../../src/adapter/acode-tool-names.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAI5D;AAED;;;GAGG;AACH,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CASpE;AASD;;;GAGG;AACH,wBAAgB,2BAA2B,CACzC,IAAI,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,GACtC,OAAO,CAKT"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
const CHINESE_GET_MESSAGE_HINT = "\u53d6\u6d88\u606f";
|
|
2
|
+
/**
|
|
3
|
+
* Main flow: normalize common MCP separators, then use the final segment as
|
|
4
|
+
* the semantic tool name exposed to the agent.
|
|
5
|
+
*/
|
|
6
|
+
export function getSemanticToolName(toolName) {
|
|
7
|
+
const normalized = toolName.trim().toLowerCase();
|
|
8
|
+
const segments = normalized.split(/__|[./]/).filter(Boolean);
|
|
9
|
+
return segments.at(-1) ?? normalized;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Main flow: detect free-form idle guidance that asks the agent to enter the
|
|
13
|
+
* message-polling loop.
|
|
14
|
+
*/
|
|
15
|
+
export function isMessagePollingIdleCommand(command) {
|
|
16
|
+
const normalized = command.trim();
|
|
17
|
+
if (!normalized)
|
|
18
|
+
return false;
|
|
19
|
+
const lower = normalized.toLowerCase();
|
|
20
|
+
return (lower.includes("poll_message") ||
|
|
21
|
+
lower.includes("get_message") ||
|
|
22
|
+
normalized.includes(CHINESE_GET_MESSAGE_HINT));
|
|
23
|
+
}
|
|
24
|
+
function hasExactToolSegment(value, toolName) {
|
|
25
|
+
if (typeof value !== "string") {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
return getSemanticToolName(value) === toolName;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Main flow: validate startup MCP tool descriptors against the exact
|
|
32
|
+
* poll_message semantic tool name instead of substring matching.
|
|
33
|
+
*/
|
|
34
|
+
export function isPollMessageToolDescriptor(tool) {
|
|
35
|
+
return (hasExactToolSegment(tool.name, "poll_message") ||
|
|
36
|
+
hasExactToolSegment(tool.source, "poll_message"));
|
|
37
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"acode-tool-names.test.d.ts","sourceRoot":"","sources":["../../src/adapter/acode-tool-names.test.ts"],"names":[],"mappings":""}
|