@librechat/agents 3.3.13 → 3.4.0
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/graphs/Graph.cjs +10 -0
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/llm/anthropic/index.cjs +35 -206
- package/dist/cjs/llm/anthropic/index.cjs.map +1 -1
- package/dist/cjs/llm/bedrock/index.cjs +121 -241
- package/dist/cjs/llm/bedrock/index.cjs.map +1 -1
- package/dist/cjs/llm/google/index.cjs +19 -12
- package/dist/cjs/llm/google/index.cjs.map +1 -1
- package/dist/cjs/llm/mistral/index.cjs +26 -0
- package/dist/cjs/llm/mistral/index.cjs.map +1 -0
- package/dist/cjs/llm/openai/index.cjs +82 -80
- package/dist/cjs/llm/openai/index.cjs.map +1 -1
- package/dist/cjs/llm/openrouter/index.cjs.map +1 -1
- package/dist/cjs/llm/providers.cjs +19 -19
- package/dist/cjs/llm/providers.cjs.map +1 -1
- package/dist/cjs/llm/stream/chunkAdapters.cjs +198 -0
- package/dist/cjs/llm/stream/chunkAdapters.cjs.map +1 -0
- package/dist/cjs/llm/stream/smoother.cjs +369 -0
- package/dist/cjs/llm/stream/smoother.cjs.map +1 -0
- package/dist/cjs/llm/vertexai/index.cjs +13 -1
- package/dist/cjs/llm/vertexai/index.cjs.map +1 -1
- package/dist/cjs/main.cjs +18 -10
- package/dist/cjs/tools/subagent/SubagentExecutor.cjs +34 -2
- package/dist/cjs/tools/subagent/SubagentExecutor.cjs.map +1 -1
- package/dist/cjs/utils/tokens.cjs +76 -29
- package/dist/cjs/utils/tokens.cjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +10 -0
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/llm/anthropic/index.mjs +34 -205
- package/dist/esm/llm/anthropic/index.mjs.map +1 -1
- package/dist/esm/llm/bedrock/index.mjs +120 -240
- package/dist/esm/llm/bedrock/index.mjs.map +1 -1
- package/dist/esm/llm/google/index.mjs +19 -12
- package/dist/esm/llm/google/index.mjs.map +1 -1
- package/dist/esm/llm/mistral/index.mjs +26 -0
- package/dist/esm/llm/mistral/index.mjs.map +1 -0
- package/dist/esm/llm/openai/index.mjs +82 -80
- package/dist/esm/llm/openai/index.mjs.map +1 -1
- package/dist/esm/llm/openrouter/index.mjs.map +1 -1
- package/dist/esm/llm/providers.mjs +3 -3
- package/dist/esm/llm/providers.mjs.map +1 -1
- package/dist/esm/llm/stream/chunkAdapters.mjs +195 -0
- package/dist/esm/llm/stream/chunkAdapters.mjs.map +1 -0
- package/dist/esm/llm/stream/smoother.mjs +365 -0
- package/dist/esm/llm/stream/smoother.mjs.map +1 -0
- package/dist/esm/llm/vertexai/index.mjs +13 -1
- package/dist/esm/llm/vertexai/index.mjs.map +1 -1
- package/dist/esm/main.mjs +4 -2
- package/dist/esm/tools/subagent/SubagentExecutor.mjs +34 -2
- package/dist/esm/tools/subagent/SubagentExecutor.mjs.map +1 -1
- package/dist/esm/utils/tokens.mjs +76 -30
- package/dist/esm/utils/tokens.mjs.map +1 -1
- package/dist/types/graphs/Graph.d.ts +3 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/llm/google/index.d.ts +2 -0
- package/dist/types/llm/mistral/index.d.ts +11 -0
- package/dist/types/llm/openai/index.d.ts +20 -4
- package/dist/types/llm/openrouter/index.d.ts +4 -1
- package/dist/types/llm/stream/chunkAdapters.d.ts +48 -0
- package/dist/types/llm/stream/smoother.d.ts +95 -0
- package/dist/types/llm/vertexai/index.d.ts +2 -0
- package/dist/types/tools/subagent/SubagentExecutor.d.ts +3 -0
- package/dist/types/types/llm.d.ts +21 -14
- package/dist/types/utils/tokens.d.ts +10 -0
- package/package.json +2 -2
- package/src/graphs/Graph.ts +11 -0
- package/src/index.ts +8 -0
- package/src/llm/anthropic/index.ts +85 -354
- package/src/llm/bedrock/index.ts +174 -390
- package/src/llm/bedrock/llm.spec.ts +2 -0
- package/src/llm/bedrock/streamSealDispatch.test.ts +76 -0
- package/src/llm/custom-chat-models.smoke.test.ts +16 -1
- package/src/llm/google/index.ts +17 -18
- package/src/llm/google/streamSmoothing.test.ts +121 -0
- package/src/llm/mistral/index.ts +33 -0
- package/src/llm/mistral/streamSmoothing.test.ts +97 -0
- package/src/llm/openai/deepseek.test.ts +56 -0
- package/src/llm/openai/index.ts +119 -126
- package/src/llm/openrouter/index.ts +4 -1
- package/src/llm/providers.ts +3 -3
- package/src/llm/stream/chunkAdapters.test.ts +202 -0
- package/src/llm/stream/chunkAdapters.ts +317 -0
- package/src/llm/stream/reassembly.test.ts +241 -0
- package/src/llm/stream/smoother.bench.test.ts +155 -0
- package/src/llm/stream/smoother.test.ts +519 -0
- package/src/llm/stream/smoother.ts +574 -0
- package/src/llm/vertexai/index.ts +17 -1
- package/src/llm/vertexai/streamSmoothing.test.ts +109 -0
- package/src/specs/subagent.test.ts +44 -0
- package/src/specs/tokens.test.ts +159 -14
- package/src/tools/__tests__/SubagentExecutor.test.ts +48 -1
- package/src/tools/subagent/SubagentExecutor.ts +69 -5
- package/src/types/llm.ts +53 -36
- package/src/utils/tokens.ts +115 -30
package/src/types/llm.ts
CHANGED
|
@@ -45,7 +45,8 @@ export type AzureClientOptions = Partial<OpenAIChatInput> &
|
|
|
45
45
|
deploymentName?: string;
|
|
46
46
|
} & BaseChatModelParams & {
|
|
47
47
|
configuration?: OAIClientOptions;
|
|
48
|
-
} & ManagedRequestOptions
|
|
48
|
+
} & ManagedRequestOptions &
|
|
49
|
+
StreamSmoothingOptions;
|
|
49
50
|
/**
|
|
50
51
|
* Controls whether Claude's reasoning content is returned in adaptive
|
|
51
52
|
* thinking responses. Added for Claude Opus 4.7, which omits thinking by
|
|
@@ -79,47 +80,63 @@ export type ManagedRequestOptions = {
|
|
|
79
80
|
promptCacheExplicit?: boolean;
|
|
80
81
|
safety_identifier?: string;
|
|
81
82
|
};
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Prompt-cache breakpoint TTL. Defaults to `'1h'` (extended cache) when
|
|
88
|
-
* `promptCache` is enabled; set `'5m'` to opt back into the legacy
|
|
89
|
-
* 5-minute behavior.
|
|
90
|
-
*/
|
|
91
|
-
promptCacheTtl?: PromptCacheTtl;
|
|
92
|
-
};
|
|
93
|
-
export type MistralAIClientOptions = ChatMistralAIInput;
|
|
94
|
-
export type VertexAIClientOptions = ChatVertexAIInput & {
|
|
95
|
-
includeThoughts?: boolean;
|
|
96
|
-
thinkingConfig?: GoogleThinkingConfig;
|
|
97
|
-
};
|
|
98
|
-
export type BedrockAnthropicInput = ChatBedrockConverseInput & {
|
|
99
|
-
additionalModelRequestFields?: ChatBedrockConverseInput['additionalModelRequestFields'] &
|
|
100
|
-
AnthropicReasoning;
|
|
101
|
-
promptCache?: boolean;
|
|
102
|
-
/**
|
|
103
|
-
* Prompt-cache checkpoint TTL. Defaults to `'1h'` (extended cache) when
|
|
104
|
-
* `promptCache` is enabled; set `'5m'` to opt into the legacy 5-minute
|
|
105
|
-
* behavior. Bedrock models that don't support the 1-hour TTL downgrade to 5m
|
|
106
|
-
* server-side, so the default is safe to leave on.
|
|
107
|
-
*/
|
|
108
|
-
promptCacheTtl?: PromptCacheTtl;
|
|
83
|
+
/**
|
|
84
|
+
* Adaptive stream-smoothing configuration shared by every provider client.
|
|
85
|
+
*/
|
|
86
|
+
export type StreamSmoothingOptions = {
|
|
109
87
|
/**
|
|
110
88
|
* Minimum delay in milliseconds between visible streamed content deltas.
|
|
89
|
+
* Defaults to 25; piece sizes adapt to the backlog so render lag stays
|
|
90
|
+
* bounded regardless of provider chunk size. Set 0 to disable smoothing.
|
|
111
91
|
*/
|
|
112
92
|
_lc_stream_delay?: number;
|
|
113
93
|
};
|
|
94
|
+
|
|
95
|
+
export type OpenAIClientOptions = ChatOpenAIFields &
|
|
96
|
+
ManagedRequestOptions &
|
|
97
|
+
StreamSmoothingOptions;
|
|
98
|
+
export type AnthropicClientOptions = Omit<AnthropicInput, 'thinking'> &
|
|
99
|
+
StreamSmoothingOptions & {
|
|
100
|
+
thinking?: ThinkingConfig;
|
|
101
|
+
promptCache?: boolean;
|
|
102
|
+
/**
|
|
103
|
+
* Prompt-cache breakpoint TTL. Defaults to `'1h'` (extended cache) when
|
|
104
|
+
* `promptCache` is enabled; set `'5m'` to opt back into the legacy
|
|
105
|
+
* 5-minute behavior.
|
|
106
|
+
*/
|
|
107
|
+
promptCacheTtl?: PromptCacheTtl;
|
|
108
|
+
};
|
|
109
|
+
export type MistralAIClientOptions = ChatMistralAIInput &
|
|
110
|
+
StreamSmoothingOptions;
|
|
111
|
+
export type VertexAIClientOptions = ChatVertexAIInput &
|
|
112
|
+
StreamSmoothingOptions & {
|
|
113
|
+
includeThoughts?: boolean;
|
|
114
|
+
thinkingConfig?: GoogleThinkingConfig;
|
|
115
|
+
};
|
|
116
|
+
export type BedrockAnthropicInput = ChatBedrockConverseInput &
|
|
117
|
+
StreamSmoothingOptions & {
|
|
118
|
+
additionalModelRequestFields?: ChatBedrockConverseInput['additionalModelRequestFields'] &
|
|
119
|
+
AnthropicReasoning;
|
|
120
|
+
promptCache?: boolean;
|
|
121
|
+
/**
|
|
122
|
+
* Prompt-cache checkpoint TTL. Defaults to `'1h'` (extended cache) when
|
|
123
|
+
* `promptCache` is enabled; set `'5m'` to opt into the legacy 5-minute
|
|
124
|
+
* behavior. Bedrock models that don't support the 1-hour TTL downgrade to 5m
|
|
125
|
+
* server-side, so the default is safe to leave on.
|
|
126
|
+
*/
|
|
127
|
+
promptCacheTtl?: PromptCacheTtl;
|
|
128
|
+
};
|
|
114
129
|
export type BedrockConverseClientOptions = BedrockAnthropicInput;
|
|
115
130
|
export type BedrockAnthropicClientOptions = BedrockAnthropicInput;
|
|
116
|
-
export type GoogleClientOptions = GoogleGenerativeAIChatInput &
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
export type
|
|
131
|
+
export type GoogleClientOptions = GoogleGenerativeAIChatInput &
|
|
132
|
+
StreamSmoothingOptions & {
|
|
133
|
+
customHeaders?: RequestOptions['customHeaders'];
|
|
134
|
+
thinkingConfig?: GoogleThinkingConfig;
|
|
135
|
+
includeServerSideToolInvocations?: boolean;
|
|
136
|
+
};
|
|
137
|
+
export type DeepSeekClientOptions = Partial<ChatDeepSeekInput> &
|
|
138
|
+
StreamSmoothingOptions;
|
|
139
|
+
export type XAIClientOptions = ChatXAIInput & StreamSmoothingOptions;
|
|
123
140
|
|
|
124
141
|
export type ClientOptions =
|
|
125
142
|
| OpenAIClientOptions
|
|
@@ -159,7 +176,7 @@ export type ProviderOptionsMap = {
|
|
|
159
176
|
[Providers.ANTHROPIC]: AnthropicClientOptions;
|
|
160
177
|
[Providers.MISTRALAI]: MistralAIClientOptions;
|
|
161
178
|
[Providers.MISTRAL]: MistralAIClientOptions;
|
|
162
|
-
[Providers.OPENROUTER]: ChatOpenRouterCallOptions;
|
|
179
|
+
[Providers.OPENROUTER]: ChatOpenRouterCallOptions & StreamSmoothingOptions;
|
|
163
180
|
[Providers.BEDROCK]: BedrockAnthropicClientOptions;
|
|
164
181
|
[Providers.XAI]: XAIClientOptions;
|
|
165
182
|
[Providers.MOONSHOT]: OpenAIClientOptions;
|
package/src/utils/tokens.ts
CHANGED
|
@@ -10,6 +10,52 @@ import { ContentTypes } from '@/common/enum';
|
|
|
10
10
|
|
|
11
11
|
export type EncodingName = 'o200k_base' | 'claude';
|
|
12
12
|
|
|
13
|
+
export type UnsafeTokenMeasurementReason =
|
|
14
|
+
| 'message_proxy'
|
|
15
|
+
| 'content_proxy'
|
|
16
|
+
| 'metadata_proxy'
|
|
17
|
+
| 'metadata_accessor'
|
|
18
|
+
| 'invalid_count';
|
|
19
|
+
|
|
20
|
+
export class UnsafeTokenMeasurementError extends Error {
|
|
21
|
+
readonly type = 'unsafe_token_measurement';
|
|
22
|
+
readonly reason: UnsafeTokenMeasurementReason;
|
|
23
|
+
readonly path: string;
|
|
24
|
+
|
|
25
|
+
constructor({
|
|
26
|
+
reason,
|
|
27
|
+
path,
|
|
28
|
+
}: {
|
|
29
|
+
reason: UnsafeTokenMeasurementReason;
|
|
30
|
+
path: string;
|
|
31
|
+
}) {
|
|
32
|
+
super(
|
|
33
|
+
JSON.stringify({
|
|
34
|
+
type: 'unsafe_token_measurement',
|
|
35
|
+
reason,
|
|
36
|
+
path,
|
|
37
|
+
})
|
|
38
|
+
);
|
|
39
|
+
this.name = 'UnsafeTokenMeasurementError';
|
|
40
|
+
this.reason = reason;
|
|
41
|
+
this.path = path;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function ensureSafeTokenMeasurement(value: number, path: string): number {
|
|
46
|
+
if (
|
|
47
|
+
!Number.isSafeInteger(value) ||
|
|
48
|
+
value < 0 ||
|
|
49
|
+
value >= Number.MAX_SAFE_INTEGER
|
|
50
|
+
) {
|
|
51
|
+
throw new UnsafeTokenMeasurementError({
|
|
52
|
+
reason: 'invalid_count',
|
|
53
|
+
path,
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
return value;
|
|
57
|
+
}
|
|
58
|
+
|
|
13
59
|
/** Anthropic minimum image token cost. */
|
|
14
60
|
const ANTHROPIC_IMAGE_MIN_TOKENS = 1024;
|
|
15
61
|
/** Anthropic divisor: tokens = width × height / 750. */
|
|
@@ -844,7 +890,10 @@ function getBoundedTextTokenCount(
|
|
|
844
890
|
value.length > MAX_STRUCTURED_TOKENIZATION_CHARS
|
|
845
891
|
? value.slice(0, MAX_STRUCTURED_TOKENIZATION_CHARS)
|
|
846
892
|
: value;
|
|
847
|
-
const previewTokens =
|
|
893
|
+
const previewTokens = ensureSafeTokenMeasurement(
|
|
894
|
+
getTokenCount(preview),
|
|
895
|
+
'tokenizer'
|
|
896
|
+
);
|
|
848
897
|
const omittedChars = value.length - preview.length;
|
|
849
898
|
if (omittedChars <= 0) {
|
|
850
899
|
return previewTokens;
|
|
@@ -859,19 +908,25 @@ function getBoundedStructuredTokenCount(
|
|
|
859
908
|
value: unknown,
|
|
860
909
|
getTokenCount: (text: string) => number
|
|
861
910
|
): number {
|
|
862
|
-
if (hasUnsafeStructuredSerialization(value)) {
|
|
863
|
-
return Number.MAX_SAFE_INTEGER;
|
|
864
|
-
}
|
|
865
911
|
const serialized = serializeStructuredValueBounded(
|
|
866
912
|
value,
|
|
867
913
|
MAX_STRUCTURED_TOKENIZATION_CHARS
|
|
868
914
|
);
|
|
869
|
-
const previewTokens =
|
|
915
|
+
const previewTokens = ensureSafeTokenMeasurement(
|
|
916
|
+
getTokenCount(serialized.content),
|
|
917
|
+
'tokenizer'
|
|
918
|
+
);
|
|
870
919
|
if (!serialized.truncated) {
|
|
871
920
|
return previewTokens;
|
|
872
921
|
}
|
|
873
|
-
|
|
874
|
-
|
|
922
|
+
// The bounded serializer uses MAX_SAFE_INTEGER as its unknown-size sentinel.
|
|
923
|
+
// Do not extrapolate from it: use its bounded preview and let the provider
|
|
924
|
+
// input projection preserve the same bounded behavior before invocation.
|
|
925
|
+
if (
|
|
926
|
+
!Number.isSafeInteger(serialized.originalChars) ||
|
|
927
|
+
serialized.originalChars >= Number.MAX_SAFE_INTEGER
|
|
928
|
+
) {
|
|
929
|
+
return previewTokens;
|
|
875
930
|
}
|
|
876
931
|
|
|
877
932
|
const omittedChars = Math.max(
|
|
@@ -893,7 +948,10 @@ export function getTokenCountForMessage(
|
|
|
893
948
|
const countText = (text: string): number =>
|
|
894
949
|
getBoundedTextTokenCount(text, getTokenCount);
|
|
895
950
|
if (isProxy(message)) {
|
|
896
|
-
|
|
951
|
+
throw new UnsafeTokenMeasurementError({
|
|
952
|
+
reason: 'message_proxy',
|
|
953
|
+
path: 'message',
|
|
954
|
+
});
|
|
897
955
|
}
|
|
898
956
|
|
|
899
957
|
type ContentBlock = Record<string, unknown> & {
|
|
@@ -907,19 +965,22 @@ export function getTokenCountForMessage(
|
|
|
907
965
|
};
|
|
908
966
|
const representedToolCallIds = new Set<string>();
|
|
909
967
|
|
|
910
|
-
const processValue = (value: unknown): void => {
|
|
968
|
+
const processValue = (value: unknown, path: string): void => {
|
|
911
969
|
if (value != null && typeof value === 'object' && isProxy(value)) {
|
|
912
|
-
|
|
913
|
-
|
|
970
|
+
throw new UnsafeTokenMeasurementError({
|
|
971
|
+
reason: 'content_proxy',
|
|
972
|
+
path,
|
|
973
|
+
});
|
|
914
974
|
}
|
|
915
975
|
if (Array.isArray(value)) {
|
|
916
|
-
for (
|
|
976
|
+
for (let index = 0; index < value.length; index++) {
|
|
977
|
+
const raw = value[index];
|
|
917
978
|
if (
|
|
918
979
|
typeof raw === 'string' ||
|
|
919
980
|
typeof raw === 'number' ||
|
|
920
981
|
typeof raw === 'boolean'
|
|
921
982
|
) {
|
|
922
|
-
processValue(raw);
|
|
983
|
+
processValue(raw, `${path}[${index}]`);
|
|
923
984
|
continue;
|
|
924
985
|
}
|
|
925
986
|
const item = raw as ContentBlock | null | undefined;
|
|
@@ -927,8 +988,10 @@ export function getTokenCountForMessage(
|
|
|
927
988
|
continue;
|
|
928
989
|
}
|
|
929
990
|
if (isProxy(item)) {
|
|
930
|
-
|
|
931
|
-
|
|
991
|
+
throw new UnsafeTokenMeasurementError({
|
|
992
|
+
reason: 'content_proxy',
|
|
993
|
+
path: `${path}[${index}]`,
|
|
994
|
+
});
|
|
932
995
|
}
|
|
933
996
|
if (typeof item.type !== 'string') {
|
|
934
997
|
numTokens += getBoundedStructuredTokenCount(item, countText);
|
|
@@ -1010,7 +1073,7 @@ export function getTokenCountForMessage(
|
|
|
1010
1073
|
}
|
|
1011
1074
|
const output = item.tool_call.output;
|
|
1012
1075
|
if (output != null) {
|
|
1013
|
-
processValue(output);
|
|
1076
|
+
processValue(output, `${path}[${index}].tool_call.output`);
|
|
1014
1077
|
}
|
|
1015
1078
|
continue;
|
|
1016
1079
|
}
|
|
@@ -1021,7 +1084,7 @@ export function getTokenCountForMessage(
|
|
|
1021
1084
|
continue;
|
|
1022
1085
|
}
|
|
1023
1086
|
|
|
1024
|
-
processValue(nestedValue);
|
|
1087
|
+
processValue(nestedValue, `${path}[${index}].${item.type}`);
|
|
1025
1088
|
}
|
|
1026
1089
|
} else if (typeof value === 'string') {
|
|
1027
1090
|
numTokens += countText(value);
|
|
@@ -1040,7 +1103,10 @@ export function getTokenCountForMessage(
|
|
|
1040
1103
|
? rawAdditionalKwargs
|
|
1041
1104
|
: undefined;
|
|
1042
1105
|
if (additionalKwargs != null && isProxy(additionalKwargs)) {
|
|
1043
|
-
|
|
1106
|
+
throw new UnsafeTokenMeasurementError({
|
|
1107
|
+
reason: 'metadata_proxy',
|
|
1108
|
+
path: 'additional_kwargs',
|
|
1109
|
+
});
|
|
1044
1110
|
}
|
|
1045
1111
|
let additionalType: PropertyDescriptor | undefined;
|
|
1046
1112
|
try {
|
|
@@ -1049,10 +1115,16 @@ export function getTokenCountForMessage(
|
|
|
1049
1115
|
? Object.getOwnPropertyDescriptor(additionalKwargs, 'type')
|
|
1050
1116
|
: undefined;
|
|
1051
1117
|
} catch {
|
|
1052
|
-
|
|
1118
|
+
throw new UnsafeTokenMeasurementError({
|
|
1119
|
+
reason: 'metadata_accessor',
|
|
1120
|
+
path: 'additional_kwargs.type',
|
|
1121
|
+
});
|
|
1053
1122
|
}
|
|
1054
1123
|
if (additionalType != null && !('value' in additionalType)) {
|
|
1055
|
-
|
|
1124
|
+
throw new UnsafeTokenMeasurementError({
|
|
1125
|
+
reason: 'metadata_accessor',
|
|
1126
|
+
path: 'additional_kwargs.type',
|
|
1127
|
+
});
|
|
1056
1128
|
}
|
|
1057
1129
|
|
|
1058
1130
|
let numTokens = tokensPerMessage;
|
|
@@ -1072,20 +1144,24 @@ export function getTokenCountForMessage(
|
|
|
1072
1144
|
) * IMAGE_TOKEN_SAFETY_MARGIN
|
|
1073
1145
|
);
|
|
1074
1146
|
} else {
|
|
1075
|
-
processValue(message.content);
|
|
1076
|
-
}
|
|
1077
|
-
if (numTokens >= Number.MAX_SAFE_INTEGER) {
|
|
1078
|
-
return Number.MAX_SAFE_INTEGER;
|
|
1147
|
+
processValue(message.content, 'content');
|
|
1079
1148
|
}
|
|
1149
|
+
ensureSafeTokenMeasurement(numTokens, 'content');
|
|
1080
1150
|
const messageRole = (message as BaseMessage & { role?: unknown }).role;
|
|
1081
1151
|
if (messageType === 'ai' || messageRole === 'assistant') {
|
|
1082
1152
|
const toolCalls = (message as AIMessage).tool_calls ?? [];
|
|
1083
1153
|
if (isProxy(toolCalls)) {
|
|
1084
|
-
|
|
1154
|
+
throw new UnsafeTokenMeasurementError({
|
|
1155
|
+
reason: 'metadata_proxy',
|
|
1156
|
+
path: 'tool_calls',
|
|
1157
|
+
});
|
|
1085
1158
|
}
|
|
1086
1159
|
for (const toolCall of toolCalls) {
|
|
1087
1160
|
if (isProxy(toolCall)) {
|
|
1088
|
-
|
|
1161
|
+
throw new UnsafeTokenMeasurementError({
|
|
1162
|
+
reason: 'metadata_proxy',
|
|
1163
|
+
path: 'tool_calls',
|
|
1164
|
+
});
|
|
1089
1165
|
}
|
|
1090
1166
|
if (
|
|
1091
1167
|
typeof toolCall.id === 'string' &&
|
|
@@ -1111,11 +1187,17 @@ export function getTokenCountForMessage(
|
|
|
1111
1187
|
? Object.getOwnPropertyDescriptor(additionalKwargs, 'function_call')
|
|
1112
1188
|
: undefined;
|
|
1113
1189
|
} catch {
|
|
1114
|
-
|
|
1190
|
+
throw new UnsafeTokenMeasurementError({
|
|
1191
|
+
reason: 'metadata_accessor',
|
|
1192
|
+
path: 'additional_kwargs.function_call',
|
|
1193
|
+
});
|
|
1115
1194
|
}
|
|
1116
1195
|
if (legacyFunctionCall != null) {
|
|
1117
1196
|
if (!('value' in legacyFunctionCall)) {
|
|
1118
|
-
|
|
1197
|
+
throw new UnsafeTokenMeasurementError({
|
|
1198
|
+
reason: 'metadata_accessor',
|
|
1199
|
+
path: 'additional_kwargs.function_call',
|
|
1200
|
+
});
|
|
1119
1201
|
}
|
|
1120
1202
|
if (legacyFunctionCall.value != null) {
|
|
1121
1203
|
numTokens += getBoundedStructuredTokenCount(
|
|
@@ -1125,7 +1207,7 @@ export function getTokenCountForMessage(
|
|
|
1125
1207
|
}
|
|
1126
1208
|
}
|
|
1127
1209
|
}
|
|
1128
|
-
return
|
|
1210
|
+
return ensureSafeTokenMeasurement(numTokens, 'message');
|
|
1129
1211
|
}
|
|
1130
1212
|
|
|
1131
1213
|
/**
|
|
@@ -1180,7 +1262,10 @@ export const createTokenCounter = async (
|
|
|
1180
1262
|
const isClaude = encoding === 'claude';
|
|
1181
1263
|
return (message: BaseMessage): number => {
|
|
1182
1264
|
const count = getTokenCountForMessage(message, countTokens, encoding);
|
|
1183
|
-
|
|
1265
|
+
const correctedCount = isClaude
|
|
1266
|
+
? Math.ceil(count * CLAUDE_TOKEN_CORRECTION)
|
|
1267
|
+
: count;
|
|
1268
|
+
return ensureSafeTokenMeasurement(correctedCount, 'message');
|
|
1184
1269
|
};
|
|
1185
1270
|
};
|
|
1186
1271
|
|