@kody-ade/kody-engine-lite 0.1.58 → 0.1.59
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bin/cli.js +84 -41
- package/kody.config.schema.json +6 -1
- package/package.json +1 -1
package/dist/bin/cli.js
CHANGED
|
@@ -252,6 +252,17 @@ var init_logger = __esm({
|
|
|
252
252
|
// src/config.ts
|
|
253
253
|
import * as fs from "fs";
|
|
254
254
|
import * as path from "path";
|
|
255
|
+
function needsLitellmProxy(config) {
|
|
256
|
+
if (config.agent.litellmUrl) return true;
|
|
257
|
+
if (config.agent.provider && config.agent.provider !== "anthropic") return true;
|
|
258
|
+
return false;
|
|
259
|
+
}
|
|
260
|
+
function getLitellmUrl(config) {
|
|
261
|
+
return config.agent.litellmUrl ?? LITELLM_DEFAULT_URL;
|
|
262
|
+
}
|
|
263
|
+
function providerApiKeyEnvVar(provider) {
|
|
264
|
+
return `${provider.toUpperCase()}_API_KEY`;
|
|
265
|
+
}
|
|
255
266
|
function setConfigDir(dir) {
|
|
256
267
|
_configDir = dir;
|
|
257
268
|
_config = null;
|
|
@@ -279,7 +290,7 @@ function getProjectConfig() {
|
|
|
279
290
|
}
|
|
280
291
|
return _config;
|
|
281
292
|
}
|
|
282
|
-
var DEFAULT_CONFIG, VERIFY_COMMAND_TIMEOUT_MS, FIX_COMMAND_TIMEOUT_MS, _config, _configDir;
|
|
293
|
+
var DEFAULT_CONFIG, LITELLM_DEFAULT_PORT, LITELLM_DEFAULT_URL, TIER_TO_ANTHROPIC_IDS, VERIFY_COMMAND_TIMEOUT_MS, FIX_COMMAND_TIMEOUT_MS, _config, _configDir;
|
|
283
294
|
var init_config = __esm({
|
|
284
295
|
"src/config.ts"() {
|
|
285
296
|
"use strict";
|
|
@@ -313,6 +324,13 @@ var init_config = __esm({
|
|
|
313
324
|
tokenBudget: 8e3
|
|
314
325
|
}
|
|
315
326
|
};
|
|
327
|
+
LITELLM_DEFAULT_PORT = 4e3;
|
|
328
|
+
LITELLM_DEFAULT_URL = `http://localhost:${LITELLM_DEFAULT_PORT}`;
|
|
329
|
+
TIER_TO_ANTHROPIC_IDS = {
|
|
330
|
+
cheap: ["claude-haiku-4-5-20251001", "claude-haiku-4-5", "haiku"],
|
|
331
|
+
mid: ["claude-sonnet-4-6-20250514", "claude-sonnet-4-6", "sonnet"],
|
|
332
|
+
strong: ["claude-opus-4-6-20250514", "claude-opus-4-6", "opus"]
|
|
333
|
+
};
|
|
316
334
|
VERIFY_COMMAND_TIMEOUT_MS = 5 * 60 * 1e3;
|
|
317
335
|
FIX_COMMAND_TIMEOUT_MS = 2 * 60 * 1e3;
|
|
318
336
|
_config = null;
|
|
@@ -1350,8 +1368,8 @@ async function executeAgentStage(ctx, def) {
|
|
|
1350
1368
|
const runnerName = config.agent.stageRunners?.[def.name] ?? config.agent.defaultRunner ?? Object.keys(ctx.runners)[0] ?? "claude";
|
|
1351
1369
|
logger.info(` runner=${runnerName} model=${model} timeout=${def.timeout / 1e3}s`);
|
|
1352
1370
|
const extraEnv = {};
|
|
1353
|
-
if (config
|
|
1354
|
-
extraEnv.ANTHROPIC_BASE_URL = config
|
|
1371
|
+
if (needsLitellmProxy(config)) {
|
|
1372
|
+
extraEnv.ANTHROPIC_BASE_URL = getLitellmUrl(config);
|
|
1355
1373
|
}
|
|
1356
1374
|
const sessions = ctx.sessions ?? {};
|
|
1357
1375
|
const sessionInfo = getSessionInfo(def.name, sessions);
|
|
@@ -3072,6 +3090,7 @@ var init_args = __esm({
|
|
|
3072
3090
|
|
|
3073
3091
|
// src/cli/litellm.ts
|
|
3074
3092
|
import * as fs19 from "fs";
|
|
3093
|
+
import * as os from "os";
|
|
3075
3094
|
import * as path18 from "path";
|
|
3076
3095
|
import { execFileSync as execFileSync10 } from "child_process";
|
|
3077
3096
|
async function checkLitellmHealth(url) {
|
|
@@ -3082,10 +3101,31 @@ async function checkLitellmHealth(url) {
|
|
|
3082
3101
|
return false;
|
|
3083
3102
|
}
|
|
3084
3103
|
}
|
|
3085
|
-
|
|
3086
|
-
const
|
|
3087
|
-
|
|
3088
|
-
|
|
3104
|
+
function generateLitellmConfig(provider, modelMap) {
|
|
3105
|
+
const apiKeyVar = providerApiKeyEnvVar(provider);
|
|
3106
|
+
const entries = ["model_list:"];
|
|
3107
|
+
for (const [tier, providerModel] of Object.entries(modelMap)) {
|
|
3108
|
+
const anthropicIds = TIER_TO_ANTHROPIC_IDS[tier];
|
|
3109
|
+
if (!anthropicIds) continue;
|
|
3110
|
+
for (const modelName of anthropicIds) {
|
|
3111
|
+
entries.push(` - model_name: ${modelName}`);
|
|
3112
|
+
entries.push(` litellm_params:`);
|
|
3113
|
+
entries.push(` model: ${provider}/${providerModel}`);
|
|
3114
|
+
entries.push(` api_key: os.environ/${apiKeyVar}`);
|
|
3115
|
+
}
|
|
3116
|
+
}
|
|
3117
|
+
return entries.join("\n") + "\n";
|
|
3118
|
+
}
|
|
3119
|
+
async function tryStartLitellm(url, projectDir, generatedConfig) {
|
|
3120
|
+
const manualConfigPath = path18.join(projectDir, "litellm-config.yaml");
|
|
3121
|
+
let configPath;
|
|
3122
|
+
if (fs19.existsSync(manualConfigPath)) {
|
|
3123
|
+
configPath = manualConfigPath;
|
|
3124
|
+
} else if (generatedConfig) {
|
|
3125
|
+
configPath = path18.join(os.tmpdir(), "kody-litellm-config.yaml");
|
|
3126
|
+
fs19.writeFileSync(configPath, generatedConfig);
|
|
3127
|
+
} else {
|
|
3128
|
+
logger.warn("litellm-config.yaml not found and no provider configured \u2014 cannot start proxy");
|
|
3089
3129
|
return null;
|
|
3090
3130
|
}
|
|
3091
3131
|
const portMatch = url.match(/:(\d+)/);
|
|
@@ -3155,6 +3195,7 @@ var init_litellm = __esm({
|
|
|
3155
3195
|
"src/cli/litellm.ts"() {
|
|
3156
3196
|
"use strict";
|
|
3157
3197
|
init_logger();
|
|
3198
|
+
init_config();
|
|
3158
3199
|
}
|
|
3159
3200
|
});
|
|
3160
3201
|
|
|
@@ -3228,6 +3269,38 @@ var init_task_state = __esm({
|
|
|
3228
3269
|
var entry_exports = {};
|
|
3229
3270
|
import * as fs21 from "fs";
|
|
3230
3271
|
import * as path20 from "path";
|
|
3272
|
+
async function ensureLitellmProxy(config, projectDir) {
|
|
3273
|
+
if (!needsLitellmProxy(config)) return null;
|
|
3274
|
+
const litellmUrl = getLitellmUrl(config);
|
|
3275
|
+
const proxyRunning = await checkLitellmHealth(litellmUrl);
|
|
3276
|
+
let litellmProcess = null;
|
|
3277
|
+
if (!proxyRunning) {
|
|
3278
|
+
if (config.agent.provider && config.agent.provider !== "anthropic") {
|
|
3279
|
+
const keyVar = providerApiKeyEnvVar(config.agent.provider);
|
|
3280
|
+
if (!process.env[keyVar]) {
|
|
3281
|
+
logger.error(`Provider '${config.agent.provider}' requires ${keyVar} environment variable`);
|
|
3282
|
+
process.exit(1);
|
|
3283
|
+
}
|
|
3284
|
+
}
|
|
3285
|
+
let generatedConfig;
|
|
3286
|
+
if (config.agent.provider && config.agent.provider !== "anthropic") {
|
|
3287
|
+
generatedConfig = generateLitellmConfig(config.agent.provider, config.agent.modelMap);
|
|
3288
|
+
}
|
|
3289
|
+
litellmProcess = await tryStartLitellm(litellmUrl, projectDir, generatedConfig);
|
|
3290
|
+
if (!litellmProcess) {
|
|
3291
|
+
logger.error("LiteLLM is configured but could not be started. Install it with: pip install 'litellm[proxy]'");
|
|
3292
|
+
process.exit(1);
|
|
3293
|
+
}
|
|
3294
|
+
} else {
|
|
3295
|
+
logger.info(`LiteLLM proxy already running at ${litellmUrl}`);
|
|
3296
|
+
}
|
|
3297
|
+
process.env.ANTHROPIC_BASE_URL = litellmUrl;
|
|
3298
|
+
logger.info(`ANTHROPIC_BASE_URL set to ${litellmUrl}`);
|
|
3299
|
+
if (!process.env.ANTHROPIC_API_KEY || !process.env.ANTHROPIC_API_KEY.startsWith("sk-ant-")) {
|
|
3300
|
+
process.env.ANTHROPIC_API_KEY = "sk-ant-api03-litellm-proxy-key-00000000000000000000000000000000000000000000000000000000000000000000";
|
|
3301
|
+
}
|
|
3302
|
+
return litellmProcess;
|
|
3303
|
+
}
|
|
3231
3304
|
async function main() {
|
|
3232
3305
|
const input = parseArgs();
|
|
3233
3306
|
const projectDir = input.cwd ? path20.resolve(input.cwd) : process.cwd();
|
|
@@ -3320,21 +3393,7 @@ async function main() {
|
|
|
3320
3393
|
}
|
|
3321
3394
|
}
|
|
3322
3395
|
const config2 = getProjectConfig();
|
|
3323
|
-
|
|
3324
|
-
if (config2.agent.litellmUrl) {
|
|
3325
|
-
const proxyRunning = await checkLitellmHealth(config2.agent.litellmUrl);
|
|
3326
|
-
if (!proxyRunning) {
|
|
3327
|
-
litellmProcess2 = await tryStartLitellm(config2.agent.litellmUrl, projectDir);
|
|
3328
|
-
if (!litellmProcess2) {
|
|
3329
|
-
logger.error("LiteLLM is configured (litellmUrl) but could not be started. Install it with: pip install 'litellm[proxy]'");
|
|
3330
|
-
process.exit(1);
|
|
3331
|
-
}
|
|
3332
|
-
}
|
|
3333
|
-
process.env.ANTHROPIC_BASE_URL = config2.agent.litellmUrl;
|
|
3334
|
-
if (!process.env.ANTHROPIC_API_KEY || !process.env.ANTHROPIC_API_KEY.startsWith("sk-ant-")) {
|
|
3335
|
-
process.env.ANTHROPIC_API_KEY = "sk-ant-api03-litellm-proxy-key-00000000000000000000000000000000000000000000000000000000000000000000";
|
|
3336
|
-
}
|
|
3337
|
-
}
|
|
3396
|
+
const litellmProcess2 = await ensureLitellmProxy(config2, projectDir);
|
|
3338
3397
|
const runners2 = createRunners(config2);
|
|
3339
3398
|
const defaultRunnerName2 = config2.agent.defaultRunner ?? Object.keys(runners2)[0] ?? "claude";
|
|
3340
3399
|
const defaultRunner2 = runners2[defaultRunnerName2];
|
|
@@ -3424,10 +3483,10 @@ ${input.feedback}` : reviewContext;
|
|
|
3424
3483
|
}
|
|
3425
3484
|
}
|
|
3426
3485
|
const config = getProjectConfig();
|
|
3427
|
-
let litellmProcess =
|
|
3486
|
+
let litellmProcess = await ensureLitellmProxy(config, projectDir);
|
|
3428
3487
|
const cleanupLitellm = () => {
|
|
3429
3488
|
if (litellmProcess) {
|
|
3430
|
-
litellmProcess.kill();
|
|
3489
|
+
litellmProcess.kill?.();
|
|
3431
3490
|
litellmProcess = null;
|
|
3432
3491
|
}
|
|
3433
3492
|
};
|
|
@@ -3440,23 +3499,6 @@ ${input.feedback}` : reviewContext;
|
|
|
3440
3499
|
cleanupLitellm();
|
|
3441
3500
|
process.exit(143);
|
|
3442
3501
|
});
|
|
3443
|
-
if (config.agent.litellmUrl) {
|
|
3444
|
-
const proxyRunning = await checkLitellmHealth(config.agent.litellmUrl);
|
|
3445
|
-
if (!proxyRunning) {
|
|
3446
|
-
litellmProcess = await tryStartLitellm(config.agent.litellmUrl, projectDir);
|
|
3447
|
-
if (!litellmProcess) {
|
|
3448
|
-
logger.error("LiteLLM is configured (litellmUrl) but could not be started. Install it with: pip install 'litellm[proxy]'");
|
|
3449
|
-
process.exit(1);
|
|
3450
|
-
}
|
|
3451
|
-
} else {
|
|
3452
|
-
logger.info(`LiteLLM proxy already running at ${config.agent.litellmUrl}`);
|
|
3453
|
-
}
|
|
3454
|
-
process.env.ANTHROPIC_BASE_URL = config.agent.litellmUrl;
|
|
3455
|
-
logger.info(`ANTHROPIC_BASE_URL set to ${config.agent.litellmUrl}`);
|
|
3456
|
-
if (!process.env.ANTHROPIC_API_KEY || !process.env.ANTHROPIC_API_KEY.startsWith("sk-ant-")) {
|
|
3457
|
-
process.env.ANTHROPIC_API_KEY = "sk-ant-api03-litellm-proxy-key-00000000000000000000000000000000000000000000000000000000000000000000";
|
|
3458
|
-
}
|
|
3459
|
-
}
|
|
3460
3502
|
const runners = createRunners(config);
|
|
3461
3503
|
const defaultRunnerName = config.agent.defaultRunner ?? Object.keys(runners)[0] ?? "claude";
|
|
3462
3504
|
const defaultRunner = runners[defaultRunnerName];
|
|
@@ -3548,6 +3590,7 @@ var init_entry = __esm({
|
|
|
3548
3590
|
init_litellm();
|
|
3549
3591
|
init_task_resolution();
|
|
3550
3592
|
init_task_state();
|
|
3593
|
+
init_config();
|
|
3551
3594
|
main().catch(async (err) => {
|
|
3552
3595
|
const msg = err instanceof Error ? err.message : String(err);
|
|
3553
3596
|
console.error(msg);
|
package/kody.config.schema.json
CHANGED
|
@@ -125,9 +125,14 @@
|
|
|
125
125
|
},
|
|
126
126
|
"additionalProperties": false
|
|
127
127
|
},
|
|
128
|
+
"provider": {
|
|
129
|
+
"type": "string",
|
|
130
|
+
"description": "LLM provider name. When set (and not 'anthropic'), engine auto-starts LiteLLM proxy and routes model calls to this provider. modelMap values should be the provider's model names.",
|
|
131
|
+
"examples": ["anthropic", "minimax", "openai", "google"]
|
|
132
|
+
},
|
|
128
133
|
"litellmUrl": {
|
|
129
134
|
"type": "string",
|
|
130
|
-
"description": "
|
|
135
|
+
"description": "(Deprecated) Use 'provider' instead. LiteLLM proxy URL for manual setup.",
|
|
131
136
|
"examples": ["http://localhost:4000"]
|
|
132
137
|
},
|
|
133
138
|
"usePerStageRouting": {
|