@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.js
CHANGED
|
@@ -2706,6 +2706,9 @@ function ensureTrailingNewline(value) {
|
|
|
2706
2706
|
return value.endsWith("\n") ? value : `${value}
|
|
2707
2707
|
`;
|
|
2708
2708
|
}
|
|
2709
|
+
function hasNonEmptyText(value) {
|
|
2710
|
+
return typeof value === "string" && value.length > 0;
|
|
2711
|
+
}
|
|
2709
2712
|
function redactDataUrlPayload(value) {
|
|
2710
2713
|
if (!value.toLowerCase().startsWith("data:")) {
|
|
2711
2714
|
return value;
|
|
@@ -2954,6 +2957,25 @@ var AgentLoggingSessionImpl = class {
|
|
|
2954
2957
|
}
|
|
2955
2958
|
this.enqueueLineWrite(timestamped);
|
|
2956
2959
|
}
|
|
2960
|
+
async writeAttachments(baseDir, attachments) {
|
|
2961
|
+
const usedNames = /* @__PURE__ */ new Set();
|
|
2962
|
+
for (const attachment of attachments ?? []) {
|
|
2963
|
+
let filename = normalisePathSegment(attachment.filename);
|
|
2964
|
+
if (!filename.includes(".")) {
|
|
2965
|
+
filename = `${filename}.bin`;
|
|
2966
|
+
}
|
|
2967
|
+
const ext = path3.extname(filename);
|
|
2968
|
+
const base = ext.length > 0 ? filename.slice(0, -ext.length) : filename;
|
|
2969
|
+
let candidate = filename;
|
|
2970
|
+
let duplicateIndex = 2;
|
|
2971
|
+
while (usedNames.has(candidate)) {
|
|
2972
|
+
candidate = `${base}-${duplicateIndex.toString()}${ext}`;
|
|
2973
|
+
duplicateIndex += 1;
|
|
2974
|
+
}
|
|
2975
|
+
usedNames.add(candidate);
|
|
2976
|
+
await writeFile(path3.join(baseDir, candidate), attachment.bytes);
|
|
2977
|
+
}
|
|
2978
|
+
}
|
|
2957
2979
|
startLlmCall(input) {
|
|
2958
2980
|
const callNumber = this.callCounter + 1;
|
|
2959
2981
|
this.callCounter = callNumber;
|
|
@@ -2966,6 +2988,9 @@ var AgentLoggingSessionImpl = class {
|
|
|
2966
2988
|
);
|
|
2967
2989
|
const responsePath = path3.join(baseDir, "response.txt");
|
|
2968
2990
|
const thoughtsPath = path3.join(baseDir, "thoughts.txt");
|
|
2991
|
+
const toolCallPath = path3.join(baseDir, "tool_call.txt");
|
|
2992
|
+
const toolCallResponsePath = path3.join(baseDir, "tool_call_response.txt");
|
|
2993
|
+
const errorPath = path3.join(baseDir, "error.txt");
|
|
2969
2994
|
const responseMetadataPath = path3.join(baseDir, "response.metadata.json");
|
|
2970
2995
|
let chain = this.ensureReady.then(async () => {
|
|
2971
2996
|
await mkdir(baseDir, { recursive: true });
|
|
@@ -2987,22 +3012,13 @@ var AgentLoggingSessionImpl = class {
|
|
|
2987
3012
|
`,
|
|
2988
3013
|
"utf8"
|
|
2989
3014
|
);
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
const base = ext.length > 0 ? filename.slice(0, -ext.length) : filename;
|
|
2998
|
-
let candidate = filename;
|
|
2999
|
-
let duplicateIndex = 2;
|
|
3000
|
-
while (usedNames.has(candidate)) {
|
|
3001
|
-
candidate = `${base}-${duplicateIndex.toString()}${ext}`;
|
|
3002
|
-
duplicateIndex += 1;
|
|
3003
|
-
}
|
|
3004
|
-
usedNames.add(candidate);
|
|
3005
|
-
await writeFile(path3.join(baseDir, candidate), attachment.bytes);
|
|
3015
|
+
await this.writeAttachments(baseDir, input.attachments);
|
|
3016
|
+
if (hasNonEmptyText(input.toolCallResponseText)) {
|
|
3017
|
+
await writeFile(
|
|
3018
|
+
toolCallResponsePath,
|
|
3019
|
+
ensureTrailingNewline(input.toolCallResponseText),
|
|
3020
|
+
"utf8"
|
|
3021
|
+
);
|
|
3006
3022
|
}
|
|
3007
3023
|
}).catch(() => void 0);
|
|
3008
3024
|
this.track(chain);
|
|
@@ -3030,18 +3046,25 @@ var AgentLoggingSessionImpl = class {
|
|
|
3030
3046
|
await appendFile(responsePath, text, "utf8");
|
|
3031
3047
|
});
|
|
3032
3048
|
},
|
|
3033
|
-
complete: (
|
|
3049
|
+
complete: (options) => {
|
|
3034
3050
|
if (closed) {
|
|
3035
3051
|
return;
|
|
3036
3052
|
}
|
|
3037
3053
|
closed = true;
|
|
3038
3054
|
enqueue(async () => {
|
|
3055
|
+
if (hasNonEmptyText(options?.responseText)) {
|
|
3056
|
+
await writeFile(responsePath, options.responseText, "utf8");
|
|
3057
|
+
}
|
|
3058
|
+
if (hasNonEmptyText(options?.toolCallText)) {
|
|
3059
|
+
await writeFile(toolCallPath, ensureTrailingNewline(options.toolCallText), "utf8");
|
|
3060
|
+
}
|
|
3061
|
+
await this.writeAttachments(baseDir, options?.attachments);
|
|
3039
3062
|
const payload = {
|
|
3040
3063
|
capturedAt: toIsoNow(),
|
|
3041
3064
|
status: "completed"
|
|
3042
3065
|
};
|
|
3043
|
-
if (metadata) {
|
|
3044
|
-
const sanitised = sanitiseLogValue(metadata);
|
|
3066
|
+
if (options?.metadata) {
|
|
3067
|
+
const sanitised = sanitiseLogValue(options.metadata);
|
|
3045
3068
|
if (sanitised && typeof sanitised === "object" && !Array.isArray(sanitised)) {
|
|
3046
3069
|
Object.assign(payload, sanitised);
|
|
3047
3070
|
} else if (sanitised !== void 0) {
|
|
@@ -3052,19 +3075,27 @@ var AgentLoggingSessionImpl = class {
|
|
|
3052
3075
|
`, "utf8");
|
|
3053
3076
|
});
|
|
3054
3077
|
},
|
|
3055
|
-
fail: (error,
|
|
3078
|
+
fail: (error, options) => {
|
|
3056
3079
|
if (closed) {
|
|
3057
3080
|
return;
|
|
3058
3081
|
}
|
|
3059
3082
|
closed = true;
|
|
3060
3083
|
enqueue(async () => {
|
|
3084
|
+
if (hasNonEmptyText(options?.responseText)) {
|
|
3085
|
+
await writeFile(responsePath, options.responseText, "utf8");
|
|
3086
|
+
}
|
|
3087
|
+
if (hasNonEmptyText(options?.toolCallText)) {
|
|
3088
|
+
await writeFile(toolCallPath, ensureTrailingNewline(options.toolCallText), "utf8");
|
|
3089
|
+
}
|
|
3090
|
+
await this.writeAttachments(baseDir, options?.attachments);
|
|
3091
|
+
await writeFile(errorPath, ensureTrailingNewline(toErrorMessage(error)), "utf8");
|
|
3061
3092
|
const payload = {
|
|
3062
3093
|
capturedAt: toIsoNow(),
|
|
3063
3094
|
status: "failed",
|
|
3064
3095
|
error: toErrorMessage(error)
|
|
3065
3096
|
};
|
|
3066
|
-
if (metadata) {
|
|
3067
|
-
const sanitised = sanitiseLogValue(metadata);
|
|
3097
|
+
if (options?.metadata) {
|
|
3098
|
+
const sanitised = sanitiseLogValue(options.metadata);
|
|
3068
3099
|
if (sanitised && typeof sanitised === "object" && !Array.isArray(sanitised)) {
|
|
3069
3100
|
Object.assign(payload, sanitised);
|
|
3070
3101
|
} else if (sanitised !== void 0) {
|
|
@@ -4907,7 +4938,10 @@ function resolveAttachmentExtension(mimeType) {
|
|
|
4907
4938
|
}
|
|
4908
4939
|
}
|
|
4909
4940
|
}
|
|
4910
|
-
function
|
|
4941
|
+
function buildLoggedAttachmentFilename(prefix, index, mimeType) {
|
|
4942
|
+
return `${prefix}-${index.toString()}.${resolveAttachmentExtension(mimeType)}`;
|
|
4943
|
+
}
|
|
4944
|
+
function decodeDataUrlAttachment(value, options) {
|
|
4911
4945
|
const trimmed = value.trim();
|
|
4912
4946
|
if (!trimmed.toLowerCase().startsWith("data:")) {
|
|
4913
4947
|
return null;
|
|
@@ -4923,7 +4957,7 @@ function decodeDataUrlAttachment(value, basename) {
|
|
|
4923
4957
|
try {
|
|
4924
4958
|
const bytes = isBase64 ? Buffer4.from(payload, "base64") : Buffer4.from(decodeURIComponent(payload), "utf8");
|
|
4925
4959
|
return {
|
|
4926
|
-
filename:
|
|
4960
|
+
filename: buildLoggedAttachmentFilename(options.prefix, options.index, mimeType),
|
|
4927
4961
|
bytes
|
|
4928
4962
|
};
|
|
4929
4963
|
} catch {
|
|
@@ -4932,10 +4966,10 @@ function decodeDataUrlAttachment(value, basename) {
|
|
|
4932
4966
|
}
|
|
4933
4967
|
function collectPayloadAttachments(value, options) {
|
|
4934
4968
|
if (typeof value === "string") {
|
|
4935
|
-
const attachment = decodeDataUrlAttachment(
|
|
4936
|
-
|
|
4937
|
-
|
|
4938
|
-
);
|
|
4969
|
+
const attachment = decodeDataUrlAttachment(value, {
|
|
4970
|
+
prefix: options.prefix,
|
|
4971
|
+
index: options.counter
|
|
4972
|
+
});
|
|
4939
4973
|
if (attachment) {
|
|
4940
4974
|
options.attachments.push(attachment);
|
|
4941
4975
|
options.counter += 1;
|
|
@@ -4960,7 +4994,7 @@ function collectPayloadAttachments(value, options) {
|
|
|
4960
4994
|
if (typeof record.data === "string" && mimeType) {
|
|
4961
4995
|
try {
|
|
4962
4996
|
options.attachments.push({
|
|
4963
|
-
filename:
|
|
4997
|
+
filename: buildLoggedAttachmentFilename(options.prefix, options.counter, mimeType),
|
|
4964
4998
|
bytes: decodeInlineDataBuffer(record.data)
|
|
4965
4999
|
});
|
|
4966
5000
|
options.counter += 1;
|
|
@@ -4980,27 +5014,166 @@ function serialiseRequestPayloadForLogging(value) {
|
|
|
4980
5014
|
`;
|
|
4981
5015
|
}
|
|
4982
5016
|
}
|
|
5017
|
+
function serialiseLogArtifactText(value) {
|
|
5018
|
+
if (value === null || value === void 0) {
|
|
5019
|
+
return void 0;
|
|
5020
|
+
}
|
|
5021
|
+
if (typeof value === "string") {
|
|
5022
|
+
if (value.length === 0) {
|
|
5023
|
+
return void 0;
|
|
5024
|
+
}
|
|
5025
|
+
return value.endsWith("\n") ? value : `${value}
|
|
5026
|
+
`;
|
|
5027
|
+
}
|
|
5028
|
+
if (Array.isArray(value) && value.length === 0) {
|
|
5029
|
+
return void 0;
|
|
5030
|
+
}
|
|
5031
|
+
if (isPlainRecord(value) && Object.keys(value).length === 0) {
|
|
5032
|
+
return void 0;
|
|
5033
|
+
}
|
|
5034
|
+
try {
|
|
5035
|
+
return `${JSON.stringify(sanitiseLogValue(value), null, 2)}
|
|
5036
|
+
`;
|
|
5037
|
+
} catch {
|
|
5038
|
+
return `${String(value)}
|
|
5039
|
+
`;
|
|
5040
|
+
}
|
|
5041
|
+
}
|
|
5042
|
+
function collectLoggedAttachmentsFromLlmParts(parts, prefix) {
|
|
5043
|
+
const attachments = [];
|
|
5044
|
+
let index = 1;
|
|
5045
|
+
for (const part of parts) {
|
|
5046
|
+
if (part.type !== "inlineData") {
|
|
5047
|
+
continue;
|
|
5048
|
+
}
|
|
5049
|
+
attachments.push({
|
|
5050
|
+
filename: buildLoggedAttachmentFilename(prefix, index, part.mimeType),
|
|
5051
|
+
bytes: decodeInlineDataBuffer(part.data)
|
|
5052
|
+
});
|
|
5053
|
+
index += 1;
|
|
5054
|
+
}
|
|
5055
|
+
return attachments;
|
|
5056
|
+
}
|
|
5057
|
+
function collectLoggedAttachmentsFromGeminiParts(parts, prefix) {
|
|
5058
|
+
return collectLoggedAttachmentsFromLlmParts(convertGooglePartsToLlmParts(parts), prefix);
|
|
5059
|
+
}
|
|
5060
|
+
function extractToolCallResponseTextFromOpenAiInput(input) {
|
|
5061
|
+
if (!Array.isArray(input)) {
|
|
5062
|
+
return void 0;
|
|
5063
|
+
}
|
|
5064
|
+
const responses = input.filter((item) => isPlainRecord(item)).flatMap((item) => {
|
|
5065
|
+
const type = typeof item.type === "string" ? item.type : "";
|
|
5066
|
+
if (type !== "function_call_output" && type !== "custom_tool_call_output") {
|
|
5067
|
+
return [];
|
|
5068
|
+
}
|
|
5069
|
+
return [
|
|
5070
|
+
{
|
|
5071
|
+
type,
|
|
5072
|
+
callId: typeof item.call_id === "string" ? item.call_id : void 0,
|
|
5073
|
+
output: "output" in item ? sanitiseLogValue(item.output) : void 0
|
|
5074
|
+
}
|
|
5075
|
+
];
|
|
5076
|
+
});
|
|
5077
|
+
return serialiseLogArtifactText(responses);
|
|
5078
|
+
}
|
|
5079
|
+
function extractToolCallResponseTextFromFireworksMessages(messages) {
|
|
5080
|
+
if (!Array.isArray(messages)) {
|
|
5081
|
+
return void 0;
|
|
5082
|
+
}
|
|
5083
|
+
const responses = messages.filter((message) => isPlainRecord(message)).flatMap((message) => {
|
|
5084
|
+
if (message.role !== "tool") {
|
|
5085
|
+
return [];
|
|
5086
|
+
}
|
|
5087
|
+
return [
|
|
5088
|
+
{
|
|
5089
|
+
toolCallId: typeof message.tool_call_id === "string" ? message.tool_call_id : void 0,
|
|
5090
|
+
content: sanitiseLogValue(message.content)
|
|
5091
|
+
}
|
|
5092
|
+
];
|
|
5093
|
+
});
|
|
5094
|
+
return serialiseLogArtifactText(responses);
|
|
5095
|
+
}
|
|
5096
|
+
function extractToolCallResponseTextFromGeminiContents(contents) {
|
|
5097
|
+
if (!Array.isArray(contents)) {
|
|
5098
|
+
return void 0;
|
|
5099
|
+
}
|
|
5100
|
+
const responses = [];
|
|
5101
|
+
for (const content of contents) {
|
|
5102
|
+
if (!content || typeof content !== "object") {
|
|
5103
|
+
continue;
|
|
5104
|
+
}
|
|
5105
|
+
const parts = content.parts;
|
|
5106
|
+
if (!Array.isArray(parts)) {
|
|
5107
|
+
continue;
|
|
5108
|
+
}
|
|
5109
|
+
for (const part of parts) {
|
|
5110
|
+
if (!part || typeof part !== "object") {
|
|
5111
|
+
continue;
|
|
5112
|
+
}
|
|
5113
|
+
const functionResponse = part.functionResponse;
|
|
5114
|
+
if (functionResponse) {
|
|
5115
|
+
responses.push(sanitiseLogValue(functionResponse));
|
|
5116
|
+
}
|
|
5117
|
+
}
|
|
5118
|
+
}
|
|
5119
|
+
return serialiseLogArtifactText(responses);
|
|
5120
|
+
}
|
|
5121
|
+
function serialiseOpenAiStyleToolCallsForLogging(calls) {
|
|
5122
|
+
return serialiseLogArtifactText(
|
|
5123
|
+
calls.map((call) => {
|
|
5124
|
+
if (call.kind === "custom") {
|
|
5125
|
+
return {
|
|
5126
|
+
kind: call.kind,
|
|
5127
|
+
name: call.name,
|
|
5128
|
+
callId: call.callId,
|
|
5129
|
+
itemId: call.itemId,
|
|
5130
|
+
input: call.input
|
|
5131
|
+
};
|
|
5132
|
+
}
|
|
5133
|
+
const { value, error } = parseOpenAiToolArguments(call.arguments);
|
|
5134
|
+
return {
|
|
5135
|
+
kind: call.kind,
|
|
5136
|
+
name: call.name,
|
|
5137
|
+
callId: call.callId,
|
|
5138
|
+
itemId: call.itemId,
|
|
5139
|
+
arguments: value,
|
|
5140
|
+
...error ? { parseError: error, rawArguments: call.arguments } : {}
|
|
5141
|
+
};
|
|
5142
|
+
})
|
|
5143
|
+
);
|
|
5144
|
+
}
|
|
5145
|
+
function serialiseGeminiToolCallsForLogging(calls) {
|
|
5146
|
+
return serialiseLogArtifactText(
|
|
5147
|
+
calls.map((call) => ({
|
|
5148
|
+
name: call.name ?? "unknown",
|
|
5149
|
+
callId: typeof call.id === "string" ? call.id : void 0,
|
|
5150
|
+
arguments: sanitiseLogValue(call.args ?? {})
|
|
5151
|
+
}))
|
|
5152
|
+
);
|
|
5153
|
+
}
|
|
4983
5154
|
function startLlmCallLoggerFromContents(options) {
|
|
4984
5155
|
const session = getCurrentAgentLoggingSession();
|
|
4985
5156
|
if (!session) {
|
|
4986
5157
|
return void 0;
|
|
4987
5158
|
}
|
|
4988
5159
|
const attachments = [];
|
|
5160
|
+
let attachmentIndex = 1;
|
|
4989
5161
|
const sections = [];
|
|
4990
5162
|
for (const [messageIndex, message] of options.contents.entries()) {
|
|
4991
5163
|
sections.push(`### message_${(messageIndex + 1).toString()} role=${message.role}`);
|
|
4992
|
-
for (const
|
|
5164
|
+
for (const part of message.parts) {
|
|
4993
5165
|
if (part.type === "text") {
|
|
4994
5166
|
const channel = part.thought === true ? "thought" : "response";
|
|
4995
5167
|
sections.push(`[text:${channel}]`);
|
|
4996
5168
|
sections.push(part.text);
|
|
4997
5169
|
continue;
|
|
4998
5170
|
}
|
|
4999
|
-
const filename =
|
|
5171
|
+
const filename = buildLoggedAttachmentFilename("input", attachmentIndex, part.mimeType);
|
|
5000
5172
|
attachments.push({
|
|
5001
5173
|
filename,
|
|
5002
5174
|
bytes: decodeInlineDataBuffer(part.data)
|
|
5003
5175
|
});
|
|
5176
|
+
attachmentIndex += 1;
|
|
5004
5177
|
sections.push(
|
|
5005
5178
|
`[inlineData] file=${filename} mime=${part.mimeType ?? "application/octet-stream"} bytes=${attachments[attachments.length - 1]?.bytes.byteLength ?? 0}`
|
|
5006
5179
|
);
|
|
@@ -5044,11 +5217,18 @@ function startLlmCallLoggerFromPayload(options) {
|
|
|
5044
5217
|
}
|
|
5045
5218
|
const attachments = [];
|
|
5046
5219
|
collectPayloadAttachments(options.requestPayload, {
|
|
5047
|
-
prefix:
|
|
5220
|
+
prefix: "input",
|
|
5048
5221
|
attachments,
|
|
5049
5222
|
seen: /* @__PURE__ */ new WeakSet(),
|
|
5050
5223
|
counter: 1
|
|
5051
5224
|
});
|
|
5225
|
+
const toolCallResponseText = options.provider === "openai" || options.provider === "chatgpt" ? extractToolCallResponseTextFromOpenAiInput(
|
|
5226
|
+
options.requestPayload.input
|
|
5227
|
+
) : options.provider === "fireworks" ? extractToolCallResponseTextFromFireworksMessages(
|
|
5228
|
+
options.requestPayload.messages
|
|
5229
|
+
) : extractToolCallResponseTextFromGeminiContents(
|
|
5230
|
+
options.requestPayload.contents
|
|
5231
|
+
);
|
|
5052
5232
|
return session.startLlmCall({
|
|
5053
5233
|
provider: options.provider,
|
|
5054
5234
|
modelId: options.modelId,
|
|
@@ -5057,7 +5237,8 @@ function startLlmCallLoggerFromPayload(options) {
|
|
|
5057
5237
|
step: options.step,
|
|
5058
5238
|
...getCurrentToolCallContext() ? { toolContext: getCurrentToolCallContext() } : {}
|
|
5059
5239
|
},
|
|
5060
|
-
attachments
|
|
5240
|
+
attachments,
|
|
5241
|
+
toolCallResponseText
|
|
5061
5242
|
});
|
|
5062
5243
|
}
|
|
5063
5244
|
async function runTextCall(params) {
|
|
@@ -5362,6 +5543,7 @@ async function runTextCall(params) {
|
|
|
5362
5543
|
const mergedParts = mergeConsecutiveTextParts(responseParts);
|
|
5363
5544
|
const content = mergedParts.length > 0 ? { role: responseRole ?? "assistant", parts: mergedParts } : void 0;
|
|
5364
5545
|
const { text, thoughts } = extractTextByChannel(content);
|
|
5546
|
+
const outputAttachments = collectLoggedAttachmentsFromLlmParts(mergedParts, "output");
|
|
5365
5547
|
const costUsd = estimateCallCostUsd({
|
|
5366
5548
|
modelId: modelVersion,
|
|
5367
5549
|
tokens: latestUsage,
|
|
@@ -5372,16 +5554,20 @@ async function runTextCall(params) {
|
|
|
5372
5554
|
queue.push({ type: "usage", usage: latestUsage, costUsd, modelVersion });
|
|
5373
5555
|
}
|
|
5374
5556
|
callLogger?.complete({
|
|
5375
|
-
|
|
5376
|
-
|
|
5377
|
-
|
|
5378
|
-
|
|
5379
|
-
|
|
5380
|
-
|
|
5381
|
-
|
|
5382
|
-
|
|
5383
|
-
|
|
5384
|
-
|
|
5557
|
+
responseText: text,
|
|
5558
|
+
attachments: outputAttachments,
|
|
5559
|
+
metadata: {
|
|
5560
|
+
provider,
|
|
5561
|
+
model: request.model,
|
|
5562
|
+
modelVersion,
|
|
5563
|
+
blocked,
|
|
5564
|
+
costUsd,
|
|
5565
|
+
usage: latestUsage,
|
|
5566
|
+
grounding: grounding ? sanitiseLogValue(grounding) : void 0,
|
|
5567
|
+
responseChars: text.length,
|
|
5568
|
+
thoughtChars: thoughts.length,
|
|
5569
|
+
responseImages
|
|
5570
|
+
}
|
|
5385
5571
|
});
|
|
5386
5572
|
return {
|
|
5387
5573
|
provider,
|
|
@@ -5396,14 +5582,21 @@ async function runTextCall(params) {
|
|
|
5396
5582
|
grounding
|
|
5397
5583
|
};
|
|
5398
5584
|
} catch (error) {
|
|
5585
|
+
const partialParts = mergeConsecutiveTextParts(responseParts);
|
|
5586
|
+
const partialContent = partialParts.length > 0 ? { role: responseRole ?? "assistant", parts: partialParts } : void 0;
|
|
5587
|
+
const { text: partialText } = extractTextByChannel(partialContent);
|
|
5399
5588
|
callLogger?.fail(error, {
|
|
5400
|
-
|
|
5401
|
-
|
|
5402
|
-
|
|
5403
|
-
|
|
5404
|
-
|
|
5405
|
-
|
|
5406
|
-
|
|
5589
|
+
responseText: partialText,
|
|
5590
|
+
attachments: collectLoggedAttachmentsFromLlmParts(partialParts, "output"),
|
|
5591
|
+
metadata: {
|
|
5592
|
+
provider,
|
|
5593
|
+
model: request.model,
|
|
5594
|
+
modelVersion,
|
|
5595
|
+
blocked,
|
|
5596
|
+
usage: latestUsage,
|
|
5597
|
+
partialResponseParts: responseParts.length,
|
|
5598
|
+
responseImages
|
|
5599
|
+
}
|
|
5407
5600
|
});
|
|
5408
5601
|
throw error;
|
|
5409
5602
|
}
|
|
@@ -5870,6 +6063,9 @@ async function runToolLoop(request) {
|
|
|
5870
6063
|
let usageTokens;
|
|
5871
6064
|
let thoughtDeltaEmitted = false;
|
|
5872
6065
|
let blocked = false;
|
|
6066
|
+
let responseText = "";
|
|
6067
|
+
let reasoningSummary = "";
|
|
6068
|
+
let stepToolCallText;
|
|
5873
6069
|
const stepRequestPayload = {
|
|
5874
6070
|
model: providerInfo.model,
|
|
5875
6071
|
input,
|
|
@@ -5962,8 +6158,8 @@ async function runToolLoop(request) {
|
|
|
5962
6158
|
throw new Error(message);
|
|
5963
6159
|
}
|
|
5964
6160
|
usageTokens = extractOpenAiUsageTokens(finalResponse.usage);
|
|
5965
|
-
|
|
5966
|
-
|
|
6161
|
+
responseText = extractOpenAiResponseParts(finalResponse).parts.filter((p) => p.type === "text" && p.thought !== true).map((p) => p.text).join("").trim();
|
|
6162
|
+
reasoningSummary = extractOpenAiReasoningSummary(finalResponse).trim();
|
|
5967
6163
|
if (!thoughtDeltaEmitted && reasoningSummary.length > 0) {
|
|
5968
6164
|
stepCallLogger?.appendThoughtDelta(reasoningSummary);
|
|
5969
6165
|
emitEvent({ type: "delta", channel: "thought", text: reasoningSummary });
|
|
@@ -5979,6 +6175,23 @@ async function runToolLoop(request) {
|
|
|
5979
6175
|
emitEvent({ type: "usage", usage: usageTokens, costUsd: stepCostUsd, modelVersion });
|
|
5980
6176
|
}
|
|
5981
6177
|
const responseToolCalls = extractOpenAiToolCalls(finalResponse.output);
|
|
6178
|
+
stepToolCallText = serialiseOpenAiStyleToolCallsForLogging(
|
|
6179
|
+
responseToolCalls.map(
|
|
6180
|
+
(call) => call.kind === "custom" ? {
|
|
6181
|
+
kind: call.kind,
|
|
6182
|
+
name: call.name,
|
|
6183
|
+
input: call.input,
|
|
6184
|
+
callId: call.call_id,
|
|
6185
|
+
itemId: call.id
|
|
6186
|
+
} : {
|
|
6187
|
+
kind: call.kind,
|
|
6188
|
+
name: call.name,
|
|
6189
|
+
arguments: call.arguments,
|
|
6190
|
+
callId: call.call_id,
|
|
6191
|
+
itemId: call.id
|
|
6192
|
+
}
|
|
6193
|
+
)
|
|
6194
|
+
);
|
|
5982
6195
|
const stepToolCalls = [];
|
|
5983
6196
|
if (responseToolCalls.length === 0) {
|
|
5984
6197
|
const steeringInput2 = steeringInternal?.drainPendingContents() ?? [];
|
|
@@ -6006,17 +6219,20 @@ async function runToolLoop(request) {
|
|
|
6006
6219
|
timing: timing2
|
|
6007
6220
|
});
|
|
6008
6221
|
stepCallLogger?.complete({
|
|
6009
|
-
|
|
6010
|
-
|
|
6011
|
-
|
|
6012
|
-
|
|
6013
|
-
|
|
6014
|
-
|
|
6015
|
-
|
|
6016
|
-
|
|
6017
|
-
|
|
6018
|
-
|
|
6019
|
-
|
|
6222
|
+
responseText,
|
|
6223
|
+
metadata: {
|
|
6224
|
+
provider: "openai",
|
|
6225
|
+
model: request.model,
|
|
6226
|
+
modelVersion,
|
|
6227
|
+
step: turn,
|
|
6228
|
+
usage: usageTokens,
|
|
6229
|
+
costUsd: stepCostUsd,
|
|
6230
|
+
blocked,
|
|
6231
|
+
responseChars: responseText.length,
|
|
6232
|
+
thoughtChars: reasoningSummary.length,
|
|
6233
|
+
toolCalls: 0,
|
|
6234
|
+
finalStep: steeringItems2.length === 0
|
|
6235
|
+
}
|
|
6020
6236
|
});
|
|
6021
6237
|
if (steeringItems2.length === 0) {
|
|
6022
6238
|
return { text: finalText, thoughts: finalThoughts, steps, totalCostUsd };
|
|
@@ -6139,28 +6355,36 @@ async function runToolLoop(request) {
|
|
|
6139
6355
|
const steeringInput = steeringInternal?.drainPendingContents() ?? [];
|
|
6140
6356
|
const steeringItems = steeringInput.length > 0 ? toOpenAiInput(steeringInput) : [];
|
|
6141
6357
|
stepCallLogger?.complete({
|
|
6142
|
-
|
|
6143
|
-
|
|
6144
|
-
|
|
6145
|
-
|
|
6146
|
-
|
|
6147
|
-
|
|
6148
|
-
|
|
6149
|
-
|
|
6150
|
-
|
|
6151
|
-
|
|
6152
|
-
|
|
6358
|
+
responseText,
|
|
6359
|
+
toolCallText: stepToolCallText,
|
|
6360
|
+
metadata: {
|
|
6361
|
+
provider: "openai",
|
|
6362
|
+
model: request.model,
|
|
6363
|
+
modelVersion,
|
|
6364
|
+
step: turn,
|
|
6365
|
+
usage: usageTokens,
|
|
6366
|
+
costUsd: stepCostUsd,
|
|
6367
|
+
blocked,
|
|
6368
|
+
responseChars: responseText.length,
|
|
6369
|
+
thoughtChars: reasoningSummary.length,
|
|
6370
|
+
toolCalls: stepToolCalls.length,
|
|
6371
|
+
finalStep: false
|
|
6372
|
+
}
|
|
6153
6373
|
});
|
|
6154
6374
|
previousResponseId = finalResponse.id;
|
|
6155
6375
|
input = steeringItems.length > 0 ? toolOutputs.concat(steeringItems) : toolOutputs;
|
|
6156
6376
|
} catch (error) {
|
|
6157
6377
|
stepCallLogger?.fail(error, {
|
|
6158
|
-
|
|
6159
|
-
|
|
6160
|
-
|
|
6161
|
-
|
|
6162
|
-
|
|
6163
|
-
|
|
6378
|
+
responseText,
|
|
6379
|
+
toolCallText: stepToolCallText,
|
|
6380
|
+
metadata: {
|
|
6381
|
+
provider: "openai",
|
|
6382
|
+
model: request.model,
|
|
6383
|
+
modelVersion,
|
|
6384
|
+
step: turn,
|
|
6385
|
+
usage: usageTokens,
|
|
6386
|
+
blocked
|
|
6387
|
+
}
|
|
6164
6388
|
});
|
|
6165
6389
|
throw error;
|
|
6166
6390
|
}
|
|
@@ -6186,6 +6410,7 @@ async function runToolLoop(request) {
|
|
|
6186
6410
|
let usageTokens;
|
|
6187
6411
|
let responseText = "";
|
|
6188
6412
|
let reasoningSummaryText = "";
|
|
6413
|
+
let stepToolCallText;
|
|
6189
6414
|
const markFirstModelEvent = () => {
|
|
6190
6415
|
if (firstModelEventAtMs === void 0) {
|
|
6191
6416
|
firstModelEventAtMs = Date.now();
|
|
@@ -6254,6 +6479,23 @@ async function runToolLoop(request) {
|
|
|
6254
6479
|
stepCallLogger?.appendResponseDelta(responseText);
|
|
6255
6480
|
}
|
|
6256
6481
|
const responseToolCalls = response.toolCalls ?? [];
|
|
6482
|
+
stepToolCallText = serialiseOpenAiStyleToolCallsForLogging(
|
|
6483
|
+
responseToolCalls.map(
|
|
6484
|
+
(call) => call.kind === "custom" ? {
|
|
6485
|
+
kind: call.kind,
|
|
6486
|
+
name: call.name,
|
|
6487
|
+
input: call.input,
|
|
6488
|
+
callId: call.callId,
|
|
6489
|
+
itemId: call.id
|
|
6490
|
+
} : {
|
|
6491
|
+
kind: call.kind,
|
|
6492
|
+
name: call.name,
|
|
6493
|
+
arguments: call.arguments,
|
|
6494
|
+
callId: call.callId,
|
|
6495
|
+
itemId: call.id
|
|
6496
|
+
}
|
|
6497
|
+
)
|
|
6498
|
+
);
|
|
6257
6499
|
if (responseToolCalls.length === 0) {
|
|
6258
6500
|
const steeringInput2 = steeringInternal?.drainPendingContents() ?? [];
|
|
6259
6501
|
const steeringItems2 = steeringInput2.length > 0 ? toChatGptInput(steeringInput2).input : [];
|
|
@@ -6279,16 +6521,19 @@ async function runToolLoop(request) {
|
|
|
6279
6521
|
timing: timing2
|
|
6280
6522
|
});
|
|
6281
6523
|
stepCallLogger?.complete({
|
|
6282
|
-
|
|
6283
|
-
|
|
6284
|
-
|
|
6285
|
-
|
|
6286
|
-
|
|
6287
|
-
|
|
6288
|
-
|
|
6289
|
-
|
|
6290
|
-
|
|
6291
|
-
|
|
6524
|
+
responseText,
|
|
6525
|
+
metadata: {
|
|
6526
|
+
provider: "chatgpt",
|
|
6527
|
+
model: request.model,
|
|
6528
|
+
modelVersion,
|
|
6529
|
+
step: turn,
|
|
6530
|
+
usage: usageTokens,
|
|
6531
|
+
costUsd: stepCostUsd,
|
|
6532
|
+
responseChars: responseText.length,
|
|
6533
|
+
thoughtChars: reasoningSummaryText.length,
|
|
6534
|
+
toolCalls: 0,
|
|
6535
|
+
finalStep: steeringItems2.length === 0
|
|
6536
|
+
}
|
|
6292
6537
|
});
|
|
6293
6538
|
if (steeringItems2.length === 0) {
|
|
6294
6539
|
return { text: finalText, thoughts: finalThoughts, steps, totalCostUsd };
|
|
@@ -6421,25 +6666,33 @@ async function runToolLoop(request) {
|
|
|
6421
6666
|
const steeringInput = steeringInternal?.drainPendingContents() ?? [];
|
|
6422
6667
|
const steeringItems = steeringInput.length > 0 ? toChatGptInput(steeringInput).input : [];
|
|
6423
6668
|
stepCallLogger?.complete({
|
|
6424
|
-
|
|
6425
|
-
|
|
6426
|
-
|
|
6427
|
-
|
|
6428
|
-
|
|
6429
|
-
|
|
6430
|
-
|
|
6431
|
-
|
|
6432
|
-
|
|
6433
|
-
|
|
6669
|
+
responseText,
|
|
6670
|
+
toolCallText: stepToolCallText,
|
|
6671
|
+
metadata: {
|
|
6672
|
+
provider: "chatgpt",
|
|
6673
|
+
model: request.model,
|
|
6674
|
+
modelVersion,
|
|
6675
|
+
step: turn,
|
|
6676
|
+
usage: usageTokens,
|
|
6677
|
+
costUsd: stepCostUsd,
|
|
6678
|
+
responseChars: responseText.length,
|
|
6679
|
+
thoughtChars: reasoningSummaryText.length,
|
|
6680
|
+
toolCalls: toolCalls.length,
|
|
6681
|
+
finalStep: false
|
|
6682
|
+
}
|
|
6434
6683
|
});
|
|
6435
6684
|
input = steeringItems.length > 0 ? input.concat(toolOutputs, steeringItems) : input.concat(toolOutputs);
|
|
6436
6685
|
} catch (error) {
|
|
6437
6686
|
stepCallLogger?.fail(error, {
|
|
6438
|
-
|
|
6439
|
-
|
|
6440
|
-
|
|
6441
|
-
|
|
6442
|
-
|
|
6687
|
+
responseText,
|
|
6688
|
+
toolCallText: stepToolCallText,
|
|
6689
|
+
metadata: {
|
|
6690
|
+
provider: "chatgpt",
|
|
6691
|
+
model: request.model,
|
|
6692
|
+
modelVersion,
|
|
6693
|
+
step: turn,
|
|
6694
|
+
usage: usageTokens
|
|
6695
|
+
}
|
|
6443
6696
|
});
|
|
6444
6697
|
throw error;
|
|
6445
6698
|
}
|
|
@@ -6462,6 +6715,7 @@ async function runToolLoop(request) {
|
|
|
6462
6715
|
let usageTokens;
|
|
6463
6716
|
let responseText = "";
|
|
6464
6717
|
let blocked = false;
|
|
6718
|
+
let stepToolCallText;
|
|
6465
6719
|
const stepRequestPayload = {
|
|
6466
6720
|
model: providerInfo.model,
|
|
6467
6721
|
messages,
|
|
@@ -6526,6 +6780,14 @@ async function runToolLoop(request) {
|
|
|
6526
6780
|
});
|
|
6527
6781
|
}
|
|
6528
6782
|
const responseToolCalls = extractFireworksToolCalls(message);
|
|
6783
|
+
stepToolCallText = serialiseOpenAiStyleToolCallsForLogging(
|
|
6784
|
+
responseToolCalls.map((call) => ({
|
|
6785
|
+
kind: "function",
|
|
6786
|
+
name: call.name,
|
|
6787
|
+
arguments: call.arguments,
|
|
6788
|
+
callId: call.id
|
|
6789
|
+
}))
|
|
6790
|
+
);
|
|
6529
6791
|
if (responseToolCalls.length === 0) {
|
|
6530
6792
|
const steeringInput2 = steeringInternal?.drainPendingContents() ?? [];
|
|
6531
6793
|
const steeringMessages = steeringInput2.length > 0 ? toFireworksMessages(steeringInput2) : [];
|
|
@@ -6551,17 +6813,20 @@ async function runToolLoop(request) {
|
|
|
6551
6813
|
timing: timing2
|
|
6552
6814
|
});
|
|
6553
6815
|
stepCallLogger?.complete({
|
|
6554
|
-
|
|
6555
|
-
|
|
6556
|
-
|
|
6557
|
-
|
|
6558
|
-
|
|
6559
|
-
|
|
6560
|
-
|
|
6561
|
-
|
|
6562
|
-
|
|
6563
|
-
|
|
6564
|
-
|
|
6816
|
+
responseText,
|
|
6817
|
+
metadata: {
|
|
6818
|
+
provider: "fireworks",
|
|
6819
|
+
model: request.model,
|
|
6820
|
+
modelVersion,
|
|
6821
|
+
step: turn,
|
|
6822
|
+
usage: usageTokens,
|
|
6823
|
+
costUsd: stepCostUsd,
|
|
6824
|
+
blocked,
|
|
6825
|
+
responseChars: responseText.length,
|
|
6826
|
+
thoughtChars: 0,
|
|
6827
|
+
toolCalls: 0,
|
|
6828
|
+
finalStep: steeringMessages.length === 0
|
|
6829
|
+
}
|
|
6565
6830
|
});
|
|
6566
6831
|
if (steeringMessages.length === 0) {
|
|
6567
6832
|
return { text: finalText, thoughts: finalThoughts, steps, totalCostUsd };
|
|
@@ -6673,17 +6938,21 @@ async function runToolLoop(request) {
|
|
|
6673
6938
|
timing
|
|
6674
6939
|
});
|
|
6675
6940
|
stepCallLogger?.complete({
|
|
6676
|
-
|
|
6677
|
-
|
|
6678
|
-
|
|
6679
|
-
|
|
6680
|
-
|
|
6681
|
-
|
|
6682
|
-
|
|
6683
|
-
|
|
6684
|
-
|
|
6685
|
-
|
|
6686
|
-
|
|
6941
|
+
responseText,
|
|
6942
|
+
toolCallText: stepToolCallText,
|
|
6943
|
+
metadata: {
|
|
6944
|
+
provider: "fireworks",
|
|
6945
|
+
model: request.model,
|
|
6946
|
+
modelVersion,
|
|
6947
|
+
step: turn,
|
|
6948
|
+
usage: usageTokens,
|
|
6949
|
+
costUsd: stepCostUsd,
|
|
6950
|
+
blocked,
|
|
6951
|
+
responseChars: responseText.length,
|
|
6952
|
+
thoughtChars: 0,
|
|
6953
|
+
toolCalls: stepToolCalls.length,
|
|
6954
|
+
finalStep: false
|
|
6955
|
+
}
|
|
6687
6956
|
});
|
|
6688
6957
|
messages.push({
|
|
6689
6958
|
role: "assistant",
|
|
@@ -6697,12 +6966,16 @@ async function runToolLoop(request) {
|
|
|
6697
6966
|
}
|
|
6698
6967
|
} catch (error) {
|
|
6699
6968
|
stepCallLogger?.fail(error, {
|
|
6700
|
-
|
|
6701
|
-
|
|
6702
|
-
|
|
6703
|
-
|
|
6704
|
-
|
|
6705
|
-
|
|
6969
|
+
responseText,
|
|
6970
|
+
toolCallText: stepToolCallText,
|
|
6971
|
+
metadata: {
|
|
6972
|
+
provider: "fireworks",
|
|
6973
|
+
model: request.model,
|
|
6974
|
+
modelVersion,
|
|
6975
|
+
step: turn,
|
|
6976
|
+
usage: usageTokens,
|
|
6977
|
+
blocked
|
|
6978
|
+
}
|
|
6706
6979
|
});
|
|
6707
6980
|
throw error;
|
|
6708
6981
|
}
|
|
@@ -6722,6 +6995,7 @@ async function runToolLoop(request) {
|
|
|
6722
6995
|
let usageTokens;
|
|
6723
6996
|
let responseText = "";
|
|
6724
6997
|
let thoughtsText = "";
|
|
6998
|
+
let stepToolCallText;
|
|
6725
6999
|
const markFirstModelEvent = () => {
|
|
6726
7000
|
if (firstModelEventAtMs === void 0) {
|
|
6727
7001
|
firstModelEventAtMs = Date.now();
|
|
@@ -6842,12 +7116,17 @@ async function runToolLoop(request) {
|
|
|
6842
7116
|
modelVersion = response.modelVersion ?? request.model;
|
|
6843
7117
|
responseText = response.responseText.trim();
|
|
6844
7118
|
thoughtsText = response.thoughtsText.trim();
|
|
7119
|
+
const responseOutputAttachments = collectLoggedAttachmentsFromGeminiParts(
|
|
7120
|
+
response.modelParts,
|
|
7121
|
+
"output"
|
|
7122
|
+
);
|
|
6845
7123
|
const stepCostUsd = estimateCallCostUsd({
|
|
6846
7124
|
modelId: modelVersion,
|
|
6847
7125
|
tokens: usageTokens,
|
|
6848
7126
|
responseImages: 0
|
|
6849
7127
|
});
|
|
6850
7128
|
totalCostUsd += stepCostUsd;
|
|
7129
|
+
stepToolCallText = serialiseGeminiToolCallsForLogging(response.functionCalls);
|
|
6851
7130
|
if (response.functionCalls.length === 0) {
|
|
6852
7131
|
const steeringInput2 = steeringInternal?.drainPendingContents() ?? [];
|
|
6853
7132
|
finalText = responseText;
|
|
@@ -6873,16 +7152,20 @@ async function runToolLoop(request) {
|
|
|
6873
7152
|
timing: timing2
|
|
6874
7153
|
});
|
|
6875
7154
|
stepCallLogger?.complete({
|
|
6876
|
-
|
|
6877
|
-
|
|
6878
|
-
|
|
6879
|
-
|
|
6880
|
-
|
|
6881
|
-
|
|
6882
|
-
|
|
6883
|
-
|
|
6884
|
-
|
|
6885
|
-
|
|
7155
|
+
responseText,
|
|
7156
|
+
attachments: responseOutputAttachments,
|
|
7157
|
+
metadata: {
|
|
7158
|
+
provider: "gemini",
|
|
7159
|
+
model: request.model,
|
|
7160
|
+
modelVersion,
|
|
7161
|
+
step: turn,
|
|
7162
|
+
usage: usageTokens,
|
|
7163
|
+
costUsd: stepCostUsd,
|
|
7164
|
+
responseChars: responseText.length,
|
|
7165
|
+
thoughtChars: thoughtsText.length,
|
|
7166
|
+
toolCalls: 0,
|
|
7167
|
+
finalStep: steeringInput2.length === 0
|
|
7168
|
+
}
|
|
6886
7169
|
});
|
|
6887
7170
|
if (steeringInput2.length === 0) {
|
|
6888
7171
|
return { text: finalText, thoughts: finalThoughts, steps, totalCostUsd };
|
|
@@ -7009,16 +7292,21 @@ async function runToolLoop(request) {
|
|
|
7009
7292
|
timing
|
|
7010
7293
|
});
|
|
7011
7294
|
stepCallLogger?.complete({
|
|
7012
|
-
|
|
7013
|
-
|
|
7014
|
-
|
|
7015
|
-
|
|
7016
|
-
|
|
7017
|
-
|
|
7018
|
-
|
|
7019
|
-
|
|
7020
|
-
|
|
7021
|
-
|
|
7295
|
+
responseText,
|
|
7296
|
+
attachments: responseOutputAttachments,
|
|
7297
|
+
toolCallText: stepToolCallText,
|
|
7298
|
+
metadata: {
|
|
7299
|
+
provider: "gemini",
|
|
7300
|
+
model: request.model,
|
|
7301
|
+
modelVersion,
|
|
7302
|
+
step: turn,
|
|
7303
|
+
usage: usageTokens,
|
|
7304
|
+
costUsd: stepCostUsd,
|
|
7305
|
+
responseChars: responseText.length,
|
|
7306
|
+
thoughtChars: thoughtsText.length,
|
|
7307
|
+
toolCalls: toolCalls.length,
|
|
7308
|
+
finalStep: false
|
|
7309
|
+
}
|
|
7022
7310
|
});
|
|
7023
7311
|
geminiContents.push({ role: "user", parts: responseParts });
|
|
7024
7312
|
const steeringInput = steeringInternal?.drainPendingContents() ?? [];
|
|
@@ -7027,13 +7315,17 @@ async function runToolLoop(request) {
|
|
|
7027
7315
|
}
|
|
7028
7316
|
} catch (error) {
|
|
7029
7317
|
stepCallLogger?.fail(error, {
|
|
7030
|
-
|
|
7031
|
-
|
|
7032
|
-
|
|
7033
|
-
|
|
7034
|
-
|
|
7035
|
-
|
|
7036
|
-
|
|
7318
|
+
responseText,
|
|
7319
|
+
toolCallText: stepToolCallText,
|
|
7320
|
+
metadata: {
|
|
7321
|
+
provider: "gemini",
|
|
7322
|
+
model: request.model,
|
|
7323
|
+
modelVersion,
|
|
7324
|
+
step: turn,
|
|
7325
|
+
usage: usageTokens,
|
|
7326
|
+
responseChars: responseText.length,
|
|
7327
|
+
thoughtChars: thoughtsText.length
|
|
7328
|
+
}
|
|
7037
7329
|
});
|
|
7038
7330
|
throw error;
|
|
7039
7331
|
}
|