openfox 2.0.117 → 2.0.119

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.
Files changed (63) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/dist/CHANGELOG.md +42 -0
  3. package/dist/agent-defaults/code-reviewer.agent.md +8 -3
  4. package/dist/{auto-config-AAUO4PKW.js → auto-config-YXNCBYEY.js} +125 -11
  5. package/dist/{chat-handler-URSNELCE.js → chat-handler-M54IWF5Y.js} +15 -14
  6. package/dist/{chunk-HZSKKJHQ.js → chunk-5FAPM2GM.js} +28 -9
  7. package/dist/{chunk-I6MY65LO.js → chunk-6DDB67FN.js} +17 -12
  8. package/dist/{chunk-ZS6MW2WM.js → chunk-AIFZNTUJ.js} +4 -4
  9. package/dist/{chunk-7SDJXHJH.js → chunk-AVQCOSOF.js} +34 -131
  10. package/dist/chunk-EW25UQG3.js +7 -0
  11. package/dist/{chunk-MKWS7TQH.js → chunk-J6KFWVZ3.js} +21 -15
  12. package/dist/{chunk-TGVDUK4N.js → chunk-JOCR4CF4.js} +1 -1
  13. package/dist/chunk-K2QKX4ZJ.js +31 -0
  14. package/dist/{chunk-ZKLE2Q3I.js → chunk-KSDWQ6IZ.js} +1 -1
  15. package/dist/{chunk-TOKQ2UVG.js → chunk-MIPQOHWS.js} +20 -6
  16. package/dist/{chunk-EQ7DK2TG.js → chunk-SE62ZBNX.js} +82 -8
  17. package/dist/{chunk-GZTMCTUS.js → chunk-U6JMRMBW.js} +17 -21
  18. package/dist/{chunk-3PEYTWCS.js → chunk-UNNCD7A3.js} +3 -3
  19. package/dist/{chunk-2PQA3DHY.js → chunk-V5XWUVF5.js} +175 -112
  20. package/dist/{chunk-6XHDNSA3.js → chunk-VFS7TFA7.js} +8 -5
  21. package/dist/{chunk-4GHLULHB.js → chunk-XAAEP5XM.js} +8 -16
  22. package/dist/{chunk-EZD7WFBZ.js → chunk-XB7IXMUI.js} +73 -13
  23. package/dist/{chunk-ECCSVMRT.js → chunk-XZ2WAI66.js} +72 -41
  24. package/dist/{chunk-QQVPUZQB.js → chunk-XZGQZ42D.js} +3 -3
  25. package/dist/{chunk-X3XKYGUN.js → chunk-YHAE2SJI.js} +3 -3
  26. package/dist/cli/dev.js +1 -1
  27. package/dist/cli/index.js +1 -1
  28. package/dist/{client-KCNTDTIR.js → client-R4PI64IL.js} +3 -3
  29. package/dist/{client-pure-B5DHEKQJ.js → client-pure-QSY7TJGK.js} +2 -2
  30. package/dist/{compactor-LAXZLPPA.js → compactor-F6XMYVHL.js} +5 -5
  31. package/dist/{dynamic-context-NNBVVFBT.js → dynamic-context-NXQ2TFAZ.js} +2 -2
  32. package/dist/{events-IVPAMMR5.js → events-KDFMBVP5.js} +2 -2
  33. package/dist/{launch-HSSFGQ5A.js → launch-I5XBYRSJ.js} +15 -14
  34. package/dist/{orchestrator-FVXUJW3K.js → orchestrator-MNON5G7R.js} +14 -13
  35. package/dist/package.json +1 -1
  36. package/dist/{path-security-JTCHWYG3.js → path-security-L4AJJN2V.js} +5 -5
  37. package/dist/{processor-JRVW5QBA.js → processor-OZSK7RUD.js} +25 -13
  38. package/dist/{protocol-CfUkCYxF.d.ts → protocol-D5kJLGWy.d.ts} +16 -9
  39. package/dist/{protocol-HYA5BYVN.js → protocol-TLODRZSB.js} +7 -7
  40. package/dist/provider/index.d.ts +4 -4
  41. package/dist/{provider-Q7J4UFTS.js → provider-7YF42S7C.js} +5 -4
  42. package/dist/{provider-manager-TMBO4DFG.js → provider-manager-FJIPQJMX.js} +5 -4
  43. package/dist/{serve-CW6PR3M2.js → serve-V34QG72C.js} +20 -19
  44. package/dist/server/index.d.ts +5 -3
  45. package/dist/server/index.js +19 -18
  46. package/dist/{server-V46SOIGP.js → server-XZQLWIVD.js} +18 -17
  47. package/dist/{service-M7XJHAK4.js → service-ZKH465DA.js} +6 -5
  48. package/dist/session-status-6Q5B5PEN.js +35 -0
  49. package/dist/shared/index.d.ts +3 -3
  50. package/dist/shared/index.js +1 -1
  51. package/dist/{tasks-X5H5HM4J.js → tasks-I766NBPW.js} +8 -6
  52. package/dist/{tools-2Q3GRECI.js → tools-ZJXDZLRH.js} +12 -11
  53. package/dist/{types-CIVhQMvD.d.ts → types-B5CI_Ql3.d.ts} +3 -1
  54. package/dist/{types-Df7NM9b5.d.ts → types-CZlj7ufS.d.ts} +2 -0
  55. package/dist/{update-YP7IRT6M.js → update-C3YVPKCR.js} +2 -2
  56. package/dist/web/assets/index-BlYcAqzD.js +324 -0
  57. package/dist/web/assets/{index-DTiVSJJu.css → index-D9sfxcRH.css} +1 -1
  58. package/dist/web/index.html +2 -2
  59. package/dist/web/sw.js +1 -1
  60. package/dist/workflow-defaults/default.workflow.json +1 -1
  61. package/package.json +1 -1
  62. package/dist/chunk-NPTI5RCQ.js +0 -7
  63. package/dist/web/assets/index-C58KXxRi.js +0 -324
package/CHANGELOG.md CHANGED
@@ -1,5 +1,47 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.0.119 - 2026-08-14
4
+
5
+ ### Features
6
+
7
+ - **Per-model sampling controls** — pick which sampling parameters each backend receives, per model
8
+ - **Read-only session status** — lightweight API and widget expose live state for external integrations
9
+
10
+ ### Enhancements
11
+
12
+ - **Reviewer gets the full picture** — code reviews now factor in intended scope, verifier notes, and changed files
13
+ - **No surprise navigation on In Progress** — moving a task keeps your place; open it via the card link
14
+ - **Task editor shortcuts inverted** — Enter inserts a newline, Shift+Enter saves
15
+
16
+ ### Bug Fixes
17
+
18
+ - **New-task autocomplete fixed** — slash/@ suggestions are no longer clipped and load on cold start
19
+ - **Long chats safer against rejection** — max_tokens now keeps 2048 tokens of headroom
20
+ - **Split panes keep dev state separate** — server status, logs, and config no longer bleed between workdirs
21
+ - **ask_user prompts render as markdown** — no more raw text walls
22
+ - **Submodule changes appear in the diff preview**
23
+ - **Auto-config spots rejected reasoning** — providers that refuse it no longer receive reasoning history
24
+ - **LM Studio context windows set by auto-config** — no longer left at zero
25
+ - **No phantom password prompt** — the login modal no longer flashes while connecting
26
+ - **Silent streams end their turn** — idle LLM connections time out cleanly instead of hanging
27
+ - **Null token usage no longer crashes sessions**
28
+
29
+ ## 2.0.118 - 2026-08-12
30
+
31
+ ### Features
32
+
33
+ - **LLM failures retry automatically** — chat, workflow steps, and sub-agents back off and retry, with a live countdown and "Retry now" to skip the wait
34
+ - **Searchable new-session modal in split view** — live case-insensitive project search with autofocus, arrow-key navigation, Enter to select, Esc to dismiss
35
+
36
+ ### Enhancements
37
+
38
+ - **LLM retries recover smoothly** — partial replies continue where they left off, provider switches apply on the next attempt, and failed calls leave no ghost messages
39
+
40
+ ### Bug Fixes
41
+
42
+ - **Paused workflow steps no longer vanish** — the choose-workspace pause survives late session refreshes
43
+ - **Composer no longer jumps while typing** — the input stays put on every keystroke
44
+
3
45
  ## 2.0.117 - 2026-08-12
4
46
 
5
47
  ### Features
package/dist/CHANGELOG.md CHANGED
@@ -1,5 +1,47 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.0.119 - 2026-08-14
4
+
5
+ ### Features
6
+
7
+ - **Per-model sampling controls** — pick which sampling parameters each backend receives, per model
8
+ - **Read-only session status** — lightweight API and widget expose live state for external integrations
9
+
10
+ ### Enhancements
11
+
12
+ - **Reviewer gets the full picture** — code reviews now factor in intended scope, verifier notes, and changed files
13
+ - **No surprise navigation on In Progress** — moving a task keeps your place; open it via the card link
14
+ - **Task editor shortcuts inverted** — Enter inserts a newline, Shift+Enter saves
15
+
16
+ ### Bug Fixes
17
+
18
+ - **New-task autocomplete fixed** — slash/@ suggestions are no longer clipped and load on cold start
19
+ - **Long chats safer against rejection** — max_tokens now keeps 2048 tokens of headroom
20
+ - **Split panes keep dev state separate** — server status, logs, and config no longer bleed between workdirs
21
+ - **ask_user prompts render as markdown** — no more raw text walls
22
+ - **Submodule changes appear in the diff preview**
23
+ - **Auto-config spots rejected reasoning** — providers that refuse it no longer receive reasoning history
24
+ - **LM Studio context windows set by auto-config** — no longer left at zero
25
+ - **No phantom password prompt** — the login modal no longer flashes while connecting
26
+ - **Silent streams end their turn** — idle LLM connections time out cleanly instead of hanging
27
+ - **Null token usage no longer crashes sessions**
28
+
29
+ ## 2.0.118 - 2026-08-12
30
+
31
+ ### Features
32
+
33
+ - **LLM failures retry automatically** — chat, workflow steps, and sub-agents back off and retry, with a live countdown and "Retry now" to skip the wait
34
+ - **Searchable new-session modal in split view** — live case-insensitive project search with autofocus, arrow-key navigation, Enter to select, Esc to dismiss
35
+
36
+ ### Enhancements
37
+
38
+ - **LLM retries recover smoothly** — partial replies continue where they left off, provider switches apply on the next attempt, and failed calls leave no ghost messages
39
+
40
+ ### Bug Fixes
41
+
42
+ - **Paused workflow steps no longer vanish** — the choose-workspace pause survives late session refreshes
43
+ - **Composer no longer jumps while typing** — the input stays put on every keystroke
44
+
3
45
  ## 2.0.117 - 2026-08-12
4
46
 
5
47
  ### Features
@@ -11,14 +11,19 @@ allowedTools:
11
11
  - session_metadata
12
12
  ---
13
13
 
14
- You are a code reviewer. Review the **git diff** of the modified files rather than reading the full files.
14
+ You are a code reviewer. Your caller may provide situational context before the diff — **intended scope (criteria)**, **what the verifier already confirmed**, and the **modified files**. Review the **git diff** of the modified files rather than reading the full files.
15
+
16
+ When context is provided, use it to judge the change against what was actually requested:
17
+
18
+ - Read the intended scope (criteria) and check the diff delivers it faithfully — flag mismatches, partial implementations, or scope creep.
19
+ - Treat the verifier's notes as already-confirmed ground truth. Don't re-verify what it covered; instead catch what it missed.
20
+ - You're not looking for 100% perfection. Just something that feels good to use and doesn't bloat the software.
21
+
15
22
  You're mostly interested in:
16
23
 
17
24
  1. **For the user (UX interaction)** — does this feel good to use? Any rough edges, confusing behavior, or unnecessary friction?
18
25
  2. **For the project (code quality + guidelines)** — does this follow project conventions? Is it maintainable? Does it bloat the software?
19
26
 
20
- You're not looking for 100% perfection. Just something that feels good to use and doesn't bloat the software.
21
-
22
27
  ## Managing Findings
23
28
 
24
29
  Use `session_metadata` to track your findings:
@@ -1,3 +1,6 @@
1
+ import {
2
+ findLmStudioModel
3
+ } from "./chunk-K2QKX4ZJ.js";
1
4
  import {
2
5
  ensureVersionPrefix
3
6
  } from "./chunk-HNCM3D7Y.js";
@@ -98,14 +101,10 @@ async function detectLmstudioInfo(baseUrl, modelId) {
98
101
  const nativeUrl = `${base.replace(/\/v\d+\/?$/, "")}/api/v1/models`;
99
102
  const response = await fetch(nativeUrl, { signal: AbortSignal.timeout(5e3) });
100
103
  if (!response.ok) throw new Error(`HTTP ${response.status}`);
101
- const data = await response.json();
102
- const model = data.find((m) => (m.key ?? m.id) === modelId);
104
+ const model = findLmStudioModel(await response.json(), modelId);
103
105
  if (!model) throw new Error(`Model ${modelId} not found in LM Studio`);
104
- const loadedContext = model.loaded_instances?.[0]?.config?.context_length;
105
- const ctxLen = loadedContext ?? model.max_context_length;
106
- const supportsVision = model.capabilities?.vision ?? false;
107
- if (ctxLen) {
108
- return { contextWindow: ctxLen, source: "backend", supportsVision };
106
+ if (model.contextWindow) {
107
+ return { contextWindow: model.contextWindow, source: "backend", supportsVision: model.supportsVision };
109
108
  }
110
109
  throw new Error("No context_length in LM Studio response");
111
110
  }
@@ -157,6 +156,117 @@ async function probeCombos(baseUrl, apiKey, model, combos) {
157
156
  logger.debug("Auto-config: no working combo found", { model });
158
157
  return null;
159
158
  }
159
+ async function probeReasoningInMessages(baseUrl, apiKey, model) {
160
+ const headers = { "Content-Type": "application/json" };
161
+ if (apiKey) headers["Authorization"] = `Bearer ${apiKey}`;
162
+ try {
163
+ const response = await fetch(`${ensureVersionPrefix(baseUrl)}/chat/completions`, {
164
+ method: "POST",
165
+ headers,
166
+ body: JSON.stringify({
167
+ model,
168
+ messages: [
169
+ { role: "user", content: "say hi in one word" },
170
+ { role: "assistant", content: "hi", reasoning: "probe" },
171
+ { role: "user", content: "say hi in one word" }
172
+ ],
173
+ max_tokens: 1
174
+ }),
175
+ signal: AbortSignal.timeout(15e3)
176
+ });
177
+ return response.ok;
178
+ } catch {
179
+ return void 0;
180
+ }
181
+ }
182
+ var STANDARD_PARAMS = ["temperature", "top_p", "max_tokens", "top_k", "reasoning_effort"];
183
+ var PARAM_VALUES = {
184
+ temperature: 0.7,
185
+ top_p: 0.9,
186
+ max_tokens: 50,
187
+ top_k: 40,
188
+ reasoning_effort: "high"
189
+ };
190
+ var escapeRegExp = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
191
+ var REJECTED_PARAM_PATTERNS = STANDARD_PARAMS.map((param) => ({
192
+ param,
193
+ pattern: new RegExp(`\\b${escapeRegExp(param)}\\b`, "i")
194
+ }));
195
+ function extractRejectedParam(errorText) {
196
+ for (const { param, pattern } of REJECTED_PARAM_PATTERNS) {
197
+ if (pattern.test(errorText)) return param;
198
+ }
199
+ return void 0;
200
+ }
201
+ var DUMMY_TOOL = {
202
+ type: "function",
203
+ function: {
204
+ name: "noop",
205
+ description: "No-op tool for probing",
206
+ parameters: { type: "object", properties: {}, required: [] }
207
+ }
208
+ };
209
+ async function probeChatCompletions(baseUrl, headers, model, samplingParams) {
210
+ const body = {
211
+ model,
212
+ messages: [{ role: "user", content: "say hi in one word" }],
213
+ tools: [DUMMY_TOOL],
214
+ tool_choice: "auto"
215
+ };
216
+ for (const param of samplingParams) {
217
+ body[param] = PARAM_VALUES[param];
218
+ }
219
+ try {
220
+ const response = await fetch(`${ensureVersionPrefix(baseUrl)}/chat/completions`, {
221
+ method: "POST",
222
+ headers,
223
+ body: JSON.stringify(body),
224
+ signal: AbortSignal.timeout(15e3)
225
+ });
226
+ if (response.ok) return { ok: true, status: response.status, errorText: "" };
227
+ return { ok: false, status: response.status, errorText: await response.text() };
228
+ } catch {
229
+ return { ok: false, status: 0, errorText: "" };
230
+ }
231
+ }
232
+ async function probeRejectedParams(baseUrl, apiKey, model, backend) {
233
+ const headers = { "Content-Type": "application/json" };
234
+ if (apiKey) headers["Authorization"] = `Bearer ${apiKey}`;
235
+ const candidates = [...STANDARD_PARAMS];
236
+ if (["openai", "anthropic", "ollama"].includes(backend)) {
237
+ const idx = candidates.indexOf("top_k");
238
+ if (idx !== -1) candidates.splice(idx, 1);
239
+ }
240
+ const control = await probeChatCompletions(baseUrl, headers, model, []);
241
+ if (!control.ok) {
242
+ logger.debug("Auto-config: rejection-probe control failed, skipping param detection", {
243
+ model,
244
+ status: control.status
245
+ });
246
+ return [];
247
+ }
248
+ const rejected = [];
249
+ const remaining = [...candidates];
250
+ while (remaining.length > 0) {
251
+ const probe = await probeChatCompletions(baseUrl, headers, model, remaining);
252
+ if (probe.ok) break;
253
+ if (probe.status === 400) {
254
+ const rejectedParam = extractRejectedParam(probe.errorText);
255
+ if (rejectedParam && remaining.includes(rejectedParam)) {
256
+ rejected.push(rejectedParam);
257
+ remaining.splice(remaining.indexOf(rejectedParam), 1);
258
+ logger.debug("Auto-config: param rejected, retrying without", { model, rejectedParam });
259
+ continue;
260
+ }
261
+ break;
262
+ }
263
+ break;
264
+ }
265
+ if (rejected.length > 0) {
266
+ logger.info("Auto-config: detected rejected params", { model, rejected });
267
+ }
268
+ return rejected;
269
+ }
160
270
  async function autoConfig(input) {
161
271
  const { url, apiKey, backend, models } = input;
162
272
  const baseUrl = url.replace(/\/+$/, "");
@@ -168,17 +278,21 @@ async function autoConfig(input) {
168
278
  source: contextSource,
169
279
  supportsVision
170
280
  } = await detectModelInfo(baseUrl, apiKey, backend, model.id);
171
- const [thinkingConfig, nonThinkingConfig] = await Promise.all([
281
+ const [thinkingConfig, nonThinkingConfig, rejectedParams] = await Promise.all([
172
282
  probeCombos(baseUrl, apiKey, model.id, THINKING_COMBOS),
173
- probeCombos(baseUrl, apiKey, model.id, NON_THINKING_COMBOS)
283
+ probeCombos(baseUrl, apiKey, model.id, NON_THINKING_COMBOS),
284
+ probeRejectedParams(baseUrl, apiKey, model.id, backend)
174
285
  ]);
286
+ const sendReasoningInMessages = thinkingConfig ? await probeReasoningInMessages(baseUrl, apiKey, model.id) : void 0;
175
287
  results.push({
176
288
  id: model.id,
177
289
  contextWindow,
178
290
  contextSource,
179
291
  supportsVision,
180
292
  thinkingConfig,
181
- nonThinkingConfig
293
+ nonThinkingConfig,
294
+ ...sendReasoningInMessages !== void 0 ? { sendReasoningInMessages } : {},
295
+ ...rejectedParams.length > 0 ? { rejectedParams } : {}
182
296
  });
183
297
  }
184
298
  return { models: results };
@@ -186,4 +300,4 @@ async function autoConfig(input) {
186
300
  export {
187
301
  autoConfig
188
302
  };
189
- //# sourceMappingURL=auto-config-AAUO4PKW.js.map
303
+ //# sourceMappingURL=auto-config-YXNCBYEY.js.map
@@ -2,14 +2,14 @@ import {
2
2
  buildRunChatTurnParams,
3
3
  finalizeTurnCompletion,
4
4
  generateSessionNameForSession
5
- } from "./chunk-6XHDNSA3.js";
5
+ } from "./chunk-VFS7TFA7.js";
6
6
  import {
7
7
  runChatTurn
8
- } from "./chunk-I6MY65LO.js";
9
- import "./chunk-2PQA3DHY.js";
10
- import "./chunk-3PEYTWCS.js";
8
+ } from "./chunk-6DDB67FN.js";
9
+ import "./chunk-V5XWUVF5.js";
10
+ import "./chunk-UNNCD7A3.js";
11
11
  import "./chunk-2FCLCUVR.js";
12
- import "./chunk-EQ7DK2TG.js";
12
+ import "./chunk-SE62ZBNX.js";
13
13
  import "./chunk-27NABDXB.js";
14
14
  import "./chunk-M6X6AIEG.js";
15
15
  import "./chunk-ZTOG6LJD.js";
@@ -18,18 +18,18 @@ import "./chunk-JE7LW7Y6.js";
18
18
  import "./chunk-OAN4BXEW.js";
19
19
  import "./chunk-O6DU226D.js";
20
20
  import "./chunk-J7GAZGZT.js";
21
- import "./chunk-HZSKKJHQ.js";
21
+ import "./chunk-5FAPM2GM.js";
22
22
  import "./chunk-EQ5CGNOT.js";
23
- import "./chunk-QQVPUZQB.js";
23
+ import "./chunk-XZGQZ42D.js";
24
24
  import {
25
25
  getEventStore
26
- } from "./chunk-TGVDUK4N.js";
26
+ } from "./chunk-JOCR4CF4.js";
27
27
  import "./chunk-KLQEL2DZ.js";
28
28
  import {
29
29
  createChatMessageMessage,
30
30
  createPhaseChangedMessage,
31
31
  createSessionRunningMessage
32
- } from "./chunk-4GHLULHB.js";
32
+ } from "./chunk-XAAEP5XM.js";
33
33
  import "./chunk-AESOGRFK.js";
34
34
  import "./chunk-JURM3RPZ.js";
35
35
  import "./chunk-JLAR2CMV.js";
@@ -38,18 +38,19 @@ import "./chunk-LCLH6ZUL.js";
38
38
  import "./chunk-LNNBLB6G.js";
39
39
  import "./chunk-OSXPQSLW.js";
40
40
  import "./chunk-3PG65AXG.js";
41
- import "./chunk-GZTMCTUS.js";
41
+ import "./chunk-U6JMRMBW.js";
42
+ import "./chunk-K2QKX4ZJ.js";
42
43
  import "./chunk-J2GP3J3X.js";
43
- import "./chunk-MKWS7TQH.js";
44
+ import "./chunk-J6KFWVZ3.js";
44
45
  import "./chunk-W7VIYHPQ.js";
45
46
  import "./chunk-AZHWLLPP.js";
46
47
  import "./chunk-HNCM3D7Y.js";
47
- import "./chunk-TOKQ2UVG.js";
48
+ import "./chunk-MIPQOHWS.js";
48
49
  import "./chunk-LTYL6ZGH.js";
49
50
  import "./chunk-HD6Y77RO.js";
50
51
  import "./chunk-5PT4UMRR.js";
51
52
  import "./chunk-K44MW7JJ.js";
52
- import "./chunk-ZKLE2Q3I.js";
53
+ import "./chunk-KSDWQ6IZ.js";
53
54
  import "./chunk-KSXCOHHW.js";
54
55
  import "./chunk-CQGTEGKL.js";
55
56
  import "./chunk-YLJ4XMA6.js";
@@ -173,4 +174,4 @@ export {
173
174
  startChatSession,
174
175
  stopSessionExecution
175
176
  };
176
- //# sourceMappingURL=chat-handler-URSNELCE.js.map
177
+ //# sourceMappingURL=chat-handler-M54IWF5Y.js.map
@@ -11,7 +11,7 @@ import {
11
11
  } from "./chunk-3PG65AXG.js";
12
12
  import {
13
13
  parseDefaultModelSelection
14
- } from "./chunk-GZTMCTUS.js";
14
+ } from "./chunk-U6JMRMBW.js";
15
15
  import {
16
16
  getDatabase
17
17
  } from "./chunk-5PT4UMRR.js";
@@ -677,6 +677,12 @@ function createTasksService(deps) {
677
677
  ...autoLaunched ? { autoLaunched } : {}
678
678
  });
679
679
  }
680
+ function reusableTarget(projectId, sessionId) {
681
+ if (!sessionId) return void 0;
682
+ const session = sessionManager.getSession(sessionId);
683
+ if (!session || session.projectId !== projectId || session.messages.length > 0) return void 0;
684
+ return sessionId;
685
+ }
680
686
  function list(projectId) {
681
687
  return listTasks(projectId);
682
688
  }
@@ -787,12 +793,14 @@ function createTasksService(deps) {
787
793
  const launched = runningCount < settings.slotLimit && !settings.queuePaused;
788
794
  setTaskRunState(taskId, launched ? "running" : "queued");
789
795
  if (launched) {
790
- const seeded = await seedSession(projectId, task, from);
796
+ const seeded = await seedSession(projectId, task, from, reusableTarget(projectId, opts.sessionId));
791
797
  addTaskLink(taskId, seeded.session.id, true);
792
798
  addAuditEntry(taskId, "human", "move", `Moved to In Progress (running)`, opts.actorName);
793
799
  sessionId = seeded.session.id;
794
800
  } else {
795
801
  appendToBottom(taskId, "in_progress");
802
+ const earmarked = reusableTarget(projectId, opts.sessionId);
803
+ if (earmarked) addTaskLink(taskId, earmarked, false);
796
804
  addAuditEntry(taskId, "human", "move", `Moved to In Progress (queued)`, opts.actorName);
797
805
  }
798
806
  }
@@ -905,11 +913,20 @@ function createTasksService(deps) {
905
913
  function activeCount(projectId) {
906
914
  return listTasks(projectId).filter((t) => t.status === "in_progress" && t.runState === "running").length;
907
915
  }
908
- async function seedSession(projectId, task, from) {
909
- const defaults = parseDefaultModelSelection(config.defaultModelSelection);
910
- const providerId = task.providerId ?? defaults.providerId ?? null;
911
- const model = task.model ?? defaults.model ?? null;
912
- const session = sessionManager.createSession(projectId, void 0, providerId, model);
916
+ async function seedSession(projectId, task, from, targetSessionId) {
917
+ let session;
918
+ if (targetSessionId) {
919
+ const existing = sessionManager.getSession(targetSessionId);
920
+ if (!existing) {
921
+ return seedSession(projectId, task, from);
922
+ }
923
+ session = existing;
924
+ } else {
925
+ const defaults = parseDefaultModelSelection(config.defaultModelSelection);
926
+ const providerId = task.providerId ?? defaults.providerId ?? null;
927
+ const model = task.model ?? defaults.model ?? null;
928
+ session = sessionManager.createSession(projectId, void 0, providerId, model);
929
+ }
913
930
  if (task.agentId) {
914
931
  try {
915
932
  sessionManager.setMode(session.id, task.agentId);
@@ -957,7 +974,9 @@ function createTasksService(deps) {
957
974
  const next = queued[0];
958
975
  if (!next) return void 0;
959
976
  setTaskRunState(next.id, "running");
960
- const seeded = await seedSession(projectId, next, "queued");
977
+ const earmarks = listTaskLinks(next.id);
978
+ const target = reusableTarget(projectId, earmarks[0]?.session_id);
979
+ const seeded = await seedSession(projectId, next, "queued", target);
961
980
  addTaskLink(next.id, seeded.session.id, true);
962
981
  addAuditEntry(next.id, "system", "auto_launch", `Auto-launched into session ${seeded.session.id}`, "system");
963
982
  return {
@@ -1079,4 +1098,4 @@ export {
1079
1098
  isTaskGateError,
1080
1099
  createTasksService
1081
1100
  };
1082
- //# sourceMappingURL=chunk-HZSKKJHQ.js.map
1101
+ //# sourceMappingURL=chunk-5FAPM2GM.js.map
@@ -4,12 +4,12 @@ import {
4
4
  getToolRegistryForAgent,
5
5
  processEventsForConversation,
6
6
  runTopLevelAgentLoop
7
- } from "./chunk-2PQA3DHY.js";
7
+ } from "./chunk-V5XWUVF5.js";
8
8
  import {
9
9
  buildCachedPrompt,
10
10
  computeDynamicContextHash,
11
11
  getToolFingerprint
12
- } from "./chunk-3PEYTWCS.js";
12
+ } from "./chunk-UNNCD7A3.js";
13
13
  import {
14
14
  getAllInstructions,
15
15
  getEnabledSkillMetadata
@@ -18,19 +18,19 @@ import {
18
18
  TurnMetrics,
19
19
  createChatDoneEvent,
20
20
  createMessageStartEvent
21
- } from "./chunk-EQ7DK2TG.js";
21
+ } from "./chunk-SE62ZBNX.js";
22
22
  import {
23
23
  buildAgentReminder,
24
24
  buildAgentSmallReminder
25
25
  } from "./chunk-27NABDXB.js";
26
26
  import {
27
27
  PathAccessDeniedError
28
- } from "./chunk-QQVPUZQB.js";
28
+ } from "./chunk-XZGQZ42D.js";
29
29
  import {
30
30
  getCurrentContextWindowId,
31
31
  getCurrentWindowMessageOptions,
32
32
  getEventStore
33
- } from "./chunk-TGVDUK4N.js";
33
+ } from "./chunk-JOCR4CF4.js";
34
34
  import {
35
35
  buildSnapshotFromSessionState
36
36
  } from "./chunk-3KBRMBTP.js";
@@ -72,9 +72,9 @@ async function buildRetryPatterns() {
72
72
  return { retryPatterns: [], maxRetriesPerTurn: 10 };
73
73
  }
74
74
  }
75
- function buildGetConversationMessages(sessionId, llmClient, append) {
75
+ function buildGetConversationMessages(sessionId, resolveLLMClient, append) {
76
76
  return async () => {
77
- const processedEvents = await processEventsForConversation(sessionId, llmClient, (event) => append(event));
77
+ const processedEvents = await processEventsForConversation(sessionId, resolveLLMClient(), (event) => append(event));
78
78
  return getConversationMessages({ type: "toplevel", sessionId }, { events: processedEvents });
79
79
  };
80
80
  }
@@ -226,7 +226,11 @@ function injectAgentReminder(sessionId, agentDef) {
226
226
  async function runAgentTurn(options, turnMetrics, agentId, append, callbacks) {
227
227
  const allAgents = await loadAllAgentsDefault(options.sessionManager.getProjectWorkdir(options.sessionId));
228
228
  const agentDef = findAgentById(agentId, allAgents) ?? findAgentById(resolveDefaultAgentId(), allAgents);
229
- const agentLlmClient = options.sessionManager.createClientForAgent(agentId, options.llmClient);
229
+ const resolveAgentClient = () => options.sessionManager.createClientForAgent(
230
+ agentId,
231
+ options.getSessionLLMClient ? options.getSessionLLMClient() : options.llmClient
232
+ );
233
+ const agentLlmClient = resolveAgentClient();
230
234
  const statsIdentity = resolveStatsIdentity({ ...options, llmClient: agentLlmClient });
231
235
  if (!options.warmup && !options.skipAgentReminder) {
232
236
  injectAgentReminder(options.sessionId, agentDef);
@@ -244,6 +248,7 @@ async function runAgentTurn(options, turnMetrics, agentId, append, callbacks) {
244
248
  sessionManager: options.sessionManager,
245
249
  sessionId: options.sessionId,
246
250
  llmClient: agentLlmClient,
251
+ getLLMClient: resolveAgentClient,
247
252
  statsIdentity,
248
253
  providerManager: options.sessionManager.getProviderManager(),
249
254
  signal: options.signal,
@@ -256,7 +261,7 @@ async function runAgentTurn(options, turnMetrics, agentId, append, callbacks) {
256
261
  instructionContent ?? "",
257
262
  skills,
258
263
  toolFingerprint,
259
- agentLlmClient.getModel()
264
+ resolveAgentClient().getModel()
260
265
  );
261
266
  if (cached.hash !== currentHash) {
262
267
  logger.debug("assembleRequest: hash mismatch", {
@@ -291,12 +296,12 @@ async function runAgentTurn(options, turnMetrics, agentId, append, callbacks) {
291
296
  });
292
297
  },
293
298
  getToolRegistry: () => getToolRegistryForAgent(agentDef, options.sessionId),
294
- getConversationMessages: buildGetConversationMessages(options.sessionId, agentLlmClient, append),
299
+ getConversationMessages: buildGetConversationMessages(options.sessionId, resolveAgentClient, append),
295
300
  injectAgentReminder: () => injectAgentReminder(options.sessionId, agentDef),
296
301
  ...options.initialCompacting ? { initialCompacting: true } : {},
297
302
  ...callbacks?.injectKickoff ? { injectKickoff: callbacks.injectKickoff } : {},
298
303
  ...callbacks?.onToolExecuted ? { onToolExecuted: callbacks.onToolExecuted } : {},
299
- ...options.suppressRecoverableErrors ? { suppressChatError: true } : {},
304
+ ...options.llmRetryPolicy ? { llmRetryPolicy: options.llmRetryPolicy } : {},
300
305
  ...options.warmup ? { warmup: true } : {}
301
306
  },
302
307
  turnMetrics
@@ -320,4 +325,4 @@ export {
320
325
  runChatTurn,
321
326
  runAgentTurn
322
327
  };
323
- //# sourceMappingURL=chunk-I6MY65LO.js.map
328
+ //# sourceMappingURL=chunk-6DDB67FN.js.map
@@ -163,7 +163,7 @@ async function runCli(options) {
163
163
  break;
164
164
  }
165
165
  case "provider": {
166
- const { runProviderCommand } = await import("./provider-Q7J4UFTS.js");
166
+ const { runProviderCommand } = await import("./provider-7YF42S7C.js");
167
167
  const [, subcommand] = positionals;
168
168
  await runProviderCommand(mode, subcommand);
169
169
  break;
@@ -200,7 +200,7 @@ async function runCli(options) {
200
200
  break;
201
201
  }
202
202
  case "update": {
203
- const { runUpdate } = await import("./update-YP7IRT6M.js");
203
+ const { runUpdate } = await import("./update-C3YVPKCR.js");
204
204
  const code = await runUpdate();
205
205
  if (code !== 0) {
206
206
  process.exit(code);
@@ -213,7 +213,7 @@ async function runCli(options) {
213
213
  if (!configExists) {
214
214
  await runNetworkSetup(mode);
215
215
  }
216
- const { runServe } = await import("./serve-CW6PR3M2.js");
216
+ const { runServe } = await import("./serve-V34QG72C.js");
217
217
  const serveOptions = { mode };
218
218
  if (values.port) serveOptions.port = parseInt(values.port);
219
219
  if (values["no-browser"] === true) serveOptions.openBrowser = false;
@@ -225,4 +225,4 @@ async function runCli(options) {
225
225
  export {
226
226
  runCli
227
227
  };
228
- //# sourceMappingURL=chunk-ZS6MW2WM.js.map
228
+ //# sourceMappingURL=chunk-AIFZNTUJ.js.map