@lazyingart/agintiflow 0.20.7 → 0.20.8

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.
@@ -48,12 +48,15 @@ Interactive commands:
48
48
 
49
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.
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.
52
+
51
53
  `/venice` opens a two-step selector for the Venice route and main models. The current text choices are:
52
54
 
53
55
  ```text
54
56
  venice/venice-uncensored-1-2
55
57
  venice/venice-uncensored
56
58
  venice/gemma-4-uncensored
59
+ Disable Venice
57
60
  ```
58
61
 
59
62
  For scripts or non-interactive terminals, `/venice` uses Venice 1.2 for both roles. You can also set both roles directly with `/venice 1.2`, `/venice 1.1`, or `/venice gemma`. Use two values to set route and main separately, for example `/venice 1.2 gemma`.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lazyingart/agintiflow",
3
- "version": "0.20.7",
3
+ "version": "0.20.8",
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",
@@ -53,7 +53,9 @@ Interactive equivalents:
53
53
  /auxiliary model grsai/nano-banana-2
54
54
  ```
55
55
 
56
- `/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), and `venice/gemma-4-uncensored` (Gemma 4). 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` restores `deepseek/deepseek-v4-flash` for route and `deepseek/deepseek-v4-pro` for main.
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
+
58
+ `/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.
57
59
 
58
60
  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.
59
61
 
@@ -10,6 +10,7 @@ import {
10
10
  selectModelRoute,
11
11
  } from "../src/model-routing.js";
12
12
  import { parseTextToolCalls, usesTextToolProtocol } from "../src/model-client.js";
13
+ import { modelRoleChoices } from "../src/interactive-cli.js";
13
14
 
14
15
  const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
15
16
 
@@ -111,6 +112,32 @@ assert(MODEL_PROVIDER_GROUPS["venice-gpt"].provider === "venice", "venice-gpt gr
111
112
  assert(modelsForProviderGroup("venice-gemma").some((item) => item.id === "gemma-4-uncensored"), "venice-gemma bucket missing Gemma");
112
113
  assert(modelsForProviderGroup("venice-uncensored").some((item) => item.id === "e2ee-venice-uncensored-24b-p"), "venice-uncensored bucket missing Venice 1.1");
113
114
  assert(AUXILIARY_MODEL_CATALOG["venice-image"].some((item) => item.id === "gpt-image-2"), "Venice image catalog missing GPT Image 2");
115
+ const routeChoices = modelRoleChoices("route").map((item) => `${item.provider}/${item.model}`);
116
+ const mainChoices = modelRoleChoices("main").map((item) => `${item.provider}/${item.model}`);
117
+ const spareChoices = modelRoleChoices("spare").map((item) => `${item.provider}/${item.model}`);
118
+ assert(JSON.stringify(routeChoices) === JSON.stringify(mainChoices), "route and main selectors should share the same text-model list");
119
+ assert(JSON.stringify(routeChoices) === JSON.stringify(spareChoices), "route and spare selectors should share the same text-model list");
120
+ for (const expected of [
121
+ "deepseek/deepseek-v4-flash",
122
+ "deepseek/deepseek-v4-pro",
123
+ "venice/venice-uncensored-1-2",
124
+ "venice/venice-uncensored",
125
+ "venice/gemma-4-uncensored",
126
+ "venice/openai-gpt-55",
127
+ "venice/claude-sonnet-4-6",
128
+ "venice/qwen3-6-27b",
129
+ "openai/gpt-5.5",
130
+ "openai/gpt-5.4",
131
+ "openai/gpt-5.4-mini",
132
+ "openai/gpt-5.3-codex",
133
+ "openai/gpt-5.3-codex-spark",
134
+ "qwen/qwen-plus",
135
+ "mock/mock-agent",
136
+ ]) {
137
+ assert(routeChoices.includes(expected), `shared model selector missing ${expected}`);
138
+ }
139
+ assert(!routeChoices.includes("venice/e2ee-venice-uncensored-24b-p"), "shared model selector should hide unstable E2EE Venice 1.1");
140
+ assert(modelRoleChoices("auxiliary").some((item) => item.provider === "grsai"), "auxiliary selector missing GRS AI");
114
141
  const parsedTextToolCalls = parseTextToolCalls('[TOOL_CALLS]list_files[ARGS]call_123[ARGS]{"path":".","maxDepth":1}');
115
142
  assert(parsedTextToolCalls.length === 1, "Venice text tool-call parser did not detect encoded tool call");
116
143
  assert(parsedTextToolCalls[0].function.name === "list_files", "Venice text tool-call parser returned wrong tool name");
@@ -151,6 +178,7 @@ console.log(
151
178
  "route-overrides",
152
179
  "provider-groups",
153
180
  "auxiliary-catalog",
181
+ "shared-model-selectors",
154
182
  "venice-text-tool-parser",
155
183
  "cli-models-command",
156
184
  "venice-shortcut",
@@ -1694,6 +1694,13 @@ function veniceTextModelChoices() {
1694
1694
  label: "Gemma 4",
1695
1695
  description: "Gemma-family Venice text model; 256K context",
1696
1696
  },
1697
+ {
1698
+ action: "disable",
1699
+ provider: "deepseek",
1700
+ model: "deepseek-v4-flash",
1701
+ label: "Disable Venice",
1702
+ description: "restore DeepSeek route/main defaults",
1703
+ },
1697
1704
  ];
1698
1705
  }
1699
1706
 
@@ -1789,98 +1796,69 @@ function printModelRoles(state) {
1789
1796
  );
1790
1797
  }
1791
1798
 
1792
- function modelRoleChoices(role = "main") {
1799
+ function compactReasoning(model = {}) {
1800
+ const values = Array.isArray(model.reasoning) ? model.reasoning : [];
1801
+ if (values.length === 0) return "";
1802
+ const preferred = model.id === "gpt-5.4-mini" || model.id === "gpt-5.3-codex-spark" ? "high" : "medium";
1803
+ return `${preferred} reasoning`;
1804
+ }
1805
+
1806
+ function modelSelectorGroup(provider, model = {}) {
1807
+ if (provider === "deepseek") return "DeepSeek";
1808
+ if (provider === "openai") return "OpenAI";
1809
+ if (provider === "qwen") return "Qwen";
1810
+ if (provider === "mock") return "Mock";
1811
+ if (provider === "venice") {
1812
+ if (model.bucket === "venice-uncensored") return "Venice Uncensored";
1813
+ if (model.bucket === "venice-gpt") return "Venice GPT";
1814
+ if (model.bucket === "venice-claude") return "Venice Claude";
1815
+ if (model.bucket === "venice-gemma") return "Venice Gemma";
1816
+ if (model.bucket === "venice-qwen") return "Venice Qwen";
1817
+ return "Venice";
1818
+ }
1819
+ return provider;
1820
+ }
1821
+
1822
+ function textModelRoleChoices() {
1823
+ const providerOrder = ["deepseek", "venice", "openai", "qwen", "mock"];
1824
+ const veniceOrder = [
1825
+ "venice-uncensored-1-2",
1826
+ "venice-uncensored",
1827
+ "gemma-4-uncensored",
1828
+ "openai-gpt-55",
1829
+ "claude-sonnet-4-6",
1830
+ "qwen3-6-27b",
1831
+ ];
1832
+ const choices = [];
1833
+ for (const provider of providerOrder) {
1834
+ let models = PROVIDER_MODEL_CATALOG[provider] || [];
1835
+ if (provider === "venice") {
1836
+ const byId = new Map(models.filter((model) => !model.hidden).map((model) => [model.id, model]));
1837
+ models = veniceOrder.map((id) => byId.get(id)).filter(Boolean);
1838
+ } else {
1839
+ models = models.filter((model) => !model.hidden);
1840
+ }
1841
+ for (const model of models) {
1842
+ const group = modelSelectorGroup(provider, model);
1843
+ const reasoning = compactReasoning(model);
1844
+ const context = model.context ? `${model.context} context` : "";
1845
+ const details = [reasoning, context, model.description].filter(Boolean).join("; ");
1846
+ choices.push({
1847
+ provider,
1848
+ model: model.id,
1849
+ label: `${group} · ${model.label}`,
1850
+ group,
1851
+ description: details,
1852
+ reasoningDefault: reasoning ? reasoning.split(" ")[0] : "",
1853
+ });
1854
+ }
1855
+ }
1856
+ return choices;
1857
+ }
1858
+
1859
+ export function modelRoleChoices(role = "main") {
1860
+ if (role !== "auxiliary") return textModelRoleChoices();
1793
1861
  const common = [
1794
- {
1795
- provider: "deepseek",
1796
- model: "deepseek-v4-flash",
1797
- label: "DeepSeek V4 Flash",
1798
- description: "fast planner, short shell/browser/code work",
1799
- route: true,
1800
- },
1801
- {
1802
- provider: "deepseek",
1803
- model: "deepseek-v4-pro",
1804
- label: "DeepSeek V4 Pro",
1805
- description: "complex coding, debugging, writing, and long tasks",
1806
- main: true,
1807
- spare: true,
1808
- },
1809
- {
1810
- provider: "venice",
1811
- model: "venice-uncensored-1-2",
1812
- label: "Venice 1.2",
1813
- description: "Venice text route; use /auth venice if missing",
1814
- route: true,
1815
- main: true,
1816
- spare: true,
1817
- },
1818
- {
1819
- provider: "venice",
1820
- model: "venice-uncensored",
1821
- label: "Venice 1.1",
1822
- description: "legacy Venice text route; use /auth venice if missing",
1823
- route: true,
1824
- main: true,
1825
- spare: true,
1826
- },
1827
- {
1828
- provider: "venice",
1829
- model: "gemma-4-uncensored",
1830
- label: "Gemma 4",
1831
- description: "Gemma-family Venice route; use /auth venice if missing",
1832
- route: true,
1833
- main: true,
1834
- spare: true,
1835
- },
1836
- {
1837
- provider: "openai",
1838
- model: "gpt-5.5",
1839
- label: "OpenAI GPT-5.5",
1840
- description: "frontier spare/manual model",
1841
- main: true,
1842
- spare: true,
1843
- },
1844
- {
1845
- provider: "openai",
1846
- model: "gpt-5.4",
1847
- label: "OpenAI GPT-5.4",
1848
- description: "strong everyday coding spare",
1849
- main: true,
1850
- spare: true,
1851
- },
1852
- {
1853
- provider: "openai",
1854
- model: "gpt-5.4-mini",
1855
- label: "OpenAI GPT-5.4 Mini",
1856
- description: "small fast spare route",
1857
- route: true,
1858
- spare: true,
1859
- },
1860
- {
1861
- provider: "qwen",
1862
- model: "qwen-plus",
1863
- label: "Qwen Plus",
1864
- description: "general Qwen route",
1865
- route: true,
1866
- },
1867
- {
1868
- provider: "qwen",
1869
- model: "qwen-max",
1870
- label: "Qwen Max",
1871
- description: "larger Qwen route",
1872
- main: true,
1873
- spare: true,
1874
- },
1875
- {
1876
- provider: "mock",
1877
- model: "mock-agent",
1878
- label: "Mock Agent",
1879
- description: "local deterministic test route",
1880
- route: true,
1881
- main: true,
1882
- spare: true,
1883
- },
1884
1862
  {
1885
1863
  provider: "grsai",
1886
1864
  model: "nano-banana-2",
@@ -1903,22 +1881,7 @@ function modelRoleChoices(role = "main") {
1903
1881
  auxiliary: true,
1904
1882
  },
1905
1883
  ];
1906
- const filtered = common.filter((item) => {
1907
- if (role === "route") return item.route;
1908
- if (role === "spare") return item.spare;
1909
- if (role === "auxiliary") return item.auxiliary;
1910
- return item.main;
1911
- });
1912
- if (role === "route") {
1913
- return filtered.sort((a, b) => Number(b.model === "deepseek-v4-flash") - Number(a.model === "deepseek-v4-flash"));
1914
- }
1915
- if (role === "spare") {
1916
- return filtered.sort((a, b) => Number(b.model === "gpt-5.4") - Number(a.model === "gpt-5.4"));
1917
- }
1918
- if (role === "auxiliary") {
1919
- return filtered.sort((a, b) => Number(b.provider === "grsai") - Number(a.provider === "grsai"));
1920
- }
1921
- return filtered.sort((a, b) => Number(b.model === "deepseek-v4-pro") - Number(a.model === "deepseek-v4-pro"));
1884
+ return common.filter((item) => item.auxiliary).sort((a, b) => Number(b.provider === "grsai") - Number(a.provider === "grsai"));
1922
1885
  }
1923
1886
 
1924
1887
  function providerChoices() {
@@ -1957,6 +1920,7 @@ function providerChoices() {
1957
1920
  }
1958
1921
 
1959
1922
  function modelChoiceLine(option) {
1923
+ if (option.action === "disable") return `${option.label} ${option.description}`;
1960
1924
  return `${option.label} ${option.provider}/${option.model} ${option.description}`;
1961
1925
  }
1962
1926
 
@@ -2092,7 +2056,7 @@ async function pickModelRole(role, state) {
2092
2056
  } else if (role === "spare") {
2093
2057
  state.spareProvider = selected.provider;
2094
2058
  state.spareModel = selected.model;
2095
- state.spareReasoning = state.spareReasoning || "medium";
2059
+ state.spareReasoning = selected.reasoningDefault || state.spareReasoning || "medium";
2096
2060
  printSystemLine(`spare=${state.spareProvider}/${state.spareModel} reasoning=${state.spareReasoning}`);
2097
2061
  } else if (role === "auxiliary") {
2098
2062
  state.auxiliaryProvider = selected.provider;
@@ -2120,10 +2084,15 @@ async function pickVeniceRouteAndMain(state) {
2120
2084
  initialIndex: routeIndex,
2121
2085
  });
2122
2086
  if (!route) return false;
2087
+ if (route.action === "disable") {
2088
+ useDeepSeekDefaults(state);
2089
+ printSystemLine("venice=off routing=smart route=deepseek/deepseek-v4-flash main=deepseek/deepseek-v4-pro");
2090
+ return true;
2091
+ }
2123
2092
 
2124
2093
  const mainIndex = Math.max(
2125
- options.findIndex((item) => item.provider === state.mainProvider && item.model === state.mainModel),
2126
- options.findIndex((item) => item.model === route.model),
2094
+ options.findIndex((item) => item.action !== "disable" && item.provider === state.mainProvider && item.model === state.mainModel),
2095
+ options.findIndex((item) => item.action !== "disable" && item.model === route.model),
2127
2096
  0
2128
2097
  );
2129
2098
  const main = await selectModelChoice({
@@ -2133,6 +2102,11 @@ async function pickVeniceRouteAndMain(state) {
2133
2102
  initialIndex: mainIndex,
2134
2103
  });
2135
2104
  if (!main) return false;
2105
+ if (main.action === "disable") {
2106
+ useDeepSeekDefaults(state);
2107
+ printSystemLine("venice=off routing=smart route=deepseek/deepseek-v4-flash main=deepseek/deepseek-v4-pro");
2108
+ return true;
2109
+ }
2136
2110
 
2137
2111
  useVeniceModels(state, route.model, main.model);
2138
2112
  printSystemLine(`venice=on routing=smart route=venice/${state.routeModel} main=venice/${state.mainModel}`);
@@ -216,24 +216,26 @@ export const PROVIDER_MODEL_CATALOG = {
216
216
  description: "Current Venice uncensored text route.",
217
217
  },
218
218
  {
219
- id: "e2ee-venice-uncensored-24b-p",
219
+ id: "venice-uncensored",
220
220
  label: "Venice Uncensored 1.1",
221
221
  bucket: "venice-uncensored",
222
222
  context: "32K",
223
- description: "E2EE Venice uncensored 1.1 text route.",
223
+ description: "Working Venice uncensored 1.1 text route.",
224
224
  },
225
225
  {
226
- id: "venice-uncensored",
227
- label: "Venice Uncensored Legacy",
226
+ id: "e2ee-venice-uncensored-24b-p",
227
+ label: "Venice Uncensored 1.1 E2EE",
228
228
  bucket: "venice-uncensored",
229
229
  context: "32K",
230
- description: "Deprecated legacy Venice uncensored text route.",
230
+ hidden: true,
231
+ description: "Documented E2EE Venice 1.1 route; hidden from selectors until upstream stabilizes.",
231
232
  },
232
233
  {
233
234
  id: "venice-uncensored-role-play",
234
235
  label: "Venice Role Play Uncensored",
235
236
  bucket: "venice-uncensored",
236
237
  context: "128K",
238
+ hidden: true,
237
239
  description: "Role-play oriented Venice route.",
238
240
  },
239
241
  {