@wrongstack/providers 0.1.2 → 0.1.4
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/LICENSE +17 -13
- package/dist/index.d.ts +153 -2
- package/dist/index.js +720 -5
- package/dist/index.js.map +1 -1
- package/package.json +15 -4
package/dist/index.js
CHANGED
|
@@ -842,9 +842,64 @@ function toolsToGemini(tools) {
|
|
|
842
842
|
return tools.map((t) => ({
|
|
843
843
|
name: t.name,
|
|
844
844
|
description: t.description,
|
|
845
|
-
parameters: t.inputSchema ?? { type: "object", properties: {} }
|
|
845
|
+
parameters: sanitizeSchemaForGemini(t.inputSchema) ?? { type: "object", properties: {} }
|
|
846
846
|
}));
|
|
847
847
|
}
|
|
848
|
+
var GEMINI_ALLOWED_KEYS = /* @__PURE__ */ new Set([
|
|
849
|
+
"type",
|
|
850
|
+
"format",
|
|
851
|
+
"description",
|
|
852
|
+
"nullable",
|
|
853
|
+
"enum",
|
|
854
|
+
"items",
|
|
855
|
+
"properties",
|
|
856
|
+
"required",
|
|
857
|
+
"anyOf",
|
|
858
|
+
"minLength",
|
|
859
|
+
"maxLength",
|
|
860
|
+
"pattern",
|
|
861
|
+
"minimum",
|
|
862
|
+
"maximum",
|
|
863
|
+
"minItems",
|
|
864
|
+
"maxItems",
|
|
865
|
+
"minProperties",
|
|
866
|
+
"maxProperties",
|
|
867
|
+
"propertyOrdering",
|
|
868
|
+
"title"
|
|
869
|
+
]);
|
|
870
|
+
function sanitizeSchemaForGemini(node) {
|
|
871
|
+
if (node === null || node === void 0) return void 0;
|
|
872
|
+
if (Array.isArray(node)) {
|
|
873
|
+
return void 0;
|
|
874
|
+
}
|
|
875
|
+
if (typeof node !== "object") return void 0;
|
|
876
|
+
const src = node;
|
|
877
|
+
const out = {};
|
|
878
|
+
for (const [k, v] of Object.entries(src)) {
|
|
879
|
+
if (!GEMINI_ALLOWED_KEYS.has(k)) continue;
|
|
880
|
+
if (k === "properties" && v && typeof v === "object") {
|
|
881
|
+
const props = {};
|
|
882
|
+
for (const [pname, pschema] of Object.entries(v)) {
|
|
883
|
+
const cleaned = sanitizeSchemaForGemini(pschema);
|
|
884
|
+
if (cleaned) props[pname] = cleaned;
|
|
885
|
+
}
|
|
886
|
+
out["properties"] = props;
|
|
887
|
+
} else if (k === "items") {
|
|
888
|
+
const cleaned = sanitizeSchemaForGemini(v);
|
|
889
|
+
if (cleaned) out["items"] = cleaned;
|
|
890
|
+
} else if (k === "anyOf" && Array.isArray(v)) {
|
|
891
|
+
const cleaned = v.map((s) => sanitizeSchemaForGemini(s)).filter((s) => s !== void 0);
|
|
892
|
+
if (cleaned.length > 0) out["anyOf"] = cleaned;
|
|
893
|
+
} else if (k === "required" && Array.isArray(v)) {
|
|
894
|
+
out["required"] = v.filter((s) => typeof s === "string");
|
|
895
|
+
} else if (k === "enum" && Array.isArray(v)) {
|
|
896
|
+
out["enum"] = v;
|
|
897
|
+
} else {
|
|
898
|
+
out[k] = v;
|
|
899
|
+
}
|
|
900
|
+
}
|
|
901
|
+
return out;
|
|
902
|
+
}
|
|
848
903
|
function messagesToGemini(messages) {
|
|
849
904
|
const out = [];
|
|
850
905
|
for (const m of messages) {
|
|
@@ -855,7 +910,14 @@ function messagesToGemini(messages) {
|
|
|
855
910
|
for (const b of blocks) {
|
|
856
911
|
if (b.type === "text" && b.text) parts.push({ text: b.text });
|
|
857
912
|
else if (b.type === "tool_use") {
|
|
858
|
-
|
|
913
|
+
const part = {
|
|
914
|
+
functionCall: { name: b.name, args: b.input }
|
|
915
|
+
};
|
|
916
|
+
const sig = b.providerMeta?.["google.thoughtSignature"];
|
|
917
|
+
if (typeof sig === "string" && sig.length > 0) {
|
|
918
|
+
part.thoughtSignature = sig;
|
|
919
|
+
}
|
|
920
|
+
parts.push(part);
|
|
859
921
|
}
|
|
860
922
|
}
|
|
861
923
|
if (parts.length > 0) out.push({ role: "model", parts });
|
|
@@ -893,6 +955,7 @@ async function* parseGoogleStream(body, fallbackModel) {
|
|
|
893
955
|
let usage = { input: 0, output: 0 };
|
|
894
956
|
let stopReason = "end_turn";
|
|
895
957
|
let started = false;
|
|
958
|
+
let sawFunctionCall = false;
|
|
896
959
|
for await (const msg of parseSSE(body)) {
|
|
897
960
|
if (!msg.data || msg.data === "[DONE]") continue;
|
|
898
961
|
const parsed = safeParse(msg.data);
|
|
@@ -908,12 +971,15 @@ async function* parseGoogleStream(body, fallbackModel) {
|
|
|
908
971
|
if (typeof part.text === "string" && part.text.length > 0) {
|
|
909
972
|
yield { type: "text_delta", text: part.text };
|
|
910
973
|
} else if (part.functionCall) {
|
|
974
|
+
sawFunctionCall = true;
|
|
911
975
|
const id = `${part.functionCall.name}_${Math.random().toString(36).slice(2, 10)}`;
|
|
912
976
|
yield { type: "tool_use_start", id, name: part.functionCall.name };
|
|
977
|
+
const providerMeta = typeof part.thoughtSignature === "string" ? { "google.thoughtSignature": part.thoughtSignature } : void 0;
|
|
913
978
|
yield {
|
|
914
979
|
type: "tool_use_stop",
|
|
915
980
|
id,
|
|
916
|
-
input: part.functionCall.args ?? {}
|
|
981
|
+
input: part.functionCall.args ?? {},
|
|
982
|
+
...providerMeta ? { providerMeta } : {}
|
|
917
983
|
};
|
|
918
984
|
}
|
|
919
985
|
}
|
|
@@ -930,8 +996,657 @@ async function* parseGoogleStream(body, fallbackModel) {
|
|
|
930
996
|
}
|
|
931
997
|
}
|
|
932
998
|
if (started) {
|
|
933
|
-
|
|
999
|
+
const finalStop = sawFunctionCall ? "tool_use" : stopReason;
|
|
1000
|
+
yield { type: "message_stop", stopReason: finalStop, usage };
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
|
|
1004
|
+
// src/wire-format.ts
|
|
1005
|
+
var WireFormatProvider = class extends WireAdapter {
|
|
1006
|
+
id;
|
|
1007
|
+
capabilities;
|
|
1008
|
+
cfg;
|
|
1009
|
+
constructor(cfg, opts) {
|
|
1010
|
+
super(opts.apiKey, opts.baseUrl ?? cfg.defaultBaseUrl, opts.fetchImpl);
|
|
1011
|
+
this.id = cfg.id;
|
|
1012
|
+
this.capabilities = cfg.capabilities;
|
|
1013
|
+
this.cfg = cfg;
|
|
1014
|
+
}
|
|
1015
|
+
buildUrl(req) {
|
|
1016
|
+
return this.cfg.buildUrl(this.baseUrl, req);
|
|
1017
|
+
}
|
|
1018
|
+
buildHeaders(req) {
|
|
1019
|
+
return {
|
|
1020
|
+
...super.buildHeaders(req),
|
|
1021
|
+
...this.cfg.buildHeaders(this.apiKey, req)
|
|
1022
|
+
};
|
|
1023
|
+
}
|
|
1024
|
+
buildBody(req) {
|
|
1025
|
+
return this.cfg.buildBody(req);
|
|
1026
|
+
}
|
|
1027
|
+
parseStream(body, fallbackModel) {
|
|
1028
|
+
return this.runStream(body, fallbackModel);
|
|
1029
|
+
}
|
|
1030
|
+
translateError(status, body) {
|
|
1031
|
+
return this.cfg.normalizeError ? this.cfg.normalizeError(status, body) : parseProviderHttpError(this.id, status, body);
|
|
1032
|
+
}
|
|
1033
|
+
async *runStream(body, fallbackModel) {
|
|
1034
|
+
const state = this.cfg.createStreamState(fallbackModel);
|
|
1035
|
+
for await (const msg of parseSSE(body)) {
|
|
1036
|
+
for (const ev of this.cfg.parseStreamEvent(msg, state)) {
|
|
1037
|
+
yield ev;
|
|
1038
|
+
}
|
|
1039
|
+
}
|
|
1040
|
+
if (this.cfg.finalizeStream) {
|
|
1041
|
+
for (const ev of this.cfg.finalizeStream(state)) {
|
|
1042
|
+
yield ev;
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
};
|
|
1047
|
+
function defineWireFormat(cfg) {
|
|
1048
|
+
return cfg;
|
|
1049
|
+
}
|
|
1050
|
+
function createWireFormatFactory(cfg, opts = {}) {
|
|
1051
|
+
return {
|
|
1052
|
+
type: cfg.id,
|
|
1053
|
+
family: cfg.family,
|
|
1054
|
+
create: (rawCfg) => {
|
|
1055
|
+
const c = rawCfg;
|
|
1056
|
+
const apiKey = opts.apiKey ?? c.apiKey;
|
|
1057
|
+
if (!apiKey) {
|
|
1058
|
+
throw new Error(`Provider "${cfg.id}" requires an apiKey.`);
|
|
1059
|
+
}
|
|
1060
|
+
return new WireFormatProvider(cfg, {
|
|
1061
|
+
apiKey,
|
|
1062
|
+
baseUrl: opts.baseUrl ?? c.baseUrl
|
|
1063
|
+
});
|
|
1064
|
+
}
|
|
1065
|
+
};
|
|
1066
|
+
}
|
|
1067
|
+
var mistralWireFormat = defineWireFormat({
|
|
1068
|
+
id: "mistral",
|
|
1069
|
+
family: "openai-compatible",
|
|
1070
|
+
capabilities: {
|
|
1071
|
+
tools: true,
|
|
1072
|
+
parallelTools: true,
|
|
1073
|
+
vision: false,
|
|
1074
|
+
streaming: true,
|
|
1075
|
+
promptCache: false,
|
|
1076
|
+
systemPrompt: true,
|
|
1077
|
+
jsonMode: true,
|
|
1078
|
+
maxContext: 128e3,
|
|
1079
|
+
cacheControl: "none"
|
|
1080
|
+
},
|
|
1081
|
+
defaultBaseUrl: "https://api.mistral.ai/v1",
|
|
1082
|
+
buildUrl: (base) => `${base.replace(/\/+$/, "")}/chat/completions`,
|
|
1083
|
+
buildHeaders: (apiKey) => ({ authorization: `Bearer ${apiKey}` }),
|
|
1084
|
+
buildBody: (req) => ({
|
|
1085
|
+
model: req.model,
|
|
1086
|
+
messages: req.messages,
|
|
1087
|
+
max_tokens: req.maxTokens,
|
|
1088
|
+
temperature: req.temperature,
|
|
1089
|
+
top_p: req.topP,
|
|
1090
|
+
stop: req.stopSequences,
|
|
1091
|
+
stream: true,
|
|
1092
|
+
tools: req.tools
|
|
1093
|
+
}),
|
|
1094
|
+
createStreamState: (fallbackModel) => ({
|
|
1095
|
+
model: fallbackModel,
|
|
1096
|
+
started: false,
|
|
1097
|
+
toolCalls: /* @__PURE__ */ new Map()
|
|
1098
|
+
}),
|
|
1099
|
+
parseStreamEvent: (msg, state) => {
|
|
1100
|
+
if (!msg.data || msg.data === "[DONE]") return [];
|
|
1101
|
+
const parsed = safeParse(msg.data);
|
|
1102
|
+
if (!parsed.ok || !parsed.value) return [];
|
|
1103
|
+
const ev = parsed.value;
|
|
1104
|
+
const out = [];
|
|
1105
|
+
if (ev.model) state.model = ev.model;
|
|
1106
|
+
if (!state.started) {
|
|
1107
|
+
state.started = true;
|
|
1108
|
+
out.push({ type: "message_start", model: state.model });
|
|
1109
|
+
}
|
|
1110
|
+
const choice = ev.choices?.[0];
|
|
1111
|
+
if (choice?.delta?.content) {
|
|
1112
|
+
out.push({ type: "text_delta", text: choice.delta.content });
|
|
1113
|
+
}
|
|
1114
|
+
for (const tc of choice?.delta?.tool_calls ?? []) {
|
|
1115
|
+
let block = state.toolCalls.get(tc.index);
|
|
1116
|
+
if (!block) {
|
|
1117
|
+
block = { id: tc.id, name: tc.function?.name, partial: "", emittedStart: false };
|
|
1118
|
+
state.toolCalls.set(tc.index, block);
|
|
1119
|
+
} else {
|
|
1120
|
+
if (tc.id && !block.id) block.id = tc.id;
|
|
1121
|
+
if (tc.function?.name && !block.name) block.name = tc.function.name;
|
|
1122
|
+
}
|
|
1123
|
+
if (!block.emittedStart && block.id && block.name) {
|
|
1124
|
+
block.emittedStart = true;
|
|
1125
|
+
out.push({ type: "tool_use_start", id: block.id, name: block.name });
|
|
1126
|
+
}
|
|
1127
|
+
const arg = tc.function?.arguments;
|
|
1128
|
+
if (arg && block.id) {
|
|
1129
|
+
block.partial += arg;
|
|
1130
|
+
out.push({ type: "tool_use_input_delta", id: block.id, partial: arg });
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
if (choice?.finish_reason) {
|
|
1134
|
+
for (const block of state.toolCalls.values()) {
|
|
1135
|
+
if (block.id) {
|
|
1136
|
+
const parsedInput = safeParse(block.partial || "{}");
|
|
1137
|
+
out.push({
|
|
1138
|
+
type: "tool_use_stop",
|
|
1139
|
+
id: block.id,
|
|
1140
|
+
input: parsedInput.ok ? parsedInput.value : {}
|
|
1141
|
+
});
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
out.push({
|
|
1145
|
+
type: "message_stop",
|
|
1146
|
+
stopReason: mapStopReason(choice.finish_reason),
|
|
1147
|
+
usage: {
|
|
1148
|
+
input: ev.usage?.prompt_tokens ?? 0,
|
|
1149
|
+
output: ev.usage?.completion_tokens ?? 0
|
|
1150
|
+
}
|
|
1151
|
+
});
|
|
1152
|
+
}
|
|
1153
|
+
return out;
|
|
1154
|
+
}
|
|
1155
|
+
});
|
|
1156
|
+
function mapStopReason(reason) {
|
|
1157
|
+
switch (reason) {
|
|
1158
|
+
case "tool_calls":
|
|
1159
|
+
return "tool_use";
|
|
1160
|
+
case "length":
|
|
1161
|
+
return "max_tokens";
|
|
1162
|
+
case "stop":
|
|
1163
|
+
return "stop_sequence";
|
|
1164
|
+
default:
|
|
1165
|
+
return "end_turn";
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
var DEFAULT_VERSION2 = "2023-06-01";
|
|
1169
|
+
var anthropicWireFormat = defineWireFormat({
|
|
1170
|
+
id: "anthropic",
|
|
1171
|
+
family: "anthropic",
|
|
1172
|
+
capabilities: {
|
|
1173
|
+
tools: true,
|
|
1174
|
+
parallelTools: true,
|
|
1175
|
+
vision: true,
|
|
1176
|
+
streaming: true,
|
|
1177
|
+
promptCache: true,
|
|
1178
|
+
systemPrompt: true,
|
|
1179
|
+
jsonMode: false,
|
|
1180
|
+
maxContext: 2e5,
|
|
1181
|
+
cacheControl: "native"
|
|
1182
|
+
},
|
|
1183
|
+
defaultBaseUrl: "https://api.anthropic.com",
|
|
1184
|
+
buildUrl: (base) => {
|
|
1185
|
+
const b = base.replace(/\/+$/, "");
|
|
1186
|
+
if (/\/v\d+\/messages$/.test(b)) return b;
|
|
1187
|
+
if (/\/v\d+$/.test(b)) return `${b}/messages`;
|
|
1188
|
+
return `${b}/v1/messages`;
|
|
1189
|
+
},
|
|
1190
|
+
buildHeaders: (apiKey) => ({
|
|
1191
|
+
"x-api-key": apiKey,
|
|
1192
|
+
"anthropic-version": DEFAULT_VERSION2
|
|
1193
|
+
}),
|
|
1194
|
+
buildBody: (req) => {
|
|
1195
|
+
const body = {
|
|
1196
|
+
model: req.model,
|
|
1197
|
+
max_tokens: req.maxTokens,
|
|
1198
|
+
messages: req.messages.map((m) => ({
|
|
1199
|
+
role: m.role === "system" ? "user" : m.role,
|
|
1200
|
+
content: m.content
|
|
1201
|
+
})),
|
|
1202
|
+
stream: true
|
|
1203
|
+
};
|
|
1204
|
+
if (req.system && req.system.length > 0) body["system"] = req.system;
|
|
1205
|
+
if (req.tools && req.tools.length > 0) body["tools"] = toolsToAnthropic(req.tools);
|
|
1206
|
+
if (req.temperature !== void 0) body["temperature"] = req.temperature;
|
|
1207
|
+
if (req.topP !== void 0) body["top_p"] = req.topP;
|
|
1208
|
+
if (req.stopSequences) body["stop_sequences"] = req.stopSequences;
|
|
1209
|
+
if (req.toolChoice) body["tool_choice"] = req.toolChoice;
|
|
1210
|
+
return body;
|
|
1211
|
+
},
|
|
1212
|
+
createStreamState: (fallbackModel) => ({
|
|
1213
|
+
model: fallbackModel,
|
|
1214
|
+
usage: { input: 0, output: 0 },
|
|
1215
|
+
stopReason: "end_turn",
|
|
1216
|
+
started: false,
|
|
1217
|
+
blocks: /* @__PURE__ */ new Map()
|
|
1218
|
+
}),
|
|
1219
|
+
parseStreamEvent: (msg, state) => {
|
|
1220
|
+
if (!msg.data || msg.data === "[DONE]") return [];
|
|
1221
|
+
const parsed = safeParse(msg.data);
|
|
1222
|
+
if (!parsed.ok || !parsed.value) return [];
|
|
1223
|
+
const ev = parsed.value;
|
|
1224
|
+
const type = String(ev["type"] ?? msg.event);
|
|
1225
|
+
const out = [];
|
|
1226
|
+
switch (type) {
|
|
1227
|
+
case "message_start": {
|
|
1228
|
+
const message = ev["message"];
|
|
1229
|
+
if (message?.model) state.model = message.model;
|
|
1230
|
+
state.usage = {
|
|
1231
|
+
input: message?.usage?.input_tokens ?? 0,
|
|
1232
|
+
output: 0,
|
|
1233
|
+
cacheRead: message?.usage?.cache_read_input_tokens,
|
|
1234
|
+
cacheWrite: message?.usage?.cache_creation_input_tokens
|
|
1235
|
+
};
|
|
1236
|
+
if (!state.started) {
|
|
1237
|
+
state.started = true;
|
|
1238
|
+
out.push({ type: "message_start", model: state.model });
|
|
1239
|
+
}
|
|
1240
|
+
break;
|
|
1241
|
+
}
|
|
1242
|
+
case "content_block_start": {
|
|
1243
|
+
const index = Number(ev["index"] ?? 0);
|
|
1244
|
+
const cb = ev["content_block"];
|
|
1245
|
+
if (cb?.type === "tool_use") {
|
|
1246
|
+
state.blocks.set(index, { kind: "tool_use", id: cb.id, name: cb.name, partial: "" });
|
|
1247
|
+
if (cb.id && cb.name) {
|
|
1248
|
+
out.push({ type: "tool_use_start", id: cb.id, name: cb.name });
|
|
1249
|
+
}
|
|
1250
|
+
} else if (cb?.type === "text") {
|
|
1251
|
+
state.blocks.set(index, { kind: "text", partial: "" });
|
|
1252
|
+
} else {
|
|
1253
|
+
state.blocks.set(index, { kind: "unknown", partial: "" });
|
|
1254
|
+
}
|
|
1255
|
+
break;
|
|
1256
|
+
}
|
|
1257
|
+
case "content_block_delta": {
|
|
1258
|
+
const index = Number(ev["index"] ?? 0);
|
|
1259
|
+
const delta = ev["delta"];
|
|
1260
|
+
const block = state.blocks.get(index);
|
|
1261
|
+
if (!block || !delta) break;
|
|
1262
|
+
if (delta.type === "text_delta" && typeof delta.text === "string") {
|
|
1263
|
+
out.push({ type: "text_delta", text: delta.text });
|
|
1264
|
+
} else if (delta.type === "input_json_delta" && typeof delta.partial_json === "string") {
|
|
1265
|
+
if (block.id) {
|
|
1266
|
+
block.partial += delta.partial_json;
|
|
1267
|
+
out.push({ type: "tool_use_input_delta", id: block.id, partial: delta.partial_json });
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
break;
|
|
1271
|
+
}
|
|
1272
|
+
case "content_block_stop": {
|
|
1273
|
+
const index = Number(ev["index"] ?? 0);
|
|
1274
|
+
const block = state.blocks.get(index);
|
|
1275
|
+
if (block?.kind === "tool_use" && block.id) {
|
|
1276
|
+
const input = block.partial ? safeParse(block.partial).value ?? {} : {};
|
|
1277
|
+
out.push({ type: "tool_use_stop", id: block.id, input });
|
|
1278
|
+
}
|
|
1279
|
+
break;
|
|
1280
|
+
}
|
|
1281
|
+
case "message_delta": {
|
|
1282
|
+
const delta = ev["delta"];
|
|
1283
|
+
const u = ev["usage"];
|
|
1284
|
+
if (delta?.stop_reason !== void 0) {
|
|
1285
|
+
state.stopReason = normalizeAnthropic(delta.stop_reason);
|
|
1286
|
+
}
|
|
1287
|
+
if (u?.output_tokens !== void 0) {
|
|
1288
|
+
state.usage = { ...state.usage, output: u.output_tokens };
|
|
1289
|
+
}
|
|
1290
|
+
break;
|
|
1291
|
+
}
|
|
1292
|
+
case "message_stop":
|
|
1293
|
+
out.push({ type: "message_stop", stopReason: state.stopReason, usage: state.usage });
|
|
1294
|
+
break;
|
|
1295
|
+
case "error": {
|
|
1296
|
+
const err = ev["error"];
|
|
1297
|
+
throw new ProviderError(
|
|
1298
|
+
err?.message ?? "Anthropic stream error",
|
|
1299
|
+
0,
|
|
1300
|
+
false,
|
|
1301
|
+
"anthropic",
|
|
1302
|
+
{ body: { type: err?.type, message: err?.message } }
|
|
1303
|
+
);
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1306
|
+
return out;
|
|
1307
|
+
},
|
|
1308
|
+
finalizeStream: (state) => {
|
|
1309
|
+
if (state.started) {
|
|
1310
|
+
return [{ type: "message_stop", stopReason: state.stopReason, usage: state.usage }];
|
|
1311
|
+
}
|
|
1312
|
+
return [];
|
|
934
1313
|
}
|
|
1314
|
+
});
|
|
1315
|
+
var openaiWireFormat = defineWireFormat({
|
|
1316
|
+
id: "openai",
|
|
1317
|
+
family: "openai",
|
|
1318
|
+
capabilities: {
|
|
1319
|
+
tools: true,
|
|
1320
|
+
parallelTools: true,
|
|
1321
|
+
vision: true,
|
|
1322
|
+
streaming: true,
|
|
1323
|
+
promptCache: false,
|
|
1324
|
+
systemPrompt: true,
|
|
1325
|
+
jsonMode: true,
|
|
1326
|
+
maxContext: 128e3,
|
|
1327
|
+
cacheControl: "auto"
|
|
1328
|
+
},
|
|
1329
|
+
defaultBaseUrl: "https://api.openai.com/v1",
|
|
1330
|
+
buildUrl: (base) => {
|
|
1331
|
+
const b = base.replace(/\/+$/, "");
|
|
1332
|
+
if (/\/chat\/completions$/.test(b)) return b;
|
|
1333
|
+
if (/\/v\d+(\/[a-z0-9_-]+)*$/i.test(b)) return `${b}/chat/completions`;
|
|
1334
|
+
return `${b}/v1/chat/completions`;
|
|
1335
|
+
},
|
|
1336
|
+
buildHeaders: (apiKey) => ({ authorization: `Bearer ${apiKey}` }),
|
|
1337
|
+
buildBody: (req) => {
|
|
1338
|
+
const body = {
|
|
1339
|
+
model: req.model,
|
|
1340
|
+
messages: messagesToOpenAI(stripCacheControl(req.system), req.messages, {}),
|
|
1341
|
+
max_tokens: req.maxTokens,
|
|
1342
|
+
stream: true,
|
|
1343
|
+
stream_options: { include_usage: true }
|
|
1344
|
+
};
|
|
1345
|
+
if (req.tools && req.tools.length > 0) {
|
|
1346
|
+
body["tools"] = toolsToOpenAI(req.tools);
|
|
1347
|
+
if (req.toolChoice) {
|
|
1348
|
+
if (typeof req.toolChoice === "string") {
|
|
1349
|
+
body["tool_choice"] = req.toolChoice === "required" ? "required" : req.toolChoice;
|
|
1350
|
+
} else {
|
|
1351
|
+
body["tool_choice"] = {
|
|
1352
|
+
type: "function",
|
|
1353
|
+
function: { name: req.toolChoice.name }
|
|
1354
|
+
};
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
if (req.temperature !== void 0) body["temperature"] = req.temperature;
|
|
1359
|
+
if (req.topP !== void 0) body["top_p"] = req.topP;
|
|
1360
|
+
if (req.stopSequences) body["stop"] = req.stopSequences;
|
|
1361
|
+
return body;
|
|
1362
|
+
},
|
|
1363
|
+
createStreamState: (fallbackModel) => ({
|
|
1364
|
+
model: fallbackModel,
|
|
1365
|
+
usage: { input: 0, output: 0 },
|
|
1366
|
+
stopReason: "end_turn",
|
|
1367
|
+
started: false,
|
|
1368
|
+
textOpen: false,
|
|
1369
|
+
toolByIndex: /* @__PURE__ */ new Map(),
|
|
1370
|
+
finalEmitted: false
|
|
1371
|
+
}),
|
|
1372
|
+
parseStreamEvent: (msg, state) => {
|
|
1373
|
+
if (!msg.data || msg.data === "[DONE]") return [];
|
|
1374
|
+
const parsed = safeParse(msg.data);
|
|
1375
|
+
if (!parsed.ok || !parsed.value) return [];
|
|
1376
|
+
const obj = parsed.value;
|
|
1377
|
+
const out = [];
|
|
1378
|
+
if (typeof obj["model"] === "string") state.model = obj["model"];
|
|
1379
|
+
if (!state.started) {
|
|
1380
|
+
state.started = true;
|
|
1381
|
+
out.push({ type: "message_start", model: state.model });
|
|
1382
|
+
}
|
|
1383
|
+
const choices = obj["choices"];
|
|
1384
|
+
const choice = choices?.[0];
|
|
1385
|
+
if (choice?.delta?.content) {
|
|
1386
|
+
if (!state.textOpen) state.textOpen = true;
|
|
1387
|
+
out.push({ type: "text_delta", text: choice.delta.content });
|
|
1388
|
+
}
|
|
1389
|
+
if (choice?.delta?.tool_calls) {
|
|
1390
|
+
for (const tc of choice.delta.tool_calls) {
|
|
1391
|
+
const idx = tc.index ?? 0;
|
|
1392
|
+
let entry = state.toolByIndex.get(idx);
|
|
1393
|
+
if (!entry && tc.id && tc.function?.name) {
|
|
1394
|
+
entry = { id: tc.id, name: tc.function.name, argBuf: "" };
|
|
1395
|
+
state.toolByIndex.set(idx, entry);
|
|
1396
|
+
state.textOpen = false;
|
|
1397
|
+
out.push({ type: "tool_use_start", id: entry.id, name: entry.name });
|
|
1398
|
+
}
|
|
1399
|
+
if (entry && tc.function?.arguments) {
|
|
1400
|
+
entry.argBuf += tc.function.arguments;
|
|
1401
|
+
out.push({
|
|
1402
|
+
type: "tool_use_input_delta",
|
|
1403
|
+
id: entry.id,
|
|
1404
|
+
partial: tc.function.arguments
|
|
1405
|
+
});
|
|
1406
|
+
}
|
|
1407
|
+
}
|
|
1408
|
+
}
|
|
1409
|
+
if (choice?.finish_reason) {
|
|
1410
|
+
state.stopReason = normalizeOpenAI(choice.finish_reason);
|
|
1411
|
+
}
|
|
1412
|
+
const u = obj["usage"];
|
|
1413
|
+
if (u) {
|
|
1414
|
+
state.usage = {
|
|
1415
|
+
input: u.prompt_tokens ?? state.usage.input,
|
|
1416
|
+
output: u.completion_tokens ?? state.usage.output,
|
|
1417
|
+
cacheRead: u.prompt_tokens_details?.cached_tokens ?? state.usage.cacheRead
|
|
1418
|
+
};
|
|
1419
|
+
}
|
|
1420
|
+
return out;
|
|
1421
|
+
},
|
|
1422
|
+
finalizeStream: (state) => {
|
|
1423
|
+
if (state.finalEmitted) return [];
|
|
1424
|
+
state.finalEmitted = true;
|
|
1425
|
+
const out = [];
|
|
1426
|
+
for (const entry of state.toolByIndex.values()) {
|
|
1427
|
+
const input = entry.argBuf ? safeParse(entry.argBuf).value ?? { _raw: entry.argBuf } : {};
|
|
1428
|
+
out.push({ type: "tool_use_stop", id: entry.id, input });
|
|
1429
|
+
}
|
|
1430
|
+
if (state.started) {
|
|
1431
|
+
out.push({ type: "message_stop", stopReason: state.stopReason, usage: state.usage });
|
|
1432
|
+
}
|
|
1433
|
+
return out;
|
|
1434
|
+
}
|
|
1435
|
+
});
|
|
1436
|
+
function stripCacheControl(system) {
|
|
1437
|
+
if (!system) return void 0;
|
|
1438
|
+
return system.map((b) => {
|
|
1439
|
+
const { cache_control: _cc, ...rest } = b;
|
|
1440
|
+
return rest;
|
|
1441
|
+
});
|
|
1442
|
+
}
|
|
1443
|
+
var googleWireFormat = defineWireFormat({
|
|
1444
|
+
id: "google",
|
|
1445
|
+
family: "google",
|
|
1446
|
+
capabilities: {
|
|
1447
|
+
tools: true,
|
|
1448
|
+
parallelTools: true,
|
|
1449
|
+
vision: true,
|
|
1450
|
+
streaming: true,
|
|
1451
|
+
promptCache: false,
|
|
1452
|
+
systemPrompt: true,
|
|
1453
|
+
jsonMode: true,
|
|
1454
|
+
maxContext: 1e6,
|
|
1455
|
+
cacheControl: "none"
|
|
1456
|
+
},
|
|
1457
|
+
defaultBaseUrl: "https://generativelanguage.googleapis.com/v1beta",
|
|
1458
|
+
buildUrl: (base, req) => `${base}/models/${encodeURIComponent(req.model)}:streamGenerateContent?alt=sse`,
|
|
1459
|
+
buildHeaders: (apiKey) => ({ "x-goog-api-key": apiKey }),
|
|
1460
|
+
buildBody: (req) => {
|
|
1461
|
+
const body = {
|
|
1462
|
+
contents: messagesToGemini2(req.messages),
|
|
1463
|
+
generationConfig: buildGenConfig(req)
|
|
1464
|
+
};
|
|
1465
|
+
if (req.system && req.system.length > 0) {
|
|
1466
|
+
body["systemInstruction"] = {
|
|
1467
|
+
parts: req.system.map((b) => ({ text: b.text }))
|
|
1468
|
+
};
|
|
1469
|
+
}
|
|
1470
|
+
if (req.tools && req.tools.length > 0) {
|
|
1471
|
+
body["tools"] = [{ functionDeclarations: toolsToGemini2(req.tools) }];
|
|
1472
|
+
}
|
|
1473
|
+
return body;
|
|
1474
|
+
},
|
|
1475
|
+
createStreamState: (fallbackModel) => ({
|
|
1476
|
+
model: fallbackModel,
|
|
1477
|
+
usage: { input: 0, output: 0 },
|
|
1478
|
+
stopReason: "end_turn",
|
|
1479
|
+
started: false,
|
|
1480
|
+
sawFunctionCall: false,
|
|
1481
|
+
finalEmitted: false
|
|
1482
|
+
}),
|
|
1483
|
+
parseStreamEvent: (msg, state) => {
|
|
1484
|
+
if (!msg.data || msg.data === "[DONE]") return [];
|
|
1485
|
+
const parsed = safeParse(msg.data);
|
|
1486
|
+
if (!parsed.ok || !parsed.value) return [];
|
|
1487
|
+
const obj = parsed.value;
|
|
1488
|
+
const out = [];
|
|
1489
|
+
if (obj.modelVersion) state.model = obj.modelVersion;
|
|
1490
|
+
if (!state.started) {
|
|
1491
|
+
state.started = true;
|
|
1492
|
+
out.push({ type: "message_start", model: state.model });
|
|
1493
|
+
}
|
|
1494
|
+
const candidate = obj.candidates?.[0];
|
|
1495
|
+
for (const part of candidate?.content?.parts ?? []) {
|
|
1496
|
+
if (typeof part.text === "string" && part.text.length > 0) {
|
|
1497
|
+
out.push({ type: "text_delta", text: part.text });
|
|
1498
|
+
} else if (part.functionCall) {
|
|
1499
|
+
state.sawFunctionCall = true;
|
|
1500
|
+
const id = `${part.functionCall.name}_${Math.random().toString(36).slice(2, 10)}`;
|
|
1501
|
+
out.push({ type: "tool_use_start", id, name: part.functionCall.name });
|
|
1502
|
+
const providerMeta = typeof part.thoughtSignature === "string" ? { "google.thoughtSignature": part.thoughtSignature } : void 0;
|
|
1503
|
+
out.push({
|
|
1504
|
+
type: "tool_use_stop",
|
|
1505
|
+
id,
|
|
1506
|
+
input: part.functionCall.args ?? {},
|
|
1507
|
+
...providerMeta ? { providerMeta } : {}
|
|
1508
|
+
});
|
|
1509
|
+
}
|
|
1510
|
+
}
|
|
1511
|
+
if (candidate?.finishReason) {
|
|
1512
|
+
state.stopReason = normalizeGemini(candidate.finishReason);
|
|
1513
|
+
}
|
|
1514
|
+
const u = obj.usageMetadata;
|
|
1515
|
+
if (u) {
|
|
1516
|
+
state.usage = {
|
|
1517
|
+
input: u.promptTokenCount ?? state.usage.input,
|
|
1518
|
+
output: u.candidatesTokenCount ?? state.usage.output,
|
|
1519
|
+
cacheRead: u.cachedContentTokenCount ?? state.usage.cacheRead
|
|
1520
|
+
};
|
|
1521
|
+
}
|
|
1522
|
+
return out;
|
|
1523
|
+
},
|
|
1524
|
+
finalizeStream: (state) => {
|
|
1525
|
+
if (state.finalEmitted || !state.started) return [];
|
|
1526
|
+
state.finalEmitted = true;
|
|
1527
|
+
const finalStop = state.sawFunctionCall ? "tool_use" : state.stopReason;
|
|
1528
|
+
return [{ type: "message_stop", stopReason: finalStop, usage: state.usage }];
|
|
1529
|
+
}
|
|
1530
|
+
});
|
|
1531
|
+
function buildGenConfig(req) {
|
|
1532
|
+
const cfg = { maxOutputTokens: req.maxTokens };
|
|
1533
|
+
if (req.temperature !== void 0) cfg["temperature"] = req.temperature;
|
|
1534
|
+
if (req.topP !== void 0) cfg["topP"] = req.topP;
|
|
1535
|
+
if (req.stopSequences) cfg["stopSequences"] = req.stopSequences;
|
|
1536
|
+
return cfg;
|
|
1537
|
+
}
|
|
1538
|
+
function toolsToGemini2(tools) {
|
|
1539
|
+
return tools.map((t) => ({
|
|
1540
|
+
name: t.name,
|
|
1541
|
+
description: t.description,
|
|
1542
|
+
parameters: sanitizeSchemaForGemini2(t.inputSchema) ?? {
|
|
1543
|
+
type: "object",
|
|
1544
|
+
properties: {}
|
|
1545
|
+
}
|
|
1546
|
+
}));
|
|
1547
|
+
}
|
|
1548
|
+
var GEMINI_ALLOWED_KEYS2 = /* @__PURE__ */ new Set([
|
|
1549
|
+
"type",
|
|
1550
|
+
"format",
|
|
1551
|
+
"description",
|
|
1552
|
+
"nullable",
|
|
1553
|
+
"enum",
|
|
1554
|
+
"items",
|
|
1555
|
+
"properties",
|
|
1556
|
+
"required",
|
|
1557
|
+
"anyOf",
|
|
1558
|
+
"minLength",
|
|
1559
|
+
"maxLength",
|
|
1560
|
+
"pattern",
|
|
1561
|
+
"minimum",
|
|
1562
|
+
"maximum",
|
|
1563
|
+
"minItems",
|
|
1564
|
+
"maxItems",
|
|
1565
|
+
"minProperties",
|
|
1566
|
+
"maxProperties",
|
|
1567
|
+
"propertyOrdering",
|
|
1568
|
+
"title"
|
|
1569
|
+
]);
|
|
1570
|
+
function sanitizeSchemaForGemini2(node) {
|
|
1571
|
+
if (node === null || node === void 0) return void 0;
|
|
1572
|
+
if (Array.isArray(node)) return void 0;
|
|
1573
|
+
if (typeof node !== "object") return void 0;
|
|
1574
|
+
const src = node;
|
|
1575
|
+
const out = {};
|
|
1576
|
+
for (const [k, v] of Object.entries(src)) {
|
|
1577
|
+
if (!GEMINI_ALLOWED_KEYS2.has(k)) continue;
|
|
1578
|
+
if (k === "properties" && v && typeof v === "object") {
|
|
1579
|
+
const props = {};
|
|
1580
|
+
for (const [pname, pschema] of Object.entries(v)) {
|
|
1581
|
+
const cleaned = sanitizeSchemaForGemini2(pschema);
|
|
1582
|
+
if (cleaned) props[pname] = cleaned;
|
|
1583
|
+
}
|
|
1584
|
+
out["properties"] = props;
|
|
1585
|
+
} else if (k === "items") {
|
|
1586
|
+
const cleaned = sanitizeSchemaForGemini2(v);
|
|
1587
|
+
if (cleaned) out["items"] = cleaned;
|
|
1588
|
+
} else if (k === "anyOf" && Array.isArray(v)) {
|
|
1589
|
+
const cleaned = v.map((s) => sanitizeSchemaForGemini2(s)).filter((s) => s !== void 0);
|
|
1590
|
+
if (cleaned.length > 0) out["anyOf"] = cleaned;
|
|
1591
|
+
} else if (k === "required" && Array.isArray(v)) {
|
|
1592
|
+
out["required"] = v.filter((s) => typeof s === "string");
|
|
1593
|
+
} else if (k === "enum" && Array.isArray(v)) {
|
|
1594
|
+
out["enum"] = v;
|
|
1595
|
+
} else {
|
|
1596
|
+
out[k] = v;
|
|
1597
|
+
}
|
|
1598
|
+
}
|
|
1599
|
+
return out;
|
|
1600
|
+
}
|
|
1601
|
+
function messagesToGemini2(messages) {
|
|
1602
|
+
const out = [];
|
|
1603
|
+
for (const m of messages) {
|
|
1604
|
+
if (m.role === "system") continue;
|
|
1605
|
+
const blocks = typeof m.content === "string" ? [{ type: "text", text: m.content }] : m.content;
|
|
1606
|
+
if (m.role === "assistant") {
|
|
1607
|
+
const parts = [];
|
|
1608
|
+
for (const b of blocks) {
|
|
1609
|
+
if (b.type === "text" && b.text) parts.push({ text: b.text });
|
|
1610
|
+
else if (b.type === "tool_use") {
|
|
1611
|
+
const part = {
|
|
1612
|
+
functionCall: { name: b.name, args: b.input }
|
|
1613
|
+
};
|
|
1614
|
+
const sig = b.providerMeta?.["google.thoughtSignature"];
|
|
1615
|
+
if (typeof sig === "string" && sig.length > 0) {
|
|
1616
|
+
part.thoughtSignature = sig;
|
|
1617
|
+
}
|
|
1618
|
+
parts.push(part);
|
|
1619
|
+
}
|
|
1620
|
+
}
|
|
1621
|
+
if (parts.length > 0) out.push({ role: "model", parts });
|
|
1622
|
+
continue;
|
|
1623
|
+
}
|
|
1624
|
+
const textParts = [];
|
|
1625
|
+
const functionParts = [];
|
|
1626
|
+
for (const b of blocks) {
|
|
1627
|
+
if (b.type === "text" && b.text) textParts.push({ text: b.text });
|
|
1628
|
+
else if (b.type === "tool_result") {
|
|
1629
|
+
const responseText = typeof b.content === "string" ? b.content : JSON.stringify(b.content);
|
|
1630
|
+
const fnName = b.name ?? b.tool_use_id;
|
|
1631
|
+
functionParts.push({
|
|
1632
|
+
functionResponse: {
|
|
1633
|
+
name: fnName,
|
|
1634
|
+
response: { content: responseText }
|
|
1635
|
+
}
|
|
1636
|
+
});
|
|
1637
|
+
} else if (b.type === "image" && b.source.type === "base64") {
|
|
1638
|
+
textParts.push({
|
|
1639
|
+
inlineData: {
|
|
1640
|
+
mimeType: b.source.media_type ?? "image/png",
|
|
1641
|
+
data: b.source.data ?? ""
|
|
1642
|
+
}
|
|
1643
|
+
});
|
|
1644
|
+
}
|
|
1645
|
+
}
|
|
1646
|
+
if (textParts.length > 0) out.push({ role: "user", parts: textParts });
|
|
1647
|
+
if (functionParts.length > 0) out.push({ role: "function", parts: functionParts });
|
|
1648
|
+
}
|
|
1649
|
+
return out;
|
|
935
1650
|
}
|
|
936
1651
|
|
|
937
1652
|
// src/capabilities.ts
|
|
@@ -1201,6 +1916,6 @@ function requireKey(cfg) {
|
|
|
1201
1916
|
throw new Error("Provider config requires apiKey (or set the corresponding env var).");
|
|
1202
1917
|
}
|
|
1203
1918
|
|
|
1204
|
-
export { AnthropicProvider, GoogleProvider, OpenAICompatibleProvider, OpenAIProvider, WireAdapter, buildProviderFactoriesFromRegistry, capabilitiesFor, contentFromAnthropic, contentFromOpenAI, makeProviderFromConfig, messagesToOpenAI, normalizeAnthropic, normalizeOpenAI, parseProviderHttpError, toolsToAnthropic, toolsToOpenAI };
|
|
1919
|
+
export { AnthropicProvider, GoogleProvider, OpenAICompatibleProvider, OpenAIProvider, WireAdapter, WireFormatProvider, anthropicWireFormat, buildProviderFactoriesFromRegistry, capabilitiesFor, contentFromAnthropic, contentFromOpenAI, createWireFormatFactory, defineWireFormat, googleWireFormat, makeProviderFromConfig, messagesToOpenAI, mistralWireFormat, normalizeAnthropic, normalizeOpenAI, openaiWireFormat, parseProviderHttpError, toolsToAnthropic, toolsToOpenAI };
|
|
1205
1920
|
//# sourceMappingURL=index.js.map
|
|
1206
1921
|
//# sourceMappingURL=index.js.map
|