@ljoukov/llm 4.0.6 → 4.0.7
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/README.md +4 -3
- package/dist/index.cjs +452 -160
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +452 -160
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -2818,6 +2818,9 @@ function ensureTrailingNewline(value) {
|
|
|
2818
2818
|
return value.endsWith("\n") ? value : `${value}
|
|
2819
2819
|
`;
|
|
2820
2820
|
}
|
|
2821
|
+
function hasNonEmptyText(value) {
|
|
2822
|
+
return typeof value === "string" && value.length > 0;
|
|
2823
|
+
}
|
|
2821
2824
|
function redactDataUrlPayload(value) {
|
|
2822
2825
|
if (!value.toLowerCase().startsWith("data:")) {
|
|
2823
2826
|
return value;
|
|
@@ -3066,6 +3069,25 @@ var AgentLoggingSessionImpl = class {
|
|
|
3066
3069
|
}
|
|
3067
3070
|
this.enqueueLineWrite(timestamped);
|
|
3068
3071
|
}
|
|
3072
|
+
async writeAttachments(baseDir, attachments) {
|
|
3073
|
+
const usedNames = /* @__PURE__ */ new Set();
|
|
3074
|
+
for (const attachment of attachments ?? []) {
|
|
3075
|
+
let filename = normalisePathSegment(attachment.filename);
|
|
3076
|
+
if (!filename.includes(".")) {
|
|
3077
|
+
filename = `${filename}.bin`;
|
|
3078
|
+
}
|
|
3079
|
+
const ext = import_node_path3.default.extname(filename);
|
|
3080
|
+
const base = ext.length > 0 ? filename.slice(0, -ext.length) : filename;
|
|
3081
|
+
let candidate = filename;
|
|
3082
|
+
let duplicateIndex = 2;
|
|
3083
|
+
while (usedNames.has(candidate)) {
|
|
3084
|
+
candidate = `${base}-${duplicateIndex.toString()}${ext}`;
|
|
3085
|
+
duplicateIndex += 1;
|
|
3086
|
+
}
|
|
3087
|
+
usedNames.add(candidate);
|
|
3088
|
+
await (0, import_promises.writeFile)(import_node_path3.default.join(baseDir, candidate), attachment.bytes);
|
|
3089
|
+
}
|
|
3090
|
+
}
|
|
3069
3091
|
startLlmCall(input) {
|
|
3070
3092
|
const callNumber = this.callCounter + 1;
|
|
3071
3093
|
this.callCounter = callNumber;
|
|
@@ -3078,6 +3100,9 @@ var AgentLoggingSessionImpl = class {
|
|
|
3078
3100
|
);
|
|
3079
3101
|
const responsePath = import_node_path3.default.join(baseDir, "response.txt");
|
|
3080
3102
|
const thoughtsPath = import_node_path3.default.join(baseDir, "thoughts.txt");
|
|
3103
|
+
const toolCallPath = import_node_path3.default.join(baseDir, "tool_call.txt");
|
|
3104
|
+
const toolCallResponsePath = import_node_path3.default.join(baseDir, "tool_call_response.txt");
|
|
3105
|
+
const errorPath = import_node_path3.default.join(baseDir, "error.txt");
|
|
3081
3106
|
const responseMetadataPath = import_node_path3.default.join(baseDir, "response.metadata.json");
|
|
3082
3107
|
let chain = this.ensureReady.then(async () => {
|
|
3083
3108
|
await (0, import_promises.mkdir)(baseDir, { recursive: true });
|
|
@@ -3099,22 +3124,13 @@ var AgentLoggingSessionImpl = class {
|
|
|
3099
3124
|
`,
|
|
3100
3125
|
"utf8"
|
|
3101
3126
|
);
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
const base = ext.length > 0 ? filename.slice(0, -ext.length) : filename;
|
|
3110
|
-
let candidate = filename;
|
|
3111
|
-
let duplicateIndex = 2;
|
|
3112
|
-
while (usedNames.has(candidate)) {
|
|
3113
|
-
candidate = `${base}-${duplicateIndex.toString()}${ext}`;
|
|
3114
|
-
duplicateIndex += 1;
|
|
3115
|
-
}
|
|
3116
|
-
usedNames.add(candidate);
|
|
3117
|
-
await (0, import_promises.writeFile)(import_node_path3.default.join(baseDir, candidate), attachment.bytes);
|
|
3127
|
+
await this.writeAttachments(baseDir, input.attachments);
|
|
3128
|
+
if (hasNonEmptyText(input.toolCallResponseText)) {
|
|
3129
|
+
await (0, import_promises.writeFile)(
|
|
3130
|
+
toolCallResponsePath,
|
|
3131
|
+
ensureTrailingNewline(input.toolCallResponseText),
|
|
3132
|
+
"utf8"
|
|
3133
|
+
);
|
|
3118
3134
|
}
|
|
3119
3135
|
}).catch(() => void 0);
|
|
3120
3136
|
this.track(chain);
|
|
@@ -3142,18 +3158,25 @@ var AgentLoggingSessionImpl = class {
|
|
|
3142
3158
|
await (0, import_promises.appendFile)(responsePath, text, "utf8");
|
|
3143
3159
|
});
|
|
3144
3160
|
},
|
|
3145
|
-
complete: (
|
|
3161
|
+
complete: (options) => {
|
|
3146
3162
|
if (closed) {
|
|
3147
3163
|
return;
|
|
3148
3164
|
}
|
|
3149
3165
|
closed = true;
|
|
3150
3166
|
enqueue(async () => {
|
|
3167
|
+
if (hasNonEmptyText(options?.responseText)) {
|
|
3168
|
+
await (0, import_promises.writeFile)(responsePath, options.responseText, "utf8");
|
|
3169
|
+
}
|
|
3170
|
+
if (hasNonEmptyText(options?.toolCallText)) {
|
|
3171
|
+
await (0, import_promises.writeFile)(toolCallPath, ensureTrailingNewline(options.toolCallText), "utf8");
|
|
3172
|
+
}
|
|
3173
|
+
await this.writeAttachments(baseDir, options?.attachments);
|
|
3151
3174
|
const payload = {
|
|
3152
3175
|
capturedAt: toIsoNow(),
|
|
3153
3176
|
status: "completed"
|
|
3154
3177
|
};
|
|
3155
|
-
if (metadata) {
|
|
3156
|
-
const sanitised = sanitiseLogValue(metadata);
|
|
3178
|
+
if (options?.metadata) {
|
|
3179
|
+
const sanitised = sanitiseLogValue(options.metadata);
|
|
3157
3180
|
if (sanitised && typeof sanitised === "object" && !Array.isArray(sanitised)) {
|
|
3158
3181
|
Object.assign(payload, sanitised);
|
|
3159
3182
|
} else if (sanitised !== void 0) {
|
|
@@ -3164,19 +3187,27 @@ var AgentLoggingSessionImpl = class {
|
|
|
3164
3187
|
`, "utf8");
|
|
3165
3188
|
});
|
|
3166
3189
|
},
|
|
3167
|
-
fail: (error,
|
|
3190
|
+
fail: (error, options) => {
|
|
3168
3191
|
if (closed) {
|
|
3169
3192
|
return;
|
|
3170
3193
|
}
|
|
3171
3194
|
closed = true;
|
|
3172
3195
|
enqueue(async () => {
|
|
3196
|
+
if (hasNonEmptyText(options?.responseText)) {
|
|
3197
|
+
await (0, import_promises.writeFile)(responsePath, options.responseText, "utf8");
|
|
3198
|
+
}
|
|
3199
|
+
if (hasNonEmptyText(options?.toolCallText)) {
|
|
3200
|
+
await (0, import_promises.writeFile)(toolCallPath, ensureTrailingNewline(options.toolCallText), "utf8");
|
|
3201
|
+
}
|
|
3202
|
+
await this.writeAttachments(baseDir, options?.attachments);
|
|
3203
|
+
await (0, import_promises.writeFile)(errorPath, ensureTrailingNewline(toErrorMessage(error)), "utf8");
|
|
3173
3204
|
const payload = {
|
|
3174
3205
|
capturedAt: toIsoNow(),
|
|
3175
3206
|
status: "failed",
|
|
3176
3207
|
error: toErrorMessage(error)
|
|
3177
3208
|
};
|
|
3178
|
-
if (metadata) {
|
|
3179
|
-
const sanitised = sanitiseLogValue(metadata);
|
|
3209
|
+
if (options?.metadata) {
|
|
3210
|
+
const sanitised = sanitiseLogValue(options.metadata);
|
|
3180
3211
|
if (sanitised && typeof sanitised === "object" && !Array.isArray(sanitised)) {
|
|
3181
3212
|
Object.assign(payload, sanitised);
|
|
3182
3213
|
} else if (sanitised !== void 0) {
|
|
@@ -5019,7 +5050,10 @@ function resolveAttachmentExtension(mimeType) {
|
|
|
5019
5050
|
}
|
|
5020
5051
|
}
|
|
5021
5052
|
}
|
|
5022
|
-
function
|
|
5053
|
+
function buildLoggedAttachmentFilename(prefix, index, mimeType) {
|
|
5054
|
+
return `${prefix}-${index.toString()}.${resolveAttachmentExtension(mimeType)}`;
|
|
5055
|
+
}
|
|
5056
|
+
function decodeDataUrlAttachment(value, options) {
|
|
5023
5057
|
const trimmed = value.trim();
|
|
5024
5058
|
if (!trimmed.toLowerCase().startsWith("data:")) {
|
|
5025
5059
|
return null;
|
|
@@ -5035,7 +5069,7 @@ function decodeDataUrlAttachment(value, basename) {
|
|
|
5035
5069
|
try {
|
|
5036
5070
|
const bytes = isBase64 ? import_node_buffer3.Buffer.from(payload, "base64") : import_node_buffer3.Buffer.from(decodeURIComponent(payload), "utf8");
|
|
5037
5071
|
return {
|
|
5038
|
-
filename:
|
|
5072
|
+
filename: buildLoggedAttachmentFilename(options.prefix, options.index, mimeType),
|
|
5039
5073
|
bytes
|
|
5040
5074
|
};
|
|
5041
5075
|
} catch {
|
|
@@ -5044,10 +5078,10 @@ function decodeDataUrlAttachment(value, basename) {
|
|
|
5044
5078
|
}
|
|
5045
5079
|
function collectPayloadAttachments(value, options) {
|
|
5046
5080
|
if (typeof value === "string") {
|
|
5047
|
-
const attachment = decodeDataUrlAttachment(
|
|
5048
|
-
|
|
5049
|
-
|
|
5050
|
-
);
|
|
5081
|
+
const attachment = decodeDataUrlAttachment(value, {
|
|
5082
|
+
prefix: options.prefix,
|
|
5083
|
+
index: options.counter
|
|
5084
|
+
});
|
|
5051
5085
|
if (attachment) {
|
|
5052
5086
|
options.attachments.push(attachment);
|
|
5053
5087
|
options.counter += 1;
|
|
@@ -5072,7 +5106,7 @@ function collectPayloadAttachments(value, options) {
|
|
|
5072
5106
|
if (typeof record.data === "string" && mimeType) {
|
|
5073
5107
|
try {
|
|
5074
5108
|
options.attachments.push({
|
|
5075
|
-
filename:
|
|
5109
|
+
filename: buildLoggedAttachmentFilename(options.prefix, options.counter, mimeType),
|
|
5076
5110
|
bytes: decodeInlineDataBuffer(record.data)
|
|
5077
5111
|
});
|
|
5078
5112
|
options.counter += 1;
|
|
@@ -5092,27 +5126,166 @@ function serialiseRequestPayloadForLogging(value) {
|
|
|
5092
5126
|
`;
|
|
5093
5127
|
}
|
|
5094
5128
|
}
|
|
5129
|
+
function serialiseLogArtifactText(value) {
|
|
5130
|
+
if (value === null || value === void 0) {
|
|
5131
|
+
return void 0;
|
|
5132
|
+
}
|
|
5133
|
+
if (typeof value === "string") {
|
|
5134
|
+
if (value.length === 0) {
|
|
5135
|
+
return void 0;
|
|
5136
|
+
}
|
|
5137
|
+
return value.endsWith("\n") ? value : `${value}
|
|
5138
|
+
`;
|
|
5139
|
+
}
|
|
5140
|
+
if (Array.isArray(value) && value.length === 0) {
|
|
5141
|
+
return void 0;
|
|
5142
|
+
}
|
|
5143
|
+
if (isPlainRecord(value) && Object.keys(value).length === 0) {
|
|
5144
|
+
return void 0;
|
|
5145
|
+
}
|
|
5146
|
+
try {
|
|
5147
|
+
return `${JSON.stringify(sanitiseLogValue(value), null, 2)}
|
|
5148
|
+
`;
|
|
5149
|
+
} catch {
|
|
5150
|
+
return `${String(value)}
|
|
5151
|
+
`;
|
|
5152
|
+
}
|
|
5153
|
+
}
|
|
5154
|
+
function collectLoggedAttachmentsFromLlmParts(parts, prefix) {
|
|
5155
|
+
const attachments = [];
|
|
5156
|
+
let index = 1;
|
|
5157
|
+
for (const part of parts) {
|
|
5158
|
+
if (part.type !== "inlineData") {
|
|
5159
|
+
continue;
|
|
5160
|
+
}
|
|
5161
|
+
attachments.push({
|
|
5162
|
+
filename: buildLoggedAttachmentFilename(prefix, index, part.mimeType),
|
|
5163
|
+
bytes: decodeInlineDataBuffer(part.data)
|
|
5164
|
+
});
|
|
5165
|
+
index += 1;
|
|
5166
|
+
}
|
|
5167
|
+
return attachments;
|
|
5168
|
+
}
|
|
5169
|
+
function collectLoggedAttachmentsFromGeminiParts(parts, prefix) {
|
|
5170
|
+
return collectLoggedAttachmentsFromLlmParts(convertGooglePartsToLlmParts(parts), prefix);
|
|
5171
|
+
}
|
|
5172
|
+
function extractToolCallResponseTextFromOpenAiInput(input) {
|
|
5173
|
+
if (!Array.isArray(input)) {
|
|
5174
|
+
return void 0;
|
|
5175
|
+
}
|
|
5176
|
+
const responses = input.filter((item) => isPlainRecord(item)).flatMap((item) => {
|
|
5177
|
+
const type = typeof item.type === "string" ? item.type : "";
|
|
5178
|
+
if (type !== "function_call_output" && type !== "custom_tool_call_output") {
|
|
5179
|
+
return [];
|
|
5180
|
+
}
|
|
5181
|
+
return [
|
|
5182
|
+
{
|
|
5183
|
+
type,
|
|
5184
|
+
callId: typeof item.call_id === "string" ? item.call_id : void 0,
|
|
5185
|
+
output: "output" in item ? sanitiseLogValue(item.output) : void 0
|
|
5186
|
+
}
|
|
5187
|
+
];
|
|
5188
|
+
});
|
|
5189
|
+
return serialiseLogArtifactText(responses);
|
|
5190
|
+
}
|
|
5191
|
+
function extractToolCallResponseTextFromFireworksMessages(messages) {
|
|
5192
|
+
if (!Array.isArray(messages)) {
|
|
5193
|
+
return void 0;
|
|
5194
|
+
}
|
|
5195
|
+
const responses = messages.filter((message) => isPlainRecord(message)).flatMap((message) => {
|
|
5196
|
+
if (message.role !== "tool") {
|
|
5197
|
+
return [];
|
|
5198
|
+
}
|
|
5199
|
+
return [
|
|
5200
|
+
{
|
|
5201
|
+
toolCallId: typeof message.tool_call_id === "string" ? message.tool_call_id : void 0,
|
|
5202
|
+
content: sanitiseLogValue(message.content)
|
|
5203
|
+
}
|
|
5204
|
+
];
|
|
5205
|
+
});
|
|
5206
|
+
return serialiseLogArtifactText(responses);
|
|
5207
|
+
}
|
|
5208
|
+
function extractToolCallResponseTextFromGeminiContents(contents) {
|
|
5209
|
+
if (!Array.isArray(contents)) {
|
|
5210
|
+
return void 0;
|
|
5211
|
+
}
|
|
5212
|
+
const responses = [];
|
|
5213
|
+
for (const content of contents) {
|
|
5214
|
+
if (!content || typeof content !== "object") {
|
|
5215
|
+
continue;
|
|
5216
|
+
}
|
|
5217
|
+
const parts = content.parts;
|
|
5218
|
+
if (!Array.isArray(parts)) {
|
|
5219
|
+
continue;
|
|
5220
|
+
}
|
|
5221
|
+
for (const part of parts) {
|
|
5222
|
+
if (!part || typeof part !== "object") {
|
|
5223
|
+
continue;
|
|
5224
|
+
}
|
|
5225
|
+
const functionResponse = part.functionResponse;
|
|
5226
|
+
if (functionResponse) {
|
|
5227
|
+
responses.push(sanitiseLogValue(functionResponse));
|
|
5228
|
+
}
|
|
5229
|
+
}
|
|
5230
|
+
}
|
|
5231
|
+
return serialiseLogArtifactText(responses);
|
|
5232
|
+
}
|
|
5233
|
+
function serialiseOpenAiStyleToolCallsForLogging(calls) {
|
|
5234
|
+
return serialiseLogArtifactText(
|
|
5235
|
+
calls.map((call) => {
|
|
5236
|
+
if (call.kind === "custom") {
|
|
5237
|
+
return {
|
|
5238
|
+
kind: call.kind,
|
|
5239
|
+
name: call.name,
|
|
5240
|
+
callId: call.callId,
|
|
5241
|
+
itemId: call.itemId,
|
|
5242
|
+
input: call.input
|
|
5243
|
+
};
|
|
5244
|
+
}
|
|
5245
|
+
const { value, error } = parseOpenAiToolArguments(call.arguments);
|
|
5246
|
+
return {
|
|
5247
|
+
kind: call.kind,
|
|
5248
|
+
name: call.name,
|
|
5249
|
+
callId: call.callId,
|
|
5250
|
+
itemId: call.itemId,
|
|
5251
|
+
arguments: value,
|
|
5252
|
+
...error ? { parseError: error, rawArguments: call.arguments } : {}
|
|
5253
|
+
};
|
|
5254
|
+
})
|
|
5255
|
+
);
|
|
5256
|
+
}
|
|
5257
|
+
function serialiseGeminiToolCallsForLogging(calls) {
|
|
5258
|
+
return serialiseLogArtifactText(
|
|
5259
|
+
calls.map((call) => ({
|
|
5260
|
+
name: call.name ?? "unknown",
|
|
5261
|
+
callId: typeof call.id === "string" ? call.id : void 0,
|
|
5262
|
+
arguments: sanitiseLogValue(call.args ?? {})
|
|
5263
|
+
}))
|
|
5264
|
+
);
|
|
5265
|
+
}
|
|
5095
5266
|
function startLlmCallLoggerFromContents(options) {
|
|
5096
5267
|
const session = getCurrentAgentLoggingSession();
|
|
5097
5268
|
if (!session) {
|
|
5098
5269
|
return void 0;
|
|
5099
5270
|
}
|
|
5100
5271
|
const attachments = [];
|
|
5272
|
+
let attachmentIndex = 1;
|
|
5101
5273
|
const sections = [];
|
|
5102
5274
|
for (const [messageIndex, message] of options.contents.entries()) {
|
|
5103
5275
|
sections.push(`### message_${(messageIndex + 1).toString()} role=${message.role}`);
|
|
5104
|
-
for (const
|
|
5276
|
+
for (const part of message.parts) {
|
|
5105
5277
|
if (part.type === "text") {
|
|
5106
5278
|
const channel = part.thought === true ? "thought" : "response";
|
|
5107
5279
|
sections.push(`[text:${channel}]`);
|
|
5108
5280
|
sections.push(part.text);
|
|
5109
5281
|
continue;
|
|
5110
5282
|
}
|
|
5111
|
-
const filename =
|
|
5283
|
+
const filename = buildLoggedAttachmentFilename("input", attachmentIndex, part.mimeType);
|
|
5112
5284
|
attachments.push({
|
|
5113
5285
|
filename,
|
|
5114
5286
|
bytes: decodeInlineDataBuffer(part.data)
|
|
5115
5287
|
});
|
|
5288
|
+
attachmentIndex += 1;
|
|
5116
5289
|
sections.push(
|
|
5117
5290
|
`[inlineData] file=${filename} mime=${part.mimeType ?? "application/octet-stream"} bytes=${attachments[attachments.length - 1]?.bytes.byteLength ?? 0}`
|
|
5118
5291
|
);
|
|
@@ -5156,11 +5329,18 @@ function startLlmCallLoggerFromPayload(options) {
|
|
|
5156
5329
|
}
|
|
5157
5330
|
const attachments = [];
|
|
5158
5331
|
collectPayloadAttachments(options.requestPayload, {
|
|
5159
|
-
prefix:
|
|
5332
|
+
prefix: "input",
|
|
5160
5333
|
attachments,
|
|
5161
5334
|
seen: /* @__PURE__ */ new WeakSet(),
|
|
5162
5335
|
counter: 1
|
|
5163
5336
|
});
|
|
5337
|
+
const toolCallResponseText = options.provider === "openai" || options.provider === "chatgpt" ? extractToolCallResponseTextFromOpenAiInput(
|
|
5338
|
+
options.requestPayload.input
|
|
5339
|
+
) : options.provider === "fireworks" ? extractToolCallResponseTextFromFireworksMessages(
|
|
5340
|
+
options.requestPayload.messages
|
|
5341
|
+
) : extractToolCallResponseTextFromGeminiContents(
|
|
5342
|
+
options.requestPayload.contents
|
|
5343
|
+
);
|
|
5164
5344
|
return session.startLlmCall({
|
|
5165
5345
|
provider: options.provider,
|
|
5166
5346
|
modelId: options.modelId,
|
|
@@ -5169,7 +5349,8 @@ function startLlmCallLoggerFromPayload(options) {
|
|
|
5169
5349
|
step: options.step,
|
|
5170
5350
|
...getCurrentToolCallContext() ? { toolContext: getCurrentToolCallContext() } : {}
|
|
5171
5351
|
},
|
|
5172
|
-
attachments
|
|
5352
|
+
attachments,
|
|
5353
|
+
toolCallResponseText
|
|
5173
5354
|
});
|
|
5174
5355
|
}
|
|
5175
5356
|
async function runTextCall(params) {
|
|
@@ -5474,6 +5655,7 @@ async function runTextCall(params) {
|
|
|
5474
5655
|
const mergedParts = mergeConsecutiveTextParts(responseParts);
|
|
5475
5656
|
const content = mergedParts.length > 0 ? { role: responseRole ?? "assistant", parts: mergedParts } : void 0;
|
|
5476
5657
|
const { text, thoughts } = extractTextByChannel(content);
|
|
5658
|
+
const outputAttachments = collectLoggedAttachmentsFromLlmParts(mergedParts, "output");
|
|
5477
5659
|
const costUsd = estimateCallCostUsd({
|
|
5478
5660
|
modelId: modelVersion,
|
|
5479
5661
|
tokens: latestUsage,
|
|
@@ -5484,16 +5666,20 @@ async function runTextCall(params) {
|
|
|
5484
5666
|
queue.push({ type: "usage", usage: latestUsage, costUsd, modelVersion });
|
|
5485
5667
|
}
|
|
5486
5668
|
callLogger?.complete({
|
|
5487
|
-
|
|
5488
|
-
|
|
5489
|
-
|
|
5490
|
-
|
|
5491
|
-
|
|
5492
|
-
|
|
5493
|
-
|
|
5494
|
-
|
|
5495
|
-
|
|
5496
|
-
|
|
5669
|
+
responseText: text,
|
|
5670
|
+
attachments: outputAttachments,
|
|
5671
|
+
metadata: {
|
|
5672
|
+
provider,
|
|
5673
|
+
model: request.model,
|
|
5674
|
+
modelVersion,
|
|
5675
|
+
blocked,
|
|
5676
|
+
costUsd,
|
|
5677
|
+
usage: latestUsage,
|
|
5678
|
+
grounding: grounding ? sanitiseLogValue(grounding) : void 0,
|
|
5679
|
+
responseChars: text.length,
|
|
5680
|
+
thoughtChars: thoughts.length,
|
|
5681
|
+
responseImages
|
|
5682
|
+
}
|
|
5497
5683
|
});
|
|
5498
5684
|
return {
|
|
5499
5685
|
provider,
|
|
@@ -5508,14 +5694,21 @@ async function runTextCall(params) {
|
|
|
5508
5694
|
grounding
|
|
5509
5695
|
};
|
|
5510
5696
|
} catch (error) {
|
|
5697
|
+
const partialParts = mergeConsecutiveTextParts(responseParts);
|
|
5698
|
+
const partialContent = partialParts.length > 0 ? { role: responseRole ?? "assistant", parts: partialParts } : void 0;
|
|
5699
|
+
const { text: partialText } = extractTextByChannel(partialContent);
|
|
5511
5700
|
callLogger?.fail(error, {
|
|
5512
|
-
|
|
5513
|
-
|
|
5514
|
-
|
|
5515
|
-
|
|
5516
|
-
|
|
5517
|
-
|
|
5518
|
-
|
|
5701
|
+
responseText: partialText,
|
|
5702
|
+
attachments: collectLoggedAttachmentsFromLlmParts(partialParts, "output"),
|
|
5703
|
+
metadata: {
|
|
5704
|
+
provider,
|
|
5705
|
+
model: request.model,
|
|
5706
|
+
modelVersion,
|
|
5707
|
+
blocked,
|
|
5708
|
+
usage: latestUsage,
|
|
5709
|
+
partialResponseParts: responseParts.length,
|
|
5710
|
+
responseImages
|
|
5711
|
+
}
|
|
5519
5712
|
});
|
|
5520
5713
|
throw error;
|
|
5521
5714
|
}
|
|
@@ -5982,6 +6175,9 @@ async function runToolLoop(request) {
|
|
|
5982
6175
|
let usageTokens;
|
|
5983
6176
|
let thoughtDeltaEmitted = false;
|
|
5984
6177
|
let blocked = false;
|
|
6178
|
+
let responseText = "";
|
|
6179
|
+
let reasoningSummary = "";
|
|
6180
|
+
let stepToolCallText;
|
|
5985
6181
|
const stepRequestPayload = {
|
|
5986
6182
|
model: providerInfo.model,
|
|
5987
6183
|
input,
|
|
@@ -6074,8 +6270,8 @@ async function runToolLoop(request) {
|
|
|
6074
6270
|
throw new Error(message);
|
|
6075
6271
|
}
|
|
6076
6272
|
usageTokens = extractOpenAiUsageTokens(finalResponse.usage);
|
|
6077
|
-
|
|
6078
|
-
|
|
6273
|
+
responseText = extractOpenAiResponseParts(finalResponse).parts.filter((p) => p.type === "text" && p.thought !== true).map((p) => p.text).join("").trim();
|
|
6274
|
+
reasoningSummary = extractOpenAiReasoningSummary(finalResponse).trim();
|
|
6079
6275
|
if (!thoughtDeltaEmitted && reasoningSummary.length > 0) {
|
|
6080
6276
|
stepCallLogger?.appendThoughtDelta(reasoningSummary);
|
|
6081
6277
|
emitEvent({ type: "delta", channel: "thought", text: reasoningSummary });
|
|
@@ -6091,6 +6287,23 @@ async function runToolLoop(request) {
|
|
|
6091
6287
|
emitEvent({ type: "usage", usage: usageTokens, costUsd: stepCostUsd, modelVersion });
|
|
6092
6288
|
}
|
|
6093
6289
|
const responseToolCalls = extractOpenAiToolCalls(finalResponse.output);
|
|
6290
|
+
stepToolCallText = serialiseOpenAiStyleToolCallsForLogging(
|
|
6291
|
+
responseToolCalls.map(
|
|
6292
|
+
(call) => call.kind === "custom" ? {
|
|
6293
|
+
kind: call.kind,
|
|
6294
|
+
name: call.name,
|
|
6295
|
+
input: call.input,
|
|
6296
|
+
callId: call.call_id,
|
|
6297
|
+
itemId: call.id
|
|
6298
|
+
} : {
|
|
6299
|
+
kind: call.kind,
|
|
6300
|
+
name: call.name,
|
|
6301
|
+
arguments: call.arguments,
|
|
6302
|
+
callId: call.call_id,
|
|
6303
|
+
itemId: call.id
|
|
6304
|
+
}
|
|
6305
|
+
)
|
|
6306
|
+
);
|
|
6094
6307
|
const stepToolCalls = [];
|
|
6095
6308
|
if (responseToolCalls.length === 0) {
|
|
6096
6309
|
const steeringInput2 = steeringInternal?.drainPendingContents() ?? [];
|
|
@@ -6118,17 +6331,20 @@ async function runToolLoop(request) {
|
|
|
6118
6331
|
timing: timing2
|
|
6119
6332
|
});
|
|
6120
6333
|
stepCallLogger?.complete({
|
|
6121
|
-
|
|
6122
|
-
|
|
6123
|
-
|
|
6124
|
-
|
|
6125
|
-
|
|
6126
|
-
|
|
6127
|
-
|
|
6128
|
-
|
|
6129
|
-
|
|
6130
|
-
|
|
6131
|
-
|
|
6334
|
+
responseText,
|
|
6335
|
+
metadata: {
|
|
6336
|
+
provider: "openai",
|
|
6337
|
+
model: request.model,
|
|
6338
|
+
modelVersion,
|
|
6339
|
+
step: turn,
|
|
6340
|
+
usage: usageTokens,
|
|
6341
|
+
costUsd: stepCostUsd,
|
|
6342
|
+
blocked,
|
|
6343
|
+
responseChars: responseText.length,
|
|
6344
|
+
thoughtChars: reasoningSummary.length,
|
|
6345
|
+
toolCalls: 0,
|
|
6346
|
+
finalStep: steeringItems2.length === 0
|
|
6347
|
+
}
|
|
6132
6348
|
});
|
|
6133
6349
|
if (steeringItems2.length === 0) {
|
|
6134
6350
|
return { text: finalText, thoughts: finalThoughts, steps, totalCostUsd };
|
|
@@ -6251,28 +6467,36 @@ async function runToolLoop(request) {
|
|
|
6251
6467
|
const steeringInput = steeringInternal?.drainPendingContents() ?? [];
|
|
6252
6468
|
const steeringItems = steeringInput.length > 0 ? toOpenAiInput(steeringInput) : [];
|
|
6253
6469
|
stepCallLogger?.complete({
|
|
6254
|
-
|
|
6255
|
-
|
|
6256
|
-
|
|
6257
|
-
|
|
6258
|
-
|
|
6259
|
-
|
|
6260
|
-
|
|
6261
|
-
|
|
6262
|
-
|
|
6263
|
-
|
|
6264
|
-
|
|
6470
|
+
responseText,
|
|
6471
|
+
toolCallText: stepToolCallText,
|
|
6472
|
+
metadata: {
|
|
6473
|
+
provider: "openai",
|
|
6474
|
+
model: request.model,
|
|
6475
|
+
modelVersion,
|
|
6476
|
+
step: turn,
|
|
6477
|
+
usage: usageTokens,
|
|
6478
|
+
costUsd: stepCostUsd,
|
|
6479
|
+
blocked,
|
|
6480
|
+
responseChars: responseText.length,
|
|
6481
|
+
thoughtChars: reasoningSummary.length,
|
|
6482
|
+
toolCalls: stepToolCalls.length,
|
|
6483
|
+
finalStep: false
|
|
6484
|
+
}
|
|
6265
6485
|
});
|
|
6266
6486
|
previousResponseId = finalResponse.id;
|
|
6267
6487
|
input = steeringItems.length > 0 ? toolOutputs.concat(steeringItems) : toolOutputs;
|
|
6268
6488
|
} catch (error) {
|
|
6269
6489
|
stepCallLogger?.fail(error, {
|
|
6270
|
-
|
|
6271
|
-
|
|
6272
|
-
|
|
6273
|
-
|
|
6274
|
-
|
|
6275
|
-
|
|
6490
|
+
responseText,
|
|
6491
|
+
toolCallText: stepToolCallText,
|
|
6492
|
+
metadata: {
|
|
6493
|
+
provider: "openai",
|
|
6494
|
+
model: request.model,
|
|
6495
|
+
modelVersion,
|
|
6496
|
+
step: turn,
|
|
6497
|
+
usage: usageTokens,
|
|
6498
|
+
blocked
|
|
6499
|
+
}
|
|
6276
6500
|
});
|
|
6277
6501
|
throw error;
|
|
6278
6502
|
}
|
|
@@ -6298,6 +6522,7 @@ async function runToolLoop(request) {
|
|
|
6298
6522
|
let usageTokens;
|
|
6299
6523
|
let responseText = "";
|
|
6300
6524
|
let reasoningSummaryText = "";
|
|
6525
|
+
let stepToolCallText;
|
|
6301
6526
|
const markFirstModelEvent = () => {
|
|
6302
6527
|
if (firstModelEventAtMs === void 0) {
|
|
6303
6528
|
firstModelEventAtMs = Date.now();
|
|
@@ -6366,6 +6591,23 @@ async function runToolLoop(request) {
|
|
|
6366
6591
|
stepCallLogger?.appendResponseDelta(responseText);
|
|
6367
6592
|
}
|
|
6368
6593
|
const responseToolCalls = response.toolCalls ?? [];
|
|
6594
|
+
stepToolCallText = serialiseOpenAiStyleToolCallsForLogging(
|
|
6595
|
+
responseToolCalls.map(
|
|
6596
|
+
(call) => call.kind === "custom" ? {
|
|
6597
|
+
kind: call.kind,
|
|
6598
|
+
name: call.name,
|
|
6599
|
+
input: call.input,
|
|
6600
|
+
callId: call.callId,
|
|
6601
|
+
itemId: call.id
|
|
6602
|
+
} : {
|
|
6603
|
+
kind: call.kind,
|
|
6604
|
+
name: call.name,
|
|
6605
|
+
arguments: call.arguments,
|
|
6606
|
+
callId: call.callId,
|
|
6607
|
+
itemId: call.id
|
|
6608
|
+
}
|
|
6609
|
+
)
|
|
6610
|
+
);
|
|
6369
6611
|
if (responseToolCalls.length === 0) {
|
|
6370
6612
|
const steeringInput2 = steeringInternal?.drainPendingContents() ?? [];
|
|
6371
6613
|
const steeringItems2 = steeringInput2.length > 0 ? toChatGptInput(steeringInput2).input : [];
|
|
@@ -6391,16 +6633,19 @@ async function runToolLoop(request) {
|
|
|
6391
6633
|
timing: timing2
|
|
6392
6634
|
});
|
|
6393
6635
|
stepCallLogger?.complete({
|
|
6394
|
-
|
|
6395
|
-
|
|
6396
|
-
|
|
6397
|
-
|
|
6398
|
-
|
|
6399
|
-
|
|
6400
|
-
|
|
6401
|
-
|
|
6402
|
-
|
|
6403
|
-
|
|
6636
|
+
responseText,
|
|
6637
|
+
metadata: {
|
|
6638
|
+
provider: "chatgpt",
|
|
6639
|
+
model: request.model,
|
|
6640
|
+
modelVersion,
|
|
6641
|
+
step: turn,
|
|
6642
|
+
usage: usageTokens,
|
|
6643
|
+
costUsd: stepCostUsd,
|
|
6644
|
+
responseChars: responseText.length,
|
|
6645
|
+
thoughtChars: reasoningSummaryText.length,
|
|
6646
|
+
toolCalls: 0,
|
|
6647
|
+
finalStep: steeringItems2.length === 0
|
|
6648
|
+
}
|
|
6404
6649
|
});
|
|
6405
6650
|
if (steeringItems2.length === 0) {
|
|
6406
6651
|
return { text: finalText, thoughts: finalThoughts, steps, totalCostUsd };
|
|
@@ -6533,25 +6778,33 @@ async function runToolLoop(request) {
|
|
|
6533
6778
|
const steeringInput = steeringInternal?.drainPendingContents() ?? [];
|
|
6534
6779
|
const steeringItems = steeringInput.length > 0 ? toChatGptInput(steeringInput).input : [];
|
|
6535
6780
|
stepCallLogger?.complete({
|
|
6536
|
-
|
|
6537
|
-
|
|
6538
|
-
|
|
6539
|
-
|
|
6540
|
-
|
|
6541
|
-
|
|
6542
|
-
|
|
6543
|
-
|
|
6544
|
-
|
|
6545
|
-
|
|
6781
|
+
responseText,
|
|
6782
|
+
toolCallText: stepToolCallText,
|
|
6783
|
+
metadata: {
|
|
6784
|
+
provider: "chatgpt",
|
|
6785
|
+
model: request.model,
|
|
6786
|
+
modelVersion,
|
|
6787
|
+
step: turn,
|
|
6788
|
+
usage: usageTokens,
|
|
6789
|
+
costUsd: stepCostUsd,
|
|
6790
|
+
responseChars: responseText.length,
|
|
6791
|
+
thoughtChars: reasoningSummaryText.length,
|
|
6792
|
+
toolCalls: toolCalls.length,
|
|
6793
|
+
finalStep: false
|
|
6794
|
+
}
|
|
6546
6795
|
});
|
|
6547
6796
|
input = steeringItems.length > 0 ? input.concat(toolOutputs, steeringItems) : input.concat(toolOutputs);
|
|
6548
6797
|
} catch (error) {
|
|
6549
6798
|
stepCallLogger?.fail(error, {
|
|
6550
|
-
|
|
6551
|
-
|
|
6552
|
-
|
|
6553
|
-
|
|
6554
|
-
|
|
6799
|
+
responseText,
|
|
6800
|
+
toolCallText: stepToolCallText,
|
|
6801
|
+
metadata: {
|
|
6802
|
+
provider: "chatgpt",
|
|
6803
|
+
model: request.model,
|
|
6804
|
+
modelVersion,
|
|
6805
|
+
step: turn,
|
|
6806
|
+
usage: usageTokens
|
|
6807
|
+
}
|
|
6555
6808
|
});
|
|
6556
6809
|
throw error;
|
|
6557
6810
|
}
|
|
@@ -6574,6 +6827,7 @@ async function runToolLoop(request) {
|
|
|
6574
6827
|
let usageTokens;
|
|
6575
6828
|
let responseText = "";
|
|
6576
6829
|
let blocked = false;
|
|
6830
|
+
let stepToolCallText;
|
|
6577
6831
|
const stepRequestPayload = {
|
|
6578
6832
|
model: providerInfo.model,
|
|
6579
6833
|
messages,
|
|
@@ -6638,6 +6892,14 @@ async function runToolLoop(request) {
|
|
|
6638
6892
|
});
|
|
6639
6893
|
}
|
|
6640
6894
|
const responseToolCalls = extractFireworksToolCalls(message);
|
|
6895
|
+
stepToolCallText = serialiseOpenAiStyleToolCallsForLogging(
|
|
6896
|
+
responseToolCalls.map((call) => ({
|
|
6897
|
+
kind: "function",
|
|
6898
|
+
name: call.name,
|
|
6899
|
+
arguments: call.arguments,
|
|
6900
|
+
callId: call.id
|
|
6901
|
+
}))
|
|
6902
|
+
);
|
|
6641
6903
|
if (responseToolCalls.length === 0) {
|
|
6642
6904
|
const steeringInput2 = steeringInternal?.drainPendingContents() ?? [];
|
|
6643
6905
|
const steeringMessages = steeringInput2.length > 0 ? toFireworksMessages(steeringInput2) : [];
|
|
@@ -6663,17 +6925,20 @@ async function runToolLoop(request) {
|
|
|
6663
6925
|
timing: timing2
|
|
6664
6926
|
});
|
|
6665
6927
|
stepCallLogger?.complete({
|
|
6666
|
-
|
|
6667
|
-
|
|
6668
|
-
|
|
6669
|
-
|
|
6670
|
-
|
|
6671
|
-
|
|
6672
|
-
|
|
6673
|
-
|
|
6674
|
-
|
|
6675
|
-
|
|
6676
|
-
|
|
6928
|
+
responseText,
|
|
6929
|
+
metadata: {
|
|
6930
|
+
provider: "fireworks",
|
|
6931
|
+
model: request.model,
|
|
6932
|
+
modelVersion,
|
|
6933
|
+
step: turn,
|
|
6934
|
+
usage: usageTokens,
|
|
6935
|
+
costUsd: stepCostUsd,
|
|
6936
|
+
blocked,
|
|
6937
|
+
responseChars: responseText.length,
|
|
6938
|
+
thoughtChars: 0,
|
|
6939
|
+
toolCalls: 0,
|
|
6940
|
+
finalStep: steeringMessages.length === 0
|
|
6941
|
+
}
|
|
6677
6942
|
});
|
|
6678
6943
|
if (steeringMessages.length === 0) {
|
|
6679
6944
|
return { text: finalText, thoughts: finalThoughts, steps, totalCostUsd };
|
|
@@ -6785,17 +7050,21 @@ async function runToolLoop(request) {
|
|
|
6785
7050
|
timing
|
|
6786
7051
|
});
|
|
6787
7052
|
stepCallLogger?.complete({
|
|
6788
|
-
|
|
6789
|
-
|
|
6790
|
-
|
|
6791
|
-
|
|
6792
|
-
|
|
6793
|
-
|
|
6794
|
-
|
|
6795
|
-
|
|
6796
|
-
|
|
6797
|
-
|
|
6798
|
-
|
|
7053
|
+
responseText,
|
|
7054
|
+
toolCallText: stepToolCallText,
|
|
7055
|
+
metadata: {
|
|
7056
|
+
provider: "fireworks",
|
|
7057
|
+
model: request.model,
|
|
7058
|
+
modelVersion,
|
|
7059
|
+
step: turn,
|
|
7060
|
+
usage: usageTokens,
|
|
7061
|
+
costUsd: stepCostUsd,
|
|
7062
|
+
blocked,
|
|
7063
|
+
responseChars: responseText.length,
|
|
7064
|
+
thoughtChars: 0,
|
|
7065
|
+
toolCalls: stepToolCalls.length,
|
|
7066
|
+
finalStep: false
|
|
7067
|
+
}
|
|
6799
7068
|
});
|
|
6800
7069
|
messages.push({
|
|
6801
7070
|
role: "assistant",
|
|
@@ -6809,12 +7078,16 @@ async function runToolLoop(request) {
|
|
|
6809
7078
|
}
|
|
6810
7079
|
} catch (error) {
|
|
6811
7080
|
stepCallLogger?.fail(error, {
|
|
6812
|
-
|
|
6813
|
-
|
|
6814
|
-
|
|
6815
|
-
|
|
6816
|
-
|
|
6817
|
-
|
|
7081
|
+
responseText,
|
|
7082
|
+
toolCallText: stepToolCallText,
|
|
7083
|
+
metadata: {
|
|
7084
|
+
provider: "fireworks",
|
|
7085
|
+
model: request.model,
|
|
7086
|
+
modelVersion,
|
|
7087
|
+
step: turn,
|
|
7088
|
+
usage: usageTokens,
|
|
7089
|
+
blocked
|
|
7090
|
+
}
|
|
6818
7091
|
});
|
|
6819
7092
|
throw error;
|
|
6820
7093
|
}
|
|
@@ -6834,6 +7107,7 @@ async function runToolLoop(request) {
|
|
|
6834
7107
|
let usageTokens;
|
|
6835
7108
|
let responseText = "";
|
|
6836
7109
|
let thoughtsText = "";
|
|
7110
|
+
let stepToolCallText;
|
|
6837
7111
|
const markFirstModelEvent = () => {
|
|
6838
7112
|
if (firstModelEventAtMs === void 0) {
|
|
6839
7113
|
firstModelEventAtMs = Date.now();
|
|
@@ -6954,12 +7228,17 @@ async function runToolLoop(request) {
|
|
|
6954
7228
|
modelVersion = response.modelVersion ?? request.model;
|
|
6955
7229
|
responseText = response.responseText.trim();
|
|
6956
7230
|
thoughtsText = response.thoughtsText.trim();
|
|
7231
|
+
const responseOutputAttachments = collectLoggedAttachmentsFromGeminiParts(
|
|
7232
|
+
response.modelParts,
|
|
7233
|
+
"output"
|
|
7234
|
+
);
|
|
6957
7235
|
const stepCostUsd = estimateCallCostUsd({
|
|
6958
7236
|
modelId: modelVersion,
|
|
6959
7237
|
tokens: usageTokens,
|
|
6960
7238
|
responseImages: 0
|
|
6961
7239
|
});
|
|
6962
7240
|
totalCostUsd += stepCostUsd;
|
|
7241
|
+
stepToolCallText = serialiseGeminiToolCallsForLogging(response.functionCalls);
|
|
6963
7242
|
if (response.functionCalls.length === 0) {
|
|
6964
7243
|
const steeringInput2 = steeringInternal?.drainPendingContents() ?? [];
|
|
6965
7244
|
finalText = responseText;
|
|
@@ -6985,16 +7264,20 @@ async function runToolLoop(request) {
|
|
|
6985
7264
|
timing: timing2
|
|
6986
7265
|
});
|
|
6987
7266
|
stepCallLogger?.complete({
|
|
6988
|
-
|
|
6989
|
-
|
|
6990
|
-
|
|
6991
|
-
|
|
6992
|
-
|
|
6993
|
-
|
|
6994
|
-
|
|
6995
|
-
|
|
6996
|
-
|
|
6997
|
-
|
|
7267
|
+
responseText,
|
|
7268
|
+
attachments: responseOutputAttachments,
|
|
7269
|
+
metadata: {
|
|
7270
|
+
provider: "gemini",
|
|
7271
|
+
model: request.model,
|
|
7272
|
+
modelVersion,
|
|
7273
|
+
step: turn,
|
|
7274
|
+
usage: usageTokens,
|
|
7275
|
+
costUsd: stepCostUsd,
|
|
7276
|
+
responseChars: responseText.length,
|
|
7277
|
+
thoughtChars: thoughtsText.length,
|
|
7278
|
+
toolCalls: 0,
|
|
7279
|
+
finalStep: steeringInput2.length === 0
|
|
7280
|
+
}
|
|
6998
7281
|
});
|
|
6999
7282
|
if (steeringInput2.length === 0) {
|
|
7000
7283
|
return { text: finalText, thoughts: finalThoughts, steps, totalCostUsd };
|
|
@@ -7121,16 +7404,21 @@ async function runToolLoop(request) {
|
|
|
7121
7404
|
timing
|
|
7122
7405
|
});
|
|
7123
7406
|
stepCallLogger?.complete({
|
|
7124
|
-
|
|
7125
|
-
|
|
7126
|
-
|
|
7127
|
-
|
|
7128
|
-
|
|
7129
|
-
|
|
7130
|
-
|
|
7131
|
-
|
|
7132
|
-
|
|
7133
|
-
|
|
7407
|
+
responseText,
|
|
7408
|
+
attachments: responseOutputAttachments,
|
|
7409
|
+
toolCallText: stepToolCallText,
|
|
7410
|
+
metadata: {
|
|
7411
|
+
provider: "gemini",
|
|
7412
|
+
model: request.model,
|
|
7413
|
+
modelVersion,
|
|
7414
|
+
step: turn,
|
|
7415
|
+
usage: usageTokens,
|
|
7416
|
+
costUsd: stepCostUsd,
|
|
7417
|
+
responseChars: responseText.length,
|
|
7418
|
+
thoughtChars: thoughtsText.length,
|
|
7419
|
+
toolCalls: toolCalls.length,
|
|
7420
|
+
finalStep: false
|
|
7421
|
+
}
|
|
7134
7422
|
});
|
|
7135
7423
|
geminiContents.push({ role: "user", parts: responseParts });
|
|
7136
7424
|
const steeringInput = steeringInternal?.drainPendingContents() ?? [];
|
|
@@ -7139,13 +7427,17 @@ async function runToolLoop(request) {
|
|
|
7139
7427
|
}
|
|
7140
7428
|
} catch (error) {
|
|
7141
7429
|
stepCallLogger?.fail(error, {
|
|
7142
|
-
|
|
7143
|
-
|
|
7144
|
-
|
|
7145
|
-
|
|
7146
|
-
|
|
7147
|
-
|
|
7148
|
-
|
|
7430
|
+
responseText,
|
|
7431
|
+
toolCallText: stepToolCallText,
|
|
7432
|
+
metadata: {
|
|
7433
|
+
provider: "gemini",
|
|
7434
|
+
model: request.model,
|
|
7435
|
+
modelVersion,
|
|
7436
|
+
step: turn,
|
|
7437
|
+
usage: usageTokens,
|
|
7438
|
+
responseChars: responseText.length,
|
|
7439
|
+
thoughtChars: thoughtsText.length
|
|
7440
|
+
}
|
|
7149
7441
|
});
|
|
7150
7442
|
throw error;
|
|
7151
7443
|
}
|