@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/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
- parts.push({ functionCall: { name: b.name, args: b.input } });
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
- yield { type: "message_stop", stopReason, usage };
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