@kody-ade/kody-engine-lite 0.1.58 → 0.1.60
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 +87 -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;
|
|
@@ -1223,6 +1241,9 @@ function resolveModel(modelTier, stageName) {
|
|
|
1223
1241
|
if (config.agent.usePerStageRouting && stageName) {
|
|
1224
1242
|
return stageName;
|
|
1225
1243
|
}
|
|
1244
|
+
if (config.agent.provider && config.agent.provider !== "anthropic") {
|
|
1245
|
+
return DEFAULT_MODEL_MAP[modelTier] ?? "sonnet";
|
|
1246
|
+
}
|
|
1226
1247
|
const mapped = config.agent.modelMap[modelTier];
|
|
1227
1248
|
if (mapped) return mapped;
|
|
1228
1249
|
return DEFAULT_MODEL_MAP[modelTier] ?? "sonnet";
|
|
@@ -1350,8 +1371,8 @@ async function executeAgentStage(ctx, def) {
|
|
|
1350
1371
|
const runnerName = config.agent.stageRunners?.[def.name] ?? config.agent.defaultRunner ?? Object.keys(ctx.runners)[0] ?? "claude";
|
|
1351
1372
|
logger.info(` runner=${runnerName} model=${model} timeout=${def.timeout / 1e3}s`);
|
|
1352
1373
|
const extraEnv = {};
|
|
1353
|
-
if (config
|
|
1354
|
-
extraEnv.ANTHROPIC_BASE_URL = config
|
|
1374
|
+
if (needsLitellmProxy(config)) {
|
|
1375
|
+
extraEnv.ANTHROPIC_BASE_URL = getLitellmUrl(config);
|
|
1355
1376
|
}
|
|
1356
1377
|
const sessions = ctx.sessions ?? {};
|
|
1357
1378
|
const sessionInfo = getSessionInfo(def.name, sessions);
|
|
@@ -3072,6 +3093,7 @@ var init_args = __esm({
|
|
|
3072
3093
|
|
|
3073
3094
|
// src/cli/litellm.ts
|
|
3074
3095
|
import * as fs19 from "fs";
|
|
3096
|
+
import * as os from "os";
|
|
3075
3097
|
import * as path18 from "path";
|
|
3076
3098
|
import { execFileSync as execFileSync10 } from "child_process";
|
|
3077
3099
|
async function checkLitellmHealth(url) {
|
|
@@ -3082,10 +3104,31 @@ async function checkLitellmHealth(url) {
|
|
|
3082
3104
|
return false;
|
|
3083
3105
|
}
|
|
3084
3106
|
}
|
|
3085
|
-
|
|
3086
|
-
const
|
|
3087
|
-
|
|
3088
|
-
|
|
3107
|
+
function generateLitellmConfig(provider, modelMap) {
|
|
3108
|
+
const apiKeyVar = providerApiKeyEnvVar(provider);
|
|
3109
|
+
const entries = ["model_list:"];
|
|
3110
|
+
for (const [tier, providerModel] of Object.entries(modelMap)) {
|
|
3111
|
+
const anthropicIds = TIER_TO_ANTHROPIC_IDS[tier];
|
|
3112
|
+
if (!anthropicIds) continue;
|
|
3113
|
+
for (const modelName of anthropicIds) {
|
|
3114
|
+
entries.push(` - model_name: ${modelName}`);
|
|
3115
|
+
entries.push(` litellm_params:`);
|
|
3116
|
+
entries.push(` model: ${provider}/${providerModel}`);
|
|
3117
|
+
entries.push(` api_key: os.environ/${apiKeyVar}`);
|
|
3118
|
+
}
|
|
3119
|
+
}
|
|
3120
|
+
return entries.join("\n") + "\n";
|
|
3121
|
+
}
|
|
3122
|
+
async function tryStartLitellm(url, projectDir, generatedConfig) {
|
|
3123
|
+
const manualConfigPath = path18.join(projectDir, "litellm-config.yaml");
|
|
3124
|
+
let configPath;
|
|
3125
|
+
if (fs19.existsSync(manualConfigPath)) {
|
|
3126
|
+
configPath = manualConfigPath;
|
|
3127
|
+
} else if (generatedConfig) {
|
|
3128
|
+
configPath = path18.join(os.tmpdir(), "kody-litellm-config.yaml");
|
|
3129
|
+
fs19.writeFileSync(configPath, generatedConfig);
|
|
3130
|
+
} else {
|
|
3131
|
+
logger.warn("litellm-config.yaml not found and no provider configured \u2014 cannot start proxy");
|
|
3089
3132
|
return null;
|
|
3090
3133
|
}
|
|
3091
3134
|
const portMatch = url.match(/:(\d+)/);
|
|
@@ -3155,6 +3198,7 @@ var init_litellm = __esm({
|
|
|
3155
3198
|
"src/cli/litellm.ts"() {
|
|
3156
3199
|
"use strict";
|
|
3157
3200
|
init_logger();
|
|
3201
|
+
init_config();
|
|
3158
3202
|
}
|
|
3159
3203
|
});
|
|
3160
3204
|
|
|
@@ -3228,6 +3272,38 @@ var init_task_state = __esm({
|
|
|
3228
3272
|
var entry_exports = {};
|
|
3229
3273
|
import * as fs21 from "fs";
|
|
3230
3274
|
import * as path20 from "path";
|
|
3275
|
+
async function ensureLitellmProxy(config, projectDir) {
|
|
3276
|
+
if (!needsLitellmProxy(config)) return null;
|
|
3277
|
+
const litellmUrl = getLitellmUrl(config);
|
|
3278
|
+
const proxyRunning = await checkLitellmHealth(litellmUrl);
|
|
3279
|
+
let litellmProcess = null;
|
|
3280
|
+
if (!proxyRunning) {
|
|
3281
|
+
if (config.agent.provider && config.agent.provider !== "anthropic") {
|
|
3282
|
+
const keyVar = providerApiKeyEnvVar(config.agent.provider);
|
|
3283
|
+
if (!process.env[keyVar]) {
|
|
3284
|
+
logger.error(`Provider '${config.agent.provider}' requires ${keyVar} environment variable`);
|
|
3285
|
+
process.exit(1);
|
|
3286
|
+
}
|
|
3287
|
+
}
|
|
3288
|
+
let generatedConfig;
|
|
3289
|
+
if (config.agent.provider && config.agent.provider !== "anthropic") {
|
|
3290
|
+
generatedConfig = generateLitellmConfig(config.agent.provider, config.agent.modelMap);
|
|
3291
|
+
}
|
|
3292
|
+
litellmProcess = await tryStartLitellm(litellmUrl, projectDir, generatedConfig);
|
|
3293
|
+
if (!litellmProcess) {
|
|
3294
|
+
logger.error("LiteLLM is configured but could not be started. Install it with: pip install 'litellm[proxy]'");
|
|
3295
|
+
process.exit(1);
|
|
3296
|
+
}
|
|
3297
|
+
} else {
|
|
3298
|
+
logger.info(`LiteLLM proxy already running at ${litellmUrl}`);
|
|
3299
|
+
}
|
|
3300
|
+
process.env.ANTHROPIC_BASE_URL = litellmUrl;
|
|
3301
|
+
logger.info(`ANTHROPIC_BASE_URL set to ${litellmUrl}`);
|
|
3302
|
+
if (!process.env.ANTHROPIC_API_KEY || !process.env.ANTHROPIC_API_KEY.startsWith("sk-ant-")) {
|
|
3303
|
+
process.env.ANTHROPIC_API_KEY = "sk-ant-api03-litellm-proxy-key-00000000000000000000000000000000000000000000000000000000000000000000";
|
|
3304
|
+
}
|
|
3305
|
+
return litellmProcess;
|
|
3306
|
+
}
|
|
3231
3307
|
async function main() {
|
|
3232
3308
|
const input = parseArgs();
|
|
3233
3309
|
const projectDir = input.cwd ? path20.resolve(input.cwd) : process.cwd();
|
|
@@ -3320,21 +3396,7 @@ async function main() {
|
|
|
3320
3396
|
}
|
|
3321
3397
|
}
|
|
3322
3398
|
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
|
-
}
|
|
3399
|
+
const litellmProcess2 = await ensureLitellmProxy(config2, projectDir);
|
|
3338
3400
|
const runners2 = createRunners(config2);
|
|
3339
3401
|
const defaultRunnerName2 = config2.agent.defaultRunner ?? Object.keys(runners2)[0] ?? "claude";
|
|
3340
3402
|
const defaultRunner2 = runners2[defaultRunnerName2];
|
|
@@ -3424,10 +3486,10 @@ ${input.feedback}` : reviewContext;
|
|
|
3424
3486
|
}
|
|
3425
3487
|
}
|
|
3426
3488
|
const config = getProjectConfig();
|
|
3427
|
-
let litellmProcess =
|
|
3489
|
+
let litellmProcess = await ensureLitellmProxy(config, projectDir);
|
|
3428
3490
|
const cleanupLitellm = () => {
|
|
3429
3491
|
if (litellmProcess) {
|
|
3430
|
-
litellmProcess.kill();
|
|
3492
|
+
litellmProcess.kill?.();
|
|
3431
3493
|
litellmProcess = null;
|
|
3432
3494
|
}
|
|
3433
3495
|
};
|
|
@@ -3440,23 +3502,6 @@ ${input.feedback}` : reviewContext;
|
|
|
3440
3502
|
cleanupLitellm();
|
|
3441
3503
|
process.exit(143);
|
|
3442
3504
|
});
|
|
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
3505
|
const runners = createRunners(config);
|
|
3461
3506
|
const defaultRunnerName = config.agent.defaultRunner ?? Object.keys(runners)[0] ?? "claude";
|
|
3462
3507
|
const defaultRunner = runners[defaultRunnerName];
|
|
@@ -3548,6 +3593,7 @@ var init_entry = __esm({
|
|
|
3548
3593
|
init_litellm();
|
|
3549
3594
|
init_task_resolution();
|
|
3550
3595
|
init_task_state();
|
|
3596
|
+
init_config();
|
|
3551
3597
|
main().catch(async (err) => {
|
|
3552
3598
|
const msg = err instanceof Error ? err.message : String(err);
|
|
3553
3599
|
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": {
|