@kody-ade/kody-engine 0.4.416 → 0.4.417
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/kody.js +137 -40
- package/dist/implementations/types.ts +1 -0
- package/package.json +2 -2
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.
|
|
18
|
+
version: "0.4.417",
|
|
19
19
|
description: "kody \u2014 autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative implementation profiles.",
|
|
20
20
|
license: "MIT",
|
|
21
21
|
type: "module",
|
|
@@ -52,7 +52,7 @@ var init_package = __esm({
|
|
|
52
52
|
dependencies: {
|
|
53
53
|
"@actions/cache": "^6.0.0",
|
|
54
54
|
"@anthropic-ai/claude-agent-sdk": "0.2.119",
|
|
55
|
-
"@kody-ade/agency-domain": "0.
|
|
55
|
+
"@kody-ade/agency-domain": "0.5.0",
|
|
56
56
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
57
57
|
convex: "^1.17.0",
|
|
58
58
|
zod: "^4.0.0"
|
|
@@ -3415,6 +3415,7 @@ async function runAgent(opts) {
|
|
|
3415
3415
|
let outcomeKind = "generic_failed";
|
|
3416
3416
|
let errorMessage2;
|
|
3417
3417
|
let tokens = { input: 0, output: 0, cacheRead: 0, cacheCreate: 0 };
|
|
3418
|
+
let costUsd = 0;
|
|
3418
3419
|
let messageCount = 0;
|
|
3419
3420
|
let finalText = "";
|
|
3420
3421
|
let getSubmitted;
|
|
@@ -3431,6 +3432,7 @@ async function runAgent(opts) {
|
|
|
3431
3432
|
outcomeKind = "generic_failed";
|
|
3432
3433
|
errorMessage2 = void 0;
|
|
3433
3434
|
tokens = { input: 0, output: 0, cacheRead: 0, cacheCreate: 0 };
|
|
3435
|
+
costUsd = 0;
|
|
3434
3436
|
messageCount = 0;
|
|
3435
3437
|
let sawMutatingTool = false;
|
|
3436
3438
|
let sawTerminalSuccess = false;
|
|
@@ -3555,6 +3557,7 @@ async function runAgent(opts) {
|
|
|
3555
3557
|
};
|
|
3556
3558
|
}
|
|
3557
3559
|
queryOptions.settingSources = opts.settingSources ?? ["project", "local"];
|
|
3560
|
+
if (opts.abortController) queryOptions.abortController = opts.abortController;
|
|
3558
3561
|
const stableBinary = ensureStableClaudeBinary();
|
|
3559
3562
|
if (stableBinary) {
|
|
3560
3563
|
const sdkBinaryPathOption = ["pathToClaudeCode", "Exec", "utable"].join("");
|
|
@@ -3683,6 +3686,8 @@ async function runAgent(opts) {
|
|
|
3683
3686
|
}
|
|
3684
3687
|
}
|
|
3685
3688
|
if (m.type === "result") {
|
|
3689
|
+
const reportedCost = Number(m.total_cost_usd ?? 0);
|
|
3690
|
+
if (Number.isFinite(reportedCost) && reportedCost >= 0) costUsd = reportedCost;
|
|
3686
3691
|
if (m.subtype === "success") {
|
|
3687
3692
|
outcome = "completed";
|
|
3688
3693
|
outcomeKind = "ok";
|
|
@@ -3760,6 +3765,7 @@ async function runAgent(opts) {
|
|
|
3760
3765
|
ndjsonPath,
|
|
3761
3766
|
durationMs: Date.now() - startedAt,
|
|
3762
3767
|
tokens,
|
|
3768
|
+
costUsd,
|
|
3763
3769
|
messageCount
|
|
3764
3770
|
};
|
|
3765
3771
|
}
|
|
@@ -13038,7 +13044,6 @@ function addDefinition(catalog, document) {
|
|
|
13038
13044
|
}
|
|
13039
13045
|
function add(collection, definition, revision) {
|
|
13040
13046
|
const mutable = collection;
|
|
13041
|
-
if (mutable.has(definition.id)) throw new Error(`Duplicate Agency Definition: ${definition.id}`);
|
|
13042
13047
|
mutable.set(definition.id, { definition, revision });
|
|
13043
13048
|
}
|
|
13044
13049
|
function validateRelationships(catalog) {
|
|
@@ -13098,7 +13103,10 @@ var init_agencyModelRepository = __esm({
|
|
|
13098
13103
|
async loadCatalog() {
|
|
13099
13104
|
const documents = await this.backend.listAgencyDefinitions(this.tenantId);
|
|
13100
13105
|
const catalog = emptyCatalog();
|
|
13101
|
-
|
|
13106
|
+
const ordered = [...documents].sort(
|
|
13107
|
+
(left, right) => left.createdAt.localeCompare(right.createdAt) || left.recordId.localeCompare(right.recordId)
|
|
13108
|
+
);
|
|
13109
|
+
for (const document of ordered) addDefinition(catalog, document);
|
|
13102
13110
|
validateRelationships(catalog);
|
|
13103
13111
|
return catalog;
|
|
13104
13112
|
}
|
|
@@ -13325,7 +13333,19 @@ async function dispatchAgencyLoopsWith(input) {
|
|
|
13325
13333
|
results.push({ loopId: record2.definition.id, decision: "skipped", reason });
|
|
13326
13334
|
continue;
|
|
13327
13335
|
}
|
|
13328
|
-
const
|
|
13336
|
+
const failurePolicy = record2.definition.reconciliationPolicy.failure;
|
|
13337
|
+
const budget = policy.snapshot.policy.budget;
|
|
13338
|
+
const maxAttempts = Math.min(failurePolicy.maxAttempts, budget.maxRuns);
|
|
13339
|
+
const timeoutSeconds = Math.min(failurePolicy.timeoutSeconds, budget.maxDurationSeconds);
|
|
13340
|
+
const backoffBudgetSeconds = Array.from(
|
|
13341
|
+
{ length: Math.max(0, maxAttempts - 1) },
|
|
13342
|
+
(_, index) => failurePolicy.backoffSeconds * 2 ** index
|
|
13343
|
+
).reduce((sum, seconds) => sum + seconds, 0);
|
|
13344
|
+
const leaseSeconds = Math.min(
|
|
13345
|
+
budget.maxDurationSeconds,
|
|
13346
|
+
maxAttempts * timeoutSeconds + backoffBudgetSeconds
|
|
13347
|
+
);
|
|
13348
|
+
const leaseUntil = new Date(input.now.getTime() + leaseSeconds * 1e3).toISOString();
|
|
13329
13349
|
const reservationId = `reservation-${randomUUID()}`;
|
|
13330
13350
|
const correlationId = `corr-${randomUUID()}`;
|
|
13331
13351
|
const trace = [policy.trace[0], ...target.intermediate, target.reference];
|
|
@@ -13365,40 +13385,82 @@ async function dispatchAgencyLoopsWith(input) {
|
|
|
13365
13385
|
updatedAt: now
|
|
13366
13386
|
});
|
|
13367
13387
|
await repository.saveState(runningState, "loop", now);
|
|
13368
|
-
const runId = `run-${randomUUID()}`;
|
|
13369
|
-
const activeRun = createRun({
|
|
13370
|
-
id: runId,
|
|
13371
|
-
status: "running",
|
|
13372
|
-
origin: { kind: "loop", id: record2.definition.id, revision: record2.revision },
|
|
13373
|
-
target: target.reference,
|
|
13374
|
-
trace,
|
|
13375
|
-
effectivePolicy: policy.snapshot,
|
|
13376
|
-
correlationId,
|
|
13377
|
-
startedAt: now
|
|
13378
|
-
});
|
|
13379
13388
|
try {
|
|
13380
|
-
|
|
13381
|
-
|
|
13382
|
-
|
|
13383
|
-
|
|
13384
|
-
|
|
13385
|
-
|
|
13386
|
-
);
|
|
13387
|
-
|
|
13388
|
-
|
|
13389
|
+
let attempts = 0;
|
|
13390
|
+
let tokens = 0;
|
|
13391
|
+
let costUsd = 0;
|
|
13392
|
+
let succeeded = false;
|
|
13393
|
+
let reason = "target failed";
|
|
13394
|
+
let finalRunId;
|
|
13395
|
+
const budgetDeadline = Date.now() + budget.maxDurationSeconds * 1e3;
|
|
13396
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt += 1) {
|
|
13397
|
+
const remainingMilliseconds = budgetDeadline - Date.now();
|
|
13398
|
+
if (remainingMilliseconds <= 0) {
|
|
13399
|
+
reason = "policy duration budget exhausted";
|
|
13400
|
+
break;
|
|
13401
|
+
}
|
|
13402
|
+
attempts = attempt;
|
|
13403
|
+
const startedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
13404
|
+
const runId = `run-${randomUUID()}`;
|
|
13405
|
+
finalRunId = runId;
|
|
13406
|
+
const activeRun = createRun({
|
|
13407
|
+
id: runId,
|
|
13408
|
+
status: "running",
|
|
13409
|
+
origin: { kind: "loop", id: record2.definition.id, revision: record2.revision },
|
|
13410
|
+
target: target.reference,
|
|
13411
|
+
trace,
|
|
13412
|
+
effectivePolicy: policy.snapshot,
|
|
13413
|
+
correlationId,
|
|
13414
|
+
startedAt
|
|
13415
|
+
});
|
|
13416
|
+
await input.backend.createAgencyModelRun(
|
|
13417
|
+
input.tenantId,
|
|
13418
|
+
target.reference.kind,
|
|
13419
|
+
target.reference.id,
|
|
13420
|
+
activeRun,
|
|
13421
|
+
startedAt
|
|
13422
|
+
);
|
|
13423
|
+
const attemptResult = await runAttempt(
|
|
13424
|
+
input.run,
|
|
13425
|
+
target.job,
|
|
13426
|
+
Math.min(timeoutSeconds, remainingMilliseconds / 1e3)
|
|
13427
|
+
);
|
|
13428
|
+
tokens += attemptResult.usage?.tokens ?? 0;
|
|
13429
|
+
costUsd += attemptResult.usage?.costUsd ?? 0;
|
|
13430
|
+
const finishedAt2 = (/* @__PURE__ */ new Date()).toISOString();
|
|
13431
|
+
succeeded = attemptResult.exitCode === 0;
|
|
13432
|
+
reason = attemptResult.reason ?? (succeeded ? "target dispatched" : "target failed");
|
|
13433
|
+
const usage = {
|
|
13434
|
+
tokens: attemptResult.usage?.tokens ?? 0,
|
|
13435
|
+
costUsd: attemptResult.usage?.costUsd ?? 0,
|
|
13436
|
+
durationSeconds: Math.max(0, (Date.parse(finishedAt2) - Date.parse(startedAt)) / 1e3)
|
|
13437
|
+
};
|
|
13438
|
+
if (tokens > budget.maxTokens || costUsd > budget.maxCostUsd) {
|
|
13439
|
+
succeeded = false;
|
|
13440
|
+
reason = tokens > budget.maxTokens ? "policy token budget exhausted" : "policy cost budget exhausted";
|
|
13441
|
+
}
|
|
13442
|
+
await input.backend.finishAgencyModelRun(
|
|
13443
|
+
input.tenantId,
|
|
13444
|
+
terminalRun(activeRun, succeeded ? "succeeded" : "failed", finishedAt2, usage),
|
|
13445
|
+
finishedAt2
|
|
13446
|
+
);
|
|
13447
|
+
if (tokens > budget.maxTokens || costUsd > budget.maxCostUsd) break;
|
|
13448
|
+
if (succeeded || attempt === maxAttempts) break;
|
|
13449
|
+
const backoffMilliseconds = failurePolicy.backoffSeconds * 2 ** (attempt - 1) * 1e3;
|
|
13450
|
+
if (Date.now() + backoffMilliseconds >= budgetDeadline) {
|
|
13451
|
+
reason = "policy duration budget exhausted during retry backoff";
|
|
13452
|
+
break;
|
|
13453
|
+
}
|
|
13454
|
+
await wait(backoffMilliseconds);
|
|
13455
|
+
}
|
|
13389
13456
|
const finishedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
13390
|
-
await input.backend.finishAgencyModelRun(
|
|
13391
|
-
input.tenantId,
|
|
13392
|
-
terminalRun(activeRun, succeeded ? "succeeded" : "failed", finishedAt),
|
|
13393
|
-
finishedAt
|
|
13394
|
-
);
|
|
13395
13457
|
await input.backend.finishAgencyDispatch(
|
|
13396
13458
|
input.tenantId,
|
|
13397
13459
|
decision.idempotencyKey,
|
|
13398
13460
|
reservationId,
|
|
13399
|
-
succeeded ? "dispatched" : "
|
|
13461
|
+
succeeded ? "dispatched" : "dead-letter",
|
|
13400
13462
|
finishedAt,
|
|
13401
|
-
|
|
13463
|
+
finalRunId
|
|
13402
13464
|
);
|
|
13403
13465
|
await repository.saveState(
|
|
13404
13466
|
createLoopState2({
|
|
@@ -13413,19 +13475,17 @@ async function dispatchAgencyLoopsWith(input) {
|
|
|
13413
13475
|
results.push({
|
|
13414
13476
|
loopId: record2.definition.id,
|
|
13415
13477
|
decision: succeeded ? "dispatched" : "failed",
|
|
13416
|
-
reason:
|
|
13478
|
+
reason: succeeded ? reason : `${reason}; dead-lettered after ${attempts} attempt${attempts === 1 ? "" : "s"}`
|
|
13417
13479
|
});
|
|
13418
13480
|
} catch (error) {
|
|
13419
13481
|
const reason = error instanceof Error ? error.message : String(error);
|
|
13420
13482
|
const finishedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
13421
|
-
await input.backend.finishAgencyModelRun(input.tenantId, terminalRun(activeRun, "failed", finishedAt), finishedAt).catch(() => void 0);
|
|
13422
13483
|
await input.backend.finishAgencyDispatch(
|
|
13423
13484
|
input.tenantId,
|
|
13424
13485
|
decision.idempotencyKey,
|
|
13425
13486
|
reservationId,
|
|
13426
|
-
"
|
|
13427
|
-
finishedAt
|
|
13428
|
-
runId
|
|
13487
|
+
"dead-letter",
|
|
13488
|
+
finishedAt
|
|
13429
13489
|
);
|
|
13430
13490
|
results.push({ loopId: record2.definition.id, decision: "failed", reason });
|
|
13431
13491
|
}
|
|
@@ -13449,8 +13509,32 @@ function resolveTarget(loop, catalog) {
|
|
|
13449
13509
|
job: target.kind === "workflow" ? { workflow: target.id, cliArgs: {}, flavor: "scheduled" } : { capability: target.id, cliArgs: {}, flavor: "scheduled" }
|
|
13450
13510
|
};
|
|
13451
13511
|
}
|
|
13452
|
-
function terminalRun(active, status, finishedAt) {
|
|
13453
|
-
return createRun({ ...active, status, finishedAt });
|
|
13512
|
+
function terminalRun(active, status, finishedAt, usage) {
|
|
13513
|
+
return createRun({ ...active, status, finishedAt, usage });
|
|
13514
|
+
}
|
|
13515
|
+
async function runAttempt(run, job, timeoutSeconds) {
|
|
13516
|
+
const abortController = new AbortController();
|
|
13517
|
+
let timer;
|
|
13518
|
+
try {
|
|
13519
|
+
return await Promise.race([
|
|
13520
|
+
run(job, abortController),
|
|
13521
|
+
new Promise((resolve17) => {
|
|
13522
|
+
timer = setTimeout(() => {
|
|
13523
|
+
abortController.abort();
|
|
13524
|
+
resolve17({ exitCode: 124, reason: `target timed out after ${formatSeconds(timeoutSeconds)}s` });
|
|
13525
|
+
}, timeoutSeconds * 1e3);
|
|
13526
|
+
})
|
|
13527
|
+
]);
|
|
13528
|
+
} finally {
|
|
13529
|
+
if (timer) clearTimeout(timer);
|
|
13530
|
+
}
|
|
13531
|
+
}
|
|
13532
|
+
function formatSeconds(seconds) {
|
|
13533
|
+
return Number.isInteger(seconds) ? String(seconds) : seconds.toFixed(3).replace(/0+$/, "").replace(/\.$/, "");
|
|
13534
|
+
}
|
|
13535
|
+
async function wait(milliseconds) {
|
|
13536
|
+
if (milliseconds <= 0) return;
|
|
13537
|
+
await new Promise((resolve17) => setTimeout(resolve17, milliseconds));
|
|
13454
13538
|
}
|
|
13455
13539
|
function repositoryTenant(config) {
|
|
13456
13540
|
const owner = config.github?.owner?.trim() || process.env.GITHUB_REPOSITORY?.split("/")[0]?.trim();
|
|
@@ -13474,7 +13558,14 @@ var init_dispatchAgencyLoops = __esm({
|
|
|
13474
13558
|
tenantId: tenantId2,
|
|
13475
13559
|
backend,
|
|
13476
13560
|
now: /* @__PURE__ */ new Date(),
|
|
13477
|
-
run: (job) => runJob(job, {
|
|
13561
|
+
run: (job, abortController) => runJob(job, {
|
|
13562
|
+
cwd: ctx.cwd,
|
|
13563
|
+
config: ctx.config,
|
|
13564
|
+
verbose: ctx.verbose,
|
|
13565
|
+
quiet: ctx.quiet,
|
|
13566
|
+
chain: false,
|
|
13567
|
+
abortController
|
|
13568
|
+
})
|
|
13478
13569
|
});
|
|
13479
13570
|
ctx.data.agencyLoopDispatchResults = results;
|
|
13480
13571
|
};
|
|
@@ -20686,6 +20777,7 @@ async function runImplementation(profileName, input) {
|
|
|
20686
20777
|
isBackendHealthy: lm ? () => lm.isHealthy() : void 0,
|
|
20687
20778
|
verbose: input.verbose,
|
|
20688
20779
|
quiet: input.quiet,
|
|
20780
|
+
abortController: input.abortController,
|
|
20689
20781
|
ndjsonDir,
|
|
20690
20782
|
additionalDirectories: agentTaskArtifacts ? [agentTaskArtifacts.absDir] : void 0,
|
|
20691
20783
|
allowedToolsOverride: profile.claudeCode.tools,
|
|
@@ -20795,6 +20887,10 @@ async function runImplementation(profileName, input) {
|
|
|
20795
20887
|
reason: err instanceof Error ? err.message : String(err)
|
|
20796
20888
|
});
|
|
20797
20889
|
}
|
|
20890
|
+
ctx.output.usage = {
|
|
20891
|
+
tokens: agentResult.tokens ? agentResult.tokens.input + agentResult.tokens.output + agentResult.tokens.cacheRead + agentResult.tokens.cacheCreate : 0,
|
|
20892
|
+
costUsd: agentResult.costUsd ?? 0
|
|
20893
|
+
};
|
|
20798
20894
|
emitEvent(input.cwd, {
|
|
20799
20895
|
implementation: profileName,
|
|
20800
20896
|
kind: "agent_end",
|
|
@@ -21637,6 +21733,7 @@ async function runCapabilityImplementationStep(valid, profileName, capabilityIde
|
|
|
21637
21733
|
skipConfig: base.skipConfig,
|
|
21638
21734
|
verbose: base.verbose,
|
|
21639
21735
|
quiet: base.quiet,
|
|
21736
|
+
abortController: base.abortController,
|
|
21640
21737
|
preloadedData: Object.keys(preloadedData).length > 0 ? preloadedData : void 0
|
|
21641
21738
|
};
|
|
21642
21739
|
const shouldApplyResolvedCapabilityArgs = valid.implementation === void 0 && resolvedCapability && profileName === resolvedCapability.implementation;
|
|
@@ -453,6 +453,7 @@ export interface Context {
|
|
|
453
453
|
exitCode: number
|
|
454
454
|
prUrl?: string
|
|
455
455
|
reason?: string
|
|
456
|
+
usage?: { tokens: number; costUsd: number }
|
|
456
457
|
/**
|
|
457
458
|
* In-process hand-off to the next stage. A stage (e.g. `classify`) sets
|
|
458
459
|
* this so the orchestrator runs the chosen sub-orchestrator
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kody-ade/kody-engine",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.417",
|
|
4
4
|
"description": "kody — autonomous development engine. Single-session Claude Code agent behind a generic executor + declarative implementation profiles.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"dependencies": {
|
|
16
16
|
"@actions/cache": "^6.0.0",
|
|
17
17
|
"@anthropic-ai/claude-agent-sdk": "0.2.119",
|
|
18
|
-
"@kody-ade/agency-domain": "0.
|
|
18
|
+
"@kody-ade/agency-domain": "0.5.0",
|
|
19
19
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
20
20
|
"convex": "^1.17.0",
|
|
21
21
|
"zod": "^4.0.0"
|