illuma-agents 1.0.8 → 1.0.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.
Files changed (250) hide show
  1. package/LICENSE +1 -5
  2. package/dist/cjs/common/enum.cjs +1 -2
  3. package/dist/cjs/common/enum.cjs.map +1 -1
  4. package/dist/cjs/events.cjs +11 -0
  5. package/dist/cjs/events.cjs.map +1 -1
  6. package/dist/cjs/graphs/Graph.cjs +2 -1
  7. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  8. package/dist/cjs/instrumentation.cjs +3 -1
  9. package/dist/cjs/instrumentation.cjs.map +1 -1
  10. package/dist/cjs/llm/anthropic/types.cjs.map +1 -1
  11. package/dist/cjs/llm/anthropic/utils/message_inputs.cjs +79 -2
  12. package/dist/cjs/llm/anthropic/utils/message_inputs.cjs.map +1 -1
  13. package/dist/cjs/llm/anthropic/utils/tools.cjs.map +1 -1
  14. package/dist/cjs/llm/bedrock/index.cjs +99 -0
  15. package/dist/cjs/llm/bedrock/index.cjs.map +1 -0
  16. package/dist/cjs/llm/fake.cjs.map +1 -1
  17. package/dist/cjs/llm/openai/index.cjs +102 -0
  18. package/dist/cjs/llm/openai/index.cjs.map +1 -1
  19. package/dist/cjs/llm/openai/utils/index.cjs +87 -1
  20. package/dist/cjs/llm/openai/utils/index.cjs.map +1 -1
  21. package/dist/cjs/llm/openrouter/index.cjs +175 -1
  22. package/dist/cjs/llm/openrouter/index.cjs.map +1 -1
  23. package/dist/cjs/llm/providers.cjs +13 -16
  24. package/dist/cjs/llm/providers.cjs.map +1 -1
  25. package/dist/cjs/llm/text.cjs.map +1 -1
  26. package/dist/cjs/messages/core.cjs +14 -14
  27. package/dist/cjs/messages/core.cjs.map +1 -1
  28. package/dist/cjs/messages/ids.cjs.map +1 -1
  29. package/dist/cjs/messages/prune.cjs.map +1 -1
  30. package/dist/cjs/run.cjs +18 -1
  31. package/dist/cjs/run.cjs.map +1 -1
  32. package/dist/cjs/splitStream.cjs.map +1 -1
  33. package/dist/cjs/stream.cjs +24 -1
  34. package/dist/cjs/stream.cjs.map +1 -1
  35. package/dist/cjs/tools/ToolNode.cjs +20 -1
  36. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  37. package/dist/cjs/tools/handlers.cjs +29 -25
  38. package/dist/cjs/tools/handlers.cjs.map +1 -1
  39. package/dist/cjs/tools/search/anthropic.cjs.map +1 -1
  40. package/dist/cjs/tools/search/content.cjs.map +1 -1
  41. package/dist/cjs/tools/search/firecrawl.cjs.map +1 -1
  42. package/dist/cjs/tools/search/format.cjs.map +1 -1
  43. package/dist/cjs/tools/search/highlights.cjs.map +1 -1
  44. package/dist/cjs/tools/search/rerankers.cjs.map +1 -1
  45. package/dist/cjs/tools/search/schema.cjs +27 -25
  46. package/dist/cjs/tools/search/schema.cjs.map +1 -1
  47. package/dist/cjs/tools/search/search.cjs +6 -1
  48. package/dist/cjs/tools/search/search.cjs.map +1 -1
  49. package/dist/cjs/tools/search/serper-scraper.cjs.map +1 -1
  50. package/dist/cjs/tools/search/tool.cjs +182 -35
  51. package/dist/cjs/tools/search/tool.cjs.map +1 -1
  52. package/dist/cjs/tools/search/utils.cjs.map +1 -1
  53. package/dist/cjs/utils/graph.cjs.map +1 -1
  54. package/dist/cjs/utils/llm.cjs +0 -1
  55. package/dist/cjs/utils/llm.cjs.map +1 -1
  56. package/dist/cjs/utils/misc.cjs.map +1 -1
  57. package/dist/cjs/utils/run.cjs.map +1 -1
  58. package/dist/cjs/utils/title.cjs +7 -7
  59. package/dist/cjs/utils/title.cjs.map +1 -1
  60. package/dist/esm/common/enum.mjs +1 -2
  61. package/dist/esm/common/enum.mjs.map +1 -1
  62. package/dist/esm/events.mjs +11 -0
  63. package/dist/esm/events.mjs.map +1 -1
  64. package/dist/esm/graphs/Graph.mjs +2 -1
  65. package/dist/esm/graphs/Graph.mjs.map +1 -1
  66. package/dist/esm/instrumentation.mjs +3 -1
  67. package/dist/esm/instrumentation.mjs.map +1 -1
  68. package/dist/esm/llm/anthropic/types.mjs.map +1 -1
  69. package/dist/esm/llm/anthropic/utils/message_inputs.mjs +79 -2
  70. package/dist/esm/llm/anthropic/utils/message_inputs.mjs.map +1 -1
  71. package/dist/esm/llm/anthropic/utils/tools.mjs.map +1 -1
  72. package/dist/esm/llm/bedrock/index.mjs +97 -0
  73. package/dist/esm/llm/bedrock/index.mjs.map +1 -0
  74. package/dist/esm/llm/fake.mjs.map +1 -1
  75. package/dist/esm/llm/openai/index.mjs +103 -1
  76. package/dist/esm/llm/openai/index.mjs.map +1 -1
  77. package/dist/esm/llm/openai/utils/index.mjs +88 -2
  78. package/dist/esm/llm/openai/utils/index.mjs.map +1 -1
  79. package/dist/esm/llm/openrouter/index.mjs +175 -1
  80. package/dist/esm/llm/openrouter/index.mjs.map +1 -1
  81. package/dist/esm/llm/providers.mjs +2 -5
  82. package/dist/esm/llm/providers.mjs.map +1 -1
  83. package/dist/esm/llm/text.mjs.map +1 -1
  84. package/dist/esm/messages/core.mjs +14 -14
  85. package/dist/esm/messages/core.mjs.map +1 -1
  86. package/dist/esm/messages/ids.mjs.map +1 -1
  87. package/dist/esm/messages/prune.mjs.map +1 -1
  88. package/dist/esm/run.mjs +18 -1
  89. package/dist/esm/run.mjs.map +1 -1
  90. package/dist/esm/splitStream.mjs.map +1 -1
  91. package/dist/esm/stream.mjs +24 -1
  92. package/dist/esm/stream.mjs.map +1 -1
  93. package/dist/esm/tools/ToolNode.mjs +20 -1
  94. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  95. package/dist/esm/tools/handlers.mjs +30 -26
  96. package/dist/esm/tools/handlers.mjs.map +1 -1
  97. package/dist/esm/tools/search/anthropic.mjs.map +1 -1
  98. package/dist/esm/tools/search/content.mjs.map +1 -1
  99. package/dist/esm/tools/search/firecrawl.mjs.map +1 -1
  100. package/dist/esm/tools/search/format.mjs.map +1 -1
  101. package/dist/esm/tools/search/highlights.mjs.map +1 -1
  102. package/dist/esm/tools/search/rerankers.mjs.map +1 -1
  103. package/dist/esm/tools/search/schema.mjs +27 -25
  104. package/dist/esm/tools/search/schema.mjs.map +1 -1
  105. package/dist/esm/tools/search/search.mjs +6 -1
  106. package/dist/esm/tools/search/search.mjs.map +1 -1
  107. package/dist/esm/tools/search/serper-scraper.mjs.map +1 -1
  108. package/dist/esm/tools/search/tool.mjs +182 -35
  109. package/dist/esm/tools/search/tool.mjs.map +1 -1
  110. package/dist/esm/tools/search/utils.mjs.map +1 -1
  111. package/dist/esm/utils/graph.mjs.map +1 -1
  112. package/dist/esm/utils/llm.mjs +0 -1
  113. package/dist/esm/utils/llm.mjs.map +1 -1
  114. package/dist/esm/utils/misc.mjs.map +1 -1
  115. package/dist/esm/utils/run.mjs.map +1 -1
  116. package/dist/esm/utils/title.mjs +7 -7
  117. package/dist/esm/utils/title.mjs.map +1 -1
  118. package/dist/types/common/enum.d.ts +1 -2
  119. package/dist/types/llm/bedrock/index.d.ts +36 -0
  120. package/dist/types/llm/openai/index.d.ts +1 -0
  121. package/dist/types/llm/openai/utils/index.d.ts +10 -1
  122. package/dist/types/llm/openrouter/index.d.ts +4 -1
  123. package/dist/types/tools/search/types.d.ts +2 -0
  124. package/dist/types/types/llm.d.ts +3 -8
  125. package/package.json +16 -12
  126. package/src/common/enum.ts +1 -2
  127. package/src/common/index.ts +1 -1
  128. package/src/events.ts +11 -0
  129. package/src/graphs/Graph.ts +2 -1
  130. package/src/instrumentation.ts +25 -22
  131. package/src/llm/anthropic/llm.spec.ts +1442 -1442
  132. package/src/llm/anthropic/types.ts +140 -140
  133. package/src/llm/anthropic/utils/message_inputs.ts +757 -660
  134. package/src/llm/anthropic/utils/output_parsers.ts +133 -133
  135. package/src/llm/anthropic/utils/tools.ts +29 -29
  136. package/src/llm/bedrock/index.ts +128 -0
  137. package/src/llm/fake.ts +133 -133
  138. package/src/llm/google/llm.spec.ts +3 -1
  139. package/src/llm/google/utils/tools.ts +160 -160
  140. package/src/llm/openai/index.ts +126 -0
  141. package/src/llm/openai/types.ts +24 -24
  142. package/src/llm/openai/utils/index.ts +116 -1
  143. package/src/llm/openai/utils/isReasoningModel.test.ts +90 -90
  144. package/src/llm/openrouter/index.ts +222 -1
  145. package/src/llm/providers.ts +2 -7
  146. package/src/llm/text.ts +94 -94
  147. package/src/messages/core.ts +463 -463
  148. package/src/messages/formatAgentMessages.tools.test.ts +400 -400
  149. package/src/messages/formatMessage.test.ts +693 -693
  150. package/src/messages/ids.ts +26 -26
  151. package/src/messages/prune.ts +567 -567
  152. package/src/messages/shiftIndexTokenCountMap.test.ts +81 -81
  153. package/src/mockStream.ts +98 -98
  154. package/src/prompts/collab.ts +5 -5
  155. package/src/prompts/index.ts +1 -1
  156. package/src/prompts/taskmanager.ts +61 -61
  157. package/src/run.ts +22 -4
  158. package/src/scripts/ant_web_search_edge_case.ts +162 -0
  159. package/src/scripts/ant_web_search_error_edge_case.ts +148 -0
  160. package/src/scripts/args.ts +48 -48
  161. package/src/scripts/caching.ts +123 -123
  162. package/src/scripts/code_exec_files.ts +193 -193
  163. package/src/scripts/empty_input.ts +137 -137
  164. package/src/scripts/memory.ts +97 -97
  165. package/src/scripts/test-tools-before-handoff.ts +1 -5
  166. package/src/scripts/thinking.ts +149 -149
  167. package/src/scripts/tools.ts +1 -4
  168. package/src/specs/anthropic.simple.test.ts +67 -0
  169. package/src/specs/spec.utils.ts +3 -3
  170. package/src/specs/token-distribution-edge-case.test.ts +316 -316
  171. package/src/specs/tool-error.test.ts +193 -193
  172. package/src/splitStream.test.ts +691 -691
  173. package/src/splitStream.ts +234 -234
  174. package/src/stream.test.ts +94 -94
  175. package/src/stream.ts +30 -1
  176. package/src/tools/ToolNode.ts +24 -1
  177. package/src/tools/handlers.ts +32 -28
  178. package/src/tools/search/anthropic.ts +51 -51
  179. package/src/tools/search/content.test.ts +173 -173
  180. package/src/tools/search/content.ts +147 -147
  181. package/src/tools/search/direct-url.test.ts +530 -0
  182. package/src/tools/search/firecrawl.ts +210 -210
  183. package/src/tools/search/format.ts +250 -250
  184. package/src/tools/search/highlights.ts +320 -320
  185. package/src/tools/search/index.ts +2 -2
  186. package/src/tools/search/jina-reranker.test.ts +126 -126
  187. package/src/tools/search/output.md +2775 -2775
  188. package/src/tools/search/rerankers.ts +242 -242
  189. package/src/tools/search/schema.ts +65 -63
  190. package/src/tools/search/search.ts +766 -759
  191. package/src/tools/search/serper-scraper.ts +155 -155
  192. package/src/tools/search/test.html +883 -883
  193. package/src/tools/search/test.md +642 -642
  194. package/src/tools/search/test.ts +159 -159
  195. package/src/tools/search/tool.ts +641 -471
  196. package/src/tools/search/types.ts +689 -687
  197. package/src/tools/search/utils.ts +79 -79
  198. package/src/types/index.ts +6 -6
  199. package/src/types/llm.ts +2 -8
  200. package/src/utils/graph.ts +10 -10
  201. package/src/utils/llm.ts +26 -27
  202. package/src/utils/llmConfig.ts +13 -5
  203. package/src/utils/logging.ts +48 -48
  204. package/src/utils/misc.ts +57 -57
  205. package/src/utils/run.ts +100 -100
  206. package/src/utils/title.ts +165 -165
  207. package/dist/cjs/llm/ollama/index.cjs +0 -70
  208. package/dist/cjs/llm/ollama/index.cjs.map +0 -1
  209. package/dist/cjs/llm/ollama/utils.cjs +0 -158
  210. package/dist/cjs/llm/ollama/utils.cjs.map +0 -1
  211. package/dist/esm/llm/ollama/index.mjs +0 -68
  212. package/dist/esm/llm/ollama/index.mjs.map +0 -1
  213. package/dist/esm/llm/ollama/utils.mjs +0 -155
  214. package/dist/esm/llm/ollama/utils.mjs.map +0 -1
  215. package/dist/types/llm/ollama/index.d.ts +0 -8
  216. package/dist/types/llm/ollama/utils.d.ts +0 -7
  217. package/src/llm/ollama/index.ts +0 -92
  218. package/src/llm/ollama/utils.ts +0 -193
  219. package/src/proto/CollabGraph.ts +0 -269
  220. package/src/proto/TaskManager.ts +0 -243
  221. package/src/proto/collab.ts +0 -200
  222. package/src/proto/collab_design.ts +0 -184
  223. package/src/proto/collab_design_v2.ts +0 -224
  224. package/src/proto/collab_design_v3.ts +0 -255
  225. package/src/proto/collab_design_v4.ts +0 -220
  226. package/src/proto/collab_design_v5.ts +0 -251
  227. package/src/proto/collab_graph.ts +0 -181
  228. package/src/proto/collab_original.ts +0 -123
  229. package/src/proto/example.ts +0 -93
  230. package/src/proto/example_new.ts +0 -68
  231. package/src/proto/example_old.ts +0 -201
  232. package/src/proto/example_test.ts +0 -152
  233. package/src/proto/example_test_anthropic.ts +0 -100
  234. package/src/proto/log_stream.ts +0 -202
  235. package/src/proto/main_collab_community_event.ts +0 -133
  236. package/src/proto/main_collab_design_v2.ts +0 -96
  237. package/src/proto/main_collab_design_v4.ts +0 -100
  238. package/src/proto/main_collab_design_v5.ts +0 -135
  239. package/src/proto/main_collab_global_analysis.ts +0 -122
  240. package/src/proto/main_collab_hackathon_event.ts +0 -153
  241. package/src/proto/main_collab_space_mission.ts +0 -153
  242. package/src/proto/main_philosophy.ts +0 -210
  243. package/src/proto/original_script.ts +0 -126
  244. package/src/proto/standard.ts +0 -100
  245. package/src/proto/stream.ts +0 -56
  246. package/src/proto/tasks.ts +0 -118
  247. package/src/proto/tools/global_analysis_tools.ts +0 -86
  248. package/src/proto/tools/space_mission_tools.ts +0 -60
  249. package/src/proto/vertexai.ts +0 -54
  250. package/src/scripts/image.ts +0 -178
@@ -643,6 +643,132 @@ export class ChatDeepSeek extends OriginalChatDeepSeek {
643
643
  } as OpenAICoreRequestOptions;
644
644
  return requestOptions;
645
645
  }
646
+
647
+ async *_streamResponseChunks(
648
+ messages: BaseMessage[],
649
+ options: this['ParsedCallOptions'],
650
+ runManager?: CallbackManagerForLLMRun
651
+ ): AsyncGenerator<ChatGenerationChunk> {
652
+ const messagesMapped: OpenAICompletionParam[] =
653
+ _convertMessagesToOpenAIParams(messages, this.model, {
654
+ includeReasoningContent: true,
655
+ });
656
+
657
+ const params = {
658
+ ...this.invocationParams(options, {
659
+ streaming: true,
660
+ }),
661
+ messages: messagesMapped,
662
+ stream: true as const,
663
+ };
664
+ let defaultRole: OpenAIRoleEnum | undefined;
665
+
666
+ const streamIterable = await this.completionWithRetry(params, options);
667
+ let usage: OpenAIClient.Completions.CompletionUsage | undefined;
668
+ for await (const data of streamIterable) {
669
+ const choice = data.choices[0] as
670
+ | Partial<OpenAIClient.Chat.Completions.ChatCompletionChunk.Choice>
671
+ | undefined;
672
+ if (data.usage) {
673
+ usage = data.usage;
674
+ }
675
+ if (!choice) {
676
+ continue;
677
+ }
678
+
679
+ const { delta } = choice;
680
+ if (!delta) {
681
+ continue;
682
+ }
683
+ const chunk = this._convertOpenAIDeltaToBaseMessageChunk(
684
+ delta,
685
+ data,
686
+ defaultRole
687
+ );
688
+ if ('reasoning_content' in delta) {
689
+ chunk.additional_kwargs.reasoning_content = delta.reasoning_content;
690
+ }
691
+ defaultRole = delta.role ?? defaultRole;
692
+ const newTokenIndices = {
693
+ prompt: (options as OpenAIChatCallOptions).promptIndex ?? 0,
694
+ completion: choice.index ?? 0,
695
+ };
696
+ if (typeof chunk.content !== 'string') {
697
+ // eslint-disable-next-line no-console
698
+ console.log(
699
+ '[WARNING]: Received non-string content from OpenAI. This is currently not supported.'
700
+ );
701
+ continue;
702
+ }
703
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
704
+ const generationInfo: Record<string, any> = { ...newTokenIndices };
705
+ if (choice.finish_reason != null) {
706
+ generationInfo.finish_reason = choice.finish_reason;
707
+ generationInfo.system_fingerprint = data.system_fingerprint;
708
+ generationInfo.model_name = data.model;
709
+ generationInfo.service_tier = data.service_tier;
710
+ }
711
+ if (this.logprobs == true) {
712
+ generationInfo.logprobs = choice.logprobs;
713
+ }
714
+ const generationChunk = new ChatGenerationChunk({
715
+ message: chunk,
716
+ text: chunk.content,
717
+ generationInfo,
718
+ });
719
+ yield generationChunk;
720
+ await runManager?.handleLLMNewToken(
721
+ generationChunk.text || '',
722
+ newTokenIndices,
723
+ undefined,
724
+ undefined,
725
+ undefined,
726
+ { chunk: generationChunk }
727
+ );
728
+ }
729
+ if (usage) {
730
+ const inputTokenDetails = {
731
+ ...(usage.prompt_tokens_details?.audio_tokens != null && {
732
+ audio: usage.prompt_tokens_details.audio_tokens,
733
+ }),
734
+ ...(usage.prompt_tokens_details?.cached_tokens != null && {
735
+ cache_read: usage.prompt_tokens_details.cached_tokens,
736
+ }),
737
+ };
738
+ const outputTokenDetails = {
739
+ ...(usage.completion_tokens_details?.audio_tokens != null && {
740
+ audio: usage.completion_tokens_details.audio_tokens,
741
+ }),
742
+ ...(usage.completion_tokens_details?.reasoning_tokens != null && {
743
+ reasoning: usage.completion_tokens_details.reasoning_tokens,
744
+ }),
745
+ };
746
+ const generationChunk = new ChatGenerationChunk({
747
+ message: new AIMessageChunk({
748
+ content: '',
749
+ response_metadata: {
750
+ usage: { ...usage },
751
+ },
752
+ usage_metadata: {
753
+ input_tokens: usage.prompt_tokens,
754
+ output_tokens: usage.completion_tokens,
755
+ total_tokens: usage.total_tokens,
756
+ ...(Object.keys(inputTokenDetails).length > 0 && {
757
+ input_token_details: inputTokenDetails,
758
+ }),
759
+ ...(Object.keys(outputTokenDetails).length > 0 && {
760
+ output_token_details: outputTokenDetails,
761
+ }),
762
+ },
763
+ }),
764
+ text: '',
765
+ });
766
+ yield generationChunk;
767
+ }
768
+ if (options.signal?.aborted === true) {
769
+ throw new Error('AbortError');
770
+ }
771
+ }
646
772
  }
647
773
 
648
774
  /** xAI-specific usage metadata type */
@@ -1,24 +1,24 @@
1
- import type { OpenAICallOptions } from '@langchain/openai';
2
-
3
- export interface OpenAIChatCallOptions extends OpenAICallOptions {
4
- promptIndex?: number;
5
- }
6
-
7
- // TODO import from SDK when available
8
- export type OpenAIRoleEnum =
9
- | 'system'
10
- | 'developer'
11
- | 'assistant'
12
- | 'user'
13
- | 'function'
14
- | 'tool';
15
-
16
- export type HeaderValue = string | undefined | null;
17
- export type HeadersLike =
18
- | Headers
19
- | readonly HeaderValue[][]
20
- | Record<string, HeaderValue | readonly HeaderValue[]>
21
- | undefined
22
- | null
23
- // NullableHeaders
24
- | { values: Headers; [key: string]: unknown };
1
+ import type { OpenAICallOptions } from '@langchain/openai';
2
+
3
+ export interface OpenAIChatCallOptions extends OpenAICallOptions {
4
+ promptIndex?: number;
5
+ }
6
+
7
+ // TODO import from SDK when available
8
+ export type OpenAIRoleEnum =
9
+ | 'system'
10
+ | 'developer'
11
+ | 'assistant'
12
+ | 'user'
13
+ | 'function'
14
+ | 'tool';
15
+
16
+ export type HeaderValue = string | undefined | null;
17
+ export type HeadersLike =
18
+ | Headers
19
+ | readonly HeaderValue[][]
20
+ | Record<string, HeaderValue | readonly HeaderValue[]>
21
+ | undefined
22
+ | null
23
+ // NullableHeaders
24
+ | { values: Headers; [key: string]: unknown };
@@ -286,10 +286,21 @@ const completionsApiContentBlockConverter: StandardContentBlockConverter<{
286
286
  },
287
287
  };
288
288
 
289
+ /** Options for converting messages to OpenAI params */
290
+ export interface ConvertMessagesOptions {
291
+ /** Include reasoning_content field for DeepSeek thinking mode with tool calls */
292
+ includeReasoningContent?: boolean;
293
+ /** Include reasoning_details field for OpenRouter/Gemini thinking mode with tool calls */
294
+ includeReasoningDetails?: boolean;
295
+ /** Convert reasoning_details to content blocks for Claude (requires content array format) */
296
+ convertReasoningDetailsToContent?: boolean;
297
+ }
298
+
289
299
  // Used in LangSmith, export is important here
290
300
  export function _convertMessagesToOpenAIParams(
291
301
  messages: BaseMessage[],
292
- model?: string
302
+ model?: string,
303
+ options?: ConvertMessagesOptions
293
304
  ): OpenAICompletionParam[] {
294
305
  // TODO: Function messages do not support array content, fix cast
295
306
  return messages.flatMap((message) => {
@@ -333,9 +344,113 @@ export function _convertMessagesToOpenAIParams(
333
344
  convertLangChainToolCallToOpenAI
334
345
  );
335
346
  completionParam.content = hasAnthropicThinkingBlock ? content : '';
347
+ if (
348
+ options?.includeReasoningContent === true &&
349
+ message.additional_kwargs.reasoning_content != null
350
+ ) {
351
+ completionParam.reasoning_content =
352
+ message.additional_kwargs.reasoning_content;
353
+ }
354
+ if (
355
+ options?.includeReasoningDetails === true &&
356
+ message.additional_kwargs.reasoning_details != null
357
+ ) {
358
+ // For Claude via OpenRouter, convert reasoning_details to content blocks
359
+ const isClaudeModel =
360
+ model?.includes('claude') === true ||
361
+ model?.includes('anthropic') === true;
362
+ if (
363
+ options.convertReasoningDetailsToContent === true &&
364
+ isClaudeModel
365
+ ) {
366
+ const reasoningDetails = message.additional_kwargs
367
+ .reasoning_details as Record<string, unknown>[];
368
+ const contentBlocks = [];
369
+
370
+ // Add thinking blocks from reasoning_details
371
+ for (const detail of reasoningDetails) {
372
+ if (detail.type === 'reasoning.text' && detail.text != null) {
373
+ contentBlocks.push({
374
+ type: 'thinking',
375
+ thinking: detail.text,
376
+ });
377
+ } else if (
378
+ detail.type === 'reasoning.encrypted' &&
379
+ detail.data != null
380
+ ) {
381
+ contentBlocks.push({
382
+ type: 'redacted_thinking',
383
+ data: detail.data,
384
+ id: detail.id,
385
+ });
386
+ }
387
+ }
388
+
389
+ // Set content to array with thinking blocks
390
+ if (contentBlocks.length > 0) {
391
+ completionParam.content = contentBlocks;
392
+ }
393
+ } else {
394
+ // For non-Claude models, pass as separate field
395
+ completionParam.reasoning_details =
396
+ message.additional_kwargs.reasoning_details;
397
+ }
398
+ }
336
399
  } else {
337
400
  if (message.additional_kwargs.tool_calls != null) {
338
401
  completionParam.tool_calls = message.additional_kwargs.tool_calls;
402
+ if (
403
+ options?.includeReasoningContent === true &&
404
+ message.additional_kwargs.reasoning_content != null
405
+ ) {
406
+ completionParam.reasoning_content =
407
+ message.additional_kwargs.reasoning_content;
408
+ }
409
+ if (
410
+ options?.includeReasoningDetails === true &&
411
+ message.additional_kwargs.reasoning_details != null
412
+ ) {
413
+ // For Claude via OpenRouter, convert reasoning_details to content blocks
414
+ const isClaudeModel =
415
+ model?.includes('claude') === true ||
416
+ model?.includes('anthropic') === true;
417
+ if (
418
+ options.convertReasoningDetailsToContent === true &&
419
+ isClaudeModel
420
+ ) {
421
+ const reasoningDetails = message.additional_kwargs
422
+ .reasoning_details as Record<string, unknown>[];
423
+ const contentBlocks = [];
424
+
425
+ // Add thinking blocks from reasoning_details
426
+ for (const detail of reasoningDetails) {
427
+ if (detail.type === 'reasoning.text' && detail.text != null) {
428
+ contentBlocks.push({
429
+ type: 'thinking',
430
+ thinking: detail.text,
431
+ });
432
+ } else if (
433
+ detail.type === 'reasoning.encrypted' &&
434
+ detail.data != null
435
+ ) {
436
+ contentBlocks.push({
437
+ type: 'redacted_thinking',
438
+ data: detail.data,
439
+ id: detail.id,
440
+ });
441
+ }
442
+ }
443
+
444
+ // Set content to array with thinking blocks
445
+ if (contentBlocks.length > 0) {
446
+ completionParam.content = contentBlocks;
447
+ }
448
+ } else {
449
+ // For non-Claude models, pass as separate field
450
+ completionParam.reasoning_details =
451
+ message.additional_kwargs.reasoning_details;
452
+ }
453
+ }
339
454
  }
340
455
  if ((message as ToolMessage).tool_call_id != null) {
341
456
  completionParam.tool_call_id = (message as ToolMessage).tool_call_id;
@@ -1,90 +1,90 @@
1
- import { isReasoningModel } from './index';
2
-
3
- describe('isReasoningModel', () => {
4
- describe('should return true for reasoning models', () => {
5
- test('basic o-series models', () => {
6
- expect(isReasoningModel('o1')).toBe(true);
7
- expect(isReasoningModel('o2')).toBe(true);
8
- expect(isReasoningModel('o9')).toBe(true);
9
- expect(isReasoningModel('o1-preview')).toBe(true);
10
- expect(isReasoningModel('o1-mini')).toBe(true);
11
- });
12
-
13
- test('gpt-5+ models', () => {
14
- expect(isReasoningModel('gpt-5')).toBe(true);
15
- expect(isReasoningModel('gpt-6')).toBe(true);
16
- expect(isReasoningModel('gpt-7')).toBe(true);
17
- expect(isReasoningModel('gpt-8')).toBe(true);
18
- expect(isReasoningModel('gpt-9')).toBe(true);
19
- });
20
-
21
- test('with provider prefixes', () => {
22
- expect(isReasoningModel('azure/o1')).toBe(true);
23
- expect(isReasoningModel('azure/gpt-5')).toBe(true);
24
- expect(isReasoningModel('openai/o1')).toBe(true);
25
- expect(isReasoningModel('openai/gpt-5')).toBe(true);
26
- });
27
-
28
- test('with custom prefixes', () => {
29
- expect(isReasoningModel('custom-provider/o1')).toBe(true);
30
- expect(isReasoningModel('my-deployment/gpt-5')).toBe(true);
31
- expect(isReasoningModel('company/azure/gpt-5')).toBe(true);
32
- });
33
-
34
- test('case insensitive', () => {
35
- expect(isReasoningModel('O1')).toBe(true);
36
- expect(isReasoningModel('GPT-5')).toBe(true);
37
- expect(isReasoningModel('gPt-6')).toBe(true);
38
- expect(isReasoningModel('Azure/O1')).toBe(true);
39
- });
40
- });
41
-
42
- describe('should return false for non-reasoning models', () => {
43
- test('older GPT models', () => {
44
- expect(isReasoningModel('gpt-3.5-turbo')).toBe(false);
45
- expect(isReasoningModel('gpt-4')).toBe(false);
46
- expect(isReasoningModel('gpt-4-turbo')).toBe(false);
47
- expect(isReasoningModel('gpt-4o')).toBe(false);
48
- expect(isReasoningModel('gpt-4o-mini')).toBe(false);
49
- });
50
-
51
- test('other model families', () => {
52
- expect(isReasoningModel('claude-3')).toBe(false);
53
- expect(isReasoningModel('claude-3-opus')).toBe(false);
54
- expect(isReasoningModel('llama-2')).toBe(false);
55
- expect(isReasoningModel('gemini-pro')).toBe(false);
56
- });
57
-
58
- test('partial matches that should not match', () => {
59
- expect(isReasoningModel('proto1')).toBe(false);
60
- expect(isReasoningModel('version-o1')).toBe(true);
61
- expect(isReasoningModel('gpt-40')).toBe(false);
62
- expect(isReasoningModel('gpt-3.5')).toBe(false);
63
- });
64
-
65
- test('empty, null, and undefined', () => {
66
- expect(isReasoningModel('')).toBe(false);
67
- expect(isReasoningModel()).toBe(false);
68
- expect(isReasoningModel(undefined)).toBe(false);
69
- });
70
- });
71
-
72
- describe('edge cases', () => {
73
- test('with special characters', () => {
74
- expect(isReasoningModel('deployment_o1_model')).toBe(false);
75
- expect(isReasoningModel('gpt-5-deployment')).toBe(true);
76
- expect(isReasoningModel('o1@latest')).toBe(true);
77
- expect(isReasoningModel('gpt-5.0')).toBe(true);
78
- });
79
-
80
- test('word boundary behavior', () => {
81
- // These should match because o1 and gpt-5 are whole words
82
- expect(isReasoningModel('use-o1-model')).toBe(true);
83
- expect(isReasoningModel('model-gpt-5-latest')).toBe(true);
84
-
85
- // These should not match because o1/gpt-5 are not whole words
86
- expect(isReasoningModel('proto1model')).toBe(false);
87
- expect(isReasoningModel('supergpt-50')).toBe(false);
88
- });
89
- });
90
- });
1
+ import { isReasoningModel } from './index';
2
+
3
+ describe('isReasoningModel', () => {
4
+ describe('should return true for reasoning models', () => {
5
+ test('basic o-series models', () => {
6
+ expect(isReasoningModel('o1')).toBe(true);
7
+ expect(isReasoningModel('o2')).toBe(true);
8
+ expect(isReasoningModel('o9')).toBe(true);
9
+ expect(isReasoningModel('o1-preview')).toBe(true);
10
+ expect(isReasoningModel('o1-mini')).toBe(true);
11
+ });
12
+
13
+ test('gpt-5+ models', () => {
14
+ expect(isReasoningModel('gpt-5')).toBe(true);
15
+ expect(isReasoningModel('gpt-6')).toBe(true);
16
+ expect(isReasoningModel('gpt-7')).toBe(true);
17
+ expect(isReasoningModel('gpt-8')).toBe(true);
18
+ expect(isReasoningModel('gpt-9')).toBe(true);
19
+ });
20
+
21
+ test('with provider prefixes', () => {
22
+ expect(isReasoningModel('azure/o1')).toBe(true);
23
+ expect(isReasoningModel('azure/gpt-5')).toBe(true);
24
+ expect(isReasoningModel('openai/o1')).toBe(true);
25
+ expect(isReasoningModel('openai/gpt-5')).toBe(true);
26
+ });
27
+
28
+ test('with custom prefixes', () => {
29
+ expect(isReasoningModel('custom-provider/o1')).toBe(true);
30
+ expect(isReasoningModel('my-deployment/gpt-5')).toBe(true);
31
+ expect(isReasoningModel('company/azure/gpt-5')).toBe(true);
32
+ });
33
+
34
+ test('case insensitive', () => {
35
+ expect(isReasoningModel('O1')).toBe(true);
36
+ expect(isReasoningModel('GPT-5')).toBe(true);
37
+ expect(isReasoningModel('gPt-6')).toBe(true);
38
+ expect(isReasoningModel('Azure/O1')).toBe(true);
39
+ });
40
+ });
41
+
42
+ describe('should return false for non-reasoning models', () => {
43
+ test('older GPT models', () => {
44
+ expect(isReasoningModel('gpt-3.5-turbo')).toBe(false);
45
+ expect(isReasoningModel('gpt-4')).toBe(false);
46
+ expect(isReasoningModel('gpt-4-turbo')).toBe(false);
47
+ expect(isReasoningModel('gpt-4o')).toBe(false);
48
+ expect(isReasoningModel('gpt-4o-mini')).toBe(false);
49
+ });
50
+
51
+ test('other model families', () => {
52
+ expect(isReasoningModel('claude-3')).toBe(false);
53
+ expect(isReasoningModel('claude-3-opus')).toBe(false);
54
+ expect(isReasoningModel('llama-2')).toBe(false);
55
+ expect(isReasoningModel('gemini-pro')).toBe(false);
56
+ });
57
+
58
+ test('partial matches that should not match', () => {
59
+ expect(isReasoningModel('proto1')).toBe(false);
60
+ expect(isReasoningModel('version-o1')).toBe(true);
61
+ expect(isReasoningModel('gpt-40')).toBe(false);
62
+ expect(isReasoningModel('gpt-3.5')).toBe(false);
63
+ });
64
+
65
+ test('empty, null, and undefined', () => {
66
+ expect(isReasoningModel('')).toBe(false);
67
+ expect(isReasoningModel()).toBe(false);
68
+ expect(isReasoningModel(undefined)).toBe(false);
69
+ });
70
+ });
71
+
72
+ describe('edge cases', () => {
73
+ test('with special characters', () => {
74
+ expect(isReasoningModel('deployment_o1_model')).toBe(false);
75
+ expect(isReasoningModel('gpt-5-deployment')).toBe(true);
76
+ expect(isReasoningModel('o1@latest')).toBe(true);
77
+ expect(isReasoningModel('gpt-5.0')).toBe(true);
78
+ });
79
+
80
+ test('word boundary behavior', () => {
81
+ // These should match because o1 and gpt-5 are whole words
82
+ expect(isReasoningModel('use-o1-model')).toBe(true);
83
+ expect(isReasoningModel('model-gpt-5-latest')).toBe(true);
84
+
85
+ // These should not match because o1/gpt-5 are not whole words
86
+ expect(isReasoningModel('proto1model')).toBe(false);
87
+ expect(isReasoningModel('supergpt-50')).toBe(false);
88
+ });
89
+ });
90
+ });