sparkecoder 0.1.60 → 0.1.61

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 (171) hide show
  1. package/dist/agent/index.d.ts +4 -3
  2. package/dist/agent/index.js +588 -176
  3. package/dist/agent/index.js.map +1 -1
  4. package/dist/cli.js +818 -95
  5. package/dist/cli.js.map +1 -1
  6. package/dist/db/index.d.ts +3 -2
  7. package/dist/db/index.js.map +1 -1
  8. package/dist/{index-Csad1Nx4.d.ts → index-DuGtMaAJ.d.ts} +85 -4
  9. package/dist/index.d.ts +6 -5
  10. package/dist/index.js +1202 -665
  11. package/dist/index.js.map +1 -1
  12. package/dist/schema-C7Mm4Ykn.d.ts +1410 -0
  13. package/dist/{search-BETuS1vh.d.ts → search-C_IFImt1.d.ts} +3 -3
  14. package/dist/server/index.js +605 -68
  15. package/dist/server/index.js.map +1 -1
  16. package/dist/tools/index.d.ts +38 -3
  17. package/dist/tools/index.js +230 -2
  18. package/dist/tools/index.js.map +1 -1
  19. package/package.json +5 -3
  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.js.nft.json +1 -1
  25. package/web/.next/standalone/web/.next/server/app/(main)/page_client-reference-manifest.js +1 -1
  26. package/web/.next/standalone/web/.next/server/app/(main)/session/[id]/page.js.nft.json +1 -1
  27. package/web/.next/standalone/web/.next/server/app/(main)/session/[id]/page_client-reference-manifest.js +1 -1
  28. package/web/.next/standalone/web/.next/server/app/_global-error.html +2 -2
  29. package/web/.next/standalone/web/.next/server/app/_global-error.rsc +1 -1
  30. package/web/.next/standalone/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  31. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  32. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  33. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  34. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  35. package/web/.next/standalone/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  36. package/web/.next/standalone/web/.next/server/app/_not-found.html +1 -1
  37. package/web/.next/standalone/web/.next/server/app/_not-found.rsc +2 -2
  38. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
  39. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  40. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
  41. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  42. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  43. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  44. package/web/.next/standalone/web/.next/server/app/api/config/route.js.nft.json +1 -1
  45. package/web/.next/standalone/web/.next/server/app/api/health/route.js.nft.json +1 -1
  46. package/web/.next/standalone/web/.next/server/app/docs/installation/page_client-reference-manifest.js +1 -1
  47. package/web/.next/standalone/web/.next/server/app/docs/installation.html +2 -2
  48. package/web/.next/standalone/web/.next/server/app/docs/installation.rsc +2 -2
  49. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_full.segment.rsc +2 -2
  50. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_head.segment.rsc +1 -1
  51. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_index.segment.rsc +2 -2
  52. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_tree.segment.rsc +2 -2
  53. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation/__PAGE__.segment.rsc +1 -1
  54. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation.segment.rsc +1 -1
  55. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs.segment.rsc +1 -1
  56. package/web/.next/standalone/web/.next/server/app/docs/page_client-reference-manifest.js +1 -1
  57. package/web/.next/standalone/web/.next/server/app/docs/skills/page_client-reference-manifest.js +1 -1
  58. package/web/.next/standalone/web/.next/server/app/docs/skills.html +2 -2
  59. package/web/.next/standalone/web/.next/server/app/docs/skills.rsc +2 -2
  60. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_full.segment.rsc +2 -2
  61. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_head.segment.rsc +1 -1
  62. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_index.segment.rsc +2 -2
  63. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_tree.segment.rsc +2 -2
  64. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills/__PAGE__.segment.rsc +1 -1
  65. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills.segment.rsc +1 -1
  66. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs.segment.rsc +1 -1
  67. package/web/.next/standalone/web/.next/server/app/docs/tools/page_client-reference-manifest.js +1 -1
  68. package/web/.next/standalone/web/.next/server/app/docs/tools.html +2 -2
  69. package/web/.next/standalone/web/.next/server/app/docs/tools.rsc +2 -2
  70. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_full.segment.rsc +2 -2
  71. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_head.segment.rsc +1 -1
  72. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_index.segment.rsc +2 -2
  73. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_tree.segment.rsc +2 -2
  74. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools/__PAGE__.segment.rsc +1 -1
  75. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools.segment.rsc +1 -1
  76. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs.segment.rsc +1 -1
  77. package/web/.next/standalone/web/.next/server/app/docs.html +2 -2
  78. package/web/.next/standalone/web/.next/server/app/docs.rsc +2 -2
  79. package/web/.next/standalone/web/.next/server/app/docs.segments/_full.segment.rsc +2 -2
  80. package/web/.next/standalone/web/.next/server/app/docs.segments/_head.segment.rsc +1 -1
  81. package/web/.next/standalone/web/.next/server/app/docs.segments/_index.segment.rsc +2 -2
  82. package/web/.next/standalone/web/.next/server/app/docs.segments/_tree.segment.rsc +2 -2
  83. package/web/.next/standalone/web/.next/server/app/docs.segments/docs/__PAGE__.segment.rsc +1 -1
  84. package/web/.next/standalone/web/.next/server/app/docs.segments/docs.segment.rsc +1 -1
  85. package/web/.next/standalone/web/.next/server/app/embed/[id]/page.js.nft.json +1 -1
  86. package/web/.next/standalone/web/.next/server/app/embed/[id]/page_client-reference-manifest.js +1 -1
  87. package/web/.next/standalone/web/.next/server/app/index.html +1 -1
  88. package/web/.next/standalone/web/.next/server/app/index.rsc +4 -4
  89. package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p/__PAGE__.segment.rsc +2 -2
  90. package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p.segment.rsc +2 -2
  91. package/web/.next/standalone/web/.next/server/app/index.segments/_full.segment.rsc +4 -4
  92. package/web/.next/standalone/web/.next/server/app/index.segments/_head.segment.rsc +1 -1
  93. package/web/.next/standalone/web/.next/server/app/index.segments/_index.segment.rsc +2 -2
  94. package/web/.next/standalone/web/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  95. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_19289e11._.js → 2374f_03d22c16._.js} +1 -1
  96. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_b4b86c1f._.js → 2374f_0d0b1fb9._.js} +1 -1
  97. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_4858a1ea._.js → 2374f_3f7d6d28._.js} +1 -1
  98. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_51385fed._.js → 2374f_6166d14d._.js} +1 -1
  99. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_40e35a02._.js → 2374f_67b9525f._.js} +1 -1
  100. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_fb95e3c9._.js → 2374f_6b436efc._.js} +1 -1
  101. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_2f0d9f6f._.js → 2374f_784d851c._.js} +1 -1
  102. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_35475cbe._.js → 2374f_976b2ded._.js} +1 -1
  103. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_7db22cde._.js → 2374f_98eba491._.js} +1 -1
  104. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_90b8e4fb._.js → 2374f_99b7b533._.js} +1 -1
  105. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_4666c827._.js → 2374f_a1a36483._.js} +1 -1
  106. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_076f03ec._.js → 2374f_b98835eb._.js} +1 -1
  107. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_b17fce11._.js → 2374f_e19eaecc._.js} +1 -1
  108. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_d8b9ce38._.js → 2374f_e3aec189._.js} +1 -1
  109. package/web/.next/standalone/web/.next/server/chunks/ssr/{[root-of-the-server]__7775f784._.js → [root-of-the-server]__4f176a16._.js} +2 -2
  110. package/web/.next/standalone/web/.next/server/chunks/ssr/[root-of-the-server]__d59f831d._.js +15 -0
  111. package/web/.next/standalone/web/.next/server/chunks/ssr/{web_645f4b90._.js → web_693f514e._.js} +2 -2
  112. package/web/.next/standalone/web/.next/server/chunks/ssr/web_a42a2651._.js +7 -0
  113. package/web/.next/standalone/web/.next/server/chunks/ssr/web_dc6ce793._.js +7 -0
  114. package/web/.next/standalone/web/.next/server/chunks/ssr/web_src_components_sessions-sidebar_tsx_92510070._.js +1 -1
  115. package/web/.next/standalone/web/.next/server/pages/404.html +1 -1
  116. package/web/.next/standalone/web/.next/server/pages/500.html +2 -2
  117. package/web/.next/standalone/web/.next/server/server-reference-manifest.js +1 -1
  118. package/web/.next/standalone/web/.next/server/server-reference-manifest.json +1 -1
  119. package/web/.next/standalone/web/.next/static/chunks/0358a0e7a40cfb93.css +1 -0
  120. package/web/.next/standalone/web/.next/static/chunks/1ecde4c0d426a635.js +1 -0
  121. package/web/.next/standalone/web/.next/static/chunks/20e0fa99c7a1c1fc.js +13 -0
  122. package/web/.next/standalone/web/.next/static/chunks/36688a049d72e8ab.js +5 -0
  123. package/web/.next/standalone/web/.next/static/chunks/95436454a7559b0d.js +7 -0
  124. package/web/.next/standalone/web/.next/static/chunks/a751ca474cc46212.js +5 -0
  125. package/web/.next/standalone/web/.next/static/static/chunks/0358a0e7a40cfb93.css +1 -0
  126. package/web/.next/standalone/web/.next/static/static/chunks/1ecde4c0d426a635.js +1 -0
  127. package/web/.next/standalone/web/.next/static/static/chunks/20e0fa99c7a1c1fc.js +13 -0
  128. package/web/.next/standalone/web/.next/static/static/chunks/36688a049d72e8ab.js +5 -0
  129. package/web/.next/standalone/web/.next/static/static/chunks/95436454a7559b0d.js +7 -0
  130. package/web/.next/standalone/web/.next/static/static/chunks/a751ca474cc46212.js +5 -0
  131. package/web/.next/standalone/web/src/components/ai-elements/complete-task-tool.tsx +126 -0
  132. package/web/.next/standalone/web/src/components/chat-interface.tsx +68 -3
  133. package/web/.next/standalone/web/src/components/sessions-sidebar.tsx +18 -1
  134. package/web/.next/standalone/web/src/lib/api.ts +12 -0
  135. package/web/.next/static/chunks/0358a0e7a40cfb93.css +1 -0
  136. package/web/.next/static/chunks/1ecde4c0d426a635.js +1 -0
  137. package/web/.next/static/chunks/20e0fa99c7a1c1fc.js +13 -0
  138. package/web/.next/static/chunks/36688a049d72e8ab.js +5 -0
  139. package/web/.next/static/chunks/95436454a7559b0d.js +7 -0
  140. package/web/.next/static/chunks/a751ca474cc46212.js +5 -0
  141. package/dist/schema-NcQknWCg.d.ts +0 -295
  142. package/web/.next/standalone/web/.next/server/chunks/ssr/[root-of-the-server]__bd396152._.js +0 -15
  143. package/web/.next/standalone/web/.next/server/chunks/ssr/web_9c9f0e3b._.js +0 -7
  144. package/web/.next/standalone/web/.next/server/chunks/ssr/web_d08270f7._.js +0 -7
  145. package/web/.next/standalone/web/.next/static/chunks/2868b007ce5163fc.css +0 -1
  146. package/web/.next/standalone/web/.next/static/chunks/3f295b6960943c38.js +0 -1
  147. package/web/.next/standalone/web/.next/static/chunks/631b023d37a08635.js +0 -13
  148. package/web/.next/standalone/web/.next/static/chunks/a2b4737b190d1b54.js +0 -5
  149. package/web/.next/standalone/web/.next/static/chunks/e97212fcc8221479.js +0 -5
  150. package/web/.next/standalone/web/.next/static/chunks/f6e47c8a9766ce91.js +0 -7
  151. package/web/.next/standalone/web/.next/static/static/chunks/2868b007ce5163fc.css +0 -1
  152. package/web/.next/standalone/web/.next/static/static/chunks/3f295b6960943c38.js +0 -1
  153. package/web/.next/standalone/web/.next/static/static/chunks/631b023d37a08635.js +0 -13
  154. package/web/.next/standalone/web/.next/static/static/chunks/a2b4737b190d1b54.js +0 -5
  155. package/web/.next/standalone/web/.next/static/static/chunks/e97212fcc8221479.js +0 -5
  156. package/web/.next/standalone/web/.next/static/static/chunks/f6e47c8a9766ce91.js +0 -7
  157. package/web/.next/static/chunks/2868b007ce5163fc.css +0 -1
  158. package/web/.next/static/chunks/3f295b6960943c38.js +0 -1
  159. package/web/.next/static/chunks/631b023d37a08635.js +0 -13
  160. package/web/.next/static/chunks/a2b4737b190d1b54.js +0 -5
  161. package/web/.next/static/chunks/e97212fcc8221479.js +0 -5
  162. package/web/.next/static/chunks/f6e47c8a9766ce91.js +0 -7
  163. /package/web/.next/standalone/web/.next/static/{R5xiWSOp_Nqqe_js-LROo → 8zJH-RqrUQ3scBGbdaCmn}/_buildManifest.js +0 -0
  164. /package/web/.next/standalone/web/.next/static/{R5xiWSOp_Nqqe_js-LROo → 8zJH-RqrUQ3scBGbdaCmn}/_clientMiddlewareManifest.json +0 -0
  165. /package/web/.next/standalone/web/.next/static/{R5xiWSOp_Nqqe_js-LROo → 8zJH-RqrUQ3scBGbdaCmn}/_ssgManifest.js +0 -0
  166. /package/web/.next/standalone/web/.next/static/static/{R5xiWSOp_Nqqe_js-LROo → 8zJH-RqrUQ3scBGbdaCmn}/_buildManifest.js +0 -0
  167. /package/web/.next/standalone/web/.next/static/static/{R5xiWSOp_Nqqe_js-LROo → 8zJH-RqrUQ3scBGbdaCmn}/_clientMiddlewareManifest.json +0 -0
  168. /package/web/.next/standalone/web/.next/static/static/{R5xiWSOp_Nqqe_js-LROo → 8zJH-RqrUQ3scBGbdaCmn}/_ssgManifest.js +0 -0
  169. /package/web/.next/static/{R5xiWSOp_Nqqe_js-LROo → 8zJH-RqrUQ3scBGbdaCmn}/_buildManifest.js +0 -0
  170. /package/web/.next/static/{R5xiWSOp_Nqqe_js-LROo → 8zJH-RqrUQ3scBGbdaCmn}/_clientMiddlewareManifest.json +0 -0
  171. /package/web/.next/static/{R5xiWSOp_Nqqe_js-LROo → 8zJH-RqrUQ3scBGbdaCmn}/_ssgManifest.js +0 -0
@@ -367,7 +367,7 @@ var init_db = __esm({
367
367
 
368
368
  // src/config/types.ts
369
369
  import { z } from "zod";
370
- var ToolApprovalConfigSchema, SkillMetadataSchema, SessionConfigSchema, VectorGatewayConfigSchema, RemoteServerConfigSchema, SparkcoderConfigSchema;
370
+ var ToolApprovalConfigSchema, SkillMetadataSchema, TaskConfigSchema, SessionConfigSchema, VectorGatewayConfigSchema, RemoteServerConfigSchema, SparkcoderConfigSchema;
371
371
  var init_types = __esm({
372
372
  "src/config/types.ts"() {
373
373
  "use strict";
@@ -386,11 +386,22 @@ var init_types = __esm({
386
386
  // Glob patterns - auto-inject when working with matching files
387
387
  globs: z.array(z.string()).optional().default([])
388
388
  });
389
+ TaskConfigSchema = z.object({
390
+ enabled: z.boolean(),
391
+ outputSchema: z.record(z.string(), z.unknown()),
392
+ webhookUrl: z.string().url().optional(),
393
+ maxIterations: z.number().optional(),
394
+ status: z.enum(["running", "completed", "failed"]),
395
+ result: z.unknown().optional(),
396
+ error: z.string().optional(),
397
+ iterations: z.number().optional()
398
+ });
389
399
  SessionConfigSchema = z.object({
390
400
  toolApprovals: z.record(z.string(), z.boolean()).optional(),
391
401
  approvalWebhook: z.string().url().optional(),
392
402
  skillsDirectory: z.string().optional(),
393
- maxContextChars: z.number().optional().default(2e5)
403
+ maxContextChars: z.number().optional().default(2e5),
404
+ task: TaskConfigSchema.optional()
394
405
  });
395
406
  VectorGatewayConfigSchema = z.object({
396
407
  // Redis cluster nodes URL for Vector Gateway (or use REDIS_CLUSTER_NODES env var)
@@ -698,6 +709,9 @@ function getConfig() {
698
709
  }
699
710
  function requiresApproval(toolName, sessionConfig) {
700
711
  const config = getConfig();
712
+ if (sessionConfig?.toolApprovals?.["*"] !== void 0) {
713
+ return sessionConfig.toolApprovals["*"];
714
+ }
701
715
  if (sessionConfig?.toolApprovals?.[toolName] !== void 0) {
702
716
  return sessionConfig.toolApprovals[toolName];
703
717
  }
@@ -1605,7 +1619,7 @@ var init_semantic_search = __esm({
1605
1619
 
1606
1620
  // src/server/index.ts
1607
1621
  import "dotenv/config";
1608
- import { Hono as Hono5 } from "hono";
1622
+ import { Hono as Hono6 } from "hono";
1609
1623
  import { serve } from "@hono/node-server";
1610
1624
  import { cors } from "hono/cors";
1611
1625
  import { logger } from "hono/logger";
@@ -1619,7 +1633,7 @@ import { fileURLToPath as fileURLToPath4 } from "url";
1619
1633
  init_db();
1620
1634
  import { Hono } from "hono";
1621
1635
  import { zValidator } from "@hono/zod-validator";
1622
- import { z as z13 } from "zod";
1636
+ import { z as z14 } from "zod";
1623
1637
  import { existsSync as existsSync13, mkdirSync as mkdirSync3, writeFileSync as writeFileSync2, readdirSync, statSync as statSync2, unlinkSync } from "fs";
1624
1638
  import { readdir as readdir5 } from "fs/promises";
1625
1639
  import { join as join5, basename as basename4, extname as extname7, relative as relative9 } from "path";
@@ -1629,18 +1643,176 @@ import { nanoid as nanoid4 } from "nanoid";
1629
1643
  import {
1630
1644
  streamText as streamText2,
1631
1645
  generateText as generateText3,
1632
- tool as tool11,
1646
+ tool as tool12,
1633
1647
  stepCountIs as stepCountIs2
1634
1648
  } from "ai";
1635
1649
 
1636
1650
  // src/agent/model.ts
1637
1651
  import { gateway } from "@ai-sdk/gateway";
1652
+
1653
+ // src/agent/remote-model.ts
1654
+ function serializePrompt(prompt) {
1655
+ return prompt.map((msg) => {
1656
+ if (!Array.isArray(msg.content)) return msg;
1657
+ return {
1658
+ ...msg,
1659
+ content: msg.content.map((part) => {
1660
+ if (part.type === "file" && part.data instanceof Uint8Array) {
1661
+ return {
1662
+ ...part,
1663
+ data: Buffer.from(part.data).toString("base64"),
1664
+ _base64: true
1665
+ };
1666
+ }
1667
+ return part;
1668
+ })
1669
+ };
1670
+ });
1671
+ }
1672
+ function deserializeValue(value) {
1673
+ if (value && typeof value === "object") {
1674
+ if (value.__uint8array && typeof value.data === "string") {
1675
+ return Buffer.from(value.data, "base64");
1676
+ }
1677
+ if (Array.isArray(value)) {
1678
+ return value.map(deserializeValue);
1679
+ }
1680
+ const result = {};
1681
+ for (const [k, v] of Object.entries(value)) {
1682
+ result[k] = deserializeValue(v);
1683
+ }
1684
+ return result;
1685
+ }
1686
+ return value;
1687
+ }
1688
+ function prepareOptions(options) {
1689
+ const { abortSignal, ...rest } = options;
1690
+ return {
1691
+ ...rest,
1692
+ prompt: serializePrompt(options.prompt)
1693
+ };
1694
+ }
1695
+ function createRemoteModel(modelId, config) {
1696
+ const baseUrl = config.url.replace(/\/$/, "");
1697
+ const headers = {
1698
+ "Content-Type": "application/json",
1699
+ "Authorization": `Bearer ${config.authKey}`
1700
+ };
1701
+ return {
1702
+ specificationVersion: "v3",
1703
+ provider: "remote-proxy",
1704
+ modelId,
1705
+ supportedUrls: {},
1706
+ async doGenerate(options) {
1707
+ const res = await fetch(`${baseUrl}/inference/generate`, {
1708
+ method: "POST",
1709
+ headers,
1710
+ body: JSON.stringify({
1711
+ modelId,
1712
+ options: prepareOptions(options)
1713
+ }),
1714
+ signal: options.abortSignal
1715
+ });
1716
+ if (!res.ok) {
1717
+ const err = await res.json().catch(() => ({}));
1718
+ throw new Error(
1719
+ `Remote inference failed (${res.status}): ${err.error || res.statusText}`
1720
+ );
1721
+ }
1722
+ const result = await res.json();
1723
+ return deserializeValue(result);
1724
+ },
1725
+ async doStream(options) {
1726
+ const res = await fetch(`${baseUrl}/inference/stream`, {
1727
+ method: "POST",
1728
+ headers,
1729
+ body: JSON.stringify({
1730
+ modelId,
1731
+ options: prepareOptions(options)
1732
+ }),
1733
+ signal: options.abortSignal
1734
+ });
1735
+ if (!res.ok) {
1736
+ const err = await res.json().catch(() => ({}));
1737
+ throw new Error(
1738
+ `Remote inference failed (${res.status}): ${err.error || res.statusText}`
1739
+ );
1740
+ }
1741
+ const reader = res.body.getReader();
1742
+ const decoder = new TextDecoder();
1743
+ let buffer = "";
1744
+ const stream = new ReadableStream({
1745
+ async pull(controller) {
1746
+ while (true) {
1747
+ const { done, value } = await reader.read();
1748
+ if (done) {
1749
+ if (buffer.trim()) {
1750
+ try {
1751
+ const parsed = deserializeValue(JSON.parse(buffer.trim()));
1752
+ if (parsed.type === "error") {
1753
+ controller.error(new Error(parsed.error));
1754
+ } else {
1755
+ controller.enqueue(parsed);
1756
+ }
1757
+ } catch {
1758
+ }
1759
+ }
1760
+ controller.close();
1761
+ return;
1762
+ }
1763
+ buffer += decoder.decode(value, { stream: true });
1764
+ const lines = buffer.split("\n");
1765
+ buffer = lines.pop() || "";
1766
+ for (const line of lines) {
1767
+ if (!line.trim()) continue;
1768
+ try {
1769
+ const parsed = deserializeValue(JSON.parse(line));
1770
+ if (parsed.type === "error") {
1771
+ controller.error(new Error(parsed.error));
1772
+ return;
1773
+ }
1774
+ controller.enqueue(parsed);
1775
+ } catch {
1776
+ }
1777
+ }
1778
+ }
1779
+ },
1780
+ cancel() {
1781
+ reader.cancel();
1782
+ }
1783
+ });
1784
+ const responseHeaders = {};
1785
+ res.headers.forEach((v, k) => {
1786
+ if (k.startsWith("x-upstream-")) {
1787
+ responseHeaders[k.replace("x-upstream-", "")] = v;
1788
+ }
1789
+ });
1790
+ return {
1791
+ stream,
1792
+ response: Object.keys(responseHeaders).length > 0 ? { headers: responseHeaders } : void 0
1793
+ };
1794
+ }
1795
+ };
1796
+ }
1797
+
1798
+ // src/agent/model.ts
1799
+ init_config();
1638
1800
  var ANTHROPIC_PREFIX = "anthropic/";
1639
1801
  function isAnthropicModel(modelId) {
1640
1802
  const normalized = modelId.trim().toLowerCase();
1641
1803
  return normalized.startsWith(ANTHROPIC_PREFIX) || normalized.startsWith("claude-");
1642
1804
  }
1643
1805
  function resolveModel(modelId) {
1806
+ try {
1807
+ const config = getConfig();
1808
+ if (config.resolvedRemoteServer.isConfigured) {
1809
+ return createRemoteModel(modelId.trim(), {
1810
+ url: config.resolvedRemoteServer.url,
1811
+ authKey: config.resolvedRemoteServer.authKey
1812
+ });
1813
+ }
1814
+ } catch {
1815
+ }
1644
1816
  return gateway(modelId.trim());
1645
1817
  }
1646
1818
  var SUBAGENT_MODELS = {
@@ -1652,7 +1824,7 @@ var SUBAGENT_MODELS = {
1652
1824
  // src/agent/index.ts
1653
1825
  init_db();
1654
1826
  init_config();
1655
- import { z as z12 } from "zod";
1827
+ import { z as z13 } from "zod";
1656
1828
  import { nanoid as nanoid3 } from "nanoid";
1657
1829
 
1658
1830
  // src/tools/bash.ts
@@ -4962,6 +5134,59 @@ Context: ${context}` : query;
4962
5134
 
4963
5135
  // src/tools/index.ts
4964
5136
  init_semantic_search();
5137
+
5138
+ // src/tools/task.ts
5139
+ import { tool as tool11 } from "ai";
5140
+ import { z as z12 } from "zod";
5141
+ import Ajv from "ajv";
5142
+ var ajv = new Ajv({ allErrors: true });
5143
+ function createCompleteTaskTool(options) {
5144
+ const validate = ajv.compile(options.outputSchema);
5145
+ return tool11({
5146
+ description: "Call this tool when you have completed the task. Pass the result as a JSON object matching the required output schema. If the result does not match the schema, you will receive validation errors and should fix and retry.",
5147
+ inputSchema: z12.object({
5148
+ result: z12.record(z12.string(), z12.unknown()).describe("The task result as a JSON object matching the output schema")
5149
+ }),
5150
+ execute: async (input) => {
5151
+ const valid = validate(input.result);
5152
+ if (!valid) {
5153
+ const errors = validate.errors?.map((e) => ({
5154
+ path: e.instancePath || "/",
5155
+ message: e.message,
5156
+ params: e.params
5157
+ }));
5158
+ return {
5159
+ status: "validation_error",
5160
+ message: "The result does not match the required output schema. Fix the errors and call complete_task again.",
5161
+ errors,
5162
+ expectedSchema: options.outputSchema
5163
+ };
5164
+ }
5165
+ options.onComplete({ status: "completed", result: input.result });
5166
+ return {
5167
+ status: "completed",
5168
+ message: "Task completed successfully."
5169
+ };
5170
+ }
5171
+ });
5172
+ }
5173
+ function createTaskFailedTool(options) {
5174
+ return tool11({
5175
+ description: "Call this tool if you are unable to complete the task. Provide a clear reason explaining why the task cannot be completed.",
5176
+ inputSchema: z12.object({
5177
+ reason: z12.string().describe("Explanation of why the task cannot be completed")
5178
+ }),
5179
+ execute: async (input) => {
5180
+ options.onComplete({ status: "failed", error: input.reason });
5181
+ return {
5182
+ status: "failed",
5183
+ message: `Task marked as failed: ${input.reason}`
5184
+ };
5185
+ }
5186
+ });
5187
+ }
5188
+
5189
+ // src/tools/index.ts
4965
5190
  init_semantic();
4966
5191
  init_semantic_search();
4967
5192
  async function createTools(options) {
@@ -5013,6 +5238,10 @@ async function createTools(options) {
5013
5238
  } catch {
5014
5239
  }
5015
5240
  }
5241
+ if (options.taskTools) {
5242
+ tools.complete_task = createCompleteTaskTool(options.taskTools);
5243
+ tools.task_failed = createTaskFailedTool(options.taskTools);
5244
+ }
5016
5245
  return tools;
5017
5246
  }
5018
5247
 
@@ -5330,6 +5559,30 @@ function formatTodosForContext(todos) {
5330
5559
  }
5331
5560
  return lines.join("\n");
5332
5561
  }
5562
+ function buildTaskPromptAddendum(outputSchema) {
5563
+ return `
5564
+ ## Task Mode
5565
+
5566
+ You are running in **task mode**. You have been given a specific task to complete autonomously.
5567
+
5568
+ ### Rules
5569
+ 1. Work independently \u2014 no human will approve tool calls. All tools run without approval.
5570
+ 2. Keep working until the task is fully complete.
5571
+ 3. When done, call the \`complete_task\` tool with a JSON result matching the output schema below.
5572
+ 4. If you determine the task is impossible or encounter an unrecoverable error, call the \`task_failed\` tool with a clear reason.
5573
+ 5. Do NOT stop without calling one of these two tools.
5574
+
5575
+ ### Output Schema
5576
+ The \`complete_task\` tool expects a \`result\` object matching this JSON Schema:
5577
+ \`\`\`json
5578
+ ${JSON.stringify(outputSchema, null, 2)}
5579
+ \`\`\`
5580
+
5581
+ ### Completion Tools
5582
+ - **\`complete_task({ result: ... })\`** \u2014 Call when the task is done. The result is validated against the schema above. If validation fails you will get errors back \u2014 fix and retry.
5583
+ - **\`task_failed({ reason: "..." })\`** \u2014 Call only if the task truly cannot be completed.
5584
+ `;
5585
+ }
5333
5586
  function createSummaryPrompt(conversationHistory) {
5334
5587
  return `Please provide a concise summary of the following conversation history. Focus on:
5335
5588
  1. The main task or goal being worked on
@@ -5591,6 +5844,25 @@ ${this.summary}`
5591
5844
  }
5592
5845
  };
5593
5846
 
5847
+ // src/utils/webhook.ts
5848
+ async function sendWebhook(url, event) {
5849
+ try {
5850
+ const controller = new AbortController();
5851
+ const timeout = setTimeout(() => controller.abort(), 5e3);
5852
+ await fetch(url, {
5853
+ method: "POST",
5854
+ headers: {
5855
+ "Content-Type": "application/json",
5856
+ "X-SparkECoder-Event": event.type
5857
+ },
5858
+ body: JSON.stringify(event),
5859
+ signal: controller.signal
5860
+ });
5861
+ clearTimeout(timeout);
5862
+ } catch {
5863
+ }
5864
+ }
5865
+
5594
5866
  // src/agent/index.ts
5595
5867
  var approvalResolvers = /* @__PURE__ */ new Map();
5596
5868
  var Agent = class _Agent {
@@ -5810,6 +6082,145 @@ ${prompt}` });
5810
6082
  steps: result.steps
5811
6083
  };
5812
6084
  }
6085
+ /**
6086
+ * Run the agent in task mode — loops autonomously until the agent calls
6087
+ * complete_task or task_failed (or hits maxIterations).
6088
+ * All tools run without approval. Webhook events are fired throughout.
6089
+ */
6090
+ async runTask(options) {
6091
+ const config = getConfig();
6092
+ const maxIterations = options.taskConfig.maxIterations ?? 50;
6093
+ const webhookUrl = options.taskConfig.webhookUrl;
6094
+ const fireWebhook = (type, data) => {
6095
+ if (!webhookUrl) return;
6096
+ sendWebhook(webhookUrl, {
6097
+ type,
6098
+ taskId: this.session.id,
6099
+ sessionId: this.session.id,
6100
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
6101
+ data
6102
+ });
6103
+ };
6104
+ const completion = { signal: null };
6105
+ const onComplete = (signal) => {
6106
+ completion.signal = signal;
6107
+ };
6108
+ const taskTools = await createTools({
6109
+ sessionId: this.session.id,
6110
+ workingDirectory: this.session.workingDirectory,
6111
+ skillsDirectories: config.resolvedSkillsDirectories,
6112
+ onBashProgress: options.onToolProgress ? (progress) => options.onToolProgress({ toolName: "bash", data: progress }) : void 0,
6113
+ onWriteFileProgress: options.onToolProgress ? (progress) => options.onToolProgress({ toolName: "write_file", data: progress }) : void 0,
6114
+ onSearchProgress: options.onToolProgress ? (progress) => options.onToolProgress({ toolName: "explore_agent", data: progress }) : void 0,
6115
+ taskTools: {
6116
+ outputSchema: options.taskConfig.outputSchema,
6117
+ onComplete
6118
+ }
6119
+ });
6120
+ const baseSystemPrompt = await buildSystemPrompt({
6121
+ workingDirectory: this.session.workingDirectory,
6122
+ skillsDirectories: config.resolvedSkillsDirectories,
6123
+ sessionId: this.session.id,
6124
+ discoveredSkills: config.discoveredSkills,
6125
+ activeFiles: []
6126
+ });
6127
+ const taskAddendum = buildTaskPromptAddendum(options.taskConfig.outputSchema);
6128
+ const systemPrompt = `${baseSystemPrompt}
6129
+
6130
+ ${taskAddendum}`;
6131
+ fireWebhook("task.started", { prompt: options.prompt });
6132
+ this.context.addUserMessage(options.prompt);
6133
+ let iteration = 0;
6134
+ while (iteration < maxIterations) {
6135
+ iteration++;
6136
+ if (options.abortSignal?.aborted) {
6137
+ const cancelError = "Task was cancelled";
6138
+ fireWebhook("task.failed", { status: "failed", error: cancelError, iterations: iteration });
6139
+ return { status: "failed", error: cancelError, iterations: iteration };
6140
+ }
6141
+ const messages = await this.context.getMessages();
6142
+ const useAnthropic = isAnthropicModel(this.session.model);
6143
+ const result = await generateText3({
6144
+ model: resolveModel(this.session.model),
6145
+ system: systemPrompt,
6146
+ messages,
6147
+ tools: taskTools,
6148
+ stopWhen: stepCountIs2(500),
6149
+ abortSignal: options.abortSignal,
6150
+ providerOptions: useAnthropic ? {
6151
+ anthropic: {
6152
+ thinking: { type: "enabled", budgetTokens: 1e4 }
6153
+ }
6154
+ } : void 0,
6155
+ onStepFinish: (step) => {
6156
+ options.onStepFinish?.(step);
6157
+ fireWebhook("task.step_finished", { iteration, text: step.text });
6158
+ }
6159
+ });
6160
+ const responseMessages = result.response.messages;
6161
+ this.context.addResponseMessages(responseMessages);
6162
+ if (result.text) {
6163
+ options.onText?.(result.text);
6164
+ fireWebhook("task.message", { iteration, text: result.text });
6165
+ }
6166
+ for (const step of result.steps) {
6167
+ if (step.toolCalls) {
6168
+ for (const tc of step.toolCalls) {
6169
+ options.onToolCall?.({ toolCallId: tc.toolCallId, toolName: tc.toolName, input: tc.args });
6170
+ fireWebhook("task.tool_call", { iteration, toolName: tc.toolName, toolCallId: tc.toolCallId, input: tc.args });
6171
+ }
6172
+ }
6173
+ if (step.toolResults) {
6174
+ for (const tr of step.toolResults) {
6175
+ options.onToolResult?.({ toolCallId: tr.toolCallId, toolName: tr.toolName, output: tr.result });
6176
+ fireWebhook("task.tool_result", { iteration, toolName: tr.toolName, toolCallId: tr.toolCallId, output: tr.result });
6177
+ }
6178
+ }
6179
+ }
6180
+ if (completion.signal) {
6181
+ const sig = completion.signal;
6182
+ const finalStatus = sig.status;
6183
+ const eventType = finalStatus === "completed" ? "task.completed" : "task.failed";
6184
+ fireWebhook(eventType, {
6185
+ status: finalStatus,
6186
+ result: sig.result,
6187
+ error: sig.error,
6188
+ iterations: iteration
6189
+ });
6190
+ const updatedTask2 = {
6191
+ ...options.taskConfig,
6192
+ status: finalStatus,
6193
+ result: sig.result,
6194
+ error: sig.error,
6195
+ iterations: iteration
6196
+ };
6197
+ await sessionQueries.update(this.session.id, {
6198
+ config: { ...this.session.config, task: updatedTask2 }
6199
+ });
6200
+ return {
6201
+ status: finalStatus,
6202
+ result: sig.result,
6203
+ error: sig.error,
6204
+ iterations: iteration
6205
+ };
6206
+ }
6207
+ this.context.addUserMessage(
6208
+ "Continue working on the task. When done, call `complete_task` with the result. If you cannot complete it, call `task_failed` with a reason."
6209
+ );
6210
+ }
6211
+ const timeoutError = `Task did not complete within ${maxIterations} iterations`;
6212
+ fireWebhook("task.failed", { status: "failed", error: timeoutError, iterations: iteration });
6213
+ const updatedTask = {
6214
+ ...options.taskConfig,
6215
+ status: "failed",
6216
+ error: timeoutError,
6217
+ iterations: iteration
6218
+ };
6219
+ await sessionQueries.update(this.session.id, {
6220
+ config: { ...this.session.config, task: updatedTask }
6221
+ });
6222
+ return { status: "failed", error: timeoutError, iterations: iteration };
6223
+ }
5813
6224
  /**
5814
6225
  * Wrap tools to add approval checking
5815
6226
  */
@@ -5823,9 +6234,9 @@ ${prompt}` });
5823
6234
  wrappedTools[name] = originalTool;
5824
6235
  continue;
5825
6236
  }
5826
- wrappedTools[name] = tool11({
6237
+ wrappedTools[name] = tool12({
5827
6238
  description: originalTool.description || "",
5828
- inputSchema: originalTool.inputSchema || z12.object({}),
6239
+ inputSchema: originalTool.inputSchema || z13.object({}),
5829
6240
  execute: async (input, toolOptions) => {
5830
6241
  const toolCallId = toolOptions.toolCallId || nanoid3();
5831
6242
  const execution = toolExecutionQueries.create({
@@ -5966,18 +6377,18 @@ function cleanupPendingInputs() {
5966
6377
  }
5967
6378
  }
5968
6379
  }
5969
- var createSessionSchema = z13.object({
5970
- name: z13.string().optional(),
5971
- workingDirectory: z13.string().optional(),
5972
- model: z13.string().optional(),
5973
- toolApprovals: z13.record(z13.string(), z13.boolean()).optional()
6380
+ var createSessionSchema = z14.object({
6381
+ name: z14.string().optional(),
6382
+ workingDirectory: z14.string().optional(),
6383
+ model: z14.string().optional(),
6384
+ toolApprovals: z14.record(z14.string(), z14.boolean()).optional()
5974
6385
  });
5975
- var paginationQuerySchema = z13.object({
5976
- limit: z13.string().optional(),
5977
- offset: z13.string().optional()
6386
+ var paginationQuerySchema = z14.object({
6387
+ limit: z14.string().optional(),
6388
+ offset: z14.string().optional()
5978
6389
  });
5979
- var messagesQuerySchema = z13.object({
5980
- limit: z13.string().optional()
6390
+ var messagesQuerySchema = z14.object({
6391
+ limit: z14.string().optional()
5981
6392
  });
5982
6393
  sessions.get(
5983
6394
  "/",
@@ -6116,10 +6527,10 @@ sessions.get("/:id/tools", async (c) => {
6116
6527
  count: executions.length
6117
6528
  });
6118
6529
  });
6119
- var updateSessionSchema = z13.object({
6120
- model: z13.string().optional(),
6121
- name: z13.string().optional(),
6122
- toolApprovals: z13.record(z13.string(), z13.boolean()).optional()
6530
+ var updateSessionSchema = z14.object({
6531
+ model: z14.string().optional(),
6532
+ name: z14.string().optional(),
6533
+ toolApprovals: z14.record(z14.string(), z14.boolean()).optional()
6123
6534
  });
6124
6535
  sessions.patch(
6125
6536
  "/:id",
@@ -6189,8 +6600,8 @@ sessions.post("/:id/clear", async (c) => {
6189
6600
  await agent.clearContext();
6190
6601
  return c.json({ success: true, sessionId: id });
6191
6602
  });
6192
- var pendingInputSchema = z13.object({
6193
- text: z13.string()
6603
+ var pendingInputSchema = z14.object({
6604
+ text: z14.string()
6194
6605
  });
6195
6606
  sessions.post(
6196
6607
  "/:id/pending-input",
@@ -6221,13 +6632,13 @@ sessions.get("/:id/pending-input", async (c) => {
6221
6632
  createdAt: pending.createdAt.toISOString()
6222
6633
  });
6223
6634
  });
6224
- var devtoolsContextSchema = z13.object({
6225
- url: z13.string(),
6226
- path: z13.string(),
6227
- pageName: z13.string().optional(),
6228
- screenWidth: z13.number().optional(),
6229
- screenHeight: z13.number().optional(),
6230
- devicePixelRatio: z13.number().optional()
6635
+ var devtoolsContextSchema = z14.object({
6636
+ url: z14.string(),
6637
+ path: z14.string(),
6638
+ pageName: z14.string().optional(),
6639
+ screenWidth: z14.number().optional(),
6640
+ screenHeight: z14.number().optional(),
6641
+ devicePixelRatio: z14.number().optional()
6231
6642
  });
6232
6643
  sessions.post(
6233
6644
  "/:id/devtools-context",
@@ -6518,10 +6929,10 @@ sessions.delete("/:id/attachments/:attachmentId", async (c) => {
6518
6929
  unlinkSync(filePath);
6519
6930
  return c.json({ success: true, id: attachmentId });
6520
6931
  });
6521
- var filesQuerySchema = z13.object({
6522
- query: z13.string().optional(),
6932
+ var filesQuerySchema = z14.object({
6933
+ query: z14.string().optional(),
6523
6934
  // Filter query (e.g., "src/com" to match "src/components")
6524
- limit: z13.string().optional()
6935
+ limit: z14.string().optional()
6525
6936
  // Max results (default 50)
6526
6937
  });
6527
6938
  var IGNORED_DIRECTORIES = /* @__PURE__ */ new Set([
@@ -6699,7 +7110,7 @@ sessions.get(
6699
7110
  init_db();
6700
7111
  import { Hono as Hono2 } from "hono";
6701
7112
  import { zValidator as zValidator2 } from "@hono/zod-validator";
6702
- import { z as z14 } from "zod";
7113
+ import { z as z15 } from "zod";
6703
7114
  import { existsSync as existsSync14, mkdirSync as mkdirSync4, writeFileSync as writeFileSync3 } from "fs";
6704
7115
  import { join as join6 } from "path";
6705
7116
  init_config();
@@ -6864,30 +7275,30 @@ function enrichPromptWithDevtoolsContext(sessionId, prompt) {
6864
7275
  ${prompt}`;
6865
7276
  }
6866
7277
  var agents = new Hono2();
6867
- var attachmentSchema = z14.object({
6868
- type: z14.enum(["image", "file"]),
6869
- data: z14.string(),
7278
+ var attachmentSchema = z15.object({
7279
+ type: z15.enum(["image", "file"]),
7280
+ data: z15.string(),
6870
7281
  // base64 data URL or raw base64
6871
- mediaType: z14.string().optional(),
6872
- filename: z14.string().optional()
7282
+ mediaType: z15.string().optional(),
7283
+ filename: z15.string().optional()
6873
7284
  });
6874
- var runPromptSchema = z14.object({
6875
- prompt: z14.string(),
7285
+ var runPromptSchema = z15.object({
7286
+ prompt: z15.string(),
6876
7287
  // Can be empty if attachments are provided
6877
- attachments: z14.array(attachmentSchema).optional()
7288
+ attachments: z15.array(attachmentSchema).optional()
6878
7289
  }).refine(
6879
7290
  (data) => data.prompt.trim().length > 0 || data.attachments && data.attachments.length > 0,
6880
7291
  { message: "Either prompt or attachments must be provided" }
6881
7292
  );
6882
- var quickStartSchema = z14.object({
6883
- prompt: z14.string().min(1),
6884
- name: z14.string().optional(),
6885
- workingDirectory: z14.string().optional(),
6886
- model: z14.string().optional(),
6887
- toolApprovals: z14.record(z14.string(), z14.boolean()).optional()
7293
+ var quickStartSchema = z15.object({
7294
+ prompt: z15.string().min(1),
7295
+ name: z15.string().optional(),
7296
+ workingDirectory: z15.string().optional(),
7297
+ model: z15.string().optional(),
7298
+ toolApprovals: z15.record(z15.string(), z15.boolean()).optional()
6888
7299
  });
6889
- var rejectSchema = z14.object({
6890
- reason: z14.string().optional()
7300
+ var rejectSchema = z15.object({
7301
+ reason: z15.string().optional()
6891
7302
  }).optional();
6892
7303
  var streamAbortControllers = /* @__PURE__ */ new Map();
6893
7304
  function getAttachmentsDirectory(sessionId) {
@@ -7317,7 +7728,7 @@ agents.get("/:id/watch", async (c) => {
7317
7728
  "Cache-Control": "no-cache",
7318
7729
  "Connection": "keep-alive",
7319
7730
  "x-vercel-ai-ui-message-stream": "v1",
7320
- "x-stream-id": streamId
7731
+ "x-stream-id": streamId ?? ""
7321
7732
  }
7322
7733
  });
7323
7734
  });
@@ -7675,7 +8086,7 @@ agents.post(
7675
8086
  init_config();
7676
8087
  import { Hono as Hono3 } from "hono";
7677
8088
  import { zValidator as zValidator3 } from "@hono/zod-validator";
7678
- import { z as z15 } from "zod";
8089
+ import { z as z16 } from "zod";
7679
8090
  import { readFileSync as readFileSync5 } from "fs";
7680
8091
  import { fileURLToPath as fileURLToPath3 } from "url";
7681
8092
  import { dirname as dirname6, join as join7 } from "path";
@@ -7785,9 +8196,9 @@ health.get("/api-keys", async (c) => {
7785
8196
  supportedProviders: SUPPORTED_PROVIDERS
7786
8197
  });
7787
8198
  });
7788
- var setApiKeySchema = z15.object({
7789
- provider: z15.string(),
7790
- apiKey: z15.string().min(1)
8199
+ var setApiKeySchema = z16.object({
8200
+ provider: z16.string(),
8201
+ apiKey: z16.string().min(1)
7791
8202
  });
7792
8203
  health.post(
7793
8204
  "/api-keys",
@@ -7826,13 +8237,13 @@ health.delete("/api-keys/:provider", async (c) => {
7826
8237
  // src/server/routes/terminals.ts
7827
8238
  import { Hono as Hono4 } from "hono";
7828
8239
  import { zValidator as zValidator4 } from "@hono/zod-validator";
7829
- import { z as z16 } from "zod";
8240
+ import { z as z17 } from "zod";
7830
8241
  init_db();
7831
8242
  var terminals = new Hono4();
7832
- var spawnSchema = z16.object({
7833
- command: z16.string(),
7834
- cwd: z16.string().optional(),
7835
- name: z16.string().optional()
8243
+ var spawnSchema = z17.object({
8244
+ command: z17.string(),
8245
+ cwd: z17.string().optional(),
8246
+ name: z17.string().optional()
7836
8247
  });
7837
8248
  terminals.post(
7838
8249
  "/:sessionId/terminals",
@@ -7913,8 +8324,8 @@ terminals.get("/:sessionId/terminals/:terminalId", async (c) => {
7913
8324
  // We don't track exit codes in tmux mode
7914
8325
  });
7915
8326
  });
7916
- var logsQuerySchema = z16.object({
7917
- tail: z16.string().optional().transform((v) => v ? parseInt(v, 10) : void 0)
8327
+ var logsQuerySchema = z17.object({
8328
+ tail: z17.string().optional().transform((v) => v ? parseInt(v, 10) : void 0)
7918
8329
  });
7919
8330
  terminals.get(
7920
8331
  "/:sessionId/terminals/:terminalId/logs",
@@ -7938,8 +8349,8 @@ terminals.get(
7938
8349
  });
7939
8350
  }
7940
8351
  );
7941
- var killSchema = z16.object({
7942
- signal: z16.enum(["SIGTERM", "SIGKILL"]).optional()
8352
+ var killSchema = z17.object({
8353
+ signal: z17.enum(["SIGTERM", "SIGKILL"]).optional()
7943
8354
  });
7944
8355
  terminals.post(
7945
8356
  "/:sessionId/terminals/:terminalId/kill",
@@ -7953,8 +8364,8 @@ terminals.post(
7953
8364
  return c.json({ success: true, message: "Terminal killed" });
7954
8365
  }
7955
8366
  );
7956
- var writeSchema = z16.object({
7957
- input: z16.string()
8367
+ var writeSchema = z17.object({
8368
+ input: z17.string()
7958
8369
  });
7959
8370
  terminals.post(
7960
8371
  "/:sessionId/terminals/:terminalId/write",
@@ -8135,6 +8546,131 @@ data: ${JSON.stringify({ status: "stopped" })}
8135
8546
  );
8136
8547
  });
8137
8548
 
8549
+ // src/server/routes/tasks.ts
8550
+ init_db();
8551
+ import { Hono as Hono5 } from "hono";
8552
+ import { zValidator as zValidator5 } from "@hono/zod-validator";
8553
+ import { z as z18 } from "zod";
8554
+ init_config();
8555
+ var tasks = new Hono5();
8556
+ var taskAbortControllers = /* @__PURE__ */ new Map();
8557
+ var createTaskSchema = z18.object({
8558
+ prompt: z18.string().min(1),
8559
+ outputSchema: z18.record(z18.string(), z18.unknown()),
8560
+ webhookUrl: z18.string().url().optional(),
8561
+ model: z18.string().optional(),
8562
+ workingDirectory: z18.string().optional(),
8563
+ name: z18.string().optional(),
8564
+ maxIterations: z18.number().int().min(1).max(500).optional()
8565
+ });
8566
+ tasks.post(
8567
+ "/",
8568
+ zValidator5("json", createTaskSchema),
8569
+ async (c) => {
8570
+ const body = c.req.valid("json");
8571
+ const config = getConfig();
8572
+ const taskConfig = {
8573
+ enabled: true,
8574
+ outputSchema: body.outputSchema,
8575
+ webhookUrl: body.webhookUrl,
8576
+ maxIterations: body.maxIterations ?? 50,
8577
+ status: "running"
8578
+ };
8579
+ const agent = await Agent.create({
8580
+ name: body.name || "Task",
8581
+ workingDirectory: body.workingDirectory || config.resolvedWorkingDirectory,
8582
+ model: body.model || config.defaultModel,
8583
+ sessionConfig: {
8584
+ toolApprovals: { bash: false, write_file: false, read_file: false },
8585
+ task: taskConfig
8586
+ }
8587
+ });
8588
+ const taskId = agent.sessionId;
8589
+ const abortController = new AbortController();
8590
+ taskAbortControllers.set(taskId, abortController);
8591
+ (async () => {
8592
+ try {
8593
+ await agent.runTask({
8594
+ prompt: body.prompt,
8595
+ taskConfig,
8596
+ abortSignal: abortController.signal
8597
+ });
8598
+ } catch (err) {
8599
+ if (err.name === "AbortError" || abortController.signal.aborted) {
8600
+ console.log(`[TASK] Task ${taskId} was cancelled`);
8601
+ } else {
8602
+ console.error(`[TASK] Error in task ${taskId}:`, err.message);
8603
+ const failedTask = {
8604
+ ...taskConfig,
8605
+ status: "failed",
8606
+ error: err.message || "Unknown error"
8607
+ };
8608
+ await sessionQueries.update(taskId, {
8609
+ config: {
8610
+ toolApprovals: { bash: false, write_file: false, read_file: false },
8611
+ task: failedTask
8612
+ }
8613
+ });
8614
+ }
8615
+ } finally {
8616
+ taskAbortControllers.delete(taskId);
8617
+ }
8618
+ })();
8619
+ return c.json({ taskId, status: "running" }, 201);
8620
+ }
8621
+ );
8622
+ tasks.get("/:id", async (c) => {
8623
+ const id = c.req.param("id");
8624
+ const session = await sessionQueries.getById(id);
8625
+ if (!session) {
8626
+ return c.json({ error: "Task not found" }, 404);
8627
+ }
8628
+ const task = session.config?.task;
8629
+ if (!task?.enabled) {
8630
+ return c.json({ error: "Session is not a task" }, 400);
8631
+ }
8632
+ return c.json({
8633
+ taskId: id,
8634
+ status: task.status,
8635
+ result: task.result,
8636
+ error: task.error,
8637
+ iterations: task.iterations,
8638
+ model: session.model,
8639
+ name: session.name,
8640
+ createdAt: session.createdAt.toISOString(),
8641
+ updatedAt: session.updatedAt.toISOString()
8642
+ });
8643
+ });
8644
+ tasks.post("/:id/cancel", async (c) => {
8645
+ const id = c.req.param("id");
8646
+ const session = await sessionQueries.getById(id);
8647
+ if (!session) {
8648
+ return c.json({ error: "Task not found" }, 404);
8649
+ }
8650
+ const task = session.config?.task;
8651
+ if (!task?.enabled) {
8652
+ return c.json({ error: "Session is not a task" }, 400);
8653
+ }
8654
+ if (task.status !== "running") {
8655
+ return c.json({ error: `Task is already ${task.status}` }, 400);
8656
+ }
8657
+ const abortController = taskAbortControllers.get(id);
8658
+ if (abortController) {
8659
+ abortController.abort();
8660
+ taskAbortControllers.delete(id);
8661
+ }
8662
+ const cancelledTask = {
8663
+ ...task,
8664
+ status: "failed",
8665
+ error: "Task cancelled by user"
8666
+ };
8667
+ await sessionQueries.update(id, {
8668
+ config: { ...session.config, task: cancelledTask }
8669
+ });
8670
+ return c.json({ taskId: id, status: "failed", error: "Task cancelled by user" });
8671
+ });
8672
+ var tasks_default = tasks;
8673
+
8138
8674
  // src/server/index.ts
8139
8675
  init_config();
8140
8676
  init_db();
@@ -8471,7 +9007,7 @@ function stopWebUI() {
8471
9007
  }
8472
9008
  }
8473
9009
  async function createApp(options = {}) {
8474
- const app = new Hono5();
9010
+ const app = new Hono6();
8475
9011
  app.use("*", cors({
8476
9012
  origin: "*",
8477
9013
  // Allow all origins
@@ -8489,6 +9025,7 @@ async function createApp(options = {}) {
8489
9025
  app.route("/agents", agents);
8490
9026
  app.route("/sessions", terminals);
8491
9027
  app.route("/terminals", terminals);
9028
+ app.route("/tasks", tasks_default);
8492
9029
  app.get("/openapi.json", async (c) => {
8493
9030
  return c.json(generateOpenAPISpec());
8494
9031
  });