openfox 2.0.123 → 2.0.125

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 (61) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/README.md +1 -0
  3. package/dist/CHANGELOG.md +33 -0
  4. package/dist/{auto-config-4BFGLPCP.js → auto-config-454YE6KC.js} +6 -66
  5. package/dist/{backend-67OLCS5O.js → backend-4YPEC3J2.js} +2 -2
  6. package/dist/{chat-handler-UWZYFGRY.js → chat-handler-HJ2RBGNV.js} +15 -15
  7. package/dist/{chunk-ZKMZI4ZG.js → chunk-7DO4JMGT.js} +6 -6
  8. package/dist/{chunk-SS6KV6DI.js → chunk-CTHRGR4O.js} +2 -2
  9. package/dist/{chunk-SYTEO5LA.js → chunk-FNXTJLCZ.js} +197 -8
  10. package/dist/chunk-GZUD5E6E.js +7 -0
  11. package/dist/{chunk-W4SM4FFZ.js → chunk-HOSFRPPI.js} +14 -10
  12. package/dist/{chunk-TPDBUOPN.js → chunk-ISE55FOR.js} +11 -4
  13. package/dist/{chunk-MIPQOHWS.js → chunk-KAZWU73N.js} +26 -2
  14. package/dist/{chunk-INOO465O.js → chunk-KD4W3I6C.js} +108 -29
  15. package/dist/{chunk-PZUKG3OZ.js → chunk-KETVPTMI.js} +3 -3
  16. package/dist/{chunk-62GUO2EG.js → chunk-LJX7KXRU.js} +3 -3
  17. package/dist/{chunk-V2UJP5CX.js → chunk-NBOSTFTS.js} +5 -5
  18. package/dist/{chunk-4L7UMEHD.js → chunk-O5A3XKE5.js} +99 -17
  19. package/dist/{chunk-AZHWLLPP.js → chunk-PBFGJFGC.js} +28 -10
  20. package/dist/{chunk-FFEZJBQO.js → chunk-T2RDFRNK.js} +60 -53
  21. package/dist/{chunk-H4JRR5KV.js → chunk-T3JVYO3Z.js} +17 -7
  22. package/dist/{chunk-JEZN37KV.js → chunk-UAAFZEIS.js} +2 -2
  23. package/dist/{chunk-YGOF4QDW.js → chunk-WMAW37GV.js} +9 -9
  24. package/dist/{chunk-YU5QPXSU.js → chunk-X2J6BAU7.js} +4 -4
  25. package/dist/{chunk-3NMLSANH.js → chunk-Y3BSBKHY.js} +31 -17
  26. package/dist/chunk-ZFNBATE3.js +196 -0
  27. package/dist/cli/dev.js +1 -1
  28. package/dist/cli/index.js +1 -1
  29. package/dist/{client-XHJHOFMU.js → client-YHYIWZY7.js} +5 -5
  30. package/dist/{client-pure-QSY7TJGK.js → client-pure-CJKM3ACP.js} +2 -2
  31. package/dist/{compactor-VTATJTPN.js → compactor-7KPBTFZF.js} +5 -5
  32. package/dist/{dynamic-context-5TPG2AJL.js → dynamic-context-5MQWJTJC.js} +2 -2
  33. package/dist/{http-client-N4ASJEKJ.js → http-client-ROVNSHF6.js} +2 -2
  34. package/dist/{launch-5PJLLVXV.js → launch-ZHAFPRCP.js} +15 -15
  35. package/dist/{model-catalog-T2GQFJI4.js → model-catalog-ZLOWTQA7.js} +2 -2
  36. package/dist/{orchestrator-2Q3R5KKR.js → orchestrator-KKUXIE3Q.js} +14 -14
  37. package/dist/package.json +1 -1
  38. package/dist/{path-security-NRO37OAP.js → path-security-YTPZ35SL.js} +6 -4
  39. package/dist/plugins-registry.json +6 -0
  40. package/dist/{processor-N2XW2KJV.js → processor-HETUXJFH.js} +14 -14
  41. package/dist/provider/index.d.ts +2 -2
  42. package/dist/{provider-EBL6Z7TV.js → provider-6LUA73HF.js} +7 -7
  43. package/dist/{provider-manager-MKF27CTA.js → provider-manager-OQTEXZ7X.js} +7 -7
  44. package/dist/{serve-TARX23JF.js → serve-UVHJHYF3.js} +20 -20
  45. package/dist/server/index.d.ts +6 -1
  46. package/dist/server/index.js +19 -19
  47. package/dist/{server-FKVRW7RV.js → server-E4DOH4OF.js} +18 -18
  48. package/dist/{service-SY6Y4BIM.js → service-BRKMLM4C.js} +8 -8
  49. package/dist/{tasks-IDIKTBOR.js → tasks-DEUZ6BNS.js} +8 -8
  50. package/dist/{tools-YPVZ5QM2.js → tools-AUHL5MPG.js} +12 -12
  51. package/dist/{types-Cr4EgGwK.d.ts → types-BWuVnaBw.d.ts} +3 -1
  52. package/dist/{update-VSSOHC47.js → update-45ZRDWUB.js} +2 -2
  53. package/dist/web/assets/index-DQ3Wg2OF.js +324 -0
  54. package/dist/web/index.html +1 -1
  55. package/dist/web/sw.js +1 -1
  56. package/dist/{workspace-J3JEGF6U.js → workspace-6CUE26YA.js} +2 -2
  57. package/package.json +1 -1
  58. package/plugins-registry.json +6 -0
  59. package/dist/chunk-LXCDR3H5.js +0 -7
  60. package/dist/chunk-VPRB5FNR.js +0 -167
  61. package/dist/web/assets/index-C10YdCOU.js +0 -324
@@ -617,11 +617,35 @@ async function buildChatCompletionCreateParams(model, request, profile, capabili
617
617
  ;
618
618
  params["top_k"] = topK;
619
619
  }
620
+ if (capabilities.supportsNumCtx && request.modelSettings?.numCtx) {
621
+ ;
622
+ params["num_ctx"] = request.modelSettings.numCtx;
623
+ }
620
624
  const resolvedEffort = reasoningEffort ?? request.reasoningEffort;
621
625
  const queryParams = request.modelSettings?.queryParams;
622
626
  const hasQueryParams = queryParams && Object.keys(queryParams).length > 0;
623
627
  const hasExplicitModelSettings = hasQueryParams || !!request.modelSettings?.chatTemplateKwargs;
624
- if (hasQueryParams) {
628
+ if (capabilities.routesEffortViaChatTemplateKwargs) {
629
+ let userKwargs = request.modelSettings?.chatTemplateKwargs;
630
+ if (hasQueryParams) {
631
+ const { chat_template_kwargs: userKwargsFromQP, ...restQueryParams } = queryParams;
632
+ Object.assign(params, restQueryParams);
633
+ if (userKwargsFromQP) {
634
+ userKwargs = userKwargsFromQP;
635
+ }
636
+ }
637
+ const kwargs = { ...userKwargs ?? {} };
638
+ if (resolvedEffort === "none") {
639
+ delete kwargs["reasoning_effort"];
640
+ kwargs["enable_thinking"] = false;
641
+ } else if (resolvedEffort && kwargs["reasoning_effort"] === void 0) {
642
+ kwargs["reasoning_effort"] = resolvedEffort;
643
+ }
644
+ if (Object.keys(kwargs).length > 0) {
645
+ ;
646
+ params["chat_template_kwargs"] = kwargs;
647
+ }
648
+ } else if (hasQueryParams) {
625
649
  Object.assign(params, queryParams);
626
650
  if (resolvedEffort) {
627
651
  ;
@@ -711,4 +735,4 @@ export {
711
735
  buildStreamingCreateParams,
712
736
  mapFinishReason
713
737
  };
714
- //# sourceMappingURL=chunk-MIPQOHWS.js.map
738
+ //# sourceMappingURL=chunk-KAZWU73N.js.map
@@ -268,30 +268,90 @@ function extractUnquotedTildePaths(command, home) {
268
268
  return paths;
269
269
  }
270
270
  var TRAVERSAL_SEGMENT_RE = /(?:^|\/)\.\.(?:\/|$)/;
271
- function extractRelativeTraversals(command) {
271
+ var CD_NON_TARGET_KEYWORDS = /* @__PURE__ */ new Set([
272
+ "cd",
273
+ "pushd",
274
+ "popd",
275
+ "echo",
276
+ "exit",
277
+ "export",
278
+ "source",
279
+ "set",
280
+ "true",
281
+ "false"
282
+ ]);
283
+ var DYNAMIC_CD_TARGET_RE = /[$`{}]/;
284
+ function applyCdTarget(cwd, target) {
285
+ if (target === "~") return normalize(homedir());
286
+ if (target.startsWith("~/")) return normalize(resolve(homedir(), target.slice(2)));
287
+ if (target.startsWith("/")) return normalize(target);
288
+ if (target.startsWith("-")) return cwd;
289
+ if (DYNAMIC_CD_TARGET_RE.test(target)) return cwd;
290
+ return normalize(resolve(cwd, target));
291
+ }
292
+ function resolveRelativeTraversals(command, workdir) {
293
+ const masked = maskCommandForPathScan(command);
272
294
  const out = [];
273
- const isTraversal = (token) => TRAVERSAL_SEGMENT_RE.test(token);
274
- const quotedPattern = /["']([^"']+)["']/g;
275
- let m;
276
- while ((m = quotedPattern.exec(command)) !== null) {
277
- const content = m[1];
278
- if (!content || content.startsWith("/") || content.startsWith("~") || isWindowsAbsolutePath(content)) continue;
279
- if (isTraversal(content)) out.push(content);
280
- }
281
- const bare = command.replace(/["'][^"']*["']/g, " ").split(/[\s|&;<>()]+/);
282
- for (const token of bare) {
283
- if (!token || token.startsWith("/") || token.startsWith("~")) continue;
284
- if (isTraversal(token)) out.push(token);
295
+ let cwd = normalize(resolve(workdir));
296
+ let quote = null;
297
+ let word = "";
298
+ let quoted = false;
299
+ let expectCdTarget = false;
300
+ const n = masked.length;
301
+ const flush = () => {
302
+ if (word) {
303
+ const isTraversal = !word.startsWith("/") && !word.startsWith("~") && TRAVERSAL_SEGMENT_RE.test(word);
304
+ if (expectCdTarget) {
305
+ expectCdTarget = false;
306
+ if (!quoted && CD_NON_TARGET_KEYWORDS.has(word)) {
307
+ } else {
308
+ if (isTraversal) out.push(normalize(resolve(cwd, word)));
309
+ cwd = applyCdTarget(cwd, word);
310
+ }
311
+ } else if (!quoted && (word === "cd" || word === "pushd")) {
312
+ expectCdTarget = true;
313
+ } else if (isTraversal) {
314
+ out.push(normalize(resolve(cwd, word)));
315
+ }
316
+ }
317
+ word = "";
318
+ quoted = false;
319
+ };
320
+ for (let i = 0; i < n; i++) {
321
+ const ch = masked[i];
322
+ if (quote !== null) {
323
+ if (ch === "\\" && quote !== "'") {
324
+ word += masked[i + 1] ?? "";
325
+ i += 1;
326
+ continue;
327
+ }
328
+ if (ch === quote) {
329
+ quote = null;
330
+ quoted = true;
331
+ continue;
332
+ }
333
+ word += ch;
334
+ continue;
335
+ }
336
+ if (ch === "'" || ch === '"' || ch === "`") {
337
+ quote = ch;
338
+ continue;
339
+ }
340
+ if (ch === "\\") {
341
+ word += masked[i + 1] ?? "";
342
+ i += 1;
343
+ continue;
344
+ }
345
+ if (/[\s&|;<>()]/.test(ch)) {
346
+ flush();
347
+ continue;
348
+ }
349
+ word += ch;
285
350
  }
351
+ flush();
286
352
  return [...new Set(out)];
287
353
  }
288
- function extractAbsolutePathsFromCommand(command) {
289
- if (!command.trim()) {
290
- return [];
291
- }
292
- const paths = [];
293
- const home = homedir();
294
- const posixShell = usesPosixPaths();
354
+ function maskCommandForPathScan(command) {
295
355
  let sanitized = command.replace(/https?:\/\/[^\s'"]+/g, " __URL__ ").replace(/ftp:\/\/[^\s'"]+/g, " __URL__ ");
296
356
  sanitized = sanitized.replace(/(?<!\w)s\/[^/]*\/[^/]*\/[gip]*/g, " __SED__ ");
297
357
  sanitized = sanitized.replace(/(?<!\w)s\|[^|]*\|[^|]*\|[gip]*/g, " __SED__ ");
@@ -299,8 +359,18 @@ function extractAbsolutePathsFromCommand(command) {
299
359
  sanitized = maskRegexAddresses(sanitized);
300
360
  sanitized = sanitized.replace(
301
361
  /git\s+commit\b.*?(?:-(?:[a-zA-Z]*m)(?=\s)|--message)\s+(["'])(?:(?!\1).)*\1/g,
302
- (match2) => match2.replace(/\/[^\s"'|&;<>`()]+/g, " __COMMIT_MSG__ ")
362
+ (match) => match.replace(/\/[^\s"'|&;<>`()]+/g, " __COMMIT_MSG__ ")
303
363
  );
364
+ return sanitized;
365
+ }
366
+ function extractAbsolutePathsFromCommand(command) {
367
+ if (!command.trim()) {
368
+ return [];
369
+ }
370
+ const paths = [];
371
+ const home = homedir();
372
+ const posixShell = usesPosixPaths();
373
+ const sanitized = maskCommandForPathScan(command);
304
374
  const fileUrlMatches = command.matchAll(/file:\/\/([^\s'"]+)/g);
305
375
  for (const match2 of fileUrlMatches) {
306
376
  const filePath = match2[1];
@@ -308,11 +378,11 @@ function extractAbsolutePathsFromCommand(command) {
308
378
  paths.push(normalizeExtracted(filePath));
309
379
  }
310
380
  }
311
- sanitized = sanitized.replace(/file:\/\/[^\s'"]+/g, " __FILEURL__ ");
312
- paths.push(...extractUnquotedTildePaths(sanitized, home));
381
+ const scanCommand = sanitized.replace(/file:\/\/[^\s'"]+/g, " __FILEURL__ ");
382
+ paths.push(...extractUnquotedTildePaths(scanCommand, home));
313
383
  const quotedPattern = /["']([^"']+)["']/g;
314
384
  let match;
315
- while ((match = quotedPattern.exec(sanitized)) !== null) {
385
+ while ((match = quotedPattern.exec(scanCommand)) !== null) {
316
386
  const content = match[1];
317
387
  if (content.startsWith("/") && content.endsWith("/")) {
318
388
  continue;
@@ -334,7 +404,7 @@ function extractAbsolutePathsFromCommand(command) {
334
404
  }
335
405
  if (isWindows()) {
336
406
  const winAbsolutePattern = /(?:^|[\s=(])([A-Za-z]:[\\/][^\s"'|&;<>`()]+)/g;
337
- while ((match = winAbsolutePattern.exec(sanitized)) !== null) {
407
+ while ((match = winAbsolutePattern.exec(scanCommand)) !== null) {
338
408
  const candidate = match[1];
339
409
  if (isPlaceholderToken(candidate)) continue;
340
410
  const resolved = normalizeExtracted(candidate);
@@ -346,10 +416,19 @@ function extractAbsolutePathsFromCommand(command) {
346
416
  if (posixShell) {
347
417
  const absolutePattern = /(?:^|[\s=(])(\/[^\s"'|&;<>`()]+)/g;
348
418
  const rootPattern = /(?:^|[\s=(])\/(?=$|[\s'"`|&;,<()])/g;
349
- if (rootPattern.test(sanitized)) {
419
+ let isRoot = false;
420
+ for (const match2 of scanCommand.matchAll(rootPattern)) {
421
+ const rest = scanCommand.slice(match2.index + match2[0].length);
422
+ if (/^\s+[0-9]/.test(rest) && !/^\s+[0-9]+[>]/.test(rest)) {
423
+ continue;
424
+ }
425
+ isRoot = true;
426
+ break;
427
+ }
428
+ if (isRoot) {
350
429
  paths.push("/");
351
430
  }
352
- while ((match = absolutePattern.exec(sanitized)) !== null) {
431
+ while ((match = absolutePattern.exec(scanCommand)) !== null) {
353
432
  const candidate = match[1];
354
433
  if (isPlaceholderToken(candidate)) continue;
355
434
  if (looksLikeRegex(candidate)) continue;
@@ -360,7 +439,6 @@ function extractAbsolutePathsFromCommand(command) {
360
439
  }
361
440
  }
362
441
  }
363
- paths.push(...extractRelativeTraversals(sanitized));
364
442
  return [...new Set(paths)];
365
443
  }
366
444
  function extractSensitivePathsFromCommand(command) {
@@ -656,6 +734,7 @@ export {
656
734
  isPathAllowed,
657
735
  clearAllowedPaths,
658
736
  isPathWithinSandbox,
737
+ resolveRelativeTraversals,
659
738
  extractAbsolutePathsFromCommand,
660
739
  extractSensitivePathsFromCommand,
661
740
  checkPathsAccess,
@@ -671,4 +750,4 @@ export {
671
750
  getConfirmationSessionId,
672
751
  getPendingConfirmationsBySession
673
752
  };
674
- //# sourceMappingURL=chunk-INOO465O.js.map
753
+ //# sourceMappingURL=chunk-KD4W3I6C.js.map
@@ -105,7 +105,7 @@ function resolveAgentDef(sessionManager, sessionId) {
105
105
  }
106
106
  async function buildCachedPrompt(sessionManager, sessionId, agentDef, modelName) {
107
107
  const { instructionContent, skills } = await loadSessionContext(sessionManager, sessionId);
108
- const { getToolRegistryForAgent } = await import("./tools-YPVZ5QM2.js");
108
+ const { getToolRegistryForAgent } = await import("./tools-AUHL5MPG.js");
109
109
  const tools = getToolRegistryForAgent(agentDef, sessionId).definitions;
110
110
  const toolFingerprint = getToolFingerprint(tools);
111
111
  const allAgents = await loadAllAgentsDefault(sessionManager.getProjectWorkdir(sessionId));
@@ -124,7 +124,7 @@ async function buildCachedPrompt(sessionManager, sessionId, agentDef, modelName)
124
124
  async function computeSessionHash(sessionManager, sessionId, modelName) {
125
125
  const { instructionContent, skills } = await loadSessionContext(sessionManager, sessionId);
126
126
  const agentDef = await resolveAgentDef(sessionManager, sessionId);
127
- const { getToolRegistryForAgent } = await import("./tools-YPVZ5QM2.js");
127
+ const { getToolRegistryForAgent } = await import("./tools-AUHL5MPG.js");
128
128
  const tools = getToolRegistryForAgent(agentDef, sessionId).definitions;
129
129
  const toolFingerprint = getToolFingerprint(tools);
130
130
  return computeDynamicContextHash(instructionContent, skills, toolFingerprint, modelName);
@@ -148,4 +148,4 @@ export {
148
148
  computeSessionHash,
149
149
  applyDynamicContext
150
150
  };
151
- //# sourceMappingURL=chunk-PZUKG3OZ.js.map
151
+ //# sourceMappingURL=chunk-KETVPTMI.js.map
@@ -6,10 +6,10 @@ import {
6
6
  } from "./chunk-GJL3QSMP.js";
7
7
  import {
8
8
  getBackendCapabilities
9
- } from "./chunk-AZHWLLPP.js";
9
+ } from "./chunk-PBFGJFGC.js";
10
10
  import {
11
11
  buildModelParams
12
- } from "./chunk-MIPQOHWS.js";
12
+ } from "./chunk-KAZWU73N.js";
13
13
  import {
14
14
  logger
15
15
  } from "./chunk-K44MW7JJ.js";
@@ -518,4 +518,4 @@ export {
518
518
  createChatDoneEvent,
519
519
  consumeStreamGenerator
520
520
  };
521
- //# sourceMappingURL=chunk-62GUO2EG.js.map
521
+ //# sourceMappingURL=chunk-LJX7KXRU.js.map
@@ -4,12 +4,12 @@ import {
4
4
  getToolRegistryForAgent,
5
5
  processEventsForConversation,
6
6
  runTopLevelAgentLoop
7
- } from "./chunk-4L7UMEHD.js";
7
+ } from "./chunk-O5A3XKE5.js";
8
8
  import {
9
9
  buildCachedPrompt,
10
10
  computeDynamicContextHash,
11
11
  getToolFingerprint
12
- } from "./chunk-PZUKG3OZ.js";
12
+ } from "./chunk-KETVPTMI.js";
13
13
  import {
14
14
  getAllInstructions,
15
15
  getEnabledSkillMetadata
@@ -18,14 +18,14 @@ import {
18
18
  TurnMetrics,
19
19
  createChatDoneEvent,
20
20
  createMessageStartEvent
21
- } from "./chunk-62GUO2EG.js";
21
+ } from "./chunk-LJX7KXRU.js";
22
22
  import {
23
23
  buildAgentReminder,
24
24
  buildAgentSmallReminder
25
25
  } from "./chunk-GIJUWPRQ.js";
26
26
  import {
27
27
  PathAccessDeniedError
28
- } from "./chunk-INOO465O.js";
28
+ } from "./chunk-KD4W3I6C.js";
29
29
  import {
30
30
  getCurrentContextWindowId,
31
31
  getCurrentWindowMessageOptions,
@@ -329,4 +329,4 @@ export {
329
329
  runChatTurn,
330
330
  runAgentTurn
331
331
  };
332
- //# sourceMappingURL=chunk-V2UJP5CX.js.map
332
+ //# sourceMappingURL=chunk-NBOSTFTS.js.map
@@ -18,7 +18,7 @@ import {
18
18
  recordLLMFailure,
19
19
  sleepThroughRetryBackoff,
20
20
  streamLLMPure
21
- } from "./chunk-62GUO2EG.js";
21
+ } from "./chunk-LJX7KXRU.js";
22
22
  import {
23
23
  COMPACTION_PROMPT,
24
24
  buildBasePrompt,
@@ -56,12 +56,12 @@ import {
56
56
  getGitBranch,
57
57
  isGitRepository,
58
58
  listWorkspaces
59
- } from "./chunk-3NMLSANH.js";
59
+ } from "./chunk-Y3BSBKHY.js";
60
60
  import {
61
61
  getGateConfig,
62
62
  isTaskConflictError,
63
63
  isTaskGateError
64
- } from "./chunk-SS6KV6DI.js";
64
+ } from "./chunk-CTHRGR4O.js";
65
65
  import {
66
66
  getSessionDisabledServers
67
67
  } from "./chunk-7YP4O4XE.js";
@@ -70,8 +70,9 @@ import {
70
70
  extractAbsolutePathsFromCommand,
71
71
  extractSensitivePathsFromCommand,
72
72
  registerPathConfirmation,
73
- requestPathAccess
74
- } from "./chunk-INOO465O.js";
73
+ requestPathAccess,
74
+ resolveRelativeTraversals
75
+ } from "./chunk-KD4W3I6C.js";
75
76
  import {
76
77
  getCurrentContextWindowId,
77
78
  getCurrentWindowMessageOptions,
@@ -119,7 +120,7 @@ import {
119
120
  formatPdfErrorMessage,
120
121
  isPdfBuffer,
121
122
  processPdfContent
122
- } from "./chunk-MIPQOHWS.js";
123
+ } from "./chunk-KAZWU73N.js";
123
124
  import {
124
125
  SETTINGS_KEYS,
125
126
  getSetting,
@@ -1218,9 +1219,11 @@ var runCommandTool = createTool(
1218
1219
  const pathsToCheck = [workingDir];
1219
1220
  const commandPaths = extractAbsolutePathsFromCommand(args.command);
1220
1221
  for (const cmdPath of commandPaths) {
1221
- const resolved = isAbsolute(cmdPath) ? cmdPath : resolve3(workingDir, cmdPath);
1222
- pathsToCheck.push(resolved);
1222
+ if (isAbsolute(cmdPath)) {
1223
+ pathsToCheck.push(cmdPath);
1224
+ }
1223
1225
  }
1226
+ pathsToCheck.push(...resolveRelativeTraversals(args.command, workingDir));
1224
1227
  const sensitivePaths = extractSensitivePathsFromCommand(args.command);
1225
1228
  for (const sensitivePath of sensitivePaths) {
1226
1229
  const resolved = isAbsolute(sensitivePath) ? sensitivePath : resolve3(workingDir, sensitivePath);
@@ -1783,6 +1786,21 @@ Error: ${toolResult.error}` : `Error: ${toolResult.error}`
1783
1786
  return { toolMessages, criteriaChanged: false, returnValueContent, returnValueResult, stepDoneCalled };
1784
1787
  }
1785
1788
 
1789
+ // src/server/chat/token-budget.ts
1790
+ var CHARS_PER_TOKEN = 4;
1791
+ var TOOL_MESSAGE_OVERHEAD_TOKENS = 16;
1792
+ function estimateToolResultTokens(toolMessages) {
1793
+ return toolMessages.reduce(
1794
+ (sum, message) => sum + TOOL_MESSAGE_OVERHEAD_TOKENS + Math.ceil(message.content.length / CHARS_PER_TOKEN),
1795
+ 0
1796
+ );
1797
+ }
1798
+ var CONTEXT_LENGTH_ERROR_PATTERN = /context\s*length|context_length|context window|prompt (?:is )?too long/i;
1799
+ function isContextLengthError(message) {
1800
+ if (!message) return false;
1801
+ return CONTEXT_LENGTH_ERROR_PATTERN.test(message);
1802
+ }
1803
+
1786
1804
  // src/server/chat/retry-limiter.ts
1787
1805
  function createRetryLimiter(max) {
1788
1806
  let current = 0;
@@ -1866,6 +1884,7 @@ function emitDoneAndBreak(assistantMsgId, segments, statsIdentity, mode, turnMet
1866
1884
  }
1867
1885
  }
1868
1886
  var MAX_TRUNCATION_RETRIES = 3;
1887
+ var MAX_CONTEXT_LENGTH_RETRIES = 3;
1869
1888
  var OUTPUT_RESERVE_TOKENS = 2048;
1870
1889
  var CONTINUE_PROMPT = "Continue your previous response. Do NOT repeat what you already wrote.";
1871
1890
  var CONTINUE_AFTER_STREAM_ERROR_PROMPT = "The LLM stream was interrupted mid-response. Continue exactly where you left off \u2014 do not repeat what was already written.";
@@ -1876,6 +1895,8 @@ async function runTopLevelAgentLoop(config, turnMetrics) {
1876
1895
  const resolveClient = () => config.getLLMClient?.() ?? llmClient;
1877
1896
  const retryLimiter = createRetryLimiter(config.maxRetriesPerTurn ?? 10);
1878
1897
  let truncationRetryCount = 0;
1898
+ let contextRetryCount = 0;
1899
+ let pendingToolResultTokens = 0;
1879
1900
  let returnValueContent;
1880
1901
  let returnValueResult;
1881
1902
  let currentMaxTokensOverride;
@@ -1978,8 +1999,14 @@ ${CONTINUE_PROMPT}` : CONTINUE_PROMPT;
1978
1999
  const contextState = sessionManager.getContextState(sessionId);
1979
2000
  previousContextTokens = contextState.currentTokens;
1980
2001
  const contextWindow = sessionManager.getCurrentModelContext(sessionId, config.mode);
1981
- const availableForOutput = Math.max(256, contextWindow - contextState.currentTokens - OUTPUT_RESERVE_TOKENS);
1982
- let modelSettings = config.modelSettings ?? (currentMaxTokensOverride !== void 0 ? { ...sessionManager.getCurrentModelSettings(sessionId, config.mode), maxTokens: currentMaxTokensOverride } : sessionManager.getCurrentModelSettings(sessionId, config.mode));
2002
+ const availableForOutput = Math.max(
2003
+ 256,
2004
+ contextWindow - contextState.currentTokens - pendingToolResultTokens - OUTPUT_RESERVE_TOKENS
2005
+ );
2006
+ let modelSettings = config.modelSettings ?? sessionManager.getCurrentModelSettings(sessionId, config.mode);
2007
+ if (modelSettings && currentMaxTokensOverride !== void 0) {
2008
+ modelSettings = { ...modelSettings, maxTokens: currentMaxTokensOverride };
2009
+ }
1983
2010
  if (modelSettings) {
1984
2011
  const requestedMaxTokens = modelSettings.maxTokens ?? 16384;
1985
2012
  modelSettings = { ...modelSettings, maxTokens: Math.min(requestedMaxTokens, availableForOutput) };
@@ -2021,6 +2048,12 @@ ${CONTINUE_PROMPT}` : CONTINUE_PROMPT;
2021
2048
  continuationAppended = true;
2022
2049
  }
2023
2050
  if (signal?.aborted) throw new Error("Aborted");
2051
+ if (isContextLengthError(attemptResult.error) && contextRetryCount < MAX_CONTEXT_LENGTH_RETRIES) {
2052
+ contextRetryCount += 1;
2053
+ const currentMax = modelSettings?.maxTokens ?? currentMaxTokensOverride ?? 16384;
2054
+ currentMaxTokensOverride = Math.max(256, Math.floor(currentMax / 2));
2055
+ continue;
2056
+ }
2024
2057
  requestFailures += 1;
2025
2058
  if (requestFirstFailureAt === 0) {
2026
2059
  requestFirstFailureAt = Date.now();
@@ -2099,9 +2132,11 @@ ${CONTINUE_PROMPT}` : CONTINUE_PROMPT;
2099
2132
  result.usage.completionTokens,
2100
2133
  config.subAgentMetadata?.subAgentId
2101
2134
  );
2135
+ pendingToolResultTokens = 0;
2136
+ currentMaxTokensOverride = void 0;
2102
2137
  if (!compacting) {
2103
2138
  const contextState = sessionManager.getContextState(sessionId);
2104
- const { shouldCompact, appendCompactionPrompt } = await import("./compactor-VTATJTPN.js");
2139
+ const { shouldCompact, appendCompactionPrompt } = await import("./compactor-7KPBTFZF.js");
2105
2140
  if (shouldCompact(
2106
2141
  contextState.currentTokens,
2107
2142
  contextState.maxTokens,
@@ -2208,6 +2243,7 @@ ${COMPACTION_PROMPT}`,
2208
2243
  }
2209
2244
  batchContext.agentTimeout = getRuntimeConfig().agent.toolTimeout;
2210
2245
  const batchResult = await executeTools(assistantMsgId, result.toolCalls, batchContext, append);
2246
+ pendingToolResultTokens = estimateToolResultTokens(batchResult.toolMessages);
2211
2247
  if (batchResult.stepDoneCalled) {
2212
2248
  emitDoneAndBreak(
2213
2249
  assistantMsgId,
@@ -2899,7 +2935,16 @@ async function executeSubAgent(options) {
2899
2935
  model: resolved.override.model,
2900
2936
  ...resolved.override.reasoningEffort ? { reasoningEffort: resolved.override.reasoningEffort } : {}
2901
2937
  };
2902
- overrideModelSettings = providerManager.getModelSettings(resolved.override.providerId, resolved.override.model);
2938
+ const overrideEffort = providerManager.resolveModelEffort(
2939
+ resolved.override.providerId,
2940
+ resolved.override.model,
2941
+ resolved.override.reasoningEffort
2942
+ );
2943
+ overrideModelSettings = providerManager.getModelSettings(
2944
+ resolved.override.providerId,
2945
+ resolved.override.model,
2946
+ overrideEffort === "none" ? "non-thinking" : "thinking"
2947
+ );
2903
2948
  logger.info("Sub-agent using model override", { subAgentType, ...resolved.override });
2904
2949
  } else if (resolved.warning) {
2905
2950
  logger.warn("Sub-agent model override unavailable, falling back", { subAgentType, warning: resolved.warning });
@@ -3116,7 +3161,7 @@ var callSubAgentTool = {
3116
3161
  };
3117
3162
  }
3118
3163
  try {
3119
- const { getToolRegistryForAgent: getToolRegistryForAgent2 } = await import("./tools-YPVZ5QM2.js");
3164
+ const { getToolRegistryForAgent: getToolRegistryForAgent2 } = await import("./tools-AUHL5MPG.js");
3120
3165
  const toolRegistry = getToolRegistryForAgent2(agentDef);
3121
3166
  const turnMetrics = new TurnMetrics();
3122
3167
  const result = await executeSubAgent({
@@ -4138,7 +4183,7 @@ var mcpConfigTool = createTool(
4138
4183
  mcpNotifyChanged?.(sessionId);
4139
4184
  }
4140
4185
  async function rebuildTools() {
4141
- const { setMcpTools: setMcpTools2 } = await import("./tools-YPVZ5QM2.js");
4186
+ const { setMcpTools: setMcpTools2 } = await import("./tools-AUHL5MPG.js");
4142
4187
  const mcpTools = createMcpTools(mcpManagerForTools);
4143
4188
  setMcpTools2(mcpTools);
4144
4189
  }
@@ -4565,13 +4610,15 @@ function getTasksService() {
4565
4610
  }
4566
4611
  var VALID_ACTIONS = ["list", "create", "edit", "move", "set_gate_value", "delete"];
4567
4612
  var LIST_STATUSES = ["todo", "in_progress", "done", "all"];
4613
+ var LIST_DEFAULT_LIMIT = 10;
4614
+ var LIST_MAX_LIMIT = 25;
4568
4615
  var projectTasksTool = createTool(
4569
4616
  "project_tasks",
4570
4617
  {
4571
4618
  type: "function",
4572
4619
  function: {
4573
4620
  name: "project_tasks",
4574
- description: "Kanban task board for this project. Core loop: list \u2192 move \u2192 set_gate_value.\n\nRules:\n- Moving to in_progress binds the task to YOUR current session.\n- Do not move tasks or fill gate values without explicit user approval or a system instruction \u2014 complete the work, then let the user review before the task advances.\n- Moving to done is blocked by unmet gates: the error names the missing fields \u2014 fill them only with user approval, then retry the move.\n- Stale writes fail with CONFLICT \u2014 re-list and retry.\n\nActions:\n- list: tasks (status, gate values, queue position, bound session, audit trail); defaults to open tasks, filter via status (todo | in_progress | done | all)\n- create: add a task to To Do (prompt required)\n- edit: update prompt/attachments/agent/model (taskId + fields)\n- move: change column (to: todo | in_progress | done; optional reason)\n- set_gate_value: fill a gate field (taskId, gateId, value)\n- delete: remove a task (taskId)",
4621
+ description: "Kanban task board for this project. Core loop: list \u2192 move \u2192 set_gate_value.\n\nRules:\n- Moving to in_progress binds the task to YOUR current session.\n- Do not move tasks or fill gate values without explicit user approval or a system instruction \u2014 complete the work, then let the user review before the task advances.\n- Moving to done is blocked by unmet gates: the error names the missing fields \u2014 fill them only with user approval, then retry the move.\n- Stale writes fail with CONFLICT \u2014 re-list and retry.\n\nActions:\n- list: tasks (status, gate values, queue position, bound session, audit trail); defaults to open tasks, filter via status (todo | in_progress | done | all); paginated \u2014 limit 10 max 25, page with offset\n- create: add a task to To Do (prompt required)\n- edit: update prompt/attachments/agent/model (taskId + fields)\n- move: change column (to: todo | in_progress | done; optional reason)\n- set_gate_value: fill a gate field (taskId, gateId, value)\n- delete: remove a task (taskId)",
4575
4622
  parameters: {
4576
4623
  type: "object",
4577
4624
  properties: {
@@ -4591,6 +4638,14 @@ var projectTasksTool = createTool(
4591
4638
  enum: ["todo", "in_progress", "done", "all"],
4592
4639
  description: "Column filter for action=list (default: open tasks)"
4593
4640
  },
4641
+ limit: {
4642
+ type: "number",
4643
+ description: "Max tasks to return for action=list (default: 10, max: 25)"
4644
+ },
4645
+ offset: {
4646
+ type: "number",
4647
+ description: "Number of tasks to skip for action=list pagination (default: 0). Pages are snapshots \u2014 re-list after mutations."
4648
+ },
4594
4649
  expectedVersion: {
4595
4650
  type: "number",
4596
4651
  description: "Task version from your last read; stale writes fail with CONFLICT"
@@ -4618,10 +4673,26 @@ var projectTasksTool = createTool(
4618
4673
  `Invalid "status" filter for action=list: "${String(status)}". Expected one of: todo, in_progress, done, all.`
4619
4674
  );
4620
4675
  }
4676
+ const page = parseListPage(args.limit, args.offset);
4677
+ if (!page.ok) return helpers.error(page.error);
4621
4678
  const tasks = svc.list(projectId);
4622
4679
  const filtered = status === "all" ? tasks : tasks.filter((t) => status === void 0 ? t.status !== "done" : t.status === status);
4680
+ const pageTasks = filtered.slice(page.offset, page.offset + page.limit);
4623
4681
  const gates = getGateConfig(projectId);
4624
- return helpers.success(JSON.stringify({ gates, tasks: filtered.map((t) => taskForAgent(t)) }, null, 2));
4682
+ return helpers.success(
4683
+ JSON.stringify(
4684
+ {
4685
+ gates,
4686
+ tasks: pageTasks.map((t) => taskForAgent(t)),
4687
+ total: filtered.length,
4688
+ limit: page.limit,
4689
+ offset: page.offset,
4690
+ hasMore: page.offset + page.limit < filtered.length
4691
+ },
4692
+ null,
4693
+ 2
4694
+ )
4695
+ );
4625
4696
  }
4626
4697
  case "create": {
4627
4698
  const task = svc.create(
@@ -4714,6 +4785,17 @@ var projectTasksTool = createTool(
4714
4785
  }
4715
4786
  }
4716
4787
  );
4788
+ function parseListPage(limit, offset) {
4789
+ const pageSize = limit ?? LIST_DEFAULT_LIMIT;
4790
+ const skip = offset ?? 0;
4791
+ if (!Number.isInteger(pageSize) || pageSize < 1 || pageSize > LIST_MAX_LIMIT) {
4792
+ return { ok: false, error: `Invalid "limit" for action=list: must be an integer between 1 and ${LIST_MAX_LIMIT}.` };
4793
+ }
4794
+ if (!Number.isInteger(skip) || skip < 0) {
4795
+ return { ok: false, error: 'Invalid "offset" for action=list: must be a non-negative integer.' };
4796
+ }
4797
+ return { ok: true, limit: pageSize, offset: skip };
4798
+ }
4717
4799
  function taskForAgent(task) {
4718
4800
  return {
4719
4801
  id: task.id,
@@ -5026,4 +5108,4 @@ export {
5026
5108
  getToolRegistryForAgent,
5027
5109
  createToolRegistry
5028
5110
  };
5029
- //# sourceMappingURL=chunk-4L7UMEHD.js.map
5111
+ //# sourceMappingURL=chunk-O5A3XKE5.js.map
@@ -2,39 +2,57 @@
2
2
  var BACKEND_CAPABILITIES = {
3
3
  vllm: {
4
4
  supportsChatTemplateKwargs: true,
5
- supportsTopK: true
5
+ supportsTopK: true,
6
+ supportsNumCtx: false,
7
+ routesEffortViaChatTemplateKwargs: false
6
8
  },
7
9
  sglang: {
8
10
  supportsChatTemplateKwargs: true,
9
- supportsTopK: true
11
+ supportsTopK: true,
12
+ supportsNumCtx: false,
13
+ routesEffortViaChatTemplateKwargs: false
10
14
  },
11
15
  openai: {
12
16
  supportsChatTemplateKwargs: false,
13
- supportsTopK: false
17
+ supportsTopK: false,
18
+ supportsNumCtx: false,
19
+ routesEffortViaChatTemplateKwargs: false
14
20
  },
15
21
  anthropic: {
16
22
  supportsChatTemplateKwargs: false,
17
- supportsTopK: false
23
+ supportsTopK: false,
24
+ supportsNumCtx: false,
25
+ routesEffortViaChatTemplateKwargs: false
18
26
  },
19
27
  ollama: {
20
28
  supportsChatTemplateKwargs: false,
21
- supportsTopK: false
29
+ supportsTopK: false,
30
+ supportsNumCtx: true,
31
+ routesEffortViaChatTemplateKwargs: false
22
32
  },
23
33
  llamacpp: {
24
34
  supportsChatTemplateKwargs: false,
25
- supportsTopK: true
35
+ supportsTopK: true,
36
+ supportsNumCtx: false,
37
+ routesEffortViaChatTemplateKwargs: true
26
38
  },
27
39
  lmstudio: {
28
40
  supportsChatTemplateKwargs: false,
29
- supportsTopK: true
41
+ supportsTopK: true,
42
+ supportsNumCtx: false,
43
+ routesEffortViaChatTemplateKwargs: false
30
44
  },
31
45
  "opencode-go": {
32
46
  supportsChatTemplateKwargs: false,
33
- supportsTopK: true
47
+ supportsTopK: true,
48
+ supportsNumCtx: false,
49
+ routesEffortViaChatTemplateKwargs: false
34
50
  },
35
51
  unknown: {
36
52
  supportsChatTemplateKwargs: true,
37
- supportsTopK: true
53
+ supportsTopK: true,
54
+ supportsNumCtx: false,
55
+ routesEffortViaChatTemplateKwargs: false
38
56
  }
39
57
  };
40
58
  function getBackendCapabilities(backend) {
@@ -67,4 +85,4 @@ export {
67
85
  getBackendCapabilities,
68
86
  getBackendDisplayName
69
87
  };
70
- //# sourceMappingURL=chunk-AZHWLLPP.js.map
88
+ //# sourceMappingURL=chunk-PBFGJFGC.js.map