@stigmer/react 3.12.4 → 3.12.6

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 (369) hide show
  1. package/agent/AgentDetailView.js +2 -2
  2. package/agent/AgentDetailView.js.map +1 -1
  3. package/agent/index.d.ts +0 -1
  4. package/agent/index.d.ts.map +1 -1
  5. package/agent/index.js +0 -1
  6. package/agent/index.js.map +1 -1
  7. package/agent/useUpdateAgent.d.ts +3 -3
  8. package/agent/useUpdateAgent.js +3 -3
  9. package/agent-instance/AgentInstanceDetailPanel.d.ts.map +1 -1
  10. package/agent-instance/AgentInstanceDetailPanel.js +5 -7
  11. package/agent-instance/AgentInstanceDetailPanel.js.map +1 -1
  12. package/agent-instance/useUpdateAgentInstance.d.ts +1 -1
  13. package/agent-instance/useUpdateAgentInstance.js +1 -1
  14. package/attachment/AttachmentChipList.js +16 -6
  15. package/attachment/AttachmentChipList.js.map +1 -1
  16. package/attachment/index.d.ts +1 -1
  17. package/attachment/index.d.ts.map +1 -1
  18. package/attachment/index.js.map +1 -1
  19. package/attachment/useAttachments.d.ts +51 -8
  20. package/attachment/useAttachments.d.ts.map +1 -1
  21. package/attachment/useAttachments.js +74 -3
  22. package/attachment/useAttachments.js.map +1 -1
  23. package/channel/AgentChannelsPanel.d.ts.map +1 -1
  24. package/channel/AgentChannelsPanel.js +10 -5
  25. package/channel/AgentChannelsPanel.js.map +1 -1
  26. package/channel/ChannelRunConfigDialog.d.ts +51 -0
  27. package/channel/ChannelRunConfigDialog.d.ts.map +1 -0
  28. package/channel/ChannelRunConfigDialog.js +121 -0
  29. package/channel/ChannelRunConfigDialog.js.map +1 -0
  30. package/channel/index.d.ts +2 -0
  31. package/channel/index.d.ts.map +1 -1
  32. package/channel/index.js +1 -0
  33. package/channel/index.js.map +1 -1
  34. package/channel/useSaveAgentChannel.d.ts.map +1 -1
  35. package/channel/useSaveAgentChannel.js +6 -3
  36. package/channel/useSaveAgentChannel.js.map +1 -1
  37. package/channel-app/ChannelAppDetailPanel.js +9 -9
  38. package/channel-app/ChannelAppDetailPanel.js.map +1 -1
  39. package/composer/ComposerToolbar.d.ts +6 -1
  40. package/composer/ComposerToolbar.d.ts.map +1 -1
  41. package/composer/ComposerToolbar.js +2 -2
  42. package/composer/ComposerToolbar.js.map +1 -1
  43. package/composer/SessionComposer.d.ts +9 -0
  44. package/composer/SessionComposer.d.ts.map +1 -1
  45. package/composer/SessionComposer.js +39 -13
  46. package/composer/SessionComposer.js.map +1 -1
  47. package/conversation/ConversationComposer.d.ts +19 -3
  48. package/conversation/ConversationComposer.d.ts.map +1 -1
  49. package/conversation/ConversationComposer.js +4 -4
  50. package/conversation/ConversationComposer.js.map +1 -1
  51. package/conversation/ConversationTemplatePickerDialog.d.ts +63 -0
  52. package/conversation/ConversationTemplatePickerDialog.d.ts.map +1 -0
  53. package/conversation/ConversationTemplatePickerDialog.js +151 -0
  54. package/conversation/ConversationTemplatePickerDialog.js.map +1 -0
  55. package/conversation/ConversationsWorkbench.d.ts.map +1 -1
  56. package/conversation/ConversationsWorkbench.js +16 -5
  57. package/conversation/ConversationsWorkbench.js.map +1 -1
  58. package/conversation/index.d.ts +3 -1
  59. package/conversation/index.d.ts.map +1 -1
  60. package/conversation/index.js +1 -0
  61. package/conversation/index.js.map +1 -1
  62. package/conversation/useConversationParticipation.d.ts +41 -4
  63. package/conversation/useConversationParticipation.d.ts.map +1 -1
  64. package/conversation/useConversationParticipation.js +13 -2
  65. package/conversation/useConversationParticipation.js.map +1 -1
  66. package/cursor-accounts/CursorAccountsConsole.d.ts.map +1 -1
  67. package/cursor-accounts/CursorAccountsConsole.js +12 -3
  68. package/cursor-accounts/CursorAccountsConsole.js.map +1 -1
  69. package/cursor-accounts/cursor-account-coverage.d.ts +30 -1
  70. package/cursor-accounts/cursor-account-coverage.d.ts.map +1 -1
  71. package/cursor-accounts/cursor-account-coverage.js +21 -0
  72. package/cursor-accounts/cursor-account-coverage.js.map +1 -1
  73. package/execution/useCreateAgentExecution.d.ts +15 -0
  74. package/execution/useCreateAgentExecution.d.ts.map +1 -1
  75. package/execution/useCreateAgentExecution.js +5 -0
  76. package/execution/useCreateAgentExecution.js.map +1 -1
  77. package/identity-account/AccountPreferencesPanel.d.ts +36 -0
  78. package/identity-account/AccountPreferencesPanel.d.ts.map +1 -0
  79. package/identity-account/AccountPreferencesPanel.js +202 -0
  80. package/identity-account/AccountPreferencesPanel.js.map +1 -0
  81. package/identity-account/index.d.ts +8 -0
  82. package/identity-account/index.d.ts.map +1 -1
  83. package/identity-account/index.js +4 -0
  84. package/identity-account/index.js.map +1 -1
  85. package/identity-account/useAccountExecutionDefaults.d.ts +36 -0
  86. package/identity-account/useAccountExecutionDefaults.d.ts.map +1 -0
  87. package/identity-account/useAccountExecutionDefaults.js +46 -0
  88. package/identity-account/useAccountExecutionDefaults.js.map +1 -0
  89. package/identity-account/useMyIdentityAccount.d.ts +55 -0
  90. package/identity-account/useMyIdentityAccount.d.ts.map +1 -0
  91. package/identity-account/useMyIdentityAccount.js +37 -0
  92. package/identity-account/useMyIdentityAccount.js.map +1 -0
  93. package/identity-account/useUpdateIdentityAccount.d.ts +42 -0
  94. package/identity-account/useUpdateIdentityAccount.d.ts.map +1 -0
  95. package/identity-account/useUpdateIdentityAccount.js +53 -0
  96. package/identity-account/useUpdateIdentityAccount.js.map +1 -0
  97. package/identity-provider/IdentityProviderDetailPanel.d.ts.map +1 -1
  98. package/identity-provider/IdentityProviderDetailPanel.js +16 -15
  99. package/identity-provider/IdentityProviderDetailPanel.js.map +1 -1
  100. package/index.d.ts +15 -13
  101. package/index.d.ts.map +1 -1
  102. package/index.js +11 -8
  103. package/index.js.map +1 -1
  104. package/internal/StandingContextField.d.ts +37 -0
  105. package/internal/StandingContextField.d.ts.map +1 -0
  106. package/internal/StandingContextField.js +24 -0
  107. package/internal/StandingContextField.js.map +1 -0
  108. package/library/InstanceVisibilitySelector.d.ts.map +1 -1
  109. package/library/InstanceVisibilitySelector.js +9 -2
  110. package/library/InstanceVisibilitySelector.js.map +1 -1
  111. package/library/ResourceVisibilityControl.d.ts +13 -3
  112. package/library/ResourceVisibilityControl.d.ts.map +1 -1
  113. package/library/ResourceVisibilityControl.js +33 -5
  114. package/library/ResourceVisibilityControl.js.map +1 -1
  115. package/library/VisibilityOptionRow.d.ts +6 -0
  116. package/library/VisibilityOptionRow.d.ts.map +1 -1
  117. package/library/VisibilityOptionRow.js +11 -1
  118. package/library/VisibilityOptionRow.js.map +1 -1
  119. package/library/VisibilitySelector.d.ts.map +1 -1
  120. package/library/VisibilitySelector.js +14 -2
  121. package/library/VisibilitySelector.js.map +1 -1
  122. package/library/index.d.ts +4 -2
  123. package/library/index.d.ts.map +1 -1
  124. package/library/index.js +2 -1
  125. package/library/index.js.map +1 -1
  126. package/library/useCanSetPublicVisibility.d.ts +30 -0
  127. package/library/useCanSetPublicVisibility.d.ts.map +1 -0
  128. package/library/useCanSetPublicVisibility.js +41 -0
  129. package/library/useCanSetPublicVisibility.js.map +1 -0
  130. package/library/visibilityLevels.d.ts +32 -1
  131. package/library/visibilityLevels.d.ts.map +1 -1
  132. package/library/visibilityLevels.js +34 -14
  133. package/library/visibilityLevels.js.map +1 -1
  134. package/mcp-server/McpServerDetailView.js +2 -2
  135. package/mcp-server/McpServerDetailView.js.map +1 -1
  136. package/mcp-server/index.d.ts +0 -1
  137. package/mcp-server/index.d.ts.map +1 -1
  138. package/mcp-server/index.js +0 -1
  139. package/mcp-server/index.js.map +1 -1
  140. package/mcp-server/internal/definitionDrift.d.ts +14 -12
  141. package/mcp-server/internal/definitionDrift.d.ts.map +1 -1
  142. package/mcp-server/internal/definitionDrift.js +22 -19
  143. package/mcp-server/internal/definitionDrift.js.map +1 -1
  144. package/mcp-server/useMcpServerConnect.d.ts +8 -5
  145. package/mcp-server/useMcpServerConnect.d.ts.map +1 -1
  146. package/mcp-server/useMcpServerConnect.js +2 -1
  147. package/mcp-server/useMcpServerConnect.js.map +1 -1
  148. package/mcp-server/useMcpServerOAuthConnect.d.ts.map +1 -1
  149. package/mcp-server/useMcpServerOAuthConnect.js +7 -2
  150. package/mcp-server/useMcpServerOAuthConnect.js.map +1 -1
  151. package/mcp-server/useUpdateMcpServer.d.ts +3 -3
  152. package/mcp-server/useUpdateMcpServer.js +3 -3
  153. package/models/ModelSelector.d.ts +33 -1
  154. package/models/ModelSelector.d.ts.map +1 -1
  155. package/models/ModelSelector.js +37 -4
  156. package/models/ModelSelector.js.map +1 -1
  157. package/models/index.d.ts +2 -0
  158. package/models/index.d.ts.map +1 -1
  159. package/models/index.js +1 -0
  160. package/models/index.js.map +1 -1
  161. package/models/registry.d.ts +16 -0
  162. package/models/registry.d.ts.map +1 -1
  163. package/models/registry.js +13 -0
  164. package/models/registry.js.map +1 -1
  165. package/models/thinking-mode.d.ts +27 -0
  166. package/models/thinking-mode.d.ts.map +1 -0
  167. package/models/thinking-mode.js +32 -0
  168. package/models/thinking-mode.js.map +1 -0
  169. package/oauth-app/CreateOAuthAppForm.d.ts +2 -2
  170. package/oauth-app/CreateOAuthAppForm.d.ts.map +1 -1
  171. package/oauth-app/CreateOAuthAppForm.js +13 -4
  172. package/oauth-app/CreateOAuthAppForm.js.map +1 -1
  173. package/oauth-app/OAuthAppDetailPanel.d.ts.map +1 -1
  174. package/oauth-app/OAuthAppDetailPanel.js +50 -22
  175. package/oauth-app/OAuthAppDetailPanel.js.map +1 -1
  176. package/organization/OrgPreferencesPanel.d.ts +32 -0
  177. package/organization/OrgPreferencesPanel.d.ts.map +1 -0
  178. package/organization/OrgPreferencesPanel.js +90 -0
  179. package/organization/OrgPreferencesPanel.js.map +1 -0
  180. package/organization/OrgProfilePanel.d.ts.map +1 -1
  181. package/organization/OrgProfilePanel.js +5 -4
  182. package/organization/OrgProfilePanel.js.map +1 -1
  183. package/organization/index.d.ts +2 -0
  184. package/organization/index.d.ts.map +1 -1
  185. package/organization/index.js +1 -0
  186. package/organization/index.js.map +1 -1
  187. package/package.json +4 -4
  188. package/platform-client/PlatformClientDetailPanel.d.ts.map +1 -1
  189. package/platform-client/PlatformClientDetailPanel.js +12 -13
  190. package/platform-client/PlatformClientDetailPanel.js.map +1 -1
  191. package/schedule/ScheduleDetailView.d.ts.map +1 -1
  192. package/schedule/ScheduleDetailView.js +21 -10
  193. package/schedule/ScheduleDetailView.js.map +1 -1
  194. package/schedule/ScheduleForm.d.ts.map +1 -1
  195. package/schedule/ScheduleForm.js +13 -3
  196. package/schedule/ScheduleForm.js.map +1 -1
  197. package/session/NewSessionViewer.d.ts +10 -1
  198. package/session/NewSessionViewer.d.ts.map +1 -1
  199. package/session/NewSessionViewer.js +2 -1
  200. package/session/NewSessionViewer.js.map +1 -1
  201. package/session/run-config.d.ts +9 -0
  202. package/session/run-config.d.ts.map +1 -1
  203. package/session/run-config.js +5 -0
  204. package/session/run-config.js.map +1 -1
  205. package/session/useNewSessionFlow.d.ts +27 -1
  206. package/session/useNewSessionFlow.d.ts.map +1 -1
  207. package/session/useNewSessionFlow.js +51 -8
  208. package/session/useNewSessionFlow.js.map +1 -1
  209. package/session/useSessionConversation.d.ts +12 -1
  210. package/session/useSessionConversation.d.ts.map +1 -1
  211. package/session/useSessionConversation.js +15 -24
  212. package/session/useSessionConversation.js.map +1 -1
  213. package/session/useSessionPageFlow.d.ts.map +1 -1
  214. package/session/useSessionPageFlow.js +14 -10
  215. package/session/useSessionPageFlow.js.map +1 -1
  216. package/session/useUpdateSession.d.ts +18 -24
  217. package/session/useUpdateSession.d.ts.map +1 -1
  218. package/session/useUpdateSession.js +18 -24
  219. package/session/useUpdateSession.js.map +1 -1
  220. package/settings/AccountPreferencesSection.d.ts +3 -0
  221. package/settings/AccountPreferencesSection.d.ts.map +1 -0
  222. package/settings/AccountPreferencesSection.js +10 -0
  223. package/settings/AccountPreferencesSection.js.map +1 -0
  224. package/settings/OrgPreferencesSection.d.ts +3 -0
  225. package/settings/OrgPreferencesSection.d.ts.map +1 -0
  226. package/settings/OrgPreferencesSection.js +13 -0
  227. package/settings/OrgPreferencesSection.js.map +1 -0
  228. package/settings/index.d.ts +2 -0
  229. package/settings/index.d.ts.map +1 -1
  230. package/settings/index.js +2 -0
  231. package/settings/index.js.map +1 -1
  232. package/settings/settings-nav.d.ts.map +1 -1
  233. package/settings/settings-nav.js +17 -1
  234. package/settings/settings-nav.js.map +1 -1
  235. package/src/agent/AgentDetailView.tsx +2 -2
  236. package/src/agent/index.ts +0 -2
  237. package/src/agent/useUpdateAgent.ts +3 -3
  238. package/src/agent-instance/AgentInstanceDetailPanel.tsx +5 -7
  239. package/src/agent-instance/__tests__/AgentInstanceDetailPanel.test.tsx +75 -0
  240. package/src/agent-instance/useUpdateAgentInstance.ts +1 -1
  241. package/src/attachment/AttachmentChipList.tsx +19 -8
  242. package/src/attachment/__tests__/AttachmentChipList.test.tsx +12 -0
  243. package/src/attachment/__tests__/useAttachments.test.ts +293 -0
  244. package/src/attachment/index.ts +1 -0
  245. package/src/attachment/useAttachments.ts +143 -11
  246. package/src/channel/AgentChannelsPanel.tsx +26 -1
  247. package/src/channel/ChannelRunConfigDialog.tsx +351 -0
  248. package/src/channel/__tests__/ChannelRunConfigDialog.test.tsx +210 -0
  249. package/src/channel/index.ts +2 -0
  250. package/src/channel/useSaveAgentChannel.ts +6 -3
  251. package/src/channel-app/ChannelAppDetailPanel.tsx +9 -9
  252. package/src/channel-app/__tests__/channelAppWhatsApp.test.tsx +2 -0
  253. package/src/channel-app/__tests__/channelAppWipeSafety.test.tsx +87 -0
  254. package/src/composer/ComposerToolbar.tsx +9 -0
  255. package/src/composer/SessionComposer.tsx +59 -16
  256. package/src/composer/__tests__/SessionComposer-thinkingMode.test.tsx +176 -0
  257. package/src/conversation/ConversationComposer.tsx +38 -4
  258. package/src/conversation/ConversationTemplatePickerDialog.tsx +441 -0
  259. package/src/conversation/ConversationsWorkbench.tsx +40 -4
  260. package/src/conversation/__tests__/ConversationComposer.test.tsx +56 -1
  261. package/src/conversation/__tests__/ConversationTemplatePickerDialog.test.tsx +224 -0
  262. package/src/conversation/__tests__/useConversationParticipation.test.tsx +45 -4
  263. package/src/conversation/index.ts +4 -0
  264. package/src/conversation/useConversationParticipation.ts +58 -6
  265. package/src/cursor-accounts/CursorAccountsConsole.tsx +40 -5
  266. package/src/cursor-accounts/__tests__/CursorAccountsConsole.test.tsx +32 -0
  267. package/src/cursor-accounts/__tests__/cursor-account-coverage.test.ts +58 -1
  268. package/src/cursor-accounts/cursor-account-coverage.ts +55 -0
  269. package/src/execution/useCreateAgentExecution.ts +19 -0
  270. package/src/identity-account/AccountPreferencesPanel.tsx +532 -0
  271. package/src/identity-account/__tests__/AccountPreferencesPanel.test.tsx +267 -0
  272. package/src/identity-account/__tests__/useAccountExecutionDefaults.test.tsx +116 -0
  273. package/src/identity-account/__tests__/useMyIdentityAccount.test.tsx +121 -0
  274. package/src/identity-account/index.ts +11 -0
  275. package/src/identity-account/useAccountExecutionDefaults.ts +63 -0
  276. package/src/identity-account/useMyIdentityAccount.ts +75 -0
  277. package/src/identity-account/useUpdateIdentityAccount.ts +73 -0
  278. package/src/identity-provider/IdentityProviderDetailPanel.tsx +18 -15
  279. package/src/identity-provider/__tests__/IdentityProviderDetailPanel.test.tsx +80 -0
  280. package/src/index.ts +26 -4
  281. package/src/internal/StandingContextField.tsx +92 -0
  282. package/src/library/InstanceVisibilitySelector.tsx +9 -2
  283. package/src/library/ResourceVisibilityControl.tsx +46 -13
  284. package/src/library/VisibilityOptionRow.tsx +28 -6
  285. package/src/library/VisibilitySelector.tsx +14 -2
  286. package/src/library/__tests__/VisibilitySelector.test.tsx +48 -1
  287. package/src/library/__tests__/visibilityLevels.test.ts +67 -1
  288. package/src/library/index.ts +6 -1
  289. package/src/library/useCanSetPublicVisibility.ts +56 -0
  290. package/src/library/visibilityLevels.ts +65 -14
  291. package/src/mcp-server/McpServerDetailView.tsx +2 -2
  292. package/src/mcp-server/__tests__/useMcpServerConnect.asyncLane.test.tsx +117 -0
  293. package/src/mcp-server/index.ts +0 -2
  294. package/src/mcp-server/internal/definitionDrift.ts +22 -20
  295. package/src/mcp-server/useMcpServerConnect.ts +9 -6
  296. package/src/mcp-server/useMcpServerOAuthConnect.ts +7 -2
  297. package/src/mcp-server/useUpdateMcpServer.ts +3 -3
  298. package/src/models/ModelSelector.tsx +94 -1
  299. package/src/models/index.ts +2 -0
  300. package/src/models/registry.ts +29 -0
  301. package/src/models/thinking-mode.ts +48 -0
  302. package/src/oauth-app/CreateOAuthAppForm.tsx +58 -3
  303. package/src/oauth-app/OAuthAppDetailPanel.tsx +103 -20
  304. package/src/oauth-app/__tests__/OAuthAppDetailPanel.test.tsx +94 -0
  305. package/src/organization/OrgPreferencesPanel.tsx +221 -0
  306. package/src/organization/OrgProfilePanel.tsx +5 -4
  307. package/src/organization/__tests__/OrgPreferencesPanel.test.tsx +145 -0
  308. package/src/organization/__tests__/OrgProfilePanel.test.tsx +108 -0
  309. package/src/organization/index.ts +2 -0
  310. package/src/platform-client/PlatformClientDetailPanel.tsx +14 -13
  311. package/src/platform-client/__tests__/PlatformClientDetailPanel.test.tsx +82 -0
  312. package/src/schedule/ScheduleDetailView.tsx +29 -4
  313. package/src/schedule/ScheduleForm.tsx +14 -1
  314. package/src/session/NewSessionViewer.tsx +12 -0
  315. package/src/session/__tests__/useNewSessionFlow.test.tsx +151 -0
  316. package/src/session/run-config.ts +16 -0
  317. package/src/session/useNewSessionFlow.ts +82 -9
  318. package/src/session/useSessionConversation.ts +32 -40
  319. package/src/session/useSessionPageFlow.ts +14 -11
  320. package/src/session/useUpdateSession.ts +18 -24
  321. package/src/settings/AccountPreferencesSection.tsx +25 -0
  322. package/src/settings/OrgPreferencesSection.tsx +35 -0
  323. package/src/settings/__tests__/settings-nav.test.ts +27 -0
  324. package/src/settings/index.ts +2 -0
  325. package/src/settings/settings-nav.ts +18 -0
  326. package/src/workflow/ApprovalFormBuilder.tsx +20 -27
  327. package/src/workflow/WorkflowDetailView.tsx +2 -2
  328. package/src/workflow/__tests__/WorkflowInstanceDetailPanel.test.tsx +83 -0
  329. package/src/workflow/index.ts +0 -2
  330. package/src/workflow/instance/WorkflowInstanceDetailPanel.tsx +6 -7
  331. package/src/workflow/useUpdateWorkflow.ts +3 -3
  332. package/styles.css +1 -1
  333. package/workflow/ApprovalFormBuilder.d.ts.map +1 -1
  334. package/workflow/ApprovalFormBuilder.js +10 -5
  335. package/workflow/ApprovalFormBuilder.js.map +1 -1
  336. package/workflow/WorkflowDetailView.js +2 -2
  337. package/workflow/WorkflowDetailView.js.map +1 -1
  338. package/workflow/index.d.ts +0 -1
  339. package/workflow/index.d.ts.map +1 -1
  340. package/workflow/index.js +0 -1
  341. package/workflow/index.js.map +1 -1
  342. package/workflow/instance/WorkflowInstanceDetailPanel.d.ts.map +1 -1
  343. package/workflow/instance/WorkflowInstanceDetailPanel.js +6 -7
  344. package/workflow/instance/WorkflowInstanceDetailPanel.js.map +1 -1
  345. package/workflow/useUpdateWorkflow.d.ts +3 -3
  346. package/workflow/useUpdateWorkflow.js +3 -3
  347. package/agent/internal/agentToInput.d.ts +0 -15
  348. package/agent/internal/agentToInput.d.ts.map +0 -1
  349. package/agent/internal/agentToInput.js +0 -84
  350. package/agent/internal/agentToInput.js.map +0 -1
  351. package/mcp-server/internal/mcpServerToInput.d.ts +0 -12
  352. package/mcp-server/internal/mcpServerToInput.d.ts.map +0 -1
  353. package/mcp-server/internal/mcpServerToInput.js +0 -84
  354. package/mcp-server/internal/mcpServerToInput.js.map +0 -1
  355. package/session/session-spec-converters.d.ts +0 -24
  356. package/session/session-spec-converters.d.ts.map +0 -1
  357. package/session/session-spec-converters.js +0 -72
  358. package/session/session-spec-converters.js.map +0 -1
  359. package/src/agent/internal/__tests__/agentToInput.test.ts +0 -145
  360. package/src/agent/internal/agentToInput.ts +0 -102
  361. package/src/mcp-server/__tests__/mcpServerToInput.test.ts +0 -201
  362. package/src/mcp-server/internal/mcpServerToInput.ts +0 -98
  363. package/src/session/__tests__/session-spec-converters.test.ts +0 -183
  364. package/src/session/session-spec-converters.ts +0 -86
  365. package/src/workflow/internal/workflowToInput.ts +0 -96
  366. package/workflow/internal/workflowToInput.d.ts +0 -12
  367. package/workflow/internal/workflowToInput.d.ts.map +0 -1
  368. package/workflow/internal/workflowToInput.js +0 -73
  369. package/workflow/internal/workflowToInput.js.map +0 -1
@@ -0,0 +1,351 @@
1
+ "use client";
2
+
3
+ import { useCallback, useId, useState } from "react";
4
+ import { cn } from "@stigmer/theme";
5
+ import { getUserMessage, type RunConfigInput } from "@stigmer/sdk";
6
+ import type { AgentChannel } from "@stigmer/protos/ai/stigmer/agentic/agentchannel/v1/api_pb";
7
+ import { Button } from "../button/Button.js";
8
+ import { DialogShell } from "../internal/DialogShell.js";
9
+ import { ModelSelector } from "../models/ModelSelector.js";
10
+ import type { HarnessOption } from "../models/harness.js";
11
+ import {
12
+ fromProtoServiceTier,
13
+ toProtoServiceTier,
14
+ type ServiceTierOption,
15
+ } from "../models/service-tier.js";
16
+ import {
17
+ fromProtoThinkingMode,
18
+ toProtoThinkingMode,
19
+ type ThinkingModeOption,
20
+ } from "../models/thinking-mode.js";
21
+ import { agentChannelToInput, useSaveAgentChannel } from "./useSaveAgentChannel.js";
22
+
23
+ /** Props for {@link ChannelRunConfigDialog}. */
24
+ export interface ChannelRunConfigDialogProps {
25
+ /** Whether the dialog is open. */
26
+ readonly open: boolean;
27
+ /** Called when the dialog requests an open-state change. */
28
+ readonly onOpenChange: (open: boolean) => void;
29
+ /** The channel whose run settings are edited. */
30
+ readonly channel: AgentChannel;
31
+ /** Called after a successful save (hosts typically pass `refetch`). */
32
+ readonly onSaved?: () => void;
33
+ /**
34
+ * When `false`, renders as an in-flow open dialog instead of a
35
+ * top-layer modal — for embedding in constrained surfaces
36
+ * (documentation demos, visual tests). Interactive hosts keep the
37
+ * default.
38
+ * @default true
39
+ */
40
+ readonly modal?: boolean;
41
+ }
42
+
43
+ /**
44
+ * Edits an installed channel's run settings (`AgentChannelSpec.run_config`)
45
+ * — the console's first run_config editor (stigmer/stigmer#792), replacing
46
+ * the Edit-YAML detour for the model pin the write-time validation guards
47
+ * (stigmer/stigmer#774).
48
+ *
49
+ * Speaks the schedule form's vocabulary (DD-018 D-5): the model pin uses
50
+ * the composer's own {@link ModelSelector} (with the fast-tier and
51
+ * thinking switches, #357/#772) and the budget is the one run bound a
52
+ * user owns; `max_tool_rounds` is an operator knob, API-reachable only —
53
+ * preserved verbatim on save, never rendered.
54
+ *
55
+ * The harness dropdown is a browsing scope for the picker, initialized to
56
+ * cursor (the platform's channel-serving default): channels carry no
57
+ * per-channel harness — the serving harness is a platform property — and
58
+ * the write-time model-pin validation judges the pin against any harness
59
+ * section, so pinning under either scope is legitimate.
60
+ *
61
+ * Saves are full-input applies via {@link agentChannelToInput}, so the
62
+ * agent reference, provider marker, credential bindings, and install
63
+ * status all survive; clearing the model with no budget set is an
64
+ * explicit reset to the platform defaults (`run_config` absent). Untouched
65
+ * variant switches stay off the wire — unspecified-vs-explicit is a
66
+ * load-bearing ledger distinction (#357).
67
+ *
68
+ * Built on the native `<dialog>` element, matching the SDK's modal
69
+ * convention. Most hosts mount it via {@link AgentChannelsPanel}'s
70
+ * channel card action.
71
+ */
72
+ export function ChannelRunConfigDialog({
73
+ open,
74
+ onOpenChange,
75
+ channel,
76
+ onSaved,
77
+ modal = true,
78
+ }: ChannelRunConfigDialogProps) {
79
+ // Instance-scoped title id (oss#593): hosts legitimately mount this
80
+ // dialog more than once per page; duplicate DOM ids would break the
81
+ // aria-labelledby association for every copy after the first.
82
+ const titleId = useId();
83
+
84
+ const handleClose = useCallback(() => {
85
+ onOpenChange(false);
86
+ }, [onOpenChange]);
87
+
88
+ return (
89
+ <DialogShell
90
+ open={open}
91
+ onOpenChange={onOpenChange}
92
+ modal={modal}
93
+ width="md"
94
+ aria-labelledby={titleId}
95
+ >
96
+ {/* Body mounts only while open so its draft resets per session —
97
+ reopening never resumes stale, unsaved edits. */}
98
+ {open && (
99
+ <ChannelRunConfigDialogBody
100
+ channel={channel}
101
+ onSaved={onSaved}
102
+ onClose={handleClose}
103
+ titleId={titleId}
104
+ />
105
+ )}
106
+ </DialogShell>
107
+ );
108
+ }
109
+
110
+ function ChannelRunConfigDialogBody({
111
+ channel,
112
+ onSaved,
113
+ onClose,
114
+ titleId,
115
+ }: {
116
+ readonly channel: AgentChannel;
117
+ readonly onSaved?: () => void;
118
+ readonly onClose: () => void;
119
+ /** Heading id minted by the outer dialog for its aria-labelledby. */
120
+ readonly titleId: string;
121
+ }) {
122
+ const channelName =
123
+ channel.metadata?.name || channel.metadata?.slug || "this channel";
124
+ const stored = channel.spec?.runConfig;
125
+
126
+ const { save, isPending, error, clearError } = useSaveAgentChannel();
127
+
128
+ const [modelName, setModelName] = useState(stored?.modelName ?? "");
129
+ const [harness, setHarness] = useState<HarnessOption>("cursor");
130
+ const [serviceTier, setServiceTier] = useState<ServiceTierOption>(
131
+ fromProtoServiceTier(stored?.serviceTier) ?? "standard",
132
+ );
133
+ const [thinkingMode, setThinkingMode] = useState<ThinkingModeOption>(
134
+ fromProtoThinkingMode(stored?.thinkingMode) ?? "disabled",
135
+ );
136
+ const [budgetUsd, setBudgetUsd] = useState(
137
+ stored && stored.maxCostUsd > 0 ? String(stored.maxCostUsd) : "",
138
+ );
139
+
140
+ const handleSave = useCallback(async () => {
141
+ try {
142
+ // Full-input apply: only run_config changes. An all-empty draft
143
+ // clears the block entirely — the proto's "empty = inherit" contract
144
+ // (DD-018 D-2) — while `max_tool_rounds`, which this editor never
145
+ // renders, survives verbatim (operator knob, DD-018 D-5).
146
+ await save({
147
+ ...agentChannelToInput(channel),
148
+ runConfig: buildRunConfig(
149
+ modelName,
150
+ budgetUsd,
151
+ serviceTier,
152
+ thinkingMode,
153
+ stored?.maxToolRounds ?? 0,
154
+ ),
155
+ });
156
+ onSaved?.();
157
+ onClose();
158
+ } catch {
159
+ // Surfaced through the hook's error state below.
160
+ }
161
+ }, [budgetUsd, channel, modelName, onClose, onSaved, save, serviceTier, stored, thinkingMode]);
162
+
163
+ return (
164
+ <div className="stg:flex stg:flex-col">
165
+ <div className="stg:flex stg:items-start stg:justify-between stg:gap-3 stg:border-b stg:border-border stg:px-5 stg:py-4">
166
+ <div className="stg:min-w-0">
167
+ <h2
168
+ id={titleId}
169
+ className="stg:text-sm stg:font-semibold stg:text-foreground"
170
+ >
171
+ Run settings
172
+ </h2>
173
+ <p className="stg:mt-0.5 stg:truncate stg:text-xs stg:text-muted-foreground">
174
+ {channelName}
175
+ </p>
176
+ </div>
177
+ <button
178
+ type="button"
179
+ onClick={onClose}
180
+ aria-label="Close dialog"
181
+ className={cn(
182
+ "stg:rounded stg:p-1 stg:text-muted-foreground",
183
+ "stg:hover:bg-accent-hover stg:hover:text-foreground",
184
+ "stg:focus:outline-none stg:focus:ring-1 stg:focus:ring-ring",
185
+ )}
186
+ >
187
+ <CloseIcon />
188
+ </button>
189
+ </div>
190
+
191
+ <div className="stg:space-y-4 stg:px-5 stg:py-4">
192
+ {/* Engine & model — the composer's own picker (DD-018 D-5), the
193
+ same shape as the schedule form's. Nothing is pinned until a
194
+ model is picked. */}
195
+ <div className="stg:space-y-1">
196
+ <span className={labelClasses}>
197
+ Model{" "}
198
+ <span className="stg:font-normal stg:text-muted-foreground">(optional)</span>
199
+ </span>
200
+ <div className="stg:flex stg:items-center stg:gap-2">
201
+ <ModelSelector
202
+ value={modelName}
203
+ onValueChange={setModelName}
204
+ initialHarness={harness}
205
+ onHarnessChange={setHarness}
206
+ serviceTier={serviceTier}
207
+ onServiceTierChange={setServiceTier}
208
+ thinkingMode={thinkingMode}
209
+ onThinkingModeChange={setThinkingMode}
210
+ placeholderLabel="Platform default"
211
+ disabled={isPending}
212
+ />
213
+ {modelName !== "" && (
214
+ <button
215
+ type="button"
216
+ onClick={() => {
217
+ setModelName("");
218
+ setServiceTier("standard");
219
+ setThinkingMode("disabled");
220
+ }}
221
+ disabled={isPending}
222
+ className={cn(
223
+ "stg:rounded-md stg:px-2 stg:py-1 stg:text-[0.65rem] stg:text-muted-foreground",
224
+ "stg:hover:text-foreground stg:focus-visible:outline-none stg:focus-visible:ring-2 stg:focus-visible:ring-ring",
225
+ "stg:disabled:pointer-events-none stg:disabled:opacity-50",
226
+ )}
227
+ >
228
+ Reset to platform default
229
+ </button>
230
+ )}
231
+ </div>
232
+ <p className={hintClasses}>
233
+ Every conversation turn on this channel runs the pinned model.
234
+ Unpinned, the platform&rsquo;s default engine and model apply.
235
+ </p>
236
+ </div>
237
+
238
+ {/* Budget — the one run bound that matters for an unattended
239
+ surface (DD-018 D-5). Clamped by the platform profile;
240
+ tool-round bounds stay API-only. */}
241
+ <div className="stg:space-y-1">
242
+ <label htmlFor={`${titleId}-budget`} className={labelClasses}>
243
+ Budget per run (USD){" "}
244
+ <span className="stg:font-normal stg:text-muted-foreground">(optional)</span>
245
+ </label>
246
+ <input
247
+ id={`${titleId}-budget`}
248
+ type="number"
249
+ min="0"
250
+ step="0.5"
251
+ inputMode="decimal"
252
+ value={budgetUsd}
253
+ onChange={(e) => setBudgetUsd(e.target.value)}
254
+ placeholder="Platform default"
255
+ disabled={isPending}
256
+ className={cn(inputClasses, "stg:max-w-40")}
257
+ />
258
+ <p className={hintClasses}>
259
+ Caps each turn&rsquo;s estimated spend. The platform profile
260
+ bounds this value; the lower cap wins.
261
+ </p>
262
+ </div>
263
+
264
+ {error && (
265
+ <div
266
+ role="alert"
267
+ className="stg:rounded-md stg:border stg:border-destructive/30 stg:bg-destructive-subtle stg:px-3 stg:py-2 stg:text-xs stg:text-destructive"
268
+ >
269
+ {getUserMessage(error)}
270
+ </div>
271
+ )}
272
+ </div>
273
+
274
+ <div className="stg:flex stg:justify-end stg:gap-2 stg:border-t stg:border-border stg:px-5 stg:py-3">
275
+ <Button
276
+ variant="ghost"
277
+ size="sm"
278
+ onClick={() => {
279
+ clearError();
280
+ onClose();
281
+ }}
282
+ disabled={isPending}
283
+ >
284
+ Cancel
285
+ </Button>
286
+ <Button
287
+ variant="primary"
288
+ size="sm"
289
+ onClick={() => void handleSave()}
290
+ disabled={isPending}
291
+ >
292
+ Save
293
+ </Button>
294
+ </div>
295
+ </div>
296
+ );
297
+ }
298
+
299
+ /**
300
+ * Assemble the run_config the save writes. The schedule form's
301
+ * `buildRunConfig` contract (#357/#772) plus the edit-surface rule from
302
+ * the schedule detail view's `normalizeRunConfig`: fields this editor
303
+ * does not own (`max_tool_rounds`) are preserved verbatim, and an
304
+ * all-empty result clears the block ("empty = inherit").
305
+ */
306
+ function buildRunConfig(
307
+ modelName: string,
308
+ budgetUsd: string,
309
+ serviceTier: ServiceTierOption,
310
+ thinkingMode: ThinkingModeOption,
311
+ storedMaxToolRounds: number,
312
+ ): RunConfigInput | undefined {
313
+ const model = modelName.trim();
314
+ const cost = Number.parseFloat(budgetUsd);
315
+
316
+ const config: RunConfigInput = {};
317
+ if (model !== "") config.modelName = model;
318
+ if (Number.isFinite(cost) && cost > 0) config.maxCostUsd = cost;
319
+ if (storedMaxToolRounds > 0) config.maxToolRounds = storedMaxToolRounds;
320
+ // Carried only when the user actively chose the variant AND pinned a
321
+ // model (both are per-model; the server refuses them without one). An
322
+ // untouched switch stays absent — unspecified-vs-explicit is a
323
+ // load-bearing ledger distinction (#357/#772).
324
+ if (serviceTier === "fast" && model !== "") {
325
+ config.serviceTier = toProtoServiceTier(serviceTier);
326
+ }
327
+ if (thinkingMode === "enabled" && model !== "") {
328
+ config.thinkingMode = toProtoThinkingMode(thinkingMode);
329
+ }
330
+
331
+ return Object.keys(config).length > 0 ? config : undefined;
332
+ }
333
+
334
+ const labelClasses = "stg:block stg:text-xs stg:font-medium stg:text-foreground";
335
+
336
+ const hintClasses = "stg:text-[0.65rem] stg:text-muted-foreground";
337
+
338
+ const inputClasses = cn(
339
+ "stg:w-full stg:rounded-md stg:border stg:border-input stg:bg-background stg:px-2.5 stg:py-1.5 stg:text-xs stg:text-foreground",
340
+ "stg:placeholder:text-muted-foreground",
341
+ "stg:focus-visible:outline-none stg:focus-visible:ring-1 stg:focus-visible:ring-ring",
342
+ "stg:disabled:pointer-events-none stg:disabled:opacity-50",
343
+ );
344
+
345
+ function CloseIcon() {
346
+ return (
347
+ <svg width="14" height="14" viewBox="0 0 14 14" fill="none" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" aria-hidden="true">
348
+ <path d="m3 3 8 8M11 3l-8 8" />
349
+ </svg>
350
+ );
351
+ }
@@ -0,0 +1,210 @@
1
+ import { describe, it, expect, vi, beforeAll, afterEach } from "vitest";
2
+ import { render, screen, fireEvent, waitFor, cleanup } from "@testing-library/react";
3
+ import type { ReactNode } from "react";
4
+ import { ServiceTier, ThinkingMode } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
5
+ import type { AgentChannelInput } from "@stigmer/sdk";
6
+ import { StigmerContext } from "../../context";
7
+ import { ModelRegistryContext } from "../../models/ModelRegistryContext";
8
+ import type { ModelInfo } from "../../models/registry";
9
+ import { ChannelRunConfigDialog } from "../ChannelRunConfigDialog";
10
+
11
+ // happy-dom does not implement the native dialog show/close methods.
12
+ beforeAll(() => {
13
+ HTMLDialogElement.prototype.showModal = function showModal() {
14
+ this.open = true;
15
+ };
16
+ HTMLDialogElement.prototype.close = function close() {
17
+ this.open = false;
18
+ };
19
+ if (!("ResizeObserver" in globalThis)) {
20
+ (globalThis as unknown as { ResizeObserver: unknown }).ResizeObserver =
21
+ class {
22
+ observe() {}
23
+ unobserve() {}
24
+ disconnect() {}
25
+ };
26
+ }
27
+ });
28
+
29
+ afterEach(cleanup);
30
+
31
+ /**
32
+ * The console's first run_config editor (stigmer/stigmer#792). The pinned
33
+ * behaviors are the edit-surface contracts the rest of the platform relies
34
+ * on: `max_tool_rounds` (the operator knob this editor never renders)
35
+ * survives every save verbatim, an all-empty draft clears the block
36
+ * ("empty = inherit"), and untouched variant switches stay off the wire
37
+ * (the #357/#772 unspecified-vs-explicit ledger distinction).
38
+ */
39
+
40
+ const MODELS: ModelInfo[] = [
41
+ {
42
+ modelId: "claude-haiku-4-5",
43
+ provider: "anthropic",
44
+ displayName: "Haiku 4.5",
45
+ shortDescription: "Fast Claude with optional thinking",
46
+ speedTier: "fast",
47
+ costTier: "economy",
48
+ harness: "cursor",
49
+ featured: true,
50
+ serviceTiers: [],
51
+ thinkingCapable: true,
52
+ },
53
+ ];
54
+
55
+ function makeChannel(runConfig?: {
56
+ modelName?: string;
57
+ maxCostUsd?: number;
58
+ maxToolRounds?: number;
59
+ serviceTier?: ServiceTier;
60
+ thinkingMode?: ThinkingMode;
61
+ }) {
62
+ return {
63
+ metadata: {
64
+ id: "ach_1",
65
+ name: "Support Slack",
66
+ slug: "support-slack",
67
+ org: "acme",
68
+ labels: {},
69
+ },
70
+ spec: {
71
+ agentRef: { org: "acme", slug: "support-agent" },
72
+ enabled: true,
73
+ providerConfig: { case: "slack", value: {} },
74
+ environmentRefs: [],
75
+ ...(runConfig
76
+ ? {
77
+ runConfig: {
78
+ modelName: runConfig.modelName ?? "",
79
+ maxCostUsd: runConfig.maxCostUsd ?? 0,
80
+ maxToolRounds: runConfig.maxToolRounds ?? 0,
81
+ serviceTier: runConfig.serviceTier ?? ServiceTier.UNSPECIFIED,
82
+ thinkingMode: runConfig.thinkingMode ?? ThinkingMode.UNSPECIFIED,
83
+ },
84
+ }
85
+ : {}),
86
+ },
87
+ status: { installState: 2 },
88
+ } as never;
89
+ }
90
+
91
+ function createMockStigmer() {
92
+ const apply = vi.fn().mockResolvedValue({});
93
+ const client = { agentChannel: { apply } } as never;
94
+ return { client, apply };
95
+ }
96
+
97
+ function Providers({
98
+ client,
99
+ children,
100
+ }: {
101
+ client: unknown;
102
+ children: ReactNode;
103
+ }) {
104
+ return (
105
+ <StigmerContext.Provider value={client as never}>
106
+ <ModelRegistryContext.Provider
107
+ value={{ models: MODELS, isLoading: false, error: null, refetch: vi.fn() }}
108
+ >
109
+ {children}
110
+ </ModelRegistryContext.Provider>
111
+ </StigmerContext.Provider>
112
+ );
113
+ }
114
+
115
+ function renderDialog(channel: unknown) {
116
+ const { client, apply } = createMockStigmer();
117
+ const onSaved = vi.fn();
118
+ render(
119
+ <Providers client={client}>
120
+ <ChannelRunConfigDialog
121
+ open
122
+ onOpenChange={vi.fn()}
123
+ channel={channel as never}
124
+ onSaved={onSaved}
125
+ />
126
+ </Providers>,
127
+ );
128
+ return { apply, onSaved };
129
+ }
130
+
131
+ async function save() {
132
+ fireEvent.click(screen.getByRole("button", { name: "Save" }));
133
+ }
134
+
135
+ describe("ChannelRunConfigDialog", () => {
136
+ it("preserves max_tool_rounds verbatim even though it never renders", async () => {
137
+ const { apply } = renderDialog(
138
+ makeChannel({ modelName: "claude-haiku-4-5", maxToolRounds: 25 }),
139
+ );
140
+
141
+ expect(screen.queryByText(/tool round/i)).toBeNull();
142
+ await save();
143
+
144
+ await waitFor(() => expect(apply).toHaveBeenCalledOnce());
145
+ const input = apply.mock.calls[0][0] as AgentChannelInput;
146
+ expect(input.runConfig?.maxToolRounds).toBe(25);
147
+ expect(input.runConfig?.modelName).toBe("claude-haiku-4-5");
148
+ });
149
+
150
+ it("clears run_config entirely when the draft is emptied (empty = inherit)", async () => {
151
+ const { apply } = renderDialog(
152
+ makeChannel({ modelName: "claude-haiku-4-5", maxCostUsd: 2 }),
153
+ );
154
+
155
+ fireEvent.click(
156
+ screen.getByRole("button", { name: "Reset to platform default" }),
157
+ );
158
+ fireEvent.change(screen.getByLabelText(/Budget per run/), {
159
+ target: { value: "" },
160
+ });
161
+ await save();
162
+
163
+ await waitFor(() => expect(apply).toHaveBeenCalledOnce());
164
+ const input = apply.mock.calls[0][0] as AgentChannelInput;
165
+ expect(input.runConfig).toBeUndefined();
166
+ });
167
+
168
+ it("carries an actively enabled thinking mode, and only then", async () => {
169
+ const { apply } = renderDialog(makeChannel({ modelName: "claude-haiku-4-5" }));
170
+
171
+ fireEvent.click(screen.getByRole("button", { name: /Haiku 4\.5/ }));
172
+ fireEvent.click(await screen.findByRole("switch", { name: "Thinking" }));
173
+ fireEvent.keyDown(document.activeElement ?? document.body, { key: "Escape" });
174
+ await save();
175
+
176
+ await waitFor(() => expect(apply).toHaveBeenCalledOnce());
177
+ const input = apply.mock.calls[0][0] as AgentChannelInput;
178
+ expect(input.runConfig?.thinkingMode).toBe(ThinkingMode.ENABLED);
179
+ // The untouched tier stays absent — never stamped as an explicit
180
+ // STANDARD by a save (#357 ledger distinction).
181
+ expect(input.runConfig?.serviceTier).toBeUndefined();
182
+ });
183
+
184
+ it("round-trips a stored thinking pin into the switch state", async () => {
185
+ renderDialog(
186
+ makeChannel({
187
+ modelName: "claude-haiku-4-5",
188
+ thinkingMode: ThinkingMode.ENABLED,
189
+ }),
190
+ );
191
+
192
+ fireEvent.click(screen.getByRole("button", { name: /Haiku 4\.5/ }));
193
+ const toggle = await screen.findByRole("switch", { name: "Thinking" });
194
+ expect(toggle.getAttribute("aria-checked")).toBe("true");
195
+ });
196
+
197
+ it("collects a budget without requiring a model pin", async () => {
198
+ const { apply } = renderDialog(makeChannel());
199
+
200
+ fireEvent.change(screen.getByLabelText(/Budget per run/), {
201
+ target: { value: "1.5" },
202
+ });
203
+ await save();
204
+
205
+ await waitFor(() => expect(apply).toHaveBeenCalledOnce());
206
+ const input = apply.mock.calls[0][0] as AgentChannelInput;
207
+ expect(input.runConfig?.maxCostUsd).toBe(1.5);
208
+ expect(input.runConfig?.modelName).toBeUndefined();
209
+ });
210
+ });
@@ -69,6 +69,8 @@ export type { ConnectWhatsAppDialogProps } from "./ConnectWhatsAppDialog.js";
69
69
 
70
70
  export { ChannelCredentialsDialog } from "./ChannelCredentialsDialog.js";
71
71
  export type { ChannelCredentialsDialogProps } from "./ChannelCredentialsDialog.js";
72
+ export { ChannelRunConfigDialog } from "./ChannelRunConfigDialog.js";
73
+ export type { ChannelRunConfigDialogProps } from "./ChannelRunConfigDialog.js";
72
74
 
73
75
  export { ChannelToolCredentials } from "./ChannelToolCredentials.js";
74
76
  export type { ChannelToolCredentialsProps } from "./ChannelToolCredentials.js";
@@ -66,9 +66,11 @@ export function agentChannelToInput(channel: AgentChannel): AgentChannelInput {
66
66
  })),
67
67
  }
68
68
  : {}),
69
- // The console does not edit run_config (yet) it rides through
70
- // opaquely so a settings save or pause/resume toggle never wipes an
71
- // override set via the CLI or API.
69
+ // run_config rides through verbatim so a settings save or
70
+ // pause/resume toggle never wipes an override set elsewhere (the
71
+ // ChannelRunConfigDialog the one surface that edits it, #792 —
72
+ // overrides this copy with its own draft; CLI/API overrides survive
73
+ // every other save).
72
74
  ...(spec?.runConfig
73
75
  ? {
74
76
  runConfig: {
@@ -76,6 +78,7 @@ export function agentChannelToInput(channel: AgentChannel): AgentChannelInput {
76
78
  maxCostUsd: spec.runConfig.maxCostUsd,
77
79
  maxToolRounds: spec.runConfig.maxToolRounds,
78
80
  serviceTier: spec.runConfig.serviceTier,
81
+ thinkingMode: spec.runConfig.thinkingMode,
79
82
  },
80
83
  }
81
84
  : {}),
@@ -2,7 +2,7 @@
2
2
 
3
3
  import { type FormEvent, useCallback, useId, useMemo, useState } from "react";
4
4
  import { cn } from "@stigmer/theme";
5
- import { getUserMessage } from "@stigmer/sdk";
5
+ import { getUserMessage, toChannelAppUpdateInput } from "@stigmer/sdk";
6
6
  import type { ChannelApp } from "@stigmer/protos/ai/stigmer/agentic/channelapp/v1/api_pb";
7
7
  import { useStigmer } from "../hooks.js";
8
8
  import { useUpdateChannelApp } from "./useUpdateChannelApp.js";
@@ -229,10 +229,10 @@ function SlackAppDetail({
229
229
 
230
230
  clearError();
231
231
  try {
232
+ // Full-spec-replace safety: spread the complete mapped input and
233
+ // override only the slack arm this form owns.
232
234
  const updated = await update({
233
- name,
234
- org: channelApp.metadata?.org ?? "",
235
- ...(channelApp.metadata?.slug ? { slug: channelApp.metadata.slug } : {}),
235
+ ...toChannelAppUpdateInput(channelApp),
236
236
  slack: {
237
237
  clientId: clientId.trim(),
238
238
  // The redaction marker means "keep the stored value" — the
@@ -246,7 +246,7 @@ function SlackAppDetail({
246
246
  // error state is managed by useUpdateChannelApp
247
247
  }
248
248
  },
249
- [canSave, clearError, update, name, channelApp.metadata, clientId, clientSecret, signingSecret, onUpdated],
249
+ [canSave, clearError, update, channelApp, clientId, clientSecret, signingSecret, onUpdated],
250
250
  );
251
251
 
252
252
  return (
@@ -379,10 +379,10 @@ function WhatsAppAppDetail({
379
379
 
380
380
  clearError();
381
381
  try {
382
+ // Full-spec-replace safety: spread the complete mapped input and
383
+ // override only the whatsapp arm this form owns.
382
384
  const updated = await update({
383
- name,
384
- org: channelApp.metadata?.org ?? "",
385
- ...(channelApp.metadata?.slug ? { slug: channelApp.metadata.slug } : {}),
385
+ ...toChannelAppUpdateInput(channelApp),
386
386
  whatsapp: {
387
387
  appId: metaAppId.trim(),
388
388
  // The redaction marker means "keep the stored value" — the
@@ -397,7 +397,7 @@ function WhatsAppAppDetail({
397
397
  // error state is managed by useUpdateChannelApp
398
398
  }
399
399
  },
400
- [canSave, clearError, update, name, channelApp.metadata, metaAppId, appSecret, accessToken, verifyToken, onUpdated],
400
+ [canSave, clearError, update, channelApp, metaAppId, appSecret, accessToken, verifyToken, onUpdated],
401
401
  );
402
402
 
403
403
  return (
@@ -228,6 +228,8 @@ describe("ChannelAppDetailPanel — WhatsApp branch", () => {
228
228
 
229
229
  await waitFor(() => expect(update).toHaveBeenCalled());
230
230
  expect(update).toHaveBeenCalledWith({
231
+ // The generated mapper carries metadata.id for exact update addressing.
232
+ id: "chapp_1",
231
233
  name: "Acme WhatsApp",
232
234
  org: "acme",
233
235
  slug: "acme-whatsapp",