From 0711b1f0863ee615feaee79bccd94258e031827a Mon Sep 17 00:00:00 2001 From: Acbox Date: Wed, 28 Jan 2026 14:00:28 +0800 Subject: [PATCH] feat: agent gateway --- AGENT_MIGRATION.md | 336 ------------------ agent/.gitignore | 44 +++ agent/README.md | 15 + agent/bun.lock | 56 +++ agent/package.json | 24 ++ agent/src/agent.ts | 109 ++++++ agent/src/gateway.ts | 14 + agent/src/index.ts | 14 + agent/src/middlewares/cors.ts | 9 + agent/src/middlewares/error.ts | 109 ++++++ agent/src/modules/chat.ts | 112 ++++++ .../agent => agent}/src/prompts/index.ts | 0 .../agent => agent}/src/prompts/schedule.ts | 2 +- .../agent => agent}/src/prompts/shared.ts | 0 .../agent => agent}/src/prompts/system.ts | 13 +- .../agent => agent}/src/prompts/utils.ts | 0 agent/src/types.ts | 14 + agent/tsconfig.json | 103 ++++++ eslint.config.mjs | 4 +- package.json | 14 +- pnpm-lock.yaml | 124 ++++--- pnpm-workspace.yaml | 1 + 22 files changed, 715 insertions(+), 402 deletions(-) delete mode 100644 AGENT_MIGRATION.md create mode 100644 agent/.gitignore create mode 100644 agent/README.md create mode 100644 agent/bun.lock create mode 100644 agent/package.json create mode 100644 agent/src/agent.ts create mode 100644 agent/src/gateway.ts create mode 100644 agent/src/index.ts create mode 100644 agent/src/middlewares/cors.ts create mode 100644 agent/src/middlewares/error.ts create mode 100644 agent/src/modules/chat.ts rename {packages/agent => agent}/src/prompts/index.ts (100%) rename {packages/agent => agent}/src/prompts/schedule.ts (93%) rename {packages/agent => agent}/src/prompts/shared.ts (100%) rename {packages/agent => agent}/src/prompts/system.ts (91%) rename {packages/agent => agent}/src/prompts/utils.ts (100%) create mode 100644 agent/src/types.ts create mode 100644 agent/tsconfig.json diff --git a/AGENT_MIGRATION.md b/AGENT_MIGRATION.md deleted file mode 100644 index 6e9ce6bc..00000000 --- a/AGENT_MIGRATION.md +++ /dev/null @@ -1,336 +0,0 @@ -# Agent Prompts 初步迁移 - -## 概述 - -本文档记录了从 TypeScript agent (`@packages/agent`) 到 Go chat 服务的初步迁移工作。 - -## 完成的工作 - -### 1. 删除 Config 中的 Memory 配置 - -由于现在使用数据库中的模型配置,不再需要配置文件中的 memory 配置。 - -**变更文件**: -- ✅ `config.toml.example` - 删除 `[memory]` 配置段 -- ✅ `internal/config/config.go` - 删除 `MemoryConfig` 结构 -- ✅ `cmd/agent/main.go` - 移除对 `cfg.Memory` 的引用 - -**影响**: -- Memory 服务现在完全依赖数据库中配置的模型 -- 如果数据库中没有配置模型,服务会启动失败并提示用户配置 -- 更清晰的配置管理,避免配置分散 - -### 2. 迁移 Agent Prompts 到 Chat 包 - -从 TypeScript 的 `packages/agent/src/prompts/` 迁移到 Go 的 `internal/chat/prompts.go`。 - -**迁移的内容**: - -#### System Prompt (系统提示词) -- ✅ 基础系统提示词 -- ✅ 日期时间格式化 -- ✅ 语言设置 -- ✅ 平台信息(available-platforms, current-platform) -- ✅ 上下文加载时间配置 -- ✅ 响应指南 - -#### Schedule Prompt (定时任务提示词) -- ✅ 定时任务触发提示 -- ✅ 任务信息(名称、描述、ID、最大调用次数、Cron 模式) -- ✅ 命令内容 - -#### 辅助函数 -- ✅ `FormatTime()` - 时间格式化 -- ✅ `Quote()` - Markdown 代码格式化 -- ✅ `Block()` - 代码块格式化 - -**暂未迁移(后续工作)**: -- ⏸️ Memory 工具说明 -- ⏸️ Schedule 工具说明 -- ⏸️ Message 工具说明 -- ⏸️ MCP 工具集成 -- ⏸️ 工具调用逻辑 - -## 新的 Prompt 结构 - -### SystemPrompt - -```go -type PromptParams struct { - Date time.Time - Locale string - Language string - MaxContextLoadTime int // 上下文加载时间(分钟) - Platforms []string // 可用平台列表 - CurrentPlatform string // 当前平台 -} - -func SystemPrompt(params PromptParams) string -``` - -**示例**: -```go -prompt := chat.SystemPrompt(chat.PromptParams{ - Date: time.Now(), - Locale: "zh-CN", - Language: "Chinese", - MaxContextLoadTime: 24 * 60, - Platforms: []string{"telegram", "wechat"}, - CurrentPlatform: "telegram", -}) -``` - -### SchedulePrompt - -```go -type SchedulePromptParams struct { - Date time.Time - Locale string - ScheduleName string - ScheduleDescription string - ScheduleID string - MaxCalls *int // nil 表示无限次 - CronPattern string - Command string -} - -func SchedulePrompt(params SchedulePromptParams) string -``` - -**示例**: -```go -maxCalls := 1 -prompt := chat.SchedulePrompt(chat.SchedulePromptParams{ - Date: time.Now(), - Locale: "zh-CN", - ScheduleName: "早餐提醒", - ScheduleDescription: "每天早上 7 点提醒吃早餐", - ScheduleID: "schedule-123", - MaxCalls: &maxCalls, - CronPattern: "0 7 * * *", - Command: "提醒用户吃早餐,推荐健康食谱", -}) -``` - -## 使用方式 - -### Chat Resolver 中的使用 - -Chat Resolver 会自动为每个请求添加系统提示词: - -```go -// 在 resolver.go 中 -systemPrompt := SystemPrompt(PromptParams{ - Date: time.Now(), - Locale: "en-US", - Language: "Same as user input", - MaxContextLoadTime: 24 * 60, - Platforms: []string{}, - CurrentPlatform: "api", -}) -``` - -### 自定义 Prompt 参数 - -未来可以通过以下方式自定义: - -1. **从数据库加载平台列表**: -```go -platforms, _ := platformService.GetActivePlatforms(ctx) -platformNames := make([]string, len(platforms)) -for i, p := range platforms { - platformNames[i] = p.Name -} -``` - -2. **从用户设置加载语言偏好**: -```go -userSettings, _ := settingsService.GetUserSettings(ctx, userID) -language := userSettings.Language -``` - -3. **从会话上下文获取当前平台**: -```go -currentPlatform := "telegram" // 从请求头或会话中获取 -``` - -## 对比 TypeScript 版本 - -### TypeScript (原始) -```typescript -export const system = ({ date, locale, language, maxContextLoadTime, platforms, currentPlatform }: SystemParams) => { - return ` ---- -${time({ date, locale })} -language: ${language} -available-platforms: -${platforms.map(platform => ` - ${platform.name}`).join('\n')} -current-platform: ${currentPlatform} ---- -You are a personal housekeeper assistant... - `.trim() -} -``` - -### Go (迁移后) -```go -func SystemPrompt(params PromptParams) string { - timeStr := FormatTime(params.Date, params.Locale) - platformsList := buildPlatformsList(params.Platforms) - - return fmt.Sprintf(`--- -%s -language: %s -available-platforms: -%s -current-platform: %s ---- -You are a personal housekeeper assistant...`, - timeStr, params.Language, platformsList, params.CurrentPlatform) -} -``` - -## 配置迁移指南 - -### 旧配置 (config.toml) -```toml -[memory] -base_url = "https://api.openai.com/v1" -api_key = "sk-..." -model = "gpt-4.1-nano" -timeout_seconds = 10 -``` - -### 新配置 (数据库) -```sql --- 1. 创建 LLM Provider -INSERT INTO llm_providers (name, client_type, base_url, api_key) -VALUES ('OpenAI', 'openai', 'https://api.openai.com/v1', 'sk-...'); - --- 2. 创建 Chat 模型(用于 memory) -INSERT INTO models (model_id, name, llm_provider_id, type, enable_as) -VALUES ('gpt-4-turbo', 'GPT-4 Turbo', '', 'chat', 'memory'); - --- 或使用现有的 chat 模型 -UPDATE models SET enable_as = 'memory' WHERE model_id = 'gpt-4-turbo'; -``` - -## 测试建议 - -### 1. 测试系统提示词 -```bash -# 发起聊天请求 -curl -X POST http://localhost:8080/api/chat \ - -H "Authorization: Bearer $TOKEN" \ - -d '{ - "messages": [ - {"role": "user", "content": "你好"} - ] - }' -``` - -检查响应中是否: -- 使用了正确的语言 -- AI 理解自己是个人管家助手 -- 响应风格友好且有帮助 - -### 2. 验证配置迁移 -```bash -# 启动服务,检查日志 -# 应该看到: -# Using memory model: gpt-4-turbo (provider: openai) - -# 不应该看到: -# WARNING: No memory model configured, using fallback LLMClient -``` - -### 3. 测试 Memory 操作 -```bash -# 添加记忆 -curl -X POST http://localhost:8080/api/memory/add \ - -H "Authorization: Bearer $TOKEN" \ - -d '{ - "messages": [ - {"role": "user", "content": "我喜欢吃披萨"} - ], - "user_id": "user-123" - }' - -# 搜索记忆 -curl -X POST http://localhost:8080/api/memory/search \ - -H "Authorization: Bearer $TOKEN" \ - -d '{ - "query": "我喜欢什么食物?", - "user_id": "user-123" - }' -``` - -## 后续工作 - -### 短期(工具集成) -- [ ] 添加 Memory 工具说明到系统提示词 -- [ ] 添加 Schedule 工具说明到系统提示词 -- [ ] 添加 Message 工具说明到系统提示词 -- [ ] 实现工具调用功能 -- [ ] 添加工具参数验证 - -### 中期(MCP 集成) -- [ ] MCP 连接管理 -- [ ] MCP 工具动态加载 -- [ ] MCP stdio/http/sse 传输支持 -- [ ] 容器环境中的 MCP 执行 - -### 长期(功能完善) -- [ ] 多语言本地化支持 -- [ ] 用户自定义系统提示词 -- [ ] Prompt 模板系统 -- [ ] A/B 测试不同 Prompt 版本 -- [ ] Prompt 性能监控 - -## 文件清单 - -### 删除/清理 -- ✅ `config.toml.example` - 删除 `[memory]` 段 -- ✅ `internal/config/config.go` - 删除 `MemoryConfig` -- ✅ `cmd/agent/main.go` - 删除 `cfg.Memory` 引用 - -### 修改 -- ✅ `internal/chat/prompts.go` - 完全重写,添加完整的 prompt 系统 -- ✅ `internal/chat/resolver.go` - 使用新的 `SystemPrompt` 函数 - -### 新增 -- ✅ `AGENT_MIGRATION.md` - 本文档 - -## 注意事项 - -1. **必须配置数据库模型**: 由于删除了配置文件中的回退配置,必须在数据库中配置至少一个 chat 模型 - -2. **Prompt 参数**: 当前使用硬编码的默认值,未来应该从用户设置或请求上下文中获取 - -3. **多语言支持**: `FormatTime()` 当前使用标准格式,未来应该使用 i18n 库进行本地化 - -4. **工具说明**: 当前 prompt 中提到了工具能力,但实际的工具说明还未添加,需要后续实现 - -5. **向后兼容**: 删除了配置文件中的 memory 配置,如果有旧的部署需要迁移 - -## 迁移检查清单 - -- [x] 删除 config.toml 中的 memory 配置 -- [x] 删除 Config 结构中的 MemoryConfig -- [x] 更新 main.go 移除 cfg.Memory 引用 -- [x] 迁移系统提示词 -- [x] 迁移定时任务提示词 -- [x] 迁移辅助函数 -- [x] 更新 resolver 使用新的 prompt -- [x] 通过 linter 检查 -- [x] 编写迁移文档 -- [ ] 测试 chat 功能 -- [ ] 测试 memory 功能 -- [ ] 更新部署文档 - -## 相关文档 - -- [Provider 重构总结](./REFACTORING_SUMMARY.md) -- [Chat 架构文档](./internal/chat/ARCHITECTURE.md) -- [TypeScript Agent 源码](./packages/agent/src/) - diff --git a/agent/.gitignore b/agent/.gitignore new file mode 100644 index 00000000..f3e107b2 --- /dev/null +++ b/agent/.gitignore @@ -0,0 +1,44 @@ +# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. + +# dependencies +/node_modules +/.pnp +.pnp.js + +# testing +/coverage + +# next.js +/.next/ +/out/ + +# production +/build + +# misc +.DS_Store +*.pem + +# debug +npm-debug.log* +yarn-debug.log* +yarn-error.log* + +# local env files +.env.local +.env.development.local +.env.test.local +.env.production.local + +# vercel +.vercel + +**/*.trace +**/*.zip +**/*.tar.gz +**/*.tgz +**/*.log +package-lock.json +**/*.bun + +dist/ \ No newline at end of file diff --git a/agent/README.md b/agent/README.md new file mode 100644 index 00000000..688c87e6 --- /dev/null +++ b/agent/README.md @@ -0,0 +1,15 @@ +# Elysia with Bun runtime + +## Getting Started +To get started with this template, simply paste this command into your terminal: +```bash +bun create elysia ./elysia-example +``` + +## Development +To start the development server run: +```bash +bun run dev +``` + +Open http://localhost:3000/ with your browser to see the result. \ No newline at end of file diff --git a/agent/bun.lock b/agent/bun.lock new file mode 100644 index 00000000..ff9b77a5 --- /dev/null +++ b/agent/bun.lock @@ -0,0 +1,56 @@ +{ + "lockfileVersion": 1, + "configVersion": 1, + "workspaces": { + "": { + "name": "agent", + "dependencies": { + "elysia": "latest", + }, + "devDependencies": { + "bun-types": "latest", + }, + }, + }, + "packages": { + "@borewit/text-codec": ["@borewit/text-codec@0.2.1", "https://registry.npmmirror.com/@borewit/text-codec/-/text-codec-0.2.1.tgz", {}, "sha512-k7vvKPbf7J2fZ5klGRD9AeKfUvojuZIQ3BT5u7Jfv+puwXkUBUT5PVyMDfJZpy30CBDXGMgw7fguK/lpOMBvgw=="], + + "@sinclair/typebox": ["@sinclair/typebox@0.34.48", "https://registry.npmmirror.com/@sinclair/typebox/-/typebox-0.34.48.tgz", {}, "sha512-kKJTNuK3AQOrgjjotVxMrCn1sUJwM76wMszfq1kdU4uYVJjvEWuFQ6HgvLt4Xz3fSmZlTOxJ/Ie13KnIcWQXFA=="], + + "@tokenizer/inflate": ["@tokenizer/inflate@0.4.1", "https://registry.npmmirror.com/@tokenizer/inflate/-/inflate-0.4.1.tgz", { "dependencies": { "debug": "^4.4.3", "token-types": "^6.1.1" } }, "sha512-2mAv+8pkG6GIZiF1kNg1jAjh27IDxEPKwdGul3snfztFerfPGI1LjDezZp3i7BElXompqEtPmoPx6c2wgtWsOA=="], + + "@tokenizer/token": ["@tokenizer/token@0.3.0", "https://registry.npmmirror.com/@tokenizer/token/-/token-0.3.0.tgz", {}, "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A=="], + + "@types/node": ["@types/node@25.0.10", "https://registry.npmmirror.com/@types/node/-/node-25.0.10.tgz", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-zWW5KPngR/yvakJgGOmZ5vTBemDoSqF3AcV/LrO5u5wTWyEAVVh+IT39G4gtyAkh3CtTZs8aX/yRM82OfzHJRg=="], + + "bun-types": ["bun-types@1.3.7", "https://registry.npmmirror.com/bun-types/-/bun-types-1.3.7.tgz", { "dependencies": { "@types/node": "*" } }, "sha512-qyschsA03Qz+gou+apt6HNl6HnI+sJJLL4wLDke4iugsE6584CMupOtTY1n+2YC9nGVrEKUlTs99jjRLKgWnjQ=="], + + "cookie": ["cookie@1.1.1", "https://registry.npmmirror.com/cookie/-/cookie-1.1.1.tgz", {}, "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ=="], + + "debug": ["debug@4.4.3", "https://registry.npmmirror.com/debug/-/debug-4.4.3.tgz", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], + + "elysia": ["elysia@1.4.22", "https://registry.npmmirror.com/elysia/-/elysia-1.4.22.tgz", { "dependencies": { "cookie": "^1.1.1", "exact-mirror": "^0.2.6", "fast-decode-uri-component": "^1.0.1", "memoirist": "^0.4.0" }, "peerDependencies": { "@sinclair/typebox": ">= 0.34.0 < 1", "@types/bun": ">= 1.2.0", "file-type": ">= 20.0.0", "openapi-types": ">= 12.0.0", "typescript": ">= 5.0.0" }, "optionalPeers": ["@types/bun", "typescript"] }, "sha512-Q90VCb1RVFxnFaRV0FDoSylESQQLWgLHFmWciQJdX9h3b2cSasji9KWEUvaJuy/L9ciAGg4RAhUVfsXHg5K2RQ=="], + + "exact-mirror": ["exact-mirror@0.2.6", "https://registry.npmmirror.com/exact-mirror/-/exact-mirror-0.2.6.tgz", { "peerDependencies": { "@sinclair/typebox": "^0.34.15" }, "optionalPeers": ["@sinclair/typebox"] }, "sha512-7s059UIx9/tnOKSySzUk5cPGkoILhTE4p6ncf6uIPaQ+9aRBQzQjc9+q85l51+oZ+P6aBxh084pD0CzBQPcFUA=="], + + "fast-decode-uri-component": ["fast-decode-uri-component@1.0.1", "https://registry.npmmirror.com/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz", {}, "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg=="], + + "file-type": ["file-type@21.3.0", "https://registry.npmmirror.com/file-type/-/file-type-21.3.0.tgz", { "dependencies": { "@tokenizer/inflate": "^0.4.1", "strtok3": "^10.3.4", "token-types": "^6.1.1", "uint8array-extras": "^1.4.0" } }, "sha512-8kPJMIGz1Yt/aPEwOsrR97ZyZaD1Iqm8PClb1nYFclUCkBi0Ma5IsYNQzvSFS9ib51lWyIw5mIT9rWzI/xjpzA=="], + + "ieee754": ["ieee754@1.2.1", "https://registry.npmmirror.com/ieee754/-/ieee754-1.2.1.tgz", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="], + + "memoirist": ["memoirist@0.4.0", "https://registry.npmmirror.com/memoirist/-/memoirist-0.4.0.tgz", {}, "sha512-zxTgA0mSYELa66DimuNQDvyLq36AwDlTuVRbnQtB+VuTcKWm5Qc4z3WkSpgsFWHNhexqkIooqpv4hdcqrX5Nmg=="], + + "ms": ["ms@2.1.3", "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + + "openapi-types": ["openapi-types@12.1.3", "https://registry.npmmirror.com/openapi-types/-/openapi-types-12.1.3.tgz", {}, "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw=="], + + "strtok3": ["strtok3@10.3.4", "https://registry.npmmirror.com/strtok3/-/strtok3-10.3.4.tgz", { "dependencies": { "@tokenizer/token": "^0.3.0" } }, "sha512-KIy5nylvC5le1OdaaoCJ07L+8iQzJHGH6pWDuzS+d07Cu7n1MZ2x26P8ZKIWfbK02+XIL8Mp4RkWeqdUCrDMfg=="], + + "token-types": ["token-types@6.1.2", "https://registry.npmmirror.com/token-types/-/token-types-6.1.2.tgz", { "dependencies": { "@borewit/text-codec": "^0.2.1", "@tokenizer/token": "^0.3.0", "ieee754": "^1.2.1" } }, "sha512-dRXchy+C0IgK8WPC6xvCHFRIWYUbqqdEIKPaKo/AcTUNzwLTK6AH7RjdLWsEZcAN/TBdtfUw3PYEgPr5VPr6ww=="], + + "uint8array-extras": ["uint8array-extras@1.5.0", "https://registry.npmmirror.com/uint8array-extras/-/uint8array-extras-1.5.0.tgz", {}, "sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A=="], + + "undici-types": ["undici-types@7.16.0", "https://registry.npmmirror.com/undici-types/-/undici-types-7.16.0.tgz", {}, "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw=="], + } +} diff --git a/agent/package.json b/agent/package.json new file mode 100644 index 00000000..e6209aff --- /dev/null +++ b/agent/package.json @@ -0,0 +1,24 @@ +{ + "name": "@memoh/agent-gateway", + "version": "1.0.0", + "scripts": { + "dev": "bun run --watch src/index.ts", + "build": "bun build src/index.ts --outfile dist/index.js --target bun --minify", + "start": "bun run dist/index.js" + }, + "dependencies": { + "@ai-sdk/anthropic": "^3.0.9", + "@ai-sdk/google": "^3.0.6", + "@ai-sdk/mcp": "^1.0.6", + "@ai-sdk/openai": "^3.0.7", + "@elysiajs/cors": "^1.4.1", + "@modelcontextprotocol/sdk": "^1.25.2", + "ai": "^6.0.25", + "elysia": "latest", + "zod": "^4.3.5" + }, + "devDependencies": { + "bun-types": "latest" + }, + "module": "src/index.js" +} diff --git a/agent/src/agent.ts b/agent/src/agent.ts new file mode 100644 index 00000000..0826f509 --- /dev/null +++ b/agent/src/agent.ts @@ -0,0 +1,109 @@ +import { generateText, ModelMessage, stepCountIs, streamText, TextStreamPart, ToolSet } from 'ai' +import { createChatGateway } from './gateway' +import { ClientType, Schedule } from './types' +import { system, schedule } from './prompts' + +export interface AgentParams { + apiKey: string + baseUrl: string + model: string + clientType: ClientType + locale?: Intl.LocalesArgument + language?: string + maxSteps?: number + maxContextLoadTime: number + platforms?: string[] + currentPlatform?: string +} + +export interface AgentInput { + messages: ModelMessage[] + query: string +} + +export interface AgentResult { + messages: ModelMessage[] +} + +export const createAgent = (params: AgentParams) => { + const gateway = createChatGateway(params.clientType) + const messages: ModelMessage[] = [] + + const maxSteps = params.maxSteps ?? 50 + + const generateSystem = () => { + return system({ + date: new Date(), + locale: params.locale, + language: params.language, + maxContextLoadTime: params.maxContextLoadTime, + platforms: params.platforms ?? [], + currentPlatform: params.currentPlatform, + }) + } + + const ask = async (input: AgentInput): Promise => { + messages.push(...input.messages) + messages.push({ + role: 'user', + content: input.query, + }) + const { response } = await generateText({ + model: gateway({ + apiKey: params.apiKey, + baseURL: params.baseUrl, + })(params.model), + system: generateSystem(), + stopWhen: stepCountIs(maxSteps), + messages, + }) + return { + messages: response.messages, + } + } + + async function* stream(input: AgentInput): AsyncGenerator, AgentResult> { + messages.push(...input.messages) + messages.push({ + role: 'user', + content: input.query, + }) + const { response, fullStream } = streamText({ + model: gateway({ + apiKey: params.apiKey, + baseURL: params.baseUrl, + })(params.model), + system: generateSystem(), + stopWhen: stepCountIs(maxSteps), + messages, + }) + for await (const event of fullStream) { + yield event + } + return { + messages: (await response).messages, + } + } + + const triggerSchedule = async ( + input: AgentInput, + scheduleData: Schedule + ) => { + messages.push(...input.messages) + messages.push({ + role: 'user', + content: schedule({ + schedule: scheduleData, + locale: params.locale, + date: new Date(), + }), + }) + return await ask(input) + } + + return { + ask, + stream, + triggerSchedule, + } +} \ No newline at end of file diff --git a/agent/src/gateway.ts b/agent/src/gateway.ts new file mode 100644 index 00000000..d8314829 --- /dev/null +++ b/agent/src/gateway.ts @@ -0,0 +1,14 @@ +import { createGateway as createAiGateway } from 'ai' +import { createOpenAI } from '@ai-sdk/openai' +import { createAnthropic } from '@ai-sdk/anthropic' +import { createGoogleGenerativeAI } from '@ai-sdk/google' +import { ClientType } from './types' + +export const createChatGateway = (clientType: ClientType) => { + const clients = { + [ClientType.OPENAI]: createOpenAI, + [ClientType.ANTHROPIC]: createAnthropic, + [ClientType.GOOGLE]: createGoogleGenerativeAI, + } + return (clients[clientType] ?? createAiGateway) +} \ No newline at end of file diff --git a/agent/src/index.ts b/agent/src/index.ts new file mode 100644 index 00000000..2c5cca2c --- /dev/null +++ b/agent/src/index.ts @@ -0,0 +1,14 @@ +import { Elysia } from 'elysia' +import { chatModule } from './modules/chat' +import { corsMiddleware } from './middlewares/cors' +import { errorMiddleware } from './middlewares/error' + +const app = new Elysia() + .use(corsMiddleware) + .use(errorMiddleware) + .use(chatModule) + .listen(8081) + +console.log( + `Agent Gateway is running at ${app.server?.hostname}:${app.server?.port}` +) diff --git a/agent/src/middlewares/cors.ts b/agent/src/middlewares/cors.ts new file mode 100644 index 00000000..fdb7aa5a --- /dev/null +++ b/agent/src/middlewares/cors.ts @@ -0,0 +1,9 @@ +import cors from '@elysiajs/cors' + +export const corsMiddleware = cors({ + origin: '*', + methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], + allowedHeaders: ['Content-Type', 'Authorization'], + exposeHeaders: ['Content-Type', 'Authorization'], + credentials: true, +}) \ No newline at end of file diff --git a/agent/src/middlewares/error.ts b/agent/src/middlewares/error.ts new file mode 100644 index 00000000..fcb3a019 --- /dev/null +++ b/agent/src/middlewares/error.ts @@ -0,0 +1,109 @@ +import { Elysia } from 'elysia' + +export interface ErrorResponse { + success: false + error: string + code?: string + details?: unknown +} + +export const errorMiddleware = new Elysia({ name: 'error' }) + .onError(({ code, error, set }) => { + console.error('[Error]', code, error) + + switch (code) { + case 'VALIDATION': + set.status = 400 + return { + success: false, + error: 'Validation failed', + code: 'VALIDATION_ERROR', + details: error.message, + } satisfies ErrorResponse + + case 'NOT_FOUND': + set.status = 404 + return { + success: false, + error: 'Resource not found', + code: 'NOT_FOUND', + } satisfies ErrorResponse + + case 'PARSE': + set.status = 400 + return { + success: false, + error: 'Invalid request format', + code: 'PARSE_ERROR', + details: error.message, + } satisfies ErrorResponse + + case 'INTERNAL_SERVER_ERROR': + set.status = 500 + return { + success: false, + error: 'Internal server error', + code: 'INTERNAL_SERVER_ERROR', + } satisfies ErrorResponse + + case 'UNKNOWN': + default: + if (error instanceof Error) { + const message = error.message + + if ( + message.includes('No bearer token') || + message.includes('Invalid or expired token') + ) { + set.status = 401 + return { + success: false, + error: message, + code: 'UNAUTHORIZED', + } satisfies ErrorResponse + } + + if (message.includes('Forbidden') || message.includes('Admin access required')) { + set.status = 403 + return { + success: false, + error: message, + code: 'FORBIDDEN', + } satisfies ErrorResponse + } + + if (message.includes('already exists')) { + set.status = 409 + return { + success: false, + error: message, + code: 'CONFLICT', + } satisfies ErrorResponse + } + + if (message.includes('not found')) { + set.status = 404 + return { + success: false, + error: message, + code: 'NOT_FOUND', + } satisfies ErrorResponse + } + + set.status = 500 + return { + success: false, + error: message, + code: 'ERROR', + } satisfies ErrorResponse + } + + set.status = 500 + return { + success: false, + error: 'An unexpected error occurred', + code: 'UNKNOWN_ERROR', + } satisfies ErrorResponse + } + }) + diff --git a/agent/src/modules/chat.ts b/agent/src/modules/chat.ts new file mode 100644 index 00000000..144b4fa8 --- /dev/null +++ b/agent/src/modules/chat.ts @@ -0,0 +1,112 @@ +import { Elysia, sse } from 'elysia' +import z from 'zod' +import { createAgent } from '../agent' +import { ClientType } from '../types' +import { ModelMessage } from 'ai' + +const ChatBody = z.object({ + apiKey: z.string().min(1, 'API key is required'), + baseUrl: z.string().min(1, 'Base URL is required'), + model: z.string().min(1, 'Model is required'), + clientType: z.enum([ + 'openai', + 'anthropic', + 'google', + ]), + locale: z.string().optional(), + language: z.string().optional(), + maxSteps: z.number().optional(), + maxContextLoadTime: z.number().min(1, 'Max context load time is required'), + platforms: z.array(z.string()).optional(), + currentPlatform: z.string().optional(), + + messages: z.array(z.object()), + query: z.string().min(1, 'Query is required'), +}) + +const ScheduleBody = z.object({ + schedule: z.object({ + id: z.string().min(1, 'Schedule ID is required'), + name: z.string().min(1, 'Schedule name is required'), + description: z.string().min(1, 'Schedule description is required'), + pattern: z.string().min(1, 'Schedule pattern is required'), + maxCalls: z.number().optional(), + command: z.string().min(1, 'Schedule command is required'), + }), +}).and(ChatBody) + +export const chatModule = new Elysia({ prefix: '/chat' }) + .post('/', async ({ body }) => { + const { ask } = createAgent({ + apiKey: body.apiKey, + baseUrl: body.baseUrl, + model: body.model, + clientType: body.clientType as ClientType, + locale: body.locale, + language: body.language, + maxSteps: body.maxSteps, + maxContextLoadTime: body.maxContextLoadTime, + platforms: body.platforms, + currentPlatform: body.currentPlatform, + }) + return await ask({ + messages: body.messages as unknown as ModelMessage[], + query: body.query, + }) + }, { + body: ChatBody, + }) + .post('/stream', async function* ({ body }) { + const { stream } = createAgent({ + apiKey: body.apiKey, + baseUrl: body.baseUrl, + model: body.model, + clientType: body.clientType as ClientType, + locale: body.locale, + language: body.language, + maxSteps: body.maxSteps, + maxContextLoadTime: body.maxContextLoadTime, + platforms: body.platforms, + currentPlatform: body.currentPlatform, + }) + const streanGenerator = stream({ + messages: body.messages as unknown as ModelMessage[], + query: body.query, + }) + while (true) { + const chunk = await streanGenerator.next() + if (chunk.done) { + yield sse({ + type: 'done', + data: chunk.value, + }) + break + } + yield sse({ + type: 'delta', + data: chunk.value + }) + } + }, { + body: ChatBody, + }) + .post('/schedule', async ({ body }) => { + const { triggerSchedule } = createAgent({ + apiKey: body.apiKey, + baseUrl: body.baseUrl, + model: body.model, + clientType: body.clientType as ClientType, + locale: body.locale, + language: body.language, + maxSteps: body.maxSteps, + maxContextLoadTime: body.maxContextLoadTime, + platforms: body.platforms, + currentPlatform: body.currentPlatform, + }) + return await triggerSchedule({ + messages: body.messages as unknown as ModelMessage[], + query: body.query, + }, body.schedule) + }, { + body: ScheduleBody, + }) \ No newline at end of file diff --git a/packages/agent/src/prompts/index.ts b/agent/src/prompts/index.ts similarity index 100% rename from packages/agent/src/prompts/index.ts rename to agent/src/prompts/index.ts diff --git a/packages/agent/src/prompts/schedule.ts b/agent/src/prompts/schedule.ts similarity index 93% rename from packages/agent/src/prompts/schedule.ts rename to agent/src/prompts/schedule.ts index c8cf83bf..77268ed8 100644 --- a/packages/agent/src/prompts/schedule.ts +++ b/agent/src/prompts/schedule.ts @@ -1,4 +1,4 @@ -import { Schedule } from '@memoh/shared' +import { Schedule } from '../types' import { time } from './shared' export interface ScheduleParams { diff --git a/packages/agent/src/prompts/shared.ts b/agent/src/prompts/shared.ts similarity index 100% rename from packages/agent/src/prompts/shared.ts rename to agent/src/prompts/shared.ts diff --git a/packages/agent/src/prompts/system.ts b/agent/src/prompts/system.ts similarity index 91% rename from packages/agent/src/prompts/system.ts rename to agent/src/prompts/system.ts index a6d1a0c1..6bc2edfe 100644 --- a/packages/agent/src/prompts/system.ts +++ b/agent/src/prompts/system.ts @@ -1,24 +1,23 @@ -import { Platform } from '@memoh/shared' import { time } from './shared' import { quote } from './utils' export interface SystemParams { date: Date locale?: Intl.LocalesArgument - language: string + language?: string maxContextLoadTime: number - platforms: Platform[] - currentPlatform: string + platforms: string[] + currentPlatform?: string } export const system = ({ date, locale, language, maxContextLoadTime, platforms, currentPlatform }: SystemParams) => { return ` --- ${time({ date, locale })} -language: ${language} +language: ${language ?? 'Same as user input'} available-platforms: -${platforms.map(platform => ` - ${platform.name}`).join('\n')} -current-platform: ${currentPlatform} +${platforms.map(platform => ` - ${platform}`).join('\n')} +current-platform: ${currentPlatform ?? 'Unknown Platform'} --- You are a personal housekeeper assistant, which able to manage the master's daily affairs. diff --git a/packages/agent/src/prompts/utils.ts b/agent/src/prompts/utils.ts similarity index 100% rename from packages/agent/src/prompts/utils.ts rename to agent/src/prompts/utils.ts diff --git a/agent/src/types.ts b/agent/src/types.ts new file mode 100644 index 00000000..8d322549 --- /dev/null +++ b/agent/src/types.ts @@ -0,0 +1,14 @@ +export enum ClientType { + OPENAI = 'openai', + ANTHROPIC = 'anthropic', + GOOGLE = 'google', +} + +export interface Schedule { + id: string + name: string + description: string + pattern: string + maxCalls?: number + command: string +} \ No newline at end of file diff --git a/agent/tsconfig.json b/agent/tsconfig.json new file mode 100644 index 00000000..1ca2350a --- /dev/null +++ b/agent/tsconfig.json @@ -0,0 +1,103 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig to read more about this file */ + + /* Projects */ + // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + + /* Language and Environment */ + "target": "ES2021", /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */ + // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "experimentalDecorators": true, /* Enable experimental support for TC39 stage 2 draft decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ + // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + + /* Modules */ + "module": "ES2022", /* Specify what module code is generated. */ + // "rootDir": "./", /* Specify the root folder within your source files. */ + "moduleResolution": "node", /* Specify how TypeScript looks up a file from a given module specifier. */ + // "baseUrl": "./", /* Specify the base directory to resolve non-relative module names. */ + // "paths": {}, /* Specify a set of entries that re-map imports to additional lookup locations. */ + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ + "types": ["bun-types"], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "resolveJsonModule": true, /* Enable importing .json files. */ + // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ + + /* JavaScript Support */ + // "allowJs": true, /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */ + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ + + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + // "sourceMap": true, /* Create source map files for emitted JavaScript files. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ + // "outDir": "./", /* Specify an output folder for all emitted files. */ + // "removeComments": true, /* Disable emitting comments. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "importsNotUsedAsValues": "remove", /* Specify emit/checking behavior for imports that are only used for types. */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + // "preserveValueImports": true, /* Preserve unused imported values in the JavaScript output that would otherwise be removed. */ + + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true, /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */ + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true, /* Ensure that casing is correct in imports. */ + + /* Type Checking */ + "strict": true, /* Enable all strict type-checking options. */ + // "noImplicitAny": true, /* Enable error reporting for expressions and declarations with an implied 'any' type. */ + // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + } +} diff --git a/eslint.config.mjs b/eslint.config.mjs index 34584998..732ab0fd 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -8,7 +8,7 @@ export default [ ...vue.configs['flat/recommended'], { ignores: ['**/node_modules/**', '**/dist/**'] }, { - files: ['packages/**/*.{js,jsx,ts,tsx}'], + files: ['packages/**/*.{js,jsx,ts,tsx}', 'agent/**/*.{js,jsx,ts,tsx}'], languageOptions: { parserOptions: { ecmaVersion: 2022, @@ -22,7 +22,7 @@ export default [ }, }, { - files: ['packages/**/*.vue'], + files: ['packages/**/*.vue', 'agent/**/*.vue'], languageOptions: { parser: vueParser, parserOptions: { diff --git a/package.json b/package.json index 8323d47b..147ac39e 100644 --- a/package.json +++ b/package.json @@ -3,23 +3,15 @@ "private": true, "version": "1.0.0", "scripts": { - "dev": "pnpm --parallel --filter @memoh/* dev", - "build": "pnpm --parallel --filter @memoh/* build", - "start": "pnpm --parallel --filter @memoh/* start", - "api:dev": "pnpm --filter @memoh/api dev", - "api:build": "pnpm --filter @memoh/api build", - "api:start": "pnpm --filter @memoh/api start", "web:dev": "pnpm --filter @memoh/web dev", "web:build": "pnpm --filter @memoh/web build", "web:start": "pnpm --filter @memoh/web start", - "db:push": "pnpm --filter @memoh/db push", - "db:migrate": "pnpm --filter @memoh/db migrate", - "db:generate": "pnpm --filter @memoh/db generate", - "db:studio": "pnpm --filter @memoh/db studio", - "cli": "pnpm --filter @memoh/client start", "docs:dev": "pnpm --filter @memoh/docs dev", "docs:build": "pnpm --filter @memoh/docs build", "docs:preview": "pnpm --filter @memoh/docs preview", + "agent:dev": "pnpm --filter @memoh/agent-gateway dev", + "agent:build": "pnpm --filter @memoh/agent-gateway build", + "agent:start": "pnpm --filter @memoh/agent-gateway start", "lint": "eslint .", "lint:fix": "eslint . --fix", "test": "vitest" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fc8f1dd0..c3e26edc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -37,6 +37,40 @@ importers: specifier: ^10.2.0 version: 10.2.0(eslint@9.39.2(jiti@2.6.1)) + agent: + dependencies: + '@ai-sdk/anthropic': + specifier: ^3.0.9 + version: 3.0.9(zod@4.3.5) + '@ai-sdk/google': + specifier: ^3.0.6 + version: 3.0.6(zod@4.3.5) + '@ai-sdk/mcp': + specifier: ^1.0.6 + version: 1.0.6(zod@4.3.5) + '@ai-sdk/openai': + specifier: ^3.0.7 + version: 3.0.7(zod@4.3.5) + '@elysiajs/cors': + specifier: ^1.4.1 + version: 1.4.1(elysia@1.4.22(@sinclair/typebox@0.34.47)(@types/bun@1.3.7)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3)) + '@modelcontextprotocol/sdk': + specifier: ^1.25.2 + version: 1.25.2(@cfworker/json-schema@4.1.1)(hono@4.11.4)(zod@4.3.5) + ai: + specifier: ^6.0.25 + version: 6.0.25(zod@4.3.5) + elysia: + specifier: latest + version: 1.4.22(@sinclair/typebox@0.34.47)(@types/bun@1.3.7)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3) + zod: + specifier: ^4.3.5 + version: 4.3.5 + devDependencies: + bun-types: + specifier: latest + version: 1.3.7 + docs: devDependencies: vitepress: @@ -110,22 +144,22 @@ importers: dependencies: '@elysiajs/bearer': specifier: ^1.1.4 - version: 1.4.2(elysia@1.4.22(@sinclair/typebox@0.34.47)(@types/bun@1.3.6)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3)) + version: 1.4.2(elysia@1.4.22(@sinclair/typebox@0.34.47)(@types/bun@1.3.7)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3)) '@elysiajs/cors': specifier: ^1.4.1 - version: 1.4.1(elysia@1.4.22(@sinclair/typebox@0.34.47)(@types/bun@1.3.6)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3)) + version: 1.4.1(elysia@1.4.22(@sinclair/typebox@0.34.47)(@types/bun@1.3.7)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3)) '@elysiajs/cron': specifier: ^1.4.1 - version: 1.4.1(elysia@1.4.22(@sinclair/typebox@0.34.47)(@types/bun@1.3.6)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3)) + version: 1.4.1(elysia@1.4.22(@sinclair/typebox@0.34.47)(@types/bun@1.3.7)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3)) '@elysiajs/eden': specifier: ^1.4.6 - version: 1.4.6(elysia@1.4.22(@sinclair/typebox@0.34.47)(@types/bun@1.3.6)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3)) + version: 1.4.6(elysia@1.4.22(@sinclair/typebox@0.34.47)(@types/bun@1.3.7)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3)) '@elysiajs/jwt': specifier: ^1.2.0 - version: 1.4.0(elysia@1.4.22(@sinclair/typebox@0.34.47)(@types/bun@1.3.6)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3)) + version: 1.4.0(elysia@1.4.22(@sinclair/typebox@0.34.47)(@types/bun@1.3.7)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3)) '@elysiajs/openapi': specifier: ^1.4.13 - version: 1.4.13(elysia@1.4.22(@sinclair/typebox@0.34.47)(@types/bun@1.3.6)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3)) + version: 1.4.13(elysia@1.4.22(@sinclair/typebox@0.34.47)(@types/bun@1.3.7)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3)) '@memoh/agent': specifier: workspace:* version: link:../agent @@ -149,10 +183,10 @@ importers: version: link:../shared drizzle-orm: specifier: ^0.45.1 - version: 0.45.1(@cloudflare/workers-types@4.20260109.0)(@opentelemetry/api@1.9.0)(@types/pg@8.16.0)(bun-types@1.3.6)(pg@8.16.3)(sqlite3@5.1.7) + version: 0.45.1(@cloudflare/workers-types@4.20260109.0)(@opentelemetry/api@1.9.0)(@types/pg@8.16.0)(bun-types@1.3.7)(pg@8.16.3)(sqlite3@5.1.7) elysia: specifier: latest - version: 1.4.22(@sinclair/typebox@0.34.47)(@types/bun@1.3.6)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3) + version: 1.4.22(@sinclair/typebox@0.34.47)(@types/bun@1.3.7)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3) node-cron: specifier: ^4.2.1 version: 4.2.1 @@ -162,13 +196,13 @@ importers: devDependencies: bun-types: specifier: latest - version: 1.3.6 + version: 1.3.7 packages/cli: dependencies: '@elysiajs/eden': specifier: ^1.4.6 - version: 1.4.6(elysia@1.4.22(@sinclair/typebox@0.34.47)(@types/bun@1.3.6)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3)) + version: 1.4.6(elysia@1.4.22(@sinclair/typebox@0.34.47)(@types/bun@1.3.7)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3)) '@memoh/api': specifier: workspace:* version: link:../api @@ -183,7 +217,7 @@ importers: version: 12.1.0 elysia: specifier: latest - version: 1.4.22(@sinclair/typebox@0.34.47)(@types/bun@1.3.6)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3) + version: 1.4.22(@sinclair/typebox@0.34.47)(@types/bun@1.3.7)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3) inquirer: specifier: ^12.3.0 version: 12.11.1(@types/node@22.19.5) @@ -202,13 +236,13 @@ importers: devDependencies: '@types/bun': specifier: latest - version: 1.3.6 + version: 1.3.7 '@types/node': specifier: ^22.10.5 version: 22.19.5 bun-types: specifier: latest - version: 1.3.6 + version: 1.3.7 packages/container: dependencies: @@ -233,7 +267,7 @@ importers: version: 17.2.3 drizzle-orm: specifier: ^0.45.1 - version: 0.45.1(@cloudflare/workers-types@4.20260109.0)(@opentelemetry/api@1.9.0)(@types/pg@8.16.0)(bun-types@1.3.6)(pg@8.16.3)(sqlite3@5.1.7) + version: 0.45.1(@cloudflare/workers-types@4.20260109.0)(@opentelemetry/api@1.9.0)(@types/pg@8.16.0)(bun-types@1.3.7)(pg@8.16.3)(sqlite3@5.1.7) pg: specifier: ^8.16.3 version: 8.16.3 @@ -267,7 +301,7 @@ importers: version: 6.0.25(zod@4.3.5) drizzle-orm: specifier: ^0.45.1 - version: 0.45.1(@cloudflare/workers-types@4.20260109.0)(@opentelemetry/api@1.9.0)(@types/pg@8.16.0)(bun-types@1.3.6)(pg@8.16.3)(sqlite3@5.1.7) + version: 0.45.1(@cloudflare/workers-types@4.20260109.0)(@opentelemetry/api@1.9.0)(@types/pg@8.16.0)(bun-types@1.3.7)(pg@8.16.3)(sqlite3@5.1.7) mem0ai: specifier: ^2.2.0 version: 2.2.0(@anthropic-ai/sdk@0.40.1(encoding@0.1.13))(@azure/identity@4.13.0)(@azure/search-documents@12.2.0)(@cloudflare/workers-types@4.20260109.0)(@google/genai@1.35.0(@modelcontextprotocol/sdk@1.25.2(@cfworker/json-schema@4.1.1)(hono@4.11.4)(zod@4.3.5)))(@langchain/core@0.3.80(@opentelemetry/api@1.9.0)(openai@4.104.0(encoding@0.1.13)(ws@8.19.0)(zod@4.3.5)))(@mistralai/mistralai@1.11.0)(@qdrant/js-client-rest@1.13.0(typescript@5.9.3))(@supabase/supabase-js@2.90.1)(@types/jest@29.5.14)(@types/pg@8.16.0)(@types/sqlite3@3.1.11)(cloudflare@4.5.0(encoding@0.1.13))(encoding@0.1.13)(groq-sdk@0.3.0(encoding@0.1.13))(neo4j-driver@5.28.2)(ollama@0.5.18)(pg@8.16.3)(redis@4.7.1)(sqlite3@5.1.7)(ws@8.19.0) @@ -279,10 +313,10 @@ importers: dependencies: '@elysiajs/cors': specifier: ^1.4.1 - version: 1.4.1(elysia@1.4.21(@sinclair/typebox@0.34.47)(@types/bun@1.3.6)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3)) + version: 1.4.1(elysia@1.4.21(@sinclair/typebox@0.34.47)(@types/bun@1.3.7)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3)) elysia: specifier: ^1.4.21 - version: 1.4.21(@sinclair/typebox@0.34.47)(@types/bun@1.3.6)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3) + version: 1.4.21(@sinclair/typebox@0.34.47)(@types/bun@1.3.7)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3) zod: specifier: ^4.3.5 version: 4.3.5 @@ -2155,8 +2189,8 @@ packages: '@types/argparse@1.0.38': resolution: {integrity: sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==} - '@types/bun@1.3.6': - resolution: {integrity: sha512-uWCv6FO/8LcpREhenN1d1b6fcspAB+cefwD7uti8C8VffIv0Um08TKMn98FynpTiU38+y2dUO55T11NgDt8VAA==} + '@types/bun@1.3.7': + resolution: {integrity: sha512-lmNuMda+Z9b7tmhA0tohwy8ZWFSnmQm1UDWXtH5r9F7wZCfkeO3Jx7wKQ1EOiKq43yHts7ky6r8SDJQWRNupkA==} '@types/chai@5.2.3': resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} @@ -2762,8 +2796,8 @@ packages: buffer@6.0.3: resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} - bun-types@1.3.6: - resolution: {integrity: sha512-OlFwHcnNV99r//9v5IIOgQ9Uk37gZqrNMCcqEaExdkVq3Avwqok1bJFmvGMCkCE0FqzdY8VMOZpfpR3lwI+CsQ==} + bun-types@1.3.7: + resolution: {integrity: sha512-qyschsA03Qz+gou+apt6HNl6HnI+sJJLL4wLDke4iugsE6584CMupOtTY1n+2YC9nGVrEKUlTs99jjRLKgWnjQ==} bundle-name@4.1.0: resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} @@ -6094,35 +6128,35 @@ snapshots: '@drizzle-team/brocli@0.10.2': {} - '@elysiajs/bearer@1.4.2(elysia@1.4.22(@sinclair/typebox@0.34.47)(@types/bun@1.3.6)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3))': + '@elysiajs/bearer@1.4.2(elysia@1.4.22(@sinclair/typebox@0.34.47)(@types/bun@1.3.7)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3))': dependencies: - elysia: 1.4.22(@sinclair/typebox@0.34.47)(@types/bun@1.3.6)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3) + elysia: 1.4.22(@sinclair/typebox@0.34.47)(@types/bun@1.3.7)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3) - '@elysiajs/cors@1.4.1(elysia@1.4.21(@sinclair/typebox@0.34.47)(@types/bun@1.3.6)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3))': + '@elysiajs/cors@1.4.1(elysia@1.4.21(@sinclair/typebox@0.34.47)(@types/bun@1.3.7)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3))': dependencies: - elysia: 1.4.21(@sinclair/typebox@0.34.47)(@types/bun@1.3.6)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3) + elysia: 1.4.21(@sinclair/typebox@0.34.47)(@types/bun@1.3.7)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3) - '@elysiajs/cors@1.4.1(elysia@1.4.22(@sinclair/typebox@0.34.47)(@types/bun@1.3.6)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3))': + '@elysiajs/cors@1.4.1(elysia@1.4.22(@sinclair/typebox@0.34.47)(@types/bun@1.3.7)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3))': dependencies: - elysia: 1.4.22(@sinclair/typebox@0.34.47)(@types/bun@1.3.6)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3) + elysia: 1.4.22(@sinclair/typebox@0.34.47)(@types/bun@1.3.7)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3) - '@elysiajs/cron@1.4.1(elysia@1.4.22(@sinclair/typebox@0.34.47)(@types/bun@1.3.6)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3))': + '@elysiajs/cron@1.4.1(elysia@1.4.22(@sinclair/typebox@0.34.47)(@types/bun@1.3.7)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3))': dependencies: croner: 6.0.7 - elysia: 1.4.22(@sinclair/typebox@0.34.47)(@types/bun@1.3.6)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3) + elysia: 1.4.22(@sinclair/typebox@0.34.47)(@types/bun@1.3.7)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3) - '@elysiajs/eden@1.4.6(elysia@1.4.22(@sinclair/typebox@0.34.47)(@types/bun@1.3.6)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3))': + '@elysiajs/eden@1.4.6(elysia@1.4.22(@sinclair/typebox@0.34.47)(@types/bun@1.3.7)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3))': dependencies: - elysia: 1.4.22(@sinclair/typebox@0.34.47)(@types/bun@1.3.6)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3) + elysia: 1.4.22(@sinclair/typebox@0.34.47)(@types/bun@1.3.7)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3) - '@elysiajs/jwt@1.4.0(elysia@1.4.22(@sinclair/typebox@0.34.47)(@types/bun@1.3.6)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3))': + '@elysiajs/jwt@1.4.0(elysia@1.4.22(@sinclair/typebox@0.34.47)(@types/bun@1.3.7)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3))': dependencies: - elysia: 1.4.22(@sinclair/typebox@0.34.47)(@types/bun@1.3.6)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3) + elysia: 1.4.22(@sinclair/typebox@0.34.47)(@types/bun@1.3.7)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3) jose: 6.1.3 - '@elysiajs/openapi@1.4.13(elysia@1.4.22(@sinclair/typebox@0.34.47)(@types/bun@1.3.6)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3))': + '@elysiajs/openapi@1.4.13(elysia@1.4.22(@sinclair/typebox@0.34.47)(@types/bun@1.3.7)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3))': dependencies: - elysia: 1.4.22(@sinclair/typebox@0.34.47)(@types/bun@1.3.6)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3) + elysia: 1.4.22(@sinclair/typebox@0.34.47)(@types/bun@1.3.7)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3) '@esbuild-kit/core-utils@3.3.2': dependencies: @@ -7167,9 +7201,9 @@ snapshots: '@types/argparse@1.0.38': {} - '@types/bun@1.3.6': + '@types/bun@1.3.7': dependencies: - bun-types: 1.3.6 + bun-types: 1.3.7 '@types/chai@5.2.3': dependencies: @@ -7935,9 +7969,9 @@ snapshots: base64-js: 1.5.1 ieee754: 1.2.1 - bun-types@1.3.6: + bun-types@1.3.7: dependencies: - '@types/node': 25.0.3 + '@types/node': 24.10.4 bundle-name@4.1.0: dependencies: @@ -8174,12 +8208,12 @@ snapshots: transitivePeerDependencies: - supports-color - drizzle-orm@0.45.1(@cloudflare/workers-types@4.20260109.0)(@opentelemetry/api@1.9.0)(@types/pg@8.16.0)(bun-types@1.3.6)(pg@8.16.3)(sqlite3@5.1.7): + drizzle-orm@0.45.1(@cloudflare/workers-types@4.20260109.0)(@opentelemetry/api@1.9.0)(@types/pg@8.16.0)(bun-types@1.3.7)(pg@8.16.3)(sqlite3@5.1.7): optionalDependencies: '@cloudflare/workers-types': 4.20260109.0 '@opentelemetry/api': 1.9.0 '@types/pg': 8.16.0 - bun-types: 1.3.6 + bun-types: 1.3.7 pg: 8.16.3 sqlite3: 5.1.7 @@ -8199,7 +8233,7 @@ snapshots: electron-to-chromium@1.5.267: {} - elysia@1.4.21(@sinclair/typebox@0.34.47)(@types/bun@1.3.6)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3): + elysia@1.4.21(@sinclair/typebox@0.34.47)(@types/bun@1.3.7)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3): dependencies: '@sinclair/typebox': 0.34.47 cookie: 1.1.1 @@ -8209,10 +8243,10 @@ snapshots: memoirist: 0.4.0 openapi-types: 12.1.3 optionalDependencies: - '@types/bun': 1.3.6 + '@types/bun': 1.3.7 typescript: 5.9.3 - elysia@1.4.22(@sinclair/typebox@0.34.47)(@types/bun@1.3.6)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3): + elysia@1.4.22(@sinclair/typebox@0.34.47)(@types/bun@1.3.7)(exact-mirror@0.2.6(@sinclair/typebox@0.34.47))(file-type@21.3.0)(openapi-types@12.1.3)(typescript@5.9.3): dependencies: '@sinclair/typebox': 0.34.47 cookie: 1.1.1 @@ -8222,7 +8256,7 @@ snapshots: memoirist: 0.4.0 openapi-types: 12.1.3 optionalDependencies: - '@types/bun': 1.3.6 + '@types/bun': 1.3.7 typescript: 5.9.3 emoji-regex-xs@1.0.0: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index c1390add..df86debd 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,6 +1,7 @@ packages: - 'packages/*' - 'docs' + - 'agent' onlyBuiltDependencies: - sqlite3 \ No newline at end of file