From 5b47a57cd0c421617aef04301e1e39663297ee44 Mon Sep 17 00:00:00 2001 From: MiaowFISH Date: Sun, 5 Jan 2025 14:15:32 +0800 Subject: [PATCH] =?UTF-8?q?=E5=B0=86=E4=BB=A3=E7=A0=81=E7=A7=BB=E5=8A=A8?= =?UTF-8?q?=E5=88=B0core=EF=BC=8C=E6=B7=BB=E5=8A=A0=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E9=83=A8=E7=BD=B2=E6=B5=81=E7=A8=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/build.yml | 14 +++ .github/workflows/publish.yml | 12 ++ .gitignore | 1 + package.json | 97 ++++----------- .../core/jest.config.ts | 0 packages/core/package.json | 82 ++++++++++++ .../core/resources}/emojis.json | 0 {src => packages/core/src}/adapters/base.ts | 0 .../core/src}/adapters/cloudflare.ts | 0 {src => packages/core/src}/adapters/config.ts | 0 .../core/src}/adapters/creators/base.ts | 0 .../core/src}/adapters/creators/component.ts | 0 .../core/src}/adapters/creators/schema.ts | 0 {src => packages/core/src}/adapters/custom.ts | 0 {src => packages/core/src}/adapters/gemini.ts | 0 {src => packages/core/src}/adapters/index.ts | 0 {src => packages/core/src}/adapters/ollama.ts | 0 {src => packages/core/src}/adapters/openai.ts | 0 {src => packages/core/src}/bot.ts | 0 {src => packages/core/src}/commands/memory.ts | 0 .../core/src}/commands/sendQuene.ts | 0 {src => packages/core/src}/config.ts | 0 {src => packages/core/src}/database/index.ts | 0 {src => packages/core/src}/embeddings/base.ts | 0 .../core/src}/embeddings/config.ts | 0 .../core/src}/embeddings/custom.ts | 0 .../core/src}/embeddings/index.ts | 0 .../core/src}/embeddings/ollama.ts | 0 .../core/src}/embeddings/openai.ts | 0 .../core/src}/extensions/.gitkeep | 0 packages/core/src/extensions/README.md | 0 {src => packages/core/src}/extensions/base.ts | 0 .../core/src}/extensions/ext_command.ts | 0 .../core/src}/extensions/ext_memory.ts | 0 {src => packages/core/src}/index.ts | 0 .../core/src}/managers/cacheManager.ts | 0 .../core/src}/managers/emojiManager.ts | 0 .../core/src}/managers/queueManager.ts | 0 .../core/src}/models/ChatMessage.ts | 0 .../core/src}/services/imageViewer.ts | 0 .../core/src}/services/sendQueue.ts | 0 {src => packages/core/src}/utils/content.ts | 0 {src => packages/core/src}/utils/factory.ts | 0 {src => packages/core/src}/utils/http.ts | 0 .../core/src}/utils/imageUtils.ts | 0 {src => packages/core/src}/utils/index.ts | 0 {src => packages/core/src}/utils/prompt.ts | 0 {src => packages/core/src}/utils/string.ts | 0 {src => packages/core/src}/utils/toolkit.ts | 0 {src => packages/core/src}/utils/verifier.ts | 0 .../core/tests}/cacheManager.spec.ts | 0 {tests => packages/core/tests}/config.ts | 0 .../core/tests}/imageCache.spec.ts | 0 {tests => packages/core/tests}/index.spec.ts | 0 {tests => packages/core/tests}/regexp.spec.ts | 0 {tests => packages/core/tests}/schema.spec.ts | 0 .../core/tests}/vectorStore.spec.ts | 0 packages/core/tsconfig.json | 12 ++ packages/extension/README.md | 1 + packages/extension/src/base.ts | 51 ++++++++ packages/extension/src/decorators.ts | 24 ++++ packages/extension/src/index.ts | 15 +++ packages/extension/src/utils.ts | 38 ++++++ packages/extension/tsconfig.json | 11 ++ packages/memory/README.md | 44 +++++++ packages/memory/package.json | 7 +- packages/memory/src/config.ts | 2 +- packages/memory/src/database.ts | 39 ++++++ packages/memory/src/index.ts | 117 ++++++++++++------ packages/memory/src/model.ts | 58 +++++++++ packages/memory/src/vectorStore.ts | 72 ++++------- packages/webui/package.json | 7 +- packages/webui/src/index.ts | 1 + tsconfig.json | 23 ++-- yakumo.yml | 26 ++++ 75 files changed, 573 insertions(+), 181 deletions(-) create mode 100644 .github/workflows/build.yml create mode 100644 .github/workflows/publish.yml rename jest.config.ts => packages/core/jest.config.ts (100%) create mode 100644 packages/core/package.json rename {resources => packages/core/resources}/emojis.json (100%) rename {src => packages/core/src}/adapters/base.ts (100%) rename {src => packages/core/src}/adapters/cloudflare.ts (100%) rename {src => packages/core/src}/adapters/config.ts (100%) rename {src => packages/core/src}/adapters/creators/base.ts (100%) rename {src => packages/core/src}/adapters/creators/component.ts (100%) rename {src => packages/core/src}/adapters/creators/schema.ts (100%) rename {src => packages/core/src}/adapters/custom.ts (100%) rename {src => packages/core/src}/adapters/gemini.ts (100%) rename {src => packages/core/src}/adapters/index.ts (100%) rename {src => packages/core/src}/adapters/ollama.ts (100%) rename {src => packages/core/src}/adapters/openai.ts (100%) rename {src => packages/core/src}/bot.ts (100%) rename {src => packages/core/src}/commands/memory.ts (100%) rename {src => packages/core/src}/commands/sendQuene.ts (100%) rename {src => packages/core/src}/config.ts (100%) rename {src => packages/core/src}/database/index.ts (100%) rename {src => packages/core/src}/embeddings/base.ts (100%) rename {src => packages/core/src}/embeddings/config.ts (100%) rename {src => packages/core/src}/embeddings/custom.ts (100%) rename {src => packages/core/src}/embeddings/index.ts (100%) rename {src => packages/core/src}/embeddings/ollama.ts (100%) rename {src => packages/core/src}/embeddings/openai.ts (100%) rename {src => packages/core/src}/extensions/.gitkeep (100%) create mode 100644 packages/core/src/extensions/README.md rename {src => packages/core/src}/extensions/base.ts (100%) rename {src => packages/core/src}/extensions/ext_command.ts (100%) rename {src => packages/core/src}/extensions/ext_memory.ts (100%) rename {src => packages/core/src}/index.ts (100%) rename {src => packages/core/src}/managers/cacheManager.ts (100%) rename {src => packages/core/src}/managers/emojiManager.ts (100%) rename {src => packages/core/src}/managers/queueManager.ts (100%) rename {src => packages/core/src}/models/ChatMessage.ts (100%) rename {src => packages/core/src}/services/imageViewer.ts (100%) rename {src => packages/core/src}/services/sendQueue.ts (100%) rename {src => packages/core/src}/utils/content.ts (100%) rename {src => packages/core/src}/utils/factory.ts (100%) rename {src => packages/core/src}/utils/http.ts (100%) rename {src => packages/core/src}/utils/imageUtils.ts (100%) rename {src => packages/core/src}/utils/index.ts (100%) rename {src => packages/core/src}/utils/prompt.ts (100%) rename {src => packages/core/src}/utils/string.ts (100%) rename {src => packages/core/src}/utils/toolkit.ts (100%) rename {src => packages/core/src}/utils/verifier.ts (100%) rename {tests => packages/core/tests}/cacheManager.spec.ts (100%) rename {tests => packages/core/tests}/config.ts (100%) rename {tests => packages/core/tests}/imageCache.spec.ts (100%) rename {tests => packages/core/tests}/index.spec.ts (100%) rename {tests => packages/core/tests}/regexp.spec.ts (100%) rename {tests => packages/core/tests}/schema.spec.ts (100%) rename {tests => packages/core/tests}/vectorStore.spec.ts (100%) create mode 100644 packages/core/tsconfig.json create mode 100644 packages/extension/README.md create mode 100644 packages/extension/src/base.ts create mode 100644 packages/extension/src/decorators.ts create mode 100644 packages/extension/src/index.ts create mode 100644 packages/extension/src/utils.ts create mode 100644 packages/extension/tsconfig.json create mode 100644 packages/memory/src/database.ts create mode 100644 packages/memory/src/model.ts create mode 100644 yakumo.yml diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 00000000..b0c838d4 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,14 @@ +name: Build + +on: + push: + pull_request: + branches: [main] + types: [opened, synchronize, reopened, labeled, unlabeled] + +jobs: + build: + uses: cordiverse/workflows/.github/workflows/build.yml@main + with: + lint: true + test: false diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml new file mode 100644 index 00000000..f3ce0785 --- /dev/null +++ b/.github/workflows/publish.yml @@ -0,0 +1,12 @@ +name: Publish + +on: + push: + branches: + - main + +jobs: + publish: + uses: cordiverse/workflows/.github/workflows/publish.yml@main + secrets: + NPM_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.gitignore b/.gitignore index 3cb70423..401fd5d7 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ yarn-error.log tsconfig.tsbuildinfo package-lock.json yarn.lock +package.tgz .eslintcache .DS_Store diff --git a/package.json b/package.json index b79127bc..4d5315ba 100644 --- a/package.json +++ b/package.json @@ -1,85 +1,36 @@ { - "name": "koishi-plugin-yesimbot", - "description": "Yes! I'm Bot! 机械壳,人类心", - "version": "2.0.0", - "main": "lib/index.js", - "typings": "lib/index.d.ts", + "name": "@root/yesimbot", + "version": "0.0.0", + "private": true, "homepage": "https://github.com/HydroGest/YesImBot", - "files": [ - "lib", - "dist", - "resources" - ], "contributors": [ "HydroGest <2445691453@qq.com>", "Dispure <3116716016@qq.com>" ], "license": "MIT", - "scripts": { - "test": "jest", - "generate": "ts-node scripts/generateSchema.ts" - }, - "keywords": [ - "chatbot", - "koishi", - "plugin", - "ai" + "workspaces": [ + "packages/*" ], - "repository": { - "type": "git", - "url": "git+https://github.com/HydroGest/YesImBot.git" - }, - "dependencies": { - "async-mutex": "^0.5.0", - "axios": "^1.7.9", - "sharp": "^0.33.5" - }, - "peerDependencies": { - "koishi": "^4.18.5" + "scripts": { + "clean": "yakumo clean", + "build": "yakumo build", + "bump": "yakumo version", + "dep": "yakumo upgrade", + "pub": "yakumo publish", + "lint": "eslint --ext .ts --ext .tsx . && prettier --check .", + "lint:fix": "eslint --ext .ts --ext .tsx . --fix && prettier --write .", + "format": "prettier --write .", + "test": "yakumo mocha -r esbuild-register -r yml-register", + "test:text": "shx rm -rf coverage && c8 -r text yarn test", + "test:json": "shx rm -rf coverage && c8 -r json yarn test", + "test:html": "shx rm -rf coverage && c8 -r html yarn test" }, + "prettier": "@hamster-bot/prettier-config", "devDependencies": { - "@koishijs/plugin-mock": "^2.6.6" - }, - "exports": { - ".": { - "types": "./lib/index.d.ts", - "default": "./lib/index.js" - }, - "./package.json": "./package.json", - "./adapters": { - "types": "./lib/adapters/index.d.ts", - "default": "./lib/adapters/index.js" - }, - "./embeddings": { - "types": "./lib/embeddings/index.d.ts", - "default": "./lib/embeddings/index.js" - }, - "./managers": { - "types": "./lib/managers/index.d.ts", - "default": "./lib/managers/index.js" - }, - "./utils": { - "types": "./lib/utils/index.d.ts", - "default": "./lib/utils/index.js" - } - }, - "koishi": { - "description": { - "zh": "让语言大模型机器人假装群友并和群友聊天!", - "en": "A Koishi plugin that allows LLM chat in your guild." - }, - "browser": true, - "service": { - "required": [ - "axios", - "database" - ], - "optional": [ - "memory" - ], - "implements": [ - "yesimbot" - ] - } + "typescript": "^5.7.2", + "yakumo": "^1.0.0-beta.20", + "yakumo-esbuild": "^1.0.0-beta.7", + "yakumo-tsc": "^1.0.0-beta.5", + "yml-register": "^1.2.5" } } diff --git a/jest.config.ts b/packages/core/jest.config.ts similarity index 100% rename from jest.config.ts rename to packages/core/jest.config.ts diff --git a/packages/core/package.json b/packages/core/package.json new file mode 100644 index 00000000..4a8a7d91 --- /dev/null +++ b/packages/core/package.json @@ -0,0 +1,82 @@ +{ + "name": "koishi-plugin-yesimbot", + "description": "Yes! I'm Bot! 机械壳,人类心", + "version": "2.0.0", + "main": "lib/index.js", + "typings": "lib/index.d.ts", + "homepage": "https://github.com/HydroGest/YesImBot", + "files": [ + "lib", + "dist", + "resources" + ], + "contributors": [ + "HydroGest <2445691453@qq.com>", + "Dispure <3116716016@qq.com>" + ], + "license": "MIT", + "keywords": [ + "chatbot", + "koishi", + "plugin", + "ai" + ], + "repository": { + "type": "git", + "url": "git+https://github.com/HydroGest/YesImBot.git", + "directory": "packages/core" + }, + "dependencies": { + "async-mutex": "^0.5.0", + "axios": "^1.7.9", + "sharp": "^0.33.5" + }, + "peerDependencies": { + "koishi": "^4.18.5" + }, + "devDependencies": { + "@koishijs/plugin-mock": "^2.6.6" + }, + "exports": { + ".": { + "types": "./lib/index.d.ts", + "default": "./lib/index.js" + }, + "./package.json": "./package.json", + "./adapters": { + "types": "./lib/adapters/index.d.ts", + "default": "./lib/adapters/index.js" + }, + "./embeddings": { + "types": "./lib/embeddings/index.d.ts", + "default": "./lib/embeddings/index.js" + }, + "./managers": { + "types": "./lib/managers/index.d.ts", + "default": "./lib/managers/index.js" + }, + "./utils": { + "types": "./lib/utils/index.d.ts", + "default": "./lib/utils/index.js" + } + }, + "koishi": { + "description": { + "zh": "让语言大模型机器人假装群友并和群友聊天!", + "en": "A Koishi plugin that allows LLM chat in your guild." + }, + "browser": true, + "service": { + "required": [ + "axios", + "database" + ], + "optional": [ + "memory" + ], + "implements": [ + "yesimbot" + ] + } + } +} diff --git a/resources/emojis.json b/packages/core/resources/emojis.json similarity index 100% rename from resources/emojis.json rename to packages/core/resources/emojis.json diff --git a/src/adapters/base.ts b/packages/core/src/adapters/base.ts similarity index 100% rename from src/adapters/base.ts rename to packages/core/src/adapters/base.ts diff --git a/src/adapters/cloudflare.ts b/packages/core/src/adapters/cloudflare.ts similarity index 100% rename from src/adapters/cloudflare.ts rename to packages/core/src/adapters/cloudflare.ts diff --git a/src/adapters/config.ts b/packages/core/src/adapters/config.ts similarity index 100% rename from src/adapters/config.ts rename to packages/core/src/adapters/config.ts diff --git a/src/adapters/creators/base.ts b/packages/core/src/adapters/creators/base.ts similarity index 100% rename from src/adapters/creators/base.ts rename to packages/core/src/adapters/creators/base.ts diff --git a/src/adapters/creators/component.ts b/packages/core/src/adapters/creators/component.ts similarity index 100% rename from src/adapters/creators/component.ts rename to packages/core/src/adapters/creators/component.ts diff --git a/src/adapters/creators/schema.ts b/packages/core/src/adapters/creators/schema.ts similarity index 100% rename from src/adapters/creators/schema.ts rename to packages/core/src/adapters/creators/schema.ts diff --git a/src/adapters/custom.ts b/packages/core/src/adapters/custom.ts similarity index 100% rename from src/adapters/custom.ts rename to packages/core/src/adapters/custom.ts diff --git a/src/adapters/gemini.ts b/packages/core/src/adapters/gemini.ts similarity index 100% rename from src/adapters/gemini.ts rename to packages/core/src/adapters/gemini.ts diff --git a/src/adapters/index.ts b/packages/core/src/adapters/index.ts similarity index 100% rename from src/adapters/index.ts rename to packages/core/src/adapters/index.ts diff --git a/src/adapters/ollama.ts b/packages/core/src/adapters/ollama.ts similarity index 100% rename from src/adapters/ollama.ts rename to packages/core/src/adapters/ollama.ts diff --git a/src/adapters/openai.ts b/packages/core/src/adapters/openai.ts similarity index 100% rename from src/adapters/openai.ts rename to packages/core/src/adapters/openai.ts diff --git a/src/bot.ts b/packages/core/src/bot.ts similarity index 100% rename from src/bot.ts rename to packages/core/src/bot.ts diff --git a/src/commands/memory.ts b/packages/core/src/commands/memory.ts similarity index 100% rename from src/commands/memory.ts rename to packages/core/src/commands/memory.ts diff --git a/src/commands/sendQuene.ts b/packages/core/src/commands/sendQuene.ts similarity index 100% rename from src/commands/sendQuene.ts rename to packages/core/src/commands/sendQuene.ts diff --git a/src/config.ts b/packages/core/src/config.ts similarity index 100% rename from src/config.ts rename to packages/core/src/config.ts diff --git a/src/database/index.ts b/packages/core/src/database/index.ts similarity index 100% rename from src/database/index.ts rename to packages/core/src/database/index.ts diff --git a/src/embeddings/base.ts b/packages/core/src/embeddings/base.ts similarity index 100% rename from src/embeddings/base.ts rename to packages/core/src/embeddings/base.ts diff --git a/src/embeddings/config.ts b/packages/core/src/embeddings/config.ts similarity index 100% rename from src/embeddings/config.ts rename to packages/core/src/embeddings/config.ts diff --git a/src/embeddings/custom.ts b/packages/core/src/embeddings/custom.ts similarity index 100% rename from src/embeddings/custom.ts rename to packages/core/src/embeddings/custom.ts diff --git a/src/embeddings/index.ts b/packages/core/src/embeddings/index.ts similarity index 100% rename from src/embeddings/index.ts rename to packages/core/src/embeddings/index.ts diff --git a/src/embeddings/ollama.ts b/packages/core/src/embeddings/ollama.ts similarity index 100% rename from src/embeddings/ollama.ts rename to packages/core/src/embeddings/ollama.ts diff --git a/src/embeddings/openai.ts b/packages/core/src/embeddings/openai.ts similarity index 100% rename from src/embeddings/openai.ts rename to packages/core/src/embeddings/openai.ts diff --git a/src/extensions/.gitkeep b/packages/core/src/extensions/.gitkeep similarity index 100% rename from src/extensions/.gitkeep rename to packages/core/src/extensions/.gitkeep diff --git a/packages/core/src/extensions/README.md b/packages/core/src/extensions/README.md new file mode 100644 index 00000000..e69de29b diff --git a/src/extensions/base.ts b/packages/core/src/extensions/base.ts similarity index 100% rename from src/extensions/base.ts rename to packages/core/src/extensions/base.ts diff --git a/src/extensions/ext_command.ts b/packages/core/src/extensions/ext_command.ts similarity index 100% rename from src/extensions/ext_command.ts rename to packages/core/src/extensions/ext_command.ts diff --git a/src/extensions/ext_memory.ts b/packages/core/src/extensions/ext_memory.ts similarity index 100% rename from src/extensions/ext_memory.ts rename to packages/core/src/extensions/ext_memory.ts diff --git a/src/index.ts b/packages/core/src/index.ts similarity index 100% rename from src/index.ts rename to packages/core/src/index.ts diff --git a/src/managers/cacheManager.ts b/packages/core/src/managers/cacheManager.ts similarity index 100% rename from src/managers/cacheManager.ts rename to packages/core/src/managers/cacheManager.ts diff --git a/src/managers/emojiManager.ts b/packages/core/src/managers/emojiManager.ts similarity index 100% rename from src/managers/emojiManager.ts rename to packages/core/src/managers/emojiManager.ts diff --git a/src/managers/queueManager.ts b/packages/core/src/managers/queueManager.ts similarity index 100% rename from src/managers/queueManager.ts rename to packages/core/src/managers/queueManager.ts diff --git a/src/models/ChatMessage.ts b/packages/core/src/models/ChatMessage.ts similarity index 100% rename from src/models/ChatMessage.ts rename to packages/core/src/models/ChatMessage.ts diff --git a/src/services/imageViewer.ts b/packages/core/src/services/imageViewer.ts similarity index 100% rename from src/services/imageViewer.ts rename to packages/core/src/services/imageViewer.ts diff --git a/src/services/sendQueue.ts b/packages/core/src/services/sendQueue.ts similarity index 100% rename from src/services/sendQueue.ts rename to packages/core/src/services/sendQueue.ts diff --git a/src/utils/content.ts b/packages/core/src/utils/content.ts similarity index 100% rename from src/utils/content.ts rename to packages/core/src/utils/content.ts diff --git a/src/utils/factory.ts b/packages/core/src/utils/factory.ts similarity index 100% rename from src/utils/factory.ts rename to packages/core/src/utils/factory.ts diff --git a/src/utils/http.ts b/packages/core/src/utils/http.ts similarity index 100% rename from src/utils/http.ts rename to packages/core/src/utils/http.ts diff --git a/src/utils/imageUtils.ts b/packages/core/src/utils/imageUtils.ts similarity index 100% rename from src/utils/imageUtils.ts rename to packages/core/src/utils/imageUtils.ts diff --git a/src/utils/index.ts b/packages/core/src/utils/index.ts similarity index 100% rename from src/utils/index.ts rename to packages/core/src/utils/index.ts diff --git a/src/utils/prompt.ts b/packages/core/src/utils/prompt.ts similarity index 100% rename from src/utils/prompt.ts rename to packages/core/src/utils/prompt.ts diff --git a/src/utils/string.ts b/packages/core/src/utils/string.ts similarity index 100% rename from src/utils/string.ts rename to packages/core/src/utils/string.ts diff --git a/src/utils/toolkit.ts b/packages/core/src/utils/toolkit.ts similarity index 100% rename from src/utils/toolkit.ts rename to packages/core/src/utils/toolkit.ts diff --git a/src/utils/verifier.ts b/packages/core/src/utils/verifier.ts similarity index 100% rename from src/utils/verifier.ts rename to packages/core/src/utils/verifier.ts diff --git a/tests/cacheManager.spec.ts b/packages/core/tests/cacheManager.spec.ts similarity index 100% rename from tests/cacheManager.spec.ts rename to packages/core/tests/cacheManager.spec.ts diff --git a/tests/config.ts b/packages/core/tests/config.ts similarity index 100% rename from tests/config.ts rename to packages/core/tests/config.ts diff --git a/tests/imageCache.spec.ts b/packages/core/tests/imageCache.spec.ts similarity index 100% rename from tests/imageCache.spec.ts rename to packages/core/tests/imageCache.spec.ts diff --git a/tests/index.spec.ts b/packages/core/tests/index.spec.ts similarity index 100% rename from tests/index.spec.ts rename to packages/core/tests/index.spec.ts diff --git a/tests/regexp.spec.ts b/packages/core/tests/regexp.spec.ts similarity index 100% rename from tests/regexp.spec.ts rename to packages/core/tests/regexp.spec.ts diff --git a/tests/schema.spec.ts b/packages/core/tests/schema.spec.ts similarity index 100% rename from tests/schema.spec.ts rename to packages/core/tests/schema.spec.ts diff --git a/tests/vectorStore.spec.ts b/packages/core/tests/vectorStore.spec.ts similarity index 100% rename from tests/vectorStore.spec.ts rename to packages/core/tests/vectorStore.spec.ts diff --git a/packages/core/tsconfig.json b/packages/core/tsconfig.json new file mode 100644 index 00000000..2d8b168d --- /dev/null +++ b/packages/core/tsconfig.json @@ -0,0 +1,12 @@ +{ + "extends": "../../tsconfig.base", + "compilerOptions": { + "rootDir": "src", + "outDir": "lib", + "emitDeclarationOnly": false, + "moduleResolution": "node", + "module": "CommonJS", + "experimentalDecorators": true + }, + "include": ["src"] +} diff --git a/packages/extension/README.md b/packages/extension/README.md new file mode 100644 index 00000000..1052ad76 --- /dev/null +++ b/packages/extension/README.md @@ -0,0 +1 @@ +# extension diff --git a/packages/extension/src/base.ts b/packages/extension/src/base.ts new file mode 100644 index 00000000..837a6494 --- /dev/null +++ b/packages/extension/src/base.ts @@ -0,0 +1,51 @@ +import fs from "fs"; +import { Context } from "koishi"; + + +export abstract class ExtFunction { + readonly name: string; + readonly description: string; + readonly params: { [key: string]: SchemaNode }; + + constructor( + protected readonly ctx: Context, + protected readonly bot: Bot + ) { + // 读取类的静态属性来初始化实例属性 + const funcName = (this.constructor as any)["funcName"]; + const description = (this.constructor as any)["description"]; + const params = (this.constructor as any)["params"]; + + // 返回一个函数实例,使得类实例可以调用 + const callable = (keyword: string) => this.apply(keyword); + Object.defineProperty(callable, "name", { value: funcName }); + Object.defineProperty(callable, "description", { value: description }); + Object.defineProperty(callable, "params", { value: params }); + return callable as any; + } + + abstract apply(...args: any[]): any; + + get session() { + return this.bot.session; + } +} + +export function getExtensions(ctx: Context, bot: Bot): ExtFunction[] { + let extensions: ExtFunction[] = []; + + fs.readdirSync(__dirname) + .filter((file) => file.startsWith("ext_")) + .forEach((file) => { + try { + const extension = require(`./${file}`); + for (const key in extension) { + extensions.push(new extension[key](ctx, bot)); + } + logger.info(`Loaded extension: ${file}`); + } catch (e) { + logger.error(`Failed to load extension: ${file}`, e); + } + }); + return extensions; +} diff --git a/packages/extension/src/decorators.ts b/packages/extension/src/decorators.ts new file mode 100644 index 00000000..a0c6e351 --- /dev/null +++ b/packages/extension/src/decorators.ts @@ -0,0 +1,24 @@ +export function Name(funcName: string) { + return function (target: Function) { + target["funcName"] = funcName; + }; +} + +export function Description(description: string) { + return function (target: Function) { + target["description"] = description; + }; +} + + +export function Param(param: string, schema: string | SchemaNode) { + return function (target: Function) { + if (!target["params"]) { + target["params"] = {}; + } + if (typeof schema === "string") { + schema = SchemaNode.String(schema); + } + target["params"][param] = schema; + }; +} diff --git a/packages/extension/src/index.ts b/packages/extension/src/index.ts new file mode 100644 index 00000000..9938ffaa --- /dev/null +++ b/packages/extension/src/index.ts @@ -0,0 +1,15 @@ +import { Context, Service } from "koishi"; +declare module "koishi" { + interface Context { + extension: Extension + } +} + +class Extension extends Service { + constructor(ctx: Context) { + super(ctx, "extension"); + } + + apply(extName: string, ...args: any) {} +} + diff --git a/packages/extension/src/utils.ts b/packages/extension/src/utils.ts new file mode 100644 index 00000000..bb2045d7 --- /dev/null +++ b/packages/extension/src/utils.ts @@ -0,0 +1,38 @@ +/** + * 生成工具模板 + * + * https://platform.openai.com/docs/guides/function-calling + * https://github.com/ollama/ollama/blob/main/docs/api.md#generate-a-chat-completion + * @param ext + * @returns + */ +export function getToolSchema(ext: Extension): ToolSchema { + return { + type: "function", + function: { + name: ext.name, + description: ext.description, + parameters: { + type: "object", + properties: ext.params, + // 如果有默认值则非必填 + required: Object.entries(ext.params).map(([key, value]) => value.default ? null : key).filter(Boolean), + }, + }, + }; +} + +/** + * 以文本形式给出的工具模板 + * @param ext + */ +export function getFunctionPrompt(ext: Extension): string { + let lines = []; + lines.push(`${ext.name}:`); + lines.push(` description: ${ext.description}`); + lines.push(` params:`); + Object.entries(ext.params).forEach(([key, value]) => { + lines.push(` ${key}: ${value.description}`); + }) + return lines.join("\n"); +} diff --git a/packages/extension/tsconfig.json b/packages/extension/tsconfig.json new file mode 100644 index 00000000..5cea7dc0 --- /dev/null +++ b/packages/extension/tsconfig.json @@ -0,0 +1,11 @@ +{ + "extends": "../../tsconfig.base", + "compilerOptions": { + "rootDir": "src", + "outDir": "lib", + "emitDeclarationOnly": false + }, + "include": [ + "src" + ], +} diff --git a/packages/memory/README.md b/packages/memory/README.md index 1ae57122..8a39cb51 100644 --- a/packages/memory/README.md +++ b/packages/memory/README.md @@ -1 +1,45 @@ # memory + +提示词设计 + +角色设定: + +1. 短期记忆(会话上下文) + 作用:捕捉当前话题和最近对话的重点。 + 实现方式: + 保留最近 N 条消息的摘要,或者直接保存 N 条原始消息。 + 根据上下文生成一个概述,帮助 LLM 理解当前话题。 + 通过关键词提取、主题分析等方法,动态调整对话重点。 + 更新机制: + 每次群聊发生新对话时,自动更新当前话题关键词和上下文摘要。 + 超过容量的对话转移到长期记忆。 + +2. 长期记忆(存储历史与人物信息) + 作用:记录群聊的长期信息,如群成员的性格特点、兴趣爱好、历史事件等。 + 存储内容: + 群聊主要内容:将话题进行分类,如“科技”“游戏”“日常闲聊”,为每个主题建立条目。 + 群成员信息:包括成员昵称、发言风格、兴趣领域,以及对某些主题的专业性。 + LLM自身信息:记录 LLM 在群聊中的设定(如性格、语气、知识背景),确保一致性。 + 通用知识:与群聊相关的特定领域信息(如游戏攻略、技术背景等)。 + +3. 记忆更新 + 保留部分短期记忆 + 上下文摘要生成 + 上下文感知的转移机制 + + +4. 获取记忆 + 设计一个动态系统: + 优先主动传递必要记忆:在已知上下文中,筛选出对当前话题高度相关的记忆直接传递,如用户的兴趣、身份或近期发言的主题。 + 必要时调用工具补充记忆:当 LLM 遇到模糊问题或需要追溯较多历史内容时,调用记忆工具查询。 + 实现策略 + 优先级筛选机制: + 定义高相关性的记忆内容,如: + 当前话题关键词相关的群成员信息。 + 群成员近期 3 条发言的摘要。 + 通过相关性评分(如 TF-IDF 或语义相似度)筛选内容。 + 工具调用触发条件: + 设置触发规则,如用户提问包含“之前”“我说过”“那是谁”等时间或身份指示词。 + LLM 可以明确表达“我需要查询相关记忆”并调用工具。 + + diff --git a/packages/memory/package.json b/packages/memory/package.json index 7d72a80b..2866d80a 100644 --- a/packages/memory/package.json +++ b/packages/memory/package.json @@ -4,12 +4,9 @@ "version": "0.0.1", "main": "lib/index.js", "typings": "lib/index.d.ts", - "devDependencies": { - "koishi": "^4.18.4" - }, "peerDependencies": { - "koishi": "^4.18.4", - "koishi-plugin-yesimbot": "^1.7.5" + "koishi": "^4.18.5", + "koishi-plugin-yesimbot": "^2.0.0" }, "koishi": { "description": { diff --git a/packages/memory/src/config.ts b/packages/memory/src/config.ts index 94e63c2c..65edc854 100644 --- a/packages/memory/src/config.ts +++ b/packages/memory/src/config.ts @@ -42,7 +42,7 @@ export const EmbeddingConfig: Schema = Schema.object({ }); export interface Config { - embedding: EmbeddingConfig + embedding: EmbeddingConfig; } export const Config: Schema = Schema.object({ diff --git a/packages/memory/src/database.ts b/packages/memory/src/database.ts new file mode 100644 index 00000000..c3e990da --- /dev/null +++ b/packages/memory/src/database.ts @@ -0,0 +1,39 @@ +import { Context } from "koishi"; +import { GuildMemory, MemoryItem, UserMemory } from "./model"; + +declare module "koishi" { + interface Tables { + "yesimbot.memory.guild": GuildMemory; + "yesimbot.memory.user": UserMemory; + } +} + +export function initDatabase(ctx: Context) { + ctx.model.extend( + "yesimbot.memory.guild", + { + guildId: "string", + guildName: "string", + guildDescription: "string", + members: "list", + recentTopics: "list", + }, + { + primary: "guildId", + } + ); + + ctx.model.extend( + "yesimbot.memory.user", + { + userId: "string", + userName: "string", + preferences: "list", + groupSpecific: "list", + }, + { + primary: "userId", + } + ); +} + diff --git a/packages/memory/src/index.ts b/packages/memory/src/index.ts index 72992863..e6ec42b7 100644 --- a/packages/memory/src/index.ts +++ b/packages/memory/src/index.ts @@ -1,8 +1,10 @@ import { Context, Schema, Service } from "koishi"; import { EmbeddingBase } from "koishi-plugin-yesimbot/embeddings"; import { getEmbedding } from "koishi-plugin-yesimbot/utils"; -import { MemoryVectorStore, Metadata, Vector } from "./vectorStore"; import { EmbeddingConfig } from "./config"; +import { initDatabase } from "./database"; +import { GroupActivity, GuildMemory, MemoryItem, UserMemory } from "./model"; +import { MemoryVectorStore, Metadata } from "./vectorStore"; declare module "koishi" { interface Context { @@ -10,84 +12,123 @@ declare module "koishi" { } } +export const inject = { + required: ["yesimbot", "database"], +}; + export { Config } from "./config"; class Memory extends Service { private vectorStore: MemoryVectorStore; - private embedder: EmbeddingBase; constructor(ctx: Context, config: Memory.Config) { super(ctx, "memory"); + initDatabase(ctx); this.vectorStore = new MemoryVectorStore(ctx); this.embedder = getEmbedding(config.embedding); } + // 获取单个记忆条目 get(memoryId: string): Metadata { return this.vectorStore.get(memoryId); } - getAll(): Vector[] { + // 获取所有记忆 + getAll(): MemoryItem[] { return this.vectorStore.getAll(); } + // 删除单个记忆 delete(memoryId: string) { return this.vectorStore.delete(memoryId); } - async update(memoryId: string, data: any): Promise { - const embedding = await this.embedder.embed(data); - return this.vectorStore.update(memoryId, embedding, data); - } - + // 清空所有记忆 clear() { this.vectorStore.clear(); } - async addText(content: string, userId?: string): Promise { - let embedding = await this.embedder.embed(content); + async update(memoryId: string, content: string, topic?: string, keywords?: string[]): Promise { + const embedding = await this.embedder.embed(content); + + if (!topic || !keywords) { + // TODO: 通过文本内容推断 topic 和 keywords(调用 LLM 或语义匹配) + } + + this.vectorStore.update(memoryId, embedding, { + content: content, + topic: topic, + keywords: keywords, + }); + } + + // 添加一条新的记忆 + async addMemory(content: string, topic: string, keywords: string[]): Promise { + const embedding = await this.embedder.embed(content); + + const memoryId = await this.vectorStore.addVector(embedding, { + content: content, + topic: topic, + keywords: keywords, + }); + + return memoryId; + } - return await this.vectorStore.addVector(embedding, { + async addUserMemory(userId: string, guildId: string, content: string, role: string): Promise { + const embedding = await this.embedder.embed(content); + + const { topic, keywords } = await this.extractTopicAndKeywords(content); + + await this.vectorStore.addVector(embedding, { content, - createdAt: Date.now(), - userId, + topic, + keywords: [...keywords, `user:${userId}`, `guild:${guildId}`], // 将用户和群聊的ID作为关键词 }); + + await this.updateUserMemory(userId, guildId, content, role); + await this.updateGuildMemory(guildId, content, role); + } + + private async updateUserMemory(userId: string, guildId: string, content: string, role: string): Promise { + let result = this.getUserMemory(userId); + + + } + + private async updateGuildMemory(guildId: string, content: string, role: string): Promise { + } - async search(query: string, limit: number, userId?: string): Promise - async search(query: string, limit: number, filter?: (metadata: Metadata) => boolean): Promise - - async search( - query: string, - limit: number = 5, - filter?: string | ((metadata: Metadata) => boolean) - ): Promise { - const embedding = await this.embedder.embed(query); - - const result = await this.vectorStore.similaritySearch( - embedding, - limit, - filter ? typeof filter === "string" ? (metadata: Metadata) => metadata.userId === filter : filter : undefined - ); - return result.map((item) => item.content); + private async getUserMemory(userId: string): Promise { + let result = await this.ctx.model.get("yesimbot.memory.user", { userId }); + + if (result.length > 0) { + return result[0]; + } } - getUserMemory(userId: string): string[] { - let vectors = this.vectorStore.filterVectors( - (vector) => vector.userId === userId - ); - return vectors.map((vector) => vector.content); + // 获取群聊记忆(示例) + private async getGuildMemory(guildId: string): Promise { + let result = await this.ctx.model.get("yesimbot.memory.guild", { guildId }); + + if (result.length > 0) { + return result[0]; + } } - filterMemory(filter: (metadata: Metadata) => boolean): string[] { - let vectors = this.vectorStore.filterVectors(filter); - return vectors.map((vector) => vector.content); + // 提取 Topic 和 Keywords + private async extractTopicAndKeywords(text: string): Promise<{ topic: string; keywords: string[] }> { + const topic = "群聊讨论"; // 模拟提取话题 + const keywords = ["讨论", "游戏", "技术"]; // 模拟提取关键词 + return { topic, keywords }; } } namespace Memory { export interface Config { - embedding: EmbeddingConfig + embedding: EmbeddingConfig; } export const Config: Schema = Schema.object({ embedding: EmbeddingConfig, diff --git a/packages/memory/src/model.ts b/packages/memory/src/model.ts new file mode 100644 index 00000000..36cf8501 --- /dev/null +++ b/packages/memory/src/model.ts @@ -0,0 +1,58 @@ +export interface MemoryItem { + id: string; // 全局唯一 ID + embedding: number[]; // 向量表示,用于语义检索 + magnitude?: number; // 向量表示的模 + content: string; // 记忆内容 + topic: string; // 主题,用于分类 + keywords: string[]; // 关键词,用于辅助查询 +} + +// 主题设计 +// 用户相关: +// 用户兴趣 +// 用户发言风格 +// 用户常用术语 +// 群聊内容: +// 最近讨论 +// 热门话题 +// 系统相关: +// LLM 设定 +// 特定领域知识 + +// 关键词设计方式 +// 用户相关: +// 用户名(如“用户A”) +// 兴趣领域(如“FPS游戏”“冒险游戏”) +// 特殊标签(如“高活跃”“低活跃”) +// 内容相关: +// 讨论话题关键词(如“游戏”“技术问题”) +// 特定领域的知识标签(如“编程语言”“机器学习”) + +export interface GuildMemory { + guildId: string; // 群聊唯一 ID + guildName: string; // 群聊名称 + guildDescription?: string; // 群聊描述 + members: MemberInfo[]; // 成员信息列表 + recentTopics: string[]; // 最近讨论主题 +} + +export interface MemberInfo { + userId: string; // 用户唯一 ID + userNick: string; // 用户在该群的昵称 + role: string; // 用户角色(如管理员、成员) +} + +export interface UserMemory { + userId: string; // 用户唯一 ID + userName: string; // 用户全局名称 + preferences: string[]; // 用户兴趣偏好 + groupSpecific: GroupActivity[]; // 与群聊相关的活动 +} + +export interface GroupActivity { + guildId: string; // 群聊唯一 ID + userNick: string; // 用户在该群的昵称 + role: string; // 用户在该群的角色 + actions: string[]; // 用户的活动记录 +} + diff --git a/packages/memory/src/vectorStore.ts b/packages/memory/src/vectorStore.ts index 12335cce..1593d38d 100644 --- a/packages/memory/src/vectorStore.ts +++ b/packages/memory/src/vectorStore.ts @@ -4,49 +4,27 @@ import { Context } from "koishi"; import { CacheManager } from "koishi-plugin-yesimbot"; import { calculateCosineSimilarity } from "koishi-plugin-yesimbot/embeddings"; - -// TODO: 如何让Bot添加记忆时正确选择标签 -enum MemoryTag { - User, // 用户记忆。包含userId - Self, // Bot自身记忆。对应userId==selfId - General // 通用记忆。没有userId -} - -export interface Vector { - id: string; // 随机生成的id - vector: number[]; // 向量 - magnitude: number; // 向量的模 - - content: string; // 记忆内容 - createdAt: number; // 创建时间 - updatedAt?: number; // 更新时间,用于计算时间权重 - - userId?: string; // 记忆关联的用户ID - tags?: MemoryTag[]; // 记忆标签。将记忆分类,便于查找 -} +import { MemoryItem } from "./model"; export interface Metadata { - content: string; // 记忆内容 - createdAt: number; // 创建时间 - updatedAt?: number; // 更新时间,用于计算时间权重 - - userId?: string; // 记忆关联的用户ID - tags?: MemoryTag[]; // 记忆标签 + content: string; + topic: string; + keywords: string[]; } export class MemoryVectorStore { - readonly store: CacheManager; + readonly store: CacheManager; constructor(private ctx: Context) { const vectorsFilePath = path.join(ctx.baseDir, "data/yesimbot/.vector_cache/memory.bin"); this.store = new CacheManager(vectorsFilePath, true); } - get(id: string): Metadata | undefined { + get(id: string): MemoryItem | undefined { return this.store.get(id); } - getAll(): Vector[] { + getAll(): MemoryItem[] { let vectors = this.store.values(); return vectors; } @@ -55,17 +33,18 @@ export class MemoryVectorStore { return this.store.remove(id); } - update(id: string, vector: number[], content: string) { + update(id: string, embedding: number[], metadata: Metadata) { if (!this.store.has(id)) { return; } let oldVector = this.store.get(id); - oldVector.content = content; - oldVector.updatedAt = Date.now(); - oldVector.vector = vector; - oldVector.magnitude = getMagnitude(vector); + oldVector.embedding = embedding; + oldVector.magnitude = getMagnitude(embedding); + oldVector.content = metadata.content; + oldVector.topic = metadata.topic || oldVector.topic; + oldVector.keywords = metadata.keywords || oldVector.keywords; this.store.set(id, oldVector); } @@ -82,32 +61,32 @@ export class MemoryVectorStore { this.store.commit(); } - async addVector(vector: number[], metadata: Metadata): Promise { + async addVector(embedding: number[], metadata: Metadata): Promise { const id = randomUUID(); this.store.set(id, { id, - vector, - magnitude: getMagnitude(vector), + embedding, + magnitude: getMagnitude(embedding), ...metadata, }); return id; } - async addVectors(vectors: number[][], metadatas: Metadata[]): Promise { - vectors.forEach((vector, index) => { + async addVectors(embeddings: number[][], metadatas: Metadata[]): Promise { + embeddings.forEach((embedding, index) => { const id = randomUUID(); this.store.set(id, { id, - vector, - magnitude: getMagnitude(vector), + embedding, + magnitude: getMagnitude(embedding), ...metadatas[index], }) }); } - filterVectors(filter: (metadata: Metadata) => boolean): Vector[] { + filterVectors(filter: (metadata: Metadata) => boolean): MemoryItem[] { return this.store.values().filter(filter); } @@ -125,12 +104,13 @@ export class MemoryVectorStore { * vector and the second element is the similarity score. The array is * sorted in descending order of similarity score. */ - async similaritySearchVectorWithScore(query: number[], k: number, filter?: (metadata: Metadata) => boolean): Promise<[Vector, number][]> { + async similaritySearchVectorWithScore(query: number[], k: number, filter?: (metadata: Metadata) => boolean): Promise<[MemoryItem, number][]> { const magnitude = getMagnitude(query); - let results: [Vector, number][] = []; + let results: [MemoryItem, number][] = []; for (const vector of this.store.values()) { - const similarity = calculateCosineSimilarity(query, vector.vector, magnitude, vector.magnitude); + if (!vector.magnitude) vector.magnitude = getMagnitude(vector.embedding); + const similarity = calculateCosineSimilarity(query, vector.embedding, magnitude, vector.magnitude); if (!filter || filter(vector)) { results.push([vector, similarity]); } @@ -140,7 +120,7 @@ export class MemoryVectorStore { return results.slice(0, k); } - async similaritySearch(query: number[], k: number, filter?: (vector: Vector) => boolean): Promise { + async similaritySearch(query: number[], k: number, filter?: (vector: MemoryItem) => boolean): Promise { const results = await this.similaritySearchVectorWithScore(query, k, filter); return results.map((result) => result[0]); } diff --git a/packages/webui/package.json b/packages/webui/package.json index c17c6a1b..3b8ec808 100644 --- a/packages/webui/package.json +++ b/packages/webui/package.json @@ -8,13 +8,12 @@ "chart.js": "^4.4.7" }, "devDependencies": { - "@koishijs/client": "^5.30.2", - "koishi": "^4.18.4" + "@koishijs/client": "^5.30.2" }, "peerDependencies": { "@koishijs/plugin-console": "^5.30.2", - "koishi": "^4.18.4", - "koishi-plugin-yesimbot": "^1.7.5", + "koishi": "^4.18.5", + "koishi-plugin-yesimbot": "^2.0.0", "koishi-plugin-yesimbot-memory": "^0.0.1" }, "koishi": { diff --git a/packages/webui/src/index.ts b/packages/webui/src/index.ts index 7f4651b1..bea0daef 100644 --- a/packages/webui/src/index.ts +++ b/packages/webui/src/index.ts @@ -1,3 +1,4 @@ +// @ts-nocheck import { resolve } from "path"; import { Context } from "koishi"; import {} from "@koishijs/plugin-console"; diff --git a/tsconfig.json b/tsconfig.json index 6e36d001..1c5d7dec 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,15 +1,10 @@ { - "extends": "./tsconfig.base", - "compilerOptions": { - "baseUrl": ".", - "rootDir": "src", - "outDir": "lib", - "emitDeclarationOnly": false, - "moduleResolution": "node", - "module": "CommonJS", - "experimentalDecorators": true - }, - "include": [ - "src" - ] -} + "extends": "./tsconfig.base", + "compilerOptions": { + "baseUrl": ".", + "paths": { + "koishi-plugin-yesimbot": ["packages/core/src"], + "koishi-plugin-yesimbot-*": ["packages/*/src"] + } + } + } diff --git a/yakumo.yml b/yakumo.yml new file mode 100644 index 00000000..92d75f59 --- /dev/null +++ b/yakumo.yml @@ -0,0 +1,26 @@ +- id: 6w97wf + name: yakumo + config: + pipeline: + build: + - tsc + - esbuild + - client + clean: + - tsc --clean +- id: ajm7mt + name: yakumo-esbuild +- id: mduzq8 + name: yakumo-tsc +- id: dxuzq6 + name: '@koishijs/client/lib' +- id: 3u9vi0 + name: yakumo/prepare +- id: cwythe + name: yakumo/run +- id: rig7vj + name: yakumo/upgrade +- id: zbr9xv + name: yakumo/publish +- id: bwjv9q + name: yakumo/version