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.
- package/dist/agent/index.d.ts +3 -3
- package/dist/agent/index.js +16 -3
- package/dist/agent/index.js.map +1 -1
- package/dist/cli.js +16 -3
- package/dist/cli.js.map +1 -1
- package/dist/db/index.d.ts +2 -2
- package/dist/{index-DuGtMaAJ.d.ts → index-Dn-eCGLe.d.ts} +25 -25
- package/dist/index.d.ts +5 -5
- package/dist/index.js +16 -3
- package/dist/index.js.map +1 -1
- package/dist/{schema-C7Mm4Ykn.d.ts → schema-XcP0dedO.d.ts} +3 -3
- package/dist/{search-C_IFImt1.d.ts → search-DINnDTgj.d.ts} +4 -4
- package/dist/server/index.js +16 -3
- package/dist/server/index.js.map +1 -1
- package/dist/tools/index.d.ts +2 -2
- package/package.json +1 -1
- package/web/.next/BUILD_ID +1 -1
- package/web/.next/standalone/web/.next/BUILD_ID +1 -1
- package/web/.next/standalone/web/.next/build-manifest.json +2 -2
- package/web/.next/standalone/web/.next/prerender-manifest.json +3 -3
- package/web/.next/standalone/web/.next/server/app/(main)/page.js.nft.json +1 -1
- package/web/.next/standalone/web/.next/server/app/(main)/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/app/(main)/session/[id]/page.js.nft.json +1 -1
- package/web/.next/standalone/web/.next/server/app/(main)/session/[id]/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/app/_global-error.html +2 -2
- package/web/.next/standalone/web/.next/server/app/_global-error.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.html +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/installation/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/installation.html +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/installation.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_full.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_index.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/_tree.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs/installation.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/installation.segments/docs.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills.html +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/skills.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_full.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_index.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/_tree.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs/skills.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/skills.segments/docs.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools.html +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/tools.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_full.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_index.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/_tree.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs/tools.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs/tools.segments/docs.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs.html +2 -2
- package/web/.next/standalone/web/.next/server/app/docs.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs.segments/_full.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs.segments/_index.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs.segments/_tree.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/docs.segments/docs/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/docs.segments/docs.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/embed/[id]/page.js.nft.json +1 -1
- package/web/.next/standalone/web/.next/server/app/embed/[id]/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/app/index.html +1 -1
- package/web/.next/standalone/web/.next/server/app/index.rsc +4 -4
- package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p/__PAGE__.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/index.segments/!KG1haW4p.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/index.segments/_full.segment.rsc +4 -4
- package/web/.next/standalone/web/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/web/.next/server/app/index.segments/_index.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/app/index.segments/_tree.segment.rsc +2 -2
- package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_e19eaecc._.js → 2374f_04a544c8._.js} +1 -1
- package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_0d0b1fb9._.js → 2374f_45534372._.js} +1 -1
- package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_03d22c16._.js → 2374f_5c78460e._.js} +1 -1
- package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_6166d14d._.js → 2374f_5d0b3394._.js} +1 -1
- package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_b98835eb._.js → 2374f_5e9eb6da._.js} +1 -1
- package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_3f7d6d28._.js → 2374f_68abddfe._.js} +1 -1
- package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_99b7b533._.js → 2374f_72fb9db7._.js} +1 -1
- package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_6b436efc._.js → 2374f_ab5b97d8._.js} +1 -1
- package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_e3aec189._.js → 2374f_bfc8ef7d._.js} +1 -1
- package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_a1a36483._.js → 2374f_c61a33b3._.js} +1 -1
- package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_976b2ded._.js → 2374f_d5f5b9ba._.js} +1 -1
- package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_67b9525f._.js → 2374f_db790cfe._.js} +1 -1
- package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_98eba491._.js → 2374f_de60e6ea._.js} +1 -1
- package/web/.next/standalone/web/.next/server/chunks/ssr/{2374f_784d851c._.js → 2374f_e366206f._.js} +1 -1
- package/web/.next/standalone/web/.next/server/chunks/ssr/{[root-of-the-server]__4f176a16._.js → [root-of-the-server]__aa788b85._.js} +2 -2
- package/web/.next/standalone/web/.next/server/chunks/ssr/{[root-of-the-server]__d59f831d._.js → [root-of-the-server]__d04c460d._.js} +4 -4
- package/web/.next/standalone/web/.next/server/chunks/ssr/web_08bbd8c8._.js +7 -0
- package/web/.next/standalone/web/.next/server/chunks/ssr/web_2b3a5919._.js +1 -1
- package/web/.next/standalone/web/.next/server/chunks/ssr/web_38156da8._.js +1 -1
- package/web/.next/standalone/web/.next/server/chunks/ssr/{web_693f514e._.js → web_6fb589ac._.js} +2 -2
- package/web/.next/standalone/web/.next/server/chunks/ssr/{web_dc6ce793._.js → web_c729ad51._.js} +2 -2
- package/web/.next/standalone/web/.next/server/chunks/ssr/web_src_components_sessions-sidebar_tsx_92510070._.js +1 -1
- package/web/.next/standalone/web/.next/server/pages/404.html +1 -1
- package/web/.next/standalone/web/.next/server/pages/500.html +2 -2
- package/web/.next/standalone/web/.next/server/server-reference-manifest.js +1 -1
- package/web/.next/standalone/web/.next/server/server-reference-manifest.json +1 -1
- package/web/.next/standalone/web/.next/static/chunks/{81685e5e8be4eac9.js → 054deec0c7b19894.js} +3 -3
- package/web/.next/standalone/web/.next/static/chunks/1ebba7ac024244f9.js +5 -0
- package/web/.next/{static/chunks/0358a0e7a40cfb93.css → standalone/web/.next/static/chunks/1f42a42914068041.css} +1 -1
- package/web/.next/standalone/web/.next/static/chunks/26eb5fab5216f3cc.js +1 -0
- package/web/.next/standalone/web/.next/static/chunks/{95436454a7559b0d.js → 5383c5717758f575.js} +3 -3
- package/web/.next/standalone/web/.next/static/chunks/{20e0fa99c7a1c1fc.js → 7fb141141caa4fac.js} +5 -5
- package/web/.next/standalone/web/.next/static/chunks/c6f40df16a9396b9.js +1 -0
- package/web/.next/standalone/web/.next/static/chunks/ea29be392100ab0f.js +5 -0
- package/web/.next/{static/chunks/294ebe8457006bce.js → standalone/web/.next/static/chunks/eea48be65cdb3f4b.js} +2 -2
- package/web/.next/{static/chunks/81685e5e8be4eac9.js → standalone/web/.next/static/static/chunks/054deec0c7b19894.js} +3 -3
- package/web/.next/standalone/web/.next/static/static/chunks/1ebba7ac024244f9.js +5 -0
- package/web/.next/standalone/web/.next/static/static/chunks/{0358a0e7a40cfb93.css → 1f42a42914068041.css} +1 -1
- package/web/.next/standalone/web/.next/static/static/chunks/26eb5fab5216f3cc.js +1 -0
- package/web/.next/standalone/web/.next/static/static/chunks/{95436454a7559b0d.js → 5383c5717758f575.js} +3 -3
- package/web/.next/standalone/web/.next/static/static/chunks/{20e0fa99c7a1c1fc.js → 7fb141141caa4fac.js} +5 -5
- package/web/.next/standalone/web/.next/static/static/chunks/c6f40df16a9396b9.js +1 -0
- package/web/.next/standalone/web/.next/static/static/chunks/ea29be392100ab0f.js +5 -0
- package/web/.next/standalone/web/.next/static/static/chunks/{294ebe8457006bce.js → eea48be65cdb3f4b.js} +2 -2
- package/web/.next/standalone/web/package-lock.json +20 -0
- package/web/.next/standalone/web/package.json +2 -0
- package/web/.next/standalone/web/src/components/ai-elements/complete-task-tool.tsx +36 -60
- package/web/.next/standalone/web/src/components/chat-interface.tsx +36 -32
- package/web/.next/standalone/web/src/components/sessions-sidebar.tsx +231 -16
- package/web/.next/standalone/web/src/lib/api.ts +17 -0
- package/web/.next/{standalone/web/.next/static/static/chunks/81685e5e8be4eac9.js → static/chunks/054deec0c7b19894.js} +3 -3
- package/web/.next/static/chunks/1ebba7ac024244f9.js +5 -0
- package/web/.next/{standalone/web/.next/static/chunks/0358a0e7a40cfb93.css → static/chunks/1f42a42914068041.css} +1 -1
- package/web/.next/static/chunks/26eb5fab5216f3cc.js +1 -0
- package/web/.next/static/chunks/{95436454a7559b0d.js → 5383c5717758f575.js} +3 -3
- package/web/.next/static/chunks/{20e0fa99c7a1c1fc.js → 7fb141141caa4fac.js} +5 -5
- package/web/.next/static/chunks/c6f40df16a9396b9.js +1 -0
- package/web/.next/static/chunks/ea29be392100ab0f.js +5 -0
- package/web/.next/{standalone/web/.next/static/chunks/294ebe8457006bce.js → static/chunks/eea48be65cdb3f4b.js} +2 -2
- package/web/package.json +2 -0
- package/web/.next/standalone/web/.next/server/chunks/ssr/web_a42a2651._.js +0 -7
- package/web/.next/standalone/web/.next/static/chunks/1ecde4c0d426a635.js +0 -1
- package/web/.next/standalone/web/.next/static/chunks/36688a049d72e8ab.js +0 -5
- package/web/.next/standalone/web/.next/static/chunks/a751ca474cc46212.js +0 -5
- package/web/.next/standalone/web/.next/static/static/chunks/1ecde4c0d426a635.js +0 -1
- package/web/.next/standalone/web/.next/static/static/chunks/36688a049d72e8ab.js +0 -5
- package/web/.next/standalone/web/.next/static/static/chunks/a751ca474cc46212.js +0 -5
- package/web/.next/static/chunks/1ecde4c0d426a635.js +0 -1
- package/web/.next/static/chunks/36688a049d72e8ab.js +0 -5
- package/web/.next/static/chunks/a751ca474cc46212.js +0 -5
- /package/web/.next/standalone/web/.next/static/{8zJH-RqrUQ3scBGbdaCmn → Xc8ztiG5d6CHUNHm_1G8b}/_buildManifest.js +0 -0
- /package/web/.next/standalone/web/.next/static/{8zJH-RqrUQ3scBGbdaCmn → Xc8ztiG5d6CHUNHm_1G8b}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/standalone/web/.next/static/{8zJH-RqrUQ3scBGbdaCmn → Xc8ztiG5d6CHUNHm_1G8b}/_ssgManifest.js +0 -0
- /package/web/.next/standalone/web/.next/static/static/{8zJH-RqrUQ3scBGbdaCmn → Xc8ztiG5d6CHUNHm_1G8b}/_buildManifest.js +0 -0
- /package/web/.next/standalone/web/.next/static/static/{8zJH-RqrUQ3scBGbdaCmn → Xc8ztiG5d6CHUNHm_1G8b}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/standalone/web/.next/static/static/{8zJH-RqrUQ3scBGbdaCmn → Xc8ztiG5d6CHUNHm_1G8b}/_ssgManifest.js +0 -0
- /package/web/.next/static/{8zJH-RqrUQ3scBGbdaCmn → Xc8ztiG5d6CHUNHm_1G8b}/_buildManifest.js +0 -0
- /package/web/.next/static/{8zJH-RqrUQ3scBGbdaCmn → Xc8ztiG5d6CHUNHm_1G8b}/_clientMiddlewareManifest.json +0 -0
- /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
|
|
6
|
-
import {
|
|
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
|
|
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-
|
|
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
|
|
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
|
-
? "
|
|
47
|
+
? "Schema mismatch"
|
|
48
48
|
: isComplete
|
|
49
|
-
? "Task
|
|
50
|
-
: "Task
|
|
49
|
+
? "Task completed"
|
|
50
|
+
: "Task failed"}
|
|
51
51
|
</span>
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
"ml-auto text-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
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
|
|
68
|
-
{/*
|
|
63
|
+
<div className="p-4">
|
|
64
|
+
{/* Completed — show result tree */}
|
|
69
65
|
{isComplete && input.result && (
|
|
70
|
-
<div className="
|
|
71
|
-
<
|
|
72
|
-
|
|
73
|
-
</
|
|
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
|
-
<
|
|
85
|
-
|
|
86
|
-
|
|
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-
|
|
97
|
-
<
|
|
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-
|
|
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-
|
|
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
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
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
|
-
{
|
|
2674
|
-
</
|
|
2675
|
-
{
|
|
2676
|
-
<span className="text-xs text-muted-foreground ml-auto">
|
|
2677
|
-
{
|
|
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
|
-
|
|
2682
|
-
|
|
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
|
-
<
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
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-[
|
|
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();
|