@mindstudio-ai/remy 0.1.332 → 0.1.334
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 +258 -268
- package/dist/index.js +206 -204
- package/dist/prompt/compiled/msfm.md +29 -5
- package/dist/prompt/skills/auth.md +1 -0
- package/dist/prompt/skills/scenarios.md +13 -3
- package/dist/prompt/static/spec-maintenance.md +1 -1
- package/dist/subagents/productVision/prompt.md +27 -15
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -332,6 +332,10 @@ async function* streamChat(params) {
|
|
|
332
332
|
requestId,
|
|
333
333
|
...subAgentId && { subAgentId },
|
|
334
334
|
error: event.error,
|
|
335
|
+
// The code decides whether this retries, so omitting it made a
|
|
336
|
+
// debug bundle unable to answer why a turn died — the whole
|
|
337
|
+
// classification input was invisible in 32k log lines (RPT-1234).
|
|
338
|
+
...event.code && { code: event.code },
|
|
335
339
|
durationMs: Date.now() - startTime
|
|
336
340
|
});
|
|
337
341
|
}
|
|
@@ -363,13 +367,17 @@ function isRetryableError(error, code) {
|
|
|
363
367
|
if (code && RETRYABLE_ERROR_CODES.has(code)) {
|
|
364
368
|
return true;
|
|
365
369
|
}
|
|
370
|
+
if (code && RETRYABLE_ERROR_CODE_PREFIXES.some((p) => code.startsWith(p))) {
|
|
371
|
+
return true;
|
|
372
|
+
}
|
|
366
373
|
return /Network error/i.test(error) || /HTTP 5\d\d/i.test(error) || /Stream stalled/i.test(error) || /overloaded/i.test(error) || /terminated/i.test(error) || // The API's friendly mapping of a provider 500 — belt-and-suspenders for
|
|
367
374
|
// pods that don't send a machine-readable code.
|
|
368
|
-
/Internal API error/i.test(error) || //
|
|
369
|
-
//
|
|
370
|
-
//
|
|
371
|
-
//
|
|
372
|
-
|
|
375
|
+
/Internal API error/i.test(error) || // Server-side media-fetch failures, for providers that send no usable
|
|
376
|
+
// code. Matching PROSE is the fallback, not the mechanism: keying on one
|
|
377
|
+
// vendor's wording is what let this class through before — Anthropic's
|
|
378
|
+
// "Unable to download" was handled while Meta's "failed to download
|
|
379
|
+
// media" was fatal, for the identical failure with the identical remedy.
|
|
380
|
+
/Unable to download/i.test(error) || /failed to download media/i.test(error);
|
|
373
381
|
}
|
|
374
382
|
function sleep(ms) {
|
|
375
383
|
return new Promise((resolve4) => setTimeout(resolve4, ms));
|
|
@@ -470,6 +478,41 @@ async function generateBackgroundAck(params) {
|
|
|
470
478
|
return FALLBACK_ACK;
|
|
471
479
|
}
|
|
472
480
|
}
|
|
481
|
+
async function fetchModelSurfaces(config) {
|
|
482
|
+
const url = `${config.baseUrl}/v1/site-settings/remy-model-surfaces`;
|
|
483
|
+
let lastError = "";
|
|
484
|
+
for (let attempt = 1; attempt <= SURFACES_FETCH_ATTEMPTS; attempt++) {
|
|
485
|
+
try {
|
|
486
|
+
const res = await fetch(url, {
|
|
487
|
+
method: "GET",
|
|
488
|
+
signal: AbortSignal.timeout(2e4)
|
|
489
|
+
});
|
|
490
|
+
if (!res.ok) {
|
|
491
|
+
lastError = `HTTP ${res.status}`;
|
|
492
|
+
} else {
|
|
493
|
+
const data = await res.json();
|
|
494
|
+
if (Array.isArray(data?.surfaces) && data.surfaces.length > 0) {
|
|
495
|
+
return data;
|
|
496
|
+
}
|
|
497
|
+
lastError = "response carried no surfaces";
|
|
498
|
+
}
|
|
499
|
+
} catch (err) {
|
|
500
|
+
lastError = err?.message ?? String(err);
|
|
501
|
+
}
|
|
502
|
+
if (attempt < SURFACES_FETCH_ATTEMPTS) {
|
|
503
|
+
const backoffMs = attempt * 2e3;
|
|
504
|
+
log.debug("model-surfaces fetch failed, retrying", {
|
|
505
|
+
attempt,
|
|
506
|
+
backoffMs,
|
|
507
|
+
error: lastError
|
|
508
|
+
});
|
|
509
|
+
await new Promise((resolve4) => setTimeout(resolve4, backoffMs));
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
throw new Error(
|
|
513
|
+
`Could not load model surfaces from ${url} after ${SURFACES_FETCH_ATTEMPTS} attempts (${lastError})`
|
|
514
|
+
);
|
|
515
|
+
}
|
|
473
516
|
async function fetchRemyContext(config) {
|
|
474
517
|
if (!config.appId) {
|
|
475
518
|
return null;
|
|
@@ -497,7 +540,7 @@ async function fetchRemyContext(config) {
|
|
|
497
540
|
return null;
|
|
498
541
|
}
|
|
499
542
|
}
|
|
500
|
-
var log, MAX_RETRIES, INITIAL_BACKOFF_MS, RETRYABLE_ERROR_CODES, FALLBACK_ACK;
|
|
543
|
+
var log, MAX_RETRIES, INITIAL_BACKOFF_MS, RETRYABLE_ERROR_CODES, RETRYABLE_ERROR_CODE_PREFIXES, FALLBACK_ACK, SURFACES_FETCH_ATTEMPTS;
|
|
501
544
|
var init_api = __esm({
|
|
502
545
|
"src/api.ts"() {
|
|
503
546
|
"use strict";
|
|
@@ -512,7 +555,9 @@ var init_api = __esm({
|
|
|
512
555
|
"overloaded_error"
|
|
513
556
|
// Anthropic's 529-equivalent
|
|
514
557
|
]);
|
|
558
|
+
RETRYABLE_ERROR_CODE_PREFIXES = ["media_url_"];
|
|
515
559
|
FALLBACK_ACK = "[Message sent to agent. Agent is working in the background and will report back with its results when finished.]";
|
|
560
|
+
SURFACES_FETCH_ATTEMPTS = 3;
|
|
516
561
|
}
|
|
517
562
|
});
|
|
518
563
|
|
|
@@ -2158,8 +2203,73 @@ var init_compaction = __esm({
|
|
|
2158
2203
|
});
|
|
2159
2204
|
|
|
2160
2205
|
// src/models/surfaces.ts
|
|
2206
|
+
function setModelRegistry(payload) {
|
|
2207
|
+
const bySurface = {};
|
|
2208
|
+
for (const surface of payload.surfaces) {
|
|
2209
|
+
if (SURFACE_IDS.includes(surface.id)) {
|
|
2210
|
+
bySurface[surface.id] = {
|
|
2211
|
+
default: surface.default,
|
|
2212
|
+
label: surface.label,
|
|
2213
|
+
description: surface.description,
|
|
2214
|
+
modelType: surface.modelType,
|
|
2215
|
+
// The platform only publishes user-pickable surfaces; internal ones
|
|
2216
|
+
// (imagePromptEnhancer) are Remy's own and never appear in a picker.
|
|
2217
|
+
userPickable: true
|
|
2218
|
+
};
|
|
2219
|
+
}
|
|
2220
|
+
}
|
|
2221
|
+
const missing = SURFACE_IDS.filter(
|
|
2222
|
+
(id) => !bySurface[id] && id !== "imagePromptEnhancer"
|
|
2223
|
+
);
|
|
2224
|
+
if (missing.length > 0) {
|
|
2225
|
+
throw new Error(
|
|
2226
|
+
`The platform published no model surface for: ${missing.join(", ")}. This Remy build expects them \u2014 the platform is likely older than this release.`
|
|
2227
|
+
);
|
|
2228
|
+
}
|
|
2229
|
+
bySurface.imagePromptEnhancer = {
|
|
2230
|
+
default: bySurface.conversationSummarizer.default,
|
|
2231
|
+
label: "Image Prompt Enhancer",
|
|
2232
|
+
description: "Rewrites image briefs into model-optimized prompts before image generation.",
|
|
2233
|
+
modelType: "text",
|
|
2234
|
+
userPickable: false
|
|
2235
|
+
};
|
|
2236
|
+
surfaces = bySurface;
|
|
2237
|
+
allowedModelsByType = payload.allowedModelsByType ?? {};
|
|
2238
|
+
textModels = parseTextModels(payload.textModels);
|
|
2239
|
+
registryLoaded = true;
|
|
2240
|
+
}
|
|
2241
|
+
function parseTextModels(raw) {
|
|
2242
|
+
const out = /* @__PURE__ */ new Map();
|
|
2243
|
+
if (!raw || typeof raw !== "object") {
|
|
2244
|
+
return out;
|
|
2245
|
+
}
|
|
2246
|
+
for (const [id, value] of Object.entries(raw)) {
|
|
2247
|
+
const force = value?.forceCompactAt;
|
|
2248
|
+
if (!id || typeof force !== "number" || !Number.isFinite(force) || force <= 0) {
|
|
2249
|
+
continue;
|
|
2250
|
+
}
|
|
2251
|
+
const suggest = value?.suggestCompactAt;
|
|
2252
|
+
out.set(id, {
|
|
2253
|
+
forceCompactAt: force,
|
|
2254
|
+
...typeof suggest === "number" && Number.isFinite(suggest) && suggest > 0 ? { suggestCompactAt: suggest } : {}
|
|
2255
|
+
});
|
|
2256
|
+
}
|
|
2257
|
+
return out;
|
|
2258
|
+
}
|
|
2259
|
+
function requireSurface(surfaceId) {
|
|
2260
|
+
const surface = surfaces[surfaceId];
|
|
2261
|
+
if (!surface) {
|
|
2262
|
+
throw new Error(
|
|
2263
|
+
registryLoaded ? `Unknown model surface '${surfaceId}'.` : `Model surfaces were read before the platform registry loaded (surface '${surfaceId}'). setModelRegistry must run during boot.`
|
|
2264
|
+
);
|
|
2265
|
+
}
|
|
2266
|
+
return surface;
|
|
2267
|
+
}
|
|
2268
|
+
function getAllowedModelsByType() {
|
|
2269
|
+
return allowedModelsByType;
|
|
2270
|
+
}
|
|
2161
2271
|
function getContextLimits(modelId) {
|
|
2162
|
-
return
|
|
2272
|
+
return textModels.get(modelId) ?? FALLBACK_CONTEXT_LIMITS;
|
|
2163
2273
|
}
|
|
2164
2274
|
function getSuggestCompactAt(modelId) {
|
|
2165
2275
|
return getContextLimits(modelId).suggestCompactAt ?? DEFAULT_SUGGEST_COMPACT_AT;
|
|
@@ -2173,17 +2283,17 @@ function filterModelPicks(picks) {
|
|
|
2173
2283
|
return out;
|
|
2174
2284
|
}
|
|
2175
2285
|
for (const [key, value] of Object.entries(picks)) {
|
|
2176
|
-
|
|
2286
|
+
const surface = surfaces[key];
|
|
2287
|
+
if (!surface) {
|
|
2177
2288
|
continue;
|
|
2178
2289
|
}
|
|
2179
|
-
const surface = MODEL_SURFACES[key];
|
|
2180
2290
|
if (!surface.userPickable) {
|
|
2181
2291
|
continue;
|
|
2182
2292
|
}
|
|
2183
2293
|
if (typeof value !== "string" || value.length === 0) {
|
|
2184
2294
|
continue;
|
|
2185
2295
|
}
|
|
2186
|
-
const allow =
|
|
2296
|
+
const allow = allowedModelsByType[surface.modelType];
|
|
2187
2297
|
if (allow && !allow.includes(value)) {
|
|
2188
2298
|
continue;
|
|
2189
2299
|
}
|
|
@@ -2193,183 +2303,50 @@ function filterModelPicks(picks) {
|
|
|
2193
2303
|
}
|
|
2194
2304
|
function getEffectiveModelSurfaces() {
|
|
2195
2305
|
const out = {};
|
|
2196
|
-
for (const
|
|
2306
|
+
for (const id of SURFACE_IDS) {
|
|
2307
|
+
const surface = surfaces[id];
|
|
2308
|
+
if (!surface) {
|
|
2309
|
+
continue;
|
|
2310
|
+
}
|
|
2197
2311
|
const orgDefault = orgDefaultModels[id];
|
|
2198
2312
|
out[id] = orgDefault ? { ...surface, default: orgDefault } : { ...surface };
|
|
2199
2313
|
}
|
|
2200
2314
|
return out;
|
|
2201
2315
|
}
|
|
2202
2316
|
function resolveModel(surfaceId, models, fallback) {
|
|
2203
|
-
return models?.[surfaceId] ?? fallback ?? orgDefaultModels[surfaceId] ??
|
|
2317
|
+
return models?.[surfaceId] ?? fallback ?? orgDefaultModels[surfaceId] ?? requireSurface(surfaceId).default;
|
|
2204
2318
|
}
|
|
2205
2319
|
function resolveParentModel(models, fallback, buildModel) {
|
|
2206
2320
|
const override = buildModel ? filterModelPicks({ parent: buildModel }).parent : void 0;
|
|
2207
2321
|
const baseline = resolveModel("parent", models, fallback);
|
|
2208
2322
|
return { baseline, effective: override ?? baseline };
|
|
2209
2323
|
}
|
|
2210
|
-
var
|
|
2324
|
+
var SURFACE_IDS, DEFAULT_SUGGEST_COMPACT_AT, FALLBACK_CONTEXT_LIMITS, surfaces, allowedModelsByType, textModels, registryLoaded, orgDefaultModels;
|
|
2211
2325
|
var init_surfaces = __esm({
|
|
2212
2326
|
"src/models/surfaces.ts"() {
|
|
2213
2327
|
"use strict";
|
|
2214
|
-
|
|
2215
|
-
parent
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2229
|
-
|
|
2230
|
-
default: "claude-5-sonnet",
|
|
2231
|
-
label: "Roadmap Agent",
|
|
2232
|
-
description: "Owns your product's roadmap and pitch deck. Helps decide what to build next and how to frame the big picture.",
|
|
2233
|
-
modelType: "text",
|
|
2234
|
-
userPickable: true
|
|
2235
|
-
},
|
|
2236
|
-
browserAutomation: {
|
|
2237
|
-
default: "claude-5-sonnet",
|
|
2238
|
-
label: "QA Agent",
|
|
2239
|
-
description: "Tests features and UI flows in an automated browser to verify they work end to end.",
|
|
2240
|
-
modelType: "text",
|
|
2241
|
-
userPickable: true
|
|
2242
|
-
},
|
|
2243
|
-
codeSanityCheck: {
|
|
2244
|
-
default: "claude-5-sonnet",
|
|
2245
|
-
label: "Architecture Agent",
|
|
2246
|
-
description: "Reviews the architecture and structure of code changes to avoid technical debt.",
|
|
2247
|
-
modelType: "text",
|
|
2248
|
-
userPickable: true
|
|
2249
|
-
},
|
|
2250
|
-
research: {
|
|
2251
|
-
default: "claude-5-sonnet",
|
|
2252
|
-
label: "Research Agent",
|
|
2253
|
-
description: "Researches using the web and reports back with citations.",
|
|
2254
|
-
modelType: "text",
|
|
2255
|
-
userPickable: true
|
|
2256
|
-
},
|
|
2257
|
-
reviewExistingProject: {
|
|
2258
|
-
default: "claude-5-sonnet",
|
|
2259
|
-
label: "Existing Project Review",
|
|
2260
|
-
description: "Reviews a project you bring from another tool and reports what is worth carrying forward.",
|
|
2261
|
-
modelType: "text",
|
|
2262
|
-
userPickable: true
|
|
2263
|
-
},
|
|
2264
|
-
copyEditor: {
|
|
2265
|
-
default: "claude-5-sonnet",
|
|
2266
|
-
label: "Copy Agent",
|
|
2267
|
-
description: "Tightens prose and copy across your app and its launch materials so it reads sharp and human, never machine-made.",
|
|
2268
|
-
modelType: "text",
|
|
2269
|
-
userPickable: true
|
|
2270
|
-
},
|
|
2271
|
-
specSync: {
|
|
2272
|
-
default: "claude-5-sonnet",
|
|
2273
|
-
label: "Spec Sync Agent",
|
|
2274
|
-
description: "Keeps your spec in sync with the code as you build, updating the affected sections in the background after changes.",
|
|
2275
|
-
modelType: "text",
|
|
2276
|
-
userPickable: true
|
|
2277
|
-
},
|
|
2278
|
-
imageGeneration: {
|
|
2279
|
-
default: "gpt-image-2",
|
|
2280
|
-
label: "Image Generation",
|
|
2281
|
-
description: "Creates images for your product \u2014 icons, illustrations, photos, and any other visual assets.",
|
|
2282
|
-
modelType: "image_generation",
|
|
2283
|
-
userPickable: true
|
|
2284
|
-
},
|
|
2285
|
-
imageAnalysis: {
|
|
2286
|
-
default: "claude-5-sonnet",
|
|
2287
|
-
label: "Image Analysis",
|
|
2288
|
-
description: "Reads screenshots taken by the QA agent during automated browser tests. Other agents use their own built-in image analysis when they need to read images.",
|
|
2289
|
-
modelType: "vision",
|
|
2290
|
-
userPickable: true
|
|
2291
|
-
},
|
|
2292
|
-
conversationSummarizer: {
|
|
2293
|
-
default: "claude-5-sonnet",
|
|
2294
|
-
label: "Compaction Utility",
|
|
2295
|
-
description: "Compresses long conversations into summaries to keep things responsive.",
|
|
2296
|
-
modelType: "text",
|
|
2297
|
-
userPickable: true
|
|
2298
|
-
},
|
|
2299
|
-
brandExtractor: {
|
|
2300
|
-
default: "claude-5-sonnet",
|
|
2301
|
-
label: "Brand Utility",
|
|
2302
|
-
description: "Extracts your product's name, colors, and fonts from your spec for use in branded documents.",
|
|
2303
|
-
modelType: "text",
|
|
2304
|
-
userPickable: true
|
|
2305
|
-
},
|
|
2306
|
-
// Internal surface — not user-pickable. Remy uses this to rewrite design
|
|
2307
|
-
// briefs into model-optimized image prompts before image generation.
|
|
2308
|
-
imagePromptEnhancer: {
|
|
2309
|
-
default: "claude-5-sonnet",
|
|
2310
|
-
label: "Image Prompt Enhancer",
|
|
2311
|
-
description: "Rewrites image briefs into model-optimized prompts before image generation.",
|
|
2312
|
-
modelType: "text",
|
|
2313
|
-
userPickable: false
|
|
2314
|
-
}
|
|
2315
|
-
};
|
|
2328
|
+
SURFACE_IDS = [
|
|
2329
|
+
"parent",
|
|
2330
|
+
"visualDesignExpert",
|
|
2331
|
+
"productVision",
|
|
2332
|
+
"browserAutomation",
|
|
2333
|
+
"codeSanityCheck",
|
|
2334
|
+
"research",
|
|
2335
|
+
"reviewExistingProject",
|
|
2336
|
+
"copyEditor",
|
|
2337
|
+
"specSync",
|
|
2338
|
+
"imageGeneration",
|
|
2339
|
+
"imageAnalysis",
|
|
2340
|
+
"conversationSummarizer",
|
|
2341
|
+
"brandExtractor",
|
|
2342
|
+
"imagePromptEnhancer"
|
|
2343
|
+
];
|
|
2316
2344
|
DEFAULT_SUGGEST_COMPACT_AT = 3e5;
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
// Anthropic 1M-context with 2x long-context pricing above 200K input.
|
|
2323
|
-
"claude-4-6-opus": { forceCompactAt: 85e4, suggestCompactAt: 18e4 },
|
|
2324
|
-
"claude-4-6-sonnet": { forceCompactAt: 85e4, suggestCompactAt: 18e4 },
|
|
2325
|
-
"claude-fable-5": { forceCompactAt: 85e4 },
|
|
2326
|
-
"claude-fable-5-1": { forceCompactAt: 85e4 },
|
|
2327
|
-
"claude-5-sonnet": { forceCompactAt: 85e4 },
|
|
2328
|
-
// OpenAI gpt-5.5/5.6: ~1M window, but the usable input ceiling under
|
|
2329
|
-
// `truncation: 'auto'` is ~794K (output + reasoning reserve), and all
|
|
2330
|
-
// rates double above 272K input.
|
|
2331
|
-
"gpt-5.5": { forceCompactAt: 6e5, suggestCompactAt: 25e4 },
|
|
2332
|
-
"gpt-5.6-sol": { forceCompactAt: 6e5, suggestCompactAt: 25e4 },
|
|
2333
|
-
"gpt-5.6-terra": { forceCompactAt: 6e5, suggestCompactAt: 25e4 },
|
|
2334
|
-
"gpt-5.6-luna": { forceCompactAt: 6e5, suggestCompactAt: 25e4 },
|
|
2335
|
-
"gpt-6-astra": { forceCompactAt: 6e5, suggestCompactAt: 25e4 },
|
|
2336
|
-
// Google ~1M-context; only 3.1-pro is tiered (higher rates above 200K).
|
|
2337
|
-
"gemini-3-pro": { forceCompactAt: 85e4 },
|
|
2338
|
-
"gemini-3.1-pro": { forceCompactAt: 85e4, suggestCompactAt: 18e4 },
|
|
2339
|
-
"gemini-3-flash": { forceCompactAt: 85e4 },
|
|
2340
|
-
"gemini-3.5-flash": { forceCompactAt: 85e4 },
|
|
2341
|
-
"gemini-3.7-flash": { forceCompactAt: 85e4 },
|
|
2342
|
-
// 256K window; its 200K pricing tier sits above the gate, so no nudge.
|
|
2343
|
-
"grok-build-0.1": { forceCompactAt: 18e4 },
|
|
2344
|
-
"grok-4.5": { forceCompactAt: 4e5 },
|
|
2345
|
-
// 500K window
|
|
2346
|
-
"grok-4.6": { forceCompactAt: 4e5 },
|
|
2347
|
-
// 500K window
|
|
2348
|
-
"glm-5.2": { forceCompactAt: 85e4 },
|
|
2349
|
-
"glm-5.3": { forceCompactAt: 85e4 },
|
|
2350
|
-
"glm-5.3-flash": { forceCompactAt: 85e4 },
|
|
2351
|
-
"muse-spark-1.1": { forceCompactAt: 85e4 },
|
|
2352
|
-
"muse-spark-1.2": { forceCompactAt: 85e4 },
|
|
2353
|
-
"muse-spark-1.3": { forceCompactAt: 85e4 },
|
|
2354
|
-
"kimi-k2-7-code": { forceCompactAt: 2e5 },
|
|
2355
|
-
// 262K window
|
|
2356
|
-
"kimi-k3": { forceCompactAt: 85e4 },
|
|
2357
|
-
"deepseek-v4-flash-0731": { forceCompactAt: 85e4 },
|
|
2358
|
-
"deepseek-v4-pro": { forceCompactAt: 85e4 },
|
|
2359
|
-
"deepseek-v4.1-flash": { forceCompactAt: 85e4 },
|
|
2360
|
-
"qwen3.8-2.4t-a95b-deepinfra": { forceCompactAt: 2e5 },
|
|
2361
|
-
// 262K window
|
|
2362
|
-
"qwen3.8-27b-deepinfra": { forceCompactAt: 2e5 },
|
|
2363
|
-
// 262K window
|
|
2364
|
-
"minimax-m3": { forceCompactAt: 42e4 }
|
|
2365
|
-
// 524K window
|
|
2366
|
-
};
|
|
2367
|
-
DEFAULT_CONTEXT_LIMITS = { forceCompactAt: 85e4 };
|
|
2368
|
-
ALLOWED_MODELS_BY_TYPE = {
|
|
2369
|
-
text: Object.keys(TEXT_MODELS)
|
|
2370
|
-
// vision: undefined — unconstrained
|
|
2371
|
-
// image_generation: undefined — unconstrained
|
|
2372
|
-
};
|
|
2345
|
+
FALLBACK_CONTEXT_LIMITS = { forceCompactAt: 85e4 };
|
|
2346
|
+
surfaces = {};
|
|
2347
|
+
allowedModelsByType = {};
|
|
2348
|
+
textModels = /* @__PURE__ */ new Map();
|
|
2349
|
+
registryLoaded = false;
|
|
2373
2350
|
orgDefaultModels = {};
|
|
2374
2351
|
}
|
|
2375
2352
|
});
|
|
@@ -11155,6 +11132,27 @@ var init_config = __esm({
|
|
|
11155
11132
|
}
|
|
11156
11133
|
});
|
|
11157
11134
|
|
|
11135
|
+
// src/models/init.ts
|
|
11136
|
+
async function initModelRegistry(config) {
|
|
11137
|
+
const payload = await fetchModelSurfaces(config);
|
|
11138
|
+
setModelRegistry(payload);
|
|
11139
|
+
log16.debug("model registry loaded", {
|
|
11140
|
+
surfaces: payload.surfaces.length,
|
|
11141
|
+
allowedTextModels: payload.allowedModelsByType?.text?.length ?? 0,
|
|
11142
|
+
textModels: Object.keys(payload.textModels ?? {}).length
|
|
11143
|
+
});
|
|
11144
|
+
}
|
|
11145
|
+
var log16;
|
|
11146
|
+
var init_init = __esm({
|
|
11147
|
+
"src/models/init.ts"() {
|
|
11148
|
+
"use strict";
|
|
11149
|
+
init_api();
|
|
11150
|
+
init_logger();
|
|
11151
|
+
init_surfaces();
|
|
11152
|
+
log16 = createLogger("models");
|
|
11153
|
+
}
|
|
11154
|
+
});
|
|
11155
|
+
|
|
11158
11156
|
// src/headless/attachments.ts
|
|
11159
11157
|
import { mkdirSync, existsSync, createWriteStream } from "fs";
|
|
11160
11158
|
import { writeFile as writeFile3, stat as stat5 } from "fs/promises";
|
|
@@ -11218,7 +11216,7 @@ async function persistAttachmentList(attachments) {
|
|
|
11218
11216
|
createWriteStream(localPath)
|
|
11219
11217
|
);
|
|
11220
11218
|
const { size } = await stat5(localPath);
|
|
11221
|
-
|
|
11219
|
+
log17.info("Attachment saved", {
|
|
11222
11220
|
filename: name,
|
|
11223
11221
|
path: localPath,
|
|
11224
11222
|
bytes: size
|
|
@@ -11232,7 +11230,7 @@ async function persistAttachmentList(attachments) {
|
|
|
11232
11230
|
if (textRes.ok) {
|
|
11233
11231
|
extractedTextPath = `${localPath}.txt`;
|
|
11234
11232
|
await writeFile3(extractedTextPath, await textRes.text(), "utf-8");
|
|
11235
|
-
|
|
11233
|
+
log17.info("Extracted text saved", { path: extractedTextPath });
|
|
11236
11234
|
}
|
|
11237
11235
|
} catch {
|
|
11238
11236
|
}
|
|
@@ -11281,12 +11279,12 @@ function buildUploadHeader(documents, images) {
|
|
|
11281
11279
|
return `[Uploaded files]
|
|
11282
11280
|
${lines.join("\n")}`;
|
|
11283
11281
|
}
|
|
11284
|
-
var
|
|
11282
|
+
var log17, UPLOADS_DIR, IMAGE_DOWNLOAD_TIMEOUT_MS, DOCUMENT_DOWNLOAD_TIMEOUT_MS, IMAGE_EXTENSIONS;
|
|
11285
11283
|
var init_attachments = __esm({
|
|
11286
11284
|
"src/headless/attachments.ts"() {
|
|
11287
11285
|
"use strict";
|
|
11288
11286
|
init_logger();
|
|
11289
|
-
|
|
11287
|
+
log17 = createLogger("headless:attachments");
|
|
11290
11288
|
UPLOADS_DIR = "src/.user-uploads";
|
|
11291
11289
|
IMAGE_DOWNLOAD_TIMEOUT_MS = 3e4;
|
|
11292
11290
|
DOCUMENT_DOWNLOAD_TIMEOUT_MS = 3e5;
|
|
@@ -11442,7 +11440,7 @@ async function readUpstreamStatus() {
|
|
|
11442
11440
|
FETCH_TIMEOUT_MS
|
|
11443
11441
|
);
|
|
11444
11442
|
if (!fetched.ok) {
|
|
11445
|
-
|
|
11443
|
+
log18.info(
|
|
11446
11444
|
`fetch failed, falling back to the origin/${DEFAULT_BRANCH} on disk: ${fetched.error}`
|
|
11447
11445
|
);
|
|
11448
11446
|
}
|
|
@@ -11495,13 +11493,13 @@ async function readUpstreamStatus() {
|
|
|
11495
11493
|
if (contained.ok) {
|
|
11496
11494
|
return null;
|
|
11497
11495
|
}
|
|
11498
|
-
|
|
11496
|
+
log18.info(
|
|
11499
11497
|
`behind by an unknown amount: rev-list and log both failed (${counts.error})`
|
|
11500
11498
|
);
|
|
11501
11499
|
}
|
|
11502
11500
|
const status = await git(["status", "--porcelain"]);
|
|
11503
11501
|
if (!status.ok) {
|
|
11504
|
-
|
|
11502
|
+
log18.info(`could not read the working tree state: ${status.error}`);
|
|
11505
11503
|
}
|
|
11506
11504
|
return {
|
|
11507
11505
|
upstream,
|
|
@@ -11512,13 +11510,13 @@ async function readUpstreamStatus() {
|
|
|
11512
11510
|
incomingTruncated: incomingLines.length > MAX_INCOMING
|
|
11513
11511
|
};
|
|
11514
11512
|
}
|
|
11515
|
-
var
|
|
11513
|
+
var log18, DEFAULT_BRANCH, MAX_INCOMING, FETCH_TIMEOUT_MS, GIT_TIMEOUT_MS, MAX_BUFFER_BYTES;
|
|
11516
11514
|
var init_upstreamStatus = __esm({
|
|
11517
11515
|
"src/git/upstreamStatus.ts"() {
|
|
11518
11516
|
"use strict";
|
|
11519
11517
|
init_projectRoot();
|
|
11520
11518
|
init_logger();
|
|
11521
|
-
|
|
11519
|
+
log18 = createLogger("upstream");
|
|
11522
11520
|
DEFAULT_BRANCH = "main";
|
|
11523
11521
|
MAX_INCOMING = 20;
|
|
11524
11522
|
FETCH_TIMEOUT_MS = 3e4;
|
|
@@ -11743,13 +11741,14 @@ var headless_exports = {};
|
|
|
11743
11741
|
__export(headless_exports, {
|
|
11744
11742
|
HeadlessSession: () => HeadlessSession
|
|
11745
11743
|
});
|
|
11746
|
-
var
|
|
11744
|
+
var log19, EXTERNAL_TOOL_TIMEOUT_MS, LONG_RUNNING_TOOLS, LONG_RUNNING_TOOL_TIMEOUT_MS, USER_FACING_TOOLS, HeadlessSession;
|
|
11747
11745
|
var init_headless = __esm({
|
|
11748
11746
|
"src/headless/index.ts"() {
|
|
11749
11747
|
"use strict";
|
|
11750
11748
|
init_logger();
|
|
11751
11749
|
init_config();
|
|
11752
11750
|
init_orgContext();
|
|
11751
|
+
init_init();
|
|
11753
11752
|
init_prompt4();
|
|
11754
11753
|
init_trigger();
|
|
11755
11754
|
init_trigger2();
|
|
@@ -11766,7 +11765,7 @@ var init_headless = __esm({
|
|
|
11766
11765
|
init_messageQueue();
|
|
11767
11766
|
init_resolve();
|
|
11768
11767
|
init_sentinel();
|
|
11769
|
-
|
|
11768
|
+
log19 = createLogger("headless");
|
|
11770
11769
|
EXTERNAL_TOOL_TIMEOUT_MS = 3e5;
|
|
11771
11770
|
LONG_RUNNING_TOOLS = /* @__PURE__ */ new Set(["runMethod", "testJewel"]);
|
|
11772
11771
|
LONG_RUNNING_TOOL_TIMEOUT_MS = 18e5;
|
|
@@ -11875,6 +11874,7 @@ var init_headless = __esm({
|
|
|
11875
11874
|
apiKey: this.opts.apiKey,
|
|
11876
11875
|
baseUrl: this.opts.baseUrl
|
|
11877
11876
|
});
|
|
11877
|
+
await initModelRegistry(this.config);
|
|
11878
11878
|
await initOrgContext(this.config);
|
|
11879
11879
|
const resumed = loadSession(this.state);
|
|
11880
11880
|
this.queue = new MessageQueue(
|
|
@@ -11893,7 +11893,7 @@ var init_headless = __esm({
|
|
|
11893
11893
|
messageCount: this.state.messages.length,
|
|
11894
11894
|
...this.state.models && { models: this.state.models },
|
|
11895
11895
|
modelSurfaces: getEffectiveModelSurfaces(),
|
|
11896
|
-
allowedModelsByType:
|
|
11896
|
+
allowedModelsByType: getAllowedModelsByType()
|
|
11897
11897
|
});
|
|
11898
11898
|
}
|
|
11899
11899
|
triggerBrandExtraction(
|
|
@@ -12010,7 +12010,7 @@ var init_headless = __esm({
|
|
|
12010
12010
|
try {
|
|
12011
12011
|
this.handleCancel("shutdown");
|
|
12012
12012
|
} catch (err) {
|
|
12013
|
-
|
|
12013
|
+
log19.warn("Shutdown cancel failed", { error: err?.message });
|
|
12014
12014
|
}
|
|
12015
12015
|
this.emit("stopping");
|
|
12016
12016
|
this.emit("stopped");
|
|
@@ -12026,7 +12026,7 @@ var init_headless = __esm({
|
|
|
12026
12026
|
}
|
|
12027
12027
|
const line = JSON.stringify(payload) + "\n";
|
|
12028
12028
|
if (event === "history") {
|
|
12029
|
-
|
|
12029
|
+
log19.info("Wrote history event to stdout", {
|
|
12030
12030
|
requestId,
|
|
12031
12031
|
bytes: line.length
|
|
12032
12032
|
});
|
|
@@ -12100,7 +12100,7 @@ var init_headless = __esm({
|
|
|
12100
12100
|
lastNotedUpstream: status.upstream
|
|
12101
12101
|
};
|
|
12102
12102
|
this.persistStats();
|
|
12103
|
-
|
|
12103
|
+
log19.info("workspace behind upstream; note parked for the next turn", {
|
|
12104
12104
|
// The upstream sha is the dedupe key, so it is what makes "why did I
|
|
12105
12105
|
// not get a note" answerable from the log alone.
|
|
12106
12106
|
upstream: status.upstream,
|
|
@@ -12109,7 +12109,7 @@ var init_headless = __esm({
|
|
|
12109
12109
|
dirty: status.dirty
|
|
12110
12110
|
});
|
|
12111
12111
|
} catch (err) {
|
|
12112
|
-
|
|
12112
|
+
log19.info(`upstream check failed: ${String(err)}`);
|
|
12113
12113
|
}
|
|
12114
12114
|
}
|
|
12115
12115
|
//////////////////////////////////////////////////////////////////////////////
|
|
@@ -12158,7 +12158,7 @@ var init_headless = __esm({
|
|
|
12158
12158
|
if (this.sessionStats.lastContextSize <= threshold) {
|
|
12159
12159
|
return;
|
|
12160
12160
|
}
|
|
12161
|
-
|
|
12161
|
+
log19.info("Forced compaction gate triggered", {
|
|
12162
12162
|
contextSize: this.sessionStats.lastContextSize,
|
|
12163
12163
|
threshold,
|
|
12164
12164
|
model: parentModel,
|
|
@@ -12178,7 +12178,7 @@ var init_headless = __esm({
|
|
|
12178
12178
|
onBackgroundComplete = (toolCallId, name, result, subAgentMessages) => {
|
|
12179
12179
|
const notify = getToolByName(name)?.backgroundNotify ?? "wake";
|
|
12180
12180
|
this.pendingBlockUpdates.push({ toolCallId, result, subAgentMessages });
|
|
12181
|
-
|
|
12181
|
+
log19.info("Background complete", {
|
|
12182
12182
|
toolCallId,
|
|
12183
12183
|
name,
|
|
12184
12184
|
notify,
|
|
@@ -12460,7 +12460,7 @@ var init_headless = __esm({
|
|
|
12460
12460
|
const { documents, images } = await persistAttachments(attachments);
|
|
12461
12461
|
return buildUploadHeader(documents, images) || void 0;
|
|
12462
12462
|
} catch (err) {
|
|
12463
|
-
|
|
12463
|
+
log19.warn("Attachment persistence failed", { error: err.message });
|
|
12464
12464
|
return void 0;
|
|
12465
12465
|
}
|
|
12466
12466
|
}
|
|
@@ -12520,7 +12520,7 @@ var init_headless = __esm({
|
|
|
12520
12520
|
}
|
|
12521
12521
|
if (batch.length === 0) {
|
|
12522
12522
|
if (landings > 0) {
|
|
12523
|
-
|
|
12523
|
+
log19.info("promptUser store landings passed through", { landings });
|
|
12524
12524
|
}
|
|
12525
12525
|
return raw;
|
|
12526
12526
|
}
|
|
@@ -12528,7 +12528,7 @@ var init_headless = __esm({
|
|
|
12528
12528
|
try {
|
|
12529
12529
|
results = await persistAttachmentList(batch);
|
|
12530
12530
|
} catch (err) {
|
|
12531
|
-
|
|
12531
|
+
log19.warn("promptUser upload persistence failed", {
|
|
12532
12532
|
error: err.message
|
|
12533
12533
|
});
|
|
12534
12534
|
results = batch.map(() => null);
|
|
@@ -12540,7 +12540,7 @@ var init_headless = __esm({
|
|
|
12540
12540
|
return r.localPath;
|
|
12541
12541
|
}
|
|
12542
12542
|
const att = batch[cursor + i];
|
|
12543
|
-
|
|
12543
|
+
log19.warn("promptUser upload not persisted; falling back to url", {
|
|
12544
12544
|
filename: att.filename
|
|
12545
12545
|
});
|
|
12546
12546
|
return att.url;
|
|
@@ -12548,7 +12548,7 @@ var init_headless = __esm({
|
|
|
12548
12548
|
cursor += slot.count;
|
|
12549
12549
|
answers[slot.id] = slot.isArray ? paths : paths[0];
|
|
12550
12550
|
}
|
|
12551
|
-
|
|
12551
|
+
log19.info("promptUser uploads persisted", { count: batch.length });
|
|
12552
12552
|
return JSON.stringify(answers);
|
|
12553
12553
|
}
|
|
12554
12554
|
/**
|
|
@@ -12571,7 +12571,7 @@ var init_headless = __esm({
|
|
|
12571
12571
|
async runSingleTurn(parsed, requestId, fromChain = false, queued = false) {
|
|
12572
12572
|
const attachments = parsed.attachments;
|
|
12573
12573
|
if (attachments?.length) {
|
|
12574
|
-
|
|
12574
|
+
log19.info("Message has attachments", {
|
|
12575
12575
|
count: attachments.length,
|
|
12576
12576
|
urls: attachments.map((a) => a.url)
|
|
12577
12577
|
});
|
|
@@ -12783,7 +12783,7 @@ var init_headless = __esm({
|
|
|
12783
12783
|
error: "Turn ended unexpectedly"
|
|
12784
12784
|
});
|
|
12785
12785
|
}
|
|
12786
|
-
|
|
12786
|
+
log19.info("Turn complete", {
|
|
12787
12787
|
requestId,
|
|
12788
12788
|
durationMs: Date.now() - this.turnStart
|
|
12789
12789
|
});
|
|
@@ -12795,7 +12795,7 @@ var init_headless = __esm({
|
|
|
12795
12795
|
error: err.message
|
|
12796
12796
|
});
|
|
12797
12797
|
}
|
|
12798
|
-
|
|
12798
|
+
log19.warn("Command failed", {
|
|
12799
12799
|
action: "message",
|
|
12800
12800
|
requestId,
|
|
12801
12801
|
error: err.message
|
|
@@ -12964,7 +12964,7 @@ var init_headless = __esm({
|
|
|
12964
12964
|
return {
|
|
12965
12965
|
...this.state.models && { models: this.state.models },
|
|
12966
12966
|
modelSurfaces: getEffectiveModelSurfaces(),
|
|
12967
|
-
allowedModelsByType:
|
|
12967
|
+
allowedModelsByType: getAllowedModelsByType()
|
|
12968
12968
|
};
|
|
12969
12969
|
}
|
|
12970
12970
|
/** Change per-agent model picks without clearing history. Takes effect on
|
|
@@ -12977,7 +12977,7 @@ var init_headless = __esm({
|
|
|
12977
12977
|
return {
|
|
12978
12978
|
...this.state.models && { models: this.state.models },
|
|
12979
12979
|
modelSurfaces: getEffectiveModelSurfaces(),
|
|
12980
|
-
allowedModelsByType:
|
|
12980
|
+
allowedModelsByType: getAllowedModelsByType()
|
|
12981
12981
|
};
|
|
12982
12982
|
}
|
|
12983
12983
|
/**
|
|
@@ -13102,7 +13102,7 @@ var init_headless = __esm({
|
|
|
13102
13102
|
try {
|
|
13103
13103
|
parsed = JSON.parse(line);
|
|
13104
13104
|
} catch (err) {
|
|
13105
|
-
|
|
13105
|
+
log19.warn("Invalid JSON on stdin", {
|
|
13106
13106
|
error: err.message,
|
|
13107
13107
|
lineLength: line.length,
|
|
13108
13108
|
preview: line.slice(0, 200)
|
|
@@ -13111,7 +13111,7 @@ var init_headless = __esm({
|
|
|
13111
13111
|
return;
|
|
13112
13112
|
}
|
|
13113
13113
|
const { action, requestId } = parsed;
|
|
13114
|
-
|
|
13114
|
+
log19.info("Command received", { action, requestId });
|
|
13115
13115
|
if (action === "tool_result" && parsed.id) {
|
|
13116
13116
|
const id = parsed.id;
|
|
13117
13117
|
const result = parsed.result ?? "";
|
|
@@ -13120,7 +13120,7 @@ var init_headless = __esm({
|
|
|
13120
13120
|
this.pendingTools.delete(id);
|
|
13121
13121
|
pending2.resolve(result);
|
|
13122
13122
|
} else if (!this.running) {
|
|
13123
|
-
|
|
13123
|
+
log19.info("Late tool_result while idle, dismissing", { id });
|
|
13124
13124
|
this.emit("completed", { success: true }, requestId);
|
|
13125
13125
|
} else {
|
|
13126
13126
|
this.earlyResults.set(id, result);
|
|
@@ -13133,7 +13133,7 @@ var init_headless = __esm({
|
|
|
13133
13133
|
...typeof parsed.before === "number" ? { before: parsed.before } : {},
|
|
13134
13134
|
...typeof parsed.limit === "number" ? { limit: parsed.limit } : {}
|
|
13135
13135
|
});
|
|
13136
|
-
|
|
13136
|
+
log19.info("History response", {
|
|
13137
13137
|
requestId,
|
|
13138
13138
|
startIndex: page.startIndex,
|
|
13139
13139
|
endIndex: page.endIndex,
|
|
@@ -13151,7 +13151,7 @@ var init_headless = __esm({
|
|
|
13151
13151
|
...this.running && this.currentRequestId ? { currentRequestId: this.currentRequestId } : {},
|
|
13152
13152
|
...this.state.models && { models: this.state.models },
|
|
13153
13153
|
modelSurfaces: getEffectiveModelSurfaces(),
|
|
13154
|
-
allowedModelsByType:
|
|
13154
|
+
allowedModelsByType: getAllowedModelsByType(),
|
|
13155
13155
|
// Current queue snapshot for connect/reconnect — get_history is the
|
|
13156
13156
|
// on-demand "current state" query. Always an array (possibly empty),
|
|
13157
13157
|
// matching the queue_changed convention so the client reconciles the
|
|
@@ -13653,6 +13653,7 @@ Error: ${err.message}`,
|
|
|
13653
13653
|
// src/index.tsx
|
|
13654
13654
|
init_config();
|
|
13655
13655
|
init_orgContext();
|
|
13656
|
+
init_init();
|
|
13656
13657
|
init_logger();
|
|
13657
13658
|
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
13658
13659
|
var args = process.argv.slice(2);
|
|
@@ -13716,6 +13717,7 @@ if (headless) {
|
|
|
13716
13717
|
baseUrl: flags.baseUrl
|
|
13717
13718
|
});
|
|
13718
13719
|
printDebugInfo(config);
|
|
13720
|
+
await initModelRegistry(config);
|
|
13719
13721
|
await initOrgContext(config);
|
|
13720
13722
|
const { waitUntilExit } = render(
|
|
13721
13723
|
/* @__PURE__ */ jsx6(
|