Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 85c01d3ef1 | |||
| 5826573d5c |
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@ztimson/ai-utils",
|
"name": "@ztimson/ai-utils",
|
||||||
"version": "1.6.0",
|
"version": "1.6.2",
|
||||||
"description": "AI Utility library",
|
"description": "AI Utility library",
|
||||||
"author": "Zak Timson",
|
"author": "Zak Timson",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
|||||||
28
src/llm.ts
28
src/llm.ts
@@ -50,6 +50,8 @@ export type LLMMessage = {
|
|||||||
role: 'assistant' | 'system' | 'user';
|
role: 'assistant' | 'system' | 'user';
|
||||||
/** Message content */
|
/** Message content */
|
||||||
content: string | any;
|
content: string | any;
|
||||||
|
/** Files attached to request */
|
||||||
|
files?: LLMFile[];
|
||||||
/** Timestamp */
|
/** Timestamp */
|
||||||
timestamp?: number;
|
timestamp?: number;
|
||||||
/** Response duration in ms */
|
/** Response duration in ms */
|
||||||
@@ -241,10 +243,8 @@ class LLM {
|
|||||||
} else if(isText) {
|
} else if(isText) {
|
||||||
text = (await this.loadBuffer(file, true)).toString('utf-8');
|
text = (await this.loadBuffer(file, true)).toString('utf-8');
|
||||||
} else {
|
} else {
|
||||||
text = `Unsupported file type: ${ext || mime}`;
|
text = typeof file.content === 'string' ? file.content : `[Binary file, unable to extract: ${name}]`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cache result, skip re-extraction on future turns of the same conversation
|
|
||||||
file.content = text;
|
file.content = text;
|
||||||
file.extracted = true;
|
file.extracted = true;
|
||||||
delete file.path;
|
delete file.path;
|
||||||
@@ -411,7 +411,8 @@ ${a.system}`,
|
|||||||
let tools: AiTool[] = options.tools || this.ai.options.llm?.tools || [];
|
let tools: AiTool[] = options.tools || this.ai.options.llm?.tools || [];
|
||||||
const prompts: string[] = [];
|
const prompts: string[] = [];
|
||||||
let history = options.history || [];
|
let history = options.history || [];
|
||||||
if(message) history.push({role: 'user', content: message, timestamp: Date.now()});
|
const files = options.files || [];
|
||||||
|
if(message || files.length) history.push({role: 'user', content: message || '', timestamp: Date.now()});
|
||||||
|
|
||||||
// MCP
|
// MCP
|
||||||
const mcp = options.mcp || this.ai.options?.llm?.mcp;
|
const mcp = options.mcp || this.ai.options?.llm?.mcp;
|
||||||
@@ -482,14 +483,16 @@ Linked: ${makeUnique([...r.links, ...r.backlinks]).join(', ')}
|
|||||||
|
|
||||||
if(aborted) throw Object.assign(new Error('Aborted'), {name: 'AbortError'});
|
if(aborted) throw Object.assign(new Error('Aborted'), {name: 'AbortError'});
|
||||||
|
|
||||||
// Files
|
|
||||||
const files = options.files || [];
|
|
||||||
const lastMsg = history[history.length - 1];
|
const lastMsg = history[history.length - 1];
|
||||||
const originalContent = lastMsg?.content;
|
if(files.length && lastMsg?.role === 'user') lastMsg.files = files;
|
||||||
if(files.length && lastMsg?.role === 'user') {
|
const restores: {msg: LLMMessage, content: any}[] = [];
|
||||||
const {text, images} = await this.resolveFiles(files);
|
for(const msg of history) {
|
||||||
const merged = text ? `${originalContent}\n\n${text}` : originalContent;
|
if(msg.role !== 'user' || !msg.files?.length) continue;
|
||||||
lastMsg.content = images.length
|
const {text, images} = await this.resolveFiles(msg.files);
|
||||||
|
if(!text && !images.length) continue;
|
||||||
|
restores.push({msg, content: msg.content});
|
||||||
|
const merged = text ? [msg.content, text].filter(Boolean).join('\n\n') : msg.content;
|
||||||
|
msg.content = images.length
|
||||||
? [...images.map(i => ({type: 'image', mime: i.mime, data: i.data})), {type: 'text', text: merged}]
|
? [...images.map(i => ({type: 'image', mime: i.mime, data: i.data})), {type: 'text', text: merged}]
|
||||||
: merged;
|
: merged;
|
||||||
}
|
}
|
||||||
@@ -503,7 +506,8 @@ Linked: ${makeUnique([...r.links, ...r.backlinks]).join(', ')}
|
|||||||
request = this.models[m].ask('', {...options, tools, system: prompts.filter(Boolean).join('\n\n')});
|
request = this.models[m].ask('', {...options, tools, system: prompts.filter(Boolean).join('\n\n')});
|
||||||
let resp = await request;
|
let resp = await request;
|
||||||
|
|
||||||
if(files.length && lastMsg?.role === 'user') lastMsg.content = originalContent;
|
// Strip the file injection shim
|
||||||
|
restores.forEach(({msg, content}) => msg.content = content);
|
||||||
|
|
||||||
// Capture meta (duration / tps)
|
// Capture meta (duration / tps)
|
||||||
for(const h of history) {
|
for(const h of history) {
|
||||||
|
|||||||
Reference in New Issue
Block a user