@gilbertgt/dsh-plan-orchestrator 1.0.0 → 1.0.1
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/lib/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { A as validatePlanArtifact, C as git, D as normalizeOwnedPath, E as extractPlanArtifact, O as parseValidationCommand, S as fullHead, _ as readJson, b as changedPaths, c as trustedIssueTexts, d as hashBytes, f as assertOwnedPaths, g as confined, h as atomicJson, i as ghRepository, k as schedulerPathIdentity, l as assertTrustedReceipts, m as RunStore, n as ghPreflight, o as prepareIssueBranch, p as disjointOwnership, s as remotePr, t as fetchIssue, u as receiptIndex, v as stateRoot, w as repoRoot, x as decodeUtf8Strict, y as assertRepoPathsConfined } from "./github-Cy4Pm35G.js";
|
|
2
|
-
import { n as validateFixedRoute, r as eligibleTransportFailure, t as installPlannerRoute } from "./planner-route-
|
|
2
|
+
import { n as validateFixedRoute, r as eligibleTransportFailure, t as installPlannerRoute } from "./planner-route-Z9MMuA1e.js";
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
4
|
import { execFile } from "node:child_process";
|
|
5
5
|
import { promisify } from "node:util";
|
|
@@ -862,6 +862,23 @@ const defaultRoute = () => ({
|
|
|
862
862
|
mode: "current",
|
|
863
863
|
fallbacks: []
|
|
864
864
|
});
|
|
865
|
+
/**
|
|
866
|
+
* Rebuild one route choice with every optional field present only when it holds
|
|
867
|
+
* a real value. Every DSH boundary this plugin crosses — `Session.append`,
|
|
868
|
+
* subagent descriptor snapshots, `llm.resolveCallConfig` and SDK child options —
|
|
869
|
+
* validates lossless JSON, where an explicitly `undefined` property is rejected
|
|
870
|
+
* while an absent one is fine. An unresolved (inherited) route legitimately has
|
|
871
|
+
* no provider/model yet, so those are omitted too rather than written as
|
|
872
|
+
* `undefined`; `routeChoices` filters such a candidate out before use.
|
|
873
|
+
*/
|
|
874
|
+
function losslessRouteChoice(choice) {
|
|
875
|
+
const route = {};
|
|
876
|
+
if (choice.provider !== void 0) route.provider = choice.provider;
|
|
877
|
+
if (choice.model !== void 0) route.model = choice.model;
|
|
878
|
+
if (choice.reasoningEffort !== void 0) route.reasoningEffort = choice.reasoningEffort;
|
|
879
|
+
if (choice.maxTokens !== void 0) route.maxTokens = choice.maxTokens;
|
|
880
|
+
return route;
|
|
881
|
+
}
|
|
865
882
|
const DEFAULT_SETTINGS = Object.freeze({
|
|
866
883
|
enabled: true,
|
|
867
884
|
roles: {
|
|
@@ -1311,6 +1328,39 @@ var PlannerReadOnlyGuard = class {
|
|
|
1311
1328
|
function isPlanxEvent(event) {
|
|
1312
1329
|
return Boolean(event && typeof event.type === "string" && event.type.startsWith("planx/") && event.data && typeof event.data.runId === "string");
|
|
1313
1330
|
}
|
|
1331
|
+
/**
|
|
1332
|
+
* Reject the payload shapes this plugin is known to produce accidentally.
|
|
1333
|
+
*
|
|
1334
|
+
* This is deliberately NOT a reimplementation of the DSH lossless-JSON
|
|
1335
|
+
* validator: it catches an explicitly `undefined` optional property (the shape
|
|
1336
|
+
* that caused the PREFLIGHT wedge), plus non-finite numbers, non-JSON
|
|
1337
|
+
* primitives, circular references, sparse arrays, symbol keys and non-plain
|
|
1338
|
+
* objects. It does not claim to match every DSH rule. `Session.append` remains
|
|
1339
|
+
* the authoritative boundary; this guard exists only so a bad payload fails
|
|
1340
|
+
* earlier with a path that names the offending field.
|
|
1341
|
+
*/
|
|
1342
|
+
function assertNoUndefinedEventData(value, label) {
|
|
1343
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1344
|
+
const walk = (node, path) => {
|
|
1345
|
+
if (node === void 0) throw new Error(`${label} carries an undefined value at ${path}; omit the optional property instead`);
|
|
1346
|
+
if (typeof node === "number" && !Number.isFinite(node)) throw new Error(`${label} carries a non-finite number at ${path}`);
|
|
1347
|
+
if (typeof node === "bigint" || typeof node === "function" || typeof node === "symbol") throw new Error(`${label} carries a non-JSON ${typeof node} at ${path}`);
|
|
1348
|
+
if (typeof node !== "object" || node === null) return;
|
|
1349
|
+
if (seen.has(node)) throw new Error(`${label} carries a circular reference at ${path}`);
|
|
1350
|
+
seen.add(node);
|
|
1351
|
+
if (Array.isArray(node)) {
|
|
1352
|
+
if (node.length !== Object.keys(node).length) throw new Error(`${label} carries a sparse array at ${path}`);
|
|
1353
|
+
node.forEach((item, index) => walk(item, `${path}[${index}]`));
|
|
1354
|
+
} else {
|
|
1355
|
+
const prototype = Object.getPrototypeOf(node);
|
|
1356
|
+
if (prototype !== Object.prototype && prototype !== null) throw new Error(`${label} carries a non-plain object at ${path}`);
|
|
1357
|
+
if (Object.getOwnPropertySymbols(node).length) throw new Error(`${label} carries a symbol key at ${path}`);
|
|
1358
|
+
for (const [key, item] of Object.entries(node)) walk(item, `${path}.${key}`);
|
|
1359
|
+
}
|
|
1360
|
+
seen.delete(node);
|
|
1361
|
+
};
|
|
1362
|
+
walk(value, label);
|
|
1363
|
+
}
|
|
1314
1364
|
function reducePlanxEvents(sessionId, events) {
|
|
1315
1365
|
const rows = /* @__PURE__ */ new Map();
|
|
1316
1366
|
for (const event of events) {
|
|
@@ -1523,6 +1573,28 @@ async function cleanupRunWorktrees(repo, runId, root = stateRoot()) {
|
|
|
1523
1573
|
}
|
|
1524
1574
|
//#endregion
|
|
1525
1575
|
//#region src/orchestration/service.ts
|
|
1576
|
+
const TERMINAL_PHASES = /* @__PURE__ */ new Set([
|
|
1577
|
+
"COMPLETE",
|
|
1578
|
+
"BLOCKED",
|
|
1579
|
+
"FAILED",
|
|
1580
|
+
"INTERRUPTED",
|
|
1581
|
+
"CANCELLED"
|
|
1582
|
+
]);
|
|
1583
|
+
/** Runner errors matching this shape are safety boundaries, not plain faults. */
|
|
1584
|
+
const BLOCKING_FAILURE = /(drift|ownership|blocked|inconclusive|unsafe|conflict|escape|checkpoint|tampered|stale)/i;
|
|
1585
|
+
function failureMessage(error) {
|
|
1586
|
+
if (error instanceof Error && error.message) return error.message;
|
|
1587
|
+
if (typeof error === "string" && error) return error;
|
|
1588
|
+
try {
|
|
1589
|
+
const encoded = JSON.stringify(error);
|
|
1590
|
+
if (encoded && encoded !== "{}" && encoded !== "null") return encoded;
|
|
1591
|
+
} catch {}
|
|
1592
|
+
return "unknown orchestration failure";
|
|
1593
|
+
}
|
|
1594
|
+
function terminalPhaseFor(aborted, message) {
|
|
1595
|
+
if (aborted) return "CANCELLED";
|
|
1596
|
+
return BLOCKING_FAILURE.test(message) ? "BLOCKED" : "FAILED";
|
|
1597
|
+
}
|
|
1526
1598
|
var OrchestrationService = class {
|
|
1527
1599
|
store;
|
|
1528
1600
|
runner;
|
|
@@ -1618,7 +1690,7 @@ var OrchestrationService = class {
|
|
|
1618
1690
|
this.append(session, "planx/run-phase", {
|
|
1619
1691
|
runId,
|
|
1620
1692
|
phase: view.phase,
|
|
1621
|
-
message: data.message,
|
|
1693
|
+
...data.message !== void 0 ? { message: String(data.message) } : {},
|
|
1622
1694
|
reviewRound: view.reviewRound,
|
|
1623
1695
|
at: now
|
|
1624
1696
|
});
|
|
@@ -1704,7 +1776,15 @@ var OrchestrationService = class {
|
|
|
1704
1776
|
return false;
|
|
1705
1777
|
}
|
|
1706
1778
|
if (pending.cancelled || this.#pending.get(sessionId) !== pending) return false;
|
|
1707
|
-
|
|
1779
|
+
let started;
|
|
1780
|
+
try {
|
|
1781
|
+
started = await this.start(pending.launch, pending.runId);
|
|
1782
|
+
} catch (error) {
|
|
1783
|
+
const message = `maintenance launch failed: ${failureMessage(error)}`;
|
|
1784
|
+
if (this.#pending.get(sessionId) === pending) this.#pending.delete(sessionId);
|
|
1785
|
+
await this.finalize(pending.launch, pending.runId, terminalPhaseFor(false, message), message).catch(() => {});
|
|
1786
|
+
return false;
|
|
1787
|
+
}
|
|
1708
1788
|
if (pending.cancelled) {
|
|
1709
1789
|
if (this.#pending.get(sessionId) === pending) this.#pending.delete(sessionId);
|
|
1710
1790
|
return false;
|
|
@@ -1793,7 +1873,15 @@ var OrchestrationService = class {
|
|
|
1793
1873
|
message: `Safe resume from ${diagnosis.resumeFrom}`,
|
|
1794
1874
|
at: now
|
|
1795
1875
|
});
|
|
1796
|
-
|
|
1876
|
+
try {
|
|
1877
|
+
await this.start(launch, runId);
|
|
1878
|
+
} catch (error) {
|
|
1879
|
+
await this.finalize(launch, runId, terminalPhaseFor(false, failureMessage(error)), failureMessage(error));
|
|
1880
|
+
return {
|
|
1881
|
+
ok: false,
|
|
1882
|
+
reason: failureMessage(error)
|
|
1883
|
+
};
|
|
1884
|
+
}
|
|
1797
1885
|
return {
|
|
1798
1886
|
ok: true,
|
|
1799
1887
|
resumeFrom: diagnosis.resumeFrom
|
|
@@ -1837,40 +1925,103 @@ var OrchestrationService = class {
|
|
|
1837
1925
|
return true;
|
|
1838
1926
|
}
|
|
1839
1927
|
async run(launch, runId, signal) {
|
|
1840
|
-
const initial = await this.store.readManifest(launch.sessionId, runId);
|
|
1841
|
-
initial.phase = launch.resumeFrom ?? "PREFLIGHT";
|
|
1842
|
-
initial.terminal = false;
|
|
1843
|
-
await this.store.writeManifest(initial);
|
|
1844
|
-
this.recordEvent("phase", {
|
|
1845
|
-
runId,
|
|
1846
|
-
phase: initial.phase
|
|
1847
|
-
});
|
|
1848
1928
|
let terminalPhase = "COMPLETE";
|
|
1849
1929
|
let terminalMessage;
|
|
1850
1930
|
let thrown;
|
|
1931
|
+
let failed = false;
|
|
1932
|
+
try {
|
|
1933
|
+
try {
|
|
1934
|
+
const initial = await this.store.readManifest(launch.sessionId, runId);
|
|
1935
|
+
initial.phase = launch.resumeFrom ?? "PREFLIGHT";
|
|
1936
|
+
initial.terminal = false;
|
|
1937
|
+
await this.store.writeManifest(initial);
|
|
1938
|
+
this.recordEvent("phase", {
|
|
1939
|
+
runId,
|
|
1940
|
+
phase: initial.phase
|
|
1941
|
+
});
|
|
1942
|
+
} catch (error) {
|
|
1943
|
+
thrown = error;
|
|
1944
|
+
failed = true;
|
|
1945
|
+
terminalMessage = failureMessage(error);
|
|
1946
|
+
terminalPhase = terminalPhaseFor(signal.aborted, terminalMessage);
|
|
1947
|
+
}
|
|
1948
|
+
if (!failed) try {
|
|
1949
|
+
await this.runner(launch, runId, signal);
|
|
1950
|
+
if (signal.aborted && terminalPhase === "COMPLETE") {
|
|
1951
|
+
terminalMessage = "run aborted before completion";
|
|
1952
|
+
terminalPhase = "CANCELLED";
|
|
1953
|
+
}
|
|
1954
|
+
} catch (error) {
|
|
1955
|
+
thrown = error;
|
|
1956
|
+
failed = true;
|
|
1957
|
+
terminalMessage = failureMessage(error);
|
|
1958
|
+
terminalPhase = terminalPhaseFor(signal.aborted, terminalMessage);
|
|
1959
|
+
}
|
|
1960
|
+
} finally {
|
|
1961
|
+
await this.finalize(launch, runId, terminalPhase, terminalMessage);
|
|
1962
|
+
}
|
|
1963
|
+
if (failed) throw thrown;
|
|
1964
|
+
}
|
|
1965
|
+
/**
|
|
1966
|
+
* Best-effort terminal manifest write. Returns the failure instead of
|
|
1967
|
+
* throwing so the caller can decide how to converge.
|
|
1968
|
+
*/
|
|
1969
|
+
async writeTerminal(launch, runId, phase) {
|
|
1851
1970
|
try {
|
|
1852
|
-
await this.
|
|
1971
|
+
const latest = await this.store.readManifest(launch.sessionId, runId);
|
|
1972
|
+
latest.phase = phase;
|
|
1973
|
+
latest.terminal = true;
|
|
1974
|
+
await this.store.writeManifest(latest);
|
|
1975
|
+
return { ok: true };
|
|
1853
1976
|
} catch (error) {
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1977
|
+
return {
|
|
1978
|
+
ok: false,
|
|
1979
|
+
error
|
|
1980
|
+
};
|
|
1857
1981
|
}
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1982
|
+
}
|
|
1983
|
+
/**
|
|
1984
|
+
* Persist the terminal state. Never throws: a session whose append is
|
|
1985
|
+
* unavailable must still not be left with a non-terminal manifest.
|
|
1986
|
+
*/
|
|
1987
|
+
async finalize(launch, runId, phase, message) {
|
|
1988
|
+
if (!TERMINAL_PHASES.has(phase)) throw new Error(`plan-orchestrator refusing non-terminal finalize phase: ${phase}`);
|
|
1989
|
+
const at = (/* @__PURE__ */ new Date()).toISOString();
|
|
1990
|
+
let effectivePhase = phase;
|
|
1991
|
+
let effectiveMessage = message;
|
|
1992
|
+
const written = await this.writeTerminal(launch, runId, effectivePhase);
|
|
1993
|
+
if (!written.ok) {
|
|
1994
|
+
effectivePhase = "FAILED";
|
|
1995
|
+
effectiveMessage = `terminal manifest persistence failed: ${failureMessage(written.error)}`;
|
|
1996
|
+
const retry = await this.writeTerminal(launch, runId, effectivePhase);
|
|
1997
|
+
if (!retry.ok) effectiveMessage = `${effectiveMessage}; retry failed: ${failureMessage(retry.error)}`;
|
|
1998
|
+
try {
|
|
1999
|
+
launch.agent?.session?.append?.("planx/finalize-error", {
|
|
2000
|
+
runId,
|
|
2001
|
+
phase: effectivePhase,
|
|
2002
|
+
message: effectiveMessage,
|
|
2003
|
+
at
|
|
2004
|
+
});
|
|
2005
|
+
} catch {}
|
|
2006
|
+
try {
|
|
2007
|
+
this.failView(runId, "FAILED", effectiveMessage, at);
|
|
2008
|
+
} catch {}
|
|
2009
|
+
}
|
|
2010
|
+
try {
|
|
2011
|
+
this.recordEvent("phase", {
|
|
2012
|
+
runId,
|
|
2013
|
+
phase: effectivePhase,
|
|
2014
|
+
...effectiveMessage !== void 0 ? { message: effectiveMessage } : {}
|
|
2015
|
+
});
|
|
2016
|
+
} catch {}
|
|
2017
|
+
try {
|
|
2018
|
+
this.append(launch.agent.session, "planx/run-terminal", {
|
|
2019
|
+
runId,
|
|
2020
|
+
phase: effectivePhase,
|
|
2021
|
+
...effectiveMessage ? { message: effectiveMessage } : {},
|
|
2022
|
+
at
|
|
2023
|
+
});
|
|
2024
|
+
} catch {}
|
|
1874
2025
|
}
|
|
1875
2026
|
async persistApproval(launch, runId, now) {
|
|
1876
2027
|
const dir = this.store.runDir(launch.sessionId, runId);
|
|
@@ -1918,21 +2069,24 @@ var OrchestrationService = class {
|
|
|
1918
2069
|
}
|
|
1919
2070
|
append(session, type, data) {
|
|
1920
2071
|
if (!session || typeof session.append !== "function") throw new Error(`plan-orchestrator cannot persist ${type}: session append unavailable`);
|
|
2072
|
+
assertNoUndefinedEventData(data, type);
|
|
1921
2073
|
session.append(type, data);
|
|
1922
2074
|
}
|
|
1923
|
-
failView(runId, phase, message) {
|
|
2075
|
+
failView(runId, phase, message, at = (/* @__PURE__ */ new Date()).toISOString()) {
|
|
1924
2076
|
const view = this.#views.get(runId);
|
|
1925
2077
|
if (!view) return;
|
|
1926
2078
|
view.phase = phase;
|
|
1927
2079
|
view.status = phase;
|
|
1928
2080
|
view.message = message;
|
|
1929
|
-
view.updatedAt =
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
2081
|
+
view.updatedAt = at;
|
|
2082
|
+
try {
|
|
2083
|
+
this.append(this.#agents.get(view.sessionId)?.session, "planx/run-terminal", {
|
|
2084
|
+
runId,
|
|
2085
|
+
phase,
|
|
2086
|
+
message,
|
|
2087
|
+
at
|
|
2088
|
+
});
|
|
2089
|
+
} catch {}
|
|
1936
2090
|
}
|
|
1937
2091
|
async latestReview(dir, round) {
|
|
1938
2092
|
for (let index = round; index >= 0; index--) {
|
|
@@ -2607,9 +2761,9 @@ function routeChoices(route, current) {
|
|
|
2607
2761
|
return [route.mode === "current" ? current : {
|
|
2608
2762
|
provider: route.provider,
|
|
2609
2763
|
model: route.model,
|
|
2610
|
-
reasoningEffort: route.reasoningEffort,
|
|
2611
|
-
maxTokens: route.maxTokens
|
|
2612
|
-
}, ...route.fallbacks].filter((v, i, a) => v.provider && v.model && a.findIndex((x) => x.provider === v.provider && x.model === v.model && x.reasoningEffort === v.reasoningEffort) === i);
|
|
2764
|
+
...route.reasoningEffort !== void 0 ? { reasoningEffort: route.reasoningEffort } : {},
|
|
2765
|
+
...route.maxTokens !== void 0 ? { maxTokens: route.maxTokens } : {}
|
|
2766
|
+
}, ...route.fallbacks].map(losslessRouteChoice).filter((v, i, a) => v.provider && v.model && a.findIndex((x) => x.provider === v.provider && x.model === v.model && x.reasoningEffort === v.reasoningEffort) === i);
|
|
2613
2767
|
}
|
|
2614
2768
|
async function preflightRoute(llm, choice) {
|
|
2615
2769
|
if (typeof llm?.resolveCallConfig !== "function") throw new Error("llm.resolveCallConfig unavailable");
|
|
@@ -2747,12 +2901,25 @@ function aggregateUsage(samples) {
|
|
|
2747
2901
|
//#endregion
|
|
2748
2902
|
//#region src/orchestration/engine.ts
|
|
2749
2903
|
const unionOwnership = (plan) => [...new Set(plan.tasks.flatMap((task) => task.modify))].sort();
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2904
|
+
/**
|
|
2905
|
+
* Absent route fields must not exist at all. An explicit `reasoningEffort:
|
|
2906
|
+
* undefined` is rejected by every DSH lossless-JSON boundary (subagent
|
|
2907
|
+
* descriptors, the session log, SDK child options), so each property is
|
|
2908
|
+
* constructed only when the live agent actually carries a value — including
|
|
2909
|
+
* provider/model, which an unresolved inherited agent legitimately lacks.
|
|
2910
|
+
*/
|
|
2911
|
+
const currentRoute = (agent) => {
|
|
2912
|
+
const provider = agent?.options?.provider;
|
|
2913
|
+
const model = agent?.options?.model;
|
|
2914
|
+
const reasoningEffort = agent?.options?.reasoningEffort;
|
|
2915
|
+
const maxTokens = agent?.options?.maxTokens;
|
|
2916
|
+
return {
|
|
2917
|
+
...provider !== void 0 ? { provider: String(provider) } : {},
|
|
2918
|
+
...model !== void 0 ? { model: String(model) } : {},
|
|
2919
|
+
...reasoningEffort !== void 0 ? { reasoningEffort: String(reasoningEffort) } : {},
|
|
2920
|
+
...maxTokens !== void 0 ? { maxTokens: Number(maxTokens) } : {}
|
|
2921
|
+
};
|
|
2922
|
+
};
|
|
2756
2923
|
async function resolvedChoices(ctx, settings, role, agent) {
|
|
2757
2924
|
const candidates = routeChoices(settings.roles[role], currentRoute(agent));
|
|
2758
2925
|
const good = [];
|
|
@@ -3715,7 +3882,7 @@ function apply(ctx) {
|
|
|
3715
3882
|
c.inject(["connection"], (scope) => scope.effect(() => {
|
|
3716
3883
|
let disposed = false;
|
|
3717
3884
|
let disposeTransport;
|
|
3718
|
-
import("./rpc-server-
|
|
3885
|
+
import("./rpc-server-Bdtz9NqI.js").then(({ registerRpc }) => {
|
|
3719
3886
|
if (disposed) return;
|
|
3720
3887
|
disposeTransport = registerRpc(scope.connection, {
|
|
3721
3888
|
ctx: scope,
|
|
@@ -11,10 +11,10 @@ async function validateFixedRoute(llm, route) {
|
|
|
11
11
|
if (!route.provider || !route.model) throw new Error("fixed route needs provider and model");
|
|
12
12
|
const requested = {
|
|
13
13
|
provider: route.provider,
|
|
14
|
-
model: route.model
|
|
15
|
-
...route.reasoningEffort ? { reasoningEffort: route.reasoningEffort } : {},
|
|
16
|
-
...route.maxTokens ? { maxTokens: route.maxTokens } : {}
|
|
14
|
+
model: route.model
|
|
17
15
|
};
|
|
16
|
+
if (route.reasoningEffort !== void 0) requested.reasoningEffort = route.reasoningEffort;
|
|
17
|
+
if (route.maxTokens !== void 0) requested.maxTokens = route.maxTokens;
|
|
18
18
|
if (typeof llm?.resolveCallConfig !== "function") throw new Error("DSH llm.resolveCallConfig is unavailable");
|
|
19
19
|
await llm.resolveCallConfig(requested);
|
|
20
20
|
for (const fallback of route.fallbacks) await llm.resolveCallConfig(fallback);
|
|
@@ -27,15 +27,15 @@ function routeAt(route, current, index) {
|
|
|
27
27
|
return {
|
|
28
28
|
provider: current.provider,
|
|
29
29
|
model: current.model,
|
|
30
|
-
reasoningEffort: current.reasoningEffort,
|
|
31
|
-
maxTokens: current.maxTokens
|
|
30
|
+
...current.reasoningEffort !== void 0 ? { reasoningEffort: current.reasoningEffort } : {},
|
|
31
|
+
...current.maxTokens !== void 0 ? { maxTokens: current.maxTokens } : {}
|
|
32
32
|
};
|
|
33
33
|
}
|
|
34
34
|
return {
|
|
35
35
|
provider: route.provider,
|
|
36
36
|
model: route.model,
|
|
37
|
-
reasoningEffort: route.reasoningEffort,
|
|
38
|
-
maxTokens: route.maxTokens
|
|
37
|
+
...route.reasoningEffort !== void 0 ? { reasoningEffort: route.reasoningEffort } : {},
|
|
38
|
+
...route.maxTokens !== void 0 ? { maxTokens: route.maxTokens } : {}
|
|
39
39
|
};
|
|
40
40
|
}
|
|
41
41
|
return route.fallbacks[index - 1];
|
|
@@ -51,12 +51,13 @@ function installPlannerRoute(ctx, getRoute, isPlanActive, isEnabled = () => true
|
|
|
51
51
|
const selected = routeAt(getRoute(agent), current, fallbackIndex.get(agent) ?? 0);
|
|
52
52
|
if (!selected) return current;
|
|
53
53
|
await ctx.llm.resolveCallConfig(selected);
|
|
54
|
+
const { reasoningEffort: _inheritedEffort, maxTokens: inheritedMaxTokens, ...rest } = current;
|
|
54
55
|
return {
|
|
55
|
-
...
|
|
56
|
+
...rest,
|
|
56
57
|
provider: selected.provider,
|
|
57
58
|
model: selected.model,
|
|
58
|
-
reasoningEffort: selected.reasoningEffort,
|
|
59
|
-
maxTokens: selected.maxTokens
|
|
59
|
+
...selected.reasoningEffort !== void 0 ? { reasoningEffort: selected.reasoningEffort } : {},
|
|
60
|
+
...selected.maxTokens !== void 0 ? { maxTokens: selected.maxTokens } : inheritedMaxTokens !== void 0 ? { maxTokens: inheritedMaxTokens } : {}
|
|
60
61
|
};
|
|
61
62
|
});
|
|
62
63
|
const assembly = ctx.on("system-prompt/assemble", async (assembled, context, next) => {
|