@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
|
@@ -3,9 +3,14 @@
|
|
|
3
3
|
import { create } from "@bufbuild/protobuf";
|
|
4
4
|
import type { AgentExecution } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
|
|
5
5
|
import { ListAgentExecutionsBySessionRequestSchema } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/io_pb";
|
|
6
|
+
import { sortChronologically } from "@stigmer/sdk";
|
|
6
7
|
import { useStigmer } from "../hooks.js";
|
|
7
8
|
import { useFetch } from "../internal/useFetch.js";
|
|
8
9
|
|
|
10
|
+
// The ordering rule lives in @stigmer/sdk with the other shared
|
|
11
|
+
// conversation-assembly rules; re-exported here for existing consumers.
|
|
12
|
+
export { sortChronologically };
|
|
13
|
+
|
|
9
14
|
/** Options for {@link useSessionExecutions}. */
|
|
10
15
|
export interface UseSessionExecutionsOptions {
|
|
11
16
|
/**
|
|
@@ -71,32 +76,6 @@ export interface UseSessionExecutionsReturn {
|
|
|
71
76
|
* const { executions } = useSessionExecutions(sessionId ?? null);
|
|
72
77
|
* ```
|
|
73
78
|
*/
|
|
74
|
-
/**
|
|
75
|
-
* Returns the executions in chronological (oldest-first) order — the order
|
|
76
|
-
* the conversation thread renders top-to-bottom.
|
|
77
|
-
*
|
|
78
|
-
* Defense-in-depth against an unordered list response: the executions ARE the
|
|
79
|
-
* transcript, so a scrambled order drops the newest turns out of view (they no
|
|
80
|
-
* longer sort to the bottom). The server orders this list, but the thread must
|
|
81
|
-
* never depend on that alone. Resource ids are time-sortable ULIDs
|
|
82
|
-
* (`aex_01k…`), so an ascending id sort is creation order without parsing
|
|
83
|
-
* timestamps; entries missing an id sort last but keep a stable relative order.
|
|
84
|
-
*
|
|
85
|
-
* @internal Exported for testing — not part of the public API.
|
|
86
|
-
*/
|
|
87
|
-
export function sortChronologically(
|
|
88
|
-
executions: readonly AgentExecution[],
|
|
89
|
-
): AgentExecution[] {
|
|
90
|
-
return [...executions].sort((a, b) => {
|
|
91
|
-
const aId = a.metadata?.id ?? "";
|
|
92
|
-
const bId = b.metadata?.id ?? "";
|
|
93
|
-
if (aId === bId) return 0;
|
|
94
|
-
if (!aId) return 1;
|
|
95
|
-
if (!bId) return -1;
|
|
96
|
-
return aId < bId ? -1 : 1;
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
|
|
100
79
|
export function useSessionExecutions(
|
|
101
80
|
sessionId: string | null,
|
|
102
81
|
options?: UseSessionExecutionsOptions,
|
|
@@ -18,8 +18,9 @@ import { useSessionConversation, type UseSessionConversationReturn } from "./use
|
|
|
18
18
|
import { resolveExecutionRuntimeEnv, type RuntimeEnvProvider } from "./runtime-env.js";
|
|
19
19
|
import { useAgentRefFromSession } from "./useAgentRefFromSession.js";
|
|
20
20
|
import { usePersistedModel, type UsePersistedModelReturn } from "./usePersistedModel.js";
|
|
21
|
-
import {
|
|
21
|
+
import { toSessionUpdateInput } from "@stigmer/sdk";
|
|
22
22
|
import type { SessionAudience } from "./audience.js";
|
|
23
|
+
import { isChannelOriginSession } from "./channelOrigin.js";
|
|
23
24
|
import { assertValidRunConfig, type SessionRunConfig } from "./run-config.js";
|
|
24
25
|
|
|
25
26
|
/**
|
|
@@ -140,20 +141,33 @@ export interface UseSessionPageFlowReturn {
|
|
|
140
141
|
readonly sessionVariables: UseSessionVariablesReturn;
|
|
141
142
|
|
|
142
143
|
/**
|
|
143
|
-
* Session-scoped "auto-approve tool calls"
|
|
144
|
+
* Session-scoped "auto-approve tool calls" state (stigmer/stigmer#816).
|
|
144
145
|
*
|
|
145
|
-
* `false` by default
|
|
146
|
-
*
|
|
147
|
-
*
|
|
148
|
-
*
|
|
149
|
-
*
|
|
150
|
-
*
|
|
151
|
-
*
|
|
146
|
+
* `false` by default. `true` when any of its sources arms it — the user's
|
|
147
|
+
* explicit choice always winning:
|
|
148
|
+
*
|
|
149
|
+
* 1. the user's composer toggle ({@link setAutoApproveAll});
|
|
150
|
+
* 2. "Approve & don't ask again" at an approval gate (see
|
|
151
|
+
* {@link submitApproval});
|
|
152
|
+
* 3. the host's app-wide `StigmerProvider` `approvalDefaults` (#302,
|
|
153
|
+
* guests excluded);
|
|
154
|
+
* 4. the active in-flight execution having been created with
|
|
155
|
+
* `spec.auto_approve_all` (e.g. armed on the new-session surface), so
|
|
156
|
+
* the state survives the launcher → session-page handoff.
|
|
157
|
+
*
|
|
158
|
+
* While `true`, follow-ups carry `auto_approve_all` ({@link handleSubmit})
|
|
159
|
+
* and gates appearing in the in-flight run are auto-released (never for
|
|
160
|
+
* guest/observer/channel-origin surfaces). Held in memory only — reset on
|
|
161
|
+
* reload back to the host default, never persisted server-side.
|
|
152
162
|
*/
|
|
153
163
|
readonly autoApproveAll: boolean;
|
|
154
164
|
/**
|
|
155
|
-
*
|
|
156
|
-
*
|
|
165
|
+
* Set the user's explicit session-scoped auto-approve choice. Wired to the
|
|
166
|
+
* composer's always-visible toggle; an explicit `false` wins over the host
|
|
167
|
+
* default and over an armed in-flight run for everything the client
|
|
168
|
+
* controls (follow-up carry, gate auto-release) — an already-armed run's
|
|
169
|
+
* server-side bypass cannot be revoked mid-run, exactly as with today's
|
|
170
|
+
* gate-time "Approve & don't ask again".
|
|
157
171
|
*/
|
|
158
172
|
readonly setAutoApproveAll: (value: boolean) => void;
|
|
159
173
|
|
|
@@ -267,6 +281,7 @@ export function useSessionPageFlow(
|
|
|
267
281
|
// callback's identity must not churn on every render (DD-010).
|
|
268
282
|
const pinnedModelName = runConfig?.modelName;
|
|
269
283
|
const pinnedServiceTier = runConfig?.serviceTier;
|
|
284
|
+
const pinnedThinkingMode = runConfig?.thinkingMode;
|
|
270
285
|
|
|
271
286
|
const stigmer = useStigmer();
|
|
272
287
|
const conv = useSessionConversation(sessionId, org);
|
|
@@ -321,17 +336,34 @@ export function useSessionPageFlow(
|
|
|
321
336
|
const [skillRefs, setSkillRefs] = useState<ResourceRef[]>([]);
|
|
322
337
|
const initialSyncDone = useRef(false);
|
|
323
338
|
|
|
324
|
-
// Session-scoped auto-approve.
|
|
325
|
-
//
|
|
326
|
-
//
|
|
327
|
-
//
|
|
328
|
-
//
|
|
329
|
-
//
|
|
330
|
-
//
|
|
339
|
+
// Session-scoped auto-approve (#816). Derived like interactionMode above —
|
|
340
|
+
// the user's explicit in-session decision wins, otherwise the truth is
|
|
341
|
+
// computed from its sources — never an effect-synced copy:
|
|
342
|
+
//
|
|
343
|
+
// effective = userChoice ?? (hostSeed || runArmed)
|
|
344
|
+
//
|
|
345
|
+
// - `userChoice`: the composer toggle, or the gate-time "Approve & don't
|
|
346
|
+
// ask again" (which has always escalated the session preference).
|
|
347
|
+
// - `hostSeed`: the host's provider-level approvalDefaults (#302) — an
|
|
348
|
+
// app-level trust judgment. Guests never inherit it (a share-link
|
|
349
|
+
// visitor is not the operator the host's trust judgment covers).
|
|
350
|
+
// - `runArmed`: the ACTIVE execution was created with
|
|
351
|
+
// spec.auto_approve_all, so the toggle reflects an armed in-flight run —
|
|
352
|
+
// this is what carries the state across the new-session → session-page
|
|
353
|
+
// handoff. Deliberately derived from the active execution ONLY, never
|
|
354
|
+
// from history: deriving from past executions would silently survive a
|
|
355
|
+
// reload and change the reset-on-reload consent contract below.
|
|
356
|
+
//
|
|
357
|
+
// Lives only in memory for the life of this page — reset on reload
|
|
358
|
+
// re-applies the host default, never a user choice.
|
|
331
359
|
const approvalDefaults = useApprovalDefaults();
|
|
332
|
-
const [
|
|
333
|
-
|
|
334
|
-
|
|
360
|
+
const [autoApproveChoice, setAutoApproveChoice] = useState<boolean | null>(null);
|
|
361
|
+
const hostSeed = !isGuest && (approvalDefaults?.autoApproveAll ?? false);
|
|
362
|
+
const runArmed = conv.activeStreamExecution?.spec?.autoApproveAll === true;
|
|
363
|
+
const autoApproveAll = autoApproveChoice ?? (hostSeed || runArmed);
|
|
364
|
+
const setAutoApproveAll = useCallback((value: boolean) => {
|
|
365
|
+
setAutoApproveChoice(value);
|
|
366
|
+
}, []);
|
|
335
367
|
|
|
336
368
|
const submitApproval = useCallback<UseSessionConversationReturn["submitApproval"]>(
|
|
337
369
|
async (toolCallId, action, comment) => {
|
|
@@ -340,13 +372,45 @@ export function useSessionPageFlow(
|
|
|
340
372
|
// plane separately resolves the current execution's remaining gates and
|
|
341
373
|
// the runner skips the gate for the rest of that run.
|
|
342
374
|
if (action === ApprovalAction.APPROVE_ALL) {
|
|
343
|
-
|
|
375
|
+
setAutoApproveChoice(true);
|
|
344
376
|
}
|
|
345
377
|
await conv.submitApproval(toolCallId, action, comment);
|
|
346
378
|
},
|
|
347
379
|
[conv.submitApproval],
|
|
348
380
|
);
|
|
349
381
|
|
|
382
|
+
// Armed responder (#816, the walk-away scenario): while auto-approve is ON,
|
|
383
|
+
// answer each approval gate as it appears in the in-flight run. This must be
|
|
384
|
+
// a standing responder, not a flip-time one-shot: a gate-time APPROVE_ALL
|
|
385
|
+
// grants a lease scoped to ONE tool class (see APPROVAL_ACTION_APPROVE_ALL
|
|
386
|
+
// in agentexecution enum.proto), so a later gate of a different class would
|
|
387
|
+
// still park the run — the responder covers each class as it surfaces, and
|
|
388
|
+
// every released call keeps an honest audit decision.
|
|
389
|
+
//
|
|
390
|
+
// Read-only surfaces must never auto-submit approvals on a viewer's behalf:
|
|
391
|
+
// the predicate mirrors SessionViewer's read-only derivation (guest audience,
|
|
392
|
+
// observer audience, channel-origin session) exactly.
|
|
393
|
+
const canRespondToGates =
|
|
394
|
+
!isGuest &&
|
|
395
|
+
options.audience !== "observer" &&
|
|
396
|
+
!isChannelOriginSession(conv.session);
|
|
397
|
+
const respondedToolCallIds = useRef<Set<string>>(new Set());
|
|
398
|
+
useEffect(() => {
|
|
399
|
+
if (!autoApproveAll || !canRespondToGates) return;
|
|
400
|
+
for (const approval of conv.pendingApprovals) {
|
|
401
|
+
const toolCallId = approval.toolCallId;
|
|
402
|
+
// Marked before the submit resolves so a re-render mid-flight cannot
|
|
403
|
+
// double-submit. A failed submission is deliberately NOT retried — the
|
|
404
|
+
// approval card stays for a manual decision instead of a retry storm.
|
|
405
|
+
if (!toolCallId || respondedToolCallIds.current.has(toolCallId)) continue;
|
|
406
|
+
respondedToolCallIds.current.add(toolCallId);
|
|
407
|
+
void conv.submitApproval(toolCallId, ApprovalAction.APPROVE_ALL).catch(() => {
|
|
408
|
+
// Swallowed by design (see above); the card's own error surface
|
|
409
|
+
// reports the failure where the user can act on it.
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
}, [autoApproveAll, canRespondToGates, conv.pendingApprovals, conv.submitApproval]);
|
|
413
|
+
|
|
350
414
|
// -------------------------------------------------------------------------
|
|
351
415
|
// Agent — derive from session, allow mid-session changes
|
|
352
416
|
// -------------------------------------------------------------------------
|
|
@@ -401,16 +465,14 @@ export function useSessionPageFlow(
|
|
|
401
465
|
}
|
|
402
466
|
}
|
|
403
467
|
|
|
404
|
-
// MCP server usages
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
468
|
+
// MCP server usages and skill references, hydrated through the SDK's
|
|
469
|
+
// complete update-input mapper (the canonical proto → input lens).
|
|
470
|
+
const mapped = toSessionUpdateInput(conv.session);
|
|
471
|
+
if (mapped.mcpServerUsages?.length) {
|
|
472
|
+
setMcpServerUsages(mapped.mcpServerUsages);
|
|
408
473
|
}
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
const skillInputs = specSkillRefsToInput(spec);
|
|
412
|
-
if (skillInputs?.length) {
|
|
413
|
-
setSkillRefs(skillInputs);
|
|
474
|
+
if (mapped.skillRefs?.length) {
|
|
475
|
+
setSkillRefs(mapped.skillRefs);
|
|
414
476
|
}
|
|
415
477
|
}, [conv.session, workspace]);
|
|
416
478
|
|
|
@@ -480,6 +542,10 @@ export function useSessionPageFlow(
|
|
|
480
542
|
serviceTier: pinnedModelName
|
|
481
543
|
? (pinnedServiceTier === "fast" ? "fast" : undefined)
|
|
482
544
|
: context?.serviceTier,
|
|
545
|
+
// The tier's #772 twin, same pin-wins + only-explicit-enabled rule.
|
|
546
|
+
thinkingMode: pinnedModelName
|
|
547
|
+
? (pinnedThinkingMode === "enabled" ? "enabled" : undefined)
|
|
548
|
+
: context?.thinkingMode,
|
|
483
549
|
buildFromPlan: context?.buildFromPlan,
|
|
484
550
|
// Sourced from the session-scoped preference set at the approval gate,
|
|
485
551
|
// not from the composer (the pre-arm toggle was removed).
|
|
@@ -490,7 +556,7 @@ export function useSessionPageFlow(
|
|
|
490
556
|
|
|
491
557
|
sessionVariables.clear();
|
|
492
558
|
},
|
|
493
|
-
[conv.sendFollowUp, modelId, pinnedModelName, pinnedServiceTier, workspace, mcpServerUsages, skillRefs, sessionVariables.clear, resolution, agentRef, sessionInstanceId, stigmer, autoApproveAll, getRuntimeEnv],
|
|
559
|
+
[conv.sendFollowUp, modelId, pinnedModelName, pinnedServiceTier, pinnedThinkingMode, workspace, mcpServerUsages, skillRefs, sessionVariables.clear, resolution, agentRef, sessionInstanceId, stigmer, autoApproveAll, getRuntimeEnv],
|
|
494
560
|
);
|
|
495
561
|
|
|
496
562
|
// -------------------------------------------------------------------------
|
|
@@ -25,40 +25,34 @@ export interface UseUpdateSessionReturn {
|
|
|
25
25
|
* by the backend to identify the resource) and all spec fields.
|
|
26
26
|
*
|
|
27
27
|
* **Full-replace semantics.** The backend replaces the entire spec with
|
|
28
|
-
* what you send — there is no field mask.
|
|
29
|
-
*
|
|
30
|
-
* from a reconstructed partial spec silently
|
|
31
|
-
* (workspace entries, MCP servers, and
|
|
32
|
-
* as the embedder session context).
|
|
33
|
-
*
|
|
28
|
+
* what you send — there is no field mask. Spread the SDK's complete
|
|
29
|
+
* `toSessionUpdateInput()` mapper and override only the fields you
|
|
30
|
+
* change: an update built from a reconstructed partial spec silently
|
|
31
|
+
* wipes the fields it omits (workspace entries, MCP servers, and
|
|
32
|
+
* `stigmer.ai/*` metadata keys such as the embedder session context).
|
|
33
|
+
* To change only the subject, prefer the field-level
|
|
34
|
+
* `session.updateSubject()` RPC instead of this hook.
|
|
34
35
|
*
|
|
35
36
|
* Typically composed into higher-level hooks like
|
|
36
|
-
* {@link useSessionConversation} (whose update path
|
|
37
|
-
* fetched
|
|
38
|
-
* direct session mutation can use this hook
|
|
37
|
+
* {@link useSessionConversation} (whose update path spreads the mapper
|
|
38
|
+
* over a freshly fetched session) rather than used directly. Platform
|
|
39
|
+
* builders who need direct session mutation can use this hook
|
|
40
|
+
* standalone.
|
|
39
41
|
*
|
|
40
42
|
* @example
|
|
41
43
|
* ```tsx
|
|
44
|
+
* import { toSessionUpdateInput } from "@stigmer/sdk";
|
|
45
|
+
*
|
|
42
46
|
* function TagSession({ session }: { session: Session }) {
|
|
43
47
|
* const { update, isUpdating } = useUpdateSession();
|
|
44
48
|
*
|
|
45
49
|
* async function handleTag() {
|
|
46
|
-
* const
|
|
50
|
+
* const mapped = toSessionUpdateInput(session);
|
|
47
51
|
* await update({
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
* //
|
|
51
|
-
*
|
|
52
|
-
* subject: spec?.subject,
|
|
53
|
-
* harnessStateId: spec?.harnessStateId,
|
|
54
|
-
* harness: spec?.harness,
|
|
55
|
-
* cursorMode: spec?.cursorMode,
|
|
56
|
-
* executionTarget: spec?.executionTarget,
|
|
57
|
-
* // ...including the spec lists (workspaceEntries, mcpServerUsages,
|
|
58
|
-
* // skillRefs), converted from the fetched proto exactly as
|
|
59
|
-
* // useSessionConversation's update path does...
|
|
60
|
-
* // ...then apply the one change on top of the carried metadata.
|
|
61
|
-
* metadata: { ...spec?.metadata, "acme/reviewed": "true" },
|
|
52
|
+
* ...mapped,
|
|
53
|
+
* // Nested values follow the same rule: spread the mapper's
|
|
54
|
+
* // complete value, then apply the one change on top.
|
|
55
|
+
* metadata: { ...mapped.metadata, "acme/reviewed": "true" },
|
|
62
56
|
* });
|
|
63
57
|
* }
|
|
64
58
|
*
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import { useId } from "react";
|
|
4
|
+
import { MemoryListPanel } from "../memory/MemoryListPanel.js";
|
|
5
|
+
import { useActiveOrgSlug } from "../organization/OrgProvider.js";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Settings section listing everything the platform remembers about the
|
|
9
|
+
* caller in the active organization.
|
|
10
|
+
*
|
|
11
|
+
* The helper copy carries the DD-006 D6 transparency statement: a
|
|
12
|
+
* confirmed memory is injected into the caller's future sessions and
|
|
13
|
+
* appears in those executions' records. Memory content everywhere else
|
|
14
|
+
* is subject-only — this page shows the caller their own records and
|
|
15
|
+
* nobody else's.
|
|
16
|
+
*/
|
|
17
|
+
export function MemorySection() {
|
|
18
|
+
const headingId = useId();
|
|
19
|
+
const org = useActiveOrgSlug();
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<section aria-labelledby={headingId}>
|
|
23
|
+
<h2
|
|
24
|
+
id={headingId}
|
|
25
|
+
className="stg:text-foreground stg:mb-1 stg:text-sm stg:font-semibold"
|
|
26
|
+
>
|
|
27
|
+
Memory
|
|
28
|
+
</h2>
|
|
29
|
+
<p className="stg:text-muted-foreground stg:mb-6 stg:text-xs">
|
|
30
|
+
Facts agents proposed to remember about you in this organization.
|
|
31
|
+
Confirmed memories are shared with agents in your future sessions
|
|
32
|
+
and appear in those executions' records. Only you can see
|
|
33
|
+
them here, and you can edit or delete any of them at any time.
|
|
34
|
+
</p>
|
|
35
|
+
|
|
36
|
+
{!org ? (
|
|
37
|
+
<p className="stg:text-muted-foreground stg:py-4 stg:text-center stg:text-xs">
|
|
38
|
+
Select an organization to view its memories.
|
|
39
|
+
</p>
|
|
40
|
+
) : (
|
|
41
|
+
<MemoryListPanel org={org} />
|
|
42
|
+
)}
|
|
43
|
+
</section>
|
|
44
|
+
);
|
|
45
|
+
}
|
package/src/settings/index.ts
CHANGED
|
@@ -12,6 +12,7 @@ export { MembersSection } from "./MembersSection.js";
|
|
|
12
12
|
export { OrgProfileSection } from "./OrgProfileSection.js";
|
|
13
13
|
export { OrgPreferencesSection } from "./OrgPreferencesSection.js";
|
|
14
14
|
export { AccountPreferencesSection } from "./AccountPreferencesSection.js";
|
|
15
|
+
export { MemorySection } from "./MemorySection.js";
|
|
15
16
|
export { EnvironmentsSection } from "./EnvironmentsSection.js";
|
|
16
17
|
export { InvitationsSection } from "./InvitationsSection.js";
|
|
17
18
|
export { IdentityProvidersSection } from "./IdentityProvidersSection.js";
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
AppWindow,
|
|
5
5
|
BarChart3,
|
|
6
6
|
Box,
|
|
7
|
+
Brain,
|
|
7
8
|
Building2,
|
|
8
9
|
CreditCard,
|
|
9
10
|
KeyRound,
|
|
@@ -108,6 +109,7 @@ export const SETTINGS_NAV_GROUPS: readonly SettingsNavGroup[] = [
|
|
|
108
109
|
label: "Preferences",
|
|
109
110
|
icon: UserCog,
|
|
110
111
|
},
|
|
112
|
+
{ href: "/settings/memory", label: "Memory", icon: Brain },
|
|
111
113
|
],
|
|
112
114
|
},
|
|
113
115
|
];
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import { useCallback, useState } from "react";
|
|
4
4
|
import type { GetOrgUsageReportOutput } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/io_pb";
|
|
5
|
+
import { downloadTextFile } from "../internal/download.js";
|
|
5
6
|
|
|
6
7
|
/** Export format for the CSV download. */
|
|
7
8
|
export type ExportFormat = "daily_summary" | "model_breakdown";
|
|
@@ -41,7 +42,7 @@ export function useExportCSV(
|
|
|
41
42
|
? buildDailySummaryCSV(report, orgId)
|
|
42
43
|
: buildModelBreakdownCSV(report, orgId);
|
|
43
44
|
|
|
44
|
-
|
|
45
|
+
downloadTextFile(csv, filename, "text/csv");
|
|
45
46
|
} finally {
|
|
46
47
|
setIsExporting(false);
|
|
47
48
|
}
|
|
@@ -100,16 +101,3 @@ function escapeCsvField(value: string): string {
|
|
|
100
101
|
}
|
|
101
102
|
return value;
|
|
102
103
|
}
|
|
103
|
-
|
|
104
|
-
function downloadCSV(csv: string, filename: string): void {
|
|
105
|
-
const blob = new Blob([csv], { type: "text/csv;charset=utf-8;" });
|
|
106
|
-
const url = URL.createObjectURL(blob);
|
|
107
|
-
const link = document.createElement("a");
|
|
108
|
-
link.href = url;
|
|
109
|
-
link.download = filename;
|
|
110
|
-
link.style.display = "none";
|
|
111
|
-
document.body.appendChild(link);
|
|
112
|
-
link.click();
|
|
113
|
-
document.body.removeChild(link);
|
|
114
|
-
URL.revokeObjectURL(url);
|
|
115
|
-
}
|
|
@@ -24,15 +24,17 @@ interface FormFieldEntry {
|
|
|
24
24
|
enumValues: string;
|
|
25
25
|
}
|
|
26
26
|
|
|
27
|
-
//
|
|
28
|
-
//
|
|
29
|
-
//
|
|
30
|
-
//
|
|
31
|
-
// the server
|
|
27
|
+
// ESCALATE carries the outcome-by-name contract (stigmer/stigmer#781): the
|
|
28
|
+
// timeout resolves to the outcome NAMED "escalate" and follows its routing,
|
|
29
|
+
// so the gate must declare that outcome — no extra config fields (the
|
|
30
|
+
// pre-#779 option wrote an `escalation_task` field the proto never had).
|
|
31
|
+
// The builder hints when the outcome is missing; the server validator is
|
|
32
|
+
// the enforcement.
|
|
32
33
|
const TIMEOUT_POLICY_OPTIONS = [
|
|
33
34
|
{ value: "HUMAN_INPUT_TIMEOUT_FAIL", label: "Fail — task errors on timeout" },
|
|
34
35
|
{ value: "HUMAN_INPUT_TIMEOUT_APPROVE", label: "Auto-approve — proceed as approved" },
|
|
35
36
|
{ value: "HUMAN_INPUT_TIMEOUT_DENY", label: "Auto-deny — proceed as denied" },
|
|
37
|
+
{ value: "HUMAN_INPUT_TIMEOUT_ESCALATE", label: "Escalate — route via the 'escalate' outcome" },
|
|
36
38
|
] as const;
|
|
37
39
|
|
|
38
40
|
const TIMEOUT_UNITS = [
|
|
@@ -111,6 +113,7 @@ export const ApprovalFormBuilder = memo(function ApprovalFormBuilder({
|
|
|
111
113
|
<TimeoutSection
|
|
112
114
|
timeout={typeof cfg.timeout === "number" ? cfg.timeout : 0}
|
|
113
115
|
onTimeout={typeof cfg.on_timeout === "string" ? cfg.on_timeout : ""}
|
|
116
|
+
hasEscalateOutcome={extractOutcomes(cfg).some((o) => o.name === "escalate")}
|
|
114
117
|
onUpdateConfig={onUpdateConfig}
|
|
115
118
|
/>
|
|
116
119
|
<StringListSection
|
|
@@ -621,10 +624,12 @@ function FormFieldRow({
|
|
|
621
624
|
function TimeoutSection({
|
|
622
625
|
timeout,
|
|
623
626
|
onTimeout,
|
|
627
|
+
hasEscalateOutcome,
|
|
624
628
|
onUpdateConfig,
|
|
625
629
|
}: {
|
|
626
630
|
timeout: number;
|
|
627
631
|
onTimeout: string;
|
|
632
|
+
hasEscalateOutcome: boolean;
|
|
628
633
|
onUpdateConfig: (fieldPath: string, value: unknown) => void;
|
|
629
634
|
}) {
|
|
630
635
|
const bestUnit = useMemo(() => {
|
|
@@ -703,6 +708,16 @@ function TimeoutSection({
|
|
|
703
708
|
<option key={opt.value} value={opt.value}>{opt.label}</option>
|
|
704
709
|
))}
|
|
705
710
|
</select>
|
|
711
|
+
{onTimeout === "HUMAN_INPUT_TIMEOUT_ESCALATE" && !hasEscalateOutcome && (
|
|
712
|
+
<p
|
|
713
|
+
role="alert"
|
|
714
|
+
className="stg:text-[10px] stg:text-[var(--stgm-warning,#d97706)]"
|
|
715
|
+
>
|
|
716
|
+
Escalate needs an outcome named "escalate" with routing —
|
|
717
|
+
the timeout resolves to it. Add the outcome above, or the server
|
|
718
|
+
will reject this workflow.
|
|
719
|
+
</p>
|
|
720
|
+
)}
|
|
706
721
|
</div>
|
|
707
722
|
)}
|
|
708
723
|
|
|
@@ -9,7 +9,7 @@ import { ValidationState } from "@stigmer/protos/ai/stigmer/agentic/workflow/v1/
|
|
|
9
9
|
import type { WorkflowInput } from "@stigmer/sdk";
|
|
10
10
|
import { useWorkflow } from "./useWorkflow.js";
|
|
11
11
|
import { useUpdateWorkflow } from "./useUpdateWorkflow.js";
|
|
12
|
-
import {
|
|
12
|
+
import { toWorkflowUpdateInput } from "@stigmer/sdk";
|
|
13
13
|
import { useWorkflowExecutionList } from "./useWorkflowExecutionList.js";
|
|
14
14
|
import { useWorkflowDashboardSummary } from "./useWorkflowDashboardSummary.js";
|
|
15
15
|
import { WorkflowOverviewGraph } from "./WorkflowOverviewGraph.js";
|
|
@@ -189,7 +189,7 @@ export function WorkflowDetailView({
|
|
|
189
189
|
value: WorkflowInput[K],
|
|
190
190
|
): Promise<boolean> => {
|
|
191
191
|
if (!workflow) return false;
|
|
192
|
-
const input =
|
|
192
|
+
const input = toWorkflowUpdateInput(workflow);
|
|
193
193
|
(input as unknown as Record<string, unknown>)[field] = value;
|
|
194
194
|
try {
|
|
195
195
|
const updated = await update(input);
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
import { describe, it, expect, vi, afterEach } from "vitest";
|
|
2
|
+
import { cleanup, fireEvent, render, screen, waitFor } from "@testing-library/react";
|
|
3
|
+
import { create } from "@bufbuild/protobuf";
|
|
4
|
+
import {
|
|
5
|
+
WorkflowInstanceSchema,
|
|
6
|
+
type WorkflowInstance,
|
|
7
|
+
} from "@stigmer/protos/ai/stigmer/agentic/workflowinstance/v1/api_pb";
|
|
8
|
+
import { WorkflowExecutionVisibility } from "@stigmer/protos/ai/stigmer/agentic/workflowinstance/v1/spec_pb";
|
|
9
|
+
import { ApiResourceKind } from "@stigmer/protos/ai/stigmer/commons/apiresource/apiresourcekind/api_resource_kind_pb";
|
|
10
|
+
import type { WorkflowInstanceInput } from "@stigmer/sdk";
|
|
11
|
+
import { StigmerContext } from "../../context";
|
|
12
|
+
import { WorkflowInstanceDetailPanel } from "../instance/WorkflowInstanceDetailPanel";
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Regression suite for the full-spec-replace wipe bug: before the
|
|
16
|
+
* generated-mapper migration, saving environment edits in this panel
|
|
17
|
+
* silently reset `execution_visibility` (run observability, which has its
|
|
18
|
+
* own dedicated updateExecutionVisibility RPC and control). The panel
|
|
19
|
+
* must spread `toWorkflowInstanceUpdateInput` and override only the
|
|
20
|
+
* environment refs.
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
const INSTANCE: WorkflowInstance = create(WorkflowInstanceSchema, {
|
|
24
|
+
metadata: {
|
|
25
|
+
id: "wfi-1",
|
|
26
|
+
name: "Nightly Triage",
|
|
27
|
+
slug: "nightly-triage",
|
|
28
|
+
org: "acme",
|
|
29
|
+
},
|
|
30
|
+
spec: {
|
|
31
|
+
workflowId: "wf-1",
|
|
32
|
+
description: "Runs every night.",
|
|
33
|
+
environmentRefs: [
|
|
34
|
+
{ org: "acme", slug: "prod", kind: ApiResourceKind.environment },
|
|
35
|
+
],
|
|
36
|
+
executionVisibility: WorkflowExecutionVisibility.organization,
|
|
37
|
+
},
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
function renderPanel(update: ReturnType<typeof vi.fn>) {
|
|
41
|
+
const client = {
|
|
42
|
+
workflowInstance: { update },
|
|
43
|
+
iamPolicy: {
|
|
44
|
+
checkMyPermission: vi.fn(async () => ({ isAuthorized: true })),
|
|
45
|
+
},
|
|
46
|
+
environment: {
|
|
47
|
+
list: vi.fn(async () => ({ items: [], totalCount: 0 })),
|
|
48
|
+
},
|
|
49
|
+
} as never;
|
|
50
|
+
return render(
|
|
51
|
+
<StigmerContext.Provider value={client}>
|
|
52
|
+
<WorkflowInstanceDetailPanel instance={INSTANCE} org="acme" onClose={() => {}} />
|
|
53
|
+
</StigmerContext.Provider>,
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
afterEach(cleanup);
|
|
58
|
+
|
|
59
|
+
describe("WorkflowInstanceDetailPanel save payload", () => {
|
|
60
|
+
it("round-trips execution_visibility on an environments-only save (the wipe bug)", async () => {
|
|
61
|
+
const update = vi.fn(async (_input: WorkflowInstanceInput) => INSTANCE);
|
|
62
|
+
renderPanel(update);
|
|
63
|
+
|
|
64
|
+
fireEvent.click(await screen.findByRole("button", { name: "Edit" }));
|
|
65
|
+
fireEvent.click(screen.getByRole("button", { name: "Save" }));
|
|
66
|
+
|
|
67
|
+
await waitFor(() => expect(update).toHaveBeenCalledTimes(1));
|
|
68
|
+
const input = update.mock.calls[0]![0];
|
|
69
|
+
|
|
70
|
+
// The wipe-bug guard: run visibility is edited elsewhere and must
|
|
71
|
+
// survive an environment save untouched.
|
|
72
|
+
expect(input.executionVisibility).toBe(
|
|
73
|
+
WorkflowExecutionVisibility.organization,
|
|
74
|
+
);
|
|
75
|
+
expect(input.workflowId).toBe("wf-1");
|
|
76
|
+
expect(input.description).toBe("Runs every night.");
|
|
77
|
+
// The form-owned field.
|
|
78
|
+
expect(input.environmentRefs).toEqual([{ org: "acme", slug: "prod" }]);
|
|
79
|
+
// Addressing fields.
|
|
80
|
+
expect(input.org).toBe("acme");
|
|
81
|
+
expect(input.slug).toBe("nightly-triage");
|
|
82
|
+
});
|
|
83
|
+
});
|
package/src/workflow/index.ts
CHANGED
|
@@ -481,8 +481,6 @@ export {
|
|
|
481
481
|
type UseUpdateWorkflowReturn,
|
|
482
482
|
} from "./useUpdateWorkflow.js";
|
|
483
483
|
|
|
484
|
-
export { workflowToInput } from "./internal/workflowToInput.js";
|
|
485
|
-
|
|
486
484
|
// Starter YAML template for new workflow creation
|
|
487
485
|
export { STARTER_WORKFLOW_YAML } from "./starter-workflow-yaml.js";
|
|
488
486
|
|
|
@@ -9,7 +9,7 @@ import { ApiResourceVisibility } from "@stigmer/protos/ai/stigmer/commons/apires
|
|
|
9
9
|
import { ApiResourceKind } from "@stigmer/protos/ai/stigmer/commons/apiresource/apiresourcekind/api_resource_kind_pb";
|
|
10
10
|
import { WorkflowExecutionVisibility } from "@stigmer/protos/ai/stigmer/agentic/workflowinstance/v1/spec_pb";
|
|
11
11
|
import type { ResourceRef } from "@stigmer/sdk";
|
|
12
|
-
import { getUserMessage } from "@stigmer/sdk";
|
|
12
|
+
import { getUserMessage, toWorkflowInstanceUpdateInput } from "@stigmer/sdk";
|
|
13
13
|
import { useUpdateWorkflowInstance } from "./useUpdateWorkflowInstance.js";
|
|
14
14
|
import { useDeleteWorkflowInstance } from "./useDeleteWorkflowInstance.js";
|
|
15
15
|
import { RunVisibilityControl } from "./RunVisibilityControl.js";
|
|
@@ -104,20 +104,19 @@ export function WorkflowInstanceDetailPanel({
|
|
|
104
104
|
|
|
105
105
|
const handleSaveEnvs = useCallback(async () => {
|
|
106
106
|
try {
|
|
107
|
+
// Full-spec-replace safety: spread the complete mapped input so
|
|
108
|
+
// unlisted spec fields (e.g. execution_visibility, which has its
|
|
109
|
+
// own dedicated control above) survive an environment-only save.
|
|
107
110
|
await update({
|
|
108
|
-
|
|
109
|
-
org: meta?.org ?? org,
|
|
110
|
-
workflowId: spec?.workflowId ?? "",
|
|
111
|
-
description: spec?.description,
|
|
111
|
+
...toWorkflowInstanceUpdateInput(instance),
|
|
112
112
|
environmentRefs: editEnvRefs,
|
|
113
|
-
visibility: meta?.visibility,
|
|
114
113
|
});
|
|
115
114
|
setIsEditingEnvs(false);
|
|
116
115
|
onUpdated?.();
|
|
117
116
|
} catch {
|
|
118
117
|
// error displayed by hook
|
|
119
118
|
}
|
|
120
|
-
}, [update,
|
|
119
|
+
}, [update, instance, editEnvRefs, onUpdated]);
|
|
121
120
|
|
|
122
121
|
const handleDelete = useCallback(async () => {
|
|
123
122
|
setDeleteError(null);
|
|
@@ -23,9 +23,9 @@ export interface UseUpdateWorkflowReturn {
|
|
|
23
23
|
*
|
|
24
24
|
* Wraps `stigmer.workflow.update(input)` with loading and error state.
|
|
25
25
|
* The caller must provide a **complete** `WorkflowInput` -- the backend
|
|
26
|
-
* performs full spec replacement. Use `
|
|
27
|
-
* the input from a fetched workflow,
|
|
28
|
-
* the result here.
|
|
26
|
+
* performs full spec replacement. Use `toWorkflowUpdateInput()` (from
|
|
27
|
+
* `@stigmer/sdk`) to reconstruct the input from a fetched workflow,
|
|
28
|
+
* modify the desired field, and pass the result here.
|
|
29
29
|
*/
|
|
30
30
|
export function useUpdateWorkflow(): UseUpdateWorkflowReturn {
|
|
31
31
|
const stigmer = useStigmer();
|