@charzhu/openjaw-agent 0.2.5 → 0.2.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.
package/dist/main.js CHANGED
@@ -123,6 +123,7 @@ function loadAgentConfig() {
123
123
  temperature: parsedLlm?.temperature ?? DEFAULT_CONFIG.llm.temperature,
124
124
  computer_use: parsedLlm?.computer_use ?? DEFAULT_CONFIG.llm.computer_use,
125
125
  use_responses_api: parsedLlm?.use_responses_api ?? DEFAULT_CONFIG.llm.use_responses_api,
126
+ model_reasoning_effort: parsedLlm?.model_reasoning_effort,
126
127
  openai_tool_mode: parsedLlm?.openai_tool_mode ?? DEFAULT_CONFIG.llm.openai_tool_mode,
127
128
  openai_max_tools: parsedLlm?.openai_max_tools ?? DEFAULT_CONFIG.llm.openai_max_tools,
128
129
  openai_mcp_max_tools: parsedLlm?.openai_mcp_max_tools,
@@ -1973,6 +1974,55 @@ var init_provider_auth = __esm({
1973
1974
  }
1974
1975
  });
1975
1976
 
1977
+ // src/providers/types.ts
1978
+ function isReasoningEffort(value) {
1979
+ return REASONING_EFFORTS.includes(value);
1980
+ }
1981
+ function reasoningEffortLabel(effort) {
1982
+ switch (effort) {
1983
+ case "none":
1984
+ return "None";
1985
+ case "minimal":
1986
+ return "Minimal";
1987
+ case "low":
1988
+ return "Low";
1989
+ case "medium":
1990
+ return "Medium";
1991
+ case "high":
1992
+ return "High";
1993
+ case "xhigh":
1994
+ return "Extra high";
1995
+ }
1996
+ }
1997
+ function normalizeReasoningEfforts(values) {
1998
+ if (!Array.isArray(values)) return [];
1999
+ const efforts = [];
2000
+ for (const item of values) {
2001
+ if (typeof item !== "string" || !isReasoningEffort(item)) continue;
2002
+ if (!efforts.includes(item)) efforts.push(item);
2003
+ }
2004
+ return efforts;
2005
+ }
2006
+ function defaultReasoningEffort(efforts) {
2007
+ if (efforts.length === 0) return void 0;
2008
+ return efforts.includes("medium") ? "medium" : efforts[0];
2009
+ }
2010
+ function orderedReasoningEfforts(efforts) {
2011
+ return REASONING_EFFORTS.filter((effort) => efforts.includes(effort));
2012
+ }
2013
+ var REASONING_EFFORTS;
2014
+ var init_types = __esm({
2015
+ "src/providers/types.ts"() {
2016
+ "use strict";
2017
+ REASONING_EFFORTS = ["none", "minimal", "low", "medium", "high", "xhigh"];
2018
+ __name(isReasoningEffort, "isReasoningEffort");
2019
+ __name(reasoningEffortLabel, "reasoningEffortLabel");
2020
+ __name(normalizeReasoningEfforts, "normalizeReasoningEfforts");
2021
+ __name(defaultReasoningEffort, "defaultReasoningEffort");
2022
+ __name(orderedReasoningEfforts, "orderedReasoningEfforts");
2023
+ }
2024
+ });
2025
+
1976
2026
  // src/providers/copilot.ts
1977
2027
  function normalizeCopilotEnterpriseDomain(value) {
1978
2028
  return value.replace(/^https?:\/\//, "").replace(/\/+$/, "");
@@ -2063,20 +2113,67 @@ function safeJsonParse(value) {
2063
2113
  return {};
2064
2114
  }
2065
2115
  }
2066
- function parseModels(body) {
2116
+ function valueAtPath(value, path3) {
2117
+ let current = value;
2118
+ for (const key of path3) {
2119
+ if (!current || typeof current !== "object" || Array.isArray(current)) return void 0;
2120
+ current = current[key];
2121
+ }
2122
+ return current;
2123
+ }
2124
+ function firstPositiveIntegerAtAny(value, paths2) {
2125
+ for (const path3 of paths2) {
2126
+ const candidate = valueAtPath(value, path3);
2127
+ if (typeof candidate !== "number" || !Number.isFinite(candidate) || candidate <= 0) continue;
2128
+ return Math.trunc(candidate);
2129
+ }
2130
+ return void 0;
2131
+ }
2132
+ function readCopilotContextWindow(capabilities) {
2133
+ return firstPositiveIntegerAtAny(capabilities, [
2134
+ ["limits", "max_context_window_tokens"],
2135
+ ["limits", "maxContextWindowTokens"],
2136
+ ["limits", "max_prompt_tokens"],
2137
+ ["max_context_window_tokens"],
2138
+ ["maxContextWindowTokens"],
2139
+ ["context_window"],
2140
+ ["contextWindow"]
2141
+ ]);
2142
+ }
2143
+ function readCopilotOutputTokens(capabilities) {
2144
+ return firstPositiveIntegerAtAny(capabilities, [
2145
+ ["limits", "max_output_tokens"],
2146
+ ["limits", "maxOutputTokens"],
2147
+ ["max_output_tokens"],
2148
+ ["maxOutputTokens"]
2149
+ ]);
2150
+ }
2151
+ function readCopilotReasoningEfforts(capabilities) {
2152
+ return normalizeReasoningEfforts(valueAtPath(capabilities, ["supports", "reasoning_effort"]));
2153
+ }
2154
+ function buildReasoning(effort, modelInfo) {
2155
+ const supported = modelInfo?.supportedReasoningEfforts?.map((option) => option.effort) ?? [];
2156
+ const selected = effort && supported.includes(effort) ? effort : void 0;
2157
+ const effective = selected ?? modelInfo?.defaultReasoningEffort;
2158
+ return effective ? { effort: effective } : void 0;
2159
+ }
2160
+ function parseCopilotModels(body) {
2067
2161
  const items = Array.isArray(body.data) ? body.data : [];
2068
2162
  const models = [];
2069
2163
  for (const item of items) {
2070
2164
  if (!item.id || item.model_picker_enabled === false || item.policy?.state === "disabled") continue;
2071
2165
  const visionMedia = item.capabilities?.limits?.vision?.supported_media_types ?? [];
2166
+ const supportedReasoning = readCopilotReasoningEfforts(item.capabilities);
2072
2167
  models.push({
2073
2168
  id: item.id,
2074
2169
  name: item.name,
2075
2170
  supportedEndpoints: item.supported_endpoints ?? [],
2076
2171
  supportsVision: item.capabilities?.supports?.vision === true || visionMedia.some((media) => media.startsWith("image/")),
2077
2172
  supportsToolCalls: item.capabilities?.supports?.tool_calls !== false,
2078
- contextWindow: item.capabilities?.limits?.max_context_window_tokens,
2079
- outputTokens: item.capabilities?.limits?.max_output_tokens
2173
+ contextWindow: readCopilotContextWindow(item.capabilities),
2174
+ outputTokens: readCopilotOutputTokens(item.capabilities),
2175
+ supportedReasoningEfforts: supportedReasoning.map((effort) => ({ effort, description: effort })),
2176
+ defaultReasoningEffort: defaultReasoningEffort(supportedReasoning)
2080
2177
  });
2081
2178
  }
2082
2179
  return models;
@@ -2086,6 +2183,7 @@ var init_copilot = __esm({
2086
2183
  "src/providers/copilot.ts"() {
2087
2184
  "use strict";
2088
2185
  init_provider_auth();
2186
+ init_types();
2089
2187
  COPILOT_PROVIDER = "github-copilot";
2090
2188
  USER_AGENT = "openjaw-agent/0.1.0";
2091
2189
  OPENAI_TOOL_NAME2 = /^[A-Za-z0-9_-]{1,64}$/;
@@ -2100,7 +2198,13 @@ var init_copilot = __esm({
2100
2198
  __name(hasImageContent, "hasImageContent");
2101
2199
  __name(openAIUserContent, "openAIUserContent");
2102
2200
  __name(safeJsonParse, "safeJsonParse");
2103
- __name(parseModels, "parseModels");
2201
+ __name(valueAtPath, "valueAtPath");
2202
+ __name(firstPositiveIntegerAtAny, "firstPositiveIntegerAtAny");
2203
+ __name(readCopilotContextWindow, "readCopilotContextWindow");
2204
+ __name(readCopilotOutputTokens, "readCopilotOutputTokens");
2205
+ __name(readCopilotReasoningEfforts, "readCopilotReasoningEfforts");
2206
+ __name(buildReasoning, "buildReasoning");
2207
+ __name(parseCopilotModels, "parseCopilotModels");
2104
2208
  CopilotProvider = class {
2105
2209
  static {
2106
2210
  __name(this, "CopilotProvider");
@@ -2113,7 +2217,14 @@ var init_copilot = __esm({
2113
2217
  }
2114
2218
  async listModels() {
2115
2219
  const models = await this.fetchModelInfo();
2116
- return models.map((model) => ({ id: model.id, name: model.name ?? model.id }));
2220
+ return models.map((model) => ({
2221
+ id: model.id,
2222
+ name: model.name ?? model.id,
2223
+ contextWindow: model.contextWindow,
2224
+ outputTokens: model.outputTokens,
2225
+ supportedReasoningEfforts: model.supportedReasoningEfforts,
2226
+ defaultReasoningEffort: model.defaultReasoningEffort
2227
+ }));
2117
2228
  }
2118
2229
  async chat(options) {
2119
2230
  const modelInfo = await this.resolveModelInfo(this.config.model);
@@ -2121,7 +2232,7 @@ var init_copilot = __esm({
2121
2232
  return this.chatAnthropicMessages(options);
2122
2233
  }
2123
2234
  if (this.shouldRouteToResponses(modelInfo)) {
2124
- return this.chatResponses(options);
2235
+ return this.chatResponses(options, modelInfo);
2125
2236
  }
2126
2237
  return this.chatCompletions(options);
2127
2238
  }
@@ -2178,7 +2289,7 @@ var init_copilot = __esm({
2178
2289
  throw new Error(`GitHub Copilot models error: ${res.status}${detail ? ` ${detail.slice(0, 160)}` : ""}`);
2179
2290
  }
2180
2291
  const parsed = await res.json();
2181
- const models = parseModels(parsed);
2292
+ const models = parseCopilotModels(parsed);
2182
2293
  this.modelCache = new Map(models.map((model) => [model.id, model]));
2183
2294
  return models;
2184
2295
  }
@@ -2294,12 +2405,14 @@ var init_copilot = __esm({
2294
2405
  }
2295
2406
  return input;
2296
2407
  }
2297
- async chatResponses(options) {
2408
+ async chatResponses(options, modelInfo) {
2409
+ const reasoning = buildReasoning(options.reasoningEffort, modelInfo);
2298
2410
  const requestBody = {
2299
2411
  model: this.config.model,
2300
2412
  input: this.buildResponsesInput(options),
2301
2413
  instructions: Array.isArray(options.systemPrompt) ? options.systemPrompt.map((block) => block.text).join("\n\n") : options.systemPrompt,
2302
- tools: options.tools.length > 0 ? options.tools.map(toResponsesTool) : void 0
2414
+ tools: options.tools.length > 0 ? options.tools.map(toResponsesTool) : void 0,
2415
+ ...reasoning && { reasoning, include: ["reasoning.encrypted_content"] }
2303
2416
  };
2304
2417
  const res = await fetch(`${this.baseUrl()}/responses`, {
2305
2418
  method: "POST",
@@ -2691,7 +2804,16 @@ var init_cost_tracker = __esm({
2691
2804
  });
2692
2805
 
2693
2806
  // src/context-manager.ts
2694
- function getContextWindow(model) {
2807
+ function contextKey(provider, model) {
2808
+ return `${provider}\0${model}`;
2809
+ }
2810
+ function normalizeContextWindow(value) {
2811
+ if (typeof value !== "number" || !Number.isFinite(value) || value <= 0) return void 0;
2812
+ return Math.trunc(value);
2813
+ }
2814
+ function getContextWindow(model, metadata) {
2815
+ const liveContextWindow = normalizeContextWindow(metadata?.contextWindow);
2816
+ if (liveContextWindow !== void 0) return liveContextWindow;
2695
2817
  if (CONTEXT_WINDOWS[model]) return CONTEXT_WINDOWS[model];
2696
2818
  for (const [key, size] of Object.entries(CONTEXT_WINDOWS)) {
2697
2819
  if (model.startsWith(key)) return size;
@@ -2716,12 +2838,45 @@ var init_context_manager = __esm({
2716
2838
  "gpt-4o": 128e3
2717
2839
  };
2718
2840
  DEFAULT_CONTEXT_WINDOW = 2e5;
2841
+ __name(contextKey, "contextKey");
2842
+ __name(normalizeContextWindow, "normalizeContextWindow");
2719
2843
  __name(getContextWindow, "getContextWindow");
2720
2844
  ContextManager = class {
2721
2845
  static {
2722
2846
  __name(this, "ContextManager");
2723
2847
  }
2724
2848
  lastTotalTokens = 0;
2849
+ activeProvider = null;
2850
+ liveModelContextWindows = /* @__PURE__ */ new Map();
2851
+ setActiveProvider(provider) {
2852
+ this.activeProvider = provider;
2853
+ }
2854
+ setProviderModelMetadata(provider, models) {
2855
+ const prefix = `${provider}\0`;
2856
+ for (const key of [...this.liveModelContextWindows.keys()]) {
2857
+ if (key.startsWith(prefix)) this.liveModelContextWindows.delete(key);
2858
+ }
2859
+ for (const model of models ?? []) {
2860
+ const contextWindow = normalizeContextWindow(model.contextWindow);
2861
+ if (contextWindow !== void 0) {
2862
+ this.liveModelContextWindows.set(contextKey(provider, model.id), contextWindow);
2863
+ }
2864
+ }
2865
+ }
2866
+ clearProviderModelMetadata(provider) {
2867
+ if (!provider) {
2868
+ this.liveModelContextWindows.clear();
2869
+ return;
2870
+ }
2871
+ const prefix = `${provider}\0`;
2872
+ for (const key of [...this.liveModelContextWindows.keys()]) {
2873
+ if (key.startsWith(prefix)) this.liveModelContextWindows.delete(key);
2874
+ }
2875
+ }
2876
+ getContextWindow(model) {
2877
+ const liveContextWindow = this.activeProvider ? this.liveModelContextWindows.get(contextKey(this.activeProvider, model)) : void 0;
2878
+ return getContextWindow(model, { contextWindow: liveContextWindow });
2879
+ }
2725
2880
  /** Update from actual API response usage */
2726
2881
  updateFromUsage(usage2) {
2727
2882
  this.lastTotalTokens = usage2.inputTokens + usage2.outputTokens + usage2.cacheReadTokens + usage2.cacheCreationTokens;
@@ -2733,7 +2888,7 @@ var init_context_manager = __esm({
2733
2888
  /** Get warning level based on model context window */
2734
2889
  getWarningLevel(model, newContentChars = 0) {
2735
2890
  const estimated = this.getEstimatedTokens(newContentChars);
2736
- const limit = getContextWindow(model);
2891
+ const limit = this.getContextWindow(model);
2737
2892
  const ratio = estimated / limit;
2738
2893
  if (ratio > 0.95) return "critical";
2739
2894
  if (ratio > 0.85) return "warning";
@@ -2741,12 +2896,12 @@ var init_context_manager = __esm({
2741
2896
  }
2742
2897
  /** Get context usage as percentage */
2743
2898
  getUsagePercent(model) {
2744
- const limit = getContextWindow(model);
2899
+ const limit = this.getContextWindow(model);
2745
2900
  return limit > 0 ? Math.round(this.lastTotalTokens / limit * 100) : 0;
2746
2901
  }
2747
2902
  /** Format context display string */
2748
2903
  formatContext(model) {
2749
- const limit = getContextWindow(model);
2904
+ const limit = this.getContextWindow(model);
2750
2905
  const fmt2 = /* @__PURE__ */ __name((n) => n >= 1e3 ? `${(n / 1e3).toFixed(0)}K` : String(n), "fmt");
2751
2906
  const pct = this.getUsagePercent(model);
2752
2907
  return `${fmt2(this.lastTotalTokens)}/${fmt2(limit)} (${pct}%)`;
@@ -3096,7 +3251,6 @@ var init_context_compressor = __esm({
3096
3251
  "src/context-compressor.ts"() {
3097
3252
  "use strict";
3098
3253
  init_providers();
3099
- init_context_manager();
3100
3254
  DEFAULT_COMPRESSION_THRESHOLD = 0.7;
3101
3255
  PROTECTED_HEAD = 3;
3102
3256
  PROTECTED_TAIL_TOKENS = 2e4;
@@ -3188,7 +3342,7 @@ Rules:
3188
3342
  shouldCompress(threshold) {
3189
3343
  const t = threshold ?? this.config.llm.compression_threshold ?? DEFAULT_COMPRESSION_THRESHOLD;
3190
3344
  const model = this.config.llm.model;
3191
- const limit = getContextWindow(model);
3345
+ const limit = this.contextManager.getContextWindow(model);
3192
3346
  const current = this.contextManager.getEstimatedTokens();
3193
3347
  const ratio = current / limit;
3194
3348
  if (ratio < t) return false;
@@ -3281,7 +3435,7 @@ ${summary}
3281
3435
  async _summarize(middle, _systemPrompt) {
3282
3436
  const auxProvider = this._getAuxProvider();
3283
3437
  const middleText = buildMiddleText(middle);
3284
- const contextWindow = getContextWindow(this.config.llm.model);
3438
+ const contextWindow = this.contextManager.getContextWindow(this.config.llm.model);
3285
3439
  const targetTokens = Math.max(
3286
3440
  SUMMARY_MIN_TOKENS,
3287
3441
  Math.min(SUMMARY_MAX_TOKENS, Math.floor(contextWindow * SUMMARY_PCT))
@@ -4129,6 +4283,7 @@ var init_agent_loop = __esm({
4129
4283
  cacheMonitor;
4130
4284
  telemetry;
4131
4285
  contextCompressor;
4286
+ liveModelMetadata = /* @__PURE__ */ new Map();
4132
4287
  _compactedOnResume = false;
4133
4288
  _toolRoundsInRun = 0;
4134
4289
  _skillSuggested = false;
@@ -4146,6 +4301,7 @@ var init_agent_loop = __esm({
4146
4301
  this.provider = createProvider(config);
4147
4302
  this.costTracker = new CostTracker();
4148
4303
  this.contextManager = new ContextManager();
4304
+ this.contextManager.setActiveProvider(config.llm.provider);
4149
4305
  this.cacheMonitor = new CacheMonitor();
4150
4306
  this.telemetry = new Telemetry("pending");
4151
4307
  if (resumeSessionId) {
@@ -4162,6 +4318,7 @@ var init_agent_loop = __esm({
4162
4318
  this.telemetry = new Telemetry(this.session.id);
4163
4319
  this.telemetry.recordSessionStart(config.llm.model, config.llm.provider);
4164
4320
  this.contextCompressor = new ContextCompressor(config, this.contextManager, this.telemetry);
4321
+ void this.refreshActiveModelMetadata();
4165
4322
  }
4166
4323
  get tools() {
4167
4324
  return this.toolRegistry;
@@ -4191,6 +4348,9 @@ var init_agent_loop = __esm({
4191
4348
  }
4192
4349
  return this.config.llm.provider;
4193
4350
  }
4351
+ get reasoningEffort() {
4352
+ return this.config.llm.model_reasoning_effort;
4353
+ }
4194
4354
  /**
4195
4355
  * Provide the user's response to an ask_user question.
4196
4356
  * Called by Chat.tsx or bridges when the user answers.
@@ -4208,7 +4368,7 @@ var init_agent_loop = __esm({
4208
4368
  return this._waitingForAskUserFlag;
4209
4369
  }
4210
4370
  /** Switch provider and/or model at runtime */
4211
- switchModel(provider, model) {
4371
+ switchModel(provider, model, reasoningEffort) {
4212
4372
  let baseUrl = this.config.llm.base_url;
4213
4373
  if (baseUrl) {
4214
4374
  if (provider === "openai" && baseUrl.includes("/api/anthropic")) {
@@ -4223,14 +4383,26 @@ var init_agent_loop = __esm({
4223
4383
  }
4224
4384
  this.config = {
4225
4385
  ...this.config,
4226
- llm: { ...this.config.llm, provider, model, base_url: baseUrl }
4386
+ llm: { ...this.config.llm, provider, model, base_url: baseUrl, model_reasoning_effort: reasoningEffort }
4227
4387
  };
4228
4388
  this.provider = createProvider(this.config);
4389
+ this.contextManager.setActiveProvider(provider);
4229
4390
  this._toolExposureState = createToolExposureState();
4230
4391
  this.session.provider = provider;
4231
4392
  this.session.model = model;
4232
4393
  saveSession(this.session);
4233
4394
  saveAgentConfig(this.config);
4395
+ void this.refreshActiveModelMetadata();
4396
+ }
4397
+ updateReasoningEffort(reasoningEffort) {
4398
+ this.config = {
4399
+ ...this.config,
4400
+ llm: { ...this.config.llm, model_reasoning_effort: reasoningEffort }
4401
+ };
4402
+ this.session.provider = this.config.llm.provider;
4403
+ this.session.model = this.config.llm.model;
4404
+ saveSession(this.session);
4405
+ saveAgentConfig(this.config);
4234
4406
  }
4235
4407
  /** Apply provider config changes that are not expressible as a model-only switch. */
4236
4408
  updateProviderConfig(updates) {
@@ -4239,15 +4411,53 @@ var init_agent_loop = __esm({
4239
4411
  llm: { ...this.config.llm, ...updates }
4240
4412
  };
4241
4413
  this.provider = createProvider(this.config);
4414
+ this.contextManager.setActiveProvider(this.config.llm.provider);
4242
4415
  this._toolExposureState = createToolExposureState();
4243
4416
  this.session.provider = this.config.llm.provider;
4244
4417
  this.session.model = this.config.llm.model;
4245
4418
  saveSession(this.session);
4246
4419
  saveAgentConfig(this.config);
4420
+ void this.refreshActiveModelMetadata();
4247
4421
  }
4248
4422
  /** List available models from the current provider's API */
4249
4423
  async listModels() {
4250
- return this.provider.listModels?.() ?? null;
4424
+ const models = await this.provider.listModels?.() ?? null;
4425
+ if (models) this.setProviderModelMetadata(this.config.llm.provider, models);
4426
+ return models;
4427
+ }
4428
+ setProviderModelMetadata(provider, models) {
4429
+ const prefix = `${provider}\0`;
4430
+ for (const key of [...this.liveModelMetadata.keys()]) {
4431
+ if (key.startsWith(prefix)) this.liveModelMetadata.delete(key);
4432
+ }
4433
+ for (const model of models ?? []) {
4434
+ this.liveModelMetadata.set(`${provider}\0${model.id}`, model);
4435
+ }
4436
+ this.contextManager.setProviderModelMetadata(provider, models);
4437
+ }
4438
+ getActiveModelMetadata(model = this.config.llm.model) {
4439
+ return this.getModelMetadata(this.config.llm.provider, model);
4440
+ }
4441
+ getModelMetadata(provider, model) {
4442
+ return this.liveModelMetadata.get(`${provider}\0${model}`);
4443
+ }
4444
+ async refreshActiveModelMetadata() {
4445
+ const providerName = this.config.llm.provider;
4446
+ const provider = this.provider;
4447
+ this.contextManager.setActiveProvider(providerName);
4448
+ if (providerName !== "github-copilot") return;
4449
+ try {
4450
+ const models = await provider.listModels?.() ?? null;
4451
+ if (models) {
4452
+ this.setProviderModelMetadata(providerName, models);
4453
+ } else {
4454
+ this.setProviderModelMetadata(providerName, null);
4455
+ this.contextManager.clearProviderModelMetadata(providerName);
4456
+ }
4457
+ } catch {
4458
+ this.setProviderModelMetadata(providerName, null);
4459
+ this.contextManager.clearProviderModelMetadata(providerName);
4460
+ }
4251
4461
  }
4252
4462
  async listAllModels() {
4253
4463
  const { STATIC_MODELS: STATIC_MODELS2 } = await Promise.resolve().then(() => (init_models_static(), models_static_exports));
@@ -4278,13 +4488,16 @@ var init_agent_loop = __esm({
4278
4488
  const seen = /* @__PURE__ */ new Set();
4279
4489
  if (live && live.length > 0) {
4280
4490
  sources[currentProvider] = { source: "live" };
4491
+ this.setProviderModelMetadata(currentProvider, live);
4281
4492
  for (const m of live) {
4282
4493
  if (seen.has(m.id)) continue;
4283
4494
  seen.add(m.id);
4284
- models.push({ provider: currentProvider, id: m.id, name: m.name, source: "live" });
4495
+ models.push({ provider: currentProvider, id: m.id, name: m.name, contextWindow: m.contextWindow, outputTokens: m.outputTokens, source: "live" });
4285
4496
  }
4286
4497
  } else {
4287
4498
  sources[currentProvider] = { source: "static", error: lastError };
4499
+ this.setProviderModelMetadata(currentProvider, null);
4500
+ this.contextManager.clearProviderModelMetadata(currentProvider);
4288
4501
  for (const m of STATIC_MODELS2[currentProvider]) {
4289
4502
  if (seen.has(m.id)) continue;
4290
4503
  seen.add(m.id);
@@ -4328,13 +4541,16 @@ var init_agent_loop = __esm({
4328
4541
  const seen = new Set(models.filter((m) => m.provider === provider && !m.group).map((m) => m.id));
4329
4542
  if (live && live.length > 0) {
4330
4543
  sources[provider] = { source: "live" };
4544
+ this.setProviderModelMetadata(provider, live);
4331
4545
  for (const m of live) {
4332
4546
  if (seen.has(m.id)) continue;
4333
4547
  seen.add(m.id);
4334
- models.push({ provider, id: m.id, name: m.name, source: "live" });
4548
+ models.push({ provider, id: m.id, name: m.name, contextWindow: m.contextWindow, outputTokens: m.outputTokens, source: "live" });
4335
4549
  }
4336
4550
  } else {
4337
4551
  sources[provider] = { source: "static", error: lastError };
4552
+ this.setProviderModelMetadata(provider, null);
4553
+ this.contextManager.clearProviderModelMetadata(provider);
4338
4554
  for (const m of STATIC_MODELS2[provider]) {
4339
4555
  if (seen.has(m.id)) continue;
4340
4556
  seen.add(m.id);
@@ -4592,6 +4808,7 @@ ${summary}
4592
4808
  messages,
4593
4809
  tools,
4594
4810
  signal,
4811
+ reasoningEffort: this.config.llm.model_reasoning_effort,
4595
4812
  debug: {
4596
4813
  toolMode: exposure.mode,
4597
4814
  fullToolCount: exposure.fullToolCount,
@@ -47628,6 +47845,12 @@ ${helpMessage}` : field.label;
47628
47845
  if (key === "mtime") {
47629
47846
  return { mtime: Date.now() };
47630
47847
  }
47848
+ if (key === "reasoning") {
47849
+ return {
47850
+ display: getUiState().showReasoning !== false ? "show" : "hide",
47851
+ value: agentLoop.reasoningEffort ?? "default"
47852
+ };
47853
+ }
47631
47854
  const ui = getUiState();
47632
47855
  return {
47633
47856
  config: {
@@ -47652,6 +47875,30 @@ ${helpMessage}` : field.label;
47652
47875
  if (typeof params?.key === "string") {
47653
47876
  const key = params.key;
47654
47877
  const rawValue = String(params.value ?? "").trim();
47878
+ if (key === "reasoning") {
47879
+ if (!rawValue) {
47880
+ return {
47881
+ display: getUiState().showReasoning !== false ? "show" : "hide",
47882
+ value: agentLoop.reasoningEffort ?? "default"
47883
+ };
47884
+ }
47885
+ if (rawValue === "hide" || rawValue === "show") {
47886
+ return { value: rawValue };
47887
+ }
47888
+ const parsed = parseReasoningEffortInput(rawValue);
47889
+ const modelInfo = agentLoop.getActiveModelMetadata();
47890
+ const nextEffort = parsed.clear ? void 0 : modelInfo ? resolveReasoningEffortForModel(modelInfo, parsed.effort) : parsed.effort;
47891
+ agentLoop.updateReasoningEffort(nextEffort);
47892
+ bus.emitEvent({
47893
+ payload: sessionInfoSnapshot(agentLoop, toolRegistry),
47894
+ session_id: agentLoop.sessionId,
47895
+ type: "session.info"
47896
+ });
47897
+ return {
47898
+ info: sessionInfoSnapshot(agentLoop, toolRegistry),
47899
+ value: nextEffort ?? "default"
47900
+ };
47901
+ }
47655
47902
  if (key === "model") {
47656
47903
  if (!rawValue) {
47657
47904
  return { value: agentLoop.model };
@@ -47665,6 +47912,15 @@ ${helpMessage}` : field.label;
47665
47912
  provider = flagsStripped[provIdx + 1];
47666
47913
  flagsStripped.splice(provIdx, 2);
47667
47914
  }
47915
+ let requestedReasoningEffort;
47916
+ let clearReasoningEffort = false;
47917
+ const effortIdx = flagsStripped.findIndex((t) => t === "--reasoning-effort" || t === "--effort");
47918
+ if (effortIdx >= 0) {
47919
+ const parsed = parseReasoningEffortInput(flagsStripped[effortIdx + 1] ?? "");
47920
+ requestedReasoningEffort = parsed.effort;
47921
+ clearReasoningEffort = parsed.clear;
47922
+ flagsStripped.splice(effortIdx, flagsStripped[effortIdx + 1] ? 2 : 1);
47923
+ }
47668
47924
  const model = flagsStripped.join(" ").trim();
47669
47925
  if (!model) {
47670
47926
  throw new Error("config.set model: missing model id");
@@ -47673,15 +47929,17 @@ ${helpMessage}` : field.label;
47673
47929
  throw new Error(`config.set model: unknown provider "${provider}"`);
47674
47930
  }
47675
47931
  const credential_warning = isProviderAuthenticated(provider) ? void 0 : `${PROVIDER_LABELS[provider]} is not connected \u2014 run /connect to add credentials`;
47932
+ const modelInfo = agentLoop.getModelMetadata(provider, model);
47933
+ const reasoningEffort = clearReasoningEffort ? void 0 : requestedReasoningEffort ? modelInfo ? resolveReasoningEffortForModel(modelInfo, requestedReasoningEffort) : requestedReasoningEffort : modelInfo ? resolveReasoningEffortForModel(modelInfo, agentLoop.reasoningEffort) : agentLoop.reasoningEffort;
47676
47934
  try {
47677
- agentLoop.switchModel(provider, model);
47935
+ agentLoop.switchModel(provider, model, reasoningEffort);
47678
47936
  } catch (err) {
47679
47937
  throw new Error(err instanceof Error ? err.message : String(err));
47680
47938
  }
47681
47939
  if (persistGlobal) {
47682
47940
  const next = {
47683
47941
  ...agentConfig,
47684
- llm: { ...agentConfig.llm, model, provider }
47942
+ llm: { ...agentConfig.llm, model, provider, model_reasoning_effort: reasoningEffort }
47685
47943
  };
47686
47944
  try {
47687
47945
  saveAgentConfig(next);
@@ -47698,6 +47956,7 @@ ${helpMessage}` : field.label;
47698
47956
  return {
47699
47957
  credential_warning,
47700
47958
  info: sessionInfoSnapshot(agentLoop, toolRegistry),
47959
+ reasoning_effort: reasoningEffort,
47701
47960
  value: model
47702
47961
  };
47703
47962
  }
@@ -47952,7 +48211,11 @@ ${helpMessage}` : field.label;
47952
48211
  bus.registerRpc("model.switch", (params) => {
47953
48212
  const provider = String(params.provider ?? agentLoop.providerName);
47954
48213
  const model = String(params.model ?? agentLoop.model);
47955
- agentLoop.switchModel(provider, model);
48214
+ const rawEffort = typeof params.reasoning_effort === "string" ? params.reasoning_effort : typeof params.effort === "string" ? params.effort : "";
48215
+ const parsedEffort = rawEffort ? parseReasoningEffortInput(rawEffort) : void 0;
48216
+ const modelInfo = agentLoop.getModelMetadata(provider, model);
48217
+ const reasoningEffort = parsedEffort?.clear ? void 0 : parsedEffort?.effort ? modelInfo ? resolveReasoningEffortForModel(modelInfo, parsedEffort.effort) : parsedEffort.effort : modelInfo ? resolveReasoningEffortForModel(modelInfo, agentLoop.reasoningEffort) : agentLoop.reasoningEffort;
48218
+ agentLoop.switchModel(provider, model, reasoningEffort);
47956
48219
  return {
47957
48220
  info: sessionInfoSnapshot(agentLoop, toolRegistry),
47958
48221
  ok: true
@@ -47964,12 +48227,20 @@ ${helpMessage}` : field.label;
47964
48227
  const liveResults = await Promise.all(
47965
48228
  PROVIDERS2.map((slug) => fetchLiveModels(slug, agentConfig, currentModel))
47966
48229
  );
48230
+ for (let i = 0; i < PROVIDERS2.length; i++) {
48231
+ const provider = PROVIDERS2[i];
48232
+ const models = liveResults[i]?.models;
48233
+ if (provider && models) {
48234
+ agentLoop.setProviderModelMetadata(provider, models);
48235
+ }
48236
+ }
47967
48237
  const providers = PROVIDERS2.map(
47968
48238
  (slug, i) => buildProviderOption(slug, currentProvider, currentModel, liveResults[i]?.models, liveResults[i]?.error)
47969
48239
  );
47970
48240
  return {
47971
48241
  model: currentModel,
47972
48242
  provider: currentProvider,
48243
+ reasoning_effort: agentLoop.reasoningEffort,
47973
48244
  providers
47974
48245
  };
47975
48246
  });
@@ -48714,14 +48985,13 @@ ${helpMessage}` : field.label;
48714
48985
  }
48715
48986
  };
48716
48987
  }
48717
- var PROVIDERS2, PROVIDER_LABELS, PROVIDER_AUTH, isProviderAuthenticated, buildProviderOption, fetchLiveModels, BRIDGE_SOURCES, isBridgeSource, inferBridgeSource, bridgeLabels, bridgeEventLabels, stripBridgeGlyph, firstLogLine, bridgeUser, formatBridgeText, runProcess, contentToText, sessionMessageToMarkdown, usageSnapshot, sessionInfoSnapshot, MCP_TOOL_PREFIX, MAX_TOTAL_TOOLS, syncMcpTools;
48988
+ var PROVIDERS2, PROVIDER_LABELS, PROVIDER_AUTH, isProviderAuthenticated, buildProviderOption, fetchLiveModels, parseReasoningEffortInput, reasoningEffortsForModel, resolveReasoningEffortForModel, BRIDGE_SOURCES, isBridgeSource, inferBridgeSource, bridgeLabels, bridgeEventLabels, stripBridgeGlyph, firstLogLine, bridgeUser, formatBridgeText, runProcess, contentToText, sessionMessageToMarkdown, usageSnapshot, sessionInfoSnapshot, MCP_TOOL_PREFIX, MAX_TOTAL_TOOLS, syncMcpTools;
48718
48989
  var init_rpcHandlers = __esm({
48719
48990
  "src/rpcHandlers.ts"() {
48720
48991
  "use strict";
48721
48992
  init_connect();
48722
48993
  init_config();
48723
48994
  init_copilot_auth();
48724
- init_context_manager();
48725
48995
  init_eventBridge();
48726
48996
  init_fork();
48727
48997
  init_provider_auth();
@@ -48733,6 +49003,7 @@ var init_rpcHandlers = __esm({
48733
49003
  init_clipboard();
48734
49004
  init_models_static();
48735
49005
  init_providers();
49006
+ init_types();
48736
49007
  init_registry3();
48737
49008
  PROVIDERS2 = ["anthropic", "openai", "github-copilot"];
48738
49009
  PROVIDER_LABELS = {
@@ -48757,6 +49028,7 @@ var init_rpcHandlers = __esm({
48757
49028
  const auth = PROVIDER_AUTH[slug];
48758
49029
  const authenticated = isProviderAuthenticated(slug);
48759
49030
  let models = [];
49031
+ let modelOptions = [];
48760
49032
  let source = "static";
48761
49033
  if (authenticated) {
48762
49034
  if (liveModels && liveModels.length > 0) {
@@ -48765,10 +49037,12 @@ var init_rpcHandlers = __esm({
48765
49037
  if (seen.has(m.id)) continue;
48766
49038
  seen.add(m.id);
48767
49039
  models.push(m.id);
49040
+ modelOptions.push(m);
48768
49041
  }
48769
49042
  source = "live";
48770
49043
  } else {
48771
49044
  models = STATIC_MODELS[slug].map((m) => m.id);
49045
+ modelOptions = STATIC_MODELS[slug].map((m) => ({ id: m.id, name: m.name }));
48772
49046
  source = "static";
48773
49047
  }
48774
49048
  }
@@ -48784,6 +49058,7 @@ var init_rpcHandlers = __esm({
48784
49058
  is_current: slug === currentProvider,
48785
49059
  key_env: auth.key_env,
48786
49060
  models,
49061
+ model_options: modelOptions,
48787
49062
  name: PROVIDER_LABELS[slug],
48788
49063
  slug,
48789
49064
  source,
@@ -48819,6 +49094,22 @@ var init_rpcHandlers = __esm({
48819
49094
  return { error: err instanceof Error ? err.message : String(err), models: null };
48820
49095
  }
48821
49096
  }, "fetchLiveModels");
49097
+ parseReasoningEffortInput = /* @__PURE__ */ __name((value) => {
49098
+ const normalized = value.trim().toLowerCase();
49099
+ if (!normalized || normalized === "default" || normalized === "clear" || normalized === "auto") {
49100
+ return { clear: true };
49101
+ }
49102
+ if (!isReasoningEffort(normalized)) {
49103
+ throw new Error(`unknown reasoning effort: ${value}`);
49104
+ }
49105
+ return { clear: false, effort: normalized };
49106
+ }, "parseReasoningEffortInput");
49107
+ reasoningEffortsForModel = /* @__PURE__ */ __name((model) => model?.supportedReasoningEfforts?.map((option) => option.effort) ?? [], "reasoningEffortsForModel");
49108
+ resolveReasoningEffortForModel = /* @__PURE__ */ __name((model, requested) => {
49109
+ const supported = reasoningEffortsForModel(model);
49110
+ const selected = requested && supported.includes(requested) ? requested : void 0;
49111
+ return selected ?? model?.defaultReasoningEffort ?? defaultReasoningEffort(supported);
49112
+ }, "resolveReasoningEffortForModel");
48822
49113
  BRIDGE_SOURCES = ["telegram", "teams", "feishu", "wechat"];
48823
49114
  isBridgeSource = /* @__PURE__ */ __name((value) => typeof value === "string" && BRIDGE_SOURCES.includes(value), "isBridgeSource");
48824
49115
  inferBridgeSource = /* @__PURE__ */ __name((event) => {
@@ -48918,7 +49209,7 @@ ${raw}`;
48918
49209
  }, "sessionMessageToMarkdown");
48919
49210
  usageSnapshot = /* @__PURE__ */ __name((agentLoop) => {
48920
49211
  const cost = agentLoop.costTracker.getSessionCost();
48921
- const contextMax = getContextWindow(agentLoop.model);
49212
+ const contextMax = agentLoop.contextManager.getContextWindow(agentLoop.model);
48922
49213
  const contextUsed = agentLoop.contextManager.lastPromptTokens;
48923
49214
  return {
48924
49215
  cache_read: cost.totalCacheReadTokens,
@@ -48938,6 +49229,7 @@ ${raw}`;
48938
49229
  sessionInfoSnapshot = /* @__PURE__ */ __name((agentLoop, toolRegistry) => ({
48939
49230
  cwd: process.cwd(),
48940
49231
  model: agentLoop.model,
49232
+ reasoning_effort: agentLoop.reasoningEffort,
48941
49233
  skills: {},
48942
49234
  system_prompt: "",
48943
49235
  tools: { [agentLoop.providerName]: toolRegistry.listTools().map((t) => t.name) },
@@ -56602,12 +56894,15 @@ import { Fragment as Fragment5, jsx as jsx25, jsxs as jsxs13 } from "react/jsx-r
56602
56894
  function ModelPicker2({ gw, mode = "switch", onCancel, onSelect, sessionId, t }) {
56603
56895
  const [providers, setProviders] = useState19([]);
56604
56896
  const [currentModel, setCurrentModel] = useState19("");
56897
+ const [currentReasoningEffort, setCurrentReasoningEffort] = useState19();
56605
56898
  const [err, setErr] = useState19("");
56606
56899
  const [loading, setLoading] = useState19(true);
56607
56900
  const [persistGlobal, setPersistGlobal] = useState19(false);
56608
56901
  const [providerIdx, setProviderIdx] = useState19(0);
56609
56902
  const [modelIdx, setModelIdx] = useState19(0);
56903
+ const [effortIdx, setEffortIdx] = useState19(0);
56610
56904
  const [stage, setStage] = useState19("provider");
56905
+ const [selectedModelForEffort, setSelectedModelForEffort] = useState19(null);
56611
56906
  const [keyInput, setKeyInput] = useState19("");
56612
56907
  const [keySaving, setKeySaving] = useState19(false);
56613
56908
  const [keyError, setKeyError] = useState19("");
@@ -56633,6 +56928,7 @@ function ModelPicker2({ gw, mode = "switch", onCancel, onSelect, sessionId, t })
56633
56928
  const next = r.providers ?? [];
56634
56929
  setProviders(next);
56635
56930
  setCurrentModel(String(r.model ?? ""));
56931
+ setCurrentReasoningEffort(r.reasoning_effort);
56636
56932
  setProviderIdx(
56637
56933
  Math.max(
56638
56934
  0,
@@ -56640,6 +56936,8 @@ function ModelPicker2({ gw, mode = "switch", onCancel, onSelect, sessionId, t })
56640
56936
  )
56641
56937
  );
56642
56938
  setModelIdx(0);
56939
+ setEffortIdx(0);
56940
+ setSelectedModelForEffort(null);
56643
56941
  setStage("provider");
56644
56942
  setErr("");
56645
56943
  setLoading(false);
@@ -56650,8 +56948,34 @@ function ModelPicker2({ gw, mode = "switch", onCancel, onSelect, sessionId, t })
56650
56948
  });
56651
56949
  }, [gw, sessionId]);
56652
56950
  const provider = providers[providerIdx];
56653
- const models = provider?.models ?? [];
56951
+ const modelOptions = useMemo12(() => {
56952
+ if (!provider) return [];
56953
+ if (provider.model_options?.length) return provider.model_options;
56954
+ return (provider.models ?? []).map((id) => ({ id }));
56955
+ }, [provider]);
56956
+ const models = useMemo12(() => modelOptions.map((model) => model.id), [modelOptions]);
56957
+ const effortChoices = useMemo12(() => modelReasoningEfforts(selectedModelForEffort), [selectedModelForEffort]);
56958
+ const providerHasReasoningStage = modelOptions.some((model) => modelReasoningEfforts(model).length > 1);
56654
56959
  const names = useMemo12(() => providerDisplayNames(providers), [providers]);
56960
+ const selectionScopeFlag = /* @__PURE__ */ __name(() => persistGlobal ? " --global" : ` ${TUI_SESSION_MODEL_FLAG}`, "selectionScopeFlag");
56961
+ const selectModel = /* @__PURE__ */ __name((model, effort) => {
56962
+ if (!provider) return;
56963
+ onSelect(`${model.id} --provider ${provider.slug} --reasoning-effort ${effort}${selectionScopeFlag()}`);
56964
+ }, "selectModel");
56965
+ const chooseModel = /* @__PURE__ */ __name((model) => {
56966
+ if (!model) {
56967
+ setStage("provider");
56968
+ return;
56969
+ }
56970
+ const efforts = modelReasoningEfforts(model);
56971
+ if (efforts.length > 1) {
56972
+ setSelectedModelForEffort(model);
56973
+ setEffortIdx(initialEffortIndex(efforts, currentReasoningEffort, defaultReasoningForModel(model, efforts)));
56974
+ setStage("effort");
56975
+ return;
56976
+ }
56977
+ selectModel(model, efforts[0] ?? "default");
56978
+ }, "chooseModel");
56655
56979
  useEffect17(() => {
56656
56980
  mountedRef.current = true;
56657
56981
  return () => {
@@ -56672,6 +56996,7 @@ function ModelPicker2({ gw, mode = "switch", onCancel, onSelect, sessionId, t })
56672
56996
  }
56673
56997
  setProviders(r.providers ?? []);
56674
56998
  setCurrentModel(String(r.model ?? ""));
56999
+ setCurrentReasoningEffort(r.reasoning_effort);
56675
57000
  }).catch(() => {
56676
57001
  }), "refreshProviders");
56677
57002
  const cancelActiveOAuth = /* @__PURE__ */ __name(() => {
@@ -56767,9 +57092,17 @@ function ModelPicker2({ gw, mode = "switch", onCancel, onSelect, sessionId, t })
56767
57092
  setOauthError("");
56768
57093
  return;
56769
57094
  }
57095
+ if (stage === "effort") {
57096
+ setStage("model");
57097
+ setEffortIdx(0);
57098
+ setSelectedModelForEffort(null);
57099
+ return;
57100
+ }
56770
57101
  if (stage === "model" || stage === "key" || stage === "disconnect") {
56771
57102
  setStage("provider");
56772
57103
  setModelIdx(0);
57104
+ setEffortIdx(0);
57105
+ setSelectedModelForEffort(null);
56773
57106
  setKeyInput("");
56774
57107
  setKeyError("");
56775
57108
  setKeySaving(false);
@@ -56867,7 +57200,7 @@ function ModelPicker2({ gw, mode = "switch", onCancel, onSelect, sessionId, t })
56867
57200
  if (r?.disconnected) {
56868
57201
  setProviders(
56869
57202
  (prev) => prev.map(
56870
- (p) => p.slug === provider.slug ? { ...p, authenticated: false, models: [], total_models: 0, warning: p.key_env ? `paste ${p.key_env} to activate` : "run `hermes model` to configure" } : p
57203
+ (p) => p.slug === provider.slug ? { ...p, authenticated: false, models: [], model_options: [], total_models: 0, warning: p.key_env ? `paste ${p.key_env} to activate` : "run `hermes model` to configure" } : p
56871
57204
  )
56872
57205
  );
56873
57206
  }
@@ -56885,9 +57218,9 @@ function ModelPicker2({ gw, mode = "switch", onCancel, onSelect, sessionId, t })
56885
57218
  }
56886
57219
  return;
56887
57220
  }
56888
- const count = stage === "provider" ? providers.length : models.length;
56889
- const sel = stage === "provider" ? providerIdx : modelIdx;
56890
- const setSel = stage === "provider" ? setProviderIdx : setModelIdx;
57221
+ const count = stage === "provider" ? providers.length : stage === "effort" ? effortChoices.length : models.length;
57222
+ const sel = stage === "provider" ? providerIdx : stage === "effort" ? effortIdx : modelIdx;
57223
+ const setSel = stage === "provider" ? setProviderIdx : stage === "effort" ? setEffortIdx : setModelIdx;
56891
57224
  if (key.upArrow && sel > 0) {
56892
57225
  setSel((v) => v - 1);
56893
57226
  return;
@@ -56922,12 +57255,16 @@ function ModelPicker2({ gw, mode = "switch", onCancel, onSelect, sessionId, t })
56922
57255
  setModelIdx(0);
56923
57256
  return;
56924
57257
  }
56925
- const model = models[modelIdx];
56926
- if (provider && model) {
56927
- onSelect(`${model} --provider ${provider.slug}${persistGlobal ? " --global" : ` ${TUI_SESSION_MODEL_FLAG}`}`);
56928
- } else {
56929
- setStage("provider");
57258
+ if (stage === "effort") {
57259
+ const effort = effortChoices[effortIdx];
57260
+ if (selectedModelForEffort && effort) {
57261
+ selectModel(selectedModelForEffort, effort);
57262
+ } else {
57263
+ setStage("model");
57264
+ }
57265
+ return;
56930
57266
  }
57267
+ chooseModel(modelOptions[modelIdx]);
56931
57268
  return;
56932
57269
  }
56933
57270
  if (ch.toLowerCase() === "g") {
@@ -57090,7 +57427,11 @@ function ModelPicker2({ gw, mode = "switch", onCancel, onSelect, sessionId, t })
57090
57427
  );
57091
57428
  const { items: items2, offset: offset2 } = windowItems(rows, providerIdx, VISIBLE2);
57092
57429
  return /* @__PURE__ */ jsxs13(Box_default, { flexDirection: "column", width, children: [
57093
- /* @__PURE__ */ jsx25(Text9, { bold: true, color: t.color.accent, wrap: "truncate-end", children: "Select provider (step 1/2)" }),
57430
+ /* @__PURE__ */ jsxs13(Text9, { bold: true, color: t.color.accent, wrap: "truncate-end", children: [
57431
+ "Select provider (step 1/",
57432
+ providerHasReasoningStage ? "3" : "2",
57433
+ ")"
57434
+ ] }),
57094
57435
  /* @__PURE__ */ jsx25(Text9, { color: t.color.muted, wrap: "truncate-end", children: "Full model IDs on the next step \xB7 Enter to continue" }),
57095
57436
  /* @__PURE__ */ jsxs13(Text9, { color: t.color.muted, wrap: "truncate-end", children: [
57096
57437
  "Current: ",
@@ -57129,9 +57470,61 @@ function ModelPicker2({ gw, mode = "switch", onCancel, onSelect, sessionId, t })
57129
57470
  /* @__PURE__ */ jsx25(OverlayHint, { t, children: "\u2191/\u2193 select \xB7 Enter choose \xB7 d disconnect \xB7 Esc/q cancel" })
57130
57471
  ] });
57131
57472
  }
57473
+ if (stage === "effort") {
57474
+ const defaultEffort = defaultReasoningForModel(selectedModelForEffort, effortChoices);
57475
+ const warningEffort = effortChoices.includes("xhigh") ? "xhigh" : effortChoices.includes("high") ? "high" : void 0;
57476
+ const warningText = warningEffort ? `\u26A0 ${reasoningEffortLabel(warningEffort)} reasoning can quickly consume rate limits.` : " ";
57477
+ const { items: items2, offset: offset2 } = windowItems(effortChoices, effortIdx, VISIBLE2);
57478
+ return /* @__PURE__ */ jsxs13(Box_default, { flexDirection: "column", width, children: [
57479
+ /* @__PURE__ */ jsx25(Text9, { bold: true, color: t.color.accent, wrap: "truncate-end", children: "Select reasoning level (step 3/3)" }),
57480
+ /* @__PURE__ */ jsxs13(Text9, { color: t.color.muted, wrap: "truncate-end", children: [
57481
+ modelOptionID(selectedModelForEffort ?? void 0) || "(unknown model)",
57482
+ " \xB7 Esc back"
57483
+ ] }),
57484
+ /* @__PURE__ */ jsx25(Text9, { color: t.color.label, wrap: "truncate-end", children: warningText }),
57485
+ /* @__PURE__ */ jsx25(Text9, { color: t.color.muted, wrap: "truncate-end", children: offset2 > 0 ? ` \u2191 ${offset2} more` : " " }),
57486
+ Array.from({ length: VISIBLE2 }, (_, i) => {
57487
+ const effort = items2[i];
57488
+ const idx = offset2 + i;
57489
+ if (!effort) {
57490
+ return !effortChoices.length && i === 0 ? /* @__PURE__ */ jsx25(Text9, { color: t.color.muted, wrap: "truncate-end", children: "no reasoning levels listed for this model" }, "empty-effort") : /* @__PURE__ */ jsx25(Text9, { color: t.color.muted, wrap: "truncate-end", children: " " }, `pad-effort-${i}`);
57491
+ }
57492
+ const option = selectedModelForEffort?.supportedReasoningEfforts?.find((o) => o.effort === effort);
57493
+ const description = option?.description && option.description !== effort ? ` \xB7 ${option.description}` : "";
57494
+ const label = `${reasoningEffortLabel(effort)}${effort === defaultEffort ? " (default)" : ""}${description}`;
57495
+ return /* @__PURE__ */ jsxs13(
57496
+ Text9,
57497
+ {
57498
+ bold: effortIdx === idx,
57499
+ color: effortIdx === idx ? t.color.accent : t.color.muted,
57500
+ inverse: effortIdx === idx,
57501
+ wrap: "truncate-end",
57502
+ children: [
57503
+ effortIdx === idx ? "\u25B8 " : currentReasoningEffort === effort ? "* " : " ",
57504
+ idx + 1,
57505
+ ". ",
57506
+ label
57507
+ ]
57508
+ },
57509
+ `${modelOptionID(selectedModelForEffort ?? void 0)}:${effort}`
57510
+ );
57511
+ }),
57512
+ /* @__PURE__ */ jsx25(Text9, { color: t.color.muted, wrap: "truncate-end", children: offset2 + VISIBLE2 < effortChoices.length ? ` \u2193 ${effortChoices.length - offset2 - VISIBLE2} more` : " " }),
57513
+ /* @__PURE__ */ jsxs13(Text9, { color: t.color.muted, wrap: "truncate-end", children: [
57514
+ "persist: ",
57515
+ persistGlobal ? "global" : "session",
57516
+ " \xB7 g toggle"
57517
+ ] }),
57518
+ /* @__PURE__ */ jsx25(OverlayHint, { t, children: "\u2191/\u2193 select \xB7 Enter switch \xB7 Esc back \xB7 q close" })
57519
+ ] });
57520
+ }
57132
57521
  const { items, offset } = windowItems(models, modelIdx, VISIBLE2);
57133
57522
  return /* @__PURE__ */ jsxs13(Box_default, { flexDirection: "column", width, children: [
57134
- /* @__PURE__ */ jsx25(Text9, { bold: true, color: t.color.accent, wrap: "truncate-end", children: "Select model (step 2/2)" }),
57523
+ /* @__PURE__ */ jsxs13(Text9, { bold: true, color: t.color.accent, wrap: "truncate-end", children: [
57524
+ "Select model (step 2/",
57525
+ providerHasReasoningStage ? "3" : "2",
57526
+ ")"
57527
+ ] }),
57135
57528
  /* @__PURE__ */ jsxs13(Text9, { color: t.color.muted, wrap: "truncate-end", children: [
57136
57529
  names[providerIdx] || "(unknown provider)",
57137
57530
  " \xB7 Esc back"
@@ -57171,7 +57564,7 @@ function ModelPicker2({ gw, mode = "switch", onCancel, onSelect, sessionId, t })
57171
57564
  /* @__PURE__ */ jsx25(OverlayHint, { t, children: models.length ? "\u2191/\u2193 select \xB7 Enter switch \xB7 Esc back \xB7 q close" : "Enter/Esc back \xB7 q close" })
57172
57565
  ] });
57173
57566
  }
57174
- var VISIBLE2, MIN_WIDTH2, MAX_WIDTH2;
57567
+ var VISIBLE2, MIN_WIDTH2, MAX_WIDTH2, modelOptionID, modelReasoningEfforts, defaultReasoningForModel, initialEffortIndex;
57175
57568
  var init_modelPicker = __esm({
57176
57569
  "src/components/modelPicker.tsx"() {
57177
57570
  "use strict";
@@ -57179,10 +57572,28 @@ var init_modelPicker = __esm({
57179
57572
  init_providers2();
57180
57573
  init_slash();
57181
57574
  init_rpc();
57575
+ init_types();
57182
57576
  init_overlayControls();
57183
57577
  VISIBLE2 = 12;
57184
57578
  MIN_WIDTH2 = 40;
57185
57579
  MAX_WIDTH2 = 90;
57580
+ modelOptionID = /* @__PURE__ */ __name((model) => model?.id ?? "", "modelOptionID");
57581
+ modelReasoningEfforts = /* @__PURE__ */ __name((model) => {
57582
+ const efforts = model?.supportedReasoningEfforts?.map((option) => option.effort) ?? [];
57583
+ return orderedReasoningEfforts(efforts);
57584
+ }, "modelReasoningEfforts");
57585
+ defaultReasoningForModel = /* @__PURE__ */ __name((model, efforts = modelReasoningEfforts(model)) => {
57586
+ const configured = model?.defaultReasoningEffort;
57587
+ if (configured && efforts.includes(configured)) {
57588
+ return configured;
57589
+ }
57590
+ return efforts[0];
57591
+ }, "defaultReasoningForModel");
57592
+ initialEffortIndex = /* @__PURE__ */ __name((efforts, current, fallback) => {
57593
+ const selected = current && efforts.includes(current) ? current : fallback;
57594
+ const idx = selected ? efforts.indexOf(selected) : -1;
57595
+ return idx >= 0 ? idx : 0;
57596
+ }, "initialEffortIndex");
57186
57597
  __name(ModelPicker2, "ModelPicker");
57187
57598
  }
57188
57599
  });