@dylanrussell/agent-router 1.0.7 → 1.1.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/README.md +61 -2
- package/dist/cli.js +51 -15
- package/dist/cli.js.map +1 -1
- package/dist/plugin.js +239 -15
- package/dist/plugin.js.map +1 -1
- package/dist/tui.js +87 -12
- package/dist/tui.js.map +1 -1
- package/package.json +1 -6
package/dist/tui.js
CHANGED
|
@@ -14615,14 +14615,26 @@ function date4(params) {
|
|
|
14615
14615
|
config(en_default());
|
|
14616
14616
|
|
|
14617
14617
|
// src/core/schema.ts
|
|
14618
|
+
var FallbackSchema = external_exports.object({
|
|
14619
|
+
model: external_exports.string().regex(/^[^/\s]+\/\S+$/, "Expected provider/model"),
|
|
14620
|
+
variant: external_exports.string().min(1).optional()
|
|
14621
|
+
}).strict();
|
|
14622
|
+
var RoutingEntrySchema = external_exports.object({
|
|
14623
|
+
model: external_exports.string().min(1),
|
|
14624
|
+
variant: external_exports.string().min(1).nullable().optional(),
|
|
14625
|
+
fallbacks: external_exports.array(FallbackSchema).max(8).optional()
|
|
14626
|
+
}).strict();
|
|
14618
14627
|
var StateFileSchema = external_exports.object({
|
|
14619
14628
|
version: external_exports.literal(1),
|
|
14620
14629
|
active: external_exports.string().min(1),
|
|
14621
14630
|
previousActive: external_exports.string().min(1).nullable(),
|
|
14622
|
-
lastSwitchedAt: external_exports.string().min(1)
|
|
14631
|
+
lastSwitchedAt: external_exports.string().min(1),
|
|
14632
|
+
fallbackAgents: external_exports.record(external_exports.string(), RoutingEntrySchema).optional()
|
|
14623
14633
|
}).strict();
|
|
14624
14634
|
var AgentEntrySchema = external_exports.object({
|
|
14625
|
-
model: external_exports.string().min(1)
|
|
14635
|
+
model: external_exports.string().min(1),
|
|
14636
|
+
variant: external_exports.string().min(1).nullable().optional(),
|
|
14637
|
+
fallbacks: external_exports.array(FallbackSchema).max(8).optional()
|
|
14626
14638
|
}).passthrough();
|
|
14627
14639
|
var StackFileSchema = external_exports.object({
|
|
14628
14640
|
agents: external_exports.record(external_exports.string(), AgentEntrySchema)
|
|
@@ -15303,6 +15315,9 @@ function collectModelRefs(stack) {
|
|
|
15303
15315
|
const refs = [];
|
|
15304
15316
|
for (const [k, v] of Object.entries(stack.agents)) {
|
|
15305
15317
|
refs.push({ path: `agents.${k}.model`, modelId: v.model });
|
|
15318
|
+
for (const [index, candidate] of (v.fallbacks ?? []).entries()) {
|
|
15319
|
+
refs.push({ path: `agents.${k}.fallbacks.${index}.model`, modelId: candidate.model });
|
|
15320
|
+
}
|
|
15306
15321
|
}
|
|
15307
15322
|
return refs;
|
|
15308
15323
|
}
|
|
@@ -15382,7 +15397,7 @@ async function applyStack(paths, name, options = {}) {
|
|
|
15382
15397
|
}
|
|
15383
15398
|
const prevState = await readState(paths.statePath);
|
|
15384
15399
|
const prevActive = prevState?.active ?? null;
|
|
15385
|
-
const displaced = { agents:
|
|
15400
|
+
const displaced = { agents: await captureAgents(paths) };
|
|
15386
15401
|
const historyId = await appendHistory(
|
|
15387
15402
|
paths.historyDir,
|
|
15388
15403
|
prevActive ?? "(none)",
|
|
@@ -15400,7 +15415,20 @@ async function applyStack(paths, name, options = {}) {
|
|
|
15400
15415
|
version: 1,
|
|
15401
15416
|
active: name,
|
|
15402
15417
|
previousActive: prevActive,
|
|
15403
|
-
lastSwitchedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
15418
|
+
lastSwitchedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
15419
|
+
fallbackAgents: Object.fromEntries(
|
|
15420
|
+
Object.entries(target.agents).filter(([, entry]) => entry.fallbacks?.length).map(([agent, entry]) => {
|
|
15421
|
+
const variant = "variant" in entry ? entry.variant : displaced.agents[agent]?.variant;
|
|
15422
|
+
return [
|
|
15423
|
+
agent,
|
|
15424
|
+
{
|
|
15425
|
+
model: entry.model,
|
|
15426
|
+
variant: typeof variant === "string" ? variant : void 0,
|
|
15427
|
+
fallbacks: entry.fallbacks
|
|
15428
|
+
}
|
|
15429
|
+
];
|
|
15430
|
+
})
|
|
15431
|
+
)
|
|
15404
15432
|
});
|
|
15405
15433
|
await trimHistory(paths.historyDir).catch(() => {
|
|
15406
15434
|
});
|
|
@@ -15416,7 +15444,7 @@ function entryOptions(entry) {
|
|
|
15416
15444
|
const rec = entry;
|
|
15417
15445
|
const out = {};
|
|
15418
15446
|
for (const [k, v] of Object.entries(rec)) {
|
|
15419
|
-
if (k === "model" || RESERVED_AGENT_KEYS.has(k)) continue;
|
|
15447
|
+
if (k === "model" || k === "fallbacks" || RESERVED_AGENT_KEYS.has(k)) continue;
|
|
15420
15448
|
out[k] = v;
|
|
15421
15449
|
}
|
|
15422
15450
|
return out;
|
|
@@ -15428,11 +15456,24 @@ function entriesToStackAgents(entries) {
|
|
|
15428
15456
|
if (!entry) continue;
|
|
15429
15457
|
const { model, options } = entry;
|
|
15430
15458
|
const stackEntry = { model };
|
|
15431
|
-
for (const [k, v] of Object.entries(options))
|
|
15459
|
+
for (const [k, v] of Object.entries(options)) {
|
|
15460
|
+
if (k !== "fallbacks") stackEntry[k] = v;
|
|
15461
|
+
}
|
|
15432
15462
|
out[name] = stackEntry;
|
|
15433
15463
|
}
|
|
15434
15464
|
return out;
|
|
15435
15465
|
}
|
|
15466
|
+
async function captureAgents(paths) {
|
|
15467
|
+
const agents = entriesToStackAgents(await readAgentEntries(paths.agentsDir));
|
|
15468
|
+
const state = await readState(paths.statePath);
|
|
15469
|
+
for (const [name, entry] of Object.entries(agents)) {
|
|
15470
|
+
const routing = state?.fallbackAgents?.[name];
|
|
15471
|
+
if (routing && routing.model === entry.model && (routing.variant ?? void 0) === (entry.variant ?? void 0)) {
|
|
15472
|
+
entry.fallbacks = routing.fallbacks;
|
|
15473
|
+
}
|
|
15474
|
+
}
|
|
15475
|
+
return agents;
|
|
15476
|
+
}
|
|
15436
15477
|
async function back(paths, n = 1, options = {}) {
|
|
15437
15478
|
if (n < 1) throw new UserError("`back -n` must be at least 1.");
|
|
15438
15479
|
const state = await readState(paths.statePath);
|
|
@@ -15702,7 +15743,16 @@ function materializeNode(node, solid) {
|
|
|
15702
15743
|
|
|
15703
15744
|
// src/tui/store.ts
|
|
15704
15745
|
function snapshotKey(active, stacks, agents = []) {
|
|
15705
|
-
return
|
|
15746
|
+
return JSON.stringify([
|
|
15747
|
+
active,
|
|
15748
|
+
stacks,
|
|
15749
|
+
agents.map((a) => [
|
|
15750
|
+
a.agent,
|
|
15751
|
+
a.model,
|
|
15752
|
+
a.variant ?? null,
|
|
15753
|
+
(a.fallbacks ?? []).map((fallback) => [fallback.model, fallback.variant ?? null])
|
|
15754
|
+
])
|
|
15755
|
+
]);
|
|
15706
15756
|
}
|
|
15707
15757
|
async function readStackSnapshot(paths) {
|
|
15708
15758
|
const [active, stacks] = await Promise.all([
|
|
@@ -15713,7 +15763,12 @@ async function readStackSnapshot(paths) {
|
|
|
15713
15763
|
if (active !== null) {
|
|
15714
15764
|
try {
|
|
15715
15765
|
const stack = await readStack(paths, active);
|
|
15716
|
-
agents = Object.entries(stack.agents).map(([agent, entry]) => ({
|
|
15766
|
+
agents = Object.entries(stack.agents).map(([agent, entry]) => ({
|
|
15767
|
+
agent,
|
|
15768
|
+
model: entry.model,
|
|
15769
|
+
variant: entry.variant ?? null,
|
|
15770
|
+
fallbacks: entry.fallbacks ?? []
|
|
15771
|
+
})).sort((a, b) => a.agent.localeCompare(b.agent));
|
|
15717
15772
|
} catch {
|
|
15718
15773
|
}
|
|
15719
15774
|
}
|
|
@@ -15761,6 +15816,9 @@ function text(content, props = {}) {
|
|
|
15761
15816
|
function restartRequired(snapshot, ctx) {
|
|
15762
15817
|
return snapshot.active !== ctx.bootActive;
|
|
15763
15818
|
}
|
|
15819
|
+
function modelLabel(assignment) {
|
|
15820
|
+
return `${assignment.model}${assignment.variant ? ` [${assignment.variant}]` : ""}`;
|
|
15821
|
+
}
|
|
15764
15822
|
function buildSidebarNodes(snapshot, ctx) {
|
|
15765
15823
|
const theme = ctx.theme ?? {};
|
|
15766
15824
|
const nodes = [text("Agent Stacks", { fg: theme.text, attributes: TEXT_ATTR_BOLD })];
|
|
@@ -15780,13 +15838,30 @@ function buildSidebarNodes(snapshot, ctx) {
|
|
|
15780
15838
|
if (snapshot.agents.length === 0) {
|
|
15781
15839
|
nodes.push(text("\u2022 (none)", { fg: theme.textMuted }));
|
|
15782
15840
|
} else {
|
|
15783
|
-
|
|
15841
|
+
nodes.push(text("Configured routing", { fg: theme.textMuted }));
|
|
15842
|
+
for (const assignment of snapshot.agents) {
|
|
15784
15843
|
nodes.push({
|
|
15785
15844
|
kind: "box",
|
|
15786
|
-
props: { flexDirection: "
|
|
15845
|
+
props: { flexDirection: "column" },
|
|
15787
15846
|
children: [
|
|
15788
|
-
|
|
15789
|
-
|
|
15847
|
+
{
|
|
15848
|
+
kind: "box",
|
|
15849
|
+
props: { flexDirection: "row", gap: 1 },
|
|
15850
|
+
children: [
|
|
15851
|
+
text("\u2022", { flexShrink: 0, style: { fg: theme.success } }),
|
|
15852
|
+
text(assignment.agent, { fg: theme.text, attributes: TEXT_ATTR_BOLD })
|
|
15853
|
+
]
|
|
15854
|
+
},
|
|
15855
|
+
{
|
|
15856
|
+
kind: "box",
|
|
15857
|
+
props: { flexDirection: "column", paddingLeft: 2 },
|
|
15858
|
+
children: [
|
|
15859
|
+
text(`Primary \u2192 ${modelLabel(assignment)}`, { fg: theme.textMuted }),
|
|
15860
|
+
...(assignment.fallbacks ?? []).map(
|
|
15861
|
+
(fallback, index) => text(`Fallback ${index + 1} \u2192 ${modelLabel(fallback)}`, { fg: theme.textMuted })
|
|
15862
|
+
)
|
|
15863
|
+
]
|
|
15864
|
+
}
|
|
15790
15865
|
]
|
|
15791
15866
|
});
|
|
15792
15867
|
}
|