@cognipeer/agent-sdk 0.8.9 → 0.8.10

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/index.d.cts CHANGED
@@ -719,7 +719,8 @@ type ReflectionConfig = {
719
719
  onReflection?: (record: ReflectionRecord, ctx: ReflectionHookContext) => void;
720
720
  };
721
721
  type NativeReasoningConfig = {
722
- effort?: "minimal" | "low" | "medium" | "high";
722
+ /** `none` is OFF — a value that gets SENT. See ReasoningEffort in providers/types.ts. */
723
+ effort?: "none" | "minimal" | "low" | "medium" | "high";
723
724
  budgetTokens?: number;
724
725
  includeThoughts?: boolean;
725
726
  providerExtras?: Record<string, any>;
@@ -2918,7 +2919,18 @@ type ChatCompletionRequest = {
2918
2919
  */
2919
2920
  reasoning?: ReasoningRequestConfig;
2920
2921
  };
2921
- type ReasoningEffort = "minimal" | "low" | "medium" | "high";
2922
+ /**
2923
+ * `none` is OFF, and it is a value rather than the absence of one.
2924
+ *
2925
+ * On a thinking-by-default model — every Qwen3 under vLLM, gpt-5.1 and newer on
2926
+ * OpenAI — sending no reasoning field leaves the model thinking. So "do not
2927
+ * think" is an instruction that has to travel: `reasoning_effort:"none"` on
2928
+ * OpenAI, `thinkingBudget:0` on Gemini, and no thinking block at all on
2929
+ * Anthropic (where thinking is opt-in and the absence IS off). Omitting
2930
+ * `effort` still means "say nothing about reasoning", which is the different
2931
+ * and equally necessary state.
2932
+ */
2933
+ type ReasoningEffort = "none" | "minimal" | "low" | "medium" | "high";
2922
2934
  type ReasoningRequestConfig = {
2923
2935
  /** Qualitative effort hint (mapped per-provider). */
2924
2936
  effort?: ReasoningEffort;
@@ -2981,6 +2993,28 @@ type OpenAIProviderConfig = {
2981
2993
  defaultModel?: string;
2982
2994
  defaultHeaders?: Record<string, string>;
2983
2995
  retry?: ProviderRetryConfig;
2996
+ /**
2997
+ * WHICH API a reasoning-carrying request is addressed to.
2998
+ *
2999
+ * auto (default, and today's behaviour) route to the Responses API when
3000
+ * the request carries `reasoning` AND the model name looks like an
3001
+ * o-series/gpt-5 reasoning model.
3002
+ * never always Chat Completions. `reasoning` is still mapped, as
3003
+ * `reasoning_effort` plus any `providerExtras`.
3004
+ * always always Responses, whatever the model is called.
3005
+ *
3006
+ * `auto` is a name-based guess, and it decides far more than where reasoning
3007
+ * goes: Responses is a different request shape (`input` not `messages`,
3008
+ * `text.format` not `response_format`, flat tool objects) and a different
3009
+ * response parse. A caller with its own measurements of the Chat Completions
3010
+ * body — a gateway, a proxy, an on-prem server that serves one and not the
3011
+ * other, or anything that has tuned `extra` — must be able to say so, rather
3012
+ * than discover that asking for less thinking silently changed the transport.
3013
+ *
3014
+ * Applies to any OpenAI-shaped endpoint, which is also why the guess is weak
3015
+ * where it matters most: a self-hosted model is named by whoever served it.
3016
+ */
3017
+ responsesApi?: "auto" | "never" | "always";
2984
3018
  };
2985
3019
  type AnthropicProviderConfig = {
2986
3020
  provider: "anthropic";
@@ -3085,10 +3119,17 @@ declare class OpenAIProvider extends BaseProvider {
3085
3119
  protected readonly baseURL: string;
3086
3120
  protected readonly defaultModel: string;
3087
3121
  protected readonly defaultHeaders: Record<string, string>;
3122
+ protected readonly responsesApi: "auto" | "never" | "always";
3088
3123
  constructor(config: OpenAIProviderConfig);
3089
- /** True when the request targets a reasoning model (o-series / gpt-5) so we
3090
- * should route through the Responses API, which exposes `reasoning.effort`
3091
- * and reasoning summaries. Chat Completions silently drops these. */
3124
+ /** True when this request should go to the Responses API rather than Chat
3125
+ * Completions — which exposes `reasoning.effort` and reasoning summaries that
3126
+ * Chat Completions silently drops.
3127
+ *
3128
+ * `auto` (the default) keeps the historical rule: only when the request
3129
+ * carries a reasoning config AND the model name looks like an o-series/gpt-5
3130
+ * model. `never`/`always` let a caller state the answer instead, because the
3131
+ * name check is a guess and the two APIs differ in far more than reasoning —
3132
+ * see `responsesApi` in OpenAIProviderConfig. */
3092
3133
  protected useResponsesApi(request: ChatCompletionRequest): boolean;
3093
3134
  complete(request: ChatCompletionRequest): Promise<ChatCompletionResponse>;
3094
3135
  completeStream(request: ChatCompletionRequest): AsyncGenerator<ChatCompletionChunk, void, unknown>;
package/dist/index.d.ts CHANGED
@@ -719,7 +719,8 @@ type ReflectionConfig = {
719
719
  onReflection?: (record: ReflectionRecord, ctx: ReflectionHookContext) => void;
720
720
  };
721
721
  type NativeReasoningConfig = {
722
- effort?: "minimal" | "low" | "medium" | "high";
722
+ /** `none` is OFF — a value that gets SENT. See ReasoningEffort in providers/types.ts. */
723
+ effort?: "none" | "minimal" | "low" | "medium" | "high";
723
724
  budgetTokens?: number;
724
725
  includeThoughts?: boolean;
725
726
  providerExtras?: Record<string, any>;
@@ -2918,7 +2919,18 @@ type ChatCompletionRequest = {
2918
2919
  */
2919
2920
  reasoning?: ReasoningRequestConfig;
2920
2921
  };
2921
- type ReasoningEffort = "minimal" | "low" | "medium" | "high";
2922
+ /**
2923
+ * `none` is OFF, and it is a value rather than the absence of one.
2924
+ *
2925
+ * On a thinking-by-default model — every Qwen3 under vLLM, gpt-5.1 and newer on
2926
+ * OpenAI — sending no reasoning field leaves the model thinking. So "do not
2927
+ * think" is an instruction that has to travel: `reasoning_effort:"none"` on
2928
+ * OpenAI, `thinkingBudget:0` on Gemini, and no thinking block at all on
2929
+ * Anthropic (where thinking is opt-in and the absence IS off). Omitting
2930
+ * `effort` still means "say nothing about reasoning", which is the different
2931
+ * and equally necessary state.
2932
+ */
2933
+ type ReasoningEffort = "none" | "minimal" | "low" | "medium" | "high";
2922
2934
  type ReasoningRequestConfig = {
2923
2935
  /** Qualitative effort hint (mapped per-provider). */
2924
2936
  effort?: ReasoningEffort;
@@ -2981,6 +2993,28 @@ type OpenAIProviderConfig = {
2981
2993
  defaultModel?: string;
2982
2994
  defaultHeaders?: Record<string, string>;
2983
2995
  retry?: ProviderRetryConfig;
2996
+ /**
2997
+ * WHICH API a reasoning-carrying request is addressed to.
2998
+ *
2999
+ * auto (default, and today's behaviour) route to the Responses API when
3000
+ * the request carries `reasoning` AND the model name looks like an
3001
+ * o-series/gpt-5 reasoning model.
3002
+ * never always Chat Completions. `reasoning` is still mapped, as
3003
+ * `reasoning_effort` plus any `providerExtras`.
3004
+ * always always Responses, whatever the model is called.
3005
+ *
3006
+ * `auto` is a name-based guess, and it decides far more than where reasoning
3007
+ * goes: Responses is a different request shape (`input` not `messages`,
3008
+ * `text.format` not `response_format`, flat tool objects) and a different
3009
+ * response parse. A caller with its own measurements of the Chat Completions
3010
+ * body — a gateway, a proxy, an on-prem server that serves one and not the
3011
+ * other, or anything that has tuned `extra` — must be able to say so, rather
3012
+ * than discover that asking for less thinking silently changed the transport.
3013
+ *
3014
+ * Applies to any OpenAI-shaped endpoint, which is also why the guess is weak
3015
+ * where it matters most: a self-hosted model is named by whoever served it.
3016
+ */
3017
+ responsesApi?: "auto" | "never" | "always";
2984
3018
  };
2985
3019
  type AnthropicProviderConfig = {
2986
3020
  provider: "anthropic";
@@ -3085,10 +3119,17 @@ declare class OpenAIProvider extends BaseProvider {
3085
3119
  protected readonly baseURL: string;
3086
3120
  protected readonly defaultModel: string;
3087
3121
  protected readonly defaultHeaders: Record<string, string>;
3122
+ protected readonly responsesApi: "auto" | "never" | "always";
3088
3123
  constructor(config: OpenAIProviderConfig);
3089
- /** True when the request targets a reasoning model (o-series / gpt-5) so we
3090
- * should route through the Responses API, which exposes `reasoning.effort`
3091
- * and reasoning summaries. Chat Completions silently drops these. */
3124
+ /** True when this request should go to the Responses API rather than Chat
3125
+ * Completions — which exposes `reasoning.effort` and reasoning summaries that
3126
+ * Chat Completions silently drops.
3127
+ *
3128
+ * `auto` (the default) keeps the historical rule: only when the request
3129
+ * carries a reasoning config AND the model name looks like an o-series/gpt-5
3130
+ * model. `never`/`always` let a caller state the answer instead, because the
3131
+ * name check is a guess and the two APIs differ in far more than reasoning —
3132
+ * see `responsesApi` in OpenAIProviderConfig. */
3092
3133
  protected useResponsesApi(request: ChatCompletionRequest): boolean;
3093
3134
  complete(request: ChatCompletionRequest): Promise<ChatCompletionResponse>;
3094
3135
  completeStream(request: ChatCompletionRequest): AsyncGenerator<ChatCompletionChunk, void, unknown>;
package/dist/index.mjs CHANGED
@@ -4289,7 +4289,7 @@ var LEVEL_DEFAULTS = {
4289
4289
  };
4290
4290
  var VALID_LEVELS = ["minimal", "low", "medium", "high"];
4291
4291
  var VALID_CADENCES = ["off", "every_turn", "after_tool", "on_branch", "initial_then_after_tool"];
4292
- var VALID_EFFORTS = ["minimal", "low", "medium", "high"];
4292
+ var VALID_EFFORTS = ["none", "minimal", "low", "medium", "high"];
4293
4293
  function validateReasoningConfig(input) {
4294
4294
  if (!input) return;
4295
4295
  if (input.level !== void 0 && !VALID_LEVELS.includes(input.level)) {
@@ -8783,12 +8783,19 @@ function parseSSEBlock(block) {
8783
8783
 
8784
8784
  // src/providers/utils/reasoning.ts
8785
8785
  var ANTHROPIC_EFFORT_BUDGET = {
8786
+ // 0 = off. `applyAnthropicReasoning` bails on a falsy budget and emits no
8787
+ // thinking block, which on Anthropic IS off — thinking there is opt-in.
8788
+ none: 0,
8786
8789
  minimal: 1024,
8787
8790
  low: 2048,
8788
8791
  medium: 8192,
8789
8792
  high: 16384
8790
8793
  };
8791
8794
  var GEMINI_EFFORT_BUDGET = {
8795
+ // 0 is Gemini's own documented spelling for "do not think", and unlike
8796
+ // Anthropic it has to be SENT — hence `applyGeminiReasoning` testing for null
8797
+ // rather than falsiness.
8798
+ none: 0,
8792
8799
  minimal: 512,
8793
8800
  low: 1024,
8794
8801
  medium: 4096,
@@ -8864,14 +8871,15 @@ function clampBudget(budget, maxTokens) {
8864
8871
  }
8865
8872
  function normalizeEffort(effort) {
8866
8873
  if (!effort) return void 0;
8867
- const allowed = ["minimal", "low", "medium", "high"];
8874
+ const allowed = ["none", "minimal", "low", "medium", "high"];
8868
8875
  return allowed.includes(effort) ? effort : void 0;
8869
8876
  }
8870
8877
  function resolveBudget(reasoning, effortBudget) {
8878
+ const effort = normalizeEffort(reasoning.effort);
8879
+ if (effort === "none") return 0;
8871
8880
  if (typeof reasoning.budgetTokens === "number" && reasoning.budgetTokens > 0) {
8872
8881
  return Math.floor(reasoning.budgetTokens);
8873
8882
  }
8874
- const effort = normalizeEffort(reasoning.effort);
8875
8883
  if (effort && effortBudget[effort]) return effortBudget[effort];
8876
8884
  return void 0;
8877
8885
  }
@@ -8960,12 +8968,21 @@ var OpenAIProvider = class extends BaseProvider {
8960
8968
  ...config.defaultHeaders,
8961
8969
  ...config.organization ? { "OpenAI-Organization": config.organization } : {}
8962
8970
  };
8971
+ this.responsesApi = config.responsesApi ?? "auto";
8963
8972
  if (config.retry) this.retryPolicy = { ...this.retryPolicy, ...config.retry };
8964
8973
  }
8965
- /** True when the request targets a reasoning model (o-series / gpt-5) so we
8966
- * should route through the Responses API, which exposes `reasoning.effort`
8967
- * and reasoning summaries. Chat Completions silently drops these. */
8974
+ /** True when this request should go to the Responses API rather than Chat
8975
+ * Completions — which exposes `reasoning.effort` and reasoning summaries that
8976
+ * Chat Completions silently drops.
8977
+ *
8978
+ * `auto` (the default) keeps the historical rule: only when the request
8979
+ * carries a reasoning config AND the model name looks like an o-series/gpt-5
8980
+ * model. `never`/`always` let a caller state the answer instead, because the
8981
+ * name check is a guess and the two APIs differ in far more than reasoning —
8982
+ * see `responsesApi` in OpenAIProviderConfig. */
8968
8983
  useResponsesApi(request) {
8984
+ if (this.responsesApi === "never") return false;
8985
+ if (this.responsesApi === "always") return true;
8969
8986
  if (!request.reasoning) return false;
8970
8987
  return isReasoningModel(request.model || this.defaultModel);
8971
8988
  }
@@ -10828,7 +10845,7 @@ function fromNativeProvider(provider, options) {
10828
10845
  if (tools?.length) req.tools = tools;
10829
10846
  if (opts?.extra) req.extra = opts.extra;
10830
10847
  const reasoningOverride = invokeOptions?.reasoning;
10831
- const reasoningCfg = reasoningOverride ?? opts?.reasoning;
10848
+ const reasoningCfg = mergeReasoning(opts?.reasoning, reasoningOverride);
10832
10849
  if (reasoningCfg) req.reasoning = reasoningCfg;
10833
10850
  const tc = invokeOptions?.tool_choice ?? invokeOptions?.toolChoice;
10834
10851
  if (tc && tools?.length) {
@@ -10857,6 +10874,15 @@ function fromNativeProvider(provider, options) {
10857
10874
  return req;
10858
10875
  }
10859
10876
  }
10877
+ function mergeReasoning(base, override) {
10878
+ if (!base) return override;
10879
+ if (!override) return base;
10880
+ const merged = { ...base, ...override };
10881
+ if (base.providerExtras || override.providerExtras) {
10882
+ merged.providerExtras = { ...base.providerExtras, ...override.providerExtras };
10883
+ }
10884
+ return merged;
10885
+ }
10860
10886
  function toUnifiedMessage(msg) {
10861
10887
  const unified = {
10862
10888
  role: msg.role,