@letta-ai/letta-code 0.26.5 → 0.26.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 (2) hide show
  1. package/letta.js +797 -773
  2. package/package.json +1 -1
package/letta.js CHANGED
@@ -4997,7 +4997,7 @@ var package_default;
4997
4997
  var init_package = __esm(() => {
4998
4998
  package_default = {
4999
4999
  name: "@letta-ai/letta-code",
5000
- version: "0.26.5",
5000
+ version: "0.26.6",
5001
5001
  description: "Letta Code is a CLI tool for interacting with stateful Letta agents from the terminal.",
5002
5002
  type: "module",
5003
5003
  packageManager: "bun@1.3.0",
@@ -140281,14 +140281,6 @@ async function updateLocalProvider(providerIdValue, apiKey, accessKey, region, p
140281
140281
  timeout: options3.timeout
140282
140282
  });
140283
140283
  }
140284
- async function deleteLocalProvider(providerIdValue, storageDir) {
140285
- const file3 = readAuthFile(storageDir);
140286
- const provider = Object.values(file3.providers).find((record5) => record5.id === providerIdValue);
140287
- if (!provider)
140288
- return;
140289
- delete file3.providers[provider.name];
140290
- writeAuthFile(file3, storageDir);
140291
- }
140292
140284
  async function removeLocalProviderByName(providerName, storageDir) {
140293
140285
  const file3 = readAuthFile(storageDir);
140294
140286
  if (!(providerName in file3.providers))
@@ -140622,13 +140614,6 @@ async function updateProvider2(providerId2, apiKey, accessKey, region, profile,
140622
140614
  }
140623
140615
  return updateProvider(providerId2, apiKey, accessKey, region, profile);
140624
140616
  }
140625
- async function deleteProvider2(providerId2, options3 = {}) {
140626
- if (useLocalProviderStore(options3.target)) {
140627
- await deleteLocalProvider(providerId2);
140628
- return;
140629
- }
140630
- await deleteProvider(providerId2);
140631
- }
140632
140617
  async function createOrUpdateProvider2(providerType, providerName, apiKey, accessKey, region, profile, options3 = {}, operationOptions = {}) {
140633
140618
  if (useLocalProviderStore(operationOptions.target)) {
140634
140619
  return createOrUpdateLocalProvider({
@@ -140878,9 +140863,6 @@ async function createOpenAICodexProvider(config3, options3 = {}) {
140878
140863
  async function updateOpenAICodexProvider(providerId2, config3, options3 = {}) {
140879
140864
  return updateProvider2(providerId2, encodeOAuthConfig(config3), undefined, undefined, undefined, options3);
140880
140865
  }
140881
- async function deleteOpenAICodexProvider(providerId2, options3 = {}) {
140882
- await deleteProvider2(providerId2, options3);
140883
- }
140884
140866
  async function createOrUpdateOpenAICodexProvider(config3, options3 = {}) {
140885
140867
  const existing = await getOpenAICodexProvider(options3);
140886
140868
  if (existing) {
@@ -140888,12 +140870,6 @@ async function createOrUpdateOpenAICodexProvider(config3, options3 = {}) {
140888
140870
  }
140889
140871
  return createOpenAICodexProvider(config3, options3);
140890
140872
  }
140891
- async function removeOpenAICodexProvider(options3 = {}) {
140892
- const existing = await getOpenAICodexProvider(options3);
140893
- if (existing) {
140894
- await deleteOpenAICodexProvider(existing.id, options3);
140895
- }
140896
- }
140897
140873
  var OPENAI_CODEX_PROVIDER_NAME = "chatgpt-plus-pro", CHATGPT_OAUTH_PROVIDER_TYPE = "chatgpt_oauth";
140898
140874
  var init_openai_codex_provider = __esm(() => {
140899
140875
  init_metadata();
@@ -144868,7 +144844,8 @@ function supportsDistinctAnthropicXHighEffort(modelHandle) {
144868
144844
  return modelHandle.includes("claude-opus-4-7") || modelHandle.includes("claude-opus-4-8");
144869
144845
  }
144870
144846
  function buildModelSettings(modelHandle, updateArgs) {
144871
- const isOpenAI = modelHandle.startsWith("openai/") || modelHandle.startsWith(`${OPENAI_CODEX_PROVIDER_NAME}/`);
144847
+ const isOpenAICodex = modelHandle.startsWith("openai-codex/");
144848
+ const isOpenAI = modelHandle.startsWith("openai/") || isOpenAICodex || modelHandle.startsWith(`${OPENAI_CODEX_PROVIDER_NAME}/`);
144872
144849
  const isAnthropic = modelHandle.startsWith("anthropic/") || modelHandle.startsWith("claude-pro-max/") || modelHandle.startsWith("minimax/");
144873
144850
  const isZai = modelHandle.startsWith("zai/");
144874
144851
  const isGoogleAI = modelHandle.startsWith("google_ai/");
@@ -144881,6 +144858,9 @@ function buildModelSettings(modelHandle, updateArgs) {
144881
144858
  provider_type: "openai",
144882
144859
  parallel_tool_calls: true
144883
144860
  };
144861
+ if (isOpenAICodex) {
144862
+ openaiSettings.provider_type = "chatgpt_oauth";
144863
+ }
144884
144864
  if (updateArgs?.reasoning_effort) {
144885
144865
  openaiSettings.reasoning = {
144886
144866
  reasoning_effort: updateArgs.reasoning_effort
@@ -144893,6 +144873,9 @@ function buildModelSettings(modelHandle, updateArgs) {
144893
144873
  if (typeof updateArgs?.strict === "boolean") {
144894
144874
  openaiSettings.strict = updateArgs.strict;
144895
144875
  }
144876
+ if (updateArgs && "service_tier" in updateArgs) {
144877
+ openaiSettings.service_tier = updateArgs.service_tier === "priority" ? "priority" : null;
144878
+ }
144896
144879
  settings3 = openaiSettings;
144897
144880
  } else if (isAnthropic) {
144898
144881
  const anthropicSettings = {
@@ -146760,6 +146743,7 @@ __export(exports_model, {
146760
146743
  normalizeModelHandleForRegistry: () => normalizeModelHandleForRegistry,
146761
146744
  models: () => models2,
146762
146745
  isLocalModelHandle: () => isLocalModelHandle,
146746
+ isLocalChatGptOAuthModelHandle: () => isLocalChatGptOAuthModelHandle,
146763
146747
  getResumeRefreshArgs: () => getResumeRefreshArgs,
146764
146748
  getReasoningTierOptionsForHandle: () => getReasoningTierOptionsForHandle,
146765
146749
  getModelUpdateArgs: () => getModelUpdateArgs,
@@ -146771,7 +146755,9 @@ __export(exports_model, {
146771
146755
  getLocalModelLabel: () => getLocalModelLabel,
146772
146756
  getDefaultModelForTier: () => getDefaultModelForTier,
146773
146757
  getDefaultModel: () => getDefaultModel,
146774
- formatAvailableModels: () => formatAvailableModels
146758
+ getChatGptFastRegistryHandleForModelHandle: () => getChatGptFastRegistryHandleForModelHandle,
146759
+ formatAvailableModels: () => formatAvailableModels,
146760
+ CHATGPT_FAST_SERVICE_TIER: () => CHATGPT_FAST_SERVICE_TIER
146775
146761
  });
146776
146762
  function isLocalModelHandle(modelHandle) {
146777
146763
  return LOCAL_MODEL_HANDLE_PREFIXES.some((prefix) => modelHandle.startsWith(prefix));
@@ -146783,10 +146769,50 @@ function getLocalModelLabel(modelHandle) {
146783
146769
  function isModelReasoningEffort(value) {
146784
146770
  return typeof value === "string" && REASONING_EFFORT_ORDER.includes(value);
146785
146771
  }
146772
+ function normalizeModelHandleForRegistry(modelHandle) {
146773
+ if (!modelHandle)
146774
+ return null;
146775
+ const [provider, ...modelParts] = modelHandle.split("/");
146776
+ const model = modelParts.join("/");
146777
+ if ((provider === CHATGPT_OAUTH_LLM_CONFIG_PROVIDER || provider === LOCAL_CHATGPT_OAUTH_HANDLE_PREFIX.slice(0, -1)) && model.length > 0 && !model.endsWith("-fast")) {
146778
+ return `${OPENAI_CODEX_PROVIDER_NAME}/${model}`;
146779
+ }
146780
+ return modelHandle;
146781
+ }
146782
+ function modelPortion(modelHandle) {
146783
+ const slashIndex = modelHandle.indexOf("/");
146784
+ if (slashIndex === -1)
146785
+ return null;
146786
+ return modelHandle.slice(slashIndex + 1);
146787
+ }
146788
+ function isLocalChatGptOAuthModelHandle(modelHandle) {
146789
+ return modelHandle.startsWith(LOCAL_CHATGPT_OAUTH_HANDLE_PREFIX);
146790
+ }
146791
+ function getChatGptFastRegistryHandleForModelHandle(modelHandle) {
146792
+ const [provider] = modelHandle.split("/");
146793
+ if (provider !== LOCAL_CHATGPT_OAUTH_HANDLE_PREFIX.slice(0, -1) && provider !== CHATGPT_OAUTH_LLM_CONFIG_PROVIDER) {
146794
+ return null;
146795
+ }
146796
+ const normalized = normalizeModelHandleForRegistry(modelHandle);
146797
+ if (!normalized?.startsWith(`${OPENAI_CODEX_PROVIDER_NAME}/`))
146798
+ return null;
146799
+ const model = modelPortion(normalized);
146800
+ if (!model || model.endsWith("-fast"))
146801
+ return null;
146802
+ const fastHandle = `${OPENAI_CODEX_PROVIDER_NAME}/${model}-fast`;
146803
+ return models2.some((entry) => entry.handle === fastHandle) ? fastHandle : null;
146804
+ }
146805
+ function displayRegistryHandleForServiceTier(modelHandle, serviceTier) {
146806
+ if (serviceTier === CHATGPT_FAST_SERVICE_TIER) {
146807
+ return getChatGptFastRegistryHandleForModelHandle(modelHandle) ?? modelHandle;
146808
+ }
146809
+ return normalizeModelHandleForRegistry(modelHandle) ?? modelHandle;
146810
+ }
146786
146811
  function getReasoningTierOptionsForHandle(modelHandle, contextWindow) {
146787
146812
  const byEffort = new Map;
146813
+ const registryHandle = normalizeModelHandleForRegistry(modelHandle) ?? modelHandle;
146788
146814
  for (const model of models2) {
146789
- if (model.handle !== modelHandle)
146815
+ if (model.handle !== registryHandle)
146790
146816
  continue;
146791
146817
  if (contextWindow !== undefined) {
146792
146818
  const mCtx = model.updateArgs?.context_window;
@@ -146800,10 +146826,10 @@ function getReasoningTierOptionsForHandle(modelHandle, contextWindow) {
146800
146826
  byEffort.set(effort, model.id);
146801
146827
  }
146802
146828
  }
146803
- if (byEffort.size === 0 && isLocalModelHandle(modelHandle)) {
146829
+ if (byEffort.size === 0 && isLocalModelHandle(registryHandle)) {
146804
146830
  return LOCAL_REASONING_EFFORT_ORDER.map((effort) => ({
146805
146831
  effort,
146806
- modelId: modelHandle
146832
+ modelId: registryHandle
146807
146833
  }));
146808
146834
  }
146809
146835
  return REASONING_EFFORT_ORDER.flatMap((effort) => {
@@ -146847,14 +146873,16 @@ function getModelInfo(modelIdentifier) {
146847
146873
  const byId = models2.find((m2) => m2.id === modelIdentifier);
146848
146874
  if (byId)
146849
146875
  return byId;
146850
- const byHandle = models2.find((m2) => m2.handle === modelIdentifier);
146876
+ const normalizedHandle = normalizeModelHandleForRegistry(modelIdentifier);
146877
+ const byHandle = models2.find((m2) => m2.handle === normalizedHandle);
146851
146878
  if (byHandle)
146852
146879
  return byHandle;
146853
146880
  return null;
146854
146881
  }
146855
146882
  function getModelInfoForLlmConfig(modelHandle, llmConfig) {
146856
- const direct = getModelInfo(modelHandle);
146857
- let candidates2 = models2.filter((m2) => m2.handle === modelHandle);
146883
+ const registryHandle = displayRegistryHandleForServiceTier(modelHandle, llmConfig?.service_tier ?? null);
146884
+ const direct = getModelInfo(registryHandle);
146885
+ let candidates2 = models2.filter((m2) => m2.handle === registryHandle);
146858
146886
  if (candidates2.length === 0) {
146859
146887
  return direct;
146860
146888
  }
@@ -146896,15 +146924,6 @@ function buildModelHandleFromConfig(config3) {
146896
146924
  }
146897
146925
  return config3.model ?? null;
146898
146926
  }
146899
- function normalizeModelHandleForRegistry(modelHandle) {
146900
- if (!modelHandle)
146901
- return null;
146902
- const [provider, ...modelParts] = modelHandle.split("/");
146903
- if (provider === "chatgpt_oauth" && modelParts.length > 0) {
146904
- return `${OPENAI_CODEX_PROVIDER_NAME}/${modelParts.join("/")}`;
146905
- }
146906
- return modelHandle;
146907
- }
146908
146927
  function shouldPreserveContextWindowForModelSelection(input) {
146909
146928
  const currentRegistryModelHandle = normalizeModelHandleForRegistry(input.currentModelHandle ?? buildModelHandleFromConfig(input.currentLlmConfig));
146910
146929
  const selectedRegistryModelHandle = normalizeModelHandleForRegistry(input.selectedModelHandle);
@@ -146965,22 +146984,23 @@ function getResumeRefreshArgs(presetUpdateArgs, agent2) {
146965
146984
  }
146966
146985
  function findModelByHandle(handle) {
146967
146986
  const pickPreferred = (candidates2) => candidates2.find((m2) => m2.isDefault) ?? candidates2.find((m2) => m2.isFeatured) ?? candidates2.find((m2) => m2.updateArgs?.reasoning_effort === "medium") ?? candidates2.find((m2) => m2.updateArgs?.reasoning_effort === "high") ?? candidates2[0] ?? null;
146968
- const exactMatch = models2.find((m2) => m2.handle === handle);
146987
+ const registryHandle = normalizeModelHandleForRegistry(handle) ?? handle;
146988
+ const exactMatch = models2.find((m2) => m2.handle === registryHandle);
146969
146989
  if (exactMatch)
146970
146990
  return exactMatch;
146971
- const [provider, ...rest3] = handle.split("/");
146991
+ const [provider, ...rest3] = registryHandle.split("/");
146972
146992
  if (provider && rest3.length > 0) {
146973
- const modelPortion = rest3.join("/");
146993
+ const modelPortion2 = rest3.join("/");
146974
146994
  const providerMatches = models2.filter((m2) => {
146975
146995
  if (!m2.handle.startsWith(`${provider}/`))
146976
146996
  return false;
146977
146997
  const mModelPortion = m2.handle.slice(provider.length + 1);
146978
- return mModelPortion.includes(modelPortion) || modelPortion.includes(mModelPortion);
146998
+ return mModelPortion.includes(modelPortion2) || modelPortion2.includes(mModelPortion);
146979
146999
  });
146980
147000
  const providerMatch = pickPreferred(providerMatches);
146981
147001
  if (providerMatch)
146982
147002
  return providerMatch;
146983
- const suffixMatches = models2.filter((m2) => m2.handle.endsWith(`/${modelPortion}`));
147003
+ const suffixMatches = models2.filter((m2) => m2.handle.endsWith(`/${modelPortion2}`));
146984
147004
  const suffixMatch = pickPreferred(suffixMatches);
146985
147005
  if (suffixMatch)
146986
147006
  return suffixMatch;
@@ -147009,7 +147029,7 @@ function resolveModelByLlmConfig(llmConfigModel) {
147009
147029
  return exactMatch.id;
147010
147030
  return null;
147011
147031
  }
147012
- var models2, REASONING_EFFORT_ORDER, LOCAL_REASONING_EFFORT_ORDER, LOCAL_MODEL_HANDLE_PREFIXES, RESUME_REFRESH_FIELDS;
147032
+ var models2, REASONING_EFFORT_ORDER, LOCAL_REASONING_EFFORT_ORDER, LOCAL_MODEL_HANDLE_PREFIXES, LOCAL_CHATGPT_OAUTH_HANDLE_PREFIX = "openai-codex/", CHATGPT_OAUTH_LLM_CONFIG_PROVIDER = "chatgpt_oauth", CHATGPT_FAST_SERVICE_TIER = "priority", RESUME_REFRESH_FIELDS;
147013
147033
  var init_model = __esm(() => {
147014
147034
  init_models7();
147015
147035
  init_openai_codex_provider();
@@ -164450,6 +164470,8 @@ var init_Edit = () => {};
164450
164470
  // src/tools/descriptions/ExecCommand.md
164451
164471
  var ExecCommand_default = `Runs a command in a PTY, returning output or a session ID for ongoing interaction.
164452
164472
 
164473
+ For ordinary one-shot commands, omit \`yield_time_ms\` and let the default wait for completion; set \`yield_time_ms\` only when intentionally returning early from a long-running or interactive command.
164474
+
164453
164475
  # Committing changes with git
164454
164476
 
164455
164477
  Only create commits when requested by the user. If unclear, ask first. When the user asks you to create a new git commit, follow these steps carefully:
@@ -172212,8 +172234,33 @@ var init_shell = __esm(() => {
172212
172234
 
172213
172235
  // src/tools/impl/exec-command.ts
172214
172236
  import { spawn as spawn6 } from "node:child_process";
172215
- function sleep8(ms) {
172216
- return new Promise((resolve13) => setTimeout(resolve13, ms));
172237
+ function createAbortError() {
172238
+ const error54 = new Error("The operation was aborted");
172239
+ error54.name = "AbortError";
172240
+ return error54;
172241
+ }
172242
+ function throwIfAborted(signal) {
172243
+ if (signal?.aborted) {
172244
+ throw createAbortError();
172245
+ }
172246
+ }
172247
+ function sleep8(ms, signal) {
172248
+ if (!signal) {
172249
+ return new Promise((resolve13) => setTimeout(resolve13, ms));
172250
+ }
172251
+ throwIfAborted(signal);
172252
+ return new Promise((resolve13, reject) => {
172253
+ const timer = setTimeout(() => {
172254
+ signal.removeEventListener("abort", onAbort);
172255
+ resolve13();
172256
+ }, ms);
172257
+ const onAbort = () => {
172258
+ clearTimeout(timer);
172259
+ signal.removeEventListener("abort", onAbort);
172260
+ reject(createAbortError());
172261
+ };
172262
+ signal.addEventListener("abort", onAbort, { once: true });
172263
+ });
172217
172264
  }
172218
172265
  function clampYieldTime(value, fallback) {
172219
172266
  const time3 = Number.isFinite(value) ? Number(value) : fallback;
@@ -172532,6 +172579,7 @@ async function waitForSessionOutput(params) {
172532
172579
  const startTime = Date.now();
172533
172580
  const deadline = startTime + params.yieldTimeMs;
172534
172581
  let emittedOffset = params.startOffset;
172582
+ throwIfAborted(params.signal);
172535
172583
  while (Date.now() < deadline && params.session.status === "running") {
172536
172584
  if (params.onOutput && params.session.output.length > emittedOffset) {
172537
172585
  for (const chunk of getSessionOutputChunks(params.session, emittedOffset, params.session.output.length)) {
@@ -172539,8 +172587,9 @@ async function waitForSessionOutput(params) {
172539
172587
  }
172540
172588
  emittedOffset = params.session.output.length;
172541
172589
  }
172542
- await sleep8(25);
172590
+ await sleep8(25, params.signal);
172543
172591
  }
172592
+ throwIfAborted(params.signal);
172544
172593
  if (params.onOutput && params.session.output.length > emittedOffset) {
172545
172594
  for (const chunk of getSessionOutputChunks(params.session, emittedOffset, params.session.output.length)) {
172546
172595
  params.onOutput(chunk.text, chunk.stream);
@@ -172619,6 +172668,7 @@ async function exec_command(args) {
172619
172668
  session,
172620
172669
  startOffset: 0,
172621
172670
  yieldTimeMs,
172671
+ signal: args.signal,
172622
172672
  onOutput: args.onOutput
172623
172673
  });
172624
172674
  const sessionId = session.status === "running" ? session.id : null;
@@ -172652,7 +172702,7 @@ async function write_stdin(args) {
172652
172702
  }
172653
172703
  if (chars) {
172654
172704
  backgroundProcess.process.write(chars);
172655
- await sleep8(100);
172705
+ await sleep8(100, args.signal);
172656
172706
  }
172657
172707
  const startOffset = session.readOffset;
172658
172708
  const yieldTimeMs = clampWriteStdinYieldTime(args.yield_time_ms, chars);
@@ -172660,6 +172710,7 @@ async function write_stdin(args) {
172660
172710
  session,
172661
172711
  startOffset,
172662
172712
  yieldTimeMs,
172713
+ signal: args.signal,
172663
172714
  onOutput: args.onOutput
172664
172715
  });
172665
172716
  const nextSessionId = session.status === "running" ? session.id : null;
@@ -189126,8 +189177,8 @@ function swapProviderPrefix(parentHandle, recommendedHandle) {
189126
189177
  const recommendedProvider = getProviderPrefix(recommendedHandle);
189127
189178
  if (!recommendedProvider || recommendedProvider !== baseProvider)
189128
189179
  return null;
189129
- const modelPortion = recommendedHandle.slice(recommendedProvider.length + 1);
189130
- return `${parentProvider}/${modelPortion}`;
189180
+ const modelPortion2 = recommendedHandle.slice(recommendedProvider.length + 1);
189181
+ return `${parentProvider}/${modelPortion2}`;
189131
189182
  }
189132
189183
  async function resolveSubagentModel(options3) {
189133
189184
  const { userModel, recommendedModel, parentModelHandle, billingTier } = options3;
@@ -202861,14 +202912,23 @@ function resolveZaiConnection(options3) {
202861
202912
  }
202862
202913
  function getCatalogModel(provider, modelId, oauthCredentials) {
202863
202914
  const spec = getPiProviderSpec(provider);
202864
- if (!spec.piProvider)
202915
+ const piProvider = spec.piProvider;
202916
+ if (!piProvider)
202865
202917
  return;
202866
- const model = getModels(spec.piProvider).find((model2) => model2.id === modelId);
202918
+ const catalog = getModels(piProvider);
202919
+ const fallbackModelId = fallbackCatalogModelId(piProvider, modelId);
202920
+ const model = catalog.find((model2) => model2.id === modelId) ?? catalog.find((model2) => model2.id === fallbackModelId);
202867
202921
  if (!model || !oauthCredentials)
202868
202922
  return model;
202869
- const oauthProvider = getOAuthProvider(spec.piProvider);
202923
+ const oauthProvider = getOAuthProvider(piProvider);
202870
202924
  return oauthProvider?.modifyModels?.([model], oauthCredentials)[0] ?? model;
202871
202925
  }
202926
+ function fallbackCatalogModelId(provider, modelId) {
202927
+ if (provider !== "openai")
202928
+ return;
202929
+ const withoutReleaseDate = modelId.replace(/-\d{4}-\d{2}-\d{2}$/, "");
202930
+ return withoutReleaseDate === modelId ? undefined : withoutReleaseDate;
202931
+ }
202872
202932
  function customOpenAICompatibleModel(input) {
202873
202933
  return {
202874
202934
  id: input.modelId,
@@ -203526,6 +203586,11 @@ function maxTokensForSettings(modelSettings) {
203526
203586
  const maxTokens = modelSettings.max_tokens;
203527
203587
  return typeof maxTokens === "number" && Number.isFinite(maxTokens) ? maxTokens : undefined;
203528
203588
  }
203589
+ function serviceTierForSettings(model, modelSettings) {
203590
+ if (model.api !== "openai-codex-responses")
203591
+ return;
203592
+ return modelSettings.service_tier === "priority" ? "priority" : undefined;
203593
+ }
203529
203594
  function toLocalAssistantMessage(message, input) {
203530
203595
  return {
203531
203596
  id: message.responseId ?? `local-assistant-${Date.now()}`,
@@ -203624,6 +203689,9 @@ class PiStreamAdapter {
203624
203689
  sessionId: input.conversationId,
203625
203690
  ...reasoningForSettings(input.agent.model_settings) ? { reasoning: reasoningForSettings(input.agent.model_settings) } : {},
203626
203691
  ...maxTokensForSettings(input.agent.model_settings) ? { maxTokens: maxTokensForSettings(input.agent.model_settings) } : {},
203692
+ ...serviceTierForSettings(resolved.model, input.agent.model_settings) ? {
203693
+ serviceTier: serviceTierForSettings(resolved.model, input.agent.model_settings)
203694
+ } : {},
203627
203695
  ...boolValue(input.agent.model_settings.parallel_tool_calls) !== undefined ? {
203628
203696
  parallelToolCalls: boolValue(input.agent.model_settings.parallel_tool_calls)
203629
203697
  } : {}
@@ -205453,6 +205521,7 @@ __export(exports_model2, {
205453
205521
  normalizeModelHandleForRegistry: () => normalizeModelHandleForRegistry2,
205454
205522
  models: () => models3,
205455
205523
  isLocalModelHandle: () => isLocalModelHandle2,
205524
+ isLocalChatGptOAuthModelHandle: () => isLocalChatGptOAuthModelHandle2,
205456
205525
  getResumeRefreshArgs: () => getResumeRefreshArgs2,
205457
205526
  getReasoningTierOptionsForHandle: () => getReasoningTierOptionsForHandle2,
205458
205527
  getModelUpdateArgs: () => getModelUpdateArgs2,
@@ -205464,7 +205533,9 @@ __export(exports_model2, {
205464
205533
  getLocalModelLabel: () => getLocalModelLabel2,
205465
205534
  getDefaultModelForTier: () => getDefaultModelForTier2,
205466
205535
  getDefaultModel: () => getDefaultModel2,
205467
- formatAvailableModels: () => formatAvailableModels2
205536
+ getChatGptFastRegistryHandleForModelHandle: () => getChatGptFastRegistryHandleForModelHandle2,
205537
+ formatAvailableModels: () => formatAvailableModels2,
205538
+ CHATGPT_FAST_SERVICE_TIER: () => CHATGPT_FAST_SERVICE_TIER2
205468
205539
  });
205469
205540
  function isLocalModelHandle2(modelHandle) {
205470
205541
  return LOCAL_MODEL_HANDLE_PREFIXES2.some((prefix) => modelHandle.startsWith(prefix));
@@ -205476,10 +205547,50 @@ function getLocalModelLabel2(modelHandle) {
205476
205547
  function isModelReasoningEffort2(value) {
205477
205548
  return typeof value === "string" && REASONING_EFFORT_ORDER2.includes(value);
205478
205549
  }
205550
+ function normalizeModelHandleForRegistry2(modelHandle) {
205551
+ if (!modelHandle)
205552
+ return null;
205553
+ const [provider, ...modelParts] = modelHandle.split("/");
205554
+ const model = modelParts.join("/");
205555
+ if ((provider === CHATGPT_OAUTH_LLM_CONFIG_PROVIDER2 || provider === LOCAL_CHATGPT_OAUTH_HANDLE_PREFIX2.slice(0, -1)) && model.length > 0 && !model.endsWith("-fast")) {
205556
+ return `${OPENAI_CODEX_PROVIDER_NAME}/${model}`;
205557
+ }
205558
+ return modelHandle;
205559
+ }
205560
+ function modelPortion2(modelHandle) {
205561
+ const slashIndex = modelHandle.indexOf("/");
205562
+ if (slashIndex === -1)
205563
+ return null;
205564
+ return modelHandle.slice(slashIndex + 1);
205565
+ }
205566
+ function isLocalChatGptOAuthModelHandle2(modelHandle) {
205567
+ return modelHandle.startsWith(LOCAL_CHATGPT_OAUTH_HANDLE_PREFIX2);
205568
+ }
205569
+ function getChatGptFastRegistryHandleForModelHandle2(modelHandle) {
205570
+ const [provider] = modelHandle.split("/");
205571
+ if (provider !== LOCAL_CHATGPT_OAUTH_HANDLE_PREFIX2.slice(0, -1) && provider !== CHATGPT_OAUTH_LLM_CONFIG_PROVIDER2) {
205572
+ return null;
205573
+ }
205574
+ const normalized = normalizeModelHandleForRegistry2(modelHandle);
205575
+ if (!normalized?.startsWith(`${OPENAI_CODEX_PROVIDER_NAME}/`))
205576
+ return null;
205577
+ const model = modelPortion2(normalized);
205578
+ if (!model || model.endsWith("-fast"))
205579
+ return null;
205580
+ const fastHandle = `${OPENAI_CODEX_PROVIDER_NAME}/${model}-fast`;
205581
+ return models3.some((entry) => entry.handle === fastHandle) ? fastHandle : null;
205582
+ }
205583
+ function displayRegistryHandleForServiceTier2(modelHandle, serviceTier) {
205584
+ if (serviceTier === CHATGPT_FAST_SERVICE_TIER2) {
205585
+ return getChatGptFastRegistryHandleForModelHandle2(modelHandle) ?? modelHandle;
205586
+ }
205587
+ return normalizeModelHandleForRegistry2(modelHandle) ?? modelHandle;
205588
+ }
205479
205589
  function getReasoningTierOptionsForHandle2(modelHandle, contextWindow) {
205480
205590
  const byEffort = new Map;
205591
+ const registryHandle = normalizeModelHandleForRegistry2(modelHandle) ?? modelHandle;
205481
205592
  for (const model of models3) {
205482
- if (model.handle !== modelHandle)
205593
+ if (model.handle !== registryHandle)
205483
205594
  continue;
205484
205595
  if (contextWindow !== undefined) {
205485
205596
  const mCtx = model.updateArgs?.context_window;
@@ -205493,10 +205604,10 @@ function getReasoningTierOptionsForHandle2(modelHandle, contextWindow) {
205493
205604
  byEffort.set(effort, model.id);
205494
205605
  }
205495
205606
  }
205496
- if (byEffort.size === 0 && isLocalModelHandle2(modelHandle)) {
205607
+ if (byEffort.size === 0 && isLocalModelHandle2(registryHandle)) {
205497
205608
  return LOCAL_REASONING_EFFORT_ORDER2.map((effort) => ({
205498
205609
  effort,
205499
- modelId: modelHandle
205610
+ modelId: registryHandle
205500
205611
  }));
205501
205612
  }
205502
205613
  return REASONING_EFFORT_ORDER2.flatMap((effort) => {
@@ -205540,14 +205651,16 @@ function getModelInfo2(modelIdentifier) {
205540
205651
  const byId = models3.find((m2) => m2.id === modelIdentifier);
205541
205652
  if (byId)
205542
205653
  return byId;
205543
- const byHandle = models3.find((m2) => m2.handle === modelIdentifier);
205654
+ const normalizedHandle = normalizeModelHandleForRegistry2(modelIdentifier);
205655
+ const byHandle = models3.find((m2) => m2.handle === normalizedHandle);
205544
205656
  if (byHandle)
205545
205657
  return byHandle;
205546
205658
  return null;
205547
205659
  }
205548
205660
  function getModelInfoForLlmConfig2(modelHandle, llmConfig) {
205549
- const direct = getModelInfo2(modelHandle);
205550
- let candidates2 = models3.filter((m2) => m2.handle === modelHandle);
205661
+ const registryHandle = displayRegistryHandleForServiceTier2(modelHandle, llmConfig?.service_tier ?? null);
205662
+ const direct = getModelInfo2(registryHandle);
205663
+ let candidates2 = models3.filter((m2) => m2.handle === registryHandle);
205551
205664
  if (candidates2.length === 0) {
205552
205665
  return direct;
205553
205666
  }
@@ -205589,15 +205702,6 @@ function buildModelHandleFromConfig2(config3) {
205589
205702
  }
205590
205703
  return config3.model ?? null;
205591
205704
  }
205592
- function normalizeModelHandleForRegistry2(modelHandle) {
205593
- if (!modelHandle)
205594
- return null;
205595
- const [provider, ...modelParts] = modelHandle.split("/");
205596
- if (provider === "chatgpt_oauth" && modelParts.length > 0) {
205597
- return `${OPENAI_CODEX_PROVIDER_NAME}/${modelParts.join("/")}`;
205598
- }
205599
- return modelHandle;
205600
- }
205601
205705
  function shouldPreserveContextWindowForModelSelection2(input) {
205602
205706
  const currentRegistryModelHandle = normalizeModelHandleForRegistry2(input.currentModelHandle ?? buildModelHandleFromConfig2(input.currentLlmConfig));
205603
205707
  const selectedRegistryModelHandle = normalizeModelHandleForRegistry2(input.selectedModelHandle);
@@ -205658,22 +205762,23 @@ function getResumeRefreshArgs2(presetUpdateArgs, agent2) {
205658
205762
  }
205659
205763
  function findModelByHandle2(handle) {
205660
205764
  const pickPreferred = (candidates2) => candidates2.find((m2) => m2.isDefault) ?? candidates2.find((m2) => m2.isFeatured) ?? candidates2.find((m2) => m2.updateArgs?.reasoning_effort === "medium") ?? candidates2.find((m2) => m2.updateArgs?.reasoning_effort === "high") ?? candidates2[0] ?? null;
205661
- const exactMatch = models3.find((m2) => m2.handle === handle);
205765
+ const registryHandle = normalizeModelHandleForRegistry2(handle) ?? handle;
205766
+ const exactMatch = models3.find((m2) => m2.handle === registryHandle);
205662
205767
  if (exactMatch)
205663
205768
  return exactMatch;
205664
- const [provider, ...rest3] = handle.split("/");
205769
+ const [provider, ...rest3] = registryHandle.split("/");
205665
205770
  if (provider && rest3.length > 0) {
205666
- const modelPortion = rest3.join("/");
205771
+ const modelPortion3 = rest3.join("/");
205667
205772
  const providerMatches = models3.filter((m2) => {
205668
205773
  if (!m2.handle.startsWith(`${provider}/`))
205669
205774
  return false;
205670
205775
  const mModelPortion = m2.handle.slice(provider.length + 1);
205671
- return mModelPortion.includes(modelPortion) || modelPortion.includes(mModelPortion);
205776
+ return mModelPortion.includes(modelPortion3) || modelPortion3.includes(mModelPortion);
205672
205777
  });
205673
205778
  const providerMatch = pickPreferred(providerMatches);
205674
205779
  if (providerMatch)
205675
205780
  return providerMatch;
205676
- const suffixMatches = models3.filter((m2) => m2.handle.endsWith(`/${modelPortion}`));
205781
+ const suffixMatches = models3.filter((m2) => m2.handle.endsWith(`/${modelPortion3}`));
205677
205782
  const suffixMatch = pickPreferred(suffixMatches);
205678
205783
  if (suffixMatch)
205679
205784
  return suffixMatch;
@@ -205702,7 +205807,7 @@ function resolveModelByLlmConfig2(llmConfigModel) {
205702
205807
  return exactMatch.id;
205703
205808
  return null;
205704
205809
  }
205705
- var models3, REASONING_EFFORT_ORDER2, LOCAL_REASONING_EFFORT_ORDER2, LOCAL_MODEL_HANDLE_PREFIXES2, RESUME_REFRESH_FIELDS2;
205810
+ var models3, REASONING_EFFORT_ORDER2, LOCAL_REASONING_EFFORT_ORDER2, LOCAL_MODEL_HANDLE_PREFIXES2, LOCAL_CHATGPT_OAUTH_HANDLE_PREFIX2 = "openai-codex/", CHATGPT_OAUTH_LLM_CONFIG_PROVIDER2 = "chatgpt_oauth", CHATGPT_FAST_SERVICE_TIER2 = "priority", RESUME_REFRESH_FIELDS2;
205706
205811
  var init_model2 = __esm(() => {
205707
205812
  init_models7();
205708
205813
  init_openai_codex_provider();
@@ -256021,6 +256126,23 @@ var init_memory_subagent_completion = __esm(() => {
256021
256126
  init_system_prompt_warning();
256022
256127
  });
256023
256128
 
256129
+ // src/cli/helpers/reflection-gate.ts
256130
+ function isReflectionSubagentActive(subagents, agentId, conversationId) {
256131
+ return subagents.some((agent2) => {
256132
+ if (agent2.type.toLowerCase() !== "reflection") {
256133
+ return false;
256134
+ }
256135
+ if (agent2.status !== "pending" && agent2.status !== "running") {
256136
+ return false;
256137
+ }
256138
+ if (!agent2.parentAgentId) {
256139
+ return false;
256140
+ }
256141
+ const parentConversationId = agent2.parentConversationId ?? "default";
256142
+ return agent2.parentAgentId === agentId && parentConversationId === conversationId;
256143
+ });
256144
+ }
256145
+
256024
256146
  // src/utils/file-lock.ts
256025
256147
  import { open as open3, readFile as readFile11, stat as stat9, unlink as unlink3 } from "node:fs/promises";
256026
256148
  async function withFileLock(lockPath, fn, options3) {
@@ -256739,6 +256861,121 @@ var init_reflection_transcript = __esm(() => {
256739
256861
  stateMutexes = new Map;
256740
256862
  });
256741
256863
 
256864
+ // src/cli/helpers/reflection-launcher.ts
256865
+ async function resolveSystemPrompt2(agentId, systemPrompt) {
256866
+ if (systemPrompt) {
256867
+ return systemPrompt;
256868
+ }
256869
+ try {
256870
+ const agent2 = await getBackend().retrieveAgent(agentId);
256871
+ return agent2.system ?? undefined;
256872
+ } catch {
256873
+ debugLog("memory", "Failed to fetch agent system prompt for reflection payload");
256874
+ return;
256875
+ }
256876
+ }
256877
+ function resolveCompletionConversationId(completionConversationId, fallback) {
256878
+ if (typeof completionConversationId === "function") {
256879
+ return completionConversationId();
256880
+ }
256881
+ return completionConversationId ?? fallback;
256882
+ }
256883
+ async function launchReflectionSubagent(options3) {
256884
+ const {
256885
+ agentId,
256886
+ conversationId,
256887
+ memfsEnabled,
256888
+ triggerSource,
256889
+ description,
256890
+ recompileByConversation,
256891
+ recompileQueuedByConversation,
256892
+ onCompletionMessage
256893
+ } = options3;
256894
+ if (!memfsEnabled) {
256895
+ return { launched: false, reason: "memfs_disabled" };
256896
+ }
256897
+ if (isReflectionSubagentActive(getSubagents(), agentId, conversationId)) {
256898
+ debugLog("memory", `Skipping reflection launch (${triggerSource}) because one is already active`);
256899
+ return { launched: false, reason: "already_active" };
256900
+ }
256901
+ try {
256902
+ const systemPrompt = await resolveSystemPrompt2(agentId, options3.systemPrompt);
256903
+ const autoPayload = await buildAutoReflectionPayload(agentId, conversationId, systemPrompt);
256904
+ if (!autoPayload) {
256905
+ debugLog("memory", `Skipping reflection launch (${triggerSource}) because transcript has no new content`);
256906
+ return { launched: false, reason: "no_payload" };
256907
+ }
256908
+ const memoryDir = getScopedMemoryFilesystemRoot(agentId);
256909
+ const parentMemory = await buildParentMemorySnapshot(memoryDir);
256910
+ const reflectionPrompt = buildReflectionSubagentPrompt({
256911
+ memoryDir,
256912
+ parentMemory
256913
+ });
256914
+ const { spawnBackgroundSubagentTask: spawnBackgroundSubagentTask2, waitForBackgroundSubagentAgentId: waitForBackgroundSubagentAgentId2 } = await Promise.resolve().then(() => (init_task(), exports_task));
256915
+ const { subagentId } = spawnBackgroundSubagentTask2({
256916
+ subagentType: "reflection",
256917
+ prompt: reflectionPrompt,
256918
+ description,
256919
+ silentCompletion: true,
256920
+ transcriptPath: autoPayload.payloadPath,
256921
+ parentScope: { agentId, conversationId },
256922
+ onComplete: async ({ success: success2, error: error54, agentId: reflectionAgentId2 }) => {
256923
+ telemetry.trackReflectionEnd(triggerSource, success2, {
256924
+ subagentId: reflectionAgentId2 ?? undefined,
256925
+ conversationId,
256926
+ error: error54
256927
+ });
256928
+ await finalizeAutoReflectionPayload(agentId, conversationId, autoPayload.payloadPath, autoPayload.endSnapshotLine, success2);
256929
+ const completionMessage = await handleMemorySubagentCompletion({
256930
+ agentId,
256931
+ conversationId: resolveCompletionConversationId(options3.completionConversationId, conversationId),
256932
+ subagentType: "reflection",
256933
+ success: success2,
256934
+ error: error54
256935
+ }, {
256936
+ recompileByConversation,
256937
+ recompileQueuedByConversation,
256938
+ logRecompileFailure: (message) => debugWarn("memory", message)
256939
+ });
256940
+ await onCompletionMessage?.(completionMessage, {
256941
+ success: success2,
256942
+ error: error54,
256943
+ reflectionAgentId: reflectionAgentId2 ?? undefined
256944
+ });
256945
+ }
256946
+ });
256947
+ const reflectionAgentId = await waitForBackgroundSubagentAgentId2(subagentId, 1000);
256948
+ telemetry.trackReflectionStart(triggerSource, {
256949
+ subagentId: reflectionAgentId ?? undefined,
256950
+ conversationId,
256951
+ startMessageId: autoPayload.startMessageId,
256952
+ endMessageId: autoPayload.endMessageId
256953
+ });
256954
+ debugLog("memory", `Launched reflection subagent (${triggerSource})`);
256955
+ return {
256956
+ launched: true,
256957
+ payloadPath: autoPayload.payloadPath,
256958
+ subagentId,
256959
+ reflectionAgentId: reflectionAgentId ?? undefined,
256960
+ startMessageId: autoPayload.startMessageId,
256961
+ endMessageId: autoPayload.endMessageId
256962
+ };
256963
+ } catch (error54) {
256964
+ debugWarn("memory", `Failed to launch reflection subagent (${triggerSource}): ${error54 instanceof Error ? error54.message : String(error54)}`);
256965
+ return { launched: false, reason: "error", error: error54 };
256966
+ }
256967
+ }
256968
+ var AUTO_REFLECTION_DESCRIPTION = "Reflect on recent conversations";
256969
+ var init_reflection_launcher = __esm(() => {
256970
+ init_memory_filesystem2();
256971
+ init_subagent_state();
256972
+ init_backend2();
256973
+ init_memory_subagent_completion();
256974
+ init_reflection_transcript();
256975
+ init_telemetry();
256976
+ init_debug();
256977
+ });
256978
+
256742
256979
  // src/cli/helpers/agent-info.ts
256743
256980
  function getRelativeTime(dateStr) {
256744
256981
  const date6 = new Date(dateStr);
@@ -260664,107 +260901,39 @@ function trackListenerUserInput(messages, modelId) {
260664
260901
  telemetry.trackUserInput(inputText, "user", modelId);
260665
260902
  }
260666
260903
  }
260667
- function hasActiveReflectionSubagent(agentId, conversationId) {
260668
- return getSubagents().some((agent2) => {
260669
- if (agent2.type.toLowerCase() !== "reflection") {
260670
- return false;
260671
- }
260672
- if (agent2.status !== "pending" && agent2.status !== "running") {
260673
- return false;
260674
- }
260675
- if (!agent2.parentAgentId) {
260676
- return false;
260677
- }
260678
- const parentConversationId = agent2.parentConversationId ?? "default";
260679
- return agent2.parentAgentId === agentId && parentConversationId === conversationId;
260680
- });
260681
- }
260682
260904
  function escapeTaskNotificationSummary(summary) {
260683
260905
  return summary.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
260684
260906
  }
260685
260907
  function buildMaybeLaunchReflectionSubagent(params) {
260686
260908
  return async (triggerSource) => {
260687
260909
  const { runtime, socket, agentId, conversationId, cachedAgent } = params;
260688
- if (!agentId || !settingsManager.isMemfsEnabled(agentId)) {
260689
- return false;
260690
- }
260691
- if (hasActiveReflectionSubagent(agentId, conversationId)) {
260692
- debugLog("memory", `Skipping auto reflection launch (${triggerSource}) because one is already active`);
260910
+ if (!agentId) {
260693
260911
  return false;
260694
260912
  }
260695
- try {
260696
- let systemPrompt = cachedAgent?.system ?? undefined;
260697
- if (!systemPrompt) {
260698
- try {
260699
- const agent2 = await getBackend().retrieveAgent(agentId);
260700
- systemPrompt = agent2.system ?? undefined;
260701
- } catch {
260702
- debugLog("memory", "Failed to fetch agent system prompt for reflection payload");
260703
- }
260704
- }
260705
- const autoPayload = await buildAutoReflectionPayload(agentId, conversationId, systemPrompt);
260706
- if (!autoPayload) {
260707
- debugLog("memory", `Skipping auto reflection launch (${triggerSource}) because transcript has no new content`);
260708
- return false;
260913
+ const result = await launchReflectionSubagent({
260914
+ agentId,
260915
+ conversationId,
260916
+ memfsEnabled: settingsManager.isMemfsEnabled(agentId),
260917
+ triggerSource,
260918
+ description: AUTO_REFLECTION_DESCRIPTION,
260919
+ systemPrompt: cachedAgent?.system ?? undefined,
260920
+ recompileByConversation: runtime.listener.systemPromptRecompileByConversation,
260921
+ recompileQueuedByConversation: runtime.listener.queuedSystemPromptRecompileByConversation,
260922
+ onCompletionMessage: async (completionMessage) => {
260923
+ const notificationXml = `<task-notification><summary>${escapeTaskNotificationSummary(completionMessage)}</summary></task-notification>`;
260924
+ emitCanonicalMessageDelta(socket, runtime, {
260925
+ type: "message",
260926
+ id: `user-msg-${crypto.randomUUID()}`,
260927
+ date: new Date().toISOString(),
260928
+ message_type: "user_message",
260929
+ content: [{ type: "text", text: notificationXml }]
260930
+ }, {
260931
+ agent_id: agentId,
260932
+ conversation_id: conversationId
260933
+ });
260709
260934
  }
260710
- const memoryDir = getMemoryFilesystemRoot(agentId);
260711
- const parentMemory = await buildParentMemorySnapshot(memoryDir);
260712
- const reflectionPrompt = buildReflectionSubagentPrompt({
260713
- memoryDir,
260714
- parentMemory
260715
- });
260716
- const { spawnBackgroundSubagentTask: spawnBackgroundSubagentTask2, waitForBackgroundSubagentAgentId: waitForBackgroundSubagentAgentId2 } = await Promise.resolve().then(() => (init_task(), exports_task));
260717
- const { subagentId } = spawnBackgroundSubagentTask2({
260718
- subagentType: "reflection",
260719
- prompt: reflectionPrompt,
260720
- description: AUTO_REFLECTION_DESCRIPTION,
260721
- silentCompletion: true,
260722
- transcriptPath: autoPayload.payloadPath,
260723
- parentScope: { agentId, conversationId },
260724
- onComplete: async ({ success: success2, error: error54, agentId: reflectionAgentId2 }) => {
260725
- telemetry.trackReflectionEnd(triggerSource, success2, {
260726
- subagentId: reflectionAgentId2 ?? undefined,
260727
- conversationId,
260728
- error: error54
260729
- });
260730
- await finalizeAutoReflectionPayload(agentId, conversationId, autoPayload.payloadPath, autoPayload.endSnapshotLine, success2);
260731
- const completionMessage = await handleMemorySubagentCompletion({
260732
- agentId,
260733
- conversationId,
260734
- subagentType: "reflection",
260735
- success: success2,
260736
- error: error54
260737
- }, {
260738
- recompileByConversation: runtime.listener.systemPromptRecompileByConversation,
260739
- recompileQueuedByConversation: runtime.listener.queuedSystemPromptRecompileByConversation,
260740
- logRecompileFailure: (message) => debugWarn("memory", message)
260741
- });
260742
- const notificationXml = `<task-notification><summary>${escapeTaskNotificationSummary(completionMessage)}</summary></task-notification>`;
260743
- emitCanonicalMessageDelta(socket, runtime, {
260744
- type: "message",
260745
- id: `user-msg-${crypto.randomUUID()}`,
260746
- date: new Date().toISOString(),
260747
- message_type: "user_message",
260748
- content: [{ type: "text", text: notificationXml }]
260749
- }, {
260750
- agent_id: agentId,
260751
- conversation_id: conversationId
260752
- });
260753
- }
260754
- });
260755
- const reflectionAgentId = await waitForBackgroundSubagentAgentId2(subagentId, 1000);
260756
- telemetry.trackReflectionStart(triggerSource, {
260757
- subagentId: reflectionAgentId ?? undefined,
260758
- conversationId,
260759
- startMessageId: autoPayload.startMessageId,
260760
- endMessageId: autoPayload.endMessageId
260761
- });
260762
- debugLog("memory", `Auto-launched reflection subagent (${triggerSource})`);
260763
- return true;
260764
- } catch (error54) {
260765
- debugWarn("memory", `Failed to auto-launch reflection subagent (${triggerSource}): ${error54 instanceof Error ? error54.message : String(error54)}`);
260766
- return false;
260767
- }
260935
+ });
260936
+ return result.launched;
260768
260937
  };
260769
260938
  }
260770
260939
  async function maybeLaunchPostTurnChannelReflection(params) {
@@ -260924,7 +261093,6 @@ async function handleIncomingMessage(msg, socket, runtime, onStatusChange, conne
260924
261093
  socket,
260925
261094
  agentId,
260926
261095
  conversationId,
260927
- workingDirectory: turnWorkingDirectory,
260928
261096
  cachedAgent
260929
261097
  }) : undefined,
260930
261098
  workingDirectory: turnWorkingDirectory
@@ -261089,7 +261257,6 @@ async function handleIncomingMessage(msg, socket, runtime, onStatusChange, conne
261089
261257
  socket,
261090
261258
  agentId: agentId || "",
261091
261259
  conversationId,
261092
- workingDirectory: turnWorkingDirectory,
261093
261260
  cachedAgent
261094
261261
  })
261095
261262
  });
@@ -261427,19 +261594,16 @@ async function handleIncomingMessage(msg, socket, runtime, onStatusChange, conne
261427
261594
  evictConversationRuntimeIfIdle(runtime);
261428
261595
  }
261429
261596
  }
261430
- var AUTO_REFLECTION_DESCRIPTION = "Reflect on recent conversations";
261431
261597
  var init_turn = __esm(async () => {
261432
261598
  init_approval_recovery();
261433
261599
  init_check_approval();
261434
261600
  init_context();
261435
261601
  init_conversation_description();
261436
- init_memory_filesystem2();
261437
- init_subagent_state();
261438
261602
  init_turn_recovery_policy();
261439
261603
  init_backend2();
261440
261604
  init_error_formatter();
261441
261605
  init_memory_reminder();
261442
- init_memory_subagent_completion();
261606
+ init_reflection_launcher();
261443
261607
  init_reflection_transcript();
261444
261608
  init_engine3();
261445
261609
  init_settings_manager();
@@ -261775,23 +261939,6 @@ var init_control_inputs = __esm(async () => {
261775
261939
  ]);
261776
261940
  });
261777
261941
 
261778
- // src/cli/helpers/reflection-gate.ts
261779
- function isReflectionSubagentActive(subagents, agentId, conversationId) {
261780
- return subagents.some((agent2) => {
261781
- if (agent2.type.toLowerCase() !== "reflection") {
261782
- return false;
261783
- }
261784
- if (agent2.status !== "pending" && agent2.status !== "running") {
261785
- return false;
261786
- }
261787
- if (!agent2.parentAgentId) {
261788
- return false;
261789
- }
261790
- const parentConversationId = agent2.parentConversationId ?? "default";
261791
- return agent2.parentAgentId === agentId && parentConversationId === conversationId;
261792
- });
261793
- }
261794
-
261795
261942
  // src/websocket/terminal-handler.ts
261796
261943
  import * as os4 from "node:os";
261797
261944
  import WebSocket5 from "ws";
@@ -263848,95 +263995,58 @@ async function wireChannelIngress(listener, socket, opts, processQueuedTurn) {
263848
263995
  registry2.setReflectionHandler(async ({ runtime }) => {
263849
263996
  const agentId = runtime.agent_id;
263850
263997
  const conversationId = runtime.conversation_id;
263851
- if (!settingsManager.isMemfsEnabled(agentId)) {
263852
- return {
263853
- handled: true,
263854
- text: "Reflection needs the memory filesystem to be enabled for this agent. Use /remember for a lightweight memory update instead."
263855
- };
263856
- }
263857
- if (isReflectionSubagentActive(getSubagents(), agentId, conversationId)) {
263858
- return {
263859
- handled: true,
263860
- text: "A reflection agent is already running for this conversation."
263861
- };
263862
- }
263863
- try {
263864
- let systemPrompt;
263865
- try {
263866
- const agent2 = await getBackend().retrieveAgent(agentId);
263867
- systemPrompt = agent2.system ?? undefined;
263868
- } catch {}
263869
- const autoPayload = await buildAutoReflectionPayload(agentId, conversationId, systemPrompt);
263870
- if (!autoPayload) {
263998
+ const result = await launchReflectionSubagent({
263999
+ agentId,
264000
+ conversationId,
264001
+ memfsEnabled: settingsManager.isMemfsEnabled(agentId),
264002
+ triggerSource: "manual",
264003
+ description: "Reflecting on channel conversation",
264004
+ recompileByConversation: listener.systemPromptRecompileByConversation,
264005
+ recompileQueuedByConversation: listener.queuedSystemPromptRecompileByConversation,
264006
+ onCompletionMessage: async (completionMessage) => {
264007
+ const conversationRuntime = getOrCreateConversationRuntime(listener, agentId, conversationId);
264008
+ const notificationXml = `<task-notification><summary>${escapeTaskNotificationSummary2(completionMessage)}</summary></task-notification>`;
264009
+ emitStreamDelta(socket, conversationRuntime, {
264010
+ type: "message",
264011
+ id: `user-msg-${crypto.randomUUID()}`,
264012
+ date: new Date().toISOString(),
264013
+ message_type: "user_message",
264014
+ content: [{ type: "text", text: notificationXml }]
264015
+ }, {
264016
+ agent_id: agentId,
264017
+ conversation_id: conversationId
264018
+ });
264019
+ }
264020
+ });
264021
+ if (!result.launched) {
264022
+ if (result.reason === "memfs_disabled") {
264023
+ return {
264024
+ handled: true,
264025
+ text: "Reflection needs the memory filesystem to be enabled for this agent. Use /remember for a lightweight memory update instead."
264026
+ };
264027
+ }
264028
+ if (result.reason === "already_active") {
264029
+ return {
264030
+ handled: true,
264031
+ text: "A reflection agent is already running for this conversation."
264032
+ };
264033
+ }
264034
+ if (result.reason === "no_payload") {
263871
264035
  return {
263872
264036
  handled: true,
263873
264037
  text: "No new transcript content to reflect on for this conversation."
263874
264038
  };
263875
264039
  }
263876
- const memoryDir = getMemoryFilesystemRoot(agentId);
263877
- const parentMemory = await buildParentMemorySnapshot(memoryDir);
263878
- const reflectionPrompt = buildReflectionSubagentPrompt({
263879
- memoryDir,
263880
- parentMemory
263881
- });
263882
- const { spawnBackgroundSubagentTask: spawnBackgroundSubagentTask2, waitForBackgroundSubagentAgentId: waitForBackgroundSubagentAgentId2 } = await Promise.resolve().then(() => (init_task(), exports_task));
263883
- const { subagentId } = spawnBackgroundSubagentTask2({
263884
- subagentType: "reflection",
263885
- prompt: reflectionPrompt,
263886
- description: "Reflecting on channel conversation",
263887
- silentCompletion: true,
263888
- transcriptPath: autoPayload.payloadPath,
263889
- parentScope: { agentId, conversationId },
263890
- onComplete: async ({ success: success2, error: error54, agentId: reflectionAgentId2 }) => {
263891
- telemetry.trackReflectionEnd("manual", success2, {
263892
- subagentId: reflectionAgentId2 ?? undefined,
263893
- conversationId,
263894
- error: error54
263895
- });
263896
- await finalizeAutoReflectionPayload(agentId, conversationId, autoPayload.payloadPath, autoPayload.endSnapshotLine, success2);
263897
- const completionMessage = await handleMemorySubagentCompletion({
263898
- agentId,
263899
- conversationId,
263900
- subagentType: "reflection",
263901
- success: success2,
263902
- error: error54
263903
- }, {
263904
- recompileByConversation: listener.systemPromptRecompileByConversation,
263905
- recompileQueuedByConversation: listener.queuedSystemPromptRecompileByConversation,
263906
- logRecompileFailure: (message) => isDebugEnabled() && console.warn(message)
263907
- });
263908
- const conversationRuntime = getOrCreateConversationRuntime(listener, agentId, conversationId);
263909
- const notificationXml = `<task-notification><summary>${escapeTaskNotificationSummary2(completionMessage)}</summary></task-notification>`;
263910
- emitStreamDelta(socket, conversationRuntime, {
263911
- type: "message",
263912
- id: `user-msg-${crypto.randomUUID()}`,
263913
- date: new Date().toISOString(),
263914
- message_type: "user_message",
263915
- content: [{ type: "text", text: notificationXml }]
263916
- }, {
263917
- agent_id: agentId,
263918
- conversation_id: conversationId
263919
- });
263920
- }
263921
- });
263922
- const reflectionAgentId = await waitForBackgroundSubagentAgentId2(subagentId, 1000);
263923
- telemetry.trackReflectionStart("manual", {
263924
- subagentId: reflectionAgentId ?? undefined,
263925
- conversationId,
263926
- startMessageId: autoPayload.startMessageId,
263927
- endMessageId: autoPayload.endMessageId
263928
- });
263929
- return {
263930
- handled: true,
263931
- text: "Started a reflection pass for this conversation."
263932
- };
263933
- } catch (error54) {
263934
- const message = error54 instanceof Error ? error54.message : String(error54);
264040
+ const message = result.error instanceof Error ? result.error.message : String(result.error ?? "Unknown error");
263935
264041
  return {
263936
264042
  handled: true,
263937
264043
  text: `Failed to start reflection: ${message}`
263938
264044
  };
263939
264045
  }
264046
+ return {
264047
+ handled: true,
264048
+ text: "Started a reflection pass for this conversation."
264049
+ };
263940
264050
  });
263941
264051
  registry2.setReady();
263942
264052
  }
@@ -264400,13 +264510,10 @@ function stopListenerClient() {
264400
264510
  stopRuntime(runtime, true);
264401
264511
  }
264402
264512
  var init_lifecycle = __esm(async () => {
264403
- init_memory_filesystem2();
264404
264513
  init_subagent_state();
264405
- init_backend2();
264406
264514
  init_commands();
264407
264515
  init_registry();
264408
- init_memory_subagent_completion();
264409
- init_reflection_transcript();
264516
+ init_reflection_launcher();
264410
264517
  init_runtime_context();
264411
264518
  init_settings_manager();
264412
264519
  init_telemetry();
@@ -268618,7 +268725,7 @@ var exports_prompt_assets2 = {};
268618
268725
  __export(exports_prompt_assets2, {
268619
268726
  validateSystemPromptPreset: () => validateSystemPromptPreset2,
268620
268727
  shouldRecommendDefaultPrompt: () => shouldRecommendDefaultPrompt2,
268621
- resolveSystemPrompt: () => resolveSystemPrompt2,
268728
+ resolveSystemPrompt: () => resolveSystemPrompt3,
268622
268729
  resolveAndBuildSystemPrompt: () => resolveAndBuildSystemPrompt2,
268623
268730
  isKnownPreset: () => isKnownPreset2,
268624
268731
  buildSystemPrompt: () => buildSystemPrompt2,
@@ -268671,9 +268778,9 @@ async function resolveAndBuildSystemPrompt2(promptId, memoryMode) {
268671
268778
  if (isKnownPreset2(id2)) {
268672
268779
  return buildSystemPrompt2(id2, memoryMode);
268673
268780
  }
268674
- return resolveSystemPrompt2(id2);
268781
+ return resolveSystemPrompt3(id2);
268675
268782
  }
268676
- async function resolveSystemPrompt2(systemPromptPreset) {
268783
+ async function resolveSystemPrompt3(systemPromptPreset) {
268677
268784
  if (!systemPromptPreset) {
268678
268785
  return SYSTEM_PROMPT2;
268679
268786
  }
@@ -441608,75 +441715,17 @@ async function runBidirectionalMode(agent2, conversationId, _outputFormat, inclu
441608
441715
  const sharedReminderState = createSharedReminderState();
441609
441716
  const isSubagent = process.env.LETTA_CODE_AGENT_ROLE === "subagent";
441610
441717
  const maybeLaunchReflectionSubagent = async (triggerSource) => {
441611
- if (!settingsManager.isMemfsEnabled(agent2.id)) {
441612
- return false;
441613
- }
441614
- if (isReflectionSubagentActive(getSubagents(), agent2.id, conversationId)) {
441615
- debugLog("memory", `Skipping auto reflection launch (${triggerSource}) because one is already active`);
441616
- return false;
441617
- }
441618
- try {
441619
- let systemPrompt = agent2.system ?? undefined;
441620
- if (!systemPrompt) {
441621
- try {
441622
- const freshAgent = await backend4.retrieveAgent(agent2.id);
441623
- systemPrompt = freshAgent.system ?? undefined;
441624
- } catch {
441625
- debugLog("memory", "Failed to fetch agent system prompt for reflection payload");
441626
- }
441627
- }
441628
- const autoPayload = await buildAutoReflectionPayload(agent2.id, conversationId, systemPrompt);
441629
- if (!autoPayload) {
441630
- debugLog("memory", `Skipping auto reflection launch (${triggerSource}) because transcript has no new content`);
441631
- return false;
441632
- }
441633
- const memoryDir = getMemoryFilesystemRoot(agent2.id);
441634
- const parentMemory = await buildParentMemorySnapshot(memoryDir);
441635
- const reflectionPrompt = buildReflectionSubagentPrompt({
441636
- memoryDir,
441637
- parentMemory
441638
- });
441639
- const { spawnBackgroundSubagentTask: spawnBackgroundSubagentTask2, waitForBackgroundSubagentAgentId: waitForBackgroundSubagentAgentId2 } = await Promise.resolve().then(() => (init_task(), exports_task));
441640
- const { subagentId } = spawnBackgroundSubagentTask2({
441641
- subagentType: "reflection",
441642
- prompt: reflectionPrompt,
441643
- description: AUTO_REFLECTION_DESCRIPTION2,
441644
- silentCompletion: true,
441645
- transcriptPath: autoPayload.payloadPath,
441646
- parentScope: { agentId: agent2.id, conversationId },
441647
- onComplete: async ({ success: success2, error: error54, agentId: reflectionAgentId2 }) => {
441648
- telemetry.trackReflectionEnd(triggerSource, success2, {
441649
- subagentId: reflectionAgentId2 ?? undefined,
441650
- conversationId,
441651
- error: error54
441652
- });
441653
- await finalizeAutoReflectionPayload(agent2.id, conversationId, autoPayload.payloadPath, autoPayload.endSnapshotLine, success2);
441654
- await handleMemorySubagentCompletion({
441655
- agentId: agent2.id,
441656
- conversationId,
441657
- subagentType: "reflection",
441658
- success: success2,
441659
- error: error54
441660
- }, {
441661
- recompileByConversation: systemPromptRecompileByConversation,
441662
- recompileQueuedByConversation: queuedSystemPromptRecompileByConversation,
441663
- logRecompileFailure: (message) => debugWarn("memory", message)
441664
- });
441665
- }
441666
- });
441667
- const reflectionAgentId = await waitForBackgroundSubagentAgentId2(subagentId, 1000);
441668
- telemetry.trackReflectionStart(triggerSource, {
441669
- subagentId: reflectionAgentId ?? undefined,
441670
- conversationId,
441671
- startMessageId: autoPayload.startMessageId,
441672
- endMessageId: autoPayload.endMessageId
441673
- });
441674
- debugLog("memory", `Auto-launched reflection subagent (${triggerSource})`);
441675
- return true;
441676
- } catch (error54) {
441677
- debugWarn("memory", `Failed to auto-launch reflection subagent (${triggerSource}): ${error54 instanceof Error ? error54.message : String(error54)}`);
441678
- return false;
441679
- }
441718
+ const result = await launchReflectionSubagent({
441719
+ agentId: agent2.id,
441720
+ conversationId,
441721
+ memfsEnabled: settingsManager.isMemfsEnabled(agent2.id),
441722
+ triggerSource,
441723
+ description: AUTO_REFLECTION_DESCRIPTION,
441724
+ systemPrompt: agent2.system ?? undefined,
441725
+ recompileByConversation: systemPromptRecompileByConversation,
441726
+ recompileQueuedByConversation: queuedSystemPromptRecompileByConversation
441727
+ });
441728
+ return result.launched;
441680
441729
  };
441681
441730
  const resolveAllPendingApprovals = async () => {
441682
441731
  const { getResumeDataFromBackend: getResumeDataFromBackend3 } = await Promise.resolve().then(() => (init_check_approval(), exports_check_approval));
@@ -442580,7 +442629,7 @@ async function runBidirectionalMode(agent2, conversationId, _outputFormat, inclu
442580
442629
  setMessageQueueAdder(null);
442581
442630
  await exitBidirectional(0, "headless_bidirectional_stdin_closed");
442582
442631
  }
442583
- var LLM_API_ERROR_MAX_RETRIES2 = 3, EMPTY_RESPONSE_MAX_RETRIES2 = 2, PROVIDER_FALLBACK_MAP2, CONVERSATION_BUSY_MAX_RETRIES = 3, AUTO_REFLECTION_DESCRIPTION2 = "Reflect on recent conversations", __headlessTestUtils;
442632
+ var LLM_API_ERROR_MAX_RETRIES2 = 3, EMPTY_RESPONSE_MAX_RETRIES2 = 2, PROVIDER_FALLBACK_MAP2, CONVERSATION_BUSY_MAX_RETRIES = 3, __headlessTestUtils;
442584
442633
  var init_headless = __esm(async () => {
442585
442634
  init_error();
442586
442635
  init_telemetry();
@@ -442593,17 +442642,15 @@ var init_headless = __esm(async () => {
442593
442642
  init_create6();
442594
442643
  init_list_messages_handler();
442595
442644
  init_memory3();
442596
- init_memory_filesystem2();
442597
442645
  init_model();
442598
442646
  init_modify();
442599
442647
  init_personality();
442600
442648
  init_skill_sources();
442601
- init_subagent_state();
442602
442649
  init_backend2();
442603
442650
  init_paths();
442604
442651
  init_error_formatter();
442605
442652
  init_memory_reminder();
442606
- init_memory_subagent_completion();
442653
+ init_reflection_launcher();
442607
442654
  init_reflection_transcript();
442608
442655
  init_constants2();
442609
442656
  init_diff_preview();
@@ -444389,13 +444436,6 @@ Location: ${keybindingsPath}`;
444389
444436
  return "Opening GitHub App installer...";
444390
444437
  }
444391
444438
  },
444392
- "/disconnect": {
444393
- desc: "Disconnect an existing account (/disconnect codex|claude|zai)",
444394
- order: 41,
444395
- handler: () => {
444396
- return "Disconnecting...";
444397
- }
444398
- },
444399
444439
  "/bg": {
444400
444440
  desc: "Show background shell processes",
444401
444441
  order: 42,
@@ -463593,6 +463633,18 @@ function getModelCategories(_billingTier, isSelfHosted, localModelCatalog, recen
463593
463633
  return base3;
463594
463634
  }
463595
463635
  function toSelectorModelForHandle(handle2) {
463636
+ const registryHandle = normalizeModelHandleForRegistry(handle2) ?? handle2;
463637
+ const modelInfo = getModelInfo(registryHandle);
463638
+ if (modelInfo) {
463639
+ return {
463640
+ id: handle2,
463641
+ handle: handle2,
463642
+ registryHandle,
463643
+ label: modelInfo.label,
463644
+ description: modelInfo.description ?? "",
463645
+ updateArgs: modelInfo.updateArgs
463646
+ };
463647
+ }
463596
463648
  return {
463597
463649
  id: handle2,
463598
463650
  handle: handle2,
@@ -463614,6 +463666,7 @@ function filterModelsByAvailabilityForSelector(typedModels, availableHandles, al
463614
463666
  function ModelSelector({
463615
463667
  currentModelId,
463616
463668
  currentModelHandle,
463669
+ currentModelServiceTier,
463617
463670
  onSelect,
463618
463671
  onOpenConnect,
463619
463672
  onOpenLogin,
@@ -463717,9 +463770,42 @@ function ModelSelector({
463717
463770
  })();
463718
463771
  }, [localModelCatalog]);
463719
463772
  const pickPreferredStaticModel = import_react93.useCallback((handle2, contextWindow) => {
463720
- const staticCandidates = typedModels.filter((m4) => m4.handle === handle2 && (contextWindow === undefined || m4.updateArgs?.context_window === contextWindow));
463773
+ const registryHandle = normalizeModelHandleForRegistry(handle2) ?? handle2;
463774
+ const staticCandidates = typedModels.filter((m4) => m4.handle === registryHandle && (contextWindow === undefined || m4.updateArgs?.context_window === contextWindow));
463721
463775
  return staticCandidates.find((m4) => m4.isDefault) ?? staticCandidates.find((m4) => m4.isFeatured) ?? staticCandidates.find((m4) => m4.updateArgs?.reasoning_effort === "medium") ?? staticCandidates.find((m4) => m4.updateArgs?.reasoning_effort === "high") ?? staticCandidates[0];
463722
463776
  }, [typedModels]);
463777
+ const serviceTierForModel = import_react93.useCallback((model) => {
463778
+ const value = model.updateArgs?.service_tier;
463779
+ return value === CHATGPT_FAST_SERVICE_TIER ? CHATGPT_FAST_SERVICE_TIER : null;
463780
+ }, []);
463781
+ const withActualHandle = import_react93.useCallback((model, handle2, registryHandle, updateArgs) => ({
463782
+ ...model,
463783
+ id: updateArgs?.service_tier === CHATGPT_FAST_SERVICE_TIER ? `${handle2}::service_tier=${CHATGPT_FAST_SERVICE_TIER}` : handle2,
463784
+ handle: handle2,
463785
+ registryHandle: registryHandle ?? model.registryHandle ?? model.handle,
463786
+ updateArgs: updateArgs ?? model.updateArgs
463787
+ }), []);
463788
+ const modelsForBackendHandle = import_react93.useCallback((handle2, includeUnknown) => {
463789
+ const registryHandle = normalizeModelHandleForRegistry(handle2) ?? handle2;
463790
+ const baseStaticModel = pickPreferredStaticModel(registryHandle);
463791
+ const fastRegistryHandle = getChatGptFastRegistryHandleForModelHandle(handle2);
463792
+ const baseUpdateArgs = {
463793
+ ...baseStaticModel?.updateArgs ?? {},
463794
+ ...fastRegistryHandle ? { service_tier: null } : {}
463795
+ };
463796
+ const baseModel = baseStaticModel ? withActualHandle(baseStaticModel, handle2, registryHandle, Object.keys(baseUpdateArgs).length > 0 ? baseUpdateArgs : undefined) : includeUnknown ? toSelectorModelForHandle(handle2) : null;
463797
+ const result = baseModel ? [baseModel] : [];
463798
+ if (fastRegistryHandle) {
463799
+ const fastStaticModel = pickPreferredStaticModel(fastRegistryHandle);
463800
+ if (fastStaticModel) {
463801
+ result.push(withActualHandle(fastStaticModel, handle2, fastRegistryHandle, {
463802
+ ...fastStaticModel.updateArgs ?? {},
463803
+ service_tier: CHATGPT_FAST_SERVICE_TIER
463804
+ }));
463805
+ }
463806
+ }
463807
+ return result;
463808
+ }, [pickPreferredStaticModel, withActualHandle]);
463723
463809
  const supportedModels = import_react93.useMemo(() => {
463724
463810
  if (availableHandles === undefined)
463725
463811
  return [];
@@ -463735,7 +463821,7 @@ function ModelSelector({
463735
463821
  const deduped = [];
463736
463822
  for (const m4 of available) {
463737
463823
  const contextWindow = m4.updateArgs?.context_window;
463738
- const key2 = `${m4.handle}:${contextWindow ?? 0}`;
463824
+ const key2 = `${m4.handle}:${contextWindow ?? 0}:${serviceTierForModel(m4) ?? "default"}`;
463739
463825
  if (seen.has(key2))
463740
463826
  continue;
463741
463827
  seen.add(key2);
@@ -463750,7 +463836,8 @@ function ModelSelector({
463750
463836
  allApiHandles,
463751
463837
  filterProvider,
463752
463838
  searchQuery,
463753
- pickPreferredStaticModel
463839
+ pickPreferredStaticModel,
463840
+ serviceTierForModel
463754
463841
  ]);
463755
463842
  const isByokHandle = import_react93.useCallback((handle2) => isByokHandleForSelector(handle2, byokProviderAliases), [byokProviderAliases]);
463756
463843
  const allLettaModels = import_react93.useMemo(() => {
@@ -463839,39 +463926,51 @@ function ModelSelector({
463839
463926
  const serverRecommendedModels = import_react93.useMemo(() => {
463840
463927
  if (!backendModelCatalog || availableHandles === undefined)
463841
463928
  return [];
463842
- let available = typedModels.filter((m4) => availableHandles?.has(m4.handle) && m4.handle !== "letta/letta-free");
463929
+ let available = allApiHandles.filter((handle2) => handle2 !== "letta/letta-free").flatMap((handle2) => modelsForBackendHandle(handle2, false));
463843
463930
  if (searchQuery) {
463844
463931
  const query2 = searchQuery.toLowerCase();
463845
- available = available.filter((m4) => m4.label.toLowerCase().includes(query2) || m4.description.toLowerCase().includes(query2) || m4.handle.toLowerCase().includes(query2));
463932
+ available = available.filter((m4) => m4.label.toLowerCase().includes(query2) || m4.description.toLowerCase().includes(query2) || m4.registryHandle?.toLowerCase().includes(query2) || m4.handle.toLowerCase().includes(query2));
463846
463933
  }
463847
463934
  const seen = new Set;
463848
463935
  const deduped = [];
463849
463936
  for (const m4 of available) {
463850
463937
  const contextWindow = m4.updateArgs?.context_window;
463851
- const key2 = `${m4.handle}:${contextWindow ?? 0}`;
463938
+ const key2 = `${m4.handle}:${contextWindow ?? 0}:${serviceTierForModel(m4) ?? "default"}`;
463852
463939
  if (seen.has(key2))
463853
463940
  continue;
463854
463941
  seen.add(key2);
463855
- deduped.push(pickPreferredStaticModel(m4.handle, contextWindow) ?? m4);
463942
+ deduped.push(m4);
463856
463943
  }
463857
463944
  return deduped;
463858
463945
  }, [
463859
463946
  backendModelCatalog,
463860
- typedModels,
463861
463947
  availableHandles,
463948
+ allApiHandles,
463862
463949
  searchQuery,
463863
- pickPreferredStaticModel
463950
+ modelsForBackendHandle,
463951
+ serviceTierForModel
463864
463952
  ]);
463865
463953
  const serverAllModels = import_react93.useMemo(() => {
463866
463954
  if (!backendModelCatalog)
463867
463955
  return [];
463868
- let handles = allApiHandles.filter((h3) => h3 !== "letta/letta-free");
463956
+ const handles = allApiHandles.filter((h3) => h3 !== "letta/letta-free");
463957
+ return handles;
463958
+ }, [backendModelCatalog, allApiHandles]);
463959
+ const serverAllModelRows = import_react93.useMemo(() => {
463960
+ if (!backendModelCatalog)
463961
+ return [];
463962
+ let rows = serverAllModels.flatMap((handle2) => modelsForBackendHandle(handle2, true));
463869
463963
  if (searchQuery) {
463870
463964
  const query2 = searchQuery.toLowerCase();
463871
- handles = handles.filter((h3) => h3.toLowerCase().includes(query2));
463965
+ rows = rows.filter((model) => model.label.toLowerCase().includes(query2) || model.description.toLowerCase().includes(query2) || model.registryHandle?.toLowerCase().includes(query2) || model.handle.toLowerCase().includes(query2));
463872
463966
  }
463873
- return handles;
463874
- }, [backendModelCatalog, allApiHandles, searchQuery]);
463967
+ return rows;
463968
+ }, [
463969
+ backendModelCatalog,
463970
+ serverAllModels,
463971
+ modelsForBackendHandle,
463972
+ searchQuery
463973
+ ]);
463875
463974
  const recentModels = import_react93.useMemo(() => {
463876
463975
  if (availableHandles === undefined)
463877
463976
  return [];
@@ -463906,7 +464005,7 @@ function ModelSelector({
463906
464005
  description: ""
463907
464006
  })),
463908
464007
  "server-recommended": serverRecommendedModels,
463909
- "server-all": serverAllModels.map(toSelectorModelForHandle),
464008
+ "server-all": serverAllModelRows,
463910
464009
  all: allLettaModels
463911
464010
  }), [
463912
464011
  recentModels,
@@ -463915,7 +464014,7 @@ function ModelSelector({
463915
464014
  byokAllModels,
463916
464015
  allLettaModels,
463917
464016
  serverRecommendedModels,
463918
- serverAllModels
464017
+ serverAllModelRows
463919
464018
  ]);
463920
464019
  const nonEmptyCategories = import_react93.useMemo(() => modelCategories.filter((cat) => {
463921
464020
  const list = categoryListMap[cat];
@@ -464049,7 +464148,14 @@ function ModelSelector({
464049
464148
  } else if (key2.return) {
464050
464149
  const selectedModel = currentList[selectedIndex];
464051
464150
  if (selectedModel) {
464052
- onSelect(selectedModel.id);
464151
+ onSelect({
464152
+ id: selectedModel.id,
464153
+ handle: selectedModel.handle,
464154
+ label: selectedModel.label,
464155
+ description: selectedModel.description,
464156
+ registryHandle: selectedModel.registryHandle,
464157
+ updateArgs: selectedModel.updateArgs
464158
+ });
464053
464159
  }
464054
464160
  }
464055
464161
  }, { isActive: true });
@@ -464065,7 +464171,7 @@ function ModelSelector({
464065
464171
  if (cat === "server-recommended")
464066
464172
  return `Recommended [${serverRecommendedModels.length}]`;
464067
464173
  if (cat === "server-all")
464068
- return `All models [${serverAllModels.length}]`;
464174
+ return `All models [${serverAllModelRows.length}]`;
464069
464175
  return `Letta API (all) [${allLettaModels.length}]`;
464070
464176
  };
464071
464177
  const getCategoryDescription = (cat) => {
@@ -464235,7 +464341,9 @@ function ModelSelector({
464235
464341
  visibleModels.map((model, index) => {
464236
464342
  const actualIndex = startIndex + index;
464237
464343
  const isSelected = actualIndex === selectedIndex;
464238
- const isCurrent = model.id === currentModelId || model.handle === currentModelHandle;
464344
+ const modelServiceTier = serviceTierForModel(model);
464345
+ const currentServiceTier = currentModelServiceTier === CHATGPT_FAST_SERVICE_TIER ? CHATGPT_FAST_SERVICE_TIER : null;
464346
+ const isCurrent = (model.id === currentModelId || model.handle === currentModelHandle) && modelServiceTier === currentServiceTier;
464239
464347
  const showLock = isFreeTier && !model.free && (category === "supported" || category === "all");
464240
464348
  return /* @__PURE__ */ jsx_dev_runtime68.jsxDEV(Box_default, {
464241
464349
  flexDirection: "row",
@@ -464492,6 +464600,20 @@ function filterProviderConfigs(providers, query2) {
464492
464600
  return searchable.includes(normalized);
464493
464601
  });
464494
464602
  }
464603
+ function providerSelectionFlow(provider, connectedProviderId) {
464604
+ if (connectedProviderId)
464605
+ return "options";
464606
+ if (provider.isOAuth)
464607
+ return "oauth";
464608
+ if ("authMethods" in provider && provider.authMethods)
464609
+ return "methodSelect";
464610
+ if ("fields" in provider && provider.fields)
464611
+ return "multiInput";
464612
+ return "input";
464613
+ }
464614
+ function isProviderTargetLoading(input) {
464615
+ return input.connectedProvidersByTarget[input.selectedTarget] === undefined && (input.selectedTarget === "local" || input.showProviderStoreTabs);
464616
+ }
464495
464617
  function ProviderSelector({
464496
464618
  onCancel,
464497
464619
  onStartOAuth
@@ -464501,8 +464623,8 @@ function ProviderSelector({
464501
464623
  const [selectedTarget, setSelectedTarget] = import_react96.useState(defaultProviderStorageTarget());
464502
464624
  const [hasConstellationCredentials, setHasConstellationCredentials] = import_react96.useState(null);
464503
464625
  const [selectedIndex, setSelectedIndex] = import_react96.useState(0);
464504
- const [connectedProviders, setConnectedProviders] = import_react96.useState(new Map);
464505
- const [isLoading, setIsLoading] = import_react96.useState(true);
464626
+ const [connectedProvidersByTarget, setConnectedProvidersByTarget] = import_react96.useState({});
464627
+ const [loadingTargets, setLoadingTargets] = import_react96.useState(new Set);
464506
464628
  const [viewState, setViewState] = import_react96.useState({ type: "list" });
464507
464629
  const [searchQuery, setSearchQuery] = import_react96.useState("");
464508
464630
  const [apiKeyInput, setApiKeyInput] = import_react96.useState("");
@@ -464518,6 +464640,12 @@ function ProviderSelector({
464518
464640
  const providers = import_react96.useMemo(() => getProviderConfigs(selectedTarget), [selectedTarget]);
464519
464641
  const filteredProviders = import_react96.useMemo(() => filterProviderConfigs(providers, searchQuery), [providers, searchQuery]);
464520
464642
  const showProviderStoreTabs = shouldShowProviderStoreTabs(hasConstellationCredentials);
464643
+ const connectedProviders = import_react96.useMemo(() => connectedProvidersByTarget[selectedTarget] ?? new Map, [connectedProvidersByTarget, selectedTarget]);
464644
+ const isLoading = isProviderTargetLoading({
464645
+ selectedTarget,
464646
+ connectedProvidersByTarget,
464647
+ showProviderStoreTabs
464648
+ });
464521
464649
  const selectableProviders = filteredProviders;
464522
464650
  const providerStartIndex = import_react96.useMemo(() => {
464523
464651
  if (selectedIndex < VISIBLE_PROVIDERS)
@@ -464548,28 +464676,67 @@ function ProviderSelector({
464548
464676
  cancelled = true;
464549
464677
  };
464550
464678
  }, []);
464679
+ const setConnectedProvidersForTarget = import_react96.useCallback((target2, providers2) => {
464680
+ setConnectedProvidersByTarget((previous) => ({
464681
+ ...previous,
464682
+ [target2]: providers2
464683
+ }));
464684
+ }, []);
464685
+ const refreshConnectedProviders = import_react96.useCallback(async (target2) => {
464686
+ setLoadingTargets((previous) => new Set(previous).add(target2));
464687
+ try {
464688
+ const providers2 = await getConnectedProviders({ target: target2 });
464689
+ if (mountedRef.current) {
464690
+ setConnectedProvidersForTarget(target2, providers2);
464691
+ }
464692
+ } catch {
464693
+ if (mountedRef.current) {
464694
+ setConnectedProvidersForTarget(target2, new Map);
464695
+ }
464696
+ } finally {
464697
+ if (mountedRef.current) {
464698
+ setLoadingTargets((previous) => {
464699
+ const next = new Set(previous);
464700
+ next.delete(target2);
464701
+ return next;
464702
+ });
464703
+ }
464704
+ }
464705
+ }, [setConnectedProvidersForTarget]);
464551
464706
  import_react96.useEffect(() => {
464552
- if (selectedTarget === "api" && !showProviderStoreTabs) {
464553
- setIsLoading(false);
464707
+ if (selectedTarget === "api" && !showProviderStoreTabs)
464708
+ return;
464709
+ if (connectedProvidersByTarget[selectedTarget])
464710
+ return;
464711
+ if (loadingTargets.has(selectedTarget))
464712
+ return;
464713
+ refreshConnectedProviders(selectedTarget);
464714
+ }, [
464715
+ connectedProvidersByTarget,
464716
+ loadingTargets,
464717
+ refreshConnectedProviders,
464718
+ selectedTarget,
464719
+ showProviderStoreTabs
464720
+ ]);
464721
+ import_react96.useEffect(() => {
464722
+ if (!showProviderStoreTabs)
464554
464723
  return;
464724
+ for (const target2 of ["local", "api"]) {
464725
+ if (target2 === selectedTarget)
464726
+ continue;
464727
+ if (connectedProvidersByTarget[target2])
464728
+ continue;
464729
+ if (loadingTargets.has(target2))
464730
+ continue;
464731
+ refreshConnectedProviders(target2);
464555
464732
  }
464556
- setIsLoading(true);
464557
- (async () => {
464558
- try {
464559
- const providers2 = await getConnectedProviders({
464560
- target: selectedTarget
464561
- });
464562
- if (mountedRef.current) {
464563
- setConnectedProviders(providers2);
464564
- setIsLoading(false);
464565
- }
464566
- } catch {
464567
- if (mountedRef.current) {
464568
- setIsLoading(false);
464569
- }
464570
- }
464571
- })();
464572
- }, [selectedTarget, showProviderStoreTabs]);
464733
+ }, [
464734
+ connectedProvidersByTarget,
464735
+ loadingTargets,
464736
+ refreshConnectedProviders,
464737
+ selectedTarget,
464738
+ showProviderStoreTabs
464739
+ ]);
464573
464740
  import_react96.useEffect(() => {
464574
464741
  if (!showProviderStoreTabs && selectedTarget !== "local") {
464575
464742
  setSelectedTarget("local");
@@ -464627,23 +464794,23 @@ function ProviderSelector({
464627
464794
  return providerName ? connectedProviders.get(providerName)?.id : undefined;
464628
464795
  }, [connectedProviders, getConnectedProviderName]);
464629
464796
  const handleSelectProvider = import_react96.useCallback((provider) => {
464630
- if ("isOAuth" in provider && provider.isOAuth) {
464797
+ const providerId2 = getProviderId(provider);
464798
+ const flow = providerSelectionFlow(provider, providerId2);
464799
+ if (flow === "options") {
464800
+ setViewState({ type: "options", provider });
464801
+ setOptionIndex(0);
464802
+ return;
464803
+ }
464804
+ if (flow === "oauth") {
464631
464805
  if (onStartOAuth) {
464632
464806
  onStartOAuth(provider, selectedTarget);
464633
464807
  }
464634
464808
  return;
464635
464809
  }
464636
- const connected = isConnected(provider);
464637
- if (connected) {
464638
- const providerId2 = getProviderId(provider);
464639
- if (providerId2) {
464640
- setViewState({ type: "options", provider, providerId: providerId2 });
464641
- setOptionIndex(0);
464642
- }
464643
- } else if ("authMethods" in provider && provider.authMethods) {
464810
+ if (flow === "methodSelect") {
464644
464811
  setViewState({ type: "methodSelect", provider });
464645
464812
  setMethodIndex(0);
464646
- } else if ("fields" in provider && provider.fields) {
464813
+ } else if (flow === "multiInput") {
464647
464814
  setViewState({ type: "multiInput", provider });
464648
464815
  setFieldValues({});
464649
464816
  setFocusedFieldIndex(0);
@@ -464655,7 +464822,7 @@ function ProviderSelector({
464655
464822
  setValidationState("idle");
464656
464823
  setValidationError(null);
464657
464824
  }
464658
- }, [isConnected, getProviderId, onStartOAuth, selectedTarget]);
464825
+ }, [getProviderId, onStartOAuth, selectedTarget]);
464659
464826
  const handleSelectAuthMethod = import_react96.useCallback(async (provider, authMethod) => {
464660
464827
  if (authMethod.id === "profile") {
464661
464828
  setIsLoadingProfiles(true);
@@ -464711,7 +464878,7 @@ function ProviderSelector({
464711
464878
  target: selectedTarget
464712
464879
  });
464713
464880
  if (mountedRef.current) {
464714
- setConnectedProviders(providers2);
464881
+ setConnectedProvidersForTarget(selectedTarget, providers2);
464715
464882
  setViewState({ type: "list" });
464716
464883
  setApiKeyInput("");
464717
464884
  setValidationState("idle");
@@ -464737,7 +464904,13 @@ function ProviderSelector({
464737
464904
  setValidationError(err instanceof Error ? err.message : "Invalid API key");
464738
464905
  }
464739
464906
  }
464740
- }, [viewState, apiKeyInput, validationState, selectedTarget]);
464907
+ }, [
464908
+ viewState,
464909
+ apiKeyInput,
464910
+ validationState,
464911
+ selectedTarget,
464912
+ setConnectedProvidersForTarget
464913
+ ]);
464741
464914
  const handleMultiFieldValidateAndSave = import_react96.useCallback(async () => {
464742
464915
  if (viewState.type !== "multiInput")
464743
464916
  return;
@@ -464762,7 +464935,7 @@ function ProviderSelector({
464762
464935
  target: selectedTarget
464763
464936
  });
464764
464937
  if (mountedRef.current) {
464765
- setConnectedProviders(providers2);
464938
+ setConnectedProvidersForTarget(selectedTarget, providers2);
464766
464939
  setViewState({ type: "list" });
464767
464940
  setFieldValues({});
464768
464941
  setValidationState("idle");
@@ -464788,7 +464961,13 @@ function ProviderSelector({
464788
464961
  setValidationError(err instanceof Error ? err.message : "Invalid credentials");
464789
464962
  }
464790
464963
  }
464791
- }, [viewState, fieldValues, validationState, selectedTarget]);
464964
+ }, [
464965
+ viewState,
464966
+ fieldValues,
464967
+ validationState,
464968
+ selectedTarget,
464969
+ setConnectedProvidersForTarget
464970
+ ]);
464792
464971
  const handleDisconnect = import_react96.useCallback(async () => {
464793
464972
  if (viewState.type !== "options")
464794
464973
  return;
@@ -464797,13 +464976,19 @@ function ProviderSelector({
464797
464976
  await removeProviderByName2(getConnectedProviderName(provider) ?? provider.providerName, {
464798
464977
  target: selectedTarget
464799
464978
  });
464979
+ clearAvailableModelsCache();
464800
464980
  const providers2 = await getConnectedProviders({ target: selectedTarget });
464801
464981
  if (mountedRef.current) {
464802
- setConnectedProviders(providers2);
464982
+ setConnectedProvidersForTarget(selectedTarget, providers2);
464803
464983
  setViewState({ type: "list" });
464804
464984
  }
464805
464985
  } catch {}
464806
- }, [viewState, selectedTarget, getConnectedProviderName]);
464986
+ }, [
464987
+ viewState,
464988
+ selectedTarget,
464989
+ getConnectedProviderName,
464990
+ setConnectedProvidersForTarget
464991
+ ]);
464807
464992
  use_input_default((input, key2) => {
464808
464993
  if (key2.ctrl && input === "c") {
464809
464994
  onCancel();
@@ -465440,40 +465625,53 @@ function ProviderSelector({
465440
465625
  if (viewState.type !== "options")
465441
465626
  return null;
465442
465627
  const { provider } = viewState;
465443
- const options3 = ["Disconnect", "Back"];
465628
+ const options3 = ["Disconnect provider", "Back"];
465444
465629
  return /* @__PURE__ */ jsx_dev_runtime71.jsxDEV(jsx_dev_runtime71.Fragment, {
465445
465630
  children: [
465446
465631
  /* @__PURE__ */ jsx_dev_runtime71.jsxDEV(Box_default, {
465447
465632
  flexDirection: "column",
465448
465633
  marginBottom: 1,
465449
- children: /* @__PURE__ */ jsx_dev_runtime71.jsxDEV(Box_default, {
465450
- flexDirection: "row",
465451
- children: [
465452
- /* @__PURE__ */ jsx_dev_runtime71.jsxDEV(Text2, {
465453
- children: " "
465454
- }, undefined, false, undefined, this),
465455
- /* @__PURE__ */ jsx_dev_runtime71.jsxDEV(Text2, {
465456
- color: "green",
465457
- children: "[✓]"
465458
- }, undefined, false, undefined, this),
465459
- /* @__PURE__ */ jsx_dev_runtime71.jsxDEV(Text2, {
465460
- children: " "
465461
- }, undefined, false, undefined, this),
465462
- /* @__PURE__ */ jsx_dev_runtime71.jsxDEV(Text2, {
465463
- bold: true,
465464
- children: provider.displayName
465465
- }, undefined, false, undefined, this),
465466
- /* @__PURE__ */ jsx_dev_runtime71.jsxDEV(Text2, {
465467
- dimColor: true,
465468
- children: " · "
465469
- }, undefined, false, undefined, this),
465470
- /* @__PURE__ */ jsx_dev_runtime71.jsxDEV(Text2, {
465471
- color: "green",
465472
- children: "Connected"
465473
- }, undefined, false, undefined, this)
465474
- ]
465475
- }, undefined, true, undefined, this)
465476
- }, undefined, false, undefined, this),
465634
+ children: [
465635
+ /* @__PURE__ */ jsx_dev_runtime71.jsxDEV(Text2, {
465636
+ bold: true,
465637
+ color: colors.selector.title,
465638
+ children: [
465639
+ "Disconnect ",
465640
+ provider.displayName
465641
+ ]
465642
+ }, undefined, true, undefined, this),
465643
+ /* @__PURE__ */ jsx_dev_runtime71.jsxDEV(Box_default, {
465644
+ height: 1
465645
+ }, undefined, false, undefined, this),
465646
+ /* @__PURE__ */ jsx_dev_runtime71.jsxDEV(Box_default, {
465647
+ flexDirection: "row",
465648
+ children: [
465649
+ /* @__PURE__ */ jsx_dev_runtime71.jsxDEV(Text2, {
465650
+ children: " "
465651
+ }, undefined, false, undefined, this),
465652
+ /* @__PURE__ */ jsx_dev_runtime71.jsxDEV(Text2, {
465653
+ color: "green",
465654
+ children: "[✓]"
465655
+ }, undefined, false, undefined, this),
465656
+ /* @__PURE__ */ jsx_dev_runtime71.jsxDEV(Text2, {
465657
+ children: " "
465658
+ }, undefined, false, undefined, this),
465659
+ /* @__PURE__ */ jsx_dev_runtime71.jsxDEV(Text2, {
465660
+ bold: true,
465661
+ children: provider.displayName
465662
+ }, undefined, false, undefined, this),
465663
+ /* @__PURE__ */ jsx_dev_runtime71.jsxDEV(Text2, {
465664
+ dimColor: true,
465665
+ children: " · "
465666
+ }, undefined, false, undefined, this),
465667
+ /* @__PURE__ */ jsx_dev_runtime71.jsxDEV(Text2, {
465668
+ color: "green",
465669
+ children: "Connected"
465670
+ }, undefined, false, undefined, this)
465671
+ ]
465672
+ }, undefined, true, undefined, this)
465673
+ ]
465674
+ }, undefined, true, undefined, this),
465477
465675
  /* @__PURE__ */ jsx_dev_runtime71.jsxDEV(Box_default, {
465478
465676
  flexDirection: "column",
465479
465677
  children: options3.map((option2, index) => {
@@ -465500,7 +465698,7 @@ function ProviderSelector({
465500
465698
  dimColor: true,
465501
465699
  children: [
465502
465700
  " ",
465503
- "Enter select · ↑↓ navigate · Esc back"
465701
+ "Enter confirm · ↑↓ navigate · Esc back"
465504
465702
  ]
465505
465703
  }, undefined, true, undefined, this)
465506
465704
  }, undefined, false, undefined, this)
@@ -470190,7 +470388,6 @@ var init_StaticTranscript = __esm(async () => {
470190
470388
  var exports_connect = {};
470191
470389
  __export(exports_connect, {
470192
470390
  setActiveCommandId: () => setActiveCommandId,
470193
- handleDisconnect: () => handleDisconnect,
470194
470391
  handleConnect: () => handleConnect
470195
470392
  });
470196
470393
  function uid2(prefix) {
@@ -470435,7 +470632,7 @@ async function handleConnectChatGPT(ctx, msg) {
470435
470632
  if (existingProvider) {
470436
470633
  addCommandResult(ctx.buffersRef, ctx.refreshDerived, msg, `Already connected to ChatGPT via OAuth.
470437
470634
 
470438
- Use /disconnect chatgpt (or /disconnect codex) to remove the current connection first.`, false);
470635
+ Open /connect and select ChatGPT / Codex plan in the current tab to disconnect or re-authenticate.`, false);
470439
470636
  return;
470440
470637
  }
470441
470638
  ctx.setCommandRunning(true);
@@ -470468,7 +470665,9 @@ Use /disconnect chatgpt (or /disconnect codex) to remove the current connection
470468
470665
  async function handleConnectLocalOAuthProvider(ctx, msg, provider) {
470469
470666
  const existingProvider = await getProviderByName2(provider.byokProvider.providerName, { target: "local" });
470470
470667
  if (existingProvider?.auth_type === "oauth") {
470471
- addCommandResult(ctx.buffersRef, ctx.refreshDerived, msg, `Already connected to ${provider.byokProvider.displayName}. Disconnect first if you want to re-authenticate.`, false);
470668
+ addCommandResult(ctx.buffersRef, ctx.refreshDerived, msg, `Already connected to ${provider.byokProvider.displayName}.
470669
+
470670
+ Open /connect and select it in the Local tab to disconnect or re-authenticate.`, false);
470472
470671
  return;
470473
470672
  }
470474
470673
  ctx.setCommandRunning(true);
@@ -470603,126 +470802,6 @@ ${formatApiKeyUsage(provider)}`, false);
470603
470802
  });
470604
470803
  }
470605
470804
  }
470606
- function formatDisconnectHelp() {
470607
- return [
470608
- "/disconnect help",
470609
- "",
470610
- "Disconnect an existing account.",
470611
- "",
470612
- "USAGE",
470613
- " /disconnect <provider> — disconnect a provider",
470614
- " /disconnect help — show this help",
470615
- "",
470616
- "PROVIDERS",
470617
- ` ${listConnectProvidersForHelp().join(", ")}, claude (legacy)`
470618
- ].join(`
470619
- `);
470620
- }
470621
- async function handleDisconnectChatGPT(ctx, msg) {
470622
- const existingProvider = await getOpenAICodexProvider({
470623
- target: ctx.target
470624
- });
470625
- if (!existingProvider) {
470626
- addCommandResult(ctx.buffersRef, ctx.refreshDerived, msg, `Not currently connected to ChatGPT via OAuth.
470627
-
470628
- Use /connect chatgpt (or /connect codex) to authenticate.`, false);
470629
- return;
470630
- }
470631
- const cmdId = addCommandResult(ctx.buffersRef, ctx.refreshDerived, msg, "Disconnecting from ChatGPT OAuth...", true, "running");
470632
- ctx.setCommandRunning(true);
470633
- try {
470634
- await removeOpenAICodexProvider({ target: ctx.target });
470635
- updateCommandResult(ctx.buffersRef, ctx.refreshDerived, cmdId, msg, `✓ Disconnected from ChatGPT OAuth.
470636
-
470637
- ` + `Provider '${OPENAI_CODEX_PROVIDER_NAME}' removed from ${providerStorageTargetLabel(ctx.target)}.`, true, "finished");
470638
- } catch (error54) {
470639
- updateCommandResult(ctx.buffersRef, ctx.refreshDerived, cmdId, msg, `✗ Failed to disconnect from ChatGPT: ${getErrorMessage2(error54)}`, false, "finished");
470640
- } finally {
470641
- ctx.setCommandRunning(false);
470642
- }
470643
- }
470644
- async function handleDisconnectByokProvider(ctx, msg, provider) {
470645
- const existing = await getProviderByName2(provider.byokProvider.providerName, {
470646
- target: provider.target
470647
- });
470648
- const authMatches = provider.target !== "local" || !existing?.auth_type ? true : provider.byokProvider.isOAuth ? existing.auth_type === "oauth" : existing.auth_type !== "oauth";
470649
- if (!existing || !authMatches) {
470650
- addCommandResult(ctx.buffersRef, ctx.refreshDerived, msg, `Not currently connected to ${provider.byokProvider.displayName}.
470651
-
470652
- Use /connect ${provider.canonical} to connect.`, false);
470653
- return;
470654
- }
470655
- const cmdId = addCommandResult(ctx.buffersRef, ctx.refreshDerived, msg, `Disconnecting from ${provider.byokProvider.displayName}...`, true, "running");
470656
- ctx.setCommandRunning(true);
470657
- try {
470658
- await removeProviderByName2(provider.byokProvider.providerName, {
470659
- target: provider.target
470660
- });
470661
- updateCommandResult(ctx.buffersRef, ctx.refreshDerived, cmdId, msg, `✓ Disconnected from ${provider.byokProvider.displayName}.
470662
-
470663
- ` + `Provider '${provider.byokProvider.providerName}' removed from ${providerStorageTargetLabel(provider.target)}.`, true, "finished");
470664
- } catch (error54) {
470665
- updateCommandResult(ctx.buffersRef, ctx.refreshDerived, cmdId, msg, `✗ Failed to disconnect from ${provider.byokProvider.displayName}: ${getErrorMessage2(error54)}`, false, "finished");
470666
- } finally {
470667
- ctx.setCommandRunning(false);
470668
- }
470669
- }
470670
- async function handleDisconnectClaude(ctx, msg) {
470671
- const CLAUDE_PROVIDER_NAME = "claude-pro-max";
470672
- const cmdId = addCommandResult(ctx.buffersRef, ctx.refreshDerived, msg, "Checking for Claude provider...", true, "running");
470673
- ctx.setCommandRunning(true);
470674
- try {
470675
- const providers = await listProviders2({ target: ctx.target });
470676
- const claudeProvider = providers.find((provider) => provider.name === CLAUDE_PROVIDER_NAME);
470677
- if (!claudeProvider) {
470678
- updateCommandResult(ctx.buffersRef, ctx.refreshDerived, cmdId, msg, `No Claude provider found.
470679
-
470680
- The '${CLAUDE_PROVIDER_NAME}' provider does not exist in your Letta account.`, false, "finished");
470681
- return;
470682
- }
470683
- updateCommandResult(ctx.buffersRef, ctx.refreshDerived, cmdId, msg, "Removing Claude provider...", true, "running");
470684
- await deleteOpenAICodexProvider(claudeProvider.id, { target: ctx.target });
470685
- updateCommandResult(ctx.buffersRef, ctx.refreshDerived, cmdId, msg, `✓ Disconnected from Claude.
470686
-
470687
- ` + `Provider '${CLAUDE_PROVIDER_NAME}' has been removed from Letta.
470688
-
470689
- ` + "Note: /connect claude has been replaced by /connect chatgpt (alias: /connect codex).", true, "finished");
470690
- } catch (error54) {
470691
- updateCommandResult(ctx.buffersRef, ctx.refreshDerived, cmdId, msg, `✗ Failed to disconnect from Claude: ${getErrorMessage2(error54)}`, false, "finished");
470692
- } finally {
470693
- ctx.setCommandRunning(false);
470694
- }
470695
- }
470696
- async function handleDisconnect(ctx, msg) {
470697
- const parts = parseArgs11(msg);
470698
- const providerToken = parts[1]?.toLowerCase();
470699
- if (providerToken === "help") {
470700
- addCommandResult(ctx.buffersRef, ctx.refreshDerived, msg, formatDisconnectHelp(), true);
470701
- return;
470702
- }
470703
- if (!providerToken) {
470704
- addCommandResult(ctx.buffersRef, ctx.refreshDerived, msg, "Usage: /disconnect <provider>", false);
470705
- return;
470706
- }
470707
- if (providerToken === "claude") {
470708
- await handleDisconnectClaude(ctx, msg);
470709
- return;
470710
- }
470711
- const provider = resolveConnectProvider(providerToken, ctx.target);
470712
- if (!provider) {
470713
- addCommandResult(ctx.buffersRef, ctx.refreshDerived, msg, `Unknown provider: "${providerToken}". Run /disconnect help for usage.`, false);
470714
- return;
470715
- }
470716
- if (isConnectOAuthProvider(provider)) {
470717
- if (provider.target === "local") {
470718
- await handleDisconnectByokProvider(ctx, msg, provider);
470719
- } else {
470720
- await handleDisconnectChatGPT(ctx, msg);
470721
- }
470722
- return;
470723
- }
470724
- await handleDisconnectByokProvider(ctx, msg, provider);
470725
- }
470726
470805
  var activeCommandId = null;
470727
470806
  var init_connect = __esm(() => {
470728
470807
  init_local_provider_timeout();
@@ -485351,6 +485430,7 @@ function AppView(props) {
485351
485430
  currentModelDisplay,
485352
485431
  currentModelHandle,
485353
485432
  currentModelId,
485433
+ currentModelServiceTier,
485354
485434
  currentModelProvider,
485355
485435
  isLocalBackend,
485356
485436
  currentPersonalityId,
@@ -485652,7 +485732,7 @@ function AppView(props) {
485652
485732
  initialEffort: modelReasoningPrompt.initialEffort,
485653
485733
  onSelect: (selectedOption) => {
485654
485734
  setModelReasoningPrompt(null);
485655
- handleModelSelect(selectedOption.modelId, null, {
485735
+ handleModelSelect(selectedOption.selection ?? selectedOption.modelId, null, {
485656
485736
  skipReasoningPrompt: true,
485657
485737
  reasoningEffort: selectedOption.effort
485658
485738
  });
@@ -485661,8 +485741,9 @@ function AppView(props) {
485661
485741
  }, undefined, false, undefined, this) : /* @__PURE__ */ jsx_dev_runtime94.jsxDEV(ModelSelector, {
485662
485742
  currentModelId: currentModelId ?? undefined,
485663
485743
  currentModelHandle,
485664
- onSelect: (modelId) => {
485665
- handleModelSelect(modelId, null, {
485744
+ currentModelServiceTier,
485745
+ onSelect: (selection) => {
485746
+ handleModelSelect(selection, null, {
485666
485747
  promptReasoning: true
485667
485748
  });
485668
485749
  },
@@ -486338,7 +486419,7 @@ var init_AppView = __esm(async () => {
486338
486419
  });
486339
486420
 
486340
486421
  // src/cli/app/constants.ts
486341
- var CLEAR_SCREEN_AND_HOME = "\x1B[2J\x1B[H", MIN_RESIZE_DELTA = 2, RESIZE_SETTLE_MS = 250, MIN_CLEAR_INTERVAL_MS = 750, STABLE_WIDTH_SETTLE_MS = 180, TOOL_CALL_COMMIT_DEFER_MS = 50, ANIMATION_RESUME_HYSTERESIS_ROWS = 2, EAGER_CANCEL = true, LLM_API_ERROR_MAX_RETRIES3 = 3, EMPTY_RESPONSE_MAX_RETRIES3 = 2, TEMP_QUOTA_OVERRIDE_MODEL = "letta/auto", PROVIDER_FALLBACK_MAP3, CONVERSATION_BUSY_MAX_RETRIES2 = 3, INTERRUPT_MESSAGE = "Interrupted – tell the agent what to do differently. Something went wrong? Use /feedback to report issues.", ERROR_FEEDBACK_HINT = "Something went wrong? Use /feedback to report issues.", PROVIDER_STATUS_PAGES, APPROVAL_OPTIONS_HEIGHT = 8, APPROVAL_PREVIEW_BUFFER = 4, MIN_WRAP_WIDTH = 10, TEXT_WRAP_GUTTER = 6, DIFF_WRAP_GUTTER = 12, SHELL_PREVIEW_MAX_LINES = 3, AUTO_REFLECTION_DESCRIPTION3 = "Reflect on recent conversations";
486422
+ var CLEAR_SCREEN_AND_HOME = "\x1B[2J\x1B[H", MIN_RESIZE_DELTA = 2, RESIZE_SETTLE_MS = 250, MIN_CLEAR_INTERVAL_MS = 750, STABLE_WIDTH_SETTLE_MS = 180, TOOL_CALL_COMMIT_DEFER_MS = 50, ANIMATION_RESUME_HYSTERESIS_ROWS = 2, EAGER_CANCEL = true, LLM_API_ERROR_MAX_RETRIES3 = 3, EMPTY_RESPONSE_MAX_RETRIES3 = 2, TEMP_QUOTA_OVERRIDE_MODEL = "letta/auto", PROVIDER_FALLBACK_MAP3, CONVERSATION_BUSY_MAX_RETRIES2 = 3, INTERRUPT_MESSAGE = "Interrupted – tell the agent what to do differently. Something went wrong? Use /feedback to report issues.", ERROR_FEEDBACK_HINT = "Something went wrong? Use /feedback to report issues.", PROVIDER_STATUS_PAGES, APPROVAL_OPTIONS_HEIGHT = 8, APPROVAL_PREVIEW_BUFFER = 4, MIN_WRAP_WIDTH = 10, TEXT_WRAP_GUTTER = 6, DIFF_WRAP_GUTTER = 12, SHELL_PREVIEW_MAX_LINES = 3;
486342
486423
  var init_constants7 = __esm(() => {
486343
486424
  PROVIDER_FALLBACK_MAP3 = {
486344
486425
  "opus-4.7-low": "bedrock-opus-4.7",
@@ -486413,12 +486494,13 @@ function estimateAdvancedDiffLines(diff3, width) {
486413
486494
  // src/cli/app/model-config.ts
486414
486495
  function deriveReasoningEffort(modelSettings, llmConfig) {
486415
486496
  if (modelSettings && "provider_type" in modelSettings) {
486416
- if (modelSettings.provider_type === "openai" && "reasoning" in modelSettings && modelSettings.reasoning) {
486497
+ const providerType = modelSettings.provider_type;
486498
+ if ((providerType === "openai" || providerType === "openai-codex" || providerType === "chatgpt_oauth") && "reasoning" in modelSettings && modelSettings.reasoning) {
486417
486499
  const re4 = modelSettings.reasoning.reasoning_effort;
486418
486500
  if (re4 === "none" || re4 === "minimal" || re4 === "low" || re4 === "medium" || re4 === "high" || re4 === "xhigh")
486419
486501
  return re4;
486420
486502
  }
486421
- if (modelSettings.provider_type === "anthropic" || modelSettings.provider_type === "bedrock") {
486503
+ if (providerType === "anthropic" || providerType === "bedrock") {
486422
486504
  const effort = modelSettings.effort;
486423
486505
  if (effort === "low" || effort === "medium" || effort === "high")
486424
486506
  return effort;
@@ -486465,7 +486547,7 @@ function mapHandleToLlmConfigPatch(modelHandle) {
486465
486547
  model: modelHandle
486466
486548
  };
486467
486549
  }
486468
- const endpointType = provider === OPENAI_CODEX_PROVIDER_NAME ? "chatgpt_oauth" : provider;
486550
+ const endpointType = provider === OPENAI_CODEX_PROVIDER_NAME || provider === "openai-codex" ? "chatgpt_oauth" : provider;
486469
486551
  return {
486470
486552
  model: modelName,
486471
486553
  model_endpoint_type: endpointType
@@ -487534,12 +487616,6 @@ function formatReflectionSettings(settings3) {
487534
487616
  }
487535
487617
  return `Step count (every ${settings3.stepCount} turns)`;
487536
487618
  }
487537
- function hasActiveReflectionSubagent2(agentId, conversationId) {
487538
- return isReflectionSubagentActive(getSubagents(), agentId, conversationId);
487539
- }
487540
- var init_reflection2 = __esm(() => {
487541
- init_subagent_state();
487542
- });
487543
487619
 
487544
487620
  // src/cli/app/use-configuration-handlers.ts
487545
487621
  function useConfigurationHandlers(ctx) {
@@ -487578,7 +487654,9 @@ function useConfigurationHandlers(ctx) {
487578
487654
  setTempModelOverride,
487579
487655
  withCommandLock
487580
487656
  } = ctx;
487581
- const handleModelSelect = import_react114.useCallback(async (modelId, commandId, opts) => {
487657
+ const handleModelSelect = import_react114.useCallback(async (model, commandId, opts) => {
487658
+ const inputSelection = typeof model === "string" ? null : model;
487659
+ const modelId = typeof model === "string" ? model : model.id;
487582
487660
  let overlayCommand = commandId ? commandRunner.getHandle(commandId, "/model") : null;
487583
487661
  const resolveOverlayCommand = () => {
487584
487662
  if (overlayCommand) {
@@ -487589,19 +487667,39 @@ function useConfigurationHandlers(ctx) {
487589
487667
  };
487590
487668
  let selectedModel = null;
487591
487669
  try {
487592
- const { getReasoningTierOptionsForHandle: getReasoningTierOptionsForHandle3, models: models4 } = await Promise.resolve().then(() => (init_model(), exports_model));
487670
+ const {
487671
+ getChatGptFastRegistryHandleForModelHandle: getChatGptFastRegistryHandleForModelHandle3,
487672
+ getReasoningTierOptionsForHandle: getReasoningTierOptionsForHandle3,
487673
+ normalizeModelHandleForRegistry: normalizeModelHandleForRegistry3,
487674
+ models: models4
487675
+ } = await Promise.resolve().then(() => (init_model(), exports_model));
487593
487676
  const pickPreferredModelForHandle = (handle2) => {
487594
- const candidates2 = models4.filter((m4) => m4.handle === handle2);
487677
+ const registryHandle2 = normalizeModelHandleForRegistry3(handle2) ?? handle2;
487678
+ const candidates2 = models4.filter((m4) => m4.handle === registryHandle2);
487595
487679
  return candidates2.find((m4) => m4.isDefault) ?? candidates2.find((m4) => m4.isFeatured) ?? candidates2.find((m4) => m4.updateArgs?.reasoning_effort === "medium") ?? candidates2.find((m4) => m4.updateArgs?.reasoning_effort === "high") ?? candidates2[0] ?? null;
487596
487680
  };
487597
- selectedModel = models4.find((m4) => m4.id === modelId) ?? null;
487681
+ selectedModel = inputSelection ? {
487682
+ id: inputSelection.id,
487683
+ handle: inputSelection.handle,
487684
+ label: inputSelection.label,
487685
+ description: inputSelection.description,
487686
+ updateArgs: inputSelection.updateArgs,
487687
+ registryHandle: inputSelection.registryHandle
487688
+ } : models4.find((m4) => m4.id === modelId) ?? null;
487598
487689
  if (!selectedModel && modelId.includes("/")) {
487599
487690
  const handleMatch = pickPreferredModelForHandle(modelId);
487600
487691
  if (handleMatch) {
487692
+ const fastRegistryHandle = getChatGptFastRegistryHandleForModelHandle3(modelId);
487693
+ const updateArgs = {
487694
+ ...handleMatch.updateArgs ?? {},
487695
+ ...fastRegistryHandle ? { service_tier: null } : {}
487696
+ };
487601
487697
  selectedModel = {
487602
487698
  ...handleMatch,
487603
487699
  id: modelId,
487604
- handle: modelId
487700
+ handle: modelId,
487701
+ registryHandle: normalizeModelHandleForRegistry3(modelId) ?? modelId,
487702
+ updateArgs: Object.keys(updateArgs).length > 0 ? updateArgs : undefined
487605
487703
  };
487606
487704
  }
487607
487705
  }
@@ -487635,20 +487733,39 @@ function useConfigurationHandlers(ctx) {
487635
487733
  cmd.fail(output);
487636
487734
  return;
487637
487735
  }
487638
- const model = selectedModel;
487639
- const modelHandle = model.handle ?? model.id;
487640
- const modelUpdateArgs = model.updateArgs;
487736
+ const model2 = selectedModel;
487737
+ const modelHandle = model2.handle ?? model2.id;
487738
+ const registryHandle = model2.registryHandle ?? normalizeModelHandleForRegistry3(modelHandle) ?? modelHandle;
487739
+ const modelUpdateArgs = model2.updateArgs;
487641
487740
  const rawReasoningEffort = modelUpdateArgs?.reasoning_effort;
487642
- const usesDistinctXHighLabel = model.label.includes("Opus 4.7") || model.label.includes("Opus 4.8");
487741
+ const usesDistinctXHighLabel = model2.label.includes("Opus 4.7") || model2.label.includes("Opus 4.8");
487643
487742
  const reasoningLevel = typeof rawReasoningEffort === "string" ? rawReasoningEffort === "none" ? "no" : rawReasoningEffort === "xhigh" ? usesDistinctXHighLabel ? "extra-high" : "max" : rawReasoningEffort : modelUpdateArgs?.enable_reasoner === false ? "no" : null;
487644
- const selectedContextWindow = model.updateArgs?.context_window;
487645
- const reasoningTierOptions = getReasoningTierOptionsForHandle3(modelHandle, selectedContextWindow);
487743
+ const selectedContextWindow = model2.updateArgs?.context_window;
487744
+ const reasoningTierOptions = getReasoningTierOptionsForHandle3(registryHandle, selectedContextWindow).map((option2) => {
487745
+ const optionModel = models4.find((entry) => entry.id === option2.modelId);
487746
+ const serviceTier = modelUpdateArgs?.service_tier;
487747
+ const optionUpdateArgs = {
487748
+ ...optionModel?.updateArgs ?? {},
487749
+ ...serviceTier !== undefined ? { service_tier: serviceTier } : {}
487750
+ };
487751
+ return {
487752
+ ...option2,
487753
+ selection: {
487754
+ id: option2.modelId,
487755
+ handle: modelHandle,
487756
+ label: model2.label,
487757
+ description: model2.description ?? "",
487758
+ registryHandle,
487759
+ updateArgs: optionUpdateArgs
487760
+ }
487761
+ };
487762
+ });
487646
487763
  if (!opts?.skipReasoningPrompt && (opts?.promptReasoning || activeOverlay === "model") && reasoningTierOptions.length > 1) {
487647
- const selectedEffort = model.updateArgs?.reasoning_effort;
487764
+ const selectedEffort = model2.updateArgs?.reasoning_effort;
487648
487765
  const preferredOption = (typeof selectedEffort === "string" && reasoningTierOptions.find((option2) => option2.effort === selectedEffort)) ?? reasoningTierOptions.find((option2) => option2.effort === "medium") ?? reasoningTierOptions[0];
487649
487766
  if (preferredOption) {
487650
487767
  setModelReasoningPrompt({
487651
- modelLabel: model.label,
487768
+ modelLabel: model2.label,
487652
487769
  initialModelId: preferredOption.modelId,
487653
487770
  initialEffort: preferredOption.effort,
487654
487771
  options: reasoningTierOptions
@@ -487667,6 +487784,7 @@ function useConfigurationHandlers(ctx) {
487667
487784
  setQueuedOverlayAction({
487668
487785
  type: "switch_model",
487669
487786
  modelId,
487787
+ modelSelection: inputSelection ?? undefined,
487670
487788
  commandId: cmd.id
487671
487789
  });
487672
487790
  return;
@@ -487679,14 +487797,14 @@ function useConfigurationHandlers(ctx) {
487679
487797
  selectedModelHandle: modelHandle,
487680
487798
  selectedContextWindow
487681
487799
  });
487682
- const modelUpdateArgsForRequest = model.updateArgs ? { ...model.updateArgs } : undefined;
487800
+ const modelUpdateArgsForRequest = model2.updateArgs ? { ...model2.updateArgs } : undefined;
487683
487801
  if (shouldPreserveContextWindow && modelUpdateArgsForRequest) {
487684
487802
  delete modelUpdateArgsForRequest.context_window;
487685
487803
  }
487686
487804
  await withCommandLock(async () => {
487687
- const cmd = resolveOverlayCommand() ?? commandRunner.start("/model", `Switching model to ${model.label}...`);
487805
+ const cmd = resolveOverlayCommand() ?? commandRunner.start("/model", `Switching model to ${model2.label}...`);
487688
487806
  cmd.update({
487689
- output: `Switching model to ${model.label}...`,
487807
+ output: `Switching model to ${model2.label}...`,
487690
487808
  phase: "running"
487691
487809
  });
487692
487810
  const isDefaultConversation = conversationIdRef.current === "default";
@@ -487775,7 +487893,7 @@ function useConfigurationHandlers(ctx) {
487775
487893
  toolsetNoticeLine = "Manual toolset override remains active: " + formatToolsetName(persistedToolsetPreference) + ".";
487776
487894
  }
487777
487895
  const outputLines = [
487778
- "Switched to " + model.label + (reasoningLevel ? ` (${reasoningLevel} reasoning)` : ""),
487896
+ "Switched to " + model2.label + (reasoningLevel ? ` (${reasoningLevel} reasoning)` : ""),
487779
487897
  ...toolsetNoticeLine ? [toolsetNoticeLine] : []
487780
487898
  ].join(`
487781
487899
  `);
@@ -488272,7 +488390,6 @@ var init_use_configuration_handlers = __esm(async () => {
488272
488390
  init_settings_manager();
488273
488391
  init_toolset_labels();
488274
488392
  init_model_config();
488275
- init_reflection2();
488276
488393
  await init_manager4();
488277
488394
  import_react114 = __toESM(require_react(), 1);
488278
488395
  });
@@ -491007,6 +491124,12 @@ var init_use_queued_approval_submit = __esm(() => {
491007
491124
  function supportsDistinctAnthropicXHighEffort3(modelHandle) {
491008
491125
  return modelHandle.includes("claude-opus-4-7") || modelHandle.includes("claude-opus-4-8");
491009
491126
  }
491127
+ function serviceTierForReasoningCycle(modelHandle, modelSettings) {
491128
+ if (!getChatGptFastRegistryHandleForModelHandle(modelHandle)) {
491129
+ return;
491130
+ }
491131
+ return modelSettings?.service_tier === CHATGPT_FAST_SERVICE_TIER ? CHATGPT_FAST_SERVICE_TIER : null;
491132
+ }
491010
491133
  function resolveReasoningCycleModelHandle(llmConfig, agentModel) {
491011
491134
  if (agentModel && isLocalModelHandle(agentModel)) {
491012
491135
  return agentModel;
@@ -491028,6 +491151,7 @@ function useReasoningCycle(ctx) {
491028
491151
  agentIdRef,
491029
491152
  agentStateRef,
491030
491153
  commandRunner,
491154
+ conversationOverrideModelSettingsRef,
491031
491155
  conversationIdRef,
491032
491156
  hasConversationModelOverrideRef,
491033
491157
  isAgentBusy,
@@ -491082,12 +491206,14 @@ function useReasoningCycle(ctx) {
491082
491206
  if (isDefaultConversation) {
491083
491207
  const { updateAgentLLMConfig: updateAgentLLMConfig3 } = await Promise.resolve().then(() => (init_modify(), exports_modify));
491084
491208
  updatedAgent = await updateAgentLLMConfig3(agentIdRef.current, desired.modelHandle, {
491085
- reasoning_effort: desired.effort
491209
+ reasoning_effort: desired.effort,
491210
+ ...desired.serviceTier !== undefined ? { service_tier: desired.serviceTier } : {}
491086
491211
  }, { preserveContextWindow: true });
491087
491212
  } else {
491088
491213
  const { updateConversationLLMConfig: updateConversationLLMConfig2 } = await Promise.resolve().then(() => (init_modify(), exports_modify));
491089
491214
  const updatedConversation = await updateConversationLLMConfig2(conversationIdRef.current, desired.modelHandle, {
491090
- reasoning_effort: desired.effort
491215
+ reasoning_effort: desired.effort,
491216
+ ...desired.serviceTier !== undefined ? { service_tier: desired.serviceTier } : {}
491091
491217
  }, { preserveContextWindow: true });
491092
491218
  conversationModelSettings2 = updatedConversation.model_settings;
491093
491219
  conversationContextWindowLimit = updatedConversation.context_window_limit;
@@ -491173,7 +491299,7 @@ function useReasoningCycle(ctx) {
491173
491299
  const modelHandle = resolveReasoningCycleModelHandle(current, hasConversationModelOverrideRef.current ? null : agentStateRef.current?.model ?? null);
491174
491300
  if (!modelHandle)
491175
491301
  return;
491176
- const modelSettingsForEffort = hasConversationModelOverrideRef.current ? undefined : agentStateRef.current?.model_settings;
491302
+ const modelSettingsForEffort = hasConversationModelOverrideRef.current ? conversationOverrideModelSettingsRef.current : agentStateRef.current?.model_settings;
491177
491303
  const currentEffort = deriveReasoningEffort(modelSettingsForEffort, current) ?? "none";
491178
491304
  const { getReasoningTierOptionsForHandle: getReasoningTierOptionsForHandle3 } = await Promise.resolve().then(() => (init_model(), exports_model));
491179
491305
  const tiers = getReasoningTierOptionsForHandle3(modelHandle).map((option2) => ({
@@ -491202,6 +491328,7 @@ function useReasoningCycle(ctx) {
491202
491328
  const next = sorted[nextIndex];
491203
491329
  if (!next)
491204
491330
  return;
491331
+ const serviceTier = serviceTierForReasoningCycle(modelHandle, modelSettingsForEffort);
491205
491332
  if (!reasoningCycleLastConfirmedRef.current) {
491206
491333
  reasoningCycleLastConfirmedRef.current = current ?? null;
491207
491334
  reasoningCycleLastConfirmedAgentStateRef.current = hasConversationModelOverrideRef.current ? null : agentStateRef.current ?? null;
@@ -491215,7 +491342,7 @@ function useReasoningCycle(ctx) {
491215
491342
  const ms = prev.model_settings;
491216
491343
  if (!ms || !("provider_type" in ms))
491217
491344
  return prev;
491218
- if (ms.provider_type === "openai") {
491345
+ if (ms.provider_type === "openai" || ms.provider_type === "chatgpt_oauth") {
491219
491346
  return {
491220
491347
  ...prev,
491221
491348
  model_settings: {
@@ -491245,7 +491372,8 @@ function useReasoningCycle(ctx) {
491245
491372
  reasoningCycleDesiredRef.current = {
491246
491373
  modelHandle,
491247
491374
  effort: next.effort,
491248
- modelId: next.id
491375
+ modelId: next.id,
491376
+ serviceTier
491249
491377
  };
491250
491378
  if (reasoningCycleTimerRef.current) {
491251
491379
  clearTimeout(reasoningCycleTimerRef.current);
@@ -492100,21 +492228,6 @@ async function handleConnectionCommand(msg, trimmed, ctx) {
492100
492228
  }
492101
492229
  return { submitted: true };
492102
492230
  }
492103
- if (trimmed.startsWith("/disconnect")) {
492104
- const cmd = commandRunner.start(msg, "Disconnecting...");
492105
- const { handleDisconnect: handleDisconnect2, setActiveCommandId: setActiveConnectCommandId } = await Promise.resolve().then(() => (init_connect(), exports_connect));
492106
- setActiveConnectCommandId(cmd.id);
492107
- try {
492108
- await handleDisconnect2({
492109
- buffersRef,
492110
- refreshDerived,
492111
- setCommandRunning
492112
- }, msg);
492113
- } finally {
492114
- setActiveConnectCommandId(null);
492115
- }
492116
- return { submitted: true };
492117
- }
492118
492231
  if (trimmed === "/server" || trimmed.startsWith("/server ") || trimmed === "/remote" || trimmed.startsWith("/remote ")) {
492119
492232
  const parts = Array.from(trimmed.matchAll(/"([^"\\]*(?:\\.[^"\\]*)*)"|'([^'\\]*(?:\\.[^'\\]*)*)'|(\S+)/g), (match4) => match4[1] ?? match4[2] ?? match4[3]);
492120
492233
  let name;
@@ -494943,76 +495056,35 @@ ${SYSTEM_REMINDER_CLOSE}`;
494943
495056
  cmd.fail("Memory filesystem is not enabled. Use /remember instead.");
494944
495057
  return { submitted: true };
494945
495058
  }
494946
- const reflectConversationId = conversationIdRef.current ?? "default";
494947
- if (hasActiveReflectionSubagent2(agentId, reflectConversationId)) {
494948
- cmd.fail("A reflection agent is already running in the background.");
494949
- return { submitted: true };
494950
- }
494951
495059
  try {
494952
- const reflectionConversationId = conversationIdRef.current;
494953
- let systemPrompt;
494954
- try {
494955
- const agent2 = await getBackend().retrieveAgent(agentId);
494956
- systemPrompt = agent2.system ?? undefined;
494957
- } catch {}
494958
- const autoPayload = await buildAutoReflectionPayload(agentId, reflectionConversationId, systemPrompt);
494959
- if (!autoPayload) {
494960
- cmd.fail("No new transcript content to reflect on.");
494961
- return { submitted: true };
494962
- }
494963
- const memoryDir = getScopedMemoryFilesystemRoot(agentId);
494964
- const parentMemory = await buildParentMemorySnapshot(memoryDir);
494965
- const reflectionPrompt = buildReflectionSubagentPrompt({
494966
- memoryDir,
494967
- parentMemory
494968
- });
494969
- const {
494970
- spawnBackgroundSubagentTask: spawnBackgroundSubagentTask2,
494971
- waitForBackgroundSubagentAgentId: waitForBackgroundSubagentAgentId2
494972
- } = await Promise.resolve().then(() => (init_task(), exports_task));
494973
- const { subagentId } = spawnBackgroundSubagentTask2({
494974
- subagentType: "reflection",
494975
- prompt: reflectionPrompt,
495060
+ const reflectionConversationId = conversationIdRef.current ?? "default";
495061
+ const result2 = await launchReflectionSubagent({
495062
+ agentId,
495063
+ conversationId: reflectionConversationId,
495064
+ memfsEnabled: isActiveMemfsEnabled(agentId),
495065
+ triggerSource: "manual",
494976
495066
  description: "Reflecting on conversation",
494977
- silentCompletion: true,
494978
- transcriptPath: autoPayload.payloadPath,
494979
- parentScope: {
494980
- agentId,
494981
- conversationId: reflectionConversationId
494982
- },
494983
- onComplete: async ({
494984
- success: success2,
494985
- error: error54,
494986
- agentId: reflectionAgentId2
494987
- }) => {
494988
- telemetry.trackReflectionEnd("manual", success2, {
494989
- subagentId: reflectionAgentId2 ?? undefined,
494990
- conversationId: reflectionConversationId,
494991
- error: error54
494992
- });
494993
- await finalizeAutoReflectionPayload(agentId, reflectionConversationId, autoPayload.payloadPath, autoPayload.endSnapshotLine, success2);
494994
- const msg2 = await handleMemorySubagentCompletion({
494995
- agentId,
494996
- conversationId: conversationIdRef.current,
494997
- subagentType: "reflection",
494998
- success: success2,
494999
- error: error54
495000
- }, {
495001
- recompileByConversation: systemPromptRecompileByConversationRef.current,
495002
- recompileQueuedByConversation: queuedSystemPromptRecompileByConversationRef.current,
495003
- logRecompileFailure: (message2) => debugWarn("memory", message2)
495004
- });
495005
- appendTaskNotificationEvents([msg2]);
495067
+ completionConversationId: () => conversationIdRef.current,
495068
+ recompileByConversation: systemPromptRecompileByConversationRef.current,
495069
+ recompileQueuedByConversation: queuedSystemPromptRecompileByConversationRef.current,
495070
+ onCompletionMessage: (completionMessage) => {
495071
+ appendTaskNotificationEvents([completionMessage]);
495006
495072
  }
495007
495073
  });
495008
- const reflectionAgentId = await waitForBackgroundSubagentAgentId2(subagentId, 1000);
495009
- telemetry.trackReflectionStart("manual", {
495010
- subagentId: reflectionAgentId ?? undefined,
495011
- conversationId: reflectionConversationId,
495012
- startMessageId: autoPayload.startMessageId,
495013
- endMessageId: autoPayload.endMessageId
495014
- });
495015
- cmd.finish(`Reflecting on the recent conversation. View the transcript here: ${autoPayload.payloadPath}`, true);
495074
+ if (!result2.launched) {
495075
+ if (result2.reason === "already_active") {
495076
+ cmd.fail("A reflection agent is already running in the background.");
495077
+ } else if (result2.reason === "no_payload") {
495078
+ cmd.fail("No new transcript content to reflect on.");
495079
+ } else if (result2.reason === "memfs_disabled") {
495080
+ cmd.fail("Memory filesystem is not enabled. Use /remember instead.");
495081
+ } else {
495082
+ const errorDetails = formatErrorDetails2(result2.error ?? "Unknown error", agentId);
495083
+ cmd.fail(`Failed to start reflection agent: ${errorDetails}`);
495084
+ }
495085
+ return { submitted: true };
495086
+ }
495087
+ cmd.finish(`Reflecting on the recent conversation. View the transcript here: ${result2.payloadPath}`, true);
495016
495088
  } catch (error54) {
495017
495089
  const errorDetails = formatErrorDetails2(error54, agentId);
495018
495090
  cmd.fail(`Failed to start reflection agent: ${errorDetails}`);
@@ -495414,84 +495486,21 @@ ${SYSTEM_REMINDER_CLOSE}
495414
495486
  reminderParts.push({ type: "text", text: text2 });
495415
495487
  };
495416
495488
  const maybeLaunchReflectionSubagent = async (triggerSource) => {
495417
- if (!memfsEnabledForAgent) {
495418
- return false;
495419
- }
495420
- const autoReflectConversationId = conversationIdRef.current ?? "default";
495421
- if (hasActiveReflectionSubagent2(agentId, autoReflectConversationId)) {
495422
- debugLog("memory", `Skipping auto reflection launch (${triggerSource}) because one is already active`);
495423
- return false;
495424
- }
495425
- try {
495426
- const reflectionConversationId = conversationIdRef.current;
495427
- let systemPrompt;
495428
- try {
495429
- const agent2 = await getBackend().retrieveAgent(agentId);
495430
- systemPrompt = agent2.system ?? undefined;
495431
- } catch {}
495432
- const autoPayload = await buildAutoReflectionPayload(agentId, reflectionConversationId, systemPrompt);
495433
- if (!autoPayload) {
495434
- debugLog("memory", `Skipping auto reflection launch (${triggerSource}) because transcript has no new content`);
495435
- return false;
495489
+ const reflectionConversationId = conversationIdRef.current ?? "default";
495490
+ const result = await launchReflectionSubagent({
495491
+ agentId,
495492
+ conversationId: reflectionConversationId,
495493
+ memfsEnabled: memfsEnabledForAgent,
495494
+ triggerSource,
495495
+ description: AUTO_REFLECTION_DESCRIPTION,
495496
+ completionConversationId: () => conversationIdRef.current,
495497
+ recompileByConversation: systemPromptRecompileByConversationRef.current,
495498
+ recompileQueuedByConversation: queuedSystemPromptRecompileByConversationRef.current,
495499
+ onCompletionMessage: (completionMessage) => {
495500
+ appendTaskNotificationEvents([completionMessage]);
495436
495501
  }
495437
- const memoryDir = getScopedMemoryFilesystemRoot(agentId);
495438
- const parentMemory = await buildParentMemorySnapshot(memoryDir);
495439
- const reflectionPrompt = buildReflectionSubagentPrompt({
495440
- memoryDir,
495441
- parentMemory
495442
- });
495443
- const {
495444
- spawnBackgroundSubagentTask: spawnBackgroundSubagentTask2,
495445
- waitForBackgroundSubagentAgentId: waitForBackgroundSubagentAgentId2
495446
- } = await Promise.resolve().then(() => (init_task(), exports_task));
495447
- const { subagentId } = spawnBackgroundSubagentTask2({
495448
- subagentType: "reflection",
495449
- prompt: reflectionPrompt,
495450
- description: AUTO_REFLECTION_DESCRIPTION3,
495451
- silentCompletion: true,
495452
- transcriptPath: autoPayload.payloadPath,
495453
- parentScope: {
495454
- agentId,
495455
- conversationId: reflectionConversationId
495456
- },
495457
- onComplete: async ({
495458
- success: success2,
495459
- error: error54,
495460
- agentId: reflectionAgentId2
495461
- }) => {
495462
- telemetry.trackReflectionEnd(triggerSource, success2, {
495463
- subagentId: reflectionAgentId2 ?? undefined,
495464
- conversationId: reflectionConversationId,
495465
- error: error54
495466
- });
495467
- await finalizeAutoReflectionPayload(agentId, reflectionConversationId, autoPayload.payloadPath, autoPayload.endSnapshotLine, success2);
495468
- const msg2 = await handleMemorySubagentCompletion({
495469
- agentId,
495470
- conversationId: conversationIdRef.current,
495471
- subagentType: "reflection",
495472
- success: success2,
495473
- error: error54
495474
- }, {
495475
- recompileByConversation: systemPromptRecompileByConversationRef.current,
495476
- recompileQueuedByConversation: queuedSystemPromptRecompileByConversationRef.current,
495477
- logRecompileFailure: (message2) => debugWarn("memory", message2)
495478
- });
495479
- appendTaskNotificationEvents([msg2]);
495480
- }
495481
- });
495482
- const reflectionAgentId = await waitForBackgroundSubagentAgentId2(subagentId, 1000);
495483
- telemetry.trackReflectionStart(triggerSource, {
495484
- subagentId: reflectionAgentId ?? undefined,
495485
- conversationId: reflectionConversationId,
495486
- startMessageId: autoPayload.startMessageId,
495487
- endMessageId: autoPayload.endMessageId
495488
- });
495489
- debugLog("memory", `Auto-launched reflection subagent (${triggerSource})`);
495490
- return true;
495491
- } catch (error54) {
495492
- debugWarn("memory", `Failed to auto-launch reflection subagent (${triggerSource}): ${error54 instanceof Error ? error54.message : String(error54)}`);
495493
- return false;
495494
- }
495502
+ });
495503
+ return result.launched;
495495
495504
  };
495496
495505
  syncReminderStateFromContextTracker(sharedReminderStateRef.current, contextTrackerRef.current);
495497
495506
  const { getSkillSources: getSkillSources2 } = await Promise.resolve().then(() => (init_context(), exports_context));
@@ -495635,10 +495644,9 @@ var init_use_submit_handler = __esm(async () => {
495635
495644
  init_goal_command();
495636
495645
  init_init_command();
495637
495646
  init_memory_reminder();
495638
- init_memory_subagent_completion();
495639
495647
  init_paste_registry();
495640
495648
  init_reasoning_tab_toggle();
495641
- init_reflection_transcript();
495649
+ init_reflection_launcher();
495642
495650
  init_system_prompt_warning();
495643
495651
  init_thinking_messages();
495644
495652
  init_constants2();
@@ -495653,10 +495661,8 @@ var init_use_submit_handler = __esm(async () => {
495653
495661
  init_debug();
495654
495662
  init_cwd_change();
495655
495663
  init_command_routing();
495656
- init_constants7();
495657
495664
  init_goal_loop();
495658
495665
  init_ids();
495659
- init_reflection2();
495660
495666
  init_session3();
495661
495667
  init_submit_connection_commands();
495662
495668
  init_submit_diagnostics_commands();
@@ -496006,6 +496012,10 @@ function App2({
496006
496012
  conversationOverrideModelSettings,
496007
496013
  setConversationOverrideModelSettings
496008
496014
  ] = import_react122.useState(null);
496015
+ const conversationOverrideModelSettingsRef = import_react122.useRef(conversationOverrideModelSettings);
496016
+ import_react122.useEffect(() => {
496017
+ conversationOverrideModelSettingsRef.current = conversationOverrideModelSettings;
496018
+ }, [conversationOverrideModelSettings]);
496009
496019
  const [
496010
496020
  conversationOverrideContextWindowLimit,
496011
496021
  setConversationOverrideContextWindowLimit
@@ -496037,6 +496047,7 @@ function App2({
496037
496047
  const currentModelLabel = tempModelOverride || currentModelHandle || agentState?.model || (llmConfig?.model_endpoint_type && llmConfig?.model ? `${llmConfig.model_endpoint_type}/${llmConfig.model}` : llmConfig?.model ?? null) || null;
496038
496048
  const effectiveModelSettings = hasConversationModelOverride ? conversationOverrideModelSettings : agentState?.model_settings;
496039
496049
  const derivedReasoningEffort = deriveReasoningEffort(effectiveModelSettings, llmConfig);
496050
+ const currentModelServiceTier = effectiveModelSettings?.service_tier === CHATGPT_FAST_SERVICE_TIER && currentModelLabel && getChatGptFastRegistryHandleForModelHandle(currentModelLabel) ? CHATGPT_FAST_SERVICE_TIER : null;
496040
496051
  const startupModelDisplayOverride = getStartupModelDisplayOverride({
496041
496052
  isLocalBackend: isLocalBackendEnabled(),
496042
496053
  startupHasAvailableLocalModels: hasAvailableLocalModels
@@ -496049,7 +496060,8 @@ function App2({
496049
496060
  const info = getModelInfoForLlmConfig(currentModelLabel, {
496050
496061
  reasoning_effort: derivedReasoningEffort ?? null,
496051
496062
  enable_reasoner: llmConfig?.enable_reasoner ?? null,
496052
- context_window: llmConfig?.context_window ?? null
496063
+ context_window: llmConfig?.context_window ?? null,
496064
+ service_tier: currentModelServiceTier
496053
496065
  });
496054
496066
  if (info) {
496055
496067
  return info.shortLabel ?? info.label;
@@ -496058,6 +496070,7 @@ function App2({
496058
496070
  }, [
496059
496071
  currentModelLabel,
496060
496072
  derivedReasoningEffort,
496073
+ currentModelServiceTier,
496061
496074
  llmConfig,
496062
496075
  startupModelDisplayOverride
496063
496076
  ]);
@@ -497553,10 +497566,12 @@ function App2({
497553
497566
  const hasConversationModelSettings = conversationModelSettings2 !== undefined && conversationModelSettings2 !== null && Object.keys(conversationModelSettings2).length > 0;
497554
497567
  const resolvedConversationModelSettings = hasConversationModelSettings ? conversationModelSettings2 : conversationModel === undefined || conversationModel === null || conversationModel === agentModelHandle ? agentState.model_settings ?? null : null;
497555
497568
  const reasoningEffort = deriveReasoningEffort(resolvedConversationModelSettings, agentState.llm_config);
497569
+ const conversationServiceTier = resolvedConversationModelSettings?.service_tier === CHATGPT_FAST_SERVICE_TIER && getChatGptFastRegistryHandleForModelHandle(effectiveModelHandle) ? CHATGPT_FAST_SERVICE_TIER : null;
497556
497570
  const modelInfo = getModelInfoForLlmConfig(effectiveModelHandle, {
497557
497571
  reasoning_effort: reasoningEffort,
497558
497572
  enable_reasoner: agentState.llm_config.enable_reasoner ?? null,
497559
- context_window: conversationContextWindowLimit ?? null
497573
+ context_window: conversationContextWindowLimit ?? null,
497574
+ service_tier: conversationServiceTier
497560
497575
  });
497561
497576
  const modelPresetContextWindow2 = modelInfo?.updateArgs?.context_window;
497562
497577
  const resolvedConversationContextWindowLimit = conversationContextWindowLimit === undefined ? typeof modelPresetContextWindow2 === "number" ? modelPresetContextWindow2 : null : conversationContextWindowLimit;
@@ -498301,7 +498316,7 @@ Memory may be stale. Try running: git -C ${getScopedMemoryFilesystemRoot(agentId
498301
498316
  backendMode: action3.backendMode
498302
498317
  });
498303
498318
  } else if (action3.type === "switch_model") {
498304
- handleModelSelect(action3.modelId, action3.commandId);
498319
+ handleModelSelect(action3.modelSelection ?? action3.modelId, action3.commandId);
498305
498320
  } else if (action3.type === "set_sleeptime") {
498306
498321
  handleSleeptimeModeSelect(action3.settings, action3.commandId);
498307
498322
  } else if (action3.type === "set_compaction") {
@@ -498443,6 +498458,7 @@ Memory may be stale. Try running: git -C ${getScopedMemoryFilesystemRoot(agentId
498443
498458
  agentIdRef,
498444
498459
  agentStateRef,
498445
498460
  commandRunner,
498461
+ conversationOverrideModelSettingsRef,
498446
498462
  conversationIdRef,
498447
498463
  hasConversationModelOverrideRef,
498448
498464
  isAgentBusy,
@@ -498647,6 +498663,7 @@ Memory may be stale. Try running: git -C ${getScopedMemoryFilesystemRoot(agentId
498647
498663
  currentModelDisplay,
498648
498664
  currentModelHandle,
498649
498665
  currentModelId,
498666
+ currentModelServiceTier,
498650
498667
  currentModelProvider,
498651
498668
  isLocalBackend,
498652
498669
  currentPersonalityId,
@@ -501846,7 +501863,8 @@ function supportsDistinctAnthropicXHighEffort2(modelHandle) {
501846
501863
  return modelHandle.includes("claude-opus-4-7") || modelHandle.includes("claude-opus-4-8");
501847
501864
  }
501848
501865
  function buildModelSettings2(modelHandle, updateArgs) {
501849
- const isOpenAI = modelHandle.startsWith("openai/") || modelHandle.startsWith(`${OPENAI_CODEX_PROVIDER_NAME}/`);
501866
+ const isOpenAICodex = modelHandle.startsWith("openai-codex/");
501867
+ const isOpenAI = modelHandle.startsWith("openai/") || isOpenAICodex || modelHandle.startsWith(`${OPENAI_CODEX_PROVIDER_NAME}/`);
501850
501868
  const isAnthropic = modelHandle.startsWith("anthropic/") || modelHandle.startsWith("claude-pro-max/") || modelHandle.startsWith("minimax/");
501851
501869
  const isZai = modelHandle.startsWith("zai/");
501852
501870
  const isGoogleAI = modelHandle.startsWith("google_ai/");
@@ -501859,6 +501877,9 @@ function buildModelSettings2(modelHandle, updateArgs) {
501859
501877
  provider_type: "openai",
501860
501878
  parallel_tool_calls: true
501861
501879
  };
501880
+ if (isOpenAICodex) {
501881
+ openaiSettings.provider_type = "chatgpt_oauth";
501882
+ }
501862
501883
  if (updateArgs?.reasoning_effort) {
501863
501884
  openaiSettings.reasoning = {
501864
501885
  reasoning_effort: updateArgs.reasoning_effort
@@ -501871,6 +501892,9 @@ function buildModelSettings2(modelHandle, updateArgs) {
501871
501892
  if (typeof updateArgs?.strict === "boolean") {
501872
501893
  openaiSettings.strict = updateArgs.strict;
501873
501894
  }
501895
+ if (updateArgs && "service_tier" in updateArgs) {
501896
+ openaiSettings.service_tier = updateArgs.service_tier === "priority" ? "priority" : null;
501897
+ }
501874
501898
  settings3 = openaiSettings;
501875
501899
  } else if (isAnthropic) {
501876
501900
  const anthropicSettings = {
@@ -505720,7 +505744,7 @@ async function runConnectSubcommand(argv, deps = {}) {
505720
505744
  if (provider.target !== "local") {
505721
505745
  await io.ensureSettingsReady();
505722
505746
  if (await io.isChatGPTOAuthConnected()) {
505723
- io.stdout("Already connected to ChatGPT via OAuth. Disconnect first if you want to re-authenticate.");
505747
+ io.stdout("Already connected to ChatGPT via OAuth. Use /connect in the TUI and select ChatGPT / Codex plan to disconnect or re-authenticate.");
505724
505748
  return 0;
505725
505749
  }
505726
505750
  await io.runChatGPTOAuthConnectFlow({
@@ -512405,4 +512429,4 @@ Error during initialization: ${message}`);
512405
512429
  }
512406
512430
  main2();
512407
512431
 
512408
- //# debugId=FB2D67983121CCDA64756E2164756E21
512432
+ //# debugId=2016C33D7C4F1E2064756E2164756E21