@librechat/agents 2.4.322 → 3.0.0-rc10
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 +15 -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 -213
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/graphs/MultiAgentGraph.cjs +507 -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 +422 -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 +137 -85
- package/dist/cjs/run.cjs.map +1 -1
- package/dist/cjs/stream.cjs +86 -52
- 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 +16 -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 -215
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/graphs/MultiAgentGraph.mjs +505 -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 +421 -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 +138 -87
- package/dist/esm/run.mjs.map +1 -1
- package/dist/esm/stream.mjs +88 -55
- 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 +17 -7
- package/dist/types/events.d.ts +5 -4
- package/dist/types/graphs/Graph.d.ts +64 -67
- package/dist/types/graphs/MultiAgentGraph.d.ts +47 -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 +82 -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/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 +129 -15
- package/dist/types/types/llm.d.ts +25 -10
- package/dist/types/types/run.d.ts +50 -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 +41 -17
- package/src/agents/AgentContext.ts +315 -0
- package/src/common/enum.ts +15 -5
- package/src/events.ts +24 -13
- package/src/graphs/Graph.ts +495 -313
- package/src/graphs/MultiAgentGraph.ts +598 -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 +641 -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 +196 -116
- 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-chain.ts +278 -0
- package/src/scripts/multi-agent-conditional.ts +220 -0
- package/src/scripts/multi-agent-document-review-chain.ts +197 -0
- package/src/scripts/multi-agent-hybrid-flow.ts +310 -0
- package/src/scripts/multi-agent-parallel.ts +341 -0
- package/src/scripts/multi-agent-sequence.ts +212 -0
- package/src/scripts/multi-agent-supervisor.ts +362 -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/test-custom-prompt-key.ts +145 -0
- package/src/scripts/test-handoff-input.ts +170 -0
- package/src/scripts/test-multi-agent-list-handoff.ts +261 -0
- package/src/scripts/test-tools-before-handoff.ts +233 -0
- 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 +143 -61
- 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 +318 -103
- package/src/types/llm.ts +26 -12
- package/src/types/run.ts +56 -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/dist/types/scripts/abort.d.ts +0 -1
- package/dist/types/scripts/args.d.ts +0 -6
- package/dist/types/scripts/caching.d.ts +0 -1
- package/dist/types/scripts/cli.d.ts +0 -1
- package/dist/types/scripts/cli2.d.ts +0 -1
- package/dist/types/scripts/cli3.d.ts +0 -1
- package/dist/types/scripts/cli4.d.ts +0 -1
- package/dist/types/scripts/cli5.d.ts +0 -1
- package/dist/types/scripts/code_exec.d.ts +0 -1
- package/dist/types/scripts/code_exec_files.d.ts +0 -1
- package/dist/types/scripts/code_exec_simple.d.ts +0 -1
- package/dist/types/scripts/content.d.ts +0 -1
- package/dist/types/scripts/empty_input.d.ts +0 -1
- package/dist/types/scripts/image.d.ts +0 -1
- package/dist/types/scripts/memory.d.ts +0 -1
- package/dist/types/scripts/search.d.ts +0 -1
- package/dist/types/scripts/simple.d.ts +0 -1
- package/dist/types/scripts/stream.d.ts +0 -1
- package/dist/types/scripts/thinking.d.ts +0 -1
- package/dist/types/scripts/tools.d.ts +0 -1
- package/dist/types/specs/spec.utils.d.ts +0 -1
package/src/llm/openai/index.ts
CHANGED
|
@@ -1,21 +1,128 @@
|
|
|
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
|
+
import { sleep } from '@/utils';
|
|
34
|
+
|
|
35
|
+
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
|
36
|
+
const iife = <T>(fn: () => T) => fn();
|
|
37
|
+
|
|
38
|
+
export function isHeaders(headers: unknown): headers is Headers {
|
|
39
|
+
return (
|
|
40
|
+
typeof Headers !== 'undefined' &&
|
|
41
|
+
headers !== null &&
|
|
42
|
+
typeof headers === 'object' &&
|
|
43
|
+
Object.prototype.toString.call(headers) === '[object Headers]'
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function normalizeHeaders(
|
|
48
|
+
headers: HeadersLike
|
|
49
|
+
): Record<string, HeaderValue | readonly HeaderValue[]> {
|
|
50
|
+
const output = iife(() => {
|
|
51
|
+
// If headers is a Headers instance
|
|
52
|
+
if (isHeaders(headers)) {
|
|
53
|
+
return headers;
|
|
54
|
+
}
|
|
55
|
+
// If headers is an array of [key, value] pairs
|
|
56
|
+
else if (Array.isArray(headers)) {
|
|
57
|
+
return new Headers(headers);
|
|
58
|
+
}
|
|
59
|
+
// If headers is a NullableHeaders-like object (has 'values' property that is a Headers)
|
|
60
|
+
else if (
|
|
61
|
+
typeof headers === 'object' &&
|
|
62
|
+
headers !== null &&
|
|
63
|
+
'values' in headers &&
|
|
64
|
+
isHeaders(headers.values)
|
|
65
|
+
) {
|
|
66
|
+
return headers.values;
|
|
67
|
+
}
|
|
68
|
+
// If headers is a plain object
|
|
69
|
+
else if (typeof headers === 'object' && headers !== null) {
|
|
70
|
+
const entries: [string, string][] = Object.entries(headers)
|
|
71
|
+
.filter(([, v]) => typeof v === 'string')
|
|
72
|
+
.map(([k, v]) => [k, v as string]);
|
|
73
|
+
return new Headers(entries);
|
|
74
|
+
}
|
|
75
|
+
return new Headers();
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
return Object.fromEntries(output.entries());
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
type OpenAICompletionParam =
|
|
82
|
+
OpenAIClient.Chat.Completions.ChatCompletionMessageParam;
|
|
83
|
+
|
|
84
|
+
type OpenAICoreRequestOptions = OpenAIClient.RequestOptions;
|
|
12
85
|
|
|
13
86
|
function createAbortHandler(controller: AbortController): () => void {
|
|
14
87
|
return function (): void {
|
|
15
88
|
controller.abort();
|
|
16
89
|
};
|
|
17
90
|
}
|
|
91
|
+
/**
|
|
92
|
+
* Formats a tool in either OpenAI format, or LangChain structured tool format
|
|
93
|
+
* into an OpenAI tool format. If the tool is already in OpenAI format, return without
|
|
94
|
+
* any changes. If it is in LangChain structured tool format, convert it to OpenAI tool format
|
|
95
|
+
* using OpenAI's `zodFunction` util, falling back to `convertToOpenAIFunction` if the parameters
|
|
96
|
+
* returned from the `zodFunction` util are not defined.
|
|
97
|
+
*
|
|
98
|
+
* @param {BindToolsInput} tool The tool to convert to an OpenAI tool.
|
|
99
|
+
* @param {Object} [fields] Additional fields to add to the OpenAI tool.
|
|
100
|
+
* @returns {ToolDefinition} The inputted tool in OpenAI tool format.
|
|
101
|
+
*/
|
|
102
|
+
export function _convertToOpenAITool(
|
|
103
|
+
tool: BindToolsInput,
|
|
104
|
+
fields?: {
|
|
105
|
+
/**
|
|
106
|
+
* If `true`, model output is guaranteed to exactly match the JSON Schema
|
|
107
|
+
* provided in the function definition.
|
|
108
|
+
*/
|
|
109
|
+
strict?: boolean;
|
|
110
|
+
}
|
|
111
|
+
): OpenAIClient.ChatCompletionTool {
|
|
112
|
+
let toolDef: OpenAIClient.ChatCompletionTool | undefined;
|
|
113
|
+
|
|
114
|
+
if (isLangChainTool(tool)) {
|
|
115
|
+
toolDef = formatToOpenAITool(tool);
|
|
116
|
+
} else {
|
|
117
|
+
toolDef = tool as ToolDefinition;
|
|
118
|
+
}
|
|
18
119
|
|
|
120
|
+
if (fields?.strict !== undefined) {
|
|
121
|
+
toolDef.function.strict = fields.strict;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
return toolDef;
|
|
125
|
+
}
|
|
19
126
|
export class CustomOpenAIClient extends OpenAIClient {
|
|
20
127
|
abortHandler?: () => void;
|
|
21
128
|
async fetchWithTimeout(
|
|
@@ -87,13 +194,25 @@ export class CustomAzureOpenAIClient extends AzureOpenAIClient {
|
|
|
87
194
|
}
|
|
88
195
|
}
|
|
89
196
|
|
|
197
|
+
/** @ts-expect-error We are intentionally overriding `getReasoningParams` */
|
|
90
198
|
export class ChatOpenAI extends OriginalChatOpenAI<t.ChatOpenAICallOptions> {
|
|
199
|
+
_lc_stream_delay?: number;
|
|
200
|
+
|
|
201
|
+
constructor(
|
|
202
|
+
fields?: t.ChatOpenAICallOptions & {
|
|
203
|
+
_lc_stream_delay?: number;
|
|
204
|
+
} & t.OpenAIChatInput['modelKwargs']
|
|
205
|
+
) {
|
|
206
|
+
super(fields);
|
|
207
|
+
this._lc_stream_delay = fields?._lc_stream_delay;
|
|
208
|
+
}
|
|
209
|
+
|
|
91
210
|
public get exposedClient(): CustomOpenAIClient {
|
|
92
211
|
return this.client;
|
|
93
212
|
}
|
|
94
213
|
protected _getClientOptions(
|
|
95
|
-
options?:
|
|
96
|
-
):
|
|
214
|
+
options?: OpenAICoreRequestOptions
|
|
215
|
+
): OpenAICoreRequestOptions {
|
|
97
216
|
if (!(this.client as OpenAIClient | undefined)) {
|
|
98
217
|
const openAIEndpointConfig: t.OpenAIEndpointConfig = {
|
|
99
218
|
baseURL: this.clientConfig.baseURL,
|
|
@@ -115,19 +234,274 @@ export class ChatOpenAI extends OriginalChatOpenAI<t.ChatOpenAICallOptions> {
|
|
|
115
234
|
const requestOptions = {
|
|
116
235
|
...this.clientConfig,
|
|
117
236
|
...options,
|
|
118
|
-
} as
|
|
237
|
+
} as OpenAICoreRequestOptions;
|
|
119
238
|
return requestOptions;
|
|
120
239
|
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Returns backwards compatible reasoning parameters from constructor params and call options
|
|
243
|
+
* @internal
|
|
244
|
+
*/
|
|
245
|
+
getReasoningParams(
|
|
246
|
+
options?: this['ParsedCallOptions']
|
|
247
|
+
): OpenAIClient.Reasoning | undefined {
|
|
248
|
+
if (!isReasoningModel(this.model)) {
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// apply options in reverse order of importance -- newer options supersede older options
|
|
253
|
+
let reasoning: OpenAIClient.Reasoning | undefined;
|
|
254
|
+
if (this.reasoning !== undefined) {
|
|
255
|
+
reasoning = {
|
|
256
|
+
...reasoning,
|
|
257
|
+
...this.reasoning,
|
|
258
|
+
};
|
|
259
|
+
}
|
|
260
|
+
if (options?.reasoning !== undefined) {
|
|
261
|
+
reasoning = {
|
|
262
|
+
...reasoning,
|
|
263
|
+
...options.reasoning,
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
return reasoning;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
protected _getReasoningParams(
|
|
271
|
+
options?: this['ParsedCallOptions']
|
|
272
|
+
): OpenAIClient.Reasoning | undefined {
|
|
273
|
+
return this.getReasoningParams(options);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
async *_streamResponseChunks(
|
|
277
|
+
messages: BaseMessage[],
|
|
278
|
+
options: this['ParsedCallOptions'],
|
|
279
|
+
runManager?: CallbackManagerForLLMRun
|
|
280
|
+
): AsyncGenerator<ChatGenerationChunk> {
|
|
281
|
+
if (!this._useResponseApi(options)) {
|
|
282
|
+
return yield* this._streamResponseChunks2(messages, options, runManager);
|
|
283
|
+
}
|
|
284
|
+
const streamIterable = await this.responseApiWithRetry(
|
|
285
|
+
{
|
|
286
|
+
...this.invocationParams<'responses'>(options, { streaming: true }),
|
|
287
|
+
input: _convertMessagesToOpenAIResponsesParams(
|
|
288
|
+
messages,
|
|
289
|
+
this.model,
|
|
290
|
+
this.zdrEnabled
|
|
291
|
+
),
|
|
292
|
+
stream: true,
|
|
293
|
+
},
|
|
294
|
+
options
|
|
295
|
+
);
|
|
296
|
+
|
|
297
|
+
for await (const data of streamIterable) {
|
|
298
|
+
const chunk = _convertOpenAIResponsesDeltaToBaseMessageChunk(
|
|
299
|
+
data as ResponseReturnStreamEvents
|
|
300
|
+
);
|
|
301
|
+
if (chunk == null) continue;
|
|
302
|
+
yield chunk;
|
|
303
|
+
if (this._lc_stream_delay != null) {
|
|
304
|
+
await sleep(this._lc_stream_delay);
|
|
305
|
+
}
|
|
306
|
+
await runManager?.handleLLMNewToken(
|
|
307
|
+
chunk.text || '',
|
|
308
|
+
undefined,
|
|
309
|
+
undefined,
|
|
310
|
+
undefined,
|
|
311
|
+
undefined,
|
|
312
|
+
{ chunk }
|
|
313
|
+
);
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
async *_streamResponseChunks2(
|
|
320
|
+
messages: BaseMessage[],
|
|
321
|
+
options: this['ParsedCallOptions'],
|
|
322
|
+
runManager?: CallbackManagerForLLMRun
|
|
323
|
+
): AsyncGenerator<ChatGenerationChunk> {
|
|
324
|
+
const messagesMapped: OpenAICompletionParam[] =
|
|
325
|
+
_convertMessagesToOpenAIParams(messages, this.model);
|
|
326
|
+
|
|
327
|
+
const params = {
|
|
328
|
+
...this.invocationParams(options, {
|
|
329
|
+
streaming: true,
|
|
330
|
+
}),
|
|
331
|
+
messages: messagesMapped,
|
|
332
|
+
stream: true as const,
|
|
333
|
+
};
|
|
334
|
+
let defaultRole: OpenAIRoleEnum | undefined;
|
|
335
|
+
|
|
336
|
+
const streamIterable = await this.completionWithRetry(params, options);
|
|
337
|
+
let usage: OpenAIClient.Completions.CompletionUsage | undefined;
|
|
338
|
+
for await (const data of streamIterable) {
|
|
339
|
+
const choice = data.choices[0] as
|
|
340
|
+
| Partial<OpenAIClient.Chat.Completions.ChatCompletionChunk.Choice>
|
|
341
|
+
| undefined;
|
|
342
|
+
if (data.usage) {
|
|
343
|
+
usage = data.usage;
|
|
344
|
+
}
|
|
345
|
+
if (!choice) {
|
|
346
|
+
continue;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
const { delta } = choice;
|
|
350
|
+
if (!delta) {
|
|
351
|
+
continue;
|
|
352
|
+
}
|
|
353
|
+
const chunk = this._convertOpenAIDeltaToBaseMessageChunk(
|
|
354
|
+
delta,
|
|
355
|
+
data,
|
|
356
|
+
defaultRole
|
|
357
|
+
);
|
|
358
|
+
if ('reasoning_content' in delta) {
|
|
359
|
+
chunk.additional_kwargs.reasoning_content = delta.reasoning_content;
|
|
360
|
+
} else if ('reasoning' in delta) {
|
|
361
|
+
chunk.additional_kwargs.reasoning_content = delta.reasoning;
|
|
362
|
+
}
|
|
363
|
+
defaultRole = delta.role ?? defaultRole;
|
|
364
|
+
const newTokenIndices = {
|
|
365
|
+
prompt: options.promptIndex ?? 0,
|
|
366
|
+
completion: choice.index ?? 0,
|
|
367
|
+
};
|
|
368
|
+
if (typeof chunk.content !== 'string') {
|
|
369
|
+
// eslint-disable-next-line no-console
|
|
370
|
+
console.log(
|
|
371
|
+
'[WARNING]: Received non-string content from OpenAI. This is currently not supported.'
|
|
372
|
+
);
|
|
373
|
+
continue;
|
|
374
|
+
}
|
|
375
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
376
|
+
const generationInfo: Record<string, any> = { ...newTokenIndices };
|
|
377
|
+
if (choice.finish_reason != null) {
|
|
378
|
+
generationInfo.finish_reason = choice.finish_reason;
|
|
379
|
+
// Only include system fingerprint in the last chunk for now
|
|
380
|
+
// to avoid concatenation issues
|
|
381
|
+
generationInfo.system_fingerprint = data.system_fingerprint;
|
|
382
|
+
generationInfo.model_name = data.model;
|
|
383
|
+
generationInfo.service_tier = data.service_tier;
|
|
384
|
+
}
|
|
385
|
+
if (this.logprobs == true) {
|
|
386
|
+
generationInfo.logprobs = choice.logprobs;
|
|
387
|
+
}
|
|
388
|
+
const generationChunk = new ChatGenerationChunk({
|
|
389
|
+
message: chunk,
|
|
390
|
+
text: chunk.content,
|
|
391
|
+
generationInfo,
|
|
392
|
+
});
|
|
393
|
+
yield generationChunk;
|
|
394
|
+
if (this._lc_stream_delay != null) {
|
|
395
|
+
await sleep(this._lc_stream_delay);
|
|
396
|
+
}
|
|
397
|
+
await runManager?.handleLLMNewToken(
|
|
398
|
+
generationChunk.text || '',
|
|
399
|
+
newTokenIndices,
|
|
400
|
+
undefined,
|
|
401
|
+
undefined,
|
|
402
|
+
undefined,
|
|
403
|
+
{ chunk: generationChunk }
|
|
404
|
+
);
|
|
405
|
+
}
|
|
406
|
+
if (usage) {
|
|
407
|
+
const inputTokenDetails = {
|
|
408
|
+
...(usage.prompt_tokens_details?.audio_tokens != null && {
|
|
409
|
+
audio: usage.prompt_tokens_details.audio_tokens,
|
|
410
|
+
}),
|
|
411
|
+
...(usage.prompt_tokens_details?.cached_tokens != null && {
|
|
412
|
+
cache_read: usage.prompt_tokens_details.cached_tokens,
|
|
413
|
+
}),
|
|
414
|
+
};
|
|
415
|
+
const outputTokenDetails = {
|
|
416
|
+
...(usage.completion_tokens_details?.audio_tokens != null && {
|
|
417
|
+
audio: usage.completion_tokens_details.audio_tokens,
|
|
418
|
+
}),
|
|
419
|
+
...(usage.completion_tokens_details?.reasoning_tokens != null && {
|
|
420
|
+
reasoning: usage.completion_tokens_details.reasoning_tokens,
|
|
421
|
+
}),
|
|
422
|
+
};
|
|
423
|
+
const generationChunk = new ChatGenerationChunk({
|
|
424
|
+
message: new AIMessageChunk({
|
|
425
|
+
content: '',
|
|
426
|
+
response_metadata: {
|
|
427
|
+
usage: { ...usage },
|
|
428
|
+
},
|
|
429
|
+
usage_metadata: {
|
|
430
|
+
input_tokens: usage.prompt_tokens,
|
|
431
|
+
output_tokens: usage.completion_tokens,
|
|
432
|
+
total_tokens: usage.total_tokens,
|
|
433
|
+
...(Object.keys(inputTokenDetails).length > 0 && {
|
|
434
|
+
input_token_details: inputTokenDetails,
|
|
435
|
+
}),
|
|
436
|
+
...(Object.keys(outputTokenDetails).length > 0 && {
|
|
437
|
+
output_token_details: outputTokenDetails,
|
|
438
|
+
}),
|
|
439
|
+
},
|
|
440
|
+
}),
|
|
441
|
+
text: '',
|
|
442
|
+
});
|
|
443
|
+
yield generationChunk;
|
|
444
|
+
if (this._lc_stream_delay != null) {
|
|
445
|
+
await sleep(this._lc_stream_delay);
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
if (options.signal?.aborted === true) {
|
|
449
|
+
throw new Error('AbortError');
|
|
450
|
+
}
|
|
451
|
+
}
|
|
121
452
|
}
|
|
122
453
|
|
|
454
|
+
/** @ts-expect-error We are intentionally overriding `getReasoningParams` */
|
|
123
455
|
export class AzureChatOpenAI extends OriginalAzureChatOpenAI {
|
|
456
|
+
_lc_stream_delay?: number;
|
|
457
|
+
|
|
458
|
+
constructor(fields?: t.AzureOpenAIInput & { _lc_stream_delay?: number }) {
|
|
459
|
+
super(fields);
|
|
460
|
+
this._lc_stream_delay = fields?._lc_stream_delay;
|
|
461
|
+
}
|
|
462
|
+
|
|
124
463
|
public get exposedClient(): CustomOpenAIClient {
|
|
125
464
|
return this.client;
|
|
126
465
|
}
|
|
466
|
+
/**
|
|
467
|
+
* Returns backwards compatible reasoning parameters from constructor params and call options
|
|
468
|
+
* @internal
|
|
469
|
+
*/
|
|
470
|
+
getReasoningParams(
|
|
471
|
+
options?: this['ParsedCallOptions']
|
|
472
|
+
): OpenAIClient.Reasoning | undefined {
|
|
473
|
+
if (!isReasoningModel(this.model)) {
|
|
474
|
+
return;
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
// apply options in reverse order of importance -- newer options supersede older options
|
|
478
|
+
let reasoning: OpenAIClient.Reasoning | undefined;
|
|
479
|
+
if (this.reasoning !== undefined) {
|
|
480
|
+
reasoning = {
|
|
481
|
+
...reasoning,
|
|
482
|
+
...this.reasoning,
|
|
483
|
+
};
|
|
484
|
+
}
|
|
485
|
+
if (options?.reasoning !== undefined) {
|
|
486
|
+
reasoning = {
|
|
487
|
+
...reasoning,
|
|
488
|
+
...options.reasoning,
|
|
489
|
+
};
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
return reasoning;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
protected _getReasoningParams(
|
|
496
|
+
options?: this['ParsedCallOptions']
|
|
497
|
+
): OpenAIClient.Reasoning | undefined {
|
|
498
|
+
return this.getReasoningParams(options);
|
|
499
|
+
}
|
|
500
|
+
|
|
127
501
|
protected _getClientOptions(
|
|
128
|
-
options:
|
|
129
|
-
):
|
|
130
|
-
if (!(this.client as AzureOpenAIClient | undefined)) {
|
|
502
|
+
options: OpenAICoreRequestOptions | undefined
|
|
503
|
+
): OpenAICoreRequestOptions {
|
|
504
|
+
if (!(this.client as unknown as AzureOpenAIClient | undefined)) {
|
|
131
505
|
const openAIEndpointConfig: t.OpenAIEndpointConfig = {
|
|
132
506
|
azureOpenAIApiDeploymentName: this.azureOpenAIApiDeploymentName,
|
|
133
507
|
azureOpenAIApiInstanceName: this.azureOpenAIApiInstanceName,
|
|
@@ -154,25 +528,26 @@ export class AzureChatOpenAI extends OriginalAzureChatOpenAI {
|
|
|
154
528
|
delete params.baseURL;
|
|
155
529
|
}
|
|
156
530
|
|
|
531
|
+
const defaultHeaders = normalizeHeaders(params.defaultHeaders);
|
|
157
532
|
params.defaultHeaders = {
|
|
158
533
|
...params.defaultHeaders,
|
|
159
534
|
'User-Agent':
|
|
160
|
-
|
|
161
|
-
? `${
|
|
162
|
-
: '
|
|
535
|
+
defaultHeaders['User-Agent'] != null
|
|
536
|
+
? `${defaultHeaders['User-Agent']}: librechat-azure-openai-v2`
|
|
537
|
+
: 'librechat-azure-openai-v2',
|
|
163
538
|
};
|
|
164
539
|
|
|
165
540
|
this.client = new CustomAzureOpenAIClient({
|
|
166
541
|
apiVersion: this.azureOpenAIApiVersion,
|
|
167
542
|
azureADTokenProvider: this.azureADTokenProvider,
|
|
168
|
-
...params,
|
|
169
|
-
});
|
|
543
|
+
...(params as t.AzureOpenAIInput),
|
|
544
|
+
}) as unknown as CustomOpenAIClient;
|
|
170
545
|
}
|
|
171
546
|
|
|
172
547
|
const requestOptions = {
|
|
173
548
|
...this.clientConfig,
|
|
174
549
|
...options,
|
|
175
|
-
} as
|
|
550
|
+
} as OpenAICoreRequestOptions;
|
|
176
551
|
if (this.azureOpenAIApiKey != null) {
|
|
177
552
|
requestOptions.headers = {
|
|
178
553
|
'api-key': this.azureOpenAIApiKey,
|
|
@@ -185,8 +560,49 @@ export class AzureChatOpenAI extends OriginalAzureChatOpenAI {
|
|
|
185
560
|
}
|
|
186
561
|
return requestOptions;
|
|
187
562
|
}
|
|
188
|
-
|
|
563
|
+
async *_streamResponseChunks(
|
|
564
|
+
messages: BaseMessage[],
|
|
565
|
+
options: this['ParsedCallOptions'],
|
|
566
|
+
runManager?: CallbackManagerForLLMRun
|
|
567
|
+
): AsyncGenerator<ChatGenerationChunk> {
|
|
568
|
+
if (!this._useResponseApi(options)) {
|
|
569
|
+
return yield* super._streamResponseChunks(messages, options, runManager);
|
|
570
|
+
}
|
|
571
|
+
const streamIterable = await this.responseApiWithRetry(
|
|
572
|
+
{
|
|
573
|
+
...this.invocationParams<'responses'>(options, { streaming: true }),
|
|
574
|
+
input: _convertMessagesToOpenAIResponsesParams(
|
|
575
|
+
messages,
|
|
576
|
+
this.model,
|
|
577
|
+
this.zdrEnabled
|
|
578
|
+
),
|
|
579
|
+
stream: true,
|
|
580
|
+
},
|
|
581
|
+
options
|
|
582
|
+
);
|
|
583
|
+
|
|
584
|
+
for await (const data of streamIterable) {
|
|
585
|
+
const chunk = _convertOpenAIResponsesDeltaToBaseMessageChunk(
|
|
586
|
+
data as ResponseReturnStreamEvents
|
|
587
|
+
);
|
|
588
|
+
if (chunk == null) continue;
|
|
589
|
+
yield chunk;
|
|
590
|
+
if (this._lc_stream_delay != null) {
|
|
591
|
+
await sleep(this._lc_stream_delay);
|
|
592
|
+
}
|
|
593
|
+
await runManager?.handleLLMNewToken(
|
|
594
|
+
chunk.text || '',
|
|
595
|
+
undefined,
|
|
596
|
+
undefined,
|
|
597
|
+
undefined,
|
|
598
|
+
undefined,
|
|
599
|
+
{ chunk }
|
|
600
|
+
);
|
|
601
|
+
}
|
|
189
602
|
|
|
603
|
+
return;
|
|
604
|
+
}
|
|
605
|
+
}
|
|
190
606
|
export class ChatDeepSeek extends OriginalChatDeepSeek {
|
|
191
607
|
public get exposedClient(): CustomOpenAIClient {
|
|
192
608
|
return this.client;
|
|
@@ -220,10 +636,53 @@ export class ChatDeepSeek extends OriginalChatDeepSeek {
|
|
|
220
636
|
}
|
|
221
637
|
}
|
|
222
638
|
|
|
639
|
+
/** xAI-specific usage metadata type */
|
|
640
|
+
export interface XAIUsageMetadata
|
|
641
|
+
extends OpenAIClient.Completions.CompletionUsage {
|
|
642
|
+
prompt_tokens_details?: {
|
|
643
|
+
audio_tokens?: number;
|
|
644
|
+
cached_tokens?: number;
|
|
645
|
+
text_tokens?: number;
|
|
646
|
+
image_tokens?: number;
|
|
647
|
+
};
|
|
648
|
+
completion_tokens_details?: {
|
|
649
|
+
audio_tokens?: number;
|
|
650
|
+
reasoning_tokens?: number;
|
|
651
|
+
accepted_prediction_tokens?: number;
|
|
652
|
+
rejected_prediction_tokens?: number;
|
|
653
|
+
};
|
|
654
|
+
num_sources_used?: number;
|
|
655
|
+
}
|
|
656
|
+
|
|
223
657
|
export class ChatXAI extends OriginalChatXAI {
|
|
658
|
+
_lc_stream_delay?: number;
|
|
659
|
+
|
|
660
|
+
constructor(
|
|
661
|
+
fields?: Partial<ChatXAIInput> & {
|
|
662
|
+
configuration?: { baseURL?: string };
|
|
663
|
+
clientConfig?: { baseURL?: string };
|
|
664
|
+
_lc_stream_delay?: number;
|
|
665
|
+
}
|
|
666
|
+
) {
|
|
667
|
+
super(fields);
|
|
668
|
+
this._lc_stream_delay = fields?._lc_stream_delay;
|
|
669
|
+
const customBaseURL =
|
|
670
|
+
fields?.configuration?.baseURL ?? fields?.clientConfig?.baseURL;
|
|
671
|
+
if (customBaseURL != null && customBaseURL) {
|
|
672
|
+
this.clientConfig = {
|
|
673
|
+
...this.clientConfig,
|
|
674
|
+
baseURL: customBaseURL,
|
|
675
|
+
};
|
|
676
|
+
// Reset the client to force recreation with new config
|
|
677
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
678
|
+
this.client = undefined as any;
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
|
|
224
682
|
public get exposedClient(): CustomOpenAIClient {
|
|
225
683
|
return this.client;
|
|
226
684
|
}
|
|
685
|
+
|
|
227
686
|
protected _getClientOptions(
|
|
228
687
|
options?: OpenAICoreRequestOptions
|
|
229
688
|
): OpenAICoreRequestOptions {
|
|
@@ -251,4 +710,172 @@ export class ChatXAI extends OriginalChatXAI {
|
|
|
251
710
|
} as OpenAICoreRequestOptions;
|
|
252
711
|
return requestOptions;
|
|
253
712
|
}
|
|
713
|
+
|
|
714
|
+
async *_streamResponseChunks(
|
|
715
|
+
messages: BaseMessage[],
|
|
716
|
+
options: this['ParsedCallOptions'],
|
|
717
|
+
runManager?: CallbackManagerForLLMRun
|
|
718
|
+
): AsyncGenerator<ChatGenerationChunk> {
|
|
719
|
+
const messagesMapped: OpenAICompletionParam[] =
|
|
720
|
+
_convertMessagesToOpenAIParams(messages, this.model);
|
|
721
|
+
|
|
722
|
+
const params = {
|
|
723
|
+
...this.invocationParams(options, {
|
|
724
|
+
streaming: true,
|
|
725
|
+
}),
|
|
726
|
+
messages: messagesMapped,
|
|
727
|
+
stream: true as const,
|
|
728
|
+
};
|
|
729
|
+
let defaultRole: OpenAIRoleEnum | undefined;
|
|
730
|
+
|
|
731
|
+
const streamIterable = await this.completionWithRetry(params, options);
|
|
732
|
+
let usage: OpenAIClient.Completions.CompletionUsage | undefined;
|
|
733
|
+
for await (const data of streamIterable) {
|
|
734
|
+
const choice = data.choices[0] as
|
|
735
|
+
| Partial<OpenAIClient.Chat.Completions.ChatCompletionChunk.Choice>
|
|
736
|
+
| undefined;
|
|
737
|
+
if (data.usage) {
|
|
738
|
+
usage = data.usage;
|
|
739
|
+
}
|
|
740
|
+
if (!choice) {
|
|
741
|
+
continue;
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
const { delta } = choice;
|
|
745
|
+
if (!delta) {
|
|
746
|
+
continue;
|
|
747
|
+
}
|
|
748
|
+
const chunk = this._convertOpenAIDeltaToBaseMessageChunk(
|
|
749
|
+
delta,
|
|
750
|
+
data,
|
|
751
|
+
defaultRole
|
|
752
|
+
);
|
|
753
|
+
if (chunk.usage_metadata != null) {
|
|
754
|
+
chunk.usage_metadata = {
|
|
755
|
+
input_tokens:
|
|
756
|
+
(chunk.usage_metadata as Partial<UsageMetadata>).input_tokens ?? 0,
|
|
757
|
+
output_tokens:
|
|
758
|
+
(chunk.usage_metadata as Partial<UsageMetadata>).output_tokens ?? 0,
|
|
759
|
+
total_tokens:
|
|
760
|
+
(chunk.usage_metadata as Partial<UsageMetadata>).total_tokens ?? 0,
|
|
761
|
+
};
|
|
762
|
+
}
|
|
763
|
+
if ('reasoning_content' in delta) {
|
|
764
|
+
chunk.additional_kwargs.reasoning_content = delta.reasoning_content;
|
|
765
|
+
}
|
|
766
|
+
defaultRole = delta.role ?? defaultRole;
|
|
767
|
+
const newTokenIndices = {
|
|
768
|
+
prompt: (options as OpenAIChatCallOptions).promptIndex ?? 0,
|
|
769
|
+
completion: choice.index ?? 0,
|
|
770
|
+
};
|
|
771
|
+
if (typeof chunk.content !== 'string') {
|
|
772
|
+
// eslint-disable-next-line no-console
|
|
773
|
+
console.log(
|
|
774
|
+
'[WARNING]: Received non-string content from OpenAI. This is currently not supported.'
|
|
775
|
+
);
|
|
776
|
+
continue;
|
|
777
|
+
}
|
|
778
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
779
|
+
const generationInfo: Record<string, any> = { ...newTokenIndices };
|
|
780
|
+
if (choice.finish_reason != null) {
|
|
781
|
+
generationInfo.finish_reason = choice.finish_reason;
|
|
782
|
+
// Only include system fingerprint in the last chunk for now
|
|
783
|
+
// to avoid concatenation issues
|
|
784
|
+
generationInfo.system_fingerprint = data.system_fingerprint;
|
|
785
|
+
generationInfo.model_name = data.model;
|
|
786
|
+
generationInfo.service_tier = data.service_tier;
|
|
787
|
+
}
|
|
788
|
+
if (this.logprobs == true) {
|
|
789
|
+
generationInfo.logprobs = choice.logprobs;
|
|
790
|
+
}
|
|
791
|
+
const generationChunk = new ChatGenerationChunk({
|
|
792
|
+
message: chunk,
|
|
793
|
+
text: chunk.content,
|
|
794
|
+
generationInfo,
|
|
795
|
+
});
|
|
796
|
+
yield generationChunk;
|
|
797
|
+
if (this._lc_stream_delay != null) {
|
|
798
|
+
await sleep(this._lc_stream_delay);
|
|
799
|
+
}
|
|
800
|
+
await runManager?.handleLLMNewToken(
|
|
801
|
+
generationChunk.text || '',
|
|
802
|
+
newTokenIndices,
|
|
803
|
+
undefined,
|
|
804
|
+
undefined,
|
|
805
|
+
undefined,
|
|
806
|
+
{ chunk: generationChunk }
|
|
807
|
+
);
|
|
808
|
+
}
|
|
809
|
+
if (usage) {
|
|
810
|
+
// Type assertion for xAI-specific usage structure
|
|
811
|
+
const xaiUsage = usage as XAIUsageMetadata;
|
|
812
|
+
const inputTokenDetails = {
|
|
813
|
+
// Standard OpenAI fields
|
|
814
|
+
...(usage.prompt_tokens_details?.audio_tokens != null && {
|
|
815
|
+
audio: usage.prompt_tokens_details.audio_tokens,
|
|
816
|
+
}),
|
|
817
|
+
...(usage.prompt_tokens_details?.cached_tokens != null && {
|
|
818
|
+
cache_read: usage.prompt_tokens_details.cached_tokens,
|
|
819
|
+
}),
|
|
820
|
+
// Add xAI-specific prompt token details if they exist
|
|
821
|
+
...(xaiUsage.prompt_tokens_details?.text_tokens != null && {
|
|
822
|
+
text: xaiUsage.prompt_tokens_details.text_tokens,
|
|
823
|
+
}),
|
|
824
|
+
...(xaiUsage.prompt_tokens_details?.image_tokens != null && {
|
|
825
|
+
image: xaiUsage.prompt_tokens_details.image_tokens,
|
|
826
|
+
}),
|
|
827
|
+
};
|
|
828
|
+
const outputTokenDetails = {
|
|
829
|
+
// Standard OpenAI fields
|
|
830
|
+
...(usage.completion_tokens_details?.audio_tokens != null && {
|
|
831
|
+
audio: usage.completion_tokens_details.audio_tokens,
|
|
832
|
+
}),
|
|
833
|
+
...(usage.completion_tokens_details?.reasoning_tokens != null && {
|
|
834
|
+
reasoning: usage.completion_tokens_details.reasoning_tokens,
|
|
835
|
+
}),
|
|
836
|
+
// Add xAI-specific completion token details if they exist
|
|
837
|
+
...(xaiUsage.completion_tokens_details?.accepted_prediction_tokens !=
|
|
838
|
+
null && {
|
|
839
|
+
accepted_prediction:
|
|
840
|
+
xaiUsage.completion_tokens_details.accepted_prediction_tokens,
|
|
841
|
+
}),
|
|
842
|
+
...(xaiUsage.completion_tokens_details?.rejected_prediction_tokens !=
|
|
843
|
+
null && {
|
|
844
|
+
rejected_prediction:
|
|
845
|
+
xaiUsage.completion_tokens_details.rejected_prediction_tokens,
|
|
846
|
+
}),
|
|
847
|
+
};
|
|
848
|
+
const generationChunk = new ChatGenerationChunk({
|
|
849
|
+
message: new AIMessageChunk({
|
|
850
|
+
content: '',
|
|
851
|
+
response_metadata: {
|
|
852
|
+
usage: { ...usage },
|
|
853
|
+
// Include xAI-specific metadata if it exists
|
|
854
|
+
...(xaiUsage.num_sources_used != null && {
|
|
855
|
+
num_sources_used: xaiUsage.num_sources_used,
|
|
856
|
+
}),
|
|
857
|
+
},
|
|
858
|
+
usage_metadata: {
|
|
859
|
+
input_tokens: usage.prompt_tokens,
|
|
860
|
+
output_tokens: usage.completion_tokens,
|
|
861
|
+
total_tokens: usage.total_tokens,
|
|
862
|
+
...(Object.keys(inputTokenDetails).length > 0 && {
|
|
863
|
+
input_token_details: inputTokenDetails,
|
|
864
|
+
}),
|
|
865
|
+
...(Object.keys(outputTokenDetails).length > 0 && {
|
|
866
|
+
output_token_details: outputTokenDetails,
|
|
867
|
+
}),
|
|
868
|
+
},
|
|
869
|
+
}),
|
|
870
|
+
text: '',
|
|
871
|
+
});
|
|
872
|
+
yield generationChunk;
|
|
873
|
+
if (this._lc_stream_delay != null) {
|
|
874
|
+
await sleep(this._lc_stream_delay);
|
|
875
|
+
}
|
|
876
|
+
}
|
|
877
|
+
if (options.signal?.aborted === true) {
|
|
878
|
+
throw new Error('AbortError');
|
|
879
|
+
}
|
|
880
|
+
}
|
|
254
881
|
}
|