mastracode 0.45.0-alpha.7 → 0.45.0

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.
@@ -50,6 +50,7 @@ let _mastra_code_sdk_thinking = require("@mastra/code-sdk/thinking");
50
50
  let _mastra_code_sdk_hooks_index = require("@mastra/code-sdk/hooks/index");
51
51
  let _mastra_code_sdk_utils_open_url = require("@mastra/code-sdk/utils/open-url");
52
52
  let _mastra_code_sdk_utils_errors = require("@mastra/code-sdk/utils/errors");
53
+ let _mastra_code_sdk_onboarding_packs = require("@mastra/code-sdk/onboarding/packs");
53
54
  let _mastra_core_workspace = require("@mastra/core/workspace");
54
55
  let _mastra_code_sdk_utils_plans = require("@mastra/code-sdk/utils/plans");
55
56
  let _mastra_core_tools = require("@mastra/core/tools");
@@ -68,7 +69,6 @@ let cli_highlight = require("cli-highlight");
68
69
  let _mastra_code_sdk_permissions = require("@mastra/code-sdk/permissions");
69
70
  let jsonriver = require("jsonriver");
70
71
  let util = require("util");
71
- let _mastra_code_sdk_onboarding_packs = require("@mastra/code-sdk/onboarding/packs");
72
72
  let _mastra_code_sdk_clipboard_index = require("@mastra/code-sdk/clipboard/index");
73
73
  let _mastra_code_sdk_onboarding_custom_packs = require("@mastra/code-sdk/onboarding/custom-packs");
74
74
  let _mastra_code_sdk_onboarding_custom_providers = require("@mastra/code-sdk/onboarding/custom-providers");
@@ -85,7 +85,6 @@ let _mastra_code_sdk_workflows_service = require("@mastra/code-sdk/workflows/ser
85
85
  let _mastra_core_request_context = require("@mastra/core/request-context");
86
86
  let _mastra_code_sdk_utils_maintenance_lock = require("@mastra/code-sdk/utils/maintenance-lock");
87
87
  let _mastra_code_sdk_utils_storage_maintenance = require("@mastra/code-sdk/utils/storage-maintenance");
88
- let _mastra_code_sdk_agents_model = require("@mastra/code-sdk/agents/model");
89
88
  let url = require("url");
90
89
  let _mastra_code_sdk_utils_slash_command_loader = require("@mastra/code-sdk/utils/slash-command-loader");
91
90
  //#region src/commit-attribution.ts
@@ -700,22 +699,21 @@ const OM_EVENT_BY_TYPE = {
700
699
  "data-om-observation-failed": "failed",
701
700
  "data-om-thread-update": "thread-title"
702
701
  };
703
- const PACK_FALLBACK_PART_TYPE = "data-mastracode-pack-fallback";
704
702
  function packFallbackRenderPart(data) {
705
703
  if (!data || typeof data !== "object") return null;
706
704
  const record = data;
707
705
  const endpoint = (value) => {
708
706
  if (!value || typeof value !== "object") return null;
709
707
  const entry = value;
710
- if (typeof entry.packId !== "string" || typeof entry.label !== "string") return null;
708
+ if (typeof entry.entryId !== "string" || typeof entry.label !== "string") return null;
711
709
  return {
712
- packId: entry.packId,
710
+ entryId: entry.entryId,
713
711
  label: entry.label
714
712
  };
715
713
  };
716
714
  const from = endpoint(record.from);
717
715
  const to = endpoint(record.to);
718
- if (!from || !to || !(0, _mastra_code_sdk_auth_account_rotation_processor.isPackFallbackReason)(record.reason)) return null;
716
+ if (!from || !to || !(0, _mastra_code_sdk_auth_account_rotation_processor.isModelFallbackReason)(record.reason)) return null;
719
717
  return {
720
718
  kind: "pack-fallback",
721
719
  from,
@@ -882,7 +880,7 @@ function getAssistantRenderParts(message) {
882
880
  if (switchPart) out.push(switchPart);
883
881
  break;
884
882
  }
885
- if (partType === PACK_FALLBACK_PART_TYPE) {
883
+ if (partType === _mastra_code_sdk_auth_account_rotation_processor.MODEL_FALLBACK_PART_TYPE) {
886
884
  const hopPart = packFallbackRenderPart(part.data);
887
885
  if (hopPart) out.push(hopPart);
888
886
  break;
@@ -2296,7 +2294,6 @@ async function handleGoalCommand(ctx, args) {
2296
2294
  return;
2297
2295
  }
2298
2296
  }
2299
- state.planStartedGoalId = void 0;
2300
2297
  if (state.session.run.isRunning() || state.session.suspensions.hasPending()) {
2301
2298
  state.activeInlineQuestion = void 0;
2302
2299
  state.pendingInlineQuestions.length = 0;
@@ -2497,7 +2494,6 @@ async function setGoal(ctx, objective, judgeModelId, maxTurns) {
2497
2494
  ctx.showError("Failed to set goal.");
2498
2495
  return null;
2499
2496
  }
2500
- state.planStartedGoalId = void 0;
2501
2497
  await goalManager.saveToThread(state);
2502
2498
  ctx.updateStatusLine();
2503
2499
  return goal;
@@ -5157,6 +5153,216 @@ function showTextStatus(ctx) {
5157
5153
  ctx.showInfo(lines.join("\n"));
5158
5154
  }
5159
5155
  //#endregion
5156
+ //#region src/tui/model-packs/apply.ts
5157
+ const packApplicationVersions = /* @__PURE__ */ new WeakMap();
5158
+ const packApplicationQueues = /* @__PURE__ */ new WeakMap();
5159
+ function beginPackApplication(ctx, modeId, expectedThreadId) {
5160
+ const session = ctx.state.session;
5161
+ const version = (packApplicationVersions.get(session) ?? 0) + 1;
5162
+ packApplicationVersions.set(session, version);
5163
+ const isCurrent = () => packApplicationVersions.get(session) === version && ctx.state.session.mode.get() === modeId && ctx.state.session.thread.getId() === expectedThreadId;
5164
+ const previous = packApplicationQueues.get(session) ?? Promise.resolve();
5165
+ return {
5166
+ isCurrent,
5167
+ run: (apply) => {
5168
+ const result = previous.catch(() => void 0).then(apply);
5169
+ packApplicationQueues.set(session, result.then(() => void 0, () => void 0));
5170
+ return result;
5171
+ }
5172
+ };
5173
+ }
5174
+ function modelRoutesMatch(current, expected) {
5175
+ if (!current || typeof current !== "object") return false;
5176
+ const entries = current.entries;
5177
+ if (!Array.isArray(entries) || entries.length !== expected.entries.length) return false;
5178
+ return expected.entries.every((entry, index) => {
5179
+ const currentEntry = entries[index];
5180
+ if (!currentEntry || typeof currentEntry !== "object") return false;
5181
+ const candidate = currentEntry;
5182
+ return candidate.id === entry.id && candidate.label === entry.label && candidate.modelId === entry.modelId && candidate.accountId === entry.accountId && candidate.memoryModelId === entry.memoryModelId;
5183
+ });
5184
+ }
5185
+ function listResolvableModePacks(settings) {
5186
+ return [...(0, _mastra_code_sdk_onboarding_packs.listBuiltinModePacks)(), ...settings.customModelPacks.map((pack) => ({
5187
+ id: `custom:${pack.name}`,
5188
+ name: pack.name,
5189
+ description: "Saved custom pack",
5190
+ models: {
5191
+ build: pack.models.build ?? "",
5192
+ plan: pack.models.plan ?? "",
5193
+ fast: pack.models.fast ?? "",
5194
+ ...pack.models.memory ? { memory: pack.models.memory } : {}
5195
+ }
5196
+ }))];
5197
+ }
5198
+ function resolvePackSelection(settings, packId, modeId) {
5199
+ const packs = listResolvableModePacks(settings);
5200
+ const packsById = new Map(packs.map((pack) => [pack.id, pack]));
5201
+ const pack = packsById.get(packId);
5202
+ if (!pack) return void 0;
5203
+ const packModels = (0, _mastra_code_sdk_onboarding_settings.resolveModePackModels)(settings, pack);
5204
+ const modelId = packModels[modeId];
5205
+ if (!modelId) return void 0;
5206
+ const subagentModels = Object.fromEntries(Object.entries({
5207
+ explore: "fast",
5208
+ plan: "plan",
5209
+ execute: "build"
5210
+ }).flatMap(([agentType, subagentModeId]) => {
5211
+ const subagentModelId = packModels[subagentModeId];
5212
+ return subagentModelId ? [[agentType, subagentModelId]] : [];
5213
+ }));
5214
+ const entries = (0, _mastra_code_sdk_onboarding_packs.resolveModePackFallbackChain)(settings.models.packFallbacks, packId, settings.customModelPacks).flatMap((routeId) => {
5215
+ const routePack = packsById.get(routeId);
5216
+ if (!routePack) return [];
5217
+ const routeModels = (0, _mastra_code_sdk_onboarding_settings.resolveModePackModels)(settings, routePack);
5218
+ const routeModelId = routeModels[modeId];
5219
+ if (!routeModelId) return [];
5220
+ const accountId = settings.models.packAccountPreferences?.[routeId]?.[routeModelId];
5221
+ return [{
5222
+ id: routeId,
5223
+ label: routePack.name,
5224
+ modelId: routeModelId,
5225
+ ...accountId ? { accountId } : {},
5226
+ ...routeModels.memory ? { memoryModelId: routeModels.memory } : {}
5227
+ }];
5228
+ });
5229
+ const memoryModelId = packModels.memory;
5230
+ return {
5231
+ modelId,
5232
+ subagentModels,
5233
+ ...memoryModelId ? {
5234
+ observerModelId: memoryModelId,
5235
+ reflectorModelId: memoryModelId
5236
+ } : {},
5237
+ modelRoute: { entries }
5238
+ };
5239
+ }
5240
+ async function applyPackToSession(ctx, packId, options = {}) {
5241
+ const settings = options.settings ?? (0, _mastra_code_sdk_onboarding_settings.loadSettings)();
5242
+ const modeId = options.modeId ?? ctx.state.session.mode.get();
5243
+ const expectedThreadId = "expectedThreadId" in options ? options.expectedThreadId : ctx.state.session.thread.getId();
5244
+ const selection = resolvePackSelection(settings, packId, modeId);
5245
+ if (!selection) throw new Error(`Model pack "${packId}" has no model for ${modeId} mode`);
5246
+ const application = beginPackApplication(ctx, modeId, expectedThreadId);
5247
+ return application.run(async () => {
5248
+ const cancelled = () => ({
5249
+ ...selection,
5250
+ applied: false
5251
+ });
5252
+ if (!application.isCurrent()) return cancelled();
5253
+ try {
5254
+ if (expectedThreadId) {
5255
+ await ctx.state.session.thread.setSetting({
5256
+ key: _mastra_code_sdk_onboarding_settings.THREAD_ACTIVE_MODEL_PACK_ID_KEY,
5257
+ value: packId
5258
+ });
5259
+ if (!application.isCurrent()) return cancelled();
5260
+ if (options.clearPendingFallback !== false) {
5261
+ await ctx.state.session.thread.setSetting({
5262
+ key: _mastra_code_sdk_auth_account_rotation_processor.MODEL_FALLBACK_STATE_KEY,
5263
+ value: void 0
5264
+ });
5265
+ if (!application.isCurrent()) return cancelled();
5266
+ }
5267
+ }
5268
+ await ctx.state.session.model.switch(selection.modelId, { ...options.thinkingLevel !== void 0 ? { thinkingLevel: options.thinkingLevel } : {} });
5269
+ if (!application.isCurrent()) return cancelled();
5270
+ for (const [agentType, modelId] of Object.entries(selection.subagentModels)) {
5271
+ await ctx.state.session.subagents.model.set({
5272
+ modelId,
5273
+ agentType
5274
+ });
5275
+ if (!application.isCurrent()) return cancelled();
5276
+ }
5277
+ if (selection.observerModelId) {
5278
+ await ctx.state.session.om.observer.switchModel({ modelId: selection.observerModelId });
5279
+ if (!application.isCurrent()) return cancelled();
5280
+ }
5281
+ if (selection.reflectorModelId) {
5282
+ await ctx.state.session.om.reflector.switchModel({ modelId: selection.reflectorModelId });
5283
+ if (!application.isCurrent()) return cancelled();
5284
+ }
5285
+ await ctx.state.session.state.set({
5286
+ modelRoute: selection.modelRoute,
5287
+ ...options.clearPendingFallback === false ? {} : { [_mastra_code_sdk_auth_account_rotation_processor.MODEL_FALLBACK_STATE_KEY]: null }
5288
+ });
5289
+ if (!application.isCurrent()) return cancelled();
5290
+ await options.afterApply?.(selection);
5291
+ return {
5292
+ ...selection,
5293
+ applied: application.isCurrent()
5294
+ };
5295
+ } catch (error) {
5296
+ if (application.isCurrent()) await options.onError?.(error);
5297
+ throw error;
5298
+ }
5299
+ });
5300
+ }
5301
+ async function resolveActivePackId(ctx, settings) {
5302
+ const threadId = ctx.state.session.thread.getId();
5303
+ const thread = threadId ? (await ctx.state.session.thread.list()).find((item) => item.id === threadId) : void 0;
5304
+ if (ctx.state.session.thread.getId() !== threadId) return void 0;
5305
+ return {
5306
+ packId: (0, _mastra_code_sdk_onboarding_settings.resolveThreadActiveModelPackId)(settings, listResolvableModePacks(settings), thread?.metadata),
5307
+ threadId
5308
+ };
5309
+ }
5310
+ async function applyCurrentThreadPack(ctx, options = {}) {
5311
+ const settings = (0, _mastra_code_sdk_onboarding_settings.loadSettings)();
5312
+ const modeId = options.modeId ?? ctx.state.session.mode.get();
5313
+ const resolution = options.packId === void 0 ? await resolveActivePackId(ctx, settings) : {
5314
+ packId: options.packId,
5315
+ threadId: ctx.state.session.thread.getId()
5316
+ };
5317
+ if (!resolution) return { applied: false };
5318
+ if (resolution.packId && resolvePackSelection(settings, resolution.packId, modeId)) return applyPackToSession(ctx, resolution.packId, {
5319
+ modeId,
5320
+ settings,
5321
+ expectedThreadId: resolution.threadId
5322
+ });
5323
+ const application = beginPackApplication(ctx, modeId, resolution.threadId);
5324
+ return application.run(async () => {
5325
+ if (!application.isCurrent()) return { applied: false };
5326
+ if (options.applyModeDefault !== false) {
5327
+ const mode = ctx.state.controller.listModes().find((item) => item.id === modeId);
5328
+ const modelId = settings.models.modeDefaults[modeId] ?? mode?.defaultModelId;
5329
+ if (modelId && ctx.state.session.model.get() !== modelId) {
5330
+ await ctx.state.session.model.switch(modelId);
5331
+ if (!application.isCurrent()) return { applied: false };
5332
+ }
5333
+ }
5334
+ if (resolution.threadId) {
5335
+ await ctx.state.session.thread.setSetting({
5336
+ key: _mastra_code_sdk_auth_account_rotation_processor.MODEL_FALLBACK_STATE_KEY,
5337
+ value: void 0
5338
+ });
5339
+ if (!application.isCurrent()) return { applied: false };
5340
+ }
5341
+ await ctx.state.session.state.set({
5342
+ modelRoute: void 0,
5343
+ [_mastra_code_sdk_auth_account_rotation_processor.MODEL_FALLBACK_STATE_KEY]: null
5344
+ });
5345
+ return { applied: application.isCurrent() };
5346
+ });
5347
+ }
5348
+ async function switchModeWithPack(ctx, modeId) {
5349
+ await ctx.state.session.mode.switch({ modeId });
5350
+ if (!(await applyCurrentThreadPack(ctx, { modeId })).applied) throw new Error("Mode switch was superseded before its model selection completed.");
5351
+ }
5352
+ async function reconcilePackAfterModeChange(ctx, modeId) {
5353
+ const settings = (0, _mastra_code_sdk_onboarding_settings.loadSettings)();
5354
+ const resolution = await resolveActivePackId(ctx, settings);
5355
+ if (!resolution?.packId || ctx.state.session.mode.get() !== modeId) return;
5356
+ const selection = resolvePackSelection(settings, resolution.packId, modeId);
5357
+ if (!selection) return;
5358
+ const state = ctx.state.session.state.get();
5359
+ if (ctx.state.session.model.get() === selection.modelId && modelRoutesMatch(state.modelRoute, selection.modelRoute) && state[_mastra_code_sdk_auth_account_rotation_processor.MODEL_FALLBACK_STATE_KEY] == null) return;
5360
+ await applyPackToSession(ctx, resolution.packId, {
5361
+ modeId,
5362
+ expectedThreadId: resolution.threadId
5363
+ });
5364
+ }
5365
+ //#endregion
5160
5366
  //#region src/tui/commands/mode.ts
5161
5367
  function applyCurrentModeColorToRenderedTools(ctx) {
5162
5368
  const color = ctx.state.session.mode.resolve().metadata?.color;
@@ -5171,7 +5377,7 @@ async function handleModeCommand(ctx, args) {
5171
5377
  return;
5172
5378
  }
5173
5379
  if (args[0]) try {
5174
- await ctx.state.session.mode.switch({ modeId: args[0] });
5380
+ await switchModeWithPack(ctx, args[0]);
5175
5381
  applyCurrentModeColorToRenderedTools(ctx);
5176
5382
  } catch (err) {
5177
5383
  ctx.showError(`Failed to switch mode: ${err instanceof Error ? err.message : String(err)}`);
@@ -5285,11 +5491,14 @@ var AccountSwitchNoticeComponent = class extends _earendil_works_pi_tui.Containe
5285
5491
  return "other";
5286
5492
  }
5287
5493
  };
5494
+ function packFallbackNoticeText(data) {
5495
+ return (0, _mastra_code_sdk_auth_account_rotation_processor.modelFallbackNoticeText)(data).replace("Switched model route:", "Switched model pack:");
5496
+ }
5288
5497
  var PackFallbackNoticeComponent = class extends _earendil_works_pi_tui.Container {
5289
5498
  textChild;
5290
5499
  constructor(data) {
5291
5500
  super();
5292
- this.textChild = new _earendil_works_pi_tui.Text(theme.fg("muted", ` ⇄ ${(0, _mastra_code_sdk_auth_account_rotation_processor.packFallbackNoticeText)(data)}`), 0, 0);
5501
+ this.textChild = new _earendil_works_pi_tui.Text(theme.fg("muted", ` ⇄ ${packFallbackNoticeText(data)}`), 0, 0);
5293
5502
  this.addChild(this.textChild);
5294
5503
  }
5295
5504
  getChatSpacingKind() {
@@ -12744,7 +12953,6 @@ async function handleSandboxCommand(ctx, args) {
12744
12953
  //#region src/tui/commands/models.ts
12745
12954
  async function switchCurrentModeModel(ctx, selectedModelId) {
12746
12955
  const modeId = ctx.state.session.mode.get();
12747
- const modeSettingKey = `modeModelId_${modeId}`;
12748
12956
  const settings = (0, _mastra_code_sdk_onboarding_settings.loadSettings)();
12749
12957
  const nextSettings = structuredClone(settings);
12750
12958
  nextSettings.models.modePackOverrides ??= {};
@@ -12754,12 +12962,11 @@ async function switchCurrentModeModel(ctx, selectedModelId) {
12754
12962
  const threadId = ctx.state.session.thread.getId();
12755
12963
  const thread = threadId ? (await ctx.state.session.thread.list()).find((item) => item.id === threadId) : void 0;
12756
12964
  const threadSettings = (0, _mastra_code_sdk_onboarding_settings.parseThreadSettings)(thread?.metadata);
12757
- const previousModeSetting = thread?.metadata?.[modeSettingKey];
12758
12965
  const previousPackSetting = thread?.metadata?.[_mastra_code_sdk_onboarding_settings.THREAD_ACTIVE_MODEL_PACK_ID_KEY];
12759
12966
  const previousFallbackStatus = thread?.metadata?.[_mastra_code_sdk_onboarding_settings.THREAD_FALLBACK_STATUS_KEY];
12760
- const previousPendingFallback = thread?.metadata?.[_mastra_code_sdk_auth_account_rotation_processor.PACK_FALLBACK_STATE_KEY];
12761
- const previousSessionState = ctx.state.session.state?.get?.();
12762
- const previousSessionPackId = previousSessionState?.activeModelPackId;
12967
+ const previousPendingFallback = thread?.metadata?.[_mastra_code_sdk_auth_account_rotation_processor.MODEL_FALLBACK_STATE_KEY];
12968
+ const previousSessionState = ctx.state.session.state.get();
12969
+ const previousFallbackUi = ctx.state.fallbackStatus;
12763
12970
  const activePackId = threadSettings.activeModelPackId ?? nextSettings.models.activeModelPackId;
12764
12971
  const builtinPack = activePackId ? (0, _mastra_code_sdk_onboarding_packs.getBuiltinModePack)(activePackId) : void 0;
12765
12972
  const customPack = activePackId?.startsWith("custom:") ? nextSettings.customModelPacks.find((item) => `custom:${item.name}` === activePackId) : void 0;
@@ -12770,10 +12977,8 @@ async function switchCurrentModeModel(ctx, selectedModelId) {
12770
12977
  const effectivePackModels = activePack ? (0, _mastra_code_sdk_onboarding_settings.resolveModePackModels)(nextSettings, activePack) : {};
12771
12978
  const modeModels = {};
12772
12979
  for (const item of modes) {
12773
- const persistedModelId = threadSettings.modeModelIds[item.id];
12774
12980
  const fallbackModelId = effectivePackModels[item.id] ?? nextSettings.models.modeDefaults[item.id] ?? item.defaultModelId;
12775
- if (persistedModelId) modeModels[item.id] = persistedModelId;
12776
- else if (fallbackModelId) modeModels[item.id] = fallbackModelId;
12981
+ if (fallbackModelId) modeModels[item.id] = fallbackModelId;
12777
12982
  }
12778
12983
  modeModels[modeId] = modelId;
12779
12984
  let nextPackId;
@@ -12802,82 +13007,73 @@ async function switchCurrentModeModel(ctx, selectedModelId) {
12802
13007
  nextSettings.models.activeModelPackId = nextPackId;
12803
13008
  nextSettings.models.modeDefaults = modeModels;
12804
13009
  }
12805
- let modeSettingSaved = false;
12806
- let packSettingSaved = false;
12807
- let sessionPackSaved = false;
12808
- let fallbackStatusCleared = false;
12809
- let pendingThreadFallbackCleared = false;
12810
- let pendingSessionFallbackCleared = false;
12811
- let globalSettingsWriteStarted = false;
12812
- try {
12813
- await ctx.state.session.thread.setSetting({
12814
- key: modeSettingKey,
12815
- value: modelId
12816
- });
12817
- modeSettingSaved = true;
12818
- if (await ctx.state.session.thread.getSetting({ key: modeSettingKey }) !== modelId) throw new Error(`Could not save the ${modeId} mode model`);
12819
- await ctx.state.session.thread.setSetting({
12820
- key: _mastra_code_sdk_onboarding_settings.THREAD_ACTIVE_MODEL_PACK_ID_KEY,
12821
- value: nextPackId
12822
- });
12823
- packSettingSaved = true;
12824
- if (await ctx.state.session.thread.getSetting({ key: _mastra_code_sdk_onboarding_settings.THREAD_ACTIVE_MODEL_PACK_ID_KEY }) !== nextPackId) throw new Error("Could not save the active model pack");
12825
- globalSettingsWriteStarted = true;
12826
- (0, _mastra_code_sdk_onboarding_settings.saveSettings)(nextSettings);
12827
- await ctx.state.session.model.switch({
12828
- modelId,
12829
- scope: "global"
12830
- });
12831
- await ctx.state.session.state.set({ activeModelPackId: nextPackId });
12832
- sessionPackSaved = true;
12833
- await ctx.state.session.thread.setSetting({
12834
- key: _mastra_code_sdk_onboarding_settings.THREAD_FALLBACK_STATUS_KEY,
12835
- value: void 0
12836
- });
12837
- fallbackStatusCleared = true;
12838
- await ctx.state.session.thread.setSetting({
12839
- key: _mastra_code_sdk_auth_account_rotation_processor.PACK_FALLBACK_STATE_KEY,
12840
- value: void 0
12841
- });
12842
- pendingThreadFallbackCleared = true;
12843
- await ctx.state.session.state.set({ [_mastra_code_sdk_auth_account_rotation_processor.PACK_FALLBACK_STATE_KEY]: null });
12844
- pendingSessionFallbackCleared = true;
12845
- } catch (error) {
12846
- if (globalSettingsWriteStarted) try {
12847
- (0, _mastra_code_sdk_onboarding_settings.saveSettings)(settings);
12848
- } catch {}
12849
- const rollbacks = [];
12850
- if (sessionPackSaved) rollbacks.push(ctx.state.session.state.set({ activeModelPackId: previousSessionPackId }));
12851
- if (pendingThreadFallbackCleared) rollbacks.push(ctx.state.session.thread.setSetting({
12852
- key: _mastra_code_sdk_auth_account_rotation_processor.PACK_FALLBACK_STATE_KEY,
12853
- value: previousPendingFallback
12854
- }));
12855
- if (pendingSessionFallbackCleared) {
12856
- const previousSessionPending = previousSessionState?.[_mastra_code_sdk_auth_account_rotation_processor.PACK_FALLBACK_STATE_KEY];
12857
- rollbacks.push(ctx.state.session.state.set({ [_mastra_code_sdk_auth_account_rotation_processor.PACK_FALLBACK_STATE_KEY]: previousSessionPending === void 0 ? null : previousSessionPending }));
13010
+ await applyPackToSession(ctx, nextPackId, {
13011
+ modeId,
13012
+ settings: nextSettings,
13013
+ expectedThreadId: threadId,
13014
+ afterApply: async () => {
13015
+ (0, _mastra_code_sdk_onboarding_settings.saveSettings)(nextSettings);
13016
+ if (await ctx.state.session.thread.getSetting({ key: _mastra_code_sdk_onboarding_settings.THREAD_ACTIVE_MODEL_PACK_ID_KEY }) !== nextPackId) throw new Error("Could not save the active model pack");
13017
+ await ctx.state.session.thread.setSetting({
13018
+ key: _mastra_code_sdk_onboarding_settings.THREAD_FALLBACK_STATUS_KEY,
13019
+ value: void 0
13020
+ });
13021
+ ctx.state.fallbackStatus = void 0;
13022
+ ctx.updateStatusLine();
13023
+ ctx.showInfo(`Switched ${modeId} mode to ${modelId}`);
13024
+ },
13025
+ onError: async () => {
13026
+ try {
13027
+ (0, _mastra_code_sdk_onboarding_settings.saveSettings)(settings);
13028
+ } catch {}
13029
+ await Promise.allSettled([
13030
+ ctx.state.session.thread.setSetting({
13031
+ key: _mastra_code_sdk_onboarding_settings.THREAD_ACTIVE_MODEL_PACK_ID_KEY,
13032
+ value: previousPackSetting
13033
+ }),
13034
+ ctx.state.session.thread.setSetting({
13035
+ key: _mastra_code_sdk_onboarding_settings.THREAD_FALLBACK_STATUS_KEY,
13036
+ value: previousFallbackStatus
13037
+ }),
13038
+ ctx.state.session.thread.setSetting({
13039
+ key: _mastra_code_sdk_auth_account_rotation_processor.MODEL_FALLBACK_STATE_KEY,
13040
+ value: previousPendingFallback
13041
+ }),
13042
+ ctx.state.session.thread.setSetting({
13043
+ key: "subagentModelId_explore",
13044
+ value: previousSessionState.subagentModelId_explore
13045
+ }),
13046
+ ctx.state.session.thread.setSetting({
13047
+ key: "subagentModelId_plan",
13048
+ value: previousSessionState.subagentModelId_plan
13049
+ }),
13050
+ ctx.state.session.thread.setSetting({
13051
+ key: "subagentModelId_execute",
13052
+ value: previousSessionState.subagentModelId_execute
13053
+ }),
13054
+ ctx.state.session.thread.setSetting({
13055
+ key: "observerModelId",
13056
+ value: previousSessionState.observerModelId
13057
+ }),
13058
+ ctx.state.session.thread.setSetting({
13059
+ key: "reflectorModelId",
13060
+ value: previousSessionState.reflectorModelId
13061
+ }),
13062
+ ctx.state.session.model.switch(previousModelId),
13063
+ ctx.state.session.state.set({
13064
+ modelRoute: previousSessionState.modelRoute,
13065
+ [_mastra_code_sdk_auth_account_rotation_processor.MODEL_FALLBACK_STATE_KEY]: previousSessionState[_mastra_code_sdk_auth_account_rotation_processor.MODEL_FALLBACK_STATE_KEY] ?? null,
13066
+ subagentModelId_explore: previousSessionState.subagentModelId_explore,
13067
+ subagentModelId_plan: previousSessionState.subagentModelId_plan,
13068
+ subagentModelId_execute: previousSessionState.subagentModelId_execute,
13069
+ observerModelId: previousSessionState.observerModelId,
13070
+ reflectorModelId: previousSessionState.reflectorModelId
13071
+ })
13072
+ ]);
13073
+ ctx.state.fallbackStatus = previousFallbackUi;
13074
+ ctx.updateStatusLine();
12858
13075
  }
12859
- if (fallbackStatusCleared) rollbacks.push(ctx.state.session.thread.setSetting({
12860
- key: _mastra_code_sdk_onboarding_settings.THREAD_FALLBACK_STATUS_KEY,
12861
- value: previousFallbackStatus
12862
- }));
12863
- if (packSettingSaved) rollbacks.push(ctx.state.session.thread.setSetting({
12864
- key: _mastra_code_sdk_onboarding_settings.THREAD_ACTIVE_MODEL_PACK_ID_KEY,
12865
- value: previousPackSetting
12866
- }));
12867
- if (modeSettingSaved) rollbacks.push(ctx.state.session.thread.setSetting({
12868
- key: modeSettingKey,
12869
- value: previousModeSetting
12870
- }));
12871
- if (ctx.state.session.model.get() !== previousModelId) rollbacks.push(ctx.state.session.model.switch({
12872
- modelId: previousModelId,
12873
- scope: "global"
12874
- }));
12875
- await Promise.allSettled(rollbacks);
12876
- throw error;
12877
- }
12878
- ctx.state.fallbackStatus = void 0;
12879
- ctx.updateStatusLine();
12880
- ctx.showInfo(`Switched ${modeId} mode to ${modelId}`);
13076
+ });
12881
13077
  }
12882
13078
  async function handleModelCommand(ctx) {
12883
13079
  try {
@@ -14195,47 +14391,6 @@ function upsertCustomPackInSettings(settings, pack, modeDefaults, previousPackId
14195
14391
  }
14196
14392
  async function applyPack(ctx, pack, previousPackId) {
14197
14393
  const modes = ctx.state.controller.listModes();
14198
- for (const mode of modes) {
14199
- const modelId = pack.models[mode.id];
14200
- if (modelId) {
14201
- mode.defaultModelId = modelId;
14202
- await ctx.state.session.thread.setSetting({
14203
- key: `modeModelId_${mode.id}`,
14204
- value: modelId
14205
- });
14206
- }
14207
- }
14208
- const currentModeId = ctx.state.session.mode.get();
14209
- const currentModeModel = pack.models[currentModeId];
14210
- if (currentModeModel) await ctx.state.session.model.switch({ modelId: currentModeModel });
14211
- for (const [agentType, modeId] of Object.entries({
14212
- explore: "fast",
14213
- plan: "plan",
14214
- execute: "build"
14215
- })) {
14216
- const saModelId = pack.models[modeId];
14217
- if (saModelId) await ctx.state.session.subagents.model.set({
14218
- modelId: saModelId,
14219
- agentType
14220
- });
14221
- }
14222
- await ctx.state.session.thread.setSetting({
14223
- key: _mastra_code_sdk_onboarding_settings.THREAD_ACTIVE_MODEL_PACK_ID_KEY,
14224
- value: pack.id
14225
- });
14226
- await ctx.state.session.thread.setSetting({
14227
- key: _mastra_code_sdk_onboarding_settings.THREAD_FALLBACK_STATUS_KEY,
14228
- value: void 0
14229
- });
14230
- await ctx.state.session.thread.setSetting({
14231
- key: _mastra_code_sdk_auth_account_rotation_processor.PACK_FALLBACK_STATE_KEY,
14232
- value: void 0
14233
- });
14234
- ctx.state.fallbackStatus = void 0;
14235
- await ctx.state.session.state.set({
14236
- activeModelPackId: pack.id,
14237
- [_mastra_code_sdk_auth_account_rotation_processor.PACK_FALLBACK_STATE_KEY]: null
14238
- });
14239
14394
  const s = (0, _mastra_code_sdk_onboarding_settings.loadSettings)();
14240
14395
  const modeDefaults = {};
14241
14396
  for (const mode of modes) {
@@ -14249,14 +14404,27 @@ async function applyPack(ctx, pack, previousPackId) {
14249
14404
  s.models.modeDefaults = {};
14250
14405
  }
14251
14406
  s.models.subagentModels = {};
14407
+ const currentModeId = ctx.state.session.mode.get();
14408
+ const currentModeModel = (0, _mastra_code_sdk_onboarding_settings.resolveModePackModels)(s, pack)[currentModeId];
14252
14409
  const hasOpenAI = Object.values(pack.models).some((modelId) => modelId.startsWith("openai/"));
14253
14410
  const sessionOverride = ctx.state.session.state.get()?.thinkingLevel;
14254
14411
  const defaultThinking = (0, _mastra_code_sdk_onboarding_settings.resolveDefaultThinkingLevel)(s, currentModeId);
14255
14412
  const effectiveThinking = sessionOverride ?? defaultThinking.level;
14256
14413
  if (hasOpenAI && sessionOverride === void 0 && defaultThinking.source === "global" && defaultThinking.level === "off") s.preferences.thinkingLevel = "low";
14257
- else if (currentModeModel?.startsWith("openai/") && effectiveThinking === "max") await ctx.state.session.state.set({ thinkingLevel: "xhigh" });
14258
- (0, _mastra_code_sdk_onboarding_settings.saveSettings)(s);
14259
- updateStatusLine(ctx.state);
14414
+ const shouldSetXhigh = currentModeModel?.startsWith("openai/") && effectiveThinking === "max";
14415
+ return (await applyPackToSession(ctx, pack.id, {
14416
+ settings: s,
14417
+ ...shouldSetXhigh ? { thinkingLevel: "xhigh" } : {},
14418
+ afterApply: async () => {
14419
+ await ctx.state.session.thread.setSetting({
14420
+ key: _mastra_code_sdk_onboarding_settings.THREAD_FALLBACK_STATUS_KEY,
14421
+ value: void 0
14422
+ });
14423
+ (0, _mastra_code_sdk_onboarding_settings.saveSettings)(s);
14424
+ ctx.state.fallbackStatus = void 0;
14425
+ updateStatusLine(ctx.state);
14426
+ }
14427
+ })).applied;
14260
14428
  }
14261
14429
  function getOverriddenPackModes(pack, builtinPack) {
14262
14430
  return [
@@ -14572,6 +14740,12 @@ async function runSetSubscriptionRouting(ctx, pack) {
14572
14740
  if (Object.keys(packPreferences).length > 0) settings.models.packAccountPreferences[pack.id] = packPreferences;
14573
14741
  else delete settings.models.packAccountPreferences[pack.id];
14574
14742
  (0, _mastra_code_sdk_onboarding_settings.saveSettings)(settings);
14743
+ const threadId = ctx.state.session.thread.getId();
14744
+ const thread = threadId ? (await ctx.state.session.thread.list()).find((item) => item.id === threadId) : void 0;
14745
+ if ((0, _mastra_code_sdk_onboarding_settings.resolveThreadActiveModelPackId)(settings, listResolvableModePacks(settings), thread?.metadata) === pack.id) await applyPackToSession(ctx, pack.id, {
14746
+ settings,
14747
+ expectedThreadId: threadId
14748
+ });
14575
14749
  const providerId = (0, _mastra_code_sdk_auth_account_rotation_processor.providerFromModelId)(modelId);
14576
14750
  const accountLabel = accountId ? ctx.authStorage?.listAccounts(providerId ?? "").find((account) => account.id === accountId)?.label ?? accountId : "Automatic";
14577
14751
  ctx.showInfo(`${pack.name} · ${modelId}: ${accountLabel}`);
@@ -14689,8 +14863,7 @@ async function handleModelsPackCommand(ctx) {
14689
14863
  imported.id = `custom:${newName}`;
14690
14864
  }
14691
14865
  }
14692
- await applyPack(ctx, imported);
14693
- ctx.showInfo(`Imported and activated ${imported.name} pack`);
14866
+ if (await applyPack(ctx, imported)) ctx.showInfo(`Imported and activated ${imported.name} pack`);
14694
14867
  resolve();
14695
14868
  return;
14696
14869
  }
@@ -14770,8 +14943,7 @@ async function handleModelsPackCommand(ctx) {
14770
14943
  resolve();
14771
14944
  return;
14772
14945
  }
14773
- await applyPack(ctx, pack, previousPackId);
14774
- ctx.showInfo(resetBuiltinPack ? `Reset and switched to ${pack.name} pack` : `Switched to ${pack.name} pack`);
14946
+ if (await applyPack(ctx, pack, previousPackId)) ctx.showInfo(resetBuiltinPack ? `Reset and switched to ${pack.name} pack` : `Switched to ${pack.name} pack`);
14775
14947
  resolve();
14776
14948
  };
14777
14949
  selectList.onCancel = () => {
@@ -18236,7 +18408,7 @@ async function performLogin(ctx, providerId, opts) {
18236
18408
  const hasSelectedModel = ctx.state.session.model.get() !== "";
18237
18409
  const defaultModel = _mastra_code_sdk_auth_storage.PROVIDER_DEFAULT_MODELS[providerId];
18238
18410
  if (defaultModel && !hasSelectedModel) {
18239
- await ctx.state.session.model.switch({ modelId: defaultModel });
18411
+ await ctx.state.session.model.switch(defaultModel);
18240
18412
  ctx.showInfo(`Logged in to ${providerName} - switched to ${defaultModel}`);
18241
18413
  } else ctx.showInfo(`Successfully logged in to ${providerName}`);
18242
18414
  }
@@ -21401,7 +21573,10 @@ function handleAgentEnd(ctx) {
21401
21573
  }
21402
21574
  });
21403
21575
  if (state.streamingComponent) finalizeStreamingAssistant(state);
21404
- state.activeGoalJudge = void 0;
21576
+ if (state.activeGoalJudge) {
21577
+ removeJudgeComponent(state, state.activeGoalJudge.component);
21578
+ state.activeGoalJudge = void 0;
21579
+ }
21405
21580
  state.followUpComponents = [];
21406
21581
  for (const tool of state.pendingTools.values()) tool.stopLiveUpdates?.();
21407
21582
  state.idleCounter?.setThinking(false);
@@ -21557,17 +21732,6 @@ function handleGoalEvaluation(ctx, payload) {
21557
21732
  ctx.updateStatusLine();
21558
21733
  flushRender(state);
21559
21734
  state.activeGoalJudge = void 0;
21560
- if (payload.status === "done") {
21561
- const goal = state.goalManager.getGoal();
21562
- if (goal && goal.id === state.planStartedGoalId) {
21563
- const goalId = state.planStartedGoalId;
21564
- state.planStartedGoalId = void 0;
21565
- state.session.mode.switch({ modeId: "plan" }).catch((error) => {
21566
- ctx.showError(`Failed to switch to Plan mode: ${error instanceof Error ? error.message : String(error)}`);
21567
- state.planStartedGoalId = goalId;
21568
- });
21569
- }
21570
- }
21571
21735
  }
21572
21736
  //#endregion
21573
21737
  //#region src/tui/handlers/message.ts
@@ -21794,18 +21958,11 @@ function handleMessageEnd(ctx, message) {
21794
21958
  flushRender(state);
21795
21959
  }
21796
21960
  /**
21797
- * Thread stickiness for a pack hop (Q19): the rotation processor writes the
21798
- * landed pack into session state (PACK_FALLBACK_STATE_KEY) when a cascade
21799
- * advances; this handler consumes it on the typed `state_changed` event —
21800
- * data parts never ride controller message events, so this key is the live
21801
- * channel. Applies the landed pack exactly like the manual /models switch
21802
- * (applyPack in models-pack.ts): every mode's thread model, subagent models,
21803
- * thinking-level fixups, thread metadata, and settings, so the thread stays
21804
- * on the landed pack until the user switches manually.
21961
+ * Keep a thread on the pack selected by a generic model-route hop.
21805
21962
  */
21806
21963
  async function handlePackFallbackState(ectx, event) {
21807
- if (!event.changedKeys.includes(_mastra_code_sdk_auth_account_rotation_processor.PACK_FALLBACK_STATE_KEY)) return;
21808
- const pending = event.state[_mastra_code_sdk_auth_account_rotation_processor.PACK_FALLBACK_STATE_KEY];
21964
+ if (!event.changedKeys.includes(_mastra_code_sdk_auth_account_rotation_processor.MODEL_FALLBACK_STATE_KEY)) return;
21965
+ const pending = event.state[_mastra_code_sdk_auth_account_rotation_processor.MODEL_FALLBACK_STATE_KEY];
21809
21966
  if (pending === null || pending === void 0) return;
21810
21967
  const entryThreadId = ectx.state.session.thread.getId();
21811
21968
  const pendingThreadId = typeof pending.threadId === "string" ? pending.threadId : entryThreadId;
@@ -21818,104 +21975,60 @@ async function handlePackFallbackState(ectx, event) {
21818
21975
  const isOriginThreadActive = () => !pendingThreadId || ectx.state.session.thread.getId() === pendingThreadId;
21819
21976
  const clearPending = async () => {
21820
21977
  await setOriginThreadSetting({
21821
- key: _mastra_code_sdk_auth_account_rotation_processor.PACK_FALLBACK_STATE_KEY,
21978
+ key: _mastra_code_sdk_auth_account_rotation_processor.MODEL_FALLBACK_STATE_KEY,
21822
21979
  value: void 0
21823
21980
  });
21824
- if (isOriginThreadActive()) await ectx.state.session.state.set({ [_mastra_code_sdk_auth_account_rotation_processor.PACK_FALLBACK_STATE_KEY]: null });
21981
+ if (isOriginThreadActive()) await ectx.state.session.state.set({ [_mastra_code_sdk_auth_account_rotation_processor.MODEL_FALLBACK_STATE_KEY]: null });
21825
21982
  };
21826
- if (typeof pending.toPackId !== "string" || typeof pending.toModelId !== "string" || pending.threadId !== void 0 && typeof pending.threadId !== "string") {
21827
- await clearPending();
21828
- return;
21829
- }
21830
- if (pending.toModelId.length === 0 || pending.toPackId.length === 0) {
21983
+ if (typeof pending.fromEntryId !== "string" || typeof pending.toEntryId !== "string" || typeof pending.toModelId !== "string" || pending.threadId !== void 0 && typeof pending.threadId !== "string" || pending.toEntryId.length === 0 || pending.toModelId.length === 0) {
21831
21984
  await clearPending();
21832
21985
  return;
21833
21986
  }
21834
21987
  if (!isOriginThreadActive()) return;
21835
21988
  const settings = (0, _mastra_code_sdk_onboarding_settings.loadSettings)();
21836
- const packs = (0, _mastra_code_sdk_agents_model.listResolvableModePacks)(settings);
21837
- const pack = packs.find((candidate) => candidate.id === pending.toPackId);
21989
+ const packs = listResolvableModePacks(settings);
21990
+ const pack = packs.find((candidate) => candidate.id === pending.toEntryId);
21838
21991
  if (!pack) {
21839
21992
  await clearPending();
21840
21993
  return;
21841
21994
  }
21842
- const failedPack = packs.find((candidate) => candidate.id === pending.fromPackId);
21995
+ const failedPack = packs.find((candidate) => candidate.id === pending.fromEntryId);
21843
21996
  const fallbackStatus = {
21844
21997
  usingPack: pack.name,
21845
- failedPack: failedPack?.name ?? pending.fromPackId
21998
+ failedPack: failedPack?.name ?? pending.fromEntryId
21846
21999
  };
21847
- const packModels = (0, _mastra_code_sdk_onboarding_settings.resolveModePackModels)(settings, pack);
21848
- const modes = ectx.state.controller.listModes();
21849
- for (const mode of modes) {
21850
- const modelId = packModels[mode.id];
21851
- if (modelId) await setOriginThreadSetting({
21852
- key: `modeModelId_${mode.id}`,
21853
- value: modelId
21854
- });
21855
- }
21856
- await setOriginThreadSetting({
21857
- key: _mastra_code_sdk_onboarding_settings.THREAD_ACTIVE_MODEL_PACK_ID_KEY,
21858
- value: pending.toPackId
21859
- });
21860
- await setOriginThreadSetting({
21861
- key: _mastra_code_sdk_onboarding_settings.THREAD_FALLBACK_STATUS_KEY,
21862
- value: fallbackStatus
21863
- });
21864
- if (!isOriginThreadActive()) return;
21865
- const subagentModeMap = {
21866
- explore: "fast",
21867
- plan: "plan",
21868
- execute: "build"
21869
- };
21870
- const subagentState = {};
21871
- for (const [agentType, modeId] of Object.entries(subagentModeMap)) {
21872
- const modelId = packModels[modeId];
21873
- if (!modelId) continue;
21874
- const key = `subagentModelId_${agentType}`;
21875
- subagentState[key] = modelId;
21876
- await setOriginThreadSetting({
21877
- key,
21878
- value: modelId
22000
+ try {
22001
+ await applyPackToSession(ectx, pending.toEntryId, {
22002
+ clearPendingFallback: false,
22003
+ afterApply: async (selection) => {
22004
+ if (!isOriginThreadActive()) return;
22005
+ await setOriginThreadSetting({
22006
+ key: _mastra_code_sdk_onboarding_settings.THREAD_FALLBACK_STATUS_KEY,
22007
+ value: fallbackStatus
22008
+ });
22009
+ if (!isOriginThreadActive()) return;
22010
+ const sessionOverride = ectx.state.session.state.get()?.thinkingLevel;
22011
+ const currentModeId = ectx.state.session.mode.get();
22012
+ const defaultThinking = (0, _mastra_code_sdk_onboarding_settings.resolveDefaultThinkingLevel)({
22013
+ ...settings,
22014
+ models: {
22015
+ ...settings.models,
22016
+ activeModelPackId: pending.toEntryId
22017
+ }
22018
+ }, currentModeId);
22019
+ const effectiveThinking = sessionOverride ?? defaultThinking.level;
22020
+ if (selection.modelRoute.entries.some((entry) => entry.modelId.startsWith("openai/")) && sessionOverride === void 0 && defaultThinking.source === "global" && defaultThinking.level === "off") await ectx.state.session.state.set({ thinkingLevel: "low" });
22021
+ else if (selection.modelId.startsWith("openai/") && effectiveThinking === "max") await ectx.state.session.state.set({ thinkingLevel: "xhigh" });
22022
+ ectx.state.fallbackStatus = fallbackStatus;
22023
+ ectx.updateStatusLine();
22024
+ await ectx.refreshModelAuthStatus();
22025
+ await clearPending();
22026
+ }
21879
22027
  });
22028
+ } catch (error) {
22029
+ await clearPending();
22030
+ throw error;
21880
22031
  }
21881
- if (!isOriginThreadActive()) return;
21882
- const currentModeId = ectx.state.session.mode.get();
21883
- const currentModeModel = packModels[currentModeId] ?? pending.toModelId;
21884
- const runtimeSettings = {
21885
- ...settings,
21886
- models: {
21887
- ...settings.models,
21888
- activeModelPackId: pending.toPackId
21889
- }
21890
- };
21891
- const hasOpenAI = Object.values(packModels).some((modelId) => modelId.startsWith("openai/"));
21892
- const sessionOverride = ectx.state.session.state.get()?.thinkingLevel;
21893
- const defaultThinking = (0, _mastra_code_sdk_onboarding_settings.resolveDefaultThinkingLevel)(runtimeSettings, currentModeId);
21894
- const effectiveThinking = sessionOverride ?? defaultThinking.level;
21895
- const stateUpdates = {
21896
- activeModelPackId: pending.toPackId,
21897
- ...subagentState
21898
- };
21899
- if (hasOpenAI && sessionOverride === void 0 && defaultThinking.source === "global" && defaultThinking.level === "off") stateUpdates.thinkingLevel = "low";
21900
- else if (currentModeModel.startsWith("openai/") && effectiveThinking === "max") stateUpdates.thinkingLevel = "xhigh";
21901
- if (!await ectx.state.session.state.setIf(stateUpdates, isOriginThreadActive)) return;
21902
- ectx.state.session.model.set({ modelId: currentModeModel });
21903
- ectx.state.session.emit({
21904
- type: "model_changed",
21905
- modelId: currentModeModel,
21906
- scope: "thread",
21907
- modeId: currentModeId
21908
- });
21909
- for (const [key, modelId] of Object.entries(subagentState)) ectx.state.session.emit({
21910
- type: "subagent_model_changed",
21911
- modelId,
21912
- scope: "thread",
21913
- agentType: key.slice(16)
21914
- });
21915
- ectx.state.fallbackStatus = fallbackStatus;
21916
- ectx.updateStatusLine();
21917
- await ectx.refreshModelAuthStatus();
21918
- await clearPending();
21919
22032
  }
21920
22033
  //#endregion
21921
22034
  //#region src/tui/handlers/om.ts
@@ -22455,6 +22568,14 @@ async function handlePlanApproval(ctx, toolCallId, submittedPath) {
22455
22568
  if (state.pendingFocus === approvalComponent) state.pendingFocus = void 0;
22456
22569
  if (!state.ui.hasOverlay()) state.ui.setFocus(state.editor);
22457
22570
  };
22571
+ const restoreApprovalAfterError = (error) => {
22572
+ ctx.showError(`Failed to start plan: ${error instanceof Error ? error.message : String(error)}`);
22573
+ approvalComponent.activate(approvalOptions);
22574
+ state.activeInlinePlanApproval = approvalComponent;
22575
+ state.ui.requestRender();
22576
+ if (state.ui.hasOverlay()) state.pendingFocus = approvalComponent;
22577
+ else state.ui.setFocus(approvalComponent);
22578
+ };
22458
22579
  const approvalOptions = {
22459
22580
  toolCallId,
22460
22581
  title: resolvedTitle,
@@ -22463,21 +22584,32 @@ async function handlePlanApproval(ctx, toolCallId, submittedPath) {
22463
22584
  previousPlan,
22464
22585
  onApprove: async () => {
22465
22586
  releaseApprovalFocus();
22466
- firePermissionResult("approved");
22587
+ try {
22588
+ await switchModeWithPack(ctx, "build");
22589
+ } catch (error) {
22590
+ restoreApprovalAfterError(error);
22591
+ return;
22592
+ }
22467
22593
  await prepareApprovedPlan(ctx, resolvedTitle, plan, planPath);
22594
+ firePermissionResult("approved");
22468
22595
  const resumed = resumeApprovedPlan(ctx, toolCallId, resolvedTitle, plan, snapshotKey);
22469
22596
  resolve();
22470
22597
  await resumed;
22471
22598
  },
22472
22599
  onGoal: async () => {
22473
22600
  releaseApprovalFocus();
22474
- firePermissionResult("approved");
22601
+ try {
22602
+ await switchModeWithPack(ctx, "build");
22603
+ } catch (error) {
22604
+ restoreApprovalAfterError(error);
22605
+ return;
22606
+ }
22475
22607
  await prepareApprovedPlan(ctx, resolvedTitle, plan, planPath);
22608
+ firePermissionResult("approved");
22476
22609
  const goal = await ctx.setGoal(formatPlanGoalObjective(resolvedTitle, plan), "Goal cancelled.").catch((error) => {
22477
22610
  ctx.showError(`Failed to set goal: ${error instanceof Error ? error.message : String(error)}`);
22478
22611
  return null;
22479
22612
  });
22480
- if (goal) state.planStartedGoalId = goal.id;
22481
22613
  const approvalRecorded = goal ? waitForToolEnd(state.session, toolCallId) : void 0;
22482
22614
  const resumed = resumeApprovedPlan(ctx, toolCallId, resolvedTitle, plan, snapshotKey);
22483
22615
  resolve();
@@ -24797,7 +24929,6 @@ function createTUIState(options) {
24797
24929
  tokensPerSec: 0,
24798
24930
  latestRequestPromptTokens: void 0,
24799
24931
  goalManager: new _mastra_code_sdk_goal_manager.GoalManager(),
24800
- planStartedGoalId: void 0,
24801
24932
  customSlashCommands: [],
24802
24933
  skillCommands: [],
24803
24934
  goalSkillCommands: [],
@@ -25083,15 +25214,17 @@ async function dispatchEvent(event, ectx, state) {
25083
25214
  handleToolEnd(ectx, event.toolCallId, event.result, event.isError, event.providerMetadata);
25084
25215
  break;
25085
25216
  case "info":
25086
- ectx.showInfo(event.message);
25217
+ ectx.showInfo(event.message.replace(/^Switched model route:/, "Switched model pack:"));
25087
25218
  break;
25088
25219
  case "error":
25089
25220
  ectx.showFormattedError(event);
25090
25221
  break;
25091
25222
  case "mode_changed":
25223
+ await reconcilePackAfterModeChange(ectx, event.modeId);
25092
25224
  await ectx.refreshModelAuthStatus();
25093
25225
  break;
25094
25226
  case "model_changed":
25227
+ ectx.updateStatusLine();
25095
25228
  await ectx.refreshModelAuthStatus();
25096
25229
  break;
25097
25230
  case "thread_changed": {
@@ -25988,7 +26121,7 @@ function setupKeyboardShortcuts(state, callbacks) {
25988
26121
  if (modes.length <= 1) return;
25989
26122
  const currentId = state.session.mode.get();
25990
26123
  const nextMode = modes[(modes.findIndex((m) => m.id === currentId) + 1) % modes.length];
25991
- await state.session.mode.switch({ modeId: nextMode.id });
26124
+ await switchModeWithPack({ state }, nextMode.id);
25992
26125
  });
25993
26126
  state.editor.onAction("toggleYolo", () => {
25994
26127
  const current = state.session.state.get()?.yolo === true;
@@ -27040,11 +27173,11 @@ async function syncInitialThreadState(state) {
27040
27173
  const initThread = initThreads.find((t) => t.id === initThreadId);
27041
27174
  const metadata = initThread?.metadata;
27042
27175
  const persistedFallbackStatus = fallbackStatusFromMetadata(metadata);
27043
- const pendingFallback = metadata?.[_mastra_code_sdk_auth_account_rotation_processor.PACK_FALLBACK_STATE_KEY];
27044
- const validPendingFallback = pendingFallback && typeof pendingFallback === "object" && typeof pendingFallback.fromPackId === "string" && typeof pendingFallback.toPackId === "string" && typeof pendingFallback.toModelId === "string" && (pendingFallback.reason === "pool-exhausted" || pendingFallback.reason === "persistent-outage") && typeof pendingFallback.at === "string" ? pendingFallback : null;
27045
- const currentPending = (state.session.state?.get?.())?.[_mastra_code_sdk_auth_account_rotation_processor.PACK_FALLBACK_STATE_KEY];
27176
+ const pendingFallback = metadata?.[_mastra_code_sdk_auth_account_rotation_processor.MODEL_FALLBACK_STATE_KEY];
27177
+ const validPendingFallback = pendingFallback && typeof pendingFallback === "object" && typeof pendingFallback.fromEntryId === "string" && typeof pendingFallback.toEntryId === "string" && typeof pendingFallback.toModelId === "string" && (pendingFallback.reason === "pool-exhausted" || pendingFallback.reason === "persistent-outage") && typeof pendingFallback.at === "string" ? pendingFallback : null;
27178
+ const currentPending = (state.session.state?.get?.())?.[_mastra_code_sdk_auth_account_rotation_processor.MODEL_FALLBACK_STATE_KEY];
27046
27179
  if (validPendingFallback || currentPending) {
27047
- const updates = { [_mastra_code_sdk_auth_account_rotation_processor.PACK_FALLBACK_STATE_KEY]: validPendingFallback };
27180
+ const updates = { [_mastra_code_sdk_auth_account_rotation_processor.MODEL_FALLBACK_STATE_KEY]: validPendingFallback };
27048
27181
  if (!(state.session.state.setIf ? await state.session.state.setIf(updates, () => state.session.thread.getId() === initThreadId) : state.session.thread.getId() === initThreadId ? await state.session.state.set(updates).then(() => true) : false) || state.session.thread.getId() !== initThreadId) return;
27049
27182
  }
27050
27183
  setCurrentThreadTitle(state, initThread?.title);
@@ -27638,8 +27771,8 @@ var MastraTUI = class MastraTUI {
27638
27771
  }
27639
27772
  if (event.type === "model_changed") analytics.capture("mastracode_model_changed", {
27640
27773
  modelId: event.modelId,
27641
- scope: event.scope,
27642
- mode: event.modeId ?? this.state.session.mode.get(),
27774
+ thinkingLevel: event.thinkingLevel,
27775
+ mode: this.state.session.mode.get(),
27643
27776
  threadId: this.state.session.thread.getId(),
27644
27777
  resourceId: this.state.session.identity.getResourceId()
27645
27778
  });
@@ -27725,16 +27858,30 @@ var MastraTUI = class MastraTUI {
27725
27858
  async syncThreadActivePackMetadata(thread, isCurrent = () => true) {
27726
27859
  const settings = (0, _mastra_code_sdk_onboarding_index.loadSettings)();
27727
27860
  const currentThreadId = this.state.session.thread.getId();
27728
- if (!currentThreadId || !isCurrent()) return;
27861
+ if (!isCurrent()) return;
27862
+ if (!currentThreadId) {
27863
+ if (!this.state.options.initialModelOverride) {
27864
+ await applyCurrentThreadPack({ state: this.state }, { packId: settings.models.activeModelPackId });
27865
+ if (!isCurrent()) return;
27866
+ }
27867
+ updateStatusLine(this.state);
27868
+ return;
27869
+ }
27729
27870
  const ownsUpdate = () => isCurrent() && this.state.session.thread.getId() === currentThreadId;
27730
27871
  const resolvedThread = thread?.id === currentThreadId ? thread : (await this.state.session.thread.list()).find((t) => t.id === currentThreadId);
27731
- const packs = (0, _mastra_code_sdk_onboarding_index.getAvailableModePacks)(await this.buildProviderAccess(), settings.customModelPacks).filter((p) => p.id !== "custom");
27872
+ const packs = listResolvableModePacks(settings);
27732
27873
  const metadata = resolvedThread?.metadata;
27733
27874
  if (!ownsUpdate()) return;
27734
- const resolvedPackId = (0, _mastra_code_sdk_onboarding_settings.resolveThreadActiveModelPackId)(settings, packs, metadata);
27875
+ const hasThreadPack = typeof metadata?.[_mastra_code_sdk_onboarding_settings.THREAD_ACTIVE_MODEL_PACK_ID_KEY] === "string";
27876
+ const hasPersistedModel = typeof metadata?.currentModelId === "string" && metadata.currentModelId.length > 0;
27877
+ const resolvedPackId = (this.state.options.initialModelOverride || hasPersistedModel) && !hasThreadPack ? null : (0, _mastra_code_sdk_onboarding_settings.resolveThreadActiveModelPackId)(settings, packs, metadata);
27735
27878
  const fallbackStatus = fallbackStatusFromMetadata(metadata);
27736
- const updates = { activeModelPackId: resolvedPackId };
27737
- if (!(this.state.session.state.setIf ? await this.state.session.state.setIf(updates, ownsUpdate) : ownsUpdate() ? (await this.state.session.state.set(updates), ownsUpdate()) : false) || !ownsUpdate()) return;
27879
+ if (!ownsUpdate()) return;
27880
+ await applyCurrentThreadPack({ state: this.state }, {
27881
+ packId: resolvedPackId,
27882
+ applyModeDefault: false
27883
+ });
27884
+ if (!ownsUpdate()) return;
27738
27885
  this.state.fallbackStatus = fallbackStatus;
27739
27886
  updateStatusLine(this.state);
27740
27887
  }
@@ -27958,7 +28105,7 @@ var MastraTUI = class MastraTUI {
27958
28105
  const { PROVIDER_DEFAULT_MODELS } = await import("@mastra/code-sdk/auth/storage");
27959
28106
  const defaultModel = PROVIDER_DEFAULT_MODELS[providerId];
27960
28107
  if (defaultModel) {
27961
- await this.state.session.model.switch({ modelId: defaultModel });
28108
+ await this.state.session.model.switch(defaultModel);
27962
28109
  showInfo(this.state, `Logged in to ${providerName} - switched to ${defaultModel}`);
27963
28110
  } else showInfo(this.state, `Successfully logged in to ${providerName}`);
27964
28111
  await seedOMDefaultAfterLogin(this.state, providerId, (message) => showInfo(this.state, message));
@@ -28063,33 +28210,8 @@ var MastraTUI = class MastraTUI {
28063
28210
  });
28064
28211
  }
28065
28212
  async applyOnboardingResult(result) {
28066
- const controller = this.state.controller;
28067
28213
  const modePack = result.modePack;
28068
- const modes = controller.listModes();
28069
- for (const mode of modes) {
28070
- const modelId = modePack.models[mode.id];
28071
- if (modelId) {
28072
- mode.defaultModelId = modelId;
28073
- await this.state.session.thread.setSetting({
28074
- key: `modeModelId_${mode.id}`,
28075
- value: modelId
28076
- });
28077
- }
28078
- }
28079
- const currentModeId = this.state.session.mode.get();
28080
- const currentModeModel = modePack.models[currentModeId];
28081
- if (currentModeModel) await this.state.session.model.switch({ modelId: currentModeModel });
28082
- for (const [agentType, modeId] of Object.entries({
28083
- explore: "fast",
28084
- plan: "plan",
28085
- execute: "build"
28086
- })) {
28087
- const saModelId = modePack.models[modeId];
28088
- if (saModelId) await this.state.session.subagents.model.set({
28089
- modelId: saModelId,
28090
- agentType
28091
- });
28092
- }
28214
+ const modes = this.state.controller.listModes();
28093
28215
  const omPack = result.omPack.modelId ? result.omPack : void 0;
28094
28216
  if (omPack) await applyOMModelToSession(this.state, omPack.modelId);
28095
28217
  await this.state.session.state.set({ yolo: result.yolo });
@@ -28103,37 +28225,25 @@ var MastraTUI = class MastraTUI {
28103
28225
  const modelId = modePack.models[mode.id];
28104
28226
  if (modelId) modeDefaults[mode.id] = modelId;
28105
28227
  }
28106
- let activeModePackId = modePack.id;
28107
- if (modePack.id === "custom" || modePack.id.startsWith("custom:")) {
28108
- const customName = modePack.id === "custom" ? modePack.name?.trim() || "Custom" : modePack.id.slice(7) || "Custom";
28109
- activeModePackId = `custom:${customName}`;
28110
- const entry = {
28111
- name: customName,
28112
- models: modeDefaults,
28113
- createdAt: (/* @__PURE__ */ new Date()).toISOString()
28114
- };
28115
- const idx = settings.customModelPacks.findIndex((p) => p.name === customName);
28116
- if (idx >= 0) settings.customModelPacks[idx] = entry;
28117
- else settings.customModelPacks.push(entry);
28118
- settings.models.modeDefaults = modeDefaults;
28119
- } else settings.models.modeDefaults = {};
28120
- settings.onboarding.modePackId = activeModePackId;
28121
- settings.models.activeModelPackId = activeModePackId;
28122
- if (this.state.session.thread.getId()) {
28123
- await this.state.session.thread.setSetting({
28124
- key: _mastra_code_sdk_onboarding_settings.THREAD_ACTIVE_MODEL_PACK_ID_KEY,
28125
- value: activeModePackId
28126
- });
28127
- await this.state.session.thread.setSetting({
28128
- key: _mastra_code_sdk_onboarding_settings.THREAD_FALLBACK_STATUS_KEY,
28129
- value: void 0
28130
- });
28228
+ let activeModePackId = settings.models.activeModelPackId;
28229
+ if (modes.every((mode) => Boolean(modeDefaults[mode.id]))) {
28230
+ activeModePackId = modePack.id;
28231
+ if (modePack.id === "custom" || modePack.id.startsWith("custom:")) {
28232
+ const customName = modePack.id === "custom" ? modePack.name?.trim() || "Custom" : modePack.id.slice(7) || "Custom";
28233
+ activeModePackId = `custom:${customName}`;
28234
+ const entry = {
28235
+ name: customName,
28236
+ models: modeDefaults,
28237
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
28238
+ };
28239
+ const idx = settings.customModelPacks.findIndex((p) => p.name === customName);
28240
+ if (idx >= 0) settings.customModelPacks[idx] = entry;
28241
+ else settings.customModelPacks.push(entry);
28242
+ settings.models.modeDefaults = modeDefaults;
28243
+ } else settings.models.modeDefaults = {};
28244
+ settings.onboarding.modePackId = activeModePackId;
28245
+ settings.models.activeModelPackId = activeModePackId;
28131
28246
  }
28132
- await this.state.session.state.set({
28133
- activeModelPackId: activeModePackId,
28134
- fallbackStatus: void 0
28135
- });
28136
- this.state.fallbackStatus = void 0;
28137
28247
  settings.models.activeOmPackId = omPack?.id ?? null;
28138
28248
  settings.models.omModelOverride = omPack?.id === "custom" ? omPack.modelId : null;
28139
28249
  settings.models.observerModelOverride = null;
@@ -28141,6 +28251,12 @@ var MastraTUI = class MastraTUI {
28141
28251
  settings.preferences.yolo = result.yolo;
28142
28252
  settings.models.subagentModels = {};
28143
28253
  (0, _mastra_code_sdk_onboarding_index.saveSettings)(settings);
28254
+ await applyCurrentThreadPack({ state: this.state }, { packId: activeModePackId });
28255
+ await this.state.session.thread.setSetting({
28256
+ key: _mastra_code_sdk_onboarding_settings.THREAD_FALLBACK_STATUS_KEY,
28257
+ value: void 0
28258
+ });
28259
+ this.state.fallbackStatus = void 0;
28144
28260
  updateStatusLine(this.state);
28145
28261
  await this.refreshModelAuthStatus();
28146
28262
  }
@@ -28417,4 +28533,4 @@ Object.defineProperty(exports, "theme", {
28417
28533
  }
28418
28534
  });
28419
28535
 
28420
- //# sourceMappingURL=tui-DGvjBiNg.cjs.map
28536
+ //# sourceMappingURL=tui-BsLtXA9y.cjs.map