sparkecoder 0.1.61 → 0.1.63

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 (168) hide show
  1. package/dist/agent/index.d.ts +3 -3
  2. package/dist/agent/index.js +16 -3
  3. package/dist/agent/index.js.map +1 -1
  4. package/dist/cli.js +16 -3
  5. package/dist/cli.js.map +1 -1
  6. package/dist/db/index.d.ts +2 -2
  7. package/dist/{index-DuGtMaAJ.d.ts → index-Dn-eCGLe.d.ts} +25 -25
  8. package/dist/index.d.ts +5 -5
  9. package/dist/index.js +16 -3
  10. package/dist/index.js.map +1 -1
  11. package/dist/{schema-C7Mm4Ykn.d.ts → schema-XcP0dedO.d.ts} +3 -3
  12. package/dist/{search-C_IFImt1.d.ts → search-DINnDTgj.d.ts} +4 -4
  13. package/dist/server/index.js +16 -3
  14. package/dist/server/index.js.map +1 -1
  15. package/dist/tools/index.d.ts +2 -2
  16. package/package.json +1 -1
  17. package/web/.next/BUILD_ID +1 -1
  18. package/web/.next/standalone/web/.next/BUILD_ID +1 -1
  19. package/web/.next/standalone/web/.next/build-manifest.json +2 -2
  20. package/web/.next/standalone/web/.next/prerender-manifest.json +3 -3
  21. package/web/.next/standalone/web/.next/server/app/(main)/page.js.nft.json +1 -1
  22. package/web/.next/standalone/web/.next/server/app/(main)/page_client-reference-manifest.js +1 -1
  23. package/web/.next/standalone/web/.next/server/app/(main)/session/[id]/page.js.nft.json +1 -1
  24. package/web/.next/standalone/web/.next/server/app/(main)/session/[id]/page_client-reference-manifest.js +1 -1
  25. package/web/.next/standalone/web/.next/server/app/_global-error.html +2 -2
  26. package/web/.next/standalone/web/.next/server/app/_global-error.rsc +1 -1
  27. package/web/.next/standalone/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  28. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  29. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  30. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  31. package/web/.next/standalone/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  32. package/web/.next/standalone/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  33. package/web/.next/standalone/web/.next/server/app/_not-found.html +1 -1
  34. package/web/.next/standalone/web/.next/server/app/_not-found.rsc +2 -2
  35. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
  36. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  37. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
  38. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  39. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  40. package/web/.next/standalone/web/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  41. package/web/.next/standalone/web/.next/server/app/docs/installation/page_client-reference-manifest.js +1 -1
  42. package/web/.next/standalone/web/.next/server/app/docs/installation.html +2 -2
  43. package/web/.next/standalone/web/.next/server/app/docs/installation.rsc +2 -2
  44. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_full.segment.rsc +2 -2
  45. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_head.segment.rsc +1 -1
  46. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_index.segment.rsc +2 -2
  47. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_tree.segment.rsc +2 -2
  48. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation/__PAGE__.segment.rsc +1 -1
  49. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation.segment.rsc +1 -1
  50. package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs.segment.rsc +1 -1
  51. package/web/.next/standalone/web/.next/server/app/docs/page_client-reference-manifest.js +1 -1
  52. package/web/.next/standalone/web/.next/server/app/docs/skills/page_client-reference-manifest.js +1 -1
  53. package/web/.next/standalone/web/.next/server/app/docs/skills.html +2 -2
  54. package/web/.next/standalone/web/.next/server/app/docs/skills.rsc +2 -2
  55. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_full.segment.rsc +2 -2
  56. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_head.segment.rsc +1 -1
  57. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_index.segment.rsc +2 -2
  58. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_tree.segment.rsc +2 -2
  59. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills/__PAGE__.segment.rsc +1 -1
  60. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills.segment.rsc +1 -1
  61. package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs.segment.rsc +1 -1
  62. package/web/.next/standalone/web/.next/server/app/docs/tools/page_client-reference-manifest.js +1 -1
  63. package/web/.next/standalone/web/.next/server/app/docs/tools.html +2 -2
  64. package/web/.next/standalone/web/.next/server/app/docs/tools.rsc +2 -2
  65. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_full.segment.rsc +2 -2
  66. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_head.segment.rsc +1 -1
  67. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_index.segment.rsc +2 -2
  68. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_tree.segment.rsc +2 -2
  69. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools/__PAGE__.segment.rsc +1 -1
  70. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools.segment.rsc +1 -1
  71. package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs.segment.rsc +1 -1
  72. package/web/.next/standalone/web/.next/server/app/docs.html +2 -2
  73. package/web/.next/standalone/web/.next/server/app/docs.rsc +2 -2
  74. package/web/.next/standalone/web/.next/server/app/docs.segments/_full.segment.rsc +2 -2
  75. package/web/.next/standalone/web/.next/server/app/docs.segments/_head.segment.rsc +1 -1
  76. package/web/.next/standalone/web/.next/server/app/docs.segments/_index.segment.rsc +2 -2
  77. package/web/.next/standalone/web/.next/server/app/docs.segments/_tree.segment.rsc +2 -2
  78. package/web/.next/standalone/web/.next/server/app/docs.segments/docs/__PAGE__.segment.rsc +1 -1
  79. package/web/.next/standalone/web/.next/server/app/docs.segments/docs.segment.rsc +1 -1
  80. package/web/.next/standalone/web/.next/server/app/embed/[id]/page.js.nft.json +1 -1
  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 +2 -2
  90. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_e19eaecc._.js → 2374f_04a544c8._.js} +1 -1
  91. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_0d0b1fb9._.js → 2374f_45534372._.js} +1 -1
  92. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_03d22c16._.js → 2374f_5c78460e._.js} +1 -1
  93. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_6166d14d._.js → 2374f_5d0b3394._.js} +1 -1
  94. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_b98835eb._.js → 2374f_5e9eb6da._.js} +1 -1
  95. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_3f7d6d28._.js → 2374f_68abddfe._.js} +1 -1
  96. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_99b7b533._.js → 2374f_72fb9db7._.js} +1 -1
  97. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_6b436efc._.js → 2374f_ab5b97d8._.js} +1 -1
  98. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_e3aec189._.js → 2374f_bfc8ef7d._.js} +1 -1
  99. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_a1a36483._.js → 2374f_c61a33b3._.js} +1 -1
  100. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_976b2ded._.js → 2374f_d5f5b9ba._.js} +1 -1
  101. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_67b9525f._.js → 2374f_db790cfe._.js} +1 -1
  102. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_98eba491._.js → 2374f_de60e6ea._.js} +1 -1
  103. package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_784d851c._.js → 2374f_e366206f._.js} +1 -1
  104. package/web/.next/standalone/web/.next/server/chunks/ssr/{[root-of-the-server]__4f176a16._.js → [root-of-the-server]__aa788b85._.js} +2 -2
  105. package/web/.next/standalone/web/.next/server/chunks/ssr/{[root-of-the-server]__d59f831d._.js → [root-of-the-server]__d04c460d._.js} +4 -4
  106. package/web/.next/standalone/web/.next/server/chunks/ssr/web_08bbd8c8._.js +7 -0
  107. package/web/.next/standalone/web/.next/server/chunks/ssr/web_2b3a5919._.js +1 -1
  108. package/web/.next/standalone/web/.next/server/chunks/ssr/web_38156da8._.js +1 -1
  109. package/web/.next/standalone/web/.next/server/chunks/ssr/{web_693f514e._.js → web_6fb589ac._.js} +2 -2
  110. package/web/.next/standalone/web/.next/server/chunks/ssr/{web_dc6ce793._.js → web_c729ad51._.js} +2 -2
  111. package/web/.next/standalone/web/.next/server/chunks/ssr/web_src_components_sessions-sidebar_tsx_92510070._.js +1 -1
  112. package/web/.next/standalone/web/.next/server/pages/404.html +1 -1
  113. package/web/.next/standalone/web/.next/server/pages/500.html +2 -2
  114. package/web/.next/standalone/web/.next/server/server-reference-manifest.js +1 -1
  115. package/web/.next/standalone/web/.next/server/server-reference-manifest.json +1 -1
  116. package/web/.next/standalone/web/.next/static/chunks/{81685e5e8be4eac9.js → 054deec0c7b19894.js} +3 -3
  117. package/web/.next/standalone/web/.next/static/chunks/1ebba7ac024244f9.js +5 -0
  118. package/web/.next/{static/chunks/0358a0e7a40cfb93.css → standalone/web/.next/static/chunks/1f42a42914068041.css} +1 -1
  119. package/web/.next/standalone/web/.next/static/chunks/26eb5fab5216f3cc.js +1 -0
  120. package/web/.next/standalone/web/.next/static/chunks/{95436454a7559b0d.js → 5383c5717758f575.js} +3 -3
  121. package/web/.next/standalone/web/.next/static/chunks/{20e0fa99c7a1c1fc.js → 7fb141141caa4fac.js} +5 -5
  122. package/web/.next/standalone/web/.next/static/chunks/c6f40df16a9396b9.js +1 -0
  123. package/web/.next/standalone/web/.next/static/chunks/ea29be392100ab0f.js +5 -0
  124. package/web/.next/{static/chunks/294ebe8457006bce.js → standalone/web/.next/static/chunks/eea48be65cdb3f4b.js} +2 -2
  125. package/web/.next/{static/chunks/81685e5e8be4eac9.js → standalone/web/.next/static/static/chunks/054deec0c7b19894.js} +3 -3
  126. package/web/.next/standalone/web/.next/static/static/chunks/1ebba7ac024244f9.js +5 -0
  127. package/web/.next/standalone/web/.next/static/static/chunks/{0358a0e7a40cfb93.css → 1f42a42914068041.css} +1 -1
  128. package/web/.next/standalone/web/.next/static/static/chunks/26eb5fab5216f3cc.js +1 -0
  129. package/web/.next/standalone/web/.next/static/static/chunks/{95436454a7559b0d.js → 5383c5717758f575.js} +3 -3
  130. package/web/.next/standalone/web/.next/static/static/chunks/{20e0fa99c7a1c1fc.js → 7fb141141caa4fac.js} +5 -5
  131. package/web/.next/standalone/web/.next/static/static/chunks/c6f40df16a9396b9.js +1 -0
  132. package/web/.next/standalone/web/.next/static/static/chunks/ea29be392100ab0f.js +5 -0
  133. package/web/.next/standalone/web/.next/static/static/chunks/{294ebe8457006bce.js → eea48be65cdb3f4b.js} +2 -2
  134. package/web/.next/standalone/web/package-lock.json +20 -0
  135. package/web/.next/standalone/web/package.json +2 -0
  136. package/web/.next/standalone/web/src/components/ai-elements/complete-task-tool.tsx +36 -60
  137. package/web/.next/standalone/web/src/components/chat-interface.tsx +36 -32
  138. package/web/.next/standalone/web/src/components/sessions-sidebar.tsx +231 -16
  139. package/web/.next/standalone/web/src/lib/api.ts +17 -0
  140. package/web/.next/{standalone/web/.next/static/static/chunks/81685e5e8be4eac9.js → static/chunks/054deec0c7b19894.js} +3 -3
  141. package/web/.next/static/chunks/1ebba7ac024244f9.js +5 -0
  142. package/web/.next/{standalone/web/.next/static/chunks/0358a0e7a40cfb93.css → static/chunks/1f42a42914068041.css} +1 -1
  143. package/web/.next/static/chunks/26eb5fab5216f3cc.js +1 -0
  144. package/web/.next/static/chunks/{95436454a7559b0d.js → 5383c5717758f575.js} +3 -3
  145. package/web/.next/static/chunks/{20e0fa99c7a1c1fc.js → 7fb141141caa4fac.js} +5 -5
  146. package/web/.next/static/chunks/c6f40df16a9396b9.js +1 -0
  147. package/web/.next/static/chunks/ea29be392100ab0f.js +5 -0
  148. package/web/.next/{standalone/web/.next/static/chunks/294ebe8457006bce.js → static/chunks/eea48be65cdb3f4b.js} +2 -2
  149. package/web/package.json +2 -0
  150. package/web/.next/standalone/web/.next/server/chunks/ssr/web_a42a2651._.js +0 -7
  151. package/web/.next/standalone/web/.next/static/chunks/1ecde4c0d426a635.js +0 -1
  152. package/web/.next/standalone/web/.next/static/chunks/36688a049d72e8ab.js +0 -5
  153. package/web/.next/standalone/web/.next/static/chunks/a751ca474cc46212.js +0 -5
  154. package/web/.next/standalone/web/.next/static/static/chunks/1ecde4c0d426a635.js +0 -1
  155. package/web/.next/standalone/web/.next/static/static/chunks/36688a049d72e8ab.js +0 -5
  156. package/web/.next/standalone/web/.next/static/static/chunks/a751ca474cc46212.js +0 -5
  157. package/web/.next/static/chunks/1ecde4c0d426a635.js +0 -1
  158. package/web/.next/static/chunks/36688a049d72e8ab.js +0 -5
  159. package/web/.next/static/chunks/a751ca474cc46212.js +0 -5
  160. /package/web/.next/standalone/web/.next/static/{8zJH-RqrUQ3scBGbdaCmn → Xc8ztiG5d6CHUNHm_1G8b}/_buildManifest.js +0 -0
  161. /package/web/.next/standalone/web/.next/static/{8zJH-RqrUQ3scBGbdaCmn → Xc8ztiG5d6CHUNHm_1G8b}/_clientMiddlewareManifest.json +0 -0
  162. /package/web/.next/standalone/web/.next/static/{8zJH-RqrUQ3scBGbdaCmn → Xc8ztiG5d6CHUNHm_1G8b}/_ssgManifest.js +0 -0
  163. /package/web/.next/standalone/web/.next/static/static/{8zJH-RqrUQ3scBGbdaCmn → Xc8ztiG5d6CHUNHm_1G8b}/_buildManifest.js +0 -0
  164. /package/web/.next/standalone/web/.next/static/static/{8zJH-RqrUQ3scBGbdaCmn → Xc8ztiG5d6CHUNHm_1G8b}/_clientMiddlewareManifest.json +0 -0
  165. /package/web/.next/standalone/web/.next/static/static/{8zJH-RqrUQ3scBGbdaCmn → Xc8ztiG5d6CHUNHm_1G8b}/_ssgManifest.js +0 -0
  166. /package/web/.next/static/{8zJH-RqrUQ3scBGbdaCmn → Xc8ztiG5d6CHUNHm_1G8b}/_buildManifest.js +0 -0
  167. /package/web/.next/static/{8zJH-RqrUQ3scBGbdaCmn → Xc8ztiG5d6CHUNHm_1G8b}/_clientMiddlewareManifest.json +0 -0
  168. /package/web/.next/static/{8zJH-RqrUQ3scBGbdaCmn → Xc8ztiG5d6CHUNHm_1G8b}/_ssgManifest.js +0 -0
@@ -2,8 +2,8 @@
2
2
 
3
3
  import { Badge } from "@/components/ui/badge";
4
4
  import { cn } from "@/lib/utils";
5
- import { CheckCircle2, XCircle, AlertTriangle, ListChecks } from "lucide-react";
6
- import { CodeBlock } from "./code-block";
5
+ import { CheckCircle2, XCircle, AlertTriangle } from "lucide-react";
6
+ import { VisualJson, TreeView } from "@visual-json/react";
7
7
 
8
8
  interface CompleteTaskToolProps {
9
9
  toolName: "complete_task" | "task_failed";
@@ -12,7 +12,7 @@ interface CompleteTaskToolProps {
12
12
  status: string;
13
13
  }
14
14
 
15
- export function CompleteTaskTool({ toolName, input, output, status }: CompleteTaskToolProps) {
15
+ export function CompleteTaskTool({ toolName, input, output }: CompleteTaskToolProps) {
16
16
  const isComplete = toolName === "complete_task";
17
17
  const isFailed = toolName === "task_failed";
18
18
  const isValidationError = output && (output as any).status === "validation_error";
@@ -20,7 +20,7 @@ export function CompleteTaskTool({ toolName, input, output, status }: CompleteTa
20
20
  return (
21
21
  <div
22
22
  className={cn(
23
- "mb-4 w-full max-w-full overflow-hidden rounded-md border",
23
+ "mb-4 w-full max-w-full overflow-hidden rounded-lg border transition-colors",
24
24
  isComplete && !isValidationError && "border-emerald-500/30",
25
25
  isFailed && "border-red-500/30",
26
26
  isValidationError && "border-amber-500/30"
@@ -29,82 +29,65 @@ export function CompleteTaskTool({ toolName, input, output, status }: CompleteTa
29
29
  {/* Header */}
30
30
  <div
31
31
  className={cn(
32
- "flex items-center gap-2 p-3",
32
+ "flex items-center gap-2.5 px-4 py-3",
33
33
  isComplete && !isValidationError && "bg-emerald-500/5",
34
34
  isFailed && "bg-red-500/5",
35
35
  isValidationError && "bg-amber-500/5"
36
36
  )}
37
37
  >
38
38
  {isValidationError ? (
39
- <AlertTriangle className="size-4 text-amber-500" />
39
+ <AlertTriangle className="size-4 text-amber-500 shrink-0" />
40
40
  ) : isComplete ? (
41
- <CheckCircle2 className="size-4 text-emerald-500" />
41
+ <CheckCircle2 className="size-4 text-emerald-500 shrink-0" />
42
42
  ) : (
43
- <XCircle className="size-4 text-red-500" />
43
+ <XCircle className="size-4 text-red-500 shrink-0" />
44
44
  )}
45
45
  <span className="font-medium text-sm">
46
46
  {isValidationError
47
- ? "Task Result — Validation Error"
47
+ ? "Schema mismatch"
48
48
  : isComplete
49
- ? "Task Completed"
50
- : "Task Failed"}
49
+ ? "Task completed"
50
+ : "Task failed"}
51
51
  </span>
52
- <Badge
53
- variant="secondary"
54
- className={cn(
55
- "ml-auto text-xs",
56
- isComplete && !isValidationError && "bg-emerald-500/10 text-emerald-600 dark:text-emerald-400",
57
- isFailed && "bg-red-500/10 text-red-600 dark:text-red-400",
58
- isValidationError && "bg-amber-500/10 text-amber-600 dark:text-amber-400"
59
- )}
60
- >
61
- <ListChecks className="size-3" />
62
- {isValidationError ? "Retry Needed" : isComplete ? "Done" : "Failed"}
63
- </Badge>
52
+ {isValidationError && (
53
+ <Badge
54
+ variant="secondary"
55
+ className="ml-auto text-[10px] bg-amber-500/10 text-amber-600 dark:text-amber-400"
56
+ >
57
+ Retry needed
58
+ </Badge>
59
+ )}
64
60
  </div>
65
61
 
66
62
  {/* Body */}
67
- <div className="p-4 space-y-3">
68
- {/* Show the result / reason */}
63
+ <div className="p-4">
64
+ {/* Completed show result tree */}
69
65
  {isComplete && input.result && (
70
- <div className="space-y-1.5">
71
- <h4 className="text-xs font-medium text-muted-foreground uppercase tracking-wide">
72
- Result
73
- </h4>
74
- <div className="rounded-md bg-muted/50 overflow-x-auto max-w-full">
75
- <CodeBlock
76
- code={JSON.stringify(input.result, null, 2)}
77
- language="json"
78
- />
79
- </div>
66
+ <div className="rounded-md border bg-muted/30 overflow-hidden">
67
+ <VisualJson value={input.result as any}>
68
+ <TreeView className="max-h-64 text-sm" />
69
+ </VisualJson>
80
70
  </div>
81
71
  )}
82
72
 
73
+ {/* Failed — show reason */}
83
74
  {isFailed && input.reason && (
84
- <div className="space-y-1.5">
85
- <h4 className="text-xs font-medium text-muted-foreground uppercase tracking-wide">
86
- Reason
87
- </h4>
88
- <p className="text-sm text-red-600 dark:text-red-400">
89
- {String(input.reason)}
90
- </p>
91
- </div>
75
+ <p className="text-sm text-red-600 dark:text-red-400">
76
+ {String(input.reason)}
77
+ </p>
92
78
  )}
93
79
 
94
- {/* Validation errors */}
80
+ {/* Validation errors — actionable detail */}
95
81
  {isValidationError && (output as any).errors && (
96
- <div className="space-y-1.5">
97
- <h4 className="text-xs font-medium text-muted-foreground uppercase tracking-wide">
98
- Validation Errors
99
- </h4>
100
- <div className="rounded-md bg-amber-500/5 p-3 space-y-1">
82
+ <div className="space-y-2">
83
+ <div className="rounded-md bg-amber-500/5 border border-amber-500/20 p-3 space-y-1.5">
101
84
  {((output as any).errors as Array<{ path: string; message: string }>).map(
102
85
  (err, i) => (
103
- <div key={i} className="text-sm">
104
- <code className="text-xs bg-muted px-1 py-0.5 rounded">
86
+ <div key={i} className="flex items-baseline gap-2 text-sm">
87
+ <code className="text-[11px] bg-muted px-1.5 py-0.5 rounded shrink-0 font-mono">
105
88
  {err.path}
106
- </code>{" "}
107
- <span className="text-amber-600 dark:text-amber-400">
89
+ </code>
90
+ <span className="text-amber-700 dark:text-amber-300">
108
91
  {err.message}
109
92
  </span>
110
93
  </div>
@@ -113,13 +96,6 @@ export function CompleteTaskTool({ toolName, input, output, status }: CompleteTa
113
96
  </div>
114
97
  </div>
115
98
  )}
116
-
117
- {/* Status message from tool output */}
118
- {output && (output as any).message && !isValidationError && (
119
- <p className="text-xs text-muted-foreground">
120
- {String((output as any).message)}
121
- </p>
122
- )}
123
99
  </div>
124
100
  </div>
125
101
  );
@@ -2654,42 +2654,46 @@ export function ChatInterface({ session, isEmbed = false }: ChatInterfaceProps)
2654
2654
  <Conversation className={cn("flex-1 p-4", isEmbed && "p-2")}>
2655
2655
  <ConversationContent className={cn("max-w-3xl mx-auto w-full", isEmbed && "max-w-none")}>
2656
2656
  {/* Task mode banner */}
2657
- {session.config?.task?.enabled && (
2658
- <div className={cn(
2659
- "mb-4 rounded-lg border p-3 text-sm",
2660
- session.config.task.status === 'completed' && "border-emerald-500/30 bg-emerald-500/5",
2661
- session.config.task.status === 'failed' && "border-red-500/30 bg-red-500/5",
2662
- session.config.task.status === 'running' && "border-blue-500/30 bg-blue-500/5",
2663
- )}>
2664
- <div className="flex items-center gap-2 mb-2">
2665
- <ListChecks className="size-4" />
2666
- <span className="font-medium">Task Mode</span>
2667
- <Badge variant="outline" className={cn(
2668
- "text-xs",
2669
- session.config.task.status === 'completed' && "border-emerald-500/30 text-emerald-600 dark:text-emerald-400",
2670
- session.config.task.status === 'failed' && "border-red-500/30 text-red-600 dark:text-red-400",
2671
- session.config.task.status === 'running' && "border-blue-500/30 text-blue-600 dark:text-blue-400",
2657
+ {session.config?.task?.enabled && (() => {
2658
+ const t = session.config.task!;
2659
+ const isRunning = t.status === 'running';
2660
+ const isDone = t.status === 'completed';
2661
+ const isFailed = t.status === 'failed';
2662
+ return (
2663
+ <div className={cn(
2664
+ "mb-4 rounded-lg border px-3.5 py-2.5 flex items-center gap-2.5 text-sm transition-colors",
2665
+ isDone && "border-emerald-500/30 bg-emerald-500/5",
2666
+ isFailed && "border-red-500/30 bg-red-500/5",
2667
+ isRunning && "border-blue-500/30 bg-blue-500/5",
2668
+ )}>
2669
+ <ListChecks className={cn(
2670
+ "size-4 shrink-0",
2671
+ isDone && "text-emerald-500",
2672
+ isFailed && "text-red-500",
2673
+ isRunning && "text-blue-500",
2674
+ )} />
2675
+ <span className="font-medium truncate">{session.name || 'Task'}</span>
2676
+ <span className={cn(
2677
+ "text-xs shrink-0",
2678
+ isDone && "text-emerald-600 dark:text-emerald-400",
2679
+ isFailed && "text-red-600 dark:text-red-400",
2680
+ isRunning && "text-blue-600 dark:text-blue-400 animate-pulse",
2672
2681
  )}>
2673
- {session.config.task.status === 'running' ? 'Running' : session.config.task.status === 'completed' ? 'Completed' : 'Failed'}
2674
- </Badge>
2675
- {session.config.task.iterations != null && (
2676
- <span className="text-xs text-muted-foreground ml-auto">
2677
- {session.config.task.iterations} iteration{session.config.task.iterations !== 1 ? 's' : ''}
2682
+ {isRunning ? 'Running' : isDone ? 'Completed' : 'Failed'}
2683
+ </span>
2684
+ {t.iterations != null && (
2685
+ <span className="text-xs text-muted-foreground ml-auto tabular-nums shrink-0">
2686
+ {t.iterations} iter.
2687
+ </span>
2688
+ )}
2689
+ {isFailed && t.error && (
2690
+ <span className="text-xs text-red-500 truncate ml-1" title={t.error}>
2691
+ — {t.error}
2678
2692
  </span>
2679
2693
  )}
2680
2694
  </div>
2681
- {session.config.task.webhookUrl && (
2682
- <div className="text-xs text-muted-foreground">
2683
- Webhook: <code className="bg-muted px-1 py-0.5 rounded text-[10px]">{session.config.task.webhookUrl}</code>
2684
- </div>
2685
- )}
2686
- {session.config.task.error && (
2687
- <div className="mt-1 text-xs text-red-600 dark:text-red-400">
2688
- Error: {session.config.task.error}
2689
- </div>
2690
- )}
2691
- </div>
2692
- )}
2695
+ );
2696
+ })()}
2693
2697
 
2694
2698
  {/* Loading history */}
2695
2699
  {isLoadingHistory && (
@@ -4,7 +4,7 @@ import { useState, useEffect, useRef } from 'react';
4
4
  import { useRouter, usePathname } from 'next/navigation';
5
5
  import Link from 'next/link';
6
6
  import Image from 'next/image';
7
- import { Plus, MessageSquare, Trash2, Loader2, Settings, PanelLeftClose, PanelLeft, Key, Check, X, Eye, EyeOff, Volume2, ListChecks } from 'lucide-react';
7
+ import { Plus, MessageSquare, Trash2, Loader2, Settings, PanelLeftClose, PanelLeft, Key, Check, X, Eye, EyeOff, Volume2, ListChecks, ChevronDown } from 'lucide-react';
8
8
  import { Badge } from '@/components/ui/badge';
9
9
  import {
10
10
  Sidebar,
@@ -42,7 +42,9 @@ import {
42
42
  TooltipProvider,
43
43
  TooltipTrigger,
44
44
  } from '@/components/ui/tooltip';
45
- import { createSession, deleteSession, getApiKeys, setApiKey, type ApiKeyStatus } from '@/lib/api';
45
+ import { createSession, createTask, deleteSession, getApiKeys, setApiKey, type ApiKeyStatus } from '@/lib/api';
46
+ import { Textarea } from '@/components/ui/textarea';
47
+ import { VisualJson, TreeView } from '@visual-json/react';
46
48
  import { getConfig, type AppConfig } from '@/lib/config';
47
49
  import { cn } from '@/lib/utils';
48
50
  import { useSessions, mutateSessions } from '@/hooks/use-sessions';
@@ -82,6 +84,18 @@ export function SessionsSidebar() {
82
84
  const [selectedModel, setSelectedModel] = useState('');
83
85
  const [toolApprovals, setToolApprovals] = useState<Record<string, boolean>>({});
84
86
 
87
+ // New task dialog state
88
+ const [taskDialogOpen, setTaskDialogOpen] = useState(false);
89
+ const [taskPrompt, setTaskPrompt] = useState('');
90
+ const defaultSchema = { type: 'object', properties: {}, required: [] as string[] };
91
+ const [taskSchema, setTaskSchema] = useState<Record<string, unknown>>(defaultSchema);
92
+ const [taskSchemaError, setTaskSchemaError] = useState('');
93
+ const [taskWebhookUrl, setTaskWebhookUrl] = useState('');
94
+ const [taskName, setTaskName] = useState('');
95
+ const [taskModel, setTaskModel] = useState('');
96
+ const [taskMaxIterations, setTaskMaxIterations] = useState('50');
97
+ const [creatingTask, setCreatingTask] = useState(false);
98
+
85
99
  // API Keys state
86
100
  const [apiKeys, setApiKeys] = useState<ApiKeyStatus[]>([]);
87
101
  const [editingProvider, setEditingProvider] = useState<string | null>(null);
@@ -217,6 +231,44 @@ export function SessionsSidebar() {
217
231
  }
218
232
  };
219
233
 
234
+ const resetTaskForm = () => {
235
+ setTaskPrompt('');
236
+ setTaskSchema(defaultSchema);
237
+ setTaskSchemaError('');
238
+ setTaskWebhookUrl('');
239
+ setTaskName('');
240
+ setTaskModel(config?.defaultModel || '');
241
+ setTaskMaxIterations('50');
242
+ };
243
+
244
+ const handleCreateTask = async () => {
245
+ if (!taskPrompt.trim()) return;
246
+ setTaskSchemaError('');
247
+ if (!taskSchema || typeof taskSchema !== 'object') {
248
+ setTaskSchemaError('Schema must be a JSON object');
249
+ return;
250
+ }
251
+ setCreatingTask(true);
252
+ try {
253
+ const result = await createTask({
254
+ prompt: taskPrompt,
255
+ outputSchema: taskSchema,
256
+ webhookUrl: taskWebhookUrl || undefined,
257
+ model: taskModel || config?.defaultModel,
258
+ name: taskName || undefined,
259
+ maxIterations: parseInt(taskMaxIterations) || 50,
260
+ });
261
+ mutateSessions();
262
+ setTaskDialogOpen(false);
263
+ resetTaskForm();
264
+ router.push(`${sessionBasePath}/${result.taskId}`);
265
+ } catch (err) {
266
+ console.error('Failed to create task:', err);
267
+ } finally {
268
+ setCreatingTask(false);
269
+ }
270
+ };
271
+
220
272
  const handleDelete = async (e: React.MouseEvent, id: string) => {
221
273
  e.preventDefault();
222
274
  e.stopPropagation();
@@ -307,18 +359,34 @@ export function SessionsSidebar() {
307
359
  </div>
308
360
  </div>
309
361
 
310
- <Button
311
- onClick={handleQuickCreate}
312
- disabled={creating}
313
- className="w-full justify-center gap-2 h-9"
314
- >
315
- {creating ? (
316
- <Loader2 className="size-4 animate-spin" />
317
- ) : (
318
- <Plus className="size-4" />
319
- )}
320
- New Agent
321
- </Button>
362
+ <div className="flex gap-2 w-full">
363
+ <Button
364
+ onClick={handleQuickCreate}
365
+ disabled={creating}
366
+ className="flex-1 justify-center gap-2 h-9"
367
+ >
368
+ {creating ? (
369
+ <Loader2 className="size-4 animate-spin" />
370
+ ) : (
371
+ <Plus className="size-4" />
372
+ )}
373
+ New Agent
374
+ </Button>
375
+ <TooltipProvider>
376
+ <Tooltip>
377
+ <TooltipTrigger asChild>
378
+ <Button
379
+ variant="outline"
380
+ onClick={() => { if (!config) loadConfig(); setTaskDialogOpen(true); }}
381
+ className="h-9 px-2.5"
382
+ >
383
+ <ListChecks className="size-4" />
384
+ </Button>
385
+ </TooltipTrigger>
386
+ <TooltipContent side="bottom">New Task</TooltipContent>
387
+ </Tooltip>
388
+ </TooltipProvider>
389
+ </div>
322
390
  </>
323
391
  )}
324
392
 
@@ -387,6 +455,23 @@ export function SessionsSidebar() {
387
455
  <TooltipContent side="right">New Agent</TooltipContent>
388
456
  </Tooltip>
389
457
  </TooltipProvider>
458
+
459
+ {/* New Task button */}
460
+ <TooltipProvider>
461
+ <Tooltip>
462
+ <TooltipTrigger asChild>
463
+ <Button
464
+ size="icon"
465
+ variant="outline"
466
+ onClick={() => { if (!config) loadConfig(); setTaskDialogOpen(true); }}
467
+ className="size-8 mx-auto"
468
+ >
469
+ <ListChecks className="size-4" />
470
+ </Button>
471
+ </TooltipTrigger>
472
+ <TooltipContent side="right">New Task</TooltipContent>
473
+ </Tooltip>
474
+ </TooltipProvider>
390
475
  </div>
391
476
  )}
392
477
  </SidebarHeader>
@@ -487,6 +572,136 @@ export function SessionsSidebar() {
487
572
  </DialogContent>
488
573
  </Dialog>
489
574
 
575
+ {/* New Task Dialog */}
576
+ <Dialog open={taskDialogOpen} onOpenChange={(open) => {
577
+ setTaskDialogOpen(open);
578
+ if (open) resetTaskForm();
579
+ }}>
580
+ <DialogContent className="sm:max-w-lg">
581
+ <DialogHeader>
582
+ <DialogTitle className="flex items-center gap-2">
583
+ <div className="size-8 rounded-lg bg-blue-600 flex items-center justify-center">
584
+ <ListChecks className="size-4 text-white" />
585
+ </div>
586
+ New Task
587
+ </DialogTitle>
588
+ </DialogHeader>
589
+ <div className="space-y-4 pt-2">
590
+ {/* Prompt — the most important field, given visual priority */}
591
+ <div className="space-y-1.5">
592
+ <Label htmlFor="task-prompt" className="text-sm font-medium">What should the agent do?</Label>
593
+ <Textarea
594
+ id="task-prompt"
595
+ placeholder="e.g. Refactor the auth module to use JWT tokens..."
596
+ value={taskPrompt}
597
+ onChange={(e) => setTaskPrompt(e.target.value)}
598
+ rows={3}
599
+ autoFocus
600
+ />
601
+ </div>
602
+
603
+ {/* Expected output shape */}
604
+ <div className="space-y-1.5">
605
+ <Label className="text-sm font-medium">Expected output shape</Label>
606
+ <p className="text-[11px] text-muted-foreground -mt-0.5">Define the JSON structure the agent must return</p>
607
+ <div className={cn(
608
+ "rounded-md border bg-muted/30 overflow-hidden transition-colors",
609
+ taskSchemaError && "border-red-500"
610
+ )}>
611
+ <VisualJson
612
+ value={taskSchema as any}
613
+ onChange={(v) => { setTaskSchema(v as Record<string, unknown>); setTaskSchemaError(''); }}
614
+ >
615
+ <TreeView className="h-44 text-sm" />
616
+ </VisualJson>
617
+ </div>
618
+ {taskSchemaError && (
619
+ <p className="text-xs text-red-500 mt-1">{taskSchemaError}</p>
620
+ )}
621
+ </div>
622
+
623
+ {/* Model + Name side by side */}
624
+ <div className="grid grid-cols-2 gap-3">
625
+ <div className="space-y-1.5">
626
+ <Label className="text-xs text-muted-foreground">Model</Label>
627
+ <Select value={taskModel} onValueChange={setTaskModel}>
628
+ <SelectTrigger className="h-9">
629
+ <SelectValue placeholder="Select a model" />
630
+ </SelectTrigger>
631
+ <SelectContent>
632
+ {config?.availableModels.map((model) => (
633
+ <SelectItem key={model.id} value={model.id}>
634
+ <div className="flex items-center gap-2">
635
+ <span>{model.name}</span>
636
+ <span className="text-xs text-muted-foreground">{model.provider}</span>
637
+ </div>
638
+ </SelectItem>
639
+ ))}
640
+ </SelectContent>
641
+ </Select>
642
+ </div>
643
+ <div className="space-y-1.5">
644
+ <Label htmlFor="task-name" className="text-xs text-muted-foreground">Name</Label>
645
+ <Input
646
+ id="task-name"
647
+ placeholder="Optional"
648
+ value={taskName}
649
+ onChange={(e) => setTaskName(e.target.value)}
650
+ className="h-9"
651
+ />
652
+ </div>
653
+ </div>
654
+
655
+ {/* Advanced — hidden by default */}
656
+ <details className="group">
657
+ <summary className="flex items-center gap-1.5 text-xs text-muted-foreground cursor-pointer select-none hover:text-foreground transition-colors">
658
+ <ChevronDown className="size-3 transition-transform group-open:rotate-180" />
659
+ Advanced
660
+ </summary>
661
+ <div className="grid grid-cols-2 gap-3 pt-3">
662
+ <div className="space-y-1.5">
663
+ <Label htmlFor="task-webhook" className="text-xs text-muted-foreground">Webhook URL</Label>
664
+ <Input
665
+ id="task-webhook"
666
+ placeholder="https://..."
667
+ value={taskWebhookUrl}
668
+ onChange={(e) => setTaskWebhookUrl(e.target.value)}
669
+ className="h-9"
670
+ />
671
+ </div>
672
+ <div className="space-y-1.5">
673
+ <Label htmlFor="task-iterations" className="text-xs text-muted-foreground">Max iterations</Label>
674
+ <Input
675
+ id="task-iterations"
676
+ type="number"
677
+ min={1}
678
+ max={500}
679
+ value={taskMaxIterations}
680
+ onChange={(e) => setTaskMaxIterations(e.target.value)}
681
+ className="h-9"
682
+ />
683
+ </div>
684
+ </div>
685
+ </details>
686
+
687
+ <Button
688
+ onClick={handleCreateTask}
689
+ disabled={creatingTask || !taskPrompt.trim()}
690
+ className="w-full"
691
+ >
692
+ {creatingTask ? (
693
+ <>
694
+ <Loader2 className="size-4 animate-spin mr-2" />
695
+ Creating...
696
+ </>
697
+ ) : (
698
+ 'Start Task'
699
+ )}
700
+ </Button>
701
+ </div>
702
+ </DialogContent>
703
+ </Dialog>
704
+
490
705
  {/* Sessions List */}
491
706
  <SidebarContent className="px-2">
492
707
  <SidebarGroup className="p-0">
@@ -598,7 +813,7 @@ export function SessionsSidebar() {
598
813
  <Badge
599
814
  variant="outline"
600
815
  className={cn(
601
- "shrink-0 text-[9px] px-1.5 py-0 h-4 font-medium",
816
+ "shrink-0 text-[10px] px-1.5 py-0 h-4 font-medium gap-1",
602
817
  session.config.task.status === 'completed' && "border-emerald-500/30 bg-emerald-500/10 text-emerald-600 dark:text-emerald-400",
603
818
  session.config.task.status === 'failed' && "border-red-500/30 bg-red-500/10 text-red-600 dark:text-red-400",
604
819
  session.config.task.status === 'running' && "border-blue-500/30 bg-blue-500/10 text-blue-600 dark:text-blue-400",
@@ -626,7 +841,7 @@ export function SessionsSidebar() {
626
841
  <TooltipContent side="right">Delete session</TooltipContent>
627
842
  </Tooltip>
628
843
  </TooltipProvider>
629
- ) : isRunning ? (
844
+ ) : isRunning && !session.config?.task?.enabled ? (
630
845
  <span className="inline-flex items-center gap-1 text-[10px] text-emerald-600 dark:text-emerald-400 shrink-0 font-medium">
631
846
  Active
632
847
  </span>
@@ -164,6 +164,23 @@ export async function deleteSession(id: string): Promise<void> {
164
164
  await fetch(`${getApiBase()}/sessions/${id}`, { method: 'DELETE' });
165
165
  }
166
166
 
167
+ // Tasks API
168
+ export async function createTask(params: {
169
+ prompt: string;
170
+ outputSchema: Record<string, unknown>;
171
+ webhookUrl?: string;
172
+ model?: string;
173
+ name?: string;
174
+ maxIterations?: number;
175
+ }): Promise<{ taskId: string; status: string }> {
176
+ const res = await fetch(`${getApiBase()}/tasks`, {
177
+ method: 'POST',
178
+ headers: { 'Content-Type': 'application/json' },
179
+ body: JSON.stringify(params),
180
+ });
181
+ return res.json();
182
+ }
183
+
167
184
  export async function getSessionTodos(sessionId: string): Promise<TodosResponse> {
168
185
  const res = await fetch(`${getApiBase()}/sessions/${sessionId}/todos`);
169
186
  return res.json();