@ycodium-ai/agent-fake 0.2.2106 → 0.2.2126
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 +151 -6
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -37,10 +37,17 @@ var FAKE_CARD = {
|
|
|
37
37
|
},
|
|
38
38
|
credentialSources: [],
|
|
39
39
|
diagnostics: [],
|
|
40
|
-
configSchema: {
|
|
40
|
+
configSchema: {
|
|
41
|
+
type: "object",
|
|
42
|
+
additionalProperties: false,
|
|
43
|
+
properties: {
|
|
44
|
+
script: { type: "string", enum: ["plain", "approval-tool"] }
|
|
45
|
+
}
|
|
46
|
+
},
|
|
41
47
|
modelConnectivity: {
|
|
42
48
|
dialects: ["openai-chat-completions"],
|
|
43
|
-
|
|
49
|
+
// 假手不 spawn、也不出网,没有「把地址和钥匙注给谁」这回事。
|
|
50
|
+
acceptsExternalEndpoints: false
|
|
44
51
|
}
|
|
45
52
|
};
|
|
46
53
|
|
|
@@ -78,9 +85,16 @@ var EventBus = class {
|
|
|
78
85
|
};
|
|
79
86
|
}
|
|
80
87
|
};
|
|
81
|
-
|
|
88
|
+
function parseScript(input) {
|
|
89
|
+
const envelope = input;
|
|
90
|
+
const script = envelope?.config?.script;
|
|
91
|
+
return script === "approval-tool" ? "approval-tool" : "plain";
|
|
92
|
+
}
|
|
93
|
+
var createFakeInstance = (config, host) => {
|
|
82
94
|
const events = new EventBus();
|
|
83
95
|
const threads = /* @__PURE__ */ new Map();
|
|
96
|
+
const script = parseScript(config);
|
|
97
|
+
const pendingDecisions = /* @__PURE__ */ new Map();
|
|
84
98
|
let seq = 0;
|
|
85
99
|
let inflight = null;
|
|
86
100
|
let disposed = false;
|
|
@@ -95,7 +109,9 @@ var createFakeInstance = (_config, host) => {
|
|
|
95
109
|
createdAt: now(),
|
|
96
110
|
type,
|
|
97
111
|
payload,
|
|
98
|
-
...extra?.turnId === void 0 ? {} : { turnId: extra.turnId }
|
|
112
|
+
...extra?.turnId === void 0 ? {} : { turnId: extra.turnId },
|
|
113
|
+
...extra?.itemId === void 0 ? {} : { itemId: extra.itemId },
|
|
114
|
+
...extra?.requestId === void 0 ? {} : { requestId: extra.requestId }
|
|
99
115
|
});
|
|
100
116
|
};
|
|
101
117
|
const requireThread = (threadId) => {
|
|
@@ -114,6 +130,121 @@ var createFakeInstance = (_config, host) => {
|
|
|
114
130
|
emit("turn.completed", booked.session.threadId, { state }, { turnId });
|
|
115
131
|
inflight = null;
|
|
116
132
|
};
|
|
133
|
+
const runApprovalToolScript = async (threadId, turnId, signal) => {
|
|
134
|
+
const isAborted = () => signal?.aborted === true;
|
|
135
|
+
const fakeReply = "\u597D";
|
|
136
|
+
emit(
|
|
137
|
+
"content.delta",
|
|
138
|
+
threadId,
|
|
139
|
+
{
|
|
140
|
+
streamKind: "reasoning_text",
|
|
141
|
+
delta: "\u5148\u60F3\u6E05\u695A\u6B65\u9AA4\uFF1A\u7B2C\u4E00\u6B65 ls \u5F53\u524D\u76EE\u5F55\uFF1B\u7B2C\u4E8C\u6B65\u8BFB README.md \u7684\u7B2C\u4E00\u884C\uFF1B\u6700\u540E\u53EA\u56DE\u4E00\u4E2A\u5B57\u3002"
|
|
142
|
+
},
|
|
143
|
+
{ turnId }
|
|
144
|
+
);
|
|
145
|
+
await yieldTick();
|
|
146
|
+
if (isAborted()) return null;
|
|
147
|
+
const approve = async (request) => {
|
|
148
|
+
emit(
|
|
149
|
+
"item.started",
|
|
150
|
+
threadId,
|
|
151
|
+
{
|
|
152
|
+
itemType: request.itemType,
|
|
153
|
+
status: "inProgress",
|
|
154
|
+
title: request.title,
|
|
155
|
+
data: request.args
|
|
156
|
+
},
|
|
157
|
+
{ turnId, itemId: request.itemId }
|
|
158
|
+
);
|
|
159
|
+
emit(
|
|
160
|
+
"request.opened",
|
|
161
|
+
threadId,
|
|
162
|
+
{
|
|
163
|
+
requestType: request.requestType,
|
|
164
|
+
toolName: request.toolName,
|
|
165
|
+
detail: request.detail,
|
|
166
|
+
args: request.args
|
|
167
|
+
},
|
|
168
|
+
{ turnId, requestId: request.requestId }
|
|
169
|
+
);
|
|
170
|
+
const decision = await new Promise((resolve) => {
|
|
171
|
+
let settled = false;
|
|
172
|
+
const settle = (value) => {
|
|
173
|
+
if (settled) return;
|
|
174
|
+
settled = true;
|
|
175
|
+
signal?.removeEventListener("abort", onAbort);
|
|
176
|
+
pendingDecisions.delete(request.requestId);
|
|
177
|
+
resolve(value);
|
|
178
|
+
};
|
|
179
|
+
const onAbort = () => settle("cancel");
|
|
180
|
+
signal?.addEventListener("abort", onAbort);
|
|
181
|
+
if (isAborted()) {
|
|
182
|
+
settle("cancel");
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
pendingDecisions.set(request.requestId, settle);
|
|
186
|
+
});
|
|
187
|
+
emit(
|
|
188
|
+
"request.resolved",
|
|
189
|
+
threadId,
|
|
190
|
+
{
|
|
191
|
+
requestType: request.requestType,
|
|
192
|
+
decision: decision === "allow" ? "accept" : decision === "deny" ? "decline" : "cancel"
|
|
193
|
+
},
|
|
194
|
+
{ turnId, requestId: request.requestId }
|
|
195
|
+
);
|
|
196
|
+
if (decision === "allow") {
|
|
197
|
+
emit(
|
|
198
|
+
"content.delta",
|
|
199
|
+
threadId,
|
|
200
|
+
{ streamKind: "command_output", delta: request.output },
|
|
201
|
+
{ turnId, itemId: request.itemId }
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
emit(
|
|
205
|
+
"item.completed",
|
|
206
|
+
threadId,
|
|
207
|
+
{
|
|
208
|
+
itemType: request.itemType,
|
|
209
|
+
status: decision === "allow" ? "completed" : "declined",
|
|
210
|
+
title: request.title,
|
|
211
|
+
data: { ...request.args, ...decision === "allow" ? { output: request.output } : {} }
|
|
212
|
+
},
|
|
213
|
+
{ turnId, itemId: request.itemId }
|
|
214
|
+
);
|
|
215
|
+
return decision;
|
|
216
|
+
};
|
|
217
|
+
const first = await approve({
|
|
218
|
+
itemId: nextId("item"),
|
|
219
|
+
requestId: nextId("req"),
|
|
220
|
+
requestType: "exec_command_approval",
|
|
221
|
+
toolName: "shell",
|
|
222
|
+
detail: "ls",
|
|
223
|
+
args: { command: "ls" },
|
|
224
|
+
itemType: "command_execution",
|
|
225
|
+
title: "ls",
|
|
226
|
+
output: "README.md\n"
|
|
227
|
+
});
|
|
228
|
+
if (first === "cancel") return null;
|
|
229
|
+
if (first === "allow") {
|
|
230
|
+
const second = await approve({
|
|
231
|
+
itemId: nextId("item"),
|
|
232
|
+
requestId: nextId("req"),
|
|
233
|
+
requestType: "file_read_approval",
|
|
234
|
+
toolName: "Read",
|
|
235
|
+
detail: "README.md",
|
|
236
|
+
args: { file_path: "README.md" },
|
|
237
|
+
itemType: "dynamic_tool_call",
|
|
238
|
+
title: "Read README.md",
|
|
239
|
+
output: "# hands-probe-workspace\n"
|
|
240
|
+
});
|
|
241
|
+
if (second === "cancel") return null;
|
|
242
|
+
}
|
|
243
|
+
if (isAborted()) return null;
|
|
244
|
+
emit("content.delta", threadId, { streamKind: "assistant_text", delta: fakeReply }, { turnId });
|
|
245
|
+
await yieldTick();
|
|
246
|
+
return isAborted() ? null : fakeReply;
|
|
247
|
+
};
|
|
117
248
|
const instance = {
|
|
118
249
|
probe: async () => ({
|
|
119
250
|
installed: true,
|
|
@@ -167,6 +298,13 @@ var createFakeInstance = (_config, host) => {
|
|
|
167
298
|
finishTurn(booked, turnId, "interrupted", []);
|
|
168
299
|
return { threadId: input.threadId, turnId };
|
|
169
300
|
}
|
|
301
|
+
if (script === "approval-tool") {
|
|
302
|
+
const finalText = await runApprovalToolScript(input.threadId, turnId, signal);
|
|
303
|
+
finishTurn(booked, turnId, aborted ? "interrupted" : "completed", [
|
|
304
|
+
...finalText === null ? [] : [{ kind: "assistant", text: finalText }]
|
|
305
|
+
]);
|
|
306
|
+
return { threadId: input.threadId, turnId };
|
|
307
|
+
}
|
|
170
308
|
emit(
|
|
171
309
|
"content.delta",
|
|
172
310
|
input.threadId,
|
|
@@ -194,8 +332,13 @@ var createFakeInstance = (_config, host) => {
|
|
|
194
332
|
host.log.info("interrupt turn", { threadId, turnId: inflight.turnId });
|
|
195
333
|
inflight.abort();
|
|
196
334
|
},
|
|
197
|
-
respondToRequest: async () => {
|
|
198
|
-
host.log.info("respondToRequest
|
|
335
|
+
respondToRequest: async (threadId, requestId, decision) => {
|
|
336
|
+
host.log.info("respondToRequest", { threadId, requestId, decision });
|
|
337
|
+
const resolve = pendingDecisions.get(requestId);
|
|
338
|
+
if (resolve !== void 0) {
|
|
339
|
+
pendingDecisions.delete(requestId);
|
|
340
|
+
resolve(decision === "allow" ? "allow" : "deny");
|
|
341
|
+
}
|
|
199
342
|
},
|
|
200
343
|
respondToUserInput: async () => {
|
|
201
344
|
host.log.info("respondToUserInput ignored");
|
|
@@ -213,6 +356,8 @@ var createFakeInstance = (_config, host) => {
|
|
|
213
356
|
disposed = true;
|
|
214
357
|
inflight?.abort();
|
|
215
358
|
inflight = null;
|
|
359
|
+
for (const settle of pendingDecisions.values()) settle("cancel");
|
|
360
|
+
pendingDecisions.clear();
|
|
216
361
|
threads.clear();
|
|
217
362
|
events.close();
|
|
218
363
|
}
|
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.2126",
|
|
4
4
|
"description": "Minimal fake executor for plugin authors and host orchestration tests.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ycodium",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"@types/node": "24.12.4",
|
|
21
21
|
"esbuild": "0.28.1",
|
|
22
22
|
"vite-plus": "0.2.2",
|
|
23
|
-
"@ycodium-ai/plugin-api": "0.2.
|
|
23
|
+
"@ycodium-ai/plugin-api": "0.2.2126"
|
|
24
24
|
},
|
|
25
25
|
"ycodium": {
|
|
26
26
|
"plugin": "./dist/index.js",
|