@stigmer/react 3.12.5 → 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 (208) 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/channel/AgentChannelsPanel.d.ts.map +1 -1
  15. package/channel/AgentChannelsPanel.js +10 -5
  16. package/channel/AgentChannelsPanel.js.map +1 -1
  17. package/channel/ChannelRunConfigDialog.d.ts +51 -0
  18. package/channel/ChannelRunConfigDialog.d.ts.map +1 -0
  19. package/channel/ChannelRunConfigDialog.js +121 -0
  20. package/channel/ChannelRunConfigDialog.js.map +1 -0
  21. package/channel/index.d.ts +2 -0
  22. package/channel/index.d.ts.map +1 -1
  23. package/channel/index.js +1 -0
  24. package/channel/index.js.map +1 -1
  25. package/channel/useSaveAgentChannel.d.ts.map +1 -1
  26. package/channel/useSaveAgentChannel.js +6 -3
  27. package/channel/useSaveAgentChannel.js.map +1 -1
  28. package/channel-app/ChannelAppDetailPanel.js +9 -9
  29. package/channel-app/ChannelAppDetailPanel.js.map +1 -1
  30. package/composer/ComposerToolbar.d.ts +6 -1
  31. package/composer/ComposerToolbar.d.ts.map +1 -1
  32. package/composer/ComposerToolbar.js +2 -2
  33. package/composer/ComposerToolbar.js.map +1 -1
  34. package/composer/SessionComposer.d.ts +9 -0
  35. package/composer/SessionComposer.d.ts.map +1 -1
  36. package/composer/SessionComposer.js +22 -3
  37. package/composer/SessionComposer.js.map +1 -1
  38. package/cursor-accounts/CursorAccountsConsole.d.ts.map +1 -1
  39. package/cursor-accounts/CursorAccountsConsole.js +12 -3
  40. package/cursor-accounts/CursorAccountsConsole.js.map +1 -1
  41. package/cursor-accounts/cursor-account-coverage.d.ts +30 -1
  42. package/cursor-accounts/cursor-account-coverage.d.ts.map +1 -1
  43. package/cursor-accounts/cursor-account-coverage.js +21 -0
  44. package/cursor-accounts/cursor-account-coverage.js.map +1 -1
  45. package/execution/useCreateAgentExecution.d.ts +15 -0
  46. package/execution/useCreateAgentExecution.d.ts.map +1 -1
  47. package/execution/useCreateAgentExecution.js +5 -0
  48. package/execution/useCreateAgentExecution.js.map +1 -1
  49. package/identity-account/AccountPreferencesPanel.d.ts +2 -1
  50. package/identity-account/AccountPreferencesPanel.d.ts.map +1 -1
  51. package/identity-account/AccountPreferencesPanel.js +33 -18
  52. package/identity-account/AccountPreferencesPanel.js.map +1 -1
  53. package/identity-provider/IdentityProviderDetailPanel.d.ts.map +1 -1
  54. package/identity-provider/IdentityProviderDetailPanel.js +16 -15
  55. package/identity-provider/IdentityProviderDetailPanel.js.map +1 -1
  56. package/index.d.ts +4 -4
  57. package/index.d.ts.map +1 -1
  58. package/index.js +3 -3
  59. package/index.js.map +1 -1
  60. package/mcp-server/McpServerDetailView.js +2 -2
  61. package/mcp-server/McpServerDetailView.js.map +1 -1
  62. package/mcp-server/index.d.ts +0 -1
  63. package/mcp-server/index.d.ts.map +1 -1
  64. package/mcp-server/index.js +0 -1
  65. package/mcp-server/index.js.map +1 -1
  66. package/mcp-server/internal/definitionDrift.d.ts +14 -12
  67. package/mcp-server/internal/definitionDrift.d.ts.map +1 -1
  68. package/mcp-server/internal/definitionDrift.js +22 -19
  69. package/mcp-server/internal/definitionDrift.js.map +1 -1
  70. package/mcp-server/useUpdateMcpServer.d.ts +3 -3
  71. package/mcp-server/useUpdateMcpServer.js +3 -3
  72. package/models/ModelSelector.d.ts +33 -1
  73. package/models/ModelSelector.d.ts.map +1 -1
  74. package/models/ModelSelector.js +37 -4
  75. package/models/ModelSelector.js.map +1 -1
  76. package/models/index.d.ts +2 -0
  77. package/models/index.d.ts.map +1 -1
  78. package/models/index.js +1 -0
  79. package/models/index.js.map +1 -1
  80. package/models/registry.d.ts +16 -0
  81. package/models/registry.d.ts.map +1 -1
  82. package/models/registry.js +13 -0
  83. package/models/registry.js.map +1 -1
  84. package/models/thinking-mode.d.ts +27 -0
  85. package/models/thinking-mode.d.ts.map +1 -0
  86. package/models/thinking-mode.js +32 -0
  87. package/models/thinking-mode.js.map +1 -0
  88. package/oauth-app/OAuthAppDetailPanel.d.ts.map +1 -1
  89. package/oauth-app/OAuthAppDetailPanel.js +21 -20
  90. package/oauth-app/OAuthAppDetailPanel.js.map +1 -1
  91. package/package.json +4 -4
  92. package/platform-client/PlatformClientDetailPanel.d.ts.map +1 -1
  93. package/platform-client/PlatformClientDetailPanel.js +12 -13
  94. package/platform-client/PlatformClientDetailPanel.js.map +1 -1
  95. package/schedule/ScheduleDetailView.d.ts.map +1 -1
  96. package/schedule/ScheduleDetailView.js +21 -10
  97. package/schedule/ScheduleDetailView.js.map +1 -1
  98. package/schedule/ScheduleForm.d.ts.map +1 -1
  99. package/schedule/ScheduleForm.js +13 -3
  100. package/schedule/ScheduleForm.js.map +1 -1
  101. package/session/run-config.d.ts +9 -0
  102. package/session/run-config.d.ts.map +1 -1
  103. package/session/run-config.js +5 -0
  104. package/session/run-config.js.map +1 -1
  105. package/session/useNewSessionFlow.d.ts.map +1 -1
  106. package/session/useNewSessionFlow.js +6 -0
  107. package/session/useNewSessionFlow.js.map +1 -1
  108. package/session/useSessionConversation.d.ts +12 -1
  109. package/session/useSessionConversation.d.ts.map +1 -1
  110. package/session/useSessionConversation.js +15 -24
  111. package/session/useSessionConversation.js.map +1 -1
  112. package/session/useSessionPageFlow.d.ts.map +1 -1
  113. package/session/useSessionPageFlow.js +14 -10
  114. package/session/useSessionPageFlow.js.map +1 -1
  115. package/session/useUpdateSession.d.ts +18 -24
  116. package/session/useUpdateSession.d.ts.map +1 -1
  117. package/session/useUpdateSession.js +18 -24
  118. package/session/useUpdateSession.js.map +1 -1
  119. package/src/agent/AgentDetailView.tsx +2 -2
  120. package/src/agent/index.ts +0 -2
  121. package/src/agent/useUpdateAgent.ts +3 -3
  122. package/src/agent-instance/AgentInstanceDetailPanel.tsx +5 -7
  123. package/src/agent-instance/__tests__/AgentInstanceDetailPanel.test.tsx +75 -0
  124. package/src/agent-instance/useUpdateAgentInstance.ts +1 -1
  125. package/src/channel/AgentChannelsPanel.tsx +26 -1
  126. package/src/channel/ChannelRunConfigDialog.tsx +351 -0
  127. package/src/channel/__tests__/ChannelRunConfigDialog.test.tsx +210 -0
  128. package/src/channel/index.ts +2 -0
  129. package/src/channel/useSaveAgentChannel.ts +6 -3
  130. package/src/channel-app/ChannelAppDetailPanel.tsx +9 -9
  131. package/src/channel-app/__tests__/channelAppWhatsApp.test.tsx +2 -0
  132. package/src/channel-app/__tests__/channelAppWipeSafety.test.tsx +87 -0
  133. package/src/composer/ComposerToolbar.tsx +9 -0
  134. package/src/composer/SessionComposer.tsx +36 -2
  135. package/src/composer/__tests__/SessionComposer-thinkingMode.test.tsx +176 -0
  136. package/src/cursor-accounts/CursorAccountsConsole.tsx +40 -5
  137. package/src/cursor-accounts/__tests__/CursorAccountsConsole.test.tsx +32 -0
  138. package/src/cursor-accounts/__tests__/cursor-account-coverage.test.ts +58 -1
  139. package/src/cursor-accounts/cursor-account-coverage.ts +55 -0
  140. package/src/execution/useCreateAgentExecution.ts +19 -0
  141. package/src/identity-account/AccountPreferencesPanel.tsx +154 -68
  142. package/src/identity-account/__tests__/AccountPreferencesPanel.test.tsx +36 -2
  143. package/src/identity-provider/IdentityProviderDetailPanel.tsx +18 -15
  144. package/src/identity-provider/__tests__/IdentityProviderDetailPanel.test.tsx +80 -0
  145. package/src/index.ts +2 -2
  146. package/src/mcp-server/McpServerDetailView.tsx +2 -2
  147. package/src/mcp-server/index.ts +0 -2
  148. package/src/mcp-server/internal/definitionDrift.ts +22 -20
  149. package/src/mcp-server/useUpdateMcpServer.ts +3 -3
  150. package/src/models/ModelSelector.tsx +94 -1
  151. package/src/models/index.ts +2 -0
  152. package/src/models/registry.ts +29 -0
  153. package/src/models/thinking-mode.ts +48 -0
  154. package/src/oauth-app/OAuthAppDetailPanel.tsx +23 -21
  155. package/src/oauth-app/__tests__/OAuthAppDetailPanel.test.tsx +94 -0
  156. package/src/platform-client/PlatformClientDetailPanel.tsx +14 -13
  157. package/src/platform-client/__tests__/PlatformClientDetailPanel.test.tsx +82 -0
  158. package/src/schedule/ScheduleDetailView.tsx +29 -4
  159. package/src/schedule/ScheduleForm.tsx +14 -1
  160. package/src/session/run-config.ts +16 -0
  161. package/src/session/useNewSessionFlow.ts +6 -0
  162. package/src/session/useSessionConversation.ts +32 -40
  163. package/src/session/useSessionPageFlow.ts +14 -11
  164. package/src/session/useUpdateSession.ts +18 -24
  165. package/src/workflow/ApprovalFormBuilder.tsx +20 -5
  166. package/src/workflow/WorkflowDetailView.tsx +2 -2
  167. package/src/workflow/__tests__/WorkflowInstanceDetailPanel.test.tsx +83 -0
  168. package/src/workflow/index.ts +0 -2
  169. package/src/workflow/instance/WorkflowInstanceDetailPanel.tsx +6 -7
  170. package/src/workflow/useUpdateWorkflow.ts +3 -3
  171. package/styles.css +1 -1
  172. package/workflow/ApprovalFormBuilder.d.ts.map +1 -1
  173. package/workflow/ApprovalFormBuilder.js +10 -8
  174. package/workflow/ApprovalFormBuilder.js.map +1 -1
  175. package/workflow/WorkflowDetailView.js +2 -2
  176. package/workflow/WorkflowDetailView.js.map +1 -1
  177. package/workflow/index.d.ts +0 -1
  178. package/workflow/index.d.ts.map +1 -1
  179. package/workflow/index.js +0 -1
  180. package/workflow/index.js.map +1 -1
  181. package/workflow/instance/WorkflowInstanceDetailPanel.d.ts.map +1 -1
  182. package/workflow/instance/WorkflowInstanceDetailPanel.js +6 -7
  183. package/workflow/instance/WorkflowInstanceDetailPanel.js.map +1 -1
  184. package/workflow/useUpdateWorkflow.d.ts +3 -3
  185. package/workflow/useUpdateWorkflow.js +3 -3
  186. package/agent/internal/agentToInput.d.ts +0 -15
  187. package/agent/internal/agentToInput.d.ts.map +0 -1
  188. package/agent/internal/agentToInput.js +0 -84
  189. package/agent/internal/agentToInput.js.map +0 -1
  190. package/mcp-server/internal/mcpServerToInput.d.ts +0 -12
  191. package/mcp-server/internal/mcpServerToInput.d.ts.map +0 -1
  192. package/mcp-server/internal/mcpServerToInput.js +0 -84
  193. package/mcp-server/internal/mcpServerToInput.js.map +0 -1
  194. package/session/session-spec-converters.d.ts +0 -24
  195. package/session/session-spec-converters.d.ts.map +0 -1
  196. package/session/session-spec-converters.js +0 -72
  197. package/session/session-spec-converters.js.map +0 -1
  198. package/src/agent/internal/__tests__/agentToInput.test.ts +0 -145
  199. package/src/agent/internal/agentToInput.ts +0 -102
  200. package/src/mcp-server/__tests__/mcpServerToInput.test.ts +0 -201
  201. package/src/mcp-server/internal/mcpServerToInput.ts +0 -98
  202. package/src/session/__tests__/session-spec-converters.test.ts +0 -183
  203. package/src/session/session-spec-converters.ts +0 -86
  204. package/src/workflow/internal/workflowToInput.ts +0 -96
  205. package/workflow/internal/workflowToInput.d.ts +0 -12
  206. package/workflow/internal/workflowToInput.d.ts.map +0 -1
  207. package/workflow/internal/workflowToInput.js +0 -73
  208. package/workflow/internal/workflowToInput.js.map +0 -1
@@ -37,7 +37,7 @@ import {
37
37
  type RunConfig,
38
38
  } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/invocation_pb";
39
39
  import { Harness } from "@stigmer/protos/ai/stigmer/agentic/session/v1/enum_pb";
40
- import { ServiceTier } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
40
+ import { ServiceTier, ThinkingMode } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
41
41
  import type { WorkspaceEntry } from "@stigmer/protos/ai/stigmer/agentic/session/v1/workspace_pb";
42
42
  import {
43
43
  cadenceToCron,
@@ -60,6 +60,11 @@ import {
60
60
  toProtoServiceTier,
61
61
  type ServiceTierOption,
62
62
  } from "../models/service-tier.js";
63
+ import {
64
+ fromProtoThinkingMode,
65
+ toProtoThinkingMode,
66
+ type ThinkingModeOption,
67
+ } from "../models/thinking-mode.js";
63
68
  import { deriveScheduleState, formatNextFire } from "./scheduleState.js";
64
69
  import {
65
70
  ScheduleRunsCompactList,
@@ -599,10 +604,10 @@ export function ScheduleDetailView({
599
604
  {editable && target ? (
600
605
  <EngineModelInlineEditor
601
606
  invocation={target}
602
- onSave={(harness, modelName, serviceTier) =>
607
+ onSave={(harness, modelName, serviceTier, thinkingMode) =>
603
608
  saveSpecField("engine-model", (s) => {
604
609
  if (s.target.case === "agent") {
605
- applyEngineModel(s.target.value, harness, modelName, serviceTier);
610
+ applyEngineModel(s.target.value, harness, modelName, serviceTier, thinkingMode);
606
611
  }
607
612
  })
608
613
  }
@@ -1016,6 +1021,7 @@ function EngineModelInlineEditor({
1016
1021
  harness: Harness,
1017
1022
  modelName: string,
1018
1023
  serviceTier: ServiceTierOption,
1024
+ thinkingMode: ThinkingModeOption,
1019
1025
  ) => Promise<boolean>;
1020
1026
  readonly isSaving: boolean;
1021
1027
  readonly error?: string;
@@ -1024,6 +1030,7 @@ function EngineModelInlineEditor({
1024
1030
  const [modelName, setModelName] = useState("");
1025
1031
  const [harness, setHarness] = useState<HarnessOption>("cursor");
1026
1032
  const [serviceTier, setServiceTier] = useState<ServiceTierOption>("standard");
1033
+ const [thinkingMode, setThinkingMode] = useState<ThinkingModeOption>("disabled");
1027
1034
 
1028
1035
  const startEdit = () => {
1029
1036
  setModelName(invocation.runConfig?.modelName ?? "");
@@ -1035,6 +1042,9 @@ function EngineModelInlineEditor({
1035
1042
  setServiceTier(
1036
1043
  fromProtoServiceTier(invocation.runConfig?.serviceTier) ?? "standard",
1037
1044
  );
1045
+ setThinkingMode(
1046
+ fromProtoThinkingMode(invocation.runConfig?.thinkingMode) ?? "disabled",
1047
+ );
1038
1048
  setIsEditing(true);
1039
1049
  };
1040
1050
 
@@ -1056,6 +1066,8 @@ function EngineModelInlineEditor({
1056
1066
  onHarnessChange={setHarness}
1057
1067
  serviceTier={serviceTier}
1058
1068
  onServiceTierChange={setServiceTier}
1069
+ thinkingMode={thinkingMode}
1070
+ onThinkingModeChange={setThinkingMode}
1059
1071
  placeholderLabel="Platform default"
1060
1072
  disabled={isSaving}
1061
1073
  />
@@ -1065,6 +1077,7 @@ function EngineModelInlineEditor({
1065
1077
  onClick={() => {
1066
1078
  setModelName("");
1067
1079
  setServiceTier("standard");
1080
+ setThinkingMode("disabled");
1068
1081
  }}
1069
1082
  disabled={isSaving}
1070
1083
  className="stg:rounded-md stg:px-2 stg:py-1 stg:text-[0.65rem] stg:text-muted-foreground stg:hover:text-foreground stg:focus-visible:outline-none stg:focus-visible:ring-2 stg:focus-visible:ring-ring stg:disabled:pointer-events-none stg:disabled:opacity-50"
@@ -1084,6 +1097,7 @@ function EngineModelInlineEditor({
1084
1097
  modelName !== "" ? toProtoHarness(harness) : Harness.UNSPECIFIED,
1085
1098
  modelName,
1086
1099
  serviceTier,
1100
+ thinkingMode,
1087
1101
  );
1088
1102
  if (ok) setIsEditing(false);
1089
1103
  }}
@@ -1169,14 +1183,17 @@ function applyEngineModel(
1169
1183
  harness: Harness,
1170
1184
  modelName: string,
1171
1185
  serviceTier: ServiceTierOption,
1186
+ thinkingMode: ThinkingModeOption,
1172
1187
  ): void {
1173
1188
  invocation.harness = harness;
1174
1189
  invocation.runConfig = normalizeRunConfig(
1175
1190
  modelName,
1176
1191
  invocation.runConfig?.maxCostUsd ?? 0,
1177
1192
  invocation.runConfig?.maxToolRounds ?? 0,
1178
- // The tier rides the model choice: no model, no tier (#357).
1193
+ // The variant attributes ride the model choice: no model, no tier and
1194
+ // no thinking (#357/#772).
1179
1195
  modelName.trim() !== "" ? serviceTier : "standard",
1196
+ modelName.trim() !== "" ? thinkingMode : "disabled",
1180
1197
  );
1181
1198
  }
1182
1199
 
@@ -1190,6 +1207,7 @@ function applyBudget(
1190
1207
  maxCostUsd ?? 0,
1191
1208
  invocation.runConfig?.maxToolRounds ?? 0,
1192
1209
  fromProtoServiceTier(invocation.runConfig?.serviceTier) ?? "standard",
1210
+ fromProtoThinkingMode(invocation.runConfig?.thinkingMode) ?? "disabled",
1193
1211
  );
1194
1212
  }
1195
1213
 
@@ -1198,12 +1216,14 @@ function normalizeRunConfig(
1198
1216
  maxCostUsd: number,
1199
1217
  maxToolRounds: number,
1200
1218
  serviceTier: ServiceTierOption,
1219
+ thinkingMode: ThinkingModeOption,
1201
1220
  ): RunConfig | undefined {
1202
1221
  const fields: {
1203
1222
  modelName?: string;
1204
1223
  maxCostUsd?: number;
1205
1224
  maxToolRounds?: number;
1206
1225
  serviceTier?: ServiceTier;
1226
+ thinkingMode?: ThinkingMode;
1207
1227
  } = {};
1208
1228
  if (modelName.trim() !== "") fields.modelName = modelName.trim();
1209
1229
  if (maxCostUsd > 0) fields.maxCostUsd = maxCostUsd;
@@ -1211,6 +1231,8 @@ function normalizeRunConfig(
1211
1231
  // Only an active fast choice is carried — an untouched tier stays
1212
1232
  // absent, preserving the unspecified-vs-explicit ledger distinction (#357).
1213
1233
  if (serviceTier === "fast") fields.serviceTier = toProtoServiceTier(serviceTier);
1234
+ // The tier's #772 twin: only an active enabled choice is carried.
1235
+ if (thinkingMode === "enabled") fields.thinkingMode = toProtoThinkingMode(thinkingMode);
1214
1236
 
1215
1237
  return Object.keys(fields).length > 0
1216
1238
  ? create(RunConfigSchema, fields)
@@ -1429,6 +1451,9 @@ function EngineModelSummary({
1429
1451
  if (invocation?.runConfig?.serviceTier === ServiceTier.FAST) {
1430
1452
  parts.push("Fast tier");
1431
1453
  }
1454
+ if (invocation?.runConfig?.thinkingMode === ThinkingMode.ENABLED) {
1455
+ parts.push("Thinking");
1456
+ }
1432
1457
  return <span className="stg:text-sm stg:text-foreground">{parts.join(" · ")}</span>;
1433
1458
  }
1434
1459
 
@@ -16,6 +16,7 @@ import { useGitHubConnection } from "../github/useGitHubConnection.js";
16
16
  import { ModelSelector } from "../models/ModelSelector.js";
17
17
  import { toProtoHarness, type HarnessOption } from "../models/harness.js";
18
18
  import { toProtoServiceTier, type ServiceTierOption } from "../models/service-tier.js";
19
+ import { toProtoThinkingMode, type ThinkingModeOption } from "../models/thinking-mode.js";
19
20
  import { Switch } from "../switch/Switch.js";
20
21
  import { useStigmerPortalContainer } from "../portal-container.js";
21
22
  import { useWorkspaceEntries } from "../workspace/useWorkspaceEntries.js";
@@ -116,6 +117,8 @@ export function ScheduleForm({
116
117
  // is picked. No model pinned = no tier pinned (fast requires a model,
117
118
  // and the form's reset button clears both).
118
119
  const [serviceTier, setServiceTier] = useState<ServiceTierOption>("standard");
120
+ // Thinking mode: the tier's #772 twin, capability-scoped the same way.
121
+ const [thinkingMode, setThinkingMode] = useState<ThinkingModeOption>("disabled");
119
122
 
120
123
  const [budgetUsd, setBudgetUsd] = useState("");
121
124
 
@@ -152,7 +155,7 @@ export function ScheduleForm({
152
155
  if (!canSubmit || !agentRef) return;
153
156
 
154
157
  clearError();
155
- const runConfig = buildRunConfig(modelName, budgetUsd, serviceTier);
158
+ const runConfig = buildRunConfig(modelName, budgetUsd, serviceTier, thinkingMode);
156
159
  try {
157
160
  const schedule = await create({
158
161
  name: trimmedName,
@@ -195,6 +198,7 @@ export function ScheduleForm({
195
198
  modelName,
196
199
  modelHarness,
197
200
  serviceTier,
201
+ thinkingMode,
198
202
  budgetUsd,
199
203
  workspace,
200
204
  onComplete,
@@ -362,6 +366,8 @@ export function ScheduleForm({
362
366
  onHarnessChange={setModelHarness}
363
367
  serviceTier={serviceTier}
364
368
  onServiceTierChange={setServiceTier}
369
+ thinkingMode={thinkingMode}
370
+ onThinkingModeChange={setThinkingMode}
365
371
  placeholderLabel="Platform default"
366
372
  disabled={isCreating}
367
373
  />
@@ -371,6 +377,7 @@ export function ScheduleForm({
371
377
  onClick={() => {
372
378
  setModelName("");
373
379
  setServiceTier("standard");
380
+ setThinkingMode("disabled");
374
381
  }}
375
382
  disabled={isCreating}
376
383
  className={cn(
@@ -514,6 +521,7 @@ function buildRunConfig(
514
521
  modelName: string,
515
522
  budgetUsd: string,
516
523
  serviceTier: ServiceTierOption,
524
+ thinkingMode: ThinkingModeOption,
517
525
  ): RunConfigInput | undefined {
518
526
  const model = modelName.trim();
519
527
  const cost = Number.parseFloat(budgetUsd);
@@ -528,6 +536,11 @@ function buildRunConfig(
528
536
  if (serviceTier === "fast" && model !== "") {
529
537
  config.serviceTier = toProtoServiceTier(serviceTier);
530
538
  }
539
+ // The tier's #772 twin: thinking is a per-model capability, same
540
+ // only-explicit-enabled + requires-a-model contract.
541
+ if (thinkingMode === "enabled" && model !== "") {
542
+ config.thinkingMode = toProtoThinkingMode(thinkingMode);
543
+ }
531
544
 
532
545
  return Object.keys(config).length > 0 ? config : undefined;
533
546
  }
@@ -1,4 +1,5 @@
1
1
  import type { ServiceTierOption } from "../models/service-tier.js";
2
+ import type { ThinkingModeOption } from "../models/thinking-mode.js";
2
3
 
3
4
  /**
4
5
  * Owner-pinned execution config for a session surface
@@ -39,6 +40,14 @@ export interface SessionRunConfig {
39
40
  * pin is a host configuration error and throws at submit.
40
41
  */
41
42
  readonly serviceTier?: ServiceTierOption;
43
+ /**
44
+ * Thinking mode for every execution (stigmer/stigmer#772).
45
+ * `"enabled"` requires {@link modelName} under the same contract as
46
+ * {@link serviceTier}: thinking is a per-model capability (the server
47
+ * refuses it fail-closed for Auto), so a mode pin without a model pin
48
+ * is a host configuration error and throws at submit.
49
+ */
50
+ readonly thinkingMode?: ThinkingModeOption;
42
51
  }
43
52
 
44
53
  /**
@@ -56,4 +65,11 @@ export function assertValidRunConfig(runConfig: SessionRunConfig): void {
56
65
  + "dimension. Pin the model the surface should run.",
57
66
  );
58
67
  }
68
+ if (runConfig.thinkingMode === "enabled" && !runConfig.modelName) {
69
+ throw new Error(
70
+ "SessionRunConfig: thinkingMode \"enabled\" requires modelName — "
71
+ + "thinking is a per-model capability and Auto (no pinned model) has "
72
+ + "no variant dimensions. Pin the model the surface should run.",
73
+ );
74
+ }
59
75
  }
@@ -307,6 +307,7 @@ export function useNewSessionFlow(
307
307
  if (runConfig) assertValidRunConfig(runConfig);
308
308
  const pinnedModelName = runConfig?.modelName;
309
309
  const pinnedServiceTier = runConfig?.serviceTier;
310
+ const pinnedThinkingMode = runConfig?.thinkingMode;
310
311
  const contextTarget = useExecutionTarget();
311
312
  const executionTarget = options.executionTarget ?? contextTarget;
312
313
  const adapter = useRunnerAdapter();
@@ -490,6 +491,10 @@ export function useNewSessionFlow(
490
491
  serviceTier: pinnedModelName
491
492
  ? (pinnedServiceTier === "fast" ? "fast" : undefined)
492
493
  : context?.serviceTier,
494
+ // The tier's #772 twin, same pin-wins + only-explicit-enabled rule.
495
+ thinkingMode: pinnedModelName
496
+ ? (pinnedThinkingMode === "enabled" ? "enabled" : undefined)
497
+ : context?.thinkingMode,
493
498
  workspaceFileRefs: context?.workspaceFileRefs,
494
499
  autoApproveAll,
495
500
  };
@@ -584,6 +589,7 @@ export function useNewSessionFlow(
584
589
  effectiveModelId,
585
590
  pinnedModelName,
586
591
  pinnedServiceTier,
592
+ pinnedThinkingMode,
587
593
  workspace,
588
594
  mcpServerUsages,
589
595
  skillRefs,
@@ -9,15 +9,17 @@ import type { Session } from "@stigmer/protos/ai/stigmer/agentic/session/v1/api_
9
9
  import type { McpServerUsage as ProtoMcpServerUsage } from "@stigmer/protos/ai/stigmer/agentic/agent/v1/spec_pb";
10
10
  import type { WorkspaceEntry as ProtoWorkspaceEntry } from "@stigmer/protos/ai/stigmer/agentic/session/v1/workspace_pb";
11
11
  import type { ApiResourceReference as ProtoApiResourceReference } from "@stigmer/protos/ai/stigmer/commons/apiresource/io_pb";
12
- import type {
13
- AttachmentInput,
14
- EnvVarInput,
15
- McpServerUsageInput,
16
- ResourceRef,
17
- WorkspaceEntryInput,
12
+ import {
13
+ toSessionUpdateInput,
14
+ type AttachmentInput,
15
+ type EnvVarInput,
16
+ type McpServerUsageInput,
17
+ type ResourceRef,
18
+ type WorkspaceEntryInput,
18
19
  } from "@stigmer/sdk";
19
20
  import { isTerminalPhase } from "../execution/execution-phases.js";
20
21
  import type { ServiceTierOption } from "../models/service-tier.js";
22
+ import type { ThinkingModeOption } from "../models/thinking-mode.js";
21
23
  import { useStigmer } from "../hooks.js";
22
24
  import { toError } from "../internal/toError.js";
23
25
  import { useConversationStoreRef } from "../internal/store/index.js";
@@ -32,11 +34,6 @@ import { useSession } from "./useSession.js";
32
34
  import { useSessionExecutions } from "./useSessionExecutions.js";
33
35
  import { useUpdateSession } from "./useUpdateSession.js";
34
36
  import { useLocalSessionWorker } from "./useLocalSessionWorker.js";
35
- import {
36
- specWorkspaceToInput,
37
- specMcpUsagesToInput,
38
- specSkillRefsToInput,
39
- } from "./session-spec-converters.js";
40
37
 
41
38
  /**
42
39
  * Cadence for re-discovering the session's executions while the live stream
@@ -111,6 +108,16 @@ export interface SendFollowUpOptions {
111
108
  * @see {@link SharedAgentExecutionFields.serviceTier}
112
109
  */
113
110
  readonly serviceTier?: ServiceTierOption;
111
+ /**
112
+ * Thinking mode for this execution's model calls (stigmer/stigmer#772).
113
+ *
114
+ * Only set when the user actively selected `"enabled"`; `undefined`
115
+ * preserves the unspecified-vs-explicit distinction (unset resolves to
116
+ * disabled on the platform side — never the provider account default).
117
+ *
118
+ * @see {@link SharedAgentExecutionFields.thinkingMode}
119
+ */
120
+ readonly thinkingMode?: ThinkingModeOption;
114
121
  /**
115
122
  * Marks this execution as a Build-from-plan turn.
116
123
  *
@@ -674,6 +681,7 @@ export function useSessionConversation(
674
681
  attachments: options?.attachments,
675
682
  interactionMode: options?.interactionMode,
676
683
  serviceTier: options?.serviceTier,
684
+ thinkingMode: options?.thinkingMode,
677
685
  buildFromPlan: options?.buildFromPlan,
678
686
  autoApproveAll: options?.autoApproveAll,
679
687
  workspaceFileRefs: options?.workspaceFileRefs,
@@ -818,13 +826,13 @@ export function useSessionConversation(
818
826
  // ---------------------------------------------------------------------------
819
827
 
820
828
  /**
821
- * Converts the existing Session proto into a SessionInput suitable for
822
- * the update RPC (which uses replace semantics — the full spec is sent).
823
- *
824
- * For each session-level collection (workspace, MCP servers, skills):
825
- * if an override is provided, it replaces the existing value; otherwise
826
- * the current session value is preserved by converting it back to input
827
- * format.
829
+ * Builds the SessionInput for the update RPC (which uses replace
830
+ * semantics — the full spec is sent) by spreading the SDK's complete
831
+ * generated mapper and overriding only the session-level collections the
832
+ * caller provided. An override replaces the existing value; an omitted
833
+ * field keeps the fetched session's value (an empty-array override
834
+ * clears the collection normalized to absent, the mappers' canonical
835
+ * shape).
828
836
  */
829
837
  function buildUpdateInput(
830
838
  session: Session,
@@ -835,30 +843,14 @@ function buildUpdateInput(
835
843
  skillRefs?: ResourceRef[];
836
844
  },
837
845
  ) {
838
- const meta = session.metadata!;
839
- const spec = session.spec;
840
-
841
- const workspaceEntries =
842
- overrides.workspaceEntries ?? specWorkspaceToInput(spec);
843
-
844
- const mcpServerUsages =
845
- overrides.mcpServerUsages ?? specMcpUsagesToInput(spec);
846
-
847
- const skillRefs = overrides.skillRefs ?? specSkillRefsToInput(spec);
846
+ const mapped = toSessionUpdateInput(session);
847
+ const workspaceEntries = overrides.workspaceEntries ?? mapped.workspaceEntries;
848
+ const mcpServerUsages = overrides.mcpServerUsages ?? mapped.mcpServerUsages;
849
+ const skillRefs = overrides.skillRefs ?? mapped.skillRefs;
848
850
 
849
851
  return {
850
- name: meta.name,
851
- org: meta.org,
852
- agentInstanceId: overrides.agentInstanceId ?? (spec?.agentInstanceId || undefined),
853
- subject: spec?.subject || undefined,
854
- harnessStateId: spec?.harnessStateId || undefined,
855
- harness: spec?.harness,
856
- cursorMode: spec?.cursorMode,
857
- executionTarget: spec?.executionTarget,
858
- metadata:
859
- spec?.metadata && Object.keys(spec.metadata).length > 0
860
- ? { ...spec.metadata }
861
- : undefined,
852
+ ...mapped,
853
+ agentInstanceId: overrides.agentInstanceId ?? mapped.agentInstanceId,
862
854
  workspaceEntries: workspaceEntries?.length ? workspaceEntries : undefined,
863
855
  mcpServerUsages: mcpServerUsages?.length ? mcpServerUsages : undefined,
864
856
  skillRefs: skillRefs?.length ? skillRefs : undefined,
@@ -18,7 +18,7 @@ import { useSessionConversation, type UseSessionConversationReturn } from "./use
18
18
  import { resolveExecutionRuntimeEnv, type RuntimeEnvProvider } from "./runtime-env.js";
19
19
  import { useAgentRefFromSession } from "./useAgentRefFromSession.js";
20
20
  import { usePersistedModel, type UsePersistedModelReturn } from "./usePersistedModel.js";
21
- import { specMcpUsagesToInput, specSkillRefsToInput } from "./session-spec-converters.js";
21
+ import { toSessionUpdateInput } from "@stigmer/sdk";
22
22
  import type { SessionAudience } from "./audience.js";
23
23
  import { assertValidRunConfig, type SessionRunConfig } from "./run-config.js";
24
24
 
@@ -267,6 +267,7 @@ export function useSessionPageFlow(
267
267
  // callback's identity must not churn on every render (DD-010).
268
268
  const pinnedModelName = runConfig?.modelName;
269
269
  const pinnedServiceTier = runConfig?.serviceTier;
270
+ const pinnedThinkingMode = runConfig?.thinkingMode;
270
271
 
271
272
  const stigmer = useStigmer();
272
273
  const conv = useSessionConversation(sessionId, org);
@@ -401,16 +402,14 @@ export function useSessionPageFlow(
401
402
  }
402
403
  }
403
404
 
404
- // MCP server usages
405
- const mcpInputs = specMcpUsagesToInput(spec);
406
- if (mcpInputs?.length) {
407
- setMcpServerUsages(mcpInputs);
405
+ // MCP server usages and skill references, hydrated through the SDK's
406
+ // complete update-input mapper (the canonical proto → input lens).
407
+ const mapped = toSessionUpdateInput(conv.session);
408
+ if (mapped.mcpServerUsages?.length) {
409
+ setMcpServerUsages(mapped.mcpServerUsages);
408
410
  }
409
-
410
- // Skill references
411
- const skillInputs = specSkillRefsToInput(spec);
412
- if (skillInputs?.length) {
413
- setSkillRefs(skillInputs);
411
+ if (mapped.skillRefs?.length) {
412
+ setSkillRefs(mapped.skillRefs);
414
413
  }
415
414
  }, [conv.session, workspace]);
416
415
 
@@ -480,6 +479,10 @@ export function useSessionPageFlow(
480
479
  serviceTier: pinnedModelName
481
480
  ? (pinnedServiceTier === "fast" ? "fast" : undefined)
482
481
  : context?.serviceTier,
482
+ // The tier's #772 twin, same pin-wins + only-explicit-enabled rule.
483
+ thinkingMode: pinnedModelName
484
+ ? (pinnedThinkingMode === "enabled" ? "enabled" : undefined)
485
+ : context?.thinkingMode,
483
486
  buildFromPlan: context?.buildFromPlan,
484
487
  // Sourced from the session-scoped preference set at the approval gate,
485
488
  // not from the composer (the pre-arm toggle was removed).
@@ -490,7 +493,7 @@ export function useSessionPageFlow(
490
493
 
491
494
  sessionVariables.clear();
492
495
  },
493
- [conv.sendFollowUp, modelId, pinnedModelName, pinnedServiceTier, workspace, mcpServerUsages, skillRefs, sessionVariables.clear, resolution, agentRef, sessionInstanceId, stigmer, autoApproveAll, getRuntimeEnv],
496
+ [conv.sendFollowUp, modelId, pinnedModelName, pinnedServiceTier, pinnedThinkingMode, workspace, mcpServerUsages, skillRefs, sessionVariables.clear, resolution, agentRef, sessionInstanceId, stigmer, autoApproveAll, getRuntimeEnv],
494
497
  );
495
498
 
496
499
  // -------------------------------------------------------------------------
@@ -25,40 +25,34 @@ export interface UseUpdateSessionReturn {
25
25
  * by the backend to identify the resource) and all spec fields.
26
26
  *
27
27
  * **Full-replace semantics.** The backend replaces the entire spec with
28
- * what you send — there is no field mask. Round-trip every spec field
29
- * you do not intend to change, *including `metadata`*: an update built
30
- * from a reconstructed partial spec silently wipes the fields it omits
31
- * (workspace entries, MCP servers, and `stigmer.ai/*` metadata keys such
32
- * as the embedder session context). To change only the subject, prefer
33
- * the field-level `session.updateSubject()` RPC instead of this hook.
28
+ * what you send — there is no field mask. Spread the SDK's complete
29
+ * `toSessionUpdateInput()` mapper and override only the fields you
30
+ * change: an update built from a reconstructed partial spec silently
31
+ * wipes the fields it omits (workspace entries, MCP servers, and
32
+ * `stigmer.ai/*` metadata keys such as the embedder session context).
33
+ * To change only the subject, prefer the field-level
34
+ * `session.updateSubject()` RPC instead of this hook.
34
35
  *
35
36
  * Typically composed into higher-level hooks like
36
- * {@link useSessionConversation} (whose update path round-trips the
37
- * fetched spec) rather than used directly. Platform builders who need
38
- * direct session mutation can use this hook standalone.
37
+ * {@link useSessionConversation} (whose update path spreads the mapper
38
+ * over a freshly fetched session) rather than used directly. Platform
39
+ * builders who need direct session mutation can use this hook
40
+ * standalone.
39
41
  *
40
42
  * @example
41
43
  * ```tsx
44
+ * import { toSessionUpdateInput } from "@stigmer/sdk";
45
+ *
42
46
  * function TagSession({ session }: { session: Session }) {
43
47
  * const { update, isUpdating } = useUpdateSession();
44
48
  *
45
49
  * async function handleTag() {
46
- * const spec = session.spec;
50
+ * const mapped = toSessionUpdateInput(session);
47
51
  * await update({
48
- * name: session.metadata!.name,
49
- * org: session.metadata!.org,
50
- * // Full replace: carry over every fetched spec field...
51
- * agentInstanceId: spec?.agentInstanceId,
52
- * subject: spec?.subject,
53
- * harnessStateId: spec?.harnessStateId,
54
- * harness: spec?.harness,
55
- * cursorMode: spec?.cursorMode,
56
- * executionTarget: spec?.executionTarget,
57
- * // ...including the spec lists (workspaceEntries, mcpServerUsages,
58
- * // skillRefs), converted from the fetched proto exactly as
59
- * // useSessionConversation's update path does...
60
- * // ...then apply the one change on top of the carried metadata.
61
- * metadata: { ...spec?.metadata, "acme/reviewed": "true" },
52
+ * ...mapped,
53
+ * // Nested values follow the same rule: spread the mapper's
54
+ * // complete value, then apply the one change on top.
55
+ * metadata: { ...mapped.metadata, "acme/reviewed": "true" },
62
56
  * });
63
57
  * }
64
58
  *
@@ -24,15 +24,17 @@ interface FormFieldEntry {
24
24
  enumValues: string;
25
25
  }
26
26
 
27
- // HUMAN_INPUT_TIMEOUT_ESCALATE is deliberately absent: the proto declares it
28
- // but no runtime exists, and the server validator refuses it at apply
29
- // (stigmer/stigmer#779). The old option also wrote an `escalation_task` field
30
- // that HumanInputTaskConfig never had, so every config it produced failed
31
- // the server's strict decode.
27
+ // ESCALATE carries the outcome-by-name contract (stigmer/stigmer#781): the
28
+ // timeout resolves to the outcome NAMED "escalate" and follows its routing,
29
+ // so the gate must declare that outcome no extra config fields (the
30
+ // pre-#779 option wrote an `escalation_task` field the proto never had).
31
+ // The builder hints when the outcome is missing; the server validator is
32
+ // the enforcement.
32
33
  const TIMEOUT_POLICY_OPTIONS = [
33
34
  { value: "HUMAN_INPUT_TIMEOUT_FAIL", label: "Fail — task errors on timeout" },
34
35
  { value: "HUMAN_INPUT_TIMEOUT_APPROVE", label: "Auto-approve — proceed as approved" },
35
36
  { value: "HUMAN_INPUT_TIMEOUT_DENY", label: "Auto-deny — proceed as denied" },
37
+ { value: "HUMAN_INPUT_TIMEOUT_ESCALATE", label: "Escalate — route via the 'escalate' outcome" },
36
38
  ] as const;
37
39
 
38
40
  const TIMEOUT_UNITS = [
@@ -111,6 +113,7 @@ export const ApprovalFormBuilder = memo(function ApprovalFormBuilder({
111
113
  <TimeoutSection
112
114
  timeout={typeof cfg.timeout === "number" ? cfg.timeout : 0}
113
115
  onTimeout={typeof cfg.on_timeout === "string" ? cfg.on_timeout : ""}
116
+ hasEscalateOutcome={extractOutcomes(cfg).some((o) => o.name === "escalate")}
114
117
  onUpdateConfig={onUpdateConfig}
115
118
  />
116
119
  <StringListSection
@@ -621,10 +624,12 @@ function FormFieldRow({
621
624
  function TimeoutSection({
622
625
  timeout,
623
626
  onTimeout,
627
+ hasEscalateOutcome,
624
628
  onUpdateConfig,
625
629
  }: {
626
630
  timeout: number;
627
631
  onTimeout: string;
632
+ hasEscalateOutcome: boolean;
628
633
  onUpdateConfig: (fieldPath: string, value: unknown) => void;
629
634
  }) {
630
635
  const bestUnit = useMemo(() => {
@@ -703,6 +708,16 @@ function TimeoutSection({
703
708
  <option key={opt.value} value={opt.value}>{opt.label}</option>
704
709
  ))}
705
710
  </select>
711
+ {onTimeout === "HUMAN_INPUT_TIMEOUT_ESCALATE" && !hasEscalateOutcome && (
712
+ <p
713
+ role="alert"
714
+ className="stg:text-[10px] stg:text-[var(--stgm-warning,#d97706)]"
715
+ >
716
+ Escalate needs an outcome named &quot;escalate&quot; with routing —
717
+ the timeout resolves to it. Add the outcome above, or the server
718
+ will reject this workflow.
719
+ </p>
720
+ )}
706
721
  </div>
707
722
  )}
708
723
 
@@ -9,7 +9,7 @@ import { ValidationState } from "@stigmer/protos/ai/stigmer/agentic/workflow/v1/
9
9
  import type { WorkflowInput } from "@stigmer/sdk";
10
10
  import { useWorkflow } from "./useWorkflow.js";
11
11
  import { useUpdateWorkflow } from "./useUpdateWorkflow.js";
12
- import { workflowToInput } from "./internal/workflowToInput.js";
12
+ import { toWorkflowUpdateInput } from "@stigmer/sdk";
13
13
  import { useWorkflowExecutionList } from "./useWorkflowExecutionList.js";
14
14
  import { useWorkflowDashboardSummary } from "./useWorkflowDashboardSummary.js";
15
15
  import { WorkflowOverviewGraph } from "./WorkflowOverviewGraph.js";
@@ -189,7 +189,7 @@ export function WorkflowDetailView({
189
189
  value: WorkflowInput[K],
190
190
  ): Promise<boolean> => {
191
191
  if (!workflow) return false;
192
- const input = workflowToInput(workflow);
192
+ const input = toWorkflowUpdateInput(workflow);
193
193
  (input as unknown as Record<string, unknown>)[field] = value;
194
194
  try {
195
195
  const updated = await update(input);