Compare commits

...
1 Commits
Author SHA1 Message Date
ztimson d29c0ca389 Fixed opanai early termination from tool calls
Publish Library / Build NPM Project (push) Successful in 55s
Publish Library / Tag Version (push) Successful in 9s
2026-09-18 02:15:02 -04:00
2 changed files with 9 additions and 3 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "@ztimson/ai-utils", "name": "@ztimson/ai-utils",
"version": "1.6.8", "version": "1.6.9",
"description": "AI Utility library", "description": "AI Utility library",
"author": "Zak Timson", "author": "Zak Timson",
"license": "MIT", "license": "MIT",
+8 -2
View File
@@ -98,11 +98,12 @@ export class OpenAi extends LLMProvider {
throw err; throw err;
}); });
let usage: any, msg: any = {content: '', tool_calls: []}; let usage: any, finishReason: string | undefined, msg: any = {content: '', tool_calls: []};
if(options.stream) { if(options.stream) {
for await (const chunk of resp) { for await (const chunk of resp) {
if(controller.signal.aborted) break; if(controller.signal.aborted) break;
if(chunk.usage) usage = chunk.usage; if(chunk.usage) usage = chunk.usage;
if(chunk.choices[0]?.finish_reason) finishReason = chunk.choices[0].finish_reason;
if(chunk.choices[0]?.delta?.content) { if(chunk.choices[0]?.delta?.content) {
msg.content += chunk.choices[0].delta.content; msg.content += chunk.choices[0].delta.content;
options.stream({text: chunk.choices[0].delta.content}); options.stream({text: chunk.choices[0].delta.content});
@@ -126,11 +127,16 @@ export class OpenAi extends LLMProvider {
} }
} else { } else {
usage = resp.usage; usage = resp.usage;
finishReason = resp.choices[0].finish_reason;
msg = resp.choices[0].message; msg = resp.choices[0].message;
} }
const duration = Date.now() - callStart; const duration = Date.now() - callStart;
const tps = usage?.completion_tokens && duration > 0 ? usage.completion_tokens / (duration / 1000) : 0; const tps = usage?.completion_tokens && duration > 0 ? usage.completion_tokens / (duration / 1000) : 0;
if(finishReason === 'length') {
console.warn('[OpenAi] Response truncated: max_completion_tokens reached before finish_reason=stop');
}
const toolCalls = msg.tool_calls || []; const toolCalls = msg.tool_calls || [];
if(toolCalls.length && !controller.signal.aborted) { if(toolCalls.length && !controller.signal.aborted) {
if(msg.content?.trim()) history.push({role: 'assistant', content: msg.content.trim(), timestamp: Date.now(), duration, tps}); if(msg.content?.trim()) history.push({role: 'assistant', content: msg.content.trim(), timestamp: Date.now(), duration, tps});
@@ -147,7 +153,7 @@ export class OpenAi extends LLMProvider {
if(!tool) { entry.error = 'Tool not found'; return; } if(!tool) { entry.error = 'Tool not found'; return; }
try { try {
const toolStream = options.stream && ((chunk: any) => { const toolStream = options.stream && ((chunk: any) => {
if(chunk.done) { terminal = true; return; } if(chunk.done) return;
options.stream!(chunk); options.stream!(chunk);
}); });
const result = await tool.fn(entry.args, toolStream, this.ai, tc.id); const result = await tool.fn(entry.args, toolStream, this.ai, tc.id);