@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 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 |
@@ -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
@@ -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, Enter to confirm, and Esc to cancel. 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.
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 shared list is grouped as DeepSeek, Venice Uncensored, Venice GPT/Claude/Gemma/Qwen, OpenAI, Qwen, and Mock. OpenAI entries show the recommended default reasoning effort in the description; `/spare` stores that reasoning value when selected.
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-uncensored` | Venice | Venice-native uncensored text models. |
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-family models through Venice. |
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.13",
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-gemma").some((item) => item.id === "gemma-4-uncensored"), "venice-gemma bucket missing Gemma");
113
- assert(modelsForProviderGroup("venice-uncensored").some((item) => item.id === "e2ee-venice-uncensored-24b-p"), "venice-uncensored bucket missing Venice 1.1");
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");
@@ -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-uncensored") return "Venice Uncensored";
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
- function textModelRoleChoices() {
1847
- const providerOrder = ["deepseek", "venice", "openai", "qwen", "mock"];
1848
- const veniceOrder = [
1849
- "venice-uncensored-1-2",
1850
- "venice-uncensored",
1851
- "gemma-4-uncensored",
1852
- "openai-gpt-55",
1853
- "claude-sonnet-4-6",
1854
- "qwen3-6-27b",
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 provider of providerOrder) {
1858
- let models = PROVIDER_MODEL_CATALOG[provider] || [];
1859
- if (provider === "venice") {
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
- const common = [
1886
- {
1887
- provider: "grsai",
1888
- model: "nano-banana-2",
1889
- label: "GRS AI Nano Banana",
1890
- description: "default auxiliary image model",
1891
- auxiliary: true,
1892
- },
1967
+ return auxiliaryModelRoleChoices();
1968
+ }
1969
+
1970
+ function auxiliaryGroupChoices() {
1971
+ return [
1893
1972
  {
1894
- provider: "venice",
1895
- model: "gpt-image-2",
1896
- label: "Venice GPT Image 2",
1897
- description: "high-quality Venice image generation",
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
- provider: "venice",
1902
- model: "nano-banana-2",
1903
- label: "Venice Nano Banana 2",
1904
- description: "Venice image generation route",
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
- return common.filter((item) => item.auxiliary).sort((a, b) => Number(b.provider === "grsai") - Number(a.provider === "grsai"));
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
- function selectModelChoice({ title, subtitle, options, initialIndex = 0 }) {
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(null);
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
- const initialIndex = Math.max(
2055
- options.findIndex((item) => item.provider === currentProvider && item.model === currentModel),
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
- const selected = await selectModelChoice({
2059
- title:
2060
- role === "route"
2061
- ? "Select route model"
2062
- : role === "spare"
2063
- ? "Select spare model"
2064
- : role === "auxiliary"
2065
- ? "Select auxiliary model"
2066
- : "Select main model",
2067
- subtitle: "Up/Down/Left/Right selects, Enter confirms, Esc cancels.",
2068
- options,
2069
- initialIndex,
2070
- });
2071
- if (!selected) return false;
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
- printSystemLine(`route=${state.routeProvider}/${state.routeModel}`);
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 = selected.reasoningDefault || state.spareReasoning || "medium";
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
- printSystemLine(`main=${state.mainProvider}/${state.mainModel}`);
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
- const routeIndex = Math.max(
2286
+ let routeIndex = Math.max(
2101
2287
  options.findIndex((item) => item.provider === state.routeProvider && item.model === state.routeModel),
2102
2288
  0
2103
2289
  );
2104
- const route = await selectModelChoice({
2105
- title: "Select Venice route model",
2106
- subtitle: "Route handles planning and short turns. Up/Down selects, Enter confirms, Esc cancels.",
2107
- options,
2108
- initialIndex: routeIndex,
2109
- });
2110
- if (!route) return false;
2111
- if (route.action === "disable") {
2112
- useDeepSeekDefaults(state);
2113
- printSystemLine("venice=off routing=smart route=deepseek/deepseek-v4-flash main=deepseek/deepseek-v4-pro");
2114
- return true;
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
- const mainIndex = Math.max(
2118
- options.findIndex((item) => item.action !== "disable" && item.provider === state.mainProvider && item.model === state.mainModel),
2119
- options.findIndex((item) => item.action !== "disable" && item.model === route.model),
2120
- 0
2121
- );
2122
- const main = await selectModelChoice({
2123
- title: "Select Venice main model",
2124
- subtitle: "Main handles complex work. Up/Down selects, Enter confirms, Esc cancels.",
2125
- options,
2126
- initialIndex: mainIndex,
2127
- });
2128
- if (!main) return false;
2129
- if (main.action === "disable") {
2130
- useDeepSeekDefaults(state);
2131
- printSystemLine("venice=off routing=smart route=deepseek/deepseek-v4-flash main=deepseek/deepseek-v4-pro");
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 model grsai/nano-banana-2`, `/auxiliary image`, or `/auxiliary off`.",
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 selected = parseProviderModel(value, state.routeProvider || "deepseek");
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
- printSystemLine(`route=${state.routeProvider}/${state.routeModel}`);
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 selected = parseProviderModel(value, state.mainProvider || state.provider || "deepseek");
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;
@@ -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
- "venice-uncensored": {
92
- label: "Venice Uncensored",
91
+ venice: {
92
+ label: "Venice",
93
93
  provider: "venice",
94
94
  role: "alternate text",
95
- description: "Venice uncensored text models for optional manual routes.",
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: "wan-2-7-pro-edit", label: "Wan 2.7 Pro Edit", type: "inpaint", price: "$0.09/edit" },
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-uncensored",
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-uncensored",
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-uncensored",
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-uncensored",
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-gemma",
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: {