@krapht/ork 1.0.0-alpha.12 → 1.0.0-alpha.14
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/{__build_info__-BJbE3Zvp.mjs → __build_info__-B82-dGJY.mjs} +3 -3
- package/dist/{attach-BmV5ckb9.mjs → attach-CdtGX9se.mjs} +5 -5
- package/dist/bin.mjs +274 -236
- package/dist/{builtin-files-w0YULJ4c.mjs → builtin-files-Bdq23IIi.mjs} +2 -2
- package/dist/{chips-CyeB_rhR.mjs → chips-BqcT58qr.mjs} +1 -1
- package/dist/{completion-CzElB8nS.mjs → completion--ywde-56.mjs} +52 -11
- package/dist/{context-BAwgVSX5.mjs → context-Y_I4Mofq.mjs} +18 -8
- package/dist/{find-p05wlbmu.mjs → find-BVX-bL4u.mjs} +1 -1
- package/dist/{format-Dni98cbh.mjs → format-CvTE5CZQ.mjs} +12 -12
- package/dist/{help-groups-DYP_zMRP.mjs → help-groups-CpR2UzSn.mjs} +20 -6
- package/dist/{in-a-run-BI-hLIl_.mjs → in-a-run-cL5N9gpH.mjs} +1 -1
- package/dist/{limits-CElmhowV.mjs → limits-Dhe--wmX.mjs} +2 -2
- package/dist/{mcp-CM3b65AZ.mjs → mcp-CsmboyXv.mjs} +6 -6
- package/dist/once-CrwI-ZdN.mjs +76 -0
- package/dist/{output-CnRzrbUM.mjs → output-B1kwo0YU.mjs} +17 -1
- package/dist/{pause-BuS83WAI.mjs → pause-DssrYcda.mjs} +4 -4
- package/dist/{relay-DAsJA8wF.mjs → relay-DASRgsTQ.mjs} +2 -2
- package/dist/run-D8divGCs.mjs +192 -0
- package/dist/send-CXv8bx0i.mjs +105 -0
- package/dist/{src-S9yK2OHU.mjs → src-8Mul0695.mjs} +8 -10
- package/dist/{src-BfxkJOYm.mjs → src-C7z_6fhn.mjs} +200 -72
- package/dist/{src-D1QedD5y.mjs → src-njdtejgZ.mjs} +140 -38
- package/dist/{src-CdDTQLdQ.mjs → src-tsuZRu0H.mjs} +2787 -1134
- package/dist/{store-B2OaE4ID.mjs → store-CleF7KeS.mjs} +33 -76
- package/dist/ui/THIRD_PARTY_LICENSES.txt +18 -0
- package/dist/ui/assets/app-D_nAPnHM.css +1 -0
- package/dist/ui/assets/app-DqBAtXSZ.js +111 -0
- package/dist/ui/assets/{index-BL7Ad0OA.js → index-D-_uPI2v.js} +2 -2
- package/dist/ui/index.html +1 -1
- package/dist/{ui-C4Ys26oO.mjs → ui-CNO1M0qT.mjs} +4 -4
- package/dist/{usage-C2zx-X6q.mjs → usage-BVXi0iFY.mjs} +13 -141
- package/dist/{verdict-CIy8tAyX.mjs → verdict-CMvPCpWC.mjs} +2 -2
- package/dist/{watch-DzCeqM05.mjs → watch-DVNIciHp.mjs} +10 -8
- package/dist/{workflows-Rr5w90A0.mjs → workflows-B30QkwTk.mjs} +3 -3
- package/dist/{worktrees-f6SAbum5.mjs → worktrees-DD4_TpkH.mjs} +3 -5
- package/package.json +2 -2
- package/dist/clean-D8GI_2K-.mjs +0 -91
- package/dist/decide-DlbyctOE.mjs +0 -50
- package/dist/list-zW2xKuGr.mjs +0 -117
- package/dist/remove-Dh7D_hVn.mjs +0 -201
- package/dist/report-CEN8VoUb.mjs +0 -140
- package/dist/send-MFEQZH31.mjs +0 -163
- package/dist/ui/assets/app-CAoZtku5.js +0 -75
- package/dist/ui/assets/app-QoHVi-mb.css +0 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { $t as
|
|
1
|
+
import { $t as countedTokens, Cn as MCP_FILE, Dn as endOf, Ft as reportSchemaFor, Gn as parseTemplate, Gr as isToolNode, Ht as heldTimeout, Kn as renderTemplate, Lr as markValue, Mr as beforeOf, Nr as programsRunBy, Nt as planNodeSession, On as outcomeEnd, Qr as integrationFor, Tn as serversIn, Wn as evaluate, Wr as isClaudeNode, Xr as INTEGRATIONS, Yr as timeoutMs, Zr as TOOL_PREFIX, an as stoppedEnd, en as runScope, gn as sessionDriver, ii as AGENT_DRIVERS, in as failedWith, jn as endFor, kn as END_DETAIL_LIMIT, kt as planReason, ln as lowerChild, mn as envReadsOf, nt as sessionRefusals, on as declaredProblem, rn as endedWith, sn as slotClock, tn as calledWorkflows, un as startAt, vn as declaredOutputOf, wn as mcpNotText } from "./src-tsuZRu0H.mjs";
|
|
2
|
+
import { t as runOnce } from "./run-D8divGCs.mjs";
|
|
2
3
|
import path from "node:path";
|
|
3
4
|
import { accessSync, constants, lstatSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
4
5
|
import { spawn } from "node:child_process";
|
|
@@ -323,7 +324,7 @@ const forkPrompt = (question, passOn) => [
|
|
|
323
324
|
/** The fork's report: one of the options or the pass-on, and a note. */
|
|
324
325
|
const forkReportSchema = (ids) => {
|
|
325
326
|
const node = {
|
|
326
|
-
type: "
|
|
327
|
+
type: "agent.worker",
|
|
327
328
|
prompt: "",
|
|
328
329
|
output: { schema: {
|
|
329
330
|
choice: [...ids],
|
|
@@ -537,43 +538,36 @@ const afterLateTurn = (first, later) => {
|
|
|
537
538
|
errors: first.errors
|
|
538
539
|
};
|
|
539
540
|
};
|
|
541
|
+
/** The least of the limits that are set; `undefined` with none. */
|
|
542
|
+
const least = (...limits) => {
|
|
543
|
+
const known = limits.filter((limit) => limit !== void 0);
|
|
544
|
+
return known.length === 0 ? void 0 : Math.min(...known);
|
|
545
|
+
};
|
|
546
|
+
/** A cap less what this activation used, beside what a quota says is left. */
|
|
547
|
+
const leftOf = (caps, used, quotaLeft) => least(...caps.map((cap) => cap === void 0 ? void 0 : cap - used), quotaLeft);
|
|
540
548
|
/**
|
|
541
|
-
* What another turn of a session may use. `spent
|
|
542
|
-
* activation's, which neither the node's cap nor the run's
|
|
543
|
-
* The quota has: the ledger took it as the session
|
|
544
|
-
*
|
|
549
|
+
* What another turn of a session may use. `spent`, `tokens` (counted, RFC-015)
|
|
550
|
+
* and `turns` are this activation's, which neither the node's cap nor the run's
|
|
551
|
+
* budget has counted. The quota has: the ledger took it as the session
|
|
552
|
+
* finished, so what it says is left is left. The run's tokens left have too:
|
|
553
|
+
* only the node's own `budgetTokens` takes `tokens` off. `null` when nothing
|
|
554
|
+
* is, and the turn does not start.
|
|
545
555
|
*/
|
|
546
|
-
const lateLimits = (spec,
|
|
547
|
-
const
|
|
548
|
-
const
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
556
|
+
const lateLimits = (spec, used, runLeft, quotaLeft, tokensLeft = {}) => {
|
|
557
|
+
const budgetUsd = leftOf([spec.budgetUsd, runLeft], used.spent, quotaLeft);
|
|
558
|
+
const budgetTokens = leftOf([spec.budgetTokens], used.tokens ?? 0, least(tokensLeft.run, tokensLeft.quota));
|
|
559
|
+
const maxTurns = spec.maxTurns === void 0 ? void 0 : spec.maxTurns - used.turns;
|
|
560
|
+
if ([
|
|
561
|
+
budgetUsd,
|
|
562
|
+
budgetTokens,
|
|
563
|
+
maxTurns
|
|
564
|
+
].some((left) => (left ?? 1) <= 0)) return null;
|
|
552
565
|
return {
|
|
553
566
|
...budgetUsd === void 0 ? {} : { budgetUsd },
|
|
567
|
+
...budgetTokens === void 0 ? {} : { budgetTokens },
|
|
554
568
|
...maxTurns === void 0 ? {} : { maxTurns }
|
|
555
569
|
};
|
|
556
570
|
};
|
|
557
|
-
/** What a session may spend as it starts: the least of the budget and any quota. */
|
|
558
|
-
const budgetNow = (context) => {
|
|
559
|
-
if (context.budgetLeftNow === void 0) return context.budgetLeftUsd;
|
|
560
|
-
const known = [context.budgetLeftNow(), context.quota?.().leftUsd].flatMap((left) => left === void 0 ? [] : [left]);
|
|
561
|
-
return known.length === 0 ? void 0 : Math.min(...known);
|
|
562
|
-
};
|
|
563
|
-
/**
|
|
564
|
-
* What a node's first session may spend, set aside from the run's budget in the
|
|
565
|
-
* same step that reads it (ADR-077), so a node starting beside it is never
|
|
566
|
-
* offered the same part: the least of what is left and the node's own
|
|
567
|
-
* `budgetUsd`. With nothing left, it waits for a worker running beside it to
|
|
568
|
-
* finish, as long as one may.
|
|
569
|
-
*/
|
|
570
|
-
const budgetToStart = async (context) => {
|
|
571
|
-
const left = budgetNow(context);
|
|
572
|
-
if (left !== void 0 && left <= 0) return await context.budgetFreed?.(context.signal) === true ? budgetToStart(context) : left;
|
|
573
|
-
const own = isClaudeNode(context.node) ? context.node.budgetUsd ?? context.workflow.defaults?.budgetUsd : void 0;
|
|
574
|
-
context.reserveBudget?.(own === void 0 || left === void 0 ? left : Math.min(own, left));
|
|
575
|
-
return left;
|
|
576
|
-
};
|
|
577
571
|
/**
|
|
578
572
|
* Whether a limit across runs, rather than the node's work, ended a node: a
|
|
579
573
|
* session whose cap was a quota's and that ran into it, or one its plan refused
|
|
@@ -586,7 +580,7 @@ const limitWatch = (context) => {
|
|
|
586
580
|
why = reason;
|
|
587
581
|
},
|
|
588
582
|
session: (asked) => {
|
|
589
|
-
const left = context.quota?.()
|
|
583
|
+
const { leftUsd: left, leftTokens } = context.quota?.() ?? {};
|
|
590
584
|
let refused;
|
|
591
585
|
return {
|
|
592
586
|
saw: (event) => {
|
|
@@ -594,7 +588,7 @@ const limitWatch = (context) => {
|
|
|
594
588
|
},
|
|
595
589
|
ended: (outcome) => {
|
|
596
590
|
if (refused !== void 0 && (outcome?.report ?? null) === null) why = refused;
|
|
597
|
-
const capped = left !== void 0 && asked.budgetUsd !== void 0 && asked.budgetUsd >= left;
|
|
591
|
+
const capped = left !== void 0 && asked.budgetUsd !== void 0 && asked.budgetUsd >= left || leftTokens !== void 0 && asked.budgetTokens !== void 0 && asked.budgetTokens >= leftTokens;
|
|
598
592
|
const spent = outcome !== null && outcomeEnd(outcome).kind === "budget_limit";
|
|
599
593
|
if (capped && spent) why = context.quota?.().blocked ?? "a session reached what was left of a quota";
|
|
600
594
|
}
|
|
@@ -628,6 +622,89 @@ const notStarted = (kind, reason, limited) => ({
|
|
|
628
622
|
}),
|
|
629
623
|
...limited === void 0 ? {} : { limited }
|
|
630
624
|
});
|
|
625
|
+
// ../nodes/src/session-driver.ts
|
|
626
|
+
/**
|
|
627
|
+
* @file The driver a Claude node's session starts on (core's `sessionDriver`),
|
|
628
|
+
* and, when its model names that driver (`command-code.deepseek/…`, RFC-015),
|
|
629
|
+
* the fit check on the value an item rendered: the run's own check before it
|
|
630
|
+
* started saw only the written model.
|
|
631
|
+
*/
|
|
632
|
+
/** What stops the node from running on `driver`, in one line, or nothing. */
|
|
633
|
+
const refusalOn = (context, driver, drivers) => {
|
|
634
|
+
const id = context.template ?? context.id;
|
|
635
|
+
const node = context.workflow.nodes[id];
|
|
636
|
+
const descriptor = drivers.find((d) => d.id === driver);
|
|
637
|
+
if (node === void 0 || descriptor === void 0) return void 0;
|
|
638
|
+
const refusals = sessionRefusals(id, node, context.workflow, descriptor);
|
|
639
|
+
return refusals.length === 0 ? void 0 : refusals.map((r) => r.message).join("; ");
|
|
640
|
+
};
|
|
641
|
+
/** The session's driver, or the node's result when none fits. */
|
|
642
|
+
const sessionDriverOf = (context, plan, options) => {
|
|
643
|
+
const driver = sessionDriver({
|
|
644
|
+
pinned: plan.pinned,
|
|
645
|
+
override: options.driver,
|
|
646
|
+
named: plan.driver,
|
|
647
|
+
ready: options.readyDriver
|
|
648
|
+
});
|
|
649
|
+
if (driver === void 0) return notStarted("tool_missing", "no agent driver is ready; see `ork doctor`");
|
|
650
|
+
const unfit = plan.pinned === void 0 ? void 0 : refusalOn(context, driver, options.drivers ?? AGENT_DRIVERS);
|
|
651
|
+
return unfit === void 0 ? driver : notStarted("invalid_node", unfit);
|
|
652
|
+
};
|
|
653
|
+
// ../nodes/src/start-budgets.ts
|
|
654
|
+
/** What a session may spend as it starts: the least of the budget and any quota. */
|
|
655
|
+
const budgetNow = (context) => context.budgetLeftNow === void 0 ? context.budgetLeftUsd : least(context.budgetLeftNow(), context.quota?.().leftUsd);
|
|
656
|
+
/** The counted tokens a session may use as it starts: the run's and a quota's. */
|
|
657
|
+
const tokensNow = (context) => least(context.tokensLeftNow?.(), context.quota?.().leftTokens);
|
|
658
|
+
/**
|
|
659
|
+
* What is `left` now, with `own` (the node's cap) set aside through `reserve`
|
|
660
|
+
* in the same step; with nothing left, it waits for a worker's reserve to
|
|
661
|
+
* free.
|
|
662
|
+
*/
|
|
663
|
+
const startWith = async (context, left, own, reserve) => {
|
|
664
|
+
const now = left();
|
|
665
|
+
if (now !== void 0 && now <= 0) {
|
|
666
|
+
context.reserveBudget?.(0);
|
|
667
|
+
context.reserveTokens?.(0);
|
|
668
|
+
return await context.budgetFreed?.(context.signal) === true ? startWith(context, left, own, reserve) : now;
|
|
669
|
+
}
|
|
670
|
+
reserve?.(own === void 0 || now === void 0 ? now : Math.min(own, now));
|
|
671
|
+
return now;
|
|
672
|
+
};
|
|
673
|
+
/**
|
|
674
|
+
* What a node's first session may spend, set aside from the run's budget in the
|
|
675
|
+
* same step that reads it (ADR-077), so a node starting beside it is never
|
|
676
|
+
* offered the same part: the least of what is left and the node's own
|
|
677
|
+
* `budgetUsd`. With nothing left, it waits for a worker running beside it to
|
|
678
|
+
* finish, as long as one may.
|
|
679
|
+
*/
|
|
680
|
+
const budgetToStart = (context) => startWith(context, () => budgetNow(context), isClaudeNode(context.node) ? context.node.budgetUsd ?? context.workflow.defaults?.budgetUsd : void 0, context.reserveBudget);
|
|
681
|
+
/** `budgetToStart` in counted tokens: the run's `budgetTokens` and a quota's. */
|
|
682
|
+
const tokensToStart = (context) => startWith(context, () => tokensNow(context), isClaudeNode(context.node) ? context.node.budgetTokens ?? context.workflow.defaults?.budgetTokens : void 0, context.reserveTokens);
|
|
683
|
+
/**
|
|
684
|
+
* What a node's first session may spend, in dollars and in counted tokens, set
|
|
685
|
+
* into `planOptions`; the node's result instead when nothing is left of
|
|
686
|
+
* either.
|
|
687
|
+
*/
|
|
688
|
+
const startBudgets = async (context, planOptions) => {
|
|
689
|
+
const usd = await budgetToStart(context);
|
|
690
|
+
if (usd !== void 0 && usd <= 0) return notStarted("budget_limit", "nothing is left of the run's budget");
|
|
691
|
+
if (usd !== void 0) planOptions.budgetLeftUsd = usd;
|
|
692
|
+
const waited = { done: false };
|
|
693
|
+
const tokens = await tokensToStart({
|
|
694
|
+
...context,
|
|
695
|
+
budgetFreed: async (signal) => {
|
|
696
|
+
waited.done = true;
|
|
697
|
+
return await context.budgetFreed?.(signal) ?? false;
|
|
698
|
+
}
|
|
699
|
+
});
|
|
700
|
+
if (tokens !== void 0 && tokens <= 0) return notStarted("budget_limit", "nothing is left of the run's tokens");
|
|
701
|
+
if (waited.done) {
|
|
702
|
+
context.reserveTokens?.(0);
|
|
703
|
+
return startBudgets(context, planOptions);
|
|
704
|
+
}
|
|
705
|
+
if (tokens !== void 0) planOptions.budgetLeftTokens = tokens;
|
|
706
|
+
return null;
|
|
707
|
+
};
|
|
631
708
|
// ../nodes/src/tool-output.ts
|
|
632
709
|
/**
|
|
633
710
|
* @file A tool node's structured result (`output: { format: json }`): the file
|
|
@@ -870,6 +947,28 @@ const tokenize = (command) => {
|
|
|
870
947
|
args
|
|
871
948
|
};
|
|
872
949
|
};
|
|
950
|
+
/**
|
|
951
|
+
* Runs `execute`, or, with `once: true`, skips it after a pass on these files:
|
|
952
|
+
* `null` then, and `verify.skipped` is recorded. `shown` is the scrubbed
|
|
953
|
+
* command.
|
|
954
|
+
*/
|
|
955
|
+
const runUnlessPassed = async ({ node, context, cwd, shown, environ, execute }) => {
|
|
956
|
+
if (node.once !== true) return execute();
|
|
957
|
+
const done = {};
|
|
958
|
+
const once = await runOnce({
|
|
959
|
+
cwd,
|
|
960
|
+
name: node.script === void 0 ? shown : `${shown}\n${node.script}`,
|
|
961
|
+
who: `${context.runId}/${context.id}`,
|
|
962
|
+
env: environ,
|
|
963
|
+
run: async () => {
|
|
964
|
+
done.run = await execute();
|
|
965
|
+
return done.run.exitCode;
|
|
966
|
+
}
|
|
967
|
+
});
|
|
968
|
+
if (!once.skipped) return done.run ?? execute();
|
|
969
|
+
context.skipped?.(shown, once.pass);
|
|
970
|
+
return null;
|
|
971
|
+
};
|
|
873
972
|
// ../nodes/src/tool-ends.ts
|
|
874
973
|
/**
|
|
875
974
|
* @file How a tool node ended (specs/runtime/session-ends.md): a node that
|
|
@@ -915,6 +1014,18 @@ const exitEnd = (output, run, context, program, signedOut) => {
|
|
|
915
1014
|
output
|
|
916
1015
|
}, end);
|
|
917
1016
|
};
|
|
1017
|
+
/** The result of a skipped check: it passed, and printed nothing this time. */
|
|
1018
|
+
const skippedCheck = (outputFile) => {
|
|
1019
|
+
if (outputFile !== void 0) removeOutputFile(outputFile);
|
|
1020
|
+
return endedWith({
|
|
1021
|
+
ok: true,
|
|
1022
|
+
output: {
|
|
1023
|
+
exitCode: 0,
|
|
1024
|
+
stdout: "",
|
|
1025
|
+
stderr: ""
|
|
1026
|
+
}
|
|
1027
|
+
}, endFor("done"));
|
|
1028
|
+
};
|
|
918
1029
|
// ../nodes/src/tool-scrub.ts
|
|
919
1030
|
/**
|
|
920
1031
|
* @file Masking a secret in what a program prints. A plain search, so a value
|
|
@@ -1245,7 +1356,8 @@ const clearStateFiles = (runDir, warn) => {
|
|
|
1245
1356
|
* without a shell, checked against `allow` (or the integration's default),
|
|
1246
1357
|
* its arguments and observed output fields from the integration's adapter,
|
|
1247
1358
|
* long output kept in run files. It sees who it is and the node's `env:`
|
|
1248
|
-
* (`tool-env.ts`),
|
|
1359
|
+
* (`tool-env.ts`), may return JSON (`tool-output.ts`), and may run once per
|
|
1360
|
+
* set of files (`runUnlessPassed` in `tool-command.ts`).
|
|
1249
1361
|
*/
|
|
1250
1362
|
/** How much of stdout and stderr a node's output keeps. */
|
|
1251
1363
|
const OUTPUT_LIMIT = 65536;
|
|
@@ -1346,29 +1458,43 @@ const toolExecutor = (given, options = {}) => async (context) => {
|
|
|
1346
1458
|
...node.watch === void 0 ? {} : { [STATE_ENV]: prepareStateFile(context.runDir, context.id) }
|
|
1347
1459
|
};
|
|
1348
1460
|
const names = Object.keys(nodeEnv.values);
|
|
1349
|
-
const
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1365
|
-
|
|
1461
|
+
const shown = scrub([
|
|
1462
|
+
command.program,
|
|
1463
|
+
...command.args,
|
|
1464
|
+
...node.script === void 0 ? [] : ["<script>"]
|
|
1465
|
+
].join(" "));
|
|
1466
|
+
const execute = async () => {
|
|
1467
|
+
const release = await context.machine?.slot([command.program, ...command.args].join(" "), context.signal);
|
|
1468
|
+
context.emit({
|
|
1469
|
+
type: "tool.called",
|
|
1470
|
+
id: context.id,
|
|
1471
|
+
name: scrub(command.program),
|
|
1472
|
+
input: {
|
|
1473
|
+
command: shown,
|
|
1474
|
+
...names.length === 0 ? {} : { env: names }
|
|
1475
|
+
}
|
|
1476
|
+
});
|
|
1477
|
+
const scriptFile = node.script === void 0 ? void 0 : writeScriptFile(context.runDir, context.id, context.round, node.script);
|
|
1478
|
+
const priority = context.machine?.priority;
|
|
1479
|
+
return runner(command.program, scriptFile === void 0 ? command.args : [...command.args, scriptFile], {
|
|
1480
|
+
cwd,
|
|
1481
|
+
signal: context.signal,
|
|
1482
|
+
env,
|
|
1483
|
+
...priority === void 0 ? {} : { priority }
|
|
1484
|
+
}).finally(() => {
|
|
1485
|
+
release?.();
|
|
1486
|
+
if (scriptFile !== void 0) removeOutputFile(scriptFile);
|
|
1487
|
+
});
|
|
1488
|
+
};
|
|
1489
|
+
const raw = await runUnlessPassed({
|
|
1490
|
+
node,
|
|
1491
|
+
context,
|
|
1366
1492
|
cwd,
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
})
|
|
1371
|
-
if (
|
|
1493
|
+
shown,
|
|
1494
|
+
environ,
|
|
1495
|
+
execute
|
|
1496
|
+
});
|
|
1497
|
+
if (raw === null) return skippedCheck(outputFile);
|
|
1372
1498
|
const run = {
|
|
1373
1499
|
exitCode: raw.exitCode,
|
|
1374
1500
|
stdout: scrub(raw.stdout),
|
|
@@ -1597,7 +1723,7 @@ const checkedResult = (result, { check, resumes }) => {
|
|
|
1597
1723
|
};
|
|
1598
1724
|
// ../nodes/src/claude.ts
|
|
1599
1725
|
/**
|
|
1600
|
-
* @file The Claude node type: runs
|
|
1726
|
+
* @file The Claude node type: runs an `agent.leader` or `agent.worker` as one
|
|
1601
1727
|
* session, planned with the run's outputs (and the brief its owner gave it),
|
|
1602
1728
|
* and turns its report into the node's output. A leader gets its children
|
|
1603
1729
|
* through the session's ports, and resumes its session on re-entry
|
|
@@ -1640,7 +1766,7 @@ const specFor = (spec, context) => {
|
|
|
1640
1766
|
};
|
|
1641
1767
|
return spec;
|
|
1642
1768
|
};
|
|
1643
|
-
/** Runs
|
|
1769
|
+
/** Runs an `agent.leader` or `agent.worker` as one session. */
|
|
1644
1770
|
const claudeExecutor = (options) => async (context) => {
|
|
1645
1771
|
const planOptions = planOptionsOf(context, options.inPlace);
|
|
1646
1772
|
const before = beforeOf(context.node, context.workflow.defaults);
|
|
@@ -1664,9 +1790,8 @@ const claudeExecutor = (options) => async (context) => {
|
|
|
1664
1790
|
}
|
|
1665
1791
|
const blocked = context.quota?.().blocked;
|
|
1666
1792
|
if (blocked !== void 0) return notStarted("plan_limit", blocked, blocked);
|
|
1667
|
-
const
|
|
1668
|
-
if (
|
|
1669
|
-
if (budget !== void 0) planOptions.budgetLeftUsd = budget;
|
|
1793
|
+
const refused = await startBudgets(context, planOptions);
|
|
1794
|
+
if (refused !== null) return refused;
|
|
1670
1795
|
const plan = planNodeSession(context.workflow, context.id, planOptions);
|
|
1671
1796
|
if (!plan.ok) return notStarted("invalid_node", plan.error);
|
|
1672
1797
|
const servers = namedMcpEntries(context.projectRoot, plan.mcp);
|
|
@@ -1676,12 +1801,8 @@ const claudeExecutor = (options) => async (context) => {
|
|
|
1676
1801
|
...servers.value
|
|
1677
1802
|
};
|
|
1678
1803
|
if (options.machineClaude === true) spec.machineClaude = true;
|
|
1679
|
-
const driver =
|
|
1680
|
-
|
|
1681
|
-
named: plan.driver,
|
|
1682
|
-
ready: options.readyDriver
|
|
1683
|
-
});
|
|
1684
|
-
if (driver === void 0) return notStarted("tool_missing", "no agent driver is ready; see `ork doctor`");
|
|
1804
|
+
const driver = sessionDriverOf(context, plan, options);
|
|
1805
|
+
if (typeof driver !== "string") return driver;
|
|
1685
1806
|
const runtime = await options.runtimeFor(driver);
|
|
1686
1807
|
const ports = { human: context.owner === void 0 ? withdrawnOnStop(context) : ownerFirst(context, context.owner, {
|
|
1687
1808
|
runtimeFor: options.runtimeFor,
|
|
@@ -1701,6 +1822,7 @@ const claudeExecutor = (options) => async (context) => {
|
|
|
1701
1822
|
const run = async (asked) => {
|
|
1702
1823
|
const watching = watch.session(asked);
|
|
1703
1824
|
context.reserveBudget?.(asked.budgetUsd);
|
|
1825
|
+
context.reserveTokens?.(asked.budgetTokens);
|
|
1704
1826
|
const session = runtime.start(asked, ports);
|
|
1705
1827
|
const stop = () => {
|
|
1706
1828
|
session.interrupt();
|
|
@@ -1719,6 +1841,7 @@ const claudeExecutor = (options) => async (context) => {
|
|
|
1719
1841
|
}
|
|
1720
1842
|
} finally {
|
|
1721
1843
|
context.reserveBudget?.(0);
|
|
1844
|
+
context.reserveTokens?.(0);
|
|
1722
1845
|
disconnect?.();
|
|
1723
1846
|
context.signal.removeEventListener("abort", stop);
|
|
1724
1847
|
}
|
|
@@ -1734,8 +1857,12 @@ const claudeExecutor = (options) => async (context) => {
|
|
|
1734
1857
|
}
|
|
1735
1858
|
return lateLimits(spec, {
|
|
1736
1859
|
spent: context.ownSpend?.(sessionId, usage.costUsd) ?? usage.costUsd,
|
|
1737
|
-
turns: usage.turns
|
|
1738
|
-
|
|
1860
|
+
turns: usage.turns,
|
|
1861
|
+
tokens: countedTokens(usage)
|
|
1862
|
+
}, context.budgetLeftNow?.(), quota?.leftUsd, {
|
|
1863
|
+
run: context.tokensLeftNow?.(),
|
|
1864
|
+
quota: quota?.leftTokens
|
|
1865
|
+
});
|
|
1739
1866
|
};
|
|
1740
1867
|
const resumeWith = (outcome, prompt, limits) => run({
|
|
1741
1868
|
...spec,
|
|
@@ -1824,6 +1951,7 @@ const gateExecutor = async (context) => {
|
|
|
1824
1951
|
nodeId: context.id,
|
|
1825
1952
|
question,
|
|
1826
1953
|
options,
|
|
1954
|
+
waits: true,
|
|
1827
1955
|
signal: withdraw.signal,
|
|
1828
1956
|
onNote: (given) => {
|
|
1829
1957
|
note = given;
|
|
@@ -2143,8 +2271,8 @@ const builtinExecutors = (options) => {
|
|
|
2143
2271
|
steps: tool
|
|
2144
2272
|
});
|
|
2145
2273
|
const executors = {
|
|
2146
|
-
"
|
|
2147
|
-
"
|
|
2274
|
+
"agent.leader": claude,
|
|
2275
|
+
"agent.worker": claude,
|
|
2148
2276
|
"human.gate": gateExecutor,
|
|
2149
2277
|
"workflow.call": callExecutor,
|
|
2150
2278
|
"mcp.call": mcpCallExecutor(options.maskedNames === void 0 ? {} : { maskedNames: options.maskedNames })
|