@ljoukov/llm 4.0.1 → 4.0.3
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 +41 -1
- package/dist/index.cjs +2010 -1047
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +17 -5
- package/dist/index.d.ts +17 -5
- package/dist/index.js +2010 -1047
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -115,8 +115,8 @@ __export(index_exports, {
|
|
|
115
115
|
module.exports = __toCommonJS(index_exports);
|
|
116
116
|
|
|
117
117
|
// src/llm.ts
|
|
118
|
-
var
|
|
119
|
-
var
|
|
118
|
+
var import_node_buffer3 = require("buffer");
|
|
119
|
+
var import_node_async_hooks2 = require("async_hooks");
|
|
120
120
|
var import_node_crypto = require("crypto");
|
|
121
121
|
var import_genai2 = require("@google/genai");
|
|
122
122
|
var import_zod_to_json_schema = require("@alcyone-labs/zod-to-json-schema");
|
|
@@ -317,6 +317,16 @@ var OPENAI_GPT_52_PRICING = {
|
|
|
317
317
|
cachedRate: 0.175 / 1e6,
|
|
318
318
|
outputRate: 14 / 1e6
|
|
319
319
|
};
|
|
320
|
+
var OPENAI_GPT_54_PRICING = {
|
|
321
|
+
inputRate: 2.5 / 1e6,
|
|
322
|
+
cachedRate: 0.25 / 1e6,
|
|
323
|
+
outputRate: 15 / 1e6
|
|
324
|
+
};
|
|
325
|
+
var OPENAI_GPT_54_PRIORITY_PRICING = {
|
|
326
|
+
inputRate: 5 / 1e6,
|
|
327
|
+
cachedRate: 0.5 / 1e6,
|
|
328
|
+
outputRate: 30 / 1e6
|
|
329
|
+
};
|
|
320
330
|
var OPENAI_GPT_53_CODEX_PRICING = {
|
|
321
331
|
inputRate: 1.25 / 1e6,
|
|
322
332
|
cachedRate: 0.125 / 1e6,
|
|
@@ -328,6 +338,12 @@ var OPENAI_GPT_5_MINI_PRICING = {
|
|
|
328
338
|
outputRate: 2 / 1e6
|
|
329
339
|
};
|
|
330
340
|
function getOpenAiPricing(modelId) {
|
|
341
|
+
if (modelId.includes("gpt-5.4-fast")) {
|
|
342
|
+
return OPENAI_GPT_54_PRIORITY_PRICING;
|
|
343
|
+
}
|
|
344
|
+
if (modelId.includes("gpt-5.4")) {
|
|
345
|
+
return OPENAI_GPT_54_PRICING;
|
|
346
|
+
}
|
|
331
347
|
if (modelId.includes("gpt-5.3-codex-spark")) {
|
|
332
348
|
return OPENAI_GPT_5_MINI_PRICING;
|
|
333
349
|
}
|
|
@@ -2738,11 +2754,18 @@ async function runOpenAiCall(fn, modelId, runOptions) {
|
|
|
2738
2754
|
}
|
|
2739
2755
|
|
|
2740
2756
|
// src/openai/models.ts
|
|
2741
|
-
var OPENAI_MODEL_IDS = [
|
|
2757
|
+
var OPENAI_MODEL_IDS = [
|
|
2758
|
+
"gpt-5.4",
|
|
2759
|
+
"gpt-5.3-codex",
|
|
2760
|
+
"gpt-5.2",
|
|
2761
|
+
"gpt-5.1-codex-mini"
|
|
2762
|
+
];
|
|
2742
2763
|
function isOpenAiModelId(value) {
|
|
2743
2764
|
return OPENAI_MODEL_IDS.includes(value);
|
|
2744
2765
|
}
|
|
2745
2766
|
var CHATGPT_MODEL_IDS = [
|
|
2767
|
+
"chatgpt-gpt-5.4",
|
|
2768
|
+
"chatgpt-gpt-5.4-fast",
|
|
2746
2769
|
"chatgpt-gpt-5.3-codex",
|
|
2747
2770
|
"chatgpt-gpt-5.3-codex-spark",
|
|
2748
2771
|
"chatgpt-gpt-5.2",
|
|
@@ -2754,9 +2777,387 @@ function isChatGptModelId(value) {
|
|
|
2754
2777
|
function stripChatGptPrefix(model) {
|
|
2755
2778
|
return model.slice("chatgpt-".length);
|
|
2756
2779
|
}
|
|
2780
|
+
function resolveChatGptProviderModel(model) {
|
|
2781
|
+
switch (model) {
|
|
2782
|
+
case "chatgpt-gpt-5.4-fast":
|
|
2783
|
+
return "gpt-5.4";
|
|
2784
|
+
default:
|
|
2785
|
+
return stripChatGptPrefix(model);
|
|
2786
|
+
}
|
|
2787
|
+
}
|
|
2788
|
+
function resolveChatGptServiceTier(model) {
|
|
2789
|
+
return model === "chatgpt-gpt-5.4-fast" ? "priority" : void 0;
|
|
2790
|
+
}
|
|
2791
|
+
|
|
2792
|
+
// src/agentLogging.ts
|
|
2793
|
+
var import_node_async_hooks = require("async_hooks");
|
|
2794
|
+
var import_node_buffer2 = require("buffer");
|
|
2795
|
+
var import_promises = require("fs/promises");
|
|
2796
|
+
var import_node_path3 = __toESM(require("path"), 1);
|
|
2797
|
+
function toIsoNow() {
|
|
2798
|
+
return (/* @__PURE__ */ new Date()).toISOString();
|
|
2799
|
+
}
|
|
2800
|
+
function toErrorMessage(error) {
|
|
2801
|
+
if (error instanceof Error && error.message) {
|
|
2802
|
+
return error.message;
|
|
2803
|
+
}
|
|
2804
|
+
if (typeof error === "string") {
|
|
2805
|
+
return error;
|
|
2806
|
+
}
|
|
2807
|
+
return String(error);
|
|
2808
|
+
}
|
|
2809
|
+
function isPromiseLike(value) {
|
|
2810
|
+
return (typeof value === "object" || typeof value === "function") && value !== null && typeof value.then === "function";
|
|
2811
|
+
}
|
|
2812
|
+
function normalisePathSegment(value) {
|
|
2813
|
+
const cleaned = value.trim().replace(/[^a-z0-9._-]+/giu, "-").replace(/-{2,}/g, "-").replace(/^-+|-+$/g, "");
|
|
2814
|
+
return cleaned.length > 0 ? cleaned : "segment";
|
|
2815
|
+
}
|
|
2816
|
+
function ensureTrailingNewline(value) {
|
|
2817
|
+
return value.endsWith("\n") ? value : `${value}
|
|
2818
|
+
`;
|
|
2819
|
+
}
|
|
2820
|
+
function redactDataUrlPayload(value) {
|
|
2821
|
+
if (!value.toLowerCase().startsWith("data:")) {
|
|
2822
|
+
return value;
|
|
2823
|
+
}
|
|
2824
|
+
const commaIndex = value.indexOf(",");
|
|
2825
|
+
if (commaIndex < 0) {
|
|
2826
|
+
return value;
|
|
2827
|
+
}
|
|
2828
|
+
return `${value.slice(0, commaIndex + 1)}...`;
|
|
2829
|
+
}
|
|
2830
|
+
function sanitiseLogValue(value, seen = /* @__PURE__ */ new WeakSet()) {
|
|
2831
|
+
if (typeof value === "string") {
|
|
2832
|
+
return redactDataUrlPayload(value);
|
|
2833
|
+
}
|
|
2834
|
+
if (typeof value === "number" || typeof value === "boolean" || value === null || value === void 0) {
|
|
2835
|
+
return value;
|
|
2836
|
+
}
|
|
2837
|
+
if (Array.isArray(value)) {
|
|
2838
|
+
return value.map((entry) => sanitiseLogValue(entry, seen));
|
|
2839
|
+
}
|
|
2840
|
+
if (typeof value !== "object") {
|
|
2841
|
+
return String(value);
|
|
2842
|
+
}
|
|
2843
|
+
if (seen.has(value)) {
|
|
2844
|
+
return "[circular]";
|
|
2845
|
+
}
|
|
2846
|
+
seen.add(value);
|
|
2847
|
+
const record = value;
|
|
2848
|
+
const output = {};
|
|
2849
|
+
const hasInlineMime = typeof record.mimeType === "string" && record.mimeType.trim().length > 0 || typeof record.mime_type === "string" && record.mime_type.trim().length > 0;
|
|
2850
|
+
for (const [key, entryValue] of Object.entries(record)) {
|
|
2851
|
+
if (key === "image_url") {
|
|
2852
|
+
if (typeof entryValue === "string") {
|
|
2853
|
+
output[key] = redactDataUrlPayload(entryValue);
|
|
2854
|
+
continue;
|
|
2855
|
+
}
|
|
2856
|
+
if (entryValue && typeof entryValue === "object") {
|
|
2857
|
+
const nested = entryValue;
|
|
2858
|
+
if (typeof nested.url === "string") {
|
|
2859
|
+
output[key] = {
|
|
2860
|
+
...nested,
|
|
2861
|
+
url: redactDataUrlPayload(nested.url)
|
|
2862
|
+
};
|
|
2863
|
+
continue;
|
|
2864
|
+
}
|
|
2865
|
+
}
|
|
2866
|
+
}
|
|
2867
|
+
if (key === "data" && hasInlineMime && typeof entryValue === "string") {
|
|
2868
|
+
output[key] = `[omitted:${import_node_buffer2.Buffer.byteLength(entryValue, "utf8")}b]`;
|
|
2869
|
+
continue;
|
|
2870
|
+
}
|
|
2871
|
+
output[key] = sanitiseLogValue(entryValue, seen);
|
|
2872
|
+
}
|
|
2873
|
+
return output;
|
|
2874
|
+
}
|
|
2875
|
+
function serialiseForSnippet(value) {
|
|
2876
|
+
if (typeof value === "string") {
|
|
2877
|
+
return value;
|
|
2878
|
+
}
|
|
2879
|
+
try {
|
|
2880
|
+
return JSON.stringify(sanitiseLogValue(value));
|
|
2881
|
+
} catch {
|
|
2882
|
+
return String(value);
|
|
2883
|
+
}
|
|
2884
|
+
}
|
|
2885
|
+
function formatToolLogSnippet(value) {
|
|
2886
|
+
const compact = serialiseForSnippet(value).replace(/\s+/gu, " ").trim();
|
|
2887
|
+
if (compact.length === 0) {
|
|
2888
|
+
return "<empty>";
|
|
2889
|
+
}
|
|
2890
|
+
const max = 600;
|
|
2891
|
+
if (compact.length <= max) {
|
|
2892
|
+
return compact;
|
|
2893
|
+
}
|
|
2894
|
+
return `${compact.slice(0, max)}...`;
|
|
2895
|
+
}
|
|
2896
|
+
function formatUsd(value) {
|
|
2897
|
+
const amount = typeof value === "number" && Number.isFinite(value) ? Math.max(0, value) : 0;
|
|
2898
|
+
return amount.toFixed(6);
|
|
2899
|
+
}
|
|
2900
|
+
function appendToolCallStreamLog(options) {
|
|
2901
|
+
const event = options.event;
|
|
2902
|
+
if (event.type !== "tool_call") {
|
|
2903
|
+
return;
|
|
2904
|
+
}
|
|
2905
|
+
const callIdSegment = typeof event.callId === "string" && event.callId.trim().length > 0 ? ` callId=${event.callId}` : "";
|
|
2906
|
+
const prefix = [
|
|
2907
|
+
`tool_call_${event.phase}:`,
|
|
2908
|
+
`turn=${event.turn.toString()}`,
|
|
2909
|
+
`index=${event.toolIndex.toString()}`,
|
|
2910
|
+
`tool=${event.toolName}${callIdSegment}`
|
|
2911
|
+
].join(" ");
|
|
2912
|
+
if (event.phase === "started") {
|
|
2913
|
+
options.append(prefix);
|
|
2914
|
+
options.append(`tool_call_input: ${formatToolLogSnippet(sanitiseLogValue(event.input))}`);
|
|
2915
|
+
return;
|
|
2916
|
+
}
|
|
2917
|
+
const durationSegment = typeof event.durationMs === "number" && Number.isFinite(event.durationMs) ? ` durationMs=${Math.max(0, Math.round(event.durationMs)).toString()}` : "";
|
|
2918
|
+
options.append(`${prefix} status=${event.error ? "error" : "ok"}${durationSegment}`);
|
|
2919
|
+
options.append(`tool_call_output: ${formatToolLogSnippet(sanitiseLogValue(event.output))}`);
|
|
2920
|
+
if (typeof event.error === "string" && event.error.trim().length > 0) {
|
|
2921
|
+
options.append(`tool_call_error: ${event.error.trim()}`);
|
|
2922
|
+
}
|
|
2923
|
+
}
|
|
2924
|
+
function appendAgentStreamEventLog(options) {
|
|
2925
|
+
const event = options.event;
|
|
2926
|
+
switch (event.type) {
|
|
2927
|
+
case "delta": {
|
|
2928
|
+
const channelPrefix = event.channel === "thought" ? "thought_delta" : "response_delta";
|
|
2929
|
+
options.append(`${channelPrefix}: ${event.text}`);
|
|
2930
|
+
return;
|
|
2931
|
+
}
|
|
2932
|
+
case "model": {
|
|
2933
|
+
options.append(`model: ${event.modelVersion}`);
|
|
2934
|
+
return;
|
|
2935
|
+
}
|
|
2936
|
+
case "usage": {
|
|
2937
|
+
options.append(
|
|
2938
|
+
[
|
|
2939
|
+
"usage:",
|
|
2940
|
+
`modelVersion=${event.modelVersion}`,
|
|
2941
|
+
`costUsd=${formatUsd(event.costUsd)}`,
|
|
2942
|
+
`tokens=${formatToolLogSnippet(sanitiseLogValue(event.usage))}`
|
|
2943
|
+
].join(" ")
|
|
2944
|
+
);
|
|
2945
|
+
return;
|
|
2946
|
+
}
|
|
2947
|
+
case "blocked": {
|
|
2948
|
+
options.append("blocked");
|
|
2949
|
+
return;
|
|
2950
|
+
}
|
|
2951
|
+
case "tool_call": {
|
|
2952
|
+
appendToolCallStreamLog({
|
|
2953
|
+
event,
|
|
2954
|
+
append: options.append
|
|
2955
|
+
});
|
|
2956
|
+
return;
|
|
2957
|
+
}
|
|
2958
|
+
}
|
|
2959
|
+
}
|
|
2960
|
+
var AgentLoggingSessionImpl = class {
|
|
2961
|
+
workspaceDir;
|
|
2962
|
+
logsRootDir;
|
|
2963
|
+
mirrorToConsole;
|
|
2964
|
+
sink;
|
|
2965
|
+
agentLogPath;
|
|
2966
|
+
ensureReady;
|
|
2967
|
+
pending = /* @__PURE__ */ new Set();
|
|
2968
|
+
lineChain = Promise.resolve();
|
|
2969
|
+
callCounter = 0;
|
|
2970
|
+
constructor(config) {
|
|
2971
|
+
this.workspaceDir = import_node_path3.default.resolve(config.workspaceDir ?? process.cwd());
|
|
2972
|
+
this.logsRootDir = import_node_path3.default.join(import_node_path3.default.dirname(this.workspaceDir), "logs");
|
|
2973
|
+
this.mirrorToConsole = config.mirrorToConsole !== false;
|
|
2974
|
+
this.sink = config.sink;
|
|
2975
|
+
this.agentLogPath = import_node_path3.default.join(this.workspaceDir, "agent.log");
|
|
2976
|
+
this.ensureReady = this.prepare();
|
|
2977
|
+
this.track(this.ensureReady);
|
|
2978
|
+
}
|
|
2979
|
+
async prepare() {
|
|
2980
|
+
await (0, import_promises.mkdir)(this.workspaceDir, { recursive: true });
|
|
2981
|
+
await (0, import_promises.mkdir)(this.logsRootDir, { recursive: true });
|
|
2982
|
+
}
|
|
2983
|
+
track(task) {
|
|
2984
|
+
this.pending.add(task);
|
|
2985
|
+
task.finally(() => {
|
|
2986
|
+
this.pending.delete(task);
|
|
2987
|
+
});
|
|
2988
|
+
}
|
|
2989
|
+
enqueueLineWrite(line) {
|
|
2990
|
+
const next = this.lineChain.then(async () => {
|
|
2991
|
+
await this.ensureReady;
|
|
2992
|
+
await (0, import_promises.appendFile)(this.agentLogPath, `${line}
|
|
2993
|
+
`, "utf8");
|
|
2994
|
+
const sinkResult = this.sink?.append(line);
|
|
2995
|
+
if (isPromiseLike(sinkResult)) {
|
|
2996
|
+
await sinkResult;
|
|
2997
|
+
}
|
|
2998
|
+
});
|
|
2999
|
+
const tracked = next.catch(() => void 0);
|
|
3000
|
+
this.lineChain = tracked;
|
|
3001
|
+
this.track(tracked);
|
|
3002
|
+
}
|
|
3003
|
+
logLine(line) {
|
|
3004
|
+
const timestamped = `${toIsoNow()} ${line}`;
|
|
3005
|
+
if (this.mirrorToConsole) {
|
|
3006
|
+
console.log(timestamped);
|
|
3007
|
+
}
|
|
3008
|
+
this.enqueueLineWrite(timestamped);
|
|
3009
|
+
}
|
|
3010
|
+
startLlmCall(input) {
|
|
3011
|
+
const callNumber = this.callCounter + 1;
|
|
3012
|
+
this.callCounter = callNumber;
|
|
3013
|
+
const timestampSegment = toIsoNow().replace(/[:]/g, "-");
|
|
3014
|
+
const modelSegment = normalisePathSegment(input.modelId);
|
|
3015
|
+
const baseDir = import_node_path3.default.join(
|
|
3016
|
+
this.logsRootDir,
|
|
3017
|
+
`${timestampSegment}-${callNumber.toString().padStart(4, "0")}`,
|
|
3018
|
+
modelSegment
|
|
3019
|
+
);
|
|
3020
|
+
const responsePath = import_node_path3.default.join(baseDir, "response.txt");
|
|
3021
|
+
const thoughtsPath = import_node_path3.default.join(baseDir, "thoughts.txt");
|
|
3022
|
+
const responseMetadataPath = import_node_path3.default.join(baseDir, "response.metadata.json");
|
|
3023
|
+
let chain = this.ensureReady.then(async () => {
|
|
3024
|
+
await (0, import_promises.mkdir)(baseDir, { recursive: true });
|
|
3025
|
+
const requestText = input.requestText.trim().length > 0 ? input.requestText : "<empty request>";
|
|
3026
|
+
await (0, import_promises.writeFile)(
|
|
3027
|
+
import_node_path3.default.join(baseDir, "request.txt"),
|
|
3028
|
+
ensureTrailingNewline(requestText),
|
|
3029
|
+
"utf8"
|
|
3030
|
+
);
|
|
3031
|
+
const requestMetadata = {
|
|
3032
|
+
capturedAt: toIsoNow(),
|
|
3033
|
+
provider: input.provider,
|
|
3034
|
+
modelId: input.modelId,
|
|
3035
|
+
...input.requestMetadata ? { request: sanitiseLogValue(input.requestMetadata) } : {}
|
|
3036
|
+
};
|
|
3037
|
+
await (0, import_promises.writeFile)(
|
|
3038
|
+
import_node_path3.default.join(baseDir, "request.metadata.json"),
|
|
3039
|
+
`${JSON.stringify(requestMetadata, null, 2)}
|
|
3040
|
+
`,
|
|
3041
|
+
"utf8"
|
|
3042
|
+
);
|
|
3043
|
+
const usedNames = /* @__PURE__ */ new Set();
|
|
3044
|
+
for (const attachment of input.attachments ?? []) {
|
|
3045
|
+
let filename = normalisePathSegment(attachment.filename);
|
|
3046
|
+
if (!filename.includes(".")) {
|
|
3047
|
+
filename = `${filename}.bin`;
|
|
3048
|
+
}
|
|
3049
|
+
const ext = import_node_path3.default.extname(filename);
|
|
3050
|
+
const base = ext.length > 0 ? filename.slice(0, -ext.length) : filename;
|
|
3051
|
+
let candidate = filename;
|
|
3052
|
+
let duplicateIndex = 2;
|
|
3053
|
+
while (usedNames.has(candidate)) {
|
|
3054
|
+
candidate = `${base}-${duplicateIndex.toString()}${ext}`;
|
|
3055
|
+
duplicateIndex += 1;
|
|
3056
|
+
}
|
|
3057
|
+
usedNames.add(candidate);
|
|
3058
|
+
await (0, import_promises.writeFile)(import_node_path3.default.join(baseDir, candidate), attachment.bytes);
|
|
3059
|
+
}
|
|
3060
|
+
}).catch(() => void 0);
|
|
3061
|
+
this.track(chain);
|
|
3062
|
+
let closed = false;
|
|
3063
|
+
const enqueue = (operation) => {
|
|
3064
|
+
const next = chain.then(operation);
|
|
3065
|
+
const tracked = next.catch(() => void 0);
|
|
3066
|
+
chain = tracked;
|
|
3067
|
+
this.track(tracked);
|
|
3068
|
+
};
|
|
3069
|
+
return {
|
|
3070
|
+
appendThoughtDelta: (text) => {
|
|
3071
|
+
if (closed || text.length === 0) {
|
|
3072
|
+
return;
|
|
3073
|
+
}
|
|
3074
|
+
enqueue(async () => {
|
|
3075
|
+
await (0, import_promises.appendFile)(thoughtsPath, text, "utf8");
|
|
3076
|
+
});
|
|
3077
|
+
},
|
|
3078
|
+
appendResponseDelta: (text) => {
|
|
3079
|
+
if (closed || text.length === 0) {
|
|
3080
|
+
return;
|
|
3081
|
+
}
|
|
3082
|
+
enqueue(async () => {
|
|
3083
|
+
await (0, import_promises.appendFile)(responsePath, text, "utf8");
|
|
3084
|
+
});
|
|
3085
|
+
},
|
|
3086
|
+
complete: (metadata) => {
|
|
3087
|
+
if (closed) {
|
|
3088
|
+
return;
|
|
3089
|
+
}
|
|
3090
|
+
closed = true;
|
|
3091
|
+
enqueue(async () => {
|
|
3092
|
+
const payload = {
|
|
3093
|
+
capturedAt: toIsoNow(),
|
|
3094
|
+
status: "completed"
|
|
3095
|
+
};
|
|
3096
|
+
if (metadata) {
|
|
3097
|
+
const sanitised = sanitiseLogValue(metadata);
|
|
3098
|
+
if (sanitised && typeof sanitised === "object" && !Array.isArray(sanitised)) {
|
|
3099
|
+
Object.assign(payload, sanitised);
|
|
3100
|
+
} else if (sanitised !== void 0) {
|
|
3101
|
+
payload.metadata = sanitised;
|
|
3102
|
+
}
|
|
3103
|
+
}
|
|
3104
|
+
await (0, import_promises.writeFile)(responseMetadataPath, `${JSON.stringify(payload, null, 2)}
|
|
3105
|
+
`, "utf8");
|
|
3106
|
+
});
|
|
3107
|
+
},
|
|
3108
|
+
fail: (error, metadata) => {
|
|
3109
|
+
if (closed) {
|
|
3110
|
+
return;
|
|
3111
|
+
}
|
|
3112
|
+
closed = true;
|
|
3113
|
+
enqueue(async () => {
|
|
3114
|
+
const payload = {
|
|
3115
|
+
capturedAt: toIsoNow(),
|
|
3116
|
+
status: "failed",
|
|
3117
|
+
error: toErrorMessage(error)
|
|
3118
|
+
};
|
|
3119
|
+
if (metadata) {
|
|
3120
|
+
const sanitised = sanitiseLogValue(metadata);
|
|
3121
|
+
if (sanitised && typeof sanitised === "object" && !Array.isArray(sanitised)) {
|
|
3122
|
+
Object.assign(payload, sanitised);
|
|
3123
|
+
} else if (sanitised !== void 0) {
|
|
3124
|
+
payload.metadata = sanitised;
|
|
3125
|
+
}
|
|
3126
|
+
}
|
|
3127
|
+
await (0, import_promises.writeFile)(responseMetadataPath, `${JSON.stringify(payload, null, 2)}
|
|
3128
|
+
`, "utf8");
|
|
3129
|
+
});
|
|
3130
|
+
}
|
|
3131
|
+
};
|
|
3132
|
+
}
|
|
3133
|
+
async flush() {
|
|
3134
|
+
while (this.pending.size > 0) {
|
|
3135
|
+
await Promise.allSettled([...this.pending]);
|
|
3136
|
+
}
|
|
3137
|
+
if (typeof this.sink?.flush === "function") {
|
|
3138
|
+
try {
|
|
3139
|
+
await this.sink.flush();
|
|
3140
|
+
} catch {
|
|
3141
|
+
}
|
|
3142
|
+
}
|
|
3143
|
+
}
|
|
3144
|
+
};
|
|
3145
|
+
var loggingSessionStorage = new import_node_async_hooks.AsyncLocalStorage();
|
|
3146
|
+
function createAgentLoggingSession(config) {
|
|
3147
|
+
return new AgentLoggingSessionImpl(config);
|
|
3148
|
+
}
|
|
3149
|
+
function runWithAgentLoggingSession(session, fn) {
|
|
3150
|
+
if (!session) {
|
|
3151
|
+
return fn();
|
|
3152
|
+
}
|
|
3153
|
+
return loggingSessionStorage.run(session, fn);
|
|
3154
|
+
}
|
|
3155
|
+
function getCurrentAgentLoggingSession() {
|
|
3156
|
+
return loggingSessionStorage.getStore();
|
|
3157
|
+
}
|
|
2757
3158
|
|
|
2758
3159
|
// src/llm.ts
|
|
2759
|
-
var toolCallContextStorage = new
|
|
3160
|
+
var toolCallContextStorage = new import_node_async_hooks2.AsyncLocalStorage();
|
|
2760
3161
|
function getCurrentToolCallContext() {
|
|
2761
3162
|
return toolCallContextStorage.getStore() ?? null;
|
|
2762
3163
|
}
|
|
@@ -3048,9 +3449,9 @@ function sanitisePartForLogging(part) {
|
|
|
3048
3449
|
case "inlineData": {
|
|
3049
3450
|
let omittedBytes;
|
|
3050
3451
|
try {
|
|
3051
|
-
omittedBytes =
|
|
3452
|
+
omittedBytes = import_node_buffer3.Buffer.from(part.data, "base64").byteLength;
|
|
3052
3453
|
} catch {
|
|
3053
|
-
omittedBytes =
|
|
3454
|
+
omittedBytes = import_node_buffer3.Buffer.byteLength(part.data, "utf8");
|
|
3054
3455
|
}
|
|
3055
3456
|
return {
|
|
3056
3457
|
type: "inlineData",
|
|
@@ -3135,7 +3536,11 @@ function convertLlmContentToGeminiContent(content) {
|
|
|
3135
3536
|
}
|
|
3136
3537
|
function resolveProvider(model) {
|
|
3137
3538
|
if (isChatGptModelId(model)) {
|
|
3138
|
-
return {
|
|
3539
|
+
return {
|
|
3540
|
+
provider: "chatgpt",
|
|
3541
|
+
model: resolveChatGptProviderModel(model),
|
|
3542
|
+
serviceTier: resolveChatGptServiceTier(model)
|
|
3543
|
+
};
|
|
3139
3544
|
}
|
|
3140
3545
|
if (isGeminiTextModelId(model) || isGeminiImageModelId(model)) {
|
|
3141
3546
|
return { provider: "gemini", model };
|
|
@@ -4113,8 +4518,8 @@ function parseOpenAiToolArguments(raw) {
|
|
|
4113
4518
|
function formatZodIssues(issues) {
|
|
4114
4519
|
const messages = [];
|
|
4115
4520
|
for (const issue of issues) {
|
|
4116
|
-
const
|
|
4117
|
-
messages.push(`${
|
|
4521
|
+
const path8 = issue.path.length > 0 ? issue.path.map(String).join(".") : "input";
|
|
4522
|
+
messages.push(`${path8}: ${issue.message}`);
|
|
4118
4523
|
}
|
|
4119
4524
|
return messages.join("; ");
|
|
4120
4525
|
}
|
|
@@ -4500,9 +4905,9 @@ function resolveGeminiThinkingConfig(modelId, thinkingLevel) {
|
|
|
4500
4905
|
}
|
|
4501
4906
|
function decodeInlineDataBuffer(base64) {
|
|
4502
4907
|
try {
|
|
4503
|
-
return
|
|
4908
|
+
return import_node_buffer3.Buffer.from(base64, "base64");
|
|
4504
4909
|
} catch {
|
|
4505
|
-
return
|
|
4910
|
+
return import_node_buffer3.Buffer.from(base64, "base64url");
|
|
4506
4911
|
}
|
|
4507
4912
|
}
|
|
4508
4913
|
function extractImages(content) {
|
|
@@ -4519,6 +4924,195 @@ function extractImages(content) {
|
|
|
4519
4924
|
}
|
|
4520
4925
|
return images;
|
|
4521
4926
|
}
|
|
4927
|
+
function resolveAttachmentExtension(mimeType) {
|
|
4928
|
+
const normalized = (mimeType ?? "").trim().toLowerCase();
|
|
4929
|
+
switch (normalized) {
|
|
4930
|
+
case "image/jpeg":
|
|
4931
|
+
return "jpg";
|
|
4932
|
+
case "image/png":
|
|
4933
|
+
return "png";
|
|
4934
|
+
case "image/webp":
|
|
4935
|
+
return "webp";
|
|
4936
|
+
case "image/gif":
|
|
4937
|
+
return "gif";
|
|
4938
|
+
case "image/heic":
|
|
4939
|
+
return "heic";
|
|
4940
|
+
case "image/heif":
|
|
4941
|
+
return "heif";
|
|
4942
|
+
case "application/pdf":
|
|
4943
|
+
return "pdf";
|
|
4944
|
+
case "application/json":
|
|
4945
|
+
return "json";
|
|
4946
|
+
case "text/plain":
|
|
4947
|
+
return "txt";
|
|
4948
|
+
case "text/markdown":
|
|
4949
|
+
return "md";
|
|
4950
|
+
default: {
|
|
4951
|
+
const slashIndex = normalized.indexOf("/");
|
|
4952
|
+
if (slashIndex >= 0) {
|
|
4953
|
+
const subtype = normalized.slice(slashIndex + 1).split("+")[0] ?? "";
|
|
4954
|
+
const cleaned = subtype.replace(/[^a-z0-9]+/giu, "");
|
|
4955
|
+
if (cleaned.length > 0) {
|
|
4956
|
+
return cleaned;
|
|
4957
|
+
}
|
|
4958
|
+
}
|
|
4959
|
+
return "bin";
|
|
4960
|
+
}
|
|
4961
|
+
}
|
|
4962
|
+
}
|
|
4963
|
+
function decodeDataUrlAttachment(value, basename) {
|
|
4964
|
+
const trimmed = value.trim();
|
|
4965
|
+
if (!trimmed.toLowerCase().startsWith("data:")) {
|
|
4966
|
+
return null;
|
|
4967
|
+
}
|
|
4968
|
+
const commaIndex = trimmed.indexOf(",");
|
|
4969
|
+
if (commaIndex < 0) {
|
|
4970
|
+
return null;
|
|
4971
|
+
}
|
|
4972
|
+
const header = trimmed.slice(5, commaIndex);
|
|
4973
|
+
const payload = trimmed.slice(commaIndex + 1);
|
|
4974
|
+
const isBase64 = /;base64(?:;|$)/iu.test(header);
|
|
4975
|
+
const mimeType = (header.split(";")[0] ?? "application/octet-stream").trim().toLowerCase();
|
|
4976
|
+
try {
|
|
4977
|
+
const bytes = isBase64 ? import_node_buffer3.Buffer.from(payload, "base64") : import_node_buffer3.Buffer.from(decodeURIComponent(payload), "utf8");
|
|
4978
|
+
return {
|
|
4979
|
+
filename: `${basename}.${resolveAttachmentExtension(mimeType)}`,
|
|
4980
|
+
bytes
|
|
4981
|
+
};
|
|
4982
|
+
} catch {
|
|
4983
|
+
return null;
|
|
4984
|
+
}
|
|
4985
|
+
}
|
|
4986
|
+
function collectPayloadAttachments(value, options) {
|
|
4987
|
+
if (typeof value === "string") {
|
|
4988
|
+
const attachment = decodeDataUrlAttachment(
|
|
4989
|
+
value,
|
|
4990
|
+
`${options.prefix}-${options.counter.toString()}`
|
|
4991
|
+
);
|
|
4992
|
+
if (attachment) {
|
|
4993
|
+
options.attachments.push(attachment);
|
|
4994
|
+
options.counter += 1;
|
|
4995
|
+
}
|
|
4996
|
+
return;
|
|
4997
|
+
}
|
|
4998
|
+
if (!value || typeof value !== "object") {
|
|
4999
|
+
return;
|
|
5000
|
+
}
|
|
5001
|
+
if (options.seen.has(value)) {
|
|
5002
|
+
return;
|
|
5003
|
+
}
|
|
5004
|
+
options.seen.add(value);
|
|
5005
|
+
if (Array.isArray(value)) {
|
|
5006
|
+
for (const entry of value) {
|
|
5007
|
+
collectPayloadAttachments(entry, options);
|
|
5008
|
+
}
|
|
5009
|
+
return;
|
|
5010
|
+
}
|
|
5011
|
+
const record = value;
|
|
5012
|
+
const mimeType = typeof record.mimeType === "string" ? record.mimeType : void 0;
|
|
5013
|
+
if (typeof record.data === "string" && mimeType) {
|
|
5014
|
+
try {
|
|
5015
|
+
options.attachments.push({
|
|
5016
|
+
filename: `${options.prefix}-${options.counter.toString()}.${resolveAttachmentExtension(mimeType)}`,
|
|
5017
|
+
bytes: decodeInlineDataBuffer(record.data)
|
|
5018
|
+
});
|
|
5019
|
+
options.counter += 1;
|
|
5020
|
+
} catch {
|
|
5021
|
+
}
|
|
5022
|
+
}
|
|
5023
|
+
for (const entry of Object.values(record)) {
|
|
5024
|
+
collectPayloadAttachments(entry, options);
|
|
5025
|
+
}
|
|
5026
|
+
}
|
|
5027
|
+
function serialiseRequestPayloadForLogging(value) {
|
|
5028
|
+
try {
|
|
5029
|
+
return `${JSON.stringify(sanitiseLogValue(value), null, 2)}
|
|
5030
|
+
`;
|
|
5031
|
+
} catch {
|
|
5032
|
+
return `${String(value)}
|
|
5033
|
+
`;
|
|
5034
|
+
}
|
|
5035
|
+
}
|
|
5036
|
+
function startLlmCallLoggerFromContents(options) {
|
|
5037
|
+
const session = getCurrentAgentLoggingSession();
|
|
5038
|
+
if (!session) {
|
|
5039
|
+
return void 0;
|
|
5040
|
+
}
|
|
5041
|
+
const attachments = [];
|
|
5042
|
+
const sections = [];
|
|
5043
|
+
for (const [messageIndex, message] of options.contents.entries()) {
|
|
5044
|
+
sections.push(`### message_${(messageIndex + 1).toString()} role=${message.role}`);
|
|
5045
|
+
for (const [partIndex, part] of message.parts.entries()) {
|
|
5046
|
+
if (part.type === "text") {
|
|
5047
|
+
const channel = part.thought === true ? "thought" : "response";
|
|
5048
|
+
sections.push(`[text:${channel}]`);
|
|
5049
|
+
sections.push(part.text);
|
|
5050
|
+
continue;
|
|
5051
|
+
}
|
|
5052
|
+
const filename = `message-${(messageIndex + 1).toString()}-part-${(partIndex + 1).toString()}.${resolveAttachmentExtension(part.mimeType)}`;
|
|
5053
|
+
attachments.push({
|
|
5054
|
+
filename,
|
|
5055
|
+
bytes: decodeInlineDataBuffer(part.data)
|
|
5056
|
+
});
|
|
5057
|
+
sections.push(
|
|
5058
|
+
`[inlineData] file=${filename} mime=${part.mimeType ?? "application/octet-stream"} bytes=${attachments[attachments.length - 1]?.bytes.byteLength ?? 0}`
|
|
5059
|
+
);
|
|
5060
|
+
}
|
|
5061
|
+
sections.push("");
|
|
5062
|
+
}
|
|
5063
|
+
return session.startLlmCall({
|
|
5064
|
+
provider: options.provider,
|
|
5065
|
+
modelId: options.request.model,
|
|
5066
|
+
requestText: sections.join("\n").trim(),
|
|
5067
|
+
requestMetadata: {
|
|
5068
|
+
model: options.request.model,
|
|
5069
|
+
input: options.contents.map((content) => ({
|
|
5070
|
+
role: content.role,
|
|
5071
|
+
parts: content.parts.map((part) => sanitisePartForLogging(part))
|
|
5072
|
+
})),
|
|
5073
|
+
...options.request.instructions ? {
|
|
5074
|
+
instructions: options.request.instructions
|
|
5075
|
+
} : {},
|
|
5076
|
+
...options.request.tools ? { tools: options.request.tools } : {},
|
|
5077
|
+
...options.request.responseMimeType ? {
|
|
5078
|
+
responseMimeType: options.request.responseMimeType
|
|
5079
|
+
} : {},
|
|
5080
|
+
...options.request.responseJsonSchema ? {
|
|
5081
|
+
responseJsonSchema: sanitiseLogValue(options.request.responseJsonSchema)
|
|
5082
|
+
} : {},
|
|
5083
|
+
...options.request.responseModalities ? { responseModalities: options.request.responseModalities } : {},
|
|
5084
|
+
...options.request.imageAspectRatio ? { imageAspectRatio: options.request.imageAspectRatio } : {},
|
|
5085
|
+
...options.request.imageSize ? { imageSize: options.request.imageSize } : {},
|
|
5086
|
+
...options.request.thinkingLevel ? { thinkingLevel: options.request.thinkingLevel } : {},
|
|
5087
|
+
...options.request.openAiTextFormat ? { openAiTextFormat: sanitiseLogValue(options.request.openAiTextFormat) } : {},
|
|
5088
|
+
...getCurrentToolCallContext() ? { toolContext: getCurrentToolCallContext() } : {}
|
|
5089
|
+
},
|
|
5090
|
+
attachments
|
|
5091
|
+
});
|
|
5092
|
+
}
|
|
5093
|
+
function startLlmCallLoggerFromPayload(options) {
|
|
5094
|
+
const session = getCurrentAgentLoggingSession();
|
|
5095
|
+
if (!session) {
|
|
5096
|
+
return void 0;
|
|
5097
|
+
}
|
|
5098
|
+
const attachments = [];
|
|
5099
|
+
collectPayloadAttachments(options.requestPayload, {
|
|
5100
|
+
prefix: `step-${options.step.toString()}`,
|
|
5101
|
+
attachments,
|
|
5102
|
+
seen: /* @__PURE__ */ new WeakSet(),
|
|
5103
|
+
counter: 1
|
|
5104
|
+
});
|
|
5105
|
+
return session.startLlmCall({
|
|
5106
|
+
provider: options.provider,
|
|
5107
|
+
modelId: options.modelId,
|
|
5108
|
+
requestText: serialiseRequestPayloadForLogging(options.requestPayload),
|
|
5109
|
+
requestMetadata: {
|
|
5110
|
+
step: options.step,
|
|
5111
|
+
...getCurrentToolCallContext() ? { toolContext: getCurrentToolCallContext() } : {}
|
|
5112
|
+
},
|
|
5113
|
+
attachments
|
|
5114
|
+
});
|
|
5115
|
+
}
|
|
4522
5116
|
async function runTextCall(params) {
|
|
4523
5117
|
const { request, queue, abortController } = params;
|
|
4524
5118
|
const providerInfo = resolveProvider(request.model);
|
|
@@ -4528,6 +5122,11 @@ async function runTextCall(params) {
|
|
|
4528
5122
|
if (contents.length === 0) {
|
|
4529
5123
|
throw new Error("LLM call received an empty prompt.");
|
|
4530
5124
|
}
|
|
5125
|
+
const callLogger = startLlmCallLoggerFromContents({
|
|
5126
|
+
provider,
|
|
5127
|
+
request,
|
|
5128
|
+
contents
|
|
5129
|
+
});
|
|
4531
5130
|
let modelVersion = request.model;
|
|
4532
5131
|
let blocked = false;
|
|
4533
5132
|
let grounding;
|
|
@@ -4535,12 +5134,17 @@ async function runTextCall(params) {
|
|
|
4535
5134
|
let responseRole;
|
|
4536
5135
|
let latestUsage;
|
|
4537
5136
|
let responseImages = 0;
|
|
4538
|
-
const pushDelta = (channel,
|
|
4539
|
-
if (!
|
|
5137
|
+
const pushDelta = (channel, text) => {
|
|
5138
|
+
if (!text) {
|
|
4540
5139
|
return;
|
|
4541
5140
|
}
|
|
4542
|
-
responseParts.push({ type: "text", text
|
|
4543
|
-
|
|
5141
|
+
responseParts.push({ type: "text", text, ...channel === "thought" ? { thought: true } : {} });
|
|
5142
|
+
if (channel === "thought") {
|
|
5143
|
+
callLogger?.appendThoughtDelta(text);
|
|
5144
|
+
} else {
|
|
5145
|
+
callLogger?.appendResponseDelta(text);
|
|
5146
|
+
}
|
|
5147
|
+
queue.push({ type: "delta", channel, text });
|
|
4544
5148
|
};
|
|
4545
5149
|
const pushInline = (data, mimeType) => {
|
|
4546
5150
|
if (!data) {
|
|
@@ -4567,263 +5171,295 @@ async function runTextCall(params) {
|
|
|
4567
5171
|
return abortController.signal;
|
|
4568
5172
|
};
|
|
4569
5173
|
const signal = resolveAbortSignal();
|
|
4570
|
-
|
|
4571
|
-
|
|
4572
|
-
|
|
4573
|
-
|
|
4574
|
-
|
|
4575
|
-
|
|
4576
|
-
|
|
4577
|
-
|
|
4578
|
-
|
|
4579
|
-
|
|
4580
|
-
|
|
4581
|
-
|
|
4582
|
-
|
|
4583
|
-
|
|
4584
|
-
|
|
4585
|
-
|
|
4586
|
-
|
|
4587
|
-
|
|
4588
|
-
|
|
4589
|
-
|
|
4590
|
-
|
|
4591
|
-
|
|
4592
|
-
|
|
4593
|
-
|
|
4594
|
-
for await (const event of stream) {
|
|
4595
|
-
switch (event.type) {
|
|
4596
|
-
case "response.output_text.delta": {
|
|
4597
|
-
const delta = event.delta ?? "";
|
|
4598
|
-
pushDelta("response", typeof delta === "string" ? delta : "");
|
|
4599
|
-
break;
|
|
4600
|
-
}
|
|
4601
|
-
case "response.reasoning_summary_text.delta": {
|
|
4602
|
-
const delta = event.delta ?? "";
|
|
4603
|
-
pushDelta("thought", typeof delta === "string" ? delta : "");
|
|
4604
|
-
break;
|
|
4605
|
-
}
|
|
4606
|
-
case "response.refusal.delta": {
|
|
4607
|
-
blocked = true;
|
|
4608
|
-
queue.push({ type: "blocked" });
|
|
4609
|
-
break;
|
|
4610
|
-
}
|
|
4611
|
-
default:
|
|
4612
|
-
break;
|
|
4613
|
-
}
|
|
4614
|
-
}
|
|
4615
|
-
const finalResponse = await stream.finalResponse();
|
|
4616
|
-
modelVersion = typeof finalResponse.model === "string" ? finalResponse.model : request.model;
|
|
4617
|
-
queue.push({ type: "model", modelVersion });
|
|
4618
|
-
if (finalResponse.error) {
|
|
4619
|
-
const message = typeof finalResponse.error.message === "string" ? finalResponse.error.message : "OpenAI response failed";
|
|
4620
|
-
throw new Error(message);
|
|
4621
|
-
}
|
|
4622
|
-
if (finalResponse.status && finalResponse.status !== "completed" && finalResponse.status !== "in_progress") {
|
|
4623
|
-
const detail = finalResponse.incomplete_details?.reason;
|
|
4624
|
-
throw new Error(
|
|
4625
|
-
`OpenAI response status ${finalResponse.status}${detail ? ` (${detail})` : ""}`
|
|
5174
|
+
try {
|
|
5175
|
+
if (provider === "openai") {
|
|
5176
|
+
const openAiInput = toOpenAiInput(contents);
|
|
5177
|
+
const openAiTools = toOpenAiTools(request.tools);
|
|
5178
|
+
const reasoningEffort = resolveOpenAiReasoningEffort(modelForProvider, request.thinkingLevel);
|
|
5179
|
+
const openAiTextConfig = {
|
|
5180
|
+
format: request.openAiTextFormat ?? { type: "text" },
|
|
5181
|
+
verbosity: resolveOpenAiVerbosity(modelForProvider)
|
|
5182
|
+
};
|
|
5183
|
+
const reasoning = {
|
|
5184
|
+
effort: toOpenAiReasoningEffort(reasoningEffort),
|
|
5185
|
+
summary: "detailed"
|
|
5186
|
+
};
|
|
5187
|
+
await runOpenAiCall(async (client) => {
|
|
5188
|
+
const stream = client.responses.stream(
|
|
5189
|
+
{
|
|
5190
|
+
model: modelForProvider,
|
|
5191
|
+
input: openAiInput,
|
|
5192
|
+
reasoning,
|
|
5193
|
+
text: openAiTextConfig,
|
|
5194
|
+
...openAiTools ? { tools: openAiTools } : {},
|
|
5195
|
+
include: ["code_interpreter_call.outputs", "reasoning.encrypted_content"]
|
|
5196
|
+
},
|
|
5197
|
+
{ signal }
|
|
4626
5198
|
);
|
|
4627
|
-
|
|
4628
|
-
|
|
4629
|
-
|
|
4630
|
-
|
|
4631
|
-
|
|
4632
|
-
|
|
4633
|
-
|
|
4634
|
-
|
|
4635
|
-
|
|
4636
|
-
|
|
5199
|
+
for await (const event of stream) {
|
|
5200
|
+
switch (event.type) {
|
|
5201
|
+
case "response.output_text.delta": {
|
|
5202
|
+
const delta = event.delta ?? "";
|
|
5203
|
+
pushDelta("response", typeof delta === "string" ? delta : "");
|
|
5204
|
+
break;
|
|
5205
|
+
}
|
|
5206
|
+
case "response.reasoning_summary_text.delta": {
|
|
5207
|
+
const delta = event.delta ?? "";
|
|
5208
|
+
pushDelta("thought", typeof delta === "string" ? delta : "");
|
|
5209
|
+
break;
|
|
5210
|
+
}
|
|
5211
|
+
case "response.refusal.delta": {
|
|
5212
|
+
blocked = true;
|
|
5213
|
+
queue.push({ type: "blocked" });
|
|
5214
|
+
break;
|
|
5215
|
+
}
|
|
5216
|
+
default:
|
|
5217
|
+
break;
|
|
4637
5218
|
}
|
|
4638
5219
|
}
|
|
4639
|
-
|
|
4640
|
-
|
|
4641
|
-
|
|
4642
|
-
|
|
4643
|
-
|
|
4644
|
-
|
|
4645
|
-
const requestPayload = {
|
|
4646
|
-
model: modelForProvider,
|
|
4647
|
-
store: false,
|
|
4648
|
-
stream: true,
|
|
4649
|
-
instructions: chatGptInput.instructions ?? "You are a helpful assistant.",
|
|
4650
|
-
input: chatGptInput.input,
|
|
4651
|
-
include: ["reasoning.encrypted_content"],
|
|
4652
|
-
reasoning: { effort: toOpenAiReasoningEffort(reasoningEffort), summary: "detailed" },
|
|
4653
|
-
text: {
|
|
4654
|
-
format: request.openAiTextFormat ?? { type: "text" },
|
|
4655
|
-
verbosity: resolveOpenAiVerbosity(request.model)
|
|
4656
|
-
},
|
|
4657
|
-
...openAiTools ? { tools: openAiTools } : {}
|
|
4658
|
-
};
|
|
4659
|
-
let sawResponseDelta = false;
|
|
4660
|
-
let sawThoughtDelta = false;
|
|
4661
|
-
const result = await collectChatGptCodexResponseWithRetry({
|
|
4662
|
-
request: requestPayload,
|
|
4663
|
-
signal,
|
|
4664
|
-
onDelta: (delta) => {
|
|
4665
|
-
if (delta.thoughtDelta) {
|
|
4666
|
-
sawThoughtDelta = true;
|
|
4667
|
-
pushDelta("thought", delta.thoughtDelta);
|
|
5220
|
+
const finalResponse = await stream.finalResponse();
|
|
5221
|
+
modelVersion = typeof finalResponse.model === "string" ? finalResponse.model : request.model;
|
|
5222
|
+
queue.push({ type: "model", modelVersion });
|
|
5223
|
+
if (finalResponse.error) {
|
|
5224
|
+
const message = typeof finalResponse.error.message === "string" ? finalResponse.error.message : "OpenAI response failed";
|
|
5225
|
+
throw new Error(message);
|
|
4668
5226
|
}
|
|
4669
|
-
if (
|
|
4670
|
-
|
|
4671
|
-
|
|
5227
|
+
if (finalResponse.status && finalResponse.status !== "completed" && finalResponse.status !== "in_progress") {
|
|
5228
|
+
const detail = finalResponse.incomplete_details?.reason;
|
|
5229
|
+
throw new Error(
|
|
5230
|
+
`OpenAI response status ${finalResponse.status}${detail ? ` (${detail})` : ""}`
|
|
5231
|
+
);
|
|
4672
5232
|
}
|
|
4673
|
-
|
|
4674
|
-
|
|
4675
|
-
|
|
4676
|
-
|
|
4677
|
-
|
|
4678
|
-
|
|
4679
|
-
|
|
4680
|
-
|
|
4681
|
-
|
|
4682
|
-
|
|
4683
|
-
|
|
4684
|
-
const fallbackText = typeof result.text === "string" ? result.text : "";
|
|
4685
|
-
const fallbackThoughts = typeof result.reasoningSummaryText === "string" && result.reasoningSummaryText.length > 0 ? result.reasoningSummaryText : typeof result.reasoningText === "string" ? result.reasoningText : "";
|
|
4686
|
-
if (!sawThoughtDelta && fallbackThoughts.length > 0) {
|
|
4687
|
-
pushDelta("thought", fallbackThoughts);
|
|
4688
|
-
}
|
|
4689
|
-
if (!sawResponseDelta && fallbackText.length > 0) {
|
|
4690
|
-
pushDelta("response", fallbackText);
|
|
4691
|
-
}
|
|
4692
|
-
} else if (provider === "fireworks") {
|
|
4693
|
-
if (request.tools && request.tools.length > 0) {
|
|
4694
|
-
throw new Error(
|
|
4695
|
-
"Fireworks provider does not support provider-native tools in generateText; use runToolLoop for function tools."
|
|
4696
|
-
);
|
|
4697
|
-
}
|
|
4698
|
-
const fireworksMessages = toFireworksMessages(contents, {
|
|
4699
|
-
responseMimeType: request.responseMimeType,
|
|
4700
|
-
responseJsonSchema: request.responseJsonSchema
|
|
4701
|
-
});
|
|
4702
|
-
await runFireworksCall(async (client) => {
|
|
4703
|
-
const responseFormat = request.responseJsonSchema ? {
|
|
4704
|
-
type: "json_schema",
|
|
4705
|
-
json_schema: {
|
|
4706
|
-
name: "llm-response",
|
|
4707
|
-
schema: request.responseJsonSchema
|
|
5233
|
+
latestUsage = extractOpenAiUsageTokens(finalResponse.usage);
|
|
5234
|
+
if (responseParts.length === 0) {
|
|
5235
|
+
const fallback = extractOpenAiResponseParts(finalResponse);
|
|
5236
|
+
blocked = blocked || fallback.blocked;
|
|
5237
|
+
for (const part of fallback.parts) {
|
|
5238
|
+
if (part.type === "text") {
|
|
5239
|
+
pushDelta(part.thought === true ? "thought" : "response", part.text);
|
|
5240
|
+
} else {
|
|
5241
|
+
pushInline(part.data, part.mimeType);
|
|
5242
|
+
}
|
|
5243
|
+
}
|
|
4708
5244
|
}
|
|
4709
|
-
}
|
|
4710
|
-
|
|
4711
|
-
|
|
4712
|
-
|
|
4713
|
-
|
|
4714
|
-
|
|
5245
|
+
}, modelForProvider);
|
|
5246
|
+
} else if (provider === "chatgpt") {
|
|
5247
|
+
const chatGptInput = toChatGptInput(contents);
|
|
5248
|
+
const reasoningEffort = resolveOpenAiReasoningEffort(request.model, request.thinkingLevel);
|
|
5249
|
+
const openAiTools = toOpenAiTools(request.tools);
|
|
5250
|
+
const requestPayload = {
|
|
5251
|
+
model: modelForProvider,
|
|
5252
|
+
store: false,
|
|
5253
|
+
stream: true,
|
|
5254
|
+
...providerInfo.serviceTier ? { service_tier: providerInfo.serviceTier } : {},
|
|
5255
|
+
instructions: chatGptInput.instructions ?? "You are a helpful assistant.",
|
|
5256
|
+
input: chatGptInput.input,
|
|
5257
|
+
include: ["reasoning.encrypted_content"],
|
|
5258
|
+
reasoning: {
|
|
5259
|
+
effort: toOpenAiReasoningEffort(reasoningEffort),
|
|
5260
|
+
summary: "detailed"
|
|
4715
5261
|
},
|
|
4716
|
-
{
|
|
4717
|
-
|
|
4718
|
-
|
|
4719
|
-
|
|
4720
|
-
|
|
4721
|
-
|
|
4722
|
-
|
|
5262
|
+
text: {
|
|
5263
|
+
format: request.openAiTextFormat ?? { type: "text" },
|
|
5264
|
+
verbosity: resolveOpenAiVerbosity(request.model)
|
|
5265
|
+
},
|
|
5266
|
+
...openAiTools ? { tools: openAiTools } : {}
|
|
5267
|
+
};
|
|
5268
|
+
let sawResponseDelta = false;
|
|
5269
|
+
let sawThoughtDelta = false;
|
|
5270
|
+
const result = await collectChatGptCodexResponseWithRetry({
|
|
5271
|
+
request: requestPayload,
|
|
5272
|
+
signal,
|
|
5273
|
+
onDelta: (delta) => {
|
|
5274
|
+
if (delta.thoughtDelta) {
|
|
5275
|
+
sawThoughtDelta = true;
|
|
5276
|
+
pushDelta("thought", delta.thoughtDelta);
|
|
5277
|
+
}
|
|
5278
|
+
if (delta.textDelta) {
|
|
5279
|
+
sawResponseDelta = true;
|
|
5280
|
+
pushDelta("response", delta.textDelta);
|
|
5281
|
+
}
|
|
5282
|
+
}
|
|
5283
|
+
});
|
|
5284
|
+
blocked = blocked || result.blocked;
|
|
5285
|
+
if (blocked) {
|
|
4723
5286
|
queue.push({ type: "blocked" });
|
|
4724
5287
|
}
|
|
4725
|
-
|
|
4726
|
-
|
|
4727
|
-
|
|
4728
|
-
if (textOutput.length > 0) {
|
|
4729
|
-
pushDelta("response", textOutput);
|
|
5288
|
+
if (result.model) {
|
|
5289
|
+
modelVersion = providerInfo.serviceTier ? request.model : `chatgpt-${result.model}`;
|
|
5290
|
+
queue.push({ type: "model", modelVersion });
|
|
4730
5291
|
}
|
|
4731
|
-
latestUsage =
|
|
4732
|
-
|
|
4733
|
-
|
|
4734
|
-
|
|
4735
|
-
|
|
4736
|
-
|
|
4737
|
-
|
|
4738
|
-
|
|
4739
|
-
|
|
4740
|
-
|
|
4741
|
-
|
|
4742
|
-
|
|
4743
|
-
|
|
4744
|
-
|
|
4745
|
-
|
|
4746
|
-
|
|
4747
|
-
|
|
4748
|
-
|
|
4749
|
-
const geminiTools = toGeminiTools(request.tools);
|
|
4750
|
-
if (geminiTools) {
|
|
4751
|
-
config.tools = geminiTools;
|
|
4752
|
-
}
|
|
4753
|
-
await runGeminiCall(async (client) => {
|
|
4754
|
-
const stream = await client.models.generateContentStream({
|
|
4755
|
-
model: modelForProvider,
|
|
4756
|
-
contents: geminiContents,
|
|
4757
|
-
config
|
|
5292
|
+
latestUsage = extractChatGptUsageTokens(result.usage);
|
|
5293
|
+
const fallbackText = typeof result.text === "string" ? result.text : "";
|
|
5294
|
+
const fallbackThoughts = typeof result.reasoningSummaryText === "string" && result.reasoningSummaryText.length > 0 ? result.reasoningSummaryText : typeof result.reasoningText === "string" ? result.reasoningText : "";
|
|
5295
|
+
if (!sawThoughtDelta && fallbackThoughts.length > 0) {
|
|
5296
|
+
pushDelta("thought", fallbackThoughts);
|
|
5297
|
+
}
|
|
5298
|
+
if (!sawResponseDelta && fallbackText.length > 0) {
|
|
5299
|
+
pushDelta("response", fallbackText);
|
|
5300
|
+
}
|
|
5301
|
+
} else if (provider === "fireworks") {
|
|
5302
|
+
if (request.tools && request.tools.length > 0) {
|
|
5303
|
+
throw new Error(
|
|
5304
|
+
"Fireworks provider does not support provider-native tools in generateText; use runToolLoop for function tools."
|
|
5305
|
+
);
|
|
5306
|
+
}
|
|
5307
|
+
const fireworksMessages = toFireworksMessages(contents, {
|
|
5308
|
+
responseMimeType: request.responseMimeType,
|
|
5309
|
+
responseJsonSchema: request.responseJsonSchema
|
|
4758
5310
|
});
|
|
4759
|
-
|
|
4760
|
-
|
|
4761
|
-
|
|
4762
|
-
|
|
4763
|
-
|
|
4764
|
-
|
|
4765
|
-
|
|
5311
|
+
await runFireworksCall(async (client) => {
|
|
5312
|
+
const responseFormat = request.responseJsonSchema ? {
|
|
5313
|
+
type: "json_schema",
|
|
5314
|
+
json_schema: {
|
|
5315
|
+
name: "llm-response",
|
|
5316
|
+
schema: request.responseJsonSchema
|
|
5317
|
+
}
|
|
5318
|
+
} : request.responseMimeType === "application/json" ? { type: "json_object" } : void 0;
|
|
5319
|
+
const response = await client.chat.completions.create(
|
|
5320
|
+
{
|
|
5321
|
+
model: modelForProvider,
|
|
5322
|
+
messages: fireworksMessages,
|
|
5323
|
+
...responseFormat ? { response_format: responseFormat } : {}
|
|
5324
|
+
},
|
|
5325
|
+
{ signal }
|
|
5326
|
+
);
|
|
5327
|
+
modelVersion = typeof response.model === "string" ? response.model : request.model;
|
|
5328
|
+
queue.push({ type: "model", modelVersion });
|
|
5329
|
+
const choice = Array.isArray(response.choices) ? response.choices[0] : void 0;
|
|
5330
|
+
if (choice?.finish_reason === "content_filter") {
|
|
4766
5331
|
blocked = true;
|
|
4767
5332
|
queue.push({ type: "blocked" });
|
|
4768
5333
|
}
|
|
4769
|
-
|
|
4770
|
-
|
|
4771
|
-
|
|
4772
|
-
|
|
4773
|
-
|
|
4774
|
-
const primary = candidates[0];
|
|
4775
|
-
if (primary && isModerationFinish(primary.finishReason)) {
|
|
4776
|
-
blocked = true;
|
|
4777
|
-
queue.push({ type: "blocked" });
|
|
5334
|
+
const textOutput = extractFireworksMessageText(
|
|
5335
|
+
choice?.message
|
|
5336
|
+
);
|
|
5337
|
+
if (textOutput.length > 0) {
|
|
5338
|
+
pushDelta("response", textOutput);
|
|
4778
5339
|
}
|
|
4779
|
-
|
|
4780
|
-
|
|
4781
|
-
|
|
4782
|
-
|
|
5340
|
+
latestUsage = extractFireworksUsageTokens(response.usage);
|
|
5341
|
+
}, modelForProvider);
|
|
5342
|
+
} else {
|
|
5343
|
+
const geminiContents = contents.map(convertLlmContentToGeminiContent);
|
|
5344
|
+
const thinkingConfig = resolveGeminiThinkingConfig(modelForProvider, request.thinkingLevel);
|
|
5345
|
+
const config = {
|
|
5346
|
+
maxOutputTokens: 32e3,
|
|
5347
|
+
...thinkingConfig ? { thinkingConfig } : {},
|
|
5348
|
+
...request.responseMimeType ? { responseMimeType: request.responseMimeType } : {},
|
|
5349
|
+
...request.responseJsonSchema ? { responseJsonSchema: request.responseJsonSchema } : {},
|
|
5350
|
+
...request.responseModalities ? { responseModalities: Array.from(request.responseModalities) } : {},
|
|
5351
|
+
...request.imageAspectRatio || request.imageSize ? {
|
|
5352
|
+
imageConfig: {
|
|
5353
|
+
...request.imageAspectRatio ? { aspectRatio: request.imageAspectRatio } : {},
|
|
5354
|
+
...request.imageSize ? { imageSize: request.imageSize } : {}
|
|
4783
5355
|
}
|
|
4784
|
-
|
|
4785
|
-
|
|
5356
|
+
} : {}
|
|
5357
|
+
};
|
|
5358
|
+
const geminiTools = toGeminiTools(request.tools);
|
|
5359
|
+
if (geminiTools) {
|
|
5360
|
+
config.tools = geminiTools;
|
|
5361
|
+
}
|
|
5362
|
+
await runGeminiCall(async (client) => {
|
|
5363
|
+
const stream = await client.models.generateContentStream({
|
|
5364
|
+
model: modelForProvider,
|
|
5365
|
+
contents: geminiContents,
|
|
5366
|
+
config
|
|
5367
|
+
});
|
|
5368
|
+
let latestGrounding;
|
|
5369
|
+
for await (const chunk of stream) {
|
|
5370
|
+
if (chunk.modelVersion) {
|
|
5371
|
+
modelVersion = chunk.modelVersion;
|
|
5372
|
+
queue.push({ type: "model", modelVersion });
|
|
4786
5373
|
}
|
|
4787
|
-
|
|
4788
|
-
|
|
4789
|
-
|
|
5374
|
+
if (chunk.promptFeedback?.blockReason) {
|
|
5375
|
+
blocked = true;
|
|
5376
|
+
queue.push({ type: "blocked" });
|
|
4790
5377
|
}
|
|
4791
|
-
|
|
4792
|
-
|
|
4793
|
-
|
|
4794
|
-
|
|
4795
|
-
|
|
5378
|
+
latestUsage = mergeTokenUpdates(
|
|
5379
|
+
latestUsage,
|
|
5380
|
+
extractGeminiUsageTokens(chunk.usageMetadata)
|
|
5381
|
+
);
|
|
5382
|
+
const candidates = chunk.candidates;
|
|
5383
|
+
if (!candidates || candidates.length === 0) {
|
|
5384
|
+
continue;
|
|
5385
|
+
}
|
|
5386
|
+
const primary = candidates[0];
|
|
5387
|
+
if (primary && isModerationFinish(primary.finishReason)) {
|
|
5388
|
+
blocked = true;
|
|
5389
|
+
queue.push({ type: "blocked" });
|
|
5390
|
+
}
|
|
5391
|
+
for (const candidate of candidates) {
|
|
5392
|
+
const candidateContent = candidate.content;
|
|
5393
|
+
if (!candidateContent) {
|
|
5394
|
+
continue;
|
|
5395
|
+
}
|
|
5396
|
+
if (candidate.groundingMetadata) {
|
|
5397
|
+
latestGrounding = candidate.groundingMetadata;
|
|
5398
|
+
}
|
|
5399
|
+
const content2 = convertGeminiContentToLlmContent(candidateContent);
|
|
5400
|
+
if (!responseRole) {
|
|
5401
|
+
responseRole = content2.role;
|
|
5402
|
+
}
|
|
5403
|
+
for (const part of content2.parts) {
|
|
5404
|
+
if (part.type === "text") {
|
|
5405
|
+
pushDelta(part.thought === true ? "thought" : "response", part.text);
|
|
5406
|
+
} else {
|
|
5407
|
+
pushInline(part.data, part.mimeType);
|
|
5408
|
+
}
|
|
4796
5409
|
}
|
|
4797
5410
|
}
|
|
4798
5411
|
}
|
|
4799
|
-
|
|
4800
|
-
|
|
4801
|
-
}
|
|
4802
|
-
|
|
4803
|
-
|
|
4804
|
-
|
|
4805
|
-
|
|
4806
|
-
|
|
4807
|
-
|
|
4808
|
-
|
|
4809
|
-
|
|
4810
|
-
|
|
4811
|
-
|
|
4812
|
-
|
|
4813
|
-
|
|
5412
|
+
grounding = latestGrounding;
|
|
5413
|
+
}, modelForProvider);
|
|
5414
|
+
}
|
|
5415
|
+
const mergedParts = mergeConsecutiveTextParts(responseParts);
|
|
5416
|
+
const content = mergedParts.length > 0 ? { role: responseRole ?? "assistant", parts: mergedParts } : void 0;
|
|
5417
|
+
const { text, thoughts } = extractTextByChannel(content);
|
|
5418
|
+
const costUsd = estimateCallCostUsd({
|
|
5419
|
+
modelId: modelVersion,
|
|
5420
|
+
tokens: latestUsage,
|
|
5421
|
+
responseImages,
|
|
5422
|
+
imageSize: request.imageSize
|
|
5423
|
+
});
|
|
5424
|
+
if (latestUsage) {
|
|
5425
|
+
queue.push({ type: "usage", usage: latestUsage, costUsd, modelVersion });
|
|
5426
|
+
}
|
|
5427
|
+
callLogger?.complete({
|
|
5428
|
+
provider,
|
|
5429
|
+
model: request.model,
|
|
5430
|
+
modelVersion,
|
|
5431
|
+
blocked,
|
|
5432
|
+
costUsd,
|
|
5433
|
+
usage: latestUsage,
|
|
5434
|
+
grounding: grounding ? sanitiseLogValue(grounding) : void 0,
|
|
5435
|
+
responseChars: text.length,
|
|
5436
|
+
thoughtChars: thoughts.length,
|
|
5437
|
+
responseImages
|
|
5438
|
+
});
|
|
5439
|
+
return {
|
|
5440
|
+
provider,
|
|
5441
|
+
model: request.model,
|
|
5442
|
+
modelVersion,
|
|
5443
|
+
content,
|
|
5444
|
+
text,
|
|
5445
|
+
thoughts,
|
|
5446
|
+
blocked,
|
|
5447
|
+
usage: latestUsage,
|
|
5448
|
+
costUsd,
|
|
5449
|
+
grounding
|
|
5450
|
+
};
|
|
5451
|
+
} catch (error) {
|
|
5452
|
+
callLogger?.fail(error, {
|
|
5453
|
+
provider,
|
|
5454
|
+
model: request.model,
|
|
5455
|
+
modelVersion,
|
|
5456
|
+
blocked,
|
|
5457
|
+
usage: latestUsage,
|
|
5458
|
+
partialResponseParts: responseParts.length,
|
|
5459
|
+
responseImages
|
|
5460
|
+
});
|
|
5461
|
+
throw error;
|
|
4814
5462
|
}
|
|
4815
|
-
return {
|
|
4816
|
-
provider,
|
|
4817
|
-
model: request.model,
|
|
4818
|
-
modelVersion,
|
|
4819
|
-
content,
|
|
4820
|
-
text,
|
|
4821
|
-
thoughts,
|
|
4822
|
-
blocked,
|
|
4823
|
-
usage: latestUsage,
|
|
4824
|
-
costUsd,
|
|
4825
|
-
grounding
|
|
4826
|
-
};
|
|
4827
5463
|
}
|
|
4828
5464
|
function streamText(request) {
|
|
4829
5465
|
const queue = createAsyncQueue();
|
|
@@ -5286,6 +5922,23 @@ async function runToolLoop(request) {
|
|
|
5286
5922
|
let modelVersion = request.model;
|
|
5287
5923
|
let usageTokens;
|
|
5288
5924
|
let thoughtDeltaEmitted = false;
|
|
5925
|
+
let blocked = false;
|
|
5926
|
+
const stepRequestPayload = {
|
|
5927
|
+
model: providerInfo.model,
|
|
5928
|
+
input,
|
|
5929
|
+
...previousResponseId ? { previous_response_id: previousResponseId } : {},
|
|
5930
|
+
...openAiTools.length > 0 ? { tools: openAiTools } : {},
|
|
5931
|
+
...openAiTools.length > 0 ? { parallel_tool_calls: true } : {},
|
|
5932
|
+
reasoning,
|
|
5933
|
+
text: textConfig,
|
|
5934
|
+
include: ["reasoning.encrypted_content"]
|
|
5935
|
+
};
|
|
5936
|
+
const stepCallLogger = startLlmCallLoggerFromPayload({
|
|
5937
|
+
provider: "openai",
|
|
5938
|
+
modelId: request.model,
|
|
5939
|
+
requestPayload: stepRequestPayload,
|
|
5940
|
+
step: turn
|
|
5941
|
+
});
|
|
5289
5942
|
const emitEvent = (ev) => {
|
|
5290
5943
|
onEvent?.(ev);
|
|
5291
5944
|
};
|
|
@@ -5294,226 +5947,276 @@ async function runToolLoop(request) {
|
|
|
5294
5947
|
firstModelEventAtMs = Date.now();
|
|
5295
5948
|
}
|
|
5296
5949
|
};
|
|
5297
|
-
|
|
5298
|
-
|
|
5299
|
-
|
|
5300
|
-
|
|
5301
|
-
|
|
5302
|
-
|
|
5303
|
-
|
|
5304
|
-
|
|
5305
|
-
|
|
5306
|
-
|
|
5307
|
-
|
|
5308
|
-
|
|
5309
|
-
|
|
5310
|
-
|
|
5311
|
-
|
|
5312
|
-
|
|
5313
|
-
|
|
5314
|
-
|
|
5315
|
-
|
|
5316
|
-
|
|
5317
|
-
|
|
5318
|
-
|
|
5319
|
-
|
|
5320
|
-
|
|
5321
|
-
|
|
5322
|
-
|
|
5323
|
-
|
|
5324
|
-
|
|
5325
|
-
|
|
5326
|
-
|
|
5327
|
-
|
|
5328
|
-
|
|
5329
|
-
|
|
5330
|
-
|
|
5331
|
-
|
|
5332
|
-
|
|
5333
|
-
|
|
5334
|
-
|
|
5950
|
+
try {
|
|
5951
|
+
const finalResponse = await runOpenAiCall(
|
|
5952
|
+
async (client) => {
|
|
5953
|
+
const stream = client.responses.stream(
|
|
5954
|
+
{
|
|
5955
|
+
model: providerInfo.model,
|
|
5956
|
+
input,
|
|
5957
|
+
...previousResponseId ? { previous_response_id: previousResponseId } : {},
|
|
5958
|
+
...openAiTools.length > 0 ? { tools: openAiTools } : {},
|
|
5959
|
+
...openAiTools.length > 0 ? { parallel_tool_calls: true } : {},
|
|
5960
|
+
reasoning,
|
|
5961
|
+
text: textConfig,
|
|
5962
|
+
include: ["reasoning.encrypted_content"]
|
|
5963
|
+
},
|
|
5964
|
+
{ signal: abortController.signal }
|
|
5965
|
+
);
|
|
5966
|
+
for await (const event of stream) {
|
|
5967
|
+
markFirstModelEvent();
|
|
5968
|
+
switch (event.type) {
|
|
5969
|
+
case "response.output_text.delta": {
|
|
5970
|
+
const text = typeof event.delta === "string" ? event.delta : "";
|
|
5971
|
+
if (text.length > 0) {
|
|
5972
|
+
stepCallLogger?.appendResponseDelta(text);
|
|
5973
|
+
}
|
|
5974
|
+
emitEvent({
|
|
5975
|
+
type: "delta",
|
|
5976
|
+
channel: "response",
|
|
5977
|
+
text
|
|
5978
|
+
});
|
|
5979
|
+
break;
|
|
5980
|
+
}
|
|
5981
|
+
case "response.reasoning_summary_text.delta": {
|
|
5982
|
+
thoughtDeltaEmitted = true;
|
|
5983
|
+
const text = typeof event.delta === "string" ? event.delta : "";
|
|
5984
|
+
if (text.length > 0) {
|
|
5985
|
+
stepCallLogger?.appendThoughtDelta(text);
|
|
5986
|
+
}
|
|
5987
|
+
emitEvent({
|
|
5988
|
+
type: "delta",
|
|
5989
|
+
channel: "thought",
|
|
5990
|
+
text
|
|
5991
|
+
});
|
|
5992
|
+
break;
|
|
5993
|
+
}
|
|
5994
|
+
case "response.refusal.delta":
|
|
5995
|
+
blocked = true;
|
|
5996
|
+
emitEvent({ type: "blocked" });
|
|
5997
|
+
break;
|
|
5998
|
+
default:
|
|
5999
|
+
break;
|
|
6000
|
+
}
|
|
6001
|
+
}
|
|
6002
|
+
return await stream.finalResponse();
|
|
6003
|
+
},
|
|
6004
|
+
providerInfo.model,
|
|
6005
|
+
{
|
|
6006
|
+
onSettled: (metrics) => {
|
|
6007
|
+
schedulerMetrics = metrics;
|
|
5335
6008
|
}
|
|
5336
6009
|
}
|
|
5337
|
-
|
|
5338
|
-
|
|
5339
|
-
|
|
5340
|
-
{
|
|
5341
|
-
|
|
5342
|
-
|
|
6010
|
+
);
|
|
6011
|
+
modelVersion = typeof finalResponse.model === "string" ? finalResponse.model : request.model;
|
|
6012
|
+
emitEvent({ type: "model", modelVersion });
|
|
6013
|
+
if (finalResponse.error) {
|
|
6014
|
+
const message = typeof finalResponse.error.message === "string" ? finalResponse.error.message : "OpenAI response failed";
|
|
6015
|
+
throw new Error(message);
|
|
6016
|
+
}
|
|
6017
|
+
usageTokens = extractOpenAiUsageTokens(finalResponse.usage);
|
|
6018
|
+
const responseText = extractOpenAiResponseParts(finalResponse).parts.filter((p) => p.type === "text" && p.thought !== true).map((p) => p.text).join("").trim();
|
|
6019
|
+
const reasoningSummary = extractOpenAiReasoningSummary(finalResponse).trim();
|
|
6020
|
+
if (!thoughtDeltaEmitted && reasoningSummary.length > 0) {
|
|
6021
|
+
stepCallLogger?.appendThoughtDelta(reasoningSummary);
|
|
6022
|
+
emitEvent({ type: "delta", channel: "thought", text: reasoningSummary });
|
|
6023
|
+
}
|
|
6024
|
+
const modelCompletedAtMs = Date.now();
|
|
6025
|
+
const stepCostUsd = estimateCallCostUsd({
|
|
6026
|
+
modelId: modelVersion,
|
|
6027
|
+
tokens: usageTokens,
|
|
6028
|
+
responseImages: 0
|
|
6029
|
+
});
|
|
6030
|
+
totalCostUsd += stepCostUsd;
|
|
6031
|
+
if (usageTokens) {
|
|
6032
|
+
emitEvent({ type: "usage", usage: usageTokens, costUsd: stepCostUsd, modelVersion });
|
|
6033
|
+
}
|
|
6034
|
+
const responseToolCalls = extractOpenAiToolCalls(finalResponse.output);
|
|
6035
|
+
const stepToolCalls = [];
|
|
6036
|
+
if (responseToolCalls.length === 0) {
|
|
6037
|
+
const steeringInput2 = steeringInternal?.drainPendingContents() ?? [];
|
|
6038
|
+
const steeringItems2 = steeringInput2.length > 0 ? toOpenAiInput(steeringInput2) : [];
|
|
6039
|
+
finalText = responseText;
|
|
6040
|
+
finalThoughts = reasoningSummary;
|
|
6041
|
+
const stepCompletedAtMs2 = Date.now();
|
|
6042
|
+
const timing2 = buildStepTiming({
|
|
6043
|
+
stepStartedAtMs,
|
|
6044
|
+
stepCompletedAtMs: stepCompletedAtMs2,
|
|
6045
|
+
modelCompletedAtMs,
|
|
6046
|
+
firstModelEventAtMs,
|
|
6047
|
+
schedulerMetrics,
|
|
6048
|
+
toolExecutionMs: 0,
|
|
6049
|
+
waitToolMs: 0
|
|
6050
|
+
});
|
|
6051
|
+
steps.push({
|
|
6052
|
+
step: steps.length + 1,
|
|
6053
|
+
modelVersion,
|
|
6054
|
+
text: responseText || void 0,
|
|
6055
|
+
thoughts: reasoningSummary || void 0,
|
|
6056
|
+
toolCalls: [],
|
|
6057
|
+
usage: usageTokens,
|
|
6058
|
+
costUsd: stepCostUsd,
|
|
6059
|
+
timing: timing2
|
|
6060
|
+
});
|
|
6061
|
+
stepCallLogger?.complete({
|
|
6062
|
+
provider: "openai",
|
|
6063
|
+
model: request.model,
|
|
6064
|
+
modelVersion,
|
|
6065
|
+
step: turn,
|
|
6066
|
+
usage: usageTokens,
|
|
6067
|
+
costUsd: stepCostUsd,
|
|
6068
|
+
blocked,
|
|
6069
|
+
responseChars: responseText.length,
|
|
6070
|
+
thoughtChars: reasoningSummary.length,
|
|
6071
|
+
toolCalls: 0,
|
|
6072
|
+
finalStep: steeringItems2.length === 0
|
|
6073
|
+
});
|
|
6074
|
+
if (steeringItems2.length === 0) {
|
|
6075
|
+
return { text: finalText, thoughts: finalThoughts, steps, totalCostUsd };
|
|
5343
6076
|
}
|
|
6077
|
+
previousResponseId = finalResponse.id;
|
|
6078
|
+
input = steeringItems2;
|
|
6079
|
+
continue;
|
|
5344
6080
|
}
|
|
5345
|
-
|
|
5346
|
-
|
|
5347
|
-
|
|
5348
|
-
|
|
5349
|
-
|
|
5350
|
-
|
|
5351
|
-
|
|
5352
|
-
|
|
5353
|
-
|
|
5354
|
-
|
|
5355
|
-
|
|
5356
|
-
|
|
5357
|
-
|
|
5358
|
-
|
|
5359
|
-
|
|
5360
|
-
|
|
5361
|
-
|
|
5362
|
-
|
|
5363
|
-
|
|
5364
|
-
|
|
5365
|
-
|
|
5366
|
-
|
|
5367
|
-
|
|
5368
|
-
|
|
5369
|
-
|
|
5370
|
-
|
|
5371
|
-
|
|
5372
|
-
|
|
5373
|
-
|
|
5374
|
-
|
|
5375
|
-
|
|
5376
|
-
const
|
|
6081
|
+
const callInputs = responseToolCalls.map((call, index) => {
|
|
6082
|
+
const toolIndex = index + 1;
|
|
6083
|
+
const toolId = buildToolLogId(turn, toolIndex);
|
|
6084
|
+
const toolName = call.name;
|
|
6085
|
+
if (call.kind === "custom") {
|
|
6086
|
+
return {
|
|
6087
|
+
call,
|
|
6088
|
+
toolName,
|
|
6089
|
+
value: call.input,
|
|
6090
|
+
parseError: void 0,
|
|
6091
|
+
toolId,
|
|
6092
|
+
turn,
|
|
6093
|
+
toolIndex
|
|
6094
|
+
};
|
|
6095
|
+
}
|
|
6096
|
+
const { value, error: parseError } = parseOpenAiToolArguments(call.arguments);
|
|
6097
|
+
return { call, toolName, value, parseError, toolId, turn, toolIndex };
|
|
6098
|
+
});
|
|
6099
|
+
for (const entry of callInputs) {
|
|
6100
|
+
emitEvent({
|
|
6101
|
+
type: "tool_call",
|
|
6102
|
+
phase: "started",
|
|
6103
|
+
turn: entry.turn,
|
|
6104
|
+
toolIndex: entry.toolIndex,
|
|
6105
|
+
toolName: entry.toolName,
|
|
6106
|
+
toolId: entry.toolId,
|
|
6107
|
+
callKind: entry.call.kind,
|
|
6108
|
+
callId: entry.call.call_id,
|
|
6109
|
+
input: entry.value
|
|
6110
|
+
});
|
|
6111
|
+
}
|
|
6112
|
+
const callResults = await Promise.all(
|
|
6113
|
+
callInputs.map(async (entry) => {
|
|
6114
|
+
return await toolCallContextStorage.run(
|
|
6115
|
+
{
|
|
6116
|
+
toolName: entry.toolName,
|
|
6117
|
+
toolId: entry.toolId,
|
|
6118
|
+
turn: entry.turn,
|
|
6119
|
+
toolIndex: entry.toolIndex
|
|
6120
|
+
},
|
|
6121
|
+
async () => {
|
|
6122
|
+
const { result, outputPayload } = await executeToolCall({
|
|
6123
|
+
callKind: entry.call.kind,
|
|
6124
|
+
toolName: entry.toolName,
|
|
6125
|
+
tool: request.tools[entry.toolName],
|
|
6126
|
+
rawInput: entry.value,
|
|
6127
|
+
parseError: entry.parseError
|
|
6128
|
+
});
|
|
6129
|
+
return { entry, result, outputPayload };
|
|
6130
|
+
}
|
|
6131
|
+
);
|
|
6132
|
+
})
|
|
6133
|
+
);
|
|
6134
|
+
const toolOutputs = [];
|
|
6135
|
+
let toolExecutionMs = 0;
|
|
6136
|
+
let waitToolMs = 0;
|
|
6137
|
+
for (const { entry, result, outputPayload } of callResults) {
|
|
6138
|
+
stepToolCalls.push({ ...result, callId: entry.call.call_id });
|
|
6139
|
+
const callDurationMs = toToolResultDuration(result);
|
|
6140
|
+
toolExecutionMs += callDurationMs;
|
|
6141
|
+
if (entry.toolName.toLowerCase() === SUBAGENT_WAIT_TOOL_NAME) {
|
|
6142
|
+
waitToolMs += callDurationMs;
|
|
6143
|
+
}
|
|
6144
|
+
emitEvent({
|
|
6145
|
+
type: "tool_call",
|
|
6146
|
+
phase: "completed",
|
|
6147
|
+
turn: entry.turn,
|
|
6148
|
+
toolIndex: entry.toolIndex,
|
|
6149
|
+
toolName: entry.toolName,
|
|
6150
|
+
toolId: entry.toolId,
|
|
6151
|
+
callKind: entry.call.kind,
|
|
6152
|
+
callId: entry.call.call_id,
|
|
6153
|
+
input: entry.value,
|
|
6154
|
+
output: result.output,
|
|
6155
|
+
error: result.error,
|
|
6156
|
+
durationMs: result.durationMs
|
|
6157
|
+
});
|
|
6158
|
+
if (entry.call.kind === "custom") {
|
|
6159
|
+
toolOutputs.push({
|
|
6160
|
+
type: "custom_tool_call_output",
|
|
6161
|
+
call_id: entry.call.call_id,
|
|
6162
|
+
output: toOpenAiToolOutput(outputPayload)
|
|
6163
|
+
});
|
|
6164
|
+
} else {
|
|
6165
|
+
toolOutputs.push({
|
|
6166
|
+
type: "function_call_output",
|
|
6167
|
+
call_id: entry.call.call_id,
|
|
6168
|
+
output: toOpenAiToolOutput(outputPayload)
|
|
6169
|
+
});
|
|
6170
|
+
}
|
|
6171
|
+
}
|
|
6172
|
+
const stepCompletedAtMs = Date.now();
|
|
6173
|
+
const timing = buildStepTiming({
|
|
5377
6174
|
stepStartedAtMs,
|
|
5378
|
-
stepCompletedAtMs
|
|
6175
|
+
stepCompletedAtMs,
|
|
5379
6176
|
modelCompletedAtMs,
|
|
5380
6177
|
firstModelEventAtMs,
|
|
5381
6178
|
schedulerMetrics,
|
|
5382
|
-
toolExecutionMs
|
|
5383
|
-
waitToolMs
|
|
6179
|
+
toolExecutionMs,
|
|
6180
|
+
waitToolMs
|
|
5384
6181
|
});
|
|
5385
6182
|
steps.push({
|
|
5386
6183
|
step: steps.length + 1,
|
|
5387
6184
|
modelVersion,
|
|
5388
6185
|
text: responseText || void 0,
|
|
5389
6186
|
thoughts: reasoningSummary || void 0,
|
|
5390
|
-
toolCalls:
|
|
6187
|
+
toolCalls: stepToolCalls,
|
|
5391
6188
|
usage: usageTokens,
|
|
5392
6189
|
costUsd: stepCostUsd,
|
|
5393
|
-
timing
|
|
6190
|
+
timing
|
|
5394
6191
|
});
|
|
5395
|
-
|
|
5396
|
-
|
|
5397
|
-
|
|
5398
|
-
|
|
5399
|
-
|
|
5400
|
-
|
|
5401
|
-
|
|
5402
|
-
|
|
5403
|
-
|
|
5404
|
-
|
|
5405
|
-
|
|
5406
|
-
|
|
5407
|
-
|
|
5408
|
-
|
|
5409
|
-
toolName,
|
|
5410
|
-
value: call.input,
|
|
5411
|
-
parseError: void 0,
|
|
5412
|
-
toolId,
|
|
5413
|
-
turn,
|
|
5414
|
-
toolIndex
|
|
5415
|
-
};
|
|
5416
|
-
}
|
|
5417
|
-
const { value, error: parseError } = parseOpenAiToolArguments(call.arguments);
|
|
5418
|
-
return { call, toolName, value, parseError, toolId, turn, toolIndex };
|
|
5419
|
-
});
|
|
5420
|
-
for (const entry of callInputs) {
|
|
5421
|
-
emitEvent({
|
|
5422
|
-
type: "tool_call",
|
|
5423
|
-
phase: "started",
|
|
5424
|
-
turn: entry.turn,
|
|
5425
|
-
toolIndex: entry.toolIndex,
|
|
5426
|
-
toolName: entry.toolName,
|
|
5427
|
-
toolId: entry.toolId,
|
|
5428
|
-
callKind: entry.call.kind,
|
|
5429
|
-
callId: entry.call.call_id,
|
|
5430
|
-
input: entry.value
|
|
6192
|
+
const steeringInput = steeringInternal?.drainPendingContents() ?? [];
|
|
6193
|
+
const steeringItems = steeringInput.length > 0 ? toOpenAiInput(steeringInput) : [];
|
|
6194
|
+
stepCallLogger?.complete({
|
|
6195
|
+
provider: "openai",
|
|
6196
|
+
model: request.model,
|
|
6197
|
+
modelVersion,
|
|
6198
|
+
step: turn,
|
|
6199
|
+
usage: usageTokens,
|
|
6200
|
+
costUsd: stepCostUsd,
|
|
6201
|
+
blocked,
|
|
6202
|
+
responseChars: responseText.length,
|
|
6203
|
+
thoughtChars: reasoningSummary.length,
|
|
6204
|
+
toolCalls: stepToolCalls.length,
|
|
6205
|
+
finalStep: false
|
|
5431
6206
|
});
|
|
5432
|
-
|
|
5433
|
-
|
|
5434
|
-
|
|
5435
|
-
|
|
5436
|
-
|
|
5437
|
-
|
|
5438
|
-
|
|
5439
|
-
|
|
5440
|
-
|
|
5441
|
-
|
|
5442
|
-
async () => {
|
|
5443
|
-
const { result, outputPayload } = await executeToolCall({
|
|
5444
|
-
callKind: entry.call.kind,
|
|
5445
|
-
toolName: entry.toolName,
|
|
5446
|
-
tool: request.tools[entry.toolName],
|
|
5447
|
-
rawInput: entry.value,
|
|
5448
|
-
parseError: entry.parseError
|
|
5449
|
-
});
|
|
5450
|
-
return { entry, result, outputPayload };
|
|
5451
|
-
}
|
|
5452
|
-
);
|
|
5453
|
-
})
|
|
5454
|
-
);
|
|
5455
|
-
const toolOutputs = [];
|
|
5456
|
-
let toolExecutionMs = 0;
|
|
5457
|
-
let waitToolMs = 0;
|
|
5458
|
-
for (const { entry, result, outputPayload } of callResults) {
|
|
5459
|
-
stepToolCalls.push({ ...result, callId: entry.call.call_id });
|
|
5460
|
-
const callDurationMs = toToolResultDuration(result);
|
|
5461
|
-
toolExecutionMs += callDurationMs;
|
|
5462
|
-
if (entry.toolName.toLowerCase() === SUBAGENT_WAIT_TOOL_NAME) {
|
|
5463
|
-
waitToolMs += callDurationMs;
|
|
5464
|
-
}
|
|
5465
|
-
emitEvent({
|
|
5466
|
-
type: "tool_call",
|
|
5467
|
-
phase: "completed",
|
|
5468
|
-
turn: entry.turn,
|
|
5469
|
-
toolIndex: entry.toolIndex,
|
|
5470
|
-
toolName: entry.toolName,
|
|
5471
|
-
toolId: entry.toolId,
|
|
5472
|
-
callKind: entry.call.kind,
|
|
5473
|
-
callId: entry.call.call_id,
|
|
5474
|
-
input: entry.value,
|
|
5475
|
-
output: result.output,
|
|
5476
|
-
error: result.error,
|
|
5477
|
-
durationMs: result.durationMs
|
|
6207
|
+
previousResponseId = finalResponse.id;
|
|
6208
|
+
input = steeringItems.length > 0 ? toolOutputs.concat(steeringItems) : toolOutputs;
|
|
6209
|
+
} catch (error) {
|
|
6210
|
+
stepCallLogger?.fail(error, {
|
|
6211
|
+
provider: "openai",
|
|
6212
|
+
model: request.model,
|
|
6213
|
+
modelVersion,
|
|
6214
|
+
step: turn,
|
|
6215
|
+
usage: usageTokens,
|
|
6216
|
+
blocked
|
|
5478
6217
|
});
|
|
5479
|
-
|
|
5480
|
-
toolOutputs.push({
|
|
5481
|
-
type: "custom_tool_call_output",
|
|
5482
|
-
call_id: entry.call.call_id,
|
|
5483
|
-
output: toOpenAiToolOutput(outputPayload)
|
|
5484
|
-
});
|
|
5485
|
-
} else {
|
|
5486
|
-
toolOutputs.push({
|
|
5487
|
-
type: "function_call_output",
|
|
5488
|
-
call_id: entry.call.call_id,
|
|
5489
|
-
output: toOpenAiToolOutput(outputPayload)
|
|
5490
|
-
});
|
|
5491
|
-
}
|
|
6218
|
+
throw error;
|
|
5492
6219
|
}
|
|
5493
|
-
const stepCompletedAtMs = Date.now();
|
|
5494
|
-
const timing = buildStepTiming({
|
|
5495
|
-
stepStartedAtMs,
|
|
5496
|
-
stepCompletedAtMs,
|
|
5497
|
-
modelCompletedAtMs,
|
|
5498
|
-
firstModelEventAtMs,
|
|
5499
|
-
schedulerMetrics,
|
|
5500
|
-
toolExecutionMs,
|
|
5501
|
-
waitToolMs
|
|
5502
|
-
});
|
|
5503
|
-
steps.push({
|
|
5504
|
-
step: steps.length + 1,
|
|
5505
|
-
modelVersion,
|
|
5506
|
-
text: responseText || void 0,
|
|
5507
|
-
thoughts: reasoningSummary || void 0,
|
|
5508
|
-
toolCalls: stepToolCalls,
|
|
5509
|
-
usage: usageTokens,
|
|
5510
|
-
costUsd: stepCostUsd,
|
|
5511
|
-
timing
|
|
5512
|
-
});
|
|
5513
|
-
const steeringInput = steeringInternal?.drainPendingContents() ?? [];
|
|
5514
|
-
const steeringItems = steeringInput.length > 0 ? toOpenAiInput(steeringInput) : [];
|
|
5515
|
-
previousResponseId = finalResponse.id;
|
|
5516
|
-
input = steeringItems.length > 0 ? toolOutputs.concat(steeringItems) : toolOutputs;
|
|
5517
6220
|
}
|
|
5518
6221
|
throw new Error(`Tool loop exceeded max steps (${maxSteps}) without final response.`);
|
|
5519
6222
|
}
|
|
@@ -5531,242 +6234,656 @@ async function runToolLoop(request) {
|
|
|
5531
6234
|
const stepStartedAtMs = Date.now();
|
|
5532
6235
|
let firstModelEventAtMs;
|
|
5533
6236
|
let thoughtDeltaEmitted = false;
|
|
6237
|
+
let sawResponseDelta = false;
|
|
6238
|
+
let modelVersion = request.model;
|
|
6239
|
+
let usageTokens;
|
|
6240
|
+
let responseText = "";
|
|
6241
|
+
let reasoningSummaryText = "";
|
|
5534
6242
|
const markFirstModelEvent = () => {
|
|
5535
6243
|
if (firstModelEventAtMs === void 0) {
|
|
5536
6244
|
firstModelEventAtMs = Date.now();
|
|
5537
6245
|
}
|
|
5538
6246
|
};
|
|
5539
|
-
const
|
|
5540
|
-
|
|
5541
|
-
|
|
5542
|
-
|
|
5543
|
-
|
|
5544
|
-
|
|
5545
|
-
|
|
5546
|
-
|
|
5547
|
-
|
|
5548
|
-
|
|
5549
|
-
|
|
5550
|
-
|
|
5551
|
-
|
|
5552
|
-
|
|
5553
|
-
|
|
5554
|
-
summary: "detailed"
|
|
5555
|
-
},
|
|
5556
|
-
text: { verbosity: resolveOpenAiVerbosity(request.model) }
|
|
6247
|
+
const stepRequestPayload = {
|
|
6248
|
+
model: providerInfo.model,
|
|
6249
|
+
store: false,
|
|
6250
|
+
stream: true,
|
|
6251
|
+
...providerInfo.serviceTier ? { service_tier: providerInfo.serviceTier } : {},
|
|
6252
|
+
instructions: toolLoopInput.instructions ?? "You are a helpful assistant.",
|
|
6253
|
+
input,
|
|
6254
|
+
prompt_cache_key: promptCacheKey,
|
|
6255
|
+
include: ["reasoning.encrypted_content"],
|
|
6256
|
+
tools: openAiTools,
|
|
6257
|
+
tool_choice: "auto",
|
|
6258
|
+
parallel_tool_calls: true,
|
|
6259
|
+
reasoning: {
|
|
6260
|
+
effort: toOpenAiReasoningEffort(reasoningEffort),
|
|
6261
|
+
summary: "detailed"
|
|
5557
6262
|
},
|
|
5558
|
-
|
|
5559
|
-
|
|
5560
|
-
|
|
5561
|
-
|
|
5562
|
-
|
|
5563
|
-
|
|
6263
|
+
text: { verbosity: resolveOpenAiVerbosity(request.model) }
|
|
6264
|
+
};
|
|
6265
|
+
const stepCallLogger = startLlmCallLoggerFromPayload({
|
|
6266
|
+
provider: "chatgpt",
|
|
6267
|
+
modelId: request.model,
|
|
6268
|
+
requestPayload: stepRequestPayload,
|
|
6269
|
+
step: turn
|
|
6270
|
+
});
|
|
6271
|
+
try {
|
|
6272
|
+
const response = await collectChatGptCodexResponseWithRetry({
|
|
6273
|
+
sessionId: conversationId,
|
|
6274
|
+
request: stepRequestPayload,
|
|
6275
|
+
signal: request.signal,
|
|
6276
|
+
onDelta: (delta) => {
|
|
6277
|
+
if (delta.thoughtDelta) {
|
|
6278
|
+
markFirstModelEvent();
|
|
6279
|
+
thoughtDeltaEmitted = true;
|
|
6280
|
+
stepCallLogger?.appendThoughtDelta(delta.thoughtDelta);
|
|
6281
|
+
request.onEvent?.({ type: "delta", channel: "thought", text: delta.thoughtDelta });
|
|
6282
|
+
}
|
|
6283
|
+
if (delta.textDelta) {
|
|
6284
|
+
markFirstModelEvent();
|
|
6285
|
+
sawResponseDelta = true;
|
|
6286
|
+
stepCallLogger?.appendResponseDelta(delta.textDelta);
|
|
6287
|
+
request.onEvent?.({ type: "delta", channel: "response", text: delta.textDelta });
|
|
6288
|
+
}
|
|
5564
6289
|
}
|
|
5565
|
-
|
|
5566
|
-
|
|
5567
|
-
|
|
6290
|
+
});
|
|
6291
|
+
const modelCompletedAtMs = Date.now();
|
|
6292
|
+
modelVersion = response.model && !providerInfo.serviceTier ? `chatgpt-${response.model}` : request.model;
|
|
6293
|
+
usageTokens = extractChatGptUsageTokens(response.usage);
|
|
6294
|
+
const stepCostUsd = estimateCallCostUsd({
|
|
6295
|
+
modelId: modelVersion,
|
|
6296
|
+
tokens: usageTokens,
|
|
6297
|
+
responseImages: 0
|
|
6298
|
+
});
|
|
6299
|
+
totalCostUsd += stepCostUsd;
|
|
6300
|
+
responseText = (response.text ?? "").trim();
|
|
6301
|
+
reasoningSummaryText = (response.reasoningSummaryText ?? "").trim();
|
|
6302
|
+
if (!thoughtDeltaEmitted && reasoningSummaryText.length > 0) {
|
|
6303
|
+
stepCallLogger?.appendThoughtDelta(reasoningSummaryText);
|
|
6304
|
+
request.onEvent?.({ type: "delta", channel: "thought", text: reasoningSummaryText });
|
|
6305
|
+
}
|
|
6306
|
+
if (!sawResponseDelta && responseText.length > 0) {
|
|
6307
|
+
stepCallLogger?.appendResponseDelta(responseText);
|
|
6308
|
+
}
|
|
6309
|
+
const responseToolCalls = response.toolCalls ?? [];
|
|
6310
|
+
if (responseToolCalls.length === 0) {
|
|
6311
|
+
const steeringInput2 = steeringInternal?.drainPendingContents() ?? [];
|
|
6312
|
+
const steeringItems2 = steeringInput2.length > 0 ? toChatGptInput(steeringInput2).input : [];
|
|
6313
|
+
finalText = responseText;
|
|
6314
|
+
finalThoughts = reasoningSummaryText;
|
|
6315
|
+
const stepCompletedAtMs2 = Date.now();
|
|
6316
|
+
const timing2 = buildStepTiming({
|
|
6317
|
+
stepStartedAtMs,
|
|
6318
|
+
stepCompletedAtMs: stepCompletedAtMs2,
|
|
6319
|
+
modelCompletedAtMs,
|
|
6320
|
+
firstModelEventAtMs,
|
|
6321
|
+
toolExecutionMs: 0,
|
|
6322
|
+
waitToolMs: 0
|
|
6323
|
+
});
|
|
6324
|
+
steps.push({
|
|
6325
|
+
step: steps.length + 1,
|
|
6326
|
+
modelVersion,
|
|
6327
|
+
text: responseText || void 0,
|
|
6328
|
+
thoughts: reasoningSummaryText || void 0,
|
|
6329
|
+
toolCalls: [],
|
|
6330
|
+
usage: usageTokens,
|
|
6331
|
+
costUsd: stepCostUsd,
|
|
6332
|
+
timing: timing2
|
|
6333
|
+
});
|
|
6334
|
+
stepCallLogger?.complete({
|
|
6335
|
+
provider: "chatgpt",
|
|
6336
|
+
model: request.model,
|
|
6337
|
+
modelVersion,
|
|
6338
|
+
step: turn,
|
|
6339
|
+
usage: usageTokens,
|
|
6340
|
+
costUsd: stepCostUsd,
|
|
6341
|
+
responseChars: responseText.length,
|
|
6342
|
+
thoughtChars: reasoningSummaryText.length,
|
|
6343
|
+
toolCalls: 0,
|
|
6344
|
+
finalStep: steeringItems2.length === 0
|
|
6345
|
+
});
|
|
6346
|
+
if (steeringItems2.length === 0) {
|
|
6347
|
+
return { text: finalText, thoughts: finalThoughts, steps, totalCostUsd };
|
|
5568
6348
|
}
|
|
6349
|
+
const assistantItem = toChatGptAssistantMessage(responseText);
|
|
6350
|
+
input = assistantItem ? input.concat(assistantItem, steeringItems2) : input.concat(steeringItems2);
|
|
6351
|
+
continue;
|
|
5569
6352
|
}
|
|
5570
|
-
|
|
5571
|
-
|
|
5572
|
-
|
|
5573
|
-
|
|
5574
|
-
|
|
5575
|
-
|
|
5576
|
-
|
|
5577
|
-
|
|
5578
|
-
|
|
5579
|
-
|
|
5580
|
-
|
|
5581
|
-
|
|
5582
|
-
|
|
5583
|
-
|
|
5584
|
-
|
|
5585
|
-
|
|
5586
|
-
|
|
5587
|
-
|
|
5588
|
-
|
|
5589
|
-
|
|
5590
|
-
|
|
5591
|
-
|
|
5592
|
-
|
|
6353
|
+
const toolCalls = [];
|
|
6354
|
+
const toolOutputs = [];
|
|
6355
|
+
const callInputs = responseToolCalls.map((call, index) => {
|
|
6356
|
+
const toolIndex = index + 1;
|
|
6357
|
+
const toolId = buildToolLogId(turn, toolIndex);
|
|
6358
|
+
const toolName = call.name;
|
|
6359
|
+
const { value, error: parseError } = call.kind === "custom" ? { value: call.input, error: void 0 } : parseOpenAiToolArguments(call.arguments);
|
|
6360
|
+
const ids = normalizeChatGptToolIds({
|
|
6361
|
+
callKind: call.kind,
|
|
6362
|
+
callId: call.callId,
|
|
6363
|
+
itemId: call.id
|
|
6364
|
+
});
|
|
6365
|
+
return { call, toolName, value, parseError, ids, toolId, turn, toolIndex };
|
|
6366
|
+
});
|
|
6367
|
+
for (const entry of callInputs) {
|
|
6368
|
+
request.onEvent?.({
|
|
6369
|
+
type: "tool_call",
|
|
6370
|
+
phase: "started",
|
|
6371
|
+
turn: entry.turn,
|
|
6372
|
+
toolIndex: entry.toolIndex,
|
|
6373
|
+
toolName: entry.toolName,
|
|
6374
|
+
toolId: entry.toolId,
|
|
6375
|
+
callKind: entry.call.kind,
|
|
6376
|
+
callId: entry.ids.callId,
|
|
6377
|
+
input: entry.value
|
|
6378
|
+
});
|
|
6379
|
+
}
|
|
6380
|
+
const callResults = await Promise.all(
|
|
6381
|
+
callInputs.map(async (entry) => {
|
|
6382
|
+
return await toolCallContextStorage.run(
|
|
6383
|
+
{
|
|
6384
|
+
toolName: entry.toolName,
|
|
6385
|
+
toolId: entry.toolId,
|
|
6386
|
+
turn: entry.turn,
|
|
6387
|
+
toolIndex: entry.toolIndex
|
|
6388
|
+
},
|
|
6389
|
+
async () => {
|
|
6390
|
+
const { result, outputPayload } = await executeToolCall({
|
|
6391
|
+
callKind: entry.call.kind,
|
|
6392
|
+
toolName: entry.toolName,
|
|
6393
|
+
tool: request.tools[entry.toolName],
|
|
6394
|
+
rawInput: entry.value,
|
|
6395
|
+
parseError: entry.parseError
|
|
6396
|
+
});
|
|
6397
|
+
return { entry, result, outputPayload };
|
|
6398
|
+
}
|
|
6399
|
+
);
|
|
6400
|
+
})
|
|
6401
|
+
);
|
|
6402
|
+
let toolExecutionMs = 0;
|
|
6403
|
+
let waitToolMs = 0;
|
|
6404
|
+
for (const { entry, result, outputPayload } of callResults) {
|
|
6405
|
+
toolCalls.push({ ...result, callId: entry.ids.callId });
|
|
6406
|
+
const callDurationMs = toToolResultDuration(result);
|
|
6407
|
+
toolExecutionMs += callDurationMs;
|
|
6408
|
+
if (entry.toolName.toLowerCase() === SUBAGENT_WAIT_TOOL_NAME) {
|
|
6409
|
+
waitToolMs += callDurationMs;
|
|
6410
|
+
}
|
|
6411
|
+
request.onEvent?.({
|
|
6412
|
+
type: "tool_call",
|
|
6413
|
+
phase: "completed",
|
|
6414
|
+
turn: entry.turn,
|
|
6415
|
+
toolIndex: entry.toolIndex,
|
|
6416
|
+
toolName: entry.toolName,
|
|
6417
|
+
toolId: entry.toolId,
|
|
6418
|
+
callKind: entry.call.kind,
|
|
6419
|
+
callId: entry.ids.callId,
|
|
6420
|
+
input: entry.value,
|
|
6421
|
+
output: result.output,
|
|
6422
|
+
error: result.error,
|
|
6423
|
+
durationMs: result.durationMs
|
|
6424
|
+
});
|
|
6425
|
+
if (entry.call.kind === "custom") {
|
|
6426
|
+
toolOutputs.push({
|
|
6427
|
+
type: "custom_tool_call",
|
|
6428
|
+
id: entry.ids.itemId,
|
|
6429
|
+
call_id: entry.ids.callId,
|
|
6430
|
+
name: entry.toolName,
|
|
6431
|
+
input: entry.call.input,
|
|
6432
|
+
status: "completed"
|
|
6433
|
+
});
|
|
6434
|
+
toolOutputs.push({
|
|
6435
|
+
type: "custom_tool_call_output",
|
|
6436
|
+
call_id: entry.ids.callId,
|
|
6437
|
+
output: toOpenAiToolOutput(outputPayload)
|
|
6438
|
+
});
|
|
6439
|
+
} else {
|
|
6440
|
+
toolOutputs.push({
|
|
6441
|
+
type: "function_call",
|
|
6442
|
+
id: entry.ids.itemId,
|
|
6443
|
+
call_id: entry.ids.callId,
|
|
6444
|
+
name: entry.toolName,
|
|
6445
|
+
arguments: entry.call.arguments,
|
|
6446
|
+
status: "completed"
|
|
6447
|
+
});
|
|
6448
|
+
toolOutputs.push({
|
|
6449
|
+
type: "function_call_output",
|
|
6450
|
+
call_id: entry.ids.callId,
|
|
6451
|
+
output: toOpenAiToolOutput(outputPayload)
|
|
6452
|
+
});
|
|
6453
|
+
}
|
|
6454
|
+
}
|
|
6455
|
+
const stepCompletedAtMs = Date.now();
|
|
6456
|
+
const timing = buildStepTiming({
|
|
5593
6457
|
stepStartedAtMs,
|
|
5594
|
-
stepCompletedAtMs
|
|
6458
|
+
stepCompletedAtMs,
|
|
5595
6459
|
modelCompletedAtMs,
|
|
5596
6460
|
firstModelEventAtMs,
|
|
5597
|
-
toolExecutionMs
|
|
5598
|
-
waitToolMs
|
|
6461
|
+
toolExecutionMs,
|
|
6462
|
+
waitToolMs
|
|
5599
6463
|
});
|
|
5600
6464
|
steps.push({
|
|
5601
6465
|
step: steps.length + 1,
|
|
5602
6466
|
modelVersion,
|
|
5603
6467
|
text: responseText || void 0,
|
|
5604
6468
|
thoughts: reasoningSummaryText || void 0,
|
|
5605
|
-
toolCalls
|
|
6469
|
+
toolCalls,
|
|
5606
6470
|
usage: usageTokens,
|
|
5607
6471
|
costUsd: stepCostUsd,
|
|
5608
|
-
timing
|
|
6472
|
+
timing
|
|
5609
6473
|
});
|
|
5610
|
-
|
|
5611
|
-
|
|
5612
|
-
|
|
5613
|
-
|
|
5614
|
-
|
|
5615
|
-
|
|
5616
|
-
|
|
5617
|
-
|
|
5618
|
-
|
|
5619
|
-
|
|
5620
|
-
|
|
5621
|
-
|
|
5622
|
-
|
|
5623
|
-
const { value, error: parseError } = call.kind === "custom" ? { value: call.input, error: void 0 } : parseOpenAiToolArguments(call.arguments);
|
|
5624
|
-
const ids = normalizeChatGptToolIds({
|
|
5625
|
-
callKind: call.kind,
|
|
5626
|
-
callId: call.callId,
|
|
5627
|
-
itemId: call.id
|
|
6474
|
+
const steeringInput = steeringInternal?.drainPendingContents() ?? [];
|
|
6475
|
+
const steeringItems = steeringInput.length > 0 ? toChatGptInput(steeringInput).input : [];
|
|
6476
|
+
stepCallLogger?.complete({
|
|
6477
|
+
provider: "chatgpt",
|
|
6478
|
+
model: request.model,
|
|
6479
|
+
modelVersion,
|
|
6480
|
+
step: turn,
|
|
6481
|
+
usage: usageTokens,
|
|
6482
|
+
costUsd: stepCostUsd,
|
|
6483
|
+
responseChars: responseText.length,
|
|
6484
|
+
thoughtChars: reasoningSummaryText.length,
|
|
6485
|
+
toolCalls: toolCalls.length,
|
|
6486
|
+
finalStep: false
|
|
5628
6487
|
});
|
|
5629
|
-
|
|
5630
|
-
})
|
|
5631
|
-
|
|
5632
|
-
|
|
5633
|
-
|
|
5634
|
-
|
|
5635
|
-
|
|
5636
|
-
|
|
5637
|
-
toolName: entry.toolName,
|
|
5638
|
-
toolId: entry.toolId,
|
|
5639
|
-
callKind: entry.call.kind,
|
|
5640
|
-
callId: entry.ids.callId,
|
|
5641
|
-
input: entry.value
|
|
6488
|
+
input = steeringItems.length > 0 ? input.concat(toolOutputs, steeringItems) : input.concat(toolOutputs);
|
|
6489
|
+
} catch (error) {
|
|
6490
|
+
stepCallLogger?.fail(error, {
|
|
6491
|
+
provider: "chatgpt",
|
|
6492
|
+
model: request.model,
|
|
6493
|
+
modelVersion,
|
|
6494
|
+
step: turn,
|
|
6495
|
+
usage: usageTokens
|
|
5642
6496
|
});
|
|
6497
|
+
throw error;
|
|
5643
6498
|
}
|
|
5644
|
-
|
|
5645
|
-
|
|
5646
|
-
|
|
5647
|
-
|
|
5648
|
-
|
|
5649
|
-
|
|
5650
|
-
|
|
5651
|
-
toolIndex: entry.toolIndex
|
|
5652
|
-
},
|
|
5653
|
-
async () => {
|
|
5654
|
-
const { result, outputPayload } = await executeToolCall({
|
|
5655
|
-
callKind: entry.call.kind,
|
|
5656
|
-
toolName: entry.toolName,
|
|
5657
|
-
tool: request.tools[entry.toolName],
|
|
5658
|
-
rawInput: entry.value,
|
|
5659
|
-
parseError: entry.parseError
|
|
5660
|
-
});
|
|
5661
|
-
return { entry, result, outputPayload };
|
|
5662
|
-
}
|
|
5663
|
-
);
|
|
5664
|
-
})
|
|
6499
|
+
}
|
|
6500
|
+
throw new Error(`Tool loop exceeded max steps (${maxSteps}) without final response.`);
|
|
6501
|
+
}
|
|
6502
|
+
if (providerInfo.provider === "fireworks") {
|
|
6503
|
+
if (request.modelTools && request.modelTools.length > 0) {
|
|
6504
|
+
throw new Error(
|
|
6505
|
+
"Fireworks provider does not support provider-native modelTools in runToolLoop."
|
|
5665
6506
|
);
|
|
5666
|
-
|
|
5667
|
-
|
|
5668
|
-
|
|
5669
|
-
|
|
5670
|
-
|
|
5671
|
-
|
|
5672
|
-
|
|
5673
|
-
|
|
6507
|
+
}
|
|
6508
|
+
const fireworksTools = buildFireworksToolsFromToolSet(request.tools);
|
|
6509
|
+
const messages = toFireworksMessages(contents);
|
|
6510
|
+
for (let stepIndex = 0; stepIndex < maxSteps; stepIndex += 1) {
|
|
6511
|
+
const turn = stepIndex + 1;
|
|
6512
|
+
const stepStartedAtMs = Date.now();
|
|
6513
|
+
let schedulerMetrics;
|
|
6514
|
+
let modelVersion = request.model;
|
|
6515
|
+
let usageTokens;
|
|
6516
|
+
let responseText = "";
|
|
6517
|
+
let blocked = false;
|
|
6518
|
+
const stepRequestPayload = {
|
|
6519
|
+
model: providerInfo.model,
|
|
6520
|
+
messages,
|
|
6521
|
+
tools: fireworksTools,
|
|
6522
|
+
tool_choice: "auto",
|
|
6523
|
+
parallel_tool_calls: true
|
|
6524
|
+
};
|
|
6525
|
+
const stepCallLogger = startLlmCallLoggerFromPayload({
|
|
6526
|
+
provider: "fireworks",
|
|
6527
|
+
modelId: request.model,
|
|
6528
|
+
requestPayload: stepRequestPayload,
|
|
6529
|
+
step: turn
|
|
6530
|
+
});
|
|
6531
|
+
try {
|
|
6532
|
+
const response = await runFireworksCall(
|
|
6533
|
+
async (client) => {
|
|
6534
|
+
return await client.chat.completions.create(
|
|
6535
|
+
{
|
|
6536
|
+
model: providerInfo.model,
|
|
6537
|
+
messages,
|
|
6538
|
+
tools: fireworksTools,
|
|
6539
|
+
tool_choice: "auto",
|
|
6540
|
+
parallel_tool_calls: true
|
|
6541
|
+
},
|
|
6542
|
+
{ signal: request.signal }
|
|
6543
|
+
);
|
|
6544
|
+
},
|
|
6545
|
+
providerInfo.model,
|
|
6546
|
+
{
|
|
6547
|
+
onSettled: (metrics) => {
|
|
6548
|
+
schedulerMetrics = metrics;
|
|
6549
|
+
}
|
|
6550
|
+
}
|
|
6551
|
+
);
|
|
6552
|
+
const modelCompletedAtMs = Date.now();
|
|
6553
|
+
modelVersion = typeof response.model === "string" ? response.model : request.model;
|
|
6554
|
+
request.onEvent?.({ type: "model", modelVersion });
|
|
6555
|
+
const choice = Array.isArray(response.choices) ? response.choices[0] : void 0;
|
|
6556
|
+
if (choice?.finish_reason === "content_filter") {
|
|
6557
|
+
blocked = true;
|
|
6558
|
+
request.onEvent?.({ type: "blocked" });
|
|
5674
6559
|
}
|
|
5675
|
-
|
|
5676
|
-
|
|
5677
|
-
|
|
5678
|
-
|
|
5679
|
-
|
|
5680
|
-
|
|
5681
|
-
|
|
5682
|
-
|
|
5683
|
-
|
|
5684
|
-
|
|
5685
|
-
|
|
5686
|
-
error: result.error,
|
|
5687
|
-
durationMs: result.durationMs
|
|
6560
|
+
const message = choice?.message;
|
|
6561
|
+
responseText = extractFireworksMessageText(message).trim();
|
|
6562
|
+
if (responseText.length > 0) {
|
|
6563
|
+
stepCallLogger?.appendResponseDelta(responseText);
|
|
6564
|
+
request.onEvent?.({ type: "delta", channel: "response", text: responseText });
|
|
6565
|
+
}
|
|
6566
|
+
usageTokens = extractFireworksUsageTokens(response.usage);
|
|
6567
|
+
const stepCostUsd = estimateCallCostUsd({
|
|
6568
|
+
modelId: modelVersion,
|
|
6569
|
+
tokens: usageTokens,
|
|
6570
|
+
responseImages: 0
|
|
5688
6571
|
});
|
|
5689
|
-
|
|
5690
|
-
|
|
5691
|
-
|
|
5692
|
-
|
|
5693
|
-
|
|
5694
|
-
|
|
5695
|
-
|
|
5696
|
-
status: "completed"
|
|
6572
|
+
totalCostUsd += stepCostUsd;
|
|
6573
|
+
if (usageTokens) {
|
|
6574
|
+
request.onEvent?.({
|
|
6575
|
+
type: "usage",
|
|
6576
|
+
usage: usageTokens,
|
|
6577
|
+
costUsd: stepCostUsd,
|
|
6578
|
+
modelVersion
|
|
5697
6579
|
});
|
|
5698
|
-
|
|
5699
|
-
|
|
5700
|
-
|
|
5701
|
-
|
|
6580
|
+
}
|
|
6581
|
+
const responseToolCalls = extractFireworksToolCalls(message);
|
|
6582
|
+
if (responseToolCalls.length === 0) {
|
|
6583
|
+
const steeringInput2 = steeringInternal?.drainPendingContents() ?? [];
|
|
6584
|
+
const steeringMessages = steeringInput2.length > 0 ? toFireworksMessages(steeringInput2) : [];
|
|
6585
|
+
finalText = responseText;
|
|
6586
|
+
finalThoughts = "";
|
|
6587
|
+
const stepCompletedAtMs2 = Date.now();
|
|
6588
|
+
const timing2 = buildStepTiming({
|
|
6589
|
+
stepStartedAtMs,
|
|
6590
|
+
stepCompletedAtMs: stepCompletedAtMs2,
|
|
6591
|
+
modelCompletedAtMs,
|
|
6592
|
+
schedulerMetrics,
|
|
6593
|
+
toolExecutionMs: 0,
|
|
6594
|
+
waitToolMs: 0
|
|
5702
6595
|
});
|
|
5703
|
-
|
|
5704
|
-
|
|
5705
|
-
|
|
5706
|
-
|
|
5707
|
-
|
|
5708
|
-
|
|
5709
|
-
|
|
5710
|
-
|
|
6596
|
+
steps.push({
|
|
6597
|
+
step: steps.length + 1,
|
|
6598
|
+
modelVersion,
|
|
6599
|
+
text: responseText || void 0,
|
|
6600
|
+
thoughts: void 0,
|
|
6601
|
+
toolCalls: [],
|
|
6602
|
+
usage: usageTokens,
|
|
6603
|
+
costUsd: stepCostUsd,
|
|
6604
|
+
timing: timing2
|
|
5711
6605
|
});
|
|
5712
|
-
|
|
5713
|
-
|
|
5714
|
-
|
|
5715
|
-
|
|
6606
|
+
stepCallLogger?.complete({
|
|
6607
|
+
provider: "fireworks",
|
|
6608
|
+
model: request.model,
|
|
6609
|
+
modelVersion,
|
|
6610
|
+
step: turn,
|
|
6611
|
+
usage: usageTokens,
|
|
6612
|
+
costUsd: stepCostUsd,
|
|
6613
|
+
blocked,
|
|
6614
|
+
responseChars: responseText.length,
|
|
6615
|
+
thoughtChars: 0,
|
|
6616
|
+
toolCalls: 0,
|
|
6617
|
+
finalStep: steeringMessages.length === 0
|
|
5716
6618
|
});
|
|
6619
|
+
if (steeringMessages.length === 0) {
|
|
6620
|
+
return { text: finalText, thoughts: finalThoughts, steps, totalCostUsd };
|
|
6621
|
+
}
|
|
6622
|
+
if (responseText.length > 0) {
|
|
6623
|
+
messages.push({ role: "assistant", content: responseText });
|
|
6624
|
+
}
|
|
6625
|
+
messages.push(...steeringMessages);
|
|
6626
|
+
continue;
|
|
5717
6627
|
}
|
|
5718
|
-
|
|
5719
|
-
|
|
5720
|
-
|
|
5721
|
-
|
|
5722
|
-
|
|
5723
|
-
|
|
5724
|
-
|
|
5725
|
-
|
|
5726
|
-
|
|
5727
|
-
|
|
5728
|
-
|
|
5729
|
-
|
|
5730
|
-
|
|
5731
|
-
|
|
5732
|
-
|
|
5733
|
-
|
|
5734
|
-
|
|
5735
|
-
|
|
5736
|
-
|
|
5737
|
-
|
|
5738
|
-
|
|
5739
|
-
|
|
5740
|
-
|
|
6628
|
+
const stepToolCalls = [];
|
|
6629
|
+
const callInputs = responseToolCalls.map((call, index) => {
|
|
6630
|
+
const toolIndex = index + 1;
|
|
6631
|
+
const toolId = buildToolLogId(turn, toolIndex);
|
|
6632
|
+
const { value, error: parseError } = parseOpenAiToolArguments(call.arguments);
|
|
6633
|
+
return { call, toolName: call.name, value, parseError, toolId, turn, toolIndex };
|
|
6634
|
+
});
|
|
6635
|
+
for (const entry of callInputs) {
|
|
6636
|
+
request.onEvent?.({
|
|
6637
|
+
type: "tool_call",
|
|
6638
|
+
phase: "started",
|
|
6639
|
+
turn: entry.turn,
|
|
6640
|
+
toolIndex: entry.toolIndex,
|
|
6641
|
+
toolName: entry.toolName,
|
|
6642
|
+
toolId: entry.toolId,
|
|
6643
|
+
callKind: "function",
|
|
6644
|
+
callId: entry.call.id,
|
|
6645
|
+
input: entry.value
|
|
6646
|
+
});
|
|
6647
|
+
}
|
|
6648
|
+
const callResults = await Promise.all(
|
|
6649
|
+
callInputs.map(async (entry) => {
|
|
6650
|
+
return await toolCallContextStorage.run(
|
|
6651
|
+
{
|
|
6652
|
+
toolName: entry.toolName,
|
|
6653
|
+
toolId: entry.toolId,
|
|
6654
|
+
turn: entry.turn,
|
|
6655
|
+
toolIndex: entry.toolIndex
|
|
6656
|
+
},
|
|
6657
|
+
async () => {
|
|
6658
|
+
const { result, outputPayload } = await executeToolCall({
|
|
6659
|
+
callKind: "function",
|
|
6660
|
+
toolName: entry.toolName,
|
|
6661
|
+
tool: request.tools[entry.toolName],
|
|
6662
|
+
rawInput: entry.value,
|
|
6663
|
+
parseError: entry.parseError
|
|
6664
|
+
});
|
|
6665
|
+
return { entry, result, outputPayload };
|
|
6666
|
+
}
|
|
6667
|
+
);
|
|
6668
|
+
})
|
|
6669
|
+
);
|
|
6670
|
+
const assistantToolCalls = [];
|
|
6671
|
+
const toolMessages = [];
|
|
6672
|
+
let toolExecutionMs = 0;
|
|
6673
|
+
let waitToolMs = 0;
|
|
6674
|
+
for (const { entry, result, outputPayload } of callResults) {
|
|
6675
|
+
stepToolCalls.push({ ...result, callId: entry.call.id });
|
|
6676
|
+
const callDurationMs = toToolResultDuration(result);
|
|
6677
|
+
toolExecutionMs += callDurationMs;
|
|
6678
|
+
if (entry.toolName.toLowerCase() === SUBAGENT_WAIT_TOOL_NAME) {
|
|
6679
|
+
waitToolMs += callDurationMs;
|
|
6680
|
+
}
|
|
6681
|
+
request.onEvent?.({
|
|
6682
|
+
type: "tool_call",
|
|
6683
|
+
phase: "completed",
|
|
6684
|
+
turn: entry.turn,
|
|
6685
|
+
toolIndex: entry.toolIndex,
|
|
6686
|
+
toolName: entry.toolName,
|
|
6687
|
+
toolId: entry.toolId,
|
|
6688
|
+
callKind: "function",
|
|
6689
|
+
callId: entry.call.id,
|
|
6690
|
+
input: entry.value,
|
|
6691
|
+
output: result.output,
|
|
6692
|
+
error: result.error,
|
|
6693
|
+
durationMs: result.durationMs
|
|
6694
|
+
});
|
|
6695
|
+
assistantToolCalls.push({
|
|
6696
|
+
id: entry.call.id,
|
|
6697
|
+
type: "function",
|
|
6698
|
+
function: {
|
|
6699
|
+
name: entry.toolName,
|
|
6700
|
+
arguments: entry.call.arguments
|
|
6701
|
+
}
|
|
6702
|
+
});
|
|
6703
|
+
toolMessages.push({
|
|
6704
|
+
role: "tool",
|
|
6705
|
+
tool_call_id: entry.call.id,
|
|
6706
|
+
content: mergeToolOutput(outputPayload)
|
|
6707
|
+
});
|
|
6708
|
+
}
|
|
6709
|
+
const stepCompletedAtMs = Date.now();
|
|
6710
|
+
const timing = buildStepTiming({
|
|
6711
|
+
stepStartedAtMs,
|
|
6712
|
+
stepCompletedAtMs,
|
|
6713
|
+
modelCompletedAtMs,
|
|
6714
|
+
schedulerMetrics,
|
|
6715
|
+
toolExecutionMs,
|
|
6716
|
+
waitToolMs
|
|
6717
|
+
});
|
|
6718
|
+
steps.push({
|
|
6719
|
+
step: steps.length + 1,
|
|
6720
|
+
modelVersion,
|
|
6721
|
+
text: responseText || void 0,
|
|
6722
|
+
thoughts: void 0,
|
|
6723
|
+
toolCalls: stepToolCalls,
|
|
6724
|
+
usage: usageTokens,
|
|
6725
|
+
costUsd: stepCostUsd,
|
|
6726
|
+
timing
|
|
6727
|
+
});
|
|
6728
|
+
stepCallLogger?.complete({
|
|
6729
|
+
provider: "fireworks",
|
|
6730
|
+
model: request.model,
|
|
6731
|
+
modelVersion,
|
|
6732
|
+
step: turn,
|
|
6733
|
+
usage: usageTokens,
|
|
6734
|
+
costUsd: stepCostUsd,
|
|
6735
|
+
blocked,
|
|
6736
|
+
responseChars: responseText.length,
|
|
6737
|
+
thoughtChars: 0,
|
|
6738
|
+
toolCalls: stepToolCalls.length,
|
|
6739
|
+
finalStep: false
|
|
6740
|
+
});
|
|
6741
|
+
messages.push({
|
|
6742
|
+
role: "assistant",
|
|
6743
|
+
...responseText.length > 0 ? { content: responseText } : {},
|
|
6744
|
+
tool_calls: assistantToolCalls
|
|
6745
|
+
});
|
|
6746
|
+
messages.push(...toolMessages);
|
|
6747
|
+
const steeringInput = steeringInternal?.drainPendingContents() ?? [];
|
|
6748
|
+
if (steeringInput.length > 0) {
|
|
6749
|
+
messages.push(...toFireworksMessages(steeringInput));
|
|
6750
|
+
}
|
|
6751
|
+
} catch (error) {
|
|
6752
|
+
stepCallLogger?.fail(error, {
|
|
6753
|
+
provider: "fireworks",
|
|
6754
|
+
model: request.model,
|
|
6755
|
+
modelVersion,
|
|
6756
|
+
step: turn,
|
|
6757
|
+
usage: usageTokens,
|
|
6758
|
+
blocked
|
|
6759
|
+
});
|
|
6760
|
+
throw error;
|
|
6761
|
+
}
|
|
5741
6762
|
}
|
|
5742
6763
|
throw new Error(`Tool loop exceeded max steps (${maxSteps}) without final response.`);
|
|
5743
6764
|
}
|
|
5744
|
-
|
|
5745
|
-
|
|
5746
|
-
|
|
5747
|
-
|
|
5748
|
-
|
|
5749
|
-
|
|
5750
|
-
const
|
|
5751
|
-
|
|
5752
|
-
|
|
5753
|
-
|
|
5754
|
-
|
|
5755
|
-
|
|
5756
|
-
|
|
6765
|
+
const geminiFunctionTools = buildGeminiFunctionDeclarations(request.tools);
|
|
6766
|
+
const geminiNativeTools = toGeminiTools(request.modelTools);
|
|
6767
|
+
const geminiTools = geminiNativeTools ? geminiNativeTools.concat(geminiFunctionTools) : geminiFunctionTools;
|
|
6768
|
+
const geminiContents = contents.map(convertLlmContentToGeminiContent);
|
|
6769
|
+
for (let stepIndex = 0; stepIndex < maxSteps; stepIndex += 1) {
|
|
6770
|
+
const turn = stepIndex + 1;
|
|
6771
|
+
const stepStartedAtMs = Date.now();
|
|
6772
|
+
let firstModelEventAtMs;
|
|
6773
|
+
let schedulerMetrics;
|
|
6774
|
+
let modelVersion = request.model;
|
|
6775
|
+
let usageTokens;
|
|
6776
|
+
let responseText = "";
|
|
6777
|
+
let thoughtsText = "";
|
|
6778
|
+
const markFirstModelEvent = () => {
|
|
6779
|
+
if (firstModelEventAtMs === void 0) {
|
|
6780
|
+
firstModelEventAtMs = Date.now();
|
|
6781
|
+
}
|
|
6782
|
+
};
|
|
6783
|
+
const thinkingConfig = resolveGeminiThinkingConfig(request.model, request.thinkingLevel);
|
|
6784
|
+
const config = {
|
|
6785
|
+
maxOutputTokens: 32e3,
|
|
6786
|
+
tools: geminiTools,
|
|
6787
|
+
toolConfig: {
|
|
6788
|
+
functionCallingConfig: {
|
|
6789
|
+
mode: import_genai2.FunctionCallingConfigMode.VALIDATED
|
|
6790
|
+
}
|
|
6791
|
+
},
|
|
6792
|
+
...thinkingConfig ? { thinkingConfig } : {}
|
|
6793
|
+
};
|
|
6794
|
+
const onEvent = request.onEvent;
|
|
6795
|
+
const stepRequestPayload = {
|
|
6796
|
+
model: request.model,
|
|
6797
|
+
contents: geminiContents,
|
|
6798
|
+
config
|
|
6799
|
+
};
|
|
6800
|
+
const stepCallLogger = startLlmCallLoggerFromPayload({
|
|
6801
|
+
provider: "gemini",
|
|
6802
|
+
modelId: request.model,
|
|
6803
|
+
requestPayload: stepRequestPayload,
|
|
6804
|
+
step: turn
|
|
6805
|
+
});
|
|
6806
|
+
try {
|
|
6807
|
+
const response = await runGeminiCall(
|
|
5757
6808
|
async (client) => {
|
|
5758
|
-
|
|
5759
|
-
|
|
5760
|
-
|
|
5761
|
-
|
|
5762
|
-
|
|
5763
|
-
|
|
5764
|
-
|
|
5765
|
-
|
|
5766
|
-
|
|
5767
|
-
);
|
|
6809
|
+
const stream = await client.models.generateContentStream({
|
|
6810
|
+
model: request.model,
|
|
6811
|
+
contents: geminiContents,
|
|
6812
|
+
config
|
|
6813
|
+
});
|
|
6814
|
+
let responseText2 = "";
|
|
6815
|
+
let thoughtsText2 = "";
|
|
6816
|
+
const modelParts = [];
|
|
6817
|
+
const functionCalls = [];
|
|
6818
|
+
const seenFunctionCallIds = /* @__PURE__ */ new Set();
|
|
6819
|
+
const seenFunctionCallKeys = /* @__PURE__ */ new Set();
|
|
6820
|
+
let latestUsageMetadata;
|
|
6821
|
+
let resolvedModelVersion;
|
|
6822
|
+
for await (const chunk of stream) {
|
|
6823
|
+
markFirstModelEvent();
|
|
6824
|
+
if (chunk.modelVersion) {
|
|
6825
|
+
resolvedModelVersion = chunk.modelVersion;
|
|
6826
|
+
onEvent?.({ type: "model", modelVersion: chunk.modelVersion });
|
|
6827
|
+
}
|
|
6828
|
+
if (chunk.usageMetadata) {
|
|
6829
|
+
latestUsageMetadata = chunk.usageMetadata;
|
|
6830
|
+
}
|
|
6831
|
+
const candidates = chunk.candidates;
|
|
6832
|
+
if (!candidates || candidates.length === 0) {
|
|
6833
|
+
continue;
|
|
6834
|
+
}
|
|
6835
|
+
const primary = candidates[0];
|
|
6836
|
+
const parts = primary?.content?.parts;
|
|
6837
|
+
if (!parts || parts.length === 0) {
|
|
6838
|
+
continue;
|
|
6839
|
+
}
|
|
6840
|
+
for (const part of parts) {
|
|
6841
|
+
modelParts.push(part);
|
|
6842
|
+
const call = part.functionCall;
|
|
6843
|
+
if (call) {
|
|
6844
|
+
const id = typeof call.id === "string" ? call.id : "";
|
|
6845
|
+
const shouldAdd = (() => {
|
|
6846
|
+
if (id.length > 0) {
|
|
6847
|
+
if (seenFunctionCallIds.has(id)) {
|
|
6848
|
+
return false;
|
|
6849
|
+
}
|
|
6850
|
+
seenFunctionCallIds.add(id);
|
|
6851
|
+
return true;
|
|
6852
|
+
}
|
|
6853
|
+
const key = JSON.stringify({ name: call.name ?? "", args: call.args ?? null });
|
|
6854
|
+
if (seenFunctionCallKeys.has(key)) {
|
|
6855
|
+
return false;
|
|
6856
|
+
}
|
|
6857
|
+
seenFunctionCallKeys.add(key);
|
|
6858
|
+
return true;
|
|
6859
|
+
})();
|
|
6860
|
+
if (shouldAdd) {
|
|
6861
|
+
functionCalls.push(call);
|
|
6862
|
+
}
|
|
6863
|
+
}
|
|
6864
|
+
if (typeof part.text === "string" && part.text.length > 0) {
|
|
6865
|
+
if (part.thought) {
|
|
6866
|
+
thoughtsText2 += part.text;
|
|
6867
|
+
stepCallLogger?.appendThoughtDelta(part.text);
|
|
6868
|
+
onEvent?.({ type: "delta", channel: "thought", text: part.text });
|
|
6869
|
+
} else {
|
|
6870
|
+
responseText2 += part.text;
|
|
6871
|
+
stepCallLogger?.appendResponseDelta(part.text);
|
|
6872
|
+
onEvent?.({ type: "delta", channel: "response", text: part.text });
|
|
6873
|
+
}
|
|
6874
|
+
}
|
|
6875
|
+
}
|
|
6876
|
+
}
|
|
6877
|
+
return {
|
|
6878
|
+
responseText: responseText2,
|
|
6879
|
+
thoughtsText: thoughtsText2,
|
|
6880
|
+
functionCalls,
|
|
6881
|
+
modelParts,
|
|
6882
|
+
usageMetadata: latestUsageMetadata,
|
|
6883
|
+
modelVersion: resolvedModelVersion ?? request.model
|
|
6884
|
+
};
|
|
5768
6885
|
},
|
|
5769
|
-
|
|
6886
|
+
request.model,
|
|
5770
6887
|
{
|
|
5771
6888
|
onSettled: (metrics) => {
|
|
5772
6889
|
schedulerMetrics = metrics;
|
|
@@ -5774,43 +6891,26 @@ async function runToolLoop(request) {
|
|
|
5774
6891
|
}
|
|
5775
6892
|
);
|
|
5776
6893
|
const modelCompletedAtMs = Date.now();
|
|
5777
|
-
|
|
5778
|
-
|
|
5779
|
-
|
|
5780
|
-
|
|
5781
|
-
request.onEvent?.({ type: "blocked" });
|
|
5782
|
-
}
|
|
5783
|
-
const message = choice?.message;
|
|
5784
|
-
const responseText = extractFireworksMessageText(message).trim();
|
|
5785
|
-
if (responseText.length > 0) {
|
|
5786
|
-
request.onEvent?.({ type: "delta", channel: "response", text: responseText });
|
|
5787
|
-
}
|
|
5788
|
-
const usageTokens = extractFireworksUsageTokens(response.usage);
|
|
6894
|
+
usageTokens = extractGeminiUsageTokens(response.usageMetadata);
|
|
6895
|
+
modelVersion = response.modelVersion ?? request.model;
|
|
6896
|
+
responseText = response.responseText.trim();
|
|
6897
|
+
thoughtsText = response.thoughtsText.trim();
|
|
5789
6898
|
const stepCostUsd = estimateCallCostUsd({
|
|
5790
6899
|
modelId: modelVersion,
|
|
5791
6900
|
tokens: usageTokens,
|
|
5792
6901
|
responseImages: 0
|
|
5793
6902
|
});
|
|
5794
6903
|
totalCostUsd += stepCostUsd;
|
|
5795
|
-
if (
|
|
5796
|
-
request.onEvent?.({
|
|
5797
|
-
type: "usage",
|
|
5798
|
-
usage: usageTokens,
|
|
5799
|
-
costUsd: stepCostUsd,
|
|
5800
|
-
modelVersion
|
|
5801
|
-
});
|
|
5802
|
-
}
|
|
5803
|
-
const responseToolCalls = extractFireworksToolCalls(message);
|
|
5804
|
-
if (responseToolCalls.length === 0) {
|
|
6904
|
+
if (response.functionCalls.length === 0) {
|
|
5805
6905
|
const steeringInput2 = steeringInternal?.drainPendingContents() ?? [];
|
|
5806
|
-
const steeringMessages = steeringInput2.length > 0 ? toFireworksMessages(steeringInput2) : [];
|
|
5807
6906
|
finalText = responseText;
|
|
5808
|
-
finalThoughts =
|
|
6907
|
+
finalThoughts = thoughtsText;
|
|
5809
6908
|
const stepCompletedAtMs2 = Date.now();
|
|
5810
6909
|
const timing2 = buildStepTiming({
|
|
5811
6910
|
stepStartedAtMs,
|
|
5812
6911
|
stepCompletedAtMs: stepCompletedAtMs2,
|
|
5813
6912
|
modelCompletedAtMs,
|
|
6913
|
+
firstModelEventAtMs,
|
|
5814
6914
|
schedulerMetrics,
|
|
5815
6915
|
toolExecutionMs: 0,
|
|
5816
6916
|
waitToolMs: 0
|
|
@@ -5818,31 +6918,65 @@ async function runToolLoop(request) {
|
|
|
5818
6918
|
steps.push({
|
|
5819
6919
|
step: steps.length + 1,
|
|
5820
6920
|
modelVersion,
|
|
5821
|
-
text:
|
|
5822
|
-
thoughts: void 0,
|
|
6921
|
+
text: finalText || void 0,
|
|
6922
|
+
thoughts: finalThoughts || void 0,
|
|
5823
6923
|
toolCalls: [],
|
|
5824
6924
|
usage: usageTokens,
|
|
5825
6925
|
costUsd: stepCostUsd,
|
|
5826
6926
|
timing: timing2
|
|
5827
6927
|
});
|
|
5828
|
-
|
|
6928
|
+
stepCallLogger?.complete({
|
|
6929
|
+
provider: "gemini",
|
|
6930
|
+
model: request.model,
|
|
6931
|
+
modelVersion,
|
|
6932
|
+
step: turn,
|
|
6933
|
+
usage: usageTokens,
|
|
6934
|
+
costUsd: stepCostUsd,
|
|
6935
|
+
responseChars: responseText.length,
|
|
6936
|
+
thoughtChars: thoughtsText.length,
|
|
6937
|
+
toolCalls: 0,
|
|
6938
|
+
finalStep: steeringInput2.length === 0
|
|
6939
|
+
});
|
|
6940
|
+
if (steeringInput2.length === 0) {
|
|
5829
6941
|
return { text: finalText, thoughts: finalThoughts, steps, totalCostUsd };
|
|
5830
6942
|
}
|
|
5831
|
-
|
|
5832
|
-
|
|
6943
|
+
const modelPartsForHistory2 = response.modelParts.filter(
|
|
6944
|
+
(part) => !(typeof part.text === "string" && part.thought === true)
|
|
6945
|
+
);
|
|
6946
|
+
if (modelPartsForHistory2.length > 0) {
|
|
6947
|
+
geminiContents.push({ role: "model", parts: modelPartsForHistory2 });
|
|
6948
|
+
} else if (response.responseText.length > 0) {
|
|
6949
|
+
geminiContents.push({ role: "model", parts: [{ text: response.responseText }] });
|
|
5833
6950
|
}
|
|
5834
|
-
|
|
6951
|
+
geminiContents.push(...steeringInput2.map(convertLlmContentToGeminiContent));
|
|
5835
6952
|
continue;
|
|
5836
6953
|
}
|
|
5837
|
-
const
|
|
5838
|
-
const
|
|
6954
|
+
const toolCalls = [];
|
|
6955
|
+
const modelPartsForHistory = response.modelParts.filter(
|
|
6956
|
+
(part) => !(typeof part.text === "string" && part.thought === true)
|
|
6957
|
+
);
|
|
6958
|
+
if (modelPartsForHistory.length > 0) {
|
|
6959
|
+
geminiContents.push({ role: "model", parts: modelPartsForHistory });
|
|
6960
|
+
} else {
|
|
6961
|
+
const parts = [];
|
|
6962
|
+
if (response.responseText) {
|
|
6963
|
+
parts.push({ text: response.responseText });
|
|
6964
|
+
}
|
|
6965
|
+
for (const call of response.functionCalls) {
|
|
6966
|
+
parts.push({ functionCall: call });
|
|
6967
|
+
}
|
|
6968
|
+
geminiContents.push({ role: "model", parts });
|
|
6969
|
+
}
|
|
6970
|
+
const responseParts = [];
|
|
6971
|
+
const callInputs = response.functionCalls.map((call, index) => {
|
|
5839
6972
|
const toolIndex = index + 1;
|
|
5840
6973
|
const toolId = buildToolLogId(turn, toolIndex);
|
|
5841
|
-
const
|
|
5842
|
-
|
|
6974
|
+
const toolName = call.name ?? "unknown";
|
|
6975
|
+
const rawInput = call.args ?? {};
|
|
6976
|
+
return { call, toolName, rawInput, toolId, turn, toolIndex };
|
|
5843
6977
|
});
|
|
5844
6978
|
for (const entry of callInputs) {
|
|
5845
|
-
|
|
6979
|
+
onEvent?.({
|
|
5846
6980
|
type: "tool_call",
|
|
5847
6981
|
phase: "started",
|
|
5848
6982
|
turn: entry.turn,
|
|
@@ -5851,7 +6985,7 @@ async function runToolLoop(request) {
|
|
|
5851
6985
|
toolId: entry.toolId,
|
|
5852
6986
|
callKind: "function",
|
|
5853
6987
|
callId: entry.call.id,
|
|
5854
|
-
input: entry.
|
|
6988
|
+
input: entry.rawInput
|
|
5855
6989
|
});
|
|
5856
6990
|
}
|
|
5857
6991
|
const callResults = await Promise.all(
|
|
@@ -5868,26 +7002,23 @@ async function runToolLoop(request) {
|
|
|
5868
7002
|
callKind: "function",
|
|
5869
7003
|
toolName: entry.toolName,
|
|
5870
7004
|
tool: request.tools[entry.toolName],
|
|
5871
|
-
rawInput: entry.
|
|
5872
|
-
parseError: entry.parseError
|
|
7005
|
+
rawInput: entry.rawInput
|
|
5873
7006
|
});
|
|
5874
7007
|
return { entry, result, outputPayload };
|
|
5875
7008
|
}
|
|
5876
7009
|
);
|
|
5877
7010
|
})
|
|
5878
7011
|
);
|
|
5879
|
-
const assistantToolCalls = [];
|
|
5880
|
-
const toolMessages = [];
|
|
5881
7012
|
let toolExecutionMs = 0;
|
|
5882
7013
|
let waitToolMs = 0;
|
|
5883
7014
|
for (const { entry, result, outputPayload } of callResults) {
|
|
5884
|
-
|
|
7015
|
+
toolCalls.push({ ...result, callId: entry.call.id });
|
|
5885
7016
|
const callDurationMs = toToolResultDuration(result);
|
|
5886
7017
|
toolExecutionMs += callDurationMs;
|
|
5887
7018
|
if (entry.toolName.toLowerCase() === SUBAGENT_WAIT_TOOL_NAME) {
|
|
5888
7019
|
waitToolMs += callDurationMs;
|
|
5889
7020
|
}
|
|
5890
|
-
|
|
7021
|
+
onEvent?.({
|
|
5891
7022
|
type: "tool_call",
|
|
5892
7023
|
phase: "completed",
|
|
5893
7024
|
turn: entry.turn,
|
|
@@ -5896,30 +7027,26 @@ async function runToolLoop(request) {
|
|
|
5896
7027
|
toolId: entry.toolId,
|
|
5897
7028
|
callKind: "function",
|
|
5898
7029
|
callId: entry.call.id,
|
|
5899
|
-
input: entry.
|
|
7030
|
+
input: entry.rawInput,
|
|
5900
7031
|
output: result.output,
|
|
5901
7032
|
error: result.error,
|
|
5902
7033
|
durationMs: result.durationMs
|
|
5903
7034
|
});
|
|
5904
|
-
|
|
5905
|
-
|
|
5906
|
-
|
|
5907
|
-
function: {
|
|
7035
|
+
const responsePayload = isPlainRecord(outputPayload) ? outputPayload : { output: outputPayload };
|
|
7036
|
+
responseParts.push({
|
|
7037
|
+
functionResponse: {
|
|
5908
7038
|
name: entry.toolName,
|
|
5909
|
-
|
|
7039
|
+
response: responsePayload,
|
|
7040
|
+
...entry.call.id ? { id: entry.call.id } : {}
|
|
5910
7041
|
}
|
|
5911
7042
|
});
|
|
5912
|
-
toolMessages.push({
|
|
5913
|
-
role: "tool",
|
|
5914
|
-
tool_call_id: entry.call.id,
|
|
5915
|
-
content: mergeToolOutput(outputPayload)
|
|
5916
|
-
});
|
|
5917
7043
|
}
|
|
5918
7044
|
const stepCompletedAtMs = Date.now();
|
|
5919
7045
|
const timing = buildStepTiming({
|
|
5920
7046
|
stepStartedAtMs,
|
|
5921
7047
|
stepCompletedAtMs,
|
|
5922
7048
|
modelCompletedAtMs,
|
|
7049
|
+
firstModelEventAtMs,
|
|
5923
7050
|
schedulerMetrics,
|
|
5924
7051
|
toolExecutionMs,
|
|
5925
7052
|
waitToolMs
|
|
@@ -5928,296 +7055,40 @@ async function runToolLoop(request) {
|
|
|
5928
7055
|
step: steps.length + 1,
|
|
5929
7056
|
modelVersion,
|
|
5930
7057
|
text: responseText || void 0,
|
|
5931
|
-
thoughts: void 0,
|
|
5932
|
-
toolCalls
|
|
7058
|
+
thoughts: thoughtsText || void 0,
|
|
7059
|
+
toolCalls,
|
|
5933
7060
|
usage: usageTokens,
|
|
5934
7061
|
costUsd: stepCostUsd,
|
|
5935
7062
|
timing
|
|
5936
7063
|
});
|
|
5937
|
-
|
|
5938
|
-
|
|
5939
|
-
|
|
5940
|
-
|
|
7064
|
+
stepCallLogger?.complete({
|
|
7065
|
+
provider: "gemini",
|
|
7066
|
+
model: request.model,
|
|
7067
|
+
modelVersion,
|
|
7068
|
+
step: turn,
|
|
7069
|
+
usage: usageTokens,
|
|
7070
|
+
costUsd: stepCostUsd,
|
|
7071
|
+
responseChars: responseText.length,
|
|
7072
|
+
thoughtChars: thoughtsText.length,
|
|
7073
|
+
toolCalls: toolCalls.length,
|
|
7074
|
+
finalStep: false
|
|
5941
7075
|
});
|
|
5942
|
-
|
|
7076
|
+
geminiContents.push({ role: "user", parts: responseParts });
|
|
5943
7077
|
const steeringInput = steeringInternal?.drainPendingContents() ?? [];
|
|
5944
7078
|
if (steeringInput.length > 0) {
|
|
5945
|
-
|
|
5946
|
-
}
|
|
5947
|
-
}
|
|
5948
|
-
throw new Error(`Tool loop exceeded max steps (${maxSteps}) without final response.`);
|
|
5949
|
-
}
|
|
5950
|
-
const geminiFunctionTools = buildGeminiFunctionDeclarations(request.tools);
|
|
5951
|
-
const geminiNativeTools = toGeminiTools(request.modelTools);
|
|
5952
|
-
const geminiTools = geminiNativeTools ? geminiNativeTools.concat(geminiFunctionTools) : geminiFunctionTools;
|
|
5953
|
-
const geminiContents = contents.map(convertLlmContentToGeminiContent);
|
|
5954
|
-
for (let stepIndex = 0; stepIndex < maxSteps; stepIndex += 1) {
|
|
5955
|
-
const stepStartedAtMs = Date.now();
|
|
5956
|
-
let firstModelEventAtMs;
|
|
5957
|
-
let schedulerMetrics;
|
|
5958
|
-
const markFirstModelEvent = () => {
|
|
5959
|
-
if (firstModelEventAtMs === void 0) {
|
|
5960
|
-
firstModelEventAtMs = Date.now();
|
|
5961
|
-
}
|
|
5962
|
-
};
|
|
5963
|
-
const thinkingConfig = resolveGeminiThinkingConfig(request.model, request.thinkingLevel);
|
|
5964
|
-
const config = {
|
|
5965
|
-
maxOutputTokens: 32e3,
|
|
5966
|
-
tools: geminiTools,
|
|
5967
|
-
toolConfig: {
|
|
5968
|
-
functionCallingConfig: {
|
|
5969
|
-
mode: import_genai2.FunctionCallingConfigMode.VALIDATED
|
|
5970
|
-
}
|
|
5971
|
-
},
|
|
5972
|
-
...thinkingConfig ? { thinkingConfig } : {}
|
|
5973
|
-
};
|
|
5974
|
-
const onEvent = request.onEvent;
|
|
5975
|
-
const response = await runGeminiCall(
|
|
5976
|
-
async (client) => {
|
|
5977
|
-
const stream = await client.models.generateContentStream({
|
|
5978
|
-
model: request.model,
|
|
5979
|
-
contents: geminiContents,
|
|
5980
|
-
config
|
|
5981
|
-
});
|
|
5982
|
-
let responseText = "";
|
|
5983
|
-
let thoughtsText = "";
|
|
5984
|
-
const modelParts = [];
|
|
5985
|
-
const functionCalls = [];
|
|
5986
|
-
const seenFunctionCallIds = /* @__PURE__ */ new Set();
|
|
5987
|
-
const seenFunctionCallKeys = /* @__PURE__ */ new Set();
|
|
5988
|
-
let latestUsageMetadata;
|
|
5989
|
-
let resolvedModelVersion;
|
|
5990
|
-
for await (const chunk of stream) {
|
|
5991
|
-
markFirstModelEvent();
|
|
5992
|
-
if (chunk.modelVersion) {
|
|
5993
|
-
resolvedModelVersion = chunk.modelVersion;
|
|
5994
|
-
onEvent?.({ type: "model", modelVersion: chunk.modelVersion });
|
|
5995
|
-
}
|
|
5996
|
-
if (chunk.usageMetadata) {
|
|
5997
|
-
latestUsageMetadata = chunk.usageMetadata;
|
|
5998
|
-
}
|
|
5999
|
-
const candidates = chunk.candidates;
|
|
6000
|
-
if (!candidates || candidates.length === 0) {
|
|
6001
|
-
continue;
|
|
6002
|
-
}
|
|
6003
|
-
const primary = candidates[0];
|
|
6004
|
-
const parts = primary?.content?.parts;
|
|
6005
|
-
if (!parts || parts.length === 0) {
|
|
6006
|
-
continue;
|
|
6007
|
-
}
|
|
6008
|
-
for (const part of parts) {
|
|
6009
|
-
modelParts.push(part);
|
|
6010
|
-
const call = part.functionCall;
|
|
6011
|
-
if (call) {
|
|
6012
|
-
const id = typeof call.id === "string" ? call.id : "";
|
|
6013
|
-
const shouldAdd = (() => {
|
|
6014
|
-
if (id.length > 0) {
|
|
6015
|
-
if (seenFunctionCallIds.has(id)) {
|
|
6016
|
-
return false;
|
|
6017
|
-
}
|
|
6018
|
-
seenFunctionCallIds.add(id);
|
|
6019
|
-
return true;
|
|
6020
|
-
}
|
|
6021
|
-
const key = JSON.stringify({ name: call.name ?? "", args: call.args ?? null });
|
|
6022
|
-
if (seenFunctionCallKeys.has(key)) {
|
|
6023
|
-
return false;
|
|
6024
|
-
}
|
|
6025
|
-
seenFunctionCallKeys.add(key);
|
|
6026
|
-
return true;
|
|
6027
|
-
})();
|
|
6028
|
-
if (shouldAdd) {
|
|
6029
|
-
functionCalls.push(call);
|
|
6030
|
-
}
|
|
6031
|
-
}
|
|
6032
|
-
if (typeof part.text === "string" && part.text.length > 0) {
|
|
6033
|
-
if (part.thought) {
|
|
6034
|
-
thoughtsText += part.text;
|
|
6035
|
-
onEvent?.({ type: "delta", channel: "thought", text: part.text });
|
|
6036
|
-
} else {
|
|
6037
|
-
responseText += part.text;
|
|
6038
|
-
onEvent?.({ type: "delta", channel: "response", text: part.text });
|
|
6039
|
-
}
|
|
6040
|
-
}
|
|
6041
|
-
}
|
|
6042
|
-
}
|
|
6043
|
-
return {
|
|
6044
|
-
responseText,
|
|
6045
|
-
thoughtsText,
|
|
6046
|
-
functionCalls,
|
|
6047
|
-
modelParts,
|
|
6048
|
-
usageMetadata: latestUsageMetadata,
|
|
6049
|
-
modelVersion: resolvedModelVersion ?? request.model
|
|
6050
|
-
};
|
|
6051
|
-
},
|
|
6052
|
-
request.model,
|
|
6053
|
-
{
|
|
6054
|
-
onSettled: (metrics) => {
|
|
6055
|
-
schedulerMetrics = metrics;
|
|
6056
|
-
}
|
|
7079
|
+
geminiContents.push(...steeringInput.map(convertLlmContentToGeminiContent));
|
|
6057
7080
|
}
|
|
6058
|
-
)
|
|
6059
|
-
|
|
6060
|
-
|
|
6061
|
-
|
|
6062
|
-
const stepCostUsd = estimateCallCostUsd({
|
|
6063
|
-
modelId: modelVersion,
|
|
6064
|
-
tokens: usageTokens,
|
|
6065
|
-
responseImages: 0
|
|
6066
|
-
});
|
|
6067
|
-
totalCostUsd += stepCostUsd;
|
|
6068
|
-
if (response.functionCalls.length === 0) {
|
|
6069
|
-
const steeringInput2 = steeringInternal?.drainPendingContents() ?? [];
|
|
6070
|
-
finalText = response.responseText.trim();
|
|
6071
|
-
finalThoughts = response.thoughtsText.trim();
|
|
6072
|
-
const stepCompletedAtMs2 = Date.now();
|
|
6073
|
-
const timing2 = buildStepTiming({
|
|
6074
|
-
stepStartedAtMs,
|
|
6075
|
-
stepCompletedAtMs: stepCompletedAtMs2,
|
|
6076
|
-
modelCompletedAtMs,
|
|
6077
|
-
firstModelEventAtMs,
|
|
6078
|
-
schedulerMetrics,
|
|
6079
|
-
toolExecutionMs: 0,
|
|
6080
|
-
waitToolMs: 0
|
|
6081
|
-
});
|
|
6082
|
-
steps.push({
|
|
6083
|
-
step: steps.length + 1,
|
|
7081
|
+
} catch (error) {
|
|
7082
|
+
stepCallLogger?.fail(error, {
|
|
7083
|
+
provider: "gemini",
|
|
7084
|
+
model: request.model,
|
|
6084
7085
|
modelVersion,
|
|
6085
|
-
|
|
6086
|
-
thoughts: finalThoughts || void 0,
|
|
6087
|
-
toolCalls: [],
|
|
7086
|
+
step: turn,
|
|
6088
7087
|
usage: usageTokens,
|
|
6089
|
-
|
|
6090
|
-
|
|
6091
|
-
});
|
|
6092
|
-
if (steeringInput2.length === 0) {
|
|
6093
|
-
return { text: finalText, thoughts: finalThoughts, steps, totalCostUsd };
|
|
6094
|
-
}
|
|
6095
|
-
const modelPartsForHistory2 = response.modelParts.filter(
|
|
6096
|
-
(part) => !(typeof part.text === "string" && part.thought === true)
|
|
6097
|
-
);
|
|
6098
|
-
if (modelPartsForHistory2.length > 0) {
|
|
6099
|
-
geminiContents.push({ role: "model", parts: modelPartsForHistory2 });
|
|
6100
|
-
} else if (response.responseText.length > 0) {
|
|
6101
|
-
geminiContents.push({ role: "model", parts: [{ text: response.responseText }] });
|
|
6102
|
-
}
|
|
6103
|
-
geminiContents.push(...steeringInput2.map(convertLlmContentToGeminiContent));
|
|
6104
|
-
continue;
|
|
6105
|
-
}
|
|
6106
|
-
const toolCalls = [];
|
|
6107
|
-
const modelPartsForHistory = response.modelParts.filter(
|
|
6108
|
-
(part) => !(typeof part.text === "string" && part.thought === true)
|
|
6109
|
-
);
|
|
6110
|
-
if (modelPartsForHistory.length > 0) {
|
|
6111
|
-
geminiContents.push({ role: "model", parts: modelPartsForHistory });
|
|
6112
|
-
} else {
|
|
6113
|
-
const parts = [];
|
|
6114
|
-
if (response.responseText) {
|
|
6115
|
-
parts.push({ text: response.responseText });
|
|
6116
|
-
}
|
|
6117
|
-
for (const call of response.functionCalls) {
|
|
6118
|
-
parts.push({ functionCall: call });
|
|
6119
|
-
}
|
|
6120
|
-
geminiContents.push({ role: "model", parts });
|
|
6121
|
-
}
|
|
6122
|
-
const responseParts = [];
|
|
6123
|
-
const callInputs = response.functionCalls.map((call, index) => {
|
|
6124
|
-
const turn = stepIndex + 1;
|
|
6125
|
-
const toolIndex = index + 1;
|
|
6126
|
-
const toolId = buildToolLogId(turn, toolIndex);
|
|
6127
|
-
const toolName = call.name ?? "unknown";
|
|
6128
|
-
const rawInput = call.args ?? {};
|
|
6129
|
-
return { call, toolName, rawInput, toolId, turn, toolIndex };
|
|
6130
|
-
});
|
|
6131
|
-
for (const entry of callInputs) {
|
|
6132
|
-
onEvent?.({
|
|
6133
|
-
type: "tool_call",
|
|
6134
|
-
phase: "started",
|
|
6135
|
-
turn: entry.turn,
|
|
6136
|
-
toolIndex: entry.toolIndex,
|
|
6137
|
-
toolName: entry.toolName,
|
|
6138
|
-
toolId: entry.toolId,
|
|
6139
|
-
callKind: "function",
|
|
6140
|
-
callId: entry.call.id,
|
|
6141
|
-
input: entry.rawInput
|
|
6142
|
-
});
|
|
6143
|
-
}
|
|
6144
|
-
const callResults = await Promise.all(
|
|
6145
|
-
callInputs.map(async (entry) => {
|
|
6146
|
-
return await toolCallContextStorage.run(
|
|
6147
|
-
{
|
|
6148
|
-
toolName: entry.toolName,
|
|
6149
|
-
toolId: entry.toolId,
|
|
6150
|
-
turn: entry.turn,
|
|
6151
|
-
toolIndex: entry.toolIndex
|
|
6152
|
-
},
|
|
6153
|
-
async () => {
|
|
6154
|
-
const { result, outputPayload } = await executeToolCall({
|
|
6155
|
-
callKind: "function",
|
|
6156
|
-
toolName: entry.toolName,
|
|
6157
|
-
tool: request.tools[entry.toolName],
|
|
6158
|
-
rawInput: entry.rawInput
|
|
6159
|
-
});
|
|
6160
|
-
return { entry, result, outputPayload };
|
|
6161
|
-
}
|
|
6162
|
-
);
|
|
6163
|
-
})
|
|
6164
|
-
);
|
|
6165
|
-
let toolExecutionMs = 0;
|
|
6166
|
-
let waitToolMs = 0;
|
|
6167
|
-
for (const { entry, result, outputPayload } of callResults) {
|
|
6168
|
-
toolCalls.push({ ...result, callId: entry.call.id });
|
|
6169
|
-
const callDurationMs = toToolResultDuration(result);
|
|
6170
|
-
toolExecutionMs += callDurationMs;
|
|
6171
|
-
if (entry.toolName.toLowerCase() === SUBAGENT_WAIT_TOOL_NAME) {
|
|
6172
|
-
waitToolMs += callDurationMs;
|
|
6173
|
-
}
|
|
6174
|
-
onEvent?.({
|
|
6175
|
-
type: "tool_call",
|
|
6176
|
-
phase: "completed",
|
|
6177
|
-
turn: entry.turn,
|
|
6178
|
-
toolIndex: entry.toolIndex,
|
|
6179
|
-
toolName: entry.toolName,
|
|
6180
|
-
toolId: entry.toolId,
|
|
6181
|
-
callKind: "function",
|
|
6182
|
-
callId: entry.call.id,
|
|
6183
|
-
input: entry.rawInput,
|
|
6184
|
-
output: result.output,
|
|
6185
|
-
error: result.error,
|
|
6186
|
-
durationMs: result.durationMs
|
|
6187
|
-
});
|
|
6188
|
-
const responsePayload = isPlainRecord(outputPayload) ? outputPayload : { output: outputPayload };
|
|
6189
|
-
responseParts.push({
|
|
6190
|
-
functionResponse: {
|
|
6191
|
-
name: entry.toolName,
|
|
6192
|
-
response: responsePayload,
|
|
6193
|
-
...entry.call.id ? { id: entry.call.id } : {}
|
|
6194
|
-
}
|
|
7088
|
+
responseChars: responseText.length,
|
|
7089
|
+
thoughtChars: thoughtsText.length
|
|
6195
7090
|
});
|
|
6196
|
-
|
|
6197
|
-
const stepCompletedAtMs = Date.now();
|
|
6198
|
-
const timing = buildStepTiming({
|
|
6199
|
-
stepStartedAtMs,
|
|
6200
|
-
stepCompletedAtMs,
|
|
6201
|
-
modelCompletedAtMs,
|
|
6202
|
-
firstModelEventAtMs,
|
|
6203
|
-
schedulerMetrics,
|
|
6204
|
-
toolExecutionMs,
|
|
6205
|
-
waitToolMs
|
|
6206
|
-
});
|
|
6207
|
-
steps.push({
|
|
6208
|
-
step: steps.length + 1,
|
|
6209
|
-
modelVersion,
|
|
6210
|
-
text: response.responseText.trim() || void 0,
|
|
6211
|
-
thoughts: response.thoughtsText.trim() || void 0,
|
|
6212
|
-
toolCalls,
|
|
6213
|
-
usage: usageTokens,
|
|
6214
|
-
costUsd: stepCostUsd,
|
|
6215
|
-
timing
|
|
6216
|
-
});
|
|
6217
|
-
geminiContents.push({ role: "user", parts: responseParts });
|
|
6218
|
-
const steeringInput = steeringInternal?.drainPendingContents() ?? [];
|
|
6219
|
-
if (steeringInput.length > 0) {
|
|
6220
|
-
geminiContents.push(...steeringInput.map(convertLlmContentToGeminiContent));
|
|
7091
|
+
throw error;
|
|
6221
7092
|
}
|
|
6222
7093
|
}
|
|
6223
7094
|
throw new Error(`Tool loop exceeded max steps (${maxSteps}) without final response.`);
|
|
@@ -6531,6 +7402,7 @@ ${lines}`;
|
|
|
6531
7402
|
|
|
6532
7403
|
// src/agent.ts
|
|
6533
7404
|
var import_node_crypto3 = require("crypto");
|
|
7405
|
+
var import_node_path7 = __toESM(require("path"), 1);
|
|
6534
7406
|
|
|
6535
7407
|
// src/agent/subagents.ts
|
|
6536
7408
|
var import_node_crypto2 = require("crypto");
|
|
@@ -7005,26 +7877,26 @@ function resolveInputItemsText(items) {
|
|
|
7005
7877
|
}
|
|
7006
7878
|
const itemType = typeof item.type === "string" ? item.type.trim() : "";
|
|
7007
7879
|
const name = typeof item.name === "string" ? item.name.trim() : "";
|
|
7008
|
-
const
|
|
7880
|
+
const path8 = typeof item.path === "string" ? item.path.trim() : "";
|
|
7009
7881
|
const imageUrl = typeof item.image_url === "string" ? item.image_url.trim() : "";
|
|
7010
7882
|
if (itemType === "image") {
|
|
7011
7883
|
lines.push("[image]");
|
|
7012
7884
|
continue;
|
|
7013
7885
|
}
|
|
7014
|
-
if (itemType === "local_image" &&
|
|
7015
|
-
lines.push(`[local_image:${
|
|
7886
|
+
if (itemType === "local_image" && path8) {
|
|
7887
|
+
lines.push(`[local_image:${path8}]`);
|
|
7016
7888
|
continue;
|
|
7017
7889
|
}
|
|
7018
|
-
if (itemType === "skill" && name &&
|
|
7019
|
-
lines.push(`[skill:$${name}](${
|
|
7890
|
+
if (itemType === "skill" && name && path8) {
|
|
7891
|
+
lines.push(`[skill:$${name}](${path8})`);
|
|
7020
7892
|
continue;
|
|
7021
7893
|
}
|
|
7022
|
-
if (itemType === "mention" && name &&
|
|
7023
|
-
lines.push(`[mention:$${name}](${
|
|
7894
|
+
if (itemType === "mention" && name && path8) {
|
|
7895
|
+
lines.push(`[mention:$${name}](${path8})`);
|
|
7024
7896
|
continue;
|
|
7025
7897
|
}
|
|
7026
|
-
if (
|
|
7027
|
-
lines.push(`[${itemType || "input"}:${
|
|
7898
|
+
if (path8 || imageUrl) {
|
|
7899
|
+
lines.push(`[${itemType || "input"}:${path8 || imageUrl}]`);
|
|
7028
7900
|
continue;
|
|
7029
7901
|
}
|
|
7030
7902
|
if (name) {
|
|
@@ -7149,7 +8021,7 @@ function startRun(agent, options) {
|
|
|
7149
8021
|
setLifecycle(agent, "idle", "input_queued", `Subagent ${agent.id} run interrupted.`);
|
|
7150
8022
|
return;
|
|
7151
8023
|
}
|
|
7152
|
-
const message =
|
|
8024
|
+
const message = toErrorMessage2(error);
|
|
7153
8025
|
agent.lastError = message;
|
|
7154
8026
|
setLifecycle(agent, "failed", "run_failed", `Subagent ${agent.id} failed: ${message}`);
|
|
7155
8027
|
emitBackgroundNotification(agent, options);
|
|
@@ -7329,7 +8201,7 @@ function trimToUndefined(value) {
|
|
|
7329
8201
|
const trimmed = value?.trim();
|
|
7330
8202
|
return trimmed && trimmed.length > 0 ? trimmed : void 0;
|
|
7331
8203
|
}
|
|
7332
|
-
function
|
|
8204
|
+
function toErrorMessage2(error) {
|
|
7333
8205
|
if (error instanceof Error) {
|
|
7334
8206
|
return error.message;
|
|
7335
8207
|
}
|
|
@@ -7342,27 +8214,27 @@ function sleep2(ms) {
|
|
|
7342
8214
|
}
|
|
7343
8215
|
|
|
7344
8216
|
// src/tools/filesystemTools.ts
|
|
7345
|
-
var
|
|
7346
|
-
var
|
|
8217
|
+
var import_node_path6 = __toESM(require("path"), 1);
|
|
8218
|
+
var import_node_buffer4 = require("buffer");
|
|
7347
8219
|
var import_zod6 = require("zod");
|
|
7348
8220
|
|
|
7349
8221
|
// src/tools/applyPatch.ts
|
|
7350
|
-
var
|
|
8222
|
+
var import_node_path5 = __toESM(require("path"), 1);
|
|
7351
8223
|
var import_zod5 = require("zod");
|
|
7352
8224
|
|
|
7353
8225
|
// src/tools/filesystem.ts
|
|
7354
8226
|
var import_node_fs3 = require("fs");
|
|
7355
|
-
var
|
|
8227
|
+
var import_node_path4 = __toESM(require("path"), 1);
|
|
7356
8228
|
var InMemoryAgentFilesystem = class {
|
|
7357
8229
|
#files = /* @__PURE__ */ new Map();
|
|
7358
8230
|
#dirs = /* @__PURE__ */ new Map();
|
|
7359
8231
|
#clock = 0;
|
|
7360
8232
|
constructor(initialFiles = {}) {
|
|
7361
|
-
const root =
|
|
8233
|
+
const root = import_node_path4.default.resolve("/");
|
|
7362
8234
|
this.#dirs.set(root, { mtimeMs: this.#nextMtime() });
|
|
7363
8235
|
for (const [filePath, content] of Object.entries(initialFiles)) {
|
|
7364
|
-
const absolutePath =
|
|
7365
|
-
this.#ensureDirSync(
|
|
8236
|
+
const absolutePath = import_node_path4.default.resolve(filePath);
|
|
8237
|
+
this.#ensureDirSync(import_node_path4.default.dirname(absolutePath));
|
|
7366
8238
|
this.#files.set(absolutePath, {
|
|
7367
8239
|
content,
|
|
7368
8240
|
mtimeMs: this.#nextMtime()
|
|
@@ -7370,7 +8242,7 @@ var InMemoryAgentFilesystem = class {
|
|
|
7370
8242
|
}
|
|
7371
8243
|
}
|
|
7372
8244
|
async readTextFile(filePath) {
|
|
7373
|
-
const absolutePath =
|
|
8245
|
+
const absolutePath = import_node_path4.default.resolve(filePath);
|
|
7374
8246
|
const file = this.#files.get(absolutePath);
|
|
7375
8247
|
if (!file) {
|
|
7376
8248
|
throw createNoSuchFileError("open", absolutePath);
|
|
@@ -7382,24 +8254,24 @@ var InMemoryAgentFilesystem = class {
|
|
|
7382
8254
|
return Buffer.from(content, "utf8");
|
|
7383
8255
|
}
|
|
7384
8256
|
async writeTextFile(filePath, content) {
|
|
7385
|
-
const absolutePath =
|
|
7386
|
-
const parentPath =
|
|
8257
|
+
const absolutePath = import_node_path4.default.resolve(filePath);
|
|
8258
|
+
const parentPath = import_node_path4.default.dirname(absolutePath);
|
|
7387
8259
|
if (!this.#dirs.has(parentPath)) {
|
|
7388
8260
|
throw createNoSuchFileError("open", parentPath);
|
|
7389
8261
|
}
|
|
7390
8262
|
this.#files.set(absolutePath, { content, mtimeMs: this.#nextMtime() });
|
|
7391
8263
|
}
|
|
7392
8264
|
async deleteFile(filePath) {
|
|
7393
|
-
const absolutePath =
|
|
8265
|
+
const absolutePath = import_node_path4.default.resolve(filePath);
|
|
7394
8266
|
if (!this.#files.delete(absolutePath)) {
|
|
7395
8267
|
throw createNoSuchFileError("unlink", absolutePath);
|
|
7396
8268
|
}
|
|
7397
8269
|
}
|
|
7398
8270
|
async ensureDir(directoryPath) {
|
|
7399
|
-
this.#ensureDirSync(
|
|
8271
|
+
this.#ensureDirSync(import_node_path4.default.resolve(directoryPath));
|
|
7400
8272
|
}
|
|
7401
8273
|
async readDir(directoryPath) {
|
|
7402
|
-
const absolutePath =
|
|
8274
|
+
const absolutePath = import_node_path4.default.resolve(directoryPath);
|
|
7403
8275
|
const directory = this.#dirs.get(absolutePath);
|
|
7404
8276
|
if (!directory) {
|
|
7405
8277
|
throw createNoSuchFileError("scandir", absolutePath);
|
|
@@ -7410,10 +8282,10 @@ var InMemoryAgentFilesystem = class {
|
|
|
7410
8282
|
if (dirPath === absolutePath) {
|
|
7411
8283
|
continue;
|
|
7412
8284
|
}
|
|
7413
|
-
if (
|
|
8285
|
+
if (import_node_path4.default.dirname(dirPath) !== absolutePath) {
|
|
7414
8286
|
continue;
|
|
7415
8287
|
}
|
|
7416
|
-
const name =
|
|
8288
|
+
const name = import_node_path4.default.basename(dirPath);
|
|
7417
8289
|
if (seenNames.has(name)) {
|
|
7418
8290
|
continue;
|
|
7419
8291
|
}
|
|
@@ -7426,10 +8298,10 @@ var InMemoryAgentFilesystem = class {
|
|
|
7426
8298
|
});
|
|
7427
8299
|
}
|
|
7428
8300
|
for (const [filePath, fileRecord] of this.#files.entries()) {
|
|
7429
|
-
if (
|
|
8301
|
+
if (import_node_path4.default.dirname(filePath) !== absolutePath) {
|
|
7430
8302
|
continue;
|
|
7431
8303
|
}
|
|
7432
|
-
const name =
|
|
8304
|
+
const name = import_node_path4.default.basename(filePath);
|
|
7433
8305
|
if (seenNames.has(name)) {
|
|
7434
8306
|
continue;
|
|
7435
8307
|
}
|
|
@@ -7445,7 +8317,7 @@ var InMemoryAgentFilesystem = class {
|
|
|
7445
8317
|
return entries;
|
|
7446
8318
|
}
|
|
7447
8319
|
async stat(entryPath) {
|
|
7448
|
-
const absolutePath =
|
|
8320
|
+
const absolutePath = import_node_path4.default.resolve(entryPath);
|
|
7449
8321
|
const file = this.#files.get(absolutePath);
|
|
7450
8322
|
if (file) {
|
|
7451
8323
|
return { kind: "file", mtimeMs: file.mtimeMs };
|
|
@@ -7461,7 +8333,7 @@ var InMemoryAgentFilesystem = class {
|
|
|
7461
8333
|
return Object.fromEntries(entries.map(([filePath, record]) => [filePath, record.content]));
|
|
7462
8334
|
}
|
|
7463
8335
|
#ensureDirSync(directoryPath) {
|
|
7464
|
-
const absolutePath =
|
|
8336
|
+
const absolutePath = import_node_path4.default.resolve(directoryPath);
|
|
7465
8337
|
const parts = [];
|
|
7466
8338
|
let cursor = absolutePath;
|
|
7467
8339
|
for (; ; ) {
|
|
@@ -7469,7 +8341,7 @@ var InMemoryAgentFilesystem = class {
|
|
|
7469
8341
|
break;
|
|
7470
8342
|
}
|
|
7471
8343
|
parts.push(cursor);
|
|
7472
|
-
const parent =
|
|
8344
|
+
const parent = import_node_path4.default.dirname(cursor);
|
|
7473
8345
|
if (parent === cursor) {
|
|
7474
8346
|
break;
|
|
7475
8347
|
}
|
|
@@ -7503,7 +8375,7 @@ function createNodeAgentFilesystem() {
|
|
|
7503
8375
|
const entries = await import_node_fs3.promises.readdir(directoryPath, { withFileTypes: true });
|
|
7504
8376
|
const result = [];
|
|
7505
8377
|
for (const entry of entries) {
|
|
7506
|
-
const entryPath =
|
|
8378
|
+
const entryPath = import_node_path4.default.resolve(directoryPath, entry.name);
|
|
7507
8379
|
const stats = await import_node_fs3.promises.lstat(entryPath);
|
|
7508
8380
|
result.push({
|
|
7509
8381
|
name: entry.name,
|
|
@@ -7667,7 +8539,7 @@ function createApplyPatchTool(options = {}) {
|
|
|
7667
8539
|
});
|
|
7668
8540
|
}
|
|
7669
8541
|
async function applyPatch(request) {
|
|
7670
|
-
const cwd =
|
|
8542
|
+
const cwd = import_node_path5.default.resolve(request.cwd ?? process.cwd());
|
|
7671
8543
|
const adapter = request.fs ?? createNodeAgentFilesystem();
|
|
7672
8544
|
const allowOutsideCwd = request.allowOutsideCwd === true;
|
|
7673
8545
|
const patchBytes = Buffer.byteLength(request.patch, "utf8");
|
|
@@ -7689,7 +8561,7 @@ async function applyPatch(request) {
|
|
|
7689
8561
|
kind: "add",
|
|
7690
8562
|
path: absolutePath2
|
|
7691
8563
|
});
|
|
7692
|
-
await adapter.ensureDir(
|
|
8564
|
+
await adapter.ensureDir(import_node_path5.default.dirname(absolutePath2));
|
|
7693
8565
|
await adapter.writeTextFile(absolutePath2, operation.content);
|
|
7694
8566
|
added.push(toDisplayPath(absolutePath2, cwd));
|
|
7695
8567
|
continue;
|
|
@@ -7723,7 +8595,7 @@ async function applyPatch(request) {
|
|
|
7723
8595
|
fromPath: absolutePath,
|
|
7724
8596
|
toPath: destinationPath
|
|
7725
8597
|
});
|
|
7726
|
-
await adapter.ensureDir(
|
|
8598
|
+
await adapter.ensureDir(import_node_path5.default.dirname(destinationPath));
|
|
7727
8599
|
await adapter.writeTextFile(destinationPath, next);
|
|
7728
8600
|
await adapter.deleteFile(absolutePath);
|
|
7729
8601
|
modified.push(toDisplayPath(destinationPath, cwd));
|
|
@@ -7754,22 +8626,22 @@ function resolvePatchPath(rawPath, cwd, allowOutsideCwd) {
|
|
|
7754
8626
|
if (trimmed.length === 0) {
|
|
7755
8627
|
throw new Error("apply_patch failed: empty file path");
|
|
7756
8628
|
}
|
|
7757
|
-
const absolutePath =
|
|
8629
|
+
const absolutePath = import_node_path5.default.isAbsolute(trimmed) ? import_node_path5.default.resolve(trimmed) : import_node_path5.default.resolve(cwd, trimmed);
|
|
7758
8630
|
if (!allowOutsideCwd && !isPathInsideCwd(absolutePath, cwd)) {
|
|
7759
8631
|
throw new Error(`apply_patch failed: path "${trimmed}" resolves outside cwd "${cwd}"`);
|
|
7760
8632
|
}
|
|
7761
8633
|
return absolutePath;
|
|
7762
8634
|
}
|
|
7763
8635
|
function isPathInsideCwd(candidatePath, cwd) {
|
|
7764
|
-
const relative =
|
|
7765
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
8636
|
+
const relative = import_node_path5.default.relative(cwd, candidatePath);
|
|
8637
|
+
return relative === "" || !relative.startsWith("..") && !import_node_path5.default.isAbsolute(relative);
|
|
7766
8638
|
}
|
|
7767
8639
|
function toDisplayPath(absolutePath, cwd) {
|
|
7768
|
-
const relative =
|
|
8640
|
+
const relative = import_node_path5.default.relative(cwd, absolutePath);
|
|
7769
8641
|
if (relative === "") {
|
|
7770
8642
|
return ".";
|
|
7771
8643
|
}
|
|
7772
|
-
if (!relative.startsWith("..") && !
|
|
8644
|
+
if (!relative.startsWith("..") && !import_node_path5.default.isAbsolute(relative)) {
|
|
7773
8645
|
return relative;
|
|
7774
8646
|
}
|
|
7775
8647
|
return absolutePath;
|
|
@@ -8536,7 +9408,7 @@ async function readBinaryFile(filesystem, filePath) {
|
|
|
8536
9408
|
return await filesystem.readBinaryFile(filePath);
|
|
8537
9409
|
}
|
|
8538
9410
|
const text = await filesystem.readTextFile(filePath);
|
|
8539
|
-
return
|
|
9411
|
+
return import_node_buffer4.Buffer.from(text, "utf8");
|
|
8540
9412
|
}
|
|
8541
9413
|
function detectImageMimeType(buffer, filePath) {
|
|
8542
9414
|
if (buffer.length >= 8 && buffer[0] === 137 && buffer[1] === 80 && buffer[2] === 78 && buffer[3] === 71 && buffer[4] === 13 && buffer[5] === 10 && buffer[6] === 26 && buffer[7] === 10) {
|
|
@@ -8554,7 +9426,7 @@ function detectImageMimeType(buffer, filePath) {
|
|
|
8554
9426
|
if (buffer.length >= 12 && buffer.subarray(0, 4).toString("ascii") === "RIFF" && buffer.subarray(8, 12).toString("ascii") === "WEBP") {
|
|
8555
9427
|
return "image/webp";
|
|
8556
9428
|
}
|
|
8557
|
-
const fromExtension = IMAGE_MIME_BY_EXTENSION[
|
|
9429
|
+
const fromExtension = IMAGE_MIME_BY_EXTENSION[import_node_path6.default.extname(filePath).toLowerCase()];
|
|
8558
9430
|
if (fromExtension && SUPPORTED_IMAGE_MIME_TYPES.has(fromExtension)) {
|
|
8559
9431
|
return fromExtension;
|
|
8560
9432
|
}
|
|
@@ -8564,13 +9436,13 @@ function isPdfFile(buffer, filePath) {
|
|
|
8564
9436
|
if (buffer.length >= 5 && buffer.subarray(0, 5).toString("ascii") === "%PDF-") {
|
|
8565
9437
|
return true;
|
|
8566
9438
|
}
|
|
8567
|
-
return
|
|
9439
|
+
return import_node_path6.default.extname(filePath).toLowerCase() === ".pdf";
|
|
8568
9440
|
}
|
|
8569
9441
|
function isValidUtf8(buffer) {
|
|
8570
9442
|
if (buffer.length === 0) {
|
|
8571
9443
|
return true;
|
|
8572
9444
|
}
|
|
8573
|
-
return
|
|
9445
|
+
return import_node_buffer4.Buffer.from(buffer.toString("utf8"), "utf8").equals(buffer);
|
|
8574
9446
|
}
|
|
8575
9447
|
async function readFileGemini(input, options) {
|
|
8576
9448
|
const runtime = resolveRuntime(options);
|
|
@@ -8602,7 +9474,7 @@ async function writeFileGemini(input, options) {
|
|
|
8602
9474
|
action: "write",
|
|
8603
9475
|
path: filePath
|
|
8604
9476
|
});
|
|
8605
|
-
await runtime.filesystem.ensureDir(
|
|
9477
|
+
await runtime.filesystem.ensureDir(import_node_path6.default.dirname(filePath));
|
|
8606
9478
|
await runtime.filesystem.writeTextFile(filePath, input.content);
|
|
8607
9479
|
return `Successfully wrote file: ${toDisplayPath2(filePath, runtime.cwd)}`;
|
|
8608
9480
|
}
|
|
@@ -8623,7 +9495,7 @@ async function replaceFileContentGemini(input, options) {
|
|
|
8623
9495
|
originalContent = await runtime.filesystem.readTextFile(filePath);
|
|
8624
9496
|
} catch (error) {
|
|
8625
9497
|
if (isNoEntError(error) && oldValue.length === 0) {
|
|
8626
|
-
await runtime.filesystem.ensureDir(
|
|
9498
|
+
await runtime.filesystem.ensureDir(import_node_path6.default.dirname(filePath));
|
|
8627
9499
|
await runtime.filesystem.writeTextFile(filePath, newValue);
|
|
8628
9500
|
return `Successfully wrote new file: ${toDisplayPath2(filePath, runtime.cwd)}`;
|
|
8629
9501
|
}
|
|
@@ -8801,7 +9673,7 @@ async function globFilesGemini(input, options) {
|
|
|
8801
9673
|
});
|
|
8802
9674
|
const matched = [];
|
|
8803
9675
|
for (const filePath of files) {
|
|
8804
|
-
const relativePath = normalizeSlashes(
|
|
9676
|
+
const relativePath = normalizeSlashes(import_node_path6.default.relative(dirPath, filePath));
|
|
8805
9677
|
if (!matcher(relativePath)) {
|
|
8806
9678
|
continue;
|
|
8807
9679
|
}
|
|
@@ -8819,7 +9691,7 @@ async function globFilesGemini(input, options) {
|
|
|
8819
9691
|
}
|
|
8820
9692
|
function resolveRuntime(options) {
|
|
8821
9693
|
return {
|
|
8822
|
-
cwd:
|
|
9694
|
+
cwd: import_node_path6.default.resolve(options.cwd ?? process.cwd()),
|
|
8823
9695
|
filesystem: options.fs ?? createNodeAgentFilesystem(),
|
|
8824
9696
|
allowOutsideCwd: options.allowOutsideCwd === true,
|
|
8825
9697
|
checkAccess: options.checkAccess,
|
|
@@ -8850,13 +9722,13 @@ function mapApplyPatchAction(action) {
|
|
|
8850
9722
|
return "move";
|
|
8851
9723
|
}
|
|
8852
9724
|
function resolvePathWithPolicy(inputPath, cwd, allowOutsideCwd) {
|
|
8853
|
-
const absolutePath =
|
|
9725
|
+
const absolutePath = import_node_path6.default.isAbsolute(inputPath) ? import_node_path6.default.resolve(inputPath) : import_node_path6.default.resolve(cwd, inputPath);
|
|
8854
9726
|
if (allowOutsideCwd || isPathInsideCwd2(absolutePath, cwd)) {
|
|
8855
9727
|
return absolutePath;
|
|
8856
9728
|
}
|
|
8857
|
-
if (
|
|
9729
|
+
if (import_node_path6.default.isAbsolute(inputPath)) {
|
|
8858
9730
|
const sandboxRelativePath = inputPath.replace(/^[/\\]+/, "");
|
|
8859
|
-
const sandboxRootedPath =
|
|
9731
|
+
const sandboxRootedPath = import_node_path6.default.resolve(cwd, sandboxRelativePath);
|
|
8860
9732
|
if (isPathInsideCwd2(sandboxRootedPath, cwd)) {
|
|
8861
9733
|
return sandboxRootedPath;
|
|
8862
9734
|
}
|
|
@@ -8864,25 +9736,25 @@ function resolvePathWithPolicy(inputPath, cwd, allowOutsideCwd) {
|
|
|
8864
9736
|
throw new Error(`path "${inputPath}" resolves outside cwd "${cwd}"`);
|
|
8865
9737
|
}
|
|
8866
9738
|
function isPathInsideCwd2(candidatePath, cwd) {
|
|
8867
|
-
const relative =
|
|
8868
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
9739
|
+
const relative = import_node_path6.default.relative(cwd, candidatePath);
|
|
9740
|
+
return relative === "" || !relative.startsWith("..") && !import_node_path6.default.isAbsolute(relative);
|
|
8869
9741
|
}
|
|
8870
9742
|
function toDisplayPath2(absolutePath, cwd) {
|
|
8871
|
-
const relative =
|
|
9743
|
+
const relative = import_node_path6.default.relative(cwd, absolutePath);
|
|
8872
9744
|
if (relative === "") {
|
|
8873
9745
|
return ".";
|
|
8874
9746
|
}
|
|
8875
|
-
if (!relative.startsWith("..") && !
|
|
9747
|
+
if (!relative.startsWith("..") && !import_node_path6.default.isAbsolute(relative)) {
|
|
8876
9748
|
return relative;
|
|
8877
9749
|
}
|
|
8878
9750
|
return absolutePath;
|
|
8879
9751
|
}
|
|
8880
9752
|
function toSandboxDisplayPath(absolutePath, cwd) {
|
|
8881
|
-
const relative =
|
|
9753
|
+
const relative = import_node_path6.default.relative(cwd, absolutePath);
|
|
8882
9754
|
if (relative === "") {
|
|
8883
9755
|
return "/";
|
|
8884
9756
|
}
|
|
8885
|
-
if (!relative.startsWith("..") && !
|
|
9757
|
+
if (!relative.startsWith("..") && !import_node_path6.default.isAbsolute(relative)) {
|
|
8886
9758
|
return `/${normalizeSlashes(relative)}`;
|
|
8887
9759
|
}
|
|
8888
9760
|
return normalizeSlashes(absolutePath);
|
|
@@ -8998,7 +9870,7 @@ function createGlobMatcher(pattern, caseSensitive = false) {
|
|
|
8998
9870
|
}));
|
|
8999
9871
|
return (candidatePath) => {
|
|
9000
9872
|
const normalizedPath = normalizeSlashes(candidatePath);
|
|
9001
|
-
const basename =
|
|
9873
|
+
const basename = import_node_path6.default.posix.basename(normalizedPath);
|
|
9002
9874
|
return compiled.some(
|
|
9003
9875
|
(entry) => entry.regex.test(entry.applyToBasename ? basename : normalizedPath)
|
|
9004
9876
|
);
|
|
@@ -9114,10 +9986,18 @@ function isNoEntError(error) {
|
|
|
9114
9986
|
// src/agent.ts
|
|
9115
9987
|
async function runAgentLoop(request) {
|
|
9116
9988
|
const telemetry = createAgentTelemetrySession(request.telemetry);
|
|
9989
|
+
const logging = createRootAgentLoggingSession(request);
|
|
9117
9990
|
try {
|
|
9118
|
-
return await
|
|
9991
|
+
return await runWithAgentLoggingSession(logging, async () => {
|
|
9992
|
+
return await runAgentLoopInternal(request, {
|
|
9993
|
+
depth: 0,
|
|
9994
|
+
telemetry,
|
|
9995
|
+
logging
|
|
9996
|
+
});
|
|
9997
|
+
});
|
|
9119
9998
|
} finally {
|
|
9120
9999
|
await telemetry?.flush();
|
|
10000
|
+
await logging?.flush();
|
|
9121
10001
|
}
|
|
9122
10002
|
}
|
|
9123
10003
|
function mergeAbortSignals2(first, second) {
|
|
@@ -9188,9 +10068,11 @@ async function runAgentLoopInternal(request, context) {
|
|
|
9188
10068
|
subagent_tool,
|
|
9189
10069
|
subagents,
|
|
9190
10070
|
telemetry,
|
|
10071
|
+
logging: _logging,
|
|
9191
10072
|
...toolLoopRequest
|
|
9192
10073
|
} = request;
|
|
9193
10074
|
const telemetrySession = context.telemetry ?? createAgentTelemetrySession(telemetry);
|
|
10075
|
+
const loggingSession = context.logging;
|
|
9194
10076
|
const runId = randomRunId();
|
|
9195
10077
|
const startedAtMs = Date.now();
|
|
9196
10078
|
const steeringChannel = toolLoopRequest.steering ?? createToolLoopSteeringChannel();
|
|
@@ -9204,6 +10086,7 @@ async function runAgentLoopInternal(request, context) {
|
|
|
9204
10086
|
model: request.model,
|
|
9205
10087
|
depth: context.depth,
|
|
9206
10088
|
telemetry: telemetrySession,
|
|
10089
|
+
logging: loggingSession,
|
|
9207
10090
|
customTools: customTools ?? {},
|
|
9208
10091
|
filesystemSelection,
|
|
9209
10092
|
subagentSelection,
|
|
@@ -9240,6 +10123,16 @@ async function runAgentLoopInternal(request, context) {
|
|
|
9240
10123
|
filesystemToolsEnabled: Object.keys(filesystemTools).length > 0,
|
|
9241
10124
|
subagentToolsEnabled: resolvedSubagentConfig.enabled
|
|
9242
10125
|
});
|
|
10126
|
+
loggingSession?.logLine(
|
|
10127
|
+
[
|
|
10128
|
+
`[agent:${runId}] run_started`,
|
|
10129
|
+
`depth=${context.depth.toString()}`,
|
|
10130
|
+
`model=${request.model}`,
|
|
10131
|
+
`tools=${Object.keys(mergedTools).length.toString()}`,
|
|
10132
|
+
`filesystemTools=${Object.keys(filesystemTools).length > 0 ? "true" : "false"}`,
|
|
10133
|
+
`subagentTools=${resolvedSubagentConfig.enabled ? "true" : "false"}`
|
|
10134
|
+
].join(" ")
|
|
10135
|
+
);
|
|
9243
10136
|
const sourceOnEvent = toolLoopRequestWithSteering.onEvent;
|
|
9244
10137
|
const includeLlmStreamEvents = telemetrySession?.includeLlmStreamEvents === true;
|
|
9245
10138
|
const wrappedOnEvent = sourceOnEvent || includeLlmStreamEvents ? (event) => {
|
|
@@ -9247,6 +10140,14 @@ async function runAgentLoopInternal(request, context) {
|
|
|
9247
10140
|
if (includeLlmStreamEvents) {
|
|
9248
10141
|
emitTelemetry({ type: "agent.run.stream", event });
|
|
9249
10142
|
}
|
|
10143
|
+
if (loggingSession) {
|
|
10144
|
+
appendAgentStreamEventLog({
|
|
10145
|
+
event,
|
|
10146
|
+
append: (line) => {
|
|
10147
|
+
loggingSession.logLine(`[agent:${runId}] ${line}`);
|
|
10148
|
+
}
|
|
10149
|
+
});
|
|
10150
|
+
}
|
|
9250
10151
|
} : void 0;
|
|
9251
10152
|
try {
|
|
9252
10153
|
const result = await runToolLoop({
|
|
@@ -9264,14 +10165,43 @@ async function runAgentLoopInternal(request, context) {
|
|
|
9264
10165
|
totalCostUsd: result.totalCostUsd,
|
|
9265
10166
|
usage: summarizeResultUsage(result)
|
|
9266
10167
|
});
|
|
10168
|
+
loggingSession?.logLine(
|
|
10169
|
+
[
|
|
10170
|
+
`[agent:${runId}] run_completed`,
|
|
10171
|
+
`status=ok`,
|
|
10172
|
+
`durationMs=${Math.max(0, Date.now() - startedAtMs).toString()}`,
|
|
10173
|
+
`steps=${result.steps.length.toString()}`,
|
|
10174
|
+
`toolCalls=${countToolCalls(result).toString()}`,
|
|
10175
|
+
`totalCostUsd=${(result.totalCostUsd ?? 0).toFixed(6)}`
|
|
10176
|
+
].join(" ")
|
|
10177
|
+
);
|
|
10178
|
+
for (const step of result.steps) {
|
|
10179
|
+
loggingSession?.logLine(
|
|
10180
|
+
[
|
|
10181
|
+
`[agent:${runId}] step_completed`,
|
|
10182
|
+
`step=${step.step.toString()}`,
|
|
10183
|
+
`modelVersion=${step.modelVersion}`,
|
|
10184
|
+
`toolCalls=${step.toolCalls.length.toString()}`,
|
|
10185
|
+
`costUsd=${(step.costUsd ?? 0).toFixed(6)}`
|
|
10186
|
+
].join(" ")
|
|
10187
|
+
);
|
|
10188
|
+
}
|
|
9267
10189
|
return result;
|
|
9268
10190
|
} catch (error) {
|
|
9269
10191
|
emitTelemetry({
|
|
9270
10192
|
type: "agent.run.completed",
|
|
9271
10193
|
success: false,
|
|
9272
10194
|
durationMs: Math.max(0, Date.now() - startedAtMs),
|
|
9273
|
-
error:
|
|
10195
|
+
error: toErrorMessage3(error)
|
|
9274
10196
|
});
|
|
10197
|
+
loggingSession?.logLine(
|
|
10198
|
+
[
|
|
10199
|
+
`[agent:${runId}] run_completed`,
|
|
10200
|
+
`status=error`,
|
|
10201
|
+
`durationMs=${Math.max(0, Date.now() - startedAtMs).toString()}`,
|
|
10202
|
+
`error=${toErrorMessage3(error)}`
|
|
10203
|
+
].join(" ")
|
|
10204
|
+
);
|
|
9275
10205
|
throw error;
|
|
9276
10206
|
} finally {
|
|
9277
10207
|
await subagentController?.closeAll();
|
|
@@ -9342,7 +10272,8 @@ function createSubagentController(params) {
|
|
|
9342
10272
|
{
|
|
9343
10273
|
depth: params.depth + 1,
|
|
9344
10274
|
parentRunId: params.runId,
|
|
9345
|
-
telemetry: params.telemetry
|
|
10275
|
+
telemetry: params.telemetry,
|
|
10276
|
+
logging: params.logging
|
|
9346
10277
|
}
|
|
9347
10278
|
);
|
|
9348
10279
|
}
|
|
@@ -9406,10 +10337,10 @@ function trimToUndefined2(value) {
|
|
|
9406
10337
|
function randomRunId() {
|
|
9407
10338
|
return (0, import_node_crypto3.randomBytes)(8).toString("hex");
|
|
9408
10339
|
}
|
|
9409
|
-
function
|
|
10340
|
+
function toIsoNow2() {
|
|
9410
10341
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
9411
10342
|
}
|
|
9412
|
-
function
|
|
10343
|
+
function toErrorMessage3(error) {
|
|
9413
10344
|
if (error instanceof Error && error.message) {
|
|
9414
10345
|
return error.message;
|
|
9415
10346
|
}
|
|
@@ -9454,9 +10385,41 @@ function summarizeResultUsage(result) {
|
|
|
9454
10385
|
}
|
|
9455
10386
|
return summary;
|
|
9456
10387
|
}
|
|
9457
|
-
function
|
|
10388
|
+
function isPromiseLike2(value) {
|
|
9458
10389
|
return (typeof value === "object" || typeof value === "function") && value !== null && typeof value.then === "function";
|
|
9459
10390
|
}
|
|
10391
|
+
function resolveAgentLoggingSelection(value) {
|
|
10392
|
+
if (value === false) {
|
|
10393
|
+
return void 0;
|
|
10394
|
+
}
|
|
10395
|
+
if (value === void 0 || value === true) {
|
|
10396
|
+
return {
|
|
10397
|
+
mirrorToConsole: true
|
|
10398
|
+
};
|
|
10399
|
+
}
|
|
10400
|
+
return value;
|
|
10401
|
+
}
|
|
10402
|
+
function resolveWorkspaceDirForLogging(request) {
|
|
10403
|
+
const explicitSelection = request.filesystemTool ?? request.filesystem_tool;
|
|
10404
|
+
if (explicitSelection && typeof explicitSelection === "object" && !Array.isArray(explicitSelection)) {
|
|
10405
|
+
const cwd = explicitSelection.options?.cwd;
|
|
10406
|
+
if (typeof cwd === "string" && cwd.trim().length > 0) {
|
|
10407
|
+
return import_node_path7.default.resolve(cwd);
|
|
10408
|
+
}
|
|
10409
|
+
}
|
|
10410
|
+
return process.cwd();
|
|
10411
|
+
}
|
|
10412
|
+
function createRootAgentLoggingSession(request) {
|
|
10413
|
+
const selected = resolveAgentLoggingSelection(request.logging);
|
|
10414
|
+
if (!selected) {
|
|
10415
|
+
return void 0;
|
|
10416
|
+
}
|
|
10417
|
+
return createAgentLoggingSession({
|
|
10418
|
+
...selected,
|
|
10419
|
+
workspaceDir: typeof selected.workspaceDir === "string" && selected.workspaceDir.trim().length > 0 ? import_node_path7.default.resolve(selected.workspaceDir) : resolveWorkspaceDirForLogging(request),
|
|
10420
|
+
mirrorToConsole: selected.mirrorToConsole !== false
|
|
10421
|
+
});
|
|
10422
|
+
}
|
|
9460
10423
|
function isAgentTelemetrySink(value) {
|
|
9461
10424
|
return typeof value === "object" && value !== null && typeof value.emit === "function";
|
|
9462
10425
|
}
|
|
@@ -9487,7 +10450,7 @@ function createAgentTelemetrySession(telemetry) {
|
|
|
9487
10450
|
const emit = (event) => {
|
|
9488
10451
|
try {
|
|
9489
10452
|
const output = config.sink.emit(event);
|
|
9490
|
-
if (
|
|
10453
|
+
if (isPromiseLike2(output)) {
|
|
9491
10454
|
const task = Promise.resolve(output).then(() => void 0).catch(() => void 0);
|
|
9492
10455
|
trackPromise(task);
|
|
9493
10456
|
}
|
|
@@ -9518,7 +10481,7 @@ function createAgentTelemetryEmitter(params) {
|
|
|
9518
10481
|
}
|
|
9519
10482
|
params.session.emit({
|
|
9520
10483
|
...event,
|
|
9521
|
-
timestamp:
|
|
10484
|
+
timestamp: toIsoNow2(),
|
|
9522
10485
|
runId: params.runId,
|
|
9523
10486
|
...params.parentRunId ? { parentRunId: params.parentRunId } : {},
|
|
9524
10487
|
depth: params.depth,
|