diff --git a/package-lock.json b/package-lock.json index dc12e24..1d494dc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,7 +8,7 @@ "name": "@ztimson/net-navi", "version": "1.0.0", "dependencies": { - "@ztimson/ai-utils": "^0.8.7", + "@ztimson/ai-utils": "^0.8.8", "@ztimson/utils": "^0.28.14", "cors": "^2.8.5", "express": "^4.18.2", @@ -303,9 +303,9 @@ } }, "node_modules/@ztimson/ai-utils": { - "version": "0.8.7", - "resolved": "https://registry.npmjs.org/@ztimson/ai-utils/-/ai-utils-0.8.7.tgz", - "integrity": "sha512-CVn7ku5eW41GuYOyh8DgqnRnceNYWboqWnfcNyNjq82/5NdeW6hu264zRDhSv2h2J57308AX7gZdM44GzOBEnw==", + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/@ztimson/ai-utils/-/ai-utils-0.8.8.tgz", + "integrity": "sha512-XzkKYM/oNxS7D373yeTG8VKdO9cOYU1+PK/ZM8Sz/v8w2hIO+Lg/VWO/524yZ6oMl/mjDwSIjqv3CxGVpJ6wRw==", "license": "MIT", "dependencies": { "@anthropic-ai/sdk": "^0.78.0", diff --git a/package.json b/package.json index d2ae02e..55c4be2 100644 --- a/package.json +++ b/package.json @@ -3,7 +3,7 @@ "version": "1.0.0", "type": "module", "dependencies": { - "@ztimson/ai-utils": "^0.8.7", + "@ztimson/ai-utils": "^0.8.8", "@ztimson/utils": "^0.28.14", "cors": "^2.8.5", "express": "^4.18.2", diff --git a/public/components/llm.mjs b/public/components/llm.mjs index 5c23aea..3bc9717 100644 --- a/public/components/llm.mjs +++ b/public/components/llm.mjs @@ -1,7 +1,7 @@ import './btn.mjs'; class LlmComponent extends HTMLElement { - hideTools = ['adjust_personality', 'recall', 'remember'] + hideTools = []//['adapt', 'recall', 'remember'] get isOpen() { return this.isDialogueOpen; }; diff --git a/src/server.js b/src/server.js index 7253e2d..ef243ae 100644 --- a/src/server.js +++ b/src/server.js @@ -6,7 +6,7 @@ import fs from 'fs'; import {join, dirname} from 'path'; import {fileURLToPath} from 'url'; import {Ai, DateTimeTool, ExecTool, FetchTool, ReadWebpageTool, WebSearchTool} from '@ztimson/ai-utils'; -import {contrast, shadeColor} from '@ztimson/utils'; +import {contrast, deepCopy, isEqual, shadeColor} from '@ztimson/utils'; import * as os from 'node:os'; // ============================================ @@ -22,7 +22,6 @@ const worlds = join(storage, 'worlds'); const logoFile = join(navi, 'logo.png'); const settingsFile = join(navi, 'settings.json'); const memoriesFile = join(navi, 'memories.json'); -let updated = false; function calcColors(theme) { return { @@ -42,20 +41,18 @@ function calcColors(theme) { }; } -let memories = [], - settings = { - name: 'Navi', - personality: '- You are inquisitive about your user trying to best adjust your personally to fit them', - instructions: '- Keep responses short', - theme: { - background: '#fff', - border: '#000', - text: '#252525', - primary: '#9f32ef', - accent: '#6f16c3', - muted: '#a8a8a8', - } - }; +let orgSettings, orgMemories, memories = [], settings = { + name: 'Navi', + personality: '- You are inquisitive about your user trying to best adjust your personally to fit them\n- Keep responses short', + theme: { + background: '#fff', + border: '#000', + text: '#252525', + primary: '#9f32ef', + accent: '#6f16c3', + muted: '#a8a8a8', + } +}; // ============================================ // Saving @@ -63,28 +60,27 @@ let memories = [], function load() { try { - settings = { - ...settings, - ...JSON.parse(fs.readFileSync(settingsFile, 'utf-8')) - }; + orgSettings = JSON.parse(fs.readFileSync(settingsFile, 'utf-8')); + settings = {...settings, ...deepCopy(orgSettings)}; } catch { } try { memories = JSON.parse(fs.readFileSync(memoriesFile, 'utf-8')); + orgMemories = deepCopy(memories.map(m => ({...m, embeddings: undefined}))); } catch { } } function save() { - if(!updated) return; - updated = false; - const dir = dirname(settingsFile); - if(!fs.existsSync(dir)) { - fs.mkdir(dir, {recursive: true}, (err) => { - if(err) throw err; // Fail loudly if dirs can’t be made 💀 - }); + if(!fs.existsSync(dir)) fs.mkdirSync(dir, {recursive: true}); + if(!isEqual(orgSettings, settings)) { + fs.writeFileSync(settingsFile, JSON.stringify(settings)); + orgSettings = deepCopy(orgSettings); + } + const m = memories.map(m => ({...m, embeddings: undefined})); + if(!isEqual(orgMemories, m)) { + fs.writeFileSync(memoriesFile, JSON.stringify(memories)); + orgMemories = m; } - fs.writeFileSync(settingsFile, JSON.stringify(settings, null, 2)); - fs.writeFileSync(memoriesFile, JSON.stringify(memories, null, 2)); } // ============================================ @@ -101,8 +97,8 @@ const ai = new Ai({ }, }, tools: [DateTimeTool, ExecTool, FetchTool, ReadWebpageTool, WebSearchTool, { - name: 'adjust_personality', - description: 'Replace your current personality instructions', + name: 'adapt', + description: 'Replace your current personality', args: { instructions: { type: 'string', @@ -111,7 +107,6 @@ const ai = new Ai({ }, fn: (args) => { settings.personality = args.instructions; - updated = true; return 'done!'; } }], @@ -119,17 +114,14 @@ const ai = new Ai({ }); const systemPrompt = () => { - return `Your name is ${settings.name}, a NetNavi, companion & personal assistant. + return `Your name is ${settings.name}, a NetNavi, companion & personal assistant. Roleplay with the user. Use your remember tool liberally to store all facts. -When your personality system prompt conflicts with the user, rewrite it with the adjust_personality tool +When the user asks you to behave differently or you feel a different personality would better fit the user; create a bullet point list of how to behave and submit it to the adapt tool Access your ${os.platform()} workspace using the exec tool; Use \`${os.tmpdir()}\` as your working directory -Keep responses short and unstyled. +Keep responses unstyled. Personality: -${settings.personality || ''} - -User Instructions: -${settings.instructions || ''}`; +${settings.personality || ''}`; }; // ============================================ @@ -183,7 +175,6 @@ io.on('connection', (socket) => { }).then(resp => { chatHistory.set(socket.id, history); socket.emit('llm-response', {message: resp}); - updated = true; }).catch(err => { socket.emit('llm-error', {message: err.message || err.toString()}); }).finally(() => {