@ycodium-ai/agent-fake 0.2.1941
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 +21 -0
- package/assets/icon.svg +4 -0
- package/dist/index.js +243 -0
- package/package.json +41 -0
package/README.md
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# @ycodium-ai/agent-fake
|
|
2
|
+
|
|
3
|
+
A minimal executor plugin. It starts no CLI and replays a fixed event script:
|
|
4
|
+
|
|
5
|
+
- `startSession` emits `session.started`
|
|
6
|
+
- `sendTurn` emits one `content.delta` then `turn.completed`
|
|
7
|
+
- `interruptTurn` (or an aborted `AbortSignal`) ends the in-flight turn as `interrupted`
|
|
8
|
+
- `readThread` returns the bookkeeping the instance recorded
|
|
9
|
+
|
|
10
|
+
Two uses:
|
|
11
|
+
|
|
12
|
+
1. **Template** for an `@ycodium-ai/agent-*` author: one card, `createInstance`, lease-scoped `host.process.spawn` (this fake never calls it), `ctx.log` instead of console.
|
|
13
|
+
2. **Stand-in** for host orchestration tests (W1 reactors / ingestion / TurnIntent). `driverKind` is `fake`.
|
|
14
|
+
|
|
15
|
+
This package is **not** in the default bundle and **not** a first-party add-grid recommended row. Load it only in tests or an explicit patch entry. Manifest permission is `{ kind: "executor" }`.
|
|
16
|
+
|
|
17
|
+
Develop with `vp run --filter @ycodium-ai/agent-fake typecheck`, `build`, and `test`.
|
|
18
|
+
|
|
19
|
+
## License
|
|
20
|
+
|
|
21
|
+
UNLICENSED.
|
package/assets/icon.svg
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import { definePlugin } from "@ycodium-ai/plugin-api";
|
|
3
|
+
|
|
4
|
+
// src/card.ts
|
|
5
|
+
var FAKE_DRIVER_KIND = "fake";
|
|
6
|
+
var FAKE_ASSISTANT_TEXT = "fake turn complete";
|
|
7
|
+
var FAKE_CARD = {
|
|
8
|
+
driverKind: FAKE_DRIVER_KIND,
|
|
9
|
+
displayName: "Fake executor",
|
|
10
|
+
iconUrl: "./assets/icon.svg",
|
|
11
|
+
commandName: "fake",
|
|
12
|
+
launchArgs: "",
|
|
13
|
+
homeEnvVar: "",
|
|
14
|
+
environment: [],
|
|
15
|
+
install: null,
|
|
16
|
+
signIn: [],
|
|
17
|
+
deviceCodeSignInArgs: [],
|
|
18
|
+
npmPackage: "",
|
|
19
|
+
homebrewFormula: "",
|
|
20
|
+
selfUpdateArgs: [],
|
|
21
|
+
docsUrl: "",
|
|
22
|
+
setupNote: "agent-fake.setupNote",
|
|
23
|
+
defaultModel: "fake",
|
|
24
|
+
defaultTextGenerationModel: "fake",
|
|
25
|
+
customModelIdExample: "",
|
|
26
|
+
modelSlugAliases: null,
|
|
27
|
+
modelsDevProviderIds: [],
|
|
28
|
+
modelsDevSlugPrefixed: false,
|
|
29
|
+
modelSlugPrefix: "",
|
|
30
|
+
mcpTransports: null,
|
|
31
|
+
pluginManaged: true,
|
|
32
|
+
verifiedSkills: false,
|
|
33
|
+
everydayHarness: false,
|
|
34
|
+
capabilities: {
|
|
35
|
+
sessionModelSwitch: "unsupported",
|
|
36
|
+
runtimeModeSwitch: "next-turn"
|
|
37
|
+
},
|
|
38
|
+
credentialSources: [],
|
|
39
|
+
diagnostics: [],
|
|
40
|
+
configSchema: { type: "object", additionalProperties: false },
|
|
41
|
+
modelConnectivity: {
|
|
42
|
+
dialects: ["openai-chat-completions"],
|
|
43
|
+
acceptsExternalEndpoints: true
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// src/fakeInstance.ts
|
|
48
|
+
var yieldTick = () => Promise.resolve();
|
|
49
|
+
var EventBus = class {
|
|
50
|
+
#queued = [];
|
|
51
|
+
#waiters = [];
|
|
52
|
+
#closed = false;
|
|
53
|
+
push(event) {
|
|
54
|
+
const waiter = this.#waiters.shift();
|
|
55
|
+
if (waiter) {
|
|
56
|
+
waiter({ done: false, value: event });
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
this.#queued.push(event);
|
|
60
|
+
}
|
|
61
|
+
close() {
|
|
62
|
+
if (this.#closed) return;
|
|
63
|
+
this.#closed = true;
|
|
64
|
+
while (this.#waiters.length > 0) {
|
|
65
|
+
this.#waiters.shift()?.({ done: true, value: void 0 });
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
[Symbol.asyncIterator]() {
|
|
69
|
+
return {
|
|
70
|
+
next: () => {
|
|
71
|
+
const queued = this.#queued.shift();
|
|
72
|
+
if (queued !== void 0) return Promise.resolve({ done: false, value: queued });
|
|
73
|
+
if (this.#closed) return Promise.resolve({ done: true, value: void 0 });
|
|
74
|
+
return new Promise((resolve) => {
|
|
75
|
+
this.#waiters.push(resolve);
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
var createFakeInstance = (_config, host) => {
|
|
82
|
+
const events = new EventBus();
|
|
83
|
+
const threads = /* @__PURE__ */ new Map();
|
|
84
|
+
let seq = 0;
|
|
85
|
+
let inflight = null;
|
|
86
|
+
let disposed = false;
|
|
87
|
+
const nextId = (prefix) => `${prefix}-fake-${++seq}`;
|
|
88
|
+
const now = () => "2026-09-15T00:00:00.000Z";
|
|
89
|
+
const emit = (type, threadId, payload, extra) => {
|
|
90
|
+
events.push({
|
|
91
|
+
eventId: nextId("evt"),
|
|
92
|
+
provider: FAKE_DRIVER_KIND,
|
|
93
|
+
providerInstanceId: host.instanceId,
|
|
94
|
+
threadId,
|
|
95
|
+
createdAt: now(),
|
|
96
|
+
type,
|
|
97
|
+
payload,
|
|
98
|
+
...extra?.turnId === void 0 ? {} : { turnId: extra.turnId }
|
|
99
|
+
});
|
|
100
|
+
};
|
|
101
|
+
const requireThread = (threadId) => {
|
|
102
|
+
const booked = threads.get(threadId);
|
|
103
|
+
if (!booked) throw new Error(`unknown thread ${threadId}`);
|
|
104
|
+
return booked;
|
|
105
|
+
};
|
|
106
|
+
const finishTurn = (booked, turnId, state, items) => {
|
|
107
|
+
booked.turns.push({ id: turnId, items });
|
|
108
|
+
const { activeTurnId: _cleared, ...idle } = booked.session;
|
|
109
|
+
booked.session = {
|
|
110
|
+
...idle,
|
|
111
|
+
status: "idle",
|
|
112
|
+
updatedAt: now()
|
|
113
|
+
};
|
|
114
|
+
emit("turn.completed", booked.session.threadId, { state }, { turnId });
|
|
115
|
+
inflight = null;
|
|
116
|
+
};
|
|
117
|
+
const instance = {
|
|
118
|
+
probe: async () => ({
|
|
119
|
+
installed: true,
|
|
120
|
+
version: "0.0.0-fake",
|
|
121
|
+
readiness: "ready",
|
|
122
|
+
auth: { status: "unknown" }
|
|
123
|
+
}),
|
|
124
|
+
startSession: async (input, signal) => {
|
|
125
|
+
if (disposed) throw new Error("instance disposed");
|
|
126
|
+
if (signal?.aborted) throw new Error("aborted");
|
|
127
|
+
const cwd = input.cwd ?? host.workspacePath(input.threadId);
|
|
128
|
+
if (cwd.trim() === "") throw new Error("workspace path missing");
|
|
129
|
+
const createdAt = now();
|
|
130
|
+
const session = {
|
|
131
|
+
provider: FAKE_DRIVER_KIND,
|
|
132
|
+
providerInstanceId: host.instanceId,
|
|
133
|
+
status: "idle",
|
|
134
|
+
runtimeMode: input.runtimeMode,
|
|
135
|
+
cwd,
|
|
136
|
+
threadId: input.threadId,
|
|
137
|
+
createdAt,
|
|
138
|
+
updatedAt: createdAt,
|
|
139
|
+
...input.discardResumeCursor === true || input.resumeCursor === void 0 ? {} : { resumeCursor: input.resumeCursor },
|
|
140
|
+
...input.bindingGeneration === void 0 ? {} : { bindingGeneration: input.bindingGeneration }
|
|
141
|
+
};
|
|
142
|
+
threads.set(input.threadId, { session, turns: [] });
|
|
143
|
+
emit("session.started", input.threadId, {});
|
|
144
|
+
host.log.info("session started", { threadId: input.threadId });
|
|
145
|
+
return session;
|
|
146
|
+
},
|
|
147
|
+
sendTurn: async (input, signal) => {
|
|
148
|
+
if (disposed) throw new Error("instance disposed");
|
|
149
|
+
const booked = requireThread(input.threadId);
|
|
150
|
+
if (inflight !== null) throw new Error("turn already in flight");
|
|
151
|
+
const turnId = input.expectedTurnId ?? nextId("turn");
|
|
152
|
+
let aborted = signal?.aborted === true;
|
|
153
|
+
const onAbort = () => {
|
|
154
|
+
aborted = true;
|
|
155
|
+
};
|
|
156
|
+
signal?.addEventListener("abort", onAbort);
|
|
157
|
+
inflight = { threadId: input.threadId, turnId, abort: onAbort };
|
|
158
|
+
booked.session = {
|
|
159
|
+
...booked.session,
|
|
160
|
+
status: "running",
|
|
161
|
+
activeTurnId: turnId,
|
|
162
|
+
updatedAt: now()
|
|
163
|
+
};
|
|
164
|
+
try {
|
|
165
|
+
await yieldTick();
|
|
166
|
+
if (aborted) {
|
|
167
|
+
finishTurn(booked, turnId, "interrupted", []);
|
|
168
|
+
return { threadId: input.threadId, turnId };
|
|
169
|
+
}
|
|
170
|
+
emit(
|
|
171
|
+
"content.delta",
|
|
172
|
+
input.threadId,
|
|
173
|
+
{ streamKind: "assistant_text", delta: FAKE_ASSISTANT_TEXT },
|
|
174
|
+
{ turnId }
|
|
175
|
+
);
|
|
176
|
+
await yieldTick();
|
|
177
|
+
if (aborted) {
|
|
178
|
+
finishTurn(booked, turnId, "interrupted", [
|
|
179
|
+
{ kind: "assistant", text: FAKE_ASSISTANT_TEXT }
|
|
180
|
+
]);
|
|
181
|
+
return { threadId: input.threadId, turnId };
|
|
182
|
+
}
|
|
183
|
+
finishTurn(booked, turnId, "completed", [{ kind: "assistant", text: FAKE_ASSISTANT_TEXT }]);
|
|
184
|
+
return { threadId: input.threadId, turnId };
|
|
185
|
+
} finally {
|
|
186
|
+
signal?.removeEventListener("abort", onAbort);
|
|
187
|
+
if (inflight?.turnId === turnId) inflight = null;
|
|
188
|
+
}
|
|
189
|
+
},
|
|
190
|
+
interruptTurn: async (threadId, turnId) => {
|
|
191
|
+
if (inflight === null) return;
|
|
192
|
+
if (inflight.threadId !== threadId) return;
|
|
193
|
+
if (turnId !== void 0 && inflight.turnId !== turnId) return;
|
|
194
|
+
host.log.info("interrupt turn", { threadId, turnId: inflight.turnId });
|
|
195
|
+
inflight.abort();
|
|
196
|
+
},
|
|
197
|
+
respondToRequest: async () => {
|
|
198
|
+
host.log.info("respondToRequest ignored");
|
|
199
|
+
},
|
|
200
|
+
respondToUserInput: async () => {
|
|
201
|
+
host.log.info("respondToUserInput ignored");
|
|
202
|
+
},
|
|
203
|
+
stopSession: async (threadId) => {
|
|
204
|
+
if (inflight?.threadId === threadId) inflight.abort();
|
|
205
|
+
threads.delete(threadId);
|
|
206
|
+
},
|
|
207
|
+
readThread: async (threadId) => {
|
|
208
|
+
const booked = requireThread(threadId);
|
|
209
|
+
return { threadId, turns: booked.turns };
|
|
210
|
+
},
|
|
211
|
+
events,
|
|
212
|
+
dispose: async () => {
|
|
213
|
+
disposed = true;
|
|
214
|
+
inflight?.abort();
|
|
215
|
+
inflight = null;
|
|
216
|
+
threads.clear();
|
|
217
|
+
events.close();
|
|
218
|
+
}
|
|
219
|
+
};
|
|
220
|
+
return instance;
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
// src/index.ts
|
|
224
|
+
var executors = [
|
|
225
|
+
{
|
|
226
|
+
card: FAKE_CARD,
|
|
227
|
+
createInstance: async (config, host) => {
|
|
228
|
+
host.log.info("createInstance");
|
|
229
|
+
return createFakeInstance(config, host);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
];
|
|
233
|
+
var index_default = definePlugin({
|
|
234
|
+
id: "agent-fake",
|
|
235
|
+
apiVersion: 2,
|
|
236
|
+
executors,
|
|
237
|
+
activate(ctx) {
|
|
238
|
+
ctx.log.info("fake executor ready");
|
|
239
|
+
}
|
|
240
|
+
});
|
|
241
|
+
export {
|
|
242
|
+
index_default as default
|
|
243
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@ycodium-ai/agent-fake",
|
|
3
|
+
"version": "0.2.1941",
|
|
4
|
+
"description": "Minimal fake executor for plugin authors and host orchestration tests.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"ycodium",
|
|
7
|
+
"ycodium-plugin"
|
|
8
|
+
],
|
|
9
|
+
"license": "UNLICENSED",
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"assets",
|
|
13
|
+
"README.md"
|
|
14
|
+
],
|
|
15
|
+
"type": "module",
|
|
16
|
+
"publishConfig": {
|
|
17
|
+
"access": "public"
|
|
18
|
+
},
|
|
19
|
+
"devDependencies": {
|
|
20
|
+
"@types/node": "24.12.4",
|
|
21
|
+
"esbuild": "0.28.1",
|
|
22
|
+
"vite-plus": "0.2.2",
|
|
23
|
+
"@ycodium-ai/plugin-api": "0.2.1941"
|
|
24
|
+
},
|
|
25
|
+
"ycodium": {
|
|
26
|
+
"plugin": "./dist/index.js",
|
|
27
|
+
"displayName": "Fake executor",
|
|
28
|
+
"description": "Scripted executor events for templates and host tests. Not a recommended add-grid row.",
|
|
29
|
+
"icon": "./assets/icon.svg",
|
|
30
|
+
"permissions": [
|
|
31
|
+
{
|
|
32
|
+
"kind": "executor"
|
|
33
|
+
}
|
|
34
|
+
]
|
|
35
|
+
},
|
|
36
|
+
"scripts": {
|
|
37
|
+
"build": "node build.mjs",
|
|
38
|
+
"typecheck": "tsgo --noEmit",
|
|
39
|
+
"test": "vp test run"
|
|
40
|
+
}
|
|
41
|
+
}
|