@ycodium-ai/agent-fake 0.2.3130 → 0.2.3168
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/index.js +122 -59
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -89,6 +89,86 @@ var FAKE_CARD = {
|
|
|
89
89
|
// src/fakeInstance.ts
|
|
90
90
|
import * as NodeCrypto from "node:crypto";
|
|
91
91
|
|
|
92
|
+
// src/fakeEventBus.ts
|
|
93
|
+
var EventBus = class {
|
|
94
|
+
#queued = [];
|
|
95
|
+
#waiters = [];
|
|
96
|
+
#closed = false;
|
|
97
|
+
push(event) {
|
|
98
|
+
const waiter = this.#waiters.shift();
|
|
99
|
+
if (waiter) {
|
|
100
|
+
waiter({ done: false, value: event });
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
this.#queued.push(event);
|
|
104
|
+
}
|
|
105
|
+
close() {
|
|
106
|
+
if (this.#closed) return;
|
|
107
|
+
this.#closed = true;
|
|
108
|
+
while (this.#waiters.length > 0) {
|
|
109
|
+
this.#waiters.shift()?.({ done: true, value: void 0 });
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
[Symbol.asyncIterator]() {
|
|
113
|
+
return {
|
|
114
|
+
next: () => {
|
|
115
|
+
const queued = this.#queued.shift();
|
|
116
|
+
if (queued !== void 0) return Promise.resolve({ done: false, value: queued });
|
|
117
|
+
if (this.#closed) return Promise.resolve({ done: true, value: void 0 });
|
|
118
|
+
return new Promise((resolve) => {
|
|
119
|
+
this.#waiters.push(resolve);
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
// src/fakeSessionLifecycle.ts
|
|
127
|
+
function runFakeTurn(run, settle, fail) {
|
|
128
|
+
const work = run();
|
|
129
|
+
return (fail === void 0 ? work : work.catch(fail)).finally(settle);
|
|
130
|
+
}
|
|
131
|
+
function createFakeSessionLifecycle(input) {
|
|
132
|
+
let disposal;
|
|
133
|
+
const closeBooked = (threadId, booked) => {
|
|
134
|
+
if (booked.closing !== void 0) return booked.closing;
|
|
135
|
+
const closing = Promise.withResolvers();
|
|
136
|
+
booked.closing = closing.promise;
|
|
137
|
+
void (async () => {
|
|
138
|
+
input.abort(threadId);
|
|
139
|
+
const [cleanup] = await Promise.allSettled([
|
|
140
|
+
(async () => input.stopPlaybook(threadId))(),
|
|
141
|
+
booked.turnWork?.catch(() => void 0)
|
|
142
|
+
]);
|
|
143
|
+
if (cleanup.status === "rejected") throw cleanup.reason;
|
|
144
|
+
if (input.threads.get(threadId) !== booked) return;
|
|
145
|
+
input.exited(booked.session);
|
|
146
|
+
input.threads.delete(threadId);
|
|
147
|
+
input.forget(threadId);
|
|
148
|
+
})().then(closing.resolve, closing.reject);
|
|
149
|
+
return closing.promise;
|
|
150
|
+
};
|
|
151
|
+
return {
|
|
152
|
+
closeBooked,
|
|
153
|
+
dispose: () => {
|
|
154
|
+
if (disposal !== void 0) return disposal;
|
|
155
|
+
const disposing = Promise.withResolvers();
|
|
156
|
+
disposal = disposing.promise;
|
|
157
|
+
void (async () => {
|
|
158
|
+
const results = await Promise.allSettled(
|
|
159
|
+
[...input.threads].map(([threadId, booked]) => closeBooked(threadId, booked))
|
|
160
|
+
);
|
|
161
|
+
for (const result of results) {
|
|
162
|
+
if (result.status === "rejected") throw result.reason;
|
|
163
|
+
}
|
|
164
|
+
await input.disposePlaybook();
|
|
165
|
+
input.closeEvents();
|
|
166
|
+
})().then(disposing.resolve, disposing.reject);
|
|
167
|
+
return disposal;
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
|
|
92
172
|
// src/laneScript.ts
|
|
93
173
|
import * as NodeFS from "node:fs";
|
|
94
174
|
import * as NodePath from "node:path";
|
|
@@ -563,12 +643,14 @@ function parseMcpSendInput(input) {
|
|
|
563
643
|
async function runMcpCalls(input) {
|
|
564
644
|
const lines = [];
|
|
565
645
|
for (const call of input.calls) {
|
|
646
|
+
if (input.signal?.aborted === true) break;
|
|
566
647
|
try {
|
|
567
648
|
const result = await callMcpTool({
|
|
568
649
|
fetch: input.fetch,
|
|
569
650
|
server: input.server,
|
|
570
651
|
name: call.tool,
|
|
571
|
-
arguments: call.arguments
|
|
652
|
+
arguments: call.arguments,
|
|
653
|
+
...input.signal === void 0 ? {} : { signal: input.signal }
|
|
572
654
|
});
|
|
573
655
|
lines.push(`mcp-send ${call.tool}: ${JSON.stringify(result)}`);
|
|
574
656
|
} catch (error) {
|
|
@@ -1153,38 +1235,6 @@ async function runVisualizeTurn(input) {
|
|
|
1153
1235
|
|
|
1154
1236
|
// src/fakeInstance.ts
|
|
1155
1237
|
var yieldTick = () => Promise.resolve();
|
|
1156
|
-
var EventBus = class {
|
|
1157
|
-
#queued = [];
|
|
1158
|
-
#waiters = [];
|
|
1159
|
-
#closed = false;
|
|
1160
|
-
push(event) {
|
|
1161
|
-
const waiter = this.#waiters.shift();
|
|
1162
|
-
if (waiter) {
|
|
1163
|
-
waiter({ done: false, value: event });
|
|
1164
|
-
return;
|
|
1165
|
-
}
|
|
1166
|
-
this.#queued.push(event);
|
|
1167
|
-
}
|
|
1168
|
-
close() {
|
|
1169
|
-
if (this.#closed) return;
|
|
1170
|
-
this.#closed = true;
|
|
1171
|
-
while (this.#waiters.length > 0) {
|
|
1172
|
-
this.#waiters.shift()?.({ done: true, value: void 0 });
|
|
1173
|
-
}
|
|
1174
|
-
}
|
|
1175
|
-
[Symbol.asyncIterator]() {
|
|
1176
|
-
return {
|
|
1177
|
-
next: () => {
|
|
1178
|
-
const queued = this.#queued.shift();
|
|
1179
|
-
if (queued !== void 0) return Promise.resolve({ done: false, value: queued });
|
|
1180
|
-
if (this.#closed) return Promise.resolve({ done: true, value: void 0 });
|
|
1181
|
-
return new Promise((resolve) => {
|
|
1182
|
-
this.#waiters.push(resolve);
|
|
1183
|
-
});
|
|
1184
|
-
}
|
|
1185
|
-
};
|
|
1186
|
-
}
|
|
1187
|
-
};
|
|
1188
1238
|
var FAKE_ASYNC_QUESTIONS = [
|
|
1189
1239
|
{
|
|
1190
1240
|
id: "q0",
|
|
@@ -1253,9 +1303,29 @@ var createFakeInstance = (config, host) => {
|
|
|
1253
1303
|
payload,
|
|
1254
1304
|
...extra?.turnId === void 0 ? {} : { turnId: extra.turnId },
|
|
1255
1305
|
...extra?.itemId === void 0 ? {} : { itemId: extra.itemId },
|
|
1256
|
-
...extra?.requestId === void 0 ? {} : { requestId: extra.requestId }
|
|
1306
|
+
...extra?.requestId === void 0 ? {} : { requestId: extra.requestId },
|
|
1307
|
+
...extra?.originBindingGeneration === void 0 ? {} : { originBindingGeneration: extra.originBindingGeneration },
|
|
1308
|
+
...extra?.originResumeCursor === void 0 ? {} : { originResumeCursor: extra.originResumeCursor }
|
|
1257
1309
|
});
|
|
1258
1310
|
};
|
|
1311
|
+
const lifecycle = createFakeSessionLifecycle({
|
|
1312
|
+
threads,
|
|
1313
|
+
abort: (threadId) => inflight.get(threadId)?.abort(),
|
|
1314
|
+
stopPlaybook: (threadId) => playbook?.stopSession(threadId),
|
|
1315
|
+
// 代次与续接游标取被关闭的那份 session,不在发送时重查当前会话。
|
|
1316
|
+
exited: (session) => emit(
|
|
1317
|
+
"session.exited",
|
|
1318
|
+
session.threadId,
|
|
1319
|
+
{ reason: "stopped" },
|
|
1320
|
+
{
|
|
1321
|
+
...session.bindingGeneration === void 0 ? {} : { originBindingGeneration: session.bindingGeneration },
|
|
1322
|
+
...session.resumeCursor === void 0 ? {} : { originResumeCursor: session.resumeCursor }
|
|
1323
|
+
}
|
|
1324
|
+
),
|
|
1325
|
+
forget: (threadId) => steeredInputs.delete(threadId),
|
|
1326
|
+
disposePlaybook: () => playbook?.dispose(),
|
|
1327
|
+
closeEvents: () => events.close()
|
|
1328
|
+
});
|
|
1259
1329
|
const requireThread = (threadId) => {
|
|
1260
1330
|
const booked = threads.get(threadId);
|
|
1261
1331
|
if (!booked) throw new Error(`unknown thread ${threadId}`);
|
|
@@ -1283,12 +1353,12 @@ var createFakeInstance = (config, host) => {
|
|
|
1283
1353
|
inflight.delete(booked.session.threadId);
|
|
1284
1354
|
}
|
|
1285
1355
|
};
|
|
1286
|
-
const runMcpSendScript = async (booked, input) => {
|
|
1356
|
+
const runMcpSendScript = async (booked, input, signal) => {
|
|
1287
1357
|
const calls = parseMcpSendInput(input);
|
|
1288
1358
|
if (calls === null) return replyText;
|
|
1289
1359
|
const server = builtinMcpServer(booked.mcpServers);
|
|
1290
1360
|
if (server === null) return "mcp-send: no MCP server was handed to this session";
|
|
1291
|
-
return runMcpCalls({ fetch: host.fetch, server, calls });
|
|
1361
|
+
return runMcpCalls({ fetch: host.fetch, server, calls, signal });
|
|
1292
1362
|
};
|
|
1293
1363
|
const runApprovalToolScript = async (threadId, turnId, signal) => {
|
|
1294
1364
|
const isAborted = () => signal?.aborted === true;
|
|
@@ -1470,7 +1540,7 @@ var createFakeInstance = (config, host) => {
|
|
|
1470
1540
|
return;
|
|
1471
1541
|
}
|
|
1472
1542
|
if (script === "mcp-send") {
|
|
1473
|
-
const text = playbookText ?? await runMcpSendScript(booked, input);
|
|
1543
|
+
const text = playbookText ?? await runMcpSendScript(booked, input, signal);
|
|
1474
1544
|
emit("content.delta", threadId, { streamKind: "assistant_text", delta: text }, { turnId });
|
|
1475
1545
|
await yieldTick();
|
|
1476
1546
|
finishTurn(booked, turnId, aborted() ? "interrupted" : "completed", [
|
|
@@ -1552,6 +1622,7 @@ var createFakeInstance = (config, host) => {
|
|
|
1552
1622
|
startSession: async (input, signal) => {
|
|
1553
1623
|
if (disposed) throw new Error("instance disposed");
|
|
1554
1624
|
if (signal?.aborted) throw new Error("aborted");
|
|
1625
|
+
if (threads.get(input.threadId)?.closing !== void 0) throw new Error("session closing");
|
|
1555
1626
|
if (failStartSession !== void 0) throw new Error(failStartSession);
|
|
1556
1627
|
const cwd = input.cwd ?? host.workspacePath(input.threadId);
|
|
1557
1628
|
if (cwd.trim() === "") throw new Error("workspace path missing");
|
|
@@ -1581,6 +1652,7 @@ var createFakeInstance = (config, host) => {
|
|
|
1581
1652
|
sendTurn: async (input, signal) => {
|
|
1582
1653
|
if (disposed) throw new Error("instance disposed");
|
|
1583
1654
|
const booked = requireThread(input.threadId);
|
|
1655
|
+
if (booked.closing !== void 0) throw new Error("session closing");
|
|
1584
1656
|
const running = inflight.get(input.threadId);
|
|
1585
1657
|
const steered = acceptLaneSteer({
|
|
1586
1658
|
running,
|
|
@@ -1611,17 +1683,15 @@ var createFakeInstance = (config, host) => {
|
|
|
1611
1683
|
signal?.removeEventListener("abort", abortTurn);
|
|
1612
1684
|
if (inflight.get(input.threadId)?.turnId === turnId) inflight.delete(input.threadId);
|
|
1613
1685
|
};
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
settle();
|
|
1624
|
-
}
|
|
1686
|
+
const background = script === "approval-tool" || script === "stream" || script === "mcp-send" || script === "visualize" || script === "lane";
|
|
1687
|
+
if (background) signal?.removeEventListener("abort", abortTurn);
|
|
1688
|
+
booked.turnWork = runFakeTurn(
|
|
1689
|
+
run,
|
|
1690
|
+
settle,
|
|
1691
|
+
background ? (error) => failTurn(booked, turnId, error) : void 0
|
|
1692
|
+
);
|
|
1693
|
+
if (!background) await booked.turnWork;
|
|
1694
|
+
return result;
|
|
1625
1695
|
},
|
|
1626
1696
|
interruptTurn: async (threadId, turnId) => {
|
|
1627
1697
|
const running = inflight.get(threadId);
|
|
@@ -1642,9 +1712,8 @@ var createFakeInstance = (config, host) => {
|
|
|
1642
1712
|
host.log.info("respondToUserInput ignored");
|
|
1643
1713
|
},
|
|
1644
1714
|
stopSession: async (threadId) => {
|
|
1645
|
-
|
|
1646
|
-
|
|
1647
|
-
await playbook?.stopSession(threadId);
|
|
1715
|
+
const booked = threads.get(threadId);
|
|
1716
|
+
if (booked !== void 0) await lifecycle.closeBooked(threadId, booked);
|
|
1648
1717
|
},
|
|
1649
1718
|
readThread: async (threadId) => {
|
|
1650
1719
|
const booked = requireThread(threadId);
|
|
@@ -1654,13 +1723,7 @@ var createFakeInstance = (config, host) => {
|
|
|
1654
1723
|
usage: createFakeUsage({ instanceId: host.instanceId, script: parseUsageScript(config) }),
|
|
1655
1724
|
dispose: async () => {
|
|
1656
1725
|
disposed = true;
|
|
1657
|
-
|
|
1658
|
-
inflight.clear();
|
|
1659
|
-
for (const settle of pendingDecisions.values()) settle("cancel");
|
|
1660
|
-
pendingDecisions.clear();
|
|
1661
|
-
threads.clear();
|
|
1662
|
-
await playbook?.dispose();
|
|
1663
|
-
events.close();
|
|
1726
|
+
await lifecycle.dispose();
|
|
1664
1727
|
}
|
|
1665
1728
|
};
|
|
1666
1729
|
return instance;
|
|
@@ -1678,7 +1741,7 @@ var executors = [
|
|
|
1678
1741
|
];
|
|
1679
1742
|
var index_default = definePlugin({
|
|
1680
1743
|
id: "agent-fake",
|
|
1681
|
-
apiVersion:
|
|
1744
|
+
apiVersion: 16,
|
|
1682
1745
|
executors,
|
|
1683
1746
|
activate(ctx) {
|
|
1684
1747
|
ctx.log.info("fake executor ready");
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ycodium-ai/agent-fake",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3168",
|
|
4
4
|
"description": "Minimal fake executor for plugin authors and host orchestration tests.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ycodium",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"@types/node": "24.12.4",
|
|
22
22
|
"esbuild": "0.28.1",
|
|
23
23
|
"vite-plus": "0.2.2",
|
|
24
|
-
"@ycodium-ai/plugin-api": "0.2.
|
|
24
|
+
"@ycodium-ai/plugin-api": "0.2.3168",
|
|
25
25
|
"ycodium-executor-testing": "0.0.0"
|
|
26
26
|
},
|
|
27
27
|
"ycodium": {
|