@lazyingart/agintiflow 0.20.165 → 0.20.166

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lazyingart/agintiflow",
3
- "version": "0.20.165",
3
+ "version": "0.20.166",
4
4
  "type": "module",
5
5
  "description": "AgInTiFlow is a project-aware agent workspace for hybrid wet-dry R&D, hardware-aware intelligence, software automation, and industrial workflows.",
6
6
  "license": "Apache-2.0",
package/public/app.js CHANGED
@@ -50,6 +50,15 @@ const translations = {
50
50
  modelLabel: "Model",
51
51
  goalLabel: "Goal",
52
52
  goalPlaceholder: "Open a site and summarize it, or use run_command for simple terminal inspection.",
53
+ runDefaultsTitle: "Run defaults",
54
+ runDefaultsHelp: "The chat box is the first goal for a new run. These controls set how that run starts.",
55
+ scsModeLabel: "SCS",
56
+ scsOnOption: "On",
57
+ scsAutoOption: "Auto",
58
+ scsOffOption: "Off",
59
+ aapsModeLabel: "AAPS",
60
+ veniceModeLabel: "Venice",
61
+ quickModeStatus: "CLI sync",
53
62
  startUrlLabel: "Start URL",
54
63
  startUrlPlaceholder: "https://news.ycombinator.com",
55
64
  allowedDomainsLabel: "Allowed domains",
@@ -88,6 +97,10 @@ const translations = {
88
97
  webSearchLabel: "Enable web search",
89
98
  parallelScoutsLabel: "Parallel DeepSeek scouts",
90
99
  parallelScoutCountLabel: "Scout count",
100
+ dynamicStepsLabel: "Dynamic steps",
101
+ dynamicStepsAutoOption: "Auto",
102
+ dynamicStepsOnOption: "On",
103
+ dynamicStepsOffOption: "Off",
91
104
  wrapperToolLabel: "Enable agent wrappers",
92
105
  preferredWrapperLabel: "Preferred wrapper",
93
106
  dockerSandboxLabel: "Use Docker sandbox",
@@ -678,6 +691,10 @@ const languageField = document.querySelector("#language");
678
691
  const routingModeField = document.querySelector("#routingMode");
679
692
  const providerField = document.querySelector("#provider");
680
693
  const modelField = document.querySelector("#model");
694
+ const enableScsField = document.querySelector("#enableScs");
695
+ const aapsModeToggle = document.querySelector("#aapsModeToggle");
696
+ const veniceModeToggle = document.querySelector("#veniceModeToggle");
697
+ const quickModeStatusEl = document.querySelector("#quick-mode-status");
681
698
  const modelCatalogEl = document.querySelector("#model-catalog");
682
699
  const modelRoleGridEl = document.querySelector("#model-role-grid");
683
700
  const modelRoutePillEl = document.querySelector("#model-route-pill");
@@ -715,6 +732,7 @@ const allowWebSearchField = document.querySelector("#allowWebSearch");
715
732
  const allowMcpToolsField = document.querySelector("#allowMcpTools");
716
733
  const allowParallelScoutsField = document.querySelector("#allowParallelScouts");
717
734
  const parallelScoutCountField = document.querySelector("#parallelScoutCount");
735
+ const dynamicStepsField = document.querySelector("#dynamicSteps");
718
736
  const allowWrapperToolsField = document.querySelector("#allowWrapperTools");
719
737
  const preferredWrapperField = document.querySelector("#preferredWrapper");
720
738
  const wrapperStatusEl = document.querySelector("#wrapper-status");
@@ -962,8 +980,7 @@ function recommendedMaxStepsForProfile(profile = "auto", goal = "") {
962
980
 
963
981
  function ensureRecommendedMaxStepsForCurrentTask(goalOverride = "") {
964
982
  const maxStepsField = document.querySelector("#maxSteps");
965
- const goalField = document.querySelector("#goal");
966
- const recommended = recommendedMaxStepsForProfile(taskProfileField?.value || "auto", goalOverride || goalField?.value || "");
983
+ const recommended = recommendedMaxStepsForProfile(taskProfileField?.value || "auto", goalOverride || chatInputEl?.value || "");
967
984
  if (maxStepsField && Number(maxStepsField.value || 0) < recommended) {
968
985
  maxStepsField.value = String(recommended);
969
986
  }
@@ -1264,6 +1281,74 @@ function refreshModelDropdowns() {
1264
1281
  );
1265
1282
  }
1266
1283
 
1284
+ function selectedVeniceTextModel() {
1285
+ const options = providerModelOptions("venice");
1286
+ return (
1287
+ fieldValue(routeProviderField) === "venice" && fieldValue(routeModelField)
1288
+ ? fieldValue(routeModelField)
1289
+ : options.find((item) => item.id === "venice-uncensored-1-2")?.id || options[0]?.id || defaults.venice
1290
+ );
1291
+ }
1292
+
1293
+ function inferVeniceMode() {
1294
+ return [providerField?.value, routeProviderField?.value, mainProviderField?.value].includes("venice");
1295
+ }
1296
+
1297
+ function syncQuickModeControls() {
1298
+ if (aapsModeToggle) aapsModeToggle.checked = (taskProfileField?.value || "auto") === "aaps";
1299
+ if (veniceModeToggle) veniceModeToggle.checked = inferVeniceMode();
1300
+ if (quickModeStatusEl) {
1301
+ const scs = enableScsField?.value || "on";
1302
+ const profile = taskProfileField?.value || "auto";
1303
+ const route = `${routeProviderField?.value || "deepseek"}/${fieldValue(routeModelField) || "auto"}`;
1304
+ const main = `${mainProviderField?.value || "deepseek"}/${fieldValue(mainModelField) || "auto"}`;
1305
+ quickModeStatusEl.textContent = `scs=${scs} · profile=${profile} · route ${route} · main ${main}`;
1306
+ }
1307
+ }
1308
+
1309
+ function applyAapsMode(enabled) {
1310
+ if (!taskProfileField) return;
1311
+ taskProfileField.value = enabled ? "aaps" : taskProfileField.value === "aaps" ? "auto" : taskProfileField.value;
1312
+ ensureRecommendedMaxStepsForCurrentTask();
1313
+ syncQuickModeControls();
1314
+ }
1315
+
1316
+ function applyVeniceMode(enabled) {
1317
+ if (enabled) {
1318
+ const model = selectedVeniceTextModel();
1319
+ routingModeField.value = "smart";
1320
+ providerField.value = "deepseek";
1321
+ if (routeProviderField) routeProviderField.value = "venice";
1322
+ refreshModelDropdowns();
1323
+ if (routeModelField) setSelectOptions(routeModelField, providerModelOptions("venice"), model, defaults.venice);
1324
+ if (mainProviderField) mainProviderField.value = "venice";
1325
+ refreshModelDropdowns();
1326
+ if (mainModelField) setSelectOptions(mainModelField, providerModelOptions("venice"), model, defaults.venice);
1327
+ } else {
1328
+ routingModeField.value = "smart";
1329
+ providerField.value = "deepseek";
1330
+ if (routeProviderField?.value === "venice") routeProviderField.value = "deepseek";
1331
+ if (mainProviderField?.value === "venice") mainProviderField.value = "deepseek";
1332
+ refreshModelDropdowns();
1333
+ if (routeModelField && routeProviderField?.value === "deepseek") {
1334
+ setSelectOptions(routeModelField, providerModelOptions("deepseek"), "deepseek-v4-flash", "deepseek-v4-flash");
1335
+ }
1336
+ if (mainModelField && mainProviderField?.value === "deepseek") {
1337
+ setSelectOptions(mainModelField, providerModelOptions("deepseek"), "deepseek-v4-pro", "deepseek-v4-pro");
1338
+ }
1339
+ }
1340
+ updateRoutingHint();
1341
+ syncQuickModeControls();
1342
+ }
1343
+
1344
+ function applyScsMode(mode = enableScsField?.value || "on") {
1345
+ if (enableScsField) enableScsField.value = ["on", "auto", "off"].includes(mode) ? mode : "on";
1346
+ if (allowParallelScoutsField && enableScsField?.value === "on") {
1347
+ allowParallelScoutsField.checked = false;
1348
+ }
1349
+ syncQuickModeControls();
1350
+ }
1351
+
1267
1352
  function renderModelRoles() {
1268
1353
  if (!modelRoleGridEl) return;
1269
1354
  const roles = {
@@ -1373,6 +1458,7 @@ function updateRoutingHint() {
1373
1458
  fieldValue(modelField) || defaults[providerField.value] || ""
1374
1459
  }`;
1375
1460
  renderModelOptions();
1461
+ syncQuickModeControls();
1376
1462
  }
1377
1463
 
1378
1464
  function updatePackageWarning() {
@@ -1511,6 +1597,8 @@ function formPayload() {
1511
1597
  allowWebSearch: allowWebSearchField?.checked ?? true,
1512
1598
  allowMcpTools: allowMcpToolsField?.checked ?? true,
1513
1599
  allowParallelScouts: allowParallelScoutsField?.checked ?? true,
1600
+ enableScs: enableScsField?.value || "on",
1601
+ dynamicSteps: dynamicStepsField?.value || "auto",
1514
1602
  parallelScoutCount: Math.min(Math.max(Number(parallelScoutCountField?.value) || 3, 1), 10),
1515
1603
  allowWrapperTools: allowWrapperToolsField.checked,
1516
1604
  preferredWrapper: preferredWrapperField.value,
@@ -2971,6 +3059,7 @@ providerField.addEventListener("change", () => {
2971
3059
  modelField.value = defaults[providerField.value] || "";
2972
3060
  }
2973
3061
  updateRoutingHint();
3062
+ syncQuickModeControls();
2974
3063
  schedulePreferenceSave();
2975
3064
  });
2976
3065
 
@@ -2982,6 +3071,21 @@ modelCatalogEl?.addEventListener("click", (event) => {
2982
3071
  schedulePreferenceSave();
2983
3072
  });
2984
3073
 
3074
+ enableScsField?.addEventListener("change", () => {
3075
+ applyScsMode(enableScsField.value);
3076
+ schedulePreferenceSave();
3077
+ });
3078
+
3079
+ aapsModeToggle?.addEventListener("change", () => {
3080
+ applyAapsMode(aapsModeToggle.checked);
3081
+ schedulePreferenceSave();
3082
+ });
3083
+
3084
+ veniceModeToggle?.addEventListener("change", () => {
3085
+ applyVeniceMode(veniceModeToggle.checked);
3086
+ schedulePreferenceSave();
3087
+ });
3088
+
2985
3089
  modelField.addEventListener("change", updateRoutingHint);
2986
3090
  [routeProviderField, routeModelField, mainProviderField, mainModelField, spareProviderField, spareModelField, spareReasoningField, wrapperModelField, wrapperReasoningField, auxiliaryProviderField, auxiliaryModelField]
2987
3091
  .filter(Boolean)
@@ -2990,12 +3094,14 @@ modelField.addEventListener("change", updateRoutingHint);
2990
3094
  if (field === routeProviderField || field === mainProviderField || field === spareProviderField || field === auxiliaryProviderField) refreshModelDropdowns();
2991
3095
  renderModelRoles();
2992
3096
  renderModelOptions();
3097
+ syncQuickModeControls();
2993
3098
  schedulePreferenceSave();
2994
3099
  });
2995
3100
  field.addEventListener("change", () => {
2996
3101
  if (field === routeProviderField || field === mainProviderField || field === spareProviderField || field === auxiliaryProviderField) refreshModelDropdowns();
2997
3102
  renderModelRoles();
2998
3103
  renderModelOptions();
3104
+ syncQuickModeControls();
2999
3105
  schedulePreferenceSave();
3000
3106
  });
3001
3107
  });
@@ -3007,8 +3113,10 @@ permissionModeField?.addEventListener("change", () => {
3007
3113
  });
3008
3114
  allowWrapperToolsField.addEventListener("change", () => renderWrapperStatus());
3009
3115
  preferredWrapperField.addEventListener("change", () => renderWrapperStatus());
3116
+ dynamicStepsField?.addEventListener("change", schedulePreferenceSave);
3010
3117
  taskProfileField?.addEventListener("change", () => {
3011
3118
  ensureRecommendedMaxStepsForCurrentTask();
3119
+ syncQuickModeControls();
3012
3120
  schedulePreferenceSave();
3013
3121
  });
3014
3122
 
@@ -3118,9 +3226,7 @@ window.addEventListener("keydown", (event) => {
3118
3226
 
3119
3227
  form.addEventListener("submit", async (event) => {
3120
3228
  event.preventDefault();
3121
-
3122
- const goal = document.querySelector("#goal").value.trim();
3123
- await startRunFromGoal(goal);
3229
+ chatInputEl?.focus();
3124
3230
  });
3125
3231
 
3126
3232
  sessionSelectEl.addEventListener("change", async () => {
@@ -3249,6 +3355,8 @@ async function loadConfig() {
3249
3355
  if (allowWebSearchField) allowWebSearchField.checked = prefs.allowWebSearch ?? true;
3250
3356
  if (allowMcpToolsField) allowMcpToolsField.checked = prefs.allowMcpTools ?? true;
3251
3357
  if (allowParallelScoutsField) allowParallelScoutsField.checked = prefs.allowParallelScouts ?? true;
3358
+ if (enableScsField) enableScsField.value = prefs.enableScs || "on";
3359
+ if (dynamicStepsField) dynamicStepsField.value = prefs.dynamicSteps || "auto";
3252
3360
  if (parallelScoutCountField) parallelScoutCountField.value = String(prefs.parallelScoutCount || 3);
3253
3361
  allowWrapperToolsField.checked = prefs.allowWrapperTools ?? false;
3254
3362
  preferredWrapperField.value = prefs.preferredWrapper || "codex";
@@ -3267,6 +3375,7 @@ async function loadConfig() {
3267
3375
  updateRoutingHint();
3268
3376
  updatePermissionHint();
3269
3377
  updatePackageWarning();
3378
+ syncQuickModeControls();
3270
3379
 
3271
3380
  renderSessions(data.sessions || []);
3272
3381
  if (data.sessions && data.sessions.length > 0) {
package/public/index.html CHANGED
@@ -84,20 +84,12 @@
84
84
  </div>
85
85
  </section>
86
86
 
87
- <form id="run-form">
88
- <label>
89
- <span data-i18n="goalLabel">Goal</span>
90
- <textarea
91
- id="goal"
92
- name="goal"
93
- rows="5"
94
- data-i18n-placeholder="goalPlaceholder"
95
- placeholder="Open a site and summarize it, or use run_command for simple terminal inspection."
96
- ></textarea>
97
- </label>
98
-
99
- <div class="actions run-start-actions">
100
- <button type="submit" data-i18n="startRunButton">Start run</button>
87
+ <form id="run-form" class="run-defaults-form">
88
+ <div class="run-defaults-head">
89
+ <div>
90
+ <strong data-i18n="runDefaultsTitle">Run defaults</strong>
91
+ <p class="subtle" data-i18n="runDefaultsHelp">The chat box is the first goal for a new run. These controls set how that run starts.</p>
92
+ </div>
101
93
  <span id="key-status" class="subtle"></span>
102
94
  </div>
103
95
 
@@ -151,6 +143,14 @@
151
143
  <span data-i18n="maxStepsLabel">Max steps</span>
152
144
  <input id="maxSteps" name="maxSteps" type="number" min="1" max="50" value="24" />
153
145
  </label>
146
+ <label>
147
+ <span data-i18n="dynamicStepsLabel">Dynamic steps</span>
148
+ <select id="dynamicSteps" name="dynamicSteps">
149
+ <option value="auto" data-i18n="dynamicStepsAutoOption">Auto</option>
150
+ <option value="on" data-i18n="dynamicStepsOnOption">On</option>
151
+ <option value="off" data-i18n="dynamicStepsOffOption">Off</option>
152
+ </select>
153
+ </label>
154
154
  </div>
155
155
  <p id="package-warning" class="subtle package-warning"></p>
156
156
 
@@ -240,6 +240,27 @@
240
240
  <strong id="run-state-text" data-i18n="runStateIdle">Ready</strong>
241
241
  <span id="run-state-detail" class="subtle" data-i18n="runStateIdleDetail">Select a conversation or type a new goal below.</span>
242
242
  </div>
243
+ <div class="quick-mode-bar" aria-label="Run mode shortcuts">
244
+ <label class="quick-mode-select">
245
+ <span data-i18n="scsModeLabel">SCS</span>
246
+ <select id="enableScs" name="enableScs">
247
+ <option value="on" data-i18n="scsOnOption">On</option>
248
+ <option value="auto" data-i18n="scsAutoOption">Auto</option>
249
+ <option value="off" data-i18n="scsOffOption">Off</option>
250
+ </select>
251
+ </label>
252
+ <label class="switch-label compact-switch">
253
+ <input id="aapsModeToggle" name="aapsModeToggle" type="checkbox" />
254
+ <span class="switch" aria-hidden="true"></span>
255
+ <span data-i18n="aapsModeLabel">AAPS</span>
256
+ </label>
257
+ <label class="switch-label compact-switch">
258
+ <input id="veniceModeToggle" name="veniceModeToggle" type="checkbox" />
259
+ <span class="switch" aria-hidden="true"></span>
260
+ <span data-i18n="veniceModeLabel">Venice</span>
261
+ </label>
262
+ <span id="quick-mode-status" class="subtle quick-mode-status"></span>
263
+ </div>
243
264
  <form id="chat-form" class="chat-form">
244
265
  <textarea
245
266
  id="chat-input"
package/public/styles.css CHANGED
@@ -128,6 +128,32 @@ h1 {
128
128
  line-height: 1.45;
129
129
  }
130
130
 
131
+ .run-defaults-form {
132
+ display: grid;
133
+ gap: 14px;
134
+ }
135
+
136
+ .run-defaults-head {
137
+ display: grid;
138
+ gap: 8px;
139
+ padding: 12px;
140
+ border: 1px solid rgba(15, 118, 110, 0.16);
141
+ border-radius: 16px;
142
+ background: rgba(204, 251, 241, 0.28);
143
+ }
144
+
145
+ .run-defaults-head strong {
146
+ color: #0f766e;
147
+ text-transform: uppercase;
148
+ letter-spacing: 0.08em;
149
+ }
150
+
151
+ .run-defaults-head p {
152
+ margin: 4px 0 0;
153
+ font-size: 0.88rem;
154
+ line-height: 1.45;
155
+ }
156
+
131
157
  .model-catalog-panel {
132
158
  display: grid;
133
159
  gap: 10px;
@@ -527,6 +553,24 @@ textarea {
527
553
  min-height: 100%;
528
554
  }
529
555
 
556
+ .compact-switch {
557
+ min-height: 42px;
558
+ padding: 8px 10px;
559
+ }
560
+
561
+ .compact-switch .switch {
562
+ width: 50px;
563
+ min-width: 50px;
564
+ }
565
+
566
+ .compact-switch .switch::before {
567
+ width: 18px;
568
+ }
569
+
570
+ .compact-switch input[type="checkbox"]:checked + .switch::before {
571
+ transform: translateX(24px);
572
+ }
573
+
530
574
  .settings-button {
531
575
  width: 100%;
532
576
  justify-self: stretch;
@@ -598,17 +642,38 @@ button.danger {
598
642
  justify-content: space-between;
599
643
  }
600
644
 
601
- .run-start-actions {
645
+ .quick-mode-bar {
602
646
  display: grid;
603
- gap: 8px;
647
+ grid-template-columns: minmax(130px, 170px) repeat(2, minmax(110px, max-content)) minmax(0, 1fr);
648
+ gap: 10px;
649
+ align-items: center;
650
+ padding: 10px;
651
+ border: 1px solid rgba(15, 118, 110, 0.16);
652
+ border-radius: 18px;
653
+ background:
654
+ linear-gradient(135deg, rgba(236, 253, 245, 0.76), rgba(255, 253, 250, 0.9)),
655
+ #fffdfa;
604
656
  }
605
657
 
606
- .run-start-actions button {
607
- width: 100%;
658
+ .quick-mode-select {
659
+ display: grid;
660
+ gap: 5px;
608
661
  }
609
662
 
610
- .run-start-actions #key-status {
611
- min-height: 1.2em;
663
+ .quick-mode-select span {
664
+ color: var(--muted);
665
+ font-size: 0.72rem;
666
+ font-weight: 800;
667
+ letter-spacing: 0.08em;
668
+ text-transform: uppercase;
669
+ }
670
+
671
+ .quick-mode-status {
672
+ min-width: 0;
673
+ overflow: hidden;
674
+ font-size: 0.84rem;
675
+ text-overflow: ellipsis;
676
+ white-space: nowrap;
612
677
  }
613
678
 
614
679
  .run-header-actions {
@@ -1781,9 +1846,14 @@ button.danger {
1781
1846
 
1782
1847
  .settings-grid,
1783
1848
  .settings-checks,
1784
- .role-editor-grid {
1849
+ .role-editor-grid,
1850
+ .quick-mode-bar {
1785
1851
  grid-template-columns: 1fr;
1786
1852
  }
1853
+
1854
+ .quick-mode-status {
1855
+ white-space: normal;
1856
+ }
1787
1857
  }
1788
1858
 
1789
1859
  @media (max-width: 720px) {
@@ -96,9 +96,12 @@ try {
96
96
  if (chatThreadIndex < 0 || chatPendingIndex < 0 || chatPendingIndex < chatThreadIndex) {
97
97
  throw new Error("pending message panel must render below the chat thread");
98
98
  }
99
- for (const marker of ['id="new-session"', 'id="run-state"', 'id="toast-region"', 'id="chat-submit"']) {
99
+ for (const marker of ['id="new-session"', 'id="run-state"', 'id="toast-region"', 'id="chat-submit"', 'id="enableScs"', 'id="aapsModeToggle"', 'id="veniceModeToggle"', 'id="dynamicSteps"']) {
100
100
  if (!webAppHtml.includes(marker)) throw new Error(`web UI is missing ${marker}`);
101
101
  }
102
+ if (webAppHtml.includes('id="goal"') || /<button[^>]+type="submit"[^>]*>\s*Start run\s*<\/button>/i.test(webAppHtml)) {
103
+ throw new Error("web UI still exposes the old separate goal/start-run form");
104
+ }
102
105
 
103
106
  const config = await fetchJson("/api/config");
104
107
  if (!config.keyStatus?.mock) throw new Error("mock provider is not advertised by /api/config");
@@ -110,6 +113,8 @@ try {
110
113
  if (config.preferences?.packageInstallPolicy !== "allow") throw new Error("web did not default to Docker package installs");
111
114
  if (config.preferences?.permissionMode !== "normal") throw new Error("web did not default to normal permission mode");
112
115
  if (config.preferences?.workspaceWritePolicy !== "allow") throw new Error("web did not default to workspace writes allowed");
116
+ if (config.preferences?.enableScs !== "on") throw new Error("web did not default to CLI-aligned SCS on mode");
117
+ if (config.preferences?.dynamicSteps !== "auto") throw new Error("web did not default to CLI-aligned dynamic steps auto mode");
113
118
  if (Number(config.preferences?.maxSteps) < 24) throw new Error("web default max steps is too low");
114
119
  if (!Array.isArray(config.taskProfiles) || !config.taskProfiles.some((profile) => profile.id === "latex")) {
115
120
  throw new Error("task profiles are not advertised by /api/config");
@@ -208,6 +213,8 @@ try {
208
213
  auxiliaryProvider: "grsai",
209
214
  auxiliaryModel: "nano-banana-2",
210
215
  goal: "Report the current working directory with a safe command.",
216
+ enableScs: "off",
217
+ dynamicSteps: "off",
211
218
  commandCwd: runtimeDir,
212
219
  sandboxMode: "host",
213
220
  packageInstallPolicy: "block",
@@ -87,13 +87,39 @@ try {
87
87
  const initialSubmit = await page.locator("#chat-submit").innerText();
88
88
  if (!/start new run/i.test(initialSubmit)) throw new Error(`composer did not default to new-run mode: ${initialSubmit}`);
89
89
  if (await page.locator("#stop-run").isVisible()) throw new Error("stop button is visible before a run starts");
90
+ if ((await page.locator("#goal").count()) !== 0) throw new Error("old standalone goal textarea is still rendered");
91
+
92
+ await page.selectOption("#enableScs", "auto");
93
+ await page.locator("label:has(#aapsModeToggle)").click();
94
+ if ((await page.locator("#taskProfile").inputValue()) !== "aaps") throw new Error("AAPS toggle did not select the AAPS task profile");
95
+ await page.locator("label:has(#veniceModeToggle)").click();
96
+ if ((await page.locator("#routeProvider").inputValue()) !== "venice") throw new Error("Venice toggle did not set route provider");
97
+ if ((await page.locator("#mainProvider").inputValue()) !== "venice") throw new Error("Venice toggle did not set main provider");
98
+ const quickStatus = await page.locator("#quick-mode-status").innerText();
99
+ if (!/scs=auto/.test(quickStatus) || !/profile=aaps/.test(quickStatus) || !/route venice\//.test(quickStatus)) {
100
+ throw new Error(`quick mode status did not reflect CLI modes: ${quickStatus}`);
101
+ }
90
102
 
91
103
  await page.selectOption("#routingMode", "manual");
92
104
  await page.selectOption("#provider", "mock");
93
105
  await page.selectOption("#model", "mock-agent");
94
106
  await page.fill("#maxSteps", "4");
107
+ await page.selectOption("#dynamicSteps", "off");
95
108
  await page.fill("#chat-input", "Say hello from the web UI composer in one concise sentence.");
96
109
  await page.click("#chat-submit");
110
+ const firstPayload = JSON.parse(runPayloads.at(-1) || "{}");
111
+ if (firstPayload.goal !== "Say hello from the web UI composer in one concise sentence.") {
112
+ throw new Error("composer text was not used as the first run goal");
113
+ }
114
+ if (firstPayload.enableScs !== "auto" || firstPayload.taskProfile !== "aaps") {
115
+ throw new Error(`CLI mode payload mismatch: ${runPayloads.at(-1) || ""}`);
116
+ }
117
+ if (firstPayload.dynamicSteps !== "off") {
118
+ throw new Error(`dynamic steps payload mismatch: ${runPayloads.at(-1) || ""}`);
119
+ }
120
+ if (firstPayload.routeProvider !== "venice" || firstPayload.mainProvider !== "venice") {
121
+ throw new Error(`Venice route/main payload mismatch: ${runPayloads.at(-1) || ""}`);
122
+ }
97
123
  await waitForRunState(page, "running");
98
124
  if (!(await page.locator("#stop-run").isVisible())) throw new Error("stop button did not appear while run was active");
99
125
  await page.click("#stop-run");
@@ -127,6 +153,10 @@ try {
127
153
  runtimeDir,
128
154
  checks: [
129
155
  "composer-starts-new-run",
156
+ "old-goal-form-hidden",
157
+ "quick-scs-aaps-venice-controls",
158
+ "dynamic-steps-dropdown",
159
+ "composer-goal-payload",
130
160
  "running-stop-button-visible",
131
161
  "running-status-toast",
132
162
  "terminal-stop-button-hidden",
package/src/web-db.js CHANGED
@@ -7,7 +7,7 @@ import { deleteSessionIndex, renameSessionIndex, upsertSessionIndex } from "./se
7
7
  import { loadDatabaseSync } from "./sqlite.js";
8
8
  import { permissionModeDefaults } from "./permission-modes.js";
9
9
 
10
- const PREFERENCES_SCHEMA_VERSION = 8;
10
+ const PREFERENCES_SCHEMA_VERSION = 9;
11
11
 
12
12
  function jsonStatePath(dbPath) {
13
13
  return dbPath.replace(/\.sqlite$/i, ".json");
@@ -71,6 +71,8 @@ function defaultPreferences(baseDir) {
71
71
  allowAuxiliaryTools: true,
72
72
  allowWebSearch: true,
73
73
  allowParallelScouts: true,
74
+ enableScs: process.env.AGINTI_SCS_MODE || "on",
75
+ dynamicSteps: process.env.AGINTI_DYNAMIC_STEPS || "auto",
74
76
  parallelScoutCount: 3,
75
77
  allowWrapperTools: false,
76
78
  preferredWrapper: "codex",
@@ -222,6 +224,10 @@ export class WebDatabase {
222
224
  preferences.allowDestructive = permissions.allowDestructive;
223
225
  preferences.allowOutsideWorkspaceFileTools = permissions.allowOutsideWorkspaceFileTools;
224
226
  }
227
+ if ((parsed.preferencesSchemaVersion || 1) < 9) {
228
+ preferences.enableScs = preferences.enableScs || process.env.AGINTI_SCS_MODE || "on";
229
+ preferences.dynamicSteps = preferences.dynamicSteps || process.env.AGINTI_DYNAMIC_STEPS || "auto";
230
+ }
225
231
  this.savePreferences(preferences);
226
232
  }
227
233
  return preferences;
package/web.js CHANGED
@@ -26,6 +26,8 @@ import {
26
26
  normalizePermissionMode,
27
27
  permissionModeForApprovalCategory,
28
28
  } from "./src/permission-modes.js";
29
+ import { normalizeScsMode } from "./src/scs-controller.js";
30
+ import { normalizeDynamicStepsMode } from "./src/step-budget-controller.js";
29
31
  import {
30
32
  ensureProjectSessionStorage,
31
33
  listProjectSessions,
@@ -277,9 +279,11 @@ function normalizePreferencePayload(body = {}, current = db.getPreferences()) {
277
279
  typeof body.allowMcpTools === "boolean" ? body.allowMcpTools : current.allowMcpTools !== false,
278
280
  allowParallelScouts:
279
281
  typeof body.allowParallelScouts === "boolean" ? body.allowParallelScouts : current.allowParallelScouts !== false,
282
+ enableScs: normalizeScsMode(body.enableScs || current.enableScs || process.env.AGINTI_SCS_MODE || "on"),
283
+ dynamicSteps: normalizeDynamicStepsMode(body.dynamicSteps || current.dynamicSteps || process.env.AGINTI_DYNAMIC_STEPS || "auto"),
280
284
  parallelScoutCount:
281
285
  Number.isFinite(parsedParallelScoutCount) && parsedParallelScoutCount > 0
282
- ? Math.min(Math.max(parsedParallelScoutCount, 1), 4)
286
+ ? Math.min(Math.max(parsedParallelScoutCount, 1), 10)
283
287
  : Number(current.parallelScoutCount) || 3,
284
288
  allowWrapperTools:
285
289
  typeof body.allowWrapperTools === "boolean" ? body.allowWrapperTools : Boolean(current.allowWrapperTools),
@@ -396,6 +400,8 @@ function buildRunConfig(body, overrides = {}) {
396
400
  allowWebSearch: merged.allowWebSearch,
397
401
  allowMcpTools: merged.allowMcpTools,
398
402
  allowParallelScouts: merged.allowParallelScouts,
403
+ enableScs: merged.enableScs,
404
+ dynamicSteps: merged.dynamicSteps,
399
405
  parallelScoutCount: merged.parallelScoutCount,
400
406
  allowWrapperTools: merged.allowWrapperTools,
401
407
  preferredWrapper: merged.preferredWrapper,