sparkecoder 0.1.87 → 0.1.93

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 (125) hide show
  1. package/README.md +1 -1
  2. package/dist/agent/index.d.ts +3 -3
  3. package/dist/agent/index.js +158 -68
  4. package/dist/agent/index.js.map +1 -1
  5. package/dist/cli.js +416 -108
  6. package/dist/cli.js.map +1 -1
  7. package/dist/db/index.d.ts +2 -2
  8. package/dist/{index-BvIissiB.d.ts → index-Bn0Zox8f.d.ts} +23 -23
  9. package/dist/index.d.ts +5 -5
  10. package/dist/index.js +272 -97
  11. package/dist/index.js.map +1 -1
  12. package/dist/{schema-CohdIL13.d.ts → schema-EmpbnQeQ.d.ts} +3 -3
  13. package/dist/{search-CCffrVJE.d.ts → search-BRnGaIl-.d.ts} +7 -7
  14. package/dist/server/index.js +272 -97
  15. package/dist/server/index.js.map +1 -1
  16. package/dist/tools/index.d.ts +30 -3
  17. package/dist/tools/index.js +38 -4
  18. package/dist/tools/index.js.map +1 -1
  19. package/package.json +5 -5
  20. package/web/.next/BUILD_ID +1 -1
  21. package/web/.next/standalone/web/.next/BUILD_ID +1 -1
  22. package/web/.next/standalone/web/.next/build-manifest.json +2 -2
  23. package/web/.next/standalone/web/.next/prerender-manifest.json +3 -3
  24. package/web/.next/standalone/web/.next/server/app/(main)/page_client-reference-manifest.js +1 -1
  25. package/web/.next/standalone/web/.next/server/app/(main)/session/[id]/page_client-reference-manifest.js +1 -1
  26. package/web/.next/standalone/web/.next/server/app/_global-error.html +2 -2
  27. package/web/.next/standalone/web/.next/server/app/_global-error.rsc +1 -1
  28. package/web/.next/standalone/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  29. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  30. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  31. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  32. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  33. package/web/.next/standalone/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  34. package/web/.next/standalone/web/.next/server/app/_not-found.html +1 -1
  35. package/web/.next/standalone/web/.next/server/app/_not-found.rsc +2 -2
  36. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
  37. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  38. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
  39. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  40. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  41. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  42. package/web/.next/standalone/web/.next/server/app/docs/installation/page_client-reference-manifest.js +1 -1
  43. package/web/.next/standalone/web/.next/server/app/docs/installation.html +2 -2
  44. package/web/.next/standalone/web/.next/server/app/docs/installation.rsc +3 -3
  45. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_full.segment.rsc +3 -3
  46. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_head.segment.rsc +1 -1
  47. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_index.segment.rsc +2 -2
  48. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_tree.segment.rsc +1 -1
  49. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation/__PAGE__.segment.rsc +2 -2
  50. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation.segment.rsc +1 -1
  51. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs.segment.rsc +2 -2
  52. package/web/.next/standalone/web/.next/server/app/docs/page_client-reference-manifest.js +1 -1
  53. package/web/.next/standalone/web/.next/server/app/docs/skills/page_client-reference-manifest.js +1 -1
  54. package/web/.next/standalone/web/.next/server/app/docs/skills.html +2 -2
  55. package/web/.next/standalone/web/.next/server/app/docs/skills.rsc +3 -3
  56. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_full.segment.rsc +3 -3
  57. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_head.segment.rsc +1 -1
  58. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_index.segment.rsc +2 -2
  59. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_tree.segment.rsc +1 -1
  60. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills/__PAGE__.segment.rsc +1 -1
  61. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills.segment.rsc +1 -1
  62. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs.segment.rsc +2 -2
  63. package/web/.next/standalone/web/.next/server/app/docs/tools/page_client-reference-manifest.js +1 -1
  64. package/web/.next/standalone/web/.next/server/app/docs/tools.html +2 -2
  65. package/web/.next/standalone/web/.next/server/app/docs/tools.rsc +3 -3
  66. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_full.segment.rsc +3 -3
  67. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_head.segment.rsc +1 -1
  68. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_index.segment.rsc +2 -2
  69. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_tree.segment.rsc +1 -1
  70. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools/__PAGE__.segment.rsc +2 -2
  71. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools.segment.rsc +1 -1
  72. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs.segment.rsc +2 -2
  73. package/web/.next/standalone/web/.next/server/app/docs.html +2 -2
  74. package/web/.next/standalone/web/.next/server/app/docs.rsc +3 -3
  75. package/web/.next/standalone/web/.next/server/app/docs.segments/_full.segment.rsc +3 -3
  76. package/web/.next/standalone/web/.next/server/app/docs.segments/_head.segment.rsc +1 -1
  77. package/web/.next/standalone/web/.next/server/app/docs.segments/_index.segment.rsc +2 -2
  78. package/web/.next/standalone/web/.next/server/app/docs.segments/_tree.segment.rsc +1 -1
  79. package/web/.next/standalone/web/.next/server/app/docs.segments/docs/__PAGE__.segment.rsc +2 -2
  80. package/web/.next/standalone/web/.next/server/app/docs.segments/docs.segment.rsc +2 -2
  81. package/web/.next/standalone/web/.next/server/app/embed/[id]/page_client-reference-manifest.js +1 -1
  82. package/web/.next/standalone/web/.next/server/app/index.html +1 -1
  83. package/web/.next/standalone/web/.next/server/app/index.rsc +4 -4
  84. package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p/__PAGE__.segment.rsc +2 -2
  85. package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p.segment.rsc +2 -2
  86. package/web/.next/standalone/web/.next/server/app/index.segments/_full.segment.rsc +4 -4
  87. package/web/.next/standalone/web/.next/server/app/index.segments/_head.segment.rsc +1 -1
  88. package/web/.next/standalone/web/.next/server/app/index.segments/_index.segment.rsc +2 -2
  89. package/web/.next/standalone/web/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  90. package/web/.next/standalone/web/.next/server/chunks/[root-of-the-server]__36edac7c._.js +1 -1
  91. package/web/.next/standalone/web/.next/server/chunks/ssr/[root-of-the-server]__be5e2967._.js +1 -1
  92. package/web/.next/standalone/web/.next/server/chunks/ssr/web_src_app_(main)_page_tsx_5ac4794b._.js +1 -1
  93. package/web/.next/standalone/web/.next/server/chunks/ssr/web_src_components_sessions-sidebar_tsx_92510070._.js +1 -1
  94. package/web/.next/standalone/web/.next/server/pages/404.html +1 -1
  95. package/web/.next/standalone/web/.next/server/pages/500.html +2 -2
  96. package/web/.next/standalone/web/.next/server/server-reference-manifest.js +1 -1
  97. package/web/.next/standalone/web/.next/server/server-reference-manifest.json +1 -1
  98. package/web/.next/{static/chunks/26eb5fab5216f3cc.js → standalone/web/.next/static/chunks/58fd0aaa2746b444.js} +1 -1
  99. package/web/.next/standalone/web/.next/static/chunks/9fce2ce79c4c834e.js +1 -0
  100. package/web/.next/standalone/web/.next/static/chunks/{8d3efc76109d2efc.js → a888d448ceab1abe.js} +1 -1
  101. package/web/.next/standalone/web/.next/static/static/chunks/{26eb5fab5216f3cc.js → 58fd0aaa2746b444.js} +1 -1
  102. package/web/.next/standalone/web/.next/static/static/chunks/9fce2ce79c4c834e.js +1 -0
  103. package/web/.next/{static/chunks/8d3efc76109d2efc.js → standalone/web/.next/static/static/chunks/a888d448ceab1abe.js} +1 -1
  104. package/web/.next/standalone/web/package-lock.json +27 -27
  105. package/web/.next/standalone/web/package.json +1 -1
  106. package/web/.next/standalone/web/src/app/(main)/page.tsx +2 -2
  107. package/web/.next/standalone/web/src/app/api/config/route.ts +3 -2
  108. package/web/.next/standalone/web/src/components/sessions-sidebar.tsx +1 -1
  109. package/web/.next/standalone/web/src/lib/config.ts +2 -1
  110. package/web/.next/{standalone/web/.next/static/chunks/26eb5fab5216f3cc.js → static/chunks/58fd0aaa2746b444.js} +1 -1
  111. package/web/.next/static/chunks/9fce2ce79c4c834e.js +1 -0
  112. package/web/.next/{standalone/web/.next/static/static/chunks/8d3efc76109d2efc.js → static/chunks/a888d448ceab1abe.js} +1 -1
  113. package/web/package.json +1 -1
  114. package/web/.next/standalone/web/.next/static/chunks/b31b0765abe0c427.js +0 -1
  115. package/web/.next/standalone/web/.next/static/static/chunks/b31b0765abe0c427.js +0 -1
  116. package/web/.next/static/chunks/b31b0765abe0c427.js +0 -1
  117. /package/web/.next/standalone/web/.next/static/{static/uUaN7Xe5kF_pP6zhfaeYi → -ax3tJNqBGukss29jpu41}/_buildManifest.js +0 -0
  118. /package/web/.next/standalone/web/.next/static/{static/uUaN7Xe5kF_pP6zhfaeYi → -ax3tJNqBGukss29jpu41}/_clientMiddlewareManifest.json +0 -0
  119. /package/web/.next/standalone/web/.next/static/{static/uUaN7Xe5kF_pP6zhfaeYi → -ax3tJNqBGukss29jpu41}/_ssgManifest.js +0 -0
  120. /package/web/.next/standalone/web/.next/static/{uUaN7Xe5kF_pP6zhfaeYi → static/-ax3tJNqBGukss29jpu41}/_buildManifest.js +0 -0
  121. /package/web/.next/standalone/web/.next/static/{uUaN7Xe5kF_pP6zhfaeYi → static/-ax3tJNqBGukss29jpu41}/_clientMiddlewareManifest.json +0 -0
  122. /package/web/.next/standalone/web/.next/static/{uUaN7Xe5kF_pP6zhfaeYi → static/-ax3tJNqBGukss29jpu41}/_ssgManifest.js +0 -0
  123. /package/web/.next/static/{uUaN7Xe5kF_pP6zhfaeYi → -ax3tJNqBGukss29jpu41}/_buildManifest.js +0 -0
  124. /package/web/.next/static/{uUaN7Xe5kF_pP6zhfaeYi → -ax3tJNqBGukss29jpu41}/_clientMiddlewareManifest.json +0 -0
  125. /package/web/.next/static/{uUaN7Xe5kF_pP6zhfaeYi → -ax3tJNqBGukss29jpu41}/_ssgManifest.js +0 -0
package/dist/index.js CHANGED
@@ -107,7 +107,7 @@ var init_types = __esm({
107
107
  }).optional();
108
108
  SparkcoderConfigSchema = z.object({
109
109
  // Default model to use (Vercel AI Gateway format)
110
- defaultModel: z.string().default("anthropic/claude-opus-4-6"),
110
+ defaultModel: z.string().default("anthropic/claude-opus-4.7"),
111
111
  // Working directory for file operations
112
112
  workingDirectory: z.string().optional(),
113
113
  // Tool approval settings
@@ -466,6 +466,14 @@ function loadApiKeysIntoEnv() {
466
466
  }
467
467
  }
468
468
  }
469
+ function isRemoteInferenceConfigured() {
470
+ try {
471
+ const config = getConfig();
472
+ return config.resolvedRemoteServer.isConfigured;
473
+ } catch {
474
+ return false;
475
+ }
476
+ }
469
477
  function setApiKey(provider, apiKey) {
470
478
  const normalizedProvider = provider.toLowerCase();
471
479
  const envVar = PROVIDER_ENV_MAP[normalizedProvider];
@@ -515,11 +523,11 @@ function getApiKeyStatus() {
515
523
  };
516
524
  });
517
525
  }
518
- function maskApiKey(key) {
519
- if (key.length <= 12) {
520
- return "****" + key.slice(-4);
526
+ function maskApiKey(key2) {
527
+ if (key2.length <= 12) {
528
+ return "****" + key2.slice(-4);
521
529
  }
522
- return key.slice(0, 4) + "..." + key.slice(-4);
530
+ return key2.slice(0, 4) + "..." + key2.slice(-4);
523
531
  }
524
532
  var CONFIG_FILE_NAMES, cachedConfig, AUTH_KEY_FILE, API_KEYS_FILE, PROVIDER_ENV_MAP, SUPPORTED_PROVIDERS;
525
533
  var init_config = __esm({
@@ -566,9 +574,9 @@ __export(remote_exports, {
566
574
  remoteToolExecutionQueries: () => remoteToolExecutionQueries,
567
575
  storageQueries: () => storageQueries
568
576
  });
569
- function initRemoteDatabase(serverUrl, key) {
577
+ function initRemoteDatabase(serverUrl, key2) {
570
578
  remoteServerUrl = serverUrl.replace(/\/$/, "");
571
- authKey = key;
579
+ authKey = key2;
572
580
  }
573
581
  function closeRemoteDatabase() {
574
582
  remoteServerUrl = null;
@@ -582,14 +590,14 @@ function parseDates(obj) {
582
590
  if (Array.isArray(obj)) return obj.map(parseDates);
583
591
  if (typeof obj !== "object" || obj instanceof Date) return obj;
584
592
  const result = { ...obj };
585
- for (const key of Object.keys(result)) {
586
- if (MODEL_MESSAGE_FIELDS.includes(key)) {
593
+ for (const key2 of Object.keys(result)) {
594
+ if (MODEL_MESSAGE_FIELDS.includes(key2)) {
587
595
  continue;
588
596
  }
589
- if (DATE_FIELDS.includes(key) && typeof result[key] === "string") {
590
- result[key] = new Date(result[key]);
591
- } else if (typeof result[key] === "object") {
592
- result[key] = parseDates(result[key]);
597
+ if (DATE_FIELDS.includes(key2) && typeof result[key2] === "string") {
598
+ result[key2] = new Date(result[key2]);
599
+ } else if (typeof result[key2] === "object") {
600
+ result[key2] = parseDates(result[key2]);
593
601
  }
594
602
  }
595
603
  return result;
@@ -1462,10 +1470,10 @@ function parseSkillFrontmatter(content) {
1462
1470
  }
1463
1471
  const colonIndex = line.indexOf(":");
1464
1472
  if (colonIndex > 0) {
1465
- const key = line.slice(0, colonIndex).trim();
1473
+ const key2 = line.slice(0, colonIndex).trim();
1466
1474
  let value = line.slice(colonIndex + 1).trim();
1467
1475
  if (value === "" || value === "[]") {
1468
- currentArrayKey = key;
1476
+ currentArrayKey = key2;
1469
1477
  currentArray = [];
1470
1478
  continue;
1471
1479
  }
@@ -1478,18 +1486,18 @@ function parseSkillFrontmatter(content) {
1478
1486
  }
1479
1487
  return trimmed;
1480
1488
  }).filter((item) => item.length > 0);
1481
- data[key] = items;
1489
+ data[key2] = items;
1482
1490
  continue;
1483
1491
  }
1484
1492
  if (value.startsWith('"') && value.endsWith('"') || value.startsWith("'") && value.endsWith("'")) {
1485
1493
  value = value.slice(1, -1);
1486
1494
  }
1487
1495
  if (value === "true") {
1488
- data[key] = true;
1496
+ data[key2] = true;
1489
1497
  } else if (value === "false") {
1490
- data[key] = false;
1498
+ data[key2] = false;
1491
1499
  } else {
1492
- data[key] = value;
1500
+ data[key2] = value;
1493
1501
  }
1494
1502
  }
1495
1503
  }
@@ -1821,9 +1829,9 @@ var init_chunker = __esm({
1821
1829
  });
1822
1830
 
1823
1831
  // src/semantic/client.ts
1824
- function initVectorClient(serverUrl, key) {
1832
+ function initVectorClient(serverUrl, key2) {
1825
1833
  remoteServerUrl2 = serverUrl.replace(/\/$/, "");
1826
- authKey2 = key;
1834
+ authKey2 = key2;
1827
1835
  }
1828
1836
  function isVectorClientConfigured() {
1829
1837
  return !!remoteServerUrl2 && !!authKey2;
@@ -2422,7 +2430,7 @@ import { promisify as promisify6 } from "util";
2422
2430
  import { writeFile as writeFile5, mkdir as mkdir4, readFile as readFile11, unlink as unlink2, readdir as readdir5, rm } from "fs/promises";
2423
2431
  import { join as join9 } from "path";
2424
2432
  import { tmpdir as tmpdir2 } from "os";
2425
- import { nanoid as nanoid4 } from "nanoid";
2433
+ import { nanoid as nanoid5 } from "nanoid";
2426
2434
  async function checkFfmpeg() {
2427
2435
  try {
2428
2436
  await execAsync6("ffmpeg -version", { timeout: 5e3 });
@@ -2477,7 +2485,7 @@ var init_recorder = __esm({
2477
2485
  */
2478
2486
  async encode() {
2479
2487
  if (this.frames.length === 0) return null;
2480
- const workDir = join9(tmpdir2(), `sparkecoder-recording-${nanoid4(8)}`);
2488
+ const workDir = join9(tmpdir2(), `sparkecoder-recording-${nanoid5(8)}`);
2481
2489
  await mkdir4(workDir, { recursive: true });
2482
2490
  try {
2483
2491
  for (let i = 0; i < this.frames.length; i++) {
@@ -2697,6 +2705,23 @@ function isAnthropicModel(modelId) {
2697
2705
  const normalized = modelId.trim().toLowerCase();
2698
2706
  return normalized.startsWith(ANTHROPIC_PREFIX) || normalized.startsWith("claude-");
2699
2707
  }
2708
+ function requiresAdaptiveThinking(modelId) {
2709
+ const m = modelId.toLowerCase().match(/claude-(?:opus|sonnet|haiku)-(\d+)[.-](\d{1,2})(?!\d)/);
2710
+ if (!m) return false;
2711
+ const major = Number(m[1]);
2712
+ const minor = Number(m[2]);
2713
+ if (Number.isNaN(major) || Number.isNaN(minor)) return false;
2714
+ if (major > 4) return true;
2715
+ if (major === 4 && minor >= 6) return true;
2716
+ return false;
2717
+ }
2718
+ function getAnthropicProviderOptions(modelId, opts = {}) {
2719
+ const { toolStreaming, budgetTokens = 1e4 } = opts;
2720
+ const thinking = requiresAdaptiveThinking(modelId) ? { type: "adaptive" } : { type: "enabled", budgetTokens };
2721
+ const out = { thinking };
2722
+ if (toolStreaming) out.toolStreaming = true;
2723
+ return out;
2724
+ }
2700
2725
  function resolveModel(modelId) {
2701
2726
  try {
2702
2727
  const config = getConfig();
@@ -2720,7 +2745,7 @@ var SUBAGENT_MODELS = {
2720
2745
  init_db();
2721
2746
  init_config();
2722
2747
  import { z as z15 } from "zod";
2723
- import { nanoid as nanoid5 } from "nanoid";
2748
+ import { nanoid as nanoid6 } from "nanoid";
2724
2749
 
2725
2750
  // src/tools/bash.ts
2726
2751
  import { tool } from "ai";
@@ -3070,11 +3095,11 @@ async function sendInput(terminalId, input, options = {}) {
3070
3095
  return false;
3071
3096
  }
3072
3097
  }
3073
- async function sendKey(terminalId, key) {
3098
+ async function sendKey(terminalId, key2) {
3074
3099
  const session = getSessionName(terminalId);
3075
3100
  try {
3076
3101
  await execAsync(`tmux has-session -t ${session}`, { timeout: 1e3 });
3077
- await execAsync(`tmux send-keys -t ${session} ${key}`, { timeout: 1e3 });
3102
+ await execAsync(`tmux send-keys -t ${session} ${key2}`, { timeout: 1e3 });
3078
3103
  return true;
3079
3104
  } catch {
3080
3105
  return false;
@@ -3213,7 +3238,7 @@ bash({ id: "abc123", input: "my text" }) // send text input
3213
3238
  Terminal output is stored in the global SparkECoder data directory. Use the \`tail\` option to read recent output.`,
3214
3239
  inputSchema: bashInputSchema,
3215
3240
  execute: async (inputArgs) => {
3216
- const { command, background, id, kill, tail, input: textInput, key } = inputArgs;
3241
+ const { command, background, id, kill, tail, input: textInput, key: key2 } = inputArgs;
3217
3242
  if (id) {
3218
3243
  if (kill) {
3219
3244
  const success = await killTerminal(id);
@@ -3244,8 +3269,8 @@ Terminal output is stored in the global SparkECoder data directory. Use the \`ta
3244
3269
  message: `Sent input "${textInput}" to terminal`
3245
3270
  };
3246
3271
  }
3247
- if (key) {
3248
- const success = await sendKey(id, key);
3272
+ if (key2) {
3273
+ const success = await sendKey(id, key2);
3249
3274
  if (!success) {
3250
3275
  return {
3251
3276
  success: false,
@@ -3261,7 +3286,7 @@ Terminal output is stored in the global SparkECoder data directory. Use the \`ta
3261
3286
  id,
3262
3287
  output: truncatedOutput2,
3263
3288
  status: status2,
3264
- message: `Sent key "${key}" to terminal`
3289
+ message: `Sent key "${key2}" to terminal`
3265
3290
  };
3266
3291
  }
3267
3292
  const { output, status } = await getLogs(id, options.workingDirectory, { tail, sessionId: options.sessionId });
@@ -3403,13 +3428,13 @@ async function resizeImageIfNeeded(buffer, mediaType) {
3403
3428
  const needsResize = longEdge > MAX_LONG_EDGE;
3404
3429
  const needsShrink = buffer.length > MAX_FILE_BYTES;
3405
3430
  if (!needsResize && !needsShrink) return { buffer, mediaType: inputMediaType };
3406
- const key = cacheKey(buffer);
3431
+ const key2 = cacheKey(buffer);
3407
3432
  const cacheDir = getCacheDir();
3408
3433
  const isPng = inputMediaType.includes("png");
3409
3434
  const willConvertToJpeg = isPng && (needsShrink || buffer.length > 2 * 1024 * 1024);
3410
3435
  const outputMediaType = willConvertToJpeg || !isPng ? "image/jpeg" : "image/png";
3411
3436
  const ext = outputMediaType === "image/png" ? ".png" : ".jpg";
3412
- const cachePath = join3(cacheDir, key + ext);
3437
+ const cachePath = join3(cacheDir, key2 + ext);
3413
3438
  if (existsSync3(cachePath)) {
3414
3439
  console.log(`[image-resize] Cache hit for ${width}x${height} image`);
3415
3440
  return { buffer: readFileSync2(cachePath), mediaType: outputMediaType };
@@ -4300,31 +4325,31 @@ async function getClientForFile(filePath) {
4300
4325
  return null;
4301
4326
  }
4302
4327
  const root = dirname4(normalized);
4303
- const key = `${serverDef.id}:${root}`;
4304
- const existing = state.clients.get(key);
4328
+ const key2 = `${serverDef.id}:${root}`;
4329
+ const existing = state.clients.get(key2);
4305
4330
  if (existing) {
4306
4331
  return existing;
4307
4332
  }
4308
- if (state.broken.has(key)) {
4333
+ if (state.broken.has(key2)) {
4309
4334
  return null;
4310
4335
  }
4311
4336
  try {
4312
4337
  const handle = await serverDef.spawn(root);
4313
4338
  if (!handle) {
4314
- state.broken.add(key);
4339
+ state.broken.add(key2);
4315
4340
  return null;
4316
4341
  }
4317
4342
  console.log(`[lsp] Started ${serverDef.name} for ${root}`);
4318
4343
  const client = await createClient(serverDef.id, handle, root);
4319
- state.clients.set(key, client);
4344
+ state.clients.set(key2, client);
4320
4345
  handle.process.on("exit", (code) => {
4321
4346
  console.log(`[lsp] ${serverDef.name} exited with code ${code}`);
4322
- state.clients.delete(key);
4347
+ state.clients.delete(key2);
4323
4348
  });
4324
4349
  return client;
4325
4350
  } catch (error) {
4326
4351
  console.error(`[lsp] Failed to start ${serverDef.name}:`, error);
4327
- state.broken.add(key);
4352
+ state.broken.add(key2);
4328
4353
  return null;
4329
4354
  }
4330
4355
  }
@@ -6056,6 +6081,7 @@ init_semantic_search();
6056
6081
  import { tool as tool11 } from "ai";
6057
6082
  import { z as z12 } from "zod";
6058
6083
  import Ajv from "ajv";
6084
+ import { nanoid as nanoid3 } from "nanoid";
6059
6085
  var ajv = new Ajv({ allErrors: true });
6060
6086
  function createCompleteTaskTool(options) {
6061
6087
  const validate = ajv.compile(options.outputSchema);
@@ -6102,6 +6128,37 @@ function createTaskFailedTool(options) {
6102
6128
  }
6103
6129
  });
6104
6130
  }
6131
+ function createAskQuestionToUserTool(options) {
6132
+ return tool11({
6133
+ description: "Ask the user a blocking clarification question when you cannot safely continue without more information. Use this only after trying to infer the answer from the available context. The task will pause until the orchestrator or user answers.",
6134
+ inputSchema: z12.object({
6135
+ question: z12.string().min(1).describe("The concise question you need answered."),
6136
+ context: z12.string().optional().describe("Brief context explaining why this answer is needed and what you already tried."),
6137
+ choices: z12.array(z12.string().min(1)).max(10).optional().describe("Optional suggested answer choices when the question is multiple choice.")
6138
+ }),
6139
+ execute: async (input) => {
6140
+ if (!options.onQuestion) {
6141
+ return {
6142
+ status: "unavailable",
6143
+ message: "Question routing is not configured for this task. Continue with the best safe assumption or call task_failed if blocked."
6144
+ };
6145
+ }
6146
+ const questionId = `q_${nanoid3(12)}`;
6147
+ const answer = await options.onQuestion({
6148
+ questionId,
6149
+ question: input.question,
6150
+ context: input.context,
6151
+ choices: input.choices
6152
+ });
6153
+ return {
6154
+ status: "answered",
6155
+ questionId,
6156
+ answer: answer.answer,
6157
+ answeredBy: answer.answeredBy ?? "unknown"
6158
+ };
6159
+ }
6160
+ });
6161
+ }
6105
6162
 
6106
6163
  // src/tools/upload-file.ts
6107
6164
  import { tool as tool12 } from "ai";
@@ -6207,7 +6264,7 @@ import { promisify as promisify5 } from "util";
6207
6264
  import { mkdirSync as mkdirSync5, existsSync as existsSync15, readFileSync as readFileSync7, unlinkSync as unlinkSync2 } from "fs";
6208
6265
  import { join as join8 } from "path";
6209
6266
  import { tmpdir } from "os";
6210
- import { nanoid as nanoid3 } from "nanoid";
6267
+ import { nanoid as nanoid4 } from "nanoid";
6211
6268
  var execAsync5 = promisify5(exec5);
6212
6269
  var DEFAULT_WIDTH = 1280;
6213
6270
  var DEFAULT_HEIGHT = 800;
@@ -6331,9 +6388,9 @@ async function runScroll(dx, dy) {
6331
6388
  { timeout: 5e3 }
6332
6389
  );
6333
6390
  }
6334
- function translateKeyForCliclick(key) {
6335
- if (!key) return [];
6336
- const parts = key.split("+").map((p) => p.trim()).filter(Boolean);
6391
+ function translateKeyForCliclick(key2) {
6392
+ if (!key2) return [];
6393
+ const parts = key2.split("+").map((p) => p.trim()).filter(Boolean);
6337
6394
  if (parts.length === 0) return [];
6338
6395
  const modMap = {
6339
6396
  ctrl: "ctrl",
@@ -6429,7 +6486,7 @@ function createComputerUseTool(options) {
6429
6486
  try {
6430
6487
  switch (input.action) {
6431
6488
  case "screenshot": {
6432
- const path = join8(tmpdir(), `cu-${nanoid3(8)}.png`);
6489
+ const path = join8(tmpdir(), `cu-${nanoid4(8)}.png`);
6433
6490
  await runScreencapture(path);
6434
6491
  const resized = await resizeScreenshotToPoints(path, displayWidth, displayHeight);
6435
6492
  try {
@@ -6560,7 +6617,7 @@ function createComputerUseTool(options) {
6560
6617
  case "zoom": {
6561
6618
  const region = input.region ?? [0, 0, displayWidth, displayHeight];
6562
6619
  const [x1, y1, x2, y2] = region;
6563
- const tmpPath = join8(tmpdir(), `cu-zoom-${nanoid3(8)}.png`);
6620
+ const tmpPath = join8(tmpdir(), `cu-zoom-${nanoid4(8)}.png`);
6564
6621
  await runScreencapture(tmpPath);
6565
6622
  const sharpModule = await import("sharp");
6566
6623
  const sharp2 = sharpModule.default || sharpModule;
@@ -6840,6 +6897,7 @@ async function createTools(options) {
6840
6897
  if (options.taskTools) {
6841
6898
  tools.complete_task = createCompleteTaskTool(options.taskTools);
6842
6899
  tools.task_failed = createTaskFailedTool(options.taskTools);
6900
+ tools.ask_question_to_user = createAskQuestionToUserTool(options.taskTools);
6843
6901
  }
6844
6902
  return tools;
6845
6903
  }
@@ -7247,9 +7305,10 @@ If you need to give the user a downloadable file (report, image, export, etc.),
7247
7305
  ### Rules
7248
7306
  1. Work independently \u2014 no human will approve tool calls. All tools run without approval.
7249
7307
  2. Keep working until the task is fully complete \u2014 and then VERIFY it is complete before finishing.
7250
- 3. When done, call the \`complete_task\` tool with a JSON result matching the output schema below.
7251
- 4. If you determine the task is impossible or encounter an unrecoverable error, call the \`task_failed\` tool with a clear reason.
7252
- 5. Do NOT stop without calling one of these two tools.
7308
+ 3. If you are blocked by missing information, call \`ask_question_to_user\` with a concise question. The run will pause until the orchestrator or user answers, then you should continue from that answer.
7309
+ 4. When done, call the \`complete_task\` tool with a JSON result matching the output schema below.
7310
+ 5. If you determine the task is impossible or encounter an unrecoverable error, call the \`task_failed\` tool with a clear reason.
7311
+ 6. Do NOT stop without calling \`complete_task\`, \`task_failed\`, or \`ask_question_to_user\` when blocked.
7253
7312
 
7254
7313
  ### Verification \u2014 BE EXTREMELY THOROUGH
7255
7314
  Before calling \`complete_task\`, you MUST verify your work completely. Do not just assume it worked. Actually check.
@@ -7320,6 +7379,7 @@ ${JSON.stringify(outputSchema, null, 2)}
7320
7379
  ### Completion Tools
7321
7380
  - **\`complete_task({ result: ... })\`** \u2014 Call ONLY after thorough verification. The result is validated against the schema above. If validation fails you will get errors back \u2014 fix and retry.
7322
7381
  - **\`task_failed({ reason: "..." })\`** \u2014 Call only if the task truly cannot be completed.
7382
+ - **\`ask_question_to_user({ question, context?, choices? })\`** \u2014 Call only when you need information that is not available in the repo, task prompt, files, logs, or tools. Ask one clear question; after the answer is returned, continue working.
7323
7383
  `;
7324
7384
  }
7325
7385
  function createSummaryPrompt(conversationHistory) {
@@ -7475,6 +7535,7 @@ function sanitizeModelMessages(messages) {
7475
7535
 
7476
7536
  // src/agent/model-limits.ts
7477
7537
  var MODEL_LIMITS = {
7538
+ "anthropic/claude-opus-4.7": { contextWindow: 2e5, rollingTarget: 15e4 },
7478
7539
  "anthropic/claude-opus-4-6": { contextWindow: 2e5, rollingTarget: 15e4 },
7479
7540
  "anthropic/claude-sonnet-4": { contextWindow: 2e5, rollingTarget: 15e4 },
7480
7541
  "anthropic/claude-3.5-sonnet": { contextWindow: 2e5, rollingTarget: 15e4 },
@@ -7811,17 +7872,65 @@ function repairToolPairing(messages) {
7811
7872
 
7812
7873
  // src/agent/index.ts
7813
7874
  init_webhook();
7875
+
7876
+ // src/tasks/questions.ts
7877
+ var pendingQuestions = /* @__PURE__ */ new Map();
7878
+ var answeredQuestions = /* @__PURE__ */ new Map();
7879
+ function key(taskId, questionId) {
7880
+ return `${taskId}:${questionId}`;
7881
+ }
7882
+ function waitForTaskQuestionAnswer(question) {
7883
+ const k = key(question.taskId, question.questionId);
7884
+ if (pendingQuestions.has(k)) {
7885
+ return Promise.reject(new Error(`Question already pending: ${question.questionId}`));
7886
+ }
7887
+ return new Promise((resolve11, reject) => {
7888
+ pendingQuestions.set(k, {
7889
+ ...question,
7890
+ createdAt: /* @__PURE__ */ new Date(),
7891
+ resolve: resolve11,
7892
+ reject
7893
+ });
7894
+ });
7895
+ }
7896
+ function answerTaskQuestion(taskId, questionId, answer) {
7897
+ const k = key(taskId, questionId);
7898
+ const pending = pendingQuestions.get(k);
7899
+ if (!pending) return answeredQuestions.has(k) ? "already_answered" : "not_found";
7900
+ pendingQuestions.delete(k);
7901
+ answeredQuestions.set(k, answer);
7902
+ pending.resolve(answer);
7903
+ return "answered";
7904
+ }
7905
+ function rejectTaskQuestions(taskId, reason) {
7906
+ for (const [k, pending] of pendingQuestions) {
7907
+ if (pending.taskId !== taskId) continue;
7908
+ pendingQuestions.delete(k);
7909
+ pending.reject(new Error(reason));
7910
+ }
7911
+ }
7912
+ function getPendingTaskQuestion(taskId, questionId) {
7913
+ const pending = pendingQuestions.get(key(taskId, questionId));
7914
+ if (!pending) return null;
7915
+ const { resolve: _resolve, reject: _reject, ...question } = pending;
7916
+ return question;
7917
+ }
7918
+ function getAnsweredTaskQuestion(taskId, questionId) {
7919
+ return answeredQuestions.get(key(taskId, questionId)) ?? null;
7920
+ }
7921
+
7922
+ // src/agent/index.ts
7814
7923
  var MAX_SSE_FIELD_LENGTH = 8 * 1024;
7815
7924
  var SSE_PREVIEW_LENGTH = 2 * 1024;
7816
7925
  function truncateWriteFileInput(input) {
7817
7926
  const out = { ...input };
7818
- for (const key of ["content", "old_string", "new_string"]) {
7819
- const val = out[key];
7927
+ for (const key2 of ["content", "old_string", "new_string"]) {
7928
+ const val = out[key2];
7820
7929
  if (typeof val === "string" && val.length > MAX_SSE_FIELD_LENGTH) {
7821
- out[key] = `${val.slice(0, SSE_PREVIEW_LENGTH)}
7930
+ out[key2] = `${val.slice(0, SSE_PREVIEW_LENGTH)}
7822
7931
  ... (truncated)`;
7823
- out[`${key}Truncated`] = true;
7824
- out[`${key}Length`] = val.length;
7932
+ out[`${key2}Truncated`] = true;
7933
+ out[`${key2}Length`] = val.length;
7825
7934
  }
7826
7935
  }
7827
7936
  return out;
@@ -7991,13 +8100,7 @@ ${prompt}` });
7991
8100
  abortSignal: options.abortSignal,
7992
8101
  // Enable extended thinking/reasoning for models that support it
7993
8102
  providerOptions: useAnthropic ? {
7994
- anthropic: {
7995
- toolStreaming: true,
7996
- thinking: {
7997
- type: "enabled",
7998
- budgetTokens: 1e4
7999
- }
8000
- }
8103
+ anthropic: getAnthropicProviderOptions(this.session.model, { toolStreaming: true })
8001
8104
  } : void 0,
8002
8105
  onStepFinish: async (step) => {
8003
8106
  options.onStepFinish?.(step);
@@ -8044,12 +8147,7 @@ ${prompt}` });
8044
8147
  stopWhen: stepCountIs2(500),
8045
8148
  // Enable extended thinking/reasoning for models that support it
8046
8149
  providerOptions: useAnthropic ? {
8047
- anthropic: {
8048
- thinking: {
8049
- type: "enabled",
8050
- budgetTokens: 1e4
8051
- }
8052
- }
8150
+ anthropic: getAnthropicProviderOptions(this.session.model)
8053
8151
  } : void 0
8054
8152
  });
8055
8153
  const responseMessages = result.response.messages;
@@ -8136,7 +8234,38 @@ ${prompt}` });
8136
8234
  },
8137
8235
  taskTools: {
8138
8236
  outputSchema: options.taskConfig.outputSchema,
8139
- onComplete
8237
+ onComplete,
8238
+ onQuestion: async (question) => {
8239
+ const payload = {
8240
+ questionId: question.questionId,
8241
+ question: question.question,
8242
+ context: question.context,
8243
+ choices: question.choices,
8244
+ status: "pending"
8245
+ };
8246
+ const answerPromise = waitForTaskQuestionAnswer({
8247
+ taskId: this.session.id,
8248
+ questionId: question.questionId,
8249
+ question: question.question,
8250
+ context: question.context,
8251
+ choices: question.choices
8252
+ });
8253
+ fireWebhook("task.question", payload);
8254
+ if (emit) {
8255
+ await emit(JSON.stringify({ type: "task-question", data: payload }));
8256
+ }
8257
+ const answer = await answerPromise;
8258
+ const answeredPayload = {
8259
+ questionId: question.questionId,
8260
+ answer: answer.answer,
8261
+ answeredBy: answer.answeredBy
8262
+ };
8263
+ fireWebhook("task.question_answered", answeredPayload);
8264
+ if (emit) {
8265
+ await emit(JSON.stringify({ type: "task-question-answered", data: answeredPayload }));
8266
+ }
8267
+ return answer;
8268
+ }
8140
8269
  }
8141
8270
  });
8142
8271
  const baseSystemPrompt = await buildSystemPrompt({
@@ -8181,10 +8310,7 @@ ${taskAddendum}`;
8181
8310
  stopWhen: stepCountIs2(500),
8182
8311
  abortSignal: options.abortSignal,
8183
8312
  providerOptions: useAnthropic ? {
8184
- anthropic: {
8185
- toolStreaming: true,
8186
- thinking: { type: "enabled", budgetTokens: 1e4 }
8187
- }
8313
+ anthropic: getAnthropicProviderOptions(this.session.model, { toolStreaming: true })
8188
8314
  } : void 0,
8189
8315
  onStepFinish: async (step) => {
8190
8316
  options.onStepFinish?.(step);
@@ -8471,7 +8597,7 @@ ${taskAddendum}`;
8471
8597
  description: originalTool.description || "",
8472
8598
  inputSchema: originalTool.inputSchema || z15.object({}),
8473
8599
  execute: async (input, toolOptions) => {
8474
- const toolCallId = toolOptions.toolCallId || nanoid5();
8600
+ const toolCallId = toolOptions.toolCallId || nanoid6();
8475
8601
  const execution = toolExecutionQueries.create({
8476
8602
  sessionId: this.session.id,
8477
8603
  toolName: name,
@@ -8598,7 +8724,7 @@ import { z as z16 } from "zod";
8598
8724
  import { existsSync as existsSync16, mkdirSync as mkdirSync6, writeFileSync as writeFileSync3, readdirSync as readdirSync2, statSync as statSync2, unlinkSync as unlinkSync3 } from "fs";
8599
8725
  import { readdir as readdir6 } from "fs/promises";
8600
8726
  import { join as join10, basename as basename5, extname as extname8, relative as relative9 } from "path";
8601
- import { nanoid as nanoid6 } from "nanoid";
8727
+ import { nanoid as nanoid7 } from "nanoid";
8602
8728
  init_config();
8603
8729
 
8604
8730
  // src/server/devtools-store.ts
@@ -9141,7 +9267,7 @@ sessions.post("/:id/attachments", async (c) => {
9141
9267
  return c.json({ error: "No file provided" }, 400);
9142
9268
  }
9143
9269
  const dir = ensureAttachmentsDir(sessionId);
9144
- const id = nanoid6(10);
9270
+ const id = nanoid7(10);
9145
9271
  const ext = extname8(file.name) || "";
9146
9272
  const safeFilename = `${id}_${basename5(file.name).replace(/[^a-zA-Z0-9._-]/g, "_")}`;
9147
9273
  const filePath = join10(dir, safeFilename);
@@ -9167,7 +9293,7 @@ sessions.post("/:id/attachments", async (c) => {
9167
9293
  return c.json({ error: "Missing filename or data" }, 400);
9168
9294
  }
9169
9295
  const dir = ensureAttachmentsDir(sessionId);
9170
- const id = nanoid6(10);
9296
+ const id = nanoid7(10);
9171
9297
  const ext = extname8(body.filename) || "";
9172
9298
  const safeFilename = `${id}_${basename5(body.filename).replace(/[^a-zA-Z0-9._-]/g, "_")}`;
9173
9299
  const filePath = join10(dir, safeFilename);
@@ -9459,9 +9585,9 @@ var store = /* @__PURE__ */ new Map();
9459
9585
  var channels = /* @__PURE__ */ new Map();
9460
9586
  var cleanupInterval = setInterval(() => {
9461
9587
  const now = Date.now();
9462
- for (const [key, data] of store.entries()) {
9588
+ for (const [key2, data] of store.entries()) {
9463
9589
  if (data.expiresAt && data.expiresAt < now) {
9464
- store.delete(key);
9590
+ store.delete(key2);
9465
9591
  }
9466
9592
  }
9467
9593
  }, 6e4);
@@ -9485,27 +9611,27 @@ var publisher = {
9485
9611
  }
9486
9612
  }
9487
9613
  },
9488
- set: async (key, value, options) => {
9614
+ set: async (key2, value, options) => {
9489
9615
  const expiresAt = options?.EX ? Date.now() + options.EX * 1e3 : void 0;
9490
- store.set(key, { value, expiresAt });
9616
+ store.set(key2, { value, expiresAt });
9491
9617
  if (options?.EX) {
9492
- setTimeout(() => store.delete(key), options.EX * 1e3);
9618
+ setTimeout(() => store.delete(key2), options.EX * 1e3);
9493
9619
  }
9494
9620
  },
9495
- get: async (key) => {
9496
- const data = store.get(key);
9621
+ get: async (key2) => {
9622
+ const data = store.get(key2);
9497
9623
  if (!data) return null;
9498
9624
  if (data.expiresAt && data.expiresAt < Date.now()) {
9499
- store.delete(key);
9625
+ store.delete(key2);
9500
9626
  return null;
9501
9627
  }
9502
9628
  return data.value;
9503
9629
  },
9504
- incr: async (key) => {
9505
- const data = store.get(key);
9630
+ incr: async (key2) => {
9631
+ const data = store.get(key2);
9506
9632
  const current = data ? parseInt(data.value, 10) : 0;
9507
9633
  const next = (isNaN(current) ? 0 : current) + 1;
9508
- store.set(key, { value: String(next), expiresAt: data?.expiresAt });
9634
+ store.set(key2, { value: String(next), expiresAt: data?.expiresAt });
9509
9635
  return next;
9510
9636
  }
9511
9637
  };
@@ -9537,7 +9663,7 @@ var streamContext = createResumableStreamContext({
9537
9663
  });
9538
9664
 
9539
9665
  // src/server/routes/agents.ts
9540
- import { nanoid as nanoid7 } from "nanoid";
9666
+ import { nanoid as nanoid8 } from "nanoid";
9541
9667
  init_stream_proxy();
9542
9668
  init_recorder();
9543
9669
  init_remote();
@@ -10096,7 +10222,7 @@ ${prompt}` });
10096
10222
  userMessageContent = prompt;
10097
10223
  }
10098
10224
  await messageQueries.create(id, { role: "user", content: userMessageContent });
10099
- const streamId = `stream_${id}_${nanoid7(10)}`;
10225
+ const streamId = `stream_${id}_${nanoid8(10)}`;
10100
10226
  console.log(`[STREAM] Creating stream ${streamId} for session ${id}`);
10101
10227
  await activeStreamQueries.create(id, streamId);
10102
10228
  const stream = await streamContext.resumableStream(
@@ -10301,7 +10427,7 @@ agents.post(
10301
10427
  });
10302
10428
  const session = agent.getSession();
10303
10429
  const enrichedPrompt = enrichPromptWithDevtoolsContext(session.id, body.prompt);
10304
- const streamId = `stream_${session.id}_${nanoid7(10)}`;
10430
+ const streamId = `stream_${session.id}_${nanoid8(10)}`;
10305
10431
  await createCheckpoint(session.id, session.workingDirectory, 0);
10306
10432
  await activeStreamQueries.create(session.id, streamId);
10307
10433
  const createQuickStreamProducer = () => {
@@ -10905,7 +11031,8 @@ health.get("/", async (c) => {
10905
11031
  const config = getConfig();
10906
11032
  const apiKeyStatus = getApiKeyStatus();
10907
11033
  const gatewayKey = apiKeyStatus.find((s) => s.provider === "ai-gateway");
10908
- const hasApiKey = gatewayKey?.configured ?? false;
11034
+ const remoteInference = isRemoteInferenceConfigured();
11035
+ const hasApiKey = remoteInference || (gatewayKey?.configured ?? false);
10909
11036
  let hwid;
10910
11037
  try {
10911
11038
  hwid = getHardwareIdCached();
@@ -10916,6 +11043,7 @@ health.get("/", async (c) => {
10916
11043
  version: currentVersion,
10917
11044
  uptime: process.uptime(),
10918
11045
  apiKeyConfigured: hasApiKey,
11046
+ inferenceMode: remoteInference ? "remote" : "local",
10919
11047
  hwid,
10920
11048
  config: {
10921
11049
  workingDirectory: config.resolvedWorkingDirectory,
@@ -11342,7 +11470,7 @@ init_db();
11342
11470
  import { Hono as Hono5 } from "hono";
11343
11471
  import { zValidator as zValidator5 } from "@hono/zod-validator";
11344
11472
  import { z as z20 } from "zod";
11345
- import { nanoid as nanoid8 } from "nanoid";
11473
+ import { nanoid as nanoid9 } from "nanoid";
11346
11474
  init_config();
11347
11475
  var tasks = new Hono5();
11348
11476
  var taskAbortControllers = /* @__PURE__ */ new Map();
@@ -11416,7 +11544,7 @@ tasks.post(
11416
11544
  const taskId = agent.sessionId;
11417
11545
  const abortController = new AbortController();
11418
11546
  taskAbortControllers.set(taskId, abortController);
11419
- const streamId = `stream_${taskId}_${nanoid8(10)}`;
11547
+ const streamId = `stream_${taskId}_${nanoid9(10)}`;
11420
11548
  await activeStreamQueries.create(taskId, streamId);
11421
11549
  const taskStreamProducer = () => {
11422
11550
  const { readable, writable } = new TransformStream();
@@ -11543,6 +11671,7 @@ tasks.post("/:id/cancel", async (c) => {
11543
11671
  abortController.abort();
11544
11672
  taskAbortControllers.delete(id);
11545
11673
  }
11674
+ rejectTaskQuestions(id, "Task cancelled by user");
11546
11675
  const cancelledTask = {
11547
11676
  ...task,
11548
11677
  status: "failed",
@@ -11564,6 +11693,52 @@ tasks.post("/:id/cancel", async (c) => {
11564
11693
  }
11565
11694
  return c.json({ taskId: id, status: "failed", error: "Task cancelled by user" });
11566
11695
  });
11696
+ var answerQuestionSchema = z20.object({
11697
+ answer: z20.string().min(1),
11698
+ answeredBy: z20.enum(["orchestrator", "user", "system"]).optional()
11699
+ });
11700
+ tasks.post(
11701
+ "/:id/questions/:questionId/answer",
11702
+ zValidator5("json", answerQuestionSchema),
11703
+ async (c) => {
11704
+ const id = c.req.param("id");
11705
+ const questionId = c.req.param("questionId");
11706
+ const body = c.req.valid("json");
11707
+ const session = await sessionQueries.getById(id);
11708
+ if (!session) {
11709
+ return c.json({ error: "Task not found" }, 404);
11710
+ }
11711
+ const task = session.config?.task;
11712
+ if (!task?.enabled) {
11713
+ return c.json({ error: "Session is not a task" }, 400);
11714
+ }
11715
+ const pending = getPendingTaskQuestion(id, questionId);
11716
+ if (!pending) {
11717
+ if (getAnsweredTaskQuestion(id, questionId)) {
11718
+ return c.json({
11719
+ taskId: id,
11720
+ questionId,
11721
+ status: "answered",
11722
+ alreadyAnswered: true
11723
+ });
11724
+ }
11725
+ return c.json({ error: "Question is not pending" }, 404);
11726
+ }
11727
+ const answerStatus = answerTaskQuestion(id, questionId, {
11728
+ answer: body.answer,
11729
+ answeredBy: body.answeredBy
11730
+ });
11731
+ if (answerStatus === "not_found") {
11732
+ return c.json({ error: "Question is not pending" }, 404);
11733
+ }
11734
+ return c.json({
11735
+ taskId: id,
11736
+ questionId,
11737
+ status: "answered",
11738
+ alreadyAnswered: answerStatus === "already_answered"
11739
+ });
11740
+ }
11741
+ );
11567
11742
  var tasks_default = tasks;
11568
11743
 
11569
11744
  // src/server/routes/system.ts
@@ -11657,15 +11832,15 @@ function loadPublicKey(input) {
11657
11832
  if (!input.includes("BEGIN") && existsSync18(input)) {
11658
11833
  pem = readFileSync11(input, "utf8");
11659
11834
  }
11660
- const key = createPublicKey({ key: pem, format: "pem" });
11661
- if (key.asymmetricKeyType !== "ed25519") {
11835
+ const key2 = createPublicKey({ key: pem, format: "pem" });
11836
+ if (key2.asymmetricKeyType !== "ed25519") {
11662
11837
  throw new Error(
11663
- `expected an ed25519 public key, got ${key.asymmetricKeyType}. Generate with personal-agents/scripts/generate-signing-keys.mjs.`
11838
+ `expected an ed25519 public key, got ${key2.asymmetricKeyType}. Generate with personal-agents/scripts/generate-signing-keys.mjs.`
11664
11839
  );
11665
11840
  }
11666
- _cachedKey = key;
11841
+ _cachedKey = key2;
11667
11842
  _cachedFromInput = input;
11668
- return key;
11843
+ return key2;
11669
11844
  }
11670
11845
  function bodyHashB64(body) {
11671
11846
  const hash = createHash3("sha256");