@lazyingart/agintiflow 0.20.0 → 0.20.2
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/docs/model-selection.md +14 -4
- package/package.json +1 -1
- package/public/app.js +155 -23
- package/public/index.html +208 -166
- package/public/styles.css +83 -0
- package/references/model-routing-provider-design.md +6 -1
- package/scripts/smoke-cli-chat.js +21 -0
- package/scripts/smoke-model-roles.js +5 -1
- package/src/interactive-cli.js +224 -21
- package/src/model-client.js +14 -2
package/src/interactive-cli.js
CHANGED
|
@@ -584,15 +584,15 @@ function printHelp() {
|
|
|
584
584
|
" /instructions Show AGINTI.md project instructions status.",
|
|
585
585
|
" /memory Alias for /instructions.",
|
|
586
586
|
" /models Show route/main/spare/wrapper/auxiliary model roles.",
|
|
587
|
-
" /venice
|
|
587
|
+
" /venice [on|off] Toggle Venice Uncensored 1.2 for route and main roles.",
|
|
588
588
|
" /route [mode|provider/model]",
|
|
589
589
|
" Open route selector, or set routing/fast route model.",
|
|
590
590
|
" /model [provider/model] Open main-model selector, or set the active/main model.",
|
|
591
|
-
" /spare
|
|
592
|
-
"
|
|
591
|
+
" /spare [provider/model] [reasoning]",
|
|
592
|
+
" Open spare selector, or set e.g. /spare openai/gpt-5.4 medium.",
|
|
593
593
|
" /wrapper [on|off|codex model reasoning]",
|
|
594
594
|
" Configure optional external wrapper.",
|
|
595
|
-
" /auxiliary [status|grsai|venice|model
|
|
595
|
+
" /auxiliary [status|grsai|venice|model [provider/model]|on|off|image]",
|
|
596
596
|
" Manage optional auxiliary skills, including image generation.",
|
|
597
597
|
" /new Start a fresh session on the next message.",
|
|
598
598
|
" /resume <session-id> Continue a saved session.",
|
|
@@ -602,7 +602,7 @@ function printHelp() {
|
|
|
602
602
|
" /web-search on|off Enable or disable the web_search tool.",
|
|
603
603
|
" /scouts on|off|<1-10> Enable parallel DeepSeek scouts and set scout count.",
|
|
604
604
|
" /routing <mode> Set routing: smart, fast, complex, manual.",
|
|
605
|
-
" /provider
|
|
605
|
+
" /provider [name] Open provider selector, or set deepseek/openai/qwen/venice/mock.",
|
|
606
606
|
" /docker on Use docker-workspace with approved package installs.",
|
|
607
607
|
" /docker off Use host shell policy.",
|
|
608
608
|
" /latex on Use the LaTeX/PDF profile in Docker with a larger step budget.",
|
|
@@ -749,6 +749,7 @@ export function buildPromptLayout(buffer = "", cursor = 0, width = terminalWidth
|
|
|
749
749
|
const visible = promptVisibleWindow(rows, cursorRow, height);
|
|
750
750
|
const renderedRows = [];
|
|
751
751
|
let renderedCursorRow = cursorRow - visible.start;
|
|
752
|
+
const useInputPadding = options.inputPadding !== false && height >= 10;
|
|
752
753
|
|
|
753
754
|
if (options.statusLine) {
|
|
754
755
|
renderedRows.push(panelLine(`${labelText("run", { prompt: true })}${compactLine(options.statusLine, lineWidth - 10)}`, ansi.statusBg, lineWidth));
|
|
@@ -771,11 +772,20 @@ export function buildPromptLayout(buffer = "", cursor = 0, width = terminalWidth
|
|
|
771
772
|
renderedCursorRow += 1;
|
|
772
773
|
}
|
|
773
774
|
|
|
775
|
+
if (useInputPadding) {
|
|
776
|
+
renderedRows.push(panelLine("", ansi.userBg, lineWidth));
|
|
777
|
+
renderedCursorRow += 1;
|
|
778
|
+
}
|
|
779
|
+
|
|
774
780
|
for (const row of rows.slice(visible.start, visible.end)) {
|
|
775
781
|
const content = safeBuffer ? `${row.prefix}${row.text}` : `${row.prefix}${emptyHint}`;
|
|
776
782
|
renderedRows.push(panelLine(content, ansi.userBg, lineWidth));
|
|
777
783
|
}
|
|
778
784
|
|
|
785
|
+
if (useInputPadding) {
|
|
786
|
+
renderedRows.push(panelLine("", ansi.userBg, lineWidth));
|
|
787
|
+
}
|
|
788
|
+
|
|
779
789
|
if (visible.bottomHidden > 0) {
|
|
780
790
|
renderedRows.push(panelLine(` ... ${visible.bottomHidden} later input row${visible.bottomHidden === 1 ? "" : "s"}`, ansi.systemBg, lineWidth));
|
|
781
791
|
}
|
|
@@ -1258,6 +1268,11 @@ class LiveRunInput {
|
|
|
1258
1268
|
async submitAsap() {
|
|
1259
1269
|
const content = this.buffer.trim();
|
|
1260
1270
|
if (!content) return;
|
|
1271
|
+
if (content.startsWith("/")) {
|
|
1272
|
+
this.printLine(`${label("warn", ansi.red)} Slash commands are disabled while a run is active. Press Esc/Ctrl+C to stop, or wait until idle.`);
|
|
1273
|
+
this.setStatus(`running · command ${compactLine(content, 24)} not accepted during active run`);
|
|
1274
|
+
return;
|
|
1275
|
+
}
|
|
1261
1276
|
const item = {
|
|
1262
1277
|
id: `cli-asap-${Date.now()}-${Math.random().toString(16).slice(2)}`,
|
|
1263
1278
|
content,
|
|
@@ -1282,6 +1297,11 @@ class LiveRunInput {
|
|
|
1282
1297
|
queueAfterFinish() {
|
|
1283
1298
|
const content = this.buffer.trim();
|
|
1284
1299
|
if (!content) return;
|
|
1300
|
+
if (content.startsWith("/")) {
|
|
1301
|
+
this.printLine(`${label("warn", ansi.red)} Slash commands cannot be queued during a run. Wait until idle, then run ${content}.`);
|
|
1302
|
+
this.setStatus(`running · command ${compactLine(content, 24)} not queued`);
|
|
1303
|
+
return;
|
|
1304
|
+
}
|
|
1285
1305
|
this.pendingQueued.push({
|
|
1286
1306
|
id: `cli-queued-${Date.now()}-${Math.random().toString(16).slice(2)}`,
|
|
1287
1307
|
content,
|
|
@@ -1596,6 +1616,35 @@ function parseProviderModel(value, fallbackProvider = "") {
|
|
|
1596
1616
|
return { provider: fallbackProvider, model: text };
|
|
1597
1617
|
}
|
|
1598
1618
|
|
|
1619
|
+
function useDeepSeekDefaults(state) {
|
|
1620
|
+
state.routingMode = "smart";
|
|
1621
|
+
state.provider = "deepseek";
|
|
1622
|
+
state.model = "";
|
|
1623
|
+
state.routeProvider = "deepseek";
|
|
1624
|
+
state.routeModel = "deepseek-v4-flash";
|
|
1625
|
+
state.mainProvider = "deepseek";
|
|
1626
|
+
state.mainModel = "deepseek-v4-pro";
|
|
1627
|
+
}
|
|
1628
|
+
|
|
1629
|
+
function useVeniceDefaults(state) {
|
|
1630
|
+
state.routingMode = "smart";
|
|
1631
|
+
state.provider = "deepseek";
|
|
1632
|
+
state.model = "";
|
|
1633
|
+
state.routeProvider = "venice";
|
|
1634
|
+
state.routeModel = "venice-uncensored-1-2";
|
|
1635
|
+
state.mainProvider = "venice";
|
|
1636
|
+
state.mainModel = "venice-uncensored-1-2";
|
|
1637
|
+
}
|
|
1638
|
+
|
|
1639
|
+
function isVeniceDefaultActive(state) {
|
|
1640
|
+
return (
|
|
1641
|
+
state.routeProvider === "venice" &&
|
|
1642
|
+
state.routeModel === "venice-uncensored-1-2" &&
|
|
1643
|
+
state.mainProvider === "venice" &&
|
|
1644
|
+
state.mainModel === "venice-uncensored-1-2"
|
|
1645
|
+
);
|
|
1646
|
+
}
|
|
1647
|
+
|
|
1599
1648
|
function printModelRoles(state) {
|
|
1600
1649
|
const roles = getModelRoleDefaults({
|
|
1601
1650
|
routeProvider: state.routeProvider,
|
|
@@ -1669,6 +1718,7 @@ function modelRoleChoices(role = "main") {
|
|
|
1669
1718
|
label: "DeepSeek V4 Pro",
|
|
1670
1719
|
description: "complex coding, debugging, writing, and long tasks",
|
|
1671
1720
|
main: true,
|
|
1721
|
+
spare: true,
|
|
1672
1722
|
},
|
|
1673
1723
|
{
|
|
1674
1724
|
provider: "venice",
|
|
@@ -1677,6 +1727,7 @@ function modelRoleChoices(role = "main") {
|
|
|
1677
1727
|
description: "Venice text route; use /auth venice if missing",
|
|
1678
1728
|
route: true,
|
|
1679
1729
|
main: true,
|
|
1730
|
+
spare: true,
|
|
1680
1731
|
},
|
|
1681
1732
|
{
|
|
1682
1733
|
provider: "openai",
|
|
@@ -1684,6 +1735,7 @@ function modelRoleChoices(role = "main") {
|
|
|
1684
1735
|
label: "OpenAI GPT-5.5",
|
|
1685
1736
|
description: "frontier spare/manual model",
|
|
1686
1737
|
main: true,
|
|
1738
|
+
spare: true,
|
|
1687
1739
|
},
|
|
1688
1740
|
{
|
|
1689
1741
|
provider: "openai",
|
|
@@ -1691,6 +1743,7 @@ function modelRoleChoices(role = "main") {
|
|
|
1691
1743
|
label: "OpenAI GPT-5.4",
|
|
1692
1744
|
description: "strong everyday coding spare",
|
|
1693
1745
|
main: true,
|
|
1746
|
+
spare: true,
|
|
1694
1747
|
},
|
|
1695
1748
|
{
|
|
1696
1749
|
provider: "openai",
|
|
@@ -1698,6 +1751,7 @@ function modelRoleChoices(role = "main") {
|
|
|
1698
1751
|
label: "OpenAI GPT-5.4 Mini",
|
|
1699
1752
|
description: "small fast spare route",
|
|
1700
1753
|
route: true,
|
|
1754
|
+
spare: true,
|
|
1701
1755
|
},
|
|
1702
1756
|
{
|
|
1703
1757
|
provider: "qwen",
|
|
@@ -1712,6 +1766,7 @@ function modelRoleChoices(role = "main") {
|
|
|
1712
1766
|
label: "Qwen Max",
|
|
1713
1767
|
description: "larger Qwen route",
|
|
1714
1768
|
main: true,
|
|
1769
|
+
spare: true,
|
|
1715
1770
|
},
|
|
1716
1771
|
{
|
|
1717
1772
|
provider: "mock",
|
|
@@ -1720,12 +1775,81 @@ function modelRoleChoices(role = "main") {
|
|
|
1720
1775
|
description: "local deterministic test route",
|
|
1721
1776
|
route: true,
|
|
1722
1777
|
main: true,
|
|
1778
|
+
spare: true,
|
|
1779
|
+
},
|
|
1780
|
+
{
|
|
1781
|
+
provider: "grsai",
|
|
1782
|
+
model: "nano-banana-2",
|
|
1783
|
+
label: "GRS AI Nano Banana",
|
|
1784
|
+
description: "default auxiliary image model",
|
|
1785
|
+
auxiliary: true,
|
|
1786
|
+
},
|
|
1787
|
+
{
|
|
1788
|
+
provider: "venice",
|
|
1789
|
+
model: "gpt-image-2",
|
|
1790
|
+
label: "Venice GPT Image 2",
|
|
1791
|
+
description: "high-quality Venice image generation",
|
|
1792
|
+
auxiliary: true,
|
|
1793
|
+
},
|
|
1794
|
+
{
|
|
1795
|
+
provider: "venice",
|
|
1796
|
+
model: "nano-banana-2",
|
|
1797
|
+
label: "Venice Nano Banana 2",
|
|
1798
|
+
description: "Venice image generation route",
|
|
1799
|
+
auxiliary: true,
|
|
1800
|
+
},
|
|
1801
|
+
];
|
|
1802
|
+
const filtered = common.filter((item) => {
|
|
1803
|
+
if (role === "route") return item.route;
|
|
1804
|
+
if (role === "spare") return item.spare;
|
|
1805
|
+
if (role === "auxiliary") return item.auxiliary;
|
|
1806
|
+
return item.main;
|
|
1807
|
+
});
|
|
1808
|
+
if (role === "route") {
|
|
1809
|
+
return filtered.sort((a, b) => Number(b.model === "deepseek-v4-flash") - Number(a.model === "deepseek-v4-flash"));
|
|
1810
|
+
}
|
|
1811
|
+
if (role === "spare") {
|
|
1812
|
+
return filtered.sort((a, b) => Number(b.model === "gpt-5.4") - Number(a.model === "gpt-5.4"));
|
|
1813
|
+
}
|
|
1814
|
+
if (role === "auxiliary") {
|
|
1815
|
+
return filtered.sort((a, b) => Number(b.provider === "grsai") - Number(a.provider === "grsai"));
|
|
1816
|
+
}
|
|
1817
|
+
return filtered.sort((a, b) => Number(b.model === "deepseek-v4-pro") - Number(a.model === "deepseek-v4-pro"));
|
|
1818
|
+
}
|
|
1819
|
+
|
|
1820
|
+
function providerChoices() {
|
|
1821
|
+
return [
|
|
1822
|
+
{
|
|
1823
|
+
provider: "deepseek",
|
|
1824
|
+
model: "deepseek-v4-flash",
|
|
1825
|
+
label: "DeepSeek",
|
|
1826
|
+
description: "default smart route with flash/pro roles",
|
|
1827
|
+
},
|
|
1828
|
+
{
|
|
1829
|
+
provider: "openai",
|
|
1830
|
+
model: "gpt-5.4",
|
|
1831
|
+
label: "OpenAI",
|
|
1832
|
+
description: "manual GPT route; use /model for exact model",
|
|
1833
|
+
},
|
|
1834
|
+
{
|
|
1835
|
+
provider: "venice",
|
|
1836
|
+
model: "venice-uncensored-1-2",
|
|
1837
|
+
label: "Venice",
|
|
1838
|
+
description: "manual Venice route; /venice toggles route+main roles",
|
|
1839
|
+
},
|
|
1840
|
+
{
|
|
1841
|
+
provider: "qwen",
|
|
1842
|
+
model: "qwen-plus",
|
|
1843
|
+
label: "Qwen",
|
|
1844
|
+
description: "manual Qwen route",
|
|
1845
|
+
},
|
|
1846
|
+
{
|
|
1847
|
+
provider: "mock",
|
|
1848
|
+
model: "mock-agent",
|
|
1849
|
+
label: "Mock local",
|
|
1850
|
+
description: "deterministic offline smoke-test provider",
|
|
1723
1851
|
},
|
|
1724
1852
|
];
|
|
1725
|
-
const filtered = common.filter((item) => (role === "route" ? item.route : item.main));
|
|
1726
|
-
return role === "route"
|
|
1727
|
-
? filtered.sort((a, b) => Number(b.model === "deepseek-v4-flash") - Number(a.model === "deepseek-v4-flash"))
|
|
1728
|
-
: filtered.sort((a, b) => Number(b.model === "deepseek-v4-pro") - Number(a.model === "deepseek-v4-pro"));
|
|
1729
1853
|
}
|
|
1730
1854
|
|
|
1731
1855
|
function modelChoiceLine(option) {
|
|
@@ -1763,6 +1887,7 @@ function selectModelChoice({ title, subtitle, options, initialIndex = 0 }) {
|
|
|
1763
1887
|
return new Promise((resolve) => {
|
|
1764
1888
|
emitKeypressEvents(input);
|
|
1765
1889
|
const wasRaw = Boolean(input.isRaw);
|
|
1890
|
+
const startedAt = Date.now();
|
|
1766
1891
|
let selectedIndex = clamp(initialIndex, 0, Math.max(options.length - 1, 0));
|
|
1767
1892
|
let lineCount = 0;
|
|
1768
1893
|
const cleanup = () => {
|
|
@@ -1799,6 +1924,7 @@ function selectModelChoice({ title, subtitle, options, initialIndex = 0 }) {
|
|
|
1799
1924
|
return;
|
|
1800
1925
|
}
|
|
1801
1926
|
if (key.name === "return" || key.name === "enter" || key.sequence === "\r") {
|
|
1927
|
+
if (Date.now() - startedAt < 120) return;
|
|
1802
1928
|
finish(options[selectedIndex]);
|
|
1803
1929
|
}
|
|
1804
1930
|
};
|
|
@@ -1812,14 +1938,35 @@ function selectModelChoice({ title, subtitle, options, initialIndex = 0 }) {
|
|
|
1812
1938
|
|
|
1813
1939
|
async function pickModelRole(role, state) {
|
|
1814
1940
|
const options = modelRoleChoices(role);
|
|
1815
|
-
const currentProvider =
|
|
1816
|
-
|
|
1941
|
+
const currentProvider =
|
|
1942
|
+
role === "route"
|
|
1943
|
+
? state.routeProvider || "deepseek"
|
|
1944
|
+
: role === "spare"
|
|
1945
|
+
? state.spareProvider || "openai"
|
|
1946
|
+
: role === "auxiliary"
|
|
1947
|
+
? state.auxiliaryProvider || "grsai"
|
|
1948
|
+
: state.mainProvider || state.provider || "deepseek";
|
|
1949
|
+
const currentModel =
|
|
1950
|
+
role === "route"
|
|
1951
|
+
? state.routeModel || "deepseek-v4-flash"
|
|
1952
|
+
: role === "spare"
|
|
1953
|
+
? state.spareModel || "gpt-5.4"
|
|
1954
|
+
: role === "auxiliary"
|
|
1955
|
+
? state.auxiliaryModel || "nano-banana-2"
|
|
1956
|
+
: state.mainModel || "deepseek-v4-pro";
|
|
1817
1957
|
const initialIndex = Math.max(
|
|
1818
1958
|
options.findIndex((item) => item.provider === currentProvider && item.model === currentModel),
|
|
1819
1959
|
0
|
|
1820
1960
|
);
|
|
1821
1961
|
const selected = await selectModelChoice({
|
|
1822
|
-
title:
|
|
1962
|
+
title:
|
|
1963
|
+
role === "route"
|
|
1964
|
+
? "Select route model"
|
|
1965
|
+
: role === "spare"
|
|
1966
|
+
? "Select spare model"
|
|
1967
|
+
: role === "auxiliary"
|
|
1968
|
+
? "Select auxiliary model"
|
|
1969
|
+
: "Select main model",
|
|
1823
1970
|
subtitle: "Up/Down/Left/Right selects, Enter confirms, Esc cancels.",
|
|
1824
1971
|
options,
|
|
1825
1972
|
initialIndex,
|
|
@@ -1833,6 +1980,16 @@ async function pickModelRole(role, state) {
|
|
|
1833
1980
|
state.routeProvider = selected.provider;
|
|
1834
1981
|
state.routeModel = selected.model;
|
|
1835
1982
|
printSystemLine(`route=${state.routeProvider}/${state.routeModel}`);
|
|
1983
|
+
} else if (role === "spare") {
|
|
1984
|
+
state.spareProvider = selected.provider;
|
|
1985
|
+
state.spareModel = selected.model;
|
|
1986
|
+
state.spareReasoning = state.spareReasoning || "medium";
|
|
1987
|
+
printSystemLine(`spare=${state.spareProvider}/${state.spareModel} reasoning=${state.spareReasoning}`);
|
|
1988
|
+
} else if (role === "auxiliary") {
|
|
1989
|
+
state.auxiliaryProvider = selected.provider;
|
|
1990
|
+
state.auxiliaryModel = selected.model;
|
|
1991
|
+
state.allowAuxiliaryTools = true;
|
|
1992
|
+
printSystemLine(`auxiliary=${state.auxiliaryProvider}/${state.auxiliaryModel}`);
|
|
1836
1993
|
} else {
|
|
1837
1994
|
state.mainProvider = selected.provider;
|
|
1838
1995
|
state.mainModel = selected.model;
|
|
@@ -1841,6 +1998,28 @@ async function pickModelRole(role, state) {
|
|
|
1841
1998
|
return true;
|
|
1842
1999
|
}
|
|
1843
2000
|
|
|
2001
|
+
async function pickProvider(state) {
|
|
2002
|
+
const options = providerChoices();
|
|
2003
|
+
const currentProvider = state.provider || "deepseek";
|
|
2004
|
+
const initialIndex = Math.max(
|
|
2005
|
+
options.findIndex((item) => item.provider === currentProvider),
|
|
2006
|
+
0
|
|
2007
|
+
);
|
|
2008
|
+
const selected = await selectModelChoice({
|
|
2009
|
+
title: "Select provider",
|
|
2010
|
+
subtitle: "Up/Down/Left/Right selects, Enter confirms, Esc cancels.",
|
|
2011
|
+
options,
|
|
2012
|
+
initialIndex,
|
|
2013
|
+
});
|
|
2014
|
+
if (!selected) return false;
|
|
2015
|
+
|
|
2016
|
+
state.provider = selected.provider;
|
|
2017
|
+
state.model = selected.model;
|
|
2018
|
+
state.routingMode = selected.provider === "deepseek" ? "smart" : "manual";
|
|
2019
|
+
printSystemLine(`provider=${state.provider} model=${state.model} routing=${state.routingMode}`);
|
|
2020
|
+
return true;
|
|
2021
|
+
}
|
|
2022
|
+
|
|
1844
2023
|
async function maybeOnboardDeepSeekKey(state) {
|
|
1845
2024
|
if (!shouldPromptForDeepSeek(state, process.cwd())) return;
|
|
1846
2025
|
|
|
@@ -1966,7 +2145,13 @@ async function handleCommand(line, state, packageDir) {
|
|
|
1966
2145
|
return true;
|
|
1967
2146
|
}
|
|
1968
2147
|
if (action.startsWith("model")) {
|
|
1969
|
-
const
|
|
2148
|
+
const modelValue = action.replace(/^model\s*/, "");
|
|
2149
|
+
if (!modelValue.trim() && input.isTTY && output.isTTY && typeof input.setRawMode === "function") {
|
|
2150
|
+
const changed = await pickModelRole("auxiliary", state);
|
|
2151
|
+
if (!changed) printSystemLine(`auxiliary=${state.auxiliaryProvider || "grsai"}/${state.auxiliaryModel || "nano-banana-2"}`);
|
|
2152
|
+
return true;
|
|
2153
|
+
}
|
|
2154
|
+
const selected = parseProviderModel(modelValue, state.auxiliaryProvider || "grsai");
|
|
1970
2155
|
state.auxiliaryProvider = selected.provider || "grsai";
|
|
1971
2156
|
state.auxiliaryModel = selected.model || state.auxiliaryModel || "nano-banana-2";
|
|
1972
2157
|
printSystemLine(`auxiliary=${state.auxiliaryProvider}/${state.auxiliaryModel}`);
|
|
@@ -2067,15 +2252,19 @@ async function handleCommand(line, state, packageDir) {
|
|
|
2067
2252
|
return true;
|
|
2068
2253
|
}
|
|
2069
2254
|
if (command === "venice") {
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2076
|
-
|
|
2255
|
+
const action = value || (isVeniceDefaultActive(state) ? "off" : "on");
|
|
2256
|
+
if (action === "off" || action === "deepseek" || action === "default") {
|
|
2257
|
+
useDeepSeekDefaults(state);
|
|
2258
|
+
printSystemLine("venice=off routing=smart route=deepseek/deepseek-v4-flash main=deepseek/deepseek-v4-pro");
|
|
2259
|
+
return true;
|
|
2260
|
+
}
|
|
2261
|
+
if (action !== "on" && action !== "venice") {
|
|
2262
|
+
printAgentMessage("Usage: /venice [on|off]. No argument toggles between Venice and DeepSeek defaults.");
|
|
2263
|
+
return true;
|
|
2264
|
+
}
|
|
2265
|
+
useVeniceDefaults(state);
|
|
2077
2266
|
const keys = providerKeyStatus(process.cwd());
|
|
2078
|
-
printSystemLine("routing=smart route=venice/venice-uncensored-1-2 main=venice/venice-uncensored-1-2");
|
|
2267
|
+
printSystemLine("venice=on routing=smart route=venice/venice-uncensored-1-2 main=venice/venice-uncensored-1-2");
|
|
2079
2268
|
if (!keys.venice) {
|
|
2080
2269
|
printAgentMessage("Venice model roles are selected, but no Venice key is configured. Run `/auth venice` to save one.");
|
|
2081
2270
|
}
|
|
@@ -2144,6 +2333,11 @@ async function handleCommand(line, state, packageDir) {
|
|
|
2144
2333
|
}
|
|
2145
2334
|
if (command === "spare") {
|
|
2146
2335
|
if (!value) {
|
|
2336
|
+
if (input.isTTY && output.isTTY && typeof input.setRawMode === "function") {
|
|
2337
|
+
const changed = await pickModelRole("spare", state);
|
|
2338
|
+
if (!changed) printSystemLine(`spare=${state.spareProvider}/${state.spareModel} reasoning=${state.spareReasoning}`);
|
|
2339
|
+
return true;
|
|
2340
|
+
}
|
|
2147
2341
|
printAgentMessage(`Spare model: ${state.spareProvider}/${state.spareModel} reasoning=${state.spareReasoning}`);
|
|
2148
2342
|
return true;
|
|
2149
2343
|
}
|
|
@@ -2182,6 +2376,15 @@ async function handleCommand(line, state, packageDir) {
|
|
|
2182
2376
|
return true;
|
|
2183
2377
|
}
|
|
2184
2378
|
if (command === "provider") {
|
|
2379
|
+
if (!value) {
|
|
2380
|
+
if (input.isTTY && output.isTTY && typeof input.setRawMode === "function") {
|
|
2381
|
+
const changed = await pickProvider(state);
|
|
2382
|
+
if (!changed) printSystemLine(`provider=${state.provider || "auto"} model=${state.model || "auto"}`);
|
|
2383
|
+
return true;
|
|
2384
|
+
}
|
|
2385
|
+
printAgentMessage(`Provider: ${state.provider || "auto"}\nUse /provider deepseek|openai|qwen|venice|mock.`);
|
|
2386
|
+
return true;
|
|
2387
|
+
}
|
|
2185
2388
|
state.provider = value === "auto" ? "" : value;
|
|
2186
2389
|
printSystemLine(`provider=${state.provider || "auto"}`);
|
|
2187
2390
|
return true;
|
package/src/model-client.js
CHANGED
|
@@ -58,7 +58,19 @@ function prepareMessages(config, messages) {
|
|
|
58
58
|
}
|
|
59
59
|
|
|
60
60
|
function requestOptions(config) {
|
|
61
|
-
|
|
61
|
+
const timeout = Number(config.modelTimeoutMs || process.env.AGINTI_MODEL_TIMEOUT_MS || 90000);
|
|
62
|
+
return {
|
|
63
|
+
...(config.abortSignal ? { signal: config.abortSignal } : {}),
|
|
64
|
+
...(Number.isFinite(timeout) && timeout > 0 ? { timeout } : {}),
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function toolChoiceForProvider(config, messages = []) {
|
|
69
|
+
if (config.provider !== "venice") return "auto";
|
|
70
|
+
|
|
71
|
+
// Venice accepts OpenAI tool calls but often treats the first "auto" call as plain chat.
|
|
72
|
+
// Require one tool call to enter the agent loop, then allow normal answer/finish behavior.
|
|
73
|
+
return messages.some((message) => message.role === "tool") ? "auto" : "required";
|
|
62
74
|
}
|
|
63
75
|
|
|
64
76
|
function mockCommandForGoal(goal = "") {
|
|
@@ -858,7 +870,7 @@ export async function requestNextStep(client, config, messages) {
|
|
|
858
870
|
{
|
|
859
871
|
model: config.model,
|
|
860
872
|
temperature: 0,
|
|
861
|
-
tool_choice:
|
|
873
|
+
tool_choice: toolChoiceForProvider(config, messages),
|
|
862
874
|
parallel_tool_calls: false,
|
|
863
875
|
messages: prepareMessages(config, messages),
|
|
864
876
|
tools,
|