@ycodium-ai/agent-fake 0.2.2936 → 0.2.2942
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/README.md +1 -1
- package/dist/index.js +106 -3
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@ A minimal executor plugin. It starts no CLI and replays a fixed event script:
|
|
|
4
4
|
|
|
5
5
|
- `startSession` emits `session.started`
|
|
6
6
|
- `sendTurn` emits `turn.started`, one `content.delta`, then `turn.completed` (the host binds the turn by `turn.started`)
|
|
7
|
-
- `config.script` picks the script: `plain` (default), `approval-tool` (two approvals before the reply), `async-question` (on a thread's first turn, the reply plus one non-blocking `user-input.requested` with `responseMode: "message"`), `stream` (a Markdown answer in `config.streamChunks` deltas, default 200, one every `config.streamIntervalMs`, default 30; the UI probe `interaction-table.ts` measures streaming with it),
|
|
7
|
+
- `config.script` picks the script: `plain` (default), `approval-tool` (two approvals before the reply), `async-question` (on a thread's first turn, the reply plus one non-blocking `user-input.requested` with `responseMode: "message"`), `stream` (a Markdown answer in `config.streamChunks` deltas, default 200, one every `config.streamIntervalMs`, default 30; the UI probe `interaction-table.ts` measures streaming with it), `mcp-send` (a turn whose input is a JSON object is passed as the arguments of one real `send_message` call through the built-in MCP server the host handed to `startSession`, the same path a real agent takes; the reply is the tool result, and any other input gets the plain reply), or `visualize` (emits one in-progress builtin tool row, holds for `config.previewHoldMs` milliseconds so the input preview can paint, then one real `visualize_visualize` call on that same server; the tool row’s result is the MCP confirmation text, and the reply is “The figure is in the card above.”)
|
|
8
8
|
- `interruptTurn` (or an aborted `AbortSignal`) ends the in-flight turn as `interrupted`
|
|
9
9
|
- `readThread` returns the bookkeeping the instance recorded
|
|
10
10
|
- `probe` reports two models, `fake` (default) and `fake-large`
|
package/dist/index.js
CHANGED
|
@@ -42,7 +42,7 @@ var FAKE_CARD = {
|
|
|
42
42
|
properties: {
|
|
43
43
|
script: {
|
|
44
44
|
type: "string",
|
|
45
|
-
enum: ["plain", "approval-tool", "async-question", "stream", "mcp-send"]
|
|
45
|
+
enum: ["plain", "approval-tool", "async-question", "stream", "mcp-send", "visualize"]
|
|
46
46
|
},
|
|
47
47
|
streamChunks: { type: "integer", minimum: 1 },
|
|
48
48
|
streamIntervalMs: { type: "integer", minimum: 0 },
|
|
@@ -251,6 +251,88 @@ async function callMcpTool(input) {
|
|
|
251
251
|
return called.message?.result;
|
|
252
252
|
}
|
|
253
253
|
|
|
254
|
+
// src/visualizeScript.ts
|
|
255
|
+
var WIRE_NAME = "mcp__ycodium__visualize_visualize";
|
|
256
|
+
var TITLE = "Monthly sales";
|
|
257
|
+
var FRAGMENT = "<section><h1>Monthly sales</h1><p>Jan 12 \xB7 Feb 18 \xB7 Mar 15</p></section>";
|
|
258
|
+
var REPLY = "The figure is in the card above.";
|
|
259
|
+
function parsePreviewHoldMs(input) {
|
|
260
|
+
const config = input?.config;
|
|
261
|
+
const raw = config?.previewHoldMs;
|
|
262
|
+
if (typeof raw !== "number" || !Number.isFinite(raw) || raw < 0) return 0;
|
|
263
|
+
return Math.min(3e4, Math.floor(raw));
|
|
264
|
+
}
|
|
265
|
+
function confirmationText(result) {
|
|
266
|
+
const content = result?.content;
|
|
267
|
+
if (!Array.isArray(content)) return "";
|
|
268
|
+
const chunks = [];
|
|
269
|
+
for (const entry of content) {
|
|
270
|
+
const text = entry?.text;
|
|
271
|
+
if (typeof text === "string" && text.length > 0) chunks.push(text);
|
|
272
|
+
}
|
|
273
|
+
return chunks.join("\n");
|
|
274
|
+
}
|
|
275
|
+
function hold(ms, signal) {
|
|
276
|
+
if (ms === 0 || signal.aborted) return Promise.resolve();
|
|
277
|
+
return new Promise((resolve) => {
|
|
278
|
+
let timer;
|
|
279
|
+
const finish = () => {
|
|
280
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
281
|
+
signal.removeEventListener("abort", finish);
|
|
282
|
+
resolve();
|
|
283
|
+
};
|
|
284
|
+
timer = setTimeout(finish, ms);
|
|
285
|
+
signal.addEventListener("abort", finish, { once: true });
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
async function runVisualizeTurn(input) {
|
|
289
|
+
const args = JSON.stringify({ action: "create", title: TITLE, fragment: FRAGMENT });
|
|
290
|
+
const tool = (status, result) => ({
|
|
291
|
+
itemType: "dynamic_tool_call",
|
|
292
|
+
status,
|
|
293
|
+
title: WIRE_NAME,
|
|
294
|
+
data: {
|
|
295
|
+
toolName: WIRE_NAME,
|
|
296
|
+
argumentText: args,
|
|
297
|
+
...result === void 0 ? {} : { result }
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
input.emit("item.started", input.threadId, tool("inProgress"), {
|
|
301
|
+
turnId: input.turnId,
|
|
302
|
+
itemId: input.itemId
|
|
303
|
+
});
|
|
304
|
+
await hold(input.holdMs, input.signal);
|
|
305
|
+
if (input.signal.aborted) return null;
|
|
306
|
+
const server = builtinMcpServer(input.mcpServers);
|
|
307
|
+
if (server === null) {
|
|
308
|
+
const failure = "visualize: no MCP server was handed to this session";
|
|
309
|
+
input.emit("item.completed", input.threadId, tool("completed", failure), {
|
|
310
|
+
turnId: input.turnId,
|
|
311
|
+
itemId: input.itemId
|
|
312
|
+
});
|
|
313
|
+
return failure;
|
|
314
|
+
}
|
|
315
|
+
let resultText;
|
|
316
|
+
try {
|
|
317
|
+
resultText = confirmationText(
|
|
318
|
+
await callMcpTool({
|
|
319
|
+
fetch: input.fetch,
|
|
320
|
+
server,
|
|
321
|
+
name: "visualize_visualize",
|
|
322
|
+
arguments: { action: "create", title: TITLE, fragment: FRAGMENT }
|
|
323
|
+
})
|
|
324
|
+
);
|
|
325
|
+
} catch (error) {
|
|
326
|
+
resultText = `visualize failed: ${String(error)}`;
|
|
327
|
+
}
|
|
328
|
+
if (input.signal.aborted) return null;
|
|
329
|
+
input.emit("item.completed", input.threadId, tool("completed", resultText), {
|
|
330
|
+
turnId: input.turnId,
|
|
331
|
+
itemId: input.itemId
|
|
332
|
+
});
|
|
333
|
+
return resultText.length > 0 ? REPLY : "visualize failed: empty tool result";
|
|
334
|
+
}
|
|
335
|
+
|
|
254
336
|
// src/fakeInstance.ts
|
|
255
337
|
var yieldTick = () => Promise.resolve();
|
|
256
338
|
var EventBus = class {
|
|
@@ -309,7 +391,7 @@ var FAKE_ASYNC_QUESTIONS = [
|
|
|
309
391
|
function parseScript(input) {
|
|
310
392
|
const envelope = input;
|
|
311
393
|
const script = envelope?.config?.script;
|
|
312
|
-
return script === "approval-tool" || script === "async-question" || script === "stream" || script === "mcp-send" ? script : "plain";
|
|
394
|
+
return script === "approval-tool" || script === "async-question" || script === "stream" || script === "mcp-send" || script === "visualize" ? script : "plain";
|
|
313
395
|
}
|
|
314
396
|
var FAKE_STREAM_TEXT = [
|
|
315
397
|
"Here is the plan for the change, step by step.\n\n",
|
|
@@ -353,6 +435,7 @@ var createFakeInstance = (config, host) => {
|
|
|
353
435
|
const replyText = parseReplyText(config);
|
|
354
436
|
const failStartSession = parseFailStartSession(config);
|
|
355
437
|
const streamOptions = parseStreamOptions(config);
|
|
438
|
+
const previewHoldMs = parsePreviewHoldMs(config);
|
|
356
439
|
const pendingDecisions = /* @__PURE__ */ new Map();
|
|
357
440
|
let seq = 0;
|
|
358
441
|
const inflight = /* @__PURE__ */ new Map();
|
|
@@ -560,6 +643,26 @@ var createFakeInstance = (config, host) => {
|
|
|
560
643
|
]);
|
|
561
644
|
return;
|
|
562
645
|
}
|
|
646
|
+
if (script === "visualize") {
|
|
647
|
+
const text = await runVisualizeTurn({
|
|
648
|
+
threadId,
|
|
649
|
+
turnId,
|
|
650
|
+
itemId: nextId("item"),
|
|
651
|
+
holdMs: previewHoldMs,
|
|
652
|
+
signal,
|
|
653
|
+
fetch: host.fetch,
|
|
654
|
+
mcpServers: booked.mcpServers,
|
|
655
|
+
emit
|
|
656
|
+
});
|
|
657
|
+
if (text === null || aborted()) {
|
|
658
|
+
finishTurn(booked, turnId, "interrupted", []);
|
|
659
|
+
return;
|
|
660
|
+
}
|
|
661
|
+
emit("content.delta", threadId, { streamKind: "assistant_text", delta: text }, { turnId });
|
|
662
|
+
await yieldTick();
|
|
663
|
+
finishTurn(booked, turnId, "completed", [{ kind: "assistant", text }]);
|
|
664
|
+
return;
|
|
665
|
+
}
|
|
563
666
|
if (script === "mcp-send") {
|
|
564
667
|
const text = await runMcpSendScript(booked, input);
|
|
565
668
|
emit("content.delta", threadId, { streamKind: "assistant_text", delta: text }, { turnId });
|
|
@@ -663,7 +766,7 @@ var createFakeInstance = (config, host) => {
|
|
|
663
766
|
signal?.removeEventListener("abort", abortTurn);
|
|
664
767
|
if (inflight.get(input.threadId)?.turnId === turnId) inflight.delete(input.threadId);
|
|
665
768
|
};
|
|
666
|
-
if (script === "approval-tool" || script === "stream" || script === "mcp-send") {
|
|
769
|
+
if (script === "approval-tool" || script === "stream" || script === "mcp-send" || script === "visualize") {
|
|
667
770
|
signal?.removeEventListener("abort", abortTurn);
|
|
668
771
|
void run().catch((error) => failTurn(booked, turnId, error)).finally(settle);
|
|
669
772
|
return result;
|
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.2942",
|
|
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.2942",
|
|
25
25
|
"ycodium-executor-testing": "0.0.0"
|
|
26
26
|
},
|
|
27
27
|
"ycodium": {
|