@kmugalkhod/lightcode 0.5.0 → 0.6.0
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/cli.js +1544 -973
- package/package.json +1 -1
- package/server.js +388 -249
package/server.js
CHANGED
|
@@ -747,9 +747,10 @@ var init_schema = __esm(() => {
|
|
|
747
747
|
|
|
748
748
|
// packages/ai/src/edit-file/schema.ts
|
|
749
749
|
import { z as z6 } from "zod";
|
|
750
|
-
var editFileDescription
|
|
750
|
+
var editFileDescription, editFileInputSchema, editFileProviderInputSchema, editFileOutputSchema;
|
|
751
751
|
var init_schema2 = __esm(() => {
|
|
752
752
|
init_base_schemas();
|
|
753
|
+
editFileDescription = "Edit a file via search and replace. Use this for focused, small edits. " + "Line endings (CRLF/LF) and surrounding whitespace are matched tolerantly, so " + "copy the lines as shown by read_file. The search text must match exactly one " + "place \u2014 include enough surrounding context to make it unique, or set " + "replaceAll: true to change every occurrence.";
|
|
753
754
|
editFileInputSchema = z6.object({
|
|
754
755
|
path: boundedPathSchema,
|
|
755
756
|
search: z6.string().min(1),
|
|
@@ -2225,126 +2226,7 @@ function selectCodingAgentIntentTools({
|
|
|
2225
2226
|
if (!normalizedText || casualPromptPattern.test(normalizedText)) {
|
|
2226
2227
|
return [];
|
|
2227
2228
|
}
|
|
2228
|
-
const
|
|
2229
|
-
const hasContinuationIntent = includesAny(normalizedText, [
|
|
2230
|
-
"continue",
|
|
2231
|
-
"proceed",
|
|
2232
|
-
"go on",
|
|
2233
|
-
"go ahead",
|
|
2234
|
-
"keep going",
|
|
2235
|
-
"carry on",
|
|
2236
|
-
"resume",
|
|
2237
|
-
"finish",
|
|
2238
|
-
"next step"
|
|
2239
|
-
]);
|
|
2240
|
-
const hasCodeIntent = includesAny(normalizedText, [
|
|
2241
|
-
"file",
|
|
2242
|
-
"folder",
|
|
2243
|
-
"code",
|
|
2244
|
-
"repo",
|
|
2245
|
-
"project",
|
|
2246
|
-
"implement",
|
|
2247
|
-
"fix",
|
|
2248
|
-
"add",
|
|
2249
|
-
"build",
|
|
2250
|
-
"refactor",
|
|
2251
|
-
"change",
|
|
2252
|
-
"create",
|
|
2253
|
-
"update",
|
|
2254
|
-
"edit",
|
|
2255
|
-
"delete",
|
|
2256
|
-
"run",
|
|
2257
|
-
"test",
|
|
2258
|
-
"typecheck",
|
|
2259
|
-
"debug",
|
|
2260
|
-
"error",
|
|
2261
|
-
"issue",
|
|
2262
|
-
"problem",
|
|
2263
|
-
"fails",
|
|
2264
|
-
"failed",
|
|
2265
|
-
"failing",
|
|
2266
|
-
"bug",
|
|
2267
|
-
"crash",
|
|
2268
|
-
"slow",
|
|
2269
|
-
"slowness",
|
|
2270
|
-
"not working",
|
|
2271
|
-
"epic",
|
|
2272
|
-
"ticket"
|
|
2273
|
-
]);
|
|
2274
|
-
const hasReadIntent = includesAny(normalizedText, [
|
|
2275
|
-
"read",
|
|
2276
|
-
"list",
|
|
2277
|
-
"find",
|
|
2278
|
-
"search",
|
|
2279
|
-
"grep",
|
|
2280
|
-
"glob",
|
|
2281
|
-
"inspect",
|
|
2282
|
-
"analyse",
|
|
2283
|
-
"analyze",
|
|
2284
|
-
"check"
|
|
2285
|
-
]);
|
|
2286
|
-
const workspaceReferents = [
|
|
2287
|
-
"this",
|
|
2288
|
-
"these",
|
|
2289
|
-
"that",
|
|
2290
|
-
"here",
|
|
2291
|
-
"code",
|
|
2292
|
-
"codebase",
|
|
2293
|
-
"repo",
|
|
2294
|
-
"repository",
|
|
2295
|
-
"project",
|
|
2296
|
-
"file",
|
|
2297
|
-
"files",
|
|
2298
|
-
"directory",
|
|
2299
|
-
"folder",
|
|
2300
|
-
"app",
|
|
2301
|
-
"application",
|
|
2302
|
-
"module",
|
|
2303
|
-
"my"
|
|
2304
|
-
];
|
|
2305
|
-
const strongReviewIntent = includesAny(normalizedText, [
|
|
2306
|
-
"review",
|
|
2307
|
-
"audit",
|
|
2308
|
-
"walk through",
|
|
2309
|
-
"walkthrough",
|
|
2310
|
-
"code review"
|
|
2311
|
-
]);
|
|
2312
|
-
const softReviewIntent = includesAny(normalizedText, [
|
|
2313
|
-
"explain",
|
|
2314
|
-
"understand",
|
|
2315
|
-
"summarize",
|
|
2316
|
-
"summarise",
|
|
2317
|
-
"overview",
|
|
2318
|
-
"describe",
|
|
2319
|
-
"explore",
|
|
2320
|
-
"look at"
|
|
2321
|
-
]) && includesAny(normalizedText, workspaceReferents);
|
|
2322
|
-
const hasReviewIntent = strongReviewIntent || softReviewIntent;
|
|
2323
|
-
const hasWriteIntent = mode === "build" && (hasContinuationIntent || includesAny(normalizedText, [
|
|
2324
|
-
"write",
|
|
2325
|
-
"edit",
|
|
2326
|
-
"change",
|
|
2327
|
-
"create",
|
|
2328
|
-
"implement",
|
|
2329
|
-
"fix",
|
|
2330
|
-
"update",
|
|
2331
|
-
"delete",
|
|
2332
|
-
"remove",
|
|
2333
|
-
"rename"
|
|
2334
|
-
]));
|
|
2335
|
-
const hasShellIntent = mode === "build" && (hasContinuationIntent || includesAny(normalizedText, [
|
|
2336
|
-
"run",
|
|
2337
|
-
"command",
|
|
2338
|
-
"terminal",
|
|
2339
|
-
"shell",
|
|
2340
|
-
"bash",
|
|
2341
|
-
"powershell",
|
|
2342
|
-
"bun",
|
|
2343
|
-
"tests",
|
|
2344
|
-
"run test",
|
|
2345
|
-
"run tests",
|
|
2346
|
-
"typecheck"
|
|
2347
|
-
]));
|
|
2229
|
+
const situational = [];
|
|
2348
2230
|
const hasGitIntent = includesAny(normalizedText, [
|
|
2349
2231
|
"git",
|
|
2350
2232
|
"diff",
|
|
@@ -2355,95 +2237,64 @@ function selectCodingAgentIntentTools({
|
|
|
2355
2237
|
"revision",
|
|
2356
2238
|
"changes"
|
|
2357
2239
|
]);
|
|
2358
|
-
const hasTodoIntent = includesAny(normalizedText, [
|
|
2359
|
-
"todo",
|
|
2360
|
-
"tasks",
|
|
2361
|
-
"checklist",
|
|
2362
|
-
"steps",
|
|
2363
|
-
"epic",
|
|
2364
|
-
"ticket"
|
|
2365
|
-
]);
|
|
2366
|
-
const hasWebIntent = includesAny(normalizedText, [
|
|
2367
|
-
"http://",
|
|
2368
|
-
"https://",
|
|
2369
|
-
"url",
|
|
2370
|
-
"fetch",
|
|
2371
|
-
"website",
|
|
2372
|
-
"web",
|
|
2373
|
-
"online",
|
|
2374
|
-
"search internet",
|
|
2375
|
-
"latest"
|
|
2376
|
-
]);
|
|
2377
|
-
const explicitToolSearch = includesAny(normalizedText, [
|
|
2378
|
-
"tool_search",
|
|
2379
|
-
"tool search",
|
|
2380
|
-
"find tool",
|
|
2381
|
-
"available tool"
|
|
2382
|
-
]);
|
|
2383
|
-
const hasSkillIntent = includesAny(normalizedText, [
|
|
2384
|
-
"skill",
|
|
2385
|
-
"skills",
|
|
2386
|
-
"load skill"
|
|
2387
|
-
]);
|
|
2388
|
-
const hasMcpIntent = includesAny(normalizedText, [
|
|
2389
|
-
"mcp",
|
|
2390
|
-
"resource",
|
|
2391
|
-
"resources",
|
|
2392
|
-
"mcp tool",
|
|
2393
|
-
"mcp server"
|
|
2394
|
-
]);
|
|
2395
|
-
if (hasCodeIntent || hasContinuationIntent || hasReviewIntent || hasReadIntent && !hasGitIntent && !hasWebIntent && !explicitToolSearch) {
|
|
2396
|
-
for (const toolName of baseReadTools) {
|
|
2397
|
-
pushUniqueTool(selectedTools, toolName);
|
|
2398
|
-
}
|
|
2399
|
-
}
|
|
2400
2240
|
if (hasGitIntent) {
|
|
2401
2241
|
if (includesAny(normalizedText, ["status", "state", "dirty", "working tree"]) || !includesAny(normalizedText, ["diff", "log", "show", "history", "commit"])) {
|
|
2402
|
-
pushUniqueTool(
|
|
2242
|
+
pushUniqueTool(situational, "git_status");
|
|
2403
2243
|
}
|
|
2404
2244
|
if (includesAny(normalizedText, ["diff", "changes", "patch"])) {
|
|
2405
|
-
pushUniqueTool(
|
|
2245
|
+
pushUniqueTool(situational, "git_diff");
|
|
2406
2246
|
}
|
|
2407
2247
|
if (includesAny(normalizedText, ["log", "history", "commits"])) {
|
|
2408
|
-
pushUniqueTool(
|
|
2248
|
+
pushUniqueTool(situational, "git_log");
|
|
2409
2249
|
}
|
|
2410
2250
|
if (includesAny(normalizedText, ["show", "revision", "commit"])) {
|
|
2411
|
-
pushUniqueTool(
|
|
2251
|
+
pushUniqueTool(situational, "git_show");
|
|
2412
2252
|
}
|
|
2413
2253
|
}
|
|
2414
|
-
if (
|
|
2415
|
-
pushUniqueTool(
|
|
2254
|
+
if (mode === "build" && includesAny(normalizedText, ["todo", "tasks", "checklist", "steps", "epic", "ticket"])) {
|
|
2255
|
+
pushUniqueTool(situational, "todo_write");
|
|
2416
2256
|
}
|
|
2417
|
-
if (
|
|
2418
|
-
pushUniqueTool(
|
|
2257
|
+
if (includesAny(normalizedText, ["tool_search", "tool search", "find tool", "available tool"])) {
|
|
2258
|
+
pushUniqueTool(situational, "tool_search");
|
|
2419
2259
|
}
|
|
2420
|
-
if (
|
|
2421
|
-
pushUniqueTool(
|
|
2260
|
+
if (includesAny(normalizedText, ["skill", "skills", "load skill"])) {
|
|
2261
|
+
pushUniqueTool(situational, "skill");
|
|
2422
2262
|
}
|
|
2423
|
-
if (
|
|
2424
|
-
pushUniqueTool(
|
|
2263
|
+
if (includesAny(normalizedText, ["mcp", "resource", "resources", "mcp tool", "mcp server"])) {
|
|
2264
|
+
pushUniqueTool(situational, "list_mcp_resources");
|
|
2425
2265
|
if (includesAny(normalizedText, ["read", "resource", "resources"])) {
|
|
2426
|
-
pushUniqueTool(
|
|
2266
|
+
pushUniqueTool(situational, "read_mcp_resource");
|
|
2427
2267
|
}
|
|
2428
2268
|
if (mode === "build" && includesAny(normalizedText, ["call", "execute", "run"])) {
|
|
2429
|
-
pushUniqueTool(
|
|
2269
|
+
pushUniqueTool(situational, "call_mcp_tool");
|
|
2430
2270
|
}
|
|
2431
2271
|
}
|
|
2432
|
-
if (
|
|
2433
|
-
|
|
2434
|
-
|
|
2272
|
+
if (includesAny(normalizedText, [
|
|
2273
|
+
"http://",
|
|
2274
|
+
"https://",
|
|
2275
|
+
"url",
|
|
2276
|
+
"fetch",
|
|
2277
|
+
"website",
|
|
2278
|
+
"web",
|
|
2279
|
+
"online",
|
|
2280
|
+
"search internet",
|
|
2281
|
+
"latest"
|
|
2282
|
+
])) {
|
|
2283
|
+
pushUniqueTool(situational, "web_fetch");
|
|
2284
|
+
pushUniqueTool(situational, "web_search");
|
|
2435
2285
|
}
|
|
2436
|
-
if (
|
|
2437
|
-
pushUniqueTool(
|
|
2286
|
+
if (mode === "plan" && includesAny(normalizedText, ["question", "ask", "clarify"])) {
|
|
2287
|
+
pushUniqueTool(situational, "request_user_input");
|
|
2438
2288
|
}
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
2289
|
+
const ordered = [...baseReadTools, ...situational];
|
|
2290
|
+
if (mode === "build") {
|
|
2291
|
+
ordered.push("write_file", "edit_file", "bash");
|
|
2442
2292
|
}
|
|
2443
|
-
|
|
2444
|
-
|
|
2293
|
+
const selected = [];
|
|
2294
|
+
for (const toolName of ordered) {
|
|
2295
|
+
pushUniqueTool(selected, toolName);
|
|
2445
2296
|
}
|
|
2446
|
-
return
|
|
2297
|
+
return selected.slice(0, maxProviderActiveTools);
|
|
2447
2298
|
}
|
|
2448
2299
|
function limitProviderActiveTools(tools, maxTools = maxProviderActiveTools) {
|
|
2449
2300
|
if (tools.length <= maxTools) {
|
|
@@ -2714,17 +2565,33 @@ function normalizeContextOptimizerConfig(config) {
|
|
|
2714
2565
|
}
|
|
2715
2566
|
function resolveContextWindowTokens({
|
|
2716
2567
|
config,
|
|
2717
|
-
modelContextWindow
|
|
2568
|
+
modelContextWindow,
|
|
2569
|
+
endpointLimitTokens
|
|
2570
|
+
}) {
|
|
2571
|
+
const resolved = config.contextWindowOverride ?? modelContextWindow ?? DEFAULT_CONTEXT_WINDOW_TOKENS;
|
|
2572
|
+
if (typeof endpointLimitTokens === "number" && Number.isFinite(endpointLimitTokens) && endpointLimitTokens > 0) {
|
|
2573
|
+
return Math.min(resolved, endpointLimitTokens);
|
|
2574
|
+
}
|
|
2575
|
+
return resolved;
|
|
2576
|
+
}
|
|
2577
|
+
function resolveInputBudgetTokens({
|
|
2578
|
+
contextWindow,
|
|
2579
|
+
reservedOutputTokens,
|
|
2580
|
+
safetyFraction = DEFAULT_INPUT_BUDGET_SAFETY_FRACTION
|
|
2718
2581
|
}) {
|
|
2719
|
-
|
|
2582
|
+
const reserved = typeof reservedOutputTokens === "number" && Number.isFinite(reservedOutputTokens) && reservedOutputTokens > 0 ? reservedOutputTokens : 0;
|
|
2583
|
+
const clampedFraction = Math.min(1, Math.max(0.1, safetyFraction));
|
|
2584
|
+
const usable = Math.max(0, contextWindow - reserved);
|
|
2585
|
+
return Math.max(0, Math.floor(usable * clampedFraction));
|
|
2720
2586
|
}
|
|
2721
|
-
var DEFAULT_CONTEXT_WINDOW_TOKENS = 128000, contextOptimizerConfigSchema, resolvedContextOptimizerConfigSchema, defaultContextOptimizerConfig;
|
|
2587
|
+
var DEFAULT_CONTEXT_WINDOW_TOKENS = 128000, contextOptimizerConfigSchema, resolvedContextOptimizerConfigSchema, defaultContextOptimizerConfig, DEFAULT_INPUT_BUDGET_SAFETY_FRACTION = 0.92;
|
|
2722
2588
|
var init_config3 = __esm(() => {
|
|
2723
2589
|
contextOptimizerConfigSchema = z26.object({
|
|
2724
2590
|
autoCompact: z26.boolean().optional(),
|
|
2725
2591
|
compactAtFraction: z26.number().min(0.3).max(0.95).optional(),
|
|
2726
2592
|
pruneAtFraction: z26.number().min(0.2).max(0.9).optional(),
|
|
2727
2593
|
preserveRecentMessages: z26.number().int().min(2).max(100).optional(),
|
|
2594
|
+
maxCoverageTokensPerCompaction: z26.number().int().min(2000).max(200000).optional(),
|
|
2728
2595
|
contextWindowOverride: z26.number().int().min(8000).max(1e7).optional(),
|
|
2729
2596
|
summaryMaxChars: z26.number().int().min(200).max(50000).optional(),
|
|
2730
2597
|
aggressivePruneWhenUncached: z26.boolean().optional(),
|
|
@@ -2738,6 +2605,7 @@ var init_config3 = __esm(() => {
|
|
|
2738
2605
|
compactAtFraction: z26.number().min(0.3).max(0.95),
|
|
2739
2606
|
pruneAtFraction: z26.number().min(0.2).max(0.9),
|
|
2740
2607
|
preserveRecentMessages: z26.number().int().min(2).max(100),
|
|
2608
|
+
maxCoverageTokensPerCompaction: z26.number().int().min(2000).max(200000),
|
|
2741
2609
|
contextWindowOverride: z26.number().int().min(8000).max(1e7).nullable(),
|
|
2742
2610
|
summaryMaxChars: z26.number().int().min(200).max(50000),
|
|
2743
2611
|
aggressivePruneWhenUncached: z26.boolean(),
|
|
@@ -2750,6 +2618,7 @@ var init_config3 = __esm(() => {
|
|
|
2750
2618
|
compactAtFraction: 0.7,
|
|
2751
2619
|
pruneAtFraction: 0.6,
|
|
2752
2620
|
preserveRecentMessages: 6,
|
|
2621
|
+
maxCoverageTokensPerCompaction: 12000,
|
|
2753
2622
|
contextWindowOverride: null,
|
|
2754
2623
|
summaryMaxChars: 4000,
|
|
2755
2624
|
aggressivePruneWhenUncached: true,
|
|
@@ -2829,10 +2698,44 @@ var init_estimate = __esm(() => {
|
|
|
2829
2698
|
totalTokens: z27.number().nonnegative().optional()
|
|
2830
2699
|
}),
|
|
2831
2700
|
modelId: z27.string().optional(),
|
|
2832
|
-
finishReason: languageModelFinishReasonSchema.optional()
|
|
2701
|
+
finishReason: languageModelFinishReasonSchema.optional(),
|
|
2702
|
+
context: z27.object({
|
|
2703
|
+
inputTokens: z27.number().nonnegative(),
|
|
2704
|
+
contextWindow: z27.number().positive(),
|
|
2705
|
+
compactedMessages: z27.number().nonnegative().optional()
|
|
2706
|
+
}).optional()
|
|
2833
2707
|
}).loose();
|
|
2834
2708
|
});
|
|
2835
2709
|
|
|
2710
|
+
// packages/ai/src/common/output-utils.ts
|
|
2711
|
+
function omissionMarker(omitted) {
|
|
2712
|
+
return `
|
|
2713
|
+
|
|
2714
|
+
... [${omitted} characters omitted; re-read a line range with read_file or raise maxChars] ...
|
|
2715
|
+
|
|
2716
|
+
`;
|
|
2717
|
+
}
|
|
2718
|
+
function truncateText(text, maxChars = DEFAULT_TOOL_TEXT_OUTPUT_CHARS) {
|
|
2719
|
+
if (text.length <= maxChars) {
|
|
2720
|
+
return {
|
|
2721
|
+
text,
|
|
2722
|
+
truncated: false
|
|
2723
|
+
};
|
|
2724
|
+
}
|
|
2725
|
+
const markerReserve = omissionMarker(text.length).length;
|
|
2726
|
+
const usable = Math.max(0, maxChars - markerReserve);
|
|
2727
|
+
const headChars = Math.floor(usable * 0.7);
|
|
2728
|
+
const tailChars = usable - headChars;
|
|
2729
|
+
const head = text.slice(0, headChars);
|
|
2730
|
+
const tail = tailChars > 0 ? text.slice(text.length - tailChars) : "";
|
|
2731
|
+
const omitted = text.length - head.length - tail.length;
|
|
2732
|
+
return {
|
|
2733
|
+
text: `${head}${omissionMarker(omitted)}${tail}`,
|
|
2734
|
+
truncated: true
|
|
2735
|
+
};
|
|
2736
|
+
}
|
|
2737
|
+
var init_output_utils = () => {};
|
|
2738
|
+
|
|
2836
2739
|
// packages/ai/src/context/heuristic-summary.ts
|
|
2837
2740
|
function truncateInline(text, maxChars) {
|
|
2838
2741
|
const normalized = text.replace(/\s+/g, " ").trim();
|
|
@@ -3182,6 +3085,127 @@ var init_tier1_prune = __esm(() => {
|
|
|
3182
3085
|
init_message_parts();
|
|
3183
3086
|
});
|
|
3184
3087
|
|
|
3088
|
+
// packages/ai/src/context/fit-to-budget.ts
|
|
3089
|
+
function estimateStructuralTokens(messages) {
|
|
3090
|
+
return messages.reduce((total, message) => total + estimateMessageTokens(message), 0);
|
|
3091
|
+
}
|
|
3092
|
+
function getPartState2(part) {
|
|
3093
|
+
const state = isRecord3(part) ? Reflect.get(part, "state") : undefined;
|
|
3094
|
+
return typeof state === "string" ? state : null;
|
|
3095
|
+
}
|
|
3096
|
+
function elideOutput(part, originalChars) {
|
|
3097
|
+
const stub = {
|
|
3098
|
+
lightcodeElided: true,
|
|
3099
|
+
note: "Tool output elided to fit the model's context budget. Re-run the tool if this output is needed again.",
|
|
3100
|
+
originalChars
|
|
3101
|
+
};
|
|
3102
|
+
return { ...part, output: stub };
|
|
3103
|
+
}
|
|
3104
|
+
function elideToolOutputsInMessage(message) {
|
|
3105
|
+
let elided = 0;
|
|
3106
|
+
const parts = message.parts.map((part) => {
|
|
3107
|
+
if (!getToolNameFromPart(part) || getPartState2(part) !== "output-available") {
|
|
3108
|
+
return part;
|
|
3109
|
+
}
|
|
3110
|
+
const output = isRecord3(part) ? Reflect.get(part, "output") : undefined;
|
|
3111
|
+
if (output === undefined || isElidedToolOutput(output)) {
|
|
3112
|
+
return part;
|
|
3113
|
+
}
|
|
3114
|
+
elided += 1;
|
|
3115
|
+
return elideOutput(part, safeStringify(output).length);
|
|
3116
|
+
});
|
|
3117
|
+
return elided > 0 ? { message: { ...message, parts }, elided } : { message, elided: 0 };
|
|
3118
|
+
}
|
|
3119
|
+
function truncateTextPartsInMessage(message, capChars) {
|
|
3120
|
+
let truncated = 0;
|
|
3121
|
+
const parts = message.parts.map((part) => {
|
|
3122
|
+
if (!isRecord3(part)) {
|
|
3123
|
+
return part;
|
|
3124
|
+
}
|
|
3125
|
+
const text = Reflect.get(part, "text");
|
|
3126
|
+
if (typeof text !== "string" || text.length <= capChars) {
|
|
3127
|
+
return part;
|
|
3128
|
+
}
|
|
3129
|
+
const result = truncateText(text, capChars);
|
|
3130
|
+
if (!result.truncated) {
|
|
3131
|
+
return part;
|
|
3132
|
+
}
|
|
3133
|
+
truncated += 1;
|
|
3134
|
+
return { ...part, text: result.text };
|
|
3135
|
+
});
|
|
3136
|
+
return truncated > 0 ? { message: { ...message, parts }, truncated } : { message, truncated: 0 };
|
|
3137
|
+
}
|
|
3138
|
+
function fitMessagesToBudget(messages, options) {
|
|
3139
|
+
const budget = Math.max(0, Math.floor(options.inputBudgetTokens));
|
|
3140
|
+
const preserveRecentMessages = Math.max(0, options.preserveRecentMessages);
|
|
3141
|
+
let working = [...messages];
|
|
3142
|
+
let elidedToolOutputs = 0;
|
|
3143
|
+
let droppedMessages = 0;
|
|
3144
|
+
let truncatedTextParts = 0;
|
|
3145
|
+
const fits = () => estimateStructuralTokens(working) <= budget;
|
|
3146
|
+
if (fits()) {
|
|
3147
|
+
return {
|
|
3148
|
+
messages: working,
|
|
3149
|
+
elidedToolOutputs: 0,
|
|
3150
|
+
droppedMessages: 0,
|
|
3151
|
+
truncatedTextParts: 0,
|
|
3152
|
+
estimatedTokens: estimateStructuralTokens(working),
|
|
3153
|
+
fitted: false,
|
|
3154
|
+
withinBudget: true
|
|
3155
|
+
};
|
|
3156
|
+
}
|
|
3157
|
+
const preserveFrom = Math.max(0, working.length - preserveRecentMessages);
|
|
3158
|
+
for (let index = 0;index < preserveFrom && !fits(); index += 1) {
|
|
3159
|
+
const { message, elided } = elideToolOutputsInMessage(working[index]);
|
|
3160
|
+
if (elided > 0) {
|
|
3161
|
+
working[index] = message;
|
|
3162
|
+
elidedToolOutputs += elided;
|
|
3163
|
+
}
|
|
3164
|
+
}
|
|
3165
|
+
const firstIsSummary = isSummaryMessage(working[0]);
|
|
3166
|
+
let dropFrom = firstIsSummary ? 1 : 0;
|
|
3167
|
+
while (!fits() && working.length - dropFrom > preserveRecentMessages && dropFrom < working.length) {
|
|
3168
|
+
working.splice(dropFrom, 1);
|
|
3169
|
+
droppedMessages += 1;
|
|
3170
|
+
}
|
|
3171
|
+
if (!fits()) {
|
|
3172
|
+
working = working.map((message) => {
|
|
3173
|
+
const { message: elidedMessage, elided } = elideToolOutputsInMessage(message);
|
|
3174
|
+
elidedToolOutputs += elided;
|
|
3175
|
+
return elidedMessage;
|
|
3176
|
+
});
|
|
3177
|
+
let cap = MAX_TOOL_TEXT_OUTPUT_CHARS;
|
|
3178
|
+
while (!fits() && cap >= MIN_TRUNCATION_CAP_CHARS) {
|
|
3179
|
+
working = working.map((message) => {
|
|
3180
|
+
const { message: truncatedMessage, truncated } = truncateTextPartsInMessage(message, cap);
|
|
3181
|
+
truncatedTextParts += truncated;
|
|
3182
|
+
return truncatedMessage;
|
|
3183
|
+
});
|
|
3184
|
+
cap = Math.floor(cap / 2);
|
|
3185
|
+
}
|
|
3186
|
+
}
|
|
3187
|
+
return {
|
|
3188
|
+
messages: working,
|
|
3189
|
+
elidedToolOutputs,
|
|
3190
|
+
droppedMessages,
|
|
3191
|
+
truncatedTextParts,
|
|
3192
|
+
estimatedTokens: estimateStructuralTokens(working),
|
|
3193
|
+
fitted: elidedToolOutputs > 0 || droppedMessages > 0 || truncatedTextParts > 0,
|
|
3194
|
+
withinBudget: fits()
|
|
3195
|
+
};
|
|
3196
|
+
}
|
|
3197
|
+
function isSummaryMessage(message) {
|
|
3198
|
+
return message?.id === contextSummaryMessageId;
|
|
3199
|
+
}
|
|
3200
|
+
var MIN_TRUNCATION_CAP_CHARS = 256;
|
|
3201
|
+
var init_fit_to_budget = __esm(() => {
|
|
3202
|
+
init_output_utils();
|
|
3203
|
+
init_estimate();
|
|
3204
|
+
init_heuristic_summary();
|
|
3205
|
+
init_message_parts();
|
|
3206
|
+
init_tier1_prune();
|
|
3207
|
+
});
|
|
3208
|
+
|
|
3185
3209
|
// packages/ai/src/context/build-provider-view.ts
|
|
3186
3210
|
function computeCompactionCutoffIndex(messages, preserveRecentMessages, afterAnchorIndex) {
|
|
3187
3211
|
const candidate = messages.length - preserveRecentMessages;
|
|
@@ -3195,11 +3219,32 @@ function computeCompactionCutoffIndex(messages, preserveRecentMessages, afterAnc
|
|
|
3195
3219
|
}
|
|
3196
3220
|
return afterAnchorIndex;
|
|
3197
3221
|
}
|
|
3222
|
+
function capCoverageToTokenBudget(coveredMessages, maxTokens) {
|
|
3223
|
+
if (coveredMessages.length <= 1) {
|
|
3224
|
+
return [...coveredMessages];
|
|
3225
|
+
}
|
|
3226
|
+
let total = 0;
|
|
3227
|
+
const capped = [];
|
|
3228
|
+
for (const message of coveredMessages) {
|
|
3229
|
+
const messageTokens = estimateStructuralTokens([message]);
|
|
3230
|
+
if (capped.length > 0 && total + messageTokens > maxTokens) {
|
|
3231
|
+
break;
|
|
3232
|
+
}
|
|
3233
|
+
capped.push(message);
|
|
3234
|
+
total += messageTokens;
|
|
3235
|
+
}
|
|
3236
|
+
return capped;
|
|
3237
|
+
}
|
|
3198
3238
|
function buildProviderView(options) {
|
|
3199
3239
|
const { messages, contextState, config } = options;
|
|
3200
3240
|
const contextWindow = resolveContextWindowTokens({
|
|
3201
3241
|
config,
|
|
3202
|
-
modelContextWindow: options.modelContextWindow
|
|
3242
|
+
modelContextWindow: options.modelContextWindow,
|
|
3243
|
+
endpointLimitTokens: options.endpointLimitTokens
|
|
3244
|
+
});
|
|
3245
|
+
const inputBudgetTokens = resolveInputBudgetTokens({
|
|
3246
|
+
contextWindow,
|
|
3247
|
+
reservedOutputTokens: options.reservedOutputTokens
|
|
3203
3248
|
});
|
|
3204
3249
|
let anchorResolved = false;
|
|
3205
3250
|
let afterAnchorIndex = 0;
|
|
@@ -3223,7 +3268,8 @@ function buildProviderView(options) {
|
|
|
3223
3268
|
let tier1 = null;
|
|
3224
3269
|
const uncachedActive = options.cacheActive === false && config.aggressivePruneWhenUncached;
|
|
3225
3270
|
const pruneFraction = uncachedActive ? config.uncachedPruneAtFraction : config.pruneAtFraction;
|
|
3226
|
-
|
|
3271
|
+
const triggerTokens = (currentEstimateTokens) => Math.max(currentEstimateTokens, estimateStructuralTokens(providerMessages), typeof options.measuredInputTokens === "number" ? options.measuredInputTokens : 0);
|
|
3272
|
+
if (triggerTokens(estimate.tokens) > pruneFraction * inputBudgetTokens) {
|
|
3227
3273
|
tier1 = pruneToolOutputs(providerMessages, {
|
|
3228
3274
|
preserveRecentMessages: config.preserveRecentMessages,
|
|
3229
3275
|
minOutputChars: uncachedActive ? config.uncachedPruneMinOutputChars : undefined,
|
|
@@ -3238,15 +3284,15 @@ function buildProviderView(options) {
|
|
|
3238
3284
|
}
|
|
3239
3285
|
}
|
|
3240
3286
|
const compactionCutoffIndex = computeCompactionCutoffIndex(messages, config.preserveRecentMessages, afterAnchorIndex);
|
|
3241
|
-
const coveredMessages = messages.slice(afterAnchorIndex, compactionCutoffIndex);
|
|
3242
|
-
const overCompactThreshold = estimate.tokens > config.compactAtFraction *
|
|
3287
|
+
const coveredMessages = capCoverageToTokenBudget(messages.slice(afterAnchorIndex, compactionCutoffIndex), config.maxCoverageTokensPerCompaction);
|
|
3288
|
+
const overCompactThreshold = triggerTokens(estimate.tokens) > config.compactAtFraction * inputBudgetTokens;
|
|
3243
3289
|
let compactionBlockedReason = null;
|
|
3244
3290
|
if (overCompactThreshold) {
|
|
3245
3291
|
if (coveredMessages.length === 0) {
|
|
3246
3292
|
compactionBlockedReason = "not_enough_messages";
|
|
3247
3293
|
} else if ((options.pendingInteractionCount ?? 0) > 0) {
|
|
3248
3294
|
compactionBlockedReason = "pending_interactions";
|
|
3249
|
-
} else if (hasUnresolvedToolWork(
|
|
3295
|
+
} else if (hasUnresolvedToolWork(coveredMessages)) {
|
|
3250
3296
|
compactionBlockedReason = "unresolved_tool_work";
|
|
3251
3297
|
}
|
|
3252
3298
|
}
|
|
@@ -3254,6 +3300,7 @@ function buildProviderView(options) {
|
|
|
3254
3300
|
providerMessages,
|
|
3255
3301
|
estimate,
|
|
3256
3302
|
contextWindow,
|
|
3303
|
+
inputBudgetTokens,
|
|
3257
3304
|
needsCompaction: overCompactThreshold && compactionBlockedReason === null,
|
|
3258
3305
|
compactionBlockedReason,
|
|
3259
3306
|
anchorResolved,
|
|
@@ -3265,6 +3312,7 @@ function buildProviderView(options) {
|
|
|
3265
3312
|
var init_build_provider_view = __esm(() => {
|
|
3266
3313
|
init_config3();
|
|
3267
3314
|
init_estimate();
|
|
3315
|
+
init_fit_to_budget();
|
|
3268
3316
|
init_heuristic_summary();
|
|
3269
3317
|
init_message_parts();
|
|
3270
3318
|
init_tier1_prune();
|
|
@@ -3310,6 +3358,7 @@ var init_context = __esm(() => {
|
|
|
3310
3358
|
init_config3();
|
|
3311
3359
|
init_context_state();
|
|
3312
3360
|
init_estimate();
|
|
3361
|
+
init_fit_to_budget();
|
|
3313
3362
|
init_heuristic_summary();
|
|
3314
3363
|
init_message_parts();
|
|
3315
3364
|
init_normalize_provider_messages();
|
|
@@ -3583,7 +3632,7 @@ var init_lightcode_config = __esm(() => {
|
|
|
3583
3632
|
context: defaultContextOptimizerConfig,
|
|
3584
3633
|
maxOutputTokens: 32768,
|
|
3585
3634
|
maxSteps: 30,
|
|
3586
|
-
maxRetries:
|
|
3635
|
+
maxRetries: 3,
|
|
3587
3636
|
autoContinue: defaultAutoContinueConfig,
|
|
3588
3637
|
headroom: defaultHeadroomConfig
|
|
3589
3638
|
};
|
|
@@ -4097,6 +4146,10 @@ async function extractToolCalls(text, knownToolNames) {
|
|
|
4097
4146
|
while ((match = DEEPSEEK_WRAPPER_RE.exec(text)) !== null) {
|
|
4098
4147
|
segments.push({ start: match.index, end: match.index + match[0].length, call: null });
|
|
4099
4148
|
}
|
|
4149
|
+
FUNCTION_CALLS_WRAPPER_RE.lastIndex = 0;
|
|
4150
|
+
while ((match = FUNCTION_CALLS_WRAPPER_RE.exec(text)) !== null) {
|
|
4151
|
+
segments.push({ start: match.index, end: match.index + match[0].length, call: null });
|
|
4152
|
+
}
|
|
4100
4153
|
const covered = (idx) => segments.some((s) => idx >= s.start && idx < s.end);
|
|
4101
4154
|
const orphanIdx = findOrphanMarker(text, covered);
|
|
4102
4155
|
if (orphanIdx !== -1) {
|
|
@@ -4184,7 +4237,7 @@ async function parseBareTrailingJson(text, knownToolNames) {
|
|
|
4184
4237
|
return null;
|
|
4185
4238
|
return { start: idx, payload };
|
|
4186
4239
|
}
|
|
4187
|
-
var TOOL_CALL_OPEN_MARKERS, MAX_MARKER_LENGTH, MARKER_CONFIRMATION_WINDOW = 256, BLOCK_CLOSE_MARKERS, CLOSED_BLOCK_RES, DEEPSEEK_WRAPPER_RE, PARAMETER_TAG_RE, PARAMETER_EQ_RE;
|
|
4240
|
+
var TOOL_CALL_OPEN_MARKERS, MAX_MARKER_LENGTH, MARKER_CONFIRMATION_WINDOW = 256, BLOCK_CLOSE_MARKERS, CLOSED_BLOCK_RES, DEEPSEEK_WRAPPER_RE, FUNCTION_CALLS_WRAPPER_RE, PARAMETER_TAG_RE, PARAMETER_EQ_RE;
|
|
4188
4241
|
var init_xml_tool_call_parser = __esm(() => {
|
|
4189
4242
|
init_tool_call_json_repair();
|
|
4190
4243
|
TOOL_CALL_OPEN_MARKERS = [
|
|
@@ -4211,6 +4264,7 @@ var init_xml_tool_call_parser = __esm(() => {
|
|
|
4211
4264
|
deepseek: /<\uFF5Ctool\u2581call\u2581begin\uFF5C>\s*(?:function)?\s*(?:<\uFF5Ctool\u2581sep\uFF5C>)?\s*([\w.-]+)\s*\n?([\s\S]*?)<\uFF5Ctool\u2581call\u2581end\uFF5C>/g
|
|
4212
4265
|
};
|
|
4213
4266
|
DEEPSEEK_WRAPPER_RE = /<\uFF5Ctool\u2581calls\u2581(?:begin|end)\uFF5C>/g;
|
|
4267
|
+
FUNCTION_CALLS_WRAPPER_RE = /<\/?function_calls\s*>/gi;
|
|
4214
4268
|
PARAMETER_TAG_RE = /<parameter\s+name=["']?([\w.-]+)["']?\s*>([\s\S]*?)(?:<\/parameter>|(?=<parameter\s)|$)/gi;
|
|
4215
4269
|
PARAMETER_EQ_RE = /<parameter=([\w.-]+)>([\s\S]*?)(?=<parameter=|<\/function>|$)/gi;
|
|
4216
4270
|
});
|
|
@@ -5099,6 +5153,14 @@ function isProviderBillingOrQuotaError(error) {
|
|
|
5099
5153
|
function isContextOverflowMessage(message) {
|
|
5100
5154
|
return contextOverflowPattern.test(message);
|
|
5101
5155
|
}
|
|
5156
|
+
function extractContextLimitTokens(message) {
|
|
5157
|
+
const match = contextLimitPattern.exec(message);
|
|
5158
|
+
if (!match) {
|
|
5159
|
+
return;
|
|
5160
|
+
}
|
|
5161
|
+
const value = Number.parseInt(match[1], 10);
|
|
5162
|
+
return Number.isFinite(value) && value > 0 ? value : undefined;
|
|
5163
|
+
}
|
|
5102
5164
|
function isAbortError(error) {
|
|
5103
5165
|
return error instanceof Error && error.name === "AbortError" || normalizeErrorMessage(getErrorMessage(error)).includes("aborted");
|
|
5104
5166
|
}
|
|
@@ -5139,7 +5201,8 @@ function classifyChatError(error) {
|
|
|
5139
5201
|
kind,
|
|
5140
5202
|
statusCode: error.statusCode,
|
|
5141
5203
|
retryable,
|
|
5142
|
-
message: message2
|
|
5204
|
+
message: message2,
|
|
5205
|
+
contextLimitTokens: kind === "context_overflow" ? extractContextLimitTokens(message2) : undefined
|
|
5143
5206
|
};
|
|
5144
5207
|
}
|
|
5145
5208
|
return {
|
|
@@ -5153,7 +5216,12 @@ function classifyChatError(error) {
|
|
|
5153
5216
|
return { kind: "aborted", retryable: false, message };
|
|
5154
5217
|
}
|
|
5155
5218
|
if (isContextOverflowMessage(message)) {
|
|
5156
|
-
return {
|
|
5219
|
+
return {
|
|
5220
|
+
kind: "context_overflow",
|
|
5221
|
+
retryable: true,
|
|
5222
|
+
message,
|
|
5223
|
+
contextLimitTokens: extractContextLimitTokens(message)
|
|
5224
|
+
};
|
|
5157
5225
|
}
|
|
5158
5226
|
if (isProviderBillingOrQuotaError(error)) {
|
|
5159
5227
|
return { kind: "billing", retryable: false, message };
|
|
@@ -5219,7 +5287,7 @@ function logChatDisconnectEvent({
|
|
|
5219
5287
|
message: getErrorMessage(error)
|
|
5220
5288
|
});
|
|
5221
5289
|
}
|
|
5222
|
-
var chatFailureCounters, logger2, retryableStatusCodes, contextOverflowPattern;
|
|
5290
|
+
var chatFailureCounters, logger2, retryableStatusCodes, contextOverflowPattern, contextLimitPattern;
|
|
5223
5291
|
var init_chat_observability = __esm(() => {
|
|
5224
5292
|
init_src();
|
|
5225
5293
|
chatFailureCounters = {
|
|
@@ -5238,6 +5306,7 @@ var init_chat_observability = __esm(() => {
|
|
|
5238
5306
|
logger2 = createLogger("chat");
|
|
5239
5307
|
retryableStatusCodes = new Set([408, 409, 429, 500, 502, 503, 504]);
|
|
5240
5308
|
contextOverflowPattern = /(context window|context length|context_length|maximum context|prompt is too long|input is too long|too many tokens|exceeds? the (?:maximum|model'?s) (?:context|token)|max(?:imum)? input tokens)/i;
|
|
5309
|
+
contextLimitPattern = /(?:maximum context (?:length|window)|max(?:imum)? input (?:length|tokens)|context (?:length|window) of)\D{0,40}?(\d{4,})/i;
|
|
5241
5310
|
});
|
|
5242
5311
|
|
|
5243
5312
|
// packages/db/generated/prisma/internal/class.ts
|
|
@@ -6133,9 +6202,6 @@ var init_resolve_within_workspace = __esm(() => {
|
|
|
6133
6202
|
WORKSPACE = defaultWorkspaceContext.root;
|
|
6134
6203
|
});
|
|
6135
6204
|
|
|
6136
|
-
// packages/ai/src/common/output-utils.ts
|
|
6137
|
-
var init_output_utils = () => {};
|
|
6138
|
-
|
|
6139
6205
|
// packages/ai/src/bash/runtime.ts
|
|
6140
6206
|
import { exec } from "child_process";
|
|
6141
6207
|
import { promisify } from "util";
|
|
@@ -6171,11 +6237,15 @@ var init_runtime5 = __esm(() => {
|
|
|
6171
6237
|
import { createTwoFilesPatch } from "diff";
|
|
6172
6238
|
var init_unified_diff = () => {};
|
|
6173
6239
|
|
|
6240
|
+
// packages/ai/src/edit-file/match.ts
|
|
6241
|
+
var init_match = () => {};
|
|
6242
|
+
|
|
6174
6243
|
// packages/ai/src/edit-file/runtime.ts
|
|
6175
6244
|
var init_runtime6 = __esm(() => {
|
|
6176
6245
|
init_runtime5();
|
|
6177
6246
|
init_resolve_within_workspace();
|
|
6178
6247
|
init_unified_diff();
|
|
6248
|
+
init_match();
|
|
6179
6249
|
init_schema2();
|
|
6180
6250
|
});
|
|
6181
6251
|
|
|
@@ -6722,6 +6792,24 @@ var init_overflow_recovery = __esm(() => {
|
|
|
6722
6792
|
overflowRecoveryRounds = new Map;
|
|
6723
6793
|
});
|
|
6724
6794
|
|
|
6795
|
+
// apps/server/src/lib/learned-context-limit.ts
|
|
6796
|
+
function noteLearnedContextLimit(modelId, limitTokens) {
|
|
6797
|
+
if (!modelId || typeof limitTokens !== "number" || !Number.isFinite(limitTokens) || limitTokens <= 0) {
|
|
6798
|
+
return;
|
|
6799
|
+
}
|
|
6800
|
+
const existing = learnedLimits.get(modelId);
|
|
6801
|
+
if (existing === undefined || limitTokens < existing) {
|
|
6802
|
+
learnedLimits.set(modelId, Math.floor(limitTokens));
|
|
6803
|
+
}
|
|
6804
|
+
}
|
|
6805
|
+
function getLearnedContextLimit(modelId) {
|
|
6806
|
+
return learnedLimits.get(modelId) ?? null;
|
|
6807
|
+
}
|
|
6808
|
+
var learnedLimits;
|
|
6809
|
+
var init_learned_context_limit = __esm(() => {
|
|
6810
|
+
learnedLimits = new Map;
|
|
6811
|
+
});
|
|
6812
|
+
|
|
6725
6813
|
// apps/server/src/lib/sse-heartbeat.ts
|
|
6726
6814
|
function endsWithEventBoundary(chunk) {
|
|
6727
6815
|
const length = chunk.length;
|
|
@@ -6947,6 +7035,16 @@ function getAnthropicProviderOptions(modelId) {
|
|
|
6947
7035
|
}
|
|
6948
7036
|
};
|
|
6949
7037
|
}
|
|
7038
|
+
function getOpenRouterProviderOptions() {
|
|
7039
|
+
return {
|
|
7040
|
+
openrouter: {
|
|
7041
|
+
provider: {
|
|
7042
|
+
allow_fallbacks: true,
|
|
7043
|
+
require_parameters: true
|
|
7044
|
+
}
|
|
7045
|
+
}
|
|
7046
|
+
};
|
|
7047
|
+
}
|
|
6950
7048
|
function resolveHeadroomRouting(config5, realBaseUrl) {
|
|
6951
7049
|
const headroom = config5.headroom;
|
|
6952
7050
|
if (!headroom?.enabled) {
|
|
@@ -7011,12 +7109,8 @@ function resolveOpenAITransportModel({
|
|
|
7011
7109
|
if (isOpenRouter) {
|
|
7012
7110
|
const referer = getEnvValue(env, "OPENROUTER_HTTP_REFERER");
|
|
7013
7111
|
const title = getEnvValue(env, "OPENROUTER_APP_TITLE", "LIGHTCODE_APP_TITLE");
|
|
7014
|
-
|
|
7015
|
-
|
|
7016
|
-
}
|
|
7017
|
-
if (title) {
|
|
7018
|
-
headers["X-OpenRouter-Title"] = title;
|
|
7019
|
-
}
|
|
7112
|
+
headers["HTTP-Referer"] = referer ?? "https://github.com/kmugalkhod/lightcode";
|
|
7113
|
+
headers["X-Title"] = title ?? "Lightcode";
|
|
7020
7114
|
}
|
|
7021
7115
|
const provider = createOpenAICompatible({
|
|
7022
7116
|
name: config5.provider,
|
|
@@ -7033,6 +7127,7 @@ function resolveOpenAITransportModel({
|
|
|
7033
7127
|
headroomRouted,
|
|
7034
7128
|
model: withXmlToolCallSupport(provider(configuredModel)),
|
|
7035
7129
|
needsToolCallDiscipline: true,
|
|
7130
|
+
providerOptions: isOpenRouter ? getOpenRouterProviderOptions() : undefined,
|
|
7036
7131
|
contextWindow: capabilities?.contextLength ?? getModelContextWindow(config5.provider, configuredModel),
|
|
7037
7132
|
missingCredentialHints: apiKey ? [] : isOpenCodeZen ? ["Set OPENCODE_API_KEY to call OpenCode Zen models."] : isOpenRouter ? ["Set OPENROUTER_API_KEY to call OpenRouter models."] : [
|
|
7038
7133
|
"Set LIGHTCODE_OPENAI_COMPATIBLE_API_KEY or OPENAI_API_KEY if your OpenAI-compatible endpoint requires authentication."
|
|
@@ -7553,6 +7648,8 @@ async function streamSessionChat(c, sessionIdentifier, messagesPayload, cwd, mod
|
|
|
7553
7648
|
}
|
|
7554
7649
|
const contextConfig = lightcodeConfigResult.config.context;
|
|
7555
7650
|
const cacheActive = resolvedProviderModel.provider === "anthropic";
|
|
7651
|
+
const reservedOutputTokens = resolveMaxOutputTokens(lightcodeConfigResult.config.maxOutputTokens, lightcodeConfigDefaults.maxOutputTokens, resolvedProviderModel.maxCompletionTokens);
|
|
7652
|
+
const endpointLimitTokens = getLearnedContextLimit(chatModelId);
|
|
7556
7653
|
const pendingInteractionCount = await countPendingChatInteractions(sessionId);
|
|
7557
7654
|
let contextState = await loadSessionContextStateSafe(sessionId);
|
|
7558
7655
|
let view = buildProviderView({
|
|
@@ -7560,44 +7657,56 @@ async function streamSessionChat(c, sessionIdentifier, messagesPayload, cwd, mod
|
|
|
7560
7657
|
contextState,
|
|
7561
7658
|
config: contextConfig,
|
|
7562
7659
|
modelContextWindow: resolvedProviderModel.contextWindow,
|
|
7660
|
+
reservedOutputTokens,
|
|
7661
|
+
endpointLimitTokens,
|
|
7563
7662
|
pendingInteractionCount,
|
|
7564
7663
|
cacheActive
|
|
7565
7664
|
});
|
|
7566
|
-
if (
|
|
7567
|
-
|
|
7568
|
-
|
|
7569
|
-
|
|
7570
|
-
|
|
7571
|
-
|
|
7572
|
-
|
|
7573
|
-
|
|
7574
|
-
|
|
7575
|
-
|
|
7576
|
-
|
|
7577
|
-
|
|
7578
|
-
|
|
7579
|
-
|
|
7580
|
-
|
|
7581
|
-
|
|
7582
|
-
contextState
|
|
7583
|
-
|
|
7584
|
-
|
|
7585
|
-
|
|
7586
|
-
|
|
7587
|
-
|
|
7588
|
-
|
|
7589
|
-
|
|
7590
|
-
|
|
7591
|
-
|
|
7592
|
-
|
|
7593
|
-
|
|
7594
|
-
|
|
7595
|
-
|
|
7596
|
-
|
|
7597
|
-
|
|
7598
|
-
|
|
7599
|
-
|
|
7600
|
-
|
|
7665
|
+
if (contextConfig.autoCompact) {
|
|
7666
|
+
let compactionRound = 0;
|
|
7667
|
+
while (view.needsCompaction && compactionRound < MAX_COMPACTION_ROUNDS) {
|
|
7668
|
+
compactionRound += 1;
|
|
7669
|
+
try {
|
|
7670
|
+
const estimatedTokensBefore = view.estimate.tokens;
|
|
7671
|
+
const compaction = await compactSessionContext({
|
|
7672
|
+
sessionId,
|
|
7673
|
+
coveredMessages: view.coveredMessages,
|
|
7674
|
+
previousState: contextState,
|
|
7675
|
+
model: resolvedProviderModel.model,
|
|
7676
|
+
modelId: chatModelId,
|
|
7677
|
+
cwd,
|
|
7678
|
+
config: contextConfig,
|
|
7679
|
+
estimatedTokens: estimatedTokensBefore
|
|
7680
|
+
});
|
|
7681
|
+
contextState = compaction.state;
|
|
7682
|
+
view = buildProviderView({
|
|
7683
|
+
messages: validatedMessages,
|
|
7684
|
+
contextState,
|
|
7685
|
+
config: contextConfig,
|
|
7686
|
+
modelContextWindow: resolvedProviderModel.contextWindow,
|
|
7687
|
+
reservedOutputTokens,
|
|
7688
|
+
endpointLimitTokens,
|
|
7689
|
+
pendingInteractionCount,
|
|
7690
|
+
cacheActive
|
|
7691
|
+
});
|
|
7692
|
+
logger8.info("context_auto_compacted", {
|
|
7693
|
+
sessionId,
|
|
7694
|
+
round: compactionRound,
|
|
7695
|
+
tier: compaction.state.tier,
|
|
7696
|
+
usedFallback: compaction.usedFallback,
|
|
7697
|
+
coveredMessageCount: compaction.state.coveredMessageCount,
|
|
7698
|
+
estimatedTokensBefore,
|
|
7699
|
+
estimatedTokensAfter: view.estimate.tokens,
|
|
7700
|
+
stillNeedsCompaction: view.needsCompaction
|
|
7701
|
+
});
|
|
7702
|
+
} catch (error) {
|
|
7703
|
+
logger8.error("context_compaction_failed", {
|
|
7704
|
+
sessionId,
|
|
7705
|
+
round: compactionRound,
|
|
7706
|
+
error: getErrorMessage(error)
|
|
7707
|
+
});
|
|
7708
|
+
break;
|
|
7709
|
+
}
|
|
7601
7710
|
}
|
|
7602
7711
|
}
|
|
7603
7712
|
const overflowPreserve = getOverflowPreserveRecentMessages(sessionId);
|
|
@@ -7612,6 +7721,8 @@ async function streamSessionChat(c, sessionIdentifier, messagesPayload, cwd, mod
|
|
|
7612
7721
|
contextState,
|
|
7613
7722
|
config: overflowConfig,
|
|
7614
7723
|
modelContextWindow: resolvedProviderModel.contextWindow,
|
|
7724
|
+
reservedOutputTokens,
|
|
7725
|
+
endpointLimitTokens,
|
|
7615
7726
|
pendingInteractionCount: 0,
|
|
7616
7727
|
cacheActive
|
|
7617
7728
|
});
|
|
@@ -7633,6 +7744,8 @@ async function streamSessionChat(c, sessionIdentifier, messagesPayload, cwd, mod
|
|
|
7633
7744
|
contextState,
|
|
7634
7745
|
config: overflowConfig,
|
|
7635
7746
|
modelContextWindow: resolvedProviderModel.contextWindow,
|
|
7747
|
+
reservedOutputTokens,
|
|
7748
|
+
endpointLimitTokens,
|
|
7636
7749
|
pendingInteractionCount: 0,
|
|
7637
7750
|
cacheActive
|
|
7638
7751
|
});
|
|
@@ -7651,7 +7764,24 @@ async function streamSessionChat(c, sessionIdentifier, messagesPayload, cwd, mod
|
|
|
7651
7764
|
});
|
|
7652
7765
|
}
|
|
7653
7766
|
}
|
|
7654
|
-
const
|
|
7767
|
+
const fitted = fitMessagesToBudget(view.providerMessages, {
|
|
7768
|
+
inputBudgetTokens: view.inputBudgetTokens,
|
|
7769
|
+
preserveRecentMessages: contextConfig.preserveRecentMessages
|
|
7770
|
+
});
|
|
7771
|
+
if (fitted.fitted) {
|
|
7772
|
+
logger8.warn("context_fit_to_budget", {
|
|
7773
|
+
sessionId,
|
|
7774
|
+
inputBudgetTokens: view.inputBudgetTokens,
|
|
7775
|
+
contextWindow: view.contextWindow,
|
|
7776
|
+
estimatedTokensBefore: estimateStructuralTokens(view.providerMessages),
|
|
7777
|
+
estimatedTokensAfter: fitted.estimatedTokens,
|
|
7778
|
+
elidedToolOutputs: fitted.elidedToolOutputs,
|
|
7779
|
+
droppedMessages: fitted.droppedMessages,
|
|
7780
|
+
truncatedTextParts: fitted.truncatedTextParts,
|
|
7781
|
+
withinBudget: fitted.withinBudget
|
|
7782
|
+
});
|
|
7783
|
+
}
|
|
7784
|
+
const providerMessages = normalizeProviderMessages(fitted.messages);
|
|
7655
7785
|
let overflowNotedThisRequest = false;
|
|
7656
7786
|
const noteOverflowForSession = () => {
|
|
7657
7787
|
if (overflowNotedThisRequest) {
|
|
@@ -7745,7 +7875,12 @@ async function streamSessionChat(c, sessionIdentifier, messagesPayload, cwd, mod
|
|
|
7745
7875
|
totalTokens: part.totalUsage.totalTokens
|
|
7746
7876
|
},
|
|
7747
7877
|
modelId: chatModelId,
|
|
7748
|
-
finishReason: part.finishReason
|
|
7878
|
+
finishReason: part.finishReason,
|
|
7879
|
+
context: {
|
|
7880
|
+
inputTokens: view.estimate.tokens,
|
|
7881
|
+
contextWindow: view.contextWindow,
|
|
7882
|
+
compactedMessages: contextState?.coveredMessageCount ?? 0
|
|
7883
|
+
}
|
|
7749
7884
|
};
|
|
7750
7885
|
};
|
|
7751
7886
|
const environmentContext = await buildWorkspaceContext({ cwd });
|
|
@@ -7793,6 +7928,7 @@ ${environmentContext}`,
|
|
|
7793
7928
|
onError: (error) => {
|
|
7794
7929
|
const classified = classifyChatError(error);
|
|
7795
7930
|
if (classified.kind === "context_overflow") {
|
|
7931
|
+
noteLearnedContextLimit(chatModelId, classified.contextLimitTokens);
|
|
7796
7932
|
noteOverflowForSession();
|
|
7797
7933
|
}
|
|
7798
7934
|
incrementChatFailureCounter(chatFailureClassForErrorKind(classified.kind), { sessionId, statusCode: classified.statusCode });
|
|
@@ -7810,6 +7946,7 @@ ${environmentContext}`,
|
|
|
7810
7946
|
const mapStreamError = (error) => {
|
|
7811
7947
|
const classified = classifyChatError(error);
|
|
7812
7948
|
if (classified.kind === "context_overflow") {
|
|
7949
|
+
noteLearnedContextLimit(chatModelId, classified.contextLimitTokens);
|
|
7813
7950
|
noteOverflowForSession();
|
|
7814
7951
|
}
|
|
7815
7952
|
incrementChatFailureCounter(chatFailureClassForErrorKind(classified.kind), {
|
|
@@ -7864,6 +8001,7 @@ ${environmentContext}`,
|
|
|
7864
8001
|
} catch (error) {
|
|
7865
8002
|
const classified = classifyChatError(error);
|
|
7866
8003
|
if (classified.kind === "context_overflow") {
|
|
8004
|
+
noteLearnedContextLimit(chatModelId, classified.contextLimitTokens);
|
|
7867
8005
|
noteContextOverflow(sessionId);
|
|
7868
8006
|
}
|
|
7869
8007
|
incrementChatFailureCounter(chatFailureClassForErrorKind(classified.kind), {
|
|
@@ -7894,7 +8032,7 @@ ${environmentContext}`,
|
|
|
7894
8032
|
}, 500);
|
|
7895
8033
|
}
|
|
7896
8034
|
}
|
|
7897
|
-
var logger8, recoverableDisconnectMessage = "Connection interrupted. Please retry or regenerate your last message.", providerBillingOrQuotaMessage, fastChatSystemPrompt, fastChatMaxOutputTokens = 512, fastChatRecentMessageCount = 6;
|
|
8035
|
+
var logger8, recoverableDisconnectMessage = "Connection interrupted. Please retry or regenerate your last message.", providerBillingOrQuotaMessage, fastChatSystemPrompt, fastChatMaxOutputTokens = 512, fastChatRecentMessageCount = 6, MAX_COMPACTION_ROUNDS = 3;
|
|
7898
8036
|
var init_chat_stream = __esm(() => {
|
|
7899
8037
|
init_src2();
|
|
7900
8038
|
init_src();
|
|
@@ -7903,6 +8041,7 @@ var init_chat_stream = __esm(() => {
|
|
|
7903
8041
|
init_chat_store();
|
|
7904
8042
|
init_context_compaction();
|
|
7905
8043
|
init_overflow_recovery();
|
|
8044
|
+
init_learned_context_limit();
|
|
7906
8045
|
init_sse_heartbeat();
|
|
7907
8046
|
init_context_state_store();
|
|
7908
8047
|
init_session_auto_title();
|