topchester-ai 0.56.0 → 0.57.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/bin.mjs CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { t as runTopchesterCli } from "./cli-AJknxj59.mjs";
2
+ import { t as runTopchesterCli } from "./cli-kvaa3acN.mjs";
3
3
  //#region src/bin.ts
4
4
  await runTopchesterCli();
5
5
  //#endregion
@@ -5335,7 +5335,7 @@ function createCodexProviderFetch(options = {}) {
5335
5335
  const providerId = options.providerId ?? "codex";
5336
5336
  const upstreamFetch = options.fetch ?? fetch;
5337
5337
  return (async (input, init) => {
5338
- const request = await rewriteCodexRequest(input, init);
5338
+ const request = await rewriteCodexRequest(input, init, options.reasoningEffort);
5339
5339
  const auth = await resolveCodexAuth({
5340
5340
  ...options,
5341
5341
  providerId,
@@ -5364,7 +5364,7 @@ function rewriteCodexRequestUrl(input) {
5364
5364
  }
5365
5365
  return input;
5366
5366
  }
5367
- async function rewriteCodexRequest(input, init) {
5367
+ async function rewriteCodexRequest(input, init, reasoningEffort) {
5368
5368
  const rewrittenUrl = rewriteCodexRequestUrl(input);
5369
5369
  const body = await readJsonBody(init?.body);
5370
5370
  if (!isChatCompletionsBody(body)) return {
@@ -5372,7 +5372,7 @@ async function rewriteCodexRequest(input, init) {
5372
5372
  ...init ? { init } : {}
5373
5373
  };
5374
5374
  const stream = body.stream === true;
5375
- const codexBody = chatCompletionsBodyToCodexResponsesBody(body);
5375
+ const codexBody = chatCompletionsBodyToCodexResponsesBody(body, reasoningEffort);
5376
5376
  const headers = new Headers(init?.headers);
5377
5377
  headers.set("Content-Type", "application/json");
5378
5378
  return {
@@ -5385,7 +5385,7 @@ async function rewriteCodexRequest(input, init) {
5385
5385
  responseMode: stream ? "chat-sse" : "chat-json"
5386
5386
  };
5387
5387
  }
5388
- function chatCompletionsBodyToCodexResponsesBody(body) {
5388
+ function chatCompletionsBodyToCodexResponsesBody(body, reasoningEffort) {
5389
5389
  const instructions = body.messages.filter((message) => message.role === "system" || message.role === "developer").map((message) => messageContentToText(message.content)).filter((text) => text.trim().length > 0).join("\n\n");
5390
5390
  const input = body.messages.filter((message) => message.role !== "system" && message.role !== "developer").map(chatMessageToResponseInputItem).filter((item) => item !== void 0);
5391
5391
  return {
@@ -5396,7 +5396,11 @@ function chatCompletionsBodyToCodexResponsesBody(body) {
5396
5396
  stream: true,
5397
5397
  ...typeof body.temperature === "number" ? { temperature: body.temperature } : {},
5398
5398
  ...typeof body.top_p === "number" ? { top_p: body.top_p } : {},
5399
- ...typeof body.max_tokens === "number" ? { max_output_tokens: body.max_tokens } : {}
5399
+ ...typeof body.max_tokens === "number" ? { max_output_tokens: body.max_tokens } : {},
5400
+ ...reasoningEffort === void 0 ? {} : { reasoning: {
5401
+ effort: reasoningEffort,
5402
+ summary: "auto"
5403
+ } }
5400
5404
  };
5401
5405
  }
5402
5406
  function chatMessageToResponseInputItem(message) {
@@ -5633,7 +5637,8 @@ var ModelGateway = class ModelGateway {
5633
5637
  if (!providerConfig) throw new Error(`No provider configured for model provider "${providerId}".`);
5634
5638
  const providerFetch = isCodexProvider(providerId, providerConfig) ? createCodexProviderFetch({
5635
5639
  ...this.#config.codexAuth,
5636
- providerId
5640
+ providerId,
5641
+ reasoningEffort: providerConfig.reasoningEffort
5637
5642
  }) : void 0;
5638
5643
  return {
5639
5644
  model: createOpenAICompatible({
@@ -5976,8 +5981,14 @@ function buildProviderOptions(providerId, config, request) {
5976
5981
  const options = {};
5977
5982
  if (config.service_tier !== void 0) options.service_tier = config.service_tier;
5978
5983
  if (shouldUsePromptCaching(config) && request?.sessionId) options.prompt_cache_key = request.sessionId;
5984
+ if (config.reasoningEffort !== void 0) Object.assign(options, buildReasoningProviderOptions(providerId, config));
5979
5985
  return { [providerId]: options };
5980
5986
  }
5987
+ function buildReasoningProviderOptions(providerId, config) {
5988
+ if (config.reasoningEffort === void 0) return {};
5989
+ if (isOpenRouterProvider$1(providerId, config)) return { reasoning: { effort: config.reasoningEffort } };
5990
+ return { reasoningEffort: config.reasoningEffort };
5991
+ }
5981
5992
  function buildNativeProviderOptions(providerId, config, request) {
5982
5993
  const options = {
5983
5994
  ...buildProviderOptions(providerId, config, request)[providerId],
@@ -6130,6 +6141,15 @@ const toolProtocolSchema = z.enum([
6130
6141
  "text-json",
6131
6142
  "text-xml"
6132
6143
  ]);
6144
+ const reasoningEfforts = [
6145
+ "none",
6146
+ "minimal",
6147
+ "low",
6148
+ "medium",
6149
+ "high",
6150
+ "xhigh"
6151
+ ];
6152
+ const reasoningEffortSchema = z.enum(reasoningEfforts);
6133
6153
  const openRouterAttributionHeaders = {
6134
6154
  "HTTP-Referer": "https://topchester.com",
6135
6155
  "X-Title": "Topchester"
@@ -6149,7 +6169,8 @@ const providerSchema = z.object({
6149
6169
  "auto",
6150
6170
  "force",
6151
6171
  "off"
6152
- ]).optional()
6172
+ ]).optional(),
6173
+ reasoningEffort: reasoningEffortSchema.optional()
6153
6174
  });
6154
6175
  const modelAssignmentSchema = z.object({
6155
6176
  name: z.string(),
@@ -6158,7 +6179,7 @@ const modelAssignmentSchema = z.object({
6158
6179
  });
6159
6180
  const modelChoiceAssignmentSchema = modelAssignmentSchema.extend({ provider: z.string().min(1) });
6160
6181
  const modelRefSchema = z.union([z.string(), modelAssignmentSchema]);
6161
- const providersSchema = z.object({ default: z.string().optional() }).catchall(providerSchema.or(z.string()));
6182
+ const providersSchema = z.object({ default: z.string().optional() }).catchall(providerSchema);
6162
6183
  const rawModelsSchema = z.object({
6163
6184
  "default": modelRefSchema.optional(),
6164
6185
  "fast": modelRefSchema.optional(),
@@ -6467,6 +6488,32 @@ async function setGlobalDefaultModel(modelRef) {
6467
6488
  defaultModel: normalizedModelRef
6468
6489
  };
6469
6490
  }
6491
+ async function setGlobalReasoningEffort(providerId, effort) {
6492
+ const normalizedProviderId = providerId.trim();
6493
+ if (!normalizedProviderId) throw new Error("No provider configured for the active model.");
6494
+ const configPath = getGlobalTopchesterConfigPath();
6495
+ const config = readConfigObject(configPath);
6496
+ const provider = ensurePlainObjectProperty(config, "providers")[normalizedProviderId];
6497
+ if (!isPlainObject(provider)) throw new Error(`No provider configured for model provider "${normalizedProviderId}".`);
6498
+ if (effort === void 0) delete provider.reasoningEffort;
6499
+ else provider.reasoningEffort = effort;
6500
+ await writeGlobalConfig(configPath, config);
6501
+ return {
6502
+ path: configPath,
6503
+ providerId: normalizedProviderId,
6504
+ ...effort === void 0 ? {} : { reasoningEffort: effort }
6505
+ };
6506
+ }
6507
+ function getActiveModelProviderId(config) {
6508
+ const purpose = config.models?.defaultPurpose ?? "agent.primary";
6509
+ const provider = (config.models?.assignments?.[purpose] ?? config.models?.assignments?.fallback)?.provider ?? config.providers?.default;
6510
+ return typeof provider === "string" ? provider : void 0;
6511
+ }
6512
+ function getConfiguredReasoningEffort(config, providerId = getActiveModelProviderId(config)) {
6513
+ if (!providerId) return;
6514
+ const provider = config.providers?.[providerId];
6515
+ return typeof provider === "object" && provider !== null && "reasoningEffort" in provider ? provider.reasoningEffort : void 0;
6516
+ }
6470
6517
  function formatModelRef(model) {
6471
6518
  return model.provider ? `${model.provider}/${model.name}` : model.name;
6472
6519
  }
@@ -9818,6 +9865,22 @@ const slashCommandSuggestions = [
9818
9865
  value: "/connect",
9819
9866
  description: "connect a model provider"
9820
9867
  },
9868
+ {
9869
+ value: "/effort",
9870
+ description: "show or set reasoning effort"
9871
+ },
9872
+ {
9873
+ value: "/effort high",
9874
+ description: "set reasoning effort to high"
9875
+ },
9876
+ {
9877
+ value: "/reasoning",
9878
+ description: "show or set reasoning effort"
9879
+ },
9880
+ {
9881
+ value: "/reasoning high",
9882
+ description: "set reasoning effort to high"
9883
+ },
9821
9884
  {
9822
9885
  value: "/kb status",
9823
9886
  description: "show non-clean knowledge files"
@@ -9904,6 +9967,16 @@ const slashCommands = [
9904
9967
  description: "connect a model provider",
9905
9968
  execute: executeInteractiveOnlyCommand("/connect")
9906
9969
  },
9970
+ {
9971
+ name: "effort",
9972
+ description: "show or set reasoning effort",
9973
+ execute: executeInteractiveOnlyCommand("/effort")
9974
+ },
9975
+ {
9976
+ name: "reasoning",
9977
+ description: "show or set reasoning effort",
9978
+ execute: executeInteractiveOnlyCommand("/reasoning")
9979
+ },
9907
9980
  {
9908
9981
  name: "provider",
9909
9982
  description: "connect a model provider",
@@ -10309,7 +10382,8 @@ function getStartupThreadMessages(context) {
10309
10382
  for (const [providerId, provider] of namedProviders) {
10310
10383
  if (typeof provider === "string") continue;
10311
10384
  const auth = provider.apiKeyEnv ? `env:${provider.apiKeyEnv}` : provider.apiKey ? "inline" : "none";
10312
- lines.push(` ${providerId}: ${provider.type} ${provider.baseURL} auth=${auth}`);
10385
+ const effort = provider.reasoningEffort ? ` effort=${provider.reasoningEffort}` : "";
10386
+ lines.push(` ${providerId}: ${provider.type} ${provider.baseURL} auth=${auth}${effort}`);
10313
10387
  }
10314
10388
  }
10315
10389
  const setupHint = getModelSetupHint(context);
@@ -10360,9 +10434,10 @@ function formatSplitStatusLine(left, right, width) {
10360
10434
  return `${leftText}${" ".repeat(gap)}${right}`;
10361
10435
  }
10362
10436
  function formatModelStatusSegment(modelLabel) {
10363
- const providerMatch = /^(?<model>.*?)(?<provider> \[[^\]]+\])$/.exec(modelLabel);
10437
+ const providerMatch = /^(?<model>.*?)(?<provider> \[[^\]]+\])(?<effort> · effort .+)?$/u.exec(modelLabel);
10364
10438
  if (!providerMatch?.groups) return ui.model(modelLabel);
10365
- return `${ui.model(providerMatch.groups.model)}${ui.label(providerMatch.groups.provider)}`;
10439
+ const effort = providerMatch.groups.effort ? ui.label(providerMatch.groups.effort) : "";
10440
+ return `${ui.model(providerMatch.groups.model)}${ui.label(providerMatch.groups.provider)}${effort}`;
10366
10441
  }
10367
10442
  function formatKnowledgeFooterStatus(status) {
10368
10443
  if (!status.kbExists) return `${ui.warn("⚠")} kb: ${ui.warn("missing")}`;
@@ -10391,7 +10466,9 @@ function getModelLabel(context) {
10391
10466
  const model = context.config.models?.assignments?.[purpose] ?? context.config.models?.assignments?.fallback;
10392
10467
  if (!model) return "not set";
10393
10468
  const provider = model.provider ?? context.config.providers?.default;
10394
- return typeof provider === "string" ? `${model.name} [${provider}]` : model.name;
10469
+ const effort = getConfiguredReasoningEffort(context.config, typeof provider === "string" ? provider : void 0);
10470
+ const effortLabel = effort ? ` · effort ${effort}` : "";
10471
+ return typeof provider === "string" ? `${model.name} [${provider}]${effortLabel}` : `${model.name}${effortLabel}`;
10395
10472
  }
10396
10473
  //#endregion
10397
10474
  //#region src/tui/text.ts
@@ -13975,6 +14052,10 @@ function isModelCommand(command) {
13975
14052
  const name = getSlashCommandName(command);
13976
14053
  return name === "model" || name === "models";
13977
14054
  }
14055
+ function isReasoningEffortCommand(command) {
14056
+ const name = getSlashCommandName(command);
14057
+ return name === "effort" || name === "reasoning";
14058
+ }
13978
14059
  function getSlashCommandName(command) {
13979
14060
  return command.trim().slice(1).split(/\s+/u).filter(Boolean)[0]?.toLowerCase();
13980
14061
  }
@@ -14461,6 +14542,10 @@ var TopchesterTuiShell = class {
14461
14542
  await this.submitModelCommand(app, tui, command);
14462
14543
  return;
14463
14544
  }
14545
+ if (isReasoningEffortCommand(command)) {
14546
+ await this.submitReasoningEffortCommand(app, tui, command);
14547
+ return;
14548
+ }
14464
14549
  const busy = new BusyIndicator(app, tui, {
14465
14550
  status: "running command",
14466
14551
  promptHint: "working...",
@@ -14550,7 +14635,7 @@ var TopchesterTuiShell = class {
14550
14635
  async resolveSkillActivationCommand(command) {
14551
14636
  const parts = command.trim().slice(1).split(/\s+/u).filter(Boolean);
14552
14637
  const name = parts[0]?.toLowerCase();
14553
- if (!name || name === "skills" || name === "kb" || isNewSessionCommand(command) || isConnectCommand(command) || isModelCommand(command)) return;
14638
+ if (!name || name === "skills" || name === "kb" || isNewSessionCommand(command) || isConnectCommand(command) || isModelCommand(command) || isReasoningEffortCommand(command)) return;
14554
14639
  if (name === "skill") {
14555
14640
  const skillName = parts[1];
14556
14641
  if (!skillName) return;
@@ -14669,6 +14754,51 @@ var TopchesterTuiShell = class {
14669
14754
  }
14670
14755
  this.showModelPicker(app, tui, query);
14671
14756
  }
14757
+ async submitReasoningEffortCommand(app, tui, command) {
14758
+ await this.clearTaskPlanForNewTurn(app);
14759
+ await this.persistPayloadWithWarning(app, slashCommandToSessionPayload(command));
14760
+ const args = getSlashCommandArgs(command);
14761
+ const value = args[0]?.toLowerCase();
14762
+ if (args.length === 0) {
14763
+ const current = getConfiguredReasoningEffort(this.context.config);
14764
+ app.addMessage(systemMessage(formatCurrentReasoningEffortMessage(current)));
14765
+ tui.requestRender();
14766
+ return;
14767
+ }
14768
+ if (args.length > 1) {
14769
+ app.addMessage(systemMessage(formatReasoningEffortUsageMessage()));
14770
+ tui.requestRender();
14771
+ return;
14772
+ }
14773
+ if (value === "clear" || value === "default") {
14774
+ await this.updateReasoningEffort(app, void 0);
14775
+ tui.requestRender();
14776
+ return;
14777
+ }
14778
+ if (!isReasoningEffort(value)) {
14779
+ app.addMessage(systemMessage(formatReasoningEffortUsageMessage()));
14780
+ tui.requestRender();
14781
+ return;
14782
+ }
14783
+ await this.updateReasoningEffort(app, value);
14784
+ tui.requestRender();
14785
+ }
14786
+ async updateReasoningEffort(app, effort) {
14787
+ try {
14788
+ const providerId = getActiveModelProviderId(this.context.config);
14789
+ if (!providerId) {
14790
+ app.addMessage(systemMessage("No provider configured for the active model. Run /connect codex or configure a provider first."));
14791
+ return;
14792
+ }
14793
+ const result = await setGlobalReasoningEffort(providerId, effort);
14794
+ this.reloadModelConfig(app);
14795
+ app.addMessage(systemMessage(effort === void 0 ? `Reasoning effort cleared; provider defaults will apply.\nconfig: ${formatHomeRelativePath(result.path)}` : `Reasoning effort set to ${effort}.\nconfig: ${formatHomeRelativePath(result.path)}`));
14796
+ app.setStatus("ready");
14797
+ } catch (error) {
14798
+ app.addMessage(systemMessage(`Reasoning effort change failed: ${formatPlainError(error)}`));
14799
+ app.setStatus("reasoning effort change failed");
14800
+ }
14801
+ }
14672
14802
  showProviderPicker(app, tui) {
14673
14803
  app.setModalActionHandler((action) => {
14674
14804
  if (action.value === "openrouter") this.startBackgroundTask(app, tui, "Connect", () => this.connectOpenRouter(app, tui));
@@ -15049,6 +15179,15 @@ function parseSteerCommandPrompt(command) {
15049
15179
  const match = /^\/steer(?:\s+([\s\S]*))?$/u.exec(trimmed);
15050
15180
  return match ? match[1] ?? "" : void 0;
15051
15181
  }
15182
+ function isReasoningEffort(value) {
15183
+ return reasoningEfforts.includes(value);
15184
+ }
15185
+ function formatCurrentReasoningEffortMessage(effort) {
15186
+ return `Current reasoning effort: ${effort ?? "provider default"}. Values: ${reasoningEfforts.join(", ")}.`;
15187
+ }
15188
+ function formatReasoningEffortUsageMessage() {
15189
+ return `Usage: /effort <${reasoningEfforts.join("|")}> or /effort clear.`;
15190
+ }
15052
15191
  //#endregion
15053
15192
  //#region src/version.ts
15054
15193
  const FALLBACK_VERSION = "0.0.0";
@@ -16029,4 +16168,4 @@ function formatDryRunSyncStatus(status) {
16029
16168
  //#endregion
16030
16169
  export { runTopchesterCli as t };
16031
16170
 
16032
- //# sourceMappingURL=cli-AJknxj59.mjs.map
16171
+ //# sourceMappingURL=cli-kvaa3acN.mjs.map