@jaypie/llm 1.3.3 → 1.3.5
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/index.cjs +906 -145
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/cjs/index.d.cts +13 -1
- package/dist/cjs/{index.d.ts → src/index.d.ts} +1 -0
- package/dist/cjs/{operate → src/operate}/adapters/AnthropicAdapter.d.ts +1 -1
- package/dist/{esm → cjs/src}/operate/adapters/OpenRouterAdapter.d.ts +8 -1
- package/dist/cjs/src/providers/anthropic/client.d.ts +54 -0
- package/dist/cjs/src/providers/anthropic/types.d.ts +129 -0
- package/dist/{esm → cjs/src}/providers/anthropic/utils.d.ts +5 -5
- package/dist/cjs/src/providers/google/client.d.ts +44 -0
- package/dist/cjs/{providers → src/providers}/google/utils.d.ts +2 -3
- package/dist/cjs/src/providers/openai/client.d.ts +74 -0
- package/dist/cjs/src/providers/openai/responseFormat.d.ts +17 -0
- package/dist/{esm → cjs/src}/providers/openai/utils.d.ts +4 -4
- package/dist/cjs/src/providers/openrouter/client.d.ts +40 -0
- package/dist/{esm → cjs/src}/providers/openrouter/utils.d.ts +2 -3
- package/dist/cjs/{providers → src/providers}/xai/utils.d.ts +2 -2
- package/dist/cjs/{util → src/util}/index.d.ts +2 -0
- package/dist/cjs/src/util/jsonSchema.d.ts +17 -0
- package/dist/cjs/src/util/sse.d.ts +12 -0
- package/dist/esm/index.d.ts +13 -1
- package/dist/esm/index.js +917 -158
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/src/index.d.ts +17 -0
- package/dist/esm/{operate → src/operate}/adapters/AnthropicAdapter.d.ts +1 -1
- package/dist/{cjs → esm/src}/operate/adapters/OpenRouterAdapter.d.ts +8 -1
- package/dist/esm/src/providers/anthropic/client.d.ts +54 -0
- package/dist/esm/src/providers/anthropic/types.d.ts +129 -0
- package/dist/{cjs → esm/src}/providers/anthropic/utils.d.ts +5 -5
- package/dist/esm/src/providers/google/client.d.ts +44 -0
- package/dist/esm/{providers → src/providers}/google/utils.d.ts +2 -3
- package/dist/esm/src/providers/openai/client.d.ts +74 -0
- package/dist/esm/src/providers/openai/responseFormat.d.ts +17 -0
- package/dist/{cjs → esm/src}/providers/openai/utils.d.ts +4 -4
- package/dist/esm/src/providers/openrouter/client.d.ts +40 -0
- package/dist/{cjs → esm/src}/providers/openrouter/utils.d.ts +2 -3
- package/dist/esm/{providers → src/providers}/xai/utils.d.ts +2 -2
- package/dist/esm/{util → src/util}/index.d.ts +2 -0
- package/dist/esm/src/util/jsonSchema.d.ts +17 -0
- package/dist/esm/src/util/sse.d.ts +12 -0
- package/package.json +4 -19
- package/dist/cjs/providers/anthropic/types.d.ts +0 -2
- package/dist/esm/providers/anthropic/types.d.ts +0 -2
- /package/dist/cjs/{Llm.d.ts → src/Llm.d.ts} +0 -0
- /package/dist/cjs/{constants.d.ts → src/constants.d.ts} +0 -0
- /package/dist/cjs/{observability → src/observability}/llmobs.d.ts +0 -0
- /package/dist/cjs/{operate → src/operate}/OperateLoop.d.ts +0 -0
- /package/dist/cjs/{operate → src/operate}/StreamLoop.d.ts +0 -0
- /package/dist/cjs/{operate → src/operate}/adapters/BedrockAdapter.d.ts +0 -0
- /package/dist/cjs/{operate → src/operate}/adapters/GoogleAdapter.d.ts +0 -0
- /package/dist/cjs/{operate → src/operate}/adapters/OpenAiAdapter.d.ts +0 -0
- /package/dist/cjs/{operate → src/operate}/adapters/ProviderAdapter.interface.d.ts +0 -0
- /package/dist/cjs/{operate → src/operate}/adapters/XaiAdapter.d.ts +0 -0
- /package/dist/cjs/{operate → src/operate}/adapters/index.d.ts +0 -0
- /package/dist/cjs/{operate → src/operate}/hooks/HookRunner.d.ts +0 -0
- /package/dist/cjs/{operate → src/operate}/hooks/index.d.ts +0 -0
- /package/dist/cjs/{operate → src/operate}/index.d.ts +0 -0
- /package/dist/cjs/{operate → src/operate}/input/InputProcessor.d.ts +0 -0
- /package/dist/cjs/{operate → src/operate}/input/index.d.ts +0 -0
- /package/dist/cjs/{operate → src/operate}/response/ResponseBuilder.d.ts +0 -0
- /package/dist/cjs/{operate → src/operate}/response/index.d.ts +0 -0
- /package/dist/cjs/{operate → src/operate}/retry/RetryExecutor.d.ts +0 -0
- /package/dist/cjs/{operate → src/operate}/retry/RetryPolicy.d.ts +0 -0
- /package/dist/cjs/{operate → src/operate}/retry/createStaleRejectionGuard.d.ts +0 -0
- /package/dist/cjs/{operate → src/operate}/retry/index.d.ts +0 -0
- /package/dist/cjs/{operate → src/operate}/retry/isTransientNetworkError.d.ts +0 -0
- /package/dist/cjs/{operate → src/operate}/types.d.ts +0 -0
- /package/dist/cjs/{providers → src/providers}/anthropic/AnthropicProvider.class.d.ts +0 -0
- /package/dist/cjs/{providers → src/providers}/anthropic/index.d.ts +0 -0
- /package/dist/cjs/{providers → src/providers}/bedrock/BedrockProvider.class.d.ts +0 -0
- /package/dist/cjs/{providers → src/providers}/bedrock/index.d.ts +0 -0
- /package/dist/cjs/{providers → src/providers}/bedrock/utils.d.ts +0 -0
- /package/dist/cjs/{providers → src/providers}/google/GoogleProvider.class.d.ts +0 -0
- /package/dist/cjs/{providers → src/providers}/google/index.d.ts +0 -0
- /package/dist/cjs/{providers → src/providers}/google/types.d.ts +0 -0
- /package/dist/cjs/{providers → src/providers}/openai/OpenAiProvider.class.d.ts +0 -0
- /package/dist/cjs/{providers → src/providers}/openai/index.d.ts +0 -0
- /package/dist/cjs/{providers → src/providers}/openai/types.d.ts +0 -0
- /package/dist/cjs/{providers → src/providers}/openrouter/OpenRouterProvider.class.d.ts +0 -0
- /package/dist/cjs/{providers → src/providers}/openrouter/index.d.ts +0 -0
- /package/dist/cjs/{providers → src/providers}/xai/XaiProvider.class.d.ts +0 -0
- /package/dist/cjs/{providers → src/providers}/xai/index.d.ts +0 -0
- /package/dist/cjs/{tools → src/tools}/Toolkit.class.d.ts +0 -0
- /package/dist/cjs/{tools → src/tools}/index.d.ts +0 -0
- /package/dist/cjs/{tools → src/tools}/random.d.ts +0 -0
- /package/dist/cjs/{tools → src/tools}/roll.d.ts +0 -0
- /package/dist/cjs/{tools → src/tools}/time.d.ts +0 -0
- /package/dist/cjs/{tools → src/tools}/weather.d.ts +0 -0
- /package/dist/cjs/{types → src/types}/LlmOperateInput.guards.d.ts +0 -0
- /package/dist/cjs/{types → src/types}/LlmProvider.interface.d.ts +0 -0
- /package/dist/cjs/{types → src/types}/LlmStreamChunk.interface.d.ts +0 -0
- /package/dist/cjs/{types → src/types}/LlmTool.interface.d.ts +0 -0
- /package/dist/cjs/{upload → src/upload}/detectMimeType.d.ts +0 -0
- /package/dist/cjs/{upload → src/upload}/extractPdfPages.d.ts +0 -0
- /package/dist/cjs/{upload → src/upload}/index.d.ts +0 -0
- /package/dist/cjs/{upload → src/upload}/loadLocalFile.d.ts +0 -0
- /package/dist/cjs/{upload → src/upload}/loadS3File.d.ts +0 -0
- /package/dist/cjs/{upload → src/upload}/resolveOperateInput.d.ts +0 -0
- /package/dist/cjs/{util → src/util}/determineModelProvider.d.ts +0 -0
- /package/dist/cjs/{util → src/util}/extractReasoning.d.ts +0 -0
- /package/dist/cjs/{util → src/util}/fillFormatArrays.d.ts +0 -0
- /package/dist/cjs/{util → src/util}/formatOperateInput.d.ts +0 -0
- /package/dist/cjs/{util → src/util}/formatOperateMessage.d.ts +0 -0
- /package/dist/cjs/{util → src/util}/jsonSchemaToOpenApi3.d.ts +0 -0
- /package/dist/cjs/{util → src/util}/logger.d.ts +0 -0
- /package/dist/cjs/{util → src/util}/maxTurnsFromOptions.d.ts +0 -0
- /package/dist/cjs/{util → src/util}/naturalZodSchema.d.ts +0 -0
- /package/dist/cjs/{util → src/util}/random.d.ts +0 -0
- /package/dist/cjs/{util → src/util}/repairFormatKeys.d.ts +0 -0
- /package/dist/cjs/{util → src/util}/tryParseNumber.d.ts +0 -0
- /package/dist/esm/{Llm.d.ts → src/Llm.d.ts} +0 -0
- /package/dist/esm/{constants.d.ts → src/constants.d.ts} +0 -0
- /package/dist/esm/{observability → src/observability}/llmobs.d.ts +0 -0
- /package/dist/esm/{operate → src/operate}/OperateLoop.d.ts +0 -0
- /package/dist/esm/{operate → src/operate}/StreamLoop.d.ts +0 -0
- /package/dist/esm/{operate → src/operate}/adapters/BedrockAdapter.d.ts +0 -0
- /package/dist/esm/{operate → src/operate}/adapters/GoogleAdapter.d.ts +0 -0
- /package/dist/esm/{operate → src/operate}/adapters/OpenAiAdapter.d.ts +0 -0
- /package/dist/esm/{operate → src/operate}/adapters/ProviderAdapter.interface.d.ts +0 -0
- /package/dist/esm/{operate → src/operate}/adapters/XaiAdapter.d.ts +0 -0
- /package/dist/esm/{operate → src/operate}/adapters/index.d.ts +0 -0
- /package/dist/esm/{operate → src/operate}/hooks/HookRunner.d.ts +0 -0
- /package/dist/esm/{operate → src/operate}/hooks/index.d.ts +0 -0
- /package/dist/esm/{operate → src/operate}/index.d.ts +0 -0
- /package/dist/esm/{operate → src/operate}/input/InputProcessor.d.ts +0 -0
- /package/dist/esm/{operate → src/operate}/input/index.d.ts +0 -0
- /package/dist/esm/{operate → src/operate}/response/ResponseBuilder.d.ts +0 -0
- /package/dist/esm/{operate → src/operate}/response/index.d.ts +0 -0
- /package/dist/esm/{operate → src/operate}/retry/RetryExecutor.d.ts +0 -0
- /package/dist/esm/{operate → src/operate}/retry/RetryPolicy.d.ts +0 -0
- /package/dist/esm/{operate → src/operate}/retry/createStaleRejectionGuard.d.ts +0 -0
- /package/dist/esm/{operate → src/operate}/retry/index.d.ts +0 -0
- /package/dist/esm/{operate → src/operate}/retry/isTransientNetworkError.d.ts +0 -0
- /package/dist/esm/{operate → src/operate}/types.d.ts +0 -0
- /package/dist/esm/{providers → src/providers}/anthropic/AnthropicProvider.class.d.ts +0 -0
- /package/dist/esm/{providers → src/providers}/anthropic/index.d.ts +0 -0
- /package/dist/esm/{providers → src/providers}/bedrock/BedrockProvider.class.d.ts +0 -0
- /package/dist/esm/{providers → src/providers}/bedrock/index.d.ts +0 -0
- /package/dist/esm/{providers → src/providers}/bedrock/utils.d.ts +0 -0
- /package/dist/esm/{providers → src/providers}/google/GoogleProvider.class.d.ts +0 -0
- /package/dist/esm/{providers → src/providers}/google/index.d.ts +0 -0
- /package/dist/esm/{providers → src/providers}/google/types.d.ts +0 -0
- /package/dist/esm/{providers → src/providers}/openai/OpenAiProvider.class.d.ts +0 -0
- /package/dist/esm/{providers → src/providers}/openai/index.d.ts +0 -0
- /package/dist/esm/{providers → src/providers}/openai/types.d.ts +0 -0
- /package/dist/esm/{providers → src/providers}/openrouter/OpenRouterProvider.class.d.ts +0 -0
- /package/dist/esm/{providers → src/providers}/openrouter/index.d.ts +0 -0
- /package/dist/esm/{providers → src/providers}/xai/XaiProvider.class.d.ts +0 -0
- /package/dist/esm/{providers → src/providers}/xai/index.d.ts +0 -0
- /package/dist/esm/{tools → src/tools}/Toolkit.class.d.ts +0 -0
- /package/dist/esm/{tools → src/tools}/index.d.ts +0 -0
- /package/dist/esm/{tools → src/tools}/random.d.ts +0 -0
- /package/dist/esm/{tools → src/tools}/roll.d.ts +0 -0
- /package/dist/esm/{tools → src/tools}/time.d.ts +0 -0
- /package/dist/esm/{tools → src/tools}/weather.d.ts +0 -0
- /package/dist/esm/{types → src/types}/LlmOperateInput.guards.d.ts +0 -0
- /package/dist/esm/{types → src/types}/LlmProvider.interface.d.ts +0 -0
- /package/dist/esm/{types → src/types}/LlmStreamChunk.interface.d.ts +0 -0
- /package/dist/esm/{types → src/types}/LlmTool.interface.d.ts +0 -0
- /package/dist/esm/{upload → src/upload}/detectMimeType.d.ts +0 -0
- /package/dist/esm/{upload → src/upload}/extractPdfPages.d.ts +0 -0
- /package/dist/esm/{upload → src/upload}/index.d.ts +0 -0
- /package/dist/esm/{upload → src/upload}/loadLocalFile.d.ts +0 -0
- /package/dist/esm/{upload → src/upload}/loadS3File.d.ts +0 -0
- /package/dist/esm/{upload → src/upload}/resolveOperateInput.d.ts +0 -0
- /package/dist/esm/{util → src/util}/determineModelProvider.d.ts +0 -0
- /package/dist/esm/{util → src/util}/extractReasoning.d.ts +0 -0
- /package/dist/esm/{util → src/util}/fillFormatArrays.d.ts +0 -0
- /package/dist/esm/{util → src/util}/formatOperateInput.d.ts +0 -0
- /package/dist/esm/{util → src/util}/formatOperateMessage.d.ts +0 -0
- /package/dist/esm/{util → src/util}/jsonSchemaToOpenApi3.d.ts +0 -0
- /package/dist/esm/{util → src/util}/logger.d.ts +0 -0
- /package/dist/esm/{util → src/util}/maxTurnsFromOptions.d.ts +0 -0
- /package/dist/esm/{util → src/util}/naturalZodSchema.d.ts +0 -0
- /package/dist/esm/{util → src/util}/random.d.ts +0 -0
- /package/dist/esm/{util → src/util}/repairFormatKeys.d.ts +0 -0
- /package/dist/esm/{util → src/util}/tryParseNumber.d.ts +0 -0
package/dist/esm/index.js
CHANGED
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import { ConfigurationError, BadGatewayError, TooManyRequestsError, NotImplementedError } from '@jaypie/errors';
|
|
2
|
-
import log$
|
|
2
|
+
import log$1, { log as log$2 } from '@jaypie/logger';
|
|
3
3
|
import { z } from 'zod/v4';
|
|
4
4
|
import { placeholders, JAYPIE, resolveValue, sleep } from '@jaypie/kit';
|
|
5
5
|
import RandomLib from 'random';
|
|
6
|
-
import { RateLimitError, APIConnectionError, APIConnectionTimeoutError, InternalServerError, APIUserAbortError, AuthenticationError, BadRequestError, ConflictError, NotFoundError, PermissionDeniedError, UnprocessableEntityError, OpenAI } from 'openai';
|
|
7
|
-
import { zodResponseFormat } from 'openai/helpers/zod';
|
|
8
6
|
import { createRequire } from 'module';
|
|
9
7
|
import { pathToFileURL } from 'url';
|
|
10
8
|
import { PDFDocument } from 'pdf-lib';
|
|
@@ -767,6 +765,119 @@ function formatOperateInput(input, options) {
|
|
|
767
765
|
return [input];
|
|
768
766
|
}
|
|
769
767
|
|
|
768
|
+
// Keywords a JSON Schema object node can carry that Natural Schema has no
|
|
769
|
+
// representation for. Anything present here (or any other unrecognized key)
|
|
770
|
+
// is dropped silently and logged, never thrown.
|
|
771
|
+
const LOSSY_OBJECT_KEYWORDS = [
|
|
772
|
+
"$defs",
|
|
773
|
+
"$id",
|
|
774
|
+
"$ref",
|
|
775
|
+
"$schema",
|
|
776
|
+
"additionalProperties",
|
|
777
|
+
"const",
|
|
778
|
+
"default",
|
|
779
|
+
"description",
|
|
780
|
+
"format",
|
|
781
|
+
"maxLength",
|
|
782
|
+
"maximum",
|
|
783
|
+
"minLength",
|
|
784
|
+
"minimum",
|
|
785
|
+
"multipleOf",
|
|
786
|
+
"nullable",
|
|
787
|
+
"allOf",
|
|
788
|
+
"anyOf",
|
|
789
|
+
"oneOf",
|
|
790
|
+
"pattern",
|
|
791
|
+
];
|
|
792
|
+
const KNOWN_KEYWORDS = new Set([
|
|
793
|
+
"type",
|
|
794
|
+
"properties",
|
|
795
|
+
"required",
|
|
796
|
+
"items",
|
|
797
|
+
"enum",
|
|
798
|
+
...LOSSY_OBJECT_KEYWORDS,
|
|
799
|
+
]);
|
|
800
|
+
/**
|
|
801
|
+
* Duck-type check for a bare JSON Schema object node: `{ type: "object", properties: {...} }`.
|
|
802
|
+
* Does not require the OpenAI-style `{ type: "json_schema", ... }` envelope.
|
|
803
|
+
*/
|
|
804
|
+
function isJsonSchema$1(value) {
|
|
805
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
806
|
+
return false;
|
|
807
|
+
}
|
|
808
|
+
const schema = value;
|
|
809
|
+
return (schema.type === "object" &&
|
|
810
|
+
typeof schema.properties === "object" &&
|
|
811
|
+
schema.properties !== null &&
|
|
812
|
+
!Array.isArray(schema.properties));
|
|
813
|
+
}
|
|
814
|
+
/**
|
|
815
|
+
* Convert a Natural Schema to JSON Schema. Lossless: Natural Schema is a
|
|
816
|
+
* strict subset of what JSON Schema can express.
|
|
817
|
+
*/
|
|
818
|
+
function naturalSchemaToJsonSchema(schema) {
|
|
819
|
+
return z.toJSONSchema(naturalZodSchema(schema));
|
|
820
|
+
}
|
|
821
|
+
function logDroppedKeywords(schema, path) {
|
|
822
|
+
for (const key of Object.keys(schema)) {
|
|
823
|
+
if (!KNOWN_KEYWORDS.has(key)) {
|
|
824
|
+
log$1.debug(`[jsonSchemaToNaturalSchema] Dropping unrecognized keyword "${key}" at "${path}"`);
|
|
825
|
+
}
|
|
826
|
+
else if (LOSSY_OBJECT_KEYWORDS.includes(key) &&
|
|
827
|
+
schema[key] !== undefined) {
|
|
828
|
+
log$1.debug(`[jsonSchemaToNaturalSchema] Dropping unsupported keyword "${key}" at "${path}"`);
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
}
|
|
832
|
+
function convertNode(schema, path) {
|
|
833
|
+
logDroppedKeywords(schema, path);
|
|
834
|
+
if (Array.isArray(schema.enum)) {
|
|
835
|
+
return schema.enum;
|
|
836
|
+
}
|
|
837
|
+
switch (schema.type) {
|
|
838
|
+
case "string":
|
|
839
|
+
return String;
|
|
840
|
+
case "number":
|
|
841
|
+
case "integer":
|
|
842
|
+
return Number;
|
|
843
|
+
case "boolean":
|
|
844
|
+
return Boolean;
|
|
845
|
+
case "array": {
|
|
846
|
+
const items = schema.items;
|
|
847
|
+
if (typeof items !== "object" || items === null || Array.isArray(items)) {
|
|
848
|
+
return Array;
|
|
849
|
+
}
|
|
850
|
+
return [convertNode(items, `${path}[]`)];
|
|
851
|
+
}
|
|
852
|
+
case "object": {
|
|
853
|
+
const properties = schema.properties;
|
|
854
|
+
if (!properties || Object.keys(properties).length === 0) {
|
|
855
|
+
return Object;
|
|
856
|
+
}
|
|
857
|
+
const required = new Set(Array.isArray(schema.required) ? schema.required : []);
|
|
858
|
+
const result = {};
|
|
859
|
+
for (const [key, value] of Object.entries(properties)) {
|
|
860
|
+
if (!required.has(key)) {
|
|
861
|
+
log$1.debug(`[jsonSchemaToNaturalSchema] Field "${path}.${key}" is optional; Natural Schema has no optional marker — treating as required`);
|
|
862
|
+
}
|
|
863
|
+
result[key] = convertNode(value, `${path}.${key}`);
|
|
864
|
+
}
|
|
865
|
+
return result;
|
|
866
|
+
}
|
|
867
|
+
default:
|
|
868
|
+
log$1.debug(`[jsonSchemaToNaturalSchema] Unsupported type "${String(schema.type)}" at "${path}"; defaulting to Object`);
|
|
869
|
+
return Object;
|
|
870
|
+
}
|
|
871
|
+
}
|
|
872
|
+
/**
|
|
873
|
+
* Convert a JSON Schema object node to Natural Schema. Lossy: constraints,
|
|
874
|
+
* descriptions, defaults, unions, and optionality have no Natural Schema
|
|
875
|
+
* representation. Dropped keywords are logged at debug level, never thrown.
|
|
876
|
+
*/
|
|
877
|
+
function jsonSchemaToNaturalSchema(schema) {
|
|
878
|
+
return convertNode(schema, "$");
|
|
879
|
+
}
|
|
880
|
+
|
|
770
881
|
/**
|
|
771
882
|
* Converts a JSON Schema (Draft 2020-12) object to the OpenAPI 3.0 schema subset
|
|
772
883
|
* that Gemini's `responseSchema` accepts. This constrains generation (not just validation)
|
|
@@ -809,7 +920,7 @@ function jsonSchemaToOpenApi3(schema) {
|
|
|
809
920
|
return result;
|
|
810
921
|
}
|
|
811
922
|
|
|
812
|
-
const getLogger$6 = () => log$
|
|
923
|
+
const getLogger$6 = () => log$2.lib({ lib: JAYPIE.LIB.LLM });
|
|
813
924
|
|
|
814
925
|
// Turn policy constants
|
|
815
926
|
const MAX_TURNS_ABSOLUTE_LIMIT = 72;
|
|
@@ -1085,6 +1196,45 @@ function repairFormatKeys({ content, format, }) {
|
|
|
1085
1196
|
return repairFromSchema(schema, structuredClone(content));
|
|
1086
1197
|
}
|
|
1087
1198
|
|
|
1199
|
+
const DEFAULT_DONE_SENTINEL = "[DONE]";
|
|
1200
|
+
/**
|
|
1201
|
+
* Parse a Server-Sent Events stream into decoded JSON chunks. Buffers across
|
|
1202
|
+
* network reads, dispatches on newline-delimited `data:` lines, and stops at
|
|
1203
|
+
* the done sentinel (OpenAI-style `[DONE]`; Gemini omits it and simply ends
|
|
1204
|
+
* the stream). Comment lines (`: ...`, used for keep-alive) are ignored.
|
|
1205
|
+
*
|
|
1206
|
+
* Shared by the provider HTTP clients that replaced their vendor SDKs.
|
|
1207
|
+
*/
|
|
1208
|
+
async function* parseSseStream(body, { doneSentinel = DEFAULT_DONE_SENTINEL } = {}) {
|
|
1209
|
+
const reader = body.getReader();
|
|
1210
|
+
const decoder = new TextDecoder();
|
|
1211
|
+
let buffer = "";
|
|
1212
|
+
try {
|
|
1213
|
+
for (;;) {
|
|
1214
|
+
const { done, value } = await reader.read();
|
|
1215
|
+
if (done)
|
|
1216
|
+
break;
|
|
1217
|
+
buffer += decoder.decode(value, { stream: true });
|
|
1218
|
+
let newlineIndex;
|
|
1219
|
+
while ((newlineIndex = buffer.indexOf("\n")) !== -1) {
|
|
1220
|
+
const line = buffer.slice(0, newlineIndex).replace(/\r$/, "");
|
|
1221
|
+
buffer = buffer.slice(newlineIndex + 1);
|
|
1222
|
+
if (line === "" || line.startsWith(":"))
|
|
1223
|
+
continue;
|
|
1224
|
+
if (!line.startsWith("data:"))
|
|
1225
|
+
continue;
|
|
1226
|
+
const data = line.slice("data:".length).trim();
|
|
1227
|
+
if (data === doneSentinel)
|
|
1228
|
+
return;
|
|
1229
|
+
yield JSON.parse(data);
|
|
1230
|
+
}
|
|
1231
|
+
}
|
|
1232
|
+
}
|
|
1233
|
+
finally {
|
|
1234
|
+
reader.releaseLock();
|
|
1235
|
+
}
|
|
1236
|
+
}
|
|
1237
|
+
|
|
1088
1238
|
/**
|
|
1089
1239
|
* Helper function to safely call a function that might throw
|
|
1090
1240
|
* @param fn Function to call safely
|
|
@@ -1676,11 +1826,13 @@ class AnthropicAdapter extends BaseProviderAdapter {
|
|
|
1676
1826
|
}
|
|
1677
1827
|
formatOutputSchema(schema) {
|
|
1678
1828
|
let jsonSchema;
|
|
1679
|
-
// Check if schema is already a JsonObject
|
|
1680
|
-
|
|
1829
|
+
// Check if schema is already a JsonObject — either the OpenAI-style
|
|
1830
|
+
// `{ type: "json_schema", ... }` envelope or a bare `{ type: "object", properties }` node
|
|
1831
|
+
if ((typeof schema === "object" &&
|
|
1681
1832
|
schema !== null &&
|
|
1682
1833
|
!Array.isArray(schema) &&
|
|
1683
|
-
schema.type === "json_schema")
|
|
1834
|
+
schema.type === "json_schema") ||
|
|
1835
|
+
isJsonSchema$1(schema)) {
|
|
1684
1836
|
jsonSchema = structuredClone(schema);
|
|
1685
1837
|
jsonSchema.type = "object"; // Validator does not recognize "json_schema"
|
|
1686
1838
|
}
|
|
@@ -2342,6 +2494,10 @@ class BedrockAdapter extends BaseProviderAdapter {
|
|
|
2342
2494
|
}));
|
|
2343
2495
|
}
|
|
2344
2496
|
formatOutputSchema(schema) {
|
|
2497
|
+
// Bare JSON Schema node: `{ type: "object", properties: {...} }`
|
|
2498
|
+
if (isJsonSchema$1(schema)) {
|
|
2499
|
+
return structuredClone(schema);
|
|
2500
|
+
}
|
|
2345
2501
|
const zodSchema = schema instanceof z.ZodType
|
|
2346
2502
|
? schema
|
|
2347
2503
|
: naturalZodSchema(schema);
|
|
@@ -2878,11 +3034,13 @@ class GoogleAdapter extends BaseProviderAdapter {
|
|
|
2878
3034
|
}
|
|
2879
3035
|
formatOutputSchema(schema) {
|
|
2880
3036
|
let jsonSchema;
|
|
2881
|
-
// Check if schema is already a JsonObject
|
|
2882
|
-
|
|
3037
|
+
// Check if schema is already a JsonObject — either the OpenAI-style
|
|
3038
|
+
// `{ type: "json_schema", ... }` envelope or a bare `{ type: "object", properties }` node
|
|
3039
|
+
if ((typeof schema === "object" &&
|
|
2883
3040
|
schema !== null &&
|
|
2884
3041
|
!Array.isArray(schema) &&
|
|
2885
|
-
schema.type === "json_schema")
|
|
3042
|
+
schema.type === "json_schema") ||
|
|
3043
|
+
isJsonSchema$1(schema)) {
|
|
2886
3044
|
jsonSchema = structuredClone(schema);
|
|
2887
3045
|
jsonSchema.type = "object";
|
|
2888
3046
|
}
|
|
@@ -3505,6 +3663,206 @@ class GoogleAdapter extends BaseProviderAdapter {
|
|
|
3505
3663
|
// Export singleton instance
|
|
3506
3664
|
const googleAdapter = new GoogleAdapter();
|
|
3507
3665
|
|
|
3666
|
+
//
|
|
3667
|
+
//
|
|
3668
|
+
// Constants
|
|
3669
|
+
//
|
|
3670
|
+
const OPENAI_BASE_URL = "https://api.openai.com/v1";
|
|
3671
|
+
//
|
|
3672
|
+
//
|
|
3673
|
+
// Errors
|
|
3674
|
+
//
|
|
3675
|
+
// The adapter's `classifyError` uses `instanceof` against these classes, so the
|
|
3676
|
+
// client throws them directly. Status → class mapping mirrors the SDK; the
|
|
3677
|
+
// non-HTTP classes (connection/abort) are thrown when `fetch` itself rejects.
|
|
3678
|
+
//
|
|
3679
|
+
class OpenAiApiError extends Error {
|
|
3680
|
+
constructor(status, message, error) {
|
|
3681
|
+
super(message);
|
|
3682
|
+
this.name = this.constructor.name;
|
|
3683
|
+
this.status = status;
|
|
3684
|
+
this.error = error;
|
|
3685
|
+
}
|
|
3686
|
+
}
|
|
3687
|
+
let BadRequestError$1 = class BadRequestError extends OpenAiApiError {
|
|
3688
|
+
};
|
|
3689
|
+
let AuthenticationError$1 = class AuthenticationError extends OpenAiApiError {
|
|
3690
|
+
};
|
|
3691
|
+
let PermissionDeniedError$1 = class PermissionDeniedError extends OpenAiApiError {
|
|
3692
|
+
};
|
|
3693
|
+
let NotFoundError$1 = class NotFoundError extends OpenAiApiError {
|
|
3694
|
+
};
|
|
3695
|
+
class ConflictError extends OpenAiApiError {
|
|
3696
|
+
}
|
|
3697
|
+
class UnprocessableEntityError extends OpenAiApiError {
|
|
3698
|
+
}
|
|
3699
|
+
let RateLimitError$1 = class RateLimitError extends OpenAiApiError {
|
|
3700
|
+
};
|
|
3701
|
+
let InternalServerError$1 = class InternalServerError extends OpenAiApiError {
|
|
3702
|
+
};
|
|
3703
|
+
class APIConnectionError extends OpenAiApiError {
|
|
3704
|
+
}
|
|
3705
|
+
class APIConnectionTimeoutError extends APIConnectionError {
|
|
3706
|
+
}
|
|
3707
|
+
class APIUserAbortError extends OpenAiApiError {
|
|
3708
|
+
}
|
|
3709
|
+
function errorForStatus$1(status, message, error) {
|
|
3710
|
+
if (status === 400)
|
|
3711
|
+
return new BadRequestError$1(status, message, error);
|
|
3712
|
+
if (status === 401)
|
|
3713
|
+
return new AuthenticationError$1(status, message, error);
|
|
3714
|
+
if (status === 403)
|
|
3715
|
+
return new PermissionDeniedError$1(status, message, error);
|
|
3716
|
+
if (status === 404)
|
|
3717
|
+
return new NotFoundError$1(status, message, error);
|
|
3718
|
+
if (status === 409)
|
|
3719
|
+
return new ConflictError(status, message, error);
|
|
3720
|
+
if (status === 422) {
|
|
3721
|
+
return new UnprocessableEntityError(status, message, error);
|
|
3722
|
+
}
|
|
3723
|
+
if (status === 429)
|
|
3724
|
+
return new RateLimitError$1(status, message, error);
|
|
3725
|
+
if (status >= 500)
|
|
3726
|
+
return new InternalServerError$1(status, message, error);
|
|
3727
|
+
return new OpenAiApiError(status, message, error);
|
|
3728
|
+
}
|
|
3729
|
+
//
|
|
3730
|
+
//
|
|
3731
|
+
// Main
|
|
3732
|
+
//
|
|
3733
|
+
/**
|
|
3734
|
+
* Minimal `fetch`-based client for the OpenAI API. Replaces the `openai` SDK —
|
|
3735
|
+
* the adapters and provider utilities only need the Responses API
|
|
3736
|
+
* (`/responses`, streaming and non-streaming) for `operate`/`stream` and the
|
|
3737
|
+
* Chat Completions API (`/chat/completions`, plus a `parse` helper for
|
|
3738
|
+
* structured output) for `send`. Mirrors the SDK's `responses.create` and
|
|
3739
|
+
* `chat.completions.create` / `chat.completions.parse` surface so call sites are
|
|
3740
|
+
* unchanged. Also serves xAI via a custom `baseURL`.
|
|
3741
|
+
*/
|
|
3742
|
+
class OpenAIClient {
|
|
3743
|
+
constructor({ apiKey, baseURL = OPENAI_BASE_URL }) {
|
|
3744
|
+
this.apiKey = apiKey;
|
|
3745
|
+
this.baseURL = baseURL;
|
|
3746
|
+
this.responses = {
|
|
3747
|
+
create: ((params, options) => params.stream
|
|
3748
|
+
? this.createResponseStream(params, options)
|
|
3749
|
+
: this.createResponse(params, options)),
|
|
3750
|
+
};
|
|
3751
|
+
this.chat = {
|
|
3752
|
+
completions: {
|
|
3753
|
+
create: (params, options) => this.chatCompletion(params, options, { parse: false }),
|
|
3754
|
+
parse: (params, options) => this.chatCompletion(params, options, { parse: true }),
|
|
3755
|
+
},
|
|
3756
|
+
};
|
|
3757
|
+
}
|
|
3758
|
+
headers(extra) {
|
|
3759
|
+
return {
|
|
3760
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
3761
|
+
"Content-Type": "application/json",
|
|
3762
|
+
...extra,
|
|
3763
|
+
};
|
|
3764
|
+
}
|
|
3765
|
+
async post(path, body, { signal } = {}, { stream = false } = {}) {
|
|
3766
|
+
let response;
|
|
3767
|
+
try {
|
|
3768
|
+
response = await fetch(`${this.baseURL}${path}`, {
|
|
3769
|
+
method: "POST",
|
|
3770
|
+
headers: this.headers(stream ? { Accept: "text/event-stream" } : undefined),
|
|
3771
|
+
body: JSON.stringify(body),
|
|
3772
|
+
signal,
|
|
3773
|
+
});
|
|
3774
|
+
}
|
|
3775
|
+
catch (cause) {
|
|
3776
|
+
if (signal?.aborted) {
|
|
3777
|
+
throw new APIUserAbortError(0, "Request was aborted");
|
|
3778
|
+
}
|
|
3779
|
+
const message = cause instanceof Error ? cause.message : "Connection error";
|
|
3780
|
+
const error = new APIConnectionError(0, message);
|
|
3781
|
+
error.cause = cause;
|
|
3782
|
+
throw error;
|
|
3783
|
+
}
|
|
3784
|
+
if (!response.ok)
|
|
3785
|
+
throw await this.toError(response);
|
|
3786
|
+
return response;
|
|
3787
|
+
}
|
|
3788
|
+
async toError(response) {
|
|
3789
|
+
let message = `OpenAI request failed with status ${response.status}`;
|
|
3790
|
+
let error;
|
|
3791
|
+
try {
|
|
3792
|
+
const body = (await response.json());
|
|
3793
|
+
if (body?.error?.message) {
|
|
3794
|
+
message = body.error.message;
|
|
3795
|
+
error = body.error;
|
|
3796
|
+
}
|
|
3797
|
+
}
|
|
3798
|
+
catch {
|
|
3799
|
+
// Non-JSON error body; keep the status-based message.
|
|
3800
|
+
}
|
|
3801
|
+
return errorForStatus$1(response.status, message, error);
|
|
3802
|
+
}
|
|
3803
|
+
async createResponse(params, options) {
|
|
3804
|
+
const response = await this.post("/responses", params, options);
|
|
3805
|
+
return (await response.json());
|
|
3806
|
+
}
|
|
3807
|
+
async createResponseStream(params, options) {
|
|
3808
|
+
const response = await this.post("/responses", params, options, {
|
|
3809
|
+
stream: true,
|
|
3810
|
+
});
|
|
3811
|
+
if (!response.body)
|
|
3812
|
+
return (async function* () { })();
|
|
3813
|
+
// The Responses API streams typed events and does not emit a `[DONE]`
|
|
3814
|
+
// sentinel; the empty default sentinel never matches, so the stream ends
|
|
3815
|
+
// when the connection closes.
|
|
3816
|
+
return parseSseStream(response.body);
|
|
3817
|
+
}
|
|
3818
|
+
async chatCompletion(params, options, { parse }) {
|
|
3819
|
+
const response = await this.post("/chat/completions", params, options);
|
|
3820
|
+
const json = (await response.json());
|
|
3821
|
+
// `chat.completions.parse` surfaces parsed JSON on each message; replicate
|
|
3822
|
+
// the SDK by JSON-parsing the assistant content into `message.parsed`.
|
|
3823
|
+
if (parse) {
|
|
3824
|
+
const choices = json.choices;
|
|
3825
|
+
if (Array.isArray(choices)) {
|
|
3826
|
+
for (const choice of choices) {
|
|
3827
|
+
const message = choice.message;
|
|
3828
|
+
if (message &&
|
|
3829
|
+
typeof message.content === "string" &&
|
|
3830
|
+
!message.refusal) {
|
|
3831
|
+
try {
|
|
3832
|
+
message.parsed = JSON.parse(message.content);
|
|
3833
|
+
}
|
|
3834
|
+
catch {
|
|
3835
|
+
message.parsed = null;
|
|
3836
|
+
}
|
|
3837
|
+
}
|
|
3838
|
+
}
|
|
3839
|
+
}
|
|
3840
|
+
}
|
|
3841
|
+
return json;
|
|
3842
|
+
}
|
|
3843
|
+
}
|
|
3844
|
+
|
|
3845
|
+
//
|
|
3846
|
+
//
|
|
3847
|
+
// Main
|
|
3848
|
+
//
|
|
3849
|
+
/**
|
|
3850
|
+
* Local replacement for `openai/helpers/zod`'s `zodResponseFormat`. Builds the
|
|
3851
|
+
* `response_format` payload OpenAI's Chat Completions / Responses APIs expect
|
|
3852
|
+
* from a Zod schema. The SDK always emits `strict: true`; callers re-derive or
|
|
3853
|
+
* sanitize `schema` as needed (e.g. forcing `additionalProperties: false`).
|
|
3854
|
+
*/
|
|
3855
|
+
function zodResponseFormat(schema, name) {
|
|
3856
|
+
return {
|
|
3857
|
+
type: "json_schema",
|
|
3858
|
+
json_schema: {
|
|
3859
|
+
name,
|
|
3860
|
+
strict: true,
|
|
3861
|
+
schema: z.toJSONSchema(schema),
|
|
3862
|
+
},
|
|
3863
|
+
};
|
|
3864
|
+
}
|
|
3865
|
+
|
|
3508
3866
|
// Patterns for OpenAI reasoning models that support extended thinking
|
|
3509
3867
|
const REASONING_MODEL_PATTERNS = [
|
|
3510
3868
|
/^gpt-[5-9]/, // GPT-5 and above (gpt-5, gpt-5.1, gpt-5.2, gpt-6, etc.)
|
|
@@ -3523,16 +3881,16 @@ function isReasoningModel(model) {
|
|
|
3523
3881
|
const RETRYABLE_ERROR_TYPES = [
|
|
3524
3882
|
APIConnectionError,
|
|
3525
3883
|
APIConnectionTimeoutError,
|
|
3526
|
-
InternalServerError,
|
|
3884
|
+
InternalServerError$1,
|
|
3527
3885
|
];
|
|
3528
3886
|
const NOT_RETRYABLE_ERROR_TYPES = [
|
|
3529
3887
|
APIUserAbortError,
|
|
3530
|
-
AuthenticationError,
|
|
3531
|
-
BadRequestError,
|
|
3888
|
+
AuthenticationError$1,
|
|
3889
|
+
BadRequestError$1,
|
|
3532
3890
|
ConflictError,
|
|
3533
|
-
NotFoundError,
|
|
3534
|
-
PermissionDeniedError,
|
|
3535
|
-
RateLimitError,
|
|
3891
|
+
NotFoundError$1,
|
|
3892
|
+
PermissionDeniedError$1,
|
|
3893
|
+
RateLimitError$1,
|
|
3536
3894
|
UnprocessableEntityError,
|
|
3537
3895
|
];
|
|
3538
3896
|
// Models known not to accept `temperature`.
|
|
@@ -3546,7 +3904,7 @@ const MODELS_WITHOUT_TEMPERATURE$1 = [
|
|
|
3546
3904
|
function isTemperatureDeprecationError$1(error) {
|
|
3547
3905
|
if (!error || typeof error !== "object")
|
|
3548
3906
|
return false;
|
|
3549
|
-
if (!(error instanceof BadRequestError) &&
|
|
3907
|
+
if (!(error instanceof BadRequestError$1) &&
|
|
3550
3908
|
error.status !== 400) {
|
|
3551
3909
|
return false;
|
|
3552
3910
|
}
|
|
@@ -3649,21 +4007,35 @@ class OpenAiAdapter extends BaseProviderAdapter {
|
|
|
3649
4007
|
schema.type === "json_schema") {
|
|
3650
4008
|
return schema;
|
|
3651
4009
|
}
|
|
3652
|
-
//
|
|
3653
|
-
|
|
3654
|
-
|
|
3655
|
-
|
|
3656
|
-
|
|
3657
|
-
|
|
3658
|
-
|
|
3659
|
-
|
|
3660
|
-
|
|
3661
|
-
|
|
3662
|
-
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
|
|
3666
|
-
|
|
4010
|
+
// Bare JSON Schema node: `{ type: "object", properties: {...} }`
|
|
4011
|
+
// Skip the zod round-trip and use it directly (still needs the
|
|
4012
|
+
// additionalProperties + envelope treatment below).
|
|
4013
|
+
let jsonSchema;
|
|
4014
|
+
let name = "response";
|
|
4015
|
+
let strict = true;
|
|
4016
|
+
if (isJsonSchema$1(schema)) {
|
|
4017
|
+
jsonSchema = { ...structuredClone(schema) };
|
|
4018
|
+
delete jsonSchema.$schema;
|
|
4019
|
+
}
|
|
4020
|
+
else {
|
|
4021
|
+
// Convert NaturalSchema to Zod schema if needed
|
|
4022
|
+
const zodSchema = schema instanceof z.ZodType
|
|
4023
|
+
? schema
|
|
4024
|
+
: naturalZodSchema(schema);
|
|
4025
|
+
const responseFormat = zodResponseFormat(zodSchema, "response");
|
|
4026
|
+
// Re-spread to drop zod v4's non-enumerable `~standard` Standard-Schema
|
|
4027
|
+
// interop marker, then strip `$schema`: OpenAI's strict json_schema subset
|
|
4028
|
+
// does not recognize the draft-2020-12 `$schema` keyword, and shipping it
|
|
4029
|
+
// can leave strict structured-output enforcement silently disabled (the
|
|
4030
|
+
// model then free-forms, omitting required fields and corrupting keys).
|
|
4031
|
+
// Mirrors the OpenRouter adapter's sanitization.
|
|
4032
|
+
jsonSchema = {
|
|
4033
|
+
...z.toJSONSchema(zodSchema),
|
|
4034
|
+
};
|
|
4035
|
+
delete jsonSchema.$schema;
|
|
4036
|
+
name = responseFormat.json_schema.name;
|
|
4037
|
+
strict = responseFormat.json_schema.strict;
|
|
4038
|
+
}
|
|
3667
4039
|
// OpenAI requires additionalProperties to be false on all objects
|
|
3668
4040
|
const checks = [jsonSchema];
|
|
3669
4041
|
while (checks.length > 0) {
|
|
@@ -3679,10 +4051,10 @@ class OpenAiAdapter extends BaseProviderAdapter {
|
|
|
3679
4051
|
checks.shift();
|
|
3680
4052
|
}
|
|
3681
4053
|
return {
|
|
3682
|
-
name
|
|
4054
|
+
name,
|
|
3683
4055
|
schema: jsonSchema,
|
|
3684
|
-
strict
|
|
3685
|
-
type:
|
|
4056
|
+
strict,
|
|
4057
|
+
type: "json_schema",
|
|
3686
4058
|
};
|
|
3687
4059
|
}
|
|
3688
4060
|
//
|
|
@@ -3900,7 +4272,7 @@ class OpenAiAdapter extends BaseProviderAdapter {
|
|
|
3900
4272
|
//
|
|
3901
4273
|
classifyError(error) {
|
|
3902
4274
|
// Check for rate limit error
|
|
3903
|
-
if (error instanceof RateLimitError) {
|
|
4275
|
+
if (error instanceof RateLimitError$1) {
|
|
3904
4276
|
return {
|
|
3905
4277
|
error,
|
|
3906
4278
|
category: ErrorCategory.RateLimit,
|
|
@@ -4088,7 +4460,7 @@ function convertContentToOpenRouter(content) {
|
|
|
4088
4460
|
if (item.type === LlmMessageType.InputImage) {
|
|
4089
4461
|
const url = item.image_url ?? "";
|
|
4090
4462
|
if (!url) {
|
|
4091
|
-
log$
|
|
4463
|
+
log$2.warn("OpenRouter image content missing image_url; image discarded");
|
|
4092
4464
|
continue;
|
|
4093
4465
|
}
|
|
4094
4466
|
parts.push({ type: "image_url", imageUrl: { url } });
|
|
@@ -4097,7 +4469,7 @@ function convertContentToOpenRouter(content) {
|
|
|
4097
4469
|
if (item.type === LlmMessageType.InputFile) {
|
|
4098
4470
|
const fileData = typeof item.file_data === "string" ? item.file_data : "";
|
|
4099
4471
|
if (!fileData) {
|
|
4100
|
-
log$
|
|
4472
|
+
log$2.warn({ filename: item.filename }, "OpenRouter file content missing file_data; file discarded");
|
|
4101
4473
|
continue;
|
|
4102
4474
|
}
|
|
4103
4475
|
parts.push({
|
|
@@ -4110,7 +4482,7 @@ function convertContentToOpenRouter(content) {
|
|
|
4110
4482
|
continue;
|
|
4111
4483
|
}
|
|
4112
4484
|
// Unknown type - warn and skip
|
|
4113
|
-
log$
|
|
4485
|
+
log$2.warn({ item }, "Unknown content type for OpenRouter; discarded");
|
|
4114
4486
|
}
|
|
4115
4487
|
// If no parts remain, return empty string to avoid empty array
|
|
4116
4488
|
if (parts.length === 0) {
|
|
@@ -4118,7 +4490,49 @@ function convertContentToOpenRouter(content) {
|
|
|
4118
4490
|
}
|
|
4119
4491
|
return parts;
|
|
4120
4492
|
}
|
|
4121
|
-
|
|
4493
|
+
/**
|
|
4494
|
+
* Convert internal content parts to the OpenAI-compatible wire shape. The
|
|
4495
|
+
* internal representation uses camelCase keys (`imageUrl`, `fileData`) that the
|
|
4496
|
+
* SDK accepted; the REST API wants snake_case (`image_url`, `file_data`).
|
|
4497
|
+
*/
|
|
4498
|
+
function contentToWire(content) {
|
|
4499
|
+
if (content === null ||
|
|
4500
|
+
content === undefined ||
|
|
4501
|
+
typeof content === "string") {
|
|
4502
|
+
return content;
|
|
4503
|
+
}
|
|
4504
|
+
return content.map((part) => {
|
|
4505
|
+
if (part.type === "image_url") {
|
|
4506
|
+
return { type: "image_url", image_url: part.imageUrl };
|
|
4507
|
+
}
|
|
4508
|
+
if (part.type === "file") {
|
|
4509
|
+
return {
|
|
4510
|
+
type: "file",
|
|
4511
|
+
file: { filename: part.file.filename, file_data: part.file.fileData },
|
|
4512
|
+
};
|
|
4513
|
+
}
|
|
4514
|
+
return part;
|
|
4515
|
+
});
|
|
4516
|
+
}
|
|
4517
|
+
/**
|
|
4518
|
+
* Serialize an internal message to the OpenAI-compatible wire shape, mapping
|
|
4519
|
+
* camelCase tool fields (`toolCalls`, `toolCallId`) to snake_case. Tool-call
|
|
4520
|
+
* objects are already wire-shaped (`{ id, type, function: { name, arguments } }`).
|
|
4521
|
+
*/
|
|
4522
|
+
function messageToWire(message) {
|
|
4523
|
+
const wire = { role: message.role };
|
|
4524
|
+
if (message.content !== undefined) {
|
|
4525
|
+
wire.content = contentToWire(message.content);
|
|
4526
|
+
}
|
|
4527
|
+
if (message.toolCalls) {
|
|
4528
|
+
wire.tool_calls = message.toolCalls;
|
|
4529
|
+
}
|
|
4530
|
+
if (message.toolCallId) {
|
|
4531
|
+
wire.tool_call_id = message.toolCallId;
|
|
4532
|
+
}
|
|
4533
|
+
return wire;
|
|
4534
|
+
}
|
|
4535
|
+
// OpenRouter error types based on HTTP status codes
|
|
4122
4536
|
const RETRYABLE_STATUS_CODES = [408, 500, 502, 503, 524, 529];
|
|
4123
4537
|
const RATE_LIMIT_STATUS_CODE = 429;
|
|
4124
4538
|
/**
|
|
@@ -4216,7 +4630,7 @@ class OpenRouterAdapter extends BaseProviderAdapter {
|
|
|
4216
4630
|
? [...request.tools]
|
|
4217
4631
|
: [];
|
|
4218
4632
|
if (useFallbackStructuredOutput && request.format) {
|
|
4219
|
-
log$
|
|
4633
|
+
log$2.warn(`[OpenRouterAdapter] Using legacy structured_output tool fallback for model ${openRouterRequest.model}; native response_format previously rejected for this model.`);
|
|
4220
4634
|
allTools.push({
|
|
4221
4635
|
name: STRUCTURED_OUTPUT_TOOL_NAME,
|
|
4222
4636
|
description: "REQUIRED: You MUST call this tool to provide your final response. " +
|
|
@@ -4282,11 +4696,13 @@ class OpenRouterAdapter extends BaseProviderAdapter {
|
|
|
4282
4696
|
}
|
|
4283
4697
|
formatOutputSchema(schema) {
|
|
4284
4698
|
let jsonSchema;
|
|
4285
|
-
// Check if schema is already a JsonObject
|
|
4286
|
-
|
|
4699
|
+
// Check if schema is already a JsonObject — either the OpenAI-style
|
|
4700
|
+
// `{ type: "json_schema", ... }` envelope or a bare `{ type: "object", properties }` node
|
|
4701
|
+
if ((typeof schema === "object" &&
|
|
4287
4702
|
schema !== null &&
|
|
4288
4703
|
!Array.isArray(schema) &&
|
|
4289
|
-
schema.type === "json_schema")
|
|
4704
|
+
schema.type === "json_schema") ||
|
|
4705
|
+
isJsonSchema$1(schema)) {
|
|
4290
4706
|
jsonSchema = structuredClone(schema);
|
|
4291
4707
|
jsonSchema.type = "object"; // Normalize type
|
|
4292
4708
|
}
|
|
@@ -4321,7 +4737,7 @@ class OpenRouterAdapter extends BaseProviderAdapter {
|
|
|
4321
4737
|
const openRouterRequest = request;
|
|
4322
4738
|
const wantsStructuredOutput = Boolean(openRouterRequest.response_format);
|
|
4323
4739
|
try {
|
|
4324
|
-
const response = (await openRouter.
|
|
4740
|
+
const response = (await openRouter.chatCompletion(this.toWireBody(openRouterRequest), signal ? { signal } : undefined));
|
|
4325
4741
|
if (wantsStructuredOutput) {
|
|
4326
4742
|
response.__jaypieStructuredOutput = true;
|
|
4327
4743
|
}
|
|
@@ -4338,7 +4754,7 @@ class OpenRouterAdapter extends BaseProviderAdapter {
|
|
|
4338
4754
|
this.rememberModelRejectsTemperature(openRouterRequest.model);
|
|
4339
4755
|
const retryRequest = { ...openRouterRequest };
|
|
4340
4756
|
delete retryRequest.temperature;
|
|
4341
|
-
const response = (await openRouter.
|
|
4757
|
+
const response = (await openRouter.chatCompletion(this.toWireBody(retryRequest), signal ? { signal } : undefined));
|
|
4342
4758
|
if (wantsStructuredOutput) {
|
|
4343
4759
|
response.__jaypieStructuredOutput = true;
|
|
4344
4760
|
}
|
|
@@ -4349,9 +4765,9 @@ class OpenRouterAdapter extends BaseProviderAdapter {
|
|
|
4349
4765
|
if (wantsStructuredOutput && isStructuredOutputUnsupportedError(error)) {
|
|
4350
4766
|
const model = openRouterRequest.model;
|
|
4351
4767
|
this.rememberModelRejectsStructuredOutput(model);
|
|
4352
|
-
log$
|
|
4768
|
+
log$2.warn(`[OpenRouterAdapter] Model ${model} rejected native response_format; falling back to legacy structured_output tool emulation.`);
|
|
4353
4769
|
const fallbackRequest = this.toFallbackStructuredOutputRequest(openRouterRequest);
|
|
4354
|
-
return (await openRouter.
|
|
4770
|
+
return (await openRouter.chatCompletion(this.toWireBody(fallbackRequest), signal ? { signal } : undefined));
|
|
4355
4771
|
}
|
|
4356
4772
|
throw error;
|
|
4357
4773
|
}
|
|
@@ -4361,31 +4777,18 @@ class OpenRouterAdapter extends BaseProviderAdapter {
|
|
|
4361
4777
|
* camelCase shape, forwarding only the fields we care about (the SDK
|
|
4362
4778
|
* silently strips unknown fields).
|
|
4363
4779
|
*/
|
|
4364
|
-
|
|
4365
|
-
|
|
4366
|
-
|
|
4367
|
-
|
|
4368
|
-
|
|
4369
|
-
|
|
4370
|
-
|
|
4780
|
+
/**
|
|
4781
|
+
* Serialize the internal request into the OpenAI-compatible wire body for
|
|
4782
|
+
* OpenRouter's Chat Completions endpoint. Top-level fields (model, tools,
|
|
4783
|
+
* tool_choice, response_format, user, temperature, and any providerOptions)
|
|
4784
|
+
* are already wire-shaped (snake_case); only messages carry camelCase tool
|
|
4785
|
+
* fields that must become snake_case on the wire.
|
|
4786
|
+
*/
|
|
4787
|
+
toWireBody(openRouterRequest) {
|
|
4788
|
+
return {
|
|
4789
|
+
...openRouterRequest,
|
|
4790
|
+
messages: openRouterRequest.messages.map(messageToWire),
|
|
4371
4791
|
};
|
|
4372
|
-
if (openRouterRequest.response_format) {
|
|
4373
|
-
const format = openRouterRequest.response_format;
|
|
4374
|
-
if (format.type === "json_schema") {
|
|
4375
|
-
params.responseFormat = {
|
|
4376
|
-
type: "json_schema",
|
|
4377
|
-
jsonSchema: format.json_schema,
|
|
4378
|
-
};
|
|
4379
|
-
}
|
|
4380
|
-
else {
|
|
4381
|
-
params.responseFormat = format;
|
|
4382
|
-
}
|
|
4383
|
-
}
|
|
4384
|
-
const temperature = openRouterRequest.temperature;
|
|
4385
|
-
if (temperature !== undefined) {
|
|
4386
|
-
params.temperature = temperature;
|
|
4387
|
-
}
|
|
4388
|
-
return params;
|
|
4389
4792
|
}
|
|
4390
4793
|
/**
|
|
4391
4794
|
* Rebuild a structured-output request without `response_format`, swapping in
|
|
@@ -4417,15 +4820,9 @@ class OpenRouterAdapter extends BaseProviderAdapter {
|
|
|
4417
4820
|
async *executeStreamRequest(client, request, signal) {
|
|
4418
4821
|
const openRouter = client;
|
|
4419
4822
|
const openRouterRequest = request;
|
|
4420
|
-
//
|
|
4421
|
-
//
|
|
4422
|
-
|
|
4423
|
-
// non-stream response.
|
|
4424
|
-
const streamParams = {
|
|
4425
|
-
...this.toSdkChatParams(openRouterRequest),
|
|
4426
|
-
stream: true,
|
|
4427
|
-
};
|
|
4428
|
-
const stream = (await openRouter.chat.send(streamParams, signal ? { signal } : undefined));
|
|
4823
|
+
// streamChatCompletion adds `stream: true` + `stream_options.include_usage`
|
|
4824
|
+
// and yields decoded SSE chunks in OpenAI-compatible (snake_case) shape.
|
|
4825
|
+
const stream = openRouter.streamChatCompletion(this.toWireBody(openRouterRequest), signal ? { signal } : undefined);
|
|
4429
4826
|
// Track current tool call being built
|
|
4430
4827
|
let currentToolCall = null;
|
|
4431
4828
|
// Track usage for final chunk
|
|
@@ -4874,7 +5271,7 @@ const TRANSIENT_INGEST_MESSAGE_PATTERNS = [
|
|
|
4874
5271
|
"failed to ingest inline file bytes",
|
|
4875
5272
|
];
|
|
4876
5273
|
function isTransientIngestError(error) {
|
|
4877
|
-
if (!(error instanceof BadRequestError))
|
|
5274
|
+
if (!(error instanceof BadRequestError$1))
|
|
4878
5275
|
return false;
|
|
4879
5276
|
const message = (error.message ?? "").toLowerCase();
|
|
4880
5277
|
return TRANSIENT_INGEST_MESSAGE_PATTERNS.some((pattern) => message.includes(pattern));
|
|
@@ -4908,7 +5305,7 @@ class XaiAdapter extends OpenAiAdapter {
|
|
|
4908
5305
|
const xaiAdapter = new XaiAdapter();
|
|
4909
5306
|
|
|
4910
5307
|
const DEFAULT_TOOL_TYPE = "function";
|
|
4911
|
-
const log = log$
|
|
5308
|
+
const log = log$2.lib({ lib: JAYPIE.LIB.LLM });
|
|
4912
5309
|
function logToolMessage(message, context) {
|
|
4913
5310
|
log.trace.var({ [context.name]: message });
|
|
4914
5311
|
}
|
|
@@ -5066,7 +5463,7 @@ const requireModule = typeof __filename !== "undefined"
|
|
|
5066
5463
|
? createRequire(pathToFileURL(__filename).href)
|
|
5067
5464
|
: createRequire(import.meta.url);
|
|
5068
5465
|
let resolved = false;
|
|
5069
|
-
let cachedSdk$
|
|
5466
|
+
let cachedSdk$1 = null;
|
|
5070
5467
|
/**
|
|
5071
5468
|
* Lazily resolve the dd-trace `llmobs` SDK. Returns null (and never throws)
|
|
5072
5469
|
* when dd-trace is absent or the SDK surface is unexpected. Cached after the
|
|
@@ -5074,7 +5471,7 @@ let cachedSdk$4 = null;
|
|
|
5074
5471
|
*/
|
|
5075
5472
|
function resolveLlmObs() {
|
|
5076
5473
|
if (resolved) {
|
|
5077
|
-
return cachedSdk$
|
|
5474
|
+
return cachedSdk$1;
|
|
5078
5475
|
}
|
|
5079
5476
|
resolved = true;
|
|
5080
5477
|
try {
|
|
@@ -5084,13 +5481,13 @@ function resolveLlmObs() {
|
|
|
5084
5481
|
if (llmobs &&
|
|
5085
5482
|
typeof llmobs.trace === "function" &&
|
|
5086
5483
|
typeof llmobs.annotate === "function") {
|
|
5087
|
-
cachedSdk$
|
|
5484
|
+
cachedSdk$1 = llmobs;
|
|
5088
5485
|
}
|
|
5089
5486
|
}
|
|
5090
5487
|
catch {
|
|
5091
|
-
cachedSdk$
|
|
5488
|
+
cachedSdk$1 = null;
|
|
5092
5489
|
}
|
|
5093
|
-
return cachedSdk$
|
|
5490
|
+
return cachedSdk$1;
|
|
5094
5491
|
}
|
|
5095
5492
|
//
|
|
5096
5493
|
//
|
|
@@ -7004,21 +7401,127 @@ function createStreamLoop(config) {
|
|
|
7004
7401
|
return new StreamLoop(config);
|
|
7005
7402
|
}
|
|
7006
7403
|
|
|
7007
|
-
//
|
|
7008
|
-
|
|
7009
|
-
|
|
7010
|
-
|
|
7011
|
-
|
|
7012
|
-
|
|
7013
|
-
|
|
7014
|
-
|
|
7404
|
+
//
|
|
7405
|
+
//
|
|
7406
|
+
// Constants
|
|
7407
|
+
//
|
|
7408
|
+
const ANTHROPIC_BASE_URL = "https://api.anthropic.com/v1";
|
|
7409
|
+
const ANTHROPIC_VERSION = "2023-06-01";
|
|
7410
|
+
//
|
|
7411
|
+
//
|
|
7412
|
+
// Errors
|
|
7413
|
+
//
|
|
7414
|
+
// The adapter's `classifyError` keys off `error.constructor.name` (the SDK's
|
|
7415
|
+
// class names), so the client throws errors whose class names match. Status →
|
|
7416
|
+
// class mapping mirrors the SDK.
|
|
7417
|
+
//
|
|
7418
|
+
class AnthropicApiError extends Error {
|
|
7419
|
+
constructor(status, message, error) {
|
|
7420
|
+
super(message);
|
|
7421
|
+
this.name = this.constructor.name;
|
|
7422
|
+
this.status = status;
|
|
7423
|
+
this.error = error;
|
|
7015
7424
|
}
|
|
7016
|
-
|
|
7017
|
-
|
|
7425
|
+
}
|
|
7426
|
+
class BadRequestError extends AnthropicApiError {
|
|
7427
|
+
}
|
|
7428
|
+
class AuthenticationError extends AnthropicApiError {
|
|
7429
|
+
}
|
|
7430
|
+
class PermissionDeniedError extends AnthropicApiError {
|
|
7431
|
+
}
|
|
7432
|
+
class NotFoundError extends AnthropicApiError {
|
|
7433
|
+
}
|
|
7434
|
+
class RateLimitError extends AnthropicApiError {
|
|
7435
|
+
}
|
|
7436
|
+
class InternalServerError extends AnthropicApiError {
|
|
7437
|
+
}
|
|
7438
|
+
function errorForStatus(status, message, error) {
|
|
7439
|
+
if (status === 400)
|
|
7440
|
+
return new BadRequestError(status, message, error);
|
|
7441
|
+
if (status === 401)
|
|
7442
|
+
return new AuthenticationError(status, message, error);
|
|
7443
|
+
if (status === 403)
|
|
7444
|
+
return new PermissionDeniedError(status, message, error);
|
|
7445
|
+
if (status === 404)
|
|
7446
|
+
return new NotFoundError(status, message, error);
|
|
7447
|
+
if (status === 429)
|
|
7448
|
+
return new RateLimitError(status, message, error);
|
|
7449
|
+
if (status >= 500)
|
|
7450
|
+
return new InternalServerError(status, message, error);
|
|
7451
|
+
return new AnthropicApiError(status, message, error);
|
|
7452
|
+
}
|
|
7453
|
+
//
|
|
7454
|
+
//
|
|
7455
|
+
// Main
|
|
7456
|
+
//
|
|
7457
|
+
/**
|
|
7458
|
+
* Minimal `fetch`-based client for Anthropic's Messages API. Replaces
|
|
7459
|
+
* `@anthropic-ai/sdk` — the adapter only needs `messages.create` (streaming and
|
|
7460
|
+
* non-streaming), header auth, and HTTP errors whose class names drive
|
|
7461
|
+
* `classifyError`. Internal request params are already Anthropic's wire shape,
|
|
7462
|
+
* so they serialize verbatim. Exposes a `messages` facade mirroring the SDK so
|
|
7463
|
+
* the adapter call sites are unchanged.
|
|
7464
|
+
*/
|
|
7465
|
+
class AnthropicClient {
|
|
7466
|
+
constructor({ apiKey, baseURL = ANTHROPIC_BASE_URL, }) {
|
|
7467
|
+
this.apiKey = apiKey;
|
|
7468
|
+
this.baseURL = baseURL;
|
|
7469
|
+
this.messages = {
|
|
7470
|
+
create: ((params, options) => params.stream
|
|
7471
|
+
? this.createStream(params, options)
|
|
7472
|
+
: this.createMessage(params, options)),
|
|
7473
|
+
};
|
|
7474
|
+
}
|
|
7475
|
+
headers() {
|
|
7476
|
+
return {
|
|
7477
|
+
"anthropic-version": ANTHROPIC_VERSION,
|
|
7478
|
+
"content-type": "application/json",
|
|
7479
|
+
"x-api-key": this.apiKey,
|
|
7480
|
+
};
|
|
7481
|
+
}
|
|
7482
|
+
async toError(response) {
|
|
7483
|
+
let message = `Anthropic request failed with status ${response.status}`;
|
|
7484
|
+
let error;
|
|
7485
|
+
try {
|
|
7486
|
+
const body = (await response.json());
|
|
7487
|
+
if (body?.error?.message) {
|
|
7488
|
+
message = body.error.message;
|
|
7489
|
+
error = body.error;
|
|
7490
|
+
}
|
|
7491
|
+
}
|
|
7492
|
+
catch {
|
|
7493
|
+
// Non-JSON error body; keep the status-based message.
|
|
7494
|
+
}
|
|
7495
|
+
return errorForStatus(response.status, message, error);
|
|
7496
|
+
}
|
|
7497
|
+
async createMessage(params, { signal } = {}) {
|
|
7498
|
+
const response = await fetch(`${this.baseURL}/messages`, {
|
|
7499
|
+
method: "POST",
|
|
7500
|
+
headers: this.headers(),
|
|
7501
|
+
body: JSON.stringify(params),
|
|
7502
|
+
signal,
|
|
7503
|
+
});
|
|
7504
|
+
if (!response.ok)
|
|
7505
|
+
throw await this.toError(response);
|
|
7506
|
+
return (await response.json());
|
|
7507
|
+
}
|
|
7508
|
+
async createStream(params, { signal } = {}) {
|
|
7509
|
+
const response = await fetch(`${this.baseURL}/messages`, {
|
|
7510
|
+
method: "POST",
|
|
7511
|
+
headers: { ...this.headers(), accept: "text/event-stream" },
|
|
7512
|
+
body: JSON.stringify(params),
|
|
7513
|
+
signal,
|
|
7514
|
+
});
|
|
7515
|
+
if (!response.ok)
|
|
7516
|
+
throw await this.toError(response);
|
|
7517
|
+
if (!response.body)
|
|
7518
|
+
return (async function* () { })();
|
|
7519
|
+
return parseSseStream(response.body);
|
|
7018
7520
|
}
|
|
7019
7521
|
}
|
|
7522
|
+
|
|
7020
7523
|
// Logger
|
|
7021
|
-
const getLogger$5 = () => log$
|
|
7524
|
+
const getLogger$5 = () => log$2.lib({ lib: JAYPIE.LIB.LLM });
|
|
7022
7525
|
// Client initialization
|
|
7023
7526
|
async function initializeClient$5({ apiKey, } = {}) {
|
|
7024
7527
|
const logger = getLogger$5();
|
|
@@ -7026,8 +7529,7 @@ async function initializeClient$5({ apiKey, } = {}) {
|
|
|
7026
7529
|
if (!resolvedApiKey) {
|
|
7027
7530
|
throw new ConfigurationError("The application could not resolve the required API key: ANTHROPIC_API_KEY");
|
|
7028
7531
|
}
|
|
7029
|
-
const
|
|
7030
|
-
const client = new sdk.default({ apiKey: resolvedApiKey });
|
|
7532
|
+
const client = new AnthropicClient({ apiKey: resolvedApiKey });
|
|
7031
7533
|
logger.trace("Initialized Anthropic client");
|
|
7032
7534
|
return client;
|
|
7033
7535
|
}
|
|
@@ -7057,7 +7559,7 @@ function prepareMessages$3(message, { data, placeholders } = {}) {
|
|
|
7057
7559
|
}
|
|
7058
7560
|
// Basic text completion
|
|
7059
7561
|
async function createTextCompletion$1(client, messages, model, systemMessage) {
|
|
7060
|
-
log$
|
|
7562
|
+
log$2.trace("Using text output (unstructured)");
|
|
7061
7563
|
const params = {
|
|
7062
7564
|
model,
|
|
7063
7565
|
messages,
|
|
@@ -7066,19 +7568,19 @@ async function createTextCompletion$1(client, messages, model, systemMessage) {
|
|
|
7066
7568
|
// Add system instruction if provided
|
|
7067
7569
|
if (systemMessage) {
|
|
7068
7570
|
params.system = systemMessage;
|
|
7069
|
-
log$
|
|
7571
|
+
log$2.trace(`System message: ${systemMessage.length} characters`);
|
|
7070
7572
|
}
|
|
7071
7573
|
const response = await client.messages.create(params);
|
|
7072
7574
|
const firstContent = response.content[0];
|
|
7073
7575
|
const text = firstContent && "text" in firstContent ? firstContent.text : "";
|
|
7074
|
-
log$
|
|
7576
|
+
log$2.trace(`Assistant reply: ${text.length} characters`);
|
|
7075
7577
|
return text;
|
|
7076
7578
|
}
|
|
7077
7579
|
// Structured output completion using Anthropic's native `output_config.format`
|
|
7078
7580
|
// field. Returns a JsonObject parsed and validated against the caller's
|
|
7079
7581
|
// Zod schema.
|
|
7080
7582
|
async function createStructuredCompletion$1(client, messages, model, responseSchema, systemMessage) {
|
|
7081
|
-
log$
|
|
7583
|
+
log$2.trace("Using native structured output");
|
|
7082
7584
|
const schema = responseSchema instanceof z.ZodType
|
|
7083
7585
|
? responseSchema
|
|
7084
7586
|
: naturalZodSchema(responseSchema);
|
|
@@ -7116,7 +7618,7 @@ async function createStructuredCompletion$1(client, messages, model, responseSch
|
|
|
7116
7618
|
if (!validation.success) {
|
|
7117
7619
|
throw new Error(`JSON response from Anthropic does not match schema: ${textBlock.text}`);
|
|
7118
7620
|
}
|
|
7119
|
-
log$
|
|
7621
|
+
log$2.trace("Received structured response", { result: validation.data });
|
|
7120
7622
|
return validation.data;
|
|
7121
7623
|
}
|
|
7122
7624
|
|
|
@@ -7127,6 +7629,7 @@ async function createStructuredCompletion$1(client, messages, model, responseSch
|
|
|
7127
7629
|
[LlmMessageRole.Assistant]: PROVIDER.ANTHROPIC.ROLE.ASSISTANT,
|
|
7128
7630
|
[LlmMessageRole.Developer]: PROVIDER.ANTHROPIC.ROLE.SYSTEM,
|
|
7129
7631
|
});
|
|
7632
|
+
/* eslint-enable @typescript-eslint/no-namespace */
|
|
7130
7633
|
|
|
7131
7634
|
// Main class implementation
|
|
7132
7635
|
class AnthropicProvider {
|
|
@@ -7215,23 +7718,23 @@ class AnthropicProvider {
|
|
|
7215
7718
|
}
|
|
7216
7719
|
}
|
|
7217
7720
|
|
|
7218
|
-
let cachedSdk
|
|
7219
|
-
async function loadSdk
|
|
7220
|
-
if (cachedSdk
|
|
7221
|
-
return cachedSdk
|
|
7721
|
+
let cachedSdk = null;
|
|
7722
|
+
async function loadSdk() {
|
|
7723
|
+
if (cachedSdk)
|
|
7724
|
+
return cachedSdk;
|
|
7222
7725
|
try {
|
|
7223
|
-
cachedSdk
|
|
7224
|
-
return cachedSdk
|
|
7726
|
+
cachedSdk = await import('@aws-sdk/client-bedrock-runtime');
|
|
7727
|
+
return cachedSdk;
|
|
7225
7728
|
}
|
|
7226
7729
|
catch {
|
|
7227
7730
|
throw new ConfigurationError("@aws-sdk/client-bedrock-runtime is required but not installed. Run: npm install @aws-sdk/client-bedrock-runtime");
|
|
7228
7731
|
}
|
|
7229
7732
|
}
|
|
7230
|
-
const getLogger$4 = () => log$
|
|
7733
|
+
const getLogger$4 = () => log$2.lib({ lib: JAYPIE.LIB.LLM });
|
|
7231
7734
|
async function initializeClient$4({ region, } = {}) {
|
|
7232
7735
|
const logger = getLogger$4();
|
|
7233
7736
|
const resolvedRegion = region || process.env.AWS_REGION || "us-east-1";
|
|
7234
|
-
const sdk = await loadSdk
|
|
7737
|
+
const sdk = await loadSdk();
|
|
7235
7738
|
const client = new sdk.BedrockRuntimeClient({ region: resolvedRegion });
|
|
7236
7739
|
logger.trace("Initialized Bedrock client");
|
|
7237
7740
|
return client;
|
|
@@ -7296,21 +7799,158 @@ class BedrockProvider {
|
|
|
7296
7799
|
}
|
|
7297
7800
|
}
|
|
7298
7801
|
|
|
7299
|
-
//
|
|
7300
|
-
|
|
7301
|
-
|
|
7302
|
-
|
|
7303
|
-
|
|
7304
|
-
|
|
7305
|
-
|
|
7306
|
-
|
|
7802
|
+
//
|
|
7803
|
+
//
|
|
7804
|
+
// Constants
|
|
7805
|
+
//
|
|
7806
|
+
const GOOGLE_BASE_URL = "https://generativelanguage.googleapis.com/v1beta";
|
|
7807
|
+
// Config keys the REST API expects at the top level of the request body. Every
|
|
7808
|
+
// other key in the SDK-style `config` object belongs under `generationConfig`.
|
|
7809
|
+
const TOP_LEVEL_CONFIG_KEYS = new Set([
|
|
7810
|
+
"systemInstruction",
|
|
7811
|
+
"tools",
|
|
7812
|
+
"toolConfig",
|
|
7813
|
+
"safetySettings",
|
|
7814
|
+
"cachedContent",
|
|
7815
|
+
]);
|
|
7816
|
+
/**
|
|
7817
|
+
* HTTP error carrying the upstream status and parsed API message. The
|
|
7818
|
+
* GoogleAdapter classifies errors by reading `.status` / `.code` and
|
|
7819
|
+
* `.message`, so this shape keeps `classifyError` working unchanged after
|
|
7820
|
+
* dropping the SDK.
|
|
7821
|
+
*/
|
|
7822
|
+
class GoogleHttpError extends Error {
|
|
7823
|
+
constructor(status, message) {
|
|
7824
|
+
super(message);
|
|
7825
|
+
this.name = "GoogleHttpError";
|
|
7826
|
+
this.status = status;
|
|
7827
|
+
this.code = status;
|
|
7307
7828
|
}
|
|
7308
|
-
|
|
7309
|
-
|
|
7829
|
+
}
|
|
7830
|
+
//
|
|
7831
|
+
//
|
|
7832
|
+
// Helpers
|
|
7833
|
+
//
|
|
7834
|
+
/**
|
|
7835
|
+
* Translate the SDK-style `{ model, contents, config }` request into the REST
|
|
7836
|
+
* `generateContent` body. `systemInstruction` (a string) becomes a Content;
|
|
7837
|
+
* top-level config keys pass through; all remaining config keys (temperature,
|
|
7838
|
+
* responseMimeType, responseSchema, responseJsonSchema, ...) move under
|
|
7839
|
+
* `generationConfig`.
|
|
7840
|
+
*/
|
|
7841
|
+
function toRestBody(params) {
|
|
7842
|
+
const body = {
|
|
7843
|
+
contents: params.contents,
|
|
7844
|
+
};
|
|
7845
|
+
const config = params.config;
|
|
7846
|
+
if (!config)
|
|
7847
|
+
return body;
|
|
7848
|
+
const generationConfig = {};
|
|
7849
|
+
for (const [key, value] of Object.entries(config)) {
|
|
7850
|
+
if (value === undefined)
|
|
7851
|
+
continue;
|
|
7852
|
+
if (key === "systemInstruction") {
|
|
7853
|
+
body.systemInstruction =
|
|
7854
|
+
typeof value === "string"
|
|
7855
|
+
? { parts: [{ text: value }] }
|
|
7856
|
+
: value;
|
|
7857
|
+
}
|
|
7858
|
+
else if (TOP_LEVEL_CONFIG_KEYS.has(key)) {
|
|
7859
|
+
body[key] = value;
|
|
7860
|
+
}
|
|
7861
|
+
else {
|
|
7862
|
+
generationConfig[key] = value;
|
|
7863
|
+
}
|
|
7864
|
+
}
|
|
7865
|
+
if (Object.keys(generationConfig).length > 0) {
|
|
7866
|
+
body.generationConfig = generationConfig;
|
|
7867
|
+
}
|
|
7868
|
+
return body;
|
|
7869
|
+
}
|
|
7870
|
+
/**
|
|
7871
|
+
* Concatenate the non-thought text parts of the first candidate, matching the
|
|
7872
|
+
* SDK's `response.text` convenience getter (consumed by `GoogleProvider.send`).
|
|
7873
|
+
*/
|
|
7874
|
+
function responseText(response) {
|
|
7875
|
+
const parts = response.candidates?.[0]?.content?.parts;
|
|
7876
|
+
if (!parts)
|
|
7877
|
+
return undefined;
|
|
7878
|
+
const text = parts
|
|
7879
|
+
.filter((part) => part.text && !part.thought)
|
|
7880
|
+
.map((part) => part.text)
|
|
7881
|
+
.join("");
|
|
7882
|
+
return text.length > 0 ? text : undefined;
|
|
7883
|
+
}
|
|
7884
|
+
//
|
|
7885
|
+
//
|
|
7886
|
+
// Main
|
|
7887
|
+
//
|
|
7888
|
+
/**
|
|
7889
|
+
* Minimal `fetch`-based client for Google's Generative Language (Gemini) REST
|
|
7890
|
+
* API. Replaces `@google/genai` — the adapter only needs `generateContent`
|
|
7891
|
+
* (streaming and non-streaming), an api-key header, and HTTP error surfacing.
|
|
7892
|
+
* Exposes a `models` facade mirroring the SDK so the adapter call sites are
|
|
7893
|
+
* unchanged.
|
|
7894
|
+
*/
|
|
7895
|
+
class GoogleClient {
|
|
7896
|
+
constructor({ apiKey, baseURL = GOOGLE_BASE_URL }) {
|
|
7897
|
+
this.apiKey = apiKey;
|
|
7898
|
+
this.baseURL = baseURL;
|
|
7899
|
+
this.models = {
|
|
7900
|
+
generateContent: (params, options) => this.generateContent(params, options),
|
|
7901
|
+
generateContentStream: (params, options) => this.generateContentStream(params, options),
|
|
7902
|
+
};
|
|
7903
|
+
}
|
|
7904
|
+
headers() {
|
|
7905
|
+
return {
|
|
7906
|
+
"Content-Type": "application/json",
|
|
7907
|
+
"x-goog-api-key": this.apiKey,
|
|
7908
|
+
};
|
|
7909
|
+
}
|
|
7910
|
+
async toError(response) {
|
|
7911
|
+
let message = `Google request failed with status ${response.status}`;
|
|
7912
|
+
try {
|
|
7913
|
+
const body = (await response.json());
|
|
7914
|
+
if (body?.error?.message)
|
|
7915
|
+
message = body.error.message;
|
|
7916
|
+
}
|
|
7917
|
+
catch {
|
|
7918
|
+
// Non-JSON error body; keep the status-based message.
|
|
7919
|
+
}
|
|
7920
|
+
return new GoogleHttpError(response.status, message);
|
|
7921
|
+
}
|
|
7922
|
+
async generateContent(params, { signal } = {}) {
|
|
7923
|
+
const url = `${this.baseURL}/models/${params.model}:generateContent`;
|
|
7924
|
+
const response = await fetch(url, {
|
|
7925
|
+
method: "POST",
|
|
7926
|
+
headers: this.headers(),
|
|
7927
|
+
body: JSON.stringify(toRestBody(params)),
|
|
7928
|
+
signal,
|
|
7929
|
+
});
|
|
7930
|
+
if (!response.ok)
|
|
7931
|
+
throw await this.toError(response);
|
|
7932
|
+
const json = (await response.json());
|
|
7933
|
+
json.text = responseText(json);
|
|
7934
|
+
return json;
|
|
7935
|
+
}
|
|
7936
|
+
async generateContentStream(params, { signal } = {}) {
|
|
7937
|
+
const url = `${this.baseURL}/models/${params.model}:streamGenerateContent?alt=sse`;
|
|
7938
|
+
const response = await fetch(url, {
|
|
7939
|
+
method: "POST",
|
|
7940
|
+
headers: { ...this.headers(), Accept: "text/event-stream" },
|
|
7941
|
+
body: JSON.stringify(toRestBody(params)),
|
|
7942
|
+
signal,
|
|
7943
|
+
});
|
|
7944
|
+
if (!response.ok)
|
|
7945
|
+
throw await this.toError(response);
|
|
7946
|
+
if (!response.body)
|
|
7947
|
+
return (async function* () { })();
|
|
7948
|
+
return parseSseStream(response.body);
|
|
7310
7949
|
}
|
|
7311
7950
|
}
|
|
7951
|
+
|
|
7312
7952
|
// Logger
|
|
7313
|
-
const getLogger$3 = () => log$
|
|
7953
|
+
const getLogger$3 = () => log$2.lib({ lib: JAYPIE.LIB.LLM });
|
|
7314
7954
|
// Client initialization
|
|
7315
7955
|
async function initializeClient$3({ apiKey, } = {}) {
|
|
7316
7956
|
const logger = getLogger$3();
|
|
@@ -7318,8 +7958,7 @@ async function initializeClient$3({ apiKey, } = {}) {
|
|
|
7318
7958
|
if (!resolvedApiKey) {
|
|
7319
7959
|
throw new ConfigurationError("The application could not resolve the requested keys");
|
|
7320
7960
|
}
|
|
7321
|
-
const
|
|
7322
|
-
const client = new sdk.GoogleGenAI({ apiKey: resolvedApiKey });
|
|
7961
|
+
const client = new GoogleClient({ apiKey: resolvedApiKey });
|
|
7323
7962
|
logger.trace("Initialized Gemini client");
|
|
7324
7963
|
return client;
|
|
7325
7964
|
}
|
|
@@ -7460,7 +8099,7 @@ class GoogleProvider {
|
|
|
7460
8099
|
}
|
|
7461
8100
|
|
|
7462
8101
|
// Logger
|
|
7463
|
-
const getLogger$2 = () => log$
|
|
8102
|
+
const getLogger$2 = () => log$2.lib({ lib: JAYPIE.LIB.LLM });
|
|
7464
8103
|
// Client initialization
|
|
7465
8104
|
async function initializeClient$2({ apiKey, } = {}) {
|
|
7466
8105
|
const logger = getLogger$2();
|
|
@@ -7468,7 +8107,7 @@ async function initializeClient$2({ apiKey, } = {}) {
|
|
|
7468
8107
|
if (!resolvedApiKey) {
|
|
7469
8108
|
throw new ConfigurationError("The application could not resolve the requested keys");
|
|
7470
8109
|
}
|
|
7471
|
-
const client = new
|
|
8110
|
+
const client = new OpenAIClient({ apiKey: resolvedApiKey });
|
|
7472
8111
|
logger.trace("Initialized OpenAI client");
|
|
7473
8112
|
return client;
|
|
7474
8113
|
}
|
|
@@ -7527,23 +8166,23 @@ async function createStructuredCompletion(client, { messages, responseSchema, mo
|
|
|
7527
8166
|
checks.shift();
|
|
7528
8167
|
}
|
|
7529
8168
|
responseFormat.json_schema.schema = jsonSchema;
|
|
7530
|
-
const completion = await client.chat.completions.parse({
|
|
8169
|
+
const completion = (await client.chat.completions.parse({
|
|
7531
8170
|
messages,
|
|
7532
8171
|
model,
|
|
7533
8172
|
response_format: responseFormat,
|
|
7534
|
-
});
|
|
8173
|
+
}));
|
|
7535
8174
|
logger.var({ assistantReply: completion.choices[0].message.parsed });
|
|
7536
8175
|
return completion.choices[0].message.parsed;
|
|
7537
8176
|
}
|
|
7538
8177
|
async function createTextCompletion(client, { messages, model, }) {
|
|
7539
8178
|
const logger = getLogger$2();
|
|
7540
8179
|
logger.trace("Using text output (unstructured)");
|
|
7541
|
-
const completion = await client.chat.completions.create({
|
|
8180
|
+
const completion = (await client.chat.completions.create({
|
|
7542
8181
|
messages,
|
|
7543
8182
|
model,
|
|
7544
|
-
});
|
|
7545
|
-
logger.trace(`Assistant reply: ${completion.choices[0]?.message?.content?.length} characters`);
|
|
7546
|
-
return completion.choices[0]?.message?.content || "";
|
|
8183
|
+
}));
|
|
8184
|
+
logger.trace(`Assistant reply: ${completion.choices?.[0]?.message?.content?.length} characters`);
|
|
8185
|
+
return completion.choices?.[0]?.message?.content || "";
|
|
7547
8186
|
}
|
|
7548
8187
|
|
|
7549
8188
|
class OpenAiProvider {
|
|
@@ -7630,21 +8269,141 @@ class OpenAiProvider {
|
|
|
7630
8269
|
}
|
|
7631
8270
|
}
|
|
7632
8271
|
|
|
7633
|
-
//
|
|
7634
|
-
|
|
7635
|
-
|
|
7636
|
-
|
|
7637
|
-
|
|
7638
|
-
|
|
7639
|
-
|
|
7640
|
-
|
|
8272
|
+
//
|
|
8273
|
+
//
|
|
8274
|
+
// Constants
|
|
8275
|
+
//
|
|
8276
|
+
const OPENROUTER_BASE_URL = "https://openrouter.ai/api/v1";
|
|
8277
|
+
/**
|
|
8278
|
+
* HTTP error carrying the upstream status and parsed API message. The
|
|
8279
|
+
* OpenRouterAdapter classifies errors by reading `.status` / `.statusCode` and
|
|
8280
|
+
* `.message` / `.error.message`, so this shape keeps `classifyError`,
|
|
8281
|
+
* `isTemperatureDeprecationError`, and `isStructuredOutputUnsupportedError`
|
|
8282
|
+
* working unchanged after dropping the SDK.
|
|
8283
|
+
*/
|
|
8284
|
+
class OpenRouterHttpError extends Error {
|
|
8285
|
+
constructor(status, message, error) {
|
|
8286
|
+
super(message);
|
|
8287
|
+
this.name = "OpenRouterHttpError";
|
|
8288
|
+
this.status = status;
|
|
8289
|
+
this.statusCode = status;
|
|
8290
|
+
this.error = error;
|
|
7641
8291
|
}
|
|
7642
|
-
|
|
7643
|
-
|
|
8292
|
+
}
|
|
8293
|
+
//
|
|
8294
|
+
//
|
|
8295
|
+
// Helpers
|
|
8296
|
+
//
|
|
8297
|
+
/**
|
|
8298
|
+
* Normalize the snake_case wire response into the camelCase shape the adapter
|
|
8299
|
+
* readers expect (the SDK previously returned camelCase). Only protocol fields
|
|
8300
|
+
* are touched — user content (schema property names, tool argument JSON) is
|
|
8301
|
+
* left untouched.
|
|
8302
|
+
*/
|
|
8303
|
+
function normalizeResponse(json) {
|
|
8304
|
+
const choices = json.choices;
|
|
8305
|
+
if (Array.isArray(choices)) {
|
|
8306
|
+
for (const choice of choices) {
|
|
8307
|
+
if (choice.finish_reason !== undefined &&
|
|
8308
|
+
choice.finishReason === undefined) {
|
|
8309
|
+
choice.finishReason = choice.finish_reason;
|
|
8310
|
+
}
|
|
8311
|
+
const message = choice.message;
|
|
8312
|
+
if (message?.tool_calls !== undefined &&
|
|
8313
|
+
message.toolCalls === undefined) {
|
|
8314
|
+
message.toolCalls = message.tool_calls;
|
|
8315
|
+
}
|
|
8316
|
+
}
|
|
8317
|
+
}
|
|
8318
|
+
const usage = json.usage;
|
|
8319
|
+
if (usage) {
|
|
8320
|
+
if (usage.promptTokens === undefined)
|
|
8321
|
+
usage.promptTokens = usage.prompt_tokens;
|
|
8322
|
+
if (usage.completionTokens === undefined) {
|
|
8323
|
+
usage.completionTokens = usage.completion_tokens;
|
|
8324
|
+
}
|
|
8325
|
+
if (usage.totalTokens === undefined)
|
|
8326
|
+
usage.totalTokens = usage.total_tokens;
|
|
8327
|
+
const details = usage.completion_tokens_details;
|
|
8328
|
+
if (details?.reasoning_tokens !== undefined &&
|
|
8329
|
+
!usage.completionTokensDetails) {
|
|
8330
|
+
usage.completionTokensDetails = {
|
|
8331
|
+
reasoningTokens: details.reasoning_tokens,
|
|
8332
|
+
};
|
|
8333
|
+
}
|
|
8334
|
+
}
|
|
8335
|
+
return json;
|
|
8336
|
+
}
|
|
8337
|
+
//
|
|
8338
|
+
//
|
|
8339
|
+
// Main
|
|
8340
|
+
//
|
|
8341
|
+
/**
|
|
8342
|
+
* Minimal `fetch`-based client for OpenRouter's OpenAI-compatible Chat
|
|
8343
|
+
* Completions endpoint. Replaces `@openrouter/sdk` — the adapter only needs a
|
|
8344
|
+
* single POST (streaming and non-streaming), header auth, and HTTP error
|
|
8345
|
+
* surfacing.
|
|
8346
|
+
*/
|
|
8347
|
+
class OpenRouterClient {
|
|
8348
|
+
constructor({ apiKey, baseURL = OPENROUTER_BASE_URL, }) {
|
|
8349
|
+
this.apiKey = apiKey;
|
|
8350
|
+
this.baseURL = baseURL;
|
|
8351
|
+
}
|
|
8352
|
+
headers() {
|
|
8353
|
+
return {
|
|
8354
|
+
Authorization: `Bearer ${this.apiKey}`,
|
|
8355
|
+
"Content-Type": "application/json",
|
|
8356
|
+
};
|
|
8357
|
+
}
|
|
8358
|
+
async toError(response) {
|
|
8359
|
+
let message = `OpenRouter request failed with status ${response.status}`;
|
|
8360
|
+
let error;
|
|
8361
|
+
try {
|
|
8362
|
+
const body = (await response.json());
|
|
8363
|
+
if (body?.error?.message) {
|
|
8364
|
+
message = body.error.message;
|
|
8365
|
+
error = body.error;
|
|
8366
|
+
}
|
|
8367
|
+
}
|
|
8368
|
+
catch {
|
|
8369
|
+
// Non-JSON error body; keep the status-based message.
|
|
8370
|
+
}
|
|
8371
|
+
return new OpenRouterHttpError(response.status, message, error);
|
|
8372
|
+
}
|
|
8373
|
+
async chatCompletion(body, { signal } = {}) {
|
|
8374
|
+
const response = await fetch(`${this.baseURL}/chat/completions`, {
|
|
8375
|
+
method: "POST",
|
|
8376
|
+
headers: this.headers(),
|
|
8377
|
+
body: JSON.stringify(body),
|
|
8378
|
+
signal,
|
|
8379
|
+
});
|
|
8380
|
+
if (!response.ok)
|
|
8381
|
+
throw await this.toError(response);
|
|
8382
|
+
const json = (await response.json());
|
|
8383
|
+
return normalizeResponse(json);
|
|
8384
|
+
}
|
|
8385
|
+
async *streamChatCompletion(body, { signal } = {}) {
|
|
8386
|
+
const response = await fetch(`${this.baseURL}/chat/completions`, {
|
|
8387
|
+
method: "POST",
|
|
8388
|
+
headers: { ...this.headers(), Accept: "text/event-stream" },
|
|
8389
|
+
// OpenAI-style streams only include usage when explicitly requested.
|
|
8390
|
+
body: JSON.stringify({
|
|
8391
|
+
...body,
|
|
8392
|
+
stream: true,
|
|
8393
|
+
stream_options: { include_usage: true },
|
|
8394
|
+
}),
|
|
8395
|
+
signal,
|
|
8396
|
+
});
|
|
8397
|
+
if (!response.ok)
|
|
8398
|
+
throw await this.toError(response);
|
|
8399
|
+
if (!response.body)
|
|
8400
|
+
return;
|
|
8401
|
+
yield* parseSseStream(response.body);
|
|
7644
8402
|
}
|
|
7645
8403
|
}
|
|
8404
|
+
|
|
7646
8405
|
// Logger
|
|
7647
|
-
const getLogger$1 = () => log$
|
|
8406
|
+
const getLogger$1 = () => log$2.lib({ lib: JAYPIE.LIB.LLM });
|
|
7648
8407
|
// Client initialization
|
|
7649
8408
|
async function initializeClient$1({ apiKey, } = {}) {
|
|
7650
8409
|
const logger = getLogger$1();
|
|
@@ -7652,8 +8411,7 @@ async function initializeClient$1({ apiKey, } = {}) {
|
|
|
7652
8411
|
if (!resolvedApiKey) {
|
|
7653
8412
|
throw new ConfigurationError("The application could not resolve the requested keys");
|
|
7654
8413
|
}
|
|
7655
|
-
const
|
|
7656
|
-
const client = new sdk.OpenRouter({ apiKey: resolvedApiKey });
|
|
8414
|
+
const client = new OpenRouterClient({ apiKey: resolvedApiKey });
|
|
7657
8415
|
logger.trace("Initialized OpenRouter client");
|
|
7658
8416
|
return client;
|
|
7659
8417
|
}
|
|
@@ -7733,12 +8491,13 @@ class OpenRouterProvider {
|
|
|
7733
8491
|
const client = await this.getClient();
|
|
7734
8492
|
const messages = prepareMessages(message, options);
|
|
7735
8493
|
const modelToUse = options?.model || this.model;
|
|
7736
|
-
//
|
|
7737
|
-
const response = await client.
|
|
8494
|
+
// OpenAI-compatible Chat Completions body; messages are already wire-shaped.
|
|
8495
|
+
const response = await client.chatCompletion({
|
|
7738
8496
|
model: modelToUse,
|
|
7739
|
-
messages
|
|
8497
|
+
messages,
|
|
7740
8498
|
});
|
|
7741
|
-
const
|
|
8499
|
+
const choices = response.choices;
|
|
8500
|
+
const rawContent = choices?.[0]?.message?.content;
|
|
7742
8501
|
// Extract text content - content could be string or array of content items
|
|
7743
8502
|
const content = typeof rawContent === "string"
|
|
7744
8503
|
? rawContent
|
|
@@ -7793,7 +8552,7 @@ class OpenRouterProvider {
|
|
|
7793
8552
|
}
|
|
7794
8553
|
|
|
7795
8554
|
// Logger
|
|
7796
|
-
const getLogger = () => log$
|
|
8555
|
+
const getLogger = () => log$2.lib({ lib: JAYPIE.LIB.LLM });
|
|
7797
8556
|
// Client initialization
|
|
7798
8557
|
async function initializeClient({ apiKey, } = {}) {
|
|
7799
8558
|
const logger = getLogger();
|
|
@@ -7801,7 +8560,7 @@ async function initializeClient({ apiKey, } = {}) {
|
|
|
7801
8560
|
if (!resolvedApiKey) {
|
|
7802
8561
|
throw new ConfigurationError("The application could not resolve the requested keys");
|
|
7803
8562
|
}
|
|
7804
|
-
const client = new
|
|
8563
|
+
const client = new OpenAIClient({
|
|
7805
8564
|
apiKey: resolvedApiKey,
|
|
7806
8565
|
baseURL: PROVIDER.XAI.BASE_URL,
|
|
7807
8566
|
});
|
|
@@ -7900,7 +8659,7 @@ class Llm {
|
|
|
7900
8659
|
let finalModel = model;
|
|
7901
8660
|
// Legacy: accept "gemini" but warn
|
|
7902
8661
|
if (providerName === "gemini") {
|
|
7903
|
-
log$
|
|
8662
|
+
log$1.warn(`Provider "gemini" is deprecated, use "${PROVIDER.GOOGLE.NAME}" instead`);
|
|
7904
8663
|
}
|
|
7905
8664
|
if (model) {
|
|
7906
8665
|
const modelDetermined = determineModelProvider(model);
|
|
@@ -8014,7 +8773,7 @@ class Llm {
|
|
|
8014
8773
|
}
|
|
8015
8774
|
catch (error) {
|
|
8016
8775
|
lastError = error;
|
|
8017
|
-
log$
|
|
8776
|
+
log$1.warn(`Provider ${this._provider} failed`, {
|
|
8018
8777
|
error: lastError.message,
|
|
8019
8778
|
fallbacksRemaining: fallbackChain.length,
|
|
8020
8779
|
});
|
|
@@ -8034,7 +8793,7 @@ class Llm {
|
|
|
8034
8793
|
}
|
|
8035
8794
|
catch (error) {
|
|
8036
8795
|
lastError = error;
|
|
8037
|
-
log$
|
|
8796
|
+
log$1.warn(`Fallback provider ${fallbackConfig.provider} failed`, {
|
|
8038
8797
|
error: lastError.message,
|
|
8039
8798
|
fallbacksRemaining: fallbackChain.length - attempts + 1,
|
|
8040
8799
|
});
|
|
@@ -8401,5 +9160,5 @@ const toolkit = new JaypieToolkit(tools);
|
|
|
8401
9160
|
[LlmMessageRole.Developer]: "user",
|
|
8402
9161
|
});
|
|
8403
9162
|
|
|
8404
|
-
export { BedrockProvider, GoogleProvider as GeminiProvider, GoogleProvider, JaypieToolkit, constants as LLM, Llm, LlmMessageRole, LlmMessageType, LlmStreamChunkType, OpenRouterProvider, Toolkit, XaiProvider, extractReasoning, isLlmOperateInput, isLlmOperateInputContent, isLlmOperateInputFile, isLlmOperateInputImage, toolkit, tools };
|
|
9163
|
+
export { BedrockProvider, GoogleProvider as GeminiProvider, GoogleProvider, JaypieToolkit, constants as LLM, Llm, LlmMessageRole, LlmMessageType, LlmStreamChunkType, OpenRouterProvider, Toolkit, XaiProvider, extractReasoning, isLlmOperateInput, isLlmOperateInputContent, isLlmOperateInputFile, isLlmOperateInputImage, jsonSchemaToNaturalSchema, naturalSchemaToJsonSchema, toolkit, tools };
|
|
8405
9164
|
//# sourceMappingURL=index.js.map
|