From ad9ee895860dc09b1f3241c16a8baf83924d1092 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E5=B2=A9=E5=B2=A9?= Date: Fri, 10 Jul 2026 15:58:32 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20=E9=A1=B9=E7=9B=AE=E7=BB=93?= =?UTF-8?q?=E6=9E=84=E9=87=8D=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/copilot-instructions.md | 17 ++ .gitignore | 4 +- docs/design.md | 178 ++++++++++++++++++ package.json | 15 +- packages/cli/package.json | 19 ++ packages/cli/src/index.ts | 1 + packages/cli/tsconfig.json | 7 + packages/core/package.json | 19 ++ packages/core/src/index.ts | 6 + packages/core/tsconfig.json | 7 + packages/desktop/package.json | 19 ++ packages/desktop/src/main.ts | 1 + packages/desktop/tsconfig.json | 7 + .../old/knowledge}/llm-to-agent-guide.md | 0 packages/old/package.json | 18 ++ {src => packages/old/src}/agents/agent.ts | 0 {src => packages/old/src}/agents/index.ts | 0 {src => packages/old/src}/agents/manager.ts | 0 {src => packages/old/src}/agents/tools.ts | 0 {src => packages/old/src}/context.ts | 0 {src => packages/old/src}/hooks/index.ts | 0 {src => packages/old/src}/hooks/log.hooks.ts | 0 {src => packages/old/src}/hooks/registry.ts | 0 {src => packages/old/src}/index.ts | 0 .../old/src}/knowledge/knowledge-base.ts | 0 .../old/src}/knowledge/search-tool.ts | 0 {src => packages/old/src}/llm.ts | 0 .../old/src}/prompts/orchestrator.ts | 0 {src => packages/old/src}/prompts/reAct.ts | 0 {src => packages/old/src}/prompts/system.ts | 0 {src => packages/old/src}/tools/calculator.ts | 0 {src => packages/old/src}/tools/guess.ts | 0 {src => packages/old/src}/tools/registry.ts | 0 {src => packages/old/src}/tools/weather.ts | 0 {src => packages/old/src}/types/index.ts | 0 packages/old/tsconfig.json | 7 + packages/plugins-builtin/package.json | 16 ++ packages/plugins-builtin/src/index.ts | 1 + packages/plugins-builtin/tsconfig.json | 7 + packages/server/package.json | 19 ++ packages/server/src/index.ts | 1 + packages/server/tsconfig.json | 7 + packages/tests/package.json | 19 ++ packages/tests/src/core.test.ts | 17 ++ packages/tests/src/plugins-builtin.test.ts | 11 ++ packages/tests/src/types.test.ts | 57 ++++++ packages/tests/tsconfig.json | 7 + packages/types/package.json | 12 ++ packages/types/src/index.ts | 46 +++++ packages/types/tsconfig.json | 7 + packages/web/index.html | 14 ++ packages/web/package.json | 10 + pnpm-workspace.yaml | 2 + tsconfig.json | 4 + 54 files changed, 575 insertions(+), 7 deletions(-) create mode 100644 .github/copilot-instructions.md create mode 100644 docs/design.md create mode 100644 packages/cli/package.json create mode 100644 packages/cli/src/index.ts create mode 100644 packages/cli/tsconfig.json create mode 100644 packages/core/package.json create mode 100644 packages/core/src/index.ts create mode 100644 packages/core/tsconfig.json create mode 100644 packages/desktop/package.json create mode 100644 packages/desktop/src/main.ts create mode 100644 packages/desktop/tsconfig.json rename {knowledge => packages/old/knowledge}/llm-to-agent-guide.md (100%) create mode 100644 packages/old/package.json rename {src => packages/old/src}/agents/agent.ts (100%) rename {src => packages/old/src}/agents/index.ts (100%) rename {src => packages/old/src}/agents/manager.ts (100%) rename {src => packages/old/src}/agents/tools.ts (100%) rename {src => packages/old/src}/context.ts (100%) rename {src => packages/old/src}/hooks/index.ts (100%) rename {src => packages/old/src}/hooks/log.hooks.ts (100%) rename {src => packages/old/src}/hooks/registry.ts (100%) rename {src => packages/old/src}/index.ts (100%) rename {src => packages/old/src}/knowledge/knowledge-base.ts (100%) rename {src => packages/old/src}/knowledge/search-tool.ts (100%) rename {src => packages/old/src}/llm.ts (100%) rename {src => packages/old/src}/prompts/orchestrator.ts (100%) rename {src => packages/old/src}/prompts/reAct.ts (100%) rename {src => packages/old/src}/prompts/system.ts (100%) rename {src => packages/old/src}/tools/calculator.ts (100%) rename {src => packages/old/src}/tools/guess.ts (100%) rename {src => packages/old/src}/tools/registry.ts (100%) rename {src => packages/old/src}/tools/weather.ts (100%) rename {src => packages/old/src}/types/index.ts (100%) create mode 100644 packages/old/tsconfig.json create mode 100644 packages/plugins-builtin/package.json create mode 100644 packages/plugins-builtin/src/index.ts create mode 100644 packages/plugins-builtin/tsconfig.json create mode 100644 packages/server/package.json create mode 100644 packages/server/src/index.ts create mode 100644 packages/server/tsconfig.json create mode 100644 packages/tests/package.json create mode 100644 packages/tests/src/core.test.ts create mode 100644 packages/tests/src/plugins-builtin.test.ts create mode 100644 packages/tests/src/types.test.ts create mode 100644 packages/tests/tsconfig.json create mode 100644 packages/types/package.json create mode 100644 packages/types/src/index.ts create mode 100644 packages/types/tsconfig.json create mode 100644 packages/web/index.html create mode 100644 packages/web/package.json create mode 100644 pnpm-workspace.yaml diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..487c65e --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,17 @@ +# 开发准则 + +## 驾驭约束 + +* **开始任务前先明确任务内容**:不允许为了不报错正确而随意修改架构/目录/接口,不允许为了结果不报错而随意修改测试用例 +* **先读文档再动手**:涉及架构/目录/接口的修改,必须先读 `docs/design.md` +* **只实现当前要求的**:禁止预建未来可能需要的模块、方法、字段 +* **最小改动范围**:每次只改最少的文件,改完一批确认一批,不要一口气创建大量文件 +* **改前先读**:编辑任何文件前必须先 `read_file` 确认当前内容(用户可能已手动修改) +* **禁止 `npx tsx -e` 内联测试**:测试代码统一写到 `packages/tests/src/` 下,用 `pnpm test` 运行 +* **改后必验证**:代码改动后运行 `pnpm test`,确保用例全通过 + +## 代码风格 + +* 不得为简单的需求过度抽象和设计 +* 简单功能不需要写注释 +* 临时文件统一放在 `tmp` 目录下,且必须在 `.gitignore` 中忽略 \ No newline at end of file diff --git a/.gitignore b/.gitignore index b4b4711..4c5307c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ node_modules .env -pnpm-lock.yaml \ No newline at end of file +pnpm-lock.yaml +.DS_Store +tmp \ No newline at end of file diff --git a/docs/design.md b/docs/design.md new file mode 100644 index 0000000..9c44769 --- /dev/null +++ b/docs/design.md @@ -0,0 +1,178 @@ +# llm-to-agent 设计文档 + +## 架构设计 + +### 核心理念:微内核 + 事件驱动 + +Agent 的本质是一个循环:**用户输入 → LLM 思考 → 工具调用 → LLM 再思考 → 最终回复**。 + +本项目的答案是:**内核只做一件事——驱动这个循环**。LLM 调用、工具执行、日志输出等一切能力全部通过事件总线交给外部插件。 + +### 三层架构 + +``` +┌──────────────────────────────────────────┐ +│ Route 层 CLI / Desktop / Web │ ← 只决定 I/O 方式 +├──────────────────────────────────────────┤ +│ Plugin 层 provider / tool / hook │ ← 可替换的能力单元 +├──────────────────────────────────────────┤ +│ Core 层 Scheduler + HookBus │ ← 只做循环 + 事件路由 +└──────────────────────────────────────────┘ +``` + +### 事件总线 + +内核循环的每一步都通过 `HookBus` 发出事件,插件注册响应,形成“事件驱动 + 插件化”的架构。 + +### 插件类型 + +| 类型 | 职责 | 响应的事件 | +|------|------|-----------| +| `provider` | LLM 提供商适配 | `llm:call`、`tool:select` | +| `tool` | 工具能力 | `tool:schema`、`tool:execute` | +| `hook` | 生命周期副作用 | `tool:before`、`tool:after`、`run:end` | +| `prompt` | 系统提示词 | 通过配置注入,不响应事件 | + +每个插件通过 `manifest.json` 声明元信息(名称、类型、提供的能力、适用平台),由 `PluginManager` 统一加载。 + +### 三条产品线 + +``` + ┌── @llm-to-agent/core ──┐ + │ MicroKernel + HookBus │ + └────────────────────────┘ + │ + ┌─────────────────┼─────────────────┐ + ▼ ▼ ▼ + CLI Desktop Web + (readline) (Electron) (Browser HTTP) + │ │ │ + ┌───────┴────────┐ ┌──────┴───────┐ ┌──────┴───────┐ + │ 本地工具全部 │ │ 同 CLI │ │ 仅远程工具 │ + │ console 日志 │ │ IPC 日志 │ │ SSE 日志 │ + └────────────────┘ └──────────────┘ └──────────────┘ +``` + +CLI 与 Desktop 共享本地工具(文件读写、Shell 执行),Web 端通过 `platforms` 字段自动跳过本地工具。 + +--- + +## 项目目录设计 + +### Monorepo 结构(pnpm workspace) + +``` +llm-to-agent/ +├── pnpm-workspace.yaml +├── package.json ← 根(private,统一 dev/test 脚本) +├── tsconfig.json +│ +├── docs/ ← 设计文档 +│ └── design.md +│ +├── packages/ +│ │ +│ ├── types/ ← @llm-to-agent/types +│ │ └── src/index.ts ← 所有共享类型(Message/ToolDef/PluginManifest/...) +│ │ +│ ├── core/ ← @llm-to-agent/core +│ │ └── src/ +│ │ ├── hook-bus.ts ← 事件总线(on/emit/request/collect) +│ │ ├── scheduler.ts ← Agent 循环(think→tool→think) +│ │ ├── context.ts ← 消息上下文管理器 +│ │ ├── plugin-manager.ts← 插件加载 + 生命周期 +│ │ └── kernel.ts ← MicroKernel 入口(组合以上模块) +│ │ +│ ├── plugins-builtin/ ← @llm-to-agent/plugins-builtin +│ │ └── [xxxxx]/ ← 内置插件 +│ │ +│ ├── cli/ ← @llm-to-agent/cli(终端入口) +│ │ └── src/index.ts ← readline 循环 + kernel.init([...]) +│ │ +│ ├── desktop/ ← @llm-to-agent/desktop(桌面入口) +│ │ └── src/main.ts ← Electron 主进程 +│ │ +│ ├── server/ ← @llm-to-agent/server(Web 后端) +│ │ └── src/index.ts ← Express + SSE +│ │ +│ ├── web/ ← @llm-to-agent/web(Web 前端) +│ │ └── index.html ← 待实现 React 聊天界面 +│ │ +│ ├── tests/ ← @llm-to-agent/tests +│ │ └── src/ ← *.test.ts(Node 原生 test runner) +│ │ +│ └── old/ ← @llm-to-agent/old(旧代码归档) +│ └── src/ ← 重构前的 Agent 实现 +``` + +### 包依赖关系 + +``` +@llm-to-agent/types ← 零依赖,纯类型 + ↑ ↑ + core plugins-builtin + ↑ ↑ + ├───────────┴────────────┐ + ↓ ↓ ↓ + cli desktop server + ↑ + web +``` + +### 插件清单规范 + +每个插件目录包含 `manifest.json`: + +```json +{ + "name": "@agent/tool-file", + "version": "1.0.0", + "type": "tool", + "provides": ["file-read", "file-write"], + "entry": "./index.ts", + "platforms": ["cli", "desktop"] +} +``` + +| 字段 | 说明 | +|------|------| +| `type` | `provider` / `tool` / `hook` / `prompt` | +| `provides` | 提供的能力标识 | +| `entry` | 入口文件,默认导出 `register(bus: HookBus)` | +| `platforms` | 可用平台,PluginManager 加载时自动过滤 | + +### 关键类型 + +```typescript +// 消息 +interface Message { + role: 'system' | 'user' | 'assistant' | 'tool'; + content: string; + tool_calls?: ToolCall[]; + tool_call_id?: string; +} + +// 工具定义(OpenAI 兼容) +interface ToolDef { + type: 'function'; + function: { + name: string; + description: string; + parameters: Record; + }; +} + +// 插件清单 +interface PluginManifest { + name: string; + version: string; + type: 'provider' | 'tool' | 'hook' | 'prompt'; + provides: string | string[]; + entry: string; + platforms?: ('cli' | 'desktop' | 'web')[]; +} + +// 事件总线 +type EventName = string; +type Listener = (data: any) => any | Promise; +``` diff --git a/package.json b/package.json index 9c4262c..7597174 100644 --- a/package.json +++ b/package.json @@ -1,13 +1,16 @@ { "name": "llm-to-agent", - "version": "0.1.0", + "version": "0.2.0", + "private": true, "type": "module", "scripts": { - "dev": "tsx src/index.ts" - }, - "dependencies": { - "dotenv": "^16.x", - "openai": "^4.x" + "dev": "pnpm --filter @llm-to-agent/cli dev", + "dev:old": "pnpm --filter @llm-to-agent/old dev", + "dev:core": "pnpm --filter @llm-to-agent/core dev", + "dev:server": "pnpm --filter @llm-to-agent/server dev", + "dev:web": "pnpm --filter @llm-to-agent/web dev", + "dev:desktop": "pnpm --filter @llm-to-agent/desktop dev", + "test": "pnpm --filter @llm-to-agent/tests test" }, "devDependencies": { "@types/node": "^25.9.1", diff --git a/packages/cli/package.json b/packages/cli/package.json new file mode 100644 index 0000000..04314a7 --- /dev/null +++ b/packages/cli/package.json @@ -0,0 +1,19 @@ +{ + "name": "@llm-to-agent/cli", + "version": "0.1.0", + "type": "module", + "private": true, + "main": "./src/index.ts", + "scripts": { + "dev": "tsx src/index.ts" + }, + "dependencies": { + "@llm-to-agent/core": "workspace:*", + "@llm-to-agent/plugins-builtin": "workspace:*" + }, + "devDependencies": { + "@types/node": "^25.9.1", + "tsx": "^4.x", + "typescript": "^5.x" + } +} diff --git a/packages/cli/src/index.ts b/packages/cli/src/index.ts new file mode 100644 index 0000000..ad1964e --- /dev/null +++ b/packages/cli/src/index.ts @@ -0,0 +1 @@ +console.log('🚀 LLM-to-Agent CLI 初始化已完成,待开发。\n'); diff --git a/packages/cli/tsconfig.json b/packages/cli/tsconfig.json new file mode 100644 index 0000000..f27ff83 --- /dev/null +++ b/packages/cli/tsconfig.json @@ -0,0 +1,7 @@ +{ + "compilerOptions": { + "module": "esnext", + "moduleResolution": "bundler", + "types": ["node"] + } +} diff --git a/packages/core/package.json b/packages/core/package.json new file mode 100644 index 0000000..0a7ee4e --- /dev/null +++ b/packages/core/package.json @@ -0,0 +1,19 @@ +{ + "name": "@llm-to-agent/core", + "version": "0.1.0", + "type": "module", + "private": true, + "main": "./src/index.ts", + "types": "./src/index.ts", + "scripts": { + "dev": "tsx src/index.ts" + }, + "dependencies": { + "@llm-to-agent/types": "workspace:*" + }, + "devDependencies": { + "@types/node": "^25.9.1", + "tsx": "^4.x", + "typescript": "^5.x" + } +} diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts new file mode 100644 index 0000000..817e4a2 --- /dev/null +++ b/packages/core/src/index.ts @@ -0,0 +1,6 @@ +export * from '@llm-to-agent/types'; + +export const init = () => { + console.log('🚀 Core 入口已初始化完成,待开发。'); +} + diff --git a/packages/core/tsconfig.json b/packages/core/tsconfig.json new file mode 100644 index 0000000..f27ff83 --- /dev/null +++ b/packages/core/tsconfig.json @@ -0,0 +1,7 @@ +{ + "compilerOptions": { + "module": "esnext", + "moduleResolution": "bundler", + "types": ["node"] + } +} diff --git a/packages/desktop/package.json b/packages/desktop/package.json new file mode 100644 index 0000000..a2f5e4e --- /dev/null +++ b/packages/desktop/package.json @@ -0,0 +1,19 @@ +{ + "name": "@llm-to-agent/desktop", + "version": "0.1.0", + "type": "module", + "private": true, + "main": "./src/main.ts", + "scripts": { + "dev": "tsx './src/main.ts'" + }, + "dependencies": { + "@llm-to-agent/core": "workspace:*", + "@llm-to-agent/plugins-builtin": "workspace:*" + }, + "devDependencies": { + "@types/node": "^25.9.1", + "tsx": "^4.x", + "typescript": "^5.x" + } +} diff --git a/packages/desktop/src/main.ts b/packages/desktop/src/main.ts new file mode 100644 index 0000000..1c84edc --- /dev/null +++ b/packages/desktop/src/main.ts @@ -0,0 +1 @@ +console.log('🚀 Desktop 入口已初始化完成,待开发。'); diff --git a/packages/desktop/tsconfig.json b/packages/desktop/tsconfig.json new file mode 100644 index 0000000..f27ff83 --- /dev/null +++ b/packages/desktop/tsconfig.json @@ -0,0 +1,7 @@ +{ + "compilerOptions": { + "module": "esnext", + "moduleResolution": "bundler", + "types": ["node"] + } +} diff --git a/knowledge/llm-to-agent-guide.md b/packages/old/knowledge/llm-to-agent-guide.md similarity index 100% rename from knowledge/llm-to-agent-guide.md rename to packages/old/knowledge/llm-to-agent-guide.md diff --git a/packages/old/package.json b/packages/old/package.json new file mode 100644 index 0000000..92310d0 --- /dev/null +++ b/packages/old/package.json @@ -0,0 +1,18 @@ +{ + "name": "@llm-to-agent/old", + "version": "0.2.0", + "type": "module", + "private": true, + "scripts": { + "dev": "tsx src/index.ts" + }, + "dependencies": { + "dotenv": "^16.x", + "openai": "^4.x" + }, + "devDependencies": { + "@types/node": "^25.9.1", + "tsx": "^4.x", + "typescript": "^5.x" + } +} diff --git a/src/agents/agent.ts b/packages/old/src/agents/agent.ts similarity index 100% rename from src/agents/agent.ts rename to packages/old/src/agents/agent.ts diff --git a/src/agents/index.ts b/packages/old/src/agents/index.ts similarity index 100% rename from src/agents/index.ts rename to packages/old/src/agents/index.ts diff --git a/src/agents/manager.ts b/packages/old/src/agents/manager.ts similarity index 100% rename from src/agents/manager.ts rename to packages/old/src/agents/manager.ts diff --git a/src/agents/tools.ts b/packages/old/src/agents/tools.ts similarity index 100% rename from src/agents/tools.ts rename to packages/old/src/agents/tools.ts diff --git a/src/context.ts b/packages/old/src/context.ts similarity index 100% rename from src/context.ts rename to packages/old/src/context.ts diff --git a/src/hooks/index.ts b/packages/old/src/hooks/index.ts similarity index 100% rename from src/hooks/index.ts rename to packages/old/src/hooks/index.ts diff --git a/src/hooks/log.hooks.ts b/packages/old/src/hooks/log.hooks.ts similarity index 100% rename from src/hooks/log.hooks.ts rename to packages/old/src/hooks/log.hooks.ts diff --git a/src/hooks/registry.ts b/packages/old/src/hooks/registry.ts similarity index 100% rename from src/hooks/registry.ts rename to packages/old/src/hooks/registry.ts diff --git a/src/index.ts b/packages/old/src/index.ts similarity index 100% rename from src/index.ts rename to packages/old/src/index.ts diff --git a/src/knowledge/knowledge-base.ts b/packages/old/src/knowledge/knowledge-base.ts similarity index 100% rename from src/knowledge/knowledge-base.ts rename to packages/old/src/knowledge/knowledge-base.ts diff --git a/src/knowledge/search-tool.ts b/packages/old/src/knowledge/search-tool.ts similarity index 100% rename from src/knowledge/search-tool.ts rename to packages/old/src/knowledge/search-tool.ts diff --git a/src/llm.ts b/packages/old/src/llm.ts similarity index 100% rename from src/llm.ts rename to packages/old/src/llm.ts diff --git a/src/prompts/orchestrator.ts b/packages/old/src/prompts/orchestrator.ts similarity index 100% rename from src/prompts/orchestrator.ts rename to packages/old/src/prompts/orchestrator.ts diff --git a/src/prompts/reAct.ts b/packages/old/src/prompts/reAct.ts similarity index 100% rename from src/prompts/reAct.ts rename to packages/old/src/prompts/reAct.ts diff --git a/src/prompts/system.ts b/packages/old/src/prompts/system.ts similarity index 100% rename from src/prompts/system.ts rename to packages/old/src/prompts/system.ts diff --git a/src/tools/calculator.ts b/packages/old/src/tools/calculator.ts similarity index 100% rename from src/tools/calculator.ts rename to packages/old/src/tools/calculator.ts diff --git a/src/tools/guess.ts b/packages/old/src/tools/guess.ts similarity index 100% rename from src/tools/guess.ts rename to packages/old/src/tools/guess.ts diff --git a/src/tools/registry.ts b/packages/old/src/tools/registry.ts similarity index 100% rename from src/tools/registry.ts rename to packages/old/src/tools/registry.ts diff --git a/src/tools/weather.ts b/packages/old/src/tools/weather.ts similarity index 100% rename from src/tools/weather.ts rename to packages/old/src/tools/weather.ts diff --git a/src/types/index.ts b/packages/old/src/types/index.ts similarity index 100% rename from src/types/index.ts rename to packages/old/src/types/index.ts diff --git a/packages/old/tsconfig.json b/packages/old/tsconfig.json new file mode 100644 index 0000000..f27ff83 --- /dev/null +++ b/packages/old/tsconfig.json @@ -0,0 +1,7 @@ +{ + "compilerOptions": { + "module": "esnext", + "moduleResolution": "bundler", + "types": ["node"] + } +} diff --git a/packages/plugins-builtin/package.json b/packages/plugins-builtin/package.json new file mode 100644 index 0000000..b5dcd57 --- /dev/null +++ b/packages/plugins-builtin/package.json @@ -0,0 +1,16 @@ +{ + "name": "@llm-to-agent/plugins-builtin", + "version": "0.1.0", + "type": "module", + "private": true, + "main": "./src/index.ts", + "dependencies": { + "@llm-to-agent/core": "workspace:*", + "@llm-to-agent/types": "workspace:*" + }, + "devDependencies": { + "@types/node": "^25.9.1", + "tsx": "^4.x", + "typescript": "^5.x" + } +} diff --git a/packages/plugins-builtin/src/index.ts b/packages/plugins-builtin/src/index.ts new file mode 100644 index 0000000..56004c9 --- /dev/null +++ b/packages/plugins-builtin/src/index.ts @@ -0,0 +1 @@ +export default {} \ No newline at end of file diff --git a/packages/plugins-builtin/tsconfig.json b/packages/plugins-builtin/tsconfig.json new file mode 100644 index 0000000..f27ff83 --- /dev/null +++ b/packages/plugins-builtin/tsconfig.json @@ -0,0 +1,7 @@ +{ + "compilerOptions": { + "module": "esnext", + "moduleResolution": "bundler", + "types": ["node"] + } +} diff --git a/packages/server/package.json b/packages/server/package.json new file mode 100644 index 0000000..6e16493 --- /dev/null +++ b/packages/server/package.json @@ -0,0 +1,19 @@ +{ + "name": "@llm-to-agent/server", + "version": "0.1.0", + "type": "module", + "private": true, + "main": "./src/index.ts", + "scripts": { + "dev": "tsx src/index.ts" + }, + "dependencies": { + "@llm-to-agent/core": "workspace:*", + "@llm-to-agent/plugins-builtin": "workspace:*" + }, + "devDependencies": { + "@types/node": "^25.9.1", + "tsx": "^4.x", + "typescript": "^5.x" + } +} diff --git a/packages/server/src/index.ts b/packages/server/src/index.ts new file mode 100644 index 0000000..49a6c64 --- /dev/null +++ b/packages/server/src/index.ts @@ -0,0 +1 @@ +console.log('🚀 Server 入口已初始化完成,待开发。'); diff --git a/packages/server/tsconfig.json b/packages/server/tsconfig.json new file mode 100644 index 0000000..f27ff83 --- /dev/null +++ b/packages/server/tsconfig.json @@ -0,0 +1,7 @@ +{ + "compilerOptions": { + "module": "esnext", + "moduleResolution": "bundler", + "types": ["node"] + } +} diff --git a/packages/tests/package.json b/packages/tests/package.json new file mode 100644 index 0000000..a6ee9b9 --- /dev/null +++ b/packages/tests/package.json @@ -0,0 +1,19 @@ +{ + "name": "@llm-to-agent/tests", + "version": "0.1.0", + "type": "module", + "private": true, + "scripts": { + "test": "tsx --test src/**/*.test.ts" + }, + "dependencies": { + "@llm-to-agent/types": "workspace:*", + "@llm-to-agent/core": "workspace:*", + "@llm-to-agent/plugins-builtin": "workspace:*" + }, + "devDependencies": { + "@types/node": "^25.9.1", + "tsx": "^4.x", + "typescript": "^5.x" + } +} diff --git a/packages/tests/src/core.test.ts b/packages/tests/src/core.test.ts new file mode 100644 index 0000000..716ded6 --- /dev/null +++ b/packages/tests/src/core.test.ts @@ -0,0 +1,17 @@ +import { describe, it } from 'node:test'; +import assert from 'node:assert/strict'; + +import { init } from '@llm-to-agent/core'; + +describe('@llm-to-agent/core', () => { + + it('init() 不抛异常', () => { + assert.doesNotThrow(() => init()); + }); + + it('core 通过 re-export 暴露 types', async () => { + const mod = await import('@llm-to-agent/core'); + assert.equal(typeof mod.init, 'function', '应导出 init 函数'); + }); + +}); diff --git a/packages/tests/src/plugins-builtin.test.ts b/packages/tests/src/plugins-builtin.test.ts new file mode 100644 index 0000000..c7cc2fe --- /dev/null +++ b/packages/tests/src/plugins-builtin.test.ts @@ -0,0 +1,11 @@ +import { describe, it } from 'node:test'; +import assert from 'node:assert/strict'; + +describe('@llm-to-agent/plugins-builtin', () => { + + it('入口文件可正常 import', async () => { + const mod = await import('@llm-to-agent/plugins-builtin'); + assert.ok(mod.default !== undefined); + }); + +}); diff --git a/packages/tests/src/types.test.ts b/packages/tests/src/types.test.ts new file mode 100644 index 0000000..54a4fb7 --- /dev/null +++ b/packages/tests/src/types.test.ts @@ -0,0 +1,57 @@ +import { describe, it } from 'node:test'; +import assert from 'node:assert/strict'; + +import { Message, ToolCall, ToolDef, PluginManifest, SchedulerConfig, EventName, Listener } from '@llm-to-agent/types'; + +describe('@llm-to-agent/types', () => { + + it('Message 类型可正常构造', () => { + const msg: Message = { role: 'user', content: 'hello' }; + assert.equal(msg.role, 'user'); + assert.equal(msg.content, 'hello'); + }); + + it('Message 支持 tool_calls 和 tool_call_id', () => { + const tc: ToolCall = { id: '1', function: { name: 'test', arguments: '{}' } }; + const msg: Message = { role: 'assistant', content: '', tool_calls: [tc] }; + assert.equal(msg.tool_calls![0].id, '1'); + }); + + it('ToolDef 可正常构造', () => { + const tool: ToolDef = { + type: 'function', + function: { + name: 'weather', + description: '查询天气', + parameters: { type: 'object', properties: {}, required: [] }, + }, + }; + assert.equal(tool.function.name, 'weather'); + }); + + it('PluginManifest 类型完整', () => { + const manifest: PluginManifest = { + name: '@agent/test', + version: '1.0.0', + type: 'tool', + provides: ['test-tool'], + entry: './index.ts', + platforms: ['cli', 'desktop'], + }; + assert.equal(manifest.type, 'tool'); + assert.deepEqual(manifest.platforms, ['cli', 'desktop']); + }); + + it('SchedulerConfig 可正常构造', () => { + const config: SchedulerConfig = { maxSteps: 5 }; + assert.equal(config.maxSteps, 5); + }); + + it('EventName 和 Listener 类型定义正确', () => { + const name: EventName = 'llm:call'; + const fn: Listener = (data: any) => data; + assert.equal(typeof fn, 'function'); + assert.equal(name, 'llm:call'); + }); + +}); diff --git a/packages/tests/tsconfig.json b/packages/tests/tsconfig.json new file mode 100644 index 0000000..f27ff83 --- /dev/null +++ b/packages/tests/tsconfig.json @@ -0,0 +1,7 @@ +{ + "compilerOptions": { + "module": "esnext", + "moduleResolution": "bundler", + "types": ["node"] + } +} diff --git a/packages/types/package.json b/packages/types/package.json new file mode 100644 index 0000000..9844c38 --- /dev/null +++ b/packages/types/package.json @@ -0,0 +1,12 @@ +{ + "name": "@llm-to-agent/types", + "version": "0.1.0", + "type": "module", + "private": true, + "main": "./src/index.ts", + "types": "./src/index.ts", + "scripts": {}, + "devDependencies": { + "typescript": "^5.x" + } +} diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts new file mode 100644 index 0000000..99f958c --- /dev/null +++ b/packages/types/src/index.ts @@ -0,0 +1,46 @@ +// ===== Agent 消息 ===== + +export interface Message { + role: 'system' | 'user' | 'assistant' | 'tool'; + content: string; + tool_calls?: ToolCall[]; + tool_call_id?: string; +} + +export interface ToolCall { + id: string; + function: { name: string; arguments: string }; +} + +// ===== 工具 ===== + +export interface ToolDef { + type: 'function'; + function: { + name: string; + description: string; + parameters: Record; + }; +} + +// ===== 插件 ===== + +export interface PluginManifest { + name: string; + version: string; + type: 'provider' | 'tool' | 'hook' | 'prompt'; + provides: string | string[]; + entry: string; + platforms?: ('cli' | 'desktop' | 'web')[]; +} + +// ===== 事件总线 ===== + +export type EventName = string; +export type Listener = (data: any) => any | Promise; + +// ===== 调度器 ===== + +export interface SchedulerConfig { + maxSteps?: number; +} diff --git a/packages/types/tsconfig.json b/packages/types/tsconfig.json new file mode 100644 index 0000000..efdc208 --- /dev/null +++ b/packages/types/tsconfig.json @@ -0,0 +1,7 @@ +{ + "compilerOptions": { + "module": "esnext", + "moduleResolution": "bundler", + "types": [] + } +} diff --git a/packages/web/index.html b/packages/web/index.html new file mode 100644 index 0000000..b2cd966 --- /dev/null +++ b/packages/web/index.html @@ -0,0 +1,14 @@ + + + + + + LLM-to-Agent Web + + +
+

🚀 LLM-to-Agent Web

+

占位页面,待实现 React 聊天界面。

+
+ + diff --git a/packages/web/package.json b/packages/web/package.json new file mode 100644 index 0000000..cf96ca1 --- /dev/null +++ b/packages/web/package.json @@ -0,0 +1,10 @@ +{ + "name": "@llm-to-agent/web", + "version": "0.1.0", + "type": "module", + "private": true, + "scripts": { + "dev": "echo 'TODO: vite dev'", + "build": "echo 'TODO: vite build'" + } +} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 0000000..18ec407 --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,2 @@ +packages: + - 'packages/*' diff --git a/tsconfig.json b/tsconfig.json index 057c24d..2a77da6 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,7 +1,11 @@ { "compilerOptions": { + "target": "ES2022", "module": "esnext", "moduleResolution": "bundler", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, "types": ["node"] } } \ No newline at end of file