@llmbridge/plugin-logging 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +5 -3
- package/dist/index.d.ts +5 -3
- package/dist/index.js +126 -83
- package/dist/index.mjs +126 -83
- package/package.json +1 -1
package/dist/index.d.mts
CHANGED
|
@@ -15,19 +15,21 @@ declare function generateRandomDigits(length: number): string;
|
|
|
15
15
|
declare class LoggingPlugin implements LLMBridge.Plugin<void, string, void, void> {
|
|
16
16
|
private options;
|
|
17
17
|
private logger;
|
|
18
|
+
private runSessions;
|
|
18
19
|
constructor(options: LoggingPluginOptions);
|
|
19
20
|
private log;
|
|
20
21
|
wrapRun(next: () => Promise<LLMBridge.Response>, context: LLMBridge.PluginCompletionContext): Promise<LLMBridge.Response>;
|
|
21
|
-
wrapExec(next: (params: any) => Promise<any>, params: any,
|
|
22
|
+
wrapExec(next: (params: any) => Promise<any>, params: any, context: LLMBridge.PluginCompletionContext): Promise<any>;
|
|
22
23
|
wrapToolExec(next: (tool: LLMBridge.Tool, counter: number, input: any) => Promise<any>, tool: LLMBridge.Tool, counter: number, input: any, context: LLMBridge.PluginCompletionContext): Promise<any>;
|
|
23
24
|
private writeJsonLog;
|
|
24
|
-
private
|
|
25
|
+
private writeSessionXml;
|
|
25
26
|
private logError;
|
|
26
27
|
private getDailyFolder;
|
|
27
|
-
private
|
|
28
|
+
private buildSessionXml;
|
|
28
29
|
private parseArguments;
|
|
29
30
|
private appendCdata;
|
|
30
31
|
private appendArguments;
|
|
32
|
+
private appendToolCalls;
|
|
31
33
|
private appendRawArguments;
|
|
32
34
|
private sanitizeAttribute;
|
|
33
35
|
private cleanXmlString;
|
package/dist/index.d.ts
CHANGED
|
@@ -15,19 +15,21 @@ declare function generateRandomDigits(length: number): string;
|
|
|
15
15
|
declare class LoggingPlugin implements LLMBridge.Plugin<void, string, void, void> {
|
|
16
16
|
private options;
|
|
17
17
|
private logger;
|
|
18
|
+
private runSessions;
|
|
18
19
|
constructor(options: LoggingPluginOptions);
|
|
19
20
|
private log;
|
|
20
21
|
wrapRun(next: () => Promise<LLMBridge.Response>, context: LLMBridge.PluginCompletionContext): Promise<LLMBridge.Response>;
|
|
21
|
-
wrapExec(next: (params: any) => Promise<any>, params: any,
|
|
22
|
+
wrapExec(next: (params: any) => Promise<any>, params: any, context: LLMBridge.PluginCompletionContext): Promise<any>;
|
|
22
23
|
wrapToolExec(next: (tool: LLMBridge.Tool, counter: number, input: any) => Promise<any>, tool: LLMBridge.Tool, counter: number, input: any, context: LLMBridge.PluginCompletionContext): Promise<any>;
|
|
23
24
|
private writeJsonLog;
|
|
24
|
-
private
|
|
25
|
+
private writeSessionXml;
|
|
25
26
|
private logError;
|
|
26
27
|
private getDailyFolder;
|
|
27
|
-
private
|
|
28
|
+
private buildSessionXml;
|
|
28
29
|
private parseArguments;
|
|
29
30
|
private appendCdata;
|
|
30
31
|
private appendArguments;
|
|
32
|
+
private appendToolCalls;
|
|
31
33
|
private appendRawArguments;
|
|
32
34
|
private sanitizeAttribute;
|
|
33
35
|
private cleanXmlString;
|
package/dist/index.js
CHANGED
|
@@ -46,6 +46,7 @@ function generateRandomDigits(length) {
|
|
|
46
46
|
}
|
|
47
47
|
var LoggingPlugin = class {
|
|
48
48
|
constructor(options) {
|
|
49
|
+
this.runSessions = /* @__PURE__ */ new Map();
|
|
49
50
|
this.options = options;
|
|
50
51
|
this.logger = options.logger;
|
|
51
52
|
}
|
|
@@ -60,25 +61,55 @@ var LoggingPlugin = class {
|
|
|
60
61
|
}
|
|
61
62
|
async wrapRun(next, context) {
|
|
62
63
|
this.log(`run ${context.model}`);
|
|
63
|
-
const
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
64
|
+
const session = {
|
|
65
|
+
startTime: (0, import_moment.default)(),
|
|
66
|
+
requestId: generateRandomDigits(4),
|
|
67
|
+
model: context.model,
|
|
68
|
+
turns: []
|
|
69
|
+
};
|
|
70
|
+
this.runSessions.set(context.options, session);
|
|
71
|
+
try {
|
|
72
|
+
const response = await next();
|
|
73
|
+
const lastResponsePath = import_node_path.default.join(this.options.folder, "last_response.json");
|
|
74
|
+
import_node_fs.default.writeFileSync(lastResponsePath, JSON.stringify(response, null, 2));
|
|
75
|
+
this.writeSessionXml(session);
|
|
76
|
+
return response;
|
|
77
|
+
} catch (error) {
|
|
78
|
+
this.writeSessionXml(session);
|
|
79
|
+
throw error;
|
|
80
|
+
} finally {
|
|
81
|
+
this.runSessions.delete(context.options);
|
|
82
|
+
}
|
|
67
83
|
}
|
|
68
|
-
async wrapExec(next, params,
|
|
69
|
-
const
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
|
|
84
|
+
async wrapExec(next, params, context) {
|
|
85
|
+
const session = this.runSessions.get(context.options);
|
|
86
|
+
const turn = { request: params, response: void 0, toolExecutions: [] };
|
|
87
|
+
const logTime = session ? session.startTime : (0, import_moment.default)();
|
|
88
|
+
const turnNumber = session ? session.turns.length + 1 : 0;
|
|
89
|
+
const logId = session ? `${session.requestId}.t${turnNumber}` : generateRandomDigits(4);
|
|
90
|
+
this.writeJsonLog(logTime, logId, "request", params);
|
|
91
|
+
if (session) {
|
|
92
|
+
session.turns.push(turn);
|
|
93
|
+
this.writeSessionXml(session);
|
|
94
|
+
}
|
|
73
95
|
const response = await next(params);
|
|
74
|
-
this.writeJsonLog(
|
|
75
|
-
|
|
96
|
+
this.writeJsonLog(logTime, logId, "response", response);
|
|
97
|
+
if (session) {
|
|
98
|
+
turn.response = response;
|
|
99
|
+
this.writeSessionXml(session);
|
|
100
|
+
}
|
|
76
101
|
return response;
|
|
77
102
|
}
|
|
78
103
|
async wrapToolExec(next, tool, counter, input, context) {
|
|
79
104
|
this.log(`run (${counter + 1}/${context.options.tools?.usesLimit}) tool ${tool.name} ${JSON.stringify(input)}`);
|
|
80
105
|
const result = await next(tool, counter, input);
|
|
81
106
|
this.log(`tool response ${JSON.stringify(result)}`);
|
|
107
|
+
const session = this.runSessions.get(context.options);
|
|
108
|
+
if (session && session.turns.length > 0) {
|
|
109
|
+
const lastTurn = session.turns[session.turns.length - 1];
|
|
110
|
+
lastTurn.toolExecutions.push({ toolName: tool.name, counter, input, result });
|
|
111
|
+
this.writeSessionXml(session);
|
|
112
|
+
}
|
|
82
113
|
return result;
|
|
83
114
|
}
|
|
84
115
|
writeJsonLog(date, requestId, type, data) {
|
|
@@ -87,16 +118,16 @@ var LoggingPlugin = class {
|
|
|
87
118
|
const filePath = import_node_path.default.join(dailyDir, fileName);
|
|
88
119
|
import_node_fs.default.writeFileSync(filePath, JSON.stringify(data, null, 2));
|
|
89
120
|
}
|
|
90
|
-
|
|
121
|
+
writeSessionXml(session) {
|
|
91
122
|
try {
|
|
92
|
-
const { dailyDir, timeString } = this.getDailyFolder(
|
|
93
|
-
const xmlFileName = `${timeString}_${requestId}.xml`;
|
|
123
|
+
const { dailyDir, timeString } = this.getDailyFolder(session.startTime);
|
|
124
|
+
const xmlFileName = `${timeString}_${session.requestId}.session.xml`;
|
|
94
125
|
const xmlPath = import_node_path.default.join(dailyDir, xmlFileName);
|
|
95
|
-
const xml = this.
|
|
126
|
+
const xml = this.buildSessionXml(session);
|
|
96
127
|
import_node_fs.default.writeFileSync(xmlPath, xml);
|
|
97
128
|
} catch (error) {
|
|
98
129
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
99
|
-
this.logError(`[LLM] Error saving XML log: ${errorMessage}`, error);
|
|
130
|
+
this.logError(`[LLM] Error saving session XML log: ${errorMessage}`, error);
|
|
100
131
|
}
|
|
101
132
|
}
|
|
102
133
|
logError(message, error) {
|
|
@@ -120,81 +151,69 @@ ${error.stack}` : "";
|
|
|
120
151
|
}
|
|
121
152
|
return { dailyDir, timeString };
|
|
122
153
|
}
|
|
123
|
-
|
|
124
|
-
const root = (0, import_xmlbuilder2.create)({ version: "1.0", encoding: "UTF-8" }).ele("
|
|
154
|
+
buildSessionXml(session) {
|
|
155
|
+
const root = (0, import_xmlbuilder2.create)({ version: "1.0", encoding: "UTF-8" }).ele("session", { model: this.sanitizeAttribute(session.model) });
|
|
125
156
|
let toolsUsed = false;
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
messageElem.att("tool_call_id", this.sanitizeAttribute(message.tool_call_id));
|
|
135
|
-
}
|
|
136
|
-
const content = message.content;
|
|
137
|
-
if (typeof content === "string") {
|
|
138
|
-
this.appendCdata(messageElem, content);
|
|
139
|
-
} else if (Array.isArray(content)) {
|
|
140
|
-
const textParts = content.filter((part) => part && typeof part === "object" && part.type === "text").map((part) => part.text ?? "").filter((text) => text.length > 0);
|
|
141
|
-
if (textParts.length > 0) {
|
|
142
|
-
this.appendCdata(messageElem, textParts.join("\n"));
|
|
157
|
+
for (let i = 0; i < session.turns.length; i++) {
|
|
158
|
+
const turn = session.turns[i];
|
|
159
|
+
const turnElem = root.ele("turn", { number: String(i + 1) });
|
|
160
|
+
const requestElem = turnElem.ele("request");
|
|
161
|
+
const messages = Array.isArray(turn.request?.messages) ? turn.request.messages : [];
|
|
162
|
+
for (const message of messages) {
|
|
163
|
+
if (!message || typeof message !== "object") {
|
|
164
|
+
continue;
|
|
143
165
|
}
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
const
|
|
153
|
-
if (
|
|
154
|
-
|
|
155
|
-
}
|
|
156
|
-
const functionData = toolCall.function ?? {};
|
|
157
|
-
if (functionData.name) {
|
|
158
|
-
toolElem.att("function_name", this.sanitizeAttribute(functionData.name));
|
|
159
|
-
}
|
|
160
|
-
const args = this.parseArguments(functionData.arguments);
|
|
161
|
-
if (args && typeof args === "object") {
|
|
162
|
-
this.appendArguments(toolElem, args);
|
|
163
|
-
} else if (functionData.arguments !== void 0) {
|
|
164
|
-
this.appendRawArguments(toolElem, functionData.arguments);
|
|
166
|
+
const messageElem = requestElem.ele("message", { role: this.sanitizeAttribute(message.role) });
|
|
167
|
+
if (message.role === "tool" && message.tool_call_id !== void 0) {
|
|
168
|
+
messageElem.att("tool_call_id", this.sanitizeAttribute(message.tool_call_id));
|
|
169
|
+
}
|
|
170
|
+
const content = message.content;
|
|
171
|
+
if (typeof content === "string") {
|
|
172
|
+
this.appendCdata(messageElem, content);
|
|
173
|
+
} else if (Array.isArray(content)) {
|
|
174
|
+
const textParts = content.filter((part) => part && typeof part === "object" && part.type === "text").map((part) => part.text ?? "").filter((text) => text.length > 0);
|
|
175
|
+
if (textParts.length > 0) {
|
|
176
|
+
this.appendCdata(messageElem, textParts.join("\n"));
|
|
165
177
|
}
|
|
166
178
|
}
|
|
179
|
+
if (Array.isArray(message.tool_calls) && message.tool_calls.length > 0) {
|
|
180
|
+
toolsUsed = true;
|
|
181
|
+
this.appendToolCalls(messageElem, message.tool_calls);
|
|
182
|
+
}
|
|
167
183
|
}
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
184
|
+
if (turn.response) {
|
|
185
|
+
const responseElem = turnElem.ele("response");
|
|
186
|
+
const responseMessageElem = responseElem.ele("message", { role: "assistant" });
|
|
187
|
+
const responseMessage = turn.response?.choices?.[0]?.message;
|
|
188
|
+
const responseContent = responseMessage?.content;
|
|
189
|
+
if (typeof responseContent === "string") {
|
|
190
|
+
this.appendCdata(responseMessageElem, responseContent);
|
|
191
|
+
}
|
|
192
|
+
const responseToolCalls = responseMessage?.tool_calls;
|
|
193
|
+
if (Array.isArray(responseToolCalls) && responseToolCalls.length > 0) {
|
|
194
|
+
toolsUsed = true;
|
|
195
|
+
this.appendToolCalls(responseMessageElem, responseToolCalls);
|
|
196
|
+
}
|
|
176
197
|
}
|
|
177
|
-
|
|
178
|
-
if (Array.isArray(responseToolCalls) && responseToolCalls.length > 0) {
|
|
198
|
+
if (turn.toolExecutions.length > 0) {
|
|
179
199
|
toolsUsed = true;
|
|
180
|
-
const
|
|
181
|
-
for (const
|
|
182
|
-
const
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
this.appendArguments(toolElem, args);
|
|
195
|
-
} else if (functionData?.arguments !== void 0) {
|
|
196
|
-
this.appendRawArguments(toolElem, functionData.arguments);
|
|
200
|
+
const toolExecsElem = turnElem.ele("tool_executions");
|
|
201
|
+
for (const exec of turn.toolExecutions) {
|
|
202
|
+
const execElem = toolExecsElem.ele("tool_execution", {
|
|
203
|
+
name: this.sanitizeAttribute(exec.toolName),
|
|
204
|
+
counter: String(exec.counter)
|
|
205
|
+
});
|
|
206
|
+
const inputElem = execElem.ele("input");
|
|
207
|
+
if (exec.input && typeof exec.input === "object" && !Array.isArray(exec.input)) {
|
|
208
|
+
for (const [key, value] of Object.entries(exec.input)) {
|
|
209
|
+
const argElem = inputElem.ele("arg", { name: this.sanitizeAttribute(key) });
|
|
210
|
+
this.appendCdata(argElem, value);
|
|
211
|
+
}
|
|
212
|
+
} else {
|
|
213
|
+
this.appendCdata(inputElem, typeof exec.input === "object" ? JSON.stringify(exec.input) : exec.input);
|
|
197
214
|
}
|
|
215
|
+
const outputElem = execElem.ele("output");
|
|
216
|
+
this.appendCdata(outputElem, typeof exec.result === "object" ? JSON.stringify(exec.result) : exec.result);
|
|
198
217
|
}
|
|
199
218
|
}
|
|
200
219
|
}
|
|
@@ -239,6 +258,30 @@ ${error.stack}` : "";
|
|
|
239
258
|
this.appendCdata(argElem, value);
|
|
240
259
|
}
|
|
241
260
|
}
|
|
261
|
+
appendToolCalls(parentElem, toolCalls) {
|
|
262
|
+
const toolCallsElem = parentElem.ele("tool_calls");
|
|
263
|
+
for (const toolCall of toolCalls) {
|
|
264
|
+
if (!toolCall || typeof toolCall !== "object") {
|
|
265
|
+
continue;
|
|
266
|
+
}
|
|
267
|
+
const functionData = toolCall.function ?? {};
|
|
268
|
+
const functionName = functionData.name;
|
|
269
|
+
if (!functionName || functionName === "null") {
|
|
270
|
+
continue;
|
|
271
|
+
}
|
|
272
|
+
const toolElem = toolCallsElem.ele("tool_call");
|
|
273
|
+
if (toolCall.id) {
|
|
274
|
+
toolElem.att("id", this.sanitizeAttribute(toolCall.id));
|
|
275
|
+
}
|
|
276
|
+
toolElem.att("function_name", this.sanitizeAttribute(functionName));
|
|
277
|
+
const args = this.parseArguments(functionData.arguments);
|
|
278
|
+
if (args && typeof args === "object") {
|
|
279
|
+
this.appendArguments(toolElem, args);
|
|
280
|
+
} else if (functionData.arguments !== void 0) {
|
|
281
|
+
this.appendRawArguments(toolElem, functionData.arguments);
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
242
285
|
appendRawArguments(toolElem, argumentsValue) {
|
|
243
286
|
const argsElem = toolElem.ele("arguments");
|
|
244
287
|
this.appendCdata(argsElem, argumentsValue);
|
package/dist/index.mjs
CHANGED
|
@@ -9,6 +9,7 @@ function generateRandomDigits(length) {
|
|
|
9
9
|
}
|
|
10
10
|
var LoggingPlugin = class {
|
|
11
11
|
constructor(options) {
|
|
12
|
+
this.runSessions = /* @__PURE__ */ new Map();
|
|
12
13
|
this.options = options;
|
|
13
14
|
this.logger = options.logger;
|
|
14
15
|
}
|
|
@@ -23,25 +24,55 @@ var LoggingPlugin = class {
|
|
|
23
24
|
}
|
|
24
25
|
async wrapRun(next, context) {
|
|
25
26
|
this.log(`run ${context.model}`);
|
|
26
|
-
const
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
27
|
+
const session = {
|
|
28
|
+
startTime: moment(),
|
|
29
|
+
requestId: generateRandomDigits(4),
|
|
30
|
+
model: context.model,
|
|
31
|
+
turns: []
|
|
32
|
+
};
|
|
33
|
+
this.runSessions.set(context.options, session);
|
|
34
|
+
try {
|
|
35
|
+
const response = await next();
|
|
36
|
+
const lastResponsePath = path.join(this.options.folder, "last_response.json");
|
|
37
|
+
fs.writeFileSync(lastResponsePath, JSON.stringify(response, null, 2));
|
|
38
|
+
this.writeSessionXml(session);
|
|
39
|
+
return response;
|
|
40
|
+
} catch (error) {
|
|
41
|
+
this.writeSessionXml(session);
|
|
42
|
+
throw error;
|
|
43
|
+
} finally {
|
|
44
|
+
this.runSessions.delete(context.options);
|
|
45
|
+
}
|
|
30
46
|
}
|
|
31
|
-
async wrapExec(next, params,
|
|
32
|
-
const
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
47
|
+
async wrapExec(next, params, context) {
|
|
48
|
+
const session = this.runSessions.get(context.options);
|
|
49
|
+
const turn = { request: params, response: void 0, toolExecutions: [] };
|
|
50
|
+
const logTime = session ? session.startTime : moment();
|
|
51
|
+
const turnNumber = session ? session.turns.length + 1 : 0;
|
|
52
|
+
const logId = session ? `${session.requestId}.t${turnNumber}` : generateRandomDigits(4);
|
|
53
|
+
this.writeJsonLog(logTime, logId, "request", params);
|
|
54
|
+
if (session) {
|
|
55
|
+
session.turns.push(turn);
|
|
56
|
+
this.writeSessionXml(session);
|
|
57
|
+
}
|
|
36
58
|
const response = await next(params);
|
|
37
|
-
this.writeJsonLog(
|
|
38
|
-
|
|
59
|
+
this.writeJsonLog(logTime, logId, "response", response);
|
|
60
|
+
if (session) {
|
|
61
|
+
turn.response = response;
|
|
62
|
+
this.writeSessionXml(session);
|
|
63
|
+
}
|
|
39
64
|
return response;
|
|
40
65
|
}
|
|
41
66
|
async wrapToolExec(next, tool, counter, input, context) {
|
|
42
67
|
this.log(`run (${counter + 1}/${context.options.tools?.usesLimit}) tool ${tool.name} ${JSON.stringify(input)}`);
|
|
43
68
|
const result = await next(tool, counter, input);
|
|
44
69
|
this.log(`tool response ${JSON.stringify(result)}`);
|
|
70
|
+
const session = this.runSessions.get(context.options);
|
|
71
|
+
if (session && session.turns.length > 0) {
|
|
72
|
+
const lastTurn = session.turns[session.turns.length - 1];
|
|
73
|
+
lastTurn.toolExecutions.push({ toolName: tool.name, counter, input, result });
|
|
74
|
+
this.writeSessionXml(session);
|
|
75
|
+
}
|
|
45
76
|
return result;
|
|
46
77
|
}
|
|
47
78
|
writeJsonLog(date, requestId, type, data) {
|
|
@@ -50,16 +81,16 @@ var LoggingPlugin = class {
|
|
|
50
81
|
const filePath = path.join(dailyDir, fileName);
|
|
51
82
|
fs.writeFileSync(filePath, JSON.stringify(data, null, 2));
|
|
52
83
|
}
|
|
53
|
-
|
|
84
|
+
writeSessionXml(session) {
|
|
54
85
|
try {
|
|
55
|
-
const { dailyDir, timeString } = this.getDailyFolder(
|
|
56
|
-
const xmlFileName = `${timeString}_${requestId}.xml`;
|
|
86
|
+
const { dailyDir, timeString } = this.getDailyFolder(session.startTime);
|
|
87
|
+
const xmlFileName = `${timeString}_${session.requestId}.session.xml`;
|
|
57
88
|
const xmlPath = path.join(dailyDir, xmlFileName);
|
|
58
|
-
const xml = this.
|
|
89
|
+
const xml = this.buildSessionXml(session);
|
|
59
90
|
fs.writeFileSync(xmlPath, xml);
|
|
60
91
|
} catch (error) {
|
|
61
92
|
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
62
|
-
this.logError(`[LLM] Error saving XML log: ${errorMessage}`, error);
|
|
93
|
+
this.logError(`[LLM] Error saving session XML log: ${errorMessage}`, error);
|
|
63
94
|
}
|
|
64
95
|
}
|
|
65
96
|
logError(message, error) {
|
|
@@ -83,81 +114,69 @@ ${error.stack}` : "";
|
|
|
83
114
|
}
|
|
84
115
|
return { dailyDir, timeString };
|
|
85
116
|
}
|
|
86
|
-
|
|
87
|
-
const root = create({ version: "1.0", encoding: "UTF-8" }).ele("
|
|
117
|
+
buildSessionXml(session) {
|
|
118
|
+
const root = create({ version: "1.0", encoding: "UTF-8" }).ele("session", { model: this.sanitizeAttribute(session.model) });
|
|
88
119
|
let toolsUsed = false;
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
messageElem.att("tool_call_id", this.sanitizeAttribute(message.tool_call_id));
|
|
98
|
-
}
|
|
99
|
-
const content = message.content;
|
|
100
|
-
if (typeof content === "string") {
|
|
101
|
-
this.appendCdata(messageElem, content);
|
|
102
|
-
} else if (Array.isArray(content)) {
|
|
103
|
-
const textParts = content.filter((part) => part && typeof part === "object" && part.type === "text").map((part) => part.text ?? "").filter((text) => text.length > 0);
|
|
104
|
-
if (textParts.length > 0) {
|
|
105
|
-
this.appendCdata(messageElem, textParts.join("\n"));
|
|
120
|
+
for (let i = 0; i < session.turns.length; i++) {
|
|
121
|
+
const turn = session.turns[i];
|
|
122
|
+
const turnElem = root.ele("turn", { number: String(i + 1) });
|
|
123
|
+
const requestElem = turnElem.ele("request");
|
|
124
|
+
const messages = Array.isArray(turn.request?.messages) ? turn.request.messages : [];
|
|
125
|
+
for (const message of messages) {
|
|
126
|
+
if (!message || typeof message !== "object") {
|
|
127
|
+
continue;
|
|
106
128
|
}
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
const
|
|
116
|
-
if (
|
|
117
|
-
|
|
118
|
-
}
|
|
119
|
-
const functionData = toolCall.function ?? {};
|
|
120
|
-
if (functionData.name) {
|
|
121
|
-
toolElem.att("function_name", this.sanitizeAttribute(functionData.name));
|
|
122
|
-
}
|
|
123
|
-
const args = this.parseArguments(functionData.arguments);
|
|
124
|
-
if (args && typeof args === "object") {
|
|
125
|
-
this.appendArguments(toolElem, args);
|
|
126
|
-
} else if (functionData.arguments !== void 0) {
|
|
127
|
-
this.appendRawArguments(toolElem, functionData.arguments);
|
|
129
|
+
const messageElem = requestElem.ele("message", { role: this.sanitizeAttribute(message.role) });
|
|
130
|
+
if (message.role === "tool" && message.tool_call_id !== void 0) {
|
|
131
|
+
messageElem.att("tool_call_id", this.sanitizeAttribute(message.tool_call_id));
|
|
132
|
+
}
|
|
133
|
+
const content = message.content;
|
|
134
|
+
if (typeof content === "string") {
|
|
135
|
+
this.appendCdata(messageElem, content);
|
|
136
|
+
} else if (Array.isArray(content)) {
|
|
137
|
+
const textParts = content.filter((part) => part && typeof part === "object" && part.type === "text").map((part) => part.text ?? "").filter((text) => text.length > 0);
|
|
138
|
+
if (textParts.length > 0) {
|
|
139
|
+
this.appendCdata(messageElem, textParts.join("\n"));
|
|
128
140
|
}
|
|
129
141
|
}
|
|
142
|
+
if (Array.isArray(message.tool_calls) && message.tool_calls.length > 0) {
|
|
143
|
+
toolsUsed = true;
|
|
144
|
+
this.appendToolCalls(messageElem, message.tool_calls);
|
|
145
|
+
}
|
|
130
146
|
}
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
147
|
+
if (turn.response) {
|
|
148
|
+
const responseElem = turnElem.ele("response");
|
|
149
|
+
const responseMessageElem = responseElem.ele("message", { role: "assistant" });
|
|
150
|
+
const responseMessage = turn.response?.choices?.[0]?.message;
|
|
151
|
+
const responseContent = responseMessage?.content;
|
|
152
|
+
if (typeof responseContent === "string") {
|
|
153
|
+
this.appendCdata(responseMessageElem, responseContent);
|
|
154
|
+
}
|
|
155
|
+
const responseToolCalls = responseMessage?.tool_calls;
|
|
156
|
+
if (Array.isArray(responseToolCalls) && responseToolCalls.length > 0) {
|
|
157
|
+
toolsUsed = true;
|
|
158
|
+
this.appendToolCalls(responseMessageElem, responseToolCalls);
|
|
159
|
+
}
|
|
139
160
|
}
|
|
140
|
-
|
|
141
|
-
if (Array.isArray(responseToolCalls) && responseToolCalls.length > 0) {
|
|
161
|
+
if (turn.toolExecutions.length > 0) {
|
|
142
162
|
toolsUsed = true;
|
|
143
|
-
const
|
|
144
|
-
for (const
|
|
145
|
-
const
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
this.appendArguments(toolElem, args);
|
|
158
|
-
} else if (functionData?.arguments !== void 0) {
|
|
159
|
-
this.appendRawArguments(toolElem, functionData.arguments);
|
|
163
|
+
const toolExecsElem = turnElem.ele("tool_executions");
|
|
164
|
+
for (const exec of turn.toolExecutions) {
|
|
165
|
+
const execElem = toolExecsElem.ele("tool_execution", {
|
|
166
|
+
name: this.sanitizeAttribute(exec.toolName),
|
|
167
|
+
counter: String(exec.counter)
|
|
168
|
+
});
|
|
169
|
+
const inputElem = execElem.ele("input");
|
|
170
|
+
if (exec.input && typeof exec.input === "object" && !Array.isArray(exec.input)) {
|
|
171
|
+
for (const [key, value] of Object.entries(exec.input)) {
|
|
172
|
+
const argElem = inputElem.ele("arg", { name: this.sanitizeAttribute(key) });
|
|
173
|
+
this.appendCdata(argElem, value);
|
|
174
|
+
}
|
|
175
|
+
} else {
|
|
176
|
+
this.appendCdata(inputElem, typeof exec.input === "object" ? JSON.stringify(exec.input) : exec.input);
|
|
160
177
|
}
|
|
178
|
+
const outputElem = execElem.ele("output");
|
|
179
|
+
this.appendCdata(outputElem, typeof exec.result === "object" ? JSON.stringify(exec.result) : exec.result);
|
|
161
180
|
}
|
|
162
181
|
}
|
|
163
182
|
}
|
|
@@ -202,6 +221,30 @@ ${error.stack}` : "";
|
|
|
202
221
|
this.appendCdata(argElem, value);
|
|
203
222
|
}
|
|
204
223
|
}
|
|
224
|
+
appendToolCalls(parentElem, toolCalls) {
|
|
225
|
+
const toolCallsElem = parentElem.ele("tool_calls");
|
|
226
|
+
for (const toolCall of toolCalls) {
|
|
227
|
+
if (!toolCall || typeof toolCall !== "object") {
|
|
228
|
+
continue;
|
|
229
|
+
}
|
|
230
|
+
const functionData = toolCall.function ?? {};
|
|
231
|
+
const functionName = functionData.name;
|
|
232
|
+
if (!functionName || functionName === "null") {
|
|
233
|
+
continue;
|
|
234
|
+
}
|
|
235
|
+
const toolElem = toolCallsElem.ele("tool_call");
|
|
236
|
+
if (toolCall.id) {
|
|
237
|
+
toolElem.att("id", this.sanitizeAttribute(toolCall.id));
|
|
238
|
+
}
|
|
239
|
+
toolElem.att("function_name", this.sanitizeAttribute(functionName));
|
|
240
|
+
const args = this.parseArguments(functionData.arguments);
|
|
241
|
+
if (args && typeof args === "object") {
|
|
242
|
+
this.appendArguments(toolElem, args);
|
|
243
|
+
} else if (functionData.arguments !== void 0) {
|
|
244
|
+
this.appendRawArguments(toolElem, functionData.arguments);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
205
248
|
appendRawArguments(toolElem, argumentsValue) {
|
|
206
249
|
const argsElem = toolElem.ele("arguments");
|
|
207
250
|
this.appendCdata(argsElem, argumentsValue);
|