@stigmer/react 3.0.8-dev.20260613041848 → 3.0.8-dev.20260613071809

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (92) hide show
  1. package/composer/ComposerToolbar.d.ts +9 -1
  2. package/composer/ComposerToolbar.d.ts.map +1 -1
  3. package/composer/ComposerToolbar.js +3 -3
  4. package/composer/ComposerToolbar.js.map +1 -1
  5. package/composer/SessionComposer.d.ts +12 -0
  6. package/composer/SessionComposer.d.ts.map +1 -1
  7. package/composer/SessionComposer.js +6 -3
  8. package/composer/SessionComposer.js.map +1 -1
  9. package/composer/icons.d.ts +2 -0
  10. package/composer/icons.d.ts.map +1 -1
  11. package/composer/icons.js +4 -0
  12. package/composer/icons.js.map +1 -1
  13. package/execution/ExecutionProgress.d.ts.map +1 -1
  14. package/execution/ExecutionProgress.js +5 -1
  15. package/execution/ExecutionProgress.js.map +1 -1
  16. package/execution/MessageEntry.d.ts +7 -0
  17. package/execution/MessageEntry.d.ts.map +1 -1
  18. package/execution/MessageEntry.js +7 -4
  19. package/execution/MessageEntry.js.map +1 -1
  20. package/execution/MessageThread.d.ts +45 -3
  21. package/execution/MessageThread.d.ts.map +1 -1
  22. package/execution/MessageThread.js +66 -11
  23. package/execution/MessageThread.js.map +1 -1
  24. package/execution/index.d.ts +2 -0
  25. package/execution/index.d.ts.map +1 -1
  26. package/execution/index.js +1 -0
  27. package/execution/index.js.map +1 -1
  28. package/execution/useAgentExecutionActions.d.ts +67 -0
  29. package/execution/useAgentExecutionActions.d.ts.map +1 -0
  30. package/execution/useAgentExecutionActions.js +105 -0
  31. package/execution/useAgentExecutionActions.js.map +1 -0
  32. package/execution/useExecutionStream.d.ts +27 -0
  33. package/execution/useExecutionStream.d.ts.map +1 -1
  34. package/execution/useExecutionStream.js +48 -5
  35. package/execution/useExecutionStream.js.map +1 -1
  36. package/index.d.ts +2 -2
  37. package/index.d.ts.map +1 -1
  38. package/index.js +1 -1
  39. package/index.js.map +1 -1
  40. package/internal/VirtualizedThread.d.ts +4 -1
  41. package/internal/VirtualizedThread.d.ts.map +1 -1
  42. package/internal/VirtualizedThread.js +5 -2
  43. package/internal/VirtualizedThread.js.map +1 -1
  44. package/internal/store/conversation-store.d.ts +22 -0
  45. package/internal/store/conversation-store.d.ts.map +1 -1
  46. package/internal/store/conversation-store.js +43 -2
  47. package/internal/store/conversation-store.js.map +1 -1
  48. package/internal/stream-controller.d.ts +46 -2
  49. package/internal/stream-controller.d.ts.map +1 -1
  50. package/internal/stream-controller.js +95 -4
  51. package/internal/stream-controller.js.map +1 -1
  52. package/internal/useFetch.d.ts +7 -0
  53. package/internal/useFetch.d.ts.map +1 -1
  54. package/internal/useFetch.js +21 -0
  55. package/internal/useFetch.js.map +1 -1
  56. package/package.json +4 -4
  57. package/session/SessionViewer.js +39 -2
  58. package/session/SessionViewer.js.map +1 -1
  59. package/session/useSessionConversation.d.ts +55 -3
  60. package/session/useSessionConversation.d.ts.map +1 -1
  61. package/session/useSessionConversation.js +95 -10
  62. package/session/useSessionConversation.js.map +1 -1
  63. package/session/useSessionExecutions.d.ts +17 -1
  64. package/session/useSessionExecutions.d.ts.map +1 -1
  65. package/session/useSessionExecutions.js +6 -2
  66. package/session/useSessionExecutions.js.map +1 -1
  67. package/src/composer/ComposerToolbar.tsx +32 -9
  68. package/src/composer/SessionComposer.tsx +22 -1
  69. package/src/composer/__tests__/SessionComposer-stop.test.tsx +98 -0
  70. package/src/composer/icons.tsx +15 -0
  71. package/src/execution/ExecutionProgress.tsx +12 -0
  72. package/src/execution/MessageEntry.tsx +57 -2
  73. package/src/execution/MessageThread.tsx +203 -5
  74. package/src/execution/__tests__/MessageThread.test.tsx +130 -0
  75. package/src/execution/__tests__/useAgentExecutionActions.test.tsx +299 -0
  76. package/src/execution/__tests__/useExecutionStream.test.tsx +95 -0
  77. package/src/execution/index.ts +6 -0
  78. package/src/execution/useAgentExecutionActions.ts +205 -0
  79. package/src/execution/useExecutionStream.ts +80 -4
  80. package/src/index.ts +3 -0
  81. package/src/internal/VirtualizedThread.tsx +10 -1
  82. package/src/internal/__tests__/stream-controller.test.ts +165 -10
  83. package/src/internal/__tests__/useFetch.test.tsx +59 -0
  84. package/src/internal/store/__tests__/conversation-store.test.ts +61 -0
  85. package/src/internal/store/conversation-store.ts +46 -3
  86. package/src/internal/stream-controller.ts +123 -3
  87. package/src/internal/useFetch.ts +26 -0
  88. package/src/session/SessionViewer.tsx +87 -1
  89. package/src/session/__tests__/useSessionConversation.test.tsx +145 -0
  90. package/src/session/useSessionConversation.ts +163 -14
  91. package/src/session/useSessionExecutions.ts +23 -1
  92. package/styles.css +1 -1
@@ -1,16 +1,26 @@
1
1
  "use client";
2
- import { useCallback, useEffect, useMemo, useState } from "react";
2
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
3
+ import { ExecutionPhase } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
3
4
  import { isTerminalPhase } from "../execution/execution-phases";
4
5
  import { useStigmer } from "../hooks";
6
+ import { toError } from "../internal/toError";
5
7
  import { useConversationStoreRef } from "../internal/store";
6
8
  import { useCreateAgentExecution } from "../execution/useCreateAgentExecution";
7
9
  import { useExecutionStream } from "../execution/useExecutionStream";
10
+ import { useAgentExecutionActions } from "../execution/useAgentExecutionActions";
8
11
  import { useSubmitApproval } from "../execution/useSubmitApproval";
9
12
  import { useSession } from "./useSession";
10
13
  import { useSessionExecutions } from "./useSessionExecutions";
11
14
  import { useUpdateSession } from "./useUpdateSession";
12
15
  import { useLocalSessionWorker } from "./useLocalSessionWorker";
13
16
  import { specWorkspaceToInput, specMcpUsagesToInput, specSkillRefsToInput, } from "./session-spec-converters";
17
+ /**
18
+ * Cadence for re-discovering the session's executions while the live stream
19
+ * cannot be relied on (a created-but-not-yet-listed execution, a silent
20
+ * connect-timeout, or an exhausted stream error). Disabled the instant the
21
+ * stream is healthy or terminal, so this never competes with the live feed.
22
+ */
23
+ const REDISCOVERY_POLL_INTERVAL_MS = 5_000;
14
24
  /**
15
25
  * Behavior hook that encapsulates the full conversation lifecycle for
16
26
  * a session: loading data, streaming the active execution, submitting
@@ -62,8 +72,17 @@ import { specWorkspaceToInput, specMcpUsagesToInput, specSkillRefsToInput, } fro
62
72
  export function useSessionConversation(sessionId, org) {
63
73
  const stigmer = useStigmer();
64
74
  const { session, isLoading: sessionLoading, error: sessionError, refetch: refetchSession, } = useSession(sessionId);
65
- const { executions, isLoading: executionsLoading, error: executionsError, refetch, } = useSessionExecutions(sessionId);
66
- const { create, isCreating, error: createError, clearError: clearCreateError, } = useCreateAgentExecution();
75
+ // Bounded re-discovery (see REDISCOVERY_POLL_INTERVAL_MS). The gate depends on
76
+ // the stream below, so the decision is synced into state via an effect and fed
77
+ // back here on the next render — a one-frame lag that is immaterial at 5s.
78
+ const [rediscoveryActive, setRediscoveryActive] = useState(false);
79
+ const { executions, isLoading: executionsLoading, error: executionsError, refetch, } = useSessionExecutions(sessionId, {
80
+ refetchInterval: rediscoveryActive ? REDISCOVERY_POLL_INTERVAL_MS : false,
81
+ // Re-list on app-relaunch / tab refocus so an execution that appeared while
82
+ // backgrounded is picked up without the user having to act.
83
+ refetchOnWindowFocus: true,
84
+ });
85
+ const { create, isCreating, clearError: clearCreateError, } = useCreateAgentExecution();
67
86
  const { update: updateSession } = useUpdateSession();
68
87
  const { submitApproval: rawSubmitApproval, submittingToolCallIds, error: approvalError, clearError: clearApprovalError, } = useSubmitApproval();
69
88
  // Local execution: attach the session's runner worker while it is open and
@@ -71,6 +90,11 @@ export function useSessionConversation(sessionId, org) {
71
90
  useLocalSessionWorker(sessionId, session);
72
91
  const [pendingExecutionId, setPendingExecutionId] = useState(null);
73
92
  const [pendingUserMessage, setPendingUserMessage] = useState(null);
93
+ // Dedicated send-failure state, distinct from the create hook's internal
94
+ // error so it can also cover the session.update() path. The last send's
95
+ // arguments are captured for an exact retry.
96
+ const [sendError, setSendError] = useState(null);
97
+ const lastSendRef = useRef(null);
74
98
  const listActiveId = useMemo(() => {
75
99
  for (let i = executions.length - 1; i >= 0; i--) {
76
100
  const phase = executions[i].status?.phase;
@@ -89,6 +113,21 @@ export function useSessionConversation(sessionId, org) {
89
113
  const stream = useExecutionStream(activeExecutionId, {
90
114
  store: conversationStore,
91
115
  });
116
+ // Re-discovery gate. Poll only while the live stream cannot carry us:
117
+ // • a fresh session whose first execution is created but not yet listed
118
+ // (`executions.length === 0`) — the race this fix targets,
119
+ // • a silent connect-timeout, or an exhausted stream error.
120
+ // Never while the stream is healthy (`isStreaming`) or the active execution
121
+ // has reached a terminal phase — the live feed is then the source of truth.
122
+ const streamTerminal = activeExecutionId !== null && isTerminalPhase(stream.phase);
123
+ const needsRediscovery = !stream.isStreaming &&
124
+ !streamTerminal &&
125
+ ((activeExecutionId === null && executions.length === 0) ||
126
+ stream.connectTimedOut ||
127
+ stream.error !== null);
128
+ useEffect(() => {
129
+ setRediscoveryActive(needsRediscovery);
130
+ }, [needsRediscovery]);
92
131
  // Clear pendingExecutionId once the execution appears in the fetched list
93
132
  useEffect(() => {
94
133
  if (pendingExecutionId &&
@@ -96,12 +135,20 @@ export function useSessionConversation(sessionId, org) {
96
135
  setPendingExecutionId(null);
97
136
  }
98
137
  }, [pendingExecutionId, executions]);
99
- // Clear optimistic message once the stream delivers its first snapshot
138
+ // Clear the optimistic message and any stale send error — once the stream
139
+ // delivers a real snapshot. This also handles recovery: if a failed send's
140
+ // execution is later re-discovered and streams, the failed turn resolves into
141
+ // the live one instead of lingering. (At send time the composer is only
142
+ // enabled when no execution is active, so a *fresh* failure cannot be cleared
143
+ // here prematurely — `stream.execution` is null then.)
100
144
  useEffect(() => {
101
- if (pendingUserMessage && stream.execution) {
145
+ if (!stream.execution)
146
+ return;
147
+ if (pendingUserMessage)
102
148
  setPendingUserMessage(null);
103
- }
104
- }, [pendingUserMessage, stream.execution]);
149
+ if (sendError)
150
+ setSendError(null);
151
+ }, [pendingUserMessage, sendError, stream.execution]);
105
152
  // Refetch executions when stream reaches a terminal phase so the
106
153
  // fetched list reflects the completed status and listActiveId clears.
107
154
  useEffect(() => {
@@ -125,6 +172,22 @@ export function useSessionConversation(sessionId, org) {
125
172
  return null;
126
173
  return stream.phase;
127
174
  }, [activeExecutionId, stream.phase]);
175
+ // Stop is only valid in phases the backend cancels/terminates from
176
+ // (PENDING / IN_PROGRESS). Other non-terminal phases (e.g.
177
+ // WAITING_FOR_APPROVAL) are handled by their own control surface.
178
+ const isStoppable = activePhase === ExecutionPhase.EXECUTION_PENDING ||
179
+ activePhase === ExecutionPhase.EXECUTION_IN_PROGRESS;
180
+ const stopActions = useAgentExecutionActions(activeExecutionId, {
181
+ // The cancel/terminate also broadcasts the new phase over the stream, but
182
+ // refetch is the belt-and-suspenders that clears the active id even if the
183
+ // stream has already ended — mirrors the workflow viewer's onSuccess.
184
+ onSuccess: refetch,
185
+ });
186
+ const stop = useCallback(async (reason) => {
187
+ if (!isStoppable)
188
+ return;
189
+ await stopActions.stop(reason);
190
+ }, [isStoppable, stopActions.stop]);
128
191
  const canSendFollowUp = !isCreating && activeExecutionId === null;
129
192
  const workspaceEntries = useMemo(() => session?.spec?.workspaceEntries ?? [], [session]);
130
193
  const mcpServerUsages = useMemo(() => session?.spec?.mcpServerUsages ?? [], [session]);
@@ -132,6 +195,9 @@ export function useSessionConversation(sessionId, org) {
132
195
  const sendFollowUp = useCallback(async (message, options) => {
133
196
  if (!sessionId || !session)
134
197
  return;
198
+ // Capture for retry and clear any prior failure before the new attempt.
199
+ lastSendRef.current = { message, options };
200
+ setSendError(null);
135
201
  setPendingUserMessage(message);
136
202
  try {
137
203
  const needsSessionUpdate = options?.agentInstanceId !== undefined ||
@@ -166,12 +232,24 @@ export function useSessionConversation(sessionId, org) {
166
232
  refetch();
167
233
  }
168
234
  catch (err) {
169
- setPendingUserMessage(null);
235
+ // Surface the failure and KEEP the user's message visible (do not clear
236
+ // pendingUserMessage) so the turn renders as failed-with-retry instead
237
+ // of vanishing. Covers both the update() and create() paths.
238
+ setSendError(toError(err));
170
239
  if (process.env.NODE_ENV !== "production") {
171
240
  console.error("[useSessionConversation] sendFollowUp failed:", err);
172
241
  }
173
242
  }
174
243
  }, [sessionId, session, org, stigmer, create, updateSession, refetch, refetchSession]);
244
+ const retryLastSend = useCallback(() => {
245
+ const last = lastSendRef.current;
246
+ if (last)
247
+ void sendFollowUp(last.message, last.options);
248
+ }, [sendFollowUp]);
249
+ const clearSendError = useCallback(() => {
250
+ setSendError(null);
251
+ clearCreateError();
252
+ }, [clearCreateError]);
175
253
  const pendingApprovals = useMemo(() => activeStreamExecution?.status?.pendingApprovals ?? [], [activeStreamExecution]);
176
254
  const submitApproval = useCallback(async (toolCallId, action, comment) => {
177
255
  if (!activeExecutionId)
@@ -190,8 +268,9 @@ export function useSessionConversation(sessionId, org) {
190
268
  sendFollowUp,
191
269
  canSendFollowUp,
192
270
  isSending: isCreating,
193
- sendError: createError,
194
- clearSendError: clearCreateError,
271
+ sendError,
272
+ clearSendError,
273
+ retryLastSend,
195
274
  pendingUserMessage,
196
275
  workspaceEntries,
197
276
  mcpServerUsages,
@@ -201,9 +280,15 @@ export function useSessionConversation(sessionId, org) {
201
280
  submittingApprovalIds: submittingToolCallIds,
202
281
  approvalError,
203
282
  clearApprovalError,
283
+ isStoppable,
284
+ stop,
285
+ isStopping: stopActions.isSubmitting,
286
+ stopError: stopActions.error,
204
287
  isLoading,
205
288
  loadError,
206
289
  isReconnecting: stream.isReconnecting,
290
+ connectTimedOut: stream.connectTimedOut,
291
+ isSlow: stream.isSlow,
207
292
  streamError: stream.error,
208
293
  reconnectStream: stream.reconnect,
209
294
  };
@@ -1 +1 @@
1
- {"version":3,"file":"useSessionConversation.js","sourceRoot":"","sources":["../../src/session/useSessionConversation.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"useSessionConversation.js","sourceRoot":"","sources":["../../src/session/useSessionConversation.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,20 @@
1
1
  import type { AgentExecution } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
2
+ /** Options for {@link useSessionExecutions}. */
3
+ export interface UseSessionExecutionsOptions {
4
+ /**
5
+ * Poll interval in milliseconds for re-listing the session's executions.
6
+ * Used by the conversation loop to re-discover a created-but-not-yet-listed
7
+ * execution. Pass `false` (the default) to disable polling and rely on the
8
+ * live stream plus imperative {@link UseSessionExecutionsReturn.refetch}.
9
+ */
10
+ readonly refetchInterval?: number | false;
11
+ /**
12
+ * Re-list when the window regains focus / the tab becomes visible — covers
13
+ * the app-relaunch case where an execution may have appeared while
14
+ * backgrounded. Defaults to `false`.
15
+ */
16
+ readonly refetchOnWindowFocus?: boolean;
17
+ }
2
18
  /** Return value of {@link useSessionExecutions}. */
3
19
  export interface UseSessionExecutionsReturn {
4
20
  /** All executions for the session, empty while loading or on error. */
@@ -46,5 +62,5 @@ export interface UseSessionExecutionsReturn {
46
62
  * const { executions } = useSessionExecutions(sessionId ?? null);
47
63
  * ```
48
64
  */
49
- export declare function useSessionExecutions(sessionId: string | null): UseSessionExecutionsReturn;
65
+ export declare function useSessionExecutions(sessionId: string | null, options?: UseSessionExecutionsOptions): UseSessionExecutionsReturn;
50
66
  //# sourceMappingURL=useSessionExecutions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"useSessionExecutions.d.ts","sourceRoot":"","sources":["../../src/session/useSessionExecutions.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6DAA6D,CAAC;AAKlG,oDAAoD;AACpD,MAAM,WAAW,0BAA0B;IACzC,uEAAuE;IACvE,QAAQ,CAAC,UAAU,EAAE,SAAS,cAAc,EAAE,CAAC;IAC/C,mDAAmD;IACnD,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,sDAAsD;IACtD,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,kEAAkE;IAClE,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IAC7B,2EAA2E;IAC3E,QAAQ,CAAC,OAAO,EAAE,MAAM,IAAI,CAAC;CAC9B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,MAAM,GAAG,IAAI,GACvB,0BAA0B,CAqB5B"}
1
+ {"version":3,"file":"useSessionExecutions.d.ts","sourceRoot":"","sources":["../../src/session/useSessionExecutions.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,6DAA6D,CAAC;AAKlG,gDAAgD;AAChD,MAAM,WAAW,2BAA2B;IAC1C;;;;;OAKG;IACH,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IAC1C;;;;OAIG;IACH,QAAQ,CAAC,oBAAoB,CAAC,EAAE,OAAO,CAAC;CACzC;AAED,oDAAoD;AACpD,MAAM,WAAW,0BAA0B;IACzC,uEAAuE;IACvE,QAAQ,CAAC,UAAU,EAAE,SAAS,cAAc,EAAE,CAAC;IAC/C,mDAAmD;IACnD,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,sDAAsD;IACtD,QAAQ,CAAC,YAAY,EAAE,OAAO,CAAC;IAC/B,kEAAkE;IAClE,QAAQ,CAAC,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;IAC7B,2EAA2E;IAC3E,QAAQ,CAAC,OAAO,EAAE,MAAM,IAAI,CAAC;CAC9B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAgB,oBAAoB,CAClC,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,OAAO,CAAC,EAAE,2BAA2B,GACpC,0BAA0B,CAyB5B"}
@@ -37,7 +37,7 @@ import { useFetch } from "../internal/useFetch";
37
37
  * const { executions } = useSessionExecutions(sessionId ?? null);
38
38
  * ```
39
39
  */
40
- export function useSessionExecutions(sessionId) {
40
+ export function useSessionExecutions(sessionId, options) {
41
41
  const stigmer = useStigmer();
42
42
  const { data: executions, isLoading, isRefetching, error, refetch } = useFetch(sessionId
43
43
  ? () => stigmer.agentExecution
@@ -46,7 +46,11 @@ export function useSessionExecutions(sessionId) {
46
46
  pageSize: 100,
47
47
  }))
48
48
  .then((result) => result.entries)
49
- : null, [sessionId, stigmer], [], { cacheKey: sessionId ? `session-executions:${sessionId}` : undefined });
49
+ : null, [sessionId, stigmer], [], {
50
+ cacheKey: sessionId ? `session-executions:${sessionId}` : undefined,
51
+ refetchInterval: options?.refetchInterval,
52
+ refetchOnWindowFocus: options?.refetchOnWindowFocus,
53
+ });
50
54
  return { executions, isLoading, isRefetching, error, refetch };
51
55
  }
52
56
  //# sourceMappingURL=useSessionExecutions.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"useSessionExecutions.js","sourceRoot":"","sources":["../../src/session/useSessionExecutions.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE5C,OAAO,EAAE,yCAAyC,EAAE,MAAM,4DAA4D,CAAC;AACvH,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAgBhD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,MAAM,UAAU,oBAAoB,CAClC,SAAwB;IAExB,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;IAE7B,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,QAAQ,CAC5E,SAAS;QACP,CAAC,CAAC,GAAG,EAAE,CACH,OAAO,CAAC,cAAc;aACnB,aAAa,CACZ,MAAM,CAAC,yCAAyC,EAAE;YAChD,SAAS;YACT,QAAQ,EAAE,GAAG;SACd,CAAC,CACH;aACA,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC;QACvC,CAAC,CAAC,IAAI,EACR,CAAC,SAAS,EAAE,OAAO,CAAC,EACpB,EAAsB,EACtB,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC,sBAAsB,SAAS,EAAE,CAAC,CAAC,CAAC,SAAS,EAAE,CACxE,CAAC;IAEF,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;AACjE,CAAC"}
1
+ {"version":3,"file":"useSessionExecutions.js","sourceRoot":"","sources":["../../src/session/useSessionExecutions.ts"],"names":[],"mappings":"AAAA,YAAY,CAAC;AAEb,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAE5C,OAAO,EAAE,yCAAyC,EAAE,MAAM,4DAA4D,CAAC;AACvH,OAAO,EAAE,UAAU,EAAE,MAAM,UAAU,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,MAAM,sBAAsB,CAAC;AAiChD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,MAAM,UAAU,oBAAoB,CAClC,SAAwB,EACxB,OAAqC;IAErC,MAAM,OAAO,GAAG,UAAU,EAAE,CAAC;IAE7B,MAAM,EAAE,IAAI,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,QAAQ,CAC5E,SAAS;QACP,CAAC,CAAC,GAAG,EAAE,CACH,OAAO,CAAC,cAAc;aACnB,aAAa,CACZ,MAAM,CAAC,yCAAyC,EAAE;YAChD,SAAS;YACT,QAAQ,EAAE,GAAG;SACd,CAAC,CACH;aACA,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC;QACvC,CAAC,CAAC,IAAI,EACR,CAAC,SAAS,EAAE,OAAO,CAAC,EACpB,EAAsB,EACtB;QACE,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC,sBAAsB,SAAS,EAAE,CAAC,CAAC,CAAC,SAAS;QACnE,eAAe,EAAE,OAAO,EAAE,eAAe;QACzC,oBAAoB,EAAE,OAAO,EAAE,oBAAoB;KACpD,CACF,CAAC;IAEF,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC;AACjE,CAAC"}
@@ -12,6 +12,7 @@ import {
12
12
  WorkspaceIcon,
13
13
  ArrowUpIcon,
14
14
  SpinnerIcon,
15
+ StopIcon,
15
16
  } from "./icons";
16
17
 
17
18
  export interface ComposerToolbarProps {
@@ -19,6 +20,14 @@ export interface ComposerToolbarProps {
19
20
  readonly isSubmitting: boolean;
20
21
  readonly canSend: boolean;
21
22
  readonly onSend: () => void;
23
+ /**
24
+ * When provided, the primary button becomes a Stop control (enabled even
25
+ * while the rest of the composer is disabled) and the Send button is hidden.
26
+ * Driven by the active execution being stoppable.
27
+ */
28
+ readonly onStop?: () => void;
29
+ /** `true` while a stop request is in flight — shows a spinner on the Stop button. */
30
+ readonly isStopping?: boolean;
22
31
 
23
32
  // -- Left group: Primary state --------------------------------------------
24
33
 
@@ -82,6 +91,8 @@ export function ComposerToolbar({
82
91
  isSubmitting,
83
92
  canSend,
84
93
  onSend,
94
+ onStop,
95
+ isStopping = false,
85
96
  showAttach,
86
97
  attachmentCount,
87
98
  onAttachClick,
@@ -210,15 +221,27 @@ export function ComposerToolbar({
210
221
  disabled={disabled}
211
222
  />
212
223
 
213
- <button
214
- type="button"
215
- disabled={!canSend}
216
- onClick={onSend}
217
- className="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-primary text-primary-foreground transition-colors hover:bg-primary-hover disabled:pointer-events-none disabled:opacity-40"
218
- aria-label="Send message"
219
- >
220
- {isSubmitting ? <SpinnerIcon /> : <ArrowUpIcon />}
221
- </button>
224
+ {onStop ? (
225
+ <button
226
+ type="button"
227
+ onClick={onStop}
228
+ className="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-primary text-primary-foreground transition-colors hover:bg-primary-hover"
229
+ aria-label="Stop generating"
230
+ title="Stop"
231
+ >
232
+ {isStopping ? <SpinnerIcon /> : <StopIcon />}
233
+ </button>
234
+ ) : (
235
+ <button
236
+ type="button"
237
+ disabled={!canSend}
238
+ onClick={onSend}
239
+ className="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-primary text-primary-foreground transition-colors hover:bg-primary-hover disabled:pointer-events-none disabled:opacity-40"
240
+ aria-label="Send message"
241
+ >
242
+ {isSubmitting ? <SpinnerIcon /> : <ArrowUpIcon />}
243
+ </button>
244
+ )}
222
245
  </div>
223
246
  </div>
224
247
  );
@@ -163,6 +163,19 @@ export interface SessionComposerProps {
163
163
  /** Disables the entire composer (e.g., while an execution streams). */
164
164
  readonly disabled?: boolean;
165
165
 
166
+ /**
167
+ * When provided, the Send button becomes a Stop control while an execution
168
+ * is in flight — clicking it calls this handler (graceful cancel, escalating
169
+ * to terminate on a repeat press). The textarea stays disabled, but the card
170
+ * is not dimmed so Stop reads as live and clickable.
171
+ *
172
+ * Opt-in: when omitted, the composer behaves exactly as before. Typically
173
+ * wired to `useSessionConversation`'s `stop`, gated on `isStoppable`.
174
+ */
175
+ readonly onStop?: () => void;
176
+ /** `true` while a stop request is in flight — shows a spinner on the Stop button. */
177
+ readonly isStopping?: boolean;
178
+
166
179
  /**
167
180
  * Currently selected execution harness.
168
181
  *
@@ -490,6 +503,8 @@ const SessionComposerInner = forwardRef<SessionComposerHandle, SessionComposerPr
490
503
  onSubmit,
491
504
  isSubmitting = false,
492
505
  disabled = false,
506
+ onStop,
507
+ isStopping = false,
493
508
  harness,
494
509
  onHarnessChange,
495
510
  showHarnessSelector = false,
@@ -552,6 +567,10 @@ const SessionComposerInner = forwardRef<SessionComposerHandle, SessionComposerPr
552
567
 
553
568
  const isDisabled = disabled || isSubmitting;
554
569
 
570
+ // Stop-mode: an in-flight, stoppable execution. The textarea/config stay
571
+ // disabled, but the card is kept un-dimmed so the Stop button reads as live.
572
+ const stopMode = onStop != null;
573
+
555
574
  const showAgent = onAgentRefChange != null && org != null;
556
575
  const showMcp = onMcpServerUsagesChange != null && org != null;
557
576
  const showWorkspace = workspace != null;
@@ -1324,7 +1343,7 @@ const SessionComposerInner = forwardRef<SessionComposerHandle, SessionComposerPr
1324
1343
  className={cn(
1325
1344
  "rounded-xl border border-border bg-card shadow-sm",
1326
1345
  "focus-within:ring-2 focus-within:ring-ring",
1327
- isDisabled && "opacity-50",
1346
+ isDisabled && !stopMode && "opacity-50",
1328
1347
  isDragOver && "ring-2 ring-primary/50",
1329
1348
  )}
1330
1349
  onDragOver={handleDragOver}
@@ -1448,6 +1467,8 @@ const SessionComposerInner = forwardRef<SessionComposerHandle, SessionComposerPr
1448
1467
  isSubmitting={isSubmitting}
1449
1468
  canSend={canSend}
1450
1469
  onSend={composer.submit}
1470
+ onStop={onStop}
1471
+ isStopping={isStopping}
1451
1472
  showWorkspace={showWorkspace}
1452
1473
  workspaceCount={workspaceCount}
1453
1474
  onWorkspaceDirectAction={workspaceDirectAction}
@@ -0,0 +1,98 @@
1
+ import { describe, it, expect, vi, afterEach } from "vitest";
2
+ import { render, screen, cleanup, fireEvent } from "@testing-library/react";
3
+ import type { ReactNode } from "react";
4
+ import type { Stigmer } from "@stigmer/sdk";
5
+ import { StigmerContext } from "../../context";
6
+ import { ModelRegistryContext } from "../../models/ModelRegistryContext";
7
+ import { SessionComposer } from "../SessionComposer";
8
+
9
+ // ---------------------------------------------------------------------------
10
+ // Helpers
11
+ // ---------------------------------------------------------------------------
12
+
13
+ function createMinimalStigmerMock(): Stigmer {
14
+ return {
15
+ agentExecution: { uploadAttachment: vi.fn() },
16
+ environment: { getPersonal: vi.fn().mockResolvedValue(null) },
17
+ baseUrl: "http://localhost:8080",
18
+ getAuthCredential: vi.fn().mockResolvedValue("test-token"),
19
+ config: {
20
+ baseUrl: "http://localhost:8080",
21
+ getAccessToken: vi.fn().mockResolvedValue(""),
22
+ },
23
+ } as unknown as Stigmer;
24
+ }
25
+
26
+ function createWrapper(client: Stigmer) {
27
+ return function Wrapper({ children }: { children: ReactNode }) {
28
+ return (
29
+ <StigmerContext.Provider value={client}>
30
+ <ModelRegistryContext.Provider
31
+ value={{ models: [], isLoading: false, error: null, refetch: vi.fn() }}
32
+ >
33
+ {children}
34
+ </ModelRegistryContext.Provider>
35
+ </StigmerContext.Provider>
36
+ );
37
+ };
38
+ }
39
+
40
+ function renderComposer(
41
+ props?: Partial<React.ComponentProps<typeof SessionComposer>>,
42
+ ) {
43
+ const client = createMinimalStigmerMock();
44
+ const onSubmit = vi.fn();
45
+ const result = render(
46
+ <SessionComposer onSubmit={onSubmit} {...props} />,
47
+ { wrapper: createWrapper(client) },
48
+ );
49
+ return { ...result, onSubmit, client };
50
+ }
51
+
52
+ afterEach(cleanup);
53
+
54
+ // ---------------------------------------------------------------------------
55
+ // Tests
56
+ // ---------------------------------------------------------------------------
57
+
58
+ describe("SessionComposer — Stop affordance", () => {
59
+ it("renders Send (not Stop) when onStop is not provided", () => {
60
+ renderComposer();
61
+
62
+ expect(screen.getByRole("button", { name: "Send message" })).toBeTruthy();
63
+ expect(
64
+ screen.queryByRole("button", { name: "Stop generating" }),
65
+ ).toBeNull();
66
+ });
67
+
68
+ it("renders Stop (not Send) when onStop is provided", () => {
69
+ renderComposer({ onStop: vi.fn(), disabled: true });
70
+
71
+ expect(screen.getByRole("button", { name: "Stop generating" })).toBeTruthy();
72
+ expect(
73
+ screen.queryByRole("button", { name: "Send message" }),
74
+ ).toBeNull();
75
+ });
76
+
77
+ it("clicking Stop calls onStop, even while the composer is disabled", () => {
78
+ const onStop = vi.fn();
79
+ renderComposer({ onStop, disabled: true });
80
+
81
+ fireEvent.click(screen.getByRole("button", { name: "Stop generating" }));
82
+ expect(onStop).toHaveBeenCalledTimes(1);
83
+ });
84
+
85
+ it("Stop stays clickable while stopping so the user can escalate", () => {
86
+ const onStop = vi.fn();
87
+ renderComposer({ onStop, disabled: true, isStopping: true });
88
+
89
+ const stop = screen.getByRole("button", {
90
+ name: "Stop generating",
91
+ }) as HTMLButtonElement;
92
+ expect(stop.disabled).toBe(false);
93
+
94
+ fireEvent.click(stop);
95
+ fireEvent.click(stop);
96
+ expect(onStop).toHaveBeenCalledTimes(2);
97
+ });
98
+ });
@@ -72,6 +72,21 @@ export function SpinnerIcon() {
72
72
  );
73
73
  }
74
74
 
75
+ /** Filled rounded square — the universal "stop" glyph (mirrors Cursor's composer). */
76
+ export function StopIcon() {
77
+ return (
78
+ <svg
79
+ width="16"
80
+ height="16"
81
+ viewBox="0 0 16 16"
82
+ fill="currentColor"
83
+ aria-hidden="true"
84
+ >
85
+ <rect x="4" y="4" width="8" height="8" rx="1.5" />
86
+ </svg>
87
+ );
88
+ }
89
+
75
90
  export function XIcon() {
76
91
  return (
77
92
  <svg
@@ -47,6 +47,10 @@ export function ExecutionProgress({
47
47
  if (phase === undefined) return null;
48
48
 
49
49
  const todos = execution.status?.todos;
50
+ // Populated by the server only on EXECUTION_FAILED — surface it next to the
51
+ // badge so this widget explains a failure rather than showing a bare phase
52
+ // (consistent with the failure reason in the message thread).
53
+ const error = execution.status?.error;
50
54
 
51
55
  return (
52
56
  <div
@@ -55,6 +59,14 @@ export function ExecutionProgress({
55
59
  aria-label="Execution progress"
56
60
  >
57
61
  <ExecutionPhaseBadge phase={phase} />
62
+ {error && (
63
+ <p
64
+ role="alert"
65
+ className="text-xs whitespace-pre-wrap break-words text-destructive"
66
+ >
67
+ {error}
68
+ </p>
69
+ )}
58
70
  {todos && <TodoList todos={todos} />}
59
71
  </div>
60
72
  );