@lazyingart/agintiflow 0.20.2 → 0.20.4
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/package.json +1 -1
- package/public/app.js +3 -1
- package/public/index.html +10 -8
- package/public/styles.css +18 -2
- package/scripts/smoke-cli-chat.js +17 -1
- package/scripts/smoke-model-roles.js +14 -1
- package/src/interactive-cli.js +16 -2
- package/src/model-client.js +55 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lazyingart/agintiflow",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.4",
|
|
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",
|
package/public/app.js
CHANGED
|
@@ -1136,7 +1136,9 @@ function renderModelOptions() {
|
|
|
1136
1136
|
modelRoutePillEl.textContent =
|
|
1137
1137
|
mode === "manual"
|
|
1138
1138
|
? `${provider} · ${primary}`
|
|
1139
|
-
: `${mode} ·
|
|
1139
|
+
: `${mode} · ${routeLabel} -> ${mainLabel}`;
|
|
1140
|
+
modelRoutePillEl.title =
|
|
1141
|
+
mode === "manual" ? `Manual route: ${provider}/${primary}` : `Route: ${routeLabel}. Main: ${mainLabel}.`;
|
|
1140
1142
|
}
|
|
1141
1143
|
if (!modelCatalogEl) return;
|
|
1142
1144
|
if (options.length === 0) {
|
package/public/index.html
CHANGED
|
@@ -114,14 +114,7 @@
|
|
|
114
114
|
|
|
115
115
|
<p id="routing-hint" class="subtle route-hint"></p>
|
|
116
116
|
<p id="model-route-status" class="subtle route-hint"></p>
|
|
117
|
-
<
|
|
118
|
-
<div class="model-catalog-head">
|
|
119
|
-
<span>Route</span>
|
|
120
|
-
<strong id="model-route-pill">DeepSeek flash/pro</strong>
|
|
121
|
-
</div>
|
|
122
|
-
<div id="model-role-grid" class="model-role-grid"></div>
|
|
123
|
-
<div id="model-catalog" class="model-catalog"></div>
|
|
124
|
-
</section>
|
|
117
|
+
<p id="model-route-pill" class="route-pill">DeepSeek flash/pro</p>
|
|
125
118
|
|
|
126
119
|
<label>
|
|
127
120
|
<span data-i18n="taskProfileLabel">Task profile</span>
|
|
@@ -381,6 +374,15 @@
|
|
|
381
374
|
</div>
|
|
382
375
|
</section>
|
|
383
376
|
|
|
377
|
+
<section class="settings-section model-catalog-panel" aria-label="Model catalog">
|
|
378
|
+
<div class="model-catalog-head">
|
|
379
|
+
<span>Catalog</span>
|
|
380
|
+
<strong>Provider models</strong>
|
|
381
|
+
</div>
|
|
382
|
+
<div id="model-role-grid" class="model-role-grid"></div>
|
|
383
|
+
<div id="model-catalog" class="model-catalog"></div>
|
|
384
|
+
</section>
|
|
385
|
+
|
|
384
386
|
<section class="settings-section">
|
|
385
387
|
<div class="settings-section-head">
|
|
386
388
|
<strong>Browser and target</strong>
|
package/public/styles.css
CHANGED
|
@@ -139,6 +139,22 @@ h1 {
|
|
|
139
139
|
#fffdfa;
|
|
140
140
|
}
|
|
141
141
|
|
|
142
|
+
.route-pill {
|
|
143
|
+
max-width: 100%;
|
|
144
|
+
overflow: hidden;
|
|
145
|
+
margin: -2px 0 0;
|
|
146
|
+
padding: 8px 10px;
|
|
147
|
+
border: 1px solid rgba(15, 118, 110, 0.16);
|
|
148
|
+
border-radius: 999px;
|
|
149
|
+
background: rgba(204, 251, 241, 0.42);
|
|
150
|
+
color: #0f766e;
|
|
151
|
+
font-size: 0.78rem;
|
|
152
|
+
font-weight: 800;
|
|
153
|
+
line-height: 1.25;
|
|
154
|
+
text-overflow: ellipsis;
|
|
155
|
+
white-space: nowrap;
|
|
156
|
+
}
|
|
157
|
+
|
|
142
158
|
.model-catalog-head {
|
|
143
159
|
display: flex;
|
|
144
160
|
align-items: center;
|
|
@@ -168,7 +184,7 @@ h1 {
|
|
|
168
184
|
.model-role-grid {
|
|
169
185
|
display: grid;
|
|
170
186
|
gap: 8px;
|
|
171
|
-
grid-template-columns: repeat(
|
|
187
|
+
grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
|
|
172
188
|
}
|
|
173
189
|
|
|
174
190
|
.model-role-card {
|
|
@@ -244,7 +260,7 @@ h1 {
|
|
|
244
260
|
.model-chip {
|
|
245
261
|
display: grid;
|
|
246
262
|
gap: 2px;
|
|
247
|
-
flex: 1 1
|
|
263
|
+
flex: 1 1 180px;
|
|
248
264
|
min-width: 0;
|
|
249
265
|
padding: 9px 11px;
|
|
250
266
|
border: 1px solid rgba(15, 118, 110, 0.2);
|
|
@@ -4,7 +4,14 @@ import fs from "node:fs/promises";
|
|
|
4
4
|
import os from "node:os";
|
|
5
5
|
import path from "node:path";
|
|
6
6
|
import { fileURLToPath } from "node:url";
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
buildLaunchHeaderLines,
|
|
9
|
+
buildPromptLayout,
|
|
10
|
+
canonicalSlashPromptBuffer,
|
|
11
|
+
classifyEscapeAction,
|
|
12
|
+
formatWorkspaceChange,
|
|
13
|
+
stripMarkdown,
|
|
14
|
+
} from "../src/interactive-cli.js";
|
|
8
15
|
|
|
9
16
|
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
10
17
|
const tempRoot = await fs.mkdtemp(path.join(os.tmpdir(), "agintiflow-cli-chat-"));
|
|
@@ -179,6 +186,14 @@ try {
|
|
|
179
186
|
if (classifyEscapeAction({ active: true, pendingAsap: [] }) !== "abort") {
|
|
180
187
|
throw new Error("active Esc should abort when no ASAP pipe messages are pending");
|
|
181
188
|
}
|
|
189
|
+
if (
|
|
190
|
+
canonicalSlashPromptBuffer("/ve") !== "/venice" ||
|
|
191
|
+
canonicalSlashPromptBuffer("/v") !== "/venice" ||
|
|
192
|
+
canonicalSlashPromptBuffer("/not-a-command") !== "/not-a-command" ||
|
|
193
|
+
canonicalSlashPromptBuffer("/venice off") !== "/venice off"
|
|
194
|
+
) {
|
|
195
|
+
throw new Error("slash command prompt canonicalization did not preserve final submitted command correctly");
|
|
196
|
+
}
|
|
182
197
|
|
|
183
198
|
await runCli(["init"], "");
|
|
184
199
|
const instructions = await fs.readFile(path.join(tempRoot, "AGINTI.md"), "utf8");
|
|
@@ -265,6 +280,7 @@ try {
|
|
|
265
280
|
"auxiliary-command-spelling",
|
|
266
281
|
"skills-command",
|
|
267
282
|
"slash-prefix-autoselect",
|
|
283
|
+
"slash-prefix-canonical-history",
|
|
268
284
|
"instructions-chat-edit",
|
|
269
285
|
"interactive-chat",
|
|
270
286
|
"mock-file-write",
|
|
@@ -9,6 +9,7 @@ import {
|
|
|
9
9
|
modelsForProviderGroup,
|
|
10
10
|
selectModelRoute,
|
|
11
11
|
} from "../src/model-routing.js";
|
|
12
|
+
import { parseTextToolCalls } from "../src/model-client.js";
|
|
12
13
|
|
|
13
14
|
const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
|
|
14
15
|
|
|
@@ -109,6 +110,10 @@ assert(fastRoute.model === "deepseek-v4-flash", "fast route did not use route mo
|
|
|
109
110
|
assert(MODEL_PROVIDER_GROUPS["venice-gpt"].provider === "venice", "venice-gpt group missing");
|
|
110
111
|
assert(modelsForProviderGroup("venice-gemma").some((item) => item.id === "gemma-4-uncensored"), "venice-gemma bucket missing Gemma");
|
|
111
112
|
assert(AUXILIARY_MODEL_CATALOG["venice-image"].some((item) => item.id === "gpt-image-2"), "Venice image catalog missing GPT Image 2");
|
|
113
|
+
const parsedTextToolCalls = parseTextToolCalls('[TOOL_CALLS]list_files[ARGS]call_123[ARGS]{"path":".","maxDepth":1}');
|
|
114
|
+
assert(parsedTextToolCalls.length === 1, "Venice text tool-call parser did not detect encoded tool call");
|
|
115
|
+
assert(parsedTextToolCalls[0].function.name === "list_files", "Venice text tool-call parser returned wrong tool name");
|
|
116
|
+
assert(parsedTextToolCalls[0].function.arguments.includes('"maxDepth":1'), "Venice text tool-call parser returned wrong arguments");
|
|
112
117
|
|
|
113
118
|
const output = await runCli(["models"]);
|
|
114
119
|
assert(output.includes("/route") && output.includes("/spare") && output.includes("venice-gpt"), "aginti models output missing role details");
|
|
@@ -125,7 +130,15 @@ console.log(
|
|
|
125
130
|
JSON.stringify(
|
|
126
131
|
{
|
|
127
132
|
ok: true,
|
|
128
|
-
checks: [
|
|
133
|
+
checks: [
|
|
134
|
+
"role-defaults",
|
|
135
|
+
"route-overrides",
|
|
136
|
+
"provider-groups",
|
|
137
|
+
"auxiliary-catalog",
|
|
138
|
+
"venice-text-tool-parser",
|
|
139
|
+
"cli-models-command",
|
|
140
|
+
"venice-shortcut",
|
|
141
|
+
],
|
|
129
142
|
},
|
|
130
143
|
null,
|
|
131
144
|
2
|
package/src/interactive-cli.js
CHANGED
|
@@ -194,6 +194,15 @@ function resolveSlashCommand(command = "") {
|
|
|
194
194
|
return suggestion ? suggestion.slice(1) : raw;
|
|
195
195
|
}
|
|
196
196
|
|
|
197
|
+
export function canonicalSlashPromptBuffer(value = "") {
|
|
198
|
+
const text = String(value || "");
|
|
199
|
+
const trimmed = text.trim();
|
|
200
|
+
if (!trimmed.startsWith("/") || /\s/.test(trimmed)) return text;
|
|
201
|
+
const raw = trimmed.slice(1);
|
|
202
|
+
const resolved = resolveSlashCommand(raw);
|
|
203
|
+
return resolved === raw ? text : `/${resolved}`;
|
|
204
|
+
}
|
|
205
|
+
|
|
197
206
|
function clamp(value, min, max) {
|
|
198
207
|
return Math.min(Math.max(value, min), max);
|
|
199
208
|
}
|
|
@@ -944,6 +953,11 @@ function readTtyPrompt(options = {}) {
|
|
|
944
953
|
};
|
|
945
954
|
|
|
946
955
|
const submit = () => {
|
|
956
|
+
const canonical = canonicalSlashPromptBuffer(buffer);
|
|
957
|
+
if (canonical !== buffer) {
|
|
958
|
+
buffer = canonical;
|
|
959
|
+
cursor = buffer.length;
|
|
960
|
+
}
|
|
947
961
|
renderNow();
|
|
948
962
|
moveToPromptBottom(rendered);
|
|
949
963
|
cleanup();
|
|
@@ -2607,7 +2621,7 @@ export async function startInteractiveCli(args = {}, { packageDir, packageVersio
|
|
|
2607
2621
|
}
|
|
2608
2622
|
throw error;
|
|
2609
2623
|
}
|
|
2610
|
-
const line = answer.trim();
|
|
2624
|
+
const line = canonicalSlashPromptBuffer(answer).trim();
|
|
2611
2625
|
if (!line) continue;
|
|
2612
2626
|
if (line.startsWith("/")) {
|
|
2613
2627
|
const keepGoing = await handleCommand(line, state, packageDir);
|
|
@@ -2619,7 +2633,7 @@ export async function startInteractiveCli(args = {}, { packageDir, packageVersio
|
|
|
2619
2633
|
const pendingPrompts = [{ content: line }];
|
|
2620
2634
|
while (pendingPrompts.length > 0) {
|
|
2621
2635
|
const nextPrompt = pendingPrompts.shift();
|
|
2622
|
-
const content = String(nextPrompt.content || "").trim();
|
|
2636
|
+
const content = canonicalSlashPromptBuffer(String(nextPrompt.content || "")).trim();
|
|
2623
2637
|
if (!content) continue;
|
|
2624
2638
|
if (content.startsWith("/")) {
|
|
2625
2639
|
const keepGoing = await handleCommand(content, state, packageDir);
|
package/src/model-client.js
CHANGED
|
@@ -73,6 +73,59 @@ function toolChoiceForProvider(config, messages = []) {
|
|
|
73
73
|
return messages.some((message) => message.role === "tool") ? "auto" : "required";
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
+
export function parseTextToolCalls(content = "") {
|
|
77
|
+
const text = String(content || "");
|
|
78
|
+
if (!text.includes("[TOOL_CALLS]")) return [];
|
|
79
|
+
|
|
80
|
+
const calls = [];
|
|
81
|
+
const pattern = /\[TOOL_CALLS\]([A-Za-z0-9_-]+)\[ARGS\]([A-Za-z0-9_.:-]+)\[ARGS\]([\s\S]*?)(?=\[TOOL_CALLS\]|$)/g;
|
|
82
|
+
for (const match of text.matchAll(pattern)) {
|
|
83
|
+
const name = match[1]?.trim();
|
|
84
|
+
const id = match[2]?.trim() || `text-tool-${calls.length + 1}`;
|
|
85
|
+
const rawArgs = match[3]?.trim() || "{}";
|
|
86
|
+
if (!name) continue;
|
|
87
|
+
try {
|
|
88
|
+
JSON.parse(rawArgs);
|
|
89
|
+
} catch {
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
calls.push({
|
|
93
|
+
id,
|
|
94
|
+
type: "function",
|
|
95
|
+
function: {
|
|
96
|
+
name,
|
|
97
|
+
arguments: rawArgs,
|
|
98
|
+
},
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
return calls;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function normalizeTextToolCallResponse(response) {
|
|
105
|
+
const message = response?.choices?.[0]?.message;
|
|
106
|
+
if (!message || Array.isArray(message.tool_calls) && message.tool_calls.length > 0) return response;
|
|
107
|
+
|
|
108
|
+
const calls = parseTextToolCalls(message.content || "");
|
|
109
|
+
if (calls.length === 0) return response;
|
|
110
|
+
|
|
111
|
+
const content = String(message.content || "").split("[TOOL_CALLS]")[0].trim();
|
|
112
|
+
return {
|
|
113
|
+
...response,
|
|
114
|
+
choices: response.choices.map((choice, index) =>
|
|
115
|
+
index === 0
|
|
116
|
+
? {
|
|
117
|
+
...choice,
|
|
118
|
+
message: {
|
|
119
|
+
...message,
|
|
120
|
+
content,
|
|
121
|
+
tool_calls: calls,
|
|
122
|
+
},
|
|
123
|
+
}
|
|
124
|
+
: choice
|
|
125
|
+
),
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
|
|
76
129
|
function mockCommandForGoal(goal = "") {
|
|
77
130
|
const text = String(goal).toLowerCase();
|
|
78
131
|
if (/\blist\b|folder contents|directory contents|files?/.test(text)) return "ls -la";
|
|
@@ -866,7 +919,7 @@ export async function requestNextStep(client, config, messages) {
|
|
|
866
919
|
]);
|
|
867
920
|
}
|
|
868
921
|
|
|
869
|
-
|
|
922
|
+
const response = await client.chat.completions.create(
|
|
870
923
|
{
|
|
871
924
|
model: config.model,
|
|
872
925
|
temperature: 0,
|
|
@@ -877,4 +930,5 @@ export async function requestNextStep(client, config, messages) {
|
|
|
877
930
|
},
|
|
878
931
|
requestOptions(config)
|
|
879
932
|
);
|
|
933
|
+
return normalizeTextToolCallResponse(response);
|
|
880
934
|
}
|