@tanstack/openai-base 0.10.16 → 0.11.1
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/esm/adapters/chat-completions-text.js +23 -2
- package/dist/esm/adapters/chat-completions-text.js.map +1 -1
- package/dist/esm/adapters/responses-text.d.ts +6 -1
- package/dist/esm/adapters/responses-text.js +110 -5
- package/dist/esm/adapters/responses-text.js.map +1 -1
- package/dist/esm/adapters/responses-user-tools.d.ts +42 -0
- package/dist/esm/adapters/responses-user-tools.js +241 -0
- package/dist/esm/adapters/responses-user-tools.js.map +1 -0
- package/package.json +3 -3
- package/src/adapters/chat-completions-text.ts +53 -2
- package/src/adapters/responses-text.ts +197 -11
- package/src/adapters/responses-user-tools.ts +355 -0
|
@@ -3,7 +3,8 @@ import { buildResponsesUsage } from "../usage.js";
|
|
|
3
3
|
import { extractRequestOptions } from "../utils/request-options.js";
|
|
4
4
|
import { createToolInputNormalizer } from "../utils/tool-input-normalizer.js";
|
|
5
5
|
import { convertToolsToResponsesFormat } from "./responses-tool-converter.js";
|
|
6
|
-
import {
|
|
6
|
+
import { hostedShellCallIds, readUserExecutedCall, userToolRequestItem, userToolResultItem } from "./responses-user-tools.js";
|
|
7
|
+
import { EventType, fileReferenceFor, isFileSource, normalizeSystemPrompts, unsupportedFileSourceError } from "@tanstack/ai";
|
|
7
8
|
import { toRunErrorPayload, toRunErrorRawEvent } from "@tanstack/ai/adapter-internals";
|
|
8
9
|
import { BaseTextAdapter } from "@tanstack/ai/adapters";
|
|
9
10
|
import { generateId } from "@tanstack/ai-utils";
|
|
@@ -639,6 +640,46 @@ var OpenAIBaseResponsesTextAdapter = class extends BaseTextAdapter {
|
|
|
639
640
|
hasClosedReasoning = false;
|
|
640
641
|
accumulatedReasoning = "";
|
|
641
642
|
};
|
|
643
|
+
const userToolChunks = (item, outputIndex, bareShell) => {
|
|
644
|
+
const call = readUserExecutedCall(item, { bareShell });
|
|
645
|
+
if (!call || toolCallMetadata.get(call.callId)?.ended) return [];
|
|
646
|
+
const tracked = toolCallMetadata.get(call.callId) ?? {
|
|
647
|
+
callId: call.callId,
|
|
648
|
+
index: outputIndex,
|
|
649
|
+
name: call.name,
|
|
650
|
+
started: false
|
|
651
|
+
};
|
|
652
|
+
toolCallMetadata.set(call.callId, tracked);
|
|
653
|
+
tracked.started = true;
|
|
654
|
+
tracked.ended = true;
|
|
655
|
+
tracked.name = call.name;
|
|
656
|
+
const timestamp = Date.now();
|
|
657
|
+
const modelName = model || options.model;
|
|
658
|
+
const metadata = {
|
|
659
|
+
openaiUserTool: call.name,
|
|
660
|
+
...call.itemId ? { itemId: call.itemId } : {},
|
|
661
|
+
...call.maxOutputLength !== void 0 ? { maxOutputLength: call.maxOutputLength } : {}
|
|
662
|
+
};
|
|
663
|
+
return [{
|
|
664
|
+
type: EventType.TOOL_CALL_START,
|
|
665
|
+
toolCallId: call.callId,
|
|
666
|
+
toolCallName: call.name,
|
|
667
|
+
toolName: call.name,
|
|
668
|
+
parentMessageId: aguiState.messageId,
|
|
669
|
+
model: modelName,
|
|
670
|
+
timestamp,
|
|
671
|
+
index: outputIndex,
|
|
672
|
+
metadata
|
|
673
|
+
}, {
|
|
674
|
+
type: EventType.TOOL_CALL_END,
|
|
675
|
+
toolCallId: call.callId,
|
|
676
|
+
toolCallName: call.name,
|
|
677
|
+
toolName: call.name,
|
|
678
|
+
model: modelName,
|
|
679
|
+
timestamp,
|
|
680
|
+
input: call.input
|
|
681
|
+
}];
|
|
682
|
+
};
|
|
642
683
|
const emitReasoningDelta = function* (text) {
|
|
643
684
|
if (!text) return;
|
|
644
685
|
yield* openReasoning();
|
|
@@ -850,6 +891,7 @@ var OpenAIBaseResponsesTextAdapter = class extends BaseTextAdapter {
|
|
|
850
891
|
metadata.started = true;
|
|
851
892
|
}
|
|
852
893
|
}
|
|
894
|
+
yield* userToolChunks(item, chunk.output_index, false);
|
|
853
895
|
}
|
|
854
896
|
if (chunk.type === "response.function_call_arguments.delta" && chunk.delta) {
|
|
855
897
|
const metadata = toolCallMetadata.get(chunk.item_id);
|
|
@@ -973,6 +1015,7 @@ var OpenAIBaseResponsesTextAdapter = class extends BaseTextAdapter {
|
|
|
973
1015
|
metadata.pendingArguments = void 0;
|
|
974
1016
|
}
|
|
975
1017
|
}
|
|
1018
|
+
yield* userToolChunks(item, chunk.output_index, false);
|
|
976
1019
|
}
|
|
977
1020
|
if (chunk.type === "response.completed") {
|
|
978
1021
|
const completedText = chunk.response.output.flatMap((item) => item.type === "message" ? item.content : []).filter((part) => part.type === "output_text").map((part) => part.text).join("");
|
|
@@ -1012,11 +1055,11 @@ var OpenAIBaseResponsesTextAdapter = class extends BaseTextAdapter {
|
|
|
1012
1055
|
};
|
|
1013
1056
|
else if (!closedReasoningStepId) yield* openReasoning();
|
|
1014
1057
|
}
|
|
1015
|
-
for (const item of chunk.response.output) {
|
|
1058
|
+
for (const [outputIndex, item] of chunk.response.output.entries()) {
|
|
1016
1059
|
if (item.type !== "function_call" || !item.id) continue;
|
|
1017
1060
|
const metadata = toolCallMetadata.get(item.id) ?? {
|
|
1018
1061
|
callId: item.call_id || item.id,
|
|
1019
|
-
index:
|
|
1062
|
+
index: outputIndex,
|
|
1020
1063
|
name: item.name || "",
|
|
1021
1064
|
started: false
|
|
1022
1065
|
};
|
|
@@ -1070,6 +1113,11 @@ var OpenAIBaseResponsesTextAdapter = class extends BaseTextAdapter {
|
|
|
1070
1113
|
metadata.pendingArguments = void 0;
|
|
1071
1114
|
}
|
|
1072
1115
|
}
|
|
1116
|
+
const shellOutputs = hostedShellCallIds(chunk.response.output);
|
|
1117
|
+
for (const [outputIndex, item] of chunk.response.output.entries()) {
|
|
1118
|
+
if (isRecord(item) && item.type === "shell_call" && typeof item.call_id === "string" && shellOutputs.has(item.call_id)) continue;
|
|
1119
|
+
yield* userToolChunks(item, outputIndex, true);
|
|
1120
|
+
}
|
|
1073
1121
|
yield* closeReasoning();
|
|
1074
1122
|
if (hasEmittedTextMessageStart) {
|
|
1075
1123
|
yield {
|
|
@@ -1080,7 +1128,12 @@ var OpenAIBaseResponsesTextAdapter = class extends BaseTextAdapter {
|
|
|
1080
1128
|
};
|
|
1081
1129
|
hasEmittedTextMessageStart = false;
|
|
1082
1130
|
}
|
|
1083
|
-
const hasFunctionCalls = chunk.response.output.some((item) =>
|
|
1131
|
+
const hasFunctionCalls = chunk.response.output.some((item) => {
|
|
1132
|
+
if (!isRecord(item)) return false;
|
|
1133
|
+
if (item.type === "function_call") return true;
|
|
1134
|
+
if (item.type === "shell_call" && typeof item.call_id === "string" && shellOutputs.has(item.call_id)) return false;
|
|
1135
|
+
return readUserExecutedCall(item, { bareShell: true }) !== null;
|
|
1136
|
+
});
|
|
1084
1137
|
const incompleteReason = chunk.response.incomplete_details?.reason;
|
|
1085
1138
|
const finishReason = hasFunctionCalls ? "tool_calls" : incompleteReason === "max_output_tokens" ? "length" : incompleteReason === "content_filter" ? "content_filter" : "stop";
|
|
1086
1139
|
yield {
|
|
@@ -1198,8 +1251,16 @@ var OpenAIBaseResponsesTextAdapter = class extends BaseTextAdapter {
|
|
|
1198
1251
|
*/
|
|
1199
1252
|
convertMessagesToInput(messages) {
|
|
1200
1253
|
const result = [];
|
|
1254
|
+
const seenReasoningIds = /* @__PURE__ */ new Set();
|
|
1255
|
+
const userToolCalls = /* @__PURE__ */ new Map();
|
|
1201
1256
|
for (const message of messages) {
|
|
1202
1257
|
if (message.role === "tool") {
|
|
1258
|
+
const owner = message.toolCallId ? userToolCalls.get(message.toolCallId) : void 0;
|
|
1259
|
+
const userOutput = owner ? userToolResultItem(owner, message.content) : null;
|
|
1260
|
+
if (userOutput) {
|
|
1261
|
+
result.push(userOutput);
|
|
1262
|
+
continue;
|
|
1263
|
+
}
|
|
1203
1264
|
const toolContent = message.content;
|
|
1204
1265
|
const output = Array.isArray(toolContent) ? toolContent.map((part) => this.convertContentPartToInput(part)) : typeof toolContent === "string" ? toolContent : JSON.stringify(toolContent);
|
|
1205
1266
|
result.push({
|
|
@@ -1210,10 +1271,16 @@ var OpenAIBaseResponsesTextAdapter = class extends BaseTextAdapter {
|
|
|
1210
1271
|
continue;
|
|
1211
1272
|
}
|
|
1212
1273
|
if (message.role === "assistant") {
|
|
1274
|
+
let reasoningCandidates = 0;
|
|
1275
|
+
let emittedReasoning = 0;
|
|
1213
1276
|
if (message.thinking) for (const thinking of message.thinking) {
|
|
1214
1277
|
if (!thinking.signature) continue;
|
|
1215
1278
|
const packed = unpackResponsesReasoningSignature(thinking.signature);
|
|
1216
1279
|
if (!packed?.id) continue;
|
|
1280
|
+
reasoningCandidates++;
|
|
1281
|
+
if (seenReasoningIds.has(packed.id)) continue;
|
|
1282
|
+
seenReasoningIds.add(packed.id);
|
|
1283
|
+
emittedReasoning++;
|
|
1217
1284
|
result.push({
|
|
1218
1285
|
type: "reasoning",
|
|
1219
1286
|
id: packed.id,
|
|
@@ -1224,13 +1291,28 @@ var OpenAIBaseResponsesTextAdapter = class extends BaseTextAdapter {
|
|
|
1224
1291
|
}] : []
|
|
1225
1292
|
});
|
|
1226
1293
|
}
|
|
1294
|
+
const canPairReasoning = reasoningCandidates === 0 || reasoningCandidates === 1 && emittedReasoning === 1;
|
|
1227
1295
|
if (message.toolCalls && message.toolCalls.length > 0) for (const toolCall of message.toolCalls) {
|
|
1228
1296
|
const argumentsString = typeof toolCall.function.arguments === "string" ? toolCall.function.arguments : JSON.stringify(toolCall.function.arguments);
|
|
1297
|
+
const replayCall = {
|
|
1298
|
+
id: toolCall.id,
|
|
1299
|
+
function: {
|
|
1300
|
+
name: toolCall.function.name,
|
|
1301
|
+
arguments: argumentsString
|
|
1302
|
+
},
|
|
1303
|
+
...toolCall.metadata !== void 0 ? { metadata: toolCall.metadata } : {}
|
|
1304
|
+
};
|
|
1305
|
+
const userItem = userToolRequestItem(replayCall);
|
|
1306
|
+
if (userItem) {
|
|
1307
|
+
userToolCalls.set(toolCall.id, replayCall);
|
|
1308
|
+
result.push(userItem);
|
|
1309
|
+
continue;
|
|
1310
|
+
}
|
|
1229
1311
|
const itemId = toolCall.metadata?.itemId;
|
|
1230
1312
|
result.push({
|
|
1231
1313
|
type: "function_call",
|
|
1232
1314
|
call_id: toolCall.id,
|
|
1233
|
-
...itemId && { id: itemId },
|
|
1315
|
+
...itemId && canPairReasoning && { id: itemId },
|
|
1234
1316
|
name: toolCall.function.name,
|
|
1235
1317
|
arguments: argumentsString
|
|
1236
1318
|
});
|
|
@@ -1270,6 +1352,14 @@ var OpenAIBaseResponsesTextAdapter = class extends BaseTextAdapter {
|
|
|
1270
1352
|
};
|
|
1271
1353
|
case "image": {
|
|
1272
1354
|
const imageMetadata = part.metadata;
|
|
1355
|
+
if (isFileSource(part.source)) {
|
|
1356
|
+
if (this.supportsFileSources !== true) throw unsupportedFileSourceError(this.name);
|
|
1357
|
+
return {
|
|
1358
|
+
type: "input_image",
|
|
1359
|
+
file_id: fileReferenceFor(part.source, this.name),
|
|
1360
|
+
detail: imageMetadata?.detail || "auto"
|
|
1361
|
+
};
|
|
1362
|
+
}
|
|
1273
1363
|
if (part.source.type === "url") return {
|
|
1274
1364
|
type: "input_image",
|
|
1275
1365
|
image_url: part.source.value,
|
|
@@ -1284,6 +1374,13 @@ var OpenAIBaseResponsesTextAdapter = class extends BaseTextAdapter {
|
|
|
1284
1374
|
};
|
|
1285
1375
|
}
|
|
1286
1376
|
case "audio": {
|
|
1377
|
+
if (isFileSource(part.source)) {
|
|
1378
|
+
if (this.supportsFileSources !== true) throw unsupportedFileSourceError(this.name);
|
|
1379
|
+
return {
|
|
1380
|
+
type: "input_file",
|
|
1381
|
+
file_id: fileReferenceFor(part.source, this.name)
|
|
1382
|
+
};
|
|
1383
|
+
}
|
|
1287
1384
|
if (part.source.type === "url") return {
|
|
1288
1385
|
type: "input_file",
|
|
1289
1386
|
file_url: part.source.value
|
|
@@ -1298,6 +1395,14 @@ var OpenAIBaseResponsesTextAdapter = class extends BaseTextAdapter {
|
|
|
1298
1395
|
case "document": {
|
|
1299
1396
|
const documentMetadata = part.metadata;
|
|
1300
1397
|
const documentDetail = documentMetadata?.detail !== void 0 ? { detail: documentMetadata.detail } : {};
|
|
1398
|
+
if (isFileSource(part.source)) {
|
|
1399
|
+
if (this.supportsFileSources !== true) throw unsupportedFileSourceError(this.name);
|
|
1400
|
+
return {
|
|
1401
|
+
type: "input_file",
|
|
1402
|
+
file_id: fileReferenceFor(part.source, this.name),
|
|
1403
|
+
...documentDetail
|
|
1404
|
+
};
|
|
1405
|
+
}
|
|
1301
1406
|
if (part.source.type === "url") return {
|
|
1302
1407
|
type: "input_file",
|
|
1303
1408
|
file_url: part.source.value,
|