stagent 0.1.11 → 0.1.13
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 +74 -49
- package/package.json +3 -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-workflow-confirm.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/playbook-list.png +0 -0
- package/public/readme/profiles-list.png +0 -0
- package/public/readme/settings-list.png +0 -0
- package/public/readme/workflows-list.png +0 -0
- package/src/__tests__/e2e/blueprint.test.ts +63 -0
- package/src/__tests__/e2e/cross-runtime.test.ts +77 -0
- package/src/__tests__/e2e/helpers.ts +286 -0
- package/src/__tests__/e2e/parallel-workflow.test.ts +120 -0
- package/src/__tests__/e2e/sequence-workflow.test.ts +109 -0
- package/src/__tests__/e2e/setup.ts +156 -0
- package/src/__tests__/e2e/single-task.test.ts +170 -0
- package/src/app/api/command-palette/recent/route.ts +41 -18
- package/src/app/api/context/batch/route.ts +44 -0
- package/src/app/api/permissions/presets/route.ts +80 -0
- package/src/app/api/playbook/status/route.ts +15 -0
- package/src/app/api/profiles/route.ts +23 -20
- package/src/app/api/settings/pricing/route.ts +15 -0
- package/src/app/api/tasks/[id]/route.ts +54 -3
- package/src/app/api/workflows/[id]/route.ts +43 -4
- package/src/app/api/workflows/[id]/status/route.ts +70 -2
- package/src/app/api/workflows/from-assist/route.ts +6 -32
- package/src/app/costs/page.tsx +53 -43
- package/src/app/dashboard/page.tsx +59 -21
- package/src/app/documents/[id]/page.tsx +10 -8
- package/src/app/globals.css +11 -0
- package/src/app/page.tsx +60 -3
- package/src/app/playbook/[slug]/page.tsx +76 -0
- package/src/app/playbook/page.tsx +54 -0
- package/src/app/profiles/page.tsx +7 -4
- package/src/app/settings/page.tsx +2 -2
- package/src/app/tasks/[id]/page.tsx +22 -2
- package/src/components/costs/cost-dashboard.tsx +226 -320
- package/src/components/dashboard/activity-feed.tsx +6 -2
- package/src/components/dashboard/greeting.tsx +3 -1
- package/src/components/dashboard/priority-queue.tsx +58 -9
- package/src/components/dashboard/stats-cards.tsx +16 -2
- package/src/components/documents/document-chip-bar.tsx +183 -0
- package/src/components/documents/document-content-renderer.tsx +146 -0
- package/src/components/documents/document-detail-view.tsx +16 -239
- package/src/components/documents/image-zoom-view.tsx +60 -0
- package/src/components/documents/smart-extracted-text.tsx +47 -0
- package/src/components/documents/utils.ts +70 -0
- package/src/components/notifications/batch-proposal-review.tsx +150 -0
- package/src/components/notifications/inbox-list.tsx +4 -5
- package/src/components/notifications/notification-item.tsx +73 -6
- package/src/components/notifications/pending-approval-host.tsx +63 -14
- package/src/components/playbook/adoption-heatmap.tsx +69 -0
- package/src/components/playbook/journey-card.tsx +110 -0
- package/src/components/playbook/playbook-action-button.tsx +22 -0
- package/src/components/playbook/playbook-browser.tsx +143 -0
- package/src/components/playbook/playbook-card.tsx +102 -0
- package/src/components/playbook/playbook-detail-view.tsx +225 -0
- package/src/components/playbook/playbook-homepage.tsx +142 -0
- package/src/components/playbook/playbook-toc.tsx +90 -0
- package/src/components/playbook/playbook-updated-badge.tsx +23 -0
- package/src/components/playbook/related-docs.tsx +30 -0
- package/src/components/profiles/__tests__/learned-context-panel.test.tsx +175 -0
- package/src/components/profiles/context-proposal-review.tsx +7 -3
- package/src/components/profiles/learned-context-panel.tsx +116 -8
- package/src/components/profiles/profile-browser.tsx +1 -0
- package/src/components/profiles/profile-card.tsx +16 -8
- package/src/components/profiles/profile-detail-view.tsx +12 -4
- package/src/components/settings/__tests__/auth-config-section.test.tsx +147 -0
- package/src/components/settings/api-key-form.tsx +5 -43
- package/src/components/settings/auth-config-section.tsx +10 -6
- package/src/components/settings/auth-status-badge.tsx +8 -0
- package/src/components/settings/budget-guardrails-section.tsx +403 -620
- package/src/components/settings/connection-test-control.tsx +63 -0
- package/src/components/settings/permissions-section.tsx +85 -75
- package/src/components/settings/permissions-sections.tsx +24 -0
- package/src/components/settings/presets-section.tsx +159 -0
- package/src/components/settings/pricing-registry-panel.tsx +164 -0
- package/src/components/shared/app-sidebar.tsx +4 -2
- package/src/components/shared/command-palette.tsx +30 -0
- package/src/components/shared/light-markdown.tsx +134 -0
- package/src/components/tasks/__tests__/kanban-board-accessibility.test.tsx +1 -1
- package/src/components/tasks/ai-assist-panel.tsx +108 -78
- package/src/components/tasks/content-preview.tsx +2 -1
- package/src/components/tasks/kanban-board.tsx +57 -5
- package/src/components/tasks/kanban-column.tsx +34 -23
- package/src/components/tasks/task-bento-cell.tsx +50 -0
- package/src/components/tasks/task-bento-grid.tsx +155 -0
- package/src/components/tasks/task-card.tsx +14 -16
- package/src/components/tasks/task-chip-bar.tsx +207 -0
- package/src/components/tasks/task-detail-view.tsx +42 -190
- package/src/components/tasks/task-result-renderer.tsx +33 -0
- package/src/components/workflows/blueprint-gallery.tsx +19 -12
- package/src/components/workflows/blueprint-preview.tsx +8 -1
- package/src/components/workflows/loop-status-view.tsx +2 -4
- package/src/components/workflows/swarm-dashboard.tsx +2 -3
- package/src/components/workflows/workflow-confirmation-view.tsx +2 -7
- package/src/components/workflows/workflow-full-output.tsx +80 -0
- package/src/components/workflows/workflow-kanban-card.tsx +121 -0
- package/src/components/workflows/workflow-list.tsx +47 -42
- package/src/components/workflows/workflow-status-view.tsx +163 -16
- package/src/lib/agents/learned-context.ts +27 -15
- package/src/lib/agents/learning-session.ts +354 -0
- package/src/lib/agents/pattern-extractor.ts +19 -0
- package/src/lib/agents/profiles/__tests__/sort.test.ts +42 -0
- package/src/lib/agents/profiles/sort.ts +7 -0
- package/src/lib/constants/card-icons.tsx +202 -0
- package/src/lib/constants/prose-styles.ts +7 -0
- package/src/lib/constants/settings.ts +1 -0
- package/src/lib/constants/task-status.ts +3 -0
- package/src/lib/db/schema.ts +3 -0
- package/src/lib/docs/adoption.ts +105 -0
- package/src/lib/docs/journey-tracker.ts +21 -0
- package/src/lib/docs/reader.ts +107 -0
- package/src/lib/docs/types.ts +54 -0
- package/src/lib/docs/usage-stage.ts +60 -0
- package/src/lib/documents/context-builder.ts +41 -0
- package/src/lib/notifications/actionable.ts +18 -10
- package/src/lib/queries/chart-data.ts +20 -1
- package/src/lib/settings/__tests__/budget-guardrails.test.ts +86 -24
- package/src/lib/settings/budget-guardrails.ts +213 -85
- package/src/lib/settings/permission-presets.ts +150 -0
- package/src/lib/settings/runtime-setup.ts +71 -0
- package/src/lib/usage/__tests__/ledger.test.ts +2 -2
- package/src/lib/usage/__tests__/pricing-registry.test.ts +78 -0
- package/src/lib/usage/ledger.ts +1 -1
- package/src/lib/usage/pricing-registry.ts +570 -0
- package/src/lib/usage/pricing.ts +15 -95
- package/src/lib/utils/__tests__/learned-context-history.test.ts +171 -0
- package/src/lib/utils/learned-context-history.ts +150 -0
- package/src/lib/validators/__tests__/settings.test.ts +23 -16
- package/src/lib/validators/settings.ts +3 -9
- package/src/lib/workflows/engine.ts +75 -61
- package/src/lib/workflows/types.ts +2 -0
- package/tsconfig.json +2 -1
- package/src/components/documents/document-preview.tsx +0 -68
|
@@ -11,6 +11,7 @@ import { EmptyState } from "@/components/shared/empty-state";
|
|
|
11
11
|
import { GitBranch, Plus, Pencil, Copy, RotateCcw, Trash2, Layers } from "lucide-react";
|
|
12
12
|
import { toast } from "sonner";
|
|
13
13
|
import { workflowStatusVariant, patternLabels } from "@/lib/constants/status-colors";
|
|
14
|
+
import { IconCircle, getWorkflowIconFromName } from "@/lib/constants/card-icons";
|
|
14
15
|
|
|
15
16
|
interface Workflow {
|
|
16
17
|
id: string;
|
|
@@ -137,6 +138,7 @@ export function WorkflowList({ projects }: WorkflowListProps) {
|
|
|
137
138
|
const pattern = getPattern(wf.definition);
|
|
138
139
|
const stepCount = getStepCount(wf.definition);
|
|
139
140
|
const promptPreview = getPromptPreview(wf.definition);
|
|
141
|
+
const wfIcon = getWorkflowIconFromName(wf.name, pattern);
|
|
140
142
|
return (
|
|
141
143
|
<Card
|
|
142
144
|
key={wf.id}
|
|
@@ -146,11 +148,9 @@ export function WorkflowList({ projects }: WorkflowListProps) {
|
|
|
146
148
|
onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") { e.preventDefault(); router.push(`/workflows/${wf.id}`); } }}
|
|
147
149
|
>
|
|
148
150
|
<CardHeader className="pb-2">
|
|
149
|
-
<div className="flex items-center
|
|
150
|
-
<
|
|
151
|
-
<
|
|
152
|
-
{wf.status}
|
|
153
|
-
</Badge>
|
|
151
|
+
<div className="flex items-center gap-3">
|
|
152
|
+
<IconCircle icon={wfIcon.icon} colors={wfIcon.colors} />
|
|
153
|
+
<CardTitle className="min-w-0 truncate text-base font-medium">{wf.name}</CardTitle>
|
|
154
154
|
</div>
|
|
155
155
|
</CardHeader>
|
|
156
156
|
<CardContent>
|
|
@@ -164,49 +164,54 @@ export function WorkflowList({ projects }: WorkflowListProps) {
|
|
|
164
164
|
{promptPreview}
|
|
165
165
|
</p>
|
|
166
166
|
)}
|
|
167
|
-
<div className="flex items-center
|
|
168
|
-
{wf.status
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
aria-label="Clone workflow"
|
|
184
|
-
onClick={(e) => { e.stopPropagation(); router.push(`/workflows/${wf.id}/edit?clone=true`); }}
|
|
185
|
-
>
|
|
186
|
-
<Copy className="h-3.5 w-3.5" />
|
|
187
|
-
</Button>
|
|
188
|
-
{(wf.status === "completed" || wf.status === "failed") && (
|
|
167
|
+
<div className="flex items-center justify-between mt-3">
|
|
168
|
+
<Badge variant={workflowStatusVariant[wf.status] ?? "secondary"}>
|
|
169
|
+
{wf.status}
|
|
170
|
+
</Badge>
|
|
171
|
+
<div className="flex items-center gap-1">
|
|
172
|
+
{wf.status === "draft" && (
|
|
173
|
+
<Button
|
|
174
|
+
variant="ghost"
|
|
175
|
+
size="icon"
|
|
176
|
+
className="h-7 w-7"
|
|
177
|
+
aria-label="Edit workflow"
|
|
178
|
+
onClick={(e) => { e.stopPropagation(); router.push(`/workflows/${wf.id}/edit`); }}
|
|
179
|
+
>
|
|
180
|
+
<Pencil className="h-3.5 w-3.5" />
|
|
181
|
+
</Button>
|
|
182
|
+
)}
|
|
189
183
|
<Button
|
|
190
184
|
variant="ghost"
|
|
191
185
|
size="icon"
|
|
192
186
|
className="h-7 w-7"
|
|
193
|
-
aria-label="
|
|
194
|
-
onClick={(e) => { e.stopPropagation();
|
|
195
|
-
>
|
|
196
|
-
<RotateCcw className="h-3.5 w-3.5" />
|
|
197
|
-
</Button>
|
|
198
|
-
)}
|
|
199
|
-
{wf.status !== "active" && (
|
|
200
|
-
<Button
|
|
201
|
-
variant="ghost"
|
|
202
|
-
size="icon"
|
|
203
|
-
className="h-7 w-7 text-destructive"
|
|
204
|
-
aria-label="Delete workflow"
|
|
205
|
-
onClick={(e) => { e.stopPropagation(); setConfirmDeleteId(wf.id); }}
|
|
187
|
+
aria-label="Clone workflow"
|
|
188
|
+
onClick={(e) => { e.stopPropagation(); router.push(`/workflows/${wf.id}/edit?clone=true`); }}
|
|
206
189
|
>
|
|
207
|
-
<
|
|
190
|
+
<Copy className="h-3.5 w-3.5" />
|
|
208
191
|
</Button>
|
|
209
|
-
|
|
192
|
+
{(wf.status === "completed" || wf.status === "failed") && (
|
|
193
|
+
<Button
|
|
194
|
+
variant="ghost"
|
|
195
|
+
size="icon"
|
|
196
|
+
className="h-7 w-7"
|
|
197
|
+
aria-label="Re-run workflow"
|
|
198
|
+
onClick={(e) => { e.stopPropagation(); handleRerun(wf.id); }}
|
|
199
|
+
>
|
|
200
|
+
<RotateCcw className="h-3.5 w-3.5" />
|
|
201
|
+
</Button>
|
|
202
|
+
)}
|
|
203
|
+
{wf.status !== "active" && (
|
|
204
|
+
<Button
|
|
205
|
+
variant="ghost"
|
|
206
|
+
size="icon"
|
|
207
|
+
className="h-7 w-7 text-destructive"
|
|
208
|
+
aria-label="Delete workflow"
|
|
209
|
+
onClick={(e) => { e.stopPropagation(); setConfirmDeleteId(wf.id); }}
|
|
210
|
+
>
|
|
211
|
+
<Trash2 className="h-3.5 w-3.5" />
|
|
212
|
+
</Button>
|
|
213
|
+
)}
|
|
214
|
+
</div>
|
|
210
215
|
</div>
|
|
211
216
|
</CardContent>
|
|
212
217
|
</Card>
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { useEffect, useState, useCallback } from "react";
|
|
4
4
|
import { useRouter } from "next/navigation";
|
|
5
|
+
import Link from "next/link";
|
|
5
6
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
|
6
7
|
import { Badge } from "@/components/ui/badge";
|
|
7
8
|
import { Button } from "@/components/ui/button";
|
|
@@ -20,12 +21,21 @@ import {
|
|
|
20
21
|
Clock3,
|
|
21
22
|
GitBranch,
|
|
22
23
|
MessageSquareMore,
|
|
24
|
+
ChevronDown,
|
|
25
|
+
ChevronRight,
|
|
26
|
+
FileText,
|
|
27
|
+
Paperclip,
|
|
23
28
|
} from "lucide-react";
|
|
29
|
+
import ReactMarkdown from "react-markdown";
|
|
30
|
+
import remarkGfm from "remark-gfm";
|
|
24
31
|
import { toast } from "sonner";
|
|
25
32
|
import { workflowStatusVariant, patternLabels } from "@/lib/constants/status-colors";
|
|
33
|
+
import { IconCircle, getWorkflowIconFromName } from "@/lib/constants/card-icons";
|
|
26
34
|
import { LoopStatusView } from "./loop-status-view";
|
|
27
35
|
import { ConfirmDialog } from "@/components/shared/confirm-dialog";
|
|
36
|
+
import { LightMarkdown } from "@/components/shared/light-markdown";
|
|
28
37
|
import { SwarmDashboard } from "./swarm-dashboard";
|
|
38
|
+
import { WorkflowFullOutput } from "./workflow-full-output";
|
|
29
39
|
import type { LoopState, LoopConfig, SwarmConfig } from "@/lib/workflows/types";
|
|
30
40
|
|
|
31
41
|
interface StepWithState {
|
|
@@ -43,6 +53,14 @@ interface StepWithState {
|
|
|
43
53
|
};
|
|
44
54
|
}
|
|
45
55
|
|
|
56
|
+
interface DocumentInfo {
|
|
57
|
+
id: string;
|
|
58
|
+
originalName: string;
|
|
59
|
+
mimeType: string;
|
|
60
|
+
storagePath: string;
|
|
61
|
+
direction: string;
|
|
62
|
+
}
|
|
63
|
+
|
|
46
64
|
interface WorkflowStatusData {
|
|
47
65
|
id: string;
|
|
48
66
|
name: string;
|
|
@@ -54,6 +72,8 @@ interface WorkflowStatusData {
|
|
|
54
72
|
loopConfig?: LoopConfig;
|
|
55
73
|
loopState?: LoopState;
|
|
56
74
|
swarmConfig?: SwarmConfig;
|
|
75
|
+
stepDocuments?: Record<string, DocumentInfo[]>;
|
|
76
|
+
parentDocuments?: DocumentInfo[];
|
|
57
77
|
}
|
|
58
78
|
|
|
59
79
|
interface WorkflowStatusViewProps {
|
|
@@ -69,6 +89,72 @@ const stepStatusIcons: Record<string, React.ReactNode> = {
|
|
|
69
89
|
waiting_dependencies: <Clock3 className="h-4 w-4 text-status-warning" />,
|
|
70
90
|
};
|
|
71
91
|
|
|
92
|
+
/** Expandable step result: collapsed LightMarkdown preview + full markdown on expand */
|
|
93
|
+
export function ExpandableResult({ result }: { result: string }) {
|
|
94
|
+
const [expanded, setExpanded] = useState(false);
|
|
95
|
+
|
|
96
|
+
if (!result) return null;
|
|
97
|
+
|
|
98
|
+
return (
|
|
99
|
+
<div className="mt-2">
|
|
100
|
+
{expanded ? (
|
|
101
|
+
<>
|
|
102
|
+
<div className="prose prose-sm dark:prose-invert max-w-none max-h-96 overflow-auto rounded-md border bg-muted/30 p-3">
|
|
103
|
+
<ReactMarkdown remarkPlugins={[remarkGfm]}>{result}</ReactMarkdown>
|
|
104
|
+
</div>
|
|
105
|
+
<Button
|
|
106
|
+
variant="ghost"
|
|
107
|
+
size="sm"
|
|
108
|
+
className="mt-1 h-6 text-xs text-muted-foreground"
|
|
109
|
+
onClick={() => setExpanded(false)}
|
|
110
|
+
>
|
|
111
|
+
<ChevronDown className="h-3 w-3 mr-1" />
|
|
112
|
+
Collapse
|
|
113
|
+
</Button>
|
|
114
|
+
</>
|
|
115
|
+
) : (
|
|
116
|
+
<>
|
|
117
|
+
<LightMarkdown content={result.slice(0, 500)} lineClamp={2} />
|
|
118
|
+
{result.length > 200 && (
|
|
119
|
+
<Button
|
|
120
|
+
variant="ghost"
|
|
121
|
+
size="sm"
|
|
122
|
+
className="mt-1 h-6 text-xs text-muted-foreground"
|
|
123
|
+
onClick={() => setExpanded(true)}
|
|
124
|
+
>
|
|
125
|
+
<ChevronRight className="h-3 w-3 mr-1" />
|
|
126
|
+
Expand
|
|
127
|
+
</Button>
|
|
128
|
+
)}
|
|
129
|
+
</>
|
|
130
|
+
)}
|
|
131
|
+
</div>
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/** Document list for a single step or parent task */
|
|
136
|
+
function DocumentList({ docs, label }: { docs: DocumentInfo[]; label: string }) {
|
|
137
|
+
if (docs.length === 0) return null;
|
|
138
|
+
|
|
139
|
+
return (
|
|
140
|
+
<div className="mt-3">
|
|
141
|
+
<p className="text-xs font-medium text-muted-foreground mb-1.5">{label}</p>
|
|
142
|
+
<div className="space-y-1">
|
|
143
|
+
{docs.map((doc) => (
|
|
144
|
+
<Link
|
|
145
|
+
key={doc.id}
|
|
146
|
+
href={`/documents/${doc.id}`}
|
|
147
|
+
className="flex items-center gap-2 text-xs text-brand-blue hover:underline"
|
|
148
|
+
>
|
|
149
|
+
<FileText className="h-3 w-3 shrink-0" />
|
|
150
|
+
{doc.originalName}
|
|
151
|
+
</Link>
|
|
152
|
+
))}
|
|
153
|
+
</div>
|
|
154
|
+
</div>
|
|
155
|
+
);
|
|
156
|
+
}
|
|
157
|
+
|
|
72
158
|
|
|
73
159
|
export function WorkflowStatusView({ workflowId }: WorkflowStatusViewProps) {
|
|
74
160
|
const router = useRouter();
|
|
@@ -218,16 +304,31 @@ export function WorkflowStatusView({ workflowId }: WorkflowStatusViewProps) {
|
|
|
218
304
|
? data.steps.find((step) => step.dependsOn?.length) ?? null
|
|
219
305
|
: null;
|
|
220
306
|
|
|
307
|
+
// Collect all completed step outputs for full output sheet
|
|
308
|
+
const completedStepOutputs = data.steps
|
|
309
|
+
.filter((s) => s.state.result && s.state.status === "completed")
|
|
310
|
+
.map((s) => ({ name: s.name, result: s.state.result! }));
|
|
311
|
+
|
|
312
|
+
// Check for any documents
|
|
313
|
+
const hasStepDocs = data.stepDocuments && Object.keys(data.stepDocuments).length > 0;
|
|
314
|
+
const hasParentDocs = data.parentDocuments && data.parentDocuments.length > 0;
|
|
315
|
+
|
|
221
316
|
return (
|
|
222
|
-
|
|
317
|
+
<div className="space-y-6">
|
|
223
318
|
<Card>
|
|
224
319
|
<CardHeader>
|
|
225
320
|
<div className="flex items-center justify-between">
|
|
226
|
-
<div>
|
|
227
|
-
<
|
|
228
|
-
|
|
229
|
-
{
|
|
230
|
-
|
|
321
|
+
<div className="flex items-center gap-3">
|
|
322
|
+
<IconCircle
|
|
323
|
+
icon={getWorkflowIconFromName(data.name, data.pattern).icon}
|
|
324
|
+
colors={getWorkflowIconFromName(data.name, data.pattern).colors}
|
|
325
|
+
/>
|
|
326
|
+
<div>
|
|
327
|
+
<CardTitle>{data.name}</CardTitle>
|
|
328
|
+
<p className="text-sm text-muted-foreground mt-1">
|
|
329
|
+
{patternLabels[data.pattern] ?? data.pattern}
|
|
330
|
+
</p>
|
|
331
|
+
</div>
|
|
231
332
|
</div>
|
|
232
333
|
<div className="flex items-center gap-2">
|
|
233
334
|
<Badge variant={workflowStatusVariant[data.status] ?? "secondary"}>
|
|
@@ -363,9 +464,14 @@ export function WorkflowStatusView({ workflowId }: WorkflowStatusViewProps) {
|
|
|
363
464
|
</p>
|
|
364
465
|
)}
|
|
365
466
|
{step.state.result && step.state.status === "completed" && (
|
|
366
|
-
<
|
|
367
|
-
|
|
368
|
-
|
|
467
|
+
<ExpandableResult result={step.state.result} />
|
|
468
|
+
)}
|
|
469
|
+
{/* Step output documents */}
|
|
470
|
+
{step.state.taskId && data.stepDocuments?.[step.state.taskId] && (
|
|
471
|
+
<DocumentList
|
|
472
|
+
docs={data.stepDocuments[step.state.taskId]}
|
|
473
|
+
label="Generated Files"
|
|
474
|
+
/>
|
|
369
475
|
)}
|
|
370
476
|
</div>
|
|
371
477
|
</div>
|
|
@@ -409,10 +515,15 @@ export function WorkflowStatusView({ workflowId }: WorkflowStatusViewProps) {
|
|
|
409
515
|
)}
|
|
410
516
|
{synthesisStep.state.result &&
|
|
411
517
|
synthesisStep.state.status === "completed" && (
|
|
412
|
-
<
|
|
413
|
-
{synthesisStep.state.result.slice(0, 260)}
|
|
414
|
-
</p>
|
|
518
|
+
<ExpandableResult result={synthesisStep.state.result} />
|
|
415
519
|
)}
|
|
520
|
+
{/* Synthesis step documents */}
|
|
521
|
+
{synthesisStep.state.taskId && data.stepDocuments?.[synthesisStep.state.taskId] && (
|
|
522
|
+
<DocumentList
|
|
523
|
+
docs={data.stepDocuments[synthesisStep.state.taskId]}
|
|
524
|
+
label="Generated Files"
|
|
525
|
+
/>
|
|
526
|
+
)}
|
|
416
527
|
</div>
|
|
417
528
|
</div>
|
|
418
529
|
</div>
|
|
@@ -448,9 +559,14 @@ export function WorkflowStatusView({ workflowId }: WorkflowStatusViewProps) {
|
|
|
448
559
|
</p>
|
|
449
560
|
)}
|
|
450
561
|
{step.state.result && step.state.status === "completed" && (
|
|
451
|
-
<
|
|
452
|
-
|
|
453
|
-
|
|
562
|
+
<ExpandableResult result={step.state.result} />
|
|
563
|
+
)}
|
|
564
|
+
{/* Step output documents */}
|
|
565
|
+
{step.state.taskId && data.stepDocuments?.[step.state.taskId] && (
|
|
566
|
+
<DocumentList
|
|
567
|
+
docs={data.stepDocuments[step.state.taskId]}
|
|
568
|
+
label="Generated Files"
|
|
569
|
+
/>
|
|
454
570
|
)}
|
|
455
571
|
</div>
|
|
456
572
|
</div>
|
|
@@ -459,9 +575,40 @@ export function WorkflowStatusView({ workflowId }: WorkflowStatusViewProps) {
|
|
|
459
575
|
)}
|
|
460
576
|
</div>
|
|
461
577
|
)}
|
|
578
|
+
|
|
579
|
+
{/* Documents section — parent inputs and step outputs */}
|
|
580
|
+
{(hasParentDocs || hasStepDocs) && (
|
|
581
|
+
<div className="mt-6 pt-4 border-t border-border/50">
|
|
582
|
+
<div className="flex items-center gap-2 mb-3">
|
|
583
|
+
<Paperclip className="h-4 w-4 text-muted-foreground" />
|
|
584
|
+
<p className="text-sm font-medium">Documents</p>
|
|
585
|
+
</div>
|
|
586
|
+
{hasParentDocs && (
|
|
587
|
+
<DocumentList docs={data.parentDocuments!} label="Input Files" />
|
|
588
|
+
)}
|
|
589
|
+
{hasStepDocs && Object.entries(data.stepDocuments!).map(([taskId, docs]) => {
|
|
590
|
+
const step = data.steps.find((s) => s.state.taskId === taskId);
|
|
591
|
+
return (
|
|
592
|
+
<DocumentList
|
|
593
|
+
key={taskId}
|
|
594
|
+
docs={docs}
|
|
595
|
+
label={step ? `Output: ${step.name}` : "Output Files"}
|
|
596
|
+
/>
|
|
597
|
+
);
|
|
598
|
+
})}
|
|
599
|
+
</div>
|
|
600
|
+
)}
|
|
462
601
|
</CardContent>
|
|
463
602
|
</Card>
|
|
464
603
|
|
|
604
|
+
{/* Full output — inline below workflow card when completed */}
|
|
605
|
+
{data.status === "completed" && completedStepOutputs.length > 0 && (
|
|
606
|
+
<WorkflowFullOutput
|
|
607
|
+
workflowName={data.name}
|
|
608
|
+
steps={completedStepOutputs}
|
|
609
|
+
/>
|
|
610
|
+
)}
|
|
611
|
+
|
|
465
612
|
{/* Delete confirmation */}
|
|
466
613
|
<ConfirmDialog
|
|
467
614
|
open={confirmDelete}
|
|
@@ -472,6 +619,6 @@ export function WorkflowStatusView({ workflowId }: WorkflowStatusViewProps) {
|
|
|
472
619
|
onConfirm={handleDelete}
|
|
473
620
|
destructive
|
|
474
621
|
/>
|
|
475
|
-
|
|
622
|
+
</div>
|
|
476
623
|
);
|
|
477
624
|
}
|
|
@@ -58,14 +58,24 @@ function getNextVersion(profileId: string): number {
|
|
|
58
58
|
// Proposal flow
|
|
59
59
|
// ---------------------------------------------------------------------------
|
|
60
60
|
|
|
61
|
-
/**
|
|
61
|
+
/**
|
|
62
|
+
* Insert a context proposal and optionally create a notification for human review.
|
|
63
|
+
*
|
|
64
|
+
* When `options.silent` is true, the proposal row is created but no notification
|
|
65
|
+
* is generated. This is used by the learning session system to buffer proposals
|
|
66
|
+
* during workflow execution — a batch notification is created when the session closes.
|
|
67
|
+
*
|
|
68
|
+
* Returns the learned_context row ID (not the notification ID) so callers can
|
|
69
|
+
* reference the proposal regardless of whether a notification was created.
|
|
70
|
+
*/
|
|
62
71
|
export async function proposeContextAddition(
|
|
63
72
|
profileId: string,
|
|
64
73
|
taskId: string,
|
|
65
|
-
additions: string
|
|
74
|
+
additions: string,
|
|
75
|
+
options?: { silent?: boolean }
|
|
66
76
|
): Promise<string> {
|
|
67
77
|
const version = getNextVersion(profileId);
|
|
68
|
-
const notificationId = crypto.randomUUID();
|
|
78
|
+
const notificationId = options?.silent ? null : crypto.randomUUID();
|
|
69
79
|
const rowId = crypto.randomUUID();
|
|
70
80
|
const now = new Date();
|
|
71
81
|
|
|
@@ -83,19 +93,21 @@ export async function proposeContextAddition(
|
|
|
83
93
|
createdAt: now,
|
|
84
94
|
});
|
|
85
95
|
|
|
86
|
-
// Create notification for human review
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
96
|
+
// Create notification for human review (unless silent)
|
|
97
|
+
if (notificationId) {
|
|
98
|
+
await db.insert(notifications).values({
|
|
99
|
+
id: notificationId,
|
|
100
|
+
taskId,
|
|
101
|
+
type: "context_proposal",
|
|
102
|
+
title: `Context proposal for ${profileId}`,
|
|
103
|
+
body: additions.slice(0, 500),
|
|
104
|
+
toolName: profileId,
|
|
105
|
+
toolInput: JSON.stringify({ profileId, additions, learnedContextId: rowId }),
|
|
106
|
+
createdAt: now,
|
|
107
|
+
});
|
|
108
|
+
}
|
|
97
109
|
|
|
98
|
-
return
|
|
110
|
+
return rowId;
|
|
99
111
|
}
|
|
100
112
|
|
|
101
113
|
// ---------------------------------------------------------------------------
|