Added tps + duration to AI history
Publish Library / Build NPM Project (push) Successful in 52s
Publish Library / Tag Version (push) Successful in 11s

This commit is contained in:
2026-08-04 09:26:57 -04:00
parent d53b1c6328
commit 62fbe73b22
4 changed files with 69 additions and 92 deletions
+18 -8
View File
@@ -21,13 +21,15 @@ export class OpenAi extends LLMProvider {
const h = history[i];
if(h.role === 'assistant' && h.tool_calls) {
const items: any[] = [];
if(h.content) items.push({role: 'assistant', content: h.content, timestamp: h.timestamp});
if(h.content) items.push({role: 'assistant', content: h.content, timestamp: h.timestamp, duration: h.duration, tps: h.tps});
items.push(...h.tool_calls.map((tc: any) => ({
role: 'tool',
id: tc.id,
name: tc.function.name,
args: JSONAttemptParse(tc.function.arguments, {}),
timestamp: h.timestamp
timestamp: h.timestamp,
duration: h.duration,
tps: h.tps
})));
history.splice(i, 1, ...items);
i += items.length - 1;
@@ -110,23 +112,27 @@ export class OpenAi extends LLMProvider {
};
}
let resp: any, terminal = false;
if(options.stream) requestParams.stream_options = {include_usage: true};
let resp: any, terminal = false, duration = 0, tps = 0;
do {
requestParams.messages = history.map(({timestamp, ...m}) => m);
const callStart = Date.now();
resp = await this.client.chat.completions.create(requestParams).catch(err => {
err.message += `\n\nMessages:\n${JSON.stringify(history, null, 2)}`;
throw err;
});
let usage: any;
if(options.stream) {
resp.choices = [{message: {role: 'assistant', content: '', tool_calls: [], timestamp: Date.now()}}];
for await (const chunk of resp) {
if(controller.signal.aborted) break;
if(chunk.choices[0].delta.content) {
if(chunk.usage) usage = chunk.usage;
if(chunk.choices[0]?.delta?.content) {
resp.choices[0].message.content += chunk.choices[0].delta.content;
options.stream({text: chunk.choices[0].delta.content});
}
if(chunk.choices[0].delta.tool_calls) {
if(chunk.choices[0]?.delta?.tool_calls) {
for(const deltaTC of chunk.choices[0].delta.tool_calls) {
const existing = resp.choices[0].message.tool_calls.find(tc => tc.index === deltaTC.index);
if(existing) {
@@ -151,19 +157,22 @@ export class OpenAi extends LLMProvider {
}
}
}
} else {
usage = resp.usage;
}
duration = Date.now() - callStart;
tps = usage?.completion_tokens && duration > 0 ? usage.completion_tokens / (duration / 1000) : 0;
if(resp.error) throw new Error(resp.error);
const toolCalls = resp.choices[0].message.tool_calls || [];
if(toolCalls.length && !controller.signal.aborted) {
history.push(resp.choices[0].message);
history.push({...resp.choices[0].message, duration, tps});
const results = await Promise.all(toolCalls.map(async (toolCall: any) => {
const tool = tools?.find(findByProp('name', toolCall.function.name));
if(options.stream) options.stream({tool: toolCall.function.name});
if(!tool) return {role: 'tool', tool_call_id: toolCall.id, content: '{"error": "Tool not found"}', timestamp: Date.now()};
try {
const args = JSONAttemptParse(toolCall.function.arguments, {});
// Wrap stream so a tool's `done` ends turn gracefully
const toolStream = options.stream && ((chunk: any) => {
if(chunk.done) { terminal = true; return; }
options.stream!(chunk);
@@ -181,8 +190,9 @@ export class OpenAi extends LLMProvider {
if(!terminal) {
const textContent = resp.choices[0].message.content || '';
history.push({role: 'assistant', content: textContent.trim(), timestamp: Date.now()});
history.push({role: 'assistant', content: textContent.trim(), timestamp: Date.now(), duration, tps});
}
history = this.toStandard(history);
if(options.history) options.history.splice(0, options.history.length, ...history.filter(h => h.role !== 'system'));
if(options.stream) options.stream({done: true});