@stigmer/react 3.12.1 → 3.12.2
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/access/ManageAccessDialog.d.ts.map +1 -1
- package/access/ManageAccessDialog.js +7 -2
- package/access/ManageAccessDialog.js.map +1 -1
- package/activity/format-relative-time.d.ts +11 -9
- package/activity/format-relative-time.d.ts.map +1 -1
- package/activity/format-relative-time.js +11 -9
- package/activity/format-relative-time.js.map +1 -1
- package/agent/steps/CapabilitiesStep.js +5 -2
- package/agent/steps/CapabilitiesStep.js.map +1 -1
- package/agent/steps/IdentityStep.d.ts.map +1 -1
- package/agent/steps/IdentityStep.js +6 -5
- package/agent/steps/IdentityStep.js.map +1 -1
- package/agent-instance/CreateAgentInstanceDialog.d.ts.map +1 -1
- package/agent-instance/CreateAgentInstanceDialog.js +10 -2
- package/agent-instance/CreateAgentInstanceDialog.js.map +1 -1
- package/api-key/ApiKeyCreatedAlert.d.ts.map +1 -1
- package/api-key/ApiKeyCreatedAlert.js +12 -20
- package/api-key/ApiKeyCreatedAlert.js.map +1 -1
- package/api-key/ApiKeyListPanel.d.ts.map +1 -1
- package/api-key/ApiKeyListPanel.js +3 -23
- package/api-key/ApiKeyListPanel.js.map +1 -1
- package/api-key/CreateApiKeyForm.d.ts.map +1 -1
- package/api-key/CreateApiKeyForm.js +6 -10
- package/api-key/CreateApiKeyForm.js.map +1 -1
- package/approval-defaults-context.d.ts +47 -0
- package/approval-defaults-context.d.ts.map +1 -0
- package/approval-defaults-context.js +27 -0
- package/approval-defaults-context.js.map +1 -0
- package/attachment/index.d.ts +2 -0
- package/attachment/index.d.ts.map +1 -1
- package/attachment/index.js +1 -0
- package/attachment/index.js.map +1 -1
- package/attachment/vision-preflight.d.ts +113 -0
- package/attachment/vision-preflight.d.ts.map +1 -0
- package/attachment/vision-preflight.js +143 -0
- package/attachment/vision-preflight.js.map +1 -0
- package/billing/AutoRechargeCard.d.ts.map +1 -1
- package/billing/AutoRechargeCard.js +3 -2
- package/billing/AutoRechargeCard.js.map +1 -1
- package/billing/BillingSection.d.ts.map +1 -1
- package/billing/BillingSection.js +3 -2
- package/billing/BillingSection.js.map +1 -1
- package/channel/ChannelConversationsDialog.d.ts.map +1 -1
- package/channel/ChannelConversationsDialog.js +5 -4
- package/channel/ChannelConversationsDialog.js.map +1 -1
- package/channel/ChannelCredentialsDialog.d.ts.map +1 -1
- package/channel/ChannelCredentialsDialog.js +9 -4
- package/channel/ChannelCredentialsDialog.js.map +1 -1
- package/channel/ChannelTemplatesDialog.d.ts.map +1 -1
- package/channel/ChannelTemplatesDialog.js +5 -4
- package/channel/ChannelTemplatesDialog.js.map +1 -1
- package/channel/ConnectSlackDialog.d.ts.map +1 -1
- package/channel/ConnectSlackDialog.js +9 -4
- package/channel/ConnectSlackDialog.js.map +1 -1
- package/channel/ConnectWhatsAppDialog.d.ts.map +1 -1
- package/channel/ConnectWhatsAppDialog.js +9 -4
- package/channel/ConnectWhatsAppDialog.js.map +1 -1
- package/channel/useChannelSessions.d.ts.map +1 -1
- package/channel/useChannelSessions.js.map +1 -1
- package/channel-app/ChannelAppDetailPanel.d.ts.map +1 -1
- package/channel-app/ChannelAppDetailPanel.js +8 -5
- package/channel-app/ChannelAppDetailPanel.js.map +1 -1
- package/channel-app/CreateChannelAppForm.d.ts.map +1 -1
- package/channel-app/CreateChannelAppForm.js +12 -7
- package/channel-app/CreateChannelAppForm.js.map +1 -1
- package/channel-app/internal.d.ts +0 -1
- package/channel-app/internal.d.ts.map +1 -1
- package/channel-app/internal.js +5 -10
- package/channel-app/internal.js.map +1 -1
- package/composer/ComposerToolbar.js +2 -1
- package/composer/ComposerToolbar.js.map +1 -1
- package/composer/SessionComposer.d.ts +1 -1
- package/composer/SessionComposer.d.ts.map +1 -1
- package/composer/SessionComposer.js +120 -13
- package/composer/SessionComposer.js.map +1 -1
- package/composer/icons.d.ts +0 -1
- package/composer/icons.d.ts.map +1 -1
- package/composer/icons.js +0 -3
- package/composer/icons.js.map +1 -1
- package/conversation/ConversationComposer.js +1 -1
- package/conversation/ConversationComposer.js.map +1 -1
- package/conversation/ConversationListPane.d.ts.map +1 -1
- package/conversation/ConversationListPane.js +3 -2
- package/conversation/ConversationListPane.js.map +1 -1
- package/cursor-accounts/MemberCoverageTable.js +3 -14
- package/cursor-accounts/MemberCoverageTable.js.map +1 -1
- package/dashboard/DashboardFailedRuns.d.ts.map +1 -1
- package/dashboard/DashboardFailedRuns.js +2 -14
- package/dashboard/DashboardFailedRuns.js.map +1 -1
- package/environment/CreateEnvironmentForm.d.ts.map +1 -1
- package/environment/CreateEnvironmentForm.js +4 -8
- package/environment/CreateEnvironmentForm.js.map +1 -1
- package/environment/EnvVarForm.d.ts.map +1 -1
- package/environment/EnvVarForm.js +2 -4
- package/environment/EnvVarForm.js.map +1 -1
- package/environment/EnvironmentVariableEditor.d.ts.map +1 -1
- package/environment/EnvironmentVariableEditor.js +5 -7
- package/environment/EnvironmentVariableEditor.js.map +1 -1
- package/execution/ArtifactApplyButton.d.ts.map +1 -1
- package/execution/ArtifactApplyButton.js +2 -4
- package/execution/ArtifactApplyButton.js.map +1 -1
- package/execution/ExecutionErrorNotice.d.ts +36 -0
- package/execution/ExecutionErrorNotice.d.ts.map +1 -0
- package/execution/ExecutionErrorNotice.js +39 -0
- package/execution/ExecutionErrorNotice.js.map +1 -0
- package/execution/FilePathLink.d.ts.map +1 -1
- package/execution/FilePathLink.js +5 -8
- package/execution/FilePathLink.js.map +1 -1
- package/execution/FileReviewCard.d.ts.map +1 -1
- package/execution/FileReviewCard.js +1 -6
- package/execution/FileReviewCard.js.map +1 -1
- package/execution/FollowUpInput.d.ts.map +1 -1
- package/execution/FollowUpInput.js +1 -3
- package/execution/FollowUpInput.js.map +1 -1
- package/execution/LivenessStatusLine.d.ts +40 -0
- package/execution/LivenessStatusLine.d.ts.map +1 -0
- package/execution/LivenessStatusLine.js +34 -0
- package/execution/LivenessStatusLine.js.map +1 -0
- package/execution/MessageEntry.d.ts.map +1 -1
- package/execution/MessageEntry.js +31 -3
- package/execution/MessageEntry.js.map +1 -1
- package/execution/MessageThread.d.ts +25 -0
- package/execution/MessageThread.d.ts.map +1 -1
- package/execution/MessageThread.js +51 -36
- package/execution/MessageThread.js.map +1 -1
- package/execution/SetupProgress.d.ts.map +1 -1
- package/execution/SetupProgress.js +1 -1
- package/execution/SetupProgress.js.map +1 -1
- package/execution/SubAgentSection.d.ts.map +1 -1
- package/execution/SubAgentSection.js +9 -7
- package/execution/SubAgentSection.js.map +1 -1
- package/execution/TerminalSession.d.ts +30 -0
- package/execution/TerminalSession.d.ts.map +1 -1
- package/execution/TerminalSession.js +37 -1
- package/execution/TerminalSession.js.map +1 -1
- package/execution/ToolCallDetail.d.ts +9 -0
- package/execution/ToolCallDetail.d.ts.map +1 -1
- package/execution/ToolCallDetail.js +16 -0
- package/execution/ToolCallDetail.js.map +1 -1
- package/execution/ToolCallItem.d.ts +20 -6
- package/execution/ToolCallItem.d.ts.map +1 -1
- package/execution/ToolCallItem.js +102 -29
- package/execution/ToolCallItem.js.map +1 -1
- package/execution/ToolRunGroup.d.ts.map +1 -1
- package/execution/ToolRunGroup.js +11 -11
- package/execution/ToolRunGroup.js.map +1 -1
- package/execution/WriteBackCard.d.ts.map +1 -1
- package/execution/WriteBackCard.js +5 -20
- package/execution/WriteBackCard.js.map +1 -1
- package/execution/index.d.ts +6 -2
- package/execution/index.d.ts.map +1 -1
- package/execution/index.js +3 -1
- package/execution/index.js.map +1 -1
- package/execution/tool-categories.d.ts +42 -7
- package/execution/tool-categories.d.ts.map +1 -1
- package/execution/tool-categories.js +38 -4
- package/execution/tool-categories.js.map +1 -1
- package/execution/tool-presenter.d.ts +17 -1
- package/execution/tool-presenter.d.ts.map +1 -1
- package/execution/tool-presenter.js +4 -1
- package/execution/tool-presenter.js.map +1 -1
- package/execution/useArtifactInspection.d.ts.map +1 -1
- package/execution/useArtifactInspection.js +4 -7
- package/execution/useArtifactInspection.js.map +1 -1
- package/iam-policy/GrantAccessForm.d.ts.map +1 -1
- package/iam-policy/GrantAccessForm.js +2 -4
- package/iam-policy/GrantAccessForm.js.map +1 -1
- package/iam-policy/OrgMembersPanel.d.ts.map +1 -1
- package/iam-policy/OrgMembersPanel.js +3 -5
- package/iam-policy/OrgMembersPanel.js.map +1 -1
- package/iam-policy/RoleSelector.d.ts.map +1 -1
- package/iam-policy/RoleSelector.js +7 -1
- package/iam-policy/RoleSelector.js.map +1 -1
- package/identity-provider/CreateIdentityProviderForm.d.ts.map +1 -1
- package/identity-provider/CreateIdentityProviderForm.js +6 -9
- package/identity-provider/CreateIdentityProviderForm.js.map +1 -1
- package/identity-provider/IdentityProviderDetailPanel.d.ts.map +1 -1
- package/identity-provider/IdentityProviderDetailPanel.js +17 -26
- package/identity-provider/IdentityProviderDetailPanel.js.map +1 -1
- package/identity-provider/IdentityProviderListPanel.d.ts.map +1 -1
- package/identity-provider/IdentityProviderListPanel.js +2 -4
- package/identity-provider/IdentityProviderListPanel.js.map +1 -1
- package/identity-provider/IdentityProviderWizard.d.ts.map +1 -1
- package/identity-provider/IdentityProviderWizard.js +8 -7
- package/identity-provider/IdentityProviderWizard.js.map +1 -1
- package/identity-provider/SsoLoginPrompt.js +5 -6
- package/identity-provider/SsoLoginPrompt.js.map +1 -1
- package/index.d.ts +9 -8
- package/index.d.ts.map +1 -1
- package/index.js +4 -4
- package/index.js.map +1 -1
- package/internal/DecisionButton.d.ts.map +1 -1
- package/internal/DecisionButton.js +1 -6
- package/internal/DecisionButton.js.map +1 -1
- package/internal/SpinnerIcon.d.ts +22 -0
- package/internal/SpinnerIcon.d.ts.map +1 -0
- package/internal/SpinnerIcon.js +23 -0
- package/internal/SpinnerIcon.js.map +1 -0
- package/internal/select-element-text.d.ts +11 -0
- package/internal/select-element-text.d.ts.map +1 -0
- package/internal/select-element-text.js +19 -0
- package/internal/select-element-text.js.map +1 -0
- package/internal/thread-card/ThreadCardShell.d.ts +27 -10
- package/internal/thread-card/ThreadCardShell.d.ts.map +1 -1
- package/internal/thread-card/ThreadCardShell.js +11 -5
- package/internal/thread-card/ThreadCardShell.js.map +1 -1
- package/internal/thread-card/glyphs.d.ts +11 -2
- package/internal/thread-card/glyphs.d.ts.map +1 -1
- package/internal/thread-card/glyphs.js +9 -3
- package/internal/thread-card/glyphs.js.map +1 -1
- package/internal/thread-card/index.d.ts +1 -1
- package/internal/thread-card/index.d.ts.map +1 -1
- package/internal/thread-card/index.js.map +1 -1
- package/internal/useCopyFeedback.d.ts +28 -0
- package/internal/useCopyFeedback.d.ts.map +1 -0
- package/internal/useCopyFeedback.js +40 -0
- package/internal/useCopyFeedback.js.map +1 -0
- package/invitation/InvitationCreatedAlert.d.ts.map +1 -1
- package/invitation/InvitationCreatedAlert.js +12 -19
- package/invitation/InvitationCreatedAlert.js.map +1 -1
- package/invitation/InvitationManager.d.ts.map +1 -1
- package/invitation/InvitationManager.js +14 -21
- package/invitation/InvitationManager.js.map +1 -1
- package/invitation/InvitationRedemption.d.ts.map +1 -1
- package/invitation/InvitationRedemption.js +2 -4
- package/invitation/InvitationRedemption.js.map +1 -1
- package/library/useExportResource.d.ts.map +1 -1
- package/library/useExportResource.js +16 -27
- package/library/useExportResource.js.map +1 -1
- package/manifest/ApplyManifestDialog.js +1 -1
- package/manifest/EditResourceYamlDialog.js +1 -1
- package/mcp-server/DefinitionDriftNotice.d.ts +42 -0
- package/mcp-server/DefinitionDriftNotice.d.ts.map +1 -0
- package/mcp-server/DefinitionDriftNotice.js +52 -0
- package/mcp-server/DefinitionDriftNotice.js.map +1 -0
- package/mcp-server/McpServerConnectDialog.js +1 -1
- package/mcp-server/McpServerDetailView.d.ts.map +1 -1
- package/mcp-server/McpServerDetailView.js +47 -14
- package/mcp-server/McpServerDetailView.js.map +1 -1
- package/mcp-server/OAuthAppForm.d.ts.map +1 -1
- package/mcp-server/OAuthAppForm.js +2 -4
- package/mcp-server/OAuthAppForm.js.map +1 -1
- package/mcp-server/internal/definitionDrift.d.ts +39 -0
- package/mcp-server/internal/definitionDrift.d.ts.map +1 -0
- package/mcp-server/internal/definitionDrift.js +122 -0
- package/mcp-server/internal/definitionDrift.js.map +1 -0
- package/mcp-server/internal/mcpServerToInput.d.ts.map +1 -1
- package/mcp-server/internal/mcpServerToInput.js +3 -0
- package/mcp-server/internal/mcpServerToInput.js.map +1 -1
- package/mcp-server/steps/EnvironmentAuthStep.d.ts.map +1 -1
- package/mcp-server/steps/EnvironmentAuthStep.js +8 -4
- package/mcp-server/steps/EnvironmentAuthStep.js.map +1 -1
- package/mcp-server/steps/IdentityTransportStep.d.ts.map +1 -1
- package/mcp-server/steps/IdentityTransportStep.js +5 -4
- package/mcp-server/steps/IdentityTransportStep.js.map +1 -1
- package/mcp-server/useMcpServerConnect.d.ts +1 -1
- package/mcp-server/useMcpServerDefinitionDrift.d.ts +44 -0
- package/mcp-server/useMcpServerDefinitionDrift.d.ts.map +1 -0
- package/mcp-server/useMcpServerDefinitionDrift.js +61 -0
- package/mcp-server/useMcpServerDefinitionDrift.js.map +1 -0
- package/models/ModelRegistryContext.d.ts +7 -1
- package/models/ModelRegistryContext.d.ts.map +1 -1
- package/models/ModelRegistryContext.js.map +1 -1
- package/models/ModelSelector.js +9 -1
- package/models/ModelSelector.js.map +1 -1
- package/models/index.d.ts +2 -2
- package/models/index.d.ts.map +1 -1
- package/models/index.js +1 -1
- package/models/index.js.map +1 -1
- package/models/registry.d.ts +88 -6
- package/models/registry.d.ts.map +1 -1
- package/models/registry.js +133 -27
- package/models/registry.js.map +1 -1
- package/models/useModelRegistry.d.ts +7 -1
- package/models/useModelRegistry.d.ts.map +1 -1
- package/models/useModelRegistry.js +3 -2
- package/models/useModelRegistry.js.map +1 -1
- package/oauth-app/CreateOAuthAppForm.d.ts.map +1 -1
- package/oauth-app/CreateOAuthAppForm.js +4 -5
- package/oauth-app/CreateOAuthAppForm.js.map +1 -1
- package/oauth-app/OAuthAppDetailPanel.d.ts.map +1 -1
- package/oauth-app/OAuthAppDetailPanel.js +5 -6
- package/oauth-app/OAuthAppDetailPanel.js.map +1 -1
- package/organization/CreateOrganizationForm.d.ts.map +1 -1
- package/organization/CreateOrganizationForm.js +5 -9
- package/organization/CreateOrganizationForm.js.map +1 -1
- package/organization/OrgProfilePanel.d.ts.map +1 -1
- package/organization/OrgProfilePanel.js +7 -16
- package/organization/OrgProfilePanel.js.map +1 -1
- package/package.json +4 -4
- package/platform-client/CreatePlatformClientForm.d.ts.map +1 -1
- package/platform-client/CreatePlatformClientForm.js +5 -6
- package/platform-client/CreatePlatformClientForm.js.map +1 -1
- package/platform-client/PlatformClientDetailPanel.d.ts.map +1 -1
- package/platform-client/PlatformClientDetailPanel.js +6 -7
- package/platform-client/PlatformClientDetailPanel.js.map +1 -1
- package/platform-client/PlatformClientListPanel.d.ts.map +1 -1
- package/platform-client/PlatformClientListPanel.js +2 -4
- package/platform-client/PlatformClientListPanel.js.map +1 -1
- package/platform-client/PlatformClientSecretAlert.d.ts.map +1 -1
- package/platform-client/PlatformClientSecretAlert.js +18 -25
- package/platform-client/PlatformClientSecretAlert.js.map +1 -1
- package/provider.d.ts +34 -1
- package/provider.d.ts.map +1 -1
- package/provider.js +14 -7
- package/provider.js.map +1 -1
- package/resource-creation/WizardNav.d.ts.map +1 -1
- package/resource-creation/WizardNav.js +2 -4
- package/resource-creation/WizardNav.js.map +1 -1
- package/resource-detail/ConfirmDialog.js +1 -1
- package/resource-detail/useCopyResource.d.ts +4 -3
- package/resource-detail/useCopyResource.d.ts.map +1 -1
- package/resource-detail/useCopyResource.js +10 -19
- package/resource-detail/useCopyResource.js.map +1 -1
- package/schedule/ScheduleDetailView.d.ts.map +1 -1
- package/schedule/ScheduleDetailView.js +2 -4
- package/schedule/ScheduleDetailView.js.map +1 -1
- package/schedule/ScheduleForm.d.ts.map +1 -1
- package/schedule/ScheduleForm.js +6 -7
- package/schedule/ScheduleForm.js.map +1 -1
- package/session/NewSessionViewer.d.ts +52 -2
- package/session/NewSessionViewer.d.ts.map +1 -1
- package/session/NewSessionViewer.js +21 -6
- package/session/NewSessionViewer.js.map +1 -1
- package/session/SessionViewer.d.ts +63 -2
- package/session/SessionViewer.d.ts.map +1 -1
- package/session/SessionViewer.js +43 -17
- package/session/SessionViewer.js.map +1 -1
- package/session/audience.d.ts +17 -0
- package/session/audience.d.ts.map +1 -1
- package/session/index.d.ts +2 -1
- package/session/index.d.ts.map +1 -1
- package/session/index.js.map +1 -1
- package/session/run-config.d.ts +50 -0
- package/session/run-config.d.ts.map +1 -0
- package/session/run-config.js +15 -0
- package/session/run-config.js.map +1 -0
- package/session/useNewSessionFlow.d.ts +11 -0
- package/session/useNewSessionFlow.d.ts.map +1 -1
- package/session/useNewSessionFlow.js +29 -2
- package/session/useNewSessionFlow.js.map +1 -1
- package/session/useSessionConversation.d.ts +7 -7
- package/session/useSessionConversation.d.ts.map +1 -1
- package/session/useSessionConversation.js +2 -0
- package/session/useSessionConversation.js.map +1 -1
- package/session/useSessionPageFlow.d.ts +18 -4
- package/session/useSessionPageFlow.d.ts.map +1 -1
- package/session/useSessionPageFlow.js +33 -6
- package/session/useSessionPageFlow.js.map +1 -1
- package/session/useSessionPanel.d.ts +37 -2
- package/session/useSessionPanel.d.ts.map +1 -1
- package/session/useSessionPanel.js +44 -10
- package/session/useSessionPanel.js.map +1 -1
- package/settings/ApiKeysSection.d.ts.map +1 -1
- package/settings/ApiKeysSection.js +3 -2
- package/settings/ApiKeysSection.js.map +1 -1
- package/settings/ChannelAppsSection.d.ts.map +1 -1
- package/settings/ChannelAppsSection.js +3 -2
- package/settings/ChannelAppsSection.js.map +1 -1
- package/settings/EnvironmentsSection.js +5 -3
- package/settings/EnvironmentsSection.js.map +1 -1
- package/settings/IdentityProvidersSection.d.ts.map +1 -1
- package/settings/IdentityProvidersSection.js +3 -2
- package/settings/IdentityProvidersSection.js.map +1 -1
- package/settings/InvitationsSection.d.ts.map +1 -1
- package/settings/InvitationsSection.js +3 -1
- package/settings/InvitationsSection.js.map +1 -1
- package/settings/MembersSection.d.ts.map +1 -1
- package/settings/MembersSection.js +3 -1
- package/settings/MembersSection.js.map +1 -1
- package/settings/OAuthAppsSection.d.ts.map +1 -1
- package/settings/OAuthAppsSection.js +3 -2
- package/settings/OAuthAppsSection.js.map +1 -1
- package/settings/OrgProfileSection.d.ts.map +1 -1
- package/settings/OrgProfileSection.js +3 -2
- package/settings/OrgProfileSection.js.map +1 -1
- package/settings/PlatformClientsSection.d.ts.map +1 -1
- package/settings/PlatformClientsSection.js +3 -2
- package/settings/PlatformClientsSection.js.map +1 -1
- package/settings/UsageSection.d.ts.map +1 -1
- package/settings/UsageSection.js +3 -1
- package/settings/UsageSection.js.map +1 -1
- package/sharing/ShareAgentDialog.d.ts.map +1 -1
- package/sharing/ShareAgentDialog.js +18 -7
- package/sharing/ShareAgentDialog.js.map +1 -1
- package/sidebar/chrome.d.ts +3 -4
- package/sidebar/chrome.d.ts.map +1 -1
- package/sidebar/chrome.js +5 -4
- package/sidebar/chrome.js.map +1 -1
- package/skill/SkillDiffDialog.js +1 -1
- package/src/access/ManageAccessDialog.tsx +10 -4
- package/src/activity/format-relative-time.ts +11 -9
- package/src/agent/steps/CapabilitiesStep.tsx +6 -3
- package/src/agent/steps/IdentityStep.tsx +19 -12
- package/src/agent-instance/CreateAgentInstanceDialog.tsx +17 -8
- package/src/api-key/ApiKeyCreatedAlert.tsx +10 -19
- package/src/api-key/ApiKeyListPanel.tsx +3 -39
- package/src/api-key/CreateApiKeyForm.tsx +12 -26
- package/src/approval-defaults-context.ts +56 -0
- package/src/attachment/__tests__/vision-preflight.test.ts +311 -0
- package/src/attachment/index.ts +12 -0
- package/src/attachment/vision-preflight.ts +236 -0
- package/src/billing/AutoRechargeCard.tsx +5 -4
- package/src/billing/BillingSection.tsx +4 -3
- package/src/channel/ChannelConversationsDialog.tsx +8 -4
- package/src/channel/ChannelCredentialsDialog.tsx +14 -4
- package/src/channel/ChannelTemplatesDialog.tsx +8 -4
- package/src/channel/ConnectSlackDialog.tsx +14 -4
- package/src/channel/ConnectWhatsAppDialog.tsx +14 -4
- package/src/channel/useChannelSessions.ts +3 -0
- package/src/channel-app/ChannelAppDetailPanel.tsx +15 -12
- package/src/channel-app/CreateChannelAppForm.tsx +17 -12
- package/src/channel-app/internal.tsx +5 -25
- package/src/composer/ComposerToolbar.tsx +1 -1
- package/src/composer/SessionComposer.tsx +160 -13
- package/src/composer/__tests__/SessionComposer-modelCoherence.test.tsx +220 -0
- package/src/composer/__tests__/SessionComposer-visionPreflight.test.tsx +222 -0
- package/src/composer/icons.tsx +0 -18
- package/src/conversation/ConversationComposer.tsx +1 -1
- package/src/conversation/ConversationListPane.tsx +4 -3
- package/src/cursor-accounts/MemberCoverageTable.tsx +3 -14
- package/src/cursor-accounts/__tests__/CursorAccountsConsole.test.tsx +2 -10
- package/src/dashboard/DashboardFailedRuns.tsx +2 -12
- package/src/environment/CreateEnvironmentForm.tsx +8 -27
- package/src/environment/EnvVarForm.tsx +2 -18
- package/src/environment/EnvironmentVariableEditor.tsx +5 -21
- package/src/execution/ArtifactApplyButton.tsx +2 -17
- package/src/execution/ExecutionErrorNotice.tsx +99 -0
- package/src/execution/FilePathLink.tsx +5 -9
- package/src/execution/FileReviewCard.tsx +1 -20
- package/src/execution/FollowUpInput.tsx +1 -16
- package/src/execution/LivenessStatusLine.tsx +59 -0
- package/src/execution/MessageEntry.tsx +136 -25
- package/src/execution/MessageThread.tsx +84 -83
- package/src/execution/SetupProgress.tsx +5 -1
- package/src/execution/SubAgentSection.tsx +9 -20
- package/src/execution/TerminalSession.tsx +97 -10
- package/src/execution/ToolCallDetail.tsx +19 -0
- package/src/execution/ToolCallItem.tsx +157 -37
- package/src/execution/ToolRunGroup.tsx +30 -32
- package/src/execution/WriteBackCard.tsx +5 -24
- package/src/execution/__tests__/MessageEntry-copy.test.tsx +125 -0
- package/src/execution/__tests__/MessageThread.test.tsx +97 -0
- package/src/execution/__tests__/TerminalSession.test.tsx +71 -1
- package/src/execution/__tests__/ToolCallDetail.test.tsx +33 -1
- package/src/execution/__tests__/ToolCallItem.test.tsx +299 -11
- package/src/execution/__tests__/ToolRunGroup.test.tsx +41 -9
- package/src/execution/__tests__/message-thread-slots.test.tsx +92 -0
- package/src/execution/__tests__/tool-presenter.test.tsx +41 -4
- package/src/execution/index.ts +8 -2
- package/src/execution/tool-categories.ts +72 -8
- package/src/execution/tool-presenter.ts +22 -1
- package/src/execution/useArtifactInspection.ts +4 -8
- package/src/iam-policy/GrantAccessForm.tsx +2 -18
- package/src/iam-policy/OrgMembersPanel.tsx +3 -19
- package/src/iam-policy/RoleSelector.tsx +8 -1
- package/src/identity-provider/CreateIdentityProviderForm.tsx +13 -31
- package/src/identity-provider/IdentityProviderDetailPanel.tsx +24 -49
- package/src/identity-provider/IdentityProviderListPanel.tsx +2 -18
- package/src/identity-provider/IdentityProviderWizard.tsx +15 -32
- package/src/identity-provider/SsoLoginPrompt.tsx +6 -21
- package/src/index.ts +23 -1
- package/src/internal/DecisionButton.tsx +1 -20
- package/src/internal/SpinnerIcon.tsx +42 -0
- package/src/internal/__tests__/ThreadCardShell.test.tsx +43 -7
- package/src/internal/__tests__/useCopyFeedback.test.ts +92 -0
- package/src/internal/select-element-text.ts +17 -0
- package/src/internal/thread-card/ThreadCardShell.tsx +53 -21
- package/src/internal/thread-card/glyphs.tsx +24 -3
- package/src/internal/thread-card/index.ts +1 -0
- package/src/internal/useCopyFeedback.ts +61 -0
- package/src/invitation/InvitationCreatedAlert.tsx +10 -18
- package/src/invitation/InvitationManager.tsx +23 -34
- package/src/invitation/InvitationRedemption.tsx +2 -18
- package/src/library/useExportResource.ts +15 -29
- package/src/manifest/ApplyManifestDialog.tsx +1 -1
- package/src/manifest/EditResourceYamlDialog.tsx +1 -1
- package/src/mcp-server/DefinitionDriftNotice.tsx +120 -0
- package/src/mcp-server/McpServerConnectDialog.tsx +1 -1
- package/src/mcp-server/McpServerDetailView.tsx +58 -26
- package/src/mcp-server/OAuthAppForm.tsx +2 -18
- package/src/mcp-server/__tests__/DefinitionDriftNotice.test.tsx +57 -0
- package/src/mcp-server/__tests__/definitionDrift.test.ts +245 -0
- package/src/mcp-server/__tests__/mcpServerToInput.test.ts +201 -0
- package/src/mcp-server/__tests__/useMcpServerDefinitionDrift.test.tsx +173 -0
- package/src/mcp-server/internal/definitionDrift.ts +158 -0
- package/src/mcp-server/internal/mcpServerToInput.ts +3 -0
- package/src/mcp-server/steps/EnvironmentAuthStep.tsx +19 -19
- package/src/mcp-server/steps/IdentityTransportStep.tsx +24 -23
- package/src/mcp-server/useMcpServerConnect.ts +1 -1
- package/src/mcp-server/useMcpServerDefinitionDrift.ts +95 -0
- package/src/models/ModelRegistryContext.ts +7 -1
- package/src/models/ModelSelector.tsx +37 -0
- package/src/models/__tests__/ModelSelector-visionIndicator.test.tsx +129 -0
- package/src/models/__tests__/resolveDefaultModel.test.ts +115 -0
- package/src/models/__tests__/useModelRegistry.test.tsx +99 -4
- package/src/models/index.ts +2 -2
- package/src/models/registry.ts +196 -29
- package/src/models/useModelRegistry.ts +10 -2
- package/src/oauth-app/CreateOAuthAppForm.tsx +16 -31
- package/src/oauth-app/OAuthAppDetailPanel.tsx +16 -31
- package/src/organization/CreateOrganizationForm.tsx +10 -29
- package/src/organization/OrgProfilePanel.tsx +13 -44
- package/src/platform-client/CreatePlatformClientForm.tsx +9 -29
- package/src/platform-client/PlatformClientDetailPanel.tsx +10 -30
- package/src/platform-client/PlatformClientListPanel.tsx +2 -18
- package/src/platform-client/PlatformClientSecretAlert.tsx +26 -55
- package/src/provider.tsx +76 -33
- package/src/resource-creation/WizardNav.tsx +2 -18
- package/src/resource-detail/ConfirmDialog.tsx +1 -1
- package/src/resource-detail/useCopyResource.ts +17 -23
- package/src/schedule/ScheduleDetailView.tsx +2 -18
- package/src/schedule/ScheduleForm.tsx +19 -34
- package/src/session/NewSessionViewer.tsx +85 -7
- package/src/session/SessionViewer.tsx +120 -17
- package/src/session/__tests__/audienceWiring.test.tsx +76 -0
- package/src/session/__tests__/panelNegotiation.test.tsx +302 -0
- package/src/session/__tests__/useNewSessionFlow.test.tsx +134 -5
- package/src/session/__tests__/useSessionPageFlow.autoApprove.test.tsx +74 -0
- package/src/session/__tests__/useSessionPageFlow.runConfig.test.tsx +157 -0
- package/src/session/__tests__/useSessionPanel.test.ts +114 -0
- package/src/session/audience.ts +18 -0
- package/src/session/index.ts +2 -1
- package/src/session/run-config.ts +59 -0
- package/src/session/useNewSessionFlow.ts +39 -2
- package/src/session/useSessionConversation.ts +10 -8
- package/src/session/useSessionPageFlow.ts +51 -10
- package/src/session/useSessionPanel.ts +91 -10
- package/src/settings/ApiKeysSection.tsx +4 -3
- package/src/settings/ChannelAppsSection.tsx +4 -3
- package/src/settings/EnvironmentsSection.tsx +8 -5
- package/src/settings/IdentityProvidersSection.tsx +4 -3
- package/src/settings/InvitationsSection.tsx +4 -2
- package/src/settings/MembersSection.tsx +4 -2
- package/src/settings/OAuthAppsSection.tsx +4 -3
- package/src/settings/OrgProfileSection.tsx +4 -3
- package/src/settings/PlatformClientsSection.tsx +4 -3
- package/src/settings/UsageSection.tsx +4 -2
- package/src/sharing/ShareAgentDialog.tsx +28 -10
- package/src/sidebar/__tests__/WorkspaceSidebar.test.tsx +4 -1
- package/src/sidebar/chrome.tsx +6 -6
- package/src/skill/SkillDiffDialog.tsx +1 -1
- package/src/styles.css +43 -0
- package/src/version-history/VersionTimelineEntry.tsx +1 -21
- package/src/workflow/FailedRunsWidget.tsx +2 -9
- package/src/workflow/PendingApprovalsWidget.tsx +2 -9
- package/src/workflow/ViewYamlDialog.tsx +7 -22
- package/src/workflow/WorkflowArchitectDialog.tsx +8 -27
- package/src/workflow/WorkflowArtifactDocument.tsx +5 -9
- package/src/workflow/WorkflowCanvasEditor.tsx +2 -0
- package/src/workflow/WorkflowCanvasInner.tsx +14 -1
- package/src/workflow/WorkflowDiffGraph.tsx +7 -1
- package/src/workflow/WorkflowExecutionViewer.tsx +88 -11
- package/src/workflow/WorkflowExplainDialog.tsx +8 -24
- package/src/workflow/WorkflowOverviewGraph.tsx +9 -1
- package/src/workflow/WorkflowRefinePanel.tsx +2 -18
- package/src/workflow/WorkflowRepairCard.tsx +2 -18
- package/src/workflow/WorkflowRunDialog.tsx +3 -23
- package/src/workflow/WorkflowTaskApprovalSummary.tsx +2 -17
- package/src/workflow/WorkflowVersionBadge.tsx +4 -13
- package/src/workflow/WorkflowVersionTimeline.tsx +1 -25
- package/src/workflow/__tests__/panelNegotiation.test.tsx +230 -0
- package/src/workflow/__tests__/useWorkflowCanvas.dirty.test.tsx +178 -0
- package/src/workflow/__tests__/useWorkflowCanvas.drag.test.tsx +224 -0
- package/src/workflow/__tests__/useWorkflowExecutionPanel.test.ts +100 -0
- package/src/workflow/execution-comparison/ExecutionComparisonPicker.tsx +7 -11
- package/src/workflow/execution-history/ExecutionHistoryTable.tsx +1 -25
- package/src/workflow/index.ts +1 -0
- package/src/workflow/instance/CreateWorkflowInstanceDialog.tsx +1 -1
- package/src/workflow/instance/WorkflowInstanceDetailPanel.tsx +2 -1
- package/src/workflow/picker/BranchAddPopover.tsx +4 -3
- package/src/workflow/templates/WorkflowTemplatePreview.tsx +1 -1
- package/src/workflow/useApprovalBoundary.ts +1 -1
- package/src/workflow/useWorkflowCanvas.ts +114 -11
- package/src/workflow/useWorkflowExecutionPanel.ts +95 -13
- package/styles.css +1 -1
- package/version-history/VersionTimelineEntry.d.ts.map +1 -1
- package/version-history/VersionTimelineEntry.js +1 -23
- package/version-history/VersionTimelineEntry.js.map +1 -1
- package/workflow/CanvasTransitionEdge.d.ts +1 -1
- package/workflow/FailedRunsWidget.d.ts.map +1 -1
- package/workflow/FailedRunsWidget.js +2 -11
- package/workflow/FailedRunsWidget.js.map +1 -1
- package/workflow/PendingApprovalsWidget.d.ts.map +1 -1
- package/workflow/PendingApprovalsWidget.js +2 -11
- package/workflow/PendingApprovalsWidget.js.map +1 -1
- package/workflow/ViewYamlDialog.d.ts.map +1 -1
- package/workflow/ViewYamlDialog.js +7 -23
- package/workflow/ViewYamlDialog.js.map +1 -1
- package/workflow/WorkflowArchitectDialog.d.ts.map +1 -1
- package/workflow/WorkflowArchitectDialog.js +7 -11
- package/workflow/WorkflowArchitectDialog.js.map +1 -1
- package/workflow/WorkflowArtifactDocument.d.ts.map +1 -1
- package/workflow/WorkflowArtifactDocument.js +5 -8
- package/workflow/WorkflowArtifactDocument.js.map +1 -1
- package/workflow/WorkflowCanvasEditor.d.ts.map +1 -1
- package/workflow/WorkflowCanvasEditor.js +1 -1
- package/workflow/WorkflowCanvasEditor.js.map +1 -1
- package/workflow/WorkflowCanvasInner.d.ts +4 -2
- package/workflow/WorkflowCanvasInner.d.ts.map +1 -1
- package/workflow/WorkflowCanvasInner.js +7 -3
- package/workflow/WorkflowCanvasInner.js.map +1 -1
- package/workflow/WorkflowDiffGraph.js +6 -2
- package/workflow/WorkflowDiffGraph.js.map +1 -1
- package/workflow/WorkflowExecutionViewer.d.ts +51 -0
- package/workflow/WorkflowExecutionViewer.d.ts.map +1 -1
- package/workflow/WorkflowExecutionViewer.js +23 -6
- package/workflow/WorkflowExecutionViewer.js.map +1 -1
- package/workflow/WorkflowExplainDialog.d.ts.map +1 -1
- package/workflow/WorkflowExplainDialog.js +6 -8
- package/workflow/WorkflowExplainDialog.js.map +1 -1
- package/workflow/WorkflowOverviewGraph.js +8 -2
- package/workflow/WorkflowOverviewGraph.js.map +1 -1
- package/workflow/WorkflowRefinePanel.d.ts.map +1 -1
- package/workflow/WorkflowRefinePanel.js +2 -4
- package/workflow/WorkflowRefinePanel.js.map +1 -1
- package/workflow/WorkflowRepairCard.d.ts.map +1 -1
- package/workflow/WorkflowRepairCard.js +2 -4
- package/workflow/WorkflowRepairCard.js.map +1 -1
- package/workflow/WorkflowRunDialog.d.ts.map +1 -1
- package/workflow/WorkflowRunDialog.js +2 -7
- package/workflow/WorkflowRunDialog.js.map +1 -1
- package/workflow/WorkflowTaskApprovalSummary.d.ts.map +1 -1
- package/workflow/WorkflowTaskApprovalSummary.js +2 -4
- package/workflow/WorkflowTaskApprovalSummary.js.map +1 -1
- package/workflow/WorkflowVersionBadge.d.ts.map +1 -1
- package/workflow/WorkflowVersionBadge.js +4 -13
- package/workflow/WorkflowVersionBadge.js.map +1 -1
- package/workflow/WorkflowVersionTimeline.d.ts.map +1 -1
- package/workflow/WorkflowVersionTimeline.js +1 -26
- package/workflow/WorkflowVersionTimeline.js.map +1 -1
- package/workflow/execution-comparison/ExecutionComparisonPicker.d.ts.map +1 -1
- package/workflow/execution-comparison/ExecutionComparisonPicker.js +7 -15
- package/workflow/execution-comparison/ExecutionComparisonPicker.js.map +1 -1
- package/workflow/execution-history/ExecutionHistoryTable.d.ts.map +1 -1
- package/workflow/execution-history/ExecutionHistoryTable.js +1 -24
- package/workflow/execution-history/ExecutionHistoryTable.js.map +1 -1
- package/workflow/index.d.ts +1 -1
- package/workflow/index.d.ts.map +1 -1
- package/workflow/index.js.map +1 -1
- package/workflow/instance/CreateWorkflowInstanceDialog.js +1 -1
- package/workflow/instance/WorkflowInstanceDetailPanel.d.ts.map +1 -1
- package/workflow/instance/WorkflowInstanceDetailPanel.js +1 -1
- package/workflow/instance/WorkflowInstanceDetailPanel.js.map +1 -1
- package/workflow/picker/BranchAddPopover.d.ts.map +1 -1
- package/workflow/picker/BranchAddPopover.js +3 -2
- package/workflow/picker/BranchAddPopover.js.map +1 -1
- package/workflow/templates/WorkflowTemplatePreview.js +1 -1
- package/workflow/useApprovalBoundary.d.ts +1 -1
- package/workflow/useApprovalBoundary.js +1 -1
- package/workflow/useWorkflowCanvas.d.ts +5 -1
- package/workflow/useWorkflowCanvas.d.ts.map +1 -1
- package/workflow/useWorkflowCanvas.js +99 -13
- package/workflow/useWorkflowCanvas.js.map +1 -1
- package/workflow/useWorkflowExecutionPanel.d.ts +38 -2
- package/workflow/useWorkflowExecutionPanel.d.ts.map +1 -1
- package/workflow/useWorkflowExecutionPanel.js +46 -13
- package/workflow/useWorkflowExecutionPanel.js.map +1 -1
|
@@ -7,9 +7,14 @@ import { useComposer } from "./useComposer.js";
|
|
|
7
7
|
import { ComposerToolbar } from "./ComposerToolbar.js";
|
|
8
8
|
import { type ConfigureMenuItem } from "./ConfigureMenu.js";
|
|
9
9
|
import type { HarnessOption } from "../models/harness.js";
|
|
10
|
-
import type
|
|
10
|
+
import { FAST_SERVICE_TIER, type ServiceTierOption } from "../models/service-tier.js";
|
|
11
11
|
import type { InteractionModeOption } from "./InteractionModePicker.js";
|
|
12
12
|
import { parseModelKey } from "../models/registry.js";
|
|
13
|
+
import { useModelRegistry } from "../models/useModelRegistry.js";
|
|
14
|
+
import {
|
|
15
|
+
assessVisionPreflight,
|
|
16
|
+
visionPreflightMessage,
|
|
17
|
+
} from "../attachment/vision-preflight.js";
|
|
13
18
|
import { WorkspaceEditor } from "../workspace/WorkspaceEditor.js";
|
|
14
19
|
import { AgentPicker } from "../agent/AgentPicker.js";
|
|
15
20
|
import { AgentEnvForm, type AgentEnvFormSubmitOptions } from "../agent/AgentEnvForm.js";
|
|
@@ -654,9 +659,23 @@ const SessionComposerInner = forwardRef<SessionComposerHandle, SessionComposerPr
|
|
|
654
659
|
|
|
655
660
|
// Service tier (#357): composer-local state like modelId. "standard" is
|
|
656
661
|
// the resting default; the ModelSelector's fail-safe resets it when the
|
|
657
|
-
// user switches to a model without a fast tier.
|
|
662
|
+
// user switches to a model without a fast tier. Whether an armed "fast"
|
|
663
|
+
// actually rides the submit is decided by the derived effective run
|
|
664
|
+
// selection below (#663) — state here records the user's intent only.
|
|
658
665
|
const [serviceTier, setServiceTier] = useState<ServiceTierOption>("standard");
|
|
659
666
|
|
|
667
|
+
// Active harness mirror: controlled hosts (both viewers) keep the
|
|
668
|
+
// `harness` prop current, but with `showHarnessSelector` the dropdown
|
|
669
|
+
// lives inside ModelSelector and an uncontrolled host would leave the
|
|
670
|
+
// prop stale — the mirror keeps the effective-model resolution scoped
|
|
671
|
+
// to the harness the picker is actually showing.
|
|
672
|
+
const [activeHarness, setActiveHarness] = useState<HarnessOption>(
|
|
673
|
+
harness ?? "native",
|
|
674
|
+
);
|
|
675
|
+
useEffect(() => {
|
|
676
|
+
if (harness !== undefined) setActiveHarness(harness);
|
|
677
|
+
}, [harness]);
|
|
678
|
+
|
|
660
679
|
const [displayNames, setDisplayNames] = useState<Map<string, string>>(
|
|
661
680
|
() => new Map(),
|
|
662
681
|
);
|
|
@@ -753,6 +772,107 @@ const SessionComposerInner = forwardRef<SessionComposerHandle, SessionComposerPr
|
|
|
753
772
|
? { onValidationError: onAttachmentValidationError }
|
|
754
773
|
: undefined,
|
|
755
774
|
);
|
|
775
|
+
|
|
776
|
+
// -------------------------------------------------------------------------
|
|
777
|
+
// Vision preflight (stigmer/stigmer#365, #386) — predicts which attached
|
|
778
|
+
// images the runner will degrade to "not viewable inline" (per-image /
|
|
779
|
+
// per-turn byte budget from the registry document) or that the selected
|
|
780
|
+
// model is explicitly blind. Non-blocking by design: the files still
|
|
781
|
+
// upload and mount fine, they just won't reach the model as pixels — so
|
|
782
|
+
// this warns, it never gates the send.
|
|
783
|
+
// -------------------------------------------------------------------------
|
|
784
|
+
|
|
785
|
+
const {
|
|
786
|
+
getByKey: registryGetByKey,
|
|
787
|
+
getModel: registryGetModel,
|
|
788
|
+
visionLimits,
|
|
789
|
+
isLoading: isRegistryLoading,
|
|
790
|
+
} = useModelRegistry();
|
|
791
|
+
const { defaultModel: harnessDefaultModel } = useModelRegistry({
|
|
792
|
+
harness: activeHarness,
|
|
793
|
+
});
|
|
794
|
+
|
|
795
|
+
// -------------------------------------------------------------------------
|
|
796
|
+
// Effective run selection (stigmer/stigmer#663) — the ONE resolution of
|
|
797
|
+
// "which model and tier will this send actually run". The model pill,
|
|
798
|
+
// the fast-tier gate, the vision preflight, and the submit payload all
|
|
799
|
+
// read it, so the pill can never promise a selection the wire doesn't
|
|
800
|
+
// carry (the #663 failure: a fallback pill with an armed fast tier over
|
|
801
|
+
// an empty model — refused fail-closed at create).
|
|
802
|
+
//
|
|
803
|
+
// Adoption of the harness default is gated on `showModelSelector`: with
|
|
804
|
+
// no pill there is no displayed promise, and whoever hid the picker owns
|
|
805
|
+
// the model (the guest share profile server-side, a host pin) — the
|
|
806
|
+
// guest no-modelName invariant depends on this gate staying put.
|
|
807
|
+
// -------------------------------------------------------------------------
|
|
808
|
+
|
|
809
|
+
const effective = useMemo(() => {
|
|
810
|
+
// modelId may be a compound "harness/id" key (unified picker) or a
|
|
811
|
+
// plain id — resolve through the unambiguous compound lookup first,
|
|
812
|
+
// mirroring the submit path's parseModelKey handling.
|
|
813
|
+
const stateModel = modelId
|
|
814
|
+
? (registryGetByKey(modelId) ?? registryGetModel(modelId))
|
|
815
|
+
: undefined;
|
|
816
|
+
|
|
817
|
+
let effectiveModelId = modelId;
|
|
818
|
+
let effectiveModel = stateModel;
|
|
819
|
+
if (showModelSelector && !isRegistryLoading && stateModel === undefined) {
|
|
820
|
+
// Empty state, or an id the registry no longer lists (e.g. a retired
|
|
821
|
+
// model carried over from the last execution): the pill falls back to
|
|
822
|
+
// the harness default, so the submission adopts it too. While the
|
|
823
|
+
// registry is still loading nothing can be classified — pass the raw
|
|
824
|
+
// id through unmodified rather than misadopting the default.
|
|
825
|
+
effectiveModelId = harnessDefaultModel?.modelId ?? modelId;
|
|
826
|
+
effectiveModel = harnessDefaultModel;
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
// "fast" rides the submit only while the effective model prices the
|
|
830
|
+
// variant — the same rule the trigger badge renders and the server
|
|
831
|
+
// enforces fail-closed (#357). An armed tier surviving onto a model
|
|
832
|
+
// with no fast variant (e.g. a prop-driven `defaultModelId` re-sync,
|
|
833
|
+
// which bypasses ModelSelector's user-pick reset) is thereby
|
|
834
|
+
// unsendable, not just unstyled.
|
|
835
|
+
const effectiveServiceTier: ServiceTierOption =
|
|
836
|
+
serviceTier === "fast"
|
|
837
|
+
&& (effectiveModel?.serviceTiers.includes(FAST_SERVICE_TIER) ?? false)
|
|
838
|
+
? "fast"
|
|
839
|
+
: "standard";
|
|
840
|
+
|
|
841
|
+
return { modelId: effectiveModelId, model: effectiveModel, serviceTier: effectiveServiceTier };
|
|
842
|
+
}, [
|
|
843
|
+
modelId,
|
|
844
|
+
serviceTier,
|
|
845
|
+
showModelSelector,
|
|
846
|
+
isRegistryLoading,
|
|
847
|
+
registryGetByKey,
|
|
848
|
+
registryGetModel,
|
|
849
|
+
harnessDefaultModel,
|
|
850
|
+
]);
|
|
851
|
+
|
|
852
|
+
// Vision preflight consumes the effective model — previously it kept a
|
|
853
|
+
// third private resolution (unified-registry default) that could name a
|
|
854
|
+
// different model than both the pill and the payload.
|
|
855
|
+
const visionNotice = useMemo(() => {
|
|
856
|
+
if (!enableAttachments || attachments.entries.length === 0) return null;
|
|
857
|
+
const preflight = assessVisionPreflight(
|
|
858
|
+
attachments.entries.map((e) => ({
|
|
859
|
+
name: e.file.name,
|
|
860
|
+
sizeBytes: e.file.size,
|
|
861
|
+
contentType: e.contentType,
|
|
862
|
+
})),
|
|
863
|
+
{ model: effective.model, limits: visionLimits },
|
|
864
|
+
);
|
|
865
|
+
return visionPreflightMessage(preflight, {
|
|
866
|
+
limits: visionLimits,
|
|
867
|
+
modelDisplayName: effective.model?.displayName,
|
|
868
|
+
});
|
|
869
|
+
}, [
|
|
870
|
+
enableAttachments,
|
|
871
|
+
attachments.entries,
|
|
872
|
+
effective.model,
|
|
873
|
+
visionLimits,
|
|
874
|
+
]);
|
|
875
|
+
|
|
756
876
|
const fileRefs = useFileReferences();
|
|
757
877
|
const fileInputRef = useRef<HTMLInputElement>(null);
|
|
758
878
|
const [isDragOver, setIsDragOver] = useState(false);
|
|
@@ -923,27 +1043,32 @@ const SessionComposerInner = forwardRef<SessionComposerHandle, SessionComposerPr
|
|
|
923
1043
|
: undefined);
|
|
924
1044
|
const hasFileRefs = enableFileReferences && fileRefs.hasRefs;
|
|
925
1045
|
const buildFromPlan = overrides?.buildFromPlan;
|
|
926
|
-
// Carried only when
|
|
927
|
-
//
|
|
928
|
-
//
|
|
929
|
-
//
|
|
930
|
-
|
|
1046
|
+
// Carried only when fast is actually in effect (armed by the user
|
|
1047
|
+
// AND priced by the effective model — see the effective run
|
|
1048
|
+
// selection): an untouched tier means "platform default" (which
|
|
1049
|
+
// resolves to standard in the runner), and the UNSPECIFIED-vs-
|
|
1050
|
+
// explicit distinction is load-bearing telemetry (#357).
|
|
1051
|
+
const submitServiceTier =
|
|
1052
|
+
effective.serviceTier === "fast" ? effective.serviceTier : undefined;
|
|
931
1053
|
|
|
932
1054
|
const context: SessionComposerSubmitContext | undefined =
|
|
933
1055
|
hasEnv || hasAttachments || effectiveMode || hasFileRefs || buildFromPlan
|
|
934
|
-
||
|
|
1056
|
+
|| submitServiceTier
|
|
935
1057
|
? {
|
|
936
1058
|
runtimeEnv: hasEnv ? env : undefined,
|
|
937
1059
|
attachments: hasAttachments ? attachmentInputs : undefined,
|
|
938
1060
|
interactionMode: effectiveMode,
|
|
939
|
-
serviceTier:
|
|
1061
|
+
serviceTier: submitServiceTier,
|
|
940
1062
|
workspaceFileRefs: hasFileRefs ? [...fileRefs.refs] : undefined,
|
|
941
1063
|
buildFromPlan,
|
|
942
1064
|
}
|
|
943
1065
|
: undefined;
|
|
944
1066
|
|
|
945
|
-
|
|
946
|
-
|
|
1067
|
+
// The payload carries the effective model — exactly what the pill
|
|
1068
|
+
// displays (#663), stripped to a plain id when the state holds a
|
|
1069
|
+
// compound "harness/id" key.
|
|
1070
|
+
const resolvedModelId = effective.modelId
|
|
1071
|
+
? (parseModelKey(effective.modelId)?.modelId ?? effective.modelId)
|
|
947
1072
|
: undefined;
|
|
948
1073
|
onSubmit(message, resolvedModelId, context);
|
|
949
1074
|
|
|
@@ -954,7 +1079,7 @@ const SessionComposerInner = forwardRef<SessionComposerHandle, SessionComposerPr
|
|
|
954
1079
|
fileRefs.clear();
|
|
955
1080
|
}
|
|
956
1081
|
},
|
|
957
|
-
[onSubmit,
|
|
1082
|
+
[onSubmit, effective, stigmer, agentSetup.state, mcpSetup.pendingRuntimeEnv, sessionVariables, enableAttachments, attachments, personalEnv, showInteractionModePicker, interactionMode],
|
|
958
1083
|
);
|
|
959
1084
|
|
|
960
1085
|
const composer = useComposer({
|
|
@@ -982,6 +1107,7 @@ const SessionComposerInner = forwardRef<SessionComposerHandle, SessionComposerPr
|
|
|
982
1107
|
|
|
983
1108
|
const handleHarnessChange = useCallback(
|
|
984
1109
|
(h: HarnessOption) => {
|
|
1110
|
+
setActiveHarness(h);
|
|
985
1111
|
onHarnessChange?.(h);
|
|
986
1112
|
},
|
|
987
1113
|
[onHarnessChange],
|
|
@@ -1636,6 +1762,25 @@ const SessionComposerInner = forwardRef<SessionComposerHandle, SessionComposerPr
|
|
|
1636
1762
|
</div>
|
|
1637
1763
|
)}
|
|
1638
1764
|
|
|
1765
|
+
{/* Zone 2.65: Vision preflight warning (stigmer/stigmer#365, #386) —
|
|
1766
|
+
derives from the attached entries, so it appears the moment an
|
|
1767
|
+
image over the advertised budget lands (paste/drop/pick) or the
|
|
1768
|
+
selected model is explicitly blind, and disappears when the
|
|
1769
|
+
offending attachment is removed or the model changes. Warning
|
|
1770
|
+
styling (not muted): unlike the upload wait, this is a problem
|
|
1771
|
+
the user can fix BEFORE spending the turn. Non-blocking — the
|
|
1772
|
+
files still upload and mount; they just won't reach the model
|
|
1773
|
+
as pixels. */}
|
|
1774
|
+
{visionNotice && (
|
|
1775
|
+
<div
|
|
1776
|
+
role="status"
|
|
1777
|
+
className="stg:mx-3 stg:mb-2 stg:flex stg:items-center stg:gap-2 stg:rounded-md stg:bg-warning/10 stg:px-2.5 stg:py-1.5 stg:text-xs stg:text-warning"
|
|
1778
|
+
>
|
|
1779
|
+
<AlertTriangleIcon />
|
|
1780
|
+
<span>{visionNotice}</span>
|
|
1781
|
+
</div>
|
|
1782
|
+
)}
|
|
1783
|
+
|
|
1639
1784
|
{/* Zone 2.7: Agent setup warning */}
|
|
1640
1785
|
{showAgent &&
|
|
1641
1786
|
agentSetup.state.status === "needsEnvVars" &&
|
|
@@ -1734,7 +1879,9 @@ const SessionComposerInner = forwardRef<SessionComposerHandle, SessionComposerPr
|
|
|
1734
1879
|
interactionMode={interactionMode}
|
|
1735
1880
|
onInteractionModeChange={handleInteractionModeChange}
|
|
1736
1881
|
showModelSelector={showModelSelector}
|
|
1737
|
-
|
|
1882
|
+
// The pill renders the effective selection — the same value the
|
|
1883
|
+
// submit payload carries (#663), never a fallback of its own.
|
|
1884
|
+
modelId={effective.modelId}
|
|
1738
1885
|
onModelChange={handleModelChange}
|
|
1739
1886
|
serviceTier={serviceTier}
|
|
1740
1887
|
onServiceTierChange={setServiceTier}
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { describe, it, expect, vi, afterEach, beforeAll } from "vitest";
|
|
2
|
+
import { render, screen, cleanup, fireEvent, waitFor } from "@testing-library/react";
|
|
3
|
+
import { type ReactNode } from "react";
|
|
4
|
+
import type { Stigmer } from "@stigmer/sdk";
|
|
5
|
+
import { StigmerContext } from "../../context";
|
|
6
|
+
import { ModelRegistryContext } from "../../models/ModelRegistryContext";
|
|
7
|
+
import type { ModelInfo } from "../../models/registry";
|
|
8
|
+
import { SessionComposer } from "../SessionComposer";
|
|
9
|
+
|
|
10
|
+
// Shim ResizeObserver for Base UI's positioner (the
|
|
11
|
+
// scheduleCreation.test.tsx pattern).
|
|
12
|
+
beforeAll(() => {
|
|
13
|
+
if (!("ResizeObserver" in globalThis)) {
|
|
14
|
+
(globalThis as unknown as { ResizeObserver: unknown }).ResizeObserver =
|
|
15
|
+
class {
|
|
16
|
+
observe() {}
|
|
17
|
+
unobserve() {}
|
|
18
|
+
disconnect() {}
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Effective run selection coherence (stigmer/stigmer#663): the submission
|
|
25
|
+
* must carry exactly the model the pill displays, and "fast" must only
|
|
26
|
+
* ride the wire while the effective model prices it. The original defect:
|
|
27
|
+
* an empty composer displayed the registry fallback with a toggleable
|
|
28
|
+
* FAST badge, then sent `service_tier: fast` with NO model — refused
|
|
29
|
+
* fail-closed by the server ("Couldn't send." + a Retry that can never
|
|
30
|
+
* succeed).
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
const AUTO: ModelInfo = {
|
|
34
|
+
modelId: "default",
|
|
35
|
+
provider: "cursor",
|
|
36
|
+
displayName: "Auto",
|
|
37
|
+
shortDescription: "Automatic model selection",
|
|
38
|
+
speedTier: "fast",
|
|
39
|
+
costTier: "standard",
|
|
40
|
+
harness: "cursor",
|
|
41
|
+
featured: true,
|
|
42
|
+
serviceTiers: [],
|
|
43
|
+
};
|
|
44
|
+
|
|
45
|
+
const FAST_CAPABLE: ModelInfo = {
|
|
46
|
+
modelId: "composer-2.5",
|
|
47
|
+
provider: "cursor",
|
|
48
|
+
displayName: "Composer 2.5",
|
|
49
|
+
shortDescription: "Fast agentic model",
|
|
50
|
+
speedTier: "fastest",
|
|
51
|
+
costTier: "economy",
|
|
52
|
+
harness: "cursor",
|
|
53
|
+
featured: true,
|
|
54
|
+
serviceTiers: ["fast"],
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
const NO_FAST: ModelInfo = {
|
|
58
|
+
modelId: "gpt-5.3-codex",
|
|
59
|
+
provider: "openai",
|
|
60
|
+
displayName: "GPT-5.3 Codex",
|
|
61
|
+
shortDescription: "No fast variant",
|
|
62
|
+
speedTier: "fast",
|
|
63
|
+
costTier: "standard",
|
|
64
|
+
harness: "cursor",
|
|
65
|
+
featured: true,
|
|
66
|
+
serviceTiers: [],
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
function createMinimalStigmerMock(): Stigmer {
|
|
70
|
+
return {
|
|
71
|
+
agentExecution: { uploadAttachment: vi.fn() },
|
|
72
|
+
environment: { getPersonal: vi.fn().mockResolvedValue(null) },
|
|
73
|
+
baseUrl: "http://localhost:8080",
|
|
74
|
+
getAuthCredential: vi.fn().mockResolvedValue("test-token"),
|
|
75
|
+
config: {
|
|
76
|
+
baseUrl: "http://localhost:8080",
|
|
77
|
+
getAccessToken: vi.fn().mockResolvedValue(""),
|
|
78
|
+
},
|
|
79
|
+
} as unknown as Stigmer;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function createWrapper(
|
|
83
|
+
client: Stigmer,
|
|
84
|
+
registry: { models: readonly ModelInfo[]; isLoading?: boolean },
|
|
85
|
+
) {
|
|
86
|
+
return function Wrapper({ children }: { children: ReactNode }) {
|
|
87
|
+
return (
|
|
88
|
+
<StigmerContext.Provider value={client}>
|
|
89
|
+
<ModelRegistryContext.Provider
|
|
90
|
+
value={{
|
|
91
|
+
models: [...registry.models],
|
|
92
|
+
isLoading: registry.isLoading ?? false,
|
|
93
|
+
error: null,
|
|
94
|
+
refetch: vi.fn(),
|
|
95
|
+
}}
|
|
96
|
+
>
|
|
97
|
+
{children}
|
|
98
|
+
</ModelRegistryContext.Provider>
|
|
99
|
+
</StigmerContext.Provider>
|
|
100
|
+
);
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
function submitMessage(message: string) {
|
|
105
|
+
const textarea = screen.getByRole("textbox");
|
|
106
|
+
fireEvent.change(textarea, { target: { value: message } });
|
|
107
|
+
fireEvent.keyDown(textarea, { key: "Enter", shiftKey: false });
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** Open the picker and flip the fast-tier switch (Base UI portals mount
|
|
111
|
+
* asynchronously in jsdom — the switch is awaited). */
|
|
112
|
+
async function toggleFastTier(triggerName: RegExp) {
|
|
113
|
+
fireEvent.click(screen.getByRole("button", { name: triggerName }));
|
|
114
|
+
const toggle = await screen.findByRole("switch", { name: "Fast tier" });
|
|
115
|
+
fireEvent.click(toggle);
|
|
116
|
+
fireEvent.keyDown(document.activeElement ?? document.body, { key: "Escape" });
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
afterEach(cleanup);
|
|
120
|
+
|
|
121
|
+
describe("SessionComposer — effective run selection (#663)", () => {
|
|
122
|
+
it("adopts the displayed harness default when no model is selected", async () => {
|
|
123
|
+
const onSubmit = vi.fn();
|
|
124
|
+
render(
|
|
125
|
+
<SessionComposer onSubmit={onSubmit} harness="cursor" />,
|
|
126
|
+
{ wrapper: createWrapper(createMinimalStigmerMock(), { models: [FAST_CAPABLE, AUTO, NO_FAST] }) },
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
// The pill displays the harness default (Auto for cursor)…
|
|
130
|
+
expect(screen.getByRole("button", { name: /Auto/ })).toBeTruthy();
|
|
131
|
+
|
|
132
|
+
submitMessage("hello");
|
|
133
|
+
|
|
134
|
+
// …and the submission carries exactly that model, never undefined.
|
|
135
|
+
await waitFor(() => expect(onSubmit).toHaveBeenCalledOnce());
|
|
136
|
+
expect(onSubmit.mock.calls[0][1]).toBe("default");
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it("renders no fast-tier switch for a fresh cursor composer (Auto has no tier dimension)", async () => {
|
|
140
|
+
render(
|
|
141
|
+
<SessionComposer onSubmit={vi.fn()} harness="cursor" />,
|
|
142
|
+
{ wrapper: createWrapper(createMinimalStigmerMock(), { models: [FAST_CAPABLE, AUTO, NO_FAST] }) },
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
fireEvent.click(screen.getByRole("button", { name: /Auto/ }));
|
|
146
|
+
// Popover content mounts async; settle on the options area appearing.
|
|
147
|
+
await screen.findByRole("dialog");
|
|
148
|
+
expect(screen.queryByRole("switch", { name: "Fast tier" })).toBeNull();
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
it("drops an armed fast tier when a prop-driven model change lands on a model without a fast variant", async () => {
|
|
152
|
+
const onSubmit = vi.fn();
|
|
153
|
+
const wrapper = createWrapper(createMinimalStigmerMock(), {
|
|
154
|
+
models: [FAST_CAPABLE, AUTO, NO_FAST],
|
|
155
|
+
});
|
|
156
|
+
const { rerender } = render(
|
|
157
|
+
<SessionComposer onSubmit={onSubmit} harness="cursor" defaultModelId="composer-2.5" />,
|
|
158
|
+
{ wrapper },
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
// Arm fast on the fast-capable model (user-driven), then let the host
|
|
162
|
+
// re-sync `defaultModelId` onto a model with no fast variant — the
|
|
163
|
+
// path that bypasses ModelSelector's user-pick reset.
|
|
164
|
+
await toggleFastTier(/Composer 2\.5/);
|
|
165
|
+
rerender(
|
|
166
|
+
<SessionComposer onSubmit={onSubmit} harness="cursor" defaultModelId="gpt-5.3-codex" />,
|
|
167
|
+
);
|
|
168
|
+
|
|
169
|
+
submitMessage("resynced");
|
|
170
|
+
|
|
171
|
+
await waitFor(() => expect(onSubmit).toHaveBeenCalledOnce());
|
|
172
|
+
expect(onSubmit.mock.calls[0][1]).toBe("gpt-5.3-codex");
|
|
173
|
+
// The armed tier is unsendable, not just unstyled (#357 fail-closed rule).
|
|
174
|
+
expect(onSubmit.mock.calls[0][2]?.serviceTier).toBeUndefined();
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
it("never adopts a default while the model selector is hidden (the hider owns the model)", async () => {
|
|
178
|
+
const onSubmit = vi.fn();
|
|
179
|
+
render(
|
|
180
|
+
<SessionComposer onSubmit={onSubmit} harness="cursor" showModelSelector={false} />,
|
|
181
|
+
{ wrapper: createWrapper(createMinimalStigmerMock(), { models: [FAST_CAPABLE, AUTO, NO_FAST] }) },
|
|
182
|
+
);
|
|
183
|
+
|
|
184
|
+
submitMessage("guest-shaped send");
|
|
185
|
+
|
|
186
|
+
// No pill, no promise: guests' server-side profile (and #664 pins)
|
|
187
|
+
// own the model — the composer must not invent one.
|
|
188
|
+
await waitFor(() => expect(onSubmit).toHaveBeenCalledOnce());
|
|
189
|
+
expect(onSubmit.mock.calls[0][1]).toBeUndefined();
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
it("adopts the displayed default over a model id the registry no longer lists", async () => {
|
|
193
|
+
const onSubmit = vi.fn();
|
|
194
|
+
render(
|
|
195
|
+
<SessionComposer onSubmit={onSubmit} harness="cursor" defaultModelId="retired-model" />,
|
|
196
|
+
{ wrapper: createWrapper(createMinimalStigmerMock(), { models: [FAST_CAPABLE, AUTO, NO_FAST] }) },
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
submitMessage("stale id");
|
|
200
|
+
|
|
201
|
+
// The pill cannot display "retired-model" (unknown → falls back to the
|
|
202
|
+
// harness default), so the payload must not carry it either.
|
|
203
|
+
await waitFor(() => expect(onSubmit).toHaveBeenCalledOnce());
|
|
204
|
+
expect(onSubmit.mock.calls[0][1]).toBe("default");
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
it("passes the raw model id through while the registry is still loading", async () => {
|
|
208
|
+
const onSubmit = vi.fn();
|
|
209
|
+
render(
|
|
210
|
+
<SessionComposer onSubmit={onSubmit} harness="cursor" defaultModelId="composer-2.5" />,
|
|
211
|
+
{ wrapper: createWrapper(createMinimalStigmerMock(), { models: [], isLoading: true }) },
|
|
212
|
+
);
|
|
213
|
+
|
|
214
|
+
submitMessage("early send");
|
|
215
|
+
|
|
216
|
+
// Nothing can be classified mid-load: adopt nothing, rewrite nothing.
|
|
217
|
+
await waitFor(() => expect(onSubmit).toHaveBeenCalledOnce());
|
|
218
|
+
expect(onSubmit.mock.calls[0][1]).toBe("composer-2.5");
|
|
219
|
+
});
|
|
220
|
+
});
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
import { describe, it, expect, vi, afterEach } from "vitest";
|
|
2
|
+
import { render, screen, cleanup, fireEvent, act } from "@testing-library/react";
|
|
3
|
+
import type { ReactNode } from "react";
|
|
4
|
+
import type { Stigmer } from "@stigmer/sdk";
|
|
5
|
+
import { StigmerContext } from "../../context";
|
|
6
|
+
import { ModelRegistryContext } from "../../models/ModelRegistryContext";
|
|
7
|
+
import type { ModelRegistryState } from "../../models/ModelRegistryContext";
|
|
8
|
+
import { parseRegistryDocument } from "../../models/registry";
|
|
9
|
+
import type { VisionLimits } from "../../models/registry";
|
|
10
|
+
import { SessionComposer } from "../SessionComposer";
|
|
11
|
+
|
|
12
|
+
// ---------------------------------------------------------------------------
|
|
13
|
+
// Helpers
|
|
14
|
+
// ---------------------------------------------------------------------------
|
|
15
|
+
|
|
16
|
+
/** The production budget the registry advertises (3 MiB / 4 MiB / 10). */
|
|
17
|
+
const LIMITS: VisionLimits = {
|
|
18
|
+
maxImageBytes: 3 * 1024 * 1024,
|
|
19
|
+
maxTotalBytes: 4 * 1024 * 1024,
|
|
20
|
+
maxImages: 10,
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Registry fixture routed through the REAL document parser so this test
|
|
25
|
+
* also breaks if the parse contract drifts. kimi-k3 mirrors the live
|
|
26
|
+
* registry's explicitly-blind cursor model.
|
|
27
|
+
*/
|
|
28
|
+
const REGISTRY_DOCUMENT = parseRegistryDocument({
|
|
29
|
+
limits: { vision: { ...LIMITS } },
|
|
30
|
+
models: [
|
|
31
|
+
{
|
|
32
|
+
id: "claude-sonnet-4.6",
|
|
33
|
+
displayName: "Claude Sonnet 4.6",
|
|
34
|
+
provider: "anthropic",
|
|
35
|
+
harness: "native",
|
|
36
|
+
costTier: "standard",
|
|
37
|
+
featured: true,
|
|
38
|
+
capabilities: { toolUse: true, vision: true, streaming: true, thinking: true, adaptiveThinking: false },
|
|
39
|
+
pricing: { inputPricePerMillion: 3, outputPricePerMillion: 15, cacheWritePricePerMillion: 3.75, cacheReadPricePerMillion: 0.3 },
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
id: "kimi-k3",
|
|
43
|
+
displayName: "Kimi K3",
|
|
44
|
+
provider: "moonshot",
|
|
45
|
+
harness: "cursor",
|
|
46
|
+
costTier: "economy",
|
|
47
|
+
featured: false,
|
|
48
|
+
capabilities: { toolUse: true, vision: false, streaming: true, thinking: false, adaptiveThinking: false },
|
|
49
|
+
pricing: { inputPricePerMillion: 1, outputPricePerMillion: 3, cacheWritePricePerMillion: 1, cacheReadPricePerMillion: 0.1 },
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
function createUploadMockClient(): Stigmer {
|
|
55
|
+
return {
|
|
56
|
+
agentExecution: {
|
|
57
|
+
uploadAttachment: vi.fn().mockResolvedValue({ storageKey: "attachments/test/file" }),
|
|
58
|
+
},
|
|
59
|
+
environment: { getPersonal: vi.fn().mockResolvedValue(null) },
|
|
60
|
+
baseUrl: "http://localhost:8080",
|
|
61
|
+
getAuthCredential: vi.fn().mockResolvedValue("test-token"),
|
|
62
|
+
config: {
|
|
63
|
+
baseUrl: "http://localhost:8080",
|
|
64
|
+
getAccessToken: vi.fn().mockResolvedValue(""),
|
|
65
|
+
},
|
|
66
|
+
} as unknown as Stigmer;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function createWrapper(registry?: Partial<ModelRegistryState>) {
|
|
70
|
+
const client = createUploadMockClient();
|
|
71
|
+
const state: ModelRegistryState = {
|
|
72
|
+
models: REGISTRY_DOCUMENT.models,
|
|
73
|
+
visionLimits: REGISTRY_DOCUMENT.visionLimits,
|
|
74
|
+
isLoading: false,
|
|
75
|
+
error: null,
|
|
76
|
+
refetch: vi.fn(),
|
|
77
|
+
...registry,
|
|
78
|
+
};
|
|
79
|
+
return function Wrapper({ children }: { children: ReactNode }) {
|
|
80
|
+
return (
|
|
81
|
+
<StigmerContext.Provider value={client}>
|
|
82
|
+
<ModelRegistryContext.Provider value={state}>
|
|
83
|
+
{children}
|
|
84
|
+
</ModelRegistryContext.Provider>
|
|
85
|
+
</StigmerContext.Provider>
|
|
86
|
+
);
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function pngFile(name: string, sizeBytes: number): File {
|
|
91
|
+
return new File([new Uint8Array(sizeBytes)], name, { type: "image/png" });
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function pasteFiles(textarea: Element, files: File[]) {
|
|
95
|
+
fireEvent.paste(textarea, {
|
|
96
|
+
clipboardData: {
|
|
97
|
+
files: files as unknown as FileList,
|
|
98
|
+
getData: () => "",
|
|
99
|
+
types: ["Files"],
|
|
100
|
+
},
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const OVERSIZED = Math.round(3.6 * 1024 * 1024);
|
|
105
|
+
const SMALL = 64 * 1024;
|
|
106
|
+
|
|
107
|
+
afterEach(cleanup);
|
|
108
|
+
|
|
109
|
+
// ---------------------------------------------------------------------------
|
|
110
|
+
// Tests
|
|
111
|
+
// ---------------------------------------------------------------------------
|
|
112
|
+
|
|
113
|
+
describe("SessionComposer — vision preflight notice (#365, #386)", () => {
|
|
114
|
+
it("warns at paste time when an image exceeds the advertised per-image cap", async () => {
|
|
115
|
+
render(<SessionComposer onSubmit={vi.fn()} />, { wrapper: createWrapper() });
|
|
116
|
+
const textarea = screen.getByRole("textbox");
|
|
117
|
+
|
|
118
|
+
await act(async () => {
|
|
119
|
+
pasteFiles(textarea, [pngFile("screenshot.png", OVERSIZED)]);
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
const notice = screen.getByText(
|
|
123
|
+
/screenshot\.png \(3\.6 MB\) exceeds the 3\.0 MB inline-image limit/,
|
|
124
|
+
);
|
|
125
|
+
expect(notice).toBeTruthy();
|
|
126
|
+
expect(notice.closest('[role="status"]')).toBeTruthy();
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it("stays silent for images within the budget", async () => {
|
|
130
|
+
render(<SessionComposer onSubmit={vi.fn()} />, { wrapper: createWrapper() });
|
|
131
|
+
const textarea = screen.getByRole("textbox");
|
|
132
|
+
|
|
133
|
+
await act(async () => {
|
|
134
|
+
pasteFiles(textarea, [pngFile("small.png", SMALL)]);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
expect(screen.queryByText(/inline-image/)).toBeNull();
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it("stays silent when the server advertises no limits (older server, tri-state)", async () => {
|
|
141
|
+
render(<SessionComposer onSubmit={vi.fn()} />, {
|
|
142
|
+
wrapper: createWrapper({ visionLimits: undefined }),
|
|
143
|
+
});
|
|
144
|
+
const textarea = screen.getByRole("textbox");
|
|
145
|
+
|
|
146
|
+
await act(async () => {
|
|
147
|
+
pasteFiles(textarea, [pngFile("huge.png", OVERSIZED)]);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
expect(screen.queryByText(/inline-image/)).toBeNull();
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it("clears the warning when the offending attachment is removed", async () => {
|
|
154
|
+
render(<SessionComposer onSubmit={vi.fn()} />, { wrapper: createWrapper() });
|
|
155
|
+
const textarea = screen.getByRole("textbox");
|
|
156
|
+
|
|
157
|
+
await act(async () => {
|
|
158
|
+
pasteFiles(textarea, [pngFile("screenshot.png", OVERSIZED)]);
|
|
159
|
+
});
|
|
160
|
+
expect(screen.getByText(/exceeds the 3\.0 MB inline-image limit/)).toBeTruthy();
|
|
161
|
+
|
|
162
|
+
const removeButton = screen.getByRole("button", { name: /remove screenshot\.png/i });
|
|
163
|
+
await act(async () => {
|
|
164
|
+
fireEvent.click(removeButton);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
expect(screen.queryByText(/inline-image/)).toBeNull();
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it("leads with the model when the selected model is explicitly blind", async () => {
|
|
171
|
+
render(
|
|
172
|
+
<SessionComposer onSubmit={vi.fn()} defaultModelId="cursor/kimi-k3" />,
|
|
173
|
+
{ wrapper: createWrapper() },
|
|
174
|
+
);
|
|
175
|
+
const textarea = screen.getByRole("textbox");
|
|
176
|
+
|
|
177
|
+
await act(async () => {
|
|
178
|
+
pasteFiles(textarea, [pngFile("tiny.png", SMALL)]);
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
expect(
|
|
182
|
+
screen.getByText(
|
|
183
|
+
"Kimi K3 can't view images — attached images will reach the agent as files only.",
|
|
184
|
+
),
|
|
185
|
+
).toBeTruthy();
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
it("never warns about non-image attachments on a blind model", async () => {
|
|
189
|
+
render(
|
|
190
|
+
<SessionComposer onSubmit={vi.fn()} defaultModelId="cursor/kimi-k3" />,
|
|
191
|
+
{ wrapper: createWrapper() },
|
|
192
|
+
);
|
|
193
|
+
const textarea = screen.getByRole("textbox");
|
|
194
|
+
|
|
195
|
+
await act(async () => {
|
|
196
|
+
pasteFiles(textarea, [
|
|
197
|
+
new File([new Uint8Array(SMALL)], "notes.pdf", { type: "application/pdf" }),
|
|
198
|
+
]);
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
expect(screen.queryByText(/can't view images/)).toBeNull();
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
it("does not gate the send — the warned message still submits with the attachment", async () => {
|
|
205
|
+
const onSubmit = vi.fn();
|
|
206
|
+
render(<SessionComposer onSubmit={onSubmit} />, { wrapper: createWrapper() });
|
|
207
|
+
const textarea = screen.getByRole("textbox");
|
|
208
|
+
|
|
209
|
+
await act(async () => {
|
|
210
|
+
pasteFiles(textarea, [pngFile("screenshot.png", OVERSIZED)]);
|
|
211
|
+
});
|
|
212
|
+
expect(screen.getByText(/exceeds the 3\.0 MB inline-image limit/)).toBeTruthy();
|
|
213
|
+
|
|
214
|
+
await act(async () => {
|
|
215
|
+
fireEvent.change(textarea, { target: { value: "look at this anyway" } });
|
|
216
|
+
fireEvent.keyDown(textarea, { key: "Enter", shiftKey: false });
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
expect(onSubmit).toHaveBeenCalledTimes(1);
|
|
220
|
+
expect(onSubmit.mock.calls[0][2]?.attachments).toHaveLength(1);
|
|
221
|
+
});
|
|
222
|
+
});
|