@mindstudio-ai/remy 0.1.312 → 0.1.314
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.d.ts +3 -2
- package/dist/headless.js +443 -277
- package/dist/index.js +502 -328
- package/dist/prompt/compiled/platform.md +1 -1
- package/dist/prompt/skills/realtimeEvents.md +32 -6
- package/dist/prompt/static/coding.md +1 -1
- package/dist/prompt/static/intake.md +1 -1
- package/dist/prompt/static/team.md +8 -0
- package/dist/subagents/codeSanityCheck/prompt.md +2 -0
- package/dist/subagents/research/prompt.md +25 -0
- package/package.json +1 -1
package/dist/headless.js
CHANGED
|
@@ -434,6 +434,13 @@ var MODEL_SURFACES = {
|
|
|
434
434
|
modelType: "text",
|
|
435
435
|
userPickable: true
|
|
436
436
|
},
|
|
437
|
+
research: {
|
|
438
|
+
default: "claude-5-sonnet",
|
|
439
|
+
label: "Research Agent",
|
|
440
|
+
description: "Researches using the web and reports back with citations.",
|
|
441
|
+
modelType: "text",
|
|
442
|
+
userPickable: true
|
|
443
|
+
},
|
|
437
444
|
copyEditor: {
|
|
438
445
|
default: "claude-5-sonnet",
|
|
439
446
|
label: "Copy Agent",
|
|
@@ -486,37 +493,59 @@ var MODEL_SURFACES = {
|
|
|
486
493
|
userPickable: false
|
|
487
494
|
}
|
|
488
495
|
};
|
|
496
|
+
var DEFAULT_SUGGEST_COMPACT_AT = 3e5;
|
|
497
|
+
var TEXT_MODELS = {
|
|
498
|
+
// Anthropic 1M-context, flat-priced.
|
|
499
|
+
"claude-5-opus": { forceCompactAt: 85e4 },
|
|
500
|
+
"claude-4-8-opus": { forceCompactAt: 85e4 },
|
|
501
|
+
"claude-4-7-opus": { forceCompactAt: 85e4 },
|
|
502
|
+
// Anthropic 1M-context with 2x long-context pricing above 200K input.
|
|
503
|
+
"claude-4-6-opus": { forceCompactAt: 85e4, suggestCompactAt: 18e4 },
|
|
504
|
+
"claude-4-6-sonnet": { forceCompactAt: 85e4, suggestCompactAt: 18e4 },
|
|
505
|
+
"claude-fable-5": { forceCompactAt: 85e4 },
|
|
506
|
+
"claude-fable-5-1": { forceCompactAt: 85e4 },
|
|
507
|
+
"claude-5-sonnet": { forceCompactAt: 85e4 },
|
|
508
|
+
// OpenAI gpt-5.5/5.6: ~1M window, but the usable input ceiling under
|
|
509
|
+
// `truncation: 'auto'` is ~794K (output + reasoning reserve), and all
|
|
510
|
+
// rates double above 272K input.
|
|
511
|
+
"gpt-5.5": { forceCompactAt: 6e5, suggestCompactAt: 25e4 },
|
|
512
|
+
"gpt-5.6-sol": { forceCompactAt: 6e5, suggestCompactAt: 25e4 },
|
|
513
|
+
"gpt-5.6-terra": { forceCompactAt: 6e5, suggestCompactAt: 25e4 },
|
|
514
|
+
"gpt-5.6-luna": { forceCompactAt: 6e5, suggestCompactAt: 25e4 },
|
|
515
|
+
// Google ~1M-context; only 3.1-pro is tiered (higher rates above 200K).
|
|
516
|
+
"gemini-3-pro": { forceCompactAt: 85e4 },
|
|
517
|
+
"gemini-3.1-pro": { forceCompactAt: 85e4, suggestCompactAt: 18e4 },
|
|
518
|
+
"gemini-3-flash": { forceCompactAt: 85e4 },
|
|
519
|
+
"gemini-3.5-flash": { forceCompactAt: 85e4 },
|
|
520
|
+
"gemini-3.7-flash": { forceCompactAt: 85e4 },
|
|
521
|
+
// 256K window; its 200K pricing tier sits above the gate, so no nudge.
|
|
522
|
+
"grok-build-0.1": { forceCompactAt: 18e4 },
|
|
523
|
+
"grok-4.5": { forceCompactAt: 4e5 },
|
|
524
|
+
// 500K window
|
|
525
|
+
"grok-4.6": { forceCompactAt: 4e5 },
|
|
526
|
+
// 500K window
|
|
527
|
+
"glm-5.2": { forceCompactAt: 85e4 },
|
|
528
|
+
"muse-spark-1.1": { forceCompactAt: 85e4 },
|
|
529
|
+
"kimi-k2-7-code": { forceCompactAt: 2e5 },
|
|
530
|
+
// 262K window
|
|
531
|
+
"kimi-k3": { forceCompactAt: 85e4 },
|
|
532
|
+
"deepseek-v4-flash-0731": { forceCompactAt: 85e4 },
|
|
533
|
+
"qwen3.8-2.4t-a95b-deepinfra": { forceCompactAt: 2e5 },
|
|
534
|
+
// 262K window
|
|
535
|
+
"qwen3.8-27b-deepinfra": { forceCompactAt: 2e5 },
|
|
536
|
+
// 262K window
|
|
537
|
+
"minimax-m3": { forceCompactAt: 42e4 }
|
|
538
|
+
// 524K window
|
|
539
|
+
};
|
|
540
|
+
var DEFAULT_CONTEXT_LIMITS = { forceCompactAt: 85e4 };
|
|
541
|
+
function getContextLimits(modelId) {
|
|
542
|
+
return TEXT_MODELS[modelId] ?? DEFAULT_CONTEXT_LIMITS;
|
|
543
|
+
}
|
|
544
|
+
function getSuggestCompactAt(modelId) {
|
|
545
|
+
return getContextLimits(modelId).suggestCompactAt ?? DEFAULT_SUGGEST_COMPACT_AT;
|
|
546
|
+
}
|
|
489
547
|
var ALLOWED_MODELS_BY_TYPE = {
|
|
490
|
-
text:
|
|
491
|
-
"claude-5-opus",
|
|
492
|
-
"claude-4-8-opus",
|
|
493
|
-
"claude-4-7-opus",
|
|
494
|
-
"claude-4-6-opus",
|
|
495
|
-
"claude-4-6-sonnet",
|
|
496
|
-
"claude-fable-5",
|
|
497
|
-
"claude-fable-5-1",
|
|
498
|
-
"claude-5-sonnet",
|
|
499
|
-
"gpt-5.5",
|
|
500
|
-
"gpt-5.6-sol",
|
|
501
|
-
"gpt-5.6-terra",
|
|
502
|
-
"gpt-5.6-luna",
|
|
503
|
-
"gemini-3-pro",
|
|
504
|
-
"gemini-3.1-pro",
|
|
505
|
-
"gemini-3-flash",
|
|
506
|
-
"gemini-3.5-flash",
|
|
507
|
-
"gemini-3.7-flash",
|
|
508
|
-
"grok-build-0.1",
|
|
509
|
-
"grok-4.5",
|
|
510
|
-
"grok-4.6",
|
|
511
|
-
"glm-5.2",
|
|
512
|
-
"muse-spark-1.1",
|
|
513
|
-
"kimi-k2-7-code",
|
|
514
|
-
"kimi-k3",
|
|
515
|
-
"deepseek-v4-flash-0731",
|
|
516
|
-
"qwen3.8-2.4t-a95b-deepinfra",
|
|
517
|
-
"qwen3.8-27b-deepinfra",
|
|
518
|
-
"minimax-m3"
|
|
519
|
-
]
|
|
548
|
+
text: Object.keys(TEXT_MODELS)
|
|
520
549
|
// vision: undefined — unconstrained
|
|
521
550
|
// image_generation: undefined — unconstrained
|
|
522
551
|
};
|
|
@@ -559,6 +588,11 @@ function getEffectiveModelSurfaces() {
|
|
|
559
588
|
function resolveModel(surfaceId, models, fallback) {
|
|
560
589
|
return models?.[surfaceId] ?? fallback ?? orgDefaultModels[surfaceId] ?? MODEL_SURFACES[surfaceId].default;
|
|
561
590
|
}
|
|
591
|
+
function resolveParentModel(models, fallback, buildModel) {
|
|
592
|
+
const override = buildModel ? filterModelPicks({ parent: buildModel }).parent : void 0;
|
|
593
|
+
const baseline = resolveModel("parent", models, fallback);
|
|
594
|
+
return { baseline, effective: override ?? baseline };
|
|
595
|
+
}
|
|
562
596
|
|
|
563
597
|
// src/orgContext.ts
|
|
564
598
|
var log3 = createLogger("orgContext");
|
|
@@ -1857,158 +1891,6 @@ var askMindStudioSdkTool = {
|
|
|
1857
1891
|
}
|
|
1858
1892
|
};
|
|
1859
1893
|
|
|
1860
|
-
// src/usageLedger.ts
|
|
1861
|
-
import fs12 from "fs";
|
|
1862
|
-
var LEDGER_FILE = ".logs/usage.ndjson";
|
|
1863
|
-
var fd = null;
|
|
1864
|
-
function nanoToDollars(nano) {
|
|
1865
|
-
return typeof nano === "number" ? nano / 1e9 : void 0;
|
|
1866
|
-
}
|
|
1867
|
-
function recordUsage(entry) {
|
|
1868
|
-
try {
|
|
1869
|
-
if (fd === null) {
|
|
1870
|
-
fs12.mkdirSync(".logs", { recursive: true });
|
|
1871
|
-
fd = fs12.openSync(LEDGER_FILE, "a");
|
|
1872
|
-
}
|
|
1873
|
-
fs12.writeSync(fd, JSON.stringify(entry) + "\n");
|
|
1874
|
-
} catch {
|
|
1875
|
-
}
|
|
1876
|
-
}
|
|
1877
|
-
|
|
1878
|
-
// src/subagents/common/runMindstudioCli.ts
|
|
1879
|
-
function stripFlags(args) {
|
|
1880
|
-
const out = [];
|
|
1881
|
-
for (let i = 0; i < args.length; i++) {
|
|
1882
|
-
const arg = args[i];
|
|
1883
|
-
if (arg === "--no-meta") {
|
|
1884
|
-
continue;
|
|
1885
|
-
}
|
|
1886
|
-
if (arg === "--output-key") {
|
|
1887
|
-
i++;
|
|
1888
|
-
continue;
|
|
1889
|
-
}
|
|
1890
|
-
out.push(arg);
|
|
1891
|
-
}
|
|
1892
|
-
return out;
|
|
1893
|
-
}
|
|
1894
|
-
async function runMindstudioCliResult(args, options) {
|
|
1895
|
-
const cleanArgs = stripFlags(args);
|
|
1896
|
-
const cliAction = args[0];
|
|
1897
|
-
const agentName = options?.caller ?? "mindstudio-cli";
|
|
1898
|
-
const start = Date.now();
|
|
1899
|
-
const res = await runCli("mindstudio", cleanArgs, options);
|
|
1900
|
-
if (!res.ok) {
|
|
1901
|
-
return { ok: false, value: formatCliResult(res) };
|
|
1902
|
-
}
|
|
1903
|
-
const truncNote = res.truncated ? "\n\n[output truncated]" : "";
|
|
1904
|
-
let envelope;
|
|
1905
|
-
try {
|
|
1906
|
-
envelope = JSON.parse(res.output);
|
|
1907
|
-
} catch {
|
|
1908
|
-
return { ok: true, value: res.output + truncNote };
|
|
1909
|
-
}
|
|
1910
|
-
if (envelope && typeof envelope === "object" && Array.isArray(envelope.results)) {
|
|
1911
|
-
const durationMs = Date.now() - start;
|
|
1912
|
-
for (const step of envelope.results) {
|
|
1913
|
-
if (typeof step?.billingCost === "number") {
|
|
1914
|
-
recordUsage({
|
|
1915
|
-
ts: Date.now(),
|
|
1916
|
-
agentName,
|
|
1917
|
-
cliAction: `${cliAction}:${step.stepType ?? "step"}`,
|
|
1918
|
-
cost: nanoToDollars(step.billingCost),
|
|
1919
|
-
inputTokens: 0,
|
|
1920
|
-
outputTokens: 0,
|
|
1921
|
-
durationMs,
|
|
1922
|
-
toolNames: []
|
|
1923
|
-
});
|
|
1924
|
-
}
|
|
1925
|
-
}
|
|
1926
|
-
return { ok: true, value: JSON.stringify(envelope.results) + truncNote };
|
|
1927
|
-
}
|
|
1928
|
-
if (typeof envelope?.$billingCost === "number") {
|
|
1929
|
-
recordUsage({
|
|
1930
|
-
ts: Date.now(),
|
|
1931
|
-
agentName,
|
|
1932
|
-
cliAction,
|
|
1933
|
-
cost: nanoToDollars(envelope.$billingCost),
|
|
1934
|
-
billingEvents: envelope.$billingEvents,
|
|
1935
|
-
// CLI billing isn't expressed as input/output tokens for most actions
|
|
1936
|
-
// (image gen is per-image, scrape per-page, etc). `numUnits` inside each
|
|
1937
|
-
// billingEvent carries the per-event unit count.
|
|
1938
|
-
inputTokens: 0,
|
|
1939
|
-
outputTokens: 0,
|
|
1940
|
-
durationMs: Date.now() - start,
|
|
1941
|
-
toolNames: []
|
|
1942
|
-
});
|
|
1943
|
-
}
|
|
1944
|
-
if (options?.outputKey) {
|
|
1945
|
-
const v = envelope?.[options.outputKey];
|
|
1946
|
-
if (v === void 0 || v === null) {
|
|
1947
|
-
return { ok: false, value: JSON.stringify(stripDollarKeys(envelope)) };
|
|
1948
|
-
}
|
|
1949
|
-
const value = typeof v === "string" ? v : JSON.stringify(v);
|
|
1950
|
-
return { ok: true, value: value + truncNote };
|
|
1951
|
-
}
|
|
1952
|
-
return {
|
|
1953
|
-
ok: true,
|
|
1954
|
-
value: JSON.stringify(stripDollarKeys(envelope)) + truncNote
|
|
1955
|
-
};
|
|
1956
|
-
}
|
|
1957
|
-
async function runMindstudioCli(args, options) {
|
|
1958
|
-
return (await runMindstudioCliResult(args, options)).value;
|
|
1959
|
-
}
|
|
1960
|
-
function stripDollarKeys(envelope) {
|
|
1961
|
-
if (!envelope || typeof envelope !== "object" || Array.isArray(envelope)) {
|
|
1962
|
-
return envelope;
|
|
1963
|
-
}
|
|
1964
|
-
const out = {};
|
|
1965
|
-
for (const [k, v] of Object.entries(envelope)) {
|
|
1966
|
-
if (!k.startsWith("$")) {
|
|
1967
|
-
out[k] = v;
|
|
1968
|
-
}
|
|
1969
|
-
}
|
|
1970
|
-
return out;
|
|
1971
|
-
}
|
|
1972
|
-
|
|
1973
|
-
// src/tools/common/searchGoogle.ts
|
|
1974
|
-
var FETCH_TOP_N = 5;
|
|
1975
|
-
var searchGoogleTool = {
|
|
1976
|
-
definition: {
|
|
1977
|
-
name: "searchGoogle",
|
|
1978
|
-
description: "Search Google and return results. Use for research, finding documentation, looking up APIs, or any task where web search would help. The top results come back with their page content already included, so read those before reaching for scrapeWebUrl \u2014 you only need that for URLs this did not return, or for a result further down the list.",
|
|
1979
|
-
inputSchema: {
|
|
1980
|
-
type: "object",
|
|
1981
|
-
properties: {
|
|
1982
|
-
query: {
|
|
1983
|
-
type: "string",
|
|
1984
|
-
description: "The search query."
|
|
1985
|
-
}
|
|
1986
|
-
},
|
|
1987
|
-
required: ["query"]
|
|
1988
|
-
}
|
|
1989
|
-
},
|
|
1990
|
-
async execute(input, context) {
|
|
1991
|
-
const query = input.query;
|
|
1992
|
-
return runMindstudioCli(
|
|
1993
|
-
[
|
|
1994
|
-
"search-google",
|
|
1995
|
-
"--query",
|
|
1996
|
-
query,
|
|
1997
|
-
"--export-type",
|
|
1998
|
-
"json",
|
|
1999
|
-
"--fetch-top-n",
|
|
2000
|
-
String(FETCH_TOP_N)
|
|
2001
|
-
],
|
|
2002
|
-
{
|
|
2003
|
-
outputKey: "results",
|
|
2004
|
-
maxBuffer: SEARCH_MAX_BUFFER,
|
|
2005
|
-
onLog: context?.onLog,
|
|
2006
|
-
caller: "parent"
|
|
2007
|
-
}
|
|
2008
|
-
);
|
|
2009
|
-
}
|
|
2010
|
-
};
|
|
2011
|
-
|
|
2012
1894
|
// src/tools/common/setProjectMetadata.ts
|
|
2013
1895
|
var setProjectMetadataTool = {
|
|
2014
1896
|
definition: {
|
|
@@ -2133,7 +2015,7 @@ This reference lives at ${skill.path}. Re-read it with readFile if you need it a
|
|
|
2133
2015
|
};
|
|
2134
2016
|
|
|
2135
2017
|
// src/tools/code/readFile.ts
|
|
2136
|
-
import
|
|
2018
|
+
import fs12 from "fs/promises";
|
|
2137
2019
|
var DEFAULT_WINDOW = 500;
|
|
2138
2020
|
var MAX_BYTES = 64 * 1024;
|
|
2139
2021
|
function isBinary(buffer) {
|
|
@@ -2174,7 +2056,7 @@ var readFileTool = {
|
|
|
2174
2056
|
},
|
|
2175
2057
|
async execute(input) {
|
|
2176
2058
|
try {
|
|
2177
|
-
const buffer = await
|
|
2059
|
+
const buffer = await fs12.readFile(input.path);
|
|
2178
2060
|
if (isBinary(buffer)) {
|
|
2179
2061
|
const size = buffer.length;
|
|
2180
2062
|
const unit = size > 1024 * 1024 ? `${(size / (1024 * 1024)).toFixed(1)}MB` : `${(size / 1024).toFixed(1)}KB`;
|
|
@@ -2246,7 +2128,7 @@ var readFileTool = {
|
|
|
2246
2128
|
};
|
|
2247
2129
|
|
|
2248
2130
|
// src/tools/code/writeFile.ts
|
|
2249
|
-
import
|
|
2131
|
+
import fs13 from "fs/promises";
|
|
2250
2132
|
import path6 from "path";
|
|
2251
2133
|
var writeFileTool = {
|
|
2252
2134
|
definition: {
|
|
@@ -2283,7 +2165,7 @@ var writeFileTool = {
|
|
|
2283
2165
|
lastNewlineCount = newlineCount;
|
|
2284
2166
|
const lastNewline = partial.content.lastIndexOf("\n");
|
|
2285
2167
|
const completeContent = partial.content.substring(0, lastNewline + 1);
|
|
2286
|
-
const oldContent = await
|
|
2168
|
+
const oldContent = await fs13.readFile(partial.path, "utf-8").catch(() => "");
|
|
2287
2169
|
return `Writing ${partial.path} (${newlineCount} lines)
|
|
2288
2170
|
${unifiedDiff(partial.path, oldContent, completeContent)}`;
|
|
2289
2171
|
}
|
|
@@ -2292,13 +2174,13 @@ ${unifiedDiff(partial.path, oldContent, completeContent)}`;
|
|
|
2292
2174
|
async execute(input) {
|
|
2293
2175
|
const release = await acquireFileLock(input.path);
|
|
2294
2176
|
try {
|
|
2295
|
-
await
|
|
2177
|
+
await fs13.mkdir(path6.dirname(input.path), { recursive: true });
|
|
2296
2178
|
let oldContent = null;
|
|
2297
2179
|
try {
|
|
2298
|
-
oldContent = await
|
|
2180
|
+
oldContent = await fs13.readFile(input.path, "utf-8");
|
|
2299
2181
|
} catch {
|
|
2300
2182
|
}
|
|
2301
|
-
await
|
|
2183
|
+
await fs13.writeFile(input.path, input.content, "utf-8");
|
|
2302
2184
|
const lineCount = input.content.split("\n").length;
|
|
2303
2185
|
const label = oldContent !== null ? "Wrote" : "Created";
|
|
2304
2186
|
return `${label} ${input.path} (${lineCount} lines)
|
|
@@ -2312,7 +2194,7 @@ ${unifiedDiff(input.path, oldContent ?? "", input.content)}`;
|
|
|
2312
2194
|
};
|
|
2313
2195
|
|
|
2314
2196
|
// src/tools/code/editFile/index.ts
|
|
2315
|
-
import
|
|
2197
|
+
import fs14 from "fs/promises";
|
|
2316
2198
|
var editFileTool = {
|
|
2317
2199
|
definition: {
|
|
2318
2200
|
name: "editFile",
|
|
@@ -2343,7 +2225,7 @@ var editFileTool = {
|
|
|
2343
2225
|
async execute(input) {
|
|
2344
2226
|
const release = await acquireFileLock(input.path);
|
|
2345
2227
|
try {
|
|
2346
|
-
const content = await
|
|
2228
|
+
const content = await fs14.readFile(input.path, "utf-8");
|
|
2347
2229
|
const { old_string, new_string, replace_all } = input;
|
|
2348
2230
|
const occurrences = findOccurrences(content, old_string);
|
|
2349
2231
|
if (replace_all) {
|
|
@@ -2359,7 +2241,7 @@ var editFileTool = {
|
|
|
2359
2241
|
new_string
|
|
2360
2242
|
);
|
|
2361
2243
|
}
|
|
2362
|
-
await
|
|
2244
|
+
await fs14.writeFile(input.path, updated, "utf-8");
|
|
2363
2245
|
return `Replaced ${occurrences.length} occurrence${occurrences.length > 1 ? "s" : ""} in ${input.path}
|
|
2364
2246
|
${unifiedDiff(input.path, content, updated)}`;
|
|
2365
2247
|
}
|
|
@@ -2370,7 +2252,7 @@ ${unifiedDiff(input.path, content, updated)}`;
|
|
|
2370
2252
|
old_string.length,
|
|
2371
2253
|
new_string
|
|
2372
2254
|
);
|
|
2373
|
-
await
|
|
2255
|
+
await fs14.writeFile(input.path, updated, "utf-8");
|
|
2374
2256
|
return `Updated ${input.path}
|
|
2375
2257
|
${unifiedDiff(input.path, content, updated)}`;
|
|
2376
2258
|
}
|
|
@@ -2386,7 +2268,7 @@ ${unifiedDiff(input.path, content, updated)}`;
|
|
|
2386
2268
|
flex.matchedText.length,
|
|
2387
2269
|
new_string
|
|
2388
2270
|
);
|
|
2389
|
-
await
|
|
2271
|
+
await fs14.writeFile(input.path, updated, "utf-8");
|
|
2390
2272
|
return `Updated ${input.path} (matched with flexible whitespace at line ${flex.line})
|
|
2391
2273
|
${unifiedDiff(input.path, content, updated)}`;
|
|
2392
2274
|
}
|
|
@@ -2712,12 +2594,12 @@ var globTool = {
|
|
|
2712
2594
|
};
|
|
2713
2595
|
|
|
2714
2596
|
// src/tools/code/listDir.ts
|
|
2715
|
-
import
|
|
2597
|
+
import fs15 from "fs/promises";
|
|
2716
2598
|
import path8 from "path";
|
|
2717
2599
|
var EXCLUDE = /* @__PURE__ */ new Set([".git", "node_modules"]);
|
|
2718
2600
|
var MAX_CHILDREN = 15;
|
|
2719
2601
|
async function readAndSort(dirPath) {
|
|
2720
|
-
const entries = await
|
|
2602
|
+
const entries = await fs15.readdir(dirPath, { withFileTypes: true });
|
|
2721
2603
|
return entries.filter((e) => !EXCLUDE.has(e.name)).sort((a, b) => {
|
|
2722
2604
|
if (a.isDirectory() && !b.isDirectory()) {
|
|
2723
2605
|
return -1;
|
|
@@ -2758,7 +2640,7 @@ function formatSize(bytes) {
|
|
|
2758
2640
|
}
|
|
2759
2641
|
async function formatFile(dirPath, name, indent) {
|
|
2760
2642
|
try {
|
|
2761
|
-
const stat4 = await
|
|
2643
|
+
const stat4 = await fs15.stat(path8.join(dirPath, name));
|
|
2762
2644
|
return `${indent}${name}${" ".repeat(Math.max(1, 30 - indent.length - name.length))}${formatSize(stat4.size)}`;
|
|
2763
2645
|
} catch {
|
|
2764
2646
|
return `${indent}${name}`;
|
|
@@ -3090,6 +2972,119 @@ var queryDatabaseTool = {
|
|
|
3090
2972
|
}
|
|
3091
2973
|
};
|
|
3092
2974
|
|
|
2975
|
+
// src/usageLedger.ts
|
|
2976
|
+
import fs16 from "fs";
|
|
2977
|
+
var LEDGER_FILE = ".logs/usage.ndjson";
|
|
2978
|
+
var fd = null;
|
|
2979
|
+
function nanoToDollars(nano) {
|
|
2980
|
+
return typeof nano === "number" ? nano / 1e9 : void 0;
|
|
2981
|
+
}
|
|
2982
|
+
function recordUsage(entry) {
|
|
2983
|
+
try {
|
|
2984
|
+
if (fd === null) {
|
|
2985
|
+
fs16.mkdirSync(".logs", { recursive: true });
|
|
2986
|
+
fd = fs16.openSync(LEDGER_FILE, "a");
|
|
2987
|
+
}
|
|
2988
|
+
fs16.writeSync(fd, JSON.stringify(entry) + "\n");
|
|
2989
|
+
} catch {
|
|
2990
|
+
}
|
|
2991
|
+
}
|
|
2992
|
+
|
|
2993
|
+
// src/subagents/common/runMindstudioCli.ts
|
|
2994
|
+
function stripFlags(args) {
|
|
2995
|
+
const out = [];
|
|
2996
|
+
for (let i = 0; i < args.length; i++) {
|
|
2997
|
+
const arg = args[i];
|
|
2998
|
+
if (arg === "--no-meta") {
|
|
2999
|
+
continue;
|
|
3000
|
+
}
|
|
3001
|
+
if (arg === "--output-key") {
|
|
3002
|
+
i++;
|
|
3003
|
+
continue;
|
|
3004
|
+
}
|
|
3005
|
+
out.push(arg);
|
|
3006
|
+
}
|
|
3007
|
+
return out;
|
|
3008
|
+
}
|
|
3009
|
+
async function runMindstudioCliResult(args, options) {
|
|
3010
|
+
const cleanArgs = stripFlags(args);
|
|
3011
|
+
const cliAction = args[0];
|
|
3012
|
+
const agentName = options?.caller ?? "mindstudio-cli";
|
|
3013
|
+
const start = Date.now();
|
|
3014
|
+
const res = await runCli("mindstudio", cleanArgs, options);
|
|
3015
|
+
if (!res.ok) {
|
|
3016
|
+
return { ok: false, value: formatCliResult(res) };
|
|
3017
|
+
}
|
|
3018
|
+
const truncNote = res.truncated ? "\n\n[output truncated]" : "";
|
|
3019
|
+
let envelope;
|
|
3020
|
+
try {
|
|
3021
|
+
envelope = JSON.parse(res.output);
|
|
3022
|
+
} catch {
|
|
3023
|
+
return { ok: true, value: res.output + truncNote };
|
|
3024
|
+
}
|
|
3025
|
+
if (envelope && typeof envelope === "object" && Array.isArray(envelope.results)) {
|
|
3026
|
+
const durationMs = Date.now() - start;
|
|
3027
|
+
for (const step of envelope.results) {
|
|
3028
|
+
if (typeof step?.billingCost === "number") {
|
|
3029
|
+
recordUsage({
|
|
3030
|
+
ts: Date.now(),
|
|
3031
|
+
agentName,
|
|
3032
|
+
cliAction: `${cliAction}:${step.stepType ?? "step"}`,
|
|
3033
|
+
cost: nanoToDollars(step.billingCost),
|
|
3034
|
+
inputTokens: 0,
|
|
3035
|
+
outputTokens: 0,
|
|
3036
|
+
durationMs,
|
|
3037
|
+
toolNames: []
|
|
3038
|
+
});
|
|
3039
|
+
}
|
|
3040
|
+
}
|
|
3041
|
+
return { ok: true, value: JSON.stringify(envelope.results) + truncNote };
|
|
3042
|
+
}
|
|
3043
|
+
if (typeof envelope?.$billingCost === "number") {
|
|
3044
|
+
recordUsage({
|
|
3045
|
+
ts: Date.now(),
|
|
3046
|
+
agentName,
|
|
3047
|
+
cliAction,
|
|
3048
|
+
cost: nanoToDollars(envelope.$billingCost),
|
|
3049
|
+
billingEvents: envelope.$billingEvents,
|
|
3050
|
+
// CLI billing isn't expressed as input/output tokens for most actions
|
|
3051
|
+
// (image gen is per-image, scrape per-page, etc). `numUnits` inside each
|
|
3052
|
+
// billingEvent carries the per-event unit count.
|
|
3053
|
+
inputTokens: 0,
|
|
3054
|
+
outputTokens: 0,
|
|
3055
|
+
durationMs: Date.now() - start,
|
|
3056
|
+
toolNames: []
|
|
3057
|
+
});
|
|
3058
|
+
}
|
|
3059
|
+
if (options?.outputKey) {
|
|
3060
|
+
const v = envelope?.[options.outputKey];
|
|
3061
|
+
if (v === void 0 || v === null) {
|
|
3062
|
+
return { ok: false, value: JSON.stringify(stripDollarKeys(envelope)) };
|
|
3063
|
+
}
|
|
3064
|
+
const value = typeof v === "string" ? v : JSON.stringify(v);
|
|
3065
|
+
return { ok: true, value: value + truncNote };
|
|
3066
|
+
}
|
|
3067
|
+
return {
|
|
3068
|
+
ok: true,
|
|
3069
|
+
value: JSON.stringify(stripDollarKeys(envelope)) + truncNote
|
|
3070
|
+
};
|
|
3071
|
+
}
|
|
3072
|
+
async function runMindstudioCli(args, options) {
|
|
3073
|
+
return (await runMindstudioCliResult(args, options)).value;
|
|
3074
|
+
}
|
|
3075
|
+
function stripDollarKeys(envelope) {
|
|
3076
|
+
if (!envelope || typeof envelope !== "object" || Array.isArray(envelope)) {
|
|
3077
|
+
return envelope;
|
|
3078
|
+
}
|
|
3079
|
+
const out = {};
|
|
3080
|
+
for (const [k, v] of Object.entries(envelope)) {
|
|
3081
|
+
if (!k.startsWith("$")) {
|
|
3082
|
+
out[k] = v;
|
|
3083
|
+
}
|
|
3084
|
+
}
|
|
3085
|
+
return out;
|
|
3086
|
+
}
|
|
3087
|
+
|
|
3093
3088
|
// src/tools/_helpers/uploadImage.ts
|
|
3094
3089
|
import { readFile, stat } from "fs/promises";
|
|
3095
3090
|
import { basename, extname, resolve } from "path";
|
|
@@ -4568,7 +4563,7 @@ The first-party SDK (@mindstudio-ai/agent) provides access to 200+ AI models (Op
|
|
|
4568
4563
|
## What Remy apps are NOT good for
|
|
4569
4564
|
|
|
4570
4565
|
- Native mobile apps (iOS/Android). Mobile-responsive web apps are fine.
|
|
4571
|
-
-
|
|
4566
|
+
- Real-time action games (server-authoritative simulation, guaranteed-order sync) \u2014 event delivery is at-most-once and ordering is the app's job, so there is no server tick to build one on.
|
|
4572
4567
|
</platform_brief>`;
|
|
4573
4568
|
}
|
|
4574
4569
|
|
|
@@ -4857,56 +4852,155 @@ var screenshotTool = {
|
|
|
4857
4852
|
execute: (input, context) => executeScreenshot(input, context?.onLog, context)
|
|
4858
4853
|
};
|
|
4859
4854
|
|
|
4860
|
-
// src/subagents/
|
|
4861
|
-
var
|
|
4862
|
-
__export(searchGoogle_exports, {
|
|
4863
|
-
definition: () => definition,
|
|
4864
|
-
execute: () => execute
|
|
4865
|
-
});
|
|
4866
|
-
var FETCH_TOP_N2 = 5;
|
|
4867
|
-
var definition = {
|
|
4855
|
+
// src/subagents/research/tools.ts
|
|
4856
|
+
var searchGoogleDefinition = {
|
|
4868
4857
|
name: "searchGoogle",
|
|
4869
|
-
description:
|
|
4858
|
+
description: "Search Google. Returns ~25 results (title, description, URL) \u2014 fast (~5s) when `fetchTopN` is omitted. Set `fetchTopN` (3\u20135) to also get the top results' page content inline, capped at ~4,000 chars per page \u2014 one call delivers excerpts, but it is much slower (~30\u201360s). Default pattern: fire SERP-only searches in parallel, then scrape the specific pages worth reading in full.",
|
|
4870
4859
|
inputSchema: {
|
|
4871
4860
|
type: "object",
|
|
4872
4861
|
properties: {
|
|
4873
4862
|
query: {
|
|
4874
4863
|
type: "string",
|
|
4875
4864
|
description: "The search query."
|
|
4865
|
+
},
|
|
4866
|
+
fetchTopN: {
|
|
4867
|
+
type: "number",
|
|
4868
|
+
description: "Also fetch page content (capped ~4,000 chars each) for this many top results. Omit for a fast SERP-only search."
|
|
4876
4869
|
}
|
|
4877
4870
|
},
|
|
4878
4871
|
required: ["query"]
|
|
4879
4872
|
}
|
|
4880
4873
|
};
|
|
4881
|
-
|
|
4874
|
+
var scrapeWebUrlDefinition = {
|
|
4875
|
+
name: "scrapeWebUrl",
|
|
4876
|
+
description: "Fetch a web page as markdown. Renders JavaScript, so client-rendered pages come back complete. Returns the full page \u2014 long docs can run tens of thousands of tokens, so fetch only pages you have chosen to read, and fire independent fetches in parallel. For code hosted on GitHub/npm, prefer cloning with bash over scraping the repo page.",
|
|
4877
|
+
inputSchema: {
|
|
4878
|
+
type: "object",
|
|
4879
|
+
properties: {
|
|
4880
|
+
url: {
|
|
4881
|
+
type: "string",
|
|
4882
|
+
description: "The URL to fetch."
|
|
4883
|
+
}
|
|
4884
|
+
},
|
|
4885
|
+
required: ["url"]
|
|
4886
|
+
}
|
|
4887
|
+
};
|
|
4888
|
+
var RESEARCH_TOOLS = [
|
|
4889
|
+
...COMMON_READ_TOOLS,
|
|
4890
|
+
searchGoogleDefinition,
|
|
4891
|
+
scrapeWebUrlDefinition,
|
|
4892
|
+
bashTool.definition
|
|
4893
|
+
];
|
|
4894
|
+
async function executeSearchGoogle(input, onLog, caller) {
|
|
4895
|
+
const fetchTopN = Math.max(0, Math.round(Number(input.fetchTopN) || 0));
|
|
4882
4896
|
return runMindstudioCli(
|
|
4883
4897
|
[
|
|
4884
4898
|
"search-google",
|
|
4885
4899
|
"--query",
|
|
4886
|
-
input.query,
|
|
4900
|
+
String(input.query),
|
|
4887
4901
|
"--export-type",
|
|
4888
4902
|
"json",
|
|
4889
4903
|
"--fetch-top-n",
|
|
4890
|
-
String(
|
|
4904
|
+
String(fetchTopN)
|
|
4891
4905
|
],
|
|
4892
4906
|
{
|
|
4893
4907
|
outputKey: "results",
|
|
4908
|
+
maxBuffer: SEARCH_MAX_BUFFER,
|
|
4894
4909
|
onLog,
|
|
4895
|
-
caller
|
|
4896
|
-
maxBuffer: SEARCH_MAX_BUFFER
|
|
4910
|
+
caller
|
|
4897
4911
|
}
|
|
4898
4912
|
);
|
|
4899
4913
|
}
|
|
4914
|
+
async function executeScrapeWebUrl(input, onLog, caller) {
|
|
4915
|
+
return runMindstudioCli(
|
|
4916
|
+
[
|
|
4917
|
+
"scrape-url",
|
|
4918
|
+
"--url",
|
|
4919
|
+
String(input.url),
|
|
4920
|
+
"--page-options",
|
|
4921
|
+
JSON.stringify({ onlyMainContent: true })
|
|
4922
|
+
],
|
|
4923
|
+
{
|
|
4924
|
+
maxBuffer: SCRAPE_MAX_BUFFER,
|
|
4925
|
+
onLog,
|
|
4926
|
+
caller
|
|
4927
|
+
}
|
|
4928
|
+
);
|
|
4929
|
+
}
|
|
4930
|
+
|
|
4931
|
+
// src/subagents/research/index.ts
|
|
4932
|
+
var BASE_PROMPT2 = readAsset("subagents/research", "prompt.md");
|
|
4933
|
+
async function runResearch(task, context) {
|
|
4934
|
+
const specIndex = loadSpecIndex();
|
|
4935
|
+
const parts = [BASE_PROMPT2, loadPlatformBrief()];
|
|
4936
|
+
parts.push("<!-- cache_breakpoint -->");
|
|
4937
|
+
if (specIndex) {
|
|
4938
|
+
parts.push(specIndex);
|
|
4939
|
+
}
|
|
4940
|
+
const system = parts.join("\n\n");
|
|
4941
|
+
const result = await runSubAgent({
|
|
4942
|
+
system,
|
|
4943
|
+
task,
|
|
4944
|
+
tools: RESEARCH_TOOLS,
|
|
4945
|
+
externalTools: /* @__PURE__ */ new Set(),
|
|
4946
|
+
executeTool: (name, toolInput, toolCallId, onLog, sams) => {
|
|
4947
|
+
const childCtx = toolCallId ? {
|
|
4948
|
+
...deriveContext(context, toolCallId, onLog),
|
|
4949
|
+
subAgentMessages: sams
|
|
4950
|
+
} : context;
|
|
4951
|
+
if (name === "searchGoogle") {
|
|
4952
|
+
return executeSearchGoogle(toolInput, childCtx.onLog, "research");
|
|
4953
|
+
}
|
|
4954
|
+
if (name === "scrapeWebUrl") {
|
|
4955
|
+
return executeScrapeWebUrl(toolInput, childCtx.onLog, "research");
|
|
4956
|
+
}
|
|
4957
|
+
return executeTool(name, toolInput, childCtx);
|
|
4958
|
+
},
|
|
4959
|
+
apiConfig: context.apiConfig,
|
|
4960
|
+
model: resolveModel("research", context.models, context.model),
|
|
4961
|
+
subAgentId: "research",
|
|
4962
|
+
signal: context.signal,
|
|
4963
|
+
parentToolId: context.toolCallId,
|
|
4964
|
+
requestId: context.requestId,
|
|
4965
|
+
onEvent: context.onEvent,
|
|
4966
|
+
resolveExternalTool: context.resolveExternalTool,
|
|
4967
|
+
toolRegistry: context.toolRegistry
|
|
4968
|
+
});
|
|
4969
|
+
context.subAgentMessages?.set(context.toolCallId, result.messages);
|
|
4970
|
+
return result.text;
|
|
4971
|
+
}
|
|
4972
|
+
var researchTool = {
|
|
4973
|
+
definition: {
|
|
4974
|
+
name: "research",
|
|
4975
|
+
description: "Your researcher. Hand it a question and it searches the web, reads the pages and source code that matter, and returns a distilled, citation-backed report. Use it for both objective research like third-party APIs and services, as well as for subjective things like current trends, patterns, and approaches (from architecture to UI to even just high-level framings and ideas). Brief it neutrally: state the question and the relevant project context, not the answer you expect.",
|
|
4976
|
+
inputSchema: {
|
|
4977
|
+
type: "object",
|
|
4978
|
+
properties: {
|
|
4979
|
+
task: {
|
|
4980
|
+
type: "string",
|
|
4981
|
+
description: "What you need to find out, in natural language, plus any project context it cannot get from reading the spec. Phrase it as a question to answer, not a conclusion to confirm."
|
|
4982
|
+
}
|
|
4983
|
+
},
|
|
4984
|
+
required: ["task"]
|
|
4985
|
+
}
|
|
4986
|
+
},
|
|
4987
|
+
async execute(input, context) {
|
|
4988
|
+
if (!context) {
|
|
4989
|
+
return "Error: research requires execution context";
|
|
4990
|
+
}
|
|
4991
|
+
return runResearch(input.task, context);
|
|
4992
|
+
}
|
|
4993
|
+
};
|
|
4900
4994
|
|
|
4901
4995
|
// src/subagents/designExpert/tools/scrapeWebUrl.ts
|
|
4902
4996
|
var scrapeWebUrl_exports = {};
|
|
4903
4997
|
__export(scrapeWebUrl_exports, {
|
|
4904
|
-
definition: () =>
|
|
4905
|
-
execute: () =>
|
|
4998
|
+
definition: () => definition,
|
|
4999
|
+
execute: () => execute
|
|
4906
5000
|
});
|
|
4907
|
-
var
|
|
5001
|
+
var definition = {
|
|
4908
5002
|
name: "scrapeWebUrl",
|
|
4909
|
-
description: "Fetch the content of a web page as markdown. Use
|
|
5003
|
+
description: "Fetch the content of a web page as markdown. Use for reading a specific URL \u2014 a site the user referenced, a brand to match, a page the researcher cited that you want in full.",
|
|
4910
5004
|
inputSchema: {
|
|
4911
5005
|
type: "object",
|
|
4912
5006
|
properties: {
|
|
@@ -4918,7 +5012,7 @@ var definition2 = {
|
|
|
4918
5012
|
required: ["url"]
|
|
4919
5013
|
}
|
|
4920
5014
|
};
|
|
4921
|
-
async function
|
|
5015
|
+
async function execute(input, onLog) {
|
|
4922
5016
|
const pageOptions = { onlyMainContent: true };
|
|
4923
5017
|
return runMindstudioCli(
|
|
4924
5018
|
[
|
|
@@ -4935,8 +5029,8 @@ async function execute2(input, onLog) {
|
|
|
4935
5029
|
// src/subagents/designExpert/tools/analyzeDesign.ts
|
|
4936
5030
|
var analyzeDesign_exports = {};
|
|
4937
5031
|
__export(analyzeDesign_exports, {
|
|
4938
|
-
definition: () =>
|
|
4939
|
-
execute: () =>
|
|
5032
|
+
definition: () => definition3,
|
|
5033
|
+
execute: () => execute3
|
|
4940
5034
|
});
|
|
4941
5035
|
import { readFile as readFile2 } from "fs/promises";
|
|
4942
5036
|
import { extname as extname2, join as join2 } from "path";
|
|
@@ -4945,8 +5039,8 @@ import { extname as extname2, join as join2 } from "path";
|
|
|
4945
5039
|
var renderImage_exports = {};
|
|
4946
5040
|
__export(renderImage_exports, {
|
|
4947
5041
|
RENDER_ANALYZE_PROMPT: () => RENDER_ANALYZE_PROMPT,
|
|
4948
|
-
definition: () =>
|
|
4949
|
-
execute: () =>
|
|
5042
|
+
definition: () => definition2,
|
|
5043
|
+
execute: () => execute2
|
|
4950
5044
|
});
|
|
4951
5045
|
import { mkdir, unlink, writeFile } from "fs/promises";
|
|
4952
5046
|
import { tmpdir } from "os";
|
|
@@ -4955,7 +5049,7 @@ import { randomUUID } from "crypto";
|
|
|
4955
5049
|
var MIN_DIMENSION = 16;
|
|
4956
5050
|
var MAX_DIMENSION = 4096;
|
|
4957
5051
|
var RENDER_ANALYZE_PROMPT = 'You are reviewing a browser-rendered graphic (composed from HTML/CSS by a designer) for fidelity. Report: whether the composition fills the full canvas or leaves unintended gaps at any edge, any clipped or overflowing text, whether custom webfonts appear to have loaded (distinctive letterforms vs generic fallback serif/sans), any misalignment or uneven spacing, any unintended scrollbars or default-styling artifacts, and \u2014 if the background is transparent \u2014 any fringing or stray opaque pixels at the edges. Then briefly describe the overall composition and how polished it looks. Be concise and practical. Respond only with your analysis as Markdown (starting with the title "Render Review") and absolutely no other text. Do not use emojis - use unicode if you need symbols.';
|
|
4958
|
-
var
|
|
5052
|
+
var definition2 = {
|
|
4959
5053
|
name: "renderImage",
|
|
4960
5054
|
description: "Render a self-contained HTML document in a real browser and capture it as a hosted PNG at exact pixel dimensions, with a fidelity review included. Deterministic \u2014 exact hex colors, real loaded webfonts, precise geometry \u2014 unlike generateImages, which is an image model. Use for token-exact graphics: Open Graph share cards, wordmarks, flat/geometric icon tiles, badges, any composition where letterforms and spacing carry the design. Compose with HTML/CSS (link webfonts from CDNs \u2014 the renderer waits for them to load); inline existing SVG markup when needed, but never hand-write new SVG path data.",
|
|
4961
5055
|
inputSchema: {
|
|
@@ -4989,7 +5083,7 @@ var definition3 = {
|
|
|
4989
5083
|
required: ["html", "width", "height"]
|
|
4990
5084
|
}
|
|
4991
5085
|
};
|
|
4992
|
-
async function
|
|
5086
|
+
async function execute2(input, onLog, context) {
|
|
4993
5087
|
const html = typeof input.html === "string" ? input.html : "";
|
|
4994
5088
|
const width = Math.round(Number(input.width));
|
|
4995
5089
|
const height = Math.round(Number(input.height));
|
|
@@ -5098,7 +5192,7 @@ Identify the specific design moves that make this page interesting and unique, d
|
|
|
5098
5192
|
|
|
5099
5193
|
Respond only with your analysis as Markdown and absolutely no other text. Do not use emojis - use unicode if you need symbols.
|
|
5100
5194
|
`;
|
|
5101
|
-
var
|
|
5195
|
+
var definition3 = {
|
|
5102
5196
|
name: "analyzeDesign",
|
|
5103
5197
|
description: "Analyze the visual design of a website, an image (URL or file on disk), or an HTML document on disk. Websites are screenshotted first; an HTML file is rendered in a real browser first and the render is analyzed, which is how you look at a wireframe you authored. Provides static image analysis only, will not capture animations or video. With no prompt, a website or image gets a full design reference analysis (mood, color, typography, layout, distinctiveness) and a rendered HTML document gets a fidelity review (clipping, overflow, webfont loading, alignment). Provide a custom prompt to ask a specific design question instead. Use a bulleted list to ask many questions at once.",
|
|
5104
5198
|
inputSchema: {
|
|
@@ -5138,7 +5232,7 @@ function splitFrontmatter(raw) {
|
|
|
5138
5232
|
html: raw.slice(match[0].length)
|
|
5139
5233
|
};
|
|
5140
5234
|
}
|
|
5141
|
-
async function
|
|
5235
|
+
async function execute3(input, onLog, context) {
|
|
5142
5236
|
const url = String(input.url ?? "").trim();
|
|
5143
5237
|
if (!url) {
|
|
5144
5238
|
return "Error: url is required.";
|
|
@@ -5246,10 +5340,10 @@ ${basePrompt}` : basePrompt;
|
|
|
5246
5340
|
// src/subagents/designExpert/tools/analyzeImage.ts
|
|
5247
5341
|
var analyzeImage_exports = {};
|
|
5248
5342
|
__export(analyzeImage_exports, {
|
|
5249
|
-
definition: () =>
|
|
5250
|
-
execute: () =>
|
|
5343
|
+
definition: () => definition4,
|
|
5344
|
+
execute: () => execute4
|
|
5251
5345
|
});
|
|
5252
|
-
var
|
|
5346
|
+
var definition4 = {
|
|
5253
5347
|
name: "analyzeImage",
|
|
5254
5348
|
description: "Analyze an image using a vision model. Provides static image analysis only, will not capture animations or video. 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. Optionally provide specific questions about what you're looking for. Use a bulleted list to ask many questions at once. If you are analyzing a screenshot of the app preview, you can reuse the same screenshot URL multiple times to ask multiple questions.",
|
|
5255
5349
|
inputSchema: {
|
|
@@ -5270,7 +5364,7 @@ var definition5 = {
|
|
|
5270
5364
|
required: ["imageUrl"]
|
|
5271
5365
|
}
|
|
5272
5366
|
};
|
|
5273
|
-
async function
|
|
5367
|
+
async function execute4(input, onLog, context) {
|
|
5274
5368
|
const prompt = buildScreenshotAnalysisPrompt({
|
|
5275
5369
|
prompt: input.prompt
|
|
5276
5370
|
});
|
|
@@ -5287,8 +5381,8 @@ async function execute5(input, onLog, context) {
|
|
|
5287
5381
|
// src/subagents/designExpert/tools/images/generateImages.ts
|
|
5288
5382
|
var generateImages_exports = {};
|
|
5289
5383
|
__export(generateImages_exports, {
|
|
5290
|
-
definition: () =>
|
|
5291
|
-
execute: () =>
|
|
5384
|
+
definition: () => definition5,
|
|
5385
|
+
execute: () => execute5
|
|
5292
5386
|
});
|
|
5293
5387
|
|
|
5294
5388
|
// src/subagents/designExpert/tools/images/enhancePrompt.ts
|
|
@@ -5515,7 +5609,7 @@ async function generateImageAssets(opts) {
|
|
|
5515
5609
|
}
|
|
5516
5610
|
|
|
5517
5611
|
// src/subagents/designExpert/tools/images/generateImages.ts
|
|
5518
|
-
var
|
|
5612
|
+
var definition5 = {
|
|
5519
5613
|
name: "generateImages",
|
|
5520
5614
|
description: "Generate images. Returns CDN URLs with a quality analysis for each image. Produces high-quality results for everything from photorealistic images and abstract/creative visuals. Pass multiple prompts to generate in parallel. No need to analyze images separately after generating \u2014 the analysis is included.",
|
|
5521
5615
|
inputSchema: {
|
|
@@ -5548,7 +5642,7 @@ var definition6 = {
|
|
|
5548
5642
|
required: ["prompts"]
|
|
5549
5643
|
}
|
|
5550
5644
|
};
|
|
5551
|
-
async function
|
|
5645
|
+
async function execute5(input, onLog, context) {
|
|
5552
5646
|
return generateImageAssets({
|
|
5553
5647
|
prompts: input.prompts,
|
|
5554
5648
|
width: input.width,
|
|
@@ -5579,10 +5673,10 @@ async function execute6(input, onLog, context) {
|
|
|
5579
5673
|
// src/subagents/designExpert/tools/images/editImages.ts
|
|
5580
5674
|
var editImages_exports = {};
|
|
5581
5675
|
__export(editImages_exports, {
|
|
5582
|
-
definition: () =>
|
|
5583
|
-
execute: () =>
|
|
5676
|
+
definition: () => definition6,
|
|
5677
|
+
execute: () => execute6
|
|
5584
5678
|
});
|
|
5585
|
-
var
|
|
5679
|
+
var definition6 = {
|
|
5586
5680
|
name: "editImages",
|
|
5587
5681
|
description: "Edit or transform existing images. Provide one or more source image URLs as reference and a prompt describing the desired edit. Use for compositing, style transfer, subject transformation, blending multiple references, or incorporating one or more references into something new. Returns CDN URLs with analysis.",
|
|
5588
5682
|
inputSchema: {
|
|
@@ -5618,7 +5712,7 @@ var definition7 = {
|
|
|
5618
5712
|
required: ["prompts", "sourceImages"]
|
|
5619
5713
|
}
|
|
5620
5714
|
};
|
|
5621
|
-
async function
|
|
5715
|
+
async function execute6(input, onLog, context) {
|
|
5622
5716
|
return generateImageAssets({
|
|
5623
5717
|
prompts: input.prompts,
|
|
5624
5718
|
sourceImages: input.sourceImages,
|
|
@@ -5649,15 +5743,15 @@ async function execute7(input, onLog, context) {
|
|
|
5649
5743
|
// src/subagents/designExpert/tools/polishCopy.ts
|
|
5650
5744
|
var polishCopy_exports = {};
|
|
5651
5745
|
__export(polishCopy_exports, {
|
|
5652
|
-
definition: () =>
|
|
5653
|
-
execute: () =>
|
|
5746
|
+
definition: () => definition7,
|
|
5747
|
+
execute: () => execute7
|
|
5654
5748
|
});
|
|
5655
5749
|
|
|
5656
5750
|
// src/subagents/copyEditor/tools.ts
|
|
5657
5751
|
var COPY_EDITOR_TOOLS = [...COMMON_READ_TOOLS];
|
|
5658
5752
|
|
|
5659
5753
|
// src/subagents/copyEditor/index.ts
|
|
5660
|
-
var
|
|
5754
|
+
var BASE_PROMPT3 = readAsset("subagents/copyEditor", "prompt.md");
|
|
5661
5755
|
var copyEditorTool = {
|
|
5662
5756
|
definition: {
|
|
5663
5757
|
name: "copyEditor",
|
|
@@ -5678,7 +5772,7 @@ var copyEditorTool = {
|
|
|
5678
5772
|
return "Error: copy editor requires execution context";
|
|
5679
5773
|
}
|
|
5680
5774
|
const specIndex = loadSpecIndex();
|
|
5681
|
-
const parts = [
|
|
5775
|
+
const parts = [BASE_PROMPT3];
|
|
5682
5776
|
parts.push("<!-- cache_breakpoint -->");
|
|
5683
5777
|
if (specIndex) {
|
|
5684
5778
|
parts.push(specIndex);
|
|
@@ -5712,7 +5806,7 @@ var copyEditorTool = {
|
|
|
5712
5806
|
};
|
|
5713
5807
|
|
|
5714
5808
|
// src/subagents/designExpert/tools/polishCopy.ts
|
|
5715
|
-
var
|
|
5809
|
+
var definition7 = {
|
|
5716
5810
|
name: "polishCopy",
|
|
5717
5811
|
description: "Hand off any user-facing copy you've written \u2014 headlines, captions, labels, body text \u2014 and get back a sharper version: better built for its audience and free of the fingerprints that make writing read as AI. It elevates how the copy communicates without inventing facts or claims you didn't give it. Give it the text plus what it's for (where it appears, the audience).",
|
|
5718
5812
|
inputSchema: {
|
|
@@ -5726,15 +5820,15 @@ var definition8 = {
|
|
|
5726
5820
|
required: ["task"]
|
|
5727
5821
|
}
|
|
5728
5822
|
};
|
|
5729
|
-
async function
|
|
5823
|
+
async function execute7(input, _onLog, context) {
|
|
5730
5824
|
return copyEditorTool.execute(input, context);
|
|
5731
5825
|
}
|
|
5732
5826
|
|
|
5733
5827
|
// src/subagents/designExpert/tools/loadSkill.ts
|
|
5734
5828
|
var loadSkill_exports = {};
|
|
5735
5829
|
__export(loadSkill_exports, {
|
|
5736
|
-
definition: () =>
|
|
5737
|
-
execute: () =>
|
|
5830
|
+
definition: () => definition8,
|
|
5831
|
+
execute: () => execute8
|
|
5738
5832
|
});
|
|
5739
5833
|
|
|
5740
5834
|
// src/subagents/designExpert/skills/_catalog.ts
|
|
@@ -5748,7 +5842,7 @@ var designSkillCatalog = buildSkillCatalog({
|
|
|
5748
5842
|
});
|
|
5749
5843
|
|
|
5750
5844
|
// src/subagents/designExpert/tools/loadSkill.ts
|
|
5751
|
-
var
|
|
5845
|
+
var definition8 = {
|
|
5752
5846
|
name: "loadSkill",
|
|
5753
5847
|
description: "Load the full craft reference for a design surface that isn't in your prompt. The available skills and the trigger for each are listed in <available_skills>. Load one before designing in its area, not after \u2014 these are hard-won technique recipes, and the defaulted version of these surfaces is exactly what they exist to prevent. Calling this is cheap and expected \u2014 if you're unsure whether you need it, load it.",
|
|
5754
5848
|
inputSchema: {
|
|
@@ -5766,7 +5860,7 @@ var definition9 = {
|
|
|
5766
5860
|
required: ["skill"]
|
|
5767
5861
|
}
|
|
5768
5862
|
};
|
|
5769
|
-
async function
|
|
5863
|
+
async function execute8(input) {
|
|
5770
5864
|
const id = String(input.skill ?? "");
|
|
5771
5865
|
const skill = designSkillCatalog.get(id);
|
|
5772
5866
|
if (!skill) {
|
|
@@ -5787,15 +5881,15 @@ This reference lives at ${skill.path}. Re-read it with readFile if you need it a
|
|
|
5787
5881
|
var createWireframe_exports = {};
|
|
5788
5882
|
__export(createWireframe_exports, {
|
|
5789
5883
|
WIREFRAMES_DIR: () => WIREFRAMES_DIR,
|
|
5790
|
-
definition: () =>
|
|
5791
|
-
execute: () =>
|
|
5884
|
+
definition: () => definition9,
|
|
5885
|
+
execute: () => execute9
|
|
5792
5886
|
});
|
|
5793
5887
|
import { mkdir as mkdir2, stat as stat2, writeFile as writeFile2 } from "fs/promises";
|
|
5794
5888
|
import { join as join3 } from "path";
|
|
5795
5889
|
var log9 = createLogger("createWireframe");
|
|
5796
5890
|
var WIREFRAMES_DIR = "src/.wireframes";
|
|
5797
5891
|
var UPLOAD_TIMEOUT_MS2 = 3e4;
|
|
5798
|
-
var
|
|
5892
|
+
var definition9 = {
|
|
5799
5893
|
name: "createWireframe",
|
|
5800
5894
|
description: "Generate a wireframe from self-contained HTML+CSS you author and write it to disk as a design artifact. This is how a wireframe comes to exist \u2014 the way generateImages is how an image comes to exist \u2014 and the developer builds from the file it creates. The result also hands back the reference line that embeds the wireframe in your response and in specs; paste it wherever the wireframe belongs and it renders as a live preview. Calling again with the same slug revises the wireframe in place, so existing references stay current \u2014 a revision is a call to this tool, never a prose description of changes to an earlier wireframe.",
|
|
5801
5895
|
inputSchema: {
|
|
@@ -5889,7 +5983,7 @@ async function uploadMirror(context, slug, content) {
|
|
|
5889
5983
|
return { ok: false, note: err.message };
|
|
5890
5984
|
}
|
|
5891
5985
|
}
|
|
5892
|
-
async function
|
|
5986
|
+
async function execute9(input, onLog, context) {
|
|
5893
5987
|
if (!context) {
|
|
5894
5988
|
return "Error: createWireframe requires execution context";
|
|
5895
5989
|
}
|
|
@@ -5937,8 +6031,29 @@ async function execute10(input, onLog, context) {
|
|
|
5937
6031
|
}
|
|
5938
6032
|
|
|
5939
6033
|
// src/subagents/designExpert/tools/index.ts
|
|
6034
|
+
var research = {
|
|
6035
|
+
definition: {
|
|
6036
|
+
name: "research",
|
|
6037
|
+
description: "Your researcher, for design questions your built-in catalogs and expertise do not settle: how leading products present a specific kind of data or interaction, current conventions or best practices for a pattern, general-purpose ideas and inspiration. It searches the web, reads the sources that matter, and returns a distilled report with citations and concrete specifics. Brief it neutrally: the question or topic, not the answer you expect.",
|
|
6038
|
+
inputSchema: {
|
|
6039
|
+
type: "object",
|
|
6040
|
+
properties: {
|
|
6041
|
+
task: {
|
|
6042
|
+
type: "string",
|
|
6043
|
+
description: "What you need to find out, in natural language, with enough product context to make the findings relevant."
|
|
6044
|
+
}
|
|
6045
|
+
},
|
|
6046
|
+
required: ["task"]
|
|
6047
|
+
}
|
|
6048
|
+
},
|
|
6049
|
+
execute: (input, _onLog, context) => {
|
|
6050
|
+
if (!context) {
|
|
6051
|
+
return Promise.resolve("Error: research requires execution context");
|
|
6052
|
+
}
|
|
6053
|
+
return runResearch(input.task, context);
|
|
6054
|
+
}
|
|
6055
|
+
};
|
|
5940
6056
|
var tools = {
|
|
5941
|
-
searchGoogle: searchGoogle_exports,
|
|
5942
6057
|
scrapeWebUrl: scrapeWebUrl_exports,
|
|
5943
6058
|
analyzeDesign: analyzeDesign_exports,
|
|
5944
6059
|
analyzeImage: analyzeImage_exports,
|
|
@@ -5952,7 +6067,8 @@ var tools = {
|
|
|
5952
6067
|
polishCopy: polishCopy_exports,
|
|
5953
6068
|
loadSkill: loadSkill_exports,
|
|
5954
6069
|
// Appended last: tool order is part of the subagent's prompt-cache prefix.
|
|
5955
|
-
createWireframe: createWireframe_exports
|
|
6070
|
+
createWireframe: createWireframe_exports,
|
|
6071
|
+
research
|
|
5956
6072
|
};
|
|
5957
6073
|
var DESIGN_EXPERT_TOOLS = [
|
|
5958
6074
|
...COMMON_READ_TOOLS,
|
|
@@ -6510,11 +6626,11 @@ ${result.text}`;
|
|
|
6510
6626
|
}
|
|
6511
6627
|
|
|
6512
6628
|
// src/subagents/productVision/prompt.ts
|
|
6513
|
-
var
|
|
6629
|
+
var BASE_PROMPT4 = readAsset("subagents/productVision", "prompt.md");
|
|
6514
6630
|
function getProductVisionPrompt() {
|
|
6515
6631
|
const specIndex = loadSpecIndex();
|
|
6516
6632
|
const roadmapIndex = loadRoadmapIndex();
|
|
6517
|
-
const parts = [
|
|
6633
|
+
const parts = [BASE_PROMPT4, loadPlatformBrief()];
|
|
6518
6634
|
parts.push("<!-- cache_breakpoint -->");
|
|
6519
6635
|
if (specIndex) {
|
|
6520
6636
|
parts.push(specIndex);
|
|
@@ -6638,11 +6754,26 @@ var SANITY_CHECK_TOOLS = [
|
|
|
6638
6754
|
},
|
|
6639
6755
|
required: ["command"]
|
|
6640
6756
|
}
|
|
6757
|
+
},
|
|
6758
|
+
// Appended last: tool order is part of the subagent's prompt-cache prefix.
|
|
6759
|
+
{
|
|
6760
|
+
name: "research",
|
|
6761
|
+
description: "Deep researcher. When the plan hinges on an unfamiliar third-party service, API, or claim you cannot settle with a quick search, hand it the question \u2014 it researches properly (multiple sources, official docs, reading real source code) and returns a distilled, citation-backed report. Quick package-liveness checks stay on searchGoogle; use this when being wrong would be expensive. Brief it neutrally: the question, not the answer you expect.",
|
|
6762
|
+
inputSchema: {
|
|
6763
|
+
type: "object",
|
|
6764
|
+
properties: {
|
|
6765
|
+
task: {
|
|
6766
|
+
type: "string",
|
|
6767
|
+
description: "What you need to find out, in natural language."
|
|
6768
|
+
}
|
|
6769
|
+
},
|
|
6770
|
+
required: ["task"]
|
|
6771
|
+
}
|
|
6641
6772
|
}
|
|
6642
6773
|
];
|
|
6643
6774
|
|
|
6644
6775
|
// src/subagents/codeSanityCheck/index.ts
|
|
6645
|
-
var
|
|
6776
|
+
var BASE_PROMPT5 = readAsset("subagents/codeSanityCheck", "prompt.md");
|
|
6646
6777
|
var codeSanityCheckTool = {
|
|
6647
6778
|
definition: {
|
|
6648
6779
|
name: "codeSanityCheck",
|
|
@@ -6663,7 +6794,7 @@ var codeSanityCheckTool = {
|
|
|
6663
6794
|
return "Error: code sanity check requires execution context";
|
|
6664
6795
|
}
|
|
6665
6796
|
const specIndex = loadSpecIndex();
|
|
6666
|
-
const parts = [
|
|
6797
|
+
const parts = [BASE_PROMPT5, loadPlatformBrief()];
|
|
6667
6798
|
parts.push("<!-- cache_breakpoint -->");
|
|
6668
6799
|
if (specIndex) {
|
|
6669
6800
|
parts.push(specIndex);
|
|
@@ -6679,6 +6810,16 @@ var codeSanityCheckTool = {
|
|
|
6679
6810
|
...deriveContext(context, toolCallId, onLog),
|
|
6680
6811
|
subAgentMessages: sams
|
|
6681
6812
|
} : context;
|
|
6813
|
+
if (name === "searchGoogle") {
|
|
6814
|
+
return executeSearchGoogle(
|
|
6815
|
+
{ ...toolInput, fetchTopN: 5 },
|
|
6816
|
+
childCtx.onLog,
|
|
6817
|
+
"codeSanityCheck"
|
|
6818
|
+
);
|
|
6819
|
+
}
|
|
6820
|
+
if (name === "research") {
|
|
6821
|
+
return runResearch(String(toolInput.task ?? ""), childCtx);
|
|
6822
|
+
}
|
|
6682
6823
|
return executeTool(name, toolInput, childCtx);
|
|
6683
6824
|
},
|
|
6684
6825
|
apiConfig: context.apiConfig,
|
|
@@ -6832,7 +6973,7 @@ function acquireSpecSyncLock() {
|
|
|
6832
6973
|
}
|
|
6833
6974
|
|
|
6834
6975
|
// src/subagents/specSync/index.ts
|
|
6835
|
-
var
|
|
6976
|
+
var BASE_PROMPT6 = readAsset("subagents/specSync", "prompt.md");
|
|
6836
6977
|
var MSFM_DOCS = `<mindstudio_flavored_markdown_spec_docs>
|
|
6837
6978
|
${readAsset(
|
|
6838
6979
|
"prompt",
|
|
@@ -6871,7 +7012,7 @@ var specSyncTool = {
|
|
|
6871
7012
|
}
|
|
6872
7013
|
const specIndex = loadSpecIndex();
|
|
6873
7014
|
const parts = [
|
|
6874
|
-
|
|
7015
|
+
BASE_PROMPT6,
|
|
6875
7016
|
loadPlatformBrief(),
|
|
6876
7017
|
MSFM_DOCS,
|
|
6877
7018
|
"<!-- cache_breakpoint -->"
|
|
@@ -6986,7 +7127,6 @@ var ALL_TOOLS = [
|
|
|
6986
7127
|
confirmDestructiveActionTool,
|
|
6987
7128
|
askMindStudioSdkTool,
|
|
6988
7129
|
scrapeWebUrlTool,
|
|
6989
|
-
searchGoogleTool,
|
|
6990
7130
|
setProjectMetadataTool,
|
|
6991
7131
|
designExpertTool,
|
|
6992
7132
|
productVisionTool,
|
|
@@ -7025,7 +7165,8 @@ var ALL_TOOLS = [
|
|
|
7025
7165
|
// Appended rather than grouped: position is part of the cache prefix, so a
|
|
7026
7166
|
// new tool goes at the end to leave every existing session's prefix intact.
|
|
7027
7167
|
loadSkillTool,
|
|
7028
|
-
testJewelTool
|
|
7168
|
+
testJewelTool,
|
|
7169
|
+
researchTool
|
|
7029
7170
|
];
|
|
7030
7171
|
var SUBAGENT_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
7031
7172
|
"visualDesignExpert",
|
|
@@ -7034,7 +7175,8 @@ var SUBAGENT_TOOL_NAMES = /* @__PURE__ */ new Set([
|
|
|
7034
7175
|
"copyEditor",
|
|
7035
7176
|
"specSync",
|
|
7036
7177
|
"runAutomatedBrowserTest",
|
|
7037
|
-
"askMindStudioSdk"
|
|
7178
|
+
"askMindStudioSdk",
|
|
7179
|
+
"research"
|
|
7038
7180
|
]);
|
|
7039
7181
|
function getToolDefinitions() {
|
|
7040
7182
|
return ALL_TOOLS.map((t) => t.definition);
|
|
@@ -8616,6 +8758,12 @@ function classify(line, matches) {
|
|
|
8616
8758
|
tailClean = SEPARATORS_ONLY.test(gap);
|
|
8617
8759
|
}
|
|
8618
8760
|
}
|
|
8761
|
+
function chipCase(label) {
|
|
8762
|
+
if (label.startsWith("`")) {
|
|
8763
|
+
return label;
|
|
8764
|
+
}
|
|
8765
|
+
return label.charAt(0).toUpperCase() + label.slice(1);
|
|
8766
|
+
}
|
|
8619
8767
|
function parseSuggestions(raw) {
|
|
8620
8768
|
if (!raw.includes(SUGGEST_MARKER)) {
|
|
8621
8769
|
return { text: raw, suggestions: [] };
|
|
@@ -8645,7 +8793,7 @@ function parseSuggestions(raw) {
|
|
|
8645
8793
|
const key = `${m.label}::${m.message}`;
|
|
8646
8794
|
if (!seen.has(key)) {
|
|
8647
8795
|
seen.add(key);
|
|
8648
|
-
suggestions.push({ label: m.label, message: m.message });
|
|
8796
|
+
suggestions.push({ label: chipCase(m.label), message: m.message });
|
|
8649
8797
|
}
|
|
8650
8798
|
}
|
|
8651
8799
|
let rebuilt = "";
|
|
@@ -8745,10 +8893,12 @@ async function runTurn(params) {
|
|
|
8745
8893
|
onBackgroundComplete
|
|
8746
8894
|
} = params;
|
|
8747
8895
|
const tools2 = getToolDefinitions();
|
|
8748
|
-
const
|
|
8749
|
-
|
|
8750
|
-
|
|
8751
|
-
|
|
8896
|
+
const { baseline, effective: parentModel } = resolveParentModel(
|
|
8897
|
+
state.models,
|
|
8898
|
+
model,
|
|
8899
|
+
buildModel
|
|
8900
|
+
);
|
|
8901
|
+
const modelOverride = parentModel !== baseline ? { from: baseline } : void 0;
|
|
8752
8902
|
const totalAttachments = entries.reduce(
|
|
8753
8903
|
(n, e) => n + (e.attachments?.length ?? 0),
|
|
8754
8904
|
0
|
|
@@ -8756,7 +8906,7 @@ async function runTurn(params) {
|
|
|
8756
8906
|
log15.info("Turn started", {
|
|
8757
8907
|
requestId,
|
|
8758
8908
|
model,
|
|
8759
|
-
buildModel:
|
|
8909
|
+
buildModel: modelOverride ? parentModel : void 0,
|
|
8760
8910
|
toolCount: tools2.length,
|
|
8761
8911
|
...entries.length > 1 && { entryCount: entries.length },
|
|
8762
8912
|
...totalAttachments > 0 && { attachmentCount: totalAttachments }
|
|
@@ -9591,12 +9741,13 @@ function loadPassiveResults() {
|
|
|
9591
9741
|
}
|
|
9592
9742
|
return [];
|
|
9593
9743
|
}
|
|
9594
|
-
function writeStats(stats, queue, passiveResults) {
|
|
9744
|
+
function writeStats(stats, queue, passiveResults, suggestCompactAt) {
|
|
9595
9745
|
try {
|
|
9596
9746
|
writeFileAtomicSync(
|
|
9597
9747
|
STATS_FILE,
|
|
9598
9748
|
JSON.stringify({
|
|
9599
9749
|
...stats,
|
|
9750
|
+
suggestCompactAt,
|
|
9600
9751
|
queue,
|
|
9601
9752
|
passiveResults
|
|
9602
9753
|
})
|
|
@@ -9798,7 +9949,6 @@ var USER_FACING_TOOLS = /* @__PURE__ */ new Set([
|
|
|
9798
9949
|
"confirmDestructiveAction",
|
|
9799
9950
|
"presentPublishPlan"
|
|
9800
9951
|
]);
|
|
9801
|
-
var FORCED_COMPACTION_THRESHOLD_TOKENS = 85e4;
|
|
9802
9952
|
var HeadlessSession = class {
|
|
9803
9953
|
// Configuration
|
|
9804
9954
|
opts;
|
|
@@ -10071,7 +10221,15 @@ var HeadlessSession = class {
|
|
|
10071
10221
|
/** Persist sessionStats + queue snapshot + passive pen to .remy-stats.json. */
|
|
10072
10222
|
persistStats() {
|
|
10073
10223
|
this.sessionStats.updatedAt = Date.now();
|
|
10074
|
-
|
|
10224
|
+
const suggestCompactAt = getSuggestCompactAt(
|
|
10225
|
+
resolveParentModel(this.state.models, this.opts.model).effective
|
|
10226
|
+
);
|
|
10227
|
+
writeStats(
|
|
10228
|
+
this.sessionStats,
|
|
10229
|
+
this.queue.snapshot(),
|
|
10230
|
+
this.passivePen,
|
|
10231
|
+
suggestCompactAt
|
|
10232
|
+
);
|
|
10075
10233
|
}
|
|
10076
10234
|
//////////////////////////////////////////////////////////////////////////////
|
|
10077
10235
|
// Background completions (tool-block mutation; message delivery via queue)
|
|
@@ -10101,8 +10259,9 @@ var HeadlessSession = class {
|
|
|
10101
10259
|
saveSession(this.state);
|
|
10102
10260
|
}
|
|
10103
10261
|
/**
|
|
10104
|
-
* Forced compaction gate. If lastContextSize exceeds the
|
|
10105
|
-
*
|
|
10262
|
+
* Forced compaction gate. If lastContextSize exceeds the upcoming turn's
|
|
10263
|
+
* model threshold (per-model — see ModelContextLimits in models/surfaces),
|
|
10264
|
+
* compact before letting the turn run. Coalesces with any in-flight
|
|
10106
10265
|
* compaction (e.g., one already started by /compact or a tool call). No
|
|
10107
10266
|
* timeout — compaction takes as long as it takes.
|
|
10108
10267
|
*
|
|
@@ -10113,13 +10272,15 @@ var HeadlessSession = class {
|
|
|
10113
10272
|
* On compaction failure we don't bail — the turn proceeds and surfaces any
|
|
10114
10273
|
* downstream overflow through the existing "prompt is too long" path.
|
|
10115
10274
|
*/
|
|
10116
|
-
async runForcedCompactionIfNeeded(requestId) {
|
|
10117
|
-
|
|
10275
|
+
async runForcedCompactionIfNeeded(requestId, parentModel) {
|
|
10276
|
+
const threshold = getContextLimits(parentModel).forceCompactAt;
|
|
10277
|
+
if (this.sessionStats.lastContextSize <= threshold) {
|
|
10118
10278
|
return;
|
|
10119
10279
|
}
|
|
10120
10280
|
log17.info("Forced compaction gate triggered", {
|
|
10121
10281
|
contextSize: this.sessionStats.lastContextSize,
|
|
10122
|
-
threshold
|
|
10282
|
+
threshold,
|
|
10283
|
+
model: parentModel,
|
|
10123
10284
|
requestId
|
|
10124
10285
|
});
|
|
10125
10286
|
try {
|
|
@@ -10601,7 +10762,12 @@ var HeadlessSession = class {
|
|
|
10601
10762
|
}
|
|
10602
10763
|
return steered;
|
|
10603
10764
|
};
|
|
10604
|
-
|
|
10765
|
+
const parentModel = resolveParentModel(
|
|
10766
|
+
this.state.models,
|
|
10767
|
+
this.opts.model,
|
|
10768
|
+
params.buildModel
|
|
10769
|
+
).effective;
|
|
10770
|
+
await this.runForcedCompactionIfNeeded(requestId, parentModel);
|
|
10605
10771
|
try {
|
|
10606
10772
|
await runTurn({
|
|
10607
10773
|
state: this.state,
|