@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.
Files changed (658) hide show
  1. package/access/ManageAccessDialog.d.ts.map +1 -1
  2. package/access/ManageAccessDialog.js +7 -2
  3. package/access/ManageAccessDialog.js.map +1 -1
  4. package/activity/format-relative-time.d.ts +11 -9
  5. package/activity/format-relative-time.d.ts.map +1 -1
  6. package/activity/format-relative-time.js +11 -9
  7. package/activity/format-relative-time.js.map +1 -1
  8. package/agent/steps/CapabilitiesStep.js +5 -2
  9. package/agent/steps/CapabilitiesStep.js.map +1 -1
  10. package/agent/steps/IdentityStep.d.ts.map +1 -1
  11. package/agent/steps/IdentityStep.js +6 -5
  12. package/agent/steps/IdentityStep.js.map +1 -1
  13. package/agent-instance/CreateAgentInstanceDialog.d.ts.map +1 -1
  14. package/agent-instance/CreateAgentInstanceDialog.js +10 -2
  15. package/agent-instance/CreateAgentInstanceDialog.js.map +1 -1
  16. package/api-key/ApiKeyCreatedAlert.d.ts.map +1 -1
  17. package/api-key/ApiKeyCreatedAlert.js +12 -20
  18. package/api-key/ApiKeyCreatedAlert.js.map +1 -1
  19. package/api-key/ApiKeyListPanel.d.ts.map +1 -1
  20. package/api-key/ApiKeyListPanel.js +3 -23
  21. package/api-key/ApiKeyListPanel.js.map +1 -1
  22. package/api-key/CreateApiKeyForm.d.ts.map +1 -1
  23. package/api-key/CreateApiKeyForm.js +6 -10
  24. package/api-key/CreateApiKeyForm.js.map +1 -1
  25. package/approval-defaults-context.d.ts +47 -0
  26. package/approval-defaults-context.d.ts.map +1 -0
  27. package/approval-defaults-context.js +27 -0
  28. package/approval-defaults-context.js.map +1 -0
  29. package/attachment/index.d.ts +2 -0
  30. package/attachment/index.d.ts.map +1 -1
  31. package/attachment/index.js +1 -0
  32. package/attachment/index.js.map +1 -1
  33. package/attachment/vision-preflight.d.ts +113 -0
  34. package/attachment/vision-preflight.d.ts.map +1 -0
  35. package/attachment/vision-preflight.js +143 -0
  36. package/attachment/vision-preflight.js.map +1 -0
  37. package/billing/AutoRechargeCard.d.ts.map +1 -1
  38. package/billing/AutoRechargeCard.js +3 -2
  39. package/billing/AutoRechargeCard.js.map +1 -1
  40. package/billing/BillingSection.d.ts.map +1 -1
  41. package/billing/BillingSection.js +3 -2
  42. package/billing/BillingSection.js.map +1 -1
  43. package/channel/ChannelConversationsDialog.d.ts.map +1 -1
  44. package/channel/ChannelConversationsDialog.js +5 -4
  45. package/channel/ChannelConversationsDialog.js.map +1 -1
  46. package/channel/ChannelCredentialsDialog.d.ts.map +1 -1
  47. package/channel/ChannelCredentialsDialog.js +9 -4
  48. package/channel/ChannelCredentialsDialog.js.map +1 -1
  49. package/channel/ChannelTemplatesDialog.d.ts.map +1 -1
  50. package/channel/ChannelTemplatesDialog.js +5 -4
  51. package/channel/ChannelTemplatesDialog.js.map +1 -1
  52. package/channel/ConnectSlackDialog.d.ts.map +1 -1
  53. package/channel/ConnectSlackDialog.js +9 -4
  54. package/channel/ConnectSlackDialog.js.map +1 -1
  55. package/channel/ConnectWhatsAppDialog.d.ts.map +1 -1
  56. package/channel/ConnectWhatsAppDialog.js +9 -4
  57. package/channel/ConnectWhatsAppDialog.js.map +1 -1
  58. package/channel/useChannelSessions.d.ts.map +1 -1
  59. package/channel/useChannelSessions.js.map +1 -1
  60. package/channel-app/ChannelAppDetailPanel.d.ts.map +1 -1
  61. package/channel-app/ChannelAppDetailPanel.js +8 -5
  62. package/channel-app/ChannelAppDetailPanel.js.map +1 -1
  63. package/channel-app/CreateChannelAppForm.d.ts.map +1 -1
  64. package/channel-app/CreateChannelAppForm.js +12 -7
  65. package/channel-app/CreateChannelAppForm.js.map +1 -1
  66. package/channel-app/internal.d.ts +0 -1
  67. package/channel-app/internal.d.ts.map +1 -1
  68. package/channel-app/internal.js +5 -10
  69. package/channel-app/internal.js.map +1 -1
  70. package/composer/ComposerToolbar.js +2 -1
  71. package/composer/ComposerToolbar.js.map +1 -1
  72. package/composer/SessionComposer.d.ts +1 -1
  73. package/composer/SessionComposer.d.ts.map +1 -1
  74. package/composer/SessionComposer.js +120 -13
  75. package/composer/SessionComposer.js.map +1 -1
  76. package/composer/icons.d.ts +0 -1
  77. package/composer/icons.d.ts.map +1 -1
  78. package/composer/icons.js +0 -3
  79. package/composer/icons.js.map +1 -1
  80. package/conversation/ConversationComposer.js +1 -1
  81. package/conversation/ConversationComposer.js.map +1 -1
  82. package/conversation/ConversationListPane.d.ts.map +1 -1
  83. package/conversation/ConversationListPane.js +3 -2
  84. package/conversation/ConversationListPane.js.map +1 -1
  85. package/cursor-accounts/MemberCoverageTable.js +3 -14
  86. package/cursor-accounts/MemberCoverageTable.js.map +1 -1
  87. package/dashboard/DashboardFailedRuns.d.ts.map +1 -1
  88. package/dashboard/DashboardFailedRuns.js +2 -14
  89. package/dashboard/DashboardFailedRuns.js.map +1 -1
  90. package/environment/CreateEnvironmentForm.d.ts.map +1 -1
  91. package/environment/CreateEnvironmentForm.js +4 -8
  92. package/environment/CreateEnvironmentForm.js.map +1 -1
  93. package/environment/EnvVarForm.d.ts.map +1 -1
  94. package/environment/EnvVarForm.js +2 -4
  95. package/environment/EnvVarForm.js.map +1 -1
  96. package/environment/EnvironmentVariableEditor.d.ts.map +1 -1
  97. package/environment/EnvironmentVariableEditor.js +5 -7
  98. package/environment/EnvironmentVariableEditor.js.map +1 -1
  99. package/execution/ArtifactApplyButton.d.ts.map +1 -1
  100. package/execution/ArtifactApplyButton.js +2 -4
  101. package/execution/ArtifactApplyButton.js.map +1 -1
  102. package/execution/ExecutionErrorNotice.d.ts +36 -0
  103. package/execution/ExecutionErrorNotice.d.ts.map +1 -0
  104. package/execution/ExecutionErrorNotice.js +39 -0
  105. package/execution/ExecutionErrorNotice.js.map +1 -0
  106. package/execution/FilePathLink.d.ts.map +1 -1
  107. package/execution/FilePathLink.js +5 -8
  108. package/execution/FilePathLink.js.map +1 -1
  109. package/execution/FileReviewCard.d.ts.map +1 -1
  110. package/execution/FileReviewCard.js +1 -6
  111. package/execution/FileReviewCard.js.map +1 -1
  112. package/execution/FollowUpInput.d.ts.map +1 -1
  113. package/execution/FollowUpInput.js +1 -3
  114. package/execution/FollowUpInput.js.map +1 -1
  115. package/execution/LivenessStatusLine.d.ts +40 -0
  116. package/execution/LivenessStatusLine.d.ts.map +1 -0
  117. package/execution/LivenessStatusLine.js +34 -0
  118. package/execution/LivenessStatusLine.js.map +1 -0
  119. package/execution/MessageEntry.d.ts.map +1 -1
  120. package/execution/MessageEntry.js +31 -3
  121. package/execution/MessageEntry.js.map +1 -1
  122. package/execution/MessageThread.d.ts +25 -0
  123. package/execution/MessageThread.d.ts.map +1 -1
  124. package/execution/MessageThread.js +51 -36
  125. package/execution/MessageThread.js.map +1 -1
  126. package/execution/SetupProgress.d.ts.map +1 -1
  127. package/execution/SetupProgress.js +1 -1
  128. package/execution/SetupProgress.js.map +1 -1
  129. package/execution/SubAgentSection.d.ts.map +1 -1
  130. package/execution/SubAgentSection.js +9 -7
  131. package/execution/SubAgentSection.js.map +1 -1
  132. package/execution/TerminalSession.d.ts +30 -0
  133. package/execution/TerminalSession.d.ts.map +1 -1
  134. package/execution/TerminalSession.js +37 -1
  135. package/execution/TerminalSession.js.map +1 -1
  136. package/execution/ToolCallDetail.d.ts +9 -0
  137. package/execution/ToolCallDetail.d.ts.map +1 -1
  138. package/execution/ToolCallDetail.js +16 -0
  139. package/execution/ToolCallDetail.js.map +1 -1
  140. package/execution/ToolCallItem.d.ts +20 -6
  141. package/execution/ToolCallItem.d.ts.map +1 -1
  142. package/execution/ToolCallItem.js +102 -29
  143. package/execution/ToolCallItem.js.map +1 -1
  144. package/execution/ToolRunGroup.d.ts.map +1 -1
  145. package/execution/ToolRunGroup.js +11 -11
  146. package/execution/ToolRunGroup.js.map +1 -1
  147. package/execution/WriteBackCard.d.ts.map +1 -1
  148. package/execution/WriteBackCard.js +5 -20
  149. package/execution/WriteBackCard.js.map +1 -1
  150. package/execution/index.d.ts +6 -2
  151. package/execution/index.d.ts.map +1 -1
  152. package/execution/index.js +3 -1
  153. package/execution/index.js.map +1 -1
  154. package/execution/tool-categories.d.ts +42 -7
  155. package/execution/tool-categories.d.ts.map +1 -1
  156. package/execution/tool-categories.js +38 -4
  157. package/execution/tool-categories.js.map +1 -1
  158. package/execution/tool-presenter.d.ts +17 -1
  159. package/execution/tool-presenter.d.ts.map +1 -1
  160. package/execution/tool-presenter.js +4 -1
  161. package/execution/tool-presenter.js.map +1 -1
  162. package/execution/useArtifactInspection.d.ts.map +1 -1
  163. package/execution/useArtifactInspection.js +4 -7
  164. package/execution/useArtifactInspection.js.map +1 -1
  165. package/iam-policy/GrantAccessForm.d.ts.map +1 -1
  166. package/iam-policy/GrantAccessForm.js +2 -4
  167. package/iam-policy/GrantAccessForm.js.map +1 -1
  168. package/iam-policy/OrgMembersPanel.d.ts.map +1 -1
  169. package/iam-policy/OrgMembersPanel.js +3 -5
  170. package/iam-policy/OrgMembersPanel.js.map +1 -1
  171. package/iam-policy/RoleSelector.d.ts.map +1 -1
  172. package/iam-policy/RoleSelector.js +7 -1
  173. package/iam-policy/RoleSelector.js.map +1 -1
  174. package/identity-provider/CreateIdentityProviderForm.d.ts.map +1 -1
  175. package/identity-provider/CreateIdentityProviderForm.js +6 -9
  176. package/identity-provider/CreateIdentityProviderForm.js.map +1 -1
  177. package/identity-provider/IdentityProviderDetailPanel.d.ts.map +1 -1
  178. package/identity-provider/IdentityProviderDetailPanel.js +17 -26
  179. package/identity-provider/IdentityProviderDetailPanel.js.map +1 -1
  180. package/identity-provider/IdentityProviderListPanel.d.ts.map +1 -1
  181. package/identity-provider/IdentityProviderListPanel.js +2 -4
  182. package/identity-provider/IdentityProviderListPanel.js.map +1 -1
  183. package/identity-provider/IdentityProviderWizard.d.ts.map +1 -1
  184. package/identity-provider/IdentityProviderWizard.js +8 -7
  185. package/identity-provider/IdentityProviderWizard.js.map +1 -1
  186. package/identity-provider/SsoLoginPrompt.js +5 -6
  187. package/identity-provider/SsoLoginPrompt.js.map +1 -1
  188. package/index.d.ts +9 -8
  189. package/index.d.ts.map +1 -1
  190. package/index.js +4 -4
  191. package/index.js.map +1 -1
  192. package/internal/DecisionButton.d.ts.map +1 -1
  193. package/internal/DecisionButton.js +1 -6
  194. package/internal/DecisionButton.js.map +1 -1
  195. package/internal/SpinnerIcon.d.ts +22 -0
  196. package/internal/SpinnerIcon.d.ts.map +1 -0
  197. package/internal/SpinnerIcon.js +23 -0
  198. package/internal/SpinnerIcon.js.map +1 -0
  199. package/internal/select-element-text.d.ts +11 -0
  200. package/internal/select-element-text.d.ts.map +1 -0
  201. package/internal/select-element-text.js +19 -0
  202. package/internal/select-element-text.js.map +1 -0
  203. package/internal/thread-card/ThreadCardShell.d.ts +27 -10
  204. package/internal/thread-card/ThreadCardShell.d.ts.map +1 -1
  205. package/internal/thread-card/ThreadCardShell.js +11 -5
  206. package/internal/thread-card/ThreadCardShell.js.map +1 -1
  207. package/internal/thread-card/glyphs.d.ts +11 -2
  208. package/internal/thread-card/glyphs.d.ts.map +1 -1
  209. package/internal/thread-card/glyphs.js +9 -3
  210. package/internal/thread-card/glyphs.js.map +1 -1
  211. package/internal/thread-card/index.d.ts +1 -1
  212. package/internal/thread-card/index.d.ts.map +1 -1
  213. package/internal/thread-card/index.js.map +1 -1
  214. package/internal/useCopyFeedback.d.ts +28 -0
  215. package/internal/useCopyFeedback.d.ts.map +1 -0
  216. package/internal/useCopyFeedback.js +40 -0
  217. package/internal/useCopyFeedback.js.map +1 -0
  218. package/invitation/InvitationCreatedAlert.d.ts.map +1 -1
  219. package/invitation/InvitationCreatedAlert.js +12 -19
  220. package/invitation/InvitationCreatedAlert.js.map +1 -1
  221. package/invitation/InvitationManager.d.ts.map +1 -1
  222. package/invitation/InvitationManager.js +14 -21
  223. package/invitation/InvitationManager.js.map +1 -1
  224. package/invitation/InvitationRedemption.d.ts.map +1 -1
  225. package/invitation/InvitationRedemption.js +2 -4
  226. package/invitation/InvitationRedemption.js.map +1 -1
  227. package/library/useExportResource.d.ts.map +1 -1
  228. package/library/useExportResource.js +16 -27
  229. package/library/useExportResource.js.map +1 -1
  230. package/manifest/ApplyManifestDialog.js +1 -1
  231. package/manifest/EditResourceYamlDialog.js +1 -1
  232. package/mcp-server/DefinitionDriftNotice.d.ts +42 -0
  233. package/mcp-server/DefinitionDriftNotice.d.ts.map +1 -0
  234. package/mcp-server/DefinitionDriftNotice.js +52 -0
  235. package/mcp-server/DefinitionDriftNotice.js.map +1 -0
  236. package/mcp-server/McpServerConnectDialog.js +1 -1
  237. package/mcp-server/McpServerDetailView.d.ts.map +1 -1
  238. package/mcp-server/McpServerDetailView.js +47 -14
  239. package/mcp-server/McpServerDetailView.js.map +1 -1
  240. package/mcp-server/OAuthAppForm.d.ts.map +1 -1
  241. package/mcp-server/OAuthAppForm.js +2 -4
  242. package/mcp-server/OAuthAppForm.js.map +1 -1
  243. package/mcp-server/internal/definitionDrift.d.ts +39 -0
  244. package/mcp-server/internal/definitionDrift.d.ts.map +1 -0
  245. package/mcp-server/internal/definitionDrift.js +122 -0
  246. package/mcp-server/internal/definitionDrift.js.map +1 -0
  247. package/mcp-server/internal/mcpServerToInput.d.ts.map +1 -1
  248. package/mcp-server/internal/mcpServerToInput.js +3 -0
  249. package/mcp-server/internal/mcpServerToInput.js.map +1 -1
  250. package/mcp-server/steps/EnvironmentAuthStep.d.ts.map +1 -1
  251. package/mcp-server/steps/EnvironmentAuthStep.js +8 -4
  252. package/mcp-server/steps/EnvironmentAuthStep.js.map +1 -1
  253. package/mcp-server/steps/IdentityTransportStep.d.ts.map +1 -1
  254. package/mcp-server/steps/IdentityTransportStep.js +5 -4
  255. package/mcp-server/steps/IdentityTransportStep.js.map +1 -1
  256. package/mcp-server/useMcpServerConnect.d.ts +1 -1
  257. package/mcp-server/useMcpServerDefinitionDrift.d.ts +44 -0
  258. package/mcp-server/useMcpServerDefinitionDrift.d.ts.map +1 -0
  259. package/mcp-server/useMcpServerDefinitionDrift.js +61 -0
  260. package/mcp-server/useMcpServerDefinitionDrift.js.map +1 -0
  261. package/models/ModelRegistryContext.d.ts +7 -1
  262. package/models/ModelRegistryContext.d.ts.map +1 -1
  263. package/models/ModelRegistryContext.js.map +1 -1
  264. package/models/ModelSelector.js +9 -1
  265. package/models/ModelSelector.js.map +1 -1
  266. package/models/index.d.ts +2 -2
  267. package/models/index.d.ts.map +1 -1
  268. package/models/index.js +1 -1
  269. package/models/index.js.map +1 -1
  270. package/models/registry.d.ts +88 -6
  271. package/models/registry.d.ts.map +1 -1
  272. package/models/registry.js +133 -27
  273. package/models/registry.js.map +1 -1
  274. package/models/useModelRegistry.d.ts +7 -1
  275. package/models/useModelRegistry.d.ts.map +1 -1
  276. package/models/useModelRegistry.js +3 -2
  277. package/models/useModelRegistry.js.map +1 -1
  278. package/oauth-app/CreateOAuthAppForm.d.ts.map +1 -1
  279. package/oauth-app/CreateOAuthAppForm.js +4 -5
  280. package/oauth-app/CreateOAuthAppForm.js.map +1 -1
  281. package/oauth-app/OAuthAppDetailPanel.d.ts.map +1 -1
  282. package/oauth-app/OAuthAppDetailPanel.js +5 -6
  283. package/oauth-app/OAuthAppDetailPanel.js.map +1 -1
  284. package/organization/CreateOrganizationForm.d.ts.map +1 -1
  285. package/organization/CreateOrganizationForm.js +5 -9
  286. package/organization/CreateOrganizationForm.js.map +1 -1
  287. package/organization/OrgProfilePanel.d.ts.map +1 -1
  288. package/organization/OrgProfilePanel.js +7 -16
  289. package/organization/OrgProfilePanel.js.map +1 -1
  290. package/package.json +4 -4
  291. package/platform-client/CreatePlatformClientForm.d.ts.map +1 -1
  292. package/platform-client/CreatePlatformClientForm.js +5 -6
  293. package/platform-client/CreatePlatformClientForm.js.map +1 -1
  294. package/platform-client/PlatformClientDetailPanel.d.ts.map +1 -1
  295. package/platform-client/PlatformClientDetailPanel.js +6 -7
  296. package/platform-client/PlatformClientDetailPanel.js.map +1 -1
  297. package/platform-client/PlatformClientListPanel.d.ts.map +1 -1
  298. package/platform-client/PlatformClientListPanel.js +2 -4
  299. package/platform-client/PlatformClientListPanel.js.map +1 -1
  300. package/platform-client/PlatformClientSecretAlert.d.ts.map +1 -1
  301. package/platform-client/PlatformClientSecretAlert.js +18 -25
  302. package/platform-client/PlatformClientSecretAlert.js.map +1 -1
  303. package/provider.d.ts +34 -1
  304. package/provider.d.ts.map +1 -1
  305. package/provider.js +14 -7
  306. package/provider.js.map +1 -1
  307. package/resource-creation/WizardNav.d.ts.map +1 -1
  308. package/resource-creation/WizardNav.js +2 -4
  309. package/resource-creation/WizardNav.js.map +1 -1
  310. package/resource-detail/ConfirmDialog.js +1 -1
  311. package/resource-detail/useCopyResource.d.ts +4 -3
  312. package/resource-detail/useCopyResource.d.ts.map +1 -1
  313. package/resource-detail/useCopyResource.js +10 -19
  314. package/resource-detail/useCopyResource.js.map +1 -1
  315. package/schedule/ScheduleDetailView.d.ts.map +1 -1
  316. package/schedule/ScheduleDetailView.js +2 -4
  317. package/schedule/ScheduleDetailView.js.map +1 -1
  318. package/schedule/ScheduleForm.d.ts.map +1 -1
  319. package/schedule/ScheduleForm.js +6 -7
  320. package/schedule/ScheduleForm.js.map +1 -1
  321. package/session/NewSessionViewer.d.ts +52 -2
  322. package/session/NewSessionViewer.d.ts.map +1 -1
  323. package/session/NewSessionViewer.js +21 -6
  324. package/session/NewSessionViewer.js.map +1 -1
  325. package/session/SessionViewer.d.ts +63 -2
  326. package/session/SessionViewer.d.ts.map +1 -1
  327. package/session/SessionViewer.js +43 -17
  328. package/session/SessionViewer.js.map +1 -1
  329. package/session/audience.d.ts +17 -0
  330. package/session/audience.d.ts.map +1 -1
  331. package/session/index.d.ts +2 -1
  332. package/session/index.d.ts.map +1 -1
  333. package/session/index.js.map +1 -1
  334. package/session/run-config.d.ts +50 -0
  335. package/session/run-config.d.ts.map +1 -0
  336. package/session/run-config.js +15 -0
  337. package/session/run-config.js.map +1 -0
  338. package/session/useNewSessionFlow.d.ts +11 -0
  339. package/session/useNewSessionFlow.d.ts.map +1 -1
  340. package/session/useNewSessionFlow.js +29 -2
  341. package/session/useNewSessionFlow.js.map +1 -1
  342. package/session/useSessionConversation.d.ts +7 -7
  343. package/session/useSessionConversation.d.ts.map +1 -1
  344. package/session/useSessionConversation.js +2 -0
  345. package/session/useSessionConversation.js.map +1 -1
  346. package/session/useSessionPageFlow.d.ts +18 -4
  347. package/session/useSessionPageFlow.d.ts.map +1 -1
  348. package/session/useSessionPageFlow.js +33 -6
  349. package/session/useSessionPageFlow.js.map +1 -1
  350. package/session/useSessionPanel.d.ts +37 -2
  351. package/session/useSessionPanel.d.ts.map +1 -1
  352. package/session/useSessionPanel.js +44 -10
  353. package/session/useSessionPanel.js.map +1 -1
  354. package/settings/ApiKeysSection.d.ts.map +1 -1
  355. package/settings/ApiKeysSection.js +3 -2
  356. package/settings/ApiKeysSection.js.map +1 -1
  357. package/settings/ChannelAppsSection.d.ts.map +1 -1
  358. package/settings/ChannelAppsSection.js +3 -2
  359. package/settings/ChannelAppsSection.js.map +1 -1
  360. package/settings/EnvironmentsSection.js +5 -3
  361. package/settings/EnvironmentsSection.js.map +1 -1
  362. package/settings/IdentityProvidersSection.d.ts.map +1 -1
  363. package/settings/IdentityProvidersSection.js +3 -2
  364. package/settings/IdentityProvidersSection.js.map +1 -1
  365. package/settings/InvitationsSection.d.ts.map +1 -1
  366. package/settings/InvitationsSection.js +3 -1
  367. package/settings/InvitationsSection.js.map +1 -1
  368. package/settings/MembersSection.d.ts.map +1 -1
  369. package/settings/MembersSection.js +3 -1
  370. package/settings/MembersSection.js.map +1 -1
  371. package/settings/OAuthAppsSection.d.ts.map +1 -1
  372. package/settings/OAuthAppsSection.js +3 -2
  373. package/settings/OAuthAppsSection.js.map +1 -1
  374. package/settings/OrgProfileSection.d.ts.map +1 -1
  375. package/settings/OrgProfileSection.js +3 -2
  376. package/settings/OrgProfileSection.js.map +1 -1
  377. package/settings/PlatformClientsSection.d.ts.map +1 -1
  378. package/settings/PlatformClientsSection.js +3 -2
  379. package/settings/PlatformClientsSection.js.map +1 -1
  380. package/settings/UsageSection.d.ts.map +1 -1
  381. package/settings/UsageSection.js +3 -1
  382. package/settings/UsageSection.js.map +1 -1
  383. package/sharing/ShareAgentDialog.d.ts.map +1 -1
  384. package/sharing/ShareAgentDialog.js +18 -7
  385. package/sharing/ShareAgentDialog.js.map +1 -1
  386. package/sidebar/chrome.d.ts +3 -4
  387. package/sidebar/chrome.d.ts.map +1 -1
  388. package/sidebar/chrome.js +5 -4
  389. package/sidebar/chrome.js.map +1 -1
  390. package/skill/SkillDiffDialog.js +1 -1
  391. package/src/access/ManageAccessDialog.tsx +10 -4
  392. package/src/activity/format-relative-time.ts +11 -9
  393. package/src/agent/steps/CapabilitiesStep.tsx +6 -3
  394. package/src/agent/steps/IdentityStep.tsx +19 -12
  395. package/src/agent-instance/CreateAgentInstanceDialog.tsx +17 -8
  396. package/src/api-key/ApiKeyCreatedAlert.tsx +10 -19
  397. package/src/api-key/ApiKeyListPanel.tsx +3 -39
  398. package/src/api-key/CreateApiKeyForm.tsx +12 -26
  399. package/src/approval-defaults-context.ts +56 -0
  400. package/src/attachment/__tests__/vision-preflight.test.ts +311 -0
  401. package/src/attachment/index.ts +12 -0
  402. package/src/attachment/vision-preflight.ts +236 -0
  403. package/src/billing/AutoRechargeCard.tsx +5 -4
  404. package/src/billing/BillingSection.tsx +4 -3
  405. package/src/channel/ChannelConversationsDialog.tsx +8 -4
  406. package/src/channel/ChannelCredentialsDialog.tsx +14 -4
  407. package/src/channel/ChannelTemplatesDialog.tsx +8 -4
  408. package/src/channel/ConnectSlackDialog.tsx +14 -4
  409. package/src/channel/ConnectWhatsAppDialog.tsx +14 -4
  410. package/src/channel/useChannelSessions.ts +3 -0
  411. package/src/channel-app/ChannelAppDetailPanel.tsx +15 -12
  412. package/src/channel-app/CreateChannelAppForm.tsx +17 -12
  413. package/src/channel-app/internal.tsx +5 -25
  414. package/src/composer/ComposerToolbar.tsx +1 -1
  415. package/src/composer/SessionComposer.tsx +160 -13
  416. package/src/composer/__tests__/SessionComposer-modelCoherence.test.tsx +220 -0
  417. package/src/composer/__tests__/SessionComposer-visionPreflight.test.tsx +222 -0
  418. package/src/composer/icons.tsx +0 -18
  419. package/src/conversation/ConversationComposer.tsx +1 -1
  420. package/src/conversation/ConversationListPane.tsx +4 -3
  421. package/src/cursor-accounts/MemberCoverageTable.tsx +3 -14
  422. package/src/cursor-accounts/__tests__/CursorAccountsConsole.test.tsx +2 -10
  423. package/src/dashboard/DashboardFailedRuns.tsx +2 -12
  424. package/src/environment/CreateEnvironmentForm.tsx +8 -27
  425. package/src/environment/EnvVarForm.tsx +2 -18
  426. package/src/environment/EnvironmentVariableEditor.tsx +5 -21
  427. package/src/execution/ArtifactApplyButton.tsx +2 -17
  428. package/src/execution/ExecutionErrorNotice.tsx +99 -0
  429. package/src/execution/FilePathLink.tsx +5 -9
  430. package/src/execution/FileReviewCard.tsx +1 -20
  431. package/src/execution/FollowUpInput.tsx +1 -16
  432. package/src/execution/LivenessStatusLine.tsx +59 -0
  433. package/src/execution/MessageEntry.tsx +136 -25
  434. package/src/execution/MessageThread.tsx +84 -83
  435. package/src/execution/SetupProgress.tsx +5 -1
  436. package/src/execution/SubAgentSection.tsx +9 -20
  437. package/src/execution/TerminalSession.tsx +97 -10
  438. package/src/execution/ToolCallDetail.tsx +19 -0
  439. package/src/execution/ToolCallItem.tsx +157 -37
  440. package/src/execution/ToolRunGroup.tsx +30 -32
  441. package/src/execution/WriteBackCard.tsx +5 -24
  442. package/src/execution/__tests__/MessageEntry-copy.test.tsx +125 -0
  443. package/src/execution/__tests__/MessageThread.test.tsx +97 -0
  444. package/src/execution/__tests__/TerminalSession.test.tsx +71 -1
  445. package/src/execution/__tests__/ToolCallDetail.test.tsx +33 -1
  446. package/src/execution/__tests__/ToolCallItem.test.tsx +299 -11
  447. package/src/execution/__tests__/ToolRunGroup.test.tsx +41 -9
  448. package/src/execution/__tests__/message-thread-slots.test.tsx +92 -0
  449. package/src/execution/__tests__/tool-presenter.test.tsx +41 -4
  450. package/src/execution/index.ts +8 -2
  451. package/src/execution/tool-categories.ts +72 -8
  452. package/src/execution/tool-presenter.ts +22 -1
  453. package/src/execution/useArtifactInspection.ts +4 -8
  454. package/src/iam-policy/GrantAccessForm.tsx +2 -18
  455. package/src/iam-policy/OrgMembersPanel.tsx +3 -19
  456. package/src/iam-policy/RoleSelector.tsx +8 -1
  457. package/src/identity-provider/CreateIdentityProviderForm.tsx +13 -31
  458. package/src/identity-provider/IdentityProviderDetailPanel.tsx +24 -49
  459. package/src/identity-provider/IdentityProviderListPanel.tsx +2 -18
  460. package/src/identity-provider/IdentityProviderWizard.tsx +15 -32
  461. package/src/identity-provider/SsoLoginPrompt.tsx +6 -21
  462. package/src/index.ts +23 -1
  463. package/src/internal/DecisionButton.tsx +1 -20
  464. package/src/internal/SpinnerIcon.tsx +42 -0
  465. package/src/internal/__tests__/ThreadCardShell.test.tsx +43 -7
  466. package/src/internal/__tests__/useCopyFeedback.test.ts +92 -0
  467. package/src/internal/select-element-text.ts +17 -0
  468. package/src/internal/thread-card/ThreadCardShell.tsx +53 -21
  469. package/src/internal/thread-card/glyphs.tsx +24 -3
  470. package/src/internal/thread-card/index.ts +1 -0
  471. package/src/internal/useCopyFeedback.ts +61 -0
  472. package/src/invitation/InvitationCreatedAlert.tsx +10 -18
  473. package/src/invitation/InvitationManager.tsx +23 -34
  474. package/src/invitation/InvitationRedemption.tsx +2 -18
  475. package/src/library/useExportResource.ts +15 -29
  476. package/src/manifest/ApplyManifestDialog.tsx +1 -1
  477. package/src/manifest/EditResourceYamlDialog.tsx +1 -1
  478. package/src/mcp-server/DefinitionDriftNotice.tsx +120 -0
  479. package/src/mcp-server/McpServerConnectDialog.tsx +1 -1
  480. package/src/mcp-server/McpServerDetailView.tsx +58 -26
  481. package/src/mcp-server/OAuthAppForm.tsx +2 -18
  482. package/src/mcp-server/__tests__/DefinitionDriftNotice.test.tsx +57 -0
  483. package/src/mcp-server/__tests__/definitionDrift.test.ts +245 -0
  484. package/src/mcp-server/__tests__/mcpServerToInput.test.ts +201 -0
  485. package/src/mcp-server/__tests__/useMcpServerDefinitionDrift.test.tsx +173 -0
  486. package/src/mcp-server/internal/definitionDrift.ts +158 -0
  487. package/src/mcp-server/internal/mcpServerToInput.ts +3 -0
  488. package/src/mcp-server/steps/EnvironmentAuthStep.tsx +19 -19
  489. package/src/mcp-server/steps/IdentityTransportStep.tsx +24 -23
  490. package/src/mcp-server/useMcpServerConnect.ts +1 -1
  491. package/src/mcp-server/useMcpServerDefinitionDrift.ts +95 -0
  492. package/src/models/ModelRegistryContext.ts +7 -1
  493. package/src/models/ModelSelector.tsx +37 -0
  494. package/src/models/__tests__/ModelSelector-visionIndicator.test.tsx +129 -0
  495. package/src/models/__tests__/resolveDefaultModel.test.ts +115 -0
  496. package/src/models/__tests__/useModelRegistry.test.tsx +99 -4
  497. package/src/models/index.ts +2 -2
  498. package/src/models/registry.ts +196 -29
  499. package/src/models/useModelRegistry.ts +10 -2
  500. package/src/oauth-app/CreateOAuthAppForm.tsx +16 -31
  501. package/src/oauth-app/OAuthAppDetailPanel.tsx +16 -31
  502. package/src/organization/CreateOrganizationForm.tsx +10 -29
  503. package/src/organization/OrgProfilePanel.tsx +13 -44
  504. package/src/platform-client/CreatePlatformClientForm.tsx +9 -29
  505. package/src/platform-client/PlatformClientDetailPanel.tsx +10 -30
  506. package/src/platform-client/PlatformClientListPanel.tsx +2 -18
  507. package/src/platform-client/PlatformClientSecretAlert.tsx +26 -55
  508. package/src/provider.tsx +76 -33
  509. package/src/resource-creation/WizardNav.tsx +2 -18
  510. package/src/resource-detail/ConfirmDialog.tsx +1 -1
  511. package/src/resource-detail/useCopyResource.ts +17 -23
  512. package/src/schedule/ScheduleDetailView.tsx +2 -18
  513. package/src/schedule/ScheduleForm.tsx +19 -34
  514. package/src/session/NewSessionViewer.tsx +85 -7
  515. package/src/session/SessionViewer.tsx +120 -17
  516. package/src/session/__tests__/audienceWiring.test.tsx +76 -0
  517. package/src/session/__tests__/panelNegotiation.test.tsx +302 -0
  518. package/src/session/__tests__/useNewSessionFlow.test.tsx +134 -5
  519. package/src/session/__tests__/useSessionPageFlow.autoApprove.test.tsx +74 -0
  520. package/src/session/__tests__/useSessionPageFlow.runConfig.test.tsx +157 -0
  521. package/src/session/__tests__/useSessionPanel.test.ts +114 -0
  522. package/src/session/audience.ts +18 -0
  523. package/src/session/index.ts +2 -1
  524. package/src/session/run-config.ts +59 -0
  525. package/src/session/useNewSessionFlow.ts +39 -2
  526. package/src/session/useSessionConversation.ts +10 -8
  527. package/src/session/useSessionPageFlow.ts +51 -10
  528. package/src/session/useSessionPanel.ts +91 -10
  529. package/src/settings/ApiKeysSection.tsx +4 -3
  530. package/src/settings/ChannelAppsSection.tsx +4 -3
  531. package/src/settings/EnvironmentsSection.tsx +8 -5
  532. package/src/settings/IdentityProvidersSection.tsx +4 -3
  533. package/src/settings/InvitationsSection.tsx +4 -2
  534. package/src/settings/MembersSection.tsx +4 -2
  535. package/src/settings/OAuthAppsSection.tsx +4 -3
  536. package/src/settings/OrgProfileSection.tsx +4 -3
  537. package/src/settings/PlatformClientsSection.tsx +4 -3
  538. package/src/settings/UsageSection.tsx +4 -2
  539. package/src/sharing/ShareAgentDialog.tsx +28 -10
  540. package/src/sidebar/__tests__/WorkspaceSidebar.test.tsx +4 -1
  541. package/src/sidebar/chrome.tsx +6 -6
  542. package/src/skill/SkillDiffDialog.tsx +1 -1
  543. package/src/styles.css +43 -0
  544. package/src/version-history/VersionTimelineEntry.tsx +1 -21
  545. package/src/workflow/FailedRunsWidget.tsx +2 -9
  546. package/src/workflow/PendingApprovalsWidget.tsx +2 -9
  547. package/src/workflow/ViewYamlDialog.tsx +7 -22
  548. package/src/workflow/WorkflowArchitectDialog.tsx +8 -27
  549. package/src/workflow/WorkflowArtifactDocument.tsx +5 -9
  550. package/src/workflow/WorkflowCanvasEditor.tsx +2 -0
  551. package/src/workflow/WorkflowCanvasInner.tsx +14 -1
  552. package/src/workflow/WorkflowDiffGraph.tsx +7 -1
  553. package/src/workflow/WorkflowExecutionViewer.tsx +88 -11
  554. package/src/workflow/WorkflowExplainDialog.tsx +8 -24
  555. package/src/workflow/WorkflowOverviewGraph.tsx +9 -1
  556. package/src/workflow/WorkflowRefinePanel.tsx +2 -18
  557. package/src/workflow/WorkflowRepairCard.tsx +2 -18
  558. package/src/workflow/WorkflowRunDialog.tsx +3 -23
  559. package/src/workflow/WorkflowTaskApprovalSummary.tsx +2 -17
  560. package/src/workflow/WorkflowVersionBadge.tsx +4 -13
  561. package/src/workflow/WorkflowVersionTimeline.tsx +1 -25
  562. package/src/workflow/__tests__/panelNegotiation.test.tsx +230 -0
  563. package/src/workflow/__tests__/useWorkflowCanvas.dirty.test.tsx +178 -0
  564. package/src/workflow/__tests__/useWorkflowCanvas.drag.test.tsx +224 -0
  565. package/src/workflow/__tests__/useWorkflowExecutionPanel.test.ts +100 -0
  566. package/src/workflow/execution-comparison/ExecutionComparisonPicker.tsx +7 -11
  567. package/src/workflow/execution-history/ExecutionHistoryTable.tsx +1 -25
  568. package/src/workflow/index.ts +1 -0
  569. package/src/workflow/instance/CreateWorkflowInstanceDialog.tsx +1 -1
  570. package/src/workflow/instance/WorkflowInstanceDetailPanel.tsx +2 -1
  571. package/src/workflow/picker/BranchAddPopover.tsx +4 -3
  572. package/src/workflow/templates/WorkflowTemplatePreview.tsx +1 -1
  573. package/src/workflow/useApprovalBoundary.ts +1 -1
  574. package/src/workflow/useWorkflowCanvas.ts +114 -11
  575. package/src/workflow/useWorkflowExecutionPanel.ts +95 -13
  576. package/styles.css +1 -1
  577. package/version-history/VersionTimelineEntry.d.ts.map +1 -1
  578. package/version-history/VersionTimelineEntry.js +1 -23
  579. package/version-history/VersionTimelineEntry.js.map +1 -1
  580. package/workflow/CanvasTransitionEdge.d.ts +1 -1
  581. package/workflow/FailedRunsWidget.d.ts.map +1 -1
  582. package/workflow/FailedRunsWidget.js +2 -11
  583. package/workflow/FailedRunsWidget.js.map +1 -1
  584. package/workflow/PendingApprovalsWidget.d.ts.map +1 -1
  585. package/workflow/PendingApprovalsWidget.js +2 -11
  586. package/workflow/PendingApprovalsWidget.js.map +1 -1
  587. package/workflow/ViewYamlDialog.d.ts.map +1 -1
  588. package/workflow/ViewYamlDialog.js +7 -23
  589. package/workflow/ViewYamlDialog.js.map +1 -1
  590. package/workflow/WorkflowArchitectDialog.d.ts.map +1 -1
  591. package/workflow/WorkflowArchitectDialog.js +7 -11
  592. package/workflow/WorkflowArchitectDialog.js.map +1 -1
  593. package/workflow/WorkflowArtifactDocument.d.ts.map +1 -1
  594. package/workflow/WorkflowArtifactDocument.js +5 -8
  595. package/workflow/WorkflowArtifactDocument.js.map +1 -1
  596. package/workflow/WorkflowCanvasEditor.d.ts.map +1 -1
  597. package/workflow/WorkflowCanvasEditor.js +1 -1
  598. package/workflow/WorkflowCanvasEditor.js.map +1 -1
  599. package/workflow/WorkflowCanvasInner.d.ts +4 -2
  600. package/workflow/WorkflowCanvasInner.d.ts.map +1 -1
  601. package/workflow/WorkflowCanvasInner.js +7 -3
  602. package/workflow/WorkflowCanvasInner.js.map +1 -1
  603. package/workflow/WorkflowDiffGraph.js +6 -2
  604. package/workflow/WorkflowDiffGraph.js.map +1 -1
  605. package/workflow/WorkflowExecutionViewer.d.ts +51 -0
  606. package/workflow/WorkflowExecutionViewer.d.ts.map +1 -1
  607. package/workflow/WorkflowExecutionViewer.js +23 -6
  608. package/workflow/WorkflowExecutionViewer.js.map +1 -1
  609. package/workflow/WorkflowExplainDialog.d.ts.map +1 -1
  610. package/workflow/WorkflowExplainDialog.js +6 -8
  611. package/workflow/WorkflowExplainDialog.js.map +1 -1
  612. package/workflow/WorkflowOverviewGraph.js +8 -2
  613. package/workflow/WorkflowOverviewGraph.js.map +1 -1
  614. package/workflow/WorkflowRefinePanel.d.ts.map +1 -1
  615. package/workflow/WorkflowRefinePanel.js +2 -4
  616. package/workflow/WorkflowRefinePanel.js.map +1 -1
  617. package/workflow/WorkflowRepairCard.d.ts.map +1 -1
  618. package/workflow/WorkflowRepairCard.js +2 -4
  619. package/workflow/WorkflowRepairCard.js.map +1 -1
  620. package/workflow/WorkflowRunDialog.d.ts.map +1 -1
  621. package/workflow/WorkflowRunDialog.js +2 -7
  622. package/workflow/WorkflowRunDialog.js.map +1 -1
  623. package/workflow/WorkflowTaskApprovalSummary.d.ts.map +1 -1
  624. package/workflow/WorkflowTaskApprovalSummary.js +2 -4
  625. package/workflow/WorkflowTaskApprovalSummary.js.map +1 -1
  626. package/workflow/WorkflowVersionBadge.d.ts.map +1 -1
  627. package/workflow/WorkflowVersionBadge.js +4 -13
  628. package/workflow/WorkflowVersionBadge.js.map +1 -1
  629. package/workflow/WorkflowVersionTimeline.d.ts.map +1 -1
  630. package/workflow/WorkflowVersionTimeline.js +1 -26
  631. package/workflow/WorkflowVersionTimeline.js.map +1 -1
  632. package/workflow/execution-comparison/ExecutionComparisonPicker.d.ts.map +1 -1
  633. package/workflow/execution-comparison/ExecutionComparisonPicker.js +7 -15
  634. package/workflow/execution-comparison/ExecutionComparisonPicker.js.map +1 -1
  635. package/workflow/execution-history/ExecutionHistoryTable.d.ts.map +1 -1
  636. package/workflow/execution-history/ExecutionHistoryTable.js +1 -24
  637. package/workflow/execution-history/ExecutionHistoryTable.js.map +1 -1
  638. package/workflow/index.d.ts +1 -1
  639. package/workflow/index.d.ts.map +1 -1
  640. package/workflow/index.js.map +1 -1
  641. package/workflow/instance/CreateWorkflowInstanceDialog.js +1 -1
  642. package/workflow/instance/WorkflowInstanceDetailPanel.d.ts.map +1 -1
  643. package/workflow/instance/WorkflowInstanceDetailPanel.js +1 -1
  644. package/workflow/instance/WorkflowInstanceDetailPanel.js.map +1 -1
  645. package/workflow/picker/BranchAddPopover.d.ts.map +1 -1
  646. package/workflow/picker/BranchAddPopover.js +3 -2
  647. package/workflow/picker/BranchAddPopover.js.map +1 -1
  648. package/workflow/templates/WorkflowTemplatePreview.js +1 -1
  649. package/workflow/useApprovalBoundary.d.ts +1 -1
  650. package/workflow/useApprovalBoundary.js +1 -1
  651. package/workflow/useWorkflowCanvas.d.ts +5 -1
  652. package/workflow/useWorkflowCanvas.d.ts.map +1 -1
  653. package/workflow/useWorkflowCanvas.js +99 -13
  654. package/workflow/useWorkflowCanvas.js.map +1 -1
  655. package/workflow/useWorkflowExecutionPanel.d.ts +38 -2
  656. package/workflow/useWorkflowExecutionPanel.d.ts.map +1 -1
  657. package/workflow/useWorkflowExecutionPanel.js +46 -13
  658. 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 { ServiceTierOption } from "../models/service-tier.js";
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 the user actively chose fast: an untouched
927
- // tier means "platform default" (which resolves to standard in
928
- // the runner), and the UNSPECIFIED-vs-explicit distinction is
929
- // load-bearing telemetry (#357).
930
- const effectiveServiceTier = serviceTier === "fast" ? serviceTier : undefined;
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
- || effectiveServiceTier
1056
+ || submitServiceTier
935
1057
  ? {
936
1058
  runtimeEnv: hasEnv ? env : undefined,
937
1059
  attachments: hasAttachments ? attachmentInputs : undefined,
938
1060
  interactionMode: effectiveMode,
939
- serviceTier: effectiveServiceTier,
1061
+ serviceTier: submitServiceTier,
940
1062
  workspaceFileRefs: hasFileRefs ? [...fileRefs.refs] : undefined,
941
1063
  buildFromPlan,
942
1064
  }
943
1065
  : undefined;
944
1066
 
945
- const resolvedModelId = modelId
946
- ? (parseModelKey(modelId)?.modelId ?? modelId)
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, modelId, serviceTier, stigmer, agentSetup.state, mcpSetup.pendingRuntimeEnv, sessionVariables, enableAttachments, attachments, personalEnv, showInteractionModePicker, interactionMode],
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
- modelId={modelId}
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
+ });