stagent 0.1.9 → 0.1.11
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/README.md +144 -62
- package/package.json +1 -2
- package/public/readme/cost-usage-list.png +0 -0
- package/public/readme/dashboard-bulk-select.png +0 -0
- package/public/readme/dashboard-card-edit.png +0 -0
- package/public/readme/dashboard-create-form-ai-applied.png +0 -0
- package/public/readme/dashboard-create-form-ai-assist.png +0 -0
- package/public/readme/dashboard-create-form-empty.png +0 -0
- package/public/readme/dashboard-create-form-filled.png +0 -0
- package/public/readme/dashboard-filtered.png +0 -0
- package/public/readme/dashboard-list.png +0 -0
- package/public/readme/dashboard-sorted.png +0 -0
- package/public/readme/dashboard-workflow-confirm.png +0 -0
- package/public/readme/documents-grid.png +0 -0
- package/public/readme/documents-list.png +0 -0
- package/public/readme/home-below-fold.png +0 -0
- package/public/readme/home-list.png +0 -0
- package/public/readme/inbox-list.png +0 -0
- package/public/readme/monitor-list.png +0 -0
- package/public/readme/profiles-list.png +0 -0
- package/public/readme/projects-detail.png +0 -0
- package/public/readme/projects-list.png +0 -0
- package/public/readme/schedules-list.png +0 -0
- package/public/readme/settings-list.png +0 -0
- package/public/readme/workflows-list.png +0 -0
- package/src/app/api/profiles/route.ts +0 -1
- package/src/app/api/workflows/from-assist/route.ts +143 -0
- package/src/app/dashboard/page.tsx +24 -2
- package/src/app/globals.css +0 -5
- package/src/app/tasks/page.tsx +5 -0
- package/src/app/workflows/from-assist/page.tsx +35 -0
- package/src/components/profiles/profile-detail-view.tsx +1 -16
- package/src/components/profiles/profile-form-view.tsx +0 -22
- package/src/components/projects/project-card.tsx +47 -35
- package/src/components/tasks/ai-assist-panel.tsx +31 -10
- package/src/components/tasks/task-card.tsx +16 -1
- package/src/components/tasks/task-create-panel.tsx +39 -0
- package/src/components/workflows/workflow-confirmation-view.tsx +447 -0
- package/src/lib/agents/__tests__/claude-agent.test.ts +7 -2
- package/src/lib/agents/__tests__/learned-context.test.ts +500 -0
- package/src/lib/agents/__tests__/pattern-extractor.test.ts +243 -0
- package/src/lib/agents/__tests__/sweep.test.ts +202 -0
- package/src/lib/agents/claude-agent.ts +104 -78
- package/src/lib/agents/learned-context.ts +5 -13
- package/src/lib/agents/pattern-extractor.ts +15 -64
- package/src/lib/agents/profiles/__tests__/suggest.test.ts +67 -0
- package/src/lib/agents/profiles/builtins/code-reviewer/profile.yaml +0 -1
- package/src/lib/agents/profiles/builtins/data-analyst/profile.yaml +0 -1
- package/src/lib/agents/profiles/builtins/devops-engineer/profile.yaml +0 -1
- package/src/lib/agents/profiles/builtins/document-writer/profile.yaml +0 -1
- package/src/lib/agents/profiles/builtins/general/profile.yaml +0 -1
- package/src/lib/agents/profiles/builtins/health-fitness-coach/profile.yaml +0 -1
- package/src/lib/agents/profiles/builtins/learning-coach/profile.yaml +0 -1
- package/src/lib/agents/profiles/builtins/project-manager/profile.yaml +0 -1
- package/src/lib/agents/profiles/builtins/researcher/profile.yaml +0 -1
- package/src/lib/agents/profiles/builtins/shopping-assistant/profile.yaml +0 -1
- package/src/lib/agents/profiles/builtins/sweep/profile.yaml +0 -1
- package/src/lib/agents/profiles/builtins/technical-writer/profile.yaml +0 -1
- package/src/lib/agents/profiles/builtins/travel-planner/profile.yaml +0 -1
- package/src/lib/agents/profiles/builtins/wealth-manager/profile.yaml +0 -1
- package/src/lib/agents/profiles/registry.ts +0 -1
- package/src/lib/agents/profiles/suggest.ts +36 -0
- package/src/lib/agents/profiles/types.ts +0 -1
- package/src/lib/agents/runtime/catalog.ts +1 -1
- package/src/lib/agents/runtime/claude.ts +102 -6
- package/src/lib/agents/runtime/task-assist-types.ts +12 -2
- package/src/lib/constants/task-status.ts +6 -0
- package/src/lib/data/__tests__/clear.test.ts +42 -0
- package/src/lib/data/clear.ts +3 -0
- package/src/lib/data/seed-data/profiles.ts +0 -3
- package/src/lib/notifications/permissions.ts +6 -2
- package/src/lib/usage/__tests__/ledger.test.ts +29 -5
- package/src/lib/usage/ledger.ts +3 -1
- package/src/lib/usage/pricing.ts +61 -7
- package/src/lib/validators/__tests__/profile.test.ts +0 -15
- package/src/lib/validators/profile.ts +0 -1
- package/src/lib/workflows/__tests__/assist-builder.test.ts +255 -0
- package/src/lib/workflows/__tests__/engine.test.ts +2 -0
- package/src/lib/workflows/assist-builder.ts +248 -0
- package/src/lib/workflows/assist-session.ts +78 -0
- package/src/lib/workflows/engine.ts +47 -1
package/src/app/globals.css
CHANGED
|
@@ -446,11 +446,6 @@
|
|
|
446
446
|
box-shadow: var(--glass-shadow-sm);
|
|
447
447
|
}
|
|
448
448
|
|
|
449
|
-
/* Temperature slider gradient track */
|
|
450
|
-
.slider-temperature [data-slot="slider-range"] {
|
|
451
|
-
background: linear-gradient(90deg, oklch(0.6 0.18 260), oklch(0.7 0.15 55));
|
|
452
|
-
}
|
|
453
|
-
|
|
454
449
|
[data-slot="popover-content"],
|
|
455
450
|
[data-slot="dropdown-menu-content"],
|
|
456
451
|
[data-slot="select-content"] {
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import Link from "next/link";
|
|
2
|
+
import { db } from "@/lib/db";
|
|
3
|
+
import { projects } from "@/lib/db/schema";
|
|
4
|
+
import { Button } from "@/components/ui/button";
|
|
5
|
+
import { ArrowLeft } from "lucide-react";
|
|
6
|
+
import { WorkflowConfirmationView } from "@/components/workflows/workflow-confirmation-view";
|
|
7
|
+
import { listProfiles } from "@/lib/agents/profiles/registry";
|
|
8
|
+
|
|
9
|
+
export const dynamic = "force-dynamic";
|
|
10
|
+
|
|
11
|
+
export default async function WorkflowFromAssistPage() {
|
|
12
|
+
const allProjects = await db
|
|
13
|
+
.select({ id: projects.id, name: projects.name })
|
|
14
|
+
.from(projects)
|
|
15
|
+
.orderBy(projects.name);
|
|
16
|
+
|
|
17
|
+
const profiles = listProfiles().map((p) => ({
|
|
18
|
+
id: p.id,
|
|
19
|
+
name: p.name,
|
|
20
|
+
}));
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<div className="gradient-ocean-mist min-h-screen p-6">
|
|
24
|
+
<div>
|
|
25
|
+
<Link href="/tasks/new?restore=1">
|
|
26
|
+
<Button variant="ghost" size="sm" className="mb-4">
|
|
27
|
+
<ArrowLeft className="h-4 w-4 mr-1" />
|
|
28
|
+
Back to Task
|
|
29
|
+
</Button>
|
|
30
|
+
</Link>
|
|
31
|
+
<WorkflowConfirmationView projects={allProjects} profiles={profiles} />
|
|
32
|
+
</div>
|
|
33
|
+
</div>
|
|
34
|
+
);
|
|
35
|
+
}
|
|
@@ -18,7 +18,6 @@ import {
|
|
|
18
18
|
Sparkles,
|
|
19
19
|
Tag,
|
|
20
20
|
User,
|
|
21
|
-
Thermometer,
|
|
22
21
|
Repeat,
|
|
23
22
|
FileOutput,
|
|
24
23
|
Wrench,
|
|
@@ -262,20 +261,6 @@ export function ProfileDetailView({ profileId, isBuiltin, initialProfile }: Prof
|
|
|
262
261
|
<CardTitle className="text-sm font-medium">Configuration</CardTitle>
|
|
263
262
|
</CardHeader>
|
|
264
263
|
<CardContent className="space-y-3">
|
|
265
|
-
{/* Temperature Gauge */}
|
|
266
|
-
{profile.temperature !== undefined && (
|
|
267
|
-
<div className="flex items-center gap-2">
|
|
268
|
-
<Thermometer className="h-3.5 w-3.5 text-muted-foreground shrink-0" />
|
|
269
|
-
<span className="text-xs text-muted-foreground w-20">Temperature</span>
|
|
270
|
-
<div className="flex-1 h-1.5 rounded-full bg-muted">
|
|
271
|
-
<div
|
|
272
|
-
className="h-full rounded-full bg-primary"
|
|
273
|
-
style={{ width: `${(profile.temperature / 2) * 100}%` }}
|
|
274
|
-
/>
|
|
275
|
-
</div>
|
|
276
|
-
<span className="text-xs font-medium w-8 text-right">{profile.temperature}</span>
|
|
277
|
-
</div>
|
|
278
|
-
)}
|
|
279
264
|
{/* Max Turns */}
|
|
280
265
|
{profile.maxTurns !== undefined && (
|
|
281
266
|
<div className="flex items-center gap-2">
|
|
@@ -294,7 +279,7 @@ export function ProfileDetailView({ profileId, isBuiltin, initialProfile }: Prof
|
|
|
294
279
|
</Badge>
|
|
295
280
|
</div>
|
|
296
281
|
)}
|
|
297
|
-
{!profile.
|
|
282
|
+
{!profile.maxTurns && !profile.outputFormat && (
|
|
298
283
|
<p className="text-sm text-muted-foreground">Default configuration</p>
|
|
299
284
|
)}
|
|
300
285
|
</CardContent>
|
|
@@ -70,7 +70,6 @@ export function ProfileFormView({
|
|
|
70
70
|
]);
|
|
71
71
|
const [codexInstructions, setCodexInstructions] = useState("");
|
|
72
72
|
const [allowedTools, setAllowedTools] = useState("");
|
|
73
|
-
const [temperature, setTemperature] = useState(0.5);
|
|
74
73
|
const [maxTurns, setMaxTurns] = useState(30);
|
|
75
74
|
const [outputFormat, setOutputFormat] = useState("");
|
|
76
75
|
const [submitting, setSubmitting] = useState(false);
|
|
@@ -94,7 +93,6 @@ export function ProfileFormView({
|
|
|
94
93
|
profile.runtimeOverrides?.["openai-codex-app-server"]?.instructions ?? ""
|
|
95
94
|
);
|
|
96
95
|
setAllowedTools(profile.allowedTools?.join(", ") ?? "");
|
|
97
|
-
setTemperature(profile.temperature ?? 0.5);
|
|
98
96
|
setMaxTurns(profile.maxTurns ?? 30);
|
|
99
97
|
setOutputFormat(profile.outputFormat ?? "");
|
|
100
98
|
})
|
|
@@ -145,7 +143,6 @@ export function ProfileFormView({
|
|
|
145
143
|
}
|
|
146
144
|
: undefined,
|
|
147
145
|
allowedTools: parseCommaSeparated(allowedTools),
|
|
148
|
-
temperature,
|
|
149
146
|
maxTurns,
|
|
150
147
|
outputFormat: outputFormat.trim() || undefined,
|
|
151
148
|
};
|
|
@@ -307,25 +304,6 @@ export function ProfileFormView({
|
|
|
307
304
|
{/* Model Tuning */}
|
|
308
305
|
<FormSectionCard icon={SlidersHorizontal} title="Model Tuning">
|
|
309
306
|
<div className="space-y-4">
|
|
310
|
-
<div className="space-y-2">
|
|
311
|
-
<div className="flex items-center justify-between">
|
|
312
|
-
<Label htmlFor="profile-temp">Temperature</Label>
|
|
313
|
-
<Badge variant="secondary" className="tabular-nums text-xs">
|
|
314
|
-
{temperature.toFixed(2)}
|
|
315
|
-
</Badge>
|
|
316
|
-
</div>
|
|
317
|
-
<div className="slider-temperature">
|
|
318
|
-
<Slider
|
|
319
|
-
id="profile-temp"
|
|
320
|
-
min={0}
|
|
321
|
-
max={1}
|
|
322
|
-
step={0.05}
|
|
323
|
-
value={[temperature]}
|
|
324
|
-
onValueChange={([v]) => setTemperature(v)}
|
|
325
|
-
/>
|
|
326
|
-
</div>
|
|
327
|
-
<p className="text-xs text-muted-foreground">Lower = deterministic, higher = creative</p>
|
|
328
|
-
</div>
|
|
329
307
|
<div className="space-y-2">
|
|
330
308
|
<div className="flex items-center justify-between">
|
|
331
309
|
<Label htmlFor="profile-turns">Max Turns</Label>
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
+
import Link from "next/link";
|
|
3
4
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
|
4
5
|
import { Badge } from "@/components/ui/badge";
|
|
5
|
-
import {
|
|
6
|
+
import { Button } from "@/components/ui/button";
|
|
7
|
+
import { FolderKanban, FolderOpen, Pencil } from "lucide-react";
|
|
6
8
|
import { projectStatusVariant } from "@/lib/constants/status-colors";
|
|
7
9
|
|
|
8
10
|
interface ProjectCardProps {
|
|
@@ -19,40 +21,50 @@ interface ProjectCardProps {
|
|
|
19
21
|
|
|
20
22
|
export function ProjectCard({ project, onEdit }: ProjectCardProps) {
|
|
21
23
|
return (
|
|
22
|
-
<
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
<FolderKanban className="h-3 w-3" />
|
|
47
|
-
<span>{project.taskCount} tasks</span>
|
|
48
|
-
</div>
|
|
49
|
-
{project.workingDirectory && (
|
|
50
|
-
<div className="flex items-center gap-1 text-xs text-muted-foreground mt-1">
|
|
51
|
-
<FolderOpen className="h-3 w-3" />
|
|
52
|
-
<span className="truncate">{project.workingDirectory}</span>
|
|
24
|
+
<Link href={`/projects/${project.id}`} className="block">
|
|
25
|
+
<Card
|
|
26
|
+
tabIndex={0}
|
|
27
|
+
className="surface-card cursor-pointer transition-colors hover:bg-accent/50 focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 rounded-xl"
|
|
28
|
+
>
|
|
29
|
+
<CardHeader className="flex flex-row items-center justify-between pb-2">
|
|
30
|
+
<CardTitle className="text-base font-medium">{project.name}</CardTitle>
|
|
31
|
+
<div className="flex items-center gap-1.5">
|
|
32
|
+
<Button
|
|
33
|
+
variant="ghost"
|
|
34
|
+
size="icon"
|
|
35
|
+
className="h-7 w-7"
|
|
36
|
+
onClick={(e) => {
|
|
37
|
+
e.preventDefault();
|
|
38
|
+
e.stopPropagation();
|
|
39
|
+
onEdit(project.id, e.currentTarget);
|
|
40
|
+
}}
|
|
41
|
+
aria-label={`Edit ${project.name}`}
|
|
42
|
+
>
|
|
43
|
+
<Pencil className="h-3.5 w-3.5" />
|
|
44
|
+
</Button>
|
|
45
|
+
<Badge variant={projectStatusVariant[project.status] ?? "secondary"}>
|
|
46
|
+
{project.status}
|
|
47
|
+
</Badge>
|
|
53
48
|
</div>
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
49
|
+
</CardHeader>
|
|
50
|
+
<CardContent>
|
|
51
|
+
{project.description && (
|
|
52
|
+
<p className="text-sm text-muted-foreground line-clamp-2 mb-3">
|
|
53
|
+
{project.description}
|
|
54
|
+
</p>
|
|
55
|
+
)}
|
|
56
|
+
<div className="flex items-center gap-1 text-xs text-muted-foreground">
|
|
57
|
+
<FolderKanban className="h-3 w-3" />
|
|
58
|
+
<span>{project.taskCount} tasks</span>
|
|
59
|
+
</div>
|
|
60
|
+
{project.workingDirectory && (
|
|
61
|
+
<div className="flex items-center gap-1 text-xs text-muted-foreground mt-1">
|
|
62
|
+
<FolderOpen className="h-3 w-3" />
|
|
63
|
+
<span className="truncate">{project.workingDirectory}</span>
|
|
64
|
+
</div>
|
|
65
|
+
)}
|
|
66
|
+
</CardContent>
|
|
67
|
+
</Card>
|
|
68
|
+
</Link>
|
|
57
69
|
);
|
|
58
70
|
}
|
|
@@ -4,7 +4,7 @@ import { useState, useEffect } from "react";
|
|
|
4
4
|
import { Button } from "@/components/ui/button";
|
|
5
5
|
import { Card, CardContent } from "@/components/ui/card";
|
|
6
6
|
import { Badge } from "@/components/ui/badge";
|
|
7
|
-
import { Sparkles, Check, X } from "lucide-react";
|
|
7
|
+
import { Sparkles, Check, X, GitBranch } from "lucide-react";
|
|
8
8
|
|
|
9
9
|
interface TaskSuggestion {
|
|
10
10
|
title: string;
|
|
@@ -27,6 +27,7 @@ interface AIAssistPanelProps {
|
|
|
27
27
|
onApplyDescription: (description: string) => void;
|
|
28
28
|
onCreateSubtasks: (subtasks: TaskSuggestion[]) => void;
|
|
29
29
|
onResultChange?: (hasResult: boolean) => void;
|
|
30
|
+
onCreateWorkflow?: (result: AssistResult) => void;
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
const patternLabels: Record<string, string> = {
|
|
@@ -34,6 +35,9 @@ const patternLabels: Record<string, string> = {
|
|
|
34
35
|
sequence: "Sequence",
|
|
35
36
|
"planner-executor": "Planner → Executor",
|
|
36
37
|
checkpoint: "Human Checkpoint",
|
|
38
|
+
parallel: "Parallel",
|
|
39
|
+
loop: "Loop",
|
|
40
|
+
swarm: "Swarm",
|
|
37
41
|
};
|
|
38
42
|
|
|
39
43
|
const complexityColors: Record<string, string> = {
|
|
@@ -88,6 +92,7 @@ export function AIAssistPanel({
|
|
|
88
92
|
onApplyDescription,
|
|
89
93
|
onCreateSubtasks,
|
|
90
94
|
onResultChange,
|
|
95
|
+
onCreateWorkflow,
|
|
91
96
|
}: AIAssistPanelProps) {
|
|
92
97
|
const [loading, setLoading] = useState(false);
|
|
93
98
|
const [result, setResult] = useState<AssistResult | null>(null);
|
|
@@ -205,15 +210,31 @@ export function AIAssistPanel({
|
|
|
205
210
|
<span className="text-xs font-medium text-muted-foreground">
|
|
206
211
|
Suggested Breakdown ({result.breakdown.length} sub-tasks)
|
|
207
212
|
</span>
|
|
208
|
-
<
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
213
|
+
<div className="flex gap-1">
|
|
214
|
+
{onCreateWorkflow &&
|
|
215
|
+
result.breakdown.length >= 2 &&
|
|
216
|
+
result.recommendedPattern !== "single" && (
|
|
217
|
+
<Button
|
|
218
|
+
type="button"
|
|
219
|
+
variant="ghost"
|
|
220
|
+
size="sm"
|
|
221
|
+
className="h-6 text-xs"
|
|
222
|
+
onClick={() => onCreateWorkflow(result)}
|
|
223
|
+
>
|
|
224
|
+
<GitBranch className="h-3 w-3 mr-1" />
|
|
225
|
+
Workflow
|
|
226
|
+
</Button>
|
|
227
|
+
)}
|
|
228
|
+
<Button
|
|
229
|
+
type="button"
|
|
230
|
+
variant="ghost"
|
|
231
|
+
size="sm"
|
|
232
|
+
className="h-6 text-xs"
|
|
233
|
+
onClick={() => onCreateSubtasks(result.breakdown)}
|
|
234
|
+
>
|
|
235
|
+
Create All
|
|
236
|
+
</Button>
|
|
237
|
+
</div>
|
|
217
238
|
</div>
|
|
218
239
|
<div className="max-h-60 overflow-y-auto space-y-1.5">
|
|
219
240
|
{result.breakdown.map((sub, i) => (
|
|
@@ -5,7 +5,7 @@ import { useSortable } from "@dnd-kit/sortable";
|
|
|
5
5
|
import { CSS } from "@dnd-kit/utilities";
|
|
6
6
|
import { Card } from "@/components/ui/card";
|
|
7
7
|
import { Badge } from "@/components/ui/badge";
|
|
8
|
-
import { AlertCircle, Bot, ArrowUp, ArrowDown, Minus, Trash2, Check, X, Loader2, Square, CheckSquare, Pencil } from "lucide-react";
|
|
8
|
+
import { AlertCircle, Bot, ArrowUp, ArrowDown, Minus, Trash2, Check, X, Loader2, Square, CheckSquare, Pencil, Workflow } from "lucide-react";
|
|
9
9
|
import type { TaskStatus } from "@/lib/constants/task-status";
|
|
10
10
|
|
|
11
11
|
export interface TaskItem {
|
|
@@ -18,6 +18,8 @@ export interface TaskItem {
|
|
|
18
18
|
agentProfile: string | null;
|
|
19
19
|
projectId: string | null;
|
|
20
20
|
projectName?: string;
|
|
21
|
+
linkedWorkflowId?: string;
|
|
22
|
+
linkedWorkflowStatus?: string;
|
|
21
23
|
result: string | null;
|
|
22
24
|
sessionId: string | null;
|
|
23
25
|
resumeCount: number;
|
|
@@ -151,6 +153,19 @@ export function TaskCard({
|
|
|
151
153
|
<span className="truncate">{task.assignedAgent}</span>
|
|
152
154
|
</Badge>
|
|
153
155
|
)}
|
|
156
|
+
{task.linkedWorkflowId && (
|
|
157
|
+
<Badge
|
|
158
|
+
variant="outline"
|
|
159
|
+
className="text-xs gap-1 cursor-pointer hover:bg-accent/50"
|
|
160
|
+
onClick={(e) => {
|
|
161
|
+
e.stopPropagation();
|
|
162
|
+
window.open(`/workflows/${task.linkedWorkflowId}`, "_self");
|
|
163
|
+
}}
|
|
164
|
+
>
|
|
165
|
+
<Workflow className="h-3 w-3 shrink-0" aria-hidden="true" />
|
|
166
|
+
{task.linkedWorkflowStatus === "completed" ? "Workflow done" : "Workflow"}
|
|
167
|
+
</Badge>
|
|
168
|
+
)}
|
|
154
169
|
{isFailed && <AlertCircle className="h-3.5 w-3.5 text-destructive" aria-label="Task failed" />}
|
|
155
170
|
{isRunning && (
|
|
156
171
|
<span className="flex h-2 w-2" aria-label="Task running">
|
|
@@ -18,7 +18,13 @@ import { Bot, FileText, Settings, Paperclip } from "lucide-react";
|
|
|
18
18
|
import { toast } from "sonner";
|
|
19
19
|
import { AIAssistPanel } from "./ai-assist-panel";
|
|
20
20
|
import { FileUpload } from "./file-upload";
|
|
21
|
+
import type { TaskAssistResponse } from "@/lib/agents/runtime/task-assist-types";
|
|
21
22
|
import { FormSectionCard } from "@/components/shared/form-section-card";
|
|
23
|
+
import {
|
|
24
|
+
saveAssistState,
|
|
25
|
+
loadTaskFormState,
|
|
26
|
+
clearTaskFormState,
|
|
27
|
+
} from "@/lib/workflows/assist-session";
|
|
22
28
|
import {
|
|
23
29
|
type AgentRuntimeId,
|
|
24
30
|
DEFAULT_AGENT_RUNTIME,
|
|
@@ -79,6 +85,24 @@ export function TaskCreatePanel({ projects, defaultProjectId }: TaskCreatePanelP
|
|
|
79
85
|
.catch(() => {});
|
|
80
86
|
}, []);
|
|
81
87
|
|
|
88
|
+
// Restore form state when returning from workflow confirmation
|
|
89
|
+
useEffect(() => {
|
|
90
|
+
const params = new URLSearchParams(window.location.search);
|
|
91
|
+
if (params.get("restore") !== "1") return;
|
|
92
|
+
const saved = loadTaskFormState();
|
|
93
|
+
if (saved) {
|
|
94
|
+
setTitle(saved.title);
|
|
95
|
+
setDescription(saved.description);
|
|
96
|
+
setProjectId(saved.projectId);
|
|
97
|
+
setPriority(saved.priority);
|
|
98
|
+
setAgentProfile(saved.agentProfile);
|
|
99
|
+
setAssignedAgent(saved.assignedAgent);
|
|
100
|
+
clearTaskFormState();
|
|
101
|
+
}
|
|
102
|
+
// Clean up URL param without triggering navigation
|
|
103
|
+
window.history.replaceState({}, "", window.location.pathname);
|
|
104
|
+
}, []);
|
|
105
|
+
|
|
82
106
|
const selectedRuntimeId = (assignedAgent ||
|
|
83
107
|
DEFAULT_AGENT_RUNTIME) as AgentRuntimeId;
|
|
84
108
|
const selectedProfile = profiles.find((profile) => profile.id === agentProfile);
|
|
@@ -351,8 +375,23 @@ export function TaskCreatePanel({ projects, defaultProjectId }: TaskCreatePanelP
|
|
|
351
375
|
}
|
|
352
376
|
router.push("/dashboard");
|
|
353
377
|
}}
|
|
378
|
+
onCreateWorkflow={(result) => {
|
|
379
|
+
saveAssistState({
|
|
380
|
+
assistResult: result as TaskAssistResponse,
|
|
381
|
+
formState: {
|
|
382
|
+
title,
|
|
383
|
+
description,
|
|
384
|
+
projectId,
|
|
385
|
+
priority,
|
|
386
|
+
agentProfile,
|
|
387
|
+
assignedAgent,
|
|
388
|
+
},
|
|
389
|
+
});
|
|
390
|
+
router.push("/workflows/from-assist");
|
|
391
|
+
}}
|
|
354
392
|
/>
|
|
355
393
|
</div>
|
|
394
|
+
|
|
356
395
|
</div>
|
|
357
396
|
</form>
|
|
358
397
|
</CardContent>
|