@mindstudio-ai/remy 0.1.175 → 0.1.176
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 +354 -155
- package/dist/index.js +389 -173
- package/dist/prompt/compiled/interfaces.md +27 -3
- package/package.json +1 -1
package/dist/headless.js
CHANGED
|
@@ -83,6 +83,7 @@ function resolveConfig(flags) {
|
|
|
83
83
|
const env = file.environments?.[activeEnv];
|
|
84
84
|
const apiKey = flags?.apiKey || process.env.MINDSTUDIO_API_KEY || env?.apiKey || "";
|
|
85
85
|
const baseUrl2 = flags?.baseUrl || process.env.MINDSTUDIO_BASE_URL || env?.apiBaseUrl || DEFAULT_BASE_URL;
|
|
86
|
+
const appId = process.env.MINDSTUDIO_APP_ID || void 0;
|
|
86
87
|
if (!apiKey) {
|
|
87
88
|
log.error("No API key found");
|
|
88
89
|
throw new Error(
|
|
@@ -93,9 +94,10 @@ function resolveConfig(flags) {
|
|
|
93
94
|
log.info("Config resolved", {
|
|
94
95
|
baseUrl: baseUrl2,
|
|
95
96
|
keySource,
|
|
96
|
-
environment: activeEnv
|
|
97
|
+
environment: activeEnv,
|
|
98
|
+
appId
|
|
97
99
|
});
|
|
98
|
-
return { apiKey, baseUrl: baseUrl2 };
|
|
100
|
+
return { apiKey, baseUrl: baseUrl2, appId };
|
|
99
101
|
}
|
|
100
102
|
|
|
101
103
|
// src/assets.ts
|
|
@@ -521,8 +523,10 @@ async function* streamChat(params) {
|
|
|
521
523
|
...subAgentId && { subAgentId },
|
|
522
524
|
durationMs: elapsed,
|
|
523
525
|
stopReason: event.stopReason,
|
|
526
|
+
modelId: event.modelId,
|
|
524
527
|
inputTokens: event.usage.inputTokens,
|
|
525
|
-
outputTokens: event.usage.outputTokens
|
|
528
|
+
outputTokens: event.usage.outputTokens,
|
|
529
|
+
cost: event.cost
|
|
526
530
|
});
|
|
527
531
|
} else if (event.type === "error") {
|
|
528
532
|
log2.error("SSE error event", {
|
|
@@ -611,6 +615,7 @@ async function generateBackgroundAck(params) {
|
|
|
611
615
|
Authorization: `Bearer ${params.apiConfig.apiKey}`
|
|
612
616
|
},
|
|
613
617
|
body: JSON.stringify({
|
|
618
|
+
appId: params.apiConfig.appId,
|
|
614
619
|
agentName: params.agentName,
|
|
615
620
|
task: params.task
|
|
616
621
|
}),
|
|
@@ -626,6 +631,24 @@ async function generateBackgroundAck(params) {
|
|
|
626
631
|
}
|
|
627
632
|
}
|
|
628
633
|
|
|
634
|
+
// src/usageLedger.ts
|
|
635
|
+
import fs5 from "fs";
|
|
636
|
+
var LEDGER_FILE = ".logs/usage.ndjson";
|
|
637
|
+
var fd = null;
|
|
638
|
+
function nanoToDollars(nano) {
|
|
639
|
+
return typeof nano === "number" ? nano / 1e9 : void 0;
|
|
640
|
+
}
|
|
641
|
+
function recordUsage(entry) {
|
|
642
|
+
try {
|
|
643
|
+
if (fd === null) {
|
|
644
|
+
fs5.mkdirSync(".logs", { recursive: true });
|
|
645
|
+
fd = fs5.openSync(LEDGER_FILE, "a");
|
|
646
|
+
}
|
|
647
|
+
fs5.writeSync(fd, JSON.stringify(entry) + "\n");
|
|
648
|
+
} catch {
|
|
649
|
+
}
|
|
650
|
+
}
|
|
651
|
+
|
|
629
652
|
// src/compaction/index.ts
|
|
630
653
|
var log3 = createLogger("compaction");
|
|
631
654
|
var CONVERSATION_SUMMARY_PROMPT = readAsset("compaction", "conversation.md");
|
|
@@ -840,6 +863,7 @@ async function generateSummary(apiConfig, name, compactionPrompt, messagesToSumm
|
|
|
840
863
|
Conversation to summarize:
|
|
841
864
|
|
|
842
865
|
${serialized}` : serialized;
|
|
866
|
+
const iterStart = Date.now();
|
|
843
867
|
for await (const event of streamChat({
|
|
844
868
|
...apiConfig,
|
|
845
869
|
subAgentId: "conversationSummarizer",
|
|
@@ -849,6 +873,20 @@ ${serialized}` : serialized;
|
|
|
849
873
|
})) {
|
|
850
874
|
if (event.type === "text") {
|
|
851
875
|
summaryText += event.text;
|
|
876
|
+
} else if (event.type === "done") {
|
|
877
|
+
recordUsage({
|
|
878
|
+
ts: Date.now(),
|
|
879
|
+
agentName: "conversationSummarizer",
|
|
880
|
+
modelId: event.modelId,
|
|
881
|
+
inputTokens: event.usage.inputTokens,
|
|
882
|
+
outputTokens: event.usage.outputTokens,
|
|
883
|
+
cacheCreationTokens: event.usage.cacheCreationTokens,
|
|
884
|
+
cacheReadTokens: event.usage.cacheReadTokens,
|
|
885
|
+
cost: nanoToDollars(event.cost),
|
|
886
|
+
billingEvents: event.billingEvents,
|
|
887
|
+
durationMs: Date.now() - iterStart,
|
|
888
|
+
toolNames: []
|
|
889
|
+
});
|
|
852
890
|
} else if (event.type === "error") {
|
|
853
891
|
log3.error("Summary generation failed", { name, error: event.error });
|
|
854
892
|
return null;
|
|
@@ -863,7 +901,7 @@ ${serialized}` : serialized;
|
|
|
863
901
|
}
|
|
864
902
|
|
|
865
903
|
// src/tools/spec/readSpec.ts
|
|
866
|
-
import
|
|
904
|
+
import fs6 from "fs/promises";
|
|
867
905
|
|
|
868
906
|
// src/tools/spec/_helpers.ts
|
|
869
907
|
var HEADING_RE = /^(#{1,6})\s+(.+)$/;
|
|
@@ -983,7 +1021,7 @@ var readSpecTool = {
|
|
|
983
1021
|
return `Error: ${err.message}`;
|
|
984
1022
|
}
|
|
985
1023
|
try {
|
|
986
|
-
const content = await
|
|
1024
|
+
const content = await fs6.readFile(input.path, "utf-8");
|
|
987
1025
|
const allLines = content.split("\n");
|
|
988
1026
|
const totalLines = allLines.length;
|
|
989
1027
|
const maxLines = input.maxLines === 0 ? Infinity : input.maxLines || DEFAULT_MAX_LINES;
|
|
@@ -1011,7 +1049,7 @@ var readSpecTool = {
|
|
|
1011
1049
|
};
|
|
1012
1050
|
|
|
1013
1051
|
// src/tools/spec/writeSpec.ts
|
|
1014
|
-
import
|
|
1052
|
+
import fs7 from "fs/promises";
|
|
1015
1053
|
import path4 from "path";
|
|
1016
1054
|
|
|
1017
1055
|
// src/tools/_helpers/diff.ts
|
|
@@ -1088,7 +1126,7 @@ var writeSpecTool = {
|
|
|
1088
1126
|
},
|
|
1089
1127
|
streaming: {
|
|
1090
1128
|
transform: async (partial) => {
|
|
1091
|
-
const oldContent = await
|
|
1129
|
+
const oldContent = await fs7.readFile(partial.path, "utf-8").catch(() => "");
|
|
1092
1130
|
const lineCount = partial.content.split("\n").length;
|
|
1093
1131
|
return `Writing ${partial.path} (${lineCount} lines)
|
|
1094
1132
|
${unifiedDiff(partial.path, oldContent, partial.content)}`;
|
|
@@ -1102,13 +1140,13 @@ ${unifiedDiff(partial.path, oldContent, partial.content)}`;
|
|
|
1102
1140
|
}
|
|
1103
1141
|
const release = await acquireFileLock(input.path);
|
|
1104
1142
|
try {
|
|
1105
|
-
await
|
|
1143
|
+
await fs7.mkdir(path4.dirname(input.path), { recursive: true });
|
|
1106
1144
|
let oldContent = null;
|
|
1107
1145
|
try {
|
|
1108
|
-
oldContent = await
|
|
1146
|
+
oldContent = await fs7.readFile(input.path, "utf-8");
|
|
1109
1147
|
} catch {
|
|
1110
1148
|
}
|
|
1111
|
-
await
|
|
1149
|
+
await fs7.writeFile(input.path, input.content, "utf-8");
|
|
1112
1150
|
const lineCount = input.content.split("\n").length;
|
|
1113
1151
|
const label = oldContent !== null ? "Wrote" : "Created";
|
|
1114
1152
|
return `${label} ${input.path} (${lineCount} lines)
|
|
@@ -1122,7 +1160,7 @@ ${unifiedDiff(input.path, oldContent ?? "", input.content)}`;
|
|
|
1122
1160
|
};
|
|
1123
1161
|
|
|
1124
1162
|
// src/tools/spec/editSpec.ts
|
|
1125
|
-
import
|
|
1163
|
+
import fs8 from "fs/promises";
|
|
1126
1164
|
var editSpecTool = {
|
|
1127
1165
|
clearable: true,
|
|
1128
1166
|
definition: {
|
|
@@ -1172,7 +1210,7 @@ var editSpecTool = {
|
|
|
1172
1210
|
try {
|
|
1173
1211
|
let originalContent;
|
|
1174
1212
|
try {
|
|
1175
|
-
originalContent = await
|
|
1213
|
+
originalContent = await fs8.readFile(input.path, "utf-8");
|
|
1176
1214
|
} catch (err) {
|
|
1177
1215
|
return `Error reading file: ${err.message}`;
|
|
1178
1216
|
}
|
|
@@ -1228,7 +1266,7 @@ ${tree}`;
|
|
|
1228
1266
|
content = lines.join("\n");
|
|
1229
1267
|
}
|
|
1230
1268
|
try {
|
|
1231
|
-
await
|
|
1269
|
+
await fs8.writeFile(input.path, content, "utf-8");
|
|
1232
1270
|
} catch (err) {
|
|
1233
1271
|
return `Error writing file: ${err.message}`;
|
|
1234
1272
|
}
|
|
@@ -1240,7 +1278,7 @@ ${tree}`;
|
|
|
1240
1278
|
};
|
|
1241
1279
|
|
|
1242
1280
|
// src/tools/spec/listSpecFiles.ts
|
|
1243
|
-
import
|
|
1281
|
+
import fs9 from "fs/promises";
|
|
1244
1282
|
import path5 from "path";
|
|
1245
1283
|
var listSpecFilesTool = {
|
|
1246
1284
|
clearable: false,
|
|
@@ -1270,7 +1308,7 @@ var listSpecFilesTool = {
|
|
|
1270
1308
|
};
|
|
1271
1309
|
async function listRecursive(dir) {
|
|
1272
1310
|
const results = [];
|
|
1273
|
-
const entries = await
|
|
1311
|
+
const entries = await fs9.readdir(dir, { withFileTypes: true });
|
|
1274
1312
|
entries.sort((a, b) => {
|
|
1275
1313
|
if (a.isDirectory() && !b.isDirectory()) {
|
|
1276
1314
|
return -1;
|
|
@@ -1316,7 +1354,7 @@ var presentPublishPlanTool = {
|
|
|
1316
1354
|
};
|
|
1317
1355
|
|
|
1318
1356
|
// src/tools/spec/writePlan.ts
|
|
1319
|
-
import
|
|
1357
|
+
import fs10 from "fs/promises";
|
|
1320
1358
|
var PLAN_FILE = ".remy-plan.md";
|
|
1321
1359
|
var writePlanTool = {
|
|
1322
1360
|
clearable: false,
|
|
@@ -1341,13 +1379,13 @@ status: pending
|
|
|
1341
1379
|
---
|
|
1342
1380
|
|
|
1343
1381
|
${content}`;
|
|
1344
|
-
await
|
|
1382
|
+
await fs10.writeFile(PLAN_FILE, file, "utf-8");
|
|
1345
1383
|
return "Plan written to .remy-plan.md. Waiting for user approval.";
|
|
1346
1384
|
}
|
|
1347
1385
|
};
|
|
1348
1386
|
|
|
1349
1387
|
// src/tools/spec/updatePlanStatus.ts
|
|
1350
|
-
import
|
|
1388
|
+
import fs11 from "fs/promises";
|
|
1351
1389
|
var PLAN_FILE2 = ".remy-plan.md";
|
|
1352
1390
|
var updatePlanStatusTool = {
|
|
1353
1391
|
clearable: false,
|
|
@@ -1370,15 +1408,15 @@ var updatePlanStatusTool = {
|
|
|
1370
1408
|
const status = input.status;
|
|
1371
1409
|
let content;
|
|
1372
1410
|
try {
|
|
1373
|
-
content = await
|
|
1411
|
+
content = await fs11.readFile(PLAN_FILE2, "utf-8");
|
|
1374
1412
|
} catch {
|
|
1375
1413
|
return "No plan file found.";
|
|
1376
1414
|
}
|
|
1377
1415
|
if (status === "rejected") {
|
|
1378
|
-
await
|
|
1416
|
+
await fs11.unlink(PLAN_FILE2);
|
|
1379
1417
|
return "Plan rejected and removed.";
|
|
1380
1418
|
}
|
|
1381
|
-
await
|
|
1419
|
+
await fs11.writeFile(
|
|
1382
1420
|
PLAN_FILE2,
|
|
1383
1421
|
content.replace(/^status:\s*\w+/m, `status: ${status}`),
|
|
1384
1422
|
"utf-8"
|
|
@@ -1684,6 +1722,90 @@ var askMindStudioSdkTool = {
|
|
|
1684
1722
|
}
|
|
1685
1723
|
};
|
|
1686
1724
|
|
|
1725
|
+
// src/subagents/common/runMindstudioCli.ts
|
|
1726
|
+
function stripFlags(args) {
|
|
1727
|
+
const out = [];
|
|
1728
|
+
for (let i = 0; i < args.length; i++) {
|
|
1729
|
+
const arg = args[i];
|
|
1730
|
+
if (arg === "--no-meta") {
|
|
1731
|
+
continue;
|
|
1732
|
+
}
|
|
1733
|
+
if (arg === "--output-key") {
|
|
1734
|
+
i++;
|
|
1735
|
+
continue;
|
|
1736
|
+
}
|
|
1737
|
+
out.push(arg);
|
|
1738
|
+
}
|
|
1739
|
+
return out;
|
|
1740
|
+
}
|
|
1741
|
+
async function runMindstudioCli(args, options) {
|
|
1742
|
+
const cleanArgs = stripFlags(args);
|
|
1743
|
+
const cliAction = args[0];
|
|
1744
|
+
const agentName = options?.caller ?? "mindstudio-cli";
|
|
1745
|
+
const start = Date.now();
|
|
1746
|
+
const raw = await runCli("mindstudio", cleanArgs, options);
|
|
1747
|
+
let envelope;
|
|
1748
|
+
try {
|
|
1749
|
+
envelope = JSON.parse(raw);
|
|
1750
|
+
} catch {
|
|
1751
|
+
return raw;
|
|
1752
|
+
}
|
|
1753
|
+
if (envelope && typeof envelope === "object" && Array.isArray(envelope.results)) {
|
|
1754
|
+
const durationMs = Date.now() - start;
|
|
1755
|
+
for (const step of envelope.results) {
|
|
1756
|
+
if (typeof step?.billingCost === "number") {
|
|
1757
|
+
recordUsage({
|
|
1758
|
+
ts: Date.now(),
|
|
1759
|
+
agentName,
|
|
1760
|
+
cliAction: `${cliAction}:${step.stepType ?? "step"}`,
|
|
1761
|
+
cost: nanoToDollars(step.billingCost),
|
|
1762
|
+
inputTokens: 0,
|
|
1763
|
+
outputTokens: 0,
|
|
1764
|
+
durationMs,
|
|
1765
|
+
toolNames: []
|
|
1766
|
+
});
|
|
1767
|
+
}
|
|
1768
|
+
}
|
|
1769
|
+
return JSON.stringify(envelope.results);
|
|
1770
|
+
}
|
|
1771
|
+
if (typeof envelope?.$billingCost === "number") {
|
|
1772
|
+
recordUsage({
|
|
1773
|
+
ts: Date.now(),
|
|
1774
|
+
agentName,
|
|
1775
|
+
cliAction,
|
|
1776
|
+
cost: nanoToDollars(envelope.$billingCost),
|
|
1777
|
+
billingEvents: envelope.$billingEvents,
|
|
1778
|
+
// CLI billing isn't expressed as input/output tokens for most actions
|
|
1779
|
+
// (image gen is per-image, scrape per-page, etc). `numUnits` inside each
|
|
1780
|
+
// billingEvent carries the per-event unit count.
|
|
1781
|
+
inputTokens: 0,
|
|
1782
|
+
outputTokens: 0,
|
|
1783
|
+
durationMs: Date.now() - start,
|
|
1784
|
+
toolNames: []
|
|
1785
|
+
});
|
|
1786
|
+
}
|
|
1787
|
+
if (options?.outputKey) {
|
|
1788
|
+
const v = envelope?.[options.outputKey];
|
|
1789
|
+
if (v === void 0 || v === null) {
|
|
1790
|
+
return JSON.stringify(stripDollarKeys(envelope));
|
|
1791
|
+
}
|
|
1792
|
+
return typeof v === "string" ? v : JSON.stringify(v);
|
|
1793
|
+
}
|
|
1794
|
+
return JSON.stringify(stripDollarKeys(envelope));
|
|
1795
|
+
}
|
|
1796
|
+
function stripDollarKeys(envelope) {
|
|
1797
|
+
if (!envelope || typeof envelope !== "object" || Array.isArray(envelope)) {
|
|
1798
|
+
return envelope;
|
|
1799
|
+
}
|
|
1800
|
+
const out = {};
|
|
1801
|
+
for (const [k, v] of Object.entries(envelope)) {
|
|
1802
|
+
if (!k.startsWith("$")) {
|
|
1803
|
+
out[k] = v;
|
|
1804
|
+
}
|
|
1805
|
+
}
|
|
1806
|
+
return out;
|
|
1807
|
+
}
|
|
1808
|
+
|
|
1687
1809
|
// src/tools/common/searchGoogle.ts
|
|
1688
1810
|
var searchGoogleTool = {
|
|
1689
1811
|
clearable: false,
|
|
@@ -1703,19 +1825,9 @@ var searchGoogleTool = {
|
|
|
1703
1825
|
},
|
|
1704
1826
|
async execute(input, context) {
|
|
1705
1827
|
const query = input.query;
|
|
1706
|
-
return
|
|
1707
|
-
"
|
|
1708
|
-
|
|
1709
|
-
"search-google",
|
|
1710
|
-
"--query",
|
|
1711
|
-
query,
|
|
1712
|
-
"--export-type",
|
|
1713
|
-
"json",
|
|
1714
|
-
"--output-key",
|
|
1715
|
-
"results",
|
|
1716
|
-
"--no-meta"
|
|
1717
|
-
],
|
|
1718
|
-
{ maxBuffer: 512 * 1024, onLog: context?.onLog }
|
|
1828
|
+
return runMindstudioCli(
|
|
1829
|
+
["search-google", "--query", query, "--export-type", "json"],
|
|
1830
|
+
{ outputKey: "results", maxBuffer: 512 * 1024, onLog: context?.onLog }
|
|
1719
1831
|
);
|
|
1720
1832
|
}
|
|
1721
1833
|
};
|
|
@@ -1779,7 +1891,7 @@ var compactConversationTool = {
|
|
|
1779
1891
|
};
|
|
1780
1892
|
|
|
1781
1893
|
// src/tools/code/readFile.ts
|
|
1782
|
-
import
|
|
1894
|
+
import fs12 from "fs/promises";
|
|
1783
1895
|
var DEFAULT_MAX_LINES2 = 500;
|
|
1784
1896
|
function isBinary(buffer) {
|
|
1785
1897
|
const sample = buffer.subarray(0, 8192);
|
|
@@ -1816,7 +1928,7 @@ var readFileTool = {
|
|
|
1816
1928
|
},
|
|
1817
1929
|
async execute(input) {
|
|
1818
1930
|
try {
|
|
1819
|
-
const buffer = await
|
|
1931
|
+
const buffer = await fs12.readFile(input.path);
|
|
1820
1932
|
if (isBinary(buffer)) {
|
|
1821
1933
|
const size = buffer.length;
|
|
1822
1934
|
const unit = size > 1024 * 1024 ? `${(size / (1024 * 1024)).toFixed(1)}MB` : `${(size / 1024).toFixed(1)}KB`;
|
|
@@ -1850,7 +1962,7 @@ var readFileTool = {
|
|
|
1850
1962
|
};
|
|
1851
1963
|
|
|
1852
1964
|
// src/tools/code/writeFile.ts
|
|
1853
|
-
import
|
|
1965
|
+
import fs13 from "fs/promises";
|
|
1854
1966
|
import path6 from "path";
|
|
1855
1967
|
var writeFileTool = {
|
|
1856
1968
|
clearable: true,
|
|
@@ -1888,7 +2000,7 @@ var writeFileTool = {
|
|
|
1888
2000
|
lastNewlineCount = newlineCount;
|
|
1889
2001
|
const lastNewline = partial.content.lastIndexOf("\n");
|
|
1890
2002
|
const completeContent = partial.content.substring(0, lastNewline + 1);
|
|
1891
|
-
const oldContent = await
|
|
2003
|
+
const oldContent = await fs13.readFile(partial.path, "utf-8").catch(() => "");
|
|
1892
2004
|
return `Writing ${partial.path} (${newlineCount} lines)
|
|
1893
2005
|
${unifiedDiff(partial.path, oldContent, completeContent)}`;
|
|
1894
2006
|
}
|
|
@@ -1897,13 +2009,13 @@ ${unifiedDiff(partial.path, oldContent, completeContent)}`;
|
|
|
1897
2009
|
async execute(input) {
|
|
1898
2010
|
const release = await acquireFileLock(input.path);
|
|
1899
2011
|
try {
|
|
1900
|
-
await
|
|
2012
|
+
await fs13.mkdir(path6.dirname(input.path), { recursive: true });
|
|
1901
2013
|
let oldContent = null;
|
|
1902
2014
|
try {
|
|
1903
|
-
oldContent = await
|
|
2015
|
+
oldContent = await fs13.readFile(input.path, "utf-8");
|
|
1904
2016
|
} catch {
|
|
1905
2017
|
}
|
|
1906
|
-
await
|
|
2018
|
+
await fs13.writeFile(input.path, input.content, "utf-8");
|
|
1907
2019
|
const lineCount = input.content.split("\n").length;
|
|
1908
2020
|
const label = oldContent !== null ? "Wrote" : "Created";
|
|
1909
2021
|
return `${label} ${input.path} (${lineCount} lines)
|
|
@@ -1917,7 +2029,7 @@ ${unifiedDiff(input.path, oldContent ?? "", input.content)}`;
|
|
|
1917
2029
|
};
|
|
1918
2030
|
|
|
1919
2031
|
// src/tools/code/editFile/index.ts
|
|
1920
|
-
import
|
|
2032
|
+
import fs14 from "fs/promises";
|
|
1921
2033
|
|
|
1922
2034
|
// src/tools/code/editFile/_helpers.ts
|
|
1923
2035
|
function buildLineOffsets(content) {
|
|
@@ -2030,7 +2142,7 @@ var editFileTool = {
|
|
|
2030
2142
|
async execute(input) {
|
|
2031
2143
|
const release = await acquireFileLock(input.path);
|
|
2032
2144
|
try {
|
|
2033
|
-
const content = await
|
|
2145
|
+
const content = await fs14.readFile(input.path, "utf-8");
|
|
2034
2146
|
const { old_string, new_string, replace_all } = input;
|
|
2035
2147
|
const occurrences = findOccurrences(content, old_string);
|
|
2036
2148
|
if (replace_all) {
|
|
@@ -2046,7 +2158,7 @@ var editFileTool = {
|
|
|
2046
2158
|
new_string
|
|
2047
2159
|
);
|
|
2048
2160
|
}
|
|
2049
|
-
await
|
|
2161
|
+
await fs14.writeFile(input.path, updated, "utf-8");
|
|
2050
2162
|
return `Replaced ${occurrences.length} occurrence${occurrences.length > 1 ? "s" : ""} in ${input.path}
|
|
2051
2163
|
${unifiedDiff(input.path, content, updated)}`;
|
|
2052
2164
|
}
|
|
@@ -2057,7 +2169,7 @@ ${unifiedDiff(input.path, content, updated)}`;
|
|
|
2057
2169
|
old_string.length,
|
|
2058
2170
|
new_string
|
|
2059
2171
|
);
|
|
2060
|
-
await
|
|
2172
|
+
await fs14.writeFile(input.path, updated, "utf-8");
|
|
2061
2173
|
return `Updated ${input.path}
|
|
2062
2174
|
${unifiedDiff(input.path, content, updated)}`;
|
|
2063
2175
|
}
|
|
@@ -2073,7 +2185,7 @@ ${unifiedDiff(input.path, content, updated)}`;
|
|
|
2073
2185
|
flex.matchedText.length,
|
|
2074
2186
|
new_string
|
|
2075
2187
|
);
|
|
2076
|
-
await
|
|
2188
|
+
await fs14.writeFile(input.path, updated, "utf-8");
|
|
2077
2189
|
return `Updated ${input.path} (matched with flexible whitespace at line ${flex.line})
|
|
2078
2190
|
${unifiedDiff(input.path, content, updated)}`;
|
|
2079
2191
|
}
|
|
@@ -2305,12 +2417,12 @@ var globTool = {
|
|
|
2305
2417
|
};
|
|
2306
2418
|
|
|
2307
2419
|
// src/tools/code/listDir.ts
|
|
2308
|
-
import
|
|
2420
|
+
import fs15 from "fs/promises";
|
|
2309
2421
|
import path7 from "path";
|
|
2310
2422
|
var EXCLUDE = /* @__PURE__ */ new Set([".git", "node_modules"]);
|
|
2311
2423
|
var MAX_CHILDREN = 15;
|
|
2312
2424
|
async function readAndSort(dirPath) {
|
|
2313
|
-
const entries = await
|
|
2425
|
+
const entries = await fs15.readdir(dirPath, { withFileTypes: true });
|
|
2314
2426
|
return entries.filter((e) => !EXCLUDE.has(e.name)).sort((a, b) => {
|
|
2315
2427
|
if (a.isDirectory() && !b.isDirectory()) {
|
|
2316
2428
|
return -1;
|
|
@@ -2351,7 +2463,7 @@ function formatSize(bytes) {
|
|
|
2351
2463
|
}
|
|
2352
2464
|
async function formatFile(dirPath, name, indent) {
|
|
2353
2465
|
try {
|
|
2354
|
-
const stat = await
|
|
2466
|
+
const stat = await fs15.stat(path7.join(dirPath, name));
|
|
2355
2467
|
return `${indent}${name}${" ".repeat(Math.max(1, 30 - indent.length - name.length))}${formatSize(stat.size)}`;
|
|
2356
2468
|
} catch {
|
|
2357
2469
|
return `${indent}${name}`;
|
|
@@ -2661,8 +2773,7 @@ var VISION_MODEL_OVERRIDE = {
|
|
|
2661
2773
|
};
|
|
2662
2774
|
async function analyzeImage(params) {
|
|
2663
2775
|
const { prompt, imageUrl, timeout = 2e5, onLog } = params;
|
|
2664
|
-
return
|
|
2665
|
-
"mindstudio",
|
|
2776
|
+
return runMindstudioCli(
|
|
2666
2777
|
[
|
|
2667
2778
|
"analyze-image",
|
|
2668
2779
|
"--prompt",
|
|
@@ -2670,12 +2781,9 @@ async function analyzeImage(params) {
|
|
|
2670
2781
|
"--image-url",
|
|
2671
2782
|
imageUrl,
|
|
2672
2783
|
"--vision-model-override",
|
|
2673
|
-
JSON.stringify(VISION_MODEL_OVERRIDE)
|
|
2674
|
-
"--output-key",
|
|
2675
|
-
"analysis",
|
|
2676
|
-
"--no-meta"
|
|
2784
|
+
JSON.stringify(VISION_MODEL_OVERRIDE)
|
|
2677
2785
|
],
|
|
2678
|
-
{ timeout, onLog }
|
|
2786
|
+
{ outputKey: "analysis", timeout, onLog }
|
|
2679
2787
|
);
|
|
2680
2788
|
}
|
|
2681
2789
|
|
|
@@ -2719,11 +2827,11 @@ async function captureAndAnalyzeScreenshot(promptOrOptions) {
|
|
|
2719
2827
|
let prompt;
|
|
2720
2828
|
let existingUrl;
|
|
2721
2829
|
let onLog;
|
|
2722
|
-
let
|
|
2830
|
+
let path12;
|
|
2723
2831
|
if (typeof promptOrOptions === "object" && promptOrOptions !== null) {
|
|
2724
2832
|
prompt = promptOrOptions.prompt;
|
|
2725
2833
|
existingUrl = promptOrOptions.imageUrl;
|
|
2726
|
-
|
|
2834
|
+
path12 = promptOrOptions.path;
|
|
2727
2835
|
onLog = promptOrOptions.onLog;
|
|
2728
2836
|
} else {
|
|
2729
2837
|
prompt = promptOrOptions;
|
|
@@ -2735,7 +2843,7 @@ async function captureAndAnalyzeScreenshot(promptOrOptions) {
|
|
|
2735
2843
|
} else {
|
|
2736
2844
|
const ssResult = await sidecarRequest(
|
|
2737
2845
|
"/screenshot-full-page",
|
|
2738
|
-
|
|
2846
|
+
path12 ? { path: path12 } : void 0,
|
|
2739
2847
|
{ timeout: 12e4 }
|
|
2740
2848
|
);
|
|
2741
2849
|
url = ssResult?.url || ssResult?.screenshotUrl;
|
|
@@ -2792,7 +2900,7 @@ function startStatusWatcher(config) {
|
|
|
2792
2900
|
"Content-Type": "application/json",
|
|
2793
2901
|
Authorization: `Bearer ${apiConfig.apiKey}`
|
|
2794
2902
|
},
|
|
2795
|
-
body: JSON.stringify({ context }),
|
|
2903
|
+
body: JSON.stringify({ appId: apiConfig.appId, context }),
|
|
2796
2904
|
signal
|
|
2797
2905
|
});
|
|
2798
2906
|
if (!res.ok || stopped) {
|
|
@@ -2984,8 +3092,14 @@ ${content}` : attachmentHeader;
|
|
|
2984
3092
|
const text = blocks.filter((b) => b.type === "text").map((b) => b.text).join("");
|
|
2985
3093
|
const toolCalls = blocks.filter((b) => b.type === "tool").map((b) => ({ id: b.id, name: b.name, input: b.input }));
|
|
2986
3094
|
const thinking = blocks.filter(
|
|
2987
|
-
(b) => b.type === "thinking"
|
|
2988
|
-
).map(
|
|
3095
|
+
(b) => b.type === "thinking" || b.type === "redacted_thinking"
|
|
3096
|
+
).map(
|
|
3097
|
+
(b) => b.type === "thinking" ? {
|
|
3098
|
+
type: "thinking",
|
|
3099
|
+
thinking: b.thinking,
|
|
3100
|
+
signature: b.signature
|
|
3101
|
+
} : { type: "redacted_thinking", data: b.data }
|
|
3102
|
+
);
|
|
2989
3103
|
const cleaned2 = {
|
|
2990
3104
|
role: msg.role,
|
|
2991
3105
|
content: text
|
|
@@ -3075,10 +3189,13 @@ ${partial}` : "[INTERRUPTED] Agent was interrupted before producing output.",
|
|
|
3075
3189
|
if (signal?.aborted) {
|
|
3076
3190
|
return abortResult([]);
|
|
3077
3191
|
}
|
|
3192
|
+
const iterStart = Date.now();
|
|
3078
3193
|
const contentBlocks = [];
|
|
3079
3194
|
let thinkingStartedAt = 0;
|
|
3195
|
+
let lastThinkingRelatedStartedAt;
|
|
3080
3196
|
let stopReason = "end_turn";
|
|
3081
3197
|
let currentToolNames = "";
|
|
3198
|
+
let lastUsage;
|
|
3082
3199
|
const statusWatcher = startStatusWatcher({
|
|
3083
3200
|
apiConfig,
|
|
3084
3201
|
getContext: () => {
|
|
@@ -3153,8 +3270,20 @@ ${partial}` : "[INTERRUPTED] Agent was interrupted before producing output.",
|
|
|
3153
3270
|
startedAt: thinkingStartedAt,
|
|
3154
3271
|
completedAt: event.ts
|
|
3155
3272
|
});
|
|
3273
|
+
lastThinkingRelatedStartedAt = thinkingStartedAt;
|
|
3156
3274
|
thinkingStartedAt = 0;
|
|
3157
3275
|
break;
|
|
3276
|
+
case "redacted_thinking_complete": {
|
|
3277
|
+
const startedAt = lastThinkingRelatedStartedAt !== void 0 ? lastThinkingRelatedStartedAt + 1 : event.ts;
|
|
3278
|
+
contentBlocks.push({
|
|
3279
|
+
type: "redacted_thinking",
|
|
3280
|
+
data: event.data,
|
|
3281
|
+
startedAt,
|
|
3282
|
+
completedAt: event.ts
|
|
3283
|
+
});
|
|
3284
|
+
lastThinkingRelatedStartedAt = startedAt;
|
|
3285
|
+
break;
|
|
3286
|
+
}
|
|
3158
3287
|
case "tool_use":
|
|
3159
3288
|
contentBlocks.push({
|
|
3160
3289
|
type: "tool",
|
|
@@ -3172,6 +3301,30 @@ ${partial}` : "[INTERRUPTED] Agent was interrupted before producing output.",
|
|
|
3172
3301
|
break;
|
|
3173
3302
|
case "done":
|
|
3174
3303
|
stopReason = event.stopReason;
|
|
3304
|
+
lastUsage = {
|
|
3305
|
+
inputTokens: event.usage.inputTokens,
|
|
3306
|
+
outputTokens: event.usage.outputTokens,
|
|
3307
|
+
cacheCreationTokens: event.usage.cacheCreationTokens,
|
|
3308
|
+
cacheReadTokens: event.usage.cacheReadTokens,
|
|
3309
|
+
llmCalls: 1
|
|
3310
|
+
};
|
|
3311
|
+
recordUsage({
|
|
3312
|
+
ts: Date.now(),
|
|
3313
|
+
requestId,
|
|
3314
|
+
agentName: subAgentId || "sub-agent",
|
|
3315
|
+
parentToolId,
|
|
3316
|
+
modelId: event.modelId,
|
|
3317
|
+
inputTokens: event.usage.inputTokens,
|
|
3318
|
+
outputTokens: event.usage.outputTokens,
|
|
3319
|
+
cacheCreationTokens: event.usage.cacheCreationTokens,
|
|
3320
|
+
cacheReadTokens: event.usage.cacheReadTokens,
|
|
3321
|
+
cost: nanoToDollars(event.cost),
|
|
3322
|
+
billingEvents: event.billingEvents,
|
|
3323
|
+
durationMs: Date.now() - iterStart,
|
|
3324
|
+
toolNames: contentBlocks.filter(
|
|
3325
|
+
(b) => b.type === "tool"
|
|
3326
|
+
).map((b) => b.name)
|
|
3327
|
+
});
|
|
3175
3328
|
break;
|
|
3176
3329
|
case "error":
|
|
3177
3330
|
return {
|
|
@@ -3191,7 +3344,8 @@ ${partial}` : "[INTERRUPTED] Agent was interrupted before producing output.",
|
|
|
3191
3344
|
}
|
|
3192
3345
|
messages.push({
|
|
3193
3346
|
role: "assistant",
|
|
3194
|
-
content: contentBlocks
|
|
3347
|
+
content: contentBlocks,
|
|
3348
|
+
...lastUsage ? { usage: lastUsage } : {}
|
|
3195
3349
|
});
|
|
3196
3350
|
const toolCalls = contentBlocks.filter(
|
|
3197
3351
|
(b) => b.type === "tool"
|
|
@@ -3517,11 +3671,11 @@ var BROWSER_TOOLS = [
|
|
|
3517
3671
|
var BROWSER_EXTERNAL_TOOLS = /* @__PURE__ */ new Set(["browserCommand"]);
|
|
3518
3672
|
|
|
3519
3673
|
// src/subagents/browserAutomation/prompt.ts
|
|
3520
|
-
import
|
|
3674
|
+
import fs16 from "fs";
|
|
3521
3675
|
var BASE_PROMPT = readAsset("subagents/browserAutomation", "prompt.md");
|
|
3522
3676
|
function getBrowserAutomationPrompt() {
|
|
3523
3677
|
try {
|
|
3524
|
-
const appSpec =
|
|
3678
|
+
const appSpec = fs16.readFileSync("src/app.md", "utf-8").trim();
|
|
3525
3679
|
return `${BASE_PROMPT}
|
|
3526
3680
|
|
|
3527
3681
|
<!-- cache_breakpoint -->
|
|
@@ -3620,10 +3774,9 @@ var browserAutomationTool = {
|
|
|
3620
3774
|
visionModelOverride: VISION_MODEL_OVERRIDE
|
|
3621
3775
|
}
|
|
3622
3776
|
}));
|
|
3623
|
-
const batchResult = await
|
|
3624
|
-
"
|
|
3625
|
-
|
|
3626
|
-
{ timeout: 2e5 }
|
|
3777
|
+
const batchResult = await runMindstudioCli(
|
|
3778
|
+
["batch", JSON.stringify(batchInput)],
|
|
3779
|
+
{ timeout: 2e5, caller: "browserAutomation" }
|
|
3627
3780
|
);
|
|
3628
3781
|
try {
|
|
3629
3782
|
const analyses = JSON.parse(batchResult);
|
|
@@ -3846,19 +3999,9 @@ var definition = {
|
|
|
3846
3999
|
}
|
|
3847
4000
|
};
|
|
3848
4001
|
async function execute(input, onLog) {
|
|
3849
|
-
return
|
|
3850
|
-
"
|
|
3851
|
-
|
|
3852
|
-
"search-google",
|
|
3853
|
-
"--query",
|
|
3854
|
-
input.query,
|
|
3855
|
-
"--export-type",
|
|
3856
|
-
"json",
|
|
3857
|
-
"--output-key",
|
|
3858
|
-
"results",
|
|
3859
|
-
"--no-meta"
|
|
3860
|
-
],
|
|
3861
|
-
{ onLog }
|
|
4002
|
+
return runMindstudioCli(
|
|
4003
|
+
["search-google", "--query", input.query, "--export-type", "json"],
|
|
4004
|
+
{ outputKey: "results", onLog, caller: "designExpert" }
|
|
3862
4005
|
);
|
|
3863
4006
|
}
|
|
3864
4007
|
|
|
@@ -3888,17 +4031,15 @@ async function execute2(input, onLog) {
|
|
|
3888
4031
|
if (input.screenshot) {
|
|
3889
4032
|
pageOptions.screenshot = true;
|
|
3890
4033
|
}
|
|
3891
|
-
return
|
|
3892
|
-
"mindstudio",
|
|
4034
|
+
return runMindstudioCli(
|
|
3893
4035
|
[
|
|
3894
4036
|
"scrape-url",
|
|
3895
4037
|
"--url",
|
|
3896
4038
|
input.url,
|
|
3897
4039
|
"--page-options",
|
|
3898
|
-
JSON.stringify(pageOptions)
|
|
3899
|
-
"--no-meta"
|
|
4040
|
+
JSON.stringify(pageOptions)
|
|
3900
4041
|
],
|
|
3901
|
-
{ onLog }
|
|
4042
|
+
{ onLog, caller: "designExpert" }
|
|
3902
4043
|
);
|
|
3903
4044
|
}
|
|
3904
4045
|
|
|
@@ -3956,8 +4097,7 @@ async function execute3(input, onLog) {
|
|
|
3956
4097
|
const isImageUrl = /\.(png|jpe?g|webp|gif|svg|avif)(\?|$)/i.test(url);
|
|
3957
4098
|
let imageUrl = url;
|
|
3958
4099
|
if (!isImageUrl) {
|
|
3959
|
-
const ssUrl = await
|
|
3960
|
-
"mindstudio",
|
|
4100
|
+
const ssUrl = await runMindstudioCli(
|
|
3961
4101
|
[
|
|
3962
4102
|
"screenshot-url",
|
|
3963
4103
|
"--url",
|
|
@@ -3967,12 +4107,14 @@ async function execute3(input, onLog) {
|
|
|
3967
4107
|
"--width",
|
|
3968
4108
|
"1440",
|
|
3969
4109
|
"--delay",
|
|
3970
|
-
"2000"
|
|
3971
|
-
"--output-key",
|
|
3972
|
-
"screenshotUrl",
|
|
3973
|
-
"--no-meta"
|
|
4110
|
+
"2000"
|
|
3974
4111
|
],
|
|
3975
|
-
{
|
|
4112
|
+
{
|
|
4113
|
+
outputKey: "screenshotUrl",
|
|
4114
|
+
timeout: 12e4,
|
|
4115
|
+
onLog,
|
|
4116
|
+
caller: "designExpert"
|
|
4117
|
+
}
|
|
3976
4118
|
);
|
|
3977
4119
|
if (ssUrl.startsWith("Error")) {
|
|
3978
4120
|
return `Could not screenshot ${url}: ${ssUrl}`;
|
|
@@ -4130,19 +4272,15 @@ ${context}
|
|
|
4130
4272
|
<brief>
|
|
4131
4273
|
${brief}
|
|
4132
4274
|
</brief>`;
|
|
4133
|
-
const enhanced = await
|
|
4134
|
-
"mindstudio",
|
|
4275
|
+
const enhanced = await runMindstudioCli(
|
|
4135
4276
|
[
|
|
4136
4277
|
"generate-text",
|
|
4137
4278
|
"--message",
|
|
4138
4279
|
message,
|
|
4139
4280
|
"--model-override",
|
|
4140
|
-
JSON.stringify(MODEL_OVERRIDE)
|
|
4141
|
-
"--output-key",
|
|
4142
|
-
"content",
|
|
4143
|
-
"--no-meta"
|
|
4281
|
+
JSON.stringify(MODEL_OVERRIDE)
|
|
4144
4282
|
],
|
|
4145
|
-
{ timeout: 6e4, onLog }
|
|
4283
|
+
{ outputKey: "content", timeout: 6e4, onLog, caller: "designExpert" }
|
|
4146
4284
|
);
|
|
4147
4285
|
return enhanced.trim();
|
|
4148
4286
|
}
|
|
@@ -4178,11 +4316,14 @@ async function generateImageAssets(opts) {
|
|
|
4178
4316
|
config
|
|
4179
4317
|
}
|
|
4180
4318
|
});
|
|
4181
|
-
const url = await
|
|
4182
|
-
"
|
|
4183
|
-
|
|
4184
|
-
|
|
4185
|
-
|
|
4319
|
+
const url = await runMindstudioCli(["generate-image"], {
|
|
4320
|
+
outputKey: "imageUrl",
|
|
4321
|
+
jsonLogs: true,
|
|
4322
|
+
timeout: 2e5,
|
|
4323
|
+
onLog,
|
|
4324
|
+
stdin: step,
|
|
4325
|
+
caller: "designExpert"
|
|
4326
|
+
});
|
|
4186
4327
|
imageUrls = [url];
|
|
4187
4328
|
} else {
|
|
4188
4329
|
const steps = enhancedPrompts.map((prompt) => ({
|
|
@@ -4195,11 +4336,12 @@ async function generateImageAssets(opts) {
|
|
|
4195
4336
|
}
|
|
4196
4337
|
}
|
|
4197
4338
|
}));
|
|
4198
|
-
const batchResult = await
|
|
4339
|
+
const batchResult = await runMindstudioCli(["batch"], {
|
|
4199
4340
|
jsonLogs: true,
|
|
4200
4341
|
timeout: 2e5,
|
|
4201
4342
|
onLog,
|
|
4202
|
-
stdin: JSON.stringify(steps)
|
|
4343
|
+
stdin: JSON.stringify(steps),
|
|
4344
|
+
caller: "designExpert"
|
|
4203
4345
|
});
|
|
4204
4346
|
try {
|
|
4205
4347
|
const parsed = JSON.parse(batchResult);
|
|
@@ -4216,17 +4358,14 @@ async function generateImageAssets(opts) {
|
|
|
4216
4358
|
if (url.startsWith("Error")) {
|
|
4217
4359
|
return url;
|
|
4218
4360
|
}
|
|
4219
|
-
const result = await
|
|
4220
|
-
"
|
|
4221
|
-
|
|
4222
|
-
"
|
|
4223
|
-
|
|
4224
|
-
|
|
4225
|
-
"
|
|
4226
|
-
|
|
4227
|
-
"--no-meta"
|
|
4228
|
-
],
|
|
4229
|
-
{ timeout: 2e5, onLog }
|
|
4361
|
+
const result = await runMindstudioCli(
|
|
4362
|
+
["remove-background-from-image", "--image-url", url],
|
|
4363
|
+
{
|
|
4364
|
+
outputKey: "imageUrl",
|
|
4365
|
+
timeout: 2e5,
|
|
4366
|
+
onLog,
|
|
4367
|
+
caller: "designExpert"
|
|
4368
|
+
}
|
|
4230
4369
|
);
|
|
4231
4370
|
return result.startsWith("Error") ? url : result;
|
|
4232
4371
|
})
|
|
@@ -4378,12 +4517,12 @@ async function executeDesignExpertTool(name, input, context, toolCallId, onLog)
|
|
|
4378
4517
|
}
|
|
4379
4518
|
|
|
4380
4519
|
// src/subagents/common/context.ts
|
|
4381
|
-
import
|
|
4520
|
+
import fs17 from "fs";
|
|
4382
4521
|
import path8 from "path";
|
|
4383
4522
|
function walkMdFiles2(dir, skip) {
|
|
4384
4523
|
const files = [];
|
|
4385
4524
|
try {
|
|
4386
|
-
for (const entry of
|
|
4525
|
+
for (const entry of fs17.readdirSync(dir, { withFileTypes: true })) {
|
|
4387
4526
|
const full = path8.join(dir, entry.name);
|
|
4388
4527
|
if (entry.isDirectory()) {
|
|
4389
4528
|
if (!skip?.has(entry.name)) {
|
|
@@ -4399,7 +4538,7 @@ function walkMdFiles2(dir, skip) {
|
|
|
4399
4538
|
}
|
|
4400
4539
|
function parseFrontmatter2(filePath) {
|
|
4401
4540
|
try {
|
|
4402
|
-
const content =
|
|
4541
|
+
const content = fs17.readFileSync(filePath, "utf-8");
|
|
4403
4542
|
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
4404
4543
|
if (!match) {
|
|
4405
4544
|
return {};
|
|
@@ -4445,7 +4584,7 @@ function loadRoadmapIndex() {
|
|
|
4445
4584
|
const parts = [];
|
|
4446
4585
|
try {
|
|
4447
4586
|
const indexJson = JSON.parse(
|
|
4448
|
-
|
|
4587
|
+
fs17.readFileSync("src/roadmap/index.json", "utf-8")
|
|
4449
4588
|
);
|
|
4450
4589
|
if (indexJson.lanes?.length > 0) {
|
|
4451
4590
|
const laneLines = indexJson.lanes.map(
|
|
@@ -4548,7 +4687,7 @@ The first-party SDK (@mindstudio-ai/agent) provides access to 200+ AI models (Op
|
|
|
4548
4687
|
}
|
|
4549
4688
|
|
|
4550
4689
|
// src/subagents/designExpert/data/sampleCache.ts
|
|
4551
|
-
import
|
|
4690
|
+
import fs18 from "fs";
|
|
4552
4691
|
var SAMPLE_FILE = ".remy-design-sample.json";
|
|
4553
4692
|
var cached = null;
|
|
4554
4693
|
function generateIndices(poolSize, sampleSize) {
|
|
@@ -4562,14 +4701,14 @@ function generateIndices(poolSize, sampleSize) {
|
|
|
4562
4701
|
}
|
|
4563
4702
|
function load() {
|
|
4564
4703
|
try {
|
|
4565
|
-
return JSON.parse(
|
|
4704
|
+
return JSON.parse(fs18.readFileSync(SAMPLE_FILE, "utf-8"));
|
|
4566
4705
|
} catch {
|
|
4567
4706
|
return null;
|
|
4568
4707
|
}
|
|
4569
4708
|
}
|
|
4570
4709
|
function save(indices) {
|
|
4571
4710
|
try {
|
|
4572
|
-
|
|
4711
|
+
fs18.writeFileSync(SAMPLE_FILE, JSON.stringify(indices));
|
|
4573
4712
|
} catch {
|
|
4574
4713
|
}
|
|
4575
4714
|
}
|
|
@@ -4898,7 +5037,7 @@ var VISION_TOOLS = [
|
|
|
4898
5037
|
];
|
|
4899
5038
|
|
|
4900
5039
|
// src/subagents/productVision/executor.ts
|
|
4901
|
-
import
|
|
5040
|
+
import fs19 from "fs";
|
|
4902
5041
|
import path9 from "path";
|
|
4903
5042
|
var ROADMAP_DIR = "src/roadmap";
|
|
4904
5043
|
var PITCH_DECK_SHELL = readAsset(
|
|
@@ -4913,13 +5052,13 @@ async function executeVisionTool(name, input, context) {
|
|
|
4913
5052
|
case "writeFile": {
|
|
4914
5053
|
const filePath = resolve(input.path);
|
|
4915
5054
|
try {
|
|
4916
|
-
|
|
5055
|
+
fs19.mkdirSync(ROADMAP_DIR, { recursive: true });
|
|
4917
5056
|
let oldContent = null;
|
|
4918
5057
|
try {
|
|
4919
|
-
oldContent =
|
|
5058
|
+
oldContent = fs19.readFileSync(filePath, "utf-8");
|
|
4920
5059
|
} catch {
|
|
4921
5060
|
}
|
|
4922
|
-
|
|
5061
|
+
fs19.writeFileSync(filePath, input.content, "utf-8");
|
|
4923
5062
|
const lineCount = input.content.split("\n").length;
|
|
4924
5063
|
const label = oldContent !== null ? "Wrote" : "Created";
|
|
4925
5064
|
return `${label} ${filePath} (${lineCount} lines)
|
|
@@ -4931,11 +5070,11 @@ ${unifiedDiff(filePath, oldContent ?? "", input.content)}`;
|
|
|
4931
5070
|
case "deleteFile": {
|
|
4932
5071
|
const filePath = resolve(input.path);
|
|
4933
5072
|
try {
|
|
4934
|
-
if (!
|
|
5073
|
+
if (!fs19.existsSync(filePath)) {
|
|
4935
5074
|
return `Error: ${filePath} does not exist`;
|
|
4936
5075
|
}
|
|
4937
|
-
const oldContent =
|
|
4938
|
-
|
|
5076
|
+
const oldContent = fs19.readFileSync(filePath, "utf-8");
|
|
5077
|
+
fs19.unlinkSync(filePath);
|
|
4939
5078
|
return `Deleted ${filePath}
|
|
4940
5079
|
${unifiedDiff(filePath, oldContent, "")}`;
|
|
4941
5080
|
} catch (err) {
|
|
@@ -4948,8 +5087,8 @@ ${unifiedDiff(filePath, oldContent, "")}`;
|
|
|
4948
5087
|
}
|
|
4949
5088
|
const filePath = resolve("pitch.html");
|
|
4950
5089
|
try {
|
|
4951
|
-
|
|
4952
|
-
const existing =
|
|
5090
|
+
fs19.mkdirSync(ROADMAP_DIR, { recursive: true });
|
|
5091
|
+
const existing = fs19.existsSync(filePath) ? fs19.readFileSync(filePath, "utf-8").trim() : "";
|
|
4953
5092
|
const currentDeck = existing || PITCH_DECK_SHELL;
|
|
4954
5093
|
const task = `
|
|
4955
5094
|
<pitch_content>${input.task}</pitch_content>
|
|
@@ -4974,7 +5113,7 @@ Respond only with the complete HTML file and absolutely no other text. Your resp
|
|
|
4974
5113
|
/```(?:html|wireframe)\n([\s\S]*?)```/
|
|
4975
5114
|
);
|
|
4976
5115
|
const html = htmlMatch ? htmlMatch[1].trim() : result;
|
|
4977
|
-
|
|
5116
|
+
fs19.writeFileSync(filePath, html, "utf-8");
|
|
4978
5117
|
return `Pitch deck written successfully.`;
|
|
4979
5118
|
} catch (err) {
|
|
4980
5119
|
return `Error generating pitch deck: ${err.message}`;
|
|
@@ -5191,15 +5330,13 @@ var scrapeWebUrlTool = {
|
|
|
5191
5330
|
if (screenshot) {
|
|
5192
5331
|
pageOptions.screenshot = true;
|
|
5193
5332
|
}
|
|
5194
|
-
return
|
|
5195
|
-
"mindstudio",
|
|
5333
|
+
return runMindstudioCli(
|
|
5196
5334
|
[
|
|
5197
5335
|
"scrape-url",
|
|
5198
5336
|
"--url",
|
|
5199
5337
|
url,
|
|
5200
5338
|
"--page-options",
|
|
5201
|
-
JSON.stringify(pageOptions)
|
|
5202
|
-
"--no-meta"
|
|
5339
|
+
JSON.stringify(pageOptions)
|
|
5203
5340
|
],
|
|
5204
5341
|
{ onLog: context?.onLog }
|
|
5205
5342
|
);
|
|
@@ -5307,7 +5444,7 @@ function triggerCompaction(state, apiConfig, opts = {}) {
|
|
|
5307
5444
|
}
|
|
5308
5445
|
|
|
5309
5446
|
// src/brandExtraction/index.ts
|
|
5310
|
-
import
|
|
5447
|
+
import fs20 from "fs";
|
|
5311
5448
|
import path10 from "path";
|
|
5312
5449
|
import { createHash } from "crypto";
|
|
5313
5450
|
var log8 = createLogger("brandExtraction");
|
|
@@ -5356,7 +5493,7 @@ function sha256(input) {
|
|
|
5356
5493
|
}
|
|
5357
5494
|
function readSafe(filePath) {
|
|
5358
5495
|
try {
|
|
5359
|
-
return
|
|
5496
|
+
return fs20.readFileSync(filePath, "utf-8");
|
|
5360
5497
|
} catch {
|
|
5361
5498
|
return "";
|
|
5362
5499
|
}
|
|
@@ -5364,7 +5501,7 @@ function readSafe(filePath) {
|
|
|
5364
5501
|
function walkMdFiles3(dir) {
|
|
5365
5502
|
const results = [];
|
|
5366
5503
|
try {
|
|
5367
|
-
const entries =
|
|
5504
|
+
const entries = fs20.readdirSync(dir, { withFileTypes: true });
|
|
5368
5505
|
for (const entry of entries) {
|
|
5369
5506
|
const full = path10.join(dir, entry.name);
|
|
5370
5507
|
if (entry.isDirectory()) {
|
|
@@ -5379,7 +5516,7 @@ function walkMdFiles3(dir) {
|
|
|
5379
5516
|
}
|
|
5380
5517
|
function parseFrontmatter3(filePath) {
|
|
5381
5518
|
try {
|
|
5382
|
-
const content =
|
|
5519
|
+
const content = fs20.readFileSync(filePath, "utf-8");
|
|
5383
5520
|
const match = content.match(/^---\n([\s\S]*?)\n---/);
|
|
5384
5521
|
if (!match) {
|
|
5385
5522
|
return { type: "" };
|
|
@@ -5398,6 +5535,7 @@ async function extractBrand(apiConfig) {
|
|
|
5398
5535
|
return { version: 1 };
|
|
5399
5536
|
}
|
|
5400
5537
|
let responseText = "";
|
|
5538
|
+
const iterStart = Date.now();
|
|
5401
5539
|
try {
|
|
5402
5540
|
for await (const event of streamChat({
|
|
5403
5541
|
...apiConfig,
|
|
@@ -5408,6 +5546,20 @@ async function extractBrand(apiConfig) {
|
|
|
5408
5546
|
})) {
|
|
5409
5547
|
if (event.type === "text") {
|
|
5410
5548
|
responseText += event.text;
|
|
5549
|
+
} else if (event.type === "done") {
|
|
5550
|
+
recordUsage({
|
|
5551
|
+
ts: Date.now(),
|
|
5552
|
+
agentName: "brandExtractor",
|
|
5553
|
+
modelId: event.modelId,
|
|
5554
|
+
inputTokens: event.usage.inputTokens,
|
|
5555
|
+
outputTokens: event.usage.outputTokens,
|
|
5556
|
+
cacheCreationTokens: event.usage.cacheCreationTokens,
|
|
5557
|
+
cacheReadTokens: event.usage.cacheReadTokens,
|
|
5558
|
+
cost: nanoToDollars(event.cost),
|
|
5559
|
+
billingEvents: event.billingEvents,
|
|
5560
|
+
durationMs: Date.now() - iterStart,
|
|
5561
|
+
toolNames: []
|
|
5562
|
+
});
|
|
5411
5563
|
} else if (event.type === "error") {
|
|
5412
5564
|
log8.error("Brand extraction stream error", { error: event.error });
|
|
5413
5565
|
return null;
|
|
@@ -5542,14 +5694,14 @@ function pickFont(raw) {
|
|
|
5542
5694
|
}
|
|
5543
5695
|
function persistBrand(brand, inputHash) {
|
|
5544
5696
|
const tmp = `${BRAND_FILE}.tmp`;
|
|
5545
|
-
|
|
5546
|
-
|
|
5697
|
+
fs20.writeFileSync(tmp, JSON.stringify(brand, null, 2), "utf-8");
|
|
5698
|
+
fs20.renameSync(tmp, BRAND_FILE);
|
|
5547
5699
|
const cache = { inputHash, generatedAt: Date.now() };
|
|
5548
|
-
|
|
5700
|
+
fs20.writeFileSync(CACHE_FILE, JSON.stringify(cache, null, 2), "utf-8");
|
|
5549
5701
|
}
|
|
5550
5702
|
function readCache() {
|
|
5551
5703
|
try {
|
|
5552
|
-
const raw =
|
|
5704
|
+
const raw = fs20.readFileSync(CACHE_FILE, "utf-8");
|
|
5553
5705
|
const parsed = JSON.parse(raw);
|
|
5554
5706
|
if (parsed && typeof parsed.inputHash === "string" && typeof parsed.generatedAt === "number") {
|
|
5555
5707
|
return parsed;
|
|
@@ -5582,12 +5734,14 @@ function triggerBrandExtraction(apiConfig) {
|
|
|
5582
5734
|
}
|
|
5583
5735
|
|
|
5584
5736
|
// src/session.ts
|
|
5585
|
-
import
|
|
5737
|
+
import fs21 from "fs";
|
|
5738
|
+
import path11 from "path";
|
|
5586
5739
|
var log10 = createLogger("session");
|
|
5587
5740
|
var SESSION_FILE = ".remy-session.json";
|
|
5741
|
+
var ARCHIVE_DIR = ".logs/sessions";
|
|
5588
5742
|
function loadSession(state) {
|
|
5589
5743
|
try {
|
|
5590
|
-
const raw =
|
|
5744
|
+
const raw = fs21.readFileSync(SESSION_FILE, "utf-8");
|
|
5591
5745
|
const data = JSON.parse(raw);
|
|
5592
5746
|
if (Array.isArray(data.messages) && data.messages.length > 0) {
|
|
5593
5747
|
state.messages = sanitizeMessages(data.messages);
|
|
@@ -5636,7 +5790,7 @@ function sanitizeMessages(messages) {
|
|
|
5636
5790
|
}
|
|
5637
5791
|
function saveSession(state) {
|
|
5638
5792
|
try {
|
|
5639
|
-
|
|
5793
|
+
fs21.writeFileSync(
|
|
5640
5794
|
SESSION_FILE,
|
|
5641
5795
|
JSON.stringify({ messages: state.messages }, null, 2),
|
|
5642
5796
|
"utf-8"
|
|
@@ -5649,8 +5803,21 @@ function saveSession(state) {
|
|
|
5649
5803
|
function clearSession(state) {
|
|
5650
5804
|
state.messages = [];
|
|
5651
5805
|
try {
|
|
5652
|
-
|
|
5653
|
-
|
|
5806
|
+
if (fs21.existsSync(SESSION_FILE)) {
|
|
5807
|
+
fs21.mkdirSync(ARCHIVE_DIR, { recursive: true });
|
|
5808
|
+
const ts = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
|
|
5809
|
+
const dest = path11.join(ARCHIVE_DIR, `cleared-${ts}.json`);
|
|
5810
|
+
fs21.renameSync(SESSION_FILE, dest);
|
|
5811
|
+
log10.info("Session archived on clear", { dest });
|
|
5812
|
+
}
|
|
5813
|
+
} catch (err) {
|
|
5814
|
+
log10.warn("Session archive on clear failed, deleting instead", {
|
|
5815
|
+
error: err.message
|
|
5816
|
+
});
|
|
5817
|
+
try {
|
|
5818
|
+
fs21.unlinkSync(SESSION_FILE);
|
|
5819
|
+
} catch {
|
|
5820
|
+
}
|
|
5654
5821
|
}
|
|
5655
5822
|
}
|
|
5656
5823
|
|
|
@@ -5960,9 +6127,11 @@ async function runTurn(params) {
|
|
|
5960
6127
|
saveSession(state);
|
|
5961
6128
|
return;
|
|
5962
6129
|
}
|
|
6130
|
+
const iterStart = Date.now();
|
|
5963
6131
|
const contentBlocks = [];
|
|
5964
6132
|
const thinkingBlockStartTimes = [];
|
|
5965
6133
|
let thinkingCompleteCount = 0;
|
|
6134
|
+
let lastThinkingRelatedStartedAt;
|
|
5966
6135
|
let textBlockOpen = false;
|
|
5967
6136
|
const toolInputAccumulators = /* @__PURE__ */ new Map();
|
|
5968
6137
|
let stopReason = "end_turn";
|
|
@@ -6094,16 +6263,30 @@ async function runTurn(params) {
|
|
|
6094
6263
|
}
|
|
6095
6264
|
onEvent({ type: "thinking", text: event.text });
|
|
6096
6265
|
break;
|
|
6097
|
-
case "thinking_complete":
|
|
6266
|
+
case "thinking_complete": {
|
|
6267
|
+
const startedAt = thinkingBlockStartTimes[thinkingCompleteCount] ?? event.ts;
|
|
6098
6268
|
contentBlocks.push({
|
|
6099
6269
|
type: "thinking",
|
|
6100
6270
|
thinking: event.thinking,
|
|
6101
6271
|
signature: event.signature,
|
|
6102
|
-
startedAt
|
|
6272
|
+
startedAt,
|
|
6103
6273
|
completedAt: event.ts
|
|
6104
6274
|
});
|
|
6105
6275
|
thinkingCompleteCount++;
|
|
6276
|
+
lastThinkingRelatedStartedAt = startedAt;
|
|
6277
|
+
break;
|
|
6278
|
+
}
|
|
6279
|
+
case "redacted_thinking_complete": {
|
|
6280
|
+
const startedAt = lastThinkingRelatedStartedAt !== void 0 ? lastThinkingRelatedStartedAt + 1 : event.ts;
|
|
6281
|
+
contentBlocks.push({
|
|
6282
|
+
type: "redacted_thinking",
|
|
6283
|
+
data: event.data,
|
|
6284
|
+
startedAt,
|
|
6285
|
+
completedAt: event.ts
|
|
6286
|
+
});
|
|
6287
|
+
lastThinkingRelatedStartedAt = startedAt;
|
|
6106
6288
|
break;
|
|
6289
|
+
}
|
|
6107
6290
|
case "tool_input_delta": {
|
|
6108
6291
|
const acc = getOrCreateAccumulator2(event.id, event.name);
|
|
6109
6292
|
acc.json += event.delta;
|
|
@@ -6157,6 +6340,22 @@ async function runTurn(params) {
|
|
|
6157
6340
|
turnOutputTokens += event.usage.outputTokens;
|
|
6158
6341
|
turnCacheCreation += lastCallCacheCreation;
|
|
6159
6342
|
turnCacheRead += lastCallCacheRead;
|
|
6343
|
+
recordUsage({
|
|
6344
|
+
ts: Date.now(),
|
|
6345
|
+
requestId,
|
|
6346
|
+
agentName: "parent",
|
|
6347
|
+
modelId: event.modelId,
|
|
6348
|
+
inputTokens: event.usage.inputTokens,
|
|
6349
|
+
outputTokens: event.usage.outputTokens,
|
|
6350
|
+
cacheCreationTokens: event.usage.cacheCreationTokens,
|
|
6351
|
+
cacheReadTokens: event.usage.cacheReadTokens,
|
|
6352
|
+
cost: nanoToDollars(event.cost),
|
|
6353
|
+
billingEvents: event.billingEvents,
|
|
6354
|
+
durationMs: Date.now() - iterStart,
|
|
6355
|
+
toolNames: contentBlocks.filter(
|
|
6356
|
+
(b) => b.type === "tool"
|
|
6357
|
+
).map((b) => b.name)
|
|
6358
|
+
});
|
|
6160
6359
|
break;
|
|
6161
6360
|
case "error":
|
|
6162
6361
|
onEvent({ type: "error", error: friendlyError(event.error) });
|