diff --git a/package.json b/package.json index 45f0bac..b2180a0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@ztimson/ai-utils", - "version": "0.1.18", + "version": "0.1.19", "description": "AI Utility library", "author": "Zak Timson", "license": "MIT", diff --git a/src/antrhopic.ts b/src/antrhopic.ts index e55e96d..c0ec2ec 100644 --- a/src/antrhopic.ts +++ b/src/antrhopic.ts @@ -39,13 +39,13 @@ export class Anthropic extends LLMProvider { if(history[i].role == 'tool') { const h: any = history[i]; history.splice(i, 1, - {role: 'assistant', content: [{type: 'tool_use', id: h.id, name: h.name, input: h.args}], timestamp: h.timestamp}, - {role: 'user', content: [{type: 'tool_result', tool_use_id: h.id, is_error: !!h.error, content: h.error || h.content}], timestamp: Date.now()} + {role: 'assistant', content: [{type: 'tool_use', id: h.id, name: h.name, input: h.args}]}, + {role: 'user', content: [{type: 'tool_result', tool_use_id: h.id, is_error: !!h.error, content: h.error || h.content}]} ) i++; } } - return history; + return history.map(({timestamp, ...h}) => h); } ask(message: string, options: LLMRequest = {}): AbortablePromise { @@ -107,7 +107,7 @@ export class Anthropic extends LLMProvider { loopMessages.push({role: 'assistant', content: resp.content, timestamp: Date.now()}); const toolCalls = resp.content.filter((c: any) => c.type === 'tool_use'); if(toolCalls.length && !controller.signal.aborted) { - history.push({role: 'assistant', content: resp.content, timestamp: Date.now()}); + history.push({role: 'assistant', content: resp.content}); const results = await Promise.all(toolCalls.map(async (toolCall: any) => { const tool = options.tools?.find(findByProp('name', toolCall.name)); if(!tool) return {tool_use_id: toolCall.id, is_error: true, content: 'Tool not found'}; @@ -118,9 +118,9 @@ export class Anthropic extends LLMProvider { return {type: 'tool_result', tool_use_id: toolCall.id, is_error: true, content: err?.message || err?.toString() || 'Unknown'}; } })); - const userMsg = {role: 'user', content: results, timestamp: Date.now()}; + const userMsg = {role: 'user', content: results}; history.push(userMsg); - loopMessages.push(userMsg); + loopMessages.push({...userMsg, timestamp: Date.now()}); requestParams.messages = history; } } while (!controller.signal.aborted && resp.content.some((c: any) => c.type === 'tool_use')); diff --git a/src/llm.ts b/src/llm.ts index cd1360f..06af876 100644 --- a/src/llm.ts +++ b/src/llm.ts @@ -12,7 +12,7 @@ export type LLMMessage = { /** Message content */ content: string | any; /** Timestamp */ - timestamp: number; + timestamp?: number; } | { /** Tool call */ role: 'tool'; @@ -27,7 +27,7 @@ export type LLMMessage = { /** Tool error */ error: undefined | string; /** Timestamp */ - timestamp: number; + timestamp?: number; } export type LLMOptions = { diff --git a/src/ollama.ts b/src/ollama.ts index f3e42df..6caeb2c 100644 --- a/src/ollama.ts +++ b/src/ollama.ts @@ -31,8 +31,9 @@ export class Ollama extends LLMProvider { private fromStandard(history: LLMMessage[]): any[] { return history.map((h: any) => { - if(h.role != 'tool') return h; - return {role: 'tool', tool_name: h.name, content: h.error || h.content, timestamp: h.timestamp} + const {timestamp, ...rest} = h; + if(h.role != 'tool') return rest; + return {role: 'tool', tool_name: h.name, content: h.error || h.content} }); } @@ -90,22 +91,21 @@ export class Ollama extends LLMProvider { } loopMessages.push({role: 'assistant', content: resp.message?.content, timestamp: Date.now()}); - if(resp.message?.tool_calls?.length && !controller.signal.aborted) { - history.push({...resp.message, timestamp: Date.now()}); + history.push(resp.message); const results = await Promise.all(resp.message.tool_calls.map(async (toolCall: any) => { const tool = (options.tools || this.ai.options.tools)?.find(findByProp('name', toolCall.function.name)); - if(!tool) return {role: 'tool', tool_name: toolCall.function.name, content: '{"error": "Tool not found"}', timestamp: Date.now()}; + if(!tool) return {role: 'tool', tool_name: toolCall.function.name, content: '{"error": "Tool not found"}'}; const args = typeof toolCall.function.arguments === 'string' ? JSONAttemptParse(toolCall.function.arguments, {}) : toolCall.function.arguments; try { const result = await tool.fn(args, this.ai); - return {role: 'tool', tool_name: toolCall.function.name, args, content: JSONSanitize(result), timestamp: Date.now()}; + return {role: 'tool', tool_name: toolCall.function.name, args, content: JSONSanitize(result)}; } catch (err: any) { - return {role: 'tool', tool_name: toolCall.function.name, args, content: JSONSanitize({error: err?.message || err?.toString() || 'Unknown'}), timestamp: Date.now()}; + return {role: 'tool', tool_name: toolCall.function.name, args, content: JSONSanitize({error: err?.message || err?.toString() || 'Unknown'})}; } })); history.push(...results); - loopMessages.push(...results); + loopMessages.push(...results.map(r => ({...r, timestamp: Date.now()}))); requestParams.messages = history; } } while (!controller.signal.aborted && resp.message?.tool_calls?.length); diff --git a/src/open-ai.ts b/src/open-ai.ts index 7e1b1a1..4862efc 100644 --- a/src/open-ai.ts +++ b/src/open-ai.ts @@ -47,16 +47,15 @@ export class OpenAi extends LLMProvider { content: null, tool_calls: [{ id: h.id, type: 'function', function: { name: h.name, arguments: JSON.stringify(h.args) } }], refusal: null, - annotations: [], - timestamp: h.timestamp + annotations: [] }, { role: 'tool', tool_call_id: h.id, - content: h.error || h.content, - timestamp: Date.now() + content: h.error || h.content }); } else { - result.push(h); + const {timestamp, ...rest} = h; + result.push(rest); } return result; }, [] as any[]); @@ -111,20 +110,20 @@ export class OpenAi extends LLMProvider { const toolCalls = resp.choices[0].message.tool_calls || []; if(toolCalls.length && !controller.signal.aborted) { - history.push({...resp.choices[0].message, timestamp: Date.now()}); + history.push(resp.choices[0].message); const results = await Promise.all(toolCalls.map(async (toolCall: any) => { const tool = options.tools?.find(findByProp('name', toolCall.function.name)); - if(!tool) return {role: 'tool', tool_call_id: toolCall.id, content: '{"error": "Tool not found"}', timestamp: Date.now()}; + if(!tool) return {role: 'tool', tool_call_id: toolCall.id, content: '{"error": "Tool not found"}'}; try { const args = JSONAttemptParse(toolCall.function.arguments, {}); const result = await tool.fn(args, this.ai); - return {role: 'tool', tool_call_id: toolCall.id, content: JSONSanitize(result), timestamp: Date.now()}; + return {role: 'tool', tool_call_id: toolCall.id, content: JSONSanitize(result)}; } catch (err: any) { - return {role: 'tool', tool_call_id: toolCall.id, content: JSONSanitize({error: err?.message || err?.toString() || 'Unknown'}), timestamp: Date.now()}; + return {role: 'tool', tool_call_id: toolCall.id, content: JSONSanitize({error: err?.message || err?.toString() || 'Unknown'})}; } })); history.push(...results); - loopMessages.push(...results); + loopMessages.push(...results.map(r => ({...r, timestamp: Date.now()}))); requestParams.messages = history; } } while (!controller.signal.aborted && resp.choices?.[0]?.message?.tool_calls?.length); @@ -134,7 +133,6 @@ export class OpenAi extends LLMProvider { if(options.stream) options.stream({done: true}); res(this.toStandard([...history, {role: 'assistant', content: combinedContent, timestamp: Date.now()}])); }); - return Object.assign(response, {abort: () => controller.abort()}); } }