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
@@ -28,9 +28,9 @@ __export(remote_exports, {
28
28
  remoteToolExecutionQueries: () => remoteToolExecutionQueries,
29
29
  storageQueries: () => storageQueries
30
30
  });
31
- function initRemoteDatabase(serverUrl, key) {
31
+ function initRemoteDatabase(serverUrl, key2) {
32
32
  remoteServerUrl = serverUrl.replace(/\/$/, "");
33
- authKey = key;
33
+ authKey = key2;
34
34
  }
35
35
  function closeRemoteDatabase() {
36
36
  remoteServerUrl = null;
@@ -44,14 +44,14 @@ function parseDates(obj) {
44
44
  if (Array.isArray(obj)) return obj.map(parseDates);
45
45
  if (typeof obj !== "object" || obj instanceof Date) return obj;
46
46
  const result = { ...obj };
47
- for (const key of Object.keys(result)) {
48
- if (MODEL_MESSAGE_FIELDS.includes(key)) {
47
+ for (const key2 of Object.keys(result)) {
48
+ if (MODEL_MESSAGE_FIELDS.includes(key2)) {
49
49
  continue;
50
50
  }
51
- if (DATE_FIELDS.includes(key) && typeof result[key] === "string") {
52
- result[key] = new Date(result[key]);
53
- } else if (typeof result[key] === "object") {
54
- result[key] = parseDates(result[key]);
51
+ if (DATE_FIELDS.includes(key2) && typeof result[key2] === "string") {
52
+ result[key2] = new Date(result[key2]);
53
+ } else if (typeof result[key2] === "object") {
54
+ result[key2] = parseDates(result[key2]);
55
55
  }
56
56
  }
57
57
  return result;
@@ -596,7 +596,7 @@ var init_types = __esm({
596
596
  }).optional();
597
597
  SparkcoderConfigSchema = z.object({
598
598
  // Default model to use (Vercel AI Gateway format)
599
- defaultModel: z.string().default("anthropic/claude-opus-4-6"),
599
+ defaultModel: z.string().default("anthropic/claude-opus-4.7"),
600
600
  // Working directory for file operations
601
601
  workingDirectory: z.string().optional(),
602
602
  // Tool approval settings
@@ -955,6 +955,14 @@ function loadApiKeysIntoEnv() {
955
955
  }
956
956
  }
957
957
  }
958
+ function isRemoteInferenceConfigured() {
959
+ try {
960
+ const config = getConfig();
961
+ return config.resolvedRemoteServer.isConfigured;
962
+ } catch {
963
+ return false;
964
+ }
965
+ }
958
966
  function setApiKey(provider, apiKey) {
959
967
  const normalizedProvider = provider.toLowerCase();
960
968
  const envVar = PROVIDER_ENV_MAP[normalizedProvider];
@@ -1004,11 +1012,11 @@ function getApiKeyStatus() {
1004
1012
  };
1005
1013
  });
1006
1014
  }
1007
- function maskApiKey(key) {
1008
- if (key.length <= 12) {
1009
- return "****" + key.slice(-4);
1015
+ function maskApiKey(key2) {
1016
+ if (key2.length <= 12) {
1017
+ return "****" + key2.slice(-4);
1010
1018
  }
1011
- return key.slice(0, 4) + "..." + key.slice(-4);
1019
+ return key2.slice(0, 4) + "..." + key2.slice(-4);
1012
1020
  }
1013
1021
  var CONFIG_FILE_NAMES, cachedConfig, AUTH_KEY_FILE, API_KEYS_FILE, PROVIDER_ENV_MAP, SUPPORTED_PROVIDERS;
1014
1022
  var init_config = __esm({
@@ -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++) {
@@ -2544,7 +2552,7 @@ import { z as z16 } from "zod";
2544
2552
  import { existsSync as existsSync16, mkdirSync as mkdirSync6, writeFileSync as writeFileSync3, readdirSync as readdirSync2, statSync as statSync2, unlinkSync as unlinkSync3 } from "fs";
2545
2553
  import { readdir as readdir6 } from "fs/promises";
2546
2554
  import { join as join10, basename as basename5, extname as extname8, relative as relative9 } from "path";
2547
- import { nanoid as nanoid6 } from "nanoid";
2555
+ import { nanoid as nanoid7 } from "nanoid";
2548
2556
 
2549
2557
  // src/agent/index.ts
2550
2558
  import {
@@ -2719,6 +2727,23 @@ function isAnthropicModel(modelId) {
2719
2727
  const normalized = modelId.trim().toLowerCase();
2720
2728
  return normalized.startsWith(ANTHROPIC_PREFIX) || normalized.startsWith("claude-");
2721
2729
  }
2730
+ function requiresAdaptiveThinking(modelId) {
2731
+ const m = modelId.toLowerCase().match(/claude-(?:opus|sonnet|haiku)-(\d+)[.-](\d{1,2})(?!\d)/);
2732
+ if (!m) return false;
2733
+ const major = Number(m[1]);
2734
+ const minor = Number(m[2]);
2735
+ if (Number.isNaN(major) || Number.isNaN(minor)) return false;
2736
+ if (major > 4) return true;
2737
+ if (major === 4 && minor >= 6) return true;
2738
+ return false;
2739
+ }
2740
+ function getAnthropicProviderOptions(modelId, opts = {}) {
2741
+ const { toolStreaming, budgetTokens = 1e4 } = opts;
2742
+ const thinking = requiresAdaptiveThinking(modelId) ? { type: "adaptive" } : { type: "enabled", budgetTokens };
2743
+ const out = { thinking };
2744
+ if (toolStreaming) out.toolStreaming = true;
2745
+ return out;
2746
+ }
2722
2747
  function resolveModel(modelId) {
2723
2748
  try {
2724
2749
  const config = getConfig();
@@ -2742,7 +2767,7 @@ var SUBAGENT_MODELS = {
2742
2767
  init_db();
2743
2768
  init_config();
2744
2769
  import { z as z15 } from "zod";
2745
- import { nanoid as nanoid5 } from "nanoid";
2770
+ import { nanoid as nanoid6 } from "nanoid";
2746
2771
 
2747
2772
  // src/tools/bash.ts
2748
2773
  import { tool } from "ai";
@@ -3075,11 +3100,11 @@ async function sendInput(terminalId, input, options = {}) {
3075
3100
  return false;
3076
3101
  }
3077
3102
  }
3078
- async function sendKey(terminalId, key) {
3103
+ async function sendKey(terminalId, key2) {
3079
3104
  const session = getSessionName(terminalId);
3080
3105
  try {
3081
3106
  await execAsync(`tmux has-session -t ${session}`, { timeout: 1e3 });
3082
- await execAsync(`tmux send-keys -t ${session} ${key}`, { timeout: 1e3 });
3107
+ await execAsync(`tmux send-keys -t ${session} ${key2}`, { timeout: 1e3 });
3083
3108
  return true;
3084
3109
  } catch {
3085
3110
  return false;
@@ -3218,7 +3243,7 @@ bash({ id: "abc123", input: "my text" }) // send text input
3218
3243
  Terminal output is stored in the global SparkECoder data directory. Use the \`tail\` option to read recent output.`,
3219
3244
  inputSchema: bashInputSchema,
3220
3245
  execute: async (inputArgs) => {
3221
- const { command, background, id, kill, tail, input: textInput, key } = inputArgs;
3246
+ const { command, background, id, kill, tail, input: textInput, key: key2 } = inputArgs;
3222
3247
  if (id) {
3223
3248
  if (kill) {
3224
3249
  const success = await killTerminal(id);
@@ -3249,8 +3274,8 @@ Terminal output is stored in the global SparkECoder data directory. Use the \`ta
3249
3274
  message: `Sent input "${textInput}" to terminal`
3250
3275
  };
3251
3276
  }
3252
- if (key) {
3253
- const success = await sendKey(id, key);
3277
+ if (key2) {
3278
+ const success = await sendKey(id, key2);
3254
3279
  if (!success) {
3255
3280
  return {
3256
3281
  success: false,
@@ -3266,7 +3291,7 @@ Terminal output is stored in the global SparkECoder data directory. Use the \`ta
3266
3291
  id,
3267
3292
  output: truncatedOutput2,
3268
3293
  status: status2,
3269
- message: `Sent key "${key}" to terminal`
3294
+ message: `Sent key "${key2}" to terminal`
3270
3295
  };
3271
3296
  }
3272
3297
  const { output, status } = await getLogs(id, options.workingDirectory, { tail, sessionId: options.sessionId });
@@ -3408,13 +3433,13 @@ async function resizeImageIfNeeded(buffer, mediaType) {
3408
3433
  const needsResize = longEdge > MAX_LONG_EDGE;
3409
3434
  const needsShrink = buffer.length > MAX_FILE_BYTES;
3410
3435
  if (!needsResize && !needsShrink) return { buffer, mediaType: inputMediaType };
3411
- const key = cacheKey(buffer);
3436
+ const key2 = cacheKey(buffer);
3412
3437
  const cacheDir = getCacheDir();
3413
3438
  const isPng = inputMediaType.includes("png");
3414
3439
  const willConvertToJpeg = isPng && (needsShrink || buffer.length > 2 * 1024 * 1024);
3415
3440
  const outputMediaType = willConvertToJpeg || !isPng ? "image/jpeg" : "image/png";
3416
3441
  const ext = outputMediaType === "image/png" ? ".png" : ".jpg";
3417
- const cachePath = join3(cacheDir, key + ext);
3442
+ const cachePath = join3(cacheDir, key2 + ext);
3418
3443
  if (existsSync3(cachePath)) {
3419
3444
  console.log(`[image-resize] Cache hit for ${width}x${height} image`);
3420
3445
  return { buffer: readFileSync2(cachePath), mediaType: outputMediaType };
@@ -4305,31 +4330,31 @@ async function getClientForFile(filePath) {
4305
4330
  return null;
4306
4331
  }
4307
4332
  const root = dirname4(normalized);
4308
- const key = `${serverDef.id}:${root}`;
4309
- const existing = state.clients.get(key);
4333
+ const key2 = `${serverDef.id}:${root}`;
4334
+ const existing = state.clients.get(key2);
4310
4335
  if (existing) {
4311
4336
  return existing;
4312
4337
  }
4313
- if (state.broken.has(key)) {
4338
+ if (state.broken.has(key2)) {
4314
4339
  return null;
4315
4340
  }
4316
4341
  try {
4317
4342
  const handle = await serverDef.spawn(root);
4318
4343
  if (!handle) {
4319
- state.broken.add(key);
4344
+ state.broken.add(key2);
4320
4345
  return null;
4321
4346
  }
4322
4347
  console.log(`[lsp] Started ${serverDef.name} for ${root}`);
4323
4348
  const client = await createClient(serverDef.id, handle, root);
4324
- state.clients.set(key, client);
4349
+ state.clients.set(key2, client);
4325
4350
  handle.process.on("exit", (code) => {
4326
4351
  console.log(`[lsp] ${serverDef.name} exited with code ${code}`);
4327
- state.clients.delete(key);
4352
+ state.clients.delete(key2);
4328
4353
  });
4329
4354
  return client;
4330
4355
  } catch (error) {
4331
4356
  console.error(`[lsp] Failed to start ${serverDef.name}:`, error);
4332
- state.broken.add(key);
4357
+ state.broken.add(key2);
4333
4358
  return null;
4334
4359
  }
4335
4360
  }
@@ -6061,6 +6086,7 @@ init_semantic_search();
6061
6086
  import { tool as tool11 } from "ai";
6062
6087
  import { z as z12 } from "zod";
6063
6088
  import Ajv from "ajv";
6089
+ import { nanoid as nanoid3 } from "nanoid";
6064
6090
  var ajv = new Ajv({ allErrors: true });
6065
6091
  function createCompleteTaskTool(options) {
6066
6092
  const validate = ajv.compile(options.outputSchema);
@@ -6107,6 +6133,37 @@ function createTaskFailedTool(options) {
6107
6133
  }
6108
6134
  });
6109
6135
  }
6136
+ function createAskQuestionToUserTool(options) {
6137
+ return tool11({
6138
+ 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.",
6139
+ inputSchema: z12.object({
6140
+ question: z12.string().min(1).describe("The concise question you need answered."),
6141
+ context: z12.string().optional().describe("Brief context explaining why this answer is needed and what you already tried."),
6142
+ choices: z12.array(z12.string().min(1)).max(10).optional().describe("Optional suggested answer choices when the question is multiple choice.")
6143
+ }),
6144
+ execute: async (input) => {
6145
+ if (!options.onQuestion) {
6146
+ return {
6147
+ status: "unavailable",
6148
+ message: "Question routing is not configured for this task. Continue with the best safe assumption or call task_failed if blocked."
6149
+ };
6150
+ }
6151
+ const questionId = `q_${nanoid3(12)}`;
6152
+ const answer = await options.onQuestion({
6153
+ questionId,
6154
+ question: input.question,
6155
+ context: input.context,
6156
+ choices: input.choices
6157
+ });
6158
+ return {
6159
+ status: "answered",
6160
+ questionId,
6161
+ answer: answer.answer,
6162
+ answeredBy: answer.answeredBy ?? "unknown"
6163
+ };
6164
+ }
6165
+ });
6166
+ }
6110
6167
 
6111
6168
  // src/tools/upload-file.ts
6112
6169
  import { tool as tool12 } from "ai";
@@ -6212,7 +6269,7 @@ import { promisify as promisify5 } from "util";
6212
6269
  import { mkdirSync as mkdirSync5, existsSync as existsSync15, readFileSync as readFileSync7, unlinkSync as unlinkSync2 } from "fs";
6213
6270
  import { join as join8 } from "path";
6214
6271
  import { tmpdir } from "os";
6215
- import { nanoid as nanoid3 } from "nanoid";
6272
+ import { nanoid as nanoid4 } from "nanoid";
6216
6273
  var execAsync5 = promisify5(exec5);
6217
6274
  var DEFAULT_WIDTH = 1280;
6218
6275
  var DEFAULT_HEIGHT = 800;
@@ -6336,9 +6393,9 @@ async function runScroll(dx, dy) {
6336
6393
  { timeout: 5e3 }
6337
6394
  );
6338
6395
  }
6339
- function translateKeyForCliclick(key) {
6340
- if (!key) return [];
6341
- const parts = key.split("+").map((p) => p.trim()).filter(Boolean);
6396
+ function translateKeyForCliclick(key2) {
6397
+ if (!key2) return [];
6398
+ const parts = key2.split("+").map((p) => p.trim()).filter(Boolean);
6342
6399
  if (parts.length === 0) return [];
6343
6400
  const modMap = {
6344
6401
  ctrl: "ctrl",
@@ -6434,7 +6491,7 @@ function createComputerUseTool(options) {
6434
6491
  try {
6435
6492
  switch (input.action) {
6436
6493
  case "screenshot": {
6437
- const path = join8(tmpdir(), `cu-${nanoid3(8)}.png`);
6494
+ const path = join8(tmpdir(), `cu-${nanoid4(8)}.png`);
6438
6495
  await runScreencapture(path);
6439
6496
  const resized = await resizeScreenshotToPoints(path, displayWidth, displayHeight);
6440
6497
  try {
@@ -6565,7 +6622,7 @@ function createComputerUseTool(options) {
6565
6622
  case "zoom": {
6566
6623
  const region = input.region ?? [0, 0, displayWidth, displayHeight];
6567
6624
  const [x1, y1, x2, y2] = region;
6568
- const tmpPath = join8(tmpdir(), `cu-zoom-${nanoid3(8)}.png`);
6625
+ const tmpPath = join8(tmpdir(), `cu-zoom-${nanoid4(8)}.png`);
6569
6626
  await runScreencapture(tmpPath);
6570
6627
  const sharpModule = await import("sharp");
6571
6628
  const sharp2 = sharpModule.default || sharpModule;
@@ -6845,6 +6902,7 @@ async function createTools(options) {
6845
6902
  if (options.taskTools) {
6846
6903
  tools.complete_task = createCompleteTaskTool(options.taskTools);
6847
6904
  tools.task_failed = createTaskFailedTool(options.taskTools);
6905
+ tools.ask_question_to_user = createAskQuestionToUserTool(options.taskTools);
6848
6906
  }
6849
6907
  return tools;
6850
6908
  }
@@ -7252,9 +7310,10 @@ If you need to give the user a downloadable file (report, image, export, etc.),
7252
7310
  ### Rules
7253
7311
  1. Work independently \u2014 no human will approve tool calls. All tools run without approval.
7254
7312
  2. Keep working until the task is fully complete \u2014 and then VERIFY it is complete before finishing.
7255
- 3. When done, call the \`complete_task\` tool with a JSON result matching the output schema below.
7256
- 4. If you determine the task is impossible or encounter an unrecoverable error, call the \`task_failed\` tool with a clear reason.
7257
- 5. Do NOT stop without calling one of these two tools.
7313
+ 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.
7314
+ 4. When done, call the \`complete_task\` tool with a JSON result matching the output schema below.
7315
+ 5. If you determine the task is impossible or encounter an unrecoverable error, call the \`task_failed\` tool with a clear reason.
7316
+ 6. Do NOT stop without calling \`complete_task\`, \`task_failed\`, or \`ask_question_to_user\` when blocked.
7258
7317
 
7259
7318
  ### Verification \u2014 BE EXTREMELY THOROUGH
7260
7319
  Before calling \`complete_task\`, you MUST verify your work completely. Do not just assume it worked. Actually check.
@@ -7325,6 +7384,7 @@ ${JSON.stringify(outputSchema, null, 2)}
7325
7384
  ### Completion Tools
7326
7385
  - **\`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.
7327
7386
  - **\`task_failed({ reason: "..." })\`** \u2014 Call only if the task truly cannot be completed.
7387
+ - **\`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.
7328
7388
  `;
7329
7389
  }
7330
7390
  function createSummaryPrompt(conversationHistory) {
@@ -7480,6 +7540,7 @@ function sanitizeModelMessages(messages) {
7480
7540
 
7481
7541
  // src/agent/model-limits.ts
7482
7542
  var MODEL_LIMITS = {
7543
+ "anthropic/claude-opus-4.7": { contextWindow: 2e5, rollingTarget: 15e4 },
7483
7544
  "anthropic/claude-opus-4-6": { contextWindow: 2e5, rollingTarget: 15e4 },
7484
7545
  "anthropic/claude-sonnet-4": { contextWindow: 2e5, rollingTarget: 15e4 },
7485
7546
  "anthropic/claude-3.5-sonnet": { contextWindow: 2e5, rollingTarget: 15e4 },
@@ -7816,17 +7877,65 @@ function repairToolPairing(messages) {
7816
7877
 
7817
7878
  // src/agent/index.ts
7818
7879
  init_webhook();
7880
+
7881
+ // src/tasks/questions.ts
7882
+ var pendingQuestions = /* @__PURE__ */ new Map();
7883
+ var answeredQuestions = /* @__PURE__ */ new Map();
7884
+ function key(taskId, questionId) {
7885
+ return `${taskId}:${questionId}`;
7886
+ }
7887
+ function waitForTaskQuestionAnswer(question) {
7888
+ const k = key(question.taskId, question.questionId);
7889
+ if (pendingQuestions.has(k)) {
7890
+ return Promise.reject(new Error(`Question already pending: ${question.questionId}`));
7891
+ }
7892
+ return new Promise((resolve11, reject) => {
7893
+ pendingQuestions.set(k, {
7894
+ ...question,
7895
+ createdAt: /* @__PURE__ */ new Date(),
7896
+ resolve: resolve11,
7897
+ reject
7898
+ });
7899
+ });
7900
+ }
7901
+ function answerTaskQuestion(taskId, questionId, answer) {
7902
+ const k = key(taskId, questionId);
7903
+ const pending = pendingQuestions.get(k);
7904
+ if (!pending) return answeredQuestions.has(k) ? "already_answered" : "not_found";
7905
+ pendingQuestions.delete(k);
7906
+ answeredQuestions.set(k, answer);
7907
+ pending.resolve(answer);
7908
+ return "answered";
7909
+ }
7910
+ function rejectTaskQuestions(taskId, reason) {
7911
+ for (const [k, pending] of pendingQuestions) {
7912
+ if (pending.taskId !== taskId) continue;
7913
+ pendingQuestions.delete(k);
7914
+ pending.reject(new Error(reason));
7915
+ }
7916
+ }
7917
+ function getPendingTaskQuestion(taskId, questionId) {
7918
+ const pending = pendingQuestions.get(key(taskId, questionId));
7919
+ if (!pending) return null;
7920
+ const { resolve: _resolve, reject: _reject, ...question } = pending;
7921
+ return question;
7922
+ }
7923
+ function getAnsweredTaskQuestion(taskId, questionId) {
7924
+ return answeredQuestions.get(key(taskId, questionId)) ?? null;
7925
+ }
7926
+
7927
+ // src/agent/index.ts
7819
7928
  var MAX_SSE_FIELD_LENGTH = 8 * 1024;
7820
7929
  var SSE_PREVIEW_LENGTH = 2 * 1024;
7821
7930
  function truncateWriteFileInput(input) {
7822
7931
  const out = { ...input };
7823
- for (const key of ["content", "old_string", "new_string"]) {
7824
- const val = out[key];
7932
+ for (const key2 of ["content", "old_string", "new_string"]) {
7933
+ const val = out[key2];
7825
7934
  if (typeof val === "string" && val.length > MAX_SSE_FIELD_LENGTH) {
7826
- out[key] = `${val.slice(0, SSE_PREVIEW_LENGTH)}
7935
+ out[key2] = `${val.slice(0, SSE_PREVIEW_LENGTH)}
7827
7936
  ... (truncated)`;
7828
- out[`${key}Truncated`] = true;
7829
- out[`${key}Length`] = val.length;
7937
+ out[`${key2}Truncated`] = true;
7938
+ out[`${key2}Length`] = val.length;
7830
7939
  }
7831
7940
  }
7832
7941
  return out;
@@ -7996,13 +8105,7 @@ ${prompt}` });
7996
8105
  abortSignal: options.abortSignal,
7997
8106
  // Enable extended thinking/reasoning for models that support it
7998
8107
  providerOptions: useAnthropic ? {
7999
- anthropic: {
8000
- toolStreaming: true,
8001
- thinking: {
8002
- type: "enabled",
8003
- budgetTokens: 1e4
8004
- }
8005
- }
8108
+ anthropic: getAnthropicProviderOptions(this.session.model, { toolStreaming: true })
8006
8109
  } : void 0,
8007
8110
  onStepFinish: async (step) => {
8008
8111
  options.onStepFinish?.(step);
@@ -8049,12 +8152,7 @@ ${prompt}` });
8049
8152
  stopWhen: stepCountIs2(500),
8050
8153
  // Enable extended thinking/reasoning for models that support it
8051
8154
  providerOptions: useAnthropic ? {
8052
- anthropic: {
8053
- thinking: {
8054
- type: "enabled",
8055
- budgetTokens: 1e4
8056
- }
8057
- }
8155
+ anthropic: getAnthropicProviderOptions(this.session.model)
8058
8156
  } : void 0
8059
8157
  });
8060
8158
  const responseMessages = result.response.messages;
@@ -8141,7 +8239,38 @@ ${prompt}` });
8141
8239
  },
8142
8240
  taskTools: {
8143
8241
  outputSchema: options.taskConfig.outputSchema,
8144
- onComplete
8242
+ onComplete,
8243
+ onQuestion: async (question) => {
8244
+ const payload = {
8245
+ questionId: question.questionId,
8246
+ question: question.question,
8247
+ context: question.context,
8248
+ choices: question.choices,
8249
+ status: "pending"
8250
+ };
8251
+ const answerPromise = waitForTaskQuestionAnswer({
8252
+ taskId: this.session.id,
8253
+ questionId: question.questionId,
8254
+ question: question.question,
8255
+ context: question.context,
8256
+ choices: question.choices
8257
+ });
8258
+ fireWebhook("task.question", payload);
8259
+ if (emit) {
8260
+ await emit(JSON.stringify({ type: "task-question", data: payload }));
8261
+ }
8262
+ const answer = await answerPromise;
8263
+ const answeredPayload = {
8264
+ questionId: question.questionId,
8265
+ answer: answer.answer,
8266
+ answeredBy: answer.answeredBy
8267
+ };
8268
+ fireWebhook("task.question_answered", answeredPayload);
8269
+ if (emit) {
8270
+ await emit(JSON.stringify({ type: "task-question-answered", data: answeredPayload }));
8271
+ }
8272
+ return answer;
8273
+ }
8145
8274
  }
8146
8275
  });
8147
8276
  const baseSystemPrompt = await buildSystemPrompt({
@@ -8186,10 +8315,7 @@ ${taskAddendum}`;
8186
8315
  stopWhen: stepCountIs2(500),
8187
8316
  abortSignal: options.abortSignal,
8188
8317
  providerOptions: useAnthropic ? {
8189
- anthropic: {
8190
- toolStreaming: true,
8191
- thinking: { type: "enabled", budgetTokens: 1e4 }
8192
- }
8318
+ anthropic: getAnthropicProviderOptions(this.session.model, { toolStreaming: true })
8193
8319
  } : void 0,
8194
8320
  onStepFinish: async (step) => {
8195
8321
  options.onStepFinish?.(step);
@@ -8476,7 +8602,7 @@ ${taskAddendum}`;
8476
8602
  description: originalTool.description || "",
8477
8603
  inputSchema: originalTool.inputSchema || z15.object({}),
8478
8604
  execute: async (input, toolOptions) => {
8479
- const toolCallId = toolOptions.toolCallId || nanoid5();
8605
+ const toolCallId = toolOptions.toolCallId || nanoid6();
8480
8606
  const execution = toolExecutionQueries.create({
8481
8607
  sessionId: this.session.id,
8482
8608
  toolName: name,
@@ -9126,7 +9252,7 @@ sessions.post("/:id/attachments", async (c) => {
9126
9252
  return c.json({ error: "No file provided" }, 400);
9127
9253
  }
9128
9254
  const dir = ensureAttachmentsDir(sessionId);
9129
- const id = nanoid6(10);
9255
+ const id = nanoid7(10);
9130
9256
  const ext = extname8(file.name) || "";
9131
9257
  const safeFilename = `${id}_${basename5(file.name).replace(/[^a-zA-Z0-9._-]/g, "_")}`;
9132
9258
  const filePath = join10(dir, safeFilename);
@@ -9152,7 +9278,7 @@ sessions.post("/:id/attachments", async (c) => {
9152
9278
  return c.json({ error: "Missing filename or data" }, 400);
9153
9279
  }
9154
9280
  const dir = ensureAttachmentsDir(sessionId);
9155
- const id = nanoid6(10);
9281
+ const id = nanoid7(10);
9156
9282
  const ext = extname8(body.filename) || "";
9157
9283
  const safeFilename = `${id}_${basename5(body.filename).replace(/[^a-zA-Z0-9._-]/g, "_")}`;
9158
9284
  const filePath = join10(dir, safeFilename);
@@ -9444,9 +9570,9 @@ var store = /* @__PURE__ */ new Map();
9444
9570
  var channels = /* @__PURE__ */ new Map();
9445
9571
  var cleanupInterval = setInterval(() => {
9446
9572
  const now = Date.now();
9447
- for (const [key, data] of store.entries()) {
9573
+ for (const [key2, data] of store.entries()) {
9448
9574
  if (data.expiresAt && data.expiresAt < now) {
9449
- store.delete(key);
9575
+ store.delete(key2);
9450
9576
  }
9451
9577
  }
9452
9578
  }, 6e4);
@@ -9470,27 +9596,27 @@ var publisher = {
9470
9596
  }
9471
9597
  }
9472
9598
  },
9473
- set: async (key, value, options) => {
9599
+ set: async (key2, value, options) => {
9474
9600
  const expiresAt = options?.EX ? Date.now() + options.EX * 1e3 : void 0;
9475
- store.set(key, { value, expiresAt });
9601
+ store.set(key2, { value, expiresAt });
9476
9602
  if (options?.EX) {
9477
- setTimeout(() => store.delete(key), options.EX * 1e3);
9603
+ setTimeout(() => store.delete(key2), options.EX * 1e3);
9478
9604
  }
9479
9605
  },
9480
- get: async (key) => {
9481
- const data = store.get(key);
9606
+ get: async (key2) => {
9607
+ const data = store.get(key2);
9482
9608
  if (!data) return null;
9483
9609
  if (data.expiresAt && data.expiresAt < Date.now()) {
9484
- store.delete(key);
9610
+ store.delete(key2);
9485
9611
  return null;
9486
9612
  }
9487
9613
  return data.value;
9488
9614
  },
9489
- incr: async (key) => {
9490
- const data = store.get(key);
9615
+ incr: async (key2) => {
9616
+ const data = store.get(key2);
9491
9617
  const current = data ? parseInt(data.value, 10) : 0;
9492
9618
  const next = (isNaN(current) ? 0 : current) + 1;
9493
- store.set(key, { value: String(next), expiresAt: data?.expiresAt });
9619
+ store.set(key2, { value: String(next), expiresAt: data?.expiresAt });
9494
9620
  return next;
9495
9621
  }
9496
9622
  };
@@ -9522,7 +9648,7 @@ var streamContext = createResumableStreamContext({
9522
9648
  });
9523
9649
 
9524
9650
  // src/server/routes/agents.ts
9525
- import { nanoid as nanoid7 } from "nanoid";
9651
+ import { nanoid as nanoid8 } from "nanoid";
9526
9652
  init_stream_proxy();
9527
9653
  init_recorder();
9528
9654
  init_remote();
@@ -10081,7 +10207,7 @@ ${prompt}` });
10081
10207
  userMessageContent = prompt;
10082
10208
  }
10083
10209
  await messageQueries.create(id, { role: "user", content: userMessageContent });
10084
- const streamId = `stream_${id}_${nanoid7(10)}`;
10210
+ const streamId = `stream_${id}_${nanoid8(10)}`;
10085
10211
  console.log(`[STREAM] Creating stream ${streamId} for session ${id}`);
10086
10212
  await activeStreamQueries.create(id, streamId);
10087
10213
  const stream = await streamContext.resumableStream(
@@ -10286,7 +10412,7 @@ agents.post(
10286
10412
  });
10287
10413
  const session = agent.getSession();
10288
10414
  const enrichedPrompt = enrichPromptWithDevtoolsContext(session.id, body.prompt);
10289
- const streamId = `stream_${session.id}_${nanoid7(10)}`;
10415
+ const streamId = `stream_${session.id}_${nanoid8(10)}`;
10290
10416
  await createCheckpoint(session.id, session.workingDirectory, 0);
10291
10417
  await activeStreamQueries.create(session.id, streamId);
10292
10418
  const createQuickStreamProducer = () => {
@@ -10890,7 +11016,8 @@ health.get("/", async (c) => {
10890
11016
  const config = getConfig();
10891
11017
  const apiKeyStatus = getApiKeyStatus();
10892
11018
  const gatewayKey = apiKeyStatus.find((s) => s.provider === "ai-gateway");
10893
- const hasApiKey = gatewayKey?.configured ?? false;
11019
+ const remoteInference = isRemoteInferenceConfigured();
11020
+ const hasApiKey = remoteInference || (gatewayKey?.configured ?? false);
10894
11021
  let hwid;
10895
11022
  try {
10896
11023
  hwid = getHardwareIdCached();
@@ -10901,6 +11028,7 @@ health.get("/", async (c) => {
10901
11028
  version: currentVersion,
10902
11029
  uptime: process.uptime(),
10903
11030
  apiKeyConfigured: hasApiKey,
11031
+ inferenceMode: remoteInference ? "remote" : "local",
10904
11032
  hwid,
10905
11033
  config: {
10906
11034
  workingDirectory: config.resolvedWorkingDirectory,
@@ -11327,7 +11455,7 @@ init_db();
11327
11455
  import { Hono as Hono5 } from "hono";
11328
11456
  import { zValidator as zValidator5 } from "@hono/zod-validator";
11329
11457
  import { z as z20 } from "zod";
11330
- import { nanoid as nanoid8 } from "nanoid";
11458
+ import { nanoid as nanoid9 } from "nanoid";
11331
11459
  init_config();
11332
11460
  var tasks = new Hono5();
11333
11461
  var taskAbortControllers = /* @__PURE__ */ new Map();
@@ -11401,7 +11529,7 @@ tasks.post(
11401
11529
  const taskId = agent.sessionId;
11402
11530
  const abortController = new AbortController();
11403
11531
  taskAbortControllers.set(taskId, abortController);
11404
- const streamId = `stream_${taskId}_${nanoid8(10)}`;
11532
+ const streamId = `stream_${taskId}_${nanoid9(10)}`;
11405
11533
  await activeStreamQueries.create(taskId, streamId);
11406
11534
  const taskStreamProducer = () => {
11407
11535
  const { readable, writable } = new TransformStream();
@@ -11528,6 +11656,7 @@ tasks.post("/:id/cancel", async (c) => {
11528
11656
  abortController.abort();
11529
11657
  taskAbortControllers.delete(id);
11530
11658
  }
11659
+ rejectTaskQuestions(id, "Task cancelled by user");
11531
11660
  const cancelledTask = {
11532
11661
  ...task,
11533
11662
  status: "failed",
@@ -11549,6 +11678,52 @@ tasks.post("/:id/cancel", async (c) => {
11549
11678
  }
11550
11679
  return c.json({ taskId: id, status: "failed", error: "Task cancelled by user" });
11551
11680
  });
11681
+ var answerQuestionSchema = z20.object({
11682
+ answer: z20.string().min(1),
11683
+ answeredBy: z20.enum(["orchestrator", "user", "system"]).optional()
11684
+ });
11685
+ tasks.post(
11686
+ "/:id/questions/:questionId/answer",
11687
+ zValidator5("json", answerQuestionSchema),
11688
+ async (c) => {
11689
+ const id = c.req.param("id");
11690
+ const questionId = c.req.param("questionId");
11691
+ const body = c.req.valid("json");
11692
+ const session = await sessionQueries.getById(id);
11693
+ if (!session) {
11694
+ return c.json({ error: "Task not found" }, 404);
11695
+ }
11696
+ const task = session.config?.task;
11697
+ if (!task?.enabled) {
11698
+ return c.json({ error: "Session is not a task" }, 400);
11699
+ }
11700
+ const pending = getPendingTaskQuestion(id, questionId);
11701
+ if (!pending) {
11702
+ if (getAnsweredTaskQuestion(id, questionId)) {
11703
+ return c.json({
11704
+ taskId: id,
11705
+ questionId,
11706
+ status: "answered",
11707
+ alreadyAnswered: true
11708
+ });
11709
+ }
11710
+ return c.json({ error: "Question is not pending" }, 404);
11711
+ }
11712
+ const answerStatus = answerTaskQuestion(id, questionId, {
11713
+ answer: body.answer,
11714
+ answeredBy: body.answeredBy
11715
+ });
11716
+ if (answerStatus === "not_found") {
11717
+ return c.json({ error: "Question is not pending" }, 404);
11718
+ }
11719
+ return c.json({
11720
+ taskId: id,
11721
+ questionId,
11722
+ status: "answered",
11723
+ alreadyAnswered: answerStatus === "already_answered"
11724
+ });
11725
+ }
11726
+ );
11552
11727
  var tasks_default = tasks;
11553
11728
 
11554
11729
  // src/server/routes/system.ts
@@ -11642,15 +11817,15 @@ function loadPublicKey(input) {
11642
11817
  if (!input.includes("BEGIN") && existsSync18(input)) {
11643
11818
  pem = readFileSync11(input, "utf8");
11644
11819
  }
11645
- const key = createPublicKey({ key: pem, format: "pem" });
11646
- if (key.asymmetricKeyType !== "ed25519") {
11820
+ const key2 = createPublicKey({ key: pem, format: "pem" });
11821
+ if (key2.asymmetricKeyType !== "ed25519") {
11647
11822
  throw new Error(
11648
- `expected an ed25519 public key, got ${key.asymmetricKeyType}. Generate with personal-agents/scripts/generate-signing-keys.mjs.`
11823
+ `expected an ed25519 public key, got ${key2.asymmetricKeyType}. Generate with personal-agents/scripts/generate-signing-keys.mjs.`
11649
11824
  );
11650
11825
  }
11651
- _cachedKey = key;
11826
+ _cachedKey = key2;
11652
11827
  _cachedFromInput = input;
11653
- return key;
11828
+ return key2;
11654
11829
  }
11655
11830
  function bodyHashB64(body) {
11656
11831
  const hash = createHash3("sha256");