@stigmer/react 3.2.1 → 3.2.3
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/activity/entry-status-badge.d.ts +23 -0
- package/activity/entry-status-badge.d.ts.map +1 -0
- package/activity/entry-status-badge.js +18 -0
- package/activity/entry-status-badge.js.map +1 -0
- package/activity/format-relative-time.d.ts +16 -0
- package/activity/format-relative-time.d.ts.map +1 -0
- package/activity/format-relative-time.js +38 -0
- package/activity/format-relative-time.js.map +1 -0
- package/activity/index.d.ts +2 -0
- package/activity/index.d.ts.map +1 -1
- package/activity/index.js +2 -0
- package/activity/index.js.map +1 -1
- package/agent/AgentDetailView.d.ts.map +1 -1
- package/agent/AgentDetailView.js +6 -3
- package/agent/AgentDetailView.js.map +1 -1
- package/execution/index.d.ts +1 -2
- package/execution/index.d.ts.map +1 -1
- package/execution/index.js +0 -1
- package/execution/index.js.map +1 -1
- package/execution/useLiveAgentExecution.d.ts +17 -1
- package/execution/useLiveAgentExecution.d.ts.map +1 -1
- package/execution/useLiveAgentExecution.js +19 -4
- package/execution/useLiveAgentExecution.js.map +1 -1
- package/index.d.ts +7 -7
- package/index.d.ts.map +1 -1
- package/index.js +3 -3
- package/index.js.map +1 -1
- package/internal/useInViewport.d.ts +24 -0
- package/internal/useInViewport.d.ts.map +1 -0
- package/internal/useInViewport.js +49 -0
- package/internal/useInViewport.js.map +1 -0
- package/library/VisibilitySelector.d.ts +22 -6
- package/library/VisibilitySelector.d.ts.map +1 -1
- package/library/VisibilitySelector.js +12 -4
- package/library/VisibilitySelector.js.map +1 -1
- package/library/index.d.ts +1 -1
- package/library/index.d.ts.map +1 -1
- package/library/index.js.map +1 -1
- package/mcp-server/McpServerDetailView.d.ts.map +1 -1
- package/mcp-server/McpServerDetailView.js +4 -3
- package/mcp-server/McpServerDetailView.js.map +1 -1
- package/package.json +4 -4
- package/session/SessionViewer.js +8 -1
- package/session/SessionViewer.js.map +1 -1
- package/session/audience.d.ts +6 -1
- package/session/audience.d.ts.map +1 -1
- package/skill/SkillDetailView.d.ts.map +1 -1
- package/skill/SkillDetailView.js +4 -3
- package/skill/SkillDetailView.js.map +1 -1
- package/src/access/__tests__/useManageAccess.test.tsx +104 -0
- package/src/activity/__tests__/format-relative-time.test.ts +40 -0
- package/src/activity/entry-status-badge.ts +39 -0
- package/src/activity/format-relative-time.ts +38 -0
- package/src/activity/index.ts +7 -0
- package/src/agent/AgentDetailView.tsx +9 -3
- package/src/execution/__tests__/useLiveAgentExecution.test.tsx +125 -0
- package/src/execution/index.ts +4 -7
- package/src/execution/useLiveAgentExecution.ts +41 -3
- package/src/index.ts +7 -5
- package/src/internal/__tests__/useInViewport.test.tsx +115 -0
- package/src/internal/useInViewport.ts +63 -0
- package/src/library/VisibilitySelector.tsx +50 -9
- package/src/library/__tests__/VisibilitySelector.test.tsx +38 -0
- package/src/library/index.ts +4 -1
- package/src/mcp-server/McpServerDetailView.tsx +7 -3
- package/src/session/SessionViewer.tsx +7 -1
- package/src/session/__tests__/audienceWiring.test.tsx +31 -1
- package/src/session/audience.ts +6 -1
- package/src/skill/SkillDetailView.tsx +7 -3
- package/src/workflow/WorkflowAgentCallTranscript.tsx +279 -0
- package/src/workflow/WorkflowDetailView.tsx +7 -3
- package/src/workflow/WorkflowExecutionViewer.tsx +20 -77
- package/src/workflow/WorkflowTaskApprovalSummary.tsx +45 -8
- package/src/workflow/__tests__/WorkflowAgentCallTranscript.liveregion.test.tsx +124 -0
- package/src/workflow/__tests__/{WorkflowAgentExecutionDocument.test.tsx → WorkflowAgentCallTranscript.test.tsx} +146 -121
- package/src/workflow/__tests__/WorkflowExecutionViewer.approvals.test.tsx +81 -220
- package/src/workflow/__tests__/WorkflowExecutionViewer.reconciliation.test.tsx +17 -16
- package/src/workflow/__tests__/WorkflowTaskApprovalSummary.test.tsx +52 -2
- package/src/workflow/__tests__/WorkflowTaskThread.test.tsx +168 -185
- package/src/workflow/__tests__/agent-call-live-experience.test.ts +4 -4
- package/src/workflow/__tests__/task-approval.test.ts +119 -0
- package/src/workflow/__tests__/task-presentation.test.ts +35 -1
- package/src/workflow/__tests__/useWorkflowExecutionPanel.test.ts +0 -57
- package/src/workflow/index.ts +6 -3
- package/src/workflow/task-detail/index.ts +3 -0
- package/src/workflow/task-detail/task-approval.ts +95 -1
- package/src/workflow/thread/WorkflowTaskThread.tsx +96 -252
- package/src/workflow/thread/task-presentation.ts +8 -2
- package/src/workflow/useWorkflowExecutionPanel.ts +0 -47
- package/workflow/WorkflowAgentCallTranscript.d.ts +87 -0
- package/workflow/WorkflowAgentCallTranscript.d.ts.map +1 -0
- package/workflow/WorkflowAgentCallTranscript.js +98 -0
- package/workflow/WorkflowAgentCallTranscript.js.map +1 -0
- package/workflow/WorkflowDetailView.d.ts.map +1 -1
- package/workflow/WorkflowDetailView.js +4 -3
- package/workflow/WorkflowDetailView.js.map +1 -1
- package/workflow/WorkflowExecutionViewer.d.ts.map +1 -1
- package/workflow/WorkflowExecutionViewer.js +23 -52
- package/workflow/WorkflowExecutionViewer.js.map +1 -1
- package/workflow/WorkflowTaskApprovalSummary.d.ts +1 -1
- package/workflow/WorkflowTaskApprovalSummary.d.ts.map +1 -1
- package/workflow/WorkflowTaskApprovalSummary.js +18 -1
- package/workflow/WorkflowTaskApprovalSummary.js.map +1 -1
- package/workflow/index.d.ts +2 -2
- package/workflow/index.d.ts.map +1 -1
- package/workflow/index.js +2 -2
- package/workflow/index.js.map +1 -1
- package/workflow/task-detail/index.d.ts +1 -1
- package/workflow/task-detail/index.d.ts.map +1 -1
- package/workflow/task-detail/index.js +1 -1
- package/workflow/task-detail/index.js.map +1 -1
- package/workflow/task-detail/task-approval.d.ts +44 -1
- package/workflow/task-detail/task-approval.d.ts.map +1 -1
- package/workflow/task-detail/task-approval.js +47 -0
- package/workflow/task-detail/task-approval.js.map +1 -1
- package/workflow/thread/WorkflowTaskThread.d.ts +17 -25
- package/workflow/thread/WorkflowTaskThread.d.ts.map +1 -1
- package/workflow/thread/WorkflowTaskThread.js +60 -105
- package/workflow/thread/WorkflowTaskThread.js.map +1 -1
- package/workflow/thread/task-presentation.d.ts.map +1 -1
- package/workflow/thread/task-presentation.js +7 -2
- package/workflow/thread/task-presentation.js.map +1 -1
- package/workflow/useWorkflowExecutionPanel.d.ts +0 -12
- package/workflow/useWorkflowExecutionPanel.d.ts.map +1 -1
- package/workflow/useWorkflowExecutionPanel.js +0 -12
- package/workflow/useWorkflowExecutionPanel.js.map +1 -1
- package/execution/agent-execution-document.d.ts +0 -31
- package/execution/agent-execution-document.d.ts.map +0 -1
- package/execution/agent-execution-document.js +0 -48
- package/execution/agent-execution-document.js.map +0 -1
- package/src/execution/__tests__/agent-execution-document.test.ts +0 -45
- package/src/execution/agent-execution-document.ts +0 -54
- package/src/workflow/WorkflowAgentExecutionDocument.tsx +0 -283
- package/workflow/WorkflowAgentExecutionDocument.d.ts +0 -79
- package/workflow/WorkflowAgentExecutionDocument.d.ts.map +0 -1
- package/workflow/WorkflowAgentExecutionDocument.js +0 -87
- package/workflow/WorkflowAgentExecutionDocument.js.map +0 -1
|
@@ -2,11 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { memo, useMemo, useState } from "react";
|
|
4
4
|
import { cn } from "@stigmer/theme";
|
|
5
|
-
import type {
|
|
6
|
-
WorkflowPendingApproval,
|
|
7
|
-
WorkflowPendingFileReview,
|
|
8
|
-
WorkflowTask,
|
|
9
|
-
} from "@stigmer/protos/ai/stigmer/agentic/workflowexecution/v1/api_pb";
|
|
5
|
+
import type { WorkflowTask } from "@stigmer/protos/ai/stigmer/agentic/workflowexecution/v1/api_pb";
|
|
10
6
|
import type { DerivedTaskState } from "../../internal/store/workflow-execution-event-store.js";
|
|
11
7
|
import { useAutoScroll } from "../../internal/useAutoScroll.js";
|
|
12
8
|
import { JumpToLatestButton } from "../../internal/JumpToLatestButton.js";
|
|
@@ -24,8 +20,7 @@ import {
|
|
|
24
20
|
} from "../../internal/thread-card/index.js";
|
|
25
21
|
import { formatMetaChips } from "../format-utils.js";
|
|
26
22
|
import type { UseWorkflowExecutionActionsReturn } from "../useWorkflowExecutionActions.js";
|
|
27
|
-
import {
|
|
28
|
-
import { WorkflowFileReviewList } from "../WorkflowFileReviewList.js";
|
|
23
|
+
import { WorkflowAgentCallTranscript } from "../WorkflowAgentCallTranscript.js";
|
|
29
24
|
import { WorkflowTaskReviewGate } from "../WorkflowTaskReviewGate.js";
|
|
30
25
|
import { WorkflowTaskApprovalSummary } from "../WorkflowTaskApprovalSummary.js";
|
|
31
26
|
import { buildIO, type TaskDetailIO } from "../task-detail/task-detail-io.js";
|
|
@@ -66,16 +61,6 @@ export type WorkflowThreadHitl = Pick<
|
|
|
66
61
|
| "fileDecisionErrorsByKey"
|
|
67
62
|
>;
|
|
68
63
|
|
|
69
|
-
/**
|
|
70
|
-
* The pending gates surfaced for one task card's child agent execution —
|
|
71
|
-
* grouped once per thread render (memoized against the snapshot lists) so
|
|
72
|
-
* non-gating cards receive `undefined` and their `React.memo` bails hold.
|
|
73
|
-
*/
|
|
74
|
-
interface ThreadTaskGates {
|
|
75
|
-
readonly approvals: readonly WorkflowPendingApproval[];
|
|
76
|
-
readonly fileReviews: readonly WorkflowPendingFileReview[];
|
|
77
|
-
}
|
|
78
|
-
|
|
79
64
|
/** Props for {@link WorkflowTaskThread}. */
|
|
80
65
|
export interface WorkflowTaskThreadProps {
|
|
81
66
|
/** Live derived task states from the execution event stream. */
|
|
@@ -85,14 +70,11 @@ export interface WorkflowTaskThreadProps {
|
|
|
85
70
|
/** Whether the execution is still running (drives streaming affordances). */
|
|
86
71
|
readonly isRunning: boolean;
|
|
87
72
|
/**
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
* not rendered.
|
|
73
|
+
* Open an AGENT_CALL task's child execution as a standalone page — the
|
|
74
|
+
* inline transcript's deep-dive pop-out. Host-routed (DD-004). Omitted →
|
|
75
|
+
* the affordance is not rendered.
|
|
91
76
|
*/
|
|
92
|
-
readonly
|
|
93
|
-
childExecutionId: string,
|
|
94
|
-
taskName: string,
|
|
95
|
-
) => void;
|
|
77
|
+
readonly onNavigateToAgentExecution?: (agentExecutionId: string) => void;
|
|
96
78
|
/**
|
|
97
79
|
* Workflow-level HITL wiring (see {@link WorkflowThreadHitl}). When
|
|
98
80
|
* provided, a gating task's card renders its decision surface directly in
|
|
@@ -101,16 +83,6 @@ export interface WorkflowTaskThreadProps {
|
|
|
101
83
|
* and behaves exactly as before (DD-011; the S5 omitted-`hitl` precedent).
|
|
102
84
|
*/
|
|
103
85
|
readonly hitl?: WorkflowThreadHitl;
|
|
104
|
-
/**
|
|
105
|
-
* The parent workflow's surfaced child tool-approval gates
|
|
106
|
-
* (`status.pending_approvals`). Only read when {@link hitl} is provided.
|
|
107
|
-
*/
|
|
108
|
-
readonly pendingApprovals?: readonly WorkflowPendingApproval[];
|
|
109
|
-
/**
|
|
110
|
-
* The parent workflow's surfaced child file-review references
|
|
111
|
-
* (`status.pending_file_reviews`). Only read when {@link hitl} is provided.
|
|
112
|
-
*/
|
|
113
|
-
readonly pendingFileReviews?: readonly WorkflowPendingFileReview[];
|
|
114
86
|
/**
|
|
115
87
|
* Per-task status snapshots (`status.tasks[]`) keyed by task name — the
|
|
116
88
|
* FULL I/O source for card bodies (T04), never an event-log scan
|
|
@@ -132,22 +104,24 @@ export interface WorkflowTaskThreadProps {
|
|
|
132
104
|
*
|
|
133
105
|
* Pending tasks render no cards (D-T02-5); the progress header keeps
|
|
134
106
|
* overall status visible. Retries collapse into one card with an attempt
|
|
135
|
-
* indicator (D-T02-6). AGENT_CALL cards
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
*
|
|
140
|
-
* the
|
|
107
|
+
* indicator (D-T02-6). AGENT_CALL cards render the child's FULL transcript
|
|
108
|
+
* inline as the card body (T07) — live-streaming while the child runs,
|
|
109
|
+
* complete history once settled — the session experience in place, with an
|
|
110
|
+
* "Open standalone" pop-out for a deep dive. Since T04 the card is the
|
|
111
|
+
* PRIMARY surface for a task's data (kind-aware preview line + bounded I/O
|
|
112
|
+
* body); since T06 it is the ONLY one — the Inspect drill-down is gone, and
|
|
113
|
+
* cards compose the session card language exactly (expand-or-none headers,
|
|
114
|
+
* no selection).
|
|
141
115
|
*
|
|
142
116
|
* Auto-follow uses the session thread's mechanism: an IntersectionObserver
|
|
143
117
|
* sentinel keeps the list pinned to the latest card until the user scrolls
|
|
144
118
|
* up, with a jump-to-latest affordance to re-engage.
|
|
145
119
|
*
|
|
146
120
|
* With `hitl` wired, a gating task's card carries its decision surface
|
|
147
|
-
* in-thread (S10/T06): the
|
|
148
|
-
*
|
|
149
|
-
* `WorkflowTaskReviewGate` (custom review renderers included)
|
|
150
|
-
* task-level human_input gates — with a read-only
|
|
121
|
+
* in-thread (S10/T06/T07): the child's own inline transcript renders the
|
|
122
|
+
* canonical `ApprovalCard`s and `FileReviewCard`s for child gates, and the
|
|
123
|
+
* full `WorkflowTaskReviewGate` (custom review renderers included) renders
|
|
124
|
+
* for task-level human_input gates — with a read-only
|
|
151
125
|
* `WorkflowTaskApprovalSummary` once the gate resolves.
|
|
152
126
|
*
|
|
153
127
|
* This component is designed to work identically whether rendered in the
|
|
@@ -158,10 +132,8 @@ export const WorkflowTaskThread = memo(function WorkflowTaskThread({
|
|
|
158
132
|
taskStates,
|
|
159
133
|
totalTasks,
|
|
160
134
|
isRunning,
|
|
161
|
-
|
|
135
|
+
onNavigateToAgentExecution,
|
|
162
136
|
hitl,
|
|
163
|
-
pendingApprovals,
|
|
164
|
-
pendingFileReviews,
|
|
165
137
|
taskSnapshotsByName,
|
|
166
138
|
className,
|
|
167
139
|
}: WorkflowTaskThreadProps) {
|
|
@@ -169,34 +141,6 @@ export const WorkflowTaskThread = memo(function WorkflowTaskThread({
|
|
|
169
141
|
const { scrollRef, sentinelRef, contentRef, isFollowing, jumpToLatest } =
|
|
170
142
|
useAutoScroll();
|
|
171
143
|
|
|
172
|
-
// Group the snapshot's gates by owning child ONCE per snapshot identity —
|
|
173
|
-
// the lists change only on a snapshot refetch, never on stream event
|
|
174
|
-
// appends, so during streaming every card's `gates` prop keeps a stable
|
|
175
|
-
// reference (`undefined` for non-gating cards) and memoized rows bail
|
|
176
|
-
// (DD-009/DD-010). Grouping is unconditional (it is cheap and usually
|
|
177
|
-
// empty); rendering is gated on `hitl` at the card.
|
|
178
|
-
const gatesByChild = useMemo((): ReadonlyMap<string, ThreadTaskGates> => {
|
|
179
|
-
const map = new Map<
|
|
180
|
-
string,
|
|
181
|
-
{ approvals: WorkflowPendingApproval[]; fileReviews: WorkflowPendingFileReview[] }
|
|
182
|
-
>();
|
|
183
|
-
const bucket = (childId: string) => {
|
|
184
|
-
let entry = map.get(childId);
|
|
185
|
-
if (!entry) {
|
|
186
|
-
entry = { approvals: [], fileReviews: [] };
|
|
187
|
-
map.set(childId, entry);
|
|
188
|
-
}
|
|
189
|
-
return entry;
|
|
190
|
-
};
|
|
191
|
-
for (const pa of pendingApprovals ?? []) {
|
|
192
|
-
if (pa.childAgentExecutionId) bucket(pa.childAgentExecutionId).approvals.push(pa);
|
|
193
|
-
}
|
|
194
|
-
for (const ref of pendingFileReviews ?? []) {
|
|
195
|
-
if (ref.childAgentExecutionId) bucket(ref.childAgentExecutionId).fileReviews.push(ref);
|
|
196
|
-
}
|
|
197
|
-
return map;
|
|
198
|
-
}, [pendingApprovals, pendingFileReviews]);
|
|
199
|
-
|
|
200
144
|
return (
|
|
201
145
|
<div className={cn("relative flex h-full min-h-0 flex-col", className)}>
|
|
202
146
|
<ThreadProgressHeader progress={progress} isRunning={isRunning} />
|
|
@@ -213,7 +157,7 @@ export const WorkflowTaskThread = memo(function WorkflowTaskThread({
|
|
|
213
157
|
<ThreadTaskCard
|
|
214
158
|
key={item.taskName}
|
|
215
159
|
item={item}
|
|
216
|
-
|
|
160
|
+
onNavigateToAgentExecution={onNavigateToAgentExecution}
|
|
217
161
|
// HITL props reach ONLY gating cards (DD-010): the bundle's
|
|
218
162
|
// identity moves whenever any gate's in-flight/error state
|
|
219
163
|
// flips (fresh Set/Map fields), so handing it to every card
|
|
@@ -221,11 +165,6 @@ export const WorkflowTaskThread = memo(function WorkflowTaskThread({
|
|
|
221
165
|
// here, non-gating cards keep `undefined === undefined` and
|
|
222
166
|
// their memo bails hold.
|
|
223
167
|
hitl={item.status === "waiting_approval" ? hitl : undefined}
|
|
224
|
-
gates={
|
|
225
|
-
item.status === "waiting_approval" && item.childExecutionId
|
|
226
|
-
? gatesByChild.get(item.childExecutionId)
|
|
227
|
-
: undefined
|
|
228
|
-
}
|
|
229
168
|
snapshot={taskSnapshotsByName?.get(item.taskName)}
|
|
230
169
|
/>
|
|
231
170
|
))
|
|
@@ -296,8 +235,8 @@ function ThreadEmptyState({ isRunning }: { readonly isRunning: boolean }) {
|
|
|
296
235
|
/**
|
|
297
236
|
* One task card. Memoized against the structurally-shared item (DD-010):
|
|
298
237
|
* during streaming only the actively-changing task's item gets a fresh
|
|
299
|
-
* identity, so settled cards bail here. `hitl
|
|
300
|
-
*
|
|
238
|
+
* identity, so settled cards bail here. `hitl` arrives ONLY while this
|
|
239
|
+
* card is gating (the thread scopes it — see the render site), so
|
|
301
240
|
* gate-state churn (a decision's in-flight Set flip re-materializes the
|
|
302
241
|
* bundle) re-renders gating cards only, never the column. `snapshot`
|
|
303
242
|
* changes identity only on a snapshot refetch, never on stream appends.
|
|
@@ -311,21 +250,22 @@ function ThreadEmptyState({ isRunning }: { readonly isRunning: boolean }) {
|
|
|
311
250
|
* old "expand, then Show more" double control never comes back).
|
|
312
251
|
* - `"summary"` kinds expand from the header — the session card's own
|
|
313
252
|
* gesture, the chevron appended by the shell (T06).
|
|
253
|
+
* - AGENT_CALL cards with a spawned child render the child's inline
|
|
254
|
+
* transcript as the body (T07) — keyed on the VARIANT, not the
|
|
255
|
+
* disclosure, so a platform builder's presenter override can never route
|
|
256
|
+
* the flagship card away from its transcript. An agent_call that failed
|
|
257
|
+
* BEFORE spawning a child (agent resolution error) has no transcript and
|
|
258
|
+
* falls back to the generic preview body so its error still surfaces.
|
|
314
259
|
*/
|
|
315
260
|
const ThreadTaskCard = memo(function ThreadTaskCard({
|
|
316
261
|
item,
|
|
317
|
-
|
|
262
|
+
onNavigateToAgentExecution,
|
|
318
263
|
hitl,
|
|
319
|
-
gates,
|
|
320
264
|
snapshot,
|
|
321
265
|
}: {
|
|
322
266
|
readonly item: WorkflowThreadItem;
|
|
323
|
-
readonly
|
|
324
|
-
childExecutionId: string,
|
|
325
|
-
taskName: string,
|
|
326
|
-
) => void;
|
|
267
|
+
readonly onNavigateToAgentExecution?: (agentExecutionId: string) => void;
|
|
327
268
|
readonly hitl?: WorkflowThreadHitl;
|
|
328
|
-
readonly gates?: ThreadTaskGates;
|
|
329
269
|
readonly snapshot?: WorkflowTask;
|
|
330
270
|
}) {
|
|
331
271
|
const [expanded, setExpanded] = useState(false);
|
|
@@ -361,30 +301,28 @@ const ThreadTaskCard = memo(function ThreadTaskCard({
|
|
|
361
301
|
);
|
|
362
302
|
|
|
363
303
|
const isPreview = item.disclosure === "preview";
|
|
364
|
-
|
|
365
|
-
//
|
|
366
|
-
//
|
|
367
|
-
//
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
!
|
|
304
|
+
// The flagship card (T07): an AGENT_CALL with a spawned child renders the
|
|
305
|
+
// child's transcript inline as its body — the single home for everything
|
|
306
|
+
// the child did. Child gates decide INSIDE the transcript (the session's
|
|
307
|
+
// own ApprovalCard/FileReviewDock), so the generic HITL section below is
|
|
308
|
+
// for task-level (human_input) gates only.
|
|
309
|
+
const showTranscript =
|
|
310
|
+
item.variant === "agent-call" && item.childExecutionId !== "";
|
|
311
|
+
const showHitl =
|
|
312
|
+
!!hitl && item.status === "waiting_approval" && !showTranscript;
|
|
373
313
|
// A resolved human_input gate presents its decision report in place of
|
|
374
314
|
// the raw output Struct (the output IS the decision record — the report
|
|
375
315
|
// is the readable rendering of it).
|
|
376
316
|
const showApprovalSummary =
|
|
377
317
|
!showHitl && approvalRequestView !== null && approvalDecision !== null;
|
|
378
318
|
// The session's `showBody` gate: a preview body renders only when it has
|
|
379
|
-
// content the header cannot carry (output, an error,
|
|
380
|
-
//
|
|
381
|
-
//
|
|
319
|
+
// content the header cannot carry (output, an error, or a gate's
|
|
320
|
+
// decision report) — a content-less preview card collapses back to a
|
|
321
|
+
// clean one-line row. Transcript cards have their own body.
|
|
382
322
|
const showPreviewBody =
|
|
323
|
+
!showTranscript &&
|
|
383
324
|
isPreview &&
|
|
384
|
-
(outputIO !== null ||
|
|
385
|
-
!!item.error ||
|
|
386
|
-
showBodyTranscript ||
|
|
387
|
-
showApprovalSummary);
|
|
325
|
+
(outputIO !== null || !!item.error || showApprovalSummary);
|
|
388
326
|
|
|
389
327
|
const meta = formatMetaChips({
|
|
390
328
|
durationMs: item.durationMs,
|
|
@@ -402,11 +340,12 @@ const ThreadTaskCard = memo(function ThreadTaskCard({
|
|
|
402
340
|
cursorTarget="workflow-task-row"
|
|
403
341
|
>
|
|
404
342
|
{/* The session card's gestures exactly (T06): summary rows expand
|
|
405
|
-
from the header (chevron appended by the shell); preview
|
|
406
|
-
bodies are always visible, so the header is a
|
|
343
|
+
from the header (chevron appended by the shell); preview and
|
|
344
|
+
transcript rows' bodies are always visible, so the header is a
|
|
345
|
+
plain layout row. */}
|
|
407
346
|
<ThreadCardHeader
|
|
408
347
|
gesture={
|
|
409
|
-
isPreview
|
|
348
|
+
isPreview || showTranscript
|
|
410
349
|
? { kind: "none" }
|
|
411
350
|
: {
|
|
412
351
|
kind: "expand",
|
|
@@ -444,23 +383,49 @@ const ThreadTaskCard = memo(function ThreadTaskCard({
|
|
|
444
383
|
)}
|
|
445
384
|
</ThreadCardHeader>
|
|
446
385
|
|
|
447
|
-
{/* In-thread HITL (S10): the
|
|
448
|
-
task is gating — ALWAYS visible,
|
|
449
|
-
(the run is blocked; Nielsen #1).
|
|
386
|
+
{/* In-thread HITL (S10/T06): the task-level (human_input) decision
|
|
387
|
+
surface renders whenever the task is gating — ALWAYS visible,
|
|
388
|
+
never behind the expand chevron (the run is blocked; Nielsen #1).
|
|
389
|
+
Child gates are NOT rendered here — they decide inside the
|
|
390
|
+
transcript body below (T07). */}
|
|
450
391
|
{showHitl && hitl && (
|
|
451
392
|
<ThreadCardBody>
|
|
452
393
|
<ThreadTaskCardHitl
|
|
453
394
|
item={item}
|
|
454
|
-
gates={gates}
|
|
455
395
|
hitl={hitl}
|
|
456
396
|
approvalRequestView={approvalRequestView}
|
|
457
|
-
onOpenAgentExecution={onOpenAgentExecution}
|
|
458
397
|
/>
|
|
459
398
|
</ThreadCardBody>
|
|
460
399
|
)}
|
|
461
400
|
|
|
401
|
+
{/* The child's inline transcript — the agent-call card's body for
|
|
402
|
+
every state: streaming while the child runs, full history once
|
|
403
|
+
settled, the child's own gates decided in place (T07). The task's
|
|
404
|
+
own error (e.g. "child execution failed") renders above it. */}
|
|
405
|
+
{showTranscript && (
|
|
406
|
+
<ThreadCardBody cursorTarget="task-transcript">
|
|
407
|
+
<div className="flex flex-col gap-2">
|
|
408
|
+
{item.error && (
|
|
409
|
+
<BoundedContent>
|
|
410
|
+
<pre className="whitespace-pre-wrap break-words text-xs text-destructive">
|
|
411
|
+
{item.error}
|
|
412
|
+
</pre>
|
|
413
|
+
</BoundedContent>
|
|
414
|
+
)}
|
|
415
|
+
<WorkflowAgentCallTranscript
|
|
416
|
+
childExecutionId={item.childExecutionId}
|
|
417
|
+
agentSlug={item.agentSlug || undefined}
|
|
418
|
+
hitl={hitl}
|
|
419
|
+
onNavigateToAgentExecution={onNavigateToAgentExecution}
|
|
420
|
+
/>
|
|
421
|
+
</div>
|
|
422
|
+
</ThreadCardBody>
|
|
423
|
+
)}
|
|
424
|
+
|
|
462
425
|
{/* Always-visible bounded output body for I/O-bearing kinds (T04) —
|
|
463
|
-
the session's preview-card model.
|
|
426
|
+
the session's preview-card model. Also the fallback for an
|
|
427
|
+
agent_call that failed before spawning a child (no transcript to
|
|
428
|
+
show; the error must still surface). */}
|
|
464
429
|
{showPreviewBody && (
|
|
465
430
|
<ThreadCardBody cursorTarget="task-preview">
|
|
466
431
|
<ThreadTaskPreviewBody
|
|
@@ -474,21 +439,13 @@ const ThreadTaskCard = memo(function ThreadTaskCard({
|
|
|
474
439
|
}
|
|
475
440
|
: undefined
|
|
476
441
|
}
|
|
477
|
-
onOpenAgentExecution={
|
|
478
|
-
showBodyTranscript ? onOpenAgentExecution : undefined
|
|
479
|
-
}
|
|
480
442
|
/>
|
|
481
443
|
</ThreadCardBody>
|
|
482
444
|
)}
|
|
483
445
|
|
|
484
|
-
{!isPreview && expanded && (
|
|
446
|
+
{!isPreview && !showTranscript && expanded && (
|
|
485
447
|
<ThreadCardBody>
|
|
486
|
-
<ThreadTaskDetail
|
|
487
|
-
item={item}
|
|
488
|
-
inputIO={inputIO}
|
|
489
|
-
outputIO={outputIO}
|
|
490
|
-
onOpenAgentExecution={onOpenAgentExecution}
|
|
491
|
-
/>
|
|
448
|
+
<ThreadTaskDetail item={item} inputIO={inputIO} outputIO={outputIO} />
|
|
492
449
|
</ThreadCardBody>
|
|
493
450
|
)}
|
|
494
451
|
</ThreadCardShell>
|
|
@@ -500,87 +457,27 @@ const ThreadTaskCard = memo(function ThreadTaskCard({
|
|
|
500
457
|
// ---------------------------------------------------------------------------
|
|
501
458
|
|
|
502
459
|
/**
|
|
503
|
-
* The decision surface on a gating card
|
|
460
|
+
* The decision surface on a gating card — since T07 this is the task-level
|
|
461
|
+
* (human_input) gate only. Child gates (tool approvals, file reviews) are
|
|
462
|
+
* the inline transcript's job: an AGENT_CALL card's body renders the
|
|
463
|
+
* child's own `ApprovalCard`s and `FileReviewDock`, so this section never
|
|
464
|
+
* renders for transcript cards (see `showHitl` at the card).
|
|
504
465
|
*
|
|
505
|
-
*
|
|
506
|
-
*
|
|
507
|
-
*
|
|
508
|
-
*
|
|
509
|
-
*
|
|
510
|
-
* 2. An AGENT_CALL card with NO surfaced gates → the child is gated but the
|
|
511
|
-
* snapshot has no entries: on cloud a brief refetch window; on OSS the
|
|
512
|
-
* steady state until the T04 forwarder lands. The honest surface is the
|
|
513
|
-
* child's own transcript (the S5 in-place expansion renders the child's
|
|
514
|
-
* ApprovalCards) — offer it, never a dead-end spinner.
|
|
515
|
-
* 3. Any other gating card → a task-level (human_input) gate. The full
|
|
516
|
-
* review surface — outcomes, forms, artifact-backed payloads, custom
|
|
517
|
-
* review renderers — renders right here (T06): the card is the only
|
|
518
|
-
* decision surface, so it carries the real `WorkflowTaskReviewGate`,
|
|
519
|
-
* not a link to one. Degrades to an honest waiting notice when the
|
|
520
|
-
* request payload is unavailable (no event stream — the snapshot
|
|
521
|
-
* fallback path).
|
|
466
|
+
* The full review surface — outcomes, forms, artifact-backed payloads,
|
|
467
|
+
* custom review renderers — renders right here (T06): the card is the only
|
|
468
|
+
* decision surface, so it carries the real `WorkflowTaskReviewGate`, not a
|
|
469
|
+
* link to one. Degrades to an honest waiting notice when the request
|
|
470
|
+
* payload is unavailable (no event stream — the snapshot fallback path).
|
|
522
471
|
*/
|
|
523
472
|
function ThreadTaskCardHitl({
|
|
524
473
|
item,
|
|
525
|
-
gates,
|
|
526
474
|
hitl,
|
|
527
475
|
approvalRequestView,
|
|
528
|
-
onOpenAgentExecution,
|
|
529
476
|
}: {
|
|
530
477
|
readonly item: WorkflowThreadItem;
|
|
531
|
-
readonly gates?: ThreadTaskGates;
|
|
532
478
|
readonly hitl: WorkflowThreadHitl;
|
|
533
479
|
readonly approvalRequestView: TaskApprovalRequestView | null;
|
|
534
|
-
readonly onOpenAgentExecution?: (
|
|
535
|
-
childExecutionId: string,
|
|
536
|
-
taskName: string,
|
|
537
|
-
) => void;
|
|
538
480
|
}) {
|
|
539
|
-
const hasChildGates =
|
|
540
|
-
!!gates && (gates.approvals.length > 0 || gates.fileReviews.length > 0);
|
|
541
|
-
|
|
542
|
-
if (hasChildGates) {
|
|
543
|
-
return (
|
|
544
|
-
<div className="flex flex-col gap-3">
|
|
545
|
-
{gates.approvals.length > 0 && (
|
|
546
|
-
<WorkflowApprovalList
|
|
547
|
-
pendingApprovals={gates.approvals}
|
|
548
|
-
onSubmitApproval={hitl.submitApproval}
|
|
549
|
-
submittingToolCallIds={hitl.approvalSubmittingToolCallIds}
|
|
550
|
-
approvalErrors={hitl.approvalErrorsByToolCallId}
|
|
551
|
-
/>
|
|
552
|
-
)}
|
|
553
|
-
{gates.fileReviews.length > 0 && (
|
|
554
|
-
<WorkflowFileReviewList
|
|
555
|
-
pendingFileReviews={gates.fileReviews}
|
|
556
|
-
onSubmitFileDecision={hitl.submitFileDecision}
|
|
557
|
-
submittingDecisionKeys={hitl.fileDecisionSubmittingKeys}
|
|
558
|
-
decisionErrors={hitl.fileDecisionErrorsByKey}
|
|
559
|
-
/>
|
|
560
|
-
)}
|
|
561
|
-
</div>
|
|
562
|
-
);
|
|
563
|
-
}
|
|
564
|
-
|
|
565
|
-
if (item.variant === "agent-call") {
|
|
566
|
-
return (
|
|
567
|
-
<div className="flex flex-wrap items-center gap-2">
|
|
568
|
-
<p className="text-xs text-muted-foreground">
|
|
569
|
-
The called agent is waiting for an approval. Decide it in the
|
|
570
|
-
agent's transcript.
|
|
571
|
-
</p>
|
|
572
|
-
{item.childExecutionId && onOpenAgentExecution && (
|
|
573
|
-
<ThreadActionButton
|
|
574
|
-
label="Open transcript"
|
|
575
|
-
onClick={() =>
|
|
576
|
-
onOpenAgentExecution(item.childExecutionId, item.taskName)
|
|
577
|
-
}
|
|
578
|
-
/>
|
|
579
|
-
)}
|
|
580
|
-
</div>
|
|
581
|
-
);
|
|
582
|
-
}
|
|
583
|
-
|
|
584
481
|
if (approvalRequestView) {
|
|
585
482
|
return (
|
|
586
483
|
<WorkflowTaskReviewGate
|
|
@@ -607,24 +504,6 @@ function ThreadTaskCardHitl({
|
|
|
607
504
|
);
|
|
608
505
|
}
|
|
609
506
|
|
|
610
|
-
function ThreadActionButton({
|
|
611
|
-
label,
|
|
612
|
-
onClick,
|
|
613
|
-
}: {
|
|
614
|
-
readonly label: string;
|
|
615
|
-
readonly onClick: () => void;
|
|
616
|
-
}) {
|
|
617
|
-
return (
|
|
618
|
-
<button
|
|
619
|
-
type="button"
|
|
620
|
-
onClick={onClick}
|
|
621
|
-
className="shrink-0 rounded border border-border px-2 py-1 text-xs font-medium text-foreground hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring"
|
|
622
|
-
>
|
|
623
|
-
{label}
|
|
624
|
-
</button>
|
|
625
|
-
);
|
|
626
|
-
}
|
|
627
|
-
|
|
628
507
|
// ---------------------------------------------------------------------------
|
|
629
508
|
// Card bodies (T04)
|
|
630
509
|
// ---------------------------------------------------------------------------
|
|
@@ -663,9 +542,10 @@ function ThreadTaskIOSection({
|
|
|
663
542
|
|
|
664
543
|
/**
|
|
665
544
|
* The always-visible body of a `"preview"`-kind card: the task's output
|
|
666
|
-
* (via the I/O fallback ladder)
|
|
667
|
-
*
|
|
668
|
-
*
|
|
545
|
+
* (via the I/O fallback ladder) and the failure detail when the task
|
|
546
|
+
* failed. Content only — the header owns all metadata (session
|
|
547
|
+
* `ToolCallDetail` invariant). AGENT_CALL cards with a spawned child never
|
|
548
|
+
* reach this body — theirs is the inline transcript (T07).
|
|
669
549
|
*
|
|
670
550
|
* A resolved human_input gate supplies `approvalSummary` and gets the
|
|
671
551
|
* read-only decision report instead of the raw output Struct — the output
|
|
@@ -675,7 +555,6 @@ function ThreadTaskPreviewBody({
|
|
|
675
555
|
item,
|
|
676
556
|
outputIO,
|
|
677
557
|
approvalSummary,
|
|
678
|
-
onOpenAgentExecution,
|
|
679
558
|
}: {
|
|
680
559
|
readonly item: WorkflowThreadItem;
|
|
681
560
|
readonly outputIO: TaskDetailIO | null;
|
|
@@ -683,10 +562,6 @@ function ThreadTaskPreviewBody({
|
|
|
683
562
|
readonly request: TaskApprovalRequestView;
|
|
684
563
|
readonly decision: TaskDetailApprovalDecision | null;
|
|
685
564
|
};
|
|
686
|
-
readonly onOpenAgentExecution?: (
|
|
687
|
-
childExecutionId: string,
|
|
688
|
-
taskName: string,
|
|
689
|
-
) => void;
|
|
690
565
|
}) {
|
|
691
566
|
return (
|
|
692
567
|
<div className="flex flex-col gap-2">
|
|
@@ -708,19 +583,6 @@ function ThreadTaskPreviewBody({
|
|
|
708
583
|
) : (
|
|
709
584
|
outputIO && <ThreadTaskIOSection label="Output" io={outputIO} />
|
|
710
585
|
)}
|
|
711
|
-
|
|
712
|
-
{item.variant === "agent-call" &&
|
|
713
|
-
item.childExecutionId &&
|
|
714
|
-
onOpenAgentExecution && (
|
|
715
|
-
<div>
|
|
716
|
-
<ThreadActionButton
|
|
717
|
-
label="Open transcript"
|
|
718
|
-
onClick={() =>
|
|
719
|
-
onOpenAgentExecution(item.childExecutionId, item.taskName)
|
|
720
|
-
}
|
|
721
|
-
/>
|
|
722
|
-
</div>
|
|
723
|
-
)}
|
|
724
586
|
</div>
|
|
725
587
|
);
|
|
726
588
|
}
|
|
@@ -729,15 +591,10 @@ function ThreadTaskDetail({
|
|
|
729
591
|
item,
|
|
730
592
|
inputIO,
|
|
731
593
|
outputIO,
|
|
732
|
-
onOpenAgentExecution,
|
|
733
594
|
}: {
|
|
734
595
|
readonly item: WorkflowThreadItem;
|
|
735
596
|
readonly inputIO: TaskDetailIO | null;
|
|
736
597
|
readonly outputIO: TaskDetailIO | null;
|
|
737
|
-
readonly onOpenAgentExecution?: (
|
|
738
|
-
childExecutionId: string,
|
|
739
|
-
taskName: string,
|
|
740
|
-
) => void;
|
|
741
598
|
}) {
|
|
742
599
|
const rows: Array<[string, string]> = [["Status", statusLabel(item.status)]];
|
|
743
600
|
if (item.durationMs > 0) {
|
|
@@ -776,19 +633,6 @@ function ThreadTaskDetail({
|
|
|
776
633
|
the card; Inspect is the opt-in debug drill-down. */}
|
|
777
634
|
{inputIO && <ThreadTaskIOSection label="Input" io={inputIO} />}
|
|
778
635
|
{outputIO && <ThreadTaskIOSection label="Output" io={outputIO} />}
|
|
779
|
-
|
|
780
|
-
{item.variant === "agent-call" &&
|
|
781
|
-
item.childExecutionId &&
|
|
782
|
-
onOpenAgentExecution && (
|
|
783
|
-
<div>
|
|
784
|
-
<ThreadActionButton
|
|
785
|
-
label="Open transcript"
|
|
786
|
-
onClick={() =>
|
|
787
|
-
onOpenAgentExecution(item.childExecutionId, item.taskName)
|
|
788
|
-
}
|
|
789
|
-
/>
|
|
790
|
-
</div>
|
|
791
|
-
)}
|
|
792
636
|
</div>
|
|
793
637
|
);
|
|
794
638
|
}
|
|
@@ -317,13 +317,19 @@ function notificationLine(state: DerivedTaskState): string | null {
|
|
|
317
317
|
return channel;
|
|
318
318
|
}
|
|
319
319
|
|
|
320
|
-
/** `approve · by
|
|
320
|
+
/** `approve · by Ada Lovelace` — the settled decision from the task output. */
|
|
321
321
|
function humanInputLine(output: JsonObject | null): string | null {
|
|
322
322
|
// The gating state is covered by the universal "Awaiting approval" line;
|
|
323
323
|
// this renders only the settled decision record.
|
|
324
324
|
const outcome = asString(output?.["outcome"]);
|
|
325
325
|
if (!outcome) return null;
|
|
326
|
-
|
|
326
|
+
// Fallback ladder over the reviewer_actor display snapshot: name → email
|
|
327
|
+
// → raw canonical id (legacy records only) → omit the "by" segment.
|
|
328
|
+
const actor = asObject(output?.["reviewer_actor"]);
|
|
329
|
+
const reviewer =
|
|
330
|
+
asString(actor?.["display_name"]) ??
|
|
331
|
+
asString(actor?.["email"]) ??
|
|
332
|
+
asString(output?.["reviewer"]);
|
|
327
333
|
return reviewer ? `${outcome} · by ${reviewer}` : outcome;
|
|
328
334
|
}
|
|
329
335
|
|
|
@@ -16,10 +16,6 @@ import {
|
|
|
16
16
|
FILE_CHANGE_DOCUMENT_ENTRY_ID,
|
|
17
17
|
fileChangeTabPath,
|
|
18
18
|
} from "../execution/file-change-document.js";
|
|
19
|
-
import {
|
|
20
|
-
AGENT_EXECUTION_DOCUMENT_ENTRY_ID,
|
|
21
|
-
agentExecutionTabPath,
|
|
22
|
-
} from "../execution/agent-execution-document.js";
|
|
23
19
|
import {
|
|
24
20
|
DIAGNOSIS_DOCUMENT_ENTRY_ID,
|
|
25
21
|
DIAGNOSIS_DOCUMENT_PATH,
|
|
@@ -112,24 +108,6 @@ export interface WorkflowExecutionPanelController {
|
|
|
112
108
|
* open/activate split. A no-op if the change is not open.
|
|
113
109
|
*/
|
|
114
110
|
readonly pinFileChange: (change: FileChange) => void;
|
|
115
|
-
/**
|
|
116
|
-
* Open (or focus) a child AgentExecution's transcript as an editor-pane
|
|
117
|
-
* document tab and expand the panel — the S4 in-place expansion. Same
|
|
118
|
-
* preview-slot semantics as {@link openArtifact}: casually stepping
|
|
119
|
-
* through agent calls reuses one tab; pinning keeps one around.
|
|
120
|
-
*/
|
|
121
|
-
readonly openAgentExecution: (
|
|
122
|
-
childExecutionId: string,
|
|
123
|
-
taskName: string,
|
|
124
|
-
) => void;
|
|
125
|
-
/**
|
|
126
|
-
* Pin a child AgentExecution's transcript tab — the double-click half of
|
|
127
|
-
* the open/activate split. A no-op if the transcript is not open.
|
|
128
|
-
*/
|
|
129
|
-
readonly pinAgentExecution: (
|
|
130
|
-
childExecutionId: string,
|
|
131
|
-
taskName: string,
|
|
132
|
-
) => void;
|
|
133
111
|
}
|
|
134
112
|
|
|
135
113
|
/** Options for {@link useWorkflowExecutionPanel}. */
|
|
@@ -213,27 +191,6 @@ export function useWorkflowExecutionPanel({
|
|
|
213
191
|
[editorsStore],
|
|
214
192
|
);
|
|
215
193
|
|
|
216
|
-
const openAgentExecution = useCallback(
|
|
217
|
-
(childExecutionId: string, taskName: string) => {
|
|
218
|
-
editorsStore.openPreview(
|
|
219
|
-
AGENT_EXECUTION_DOCUMENT_ENTRY_ID,
|
|
220
|
-
agentExecutionTabPath(childExecutionId, taskName),
|
|
221
|
-
);
|
|
222
|
-
setIsOpen(true);
|
|
223
|
-
},
|
|
224
|
-
[editorsStore],
|
|
225
|
-
);
|
|
226
|
-
|
|
227
|
-
const pinAgentExecution = useCallback(
|
|
228
|
-
(childExecutionId: string, taskName: string) => {
|
|
229
|
-
editorsStore.pin(
|
|
230
|
-
AGENT_EXECUTION_DOCUMENT_ENTRY_ID,
|
|
231
|
-
agentExecutionTabPath(childExecutionId, taskName),
|
|
232
|
-
);
|
|
233
|
-
},
|
|
234
|
-
[editorsStore],
|
|
235
|
-
);
|
|
236
|
-
|
|
237
194
|
const activateEditor = useCallback(
|
|
238
195
|
(entryId: string, path: string) => editorsStore.activate(entryId, path),
|
|
239
196
|
[editorsStore],
|
|
@@ -266,8 +223,6 @@ export function useWorkflowExecutionPanel({
|
|
|
266
223
|
pinArtifact,
|
|
267
224
|
openFileChange,
|
|
268
225
|
pinFileChange,
|
|
269
|
-
openAgentExecution,
|
|
270
|
-
pinAgentExecution,
|
|
271
226
|
}),
|
|
272
227
|
[
|
|
273
228
|
editorsStore,
|
|
@@ -285,8 +240,6 @@ export function useWorkflowExecutionPanel({
|
|
|
285
240
|
pinArtifact,
|
|
286
241
|
openFileChange,
|
|
287
242
|
pinFileChange,
|
|
288
|
-
openAgentExecution,
|
|
289
|
-
pinAgentExecution,
|
|
290
243
|
],
|
|
291
244
|
);
|
|
292
245
|
}
|