@byfriends/cli 0.1.0 → 0.1.1

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 (3) hide show
  1. package/dist/main.mjs +259 -404
  2. package/package.json +25 -25
  3. package/LICENSE +0 -28
package/dist/main.mjs CHANGED
@@ -8059,6 +8059,9 @@ const UNKNOWN_CAPABILITY = Object.freeze(Object.defineProperty({
8059
8059
  audio_in: false,
8060
8060
  thinking: false,
8061
8061
  tool_use: false,
8062
+ thinking_effort: false,
8063
+ thinking_xhigh: false,
8064
+ thinking_max: false,
8062
8065
  max_context_tokens: 0
8063
8066
  }, Symbol.for("byf.kosong.UNKNOWN_CAPABILITY"), { value: true }));
8064
8067
  //#endregion
@@ -8106,6 +8109,20 @@ const OPENAI_REASONING_CAPABILITY = Object.freeze({
8106
8109
  audio_in: false,
8107
8110
  thinking: true,
8108
8111
  tool_use: true,
8112
+ thinking_effort: true,
8113
+ thinking_xhigh: false,
8114
+ thinking_max: false,
8115
+ max_context_tokens: 0
8116
+ });
8117
+ const OPENAI_REASONING_XHIGH_CAPABILITY = Object.freeze({
8118
+ image_in: false,
8119
+ video_in: false,
8120
+ audio_in: false,
8121
+ thinking: true,
8122
+ tool_use: true,
8123
+ thinking_effort: true,
8124
+ thinking_xhigh: true,
8125
+ thinking_max: false,
8109
8126
  max_context_tokens: 0
8110
8127
  });
8111
8128
  const OPENAI_VISION_TOOL_CAPABILITY = Object.freeze({
@@ -8114,6 +8131,9 @@ const OPENAI_VISION_TOOL_CAPABILITY = Object.freeze({
8114
8131
  audio_in: false,
8115
8132
  thinking: false,
8116
8133
  tool_use: true,
8134
+ thinking_effort: false,
8135
+ thinking_xhigh: false,
8136
+ thinking_max: false,
8117
8137
  max_context_tokens: 0
8118
8138
  });
8119
8139
  const OPENAI_TEXT_TOOL_CAPABILITY = Object.freeze({
@@ -8122,6 +8142,9 @@ const OPENAI_TEXT_TOOL_CAPABILITY = Object.freeze({
8122
8142
  audio_in: false,
8123
8143
  thinking: false,
8124
8144
  tool_use: true,
8145
+ thinking_effort: false,
8146
+ thinking_xhigh: false,
8147
+ thinking_max: false,
8125
8148
  max_context_tokens: 0
8126
8149
  });
8127
8150
  const ANTHROPIC_VISION_TOOL_CAPABILITY = Object.freeze({
@@ -8130,6 +8153,9 @@ const ANTHROPIC_VISION_TOOL_CAPABILITY = Object.freeze({
8130
8153
  audio_in: false,
8131
8154
  thinking: false,
8132
8155
  tool_use: true,
8156
+ thinking_effort: false,
8157
+ thinking_xhigh: false,
8158
+ thinking_max: false,
8133
8159
  max_context_tokens: 0
8134
8160
  });
8135
8161
  const ANTHROPIC_THINKING_VISION_TOOL_CAPABILITY = Object.freeze({
@@ -8138,6 +8164,20 @@ const ANTHROPIC_THINKING_VISION_TOOL_CAPABILITY = Object.freeze({
8138
8164
  audio_in: false,
8139
8165
  thinking: true,
8140
8166
  tool_use: true,
8167
+ thinking_effort: true,
8168
+ thinking_xhigh: false,
8169
+ thinking_max: true,
8170
+ max_context_tokens: 0
8171
+ });
8172
+ const ANTHROPIC_THINKING_XHIGH_VISION_TOOL_CAPABILITY = Object.freeze({
8173
+ image_in: true,
8174
+ video_in: false,
8175
+ audio_in: false,
8176
+ thinking: true,
8177
+ tool_use: true,
8178
+ thinking_effort: true,
8179
+ thinking_xhigh: true,
8180
+ thinking_max: true,
8141
8181
  max_context_tokens: 0
8142
8182
  });
8143
8183
  const GEMINI_MULTIMODAL_TOOL_CAPABILITY = Object.freeze({
@@ -8146,6 +8186,9 @@ const GEMINI_MULTIMODAL_TOOL_CAPABILITY = Object.freeze({
8146
8186
  audio_in: true,
8147
8187
  thinking: false,
8148
8188
  tool_use: true,
8189
+ thinking_effort: false,
8190
+ thinking_xhigh: false,
8191
+ thinking_max: false,
8149
8192
  max_context_tokens: 0
8150
8193
  });
8151
8194
  const GEMINI_THINKING_MULTIMODAL_TOOL_CAPABILITY = Object.freeze({
@@ -8154,9 +8197,16 @@ const GEMINI_THINKING_MULTIMODAL_TOOL_CAPABILITY = Object.freeze({
8154
8197
  audio_in: true,
8155
8198
  thinking: true,
8156
8199
  tool_use: true,
8200
+ thinking_effort: false,
8201
+ thinking_xhigh: false,
8202
+ thinking_max: false,
8157
8203
  max_context_tokens: 0
8158
8204
  });
8159
8205
  const OPENAI_LEGACY_CAPABILITY_CATALOG = [
8206
+ {
8207
+ matches: isOpenAIGpt5ReasoningModel,
8208
+ capability: OPENAI_REASONING_XHIGH_CAPABILITY
8209
+ },
8160
8210
  {
8161
8211
  matches: isOpenAIReasoningModel,
8162
8212
  capability: OPENAI_REASONING_CAPABILITY
@@ -8170,20 +8220,34 @@ const OPENAI_LEGACY_CAPABILITY_CATALOG = [
8170
8220
  capability: OPENAI_TEXT_TOOL_CAPABILITY
8171
8221
  }
8172
8222
  ];
8173
- const OPENAI_RESPONSES_CAPABILITY_CATALOG = [{
8174
- matches: isOpenAIReasoningModel,
8175
- capability: OPENAI_REASONING_CAPABILITY
8176
- }, {
8177
- matches: (name) => hasPrefix(name, OPENAI_VISION_TOOL_PREFIXES),
8178
- capability: OPENAI_VISION_TOOL_CAPABILITY
8179
- }];
8180
- const ANTHROPIC_CAPABILITY_CATALOG = [{
8181
- matches: (name) => hasPrefix(name, CLAUDE_3_PREFIXES),
8182
- capability: ANTHROPIC_VISION_TOOL_CAPABILITY
8183
- }, {
8184
- matches: (name) => hasPrefix(name, CLAUDE_4_PREFIXES),
8185
- capability: ANTHROPIC_THINKING_VISION_TOOL_CAPABILITY
8186
- }];
8223
+ const OPENAI_RESPONSES_CAPABILITY_CATALOG = [
8224
+ {
8225
+ matches: isOpenAIGpt5ReasoningModel,
8226
+ capability: OPENAI_REASONING_XHIGH_CAPABILITY
8227
+ },
8228
+ {
8229
+ matches: isOpenAIReasoningModel,
8230
+ capability: OPENAI_REASONING_CAPABILITY
8231
+ },
8232
+ {
8233
+ matches: (name) => hasPrefix(name, OPENAI_VISION_TOOL_PREFIXES),
8234
+ capability: OPENAI_VISION_TOOL_CAPABILITY
8235
+ }
8236
+ ];
8237
+ const ANTHROPIC_CAPABILITY_CATALOG = [
8238
+ {
8239
+ matches: (name) => hasPrefix(name, CLAUDE_3_PREFIXES),
8240
+ capability: ANTHROPIC_VISION_TOOL_CAPABILITY
8241
+ },
8242
+ {
8243
+ matches: isClaudeOpus47Or48,
8244
+ capability: ANTHROPIC_THINKING_XHIGH_VISION_TOOL_CAPABILITY
8245
+ },
8246
+ {
8247
+ matches: (name) => hasPrefix(name, CLAUDE_4_PREFIXES),
8248
+ capability: ANTHROPIC_THINKING_VISION_TOOL_CAPABILITY
8249
+ }
8250
+ ];
8187
8251
  function normalizeModelName(modelName) {
8188
8252
  return modelName.toLowerCase();
8189
8253
  }
@@ -8193,6 +8257,12 @@ function hasPrefix(modelName, prefixes) {
8193
8257
  function isOpenAIReasoningModel(modelName) {
8194
8258
  return /^o\d/.test(modelName);
8195
8259
  }
8260
+ function isOpenAIGpt5ReasoningModel(modelName) {
8261
+ return /^gpt-5/.test(modelName);
8262
+ }
8263
+ function isClaudeOpus47Or48(modelName) {
8264
+ return /claude-opus-4-[78]/.test(modelName);
8265
+ }
8196
8266
  function capabilityFromCatalog(modelName, catalog) {
8197
8267
  const normalized = normalizeModelName(modelName);
8198
8268
  for (const entry of catalog) if (entry.matches(normalized)) return entry.capability;
@@ -8429,33 +8499,23 @@ function supportsAdaptiveThinking(model) {
8429
8499
  if (match === null) return false;
8430
8500
  return versionAtLeast(parseVersion(match), ADAPTIVE_MIN_VERSION);
8431
8501
  }
8432
- function isOpus47(model) {
8502
+ function supportsXhigh(model) {
8433
8503
  const match = OPUS_VERSION_RE.exec(model.toLowerCase());
8434
8504
  if (match === null) return false;
8435
8505
  const version = parseVersion(match);
8436
- return version.major === 4 && version.minor === 7;
8437
- }
8438
- function supportsEffortParam(model) {
8439
- if (supportsAdaptiveThinking(model)) return true;
8440
- const normalized = model.toLowerCase();
8441
- return normalized.includes("opus-4-5") || normalized.includes("opus-4.5");
8506
+ return version.major === 4 && (version.minor === 7 || version.minor === 8);
8442
8507
  }
8443
8508
  function clampEffort(effort, model) {
8444
8509
  if (effort === "off") return effort;
8445
- if (effort === "xhigh" && !isOpus47(model)) return "high";
8446
- if (effort === "max" && !supportsAdaptiveThinking(model)) return "high";
8447
- return effort;
8448
- }
8449
- function budgetTokensForEffort(effort) {
8450
- switch (effort) {
8451
- case "low": return 1024;
8452
- case "medium": return 4096;
8453
- case "high": return 32e3;
8454
- case "off":
8455
- case "xhigh":
8456
- case "max": throw new Error(`Unsupported budget-based thinking effort: ${effort}`);
8510
+ if (effort === "xhigh" && !supportsXhigh(model)) {
8511
+ console.warn(`effort 'xhigh' clamped to 'high' for model ${model}`);
8512
+ return "high";
8457
8513
  }
8458
- throw new Error(`Unknown thinking effort: ${String(effort)}`);
8514
+ if (effort === "max" && !supportsAdaptiveThinking(model)) {
8515
+ console.warn(`effort 'max' clamped to 'high' for model ${model}`);
8516
+ return "high";
8517
+ }
8518
+ return effort;
8459
8519
  }
8460
8520
  const CACHE_CONTROL = { type: "ephemeral" };
8461
8521
  /**
@@ -8548,7 +8608,7 @@ function toolResultToBlock(toolCallId, content) {
8548
8608
  content: blocks
8549
8609
  };
8550
8610
  }
8551
- function convertMessage$3(message) {
8611
+ function convertMessage$2(message) {
8552
8612
  const role = message.role;
8553
8613
  if (role === "system") return {
8554
8614
  role: "user",
@@ -8822,20 +8882,15 @@ var AnthropicChatProvider = class {
8822
8882
  const thinkingConfig = this._generationKwargs.thinking;
8823
8883
  if (thinkingConfig === void 0 || thinkingConfig === null) return null;
8824
8884
  if (thinkingConfig.type === "disabled") return "off";
8825
- if (thinkingConfig.type === "adaptive") {
8826
- const effort = this._generationKwargs.output_config?.effort;
8827
- if (effort === void 0 || effort === null) return "high";
8828
- switch (effort) {
8829
- case "low":
8830
- case "medium":
8831
- case "high":
8832
- case "xhigh":
8833
- case "max": return effort;
8834
- }
8835
- }
8836
- const budget = thinkingConfig.budget_tokens ?? 0;
8837
- if (budget <= 1024) return "low";
8838
- if (budget <= 4096) return "medium";
8885
+ const effort = this._generationKwargs.output_config?.effort;
8886
+ if (effort === void 0 || effort === null) return "high";
8887
+ switch (effort) {
8888
+ case "low":
8889
+ case "medium":
8890
+ case "high":
8891
+ case "xhigh":
8892
+ case "max": return effort;
8893
+ }
8839
8894
  return "high";
8840
8895
  }
8841
8896
  get modelParameters() {
@@ -8855,7 +8910,7 @@ var AnthropicChatProvider = class {
8855
8910
  }] : void 0;
8856
8911
  const messages = [];
8857
8912
  for (const msg of history) {
8858
- const converted = convertMessage$3(msg);
8913
+ const converted = convertMessage$2(msg);
8859
8914
  const last = messages.at(-1);
8860
8915
  if (last !== void 0 && isToolResultOnly(last) && isToolResultOnly(converted)) last.content = [...last.content, ...converted.content];
8861
8916
  else messages.push(converted);
@@ -8923,7 +8978,7 @@ var AnthropicChatProvider = class {
8923
8978
  withThinking(effort) {
8924
8979
  if (effort === "off") {
8925
8980
  let newBetas = [...this._generationKwargs.betaFeatures ?? []];
8926
- if (supportsAdaptiveThinking(this._model)) newBetas = newBetas.filter((b) => b !== INTERLEAVED_THINKING_BETA);
8981
+ newBetas = newBetas.filter((b) => b !== INTERLEAVED_THINKING_BETA);
8927
8982
  const clone = this._withGenerationKwargs({
8928
8983
  thinking: { type: "disabled" },
8929
8984
  betaFeatures: newBetas
@@ -8934,29 +8989,15 @@ var AnthropicChatProvider = class {
8934
8989
  const effectiveEffort = clampEffort(effort, this._model);
8935
8990
  if (effectiveEffort === "off") throw new Error("Non-off thinking effort unexpectedly clamped to off.");
8936
8991
  let newBetas = [...this._generationKwargs.betaFeatures ?? []];
8937
- if (supportsAdaptiveThinking(this._model)) {
8938
- newBetas = newBetas.filter((b) => b !== INTERLEAVED_THINKING_BETA);
8939
- return this._withGenerationKwargs({
8940
- thinking: {
8941
- type: "adaptive",
8942
- display: "summarized"
8943
- },
8944
- output_config: { effort: effectiveEffort },
8945
- betaFeatures: newBetas
8946
- });
8947
- }
8948
- const kwargs = {
8992
+ newBetas = newBetas.filter((b) => b !== INTERLEAVED_THINKING_BETA);
8993
+ return this._withGenerationKwargs({
8949
8994
  thinking: {
8950
- type: "enabled",
8951
- budget_tokens: budgetTokensForEffort(effectiveEffort)
8995
+ type: "adaptive",
8996
+ display: "summarized"
8952
8997
  },
8998
+ output_config: { effort: effectiveEffort },
8953
8999
  betaFeatures: newBetas
8954
- };
8955
- if (supportsEffortParam(this._model)) kwargs.output_config = { effort: effectiveEffort };
8956
- else kwargs.output_config = void 0;
8957
- const clone = this._withGenerationKwargs(kwargs);
8958
- if (!supportsEffortParam(this._model)) delete clone._generationKwargs.output_config;
8959
- return clone;
9000
+ });
8960
9001
  }
8961
9002
  withGenerationKwargs(kwargs) {
8962
9003
  return this._withGenerationKwargs(kwargs);
@@ -44970,16 +45011,41 @@ function isFunctionToolCall(tc) {
44970
45011
  return tc.type === "function";
44971
45012
  }
44972
45013
  /**
45014
+ * Model name prefixes / exact names known to support the `xhigh` reasoning
45015
+ * effort level. All other OpenAI-compatible models clamp `xhigh` / `max`
45016
+ * down to `high`.
45017
+ */
45018
+ const XHIGH_SUPPORT_PREFIXES = [
45019
+ "gpt-5.",
45020
+ "gpt-5-",
45021
+ "o3-pro",
45022
+ "o4-mini"
45023
+ ];
45024
+ function supportsXhighReasoningEffort(model) {
45025
+ const normalized = model.toLowerCase();
45026
+ return XHIGH_SUPPORT_PREFIXES.some((prefix) => normalized.startsWith(prefix));
45027
+ }
45028
+ /**
44973
45029
  * Map kosong `ThinkingEffort` to OpenAI `reasoning_effort` string.
45030
+ *
45031
+ * When `model` is provided, `xhigh` / `max` are clamped to `'high'` with a
45032
+ * `console.warn` if the model is not known to support the `xhigh` effort
45033
+ * level. When `model` is omitted the mapping is pass-through (backward
45034
+ * compatible).
44974
45035
  */
44975
- function thinkingEffortToReasoningEffort(effort) {
45036
+ function thinkingEffortToReasoningEffort(effort, model) {
44976
45037
  switch (effort) {
44977
45038
  case "off": return;
44978
45039
  case "low": return "low";
44979
45040
  case "medium": return "medium";
44980
45041
  case "high": return "high";
44981
45042
  case "xhigh":
44982
- case "max": return "xhigh";
45043
+ case "max":
45044
+ if (model !== void 0 && !supportsXhighReasoningEffort(model)) {
45045
+ console.warn(`effort '${effort}' clamped to 'high' for model ${model}`);
45046
+ return "high";
45047
+ }
45048
+ return "xhigh";
44983
45049
  default: throw new Error(`Unknown thinking effort: ${String(effort)}`);
44984
45050
  }
44985
45051
  }
@@ -45252,7 +45318,22 @@ function convertChatCompletionStreamToolCall(toolCall, bufferedByIndex) {
45252
45318
  }];
45253
45319
  }
45254
45320
  //#endregion
45255
- //#region ../../packages/kosong/src/providers/openai-compat.ts
45321
+ //#region ../../packages/kosong/src/providers/openai-completions.ts
45322
+ const KNOWN_REASONING_KEYS = [
45323
+ "reasoning_content",
45324
+ "reasoning_details",
45325
+ "reasoning"
45326
+ ];
45327
+ const DEFAULT_OUTBOUND_REASONING_KEY = KNOWN_REASONING_KEYS[0];
45328
+ function extractReasoningContent(source, explicitKey) {
45329
+ if (typeof source !== "object" || source === null) return void 0;
45330
+ const record = source;
45331
+ const keys = explicitKey !== void 0 ? [explicitKey] : KNOWN_REASONING_KEYS;
45332
+ for (const key of keys) {
45333
+ const value = record[key];
45334
+ if (typeof value === "string" && value.length > 0) return value;
45335
+ }
45336
+ }
45256
45337
  function isEffectivelyEmptyContent(parts) {
45257
45338
  for (const part of parts) {
45258
45339
  if (part.type !== "text") return false;
@@ -45260,14 +45341,23 @@ function isEffectivelyEmptyContent(parts) {
45260
45341
  }
45261
45342
  return true;
45262
45343
  }
45263
- function convertMessage$2(message) {
45344
+ function convertMessage$1(message, reasoningKey, toolMessageConversion) {
45264
45345
  let reasoningContent = "";
45265
45346
  const nonThinkParts = [];
45266
45347
  for (const part of message.content) if (part.type === "think") reasoningContent += part.think;
45267
45348
  else nonThinkParts.push(part);
45268
45349
  const result = { role: message.role };
45269
45350
  const hasToolCalls = message.toolCalls.length > 0;
45270
- if (!(message.role === "assistant" && hasToolCalls && isEffectivelyEmptyContent(nonThinkParts))) {
45351
+ const shouldOmitContent = message.role === "assistant" && hasToolCalls && isEffectivelyEmptyContent(nonThinkParts);
45352
+ if (message.role === "tool") {
45353
+ const effectiveConversion = message.content.some((p) => p.type !== "text" && p.type !== "think") ? "extract_text" : toolMessageConversion;
45354
+ if (effectiveConversion !== null) result.content = convertToolMessageContent(message, effectiveConversion);
45355
+ else if (!shouldOmitContent) {
45356
+ const firstPart = nonThinkParts[0];
45357
+ if (nonThinkParts.length === 1 && firstPart?.type === "text") result.content = firstPart.text;
45358
+ else if (nonThinkParts.length > 0) result.content = nonThinkParts.map((p) => convertContentPart(p)).filter((p) => p !== null);
45359
+ }
45360
+ } else if (!shouldOmitContent) {
45271
45361
  const firstPart = nonThinkParts[0];
45272
45362
  if (nonThinkParts.length === 1 && firstPart?.type === "text") result.content = firstPart.text;
45273
45363
  else if (nonThinkParts.length > 0) result.content = nonThinkParts.map((p) => convertContentPart(p)).filter((p) => p !== null);
@@ -45286,7 +45376,7 @@ function convertMessage$2(message) {
45286
45376
  return mapped;
45287
45377
  });
45288
45378
  if (message.toolCallId !== void 0) result.tool_call_id = message.toolCallId;
45289
- if (reasoningContent) result.reasoning_content = reasoningContent;
45379
+ if (reasoningContent) result[reasoningKey ?? DEFAULT_OUTBOUND_REASONING_KEY] = reasoningContent;
45290
45380
  return result;
45291
45381
  }
45292
45382
  function convertTool$1(tool) {
@@ -45303,10 +45393,6 @@ function convertTool$1(tool) {
45303
45393
  }
45304
45394
  };
45305
45395
  }
45306
- /**
45307
- * Extract usage from a streaming chunk. Some OpenAI-compatible providers may place usage in
45308
- * `choices[0].usage` in addition to the top-level `usage` field.
45309
- */
45310
45396
  function extractUsageFromChunk(chunk) {
45311
45397
  if (chunk["usage"] !== null && chunk["usage"] !== void 0 && typeof chunk["usage"] === "object") return chunk["usage"];
45312
45398
  const choices = chunk["choices"];
@@ -45317,15 +45403,15 @@ function extractUsageFromChunk(chunk) {
45317
45403
  if (choiceUsage !== null && choiceUsage !== void 0 && typeof choiceUsage === "object") return choiceUsage;
45318
45404
  return null;
45319
45405
  }
45320
- var OpenAICompatStreamedMessage = class {
45406
+ var OpenAICompletionsStreamedMessage = class {
45321
45407
  _id = null;
45322
45408
  _usage = null;
45323
45409
  _finishReason = null;
45324
45410
  _rawFinishReason = null;
45325
45411
  _iter;
45326
- constructor(response, isStream) {
45327
- if (isStream) this._iter = this._convertStreamResponse(response);
45328
- else this._iter = this._convertNonStreamResponse(response);
45412
+ constructor(response, isStream, reasoningKey) {
45413
+ if (isStream) this._iter = this._convertStreamResponse(response, reasoningKey);
45414
+ else this._iter = this._convertNonStreamResponse(response, reasoningKey);
45329
45415
  }
45330
45416
  get id() {
45331
45417
  return this._id;
@@ -45347,16 +45433,16 @@ var OpenAICompatStreamedMessage = class {
45347
45433
  this._finishReason = normalized.finishReason;
45348
45434
  this._rawFinishReason = normalized.rawFinishReason;
45349
45435
  }
45350
- async *_convertNonStreamResponse(response) {
45436
+ async *_convertNonStreamResponse(response, reasoningKey) {
45351
45437
  this._id = response.id;
45352
45438
  if (response.usage) this._usage = extractUsage(response.usage) ?? null;
45353
45439
  this._captureFinishReason(response.choices[0]?.finish_reason ?? null);
45354
45440
  const message = response.choices[0]?.message;
45355
45441
  if (!message) return;
45356
- const rc = message["reasoning_content"];
45357
- if (typeof rc === "string" && rc) yield {
45442
+ const reasoning = extractReasoningContent(message, reasoningKey);
45443
+ if (reasoning) yield {
45358
45444
  type: "think",
45359
- think: rc
45445
+ think: reasoning
45360
45446
  };
45361
45447
  if (message.content) yield {
45362
45448
  type: "text",
@@ -45372,7 +45458,7 @@ var OpenAICompatStreamedMessage = class {
45372
45458
  };
45373
45459
  }
45374
45460
  }
45375
- async *_convertStreamResponse(response) {
45461
+ async *_convertStreamResponse(response, reasoningKey) {
45376
45462
  const bufferedToolCalls = /* @__PURE__ */ new Map();
45377
45463
  try {
45378
45464
  for await (const chunk of response) {
@@ -45384,10 +45470,10 @@ var OpenAICompatStreamedMessage = class {
45384
45470
  if (!choice) continue;
45385
45471
  if (choice.finish_reason !== null && choice.finish_reason !== void 0) this._captureFinishReason(choice.finish_reason);
45386
45472
  const delta = choice.delta;
45387
- const rc = delta["reasoning_content"];
45388
- if (typeof rc === "string" && rc) yield {
45473
+ const reasoning = extractReasoningContent(delta, reasoningKey);
45474
+ if (reasoning) yield {
45389
45475
  type: "think",
45390
- think: rc
45476
+ think: reasoning
45391
45477
  };
45392
45478
  if (delta.content) yield {
45393
45479
  type: "text",
@@ -45400,8 +45486,8 @@ var OpenAICompatStreamedMessage = class {
45400
45486
  }
45401
45487
  }
45402
45488
  };
45403
- var OpenAICompatChatProvider = class {
45404
- name = "openai-compat";
45489
+ var OpenAICompletionsChatProvider = class {
45490
+ name = "openai-completions";
45405
45491
  _model;
45406
45492
  _stream;
45407
45493
  _apiKey;
@@ -45409,20 +45495,25 @@ var OpenAICompatChatProvider = class {
45409
45495
  _defaultHeaders;
45410
45496
  _generationKwargs;
45411
45497
  _thinkingEffortKey;
45498
+ _reasoningKey;
45499
+ _toolMessageConversion;
45412
45500
  _client;
45413
45501
  _clientFactory;
45414
45502
  _files;
45415
45503
  constructor(options) {
45416
45504
  const apiKey = options.apiKey;
45417
45505
  this._apiKey = apiKey === void 0 || apiKey.length === 0 ? void 0 : apiKey;
45418
- this._baseUrl = options.baseUrl ?? process.env["BYF_BASE_URL"] ?? "";
45506
+ this._baseUrl = options.baseUrl ?? "";
45419
45507
  this._defaultHeaders = options.defaultHeaders;
45420
45508
  this._clientFactory = options.clientFactory;
45421
45509
  this._model = options.model;
45422
45510
  this._stream = options.stream ?? true;
45423
45511
  const normalizedThinkingEffortKey = options.thinkingEffortKey?.trim();
45424
45512
  this._thinkingEffortKey = normalizedThinkingEffortKey !== void 0 && normalizedThinkingEffortKey.length > 0 ? normalizedThinkingEffortKey : "reasoning_effort";
45513
+ const normalizedReasoningKey = options.reasoningKey?.trim();
45514
+ this._reasoningKey = normalizedReasoningKey !== void 0 && normalizedReasoningKey.length > 0 ? normalizedReasoningKey : void 0;
45425
45515
  this._generationKwargs = { ...options.generationKwargs };
45516
+ this._toolMessageConversion = options.toolMessageConversion ?? null;
45426
45517
  this._client = this._apiKey === void 0 ? void 0 : new OpenAI({
45427
45518
  apiKey: this._apiKey,
45428
45519
  baseURL: this._baseUrl,
@@ -45432,13 +45523,12 @@ var OpenAICompatChatProvider = class {
45432
45523
  get modelName() {
45433
45524
  return this._model;
45434
45525
  }
45435
- /**
45436
- * File upload client for an OpenAI-compatible service.
45437
- *
45438
- * Use this to upload videos (and other media in the future) to the file
45439
- * service and receive a content part that can be embedded in chat
45440
- * messages.
45441
- */
45526
+ get thinkingEffort() {
45527
+ const customValue = this._generationKwargs[this._thinkingEffortKey];
45528
+ if (typeof customValue === "string") return reasoningEffortToThinkingEffort(customValue);
45529
+ const defaultValue = this._generationKwargs.reasoning_effort;
45530
+ return reasoningEffortToThinkingEffort(defaultValue);
45531
+ }
45442
45532
  get files() {
45443
45533
  this._files ??= new OpenAICompatFiles({
45444
45534
  apiKey: this._apiKey,
@@ -45451,12 +45541,6 @@ var OpenAICompatChatProvider = class {
45451
45541
  uploadVideo(input, options) {
45452
45542
  return this.files.uploadVideo(input, options);
45453
45543
  }
45454
- get thinkingEffort() {
45455
- const customValue = this._generationKwargs[this._thinkingEffortKey];
45456
- if (typeof customValue === "string") return reasoningEffortToThinkingEffort(customValue);
45457
- const defaultValue = this._generationKwargs.reasoning_effort;
45458
- return reasoningEffortToThinkingEffort(defaultValue);
45459
- }
45460
45544
  get modelParameters() {
45461
45545
  return {
45462
45546
  model: this._model,
@@ -45464,14 +45548,20 @@ var OpenAICompatChatProvider = class {
45464
45548
  ...this._generationKwargs
45465
45549
  };
45466
45550
  }
45551
+ getCapability(model) {
45552
+ return getOpenAILegacyModelCapability(model ?? this._model);
45553
+ }
45467
45554
  async generate(systemPrompt, tools, history, options) {
45468
45555
  const messages = [];
45469
45556
  if (systemPrompt) messages.push({
45470
45557
  role: "system",
45471
45558
  content: systemPrompt
45472
45559
  });
45473
- for (const msg of history) messages.push(convertMessage$2(msg));
45560
+ for (const msg of history) messages.push(convertMessage$1(msg, this._reasoningKey, this._toolMessageConversion));
45474
45561
  const kwargs = { ...this._generationKwargs };
45562
+ if (kwargs[this._thinkingEffortKey] === void 0 && kwargs["reasoning_effort"] === void 0) {
45563
+ if (history.some((message) => message.content.some((part) => part.type === "think"))) kwargs[this._thinkingEffortKey] = "high";
45564
+ }
45475
45565
  for (const key of Object.keys(kwargs)) if (kwargs[key] === void 0) delete kwargs[key];
45476
45566
  if (kwargs["max_completion_tokens"] === void 0 && kwargs["max_tokens"] !== void 0) kwargs["max_completion_tokens"] = kwargs["max_tokens"];
45477
45567
  delete kwargs["max_tokens"];
@@ -45486,14 +45576,11 @@ var OpenAICompatChatProvider = class {
45486
45576
  if (tools.length > 0) createParams["tools"] = tools.map((t) => convertTool$1(t));
45487
45577
  if (this._stream) createParams["stream_options"] = { include_usage: true };
45488
45578
  try {
45489
- return new OpenAICompatStreamedMessage(await this._createClient(options?.auth).chat.completions.create(createParams, options?.signal ? { signal: options.signal } : void 0), this._stream);
45579
+ return new OpenAICompletionsStreamedMessage(await this._createClient(options?.auth).chat.completions.create(createParams, options?.signal ? { signal: options.signal } : void 0), this._stream, this._reasoningKey);
45490
45580
  } catch (error) {
45491
45581
  throw convertOpenAIError(error);
45492
45582
  }
45493
45583
  }
45494
- getCapability(_model) {
45495
- return UNKNOWN_CAPABILITY;
45496
- }
45497
45584
  withThinking(effort) {
45498
45585
  const thinking = { type: effort === "off" ? "disabled" : "enabled" };
45499
45586
  let reasoningEffort;
@@ -45543,7 +45630,7 @@ var OpenAICompatChatProvider = class {
45543
45630
  }, auth, (a) => {
45544
45631
  const defaultHeaders = mergeRequestHeaders(this._defaultHeaders, a?.headers);
45545
45632
  return new OpenAI({
45546
- apiKey: requireProviderApiKey("OpenAICompatChatProvider", a, this._apiKey),
45633
+ apiKey: requireProviderApiKey("OpenAICompletionsChatProvider", a, this._apiKey),
45547
45634
  baseURL: this._baseUrl,
45548
45635
  defaultHeaders
45549
45636
  });
@@ -45565,248 +45652,6 @@ var OpenAICompatChatProvider = class {
45565
45652
  }
45566
45653
  };
45567
45654
  //#endregion
45568
- //#region ../../packages/kosong/src/providers/openai-legacy.ts
45569
- const KNOWN_REASONING_KEYS = [
45570
- "reasoning_content",
45571
- "reasoning_details",
45572
- "reasoning"
45573
- ];
45574
- const DEFAULT_OUTBOUND_REASONING_KEY = KNOWN_REASONING_KEYS[0];
45575
- function extractReasoningContent(source, explicitKey) {
45576
- if (typeof source !== "object" || source === null) return void 0;
45577
- const record = source;
45578
- const keys = explicitKey !== void 0 ? [explicitKey] : KNOWN_REASONING_KEYS;
45579
- for (const key of keys) {
45580
- const value = record[key];
45581
- if (typeof value === "string" && value.length > 0) return value;
45582
- }
45583
- }
45584
- function convertMessage$1(message, reasoningKey, toolMessageConversion) {
45585
- let reasoningContent = "";
45586
- const nonThinkParts = [];
45587
- for (const part of message.content) if (part.type === "think") reasoningContent += part.think;
45588
- else nonThinkParts.push(part);
45589
- const result = { role: message.role };
45590
- if (message.role === "tool") {
45591
- const effectiveConversion = message.content.some((p) => p.type !== "text" && p.type !== "think") ? "extract_text" : toolMessageConversion;
45592
- if (effectiveConversion !== null) result.content = convertToolMessageContent(message, effectiveConversion);
45593
- else {
45594
- const firstPart = nonThinkParts[0];
45595
- if (nonThinkParts.length === 1 && firstPart?.type === "text") result.content = firstPart.text;
45596
- else if (nonThinkParts.length > 0) result.content = nonThinkParts.map((p) => convertContentPart(p)).filter((p) => p !== null);
45597
- }
45598
- } else {
45599
- const firstPart = nonThinkParts[0];
45600
- if (nonThinkParts.length === 1 && firstPart?.type === "text") result.content = firstPart.text;
45601
- else if (nonThinkParts.length > 0) result.content = nonThinkParts.map((p) => convertContentPart(p)).filter((p) => p !== null);
45602
- }
45603
- if (message.name !== void 0) result.name = message.name;
45604
- if (message.toolCalls.length > 0) result.tool_calls = message.toolCalls.map((tc) => ({
45605
- type: tc.type,
45606
- id: tc.id,
45607
- function: {
45608
- name: tc.name,
45609
- arguments: tc.arguments
45610
- }
45611
- }));
45612
- if (message.toolCallId !== void 0) result.tool_call_id = message.toolCallId;
45613
- if (reasoningContent) result[reasoningKey ?? DEFAULT_OUTBOUND_REASONING_KEY] = reasoningContent;
45614
- return result;
45615
- }
45616
- var OpenAILegacyStreamedMessage = class {
45617
- _id = null;
45618
- _usage = null;
45619
- _finishReason = null;
45620
- _rawFinishReason = null;
45621
- _iter;
45622
- constructor(response, isStream, reasoningKey) {
45623
- if (isStream) this._iter = this._convertStreamResponse(response, reasoningKey);
45624
- else this._iter = this._convertNonStreamResponse(response, reasoningKey);
45625
- }
45626
- get id() {
45627
- return this._id;
45628
- }
45629
- get usage() {
45630
- return this._usage;
45631
- }
45632
- get finishReason() {
45633
- return this._finishReason;
45634
- }
45635
- get rawFinishReason() {
45636
- return this._rawFinishReason;
45637
- }
45638
- async *[Symbol.asyncIterator]() {
45639
- yield* this._iter;
45640
- }
45641
- _captureFinishReason(raw) {
45642
- const normalized = normalizeOpenAIFinishReason(raw);
45643
- this._finishReason = normalized.finishReason;
45644
- this._rawFinishReason = normalized.rawFinishReason;
45645
- }
45646
- async *_convertNonStreamResponse(response, reasoningKey) {
45647
- this._id = response.id;
45648
- if (response.usage) this._usage = extractUsage(response.usage) ?? null;
45649
- this._captureFinishReason(response.choices[0]?.finish_reason ?? null);
45650
- const message = response.choices[0]?.message;
45651
- if (!message) return;
45652
- const reasoning = extractReasoningContent(message, reasoningKey);
45653
- if (reasoning) yield {
45654
- type: "think",
45655
- think: reasoning
45656
- };
45657
- if (message.content) yield {
45658
- type: "text",
45659
- text: message.content
45660
- };
45661
- if (message.tool_calls) for (const toolCall of message.tool_calls) {
45662
- if (!isFunctionToolCall(toolCall)) continue;
45663
- yield {
45664
- type: "function",
45665
- id: toolCall.id || crypto.randomUUID(),
45666
- name: toolCall.function.name,
45667
- arguments: toolCall.function.arguments
45668
- };
45669
- }
45670
- }
45671
- async *_convertStreamResponse(response, reasoningKey) {
45672
- const bufferedToolCalls = /* @__PURE__ */ new Map();
45673
- try {
45674
- for await (const chunk of response) {
45675
- if (chunk.id) this._id = chunk.id;
45676
- if (chunk.usage) this._usage = extractUsage(chunk.usage) ?? null;
45677
- if (!chunk.choices || chunk.choices.length === 0) continue;
45678
- const choice = chunk.choices[0];
45679
- if (!choice) continue;
45680
- if (choice.finish_reason !== null && choice.finish_reason !== void 0) this._captureFinishReason(choice.finish_reason);
45681
- const delta = choice.delta;
45682
- const reasoning = extractReasoningContent(delta, reasoningKey);
45683
- if (reasoning) yield {
45684
- type: "think",
45685
- think: reasoning
45686
- };
45687
- if (delta.content) yield {
45688
- type: "text",
45689
- text: delta.content
45690
- };
45691
- for (const toolCall of delta.tool_calls ?? []) for (const part of convertChatCompletionStreamToolCall(toolCall, bufferedToolCalls)) yield part;
45692
- }
45693
- } catch (error) {
45694
- throw convertOpenAIError(error);
45695
- }
45696
- }
45697
- };
45698
- var OpenAILegacyChatProvider = class {
45699
- name = "openai";
45700
- _model;
45701
- _stream;
45702
- _apiKey;
45703
- _baseUrl;
45704
- _defaultHeaders;
45705
- _reasoningKey;
45706
- _reasoningEffort;
45707
- _generationKwargs;
45708
- _toolMessageConversion;
45709
- _client;
45710
- _httpClient;
45711
- _clientFactory;
45712
- constructor(options) {
45713
- const apiKey = options.apiKey ?? process.env["OPENAI_API_KEY"];
45714
- this._apiKey = apiKey === void 0 || apiKey.length === 0 ? void 0 : apiKey;
45715
- this._baseUrl = options.baseUrl ?? "https://api.openai.com/v1";
45716
- this._defaultHeaders = options.defaultHeaders;
45717
- this._model = options.model;
45718
- this._stream = options.stream ?? true;
45719
- const normalizedReasoningKey = options.reasoningKey?.trim();
45720
- this._reasoningKey = normalizedReasoningKey !== void 0 && normalizedReasoningKey.length > 0 ? normalizedReasoningKey : void 0;
45721
- this._reasoningEffort = void 0;
45722
- this._generationKwargs = {};
45723
- if (options.maxTokens !== void 0) this._generationKwargs.max_tokens = options.maxTokens;
45724
- this._toolMessageConversion = options.toolMessageConversion ?? null;
45725
- this._httpClient = options.httpClient;
45726
- this._clientFactory = options.clientFactory;
45727
- this._client = this._apiKey === void 0 ? void 0 : this._buildClient(this._apiKey);
45728
- }
45729
- get modelName() {
45730
- return this._model;
45731
- }
45732
- get thinkingEffort() {
45733
- return reasoningEffortToThinkingEffort(this._reasoningEffort);
45734
- }
45735
- get modelParameters() {
45736
- return {
45737
- model: this._model,
45738
- baseUrl: this._baseUrl,
45739
- ...this._generationKwargs
45740
- };
45741
- }
45742
- getCapability(model) {
45743
- return getOpenAILegacyModelCapability(model ?? this._model);
45744
- }
45745
- async generate(systemPrompt, tools, history, options) {
45746
- const messages = [];
45747
- if (systemPrompt) messages.push({
45748
- role: "system",
45749
- content: systemPrompt
45750
- });
45751
- for (const msg of history) messages.push(convertMessage$1(msg, this._reasoningKey, this._toolMessageConversion));
45752
- const kwargs = { ...this._generationKwargs };
45753
- let reasoningEffort = this._reasoningEffort;
45754
- if (reasoningEffort === void 0 && kwargs["reasoning_effort"] === void 0) {
45755
- if (history.some((message) => message.content.some((part) => part.type === "think"))) reasoningEffort = "medium";
45756
- }
45757
- for (const key of Object.keys(kwargs)) if (kwargs[key] === void 0) delete kwargs[key];
45758
- const createParams = {
45759
- model: this._model,
45760
- messages,
45761
- stream: this._stream,
45762
- ...kwargs
45763
- };
45764
- if (tools.length > 0) createParams["tools"] = tools.map((t) => toolToOpenAI(t));
45765
- if (this._stream) createParams["stream_options"] = { include_usage: true };
45766
- if (reasoningEffort !== void 0) createParams["reasoning_effort"] = reasoningEffort;
45767
- try {
45768
- return new OpenAILegacyStreamedMessage(await this._createClient(options?.auth).chat.completions.create(createParams, options?.signal ? { signal: options.signal } : void 0), this._stream, this._reasoningKey);
45769
- } catch (error) {
45770
- throw convertOpenAIError(error);
45771
- }
45772
- }
45773
- withThinking(effort) {
45774
- const reasoningEffort = thinkingEffortToReasoningEffort(effort);
45775
- const clone = this._clone();
45776
- clone._reasoningEffort = reasoningEffort;
45777
- return clone;
45778
- }
45779
- withGenerationKwargs(kwargs) {
45780
- const clone = this._clone();
45781
- clone._generationKwargs = {
45782
- ...clone._generationKwargs,
45783
- ...kwargs
45784
- };
45785
- return clone;
45786
- }
45787
- _clone() {
45788
- const clone = Object.assign(Object.create(Object.getPrototypeOf(this)), this);
45789
- clone._generationKwargs = { ...this._generationKwargs };
45790
- return clone;
45791
- }
45792
- _createClient(auth) {
45793
- return resolveAuthBackedClient({
45794
- cachedClient: this._client,
45795
- clientFactory: this._clientFactory
45796
- }, auth, (a) => this._buildClient(requireProviderApiKey("OpenAILegacyChatProvider", a, this._apiKey), a));
45797
- }
45798
- _buildClient(apiKey, auth) {
45799
- const clientOpts = {
45800
- apiKey,
45801
- baseURL: this._baseUrl
45802
- };
45803
- const defaultHeaders = mergeRequestHeaders(this._defaultHeaders, auth?.headers);
45804
- if (defaultHeaders !== void 0) clientOpts["defaultHeaders"] = defaultHeaders;
45805
- if (this._httpClient !== void 0) clientOpts["httpClient"] = this._httpClient;
45806
- return new OpenAI(clientOpts);
45807
- }
45808
- };
45809
- //#endregion
45810
45655
  //#region ../../packages/kosong/src/providers/openai-responses.ts
45811
45656
  /**
45812
45657
  * Normalize the Responses API status / incomplete_details into the unified
@@ -46385,7 +46230,7 @@ var OpenAIResponsesChatProvider = class {
46385
46230
  }
46386
46231
  }
46387
46232
  withThinking(effort) {
46388
- const reasoningEffort = thinkingEffortToReasoningEffort(effort);
46233
+ const reasoningEffort = thinkingEffortToReasoningEffort(effort, this._model);
46389
46234
  const clone = this._clone();
46390
46235
  clone._generationKwargs = {
46391
46236
  ...clone._generationKwargs,
@@ -46428,8 +46273,7 @@ var OpenAIResponsesChatProvider = class {
46428
46273
  function createProvider(config) {
46429
46274
  switch (config.type) {
46430
46275
  case "anthropic": return new AnthropicChatProvider(config);
46431
- case "openai": return new OpenAILegacyChatProvider(config);
46432
- case "openai-compat": return new OpenAICompatChatProvider(config);
46276
+ case "openai-completions": return new OpenAICompletionsChatProvider(config);
46433
46277
  case "google-genai": return new GoogleGenAIChatProvider(config);
46434
46278
  case "openai_responses": return new OpenAIResponsesChatProvider(config);
46435
46279
  case "vertexai": return new GoogleGenAIChatProvider(config);
@@ -46440,8 +46284,7 @@ function createProvider(config) {
46440
46284
  //#region ../../packages/kosong/src/catalog.ts
46441
46285
  const KNOWN_WIRE_TYPES = [
46442
46286
  "anthropic",
46443
- "openai",
46444
- "openai-compat",
46287
+ "openai-completions",
46445
46288
  "google-genai",
46446
46289
  "openai_responses",
46447
46290
  "vertexai"
@@ -46471,7 +46314,7 @@ function inferWireType(entry) {
46471
46314
  if (npm.includes("anthropic") || id.includes("anthropic") || id.includes("claude")) return "anthropic";
46472
46315
  if (id.includes("vertex")) return "vertexai";
46473
46316
  if (npm.includes("google") || id.includes("google") || id.includes("gemini")) return "google-genai";
46474
- if (npm.includes("openai") || id.includes("openai")) return "openai";
46317
+ if (npm.includes("openai") || id.includes("openai")) return "openai-completions";
46475
46318
  }
46476
46319
  /**
46477
46320
  * Resolves the base URL to store for a catalog provider, adapting the catalog's
@@ -46509,6 +46352,9 @@ function catalogModelToCapability(model) {
46509
46352
  audio_in: inputs.includes("audio"),
46510
46353
  thinking: Boolean(model.reasoning),
46511
46354
  tool_use: model.tool_call ?? true,
46355
+ thinking_effort: false,
46356
+ thinking_xhigh: false,
46357
+ thinking_max: false,
46512
46358
  max_context_tokens: context
46513
46359
  }
46514
46360
  };
@@ -46692,8 +46538,8 @@ function addUsage(a, b) {
46692
46538
  /**
46693
46539
  * Concrete provider adapters stay off the root barrel because their SDK type
46694
46540
  * graphs pollute downstream declaration bundles. Import them from subpaths:
46695
- * `@byf/kosong/providers/openai-compat`,
46696
- * `@byf/kosong/providers/openai-legacy`, etc.
46541
+ * `@byfriends/kosong/providers/openai-responses`,
46542
+ * `@byfriends/kosong/providers/anthropic`, etc.
46697
46543
  */
46698
46544
  //#endregion
46699
46545
  //#region ../../packages/agent-core/src/errors/serialize.ts
@@ -84939,8 +84785,7 @@ function proxyWithExtraPayload(methods, extraPayload) {
84939
84785
  //#region ../../packages/agent-core/src/config/schema.ts
84940
84786
  const ProviderTypeSchema = z.enum([
84941
84787
  "anthropic",
84942
- "openai",
84943
- "openai-compat",
84788
+ "openai-completions",
84944
84789
  "google-genai",
84945
84790
  "openai_responses",
84946
84791
  "vertexai"
@@ -84975,7 +84820,13 @@ const ThinkingConfigSchema = z.object({
84975
84820
  "on",
84976
84821
  "off"
84977
84822
  ]).optional(),
84978
- effort: z.string().optional()
84823
+ effort: z.enum([
84824
+ "low",
84825
+ "medium",
84826
+ "high",
84827
+ "xhigh",
84828
+ "max"
84829
+ ]).optional()
84979
84830
  });
84980
84831
  const PermissionModeSchema = z.enum([
84981
84832
  "yolo",
@@ -104753,6 +104604,9 @@ function resolveModelCapabilities(alias, provider) {
104753
104604
  audio_in: has("audio_in") || providerCapability.audio_in,
104754
104605
  thinking: has("thinking") || has("always_thinking") || providerCapability.thinking,
104755
104606
  tool_use: has("tool_use") || providerCapability.tool_use,
104607
+ thinking_effort: has("thinking_effort") || providerCapability.thinking_effort,
104608
+ thinking_xhigh: has("thinking_xhigh") || providerCapability.thinking_xhigh,
104609
+ thinking_max: has("thinking_max") || providerCapability.thinking_max,
104756
104610
  max_context_tokens: alias.maxContextSize
104757
104611
  };
104758
104612
  }
@@ -104766,31 +104620,25 @@ function toKosongProviderConfig(provider, model, byfRequestHeaders, maxOutputSiz
104766
104620
  ...maxOutputSize !== void 0 ? { defaultMaxTokens: maxOutputSize } : {},
104767
104621
  ...defaultHeadersField(provider.customHeaders)
104768
104622
  };
104769
- case "openai": return {
104770
- type: "openai",
104771
- model,
104772
- baseUrl: providerValue(provider.baseUrl, provider.env, "OPENAI_BASE_URL"),
104773
- apiKey: providerApiKey(provider),
104774
- reasoningKey,
104775
- ...defaultHeadersField(provider.customHeaders)
104776
- };
104777
- case "openai-compat": {
104623
+ case "openai-completions": {
104778
104624
  const defaultHeaders = {
104779
104625
  ...byfRequestHeaders,
104780
104626
  ...provider.customHeaders
104781
104627
  };
104782
104628
  if (Object.keys(defaultHeaders).length === 0) return {
104783
- type: "openai-compat",
104629
+ type: "openai-completions",
104784
104630
  model,
104785
104631
  baseUrl: providerValue(provider.baseUrl, provider.env, "BYF_BASE_URL"),
104632
+ reasoningKey,
104786
104633
  thinkingEffortKey: provider.thinkingEffortKey,
104787
104634
  generationKwargs: { prompt_cache_key: promptCacheKey },
104788
104635
  apiKey: providerApiKey(provider)
104789
104636
  };
104790
104637
  return {
104791
- type: "openai-compat",
104638
+ type: "openai-completions",
104792
104639
  model,
104793
104640
  baseUrl: providerValue(provider.baseUrl, provider.env, "BYF_BASE_URL"),
104641
+ reasoningKey,
104794
104642
  thinkingEffortKey: provider.thinkingEffortKey,
104795
104643
  generationKwargs: { prompt_cache_key: promptCacheKey },
104796
104644
  defaultHeaders,
@@ -104844,9 +104692,8 @@ function providerForCapabilityProbe(provider) {
104844
104692
  function providerApiKey(provider) {
104845
104693
  switch (provider.type) {
104846
104694
  case "anthropic": return providerValue(provider.apiKey, provider.env, "ANTHROPIC_API_KEY");
104847
- case "openai":
104848
104695
  case "openai_responses": return providerValue(provider.apiKey, provider.env, "OPENAI_API_KEY");
104849
- case "openai-compat": return providerValue(provider.apiKey, provider.env, "BYF_API_KEY");
104696
+ case "openai-completions": return providerValue(provider.apiKey, provider.env, "BYF_API_KEY");
104850
104697
  case "google-genai": return providerValue(provider.apiKey, provider.env, "GOOGLE_API_KEY");
104851
104698
  case "vertexai": return nonEmptyString$2(provider.apiKey) ?? envValue(provider.env, "VERTEXAI_API_KEY") ?? envValue(provider.env, "GOOGLE_API_KEY");
104852
104699
  default: {
@@ -107218,7 +107065,7 @@ async function shutdownTelemetry(options = {}) {
107218
107065
  const CLI_USER_AGENT_PRODUCT = "byf-cli";
107219
107066
  const CLI_UI_MODE = "shell";
107220
107067
  const CLI_SHUTDOWN_TIMEOUT_MS = 3e3;
107221
- const NPM_PACKAGE_NAME = "@byf/cli";
107068
+ const NPM_PACKAGE_NAME = "@byfriends/cli";
107222
107069
  const BYF_HOME_ENV = "BYF_HOME";
107223
107070
  const BYF_DATA_DIR_NAME = ".byf";
107224
107071
  const BYF_UPDATE_DIR_NAME = "updates";
@@ -108261,7 +108108,7 @@ function applyProviderConfig(config, options) {
108261
108108
  const providerKey = options.name;
108262
108109
  const modelKey = `${providerKey}/${options.selectedModel.id}`;
108263
108110
  config.providers[providerKey] = {
108264
- type: "openai-compat",
108111
+ type: "openai-completions",
108265
108112
  baseUrl: options.baseUrl,
108266
108113
  apiKey: options.apiKey,
108267
108114
  thinkingEffortKey: options.selectedModel.reasoningEffortKey
@@ -113779,12 +113626,19 @@ function thinkingAvailability(model) {
113779
113626
  if (caps.includes("thinking")) return "toggle";
113780
113627
  return "unsupported";
113781
113628
  }
113782
- const EFFORT_LEVELS = [
113629
+ const BASE_EFFORT_LEVELS = [
113783
113630
  "off",
113784
113631
  "low",
113785
113632
  "medium",
113786
113633
  "high"
113787
113634
  ];
113635
+ function effortLevelsForModel(model) {
113636
+ const caps = model.capabilities ?? [];
113637
+ const levels = [...BASE_EFFORT_LEVELS];
113638
+ if (caps.includes("thinking_xhigh")) levels.push("xhigh");
113639
+ if (caps.includes("thinking_max")) levels.push("max");
113640
+ return levels;
113641
+ }
113788
113642
  function effectiveThinking(model, effortDraft) {
113789
113643
  const availability = thinkingAvailability(model);
113790
113644
  if (availability === "always-on") return "high";
@@ -113820,15 +113674,16 @@ var ModelSelectorComponent = class extends Container {
113820
113674
  }
113821
113675
  const selected = this.list.selected();
113822
113676
  const availability = selected !== void 0 ? thinkingAvailability(selected.model) : "unsupported";
113823
- if (availability === "effort") {
113677
+ if (availability === "effort" && selected !== void 0) {
113678
+ const levels = effortLevelsForModel(selected.model);
113824
113679
  if (matchesKey(data, Key.left)) {
113825
- const idx = EFFORT_LEVELS.indexOf(this.effortDraft);
113826
- if (idx > 0) this.effortDraft = EFFORT_LEVELS[idx - 1];
113680
+ const idx = levels.indexOf(this.effortDraft);
113681
+ if (idx > 0) this.effortDraft = levels[idx - 1];
113827
113682
  return;
113828
113683
  }
113829
113684
  if (matchesKey(data, Key.right)) {
113830
- const idx = EFFORT_LEVELS.indexOf(this.effortDraft);
113831
- if (idx < EFFORT_LEVELS.length - 1) this.effortDraft = EFFORT_LEVELS[idx + 1];
113685
+ const idx = levels.indexOf(this.effortDraft);
113686
+ if (idx < levels.length - 1) this.effortDraft = levels[idx + 1];
113832
113687
  return;
113833
113688
  }
113834
113689
  } else if (availability === "toggle") {
@@ -113892,19 +113747,16 @@ var ModelSelectorComponent = class extends Container {
113892
113747
  if (availability === "always-on") return ` ${segment("Always on", true)}`;
113893
113748
  if (availability === "unsupported") return ` ${segment("Off", true)} ${chalk.hex(colors.textMuted)("unsupported")}`;
113894
113749
  if (availability === "effort") {
113895
- const labels = [
113896
- "off",
113897
- "low",
113898
- "medium",
113899
- "high"
113900
- ];
113901
- const displayLabels = [
113902
- "Off",
113903
- "Low",
113904
- "Medium",
113905
- "High"
113906
- ];
113907
- return " " + labels.map((level, i) => segment(displayLabels[i], this.effortDraft === level)).join("");
113750
+ const levels = effortLevelsForModel(model);
113751
+ const displayMap = {
113752
+ off: "Off",
113753
+ low: "Low",
113754
+ medium: "Medium",
113755
+ high: "High",
113756
+ xhigh: "XHigh",
113757
+ max: "Max"
113758
+ };
113759
+ return " " + levels.map((level) => segment(displayMap[level], this.effortDraft === level)).join("");
113908
113760
  }
113909
113761
  return ` ${segment("On", this.effortDraft !== "off")} ${segment("Off", this.effortDraft === "off")}`;
113910
113762
  }
@@ -117504,11 +117356,13 @@ const THINKING_EFFORT_LEVELS = new Set([
117504
117356
  "off",
117505
117357
  "low",
117506
117358
  "medium",
117507
- "high"
117359
+ "high",
117360
+ "xhigh",
117361
+ "max"
117508
117362
  ]);
117509
117363
  function parseThinkingEffort(value) {
117510
117364
  if (value && THINKING_EFFORT_LEVELS.has(value)) return value;
117511
- if (value === "on" || value === "xhigh" || value === "max") return "high";
117365
+ if (value === "on") return "high";
117512
117366
  return "off";
117513
117367
  }
117514
117368
  const INITIAL_LIVE_PANE = {
@@ -118675,6 +118529,7 @@ var ByfTui = class {
118675
118529
  });
118676
118530
  return;
118677
118531
  }
118532
+ if (config.defaultThinking !== void 0) log.warn("defaultThinking is deprecated. Use [thinking] mode and effort instead.");
118678
118533
  const defaultThinkingEffort = config.thinking?.mode === "off" ? "off" : config.thinking?.effort !== void 0 ? parseThinkingEffort(config.thinking.effort) : config.defaultThinking === void 0 ? void 0 : config.defaultThinking ? "high" : "off";
118679
118534
  await this.activateModelAfterLogin(defaultModel, defaultThinkingEffort);
118680
118535
  const appStatePatch = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@byfriends/cli",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "BYF (Be Your Friend), an AI coding agent that runs in your terminal",
5
5
  "license": "Proprietary",
6
6
  "author": "ByronFinn",
@@ -39,29 +39,6 @@
39
39
  "access": "public",
40
40
  "provenance": false
41
41
  },
42
- "dependencies": {
43
- "@earendil-works/pi-tui": "^0.74.0",
44
- "@mariozechner/clipboard": "^0.3.2",
45
- "chalk": "^5.4.1",
46
- "cli-highlight": "^2.1.11",
47
- "commander": "^13.1.0",
48
- "semver": "^7.7.4",
49
- "smol-toml": "^1.6.1",
50
- "zod": "^4.3.6"
51
- },
52
- "devDependencies": {
53
- "@types/semver": "^7.7.0",
54
- "@types/yazl": "^2.4.6",
55
- "postject": "1.0.0-alpha.6",
56
- "tsx": "^4.21.0",
57
- "yazl": "^3.3.1",
58
- "@byfriends/oauth": "^1.0.0",
59
- "@byfriends/sdk": "^1.0.0",
60
- "@byfriends/telemetry": "^0.0.2"
61
- },
62
- "engines": {
63
- "node": ">=22.19.0"
64
- },
65
42
  "scripts": {
66
43
  "build": "tsdown",
67
44
  "catalog:update": "node scripts/update-catalog.mjs --out dist/built-in-catalog.json",
@@ -81,5 +58,28 @@
81
58
  "e2e": "pnpm -w run build:packages && BYF_E2E=1 vitest run test/e2e",
82
59
  "e2e:real": "pnpm -w run build:packages && BYF_E2E_REAL=1 vitest run test/e2e/real-llm-smoke.e2e.test.ts",
83
60
  "postinstall": "node scripts/postinstall.mjs"
61
+ },
62
+ "dependencies": {
63
+ "@earendil-works/pi-tui": "^0.74.0",
64
+ "@mariozechner/clipboard": "^0.3.2",
65
+ "chalk": "^5.4.1",
66
+ "cli-highlight": "^2.1.11",
67
+ "commander": "^13.1.0",
68
+ "semver": "^7.7.4",
69
+ "smol-toml": "^1.6.1",
70
+ "zod": "^4.3.6"
71
+ },
72
+ "devDependencies": {
73
+ "@byfriends/oauth": "workspace:^",
74
+ "@byfriends/sdk": "workspace:^",
75
+ "@byfriends/telemetry": "workspace:^",
76
+ "@types/semver": "^7.7.0",
77
+ "@types/yazl": "^2.4.6",
78
+ "postject": "1.0.0-alpha.6",
79
+ "tsx": "^4.21.0",
80
+ "yazl": "^3.3.1"
81
+ },
82
+ "engines": {
83
+ "node": ">=22.19.0"
84
84
  }
85
- }
85
+ }
package/LICENSE DELETED
@@ -1,28 +0,0 @@
1
- BYF PROPRIETARY LICENSE
2
-
3
- Copyright (c) 2026-2027 ByronFinn
4
-
5
- Permission is hereby granted to copy and redistribute this software in its
6
- unmodified form, without charge. This permission does not extend to modified
7
- versions of the software.
8
-
9
- Local modification of this software for personal use is permitted, provided
10
- that such modifications are not distributed to third parties.
11
-
12
- Restrictions:
13
- 1. You may NOT redistribute modified versions of this software.
14
- 2. You may NOT use this software for commercial purposes.
15
- 3. You may NOT sublicense, sell, or offer this software as a service.
16
-
17
- This software is source-available but NOT open source. The source code is
18
- made publicly visible for review purposes only.
19
-
20
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26
- SOFTWARE.
27
-
28
- For questions about licensing, contact: https://github.com/ByronFinn/byf/issues