@kmugalkhod/lightcode 0.2.0 → 0.3.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 +207 -56
- package/package.json +1 -1
- package/server.js +230 -19
package/cli.js
CHANGED
|
@@ -124,7 +124,7 @@ var init_logger = __esm(() => {
|
|
|
124
124
|
});
|
|
125
125
|
|
|
126
126
|
// packages/shared/src/version.ts
|
|
127
|
-
var lightcodeVersion = "0.
|
|
127
|
+
var lightcodeVersion = "0.3.0";
|
|
128
128
|
|
|
129
129
|
// packages/shared/src/index.ts
|
|
130
130
|
var productName = "Lightcode";
|
|
@@ -4173,6 +4173,43 @@ var init_build_provider_view = __esm(() => {
|
|
|
4173
4173
|
init_tier1_prune();
|
|
4174
4174
|
});
|
|
4175
4175
|
|
|
4176
|
+
// packages/ai/src/context/normalize-provider-messages.ts
|
|
4177
|
+
import { isToolUIPart } from "ai";
|
|
4178
|
+
function hasDanglingToolParts(messages) {
|
|
4179
|
+
return messages.some((message) => message.parts.some((part) => isToolUIPart(part) && !terminalToolStates.has(part.state)));
|
|
4180
|
+
}
|
|
4181
|
+
function resolveDanglingToolParts(messages, errorText = interruptedToolErrorText) {
|
|
4182
|
+
return messages.map((message) => {
|
|
4183
|
+
if (message.role !== "assistant") {
|
|
4184
|
+
return message;
|
|
4185
|
+
}
|
|
4186
|
+
let changed = false;
|
|
4187
|
+
const parts = message.parts.map((part) => {
|
|
4188
|
+
if (!isToolUIPart(part) || terminalToolStates.has(part.state)) {
|
|
4189
|
+
return part;
|
|
4190
|
+
}
|
|
4191
|
+
changed = true;
|
|
4192
|
+
return {
|
|
4193
|
+
...part,
|
|
4194
|
+
state: "output-error",
|
|
4195
|
+
errorText
|
|
4196
|
+
};
|
|
4197
|
+
});
|
|
4198
|
+
return changed ? { ...message, parts } : message;
|
|
4199
|
+
});
|
|
4200
|
+
}
|
|
4201
|
+
function normalizeProviderMessages(messages) {
|
|
4202
|
+
return resolveDanglingToolParts(messages);
|
|
4203
|
+
}
|
|
4204
|
+
var terminalToolStates, interruptedToolErrorText = "Tool call was interrupted by a connection retry. Re-issue the tool call if it is still needed.";
|
|
4205
|
+
var init_normalize_provider_messages = __esm(() => {
|
|
4206
|
+
terminalToolStates = new Set([
|
|
4207
|
+
"output-available",
|
|
4208
|
+
"output-error",
|
|
4209
|
+
"output-denied"
|
|
4210
|
+
]);
|
|
4211
|
+
});
|
|
4212
|
+
|
|
4176
4213
|
// packages/ai/src/context/index.ts
|
|
4177
4214
|
var init_context = __esm(() => {
|
|
4178
4215
|
init_build_provider_view();
|
|
@@ -4181,6 +4218,7 @@ var init_context = __esm(() => {
|
|
|
4181
4218
|
init_estimate();
|
|
4182
4219
|
init_heuristic_summary();
|
|
4183
4220
|
init_message_parts();
|
|
4221
|
+
init_normalize_provider_messages();
|
|
4184
4222
|
init_tier1_prune();
|
|
4185
4223
|
});
|
|
4186
4224
|
|
|
@@ -4279,6 +4317,12 @@ function readEnvConfig(env) {
|
|
|
4279
4317
|
summaryMaxChars: parseNumberEnv(env.LIGHTCODE_CONTEXT_SUMMARY_MAX_CHARS, "LIGHTCODE_CONTEXT_SUMMARY_MAX_CHARS")
|
|
4280
4318
|
};
|
|
4281
4319
|
const compactContextConfig = Object.fromEntries(Object.entries(contextConfig).filter(([, value]) => value !== undefined));
|
|
4320
|
+
const headroomConfig = {
|
|
4321
|
+
enabled: parseBooleanEnv(env.LIGHTCODE_HEADROOM_ENABLED, "LIGHTCODE_HEADROOM_ENABLED"),
|
|
4322
|
+
proxyUrl: env.LIGHTCODE_HEADROOM_PROXY_URL?.trim() || undefined,
|
|
4323
|
+
failOpen: parseBooleanEnv(env.LIGHTCODE_HEADROOM_FAIL_OPEN, "LIGHTCODE_HEADROOM_FAIL_OPEN")
|
|
4324
|
+
};
|
|
4325
|
+
const compactHeadroomConfig = Object.fromEntries(Object.entries(headroomConfig).filter(([, value]) => value !== undefined));
|
|
4282
4326
|
const rawConfig = {
|
|
4283
4327
|
provider: env.LIGHTCODE_PROVIDER,
|
|
4284
4328
|
model: env.LIGHTCODE_CHAT_MODEL,
|
|
@@ -4288,7 +4332,8 @@ function readEnvConfig(env) {
|
|
|
4288
4332
|
maxOutputTokens: parseNumberEnv(env.LIGHTCODE_MAX_OUTPUT_TOKENS, "LIGHTCODE_MAX_OUTPUT_TOKENS"),
|
|
4289
4333
|
maxSteps: parseNumberEnv(env.LIGHTCODE_MAX_STEPS, "LIGHTCODE_MAX_STEPS"),
|
|
4290
4334
|
maxRetries: parseNumberEnv(env.LIGHTCODE_MAX_RETRIES, "LIGHTCODE_MAX_RETRIES"),
|
|
4291
|
-
context: Object.keys(compactContextConfig).length > 0 ? compactContextConfig : undefined
|
|
4335
|
+
context: Object.keys(compactContextConfig).length > 0 ? compactContextConfig : undefined,
|
|
4336
|
+
headroom: Object.keys(compactHeadroomConfig).length > 0 ? compactHeadroomConfig : undefined
|
|
4292
4337
|
};
|
|
4293
4338
|
const compactConfig = Object.fromEntries(Object.entries(rawConfig).filter(([, value]) => value !== undefined));
|
|
4294
4339
|
const parsedConfig = lightcodeConfigSchema.safeParse(compactConfig);
|
|
@@ -4312,6 +4357,10 @@ function mergeConfig(...configs) {
|
|
|
4312
4357
|
...mergedConfig.autoContinue,
|
|
4313
4358
|
...config2.autoContinue
|
|
4314
4359
|
} : mergedConfig.autoContinue,
|
|
4360
|
+
headroom: config2.headroom ? {
|
|
4361
|
+
...mergedConfig.headroom,
|
|
4362
|
+
...config2.headroom
|
|
4363
|
+
} : mergedConfig.headroom,
|
|
4315
4364
|
allowedTools: config2.allowedTools ?? mergedConfig.allowedTools
|
|
4316
4365
|
}), {});
|
|
4317
4366
|
}
|
|
@@ -4352,6 +4401,10 @@ function loadLightcodeConfig({
|
|
|
4352
4401
|
autoContinue: {
|
|
4353
4402
|
...defaultAutoContinueConfig,
|
|
4354
4403
|
...mergedConfig.autoContinue
|
|
4404
|
+
},
|
|
4405
|
+
headroom: {
|
|
4406
|
+
...defaultHeadroomConfig,
|
|
4407
|
+
...mergedConfig.headroom
|
|
4355
4408
|
}
|
|
4356
4409
|
};
|
|
4357
4410
|
return lightcodeConfigLoadResultSchema.parse({
|
|
@@ -4359,7 +4412,7 @@ function loadLightcodeConfig({
|
|
|
4359
4412
|
loadedFiles: [userConfig.file, projectConfig.file]
|
|
4360
4413
|
});
|
|
4361
4414
|
}
|
|
4362
|
-
var lightcodeProviderSchema, autoContinueConfigSchema, resolvedAutoContinueConfigSchema, defaultAutoContinueConfig, lightcodeConfigSchema, lightcodeConfigDefaults, loadedConfigFileSchema, lightcodeResolvedConfigSchema, lightcodeConfigLoadResultSchema, lightcodeConfigStatusSchema, LightcodeConfigError;
|
|
4415
|
+
var lightcodeProviderSchema, autoContinueConfigSchema, resolvedAutoContinueConfigSchema, defaultAutoContinueConfig, headroomConfigSchema, resolvedHeadroomConfigSchema, defaultHeadroomConfig, lightcodeConfigSchema, lightcodeConfigDefaults, loadedConfigFileSchema, lightcodeResolvedConfigSchema, lightcodeConfigLoadResultSchema, lightcodeConfigStatusSchema, LightcodeConfigError;
|
|
4363
4416
|
var init_lightcode_config = __esm(() => {
|
|
4364
4417
|
init_coding_agent_modes();
|
|
4365
4418
|
init_coding_agent_modes();
|
|
@@ -4391,6 +4444,24 @@ var init_lightcode_config = __esm(() => {
|
|
|
4391
4444
|
maxErrorRetries: 5,
|
|
4392
4445
|
stallTimeoutSeconds: 180
|
|
4393
4446
|
};
|
|
4447
|
+
headroomConfigSchema = z28.object({
|
|
4448
|
+
enabled: z28.boolean().optional(),
|
|
4449
|
+
proxyUrl: z28.string().min(1).max(4096).optional(),
|
|
4450
|
+
providers: z28.array(lightcodeProviderSchema).optional(),
|
|
4451
|
+
failOpen: z28.boolean().optional()
|
|
4452
|
+
}).strict();
|
|
4453
|
+
resolvedHeadroomConfigSchema = z28.object({
|
|
4454
|
+
enabled: z28.boolean(),
|
|
4455
|
+
proxyUrl: z28.string().min(1).max(4096),
|
|
4456
|
+
providers: z28.array(lightcodeProviderSchema).nullable(),
|
|
4457
|
+
failOpen: z28.boolean()
|
|
4458
|
+
});
|
|
4459
|
+
defaultHeadroomConfig = {
|
|
4460
|
+
enabled: false,
|
|
4461
|
+
proxyUrl: "http://127.0.0.1:8787",
|
|
4462
|
+
providers: null,
|
|
4463
|
+
failOpen: true
|
|
4464
|
+
};
|
|
4394
4465
|
lightcodeConfigSchema = z28.object({
|
|
4395
4466
|
provider: lightcodeProviderSchema.optional(),
|
|
4396
4467
|
model: z28.string().min(1).max(240).optional(),
|
|
@@ -4402,10 +4473,11 @@ var init_lightcode_config = __esm(() => {
|
|
|
4402
4473
|
sandbox: sandboxConfigSchema.optional(),
|
|
4403
4474
|
mcp: mcpConfigSchema.optional(),
|
|
4404
4475
|
context: contextOptimizerConfigSchema.optional(),
|
|
4405
|
-
maxOutputTokens: z28.number().int().min(1).max(
|
|
4476
|
+
maxOutputTokens: z28.number().int().min(1).max(1e6).optional(),
|
|
4406
4477
|
maxSteps: z28.number().int().min(1).max(100).optional(),
|
|
4407
4478
|
maxRetries: z28.number().int().min(0).max(10).optional(),
|
|
4408
|
-
autoContinue: autoContinueConfigSchema.optional()
|
|
4479
|
+
autoContinue: autoContinueConfigSchema.optional(),
|
|
4480
|
+
headroom: headroomConfigSchema.optional()
|
|
4409
4481
|
}).strict();
|
|
4410
4482
|
lightcodeConfigDefaults = {
|
|
4411
4483
|
provider: "anthropic",
|
|
@@ -4414,7 +4486,8 @@ var init_lightcode_config = __esm(() => {
|
|
|
4414
4486
|
maxOutputTokens: 32768,
|
|
4415
4487
|
maxSteps: 30,
|
|
4416
4488
|
maxRetries: 5,
|
|
4417
|
-
autoContinue: defaultAutoContinueConfig
|
|
4489
|
+
autoContinue: defaultAutoContinueConfig,
|
|
4490
|
+
headroom: defaultHeadroomConfig
|
|
4418
4491
|
};
|
|
4419
4492
|
loadedConfigFileSchema = z28.object({
|
|
4420
4493
|
scope: z28.enum(["user", "project"]),
|
|
@@ -4426,10 +4499,11 @@ var init_lightcode_config = __esm(() => {
|
|
|
4426
4499
|
provider: lightcodeProviderSchema,
|
|
4427
4500
|
defaultMode: codingAgentModeSchema,
|
|
4428
4501
|
context: resolvedContextOptimizerConfigSchema,
|
|
4429
|
-
maxOutputTokens: z28.number().int().min(1).max(
|
|
4502
|
+
maxOutputTokens: z28.number().int().min(1).max(1e6),
|
|
4430
4503
|
maxSteps: z28.number().int().min(1).max(100),
|
|
4431
4504
|
maxRetries: z28.number().int().min(0).max(10),
|
|
4432
|
-
autoContinue: resolvedAutoContinueConfigSchema
|
|
4505
|
+
autoContinue: resolvedAutoContinueConfigSchema,
|
|
4506
|
+
headroom: resolvedHeadroomConfigSchema.optional()
|
|
4433
4507
|
});
|
|
4434
4508
|
lightcodeConfigLoadResultSchema = z28.object({
|
|
4435
4509
|
config: lightcodeResolvedConfigSchema,
|
|
@@ -4443,10 +4517,15 @@ var init_lightcode_config = __esm(() => {
|
|
|
4443
4517
|
baseUrl: z28.string().nullable(),
|
|
4444
4518
|
defaultMode: codingAgentModeSchema,
|
|
4445
4519
|
permissionMode: permissionModeSchema.nullable(),
|
|
4446
|
-
maxOutputTokens: z28.number().int().min(1).max(
|
|
4520
|
+
maxOutputTokens: z28.number().int().min(1).max(1e6),
|
|
4447
4521
|
maxSteps: z28.number().int().min(1).max(100),
|
|
4448
4522
|
autoContinue: resolvedAutoContinueConfigSchema,
|
|
4449
4523
|
contextWindow: z28.number().int().positive(),
|
|
4524
|
+
headroom: z28.object({
|
|
4525
|
+
enabled: z28.boolean(),
|
|
4526
|
+
proxyUrl: z28.string().nullable(),
|
|
4527
|
+
routed: z28.boolean()
|
|
4528
|
+
}),
|
|
4450
4529
|
missingCredentialHints: z28.array(z28.string())
|
|
4451
4530
|
});
|
|
4452
4531
|
LightcodeConfigError = class LightcodeConfigError extends Error {
|
|
@@ -4705,6 +4784,21 @@ var init_runtime = __esm(() => {
|
|
|
4705
4784
|
init_schema13();
|
|
4706
4785
|
});
|
|
4707
4786
|
|
|
4787
|
+
// packages/ai/src/providers/clamp-output-tokens.ts
|
|
4788
|
+
function clampMaxOutputTokens(configured, modelMaxCompletionTokens) {
|
|
4789
|
+
if (typeof modelMaxCompletionTokens === "number" && Number.isFinite(modelMaxCompletionTokens) && modelMaxCompletionTokens > 0) {
|
|
4790
|
+
return Math.min(configured, modelMaxCompletionTokens);
|
|
4791
|
+
}
|
|
4792
|
+
return configured;
|
|
4793
|
+
}
|
|
4794
|
+
function resolveMaxOutputTokens(configured, defaultValue, modelMaxCompletionTokens) {
|
|
4795
|
+
const hasModelCap = typeof modelMaxCompletionTokens === "number" && Number.isFinite(modelMaxCompletionTokens) && modelMaxCompletionTokens > 0;
|
|
4796
|
+
if (configured === defaultValue) {
|
|
4797
|
+
return hasModelCap ? modelMaxCompletionTokens : configured;
|
|
4798
|
+
}
|
|
4799
|
+
return clampMaxOutputTokens(configured, modelMaxCompletionTokens);
|
|
4800
|
+
}
|
|
4801
|
+
|
|
4708
4802
|
// packages/ai/src/providers/model-metadata.ts
|
|
4709
4803
|
function getModelContextWindow(provider, modelId) {
|
|
4710
4804
|
if (provider === "anthropic") {
|
|
@@ -7515,9 +7609,12 @@ __export(exports_runtime, {
|
|
|
7515
7609
|
sandboxConfigSchema: () => sandboxConfigSchema,
|
|
7516
7610
|
safeStringify: () => safeStringify,
|
|
7517
7611
|
runPluginHooks: () => runPluginHooks,
|
|
7612
|
+
resolvedHeadroomConfigSchema: () => resolvedHeadroomConfigSchema,
|
|
7518
7613
|
resolvedContextOptimizerConfigSchema: () => resolvedContextOptimizerConfigSchema,
|
|
7519
7614
|
resolvedAutoContinueConfigSchema: () => resolvedAutoContinueConfigSchema,
|
|
7520
7615
|
resolveWithinWorkspace: () => resolveWithinWorkspace,
|
|
7616
|
+
resolveMaxOutputTokens: () => resolveMaxOutputTokens,
|
|
7617
|
+
resolveDanglingToolParts: () => resolveDanglingToolParts,
|
|
7521
7618
|
resolveContextWindowTokens: () => resolveContextWindowTokens,
|
|
7522
7619
|
resolveCodingPermissionMode: () => resolveCodingPermissionMode,
|
|
7523
7620
|
requestUserInputToolProviderInputSchema: () => requestUserInputToolProviderInputSchema,
|
|
@@ -7547,6 +7644,7 @@ __export(exports_runtime, {
|
|
|
7547
7644
|
parseCodingToolInput: () => parseCodingToolInput,
|
|
7548
7645
|
parseChatStreamError: () => parseChatStreamError,
|
|
7549
7646
|
normalizeSandboxConfig: () => normalizeSandboxConfig,
|
|
7647
|
+
normalizeProviderMessages: () => normalizeProviderMessages,
|
|
7550
7648
|
normalizeContextOptimizerConfig: () => normalizeContextOptimizerConfig,
|
|
7551
7649
|
messageUsageMetadataSchema: () => messageUsageMetadataSchema,
|
|
7552
7650
|
mcpStdioServerConfigSchema: () => mcpStdioServerConfigSchema,
|
|
@@ -7577,7 +7675,10 @@ __export(exports_runtime, {
|
|
|
7577
7675
|
isRecord: () => isRecord3,
|
|
7578
7676
|
isPermissionDeniedError: () => isPermissionDeniedError,
|
|
7579
7677
|
isElidedToolOutput: () => isElidedToolOutput,
|
|
7678
|
+
interruptedToolErrorText: () => interruptedToolErrorText,
|
|
7679
|
+
headroomConfigSchema: () => headroomConfigSchema,
|
|
7580
7680
|
hasUnresolvedToolWork: () => hasUnresolvedToolWork,
|
|
7681
|
+
hasDanglingToolParts: () => hasDanglingToolParts,
|
|
7581
7682
|
getToolNameFromPart: () => getToolNameFromPart,
|
|
7582
7683
|
getTextPartContent: () => getTextPartContent,
|
|
7583
7684
|
getSandboxRuntimeStatus: () => getSandboxRuntimeStatus,
|
|
@@ -7628,6 +7729,7 @@ __export(exports_runtime, {
|
|
|
7628
7729
|
describeChatStreamError: () => describeChatStreamError,
|
|
7629
7730
|
defaultSubagentTaskMode: () => defaultSubagentTaskMode,
|
|
7630
7731
|
defaultPermissionModeForCodingMode: () => defaultPermissionModeForCodingMode,
|
|
7732
|
+
defaultHeadroomConfig: () => defaultHeadroomConfig,
|
|
7631
7733
|
defaultContextOptimizerConfig: () => defaultContextOptimizerConfig,
|
|
7632
7734
|
defaultCodingAgentSystemPrompt: () => defaultCodingAgentSystemPrompt,
|
|
7633
7735
|
defaultCodingAgentMode: () => defaultCodingAgentMode,
|
|
@@ -7663,6 +7765,7 @@ __export(exports_runtime, {
|
|
|
7663
7765
|
codingAgentModeSchema: () => codingAgentModeSchema,
|
|
7664
7766
|
codingAgentModeOrder: () => codingAgentModeOrder,
|
|
7665
7767
|
codingAgentCallOptionsSchema: () => codingAgentCallOptionsSchema,
|
|
7768
|
+
clampMaxOutputTokens: () => clampMaxOutputTokens,
|
|
7666
7769
|
chatInteractionUserPromptPayloadSchema: () => chatInteractionUserPromptPayloadSchema,
|
|
7667
7770
|
chatInteractionUpsertRequestSchema: () => chatInteractionUpsertRequestSchema,
|
|
7668
7771
|
chatInteractionToolCallIdSchema: () => chatInteractionToolCallIdSchema,
|
|
@@ -8026,7 +8129,7 @@ var init_auto_continue = __esm(() => {
|
|
|
8026
8129
|
import { useChat } from "@ai-sdk/react";
|
|
8027
8130
|
import {
|
|
8028
8131
|
DefaultChatTransport,
|
|
8029
|
-
isToolUIPart,
|
|
8132
|
+
isToolUIPart as isToolUIPart2,
|
|
8030
8133
|
lastAssistantMessageIsCompleteWithToolCalls,
|
|
8031
8134
|
safeValidateUIMessages
|
|
8032
8135
|
} from "ai";
|
|
@@ -8118,30 +8221,38 @@ function queueToolOutput(outputResult) {
|
|
|
8118
8221
|
console.warn("Failed to add tool output.", outputError);
|
|
8119
8222
|
});
|
|
8120
8223
|
}
|
|
8121
|
-
function
|
|
8122
|
-
if (
|
|
8123
|
-
return false;
|
|
8124
|
-
}
|
|
8125
|
-
if (message.parts.length === 0) {
|
|
8224
|
+
function isIncompletePart(part) {
|
|
8225
|
+
if ((part.type === "text" || part.type === "reasoning") && Reflect.get(part, "state") === "streaming") {
|
|
8126
8226
|
return true;
|
|
8127
8227
|
}
|
|
8128
|
-
return
|
|
8129
|
-
if ((part.type === "text" || part.type === "reasoning") && Reflect.get(part, "state") === "streaming") {
|
|
8130
|
-
return true;
|
|
8131
|
-
}
|
|
8132
|
-
return isToolUIPart(part) && part.state === "input-streaming";
|
|
8133
|
-
});
|
|
8228
|
+
return isToolUIPart2(part) && part.state === "input-streaming";
|
|
8134
8229
|
}
|
|
8135
|
-
function
|
|
8136
|
-
let
|
|
8137
|
-
while (
|
|
8138
|
-
|
|
8230
|
+
function pruneIncompleteTrailingAssistantParts(messages) {
|
|
8231
|
+
let result = messages;
|
|
8232
|
+
while (result.length > 0) {
|
|
8233
|
+
const lastIndex = result.length - 1;
|
|
8234
|
+
const last = result[lastIndex];
|
|
8235
|
+
if (last.role !== "assistant") {
|
|
8236
|
+
break;
|
|
8237
|
+
}
|
|
8238
|
+
const completeParts = last.parts.filter((part) => !isIncompletePart(part));
|
|
8239
|
+
if (completeParts.length === last.parts.length) {
|
|
8240
|
+
break;
|
|
8241
|
+
}
|
|
8242
|
+
if (completeParts.length === 0) {
|
|
8243
|
+
result = result.slice(0, lastIndex);
|
|
8244
|
+
continue;
|
|
8245
|
+
}
|
|
8246
|
+
const next = result.slice();
|
|
8247
|
+
next[lastIndex] = { ...last, parts: completeParts };
|
|
8248
|
+
result = next;
|
|
8249
|
+
break;
|
|
8139
8250
|
}
|
|
8140
|
-
return
|
|
8251
|
+
return result;
|
|
8141
8252
|
}
|
|
8142
8253
|
function hasUnresolvedToolParts(messages) {
|
|
8143
8254
|
return messages.some((message) => message.parts.some((part) => {
|
|
8144
|
-
if (!
|
|
8255
|
+
if (!isToolUIPart2(part)) {
|
|
8145
8256
|
return false;
|
|
8146
8257
|
}
|
|
8147
8258
|
return ![
|
|
@@ -8151,26 +8262,21 @@ function hasUnresolvedToolParts(messages) {
|
|
|
8151
8262
|
].includes(part.state);
|
|
8152
8263
|
}));
|
|
8153
8264
|
}
|
|
8154
|
-
function
|
|
8155
|
-
|
|
8156
|
-
|
|
8157
|
-
|
|
8158
|
-
|
|
8159
|
-
|
|
8160
|
-
|
|
8161
|
-
|
|
8162
|
-
if (!isToolUIPart(part) || terminalToolPartStates.has(part.state)) {
|
|
8163
|
-
return part;
|
|
8265
|
+
function countCompletedWork(messages) {
|
|
8266
|
+
let total = 0;
|
|
8267
|
+
for (const message of messages) {
|
|
8268
|
+
for (const part of message.parts) {
|
|
8269
|
+
if ((part.type === "text" || part.type === "reasoning") && Reflect.get(part, "state") !== "streaming") {
|
|
8270
|
+
total += 1;
|
|
8271
|
+
} else if (isToolUIPart2(part) && terminalToolPartStates.has(part.state)) {
|
|
8272
|
+
total += 1;
|
|
8164
8273
|
}
|
|
8165
|
-
|
|
8166
|
-
|
|
8167
|
-
|
|
8168
|
-
|
|
8169
|
-
|
|
8170
|
-
|
|
8171
|
-
});
|
|
8172
|
-
return changed ? { ...message, parts } : message;
|
|
8173
|
-
});
|
|
8274
|
+
}
|
|
8275
|
+
}
|
|
8276
|
+
return total;
|
|
8277
|
+
}
|
|
8278
|
+
function sanitizeMessagesForRetry(messages) {
|
|
8279
|
+
return resolveDanglingToolParts(pruneIncompleteTrailingAssistantParts(messages));
|
|
8174
8280
|
}
|
|
8175
8281
|
function hasActiveClientToolWork({
|
|
8176
8282
|
messages,
|
|
@@ -8180,7 +8286,7 @@ function hasActiveClientToolWork({
|
|
|
8180
8286
|
const pendingApprovalIds = new Set(pendingApprovals.map((approval) => approval.toolCallId));
|
|
8181
8287
|
const pendingPromptIds = new Set(pendingUserPrompts.map((prompt) => prompt.toolCallId));
|
|
8182
8288
|
return messages.some((message) => message.parts.some((part) => {
|
|
8183
|
-
if (!
|
|
8289
|
+
if (!isToolUIPart2(part)) {
|
|
8184
8290
|
return false;
|
|
8185
8291
|
}
|
|
8186
8292
|
if (part.state === "input-streaming" || part.state === "approval-responded") {
|
|
@@ -8308,6 +8414,9 @@ function useCodingSessionChat({
|
|
|
8308
8414
|
autoContinueLimitsRef.current = autoContinueLimits;
|
|
8309
8415
|
const maxErrorRetriesRef = useRef(maxErrorRetries);
|
|
8310
8416
|
maxErrorRetriesRef.current = maxErrorRetries;
|
|
8417
|
+
const maxNoProgressRetries = maxErrorRetries + 3;
|
|
8418
|
+
const maxNoProgressRetriesRef = useRef(maxNoProgressRetries);
|
|
8419
|
+
maxNoProgressRetriesRef.current = maxNoProgressRetries;
|
|
8311
8420
|
const stallTimeoutMsRef = useRef(stallTimeoutMs);
|
|
8312
8421
|
stallTimeoutMsRef.current = stallTimeoutMs;
|
|
8313
8422
|
const lastStreamActivityRef = useRef(Date.now());
|
|
@@ -8316,11 +8425,18 @@ function useCodingSessionChat({
|
|
|
8316
8425
|
const errorRetriesRef = useRef(0);
|
|
8317
8426
|
const errorRetryTimerRef = useRef(null);
|
|
8318
8427
|
const lastDecidedAssistantIdRef = useRef(null);
|
|
8428
|
+
const lastProgressMarkerRef = useRef(0);
|
|
8429
|
+
const noProgressRetriesRef = useRef(0);
|
|
8430
|
+
const taskStuckRef = useRef(false);
|
|
8431
|
+
const messagesRef = useRef([]);
|
|
8319
8432
|
const advanceTurnKey = useCallback(() => {
|
|
8320
8433
|
turnCounterRef.current += 1;
|
|
8321
8434
|
turnKeyRef.current = `turn-${Date.now()}-${turnCounterRef.current}`;
|
|
8322
8435
|
autoContinuesRef.current = 0;
|
|
8323
8436
|
errorRetriesRef.current = 0;
|
|
8437
|
+
lastProgressMarkerRef.current = 0;
|
|
8438
|
+
noProgressRetriesRef.current = 0;
|
|
8439
|
+
taskStuckRef.current = false;
|
|
8324
8440
|
lastDecidedAssistantIdRef.current = null;
|
|
8325
8441
|
if (errorRetryTimerRef.current) {
|
|
8326
8442
|
clearTimeout(errorRetryTimerRef.current);
|
|
@@ -8328,6 +8444,20 @@ function useCodingSessionChat({
|
|
|
8328
8444
|
}
|
|
8329
8445
|
setAutoContinueState(null);
|
|
8330
8446
|
}, []);
|
|
8447
|
+
const registerRetryProgress = useCallback((currentMessages) => {
|
|
8448
|
+
const marker = countCompletedWork(currentMessages);
|
|
8449
|
+
if (marker > lastProgressMarkerRef.current) {
|
|
8450
|
+
lastProgressMarkerRef.current = marker;
|
|
8451
|
+
noProgressRetriesRef.current = 0;
|
|
8452
|
+
return true;
|
|
8453
|
+
}
|
|
8454
|
+
noProgressRetriesRef.current += 1;
|
|
8455
|
+
if (noProgressRetriesRef.current > maxNoProgressRetriesRef.current) {
|
|
8456
|
+
taskStuckRef.current = true;
|
|
8457
|
+
return false;
|
|
8458
|
+
}
|
|
8459
|
+
return true;
|
|
8460
|
+
}, []);
|
|
8331
8461
|
modeRef.current = mode;
|
|
8332
8462
|
cwdRef.current = cwd;
|
|
8333
8463
|
permissionModeRef.current = permissionMode;
|
|
@@ -8707,6 +8837,9 @@ function useCodingSessionChat({
|
|
|
8707
8837
|
lastStreamActivityRef.current = Date.now();
|
|
8708
8838
|
}
|
|
8709
8839
|
}, [messages, status]);
|
|
8840
|
+
useEffect(() => {
|
|
8841
|
+
messagesRef.current = messages;
|
|
8842
|
+
}, [messages]);
|
|
8710
8843
|
useEffect(() => {
|
|
8711
8844
|
if (status !== "streaming" && status !== "submitted") {
|
|
8712
8845
|
return;
|
|
@@ -8719,7 +8852,15 @@ function useCodingSessionChat({
|
|
|
8719
8852
|
})) {
|
|
8720
8853
|
return;
|
|
8721
8854
|
}
|
|
8722
|
-
if (stallRecoveryInFlightRef.current || errorRetriesRef.current >= maxErrorRetriesRef.current) {
|
|
8855
|
+
if (taskStuckRef.current || stallRecoveryInFlightRef.current || errorRetriesRef.current >= maxErrorRetriesRef.current) {
|
|
8856
|
+
return;
|
|
8857
|
+
}
|
|
8858
|
+
if (!registerRetryProgress(messagesRef.current)) {
|
|
8859
|
+
setAutoContinueState({
|
|
8860
|
+
attempt: errorRetriesRef.current,
|
|
8861
|
+
kind: "none",
|
|
8862
|
+
guardTripped: "no-progress"
|
|
8863
|
+
});
|
|
8723
8864
|
return;
|
|
8724
8865
|
}
|
|
8725
8866
|
stallRecoveryInFlightRef.current = true;
|
|
@@ -8741,12 +8882,12 @@ function useCodingSessionChat({
|
|
|
8741
8882
|
})();
|
|
8742
8883
|
}, 15000);
|
|
8743
8884
|
return () => clearInterval(intervalId);
|
|
8744
|
-
}, [clearError, sendMessage, setMessages, status, stop]);
|
|
8885
|
+
}, [clearError, registerRetryProgress, sendMessage, setMessages, status, stop]);
|
|
8745
8886
|
useEffect(() => {
|
|
8746
8887
|
if (status !== "ready" || error) {
|
|
8747
8888
|
return;
|
|
8748
8889
|
}
|
|
8749
|
-
if (isHistoryLoading || pendingApprovals.length > 0 || pendingUserPrompts.length > 0 || hasUnresolvedToolParts(messages)) {
|
|
8890
|
+
if (taskStuckRef.current || isHistoryLoading || pendingApprovals.length > 0 || pendingUserPrompts.length > 0 || hasUnresolvedToolParts(messages)) {
|
|
8750
8891
|
return;
|
|
8751
8892
|
}
|
|
8752
8893
|
const lastMessage = messages[messages.length - 1];
|
|
@@ -8798,7 +8939,7 @@ function useCodingSessionChat({
|
|
|
8798
8939
|
if (!error?.message || !isRecoverableChatErrorMessage(error.message)) {
|
|
8799
8940
|
return;
|
|
8800
8941
|
}
|
|
8801
|
-
if (pendingApprovals.length > 0 || pendingUserPrompts.length > 0 || errorRetryTimerRef.current || stallRecoveryInFlightRef.current) {
|
|
8942
|
+
if (taskStuckRef.current || pendingApprovals.length > 0 || pendingUserPrompts.length > 0 || errorRetryTimerRef.current || stallRecoveryInFlightRef.current) {
|
|
8802
8943
|
return;
|
|
8803
8944
|
}
|
|
8804
8945
|
if (errorRetriesRef.current >= maxErrorRetriesRef.current) {
|
|
@@ -8809,6 +8950,14 @@ function useCodingSessionChat({
|
|
|
8809
8950
|
const delay = Math.min(errorRetryBaseDelayMs * 2 ** (attempt - 1), errorRetryMaxDelayMs);
|
|
8810
8951
|
errorRetryTimerRef.current = setTimeout(() => {
|
|
8811
8952
|
errorRetryTimerRef.current = null;
|
|
8953
|
+
if (!registerRetryProgress(messagesRef.current)) {
|
|
8954
|
+
setAutoContinueState({
|
|
8955
|
+
attempt: errorRetriesRef.current,
|
|
8956
|
+
kind: "none",
|
|
8957
|
+
guardTripped: "no-progress"
|
|
8958
|
+
});
|
|
8959
|
+
return;
|
|
8960
|
+
}
|
|
8812
8961
|
errorRetriesRef.current = attempt;
|
|
8813
8962
|
setAutoContinueState({ attempt, kind: "retry-error" });
|
|
8814
8963
|
setMessages(retryMessages);
|
|
@@ -8828,6 +8977,7 @@ function useCodingSessionChat({
|
|
|
8828
8977
|
messages,
|
|
8829
8978
|
pendingApprovals.length,
|
|
8830
8979
|
pendingUserPrompts.length,
|
|
8980
|
+
registerRetryProgress,
|
|
8831
8981
|
sendMessage,
|
|
8832
8982
|
setMessages
|
|
8833
8983
|
]);
|
|
@@ -8906,7 +9056,7 @@ function useCodingSessionChat({
|
|
|
8906
9056
|
if (cancelled) {
|
|
8907
9057
|
return;
|
|
8908
9058
|
}
|
|
8909
|
-
const resumableMessages = restoredApprovals.length === 0 && restoredPrompts.length === 0 ?
|
|
9059
|
+
const resumableMessages = restoredApprovals.length === 0 && restoredPrompts.length === 0 ? pruneIncompleteTrailingAssistantParts(validatedMessages) : validatedMessages;
|
|
8910
9060
|
setMessagesRef.current(resumableMessages);
|
|
8911
9061
|
setPendingApprovals(restoredApprovals);
|
|
8912
9062
|
setPendingUserPrompts(restoredPrompts);
|
|
@@ -9027,7 +9177,7 @@ function useCodingSessionChat({
|
|
|
9027
9177
|
isSessionIdValid
|
|
9028
9178
|
};
|
|
9029
9179
|
}
|
|
9030
|
-
var recoverableDisconnectMessage = "Connection interrupted. Please retry or regenerate your last message.", buildModeAutoPromptResponse = "Proceed with implementation in Build mode. Continue without additional plan questions.", chatMessageUpdateThrottleMs = 50, retryCommandPattern, codingToolNameSet, errorRetryBaseDelayMs = 1000, errorRetryMaxDelayMs = 8000, disconnectErrorPattern, transientProviderErrorPattern,
|
|
9180
|
+
var recoverableDisconnectMessage = "Connection interrupted. Please retry or regenerate your last message.", buildModeAutoPromptResponse = "Proceed with implementation in Build mode. Continue without additional plan questions.", chatMessageUpdateThrottleMs = 50, retryCommandPattern, codingToolNameSet, errorRetryBaseDelayMs = 1000, errorRetryMaxDelayMs = 8000, disconnectErrorPattern, transientProviderErrorPattern, terminalToolPartStates;
|
|
9031
9181
|
var init_use_coding_session_chat = __esm(() => {
|
|
9032
9182
|
init_agent_tools();
|
|
9033
9183
|
init_chat_error();
|
|
@@ -9040,6 +9190,7 @@ var init_use_coding_session_chat = __esm(() => {
|
|
|
9040
9190
|
init_schema9();
|
|
9041
9191
|
init_runtime12();
|
|
9042
9192
|
init_auto_continue();
|
|
9193
|
+
init_normalize_provider_messages();
|
|
9043
9194
|
retryCommandPattern = /^\/?(retry|regenerate)$/i;
|
|
9044
9195
|
codingToolNameSet = new Set(Object.keys(codingToolInputSchemas));
|
|
9045
9196
|
disconnectErrorPattern = /(failed to fetch|networkerror|socket|connection|aborted|terminated|timed?\s?out|timeout|econnreset)/i;
|
|
@@ -10156,7 +10307,7 @@ var init_chat_message_tool_invocation_part = __esm(() => {
|
|
|
10156
10307
|
});
|
|
10157
10308
|
|
|
10158
10309
|
// apps/cli/src/components/chat/chat-message.tsx
|
|
10159
|
-
import { isToolUIPart as
|
|
10310
|
+
import { isToolUIPart as isToolUIPart3 } from "ai";
|
|
10160
10311
|
import { TextAttributes as TextAttributes9 } from "@opentui/core";
|
|
10161
10312
|
import { jsxDEV as jsxDEV13 } from "@opentui/react/jsx-dev-runtime";
|
|
10162
10313
|
function ChatMessage({ message, pendingApprovalIds }) {
|
|
@@ -10173,7 +10324,7 @@ function ChatMessage({ message, pendingApprovalIds }) {
|
|
|
10173
10324
|
part
|
|
10174
10325
|
}, key, false, undefined, this);
|
|
10175
10326
|
}
|
|
10176
|
-
if (
|
|
10327
|
+
if (isToolUIPart3(part)) {
|
|
10177
10328
|
return /* @__PURE__ */ jsxDEV13(ChatMessageToolInvocationPart, {
|
|
10178
10329
|
part,
|
|
10179
10330
|
pendingApprovalIds
|
|
@@ -11904,7 +12055,7 @@ function ChatScreen() {
|
|
|
11904
12055
|
paddingX: 1,
|
|
11905
12056
|
children: /* @__PURE__ */ jsxDEV21("text", {
|
|
11906
12057
|
fg: cliTheme.semantic.warning,
|
|
11907
|
-
children: autoContinueState.guardTripped === "doom-loop" ? "Agent appears stuck repeating itself \u2014 automatic continuation stopped. Send a message to resume." : `Reached the automatic continuation limit (${autoContinueState.attempt}). Send a message to resume.`
|
|
12058
|
+
children: autoContinueState.guardTripped === "doom-loop" ? "Agent appears stuck repeating itself \u2014 automatic continuation stopped. Send a message to resume." : autoContinueState.guardTripped === "no-progress" ? "The connection keeps dropping without making progress \u2014 automatic retry stopped. Send a message to resume." : `Reached the automatic continuation limit (${autoContinueState.attempt}). Send a message to resume.`
|
|
11908
12059
|
}, undefined, false, undefined, this)
|
|
11909
12060
|
}, undefined, false, undefined, this) : autoContinueState ? /* @__PURE__ */ jsxDEV21("box", {
|
|
11910
12061
|
paddingX: 1,
|
package/package.json
CHANGED
package/server.js
CHANGED
|
@@ -3201,6 +3201,40 @@ var init_build_provider_view = __esm(() => {
|
|
|
3201
3201
|
init_tier1_prune();
|
|
3202
3202
|
});
|
|
3203
3203
|
|
|
3204
|
+
// packages/ai/src/context/normalize-provider-messages.ts
|
|
3205
|
+
import { isToolUIPart } from "ai";
|
|
3206
|
+
function resolveDanglingToolParts(messages, errorText = interruptedToolErrorText) {
|
|
3207
|
+
return messages.map((message) => {
|
|
3208
|
+
if (message.role !== "assistant") {
|
|
3209
|
+
return message;
|
|
3210
|
+
}
|
|
3211
|
+
let changed = false;
|
|
3212
|
+
const parts = message.parts.map((part) => {
|
|
3213
|
+
if (!isToolUIPart(part) || terminalToolStates.has(part.state)) {
|
|
3214
|
+
return part;
|
|
3215
|
+
}
|
|
3216
|
+
changed = true;
|
|
3217
|
+
return {
|
|
3218
|
+
...part,
|
|
3219
|
+
state: "output-error",
|
|
3220
|
+
errorText
|
|
3221
|
+
};
|
|
3222
|
+
});
|
|
3223
|
+
return changed ? { ...message, parts } : message;
|
|
3224
|
+
});
|
|
3225
|
+
}
|
|
3226
|
+
function normalizeProviderMessages(messages) {
|
|
3227
|
+
return resolveDanglingToolParts(messages);
|
|
3228
|
+
}
|
|
3229
|
+
var terminalToolStates, interruptedToolErrorText = "Tool call was interrupted by a connection retry. Re-issue the tool call if it is still needed.";
|
|
3230
|
+
var init_normalize_provider_messages = __esm(() => {
|
|
3231
|
+
terminalToolStates = new Set([
|
|
3232
|
+
"output-available",
|
|
3233
|
+
"output-error",
|
|
3234
|
+
"output-denied"
|
|
3235
|
+
]);
|
|
3236
|
+
});
|
|
3237
|
+
|
|
3204
3238
|
// packages/ai/src/context/index.ts
|
|
3205
3239
|
var init_context = __esm(() => {
|
|
3206
3240
|
init_build_provider_view();
|
|
@@ -3209,6 +3243,7 @@ var init_context = __esm(() => {
|
|
|
3209
3243
|
init_estimate();
|
|
3210
3244
|
init_heuristic_summary();
|
|
3211
3245
|
init_message_parts();
|
|
3246
|
+
init_normalize_provider_messages();
|
|
3212
3247
|
init_tier1_prune();
|
|
3213
3248
|
});
|
|
3214
3249
|
|
|
@@ -3307,6 +3342,12 @@ function readEnvConfig(env) {
|
|
|
3307
3342
|
summaryMaxChars: parseNumberEnv(env.LIGHTCODE_CONTEXT_SUMMARY_MAX_CHARS, "LIGHTCODE_CONTEXT_SUMMARY_MAX_CHARS")
|
|
3308
3343
|
};
|
|
3309
3344
|
const compactContextConfig = Object.fromEntries(Object.entries(contextConfig).filter(([, value]) => value !== undefined));
|
|
3345
|
+
const headroomConfig = {
|
|
3346
|
+
enabled: parseBooleanEnv(env.LIGHTCODE_HEADROOM_ENABLED, "LIGHTCODE_HEADROOM_ENABLED"),
|
|
3347
|
+
proxyUrl: env.LIGHTCODE_HEADROOM_PROXY_URL?.trim() || undefined,
|
|
3348
|
+
failOpen: parseBooleanEnv(env.LIGHTCODE_HEADROOM_FAIL_OPEN, "LIGHTCODE_HEADROOM_FAIL_OPEN")
|
|
3349
|
+
};
|
|
3350
|
+
const compactHeadroomConfig = Object.fromEntries(Object.entries(headroomConfig).filter(([, value]) => value !== undefined));
|
|
3310
3351
|
const rawConfig = {
|
|
3311
3352
|
provider: env.LIGHTCODE_PROVIDER,
|
|
3312
3353
|
model: env.LIGHTCODE_CHAT_MODEL,
|
|
@@ -3316,7 +3357,8 @@ function readEnvConfig(env) {
|
|
|
3316
3357
|
maxOutputTokens: parseNumberEnv(env.LIGHTCODE_MAX_OUTPUT_TOKENS, "LIGHTCODE_MAX_OUTPUT_TOKENS"),
|
|
3317
3358
|
maxSteps: parseNumberEnv(env.LIGHTCODE_MAX_STEPS, "LIGHTCODE_MAX_STEPS"),
|
|
3318
3359
|
maxRetries: parseNumberEnv(env.LIGHTCODE_MAX_RETRIES, "LIGHTCODE_MAX_RETRIES"),
|
|
3319
|
-
context: Object.keys(compactContextConfig).length > 0 ? compactContextConfig : undefined
|
|
3360
|
+
context: Object.keys(compactContextConfig).length > 0 ? compactContextConfig : undefined,
|
|
3361
|
+
headroom: Object.keys(compactHeadroomConfig).length > 0 ? compactHeadroomConfig : undefined
|
|
3320
3362
|
};
|
|
3321
3363
|
const compactConfig = Object.fromEntries(Object.entries(rawConfig).filter(([, value]) => value !== undefined));
|
|
3322
3364
|
const parsedConfig = lightcodeConfigSchema.safeParse(compactConfig);
|
|
@@ -3340,6 +3382,10 @@ function mergeConfig(...configs) {
|
|
|
3340
3382
|
...mergedConfig.autoContinue,
|
|
3341
3383
|
...config2.autoContinue
|
|
3342
3384
|
} : mergedConfig.autoContinue,
|
|
3385
|
+
headroom: config2.headroom ? {
|
|
3386
|
+
...mergedConfig.headroom,
|
|
3387
|
+
...config2.headroom
|
|
3388
|
+
} : mergedConfig.headroom,
|
|
3343
3389
|
allowedTools: config2.allowedTools ?? mergedConfig.allowedTools
|
|
3344
3390
|
}), {});
|
|
3345
3391
|
}
|
|
@@ -3380,6 +3426,10 @@ function loadLightcodeConfig({
|
|
|
3380
3426
|
autoContinue: {
|
|
3381
3427
|
...defaultAutoContinueConfig,
|
|
3382
3428
|
...mergedConfig.autoContinue
|
|
3429
|
+
},
|
|
3430
|
+
headroom: {
|
|
3431
|
+
...defaultHeadroomConfig,
|
|
3432
|
+
...mergedConfig.headroom
|
|
3383
3433
|
}
|
|
3384
3434
|
};
|
|
3385
3435
|
return lightcodeConfigLoadResultSchema.parse({
|
|
@@ -3387,7 +3437,7 @@ function loadLightcodeConfig({
|
|
|
3387
3437
|
loadedFiles: [userConfig.file, projectConfig.file]
|
|
3388
3438
|
});
|
|
3389
3439
|
}
|
|
3390
|
-
var lightcodeProviderSchema, autoContinueConfigSchema, resolvedAutoContinueConfigSchema, defaultAutoContinueConfig, lightcodeConfigSchema, lightcodeConfigDefaults, loadedConfigFileSchema, lightcodeResolvedConfigSchema, lightcodeConfigLoadResultSchema, lightcodeConfigStatusSchema, LightcodeConfigError;
|
|
3440
|
+
var lightcodeProviderSchema, autoContinueConfigSchema, resolvedAutoContinueConfigSchema, defaultAutoContinueConfig, headroomConfigSchema, resolvedHeadroomConfigSchema, defaultHeadroomConfig, lightcodeConfigSchema, lightcodeConfigDefaults, loadedConfigFileSchema, lightcodeResolvedConfigSchema, lightcodeConfigLoadResultSchema, lightcodeConfigStatusSchema, LightcodeConfigError;
|
|
3391
3441
|
var init_lightcode_config = __esm(() => {
|
|
3392
3442
|
init_coding_agent_modes();
|
|
3393
3443
|
init_coding_agent_modes();
|
|
@@ -3419,6 +3469,24 @@ var init_lightcode_config = __esm(() => {
|
|
|
3419
3469
|
maxErrorRetries: 5,
|
|
3420
3470
|
stallTimeoutSeconds: 180
|
|
3421
3471
|
};
|
|
3472
|
+
headroomConfigSchema = z28.object({
|
|
3473
|
+
enabled: z28.boolean().optional(),
|
|
3474
|
+
proxyUrl: z28.string().min(1).max(4096).optional(),
|
|
3475
|
+
providers: z28.array(lightcodeProviderSchema).optional(),
|
|
3476
|
+
failOpen: z28.boolean().optional()
|
|
3477
|
+
}).strict();
|
|
3478
|
+
resolvedHeadroomConfigSchema = z28.object({
|
|
3479
|
+
enabled: z28.boolean(),
|
|
3480
|
+
proxyUrl: z28.string().min(1).max(4096),
|
|
3481
|
+
providers: z28.array(lightcodeProviderSchema).nullable(),
|
|
3482
|
+
failOpen: z28.boolean()
|
|
3483
|
+
});
|
|
3484
|
+
defaultHeadroomConfig = {
|
|
3485
|
+
enabled: false,
|
|
3486
|
+
proxyUrl: "http://127.0.0.1:8787",
|
|
3487
|
+
providers: null,
|
|
3488
|
+
failOpen: true
|
|
3489
|
+
};
|
|
3422
3490
|
lightcodeConfigSchema = z28.object({
|
|
3423
3491
|
provider: lightcodeProviderSchema.optional(),
|
|
3424
3492
|
model: z28.string().min(1).max(240).optional(),
|
|
@@ -3430,10 +3498,11 @@ var init_lightcode_config = __esm(() => {
|
|
|
3430
3498
|
sandbox: sandboxConfigSchema.optional(),
|
|
3431
3499
|
mcp: mcpConfigSchema.optional(),
|
|
3432
3500
|
context: contextOptimizerConfigSchema.optional(),
|
|
3433
|
-
maxOutputTokens: z28.number().int().min(1).max(
|
|
3501
|
+
maxOutputTokens: z28.number().int().min(1).max(1e6).optional(),
|
|
3434
3502
|
maxSteps: z28.number().int().min(1).max(100).optional(),
|
|
3435
3503
|
maxRetries: z28.number().int().min(0).max(10).optional(),
|
|
3436
|
-
autoContinue: autoContinueConfigSchema.optional()
|
|
3504
|
+
autoContinue: autoContinueConfigSchema.optional(),
|
|
3505
|
+
headroom: headroomConfigSchema.optional()
|
|
3437
3506
|
}).strict();
|
|
3438
3507
|
lightcodeConfigDefaults = {
|
|
3439
3508
|
provider: "anthropic",
|
|
@@ -3442,7 +3511,8 @@ var init_lightcode_config = __esm(() => {
|
|
|
3442
3511
|
maxOutputTokens: 32768,
|
|
3443
3512
|
maxSteps: 30,
|
|
3444
3513
|
maxRetries: 5,
|
|
3445
|
-
autoContinue: defaultAutoContinueConfig
|
|
3514
|
+
autoContinue: defaultAutoContinueConfig,
|
|
3515
|
+
headroom: defaultHeadroomConfig
|
|
3446
3516
|
};
|
|
3447
3517
|
loadedConfigFileSchema = z28.object({
|
|
3448
3518
|
scope: z28.enum(["user", "project"]),
|
|
@@ -3454,10 +3524,11 @@ var init_lightcode_config = __esm(() => {
|
|
|
3454
3524
|
provider: lightcodeProviderSchema,
|
|
3455
3525
|
defaultMode: codingAgentModeSchema,
|
|
3456
3526
|
context: resolvedContextOptimizerConfigSchema,
|
|
3457
|
-
maxOutputTokens: z28.number().int().min(1).max(
|
|
3527
|
+
maxOutputTokens: z28.number().int().min(1).max(1e6),
|
|
3458
3528
|
maxSteps: z28.number().int().min(1).max(100),
|
|
3459
3529
|
maxRetries: z28.number().int().min(0).max(10),
|
|
3460
|
-
autoContinue: resolvedAutoContinueConfigSchema
|
|
3530
|
+
autoContinue: resolvedAutoContinueConfigSchema,
|
|
3531
|
+
headroom: resolvedHeadroomConfigSchema.optional()
|
|
3461
3532
|
});
|
|
3462
3533
|
lightcodeConfigLoadResultSchema = z28.object({
|
|
3463
3534
|
config: lightcodeResolvedConfigSchema,
|
|
@@ -3471,10 +3542,15 @@ var init_lightcode_config = __esm(() => {
|
|
|
3471
3542
|
baseUrl: z28.string().nullable(),
|
|
3472
3543
|
defaultMode: codingAgentModeSchema,
|
|
3473
3544
|
permissionMode: permissionModeSchema.nullable(),
|
|
3474
|
-
maxOutputTokens: z28.number().int().min(1).max(
|
|
3545
|
+
maxOutputTokens: z28.number().int().min(1).max(1e6),
|
|
3475
3546
|
maxSteps: z28.number().int().min(1).max(100),
|
|
3476
3547
|
autoContinue: resolvedAutoContinueConfigSchema,
|
|
3477
3548
|
contextWindow: z28.number().int().positive(),
|
|
3549
|
+
headroom: z28.object({
|
|
3550
|
+
enabled: z28.boolean(),
|
|
3551
|
+
proxyUrl: z28.string().nullable(),
|
|
3552
|
+
routed: z28.boolean()
|
|
3553
|
+
}),
|
|
3478
3554
|
missingCredentialHints: z28.array(z28.string())
|
|
3479
3555
|
});
|
|
3480
3556
|
LightcodeConfigError = class LightcodeConfigError extends Error {
|
|
@@ -3714,6 +3790,21 @@ var init_runtime = __esm(() => {
|
|
|
3714
3790
|
init_schema13();
|
|
3715
3791
|
});
|
|
3716
3792
|
|
|
3793
|
+
// packages/ai/src/providers/clamp-output-tokens.ts
|
|
3794
|
+
function clampMaxOutputTokens(configured, modelMaxCompletionTokens) {
|
|
3795
|
+
if (typeof modelMaxCompletionTokens === "number" && Number.isFinite(modelMaxCompletionTokens) && modelMaxCompletionTokens > 0) {
|
|
3796
|
+
return Math.min(configured, modelMaxCompletionTokens);
|
|
3797
|
+
}
|
|
3798
|
+
return configured;
|
|
3799
|
+
}
|
|
3800
|
+
function resolveMaxOutputTokens(configured, defaultValue, modelMaxCompletionTokens) {
|
|
3801
|
+
const hasModelCap = typeof modelMaxCompletionTokens === "number" && Number.isFinite(modelMaxCompletionTokens) && modelMaxCompletionTokens > 0;
|
|
3802
|
+
if (configured === defaultValue) {
|
|
3803
|
+
return hasModelCap ? modelMaxCompletionTokens : configured;
|
|
3804
|
+
}
|
|
3805
|
+
return clampMaxOutputTokens(configured, modelMaxCompletionTokens);
|
|
3806
|
+
}
|
|
3807
|
+
|
|
3717
3808
|
// packages/ai/src/providers/model-metadata.ts
|
|
3718
3809
|
function getModelContextWindow(provider, modelId) {
|
|
3719
3810
|
if (provider === "anthropic") {
|
|
@@ -6551,6 +6642,9 @@ function summarizeRawModel(raw2) {
|
|
|
6551
6642
|
}
|
|
6552
6643
|
const name = Reflect.get(raw2, "name");
|
|
6553
6644
|
const contextLength = Reflect.get(raw2, "context_length");
|
|
6645
|
+
const topProvider = Reflect.get(raw2, "top_provider");
|
|
6646
|
+
const topProviderMaxCompletion = typeof topProvider === "object" && topProvider !== null ? Reflect.get(topProvider, "max_completion_tokens") : undefined;
|
|
6647
|
+
const rawMaxCompletion = typeof topProviderMaxCompletion === "number" ? topProviderMaxCompletion : Reflect.get(raw2, "max_completion_tokens");
|
|
6554
6648
|
const supportedParameters = Reflect.get(raw2, "supported_parameters");
|
|
6555
6649
|
const parameterList = Array.isArray(supportedParameters) ? supportedParameters.filter((entry) => typeof entry === "string") : [];
|
|
6556
6650
|
const pricingRaw = Reflect.get(raw2, "pricing");
|
|
@@ -6562,6 +6656,7 @@ function summarizeRawModel(raw2) {
|
|
|
6562
6656
|
id,
|
|
6563
6657
|
name: typeof name === "string" && name.length > 0 ? name : id,
|
|
6564
6658
|
contextLength: typeof contextLength === "number" && contextLength > 0 ? Math.round(contextLength) : null,
|
|
6659
|
+
maxCompletionTokens: typeof rawMaxCompletion === "number" && rawMaxCompletion > 0 ? Math.round(rawMaxCompletion) : null,
|
|
6565
6660
|
supportsTools: parameterList.includes("tools"),
|
|
6566
6661
|
supportsReasoning: parameterList.includes("reasoning"),
|
|
6567
6662
|
pricing
|
|
@@ -6611,7 +6706,8 @@ async function getOpenRouterModelCapabilities(modelId) {
|
|
|
6611
6706
|
}
|
|
6612
6707
|
return {
|
|
6613
6708
|
supportsNativeTools: model.supportsTools,
|
|
6614
|
-
contextLength: model.contextLength ?? undefined
|
|
6709
|
+
contextLength: model.contextLength ?? undefined,
|
|
6710
|
+
maxCompletionTokens: model.maxCompletionTokens
|
|
6615
6711
|
};
|
|
6616
6712
|
} catch {
|
|
6617
6713
|
return;
|
|
@@ -6626,6 +6722,7 @@ var init_openrouter_models = __esm(() => {
|
|
|
6626
6722
|
id: z34.string(),
|
|
6627
6723
|
name: z34.string(),
|
|
6628
6724
|
contextLength: z34.number().int().positive().nullable(),
|
|
6725
|
+
maxCompletionTokens: z34.number().int().positive().nullable().default(null),
|
|
6629
6726
|
supportsTools: z34.boolean(),
|
|
6630
6727
|
supportsReasoning: z34.boolean(),
|
|
6631
6728
|
pricing: z34.object({
|
|
@@ -6671,6 +6768,16 @@ function getAnthropicProviderOptions(modelId) {
|
|
|
6671
6768
|
}
|
|
6672
6769
|
};
|
|
6673
6770
|
}
|
|
6771
|
+
function resolveHeadroomRouting(config5, realBaseUrl) {
|
|
6772
|
+
const headroom = config5.headroom;
|
|
6773
|
+
if (!headroom?.enabled) {
|
|
6774
|
+
return { effectiveBaseUrl: realBaseUrl, headroomRouted: false };
|
|
6775
|
+
}
|
|
6776
|
+
if (headroom.providers && !headroom.providers.includes(config5.provider)) {
|
|
6777
|
+
return { effectiveBaseUrl: realBaseUrl, headroomRouted: false };
|
|
6778
|
+
}
|
|
6779
|
+
return { effectiveBaseUrl: headroom.proxyUrl, headroomRouted: true };
|
|
6780
|
+
}
|
|
6674
6781
|
function resolveAnthropicModel({
|
|
6675
6782
|
config: config5,
|
|
6676
6783
|
env,
|
|
@@ -6681,19 +6788,22 @@ function resolveAnthropicModel({
|
|
|
6681
6788
|
const apiKey = getEnvValue(env, "ANTHROPIC_API_KEY") ?? storedCredentials.anthropicApiKey;
|
|
6682
6789
|
const authToken = getEnvValue(env, "ANTHROPIC_AUTH_TOKEN");
|
|
6683
6790
|
const baseUrl = config5.baseUrl ?? getEnvValue(env, "ANTHROPIC_BASE_URL") ?? null;
|
|
6791
|
+
const { effectiveBaseUrl, headroomRouted } = resolveHeadroomRouting(config5, baseUrl);
|
|
6684
6792
|
const missingCredentialHints = apiKey || authToken ? [] : [
|
|
6685
6793
|
"Set ANTHROPIC_API_KEY or ANTHROPIC_AUTH_TOKEN to call Anthropic models."
|
|
6686
6794
|
];
|
|
6687
6795
|
const provider = createAnthropic({
|
|
6688
6796
|
apiKey,
|
|
6689
6797
|
authToken,
|
|
6690
|
-
baseURL:
|
|
6798
|
+
baseURL: effectiveBaseUrl ?? undefined
|
|
6691
6799
|
});
|
|
6692
6800
|
return {
|
|
6693
6801
|
provider: "anthropic",
|
|
6694
6802
|
configuredModel,
|
|
6695
6803
|
resolvedModelId: modelId,
|
|
6696
6804
|
baseUrl,
|
|
6805
|
+
effectiveBaseUrl,
|
|
6806
|
+
headroomRouted,
|
|
6697
6807
|
model: provider(modelId),
|
|
6698
6808
|
providerOptions: getAnthropicProviderOptions(modelId),
|
|
6699
6809
|
contextWindow: getModelContextWindow("anthropic", modelId),
|
|
@@ -6716,6 +6826,7 @@ function resolveOpenAITransportModel({
|
|
|
6716
6826
|
if (!baseUrl) {
|
|
6717
6827
|
throw new Error('OpenAI-compatible provider requires "baseUrl" in config or LIGHTCODE_OPENAI_COMPATIBLE_BASE_URL.');
|
|
6718
6828
|
}
|
|
6829
|
+
const { effectiveBaseUrl, headroomRouted } = resolveHeadroomRouting(config5, baseUrl);
|
|
6719
6830
|
const apiKey = isOpenCodeZen ? getEnvValue(env, "OPENCODE_API_KEY", "LIGHTCODE_OPENAI_COMPATIBLE_API_KEY", "OPENAI_API_KEY") ?? storedCredentials.opencodeApiKey : isOpenRouter ? getEnvValue(env, "OPENROUTER_API_KEY", "LIGHTCODE_OPENAI_COMPATIBLE_API_KEY", "OPENAI_API_KEY") ?? storedCredentials.openrouterApiKey : getEnvValue(env, "LIGHTCODE_OPENAI_COMPATIBLE_API_KEY", "OPENAI_API_KEY") ?? storedCredentials.openaiCompatibleApiKey;
|
|
6720
6831
|
const headers = {};
|
|
6721
6832
|
if (isOpenRouter) {
|
|
@@ -6730,7 +6841,7 @@ function resolveOpenAITransportModel({
|
|
|
6730
6841
|
}
|
|
6731
6842
|
const provider = createOpenAICompatible({
|
|
6732
6843
|
name: config5.provider,
|
|
6733
|
-
baseURL: baseUrl,
|
|
6844
|
+
baseURL: effectiveBaseUrl ?? baseUrl,
|
|
6734
6845
|
apiKey,
|
|
6735
6846
|
headers
|
|
6736
6847
|
});
|
|
@@ -6739,12 +6850,15 @@ function resolveOpenAITransportModel({
|
|
|
6739
6850
|
configuredModel,
|
|
6740
6851
|
resolvedModelId: configuredModel,
|
|
6741
6852
|
baseUrl,
|
|
6853
|
+
effectiveBaseUrl,
|
|
6854
|
+
headroomRouted,
|
|
6742
6855
|
model: withXmlToolCallSupport(provider(configuredModel)),
|
|
6743
6856
|
needsToolCallDiscipline: true,
|
|
6744
6857
|
contextWindow: capabilities?.contextLength ?? getModelContextWindow(config5.provider, configuredModel),
|
|
6745
6858
|
missingCredentialHints: apiKey ? [] : isOpenCodeZen ? ["Set OPENCODE_API_KEY to call OpenCode Zen models."] : isOpenRouter ? ["Set OPENROUTER_API_KEY to call OpenRouter models."] : [
|
|
6746
6859
|
"Set LIGHTCODE_OPENAI_COMPATIBLE_API_KEY or OPENAI_API_KEY if your OpenAI-compatible endpoint requires authentication."
|
|
6747
|
-
]
|
|
6860
|
+
],
|
|
6861
|
+
maxCompletionTokens: capabilities?.maxCompletionTokens ?? null
|
|
6748
6862
|
};
|
|
6749
6863
|
}
|
|
6750
6864
|
function resolveConfiguredProviderModel({
|
|
@@ -6776,13 +6890,18 @@ function createConfigStatus({
|
|
|
6776
6890
|
baseUrl: resolvedProviderModel.baseUrl,
|
|
6777
6891
|
defaultMode: config5.defaultMode,
|
|
6778
6892
|
permissionMode: config5.permissionMode ?? null,
|
|
6779
|
-
maxOutputTokens: config5.maxOutputTokens,
|
|
6893
|
+
maxOutputTokens: resolveMaxOutputTokens(config5.maxOutputTokens, lightcodeConfigDefaults.maxOutputTokens, resolvedProviderModel.maxCompletionTokens),
|
|
6780
6894
|
maxSteps: config5.maxSteps,
|
|
6781
6895
|
autoContinue: config5.autoContinue,
|
|
6782
6896
|
contextWindow: resolveContextWindowTokens({
|
|
6783
6897
|
config: config5.context,
|
|
6784
6898
|
modelContextWindow: resolvedProviderModel.contextWindow
|
|
6785
6899
|
}),
|
|
6900
|
+
headroom: {
|
|
6901
|
+
enabled: config5.headroom?.enabled ?? false,
|
|
6902
|
+
proxyUrl: config5.headroom?.proxyUrl ?? null,
|
|
6903
|
+
routed: resolvedProviderModel.headroomRouted
|
|
6904
|
+
},
|
|
6786
6905
|
missingCredentialHints: resolvedProviderModel.missingCredentialHints
|
|
6787
6906
|
});
|
|
6788
6907
|
}
|
|
@@ -6802,6 +6921,7 @@ __export(exports_runtime_config, {
|
|
|
6802
6921
|
resolvedProviderModel: () => resolvedProviderModel,
|
|
6803
6922
|
lightcodeConfigResult: () => lightcodeConfigResult,
|
|
6804
6923
|
initializeModelCapabilities: () => initializeModelCapabilities,
|
|
6924
|
+
disableHeadroomRouting: () => disableHeadroomRouting,
|
|
6805
6925
|
configStatus: () => configStatus,
|
|
6806
6926
|
codingAgent: () => codingAgent,
|
|
6807
6927
|
chatModelId: () => chatModelId,
|
|
@@ -6814,7 +6934,7 @@ function buildCodingAgent(config5, model) {
|
|
|
6814
6934
|
providerOptions: model.providerOptions,
|
|
6815
6935
|
maxSteps: config5.maxSteps,
|
|
6816
6936
|
maxRetries: config5.maxRetries,
|
|
6817
|
-
maxOutputTokens: config5.maxOutputTokens,
|
|
6937
|
+
maxOutputTokens: resolveMaxOutputTokens(config5.maxOutputTokens, lightcodeConfigDefaults.maxOutputTokens, model.maxCompletionTokens),
|
|
6818
6938
|
includeToolDiscipline: model.needsToolCallDiscipline ?? false
|
|
6819
6939
|
});
|
|
6820
6940
|
}
|
|
@@ -6859,6 +6979,39 @@ function applyModelSelection({
|
|
|
6859
6979
|
});
|
|
6860
6980
|
return configStatus;
|
|
6861
6981
|
}
|
|
6982
|
+
function disableHeadroomRouting() {
|
|
6983
|
+
if (!lightcodeConfigResult.config.headroom?.enabled) {
|
|
6984
|
+
return;
|
|
6985
|
+
}
|
|
6986
|
+
const nextConfig = {
|
|
6987
|
+
...lightcodeConfigResult.config,
|
|
6988
|
+
headroom: {
|
|
6989
|
+
...lightcodeConfigResult.config.headroom ?? lightcodeConfigDefaults.headroom,
|
|
6990
|
+
enabled: false
|
|
6991
|
+
}
|
|
6992
|
+
};
|
|
6993
|
+
const nextResolved = resolveConfiguredProviderModel({
|
|
6994
|
+
config: nextConfig,
|
|
6995
|
+
env: Bun.env
|
|
6996
|
+
});
|
|
6997
|
+
const nextAgent = buildCodingAgent(nextConfig, nextResolved);
|
|
6998
|
+
lightcodeConfigResult = {
|
|
6999
|
+
...lightcodeConfigResult,
|
|
7000
|
+
config: nextConfig
|
|
7001
|
+
};
|
|
7002
|
+
resolvedProviderModel = nextResolved;
|
|
7003
|
+
chatModelId = nextResolved.resolvedModelId;
|
|
7004
|
+
codingAgent = nextAgent;
|
|
7005
|
+
configStatus = createConfigStatus({
|
|
7006
|
+
config: nextConfig,
|
|
7007
|
+
loadedFiles: lightcodeConfigResult.loadedFiles,
|
|
7008
|
+
resolvedProviderModel: nextResolved
|
|
7009
|
+
});
|
|
7010
|
+
logger5.info("headroom_routing_disabled", {
|
|
7011
|
+
provider: nextResolved.provider,
|
|
7012
|
+
model: nextResolved.resolvedModelId
|
|
7013
|
+
});
|
|
7014
|
+
}
|
|
6862
7015
|
async function initializeModelCapabilities() {
|
|
6863
7016
|
if (lightcodeConfigResult.config.provider !== "openrouter") {
|
|
6864
7017
|
return;
|
|
@@ -7171,7 +7324,7 @@ async function streamSessionChat(c, sessionIdentifier, messagesPayload, cwd, mod
|
|
|
7171
7324
|
});
|
|
7172
7325
|
}
|
|
7173
7326
|
}
|
|
7174
|
-
const providerMessages = view.providerMessages;
|
|
7327
|
+
const providerMessages = normalizeProviderMessages(view.providerMessages);
|
|
7175
7328
|
let overflowNotedThisRequest = false;
|
|
7176
7329
|
const noteOverflowForSession = () => {
|
|
7177
7330
|
if (overflowNotedThisRequest) {
|
|
@@ -8228,9 +8381,62 @@ var init_app = __esm(() => {
|
|
|
8228
8381
|
})).route("/", rootRoutes).route("/config", configRoutes).route("/diagnostics", diagnosticsRoutes).route("/extensions", extensionRoutes).route("/sessions", sessionRoutes);
|
|
8229
8382
|
});
|
|
8230
8383
|
|
|
8384
|
+
// apps/server/src/lib/headroom-proxy.ts
|
|
8385
|
+
var exports_headroom_proxy = {};
|
|
8386
|
+
__export(exports_headroom_proxy, {
|
|
8387
|
+
ensureHeadroomRouting: () => ensureHeadroomRouting,
|
|
8388
|
+
checkHeadroomHealth: () => checkHeadroomHealth
|
|
8389
|
+
});
|
|
8390
|
+
async function checkHeadroomHealth(proxyUrl) {
|
|
8391
|
+
try {
|
|
8392
|
+
await fetch(new URL("/health", proxyUrl), {
|
|
8393
|
+
signal: AbortSignal.timeout(healthCheckTimeoutMs)
|
|
8394
|
+
});
|
|
8395
|
+
return "healthy";
|
|
8396
|
+
} catch {
|
|
8397
|
+
return "down";
|
|
8398
|
+
}
|
|
8399
|
+
}
|
|
8400
|
+
async function ensureHeadroomRouting() {
|
|
8401
|
+
const headroom = lightcodeConfigResult.config.headroom;
|
|
8402
|
+
if (!headroom?.enabled) {
|
|
8403
|
+
return;
|
|
8404
|
+
}
|
|
8405
|
+
let health;
|
|
8406
|
+
try {
|
|
8407
|
+
health = await checkHeadroomHealth(headroom.proxyUrl);
|
|
8408
|
+
} catch (error) {
|
|
8409
|
+
health = "down";
|
|
8410
|
+
logger9.warn("headroom_health_probe_failed", {
|
|
8411
|
+
proxyUrl: headroom.proxyUrl,
|
|
8412
|
+
error: getErrorMessage(error)
|
|
8413
|
+
});
|
|
8414
|
+
}
|
|
8415
|
+
if (health === "healthy") {
|
|
8416
|
+
logger9.info("headroom_routing_active", { proxyUrl: headroom.proxyUrl });
|
|
8417
|
+
return;
|
|
8418
|
+
}
|
|
8419
|
+
if (headroom.failOpen) {
|
|
8420
|
+
logger9.warn("headroom_unreachable_failing_open", {
|
|
8421
|
+
proxyUrl: headroom.proxyUrl
|
|
8422
|
+
});
|
|
8423
|
+
disableHeadroomRouting();
|
|
8424
|
+
return;
|
|
8425
|
+
}
|
|
8426
|
+
logger9.error("headroom_unreachable_fail_closed", {
|
|
8427
|
+
proxyUrl: headroom.proxyUrl
|
|
8428
|
+
});
|
|
8429
|
+
}
|
|
8430
|
+
var logger9, healthCheckTimeoutMs = 1500;
|
|
8431
|
+
var init_headroom_proxy = __esm(() => {
|
|
8432
|
+
init_src();
|
|
8433
|
+
init_runtime_config();
|
|
8434
|
+
logger9 = createLogger("headroom-proxy");
|
|
8435
|
+
});
|
|
8436
|
+
|
|
8231
8437
|
// apps/server/src/index.ts
|
|
8232
8438
|
init_src();
|
|
8233
|
-
var
|
|
8439
|
+
var logger10 = createLogger("server");
|
|
8234
8440
|
var httpIdleTimeoutSeconds = 30;
|
|
8235
8441
|
var shutdownForceExitMs = 5000;
|
|
8236
8442
|
function isChatStreamingRoute(request) {
|
|
@@ -8243,7 +8449,7 @@ function isChatStreamingRoute(request) {
|
|
|
8243
8449
|
async function startServer() {
|
|
8244
8450
|
const logDirectory = enableFileLogSink(Bun.env);
|
|
8245
8451
|
if (logDirectory) {
|
|
8246
|
-
|
|
8452
|
+
logger10.info("file_log_sink_enabled", { directory: logDirectory });
|
|
8247
8453
|
}
|
|
8248
8454
|
const port = Number(Bun.env.PORT ?? 4983);
|
|
8249
8455
|
const hostname = Bun.env.LIGHTCODE_HOST ?? "127.0.0.1";
|
|
@@ -8264,7 +8470,12 @@ async function startServer() {
|
|
|
8264
8470
|
process.exit(1);
|
|
8265
8471
|
}
|
|
8266
8472
|
Promise.resolve().then(() => (init_runtime_config(), exports_runtime_config)).then((runtime19) => runtime19.initializeModelCapabilities()).catch((error) => {
|
|
8267
|
-
|
|
8473
|
+
logger10.warn("model_capability_init_failed", {
|
|
8474
|
+
error: getErrorMessage(error)
|
|
8475
|
+
});
|
|
8476
|
+
});
|
|
8477
|
+
Promise.resolve().then(() => (init_headroom_proxy(), exports_headroom_proxy)).then((headroom) => headroom.ensureHeadroomRouting()).catch((error) => {
|
|
8478
|
+
logger10.warn("headroom_init_failed", {
|
|
8268
8479
|
error: getErrorMessage(error)
|
|
8269
8480
|
});
|
|
8270
8481
|
});
|
|
@@ -8300,7 +8511,7 @@ async function startServer() {
|
|
|
8300
8511
|
return;
|
|
8301
8512
|
}
|
|
8302
8513
|
shuttingDown = true;
|
|
8303
|
-
|
|
8514
|
+
logger10.info("server_shutdown", { signal });
|
|
8304
8515
|
const forceExitTimer = setTimeout(() => {
|
|
8305
8516
|
server.stop(true);
|
|
8306
8517
|
process.exit(0);
|