@lazyingart/agintiflow 0.20.13 → 0.20.15
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 +4 -0
- package/demos/README.md +6 -0
- package/demos/agintiflow-cli-launch.jpg +0 -0
- package/docs/model-selection.md +29 -4
- package/package.json +2 -1
- package/public/app.js +1 -1
- package/references/model-routing-provider-design.md +2 -0
- package/scripts/smoke-model-roles.js +14 -2
- package/src/interactive-cli.js +303 -99
- package/src/model-routing.js +239 -9
package/README.md
CHANGED
|
@@ -21,6 +21,10 @@ AgInTiFlow is AgInTi's web-first agent platform for controlled website automatio
|
|
|
21
21
|
|
|
22
22
|
It is designed for workflows where an AI agent should act, but every tool, log, and session state should remain inspectable.
|
|
23
23
|
|
|
24
|
+
<p align="center">
|
|
25
|
+
<img src="./demos/agintiflow-cli-launch.jpg" alt="AgInTiFlow interactive CLI launch screen with colorful terminal banner, Docker workspace status, and chat input panel" width="960" />
|
|
26
|
+
</p>
|
|
27
|
+
|
|
24
28
|
## Product Snapshot
|
|
25
29
|
|
|
26
30
|
| Area | Direction |
|
package/demos/README.md
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
# AgInTiFlow Demos
|
|
2
|
+
|
|
3
|
+
This folder stores shareable screenshots and visual demos used by the repository README.
|
|
4
|
+
|
|
5
|
+
- `agintiflow-cli-launch.png`: interactive CLI launch screen with the AgInTi Flow terminal banner, Docker workspace status, and input panel.
|
|
6
|
+
- `agintiflow-cli-launch.jpg`: optimized README/web preview derived from the same screenshot.
|
|
Binary file
|
package/docs/model-selection.md
CHANGED
|
@@ -46,9 +46,27 @@ Interactive commands:
|
|
|
46
46
|
/auxiliary model grsai/nano-banana-2
|
|
47
47
|
```
|
|
48
48
|
|
|
49
|
-
In the interactive CLI, `/provider`, `/route`, `/model`, `/spare`, and `/auxiliary model` without arguments open selectors. Use Up/Down/Left/Right to move through choices
|
|
49
|
+
In the interactive CLI, `/provider`, `/route`, `/model`, `/spare`, and `/auxiliary model` without arguments open selectors. Use Up/Down/Left/Right to move through choices and Enter to confirm. Esc cancels at the top level; inside multi-level selectors it goes back one level. Slash-command hints use the same arrow selection behavior: type a prefix such as `/mo`, use arrows to choose `/model` or `/models`, then press Enter or Tab.
|
|
50
50
|
|
|
51
|
-
`/route`, `/model`, and `/spare` intentionally share the same text-model selector so users do not need to learn three different catalogs. The
|
|
51
|
+
`/route`, `/model`, and `/spare` intentionally share the same text-model selector so users do not need to learn three different catalogs. The selector is hierarchical:
|
|
52
|
+
|
|
53
|
+
1. Choose a provider family.
|
|
54
|
+
2. Choose the model in that family.
|
|
55
|
+
3. For OpenAI models, choose reasoning effort: `low`, `medium`, `high`, or `xhigh`.
|
|
56
|
+
|
|
57
|
+
Provider families:
|
|
58
|
+
|
|
59
|
+
| Family | Models |
|
|
60
|
+
| --- | --- |
|
|
61
|
+
| DeepSeek | `deepseek-v4-flash`, `deepseek-v4-pro` |
|
|
62
|
+
| Venice | `venice-uncensored-1-2`, `venice-uncensored`, `gemma-4-uncensored` |
|
|
63
|
+
| OpenAI | `gpt-5.5`, `gpt-5.4`, `gpt-5.4-mini`, `gpt-5.3-codex`, `gpt-5.3-codex-spark`, `gpt-5.2`; each has low/medium/high/xhigh reasoning |
|
|
64
|
+
| Venice GPT | GPT-family Venice routes such as `openai-gpt-55`, `openai-gpt-54`, `openai-gpt-54-mini`, `openai-gpt-53-codex`, `openai-gpt-52` |
|
|
65
|
+
| Venice Gemma | Gemma instruct routes such as `google-gemma-4-31b-it`, `google-gemma-4-26b-a4b-it`, `google-gemma-3-27b-it` |
|
|
66
|
+
| Venice Claude | Claude Sonnet/Opus routes such as `claude-sonnet-4-6`, `claude-opus-4-7`, `claude-opus-4-6` |
|
|
67
|
+
| Venice Qwen | Qwen routes such as `qwen3-6-27b`, `qwen-3-6-plus`, `qwen3-coder-480b-a35b-instruct-turbo` |
|
|
68
|
+
| Qwen | `qwen-plus`, `qwen-turbo`, `qwen-max` |
|
|
69
|
+
| Mock | `mock-agent` |
|
|
52
70
|
|
|
53
71
|
`/venice` opens a two-step selector for the Venice route and main models. The current text choices are:
|
|
54
72
|
|
|
@@ -77,14 +95,21 @@ It keeps smart routing enabled. If the Venice key is missing, run `/auth venice`
|
|
|
77
95
|
| `deepseek` | DeepSeek | Default route/main because V4 Flash and V4 Pro are cheap and strong. |
|
|
78
96
|
| `openai` | OpenAI | Spare/frontier checks, Codex-family work, and explicit manual routes. |
|
|
79
97
|
| `qwen` | Qwen | Chinese and general-purpose OpenAI-compatible tasks. |
|
|
80
|
-
| `venice
|
|
98
|
+
| `venice` | Venice | Venice-native text shortcuts: Venice 1.2, Venice 1.1, and Gemma 4 Uncensored. |
|
|
81
99
|
| `venice-gpt` | Venice | GPT-family models through Venice. |
|
|
82
100
|
| `venice-claude` | Venice | Claude-family models through Venice. |
|
|
83
|
-
| `venice-gemma` | Venice | Gemma
|
|
101
|
+
| `venice-gemma` | Venice | Gemma instruct models through Venice, excluding the Gemma 4 Uncensored shortcut. |
|
|
84
102
|
| `venice-qwen` | Venice | Qwen-family models through Venice. |
|
|
85
103
|
| `venice-image` | Venice | Image generation/editing such as Nano Banana, GPT Image, Wan, Qwen Image. |
|
|
86
104
|
| `grsai` | GRS AI | Auxiliary image generation only. |
|
|
87
105
|
|
|
106
|
+
`/auxiliary model` uses the same two-level pattern for image tools:
|
|
107
|
+
|
|
108
|
+
| Family | Models |
|
|
109
|
+
| --- | --- |
|
|
110
|
+
| GRS AI | `nano-banana-2`, `nano-banana-2-edit`, `gpt-image-2`, `gpt-image-2-edit` when the configured GRS AI-compatible endpoint supports them |
|
|
111
|
+
| Venice Image | `wan-2-7-pro-edit`, `nano-banana-2`, `gpt-image-2`, `grok-imagine-image`, `qwen-image-2-pro`, `bria-bg-remover`, `recraft-v4`, `flux-2-pro`, and related image/edit routes |
|
|
112
|
+
|
|
88
113
|
## Keys
|
|
89
114
|
|
|
90
115
|
Keys are set per project and stored only in ignored `.aginti/.env`:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lazyingart/agintiflow",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.15",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "AgInTiFlow is a web-first coding agent and CLI with DeepSeek routing, sandboxed tools, model providers, canvas artifacts, and optional wrappers.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -37,6 +37,7 @@
|
|
|
37
37
|
"bin/",
|
|
38
38
|
"docs/",
|
|
39
39
|
"docker/",
|
|
40
|
+
"demos/agintiflow-cli-launch.jpg",
|
|
40
41
|
"i18n/",
|
|
41
42
|
"logos/banner-opaque.png",
|
|
42
43
|
"logos/logo.png",
|
package/public/app.js
CHANGED
|
@@ -989,7 +989,7 @@ function fieldValue(field) {
|
|
|
989
989
|
}
|
|
990
990
|
|
|
991
991
|
function providerModelOptions(provider = providerField.value) {
|
|
992
|
-
return modelCatalog[provider] || [];
|
|
992
|
+
return (modelCatalog[provider] || []).filter((item) => !item.hidden);
|
|
993
993
|
}
|
|
994
994
|
|
|
995
995
|
function mergeModelOptions(...groups) {
|
|
@@ -55,6 +55,8 @@ Interactive equivalents:
|
|
|
55
55
|
|
|
56
56
|
`/route`, `/model`, and `/spare` share a single text-model selector. The selector is grouped as DeepSeek, Venice Uncensored, Venice GPT/Claude/Gemma/Qwen, OpenAI, Qwen, and Mock so the user sees the same union of route/main/spare-capable models in every role.
|
|
57
57
|
|
|
58
|
+
Interactive selectors are hierarchical. Enter moves forward or confirms. Esc cancels only at the first level; at model/reasoning levels it returns to the previous selector instead of dropping the whole flow.
|
|
59
|
+
|
|
58
60
|
`/venice` opens a route/main selector for Venice text models. The selector includes `venice/venice-uncensored-1-2` (Venice 1.2), `venice/venice-uncensored` (Venice 1.1), `venice/gemma-4-uncensored` (Gemma 4), and a Disable Venice option. In non-interactive shells, `/venice` keeps script compatibility by selecting `venice/venice-uncensored-1-2` for both roles. `/venice 1.2 gemma` sets route to Venice 1.2 and main to Gemma 4; `/venice off` or the Disable Venice selector option restores `deepseek/deepseek-v4-flash` for route and `deepseek/deepseek-v4-pro` for main.
|
|
59
61
|
|
|
60
62
|
The web UI should expose model names as dropdowns, not free-text fields. The left panel should stay focused on common daily controls, while model-role editing and less-used switches live in an Advanced settings modal. The terminal-like capability panels belong after the runtime log so the left control panel remains short.
|
|
@@ -109,9 +109,14 @@ const fastRoute = selectModelRoute({
|
|
|
109
109
|
assert(fastRoute.model === "deepseek-v4-flash", "fast route did not use route model override");
|
|
110
110
|
|
|
111
111
|
assert(MODEL_PROVIDER_GROUPS["venice-gpt"].provider === "venice", "venice-gpt group missing");
|
|
112
|
-
assert(modelsForProviderGroup("venice
|
|
113
|
-
assert(modelsForProviderGroup("venice-
|
|
112
|
+
assert(modelsForProviderGroup("venice").some((item) => item.id === "venice-uncensored-1-2"), "venice group missing Venice 1.2");
|
|
113
|
+
assert(modelsForProviderGroup("venice-gemma").some((item) => item.id === "google-gemma-4-31b-it"), "venice-gemma bucket missing Gemma 4 instruct");
|
|
114
|
+
assert(!modelsForProviderGroup("venice-gemma").some((item) => item.id === "gemma-4-uncensored"), "venice-gemma bucket should not include Gemma 4 Uncensored shortcut");
|
|
115
|
+
assert(modelsForProviderGroup("venice-gpt").some((item) => item.id === "openai-gpt-54-mini"), "venice-gpt bucket missing GPT-5.4 Mini");
|
|
116
|
+
assert(modelsForProviderGroup("venice-claude").some((item) => item.id === "claude-opus-4-7"), "venice-claude bucket missing Claude Opus 4.7");
|
|
117
|
+
assert(modelsForProviderGroup("venice-qwen").some((item) => item.id === "qwen3-coder-480b-a35b-instruct-turbo"), "venice-qwen bucket missing Qwen Coder");
|
|
114
118
|
assert(AUXILIARY_MODEL_CATALOG["venice-image"].some((item) => item.id === "gpt-image-2"), "Venice image catalog missing GPT Image 2");
|
|
119
|
+
assert(AUXILIARY_MODEL_CATALOG["venice-image"].some((item) => item.id === "wan-2-7-pro-edit"), "Venice image catalog missing Wan edit");
|
|
115
120
|
const routeChoices = modelRoleChoices("route").map((item) => `${item.provider}/${item.model}`);
|
|
116
121
|
const mainChoices = modelRoleChoices("main").map((item) => `${item.provider}/${item.model}`);
|
|
117
122
|
const spareChoices = modelRoleChoices("spare").map((item) => `${item.provider}/${item.model}`);
|
|
@@ -123,9 +128,14 @@ for (const expected of [
|
|
|
123
128
|
"venice/venice-uncensored-1-2",
|
|
124
129
|
"venice/venice-uncensored",
|
|
125
130
|
"venice/gemma-4-uncensored",
|
|
131
|
+
"venice/google-gemma-4-31b-it",
|
|
132
|
+
"venice/google-gemma-4-26b-a4b-it",
|
|
126
133
|
"venice/openai-gpt-55",
|
|
134
|
+
"venice/openai-gpt-54-mini",
|
|
127
135
|
"venice/claude-sonnet-4-6",
|
|
136
|
+
"venice/claude-opus-4-7",
|
|
128
137
|
"venice/qwen3-6-27b",
|
|
138
|
+
"venice/qwen3-coder-480b-a35b-instruct-turbo",
|
|
129
139
|
"openai/gpt-5.5",
|
|
130
140
|
"openai/gpt-5.4",
|
|
131
141
|
"openai/gpt-5.4-mini",
|
|
@@ -137,7 +147,9 @@ for (const expected of [
|
|
|
137
147
|
assert(routeChoices.includes(expected), `shared model selector missing ${expected}`);
|
|
138
148
|
}
|
|
139
149
|
assert(!routeChoices.includes("venice/e2ee-venice-uncensored-24b-p"), "shared model selector should hide unstable E2EE Venice 1.1");
|
|
150
|
+
assert(modelRoleChoices("route").some((item) => item.provider === "openai" && item.model === "gpt-5.5" && item.reasoningOptions.includes("xhigh")), "OpenAI selector missing reasoning levels");
|
|
140
151
|
assert(modelRoleChoices("auxiliary").some((item) => item.provider === "grsai"), "auxiliary selector missing GRS AI");
|
|
152
|
+
assert(modelRoleChoices("auxiliary").some((item) => item.provider === "venice" && item.model === "wan-2-7-pro-edit"), "auxiliary selector missing Venice Wan edit");
|
|
141
153
|
const parsedTextToolCalls = parseTextToolCalls('[TOOL_CALLS]list_files[ARGS]call_123[ARGS]{"path":".","maxDepth":1}');
|
|
142
154
|
assert(parsedTextToolCalls.length === 1, "Venice text tool-call parser did not detect encoded tool call");
|
|
143
155
|
assert(parsedTextToolCalls[0].function.name === "list_files", "Venice text tool-call parser returned wrong tool name");
|
package/src/interactive-cli.js
CHANGED
|
@@ -1651,8 +1651,10 @@ function createState(args = {}) {
|
|
|
1651
1651
|
preferredWrapper: args.preferredWrapper || "codex",
|
|
1652
1652
|
routeProvider: args.routeProvider || "",
|
|
1653
1653
|
routeModel: args.routeModel || "",
|
|
1654
|
+
routeReasoning: args.routeReasoning || "",
|
|
1654
1655
|
mainProvider: args.mainProvider || "",
|
|
1655
1656
|
mainModel: args.mainModel || "",
|
|
1657
|
+
mainReasoning: args.mainReasoning || "",
|
|
1656
1658
|
spareProvider: args.spareProvider || "openai",
|
|
1657
1659
|
spareModel: args.spareModel || "gpt-5.4",
|
|
1658
1660
|
spareReasoning: args.spareReasoning || "medium",
|
|
@@ -1694,8 +1696,10 @@ function useDeepSeekDefaults(state) {
|
|
|
1694
1696
|
state.model = "";
|
|
1695
1697
|
state.routeProvider = "deepseek";
|
|
1696
1698
|
state.routeModel = "deepseek-v4-flash";
|
|
1699
|
+
state.routeReasoning = "";
|
|
1697
1700
|
state.mainProvider = "deepseek";
|
|
1698
1701
|
state.mainModel = "deepseek-v4-pro";
|
|
1702
|
+
state.mainReasoning = "";
|
|
1699
1703
|
}
|
|
1700
1704
|
|
|
1701
1705
|
function veniceTextModelChoices() {
|
|
@@ -1766,8 +1770,10 @@ function printModelRoles(state) {
|
|
|
1766
1770
|
const roles = getModelRoleDefaults({
|
|
1767
1771
|
routeProvider: state.routeProvider,
|
|
1768
1772
|
routeModel: state.routeModel,
|
|
1773
|
+
routeReasoning: state.routeReasoning,
|
|
1769
1774
|
mainProvider: state.mainProvider,
|
|
1770
1775
|
mainModel: state.mainModel,
|
|
1776
|
+
mainReasoning: state.mainReasoning,
|
|
1771
1777
|
spareProvider: state.spareProvider,
|
|
1772
1778
|
spareModel: state.spareModel,
|
|
1773
1779
|
spareReasoning: state.spareReasoning,
|
|
@@ -1827,13 +1833,17 @@ function compactReasoning(model = {}) {
|
|
|
1827
1833
|
return `${preferred} reasoning`;
|
|
1828
1834
|
}
|
|
1829
1835
|
|
|
1836
|
+
function isReasoningLevel(value = "") {
|
|
1837
|
+
return ["low", "medium", "high", "xhigh"].includes(String(value || "").toLowerCase());
|
|
1838
|
+
}
|
|
1839
|
+
|
|
1830
1840
|
function modelSelectorGroup(provider, model = {}) {
|
|
1831
1841
|
if (provider === "deepseek") return "DeepSeek";
|
|
1832
1842
|
if (provider === "openai") return "OpenAI";
|
|
1833
1843
|
if (provider === "qwen") return "Qwen";
|
|
1834
1844
|
if (provider === "mock") return "Mock";
|
|
1835
1845
|
if (provider === "venice") {
|
|
1836
|
-
if (model.bucket === "venice
|
|
1846
|
+
if (model.bucket === "venice") return "Venice";
|
|
1837
1847
|
if (model.bucket === "venice-gpt") return "Venice GPT";
|
|
1838
1848
|
if (model.bucket === "venice-claude") return "Venice Claude";
|
|
1839
1849
|
if (model.bucket === "venice-gemma") return "Venice Gemma";
|
|
@@ -1843,25 +1853,96 @@ function modelSelectorGroup(provider, model = {}) {
|
|
|
1843
1853
|
return provider;
|
|
1844
1854
|
}
|
|
1845
1855
|
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
"
|
|
1850
|
-
"
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
"
|
|
1854
|
-
"
|
|
1855
|
-
|
|
1856
|
+
const TEXT_MODEL_GROUPS = [
|
|
1857
|
+
{
|
|
1858
|
+
id: "deepseek",
|
|
1859
|
+
label: "DeepSeek",
|
|
1860
|
+
description: "DeepSeek V4 Flash and Pro defaults.",
|
|
1861
|
+
},
|
|
1862
|
+
{
|
|
1863
|
+
id: "venice",
|
|
1864
|
+
label: "Venice",
|
|
1865
|
+
description: "Venice 1.2, Venice 1.1, and Gemma 4 Uncensored.",
|
|
1866
|
+
},
|
|
1867
|
+
{
|
|
1868
|
+
id: "openai",
|
|
1869
|
+
label: "OpenAI",
|
|
1870
|
+
description: "GPT and Codex models with selectable reasoning.",
|
|
1871
|
+
},
|
|
1872
|
+
{
|
|
1873
|
+
id: "venice-gpt",
|
|
1874
|
+
label: "Venice GPT",
|
|
1875
|
+
description: "OpenAI/GPT-family text models through Venice.",
|
|
1876
|
+
},
|
|
1877
|
+
{
|
|
1878
|
+
id: "venice-gemma",
|
|
1879
|
+
label: "Venice Gemma",
|
|
1880
|
+
description: "Gemma instruct models through Venice, excluding Gemma 4 Uncensored.",
|
|
1881
|
+
},
|
|
1882
|
+
{
|
|
1883
|
+
id: "venice-claude",
|
|
1884
|
+
label: "Venice Claude",
|
|
1885
|
+
description: "Claude Sonnet and Opus models through Venice.",
|
|
1886
|
+
},
|
|
1887
|
+
{
|
|
1888
|
+
id: "venice-qwen",
|
|
1889
|
+
label: "Venice Qwen",
|
|
1890
|
+
description: "Qwen text and coder models through Venice.",
|
|
1891
|
+
},
|
|
1892
|
+
{
|
|
1893
|
+
id: "qwen",
|
|
1894
|
+
label: "Qwen",
|
|
1895
|
+
description: "DashScope Qwen Plus/Turbo/Max.",
|
|
1896
|
+
},
|
|
1897
|
+
{
|
|
1898
|
+
id: "mock",
|
|
1899
|
+
label: "Mock",
|
|
1900
|
+
description: "Deterministic local test model.",
|
|
1901
|
+
},
|
|
1902
|
+
];
|
|
1903
|
+
|
|
1904
|
+
function modelGroupForSelection(provider, model = {}) {
|
|
1905
|
+
if (provider === "venice") return model.bucket || "venice";
|
|
1906
|
+
return provider;
|
|
1907
|
+
}
|
|
1908
|
+
|
|
1909
|
+
function modelGroupChoices() {
|
|
1910
|
+
return TEXT_MODEL_GROUPS.map((group) => ({
|
|
1911
|
+
action: "group",
|
|
1912
|
+
groupId: group.id,
|
|
1913
|
+
label: group.label,
|
|
1914
|
+
description: group.description,
|
|
1915
|
+
}));
|
|
1916
|
+
}
|
|
1917
|
+
|
|
1918
|
+
function modelsForSelectorGroup(groupId = "") {
|
|
1919
|
+
const group = String(groupId || "");
|
|
1920
|
+
if (group === "deepseek") return (PROVIDER_MODEL_CATALOG.deepseek || []).filter((model) => !model.hidden);
|
|
1921
|
+
if (group === "openai") return (PROVIDER_MODEL_CATALOG.openai || []).filter((model) => !model.hidden);
|
|
1922
|
+
if (group === "qwen") return (PROVIDER_MODEL_CATALOG.qwen || []).filter((model) => !model.hidden);
|
|
1923
|
+
if (group === "mock") return (PROVIDER_MODEL_CATALOG.mock || []).filter((model) => !model.hidden);
|
|
1924
|
+
if (group === "venice") {
|
|
1925
|
+
const order = ["venice-uncensored-1-2", "venice-uncensored", "gemma-4-uncensored"];
|
|
1926
|
+
const byId = new Map((PROVIDER_MODEL_CATALOG.venice || []).filter((model) => !model.hidden).map((model) => [model.id, model]));
|
|
1927
|
+
return order.map((id) => byId.get(id)).filter(Boolean);
|
|
1928
|
+
}
|
|
1929
|
+
if (group.startsWith("venice-")) {
|
|
1930
|
+
return (PROVIDER_MODEL_CATALOG.venice || []).filter((model) => !model.hidden && model.bucket === group);
|
|
1931
|
+
}
|
|
1932
|
+
return [];
|
|
1933
|
+
}
|
|
1934
|
+
|
|
1935
|
+
function providerForSelectorGroup(groupId = "") {
|
|
1936
|
+
if (String(groupId).startsWith("venice")) return "venice";
|
|
1937
|
+
return groupId;
|
|
1938
|
+
}
|
|
1939
|
+
|
|
1940
|
+
function textModelRoleChoices(groupId = "") {
|
|
1941
|
+
const groups = groupId ? [groupId] : TEXT_MODEL_GROUPS.map((group) => group.id);
|
|
1856
1942
|
const choices = [];
|
|
1857
|
-
for (const
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
const byId = new Map(models.filter((model) => !model.hidden).map((model) => [model.id, model]));
|
|
1861
|
-
models = veniceOrder.map((id) => byId.get(id)).filter(Boolean);
|
|
1862
|
-
} else {
|
|
1863
|
-
models = models.filter((model) => !model.hidden);
|
|
1864
|
-
}
|
|
1943
|
+
for (const groupIdItem of groups) {
|
|
1944
|
+
const provider = providerForSelectorGroup(groupIdItem);
|
|
1945
|
+
const models = modelsForSelectorGroup(groupIdItem);
|
|
1865
1946
|
for (const model of models) {
|
|
1866
1947
|
const group = modelSelectorGroup(provider, model);
|
|
1867
1948
|
const reasoning = compactReasoning(model);
|
|
@@ -1874,6 +1955,7 @@ function textModelRoleChoices() {
|
|
|
1874
1955
|
group,
|
|
1875
1956
|
description: details,
|
|
1876
1957
|
reasoningDefault: reasoning ? reasoning.split(" ")[0] : "",
|
|
1958
|
+
reasoningOptions: Array.isArray(model.reasoning) ? model.reasoning : [],
|
|
1877
1959
|
});
|
|
1878
1960
|
}
|
|
1879
1961
|
}
|
|
@@ -1882,30 +1964,47 @@ function textModelRoleChoices() {
|
|
|
1882
1964
|
|
|
1883
1965
|
export function modelRoleChoices(role = "main") {
|
|
1884
1966
|
if (role !== "auxiliary") return textModelRoleChoices();
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
description: "default auxiliary image model",
|
|
1891
|
-
auxiliary: true,
|
|
1892
|
-
},
|
|
1967
|
+
return auxiliaryModelRoleChoices();
|
|
1968
|
+
}
|
|
1969
|
+
|
|
1970
|
+
function auxiliaryGroupChoices() {
|
|
1971
|
+
return [
|
|
1893
1972
|
{
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
label: "
|
|
1897
|
-
description: "
|
|
1898
|
-
auxiliary: true,
|
|
1973
|
+
action: "group",
|
|
1974
|
+
groupId: "grsai",
|
|
1975
|
+
label: "GRS AI",
|
|
1976
|
+
description: "Nano Banana and GPT image models through GRS AI-compatible keys.",
|
|
1899
1977
|
},
|
|
1900
1978
|
{
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
label: "Venice
|
|
1904
|
-
description: "Venice image
|
|
1905
|
-
auxiliary: true,
|
|
1979
|
+
action: "group",
|
|
1980
|
+
groupId: "venice-image",
|
|
1981
|
+
label: "Venice Image",
|
|
1982
|
+
description: "Venice image, edit, background-removal, Qwen, Wan, Grok, Recraft, Flux routes.",
|
|
1906
1983
|
},
|
|
1907
1984
|
];
|
|
1908
|
-
|
|
1985
|
+
}
|
|
1986
|
+
|
|
1987
|
+
function auxiliaryProviderForGroup(groupId = "") {
|
|
1988
|
+
return groupId === "venice-image" ? "venice" : "grsai";
|
|
1989
|
+
}
|
|
1990
|
+
|
|
1991
|
+
function auxiliaryModelRoleChoices(groupId = "") {
|
|
1992
|
+
const groups = groupId ? [groupId] : ["grsai", "venice-image"];
|
|
1993
|
+
const choices = [];
|
|
1994
|
+
for (const group of groups) {
|
|
1995
|
+
const provider = auxiliaryProviderForGroup(group);
|
|
1996
|
+
for (const model of AUXILIARY_MODEL_CATALOG[group] || []) {
|
|
1997
|
+
choices.push({
|
|
1998
|
+
provider,
|
|
1999
|
+
model: model.id,
|
|
2000
|
+
label: `${group === "venice-image" ? "Venice Image" : "GRS AI"} · ${model.label || model.id}`,
|
|
2001
|
+
group,
|
|
2002
|
+
description: [model.type, model.price, model.description].filter(Boolean).join("; "),
|
|
2003
|
+
auxiliary: true,
|
|
2004
|
+
});
|
|
2005
|
+
}
|
|
2006
|
+
}
|
|
2007
|
+
return choices;
|
|
1909
2008
|
}
|
|
1910
2009
|
|
|
1911
2010
|
function providerChoices() {
|
|
@@ -1945,6 +2044,7 @@ function providerChoices() {
|
|
|
1945
2044
|
|
|
1946
2045
|
function modelChoiceLine(option) {
|
|
1947
2046
|
if (option.action === "disable") return `${option.label} ${option.description}`;
|
|
2047
|
+
if (option.action === "group" || option.action === "reasoning") return `${option.label} ${option.description}`;
|
|
1948
2048
|
return `${option.label} ${option.provider}/${option.model} ${option.description}`;
|
|
1949
2049
|
}
|
|
1950
2050
|
|
|
@@ -1979,7 +2079,13 @@ function renderSelector({ title, subtitle, options, selectedIndex, lineCount = 0
|
|
|
1979
2079
|
return rows.length;
|
|
1980
2080
|
}
|
|
1981
2081
|
|
|
1982
|
-
|
|
2082
|
+
const SELECTOR_BACK = Symbol("selector-back");
|
|
2083
|
+
|
|
2084
|
+
function isSelectorBack(value) {
|
|
2085
|
+
return value === SELECTOR_BACK;
|
|
2086
|
+
}
|
|
2087
|
+
|
|
2088
|
+
function selectModelChoice({ title, subtitle, options, initialIndex = 0, escapeValue = null }) {
|
|
1983
2089
|
if (!input.isTTY || !output.isTTY || typeof input.setRawMode !== "function") return Promise.resolve(null);
|
|
1984
2090
|
return new Promise((resolve) => {
|
|
1985
2091
|
emitKeypressEvents(input);
|
|
@@ -2007,7 +2113,7 @@ function selectModelChoice({ title, subtitle, options, initialIndex = 0 }) {
|
|
|
2007
2113
|
return;
|
|
2008
2114
|
}
|
|
2009
2115
|
if (key.name === "escape") {
|
|
2010
|
-
finish(
|
|
2116
|
+
finish(escapeValue);
|
|
2011
2117
|
return;
|
|
2012
2118
|
}
|
|
2013
2119
|
if (key.name === "up" || key.name === "left") {
|
|
@@ -2034,7 +2140,6 @@ function selectModelChoice({ title, subtitle, options, initialIndex = 0 }) {
|
|
|
2034
2140
|
}
|
|
2035
2141
|
|
|
2036
2142
|
async function pickModelRole(role, state) {
|
|
2037
|
-
const options = modelRoleChoices(role);
|
|
2038
2143
|
const currentProvider =
|
|
2039
2144
|
role === "route"
|
|
2040
2145
|
? state.routeProvider || "deepseek"
|
|
@@ -2051,24 +2156,103 @@ async function pickModelRole(role, state) {
|
|
|
2051
2156
|
: role === "auxiliary"
|
|
2052
2157
|
? state.auxiliaryModel || "nano-banana-2"
|
|
2053
2158
|
: state.mainModel || "deepseek-v4-pro";
|
|
2054
|
-
|
|
2055
|
-
|
|
2159
|
+
|
|
2160
|
+
const groupOptions = role === "auxiliary" ? auxiliaryGroupChoices() : modelGroupChoices();
|
|
2161
|
+
const currentModelEntry =
|
|
2162
|
+
role === "auxiliary"
|
|
2163
|
+
? modelRoleChoices("auxiliary").find((item) => item.provider === currentProvider && item.model === currentModel)
|
|
2164
|
+
: modelRoleChoices(role).find((item) => item.provider === currentProvider && item.model === currentModel);
|
|
2165
|
+
const currentGroup = currentModelEntry?.group || currentProvider;
|
|
2166
|
+
let selected = null;
|
|
2167
|
+
let selectedReasoning = "";
|
|
2168
|
+
let initialGroupIndex = Math.max(
|
|
2169
|
+
groupOptions.findIndex((item) => item.groupId === currentGroup),
|
|
2056
2170
|
0
|
|
2057
2171
|
);
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
? "Select
|
|
2064
|
-
: role === "
|
|
2065
|
-
? "Select
|
|
2066
|
-
:
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2172
|
+
|
|
2173
|
+
while (!selected) {
|
|
2174
|
+
const group = await selectModelChoice({
|
|
2175
|
+
title:
|
|
2176
|
+
role === "route"
|
|
2177
|
+
? "Select route model family"
|
|
2178
|
+
: role === "spare"
|
|
2179
|
+
? "Select spare model family"
|
|
2180
|
+
: role === "auxiliary"
|
|
2181
|
+
? "Select auxiliary provider"
|
|
2182
|
+
: "Select main model family",
|
|
2183
|
+
subtitle: "First choose a provider family. Up/Down/Left/Right selects, Enter confirms, Esc cancels.",
|
|
2184
|
+
options: groupOptions,
|
|
2185
|
+
initialIndex: initialGroupIndex,
|
|
2186
|
+
});
|
|
2187
|
+
if (!group) return false;
|
|
2188
|
+
initialGroupIndex = Math.max(
|
|
2189
|
+
groupOptions.findIndex((item) => item.groupId === group.groupId),
|
|
2190
|
+
0
|
|
2191
|
+
);
|
|
2192
|
+
|
|
2193
|
+
const options = role === "auxiliary" ? auxiliaryModelRoleChoices(group.groupId) : textModelRoleChoices(group.groupId);
|
|
2194
|
+
let initialModelIndex = Math.max(
|
|
2195
|
+
options.findIndex((item) => item.provider === currentProvider && item.model === currentModel),
|
|
2196
|
+
0
|
|
2197
|
+
);
|
|
2198
|
+
|
|
2199
|
+
while (!selected) {
|
|
2200
|
+
const modelSelection = await selectModelChoice({
|
|
2201
|
+
title:
|
|
2202
|
+
role === "route"
|
|
2203
|
+
? `Select route model: ${group.label}`
|
|
2204
|
+
: role === "spare"
|
|
2205
|
+
? `Select spare model: ${group.label}`
|
|
2206
|
+
: role === "auxiliary"
|
|
2207
|
+
? `Select auxiliary model: ${group.label}`
|
|
2208
|
+
: `Select main model: ${group.label}`,
|
|
2209
|
+
subtitle:
|
|
2210
|
+
role === "auxiliary"
|
|
2211
|
+
? "Choose the image/edit auxiliary model. Enter confirms, Esc goes back."
|
|
2212
|
+
: "Choose the text model. OpenAI choices ask for reasoning next. Esc goes back.",
|
|
2213
|
+
options,
|
|
2214
|
+
initialIndex: initialModelIndex,
|
|
2215
|
+
escapeValue: SELECTOR_BACK,
|
|
2216
|
+
});
|
|
2217
|
+
if (isSelectorBack(modelSelection)) break;
|
|
2218
|
+
if (!modelSelection) return false;
|
|
2219
|
+
initialModelIndex = Math.max(
|
|
2220
|
+
options.findIndex((item) => item.provider === modelSelection.provider && item.model === modelSelection.model),
|
|
2221
|
+
0
|
|
2222
|
+
);
|
|
2223
|
+
|
|
2224
|
+
selectedReasoning = modelSelection.reasoningDefault || "";
|
|
2225
|
+
if (Array.isArray(modelSelection.reasoningOptions) && modelSelection.reasoningOptions.length > 0) {
|
|
2226
|
+
const currentReasoning =
|
|
2227
|
+
role === "route"
|
|
2228
|
+
? state.routeReasoning || selectedReasoning || "medium"
|
|
2229
|
+
: role === "spare"
|
|
2230
|
+
? state.spareReasoning || selectedReasoning || "medium"
|
|
2231
|
+
: state.mainReasoning || selectedReasoning || "medium";
|
|
2232
|
+
const reasoningOptions = modelSelection.reasoningOptions.map((level) => ({
|
|
2233
|
+
action: "reasoning",
|
|
2234
|
+
label: level,
|
|
2235
|
+
value: level,
|
|
2236
|
+
description: `${modelSelection.label} with ${level} reasoning`,
|
|
2237
|
+
}));
|
|
2238
|
+
const reasoning = await selectModelChoice({
|
|
2239
|
+
title: `Select reasoning: ${modelSelection.label}`,
|
|
2240
|
+
subtitle: "Up/Down selects reasoning effort. Enter confirms, Esc goes back.",
|
|
2241
|
+
options: reasoningOptions,
|
|
2242
|
+
initialIndex: Math.max(
|
|
2243
|
+
reasoningOptions.findIndex((item) => item.value === currentReasoning),
|
|
2244
|
+
reasoningOptions.findIndex((item) => item.value === selectedReasoning),
|
|
2245
|
+
0
|
|
2246
|
+
),
|
|
2247
|
+
escapeValue: SELECTOR_BACK,
|
|
2248
|
+
});
|
|
2249
|
+
if (isSelectorBack(reasoning)) continue;
|
|
2250
|
+
if (!reasoning) return false;
|
|
2251
|
+
selectedReasoning = reasoning.value;
|
|
2252
|
+
}
|
|
2253
|
+
selected = modelSelection;
|
|
2254
|
+
}
|
|
2255
|
+
}
|
|
2072
2256
|
|
|
2073
2257
|
state.routingMode = "smart";
|
|
2074
2258
|
state.provider = "deepseek";
|
|
@@ -2076,11 +2260,12 @@ async function pickModelRole(role, state) {
|
|
|
2076
2260
|
if (role === "route") {
|
|
2077
2261
|
state.routeProvider = selected.provider;
|
|
2078
2262
|
state.routeModel = selected.model;
|
|
2079
|
-
|
|
2263
|
+
state.routeReasoning = selectedReasoning || state.routeReasoning || "";
|
|
2264
|
+
printSystemLine(`route=${state.routeProvider}/${state.routeModel}${state.routeReasoning ? ` reasoning=${state.routeReasoning}` : ""}`);
|
|
2080
2265
|
} else if (role === "spare") {
|
|
2081
2266
|
state.spareProvider = selected.provider;
|
|
2082
2267
|
state.spareModel = selected.model;
|
|
2083
|
-
state.spareReasoning =
|
|
2268
|
+
state.spareReasoning = selectedReasoning || state.spareReasoning || "medium";
|
|
2084
2269
|
printSystemLine(`spare=${state.spareProvider}/${state.spareModel} reasoning=${state.spareReasoning}`);
|
|
2085
2270
|
} else if (role === "auxiliary") {
|
|
2086
2271
|
state.auxiliaryProvider = selected.provider;
|
|
@@ -2090,51 +2275,60 @@ async function pickModelRole(role, state) {
|
|
|
2090
2275
|
} else {
|
|
2091
2276
|
state.mainProvider = selected.provider;
|
|
2092
2277
|
state.mainModel = selected.model;
|
|
2093
|
-
|
|
2278
|
+
state.mainReasoning = selectedReasoning || state.mainReasoning || "";
|
|
2279
|
+
printSystemLine(`main=${state.mainProvider}/${state.mainModel}${state.mainReasoning ? ` reasoning=${state.mainReasoning}` : ""}`);
|
|
2094
2280
|
}
|
|
2095
2281
|
return true;
|
|
2096
2282
|
}
|
|
2097
2283
|
|
|
2098
2284
|
async function pickVeniceRouteAndMain(state) {
|
|
2099
2285
|
const options = veniceTextModelChoices();
|
|
2100
|
-
|
|
2286
|
+
let routeIndex = Math.max(
|
|
2101
2287
|
options.findIndex((item) => item.provider === state.routeProvider && item.model === state.routeModel),
|
|
2102
2288
|
0
|
|
2103
2289
|
);
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2290
|
+
while (true) {
|
|
2291
|
+
const route = await selectModelChoice({
|
|
2292
|
+
title: "Select Venice route model",
|
|
2293
|
+
subtitle: "Route handles planning and short turns. Up/Down selects, Enter confirms, Esc cancels.",
|
|
2294
|
+
options,
|
|
2295
|
+
initialIndex: routeIndex,
|
|
2296
|
+
});
|
|
2297
|
+
if (!route) return false;
|
|
2298
|
+
routeIndex = Math.max(
|
|
2299
|
+
options.findIndex((item) => item.provider === route.provider && item.model === route.model),
|
|
2300
|
+
0
|
|
2301
|
+
);
|
|
2302
|
+
if (route.action === "disable") {
|
|
2303
|
+
useDeepSeekDefaults(state);
|
|
2304
|
+
printSystemLine("venice=off routing=smart route=deepseek/deepseek-v4-flash main=deepseek/deepseek-v4-pro");
|
|
2305
|
+
return true;
|
|
2306
|
+
}
|
|
2116
2307
|
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2308
|
+
const mainIndex = Math.max(
|
|
2309
|
+
options.findIndex((item) => item.action !== "disable" && item.provider === state.mainProvider && item.model === state.mainModel),
|
|
2310
|
+
options.findIndex((item) => item.action !== "disable" && item.model === route.model),
|
|
2311
|
+
0
|
|
2312
|
+
);
|
|
2313
|
+
const main = await selectModelChoice({
|
|
2314
|
+
title: "Select Venice main model",
|
|
2315
|
+
subtitle: "Main handles complex work. Up/Down selects, Enter confirms, Esc goes back.",
|
|
2316
|
+
options,
|
|
2317
|
+
initialIndex: mainIndex,
|
|
2318
|
+
escapeValue: SELECTOR_BACK,
|
|
2319
|
+
});
|
|
2320
|
+
if (isSelectorBack(main)) continue;
|
|
2321
|
+
if (!main) return false;
|
|
2322
|
+
if (main.action === "disable") {
|
|
2323
|
+
useDeepSeekDefaults(state);
|
|
2324
|
+
printSystemLine("venice=off routing=smart route=deepseek/deepseek-v4-flash main=deepseek/deepseek-v4-pro");
|
|
2325
|
+
return true;
|
|
2326
|
+
}
|
|
2327
|
+
|
|
2328
|
+
useVeniceModels(state, route.model, main.model);
|
|
2329
|
+
printSystemLine(`venice=on routing=smart route=venice/${state.routeModel} main=venice/${state.mainModel}`);
|
|
2132
2330
|
return true;
|
|
2133
2331
|
}
|
|
2134
|
-
|
|
2135
|
-
useVeniceModels(state, route.model, main.model);
|
|
2136
|
-
printSystemLine(`venice=on routing=smart route=venice/${state.routeModel} main=venice/${state.mainModel}`);
|
|
2137
|
-
return true;
|
|
2138
2332
|
}
|
|
2139
2333
|
|
|
2140
2334
|
async function pickProvider(state) {
|
|
@@ -2274,11 +2468,16 @@ async function handleCommand(line, state, packageDir) {
|
|
|
2274
2468
|
`Image generation: ${keys.grsai ? "GRSAI key available" : "missing GRSAI key"}`,
|
|
2275
2469
|
`Venice image: ${keys.venice ? "Venice key available" : "missing Venice key"}`,
|
|
2276
2470
|
`Selected auxiliary: ${state.auxiliaryProvider || "grsai"}/${state.auxiliaryModel || "nano-banana-2"}`,
|
|
2277
|
-
"Use `/auxiliary grsai` or `/auxiliary venice` to paste a key, `/auxiliary
|
|
2471
|
+
"Use `/auxiliary model` for the two-level selector, `/auxiliary grsai` or `/auxiliary venice` to paste a key, `/auxiliary image`, or `/auxiliary off`.",
|
|
2278
2472
|
].join("\n")
|
|
2279
2473
|
);
|
|
2280
2474
|
return true;
|
|
2281
2475
|
}
|
|
2476
|
+
if (action === "select") {
|
|
2477
|
+
const changed = await pickModelRole("auxiliary", state);
|
|
2478
|
+
if (!changed) printSystemLine(`auxiliary=${state.auxiliaryProvider || "grsai"}/${state.auxiliaryModel || "nano-banana-2"}`);
|
|
2479
|
+
return true;
|
|
2480
|
+
}
|
|
2282
2481
|
if (action === "on") {
|
|
2283
2482
|
state.allowAuxiliaryTools = true;
|
|
2284
2483
|
printSystemLine("auxiliary=on");
|
|
@@ -2303,7 +2502,7 @@ async function handleCommand(line, state, packageDir) {
|
|
|
2303
2502
|
return true;
|
|
2304
2503
|
}
|
|
2305
2504
|
const selected = parseProviderModel(modelValue, state.auxiliaryProvider || "grsai");
|
|
2306
|
-
state.auxiliaryProvider = selected.provider || "grsai";
|
|
2505
|
+
state.auxiliaryProvider = selected.provider === "venice-image" ? "venice" : selected.provider || "grsai";
|
|
2307
2506
|
state.auxiliaryModel = selected.model || state.auxiliaryModel || "nano-banana-2";
|
|
2308
2507
|
printSystemLine(`auxiliary=${state.auxiliaryProvider}/${state.auxiliaryModel}`);
|
|
2309
2508
|
return true;
|
|
@@ -2312,7 +2511,7 @@ async function handleCommand(line, state, packageDir) {
|
|
|
2312
2511
|
await promptAndSaveProviderKey(action === "venice" ? "venice" : "grsai", state);
|
|
2313
2512
|
return true;
|
|
2314
2513
|
}
|
|
2315
|
-
printAgentMessage("Usage: /auxiliary [status|grsai|venice|model grsai/nano-banana-2|on|off|image]");
|
|
2514
|
+
printAgentMessage("Usage: /auxiliary [status|select|grsai|venice|model [grsai/nano-banana-2]|on|off|image]");
|
|
2316
2515
|
return true;
|
|
2317
2516
|
}
|
|
2318
2517
|
if (command === "new") {
|
|
@@ -2464,10 +2663,12 @@ async function handleCommand(line, state, packageDir) {
|
|
|
2464
2663
|
printSystemLine(`routing=${state.routingMode}`);
|
|
2465
2664
|
return true;
|
|
2466
2665
|
}
|
|
2467
|
-
const
|
|
2666
|
+
const parts = value.split(/\s+/).filter(Boolean);
|
|
2667
|
+
const selected = parseProviderModel(parts[0] || value, state.routeProvider || "deepseek");
|
|
2468
2668
|
state.routeProvider = selected.provider || "deepseek";
|
|
2469
2669
|
state.routeModel = selected.model || state.routeModel || "deepseek-v4-flash";
|
|
2470
|
-
|
|
2670
|
+
if (isReasoningLevel(parts[1])) state.routeReasoning = parts[1].toLowerCase();
|
|
2671
|
+
printSystemLine(`route=${state.routeProvider}/${state.routeModel}${state.routeReasoning ? ` reasoning=${state.routeReasoning}` : ""}`);
|
|
2471
2672
|
return true;
|
|
2472
2673
|
}
|
|
2473
2674
|
if (command === "main" || command === "model") {
|
|
@@ -2486,6 +2687,7 @@ async function handleCommand(line, state, packageDir) {
|
|
|
2486
2687
|
if (command === "main") {
|
|
2487
2688
|
state.mainProvider = "";
|
|
2488
2689
|
state.mainModel = "";
|
|
2690
|
+
state.mainReasoning = "";
|
|
2489
2691
|
printSystemLine("main=auto");
|
|
2490
2692
|
} else {
|
|
2491
2693
|
state.model = "";
|
|
@@ -2493,15 +2695,17 @@ async function handleCommand(line, state, packageDir) {
|
|
|
2493
2695
|
}
|
|
2494
2696
|
return true;
|
|
2495
2697
|
}
|
|
2496
|
-
const
|
|
2698
|
+
const parts = value.split(/\s+/).filter(Boolean);
|
|
2699
|
+
const selected = parseProviderModel(parts[0] || value, state.mainProvider || state.provider || "deepseek");
|
|
2497
2700
|
if (command === "main" || selected.provider) {
|
|
2498
2701
|
state.mainProvider = selected.provider || "deepseek";
|
|
2499
2702
|
state.mainModel = selected.model || "deepseek-v4-pro";
|
|
2703
|
+
if (isReasoningLevel(parts[1])) state.mainReasoning = parts[1].toLowerCase();
|
|
2500
2704
|
if (command === "model") {
|
|
2501
2705
|
state.provider = state.mainProvider;
|
|
2502
2706
|
state.model = state.mainModel;
|
|
2503
2707
|
}
|
|
2504
|
-
printSystemLine(`main=${state.mainProvider}/${state.mainModel}`);
|
|
2708
|
+
printSystemLine(`main=${state.mainProvider}/${state.mainModel}${state.mainReasoning ? ` reasoning=${state.mainReasoning}` : ""}`);
|
|
2505
2709
|
return true;
|
|
2506
2710
|
}
|
|
2507
2711
|
state.model = value;
|
package/src/model-routing.js
CHANGED
|
@@ -88,11 +88,11 @@ export const MODEL_PROVIDER_GROUPS = {
|
|
|
88
88
|
role: "regional/general",
|
|
89
89
|
description: "DashScope/OpenAI-compatible Qwen route for Chinese and general work.",
|
|
90
90
|
},
|
|
91
|
-
|
|
92
|
-
label: "Venice
|
|
91
|
+
venice: {
|
|
92
|
+
label: "Venice",
|
|
93
93
|
provider: "venice",
|
|
94
94
|
role: "alternate text",
|
|
95
|
-
description: "Venice
|
|
95
|
+
description: "Venice 1.2/1.1 and Gemma 4 Uncensored for optional manual routes.",
|
|
96
96
|
},
|
|
97
97
|
"venice-gpt": {
|
|
98
98
|
label: "Venice GPT",
|
|
@@ -128,21 +128,46 @@ export const AUXILIARY_MODEL_CATALOG = {
|
|
|
128
128
|
type: "image",
|
|
129
129
|
description: "Default auxiliary image-generation route through GRS AI-compatible APIs.",
|
|
130
130
|
},
|
|
131
|
+
{
|
|
132
|
+
id: "nano-banana-2-edit",
|
|
133
|
+
label: "Nano Banana 2 Edit",
|
|
134
|
+
type: "inpaint",
|
|
135
|
+
description: "Image edit route through GRS AI-compatible APIs when available.",
|
|
136
|
+
},
|
|
131
137
|
{
|
|
132
138
|
id: "gpt-image-2",
|
|
133
139
|
label: "GPT Image 2",
|
|
134
140
|
type: "image",
|
|
135
141
|
description: "High-quality image generation when available through the configured auxiliary endpoint.",
|
|
136
142
|
},
|
|
143
|
+
{
|
|
144
|
+
id: "gpt-image-2-edit",
|
|
145
|
+
label: "GPT Image 2 Edit",
|
|
146
|
+
type: "inpaint",
|
|
147
|
+
description: "High-quality image editing when available through the configured auxiliary endpoint.",
|
|
148
|
+
},
|
|
137
149
|
],
|
|
138
150
|
"venice-image": [
|
|
151
|
+
{ id: "wan-2-7-pro-edit", label: "Wan 2.7 Pro Edit", type: "inpaint", price: "$0.09/edit" },
|
|
139
152
|
{ id: "nano-banana-2", label: "Nano Banana 2", type: "image", price: "$0.10/image" },
|
|
153
|
+
{ id: "nano-banana-2-edit", label: "Nano Banana 2 Edit", type: "inpaint", price: "$0.10/edit" },
|
|
140
154
|
{ id: "gpt-image-2", label: "GPT Image 2", type: "image", price: "$0.27/image" },
|
|
141
155
|
{ id: "gpt-image-2-edit", label: "GPT Image 2 Edit", type: "inpaint", price: "$0.36/edit" },
|
|
142
|
-
{ id: "
|
|
156
|
+
{ id: "grok-imagine-image-pro", label: "Grok Imagine Pro", type: "image", price: "$0.09/image" },
|
|
143
157
|
{ id: "grok-imagine-image", label: "Grok Imagine", type: "image", price: "$0.03/image" },
|
|
158
|
+
{ id: "wan-2-7-text-to-image", label: "Wan 2.7", type: "image", price: "$0.04/image" },
|
|
159
|
+
{ id: "wan-2-7-pro-text-to-image", label: "Wan 2.7 Pro", type: "image", price: "$0.09/image" },
|
|
160
|
+
{ id: "qwen-image-2", label: "Qwen Image 2", type: "image", price: "$0.05/image" },
|
|
144
161
|
{ id: "qwen-image-2-pro", label: "Qwen Image 2 Pro", type: "image", price: "$0.10/image" },
|
|
162
|
+
{ id: "qwen-image-2-edit", label: "Qwen Image 2 Edit", type: "inpaint", price: "$0.05/edit" },
|
|
163
|
+
{ id: "qwen-image-2-pro-edit", label: "Qwen Image 2 Pro Edit", type: "inpaint", price: "$0.10/edit" },
|
|
145
164
|
{ id: "bria-bg-remover", label: "Background Remover", type: "image", price: "$0.03/image" },
|
|
165
|
+
{ id: "recraft-v4", label: "Recraft V4", type: "image", price: "$0.05/image" },
|
|
166
|
+
{ id: "recraft-v4-pro", label: "Recraft V4 Pro", type: "image", price: "$0.29/image" },
|
|
167
|
+
{ id: "flux-2-pro", label: "Flux 2 Pro", type: "image", price: "$0.04/image" },
|
|
168
|
+
{ id: "flux-2-max", label: "Flux 2 Max", type: "image", price: "$0.09/image" },
|
|
169
|
+
{ id: "nano-banana-pro", label: "Nano Banana Pro", type: "image", price: "$0.18/image" },
|
|
170
|
+
{ id: "nano-banana-pro-edit", label: "Nano Banana Pro Edit", type: "inpaint", price: "$0.18/edit" },
|
|
146
171
|
],
|
|
147
172
|
};
|
|
148
173
|
|
|
@@ -211,21 +236,21 @@ export const PROVIDER_MODEL_CATALOG = {
|
|
|
211
236
|
{
|
|
212
237
|
id: "venice-uncensored-1-2",
|
|
213
238
|
label: "Venice Uncensored 1.2",
|
|
214
|
-
bucket: "venice
|
|
239
|
+
bucket: "venice",
|
|
215
240
|
context: "128K",
|
|
216
241
|
description: "Current Venice uncensored text route.",
|
|
217
242
|
},
|
|
218
243
|
{
|
|
219
244
|
id: "venice-uncensored",
|
|
220
245
|
label: "Venice Uncensored 1.1",
|
|
221
|
-
bucket: "venice
|
|
246
|
+
bucket: "venice",
|
|
222
247
|
context: "32K",
|
|
223
248
|
description: "Working Venice uncensored 1.1 text route.",
|
|
224
249
|
},
|
|
225
250
|
{
|
|
226
251
|
id: "e2ee-venice-uncensored-24b-p",
|
|
227
252
|
label: "Venice Uncensored 1.1 E2EE",
|
|
228
|
-
bucket: "venice
|
|
253
|
+
bucket: "venice",
|
|
229
254
|
context: "32K",
|
|
230
255
|
hidden: true,
|
|
231
256
|
description: "Documented E2EE Venice 1.1 route; hidden from selectors until upstream stabilizes.",
|
|
@@ -233,7 +258,7 @@ export const PROVIDER_MODEL_CATALOG = {
|
|
|
233
258
|
{
|
|
234
259
|
id: "venice-uncensored-role-play",
|
|
235
260
|
label: "Venice Role Play Uncensored",
|
|
236
|
-
bucket: "venice
|
|
261
|
+
bucket: "venice",
|
|
237
262
|
context: "128K",
|
|
238
263
|
hidden: true,
|
|
239
264
|
description: "Role-play oriented Venice route.",
|
|
@@ -241,10 +266,38 @@ export const PROVIDER_MODEL_CATALOG = {
|
|
|
241
266
|
{
|
|
242
267
|
id: "gemma-4-uncensored",
|
|
243
268
|
label: "Gemma 4 Uncensored",
|
|
244
|
-
bucket: "venice
|
|
269
|
+
bucket: "venice",
|
|
245
270
|
context: "256K",
|
|
246
271
|
description: "Gemma-family uncensored Venice route.",
|
|
247
272
|
},
|
|
273
|
+
{
|
|
274
|
+
id: "google-gemma-4-31b-it",
|
|
275
|
+
label: "Google Gemma 4 31B Instruct",
|
|
276
|
+
bucket: "venice-gemma",
|
|
277
|
+
context: "256K",
|
|
278
|
+
description: "Gemma 4 instruct model through Venice.",
|
|
279
|
+
},
|
|
280
|
+
{
|
|
281
|
+
id: "google-gemma-4-26b-a4b-it",
|
|
282
|
+
label: "Google Gemma 4 26B A4B Instruct",
|
|
283
|
+
bucket: "venice-gemma",
|
|
284
|
+
context: "256K",
|
|
285
|
+
description: "Smaller Gemma 4 instruct model through Venice.",
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
id: "google-gemma-3-27b-it",
|
|
289
|
+
label: "Google Gemma 3 27B Instruct",
|
|
290
|
+
bucket: "venice-gemma",
|
|
291
|
+
context: "198K",
|
|
292
|
+
description: "Gemma 3 instruct model through Venice.",
|
|
293
|
+
},
|
|
294
|
+
{
|
|
295
|
+
id: "e2ee-gemma-3-27b-p",
|
|
296
|
+
label: "Gemma 3 27B E2EE",
|
|
297
|
+
bucket: "venice-gemma",
|
|
298
|
+
context: "40K",
|
|
299
|
+
description: "Private E2EE Gemma 3 route through Venice.",
|
|
300
|
+
},
|
|
248
301
|
{
|
|
249
302
|
id: "qwen3-6-27b",
|
|
250
303
|
label: "Qwen 3.6 27B",
|
|
@@ -252,6 +305,77 @@ export const PROVIDER_MODEL_CATALOG = {
|
|
|
252
305
|
context: "256K",
|
|
253
306
|
description: "Qwen-family Venice route.",
|
|
254
307
|
},
|
|
308
|
+
{
|
|
309
|
+
id: "qwen-3-6-plus",
|
|
310
|
+
label: "Qwen 3.6 Plus Uncensored",
|
|
311
|
+
bucket: "venice-qwen",
|
|
312
|
+
context: "1.0M",
|
|
313
|
+
description: "Long-context Qwen 3.6 Plus route through Venice.",
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
id: "qwen3-5-9b",
|
|
317
|
+
label: "Qwen 3.5 9B",
|
|
318
|
+
bucket: "venice-qwen",
|
|
319
|
+
context: "256K",
|
|
320
|
+
description: "Small fast Qwen-family Venice route.",
|
|
321
|
+
},
|
|
322
|
+
{
|
|
323
|
+
id: "qwen3-5-35b-a3b",
|
|
324
|
+
label: "Qwen 3.5 35B A3B",
|
|
325
|
+
bucket: "venice-qwen",
|
|
326
|
+
context: "256K",
|
|
327
|
+
description: "Mid-size Qwen-family Venice route.",
|
|
328
|
+
},
|
|
329
|
+
{
|
|
330
|
+
id: "qwen3-5-397b-a17b",
|
|
331
|
+
label: "Qwen 3.5 397B A17B",
|
|
332
|
+
bucket: "venice-qwen",
|
|
333
|
+
context: "128K",
|
|
334
|
+
description: "Large Qwen-family Venice route.",
|
|
335
|
+
},
|
|
336
|
+
{
|
|
337
|
+
id: "qwen3-coder-480b-a35b-instruct-turbo",
|
|
338
|
+
label: "Qwen 3 Coder 480B Turbo",
|
|
339
|
+
bucket: "venice-qwen",
|
|
340
|
+
context: "256K",
|
|
341
|
+
description: "Coding-oriented Qwen route through Venice.",
|
|
342
|
+
},
|
|
343
|
+
{
|
|
344
|
+
id: "qwen3-vl-235b-a22b",
|
|
345
|
+
label: "Qwen3 VL 235B",
|
|
346
|
+
bucket: "venice-qwen",
|
|
347
|
+
context: "256K",
|
|
348
|
+
description: "Vision-language Qwen route through Venice.",
|
|
349
|
+
},
|
|
350
|
+
{
|
|
351
|
+
id: "qwen3-235b-a22b-thinking-2507",
|
|
352
|
+
label: "Qwen 3 235B A22B Thinking",
|
|
353
|
+
bucket: "venice-qwen",
|
|
354
|
+
context: "128K",
|
|
355
|
+
description: "Qwen thinking route through Venice.",
|
|
356
|
+
},
|
|
357
|
+
{
|
|
358
|
+
id: "qwen3-235b-a22b-instruct-2507",
|
|
359
|
+
label: "Qwen 3 235B A22B Instruct",
|
|
360
|
+
bucket: "venice-qwen",
|
|
361
|
+
context: "128K",
|
|
362
|
+
description: "Qwen instruct route through Venice.",
|
|
363
|
+
},
|
|
364
|
+
{
|
|
365
|
+
id: "qwen3-next-80b",
|
|
366
|
+
label: "Qwen 3 Next 80B",
|
|
367
|
+
bucket: "venice-qwen",
|
|
368
|
+
context: "256K",
|
|
369
|
+
description: "Qwen Next route through Venice.",
|
|
370
|
+
},
|
|
371
|
+
{
|
|
372
|
+
id: "qwen3-coder-480b-a35b-instruct",
|
|
373
|
+
label: "Qwen 3 Coder 480B",
|
|
374
|
+
bucket: "venice-qwen",
|
|
375
|
+
context: "256K",
|
|
376
|
+
hidden: true,
|
|
377
|
+
description: "Deprecated Qwen Coder route; hidden by default.",
|
|
378
|
+
},
|
|
255
379
|
{
|
|
256
380
|
id: "openai-gpt-55",
|
|
257
381
|
label: "GPT-5.5 via Venice",
|
|
@@ -259,6 +383,69 @@ export const PROVIDER_MODEL_CATALOG = {
|
|
|
259
383
|
context: "1.0M",
|
|
260
384
|
description: "OpenAI-family Venice-routed model.",
|
|
261
385
|
},
|
|
386
|
+
{
|
|
387
|
+
id: "openai-gpt-55-pro",
|
|
388
|
+
label: "GPT-5.5 Pro via Venice",
|
|
389
|
+
bucket: "venice-gpt",
|
|
390
|
+
context: "1.0M",
|
|
391
|
+
description: "High-capacity GPT-5.5 Pro route through Venice.",
|
|
392
|
+
},
|
|
393
|
+
{
|
|
394
|
+
id: "openai-gpt-54",
|
|
395
|
+
label: "GPT-5.4 via Venice",
|
|
396
|
+
bucket: "venice-gpt",
|
|
397
|
+
context: "1.0M",
|
|
398
|
+
description: "GPT-5.4 route through Venice.",
|
|
399
|
+
},
|
|
400
|
+
{
|
|
401
|
+
id: "openai-gpt-54-pro",
|
|
402
|
+
label: "GPT-5.4 Pro via Venice",
|
|
403
|
+
bucket: "venice-gpt",
|
|
404
|
+
context: "1.0M",
|
|
405
|
+
description: "High-capacity GPT-5.4 Pro route through Venice.",
|
|
406
|
+
},
|
|
407
|
+
{
|
|
408
|
+
id: "openai-gpt-54-mini",
|
|
409
|
+
label: "GPT-5.4 Mini via Venice",
|
|
410
|
+
bucket: "venice-gpt",
|
|
411
|
+
context: "400K",
|
|
412
|
+
description: "Small fast GPT route through Venice.",
|
|
413
|
+
},
|
|
414
|
+
{
|
|
415
|
+
id: "openai-gpt-53-codex",
|
|
416
|
+
label: "GPT-5.3 Codex via Venice",
|
|
417
|
+
bucket: "venice-gpt",
|
|
418
|
+
context: "400K",
|
|
419
|
+
description: "Coding-optimized GPT route through Venice.",
|
|
420
|
+
},
|
|
421
|
+
{
|
|
422
|
+
id: "openai-gpt-52",
|
|
423
|
+
label: "GPT-5.2 via Venice",
|
|
424
|
+
bucket: "venice-gpt",
|
|
425
|
+
context: "256K",
|
|
426
|
+
description: "Professional-work GPT route through Venice.",
|
|
427
|
+
},
|
|
428
|
+
{
|
|
429
|
+
id: "openai-gpt-52-codex",
|
|
430
|
+
label: "GPT-5.2 Codex via Venice",
|
|
431
|
+
bucket: "venice-gpt",
|
|
432
|
+
context: "256K",
|
|
433
|
+
description: "Codex-flavored GPT-5.2 route through Venice.",
|
|
434
|
+
},
|
|
435
|
+
{
|
|
436
|
+
id: "openai-gpt-4o-2024-11-20",
|
|
437
|
+
label: "GPT-4o via Venice",
|
|
438
|
+
bucket: "venice-gpt",
|
|
439
|
+
context: "128K",
|
|
440
|
+
description: "GPT-4o route through Venice.",
|
|
441
|
+
},
|
|
442
|
+
{
|
|
443
|
+
id: "openai-gpt-4o-mini-2024-07-18",
|
|
444
|
+
label: "GPT-4o Mini via Venice",
|
|
445
|
+
bucket: "venice-gpt",
|
|
446
|
+
context: "128K",
|
|
447
|
+
description: "Small GPT-4o route through Venice.",
|
|
448
|
+
},
|
|
262
449
|
{
|
|
263
450
|
id: "claude-sonnet-4-6",
|
|
264
451
|
label: "Claude Sonnet 4.6 via Venice",
|
|
@@ -266,6 +453,41 @@ export const PROVIDER_MODEL_CATALOG = {
|
|
|
266
453
|
context: "1.0M",
|
|
267
454
|
description: "Claude-family Venice-routed model.",
|
|
268
455
|
},
|
|
456
|
+
{
|
|
457
|
+
id: "claude-opus-4-7",
|
|
458
|
+
label: "Claude Opus 4.7 via Venice",
|
|
459
|
+
bucket: "venice-claude",
|
|
460
|
+
context: "1.0M",
|
|
461
|
+
description: "High-capacity Claude Opus route through Venice.",
|
|
462
|
+
},
|
|
463
|
+
{
|
|
464
|
+
id: "claude-opus-4-6-fast",
|
|
465
|
+
label: "Claude Opus 4.6 Fast via Venice",
|
|
466
|
+
bucket: "venice-claude",
|
|
467
|
+
context: "1.0M",
|
|
468
|
+
description: "Fast Claude Opus route through Venice.",
|
|
469
|
+
},
|
|
470
|
+
{
|
|
471
|
+
id: "claude-opus-4-6",
|
|
472
|
+
label: "Claude Opus 4.6 via Venice",
|
|
473
|
+
bucket: "venice-claude",
|
|
474
|
+
context: "1.0M",
|
|
475
|
+
description: "Claude Opus route through Venice.",
|
|
476
|
+
},
|
|
477
|
+
{
|
|
478
|
+
id: "claude-opus-4-5",
|
|
479
|
+
label: "Claude Opus 4.5 via Venice",
|
|
480
|
+
bucket: "venice-claude",
|
|
481
|
+
context: "198K",
|
|
482
|
+
description: "Claude Opus 4.5 route through Venice.",
|
|
483
|
+
},
|
|
484
|
+
{
|
|
485
|
+
id: "claude-sonnet-4-5",
|
|
486
|
+
label: "Claude Sonnet 4.5 via Venice",
|
|
487
|
+
bucket: "venice-claude",
|
|
488
|
+
context: "198K",
|
|
489
|
+
description: "Claude Sonnet 4.5 route through Venice.",
|
|
490
|
+
},
|
|
269
491
|
],
|
|
270
492
|
qwen: [
|
|
271
493
|
{
|
|
@@ -274,6 +496,12 @@ export const PROVIDER_MODEL_CATALOG = {
|
|
|
274
496
|
role: "default",
|
|
275
497
|
description: "DashScope OpenAI-compatible route.",
|
|
276
498
|
},
|
|
499
|
+
{
|
|
500
|
+
id: "qwen-turbo",
|
|
501
|
+
label: "Qwen Turbo",
|
|
502
|
+
role: "fast",
|
|
503
|
+
description: "Fast DashScope OpenAI-compatible Qwen route.",
|
|
504
|
+
},
|
|
277
505
|
{
|
|
278
506
|
id: "qwen-max",
|
|
279
507
|
label: "Qwen Max",
|
|
@@ -497,6 +725,7 @@ export function getModelRoleDefaults(overrides = {}) {
|
|
|
497
725
|
command: "/route",
|
|
498
726
|
provider: presets.fast.provider,
|
|
499
727
|
model: presets.fast.model,
|
|
728
|
+
reasoning: overrides.routeReasoning || process.env.AGINTI_ROUTE_REASONING || "",
|
|
500
729
|
description: "Fast planner and triage model. Default: DeepSeek V4 Flash.",
|
|
501
730
|
},
|
|
502
731
|
main: {
|
|
@@ -505,6 +734,7 @@ export function getModelRoleDefaults(overrides = {}) {
|
|
|
505
734
|
command: "/model",
|
|
506
735
|
provider: presets.complex.provider,
|
|
507
736
|
model: presets.complex.model,
|
|
737
|
+
reasoning: overrides.mainReasoning || process.env.AGINTI_MAIN_REASONING || "",
|
|
508
738
|
description: "Complex executor for coding, debugging, writing, and long tasks. Default: DeepSeek V4 Pro.",
|
|
509
739
|
},
|
|
510
740
|
spare: {
|