@librechat/agents 2.4.322 → 3.0.0-rc1
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/cjs/agents/AgentContext.cjs +218 -0
- package/dist/cjs/agents/AgentContext.cjs.map +1 -0
- package/dist/cjs/common/enum.cjs +14 -5
- package/dist/cjs/common/enum.cjs.map +1 -1
- package/dist/cjs/events.cjs +10 -6
- package/dist/cjs/events.cjs.map +1 -1
- package/dist/cjs/graphs/Graph.cjs +309 -212
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/graphs/MultiAgentGraph.cjs +322 -0
- package/dist/cjs/graphs/MultiAgentGraph.cjs.map +1 -0
- package/dist/cjs/llm/anthropic/index.cjs +54 -9
- package/dist/cjs/llm/anthropic/index.cjs.map +1 -1
- package/dist/cjs/llm/anthropic/types.cjs.map +1 -1
- package/dist/cjs/llm/anthropic/utils/message_inputs.cjs +52 -6
- package/dist/cjs/llm/anthropic/utils/message_inputs.cjs.map +1 -1
- package/dist/cjs/llm/anthropic/utils/message_outputs.cjs +22 -2
- package/dist/cjs/llm/anthropic/utils/message_outputs.cjs.map +1 -1
- package/dist/cjs/llm/anthropic/utils/tools.cjs +29 -0
- package/dist/cjs/llm/anthropic/utils/tools.cjs.map +1 -0
- package/dist/cjs/llm/google/index.cjs +144 -0
- package/dist/cjs/llm/google/index.cjs.map +1 -0
- package/dist/cjs/llm/google/utils/common.cjs +477 -0
- package/dist/cjs/llm/google/utils/common.cjs.map +1 -0
- package/dist/cjs/llm/ollama/index.cjs +67 -0
- package/dist/cjs/llm/ollama/index.cjs.map +1 -0
- package/dist/cjs/llm/ollama/utils.cjs +158 -0
- package/dist/cjs/llm/ollama/utils.cjs.map +1 -0
- package/dist/cjs/llm/openai/index.cjs +389 -3
- package/dist/cjs/llm/openai/index.cjs.map +1 -1
- package/dist/cjs/llm/openai/utils/index.cjs +672 -0
- package/dist/cjs/llm/openai/utils/index.cjs.map +1 -0
- package/dist/cjs/llm/providers.cjs +15 -15
- package/dist/cjs/llm/providers.cjs.map +1 -1
- package/dist/cjs/llm/text.cjs +14 -3
- package/dist/cjs/llm/text.cjs.map +1 -1
- package/dist/cjs/llm/vertexai/index.cjs +330 -0
- package/dist/cjs/llm/vertexai/index.cjs.map +1 -0
- package/dist/cjs/main.cjs +11 -0
- package/dist/cjs/main.cjs.map +1 -1
- package/dist/cjs/run.cjs +120 -81
- package/dist/cjs/run.cjs.map +1 -1
- package/dist/cjs/stream.cjs +85 -51
- package/dist/cjs/stream.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs +10 -4
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/cjs/tools/handlers.cjs +119 -13
- package/dist/cjs/tools/handlers.cjs.map +1 -1
- package/dist/cjs/tools/search/anthropic.cjs +40 -0
- package/dist/cjs/tools/search/anthropic.cjs.map +1 -0
- package/dist/cjs/tools/search/firecrawl.cjs +55 -9
- package/dist/cjs/tools/search/firecrawl.cjs.map +1 -1
- package/dist/cjs/tools/search/format.cjs +6 -6
- package/dist/cjs/tools/search/format.cjs.map +1 -1
- package/dist/cjs/tools/search/rerankers.cjs +7 -29
- package/dist/cjs/tools/search/rerankers.cjs.map +1 -1
- package/dist/cjs/tools/search/search.cjs +86 -16
- package/dist/cjs/tools/search/search.cjs.map +1 -1
- package/dist/cjs/tools/search/tool.cjs +4 -2
- package/dist/cjs/tools/search/tool.cjs.map +1 -1
- package/dist/cjs/tools/search/utils.cjs +1 -1
- package/dist/cjs/tools/search/utils.cjs.map +1 -1
- package/dist/cjs/utils/events.cjs +31 -0
- package/dist/cjs/utils/events.cjs.map +1 -0
- package/dist/cjs/utils/title.cjs +57 -21
- package/dist/cjs/utils/title.cjs.map +1 -1
- package/dist/cjs/utils/tokens.cjs +54 -7
- package/dist/cjs/utils/tokens.cjs.map +1 -1
- package/dist/esm/agents/AgentContext.mjs +216 -0
- package/dist/esm/agents/AgentContext.mjs.map +1 -0
- package/dist/esm/common/enum.mjs +15 -6
- package/dist/esm/common/enum.mjs.map +1 -1
- package/dist/esm/events.mjs +10 -6
- package/dist/esm/events.mjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +311 -214
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/graphs/MultiAgentGraph.mjs +320 -0
- package/dist/esm/graphs/MultiAgentGraph.mjs.map +1 -0
- package/dist/esm/llm/anthropic/index.mjs +54 -9
- package/dist/esm/llm/anthropic/index.mjs.map +1 -1
- package/dist/esm/llm/anthropic/types.mjs.map +1 -1
- package/dist/esm/llm/anthropic/utils/message_inputs.mjs +52 -6
- package/dist/esm/llm/anthropic/utils/message_inputs.mjs.map +1 -1
- package/dist/esm/llm/anthropic/utils/message_outputs.mjs +22 -2
- package/dist/esm/llm/anthropic/utils/message_outputs.mjs.map +1 -1
- package/dist/esm/llm/anthropic/utils/tools.mjs +27 -0
- package/dist/esm/llm/anthropic/utils/tools.mjs.map +1 -0
- package/dist/esm/llm/google/index.mjs +142 -0
- package/dist/esm/llm/google/index.mjs.map +1 -0
- package/dist/esm/llm/google/utils/common.mjs +471 -0
- package/dist/esm/llm/google/utils/common.mjs.map +1 -0
- package/dist/esm/llm/ollama/index.mjs +65 -0
- package/dist/esm/llm/ollama/index.mjs.map +1 -0
- package/dist/esm/llm/ollama/utils.mjs +155 -0
- package/dist/esm/llm/ollama/utils.mjs.map +1 -0
- package/dist/esm/llm/openai/index.mjs +388 -4
- package/dist/esm/llm/openai/index.mjs.map +1 -1
- package/dist/esm/llm/openai/utils/index.mjs +666 -0
- package/dist/esm/llm/openai/utils/index.mjs.map +1 -0
- package/dist/esm/llm/providers.mjs +5 -5
- package/dist/esm/llm/providers.mjs.map +1 -1
- package/dist/esm/llm/text.mjs +14 -3
- package/dist/esm/llm/text.mjs.map +1 -1
- package/dist/esm/llm/vertexai/index.mjs +328 -0
- package/dist/esm/llm/vertexai/index.mjs.map +1 -0
- package/dist/esm/main.mjs +6 -5
- package/dist/esm/main.mjs.map +1 -1
- package/dist/esm/run.mjs +121 -83
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/stream.mjs +87 -54
- package/dist/esm/stream.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs +10 -4
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/esm/tools/handlers.mjs +119 -15
- package/dist/esm/tools/handlers.mjs.map +1 -1
- package/dist/esm/tools/search/anthropic.mjs +37 -0
- package/dist/esm/tools/search/anthropic.mjs.map +1 -0
- package/dist/esm/tools/search/firecrawl.mjs +55 -9
- package/dist/esm/tools/search/firecrawl.mjs.map +1 -1
- package/dist/esm/tools/search/format.mjs +7 -7
- package/dist/esm/tools/search/format.mjs.map +1 -1
- package/dist/esm/tools/search/rerankers.mjs +7 -29
- package/dist/esm/tools/search/rerankers.mjs.map +1 -1
- package/dist/esm/tools/search/search.mjs +86 -16
- package/dist/esm/tools/search/search.mjs.map +1 -1
- package/dist/esm/tools/search/tool.mjs +4 -2
- package/dist/esm/tools/search/tool.mjs.map +1 -1
- package/dist/esm/tools/search/utils.mjs +1 -1
- package/dist/esm/tools/search/utils.mjs.map +1 -1
- package/dist/esm/utils/events.mjs +29 -0
- package/dist/esm/utils/events.mjs.map +1 -0
- package/dist/esm/utils/title.mjs +57 -22
- package/dist/esm/utils/title.mjs.map +1 -1
- package/dist/esm/utils/tokens.mjs +54 -8
- package/dist/esm/utils/tokens.mjs.map +1 -1
- package/dist/types/agents/AgentContext.d.ts +91 -0
- package/dist/types/common/enum.d.ts +15 -6
- package/dist/types/events.d.ts +5 -4
- package/dist/types/graphs/Graph.d.ts +64 -67
- package/dist/types/graphs/MultiAgentGraph.d.ts +37 -0
- package/dist/types/graphs/index.d.ts +1 -0
- package/dist/types/llm/anthropic/index.d.ts +11 -0
- package/dist/types/llm/anthropic/types.d.ts +9 -3
- package/dist/types/llm/anthropic/utils/message_inputs.d.ts +1 -1
- package/dist/types/llm/anthropic/utils/output_parsers.d.ts +4 -4
- package/dist/types/llm/anthropic/utils/tools.d.ts +3 -0
- package/dist/types/llm/google/index.d.ts +13 -0
- package/dist/types/llm/google/types.d.ts +32 -0
- package/dist/types/llm/google/utils/common.d.ts +19 -0
- package/dist/types/llm/google/utils/tools.d.ts +10 -0
- package/dist/types/llm/google/utils/zod_to_genai_parameters.d.ts +14 -0
- package/dist/types/llm/ollama/index.d.ts +7 -0
- package/dist/types/llm/ollama/utils.d.ts +7 -0
- package/dist/types/llm/openai/index.d.ts +72 -3
- package/dist/types/llm/openai/types.d.ts +10 -0
- package/dist/types/llm/openai/utils/index.d.ts +20 -0
- package/dist/types/llm/text.d.ts +1 -1
- package/dist/types/llm/vertexai/index.d.ts +293 -0
- package/dist/types/messages/reducer.d.ts +9 -0
- package/dist/types/run.d.ts +19 -12
- package/dist/types/scripts/ant_web_search.d.ts +1 -0
- package/dist/types/scripts/args.d.ts +2 -1
- package/dist/types/scripts/handoff-test.d.ts +1 -0
- package/dist/types/scripts/multi-agent-conditional.d.ts +1 -0
- package/dist/types/scripts/multi-agent-parallel.d.ts +1 -0
- package/dist/types/scripts/multi-agent-sequence.d.ts +1 -0
- package/dist/types/scripts/multi-agent-test.d.ts +1 -0
- package/dist/types/stream.d.ts +10 -3
- package/dist/types/tools/CodeExecutor.d.ts +2 -2
- package/dist/types/tools/ToolNode.d.ts +1 -1
- package/dist/types/tools/handlers.d.ts +17 -4
- package/dist/types/tools/search/anthropic.d.ts +16 -0
- package/dist/types/tools/search/firecrawl.d.ts +15 -0
- package/dist/types/tools/search/rerankers.d.ts +0 -1
- package/dist/types/tools/search/types.d.ts +30 -9
- package/dist/types/types/graph.d.ts +95 -15
- package/dist/types/types/llm.d.ts +24 -10
- package/dist/types/types/run.d.ts +46 -8
- package/dist/types/types/stream.d.ts +16 -2
- package/dist/types/types/tools.d.ts +1 -1
- package/dist/types/utils/events.d.ts +6 -0
- package/dist/types/utils/title.d.ts +2 -1
- package/dist/types/utils/tokens.d.ts +24 -0
- package/package.json +33 -17
- package/src/agents/AgentContext.ts +315 -0
- package/src/common/enum.ts +14 -5
- package/src/events.ts +24 -13
- package/src/graphs/Graph.ts +495 -312
- package/src/graphs/MultiAgentGraph.ts +381 -0
- package/src/graphs/index.ts +2 -1
- package/src/llm/anthropic/Jacob_Lee_Resume_2023.pdf +0 -0
- package/src/llm/anthropic/index.ts +78 -13
- package/src/llm/anthropic/llm.spec.ts +491 -115
- package/src/llm/anthropic/types.ts +39 -3
- package/src/llm/anthropic/utils/message_inputs.ts +67 -11
- package/src/llm/anthropic/utils/message_outputs.ts +21 -2
- package/src/llm/anthropic/utils/output_parsers.ts +25 -6
- package/src/llm/anthropic/utils/tools.ts +29 -0
- package/src/llm/google/index.ts +218 -0
- package/src/llm/google/types.ts +43 -0
- package/src/llm/google/utils/common.ts +646 -0
- package/src/llm/google/utils/tools.ts +160 -0
- package/src/llm/google/utils/zod_to_genai_parameters.ts +86 -0
- package/src/llm/ollama/index.ts +89 -0
- package/src/llm/ollama/utils.ts +193 -0
- package/src/llm/openai/index.ts +600 -14
- package/src/llm/openai/types.ts +24 -0
- package/src/llm/openai/utils/index.ts +912 -0
- package/src/llm/openai/utils/isReasoningModel.test.ts +90 -0
- package/src/llm/providers.ts +10 -9
- package/src/llm/text.ts +26 -7
- package/src/llm/vertexai/index.ts +360 -0
- package/src/messages/reducer.ts +80 -0
- package/src/run.ts +181 -112
- package/src/scripts/ant_web_search.ts +158 -0
- package/src/scripts/args.ts +12 -8
- package/src/scripts/cli4.ts +29 -21
- package/src/scripts/cli5.ts +29 -21
- package/src/scripts/code_exec.ts +54 -23
- package/src/scripts/code_exec_files.ts +48 -17
- package/src/scripts/code_exec_simple.ts +46 -27
- package/src/scripts/handoff-test.ts +135 -0
- package/src/scripts/image.ts +52 -20
- package/src/scripts/multi-agent-conditional.ts +220 -0
- package/src/scripts/multi-agent-example-output.md +110 -0
- package/src/scripts/multi-agent-parallel.ts +337 -0
- package/src/scripts/multi-agent-sequence.ts +212 -0
- package/src/scripts/multi-agent-test.ts +186 -0
- package/src/scripts/search.ts +1 -9
- package/src/scripts/simple.ts +25 -10
- package/src/scripts/tools.ts +48 -18
- package/src/specs/anthropic.simple.test.ts +150 -34
- package/src/specs/azure.simple.test.ts +325 -0
- package/src/specs/openai.simple.test.ts +140 -33
- package/src/specs/openrouter.simple.test.ts +107 -0
- package/src/specs/prune.test.ts +4 -9
- package/src/specs/reasoning.test.ts +80 -44
- package/src/specs/token-memoization.test.ts +39 -0
- package/src/stream.test.ts +94 -0
- package/src/stream.ts +139 -60
- package/src/tools/ToolNode.ts +21 -7
- package/src/tools/handlers.ts +192 -18
- package/src/tools/search/anthropic.ts +51 -0
- package/src/tools/search/firecrawl.ts +69 -20
- package/src/tools/search/format.ts +6 -8
- package/src/tools/search/rerankers.ts +7 -40
- package/src/tools/search/search.ts +97 -16
- package/src/tools/search/tool.ts +5 -2
- package/src/tools/search/types.ts +30 -10
- package/src/tools/search/utils.ts +1 -1
- package/src/types/graph.ts +272 -103
- package/src/types/llm.ts +25 -12
- package/src/types/run.ts +51 -13
- package/src/types/stream.ts +22 -1
- package/src/types/tools.ts +16 -10
- package/src/utils/events.ts +32 -0
- package/src/utils/llmConfig.ts +19 -7
- package/src/utils/title.ts +104 -30
- package/src/utils/tokens.ts +69 -10
package/src/llm/openai/index.ts
CHANGED
|
@@ -1,21 +1,127 @@
|
|
|
1
1
|
import { AzureOpenAI as AzureOpenAIClient } from 'openai';
|
|
2
|
+
import { AIMessageChunk } from '@langchain/core/messages';
|
|
2
3
|
import { ChatXAI as OriginalChatXAI } from '@langchain/xai';
|
|
4
|
+
import { ChatGenerationChunk } from '@langchain/core/outputs';
|
|
5
|
+
import { ToolDefinition } from '@langchain/core/language_models/base';
|
|
6
|
+
import { isLangChainTool } from '@langchain/core/utils/function_calling';
|
|
3
7
|
import { ChatDeepSeek as OriginalChatDeepSeek } from '@langchain/deepseek';
|
|
8
|
+
import { CallbackManagerForLLMRun } from '@langchain/core/callbacks/manager';
|
|
4
9
|
import {
|
|
5
10
|
getEndpoint,
|
|
6
11
|
OpenAIClient,
|
|
12
|
+
formatToOpenAITool,
|
|
7
13
|
ChatOpenAI as OriginalChatOpenAI,
|
|
8
14
|
AzureChatOpenAI as OriginalAzureChatOpenAI,
|
|
9
15
|
} from '@langchain/openai';
|
|
10
|
-
import type {
|
|
16
|
+
import type {
|
|
17
|
+
OpenAIChatCallOptions,
|
|
18
|
+
OpenAIRoleEnum,
|
|
19
|
+
HeaderValue,
|
|
20
|
+
HeadersLike,
|
|
21
|
+
} from './types';
|
|
22
|
+
import type { BindToolsInput } from '@langchain/core/language_models/chat_models';
|
|
23
|
+
import type { BaseMessage, UsageMetadata } from '@langchain/core/messages';
|
|
24
|
+
import type { ChatXAIInput } from '@langchain/xai';
|
|
11
25
|
import type * as t from '@langchain/openai';
|
|
26
|
+
import {
|
|
27
|
+
isReasoningModel,
|
|
28
|
+
_convertMessagesToOpenAIParams,
|
|
29
|
+
_convertMessagesToOpenAIResponsesParams,
|
|
30
|
+
_convertOpenAIResponsesDeltaToBaseMessageChunk,
|
|
31
|
+
type ResponseReturnStreamEvents,
|
|
32
|
+
} from './utils';
|
|
33
|
+
|
|
34
|
+
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
|
35
|
+
const iife = <T>(fn: () => T) => fn();
|
|
36
|
+
|
|
37
|
+
export function isHeaders(headers: unknown): headers is Headers {
|
|
38
|
+
return (
|
|
39
|
+
typeof Headers !== 'undefined' &&
|
|
40
|
+
headers !== null &&
|
|
41
|
+
typeof headers === 'object' &&
|
|
42
|
+
Object.prototype.toString.call(headers) === '[object Headers]'
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function normalizeHeaders(
|
|
47
|
+
headers: HeadersLike
|
|
48
|
+
): Record<string, HeaderValue | readonly HeaderValue[]> {
|
|
49
|
+
const output = iife(() => {
|
|
50
|
+
// If headers is a Headers instance
|
|
51
|
+
if (isHeaders(headers)) {
|
|
52
|
+
return headers;
|
|
53
|
+
}
|
|
54
|
+
// If headers is an array of [key, value] pairs
|
|
55
|
+
else if (Array.isArray(headers)) {
|
|
56
|
+
return new Headers(headers);
|
|
57
|
+
}
|
|
58
|
+
// If headers is a NullableHeaders-like object (has 'values' property that is a Headers)
|
|
59
|
+
else if (
|
|
60
|
+
typeof headers === 'object' &&
|
|
61
|
+
headers !== null &&
|
|
62
|
+
'values' in headers &&
|
|
63
|
+
isHeaders(headers.values)
|
|
64
|
+
) {
|
|
65
|
+
return headers.values;
|
|
66
|
+
}
|
|
67
|
+
// If headers is a plain object
|
|
68
|
+
else if (typeof headers === 'object' && headers !== null) {
|
|
69
|
+
const entries: [string, string][] = Object.entries(headers)
|
|
70
|
+
.filter(([, v]) => typeof v === 'string')
|
|
71
|
+
.map(([k, v]) => [k, v as string]);
|
|
72
|
+
return new Headers(entries);
|
|
73
|
+
}
|
|
74
|
+
return new Headers();
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
return Object.fromEntries(output.entries());
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
type OpenAICompletionParam =
|
|
81
|
+
OpenAIClient.Chat.Completions.ChatCompletionMessageParam;
|
|
82
|
+
|
|
83
|
+
type OpenAICoreRequestOptions = OpenAIClient.RequestOptions;
|
|
12
84
|
|
|
13
85
|
function createAbortHandler(controller: AbortController): () => void {
|
|
14
86
|
return function (): void {
|
|
15
87
|
controller.abort();
|
|
16
88
|
};
|
|
17
89
|
}
|
|
90
|
+
/**
|
|
91
|
+
* Formats a tool in either OpenAI format, or LangChain structured tool format
|
|
92
|
+
* into an OpenAI tool format. If the tool is already in OpenAI format, return without
|
|
93
|
+
* any changes. If it is in LangChain structured tool format, convert it to OpenAI tool format
|
|
94
|
+
* using OpenAI's `zodFunction` util, falling back to `convertToOpenAIFunction` if the parameters
|
|
95
|
+
* returned from the `zodFunction` util are not defined.
|
|
96
|
+
*
|
|
97
|
+
* @param {BindToolsInput} tool The tool to convert to an OpenAI tool.
|
|
98
|
+
* @param {Object} [fields] Additional fields to add to the OpenAI tool.
|
|
99
|
+
* @returns {ToolDefinition} The inputted tool in OpenAI tool format.
|
|
100
|
+
*/
|
|
101
|
+
export function _convertToOpenAITool(
|
|
102
|
+
tool: BindToolsInput,
|
|
103
|
+
fields?: {
|
|
104
|
+
/**
|
|
105
|
+
* If `true`, model output is guaranteed to exactly match the JSON Schema
|
|
106
|
+
* provided in the function definition.
|
|
107
|
+
*/
|
|
108
|
+
strict?: boolean;
|
|
109
|
+
}
|
|
110
|
+
): OpenAIClient.ChatCompletionTool {
|
|
111
|
+
let toolDef: OpenAIClient.ChatCompletionTool | undefined;
|
|
18
112
|
|
|
113
|
+
if (isLangChainTool(tool)) {
|
|
114
|
+
toolDef = formatToOpenAITool(tool);
|
|
115
|
+
} else {
|
|
116
|
+
toolDef = tool as ToolDefinition;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
if (fields?.strict !== undefined) {
|
|
120
|
+
toolDef.function.strict = fields.strict;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return toolDef;
|
|
124
|
+
}
|
|
19
125
|
export class CustomOpenAIClient extends OpenAIClient {
|
|
20
126
|
abortHandler?: () => void;
|
|
21
127
|
async fetchWithTimeout(
|
|
@@ -87,13 +193,14 @@ export class CustomAzureOpenAIClient extends AzureOpenAIClient {
|
|
|
87
193
|
}
|
|
88
194
|
}
|
|
89
195
|
|
|
196
|
+
/** @ts-expect-error We are intentionally overriding `getReasoningParams` */
|
|
90
197
|
export class ChatOpenAI extends OriginalChatOpenAI<t.ChatOpenAICallOptions> {
|
|
91
198
|
public get exposedClient(): CustomOpenAIClient {
|
|
92
199
|
return this.client;
|
|
93
200
|
}
|
|
94
201
|
protected _getClientOptions(
|
|
95
|
-
options?:
|
|
96
|
-
):
|
|
202
|
+
options?: OpenAICoreRequestOptions
|
|
203
|
+
): OpenAICoreRequestOptions {
|
|
97
204
|
if (!(this.client as OpenAIClient | undefined)) {
|
|
98
205
|
const openAIEndpointConfig: t.OpenAIEndpointConfig = {
|
|
99
206
|
baseURL: this.clientConfig.baseURL,
|
|
@@ -115,19 +222,258 @@ export class ChatOpenAI extends OriginalChatOpenAI<t.ChatOpenAICallOptions> {
|
|
|
115
222
|
const requestOptions = {
|
|
116
223
|
...this.clientConfig,
|
|
117
224
|
...options,
|
|
118
|
-
} as
|
|
225
|
+
} as OpenAICoreRequestOptions;
|
|
119
226
|
return requestOptions;
|
|
120
227
|
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Returns backwards compatible reasoning parameters from constructor params and call options
|
|
231
|
+
* @internal
|
|
232
|
+
*/
|
|
233
|
+
getReasoningParams(
|
|
234
|
+
options?: this['ParsedCallOptions']
|
|
235
|
+
): OpenAIClient.Reasoning | undefined {
|
|
236
|
+
if (!isReasoningModel(this.model)) {
|
|
237
|
+
return;
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
// apply options in reverse order of importance -- newer options supersede older options
|
|
241
|
+
let reasoning: OpenAIClient.Reasoning | undefined;
|
|
242
|
+
if (this.reasoning !== undefined) {
|
|
243
|
+
reasoning = {
|
|
244
|
+
...reasoning,
|
|
245
|
+
...this.reasoning,
|
|
246
|
+
};
|
|
247
|
+
}
|
|
248
|
+
if (options?.reasoning !== undefined) {
|
|
249
|
+
reasoning = {
|
|
250
|
+
...reasoning,
|
|
251
|
+
...options.reasoning,
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
return reasoning;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
protected _getReasoningParams(
|
|
259
|
+
options?: this['ParsedCallOptions']
|
|
260
|
+
): OpenAIClient.Reasoning | undefined {
|
|
261
|
+
return this.getReasoningParams(options);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
async *_streamResponseChunks(
|
|
265
|
+
messages: BaseMessage[],
|
|
266
|
+
options: this['ParsedCallOptions'],
|
|
267
|
+
runManager?: CallbackManagerForLLMRun
|
|
268
|
+
): AsyncGenerator<ChatGenerationChunk> {
|
|
269
|
+
if (!this._useResponseApi(options)) {
|
|
270
|
+
return yield* this._streamResponseChunks2(messages, options, runManager);
|
|
271
|
+
}
|
|
272
|
+
const streamIterable = await this.responseApiWithRetry(
|
|
273
|
+
{
|
|
274
|
+
...this.invocationParams<'responses'>(options, { streaming: true }),
|
|
275
|
+
input: _convertMessagesToOpenAIResponsesParams(
|
|
276
|
+
messages,
|
|
277
|
+
this.model,
|
|
278
|
+
this.zdrEnabled
|
|
279
|
+
),
|
|
280
|
+
stream: true,
|
|
281
|
+
},
|
|
282
|
+
options
|
|
283
|
+
);
|
|
284
|
+
|
|
285
|
+
for await (const data of streamIterable) {
|
|
286
|
+
const chunk = _convertOpenAIResponsesDeltaToBaseMessageChunk(
|
|
287
|
+
data as ResponseReturnStreamEvents
|
|
288
|
+
);
|
|
289
|
+
if (chunk == null) continue;
|
|
290
|
+
yield chunk;
|
|
291
|
+
await runManager?.handleLLMNewToken(
|
|
292
|
+
chunk.text || '',
|
|
293
|
+
undefined,
|
|
294
|
+
undefined,
|
|
295
|
+
undefined,
|
|
296
|
+
undefined,
|
|
297
|
+
{ chunk }
|
|
298
|
+
);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
async *_streamResponseChunks2(
|
|
305
|
+
messages: BaseMessage[],
|
|
306
|
+
options: this['ParsedCallOptions'],
|
|
307
|
+
runManager?: CallbackManagerForLLMRun
|
|
308
|
+
): AsyncGenerator<ChatGenerationChunk> {
|
|
309
|
+
const messagesMapped: OpenAICompletionParam[] =
|
|
310
|
+
_convertMessagesToOpenAIParams(messages, this.model);
|
|
311
|
+
|
|
312
|
+
const params = {
|
|
313
|
+
...this.invocationParams(options, {
|
|
314
|
+
streaming: true,
|
|
315
|
+
}),
|
|
316
|
+
messages: messagesMapped,
|
|
317
|
+
stream: true as const,
|
|
318
|
+
};
|
|
319
|
+
let defaultRole: OpenAIRoleEnum | undefined;
|
|
320
|
+
|
|
321
|
+
const streamIterable = await this.completionWithRetry(params, options);
|
|
322
|
+
let usage: OpenAIClient.Completions.CompletionUsage | undefined;
|
|
323
|
+
for await (const data of streamIterable) {
|
|
324
|
+
const choice = data.choices[0] as
|
|
325
|
+
| Partial<OpenAIClient.Chat.Completions.ChatCompletionChunk.Choice>
|
|
326
|
+
| undefined;
|
|
327
|
+
if (data.usage) {
|
|
328
|
+
usage = data.usage;
|
|
329
|
+
}
|
|
330
|
+
if (!choice) {
|
|
331
|
+
continue;
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
const { delta } = choice;
|
|
335
|
+
if (!delta) {
|
|
336
|
+
continue;
|
|
337
|
+
}
|
|
338
|
+
const chunk = this._convertOpenAIDeltaToBaseMessageChunk(
|
|
339
|
+
delta,
|
|
340
|
+
data,
|
|
341
|
+
defaultRole
|
|
342
|
+
);
|
|
343
|
+
if ('reasoning_content' in delta) {
|
|
344
|
+
chunk.additional_kwargs.reasoning_content = delta.reasoning_content;
|
|
345
|
+
} else if ('reasoning' in delta) {
|
|
346
|
+
chunk.additional_kwargs.reasoning_content = delta.reasoning;
|
|
347
|
+
}
|
|
348
|
+
defaultRole = delta.role ?? defaultRole;
|
|
349
|
+
const newTokenIndices = {
|
|
350
|
+
prompt: options.promptIndex ?? 0,
|
|
351
|
+
completion: choice.index ?? 0,
|
|
352
|
+
};
|
|
353
|
+
if (typeof chunk.content !== 'string') {
|
|
354
|
+
// eslint-disable-next-line no-console
|
|
355
|
+
console.log(
|
|
356
|
+
'[WARNING]: Received non-string content from OpenAI. This is currently not supported.'
|
|
357
|
+
);
|
|
358
|
+
continue;
|
|
359
|
+
}
|
|
360
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
361
|
+
const generationInfo: Record<string, any> = { ...newTokenIndices };
|
|
362
|
+
if (choice.finish_reason != null) {
|
|
363
|
+
generationInfo.finish_reason = choice.finish_reason;
|
|
364
|
+
// Only include system fingerprint in the last chunk for now
|
|
365
|
+
// to avoid concatenation issues
|
|
366
|
+
generationInfo.system_fingerprint = data.system_fingerprint;
|
|
367
|
+
generationInfo.model_name = data.model;
|
|
368
|
+
generationInfo.service_tier = data.service_tier;
|
|
369
|
+
}
|
|
370
|
+
if (this.logprobs == true) {
|
|
371
|
+
generationInfo.logprobs = choice.logprobs;
|
|
372
|
+
}
|
|
373
|
+
const generationChunk = new ChatGenerationChunk({
|
|
374
|
+
message: chunk,
|
|
375
|
+
text: chunk.content,
|
|
376
|
+
generationInfo,
|
|
377
|
+
});
|
|
378
|
+
yield generationChunk;
|
|
379
|
+
await runManager?.handleLLMNewToken(
|
|
380
|
+
generationChunk.text || '',
|
|
381
|
+
newTokenIndices,
|
|
382
|
+
undefined,
|
|
383
|
+
undefined,
|
|
384
|
+
undefined,
|
|
385
|
+
{ chunk: generationChunk }
|
|
386
|
+
);
|
|
387
|
+
}
|
|
388
|
+
if (usage) {
|
|
389
|
+
const inputTokenDetails = {
|
|
390
|
+
...(usage.prompt_tokens_details?.audio_tokens != null && {
|
|
391
|
+
audio: usage.prompt_tokens_details.audio_tokens,
|
|
392
|
+
}),
|
|
393
|
+
...(usage.prompt_tokens_details?.cached_tokens != null && {
|
|
394
|
+
cache_read: usage.prompt_tokens_details.cached_tokens,
|
|
395
|
+
}),
|
|
396
|
+
};
|
|
397
|
+
const outputTokenDetails = {
|
|
398
|
+
...(usage.completion_tokens_details?.audio_tokens != null && {
|
|
399
|
+
audio: usage.completion_tokens_details.audio_tokens,
|
|
400
|
+
}),
|
|
401
|
+
...(usage.completion_tokens_details?.reasoning_tokens != null && {
|
|
402
|
+
reasoning: usage.completion_tokens_details.reasoning_tokens,
|
|
403
|
+
}),
|
|
404
|
+
};
|
|
405
|
+
const generationChunk = new ChatGenerationChunk({
|
|
406
|
+
message: new AIMessageChunk({
|
|
407
|
+
content: '',
|
|
408
|
+
response_metadata: {
|
|
409
|
+
usage: { ...usage },
|
|
410
|
+
},
|
|
411
|
+
usage_metadata: {
|
|
412
|
+
input_tokens: usage.prompt_tokens,
|
|
413
|
+
output_tokens: usage.completion_tokens,
|
|
414
|
+
total_tokens: usage.total_tokens,
|
|
415
|
+
...(Object.keys(inputTokenDetails).length > 0 && {
|
|
416
|
+
input_token_details: inputTokenDetails,
|
|
417
|
+
}),
|
|
418
|
+
...(Object.keys(outputTokenDetails).length > 0 && {
|
|
419
|
+
output_token_details: outputTokenDetails,
|
|
420
|
+
}),
|
|
421
|
+
},
|
|
422
|
+
}),
|
|
423
|
+
text: '',
|
|
424
|
+
});
|
|
425
|
+
yield generationChunk;
|
|
426
|
+
}
|
|
427
|
+
if (options.signal?.aborted === true) {
|
|
428
|
+
throw new Error('AbortError');
|
|
429
|
+
}
|
|
430
|
+
}
|
|
121
431
|
}
|
|
122
432
|
|
|
433
|
+
/** @ts-expect-error We are intentionally overriding `getReasoningParams` */
|
|
123
434
|
export class AzureChatOpenAI extends OriginalAzureChatOpenAI {
|
|
124
435
|
public get exposedClient(): CustomOpenAIClient {
|
|
125
436
|
return this.client;
|
|
126
437
|
}
|
|
438
|
+
/**
|
|
439
|
+
* Returns backwards compatible reasoning parameters from constructor params and call options
|
|
440
|
+
* @internal
|
|
441
|
+
*/
|
|
442
|
+
getReasoningParams(
|
|
443
|
+
options?: this['ParsedCallOptions']
|
|
444
|
+
): OpenAIClient.Reasoning | undefined {
|
|
445
|
+
if (!isReasoningModel(this.model)) {
|
|
446
|
+
return;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
// apply options in reverse order of importance -- newer options supersede older options
|
|
450
|
+
let reasoning: OpenAIClient.Reasoning | undefined;
|
|
451
|
+
if (this.reasoning !== undefined) {
|
|
452
|
+
reasoning = {
|
|
453
|
+
...reasoning,
|
|
454
|
+
...this.reasoning,
|
|
455
|
+
};
|
|
456
|
+
}
|
|
457
|
+
if (options?.reasoning !== undefined) {
|
|
458
|
+
reasoning = {
|
|
459
|
+
...reasoning,
|
|
460
|
+
...options.reasoning,
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
return reasoning;
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
protected _getReasoningParams(
|
|
468
|
+
options?: this['ParsedCallOptions']
|
|
469
|
+
): OpenAIClient.Reasoning | undefined {
|
|
470
|
+
return this.getReasoningParams(options);
|
|
471
|
+
}
|
|
472
|
+
|
|
127
473
|
protected _getClientOptions(
|
|
128
|
-
options:
|
|
129
|
-
):
|
|
130
|
-
if (!(this.client as AzureOpenAIClient | undefined)) {
|
|
474
|
+
options: OpenAICoreRequestOptions | undefined
|
|
475
|
+
): OpenAICoreRequestOptions {
|
|
476
|
+
if (!(this.client as unknown as AzureOpenAIClient | undefined)) {
|
|
131
477
|
const openAIEndpointConfig: t.OpenAIEndpointConfig = {
|
|
132
478
|
azureOpenAIApiDeploymentName: this.azureOpenAIApiDeploymentName,
|
|
133
479
|
azureOpenAIApiInstanceName: this.azureOpenAIApiInstanceName,
|
|
@@ -154,25 +500,26 @@ export class AzureChatOpenAI extends OriginalAzureChatOpenAI {
|
|
|
154
500
|
delete params.baseURL;
|
|
155
501
|
}
|
|
156
502
|
|
|
503
|
+
const defaultHeaders = normalizeHeaders(params.defaultHeaders);
|
|
157
504
|
params.defaultHeaders = {
|
|
158
505
|
...params.defaultHeaders,
|
|
159
506
|
'User-Agent':
|
|
160
|
-
|
|
161
|
-
? `${
|
|
162
|
-
: '
|
|
507
|
+
defaultHeaders['User-Agent'] != null
|
|
508
|
+
? `${defaultHeaders['User-Agent']}: librechat-azure-openai-v2`
|
|
509
|
+
: 'librechat-azure-openai-v2',
|
|
163
510
|
};
|
|
164
511
|
|
|
165
512
|
this.client = new CustomAzureOpenAIClient({
|
|
166
513
|
apiVersion: this.azureOpenAIApiVersion,
|
|
167
514
|
azureADTokenProvider: this.azureADTokenProvider,
|
|
168
|
-
...params,
|
|
169
|
-
});
|
|
515
|
+
...(params as t.AzureOpenAIInput),
|
|
516
|
+
}) as unknown as CustomOpenAIClient;
|
|
170
517
|
}
|
|
171
518
|
|
|
172
519
|
const requestOptions = {
|
|
173
520
|
...this.clientConfig,
|
|
174
521
|
...options,
|
|
175
|
-
} as
|
|
522
|
+
} as OpenAICoreRequestOptions;
|
|
176
523
|
if (this.azureOpenAIApiKey != null) {
|
|
177
524
|
requestOptions.headers = {
|
|
178
525
|
'api-key': this.azureOpenAIApiKey,
|
|
@@ -185,8 +532,46 @@ export class AzureChatOpenAI extends OriginalAzureChatOpenAI {
|
|
|
185
532
|
}
|
|
186
533
|
return requestOptions;
|
|
187
534
|
}
|
|
188
|
-
|
|
535
|
+
async *_streamResponseChunks(
|
|
536
|
+
messages: BaseMessage[],
|
|
537
|
+
options: this['ParsedCallOptions'],
|
|
538
|
+
runManager?: CallbackManagerForLLMRun
|
|
539
|
+
): AsyncGenerator<ChatGenerationChunk> {
|
|
540
|
+
if (!this._useResponseApi(options)) {
|
|
541
|
+
return yield* super._streamResponseChunks(messages, options, runManager);
|
|
542
|
+
}
|
|
543
|
+
const streamIterable = await this.responseApiWithRetry(
|
|
544
|
+
{
|
|
545
|
+
...this.invocationParams<'responses'>(options, { streaming: true }),
|
|
546
|
+
input: _convertMessagesToOpenAIResponsesParams(
|
|
547
|
+
messages,
|
|
548
|
+
this.model,
|
|
549
|
+
this.zdrEnabled
|
|
550
|
+
),
|
|
551
|
+
stream: true,
|
|
552
|
+
},
|
|
553
|
+
options
|
|
554
|
+
);
|
|
555
|
+
|
|
556
|
+
for await (const data of streamIterable) {
|
|
557
|
+
const chunk = _convertOpenAIResponsesDeltaToBaseMessageChunk(
|
|
558
|
+
data as ResponseReturnStreamEvents
|
|
559
|
+
);
|
|
560
|
+
if (chunk == null) continue;
|
|
561
|
+
yield chunk;
|
|
562
|
+
await runManager?.handleLLMNewToken(
|
|
563
|
+
chunk.text || '',
|
|
564
|
+
undefined,
|
|
565
|
+
undefined,
|
|
566
|
+
undefined,
|
|
567
|
+
undefined,
|
|
568
|
+
{ chunk }
|
|
569
|
+
);
|
|
570
|
+
}
|
|
189
571
|
|
|
572
|
+
return;
|
|
573
|
+
}
|
|
574
|
+
}
|
|
190
575
|
export class ChatDeepSeek extends OriginalChatDeepSeek {
|
|
191
576
|
public get exposedClient(): CustomOpenAIClient {
|
|
192
577
|
return this.client;
|
|
@@ -220,10 +605,49 @@ export class ChatDeepSeek extends OriginalChatDeepSeek {
|
|
|
220
605
|
}
|
|
221
606
|
}
|
|
222
607
|
|
|
608
|
+
/** xAI-specific usage metadata type */
|
|
609
|
+
export interface XAIUsageMetadata
|
|
610
|
+
extends OpenAIClient.Completions.CompletionUsage {
|
|
611
|
+
prompt_tokens_details?: {
|
|
612
|
+
audio_tokens?: number;
|
|
613
|
+
cached_tokens?: number;
|
|
614
|
+
text_tokens?: number;
|
|
615
|
+
image_tokens?: number;
|
|
616
|
+
};
|
|
617
|
+
completion_tokens_details?: {
|
|
618
|
+
audio_tokens?: number;
|
|
619
|
+
reasoning_tokens?: number;
|
|
620
|
+
accepted_prediction_tokens?: number;
|
|
621
|
+
rejected_prediction_tokens?: number;
|
|
622
|
+
};
|
|
623
|
+
num_sources_used?: number;
|
|
624
|
+
}
|
|
625
|
+
|
|
223
626
|
export class ChatXAI extends OriginalChatXAI {
|
|
627
|
+
constructor(
|
|
628
|
+
fields?: Partial<ChatXAIInput> & {
|
|
629
|
+
configuration?: { baseURL?: string };
|
|
630
|
+
clientConfig?: { baseURL?: string };
|
|
631
|
+
}
|
|
632
|
+
) {
|
|
633
|
+
super(fields);
|
|
634
|
+
const customBaseURL =
|
|
635
|
+
fields?.configuration?.baseURL ?? fields?.clientConfig?.baseURL;
|
|
636
|
+
if (customBaseURL != null && customBaseURL) {
|
|
637
|
+
this.clientConfig = {
|
|
638
|
+
...this.clientConfig,
|
|
639
|
+
baseURL: customBaseURL,
|
|
640
|
+
};
|
|
641
|
+
// Reset the client to force recreation with new config
|
|
642
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
643
|
+
this.client = undefined as any;
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
|
|
224
647
|
public get exposedClient(): CustomOpenAIClient {
|
|
225
648
|
return this.client;
|
|
226
649
|
}
|
|
650
|
+
|
|
227
651
|
protected _getClientOptions(
|
|
228
652
|
options?: OpenAICoreRequestOptions
|
|
229
653
|
): OpenAICoreRequestOptions {
|
|
@@ -251,4 +675,166 @@ export class ChatXAI extends OriginalChatXAI {
|
|
|
251
675
|
} as OpenAICoreRequestOptions;
|
|
252
676
|
return requestOptions;
|
|
253
677
|
}
|
|
678
|
+
|
|
679
|
+
async *_streamResponseChunks(
|
|
680
|
+
messages: BaseMessage[],
|
|
681
|
+
options: this['ParsedCallOptions'],
|
|
682
|
+
runManager?: CallbackManagerForLLMRun
|
|
683
|
+
): AsyncGenerator<ChatGenerationChunk> {
|
|
684
|
+
const messagesMapped: OpenAICompletionParam[] =
|
|
685
|
+
_convertMessagesToOpenAIParams(messages, this.model);
|
|
686
|
+
|
|
687
|
+
const params = {
|
|
688
|
+
...this.invocationParams(options, {
|
|
689
|
+
streaming: true,
|
|
690
|
+
}),
|
|
691
|
+
messages: messagesMapped,
|
|
692
|
+
stream: true as const,
|
|
693
|
+
};
|
|
694
|
+
let defaultRole: OpenAIRoleEnum | undefined;
|
|
695
|
+
|
|
696
|
+
const streamIterable = await this.completionWithRetry(params, options);
|
|
697
|
+
let usage: OpenAIClient.Completions.CompletionUsage | undefined;
|
|
698
|
+
for await (const data of streamIterable) {
|
|
699
|
+
const choice = data.choices[0] as
|
|
700
|
+
| Partial<OpenAIClient.Chat.Completions.ChatCompletionChunk.Choice>
|
|
701
|
+
| undefined;
|
|
702
|
+
if (data.usage) {
|
|
703
|
+
usage = data.usage;
|
|
704
|
+
}
|
|
705
|
+
if (!choice) {
|
|
706
|
+
continue;
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
const { delta } = choice;
|
|
710
|
+
if (!delta) {
|
|
711
|
+
continue;
|
|
712
|
+
}
|
|
713
|
+
const chunk = this._convertOpenAIDeltaToBaseMessageChunk(
|
|
714
|
+
delta,
|
|
715
|
+
data,
|
|
716
|
+
defaultRole
|
|
717
|
+
);
|
|
718
|
+
if (chunk.usage_metadata != null) {
|
|
719
|
+
chunk.usage_metadata = {
|
|
720
|
+
input_tokens:
|
|
721
|
+
(chunk.usage_metadata as Partial<UsageMetadata>).input_tokens ?? 0,
|
|
722
|
+
output_tokens:
|
|
723
|
+
(chunk.usage_metadata as Partial<UsageMetadata>).output_tokens ?? 0,
|
|
724
|
+
total_tokens:
|
|
725
|
+
(chunk.usage_metadata as Partial<UsageMetadata>).total_tokens ?? 0,
|
|
726
|
+
};
|
|
727
|
+
}
|
|
728
|
+
if ('reasoning_content' in delta) {
|
|
729
|
+
chunk.additional_kwargs.reasoning_content = delta.reasoning_content;
|
|
730
|
+
}
|
|
731
|
+
defaultRole = delta.role ?? defaultRole;
|
|
732
|
+
const newTokenIndices = {
|
|
733
|
+
prompt: (options as OpenAIChatCallOptions).promptIndex ?? 0,
|
|
734
|
+
completion: choice.index ?? 0,
|
|
735
|
+
};
|
|
736
|
+
if (typeof chunk.content !== 'string') {
|
|
737
|
+
// eslint-disable-next-line no-console
|
|
738
|
+
console.log(
|
|
739
|
+
'[WARNING]: Received non-string content from OpenAI. This is currently not supported.'
|
|
740
|
+
);
|
|
741
|
+
continue;
|
|
742
|
+
}
|
|
743
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
744
|
+
const generationInfo: Record<string, any> = { ...newTokenIndices };
|
|
745
|
+
if (choice.finish_reason != null) {
|
|
746
|
+
generationInfo.finish_reason = choice.finish_reason;
|
|
747
|
+
// Only include system fingerprint in the last chunk for now
|
|
748
|
+
// to avoid concatenation issues
|
|
749
|
+
generationInfo.system_fingerprint = data.system_fingerprint;
|
|
750
|
+
generationInfo.model_name = data.model;
|
|
751
|
+
generationInfo.service_tier = data.service_tier;
|
|
752
|
+
}
|
|
753
|
+
if (this.logprobs == true) {
|
|
754
|
+
generationInfo.logprobs = choice.logprobs;
|
|
755
|
+
}
|
|
756
|
+
const generationChunk = new ChatGenerationChunk({
|
|
757
|
+
message: chunk,
|
|
758
|
+
text: chunk.content,
|
|
759
|
+
generationInfo,
|
|
760
|
+
});
|
|
761
|
+
yield generationChunk;
|
|
762
|
+
await runManager?.handleLLMNewToken(
|
|
763
|
+
generationChunk.text || '',
|
|
764
|
+
newTokenIndices,
|
|
765
|
+
undefined,
|
|
766
|
+
undefined,
|
|
767
|
+
undefined,
|
|
768
|
+
{ chunk: generationChunk }
|
|
769
|
+
);
|
|
770
|
+
}
|
|
771
|
+
if (usage) {
|
|
772
|
+
// Type assertion for xAI-specific usage structure
|
|
773
|
+
const xaiUsage = usage as XAIUsageMetadata;
|
|
774
|
+
const inputTokenDetails = {
|
|
775
|
+
// Standard OpenAI fields
|
|
776
|
+
...(usage.prompt_tokens_details?.audio_tokens != null && {
|
|
777
|
+
audio: usage.prompt_tokens_details.audio_tokens,
|
|
778
|
+
}),
|
|
779
|
+
...(usage.prompt_tokens_details?.cached_tokens != null && {
|
|
780
|
+
cache_read: usage.prompt_tokens_details.cached_tokens,
|
|
781
|
+
}),
|
|
782
|
+
// Add xAI-specific prompt token details if they exist
|
|
783
|
+
...(xaiUsage.prompt_tokens_details?.text_tokens != null && {
|
|
784
|
+
text: xaiUsage.prompt_tokens_details.text_tokens,
|
|
785
|
+
}),
|
|
786
|
+
...(xaiUsage.prompt_tokens_details?.image_tokens != null && {
|
|
787
|
+
image: xaiUsage.prompt_tokens_details.image_tokens,
|
|
788
|
+
}),
|
|
789
|
+
};
|
|
790
|
+
const outputTokenDetails = {
|
|
791
|
+
// Standard OpenAI fields
|
|
792
|
+
...(usage.completion_tokens_details?.audio_tokens != null && {
|
|
793
|
+
audio: usage.completion_tokens_details.audio_tokens,
|
|
794
|
+
}),
|
|
795
|
+
...(usage.completion_tokens_details?.reasoning_tokens != null && {
|
|
796
|
+
reasoning: usage.completion_tokens_details.reasoning_tokens,
|
|
797
|
+
}),
|
|
798
|
+
// Add xAI-specific completion token details if they exist
|
|
799
|
+
...(xaiUsage.completion_tokens_details?.accepted_prediction_tokens !=
|
|
800
|
+
null && {
|
|
801
|
+
accepted_prediction:
|
|
802
|
+
xaiUsage.completion_tokens_details.accepted_prediction_tokens,
|
|
803
|
+
}),
|
|
804
|
+
...(xaiUsage.completion_tokens_details?.rejected_prediction_tokens !=
|
|
805
|
+
null && {
|
|
806
|
+
rejected_prediction:
|
|
807
|
+
xaiUsage.completion_tokens_details.rejected_prediction_tokens,
|
|
808
|
+
}),
|
|
809
|
+
};
|
|
810
|
+
const generationChunk = new ChatGenerationChunk({
|
|
811
|
+
message: new AIMessageChunk({
|
|
812
|
+
content: '',
|
|
813
|
+
response_metadata: {
|
|
814
|
+
usage: { ...usage },
|
|
815
|
+
// Include xAI-specific metadata if it exists
|
|
816
|
+
...(xaiUsage.num_sources_used != null && {
|
|
817
|
+
num_sources_used: xaiUsage.num_sources_used,
|
|
818
|
+
}),
|
|
819
|
+
},
|
|
820
|
+
usage_metadata: {
|
|
821
|
+
input_tokens: usage.prompt_tokens,
|
|
822
|
+
output_tokens: usage.completion_tokens,
|
|
823
|
+
total_tokens: usage.total_tokens,
|
|
824
|
+
...(Object.keys(inputTokenDetails).length > 0 && {
|
|
825
|
+
input_token_details: inputTokenDetails,
|
|
826
|
+
}),
|
|
827
|
+
...(Object.keys(outputTokenDetails).length > 0 && {
|
|
828
|
+
output_token_details: outputTokenDetails,
|
|
829
|
+
}),
|
|
830
|
+
},
|
|
831
|
+
}),
|
|
832
|
+
text: '',
|
|
833
|
+
});
|
|
834
|
+
yield generationChunk;
|
|
835
|
+
}
|
|
836
|
+
if (options.signal?.aborted === true) {
|
|
837
|
+
throw new Error('AbortError');
|
|
838
|
+
}
|
|
839
|
+
}
|
|
254
840
|
}
|