@kody-ade/kody-engine 0.4.308 → 0.4.310

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.
Files changed (2) hide show
  1. package/dist/bin/kody.js +208 -22
  2. package/package.json +1 -1
package/dist/bin/kody.js CHANGED
@@ -15,7 +15,7 @@ var init_package = __esm({
15
15
  "package.json"() {
16
16
  package_default = {
17
17
  name: "@kody-ade/kody-engine",
18
- version: "0.4.308",
18
+ version: "0.4.310",
19
19
  description: "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
20
20
  license: "MIT",
21
21
  type: "module",
@@ -6009,27 +6009,30 @@ function resolveLitellmTimeoutMs() {
6009
6009
  function generateLitellmConfigYaml(model) {
6010
6010
  const apiKeyVar = model.apiKeyEnvVar ?? providerApiKeyEnvVar(model.provider);
6011
6011
  const litellmProvider = model.litellmProvider ?? model.provider;
6012
- const modelGroup = litellmModelGroup(model);
6012
+ const modelGroups = litellmModelGroups(model);
6013
6013
  const providerParams = model.baseURL ? [["api_base", model.baseURL]] : [];
6014
- return [
6015
- "model_list:",
6014
+ const modelEntries = modelGroups.flatMap((modelGroup) => [
6016
6015
  ` - model_name: ${modelGroup}`,
6017
6016
  ` litellm_params:`,
6018
6017
  ` model: ${litellmProvider}/${model.model}`,
6019
6018
  ` api_key: os.environ/${apiKeyVar}`,
6020
- ...providerParams.map(([key, value]) => ` ${key}: ${value}`),
6021
- "",
6022
- "litellm_settings:",
6023
- " drop_params: true",
6024
- ""
6025
- ].join("\n");
6019
+ ...providerParams.map(([key, value]) => ` ${key}: ${value}`)
6020
+ ]);
6021
+ return ["model_list:", ...modelEntries, "", "litellm_settings:", " drop_params: true", ""].join("\n");
6026
6022
  }
6027
- async function litellmServesModel(url, modelGroup) {
6023
+ function litellmModelGroups(model) {
6024
+ const primary = litellmModelGroup(model);
6025
+ return Array.from(/* @__PURE__ */ new Set([primary, ...CLAUDE_CODE_PROXY_MODEL_ALIASES]));
6026
+ }
6027
+ async function litellmServesModels(url, modelGroups) {
6028
6028
  try {
6029
6029
  const response = await fetch(`${url.replace(/\/+$/, "")}/v1/models`, { signal: AbortSignal.timeout(3e3) });
6030
6030
  if (!response.ok) return false;
6031
6031
  const payload = await response.json();
6032
- return (payload.data ?? []).some((entry) => entry.id === modelGroup);
6032
+ const served = new Set(
6033
+ (payload.data ?? []).map((entry) => entry.id).filter((id) => typeof id === "string")
6034
+ );
6035
+ return modelGroups.every((modelGroup) => served.has(modelGroup));
6033
6036
  } catch {
6034
6037
  return false;
6035
6038
  }
@@ -6086,7 +6089,7 @@ async function startLitellmIfNeeded(model, projectDir, url = LITELLM_DEFAULT_URL
6086
6089
  if (!needsLitellmProxy(model)) return null;
6087
6090
  const cmd = resolveLitellmCommand();
6088
6091
  let activeUrl = url.replace(/\/+$/, "");
6089
- const modelGroup = litellmModelGroup(model);
6092
+ const modelGroups = litellmModelGroups(model);
6090
6093
  const childEnv = stripBlockingEnv({ ...process.env, ...readDotenvApiKeys(projectDir) });
6091
6094
  let child;
6092
6095
  let logPath;
@@ -6150,13 +6153,13 @@ ${tail}
6150
6153
  };
6151
6154
  const isHealthy = () => checkLitellmHealth(activeUrl);
6152
6155
  if (await checkLitellmHealth(activeUrl)) {
6153
- if (await litellmServesModel(activeUrl, modelGroup)) {
6156
+ if (await litellmServesModels(activeUrl, modelGroups)) {
6154
6157
  return { url: activeUrl, kill: killChild, isHealthy, ensureHealthy };
6155
6158
  }
6156
6159
  const staleUrl = activeUrl;
6157
6160
  activeUrl = await nextAvailableLitellmUrl(activeUrl);
6158
6161
  process.stderr.write(
6159
- `[kody litellm] existing proxy at ${staleUrl} does not serve ${modelGroup}; starting a separate proxy at ${activeUrl}
6162
+ `[kody litellm] existing proxy at ${staleUrl} does not serve ${modelGroups.join(", ")}; starting a separate proxy at ${activeUrl}
6160
6163
  `
6161
6164
  );
6162
6165
  }
@@ -6220,13 +6223,14 @@ function stripBlockingEnv(env) {
6220
6223
  delete out.AI_BASE_URL;
6221
6224
  return out;
6222
6225
  }
6223
- var DEFAULT_LITELLM_STARTUP_TIMEOUT_SEC, LITELLM_HEALTH_POLL_INTERVAL_MS;
6226
+ var DEFAULT_LITELLM_STARTUP_TIMEOUT_SEC, LITELLM_HEALTH_POLL_INTERVAL_MS, CLAUDE_CODE_PROXY_MODEL_ALIASES;
6224
6227
  var init_litellm = __esm({
6225
6228
  "src/litellm.ts"() {
6226
6229
  "use strict";
6227
6230
  init_config();
6228
6231
  DEFAULT_LITELLM_STARTUP_TIMEOUT_SEC = 150;
6229
6232
  LITELLM_HEALTH_POLL_INTERVAL_MS = 2e3;
6233
+ CLAUDE_CODE_PROXY_MODEL_ALIASES = ["claude-haiku-4-5-20251001", "haiku"];
6230
6234
  }
6231
6235
  });
6232
6236
 
@@ -7052,16 +7056,76 @@ function enrichGoalRunLogEvent(config, data, logPath, event) {
7052
7056
  const stateRepo = stateRepoContext(config, event.goalId, logPath);
7053
7057
  const trigger = event.trigger ?? triggerContext();
7054
7058
  const job = event.job ?? jobContext(data);
7055
- return pruneUndefined({
7059
+ const run = event.run ?? runContext(data);
7060
+ const links = event.links ?? linkContext(stateRepo);
7061
+ const enriched = pruneUndefined({
7056
7062
  ...event,
7057
- run: event.run ?? runContext(data),
7063
+ run,
7058
7064
  repo: event.repo ?? repoContext(config),
7059
7065
  stateRepo: event.stateRepo ?? stateRepo,
7060
7066
  trigger,
7061
7067
  job,
7062
7068
  dispatchContext: event.dispatchContext ?? dispatchContext(event, trigger, job),
7063
- links: event.links ?? linkContext(stateRepo)
7069
+ links
7070
+ });
7071
+ enriched.trace = event.trace ?? goalRunTrace(enriched);
7072
+ return enriched;
7073
+ }
7074
+ function goalRunTrace(event) {
7075
+ const run = recordValue2(event.run);
7076
+ const trigger = recordValue2(event.trigger);
7077
+ const goal = recordValue2(event.goal);
7078
+ const inspection = recordValue2(event.inspection);
7079
+ const capabilityOutput = recordValue2(inspection?.capabilityOutput);
7080
+ return pruneUndefined({
7081
+ version: 1,
7082
+ runId: stringValue2(run?.id) ?? void 0,
7083
+ workflowRunId: stringValue2(run?.githubRunId) ?? void 0,
7084
+ triggerKind: stringValue2(trigger?.kind) ?? void 0,
7085
+ source: event.source,
7086
+ event: event.event,
7087
+ goal: pruneUndefined({
7088
+ id: event.goalId,
7089
+ type: event.goalType ?? stringValue2(goal?.type) ?? void 0,
7090
+ state: event.goalState ?? stringValue2(goal?.state) ?? void 0,
7091
+ stage: event.stage ?? stringValue2(goal?.stage) ?? void 0
7092
+ }),
7093
+ evidence: goalTraceEvidence(event, goal, inspection),
7094
+ capability: event.dispatch ?? capabilityDispatchFromOutput(capabilityOutput),
7095
+ result: goalTraceResult(event, capabilityOutput),
7096
+ change: event.change,
7097
+ links: event.links
7098
+ });
7099
+ }
7100
+ function goalTraceEvidence(event, goal, inspection) {
7101
+ const expectedEvidence = recordValue2(inspection?.expectedEvidence);
7102
+ const out = pruneUndefined({
7103
+ current: event.evidence,
7104
+ required: stringArrayValue(goal?.requiredEvidence) ?? stringArrayValue(inspection?.requiredEvidence) ?? void 0,
7105
+ satisfied: stringArrayValue(goal?.satisfiedEvidence) ?? stringArrayValue(inspection?.satisfiedEvidence) ?? void 0,
7106
+ missing: stringArrayValue(goal?.missingEvidence) ?? stringArrayValue(inspection?.missingEvidence) ?? stringArrayValue(expectedEvidence?.missingBefore) ?? void 0,
7107
+ pending: stringValue2(goal?.pendingEvidence) ?? stringValue2(inspection?.pendingEvidence) ?? stringValue2(expectedEvidence?.pendingBefore) ?? void 0,
7108
+ values: event.evidenceValues
7109
+ });
7110
+ return Object.keys(out).length > 0 ? out : void 0;
7111
+ }
7112
+ function capabilityDispatchFromOutput(output) {
7113
+ if (!output) return void 0;
7114
+ const dispatch2 = pruneUndefined({
7115
+ capability: stringValue2(output.capability) ?? void 0,
7116
+ executable: stringValue2(output.executable) ?? void 0,
7117
+ action: stringValue2(output.action) ?? void 0
7064
7118
  });
7119
+ return Object.keys(dispatch2).length > 0 ? dispatch2 : void 0;
7120
+ }
7121
+ function goalTraceResult(event, capabilityOutput) {
7122
+ const result = pruneUndefined({
7123
+ status: event.status ?? stringValue2(capabilityOutput?.status) ?? void 0,
7124
+ summary: event.reason ?? stringValue2(capabilityOutput?.summary) ?? void 0,
7125
+ blockers: event.inspection ? stringArrayValue(capabilityOutput?.blockers) ?? void 0 : void 0,
7126
+ artifacts: event.artifacts
7127
+ });
7128
+ return Object.keys(result).length > 0 ? result : void 0;
7065
7129
  }
7066
7130
  function runContext(data) {
7067
7131
  const runId = process.env.GITHUB_RUN_ID?.trim();
@@ -12218,6 +12282,126 @@ var init_ensurePr = __esm({
12218
12282
  }
12219
12283
  });
12220
12284
 
12285
+ // src/agencyBoundaryEval.ts
12286
+ function evaluateAgencyBoundaries(input) {
12287
+ const findings = [];
12288
+ const results = input.results ?? [];
12289
+ findings.push(evaluateObserveBoundary(input.capabilityKind, results));
12290
+ findings.push(evaluateVerifyBoundary(input.capabilityKind, results));
12291
+ findings.push(evaluateGoalOwnershipBoundary(results));
12292
+ return {
12293
+ version: 1,
12294
+ status: findings.some((finding) => finding.status === "fail") ? "fail" : "pass",
12295
+ ...input.capability ? { capability: input.capability } : {},
12296
+ ...input.capabilityKind ? { capabilityKind: input.capabilityKind } : {},
12297
+ findings
12298
+ };
12299
+ }
12300
+ function evaluateObserveBoundary(capabilityKind, results) {
12301
+ if (capabilityKind !== "observe") {
12302
+ return pass("observe-does-not-act", "capability is not observe", { capabilityKind });
12303
+ }
12304
+ const actionResults = results.filter(resultLooksLikeAction);
12305
+ if (actionResults.length === 0) {
12306
+ return pass("observe-does-not-act", "observe capability reported facts without action output", {
12307
+ resultCount: results.length
12308
+ });
12309
+ }
12310
+ return fail2("observe-does-not-act", "observe capability returned action-shaped output", {
12311
+ resultCount: results.length,
12312
+ actionResults: actionResults.map(resultSummary)
12313
+ });
12314
+ }
12315
+ function evaluateVerifyBoundary(capabilityKind, results) {
12316
+ if (capabilityKind !== "verify") {
12317
+ return pass("verify-does-not-fix", "capability is not verify", { capabilityKind });
12318
+ }
12319
+ const actionResults = results.filter(resultLooksLikeAction);
12320
+ if (actionResults.length === 0) {
12321
+ return pass("verify-does-not-fix", "verify capability returned verdict evidence without action output", {
12322
+ resultCount: results.length
12323
+ });
12324
+ }
12325
+ return fail2("verify-does-not-fix", "verify capability returned fix/change output", {
12326
+ resultCount: results.length,
12327
+ actionResults: actionResults.map(resultSummary)
12328
+ });
12329
+ }
12330
+ function evaluateGoalOwnershipBoundary(results) {
12331
+ const targetBearing = results.filter((result) => result.target?.type === "goal");
12332
+ if (targetBearing.length === 0) {
12333
+ return pass("capability-does-not-own-goal-progress", "capability output is parent-neutral", {
12334
+ resultCount: results.length
12335
+ });
12336
+ }
12337
+ return fail2("capability-does-not-own-goal-progress", "capability output names a goal target", {
12338
+ resultCount: results.length,
12339
+ targetBearingResults: targetBearing.map(resultSummary)
12340
+ });
12341
+ }
12342
+ function resultLooksLikeAction(result) {
12343
+ if (result.status === "changed") return true;
12344
+ return Object.keys(result.facts).some((key) => ACTION_FACT_KEYS.has(key));
12345
+ }
12346
+ function resultSummary(result) {
12347
+ return {
12348
+ status: result.status,
12349
+ summary: result.summary,
12350
+ target: result.target,
12351
+ actionFactKeys: Object.keys(result.facts).filter((key) => ACTION_FACT_KEYS.has(key))
12352
+ };
12353
+ }
12354
+ function pass(rule, message, evidence) {
12355
+ return { rule, status: "pass", message, evidence };
12356
+ }
12357
+ function fail2(rule, message, evidence) {
12358
+ return { rule, status: "fail", message, evidence };
12359
+ }
12360
+ var ACTION_FACT_KEYS;
12361
+ var init_agencyBoundaryEval = __esm({
12362
+ "src/agencyBoundaryEval.ts"() {
12363
+ "use strict";
12364
+ ACTION_FACT_KEYS = /* @__PURE__ */ new Set(["changedResources", "createdResources", "actionResult"]);
12365
+ }
12366
+ });
12367
+
12368
+ // src/scripts/evaluateAgencyBoundaries.ts
12369
+ function collectResults2(raw, agentResult) {
12370
+ const out = [];
12371
+ if (Array.isArray(raw)) {
12372
+ for (const item of raw) {
12373
+ const parsed = parseCapabilityResult(item);
12374
+ if (parsed) out.push(parsed);
12375
+ }
12376
+ }
12377
+ if (agentResult?.finalText) out.push(...parseCapabilityResultsFromText(agentResult.finalText));
12378
+ return out;
12379
+ }
12380
+ var evaluateAgencyBoundariesScript;
12381
+ var init_evaluateAgencyBoundaries = __esm({
12382
+ "src/scripts/evaluateAgencyBoundaries.ts"() {
12383
+ "use strict";
12384
+ init_agencyBoundaryEval();
12385
+ init_capabilityResult();
12386
+ evaluateAgencyBoundariesScript = async (ctx, profile, agentResult) => {
12387
+ const results = collectResults2(ctx.data.capabilityResults ?? ctx.data.dutyResults, agentResult);
12388
+ const evalResult = evaluateAgencyBoundaries({
12389
+ capability: profile.name,
12390
+ capabilityKind: profile.capabilityKind,
12391
+ results
12392
+ });
12393
+ ctx.data.agencyBoundaryEval = evalResult;
12394
+ process.stdout.write(`KODY_AGENCY_BOUNDARY_EVAL=${JSON.stringify(evalResult)}
12395
+ `);
12396
+ if (evalResult.status === "fail") {
12397
+ const failed = evalResult.findings.filter((finding) => finding.status === "fail").map((finding) => finding.rule);
12398
+ ctx.output.exitCode = ctx.output.exitCode === 0 ? 99 : ctx.output.exitCode;
12399
+ ctx.output.reason = ctx.output.reason ? `${ctx.output.reason}; agency boundary eval failed: ${failed.join(", ")}` : `agency boundary eval failed: ${failed.join(", ")}`;
12400
+ }
12401
+ };
12402
+ }
12403
+ });
12404
+
12221
12405
  // src/scripts/failOnceTaskJob.ts
12222
12406
  var failOnceTaskJob;
12223
12407
  var init_failOnceTaskJob = __esm({
@@ -14088,7 +14272,7 @@ var init_markFlowSuccess = __esm({
14088
14272
  });
14089
14273
 
14090
14274
  // src/goal/operations.ts
14091
- function fail2(err) {
14275
+ function fail3(err) {
14092
14276
  if (err instanceof Error) {
14093
14277
  const lines = err.message.split("\n").filter(Boolean);
14094
14278
  return { ok: false, error: lines[0] ?? err.message };
@@ -14100,7 +14284,7 @@ function commentOnIssue(issueNumber, body, cwd) {
14100
14284
  gh(["issue", "comment", String(issueNumber), "--body", body], { cwd });
14101
14285
  return { ok: true };
14102
14286
  } catch (err) {
14103
- return fail2(err);
14287
+ return fail3(err);
14104
14288
  }
14105
14289
  }
14106
14290
  function mergePrSquash(prNumber, cwd) {
@@ -14108,7 +14292,7 @@ function mergePrSquash(prNumber, cwd) {
14108
14292
  gh(["pr", "merge", String(prNumber), "--squash", "--delete-branch"], { cwd });
14109
14293
  return { ok: true };
14110
14294
  } catch (err) {
14111
- return fail2(err);
14295
+ return fail3(err);
14112
14296
  }
14113
14297
  }
14114
14298
  var init_operations = __esm({
@@ -17988,6 +18172,7 @@ var init_scripts = __esm({
17988
18172
  init_dispatchClassified();
17989
18173
  init_dispatchNextTaskJob();
17990
18174
  init_ensurePr();
18175
+ init_evaluateAgencyBoundaries();
17991
18176
  init_failOnceTaskJob();
17992
18177
  init_finalizeTerminal();
17993
18178
  init_finishFlow();
@@ -18132,6 +18317,7 @@ var init_scripts = __esm({
18132
18317
  stageMergeConflicts,
18133
18318
  commitAndPush: commitAndPush2,
18134
18319
  ensurePr: ensurePr2,
18320
+ evaluateAgencyBoundaries: evaluateAgencyBoundariesScript,
18135
18321
  postAgentComment,
18136
18322
  postIssueComment: postIssueComment2,
18137
18323
  postPlanComment,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kody-ade/kody-engine",
3
- "version": "0.4.308",
3
+ "version": "0.4.310",
4
4
  "description": "kody — autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative executable profiles.",
5
5
  "license": "MIT",
6
6
  "type": "module",