@ljoukov/llm 4.0.0 → 4.0.2
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 +38 -0
- package/dist/index.cjs +1969 -1046
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -1
- package/dist/index.d.ts +13 -1
- package/dist/index.js +1969 -1046
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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");
|
|
@@ -2755,8 +2755,375 @@ function stripChatGptPrefix(model) {
|
|
|
2755
2755
|
return model.slice("chatgpt-".length);
|
|
2756
2756
|
}
|
|
2757
2757
|
|
|
2758
|
+
// src/agentLogging.ts
|
|
2759
|
+
var import_node_async_hooks = require("async_hooks");
|
|
2760
|
+
var import_node_buffer2 = require("buffer");
|
|
2761
|
+
var import_promises = require("fs/promises");
|
|
2762
|
+
var import_node_path3 = __toESM(require("path"), 1);
|
|
2763
|
+
function toIsoNow() {
|
|
2764
|
+
return (/* @__PURE__ */ new Date()).toISOString();
|
|
2765
|
+
}
|
|
2766
|
+
function toErrorMessage(error) {
|
|
2767
|
+
if (error instanceof Error && error.message) {
|
|
2768
|
+
return error.message;
|
|
2769
|
+
}
|
|
2770
|
+
if (typeof error === "string") {
|
|
2771
|
+
return error;
|
|
2772
|
+
}
|
|
2773
|
+
return String(error);
|
|
2774
|
+
}
|
|
2775
|
+
function isPromiseLike(value) {
|
|
2776
|
+
return (typeof value === "object" || typeof value === "function") && value !== null && typeof value.then === "function";
|
|
2777
|
+
}
|
|
2778
|
+
function normalisePathSegment(value) {
|
|
2779
|
+
const cleaned = value.trim().replace(/[^a-z0-9._-]+/giu, "-").replace(/-{2,}/g, "-").replace(/^-+|-+$/g, "");
|
|
2780
|
+
return cleaned.length > 0 ? cleaned : "segment";
|
|
2781
|
+
}
|
|
2782
|
+
function ensureTrailingNewline(value) {
|
|
2783
|
+
return value.endsWith("\n") ? value : `${value}
|
|
2784
|
+
`;
|
|
2785
|
+
}
|
|
2786
|
+
function redactDataUrlPayload(value) {
|
|
2787
|
+
if (!value.toLowerCase().startsWith("data:")) {
|
|
2788
|
+
return value;
|
|
2789
|
+
}
|
|
2790
|
+
const commaIndex = value.indexOf(",");
|
|
2791
|
+
if (commaIndex < 0) {
|
|
2792
|
+
return value;
|
|
2793
|
+
}
|
|
2794
|
+
return `${value.slice(0, commaIndex + 1)}...`;
|
|
2795
|
+
}
|
|
2796
|
+
function sanitiseLogValue(value, seen = /* @__PURE__ */ new WeakSet()) {
|
|
2797
|
+
if (typeof value === "string") {
|
|
2798
|
+
return redactDataUrlPayload(value);
|
|
2799
|
+
}
|
|
2800
|
+
if (typeof value === "number" || typeof value === "boolean" || value === null || value === void 0) {
|
|
2801
|
+
return value;
|
|
2802
|
+
}
|
|
2803
|
+
if (Array.isArray(value)) {
|
|
2804
|
+
return value.map((entry) => sanitiseLogValue(entry, seen));
|
|
2805
|
+
}
|
|
2806
|
+
if (typeof value !== "object") {
|
|
2807
|
+
return String(value);
|
|
2808
|
+
}
|
|
2809
|
+
if (seen.has(value)) {
|
|
2810
|
+
return "[circular]";
|
|
2811
|
+
}
|
|
2812
|
+
seen.add(value);
|
|
2813
|
+
const record = value;
|
|
2814
|
+
const output = {};
|
|
2815
|
+
const hasInlineMime = typeof record.mimeType === "string" && record.mimeType.trim().length > 0 || typeof record.mime_type === "string" && record.mime_type.trim().length > 0;
|
|
2816
|
+
for (const [key, entryValue] of Object.entries(record)) {
|
|
2817
|
+
if (key === "image_url") {
|
|
2818
|
+
if (typeof entryValue === "string") {
|
|
2819
|
+
output[key] = redactDataUrlPayload(entryValue);
|
|
2820
|
+
continue;
|
|
2821
|
+
}
|
|
2822
|
+
if (entryValue && typeof entryValue === "object") {
|
|
2823
|
+
const nested = entryValue;
|
|
2824
|
+
if (typeof nested.url === "string") {
|
|
2825
|
+
output[key] = {
|
|
2826
|
+
...nested,
|
|
2827
|
+
url: redactDataUrlPayload(nested.url)
|
|
2828
|
+
};
|
|
2829
|
+
continue;
|
|
2830
|
+
}
|
|
2831
|
+
}
|
|
2832
|
+
}
|
|
2833
|
+
if (key === "data" && hasInlineMime && typeof entryValue === "string") {
|
|
2834
|
+
output[key] = `[omitted:${import_node_buffer2.Buffer.byteLength(entryValue, "utf8")}b]`;
|
|
2835
|
+
continue;
|
|
2836
|
+
}
|
|
2837
|
+
output[key] = sanitiseLogValue(entryValue, seen);
|
|
2838
|
+
}
|
|
2839
|
+
return output;
|
|
2840
|
+
}
|
|
2841
|
+
function serialiseForSnippet(value) {
|
|
2842
|
+
if (typeof value === "string") {
|
|
2843
|
+
return value;
|
|
2844
|
+
}
|
|
2845
|
+
try {
|
|
2846
|
+
return JSON.stringify(sanitiseLogValue(value));
|
|
2847
|
+
} catch {
|
|
2848
|
+
return String(value);
|
|
2849
|
+
}
|
|
2850
|
+
}
|
|
2851
|
+
function formatToolLogSnippet(value) {
|
|
2852
|
+
const compact = serialiseForSnippet(value).replace(/\s+/gu, " ").trim();
|
|
2853
|
+
if (compact.length === 0) {
|
|
2854
|
+
return "<empty>";
|
|
2855
|
+
}
|
|
2856
|
+
const max = 600;
|
|
2857
|
+
if (compact.length <= max) {
|
|
2858
|
+
return compact;
|
|
2859
|
+
}
|
|
2860
|
+
return `${compact.slice(0, max)}...`;
|
|
2861
|
+
}
|
|
2862
|
+
function formatUsd(value) {
|
|
2863
|
+
const amount = typeof value === "number" && Number.isFinite(value) ? Math.max(0, value) : 0;
|
|
2864
|
+
return amount.toFixed(6);
|
|
2865
|
+
}
|
|
2866
|
+
function appendToolCallStreamLog(options) {
|
|
2867
|
+
const event = options.event;
|
|
2868
|
+
if (event.type !== "tool_call") {
|
|
2869
|
+
return;
|
|
2870
|
+
}
|
|
2871
|
+
const callIdSegment = typeof event.callId === "string" && event.callId.trim().length > 0 ? ` callId=${event.callId}` : "";
|
|
2872
|
+
const prefix = [
|
|
2873
|
+
`tool_call_${event.phase}:`,
|
|
2874
|
+
`turn=${event.turn.toString()}`,
|
|
2875
|
+
`index=${event.toolIndex.toString()}`,
|
|
2876
|
+
`tool=${event.toolName}${callIdSegment}`
|
|
2877
|
+
].join(" ");
|
|
2878
|
+
if (event.phase === "started") {
|
|
2879
|
+
options.append(prefix);
|
|
2880
|
+
options.append(`tool_call_input: ${formatToolLogSnippet(sanitiseLogValue(event.input))}`);
|
|
2881
|
+
return;
|
|
2882
|
+
}
|
|
2883
|
+
const durationSegment = typeof event.durationMs === "number" && Number.isFinite(event.durationMs) ? ` durationMs=${Math.max(0, Math.round(event.durationMs)).toString()}` : "";
|
|
2884
|
+
options.append(`${prefix} status=${event.error ? "error" : "ok"}${durationSegment}`);
|
|
2885
|
+
options.append(`tool_call_output: ${formatToolLogSnippet(sanitiseLogValue(event.output))}`);
|
|
2886
|
+
if (typeof event.error === "string" && event.error.trim().length > 0) {
|
|
2887
|
+
options.append(`tool_call_error: ${event.error.trim()}`);
|
|
2888
|
+
}
|
|
2889
|
+
}
|
|
2890
|
+
function appendAgentStreamEventLog(options) {
|
|
2891
|
+
const event = options.event;
|
|
2892
|
+
switch (event.type) {
|
|
2893
|
+
case "delta": {
|
|
2894
|
+
const channelPrefix = event.channel === "thought" ? "thought_delta" : "response_delta";
|
|
2895
|
+
options.append(`${channelPrefix}: ${event.text}`);
|
|
2896
|
+
return;
|
|
2897
|
+
}
|
|
2898
|
+
case "model": {
|
|
2899
|
+
options.append(`model: ${event.modelVersion}`);
|
|
2900
|
+
return;
|
|
2901
|
+
}
|
|
2902
|
+
case "usage": {
|
|
2903
|
+
options.append(
|
|
2904
|
+
[
|
|
2905
|
+
"usage:",
|
|
2906
|
+
`modelVersion=${event.modelVersion}`,
|
|
2907
|
+
`costUsd=${formatUsd(event.costUsd)}`,
|
|
2908
|
+
`tokens=${formatToolLogSnippet(sanitiseLogValue(event.usage))}`
|
|
2909
|
+
].join(" ")
|
|
2910
|
+
);
|
|
2911
|
+
return;
|
|
2912
|
+
}
|
|
2913
|
+
case "blocked": {
|
|
2914
|
+
options.append("blocked");
|
|
2915
|
+
return;
|
|
2916
|
+
}
|
|
2917
|
+
case "tool_call": {
|
|
2918
|
+
appendToolCallStreamLog({
|
|
2919
|
+
event,
|
|
2920
|
+
append: options.append
|
|
2921
|
+
});
|
|
2922
|
+
return;
|
|
2923
|
+
}
|
|
2924
|
+
}
|
|
2925
|
+
}
|
|
2926
|
+
var AgentLoggingSessionImpl = class {
|
|
2927
|
+
workspaceDir;
|
|
2928
|
+
logsRootDir;
|
|
2929
|
+
mirrorToConsole;
|
|
2930
|
+
sink;
|
|
2931
|
+
agentLogPath;
|
|
2932
|
+
ensureReady;
|
|
2933
|
+
pending = /* @__PURE__ */ new Set();
|
|
2934
|
+
lineChain = Promise.resolve();
|
|
2935
|
+
callCounter = 0;
|
|
2936
|
+
constructor(config) {
|
|
2937
|
+
this.workspaceDir = import_node_path3.default.resolve(config.workspaceDir ?? process.cwd());
|
|
2938
|
+
this.logsRootDir = import_node_path3.default.join(import_node_path3.default.dirname(this.workspaceDir), "logs");
|
|
2939
|
+
this.mirrorToConsole = config.mirrorToConsole !== false;
|
|
2940
|
+
this.sink = config.sink;
|
|
2941
|
+
this.agentLogPath = import_node_path3.default.join(this.workspaceDir, "agent.log");
|
|
2942
|
+
this.ensureReady = this.prepare();
|
|
2943
|
+
this.track(this.ensureReady);
|
|
2944
|
+
}
|
|
2945
|
+
async prepare() {
|
|
2946
|
+
await (0, import_promises.mkdir)(this.workspaceDir, { recursive: true });
|
|
2947
|
+
await (0, import_promises.mkdir)(this.logsRootDir, { recursive: true });
|
|
2948
|
+
}
|
|
2949
|
+
track(task) {
|
|
2950
|
+
this.pending.add(task);
|
|
2951
|
+
task.finally(() => {
|
|
2952
|
+
this.pending.delete(task);
|
|
2953
|
+
});
|
|
2954
|
+
}
|
|
2955
|
+
enqueueLineWrite(line) {
|
|
2956
|
+
const next = this.lineChain.then(async () => {
|
|
2957
|
+
await this.ensureReady;
|
|
2958
|
+
await (0, import_promises.appendFile)(this.agentLogPath, `${line}
|
|
2959
|
+
`, "utf8");
|
|
2960
|
+
const sinkResult = this.sink?.append(line);
|
|
2961
|
+
if (isPromiseLike(sinkResult)) {
|
|
2962
|
+
await sinkResult;
|
|
2963
|
+
}
|
|
2964
|
+
});
|
|
2965
|
+
const tracked = next.catch(() => void 0);
|
|
2966
|
+
this.lineChain = tracked;
|
|
2967
|
+
this.track(tracked);
|
|
2968
|
+
}
|
|
2969
|
+
logLine(line) {
|
|
2970
|
+
const timestamped = `${toIsoNow()} ${line}`;
|
|
2971
|
+
if (this.mirrorToConsole) {
|
|
2972
|
+
console.log(timestamped);
|
|
2973
|
+
}
|
|
2974
|
+
this.enqueueLineWrite(timestamped);
|
|
2975
|
+
}
|
|
2976
|
+
startLlmCall(input) {
|
|
2977
|
+
const callNumber = this.callCounter + 1;
|
|
2978
|
+
this.callCounter = callNumber;
|
|
2979
|
+
const timestampSegment = toIsoNow().replace(/[:]/g, "-");
|
|
2980
|
+
const modelSegment = normalisePathSegment(input.modelId);
|
|
2981
|
+
const baseDir = import_node_path3.default.join(
|
|
2982
|
+
this.logsRootDir,
|
|
2983
|
+
`${timestampSegment}-${callNumber.toString().padStart(4, "0")}`,
|
|
2984
|
+
modelSegment
|
|
2985
|
+
);
|
|
2986
|
+
const responsePath = import_node_path3.default.join(baseDir, "response.txt");
|
|
2987
|
+
const thoughtsPath = import_node_path3.default.join(baseDir, "thoughts.txt");
|
|
2988
|
+
const responseMetadataPath = import_node_path3.default.join(baseDir, "response.metadata.json");
|
|
2989
|
+
let chain = this.ensureReady.then(async () => {
|
|
2990
|
+
await (0, import_promises.mkdir)(baseDir, { recursive: true });
|
|
2991
|
+
const requestText = input.requestText.trim().length > 0 ? input.requestText : "<empty request>";
|
|
2992
|
+
await (0, import_promises.writeFile)(
|
|
2993
|
+
import_node_path3.default.join(baseDir, "request.txt"),
|
|
2994
|
+
ensureTrailingNewline(requestText),
|
|
2995
|
+
"utf8"
|
|
2996
|
+
);
|
|
2997
|
+
const requestMetadata = {
|
|
2998
|
+
capturedAt: toIsoNow(),
|
|
2999
|
+
provider: input.provider,
|
|
3000
|
+
modelId: input.modelId,
|
|
3001
|
+
...input.requestMetadata ? { request: sanitiseLogValue(input.requestMetadata) } : {}
|
|
3002
|
+
};
|
|
3003
|
+
await (0, import_promises.writeFile)(
|
|
3004
|
+
import_node_path3.default.join(baseDir, "request.metadata.json"),
|
|
3005
|
+
`${JSON.stringify(requestMetadata, null, 2)}
|
|
3006
|
+
`,
|
|
3007
|
+
"utf8"
|
|
3008
|
+
);
|
|
3009
|
+
const usedNames = /* @__PURE__ */ new Set();
|
|
3010
|
+
for (const attachment of input.attachments ?? []) {
|
|
3011
|
+
let filename = normalisePathSegment(attachment.filename);
|
|
3012
|
+
if (!filename.includes(".")) {
|
|
3013
|
+
filename = `${filename}.bin`;
|
|
3014
|
+
}
|
|
3015
|
+
const ext = import_node_path3.default.extname(filename);
|
|
3016
|
+
const base = ext.length > 0 ? filename.slice(0, -ext.length) : filename;
|
|
3017
|
+
let candidate = filename;
|
|
3018
|
+
let duplicateIndex = 2;
|
|
3019
|
+
while (usedNames.has(candidate)) {
|
|
3020
|
+
candidate = `${base}-${duplicateIndex.toString()}${ext}`;
|
|
3021
|
+
duplicateIndex += 1;
|
|
3022
|
+
}
|
|
3023
|
+
usedNames.add(candidate);
|
|
3024
|
+
await (0, import_promises.writeFile)(import_node_path3.default.join(baseDir, candidate), attachment.bytes);
|
|
3025
|
+
}
|
|
3026
|
+
}).catch(() => void 0);
|
|
3027
|
+
this.track(chain);
|
|
3028
|
+
let closed = false;
|
|
3029
|
+
const enqueue = (operation) => {
|
|
3030
|
+
const next = chain.then(operation);
|
|
3031
|
+
const tracked = next.catch(() => void 0);
|
|
3032
|
+
chain = tracked;
|
|
3033
|
+
this.track(tracked);
|
|
3034
|
+
};
|
|
3035
|
+
return {
|
|
3036
|
+
appendThoughtDelta: (text) => {
|
|
3037
|
+
if (closed || text.length === 0) {
|
|
3038
|
+
return;
|
|
3039
|
+
}
|
|
3040
|
+
enqueue(async () => {
|
|
3041
|
+
await (0, import_promises.appendFile)(thoughtsPath, text, "utf8");
|
|
3042
|
+
});
|
|
3043
|
+
},
|
|
3044
|
+
appendResponseDelta: (text) => {
|
|
3045
|
+
if (closed || text.length === 0) {
|
|
3046
|
+
return;
|
|
3047
|
+
}
|
|
3048
|
+
enqueue(async () => {
|
|
3049
|
+
await (0, import_promises.appendFile)(responsePath, text, "utf8");
|
|
3050
|
+
});
|
|
3051
|
+
},
|
|
3052
|
+
complete: (metadata) => {
|
|
3053
|
+
if (closed) {
|
|
3054
|
+
return;
|
|
3055
|
+
}
|
|
3056
|
+
closed = true;
|
|
3057
|
+
enqueue(async () => {
|
|
3058
|
+
const payload = {
|
|
3059
|
+
capturedAt: toIsoNow(),
|
|
3060
|
+
status: "completed"
|
|
3061
|
+
};
|
|
3062
|
+
if (metadata) {
|
|
3063
|
+
const sanitised = sanitiseLogValue(metadata);
|
|
3064
|
+
if (sanitised && typeof sanitised === "object" && !Array.isArray(sanitised)) {
|
|
3065
|
+
Object.assign(payload, sanitised);
|
|
3066
|
+
} else if (sanitised !== void 0) {
|
|
3067
|
+
payload.metadata = sanitised;
|
|
3068
|
+
}
|
|
3069
|
+
}
|
|
3070
|
+
await (0, import_promises.writeFile)(responseMetadataPath, `${JSON.stringify(payload, null, 2)}
|
|
3071
|
+
`, "utf8");
|
|
3072
|
+
});
|
|
3073
|
+
},
|
|
3074
|
+
fail: (error, metadata) => {
|
|
3075
|
+
if (closed) {
|
|
3076
|
+
return;
|
|
3077
|
+
}
|
|
3078
|
+
closed = true;
|
|
3079
|
+
enqueue(async () => {
|
|
3080
|
+
const payload = {
|
|
3081
|
+
capturedAt: toIsoNow(),
|
|
3082
|
+
status: "failed",
|
|
3083
|
+
error: toErrorMessage(error)
|
|
3084
|
+
};
|
|
3085
|
+
if (metadata) {
|
|
3086
|
+
const sanitised = sanitiseLogValue(metadata);
|
|
3087
|
+
if (sanitised && typeof sanitised === "object" && !Array.isArray(sanitised)) {
|
|
3088
|
+
Object.assign(payload, sanitised);
|
|
3089
|
+
} else if (sanitised !== void 0) {
|
|
3090
|
+
payload.metadata = sanitised;
|
|
3091
|
+
}
|
|
3092
|
+
}
|
|
3093
|
+
await (0, import_promises.writeFile)(responseMetadataPath, `${JSON.stringify(payload, null, 2)}
|
|
3094
|
+
`, "utf8");
|
|
3095
|
+
});
|
|
3096
|
+
}
|
|
3097
|
+
};
|
|
3098
|
+
}
|
|
3099
|
+
async flush() {
|
|
3100
|
+
while (this.pending.size > 0) {
|
|
3101
|
+
await Promise.allSettled([...this.pending]);
|
|
3102
|
+
}
|
|
3103
|
+
if (typeof this.sink?.flush === "function") {
|
|
3104
|
+
try {
|
|
3105
|
+
await this.sink.flush();
|
|
3106
|
+
} catch {
|
|
3107
|
+
}
|
|
3108
|
+
}
|
|
3109
|
+
}
|
|
3110
|
+
};
|
|
3111
|
+
var loggingSessionStorage = new import_node_async_hooks.AsyncLocalStorage();
|
|
3112
|
+
function createAgentLoggingSession(config) {
|
|
3113
|
+
return new AgentLoggingSessionImpl(config);
|
|
3114
|
+
}
|
|
3115
|
+
function runWithAgentLoggingSession(session, fn) {
|
|
3116
|
+
if (!session) {
|
|
3117
|
+
return fn();
|
|
3118
|
+
}
|
|
3119
|
+
return loggingSessionStorage.run(session, fn);
|
|
3120
|
+
}
|
|
3121
|
+
function getCurrentAgentLoggingSession() {
|
|
3122
|
+
return loggingSessionStorage.getStore();
|
|
3123
|
+
}
|
|
3124
|
+
|
|
2758
3125
|
// src/llm.ts
|
|
2759
|
-
var toolCallContextStorage = new
|
|
3126
|
+
var toolCallContextStorage = new import_node_async_hooks2.AsyncLocalStorage();
|
|
2760
3127
|
function getCurrentToolCallContext() {
|
|
2761
3128
|
return toolCallContextStorage.getStore() ?? null;
|
|
2762
3129
|
}
|
|
@@ -3048,9 +3415,9 @@ function sanitisePartForLogging(part) {
|
|
|
3048
3415
|
case "inlineData": {
|
|
3049
3416
|
let omittedBytes;
|
|
3050
3417
|
try {
|
|
3051
|
-
omittedBytes =
|
|
3418
|
+
omittedBytes = import_node_buffer3.Buffer.from(part.data, "base64").byteLength;
|
|
3052
3419
|
} catch {
|
|
3053
|
-
omittedBytes =
|
|
3420
|
+
omittedBytes = import_node_buffer3.Buffer.byteLength(part.data, "utf8");
|
|
3054
3421
|
}
|
|
3055
3422
|
return {
|
|
3056
3423
|
type: "inlineData",
|
|
@@ -4113,8 +4480,8 @@ function parseOpenAiToolArguments(raw) {
|
|
|
4113
4480
|
function formatZodIssues(issues) {
|
|
4114
4481
|
const messages = [];
|
|
4115
4482
|
for (const issue of issues) {
|
|
4116
|
-
const
|
|
4117
|
-
messages.push(`${
|
|
4483
|
+
const path8 = issue.path.length > 0 ? issue.path.map(String).join(".") : "input";
|
|
4484
|
+
messages.push(`${path8}: ${issue.message}`);
|
|
4118
4485
|
}
|
|
4119
4486
|
return messages.join("; ");
|
|
4120
4487
|
}
|
|
@@ -4500,9 +4867,9 @@ function resolveGeminiThinkingConfig(modelId, thinkingLevel) {
|
|
|
4500
4867
|
}
|
|
4501
4868
|
function decodeInlineDataBuffer(base64) {
|
|
4502
4869
|
try {
|
|
4503
|
-
return
|
|
4870
|
+
return import_node_buffer3.Buffer.from(base64, "base64");
|
|
4504
4871
|
} catch {
|
|
4505
|
-
return
|
|
4872
|
+
return import_node_buffer3.Buffer.from(base64, "base64url");
|
|
4506
4873
|
}
|
|
4507
4874
|
}
|
|
4508
4875
|
function extractImages(content) {
|
|
@@ -4519,6 +4886,195 @@ function extractImages(content) {
|
|
|
4519
4886
|
}
|
|
4520
4887
|
return images;
|
|
4521
4888
|
}
|
|
4889
|
+
function resolveAttachmentExtension(mimeType) {
|
|
4890
|
+
const normalized = (mimeType ?? "").trim().toLowerCase();
|
|
4891
|
+
switch (normalized) {
|
|
4892
|
+
case "image/jpeg":
|
|
4893
|
+
return "jpg";
|
|
4894
|
+
case "image/png":
|
|
4895
|
+
return "png";
|
|
4896
|
+
case "image/webp":
|
|
4897
|
+
return "webp";
|
|
4898
|
+
case "image/gif":
|
|
4899
|
+
return "gif";
|
|
4900
|
+
case "image/heic":
|
|
4901
|
+
return "heic";
|
|
4902
|
+
case "image/heif":
|
|
4903
|
+
return "heif";
|
|
4904
|
+
case "application/pdf":
|
|
4905
|
+
return "pdf";
|
|
4906
|
+
case "application/json":
|
|
4907
|
+
return "json";
|
|
4908
|
+
case "text/plain":
|
|
4909
|
+
return "txt";
|
|
4910
|
+
case "text/markdown":
|
|
4911
|
+
return "md";
|
|
4912
|
+
default: {
|
|
4913
|
+
const slashIndex = normalized.indexOf("/");
|
|
4914
|
+
if (slashIndex >= 0) {
|
|
4915
|
+
const subtype = normalized.slice(slashIndex + 1).split("+")[0] ?? "";
|
|
4916
|
+
const cleaned = subtype.replace(/[^a-z0-9]+/giu, "");
|
|
4917
|
+
if (cleaned.length > 0) {
|
|
4918
|
+
return cleaned;
|
|
4919
|
+
}
|
|
4920
|
+
}
|
|
4921
|
+
return "bin";
|
|
4922
|
+
}
|
|
4923
|
+
}
|
|
4924
|
+
}
|
|
4925
|
+
function decodeDataUrlAttachment(value, basename) {
|
|
4926
|
+
const trimmed = value.trim();
|
|
4927
|
+
if (!trimmed.toLowerCase().startsWith("data:")) {
|
|
4928
|
+
return null;
|
|
4929
|
+
}
|
|
4930
|
+
const commaIndex = trimmed.indexOf(",");
|
|
4931
|
+
if (commaIndex < 0) {
|
|
4932
|
+
return null;
|
|
4933
|
+
}
|
|
4934
|
+
const header = trimmed.slice(5, commaIndex);
|
|
4935
|
+
const payload = trimmed.slice(commaIndex + 1);
|
|
4936
|
+
const isBase64 = /;base64(?:;|$)/iu.test(header);
|
|
4937
|
+
const mimeType = (header.split(";")[0] ?? "application/octet-stream").trim().toLowerCase();
|
|
4938
|
+
try {
|
|
4939
|
+
const bytes = isBase64 ? import_node_buffer3.Buffer.from(payload, "base64") : import_node_buffer3.Buffer.from(decodeURIComponent(payload), "utf8");
|
|
4940
|
+
return {
|
|
4941
|
+
filename: `${basename}.${resolveAttachmentExtension(mimeType)}`,
|
|
4942
|
+
bytes
|
|
4943
|
+
};
|
|
4944
|
+
} catch {
|
|
4945
|
+
return null;
|
|
4946
|
+
}
|
|
4947
|
+
}
|
|
4948
|
+
function collectPayloadAttachments(value, options) {
|
|
4949
|
+
if (typeof value === "string") {
|
|
4950
|
+
const attachment = decodeDataUrlAttachment(
|
|
4951
|
+
value,
|
|
4952
|
+
`${options.prefix}-${options.counter.toString()}`
|
|
4953
|
+
);
|
|
4954
|
+
if (attachment) {
|
|
4955
|
+
options.attachments.push(attachment);
|
|
4956
|
+
options.counter += 1;
|
|
4957
|
+
}
|
|
4958
|
+
return;
|
|
4959
|
+
}
|
|
4960
|
+
if (!value || typeof value !== "object") {
|
|
4961
|
+
return;
|
|
4962
|
+
}
|
|
4963
|
+
if (options.seen.has(value)) {
|
|
4964
|
+
return;
|
|
4965
|
+
}
|
|
4966
|
+
options.seen.add(value);
|
|
4967
|
+
if (Array.isArray(value)) {
|
|
4968
|
+
for (const entry of value) {
|
|
4969
|
+
collectPayloadAttachments(entry, options);
|
|
4970
|
+
}
|
|
4971
|
+
return;
|
|
4972
|
+
}
|
|
4973
|
+
const record = value;
|
|
4974
|
+
const mimeType = typeof record.mimeType === "string" ? record.mimeType : void 0;
|
|
4975
|
+
if (typeof record.data === "string" && mimeType) {
|
|
4976
|
+
try {
|
|
4977
|
+
options.attachments.push({
|
|
4978
|
+
filename: `${options.prefix}-${options.counter.toString()}.${resolveAttachmentExtension(mimeType)}`,
|
|
4979
|
+
bytes: decodeInlineDataBuffer(record.data)
|
|
4980
|
+
});
|
|
4981
|
+
options.counter += 1;
|
|
4982
|
+
} catch {
|
|
4983
|
+
}
|
|
4984
|
+
}
|
|
4985
|
+
for (const entry of Object.values(record)) {
|
|
4986
|
+
collectPayloadAttachments(entry, options);
|
|
4987
|
+
}
|
|
4988
|
+
}
|
|
4989
|
+
function serialiseRequestPayloadForLogging(value) {
|
|
4990
|
+
try {
|
|
4991
|
+
return `${JSON.stringify(sanitiseLogValue(value), null, 2)}
|
|
4992
|
+
`;
|
|
4993
|
+
} catch {
|
|
4994
|
+
return `${String(value)}
|
|
4995
|
+
`;
|
|
4996
|
+
}
|
|
4997
|
+
}
|
|
4998
|
+
function startLlmCallLoggerFromContents(options) {
|
|
4999
|
+
const session = getCurrentAgentLoggingSession();
|
|
5000
|
+
if (!session) {
|
|
5001
|
+
return void 0;
|
|
5002
|
+
}
|
|
5003
|
+
const attachments = [];
|
|
5004
|
+
const sections = [];
|
|
5005
|
+
for (const [messageIndex, message] of options.contents.entries()) {
|
|
5006
|
+
sections.push(`### message_${(messageIndex + 1).toString()} role=${message.role}`);
|
|
5007
|
+
for (const [partIndex, part] of message.parts.entries()) {
|
|
5008
|
+
if (part.type === "text") {
|
|
5009
|
+
const channel = part.thought === true ? "thought" : "response";
|
|
5010
|
+
sections.push(`[text:${channel}]`);
|
|
5011
|
+
sections.push(part.text);
|
|
5012
|
+
continue;
|
|
5013
|
+
}
|
|
5014
|
+
const filename = `message-${(messageIndex + 1).toString()}-part-${(partIndex + 1).toString()}.${resolveAttachmentExtension(part.mimeType)}`;
|
|
5015
|
+
attachments.push({
|
|
5016
|
+
filename,
|
|
5017
|
+
bytes: decodeInlineDataBuffer(part.data)
|
|
5018
|
+
});
|
|
5019
|
+
sections.push(
|
|
5020
|
+
`[inlineData] file=${filename} mime=${part.mimeType ?? "application/octet-stream"} bytes=${attachments[attachments.length - 1]?.bytes.byteLength ?? 0}`
|
|
5021
|
+
);
|
|
5022
|
+
}
|
|
5023
|
+
sections.push("");
|
|
5024
|
+
}
|
|
5025
|
+
return session.startLlmCall({
|
|
5026
|
+
provider: options.provider,
|
|
5027
|
+
modelId: options.request.model,
|
|
5028
|
+
requestText: sections.join("\n").trim(),
|
|
5029
|
+
requestMetadata: {
|
|
5030
|
+
model: options.request.model,
|
|
5031
|
+
input: options.contents.map((content) => ({
|
|
5032
|
+
role: content.role,
|
|
5033
|
+
parts: content.parts.map((part) => sanitisePartForLogging(part))
|
|
5034
|
+
})),
|
|
5035
|
+
...options.request.instructions ? {
|
|
5036
|
+
instructions: options.request.instructions
|
|
5037
|
+
} : {},
|
|
5038
|
+
...options.request.tools ? { tools: options.request.tools } : {},
|
|
5039
|
+
...options.request.responseMimeType ? {
|
|
5040
|
+
responseMimeType: options.request.responseMimeType
|
|
5041
|
+
} : {},
|
|
5042
|
+
...options.request.responseJsonSchema ? {
|
|
5043
|
+
responseJsonSchema: sanitiseLogValue(options.request.responseJsonSchema)
|
|
5044
|
+
} : {},
|
|
5045
|
+
...options.request.responseModalities ? { responseModalities: options.request.responseModalities } : {},
|
|
5046
|
+
...options.request.imageAspectRatio ? { imageAspectRatio: options.request.imageAspectRatio } : {},
|
|
5047
|
+
...options.request.imageSize ? { imageSize: options.request.imageSize } : {},
|
|
5048
|
+
...options.request.thinkingLevel ? { thinkingLevel: options.request.thinkingLevel } : {},
|
|
5049
|
+
...options.request.openAiTextFormat ? { openAiTextFormat: sanitiseLogValue(options.request.openAiTextFormat) } : {},
|
|
5050
|
+
...getCurrentToolCallContext() ? { toolContext: getCurrentToolCallContext() } : {}
|
|
5051
|
+
},
|
|
5052
|
+
attachments
|
|
5053
|
+
});
|
|
5054
|
+
}
|
|
5055
|
+
function startLlmCallLoggerFromPayload(options) {
|
|
5056
|
+
const session = getCurrentAgentLoggingSession();
|
|
5057
|
+
if (!session) {
|
|
5058
|
+
return void 0;
|
|
5059
|
+
}
|
|
5060
|
+
const attachments = [];
|
|
5061
|
+
collectPayloadAttachments(options.requestPayload, {
|
|
5062
|
+
prefix: `step-${options.step.toString()}`,
|
|
5063
|
+
attachments,
|
|
5064
|
+
seen: /* @__PURE__ */ new WeakSet(),
|
|
5065
|
+
counter: 1
|
|
5066
|
+
});
|
|
5067
|
+
return session.startLlmCall({
|
|
5068
|
+
provider: options.provider,
|
|
5069
|
+
modelId: options.modelId,
|
|
5070
|
+
requestText: serialiseRequestPayloadForLogging(options.requestPayload),
|
|
5071
|
+
requestMetadata: {
|
|
5072
|
+
step: options.step,
|
|
5073
|
+
...getCurrentToolCallContext() ? { toolContext: getCurrentToolCallContext() } : {}
|
|
5074
|
+
},
|
|
5075
|
+
attachments
|
|
5076
|
+
});
|
|
5077
|
+
}
|
|
4522
5078
|
async function runTextCall(params) {
|
|
4523
5079
|
const { request, queue, abortController } = params;
|
|
4524
5080
|
const providerInfo = resolveProvider(request.model);
|
|
@@ -4528,6 +5084,11 @@ async function runTextCall(params) {
|
|
|
4528
5084
|
if (contents.length === 0) {
|
|
4529
5085
|
throw new Error("LLM call received an empty prompt.");
|
|
4530
5086
|
}
|
|
5087
|
+
const callLogger = startLlmCallLoggerFromContents({
|
|
5088
|
+
provider,
|
|
5089
|
+
request,
|
|
5090
|
+
contents
|
|
5091
|
+
});
|
|
4531
5092
|
let modelVersion = request.model;
|
|
4532
5093
|
let blocked = false;
|
|
4533
5094
|
let grounding;
|
|
@@ -4535,12 +5096,17 @@ async function runTextCall(params) {
|
|
|
4535
5096
|
let responseRole;
|
|
4536
5097
|
let latestUsage;
|
|
4537
5098
|
let responseImages = 0;
|
|
4538
|
-
const pushDelta = (channel,
|
|
4539
|
-
if (!
|
|
5099
|
+
const pushDelta = (channel, text) => {
|
|
5100
|
+
if (!text) {
|
|
4540
5101
|
return;
|
|
4541
5102
|
}
|
|
4542
|
-
responseParts.push({ type: "text", text
|
|
4543
|
-
|
|
5103
|
+
responseParts.push({ type: "text", text, ...channel === "thought" ? { thought: true } : {} });
|
|
5104
|
+
if (channel === "thought") {
|
|
5105
|
+
callLogger?.appendThoughtDelta(text);
|
|
5106
|
+
} else {
|
|
5107
|
+
callLogger?.appendResponseDelta(text);
|
|
5108
|
+
}
|
|
5109
|
+
queue.push({ type: "delta", channel, text });
|
|
4544
5110
|
};
|
|
4545
5111
|
const pushInline = (data, mimeType) => {
|
|
4546
5112
|
if (!data) {
|
|
@@ -4567,263 +5133,294 @@ async function runTextCall(params) {
|
|
|
4567
5133
|
return abortController.signal;
|
|
4568
5134
|
};
|
|
4569
5135
|
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
|
-
|
|
4595
|
-
|
|
4596
|
-
|
|
4597
|
-
|
|
4598
|
-
|
|
4599
|
-
|
|
5136
|
+
try {
|
|
5137
|
+
if (provider === "openai") {
|
|
5138
|
+
const openAiInput = toOpenAiInput(contents);
|
|
5139
|
+
const openAiTools = toOpenAiTools(request.tools);
|
|
5140
|
+
const reasoningEffort = resolveOpenAiReasoningEffort(modelForProvider, request.thinkingLevel);
|
|
5141
|
+
const openAiTextConfig = {
|
|
5142
|
+
format: request.openAiTextFormat ?? { type: "text" },
|
|
5143
|
+
verbosity: resolveOpenAiVerbosity(modelForProvider)
|
|
5144
|
+
};
|
|
5145
|
+
const reasoning = {
|
|
5146
|
+
effort: toOpenAiReasoningEffort(reasoningEffort),
|
|
5147
|
+
summary: "detailed"
|
|
5148
|
+
};
|
|
5149
|
+
await runOpenAiCall(async (client) => {
|
|
5150
|
+
const stream = client.responses.stream(
|
|
5151
|
+
{
|
|
5152
|
+
model: modelForProvider,
|
|
5153
|
+
input: openAiInput,
|
|
5154
|
+
reasoning,
|
|
5155
|
+
text: openAiTextConfig,
|
|
5156
|
+
...openAiTools ? { tools: openAiTools } : {},
|
|
5157
|
+
include: ["code_interpreter_call.outputs", "reasoning.encrypted_content"]
|
|
5158
|
+
},
|
|
5159
|
+
{ signal }
|
|
5160
|
+
);
|
|
5161
|
+
for await (const event of stream) {
|
|
5162
|
+
switch (event.type) {
|
|
5163
|
+
case "response.output_text.delta": {
|
|
5164
|
+
const delta = event.delta ?? "";
|
|
5165
|
+
pushDelta("response", typeof delta === "string" ? delta : "");
|
|
5166
|
+
break;
|
|
5167
|
+
}
|
|
5168
|
+
case "response.reasoning_summary_text.delta": {
|
|
5169
|
+
const delta = event.delta ?? "";
|
|
5170
|
+
pushDelta("thought", typeof delta === "string" ? delta : "");
|
|
5171
|
+
break;
|
|
5172
|
+
}
|
|
5173
|
+
case "response.refusal.delta": {
|
|
5174
|
+
blocked = true;
|
|
5175
|
+
queue.push({ type: "blocked" });
|
|
5176
|
+
break;
|
|
5177
|
+
}
|
|
5178
|
+
default:
|
|
5179
|
+
break;
|
|
4600
5180
|
}
|
|
4601
|
-
|
|
4602
|
-
|
|
4603
|
-
|
|
4604
|
-
|
|
5181
|
+
}
|
|
5182
|
+
const finalResponse = await stream.finalResponse();
|
|
5183
|
+
modelVersion = typeof finalResponse.model === "string" ? finalResponse.model : request.model;
|
|
5184
|
+
queue.push({ type: "model", modelVersion });
|
|
5185
|
+
if (finalResponse.error) {
|
|
5186
|
+
const message = typeof finalResponse.error.message === "string" ? finalResponse.error.message : "OpenAI response failed";
|
|
5187
|
+
throw new Error(message);
|
|
5188
|
+
}
|
|
5189
|
+
if (finalResponse.status && finalResponse.status !== "completed" && finalResponse.status !== "in_progress") {
|
|
5190
|
+
const detail = finalResponse.incomplete_details?.reason;
|
|
5191
|
+
throw new Error(
|
|
5192
|
+
`OpenAI response status ${finalResponse.status}${detail ? ` (${detail})` : ""}`
|
|
5193
|
+
);
|
|
5194
|
+
}
|
|
5195
|
+
latestUsage = extractOpenAiUsageTokens(finalResponse.usage);
|
|
5196
|
+
if (responseParts.length === 0) {
|
|
5197
|
+
const fallback = extractOpenAiResponseParts(finalResponse);
|
|
5198
|
+
blocked = blocked || fallback.blocked;
|
|
5199
|
+
for (const part of fallback.parts) {
|
|
5200
|
+
if (part.type === "text") {
|
|
5201
|
+
pushDelta(part.thought === true ? "thought" : "response", part.text);
|
|
5202
|
+
} else {
|
|
5203
|
+
pushInline(part.data, part.mimeType);
|
|
5204
|
+
}
|
|
4605
5205
|
}
|
|
4606
|
-
|
|
4607
|
-
|
|
4608
|
-
|
|
4609
|
-
|
|
5206
|
+
}
|
|
5207
|
+
}, modelForProvider);
|
|
5208
|
+
} else if (provider === "chatgpt") {
|
|
5209
|
+
const chatGptInput = toChatGptInput(contents);
|
|
5210
|
+
const reasoningEffort = resolveOpenAiReasoningEffort(request.model, request.thinkingLevel);
|
|
5211
|
+
const openAiTools = toOpenAiTools(request.tools);
|
|
5212
|
+
const requestPayload = {
|
|
5213
|
+
model: modelForProvider,
|
|
5214
|
+
store: false,
|
|
5215
|
+
stream: true,
|
|
5216
|
+
instructions: chatGptInput.instructions ?? "You are a helpful assistant.",
|
|
5217
|
+
input: chatGptInput.input,
|
|
5218
|
+
include: ["reasoning.encrypted_content"],
|
|
5219
|
+
reasoning: {
|
|
5220
|
+
effort: toOpenAiReasoningEffort(reasoningEffort),
|
|
5221
|
+
summary: "detailed"
|
|
5222
|
+
},
|
|
5223
|
+
text: {
|
|
5224
|
+
format: request.openAiTextFormat ?? { type: "text" },
|
|
5225
|
+
verbosity: resolveOpenAiVerbosity(request.model)
|
|
5226
|
+
},
|
|
5227
|
+
...openAiTools ? { tools: openAiTools } : {}
|
|
5228
|
+
};
|
|
5229
|
+
let sawResponseDelta = false;
|
|
5230
|
+
let sawThoughtDelta = false;
|
|
5231
|
+
const result = await collectChatGptCodexResponseWithRetry({
|
|
5232
|
+
request: requestPayload,
|
|
5233
|
+
signal,
|
|
5234
|
+
onDelta: (delta) => {
|
|
5235
|
+
if (delta.thoughtDelta) {
|
|
5236
|
+
sawThoughtDelta = true;
|
|
5237
|
+
pushDelta("thought", delta.thoughtDelta);
|
|
5238
|
+
}
|
|
5239
|
+
if (delta.textDelta) {
|
|
5240
|
+
sawResponseDelta = true;
|
|
5241
|
+
pushDelta("response", delta.textDelta);
|
|
4610
5242
|
}
|
|
4611
|
-
default:
|
|
4612
|
-
break;
|
|
4613
5243
|
}
|
|
5244
|
+
});
|
|
5245
|
+
blocked = blocked || result.blocked;
|
|
5246
|
+
if (blocked) {
|
|
5247
|
+
queue.push({ type: "blocked" });
|
|
4614
5248
|
}
|
|
4615
|
-
|
|
4616
|
-
|
|
4617
|
-
|
|
4618
|
-
if (finalResponse.error) {
|
|
4619
|
-
const message = typeof finalResponse.error.message === "string" ? finalResponse.error.message : "OpenAI response failed";
|
|
4620
|
-
throw new Error(message);
|
|
5249
|
+
if (result.model) {
|
|
5250
|
+
modelVersion = `chatgpt-${result.model}`;
|
|
5251
|
+
queue.push({ type: "model", modelVersion });
|
|
4621
5252
|
}
|
|
4622
|
-
|
|
4623
|
-
|
|
5253
|
+
latestUsage = extractChatGptUsageTokens(result.usage);
|
|
5254
|
+
const fallbackText = typeof result.text === "string" ? result.text : "";
|
|
5255
|
+
const fallbackThoughts = typeof result.reasoningSummaryText === "string" && result.reasoningSummaryText.length > 0 ? result.reasoningSummaryText : typeof result.reasoningText === "string" ? result.reasoningText : "";
|
|
5256
|
+
if (!sawThoughtDelta && fallbackThoughts.length > 0) {
|
|
5257
|
+
pushDelta("thought", fallbackThoughts);
|
|
5258
|
+
}
|
|
5259
|
+
if (!sawResponseDelta && fallbackText.length > 0) {
|
|
5260
|
+
pushDelta("response", fallbackText);
|
|
5261
|
+
}
|
|
5262
|
+
} else if (provider === "fireworks") {
|
|
5263
|
+
if (request.tools && request.tools.length > 0) {
|
|
4624
5264
|
throw new Error(
|
|
4625
|
-
|
|
5265
|
+
"Fireworks provider does not support provider-native tools in generateText; use runToolLoop for function tools."
|
|
4626
5266
|
);
|
|
4627
5267
|
}
|
|
4628
|
-
|
|
4629
|
-
|
|
4630
|
-
|
|
4631
|
-
|
|
4632
|
-
|
|
4633
|
-
|
|
4634
|
-
|
|
4635
|
-
|
|
4636
|
-
|
|
5268
|
+
const fireworksMessages = toFireworksMessages(contents, {
|
|
5269
|
+
responseMimeType: request.responseMimeType,
|
|
5270
|
+
responseJsonSchema: request.responseJsonSchema
|
|
5271
|
+
});
|
|
5272
|
+
await runFireworksCall(async (client) => {
|
|
5273
|
+
const responseFormat = request.responseJsonSchema ? {
|
|
5274
|
+
type: "json_schema",
|
|
5275
|
+
json_schema: {
|
|
5276
|
+
name: "llm-response",
|
|
5277
|
+
schema: request.responseJsonSchema
|
|
4637
5278
|
}
|
|
4638
|
-
}
|
|
4639
|
-
|
|
4640
|
-
|
|
4641
|
-
|
|
4642
|
-
|
|
4643
|
-
|
|
4644
|
-
|
|
4645
|
-
|
|
4646
|
-
|
|
4647
|
-
|
|
4648
|
-
|
|
4649
|
-
|
|
4650
|
-
|
|
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);
|
|
4668
|
-
}
|
|
4669
|
-
if (delta.textDelta) {
|
|
4670
|
-
sawResponseDelta = true;
|
|
4671
|
-
pushDelta("response", delta.textDelta);
|
|
4672
|
-
}
|
|
4673
|
-
}
|
|
4674
|
-
});
|
|
4675
|
-
blocked = blocked || result.blocked;
|
|
4676
|
-
if (blocked) {
|
|
4677
|
-
queue.push({ type: "blocked" });
|
|
4678
|
-
}
|
|
4679
|
-
if (result.model) {
|
|
4680
|
-
modelVersion = `chatgpt-${result.model}`;
|
|
4681
|
-
queue.push({ type: "model", modelVersion });
|
|
4682
|
-
}
|
|
4683
|
-
latestUsage = extractChatGptUsageTokens(result.usage);
|
|
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
|
|
4708
|
-
}
|
|
4709
|
-
} : request.responseMimeType === "application/json" ? { type: "json_object" } : void 0;
|
|
4710
|
-
const response = await client.chat.completions.create(
|
|
4711
|
-
{
|
|
4712
|
-
model: modelForProvider,
|
|
4713
|
-
messages: fireworksMessages,
|
|
4714
|
-
...responseFormat ? { response_format: responseFormat } : {}
|
|
4715
|
-
},
|
|
4716
|
-
{ signal }
|
|
4717
|
-
);
|
|
4718
|
-
modelVersion = typeof response.model === "string" ? response.model : request.model;
|
|
4719
|
-
queue.push({ type: "model", modelVersion });
|
|
4720
|
-
const choice = Array.isArray(response.choices) ? response.choices[0] : void 0;
|
|
4721
|
-
if (choice?.finish_reason === "content_filter") {
|
|
4722
|
-
blocked = true;
|
|
4723
|
-
queue.push({ type: "blocked" });
|
|
4724
|
-
}
|
|
4725
|
-
const textOutput = extractFireworksMessageText(
|
|
4726
|
-
choice?.message
|
|
4727
|
-
);
|
|
4728
|
-
if (textOutput.length > 0) {
|
|
4729
|
-
pushDelta("response", textOutput);
|
|
4730
|
-
}
|
|
4731
|
-
latestUsage = extractFireworksUsageTokens(response.usage);
|
|
4732
|
-
}, modelForProvider);
|
|
4733
|
-
} else {
|
|
4734
|
-
const geminiContents = contents.map(convertLlmContentToGeminiContent);
|
|
4735
|
-
const thinkingConfig = resolveGeminiThinkingConfig(modelForProvider, request.thinkingLevel);
|
|
4736
|
-
const config = {
|
|
4737
|
-
maxOutputTokens: 32e3,
|
|
4738
|
-
...thinkingConfig ? { thinkingConfig } : {},
|
|
4739
|
-
...request.responseMimeType ? { responseMimeType: request.responseMimeType } : {},
|
|
4740
|
-
...request.responseJsonSchema ? { responseJsonSchema: request.responseJsonSchema } : {},
|
|
4741
|
-
...request.responseModalities ? { responseModalities: Array.from(request.responseModalities) } : {},
|
|
4742
|
-
...request.imageAspectRatio || request.imageSize ? {
|
|
4743
|
-
imageConfig: {
|
|
4744
|
-
...request.imageAspectRatio ? { aspectRatio: request.imageAspectRatio } : {},
|
|
4745
|
-
...request.imageSize ? { imageSize: request.imageSize } : {}
|
|
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
|
|
4758
|
-
});
|
|
4759
|
-
let latestGrounding;
|
|
4760
|
-
for await (const chunk of stream) {
|
|
4761
|
-
if (chunk.modelVersion) {
|
|
4762
|
-
modelVersion = chunk.modelVersion;
|
|
4763
|
-
queue.push({ type: "model", modelVersion });
|
|
4764
|
-
}
|
|
4765
|
-
if (chunk.promptFeedback?.blockReason) {
|
|
5279
|
+
} : request.responseMimeType === "application/json" ? { type: "json_object" } : void 0;
|
|
5280
|
+
const response = await client.chat.completions.create(
|
|
5281
|
+
{
|
|
5282
|
+
model: modelForProvider,
|
|
5283
|
+
messages: fireworksMessages,
|
|
5284
|
+
...responseFormat ? { response_format: responseFormat } : {}
|
|
5285
|
+
},
|
|
5286
|
+
{ signal }
|
|
5287
|
+
);
|
|
5288
|
+
modelVersion = typeof response.model === "string" ? response.model : request.model;
|
|
5289
|
+
queue.push({ type: "model", modelVersion });
|
|
5290
|
+
const choice = Array.isArray(response.choices) ? response.choices[0] : void 0;
|
|
5291
|
+
if (choice?.finish_reason === "content_filter") {
|
|
4766
5292
|
blocked = true;
|
|
4767
5293
|
queue.push({ type: "blocked" });
|
|
4768
5294
|
}
|
|
4769
|
-
|
|
4770
|
-
|
|
4771
|
-
|
|
4772
|
-
|
|
4773
|
-
|
|
4774
|
-
const primary = candidates[0];
|
|
4775
|
-
if (primary && isModerationFinish(primary.finishReason)) {
|
|
4776
|
-
blocked = true;
|
|
4777
|
-
queue.push({ type: "blocked" });
|
|
5295
|
+
const textOutput = extractFireworksMessageText(
|
|
5296
|
+
choice?.message
|
|
5297
|
+
);
|
|
5298
|
+
if (textOutput.length > 0) {
|
|
5299
|
+
pushDelta("response", textOutput);
|
|
4778
5300
|
}
|
|
4779
|
-
|
|
4780
|
-
|
|
4781
|
-
|
|
4782
|
-
|
|
5301
|
+
latestUsage = extractFireworksUsageTokens(response.usage);
|
|
5302
|
+
}, modelForProvider);
|
|
5303
|
+
} else {
|
|
5304
|
+
const geminiContents = contents.map(convertLlmContentToGeminiContent);
|
|
5305
|
+
const thinkingConfig = resolveGeminiThinkingConfig(modelForProvider, request.thinkingLevel);
|
|
5306
|
+
const config = {
|
|
5307
|
+
maxOutputTokens: 32e3,
|
|
5308
|
+
...thinkingConfig ? { thinkingConfig } : {},
|
|
5309
|
+
...request.responseMimeType ? { responseMimeType: request.responseMimeType } : {},
|
|
5310
|
+
...request.responseJsonSchema ? { responseJsonSchema: request.responseJsonSchema } : {},
|
|
5311
|
+
...request.responseModalities ? { responseModalities: Array.from(request.responseModalities) } : {},
|
|
5312
|
+
...request.imageAspectRatio || request.imageSize ? {
|
|
5313
|
+
imageConfig: {
|
|
5314
|
+
...request.imageAspectRatio ? { aspectRatio: request.imageAspectRatio } : {},
|
|
5315
|
+
...request.imageSize ? { imageSize: request.imageSize } : {}
|
|
4783
5316
|
}
|
|
4784
|
-
|
|
4785
|
-
|
|
5317
|
+
} : {}
|
|
5318
|
+
};
|
|
5319
|
+
const geminiTools = toGeminiTools(request.tools);
|
|
5320
|
+
if (geminiTools) {
|
|
5321
|
+
config.tools = geminiTools;
|
|
5322
|
+
}
|
|
5323
|
+
await runGeminiCall(async (client) => {
|
|
5324
|
+
const stream = await client.models.generateContentStream({
|
|
5325
|
+
model: modelForProvider,
|
|
5326
|
+
contents: geminiContents,
|
|
5327
|
+
config
|
|
5328
|
+
});
|
|
5329
|
+
let latestGrounding;
|
|
5330
|
+
for await (const chunk of stream) {
|
|
5331
|
+
if (chunk.modelVersion) {
|
|
5332
|
+
modelVersion = chunk.modelVersion;
|
|
5333
|
+
queue.push({ type: "model", modelVersion });
|
|
4786
5334
|
}
|
|
4787
|
-
|
|
4788
|
-
|
|
4789
|
-
|
|
5335
|
+
if (chunk.promptFeedback?.blockReason) {
|
|
5336
|
+
blocked = true;
|
|
5337
|
+
queue.push({ type: "blocked" });
|
|
4790
5338
|
}
|
|
4791
|
-
|
|
4792
|
-
|
|
4793
|
-
|
|
4794
|
-
|
|
4795
|
-
|
|
5339
|
+
latestUsage = mergeTokenUpdates(
|
|
5340
|
+
latestUsage,
|
|
5341
|
+
extractGeminiUsageTokens(chunk.usageMetadata)
|
|
5342
|
+
);
|
|
5343
|
+
const candidates = chunk.candidates;
|
|
5344
|
+
if (!candidates || candidates.length === 0) {
|
|
5345
|
+
continue;
|
|
5346
|
+
}
|
|
5347
|
+
const primary = candidates[0];
|
|
5348
|
+
if (primary && isModerationFinish(primary.finishReason)) {
|
|
5349
|
+
blocked = true;
|
|
5350
|
+
queue.push({ type: "blocked" });
|
|
5351
|
+
}
|
|
5352
|
+
for (const candidate of candidates) {
|
|
5353
|
+
const candidateContent = candidate.content;
|
|
5354
|
+
if (!candidateContent) {
|
|
5355
|
+
continue;
|
|
5356
|
+
}
|
|
5357
|
+
if (candidate.groundingMetadata) {
|
|
5358
|
+
latestGrounding = candidate.groundingMetadata;
|
|
5359
|
+
}
|
|
5360
|
+
const content2 = convertGeminiContentToLlmContent(candidateContent);
|
|
5361
|
+
if (!responseRole) {
|
|
5362
|
+
responseRole = content2.role;
|
|
5363
|
+
}
|
|
5364
|
+
for (const part of content2.parts) {
|
|
5365
|
+
if (part.type === "text") {
|
|
5366
|
+
pushDelta(part.thought === true ? "thought" : "response", part.text);
|
|
5367
|
+
} else {
|
|
5368
|
+
pushInline(part.data, part.mimeType);
|
|
5369
|
+
}
|
|
4796
5370
|
}
|
|
4797
5371
|
}
|
|
4798
5372
|
}
|
|
4799
|
-
|
|
4800
|
-
|
|
4801
|
-
}
|
|
4802
|
-
|
|
4803
|
-
|
|
4804
|
-
|
|
4805
|
-
|
|
4806
|
-
|
|
4807
|
-
|
|
4808
|
-
|
|
4809
|
-
|
|
4810
|
-
|
|
4811
|
-
|
|
4812
|
-
|
|
4813
|
-
|
|
5373
|
+
grounding = latestGrounding;
|
|
5374
|
+
}, modelForProvider);
|
|
5375
|
+
}
|
|
5376
|
+
const mergedParts = mergeConsecutiveTextParts(responseParts);
|
|
5377
|
+
const content = mergedParts.length > 0 ? { role: responseRole ?? "assistant", parts: mergedParts } : void 0;
|
|
5378
|
+
const { text, thoughts } = extractTextByChannel(content);
|
|
5379
|
+
const costUsd = estimateCallCostUsd({
|
|
5380
|
+
modelId: modelVersion,
|
|
5381
|
+
tokens: latestUsage,
|
|
5382
|
+
responseImages,
|
|
5383
|
+
imageSize: request.imageSize
|
|
5384
|
+
});
|
|
5385
|
+
if (latestUsage) {
|
|
5386
|
+
queue.push({ type: "usage", usage: latestUsage, costUsd, modelVersion });
|
|
5387
|
+
}
|
|
5388
|
+
callLogger?.complete({
|
|
5389
|
+
provider,
|
|
5390
|
+
model: request.model,
|
|
5391
|
+
modelVersion,
|
|
5392
|
+
blocked,
|
|
5393
|
+
costUsd,
|
|
5394
|
+
usage: latestUsage,
|
|
5395
|
+
grounding: grounding ? sanitiseLogValue(grounding) : void 0,
|
|
5396
|
+
responseChars: text.length,
|
|
5397
|
+
thoughtChars: thoughts.length,
|
|
5398
|
+
responseImages
|
|
5399
|
+
});
|
|
5400
|
+
return {
|
|
5401
|
+
provider,
|
|
5402
|
+
model: request.model,
|
|
5403
|
+
modelVersion,
|
|
5404
|
+
content,
|
|
5405
|
+
text,
|
|
5406
|
+
thoughts,
|
|
5407
|
+
blocked,
|
|
5408
|
+
usage: latestUsage,
|
|
5409
|
+
costUsd,
|
|
5410
|
+
grounding
|
|
5411
|
+
};
|
|
5412
|
+
} catch (error) {
|
|
5413
|
+
callLogger?.fail(error, {
|
|
5414
|
+
provider,
|
|
5415
|
+
model: request.model,
|
|
5416
|
+
modelVersion,
|
|
5417
|
+
blocked,
|
|
5418
|
+
usage: latestUsage,
|
|
5419
|
+
partialResponseParts: responseParts.length,
|
|
5420
|
+
responseImages
|
|
5421
|
+
});
|
|
5422
|
+
throw error;
|
|
4814
5423
|
}
|
|
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
5424
|
}
|
|
4828
5425
|
function streamText(request) {
|
|
4829
5426
|
const queue = createAsyncQueue();
|
|
@@ -5286,6 +5883,23 @@ async function runToolLoop(request) {
|
|
|
5286
5883
|
let modelVersion = request.model;
|
|
5287
5884
|
let usageTokens;
|
|
5288
5885
|
let thoughtDeltaEmitted = false;
|
|
5886
|
+
let blocked = false;
|
|
5887
|
+
const stepRequestPayload = {
|
|
5888
|
+
model: providerInfo.model,
|
|
5889
|
+
input,
|
|
5890
|
+
...previousResponseId ? { previous_response_id: previousResponseId } : {},
|
|
5891
|
+
...openAiTools.length > 0 ? { tools: openAiTools } : {},
|
|
5892
|
+
...openAiTools.length > 0 ? { parallel_tool_calls: true } : {},
|
|
5893
|
+
reasoning,
|
|
5894
|
+
text: textConfig,
|
|
5895
|
+
include: ["reasoning.encrypted_content"]
|
|
5896
|
+
};
|
|
5897
|
+
const stepCallLogger = startLlmCallLoggerFromPayload({
|
|
5898
|
+
provider: "openai",
|
|
5899
|
+
modelId: request.model,
|
|
5900
|
+
requestPayload: stepRequestPayload,
|
|
5901
|
+
step: turn
|
|
5902
|
+
});
|
|
5289
5903
|
const emitEvent = (ev) => {
|
|
5290
5904
|
onEvent?.(ev);
|
|
5291
5905
|
};
|
|
@@ -5294,226 +5908,276 @@ async function runToolLoop(request) {
|
|
|
5294
5908
|
firstModelEventAtMs = Date.now();
|
|
5295
5909
|
}
|
|
5296
5910
|
};
|
|
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
|
-
|
|
5911
|
+
try {
|
|
5912
|
+
const finalResponse = await runOpenAiCall(
|
|
5913
|
+
async (client) => {
|
|
5914
|
+
const stream = client.responses.stream(
|
|
5915
|
+
{
|
|
5916
|
+
model: providerInfo.model,
|
|
5917
|
+
input,
|
|
5918
|
+
...previousResponseId ? { previous_response_id: previousResponseId } : {},
|
|
5919
|
+
...openAiTools.length > 0 ? { tools: openAiTools } : {},
|
|
5920
|
+
...openAiTools.length > 0 ? { parallel_tool_calls: true } : {},
|
|
5921
|
+
reasoning,
|
|
5922
|
+
text: textConfig,
|
|
5923
|
+
include: ["reasoning.encrypted_content"]
|
|
5924
|
+
},
|
|
5925
|
+
{ signal: abortController.signal }
|
|
5926
|
+
);
|
|
5927
|
+
for await (const event of stream) {
|
|
5928
|
+
markFirstModelEvent();
|
|
5929
|
+
switch (event.type) {
|
|
5930
|
+
case "response.output_text.delta": {
|
|
5931
|
+
const text = typeof event.delta === "string" ? event.delta : "";
|
|
5932
|
+
if (text.length > 0) {
|
|
5933
|
+
stepCallLogger?.appendResponseDelta(text);
|
|
5934
|
+
}
|
|
5935
|
+
emitEvent({
|
|
5936
|
+
type: "delta",
|
|
5937
|
+
channel: "response",
|
|
5938
|
+
text
|
|
5939
|
+
});
|
|
5940
|
+
break;
|
|
5941
|
+
}
|
|
5942
|
+
case "response.reasoning_summary_text.delta": {
|
|
5943
|
+
thoughtDeltaEmitted = true;
|
|
5944
|
+
const text = typeof event.delta === "string" ? event.delta : "";
|
|
5945
|
+
if (text.length > 0) {
|
|
5946
|
+
stepCallLogger?.appendThoughtDelta(text);
|
|
5947
|
+
}
|
|
5948
|
+
emitEvent({
|
|
5949
|
+
type: "delta",
|
|
5950
|
+
channel: "thought",
|
|
5951
|
+
text
|
|
5952
|
+
});
|
|
5953
|
+
break;
|
|
5954
|
+
}
|
|
5955
|
+
case "response.refusal.delta":
|
|
5956
|
+
blocked = true;
|
|
5957
|
+
emitEvent({ type: "blocked" });
|
|
5958
|
+
break;
|
|
5959
|
+
default:
|
|
5960
|
+
break;
|
|
5961
|
+
}
|
|
5962
|
+
}
|
|
5963
|
+
return await stream.finalResponse();
|
|
5964
|
+
},
|
|
5965
|
+
providerInfo.model,
|
|
5966
|
+
{
|
|
5967
|
+
onSettled: (metrics) => {
|
|
5968
|
+
schedulerMetrics = metrics;
|
|
5335
5969
|
}
|
|
5336
5970
|
}
|
|
5337
|
-
|
|
5338
|
-
|
|
5339
|
-
|
|
5340
|
-
{
|
|
5341
|
-
|
|
5342
|
-
|
|
5971
|
+
);
|
|
5972
|
+
modelVersion = typeof finalResponse.model === "string" ? finalResponse.model : request.model;
|
|
5973
|
+
emitEvent({ type: "model", modelVersion });
|
|
5974
|
+
if (finalResponse.error) {
|
|
5975
|
+
const message = typeof finalResponse.error.message === "string" ? finalResponse.error.message : "OpenAI response failed";
|
|
5976
|
+
throw new Error(message);
|
|
5977
|
+
}
|
|
5978
|
+
usageTokens = extractOpenAiUsageTokens(finalResponse.usage);
|
|
5979
|
+
const responseText = extractOpenAiResponseParts(finalResponse).parts.filter((p) => p.type === "text" && p.thought !== true).map((p) => p.text).join("").trim();
|
|
5980
|
+
const reasoningSummary = extractOpenAiReasoningSummary(finalResponse).trim();
|
|
5981
|
+
if (!thoughtDeltaEmitted && reasoningSummary.length > 0) {
|
|
5982
|
+
stepCallLogger?.appendThoughtDelta(reasoningSummary);
|
|
5983
|
+
emitEvent({ type: "delta", channel: "thought", text: reasoningSummary });
|
|
5984
|
+
}
|
|
5985
|
+
const modelCompletedAtMs = Date.now();
|
|
5986
|
+
const stepCostUsd = estimateCallCostUsd({
|
|
5987
|
+
modelId: modelVersion,
|
|
5988
|
+
tokens: usageTokens,
|
|
5989
|
+
responseImages: 0
|
|
5990
|
+
});
|
|
5991
|
+
totalCostUsd += stepCostUsd;
|
|
5992
|
+
if (usageTokens) {
|
|
5993
|
+
emitEvent({ type: "usage", usage: usageTokens, costUsd: stepCostUsd, modelVersion });
|
|
5994
|
+
}
|
|
5995
|
+
const responseToolCalls = extractOpenAiToolCalls(finalResponse.output);
|
|
5996
|
+
const stepToolCalls = [];
|
|
5997
|
+
if (responseToolCalls.length === 0) {
|
|
5998
|
+
const steeringInput2 = steeringInternal?.drainPendingContents() ?? [];
|
|
5999
|
+
const steeringItems2 = steeringInput2.length > 0 ? toOpenAiInput(steeringInput2) : [];
|
|
6000
|
+
finalText = responseText;
|
|
6001
|
+
finalThoughts = reasoningSummary;
|
|
6002
|
+
const stepCompletedAtMs2 = Date.now();
|
|
6003
|
+
const timing2 = buildStepTiming({
|
|
6004
|
+
stepStartedAtMs,
|
|
6005
|
+
stepCompletedAtMs: stepCompletedAtMs2,
|
|
6006
|
+
modelCompletedAtMs,
|
|
6007
|
+
firstModelEventAtMs,
|
|
6008
|
+
schedulerMetrics,
|
|
6009
|
+
toolExecutionMs: 0,
|
|
6010
|
+
waitToolMs: 0
|
|
6011
|
+
});
|
|
6012
|
+
steps.push({
|
|
6013
|
+
step: steps.length + 1,
|
|
6014
|
+
modelVersion,
|
|
6015
|
+
text: responseText || void 0,
|
|
6016
|
+
thoughts: reasoningSummary || void 0,
|
|
6017
|
+
toolCalls: [],
|
|
6018
|
+
usage: usageTokens,
|
|
6019
|
+
costUsd: stepCostUsd,
|
|
6020
|
+
timing: timing2
|
|
6021
|
+
});
|
|
6022
|
+
stepCallLogger?.complete({
|
|
6023
|
+
provider: "openai",
|
|
6024
|
+
model: request.model,
|
|
6025
|
+
modelVersion,
|
|
6026
|
+
step: turn,
|
|
6027
|
+
usage: usageTokens,
|
|
6028
|
+
costUsd: stepCostUsd,
|
|
6029
|
+
blocked,
|
|
6030
|
+
responseChars: responseText.length,
|
|
6031
|
+
thoughtChars: reasoningSummary.length,
|
|
6032
|
+
toolCalls: 0,
|
|
6033
|
+
finalStep: steeringItems2.length === 0
|
|
6034
|
+
});
|
|
6035
|
+
if (steeringItems2.length === 0) {
|
|
6036
|
+
return { text: finalText, thoughts: finalThoughts, steps, totalCostUsd };
|
|
5343
6037
|
}
|
|
6038
|
+
previousResponseId = finalResponse.id;
|
|
6039
|
+
input = steeringItems2;
|
|
6040
|
+
continue;
|
|
5344
6041
|
}
|
|
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
|
|
6042
|
+
const callInputs = responseToolCalls.map((call, index) => {
|
|
6043
|
+
const toolIndex = index + 1;
|
|
6044
|
+
const toolId = buildToolLogId(turn, toolIndex);
|
|
6045
|
+
const toolName = call.name;
|
|
6046
|
+
if (call.kind === "custom") {
|
|
6047
|
+
return {
|
|
6048
|
+
call,
|
|
6049
|
+
toolName,
|
|
6050
|
+
value: call.input,
|
|
6051
|
+
parseError: void 0,
|
|
6052
|
+
toolId,
|
|
6053
|
+
turn,
|
|
6054
|
+
toolIndex
|
|
6055
|
+
};
|
|
6056
|
+
}
|
|
6057
|
+
const { value, error: parseError } = parseOpenAiToolArguments(call.arguments);
|
|
6058
|
+
return { call, toolName, value, parseError, toolId, turn, toolIndex };
|
|
6059
|
+
});
|
|
6060
|
+
for (const entry of callInputs) {
|
|
6061
|
+
emitEvent({
|
|
6062
|
+
type: "tool_call",
|
|
6063
|
+
phase: "started",
|
|
6064
|
+
turn: entry.turn,
|
|
6065
|
+
toolIndex: entry.toolIndex,
|
|
6066
|
+
toolName: entry.toolName,
|
|
6067
|
+
toolId: entry.toolId,
|
|
6068
|
+
callKind: entry.call.kind,
|
|
6069
|
+
callId: entry.call.call_id,
|
|
6070
|
+
input: entry.value
|
|
6071
|
+
});
|
|
6072
|
+
}
|
|
6073
|
+
const callResults = await Promise.all(
|
|
6074
|
+
callInputs.map(async (entry) => {
|
|
6075
|
+
return await toolCallContextStorage.run(
|
|
6076
|
+
{
|
|
6077
|
+
toolName: entry.toolName,
|
|
6078
|
+
toolId: entry.toolId,
|
|
6079
|
+
turn: entry.turn,
|
|
6080
|
+
toolIndex: entry.toolIndex
|
|
6081
|
+
},
|
|
6082
|
+
async () => {
|
|
6083
|
+
const { result, outputPayload } = await executeToolCall({
|
|
6084
|
+
callKind: entry.call.kind,
|
|
6085
|
+
toolName: entry.toolName,
|
|
6086
|
+
tool: request.tools[entry.toolName],
|
|
6087
|
+
rawInput: entry.value,
|
|
6088
|
+
parseError: entry.parseError
|
|
6089
|
+
});
|
|
6090
|
+
return { entry, result, outputPayload };
|
|
6091
|
+
}
|
|
6092
|
+
);
|
|
6093
|
+
})
|
|
6094
|
+
);
|
|
6095
|
+
const toolOutputs = [];
|
|
6096
|
+
let toolExecutionMs = 0;
|
|
6097
|
+
let waitToolMs = 0;
|
|
6098
|
+
for (const { entry, result, outputPayload } of callResults) {
|
|
6099
|
+
stepToolCalls.push({ ...result, callId: entry.call.call_id });
|
|
6100
|
+
const callDurationMs = toToolResultDuration(result);
|
|
6101
|
+
toolExecutionMs += callDurationMs;
|
|
6102
|
+
if (entry.toolName.toLowerCase() === SUBAGENT_WAIT_TOOL_NAME) {
|
|
6103
|
+
waitToolMs += callDurationMs;
|
|
6104
|
+
}
|
|
6105
|
+
emitEvent({
|
|
6106
|
+
type: "tool_call",
|
|
6107
|
+
phase: "completed",
|
|
6108
|
+
turn: entry.turn,
|
|
6109
|
+
toolIndex: entry.toolIndex,
|
|
6110
|
+
toolName: entry.toolName,
|
|
6111
|
+
toolId: entry.toolId,
|
|
6112
|
+
callKind: entry.call.kind,
|
|
6113
|
+
callId: entry.call.call_id,
|
|
6114
|
+
input: entry.value,
|
|
6115
|
+
output: result.output,
|
|
6116
|
+
error: result.error,
|
|
6117
|
+
durationMs: result.durationMs
|
|
6118
|
+
});
|
|
6119
|
+
if (entry.call.kind === "custom") {
|
|
6120
|
+
toolOutputs.push({
|
|
6121
|
+
type: "custom_tool_call_output",
|
|
6122
|
+
call_id: entry.call.call_id,
|
|
6123
|
+
output: toOpenAiToolOutput(outputPayload)
|
|
6124
|
+
});
|
|
6125
|
+
} else {
|
|
6126
|
+
toolOutputs.push({
|
|
6127
|
+
type: "function_call_output",
|
|
6128
|
+
call_id: entry.call.call_id,
|
|
6129
|
+
output: toOpenAiToolOutput(outputPayload)
|
|
6130
|
+
});
|
|
6131
|
+
}
|
|
6132
|
+
}
|
|
6133
|
+
const stepCompletedAtMs = Date.now();
|
|
6134
|
+
const timing = buildStepTiming({
|
|
5377
6135
|
stepStartedAtMs,
|
|
5378
|
-
stepCompletedAtMs
|
|
6136
|
+
stepCompletedAtMs,
|
|
5379
6137
|
modelCompletedAtMs,
|
|
5380
6138
|
firstModelEventAtMs,
|
|
5381
6139
|
schedulerMetrics,
|
|
5382
|
-
toolExecutionMs
|
|
5383
|
-
waitToolMs
|
|
6140
|
+
toolExecutionMs,
|
|
6141
|
+
waitToolMs
|
|
5384
6142
|
});
|
|
5385
6143
|
steps.push({
|
|
5386
6144
|
step: steps.length + 1,
|
|
5387
6145
|
modelVersion,
|
|
5388
6146
|
text: responseText || void 0,
|
|
5389
6147
|
thoughts: reasoningSummary || void 0,
|
|
5390
|
-
toolCalls:
|
|
6148
|
+
toolCalls: stepToolCalls,
|
|
5391
6149
|
usage: usageTokens,
|
|
5392
6150
|
costUsd: stepCostUsd,
|
|
5393
|
-
timing
|
|
6151
|
+
timing
|
|
5394
6152
|
});
|
|
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
|
|
6153
|
+
const steeringInput = steeringInternal?.drainPendingContents() ?? [];
|
|
6154
|
+
const steeringItems = steeringInput.length > 0 ? toOpenAiInput(steeringInput) : [];
|
|
6155
|
+
stepCallLogger?.complete({
|
|
6156
|
+
provider: "openai",
|
|
6157
|
+
model: request.model,
|
|
6158
|
+
modelVersion,
|
|
6159
|
+
step: turn,
|
|
6160
|
+
usage: usageTokens,
|
|
6161
|
+
costUsd: stepCostUsd,
|
|
6162
|
+
blocked,
|
|
6163
|
+
responseChars: responseText.length,
|
|
6164
|
+
thoughtChars: reasoningSummary.length,
|
|
6165
|
+
toolCalls: stepToolCalls.length,
|
|
6166
|
+
finalStep: false
|
|
5431
6167
|
});
|
|
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
|
|
6168
|
+
previousResponseId = finalResponse.id;
|
|
6169
|
+
input = steeringItems.length > 0 ? toolOutputs.concat(steeringItems) : toolOutputs;
|
|
6170
|
+
} catch (error) {
|
|
6171
|
+
stepCallLogger?.fail(error, {
|
|
6172
|
+
provider: "openai",
|
|
6173
|
+
model: request.model,
|
|
6174
|
+
modelVersion,
|
|
6175
|
+
step: turn,
|
|
6176
|
+
usage: usageTokens,
|
|
6177
|
+
blocked
|
|
5478
6178
|
});
|
|
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
|
-
}
|
|
6179
|
+
throw error;
|
|
5492
6180
|
}
|
|
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
6181
|
}
|
|
5518
6182
|
throw new Error(`Tool loop exceeded max steps (${maxSteps}) without final response.`);
|
|
5519
6183
|
}
|
|
@@ -5531,242 +6195,655 @@ async function runToolLoop(request) {
|
|
|
5531
6195
|
const stepStartedAtMs = Date.now();
|
|
5532
6196
|
let firstModelEventAtMs;
|
|
5533
6197
|
let thoughtDeltaEmitted = false;
|
|
6198
|
+
let sawResponseDelta = false;
|
|
6199
|
+
let modelVersion = request.model;
|
|
6200
|
+
let usageTokens;
|
|
6201
|
+
let responseText = "";
|
|
6202
|
+
let reasoningSummaryText = "";
|
|
5534
6203
|
const markFirstModelEvent = () => {
|
|
5535
6204
|
if (firstModelEventAtMs === void 0) {
|
|
5536
6205
|
firstModelEventAtMs = Date.now();
|
|
5537
6206
|
}
|
|
5538
6207
|
};
|
|
5539
|
-
const
|
|
5540
|
-
|
|
5541
|
-
|
|
5542
|
-
|
|
5543
|
-
|
|
5544
|
-
|
|
5545
|
-
|
|
5546
|
-
|
|
5547
|
-
|
|
5548
|
-
|
|
5549
|
-
|
|
5550
|
-
|
|
5551
|
-
|
|
5552
|
-
|
|
5553
|
-
effort: toOpenAiReasoningEffort(reasoningEffort),
|
|
5554
|
-
summary: "detailed"
|
|
5555
|
-
},
|
|
5556
|
-
text: { verbosity: resolveOpenAiVerbosity(request.model) }
|
|
6208
|
+
const stepRequestPayload = {
|
|
6209
|
+
model: providerInfo.model,
|
|
6210
|
+
store: false,
|
|
6211
|
+
stream: true,
|
|
6212
|
+
instructions: toolLoopInput.instructions ?? "You are a helpful assistant.",
|
|
6213
|
+
input,
|
|
6214
|
+
prompt_cache_key: promptCacheKey,
|
|
6215
|
+
include: ["reasoning.encrypted_content"],
|
|
6216
|
+
tools: openAiTools,
|
|
6217
|
+
tool_choice: "auto",
|
|
6218
|
+
parallel_tool_calls: true,
|
|
6219
|
+
reasoning: {
|
|
6220
|
+
effort: toOpenAiReasoningEffort(reasoningEffort),
|
|
6221
|
+
summary: "detailed"
|
|
5557
6222
|
},
|
|
5558
|
-
|
|
5559
|
-
|
|
5560
|
-
|
|
5561
|
-
|
|
5562
|
-
|
|
5563
|
-
|
|
6223
|
+
text: { verbosity: resolveOpenAiVerbosity(request.model) }
|
|
6224
|
+
};
|
|
6225
|
+
const stepCallLogger = startLlmCallLoggerFromPayload({
|
|
6226
|
+
provider: "chatgpt",
|
|
6227
|
+
modelId: request.model,
|
|
6228
|
+
requestPayload: stepRequestPayload,
|
|
6229
|
+
step: turn
|
|
6230
|
+
});
|
|
6231
|
+
try {
|
|
6232
|
+
const response = await collectChatGptCodexResponseWithRetry({
|
|
6233
|
+
sessionId: conversationId,
|
|
6234
|
+
request: stepRequestPayload,
|
|
6235
|
+
signal: request.signal,
|
|
6236
|
+
onDelta: (delta) => {
|
|
6237
|
+
if (delta.thoughtDelta) {
|
|
6238
|
+
markFirstModelEvent();
|
|
6239
|
+
thoughtDeltaEmitted = true;
|
|
6240
|
+
stepCallLogger?.appendThoughtDelta(delta.thoughtDelta);
|
|
6241
|
+
request.onEvent?.({ type: "delta", channel: "thought", text: delta.thoughtDelta });
|
|
6242
|
+
}
|
|
6243
|
+
if (delta.textDelta) {
|
|
6244
|
+
markFirstModelEvent();
|
|
6245
|
+
sawResponseDelta = true;
|
|
6246
|
+
stepCallLogger?.appendResponseDelta(delta.textDelta);
|
|
6247
|
+
request.onEvent?.({ type: "delta", channel: "response", text: delta.textDelta });
|
|
6248
|
+
}
|
|
5564
6249
|
}
|
|
5565
|
-
|
|
5566
|
-
|
|
5567
|
-
|
|
6250
|
+
});
|
|
6251
|
+
const modelCompletedAtMs = Date.now();
|
|
6252
|
+
modelVersion = response.model ? `chatgpt-${response.model}` : request.model;
|
|
6253
|
+
usageTokens = extractChatGptUsageTokens(response.usage);
|
|
6254
|
+
const stepCostUsd = estimateCallCostUsd({
|
|
6255
|
+
modelId: modelVersion,
|
|
6256
|
+
tokens: usageTokens,
|
|
6257
|
+
responseImages: 0
|
|
6258
|
+
});
|
|
6259
|
+
totalCostUsd += stepCostUsd;
|
|
6260
|
+
responseText = (response.text ?? "").trim();
|
|
6261
|
+
reasoningSummaryText = (response.reasoningSummaryText ?? "").trim();
|
|
6262
|
+
if (!thoughtDeltaEmitted && reasoningSummaryText.length > 0) {
|
|
6263
|
+
stepCallLogger?.appendThoughtDelta(reasoningSummaryText);
|
|
6264
|
+
request.onEvent?.({ type: "delta", channel: "thought", text: reasoningSummaryText });
|
|
6265
|
+
}
|
|
6266
|
+
if (!sawResponseDelta && responseText.length > 0) {
|
|
6267
|
+
stepCallLogger?.appendResponseDelta(responseText);
|
|
6268
|
+
}
|
|
6269
|
+
const responseToolCalls = response.toolCalls ?? [];
|
|
6270
|
+
if (responseToolCalls.length === 0) {
|
|
6271
|
+
const steeringInput2 = steeringInternal?.drainPendingContents() ?? [];
|
|
6272
|
+
const steeringItems2 = steeringInput2.length > 0 ? toChatGptInput(steeringInput2).input : [];
|
|
6273
|
+
finalText = responseText;
|
|
6274
|
+
finalThoughts = reasoningSummaryText;
|
|
6275
|
+
const stepCompletedAtMs2 = Date.now();
|
|
6276
|
+
const timing2 = buildStepTiming({
|
|
6277
|
+
stepStartedAtMs,
|
|
6278
|
+
stepCompletedAtMs: stepCompletedAtMs2,
|
|
6279
|
+
modelCompletedAtMs,
|
|
6280
|
+
firstModelEventAtMs,
|
|
6281
|
+
toolExecutionMs: 0,
|
|
6282
|
+
waitToolMs: 0
|
|
6283
|
+
});
|
|
6284
|
+
steps.push({
|
|
6285
|
+
step: steps.length + 1,
|
|
6286
|
+
modelVersion,
|
|
6287
|
+
text: responseText || void 0,
|
|
6288
|
+
thoughts: reasoningSummaryText || void 0,
|
|
6289
|
+
toolCalls: [],
|
|
6290
|
+
usage: usageTokens,
|
|
6291
|
+
costUsd: stepCostUsd,
|
|
6292
|
+
timing: timing2
|
|
6293
|
+
});
|
|
6294
|
+
stepCallLogger?.complete({
|
|
6295
|
+
provider: "chatgpt",
|
|
6296
|
+
model: request.model,
|
|
6297
|
+
modelVersion,
|
|
6298
|
+
step: turn,
|
|
6299
|
+
usage: usageTokens,
|
|
6300
|
+
costUsd: stepCostUsd,
|
|
6301
|
+
responseChars: responseText.length,
|
|
6302
|
+
thoughtChars: reasoningSummaryText.length,
|
|
6303
|
+
toolCalls: 0,
|
|
6304
|
+
finalStep: steeringItems2.length === 0
|
|
6305
|
+
});
|
|
6306
|
+
if (steeringItems2.length === 0) {
|
|
6307
|
+
return { text: finalText, thoughts: finalThoughts, steps, totalCostUsd };
|
|
5568
6308
|
}
|
|
6309
|
+
const assistantItem = toChatGptAssistantMessage(responseText);
|
|
6310
|
+
input = assistantItem ? input.concat(assistantItem, steeringItems2) : input.concat(steeringItems2);
|
|
6311
|
+
continue;
|
|
5569
6312
|
}
|
|
5570
|
-
|
|
5571
|
-
|
|
5572
|
-
|
|
5573
|
-
|
|
5574
|
-
|
|
5575
|
-
|
|
5576
|
-
|
|
5577
|
-
|
|
5578
|
-
|
|
5579
|
-
|
|
5580
|
-
|
|
5581
|
-
|
|
5582
|
-
|
|
5583
|
-
|
|
5584
|
-
|
|
5585
|
-
|
|
5586
|
-
|
|
5587
|
-
|
|
5588
|
-
|
|
5589
|
-
|
|
5590
|
-
|
|
5591
|
-
|
|
5592
|
-
|
|
6313
|
+
const toolCalls = [];
|
|
6314
|
+
const toolOutputs = [];
|
|
6315
|
+
const callInputs = responseToolCalls.map((call, index) => {
|
|
6316
|
+
const toolIndex = index + 1;
|
|
6317
|
+
const toolId = buildToolLogId(turn, toolIndex);
|
|
6318
|
+
const toolName = call.name;
|
|
6319
|
+
const { value, error: parseError } = call.kind === "custom" ? { value: call.input, error: void 0 } : parseOpenAiToolArguments(call.arguments);
|
|
6320
|
+
const ids = normalizeChatGptToolIds({
|
|
6321
|
+
callKind: call.kind,
|
|
6322
|
+
callId: call.callId,
|
|
6323
|
+
itemId: call.id
|
|
6324
|
+
});
|
|
6325
|
+
return { call, toolName, value, parseError, ids, toolId, turn, toolIndex };
|
|
6326
|
+
});
|
|
6327
|
+
for (const entry of callInputs) {
|
|
6328
|
+
request.onEvent?.({
|
|
6329
|
+
type: "tool_call",
|
|
6330
|
+
phase: "started",
|
|
6331
|
+
turn: entry.turn,
|
|
6332
|
+
toolIndex: entry.toolIndex,
|
|
6333
|
+
toolName: entry.toolName,
|
|
6334
|
+
toolId: entry.toolId,
|
|
6335
|
+
callKind: entry.call.kind,
|
|
6336
|
+
callId: entry.ids.callId,
|
|
6337
|
+
input: entry.value
|
|
6338
|
+
});
|
|
6339
|
+
}
|
|
6340
|
+
const callResults = await Promise.all(
|
|
6341
|
+
callInputs.map(async (entry) => {
|
|
6342
|
+
return await toolCallContextStorage.run(
|
|
6343
|
+
{
|
|
6344
|
+
toolName: entry.toolName,
|
|
6345
|
+
toolId: entry.toolId,
|
|
6346
|
+
turn: entry.turn,
|
|
6347
|
+
toolIndex: entry.toolIndex
|
|
6348
|
+
},
|
|
6349
|
+
async () => {
|
|
6350
|
+
const { result, outputPayload } = await executeToolCall({
|
|
6351
|
+
callKind: entry.call.kind,
|
|
6352
|
+
toolName: entry.toolName,
|
|
6353
|
+
tool: request.tools[entry.toolName],
|
|
6354
|
+
rawInput: entry.value,
|
|
6355
|
+
parseError: entry.parseError
|
|
6356
|
+
});
|
|
6357
|
+
return { entry, result, outputPayload };
|
|
6358
|
+
}
|
|
6359
|
+
);
|
|
6360
|
+
})
|
|
6361
|
+
);
|
|
6362
|
+
let toolExecutionMs = 0;
|
|
6363
|
+
let waitToolMs = 0;
|
|
6364
|
+
for (const { entry, result, outputPayload } of callResults) {
|
|
6365
|
+
toolCalls.push({ ...result, callId: entry.ids.callId });
|
|
6366
|
+
const callDurationMs = toToolResultDuration(result);
|
|
6367
|
+
toolExecutionMs += callDurationMs;
|
|
6368
|
+
if (entry.toolName.toLowerCase() === SUBAGENT_WAIT_TOOL_NAME) {
|
|
6369
|
+
waitToolMs += callDurationMs;
|
|
6370
|
+
}
|
|
6371
|
+
request.onEvent?.({
|
|
6372
|
+
type: "tool_call",
|
|
6373
|
+
phase: "completed",
|
|
6374
|
+
turn: entry.turn,
|
|
6375
|
+
toolIndex: entry.toolIndex,
|
|
6376
|
+
toolName: entry.toolName,
|
|
6377
|
+
toolId: entry.toolId,
|
|
6378
|
+
callKind: entry.call.kind,
|
|
6379
|
+
callId: entry.ids.callId,
|
|
6380
|
+
input: entry.value,
|
|
6381
|
+
output: result.output,
|
|
6382
|
+
error: result.error,
|
|
6383
|
+
durationMs: result.durationMs
|
|
6384
|
+
});
|
|
6385
|
+
if (entry.call.kind === "custom") {
|
|
6386
|
+
toolOutputs.push({
|
|
6387
|
+
type: "custom_tool_call",
|
|
6388
|
+
id: entry.ids.itemId,
|
|
6389
|
+
call_id: entry.ids.callId,
|
|
6390
|
+
name: entry.toolName,
|
|
6391
|
+
input: entry.call.input,
|
|
6392
|
+
status: "completed"
|
|
6393
|
+
});
|
|
6394
|
+
toolOutputs.push({
|
|
6395
|
+
type: "custom_tool_call_output",
|
|
6396
|
+
call_id: entry.ids.callId,
|
|
6397
|
+
output: toOpenAiToolOutput(outputPayload)
|
|
6398
|
+
});
|
|
6399
|
+
} else {
|
|
6400
|
+
toolOutputs.push({
|
|
6401
|
+
type: "function_call",
|
|
6402
|
+
id: entry.ids.itemId,
|
|
6403
|
+
call_id: entry.ids.callId,
|
|
6404
|
+
name: entry.toolName,
|
|
6405
|
+
arguments: entry.call.arguments,
|
|
6406
|
+
status: "completed"
|
|
6407
|
+
});
|
|
6408
|
+
toolOutputs.push({
|
|
6409
|
+
type: "function_call_output",
|
|
6410
|
+
call_id: entry.ids.callId,
|
|
6411
|
+
output: toOpenAiToolOutput(outputPayload)
|
|
6412
|
+
});
|
|
6413
|
+
}
|
|
6414
|
+
}
|
|
6415
|
+
const stepCompletedAtMs = Date.now();
|
|
6416
|
+
const timing = buildStepTiming({
|
|
5593
6417
|
stepStartedAtMs,
|
|
5594
|
-
stepCompletedAtMs
|
|
6418
|
+
stepCompletedAtMs,
|
|
5595
6419
|
modelCompletedAtMs,
|
|
5596
6420
|
firstModelEventAtMs,
|
|
5597
|
-
toolExecutionMs
|
|
5598
|
-
waitToolMs
|
|
6421
|
+
toolExecutionMs,
|
|
6422
|
+
waitToolMs
|
|
5599
6423
|
});
|
|
5600
6424
|
steps.push({
|
|
5601
6425
|
step: steps.length + 1,
|
|
5602
6426
|
modelVersion,
|
|
5603
6427
|
text: responseText || void 0,
|
|
5604
6428
|
thoughts: reasoningSummaryText || void 0,
|
|
5605
|
-
toolCalls
|
|
6429
|
+
toolCalls,
|
|
5606
6430
|
usage: usageTokens,
|
|
5607
6431
|
costUsd: stepCostUsd,
|
|
5608
|
-
timing
|
|
6432
|
+
timing
|
|
5609
6433
|
});
|
|
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
|
|
6434
|
+
const steeringInput = steeringInternal?.drainPendingContents() ?? [];
|
|
6435
|
+
const steeringItems = steeringInput.length > 0 ? toChatGptInput(steeringInput).input : [];
|
|
6436
|
+
stepCallLogger?.complete({
|
|
6437
|
+
provider: "chatgpt",
|
|
6438
|
+
model: request.model,
|
|
6439
|
+
modelVersion,
|
|
6440
|
+
step: turn,
|
|
6441
|
+
usage: usageTokens,
|
|
6442
|
+
costUsd: stepCostUsd,
|
|
6443
|
+
responseChars: responseText.length,
|
|
6444
|
+
thoughtChars: reasoningSummaryText.length,
|
|
6445
|
+
toolCalls: toolCalls.length,
|
|
6446
|
+
finalStep: false
|
|
5628
6447
|
});
|
|
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
|
|
6448
|
+
input = steeringItems.length > 0 ? input.concat(toolOutputs, steeringItems) : input.concat(toolOutputs);
|
|
6449
|
+
} catch (error) {
|
|
6450
|
+
stepCallLogger?.fail(error, {
|
|
6451
|
+
provider: "chatgpt",
|
|
6452
|
+
model: request.model,
|
|
6453
|
+
modelVersion,
|
|
6454
|
+
step: turn,
|
|
6455
|
+
usage: usageTokens
|
|
5642
6456
|
});
|
|
6457
|
+
throw error;
|
|
5643
6458
|
}
|
|
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
|
-
})
|
|
6459
|
+
}
|
|
6460
|
+
throw new Error(`Tool loop exceeded max steps (${maxSteps}) without final response.`);
|
|
6461
|
+
}
|
|
6462
|
+
if (providerInfo.provider === "fireworks") {
|
|
6463
|
+
if (request.modelTools && request.modelTools.length > 0) {
|
|
6464
|
+
throw new Error(
|
|
6465
|
+
"Fireworks provider does not support provider-native modelTools in runToolLoop."
|
|
5665
6466
|
);
|
|
5666
|
-
|
|
5667
|
-
|
|
5668
|
-
|
|
5669
|
-
|
|
5670
|
-
|
|
5671
|
-
|
|
5672
|
-
|
|
5673
|
-
|
|
6467
|
+
}
|
|
6468
|
+
const fireworksTools = buildFireworksToolsFromToolSet(request.tools);
|
|
6469
|
+
const messages = toFireworksMessages(contents);
|
|
6470
|
+
for (let stepIndex = 0; stepIndex < maxSteps; stepIndex += 1) {
|
|
6471
|
+
const turn = stepIndex + 1;
|
|
6472
|
+
const stepStartedAtMs = Date.now();
|
|
6473
|
+
let schedulerMetrics;
|
|
6474
|
+
let modelVersion = request.model;
|
|
6475
|
+
let usageTokens;
|
|
6476
|
+
let responseText = "";
|
|
6477
|
+
let blocked = false;
|
|
6478
|
+
const stepRequestPayload = {
|
|
6479
|
+
model: providerInfo.model,
|
|
6480
|
+
messages,
|
|
6481
|
+
tools: fireworksTools,
|
|
6482
|
+
tool_choice: "auto",
|
|
6483
|
+
parallel_tool_calls: true
|
|
6484
|
+
};
|
|
6485
|
+
const stepCallLogger = startLlmCallLoggerFromPayload({
|
|
6486
|
+
provider: "fireworks",
|
|
6487
|
+
modelId: request.model,
|
|
6488
|
+
requestPayload: stepRequestPayload,
|
|
6489
|
+
step: turn
|
|
6490
|
+
});
|
|
6491
|
+
try {
|
|
6492
|
+
const response = await runFireworksCall(
|
|
6493
|
+
async (client) => {
|
|
6494
|
+
return await client.chat.completions.create(
|
|
6495
|
+
{
|
|
6496
|
+
model: providerInfo.model,
|
|
6497
|
+
messages,
|
|
6498
|
+
tools: fireworksTools,
|
|
6499
|
+
tool_choice: "auto",
|
|
6500
|
+
parallel_tool_calls: true
|
|
6501
|
+
},
|
|
6502
|
+
{ signal: request.signal }
|
|
6503
|
+
);
|
|
6504
|
+
},
|
|
6505
|
+
providerInfo.model,
|
|
6506
|
+
{
|
|
6507
|
+
onSettled: (metrics) => {
|
|
6508
|
+
schedulerMetrics = metrics;
|
|
6509
|
+
}
|
|
6510
|
+
}
|
|
6511
|
+
);
|
|
6512
|
+
const modelCompletedAtMs = Date.now();
|
|
6513
|
+
modelVersion = typeof response.model === "string" ? response.model : request.model;
|
|
6514
|
+
request.onEvent?.({ type: "model", modelVersion });
|
|
6515
|
+
const choice = Array.isArray(response.choices) ? response.choices[0] : void 0;
|
|
6516
|
+
if (choice?.finish_reason === "content_filter") {
|
|
6517
|
+
blocked = true;
|
|
6518
|
+
request.onEvent?.({ type: "blocked" });
|
|
5674
6519
|
}
|
|
5675
|
-
|
|
5676
|
-
|
|
5677
|
-
|
|
5678
|
-
|
|
5679
|
-
|
|
5680
|
-
|
|
5681
|
-
|
|
5682
|
-
|
|
5683
|
-
|
|
5684
|
-
|
|
5685
|
-
|
|
5686
|
-
error: result.error,
|
|
5687
|
-
durationMs: result.durationMs
|
|
6520
|
+
const message = choice?.message;
|
|
6521
|
+
responseText = extractFireworksMessageText(message).trim();
|
|
6522
|
+
if (responseText.length > 0) {
|
|
6523
|
+
stepCallLogger?.appendResponseDelta(responseText);
|
|
6524
|
+
request.onEvent?.({ type: "delta", channel: "response", text: responseText });
|
|
6525
|
+
}
|
|
6526
|
+
usageTokens = extractFireworksUsageTokens(response.usage);
|
|
6527
|
+
const stepCostUsd = estimateCallCostUsd({
|
|
6528
|
+
modelId: modelVersion,
|
|
6529
|
+
tokens: usageTokens,
|
|
6530
|
+
responseImages: 0
|
|
5688
6531
|
});
|
|
5689
|
-
|
|
5690
|
-
|
|
5691
|
-
|
|
5692
|
-
|
|
5693
|
-
|
|
5694
|
-
|
|
5695
|
-
|
|
5696
|
-
status: "completed"
|
|
6532
|
+
totalCostUsd += stepCostUsd;
|
|
6533
|
+
if (usageTokens) {
|
|
6534
|
+
request.onEvent?.({
|
|
6535
|
+
type: "usage",
|
|
6536
|
+
usage: usageTokens,
|
|
6537
|
+
costUsd: stepCostUsd,
|
|
6538
|
+
modelVersion
|
|
5697
6539
|
});
|
|
5698
|
-
|
|
5699
|
-
|
|
5700
|
-
|
|
5701
|
-
|
|
6540
|
+
}
|
|
6541
|
+
const responseToolCalls = extractFireworksToolCalls(message);
|
|
6542
|
+
if (responseToolCalls.length === 0) {
|
|
6543
|
+
const steeringInput2 = steeringInternal?.drainPendingContents() ?? [];
|
|
6544
|
+
const steeringMessages = steeringInput2.length > 0 ? toFireworksMessages(steeringInput2) : [];
|
|
6545
|
+
finalText = responseText;
|
|
6546
|
+
finalThoughts = "";
|
|
6547
|
+
const stepCompletedAtMs2 = Date.now();
|
|
6548
|
+
const timing2 = buildStepTiming({
|
|
6549
|
+
stepStartedAtMs,
|
|
6550
|
+
stepCompletedAtMs: stepCompletedAtMs2,
|
|
6551
|
+
modelCompletedAtMs,
|
|
6552
|
+
schedulerMetrics,
|
|
6553
|
+
toolExecutionMs: 0,
|
|
6554
|
+
waitToolMs: 0
|
|
5702
6555
|
});
|
|
5703
|
-
|
|
5704
|
-
|
|
5705
|
-
|
|
5706
|
-
|
|
5707
|
-
|
|
5708
|
-
|
|
5709
|
-
|
|
5710
|
-
|
|
6556
|
+
steps.push({
|
|
6557
|
+
step: steps.length + 1,
|
|
6558
|
+
modelVersion,
|
|
6559
|
+
text: responseText || void 0,
|
|
6560
|
+
thoughts: void 0,
|
|
6561
|
+
toolCalls: [],
|
|
6562
|
+
usage: usageTokens,
|
|
6563
|
+
costUsd: stepCostUsd,
|
|
6564
|
+
timing: timing2
|
|
5711
6565
|
});
|
|
5712
|
-
|
|
5713
|
-
|
|
5714
|
-
|
|
5715
|
-
|
|
6566
|
+
stepCallLogger?.complete({
|
|
6567
|
+
provider: "fireworks",
|
|
6568
|
+
model: request.model,
|
|
6569
|
+
modelVersion,
|
|
6570
|
+
step: turn,
|
|
6571
|
+
usage: usageTokens,
|
|
6572
|
+
costUsd: stepCostUsd,
|
|
6573
|
+
blocked,
|
|
6574
|
+
responseChars: responseText.length,
|
|
6575
|
+
thoughtChars: 0,
|
|
6576
|
+
toolCalls: 0,
|
|
6577
|
+
finalStep: steeringMessages.length === 0
|
|
5716
6578
|
});
|
|
6579
|
+
if (steeringMessages.length === 0) {
|
|
6580
|
+
return { text: finalText, thoughts: finalThoughts, steps, totalCostUsd };
|
|
6581
|
+
}
|
|
6582
|
+
if (responseText.length > 0) {
|
|
6583
|
+
messages.push({ role: "assistant", content: responseText });
|
|
6584
|
+
}
|
|
6585
|
+
messages.push(...steeringMessages);
|
|
6586
|
+
continue;
|
|
5717
6587
|
}
|
|
5718
|
-
|
|
5719
|
-
|
|
5720
|
-
|
|
5721
|
-
|
|
5722
|
-
|
|
5723
|
-
|
|
5724
|
-
|
|
5725
|
-
|
|
5726
|
-
|
|
5727
|
-
|
|
5728
|
-
|
|
5729
|
-
|
|
5730
|
-
|
|
5731
|
-
|
|
5732
|
-
|
|
5733
|
-
|
|
5734
|
-
|
|
5735
|
-
|
|
5736
|
-
|
|
5737
|
-
|
|
5738
|
-
|
|
5739
|
-
|
|
5740
|
-
|
|
6588
|
+
const stepToolCalls = [];
|
|
6589
|
+
const callInputs = responseToolCalls.map((call, index) => {
|
|
6590
|
+
const toolIndex = index + 1;
|
|
6591
|
+
const toolId = buildToolLogId(turn, toolIndex);
|
|
6592
|
+
const { value, error: parseError } = parseOpenAiToolArguments(call.arguments);
|
|
6593
|
+
return { call, toolName: call.name, value, parseError, toolId, turn, toolIndex };
|
|
6594
|
+
});
|
|
6595
|
+
for (const entry of callInputs) {
|
|
6596
|
+
request.onEvent?.({
|
|
6597
|
+
type: "tool_call",
|
|
6598
|
+
phase: "started",
|
|
6599
|
+
turn: entry.turn,
|
|
6600
|
+
toolIndex: entry.toolIndex,
|
|
6601
|
+
toolName: entry.toolName,
|
|
6602
|
+
toolId: entry.toolId,
|
|
6603
|
+
callKind: "function",
|
|
6604
|
+
callId: entry.call.id,
|
|
6605
|
+
input: entry.value
|
|
6606
|
+
});
|
|
6607
|
+
}
|
|
6608
|
+
const callResults = await Promise.all(
|
|
6609
|
+
callInputs.map(async (entry) => {
|
|
6610
|
+
return await toolCallContextStorage.run(
|
|
6611
|
+
{
|
|
6612
|
+
toolName: entry.toolName,
|
|
6613
|
+
toolId: entry.toolId,
|
|
6614
|
+
turn: entry.turn,
|
|
6615
|
+
toolIndex: entry.toolIndex
|
|
6616
|
+
},
|
|
6617
|
+
async () => {
|
|
6618
|
+
const { result, outputPayload } = await executeToolCall({
|
|
6619
|
+
callKind: "function",
|
|
6620
|
+
toolName: entry.toolName,
|
|
6621
|
+
tool: request.tools[entry.toolName],
|
|
6622
|
+
rawInput: entry.value,
|
|
6623
|
+
parseError: entry.parseError
|
|
6624
|
+
});
|
|
6625
|
+
return { entry, result, outputPayload };
|
|
6626
|
+
}
|
|
6627
|
+
);
|
|
6628
|
+
})
|
|
6629
|
+
);
|
|
6630
|
+
const assistantToolCalls = [];
|
|
6631
|
+
const toolMessages = [];
|
|
6632
|
+
let toolExecutionMs = 0;
|
|
6633
|
+
let waitToolMs = 0;
|
|
6634
|
+
for (const { entry, result, outputPayload } of callResults) {
|
|
6635
|
+
stepToolCalls.push({ ...result, callId: entry.call.id });
|
|
6636
|
+
const callDurationMs = toToolResultDuration(result);
|
|
6637
|
+
toolExecutionMs += callDurationMs;
|
|
6638
|
+
if (entry.toolName.toLowerCase() === SUBAGENT_WAIT_TOOL_NAME) {
|
|
6639
|
+
waitToolMs += callDurationMs;
|
|
6640
|
+
}
|
|
6641
|
+
request.onEvent?.({
|
|
6642
|
+
type: "tool_call",
|
|
6643
|
+
phase: "completed",
|
|
6644
|
+
turn: entry.turn,
|
|
6645
|
+
toolIndex: entry.toolIndex,
|
|
6646
|
+
toolName: entry.toolName,
|
|
6647
|
+
toolId: entry.toolId,
|
|
6648
|
+
callKind: "function",
|
|
6649
|
+
callId: entry.call.id,
|
|
6650
|
+
input: entry.value,
|
|
6651
|
+
output: result.output,
|
|
6652
|
+
error: result.error,
|
|
6653
|
+
durationMs: result.durationMs
|
|
6654
|
+
});
|
|
6655
|
+
assistantToolCalls.push({
|
|
6656
|
+
id: entry.call.id,
|
|
6657
|
+
type: "function",
|
|
6658
|
+
function: {
|
|
6659
|
+
name: entry.toolName,
|
|
6660
|
+
arguments: entry.call.arguments
|
|
6661
|
+
}
|
|
6662
|
+
});
|
|
6663
|
+
toolMessages.push({
|
|
6664
|
+
role: "tool",
|
|
6665
|
+
tool_call_id: entry.call.id,
|
|
6666
|
+
content: mergeToolOutput(outputPayload)
|
|
6667
|
+
});
|
|
6668
|
+
}
|
|
6669
|
+
const stepCompletedAtMs = Date.now();
|
|
6670
|
+
const timing = buildStepTiming({
|
|
6671
|
+
stepStartedAtMs,
|
|
6672
|
+
stepCompletedAtMs,
|
|
6673
|
+
modelCompletedAtMs,
|
|
6674
|
+
schedulerMetrics,
|
|
6675
|
+
toolExecutionMs,
|
|
6676
|
+
waitToolMs
|
|
6677
|
+
});
|
|
6678
|
+
steps.push({
|
|
6679
|
+
step: steps.length + 1,
|
|
6680
|
+
modelVersion,
|
|
6681
|
+
text: responseText || void 0,
|
|
6682
|
+
thoughts: void 0,
|
|
6683
|
+
toolCalls: stepToolCalls,
|
|
6684
|
+
usage: usageTokens,
|
|
6685
|
+
costUsd: stepCostUsd,
|
|
6686
|
+
timing
|
|
6687
|
+
});
|
|
6688
|
+
stepCallLogger?.complete({
|
|
6689
|
+
provider: "fireworks",
|
|
6690
|
+
model: request.model,
|
|
6691
|
+
modelVersion,
|
|
6692
|
+
step: turn,
|
|
6693
|
+
usage: usageTokens,
|
|
6694
|
+
costUsd: stepCostUsd,
|
|
6695
|
+
blocked,
|
|
6696
|
+
responseChars: responseText.length,
|
|
6697
|
+
thoughtChars: 0,
|
|
6698
|
+
toolCalls: stepToolCalls.length,
|
|
6699
|
+
finalStep: false
|
|
6700
|
+
});
|
|
6701
|
+
messages.push({
|
|
6702
|
+
role: "assistant",
|
|
6703
|
+
...responseText.length > 0 ? { content: responseText } : {},
|
|
6704
|
+
tool_calls: assistantToolCalls
|
|
6705
|
+
});
|
|
6706
|
+
messages.push(...toolMessages);
|
|
6707
|
+
const steeringInput = steeringInternal?.drainPendingContents() ?? [];
|
|
6708
|
+
if (steeringInput.length > 0) {
|
|
6709
|
+
messages.push(...toFireworksMessages(steeringInput));
|
|
6710
|
+
}
|
|
6711
|
+
} catch (error) {
|
|
6712
|
+
stepCallLogger?.fail(error, {
|
|
6713
|
+
provider: "fireworks",
|
|
6714
|
+
model: request.model,
|
|
6715
|
+
modelVersion,
|
|
6716
|
+
step: turn,
|
|
6717
|
+
usage: usageTokens,
|
|
6718
|
+
blocked
|
|
6719
|
+
});
|
|
6720
|
+
throw error;
|
|
6721
|
+
}
|
|
5741
6722
|
}
|
|
5742
6723
|
throw new Error(`Tool loop exceeded max steps (${maxSteps}) without final response.`);
|
|
5743
6724
|
}
|
|
5744
|
-
|
|
5745
|
-
|
|
5746
|
-
|
|
5747
|
-
|
|
5748
|
-
|
|
5749
|
-
|
|
5750
|
-
const
|
|
5751
|
-
|
|
5752
|
-
|
|
5753
|
-
|
|
5754
|
-
|
|
5755
|
-
|
|
5756
|
-
|
|
6725
|
+
const geminiFunctionTools = buildGeminiFunctionDeclarations(request.tools);
|
|
6726
|
+
const geminiNativeTools = toGeminiTools(request.modelTools);
|
|
6727
|
+
const geminiTools = geminiNativeTools ? geminiNativeTools.concat(geminiFunctionTools) : geminiFunctionTools;
|
|
6728
|
+
const geminiContents = contents.map(convertLlmContentToGeminiContent);
|
|
6729
|
+
for (let stepIndex = 0; stepIndex < maxSteps; stepIndex += 1) {
|
|
6730
|
+
const turn = stepIndex + 1;
|
|
6731
|
+
const stepStartedAtMs = Date.now();
|
|
6732
|
+
let firstModelEventAtMs;
|
|
6733
|
+
let schedulerMetrics;
|
|
6734
|
+
let modelVersion = request.model;
|
|
6735
|
+
let usageTokens;
|
|
6736
|
+
let responseText = "";
|
|
6737
|
+
let thoughtsText = "";
|
|
6738
|
+
const markFirstModelEvent = () => {
|
|
6739
|
+
if (firstModelEventAtMs === void 0) {
|
|
6740
|
+
firstModelEventAtMs = Date.now();
|
|
6741
|
+
}
|
|
6742
|
+
};
|
|
6743
|
+
const thinkingConfig = resolveGeminiThinkingConfig(request.model, request.thinkingLevel);
|
|
6744
|
+
const config = {
|
|
6745
|
+
maxOutputTokens: 32e3,
|
|
6746
|
+
tools: geminiTools,
|
|
6747
|
+
toolConfig: {
|
|
6748
|
+
functionCallingConfig: {
|
|
6749
|
+
mode: import_genai2.FunctionCallingConfigMode.VALIDATED
|
|
6750
|
+
}
|
|
6751
|
+
},
|
|
6752
|
+
...thinkingConfig ? { thinkingConfig } : {}
|
|
6753
|
+
};
|
|
6754
|
+
const onEvent = request.onEvent;
|
|
6755
|
+
const stepRequestPayload = {
|
|
6756
|
+
model: request.model,
|
|
6757
|
+
contents: geminiContents,
|
|
6758
|
+
config
|
|
6759
|
+
};
|
|
6760
|
+
const stepCallLogger = startLlmCallLoggerFromPayload({
|
|
6761
|
+
provider: "gemini",
|
|
6762
|
+
modelId: request.model,
|
|
6763
|
+
requestPayload: stepRequestPayload,
|
|
6764
|
+
step: turn
|
|
6765
|
+
});
|
|
6766
|
+
try {
|
|
6767
|
+
const response = await runGeminiCall(
|
|
5757
6768
|
async (client) => {
|
|
5758
|
-
|
|
5759
|
-
|
|
5760
|
-
|
|
5761
|
-
|
|
5762
|
-
|
|
5763
|
-
|
|
5764
|
-
|
|
5765
|
-
|
|
5766
|
-
|
|
5767
|
-
);
|
|
6769
|
+
const stream = await client.models.generateContentStream({
|
|
6770
|
+
model: request.model,
|
|
6771
|
+
contents: geminiContents,
|
|
6772
|
+
config
|
|
6773
|
+
});
|
|
6774
|
+
let responseText2 = "";
|
|
6775
|
+
let thoughtsText2 = "";
|
|
6776
|
+
const modelParts = [];
|
|
6777
|
+
const functionCalls = [];
|
|
6778
|
+
const seenFunctionCallIds = /* @__PURE__ */ new Set();
|
|
6779
|
+
const seenFunctionCallKeys = /* @__PURE__ */ new Set();
|
|
6780
|
+
let latestUsageMetadata;
|
|
6781
|
+
let resolvedModelVersion;
|
|
6782
|
+
for await (const chunk of stream) {
|
|
6783
|
+
markFirstModelEvent();
|
|
6784
|
+
if (chunk.modelVersion) {
|
|
6785
|
+
resolvedModelVersion = chunk.modelVersion;
|
|
6786
|
+
onEvent?.({ type: "model", modelVersion: chunk.modelVersion });
|
|
6787
|
+
}
|
|
6788
|
+
if (chunk.usageMetadata) {
|
|
6789
|
+
latestUsageMetadata = chunk.usageMetadata;
|
|
6790
|
+
}
|
|
6791
|
+
const candidates = chunk.candidates;
|
|
6792
|
+
if (!candidates || candidates.length === 0) {
|
|
6793
|
+
continue;
|
|
6794
|
+
}
|
|
6795
|
+
const primary = candidates[0];
|
|
6796
|
+
const parts = primary?.content?.parts;
|
|
6797
|
+
if (!parts || parts.length === 0) {
|
|
6798
|
+
continue;
|
|
6799
|
+
}
|
|
6800
|
+
for (const part of parts) {
|
|
6801
|
+
modelParts.push(part);
|
|
6802
|
+
const call = part.functionCall;
|
|
6803
|
+
if (call) {
|
|
6804
|
+
const id = typeof call.id === "string" ? call.id : "";
|
|
6805
|
+
const shouldAdd = (() => {
|
|
6806
|
+
if (id.length > 0) {
|
|
6807
|
+
if (seenFunctionCallIds.has(id)) {
|
|
6808
|
+
return false;
|
|
6809
|
+
}
|
|
6810
|
+
seenFunctionCallIds.add(id);
|
|
6811
|
+
return true;
|
|
6812
|
+
}
|
|
6813
|
+
const key = JSON.stringify({ name: call.name ?? "", args: call.args ?? null });
|
|
6814
|
+
if (seenFunctionCallKeys.has(key)) {
|
|
6815
|
+
return false;
|
|
6816
|
+
}
|
|
6817
|
+
seenFunctionCallKeys.add(key);
|
|
6818
|
+
return true;
|
|
6819
|
+
})();
|
|
6820
|
+
if (shouldAdd) {
|
|
6821
|
+
functionCalls.push(call);
|
|
6822
|
+
}
|
|
6823
|
+
}
|
|
6824
|
+
if (typeof part.text === "string" && part.text.length > 0) {
|
|
6825
|
+
if (part.thought) {
|
|
6826
|
+
thoughtsText2 += part.text;
|
|
6827
|
+
stepCallLogger?.appendThoughtDelta(part.text);
|
|
6828
|
+
onEvent?.({ type: "delta", channel: "thought", text: part.text });
|
|
6829
|
+
} else {
|
|
6830
|
+
responseText2 += part.text;
|
|
6831
|
+
stepCallLogger?.appendResponseDelta(part.text);
|
|
6832
|
+
onEvent?.({ type: "delta", channel: "response", text: part.text });
|
|
6833
|
+
}
|
|
6834
|
+
}
|
|
6835
|
+
}
|
|
6836
|
+
}
|
|
6837
|
+
return {
|
|
6838
|
+
responseText: responseText2,
|
|
6839
|
+
thoughtsText: thoughtsText2,
|
|
6840
|
+
functionCalls,
|
|
6841
|
+
modelParts,
|
|
6842
|
+
usageMetadata: latestUsageMetadata,
|
|
6843
|
+
modelVersion: resolvedModelVersion ?? request.model
|
|
6844
|
+
};
|
|
5768
6845
|
},
|
|
5769
|
-
|
|
6846
|
+
request.model,
|
|
5770
6847
|
{
|
|
5771
6848
|
onSettled: (metrics) => {
|
|
5772
6849
|
schedulerMetrics = metrics;
|
|
@@ -5774,43 +6851,26 @@ async function runToolLoop(request) {
|
|
|
5774
6851
|
}
|
|
5775
6852
|
);
|
|
5776
6853
|
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);
|
|
6854
|
+
usageTokens = extractGeminiUsageTokens(response.usageMetadata);
|
|
6855
|
+
modelVersion = response.modelVersion ?? request.model;
|
|
6856
|
+
responseText = response.responseText.trim();
|
|
6857
|
+
thoughtsText = response.thoughtsText.trim();
|
|
5789
6858
|
const stepCostUsd = estimateCallCostUsd({
|
|
5790
6859
|
modelId: modelVersion,
|
|
5791
6860
|
tokens: usageTokens,
|
|
5792
6861
|
responseImages: 0
|
|
5793
6862
|
});
|
|
5794
6863
|
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) {
|
|
6864
|
+
if (response.functionCalls.length === 0) {
|
|
5805
6865
|
const steeringInput2 = steeringInternal?.drainPendingContents() ?? [];
|
|
5806
|
-
const steeringMessages = steeringInput2.length > 0 ? toFireworksMessages(steeringInput2) : [];
|
|
5807
6866
|
finalText = responseText;
|
|
5808
|
-
finalThoughts =
|
|
6867
|
+
finalThoughts = thoughtsText;
|
|
5809
6868
|
const stepCompletedAtMs2 = Date.now();
|
|
5810
6869
|
const timing2 = buildStepTiming({
|
|
5811
6870
|
stepStartedAtMs,
|
|
5812
6871
|
stepCompletedAtMs: stepCompletedAtMs2,
|
|
5813
6872
|
modelCompletedAtMs,
|
|
6873
|
+
firstModelEventAtMs,
|
|
5814
6874
|
schedulerMetrics,
|
|
5815
6875
|
toolExecutionMs: 0,
|
|
5816
6876
|
waitToolMs: 0
|
|
@@ -5818,31 +6878,65 @@ async function runToolLoop(request) {
|
|
|
5818
6878
|
steps.push({
|
|
5819
6879
|
step: steps.length + 1,
|
|
5820
6880
|
modelVersion,
|
|
5821
|
-
text:
|
|
5822
|
-
thoughts: void 0,
|
|
6881
|
+
text: finalText || void 0,
|
|
6882
|
+
thoughts: finalThoughts || void 0,
|
|
5823
6883
|
toolCalls: [],
|
|
5824
6884
|
usage: usageTokens,
|
|
5825
6885
|
costUsd: stepCostUsd,
|
|
5826
6886
|
timing: timing2
|
|
5827
6887
|
});
|
|
5828
|
-
|
|
6888
|
+
stepCallLogger?.complete({
|
|
6889
|
+
provider: "gemini",
|
|
6890
|
+
model: request.model,
|
|
6891
|
+
modelVersion,
|
|
6892
|
+
step: turn,
|
|
6893
|
+
usage: usageTokens,
|
|
6894
|
+
costUsd: stepCostUsd,
|
|
6895
|
+
responseChars: responseText.length,
|
|
6896
|
+
thoughtChars: thoughtsText.length,
|
|
6897
|
+
toolCalls: 0,
|
|
6898
|
+
finalStep: steeringInput2.length === 0
|
|
6899
|
+
});
|
|
6900
|
+
if (steeringInput2.length === 0) {
|
|
5829
6901
|
return { text: finalText, thoughts: finalThoughts, steps, totalCostUsd };
|
|
5830
6902
|
}
|
|
5831
|
-
|
|
5832
|
-
|
|
6903
|
+
const modelPartsForHistory2 = response.modelParts.filter(
|
|
6904
|
+
(part) => !(typeof part.text === "string" && part.thought === true)
|
|
6905
|
+
);
|
|
6906
|
+
if (modelPartsForHistory2.length > 0) {
|
|
6907
|
+
geminiContents.push({ role: "model", parts: modelPartsForHistory2 });
|
|
6908
|
+
} else if (response.responseText.length > 0) {
|
|
6909
|
+
geminiContents.push({ role: "model", parts: [{ text: response.responseText }] });
|
|
5833
6910
|
}
|
|
5834
|
-
|
|
6911
|
+
geminiContents.push(...steeringInput2.map(convertLlmContentToGeminiContent));
|
|
5835
6912
|
continue;
|
|
5836
6913
|
}
|
|
5837
|
-
const
|
|
5838
|
-
const
|
|
6914
|
+
const toolCalls = [];
|
|
6915
|
+
const modelPartsForHistory = response.modelParts.filter(
|
|
6916
|
+
(part) => !(typeof part.text === "string" && part.thought === true)
|
|
6917
|
+
);
|
|
6918
|
+
if (modelPartsForHistory.length > 0) {
|
|
6919
|
+
geminiContents.push({ role: "model", parts: modelPartsForHistory });
|
|
6920
|
+
} else {
|
|
6921
|
+
const parts = [];
|
|
6922
|
+
if (response.responseText) {
|
|
6923
|
+
parts.push({ text: response.responseText });
|
|
6924
|
+
}
|
|
6925
|
+
for (const call of response.functionCalls) {
|
|
6926
|
+
parts.push({ functionCall: call });
|
|
6927
|
+
}
|
|
6928
|
+
geminiContents.push({ role: "model", parts });
|
|
6929
|
+
}
|
|
6930
|
+
const responseParts = [];
|
|
6931
|
+
const callInputs = response.functionCalls.map((call, index) => {
|
|
5839
6932
|
const toolIndex = index + 1;
|
|
5840
6933
|
const toolId = buildToolLogId(turn, toolIndex);
|
|
5841
|
-
const
|
|
5842
|
-
|
|
6934
|
+
const toolName = call.name ?? "unknown";
|
|
6935
|
+
const rawInput = call.args ?? {};
|
|
6936
|
+
return { call, toolName, rawInput, toolId, turn, toolIndex };
|
|
5843
6937
|
});
|
|
5844
6938
|
for (const entry of callInputs) {
|
|
5845
|
-
|
|
6939
|
+
onEvent?.({
|
|
5846
6940
|
type: "tool_call",
|
|
5847
6941
|
phase: "started",
|
|
5848
6942
|
turn: entry.turn,
|
|
@@ -5851,7 +6945,7 @@ async function runToolLoop(request) {
|
|
|
5851
6945
|
toolId: entry.toolId,
|
|
5852
6946
|
callKind: "function",
|
|
5853
6947
|
callId: entry.call.id,
|
|
5854
|
-
input: entry.
|
|
6948
|
+
input: entry.rawInput
|
|
5855
6949
|
});
|
|
5856
6950
|
}
|
|
5857
6951
|
const callResults = await Promise.all(
|
|
@@ -5868,26 +6962,23 @@ async function runToolLoop(request) {
|
|
|
5868
6962
|
callKind: "function",
|
|
5869
6963
|
toolName: entry.toolName,
|
|
5870
6964
|
tool: request.tools[entry.toolName],
|
|
5871
|
-
rawInput: entry.
|
|
5872
|
-
parseError: entry.parseError
|
|
6965
|
+
rawInput: entry.rawInput
|
|
5873
6966
|
});
|
|
5874
6967
|
return { entry, result, outputPayload };
|
|
5875
6968
|
}
|
|
5876
6969
|
);
|
|
5877
6970
|
})
|
|
5878
6971
|
);
|
|
5879
|
-
const assistantToolCalls = [];
|
|
5880
|
-
const toolMessages = [];
|
|
5881
6972
|
let toolExecutionMs = 0;
|
|
5882
6973
|
let waitToolMs = 0;
|
|
5883
6974
|
for (const { entry, result, outputPayload } of callResults) {
|
|
5884
|
-
|
|
6975
|
+
toolCalls.push({ ...result, callId: entry.call.id });
|
|
5885
6976
|
const callDurationMs = toToolResultDuration(result);
|
|
5886
6977
|
toolExecutionMs += callDurationMs;
|
|
5887
6978
|
if (entry.toolName.toLowerCase() === SUBAGENT_WAIT_TOOL_NAME) {
|
|
5888
6979
|
waitToolMs += callDurationMs;
|
|
5889
6980
|
}
|
|
5890
|
-
|
|
6981
|
+
onEvent?.({
|
|
5891
6982
|
type: "tool_call",
|
|
5892
6983
|
phase: "completed",
|
|
5893
6984
|
turn: entry.turn,
|
|
@@ -5896,30 +6987,26 @@ async function runToolLoop(request) {
|
|
|
5896
6987
|
toolId: entry.toolId,
|
|
5897
6988
|
callKind: "function",
|
|
5898
6989
|
callId: entry.call.id,
|
|
5899
|
-
input: entry.
|
|
6990
|
+
input: entry.rawInput,
|
|
5900
6991
|
output: result.output,
|
|
5901
6992
|
error: result.error,
|
|
5902
6993
|
durationMs: result.durationMs
|
|
5903
6994
|
});
|
|
5904
|
-
|
|
5905
|
-
|
|
5906
|
-
|
|
5907
|
-
function: {
|
|
6995
|
+
const responsePayload = isPlainRecord(outputPayload) ? outputPayload : { output: outputPayload };
|
|
6996
|
+
responseParts.push({
|
|
6997
|
+
functionResponse: {
|
|
5908
6998
|
name: entry.toolName,
|
|
5909
|
-
|
|
6999
|
+
response: responsePayload,
|
|
7000
|
+
...entry.call.id ? { id: entry.call.id } : {}
|
|
5910
7001
|
}
|
|
5911
7002
|
});
|
|
5912
|
-
toolMessages.push({
|
|
5913
|
-
role: "tool",
|
|
5914
|
-
tool_call_id: entry.call.id,
|
|
5915
|
-
content: mergeToolOutput(outputPayload)
|
|
5916
|
-
});
|
|
5917
7003
|
}
|
|
5918
7004
|
const stepCompletedAtMs = Date.now();
|
|
5919
7005
|
const timing = buildStepTiming({
|
|
5920
7006
|
stepStartedAtMs,
|
|
5921
7007
|
stepCompletedAtMs,
|
|
5922
7008
|
modelCompletedAtMs,
|
|
7009
|
+
firstModelEventAtMs,
|
|
5923
7010
|
schedulerMetrics,
|
|
5924
7011
|
toolExecutionMs,
|
|
5925
7012
|
waitToolMs
|
|
@@ -5928,296 +7015,40 @@ async function runToolLoop(request) {
|
|
|
5928
7015
|
step: steps.length + 1,
|
|
5929
7016
|
modelVersion,
|
|
5930
7017
|
text: responseText || void 0,
|
|
5931
|
-
thoughts: void 0,
|
|
5932
|
-
toolCalls
|
|
7018
|
+
thoughts: thoughtsText || void 0,
|
|
7019
|
+
toolCalls,
|
|
5933
7020
|
usage: usageTokens,
|
|
5934
7021
|
costUsd: stepCostUsd,
|
|
5935
7022
|
timing
|
|
5936
7023
|
});
|
|
5937
|
-
|
|
5938
|
-
|
|
5939
|
-
|
|
5940
|
-
|
|
7024
|
+
stepCallLogger?.complete({
|
|
7025
|
+
provider: "gemini",
|
|
7026
|
+
model: request.model,
|
|
7027
|
+
modelVersion,
|
|
7028
|
+
step: turn,
|
|
7029
|
+
usage: usageTokens,
|
|
7030
|
+
costUsd: stepCostUsd,
|
|
7031
|
+
responseChars: responseText.length,
|
|
7032
|
+
thoughtChars: thoughtsText.length,
|
|
7033
|
+
toolCalls: toolCalls.length,
|
|
7034
|
+
finalStep: false
|
|
5941
7035
|
});
|
|
5942
|
-
|
|
7036
|
+
geminiContents.push({ role: "user", parts: responseParts });
|
|
5943
7037
|
const steeringInput = steeringInternal?.drainPendingContents() ?? [];
|
|
5944
7038
|
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
|
-
}
|
|
7039
|
+
geminiContents.push(...steeringInput.map(convertLlmContentToGeminiContent));
|
|
6057
7040
|
}
|
|
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,
|
|
7041
|
+
} catch (error) {
|
|
7042
|
+
stepCallLogger?.fail(error, {
|
|
7043
|
+
provider: "gemini",
|
|
7044
|
+
model: request.model,
|
|
6084
7045
|
modelVersion,
|
|
6085
|
-
|
|
6086
|
-
thoughts: finalThoughts || void 0,
|
|
6087
|
-
toolCalls: [],
|
|
7046
|
+
step: turn,
|
|
6088
7047
|
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
|
-
}
|
|
7048
|
+
responseChars: responseText.length,
|
|
7049
|
+
thoughtChars: thoughtsText.length
|
|
6195
7050
|
});
|
|
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));
|
|
7051
|
+
throw error;
|
|
6221
7052
|
}
|
|
6222
7053
|
}
|
|
6223
7054
|
throw new Error(`Tool loop exceeded max steps (${maxSteps}) without final response.`);
|
|
@@ -6531,6 +7362,7 @@ ${lines}`;
|
|
|
6531
7362
|
|
|
6532
7363
|
// src/agent.ts
|
|
6533
7364
|
var import_node_crypto3 = require("crypto");
|
|
7365
|
+
var import_node_path7 = __toESM(require("path"), 1);
|
|
6534
7366
|
|
|
6535
7367
|
// src/agent/subagents.ts
|
|
6536
7368
|
var import_node_crypto2 = require("crypto");
|
|
@@ -7005,26 +7837,26 @@ function resolveInputItemsText(items) {
|
|
|
7005
7837
|
}
|
|
7006
7838
|
const itemType = typeof item.type === "string" ? item.type.trim() : "";
|
|
7007
7839
|
const name = typeof item.name === "string" ? item.name.trim() : "";
|
|
7008
|
-
const
|
|
7840
|
+
const path8 = typeof item.path === "string" ? item.path.trim() : "";
|
|
7009
7841
|
const imageUrl = typeof item.image_url === "string" ? item.image_url.trim() : "";
|
|
7010
7842
|
if (itemType === "image") {
|
|
7011
7843
|
lines.push("[image]");
|
|
7012
7844
|
continue;
|
|
7013
7845
|
}
|
|
7014
|
-
if (itemType === "local_image" &&
|
|
7015
|
-
lines.push(`[local_image:${
|
|
7846
|
+
if (itemType === "local_image" && path8) {
|
|
7847
|
+
lines.push(`[local_image:${path8}]`);
|
|
7016
7848
|
continue;
|
|
7017
7849
|
}
|
|
7018
|
-
if (itemType === "skill" && name &&
|
|
7019
|
-
lines.push(`[skill:$${name}](${
|
|
7850
|
+
if (itemType === "skill" && name && path8) {
|
|
7851
|
+
lines.push(`[skill:$${name}](${path8})`);
|
|
7020
7852
|
continue;
|
|
7021
7853
|
}
|
|
7022
|
-
if (itemType === "mention" && name &&
|
|
7023
|
-
lines.push(`[mention:$${name}](${
|
|
7854
|
+
if (itemType === "mention" && name && path8) {
|
|
7855
|
+
lines.push(`[mention:$${name}](${path8})`);
|
|
7024
7856
|
continue;
|
|
7025
7857
|
}
|
|
7026
|
-
if (
|
|
7027
|
-
lines.push(`[${itemType || "input"}:${
|
|
7858
|
+
if (path8 || imageUrl) {
|
|
7859
|
+
lines.push(`[${itemType || "input"}:${path8 || imageUrl}]`);
|
|
7028
7860
|
continue;
|
|
7029
7861
|
}
|
|
7030
7862
|
if (name) {
|
|
@@ -7149,7 +7981,7 @@ function startRun(agent, options) {
|
|
|
7149
7981
|
setLifecycle(agent, "idle", "input_queued", `Subagent ${agent.id} run interrupted.`);
|
|
7150
7982
|
return;
|
|
7151
7983
|
}
|
|
7152
|
-
const message =
|
|
7984
|
+
const message = toErrorMessage2(error);
|
|
7153
7985
|
agent.lastError = message;
|
|
7154
7986
|
setLifecycle(agent, "failed", "run_failed", `Subagent ${agent.id} failed: ${message}`);
|
|
7155
7987
|
emitBackgroundNotification(agent, options);
|
|
@@ -7329,7 +8161,7 @@ function trimToUndefined(value) {
|
|
|
7329
8161
|
const trimmed = value?.trim();
|
|
7330
8162
|
return trimmed && trimmed.length > 0 ? trimmed : void 0;
|
|
7331
8163
|
}
|
|
7332
|
-
function
|
|
8164
|
+
function toErrorMessage2(error) {
|
|
7333
8165
|
if (error instanceof Error) {
|
|
7334
8166
|
return error.message;
|
|
7335
8167
|
}
|
|
@@ -7342,27 +8174,27 @@ function sleep2(ms) {
|
|
|
7342
8174
|
}
|
|
7343
8175
|
|
|
7344
8176
|
// src/tools/filesystemTools.ts
|
|
7345
|
-
var
|
|
7346
|
-
var
|
|
8177
|
+
var import_node_path6 = __toESM(require("path"), 1);
|
|
8178
|
+
var import_node_buffer4 = require("buffer");
|
|
7347
8179
|
var import_zod6 = require("zod");
|
|
7348
8180
|
|
|
7349
8181
|
// src/tools/applyPatch.ts
|
|
7350
|
-
var
|
|
8182
|
+
var import_node_path5 = __toESM(require("path"), 1);
|
|
7351
8183
|
var import_zod5 = require("zod");
|
|
7352
8184
|
|
|
7353
8185
|
// src/tools/filesystem.ts
|
|
7354
8186
|
var import_node_fs3 = require("fs");
|
|
7355
|
-
var
|
|
8187
|
+
var import_node_path4 = __toESM(require("path"), 1);
|
|
7356
8188
|
var InMemoryAgentFilesystem = class {
|
|
7357
8189
|
#files = /* @__PURE__ */ new Map();
|
|
7358
8190
|
#dirs = /* @__PURE__ */ new Map();
|
|
7359
8191
|
#clock = 0;
|
|
7360
8192
|
constructor(initialFiles = {}) {
|
|
7361
|
-
const root =
|
|
8193
|
+
const root = import_node_path4.default.resolve("/");
|
|
7362
8194
|
this.#dirs.set(root, { mtimeMs: this.#nextMtime() });
|
|
7363
8195
|
for (const [filePath, content] of Object.entries(initialFiles)) {
|
|
7364
|
-
const absolutePath =
|
|
7365
|
-
this.#ensureDirSync(
|
|
8196
|
+
const absolutePath = import_node_path4.default.resolve(filePath);
|
|
8197
|
+
this.#ensureDirSync(import_node_path4.default.dirname(absolutePath));
|
|
7366
8198
|
this.#files.set(absolutePath, {
|
|
7367
8199
|
content,
|
|
7368
8200
|
mtimeMs: this.#nextMtime()
|
|
@@ -7370,7 +8202,7 @@ var InMemoryAgentFilesystem = class {
|
|
|
7370
8202
|
}
|
|
7371
8203
|
}
|
|
7372
8204
|
async readTextFile(filePath) {
|
|
7373
|
-
const absolutePath =
|
|
8205
|
+
const absolutePath = import_node_path4.default.resolve(filePath);
|
|
7374
8206
|
const file = this.#files.get(absolutePath);
|
|
7375
8207
|
if (!file) {
|
|
7376
8208
|
throw createNoSuchFileError("open", absolutePath);
|
|
@@ -7382,24 +8214,24 @@ var InMemoryAgentFilesystem = class {
|
|
|
7382
8214
|
return Buffer.from(content, "utf8");
|
|
7383
8215
|
}
|
|
7384
8216
|
async writeTextFile(filePath, content) {
|
|
7385
|
-
const absolutePath =
|
|
7386
|
-
const parentPath =
|
|
8217
|
+
const absolutePath = import_node_path4.default.resolve(filePath);
|
|
8218
|
+
const parentPath = import_node_path4.default.dirname(absolutePath);
|
|
7387
8219
|
if (!this.#dirs.has(parentPath)) {
|
|
7388
8220
|
throw createNoSuchFileError("open", parentPath);
|
|
7389
8221
|
}
|
|
7390
8222
|
this.#files.set(absolutePath, { content, mtimeMs: this.#nextMtime() });
|
|
7391
8223
|
}
|
|
7392
8224
|
async deleteFile(filePath) {
|
|
7393
|
-
const absolutePath =
|
|
8225
|
+
const absolutePath = import_node_path4.default.resolve(filePath);
|
|
7394
8226
|
if (!this.#files.delete(absolutePath)) {
|
|
7395
8227
|
throw createNoSuchFileError("unlink", absolutePath);
|
|
7396
8228
|
}
|
|
7397
8229
|
}
|
|
7398
8230
|
async ensureDir(directoryPath) {
|
|
7399
|
-
this.#ensureDirSync(
|
|
8231
|
+
this.#ensureDirSync(import_node_path4.default.resolve(directoryPath));
|
|
7400
8232
|
}
|
|
7401
8233
|
async readDir(directoryPath) {
|
|
7402
|
-
const absolutePath =
|
|
8234
|
+
const absolutePath = import_node_path4.default.resolve(directoryPath);
|
|
7403
8235
|
const directory = this.#dirs.get(absolutePath);
|
|
7404
8236
|
if (!directory) {
|
|
7405
8237
|
throw createNoSuchFileError("scandir", absolutePath);
|
|
@@ -7410,10 +8242,10 @@ var InMemoryAgentFilesystem = class {
|
|
|
7410
8242
|
if (dirPath === absolutePath) {
|
|
7411
8243
|
continue;
|
|
7412
8244
|
}
|
|
7413
|
-
if (
|
|
8245
|
+
if (import_node_path4.default.dirname(dirPath) !== absolutePath) {
|
|
7414
8246
|
continue;
|
|
7415
8247
|
}
|
|
7416
|
-
const name =
|
|
8248
|
+
const name = import_node_path4.default.basename(dirPath);
|
|
7417
8249
|
if (seenNames.has(name)) {
|
|
7418
8250
|
continue;
|
|
7419
8251
|
}
|
|
@@ -7426,10 +8258,10 @@ var InMemoryAgentFilesystem = class {
|
|
|
7426
8258
|
});
|
|
7427
8259
|
}
|
|
7428
8260
|
for (const [filePath, fileRecord] of this.#files.entries()) {
|
|
7429
|
-
if (
|
|
8261
|
+
if (import_node_path4.default.dirname(filePath) !== absolutePath) {
|
|
7430
8262
|
continue;
|
|
7431
8263
|
}
|
|
7432
|
-
const name =
|
|
8264
|
+
const name = import_node_path4.default.basename(filePath);
|
|
7433
8265
|
if (seenNames.has(name)) {
|
|
7434
8266
|
continue;
|
|
7435
8267
|
}
|
|
@@ -7445,7 +8277,7 @@ var InMemoryAgentFilesystem = class {
|
|
|
7445
8277
|
return entries;
|
|
7446
8278
|
}
|
|
7447
8279
|
async stat(entryPath) {
|
|
7448
|
-
const absolutePath =
|
|
8280
|
+
const absolutePath = import_node_path4.default.resolve(entryPath);
|
|
7449
8281
|
const file = this.#files.get(absolutePath);
|
|
7450
8282
|
if (file) {
|
|
7451
8283
|
return { kind: "file", mtimeMs: file.mtimeMs };
|
|
@@ -7461,7 +8293,7 @@ var InMemoryAgentFilesystem = class {
|
|
|
7461
8293
|
return Object.fromEntries(entries.map(([filePath, record]) => [filePath, record.content]));
|
|
7462
8294
|
}
|
|
7463
8295
|
#ensureDirSync(directoryPath) {
|
|
7464
|
-
const absolutePath =
|
|
8296
|
+
const absolutePath = import_node_path4.default.resolve(directoryPath);
|
|
7465
8297
|
const parts = [];
|
|
7466
8298
|
let cursor = absolutePath;
|
|
7467
8299
|
for (; ; ) {
|
|
@@ -7469,7 +8301,7 @@ var InMemoryAgentFilesystem = class {
|
|
|
7469
8301
|
break;
|
|
7470
8302
|
}
|
|
7471
8303
|
parts.push(cursor);
|
|
7472
|
-
const parent =
|
|
8304
|
+
const parent = import_node_path4.default.dirname(cursor);
|
|
7473
8305
|
if (parent === cursor) {
|
|
7474
8306
|
break;
|
|
7475
8307
|
}
|
|
@@ -7503,7 +8335,7 @@ function createNodeAgentFilesystem() {
|
|
|
7503
8335
|
const entries = await import_node_fs3.promises.readdir(directoryPath, { withFileTypes: true });
|
|
7504
8336
|
const result = [];
|
|
7505
8337
|
for (const entry of entries) {
|
|
7506
|
-
const entryPath =
|
|
8338
|
+
const entryPath = import_node_path4.default.resolve(directoryPath, entry.name);
|
|
7507
8339
|
const stats = await import_node_fs3.promises.lstat(entryPath);
|
|
7508
8340
|
result.push({
|
|
7509
8341
|
name: entry.name,
|
|
@@ -7667,7 +8499,7 @@ function createApplyPatchTool(options = {}) {
|
|
|
7667
8499
|
});
|
|
7668
8500
|
}
|
|
7669
8501
|
async function applyPatch(request) {
|
|
7670
|
-
const cwd =
|
|
8502
|
+
const cwd = import_node_path5.default.resolve(request.cwd ?? process.cwd());
|
|
7671
8503
|
const adapter = request.fs ?? createNodeAgentFilesystem();
|
|
7672
8504
|
const allowOutsideCwd = request.allowOutsideCwd === true;
|
|
7673
8505
|
const patchBytes = Buffer.byteLength(request.patch, "utf8");
|
|
@@ -7689,7 +8521,7 @@ async function applyPatch(request) {
|
|
|
7689
8521
|
kind: "add",
|
|
7690
8522
|
path: absolutePath2
|
|
7691
8523
|
});
|
|
7692
|
-
await adapter.ensureDir(
|
|
8524
|
+
await adapter.ensureDir(import_node_path5.default.dirname(absolutePath2));
|
|
7693
8525
|
await adapter.writeTextFile(absolutePath2, operation.content);
|
|
7694
8526
|
added.push(toDisplayPath(absolutePath2, cwd));
|
|
7695
8527
|
continue;
|
|
@@ -7723,7 +8555,7 @@ async function applyPatch(request) {
|
|
|
7723
8555
|
fromPath: absolutePath,
|
|
7724
8556
|
toPath: destinationPath
|
|
7725
8557
|
});
|
|
7726
|
-
await adapter.ensureDir(
|
|
8558
|
+
await adapter.ensureDir(import_node_path5.default.dirname(destinationPath));
|
|
7727
8559
|
await adapter.writeTextFile(destinationPath, next);
|
|
7728
8560
|
await adapter.deleteFile(absolutePath);
|
|
7729
8561
|
modified.push(toDisplayPath(destinationPath, cwd));
|
|
@@ -7754,22 +8586,22 @@ function resolvePatchPath(rawPath, cwd, allowOutsideCwd) {
|
|
|
7754
8586
|
if (trimmed.length === 0) {
|
|
7755
8587
|
throw new Error("apply_patch failed: empty file path");
|
|
7756
8588
|
}
|
|
7757
|
-
const absolutePath =
|
|
8589
|
+
const absolutePath = import_node_path5.default.isAbsolute(trimmed) ? import_node_path5.default.resolve(trimmed) : import_node_path5.default.resolve(cwd, trimmed);
|
|
7758
8590
|
if (!allowOutsideCwd && !isPathInsideCwd(absolutePath, cwd)) {
|
|
7759
8591
|
throw new Error(`apply_patch failed: path "${trimmed}" resolves outside cwd "${cwd}"`);
|
|
7760
8592
|
}
|
|
7761
8593
|
return absolutePath;
|
|
7762
8594
|
}
|
|
7763
8595
|
function isPathInsideCwd(candidatePath, cwd) {
|
|
7764
|
-
const relative =
|
|
7765
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
8596
|
+
const relative = import_node_path5.default.relative(cwd, candidatePath);
|
|
8597
|
+
return relative === "" || !relative.startsWith("..") && !import_node_path5.default.isAbsolute(relative);
|
|
7766
8598
|
}
|
|
7767
8599
|
function toDisplayPath(absolutePath, cwd) {
|
|
7768
|
-
const relative =
|
|
8600
|
+
const relative = import_node_path5.default.relative(cwd, absolutePath);
|
|
7769
8601
|
if (relative === "") {
|
|
7770
8602
|
return ".";
|
|
7771
8603
|
}
|
|
7772
|
-
if (!relative.startsWith("..") && !
|
|
8604
|
+
if (!relative.startsWith("..") && !import_node_path5.default.isAbsolute(relative)) {
|
|
7773
8605
|
return relative;
|
|
7774
8606
|
}
|
|
7775
8607
|
return absolutePath;
|
|
@@ -8536,7 +9368,7 @@ async function readBinaryFile(filesystem, filePath) {
|
|
|
8536
9368
|
return await filesystem.readBinaryFile(filePath);
|
|
8537
9369
|
}
|
|
8538
9370
|
const text = await filesystem.readTextFile(filePath);
|
|
8539
|
-
return
|
|
9371
|
+
return import_node_buffer4.Buffer.from(text, "utf8");
|
|
8540
9372
|
}
|
|
8541
9373
|
function detectImageMimeType(buffer, filePath) {
|
|
8542
9374
|
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 +9386,7 @@ function detectImageMimeType(buffer, filePath) {
|
|
|
8554
9386
|
if (buffer.length >= 12 && buffer.subarray(0, 4).toString("ascii") === "RIFF" && buffer.subarray(8, 12).toString("ascii") === "WEBP") {
|
|
8555
9387
|
return "image/webp";
|
|
8556
9388
|
}
|
|
8557
|
-
const fromExtension = IMAGE_MIME_BY_EXTENSION[
|
|
9389
|
+
const fromExtension = IMAGE_MIME_BY_EXTENSION[import_node_path6.default.extname(filePath).toLowerCase()];
|
|
8558
9390
|
if (fromExtension && SUPPORTED_IMAGE_MIME_TYPES.has(fromExtension)) {
|
|
8559
9391
|
return fromExtension;
|
|
8560
9392
|
}
|
|
@@ -8564,13 +9396,13 @@ function isPdfFile(buffer, filePath) {
|
|
|
8564
9396
|
if (buffer.length >= 5 && buffer.subarray(0, 5).toString("ascii") === "%PDF-") {
|
|
8565
9397
|
return true;
|
|
8566
9398
|
}
|
|
8567
|
-
return
|
|
9399
|
+
return import_node_path6.default.extname(filePath).toLowerCase() === ".pdf";
|
|
8568
9400
|
}
|
|
8569
9401
|
function isValidUtf8(buffer) {
|
|
8570
9402
|
if (buffer.length === 0) {
|
|
8571
9403
|
return true;
|
|
8572
9404
|
}
|
|
8573
|
-
return
|
|
9405
|
+
return import_node_buffer4.Buffer.from(buffer.toString("utf8"), "utf8").equals(buffer);
|
|
8574
9406
|
}
|
|
8575
9407
|
async function readFileGemini(input, options) {
|
|
8576
9408
|
const runtime = resolveRuntime(options);
|
|
@@ -8602,7 +9434,7 @@ async function writeFileGemini(input, options) {
|
|
|
8602
9434
|
action: "write",
|
|
8603
9435
|
path: filePath
|
|
8604
9436
|
});
|
|
8605
|
-
await runtime.filesystem.ensureDir(
|
|
9437
|
+
await runtime.filesystem.ensureDir(import_node_path6.default.dirname(filePath));
|
|
8606
9438
|
await runtime.filesystem.writeTextFile(filePath, input.content);
|
|
8607
9439
|
return `Successfully wrote file: ${toDisplayPath2(filePath, runtime.cwd)}`;
|
|
8608
9440
|
}
|
|
@@ -8623,7 +9455,7 @@ async function replaceFileContentGemini(input, options) {
|
|
|
8623
9455
|
originalContent = await runtime.filesystem.readTextFile(filePath);
|
|
8624
9456
|
} catch (error) {
|
|
8625
9457
|
if (isNoEntError(error) && oldValue.length === 0) {
|
|
8626
|
-
await runtime.filesystem.ensureDir(
|
|
9458
|
+
await runtime.filesystem.ensureDir(import_node_path6.default.dirname(filePath));
|
|
8627
9459
|
await runtime.filesystem.writeTextFile(filePath, newValue);
|
|
8628
9460
|
return `Successfully wrote new file: ${toDisplayPath2(filePath, runtime.cwd)}`;
|
|
8629
9461
|
}
|
|
@@ -8801,7 +9633,7 @@ async function globFilesGemini(input, options) {
|
|
|
8801
9633
|
});
|
|
8802
9634
|
const matched = [];
|
|
8803
9635
|
for (const filePath of files) {
|
|
8804
|
-
const relativePath = normalizeSlashes(
|
|
9636
|
+
const relativePath = normalizeSlashes(import_node_path6.default.relative(dirPath, filePath));
|
|
8805
9637
|
if (!matcher(relativePath)) {
|
|
8806
9638
|
continue;
|
|
8807
9639
|
}
|
|
@@ -8819,7 +9651,7 @@ async function globFilesGemini(input, options) {
|
|
|
8819
9651
|
}
|
|
8820
9652
|
function resolveRuntime(options) {
|
|
8821
9653
|
return {
|
|
8822
|
-
cwd:
|
|
9654
|
+
cwd: import_node_path6.default.resolve(options.cwd ?? process.cwd()),
|
|
8823
9655
|
filesystem: options.fs ?? createNodeAgentFilesystem(),
|
|
8824
9656
|
allowOutsideCwd: options.allowOutsideCwd === true,
|
|
8825
9657
|
checkAccess: options.checkAccess,
|
|
@@ -8850,13 +9682,13 @@ function mapApplyPatchAction(action) {
|
|
|
8850
9682
|
return "move";
|
|
8851
9683
|
}
|
|
8852
9684
|
function resolvePathWithPolicy(inputPath, cwd, allowOutsideCwd) {
|
|
8853
|
-
const absolutePath =
|
|
9685
|
+
const absolutePath = import_node_path6.default.isAbsolute(inputPath) ? import_node_path6.default.resolve(inputPath) : import_node_path6.default.resolve(cwd, inputPath);
|
|
8854
9686
|
if (allowOutsideCwd || isPathInsideCwd2(absolutePath, cwd)) {
|
|
8855
9687
|
return absolutePath;
|
|
8856
9688
|
}
|
|
8857
|
-
if (
|
|
9689
|
+
if (import_node_path6.default.isAbsolute(inputPath)) {
|
|
8858
9690
|
const sandboxRelativePath = inputPath.replace(/^[/\\]+/, "");
|
|
8859
|
-
const sandboxRootedPath =
|
|
9691
|
+
const sandboxRootedPath = import_node_path6.default.resolve(cwd, sandboxRelativePath);
|
|
8860
9692
|
if (isPathInsideCwd2(sandboxRootedPath, cwd)) {
|
|
8861
9693
|
return sandboxRootedPath;
|
|
8862
9694
|
}
|
|
@@ -8864,25 +9696,25 @@ function resolvePathWithPolicy(inputPath, cwd, allowOutsideCwd) {
|
|
|
8864
9696
|
throw new Error(`path "${inputPath}" resolves outside cwd "${cwd}"`);
|
|
8865
9697
|
}
|
|
8866
9698
|
function isPathInsideCwd2(candidatePath, cwd) {
|
|
8867
|
-
const relative =
|
|
8868
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
9699
|
+
const relative = import_node_path6.default.relative(cwd, candidatePath);
|
|
9700
|
+
return relative === "" || !relative.startsWith("..") && !import_node_path6.default.isAbsolute(relative);
|
|
8869
9701
|
}
|
|
8870
9702
|
function toDisplayPath2(absolutePath, cwd) {
|
|
8871
|
-
const relative =
|
|
9703
|
+
const relative = import_node_path6.default.relative(cwd, absolutePath);
|
|
8872
9704
|
if (relative === "") {
|
|
8873
9705
|
return ".";
|
|
8874
9706
|
}
|
|
8875
|
-
if (!relative.startsWith("..") && !
|
|
9707
|
+
if (!relative.startsWith("..") && !import_node_path6.default.isAbsolute(relative)) {
|
|
8876
9708
|
return relative;
|
|
8877
9709
|
}
|
|
8878
9710
|
return absolutePath;
|
|
8879
9711
|
}
|
|
8880
9712
|
function toSandboxDisplayPath(absolutePath, cwd) {
|
|
8881
|
-
const relative =
|
|
9713
|
+
const relative = import_node_path6.default.relative(cwd, absolutePath);
|
|
8882
9714
|
if (relative === "") {
|
|
8883
9715
|
return "/";
|
|
8884
9716
|
}
|
|
8885
|
-
if (!relative.startsWith("..") && !
|
|
9717
|
+
if (!relative.startsWith("..") && !import_node_path6.default.isAbsolute(relative)) {
|
|
8886
9718
|
return `/${normalizeSlashes(relative)}`;
|
|
8887
9719
|
}
|
|
8888
9720
|
return normalizeSlashes(absolutePath);
|
|
@@ -8998,7 +9830,7 @@ function createGlobMatcher(pattern, caseSensitive = false) {
|
|
|
8998
9830
|
}));
|
|
8999
9831
|
return (candidatePath) => {
|
|
9000
9832
|
const normalizedPath = normalizeSlashes(candidatePath);
|
|
9001
|
-
const basename =
|
|
9833
|
+
const basename = import_node_path6.default.posix.basename(normalizedPath);
|
|
9002
9834
|
return compiled.some(
|
|
9003
9835
|
(entry) => entry.regex.test(entry.applyToBasename ? basename : normalizedPath)
|
|
9004
9836
|
);
|
|
@@ -9114,10 +9946,18 @@ function isNoEntError(error) {
|
|
|
9114
9946
|
// src/agent.ts
|
|
9115
9947
|
async function runAgentLoop(request) {
|
|
9116
9948
|
const telemetry = createAgentTelemetrySession(request.telemetry);
|
|
9949
|
+
const logging = createRootAgentLoggingSession(request);
|
|
9117
9950
|
try {
|
|
9118
|
-
return await
|
|
9951
|
+
return await runWithAgentLoggingSession(logging, async () => {
|
|
9952
|
+
return await runAgentLoopInternal(request, {
|
|
9953
|
+
depth: 0,
|
|
9954
|
+
telemetry,
|
|
9955
|
+
logging
|
|
9956
|
+
});
|
|
9957
|
+
});
|
|
9119
9958
|
} finally {
|
|
9120
9959
|
await telemetry?.flush();
|
|
9960
|
+
await logging?.flush();
|
|
9121
9961
|
}
|
|
9122
9962
|
}
|
|
9123
9963
|
function mergeAbortSignals2(first, second) {
|
|
@@ -9188,9 +10028,11 @@ async function runAgentLoopInternal(request, context) {
|
|
|
9188
10028
|
subagent_tool,
|
|
9189
10029
|
subagents,
|
|
9190
10030
|
telemetry,
|
|
10031
|
+
logging: _logging,
|
|
9191
10032
|
...toolLoopRequest
|
|
9192
10033
|
} = request;
|
|
9193
10034
|
const telemetrySession = context.telemetry ?? createAgentTelemetrySession(telemetry);
|
|
10035
|
+
const loggingSession = context.logging;
|
|
9194
10036
|
const runId = randomRunId();
|
|
9195
10037
|
const startedAtMs = Date.now();
|
|
9196
10038
|
const steeringChannel = toolLoopRequest.steering ?? createToolLoopSteeringChannel();
|
|
@@ -9204,6 +10046,7 @@ async function runAgentLoopInternal(request, context) {
|
|
|
9204
10046
|
model: request.model,
|
|
9205
10047
|
depth: context.depth,
|
|
9206
10048
|
telemetry: telemetrySession,
|
|
10049
|
+
logging: loggingSession,
|
|
9207
10050
|
customTools: customTools ?? {},
|
|
9208
10051
|
filesystemSelection,
|
|
9209
10052
|
subagentSelection,
|
|
@@ -9240,6 +10083,16 @@ async function runAgentLoopInternal(request, context) {
|
|
|
9240
10083
|
filesystemToolsEnabled: Object.keys(filesystemTools).length > 0,
|
|
9241
10084
|
subagentToolsEnabled: resolvedSubagentConfig.enabled
|
|
9242
10085
|
});
|
|
10086
|
+
loggingSession?.logLine(
|
|
10087
|
+
[
|
|
10088
|
+
`[agent:${runId}] run_started`,
|
|
10089
|
+
`depth=${context.depth.toString()}`,
|
|
10090
|
+
`model=${request.model}`,
|
|
10091
|
+
`tools=${Object.keys(mergedTools).length.toString()}`,
|
|
10092
|
+
`filesystemTools=${Object.keys(filesystemTools).length > 0 ? "true" : "false"}`,
|
|
10093
|
+
`subagentTools=${resolvedSubagentConfig.enabled ? "true" : "false"}`
|
|
10094
|
+
].join(" ")
|
|
10095
|
+
);
|
|
9243
10096
|
const sourceOnEvent = toolLoopRequestWithSteering.onEvent;
|
|
9244
10097
|
const includeLlmStreamEvents = telemetrySession?.includeLlmStreamEvents === true;
|
|
9245
10098
|
const wrappedOnEvent = sourceOnEvent || includeLlmStreamEvents ? (event) => {
|
|
@@ -9247,6 +10100,14 @@ async function runAgentLoopInternal(request, context) {
|
|
|
9247
10100
|
if (includeLlmStreamEvents) {
|
|
9248
10101
|
emitTelemetry({ type: "agent.run.stream", event });
|
|
9249
10102
|
}
|
|
10103
|
+
if (loggingSession) {
|
|
10104
|
+
appendAgentStreamEventLog({
|
|
10105
|
+
event,
|
|
10106
|
+
append: (line) => {
|
|
10107
|
+
loggingSession.logLine(`[agent:${runId}] ${line}`);
|
|
10108
|
+
}
|
|
10109
|
+
});
|
|
10110
|
+
}
|
|
9250
10111
|
} : void 0;
|
|
9251
10112
|
try {
|
|
9252
10113
|
const result = await runToolLoop({
|
|
@@ -9264,14 +10125,43 @@ async function runAgentLoopInternal(request, context) {
|
|
|
9264
10125
|
totalCostUsd: result.totalCostUsd,
|
|
9265
10126
|
usage: summarizeResultUsage(result)
|
|
9266
10127
|
});
|
|
10128
|
+
loggingSession?.logLine(
|
|
10129
|
+
[
|
|
10130
|
+
`[agent:${runId}] run_completed`,
|
|
10131
|
+
`status=ok`,
|
|
10132
|
+
`durationMs=${Math.max(0, Date.now() - startedAtMs).toString()}`,
|
|
10133
|
+
`steps=${result.steps.length.toString()}`,
|
|
10134
|
+
`toolCalls=${countToolCalls(result).toString()}`,
|
|
10135
|
+
`totalCostUsd=${(result.totalCostUsd ?? 0).toFixed(6)}`
|
|
10136
|
+
].join(" ")
|
|
10137
|
+
);
|
|
10138
|
+
for (const step of result.steps) {
|
|
10139
|
+
loggingSession?.logLine(
|
|
10140
|
+
[
|
|
10141
|
+
`[agent:${runId}] step_completed`,
|
|
10142
|
+
`step=${step.step.toString()}`,
|
|
10143
|
+
`modelVersion=${step.modelVersion}`,
|
|
10144
|
+
`toolCalls=${step.toolCalls.length.toString()}`,
|
|
10145
|
+
`costUsd=${(step.costUsd ?? 0).toFixed(6)}`
|
|
10146
|
+
].join(" ")
|
|
10147
|
+
);
|
|
10148
|
+
}
|
|
9267
10149
|
return result;
|
|
9268
10150
|
} catch (error) {
|
|
9269
10151
|
emitTelemetry({
|
|
9270
10152
|
type: "agent.run.completed",
|
|
9271
10153
|
success: false,
|
|
9272
10154
|
durationMs: Math.max(0, Date.now() - startedAtMs),
|
|
9273
|
-
error:
|
|
10155
|
+
error: toErrorMessage3(error)
|
|
9274
10156
|
});
|
|
10157
|
+
loggingSession?.logLine(
|
|
10158
|
+
[
|
|
10159
|
+
`[agent:${runId}] run_completed`,
|
|
10160
|
+
`status=error`,
|
|
10161
|
+
`durationMs=${Math.max(0, Date.now() - startedAtMs).toString()}`,
|
|
10162
|
+
`error=${toErrorMessage3(error)}`
|
|
10163
|
+
].join(" ")
|
|
10164
|
+
);
|
|
9275
10165
|
throw error;
|
|
9276
10166
|
} finally {
|
|
9277
10167
|
await subagentController?.closeAll();
|
|
@@ -9342,7 +10232,8 @@ function createSubagentController(params) {
|
|
|
9342
10232
|
{
|
|
9343
10233
|
depth: params.depth + 1,
|
|
9344
10234
|
parentRunId: params.runId,
|
|
9345
|
-
telemetry: params.telemetry
|
|
10235
|
+
telemetry: params.telemetry,
|
|
10236
|
+
logging: params.logging
|
|
9346
10237
|
}
|
|
9347
10238
|
);
|
|
9348
10239
|
}
|
|
@@ -9406,10 +10297,10 @@ function trimToUndefined2(value) {
|
|
|
9406
10297
|
function randomRunId() {
|
|
9407
10298
|
return (0, import_node_crypto3.randomBytes)(8).toString("hex");
|
|
9408
10299
|
}
|
|
9409
|
-
function
|
|
10300
|
+
function toIsoNow2() {
|
|
9410
10301
|
return (/* @__PURE__ */ new Date()).toISOString();
|
|
9411
10302
|
}
|
|
9412
|
-
function
|
|
10303
|
+
function toErrorMessage3(error) {
|
|
9413
10304
|
if (error instanceof Error && error.message) {
|
|
9414
10305
|
return error.message;
|
|
9415
10306
|
}
|
|
@@ -9454,9 +10345,41 @@ function summarizeResultUsage(result) {
|
|
|
9454
10345
|
}
|
|
9455
10346
|
return summary;
|
|
9456
10347
|
}
|
|
9457
|
-
function
|
|
10348
|
+
function isPromiseLike2(value) {
|
|
9458
10349
|
return (typeof value === "object" || typeof value === "function") && value !== null && typeof value.then === "function";
|
|
9459
10350
|
}
|
|
10351
|
+
function resolveAgentLoggingSelection(value) {
|
|
10352
|
+
if (value === false) {
|
|
10353
|
+
return void 0;
|
|
10354
|
+
}
|
|
10355
|
+
if (value === void 0 || value === true) {
|
|
10356
|
+
return {
|
|
10357
|
+
mirrorToConsole: true
|
|
10358
|
+
};
|
|
10359
|
+
}
|
|
10360
|
+
return value;
|
|
10361
|
+
}
|
|
10362
|
+
function resolveWorkspaceDirForLogging(request) {
|
|
10363
|
+
const explicitSelection = request.filesystemTool ?? request.filesystem_tool;
|
|
10364
|
+
if (explicitSelection && typeof explicitSelection === "object" && !Array.isArray(explicitSelection)) {
|
|
10365
|
+
const cwd = explicitSelection.options?.cwd;
|
|
10366
|
+
if (typeof cwd === "string" && cwd.trim().length > 0) {
|
|
10367
|
+
return import_node_path7.default.resolve(cwd);
|
|
10368
|
+
}
|
|
10369
|
+
}
|
|
10370
|
+
return process.cwd();
|
|
10371
|
+
}
|
|
10372
|
+
function createRootAgentLoggingSession(request) {
|
|
10373
|
+
const selected = resolveAgentLoggingSelection(request.logging);
|
|
10374
|
+
if (!selected) {
|
|
10375
|
+
return void 0;
|
|
10376
|
+
}
|
|
10377
|
+
return createAgentLoggingSession({
|
|
10378
|
+
...selected,
|
|
10379
|
+
workspaceDir: typeof selected.workspaceDir === "string" && selected.workspaceDir.trim().length > 0 ? import_node_path7.default.resolve(selected.workspaceDir) : resolveWorkspaceDirForLogging(request),
|
|
10380
|
+
mirrorToConsole: selected.mirrorToConsole !== false
|
|
10381
|
+
});
|
|
10382
|
+
}
|
|
9460
10383
|
function isAgentTelemetrySink(value) {
|
|
9461
10384
|
return typeof value === "object" && value !== null && typeof value.emit === "function";
|
|
9462
10385
|
}
|
|
@@ -9487,7 +10410,7 @@ function createAgentTelemetrySession(telemetry) {
|
|
|
9487
10410
|
const emit = (event) => {
|
|
9488
10411
|
try {
|
|
9489
10412
|
const output = config.sink.emit(event);
|
|
9490
|
-
if (
|
|
10413
|
+
if (isPromiseLike2(output)) {
|
|
9491
10414
|
const task = Promise.resolve(output).then(() => void 0).catch(() => void 0);
|
|
9492
10415
|
trackPromise(task);
|
|
9493
10416
|
}
|
|
@@ -9518,7 +10441,7 @@ function createAgentTelemetryEmitter(params) {
|
|
|
9518
10441
|
}
|
|
9519
10442
|
params.session.emit({
|
|
9520
10443
|
...event,
|
|
9521
|
-
timestamp:
|
|
10444
|
+
timestamp: toIsoNow2(),
|
|
9522
10445
|
runId: params.runId,
|
|
9523
10446
|
...params.parentRunId ? { parentRunId: params.parentRunId } : {},
|
|
9524
10447
|
depth: params.depth,
|