@mindstudio-ai/remy 0.1.35 → 0.1.37
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/headless.js +723 -336
- package/dist/index.js +743 -348
- package/dist/prompt/compiled/media-cdn.md +1 -1
- package/dist/prompt/sources/frontend-design-notes.md +15 -27
- package/dist/prompt/static/team.md +25 -0
- package/dist/subagents/.notes-background-agents.md +36 -64
- package/dist/subagents/designExpert/prompts/images.md +8 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -250,13 +250,38 @@ async function* streamChatWithRetry(params, options) {
|
|
|
250
250
|
return;
|
|
251
251
|
}
|
|
252
252
|
}
|
|
253
|
-
|
|
253
|
+
async function generateBackgroundAck(params) {
|
|
254
|
+
const url = `${params.apiConfig.baseUrl}/_internal/v2/agent/remy/generate-ack`;
|
|
255
|
+
try {
|
|
256
|
+
const res = await fetch(url, {
|
|
257
|
+
method: "POST",
|
|
258
|
+
headers: {
|
|
259
|
+
"Content-Type": "application/json",
|
|
260
|
+
Authorization: `Bearer ${params.apiConfig.apiKey}`
|
|
261
|
+
},
|
|
262
|
+
body: JSON.stringify({
|
|
263
|
+
agentName: params.agentName,
|
|
264
|
+
task: params.task
|
|
265
|
+
}),
|
|
266
|
+
signal: AbortSignal.timeout(2e4)
|
|
267
|
+
});
|
|
268
|
+
if (!res.ok) {
|
|
269
|
+
return FALLBACK_ACK;
|
|
270
|
+
}
|
|
271
|
+
const data = await res.json();
|
|
272
|
+
return data.message || FALLBACK_ACK;
|
|
273
|
+
} catch (err) {
|
|
274
|
+
return FALLBACK_ACK;
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
var MAX_RETRIES, INITIAL_BACKOFF_MS, FALLBACK_ACK;
|
|
254
278
|
var init_api = __esm({
|
|
255
279
|
"src/api.ts"() {
|
|
256
280
|
"use strict";
|
|
257
281
|
init_logger();
|
|
258
282
|
MAX_RETRIES = 3;
|
|
259
283
|
INITIAL_BACKOFF_MS = 1e3;
|
|
284
|
+
FALLBACK_ACK = "[Message sent to agent. Agent is working in the background and will report back with its results when finished.]";
|
|
260
285
|
}
|
|
261
286
|
});
|
|
262
287
|
|
|
@@ -1020,8 +1045,12 @@ function runCli(cmd, options) {
|
|
|
1020
1045
|
const maxBuffer = options?.maxBuffer ?? 1024 * 1024;
|
|
1021
1046
|
const cmdWithLogs = options?.jsonLogs && !cmd.includes("--json-logs") ? cmd.replace(/^(mindstudio\s+\S+)/, "$1 --json-logs") : cmd;
|
|
1022
1047
|
const child = spawn("sh", ["-c", cmdWithLogs], {
|
|
1023
|
-
stdio: ["ignore", "pipe", "pipe"]
|
|
1048
|
+
stdio: [options?.stdin ? "pipe" : "ignore", "pipe", "pipe"]
|
|
1024
1049
|
});
|
|
1050
|
+
if (options?.stdin) {
|
|
1051
|
+
child.stdin.write(options.stdin);
|
|
1052
|
+
child.stdin.end();
|
|
1053
|
+
}
|
|
1025
1054
|
const logs = [];
|
|
1026
1055
|
let stdout = "";
|
|
1027
1056
|
let stderr = "";
|
|
@@ -1201,24 +1230,31 @@ var init_searchGoogle = __esm({
|
|
|
1201
1230
|
}
|
|
1202
1231
|
});
|
|
1203
1232
|
|
|
1204
|
-
// src/tools/common/
|
|
1205
|
-
var
|
|
1206
|
-
var
|
|
1207
|
-
"src/tools/common/
|
|
1233
|
+
// src/tools/common/setProjectMetadata.ts
|
|
1234
|
+
var setProjectMetadataTool;
|
|
1235
|
+
var init_setProjectMetadata = __esm({
|
|
1236
|
+
"src/tools/common/setProjectMetadata.ts"() {
|
|
1208
1237
|
"use strict";
|
|
1209
|
-
|
|
1238
|
+
setProjectMetadataTool = {
|
|
1210
1239
|
definition: {
|
|
1211
|
-
name: "
|
|
1212
|
-
description:
|
|
1240
|
+
name: "setProjectMetadata",
|
|
1241
|
+
description: "Set project metadata. Can update any combination of: display name, app icon, and Open Graph share image. Provide only the fields you want to change.",
|
|
1213
1242
|
inputSchema: {
|
|
1214
1243
|
type: "object",
|
|
1215
1244
|
properties: {
|
|
1216
1245
|
name: {
|
|
1217
1246
|
type: "string",
|
|
1218
|
-
description: "
|
|
1247
|
+
description: "Project display name. Keep it short (2-4 words). Use the app's actual name if the user mentioned one, otherwise pick something descriptive."
|
|
1248
|
+
},
|
|
1249
|
+
iconUrl: {
|
|
1250
|
+
type: "string",
|
|
1251
|
+
description: "URL for the app icon (square."
|
|
1252
|
+
},
|
|
1253
|
+
openGraphShareImageUrl: {
|
|
1254
|
+
type: "string",
|
|
1255
|
+
description: "URL for the Open Graph share image (1200x630)."
|
|
1219
1256
|
}
|
|
1220
|
-
}
|
|
1221
|
-
required: ["name"]
|
|
1257
|
+
}
|
|
1222
1258
|
}
|
|
1223
1259
|
},
|
|
1224
1260
|
async execute() {
|
|
@@ -1972,7 +2008,7 @@ var init_runScenario = __esm({
|
|
|
1972
2008
|
runScenarioTool = {
|
|
1973
2009
|
definition: {
|
|
1974
2010
|
name: "runScenario",
|
|
1975
|
-
description: "Run a scenario to seed the dev database with test data. Truncates all tables first, then executes the seed function and impersonates the scenario roles. Blocks until complete. Scenario IDs are defined in mindstudio.json. If it fails, check .logs/tunnel.log or .logs/requests.ndjson for details.",
|
|
2011
|
+
description: "Run a scenario to seed the dev database with test data. Truncates all tables first, then executes the seed function and impersonates the scenario roles. Blocks until complete. Scenario IDs are defined in mindstudio.json. If it fails, check .logs/tunnel.log or .logs/requests.ndjson for details. Return synchronously - no need to sleep before checking results.",
|
|
1976
2012
|
inputSchema: {
|
|
1977
2013
|
type: "object",
|
|
1978
2014
|
properties: {
|
|
@@ -1999,7 +2035,7 @@ var init_runMethod = __esm({
|
|
|
1999
2035
|
runMethodTool = {
|
|
2000
2036
|
definition: {
|
|
2001
2037
|
name: "runMethod",
|
|
2002
|
-
description: "Run a method in the dev environment and return the result. Use for testing methods after writing or modifying them. Returns output, captured console output, errors with stack traces, and duration. If it fails, check .logs/tunnel.log or .logs/requests.ndjson for more details.",
|
|
2038
|
+
description: "Run a method in the dev environment and return the result. Use for testing methods after writing or modifying them. Returns output, captured console output, errors with stack traces, and duration. If it fails, check .logs/tunnel.log or .logs/requests.ndjson for more details. Return synchronously - no need to sleep before checking results.",
|
|
2003
2039
|
inputSchema: {
|
|
2004
2040
|
type: "object",
|
|
2005
2041
|
properties: {
|
|
@@ -2059,7 +2095,7 @@ var init_screenshot = __esm({
|
|
|
2059
2095
|
init_sidecar();
|
|
2060
2096
|
init_runCli();
|
|
2061
2097
|
init_logger();
|
|
2062
|
-
SCREENSHOT_ANALYSIS_PROMPT = "Describe everything visible on screen from top to bottom \u2014 every element, its position, its size relative to the viewport, its colors, its content. Be thorough and spatial. After the inventory, note anything that looks visually broken (overlapping elements, clipped text, misaligned components).";
|
|
2098
|
+
SCREENSHOT_ANALYSIS_PROMPT = "Describe everything visible on screen from top to bottom \u2014 every element, its position, its size relative to the viewport, its colors, its content. Be comprehensive, thorough, and spatial. After the inventory, note anything that looks visually broken (overlapping elements, clipped text, misaligned components). Respond only with your analysis as Markdown and absolutely no other text. Do not use emojis - use unicode if you need symbols.";
|
|
2063
2099
|
}
|
|
2064
2100
|
});
|
|
2065
2101
|
|
|
@@ -2097,9 +2133,100 @@ var init_screenshot2 = __esm({
|
|
|
2097
2133
|
}
|
|
2098
2134
|
});
|
|
2099
2135
|
|
|
2136
|
+
// src/statusWatcher.ts
|
|
2137
|
+
function startStatusWatcher(config) {
|
|
2138
|
+
const { apiConfig, getContext, onStatus, interval = 3e3, signal } = config;
|
|
2139
|
+
let lastLabel = "";
|
|
2140
|
+
let inflight = false;
|
|
2141
|
+
let stopped = false;
|
|
2142
|
+
const url = `${apiConfig.baseUrl}/_internal/v2/agent/remy/generate-status`;
|
|
2143
|
+
async function tick() {
|
|
2144
|
+
if (stopped || signal?.aborted || inflight) {
|
|
2145
|
+
return;
|
|
2146
|
+
}
|
|
2147
|
+
inflight = true;
|
|
2148
|
+
try {
|
|
2149
|
+
const ctx = getContext();
|
|
2150
|
+
if (!ctx.assistantText && !ctx.lastToolName) {
|
|
2151
|
+
log.debug("Status watcher: no context, skipping");
|
|
2152
|
+
return;
|
|
2153
|
+
}
|
|
2154
|
+
log.debug("Status watcher: requesting label", {
|
|
2155
|
+
textLength: ctx.assistantText.length,
|
|
2156
|
+
lastToolName: ctx.lastToolName
|
|
2157
|
+
});
|
|
2158
|
+
const res = await fetch(url, {
|
|
2159
|
+
method: "POST",
|
|
2160
|
+
headers: {
|
|
2161
|
+
"Content-Type": "application/json",
|
|
2162
|
+
Authorization: `Bearer ${apiConfig.apiKey}`
|
|
2163
|
+
},
|
|
2164
|
+
body: JSON.stringify({
|
|
2165
|
+
assistantText: ctx.assistantText.slice(-500),
|
|
2166
|
+
lastToolName: ctx.lastToolName,
|
|
2167
|
+
lastToolResult: ctx.lastToolResult?.slice(-200),
|
|
2168
|
+
onboardingState: ctx.onboardingState,
|
|
2169
|
+
userMessage: ctx.userMessage?.slice(-200)
|
|
2170
|
+
}),
|
|
2171
|
+
signal
|
|
2172
|
+
});
|
|
2173
|
+
if (!res.ok) {
|
|
2174
|
+
log.debug("Status watcher: endpoint returned non-ok", {
|
|
2175
|
+
status: res.status
|
|
2176
|
+
});
|
|
2177
|
+
return;
|
|
2178
|
+
}
|
|
2179
|
+
const data = await res.json();
|
|
2180
|
+
if (!data.label) {
|
|
2181
|
+
log.debug("Status watcher: no label in response");
|
|
2182
|
+
return;
|
|
2183
|
+
}
|
|
2184
|
+
if (data.label === lastLabel) {
|
|
2185
|
+
log.debug("Status watcher: duplicate label, skipping", {
|
|
2186
|
+
label: data.label
|
|
2187
|
+
});
|
|
2188
|
+
return;
|
|
2189
|
+
}
|
|
2190
|
+
lastLabel = data.label;
|
|
2191
|
+
if (stopped) {
|
|
2192
|
+
return;
|
|
2193
|
+
}
|
|
2194
|
+
log.debug("Status watcher: emitting", { label: data.label });
|
|
2195
|
+
onStatus(data.label);
|
|
2196
|
+
} catch (err) {
|
|
2197
|
+
log.debug("Status watcher: error", { error: err?.message ?? "unknown" });
|
|
2198
|
+
} finally {
|
|
2199
|
+
inflight = false;
|
|
2200
|
+
}
|
|
2201
|
+
}
|
|
2202
|
+
const timer = setInterval(tick, interval);
|
|
2203
|
+
tick().catch(() => {
|
|
2204
|
+
});
|
|
2205
|
+
log.debug("Status watcher started", { interval });
|
|
2206
|
+
return {
|
|
2207
|
+
stop() {
|
|
2208
|
+
stopped = true;
|
|
2209
|
+
clearInterval(timer);
|
|
2210
|
+
log.debug("Status watcher stopped");
|
|
2211
|
+
}
|
|
2212
|
+
};
|
|
2213
|
+
}
|
|
2214
|
+
var init_statusWatcher = __esm({
|
|
2215
|
+
"src/statusWatcher.ts"() {
|
|
2216
|
+
"use strict";
|
|
2217
|
+
init_logger();
|
|
2218
|
+
}
|
|
2219
|
+
});
|
|
2220
|
+
|
|
2100
2221
|
// src/subagents/common/cleanMessages.ts
|
|
2101
2222
|
function cleanMessagesForApi(messages) {
|
|
2102
2223
|
return messages.map((msg) => {
|
|
2224
|
+
if (msg.role === "user" && typeof msg.content === "string" && msg.content.startsWith("@@automated::")) {
|
|
2225
|
+
return {
|
|
2226
|
+
...msg,
|
|
2227
|
+
content: msg.content.replace(/^@@automated::[^@]*@@\n?/, "")
|
|
2228
|
+
};
|
|
2229
|
+
}
|
|
2103
2230
|
if (!Array.isArray(msg.content)) {
|
|
2104
2231
|
return msg;
|
|
2105
2232
|
}
|
|
@@ -2142,177 +2269,271 @@ async function runSubAgent(config) {
|
|
|
2142
2269
|
apiConfig,
|
|
2143
2270
|
model,
|
|
2144
2271
|
subAgentId,
|
|
2145
|
-
signal,
|
|
2272
|
+
signal: parentSignal,
|
|
2146
2273
|
parentToolId,
|
|
2147
2274
|
onEvent,
|
|
2148
|
-
resolveExternalTool
|
|
2275
|
+
resolveExternalTool,
|
|
2276
|
+
toolRegistry,
|
|
2277
|
+
background,
|
|
2278
|
+
onBackgroundComplete
|
|
2149
2279
|
} = config;
|
|
2280
|
+
const bgAbort = background ? new AbortController() : null;
|
|
2281
|
+
const signal = background ? bgAbort.signal : parentSignal;
|
|
2150
2282
|
const emit2 = (e) => {
|
|
2151
2283
|
onEvent({ ...e, parentToolId });
|
|
2152
2284
|
};
|
|
2153
|
-
const
|
|
2154
|
-
|
|
2155
|
-
|
|
2285
|
+
const run = async () => {
|
|
2286
|
+
const messages = [{ role: "user", content: task }];
|
|
2287
|
+
function getPartialText(blocks) {
|
|
2288
|
+
return blocks.filter((b) => b.type === "text").map((b) => b.text).join("");
|
|
2289
|
+
}
|
|
2290
|
+
function abortResult(blocks) {
|
|
2291
|
+
if (signal?.reason === "graceful") {
|
|
2292
|
+
const partial = getPartialText(blocks);
|
|
2293
|
+
return {
|
|
2294
|
+
text: partial ? `[INTERRUPTED - PARTIAL OUTPUT RETRIEVED] Note that partial output may include thinking text or other unfinalized decisions. It is NOT an authoritative response from this agent.
|
|
2295
|
+
|
|
2296
|
+
${partial}` : "[INTERRUPTED] Agent was interrupted before producing output.",
|
|
2297
|
+
messages
|
|
2298
|
+
};
|
|
2299
|
+
}
|
|
2156
2300
|
return { text: "Error: cancelled", messages };
|
|
2157
2301
|
}
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2302
|
+
let lastToolResult = "";
|
|
2303
|
+
while (true) {
|
|
2304
|
+
if (signal?.aborted) {
|
|
2305
|
+
return abortResult([]);
|
|
2306
|
+
}
|
|
2307
|
+
const contentBlocks = [];
|
|
2308
|
+
let thinkingStartedAt = 0;
|
|
2309
|
+
let stopReason = "end_turn";
|
|
2310
|
+
let currentToolNames = "";
|
|
2311
|
+
const statusWatcher = startStatusWatcher({
|
|
2312
|
+
apiConfig,
|
|
2313
|
+
getContext: () => ({
|
|
2314
|
+
assistantText: getPartialText(contentBlocks),
|
|
2315
|
+
lastToolName: currentToolNames || void 0,
|
|
2316
|
+
lastToolResult: lastToolResult || void 0
|
|
2317
|
+
}),
|
|
2318
|
+
onStatus: (label) => emit2({ type: "status", message: label }),
|
|
2319
|
+
signal
|
|
2320
|
+
});
|
|
2321
|
+
const fullSystem = `${system}
|
|
2162
2322
|
|
|
2163
2323
|
Current date/time: ${(/* @__PURE__ */ new Date()).toISOString().replace("T", " ").replace(/\.\d+Z$/, " UTC")}`;
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2181
|
-
|
|
2182
|
-
|
|
2183
|
-
contentBlocks.push({
|
|
2184
|
-
type: "text",
|
|
2185
|
-
text: event.text,
|
|
2186
|
-
startedAt: event.ts
|
|
2187
|
-
});
|
|
2188
|
-
}
|
|
2189
|
-
emit2({ type: "text", text: event.text });
|
|
2324
|
+
try {
|
|
2325
|
+
for await (const event of streamChatWithRetry(
|
|
2326
|
+
{
|
|
2327
|
+
...apiConfig,
|
|
2328
|
+
model,
|
|
2329
|
+
subAgentId,
|
|
2330
|
+
system: fullSystem,
|
|
2331
|
+
messages: cleanMessagesForApi(messages),
|
|
2332
|
+
tools: tools2,
|
|
2333
|
+
signal
|
|
2334
|
+
},
|
|
2335
|
+
{
|
|
2336
|
+
onRetry: (attempt) => emit2({
|
|
2337
|
+
type: "status",
|
|
2338
|
+
message: `Lost connection, retrying (attempt ${attempt + 2} of 3)...`
|
|
2339
|
+
})
|
|
2340
|
+
}
|
|
2341
|
+
)) {
|
|
2342
|
+
if (signal?.aborted) {
|
|
2190
2343
|
break;
|
|
2191
2344
|
}
|
|
2192
|
-
|
|
2193
|
-
|
|
2194
|
-
|
|
2345
|
+
switch (event.type) {
|
|
2346
|
+
case "text": {
|
|
2347
|
+
const lastBlock = contentBlocks.at(-1);
|
|
2348
|
+
if (lastBlock?.type === "text") {
|
|
2349
|
+
lastBlock.text += event.text;
|
|
2350
|
+
} else {
|
|
2351
|
+
contentBlocks.push({
|
|
2352
|
+
type: "text",
|
|
2353
|
+
text: event.text,
|
|
2354
|
+
startedAt: event.ts
|
|
2355
|
+
});
|
|
2356
|
+
}
|
|
2357
|
+
emit2({ type: "text", text: event.text });
|
|
2358
|
+
break;
|
|
2195
2359
|
}
|
|
2196
|
-
|
|
2197
|
-
|
|
2198
|
-
|
|
2199
|
-
|
|
2200
|
-
type: "thinking",
|
|
2201
|
-
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2214
|
-
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2360
|
+
case "thinking":
|
|
2361
|
+
if (!thinkingStartedAt) {
|
|
2362
|
+
thinkingStartedAt = event.ts;
|
|
2363
|
+
}
|
|
2364
|
+
emit2({ type: "thinking", text: event.text });
|
|
2365
|
+
break;
|
|
2366
|
+
case "thinking_complete":
|
|
2367
|
+
contentBlocks.push({
|
|
2368
|
+
type: "thinking",
|
|
2369
|
+
thinking: event.thinking,
|
|
2370
|
+
signature: event.signature,
|
|
2371
|
+
startedAt: thinkingStartedAt,
|
|
2372
|
+
completedAt: event.ts
|
|
2373
|
+
});
|
|
2374
|
+
thinkingStartedAt = 0;
|
|
2375
|
+
break;
|
|
2376
|
+
case "tool_use":
|
|
2377
|
+
contentBlocks.push({
|
|
2378
|
+
type: "tool",
|
|
2379
|
+
id: event.id,
|
|
2380
|
+
name: event.name,
|
|
2381
|
+
input: event.input,
|
|
2382
|
+
startedAt: Date.now()
|
|
2383
|
+
});
|
|
2384
|
+
emit2({
|
|
2385
|
+
type: "tool_start",
|
|
2386
|
+
id: event.id,
|
|
2387
|
+
name: event.name,
|
|
2388
|
+
input: event.input
|
|
2389
|
+
});
|
|
2390
|
+
break;
|
|
2391
|
+
case "done":
|
|
2392
|
+
stopReason = event.stopReason;
|
|
2393
|
+
break;
|
|
2394
|
+
case "error":
|
|
2395
|
+
return { text: `Error: ${event.error}`, messages };
|
|
2396
|
+
}
|
|
2397
|
+
}
|
|
2398
|
+
} catch (err) {
|
|
2399
|
+
if (!signal?.aborted) {
|
|
2400
|
+
throw err;
|
|
2228
2401
|
}
|
|
2229
2402
|
}
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2403
|
+
if (signal?.aborted) {
|
|
2404
|
+
statusWatcher.stop();
|
|
2405
|
+
return abortResult(contentBlocks);
|
|
2233
2406
|
}
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
if (signal?.aborted) {
|
|
2257
|
-
return { id: tc.id, result: "Error: cancelled", isError: true };
|
|
2258
|
-
}
|
|
2259
|
-
try {
|
|
2260
|
-
let result;
|
|
2261
|
-
if (externalTools.has(tc.name) && resolveExternalTool) {
|
|
2262
|
-
result = await resolveExternalTool(tc.id, tc.name, tc.input);
|
|
2263
|
-
} else {
|
|
2264
|
-
const onLog = (line) => emit2({
|
|
2265
|
-
type: "tool_input_delta",
|
|
2266
|
-
id: tc.id,
|
|
2267
|
-
name: tc.name,
|
|
2268
|
-
result: line
|
|
2269
|
-
});
|
|
2270
|
-
result = await executeTool2(tc.name, tc.input, tc.id, onLog);
|
|
2407
|
+
messages.push({
|
|
2408
|
+
role: "assistant",
|
|
2409
|
+
content: contentBlocks
|
|
2410
|
+
});
|
|
2411
|
+
const toolCalls = contentBlocks.filter(
|
|
2412
|
+
(b) => b.type === "tool"
|
|
2413
|
+
);
|
|
2414
|
+
if (stopReason !== "tool_use" || toolCalls.length === 0) {
|
|
2415
|
+
statusWatcher.stop();
|
|
2416
|
+
const text = getPartialText(contentBlocks);
|
|
2417
|
+
return { text, messages };
|
|
2418
|
+
}
|
|
2419
|
+
log.info("Sub-agent executing tools", {
|
|
2420
|
+
parentToolId,
|
|
2421
|
+
count: toolCalls.length,
|
|
2422
|
+
tools: toolCalls.map((tc) => tc.name)
|
|
2423
|
+
});
|
|
2424
|
+
currentToolNames = toolCalls.map((tc) => tc.name).join(", ");
|
|
2425
|
+
const results = await Promise.all(
|
|
2426
|
+
toolCalls.map(async (tc) => {
|
|
2427
|
+
if (signal?.aborted) {
|
|
2428
|
+
return { id: tc.id, result: "Error: cancelled", isError: true };
|
|
2271
2429
|
}
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
2430
|
+
let settle;
|
|
2431
|
+
const resultPromise = new Promise((res) => {
|
|
2432
|
+
settle = (result, isError) => res({ id: tc.id, result, isError });
|
|
2433
|
+
});
|
|
2434
|
+
let toolAbort = new AbortController();
|
|
2435
|
+
const cascadeAbort = () => toolAbort.abort();
|
|
2436
|
+
signal?.addEventListener("abort", cascadeAbort, { once: true });
|
|
2437
|
+
let settled = false;
|
|
2438
|
+
const safeSettle = (result, isError) => {
|
|
2439
|
+
if (settled) {
|
|
2440
|
+
return;
|
|
2441
|
+
}
|
|
2442
|
+
settled = true;
|
|
2443
|
+
signal?.removeEventListener("abort", cascadeAbort);
|
|
2444
|
+
settle(result, isError);
|
|
2445
|
+
};
|
|
2446
|
+
const run2 = async (input) => {
|
|
2447
|
+
try {
|
|
2448
|
+
let result;
|
|
2449
|
+
if (externalTools.has(tc.name) && resolveExternalTool) {
|
|
2450
|
+
result = await resolveExternalTool(tc.id, tc.name, input);
|
|
2451
|
+
} else {
|
|
2452
|
+
const onLog = (line) => emit2({
|
|
2453
|
+
type: "tool_input_delta",
|
|
2454
|
+
id: tc.id,
|
|
2455
|
+
name: tc.name,
|
|
2456
|
+
result: line
|
|
2457
|
+
});
|
|
2458
|
+
result = await executeTool2(tc.name, input, tc.id, onLog);
|
|
2459
|
+
}
|
|
2460
|
+
safeSettle(result, result.startsWith("Error"));
|
|
2461
|
+
} catch (err) {
|
|
2462
|
+
safeSettle(`Error: ${err.message}`, true);
|
|
2463
|
+
}
|
|
2464
|
+
};
|
|
2465
|
+
const entry = {
|
|
2275
2466
|
id: tc.id,
|
|
2276
2467
|
name: tc.name,
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2468
|
+
input: tc.input,
|
|
2469
|
+
parentToolId,
|
|
2470
|
+
abortController: toolAbort,
|
|
2471
|
+
startedAt: Date.now(),
|
|
2472
|
+
settle: safeSettle,
|
|
2473
|
+
rerun: (newInput) => {
|
|
2474
|
+
settled = false;
|
|
2475
|
+
toolAbort = new AbortController();
|
|
2476
|
+
signal?.addEventListener("abort", () => toolAbort.abort(), {
|
|
2477
|
+
once: true
|
|
2478
|
+
});
|
|
2479
|
+
entry.abortController = toolAbort;
|
|
2480
|
+
entry.input = newInput;
|
|
2481
|
+
run2(newInput);
|
|
2482
|
+
}
|
|
2483
|
+
};
|
|
2484
|
+
toolRegistry?.register(entry);
|
|
2485
|
+
run2(tc.input);
|
|
2486
|
+
const r = await resultPromise;
|
|
2487
|
+
toolRegistry?.unregister(tc.id);
|
|
2283
2488
|
emit2({
|
|
2284
2489
|
type: "tool_done",
|
|
2285
2490
|
id: tc.id,
|
|
2286
2491
|
name: tc.name,
|
|
2287
|
-
result:
|
|
2288
|
-
isError:
|
|
2492
|
+
result: r.result,
|
|
2493
|
+
isError: r.isError
|
|
2289
2494
|
});
|
|
2290
|
-
return
|
|
2291
|
-
}
|
|
2292
|
-
})
|
|
2293
|
-
);
|
|
2294
|
-
for (const r of results) {
|
|
2295
|
-
const block = contentBlocks.find(
|
|
2296
|
-
(b) => b.type === "tool" && b.id === r.id
|
|
2495
|
+
return r;
|
|
2496
|
+
})
|
|
2297
2497
|
);
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2498
|
+
statusWatcher.stop();
|
|
2499
|
+
lastToolResult = results.at(-1)?.result ?? "";
|
|
2500
|
+
for (const r of results) {
|
|
2501
|
+
const block = contentBlocks.find(
|
|
2502
|
+
(b) => b.type === "tool" && b.id === r.id
|
|
2503
|
+
);
|
|
2504
|
+
if (block?.type === "tool") {
|
|
2505
|
+
block.result = r.result;
|
|
2506
|
+
block.isError = r.isError;
|
|
2507
|
+
block.completedAt = Date.now();
|
|
2508
|
+
}
|
|
2509
|
+
messages.push({
|
|
2510
|
+
role: "user",
|
|
2511
|
+
content: r.result,
|
|
2512
|
+
toolCallId: r.id,
|
|
2513
|
+
isToolError: r.isError
|
|
2514
|
+
});
|
|
2515
|
+
}
|
|
2308
2516
|
}
|
|
2517
|
+
};
|
|
2518
|
+
if (!background) {
|
|
2519
|
+
return run();
|
|
2309
2520
|
}
|
|
2521
|
+
const ack = await generateBackgroundAck({
|
|
2522
|
+
apiConfig,
|
|
2523
|
+
agentName: subAgentId || "agent",
|
|
2524
|
+
task
|
|
2525
|
+
});
|
|
2526
|
+
run().then((finalResult) => onBackgroundComplete?.(finalResult)).catch(
|
|
2527
|
+
(err) => onBackgroundComplete?.({ text: `Error: ${err.message}`, messages: [] })
|
|
2528
|
+
);
|
|
2529
|
+
return { text: ack, messages: [], backgrounded: true };
|
|
2310
2530
|
}
|
|
2311
2531
|
var init_runner = __esm({
|
|
2312
2532
|
"src/subagents/runner.ts"() {
|
|
2313
2533
|
"use strict";
|
|
2314
2534
|
init_api();
|
|
2315
2535
|
init_logger();
|
|
2536
|
+
init_statusWatcher();
|
|
2316
2537
|
init_cleanMessages();
|
|
2317
2538
|
}
|
|
2318
2539
|
});
|
|
@@ -2604,7 +2825,8 @@ var init_browserAutomation = __esm({
|
|
|
2604
2825
|
}
|
|
2605
2826
|
}
|
|
2606
2827
|
return result2;
|
|
2607
|
-
}
|
|
2828
|
+
},
|
|
2829
|
+
toolRegistry: context.toolRegistry
|
|
2608
2830
|
});
|
|
2609
2831
|
context.subAgentMessages?.set(context.toolCallId, result.messages);
|
|
2610
2832
|
return result.text;
|
|
@@ -2710,9 +2932,7 @@ async function execute3(input, onLog) {
|
|
|
2710
2932
|
`mindstudio analyze-image --prompt ${JSON.stringify(analysisPrompt)} --image-url ${JSON.stringify(imageUrl)} --output-key analysis --no-meta`,
|
|
2711
2933
|
{ timeout: 2e5, onLog }
|
|
2712
2934
|
);
|
|
2713
|
-
return
|
|
2714
|
-
|
|
2715
|
-
${analysis}`;
|
|
2935
|
+
return JSON.stringify({ url: imageUrl, analysis });
|
|
2716
2936
|
}
|
|
2717
2937
|
var DESIGN_REFERENCE_PROMPT, definition3;
|
|
2718
2938
|
var init_analyzeDesign = __esm({
|
|
@@ -2738,7 +2958,7 @@ Brief description of the types used on the page. If you can identify the actual
|
|
|
2738
2958
|
## Techniques
|
|
2739
2959
|
Identify the specific design moves that make this page interesting and unique, described in terms of how a designer with a technical background would write them down as notes in their notebook for inspiration. Focus only on the non-obvious, hard-to-think-of techniques \u2014 the things that make this page gallery-worthy. Skip basics like "high contrast CTA" or "generous whitespace" that any competent designer already knows.
|
|
2740
2960
|
|
|
2741
|
-
Respond only with
|
|
2961
|
+
Respond only with your analysis as Markdown and absolutely no other text. Do not use emojis - use unicode if you need symbols.
|
|
2742
2962
|
`;
|
|
2743
2963
|
definition3 = {
|
|
2744
2964
|
name: "analyzeDesign",
|
|
@@ -2781,10 +3001,10 @@ var init_analyzeImage = __esm({
|
|
|
2781
3001
|
"src/subagents/designExpert/tools/analyzeImage.ts"() {
|
|
2782
3002
|
"use strict";
|
|
2783
3003
|
init_runCli();
|
|
2784
|
-
DEFAULT_PROMPT = "Describe everything visible in this image \u2014 every element, its position, its size relative to the frame, its colors, its content. Be thorough and spatial. After the inventory, note anything that looks visually broken (overlapping elements, clipped text, misaligned components).";
|
|
3004
|
+
DEFAULT_PROMPT = "Describe everything visible in this image \u2014 every element, its position, its size relative to the frame, its colors, its content. Be comprhensive, thorough and spatial. After the inventory, note anything that looks visually broken (overlapping elements, clipped text, misaligned components). Respond only with your analysis as Markdown and absolutely no other text. Do not use emojis - use unicode if you need symbols.";
|
|
2785
3005
|
definition4 = {
|
|
2786
3006
|
name: "analyzeImage",
|
|
2787
|
-
description: "Analyze an image by URL. Returns
|
|
3007
|
+
description: "Analyze an image by URL using a vision model. Returns an objective description of what is visible \u2014 shapes, colors, layout, text, artifacts. Use for factual inventory of image contents, not for subjective design judgment - the vision model providing the analysis has no sense of design. You are the design expert - use the analysis tool for factual inventory, then apply your own expertise for quality and suitability assessments.",
|
|
2788
3008
|
inputSchema: {
|
|
2789
3009
|
type: "object",
|
|
2790
3010
|
properties: {
|
|
@@ -2874,13 +3094,15 @@ async function seedreamGenerate(opts) {
|
|
|
2874
3094
|
}
|
|
2875
3095
|
}
|
|
2876
3096
|
}));
|
|
2877
|
-
const batchResult = await runCli(
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
3097
|
+
const batchResult = await runCli(`mindstudio batch --no-meta`, {
|
|
3098
|
+
jsonLogs: true,
|
|
3099
|
+
timeout: 2e5,
|
|
3100
|
+
onLog,
|
|
3101
|
+
stdin: JSON.stringify(steps)
|
|
3102
|
+
});
|
|
2881
3103
|
try {
|
|
2882
3104
|
const parsed = JSON.parse(batchResult);
|
|
2883
|
-
imageUrls = parsed.
|
|
3105
|
+
imageUrls = parsed.map(
|
|
2884
3106
|
(r) => r.output?.imageUrl ?? `Error: ${r.error}`
|
|
2885
3107
|
);
|
|
2886
3108
|
} catch {
|
|
@@ -2920,7 +3142,7 @@ var init_seedream = __esm({
|
|
|
2920
3142
|
"src/subagents/designExpert/tools/_seedream.ts"() {
|
|
2921
3143
|
"use strict";
|
|
2922
3144
|
init_runCli();
|
|
2923
|
-
ANALYZE_PROMPT = "You are reviewing this image for a visual designer sourcing assets for a project. Describe: what the image depicts, the mood and color palette, how the lighting and composition work, whether there are any issues (unwanted text, artifacts, distortions), and how it could be used in a layout (hero background, feature section, card texture, etc). Be concise and practical.";
|
|
3145
|
+
ANALYZE_PROMPT = "You are reviewing this image for a visual designer sourcing assets for a project. Describe: what the image depicts, the mood and color palette, how the lighting and composition work, whether there are any issues (unwanted text, artifacts, distortions), and how it could be used in a layout (hero background, feature section, card texture, etc). Be concise and practical. Respond only with your analysis as Markdown and absolutely no other text. Do not use emojis - use unicode if you need symbols.";
|
|
2924
3146
|
}
|
|
2925
3147
|
});
|
|
2926
3148
|
|
|
@@ -3324,6 +3546,10 @@ Visual design expert. Describe the situation and what you need \u2014 the agent
|
|
|
3324
3546
|
task: {
|
|
3325
3547
|
type: "string",
|
|
3326
3548
|
description: "What you need, in natural language. Include context about the project when relevant."
|
|
3549
|
+
},
|
|
3550
|
+
background: {
|
|
3551
|
+
type: "boolean",
|
|
3552
|
+
description: "Run in background \u2014 returns immediately and doesn't block while continuing to do work in the background. Reports results when finished working."
|
|
3327
3553
|
}
|
|
3328
3554
|
},
|
|
3329
3555
|
required: ["task"]
|
|
@@ -3345,7 +3571,17 @@ Visual design expert. Describe the situation and what you need \u2014 the agent
|
|
|
3345
3571
|
signal: context.signal,
|
|
3346
3572
|
parentToolId: context.toolCallId,
|
|
3347
3573
|
onEvent: context.onEvent,
|
|
3348
|
-
resolveExternalTool: context.resolveExternalTool
|
|
3574
|
+
resolveExternalTool: context.resolveExternalTool,
|
|
3575
|
+
toolRegistry: context.toolRegistry,
|
|
3576
|
+
background: input.background,
|
|
3577
|
+
onBackgroundComplete: input.background ? (bgResult) => {
|
|
3578
|
+
context.onBackgroundComplete?.(
|
|
3579
|
+
context.toolCallId,
|
|
3580
|
+
"visualDesignExpert",
|
|
3581
|
+
bgResult.text,
|
|
3582
|
+
bgResult.messages
|
|
3583
|
+
);
|
|
3584
|
+
} : void 0
|
|
3349
3585
|
});
|
|
3350
3586
|
context.subAgentMessages?.set(context.toolCallId, result.messages);
|
|
3351
3587
|
return result.text;
|
|
@@ -3639,6 +3875,10 @@ var init_productVision = __esm({
|
|
|
3639
3875
|
task: {
|
|
3640
3876
|
type: "string",
|
|
3641
3877
|
description: "Brief description of what happened or what is needed. Do not specify how many items to create, what topics to cover, or how to think. The agent reads the spec files and decides for itself."
|
|
3878
|
+
},
|
|
3879
|
+
background: {
|
|
3880
|
+
type: "boolean",
|
|
3881
|
+
description: "Run in background \u2014 returns immediately and doesn't block while continuing to do work in the background. Reports results when finished working."
|
|
3642
3882
|
}
|
|
3643
3883
|
},
|
|
3644
3884
|
required: ["task"]
|
|
@@ -3660,7 +3900,17 @@ var init_productVision = __esm({
|
|
|
3660
3900
|
signal: context.signal,
|
|
3661
3901
|
parentToolId: context.toolCallId,
|
|
3662
3902
|
onEvent: context.onEvent,
|
|
3663
|
-
resolveExternalTool: context.resolveExternalTool
|
|
3903
|
+
resolveExternalTool: context.resolveExternalTool,
|
|
3904
|
+
toolRegistry: context.toolRegistry,
|
|
3905
|
+
background: input.background,
|
|
3906
|
+
onBackgroundComplete: input.background ? (bgResult) => {
|
|
3907
|
+
context.onBackgroundComplete?.(
|
|
3908
|
+
context.toolCallId,
|
|
3909
|
+
"productVision",
|
|
3910
|
+
bgResult.text,
|
|
3911
|
+
bgResult.messages
|
|
3912
|
+
);
|
|
3913
|
+
} : void 0
|
|
3664
3914
|
});
|
|
3665
3915
|
context.subAgentMessages?.set(context.toolCallId, result.messages);
|
|
3666
3916
|
return result.text;
|
|
@@ -3814,7 +4064,8 @@ var init_codeSanityCheck = __esm({
|
|
|
3814
4064
|
signal: context.signal,
|
|
3815
4065
|
parentToolId: context.toolCallId,
|
|
3816
4066
|
onEvent: context.onEvent,
|
|
3817
|
-
resolveExternalTool: context.resolveExternalTool
|
|
4067
|
+
resolveExternalTool: context.resolveExternalTool,
|
|
4068
|
+
toolRegistry: context.toolRegistry
|
|
3818
4069
|
});
|
|
3819
4070
|
context.subAgentMessages?.set(context.toolCallId, result.messages);
|
|
3820
4071
|
return result.text;
|
|
@@ -3855,7 +4106,7 @@ function getCommonTools() {
|
|
|
3855
4106
|
askMindStudioSdkTool,
|
|
3856
4107
|
fetchUrlTool,
|
|
3857
4108
|
searchGoogleTool,
|
|
3858
|
-
|
|
4109
|
+
setProjectMetadataTool,
|
|
3859
4110
|
designExpertTool,
|
|
3860
4111
|
productVisionTool,
|
|
3861
4112
|
codeSanityCheckTool
|
|
@@ -3920,7 +4171,7 @@ var init_tools5 = __esm({
|
|
|
3920
4171
|
init_sdkConsultant();
|
|
3921
4172
|
init_fetchUrl();
|
|
3922
4173
|
init_searchGoogle();
|
|
3923
|
-
|
|
4174
|
+
init_setProjectMetadata();
|
|
3924
4175
|
init_readFile();
|
|
3925
4176
|
init_writeFile();
|
|
3926
4177
|
init_editFile();
|
|
@@ -4186,91 +4437,6 @@ var init_parsePartialJson = __esm({
|
|
|
4186
4437
|
}
|
|
4187
4438
|
});
|
|
4188
4439
|
|
|
4189
|
-
// src/statusWatcher.ts
|
|
4190
|
-
function startStatusWatcher(config) {
|
|
4191
|
-
const { apiConfig, getContext, onStatus, interval = 3e3, signal } = config;
|
|
4192
|
-
let lastLabel = "";
|
|
4193
|
-
let inflight = false;
|
|
4194
|
-
let stopped = false;
|
|
4195
|
-
const url = `${apiConfig.baseUrl}/_internal/v2/agent/remy/generate-status`;
|
|
4196
|
-
async function tick() {
|
|
4197
|
-
if (stopped || signal?.aborted || inflight) {
|
|
4198
|
-
return;
|
|
4199
|
-
}
|
|
4200
|
-
inflight = true;
|
|
4201
|
-
try {
|
|
4202
|
-
const ctx = getContext();
|
|
4203
|
-
if (!ctx.assistantText && !ctx.lastToolName) {
|
|
4204
|
-
log.debug("Status watcher: no context, skipping");
|
|
4205
|
-
return;
|
|
4206
|
-
}
|
|
4207
|
-
log.debug("Status watcher: requesting label", {
|
|
4208
|
-
textLength: ctx.assistantText.length,
|
|
4209
|
-
lastToolName: ctx.lastToolName
|
|
4210
|
-
});
|
|
4211
|
-
const res = await fetch(url, {
|
|
4212
|
-
method: "POST",
|
|
4213
|
-
headers: {
|
|
4214
|
-
"Content-Type": "application/json",
|
|
4215
|
-
Authorization: `Bearer ${apiConfig.apiKey}`
|
|
4216
|
-
},
|
|
4217
|
-
body: JSON.stringify({
|
|
4218
|
-
assistantText: ctx.assistantText.slice(-500),
|
|
4219
|
-
lastToolName: ctx.lastToolName,
|
|
4220
|
-
lastToolResult: ctx.lastToolResult?.slice(-200),
|
|
4221
|
-
onboardingState: ctx.onboardingState,
|
|
4222
|
-
userMessage: ctx.userMessage?.slice(-200)
|
|
4223
|
-
}),
|
|
4224
|
-
signal
|
|
4225
|
-
});
|
|
4226
|
-
if (!res.ok) {
|
|
4227
|
-
log.debug("Status watcher: endpoint returned non-ok", {
|
|
4228
|
-
status: res.status
|
|
4229
|
-
});
|
|
4230
|
-
return;
|
|
4231
|
-
}
|
|
4232
|
-
const data = await res.json();
|
|
4233
|
-
if (!data.label) {
|
|
4234
|
-
log.debug("Status watcher: no label in response");
|
|
4235
|
-
return;
|
|
4236
|
-
}
|
|
4237
|
-
if (data.label === lastLabel) {
|
|
4238
|
-
log.debug("Status watcher: duplicate label, skipping", {
|
|
4239
|
-
label: data.label
|
|
4240
|
-
});
|
|
4241
|
-
return;
|
|
4242
|
-
}
|
|
4243
|
-
lastLabel = data.label;
|
|
4244
|
-
if (stopped) {
|
|
4245
|
-
return;
|
|
4246
|
-
}
|
|
4247
|
-
log.debug("Status watcher: emitting", { label: data.label });
|
|
4248
|
-
onStatus(data.label);
|
|
4249
|
-
} catch (err) {
|
|
4250
|
-
log.debug("Status watcher: error", { error: err?.message ?? "unknown" });
|
|
4251
|
-
} finally {
|
|
4252
|
-
inflight = false;
|
|
4253
|
-
}
|
|
4254
|
-
}
|
|
4255
|
-
const timer = setInterval(tick, interval);
|
|
4256
|
-
tick().catch(() => {
|
|
4257
|
-
});
|
|
4258
|
-
log.debug("Status watcher started", { interval });
|
|
4259
|
-
return {
|
|
4260
|
-
stop() {
|
|
4261
|
-
stopped = true;
|
|
4262
|
-
clearInterval(timer);
|
|
4263
|
-
log.debug("Status watcher stopped");
|
|
4264
|
-
}
|
|
4265
|
-
};
|
|
4266
|
-
}
|
|
4267
|
-
var init_statusWatcher = __esm({
|
|
4268
|
-
"src/statusWatcher.ts"() {
|
|
4269
|
-
"use strict";
|
|
4270
|
-
init_logger();
|
|
4271
|
-
}
|
|
4272
|
-
});
|
|
4273
|
-
|
|
4274
4440
|
// src/errors.ts
|
|
4275
4441
|
function friendlyError(raw) {
|
|
4276
4442
|
for (const [pattern, message] of patterns) {
|
|
@@ -4327,7 +4493,9 @@ async function runTurn(params) {
|
|
|
4327
4493
|
signal,
|
|
4328
4494
|
onEvent,
|
|
4329
4495
|
resolveExternalTool,
|
|
4330
|
-
hidden
|
|
4496
|
+
hidden,
|
|
4497
|
+
toolRegistry,
|
|
4498
|
+
onBackgroundComplete
|
|
4331
4499
|
} = params;
|
|
4332
4500
|
const tools2 = getToolDefinitions(onboardingState);
|
|
4333
4501
|
log.info("Turn started", {
|
|
@@ -4340,8 +4508,7 @@ async function runTurn(params) {
|
|
|
4340
4508
|
}
|
|
4341
4509
|
});
|
|
4342
4510
|
onEvent({ type: "turn_started" });
|
|
4343
|
-
const
|
|
4344
|
-
const userMsg = { role: "user", content: cleanMessage };
|
|
4511
|
+
const userMsg = { role: "user", content: userMessage };
|
|
4345
4512
|
if (hidden) {
|
|
4346
4513
|
userMsg.hidden = true;
|
|
4347
4514
|
}
|
|
@@ -4355,7 +4522,7 @@ async function runTurn(params) {
|
|
|
4355
4522
|
state.messages.push(userMsg);
|
|
4356
4523
|
const STATUS_EXCLUDED_TOOLS = /* @__PURE__ */ new Set([
|
|
4357
4524
|
"setProjectOnboardingState",
|
|
4358
|
-
"
|
|
4525
|
+
"setProjectMetadata",
|
|
4359
4526
|
"clearSyncStatus",
|
|
4360
4527
|
"editsFinished"
|
|
4361
4528
|
]);
|
|
@@ -4380,6 +4547,20 @@ async function runTurn(params) {
|
|
|
4380
4547
|
let thinkingStartedAt = 0;
|
|
4381
4548
|
const toolInputAccumulators = /* @__PURE__ */ new Map();
|
|
4382
4549
|
let stopReason = "end_turn";
|
|
4550
|
+
let subAgentText = "";
|
|
4551
|
+
let currentToolNames = "";
|
|
4552
|
+
const statusWatcher = startStatusWatcher({
|
|
4553
|
+
apiConfig,
|
|
4554
|
+
getContext: () => ({
|
|
4555
|
+
assistantText: subAgentText || getTextContent(contentBlocks).slice(-500),
|
|
4556
|
+
lastToolName: currentToolNames || getToolCalls(contentBlocks).filter((tc) => !STATUS_EXCLUDED_TOOLS.has(tc.name)).at(-1)?.name || lastCompletedTools || void 0,
|
|
4557
|
+
lastToolResult: lastCompletedResult || void 0,
|
|
4558
|
+
onboardingState,
|
|
4559
|
+
userMessage
|
|
4560
|
+
}),
|
|
4561
|
+
onStatus: (label) => onEvent({ type: "status", message: label }),
|
|
4562
|
+
signal
|
|
4563
|
+
});
|
|
4383
4564
|
async function handlePartialInput(acc, id, name, partial) {
|
|
4384
4565
|
const tool = getToolByName(name);
|
|
4385
4566
|
if (!tool?.streaming) {
|
|
@@ -4443,18 +4624,6 @@ async function runTurn(params) {
|
|
|
4443
4624
|
onEvent({ type: "tool_input_delta", id, name, result: content });
|
|
4444
4625
|
}
|
|
4445
4626
|
}
|
|
4446
|
-
const statusWatcher = startStatusWatcher({
|
|
4447
|
-
apiConfig,
|
|
4448
|
-
getContext: () => ({
|
|
4449
|
-
assistantText: getTextContent(contentBlocks).slice(-500),
|
|
4450
|
-
lastToolName: getToolCalls(contentBlocks).filter((tc) => !STATUS_EXCLUDED_TOOLS.has(tc.name)).at(-1)?.name || lastCompletedTools || void 0,
|
|
4451
|
-
lastToolResult: lastCompletedResult || void 0,
|
|
4452
|
-
onboardingState,
|
|
4453
|
-
userMessage
|
|
4454
|
-
}),
|
|
4455
|
-
onStatus: (label) => onEvent({ type: "status", message: label }),
|
|
4456
|
-
signal
|
|
4457
|
-
});
|
|
4458
4627
|
try {
|
|
4459
4628
|
for await (const event of streamChatWithRetry(
|
|
4460
4629
|
{
|
|
@@ -4540,7 +4709,8 @@ async function runTurn(params) {
|
|
|
4540
4709
|
id: event.id,
|
|
4541
4710
|
name: event.name,
|
|
4542
4711
|
input: event.input,
|
|
4543
|
-
startedAt: event.ts
|
|
4712
|
+
startedAt: event.ts,
|
|
4713
|
+
...event.input.background && { background: true }
|
|
4544
4714
|
});
|
|
4545
4715
|
const acc = toolInputAccumulators.get(event.id);
|
|
4546
4716
|
const tool = getToolByName(event.name);
|
|
@@ -4575,10 +4745,9 @@ async function runTurn(params) {
|
|
|
4575
4745
|
} else {
|
|
4576
4746
|
throw err;
|
|
4577
4747
|
}
|
|
4578
|
-
} finally {
|
|
4579
|
-
statusWatcher.stop();
|
|
4580
4748
|
}
|
|
4581
4749
|
if (signal?.aborted) {
|
|
4750
|
+
statusWatcher.stop();
|
|
4582
4751
|
if (contentBlocks.length > 0) {
|
|
4583
4752
|
contentBlocks.push({
|
|
4584
4753
|
type: "text",
|
|
@@ -4600,6 +4769,7 @@ async function runTurn(params) {
|
|
|
4600
4769
|
});
|
|
4601
4770
|
const toolCalls = getToolCalls(contentBlocks);
|
|
4602
4771
|
if (stopReason !== "tool_use" || toolCalls.length === 0) {
|
|
4772
|
+
statusWatcher.stop();
|
|
4603
4773
|
saveSession(state);
|
|
4604
4774
|
onEvent({ type: "turn_done" });
|
|
4605
4775
|
return;
|
|
@@ -4608,8 +4778,7 @@ async function runTurn(params) {
|
|
|
4608
4778
|
count: toolCalls.length,
|
|
4609
4779
|
tools: toolCalls.map((tc) => tc.name)
|
|
4610
4780
|
});
|
|
4611
|
-
|
|
4612
|
-
const origOnEvent = onEvent;
|
|
4781
|
+
currentToolNames = toolCalls.filter((tc) => !STATUS_EXCLUDED_TOOLS.has(tc.name)).map((tc) => tc.name).join(", ");
|
|
4613
4782
|
const wrappedOnEvent = (e) => {
|
|
4614
4783
|
if ("parentToolId" in e && e.parentToolId) {
|
|
4615
4784
|
if (e.type === "text") {
|
|
@@ -4618,86 +4787,104 @@ async function runTurn(params) {
|
|
|
4618
4787
|
subAgentText = `Using ${e.name}`;
|
|
4619
4788
|
}
|
|
4620
4789
|
}
|
|
4621
|
-
|
|
4790
|
+
onEvent(e);
|
|
4622
4791
|
};
|
|
4623
|
-
const toolStatusWatcher = startStatusWatcher({
|
|
4624
|
-
apiConfig,
|
|
4625
|
-
getContext: () => ({
|
|
4626
|
-
assistantText: subAgentText || getTextContent(contentBlocks).slice(-500),
|
|
4627
|
-
lastToolName: toolCalls.filter((tc) => !STATUS_EXCLUDED_TOOLS.has(tc.name)).map((tc) => tc.name).join(", ") || void 0,
|
|
4628
|
-
lastToolResult: lastCompletedResult || void 0,
|
|
4629
|
-
onboardingState,
|
|
4630
|
-
userMessage
|
|
4631
|
-
}),
|
|
4632
|
-
onStatus: (label) => origOnEvent({ type: "status", message: label }),
|
|
4633
|
-
signal
|
|
4634
|
-
});
|
|
4635
4792
|
const subAgentMessages = /* @__PURE__ */ new Map();
|
|
4636
4793
|
const results = await Promise.all(
|
|
4637
4794
|
toolCalls.map(async (tc) => {
|
|
4638
4795
|
if (signal?.aborted) {
|
|
4639
|
-
return {
|
|
4640
|
-
id: tc.id,
|
|
4641
|
-
result: "Error: cancelled",
|
|
4642
|
-
isError: true
|
|
4643
|
-
};
|
|
4796
|
+
return { id: tc.id, result: "Error: cancelled", isError: true };
|
|
4644
4797
|
}
|
|
4645
4798
|
const toolStart = Date.now();
|
|
4646
|
-
|
|
4647
|
-
|
|
4648
|
-
|
|
4649
|
-
|
|
4650
|
-
|
|
4651
|
-
|
|
4652
|
-
|
|
4653
|
-
|
|
4654
|
-
|
|
4655
|
-
|
|
4656
|
-
|
|
4657
|
-
|
|
4658
|
-
|
|
4659
|
-
|
|
4660
|
-
|
|
4661
|
-
|
|
4662
|
-
|
|
4663
|
-
|
|
4664
|
-
|
|
4665
|
-
|
|
4666
|
-
|
|
4799
|
+
let settle;
|
|
4800
|
+
const resultPromise = new Promise((res) => {
|
|
4801
|
+
settle = (result, isError) => res({ id: tc.id, result, isError });
|
|
4802
|
+
});
|
|
4803
|
+
let toolAbort = new AbortController();
|
|
4804
|
+
const cascadeAbort = () => toolAbort.abort();
|
|
4805
|
+
signal?.addEventListener("abort", cascadeAbort, { once: true });
|
|
4806
|
+
let settled = false;
|
|
4807
|
+
const safeSettle = (result, isError) => {
|
|
4808
|
+
if (settled) {
|
|
4809
|
+
return;
|
|
4810
|
+
}
|
|
4811
|
+
settled = true;
|
|
4812
|
+
signal?.removeEventListener("abort", cascadeAbort);
|
|
4813
|
+
settle(result, isError);
|
|
4814
|
+
};
|
|
4815
|
+
const run = async (input) => {
|
|
4816
|
+
try {
|
|
4817
|
+
let result;
|
|
4818
|
+
if (EXTERNAL_TOOLS.has(tc.name) && resolveExternalTool) {
|
|
4819
|
+
saveSession(state);
|
|
4820
|
+
log.info("Waiting for external tool result", {
|
|
4667
4821
|
name: tc.name,
|
|
4668
|
-
|
|
4669
|
-
})
|
|
4822
|
+
id: tc.id
|
|
4823
|
+
});
|
|
4824
|
+
result = await resolveExternalTool(tc.id, tc.name, input);
|
|
4825
|
+
} else {
|
|
4826
|
+
result = await executeTool(tc.name, input, {
|
|
4827
|
+
apiConfig,
|
|
4828
|
+
model,
|
|
4829
|
+
signal: toolAbort.signal,
|
|
4830
|
+
onEvent: wrappedOnEvent,
|
|
4831
|
+
resolveExternalTool,
|
|
4832
|
+
toolCallId: tc.id,
|
|
4833
|
+
subAgentMessages,
|
|
4834
|
+
toolRegistry,
|
|
4835
|
+
onBackgroundComplete,
|
|
4836
|
+
onLog: (line) => wrappedOnEvent({
|
|
4837
|
+
type: "tool_input_delta",
|
|
4838
|
+
id: tc.id,
|
|
4839
|
+
name: tc.name,
|
|
4840
|
+
result: line
|
|
4841
|
+
})
|
|
4842
|
+
});
|
|
4843
|
+
}
|
|
4844
|
+
safeSettle(result, result.startsWith("Error"));
|
|
4845
|
+
} catch (err) {
|
|
4846
|
+
safeSettle(`Error: ${err.message}`, true);
|
|
4847
|
+
}
|
|
4848
|
+
};
|
|
4849
|
+
const entry = {
|
|
4850
|
+
id: tc.id,
|
|
4851
|
+
name: tc.name,
|
|
4852
|
+
input: tc.input,
|
|
4853
|
+
abortController: toolAbort,
|
|
4854
|
+
startedAt: toolStart,
|
|
4855
|
+
settle: safeSettle,
|
|
4856
|
+
rerun: (newInput) => {
|
|
4857
|
+
settled = false;
|
|
4858
|
+
toolAbort = new AbortController();
|
|
4859
|
+
signal?.addEventListener("abort", () => toolAbort.abort(), {
|
|
4860
|
+
once: true
|
|
4670
4861
|
});
|
|
4862
|
+
entry.abortController = toolAbort;
|
|
4863
|
+
entry.input = newInput;
|
|
4864
|
+
run(newInput);
|
|
4671
4865
|
}
|
|
4672
|
-
|
|
4673
|
-
|
|
4674
|
-
|
|
4675
|
-
|
|
4676
|
-
|
|
4677
|
-
|
|
4678
|
-
|
|
4679
|
-
|
|
4680
|
-
|
|
4681
|
-
|
|
4682
|
-
|
|
4683
|
-
|
|
4684
|
-
|
|
4685
|
-
|
|
4686
|
-
|
|
4687
|
-
|
|
4688
|
-
|
|
4689
|
-
|
|
4690
|
-
|
|
4691
|
-
id: tc.id,
|
|
4692
|
-
name: tc.name,
|
|
4693
|
-
result: errorMsg,
|
|
4694
|
-
isError: true
|
|
4695
|
-
});
|
|
4696
|
-
return { id: tc.id, result: errorMsg, isError: true };
|
|
4697
|
-
}
|
|
4866
|
+
};
|
|
4867
|
+
toolRegistry?.register(entry);
|
|
4868
|
+
run(tc.input);
|
|
4869
|
+
const r = await resultPromise;
|
|
4870
|
+
toolRegistry?.unregister(tc.id);
|
|
4871
|
+
log.info("Tool completed", {
|
|
4872
|
+
name: tc.name,
|
|
4873
|
+
elapsed: `${Date.now() - toolStart}ms`,
|
|
4874
|
+
isError: r.isError,
|
|
4875
|
+
resultLength: r.result.length
|
|
4876
|
+
});
|
|
4877
|
+
onEvent({
|
|
4878
|
+
type: "tool_done",
|
|
4879
|
+
id: tc.id,
|
|
4880
|
+
name: tc.name,
|
|
4881
|
+
result: r.result,
|
|
4882
|
+
isError: r.isError
|
|
4883
|
+
});
|
|
4884
|
+
return r;
|
|
4698
4885
|
})
|
|
4699
4886
|
);
|
|
4700
|
-
|
|
4887
|
+
statusWatcher.stop();
|
|
4701
4888
|
for (const r of results) {
|
|
4702
4889
|
const block = contentBlocks.find(
|
|
4703
4890
|
(b) => b.type === "tool" && b.id === r.id
|
|
@@ -4705,6 +4892,7 @@ async function runTurn(params) {
|
|
|
4705
4892
|
if (block?.type === "tool") {
|
|
4706
4893
|
block.result = r.result;
|
|
4707
4894
|
block.isError = r.isError;
|
|
4895
|
+
block.completedAt = Date.now();
|
|
4708
4896
|
const msgs = subAgentMessages.get(r.id);
|
|
4709
4897
|
if (msgs) {
|
|
4710
4898
|
block.subAgentMessages = msgs;
|
|
@@ -4751,7 +4939,7 @@ var init_agent = __esm({
|
|
|
4751
4939
|
"runScenario",
|
|
4752
4940
|
"runMethod",
|
|
4753
4941
|
"browserCommand",
|
|
4754
|
-
"
|
|
4942
|
+
"setProjectMetadata"
|
|
4755
4943
|
]);
|
|
4756
4944
|
}
|
|
4757
4945
|
});
|
|
@@ -5063,6 +5251,84 @@ var init_config = __esm({
|
|
|
5063
5251
|
}
|
|
5064
5252
|
});
|
|
5065
5253
|
|
|
5254
|
+
// src/toolRegistry.ts
|
|
5255
|
+
var ToolRegistry;
|
|
5256
|
+
var init_toolRegistry = __esm({
|
|
5257
|
+
"src/toolRegistry.ts"() {
|
|
5258
|
+
"use strict";
|
|
5259
|
+
ToolRegistry = class {
|
|
5260
|
+
entries = /* @__PURE__ */ new Map();
|
|
5261
|
+
onEvent;
|
|
5262
|
+
register(entry) {
|
|
5263
|
+
this.entries.set(entry.id, entry);
|
|
5264
|
+
}
|
|
5265
|
+
unregister(id) {
|
|
5266
|
+
this.entries.delete(id);
|
|
5267
|
+
}
|
|
5268
|
+
get(id) {
|
|
5269
|
+
return this.entries.get(id);
|
|
5270
|
+
}
|
|
5271
|
+
/**
|
|
5272
|
+
* Stop a running tool.
|
|
5273
|
+
*
|
|
5274
|
+
* - graceful: abort and settle with [INTERRUPTED] + partial result
|
|
5275
|
+
* - hard: abort and settle with a generic error
|
|
5276
|
+
*
|
|
5277
|
+
* Returns true if the tool was found and stopped.
|
|
5278
|
+
*/
|
|
5279
|
+
stop(id, mode) {
|
|
5280
|
+
const entry = this.entries.get(id);
|
|
5281
|
+
if (!entry) {
|
|
5282
|
+
return false;
|
|
5283
|
+
}
|
|
5284
|
+
entry.abortController.abort(mode);
|
|
5285
|
+
if (mode === "graceful") {
|
|
5286
|
+
const partial = entry.getPartialResult?.() ?? "";
|
|
5287
|
+
const result = partial ? `[INTERRUPTED]
|
|
5288
|
+
|
|
5289
|
+
${partial}` : "[INTERRUPTED] Tool execution was stopped.";
|
|
5290
|
+
entry.settle(result, false);
|
|
5291
|
+
} else {
|
|
5292
|
+
entry.settle("Error: tool was cancelled", true);
|
|
5293
|
+
}
|
|
5294
|
+
this.onEvent?.({
|
|
5295
|
+
type: "tool_stopped",
|
|
5296
|
+
id: entry.id,
|
|
5297
|
+
name: entry.name,
|
|
5298
|
+
mode,
|
|
5299
|
+
...entry.parentToolId && { parentToolId: entry.parentToolId }
|
|
5300
|
+
});
|
|
5301
|
+
this.entries.delete(id);
|
|
5302
|
+
return true;
|
|
5303
|
+
}
|
|
5304
|
+
/**
|
|
5305
|
+
* Restart a running tool with the same or patched input.
|
|
5306
|
+
* The original controllable promise stays pending and settles
|
|
5307
|
+
* when the new execution finishes.
|
|
5308
|
+
*
|
|
5309
|
+
* Returns true if the tool was found and restarted.
|
|
5310
|
+
*/
|
|
5311
|
+
restart(id, patchedInput) {
|
|
5312
|
+
const entry = this.entries.get(id);
|
|
5313
|
+
if (!entry) {
|
|
5314
|
+
return false;
|
|
5315
|
+
}
|
|
5316
|
+
entry.abortController.abort("restart");
|
|
5317
|
+
const newInput = patchedInput ? { ...entry.input, ...patchedInput } : entry.input;
|
|
5318
|
+
this.onEvent?.({
|
|
5319
|
+
type: "tool_restarted",
|
|
5320
|
+
id: entry.id,
|
|
5321
|
+
name: entry.name,
|
|
5322
|
+
input: newInput,
|
|
5323
|
+
...entry.parentToolId && { parentToolId: entry.parentToolId }
|
|
5324
|
+
});
|
|
5325
|
+
entry.rerun(newInput);
|
|
5326
|
+
return true;
|
|
5327
|
+
}
|
|
5328
|
+
};
|
|
5329
|
+
}
|
|
5330
|
+
});
|
|
5331
|
+
|
|
5066
5332
|
// src/headless.ts
|
|
5067
5333
|
var headless_exports = {};
|
|
5068
5334
|
__export(headless_exports, {
|
|
@@ -5134,6 +5400,55 @@ async function startHeadless(opts = {}) {
|
|
|
5134
5400
|
const EXTERNAL_TOOL_TIMEOUT_MS = 3e5;
|
|
5135
5401
|
const pendingTools = /* @__PURE__ */ new Map();
|
|
5136
5402
|
const earlyResults = /* @__PURE__ */ new Map();
|
|
5403
|
+
const toolRegistry = new ToolRegistry();
|
|
5404
|
+
const backgroundQueue = [];
|
|
5405
|
+
function flushBackgroundQueue() {
|
|
5406
|
+
if (backgroundQueue.length === 0) {
|
|
5407
|
+
return;
|
|
5408
|
+
}
|
|
5409
|
+
const results = backgroundQueue.splice(0);
|
|
5410
|
+
const xmlParts = results.map(
|
|
5411
|
+
(r) => `<tool_result id="${r.toolCallId}" name="${r.name}">
|
|
5412
|
+
${r.result}
|
|
5413
|
+
</tool_result>`
|
|
5414
|
+
).join("\n\n");
|
|
5415
|
+
const message = `@@automated::background_results@@
|
|
5416
|
+
<background_results>
|
|
5417
|
+
${xmlParts}
|
|
5418
|
+
</background_results>`;
|
|
5419
|
+
handleMessage({ action: "message", text: message }, void 0);
|
|
5420
|
+
}
|
|
5421
|
+
function onBackgroundComplete(toolCallId, name, result, subAgentMessages) {
|
|
5422
|
+
for (const msg of state.messages) {
|
|
5423
|
+
if (!Array.isArray(msg.content)) {
|
|
5424
|
+
continue;
|
|
5425
|
+
}
|
|
5426
|
+
for (const block of msg.content) {
|
|
5427
|
+
if (block.type === "tool" && block.id === toolCallId) {
|
|
5428
|
+
block.backgroundResult = result;
|
|
5429
|
+
block.completedAt = Date.now();
|
|
5430
|
+
if (subAgentMessages) {
|
|
5431
|
+
block.subAgentMessages = subAgentMessages;
|
|
5432
|
+
}
|
|
5433
|
+
}
|
|
5434
|
+
}
|
|
5435
|
+
}
|
|
5436
|
+
onEvent({
|
|
5437
|
+
type: "tool_background_complete",
|
|
5438
|
+
id: toolCallId,
|
|
5439
|
+
name,
|
|
5440
|
+
result
|
|
5441
|
+
});
|
|
5442
|
+
backgroundQueue.push({
|
|
5443
|
+
toolCallId,
|
|
5444
|
+
name,
|
|
5445
|
+
result,
|
|
5446
|
+
completedAt: Date.now()
|
|
5447
|
+
});
|
|
5448
|
+
if (!running) {
|
|
5449
|
+
flushBackgroundQueue();
|
|
5450
|
+
}
|
|
5451
|
+
}
|
|
5137
5452
|
const USER_FACING_TOOLS = /* @__PURE__ */ new Set([
|
|
5138
5453
|
"promptUser",
|
|
5139
5454
|
"confirmDestructiveAction",
|
|
@@ -5174,6 +5489,7 @@ async function startHeadless(opts = {}) {
|
|
|
5174
5489
|
case "turn_done":
|
|
5175
5490
|
completedEmitted = true;
|
|
5176
5491
|
emit("completed", { success: true }, rid);
|
|
5492
|
+
setTimeout(() => flushBackgroundQueue(), 0);
|
|
5177
5493
|
return;
|
|
5178
5494
|
case "turn_cancelled":
|
|
5179
5495
|
completedEmitted = true;
|
|
@@ -5220,6 +5536,7 @@ async function startHeadless(opts = {}) {
|
|
|
5220
5536
|
name: e.name,
|
|
5221
5537
|
input: e.input,
|
|
5222
5538
|
...e.partial && { partial: true },
|
|
5539
|
+
...e.background && { background: true },
|
|
5223
5540
|
...e.parentToolId && { parentToolId: e.parentToolId }
|
|
5224
5541
|
},
|
|
5225
5542
|
rid
|
|
@@ -5238,14 +5555,58 @@ async function startHeadless(opts = {}) {
|
|
|
5238
5555
|
rid
|
|
5239
5556
|
);
|
|
5240
5557
|
return;
|
|
5558
|
+
case "tool_background_complete":
|
|
5559
|
+
emit(
|
|
5560
|
+
"tool_background_complete",
|
|
5561
|
+
{
|
|
5562
|
+
id: e.id,
|
|
5563
|
+
name: e.name,
|
|
5564
|
+
result: e.result,
|
|
5565
|
+
...e.parentToolId && { parentToolId: e.parentToolId }
|
|
5566
|
+
},
|
|
5567
|
+
rid
|
|
5568
|
+
);
|
|
5569
|
+
return;
|
|
5570
|
+
case "tool_stopped":
|
|
5571
|
+
emit(
|
|
5572
|
+
"tool_stopped",
|
|
5573
|
+
{
|
|
5574
|
+
id: e.id,
|
|
5575
|
+
name: e.name,
|
|
5576
|
+
mode: e.mode,
|
|
5577
|
+
...e.parentToolId && { parentToolId: e.parentToolId }
|
|
5578
|
+
},
|
|
5579
|
+
rid
|
|
5580
|
+
);
|
|
5581
|
+
return;
|
|
5582
|
+
case "tool_restarted":
|
|
5583
|
+
emit(
|
|
5584
|
+
"tool_restarted",
|
|
5585
|
+
{
|
|
5586
|
+
id: e.id,
|
|
5587
|
+
name: e.name,
|
|
5588
|
+
input: e.input,
|
|
5589
|
+
...e.parentToolId && { parentToolId: e.parentToolId }
|
|
5590
|
+
},
|
|
5591
|
+
rid
|
|
5592
|
+
);
|
|
5593
|
+
return;
|
|
5241
5594
|
case "status":
|
|
5242
|
-
emit(
|
|
5595
|
+
emit(
|
|
5596
|
+
"status",
|
|
5597
|
+
{
|
|
5598
|
+
message: e.message,
|
|
5599
|
+
...e.parentToolId && { parentToolId: e.parentToolId }
|
|
5600
|
+
},
|
|
5601
|
+
rid
|
|
5602
|
+
);
|
|
5243
5603
|
return;
|
|
5244
5604
|
case "error":
|
|
5245
5605
|
emit("error", { error: e.error }, rid);
|
|
5246
5606
|
return;
|
|
5247
5607
|
}
|
|
5248
5608
|
}
|
|
5609
|
+
toolRegistry.onEvent = onEvent;
|
|
5249
5610
|
async function handleMessage(parsed, requestId) {
|
|
5250
5611
|
if (running) {
|
|
5251
5612
|
emit(
|
|
@@ -5273,6 +5634,7 @@ async function startHeadless(opts = {}) {
|
|
|
5273
5634
|
}
|
|
5274
5635
|
let userMessage = parsed.text ?? "";
|
|
5275
5636
|
const isCommand = !!parsed.runCommand;
|
|
5637
|
+
const isHidden = isCommand || !!parsed.hidden;
|
|
5276
5638
|
if (parsed.runCommand === "sync") {
|
|
5277
5639
|
userMessage = loadActionPrompt("sync");
|
|
5278
5640
|
} else if (parsed.runCommand === "publish") {
|
|
@@ -5297,7 +5659,9 @@ async function startHeadless(opts = {}) {
|
|
|
5297
5659
|
signal: currentAbort.signal,
|
|
5298
5660
|
onEvent,
|
|
5299
5661
|
resolveExternalTool,
|
|
5300
|
-
hidden:
|
|
5662
|
+
hidden: isHidden,
|
|
5663
|
+
toolRegistry,
|
|
5664
|
+
onBackgroundComplete
|
|
5301
5665
|
});
|
|
5302
5666
|
if (!completedEmitted) {
|
|
5303
5667
|
emit(
|
|
@@ -5351,6 +5715,36 @@ async function startHeadless(opts = {}) {
|
|
|
5351
5715
|
emit("completed", { success: true }, requestId);
|
|
5352
5716
|
return;
|
|
5353
5717
|
}
|
|
5718
|
+
if (action === "stop_tool") {
|
|
5719
|
+
const id = parsed.id;
|
|
5720
|
+
const mode = parsed.mode ?? "hard";
|
|
5721
|
+
const found = toolRegistry.stop(id, mode);
|
|
5722
|
+
if (found) {
|
|
5723
|
+
emit("completed", { success: true }, requestId);
|
|
5724
|
+
} else {
|
|
5725
|
+
emit(
|
|
5726
|
+
"completed",
|
|
5727
|
+
{ success: false, error: "Tool not found" },
|
|
5728
|
+
requestId
|
|
5729
|
+
);
|
|
5730
|
+
}
|
|
5731
|
+
return;
|
|
5732
|
+
}
|
|
5733
|
+
if (action === "restart_tool") {
|
|
5734
|
+
const id = parsed.id;
|
|
5735
|
+
const patchedInput = parsed.input;
|
|
5736
|
+
const found = toolRegistry.restart(id, patchedInput);
|
|
5737
|
+
if (found) {
|
|
5738
|
+
emit("completed", { success: true }, requestId);
|
|
5739
|
+
} else {
|
|
5740
|
+
emit(
|
|
5741
|
+
"completed",
|
|
5742
|
+
{ success: false, error: "Tool not found" },
|
|
5743
|
+
requestId
|
|
5744
|
+
);
|
|
5745
|
+
}
|
|
5746
|
+
return;
|
|
5747
|
+
}
|
|
5354
5748
|
if (action === "message") {
|
|
5355
5749
|
await handleMessage(parsed, requestId);
|
|
5356
5750
|
return;
|
|
@@ -5385,6 +5779,7 @@ var init_headless = __esm({
|
|
|
5385
5779
|
init_lsp();
|
|
5386
5780
|
init_agent();
|
|
5387
5781
|
init_session();
|
|
5782
|
+
init_toolRegistry();
|
|
5388
5783
|
}
|
|
5389
5784
|
});
|
|
5390
5785
|
|