@stigmer/react 3.12.5 → 3.12.7
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/agent/AgentDetailView.js +2 -2
- package/agent/AgentDetailView.js.map +1 -1
- package/agent/index.d.ts +0 -1
- package/agent/index.d.ts.map +1 -1
- package/agent/index.js +0 -1
- package/agent/index.js.map +1 -1
- package/agent/useUpdateAgent.d.ts +3 -3
- package/agent/useUpdateAgent.js +3 -3
- package/agent-instance/AgentInstanceDetailPanel.d.ts.map +1 -1
- package/agent-instance/AgentInstanceDetailPanel.js +5 -7
- package/agent-instance/AgentInstanceDetailPanel.js.map +1 -1
- package/agent-instance/useUpdateAgentInstance.d.ts +1 -1
- package/agent-instance/useUpdateAgentInstance.js +1 -1
- package/channel/AgentChannelsPanel.d.ts.map +1 -1
- package/channel/AgentChannelsPanel.js +10 -5
- package/channel/AgentChannelsPanel.js.map +1 -1
- package/channel/ChannelRunConfigDialog.d.ts +51 -0
- package/channel/ChannelRunConfigDialog.d.ts.map +1 -0
- package/channel/ChannelRunConfigDialog.js +121 -0
- package/channel/ChannelRunConfigDialog.js.map +1 -0
- package/channel/index.d.ts +2 -0
- package/channel/index.d.ts.map +1 -1
- package/channel/index.js +1 -0
- package/channel/index.js.map +1 -1
- package/channel/useSaveAgentChannel.d.ts.map +1 -1
- package/channel/useSaveAgentChannel.js +6 -3
- package/channel/useSaveAgentChannel.js.map +1 -1
- package/channel-app/ChannelAppDetailPanel.js +9 -9
- package/channel-app/ChannelAppDetailPanel.js.map +1 -1
- package/composer/ComposerToolbar.d.ts +24 -1
- package/composer/ComposerToolbar.d.ts.map +1 -1
- package/composer/ComposerToolbar.js +7 -2
- package/composer/ComposerToolbar.js.map +1 -1
- package/composer/SessionComposer.d.ts +19 -0
- package/composer/SessionComposer.d.ts.map +1 -1
- package/composer/SessionComposer.js +24 -5
- package/composer/SessionComposer.js.map +1 -1
- package/composer/index.d.ts +1 -0
- package/composer/index.d.ts.map +1 -1
- package/composer/index.js.map +1 -1
- package/cursor-accounts/CursorAccountsConsole.d.ts.map +1 -1
- package/cursor-accounts/CursorAccountsConsole.js +12 -3
- package/cursor-accounts/CursorAccountsConsole.js.map +1 -1
- package/cursor-accounts/cursor-account-coverage.d.ts +30 -1
- package/cursor-accounts/cursor-account-coverage.d.ts.map +1 -1
- package/cursor-accounts/cursor-account-coverage.js +21 -0
- package/cursor-accounts/cursor-account-coverage.js.map +1 -1
- package/execution/MessageThread.d.ts.map +1 -1
- package/execution/MessageThread.js +8 -11
- package/execution/MessageThread.js.map +1 -1
- package/execution/useCreateAgentExecution.d.ts +15 -0
- package/execution/useCreateAgentExecution.d.ts.map +1 -1
- package/execution/useCreateAgentExecution.js +5 -0
- package/execution/useCreateAgentExecution.js.map +1 -1
- package/execution/useFileChangeContent.d.ts +2 -6
- package/execution/useFileChangeContent.d.ts.map +1 -1
- package/execution/useFileChangeContent.js +4 -12
- package/execution/useFileChangeContent.js.map +1 -1
- package/identity-account/AccountPreferencesPanel.d.ts +2 -1
- package/identity-account/AccountPreferencesPanel.d.ts.map +1 -1
- package/identity-account/AccountPreferencesPanel.js +33 -18
- package/identity-account/AccountPreferencesPanel.js.map +1 -1
- package/identity-provider/IdentityProviderDetailPanel.d.ts.map +1 -1
- package/identity-provider/IdentityProviderDetailPanel.js +16 -15
- package/identity-provider/IdentityProviderDetailPanel.js.map +1 -1
- package/index.d.ts +10 -7
- package/index.d.ts.map +1 -1
- package/index.js +8 -4
- package/index.js.map +1 -1
- package/internal/download.d.ts +8 -0
- package/internal/download.d.ts.map +1 -0
- package/internal/download.js +25 -0
- package/internal/download.js.map +1 -0
- package/library/useExportResource.d.ts.map +1 -1
- package/library/useExportResource.js +3 -17
- package/library/useExportResource.js.map +1 -1
- package/mcp-server/McpServerDetailView.js +2 -2
- package/mcp-server/McpServerDetailView.js.map +1 -1
- package/mcp-server/index.d.ts +0 -1
- package/mcp-server/index.d.ts.map +1 -1
- package/mcp-server/index.js +0 -1
- package/mcp-server/index.js.map +1 -1
- package/mcp-server/internal/definitionDrift.d.ts +14 -12
- package/mcp-server/internal/definitionDrift.d.ts.map +1 -1
- package/mcp-server/internal/definitionDrift.js +22 -19
- package/mcp-server/internal/definitionDrift.js.map +1 -1
- package/mcp-server/useUpdateMcpServer.d.ts +3 -3
- package/mcp-server/useUpdateMcpServer.js +3 -3
- package/memory/MemoryListPanel.d.ts +35 -0
- package/memory/MemoryListPanel.d.ts.map +1 -0
- package/memory/MemoryListPanel.js +141 -0
- package/memory/MemoryListPanel.js.map +1 -0
- package/memory/index.d.ts +8 -0
- package/memory/index.d.ts.map +1 -0
- package/memory/index.js +12 -0
- package/memory/index.js.map +1 -0
- package/memory/memoryGroups.d.ts +31 -0
- package/memory/memoryGroups.d.ts.map +1 -0
- package/memory/memoryGroups.js +52 -0
- package/memory/memoryGroups.js.map +1 -0
- package/memory/useConfirmMemory.d.ts +31 -0
- package/memory/useConfirmMemory.d.ts.map +1 -0
- package/memory/useConfirmMemory.js +43 -0
- package/memory/useConfirmMemory.js.map +1 -0
- package/memory/useDeleteMemory.d.ts +30 -0
- package/memory/useDeleteMemory.d.ts.map +1 -0
- package/memory/useDeleteMemory.js +42 -0
- package/memory/useDeleteMemory.js.map +1 -0
- package/memory/useMemories.d.ts +33 -0
- package/memory/useMemories.d.ts.map +1 -0
- package/memory/useMemories.js +42 -0
- package/memory/useMemories.js.map +1 -0
- package/memory/useRejectMemory.d.ts +34 -0
- package/memory/useRejectMemory.d.ts.map +1 -0
- package/memory/useRejectMemory.js +46 -0
- package/memory/useRejectMemory.js.map +1 -0
- package/memory/useUpdateMemoryContent.d.ts +32 -0
- package/memory/useUpdateMemoryContent.d.ts.map +1 -0
- package/memory/useUpdateMemoryContent.js +48 -0
- package/memory/useUpdateMemoryContent.js.map +1 -0
- package/models/ModelSelector.d.ts +33 -1
- package/models/ModelSelector.d.ts.map +1 -1
- package/models/ModelSelector.js +37 -4
- package/models/ModelSelector.js.map +1 -1
- package/models/index.d.ts +2 -0
- package/models/index.d.ts.map +1 -1
- package/models/index.js +1 -0
- package/models/index.js.map +1 -1
- package/models/registry.d.ts +16 -0
- package/models/registry.d.ts.map +1 -1
- package/models/registry.js +13 -0
- package/models/registry.js.map +1 -1
- package/models/thinking-mode.d.ts +27 -0
- package/models/thinking-mode.d.ts.map +1 -0
- package/models/thinking-mode.js +32 -0
- package/models/thinking-mode.js.map +1 -0
- package/oauth-app/OAuthAppDetailPanel.d.ts.map +1 -1
- package/oauth-app/OAuthAppDetailPanel.js +21 -20
- package/oauth-app/OAuthAppDetailPanel.js.map +1 -1
- package/package.json +4 -4
- package/platform-client/PlatformClientDetailPanel.d.ts.map +1 -1
- package/platform-client/PlatformClientDetailPanel.js +12 -13
- package/platform-client/PlatformClientDetailPanel.js.map +1 -1
- package/schedule/ScheduleDetailView.d.ts.map +1 -1
- package/schedule/ScheduleDetailView.js +21 -10
- package/schedule/ScheduleDetailView.js.map +1 -1
- package/schedule/ScheduleForm.d.ts.map +1 -1
- package/schedule/ScheduleForm.js +13 -3
- package/schedule/ScheduleForm.js.map +1 -1
- package/session/NewSessionViewer.d.ts.map +1 -1
- package/session/NewSessionViewer.js +9 -1
- package/session/NewSessionViewer.js.map +1 -1
- package/session/SessionViewer.d.ts +14 -1
- package/session/SessionViewer.d.ts.map +1 -1
- package/session/SessionViewer.js +21 -25
- package/session/SessionViewer.js.map +1 -1
- package/session/TranscriptExportMenu.d.ts +24 -0
- package/session/TranscriptExportMenu.d.ts.map +1 -0
- package/session/TranscriptExportMenu.js +26 -0
- package/session/TranscriptExportMenu.js.map +1 -0
- package/session/index.d.ts +4 -0
- package/session/index.d.ts.map +1 -1
- package/session/index.js +2 -0
- package/session/index.js.map +1 -1
- package/session/run-config.d.ts +9 -0
- package/session/run-config.d.ts.map +1 -1
- package/session/run-config.js +5 -0
- package/session/run-config.js.map +1 -1
- package/session/useExportTranscript.d.ts +44 -0
- package/session/useExportTranscript.d.ts.map +1 -0
- package/session/useExportTranscript.js +109 -0
- package/session/useExportTranscript.js.map +1 -0
- package/session/useNewSessionFlow.d.ts +11 -0
- package/session/useNewSessionFlow.d.ts.map +1 -1
- package/session/useNewSessionFlow.js +20 -6
- package/session/useNewSessionFlow.js.map +1 -1
- package/session/useSessionConversation.d.ts +12 -1
- package/session/useSessionConversation.d.ts.map +1 -1
- package/session/useSessionConversation.js +21 -42
- package/session/useSessionConversation.js.map +1 -1
- package/session/useSessionExecutions.d.ts +2 -14
- package/session/useSessionExecutions.d.ts.map +1 -1
- package/session/useSessionExecutions.js +4 -26
- package/session/useSessionExecutions.js.map +1 -1
- package/session/useSessionPageFlow.d.ts +23 -10
- package/session/useSessionPageFlow.d.ts.map +1 -1
- package/session/useSessionPageFlow.js +75 -19
- package/session/useSessionPageFlow.js.map +1 -1
- package/session/useUpdateSession.d.ts +18 -24
- package/session/useUpdateSession.d.ts.map +1 -1
- package/session/useUpdateSession.js +18 -24
- package/session/useUpdateSession.js.map +1 -1
- package/settings/MemorySection.d.ts +12 -0
- package/settings/MemorySection.d.ts.map +1 -0
- package/settings/MemorySection.js +21 -0
- package/settings/MemorySection.js.map +1 -0
- package/settings/index.d.ts +1 -0
- package/settings/index.d.ts.map +1 -1
- package/settings/index.js +1 -0
- package/settings/index.js.map +1 -1
- package/settings/settings-nav.d.ts.map +1 -1
- package/settings/settings-nav.js +2 -1
- package/settings/settings-nav.js.map +1 -1
- package/src/__tests__/public-api.test.ts +21 -0
- package/src/agent/AgentDetailView.tsx +2 -2
- package/src/agent/index.ts +0 -2
- package/src/agent/useUpdateAgent.ts +3 -3
- package/src/agent-instance/AgentInstanceDetailPanel.tsx +5 -7
- package/src/agent-instance/__tests__/AgentInstanceDetailPanel.test.tsx +75 -0
- package/src/agent-instance/useUpdateAgentInstance.ts +1 -1
- package/src/channel/AgentChannelsPanel.tsx +26 -1
- package/src/channel/ChannelRunConfigDialog.tsx +351 -0
- package/src/channel/__tests__/ChannelRunConfigDialog.test.tsx +210 -0
- package/src/channel/index.ts +2 -0
- package/src/channel/useSaveAgentChannel.ts +6 -3
- package/src/channel-app/ChannelAppDetailPanel.tsx +9 -9
- package/src/channel-app/__tests__/channelAppWhatsApp.test.tsx +2 -0
- package/src/channel-app/__tests__/channelAppWipeSafety.test.tsx +87 -0
- package/src/composer/ComposerToolbar.tsx +67 -0
- package/src/composer/SessionComposer.tsx +49 -3
- package/src/composer/__tests__/ComposerToolbar-autoApprove.test.tsx +80 -0
- package/src/composer/__tests__/SessionComposer-thinkingMode.test.tsx +176 -0
- package/src/composer/index.ts +1 -0
- package/src/cursor-accounts/CursorAccountsConsole.tsx +40 -5
- package/src/cursor-accounts/__tests__/CursorAccountsConsole.test.tsx +32 -0
- package/src/cursor-accounts/__tests__/cursor-account-coverage.test.ts +58 -1
- package/src/cursor-accounts/cursor-account-coverage.ts +55 -0
- package/src/execution/MessageThread.tsx +8 -11
- package/src/execution/useCreateAgentExecution.ts +19 -0
- package/src/execution/useFileChangeContent.ts +5 -12
- package/src/identity-account/AccountPreferencesPanel.tsx +154 -68
- package/src/identity-account/__tests__/AccountPreferencesPanel.test.tsx +36 -2
- package/src/identity-provider/IdentityProviderDetailPanel.tsx +18 -15
- package/src/identity-provider/__tests__/IdentityProviderDetailPanel.test.tsx +80 -0
- package/src/index.ts +36 -2
- package/src/internal/download.ts +29 -0
- package/src/library/useExportResource.ts +3 -19
- package/src/mcp-server/McpServerDetailView.tsx +2 -2
- package/src/mcp-server/index.ts +0 -2
- package/src/mcp-server/internal/definitionDrift.ts +22 -20
- package/src/mcp-server/useUpdateMcpServer.ts +3 -3
- package/src/memory/MemoryListPanel.tsx +532 -0
- package/src/memory/__tests__/MemoryListPanel.test.tsx +259 -0
- package/src/memory/__tests__/memoryHooks.test.tsx +220 -0
- package/src/memory/index.ts +19 -0
- package/src/memory/memoryGroups.ts +64 -0
- package/src/memory/useConfirmMemory.ts +62 -0
- package/src/memory/useDeleteMemory.ts +61 -0
- package/src/memory/useMemories.ts +66 -0
- package/src/memory/useRejectMemory.ts +65 -0
- package/src/memory/useUpdateMemoryContent.ts +67 -0
- package/src/models/ModelSelector.tsx +94 -1
- package/src/models/index.ts +2 -0
- package/src/models/registry.ts +29 -0
- package/src/models/thinking-mode.ts +48 -0
- package/src/oauth-app/OAuthAppDetailPanel.tsx +23 -21
- package/src/oauth-app/__tests__/OAuthAppDetailPanel.test.tsx +94 -0
- package/src/platform-client/PlatformClientDetailPanel.tsx +14 -13
- package/src/platform-client/__tests__/PlatformClientDetailPanel.test.tsx +82 -0
- package/src/schedule/ScheduleDetailView.tsx +29 -4
- package/src/schedule/ScheduleForm.tsx +14 -1
- package/src/session/NewSessionViewer.tsx +15 -1
- package/src/session/SessionViewer.tsx +48 -49
- package/src/session/TranscriptExportMenu.tsx +78 -0
- package/src/session/__tests__/SessionViewer-autoApproveToggle.test.tsx +178 -0
- package/src/session/__tests__/SessionViewer-transcriptExport.test.tsx +151 -0
- package/src/session/__tests__/TranscriptExportMenu.test.tsx +97 -0
- package/src/session/__tests__/useExportTranscript.test.tsx +187 -0
- package/src/session/__tests__/useNewSessionFlow.test.tsx +33 -0
- package/src/session/__tests__/useSessionPageFlow.autoApprove.test.tsx +176 -2
- package/src/session/index.ts +9 -0
- package/src/session/run-config.ts +16 -0
- package/src/session/useExportTranscript.ts +171 -0
- package/src/session/useNewSessionFlow.ts +34 -7
- package/src/session/useSessionConversation.ts +42 -56
- package/src/session/useSessionExecutions.ts +5 -26
- package/src/session/useSessionPageFlow.ts +98 -32
- package/src/session/useUpdateSession.ts +18 -24
- package/src/settings/MemorySection.tsx +45 -0
- package/src/settings/index.ts +1 -0
- package/src/settings/settings-nav.ts +2 -0
- package/src/usage/useExportCSV.ts +2 -14
- package/src/workflow/ApprovalFormBuilder.tsx +20 -5
- package/src/workflow/WorkflowDetailView.tsx +2 -2
- package/src/workflow/__tests__/WorkflowInstanceDetailPanel.test.tsx +83 -0
- package/src/workflow/index.ts +0 -2
- package/src/workflow/instance/WorkflowInstanceDetailPanel.tsx +6 -7
- package/src/workflow/useUpdateWorkflow.ts +3 -3
- package/styles.css +1 -1
- package/usage/useExportCSV.d.ts.map +1 -1
- package/usage/useExportCSV.js +2 -13
- package/usage/useExportCSV.js.map +1 -1
- package/workflow/ApprovalFormBuilder.d.ts.map +1 -1
- package/workflow/ApprovalFormBuilder.js +10 -8
- package/workflow/ApprovalFormBuilder.js.map +1 -1
- package/workflow/WorkflowDetailView.js +2 -2
- package/workflow/WorkflowDetailView.js.map +1 -1
- package/workflow/index.d.ts +0 -1
- package/workflow/index.d.ts.map +1 -1
- package/workflow/index.js +0 -1
- package/workflow/index.js.map +1 -1
- package/workflow/instance/WorkflowInstanceDetailPanel.d.ts.map +1 -1
- package/workflow/instance/WorkflowInstanceDetailPanel.js +6 -7
- package/workflow/instance/WorkflowInstanceDetailPanel.js.map +1 -1
- package/workflow/useUpdateWorkflow.d.ts +3 -3
- package/workflow/useUpdateWorkflow.js +3 -3
- package/agent/internal/agentToInput.d.ts +0 -15
- package/agent/internal/agentToInput.d.ts.map +0 -1
- package/agent/internal/agentToInput.js +0 -84
- package/agent/internal/agentToInput.js.map +0 -1
- package/mcp-server/internal/mcpServerToInput.d.ts +0 -12
- package/mcp-server/internal/mcpServerToInput.d.ts.map +0 -1
- package/mcp-server/internal/mcpServerToInput.js +0 -84
- package/mcp-server/internal/mcpServerToInput.js.map +0 -1
- package/session/session-spec-converters.d.ts +0 -24
- package/session/session-spec-converters.d.ts.map +0 -1
- package/session/session-spec-converters.js +0 -72
- package/session/session-spec-converters.js.map +0 -1
- package/src/agent/internal/__tests__/agentToInput.test.ts +0 -145
- package/src/agent/internal/agentToInput.ts +0 -102
- package/src/mcp-server/__tests__/mcpServerToInput.test.ts +0 -201
- package/src/mcp-server/internal/mcpServerToInput.ts +0 -98
- package/src/session/__tests__/session-spec-converters.test.ts +0 -183
- package/src/session/session-spec-converters.ts +0 -86
- package/src/workflow/internal/workflowToInput.ts +0 -96
- package/workflow/internal/workflowToInput.d.ts +0 -12
- package/workflow/internal/workflowToInput.d.ts.map +0 -1
- package/workflow/internal/workflowToInput.js +0 -73
- package/workflow/internal/workflowToInput.js.map +0 -1
|
@@ -11,11 +11,20 @@ import { ApprovalAction } from "@stigmer/protos/ai/stigmer/agentic/agentexecutio
|
|
|
11
11
|
const mockSubmitApproval = vi.fn<(t: string, a: ApprovalAction, c?: string) => Promise<void>>();
|
|
12
12
|
const mockSendFollowUp = vi.fn();
|
|
13
13
|
|
|
14
|
+
/** Loosely-typed conversation stub — individual tests mutate the arming and
|
|
15
|
+
* gate fields, and restore them in their afterEach. */
|
|
14
16
|
const mockConv = {
|
|
15
|
-
session: { spec: {} }
|
|
17
|
+
session: { spec: {} } as {
|
|
18
|
+
spec: object;
|
|
19
|
+
metadata?: { labels?: Record<string, string> };
|
|
20
|
+
},
|
|
16
21
|
isLoading: false,
|
|
17
22
|
completedExecutions: [] as unknown[],
|
|
18
|
-
activeStreamExecution: null
|
|
23
|
+
activeStreamExecution: null as {
|
|
24
|
+
spec?: { autoApproveAll?: boolean };
|
|
25
|
+
status?: object;
|
|
26
|
+
} | null,
|
|
27
|
+
pendingApprovals: [] as { toolCallId: string }[],
|
|
19
28
|
workspaceEntries: [] as unknown[],
|
|
20
29
|
submitApproval: mockSubmitApproval,
|
|
21
30
|
sendFollowUp: mockSendFollowUp,
|
|
@@ -221,3 +230,168 @@ describe("useSessionPageFlow — host-set approval default (#302)", () => {
|
|
|
221
230
|
expect(result.current.autoApproveAll).toBe(false);
|
|
222
231
|
});
|
|
223
232
|
});
|
|
233
|
+
|
|
234
|
+
describe("useSessionPageFlow — arming derived from the in-flight run (#816)", () => {
|
|
235
|
+
afterEach(() => {
|
|
236
|
+
mockConv.activeStreamExecution = null;
|
|
237
|
+
mockConv.completedExecutions = [];
|
|
238
|
+
vi.clearAllMocks();
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
it("reflects an active execution armed at create (launcher handoff)", () => {
|
|
242
|
+
mockConv.activeStreamExecution = { spec: { autoApproveAll: true }, status: {} };
|
|
243
|
+
const { result } = renderHook(() => useSessionPageFlow(OPTS));
|
|
244
|
+
expect(result.current.autoApproveAll).toBe(true);
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
it("the user's explicit OFF beats the armed run for follow-up carry", async () => {
|
|
248
|
+
mockConv.activeStreamExecution = { spec: { autoApproveAll: true }, status: {} };
|
|
249
|
+
const { result } = renderHook(() => useSessionPageFlow(OPTS));
|
|
250
|
+
|
|
251
|
+
act(() => {
|
|
252
|
+
result.current.setAutoApproveAll(false);
|
|
253
|
+
});
|
|
254
|
+
expect(result.current.autoApproveAll).toBe(false);
|
|
255
|
+
|
|
256
|
+
await act(async () => {
|
|
257
|
+
await result.current.handleSubmit("after explicit off");
|
|
258
|
+
});
|
|
259
|
+
const followUpOpts = mockSendFollowUp.mock.calls.at(-1)?.[1];
|
|
260
|
+
expect(followUpOpts.autoApproveAll).toBeUndefined();
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
it("never derives from PAST executions (the reset-on-reload consent contract)", () => {
|
|
264
|
+
// A reloaded page whose history contains an armed run must come up at
|
|
265
|
+
// the host default — deriving from history would make the consent
|
|
266
|
+
// silently survive reloads.
|
|
267
|
+
mockConv.completedExecutions = [{ spec: { autoApproveAll: true }, status: {} }];
|
|
268
|
+
const { result } = renderHook(() => useSessionPageFlow(OPTS));
|
|
269
|
+
expect(result.current.autoApproveAll).toBe(false);
|
|
270
|
+
});
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
describe("useSessionPageFlow — armed responder (#816, the walk-away scenario)", () => {
|
|
274
|
+
beforeEach(() => {
|
|
275
|
+
mockSubmitApproval.mockResolvedValue(undefined);
|
|
276
|
+
});
|
|
277
|
+
afterEach(() => {
|
|
278
|
+
mockConv.pendingApprovals = [];
|
|
279
|
+
mockConv.activeStreamExecution = null;
|
|
280
|
+
mockConv.session = { spec: {} };
|
|
281
|
+
vi.clearAllMocks();
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
it("releases a gate that appears while armed", async () => {
|
|
285
|
+
const { rerender } = renderHook(() => useSessionPageFlow(OPTS), {
|
|
286
|
+
wrapper: hostDefaultWrapper(true),
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
mockConv.pendingApprovals = [{ toolCallId: "tc1" }];
|
|
290
|
+
await act(async () => rerender());
|
|
291
|
+
|
|
292
|
+
expect(mockSubmitApproval).toHaveBeenCalledExactlyOnceWith(
|
|
293
|
+
"tc1",
|
|
294
|
+
ApprovalAction.APPROVE_ALL,
|
|
295
|
+
);
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
it("releases a gate already waiting when the toggle flips ON", async () => {
|
|
299
|
+
mockConv.pendingApprovals = [{ toolCallId: "tc9" }];
|
|
300
|
+
const { result } = renderHook(() => useSessionPageFlow(OPTS));
|
|
301
|
+
expect(mockSubmitApproval).not.toHaveBeenCalled();
|
|
302
|
+
|
|
303
|
+
await act(async () => {
|
|
304
|
+
result.current.setAutoApproveAll(true);
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
expect(mockSubmitApproval).toHaveBeenCalledExactlyOnceWith(
|
|
308
|
+
"tc9",
|
|
309
|
+
ApprovalAction.APPROVE_ALL,
|
|
310
|
+
);
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
it("submits once per gate across re-renders", async () => {
|
|
314
|
+
const { rerender } = renderHook(() => useSessionPageFlow(OPTS), {
|
|
315
|
+
wrapper: hostDefaultWrapper(true),
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
mockConv.pendingApprovals = [{ toolCallId: "tc1" }];
|
|
319
|
+
await act(async () => rerender());
|
|
320
|
+
await act(async () => rerender());
|
|
321
|
+
|
|
322
|
+
expect(mockSubmitApproval).toHaveBeenCalledTimes(1);
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
it("covers a LATER gate of a different class (lease scope contract)", async () => {
|
|
326
|
+
// A gate-time APPROVE_ALL grants a class-scoped lease, so a second gate
|
|
327
|
+
// of another class still parks — the responder must answer it too.
|
|
328
|
+
const { rerender } = renderHook(() => useSessionPageFlow(OPTS), {
|
|
329
|
+
wrapper: hostDefaultWrapper(true),
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
mockConv.pendingApprovals = [{ toolCallId: "tc-shell" }];
|
|
333
|
+
await act(async () => rerender());
|
|
334
|
+
mockConv.pendingApprovals = [{ toolCallId: "tc-write" }];
|
|
335
|
+
await act(async () => rerender());
|
|
336
|
+
|
|
337
|
+
expect(mockSubmitApproval).toHaveBeenCalledTimes(2);
|
|
338
|
+
expect(mockSubmitApproval).toHaveBeenLastCalledWith(
|
|
339
|
+
"tc-write",
|
|
340
|
+
ApprovalAction.APPROVE_ALL,
|
|
341
|
+
);
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
it("does not retry a failed submission (the card stays for manual action)", async () => {
|
|
345
|
+
mockSubmitApproval.mockRejectedValue(new Error("boom"));
|
|
346
|
+
const { rerender } = renderHook(() => useSessionPageFlow(OPTS), {
|
|
347
|
+
wrapper: hostDefaultWrapper(true),
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
mockConv.pendingApprovals = [{ toolCallId: "tc1" }];
|
|
351
|
+
await act(async () => rerender());
|
|
352
|
+
await act(async () => rerender());
|
|
353
|
+
|
|
354
|
+
expect(mockSubmitApproval).toHaveBeenCalledTimes(1);
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
it("stays inert while OFF", async () => {
|
|
358
|
+
const { rerender } = renderHook(() => useSessionPageFlow(OPTS));
|
|
359
|
+
|
|
360
|
+
mockConv.pendingApprovals = [{ toolCallId: "tc1" }];
|
|
361
|
+
await act(async () => rerender());
|
|
362
|
+
|
|
363
|
+
expect(mockSubmitApproval).not.toHaveBeenCalled();
|
|
364
|
+
});
|
|
365
|
+
|
|
366
|
+
it("never fires for a guest, even when the run itself is armed", async () => {
|
|
367
|
+
mockConv.activeStreamExecution = { spec: { autoApproveAll: true }, status: {} };
|
|
368
|
+
mockConv.pendingApprovals = [{ toolCallId: "tc1" }];
|
|
369
|
+
renderHook(() => useSessionPageFlow({ ...OPTS, audience: "guest" }), {
|
|
370
|
+
wrapper: hostDefaultWrapper(true),
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
expect(mockSubmitApproval).not.toHaveBeenCalled();
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
it("never fires for an observer", async () => {
|
|
377
|
+
mockConv.pendingApprovals = [{ toolCallId: "tc1" }];
|
|
378
|
+
renderHook(() => useSessionPageFlow({ ...OPTS, audience: "observer" }), {
|
|
379
|
+
wrapper: hostDefaultWrapper(true),
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
expect(mockSubmitApproval).not.toHaveBeenCalled();
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
it("never fires for a channel-origin session (read-only by construction)", async () => {
|
|
386
|
+
mockConv.session = {
|
|
387
|
+
spec: {},
|
|
388
|
+
metadata: { labels: { "stigmer.ai/channel-id": "ch_1" } },
|
|
389
|
+
};
|
|
390
|
+
mockConv.pendingApprovals = [{ toolCallId: "tc1" }];
|
|
391
|
+
renderHook(() => useSessionPageFlow(OPTS), {
|
|
392
|
+
wrapper: hostDefaultWrapper(true),
|
|
393
|
+
});
|
|
394
|
+
|
|
395
|
+
expect(mockSubmitApproval).not.toHaveBeenCalled();
|
|
396
|
+
});
|
|
397
|
+
});
|
package/src/session/index.ts
CHANGED
|
@@ -39,6 +39,15 @@ export type {
|
|
|
39
39
|
UseSessionConversationReturn,
|
|
40
40
|
} from "./useSessionConversation.js";
|
|
41
41
|
|
|
42
|
+
export { useExportTranscript } from "./useExportTranscript.js";
|
|
43
|
+
export type {
|
|
44
|
+
UseExportTranscriptOptions,
|
|
45
|
+
UseExportTranscriptReturn,
|
|
46
|
+
} from "./useExportTranscript.js";
|
|
47
|
+
|
|
48
|
+
export { TranscriptExportMenu } from "./TranscriptExportMenu.js";
|
|
49
|
+
export type { TranscriptExportMenuProps } from "./TranscriptExportMenu.js";
|
|
50
|
+
|
|
42
51
|
export { useSessionArtifacts, artifactKey } from "./useSessionArtifacts.js";
|
|
43
52
|
export type {
|
|
44
53
|
SessionArtifactEntry,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ServiceTierOption } from "../models/service-tier.js";
|
|
2
|
+
import type { ThinkingModeOption } from "../models/thinking-mode.js";
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Owner-pinned execution config for a session surface
|
|
@@ -39,6 +40,14 @@ export interface SessionRunConfig {
|
|
|
39
40
|
* pin is a host configuration error and throws at submit.
|
|
40
41
|
*/
|
|
41
42
|
readonly serviceTier?: ServiceTierOption;
|
|
43
|
+
/**
|
|
44
|
+
* Thinking mode for every execution (stigmer/stigmer#772).
|
|
45
|
+
* `"enabled"` requires {@link modelName} under the same contract as
|
|
46
|
+
* {@link serviceTier}: thinking is a per-model capability (the server
|
|
47
|
+
* refuses it fail-closed for Auto), so a mode pin without a model pin
|
|
48
|
+
* is a host configuration error and throws at submit.
|
|
49
|
+
*/
|
|
50
|
+
readonly thinkingMode?: ThinkingModeOption;
|
|
42
51
|
}
|
|
43
52
|
|
|
44
53
|
/**
|
|
@@ -56,4 +65,11 @@ export function assertValidRunConfig(runConfig: SessionRunConfig): void {
|
|
|
56
65
|
+ "dimension. Pin the model the surface should run.",
|
|
57
66
|
);
|
|
58
67
|
}
|
|
68
|
+
if (runConfig.thinkingMode === "enabled" && !runConfig.modelName) {
|
|
69
|
+
throw new Error(
|
|
70
|
+
"SessionRunConfig: thinkingMode \"enabled\" requires modelName — "
|
|
71
|
+
+ "thinking is a per-model capability and Auto (no pinned model) has "
|
|
72
|
+
+ "no variant dimensions. Pin the model the surface should run.",
|
|
73
|
+
);
|
|
74
|
+
}
|
|
59
75
|
}
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useCallback, useMemo, useState } from "react";
|
|
4
|
+
import {
|
|
5
|
+
fetchSessionTranscript,
|
|
6
|
+
resolvedSubject,
|
|
7
|
+
transcriptToJson,
|
|
8
|
+
transcriptToMarkdown,
|
|
9
|
+
type SessionTranscript,
|
|
10
|
+
} from "@stigmer/sdk";
|
|
11
|
+
import { toast } from "../feedback/toast.js";
|
|
12
|
+
import { useStigmer } from "../hooks.js";
|
|
13
|
+
import { downloadTextFile } from "../internal/download.js";
|
|
14
|
+
import { generateSlug } from "../internal/slug.js";
|
|
15
|
+
import { toError } from "../internal/toError.js";
|
|
16
|
+
|
|
17
|
+
/** Options for {@link useExportTranscript}. */
|
|
18
|
+
export interface UseExportTranscriptOptions {
|
|
19
|
+
/**
|
|
20
|
+
* Keep turns replaced by edit-and-resubmit in the export, marked as
|
|
21
|
+
* superseded. Defaults to `false` — the conversation as the viewer
|
|
22
|
+
* shows it.
|
|
23
|
+
*/
|
|
24
|
+
readonly includeSuperseded?: boolean;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Return value of {@link useExportTranscript}. */
|
|
28
|
+
export interface UseExportTranscriptReturn {
|
|
29
|
+
/** Copy the whole conversation as Markdown to the clipboard. */
|
|
30
|
+
readonly copyMarkdown: () => Promise<void>;
|
|
31
|
+
/** Download the whole conversation as a Markdown file. */
|
|
32
|
+
readonly downloadMarkdown: () => Promise<void>;
|
|
33
|
+
/** Download the whole conversation as a structured JSON file. */
|
|
34
|
+
readonly downloadJson: () => Promise<void>;
|
|
35
|
+
/** `true` while a transcript fetch (and offload resolution) is in flight. */
|
|
36
|
+
readonly isExporting: boolean;
|
|
37
|
+
/** The last export failure, or `null`. Cleared when a new export starts. */
|
|
38
|
+
readonly error: Error | null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Behavior hook that exports a session's whole conversation — thinking,
|
|
43
|
+
* tool calls with offloaded outputs resolved, sub-agent turns, timestamps —
|
|
44
|
+
* as Markdown (copy or download) or structured JSON (stigmer/stigmer#814).
|
|
45
|
+
*
|
|
46
|
+
* Lazy: nothing is fetched until an action is invoked. Each action fetches
|
|
47
|
+
* the canonical transcript via `fetchSessionTranscript` (the SDK's one
|
|
48
|
+
* authoritative assembly), so every export surface produces identical
|
|
49
|
+
* content. Feedback follows the `useExportResource` convention: toasts for
|
|
50
|
+
* success/failure, plus a typed `error` for hosts that render their own.
|
|
51
|
+
*
|
|
52
|
+
* @example
|
|
53
|
+
* ```tsx
|
|
54
|
+
* const exporter = useExportTranscript(sessionId);
|
|
55
|
+
*
|
|
56
|
+
* <ActionMenu.Item onSelect={exporter.copyMarkdown}>Copy transcript</ActionMenu.Item>
|
|
57
|
+
* <ActionMenu.Item onSelect={exporter.downloadMarkdown}>Download .md</ActionMenu.Item>
|
|
58
|
+
* <ActionMenu.Item onSelect={exporter.downloadJson}>Download .json</ActionMenu.Item>
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
export function useExportTranscript(
|
|
62
|
+
sessionId: string | null,
|
|
63
|
+
options?: UseExportTranscriptOptions,
|
|
64
|
+
): UseExportTranscriptReturn {
|
|
65
|
+
const stigmer = useStigmer();
|
|
66
|
+
const includeSuperseded = options?.includeSuperseded === true;
|
|
67
|
+
const [isExporting, setIsExporting] = useState(false);
|
|
68
|
+
const [error, setError] = useState<Error | null>(null);
|
|
69
|
+
|
|
70
|
+
const fetchTranscript = useCallback((): Promise<SessionTranscript> => {
|
|
71
|
+
if (!sessionId) {
|
|
72
|
+
return Promise.reject(
|
|
73
|
+
new Error(
|
|
74
|
+
"Cannot export a transcript without a session id. Pass the session's " +
|
|
75
|
+
"id to useExportTranscript once the session exists.",
|
|
76
|
+
),
|
|
77
|
+
);
|
|
78
|
+
}
|
|
79
|
+
return fetchSessionTranscript(stigmer, sessionId, { includeSuperseded });
|
|
80
|
+
}, [stigmer, sessionId, includeSuperseded]);
|
|
81
|
+
|
|
82
|
+
const copyMarkdown = useCallback(async (): Promise<void> => {
|
|
83
|
+
setError(null);
|
|
84
|
+
setIsExporting(true);
|
|
85
|
+
const markdown = fetchTranscript().then(
|
|
86
|
+
(t) => transcriptToMarkdown(t, { generatedAt: new Date().toISOString() }),
|
|
87
|
+
);
|
|
88
|
+
try {
|
|
89
|
+
// The transcript is fetched before it can be copied, and WebKit (the
|
|
90
|
+
// desktop app's webview) only honors clipboard writes inside the user
|
|
91
|
+
// gesture's task — a plain writeText after the await is rejected
|
|
92
|
+
// there. ClipboardItem accepts a promise, letting the write start
|
|
93
|
+
// synchronously in the gesture while the content resolves.
|
|
94
|
+
if (typeof ClipboardItem !== "undefined" && navigator.clipboard?.write) {
|
|
95
|
+
await navigator.clipboard.write([
|
|
96
|
+
new ClipboardItem({
|
|
97
|
+
"text/plain": markdown.then(
|
|
98
|
+
(text) => new Blob([text], { type: "text/plain" }),
|
|
99
|
+
),
|
|
100
|
+
}),
|
|
101
|
+
]);
|
|
102
|
+
} else {
|
|
103
|
+
await navigator.clipboard.writeText(await markdown);
|
|
104
|
+
}
|
|
105
|
+
toast.success("Transcript copied to clipboard");
|
|
106
|
+
} catch (e) {
|
|
107
|
+
const err = toError(e);
|
|
108
|
+
setError(err);
|
|
109
|
+
toast.error(`Couldn't copy the transcript: ${err.message}`);
|
|
110
|
+
} finally {
|
|
111
|
+
setIsExporting(false);
|
|
112
|
+
}
|
|
113
|
+
}, [fetchTranscript]);
|
|
114
|
+
|
|
115
|
+
const download = useCallback(
|
|
116
|
+
async (serialize: (t: SessionTranscript) => { content: string; extension: string; mimeType: string }): Promise<void> => {
|
|
117
|
+
setError(null);
|
|
118
|
+
setIsExporting(true);
|
|
119
|
+
try {
|
|
120
|
+
const transcript = await fetchTranscript();
|
|
121
|
+
const { content, extension, mimeType } = serialize(transcript);
|
|
122
|
+
downloadTextFile(
|
|
123
|
+
content,
|
|
124
|
+
`${transcriptFilename(transcript)}.${extension}`,
|
|
125
|
+
mimeType,
|
|
126
|
+
);
|
|
127
|
+
} catch (e) {
|
|
128
|
+
const err = toError(e);
|
|
129
|
+
setError(err);
|
|
130
|
+
toast.error(`Couldn't export the transcript: ${err.message}`);
|
|
131
|
+
} finally {
|
|
132
|
+
setIsExporting(false);
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
[fetchTranscript],
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
const downloadMarkdown = useCallback(
|
|
139
|
+
() =>
|
|
140
|
+
download((t) => ({
|
|
141
|
+
content: transcriptToMarkdown(t, {
|
|
142
|
+
generatedAt: new Date().toISOString(),
|
|
143
|
+
}),
|
|
144
|
+
extension: "md",
|
|
145
|
+
mimeType: "text/markdown",
|
|
146
|
+
})),
|
|
147
|
+
[download],
|
|
148
|
+
);
|
|
149
|
+
|
|
150
|
+
const downloadJson = useCallback(
|
|
151
|
+
() =>
|
|
152
|
+
download((t) => ({
|
|
153
|
+
content: JSON.stringify(transcriptToJson(t), null, 2),
|
|
154
|
+
extension: "json",
|
|
155
|
+
mimeType: "application/json",
|
|
156
|
+
})),
|
|
157
|
+
[download],
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
return useMemo(
|
|
161
|
+
() => ({ copyMarkdown, downloadMarkdown, downloadJson, isExporting, error }),
|
|
162
|
+
[copyMarkdown, downloadMarkdown, downloadJson, isExporting, error],
|
|
163
|
+
);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/** `<subject-slug>-transcript`, falling back to the session id. */
|
|
167
|
+
function transcriptFilename(transcript: SessionTranscript): string {
|
|
168
|
+
const subject = resolvedSubject(transcript.session.spec?.subject);
|
|
169
|
+
const slug = subject ? generateSlug(subject).slice(0, 60) : "";
|
|
170
|
+
return `${slug || transcript.session.metadata?.id || "session"}-transcript`;
|
|
171
|
+
}
|
|
@@ -218,6 +218,18 @@ export interface UseNewSessionFlowReturn {
|
|
|
218
218
|
/** Session variables (per-execution secrets) manager. */
|
|
219
219
|
readonly sessionVariables: UseSessionVariablesReturn;
|
|
220
220
|
|
|
221
|
+
/**
|
|
222
|
+
* Pre-arm "auto-approve tool calls" for the session this surface will
|
|
223
|
+
* create (stigmer/stigmer#816, the walk-away scenario). Seeded from the
|
|
224
|
+
* host's `StigmerProvider` `approvalDefaults` (#302, guests excluded);
|
|
225
|
+
* the user's toggle wins from then on. Carried into the bootstrap create
|
|
226
|
+
* as `spec.auto_approve_all` — the whole-run server-side bypass — so the
|
|
227
|
+
* first run stays covered even if the user closes the tab.
|
|
228
|
+
*/
|
|
229
|
+
readonly autoApproveAll: boolean;
|
|
230
|
+
/** Set the user's explicit auto-approve choice for the created session. */
|
|
231
|
+
readonly setAutoApproveAll: (value: boolean) => void;
|
|
232
|
+
|
|
221
233
|
/** `true` while the create session + execution flow is in flight. */
|
|
222
234
|
readonly isSubmitting: boolean;
|
|
223
235
|
/** Human-readable error from the last failed submission, or `null`. */
|
|
@@ -307,16 +319,22 @@ export function useNewSessionFlow(
|
|
|
307
319
|
if (runConfig) assertValidRunConfig(runConfig);
|
|
308
320
|
const pinnedModelName = runConfig?.modelName;
|
|
309
321
|
const pinnedServiceTier = runConfig?.serviceTier;
|
|
322
|
+
const pinnedThinkingMode = runConfig?.thinkingMode;
|
|
310
323
|
const contextTarget = useExecutionTarget();
|
|
311
324
|
const executionTarget = options.executionTarget ?? contextTarget;
|
|
312
325
|
const adapter = useRunnerAdapter();
|
|
313
|
-
//
|
|
314
|
-
//
|
|
315
|
-
//
|
|
316
|
-
//
|
|
326
|
+
// Auto-approve for the session about to be created (#816): the host
|
|
327
|
+
// approval default (#302) seeds the INITIAL state only; the user's
|
|
328
|
+
// composer toggle wins from then on. Guests never inherit the default
|
|
329
|
+
// and never see the toggle — a share-link visitor is not the operator
|
|
330
|
+
// the host's trust judgment covers (the GUEST_HARNESS
|
|
331
|
+
// fixed-platform-policy reasoning). Carried into the bootstrap create as
|
|
332
|
+
// spec.auto_approve_all, the whole-run server-side bypass — the created
|
|
333
|
+
// run stays covered even if this tab dies before its first gate.
|
|
317
334
|
const approvalDefaults = useApprovalDefaults();
|
|
318
|
-
const autoApproveAll =
|
|
319
|
-
(!isGuest && approvalDefaults?.autoApproveAll
|
|
335
|
+
const [autoApproveAll, setAutoApproveAll] = useState(
|
|
336
|
+
() => !isGuest && (approvalDefaults?.autoApproveAll ?? false),
|
|
337
|
+
);
|
|
320
338
|
|
|
321
339
|
const [harness, setHarnessRaw] = useState<HarnessOption>(() => {
|
|
322
340
|
// Guests get the fixed platform policy (see GUEST_HARNESS) and never
|
|
@@ -490,8 +508,14 @@ export function useNewSessionFlow(
|
|
|
490
508
|
serviceTier: pinnedModelName
|
|
491
509
|
? (pinnedServiceTier === "fast" ? "fast" : undefined)
|
|
492
510
|
: context?.serviceTier,
|
|
511
|
+
// The tier's #772 twin, same pin-wins + only-explicit-enabled rule.
|
|
512
|
+
thinkingMode: pinnedModelName
|
|
513
|
+
? (pinnedThinkingMode === "enabled" ? "enabled" : undefined)
|
|
514
|
+
: context?.thinkingMode,
|
|
493
515
|
workspaceFileRefs: context?.workspaceFileRefs,
|
|
494
|
-
|
|
516
|
+
// Only an armed state travels; false stays off the wire (the
|
|
517
|
+
// serviceTier/thinkingMode only-explicit discipline).
|
|
518
|
+
autoApproveAll: autoApproveAll || undefined,
|
|
495
519
|
};
|
|
496
520
|
|
|
497
521
|
// Resolve which agent the bootstrapped session runs against: an
|
|
@@ -584,6 +608,7 @@ export function useNewSessionFlow(
|
|
|
584
608
|
effectiveModelId,
|
|
585
609
|
pinnedModelName,
|
|
586
610
|
pinnedServiceTier,
|
|
611
|
+
pinnedThinkingMode,
|
|
587
612
|
workspace,
|
|
588
613
|
mcpServerUsages,
|
|
589
614
|
skillRefs,
|
|
@@ -618,6 +643,8 @@ export function useNewSessionFlow(
|
|
|
618
643
|
setSkillRefs,
|
|
619
644
|
workspace,
|
|
620
645
|
sessionVariables,
|
|
646
|
+
autoApproveAll,
|
|
647
|
+
setAutoApproveAll,
|
|
621
648
|
isSubmitting,
|
|
622
649
|
submitError,
|
|
623
650
|
submit,
|
|
@@ -9,15 +9,18 @@ import type { Session } from "@stigmer/protos/ai/stigmer/agentic/session/v1/api_
|
|
|
9
9
|
import type { McpServerUsage as ProtoMcpServerUsage } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/spec_pb";
|
|
10
10
|
import type { WorkspaceEntry as ProtoWorkspaceEntry } from "@stigmer/protos/ai/stigmer/agentic/session/v1/workspace_pb";
|
|
11
11
|
import type { ApiResourceReference as ProtoApiResourceReference } from "@stigmer/protos/ai/stigmer/commons/apiresource/io_pb";
|
|
12
|
-
import
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
12
|
+
import {
|
|
13
|
+
supersededExecutionIds,
|
|
14
|
+
toSessionUpdateInput,
|
|
15
|
+
type AttachmentInput,
|
|
16
|
+
type EnvVarInput,
|
|
17
|
+
type McpServerUsageInput,
|
|
18
|
+
type ResourceRef,
|
|
19
|
+
type WorkspaceEntryInput,
|
|
18
20
|
} from "@stigmer/sdk";
|
|
19
21
|
import { isTerminalPhase } from "../execution/execution-phases.js";
|
|
20
22
|
import type { ServiceTierOption } from "../models/service-tier.js";
|
|
23
|
+
import type { ThinkingModeOption } from "../models/thinking-mode.js";
|
|
21
24
|
import { useStigmer } from "../hooks.js";
|
|
22
25
|
import { toError } from "../internal/toError.js";
|
|
23
26
|
import { useConversationStoreRef } from "../internal/store/index.js";
|
|
@@ -32,11 +35,6 @@ import { useSession } from "./useSession.js";
|
|
|
32
35
|
import { useSessionExecutions } from "./useSessionExecutions.js";
|
|
33
36
|
import { useUpdateSession } from "./useUpdateSession.js";
|
|
34
37
|
import { useLocalSessionWorker } from "./useLocalSessionWorker.js";
|
|
35
|
-
import {
|
|
36
|
-
specWorkspaceToInput,
|
|
37
|
-
specMcpUsagesToInput,
|
|
38
|
-
specSkillRefsToInput,
|
|
39
|
-
} from "./session-spec-converters.js";
|
|
40
38
|
|
|
41
39
|
/**
|
|
42
40
|
* Cadence for re-discovering the session's executions while the live stream
|
|
@@ -111,6 +109,16 @@ export interface SendFollowUpOptions {
|
|
|
111
109
|
* @see {@link SharedAgentExecutionFields.serviceTier}
|
|
112
110
|
*/
|
|
113
111
|
readonly serviceTier?: ServiceTierOption;
|
|
112
|
+
/**
|
|
113
|
+
* Thinking mode for this execution's model calls (stigmer/stigmer#772).
|
|
114
|
+
*
|
|
115
|
+
* Only set when the user actively selected `"enabled"`; `undefined`
|
|
116
|
+
* preserves the unspecified-vs-explicit distinction (unset resolves to
|
|
117
|
+
* disabled on the platform side — never the provider account default).
|
|
118
|
+
*
|
|
119
|
+
* @see {@link SharedAgentExecutionFields.thinkingMode}
|
|
120
|
+
*/
|
|
121
|
+
readonly thinkingMode?: ThinkingModeOption;
|
|
114
122
|
/**
|
|
115
123
|
* Marks this execution as a Build-from-plan turn.
|
|
116
124
|
*
|
|
@@ -537,13 +545,11 @@ export function useSessionConversation(
|
|
|
537
545
|
}
|
|
538
546
|
}, [activeExecutionId, stream.phase, refetch]);
|
|
539
547
|
|
|
540
|
-
// Executions replaced via edit-and-resubmit
|
|
541
|
-
//
|
|
542
|
-
//
|
|
543
|
-
//
|
|
544
|
-
//
|
|
545
|
-
// Display-only: the raw `executions` list (and therefore active-id
|
|
546
|
-
// resolution above) is never filtered.
|
|
548
|
+
// Executions replaced via edit-and-resubmit (the shared conversation rule —
|
|
549
|
+
// see supersededExecutionIds in @stigmer/sdk for the why). The extra id is
|
|
550
|
+
// the live stream copy's link: right after a resubmit, the successor streams
|
|
551
|
+
// before the list refetch delivers it. Display-only: the raw `executions`
|
|
552
|
+
// list (and therefore active-id resolution above) is never filtered.
|
|
547
553
|
//
|
|
548
554
|
// Dep is the scalar link, NOT stream.execution: the stream object changes
|
|
549
555
|
// reference every frame, and rebuilding the Set per frame would hand
|
|
@@ -551,15 +557,10 @@ export function useSessionConversation(
|
|
|
551
557
|
// memoization (DD-010).
|
|
552
558
|
const streamSupersededId =
|
|
553
559
|
stream.execution?.spec?.supersedesExecutionId || null;
|
|
554
|
-
const supersededIds = useMemo(
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
if (superseded) ids.add(superseded);
|
|
559
|
-
}
|
|
560
|
-
if (streamSupersededId) ids.add(streamSupersededId);
|
|
561
|
-
return ids;
|
|
562
|
-
}, [executions, streamSupersededId]);
|
|
560
|
+
const supersededIds = useMemo(
|
|
561
|
+
() => supersededExecutionIds(executions, streamSupersededId),
|
|
562
|
+
[executions, streamSupersededId],
|
|
563
|
+
);
|
|
563
564
|
|
|
564
565
|
const completedExecutions = useMemo(() => {
|
|
565
566
|
return executions.filter((e) => {
|
|
@@ -674,6 +675,7 @@ export function useSessionConversation(
|
|
|
674
675
|
attachments: options?.attachments,
|
|
675
676
|
interactionMode: options?.interactionMode,
|
|
676
677
|
serviceTier: options?.serviceTier,
|
|
678
|
+
thinkingMode: options?.thinkingMode,
|
|
677
679
|
buildFromPlan: options?.buildFromPlan,
|
|
678
680
|
autoApproveAll: options?.autoApproveAll,
|
|
679
681
|
workspaceFileRefs: options?.workspaceFileRefs,
|
|
@@ -818,13 +820,13 @@ export function useSessionConversation(
|
|
|
818
820
|
// ---------------------------------------------------------------------------
|
|
819
821
|
|
|
820
822
|
/**
|
|
821
|
-
*
|
|
822
|
-
*
|
|
823
|
-
*
|
|
824
|
-
*
|
|
825
|
-
*
|
|
826
|
-
* the
|
|
827
|
-
*
|
|
823
|
+
* Builds the SessionInput for the update RPC (which uses replace
|
|
824
|
+
* semantics — the full spec is sent) by spreading the SDK's complete
|
|
825
|
+
* generated mapper and overriding only the session-level collections the
|
|
826
|
+
* caller provided. An override replaces the existing value; an omitted
|
|
827
|
+
* field keeps the fetched session's value (an empty-array override
|
|
828
|
+
* clears the collection — normalized to absent, the mappers' canonical
|
|
829
|
+
* shape).
|
|
828
830
|
*/
|
|
829
831
|
function buildUpdateInput(
|
|
830
832
|
session: Session,
|
|
@@ -835,30 +837,14 @@ function buildUpdateInput(
|
|
|
835
837
|
skillRefs?: ResourceRef[];
|
|
836
838
|
},
|
|
837
839
|
) {
|
|
838
|
-
const
|
|
839
|
-
const
|
|
840
|
-
|
|
841
|
-
const
|
|
842
|
-
overrides.workspaceEntries ?? specWorkspaceToInput(spec);
|
|
843
|
-
|
|
844
|
-
const mcpServerUsages =
|
|
845
|
-
overrides.mcpServerUsages ?? specMcpUsagesToInput(spec);
|
|
846
|
-
|
|
847
|
-
const skillRefs = overrides.skillRefs ?? specSkillRefsToInput(spec);
|
|
840
|
+
const mapped = toSessionUpdateInput(session);
|
|
841
|
+
const workspaceEntries = overrides.workspaceEntries ?? mapped.workspaceEntries;
|
|
842
|
+
const mcpServerUsages = overrides.mcpServerUsages ?? mapped.mcpServerUsages;
|
|
843
|
+
const skillRefs = overrides.skillRefs ?? mapped.skillRefs;
|
|
848
844
|
|
|
849
845
|
return {
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
agentInstanceId: overrides.agentInstanceId ?? (spec?.agentInstanceId || undefined),
|
|
853
|
-
subject: spec?.subject || undefined,
|
|
854
|
-
harnessStateId: spec?.harnessStateId || undefined,
|
|
855
|
-
harness: spec?.harness,
|
|
856
|
-
cursorMode: spec?.cursorMode,
|
|
857
|
-
executionTarget: spec?.executionTarget,
|
|
858
|
-
metadata:
|
|
859
|
-
spec?.metadata && Object.keys(spec.metadata).length > 0
|
|
860
|
-
? { ...spec.metadata }
|
|
861
|
-
: undefined,
|
|
846
|
+
...mapped,
|
|
847
|
+
agentInstanceId: overrides.agentInstanceId ?? mapped.agentInstanceId,
|
|
862
848
|
workspaceEntries: workspaceEntries?.length ? workspaceEntries : undefined,
|
|
863
849
|
mcpServerUsages: mcpServerUsages?.length ? mcpServerUsages : undefined,
|
|
864
850
|
skillRefs: skillRefs?.length ? skillRefs : undefined,
|