@mindstudio-ai/remy 0.1.36 → 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 +398 -238
- package/dist/index.js +402 -242
- 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: {
|
|
@@ -2185,6 +2221,12 @@ var init_statusWatcher = __esm({
|
|
|
2185
2221
|
// src/subagents/common/cleanMessages.ts
|
|
2186
2222
|
function cleanMessagesForApi(messages) {
|
|
2187
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
|
+
}
|
|
2188
2230
|
if (!Array.isArray(msg.content)) {
|
|
2189
2231
|
return msg;
|
|
2190
2232
|
}
|
|
@@ -2227,238 +2269,264 @@ async function runSubAgent(config) {
|
|
|
2227
2269
|
apiConfig,
|
|
2228
2270
|
model,
|
|
2229
2271
|
subAgentId,
|
|
2230
|
-
signal,
|
|
2272
|
+
signal: parentSignal,
|
|
2231
2273
|
parentToolId,
|
|
2232
2274
|
onEvent,
|
|
2233
2275
|
resolveExternalTool,
|
|
2234
|
-
toolRegistry
|
|
2276
|
+
toolRegistry,
|
|
2277
|
+
background,
|
|
2278
|
+
onBackgroundComplete
|
|
2235
2279
|
} = config;
|
|
2280
|
+
const bgAbort = background ? new AbortController() : null;
|
|
2281
|
+
const signal = background ? bgAbort.signal : parentSignal;
|
|
2236
2282
|
const emit2 = (e) => {
|
|
2237
2283
|
onEvent({ ...e, parentToolId });
|
|
2238
2284
|
};
|
|
2239
|
-
const
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
function abortResult(blocks) {
|
|
2244
|
-
if (signal?.reason === "graceful") {
|
|
2245
|
-
const partial = getPartialText(blocks);
|
|
2246
|
-
return {
|
|
2247
|
-
text: partial ? `[INTERRUPTED]
|
|
2248
|
-
|
|
2249
|
-
${partial}` : "[INTERRUPTED] Sub-agent was interrupted before producing output.",
|
|
2250
|
-
messages
|
|
2251
|
-
};
|
|
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("");
|
|
2252
2289
|
}
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
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
|
+
}
|
|
2300
|
+
return { text: "Error: cancelled", messages };
|
|
2259
2301
|
}
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
|
|
2274
|
-
|
|
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}
|
|
2275
2322
|
|
|
2276
2323
|
Current date/time: ${(/* @__PURE__ */ new Date()).toISOString().replace("T", " ").replace(/\.\d+Z$/, " UTC")}`;
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
contentBlocks.push({
|
|
2297
|
-
type: "text",
|
|
2298
|
-
text: event.text,
|
|
2299
|
-
startedAt: event.ts
|
|
2300
|
-
});
|
|
2301
|
-
}
|
|
2302
|
-
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) {
|
|
2303
2343
|
break;
|
|
2304
2344
|
}
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
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;
|
|
2308
2359
|
}
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
type: "thinking",
|
|
2314
|
-
|
|
2315
|
-
|
|
2316
|
-
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
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;
|
|
2341
2401
|
}
|
|
2342
2402
|
}
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2403
|
+
if (signal?.aborted) {
|
|
2404
|
+
statusWatcher.stop();
|
|
2405
|
+
return abortResult(contentBlocks);
|
|
2346
2406
|
}
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2367
|
-
|
|
2368
|
-
|
|
2369
|
-
currentToolNames = toolCalls.map((tc) => tc.name).join(", ");
|
|
2370
|
-
const results = await Promise.all(
|
|
2371
|
-
toolCalls.map(async (tc) => {
|
|
2372
|
-
if (signal?.aborted) {
|
|
2373
|
-
return { id: tc.id, result: "Error: cancelled", isError: true };
|
|
2374
|
-
}
|
|
2375
|
-
let settle;
|
|
2376
|
-
const resultPromise = new Promise((res) => {
|
|
2377
|
-
settle = (result, isError) => res({ id: tc.id, result, isError });
|
|
2378
|
-
});
|
|
2379
|
-
let toolAbort = new AbortController();
|
|
2380
|
-
const cascadeAbort = () => toolAbort.abort();
|
|
2381
|
-
signal?.addEventListener("abort", cascadeAbort, { once: true });
|
|
2382
|
-
let settled = false;
|
|
2383
|
-
const safeSettle = (result, isError) => {
|
|
2384
|
-
if (settled) {
|
|
2385
|
-
return;
|
|
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 };
|
|
2386
2429
|
}
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
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 = {
|
|
2466
|
+
id: tc.id,
|
|
2467
|
+
name: tc.name,
|
|
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
|
|
2402
2478
|
});
|
|
2403
|
-
|
|
2479
|
+
entry.abortController = toolAbort;
|
|
2480
|
+
entry.input = newInput;
|
|
2481
|
+
run2(newInput);
|
|
2404
2482
|
}
|
|
2405
|
-
|
|
2406
|
-
|
|
2407
|
-
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
settled = false;
|
|
2420
|
-
toolAbort = new AbortController();
|
|
2421
|
-
signal?.addEventListener("abort", () => toolAbort.abort(), {
|
|
2422
|
-
once: true
|
|
2423
|
-
});
|
|
2424
|
-
entry.abortController = toolAbort;
|
|
2425
|
-
entry.input = newInput;
|
|
2426
|
-
run(newInput);
|
|
2427
|
-
}
|
|
2428
|
-
};
|
|
2429
|
-
toolRegistry?.register(entry);
|
|
2430
|
-
run(tc.input);
|
|
2431
|
-
const r = await resultPromise;
|
|
2432
|
-
toolRegistry?.unregister(tc.id);
|
|
2433
|
-
emit2({
|
|
2434
|
-
type: "tool_done",
|
|
2435
|
-
id: tc.id,
|
|
2436
|
-
name: tc.name,
|
|
2437
|
-
result: r.result,
|
|
2438
|
-
isError: r.isError
|
|
2439
|
-
});
|
|
2440
|
-
return r;
|
|
2441
|
-
})
|
|
2442
|
-
);
|
|
2443
|
-
statusWatcher.stop();
|
|
2444
|
-
lastToolResult = results.at(-1)?.result ?? "";
|
|
2445
|
-
for (const r of results) {
|
|
2446
|
-
const block = contentBlocks.find(
|
|
2447
|
-
(b) => b.type === "tool" && b.id === r.id
|
|
2483
|
+
};
|
|
2484
|
+
toolRegistry?.register(entry);
|
|
2485
|
+
run2(tc.input);
|
|
2486
|
+
const r = await resultPromise;
|
|
2487
|
+
toolRegistry?.unregister(tc.id);
|
|
2488
|
+
emit2({
|
|
2489
|
+
type: "tool_done",
|
|
2490
|
+
id: tc.id,
|
|
2491
|
+
name: tc.name,
|
|
2492
|
+
result: r.result,
|
|
2493
|
+
isError: r.isError
|
|
2494
|
+
});
|
|
2495
|
+
return r;
|
|
2496
|
+
})
|
|
2448
2497
|
);
|
|
2449
|
-
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
block
|
|
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
|
+
});
|
|
2453
2515
|
}
|
|
2454
|
-
messages.push({
|
|
2455
|
-
role: "user",
|
|
2456
|
-
content: r.result,
|
|
2457
|
-
toolCallId: r.id,
|
|
2458
|
-
isToolError: r.isError
|
|
2459
|
-
});
|
|
2460
2516
|
}
|
|
2517
|
+
};
|
|
2518
|
+
if (!background) {
|
|
2519
|
+
return run();
|
|
2461
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 };
|
|
2462
2530
|
}
|
|
2463
2531
|
var init_runner = __esm({
|
|
2464
2532
|
"src/subagents/runner.ts"() {
|
|
@@ -2864,9 +2932,7 @@ async function execute3(input, onLog) {
|
|
|
2864
2932
|
`mindstudio analyze-image --prompt ${JSON.stringify(analysisPrompt)} --image-url ${JSON.stringify(imageUrl)} --output-key analysis --no-meta`,
|
|
2865
2933
|
{ timeout: 2e5, onLog }
|
|
2866
2934
|
);
|
|
2867
|
-
return
|
|
2868
|
-
|
|
2869
|
-
${analysis}`;
|
|
2935
|
+
return JSON.stringify({ url: imageUrl, analysis });
|
|
2870
2936
|
}
|
|
2871
2937
|
var DESIGN_REFERENCE_PROMPT, definition3;
|
|
2872
2938
|
var init_analyzeDesign = __esm({
|
|
@@ -2938,7 +3004,7 @@ var init_analyzeImage = __esm({
|
|
|
2938
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.";
|
|
2939
3005
|
definition4 = {
|
|
2940
3006
|
name: "analyzeImage",
|
|
2941
|
-
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.",
|
|
2942
3008
|
inputSchema: {
|
|
2943
3009
|
type: "object",
|
|
2944
3010
|
properties: {
|
|
@@ -3028,10 +3094,12 @@ async function seedreamGenerate(opts) {
|
|
|
3028
3094
|
}
|
|
3029
3095
|
}
|
|
3030
3096
|
}));
|
|
3031
|
-
const batchResult = await runCli(
|
|
3032
|
-
|
|
3033
|
-
|
|
3034
|
-
|
|
3097
|
+
const batchResult = await runCli(`mindstudio batch --no-meta`, {
|
|
3098
|
+
jsonLogs: true,
|
|
3099
|
+
timeout: 2e5,
|
|
3100
|
+
onLog,
|
|
3101
|
+
stdin: JSON.stringify(steps)
|
|
3102
|
+
});
|
|
3035
3103
|
try {
|
|
3036
3104
|
const parsed = JSON.parse(batchResult);
|
|
3037
3105
|
imageUrls = parsed.map(
|
|
@@ -3478,6 +3546,10 @@ Visual design expert. Describe the situation and what you need \u2014 the agent
|
|
|
3478
3546
|
task: {
|
|
3479
3547
|
type: "string",
|
|
3480
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."
|
|
3481
3553
|
}
|
|
3482
3554
|
},
|
|
3483
3555
|
required: ["task"]
|
|
@@ -3500,7 +3572,16 @@ Visual design expert. Describe the situation and what you need \u2014 the agent
|
|
|
3500
3572
|
parentToolId: context.toolCallId,
|
|
3501
3573
|
onEvent: context.onEvent,
|
|
3502
3574
|
resolveExternalTool: context.resolveExternalTool,
|
|
3503
|
-
toolRegistry: context.toolRegistry
|
|
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
|
|
3504
3585
|
});
|
|
3505
3586
|
context.subAgentMessages?.set(context.toolCallId, result.messages);
|
|
3506
3587
|
return result.text;
|
|
@@ -3794,6 +3875,10 @@ var init_productVision = __esm({
|
|
|
3794
3875
|
task: {
|
|
3795
3876
|
type: "string",
|
|
3796
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."
|
|
3797
3882
|
}
|
|
3798
3883
|
},
|
|
3799
3884
|
required: ["task"]
|
|
@@ -3816,7 +3901,16 @@ var init_productVision = __esm({
|
|
|
3816
3901
|
parentToolId: context.toolCallId,
|
|
3817
3902
|
onEvent: context.onEvent,
|
|
3818
3903
|
resolveExternalTool: context.resolveExternalTool,
|
|
3819
|
-
toolRegistry: context.toolRegistry
|
|
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
|
|
3820
3914
|
});
|
|
3821
3915
|
context.subAgentMessages?.set(context.toolCallId, result.messages);
|
|
3822
3916
|
return result.text;
|
|
@@ -4012,7 +4106,7 @@ function getCommonTools() {
|
|
|
4012
4106
|
askMindStudioSdkTool,
|
|
4013
4107
|
fetchUrlTool,
|
|
4014
4108
|
searchGoogleTool,
|
|
4015
|
-
|
|
4109
|
+
setProjectMetadataTool,
|
|
4016
4110
|
designExpertTool,
|
|
4017
4111
|
productVisionTool,
|
|
4018
4112
|
codeSanityCheckTool
|
|
@@ -4077,7 +4171,7 @@ var init_tools5 = __esm({
|
|
|
4077
4171
|
init_sdkConsultant();
|
|
4078
4172
|
init_fetchUrl();
|
|
4079
4173
|
init_searchGoogle();
|
|
4080
|
-
|
|
4174
|
+
init_setProjectMetadata();
|
|
4081
4175
|
init_readFile();
|
|
4082
4176
|
init_writeFile();
|
|
4083
4177
|
init_editFile();
|
|
@@ -4400,7 +4494,8 @@ async function runTurn(params) {
|
|
|
4400
4494
|
onEvent,
|
|
4401
4495
|
resolveExternalTool,
|
|
4402
4496
|
hidden,
|
|
4403
|
-
toolRegistry
|
|
4497
|
+
toolRegistry,
|
|
4498
|
+
onBackgroundComplete
|
|
4404
4499
|
} = params;
|
|
4405
4500
|
const tools2 = getToolDefinitions(onboardingState);
|
|
4406
4501
|
log.info("Turn started", {
|
|
@@ -4413,8 +4508,7 @@ async function runTurn(params) {
|
|
|
4413
4508
|
}
|
|
4414
4509
|
});
|
|
4415
4510
|
onEvent({ type: "turn_started" });
|
|
4416
|
-
const
|
|
4417
|
-
const userMsg = { role: "user", content: cleanMessage };
|
|
4511
|
+
const userMsg = { role: "user", content: userMessage };
|
|
4418
4512
|
if (hidden) {
|
|
4419
4513
|
userMsg.hidden = true;
|
|
4420
4514
|
}
|
|
@@ -4428,7 +4522,7 @@ async function runTurn(params) {
|
|
|
4428
4522
|
state.messages.push(userMsg);
|
|
4429
4523
|
const STATUS_EXCLUDED_TOOLS = /* @__PURE__ */ new Set([
|
|
4430
4524
|
"setProjectOnboardingState",
|
|
4431
|
-
"
|
|
4525
|
+
"setProjectMetadata",
|
|
4432
4526
|
"clearSyncStatus",
|
|
4433
4527
|
"editsFinished"
|
|
4434
4528
|
]);
|
|
@@ -4615,7 +4709,8 @@ async function runTurn(params) {
|
|
|
4615
4709
|
id: event.id,
|
|
4616
4710
|
name: event.name,
|
|
4617
4711
|
input: event.input,
|
|
4618
|
-
startedAt: event.ts
|
|
4712
|
+
startedAt: event.ts,
|
|
4713
|
+
...event.input.background && { background: true }
|
|
4619
4714
|
});
|
|
4620
4715
|
const acc = toolInputAccumulators.get(event.id);
|
|
4621
4716
|
const tool = getToolByName(event.name);
|
|
@@ -4737,6 +4832,7 @@ async function runTurn(params) {
|
|
|
4737
4832
|
toolCallId: tc.id,
|
|
4738
4833
|
subAgentMessages,
|
|
4739
4834
|
toolRegistry,
|
|
4835
|
+
onBackgroundComplete,
|
|
4740
4836
|
onLog: (line) => wrappedOnEvent({
|
|
4741
4837
|
type: "tool_input_delta",
|
|
4742
4838
|
id: tc.id,
|
|
@@ -4843,7 +4939,7 @@ var init_agent = __esm({
|
|
|
4843
4939
|
"runScenario",
|
|
4844
4940
|
"runMethod",
|
|
4845
4941
|
"browserCommand",
|
|
4846
|
-
"
|
|
4942
|
+
"setProjectMetadata"
|
|
4847
4943
|
]);
|
|
4848
4944
|
}
|
|
4849
4945
|
});
|
|
@@ -5305,6 +5401,54 @@ async function startHeadless(opts = {}) {
|
|
|
5305
5401
|
const pendingTools = /* @__PURE__ */ new Map();
|
|
5306
5402
|
const earlyResults = /* @__PURE__ */ new Map();
|
|
5307
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
|
+
}
|
|
5308
5452
|
const USER_FACING_TOOLS = /* @__PURE__ */ new Set([
|
|
5309
5453
|
"promptUser",
|
|
5310
5454
|
"confirmDestructiveAction",
|
|
@@ -5345,6 +5489,7 @@ async function startHeadless(opts = {}) {
|
|
|
5345
5489
|
case "turn_done":
|
|
5346
5490
|
completedEmitted = true;
|
|
5347
5491
|
emit("completed", { success: true }, rid);
|
|
5492
|
+
setTimeout(() => flushBackgroundQueue(), 0);
|
|
5348
5493
|
return;
|
|
5349
5494
|
case "turn_cancelled":
|
|
5350
5495
|
completedEmitted = true;
|
|
@@ -5391,6 +5536,7 @@ async function startHeadless(opts = {}) {
|
|
|
5391
5536
|
name: e.name,
|
|
5392
5537
|
input: e.input,
|
|
5393
5538
|
...e.partial && { partial: true },
|
|
5539
|
+
...e.background && { background: true },
|
|
5394
5540
|
...e.parentToolId && { parentToolId: e.parentToolId }
|
|
5395
5541
|
},
|
|
5396
5542
|
rid
|
|
@@ -5409,6 +5555,18 @@ async function startHeadless(opts = {}) {
|
|
|
5409
5555
|
rid
|
|
5410
5556
|
);
|
|
5411
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;
|
|
5412
5570
|
case "tool_stopped":
|
|
5413
5571
|
emit(
|
|
5414
5572
|
"tool_stopped",
|
|
@@ -5476,6 +5634,7 @@ async function startHeadless(opts = {}) {
|
|
|
5476
5634
|
}
|
|
5477
5635
|
let userMessage = parsed.text ?? "";
|
|
5478
5636
|
const isCommand = !!parsed.runCommand;
|
|
5637
|
+
const isHidden = isCommand || !!parsed.hidden;
|
|
5479
5638
|
if (parsed.runCommand === "sync") {
|
|
5480
5639
|
userMessage = loadActionPrompt("sync");
|
|
5481
5640
|
} else if (parsed.runCommand === "publish") {
|
|
@@ -5500,8 +5659,9 @@ async function startHeadless(opts = {}) {
|
|
|
5500
5659
|
signal: currentAbort.signal,
|
|
5501
5660
|
onEvent,
|
|
5502
5661
|
resolveExternalTool,
|
|
5503
|
-
hidden:
|
|
5504
|
-
toolRegistry
|
|
5662
|
+
hidden: isHidden,
|
|
5663
|
+
toolRegistry,
|
|
5664
|
+
onBackgroundComplete
|
|
5505
5665
|
});
|
|
5506
5666
|
if (!completedEmitted) {
|
|
5507
5667
|
emit(
|