@lazyingart/agintiflow 0.20.1 → 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 +10 -0
- package/scripts/smoke-model-roles.js +5 -1
- package/src/interactive-cli.js +214 -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.",
|
|
@@ -1268,6 +1268,11 @@ class LiveRunInput {
|
|
|
1268
1268
|
async submitAsap() {
|
|
1269
1269
|
const content = this.buffer.trim();
|
|
1270
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
|
+
}
|
|
1271
1276
|
const item = {
|
|
1272
1277
|
id: `cli-asap-${Date.now()}-${Math.random().toString(16).slice(2)}`,
|
|
1273
1278
|
content,
|
|
@@ -1292,6 +1297,11 @@ class LiveRunInput {
|
|
|
1292
1297
|
queueAfterFinish() {
|
|
1293
1298
|
const content = this.buffer.trim();
|
|
1294
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
|
+
}
|
|
1295
1305
|
this.pendingQueued.push({
|
|
1296
1306
|
id: `cli-queued-${Date.now()}-${Math.random().toString(16).slice(2)}`,
|
|
1297
1307
|
content,
|
|
@@ -1606,6 +1616,35 @@ function parseProviderModel(value, fallbackProvider = "") {
|
|
|
1606
1616
|
return { provider: fallbackProvider, model: text };
|
|
1607
1617
|
}
|
|
1608
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
|
+
|
|
1609
1648
|
function printModelRoles(state) {
|
|
1610
1649
|
const roles = getModelRoleDefaults({
|
|
1611
1650
|
routeProvider: state.routeProvider,
|
|
@@ -1679,6 +1718,7 @@ function modelRoleChoices(role = "main") {
|
|
|
1679
1718
|
label: "DeepSeek V4 Pro",
|
|
1680
1719
|
description: "complex coding, debugging, writing, and long tasks",
|
|
1681
1720
|
main: true,
|
|
1721
|
+
spare: true,
|
|
1682
1722
|
},
|
|
1683
1723
|
{
|
|
1684
1724
|
provider: "venice",
|
|
@@ -1687,6 +1727,7 @@ function modelRoleChoices(role = "main") {
|
|
|
1687
1727
|
description: "Venice text route; use /auth venice if missing",
|
|
1688
1728
|
route: true,
|
|
1689
1729
|
main: true,
|
|
1730
|
+
spare: true,
|
|
1690
1731
|
},
|
|
1691
1732
|
{
|
|
1692
1733
|
provider: "openai",
|
|
@@ -1694,6 +1735,7 @@ function modelRoleChoices(role = "main") {
|
|
|
1694
1735
|
label: "OpenAI GPT-5.5",
|
|
1695
1736
|
description: "frontier spare/manual model",
|
|
1696
1737
|
main: true,
|
|
1738
|
+
spare: true,
|
|
1697
1739
|
},
|
|
1698
1740
|
{
|
|
1699
1741
|
provider: "openai",
|
|
@@ -1701,6 +1743,7 @@ function modelRoleChoices(role = "main") {
|
|
|
1701
1743
|
label: "OpenAI GPT-5.4",
|
|
1702
1744
|
description: "strong everyday coding spare",
|
|
1703
1745
|
main: true,
|
|
1746
|
+
spare: true,
|
|
1704
1747
|
},
|
|
1705
1748
|
{
|
|
1706
1749
|
provider: "openai",
|
|
@@ -1708,6 +1751,7 @@ function modelRoleChoices(role = "main") {
|
|
|
1708
1751
|
label: "OpenAI GPT-5.4 Mini",
|
|
1709
1752
|
description: "small fast spare route",
|
|
1710
1753
|
route: true,
|
|
1754
|
+
spare: true,
|
|
1711
1755
|
},
|
|
1712
1756
|
{
|
|
1713
1757
|
provider: "qwen",
|
|
@@ -1722,6 +1766,7 @@ function modelRoleChoices(role = "main") {
|
|
|
1722
1766
|
label: "Qwen Max",
|
|
1723
1767
|
description: "larger Qwen route",
|
|
1724
1768
|
main: true,
|
|
1769
|
+
spare: true,
|
|
1725
1770
|
},
|
|
1726
1771
|
{
|
|
1727
1772
|
provider: "mock",
|
|
@@ -1730,12 +1775,81 @@ function modelRoleChoices(role = "main") {
|
|
|
1730
1775
|
description: "local deterministic test route",
|
|
1731
1776
|
route: true,
|
|
1732
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",
|
|
1733
1851
|
},
|
|
1734
1852
|
];
|
|
1735
|
-
const filtered = common.filter((item) => (role === "route" ? item.route : item.main));
|
|
1736
|
-
return role === "route"
|
|
1737
|
-
? filtered.sort((a, b) => Number(b.model === "deepseek-v4-flash") - Number(a.model === "deepseek-v4-flash"))
|
|
1738
|
-
: filtered.sort((a, b) => Number(b.model === "deepseek-v4-pro") - Number(a.model === "deepseek-v4-pro"));
|
|
1739
1853
|
}
|
|
1740
1854
|
|
|
1741
1855
|
function modelChoiceLine(option) {
|
|
@@ -1773,6 +1887,7 @@ function selectModelChoice({ title, subtitle, options, initialIndex = 0 }) {
|
|
|
1773
1887
|
return new Promise((resolve) => {
|
|
1774
1888
|
emitKeypressEvents(input);
|
|
1775
1889
|
const wasRaw = Boolean(input.isRaw);
|
|
1890
|
+
const startedAt = Date.now();
|
|
1776
1891
|
let selectedIndex = clamp(initialIndex, 0, Math.max(options.length - 1, 0));
|
|
1777
1892
|
let lineCount = 0;
|
|
1778
1893
|
const cleanup = () => {
|
|
@@ -1809,6 +1924,7 @@ function selectModelChoice({ title, subtitle, options, initialIndex = 0 }) {
|
|
|
1809
1924
|
return;
|
|
1810
1925
|
}
|
|
1811
1926
|
if (key.name === "return" || key.name === "enter" || key.sequence === "\r") {
|
|
1927
|
+
if (Date.now() - startedAt < 120) return;
|
|
1812
1928
|
finish(options[selectedIndex]);
|
|
1813
1929
|
}
|
|
1814
1930
|
};
|
|
@@ -1822,14 +1938,35 @@ function selectModelChoice({ title, subtitle, options, initialIndex = 0 }) {
|
|
|
1822
1938
|
|
|
1823
1939
|
async function pickModelRole(role, state) {
|
|
1824
1940
|
const options = modelRoleChoices(role);
|
|
1825
|
-
const currentProvider =
|
|
1826
|
-
|
|
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";
|
|
1827
1957
|
const initialIndex = Math.max(
|
|
1828
1958
|
options.findIndex((item) => item.provider === currentProvider && item.model === currentModel),
|
|
1829
1959
|
0
|
|
1830
1960
|
);
|
|
1831
1961
|
const selected = await selectModelChoice({
|
|
1832
|
-
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",
|
|
1833
1970
|
subtitle: "Up/Down/Left/Right selects, Enter confirms, Esc cancels.",
|
|
1834
1971
|
options,
|
|
1835
1972
|
initialIndex,
|
|
@@ -1843,6 +1980,16 @@ async function pickModelRole(role, state) {
|
|
|
1843
1980
|
state.routeProvider = selected.provider;
|
|
1844
1981
|
state.routeModel = selected.model;
|
|
1845
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}`);
|
|
1846
1993
|
} else {
|
|
1847
1994
|
state.mainProvider = selected.provider;
|
|
1848
1995
|
state.mainModel = selected.model;
|
|
@@ -1851,6 +1998,28 @@ async function pickModelRole(role, state) {
|
|
|
1851
1998
|
return true;
|
|
1852
1999
|
}
|
|
1853
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
|
+
|
|
1854
2023
|
async function maybeOnboardDeepSeekKey(state) {
|
|
1855
2024
|
if (!shouldPromptForDeepSeek(state, process.cwd())) return;
|
|
1856
2025
|
|
|
@@ -1976,7 +2145,13 @@ async function handleCommand(line, state, packageDir) {
|
|
|
1976
2145
|
return true;
|
|
1977
2146
|
}
|
|
1978
2147
|
if (action.startsWith("model")) {
|
|
1979
|
-
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");
|
|
1980
2155
|
state.auxiliaryProvider = selected.provider || "grsai";
|
|
1981
2156
|
state.auxiliaryModel = selected.model || state.auxiliaryModel || "nano-banana-2";
|
|
1982
2157
|
printSystemLine(`auxiliary=${state.auxiliaryProvider}/${state.auxiliaryModel}`);
|
|
@@ -2077,15 +2252,19 @@ async function handleCommand(line, state, packageDir) {
|
|
|
2077
2252
|
return true;
|
|
2078
2253
|
}
|
|
2079
2254
|
if (command === "venice") {
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
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);
|
|
2087
2266
|
const keys = providerKeyStatus(process.cwd());
|
|
2088
|
-
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");
|
|
2089
2268
|
if (!keys.venice) {
|
|
2090
2269
|
printAgentMessage("Venice model roles are selected, but no Venice key is configured. Run `/auth venice` to save one.");
|
|
2091
2270
|
}
|
|
@@ -2154,6 +2333,11 @@ async function handleCommand(line, state, packageDir) {
|
|
|
2154
2333
|
}
|
|
2155
2334
|
if (command === "spare") {
|
|
2156
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
|
+
}
|
|
2157
2341
|
printAgentMessage(`Spare model: ${state.spareProvider}/${state.spareModel} reasoning=${state.spareReasoning}`);
|
|
2158
2342
|
return true;
|
|
2159
2343
|
}
|
|
@@ -2192,6 +2376,15 @@ async function handleCommand(line, state, packageDir) {
|
|
|
2192
2376
|
return true;
|
|
2193
2377
|
}
|
|
2194
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
|
+
}
|
|
2195
2388
|
state.provider = value === "auto" ? "" : value;
|
|
2196
2389
|
printSystemLine(`provider=${state.provider || "auto"}`);
|
|
2197
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,
|