@dreb/ai 2.43.2 → 2.43.3

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/README.md CHANGED
@@ -830,16 +830,27 @@ await streamAnthropic(claude, context, options);
830
830
 
831
831
  ## Cross-Provider Handoffs
832
832
 
833
- The library supports seamless handoffs between different LLM providers within the same conversation. This allows you to switch models mid-conversation while preserving context, including thinking blocks, tool calls, and tool results.
833
+ The library can prepare one conversation for another model without changing the stored `Context`. User messages, visible assistant text, tool calls, and tool results remain available, while model-bound tool signatures and IDs are normalized for the destination. Provider-specific reasoning state is handled conservatively.
834
834
 
835
- ### How It Works
835
+ ### Reasoning State Compatibility
836
836
 
837
- When messages from one provider are sent to a different provider, the library automatically transforms them for compatibility:
837
+ - **Exact model:** signed, encrypted, and redacted reasoning state is replayed unchanged.
838
+ - **Compatible model switch:** structured reasoning is preserved only when source and target share a provider, both use `openai-completions`, the destination accepts structured reasoning, and the source uses a recognized plain field: `reasoning_content`, `reasoning`, or `reasoning_text`.
839
+ - **Other readable reasoning:** it is retained as labelled plaintext inside `<reformatted-pre-switch-reasoning>` markers, with incompatible protocol metadata stripped.
840
+ - **Opaque state:** redacted or encrypted-only reasoning is omitted for incompatible targets.
838
841
 
839
- - **User and tool result messages** are passed through unchanged
840
- - **Assistant messages from the same provider/API** are preserved as-is
841
- - **Assistant messages from different providers** have their thinking blocks converted to text with `<thinking>` tags
842
- - **Tool calls and regular text** are preserved unchanged
842
+ Compatibility depends on provider, API, and signature behavior. This includes custom models: two models at the same endpoint are not compatible merely because their IDs or URLs match; they must share the configured provider identity as well.
843
+
844
+ The transformation applies only to the outbound request. It does not mutate `Context.messages`, so a later switch back to the original model can replay its original reasoning state unless that history has been compacted or pruned by the caller.
845
+
846
+ ### Examples
847
+
848
+ | Source and target | Outbound reasoning state |
849
+ |---|---|
850
+ | The same model | Original signed, encrypted, or redacted state is replayed unchanged. |
851
+ | Two models under the same custom provider, both using `openai-completions`, where the destination accepts the source's `reasoning_content`, `reasoning`, or `reasoning_text` field | Recognized plain structured reasoning is preserved. |
852
+ | Different providers or APIs with readable reasoning | Reasoning is sent as labelled plaintext in `<reformatted-pre-switch-reasoning>` markers. |
853
+ | An incompatible target with redacted or encrypted-only reasoning | Opaque reasoning state is omitted. |
843
854
 
844
855
  ### Example: Multi-Provider Conversation
845
856
 
@@ -858,32 +869,17 @@ const claudeResponse = await complete(claude, context, {
858
869
  });
859
870
  context.messages.push(claudeResponse);
860
871
 
861
- // Switch to GPT-5 - it will see Claude's thinking as <thinking> tagged text
872
+ // Switch to GPT-5. Readable Claude reasoning is reformatted for this outbound request.
862
873
  const gpt5 = getModel('openai', 'gpt-5-mini');
863
874
  context.messages.push({ role: 'user', content: 'Is that calculation correct?' });
864
875
  const gptResponse = await complete(gpt5, context);
865
876
  context.messages.push(gptResponse);
866
877
 
867
- // Switch to Gemini
868
- const gemini = getModel('google', 'gemini-2.5-flash');
878
+ // Switching back to Claude can use the original Claude state in context.
869
879
  context.messages.push({ role: 'user', content: 'What was the original question?' });
870
- const geminiResponse = await complete(gemini, context);
880
+ const finalClaudeResponse = await complete(claude, context);
871
881
  ```
872
882
 
873
- ### Provider Compatibility
874
-
875
- All providers can handle messages from other providers, including:
876
- - Text content
877
- - Tool calls and tool results (including images in tool results)
878
- - Thinking/reasoning blocks (transformed to tagged text for cross-provider compatibility)
879
- - Aborted messages with partial content
880
-
881
- This enables flexible workflows where you can:
882
- - Start with a fast model for initial responses
883
- - Switch to a more capable model for complex reasoning
884
- - Use specialized models for specific tasks
885
- - Maintain conversation continuity across provider outages
886
-
887
883
  ## Context Serialization
888
884
 
889
885
  The `Context` object can be easily serialized and deserialized using standard JSON methods, making it simple to persist conversations, implement chat history, or transfer contexts between services:
@@ -7878,7 +7878,7 @@ export declare const MODELS: {
7878
7878
  readonly "grok-4.5": {
7879
7879
  id: string;
7880
7880
  name: string;
7881
- api: "openai-completions";
7881
+ api: "openai-responses";
7882
7882
  provider: string;
7883
7883
  baseUrl: string;
7884
7884
  reasoning: true;
@@ -8186,7 +8186,7 @@ export declare const MODELS: {
8186
8186
  readonly "grok-4.5": {
8187
8187
  id: string;
8188
8188
  name: string;
8189
- api: "openai-completions";
8189
+ api: "openai-responses";
8190
8190
  provider: string;
8191
8191
  baseUrl: string;
8192
8192
  reasoning: true;
@@ -9613,23 +9613,6 @@ export declare const MODELS: {
9613
9613
  contextWindow: number;
9614
9614
  maxTokens: number;
9615
9615
  };
9616
- readonly "meta-llama/llama-3.3-70b-instruct:free": {
9617
- id: string;
9618
- name: string;
9619
- api: "openai-completions";
9620
- provider: string;
9621
- baseUrl: string;
9622
- reasoning: false;
9623
- input: "text"[];
9624
- cost: {
9625
- input: number;
9626
- output: number;
9627
- cacheRead: number;
9628
- cacheWrite: number;
9629
- };
9630
- contextWindow: number;
9631
- maxTokens: number;
9632
- };
9633
9616
  readonly "meta-llama/llama-4-maverick": {
9634
9617
  id: string;
9635
9618
  name: string;
@@ -11823,23 +11806,6 @@ export declare const MODELS: {
11823
11806
  contextWindow: number;
11824
11807
  maxTokens: number;
11825
11808
  };
11826
- readonly "qwen/qwen3-coder:free": {
11827
- id: string;
11828
- name: string;
11829
- api: "openai-completions";
11830
- provider: string;
11831
- baseUrl: string;
11832
- reasoning: false;
11833
- input: "text"[];
11834
- cost: {
11835
- input: number;
11836
- output: number;
11837
- cacheRead: number;
11838
- cacheWrite: number;
11839
- };
11840
- contextWindow: number;
11841
- maxTokens: number;
11842
- };
11843
11809
  readonly "qwen/qwen3-max": {
11844
11810
  id: string;
11845
11811
  name: string;
@@ -11891,23 +11857,6 @@ export declare const MODELS: {
11891
11857
  contextWindow: number;
11892
11858
  maxTokens: number;
11893
11859
  };
11894
- readonly "qwen/qwen3-next-80b-a3b-instruct:free": {
11895
- id: string;
11896
- name: string;
11897
- api: "openai-completions";
11898
- provider: string;
11899
- baseUrl: string;
11900
- reasoning: false;
11901
- input: "text"[];
11902
- cost: {
11903
- input: number;
11904
- output: number;
11905
- cacheRead: number;
11906
- cacheWrite: number;
11907
- };
11908
- contextWindow: number;
11909
- maxTokens: number;
11910
- };
11911
11860
  readonly "qwen/qwen3-next-80b-a3b-thinking": {
11912
11861
  id: string;
11913
11862
  name: string;