From ddafdb5491686b272fd0c3a47ca9c14a3c0425af Mon Sep 17 00:00:00 2001 From: lwmacct Date: Thu, 4 Dec 2025 19:04:56 +0800 Subject: [PATCH 1/2] style: format code with prettier --- client-sdks/client-js/README.md | 303 +++++----- client-sdks/client-js/docs/API.md | 439 +++++++------- client-sdks/client-js/docs/QUICKSTART.md | 319 +++++------ client-sdks/client-js/examples/agent-usage.ts | 306 +++++----- .../client-js/examples/complete-usage.ts | 354 +++++++----- client-sdks/client-js/examples/eval-usage.ts | 322 ++++++----- .../client-js/examples/event-subscription.ts | 89 +-- .../client-js/examples/mcp-middleware-tool.ts | 316 +++++----- .../client-js/examples/memory-usage.ts | 210 +++---- .../client-js/examples/session-workflow.ts | 251 ++++---- client-sdks/client-js/package.json | 1 - client-sdks/client-js/src/client.ts | 42 +- .../client-js/src/events/subscription.ts | 56 +- client-sdks/client-js/src/events/types.ts | 70 +-- client-sdks/client-js/src/index.ts | 60 +- client-sdks/client-js/src/resources/agent.ts | 120 ++-- client-sdks/client-js/src/resources/base.ts | 69 ++- client-sdks/client-js/src/resources/eval.ts | 133 ++--- client-sdks/client-js/src/resources/mcp.ts | 67 ++- client-sdks/client-js/src/resources/memory.ts | 147 +++-- .../client-js/src/resources/middleware.ts | 52 +- .../client-js/src/resources/session.ts | 129 ++--- client-sdks/client-js/src/resources/system.ts | 22 +- .../client-js/src/resources/telemetry.ts | 135 ++--- client-sdks/client-js/src/resources/tool.ts | 91 ++- .../client-js/src/resources/workflow.ts | 115 ++-- .../client-js/src/transport/websocket.ts | 89 +-- client-sdks/client-js/src/types/agent.ts | 44 +- client-sdks/client-js/src/types/eval.ts | 52 +- client-sdks/client-js/src/types/mcp.ts | 26 +- client-sdks/client-js/src/types/memory.ts | 28 +- client-sdks/client-js/src/types/middleware.ts | 69 +-- client-sdks/client-js/src/types/session.ts | 34 +- client-sdks/client-js/src/types/telemetry.ts | 48 +- client-sdks/client-js/src/types/tool.ts | 56 +- client-sdks/client-js/src/types/workflow.ts | 42 +- client-sdks/client-js/test_client.js | 215 +++---- .../client-js/tests/events/types.test.ts | 231 ++++---- .../client-js/tests/integration.test.ts | 227 ++++---- .../tests/integration/client.test.ts | 405 +++++++------ .../client-js/tests/resources/memory.test.ts | 457 ++++++++------- client-sdks/client-js/tsconfig.json | 1 - client-sdks/client-js/vitest.config.ts | 24 +- docs/app.config.ts | 46 +- docs/components/AppHeader.vue | 4 +- docs/content/01.introduction/1.overview.md | 18 +- docs/content/01.introduction/3.quickstart.md | 28 +- .../content/01.introduction/4.architecture.md | 76 +-- .../02.core-concepts/1.agent-lifecycle.md | 2 + .../02.core-concepts/10.subagent-system.md | 25 +- .../02.core-concepts/11.subagent-async.md | 50 +- .../02.core-concepts/12.prompt-builder.md | 63 +- .../02.core-concepts/2.event-system.md | 24 +- docs/content/02.core-concepts/3.middleware.md | 7 + docs/content/02.core-concepts/5.sandbox.md | 39 +- .../02.core-concepts/6.workflow-agents.md | 63 +- .../02.core-concepts/7.session-persistence.md | 68 +-- .../02.core-concepts/9.skills-system.md | 69 ++- docs/content/03.providers/gemini.md | 27 +- docs/content/03.providers/openai.md | 26 +- docs/content/03.providers/overview.md | 55 +- docs/content/03.providers/usage.md | 26 +- docs/content/04.memory/1.overview.md | 1 - docs/content/04.memory/2.short-vs-long.md | 1 - docs/content/04.memory/3.semantic-workflow.md | 1 - docs/content/04.memory/4.backends.md | 1 - docs/content/04.memory/5.provenance.md | 21 +- docs/content/04.memory/6.consolidation.md | 6 + .../04.memory/9.session-compression.md | 3 + docs/content/05.tools/2.builtin/1.builtin.md | 53 +- docs/content/05.tools/2.builtin/2.mcp.md | 33 +- docs/content/05.tools/2.builtin/3.custom.md | 90 +-- .../05.tools/2.builtin/4.developing-tools.md | 10 +- docs/content/05.tools/2.builtin/index.md | 6 + docs/content/05.tools/3.mcp/overview.md | 3 +- .../05.tools/4.custom/knowledge-tools.md | 4 + docs/content/05.tools/5.ptc/1.quickstart.md | 34 +- docs/content/05.tools/5.ptc/2.advanced.md | 18 +- docs/content/05.tools/5.ptc/3.architecture.md | 32 +- .../05.tools/5.ptc/4.troubleshooting.md | 46 +- docs/content/05.tools/5.ptc/index.md | 21 +- docs/content/05.tools/index.md | 4 + .../06.middleware/2.builtin/builtin.md | 89 +-- .../2.builtin/human-in-the-loop.md | 66 +-- docs/content/06.middleware/2.builtin/index.md | 39 +- .../06.middleware/2.builtin/pii-redaction.md | 4 + docs/content/06.middleware/index.md | 2 + docs/content/07.workflows/1.overview/index.md | 23 +- .../07.workflows/2.basic/1.getting-started.md | 15 +- .../07.workflows/2.basic/2.step-types.md | 27 +- .../07.workflows/3.advanced/1.router.md | 6 +- .../3.advanced/2.workflow-agent.md | 37 +- docs/content/07.workflows/index.md | 2 + docs/content/08.multi-agent/.navigation.yml | 2 +- .../08.multi-agent/1.overview/index.md | 67 ++- docs/content/08.multi-agent/4.comparison.md | 24 +- .../08.multi-agent/5.subagent-comparison.md | 135 +++-- docs/content/08.multi-agent/index.md | 22 +- docs/content/08.security/1.guardrails.md | 7 +- docs/content/09.deployment/.navigation.yml | 2 +- .../content/09.deployment/1.overview/index.md | 1 - .../09.deployment/2.local/workflow-http.md | 10 +- docs/content/09.deployment/index.md | 5 + .../10.observability/1.logging/overview.md | 26 +- .../10.observability/2.monitoring/metrics.md | 53 +- .../3.tracing/opentelemetry.md | 34 +- docs/content/10.observability/index.md | 4 + docs/content/11.evals/.navigation.yml | 2 +- docs/content/11.evals/1.overview/index.md | 45 +- docs/content/11.evals/index.md | 3 + .../12.examples/1.basic/5.custom-prompt.md | 11 +- docs/content/12.examples/1.basic/index.md | 9 +- .../content/12.examples/1.basic/multimodal.md | 14 +- docs/content/12.examples/2.memory/1.basic.md | 53 +- .../12.examples/2.memory/4.backends.md | 62 +- .../12.examples/2.memory/6.semantic-search.md | 4 +- .../12.examples/3.tools/1.file-operations.md | 16 +- .../12.examples/3.tools/2.http-requests.md | 4 + docs/content/12.examples/3.tools/index.md | 5 +- docs/content/12.examples/4.skills/index.md | 38 +- .../4.skills/markdown-translator.md | 57 +- .../5.workflows/semantic-workflow.md | 1 - .../12.examples/7.integration/client-js.md | 24 +- .../12.examples/8.scenarios/1.code-review.md | 20 +- .../8.scenarios/2.data-analysis.md | 14 +- docs/content/12.examples/8.scenarios/index.md | 5 +- docs/content/12.examples/index.md | 9 + docs/content/13.guides/.navigation.yml | 2 +- .../13.guides/1.quickstart/basic-agent.md | 1 + docs/content/13.guides/1.quickstart/index.md | 23 +- .../2.advanced/context-engineering.md | 83 ++- .../13.guides/2.advanced/human-in-the-loop.md | 86 +-- docs/content/13.guides/2.advanced/index.md | 1 + docs/content/13.guides/index.md | 5 + .../14.api-reference/1.agent/overview.md | 32 +- .../14.api-reference/10.subagent/overview.md | 1 + .../14.api-reference/2.provider/overview.md | 61 +- .../14.api-reference/3.tools/overview.md | 6 + .../14.api-reference/4.middleware/overview.md | 4 + .../14.api-reference/9.skills/overview.md | 3 +- docs/content/14.api-reference/cli.md | 4 +- docs/content/14.api-reference/index.md | 8 + .../15.best-practices/authentication.md | 41 +- docs/content/15.best-practices/deployment.md | 14 +- docs/content/15.best-practices/index.md | 12 +- docs/content/15.best-practices/monitoring.md | 32 +- docs/content/15.best-practices/performance.md | 33 +- docs/content/15.best-practices/security.md | 11 +- .../15.best-practices/skills-authoring.md | 26 +- docs/content/15.best-practices/skills.md | 47 +- docs/content/15.best-practices/testing.md | 10 +- docs/content/16.whitepaper/1.whitepaper.md | 538 ++++++++++++------ docs/content/17.about/1.wordflowlab.md | 26 +- docs/content/17.about/2.why-agentsdk.md | 92 +-- docs/content/17.about/3.roadmap.md | 110 ++-- docs/content/17.about/4.contributing.md | 87 ++- docs/content/17.about/5.release-notes.md | 18 +- docs/content/17.about/6.acknowledgements.md | 25 +- docs/content/18.architecture/1.overview.md | 45 +- docs/content/18.architecture/2.core-sdk.md | 107 ++-- docs/content/18.architecture/3.http-layer.md | 37 +- docs/content/18.architecture/4.client-sdk.md | 196 +++---- docs/content/18.architecture/hitl-overview.md | 42 +- docs/content/18.architecture/index.md | 63 +- .../18.architecture/server-architecture.md | 28 +- docs/nuxt.config.ts | 14 +- docs/package-lock.json | 12 +- docs/package.json | 2 +- docs/tailwind.config.js | 59 +- 169 files changed, 5849 insertions(+), 4666 deletions(-) diff --git a/client-sdks/client-js/README.md b/client-sdks/client-js/README.md index 652535b..3ad28a9 100644 --- a/client-sdks/client-js/README.md +++ b/client-sdks/client-js/README.md @@ -18,18 +18,22 @@ ### 当前可用功能(7.5%) ✅ **Chat 功能** - 完全可用 + - 同步对话 (`agents.chat`) - 流式对话 (`agents.chatStream`) ✅ **Skills 管理** - 完全可用 + - Skills 列表、安装、卸载 - 版本管理 🟡 **Evals** - 部分可用(11%) + - 文本评估、Session 评估、批量评估 - ❌ Test Case 管理、Benchmark、A/B Test 🟡 **Semantic Search** - 部分可用(17%) + - ✅ 搜索记忆 - ❌ 存储、删除记忆 @@ -45,6 +49,7 @@ ❌ Telemetry(100% 不可用) **详细信息**: + - [API 可用性状态](./API_AVAILABILITY.md) - 详细的功能可用性 - [后端 API 缺失分析](/BACKEND_API_GAP_ANALYSIS.md) - 缺失功能分析 - [后端 API 路线图](/BACKEND_API_ROADMAP.md) - 开发计划(预计 12-15 周) @@ -58,12 +63,14 @@ > ⚠️ 注意:以下功能已在 Client SDK 中实现,但大部分需要后端 API 支持才能使用。 #### 事件驱动架构(后端部分支持) + - ✅ 三通道事件系统(Progress/Control/Monitor) - ✅ WebSocket 客户端(自动重连、心跳) - ✅ AsyncIterable 事件订阅 - **后端状态**: 🟡 SSE 可用,WebSocket 需开发 #### Agent 管理(后端 9% 可用) + - ✅ CRUD + 状态管理(Client SDK 完成) - ✅ 同步对话(**后端可用** ✅) - ✅ 流式对话(**后端可用** ✅) @@ -72,12 +79,14 @@ - **后端状态**: 🔴 仅 Chat 可用,其他需开发 #### Session 管理(后端 0% 可用) + - ✅ CRUD + 消息管理(Client SDK 完成) - ✅ 7 段断点恢复机制(Client SDK 完成) - ✅ 统计和多格式导出(Client SDK 完成) - **后端状态**: 🔴 完全不可用,需开发 #### 三层记忆系统(后端 5% 可用) + - ✅ Working Memory(Client SDK 完成) - ✅ Semantic Memory(Client SDK 完成) - ✅ 搜索(**后端可用** ✅) @@ -87,29 +96,34 @@ - **后端状态**: 🔴 仅 search 可用,其他需开发 #### Workflow 编排(后端 0% 可用) + - ✅ Parallel/Sequential/Loop(Client SDK 完成) - ✅ 执行控制(暂停/恢复/取消)(Client SDK 完成) - **后端状态**: 🔴 仅 Demo 可用,完整功能需开发 #### MCP 协议(后端 6% 可用) + - ✅ Server 管理(Client SDK 完成) - ✅ 远程工具调用(Client SDK 完成) - ✅ 资源和 Prompt 访问(Client SDK 完成) - **后端状态**: 🔴 仅 MCP Server 可用,管理 API 需开发 #### Middleware 系统(后端 0% 可用) + - ✅ 8 个内置 Middleware(Client SDK 完成) - ✅ 洋葱模型(Client SDK 完成) - ✅ 灵活配置(Client SDK 完成) - **后端状态**: 🔴 完全不可用,需开发 #### Tool 系统(后端 0% 可用) + - ✅ 7 个内置工具(Client SDK 完成) - ✅ 同步/异步执行(Client SDK 完成) - ✅ 长时运行任务管理(Client SDK 完成) - **后端状态**: 🔴 完全不可用,需开发 #### Eval 系统(后端 11% 可用) + - ✅ 5 种 Eval 类型(Client SDK 完成) - ✅ 10 种 Scorer(Client SDK 完成) - ✅ Text/Session/Batch Eval(**后端可用** ✅) @@ -118,17 +132,20 @@ - **后端状态**: 🟡 基础 Eval 可用,高级功能需开发 #### Telemetry(后端 0% 可用) + - ✅ Metrics/Traces/Logs(Client SDK 完成) - ✅ 健康检查(Client SDK 完成) - ✅ 性能和成本统计(Client SDK 完成) - **后端状态**: 🔴 完全不可用,需开发 #### Skills 管理(后端 100% 可用)✅ + - ✅ Skills 列表、安装、卸载(**后端可用** ✅) - ✅ 版本管理(**后端可用** ✅) - **后端状态**: ✅ 完全可用 ### 后端开发计划 + - Week 4: Agent CRUD + Session 管理 - Week 8: Memory 系统 + Workflow 完整 - Week 12: Tool 管理 + Eval 扩展 @@ -156,19 +173,19 @@ yarn add @aster/client-js ### 基础 Chat ```typescript -import { AsterClient } from '@aster/client-js'; +import { AsterClient } from "@aster/client-js"; // 创建客户端 const client = new AsterClient({ - baseUrl: 'http://localhost:8080', - apiKey: process.env.ASTER_API_KEY + baseUrl: "http://localhost:8080", + apiKey: process.env.ASTER_API_KEY, }); // 同步 Chat const response = await client.agent.chat({ - templateId: 'assistant', - input: 'What is the capital of France?', - messages: [] + templateId: "assistant", + input: "What is the capital of France?", + messages: [], }); console.log(response.text); // "Paris is the capital of France." @@ -179,10 +196,10 @@ console.log(response.text); // "Paris is the capital of France." ```typescript // 流式 Chat for await (const event of client.agent.stream({ - templateId: 'assistant', - input: 'Tell me a long story' + templateId: "assistant", + input: "Tell me a long story", })) { - if (event.type === 'text_chunk') { + if (event.type === "text_chunk") { process.stdout.write(event.data.delta); } } @@ -226,42 +243,42 @@ await client.skill.deleteVersion('my-skill', 'v1.0'); ```typescript // 订阅事件(三通道) const subscription = await client.agent.subscribe( - ['progress', 'control', 'monitor'], + ["progress", "control", "monitor"], { - agentId: 'agent-123', - eventTypes: ['thinking', 'text_chunk', 'tool_start'] - } + agentId: "agent-123", + eventTypes: ["thinking", "text_chunk", "tool_start"], + }, ); // 处理事件 for await (const event of subscription) { switch (event.channel) { - case 'progress': + case "progress": // 数据流:思考、文本、工具执行 - if (event.type === 'thinking') { - console.log('AI 正在思考:', event.data.content); - } else if (event.type === 'text_chunk') { + if (event.type === "thinking") { + console.log("AI 正在思考:", event.data.content); + } else if (event.type === "text_chunk") { process.stdout.write(event.data.delta); - } else if (event.type === 'tool_start') { - console.log('调用工具:', event.data.toolName); + } else if (event.type === "tool_start") { + console.log("调用工具:", event.data.toolName); } break; - - case 'control': + + case "control": // 审批流:工具审批、暂停/恢复 - if (event.type === 'tool_approval_request') { - console.log('需要审批工具:', event.data.toolName); + if (event.type === "tool_approval_request") { + console.log("需要审批工具:", event.data.toolName); // 审批或拒绝 await client.security.approve(event.data.approvalId); } break; - - case 'monitor': + + case "monitor": // 治理流:Token、成本、合规 - if (event.type === 'token_usage') { - console.log('Token 使用:', event.data.tokens); - } else if (event.type === 'cost') { - console.log('成本:', event.data.cost); + if (event.type === "token_usage") { + console.log("Token 使用:", event.data.tokens); + } else if (event.type === "cost") { + console.log("成本:", event.data.cost); } break; } @@ -274,16 +291,19 @@ subscription.unsubscribe(); **支持的事件类型(20+)**: **Progress Channel**: + - `thinking` - 思考过程 - `text_chunk` - 流式文本 - `tool_start` / `tool_end` - 工具执行 - `done` / `error` - 完成/错误 **Control Channel**: + - `tool_approval_request` / `tool_approval_response` - 工具审批 - `pause` / `resume` - 暂停/恢复 **Monitor Channel**: + - `token_usage` - Token 使用 - `latency` - 延迟 - `cost` - 成本 @@ -297,36 +317,42 @@ subscription.unsubscribe(); ```typescript // 设置工作记忆 -await client.memory.working.set('user_preference', { - theme: 'dark', - language: 'zh-CN', - notifications: true -}, { - scope: 'thread', // 'thread' 或 'resource' - ttl: 3600, // 1 小时后过期 - schema: { // JSON Schema 验证 - type: 'object', - properties: { - theme: { type: 'string', enum: ['light', 'dark'] }, - language: { type: 'string' }, - notifications: { type: 'boolean' } +await client.memory.working.set( + "user_preference", + { + theme: "dark", + language: "zh-CN", + notifications: true, + }, + { + scope: "thread", // 'thread' 或 'resource' + ttl: 3600, // 1 小时后过期 + schema: { + // JSON Schema 验证 + type: "object", + properties: { + theme: { type: "string", enum: ["light", "dark"] }, + language: { type: "string" }, + notifications: { type: "boolean" }, + }, + required: ["theme", "language"], }, - required: ['theme', 'language'] - } -}); + }, +); // 获取工作记忆 -const preference = await client.memory.working.get('user_preference', 'thread'); +const preference = await client.memory.working.get("user_preference", "thread"); console.log(preference); // { theme: 'dark', language: 'zh-CN', ... } // 列出所有工作记忆 -const allMemories = await client.memory.working.list('thread'); +const allMemories = await client.memory.working.list("thread"); // 删除工作记忆 -await client.memory.working.delete('user_preference', 'thread'); +await client.memory.working.delete("user_preference", "thread"); ``` **特性**: + - ✅ **双作用域**: Thread(会话级)和 Resource(全局) - ✅ **LLM 可主动更新**: 通过内置工具 - ✅ **自动加载**: 自动添加到 system prompt @@ -342,21 +368,21 @@ await client.memory.working.delete('user_preference', 'thread'); ```typescript // 存储记忆 const chunkId = await client.memory.semantic.store( - 'Paris is the capital of France.', + "Paris is the capital of France.", { - source: 'wikipedia', - category: 'geography' - } + source: "wikipedia", + category: "geography", + }, ); // 语义搜索 const results = await client.memory.semantic.search( - 'What is the capital of France?', + "What is the capital of France?", { limit: 10, threshold: 0.8, - filter: { category: 'geography' } - } + filter: { category: "geography" }, + }, ); console.log(results); @@ -370,7 +396,7 @@ console.log(results); // ] // 删除记忆 -await client.memory.semantic.delete('chunk-123'); +await client.memory.semantic.delete("chunk-123"); ``` --- @@ -382,12 +408,12 @@ await client.memory.semantic.delete('chunk-123'); ```typescript // 创建会话 const session = await client.session.create({ - agentId: 'agent-123', - templateId: 'assistant', + agentId: "agent-123", + templateId: "assistant", metadata: { - userId: 'user-456', - project: 'demo' - } + userId: "user-456", + project: "demo", + }, }); // 获取会话详情 @@ -396,7 +422,7 @@ const sessionInfo = await client.session.get(session.id); // 获取会话消息 const messages = await client.session.getMessages(session.id, { page: 1, - pageSize: 20 + pageSize: 20, }); // 断点恢复(7 段断点机制) @@ -426,39 +452,39 @@ await client.session.delete(session.id); ```typescript // 1. Parallel Workflow(并行执行) const parallelWorkflow = await client.workflow.create({ - type: 'parallel', - name: 'Multi-Agent Research', + type: "parallel", + name: "Multi-Agent Research", agents: [ - { id: 'researcher-1', task: 'Research topic A' }, - { id: 'researcher-2', task: 'Research topic B' }, - { id: 'researcher-3', task: 'Research topic C' } + { id: "researcher-1", task: "Research topic A" }, + { id: "researcher-2", task: "Research topic B" }, + { id: "researcher-3", task: "Research topic C" }, ], - maxConcurrency: 3 + maxConcurrency: 3, }); // 2. Sequential Workflow(顺序执行) const sequentialWorkflow = await client.workflow.create({ - type: 'sequential', - name: 'Document Processing Pipeline', + type: "sequential", + name: "Document Processing Pipeline", steps: [ - { agent: 'reader', action: 'read_document' }, - { agent: 'analyzer', action: 'analyze_content' }, - { agent: 'summarizer', action: 'generate_summary' } - ] + { agent: "reader", action: "read_document" }, + { agent: "analyzer", action: "analyze_content" }, + { agent: "summarizer", action: "generate_summary" }, + ], }); // 3. Loop Workflow(循环执行) const loopWorkflow = await client.workflow.create({ - type: 'loop', - name: 'Iterative Improvement', - agent: 'optimizer', + type: "loop", + name: "Iterative Improvement", + agent: "optimizer", condition: (result) => result.quality < 0.95, - maxIterations: 10 + maxIterations: 10, }); // 执行工作流 const run = await client.workflow.execute(parallelWorkflow.id, { - input: 'Research AI trends in 2024' + input: "Research AI trends in 2024", }); // 暂停工作流 @@ -469,7 +495,10 @@ await client.workflow.resume(parallelWorkflow.id, run.id); // 获取执行历史 const runs = await client.workflow.getRuns(parallelWorkflow.id); -const runDetails = await client.workflow.getRunDetails(parallelWorkflow.id, run.id); +const runDetails = await client.workflow.getRunDetails( + parallelWorkflow.id, + run.id, +); ``` --- @@ -481,19 +510,19 @@ const runDetails = await client.workflow.getRunDetails(parallelWorkflow.id, run. ```typescript // 添加 MCP 服务器 await client.mcp.addServer({ - serverId: 'my-mcp-server', - endpoint: 'http://localhost:8090/mcp', - accessKeyId: 'key', - accessKeySecret: 'secret' + serverId: "my-mcp-server", + endpoint: "http://localhost:8090/mcp", + accessKeyId: "key", + accessKeySecret: "secret", }); // 列出服务器工具 -const tools = await client.mcp.getServerTools('my-mcp-server'); +const tools = await client.mcp.getServerTools("my-mcp-server"); // 调用远程工具 -const result = await client.mcp.callTool('my-mcp-server', 'calculator', { - operation: 'add', - numbers: [1, 2, 3] +const result = await client.mcp.callTool("my-mcp-server", "calculator", { + operation: "add", + numbers: [1, 2, 3], }); ``` @@ -504,12 +533,12 @@ const result = await client.mcp.callTool('my-mcp-server', 'calculator', { const middlewares = await client.middleware.list(); // 获取中间件配置 -const config = await client.middleware.get('summarization'); +const config = await client.middleware.get("summarization"); // 更新中间件配置 -await client.middleware.update('summarization', { - threshold: 170000, // Token 阈值 - keepMessages: 6 // 保留最近 N 条消息 +await client.middleware.update("summarization", { + threshold: 170000, // Token 阈值 + keepMessages: 6, // 保留最近 N 条消息 }); ``` @@ -520,13 +549,13 @@ await client.middleware.update('summarization', { const tools = await client.tool.list(); // 同步执行工具 -const result = await client.tool.execute('bash', { - command: 'ls -la' +const result = await client.tool.execute("bash", { + command: "ls -la", }); // 异步执行(长时运行工具) -const taskId = await client.tool.executeAsync('web_scraper', { - url: 'https://example.com' +const taskId = await client.tool.executeAsync("web_scraper", { + url: "https://example.com", }); // 查询任务进度 @@ -547,24 +576,24 @@ await client.tool.cancelTask(taskId); ```typescript // 获取追踪数据 const traces = await client.telemetry.getTraces({ - startTime: '2024-01-01T00:00:00Z', - endTime: '2024-01-02T00:00:00Z', - agentId: 'agent-123' + startTime: "2024-01-01T00:00:00Z", + endTime: "2024-01-02T00:00:00Z", + agentId: "agent-123", }); // 获取单个追踪详情 -const trace = await client.telemetry.getTrace('trace-456'); +const trace = await client.telemetry.getTrace("trace-456"); // 获取指标 const metrics = await client.telemetry.getMetrics({ - name: 'token_usage', - timeRange: '1h' + name: "token_usage", + timeRange: "1h", }); // 导出遥测数据 const exportResult = await client.telemetry.export({ - format: 'json', - timeRange: '24h' + format: "json", + timeRange: "24h", }); ``` @@ -577,30 +606,30 @@ const exportResult = await client.telemetry.export({ ```typescript const client = new AsterClient({ // 基础配置 - baseUrl: 'http://localhost:8080', + baseUrl: "http://localhost:8080", apiKey: process.env.ASTER_API_KEY, - + // 超时配置 - timeout: 120000, // 全局超时(毫秒) - + timeout: 120000, // 全局超时(毫秒) + // Retry 配置 retry: { maxRetries: 3, retryableStatusCodes: [408, 429, 500, 502, 503, 504], backoffMultiplier: 2, - maxBackoffTime: 30000 + maxBackoffTime: 30000, }, - + // 日志配置 logging: { - level: 'info', // 'debug' | 'info' | 'warn' | 'error' - format: 'json' // 'json' | 'text' + level: "info", // 'debug' | 'info' | 'warn' | 'error' + format: "json", // 'json' | 'text' }, - + // 自定义 headers headers: { - 'X-Custom-Header': 'value' - } + "X-Custom-Header": "value", + }, }); ``` @@ -645,6 +674,7 @@ npm run test:watch ### 完整 API 参考 查看自动生成的 API 文档: + ```bash npm run docs ``` @@ -653,29 +683,30 @@ npm run docs ### 资源列表 -| 资源 | 状态 | 端点数 | 说明 | -|------|------|--------|------| -| `agent` | ✅ 部分 | 2/7 | Agent 管理和 Chat | -| `memory` | 🚧 开发中 | 0/8 | 三层记忆系统 | -| `workflow` | 🚧 开发中 | 0/8 | 工作流编排 | -| `session` | 🚧 开发中 | 0/7 | 会话管理 | -| `skill` | ✅ 完成 | 6/6 | 技能管理 | -| `eval` | ✅ 部分 | 3/8 | 评估系统 | -| `tool` | 🚧 开发中 | 0/6 | 工具执行 | -| `mcp` | 🚧 开发中 | 1/5 | MCP 协议 | -| `middleware` | 🚧 开发中 | 0/3 | 中间件配置 | -| `telemetry` | 🚧 开发中 | 0/5 | 可观测性 | -| `router` | 📅 计划中 | 0/3 | 模型路由 | -| `sandbox` | 📅 计划中 | 0/5 | 沙箱管理 | -| `provider` | 📅 计划中 | 0/4 | Provider 管理 | -| `template` | 📅 计划中 | 0/5 | 模板管理 | -| `security` | 📅 计划中 | 0/4 | 安全系统 | +| 资源 | 状态 | 端点数 | 说明 | +| ------------ | --------- | ------ | ----------------- | +| `agent` | ✅ 部分 | 2/7 | Agent 管理和 Chat | +| `memory` | 🚧 开发中 | 0/8 | 三层记忆系统 | +| `workflow` | 🚧 开发中 | 0/8 | 工作流编排 | +| `session` | 🚧 开发中 | 0/7 | 会话管理 | +| `skill` | ✅ 完成 | 6/6 | 技能管理 | +| `eval` | ✅ 部分 | 3/8 | 评估系统 | +| `tool` | 🚧 开发中 | 0/6 | 工具执行 | +| `mcp` | 🚧 开发中 | 1/5 | MCP 协议 | +| `middleware` | 🚧 开发中 | 0/3 | 中间件配置 | +| `telemetry` | 🚧 开发中 | 0/5 | 可观测性 | +| `router` | 📅 计划中 | 0/3 | 模型路由 | +| `sandbox` | 📅 计划中 | 0/5 | 沙箱管理 | +| `provider` | 📅 计划中 | 0/4 | Provider 管理 | +| `template` | 📅 计划中 | 0/5 | 模板管理 | +| `security` | 📅 计划中 | 0/4 | 安全系统 | --- ## 🗺️ 路线图 ### v0.5.0 (Week 6) - 核心架构 + - ✅ 事件驱动架构 - ✅ 三层记忆系统 - ✅ Session + Workflow @@ -683,11 +714,13 @@ npm run docs - ✅ Tool + Telemetry ### v0.8.0 (Week 10) - 高级功能 + - ✅ Router + Sandbox - ✅ Pool/Room + Evals 扩展 - ✅ Provider + Template ### v1.0.0 (Week 13) - 生产就绪 ✨ + - ✅ Commands + Security + Store - ✅ 完整文档和示例 - ✅ 100% API 覆盖 @@ -717,7 +750,7 @@ npm run docs --- -**最后更新**: 2024年11月17日 -**版本**: v0.1.0 → v1.0.0 (计划中) -**状态**: 🚧 核心架构开发中 +**最后更新**: 2024年11月17日 +**版本**: v0.1.0 → v1.0.0 (计划中) +**状态**: 🚧 核心架构开发中 **预计完成**: 10-13 周 diff --git a/client-sdks/client-js/docs/API.md b/client-sdks/client-js/docs/API.md index fc54014..c63373a 100644 --- a/client-sdks/client-js/docs/API.md +++ b/client-sdks/client-js/docs/API.md @@ -1,6 +1,6 @@ # aster Client JS - API 文档 -> **版本**: v0.5.0 +> **版本**: v0.5.0 > **更新时间**: 2024年11月17日 --- @@ -23,28 +23,29 @@ ### 初始化 ```typescript -import { aster } from '@aster/client-js'; +import { aster } from "@aster/client-js"; const client = new aster({ - baseUrl: 'http://localhost:8080', - apiKey: 'your-api-key', - timeout: 30000, // 可选,默认 30000ms - retry: { // 可选 + baseUrl: "http://localhost:8080", + apiKey: "your-api-key", + timeout: 30000, // 可选,默认 30000ms + retry: { + // 可选 maxRetries: 3, - retryDelay: 1000 - } + retryDelay: 1000, + }, }); ``` ### 配置选项 -| 参数 | 类型 | 必需 | 说明 | -|------|------|------|------| -| `baseUrl` | string | ✅ | aster 服务器地址 | -| `apiKey` | string | ❌ | API 密钥 | -| `timeout` | number | ❌ | 请求超时时间(毫秒) | -| `retry.maxRetries` | number | ❌ | 最大重试次数 | -| `retry.retryDelay` | number | ❌ | 重试延迟(毫秒) | +| 参数 | 类型 | 必需 | 说明 | +| ------------------ | ------ | ---- | -------------------- | +| `baseUrl` | string | ✅ | aster 服务器地址 | +| `apiKey` | string | ❌ | API 密钥 | +| `timeout` | number | ❌ | 请求超时时间(毫秒) | +| `retry.maxRetries` | number | ❌ | 最大重试次数 | +| `retry.retryDelay` | number | ❌ | 重试延迟(毫秒) | ### 便捷方法 @@ -57,14 +58,14 @@ const status = await client.getStatus(); // 获取使用统计 const usage = await client.getUsageStatistics({ - start: '2024-01-01T00:00:00Z', - end: '2024-01-08T00:00:00Z' + start: "2024-01-01T00:00:00Z", + end: "2024-01-08T00:00:00Z", }); // 获取性能指标 const perf = await client.getPerformanceMetrics({ - start: '2024-01-01T00:00:00Z', - end: '2024-01-02T00:00:00Z' + start: "2024-01-01T00:00:00Z", + end: "2024-01-02T00:00:00Z", }); ``` @@ -78,41 +79,42 @@ const perf = await client.getPerformanceMetrics({ ```typescript await client.memory.working.set( - 'user_preference', - { theme: 'dark', language: 'zh-CN' }, + "user_preference", + { theme: "dark", language: "zh-CN" }, { - scope: 'resource', // 'thread' | 'resource' - ttl: 3600, // 过期时间(秒) - schema: { // 可选,JSON Schema 验证 - type: 'object', + scope: "resource", // 'thread' | 'resource' + ttl: 3600, // 过期时间(秒) + schema: { + // 可选,JSON Schema 验证 + type: "object", properties: { - theme: { type: 'string' }, - language: { type: 'string' } - } - } - } + theme: { type: "string" }, + language: { type: "string" }, + }, + }, + }, ); ``` #### get() - 获取 Working Memory ```typescript -const item = await client.memory.working.get('user_preference'); -console.log(item?.value); // { theme: 'dark', language: 'zh-CN' } +const item = await client.memory.working.get("user_preference"); +console.log(item?.value); // { theme: 'dark', language: 'zh-CN' } ``` #### delete() - 删除 Working Memory ```typescript -await client.memory.working.delete('user_preference'); +await client.memory.working.delete("user_preference"); ``` #### list() - 列出所有 Working Memory ```typescript const items = await client.memory.working.list({ - scope: 'resource', - prefix: 'user_' + scope: "resource", + prefix: "user_", }); ``` @@ -122,46 +124,43 @@ const items = await client.memory.working.list({ ```typescript await client.memory.semantic.store( - 'aster is a powerful framework for building AI agents', + "aster is a powerful framework for building AI agents", { - source: 'documentation', - category: 'introduction', - timestamp: new Date().toISOString() - } + source: "documentation", + category: "introduction", + timestamp: new Date().toISOString(), + }, ); ``` #### search() - 语义搜索 ```typescript -const chunks = await client.memory.semantic.search( - 'What is aster?', - { - limit: 5, - threshold: 0.7, - filter: { - category: 'introduction' - } - } -); +const chunks = await client.memory.semantic.search("What is aster?", { + limit: 5, + threshold: 0.7, + filter: { + category: "introduction", + }, +}); ``` #### delete() - 删除语义记忆 ```typescript -await client.memory.semantic.delete('chunk-id'); +await client.memory.semantic.delete("chunk-id"); ``` ### Provenance - 记忆溯源 ```typescript // 获取溯源链 -const chain = await client.memory.provenance.getChain('memory-id'); +const chain = await client.memory.provenance.getChain("memory-id"); // 列出所有溯源 const items = await client.memory.provenance.list({ - memoryType: 'semantic', - startTime: '2024-01-01T00:00:00Z' + memoryType: "semantic", + startTime: "2024-01-01T00:00:00Z", }); ``` @@ -170,15 +169,15 @@ const items = await client.memory.provenance.list({ ```typescript // 合并记忆 await client.memory.consolidation.consolidate({ - sourceIds: ['chunk-1', 'chunk-2', 'chunk-3'], - strategy: 'llm_based', - targetScope: 'resource' + sourceIds: ["chunk-1", "chunk-2", "chunk-3"], + strategy: "llm_based", + targetScope: "resource", }); // 获取合并历史 const history = await client.memory.consolidation.getHistory({ - startTime: '2024-01-01T00:00:00Z', - limit: 10 + startTime: "2024-01-01T00:00:00Z", + limit: 10, }); ``` @@ -190,34 +189,34 @@ const history = await client.memory.consolidation.getHistory({ ```typescript const session = await client.sessions.create({ - agentId: 'agent-123', - templateId: 'chat-template', - userId: 'user-456', + agentId: "agent-123", + templateId: "chat-template", + userId: "user-456", metadata: { - project: 'demo' + project: "demo", }, enableCheckpoints: true, - checkpointInterval: 5 // 每5条消息创建断点 + checkpointInterval: 5, // 每5条消息创建断点 }); ``` ### get() - 获取 Session ```typescript -const session = await client.sessions.get('session-id'); +const session = await client.sessions.get("session-id"); ``` ### list() - 列出 Sessions ```typescript const result = await client.sessions.list({ - status: 'active', + status: "active", page: 1, - pageSize: 20 + pageSize: 20, }); console.log(`总计: ${result.total}`); -result.items.forEach(session => { +result.items.forEach((session) => { console.log(session.id, session.status); }); ``` @@ -225,24 +224,24 @@ result.items.forEach(session => { ### addMessage() - 添加消息 ```typescript -await client.sessions.addMessage('session-id', { - role: 'user', - content: 'Hello, how can you help me?' +await client.sessions.addMessage("session-id", { + role: "user", + content: "Hello, how can you help me?", }); -await client.sessions.addMessage('session-id', { - role: 'assistant', - content: 'I can help you with various tasks.' +await client.sessions.addMessage("session-id", { + role: "assistant", + content: "I can help you with various tasks.", }); ``` ### getMessages() - 获取消息列表 ```typescript -const messages = await client.sessions.getMessages('session-id', { +const messages = await client.sessions.getMessages("session-id", { page: 1, pageSize: 50, - sort: 'asc' + sort: "asc", }); ``` @@ -251,17 +250,17 @@ const messages = await client.sessions.getMessages('session-id', { ```typescript // 创建手动断点 const checkpoint = await client.sessions.createCheckpoint( - 'session-id', - 'before-important-action' + "session-id", + "before-important-action", ); // 获取所有断点 -const checkpoints = await client.sessions.getCheckpoints('session-id'); +const checkpoints = await client.sessions.getCheckpoints("session-id"); // 从断点恢复 -await client.sessions.resume('session-id', { +await client.sessions.resume("session-id", { checkpointId: checkpoint.id, - keepSubsequentMessages: false + keepSubsequentMessages: false, }); ``` @@ -269,16 +268,16 @@ await client.sessions.resume('session-id', { ```typescript // 暂停 Session -await client.sessions.pause('session-id'); +await client.sessions.pause("session-id"); // 激活 Session -await client.sessions.activate('session-id'); +await client.sessions.activate("session-id"); // 完成 Session -await client.sessions.complete('session-id'); +await client.sessions.complete("session-id"); // 归档 Session -await client.sessions.archive('session-id'); +await client.sessions.archive("session-id"); ``` --- @@ -291,16 +290,16 @@ await client.sessions.archive('session-id'); ```typescript const workflow = await client.workflows.create({ - type: 'parallel', - name: 'Multi-Agent Research', - description: '多个 Agent 并行研究', + type: "parallel", + name: "Multi-Agent Research", + description: "多个 Agent 并行研究", agents: [ - { id: 'researcher-1', task: 'Research AI trends' }, - { id: 'researcher-2', task: 'Research quantum computing' }, - { id: 'researcher-3', task: 'Research climate tech' } + { id: "researcher-1", task: "Research AI trends" }, + { id: "researcher-2", task: "Research quantum computing" }, + { id: "researcher-3", task: "Research climate tech" }, ], maxConcurrency: 3, - timeout: 300 + timeout: 300, }); ``` @@ -308,15 +307,15 @@ const workflow = await client.workflows.create({ ```typescript const workflow = await client.workflows.create({ - type: 'sequential', - name: 'Document Processing', - description: '文档处理流水线', + type: "sequential", + name: "Document Processing", + description: "文档处理流水线", steps: [ - { agent: 'reader', action: 'read_document' }, - { agent: 'analyzer', action: 'analyze_content' }, - { agent: 'summarizer', action: 'generate_summary' } + { agent: "reader", action: "read_document" }, + { agent: "analyzer", action: "analyze_content" }, + { agent: "summarizer", action: "generate_summary" }, ], - continueOnError: false + continueOnError: false, }); ``` @@ -324,25 +323,25 @@ const workflow = await client.workflows.create({ ```typescript const workflow = await client.workflows.create({ - type: 'loop', - name: 'Code Optimizer', - description: '迭代优化代码', - agent: 'optimizer', - condition: 'result.quality < 0.95', + type: "loop", + name: "Code Optimizer", + description: "迭代优化代码", + agent: "optimizer", + condition: "result.quality < 0.95", maxIterations: 10, - initialInput: { code: '...' } + initialInput: { code: "..." }, }); ``` ### execute() - 执行 Workflow ```typescript -const run = await client.workflows.execute('workflow-id', { - input: { documentUrl: 'https://example.com/doc.pdf' }, +const run = await client.workflows.execute("workflow-id", { + input: { documentUrl: "https://example.com/doc.pdf" }, options: { timeout: 300, - async: false - } + async: false, + }, }); ``` @@ -350,20 +349,20 @@ const run = await client.workflows.execute('workflow-id', { ```typescript // 暂停执行 -await client.workflows.suspend('workflow-id', { - runId: 'run-id', - reason: 'User requested pause' +await client.workflows.suspend("workflow-id", { + runId: "run-id", + reason: "User requested pause", }); // 恢复执行 -await client.workflows.resume('workflow-id', { - runId: 'run-id' +await client.workflows.resume("workflow-id", { + runId: "run-id", }); // 取消执行 -await client.workflows.cancel('workflow-id', { - runId: 'run-id', - reason: 'User cancelled' +await client.workflows.cancel("workflow-id", { + runId: "run-id", + reason: "User cancelled", }); ``` @@ -371,12 +370,12 @@ await client.workflows.cancel('workflow-id', { ```typescript const result = await client.workflows.waitForCompletion( - 'workflow-id', - 'run-id', + "workflow-id", + "run-id", { pollInterval: 2000, - timeout: 60000 - } + timeout: 60000, + }, ); ``` @@ -388,30 +387,26 @@ const result = await client.workflows.waitForCompletion( ```typescript const server = await client.mcp.addServer({ - serverId: 'my-server', - name: 'My MCP Server', - endpoint: 'http://localhost:8090/mcp', - accessKeyId: 'key', - accessKeySecret: 'secret', - enabled: true + serverId: "my-server", + name: "My MCP Server", + endpoint: "http://localhost:8090/mcp", + accessKeyId: "key", + accessKeySecret: "secret", + enabled: true, }); ``` ### call() - 调用 MCP 工具 ```typescript -const result = await client.mcp.call( - 'server-id', - 'tool-name', - { - param1: 'value1', - param2: 'value2' - } -); +const result = await client.mcp.call("server-id", "tool-name", { + param1: "value1", + param2: "value2", +}); console.log(result.success); console.log(result.result); -console.log(result.executionTime, 'ms'); +console.log(result.executionTime, "ms"); ``` ### 管理 Servers @@ -421,13 +416,13 @@ console.log(result.executionTime, 'ms'); const servers = await client.mcp.listServers(); // 连接 Server -await client.mcp.connectServer('server-id'); +await client.mcp.connectServer("server-id"); // 断开 Server -await client.mcp.disconnectServer('server-id'); +await client.mcp.disconnectServer("server-id"); // 移除 Server -await client.mcp.removeServer('server-id'); +await client.mcp.removeServer("server-id"); ``` --- @@ -439,8 +434,10 @@ await client.mcp.removeServer('server-id'); ```typescript const middlewares = await client.middleware.list(); -middlewares.forEach(mw => { - console.log(`[P${mw.priority}] ${mw.displayName} - ${mw.enabled ? 'ON' : 'OFF'}`); +middlewares.forEach((mw) => { + console.log( + `[P${mw.priority}] ${mw.displayName} - ${mw.enabled ? "ON" : "OFF"}`, + ); }); ``` @@ -449,40 +446,40 @@ middlewares.forEach(mw => { #### Summarization(上下文总结) ```typescript -await client.middleware.updateConfig('summarization', { +await client.middleware.updateConfig("summarization", { threshold: 170000, keepMessages: 6, - llmProvider: 'anthropic', - llmModel: 'claude-sonnet-4' + llmProvider: "anthropic", + llmModel: "claude-sonnet-4", }); ``` #### Tool Approval(工具审批) ```typescript -await client.middleware.updateConfig('tool_approval', { - approvalRequired: ['file_delete', 'bash', 'database_query'], - autoApprove: ['file_read', 'http_request'], +await client.middleware.updateConfig("tool_approval", { + approvalRequired: ["file_delete", "bash", "database_query"], + autoApprove: ["file_read", "http_request"], approvalTimeout: 300, - timeoutBehavior: 'reject' + timeoutBehavior: "reject", }); ``` #### Cost Tracker(成本追踪) ```typescript -await client.middleware.updateConfig('cost_tracker', { +await client.middleware.updateConfig("cost_tracker", { enabled: true, - costModel: 'token_based', + costModel: "token_based", pricing: { promptTokenPrice: 0.003, completionTokenPrice: 0.015, - currency: 'USD' + currency: "USD", }, budget: { daily: 100, - monthly: 2000 - } + monthly: 2000, + }, }); ``` @@ -494,11 +491,11 @@ const order = await client.middleware.getExecutionOrder(); // 设置执行顺序 await client.middleware.setExecutionOrder([ - 'logging', - 'telemetry', - 'cost_tracker', - 'token_limiter', - 'summarization' + "logging", + "telemetry", + "cost_tracker", + "token_limiter", + "summarization", ]); // 重置为默认顺序 @@ -512,52 +509,52 @@ await client.middleware.resetExecutionOrder(); ### execute() - 执行工具(同步) ```typescript -const result = await client.tools.execute('bash', { - command: 'ls -la /tmp', - workDir: '/tmp', - timeout: 10 +const result = await client.tools.execute("bash", { + command: "ls -la /tmp", + workDir: "/tmp", + timeout: 10, }); console.log(result.success); console.log(result.result); -console.log(result.executionTime, 'ms'); +console.log(result.executionTime, "ms"); ``` ### executeAsync() - 执行工具(异步) ```typescript // 启动长时运行任务 -const task = await client.tools.executeAsync('web_scraper', { - url: 'https://example.com', - selectors: ['h1', 'p'], - executeJs: true +const task = await client.tools.executeAsync("web_scraper", { + url: "https://example.com", + selectors: ["h1", "p"], + executeJs: true, }); -console.log('Task ID:', task.taskId); +console.log("Task ID:", task.taskId); // 等待任务完成 const result = await client.tools.waitForTask(task.taskId, { pollInterval: 2000, - timeout: 60000 + timeout: 60000, }); -console.log('Status:', result.status); -console.log('Result:', result.result); +console.log("Status:", result.status); +console.log("Result:", result.result); ``` ### 任务管理 ```typescript // 获取任务进度 -const progress = await client.tools.getTaskProgress('task-id'); +const progress = await client.tools.getTaskProgress("task-id"); // 列出所有任务 const tasks = await client.tools.listTasks({ - status: 'running' + status: "running", }); // 取消任务 -await client.tools.cancelTask('task-id'); +await client.tools.cancelTask("task-id"); ``` ### 工具管理 @@ -565,13 +562,13 @@ await client.tools.cancelTask('task-id'); ```typescript // 列出所有工具 const tools = await client.tools.list({ - type: 'builtin', - enabled: true + type: "builtin", + enabled: true, }); // 启用/禁用工具 -await client.tools.enable('bash'); -await client.tools.disable('database_query'); +await client.tools.enable("bash"); +await client.tools.disable("database_query"); ``` --- @@ -586,17 +583,17 @@ const metrics = await client.telemetry.listMetrics(); // 查询 Metric 数据 const dataPoints = await client.telemetry.queryMetrics({ - name: 'request_count', + name: "request_count", timeRange: { - start: '2024-01-01T00:00:00Z', - end: '2024-01-02T00:00:00Z' + start: "2024-01-01T00:00:00Z", + end: "2024-01-02T00:00:00Z", }, - aggregation: 'sum' + aggregation: "sum", }); // 记录自定义 Metric -await client.telemetry.recordMetric('custom_metric', 42, { - label1: 'value1' +await client.telemetry.recordMetric("custom_metric", 42, { + label1: "value1", }); ``` @@ -605,21 +602,21 @@ await client.telemetry.recordMetric('custom_metric', 42, { ```typescript // 查询 Traces const traces = await client.telemetry.queryTraces({ - operationName: 'workflow_execution', + operationName: "workflow_execution", timeRange: { - start: '2024-01-01T00:00:00Z', - end: '2024-01-02T00:00:00Z' + start: "2024-01-01T00:00:00Z", + end: "2024-01-02T00:00:00Z", }, minDuration: 1000, - status: 'error', - limit: 10 + status: "error", + limit: 10, }); // 获取 Trace 详情 -const trace = await client.telemetry.getTrace('trace-id'); +const trace = await client.telemetry.getTrace("trace-id"); // 获取 Trace 的所有 Spans -const spans = await client.telemetry.getTraceSpans('trace-id'); +const spans = await client.telemetry.getTraceSpans("trace-id"); ``` ### Logs @@ -627,23 +624,23 @@ const spans = await client.telemetry.getTraceSpans('trace-id'); ```typescript // 查询日志 const logs = await client.telemetry.queryLogs({ - level: 'error', + level: "error", timeRange: { - start: '2024-01-01T00:00:00Z', - end: '2024-01-02T00:00:00Z' + start: "2024-01-01T00:00:00Z", + end: "2024-01-02T00:00:00Z", }, - search: 'timeout', - limit: 100 + search: "timeout", + limit: 100, }); // 写入日志 await client.telemetry.writeLog({ - level: 'info', - message: 'Custom log message', - source: 'my-app', + level: "info", + message: "Custom log message", + source: "my-app", attributes: { - userId: 'user-123' - } + userId: "user-123", + }, }); ``` @@ -651,21 +648,21 @@ await client.telemetry.writeLog({ ```typescript // 导出 Metrics(Prometheus 格式) -const metricsExport = await client.telemetry.exportMetrics('prometheus', { - start: '2024-01-01T00:00:00Z', - end: '2024-01-02T00:00:00Z' +const metricsExport = await client.telemetry.exportMetrics("prometheus", { + start: "2024-01-01T00:00:00Z", + end: "2024-01-02T00:00:00Z", }); // 导出 Traces(OpenTelemetry 格式) -const tracesExport = await client.telemetry.exportTraces('opentelemetry', { - start: '2024-01-01T00:00:00Z', - end: '2024-01-02T00:00:00Z' +const tracesExport = await client.telemetry.exportTraces("opentelemetry", { + start: "2024-01-01T00:00:00Z", + end: "2024-01-02T00:00:00Z", }); // 导出 Logs(CSV 格式) -const logsExport = await client.telemetry.exportLogs('csv', { - start: '2024-01-01T00:00:00Z', - end: '2024-01-02T00:00:00Z' +const logsExport = await client.telemetry.exportLogs("csv", { + start: "2024-01-01T00:00:00Z", + end: "2024-01-02T00:00:00Z", }); ``` @@ -677,17 +674,17 @@ const logsExport = await client.telemetry.exportLogs('csv', { ```typescript try { - const result = await client.tools.execute('bash', { - command: 'invalid-command' + const result = await client.tools.execute("bash", { + command: "invalid-command", }); } catch (error) { - console.error('Error:', error.message); - + console.error("Error:", error.message); + // 检查特定错误类型 if (error.statusCode === 404) { - console.error('Tool not found'); + console.error("Tool not found"); } else if (error.statusCode === 429) { - console.error('Rate limited'); + console.error("Rate limited"); } } ``` @@ -703,19 +700,19 @@ import { // Memory 类型 WorkingMemoryItem, SemanticMemoryChunk, - + // Session 类型 SessionInfo, Message, Checkpoint, - + // Workflow 类型 WorkflowInfo, WorkflowRun, ParallelWorkflowDefinition, - + // 其他... -} from '@aster/client-js'; +} from "@aster/client-js"; ``` --- @@ -732,5 +729,5 @@ import { --- -**文档版本**: v0.5.0 +**文档版本**: v0.5.0 **最后更新**: 2024年11月17日 diff --git a/client-sdks/client-js/docs/QUICKSTART.md b/client-sdks/client-js/docs/QUICKSTART.md index a3a84f2..e66d5ea 100644 --- a/client-sdks/client-js/docs/QUICKSTART.md +++ b/client-sdks/client-js/docs/QUICKSTART.md @@ -21,11 +21,11 @@ pnpm add @aster/client-js ### 1. 初始化客户端 ```typescript -import { aster } from '@aster/client-js'; +import { aster } from "@aster/client-js"; const client = new aster({ - baseUrl: 'http://localhost:8080', - apiKey: 'your-api-key' // 可选 + baseUrl: "http://localhost:8080", + apiKey: "your-api-key", // 可选 }); ``` @@ -33,7 +33,7 @@ const client = new aster({ ```typescript const health = await client.healthCheck(); -console.log('状态:', health.status); // healthy +console.log("状态:", health.status); // healthy ``` --- @@ -46,17 +46,21 @@ console.log('状态:', health.status); // healthy ```typescript // 设置 -await client.memory.working.set('user_preference', { - theme: 'dark', - language: 'zh-CN' -}, { - scope: 'resource', // 跨会话 - ttl: 3600 // 1小时过期 -}); +await client.memory.working.set( + "user_preference", + { + theme: "dark", + language: "zh-CN", + }, + { + scope: "resource", // 跨会话 + ttl: 3600, // 1小时过期 + }, +); // 获取 -const item = await client.memory.working.get('user_preference'); -console.log(item?.value); // { theme: 'dark', language: 'zh-CN' } +const item = await client.memory.working.get("user_preference"); +console.log(item?.value); // { theme: 'dark', language: 'zh-CN' } ``` #### Semantic Memory(语义记忆) @@ -64,17 +68,16 @@ console.log(item?.value); // { theme: 'dark', language: 'zh-CN' } ```typescript // 存储 await client.memory.semantic.store( - 'aster is a powerful framework for building AI agents', - { category: 'introduction' } + "aster is a powerful framework for building AI agents", + { category: "introduction" }, ); // 搜索 -const results = await client.memory.semantic.search( - 'What is aster?', - { limit: 5 } -); +const results = await client.memory.semantic.search("What is aster?", { + limit: 5, +}); -results.forEach(chunk => { +results.forEach((chunk) => { console.log(chunk.content, chunk.similarity); }); ``` @@ -86,21 +89,21 @@ results.forEach(chunk => { ```typescript // 创建 Session const session = await client.sessions.create({ - agentId: 'assistant-agent', - templateId: 'chat', - userId: 'user-123', - enableCheckpoints: true // 启用断点恢复 + agentId: "assistant-agent", + templateId: "chat", + userId: "user-123", + enableCheckpoints: true, // 启用断点恢复 }); // 添加消息 await client.sessions.addMessage(session.id, { - role: 'user', - content: 'Hello!' + role: "user", + content: "Hello!", }); await client.sessions.addMessage(session.id, { - role: 'assistant', - content: 'Hi! How can I help you?' + role: "assistant", + content: "Hi! How can I help you?", }); // 获取消息历史 @@ -120,40 +123,37 @@ await client.sessions.complete(session.id); ```typescript // 创建并行工作流 const workflow = await client.workflows.create({ - type: 'parallel', - name: 'Multi-Agent Research', + type: "parallel", + name: "Multi-Agent Research", agents: [ - { id: 'researcher-1', task: 'Research AI trends' }, - { id: 'researcher-2', task: 'Research quantum computing' } + { id: "researcher-1", task: "Research AI trends" }, + { id: "researcher-2", task: "Research quantum computing" }, ], - maxConcurrency: 2 + maxConcurrency: 2, }); // 执行 const run = await client.workflows.execute(workflow.id, { - input: 'Start research' + input: "Start research", }); // 等待完成 -const result = await client.workflows.waitForCompletion( - workflow.id, - run.id -); +const result = await client.workflows.waitForCompletion(workflow.id, run.id); -console.log('状态:', result.status); // completed +console.log("状态:", result.status); // completed ``` #### Sequential Workflow(顺序) ```typescript const workflow = await client.workflows.create({ - type: 'sequential', - name: 'Document Pipeline', + type: "sequential", + name: "Document Pipeline", steps: [ - { agent: 'reader', action: 'read_document' }, - { agent: 'analyzer', action: 'analyze' }, - { agent: 'summarizer', action: 'summarize' } - ] + { agent: "reader", action: "read_document" }, + { agent: "analyzer", action: "analyze" }, + { agent: "summarizer", action: "summarize" }, + ], }); ``` @@ -163,22 +163,22 @@ const workflow = await client.workflows.create({ ```typescript // 同步执行(快速工具) -const result = await client.tools.execute('bash', { +const result = await client.tools.execute("bash", { command: 'echo "Hello aster"', - timeout: 10 + timeout: 10, }); -console.log(result.result); // Hello aster -console.log('耗时:', result.executionTime, 'ms'); +console.log(result.result); // Hello aster +console.log("耗时:", result.executionTime, "ms"); // 异步执行(长时运行工具) -const task = await client.tools.executeAsync('web_scraper', { - url: 'https://example.com' +const task = await client.tools.executeAsync("web_scraper", { + url: "https://example.com", }); // 等待完成 const taskResult = await client.tools.waitForTask(task.taskId); -console.log('抓取结果:', taskResult.result); +console.log("抓取结果:", taskResult.result); ``` --- @@ -188,19 +188,18 @@ console.log('抓取结果:', taskResult.result); ```typescript // 添加 MCP Server await client.mcp.addServer({ - serverId: 'my-server', - name: 'My MCP Server', - endpoint: 'http://localhost:8090/mcp' + serverId: "my-server", + name: "My MCP Server", + endpoint: "http://localhost:8090/mcp", }); // 调用远程工具 -const result = await client.mcp.call( - 'my-server', - 'calculator', - { operation: 'add', numbers: [1, 2, 3] } -); +const result = await client.mcp.call("my-server", "calculator", { + operation: "add", + numbers: [1, 2, 3], +}); -console.log('结果:', result.result); // 6 +console.log("结果:", result.result); // 6 ``` --- @@ -209,29 +208,29 @@ console.log('结果:', result.result); // 6 ```typescript // 配置上下文总结 -await client.middleware.updateConfig('summarization', { - threshold: 170000, // 170K tokens 触发 - keepMessages: 6 +await client.middleware.updateConfig("summarization", { + threshold: 170000, // 170K tokens 触发 + keepMessages: 6, }); // 配置成本追踪 -await client.middleware.updateConfig('cost_tracker', { +await client.middleware.updateConfig("cost_tracker", { enabled: true, pricing: { promptTokenPrice: 0.003, completionTokenPrice: 0.015, - currency: 'USD' + currency: "USD", }, budget: { daily: 100, - monthly: 2000 - } + monthly: 2000, + }, }); // 列出所有 Middleware const middlewares = await client.middleware.list(); -middlewares.forEach(mw => { - console.log(`${mw.displayName}: ${mw.enabled ? 'ON' : 'OFF'}`); +middlewares.forEach((mw) => { + console.log(`${mw.displayName}: ${mw.enabled ? "ON" : "OFF"}`); }); ``` @@ -242,27 +241,27 @@ middlewares.forEach(mw => { ```typescript // 获取性能指标 const perf = await client.getPerformanceMetrics({ - start: '2024-01-01T00:00:00Z', - end: '2024-01-02T00:00:00Z' + start: "2024-01-01T00:00:00Z", + end: "2024-01-02T00:00:00Z", }); -console.log('总请求数:', perf.requests.total); -console.log('平均延迟:', perf.requests.avgLatency, 'ms'); -console.log('P95 延迟:', perf.requests.p95Latency, 'ms'); +console.log("总请求数:", perf.requests.total); +console.log("平均延迟:", perf.requests.avgLatency, "ms"); +console.log("P95 延迟:", perf.requests.p95Latency, "ms"); // 获取使用统计 const usage = await client.getUsageStatistics({ - start: '2024-01-01T00:00:00Z', - end: '2024-01-08T00:00:00Z' + start: "2024-01-01T00:00:00Z", + end: "2024-01-08T00:00:00Z", }); -console.log('总 Sessions:', usage.sessions?.total); -console.log('最常用工具:', usage.tools?.topTools); +console.log("总 Sessions:", usage.sessions?.total); +console.log("最常用工具:", usage.tools?.topTools); // 查询 Metrics const metrics = await client.telemetry.listMetrics(); -metrics.forEach(m => { - console.log(`${m.name}: ${m.value} ${m.unit || ''}`); +metrics.forEach((m) => { + console.log(`${m.name}: ${m.value} ${m.unit || ""}`); }); ``` @@ -273,44 +272,48 @@ metrics.forEach(m => { ### 示例 1:智能对话 Agent ```typescript -import { aster } from '@aster/client-js'; +import { aster } from "@aster/client-js"; async function chatExample() { const client = new aster({ - baseUrl: 'http://localhost:8080', - apiKey: process.env.ASTER_API_KEY + baseUrl: "http://localhost:8080", + apiKey: process.env.ASTER_API_KEY, }); // 1. 创建 Session const session = await client.sessions.create({ - agentId: 'chat-agent', - templateId: 'assistant', - userId: 'user-123', - enableCheckpoints: true + agentId: "chat-agent", + templateId: "assistant", + userId: "user-123", + enableCheckpoints: true, }); // 2. 存储用户偏好到 Working Memory - await client.memory.working.set('user_context', { - name: 'Alice', - preferences: { language: 'zh-CN' } - }, { scope: 'resource' }); + await client.memory.working.set( + "user_context", + { + name: "Alice", + preferences: { language: "zh-CN" }, + }, + { scope: "resource" }, + ); // 3. 对话 await client.sessions.addMessage(session.id, { - role: 'user', - content: '帮我总结一下 AI 的最新趋势' + role: "user", + content: "帮我总结一下 AI 的最新趋势", }); // 4. 存储重要信息到 Semantic Memory - await client.memory.semantic.store( - 'User is interested in AI trends', - { userId: 'user-123', topic: 'AI' } - ); + await client.memory.semantic.store("User is interested in AI trends", { + userId: "user-123", + topic: "AI", + }); // 5. 获取统计 const stats = await client.sessions.getStats(session.id); - console.log('总 Tokens:', stats.totalTokens); - console.log('总成本:', stats.totalCost, stats.currency); + console.log("总 Tokens:", stats.totalTokens); + console.log("总成本:", stats.totalCost, stats.currency); // 6. 完成 await client.sessions.complete(session.id); @@ -322,51 +325,49 @@ chatExample().catch(console.error); ### 示例 2:并行研究工作流 ```typescript -import { aster } from '@aster/client-js'; +import { aster } from "@aster/client-js"; async function researchWorkflow() { const client = new aster({ - baseUrl: 'http://localhost:8080', - apiKey: process.env.ASTER_API_KEY + baseUrl: "http://localhost:8080", + apiKey: process.env.ASTER_API_KEY, }); // 1. 创建并行工作流 const workflow = await client.workflows.create({ - type: 'parallel', - name: 'Tech Research', + type: "parallel", + name: "Tech Research", agents: [ - { id: 'ai-researcher', task: 'Research AI developments' }, - { id: 'quantum-researcher', task: 'Research quantum computing' }, - { id: 'climate-researcher', task: 'Research climate tech' } + { id: "ai-researcher", task: "Research AI developments" }, + { id: "quantum-researcher", task: "Research quantum computing" }, + { id: "climate-researcher", task: "Research climate tech" }, ], maxConcurrency: 3, - timeout: 300 + timeout: 300, }); // 2. 执行 const run = await client.workflows.execute(workflow.id, { - input: 'Research latest developments in 2024' + input: "Research latest developments in 2024", }); // 3. 监控进度 const interval = setInterval(async () => { const status = await client.workflows.getRunStatus(workflow.id, run.id); console.log(`进度: ${status.progress}%`); - - if (status.status !== 'running') { + + if (status.status !== "running") { clearInterval(interval); } }, 2000); // 4. 等待完成 - const result = await client.workflows.waitForCompletion( - workflow.id, - run.id, - { timeout: 300000 } - ); + const result = await client.workflows.waitForCompletion(workflow.id, run.id, { + timeout: 300000, + }); - console.log('工作流完成:', result.status); - console.log('结果:', result.output); + console.log("工作流完成:", result.status); + console.log("结果:", result.output); // 5. 获取详细结果 const details = await client.workflows.getRunDetails(workflow.id, run.id); @@ -381,47 +382,47 @@ researchWorkflow().catch(console.error); ### 示例 3:使用 MCP 和 Tools ```typescript -import { aster } from '@aster/client-js'; +import { aster } from "@aster/client-js"; async function mcpToolsExample() { const client = new aster({ - baseUrl: 'http://localhost:8080', - apiKey: process.env.ASTER_API_KEY + baseUrl: "http://localhost:8080", + apiKey: process.env.ASTER_API_KEY, }); // 1. 添加 MCP Server await client.mcp.addServer({ - serverId: 'file-server', - name: 'File Operations Server', - endpoint: 'http://localhost:8090/mcp' + serverId: "file-server", + name: "File Operations Server", + endpoint: "http://localhost:8090/mcp", }); // 2. 调用 MCP 工具 - const fileList = await client.mcp.call('file-server', 'list_files', { - directory: '/tmp' + const fileList = await client.mcp.call("file-server", "list_files", { + directory: "/tmp", }); // 3. 使用本地工具 - const httpResult = await client.tools.execute('http_request', { - url: 'https://api.github.com/zen', - method: 'GET' + const httpResult = await client.tools.execute("http_request", { + url: "https://api.github.com/zen", + method: "GET", }); - console.log('GitHub Zen:', httpResult.result); + console.log("GitHub Zen:", httpResult.result); // 4. 异步执行长时运行工具 - const task = await client.tools.executeAsync('web_scraper', { - url: 'https://example.com', - selectors: ['h1', 'p'] + const task = await client.tools.executeAsync("web_scraper", { + url: "https://example.com", + selectors: ["h1", "p"], }); const scrapeResult = await client.tools.waitForTask(task.taskId); - console.log('抓取完成:', scrapeResult.result); + console.log("抓取完成:", scrapeResult.result); // 5. 获取工具统计 - const stats = await client.tools.getStats('http_request'); - console.log('HTTP 请求调用次数:', stats.totalCalls); - console.log('平均耗时:', stats.avgExecutionTime, 'ms'); + const stats = await client.tools.getStats("http_request"); + console.log("HTTP 请求调用次数:", stats.totalCalls); + console.log("平均耗时:", stats.avgExecutionTime, "ms"); } mcpToolsExample().catch(console.error); @@ -444,12 +445,12 @@ mcpToolsExample().catch(console.error); ```typescript // 配置日志 Middleware -await client.middleware.updateConfig('logging', { - level: 'debug', +await client.middleware.updateConfig("logging", { + level: "debug", logRequests: true, logResponses: true, - format: 'json', - outputs: ['console'] + format: "json", + outputs: ["console"], }); ``` @@ -457,15 +458,15 @@ await client.middleware.updateConfig('logging', { ```typescript try { - await client.tools.execute('bash', { - command: 'invalid-command' + await client.tools.execute("bash", { + command: "invalid-command", }); } catch (error: any) { - console.error('错误:', error.message); - console.error('状态码:', error.statusCode); - + console.error("错误:", error.message); + console.error("状态码:", error.statusCode); + if (error.statusCode === 429) { - console.error('速率限制,请稍后重试'); + console.error("速率限制,请稍后重试"); } } ``` @@ -480,8 +481,8 @@ A: 在初始化客户端时传入: ```typescript const client = new aster({ - baseUrl: 'http://localhost:8080', - apiKey: process.env.ASTER_API_KEY + baseUrl: "http://localhost:8080", + apiKey: process.env.ASTER_API_KEY, }); ``` @@ -492,14 +493,14 @@ A: 可以在配置中设置全局超时,或在单个请求中设置: ```typescript // 全局超时 const client = new aster({ - baseUrl: 'http://localhost:8080', - timeout: 60000 // 60秒 + baseUrl: "http://localhost:8080", + timeout: 60000, // 60秒 }); // 单个请求超时 -await client.tools.execute('bash', { - command: 'long-running-command', - timeout: 120 // 120秒 +await client.tools.execute("bash", { + command: "long-running-command", + timeout: 120, // 120秒 }); ``` @@ -509,11 +510,11 @@ A: 配置重试选项: ```typescript const client = new aster({ - baseUrl: 'http://localhost:8080', + baseUrl: "http://localhost:8080", retry: { maxRetries: 3, - retryDelay: 1000 - } + retryDelay: 1000, + }, }); ``` @@ -523,5 +524,5 @@ A: Node.js 16+ 或最新的 LTS 版本。 --- -**文档版本**: v0.5.0 +**文档版本**: v0.5.0 **最后更新**: 2024年11月17日 diff --git a/client-sdks/client-js/examples/agent-usage.ts b/client-sdks/client-js/examples/agent-usage.ts index adc3563..09ce515 100644 --- a/client-sdks/client-js/examples/agent-usage.ts +++ b/client-sdks/client-js/examples/agent-usage.ts @@ -3,30 +3,30 @@ * 展示 Agent 的创建、管理、对话等功能 */ -import { AsterClient } from '@aster/client-js'; +import { AsterClient } from "@aster/client-js"; async function main() { - console.log('='.repeat(70)); - console.log('AsterClient Agent 功能演示'); - console.log('='.repeat(70)); + console.log("=".repeat(70)); + console.log("AsterClient Agent 功能演示"); + console.log("=".repeat(70)); // 初始化客户端 const client = new AsterClient({ - baseUrl: 'http://localhost:8080', - apiKey: process.env.ASTER_API_KEY + baseUrl: "http://localhost:8080", + apiKey: process.env.ASTER_API_KEY, }); // ======================================================================== // 1. Agent 模板 // ======================================================================== - console.log('\n📋 1. Agent 模板'); - console.log('-'.repeat(70)); + console.log("\n📋 1. Agent 模板"); + console.log("-".repeat(70)); // 列出所有模板 const templates = await client.agents.listTemplates(); console.log(`✅ 可用模板: ${templates.length} 个`); templates.forEach((template, i) => { - const icon = template.builtin ? '🔧' : '✨'; + const icon = template.builtin ? "🔧" : "✨"; console.log(` ${icon} ${i + 1}. ${template.name} (${template.type})`); console.log(` ${template.description}`); }); @@ -34,177 +34,190 @@ async function main() { // ======================================================================== // 2. 创建 Agent // ======================================================================== - console.log('\n🤖 2. 创建 Agent'); - console.log('-'.repeat(70)); + console.log("\n🤖 2. 创建 Agent"); + console.log("-".repeat(70)); // 从模板创建 - const assistant = await client.agents.createFromTemplate('assistant', { - name: 'My Assistant', - description: '我的智能助手', - llmProvider: 'anthropic', - llmModel: 'claude-sonnet-4', + const assistant = await client.agents.createFromTemplate("assistant", { + name: "My Assistant", + description: "我的智能助手", + llmProvider: "anthropic", + llmModel: "claude-sonnet-4", llmParams: { temperature: 0.7, - maxTokens: 4096 - } + maxTokens: 4096, + }, }); - console.log('✅ 从模板创建 Agent:', assistant.id); - console.log(' 名称:', assistant.name); - console.log(' 状态:', assistant.status); - console.log(' LLM:', `${assistant.llmProvider}/${assistant.llmModel}`); + console.log("✅ 从模板创建 Agent:", assistant.id); + console.log(" 名称:", assistant.name); + console.log(" 状态:", assistant.status); + console.log(" LLM:", `${assistant.llmProvider}/${assistant.llmModel}`); // 直接创建 const researcher = await client.agents.create({ - name: 'Research Agent', - description: 'AI 研究专家', - templateId: 'researcher', - llmProvider: 'openai', - llmModel: 'gpt-4-turbo', - systemPrompt: 'You are an expert AI researcher. Provide detailed, accurate information.', - tools: ['http_request', 'web_scraper'], - middlewares: ['summarization', 'cost_tracker'] + name: "Research Agent", + description: "AI 研究专家", + templateId: "researcher", + llmProvider: "openai", + llmModel: "gpt-4-turbo", + systemPrompt: + "You are an expert AI researcher. Provide detailed, accurate information.", + tools: ["http_request", "web_scraper"], + middlewares: ["summarization", "cost_tracker"], }); - console.log('✅ 直接创建 Agent:', researcher.id); + console.log("✅ 直接创建 Agent:", researcher.id); // ======================================================================== // 3. Agent 管理 // ======================================================================== - console.log('\n📂 3. Agent 管理'); - console.log('-'.repeat(70)); + console.log("\n📂 3. Agent 管理"); + console.log("-".repeat(70)); // 列出所有 Agents const agents = await client.agents.list({ - status: 'active', + status: "active", page: 1, pageSize: 10, - sortBy: 'createdAt', - sortOrder: 'desc' + sortBy: "createdAt", + sortOrder: "desc", }); - console.log(`📋 总共 ${agents.total} 个 Agents (显示 ${agents.items.length} 个):`); + console.log( + `📋 总共 ${agents.total} 个 Agents (显示 ${agents.items.length} 个):`, + ); agents.items.forEach((agent, i) => { console.log(` ${i + 1}. ${agent.name} (${agent.id})`); - console.log(` 状态: ${agent.status} | LLM: ${agent.llmProvider}/${agent.llmModel}`); + console.log( + ` 状态: ${agent.status} | LLM: ${agent.llmProvider}/${agent.llmModel}`, + ); }); // 获取 Agent 详情 const agentDetail = await client.agents.get(assistant.id); - console.log('\n🔍 Agent 详情:'); - console.log(' 名称:', agentDetail.name); - console.log(' 模板:', agentDetail.templateId); - console.log(' 工具:', agentDetail.tools?.join(', ') || '无'); - console.log(' 中间件:', agentDetail.middlewares?.join(', ') || '无'); - console.log(' 版本:', agentDetail.version); + console.log("\n🔍 Agent 详情:"); + console.log(" 名称:", agentDetail.name); + console.log(" 模板:", agentDetail.templateId); + console.log(" 工具:", agentDetail.tools?.join(", ") || "无"); + console.log(" 中间件:", agentDetail.middlewares?.join(", ") || "无"); + console.log(" 版本:", agentDetail.version); // 更新 Agent await client.agents.update(assistant.id, { - description: '我的智能助手 - 已更新', + description: "我的智能助手 - 已更新", llmParams: { - temperature: 0.8 + temperature: 0.8, }, - tools: ['bash', 'http_request', 'file_read'] + tools: ["bash", "http_request", "file_read"], }); - console.log('✅ Agent 已更新'); + console.log("✅ Agent 已更新"); // ======================================================================== // 4. Agent 对话(同步) // ======================================================================== - console.log('\n💬 4. Agent 对话(同步)'); - console.log('-'.repeat(70)); + console.log("\n💬 4. Agent 对话(同步)"); + console.log("-".repeat(70)); const chatResponse = await client.agents.chat(assistant.id, { - input: 'Hello! Can you help me understand what AsterClient is?', - userId: 'user-123' + input: "Hello! Can you help me understand what AsterClient is?", + userId: "user-123", }); - console.log('🤖 Agent 响应:'); + console.log("🤖 Agent 响应:"); console.log(` Session ID: ${chatResponse.sessionId}`); console.log(` 响应: ${chatResponse.response}`); - + if (chatResponse.usage) { - console.log(' Token 使用:'); + console.log(" Token 使用:"); console.log(` Prompt: ${chatResponse.usage.promptTokens}`); console.log(` Completion: ${chatResponse.usage.completionTokens}`); console.log(` Total: ${chatResponse.usage.totalTokens}`); } - + if (chatResponse.cost) { - console.log(` 成本: ${chatResponse.cost.currency} ${chatResponse.cost.amount.toFixed(4)}`); + console.log( + ` 成本: ${chatResponse.cost.currency} ${chatResponse.cost.amount.toFixed(4)}`, + ); } - + console.log(` 执行时间: ${chatResponse.executionTime}ms`); // 继续对话(复用 Session) const followUp = await client.agents.chat(assistant.id, { - input: 'Can you give me an example use case?', + input: "Can you give me an example use case?", sessionId: chatResponse.sessionId, - userId: 'user-123' + userId: "user-123", }); - console.log('\n💬 继续对话:'); + console.log("\n💬 继续对话:"); console.log(` 响应: ${followUp.response}`); // ======================================================================== // 5. Agent 对话(流式) // ======================================================================== - console.log('\n🌊 5. Agent 对话(流式)'); - console.log('-'.repeat(70)); + console.log("\n🌊 5. Agent 对话(流式)"); + console.log("-".repeat(70)); + + console.log("🤖 开始流式对话..."); + let streamResponse = ""; - console.log('🤖 开始流式对话...'); - let streamResponse = ''; - try { for await (const event of client.agents.chatStream(assistant.id, { - input: 'Tell me about the benefits of using AsterClient', - userId: 'user-123' + input: "Tell me about the benefits of using AsterClient", + userId: "user-123", })) { switch (event.type) { - case 'start': + case "start": console.log(` Session: ${event.sessionId}`); break; - case 'token': + case "token": streamResponse += event.token; process.stdout.write(event.token); break; - case 'tool_call': + case "tool_call": console.log(`\n 🔧 工具调用: ${event.toolCall.name}`); break; - case 'end': - console.log('\n ✅ 完成'); + case "end": + console.log("\n ✅ 完成"); console.log(` 总耗时: ${event.response.executionTime}ms`); break; - case 'error': + case "error": console.log(`\n ❌ 错误: ${event.error}`); break; } } } catch (error: any) { - console.log('\n⚠️ 流式对话失败:', error.message); + console.log("\n⚠️ 流式对话失败:", error.message); } // ======================================================================== // 6. Agent 统计 // ======================================================================== - console.log('\n📊 6. Agent 统计'); - console.log('-'.repeat(70)); + console.log("\n📊 6. Agent 统计"); + console.log("-".repeat(70)); const stats = await client.agents.getStats(assistant.id, { start: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString(), - end: new Date().toISOString() + end: new Date().toISOString(), }); - console.log('Agent 统计(过去7天):'); + console.log("Agent 统计(过去7天):"); console.log(` 总请求数: ${stats.totalRequests}`); - console.log(` 成功率: ${((stats.successfulRequests / stats.totalRequests) * 100).toFixed(1)}%`); + console.log( + ` 成功率: ${((stats.successfulRequests / stats.totalRequests) * 100).toFixed(1)}%`, + ); console.log(` 平均响应时间: ${stats.avgResponseTime.toFixed(2)}ms`); - console.log(` Token 使用: ${stats.tokenUsage.totalTokens.toLocaleString()}`); - console.log(` 总成本: ${stats.cost.currency} ${stats.cost.total.toFixed(4)}`); - + console.log( + ` Token 使用: ${stats.tokenUsage.totalTokens.toLocaleString()}`, + ); + console.log( + ` 总成本: ${stats.cost.currency} ${stats.cost.total.toFixed(4)}`, + ); + if (stats.toolCalls) { console.log(` 工具调用: ${stats.toolCalls.total} 次`); const topTools = Object.entries(stats.toolCalls.byTool) .sort(([, a], [, b]) => b - a) .slice(0, 3); if (topTools.length > 0) { - console.log(' 最常用工具:'); + console.log(" 最常用工具:"); topTools.forEach(([tool, count]) => { console.log(` - ${tool}: ${count} 次`); }); @@ -214,118 +227,125 @@ async function main() { // 汇总统计 const aggregated = await client.agents.getAggregatedStats({ start: new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString(), - end: new Date().toISOString() + end: new Date().toISOString(), }); - console.log('\n📈 所有 Agents 汇总(过去24小时):'); - console.log(` 总 Agents: ${aggregated.totalAgents} | 活跃: ${aggregated.activeAgents}`); + console.log("\n📈 所有 Agents 汇总(过去24小时):"); + console.log( + ` 总 Agents: ${aggregated.totalAgents} | 活跃: ${aggregated.activeAgents}`, + ); console.log(` 总请求数: ${aggregated.totalRequests.toLocaleString()}`); console.log(` 总 Tokens: ${aggregated.totalTokens.toLocaleString()}`); - console.log(` 总成本: ${aggregated.currency} ${aggregated.totalCost.toFixed(2)}`); + console.log( + ` 总成本: ${aggregated.currency} ${aggregated.totalCost.toFixed(2)}`, + ); // ======================================================================== // 7. Agent 克隆 // ======================================================================== - console.log('\n📋 7. Agent 克隆'); - console.log('-'.repeat(70)); - - const cloned = await client.agents.clone(assistant.id, 'My Assistant (Clone)'); - console.log('✅ Agent 已克隆:', cloned.id); - console.log(' 原始 Agent:', assistant.id); - console.log(' 克隆 Agent:', cloned.id); - console.log(' 名称:', cloned.name); + console.log("\n📋 7. Agent 克隆"); + console.log("-".repeat(70)); + + const cloned = await client.agents.clone( + assistant.id, + "My Assistant (Clone)", + ); + console.log("✅ Agent 已克隆:", cloned.id); + console.log(" 原始 Agent:", assistant.id); + console.log(" 克隆 Agent:", cloned.id); + console.log(" 名称:", cloned.name); // ======================================================================== // 8. Agent 状态管理 // ======================================================================== - console.log('\n⚙️ 8. Agent 状态管理'); - console.log('-'.repeat(70)); + console.log("\n⚙️ 8. Agent 状态管理"); + console.log("-".repeat(70)); // 禁用 Agent await client.agents.disable(cloned.id); - console.log('⏸️ Agent 已禁用:', cloned.id); + console.log("⏸️ Agent 已禁用:", cloned.id); // 激活 Agent await client.agents.activate(cloned.id); - console.log('▶️ Agent 已激活:', cloned.id); + console.log("▶️ Agent 已激活:", cloned.id); // 归档 Agent await client.agents.archive(cloned.id); - console.log('📦 Agent 已归档:', cloned.id); + console.log("📦 Agent 已归档:", cloned.id); // ======================================================================== // 9. Agent 验证 // ======================================================================== - console.log('\n✅ 9. Agent 验证'); - console.log('-'.repeat(70)); + console.log("\n✅ 9. Agent 验证"); + console.log("-".repeat(70)); const validation = await client.agents.validate({ - name: 'Test Agent', - templateId: 'assistant', - llmProvider: 'openai', - llmModel: 'gpt-4', + name: "Test Agent", + templateId: "assistant", + llmProvider: "openai", + llmModel: "gpt-4", llmParams: { - temperature: 0.7 - } + temperature: 0.7, + }, }); - console.log('验证结果:'); - console.log(` 有效: ${validation.valid ? '✅' : '❌'}`); + console.log("验证结果:"); + console.log(` 有效: ${validation.valid ? "✅" : "❌"}`); if (validation.errors && validation.errors.length > 0) { - console.log(' 错误:'); - validation.errors.forEach(err => console.log(` - ${err}`)); + console.log(" 错误:"); + validation.errors.forEach((err) => console.log(` - ${err}`)); } if (validation.warnings && validation.warnings.length > 0) { - console.log(' 警告:'); - validation.warnings.forEach(warn => console.log(` - ${warn}`)); + console.log(" 警告:"); + validation.warnings.forEach((warn) => console.log(` - ${warn}`)); } // ======================================================================== // 10. 批量操作 // ======================================================================== - console.log('\n🗂️ 10. 批量操作'); - console.log('-'.repeat(70)); + console.log("\n🗂️ 10. 批量操作"); + console.log("-".repeat(70)); // 批量归档 await client.agents.archiveBatch([researcher.id]); - console.log('✅ 批量归档完成'); + console.log("✅ 批量归档完成"); // 批量激活 await client.agents.activateBatch([researcher.id]); - console.log('✅ 批量激活完成'); + console.log("✅ 批量激活完成"); // ======================================================================== // 11. 清理 // ======================================================================== - console.log('\n🧹 11. 清理'); - console.log('-'.repeat(70)); + console.log("\n🧹 11. 清理"); + console.log("-".repeat(70)); await client.agents.delete(assistant.id); - console.log('✅ Agent 已删除:', assistant.id); + console.log("✅ Agent 已删除:", assistant.id); await client.agents.deleteBatch([researcher.id, cloned.id]); - console.log('✅ 批量删除完成'); - - console.log('\n' + '='.repeat(70)); - console.log('✅ 演示完成!'); - console.log('='.repeat(70)); - - console.log('\n📝 总结:'); - console.log('本示例展示了 Agent 的完整功能:'); - console.log(' 1. ✅ Agent 模板浏览和使用'); - console.log(' 2. ✅ Agent 创建(从模板/直接创建)'); - console.log(' 3. ✅ Agent 管理(列表、详情、更新)'); - console.log(' 4. ✅ Agent 对话(同步)'); - console.log(' 5. ✅ Agent 对话(流式)'); - console.log(' 6. ✅ Agent 统计和汇总'); - console.log(' 7. ✅ Agent 克隆'); - console.log(' 8. ✅ Agent 状态管理'); - console.log(' 9. ✅ Agent 验证'); - console.log(' 10. ✅ 批量操作'); - console.log(' 11. ✅ 资源清理'); + console.log("✅ 批量删除完成"); + + console.log("\n" + "=".repeat(70)); + console.log("✅ 演示完成!"); + console.log("=".repeat(70)); + + console.log("\n📝 总结:"); + console.log("本示例展示了 Agent 的完整功能:"); + console.log(" 1. ✅ Agent 模板浏览和使用"); + console.log(" 2. ✅ Agent 创建(从模板/直接创建)"); + console.log(" 3. ✅ Agent 管理(列表、详情、更新)"); + console.log(" 4. ✅ Agent 对话(同步)"); + console.log(" 5. ✅ Agent 对话(流式)"); + console.log(" 6. ✅ Agent 统计和汇总"); + console.log(" 7. ✅ Agent 克隆"); + console.log(" 8. ✅ Agent 状态管理"); + console.log(" 9. ✅ Agent 验证"); + console.log(" 10. ✅ 批量操作"); + console.log(" 11. ✅ 资源清理"); } // 运行示例 -main().catch(error => { - console.error('❌ 错误:', error); +main().catch((error) => { + console.error("❌ 错误:", error); process.exit(1); }); diff --git a/client-sdks/client-js/examples/complete-usage.ts b/client-sdks/client-js/examples/complete-usage.ts index c7ad3a4..4669823 100644 --- a/client-sdks/client-js/examples/complete-usage.ts +++ b/client-sdks/client-js/examples/complete-usage.ts @@ -3,103 +3,110 @@ * 展示主客户端类的所有功能 */ -import { AsterClient } from '@aster/client-js'; +import { AsterClient } from "@aster/client-js"; async function main() { - console.log('='.repeat(70)); - console.log('AsterClient 完整功能演示'); - console.log('='.repeat(70)); + console.log("=".repeat(70)); + console.log("AsterClient 完整功能演示"); + console.log("=".repeat(70)); // ======================================================================== // 1. 初始化客户端 // ======================================================================== - console.log('\n🚀 1. 初始化 AsterClient 客户端'); - console.log('-'.repeat(70)); + console.log("\n🚀 1. 初始化 AsterClient 客户端"); + console.log("-".repeat(70)); const client = new AsterClient({ - baseUrl: 'http://localhost:8080', + baseUrl: "http://localhost:8080", apiKey: process.env.ASTER_API_KEY, timeout: 30000, retry: { maxRetries: 3, - retryDelay: 1000 - } + retryDelay: 1000, + }, }); - console.log('✅ 客户端已初始化'); - console.log(' Base URL:', 'http://localhost:8080'); + console.log("✅ 客户端已初始化"); + console.log(" Base URL:", "http://localhost:8080"); // 健康检查 try { const health = await client.healthCheck(); - console.log('💚 健康检查:', health.status); - console.log(' 组件状态:'); + console.log("💚 健康检查:", health.status); + console.log(" 组件状态:"); Object.entries(health.components).forEach(([name, status]) => { - const icon = status.status === 'healthy' ? '✅' : '⚠️'; + const icon = status.status === "healthy" ? "✅" : "⚠️"; console.log(` ${icon} ${name}: ${status.status}`); }); } catch (error: any) { - console.log('⚠️ 健康检查失败:', error.message); + console.log("⚠️ 健康检查失败:", error.message); } // ======================================================================== // 2. Memory 系统 // ======================================================================== - console.log('\n🧠 2. Memory 系统'); - console.log('-'.repeat(70)); + console.log("\n🧠 2. Memory 系统"); + console.log("-".repeat(70)); // Working Memory - await client.memory.working.set('user_preference', { - theme: 'dark', - language: 'zh-CN', - notifications: true - }, { - scope: 'resource', // 全局级别(跨会话) - ttl: 3600 - }); - console.log('✅ Working Memory 已设置'); + await client.memory.working.set( + "user_preference", + { + theme: "dark", + language: "zh-CN", + notifications: true, + }, + { + scope: "resource", // 全局级别(跨会话) + ttl: 3600, + }, + ); + console.log("✅ Working Memory 已设置"); - const preference = await client.memory.working.get('user_preference'); - console.log('📝 获取 Working Memory:', preference?.value); + const preference = await client.memory.working.get("user_preference"); + console.log("📝 获取 Working Memory:", preference?.value); // Semantic Memory await client.memory.semantic.store( - 'AsterClient is a powerful framework for building AI agents', - { source: 'documentation', category: 'introduction' } + "AsterClient is a powerful framework for building AI agents", + { source: "documentation", category: "introduction" }, ); - console.log('✅ Semantic Memory 已添加'); + console.log("✅ Semantic Memory 已添加"); - const searchResults = await client.memory.semantic.search('What is AsterClient?', { - limit: 3 - }); + const searchResults = await client.memory.semantic.search( + "What is AsterClient?", + { + limit: 3, + }, + ); console.log(`🔍 搜索结果: ${searchResults.length} 条`); // ======================================================================== // 3. Session 管理 // ======================================================================== - console.log('\n💬 3. Session 管理'); - console.log('-'.repeat(70)); + console.log("\n💬 3. Session 管理"); + console.log("-".repeat(70)); const session = await client.sessions.create({ - agentId: 'assistant-agent', - templateId: 'chat-template', - userId: 'user-123', + agentId: "assistant-agent", + templateId: "chat-template", + userId: "user-123", enableCheckpoints: true, - checkpointInterval: 5 + checkpointInterval: 5, }); - console.log('✅ Session 已创建:', session.id); + console.log("✅ Session 已创建:", session.id); await client.sessions.addMessage(session.id, { - role: 'user', - content: 'Hello, how can you help me today?' + role: "user", + content: "Hello, how can you help me today?", }); - console.log('📨 用户消息已添加'); + console.log("📨 用户消息已添加"); await client.sessions.addMessage(session.id, { - role: 'assistant', - content: 'I can help you with various tasks. What do you need?' + role: "assistant", + content: "I can help you with various tasks. What do you need?", }); - console.log('🤖 助手响应已添加'); + console.log("🤖 助手响应已添加"); const messages = await client.sessions.getMessages(session.id); console.log(`📋 消息列表: ${messages.items.length} 条消息`); @@ -107,157 +114,189 @@ async function main() { // ======================================================================== // 4. Workflow 编排 // ======================================================================== - console.log('\n🔄 4. Workflow 编排'); - console.log('-'.repeat(70)); + console.log("\n🔄 4. Workflow 编排"); + console.log("-".repeat(70)); const workflow = await client.workflows.create({ - type: 'sequential', - name: 'Document Processing Pipeline', - description: '文档处理流水线', + type: "sequential", + name: "Document Processing Pipeline", + description: "文档处理流水线", steps: [ - { agent: 'reader', action: 'read_document' }, - { agent: 'analyzer', action: 'analyze_content' }, - { agent: 'summarizer', action: 'generate_summary' } - ] + { agent: "reader", action: "read_document" }, + { agent: "analyzer", action: "analyze_content" }, + { agent: "summarizer", action: "generate_summary" }, + ], }); - console.log('✅ Workflow 已创建:', workflow.id); + console.log("✅ Workflow 已创建:", workflow.id); const run = await client.workflows.execute(workflow.id, { - input: { documentUrl: 'https://example.com/doc.pdf' } + input: { documentUrl: "https://example.com/doc.pdf" }, }); - console.log('▶️ Workflow 已启动:', run.id); - console.log(' 状态:', run.status); - console.log(' 进度:', run.progress, '%'); + console.log("▶️ Workflow 已启动:", run.id); + console.log(" 状态:", run.status); + console.log(" 进度:", run.progress, "%"); // ======================================================================== // 5. MCP 协议 // ======================================================================== - console.log('\n🔌 5. MCP 协议'); - console.log('-'.repeat(70)); + console.log("\n🔌 5. MCP 协议"); + console.log("-".repeat(70)); try { await client.mcp.addServer({ - serverId: 'example-server', - name: 'Example MCP Server', - endpoint: 'http://localhost:8090/mcp', - enabled: true + serverId: "example-server", + name: "Example MCP Server", + endpoint: "http://localhost:8090/mcp", + enabled: true, }); - console.log('✅ MCP Server 已添加'); + console.log("✅ MCP Server 已添加"); const servers = await client.mcp.listServers(); console.log(`📋 MCP Servers: ${servers.length} 个`); } catch (error: any) { - console.log('⚠️ MCP Server 操作失败:', error.message); + console.log("⚠️ MCP Server 操作失败:", error.message); } // ======================================================================== // 6. Middleware 配置 // ======================================================================== - console.log('\n🧅 6. Middleware 配置'); - console.log('-'.repeat(70)); + console.log("\n🧅 6. Middleware 配置"); + console.log("-".repeat(70)); const middlewares = await client.middleware.list(); console.log(`📋 总共 ${middlewares.length} 个 Middlewares`); // 配置 Summarization - await client.middleware.updateConfig('summarization', { + await client.middleware.updateConfig("summarization", { threshold: 170000, keepMessages: 6, - llmProvider: 'anthropic', - llmModel: 'claude-sonnet-4' + llmProvider: "anthropic", + llmModel: "claude-sonnet-4", }); - console.log('✅ Summarization 已配置'); + console.log("✅ Summarization 已配置"); // 配置 Cost Tracker - await client.middleware.updateConfig('cost_tracker', { + await client.middleware.updateConfig("cost_tracker", { enabled: true, - costModel: 'token_based', + costModel: "token_based", pricing: { promptTokenPrice: 0.003, completionTokenPrice: 0.015, - currency: 'USD' + currency: "USD", }, budget: { daily: 100, - monthly: 2000 - } + monthly: 2000, + }, }); - console.log('✅ Cost Tracker 已配置'); + console.log("✅ Cost Tracker 已配置"); // ======================================================================== // 7. Tool 执行 // ======================================================================== - console.log('\n🔧 7. Tool 执行'); - console.log('-'.repeat(70)); + console.log("\n🔧 7. Tool 执行"); + console.log("-".repeat(70)); - const tools = await client.tools.list({ type: 'builtin' }); + const tools = await client.tools.list({ type: "builtin" }); console.log(`📋 内置工具: ${tools.length} 个`); try { // 执行 Bash 工具 - const result = await client.tools.execute('bash', { + const result = await client.tools.execute("bash", { command: 'echo "Hello from AsterClient"', - timeout: 10 + timeout: 10, }); - console.log('✅ Bash 执行成功:'); - console.log(' 耗时:', result.executionTime, 'ms'); - console.log(' 结果:', result.result); + console.log("✅ Bash 执行成功:"); + console.log(" 耗时:", result.executionTime, "ms"); + console.log(" 结果:", result.result); // 执行 HTTP 请求工具 - const httpResult = await client.tools.execute('http_request', { - url: 'https://api.github.com/zen', - method: 'GET' + const httpResult = await client.tools.execute("http_request", { + url: "https://api.github.com/zen", + method: "GET", }); - console.log('✅ HTTP 请求成功:'); - console.log(' 响应:', httpResult.result); + console.log("✅ HTTP 请求成功:"); + console.log(" 响应:", httpResult.result); } catch (error: any) { - console.log('⚠️ 工具执行失败:', error.message); + console.log("⚠️ 工具执行失败:", error.message); } // ======================================================================== // 8. Telemetry 监控 // ======================================================================== - console.log('\n📊 8. Telemetry 监控'); - console.log('-'.repeat(70)); + console.log("\n📊 8. Telemetry 监控"); + console.log("-".repeat(70)); try { // 获取性能指标 const performance = await client.getPerformanceMetrics({ start: new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString(), - end: new Date().toISOString() + end: new Date().toISOString(), }); - console.log('📈 性能指标(过去24小时):'); - console.log(' 总请求数:', performance.requests.total); - console.log(' 成功率:', - ((performance.requests.successful / performance.requests.total) * 100).toFixed(1), '%'); - console.log(' 平均延迟:', performance.requests.avgLatency.toFixed(2), 'ms'); - console.log(' P95 延迟:', performance.requests.p95Latency.toFixed(2), 'ms'); - console.log(' P99 延迟:', performance.requests.p99Latency.toFixed(2), 'ms'); + console.log("📈 性能指标(过去24小时):"); + console.log(" 总请求数:", performance.requests.total); + console.log( + " 成功率:", + ( + (performance.requests.successful / performance.requests.total) * + 100 + ).toFixed(1), + "%", + ); + console.log( + " 平均延迟:", + performance.requests.avgLatency.toFixed(2), + "ms", + ); + console.log( + " P95 延迟:", + performance.requests.p95Latency.toFixed(2), + "ms", + ); + console.log( + " P99 延迟:", + performance.requests.p99Latency.toFixed(2), + "ms", + ); if (performance.tokens) { - console.log(' 总 Tokens:', performance.tokens.total.toLocaleString()); + console.log(" 总 Tokens:", performance.tokens.total.toLocaleString()); } if (performance.cost) { - console.log(' 总成本:', performance.cost.currency, performance.cost.total.toFixed(2)); + console.log( + " 总成本:", + performance.cost.currency, + performance.cost.total.toFixed(2), + ); } // 获取使用统计 const usage = await client.getUsageStatistics({ start: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString(), - end: new Date().toISOString() + end: new Date().toISOString(), }); - console.log('\n📊 使用统计(过去7天):'); + console.log("\n📊 使用统计(过去7天):"); if (usage.sessions) { - console.log(' Sessions: 总计', usage.sessions.total, '| 活跃', usage.sessions.active); - console.log(' 平均时长:', usage.sessions.avgDuration.toFixed(0), '秒'); + console.log( + " Sessions: 总计", + usage.sessions.total, + "| 活跃", + usage.sessions.active, + ); + console.log(" 平均时长:", usage.sessions.avgDuration.toFixed(0), "秒"); } if (usage.workflows) { - console.log(' Workflows: 成功', usage.workflows.successful, '| 失败', usage.workflows.failed); + console.log( + " Workflows: 成功", + usage.workflows.successful, + "| 失败", + usage.workflows.failed, + ); } if (usage.tools) { - console.log(' 工具调用:', usage.tools.total, '次'); + console.log(" 工具调用:", usage.tools.total, "次"); if (usage.tools.topTools && usage.tools.topTools.length > 0) { - console.log(' 最常用工具:'); + console.log(" 最常用工具:"); usage.tools.topTools.slice(0, 3).forEach((tool, i) => { console.log(` ${i + 1}. ${tool.toolName} - ${tool.callCount} 次`); }); @@ -268,87 +307,90 @@ async function main() { const metrics = await client.telemetry.listMetrics(); console.log(`\n📊 Metrics: ${metrics.length} 个`); metrics.slice(0, 5).forEach((metric, i) => { - console.log(` ${i + 1}. ${metric.name} (${metric.type}): ${metric.value} ${metric.unit || ''}`); + console.log( + ` ${i + 1}. ${metric.name} (${metric.type}): ${metric.value} ${metric.unit || ""}`, + ); }); // 查询 Traces const traces = await client.telemetry.queryTraces({ timeRange: { start: new Date(Date.now() - 60 * 60 * 1000).toISOString(), - end: new Date().toISOString() + end: new Date().toISOString(), }, - limit: 5 + limit: 5, }); console.log(`\n🔍 Traces(过去1小时): ${traces.length} 个`); traces.forEach((trace, i) => { - console.log(` ${i + 1}. ${trace.operationName} - ${trace.duration}ms (${trace.status})`); + console.log( + ` ${i + 1}. ${trace.operationName} - ${trace.duration}ms (${trace.status})`, + ); }); - } catch (error: any) { - console.log('⚠️ Telemetry 查询失败:', error.message); + console.log("⚠️ Telemetry 查询失败:", error.message); } // ======================================================================== // 9. 导出数据 // ======================================================================== - console.log('\n💾 9. 数据导出'); - console.log('-'.repeat(70)); + console.log("\n💾 9. 数据导出"); + console.log("-".repeat(70)); try { // 导出 Session const sessionExport = await client.sessions.export(session.id, { - format: 'json', + format: "json", includeMetadata: true, - includeStats: true + includeStats: true, }); - console.log('✅ Session 已导出:'); - console.log(' 格式:', sessionExport.format); - console.log(' 文件名:', sessionExport.suggestedFilename); + console.log("✅ Session 已导出:"); + console.log(" 格式:", sessionExport.format); + console.log(" 文件名:", sessionExport.suggestedFilename); // 导出 Metrics - const metricsExport = await client.telemetry.exportMetrics('json', { + const metricsExport = await client.telemetry.exportMetrics("json", { start: new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString(), - end: new Date().toISOString() + end: new Date().toISOString(), }); - console.log('✅ Metrics 已导出:'); - console.log(' 格式:', metricsExport.format); - console.log(' 文件名:', metricsExport.suggestedFilename); + console.log("✅ Metrics 已导出:"); + console.log(" 格式:", metricsExport.format); + console.log(" 文件名:", metricsExport.suggestedFilename); } catch (error: any) { - console.log('⚠️ 导出失败:', error.message); + console.log("⚠️ 导出失败:", error.message); } // ======================================================================== // 10. 清理 // ======================================================================== - console.log('\n🧹 10. 清理'); - console.log('-'.repeat(70)); + console.log("\n🧹 10. 清理"); + console.log("-".repeat(70)); await client.sessions.complete(session.id); - console.log('✅ Session 已完成'); + console.log("✅ Session 已完成"); await client.workflows.archiveBatch([workflow.id]); - console.log('✅ Workflow 已归档'); - - console.log('\n' + '='.repeat(70)); - console.log('✅ 演示完成!'); - console.log('='.repeat(70)); - - console.log('\n📝 总结:'); - console.log('本示例展示了 AsterClient 的核心功能:'); - console.log(' 1. ✅ 客户端初始化和健康检查'); - console.log(' 2. ✅ Memory 系统(Working + Semantic)'); - console.log(' 3. ✅ Session 管理和消息历史'); - console.log(' 4. ✅ Workflow 编排和执行'); - console.log(' 5. ✅ MCP 协议集成'); - console.log(' 6. ✅ Middleware 配置'); - console.log(' 7. ✅ Tool 执行'); - console.log(' 8. ✅ Telemetry 监控'); - console.log(' 9. ✅ 数据导出'); - console.log(' 10. ✅ 资源清理'); + console.log("✅ Workflow 已归档"); + + console.log("\n" + "=".repeat(70)); + console.log("✅ 演示完成!"); + console.log("=".repeat(70)); + + console.log("\n📝 总结:"); + console.log("本示例展示了 AsterClient 的核心功能:"); + console.log(" 1. ✅ 客户端初始化和健康检查"); + console.log(" 2. ✅ Memory 系统(Working + Semantic)"); + console.log(" 3. ✅ Session 管理和消息历史"); + console.log(" 4. ✅ Workflow 编排和执行"); + console.log(" 5. ✅ MCP 协议集成"); + console.log(" 6. ✅ Middleware 配置"); + console.log(" 7. ✅ Tool 执行"); + console.log(" 8. ✅ Telemetry 监控"); + console.log(" 9. ✅ 数据导出"); + console.log(" 10. ✅ 资源清理"); } // 运行示例 -main().catch(error => { - console.error('❌ 错误:', error); +main().catch((error) => { + console.error("❌ 错误:", error); process.exit(1); }); diff --git a/client-sdks/client-js/examples/eval-usage.ts b/client-sdks/client-js/examples/eval-usage.ts index 5ecb796..1cc6703 100644 --- a/client-sdks/client-js/examples/eval-usage.ts +++ b/client-sdks/client-js/examples/eval-usage.ts @@ -3,184 +3,200 @@ * 展示 Agent 评估、测试和基准测试功能 */ -import { AsterClient } from '@aster/client-js'; +import { AsterClient } from "@aster/client-js"; async function main() { - console.log('='.repeat(70)); - console.log('AsterClient Eval 功能演示'); - console.log('='.repeat(70)); + console.log("=".repeat(70)); + console.log("AsterClient Eval 功能演示"); + console.log("=".repeat(70)); // 初始化客户端 const client = new AsterClient({ - baseUrl: 'http://localhost:8080', - apiKey: process.env.ASTER_API_KEY + baseUrl: "http://localhost:8080", + apiKey: process.env.ASTER_API_KEY, }); // ======================================================================== // 1. 创建测试用例集 // ======================================================================== - console.log('\n📝 1. 创建测试用例集'); - console.log('-'.repeat(70)); + console.log("\n📝 1. 创建测试用例集"); + console.log("-".repeat(70)); const testCaseSet = await client.evals.createTestCaseSet( - 'Q&A Test Cases', + "Q&A Test Cases", [ { - id: 'test-1', - name: 'Basic Greeting', - input: 'Hello, how are you?', - expectedOutput: 'I am doing well, thank you for asking!', - tags: ['greeting', 'simple'] + id: "test-1", + name: "Basic Greeting", + input: "Hello, how are you?", + expectedOutput: "I am doing well, thank you for asking!", + tags: ["greeting", "simple"], }, { - id: 'test-2', - name: 'Technical Question', - input: 'What is the difference between HTTP and HTTPS?', - expectedOutput: 'HTTPS is the secure version of HTTP. It uses SSL/TLS encryption to protect data in transit.', - tags: ['technical', 'security'] + id: "test-2", + name: "Technical Question", + input: "What is the difference between HTTP and HTTPS?", + expectedOutput: + "HTTPS is the secure version of HTTP. It uses SSL/TLS encryption to protect data in transit.", + tags: ["technical", "security"], }, { - id: 'test-3', - name: 'Complex Query', - input: 'Explain how machine learning models are trained', - expectedOutput: 'Machine learning models are trained by feeding them data and adjusting their parameters to minimize prediction errors.', - tags: ['ml', 'complex'] - } + id: "test-3", + name: "Complex Query", + input: "Explain how machine learning models are trained", + expectedOutput: + "Machine learning models are trained by feeding them data and adjusting their parameters to minimize prediction errors.", + tags: ["ml", "complex"], + }, ], - 'A collection of Q&A test cases for agent evaluation' + "A collection of Q&A test cases for agent evaluation", ); - console.log('✅ 测试用例集已创建:', testCaseSet.id); + console.log("✅ 测试用例集已创建:", testCaseSet.id); console.log(` 名称: ${testCaseSet.name}`); console.log(` 测试用例数: ${testCaseSet.testCases.length}`); // ======================================================================== // 2. 快速单次评估 // ======================================================================== - console.log('\n⚡ 2. 快速单次评估'); - console.log('-'.repeat(70)); + console.log("\n⚡ 2. 快速单次评估"); + console.log("-".repeat(70)); // 创建一个测试 Agent - const agent = await client.agents.createFromTemplate('assistant', { - name: 'Test Assistant', - llmProvider: 'openai', - llmModel: 'gpt-4' + const agent = await client.agents.createFromTemplate("assistant", { + name: "Test Assistant", + llmProvider: "openai", + llmModel: "gpt-4", }); - console.log('✅ 测试 Agent 已创建:', agent.id); + console.log("✅ 测试 Agent 已创建:", agent.id); // 执行快速评估 const quickResult = await client.evals.quickEval( agent.id, - 'What is AI?', - 'Artificial Intelligence (AI) refers to computer systems that can perform tasks requiring human intelligence.', + "What is AI?", + "Artificial Intelligence (AI) refers to computer systems that can perform tasks requiring human intelligence.", [ - { type: 'semantic_similarity', weight: 0.5, params: { threshold: 0.7 } }, - { type: 'keyword_coverage', weight: 0.3 }, - { type: 'coherence', weight: 0.2 } - ] + { type: "semantic_similarity", weight: 0.5, params: { threshold: 0.7 } }, + { type: "keyword_coverage", weight: 0.3 }, + { type: "coherence", weight: 0.2 }, + ], ); - console.log('\n📊 快速评估结果:'); + console.log("\n📊 快速评估结果:"); console.log(` 状态: ${quickResult.status}`); console.log(` 总分: ${quickResult.summary.avgScore.toFixed(2)}`); console.log(` 通过率: ${(quickResult.summary.passRate * 100).toFixed(1)}%`); - + const testResult = quickResult.testCaseResults[0]; - console.log('\n 详细结果:'); + console.log("\n 详细结果:"); console.log(` - Agent 输出: ${testResult.output.substring(0, 100)}...`); console.log(` - 评分: ${testResult.overallScore.toFixed(2)}`); - console.log(` - 通过: ${testResult.passed ? '✅' : '❌'}`); + console.log(` - 通过: ${testResult.passed ? "✅" : "❌"}`); console.log(` - 执行时间: ${testResult.executionTime}ms`); // ======================================================================== // 3. 批量评估 // ======================================================================== - console.log('\n📦 3. 批量评估'); - console.log('-'.repeat(70)); + console.log("\n📦 3. 批量评估"); + console.log("-".repeat(70)); - console.log('开始批量评估...'); + console.log("开始批量评估..."); const batchResult = await client.evals.batchEval( agent.id, testCaseSet.testCases, [ - { type: 'semantic_similarity', weight: 0.4 }, - { - type: 'llm_judge', + { type: "semantic_similarity", weight: 0.4 }, + { + type: "llm_judge", weight: 0.4, params: { - provider: 'openai', - model: 'gpt-4', - criteria: ['accuracy', 'completeness', 'clarity'] - } + provider: "openai", + model: "gpt-4", + criteria: ["accuracy", "completeness", "clarity"], + }, }, - { type: 'coherence', weight: 0.2 } + { type: "coherence", weight: 0.2 }, ], - 2 // 并发数 + 2, // 并发数 ); - console.log('\n📊 批量评估结果:'); + console.log("\n📊 批量评估结果:"); console.log(` 总测试用例: ${batchResult.summary.totalTestCases}`); - console.log(` 通过: ${batchResult.summary.passed} | 失败: ${batchResult.summary.failed}`); + console.log( + ` 通过: ${batchResult.summary.passed} | 失败: ${batchResult.summary.failed}`, + ); console.log(` 通过率: ${(batchResult.summary.passRate * 100).toFixed(1)}%`); console.log(` 平均分数: ${batchResult.summary.avgScore.toFixed(2)}`); - console.log(` 平均执行时间: ${batchResult.summary.avgExecutionTime.toFixed(0)}ms`); - + console.log( + ` 平均执行时间: ${batchResult.summary.avgExecutionTime.toFixed(0)}ms`, + ); + if (batchResult.summary.totalTokenUsage) { - console.log(` 总 Tokens: ${batchResult.summary.totalTokenUsage.totalTokens.toLocaleString()}`); + console.log( + ` 总 Tokens: ${batchResult.summary.totalTokenUsage.totalTokens.toLocaleString()}`, + ); } - + if (batchResult.summary.totalCost) { - console.log(` 总成本: ${batchResult.summary.totalCost.currency} ${batchResult.summary.totalCost.amount.toFixed(4)}`); + console.log( + ` 总成本: ${batchResult.summary.totalCost.currency} ${batchResult.summary.totalCost.amount.toFixed(4)}`, + ); } - console.log('\n 各 Scorer 平均分:'); - Object.entries(batchResult.summary.avgScoresByScorer).forEach(([scorer, score]) => { - console.log(` ${scorer}: ${score.toFixed(2)}`); - }); + console.log("\n 各 Scorer 平均分:"); + Object.entries(batchResult.summary.avgScoresByScorer).forEach( + ([scorer, score]) => { + console.log(` ${scorer}: ${score.toFixed(2)}`); + }, + ); - console.log('\n 各测试用例结果:'); + console.log("\n 各测试用例结果:"); batchResult.testCaseResults.forEach((result, i) => { - const icon = result.passed ? '✅' : '❌'; - console.log(` ${icon} ${result.testCaseName}: ${result.overallScore.toFixed(2)}`); + const icon = result.passed ? "✅" : "❌"; + console.log( + ` ${icon} ${result.testCaseName}: ${result.overallScore.toFixed(2)}`, + ); }); // ======================================================================== // 4. Benchmark 多个 Agents // ======================================================================== - console.log('\n🏆 4. Benchmark 多个 Agents'); - console.log('-'.repeat(70)); + console.log("\n🏆 4. Benchmark 多个 Agents"); + console.log("-".repeat(70)); // 创建第二个 Agent - const agent2 = await client.agents.createFromTemplate('assistant', { - name: 'Test Assistant 2', - llmProvider: 'anthropic', - llmModel: 'claude-sonnet-4' + const agent2 = await client.agents.createFromTemplate("assistant", { + name: "Test Assistant 2", + llmProvider: "anthropic", + llmModel: "claude-sonnet-4", }); - console.log('✅ 第二个测试 Agent 已创建:', agent2.id); + console.log("✅ 第二个测试 Agent 已创建:", agent2.id); // 执行 Benchmark - console.log('\n开始 Benchmark...'); + console.log("\n开始 Benchmark..."); const benchmark = await client.evals.createBenchmark({ - name: 'Agent Comparison Benchmark', - description: '比较两个 Agents 的性能', + name: "Agent Comparison Benchmark", + description: "比较两个 Agents 的性能", agentIds: [agent.id, agent2.id], testCaseSetId: testCaseSet.id, scorers: [ - { type: 'semantic_similarity', weight: 0.5 }, - { type: 'keyword_coverage', weight: 0.3 }, - { type: 'coherence', weight: 0.2 } + { type: "semantic_similarity", weight: 0.5 }, + { type: "keyword_coverage", weight: 0.3 }, + { type: "coherence", weight: 0.2 }, ], - concurrency: 2 + concurrency: 2, }); // 等待 Benchmark 完成 - const benchmarkResult = await client.evals.waitForBenchmarkCompletion(benchmark.id); + const benchmarkResult = await client.evals.waitForBenchmarkCompletion( + benchmark.id, + ); - console.log('\n📊 Benchmark 结果:'); + console.log("\n📊 Benchmark 结果:"); console.log(` 状态: ${benchmarkResult.status}`); - console.log('\n 排行榜:'); + console.log("\n 排行榜:"); benchmarkResult.leaderboard.forEach((entry) => { - const medal = entry.rank === 1 ? '🥇' : entry.rank === 2 ? '🥈' : '🥉'; + const medal = entry.rank === 1 ? "🥇" : entry.rank === 2 ? "🥈" : "🥉"; console.log(` ${medal} #${entry.rank} ${entry.agentName}`); console.log(` 平均分数: ${entry.avgScore.toFixed(2)}`); console.log(` 通过率: ${(entry.passRate * 100).toFixed(1)}%`); @@ -190,50 +206,53 @@ async function main() { // ======================================================================== // 5. A/B 测试 // ======================================================================== - console.log('\n🔬 5. A/B 测试'); - console.log('-'.repeat(70)); + console.log("\n🔬 5. A/B 测试"); + console.log("-".repeat(70)); - console.log('开始 A/B 测试...'); + console.log("开始 A/B 测试..."); const abTestResult = await client.evals.compareAgents( agent.id, agent2.id, testCaseSet.id, [ - { type: 'semantic_similarity', weight: 0.5 }, - { type: 'keyword_coverage', weight: 0.5 } - ] + { type: "semantic_similarity", weight: 0.5 }, + { type: "keyword_coverage", weight: 0.5 }, + ], ); - console.log('\n📊 A/B 测试结果:'); + console.log("\n📊 A/B 测试结果:"); console.log(` 状态: ${abTestResult.status}`); - + const stats = abTestResult.statisticalAnalysis; - console.log('\n 统计分析:'); + console.log("\n 统计分析:"); console.log(` Agent A 平均分: ${stats.agentAAvgScore.toFixed(2)}`); console.log(` Agent B 平均分: ${stats.agentBAvgScore.toFixed(2)}`); - console.log(` 差异: ${stats.difference > 0 ? '+' : ''}${stats.difference.toFixed(2)} (${stats.differencePercent > 0 ? '+' : ''}${stats.differencePercent.toFixed(1)}%)`); + console.log( + ` 差异: ${stats.difference > 0 ? "+" : ""}${stats.difference.toFixed(2)} (${stats.differencePercent > 0 ? "+" : ""}${stats.differencePercent.toFixed(1)}%)`, + ); console.log(` p-value: ${stats.pValue.toFixed(4)}`); - console.log(` 显著性: ${stats.isSignificant ? '✅ 显著' : '❌ 不显著'}`); - + console.log(` 显著性: ${stats.isSignificant ? "✅ 显著" : "❌ 不显著"}`); + if (stats.winner) { - const winnerIcon = stats.winner === 'A' ? '🏆' : stats.winner === 'B' ? '🏆' : '🤝'; + const winnerIcon = + stats.winner === "A" ? "🏆" : stats.winner === "B" ? "🏆" : "🤝"; console.log(` 胜者: ${winnerIcon} Agent ${stats.winner}`); } // ======================================================================== // 6. 生成报告 // ======================================================================== - console.log('\n📄 6. 生成报告'); - console.log('-'.repeat(70)); + console.log("\n📄 6. 生成报告"); + console.log("-".repeat(70)); // 生成 HTML 报告 const htmlReport = await client.evals.generateReport({ evalId: batchResult.evalId, - format: 'html', + format: "html", includeDetails: true, - includeVisualization: true + includeVisualization: true, }); - console.log('✅ HTML 报告已生成'); + console.log("✅ HTML 报告已生成"); console.log(` 格式: ${htmlReport.format}`); console.log(` 生成时间: ${htmlReport.generatedAt}`); console.log(` 内容长度: ${htmlReport.content.length} 字符`); @@ -241,44 +260,51 @@ async function main() { // 生成 Markdown 报告 const mdReport = await client.evals.generateReport({ evalId: batchResult.evalId, - format: 'markdown', - includeDetails: false + format: "markdown", + includeDetails: false, }); - console.log('\n✅ Markdown 报告已生成'); - console.log(' 预览:'); - console.log(mdReport.content.substring(0, 200) + '...'); + console.log("\n✅ Markdown 报告已生成"); + console.log(" 预览:"); + console.log(mdReport.content.substring(0, 200) + "..."); // 导出 JSON - const jsonExport = await client.evals.exportResult(batchResult.evalId, 'json'); - console.log('\n✅ JSON 导出已完成'); + const jsonExport = await client.evals.exportResult( + batchResult.evalId, + "json", + ); + console.log("\n✅ JSON 导出已完成"); console.log(` 大小: ${jsonExport.length} 字符`); // ======================================================================== // 7. Eval 管理 // ======================================================================== - console.log('\n📂 7. Eval 管理'); - console.log('-'.repeat(70)); + console.log("\n📂 7. Eval 管理"); + console.log("-".repeat(70)); // 列出所有 Evals const evals = await client.evals.list({ agentId: agent.id, - status: 'completed', + status: "completed", page: 1, pageSize: 10, - sortBy: 'createdAt', - sortOrder: 'desc' + sortBy: "createdAt", + sortOrder: "desc", }); - console.log(`📋 找到 ${evals.total} 个 Evals (显示 ${evals.items.length} 个):`); + console.log( + `📋 找到 ${evals.total} 个 Evals (显示 ${evals.items.length} 个):`, + ); evals.items.forEach((evalInfo, i) => { console.log(` ${i + 1}. ${evalInfo.name} (${evalInfo.type})`); console.log(` 状态: ${evalInfo.status} | 进度: ${evalInfo.progress}%`); - console.log(` 测试用例: ${evalInfo.completedTestCases}/${evalInfo.totalTestCases}`); + console.log( + ` 测试用例: ${evalInfo.completedTestCases}/${evalInfo.totalTestCases}`, + ); }); // 获取 Eval 详情 const evalDetail = await client.evals.get(batchResult.evalId); - console.log('\n🔍 Eval 详情:'); + console.log("\n🔍 Eval 详情:"); console.log(` ID: ${evalDetail.id}`); console.log(` 名称: ${evalDetail.name}`); console.log(` 类型: ${evalDetail.type}`); @@ -288,8 +314,8 @@ async function main() { // ======================================================================== // 8. 测试用例集管理 // ======================================================================== - console.log('\n📚 8. 测试用例集管理'); - console.log('-'.repeat(70)); + console.log("\n📚 8. 测试用例集管理"); + console.log("-".repeat(70)); // 列出所有测试用例集 const testCaseSets = await client.evals.listTestCaseSets(); @@ -300,49 +326,49 @@ async function main() { // 更新测试用例集 await client.evals.updateTestCaseSet(testCaseSet.id, { - description: 'Updated: ' + testCaseSet.description + description: "Updated: " + testCaseSet.description, }); - console.log('\n✅ 测试用例集已更新'); + console.log("\n✅ 测试用例集已更新"); // ======================================================================== // 9. 清理 // ======================================================================== - console.log('\n🧹 9. 清理'); - console.log('-'.repeat(70)); + console.log("\n🧹 9. 清理"); + console.log("-".repeat(70)); // 删除 Evals await client.evals.delete(quickResult.evalId); await client.evals.delete(batchResult.evalId); - console.log('✅ Evals 已删除'); + console.log("✅ Evals 已删除"); // 删除测试用例集 await client.evals.deleteTestCaseSet(testCaseSet.id); - console.log('✅ 测试用例集已删除'); + console.log("✅ 测试用例集已删除"); // 删除 Agents await client.agents.delete(agent.id); await client.agents.delete(agent2.id); - console.log('✅ Agents 已删除'); - - console.log('\n' + '='.repeat(70)); - console.log('✅ 演示完成!'); - console.log('='.repeat(70)); - - console.log('\n📝 总结:'); - console.log('本示例展示了 Eval 的完整功能:'); - console.log(' 1. ✅ 测试用例集管理'); - console.log(' 2. ✅ 快速单次评估'); - console.log(' 3. ✅ 批量评估'); - console.log(' 4. ✅ Benchmark 多个 Agents'); - console.log(' 5. ✅ A/B 测试和统计分析'); - console.log(' 6. ✅ 报告生成(HTML/Markdown/JSON)'); - console.log(' 7. ✅ Eval 管理和查询'); - console.log(' 8. ✅ 测试用例集管理'); - console.log(' 9. ✅ 资源清理'); + console.log("✅ Agents 已删除"); + + console.log("\n" + "=".repeat(70)); + console.log("✅ 演示完成!"); + console.log("=".repeat(70)); + + console.log("\n📝 总结:"); + console.log("本示例展示了 Eval 的完整功能:"); + console.log(" 1. ✅ 测试用例集管理"); + console.log(" 2. ✅ 快速单次评估"); + console.log(" 3. ✅ 批量评估"); + console.log(" 4. ✅ Benchmark 多个 Agents"); + console.log(" 5. ✅ A/B 测试和统计分析"); + console.log(" 6. ✅ 报告生成(HTML/Markdown/JSON)"); + console.log(" 7. ✅ Eval 管理和查询"); + console.log(" 8. ✅ 测试用例集管理"); + console.log(" 9. ✅ 资源清理"); } // 运行示例 -main().catch(error => { - console.error('❌ 错误:', error); +main().catch((error) => { + console.error("❌ 错误:", error); process.exit(1); }); diff --git a/client-sdks/client-js/examples/event-subscription.ts b/client-sdks/client-js/examples/event-subscription.ts index 8dfe313..3afb322 100644 --- a/client-sdks/client-js/examples/event-subscription.ts +++ b/client-sdks/client-js/examples/event-subscription.ts @@ -9,8 +9,8 @@ import { isProgressEvent, isControlEvent, isMonitorEvent, - isEventType -} from '@aster/client-js'; + isEventType, +} from "@aster/client-js"; async function main() { // 1. 创建 WebSocket 客户端 @@ -18,15 +18,15 @@ async function main() { maxReconnectAttempts: 5, reconnectDelay: 1000, heartbeatInterval: 30000, - heartbeatTimeout: 10000 + heartbeatTimeout: 10000, }); // 2. 连接到 aster 服务器 try { - await ws.connect('ws://localhost:8080/ws'); - console.log('✅ Connected to aster'); + await ws.connect("ws://localhost:8080/ws"); + console.log("✅ Connected to aster"); } catch (error) { - console.error('❌ Connection failed:', error); + console.error("❌ Connection failed:", error); return; } @@ -35,11 +35,11 @@ async function main() { // 4. 订阅所有三个通道 const subscription = subscriptionManager.subscribe( - ['progress', 'control', 'monitor'], + ["progress", "control", "monitor"], { - agentId: 'agent-123', - eventTypes: ['thinking', 'text_chunk', 'tool_start', 'token_usage'] - } + agentId: "agent-123", + eventTypes: ["thinking", "text_chunk", "tool_start", "token_usage"], + }, ); // 5. 处理事件 @@ -57,7 +57,7 @@ async function main() { } } } catch (error) { - console.error('❌ Event subscription error:', error); + console.error("❌ Event subscription error:", error); } // 6. 清理 @@ -69,18 +69,23 @@ async function main() { * 处理 Progress Channel 事件 */ function handleProgressEvent(event: any) { - if (isEventType(event, 'thinking')) { - console.log('🤔 AI 正在思考:', event.data.content); - } else if (isEventType(event, 'text_chunk')) { + if (isEventType(event, "thinking")) { + console.log("🤔 AI 正在思考:", event.data.content); + } else if (isEventType(event, "text_chunk")) { process.stdout.write(event.data.delta); - } else if (isEventType(event, 'tool_start')) { - console.log('🔧 调用工具:', event.data.toolName); - } else if (isEventType(event, 'tool_end')) { - console.log('✅ 工具完成:', event.data.toolName, '结果:', event.data.result); - } else if (isEventType(event, 'done')) { - console.log('\n\n✅ 任务完成:', event.data.text); - } else if (isEventType(event, 'error')) { - console.error('❌ 错误:', event.data.error); + } else if (isEventType(event, "tool_start")) { + console.log("🔧 调用工具:", event.data.toolName); + } else if (isEventType(event, "tool_end")) { + console.log( + "✅ 工具完成:", + event.data.toolName, + "结果:", + event.data.result, + ); + } else if (isEventType(event, "done")) { + console.log("\n\n✅ 任务完成:", event.data.text); + } else if (isEventType(event, "error")) { + console.error("❌ 错误:", event.data.error); } } @@ -88,15 +93,15 @@ function handleProgressEvent(event: any) { * 处理 Control Channel 事件 */ function handleControlEvent(event: any) { - if (isEventType(event, 'tool_approval_request')) { - console.log('⚠️ 需要审批工具:', event.data.toolName); - console.log(' 审批 ID:', event.data.approvalId); - console.log(' 参数:', event.data.params); + if (isEventType(event, "tool_approval_request")) { + console.log("⚠️ 需要审批工具:", event.data.toolName); + console.log(" 审批 ID:", event.data.approvalId); + console.log(" 参数:", event.data.params); // 这里可以调用 API 批准或拒绝 - } else if (isEventType(event, 'pause')) { - console.log('⏸️ 执行暂停:', event.data.reason); - } else if (isEventType(event, 'resume')) { - console.log('▶️ 执行恢复:', event.data.timestamp); + } else if (isEventType(event, "pause")) { + console.log("⏸️ 执行暂停:", event.data.reason); + } else if (isEventType(event, "resume")) { + console.log("▶️ 执行恢复:", event.data.timestamp); } } @@ -104,18 +109,24 @@ function handleControlEvent(event: any) { * 处理 Monitor Channel 事件 */ function handleMonitorEvent(event: any) { - if (isEventType(event, 'token_usage')) { - console.log('📊 Token 使用:', { + if (isEventType(event, "token_usage")) { + console.log("📊 Token 使用:", { prompt: event.data.promptTokens, completion: event.data.completionTokens, - total: event.data.totalTokens + total: event.data.totalTokens, }); - } else if (isEventType(event, 'latency')) { - console.log('⏱️ 延迟:', event.data.latencyMs, 'ms', '操作:', event.data.operation); - } else if (isEventType(event, 'cost')) { - console.log('💰 成本:', event.data.cost, event.data.currency); - } else if (isEventType(event, 'compliance')) { - const status = event.data.passed ? '✅' : '❌'; + } else if (isEventType(event, "latency")) { + console.log( + "⏱️ 延迟:", + event.data.latencyMs, + "ms", + "操作:", + event.data.operation, + ); + } else if (isEventType(event, "cost")) { + console.log("💰 成本:", event.data.cost, event.data.currency); + } else if (isEventType(event, "compliance")) { + const status = event.data.passed ? "✅" : "❌"; console.log(`${status} 合规检查:`, event.data.details); } } diff --git a/client-sdks/client-js/examples/mcp-middleware-tool.ts b/client-sdks/client-js/examples/mcp-middleware-tool.ts index 4e51bc9..19fc8cc 100644 --- a/client-sdks/client-js/examples/mcp-middleware-tool.ts +++ b/client-sdks/client-js/examples/mcp-middleware-tool.ts @@ -5,48 +5,48 @@ import { MCPResource, MiddlewareResource, - ToolResource -} from '@aster/client-js'; + ToolResource, +} from "@aster/client-js"; async function main() { - console.log('='.repeat(60)); - console.log('AsterClient MCP + Middleware + Tool 演示'); - console.log('='.repeat(60)); + console.log("=".repeat(60)); + console.log("AsterClient MCP + Middleware + Tool 演示"); + console.log("=".repeat(60)); // 创建资源实例 const mcp = new MCPResource({ - baseUrl: 'http://localhost:8080', - apiKey: process.env.ASTER_API_KEY + baseUrl: "http://localhost:8080", + apiKey: process.env.ASTER_API_KEY, }); const middleware = new MiddlewareResource({ - baseUrl: 'http://localhost:8080', - apiKey: process.env.ASTER_API_KEY + baseUrl: "http://localhost:8080", + apiKey: process.env.ASTER_API_KEY, }); const tool = new ToolResource({ - baseUrl: 'http://localhost:8080', - apiKey: process.env.ASTER_API_KEY + baseUrl: "http://localhost:8080", + apiKey: process.env.ASTER_API_KEY, }); // ======================================================================== // 1. MCP 协议演示 // ======================================================================== - console.log('\n🔌 1. MCP 协议(Model Context Protocol)'); - console.log('-'.repeat(60)); + console.log("\n🔌 1. MCP 协议(Model Context Protocol)"); + console.log("-".repeat(60)); // 添加 MCP Server const mcpServer = await mcp.addServer({ - serverId: 'my-mcp-server', - name: 'My MCP Server', - endpoint: 'http://localhost:8090/mcp', - accessKeyId: 'key', - accessKeySecret: 'secret', - enabled: true + serverId: "my-mcp-server", + name: "My MCP Server", + endpoint: "http://localhost:8090/mcp", + accessKeyId: "key", + accessKeySecret: "secret", + enabled: true, }); - console.log('✅ 添加 MCP Server:', mcpServer.serverId); - console.log(' 状态:', mcpServer.status); - console.log(' 工具数:', mcpServer.toolCount); + console.log("✅ 添加 MCP Server:", mcpServer.serverId); + console.log(" 状态:", mcpServer.status); + console.log(" 工具数:", mcpServer.toolCount); // 列出所有 Servers const servers = await mcp.listServers(); @@ -54,15 +54,15 @@ async function main() { // 连接到 Server try { - await mcp.connectServer('my-mcp-server'); - console.log('✅ 已连接到 Server'); + await mcp.connectServer("my-mcp-server"); + console.log("✅ 已连接到 Server"); } catch (error: any) { - console.log('⚠️ 连接失败:', error.message); + console.log("⚠️ 连接失败:", error.message); } // 获取 Server 的工具列表 try { - const tools = await mcp.getServerTools('my-mcp-server'); + const tools = await mcp.getServerTools("my-mcp-server"); console.log(`🔧 Server 提供 ${tools.length} 个工具:`); tools.forEach((tool, index) => { console.log(` ${index + 1}. ${tool.name} - ${tool.description}`); @@ -70,102 +70,116 @@ async function main() { // 调用 MCP 工具 if (tools.length > 0) { - const result = await mcp.call('my-mcp-server', tools[0].name, { + const result = await mcp.call("my-mcp-server", tools[0].name, { // 参数示例 - input: 'test' + input: "test", }); - console.log('📤 工具调用结果:'); - console.log(' 成功:', result.success); - console.log(' 耗时:', result.executionTime, 'ms'); + console.log("📤 工具调用结果:"); + console.log(" 成功:", result.success); + console.log(" 耗时:", result.executionTime, "ms"); if (result.result) { - console.log(' 结果:', JSON.stringify(result.result).substring(0, 100)); + console.log( + " 结果:", + JSON.stringify(result.result).substring(0, 100), + ); } } } catch (error: any) { - console.log('⚠️ 获取工具失败:', error.message); + console.log("⚠️ 获取工具失败:", error.message); } // MCP 统计信息 try { const stats = await mcp.getStats(); - console.log('📊 MCP 统计:'); - console.log(' 连接的 Servers:', stats.connectedServers, '/', stats.totalServers); - console.log(' 总工具数:', stats.totalTools); - console.log(' 总调用次数:', stats.totalCalls); - console.log(' 成功率:', ((stats.successfulCalls / stats.totalCalls) * 100).toFixed(1), '%'); + console.log("📊 MCP 统计:"); + console.log( + " 连接的 Servers:", + stats.connectedServers, + "/", + stats.totalServers, + ); + console.log(" 总工具数:", stats.totalTools); + console.log(" 总调用次数:", stats.totalCalls); + console.log( + " 成功率:", + ((stats.successfulCalls / stats.totalCalls) * 100).toFixed(1), + "%", + ); } catch (error: any) { - console.log('⚠️ 获取统计失败:', error.message); + console.log("⚠️ 获取统计失败:", error.message); } // ======================================================================== // 2. Middleware 系统演示 // ======================================================================== - console.log('\n🧅 2. Middleware 系统(洋葱模型)'); - console.log('-'.repeat(60)); + console.log("\n🧅 2. Middleware 系统(洋葱模型)"); + console.log("-".repeat(60)); // 列出所有 Middleware const middlewares = await middleware.list(); console.log(`📋 总共 ${middlewares.length} 个 Middlewares:`); middlewares.forEach((mw, index) => { - const status = mw.enabled ? '✅' : '⏸️ '; - console.log(` ${status} ${index + 1}. [P${mw.priority}] ${mw.displayName} - ${mw.description}`); + const status = mw.enabled ? "✅" : "⏸️ "; + console.log( + ` ${status} ${index + 1}. [P${mw.priority}] ${mw.displayName} - ${mw.description}`, + ); }); // 配置 Summarization Middleware(上下文压缩) - console.log('\n📝 配置 Summarization Middleware:'); - const summarization = await middleware.updateConfig('summarization', { - threshold: 170000, // 170K tokens 后触发总结 - keepMessages: 6, // 保留最近 6 条消息 - llmProvider: 'anthropic', - llmModel: 'claude-sonnet-4' + console.log("\n📝 配置 Summarization Middleware:"); + const summarization = await middleware.updateConfig("summarization", { + threshold: 170000, // 170K tokens 后触发总结 + keepMessages: 6, // 保留最近 6 条消息 + llmProvider: "anthropic", + llmModel: "claude-sonnet-4", }); - console.log('✅ Summarization 已配置'); - console.log(' 阈值:', summarization.config?.threshold, 'tokens'); - console.log(' 保留消息数:', summarization.config?.keepMessages); + console.log("✅ Summarization 已配置"); + console.log(" 阈值:", summarization.config?.threshold, "tokens"); + console.log(" 保留消息数:", summarization.config?.keepMessages); // 配置 Tool Approval Middleware(工具审批) - console.log('\n🔐 配置 Tool Approval Middleware:'); - await middleware.updateConfig('tool_approval', { - approvalRequired: ['file_delete', 'bash', 'database_query'], - autoApprove: ['file_read', 'http_request'], - approvalTimeout: 300, // 5分钟 - timeoutBehavior: 'reject' + console.log("\n🔐 配置 Tool Approval Middleware:"); + await middleware.updateConfig("tool_approval", { + approvalRequired: ["file_delete", "bash", "database_query"], + autoApprove: ["file_read", "http_request"], + approvalTimeout: 300, // 5分钟 + timeoutBehavior: "reject", }); - console.log('✅ Tool Approval 已配置'); - console.log(' 需要审批的工具: file_delete, bash, database_query'); - console.log(' 自动批准的工具: file_read, http_request'); + console.log("✅ Tool Approval 已配置"); + console.log(" 需要审批的工具: file_delete, bash, database_query"); + console.log(" 自动批准的工具: file_read, http_request"); // 配置 PII Redaction Middleware(敏感信息脱敏) - console.log('\n🔒 配置 PII Redaction Middleware:'); - await middleware.updateConfig('pii_redaction', { - enabledTypes: ['email', 'phone', 'ssn', 'credit_card'], - strategy: 'mask', // 遮蔽策略 - partial: true // 保留部分信息 + console.log("\n🔒 配置 PII Redaction Middleware:"); + await middleware.updateConfig("pii_redaction", { + enabledTypes: ["email", "phone", "ssn", "credit_card"], + strategy: "mask", // 遮蔽策略 + partial: true, // 保留部分信息 }); - console.log('✅ PII Redaction 已配置'); + console.log("✅ PII Redaction 已配置"); // 配置 Cost Tracker Middleware(成本追踪) - console.log('\n💰 配置 Cost Tracker Middleware:'); - await middleware.updateConfig('cost_tracker', { + console.log("\n💰 配置 Cost Tracker Middleware:"); + await middleware.updateConfig("cost_tracker", { enabled: true, - costModel: 'token_based', + costModel: "token_based", pricing: { - promptTokenPrice: 0.003, // $0.003 / 1K tokens - completionTokenPrice: 0.015, // $0.015 / 1K tokens - currency: 'USD' + promptTokenPrice: 0.003, // $0.003 / 1K tokens + completionTokenPrice: 0.015, // $0.015 / 1K tokens + currency: "USD", }, budget: { - daily: 100, // $100/天 - monthly: 2000 // $2000/月 - } + daily: 100, // $100/天 + monthly: 2000, // $2000/月 + }, }); - console.log('✅ Cost Tracker 已配置'); - console.log(' 每日预算: $100'); - console.log(' 每月预算: $2000'); + console.log("✅ Cost Tracker 已配置"); + console.log(" 每日预算: $100"); + console.log(" 每月预算: $2000"); // 获取 Middleware 执行顺序 const executionOrder = await middleware.getExecutionOrder(); - console.log('\n🔄 Middleware 执行顺序:'); + console.log("\n🔄 Middleware 执行顺序:"); executionOrder.forEach((name, index) => { console.log(` ${index + 1}. ${name}`); }); @@ -173,30 +187,32 @@ async function main() { // 获取 Middleware 统计信息 try { const allStats = await middleware.getAllStats(); - console.log('\n📊 Middleware 统计:'); - allStats.slice(0, 3).forEach(stat => { + console.log("\n📊 Middleware 统计:"); + allStats.slice(0, 3).forEach((stat) => { console.log(` ${stat.name}:`); console.log(` 执行: ${stat.executionCount} 次`); - console.log(` 成功率: ${((stat.successCount / stat.executionCount) * 100).toFixed(1)}%`); + console.log( + ` 成功率: ${((stat.successCount / stat.executionCount) * 100).toFixed(1)}%`, + ); console.log(` 平均耗时: ${stat.avgExecutionTime.toFixed(2)} ms`); }); } catch (error: any) { - console.log('⚠️ 获取统计失败:', error.message); + console.log("⚠️ 获取统计失败:", error.message); } // ======================================================================== // 3. Tool 系统演示 // ======================================================================== - console.log('\n🔧 3. Tool 系统'); - console.log('-'.repeat(60)); + console.log("\n🔧 3. Tool 系统"); + console.log("-".repeat(60)); // 列出所有工具 const tools = await tool.list(); console.log(`📋 总共 ${tools.length} 个工具:`); - + // 按分类统计 const categoryCount: Record = {}; - tools.forEach(t => { + tools.forEach((t) => { categoryCount[t.category] = (categoryCount[t.category] || 0) + 1; }); Object.entries(categoryCount).forEach(([category, count]) => { @@ -204,139 +220,147 @@ async function main() { }); // 列出内置工具 - const builtinTools = tools.filter(t => t.type === 'builtin'); + const builtinTools = tools.filter((t) => t.type === "builtin"); console.log(`\n🛠️ 内置工具 (${builtinTools.length} 个):`); builtinTools.forEach((t, index) => { - const status = t.enabled ? '✅' : '⏸️ '; - const approval = t.requiresApproval ? '🔒' : ''; - console.log(` ${status}${approval} ${index + 1}. ${t.name} - ${t.description}`); + const status = t.enabled ? "✅" : "⏸️ "; + const approval = t.requiresApproval ? "🔒" : ""; + console.log( + ` ${status}${approval} ${index + 1}. ${t.name} - ${t.description}`, + ); }); // 执行 Bash 工具(同步) - console.log('\n💻 执行 Bash 工具:'); + console.log("\n💻 执行 Bash 工具:"); try { - const result = await tool.execute('bash', { + const result = await tool.execute("bash", { command: 'echo "Hello from AsterClient!"', - workDir: '/tmp', - timeout: 10 + workDir: "/tmp", + timeout: 10, }); - console.log('✅ 执行成功:'); - console.log(' 耗时:', result.executionTime, 'ms'); - console.log(' 结果:', result.result); + console.log("✅ 执行成功:"); + console.log(" 耗时:", result.executionTime, "ms"); + console.log(" 结果:", result.result); } catch (error: any) { - console.log('⚠️ 执行失败:', error.message); + console.log("⚠️ 执行失败:", error.message); } // 执行 HTTP 请求工具 - console.log('\n🌐 执行 HTTP 请求工具:'); + console.log("\n🌐 执行 HTTP 请求工具:"); try { - const result = await tool.execute('http_request', { - url: 'https://api.github.com/zen', - method: 'GET', - timeout: 10 + const result = await tool.execute("http_request", { + url: "https://api.github.com/zen", + method: "GET", + timeout: 10, }); - console.log('✅ 执行成功:'); - console.log(' 耗时:', result.executionTime, 'ms'); - console.log(' 响应:', result.result); + console.log("✅ 执行成功:"); + console.log(" 耗时:", result.executionTime, "ms"); + console.log(" 响应:", result.result); } catch (error: any) { - console.log('⚠️ 执行失败:', error.message); + console.log("⚠️ 执行失败:", error.message); } // 执行长时运行工具(异步) - console.log('\n⏱️ 执行 Web Scraper(长时运行工具):'); + console.log("\n⏱️ 执行 Web Scraper(长时运行工具):"); try { - const asyncResult = await tool.executeAsync('web_scraper', { - url: 'https://example.com', - selectors: ['h1', 'p'], + const asyncResult = await tool.executeAsync("web_scraper", { + url: "https://example.com", + selectors: ["h1", "p"], executeJs: true, - waitTime: 2000 + waitTime: 2000, }); - console.log('✅ 任务已创建:', asyncResult.taskId); - console.log(' 状态:', asyncResult.status); + console.log("✅ 任务已创建:", asyncResult.taskId); + console.log(" 状态:", asyncResult.status); // 等待任务完成 - console.log('⏳ 等待任务完成...'); + console.log("⏳ 等待任务完成..."); const task = await tool.waitForTask(asyncResult.taskId, { pollInterval: 2000, - timeout: 60000 + timeout: 60000, }); - console.log('✅ 任务完成:'); - console.log(' 状态:', task.status); - console.log(' 进度:', task.progress, '%'); + console.log("✅ 任务完成:"); + console.log(" 状态:", task.status); + console.log(" 进度:", task.progress, "%"); if (task.result) { - console.log(' 结果:', JSON.stringify(task.result).substring(0, 200)); + console.log(" 结果:", JSON.stringify(task.result).substring(0, 200)); } } catch (error: any) { - console.log('⚠️ 执行失败:', error.message); + console.log("⚠️ 执行失败:", error.message); } // 列出所有任务 try { const tasks = await tool.listTasks({ - status: 'running' + status: "running", }); console.log(`\n📊 运行中的任务: ${tasks.length} 个`); tasks.forEach((t, index) => { - console.log(` ${index + 1}. [${t.toolName}] ${t.status} - ${t.progress}%`); + console.log( + ` ${index + 1}. [${t.toolName}] ${t.status} - ${t.progress}%`, + ); }); } catch (error: any) { - console.log('⚠️ 获取任务列表失败:', error.message); + console.log("⚠️ 获取任务列表失败:", error.message); } // 工具统计信息 try { const allStats = await tool.getAllStats(); - console.log('\n📊 工具使用统计 (Top 5):'); + console.log("\n📊 工具使用统计 (Top 5):"); allStats .sort((a, b) => b.totalCalls - a.totalCalls) .slice(0, 5) .forEach((stat, index) => { console.log(` ${index + 1}. ${stat.toolName}:`); console.log(` 调用: ${stat.totalCalls} 次`); - console.log(` 成功率: ${((stat.successCount / stat.totalCalls) * 100).toFixed(1)}%`); + console.log( + ` 成功率: ${((stat.successCount / stat.totalCalls) * 100).toFixed(1)}%`, + ); console.log(` 平均耗时: ${stat.avgExecutionTime.toFixed(2)} ms`); }); } catch (error: any) { - console.log('⚠️ 获取统计失败:', error.message); + console.log("⚠️ 获取统计失败:", error.message); } // 工具使用报告 try { const report = await tool.getUsageReport({ - start: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString(), // 7天前 - end: new Date().toISOString() + start: new Date(Date.now() - 7 * 24 * 60 * 60 * 1000).toISOString(), // 7天前 + end: new Date().toISOString(), }); - console.log('\n📈 工具使用报告(过去7天):'); - console.log(' 总调用次数:', report.totalCalls); - console.log(' 最常用工具:'); + console.log("\n📈 工具使用报告(过去7天):"); + console.log(" 总调用次数:", report.totalCalls); + console.log(" 最常用工具:"); report.topTools.slice(0, 3).forEach((t, index) => { - console.log(` ${index + 1}. ${t.toolName} - ${t.callCount} 次 (${t.percentage.toFixed(1)}%)`); + console.log( + ` ${index + 1}. ${t.toolName} - ${t.callCount} 次 (${t.percentage.toFixed(1)}%)`, + ); }); } catch (error: any) { - console.log('⚠️ 获取报告失败:', error.message); + console.log("⚠️ 获取报告失败:", error.message); } // ======================================================================== // 4. 清理 // ======================================================================== - console.log('\n🧹 4. 清理'); - console.log('-'.repeat(60)); + console.log("\n🧹 4. 清理"); + console.log("-".repeat(60)); // 断开 MCP Server try { - await mcp.disconnectServer('my-mcp-server'); - console.log('✅ MCP Server 已断开'); + await mcp.disconnectServer("my-mcp-server"); + console.log("✅ MCP Server 已断开"); } catch (error: any) { - console.log('⚠️ 断开失败:', error.message); + console.log("⚠️ 断开失败:", error.message); } - console.log('\n' + '='.repeat(60)); - console.log('✅ 演示完成!'); - console.log('='.repeat(60)); + console.log("\n" + "=".repeat(60)); + console.log("✅ 演示完成!"); + console.log("=".repeat(60)); } // 运行示例 -main().catch(error => { - console.error('❌ 错误:', error); +main().catch((error) => { + console.error("❌ 错误:", error); process.exit(1); }); diff --git a/client-sdks/client-js/examples/memory-usage.ts b/client-sdks/client-js/examples/memory-usage.ts index 1ffe941..38cdf19 100644 --- a/client-sdks/client-js/examples/memory-usage.ts +++ b/client-sdks/client-js/examples/memory-usage.ts @@ -2,213 +2,227 @@ * Memory 三层记忆系统使用示例 */ -import { MemoryResource } from '@aster/client-js'; +import { MemoryResource } from "@aster/client-js"; async function main() { // 创建 Memory 资源 const memory = new MemoryResource({ - baseUrl: 'http://localhost:8080', - apiKey: process.env.ASTER_API_KEY + baseUrl: "http://localhost:8080", + apiKey: process.env.ASTER_API_KEY, }); - console.log('='.repeat(60)); - console.log('AsterClient 三层记忆系统演示'); - console.log('='.repeat(60)); + console.log("=".repeat(60)); + console.log("AsterClient 三层记忆系统演示"); + console.log("=".repeat(60)); // ======================================================================== // 1. Working Memory 演示 // ======================================================================== - console.log('\n📝 1. Working Memory(工作记忆)'); - console.log('-'.repeat(60)); + console.log("\n📝 1. Working Memory(工作记忆)"); + console.log("-".repeat(60)); // 设置 Thread 作用域的记忆(会话级别) - await memory.working.set('user_preference', { - theme: 'dark', - language: 'zh-CN', - notifications: true - }, { - scope: 'thread', - ttl: 3600 // 1小时后过期 - }); - console.log('✅ 设置 Thread 作用域记忆: user_preference'); + await memory.working.set( + "user_preference", + { + theme: "dark", + language: "zh-CN", + notifications: true, + }, + { + scope: "thread", + ttl: 3600, // 1小时后过期 + }, + ); + console.log("✅ 设置 Thread 作用域记忆: user_preference"); // 设置 Resource 作用域的记忆(全局) - await memory.working.set('app_config', { - version: '1.0.0', - features: ['chat', 'workflow', 'memory'] - }, { - scope: 'resource', // 全局作用域 - ttl: 0 // 永不过期 - }); - console.log('✅ 设置 Resource 作用域记忆: app_config'); + await memory.working.set( + "app_config", + { + version: "1.0.0", + features: ["chat", "workflow", "memory"], + }, + { + scope: "resource", // 全局作用域 + ttl: 0, // 永不过期 + }, + ); + console.log("✅ 设置 Resource 作用域记忆: app_config"); // 带 JSON Schema 验证的记忆 - await memory.working.set('validated_data', { - count: 42, - name: 'test' - }, { - schema: { - type: 'object', - properties: { - count: { type: 'number' }, - name: { type: 'string' } + await memory.working.set( + "validated_data", + { + count: 42, + name: "test", + }, + { + schema: { + type: "object", + properties: { + count: { type: "number" }, + name: { type: "string" }, + }, + required: ["count", "name"], }, - required: ['count', 'name'] - } - }); - console.log('✅ 设置带 Schema 验证的记忆: validated_data'); + }, + ); + console.log("✅ 设置带 Schema 验证的记忆: validated_data"); // 获取记忆 - const preference = await memory.working.get('user_preference', 'thread'); - console.log('📖 读取记忆:', preference); + const preference = await memory.working.get("user_preference", "thread"); + console.log("📖 读取记忆:", preference); // 列出所有 Thread 作用域的记忆 - const threadMemories = await memory.working.list('thread'); - console.log('📋 Thread 作用域记忆数:', Object.keys(threadMemories).length); + const threadMemories = await memory.working.list("thread"); + console.log("📋 Thread 作用域记忆数:", Object.keys(threadMemories).length); // ======================================================================== // 2. Semantic Memory 演示 // ======================================================================== - console.log('\n🔍 2. Semantic Memory(语义记忆)'); - console.log('-'.repeat(60)); + console.log("\n🔍 2. Semantic Memory(语义记忆)"); + console.log("-".repeat(60)); // 存储知识 const chunk1 = await memory.semantic.store( - 'Paris is the capital of France.', - { source: 'wikipedia', category: 'geography', language: 'en' } + "Paris is the capital of France.", + { source: "wikipedia", category: "geography", language: "en" }, ); - console.log('✅ 存储记忆块 1:', chunk1); + console.log("✅ 存储记忆块 1:", chunk1); const chunk2 = await memory.semantic.store( - 'The Eiffel Tower is located in Paris.', - { source: 'wikipedia', category: 'landmarks', language: 'en' } + "The Eiffel Tower is located in Paris.", + { source: "wikipedia", category: "landmarks", language: "en" }, ); - console.log('✅ 存储记忆块 2:', chunk2); + console.log("✅ 存储记忆块 2:", chunk2); const chunk3 = await memory.semantic.store( - 'France is a country in Western Europe.', - { source: 'wikipedia', category: 'geography', language: 'en' } + "France is a country in Western Europe.", + { source: "wikipedia", category: "geography", language: "en" }, ); - console.log('✅ 存储记忆块 3:', chunk3); + console.log("✅ 存储记忆块 3:", chunk3); // 语义搜索 console.log('\n🔎 搜索: "What is the capital of France?"'); const results = await memory.semantic.search( - 'What is the capital of France?', + "What is the capital of France?", { limit: 5, threshold: 0.7, - filter: { category: 'geography' } - } + filter: { category: "geography" }, + }, ); results.forEach((chunk, index) => { - console.log(` ${index + 1}. [Score: ${chunk.score?.toFixed(2)}] ${chunk.content}`); + console.log( + ` ${index + 1}. [Score: ${chunk.score?.toFixed(2)}] ${chunk.content}`, + ); console.log(` Metadata:`, chunk.metadata); }); // ======================================================================== // 3. Memory Provenance 演示 // ======================================================================== - console.log('\n🔗 3. Memory Provenance(记忆溯源)'); - console.log('-'.repeat(60)); + console.log("\n🔗 3. Memory Provenance(记忆溯源)"); + console.log("-".repeat(60)); // 查询记忆溯源 try { const provenance = await memory.getProvenance(chunk1); - console.log('📊 记忆溯源信息:'); - console.log(' - 来源:', provenance.provenance.source); - console.log(' - 置信度:', provenance.provenance.confidence); - console.log(' - 时间:', provenance.provenance.timestamp); + console.log("📊 记忆溯源信息:"); + console.log(" - 来源:", provenance.provenance.source); + console.log(" - 置信度:", provenance.provenance.confidence); + console.log(" - 时间:", provenance.provenance.timestamp); // 查询谱系链 if (provenance.provenance.parentId) { const lineage = await memory.getLineage(chunk1); - console.log(' - 谱系链长度:', lineage.length); + console.log(" - 谱系链长度:", lineage.length); } } catch (error: any) { - console.log('⚠️ 溯源功能未启用或记忆未找到:', error.message); + console.log("⚠️ 溯源功能未启用或记忆未找到:", error.message); } // ======================================================================== // 4. Memory Consolidation 演示 // ======================================================================== - console.log('\n🔄 4. Memory Consolidation(记忆合并)'); - console.log('-'.repeat(60)); + console.log("\n🔄 4. Memory Consolidation(记忆合并)"); + console.log("-".repeat(60)); try { // 触发记忆合并 const consolidation = await memory.consolidate({ - strategy: 'summarize', - llmProvider: 'anthropic', - llmModel: 'claude-sonnet-4' + strategy: "summarize", + llmProvider: "anthropic", + llmModel: "claude-sonnet-4", }); - console.log('✅ 合并任务已启动:', consolidation.jobId); - console.log(' 状态:', consolidation.status); + console.log("✅ 合并任务已启动:", consolidation.jobId); + console.log(" 状态:", consolidation.status); // 查询合并状态 const status = await memory.getConsolidationStatus(consolidation.jobId); - console.log('📊 合并进度:', status.progress, '%'); + console.log("📊 合并进度:", status.progress, "%"); // 如果需要取消 // await memory.cancelConsolidation(consolidation.jobId); } catch (error: any) { - console.log('⚠️ 合并功能未启用:', error.message); + console.log("⚠️ 合并功能未启用:", error.message); } // ======================================================================== // 5. 统计信息 // ======================================================================== - console.log('\n📊 5. 统计信息'); - console.log('-'.repeat(60)); + console.log("\n📊 5. 统计信息"); + console.log("-".repeat(60)); try { const stats = await memory.getStats(); - console.log('Working Memory:'); - console.log(' - Thread 记忆数:', stats.workingMemory.threadCount); - console.log(' - Resource 记忆数:', stats.workingMemory.resourceCount); - console.log(' - 总大小:', stats.workingMemory.totalSize, 'bytes'); - - console.log('Semantic Memory:'); - console.log(' - 记忆块数:', stats.semanticMemory.chunkCount); - console.log(' - 总大小:', stats.semanticMemory.totalSize, 'bytes'); + console.log("Working Memory:"); + console.log(" - Thread 记忆数:", stats.workingMemory.threadCount); + console.log(" - Resource 记忆数:", stats.workingMemory.resourceCount); + console.log(" - 总大小:", stats.workingMemory.totalSize, "bytes"); + + console.log("Semantic Memory:"); + console.log(" - 记忆块数:", stats.semanticMemory.chunkCount); + console.log(" - 总大小:", stats.semanticMemory.totalSize, "bytes"); } catch (error: any) { - console.log('⚠️ 统计信息获取失败:', error.message); + console.log("⚠️ 统计信息获取失败:", error.message); } // ======================================================================== // 6. 清理 // ======================================================================== - console.log('\n🧹 6. 清理(可选)'); - console.log('-'.repeat(60)); + console.log("\n🧹 6. 清理(可选)"); + console.log("-".repeat(60)); // 删除单个记忆 - await memory.working.delete('validated_data', 'thread'); - console.log('✅ 删除 Working Memory: validated_data'); + await memory.working.delete("validated_data", "thread"); + console.log("✅ 删除 Working Memory: validated_data"); // 删除 Semantic Memory await memory.semantic.delete(chunk3); - console.log('✅ 删除 Semantic Memory:', chunk3); + console.log("✅ 删除 Semantic Memory:", chunk3); // 批量删除 await memory.semantic.deleteBatch([chunk1, chunk2]); - console.log('✅ 批量删除 Semantic Memory'); + console.log("✅ 批量删除 Semantic Memory"); // 清空 Thread 作用域的所有记忆 - await memory.working.clear('thread'); - console.log('✅ 清空 Thread 作用域记忆'); + await memory.working.clear("thread"); + console.log("✅ 清空 Thread 作用域记忆"); // 危险:清空所有记忆 // await memory.clearAll(true); - console.log('\n' + '='.repeat(60)); - console.log('✅ 演示完成!'); - console.log('='.repeat(60)); + console.log("\n" + "=".repeat(60)); + console.log("✅ 演示完成!"); + console.log("=".repeat(60)); } // 运行示例 -main().catch(error => { - console.error('❌ 错误:', error); +main().catch((error) => { + console.error("❌ 错误:", error); process.exit(1); }); diff --git a/client-sdks/client-js/examples/session-workflow.ts b/client-sdks/client-js/examples/session-workflow.ts index b8afe29..c20b3a5 100644 --- a/client-sdks/client-js/examples/session-workflow.ts +++ b/client-sdks/client-js/examples/session-workflow.ts @@ -7,101 +7,107 @@ import { WorkflowResource, ParallelWorkflowDefinition, SequentialWorkflowDefinition, - LoopWorkflowDefinition -} from '@aster/client-js'; + LoopWorkflowDefinition, +} from "@aster/client-js"; async function main() { - console.log('='.repeat(60)); - console.log('AsterClient Session + Workflow 演示'); - console.log('='.repeat(60)); + console.log("=".repeat(60)); + console.log("AsterClient Session + Workflow 演示"); + console.log("=".repeat(60)); // 创建资源实例 const session = new SessionResource({ - baseUrl: 'http://localhost:8080', - apiKey: process.env.ASTER_API_KEY + baseUrl: "http://localhost:8080", + apiKey: process.env.ASTER_API_KEY, }); const workflow = new WorkflowResource({ - baseUrl: 'http://localhost:8080', - apiKey: process.env.ASTER_API_KEY + baseUrl: "http://localhost:8080", + apiKey: process.env.ASTER_API_KEY, }); // ======================================================================== // 1. Session 管理演示 // ======================================================================== - console.log('\n📝 1. Session 管理'); - console.log('-'.repeat(60)); + console.log("\n📝 1. Session 管理"); + console.log("-".repeat(60)); // 创建 Session const newSession = await session.create({ - agentId: 'agent-123', - templateId: 'assistant', - userId: 'user-456', + agentId: "agent-123", + templateId: "assistant", + userId: "user-456", metadata: { - project: 'demo', - environment: 'development' + project: "demo", + environment: "development", }, enableCheckpoints: true, - checkpointInterval: 5 // 每5条消息创建一个断点 + checkpointInterval: 5, // 每5条消息创建一个断点 }); - console.log('✅ 创建 Session:', newSession.id); + console.log("✅ 创建 Session:", newSession.id); // 添加消息 await session.addMessage(newSession.id, { - role: 'user', - content: 'Hello! Can you help me with something?' + role: "user", + content: "Hello! Can you help me with something?", }); - console.log('✅ 添加用户消息'); + console.log("✅ 添加用户消息"); await session.addMessage(newSession.id, { - role: 'assistant', - content: 'Of course! I\'d be happy to help. What do you need assistance with?' + role: "assistant", + content: + "Of course! I'd be happy to help. What do you need assistance with?", }); - console.log('✅ 添加助手消息'); + console.log("✅ 添加助手消息"); // 获取消息列表 const messages = await session.getMessages(newSession.id, { page: 1, pageSize: 10, - sort: 'asc' + sort: "asc", }); console.log(`📋 获取消息列表: ${messages.items.length} 条消息`); // ======================================================================== // 2. Checkpoint 断点恢复演示 // ======================================================================== - console.log('\n🔄 2. Checkpoint 断点恢复'); - console.log('-'.repeat(60)); + console.log("\n🔄 2. Checkpoint 断点恢复"); + console.log("-".repeat(60)); // 创建手动 checkpoint - const checkpoint = await session.createCheckpoint(newSession.id, 'before-important-action'); - console.log('✅ 创建 Checkpoint:', checkpoint.id); + const checkpoint = await session.createCheckpoint( + newSession.id, + "before-important-action", + ); + console.log("✅ 创建 Checkpoint:", checkpoint.id); // 获取所有 checkpoints const checkpoints = await session.getCheckpoints(newSession.id); console.log(`📊 总共 ${checkpoints.length} 个 Checkpoints:`); checkpoints.forEach((cp, index) => { - console.log(` ${index + 1}. [${cp.type}] Sequence: ${cp.sequence}, Time: ${cp.timestamp}`); + console.log( + ` ${index + 1}. [${cp.type}] Sequence: ${cp.sequence}, Time: ${cp.timestamp}`, + ); }); // 从 checkpoint 恢复 if (checkpoints.length > 0) { - console.log('\n🔄 从最新 Checkpoint 恢复...'); + console.log("\n🔄 从最新 Checkpoint 恢复..."); const resumed = await session.resume(newSession.id, { checkpointId: checkpoints[checkpoints.length - 1].id, - keepSubsequentMessages: false + keepSubsequentMessages: false, }); - console.log('✅ Session 已恢复:', resumed.status); + console.log("✅ Session 已恢复:", resumed.status); } // ======================================================================== // 3. Session 统计演示 // ======================================================================== - console.log('\n📊 3. Session 统计'); - console.log('-'.repeat(60)); + console.log("\n📊 3. Session 统计"); + console.log("-".repeat(60)); const stats = await session.getStats(newSession.id); - console.log('统计信息:'); + console.log("统计信息:"); console.log(` - 总消息数: ${stats.totalMessages}`); console.log(` - 用户消息: ${stats.userMessages}`); console.log(` - 助手消息: ${stats.assistantMessages}`); @@ -112,123 +118,130 @@ async function main() { // ======================================================================== // 4. Parallel Workflow 演示 // ======================================================================== - console.log('\n🔀 4. Parallel Workflow(并行执行)'); - console.log('-'.repeat(60)); + console.log("\n🔀 4. Parallel Workflow(并行执行)"); + console.log("-".repeat(60)); const parallelWorkflow: ParallelWorkflowDefinition = { - type: 'parallel', - name: 'Multi-Agent Research', - description: '多个 Agent 并行研究不同主题', + type: "parallel", + name: "Multi-Agent Research", + description: "多个 Agent 并行研究不同主题", agents: [ - { id: 'researcher-1', task: 'Research AI trends in 2024' }, - { id: 'researcher-2', task: 'Research quantum computing developments' }, - { id: 'researcher-3', task: 'Research climate tech innovations' } + { id: "researcher-1", task: "Research AI trends in 2024" }, + { id: "researcher-2", task: "Research quantum computing developments" }, + { id: "researcher-3", task: "Research climate tech innovations" }, ], maxConcurrency: 3, - timeout: 300 + timeout: 300, }; const parallelWf = await workflow.create(parallelWorkflow); - console.log('✅ 创建 Parallel Workflow:', parallelWf.id); + console.log("✅ 创建 Parallel Workflow:", parallelWf.id); // 执行 Workflow const parallelRun = await workflow.execute(parallelWf.id, { - input: 'Please provide comprehensive research summaries', - options: { async: false } + input: "Please provide comprehensive research summaries", + options: { async: false }, }); - console.log('▶️ 执行 Workflow, Run ID:', parallelRun.id); + console.log("▶️ 执行 Workflow, Run ID:", parallelRun.id); // 等待完成(模拟) try { - const finalRun = await workflow.waitForCompletion(parallelWf.id, parallelRun.id, { - pollInterval: 2000, - timeout: 60000 - }); - console.log('✅ Workflow 完成:', finalRun.status); + const finalRun = await workflow.waitForCompletion( + parallelWf.id, + parallelRun.id, + { + pollInterval: 2000, + timeout: 60000, + }, + ); + console.log("✅ Workflow 完成:", finalRun.status); } catch (error: any) { - console.log('⚠️ 等待超时或失败:', error.message); + console.log("⚠️ 等待超时或失败:", error.message); } // ======================================================================== // 5. Sequential Workflow 演示 // ======================================================================== - console.log('\n➡️ 5. Sequential Workflow(顺序执行)'); - console.log('-'.repeat(60)); + console.log("\n➡️ 5. Sequential Workflow(顺序执行)"); + console.log("-".repeat(60)); const sequentialWorkflow: SequentialWorkflowDefinition = { - type: 'sequential', - name: 'Document Processing Pipeline', - description: '文档处理流水线', + type: "sequential", + name: "Document Processing Pipeline", + description: "文档处理流水线", steps: [ { - agent: 'reader', - action: 'read_document', - params: { source: 'https://example.com/doc.pdf' } + agent: "reader", + action: "read_document", + params: { source: "https://example.com/doc.pdf" }, }, { - agent: 'analyzer', - action: 'analyze_content', - params: { depth: 'detailed' } + agent: "analyzer", + action: "analyze_content", + params: { depth: "detailed" }, }, { - agent: 'summarizer', - action: 'generate_summary', - params: { length: 'medium' } + agent: "summarizer", + action: "generate_summary", + params: { length: "medium" }, }, { - agent: 'translator', - action: 'translate', - params: { targetLang: 'zh-CN' }, - condition: 'previousStep.language === "en"' - } + agent: "translator", + action: "translate", + params: { targetLang: "zh-CN" }, + condition: 'previousStep.language === "en"', + }, ], - continueOnError: false + continueOnError: false, }; const sequentialWf = await workflow.create(sequentialWorkflow); - console.log('✅ 创建 Sequential Workflow:', sequentialWf.id); + console.log("✅ 创建 Sequential Workflow:", sequentialWf.id); const sequentialRun = await workflow.execute(sequentialWf.id, { - input: { documentUrl: 'https://example.com/doc.pdf' } + input: { documentUrl: "https://example.com/doc.pdf" }, }); - console.log('▶️ 执行 Workflow, Run ID:', sequentialRun.id); + console.log("▶️ 执行 Workflow, Run ID:", sequentialRun.id); // ======================================================================== // 6. Loop Workflow 演示 // ======================================================================== - console.log('\n🔁 6. Loop Workflow(循环执行)'); - console.log('-'.repeat(60)); + console.log("\n🔁 6. Loop Workflow(循环执行)"); + console.log("-".repeat(60)); const loopWorkflow: LoopWorkflowDefinition = { - type: 'loop', - name: 'Iterative Code Optimizer', - description: '迭代优化代码直到达到质量标准', - agent: 'optimizer', - condition: 'result.quality < 0.95', // 质量 < 95% 则继续 + type: "loop", + name: "Iterative Code Optimizer", + description: "迭代优化代码直到达到质量标准", + agent: "optimizer", + condition: "result.quality < 0.95", // 质量 < 95% 则继续 maxIterations: 10, initialInput: { - code: 'function add(a, b) { return a + b; }', - targetQuality: 0.95 - } + code: "function add(a, b) { return a + b; }", + targetQuality: 0.95, + }, }; const loopWf = await workflow.create(loopWorkflow); - console.log('✅ 创建 Loop Workflow:', loopWf.id); + console.log("✅ 创建 Loop Workflow:", loopWf.id); const loopRun = await workflow.execute(loopWf.id, { - input: { code: 'function example() { /* needs optimization */ }' } + input: { code: "function example() { /* needs optimization */ }" }, }); - console.log('▶️ 执行 Workflow, Run ID:', loopRun.id); + console.log("▶️ 执行 Workflow, Run ID:", loopRun.id); // ======================================================================== // 7. Workflow 控制操作 // ======================================================================== - console.log('\n⏯️ 7. Workflow 控制操作'); - console.log('-'.repeat(60)); + console.log("\n⏯️ 7. Workflow 控制操作"); + console.log("-".repeat(60)); // 获取执行详情 - const runDetails = await workflow.getRunDetails(parallelWf.id, parallelRun.id); - console.log('📊 执行详情:'); + const runDetails = await workflow.getRunDetails( + parallelWf.id, + parallelRun.id, + ); + console.log("📊 执行详情:"); console.log(` - 状态: ${runDetails.status}`); console.log(` - 进度: ${runDetails.progress}%`); console.log(` - 步骤: ${runDetails.currentStep}/${runDetails.totalSteps}`); @@ -236,47 +249,49 @@ async function main() { console.log(` - 总耗时: ${runDetails.stats.totalDuration}ms`); // 暂停执行(如果正在运行) - if (loopRun.status === 'running') { + if (loopRun.status === "running") { await workflow.suspend(loopWf.id, { runId: loopRun.id, - reason: 'User requested pause' + reason: "User requested pause", }); - console.log('⏸️ 已暂停 Workflow'); + console.log("⏸️ 已暂停 Workflow"); // 恢复执行 await workflow.resume(loopWf.id, { - runId: loopRun.id + runId: loopRun.id, }); - console.log('▶️ 已恢复 Workflow'); + console.log("▶️ 已恢复 Workflow"); } // ======================================================================== // 8. Workflow 历史查询 // ======================================================================== - console.log('\n📜 8. Workflow 历史查询'); - console.log('-'.repeat(60)); + console.log("\n📜 8. Workflow 历史查询"); + console.log("-".repeat(60)); const runs = await workflow.getRuns(parallelWf.id, { page: 1, - pageSize: 10 + pageSize: 10, }); console.log(`📋 执行历史: 共 ${runs.total} 次执行`); runs.items.forEach((run, index) => { - console.log(` ${index + 1}. [${run.status}] ${run.startedAt} - Progress: ${run.progress}%`); + console.log( + ` ${index + 1}. [${run.status}] ${run.startedAt} - Progress: ${run.progress}%`, + ); }); // ======================================================================== // 9. Session 导出 // ======================================================================== - console.log('\n💾 9. Session 导出'); - console.log('-'.repeat(60)); + console.log("\n💾 9. Session 导出"); + console.log("-".repeat(60)); const exported = await session.export(newSession.id, { - format: 'json', + format: "json", includeMetadata: true, - includeStats: true + includeStats: true, }); - console.log('✅ Session 已导出:'); + console.log("✅ Session 已导出:"); console.log(` - 格式: ${exported.format}`); console.log(` - 文件名: ${exported.suggestedFilename}`); console.log(` - 导出时间: ${exported.exportedAt}`); @@ -284,24 +299,24 @@ async function main() { // ======================================================================== // 10. 清理 // ======================================================================== - console.log('\n🧹 10. 清理'); - console.log('-'.repeat(60)); + console.log("\n🧹 10. 清理"); + console.log("-".repeat(60)); // 完成 Session await session.complete(newSession.id); - console.log('✅ Session 已完成'); + console.log("✅ Session 已完成"); // 归档 Workflows await workflow.archiveBatch([parallelWf.id, sequentialWf.id, loopWf.id]); - console.log('✅ Workflows 已归档'); + console.log("✅ Workflows 已归档"); - console.log('\n' + '='.repeat(60)); - console.log('✅ 演示完成!'); - console.log('='.repeat(60)); + console.log("\n" + "=".repeat(60)); + console.log("✅ 演示完成!"); + console.log("=".repeat(60)); } // 运行示例 -main().catch(error => { - console.error('❌ 错误:', error); +main().catch((error) => { + console.error("❌ 错误:", error); process.exit(1); }); diff --git a/client-sdks/client-js/package.json b/client-sdks/client-js/package.json index aaadf04..8e32440 100644 --- a/client-sdks/client-js/package.json +++ b/client-sdks/client-js/package.json @@ -51,4 +51,3 @@ "ws": "^8.18.3" } } - diff --git a/client-sdks/client-js/src/client.ts b/client-sdks/client-js/src/client.ts index 6ef3fdb..1b1afa8 100644 --- a/client-sdks/client-js/src/client.ts +++ b/client-sdks/client-js/src/client.ts @@ -3,17 +3,17 @@ * 整合所有资源模块 */ -import { ClientOptions } from './resources/base'; -import { AgentResource } from './resources/agent'; -import { MemoryResource } from './resources/memory'; -import { SessionResource } from './resources/session'; -import { WorkflowResource } from './resources/workflow'; -import { MCPResource } from './resources/mcp'; -import { MiddlewareResource } from './resources/middleware'; -import { ToolResource } from './resources/tool'; -import { TelemetryResource } from './resources/telemetry'; -import { EvalResource } from './resources/eval'; -import { SystemResource } from './resources/system'; +import { ClientOptions } from "./resources/base"; +import { AgentResource } from "./resources/agent"; +import { MemoryResource } from "./resources/memory"; +import { SessionResource } from "./resources/session"; +import { WorkflowResource } from "./resources/workflow"; +import { MCPResource } from "./resources/mcp"; +import { MiddlewareResource } from "./resources/middleware"; +import { ToolResource } from "./resources/tool"; +import { TelemetryResource } from "./resources/telemetry"; +import { EvalResource } from "./resources/eval"; +import { SystemResource } from "./resources/system"; /** * aster 客户端配置 @@ -34,20 +34,20 @@ export interface asterConfig { /** * aster 主客户端 - * + * * @example * ```typescript * const client = new aster({ * baseUrl: 'http://localhost:8080', * apiKey: 'your-api-key' * }); - * + * * // 使用 Memory * await client.memory.working.set('key', { data: 'value' }); - * + * * // 使用 Workflow * const wf = await client.workflows.create({ type: 'parallel', ... }); - * + * * // 使用 MCP * await client.mcp.call('server-id', 'tool-name', { params }); * ``` @@ -95,7 +95,7 @@ export class aster { baseUrl: config.baseUrl, apiKey: config.apiKey, timeout: config.timeout, - retry: config.retry + retry: config.retry, }; // 初始化所有资源模块 @@ -136,10 +136,7 @@ export class aster { * @param timeRange 时间范围 * @returns 使用统计 */ - async getUsageStatistics(timeRange?: { - start: string; - end: string; - }) { + async getUsageStatistics(timeRange?: { start: string; end: string }) { return this.telemetry.getUsageStatistics(timeRange); } @@ -148,10 +145,7 @@ export class aster { * @param timeRange 时间范围 * @returns 性能指标 */ - async getPerformanceMetrics(timeRange?: { - start: string; - end: string; - }) { + async getPerformanceMetrics(timeRange?: { start: string; end: string }) { return this.telemetry.getPerformanceMetrics(timeRange); } } diff --git a/client-sdks/client-js/src/events/subscription.ts b/client-sdks/client-js/src/events/subscription.ts index e63aacc..b3c2aa4 100644 --- a/client-sdks/client-js/src/events/subscription.ts +++ b/client-sdks/client-js/src/events/subscription.ts @@ -3,8 +3,8 @@ * 支持异步迭代、背压控制、事件过滤 */ -import { WebSocketClient, WebSocketState } from '../transport/websocket'; -import { StreamEvent, EventEnvelope, Channel, EventFilter } from './types'; +import { WebSocketClient, WebSocketState } from "../transport/websocket"; +import { StreamEvent, EventEnvelope, Channel, EventFilter } from "./types"; /** * 事件订阅 @@ -19,11 +19,7 @@ export class EventSubscription { private resolvers: Array<(value: IteratorResult) => void> = []; private unsubscribeWs?: () => void; - constructor( - ws: WebSocketClient, - channels: Channel[], - filter?: EventFilter - ) { + constructor(ws: WebSocketClient, channels: Channel[], filter?: EventFilter) { this.ws = ws; this.channels = channels; this.filter = filter; @@ -51,14 +47,16 @@ export class EventSubscription { } // 等待新事件 - const result = await new Promise>((resolve) => { - if (!this.isActive) { - resolve({ done: true, value: undefined }); - return; - } - - this.resolvers.push(resolve); - }); + const result = await new Promise>( + (resolve) => { + if (!this.isActive) { + resolve({ done: true, value: undefined }); + return; + } + + this.resolvers.push(resolve); + }, + ); if (result.done) { break; @@ -90,7 +88,7 @@ export class EventSubscription { this.eventQueue = []; // 通知所有等待的迭代器 - this.resolvers.forEach(resolve => { + this.resolvers.forEach((resolve) => { resolve({ done: true, value: undefined }); }); this.resolvers = []; @@ -118,7 +116,10 @@ export class EventSubscription { } // 事件类型过滤 - if (this.filter.eventTypes && !this.filter.eventTypes.includes(envelope.event.type)) { + if ( + this.filter.eventTypes && + !this.filter.eventTypes.includes(envelope.event.type) + ) { return; } } @@ -133,7 +134,9 @@ export class EventSubscription { // 防止队列过大 if (this.eventQueue.length > 1000) { - console.warn('[EventSubscription] Event queue overflow, dropping oldest events'); + console.warn( + "[EventSubscription] Event queue overflow, dropping oldest events", + ); this.eventQueue = this.eventQueue.slice(-500); // 保留最新的 500 个 } } @@ -144,9 +147,9 @@ export class EventSubscription { */ private sendSubscribeRequest(): void { this.ws.send({ - type: 'subscribe', + type: "subscribe", channels: this.channels, - filter: this.filter + filter: this.filter, }); } @@ -155,8 +158,8 @@ export class EventSubscription { */ private sendUnsubscribeRequest(): void { this.ws.send({ - type: 'unsubscribe', - channels: this.channels + type: "unsubscribe", + channels: this.channels, }); } } @@ -177,13 +180,10 @@ export class SubscriptionManager { /** * 创建订阅 */ - subscribe( - channels: Channel[], - filter?: EventFilter - ): EventSubscription { + subscribe(channels: Channel[], filter?: EventFilter): EventSubscription { const subscription = new EventSubscription(this.ws, channels, filter); const subscriptionId = `sub_${++this.subscriptionCounter}`; - + this.subscriptions.set(subscriptionId, subscription); return subscription; @@ -204,7 +204,7 @@ export class SubscriptionManager { * 取消所有订阅 */ unsubscribeAll(): void { - this.subscriptions.forEach(subscription => { + this.subscriptions.forEach((subscription) => { subscription.unsubscribe(); }); this.subscriptions.clear(); diff --git a/client-sdks/client-js/src/events/types.ts b/client-sdks/client-js/src/events/types.ts index 46e1d5a..0ade3e8 100644 --- a/client-sdks/client-js/src/events/types.ts +++ b/client-sdks/client-js/src/events/types.ts @@ -1,6 +1,6 @@ /** * AsterClient 事件驱动架构 - 三通道事件类型定义 - * + * * 三通道设计: * - Progress Channel: 数据流(思考、文本、工具执行) * - Control Channel: 审批流(工具审批、暂停/恢复) @@ -14,7 +14,7 @@ /** * 事件通道类型 */ -export type Channel = 'progress' | 'control' | 'monitor'; +export type Channel = "progress" | "control" | "monitor"; /** * 事件过滤器 @@ -35,8 +35,8 @@ export interface EventFilter { * AI 正在思考的过程 */ export interface ProgressThinkingEvent { - type: 'thinking'; - channel: 'progress'; + type: "thinking"; + channel: "progress"; data: { /** 思考内容 */ content: string; @@ -48,8 +48,8 @@ export interface ProgressThinkingEvent { * 流式文本输出 */ export interface ProgressTextChunkEvent { - type: 'text_chunk'; - channel: 'progress'; + type: "text_chunk"; + channel: "progress"; data: { /** 增量文本 */ delta: string; @@ -63,8 +63,8 @@ export interface ProgressTextChunkEvent { * 工具调用开始 */ export interface ProgressToolStartEvent { - type: 'tool_start'; - channel: 'progress'; + type: "tool_start"; + channel: "progress"; data: { /** 工具名称 */ toolName: string; @@ -78,8 +78,8 @@ export interface ProgressToolStartEvent { * 工具调用完成 */ export interface ProgressToolEndEvent { - type: 'tool_end'; - channel: 'progress'; + type: "tool_end"; + channel: "progress"; data: { /** 工具名称 */ toolName: string; @@ -93,8 +93,8 @@ export interface ProgressToolEndEvent { * Agent 执行完成 */ export interface ProgressDoneEvent { - type: 'done'; - channel: 'progress'; + type: "done"; + channel: "progress"; data: { /** 最终文本 */ text: string; @@ -106,8 +106,8 @@ export interface ProgressDoneEvent { * 执行过程中发生错误 */ export interface ProgressErrorEvent { - type: 'error'; - channel: 'progress'; + type: "error"; + channel: "progress"; data: { /** 错误信息 */ error: string; @@ -134,8 +134,8 @@ export type ProgressEvent = * 需要用户审批工具调用 */ export interface ControlToolApprovalRequestEvent { - type: 'tool_approval_request'; - channel: 'control'; + type: "tool_approval_request"; + channel: "control"; data: { /** 审批 ID */ approvalId: string; @@ -151,8 +151,8 @@ export interface ControlToolApprovalRequestEvent { * 用户审批结果 */ export interface ControlToolApprovalResponseEvent { - type: 'tool_approval_response'; - channel: 'control'; + type: "tool_approval_response"; + channel: "control"; data: { /** 审批 ID */ approvalId: string; @@ -166,8 +166,8 @@ export interface ControlToolApprovalResponseEvent { * Agent 执行被暂停 */ export interface ControlPauseEvent { - type: 'pause'; - channel: 'control'; + type: "pause"; + channel: "control"; data: { /** 暂停原因 */ reason: string; @@ -179,8 +179,8 @@ export interface ControlPauseEvent { * Agent 执行恢复 */ export interface ControlResumeEvent { - type: 'resume'; - channel: 'control'; + type: "resume"; + channel: "control"; data: { /** 恢复时间戳 */ timestamp: string; @@ -205,8 +205,8 @@ export type ControlEvent = * 记录 Token 消耗 */ export interface MonitorTokenUsageEvent { - type: 'token_usage'; - channel: 'monitor'; + type: "token_usage"; + channel: "monitor"; data: { /** Prompt Tokens */ promptTokens: number; @@ -222,8 +222,8 @@ export interface MonitorTokenUsageEvent { * 记录操作延迟 */ export interface MonitorLatencyEvent { - type: 'latency'; - channel: 'monitor'; + type: "latency"; + channel: "monitor"; data: { /** 延迟(毫秒) */ latencyMs: number; @@ -237,8 +237,8 @@ export interface MonitorLatencyEvent { * 记录 API 调用成本 */ export interface MonitorCostEvent { - type: 'cost'; - channel: 'monitor'; + type: "cost"; + channel: "monitor"; data: { /** 成本金额 */ cost: number; @@ -252,8 +252,8 @@ export interface MonitorCostEvent { * 记录合规检查结果 */ export interface MonitorComplianceEvent { - type: 'compliance'; - channel: 'monitor'; + type: "compliance"; + channel: "monitor"; data: { /** 是否通过 */ passed: boolean; @@ -304,29 +304,29 @@ export interface EventEnvelope { * 类型守卫:检查是否为 Progress 事件 */ export function isProgressEvent(event: StreamEvent): event is ProgressEvent { - return event.channel === 'progress'; + return event.channel === "progress"; } /** * 类型守卫:检查是否为 Control 事件 */ export function isControlEvent(event: StreamEvent): event is ControlEvent { - return event.channel === 'control'; + return event.channel === "control"; } /** * 类型守卫:检查是否为 Monitor 事件 */ export function isMonitorEvent(event: StreamEvent): event is MonitorEvent { - return event.channel === 'monitor'; + return event.channel === "monitor"; } /** * 类型守卫:检查具体事件类型 */ -export function isEventType( +export function isEventType( event: StreamEvent, - type: T + type: T, ): event is Extract { return event.type === type; } diff --git a/client-sdks/client-js/src/index.ts b/client-sdks/client-js/src/index.ts index 8d33f65..62b001c 100644 --- a/client-sdks/client-js/src/index.ts +++ b/client-sdks/client-js/src/index.ts @@ -3,62 +3,66 @@ // ============================================================================ // 事件类型 -export * from './events/types'; +export * from "./events/types"; // WebSocket 客户端 -export { WebSocketClient, WebSocketState } from './transport/websocket'; -export type { WebSocketClientOptions } from './transport/websocket'; +export { WebSocketClient, WebSocketState } from "./transport/websocket"; +export type { WebSocketClientOptions } from "./transport/websocket"; // 事件订阅 -export { EventSubscription, SubscriptionManager } from './events/subscription'; +export { EventSubscription, SubscriptionManager } from "./events/subscription"; // Agent 类型 -export * from './types/agent'; +export * from "./types/agent"; // Memory 类型 -export * from './types/memory'; +export * from "./types/memory"; // Session 类型 -export * from './types/session'; +export * from "./types/session"; // Workflow 类型 -export * from './types/workflow'; +export * from "./types/workflow"; // MCP 类型 -export * from './types/mcp'; +export * from "./types/mcp"; // Middleware 类型 -export * from './types/middleware'; +export * from "./types/middleware"; // Tool 类型 -export * from './types/tool'; +export * from "./types/tool"; // Telemetry 类型 -export * from './types/telemetry'; +export * from "./types/telemetry"; // Eval 类型 -export * from './types/eval'; +export * from "./types/eval"; // 资源类 -export { BaseResource } from './resources/base'; -export type { ClientOptions, RequestOptions, RetryOptions } from './resources/base'; -export { AgentResource } from './resources/agent'; -export { MemoryResource } from './resources/memory'; -export { SessionResource } from './resources/session'; -export { WorkflowResource } from './resources/workflow'; -export { MCPResource } from './resources/mcp'; -export { MiddlewareResource } from './resources/middleware'; -export { ToolResource } from './resources/tool'; -export { TelemetryResource } from './resources/telemetry'; -export { EvalResource } from './resources/eval'; +export { BaseResource } from "./resources/base"; +export type { + ClientOptions, + RequestOptions, + RetryOptions, +} from "./resources/base"; +export { AgentResource } from "./resources/agent"; +export { MemoryResource } from "./resources/memory"; +export { SessionResource } from "./resources/session"; +export { WorkflowResource } from "./resources/workflow"; +export { MCPResource } from "./resources/mcp"; +export { MiddlewareResource } from "./resources/middleware"; +export { ToolResource } from "./resources/tool"; +export { TelemetryResource } from "./resources/telemetry"; +export { EvalResource } from "./resources/eval"; // 主客户端类 -export { aster, createClient } from './client'; -export type { asterConfig } from './client'; +export { aster, createClient } from "./client"; +export type { asterConfig } from "./client"; // 向后兼容的别名 -export { aster as AsterClient } from './client'; -export type { asterConfig as AsterClientConfig } from './client'; +export { aster as AsterClient } from "./client"; +export type { asterConfig as AsterClientConfig } from "./client"; // ============================================================================ // 原有接口(向后兼容) diff --git a/client-sdks/client-js/src/resources/agent.ts b/client-sdks/client-js/src/resources/agent.ts index 211b732..ed48f61 100644 --- a/client-sdks/client-js/src/resources/agent.ts +++ b/client-sdks/client-js/src/resources/agent.ts @@ -3,7 +3,7 @@ * Agent 完整管理功能 */ -import { BaseResource, ClientOptions } from './base'; +import { BaseResource, ClientOptions } from "./base"; import { AgentInfo, AgentFilter, @@ -16,8 +16,8 @@ import { AgentTemplate, AgentStats, AgentValidationResult, - AgentStatus -} from '../types/agent'; + AgentStatus, +} from "../types/agent"; /** * Agent 资源类 @@ -37,9 +37,9 @@ export class AgentResource extends BaseResource { * @returns Agent 信息 */ async create(request: CreateAgentRequest): Promise { - return this.request('/v1/agents', { - method: 'POST', - body: request + return this.request("/v1/agents", { + method: "POST", + body: request, }); } @@ -58,8 +58,8 @@ export class AgentResource extends BaseResource { * @returns Agent 列表 */ async list(filter?: AgentFilter): Promise { - return this.request('/v1/agents', { - params: filter + return this.request("/v1/agents", { + params: filter, }); } @@ -71,11 +71,11 @@ export class AgentResource extends BaseResource { */ async update( agentId: string, - updates: UpdateAgentRequest + updates: UpdateAgentRequest, ): Promise { return this.request(`/v1/agents/${agentId}`, { - method: 'PATCH', - body: updates + method: "PATCH", + body: updates, }); } @@ -85,7 +85,7 @@ export class AgentResource extends BaseResource { */ async delete(agentId: string): Promise { await this.request(`/v1/agents/${agentId}`, { - method: 'DELETE' + method: "DELETE", }); } @@ -99,7 +99,7 @@ export class AgentResource extends BaseResource { * @returns 更新后的 Agent */ async activate(agentId: string): Promise { - return this.updateStatus(agentId, 'active'); + return this.updateStatus(agentId, "active"); } /** @@ -108,7 +108,7 @@ export class AgentResource extends BaseResource { * @returns 更新后的 Agent */ async disable(agentId: string): Promise { - return this.updateStatus(agentId, 'disabled'); + return this.updateStatus(agentId, "disabled"); } /** @@ -117,7 +117,7 @@ export class AgentResource extends BaseResource { * @returns 更新后的 Agent */ async archive(agentId: string): Promise { - return this.updateStatus(agentId, 'archived'); + return this.updateStatus(agentId, "archived"); } /** @@ -128,7 +128,7 @@ export class AgentResource extends BaseResource { */ private async updateStatus( agentId: string, - status: AgentStatus + status: AgentStatus, ): Promise { return this.update(agentId, { status }); } @@ -143,13 +143,10 @@ export class AgentResource extends BaseResource { * @param request Chat 请求 * @returns Chat 响应 */ - async chat( - agentId: string, - request: ChatRequest - ): Promise { + async chat(agentId: string, request: ChatRequest): Promise { return this.request(`/v1/agents/${agentId}/chat`, { - method: 'POST', - body: request + method: "POST", + body: request, }); } @@ -161,18 +158,20 @@ export class AgentResource extends BaseResource { */ async *chatStream( agentId: string, - request: ChatRequest + request: ChatRequest, ): AsyncIterable { const response = await fetch( `${this.options.baseUrl}/v1/agents/${agentId}/chat/stream`, { - method: 'POST', + method: "POST", headers: { - 'Content-Type': 'application/json', - ...(this.options.apiKey && { 'Authorization': `Bearer ${this.options.apiKey}` }) + "Content-Type": "application/json", + ...(this.options.apiKey && { + Authorization: `Bearer ${this.options.apiKey}`, + }), }, - body: JSON.stringify(request) - } + body: JSON.stringify(request), + }, ); if (!response.ok) { @@ -181,11 +180,11 @@ export class AgentResource extends BaseResource { const reader = response.body?.getReader(); if (!reader) { - throw new Error('Response body is not readable'); + throw new Error("Response body is not readable"); } const decoder = new TextDecoder(); - let buffer = ''; + let buffer = ""; try { while (true) { @@ -193,20 +192,20 @@ export class AgentResource extends BaseResource { if (done) break; buffer += decoder.decode(value, { stream: true }); - const lines = buffer.split('\n'); - buffer = lines.pop() || ''; + const lines = buffer.split("\n"); + buffer = lines.pop() || ""; for (const line of lines) { - if (line.startsWith('data: ')) { + if (line.startsWith("data: ")) { const data = line.slice(6); - if (data === '[DONE]') { + if (data === "[DONE]") { return; } try { const event = JSON.parse(data) as StreamChatEvent; yield event; } catch (error) { - console.error('Failed to parse SSE data:', data); + console.error("Failed to parse SSE data:", data); } } } @@ -226,7 +225,7 @@ export class AgentResource extends BaseResource { */ async listTemplates(): Promise { const result = await this.request<{ templates: AgentTemplate[] }>( - '/v1/agents/templates' + "/v1/agents/templates", ); return result.templates; } @@ -248,21 +247,22 @@ export class AgentResource extends BaseResource { */ async createFromTemplate( templateId: string, - overrides: Partial + overrides: Partial, ): Promise { const template = await this.getTemplate(templateId); - + const request: CreateAgentRequest = { name: overrides.name || `Agent from ${template.name}`, templateId, - llmProvider: overrides.llmProvider || template.recommendedProvider || 'openai', - llmModel: overrides.llmModel || template.recommendedModel || 'gpt-4', + llmProvider: + overrides.llmProvider || template.recommendedProvider || "openai", + llmModel: overrides.llmModel || template.recommendedModel || "gpt-4", systemPrompt: overrides.systemPrompt || template.defaultSystemPrompt, tools: overrides.tools || template.defaultTools, middlewares: overrides.middlewares || template.defaultMiddlewares, description: overrides.description, llmParams: overrides.llmParams, - metadata: overrides.metadata + metadata: overrides.metadata, }; return this.create(request); @@ -280,10 +280,10 @@ export class AgentResource extends BaseResource { */ async getStats( agentId: string, - timeRange?: { start: string; end: string } + timeRange?: { start: string; end: string }, ): Promise { return this.request(`/v1/agents/${agentId}/stats`, { - params: timeRange + params: timeRange, }); } @@ -303,8 +303,8 @@ export class AgentResource extends BaseResource { totalCost: number; currency: string; }> { - return this.request('/v1/agents/stats/aggregated', { - params: timeRange + return this.request("/v1/agents/stats/aggregated", { + params: timeRange, }); } @@ -318,11 +318,11 @@ export class AgentResource extends BaseResource { * @returns 验证结果 */ async validate( - config: CreateAgentRequest | UpdateAgentRequest + config: CreateAgentRequest | UpdateAgentRequest, ): Promise { - return this.request('/v1/agents/validate', { - method: 'POST', - body: config + return this.request("/v1/agents/validate", { + method: "POST", + body: config, }); } @@ -335,9 +335,9 @@ export class AgentResource extends BaseResource { * @param agentIds Agent ID 列表 */ async deleteBatch(agentIds: string[]): Promise { - await this.request('/v1/agents/batch', { - method: 'DELETE', - body: { agentIds } + await this.request("/v1/agents/batch", { + method: "DELETE", + body: { agentIds }, }); } @@ -346,9 +346,9 @@ export class AgentResource extends BaseResource { * @param agentIds Agent ID 列表 */ async archiveBatch(agentIds: string[]): Promise { - await this.request('/v1/agents/batch/archive', { - method: 'POST', - body: { agentIds } + await this.request("/v1/agents/batch/archive", { + method: "POST", + body: { agentIds }, }); } @@ -357,9 +357,9 @@ export class AgentResource extends BaseResource { * @param agentIds Agent ID 列表 */ async activateBatch(agentIds: string[]): Promise { - await this.request('/v1/agents/batch/activate', { - method: 'POST', - body: { agentIds } + await this.request("/v1/agents/batch/activate", { + method: "POST", + body: { agentIds }, }); } @@ -375,8 +375,8 @@ export class AgentResource extends BaseResource { */ async clone(agentId: string, newName: string): Promise { return this.request(`/v1/agents/${agentId}/clone`, { - method: 'POST', - body: { name: newName } + method: "POST", + body: { name: newName }, }); } } diff --git a/client-sdks/client-js/src/resources/base.ts b/client-sdks/client-js/src/resources/base.ts index 497bb50..204d067 100644 --- a/client-sdks/client-js/src/resources/base.ts +++ b/client-sdks/client-js/src/resources/base.ts @@ -40,7 +40,7 @@ export interface RetryOptions { */ export interface RequestOptions { /** HTTP 方法 */ - method?: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH'; + method?: "GET" | "POST" | "PUT" | "DELETE" | "PATCH"; /** 请求体 */ body?: any; /** 查询参数 */ @@ -66,7 +66,7 @@ export class BaseResource { maxRetries: 3, retryableStatusCodes: [408, 429, 500, 502, 503, 504], backoffMultiplier: 2, - maxBackoffTime: 30000 // 30秒 + maxBackoffTime: 30000, // 30秒 }; constructor(options: ClientOptions) { @@ -75,10 +75,10 @@ export class BaseResource { ...options, retry: { ...this.defaultRetry, - ...options.retry - } + ...options.retry, + }, }; - + this.fetchImpl = options.fetchImpl ?? fetch; } @@ -88,11 +88,11 @@ export class BaseResource { */ protected async request( path: string, - options: RequestOptions = {} + options: RequestOptions = {}, ): Promise { const url = this.buildUrl(path, options.params); const timeout = options.timeout ?? this.options.timeout; - + let lastError: Error | null = null; const maxRetries = this.options.retry!.maxRetries!; @@ -105,28 +105,32 @@ export class BaseResource { try { const response = await this.fetchImpl(url, { - method: options.method ?? 'GET', + method: options.method ?? "GET", headers: this.buildHeaders(options.headers), body: options.body ? JSON.stringify(options.body) : undefined, - signal: options.signal ?? controller.signal + signal: options.signal ?? controller.signal, }); clearTimeout(timeoutId); // 检查是否需要重试 - if (!response.ok && this.shouldRetry(response.status) && attempt < maxRetries) { - lastError = new Error(`HTTP ${response.status}: ${response.statusText}`); + if ( + !response.ok && + this.shouldRetry(response.status) && + attempt < maxRetries + ) { + lastError = new Error( + `HTTP ${response.status}: ${response.statusText}`, + ); await this.delay(this.getBackoffDelay(attempt)); continue; } // 处理响应 return await this.handleResponse(response); - } finally { clearTimeout(timeoutId); } - } catch (error: any) { lastError = error; @@ -149,8 +153,8 @@ export class BaseResource { * 构建完整 URL */ private buildUrl(path: string, params?: Record): string { - const baseUrl = this.options.baseUrl.replace(/\/+$/, ''); - const fullPath = path.startsWith('/') ? path : `/${path}`; + const baseUrl = this.options.baseUrl.replace(/\/+$/, ""); + const fullPath = path.startsWith("/") ? path : `/${path}`; let url = `${baseUrl}${fullPath}`; // 添加查询参数 @@ -173,16 +177,18 @@ export class BaseResource { /** * 构建请求 headers */ - private buildHeaders(customHeaders?: Record): Record { + private buildHeaders( + customHeaders?: Record, + ): Record { const headers: Record = { - 'Content-Type': 'application/json', + "Content-Type": "application/json", ...this.options.headers, - ...customHeaders + ...customHeaders, }; // 添加 API Key if (this.options.apiKey) { - headers['Authorization'] = `Bearer ${this.options.apiKey}`; + headers["Authorization"] = `Bearer ${this.options.apiKey}`; } return headers; @@ -206,7 +212,9 @@ export class BaseResource { } catch (error) { // 不是有效的 JSON if (!response.ok) { - throw new Error(`HTTP ${response.status}: ${text || response.statusText}`); + throw new Error( + `HTTP ${response.status}: ${text || response.statusText}`, + ); } return text as T; } @@ -218,7 +226,12 @@ export class BaseResource { } // 解包 {success: true, data: {...}} 格式的响应 - if (data && typeof data === 'object' && 'success' in data && 'data' in data) { + if ( + data && + typeof data === "object" && + "success" in data && + "data" in data + ) { return data.data as T; } @@ -238,11 +251,11 @@ export class BaseResource { private isRetryableError(error: any): boolean { // 超时、网络错误等 return ( - error.name === 'AbortError' || - error.name === 'TimeoutError' || - error.message?.includes('fetch failed') || - error.message?.includes('network') || - error.message?.includes('ECONNREFUSED') + error.name === "AbortError" || + error.name === "TimeoutError" || + error.message?.includes("fetch failed") || + error.message?.includes("network") || + error.message?.includes("ECONNREFUSED") ); } @@ -254,7 +267,7 @@ export class BaseResource { const { backoffMultiplier, maxBackoffTime } = this.options.retry!; const delay = Math.min( 1000 * Math.pow(backoffMultiplier!, attempt), - maxBackoffTime! + maxBackoffTime!, ); // 添加随机抖动(±25%) const jitter = delay * (0.75 + Math.random() * 0.5); @@ -265,7 +278,7 @@ export class BaseResource { * 延迟函数 */ private delay(ms: number): Promise { - return new Promise(resolve => setTimeout(resolve, ms)); + return new Promise((resolve) => setTimeout(resolve, ms)); } /** diff --git a/client-sdks/client-js/src/resources/eval.ts b/client-sdks/client-js/src/resources/eval.ts index 65e6264..38da85d 100644 --- a/client-sdks/client-js/src/resources/eval.ts +++ b/client-sdks/client-js/src/resources/eval.ts @@ -3,7 +3,7 @@ * Agent 评估和测试系统 */ -import { BaseResource, ClientOptions } from './base'; +import { BaseResource, ClientOptions } from "./base"; import { EvalRequest, EvalInfo, @@ -18,8 +18,8 @@ import { ABTestResult, EvalReportRequest, EvalReportResult, - ScorerConfig -} from '../types/eval'; + ScorerConfig, +} from "../types/eval"; /** * Eval 资源类 @@ -39,9 +39,9 @@ export class EvalResource extends BaseResource { * @returns Eval 信息 */ async create(request: EvalRequest): Promise { - return this.request('/v1/evals', { - method: 'POST', - body: request + return this.request("/v1/evals", { + method: "POST", + body: request, }); } @@ -57,8 +57,8 @@ export class EvalResource extends BaseResource { [key: string]: any; }): Promise { const evalInfo = await this.create({ - type: 'text', - ...request + type: "text", + ...request, } as unknown as EvalRequest); return this.waitForCompletion(evalInfo.id); } @@ -74,8 +74,8 @@ export class EvalResource extends BaseResource { [key: string]: any; }): Promise { const evalInfo = await this.create({ - type: 'batch', - ...request + type: "batch", + ...request, } as unknown as EvalRequest); return this.waitForCompletion(evalInfo.id); } @@ -95,8 +95,8 @@ export class EvalResource extends BaseResource { * @returns Eval 列表 */ async list(filter?: EvalFilter): Promise { - return this.request('/v1/evals', { - params: filter + return this.request("/v1/evals", { + params: filter, }); } @@ -107,7 +107,7 @@ export class EvalResource extends BaseResource { */ async cancel(evalId: string): Promise { return this.request(`/v1/evals/${evalId}/cancel`, { - method: 'POST' + method: "POST", }); } @@ -117,7 +117,7 @@ export class EvalResource extends BaseResource { */ async delete(evalId: string): Promise { await this.request(`/v1/evals/${evalId}`, { - method: 'DELETE' + method: "DELETE", }); } @@ -144,25 +144,25 @@ export class EvalResource extends BaseResource { async waitForCompletion( evalId: string, pollInterval: number = 1000, - maxWaitTime: number = 300000 + maxWaitTime: number = 300000, ): Promise { const startTime = Date.now(); while (Date.now() - startTime < maxWaitTime) { const evalInfo = await this.get(evalId); - if (evalInfo.status === 'completed') { + if (evalInfo.status === "completed") { return this.getResult(evalId); } - if (evalInfo.status === 'failed' || evalInfo.status === 'cancelled') { + if (evalInfo.status === "failed" || evalInfo.status === "cancelled") { throw new Error( - `Eval ${evalId} ${evalInfo.status}${evalInfo.error ? `: ${evalInfo.error}` : ''}` + `Eval ${evalId} ${evalInfo.status}${evalInfo.error ? `: ${evalInfo.error}` : ""}`, ); } // 等待下次轮询 - await new Promise(resolve => setTimeout(resolve, pollInterval)); + await new Promise((resolve) => setTimeout(resolve, pollInterval)); } throw new Error(`Eval ${evalId} did not complete within ${maxWaitTime}ms`); @@ -182,11 +182,11 @@ export class EvalResource extends BaseResource { async createTestCaseSet( name: string, testCases: TestCase[], - description?: string + description?: string, ): Promise { - return this.request('/v1/evals/test-cases', { - method: 'POST', - body: { name, testCases, description } + return this.request("/v1/evals/test-cases", { + method: "POST", + body: { name, testCases, description }, }); } @@ -205,7 +205,7 @@ export class EvalResource extends BaseResource { */ async listTestCaseSets(): Promise { const result = await this.request<{ items: TestCaseSet[] }>( - '/v1/evals/test-cases' + "/v1/evals/test-cases", ); return result.items; } @@ -222,11 +222,11 @@ export class EvalResource extends BaseResource { name?: string; description?: string; testCases?: TestCase[]; - } + }, ): Promise { return this.request(`/v1/evals/test-cases/${testCaseSetId}`, { - method: 'PATCH', - body: updates + method: "PATCH", + body: updates, }); } @@ -236,7 +236,7 @@ export class EvalResource extends BaseResource { */ async deleteTestCaseSet(testCaseSetId: string): Promise { await this.request(`/v1/evals/test-cases/${testCaseSetId}`, { - method: 'DELETE' + method: "DELETE", }); } @@ -250,9 +250,9 @@ export class EvalResource extends BaseResource { * @returns Benchmark 结果 */ async createBenchmark(config: BenchmarkConfig): Promise { - return this.request('/v1/evals/benchmark', { - method: 'POST', - body: config + return this.request("/v1/evals/benchmark", { + method: "POST", + body: config, }); } @@ -271,7 +271,7 @@ export class EvalResource extends BaseResource { */ async deleteBenchmark(benchmarkId: string): Promise { await this.request(`/v1/evals/benchmark/${benchmarkId}`, { - method: 'DELETE' + method: "DELETE", }); } @@ -285,25 +285,27 @@ export class EvalResource extends BaseResource { async waitForBenchmarkCompletion( benchmarkId: string, pollInterval: number = 2000, - maxWaitTime: number = 600000 + maxWaitTime: number = 600000, ): Promise { const startTime = Date.now(); while (Date.now() - startTime < maxWaitTime) { const result = await this.getBenchmark(benchmarkId); - if (result.status === 'completed') { + if (result.status === "completed") { return result; } - if (result.status === 'failed' || result.status === 'cancelled') { + if (result.status === "failed" || result.status === "cancelled") { throw new Error(`Benchmark ${benchmarkId} ${result.status}`); } - await new Promise(resolve => setTimeout(resolve, pollInterval)); + await new Promise((resolve) => setTimeout(resolve, pollInterval)); } - throw new Error(`Benchmark ${benchmarkId} did not complete within ${maxWaitTime}ms`); + throw new Error( + `Benchmark ${benchmarkId} did not complete within ${maxWaitTime}ms`, + ); } // ========================================================================== @@ -316,9 +318,9 @@ export class EvalResource extends BaseResource { * @returns A/B 测试结果 */ async createABTest(config: ABTestConfig): Promise { - return this.request('/v1/evals/ab-test', { - method: 'POST', - body: config + return this.request("/v1/evals/ab-test", { + method: "POST", + body: config, }); } @@ -341,25 +343,27 @@ export class EvalResource extends BaseResource { async waitForABTestCompletion( abTestId: string, pollInterval: number = 2000, - maxWaitTime: number = 600000 + maxWaitTime: number = 600000, ): Promise { const startTime = Date.now(); while (Date.now() - startTime < maxWaitTime) { const result = await this.getABTest(abTestId); - if (result.status === 'completed') { + if (result.status === "completed") { return result; } - if (result.status === 'failed' || result.status === 'cancelled') { + if (result.status === "failed" || result.status === "cancelled") { throw new Error(`A/B Test ${abTestId} ${result.status}`); } - await new Promise(resolve => setTimeout(resolve, pollInterval)); + await new Promise((resolve) => setTimeout(resolve, pollInterval)); } - throw new Error(`A/B Test ${abTestId} did not complete within ${maxWaitTime}ms`); + throw new Error( + `A/B Test ${abTestId} did not complete within ${maxWaitTime}ms`, + ); } // ========================================================================== @@ -372,9 +376,9 @@ export class EvalResource extends BaseResource { * @returns 报告结果 */ async generateReport(request: EvalReportRequest): Promise { - return this.request('/v1/evals/reports', { - method: 'POST', - body: request + return this.request("/v1/evals/reports", { + method: "POST", + body: request, }); } @@ -384,15 +388,12 @@ export class EvalResource extends BaseResource { * @param format 导出格式 * @returns 导出内容 */ - async exportResult( - evalId: string, - format: 'json' | 'csv' - ): Promise { + async exportResult(evalId: string, format: "json" | "csv"): Promise { const result = await this.request<{ content: string }>( `/v1/evals/${evalId}/export`, { - params: { format } - } + params: { format }, + }, ); return result.content; } @@ -413,21 +414,21 @@ export class EvalResource extends BaseResource { agentId: string, input: string, expectedOutput: string, - scorers: ScorerConfig[] + scorers: ScorerConfig[], ): Promise { const evalInfo = await this.create({ name: `Quick Eval - ${new Date().toISOString()}`, - type: 'single', + type: "single", agentId, testCases: [ { - id: 'quick-test-1', - name: 'Quick Test', + id: "quick-test-1", + name: "Quick Test", input, - expectedOutput - } + expectedOutput, + }, ], - scorers + scorers, }); return this.waitForCompletion(evalInfo.id); @@ -445,15 +446,15 @@ export class EvalResource extends BaseResource { agentId: string, testCases: TestCase[], scorers: ScorerConfig[], - concurrency?: number + concurrency?: number, ): Promise { const evalInfo = await this.create({ name: `Batch Eval - ${new Date().toISOString()}`, - type: 'batch', + type: "batch", agentId, testCases, scorers, - concurrency + concurrency, }); return this.waitForCompletion(evalInfo.id); @@ -471,14 +472,14 @@ export class EvalResource extends BaseResource { agentAId: string, agentBId: string, testCaseSetId: string, - scorers: ScorerConfig[] + scorers: ScorerConfig[], ): Promise { const abTest = await this.createABTest({ name: `Compare ${agentAId} vs ${agentBId}`, agentAId, agentBId, testCaseSetId, - scorers + scorers, }); return this.waitForABTestCompletion(abTest.id); diff --git a/client-sdks/client-js/src/resources/mcp.ts b/client-sdks/client-js/src/resources/mcp.ts index 5feeee2..ebca3da 100644 --- a/client-sdks/client-js/src/resources/mcp.ts +++ b/client-sdks/client-js/src/resources/mcp.ts @@ -3,7 +3,7 @@ * Model Context Protocol - AsterClient 作为 MCP Client 和 Server */ -import { BaseResource, ClientOptions } from './base'; +import { BaseResource, ClientOptions } from "./base"; import { MCPServerConfig, MCPServerInfo, @@ -14,8 +14,8 @@ import { MCPResourceContent, MCPPrompt, MCPPromptResult, - MCPStats -} from '../types/mcp'; + MCPStats, +} from "../types/mcp"; /** * MCP 资源类 @@ -35,9 +35,9 @@ export class MCPResource extends BaseResource { * @returns Server 信息 */ async addServer(config: MCPServerConfig): Promise { - return this.request('/v1/mcp/servers', { - method: 'POST', - body: config + return this.request("/v1/mcp/servers", { + method: "POST", + body: config, }); } @@ -56,7 +56,7 @@ export class MCPResource extends BaseResource { */ async listServers(): Promise { const result = await this.request<{ servers: MCPServerInfo[] }>( - '/v1/mcp/servers' + "/v1/mcp/servers", ); return result.servers; } @@ -78,11 +78,11 @@ export class MCPResource extends BaseResource { */ async updateServer( serverId: string, - updates: Partial + updates: Partial, ): Promise { return this.request(`/v1/mcp/servers/${serverId}`, { - method: 'PATCH', - body: updates + method: "PATCH", + body: updates, }); } @@ -92,7 +92,7 @@ export class MCPResource extends BaseResource { */ async removeServer(serverId: string): Promise { await this.request(`/v1/mcp/servers/${serverId}`, { - method: 'DELETE' + method: "DELETE", }); } @@ -110,10 +110,9 @@ export class MCPResource extends BaseResource { * @returns 连接结果 */ async connectServer(serverId: string): Promise { - return this.request( - `/v1/mcp/servers/${serverId}/connect`, - { method: 'POST' } - ); + return this.request(`/v1/mcp/servers/${serverId}/connect`, { + method: "POST", + }); } /** @@ -131,7 +130,7 @@ export class MCPResource extends BaseResource { */ async disconnectServer(serverId: string): Promise { await this.request(`/v1/mcp/servers/${serverId}/disconnect`, { - method: 'POST' + method: "POST", }); } @@ -154,7 +153,7 @@ export class MCPResource extends BaseResource { */ async getServerTools(serverId: string): Promise { const result = await this.request<{ tools: MCPTool[] }>( - `/v1/mcp/servers/${serverId}/tools` + `/v1/mcp/servers/${serverId}/tools`, ); return result.tools; } @@ -164,9 +163,7 @@ export class MCPResource extends BaseResource { * @returns 工具列表 */ async listAllTools(): Promise { - const result = await this.request<{ tools: MCPTool[] }>( - '/v1/mcp/tools' - ); + const result = await this.request<{ tools: MCPTool[] }>("/v1/mcp/tools"); return result.tools; } @@ -176,10 +173,10 @@ export class MCPResource extends BaseResource { * @returns 调用响应 */ async callTool(request: MCPToolCallRequest): Promise { - return this.request('/v1/mcp/tools/call', { - method: 'POST', + return this.request("/v1/mcp/tools/call", { + method: "POST", body: request, - timeout: request.timeout + timeout: request.timeout, }); } @@ -193,7 +190,7 @@ export class MCPResource extends BaseResource { async call( serverId: string, toolName: string, - params: Record + params: Record, ): Promise { return this.callTool({ serverId, toolName, params }); } @@ -209,7 +206,7 @@ export class MCPResource extends BaseResource { */ async listResources(serverId: string): Promise { const result = await this.request<{ resources: MCPResourceData[] }>( - `/v1/mcp/servers/${serverId}/resources` + `/v1/mcp/servers/${serverId}/resources`, ); return result.resources; } @@ -222,14 +219,14 @@ export class MCPResource extends BaseResource { */ async readResource( serverId: string, - uri: string + uri: string, ): Promise { return this.request( `/v1/mcp/servers/${serverId}/resources/read`, { - method: 'POST', - body: { uri } - } + method: "POST", + body: { uri }, + }, ); } @@ -244,7 +241,7 @@ export class MCPResource extends BaseResource { */ async listPrompts(serverId: string): Promise { const result = await this.request<{ prompts: MCPPrompt[] }>( - `/v1/mcp/servers/${serverId}/prompts` + `/v1/mcp/servers/${serverId}/prompts`, ); return result.prompts; } @@ -259,14 +256,14 @@ export class MCPResource extends BaseResource { async getPrompt( serverId: string, name: string, - args?: Record + args?: Record, ): Promise { return this.request( `/v1/mcp/servers/${serverId}/prompts/${name}`, { - method: 'POST', - body: { arguments: args } - } + method: "POST", + body: { arguments: args }, + }, ); } @@ -279,7 +276,7 @@ export class MCPResource extends BaseResource { * @returns 统计数据 */ async getStats(): Promise { - return this.request('/v1/mcp/stats'); + return this.request("/v1/mcp/stats"); } /** diff --git a/client-sdks/client-js/src/resources/memory.ts b/client-sdks/client-js/src/resources/memory.ts index 4198e4d..b1f6f95 100644 --- a/client-sdks/client-js/src/resources/memory.ts +++ b/client-sdks/client-js/src/resources/memory.ts @@ -3,7 +3,7 @@ * 实现三层记忆系统:Text Memory、Working Memory、Semantic Memory */ -import { BaseResource, ClientOptions } from './base'; +import { BaseResource, ClientOptions } from "./base"; import { WorkingMemoryScope, WorkingMemorySetOptions, @@ -15,8 +15,8 @@ import { ProvenanceResponse, ConsolidateOptions, ConsolidationResult, - JobStatus -} from '../types/memory'; + JobStatus, +} from "../types/memory"; /** * Memory 资源类 @@ -42,16 +42,12 @@ export class MemoryResource extends BaseResource { * @param scope 作用域(默认: thread) * @returns 值 */ - get: async ( - key: string, - scope?: WorkingMemoryScope - ): Promise => { + get: async (key: string, scope?: WorkingMemoryScope): Promise => { const params: any = { key }; if (scope) params.scope = scope; - const result = await this.request<{ value: any }>( - '/v1/memory/working', - { params } - ); + const result = await this.request<{ value: any }>("/v1/memory/working", { + params, + }); return result.value; }, @@ -64,17 +60,17 @@ export class MemoryResource extends BaseResource { set: async ( key: string, value: any, - options?: WorkingMemorySetOptions + options?: WorkingMemorySetOptions, ): Promise => { - await this.request('/v1/memory/working', { - method: 'POST', + await this.request("/v1/memory/working", { + method: "POST", body: { key, value, - scope: options?.scope ?? 'thread', + scope: options?.scope ?? "thread", ttl: options?.ttl, - schema: options?.schema - } + schema: options?.schema, + }, }); }, @@ -83,14 +79,11 @@ export class MemoryResource extends BaseResource { * @param key 键名 * @param scope 作用域(默认: thread) */ - delete: async ( - key: string, - scope?: WorkingMemoryScope - ): Promise => { + delete: async (key: string, scope?: WorkingMemoryScope): Promise => { const params = scope ? { scope } : undefined; await this.request(`/v1/memory/working/${key}`, { - method: 'DELETE', - params + method: "DELETE", + params, }); }, @@ -99,19 +92,17 @@ export class MemoryResource extends BaseResource { * @param scope 作用域(可选,不指定则返回所有) * @returns 键值对对象 */ - list: async ( - scope?: WorkingMemoryScope - ): Promise> => { + list: async (scope?: WorkingMemoryScope): Promise> => { const params = scope ? { scope } : undefined; const result = await this.request( - '/v1/memory/working', - { params } + "/v1/memory/working", + { params }, ); - + // 转换为键值对对象 const items: Record = {}; if (Array.isArray(result)) { - result.forEach(item => { + result.forEach((item) => { items[item.key] = item.value; }); } @@ -122,15 +113,13 @@ export class MemoryResource extends BaseResource { * 清空 Working Memory * @param scope 作用域(可选,不指定则清空所有) */ - clear: async ( - scope?: WorkingMemoryScope - ): Promise => { + clear: async (scope?: WorkingMemoryScope): Promise => { const body = scope ? { scope } : {}; - await this.request('/v1/memory/working/clear', { - method: 'POST', - body + await this.request("/v1/memory/working/clear", { + method: "POST", + body, }); - } + }, }; // ========================================================================== @@ -150,19 +139,19 @@ export class MemoryResource extends BaseResource { */ search: async ( query: string, - options?: SearchOptions + options?: SearchOptions, ): Promise => { const result = await this.request( - '/v1/memory/semantic/search', + "/v1/memory/semantic/search", { - method: 'POST', + method: "POST", body: { query, limit: options?.limit ?? 10, threshold: options?.threshold, - filter: options?.filter - } - } + filter: options?.filter, + }, + }, ); return result.chunks; }, @@ -175,15 +164,12 @@ export class MemoryResource extends BaseResource { */ store: async ( content: string, - metadata?: Record + metadata?: Record, ): Promise => { - const result = await this.request<{ id: string }>( - '/v1/memory/semantic', - { - method: 'POST', - body: { content, ...metadata } - } - ); + const result = await this.request<{ id: string }>("/v1/memory/semantic", { + method: "POST", + body: { content, ...metadata }, + }); return result.id; }, @@ -199,7 +185,7 @@ export class MemoryResource extends BaseResource { }): Promise<{ id: string; content: string; [key: string]: any }> => { const chunkId = await this.semantic.store(data.content, { ...data.metadata, - tags: data.tags + tags: data.tags, }); return { id: chunkId, content: data.content }; }, @@ -214,7 +200,7 @@ export class MemoryResource extends BaseResource { filter?: Record; }): Promise => { // 使用空查询返回所有记忆 - return this.semantic.search('', options); + return this.semantic.search("", options); }, /** @@ -223,7 +209,7 @@ export class MemoryResource extends BaseResource { */ delete: async (chunkId: string): Promise => { await this.request(`/v1/memory/semantic/${chunkId}`, { - method: 'DELETE' + method: "DELETE", }); }, @@ -232,11 +218,11 @@ export class MemoryResource extends BaseResource { * @param chunkIds 记忆块 ID 列表 */ deleteBatch: async (chunkIds: string[]): Promise => { - await this.request('/v1/memory/semantic/batch', { - method: 'DELETE', - body: { chunkIds } + await this.request("/v1/memory/semantic/batch", { + method: "DELETE", + body: { chunkIds }, }); - } + }, }; // ========================================================================== @@ -246,26 +232,26 @@ export class MemoryResource extends BaseResource { /** * 获取记忆溯源信息 * 追踪记忆的来源、置信度和谱系关系 - * + * * @param memoryId 记忆 ID * @returns 溯源信息 */ async getProvenance(memoryId: string): Promise { return this.request( - `/v1/memory/provenance/${memoryId}` + `/v1/memory/provenance/${memoryId}`, ); } /** * 获取记忆谱系链 * 从根记忆到当前记忆的完整路径 - * + * * @param memoryId 记忆 ID * @returns 谱系链 */ async getLineage(memoryId: string): Promise { const result = await this.request<{ lineage: Provenance[] }>( - `/v1/memory/lineage/${memoryId}` + `/v1/memory/lineage/${memoryId}`, ); return result.lineage; } @@ -277,42 +263,37 @@ export class MemoryResource extends BaseResource { /** * 触发记忆合并 * LLM 驱动的智能合并,处理冗余、冲突、生成总结 - * + * * @param options 合并选项 * @returns 合并任务结果 */ async consolidate( - options?: ConsolidateOptions + options?: ConsolidateOptions, ): Promise { - return this.request( - '/v1/memory/consolidate', - { - method: 'POST', - body: options - } - ); + return this.request("/v1/memory/consolidate", { + method: "POST", + body: options, + }); } /** * 获取合并任务状态 - * + * * @param jobId 任务 ID * @returns 任务状态 */ async getConsolidationStatus(jobId: string): Promise { - return this.request( - `/v1/memory/consolidation/${jobId}` - ); + return this.request(`/v1/memory/consolidation/${jobId}`); } /** * 取消合并任务 - * + * * @param jobId 任务 ID */ async cancelConsolidation(jobId: string): Promise { await this.request(`/v1/memory/consolidation/${jobId}`, { - method: 'DELETE' + method: "DELETE", }); } @@ -335,7 +316,7 @@ export class MemoryResource extends BaseResource { totalSize: number; }; }> { - return this.request('/v1/memory/stats'); + return this.request("/v1/memory/stats"); } /** @@ -344,12 +325,12 @@ export class MemoryResource extends BaseResource { */ async clearAll(confirm: boolean = false): Promise { if (!confirm) { - throw new Error('Must confirm to clear all memory. Pass confirm=true.'); + throw new Error("Must confirm to clear all memory. Pass confirm=true."); } - - await this.request('/v1/memory/clear', { - method: 'POST', - body: { confirm: true } + + await this.request("/v1/memory/clear", { + method: "POST", + body: { confirm: true }, }); } } diff --git a/client-sdks/client-js/src/resources/middleware.ts b/client-sdks/client-js/src/resources/middleware.ts index d53485c..2f222a8 100644 --- a/client-sdks/client-js/src/resources/middleware.ts +++ b/client-sdks/client-js/src/resources/middleware.ts @@ -3,12 +3,12 @@ * 管理洋葱模型中间件系统 */ -import { BaseResource, ClientOptions } from './base'; +import { BaseResource, ClientOptions } from "./base"; import { MiddlewareInfo, UpdateMiddlewareRequest, - MiddlewareStats -} from '../types/middleware'; + MiddlewareStats, +} from "../types/middleware"; /** * Middleware 资源类 @@ -33,9 +33,9 @@ export class MiddlewareResource extends BaseResource { priority: number; config?: Record; }): Promise { - return this.request('/v1/middlewares', { - method: 'POST', - body: middleware + return this.request("/v1/middlewares", { + method: "POST", + body: middleware, }); } @@ -45,7 +45,7 @@ export class MiddlewareResource extends BaseResource { */ async list(): Promise { const result = await this.request<{ middlewares: MiddlewareInfo[] }>( - '/v1/middlewares' + "/v1/middlewares", ); return result.middlewares; } @@ -67,11 +67,11 @@ export class MiddlewareResource extends BaseResource { */ async update( name: string, - updates: UpdateMiddlewareRequest + updates: UpdateMiddlewareRequest, ): Promise { return this.request(`/v1/middlewares/${name}`, { - method: 'PATCH', - body: updates + method: "PATCH", + body: updates, }); } @@ -97,7 +97,7 @@ export class MiddlewareResource extends BaseResource { */ async delete(nameOrId: string): Promise { await this.request(`/v1/middlewares/${nameOrId}`, { - method: 'DELETE' + method: "DELETE", }); } @@ -108,7 +108,7 @@ export class MiddlewareResource extends BaseResource { */ async updateConfig( name: string, - config: Record + config: Record, ): Promise { return this.update(name, { config }); } @@ -120,7 +120,7 @@ export class MiddlewareResource extends BaseResource { */ async updatePriority( name: string, - priority: number + priority: number, ): Promise { return this.update(name, { priority }); } @@ -144,7 +144,7 @@ export class MiddlewareResource extends BaseResource { */ async getAllStats(): Promise { const result = await this.request<{ stats: MiddlewareStats[] }>( - '/v1/middlewares/stats' + "/v1/middlewares/stats", ); return result.stats; } @@ -158,9 +158,9 @@ export class MiddlewareResource extends BaseResource { * @param names Middleware 名称列表 */ async enableBatch(names: string[]): Promise { - await this.request('/v1/middlewares/batch/enable', { - method: 'POST', - body: { names } + await this.request("/v1/middlewares/batch/enable", { + method: "POST", + body: { names }, }); } @@ -169,9 +169,9 @@ export class MiddlewareResource extends BaseResource { * @param names Middleware 名称列表 */ async disableBatch(names: string[]): Promise { - await this.request('/v1/middlewares/batch/disable', { - method: 'POST', - body: { names } + await this.request("/v1/middlewares/batch/disable", { + method: "POST", + body: { names }, }); } @@ -185,7 +185,7 @@ export class MiddlewareResource extends BaseResource { */ async getExecutionOrder(): Promise { const result = await this.request<{ order: string[] }>( - '/v1/middlewares/execution-order' + "/v1/middlewares/execution-order", ); return result.order; } @@ -195,9 +195,9 @@ export class MiddlewareResource extends BaseResource { * @param order Middleware 名称列表(按执行顺序) */ async setExecutionOrder(order: string[]): Promise { - await this.request('/v1/middlewares/execution-order', { - method: 'PUT', - body: { order } + await this.request("/v1/middlewares/execution-order", { + method: "PUT", + body: { order }, }); } @@ -205,8 +205,8 @@ export class MiddlewareResource extends BaseResource { * 重置 Middleware 顺序为默认值 */ async resetExecutionOrder(): Promise { - await this.request('/v1/middlewares/execution-order/reset', { - method: 'POST' + await this.request("/v1/middlewares/execution-order/reset", { + method: "POST", }); } } diff --git a/client-sdks/client-js/src/resources/session.ts b/client-sdks/client-js/src/resources/session.ts index 9ec5ae0..3b36ed1 100644 --- a/client-sdks/client-js/src/resources/session.ts +++ b/client-sdks/client-js/src/resources/session.ts @@ -3,7 +3,7 @@ * 管理会话生命周期、消息历史、断点恢复 */ -import { BaseResource, ClientOptions } from './base'; +import { BaseResource, ClientOptions } from "./base"; import { SessionConfig, SessionInfo, @@ -17,8 +17,8 @@ import { SessionStats, UpdateSessionRequest, ExportOptions, - ExportResult -} from '../types/session'; + ExportResult, +} from "../types/session"; /** * Session 资源类 @@ -38,9 +38,9 @@ export class SessionResource extends BaseResource { * @returns Session 信息 */ async create(config: SessionConfig): Promise { - return this.request('/v1/sessions', { - method: 'POST', - body: config + return this.request("/v1/sessions", { + method: "POST", + body: config, }); } @@ -59,8 +59,8 @@ export class SessionResource extends BaseResource { * @returns Session 列表 */ async list(filter?: SessionFilter): Promise> { - return this.request>('/v1/sessions', { - params: filter + return this.request>("/v1/sessions", { + params: filter, }); } @@ -71,11 +71,11 @@ export class SessionResource extends BaseResource { */ async update( sessionId: string, - updates: UpdateSessionRequest + updates: UpdateSessionRequest, ): Promise { return this.request(`/v1/sessions/${sessionId}`, { - method: 'PATCH', - body: updates + method: "PATCH", + body: updates, }); } @@ -85,7 +85,7 @@ export class SessionResource extends BaseResource { */ async delete(sessionId: string): Promise { await this.request(`/v1/sessions/${sessionId}`, { - method: 'DELETE' + method: "DELETE", }); } @@ -101,11 +101,11 @@ export class SessionResource extends BaseResource { */ async getMessages( sessionId: string, - pagination?: Pagination + pagination?: Pagination, ): Promise> { return this.request>( `/v1/sessions/${sessionId}/messages`, - { params: pagination } + { params: pagination }, ); } @@ -117,15 +117,12 @@ export class SessionResource extends BaseResource { */ async addMessage( sessionId: string, - message: Omit + message: Omit, ): Promise { - return this.request( - `/v1/sessions/${sessionId}/messages`, - { - method: 'POST', - body: message - } - ); + return this.request(`/v1/sessions/${sessionId}/messages`, { + method: "POST", + body: message, + }); } /** @@ -134,12 +131,9 @@ export class SessionResource extends BaseResource { * @param messageId Message ID * @returns 消息详情 */ - async getMessage( - sessionId: string, - messageId: string - ): Promise { + async getMessage(sessionId: string, messageId: string): Promise { return this.request( - `/v1/sessions/${sessionId}/messages/${messageId}` + `/v1/sessions/${sessionId}/messages/${messageId}`, ); } @@ -148,14 +142,10 @@ export class SessionResource extends BaseResource { * @param sessionId Session ID * @param messageId Message ID */ - async deleteMessage( - sessionId: string, - messageId: string - ): Promise { - await this.request( - `/v1/sessions/${sessionId}/messages/${messageId}`, - { method: 'DELETE' } - ); + async deleteMessage(sessionId: string, messageId: string): Promise { + await this.request(`/v1/sessions/${sessionId}/messages/${messageId}`, { + method: "DELETE", + }); } // ========================================================================== @@ -169,7 +159,7 @@ export class SessionResource extends BaseResource { */ async getCheckpoints(sessionId: string): Promise { const result = await this.request<{ checkpoints: Checkpoint[] }>( - `/v1/sessions/${sessionId}/checkpoints` + `/v1/sessions/${sessionId}/checkpoints`, ); return result.checkpoints; } @@ -182,10 +172,10 @@ export class SessionResource extends BaseResource { */ async getCheckpoint( sessionId: string, - checkpointId: string + checkpointId: string, ): Promise { return this.request( - `/v1/sessions/${sessionId}/checkpoints/${checkpointId}` + `/v1/sessions/${sessionId}/checkpoints/${checkpointId}`, ); } @@ -196,15 +186,12 @@ export class SessionResource extends BaseResource { */ async resume( sessionId: string, - options?: ResumeOptions + options?: ResumeOptions, ): Promise { - return this.request( - `/v1/sessions/${sessionId}/resume`, - { - method: 'POST', - body: options - } - ); + return this.request(`/v1/sessions/${sessionId}/resume`, { + method: "POST", + body: options, + }); } /** @@ -215,15 +202,12 @@ export class SessionResource extends BaseResource { */ async createCheckpoint( sessionId: string, - label?: string + label?: string, ): Promise { - return this.request( - `/v1/sessions/${sessionId}/checkpoints`, - { - method: 'POST', - body: { label } - } - ); + return this.request(`/v1/sessions/${sessionId}/checkpoints`, { + method: "POST", + body: { label }, + }); } // ========================================================================== @@ -236,9 +220,7 @@ export class SessionResource extends BaseResource { * @returns 统计数据 */ async getStats(sessionId: string): Promise { - return this.request( - `/v1/sessions/${sessionId}/stats` - ); + return this.request(`/v1/sessions/${sessionId}/stats`); } // ========================================================================== @@ -250,7 +232,7 @@ export class SessionResource extends BaseResource { * @param sessionId Session ID */ async pause(sessionId: string): Promise { - return this.update(sessionId, { status: 'paused' }); + return this.update(sessionId, { status: "paused" }); } /** @@ -258,7 +240,7 @@ export class SessionResource extends BaseResource { * @param sessionId Session ID */ async activate(sessionId: string): Promise { - return this.update(sessionId, { status: 'active' }); + return this.update(sessionId, { status: "active" }); } /** @@ -266,7 +248,7 @@ export class SessionResource extends BaseResource { * @param sessionId Session ID */ async complete(sessionId: string): Promise { - return this.update(sessionId, { status: 'completed' }); + return this.update(sessionId, { status: "completed" }); } /** @@ -274,7 +256,7 @@ export class SessionResource extends BaseResource { * @param sessionId Session ID */ async archive(sessionId: string): Promise { - return this.update(sessionId, { status: 'archived' }); + return this.update(sessionId, { status: "archived" }); } // ========================================================================== @@ -289,15 +271,12 @@ export class SessionResource extends BaseResource { */ async export( sessionId: string, - options: ExportOptions + options: ExportOptions, ): Promise { - return this.request( - `/v1/sessions/${sessionId}/export`, - { - method: 'POST', - body: options - } - ); + return this.request(`/v1/sessions/${sessionId}/export`, { + method: "POST", + body: options, + }); } // ========================================================================== @@ -309,9 +288,9 @@ export class SessionResource extends BaseResource { * @param sessionIds Session ID 列表 */ async deleteBatch(sessionIds: string[]): Promise { - await this.request('/v1/sessions/batch', { - method: 'DELETE', - body: { sessionIds } + await this.request("/v1/sessions/batch", { + method: "DELETE", + body: { sessionIds }, }); } @@ -320,9 +299,9 @@ export class SessionResource extends BaseResource { * @param sessionIds Session ID 列表 */ async archiveBatch(sessionIds: string[]): Promise { - await this.request('/v1/sessions/batch/archive', { - method: 'POST', - body: { sessionIds } + await this.request("/v1/sessions/batch/archive", { + method: "POST", + body: { sessionIds }, }); } } diff --git a/client-sdks/client-js/src/resources/system.ts b/client-sdks/client-js/src/resources/system.ts index 4904fd6..2eaea5a 100644 --- a/client-sdks/client-js/src/resources/system.ts +++ b/client-sdks/client-js/src/resources/system.ts @@ -3,7 +3,7 @@ * 系统配置和管理功能 */ -import { BaseResource, ClientOptions } from './base'; +import { BaseResource, ClientOptions } from "./base"; export interface SystemConfig { key: string; @@ -41,7 +41,7 @@ export class SystemResource extends BaseResource { // Config Management async listConfig(): Promise { - return this.request('/v1/system/config'); + return this.request("/v1/system/config"); } async getConfig(key: string): Promise { @@ -50,39 +50,39 @@ export class SystemResource extends BaseResource { async updateConfig(key: string, value: any): Promise { return this.request(`/v1/system/config/${key}`, { - method: 'PUT', - body: { value } + method: "PUT", + body: { value }, }); } async deleteConfig(key: string): Promise { await this.request(`/v1/system/config/${key}`, { - method: 'DELETE' + method: "DELETE", }); } // System Operations async getInfo(): Promise { - return this.request('/v1/system/info'); + return this.request("/v1/system/info"); } async getHealth(): Promise { - return this.request('/v1/system/health'); + return this.request("/v1/system/health"); } async getStats(): Promise { - return this.request('/v1/system/stats'); + return this.request("/v1/system/stats"); } async reload(): Promise<{ reloaded: boolean }> { - return this.request('/v1/system/reload', { method: 'POST' }); + return this.request("/v1/system/reload", { method: "POST" }); } async runGC(): Promise<{ gc_completed: boolean; freed_mb: number }> { - return this.request('/v1/system/gc', { method: 'POST' }); + return this.request("/v1/system/gc", { method: "POST" }); } async backup(): Promise<{ backup_started: boolean; backup_id: string }> { - return this.request('/v1/system/backup', { method: 'POST' }); + return this.request("/v1/system/backup", { method: "POST" }); } } diff --git a/client-sdks/client-js/src/resources/telemetry.ts b/client-sdks/client-js/src/resources/telemetry.ts index 2a39074..cfea8ff 100644 --- a/client-sdks/client-js/src/resources/telemetry.ts +++ b/client-sdks/client-js/src/resources/telemetry.ts @@ -3,7 +3,7 @@ * 可观测性:Metrics、Traces、Logs */ -import { BaseResource, ClientOptions } from './base'; +import { BaseResource, ClientOptions } from "./base"; import { MetricInfo, MetricDataPoint, @@ -17,8 +17,8 @@ import { PerformanceMetrics, UsageStatistics, ExportTelemetryRequest, - ExportTelemetryResult -} from '../types/telemetry'; + ExportTelemetryResult, +} from "../types/telemetry"; /** * Telemetry 资源类 @@ -37,7 +37,7 @@ export class TelemetryResource extends BaseResource { * @returns Telemetry 配置 */ async getConfig(): Promise { - return this.request('/v1/telemetry/config'); + return this.request("/v1/telemetry/config"); } /** @@ -46,11 +46,11 @@ export class TelemetryResource extends BaseResource { * @returns 更新后的配置 */ async updateConfig( - config: Partial + config: Partial, ): Promise { - return this.request('/v1/telemetry/config', { - method: 'PATCH', - body: config + return this.request("/v1/telemetry/config", { + method: "PATCH", + body: config, }); } @@ -64,7 +64,7 @@ export class TelemetryResource extends BaseResource { */ async listMetrics(): Promise { const result = await this.request<{ metrics: MetricInfo[] }>( - '/v1/telemetry/metrics' + "/v1/telemetry/metrics", ); return result.metrics; } @@ -83,15 +83,13 @@ export class TelemetryResource extends BaseResource { * @param options 查询选项 * @returns 数据点列表 */ - async queryMetrics( - options: MetricQueryOptions - ): Promise { + async queryMetrics(options: MetricQueryOptions): Promise { const result = await this.request<{ dataPoints: MetricDataPoint[] }>( - '/v1/telemetry/metrics/query', + "/v1/telemetry/metrics/query", { - method: 'POST', - body: options - } + method: "POST", + body: options, + }, ); return result.dataPoints; } @@ -105,7 +103,7 @@ export class TelemetryResource extends BaseResource { async recordMetric( name: string, value: number, - labels?: Record + labels?: Record, ): Promise; async recordMetric(data: { name: string; @@ -114,19 +112,26 @@ export class TelemetryResource extends BaseResource { labels?: Record; }): Promise; async recordMetric( - nameOrData: string | { name: string; type?: string; value: number; labels?: Record }, + nameOrData: + | string + | { + name: string; + type?: string; + value: number; + labels?: Record; + }, value?: number, - labels?: Record + labels?: Record, ): Promise { let body: any; - if (typeof nameOrData === 'string') { + if (typeof nameOrData === "string") { body = { name: nameOrData, value: value!, labels }; } else { body = nameOrData; } - await this.request('/v1/telemetry/metrics', { - method: 'POST', - body + await this.request("/v1/telemetry/metrics", { + method: "POST", + body, }); } @@ -146,9 +151,9 @@ export class TelemetryResource extends BaseResource { parent_id?: string; [key: string]: any; }): Promise { - return this.request('/v1/telemetry/traces', { - method: 'POST', - body: trace + return this.request("/v1/telemetry/traces", { + method: "POST", + body: trace, }); } @@ -159,11 +164,11 @@ export class TelemetryResource extends BaseResource { */ async queryTraces(options?: TraceQueryOptions): Promise { const result = await this.request<{ traces: TraceInfo[] }>( - '/v1/telemetry/traces/query', + "/v1/telemetry/traces/query", { - method: 'POST', - body: options || {} - } + method: "POST", + body: options || {}, + }, ); return result.traces; } @@ -193,7 +198,7 @@ export class TelemetryResource extends BaseResource { */ async getTraceSpans(traceId: string): Promise { const result = await this.request<{ spans: TraceInfo[] }>( - `/v1/telemetry/traces/${traceId}/spans` + `/v1/telemetry/traces/${traceId}/spans`, ); return result.spans; } @@ -209,11 +214,11 @@ export class TelemetryResource extends BaseResource { */ async queryLogs(options: LogQueryOptions): Promise { const result = await this.request<{ logs: LogEntry[] }>( - '/v1/telemetry/logs/query', + "/v1/telemetry/logs/query", { - method: 'POST', - body: options - } + method: "POST", + body: options, + }, ); return result.logs; } @@ -222,10 +227,10 @@ export class TelemetryResource extends BaseResource { * 写入日志 * @param entry 日志条目 */ - async writeLog(entry: Omit): Promise { - await this.request('/v1/telemetry/logs', { - method: 'POST', - body: entry + async writeLog(entry: Omit): Promise { + await this.request("/v1/telemetry/logs", { + method: "POST", + body: entry, }); } @@ -236,7 +241,7 @@ export class TelemetryResource extends BaseResource { */ async getTraceLogs(traceId: string): Promise { const result = await this.request<{ logs: LogEntry[] }>( - `/v1/telemetry/traces/${traceId}/logs` + `/v1/telemetry/traces/${traceId}/logs`, ); return result.logs; } @@ -250,7 +255,7 @@ export class TelemetryResource extends BaseResource { * @returns 健康状态 */ async healthCheck(): Promise { - return this.request('/v1/telemetry/health'); + return this.request("/v1/telemetry/health"); } /** @@ -263,7 +268,7 @@ export class TelemetryResource extends BaseResource { version: string; [key: string]: any; }> { - return this.request('/v1/telemetry/status'); + return this.request("/v1/telemetry/status"); } // ========================================================================== @@ -279,10 +284,9 @@ export class TelemetryResource extends BaseResource { start: string; end: string; }): Promise { - return this.request( - '/v1/telemetry/performance', - { params: timeRange } - ); + return this.request("/v1/telemetry/performance", { + params: timeRange, + }); } /** @@ -294,10 +298,9 @@ export class TelemetryResource extends BaseResource { start: string; end: string; }): Promise { - return this.request( - '/v1/telemetry/usage', - { params: timeRange } - ); + return this.request("/v1/telemetry/usage", { + params: timeRange, + }); } // ========================================================================== @@ -310,11 +313,11 @@ export class TelemetryResource extends BaseResource { * @returns 导出结果 */ async export( - request: ExportTelemetryRequest + request: ExportTelemetryRequest, ): Promise { - return this.request('/v1/telemetry/export', { - method: 'POST', - body: request + return this.request("/v1/telemetry/export", { + method: "POST", + body: request, }); } @@ -325,13 +328,13 @@ export class TelemetryResource extends BaseResource { * @returns 导出结果 */ async exportMetrics( - format: 'json' | 'csv' | 'prometheus', - timeRange?: { start: string; end: string } + format: "json" | "csv" | "prometheus", + timeRange?: { start: string; end: string }, ): Promise { return this.export({ - type: 'metrics', + type: "metrics", format, - timeRange + timeRange, }); } @@ -342,13 +345,13 @@ export class TelemetryResource extends BaseResource { * @returns 导出结果 */ async exportTraces( - format: 'json' | 'opentelemetry', - timeRange?: { start: string; end: string } + format: "json" | "opentelemetry", + timeRange?: { start: string; end: string }, ): Promise { return this.export({ - type: 'traces', + type: "traces", format, - timeRange + timeRange, }); } @@ -359,13 +362,13 @@ export class TelemetryResource extends BaseResource { * @returns 导出结果 */ async exportLogs( - format: 'json' | 'csv', - timeRange?: { start: string; end: string } + format: "json" | "csv", + timeRange?: { start: string; end: string }, ): Promise { return this.export({ - type: 'logs', + type: "logs", format, - timeRange + timeRange, }); } } diff --git a/client-sdks/client-js/src/resources/tool.ts b/client-sdks/client-js/src/resources/tool.ts index f1df80c..9288938 100644 --- a/client-sdks/client-js/src/resources/tool.ts +++ b/client-sdks/client-js/src/resources/tool.ts @@ -3,7 +3,7 @@ * 管理内置工具和长时运行工具 */ -import { BaseResource, ClientOptions } from './base'; +import { BaseResource, ClientOptions } from "./base"; import { ToolInfo, ToolExecutionRequest, @@ -11,8 +11,8 @@ import { AsyncToolExecutionResponse, TaskProgress, ToolStats, - ToolUsageReport -} from '../types/tool'; + ToolUsageReport, +} from "../types/tool"; /** * Tool 资源类 @@ -37,9 +37,9 @@ export class ToolResource extends BaseResource { schema: Record; description?: string; }): Promise { - return this.request('/v1/tools', { - method: 'POST', - body: tool + return this.request("/v1/tools", { + method: "POST", + body: tool, }); } @@ -49,14 +49,13 @@ export class ToolResource extends BaseResource { * @returns 工具列表 */ async list(filter?: { - type?: 'builtin' | 'custom' | 'mcp'; + type?: "builtin" | "custom" | "mcp"; category?: string; enabled?: boolean; }): Promise { - const result = await this.request<{ tools: ToolInfo[] }>( - '/v1/tools', - { params: filter } - ); + const result = await this.request<{ tools: ToolInfo[] }>("/v1/tools", { + params: filter, + }); return result.tools; } @@ -75,7 +74,7 @@ export class ToolResource extends BaseResource { */ async enable(toolName: string): Promise { return this.request(`/v1/tools/${toolName}/enable`, { - method: 'POST' + method: "POST", }); } @@ -85,7 +84,7 @@ export class ToolResource extends BaseResource { */ async disable(toolName: string): Promise { return this.request(`/v1/tools/${toolName}/disable`, { - method: 'POST' + method: "POST", }); } @@ -95,7 +94,7 @@ export class ToolResource extends BaseResource { */ async delete(toolId: string): Promise { await this.request(`/v1/tools/${toolId}`, { - method: 'DELETE' + method: "DELETE", }); } @@ -111,8 +110,8 @@ export class ToolResource extends BaseResource { */ async execute(toolId: string, input: Record): Promise { return this.request(`/v1/tools/${toolId}/execute`, { - method: 'POST', - body: { input } + method: "POST", + body: { input }, }); } @@ -124,15 +123,15 @@ export class ToolResource extends BaseResource { */ async executeAsync( toolName: string, - params: Record + params: Record, ): Promise { - return this.request('/v1/tools/execute', { - method: 'POST', + return this.request("/v1/tools/execute", { + method: "POST", body: { toolName, params, - async: true - } + async: true, + }, }); } @@ -142,12 +141,12 @@ export class ToolResource extends BaseResource { * @returns 执行结果或任务信息 */ async executeWithOptions( - request: ToolExecutionRequest + request: ToolExecutionRequest, ): Promise { - return this.request('/v1/tools/execute', { - method: 'POST', + return this.request("/v1/tools/execute", { + method: "POST", body: request, - timeout: request.timeout + timeout: request.timeout, }); } @@ -170,12 +169,12 @@ export class ToolResource extends BaseResource { * @returns 任务列表 */ async listTasks(filter?: { - status?: 'pending' | 'running' | 'completed' | 'failed' | 'cancelled'; + status?: "pending" | "running" | "completed" | "failed" | "cancelled"; toolName?: string; }): Promise { const result = await this.request<{ tasks: TaskProgress[] }>( - '/v1/tools/tasks', - { params: filter } + "/v1/tools/tasks", + { params: filter }, ); return result.tasks; } @@ -186,7 +185,7 @@ export class ToolResource extends BaseResource { */ async cancelTask(taskId: string): Promise { await this.request(`/v1/tools/tasks/${taskId}/cancel`, { - method: 'POST' + method: "POST", }); } @@ -199,9 +198,9 @@ export class ToolResource extends BaseResource { async waitForTask( taskId: string, options?: { - pollInterval?: number; // 轮询间隔(毫秒),默认 1000 - timeout?: number; // 超时时间(毫秒),默认 300000 (5分钟) - } + pollInterval?: number; // 轮询间隔(毫秒),默认 1000 + timeout?: number; // 超时时间(毫秒),默认 300000 (5分钟) + }, ): Promise { const pollInterval = options?.pollInterval ?? 1000; const timeout = options?.timeout ?? 300000; @@ -212,9 +211,9 @@ export class ToolResource extends BaseResource { // 检查是否完成 if ( - task.status === 'completed' || - task.status === 'failed' || - task.status === 'cancelled' + task.status === "completed" || + task.status === "failed" || + task.status === "cancelled" ) { return task; } @@ -222,12 +221,12 @@ export class ToolResource extends BaseResource { // 检查超时 if (Date.now() - startTime > timeout) { throw new Error( - `Task timeout after ${timeout}ms. Current status: ${task.status}` + `Task timeout after ${timeout}ms. Current status: ${task.status}`, ); } // 等待后继续轮询 - await new Promise(resolve => setTimeout(resolve, pollInterval)); + await new Promise((resolve) => setTimeout(resolve, pollInterval)); } } @@ -250,7 +249,7 @@ export class ToolResource extends BaseResource { */ async getAllStats(): Promise { const result = await this.request<{ stats: ToolStats[] }>( - '/v1/tools/stats' + "/v1/tools/stats", ); return result.stats; } @@ -264,8 +263,8 @@ export class ToolResource extends BaseResource { start: string; end: string; }): Promise { - return this.request('/v1/tools/usage-report', { - params: timeRange + return this.request("/v1/tools/usage-report", { + params: timeRange, }); } @@ -278,9 +277,9 @@ export class ToolResource extends BaseResource { * @param toolNames 工具名称列表 */ async enableBatch(toolNames: string[]): Promise { - await this.request('/v1/tools/batch/enable', { - method: 'POST', - body: { toolNames } + await this.request("/v1/tools/batch/enable", { + method: "POST", + body: { toolNames }, }); } @@ -289,9 +288,9 @@ export class ToolResource extends BaseResource { * @param toolNames 工具名称列表 */ async disableBatch(toolNames: string[]): Promise { - await this.request('/v1/tools/batch/disable', { - method: 'POST', - body: { toolNames } + await this.request("/v1/tools/batch/disable", { + method: "POST", + body: { toolNames }, }); } } diff --git a/client-sdks/client-js/src/resources/workflow.ts b/client-sdks/client-js/src/resources/workflow.ts index 8f75930..6d5b280 100644 --- a/client-sdks/client-js/src/resources/workflow.ts +++ b/client-sdks/client-js/src/resources/workflow.ts @@ -3,7 +3,7 @@ * 管理工作流:Parallel、Sequential、Loop */ -import { BaseResource, ClientOptions } from './base'; +import { BaseResource, ClientOptions } from "./base"; import { WorkflowDefinition, WorkflowInfo, @@ -16,9 +16,9 @@ import { CancelWorkflowRequest, WorkflowRunFilter, WorkflowValidationResult, - UpdateWorkflowRequest -} from '../types/workflow'; -import { PaginatedResponse } from '../types/session'; + UpdateWorkflowRequest, +} from "../types/workflow"; +import { PaginatedResponse } from "../types/session"; /** * Workflow 资源类 @@ -38,9 +38,9 @@ export class WorkflowResource extends BaseResource { * @returns Workflow 信息 */ async create(definition: WorkflowDefinition): Promise { - return this.request('/v1/workflows', { - method: 'POST', - body: definition + return this.request("/v1/workflows", { + method: "POST", + body: definition, }); } @@ -59,10 +59,10 @@ export class WorkflowResource extends BaseResource { * @returns Workflow 列表 */ async list( - filter?: WorkflowFilter + filter?: WorkflowFilter, ): Promise> { - return this.request>('/v1/workflows', { - params: filter + return this.request>("/v1/workflows", { + params: filter, }); } @@ -74,11 +74,11 @@ export class WorkflowResource extends BaseResource { */ async update( workflowId: string, - updates: UpdateWorkflowRequest + updates: UpdateWorkflowRequest, ): Promise { return this.request(`/v1/workflows/${workflowId}`, { - method: 'PATCH', - body: updates + method: "PATCH", + body: updates, }); } @@ -88,7 +88,7 @@ export class WorkflowResource extends BaseResource { */ async delete(workflowId: string): Promise { await this.request(`/v1/workflows/${workflowId}`, { - method: 'DELETE' + method: "DELETE", }); } @@ -104,15 +104,12 @@ export class WorkflowResource extends BaseResource { */ async execute( workflowId: string, - request: ExecuteWorkflowRequest + request: ExecuteWorkflowRequest, ): Promise { - return this.request( - `/v1/workflows/${workflowId}/execute`, - { - method: 'POST', - body: request - } - ); + return this.request(`/v1/workflows/${workflowId}/execute`, { + method: "POST", + body: request, + }); } /** @@ -122,11 +119,11 @@ export class WorkflowResource extends BaseResource { */ async suspend( workflowId: string, - request: SuspendWorkflowRequest + request: SuspendWorkflowRequest, ): Promise { await this.request(`/v1/workflows/${workflowId}/suspend`, { - method: 'POST', - body: request + method: "POST", + body: request, }); } @@ -137,11 +134,11 @@ export class WorkflowResource extends BaseResource { */ async resume( workflowId: string, - request: ResumeWorkflowRequest + request: ResumeWorkflowRequest, ): Promise { await this.request(`/v1/workflows/${workflowId}/resume`, { - method: 'POST', - body: request + method: "POST", + body: request, }); } @@ -152,11 +149,11 @@ export class WorkflowResource extends BaseResource { */ async cancel( workflowId: string, - request: CancelWorkflowRequest + request: CancelWorkflowRequest, ): Promise { await this.request(`/v1/workflows/${workflowId}/cancel`, { - method: 'POST', - body: request + method: "POST", + body: request, }); } @@ -172,11 +169,11 @@ export class WorkflowResource extends BaseResource { */ async getRuns( workflowId: string, - filter?: WorkflowRunFilter + filter?: WorkflowRunFilter, ): Promise> { return this.request>( `/v1/workflows/${workflowId}/executions`, - { params: filter } + { params: filter }, ); } @@ -188,7 +185,7 @@ export class WorkflowResource extends BaseResource { */ async listExecutions( workflowId: string, - filter?: WorkflowRunFilter + filter?: WorkflowRunFilter, ): Promise { const result = await this.getRuns(workflowId, filter); return result.items || []; @@ -200,12 +197,9 @@ export class WorkflowResource extends BaseResource { * @param runId Run ID * @returns 执行详情 */ - async getRunDetails( - workflowId: string, - runId: string - ): Promise { + async getRunDetails(workflowId: string, runId: string): Promise { return this.request( - `/v1/workflows/${workflowId}/runs/${runId}` + `/v1/workflows/${workflowId}/runs/${runId}`, ); } @@ -215,12 +209,9 @@ export class WorkflowResource extends BaseResource { * @param runId Run ID * @returns 执行状态 */ - async getRunStatus( - workflowId: string, - runId: string - ): Promise { + async getRunStatus(workflowId: string, runId: string): Promise { return this.request( - `/v1/workflows/${workflowId}/runs/${runId}/status` + `/v1/workflows/${workflowId}/runs/${runId}/status`, ); } @@ -234,11 +225,11 @@ export class WorkflowResource extends BaseResource { * @returns 验证结果 */ async validate( - definition: WorkflowDefinition + definition: WorkflowDefinition, ): Promise { - return this.request('/v1/workflows/validate', { - method: 'POST', - body: definition + return this.request("/v1/workflows/validate", { + method: "POST", + body: definition, }); } @@ -251,9 +242,9 @@ export class WorkflowResource extends BaseResource { * @param workflowIds Workflow ID 列表 */ async deleteBatch(workflowIds: string[]): Promise { - await this.request('/v1/workflows/batch', { - method: 'DELETE', - body: { workflowIds } + await this.request("/v1/workflows/batch", { + method: "DELETE", + body: { workflowIds }, }); } @@ -262,9 +253,9 @@ export class WorkflowResource extends BaseResource { * @param workflowIds Workflow ID 列表 */ async archiveBatch(workflowIds: string[]): Promise { - await this.request('/v1/workflows/batch/archive', { - method: 'POST', - body: { workflowIds } + await this.request("/v1/workflows/batch/archive", { + method: "POST", + body: { workflowIds }, }); } @@ -283,9 +274,9 @@ export class WorkflowResource extends BaseResource { workflowId: string, runId: string, options?: { - pollInterval?: number; // 轮询间隔(毫秒),默认 1000 - timeout?: number; // 超时时间(毫秒),默认 300000 (5分钟) - } + pollInterval?: number; // 轮询间隔(毫秒),默认 1000 + timeout?: number; // 超时时间(毫秒),默认 300000 (5分钟) + }, ): Promise { const pollInterval = options?.pollInterval ?? 1000; const timeout = options?.timeout ?? 300000; @@ -296,9 +287,9 @@ export class WorkflowResource extends BaseResource { // 检查是否完成 if ( - run.status === 'completed' || - run.status === 'failed' || - run.status === 'cancelled' + run.status === "completed" || + run.status === "failed" || + run.status === "cancelled" ) { return run; } @@ -306,12 +297,12 @@ export class WorkflowResource extends BaseResource { // 检查超时 if (Date.now() - startTime > timeout) { throw new Error( - `Workflow execution timeout after ${timeout}ms. Current status: ${run.status}` + `Workflow execution timeout after ${timeout}ms. Current status: ${run.status}`, ); } // 等待后继续轮询 - await new Promise(resolve => setTimeout(resolve, pollInterval)); + await new Promise((resolve) => setTimeout(resolve, pollInterval)); } } } diff --git a/client-sdks/client-js/src/transport/websocket.ts b/client-sdks/client-js/src/transport/websocket.ts index f1880e5..4dcb85b 100644 --- a/client-sdks/client-js/src/transport/websocket.ts +++ b/client-sdks/client-js/src/transport/websocket.ts @@ -7,12 +7,12 @@ * WebSocket 连接状态 */ export enum WebSocketState { - CONNECTING = 'CONNECTING', - CONNECTED = 'CONNECTED', - DISCONNECTING = 'DISCONNECTING', - DISCONNECTED = 'DISCONNECTED', - RECONNECTING = 'RECONNECTING', - FAILED = 'FAILED', + CONNECTING = "CONNECTING", + CONNECTED = "CONNECTED", + DISCONNECTING = "DISCONNECTING", + DISCONNECTED = "DISCONNECTED", + RECONNECTING = "RECONNECTING", + FAILED = "FAILED", } /** @@ -70,8 +70,11 @@ export class WebSocketClient { * 连接到 WebSocket 服务器 */ async connect(url: string): Promise { - if (this.state === WebSocketState.CONNECTED || this.state === WebSocketState.CONNECTING) { - console.warn('[WebSocket] Already connected or connecting'); + if ( + this.state === WebSocketState.CONNECTED || + this.state === WebSocketState.CONNECTING + ) { + console.warn("[WebSocket] Already connected or connecting"); return; } @@ -81,15 +84,14 @@ export class WebSocketClient { return new Promise((resolve, reject) => { try { // 在浏览器和 Node.js 中使用不同的 WebSocket - const WebSocketImpl = typeof window !== 'undefined' - ? window.WebSocket - : require('ws'); - + const WebSocketImpl = + typeof window !== "undefined" ? window.WebSocket : require("ws"); + this.ws = new WebSocketImpl(url); if (this.ws) { this.ws.onopen = () => { - console.log('[WebSocket] Connected'); + console.log("[WebSocket] Connected"); this.setState(WebSocketState.CONNECTED); this.reconnectAttempts = 0; this.startHeartbeat(); @@ -102,14 +104,14 @@ export class WebSocketClient { }; this.ws.onerror = (error) => { - console.error('[WebSocket] Error:', error); + console.error("[WebSocket] Error:", error); reject(error); }; this.ws.onclose = (event) => { - console.log('[WebSocket] Closed:', event.code, event.reason); + console.log("[WebSocket] Closed:", event.code, event.reason); this.stopHeartbeat(); - + if (this.state !== WebSocketState.DISCONNECTING) { this.handleReconnect(); } else { @@ -117,9 +119,8 @@ export class WebSocketClient { } }; } - } catch (error) { - console.error('[WebSocket] Connection failed:', error); + console.error("[WebSocket] Connection failed:", error); this.setState(WebSocketState.FAILED); reject(error); } @@ -130,7 +131,10 @@ export class WebSocketClient { * 断开连接 */ disconnect(): void { - if (this.state === WebSocketState.DISCONNECTED || this.state === WebSocketState.DISCONNECTING) { + if ( + this.state === WebSocketState.DISCONNECTED || + this.state === WebSocketState.DISCONNECTING + ) { return; } @@ -149,13 +153,14 @@ export class WebSocketClient { * 发送消息 */ send(message: any): void { - const data = typeof message === 'string' ? message : JSON.stringify(message); + const data = + typeof message === "string" ? message : JSON.stringify(message); if (this.state === WebSocketState.CONNECTED && this.ws) { try { this.ws.send(data); } catch (error) { - console.error('[WebSocket] Send failed:', error); + console.error("[WebSocket] Send failed:", error); // 发送失败,加入队列 this.messageQueue.push(message); } @@ -199,24 +204,27 @@ export class WebSocketClient { */ private handleMessage(data: string | Buffer): void { try { - const message = typeof data === 'string' ? JSON.parse(data) : JSON.parse(data.toString()); - + const message = + typeof data === "string" + ? JSON.parse(data) + : JSON.parse(data.toString()); + // 检查是否为心跳响应 - if (message.type === 'pong') { + if (message.type === "pong") { this.handleHeartbeatResponse(); return; } // 通知所有监听器 - this.messageListeners.forEach(listener => { + this.messageListeners.forEach((listener) => { try { listener(message); } catch (error) { - console.error('[WebSocket] Message listener error:', error); + console.error("[WebSocket] Message listener error:", error); } }); } catch (error) { - console.error('[WebSocket] Parse message failed:', error); + console.error("[WebSocket] Parse message failed:", error); } } @@ -224,7 +232,10 @@ export class WebSocketClient { * 刷新消息队列 */ private flushMessageQueue(): void { - while (this.messageQueue.length > 0 && this.state === WebSocketState.CONNECTED) { + while ( + this.messageQueue.length > 0 && + this.state === WebSocketState.CONNECTED + ) { const message = this.messageQueue.shift(); this.send(message); } @@ -235,7 +246,7 @@ export class WebSocketClient { */ private async handleReconnect(): Promise { if (this.reconnectAttempts >= this.maxReconnectAttempts) { - console.error('[WebSocket] Max reconnect attempts reached'); + console.error("[WebSocket] Max reconnect attempts reached"); this.setState(WebSocketState.FAILED); return; } @@ -245,15 +256,17 @@ export class WebSocketClient { // 指数退避 const delay = this.reconnectDelay * Math.pow(2, this.reconnectAttempts - 1); - console.log(`[WebSocket] Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts}/${this.maxReconnectAttempts})`); + console.log( + `[WebSocket] Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts}/${this.maxReconnectAttempts})`, + ); - await new Promise(resolve => setTimeout(resolve, delay)); + await new Promise((resolve) => setTimeout(resolve, delay)); if (this.url) { try { await this.connect(this.url); } catch (error) { - console.error('[WebSocket] Reconnect failed:', error); + console.error("[WebSocket] Reconnect failed:", error); // 继续尝试重连 this.handleReconnect(); } @@ -267,13 +280,13 @@ export class WebSocketClient { if (this.state !== newState) { this.state = newState; console.log(`[WebSocket] State changed: ${newState}`); - + // 通知所有监听器 - this.stateChangeListeners.forEach(listener => { + this.stateChangeListeners.forEach((listener) => { try { listener(newState); } catch (error) { - console.error('[WebSocket] State change listener error:', error); + console.error("[WebSocket] State change listener error:", error); } }); } @@ -287,11 +300,11 @@ export class WebSocketClient { this.heartbeatTimer = setInterval(() => { if (this.state === WebSocketState.CONNECTED) { - this.send({ type: 'ping' }); - + this.send({ type: "ping" }); + // 设置心跳超时 this.heartbeatTimeoutTimer = setTimeout(() => { - console.warn('[WebSocket] Heartbeat timeout, reconnecting...'); + console.warn("[WebSocket] Heartbeat timeout, reconnecting..."); this.disconnect(); if (this.url) { this.connect(this.url); diff --git a/client-sdks/client-js/src/types/agent.ts b/client-sdks/client-js/src/types/agent.ts index 225ef71..7106a07 100644 --- a/client-sdks/client-js/src/types/agent.ts +++ b/client-sdks/client-js/src/types/agent.ts @@ -42,11 +42,11 @@ export interface AgentConfig { /** * Agent 状态 */ -export type AgentStatus = - | 'active' // 活跃 - | 'inactive' // 未激活 - | 'disabled' // 已禁用 - | 'archived'; // 已归档 +export type AgentStatus = + | "active" // 活跃 + | "inactive" // 未激活 + | "disabled" // 已禁用 + | "archived"; // 已归档 /** * Agent 信息 @@ -73,14 +73,14 @@ export interface AgentInfo extends AgentConfig { /** * Agent 模板类型 */ -export type AgentTemplateType = - | 'assistant' // 通用助手 - | 'researcher' // 研究员 - | 'coder' // 程序员 - | 'writer' // 写作者 - | 'analyzer' // 分析师 - | 'translator' // 翻译员 - | 'custom'; // 自定义 +export type AgentTemplateType = + | "assistant" // 通用助手 + | "researcher" // 研究员 + | "coder" // 程序员 + | "writer" // 写作者 + | "analyzer" // 分析师 + | "translator" // 翻译员 + | "custom"; // 自定义 /** * Agent 模板 @@ -230,18 +230,18 @@ export interface ToolCall { /** 结果 */ result?: any; /** 状态 */ - status: 'pending' | 'running' | 'completed' | 'failed'; + status: "pending" | "running" | "completed" | "failed"; } /** * 流式 Chat 事件 */ -export type StreamChatEvent = - | { type: 'start'; sessionId: string } - | { type: 'token'; token: string } - | { type: 'tool_call'; toolCall: ToolCall } - | { type: 'end'; response: ChatResponse } - | { type: 'error'; error: string }; +export type StreamChatEvent = + | { type: "start"; sessionId: string } + | { type: "token"; token: string } + | { type: "tool_call"; toolCall: ToolCall } + | { type: "end"; response: ChatResponse } + | { type: "error"; error: string }; // ============================================================================ // Agent Statistics @@ -308,9 +308,9 @@ export interface AgentFilter { createdAfter?: string; createdBefore?: string; /** 排序字段 */ - sortBy?: 'name' | 'createdAt' | 'updatedAt' | 'lastUsedAt'; + sortBy?: "name" | "createdAt" | "updatedAt" | "lastUsedAt"; /** 排序方向 */ - sortOrder?: 'asc' | 'desc'; + sortOrder?: "asc" | "desc"; /** 分页 */ page?: number; pageSize?: number; diff --git a/client-sdks/client-js/src/types/eval.ts b/client-sdks/client-js/src/types/eval.ts index 8fd26a3..a3b493c 100644 --- a/client-sdks/client-js/src/types/eval.ts +++ b/client-sdks/client-js/src/types/eval.ts @@ -11,21 +11,21 @@ * Eval 类型 */ export type EvalType = - | 'single' // 单次评估 - | 'batch' // 批量评估 - | 'benchmark' // 基准测试 - | 'regression' // 回归测试 - | 'ab_test'; // A/B 测试 + | "single" // 单次评估 + | "batch" // 批量评估 + | "benchmark" // 基准测试 + | "regression" // 回归测试 + | "ab_test"; // A/B 测试 /** * Eval 状态 */ export type EvalStatus = - | 'pending' // 待执行 - | 'running' // 执行中 - | 'completed' // 已完成 - | 'failed' // 失败 - | 'cancelled'; // 已取消 + | "pending" // 待执行 + | "running" // 执行中 + | "completed" // 已完成 + | "failed" // 失败 + | "cancelled"; // 已取消 // ============================================================================ // Scorers @@ -35,16 +35,16 @@ export type EvalStatus = * Scorer 类型 */ export type ScorerType = - | 'exact_match' // 精确匹配 - | 'contains' // 包含检查 - | 'semantic_similarity' // 语义相似度 - | 'llm_judge' // LLM 评分 - | 'keyword_coverage' // 关键词覆盖率 - | 'sentiment' // 情感分析 - | 'factuality' // 事实准确性 - | 'coherence' // 连贯性 - | 'relevance' // 相关性 - | 'custom'; // 自定义 + | "exact_match" // 精确匹配 + | "contains" // 包含检查 + | "semantic_similarity" // 语义相似度 + | "llm_judge" // LLM 评分 + | "keyword_coverage" // 关键词覆盖率 + | "sentiment" // 情感分析 + | "factuality" // 事实准确性 + | "coherence" // 连贯性 + | "relevance" // 相关性 + | "custom"; // 自定义 /** * Scorer 配置 @@ -62,7 +62,7 @@ export interface ScorerConfig { * LLM Judge Scorer 配置 */ export interface LLMJudgeScorerConfig extends ScorerConfig { - type: 'llm_judge'; + type: "llm_judge"; params: { /** LLM Provider */ provider: string; @@ -84,7 +84,7 @@ export interface LLMJudgeScorerConfig extends ScorerConfig { * Semantic Similarity Scorer 配置 */ export interface SemanticSimilarityScorerConfig extends ScorerConfig { - type: 'semantic_similarity'; + type: "semantic_similarity"; params: { /** 嵌入模型 */ embeddingModel?: string; @@ -401,7 +401,7 @@ export interface ABTestResult { /** 是否显著 */ isSignificant: boolean; /** 胜者 */ - winner?: 'A' | 'B' | 'tie'; + winner?: "A" | "B" | "tie"; }; /** 创建时间 */ createdAt: string; @@ -427,9 +427,9 @@ export interface EvalFilter { createdAfter?: string; createdBefore?: string; /** 排序字段 */ - sortBy?: 'createdAt' | 'completedAt' | 'avgScore' | 'passRate'; + sortBy?: "createdAt" | "completedAt" | "avgScore" | "passRate"; /** 排序方向 */ - sortOrder?: 'asc' | 'desc'; + sortOrder?: "asc" | "desc"; /** 分页 */ page?: number; pageSize?: number; @@ -458,7 +458,7 @@ export interface PaginatedEvalResponse { /** * 报告格式 */ -export type ReportFormat = 'json' | 'html' | 'markdown' | 'csv'; +export type ReportFormat = "json" | "html" | "markdown" | "csv"; /** * 报告请求 diff --git a/client-sdks/client-js/src/types/mcp.ts b/client-sdks/client-js/src/types/mcp.ts index 34ae50d..78566a9 100644 --- a/client-sdks/client-js/src/types/mcp.ts +++ b/client-sdks/client-js/src/types/mcp.ts @@ -46,11 +46,11 @@ export interface MCPServerInfo extends MCPServerConfig { /** * MCP Server 状态 */ -export type MCPServerStatus = - | 'connected' // 已连接 - | 'disconnected' // 已断开 - | 'connecting' // 连接中 - | 'error'; // 错误 +export type MCPServerStatus = + | "connected" // 已连接 + | "disconnected" // 已断开 + | "connecting" // 连接中 + | "error"; // 错误 // ============================================================================ // MCP Tools @@ -69,7 +69,7 @@ export interface MCPTool { /** 输出 Schema */ outputSchema?: MCPToolSchema; /** 工具类型 */ - type?: 'function' | 'api' | 'command'; + type?: "function" | "api" | "command"; /** 所属 Server */ serverId: string; } @@ -192,7 +192,7 @@ export interface MCPPrompt { export interface MCPPromptResult { /** 消息列表 */ messages: Array<{ - role: 'user' | 'assistant' | 'system'; + role: "user" | "assistant" | "system"; content: string; }>; } @@ -228,12 +228,12 @@ export interface MCPStats { /** * MCP 事件类型 */ -export type MCPEventType = - | 'server_connected' - | 'server_disconnected' - | 'tool_called' - | 'tool_completed' - | 'error'; +export type MCPEventType = + | "server_connected" + | "server_disconnected" + | "tool_called" + | "tool_completed" + | "error"; /** * MCP 事件 diff --git a/client-sdks/client-js/src/types/memory.ts b/client-sdks/client-js/src/types/memory.ts index ab9fc10..df922cf 100644 --- a/client-sdks/client-js/src/types/memory.ts +++ b/client-sdks/client-js/src/types/memory.ts @@ -12,7 +12,7 @@ * - thread: 会话级别(当前对话) * - resource: 全局级别(跨会话) */ -export type WorkingMemoryScope = 'thread' | 'resource'; +export type WorkingMemoryScope = "thread" | "resource"; /** * JSON Schema 定义 @@ -111,7 +111,11 @@ export interface SearchResult { /** * 记忆来源类型 */ -export type MemorySource = 'user_input' | 'tool_output' | 'inference' | 'external'; +export type MemorySource = + | "user_input" + | "tool_output" + | "inference" + | "external"; /** * 记忆溯源信息 @@ -150,10 +154,10 @@ export interface ProvenanceResponse { /** * 记忆合并策略 */ -export type ConsolidationStrategy = - | 'dedup' // 去重 - | 'resolve_conflict' // 解决冲突 - | 'summarize'; // 总结 +export type ConsolidationStrategy = + | "dedup" // 去重 + | "resolve_conflict" // 解决冲突 + | "summarize"; // 总结 /** * 记忆合并选项 @@ -177,11 +181,11 @@ export interface ConsolidateOptions { /** * 合并任务状态 */ -export type ConsolidationStatus = - | 'pending' // 等待中 - | 'running' // 运行中 - | 'completed' // 完成 - | 'failed'; // 失败 +export type ConsolidationStatus = + | "pending" // 等待中 + | "running" // 运行中 + | "completed" // 完成 + | "failed"; // 失败 /** * 记忆合并结果 @@ -226,7 +230,7 @@ export interface JobStatus { /** * 消息角色 */ -export type MessageRole = 'user' | 'assistant' | 'system' | 'tool'; +export type MessageRole = "user" | "assistant" | "system" | "tool"; /** * 消息内容 diff --git a/client-sdks/client-js/src/types/middleware.ts b/client-sdks/client-js/src/types/middleware.ts index bec0b69..0a16911 100644 --- a/client-sdks/client-js/src/types/middleware.ts +++ b/client-sdks/client-js/src/types/middleware.ts @@ -10,15 +10,15 @@ /** * 内置 Middleware 名称 */ -export type BuiltinMiddlewareName = - | 'summarization' // 1. 总结中间件(上下文压缩) - | 'tool_approval' // 2. 工具审批 - | 'pii_redaction' // 3. PII 脱敏 - | 'token_limiter' // 4. Token 限制 - | 'rate_limiter' // 5. 速率限制 - | 'cost_tracker' // 6. 成本追踪 - | 'logging' // 7. 日志记录 - | 'telemetry'; // 8. 遥测 +export type BuiltinMiddlewareName = + | "summarization" // 1. 总结中间件(上下文压缩) + | "tool_approval" // 2. 工具审批 + | "pii_redaction" // 3. PII 脱敏 + | "token_limiter" // 4. Token 限制 + | "rate_limiter" // 5. 速率限制 + | "cost_tracker" // 6. 成本追踪 + | "logging" // 7. 日志记录 + | "telemetry"; // 8. 遥测 /** * Middleware 信息 @@ -31,7 +31,7 @@ export interface MiddlewareInfo { /** 描述 */ description: string; /** 类型 */ - type: 'builtin' | 'custom'; + type: "builtin" | "custom"; /** 是否启用 */ enabled: boolean; /** 优先级(数字越小越早执行) */ @@ -49,14 +49,17 @@ export interface MiddlewareConfigSchema { /** Schema 类型 */ type: string; /** 属性定义 */ - properties: Record; + properties: Record< + string, + { + type: string; + description?: string; + default?: any; + enum?: any[]; + minimum?: number; + maximum?: number; + } + >; /** 必需字段 */ required?: string[]; } @@ -94,7 +97,7 @@ export interface ToolApprovalConfig { /** 审批超时时间(秒) */ approvalTimeout: number; /** 超时默认行为 */ - timeoutBehavior: 'approve' | 'reject'; + timeoutBehavior: "approve" | "reject"; } /** @@ -103,9 +106,11 @@ export interface ToolApprovalConfig { */ export interface PIIRedactionConfig { /** 启用的 PII 类型 */ - enabledTypes: Array<'email' | 'phone' | 'ssn' | 'credit_card' | 'ip_address' | 'name'>; + enabledTypes: Array< + "email" | "phone" | "ssn" | "credit_card" | "ip_address" | "name" + >; /** 脱敏策略 */ - strategy: 'mask' | 'remove' | 'replace'; + strategy: "mask" | "remove" | "replace"; /** 替换文本(strategy=replace 时使用) */ replacementText?: string; /** 是否保留部分信息 */ @@ -124,7 +129,7 @@ export interface TokenLimiterConfig { /** 每天最大 Token 数 */ maxTokensPerDay?: number; /** 超限行为 */ - onExceeded: 'reject' | 'truncate' | 'queue'; + onExceeded: "reject" | "truncate" | "queue"; } /** @@ -137,9 +142,9 @@ export interface RateLimiterConfig { /** 窗口内最大请求数 */ maxRequests: number; /** 限流策略 */ - strategy: 'fixed_window' | 'sliding_window' | 'token_bucket'; + strategy: "fixed_window" | "sliding_window" | "token_bucket"; /** 超限行为 */ - onExceeded: 'reject' | 'queue' | 'delay'; + onExceeded: "reject" | "queue" | "delay"; } /** @@ -150,12 +155,12 @@ export interface CostTrackerConfig { /** 是否启用成本追踪 */ enabled: boolean; /** 成本模型 */ - costModel: 'token_based' | 'time_based' | 'custom'; + costModel: "token_based" | "time_based" | "custom"; /** 成本计算方式 */ pricing?: { - promptTokenPrice: number; // 每 1K prompt tokens 的价格 - completionTokenPrice: number; // 每 1K completion tokens 的价格 - currency: string; // 货币单位 + promptTokenPrice: number; // 每 1K prompt tokens 的价格 + completionTokenPrice: number; // 每 1K completion tokens 的价格 + currency: string; // 货币单位 }; /** 预算限制 */ budget?: { @@ -170,7 +175,7 @@ export interface CostTrackerConfig { */ export interface LoggingConfig { /** 日志级别 */ - level: 'debug' | 'info' | 'warn' | 'error'; + level: "debug" | "info" | "warn" | "error"; /** 是否记录请求 */ logRequests: boolean; /** 是否记录响应 */ @@ -180,9 +185,9 @@ export interface LoggingConfig { /** 是否记录错误 */ logErrors: boolean; /** 日志格式 */ - format: 'json' | 'text'; + format: "json" | "text"; /** 输出目标 */ - outputs: Array<'console' | 'file' | 'remote'>; + outputs: Array<"console" | "file" | "remote">; } /** @@ -195,7 +200,7 @@ export interface TelemetryMiddlewareConfig { /** 采样率(0-1) */ samplingRate: number; /** 收集的指标 */ - metrics: Array<'latency' | 'tokens' | 'cost' | 'errors' | 'tool_calls'>; + metrics: Array<"latency" | "tokens" | "cost" | "errors" | "tool_calls">; /** 导出端点 */ exportEndpoint?: string; /** 导出间隔(秒) */ diff --git a/client-sdks/client-js/src/types/session.ts b/client-sdks/client-js/src/types/session.ts index 993efa7..b9e5065 100644 --- a/client-sdks/client-js/src/types/session.ts +++ b/client-sdks/client-js/src/types/session.ts @@ -3,7 +3,7 @@ * 会话生命周期管理、消息历史、断点恢复 */ -import { Message as MemoryMessage } from './memory'; +import { Message as MemoryMessage } from "./memory"; // 重新导出 Message 类型 export type { MemoryMessage as Message }; @@ -59,11 +59,11 @@ export interface SessionInfo { /** * Session 状态 */ -export type SessionStatus = - | 'active' // 活跃 - | 'paused' // 暂停 - | 'completed' // 完成 - | 'archived'; // 归档 +export type SessionStatus = + | "active" // 活跃 + | "paused" // 暂停 + | "completed" // 完成 + | "archived"; // 归档 /** * Session 过滤器 @@ -98,7 +98,7 @@ export interface Pagination { /** 每页数量 */ pageSize?: number; /** 排序方式 */ - sort?: 'asc' | 'desc'; + sort?: "asc" | "desc"; } /** @@ -125,14 +125,14 @@ export interface PaginatedResponse { * Checkpoint 类型 * AsterClient 使用 7 段断点机制 */ -export type CheckpointType = - | 'user_input' // 1. 用户输入 - | 'agent_thinking' // 2. Agent 思考 - | 'tool_call' // 3. 工具调用 - | 'tool_result' // 4. 工具结果 - | 'agent_response' // 5. Agent 响应 - | 'memory_update' // 6. 记忆更新 - | 'session_state'; // 7. 会话状态 +export type CheckpointType = + | "user_input" // 1. 用户输入 + | "agent_thinking" // 2. Agent 思考 + | "tool_call" // 3. 工具调用 + | "tool_result" // 4. 工具结果 + | "agent_response" // 5. Agent 响应 + | "memory_update" // 6. 记忆更新 + | "session_state"; // 7. 会话状态 /** * Checkpoint 信息 @@ -225,7 +225,7 @@ export interface AddMessageRequest { /** Session ID */ sessionId: string; /** 消息内容 */ - message: Omit; + message: Omit; } /** @@ -243,7 +243,7 @@ export interface UpdateSessionRequest { */ export interface ExportOptions { /** 格式 */ - format: 'json' | 'markdown' | 'html'; + format: "json" | "markdown" | "html"; /** 是否包含元数据 */ includeMetadata?: boolean; /** 是否包含统计信息 */ diff --git a/client-sdks/client-js/src/types/telemetry.ts b/client-sdks/client-js/src/types/telemetry.ts index a6d3f59..c5eae8e 100644 --- a/client-sdks/client-js/src/types/telemetry.ts +++ b/client-sdks/client-js/src/types/telemetry.ts @@ -10,11 +10,11 @@ /** * Metric 类型 */ -export type MetricType = - | 'counter' // 计数器(只增不减) - | 'gauge' // 仪表盘(可增可减) - | 'histogram' // 直方图(分布统计) - | 'summary'; // 摘要(百分位数) +export type MetricType = + | "counter" // 计数器(只增不减) + | "gauge" // 仪表盘(可增可减) + | "histogram" // 直方图(分布统计) + | "summary"; // 摘要(百分位数) /** * Metric 信息 @@ -62,7 +62,7 @@ export interface MetricQueryOptions { /** 标签过滤 */ labels?: Record; /** 聚合方式 */ - aggregation?: 'sum' | 'avg' | 'min' | 'max' | 'count'; + aggregation?: "sum" | "avg" | "min" | "max" | "count"; /** 分组 */ groupBy?: string[]; } @@ -90,7 +90,7 @@ export interface TraceInfo { /** 持续时间(毫秒) */ duration?: number; /** 状态 */ - status: 'ok' | 'error'; + status: "ok" | "error"; /** 标签 */ tags?: Record; /** 事件 */ @@ -127,7 +127,7 @@ export interface TraceQueryOptions { /** 最大持续时间(毫秒) */ maxDuration?: number; /** 状态 */ - status?: 'ok' | 'error'; + status?: "ok" | "error"; /** 标签过滤 */ tags?: Record; /** 限制数量 */ @@ -141,7 +141,7 @@ export interface TraceQueryOptions { /** * 日志级别 */ -export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'fatal'; +export type LogLevel = "debug" | "info" | "warn" | "error" | "fatal"; /** * 日志条目 @@ -185,7 +185,7 @@ export interface LogQueryOptions { /** 限制数量 */ limit?: number; /** 排序 */ - sort?: 'asc' | 'desc'; + sort?: "asc" | "desc"; } // ============================================================================ @@ -201,13 +201,13 @@ export interface TelemetryConfig { /** Metrics 配置 */ metrics?: { enabled: boolean; - exportInterval?: number; // 导出间隔(秒) + exportInterval?: number; // 导出间隔(秒) endpoint?: string; }; /** Traces 配置 */ traces?: { enabled: boolean; - samplingRate?: number; // 采样率(0-1) + samplingRate?: number; // 采样率(0-1) endpoint?: string; }; /** Logs 配置 */ @@ -227,7 +227,7 @@ export interface TelemetryConfig { */ export interface HealthCheckResult { /** 状态 */ - status: 'healthy' | 'degraded' | 'unhealthy'; + status: "healthy" | "degraded" | "unhealthy"; /** 时间戳 */ timestamp: string; /** 组件健康状态 */ @@ -241,7 +241,7 @@ export interface HealthCheckResult { */ export interface ComponentHealth { /** 状态 */ - status: 'healthy' | 'degraded' | 'unhealthy'; + status: "healthy" | "degraded" | "unhealthy"; /** 消息 */ message?: string; /** 详细信息 */ @@ -266,10 +266,10 @@ export interface PerformanceMetrics { total: number; successful: number; failed: number; - avgLatency: number; // 平均延迟(ms) - p50Latency: number; // P50 延迟 - p95Latency: number; // P95 延迟 - p99Latency: number; // P99 延迟 + avgLatency: number; // 平均延迟(ms) + p50Latency: number; // P50 延迟 + p95Latency: number; // P95 延迟 + p99Latency: number; // P99 延迟 }; /** Token 统计 */ tokens?: { @@ -345,18 +345,18 @@ export interface UsageStatistics { /** * 导出格式 */ -export type ExportFormat = - | 'json' - | 'csv' - | 'prometheus' // Prometheus 格式 - | 'opentelemetry'; // OpenTelemetry 格式 +export type ExportFormat = + | "json" + | "csv" + | "prometheus" // Prometheus 格式 + | "opentelemetry"; // OpenTelemetry 格式 /** * 导出请求 */ export interface ExportTelemetryRequest { /** 导出类型 */ - type: 'metrics' | 'traces' | 'logs'; + type: "metrics" | "traces" | "logs"; /** 格式 */ format: ExportFormat; /** 时间范围 */ diff --git a/client-sdks/client-js/src/types/tool.ts b/client-sdks/client-js/src/types/tool.ts index d0eecdf..8fde9e5 100644 --- a/client-sdks/client-js/src/types/tool.ts +++ b/client-sdks/client-js/src/types/tool.ts @@ -10,34 +10,34 @@ /** * 工具类型 */ -export type ToolType = - | 'builtin' // 内置工具 - | 'custom' // 自定义工具 - | 'mcp'; // MCP 工具 +export type ToolType = + | "builtin" // 内置工具 + | "custom" // 自定义工具 + | "mcp"; // MCP 工具 /** * 工具分类 */ -export type ToolCategory = - | 'system' // 系统工具 - | 'file' // 文件操作 - | 'network' // 网络请求 - | 'data' // 数据处理 - | 'code' // 代码执行 - | 'integration' // 第三方集成 - | 'other'; // 其他 +export type ToolCategory = + | "system" // 系统工具 + | "file" // 文件操作 + | "network" // 网络请求 + | "data" // 数据处理 + | "code" // 代码执行 + | "integration" // 第三方集成 + | "other"; // 其他 /** * 内置工具名称 */ -export type BuiltinToolName = - | 'bash' // Bash 命令执行 - | 'python' // Python 代码执行 - | 'http_request' // HTTP 请求 - | 'file_read' // 文件读取 - | 'file_write' // 文件写入 - | 'web_scraper' // 网页抓取 - | 'database_query'; // 数据库查询 +export type BuiltinToolName = + | "bash" // Bash 命令执行 + | "python" // Python 代码执行 + | "http_request" // HTTP 请求 + | "file_read" // 文件读取 + | "file_write" // 文件写入 + | "web_scraper" // 网页抓取 + | "database_query"; // 数据库查询 // ============================================================================ // Tool Info @@ -154,7 +154,7 @@ export interface AsyncToolExecutionResponse { /** 任务 ID */ taskId: string; /** 状态 */ - status: 'pending' | 'running'; + status: "pending" | "running"; /** 创建时间 */ createdAt: string; } @@ -166,12 +166,12 @@ export interface AsyncToolExecutionResponse { /** * 长时运行任务状态 */ -export type TaskStatus = - | 'pending' // 等待中 - | 'running' // 运行中 - | 'completed' // 完成 - | 'failed' // 失败 - | 'cancelled'; // 已取消 +export type TaskStatus = + | "pending" // 等待中 + | "running" // 运行中 + | "completed" // 完成 + | "failed" // 失败 + | "cancelled"; // 已取消 /** * 任务进度信息 @@ -238,7 +238,7 @@ export interface HttpRequestToolParams { /** URL */ url: string; /** 方法 */ - method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH'; + method: "GET" | "POST" | "PUT" | "DELETE" | "PATCH"; /** Headers */ headers?: Record; /** 请求体 */ diff --git a/client-sdks/client-js/src/types/workflow.ts b/client-sdks/client-js/src/types/workflow.ts index aee1080..e23d476 100644 --- a/client-sdks/client-js/src/types/workflow.ts +++ b/client-sdks/client-js/src/types/workflow.ts @@ -10,19 +10,19 @@ /** * Workflow 类型 */ -export type WorkflowType = - | 'parallel' // 并行执行 - | 'sequential' // 顺序执行 - | 'loop'; // 循环执行 +export type WorkflowType = + | "parallel" // 并行执行 + | "sequential" // 顺序执行 + | "loop"; // 循环执行 /** * Workflow 状态 */ -export type WorkflowStatus = - | 'draft' // 草稿 - | 'active' // 活跃 - | 'paused' // 暂停 - | 'archived'; // 归档 +export type WorkflowStatus = + | "draft" // 草稿 + | "active" // 活跃 + | "paused" // 暂停 + | "archived"; // 归档 // ============================================================================ // Workflow Definition @@ -45,7 +45,7 @@ interface BaseWorkflowDefinition { * 多个 Agent 并行执行 */ export interface ParallelWorkflowDefinition extends BaseWorkflowDefinition { - type: 'parallel'; + type: "parallel"; /** Agent 配置列表 */ agents: Array<{ id: string; @@ -63,7 +63,7 @@ export interface ParallelWorkflowDefinition extends BaseWorkflowDefinition { * Agent 按顺序执行 */ export interface SequentialWorkflowDefinition extends BaseWorkflowDefinition { - type: 'sequential'; + type: "sequential"; /** 执行步骤 */ steps: Array<{ agent: string; @@ -81,7 +81,7 @@ export interface SequentialWorkflowDefinition extends BaseWorkflowDefinition { * 循环执行直到满足条件 */ export interface LoopWorkflowDefinition extends BaseWorkflowDefinition { - type: 'loop'; + type: "loop"; /** Agent ID */ agent: string; /** 循环条件(JavaScript 表达式) */ @@ -95,7 +95,7 @@ export interface LoopWorkflowDefinition extends BaseWorkflowDefinition { /** * Workflow 定义联合类型 */ -export type WorkflowDefinition = +export type WorkflowDefinition = | ParallelWorkflowDefinition | SequentialWorkflowDefinition | LoopWorkflowDefinition; @@ -139,13 +139,13 @@ export interface WorkflowInfo { /** * Workflow 执行状态 */ -export type WorkflowRunStatus = - | 'pending' // 等待中 - | 'running' // 运行中 - | 'suspended' // 已暂停 - | 'completed' // 完成 - | 'failed' // 失败 - | 'cancelled'; // 已取消 +export type WorkflowRunStatus = + | "pending" // 等待中 + | "running" // 运行中 + | "suspended" // 已暂停 + | "completed" // 完成 + | "failed" // 失败 + | "cancelled"; // 已取消 /** * Workflow 执行记录 @@ -194,7 +194,7 @@ export interface WorkflowStepResult { /** Agent ID */ agentId: string; /** 状态 */ - status: 'pending' | 'running' | 'completed' | 'failed' | 'skipped'; + status: "pending" | "running" | "completed" | "failed" | "skipped"; /** 开始时间 */ startedAt?: string; /** 结束时间 */ diff --git a/client-sdks/client-js/test_client.js b/client-sdks/client-js/test_client.js index 4863445..31b1dc3 100644 --- a/client-sdks/client-js/test_client.js +++ b/client-sdks/client-js/test_client.js @@ -3,35 +3,35 @@ * 验证与服务端API的连接性 */ -const BASE_URL = process.env.API_URL || 'http://localhost:8080'; +const BASE_URL = process.env.API_URL || "http://localhost:8080"; // 简单的HTTP请求辅助函数 async function request(endpoint, options = {}) { const url = BASE_URL + endpoint; const response = await fetch(url, { - method: options.method || 'GET', + method: options.method || "GET", headers: { - 'Content-Type': 'application/json', - ...options.headers + "Content-Type": "application/json", + ...options.headers, }, - body: options.body ? JSON.stringify(options.body) : undefined + body: options.body ? JSON.stringify(options.body) : undefined, }); - + if (!response.ok && response.status !== 204) { const error = await response.text(); throw new Error(`Request failed: ${response.status} - ${error}`); } - + if (response.status === 204) { return null; } - + return await response.json(); } async function runTests() { - console.log('🚀 开始测试客户端SDK与服务端API连接性...\n'); - + console.log("🚀 开始测试客户端SDK与服务端API连接性...\n"); + let testsRun = 0; let testsPassed = 0; let testsFailed = 0; @@ -52,229 +52,232 @@ async function runTests() { // Agent API测试 let agentId; - await test('Agent: 创建', async () => { - const result = await request('/v1/agents', { - method: 'POST', - body: { name: 'Test Agent', model: 'gpt-4' } + await test("Agent: 创建", async () => { + const result = await request("/v1/agents", { + method: "POST", + body: { name: "Test Agent", model: "gpt-4" }, }); agentId = result.data.id; }); - await test('Agent: 列表', async () => { - await request('/v1/agents'); + await test("Agent: 列表", async () => { + await request("/v1/agents"); }); if (agentId) { - await test('Agent: 获取详情', async () => { + await test("Agent: 获取详情", async () => { await request(`/v1/agents/${agentId}`); }); - await test('Agent: 激活', async () => { - await request(`/v1/agents/${agentId}/activate`, { method: 'POST' }); + await test("Agent: 激活", async () => { + await request(`/v1/agents/${agentId}/activate`, { method: "POST" }); }); - await test('Agent: 删除', async () => { - await request(`/v1/agents/${agentId}`, { method: 'DELETE' }); + await test("Agent: 删除", async () => { + await request(`/v1/agents/${agentId}`, { method: "DELETE" }); }); } // Session API测试 let sessionId; - await test('Session: 创建', async () => { - const result = await request('/v1/sessions', { - method: 'POST', - body: { name: 'Test Session' } + await test("Session: 创建", async () => { + const result = await request("/v1/sessions", { + method: "POST", + body: { name: "Test Session" }, }); sessionId = result.data.id; }); - await test('Session: 列表', async () => { - await request('/v1/sessions'); + await test("Session: 列表", async () => { + await request("/v1/sessions"); }); if (sessionId) { - await test('Session: 添加消息', async () => { + await test("Session: 添加消息", async () => { await request(`/v1/sessions/${sessionId}/messages`, { - method: 'POST', - body: { role: 'user', content: 'Hello!' } + method: "POST", + body: { role: "user", content: "Hello!" }, }); }); - await test('Session: 删除', async () => { - await request(`/v1/sessions/${sessionId}`, { method: 'DELETE' }); + await test("Session: 删除", async () => { + await request(`/v1/sessions/${sessionId}`, { method: "DELETE" }); }); } // Memory API测试 - await test('Memory: 创建 Working Memory', async () => { - await request('/v1/memory/working', { - method: 'POST', - body: { key: 'test', value: { data: 'test' } } + await test("Memory: 创建 Working Memory", async () => { + await request("/v1/memory/working", { + method: "POST", + body: { key: "test", value: { data: "test" } }, }); }); - await test('Memory: 列表 Working Memory', async () => { - await request('/v1/memory/working'); + await test("Memory: 列表 Working Memory", async () => { + await request("/v1/memory/working"); }); - await test('Memory: 创建 Semantic Memory', async () => { - await request('/v1/memory/semantic', { - method: 'POST', - body: { content: 'Test', tags: ['test'] } + await test("Memory: 创建 Semantic Memory", async () => { + await request("/v1/memory/semantic", { + method: "POST", + body: { content: "Test", tags: ["test"] }, }); }); // Workflow API测试 let workflowId; - await test('Workflow: 创建', async () => { - const result = await request('/v1/workflows', { - method: 'POST', - body: { name: 'Test', steps: [{ id: '1', name: 'S1', type: 'agent' }] } + await test("Workflow: 创建", async () => { + const result = await request("/v1/workflows", { + method: "POST", + body: { name: "Test", steps: [{ id: "1", name: "S1", type: "agent" }] }, }); workflowId = result.data.id; }); if (workflowId) { - await test('Workflow: 执行', async () => { - await request(`/v1/workflows/${workflowId}/execute`, { method: 'POST', body: {} }); + await test("Workflow: 执行", async () => { + await request(`/v1/workflows/${workflowId}/execute`, { + method: "POST", + body: {}, + }); }); - await test('Workflow: 删除', async () => { - await request(`/v1/workflows/${workflowId}`, { method: 'DELETE' }); + await test("Workflow: 删除", async () => { + await request(`/v1/workflows/${workflowId}`, { method: "DELETE" }); }); } // Tool API测试 let toolId; - await test('Tool: 创建', async () => { - const result = await request('/v1/tools', { - method: 'POST', - body: { name: 'Test Tool', type: 'custom', schema: { type: 'object' } } + await test("Tool: 创建", async () => { + const result = await request("/v1/tools", { + method: "POST", + body: { name: "Test Tool", type: "custom", schema: { type: "object" } }, }); toolId = result.data.id; }); if (toolId) { - await test('Tool: 执行', async () => { + await test("Tool: 执行", async () => { await request(`/v1/tools/${toolId}/execute`, { - method: 'POST', - body: { input: {} } + method: "POST", + body: { input: {} }, }); }); - await test('Tool: 删除', async () => { - await request(`/v1/tools/${toolId}`, { method: 'DELETE' }); + await test("Tool: 删除", async () => { + await request(`/v1/tools/${toolId}`, { method: "DELETE" }); }); } // MCP API测试 let mcpId; - await test('MCP: 创建服务器', async () => { - const result = await request('/v1/mcp/servers', { - method: 'POST', - body: { name: 'Test', type: 'stdio', command: 'node' } + await test("MCP: 创建服务器", async () => { + const result = await request("/v1/mcp/servers", { + method: "POST", + body: { name: "Test", type: "stdio", command: "node" }, }); mcpId = result.data.id; }); if (mcpId) { - await test('MCP: 启动', async () => { - await request(`/v1/mcp/servers/${mcpId}/start`, { method: 'POST' }); + await test("MCP: 启动", async () => { + await request(`/v1/mcp/servers/${mcpId}/start`, { method: "POST" }); }); - await test('MCP: 停止', async () => { - await request(`/v1/mcp/servers/${mcpId}/stop`, { method: 'POST' }); + await test("MCP: 停止", async () => { + await request(`/v1/mcp/servers/${mcpId}/stop`, { method: "POST" }); }); - await test('MCP: 删除', async () => { - await request(`/v1/mcp/servers/${mcpId}`, { method: 'DELETE' }); + await test("MCP: 删除", async () => { + await request(`/v1/mcp/servers/${mcpId}`, { method: "DELETE" }); }); } // Middleware API测试 let mwId; - await test('Middleware: 创建', async () => { - const result = await request('/v1/middlewares', { - method: 'POST', - body: { name: 'Test MW', type: 'custom', priority: 10 } + await test("Middleware: 创建", async () => { + const result = await request("/v1/middlewares", { + method: "POST", + body: { name: "Test MW", type: "custom", priority: 10 }, }); mwId = result.data.id; }); if (mwId) { - await test('Middleware: 启用', async () => { - await request(`/v1/middlewares/${mwId}/enable`, { method: 'POST' }); + await test("Middleware: 启用", async () => { + await request(`/v1/middlewares/${mwId}/enable`, { method: "POST" }); }); - await test('Middleware: 删除', async () => { - await request(`/v1/middlewares/${mwId}`, { method: 'DELETE' }); + await test("Middleware: 删除", async () => { + await request(`/v1/middlewares/${mwId}`, { method: "DELETE" }); }); } // Telemetry API测试 - await test('Telemetry: 记录 Metric', async () => { - await request('/v1/telemetry/metrics', { - method: 'POST', - body: { name: 'test', type: 'counter', value: 1 } + await test("Telemetry: 记录 Metric", async () => { + await request("/v1/telemetry/metrics", { + method: "POST", + body: { name: "test", type: "counter", value: 1 }, }); }); - await test('Telemetry: 记录 Trace', async () => { - await request('/v1/telemetry/traces', { - method: 'POST', - body: { name: 'test', span_id: 'span-1' } + await test("Telemetry: 记录 Trace", async () => { + await request("/v1/telemetry/traces", { + method: "POST", + body: { name: "test", span_id: "span-1" }, }); }); // Eval API测试 - await test('Eval: 文本评估', async () => { - await request('/v1/eval/text', { - method: 'POST', - body: { prompt: 'Test', expected: 'Test' } + await test("Eval: 文本评估", async () => { + await request("/v1/eval/text", { + method: "POST", + body: { prompt: "Test", expected: "Test" }, }); }); - await test('Eval: 批量评估', async () => { - await request('/v1/eval/batch', { - method: 'POST', - body: { items: [{ prompt: 'Test' }] } + await test("Eval: 批量评估", async () => { + await request("/v1/eval/batch", { + method: "POST", + body: { items: [{ prompt: "Test" }] }, }); }); // System API测试 - await test('System: 获取信息', async () => { - await request('/v1/system/info'); + await test("System: 获取信息", async () => { + await request("/v1/system/info"); }); - await test('System: 健康检查', async () => { - await request('/v1/system/health'); + await test("System: 健康检查", async () => { + await request("/v1/system/health"); }); - await test('System: 获取统计', async () => { - await request('/v1/system/stats'); + await test("System: 获取统计", async () => { + await request("/v1/system/stats"); }); // 打印总结 - console.log(`\n${'='.repeat(60)}`); + console.log(`\n${"=".repeat(60)}`); console.log(`📊 测试总结`); - console.log(`${'='.repeat(60)}`); + console.log(`${"=".repeat(60)}`); console.log(`总测试数: ${testsRun}`); console.log(`✅ 通过: ${testsPassed}`); console.log(`❌ 失败: ${testsFailed}`); console.log(`成功率: ${((testsPassed / testsRun) * 100).toFixed(1)}%`); - console.log(`${'='.repeat(60)}\n`); + console.log(`${"=".repeat(60)}\n`); if (testsFailed === 0) { - console.log('🎉 所有测试通过!客户端SDK与服务端API完全兼容!'); + console.log("🎉 所有测试通过!客户端SDK与服务端API完全兼容!"); process.exit(0); } else { - console.log('⚠️ 部分测试失败,请检查服务端是否正常运行'); + console.log("⚠️ 部分测试失败,请检查服务端是否正常运行"); process.exit(1); } } // 运行测试 -runTests().catch(error => { - console.error('❌ 测试运行失败:', error); +runTests().catch((error) => { + console.error("❌ 测试运行失败:", error); process.exit(1); }); diff --git a/client-sdks/client-js/tests/events/types.test.ts b/client-sdks/client-js/tests/events/types.test.ts index 9fc6c2b..f5eedd3 100644 --- a/client-sdks/client-js/tests/events/types.test.ts +++ b/client-sdks/client-js/tests/events/types.test.ts @@ -2,7 +2,7 @@ * 事件类型测试 */ -import { describe, it, expect } from 'vitest'; +import { describe, it, expect } from "vitest"; import { ProgressThinkingEvent, ProgressTextChunkEvent, @@ -22,185 +22,188 @@ import { isControlEvent, isMonitorEvent, isEventType, - StreamEvent -} from '../../src/events/types'; + StreamEvent, +} from "../../src/events/types"; -describe('Event Types', () => { - describe('Progress Events', () => { - it('should create thinking event', () => { +describe("Event Types", () => { + describe("Progress Events", () => { + it("should create thinking event", () => { const event: ProgressThinkingEvent = { - type: 'thinking', - channel: 'progress', - data: { content: 'Analyzing the question...' } + type: "thinking", + channel: "progress", + data: { content: "Analyzing the question..." }, }; - expect(event.type).toBe('thinking'); - expect(event.channel).toBe('progress'); - expect(event.data.content).toBe('Analyzing the question...'); + expect(event.type).toBe("thinking"); + expect(event.channel).toBe("progress"); + expect(event.data.content).toBe("Analyzing the question..."); }); - it('should create text chunk event', () => { + it("should create text chunk event", () => { const event: ProgressTextChunkEvent = { - type: 'text_chunk', - channel: 'progress', - data: { delta: 'Hello', text: 'Hello' } + type: "text_chunk", + channel: "progress", + data: { delta: "Hello", text: "Hello" }, }; - expect(event.type).toBe('text_chunk'); - expect(event.data.delta).toBe('Hello'); + expect(event.type).toBe("text_chunk"); + expect(event.data.delta).toBe("Hello"); }); - it('should create tool start event', () => { + it("should create tool start event", () => { const event: ProgressToolStartEvent = { - type: 'tool_start', - channel: 'progress', - data: { toolName: 'calculator', params: { operation: 'add', numbers: [1, 2] } } + type: "tool_start", + channel: "progress", + data: { + toolName: "calculator", + params: { operation: "add", numbers: [1, 2] }, + }, }; - expect(event.type).toBe('tool_start'); - expect(event.data.toolName).toBe('calculator'); + expect(event.type).toBe("tool_start"); + expect(event.data.toolName).toBe("calculator"); }); - it('should create tool end event', () => { + it("should create tool end event", () => { const event: ProgressToolEndEvent = { - type: 'tool_end', - channel: 'progress', - data: { toolName: 'calculator', result: 3 } + type: "tool_end", + channel: "progress", + data: { toolName: "calculator", result: 3 }, }; - expect(event.type).toBe('tool_end'); + expect(event.type).toBe("tool_end"); expect(event.data.result).toBe(3); }); - it('should create done event', () => { + it("should create done event", () => { const event: ProgressDoneEvent = { - type: 'done', - channel: 'progress', - data: { text: 'Task completed' } + type: "done", + channel: "progress", + data: { text: "Task completed" }, }; - expect(event.type).toBe('done'); - expect(event.data.text).toBe('Task completed'); + expect(event.type).toBe("done"); + expect(event.data.text).toBe("Task completed"); }); - it('should create error event', () => { + it("should create error event", () => { const event: ProgressErrorEvent = { - type: 'error', - channel: 'progress', - data: { error: 'Something went wrong' } + type: "error", + channel: "progress", + data: { error: "Something went wrong" }, }; - expect(event.type).toBe('error'); - expect(event.data.error).toBe('Something went wrong'); + expect(event.type).toBe("error"); + expect(event.data.error).toBe("Something went wrong"); }); }); - describe('Control Events', () => { - it('should create tool approval request event', () => { + describe("Control Events", () => { + it("should create tool approval request event", () => { const event: ControlToolApprovalRequestEvent = { - type: 'tool_approval_request', - channel: 'control', + type: "tool_approval_request", + channel: "control", data: { - approvalId: 'approval-123', - toolName: 'file_delete', - params: { path: '/important/file.txt' } - } + approvalId: "approval-123", + toolName: "file_delete", + params: { path: "/important/file.txt" }, + }, }; - expect(event.type).toBe('tool_approval_request'); - expect(event.data.approvalId).toBe('approval-123'); + expect(event.type).toBe("tool_approval_request"); + expect(event.data.approvalId).toBe("approval-123"); }); - it('should create tool approval response event', () => { + it("should create tool approval response event", () => { const event: ControlToolApprovalResponseEvent = { - type: 'tool_approval_response', - channel: 'control', - data: { approvalId: 'approval-123', approved: true } + type: "tool_approval_response", + channel: "control", + data: { approvalId: "approval-123", approved: true }, }; - expect(event.type).toBe('tool_approval_response'); + expect(event.type).toBe("tool_approval_response"); expect(event.data.approved).toBe(true); }); - it('should create pause event', () => { + it("should create pause event", () => { const event: ControlPauseEvent = { - type: 'pause', - channel: 'control', - data: { reason: 'User requested pause' } + type: "pause", + channel: "control", + data: { reason: "User requested pause" }, }; - expect(event.type).toBe('pause'); - expect(event.data.reason).toBe('User requested pause'); + expect(event.type).toBe("pause"); + expect(event.data.reason).toBe("User requested pause"); }); - it('should create resume event', () => { + it("should create resume event", () => { const event: ControlResumeEvent = { - type: 'resume', - channel: 'control', - data: { timestamp: '2024-01-01T00:00:00Z' } + type: "resume", + channel: "control", + data: { timestamp: "2024-01-01T00:00:00Z" }, }; - expect(event.type).toBe('resume'); - expect(event.data.timestamp).toBe('2024-01-01T00:00:00Z'); + expect(event.type).toBe("resume"); + expect(event.data.timestamp).toBe("2024-01-01T00:00:00Z"); }); }); - describe('Monitor Events', () => { - it('should create token usage event', () => { + describe("Monitor Events", () => { + it("should create token usage event", () => { const event: MonitorTokenUsageEvent = { - type: 'token_usage', - channel: 'monitor', + type: "token_usage", + channel: "monitor", data: { promptTokens: 100, completionTokens: 50, - totalTokens: 150 - } + totalTokens: 150, + }, }; - expect(event.type).toBe('token_usage'); + expect(event.type).toBe("token_usage"); expect(event.data.totalTokens).toBe(150); }); - it('should create latency event', () => { + it("should create latency event", () => { const event: MonitorLatencyEvent = { - type: 'latency', - channel: 'monitor', - data: { latencyMs: 250, operation: 'chat' } + type: "latency", + channel: "monitor", + data: { latencyMs: 250, operation: "chat" }, }; - expect(event.type).toBe('latency'); + expect(event.type).toBe("latency"); expect(event.data.latencyMs).toBe(250); }); - it('should create cost event', () => { + it("should create cost event", () => { const event: MonitorCostEvent = { - type: 'cost', - channel: 'monitor', - data: { cost: 0.05, currency: 'USD' } + type: "cost", + channel: "monitor", + data: { cost: 0.05, currency: "USD" }, }; - expect(event.type).toBe('cost'); + expect(event.type).toBe("cost"); expect(event.data.cost).toBe(0.05); }); - it('should create compliance event', () => { + it("should create compliance event", () => { const event: MonitorComplianceEvent = { - type: 'compliance', - channel: 'monitor', - data: { passed: true, details: 'All checks passed' } + type: "compliance", + channel: "monitor", + data: { passed: true, details: "All checks passed" }, }; - expect(event.type).toBe('compliance'); + expect(event.type).toBe("compliance"); expect(event.data.passed).toBe(true); }); }); - describe('Type Guards', () => { - it('should identify progress events', () => { + describe("Type Guards", () => { + it("should identify progress events", () => { const event: StreamEvent = { - type: 'thinking', - channel: 'progress', - data: { content: 'test' } + type: "thinking", + channel: "progress", + data: { content: "test" }, }; expect(isProgressEvent(event)).toBe(true); @@ -208,11 +211,11 @@ describe('Event Types', () => { expect(isMonitorEvent(event)).toBe(false); }); - it('should identify control events', () => { + it("should identify control events", () => { const event: StreamEvent = { - type: 'pause', - channel: 'control', - data: { reason: 'test' } + type: "pause", + channel: "control", + data: { reason: "test" }, }; expect(isProgressEvent(event)).toBe(false); @@ -220,11 +223,11 @@ describe('Event Types', () => { expect(isMonitorEvent(event)).toBe(false); }); - it('should identify monitor events', () => { + it("should identify monitor events", () => { const event: StreamEvent = { - type: 'token_usage', - channel: 'monitor', - data: { promptTokens: 10, completionTokens: 5, totalTokens: 15 } + type: "token_usage", + channel: "monitor", + data: { promptTokens: 10, completionTokens: 5, totalTokens: 15 }, }; expect(isProgressEvent(event)).toBe(false); @@ -232,23 +235,23 @@ describe('Event Types', () => { expect(isMonitorEvent(event)).toBe(true); }); - it('should identify specific event types', () => { + it("should identify specific event types", () => { const thinkingEvent: StreamEvent = { - type: 'thinking', - channel: 'progress', - data: { content: 'test' } + type: "thinking", + channel: "progress", + data: { content: "test" }, }; const pauseEvent: StreamEvent = { - type: 'pause', - channel: 'control', - data: { reason: 'test' } + type: "pause", + channel: "control", + data: { reason: "test" }, }; - expect(isEventType(thinkingEvent, 'thinking')).toBe(true); - expect(isEventType(thinkingEvent, 'pause')).toBe(false); - expect(isEventType(pauseEvent, 'pause')).toBe(true); - expect(isEventType(pauseEvent, 'thinking')).toBe(false); + expect(isEventType(thinkingEvent, "thinking")).toBe(true); + expect(isEventType(thinkingEvent, "pause")).toBe(false); + expect(isEventType(pauseEvent, "pause")).toBe(true); + expect(isEventType(pauseEvent, "thinking")).toBe(false); }); }); }); diff --git a/client-sdks/client-js/tests/integration.test.ts b/client-sdks/client-js/tests/integration.test.ts index 619d171..36f2f53 100644 --- a/client-sdks/client-js/tests/integration.test.ts +++ b/client-sdks/client-js/tests/integration.test.ts @@ -2,348 +2,345 @@ * 完整集成测试 - 验证所有174个API端点 */ -import { describe, it, expect, beforeAll } from 'vitest'; -import { AsterClient } from '../src/client'; +import { describe, it, expect, beforeAll } from "vitest"; +import { AsterClient } from "../src/client"; -const BASE_URL = process.env.API_URL || 'http://localhost:8080'; +const BASE_URL = process.env.API_URL || "http://localhost:8080"; -describe('AsterClient 完整功能测试', () => { +describe("AsterClient 完整功能测试", () => { let client: AsterClient; beforeAll(() => { client = new AsterClient({ - baseUrl: BASE_URL + baseUrl: BASE_URL, }); }); - describe('Agent API (18个端点)', () => { + describe("Agent API (18个端点)", () => { let agentId: string; - it('应该创建 Agent', async () => { + it("应该创建 Agent", async () => { const agent = await client.agents.create({ - name: 'Test Agent', - templateId: 'default', - llmProvider: 'openai', - llmModel: 'gpt-4', - systemPrompt: 'You are a helpful assistant' + name: "Test Agent", + templateId: "default", + llmProvider: "openai", + llmModel: "gpt-4", + systemPrompt: "You are a helpful assistant", }); expect(agent.id).toBeDefined(); agentId = agent.id; }); - it('应该列出所有 Agents', async () => { + it("应该列出所有 Agents", async () => { const result = await client.agents.list(); expect(result.items).toBeDefined(); expect(Array.isArray(result.items)).toBe(true); }); - it('应该获取 Agent 详情', async () => { + it("应该获取 Agent 详情", async () => { const agent = await client.agents.get(agentId); expect(agent.id).toBe(agentId); }); - it('应该更新 Agent', async () => { + it("应该更新 Agent", async () => { const updated = await client.agents.update(agentId, { - name: 'Updated Agent' + name: "Updated Agent", }); - expect(updated.name).toBe('Updated Agent'); + expect(updated.name).toBe("Updated Agent"); }); - it('应该激活 Agent', async () => { + it("应该激活 Agent", async () => { const result = await client.agents.activate(agentId); - expect(result.status).toBe('active'); + expect(result.status).toBe("active"); }); - it('应该删除 Agent', async () => { + it("应该删除 Agent", async () => { await client.agents.delete(agentId); }); }); - describe('Session API (18个端点)', () => { + describe("Session API (18个端点)", () => { let sessionId: string; let testAgentId: string; - it('应该创建 Session', async () => { + it("应该创建 Session", async () => { // 先创建一个测试用 Agent const agent = await client.agents.create({ - name: 'Session Test Agent', - templateId: 'default', - llmProvider: 'openai', - llmModel: 'gpt-4' + name: "Session Test Agent", + templateId: "default", + llmProvider: "openai", + llmModel: "gpt-4", }); testAgentId = agent.id; - + const session = await client.sessions.create({ - agentId: testAgentId + agentId: testAgentId, }); expect(session.id).toBeDefined(); sessionId = session.id; }); - it('应该列出所有 Sessions', async () => { + it("应该列出所有 Sessions", async () => { const sessions = await client.sessions.list(); expect(Array.isArray(sessions)).toBe(true); }); - it('应该添加消息', async () => { + it("应该添加消息", async () => { const message = await client.sessions.addMessage(sessionId, { - role: 'user', - content: 'Hello!' + role: "user", + content: "Hello!", }); - expect(message.content).toBe('Hello!'); + expect(message.content).toBe("Hello!"); }); - it('应该创建 Checkpoint', async () => { + it("应该创建 Checkpoint", async () => { const checkpoint = await client.sessions.createCheckpoint(sessionId); expect(checkpoint.id).toBeDefined(); }); - it('应该删除 Session', async () => { + it("应该删除 Session", async () => { await client.sessions.delete(sessionId); }); }); - describe('Memory API (18个端点)', () => { - it('应该创建 Working Memory', async () => { - const memory = await client.memory.working.set('test_key', { - data: 'test_value' + describe("Memory API (18个端点)", () => { + it("应该创建 Working Memory", async () => { + const memory = await client.memory.working.set("test_key", { + data: "test_value", }); expect(memory).toBeDefined(); }); - it('应该获取 Working Memory', async () => { - const memory = await client.memory.working.get('test_key'); + it("应该获取 Working Memory", async () => { + const memory = await client.memory.working.get("test_key"); expect(memory.value).toBeDefined(); }); - it('应该创建 Semantic Memory', async () => { + it("应该创建 Semantic Memory", async () => { const memory = await client.memory.semantic.create({ - content: 'Test semantic memory', - tags: ['test'] + content: "Test semantic memory", + tags: ["test"], }); expect(memory.id).toBeDefined(); }); - it('应该列出 Semantic Memories', async () => { + it("应该列出 Semantic Memories", async () => { const memories = await client.memory.semantic.list(); expect(Array.isArray(memories)).toBe(true); }); }); - describe('Workflow API (12个端点)', () => { + describe("Workflow API (12个端点)", () => { let workflowId: string; - it('应该创建 Workflow', async () => { + it("应该创建 Workflow", async () => { const workflow = await client.workflows.create({ - type: 'sequential', - name: 'Test Workflow', - steps: [ - { agent: 'test-agent', action: 'process', params: {} } - ] + type: "sequential", + name: "Test Workflow", + steps: [{ agent: "test-agent", action: "process", params: {} }], }); expect(workflow.id).toBeDefined(); workflowId = workflow.id; }); - it('应该执行 Workflow', async () => { - const execution = await client.workflows.execute(workflowId, { input: {} }); + it("应该执行 Workflow", async () => { + const execution = await client.workflows.execute(workflowId, { + input: {}, + }); expect(execution.id).toBeDefined(); }); - it('应该获取执行记录', async () => { + it("应该获取执行记录", async () => { const executions = await client.workflows.listExecutions(workflowId); expect(Array.isArray(executions)).toBe(true); }); - it('应该删除 Workflow', async () => { + it("应该删除 Workflow", async () => { await client.workflows.delete(workflowId); }); }); - describe('Tool API (16个端点)', () => { + describe("Tool API (16个端点)", () => { let toolName: string; - it('应该创建 Tool', async () => { + it("应该创建 Tool", async () => { const tool = await client.tools.create({ - name: 'test_tool', - type: 'custom', - schema: { type: 'object' } + name: "test_tool", + type: "custom", + schema: { type: "object" }, }); expect(tool.name).toBeDefined(); toolName = tool.name; }); - it('应该列出所有 Tools', async () => { + it("应该列出所有 Tools", async () => { const tools = await client.tools.list(); expect(Array.isArray(tools)).toBe(true); }); - it('应该执行 Tool', async () => { - const result = await client.tools.execute(toolName, { test: 'data' }); + it("应该执行 Tool", async () => { + const result = await client.tools.execute(toolName, { test: "data" }); expect(result).toBeDefined(); }); - it('应该删除 Tool', async () => { + it("应该删除 Tool", async () => { await client.tools.delete(toolName); }); }); - describe('MCP API (16个端点)', () => { + describe("MCP API (16个端点)", () => { let serverId: string; - it('应该创建 MCP Server', async () => { + it("应该创建 MCP Server", async () => { const server = await client.mcp.createServer({ - serverId: 'test-mcp-server', - name: 'Test Server', - endpoint: 'http://localhost:3000' + serverId: "test-mcp-server", + name: "Test Server", + endpoint: "http://localhost:3000", }); expect(server.serverId).toBeDefined(); serverId = server.serverId; }); - it('应该列出所有 MCP Servers', async () => { + it("应该列出所有 MCP Servers", async () => { const servers = await client.mcp.listServers(); expect(Array.isArray(servers)).toBe(true); }); - it.skip('应该启动 MCP Server - TODO: 等待后端实现 connect 功能', async () => { + it.skip("应该启动 MCP Server - TODO: 等待后端实现 connect 功能", async () => { const result = await client.mcp.startServer(serverId); - expect(result.status).toBe('running'); + expect(result.status).toBe("running"); }); - it.skip('应该停止 MCP Server - TODO: 等待后端实现 disconnect 功能', async () => { + it.skip("应该停止 MCP Server - TODO: 等待后端实现 disconnect 功能", async () => { const result = await client.mcp.stopServer(serverId); - expect(result.status).toBe('stopped'); + expect(result.status).toBe("stopped"); }); - it('应该删除 MCP Server', async () => { + it("应该删除 MCP Server", async () => { await client.mcp.deleteServer(serverId); }); }); - describe('Middleware API (14个端点)', () => { + describe("Middleware API (14个端点)", () => { let middlewareName: string; - it('应该创建 Middleware', async () => { + it("应该创建 Middleware", async () => { const mw = await client.middleware.create({ - name: 'test_middleware', - type: 'custom', - priority: 10 + name: "test_middleware", + type: "custom", + priority: 10, }); expect(mw.name).toBeDefined(); middlewareName = mw.name; }); - it('应该列出所有 Middlewares', async () => { + it("应该列出所有 Middlewares", async () => { const middlewares = await client.middleware.list(); expect(Array.isArray(middlewares)).toBe(true); }); - it('应该启用 Middleware', async () => { + it("应该启用 Middleware", async () => { await client.middleware.enable(middlewareName); // enable 返回 void }); - it('应该禁用 Middleware', async () => { + it("应该禁用 Middleware", async () => { await client.middleware.disable(middlewareName); // disable 返回 void }); - it('应该删除 Middleware', async () => { + it("应该删除 Middleware", async () => { await client.middleware.delete(middlewareName); }); }); - describe('Telemetry API (20个端点)', () => { - it('应该记录 Metric', async () => { + describe("Telemetry API (20个端点)", () => { + it("应该记录 Metric", async () => { await client.telemetry.recordMetric({ - name: 'test_metric', - type: 'counter', - value: 1 + name: "test_metric", + type: "counter", + value: 1, }); // recordMetric 返回 void }); - it('应该列出 Metrics', async () => { + it("应该列出 Metrics", async () => { const metrics = await client.telemetry.listMetrics(); expect(Array.isArray(metrics)).toBe(true); }); - it('应该记录 Trace', async () => { + it("应该记录 Trace", async () => { await client.telemetry.recordTrace({ - name: 'test_trace', - span_id: 'span-123' + name: "test_trace", + span_id: "span-123", }); // recordTrace 返回 void }); - it('应该列出 Traces', async () => { + it("应该列出 Traces", async () => { const traces = await client.telemetry.listTraces(); expect(Array.isArray(traces)).toBe(true); }); - it('应该获取健康状态', async () => { + it("应该获取健康状态", async () => { const health = await client.telemetry.healthCheck(); expect(health.status).toBeDefined(); }); }); - describe('Eval API (20个端点)', () => { - it.skip('应该运行文本评估 - TODO: 等待后端实现 POST /v1/evals', async () => { + describe("Eval API (20个端点)", () => { + it.skip("应该运行文本评估 - TODO: 等待后端实现 POST /v1/evals", async () => { const result = await client.evals.runTextEval({ - prompt: 'What is AI?', - expected: 'Artificial Intelligence' + prompt: "What is AI?", + expected: "Artificial Intelligence", }); expect(result.score).toBeDefined(); }); - it.skip('应该运行批量评估 - TODO: 等待后端实现 POST /v1/evals', async () => { + it.skip("应该运行批量评估 - TODO: 等待后端实现 POST /v1/evals", async () => { const result = await client.evals.runBatchEval({ - items: [ - { prompt: 'Test 1' }, - { prompt: 'Test 2' } - ] + items: [{ prompt: "Test 1" }, { prompt: "Test 2" }], }); expect(result.id).toBeDefined(); }); - it.skip('应该列出所有评估 - TODO: 等待后端实现 GET /v1/evals', async () => { + it.skip("应该列出所有评估 - TODO: 等待后端实现 GET /v1/evals", async () => { const evals = await client.evals.list(); expect(Array.isArray(evals)).toBe(true); }); let benchmarkId: string; - it.skip('应该创建 Benchmark - TODO: 等待后端实现 POST /v1/evals/benchmark', async () => { + it.skip("应该创建 Benchmark - TODO: 等待后端实现 POST /v1/evals/benchmark", async () => { const benchmark = await client.evals.createBenchmark({ - name: 'Test Benchmark', - runs: 10 + name: "Test Benchmark", + runs: 10, }); expect(benchmark.id).toBeDefined(); benchmarkId = benchmark.id; }); - it.skip('应该删除 Benchmark - TODO: 等待后端实现 DELETE /v1/evals/benchmark/:id', async () => { + it.skip("应该删除 Benchmark - TODO: 等待后端实现 DELETE /v1/evals/benchmark/:id", async () => { await client.evals.deleteBenchmark(benchmarkId); }); }); - describe('System API (10个端点)', () => { - it('应该获取系统信息', async () => { + describe("System API (10个端点)", () => { + it("应该获取系统信息", async () => { const info = await client.system.getInfo(); expect(info.version).toBeDefined(); }); - it('应该获取健康状态', async () => { + it("应该获取健康状态", async () => { const health = await client.system.getHealth(); expect(health.status).toBeDefined(); }); - it('应该获取统计信息', async () => { + it("应该获取统计信息", async () => { const stats = await client.system.getStats(); expect(stats.requests_total).toBeDefined(); }); - it('应该列出配置', async () => { + it("应该列出配置", async () => { const configs = await client.system.listConfig(); expect(Array.isArray(configs)).toBe(true); }); diff --git a/client-sdks/client-js/tests/integration/client.test.ts b/client-sdks/client-js/tests/integration/client.test.ts index 943ca29..b35644a 100644 --- a/client-sdks/client-js/tests/integration/client.test.ts +++ b/client-sdks/client-js/tests/integration/client.test.ts @@ -3,8 +3,8 @@ * 测试所有模块的交互和集成 */ -import { describe, it, expect, beforeEach, vi } from 'vitest'; -import { AsterClient } from '../../src/client'; +import { describe, it, expect, beforeEach, vi } from "vitest"; +import { AsterClient } from "../../src/client"; // Mock fetch global.fetch = vi.fn(); @@ -14,19 +14,19 @@ function mockResponse(data: any) { return { ok: true, json: async () => data, - text: async () => JSON.stringify(data) + text: async () => JSON.stringify(data), }; } -describe('AsterClient Client Integration', () => { +describe("AsterClient Client Integration", () => { let client: AsterClient; beforeEach(() => { vi.clearAllMocks(); client = new AsterClient({ - baseUrl: 'http://localhost:8080', - apiKey: 'test-api-key', - timeout: 30000 + baseUrl: "http://localhost:8080", + apiKey: "test-api-key", + timeout: 30000, }); }); @@ -34,8 +34,8 @@ describe('AsterClient Client Integration', () => { // 客户端初始化测试 // ========================================================================== - describe('Client Initialization', () => { - it('should initialize with all resource modules', () => { + describe("Client Initialization", () => { + it("should initialize with all resource modules", () => { expect(client.memory).toBeDefined(); expect(client.sessions).toBeDefined(); expect(client.workflows).toBeDefined(); @@ -45,11 +45,11 @@ describe('AsterClient Client Integration', () => { expect(client.telemetry).toBeDefined(); }); - it('should have convenience methods', () => { - expect(typeof client.healthCheck).toBe('function'); - expect(typeof client.getStatus).toBe('function'); - expect(typeof client.getUsageStatistics).toBe('function'); - expect(typeof client.getPerformanceMetrics).toBe('function'); + it("should have convenience methods", () => { + expect(typeof client.healthCheck).toBe("function"); + expect(typeof client.getStatus).toBe("function"); + expect(typeof client.getUsageStatistics).toBe("function"); + expect(typeof client.getPerformanceMetrics).toBe("function"); }); }); @@ -57,63 +57,72 @@ describe('AsterClient Client Integration', () => { // Memory + Session 集成测试 // ========================================================================== - describe('Memory + Session Integration', () => { - it('should create session and use working memory', async () => { + describe("Memory + Session Integration", () => { + it("should create session and use working memory", async () => { // Mock session creation - (global.fetch as any).mockResolvedValueOnce(mockResponse({ - id: 'session-123', - agentId: 'agent-1', - status: 'active', - createdAt: new Date().toISOString() - })); + (global.fetch as any).mockResolvedValueOnce( + mockResponse({ + id: "session-123", + agentId: "agent-1", + status: "active", + createdAt: new Date().toISOString(), + }), + ); const session = await client.sessions.create({ - agentId: 'agent-1', - templateId: 'chat', - userId: 'user-1' + agentId: "agent-1", + templateId: "chat", + userId: "user-1", }); - expect(session.id).toBe('session-123'); + expect(session.id).toBe("session-123"); // Mock working memory set (global.fetch as any).mockResolvedValueOnce(mockResponse({})); - await client.memory.working.set('session_context', { - sessionId: session.id, - userId: 'user-1' - }, { - scope: 'thread' - }); + await client.memory.working.set( + "session_context", + { + sessionId: session.id, + userId: "user-1", + }, + { + scope: "thread", + }, + ); expect(global.fetch).toHaveBeenCalledTimes(2); }); - it('should use semantic memory for session context', async () => { + it("should use semantic memory for session context", async () => { // Mock semantic memory store - (global.fetch as any).mockResolvedValueOnce(mockResponse({ - id: 'chunk-1', - content: 'User preference: dark theme' - })); - - await client.memory.semantic.store( - 'User prefers dark theme', - { sessionId: 'session-123' } + (global.fetch as any).mockResolvedValueOnce( + mockResponse({ + id: "chunk-1", + content: "User preference: dark theme", + }), ); + await client.memory.semantic.store("User prefers dark theme", { + sessionId: "session-123", + }); + // Mock semantic search - (global.fetch as any).mockResolvedValueOnce(mockResponse({ - chunks: [ - { - id: 'chunk-1', - content: 'User preference: dark theme', - similarity: 0.95 - } - ] - })); + (global.fetch as any).mockResolvedValueOnce( + mockResponse({ + chunks: [ + { + id: "chunk-1", + content: "User preference: dark theme", + similarity: 0.95, + }, + ], + }), + ); const results = await client.memory.semantic.search( - 'What is the user preference?', - { limit: 5 } + "What is the user preference?", + { limit: 5 }, ); expect(results.length).toBeGreaterThan(0); @@ -125,37 +134,41 @@ describe('AsterClient Client Integration', () => { // Workflow + Tool 集成测试 // ========================================================================== - describe('Workflow + Tool Integration', () => { - it('should create workflow and execute tools', async () => { + describe("Workflow + Tool Integration", () => { + it("should create workflow and execute tools", async () => { // Mock workflow creation - (global.fetch as any).mockResolvedValueOnce(mockResponse({ - id: 'workflow-1', - type: 'sequential', - name: 'Tool Pipeline', - status: 'active' - })); + (global.fetch as any).mockResolvedValueOnce( + mockResponse({ + id: "workflow-1", + type: "sequential", + name: "Tool Pipeline", + status: "active", + }), + ); const workflow = await client.workflows.create({ - type: 'sequential', - name: 'Tool Pipeline', - description: 'Execute tools in sequence', + type: "sequential", + name: "Tool Pipeline", + description: "Execute tools in sequence", steps: [ - { agent: 'reader', action: 'read_file' }, - { agent: 'processor', action: 'process_data' } - ] + { agent: "reader", action: "read_file" }, + { agent: "processor", action: "process_data" }, + ], }); - expect(workflow.id).toBe('workflow-1'); + expect(workflow.id).toBe("workflow-1"); // Mock tool execution - (global.fetch as any).mockResolvedValueOnce(mockResponse({ - success: true, - result: 'file content', - executionTime: 150 - })); - - const toolResult = await client.tools.execute('file_read', { - path: '/tmp/test.txt' + (global.fetch as any).mockResolvedValueOnce( + mockResponse({ + success: true, + result: "file content", + executionTime: 150, + }), + ); + + const toolResult = await client.tools.execute("file_read", { + path: "/tmp/test.txt", }); expect(toolResult.success).toBe(true); @@ -167,35 +180,39 @@ describe('AsterClient Client Integration', () => { // MCP + Middleware 集成测试 // ========================================================================== - describe('MCP + Middleware Integration', () => { - it('should add MCP server and configure middleware', async () => { + describe("MCP + Middleware Integration", () => { + it("should add MCP server and configure middleware", async () => { // Mock MCP server addition - (global.fetch as any).mockResolvedValueOnce(mockResponse({ - serverId: 'mcp-1', - name: 'Test Server', - status: 'connected', - toolCount: 5 - })); + (global.fetch as any).mockResolvedValueOnce( + mockResponse({ + serverId: "mcp-1", + name: "Test Server", + status: "connected", + toolCount: 5, + }), + ); const server = await client.mcp.addServer({ - serverId: 'mcp-1', - name: 'Test Server', - endpoint: 'http://localhost:9000/mcp' + serverId: "mcp-1", + name: "Test Server", + endpoint: "http://localhost:9000/mcp", }); - expect(server.serverId).toBe('mcp-1'); + expect(server.serverId).toBe("mcp-1"); // Mock middleware config update - (global.fetch as any).mockResolvedValueOnce(mockResponse({ - name: 'tool_approval', - enabled: true, - config: { - approvalRequired: ['bash', 'file_delete'] - } - })); - - await client.middleware.updateConfig('tool_approval', { - approvalRequired: ['bash', 'file_delete'] + (global.fetch as any).mockResolvedValueOnce( + mockResponse({ + name: "tool_approval", + enabled: true, + config: { + approvalRequired: ["bash", "file_delete"], + }, + }), + ); + + await client.middleware.updateConfig("tool_approval", { + approvalRequired: ["bash", "file_delete"], }); expect(global.fetch).toHaveBeenCalledTimes(2); @@ -206,67 +223,73 @@ describe('AsterClient Client Integration', () => { // Telemetry 监控测试 // ========================================================================== - describe('Telemetry Monitoring', () => { - it('should check health and get performance metrics', async () => { + describe("Telemetry Monitoring", () => { + it("should check health and get performance metrics", async () => { // Mock health check - (global.fetch as any).mockResolvedValueOnce(mockResponse({ - status: 'healthy', - timestamp: new Date().toISOString(), - components: { - database: { status: 'healthy' }, - memory: { status: 'healthy' } - } - })); + (global.fetch as any).mockResolvedValueOnce( + mockResponse({ + status: "healthy", + timestamp: new Date().toISOString(), + components: { + database: { status: "healthy" }, + memory: { status: "healthy" }, + }, + }), + ); const health = await client.healthCheck(); - expect(health.status).toBe('healthy'); + expect(health.status).toBe("healthy"); // Mock performance metrics - (global.fetch as any).mockResolvedValueOnce(mockResponse({ - timeRange: { - start: '2024-01-01T00:00:00Z', - end: '2024-01-02T00:00:00Z' - }, - requests: { - total: 1000, - successful: 950, - failed: 50, - avgLatency: 120, - p95Latency: 250, - p99Latency: 500 - } - })); + (global.fetch as any).mockResolvedValueOnce( + mockResponse({ + timeRange: { + start: "2024-01-01T00:00:00Z", + end: "2024-01-02T00:00:00Z", + }, + requests: { + total: 1000, + successful: 950, + failed: 50, + avgLatency: 120, + p95Latency: 250, + p99Latency: 500, + }, + }), + ); const perf = await client.getPerformanceMetrics(); expect(perf.requests.total).toBe(1000); expect(global.fetch).toHaveBeenCalledTimes(2); }); - it('should get usage statistics', async () => { + it("should get usage statistics", async () => { // Mock usage statistics - (global.fetch as any).mockResolvedValueOnce(mockResponse({ - timeRange: { - start: '2024-01-01T00:00:00Z', - end: '2024-01-08T00:00:00Z' - }, - sessions: { - total: 500, - active: 50, - avgDuration: 3600 - }, - workflows: { - total: 200, - successful: 180, - failed: 20 - }, - tools: { - total: 1000, - topTools: [ - { toolName: 'bash', callCount: 300 }, - { toolName: 'http_request', callCount: 250 } - ] - } - })); + (global.fetch as any).mockResolvedValueOnce( + mockResponse({ + timeRange: { + start: "2024-01-01T00:00:00Z", + end: "2024-01-08T00:00:00Z", + }, + sessions: { + total: 500, + active: 50, + avgDuration: 3600, + }, + workflows: { + total: 200, + successful: 180, + failed: 20, + }, + tools: { + total: 1000, + topTools: [ + { toolName: "bash", callCount: 300 }, + { toolName: "http_request", callCount: 250 }, + ], + }, + }), + ); const usage = await client.getUsageStatistics(); expect(usage.sessions?.total).toBe(500); @@ -278,72 +301,82 @@ describe('AsterClient Client Integration', () => { // 完整工作流测试 // ========================================================================== - describe('Complete Workflow', () => { - it('should execute a complete workflow from start to finish', async () => { + describe("Complete Workflow", () => { + it("should execute a complete workflow from start to finish", async () => { // 1. Create session - (global.fetch as any).mockResolvedValueOnce(mockResponse({ - id: 'session-1', - agentId: 'agent-1', - status: 'active' - })); + (global.fetch as any).mockResolvedValueOnce( + mockResponse({ + id: "session-1", + agentId: "agent-1", + status: "active", + }), + ); const session = await client.sessions.create({ - agentId: 'agent-1', - templateId: 'chat', - userId: 'user-1', - enableCheckpoints: true + agentId: "agent-1", + templateId: "chat", + userId: "user-1", + enableCheckpoints: true, }); // 2. Set working memory (global.fetch as any).mockResolvedValueOnce(mockResponse({})); - await client.memory.working.set('context', { - sessionId: session.id + await client.memory.working.set("context", { + sessionId: session.id, }); // 3. Create and execute workflow - (global.fetch as any).mockResolvedValueOnce(mockResponse({ - id: 'workflow-1', - type: 'parallel', - name: 'Research', - status: 'active' - })); + (global.fetch as any).mockResolvedValueOnce( + mockResponse({ + id: "workflow-1", + type: "parallel", + name: "Research", + status: "active", + }), + ); const workflow = await client.workflows.create({ - type: 'parallel', - name: 'Research', + type: "parallel", + name: "Research", agents: [ - { id: 'researcher-1', task: 'Research AI' }, - { id: 'researcher-2', task: 'Research ML' } + { id: "researcher-1", task: "Research AI" }, + { id: "researcher-2", task: "Research ML" }, ], - maxConcurrency: 2 + maxConcurrency: 2, }); - (global.fetch as any).mockResolvedValueOnce(mockResponse({ - id: 'run-1', - workflowId: workflow.id, - status: 'running', - progress: 0 - })); + (global.fetch as any).mockResolvedValueOnce( + mockResponse({ + id: "run-1", + workflowId: workflow.id, + status: "running", + progress: 0, + }), + ); const run = await client.workflows.execute(workflow.id, { - input: 'Start research' + input: "Start research", }); // 4. Get telemetry - (global.fetch as any).mockResolvedValueOnce(mockResponse({ - status: 'healthy', - timestamp: new Date().toISOString(), - components: {} - })); + (global.fetch as any).mockResolvedValueOnce( + mockResponse({ + status: "healthy", + timestamp: new Date().toISOString(), + components: {}, + }), + ); await client.healthCheck(); // 5. Complete session - (global.fetch as any).mockResolvedValueOnce(mockResponse({ - id: session.id, - status: 'completed' - })); + (global.fetch as any).mockResolvedValueOnce( + mockResponse({ + id: session.id, + status: "completed", + }), + ); await client.sessions.complete(session.id); diff --git a/client-sdks/client-js/tests/resources/memory.test.ts b/client-sdks/client-js/tests/resources/memory.test.ts index 7c5d0a0..f9e1469 100644 --- a/client-sdks/client-js/tests/resources/memory.test.ts +++ b/client-sdks/client-js/tests/resources/memory.test.ts @@ -2,454 +2,499 @@ * Memory 资源类测试 */ -import { describe, it, expect, beforeEach, vi } from 'vitest'; -import { MemoryResource } from '../../src/resources/memory'; -import type { ClientOptions } from '../../src/resources/base'; +import { describe, it, expect, beforeEach, vi } from "vitest"; +import { MemoryResource } from "../../src/resources/memory"; +import type { ClientOptions } from "../../src/resources/base"; -describe('MemoryResource', () => { +describe("MemoryResource", () => { let memory: MemoryResource; let mockFetch: ReturnType; beforeEach(() => { // Mock fetch mockFetch = vi.fn(); - + const options: ClientOptions = { - baseUrl: 'http://localhost:8080', - fetchImpl: mockFetch as any + baseUrl: "http://localhost:8080", + fetchImpl: mockFetch as any, }; memory = new MemoryResource(options); }); - describe('Working Memory', () => { - describe('set', () => { - it('should set working memory with default scope', async () => { + describe("Working Memory", () => { + describe("set", () => { + it("should set working memory with default scope", async () => { mockFetch.mockResolvedValueOnce({ ok: true, status: 200, - text: async () => JSON.stringify({}) + text: async () => JSON.stringify({}), }); - await memory.working.set('user_preference', { - theme: 'dark', - language: 'zh-CN' + await memory.working.set("user_preference", { + theme: "dark", + language: "zh-CN", }); expect(mockFetch).toHaveBeenCalledWith( - 'http://localhost:8080/v1/memory/working', + "http://localhost:8080/v1/memory/working", expect.objectContaining({ - method: 'PUT', + method: "PUT", body: JSON.stringify({ - key: 'user_preference', - value: { theme: 'dark', language: 'zh-CN' }, - scope: 'thread' - }) - }) + key: "user_preference", + value: { theme: "dark", language: "zh-CN" }, + scope: "thread", + }), + }), ); }); - it('should set working memory with custom scope', async () => { + it("should set working memory with custom scope", async () => { mockFetch.mockResolvedValueOnce({ ok: true, status: 200, - text: async () => JSON.stringify({}) + text: async () => JSON.stringify({}), }); - await memory.working.set('global_config', { version: '1.0' }, { - scope: 'resource', - ttl: 3600 - }); + await memory.working.set( + "global_config", + { version: "1.0" }, + { + scope: "resource", + ttl: 3600, + }, + ); expect(mockFetch).toHaveBeenCalledWith( - 'http://localhost:8080/v1/memory/working', + "http://localhost:8080/v1/memory/working", expect.objectContaining({ - method: 'PUT', + method: "PUT", body: JSON.stringify({ - key: 'global_config', - value: { version: '1.0' }, - scope: 'resource', - ttl: 3600 - }) - }) + key: "global_config", + value: { version: "1.0" }, + scope: "resource", + ttl: 3600, + }), + }), ); }); - it('should set working memory with JSON Schema', async () => { + it("should set working memory with JSON Schema", async () => { mockFetch.mockResolvedValueOnce({ ok: true, status: 200, - text: async () => JSON.stringify({}) + text: async () => JSON.stringify({}), }); - await memory.working.set('validated_data', { count: 42 }, { - schema: { - type: 'object', - properties: { - count: { type: 'number' } + await memory.working.set( + "validated_data", + { count: 42 }, + { + schema: { + type: "object", + properties: { + count: { type: "number" }, + }, + required: ["count"], }, - required: ['count'] - } - }); + }, + ); const call = mockFetch.mock.calls[0]; const body = JSON.parse(call[1].body); expect(body.schema).toBeDefined(); - expect(body.schema.type).toBe('object'); + expect(body.schema.type).toBe("object"); }); }); - describe('get', () => { - it('should get working memory value', async () => { + describe("get", () => { + it("should get working memory value", async () => { mockFetch.mockResolvedValueOnce({ ok: true, status: 200, - text: async () => JSON.stringify({ - value: { theme: 'dark' } - }) + text: async () => + JSON.stringify({ + value: { theme: "dark" }, + }), }); - const result = await memory.working.get('user_preference'); + const result = await memory.working.get("user_preference"); - expect(result).toEqual({ theme: 'dark' }); + expect(result).toEqual({ theme: "dark" }); expect(mockFetch).toHaveBeenCalledWith( - 'http://localhost:8080/v1/memory/working/user_preference', + "http://localhost:8080/v1/memory/working/user_preference", expect.objectContaining({ - method: 'GET' - }) + method: "GET", + }), ); }); - it('should get working memory with scope', async () => { + it("should get working memory with scope", async () => { mockFetch.mockResolvedValueOnce({ ok: true, status: 200, - text: async () => JSON.stringify({ - value: { version: '1.0' } - }) + text: async () => + JSON.stringify({ + value: { version: "1.0" }, + }), }); - await memory.working.get('global_config', 'resource'); + await memory.working.get("global_config", "resource"); expect(mockFetch).toHaveBeenCalledWith( - 'http://localhost:8080/v1/memory/working/global_config?scope=resource', - expect.any(Object) + "http://localhost:8080/v1/memory/working/global_config?scope=resource", + expect.any(Object), ); }); }); - describe('delete', () => { - it('should delete working memory', async () => { + describe("delete", () => { + it("should delete working memory", async () => { mockFetch.mockResolvedValueOnce({ ok: true, status: 204, - text: async () => '' + text: async () => "", }); - await memory.working.delete('user_preference'); + await memory.working.delete("user_preference"); expect(mockFetch).toHaveBeenCalledWith( - 'http://localhost:8080/v1/memory/working/user_preference', + "http://localhost:8080/v1/memory/working/user_preference", expect.objectContaining({ - method: 'DELETE' - }) + method: "DELETE", + }), ); }); - it('should delete working memory with scope', async () => { + it("should delete working memory with scope", async () => { mockFetch.mockResolvedValueOnce({ ok: true, status: 204, - text: async () => '' + text: async () => "", }); - await memory.working.delete('global_config', 'resource'); + await memory.working.delete("global_config", "resource"); expect(mockFetch).toHaveBeenCalledWith( - 'http://localhost:8080/v1/memory/working/global_config?scope=resource', - expect.any(Object) + "http://localhost:8080/v1/memory/working/global_config?scope=resource", + expect.any(Object), ); }); }); - describe('list', () => { - it('should list all working memory', async () => { + describe("list", () => { + it("should list all working memory", async () => { mockFetch.mockResolvedValueOnce({ ok: true, status: 200, - text: async () => JSON.stringify({ - items: [ - { key: 'pref1', value: 'val1', scope: 'thread', createdAt: '2024-01-01' }, - { key: 'pref2', value: 'val2', scope: 'thread', createdAt: '2024-01-01' } - ] - }) + text: async () => + JSON.stringify({ + items: [ + { + key: "pref1", + value: "val1", + scope: "thread", + createdAt: "2024-01-01", + }, + { + key: "pref2", + value: "val2", + scope: "thread", + createdAt: "2024-01-01", + }, + ], + }), }); const result = await memory.working.list(); expect(result).toEqual({ - pref1: 'val1', - pref2: 'val2' + pref1: "val1", + pref2: "val2", }); }); - it('should list working memory by scope', async () => { + it("should list working memory by scope", async () => { mockFetch.mockResolvedValueOnce({ ok: true, status: 200, - text: async () => JSON.stringify({ - items: [ - { key: 'config1', value: 'val1', scope: 'resource', createdAt: '2024-01-01' } - ] - }) + text: async () => + JSON.stringify({ + items: [ + { + key: "config1", + value: "val1", + scope: "resource", + createdAt: "2024-01-01", + }, + ], + }), }); - await memory.working.list('resource'); + await memory.working.list("resource"); expect(mockFetch).toHaveBeenCalledWith( - 'http://localhost:8080/v1/memory/working?scope=resource', - expect.any(Object) + "http://localhost:8080/v1/memory/working?scope=resource", + expect.any(Object), ); }); }); - describe('clear', () => { - it('should clear all working memory', async () => { + describe("clear", () => { + it("should clear all working memory", async () => { mockFetch.mockResolvedValueOnce({ ok: true, status: 204, - text: async () => '' + text: async () => "", }); await memory.working.clear(); expect(mockFetch).toHaveBeenCalledWith( - 'http://localhost:8080/v1/memory/working', + "http://localhost:8080/v1/memory/working", expect.objectContaining({ - method: 'DELETE' - }) + method: "DELETE", + }), ); }); }); }); - describe('Semantic Memory', () => { - describe('search', () => { - it('should search semantic memory', async () => { + describe("Semantic Memory", () => { + describe("search", () => { + it("should search semantic memory", async () => { mockFetch.mockResolvedValueOnce({ ok: true, status: 200, - text: async () => JSON.stringify({ - chunks: [ - { - id: 'chunk-1', - content: 'Paris is the capital of France', - score: 0.95, - timestamp: '2024-01-01' - } - ], - total: 1 - }) + text: async () => + JSON.stringify({ + chunks: [ + { + id: "chunk-1", + content: "Paris is the capital of France", + score: 0.95, + timestamp: "2024-01-01", + }, + ], + total: 1, + }), }); - const results = await memory.semantic.search('capital of France'); + const results = await memory.semantic.search("capital of France"); expect(results).toHaveLength(1); - expect(results[0].content).toBe('Paris is the capital of France'); + expect(results[0].content).toBe("Paris is the capital of France"); expect(results[0].score).toBe(0.95); }); - it('should search with options', async () => { + it("should search with options", async () => { mockFetch.mockResolvedValueOnce({ ok: true, status: 200, - text: async () => JSON.stringify({ chunks: [], total: 0 }) + text: async () => JSON.stringify({ chunks: [], total: 0 }), }); - await memory.semantic.search('test query', { + await memory.semantic.search("test query", { limit: 5, threshold: 0.8, - filter: { category: 'geography' } + filter: { category: "geography" }, }); const call = mockFetch.mock.calls[0]; const body = JSON.parse(call[1].body); expect(body.limit).toBe(5); expect(body.threshold).toBe(0.8); - expect(body.filter).toEqual({ category: 'geography' }); + expect(body.filter).toEqual({ category: "geography" }); }); }); - describe('store', () => { - it('should store memory chunk', async () => { + describe("store", () => { + it("should store memory chunk", async () => { mockFetch.mockResolvedValueOnce({ ok: true, status: 200, - text: async () => JSON.stringify({ chunkId: 'chunk-123' }) + text: async () => JSON.stringify({ chunkId: "chunk-123" }), }); const chunkId = await memory.semantic.store( - 'Paris is the capital of France', - { source: 'wikipedia', category: 'geography' } + "Paris is the capital of France", + { source: "wikipedia", category: "geography" }, ); - expect(chunkId).toBe('chunk-123'); - + expect(chunkId).toBe("chunk-123"); + const call = mockFetch.mock.calls[0]; const body = JSON.parse(call[1].body); - expect(body.content).toBe('Paris is the capital of France'); - expect(body.metadata).toEqual({ source: 'wikipedia', category: 'geography' }); + expect(body.content).toBe("Paris is the capital of France"); + expect(body.metadata).toEqual({ + source: "wikipedia", + category: "geography", + }); }); }); - describe('delete', () => { - it('should delete memory chunk', async () => { + describe("delete", () => { + it("should delete memory chunk", async () => { mockFetch.mockResolvedValueOnce({ ok: true, status: 204, - text: async () => '' + text: async () => "", }); - await memory.semantic.delete('chunk-123'); + await memory.semantic.delete("chunk-123"); expect(mockFetch).toHaveBeenCalledWith( - 'http://localhost:8080/v1/memory/semantic/chunk-123', + "http://localhost:8080/v1/memory/semantic/chunk-123", expect.objectContaining({ - method: 'DELETE' - }) + method: "DELETE", + }), ); }); - it('should batch delete memory chunks', async () => { + it("should batch delete memory chunks", async () => { mockFetch.mockResolvedValueOnce({ ok: true, status: 204, - text: async () => '' + text: async () => "", }); - await memory.semantic.deleteBatch(['chunk-1', 'chunk-2', 'chunk-3']); + await memory.semantic.deleteBatch(["chunk-1", "chunk-2", "chunk-3"]); const call = mockFetch.mock.calls[0]; const body = JSON.parse(call[1].body); - expect(body.chunkIds).toEqual(['chunk-1', 'chunk-2', 'chunk-3']); + expect(body.chunkIds).toEqual(["chunk-1", "chunk-2", "chunk-3"]); }); }); }); - describe('Provenance', () => { - it('should get memory provenance', async () => { + describe("Provenance", () => { + it("should get memory provenance", async () => { mockFetch.mockResolvedValueOnce({ ok: true, status: 200, - text: async () => JSON.stringify({ - memoryId: 'mem-123', - provenance: { - source: 'user_input', - confidence: 0.95, - timestamp: '2024-01-01T00:00:00Z' - } - }) + text: async () => + JSON.stringify({ + memoryId: "mem-123", + provenance: { + source: "user_input", + confidence: 0.95, + timestamp: "2024-01-01T00:00:00Z", + }, + }), }); - const result = await memory.getProvenance('mem-123'); + const result = await memory.getProvenance("mem-123"); - expect(result.memoryId).toBe('mem-123'); - expect(result.provenance.source).toBe('user_input'); + expect(result.memoryId).toBe("mem-123"); + expect(result.provenance.source).toBe("user_input"); expect(result.provenance.confidence).toBe(0.95); }); - it('should get memory lineage', async () => { + it("should get memory lineage", async () => { mockFetch.mockResolvedValueOnce({ ok: true, status: 200, - text: async () => JSON.stringify({ - lineage: [ - { source: 'user_input', confidence: 1.0, timestamp: '2024-01-01' }, - { source: 'inference', confidence: 0.9, timestamp: '2024-01-02', parentId: 'mem-1' } - ] - }) + text: async () => + JSON.stringify({ + lineage: [ + { + source: "user_input", + confidence: 1.0, + timestamp: "2024-01-01", + }, + { + source: "inference", + confidence: 0.9, + timestamp: "2024-01-02", + parentId: "mem-1", + }, + ], + }), }); - const lineage = await memory.getLineage('mem-123'); + const lineage = await memory.getLineage("mem-123"); expect(lineage).toHaveLength(2); - expect(lineage[0].source).toBe('user_input'); - expect(lineage[1].source).toBe('inference'); + expect(lineage[0].source).toBe("user_input"); + expect(lineage[1].source).toBe("inference"); }); }); - describe('Consolidation', () => { - it('should trigger memory consolidation', async () => { + describe("Consolidation", () => { + it("should trigger memory consolidation", async () => { mockFetch.mockResolvedValueOnce({ ok: true, status: 200, - text: async () => JSON.stringify({ - jobId: 'job-123', - status: 'pending', - startedAt: '2024-01-01T00:00:00Z' - }) + text: async () => + JSON.stringify({ + jobId: "job-123", + status: "pending", + startedAt: "2024-01-01T00:00:00Z", + }), }); const result = await memory.consolidate({ - strategy: 'summarize', - llmProvider: 'anthropic' + strategy: "summarize", + llmProvider: "anthropic", }); - expect(result.jobId).toBe('job-123'); - expect(result.status).toBe('pending'); + expect(result.jobId).toBe("job-123"); + expect(result.status).toBe("pending"); }); - it('should get consolidation status', async () => { + it("should get consolidation status", async () => { mockFetch.mockResolvedValueOnce({ ok: true, status: 200, - text: async () => JSON.stringify({ - jobId: 'job-123', - status: 'completed', - progress: 100 - }) + text: async () => + JSON.stringify({ + jobId: "job-123", + status: "completed", + progress: 100, + }), }); - const status = await memory.getConsolidationStatus('job-123'); + const status = await memory.getConsolidationStatus("job-123"); - expect(status.status).toBe('completed'); + expect(status.status).toBe("completed"); expect(status.progress).toBe(100); }); - it('should cancel consolidation', async () => { + it("should cancel consolidation", async () => { mockFetch.mockResolvedValueOnce({ ok: true, status: 204, - text: async () => '' + text: async () => "", }); - await memory.cancelConsolidation('job-123'); + await memory.cancelConsolidation("job-123"); expect(mockFetch).toHaveBeenCalledWith( - 'http://localhost:8080/v1/memory/consolidation/job-123', + "http://localhost:8080/v1/memory/consolidation/job-123", expect.objectContaining({ - method: 'DELETE' - }) + method: "DELETE", + }), ); }); }); - describe('Stats and Management', () => { - it('should get memory stats', async () => { + describe("Stats and Management", () => { + it("should get memory stats", async () => { mockFetch.mockResolvedValueOnce({ ok: true, status: 200, - text: async () => JSON.stringify({ - workingMemory: { - threadCount: 10, - resourceCount: 5, - totalSize: 1024 - }, - semanticMemory: { - chunkCount: 100, - totalSize: 10240 - } - }) + text: async () => + JSON.stringify({ + workingMemory: { + threadCount: 10, + resourceCount: 5, + totalSize: 1024, + }, + semanticMemory: { + chunkCount: 100, + totalSize: 10240, + }, + }), }); const stats = await memory.getStats(); @@ -458,15 +503,15 @@ describe('MemoryResource', () => { expect(stats.semanticMemory.chunkCount).toBe(100); }); - it('should require confirmation to clear all', async () => { - await expect(memory.clearAll()).rejects.toThrow('Must confirm'); + it("should require confirmation to clear all", async () => { + await expect(memory.clearAll()).rejects.toThrow("Must confirm"); }); - it('should clear all memory with confirmation', async () => { + it("should clear all memory with confirmation", async () => { mockFetch.mockResolvedValueOnce({ ok: true, status: 204, - text: async () => '' + text: async () => "", }); await memory.clearAll(true); diff --git a/client-sdks/client-js/tsconfig.json b/client-sdks/client-js/tsconfig.json index c08fba1..b6036d9 100644 --- a/client-sdks/client-js/tsconfig.json +++ b/client-sdks/client-js/tsconfig.json @@ -10,4 +10,3 @@ }, "include": ["src"] } - diff --git a/client-sdks/client-js/vitest.config.ts b/client-sdks/client-js/vitest.config.ts index cdfad90..f09e89b 100644 --- a/client-sdks/client-js/vitest.config.ts +++ b/client-sdks/client-js/vitest.config.ts @@ -1,19 +1,19 @@ -import { defineConfig } from 'vitest/config'; +import { defineConfig } from "vitest/config"; export default defineConfig({ test: { globals: true, - environment: 'node', + environment: "node", coverage: { - provider: 'v8', - reporter: ['text', 'json', 'html'], + provider: "v8", + reporter: ["text", "json", "html"], exclude: [ - 'node_modules/', - 'dist/', - 'tests/', - '**/*.test.ts', - '**/*.config.ts' - ] - } - } + "node_modules/", + "dist/", + "tests/", + "**/*.test.ts", + "**/*.config.ts", + ], + }, + }, }); diff --git a/docs/app.config.ts b/docs/app.config.ts index 107b2d5..f7e18bf 100644 --- a/docs/app.config.ts +++ b/docs/app.config.ts @@ -1,41 +1,41 @@ export default { docus: { - title: 'Aster · 星尘云枢', - description: '让每一个 Agent 都能在生产环境中闪耀', - url: 'https://astercloud.github.io/aster', - - image: '/images/logo-banner.svg', - + title: "Aster · 星尘云枢", + description: "让每一个 Agent 都能在生产环境中闪耀", + url: "https://astercloud.github.io/aster", + + image: "/images/logo-banner.svg", + socials: { - github: 'astercloud/aster', + github: "astercloud/aster", }, - + header: { logo: true, - title: 'Aster', + title: "Aster", showLinkIcon: true, }, - + aside: { level: 0, collapsed: false, - exclude: [] + exclude: [], }, - + footer: { credits: { - icon: '', - text: 'Made with 💜 by astercloud', - href: 'https://github.com/astercloud' + icon: "", + text: "Made with 💜 by astercloud", + href: "https://github.com/astercloud", }, textLinks: [ { - text: 'GitHub', - href: 'https://github.com/astercloud/aster', - target: '_blank' - } + text: "GitHub", + href: "https://github.com/astercloud/aster", + target: "_blank", + }, ], - iconLinks: [] - } - } -} + iconLinks: [], + }, + }, +}; diff --git a/docs/components/AppHeader.vue b/docs/components/AppHeader.vue index 3fb2907..51ca3bf 100644 --- a/docs/components/AppHeader.vue +++ b/docs/components/AppHeader.vue @@ -5,7 +5,9 @@ Aster Logo
- + Aster · 星尘云枢 星尘汇聚,智能成枢 diff --git a/docs/content/01.introduction/1.overview.md b/docs/content/01.introduction/1.overview.md index a1dc558..d94eb6f 100644 --- a/docs/content/01.introduction/1.overview.md +++ b/docs/content/01.introduction/1.overview.md @@ -6,7 +6,7 @@ description: Aster · 星尘云枢 - 让每一个 Agent 都能在生产环境中 # 概述 ::alert{type="info" icon="✨"} -**星尘汇聚,智能成枢** +**星尘汇聚,智能成枢** 让每一个 Agent 都能在生产环境中闪耀 :: @@ -20,9 +20,9 @@ description: Aster · 星尘云枢 - 让每一个 Agent 都能在生产环境中 - **事件驱动架构** - 高性能的异步处理机制 - **企业级安全治理** - 生产环境的可靠保障 -*Go 的高性能基底,脚本的灵活编排,为生产环境而生* +_Go 的高性能基底,脚本的灵活编排,为生产环境而生_ -## 为什么需要 Aster? +## 为什么需要 Aster? aster 是一个为生产环境设计的 **Go语言AI Agent开发框架**。它提供了企业级的Agent运行时,支持事件驱动、云端沙箱、安全可控等特性。 @@ -104,12 +104,12 @@ ag, err := agent.Create(ctx, &types.AgentConfig{ 支持多种沙箱后端,确保代码执行安全: -| 沙箱类型 | 使用场景 | 特点 | -|---------|---------|------| -| LocalSandbox | 开发测试 | 快速迭代,本地Docker | -| AliyunSandbox | 生产环境 | 阿里云AgentBay,高安全 | -| VolcengineSandbox | 生产环境 | 火山引擎,高性能 | -| MockSandbox | 单元测试 | 模拟执行,无副作用 | +| 沙箱类型 | 使用场景 | 特点 | +| ----------------- | -------- | ---------------------- | +| LocalSandbox | 开发测试 | 快速迭代,本地Docker | +| AliyunSandbox | 生产环境 | 阿里云AgentBay,高安全 | +| VolcengineSandbox | 生产环境 | 火山引擎,高性能 | +| MockSandbox | 单元测试 | 模拟执行,无副作用 | ```go ag, err := agent.Create(ctx, &types.AgentConfig{ diff --git a/docs/content/01.introduction/3.quickstart.md b/docs/content/01.introduction/3.quickstart.md index 9e08a32..59ae9ba 100644 --- a/docs/content/01.introduction/3.quickstart.md +++ b/docs/content/01.introduction/3.quickstart.md @@ -278,20 +278,20 @@ ag, _ := agent.Create(ctx, &types.AgentConfig{ aster提供丰富的内置工具: -| 类别 | 工具名称 | 功能描述 | -|------|---------|---------| -| **文件系统** | `Read` | 读取文件内容(支持分页) | -| | `Write` | 写入文件 | -| | `Edit` | 精确编辑(字符串替换) | -| | `Ls` | 列出目录 | -| | `Glob` | Glob模式匹配 | -| | `Grep` | 正则搜索(显示行号) | -| **命令执行** | `Bash` | 执行Bash命令 | -| **任务管理** | `todo_list` | 列出待办事项 | -| | `todo_add` | 添加待办 | -| | `todo_update` | 更新待办状态 | -| **网络** | `http_fetch` | HTTP请求 | -| | `WebSearch` | 网络搜索 | +| 类别 | 工具名称 | 功能描述 | +| ------------ | ------------- | ------------------------ | +| **文件系统** | `Read` | 读取文件内容(支持分页) | +| | `Write` | 写入文件 | +| | `Edit` | 精确编辑(字符串替换) | +| | `Ls` | 列出目录 | +| | `Glob` | Glob模式匹配 | +| | `Grep` | 正则搜索(显示行号) | +| **命令执行** | `Bash` | 执行Bash命令 | +| **任务管理** | `todo_list` | 列出待办事项 | +| | `todo_add` | 添加待办 | +| | `todo_update` | 更新待办状态 | +| **网络** | `http_fetch` | HTTP请求 | +| | `WebSearch` | 网络搜索 | **注册所有工具**: diff --git a/docs/content/01.introduction/4.architecture.md b/docs/content/01.introduction/4.architecture.md index 0ba46ed..02c3822 100644 --- a/docs/content/01.introduction/4.architecture.md +++ b/docs/content/01.introduction/4.architecture.md @@ -224,12 +224,12 @@ type BackendProtocol interface { ### 四种Backend实现 -| Backend | 生命周期 | 使用场景 | 特点 | -|---------|---------|---------|------| -| **StateBackend** | 会话级 | 临时文件、中间结果 | 内存存储,快速 | -| **StoreBackend** | 跨会话 | 知识库、记忆 | 持久化,可恢复 | -| **FilesystemBackend** | 永久 | 工作空间文件 | 真实文件系统 | -| **CompositeBackend** | - | 混合存储策略 | 路由组合 | +| Backend | 生命周期 | 使用场景 | 特点 | +| --------------------- | -------- | ------------------ | -------------- | +| **StateBackend** | 会话级 | 临时文件、中间结果 | 内存存储,快速 | +| **StoreBackend** | 跨会话 | 知识库、记忆 | 持久化,可恢复 | +| **FilesystemBackend** | 永久 | 工作空间文件 | 真实文件系统 | +| **CompositeBackend** | - | 混合存储策略 | 路由组合 | ### 使用示例 @@ -277,11 +277,11 @@ aster采用事件驱动架构,通过三个独立通道分离不同类型的事 ### 三通道设计 -| 通道 | 用途 | 典型订阅者 | 事件类型 | -|------|------|-----------|---------| -| **Progress** | 实时进度、UI展示 | 前端、聊天界面 | 文本流、工具执行 | -| **Control** | 审批、人机交互 | 审批服务、安全网关 | 工具审批请求 | -| **Monitor** | 监控、审计 | 监控系统、日志平台 | 错误、性能指标 | +| 通道 | 用途 | 典型订阅者 | 事件类型 | +| ------------ | ---------------- | ------------------ | ---------------- | +| **Progress** | 实时进度、UI展示 | 前端、聊天界面 | 文本流、工具执行 | +| **Control** | 审批、人机交互 | 审批服务、安全网关 | 工具审批请求 | +| **Monitor** | 监控、审计 | 监控系统、日志平台 | 错误、性能指标 | ### 事件订阅 @@ -398,12 +398,12 @@ type Provider interface { ### 支持的Provider -| Provider | 模型 | 特点 | -|---------|------|------| +| Provider | 模型 | 特点 | +| ------------- | -------------- | ---------------------- | | **Anthropic** | Claude 3/4系列 | 长上下文、工具调用优秀 | -| **OpenAI** | GPT-4/GPT-3.5 | 生态成熟 | -| **DeepSeek** | DeepSeek-V2 | 性价比高 | -| **GLM** | ChatGLM系列 | 中文优化 | +| **OpenAI** | GPT-4/GPT-3.5 | 生态成熟 | +| **DeepSeek** | DeepSeek-V2 | 性价比高 | +| **GLM** | ChatGLM系列 | 中文优化 | ### 使用示例 @@ -428,12 +428,12 @@ for event := range stream { ### 沙箱类型 -| 类型 | 使用场景 | 隔离级别 | 配置 | -|-----|---------|---------|------| -| **LocalSandbox** | 开发测试 | 进程级 | 本地Docker | -| **AliyunSandbox** | 生产环境 | 容器级 | AgentBay | -| **VolcengineSandbox** | 生产环境 | 容器级 | 火山引擎 | -| **MockSandbox** | 单元测试 | 无隔离 | 模拟执行 | +| 类型 | 使用场景 | 隔离级别 | 配置 | +| --------------------- | -------- | -------- | ---------- | +| **LocalSandbox** | 开发测试 | 进程级 | 本地Docker | +| **AliyunSandbox** | 生产环境 | 容器级 | AgentBay | +| **VolcengineSandbox** | 生产环境 | 容器级 | 火山引擎 | +| **MockSandbox** | 单元测试 | 无隔离 | 模拟执行 | ### 配置示例 @@ -460,11 +460,11 @@ Sandbox: &types.SandboxConfig{ 基于Apple M1, Go 1.21的性能测试: -| 操作 | 性能 | 内存分配 | 吞吐量 | -|------|------|---------|--------| -| Middleware Stack | 36.21 ns/op | 96 B/op | ~27M ops/s | -| Backend Write | 257.9 ns/op | 480 B/op | ~3.8M ops/s | -| Tool Execution | < 1ms | 1-5 KB | 1000+ ops/s | +| 操作 | 性能 | 内存分配 | 吞吐量 | +| ---------------- | ----------- | -------- | ----------- | +| Middleware Stack | 36.21 ns/op | 96 B/op | ~27M ops/s | +| Backend Write | 257.9 ns/op | 480 B/op | ~3.8M ops/s | +| Tool Execution | < 1ms | 1-5 KB | 1000+ ops/s | ## 🎨 设计模式 @@ -504,17 +504,17 @@ ag.Emit(event) ## 🔄 与DeepAgents对比 -| 特性 | DeepAgents (Python) | aster (Go) | -|------|-------------------|---------------| -| Backend Protocol | ✅ 4种 | ✅ 4种 | -| Middleware栈 | ✅ 洋葱模型 | ✅ 洋葱模型 | -| 文件工具 | ✅ 6个 | ✅ 6个 | -| 自动驱逐 | ✅ | ✅ | -| 子代理 | ✅ | ✅ | -| 性能 | 中等 | **极高** | -| 内存 | 高 | **低** | -| 并发 | GIL限制 | **真正并发** | -| 类型安全 | 动态 | **静态** | +| 特性 | DeepAgents (Python) | aster (Go) | +| ---------------- | ------------------- | ------------ | +| Backend Protocol | ✅ 4种 | ✅ 4种 | +| Middleware栈 | ✅ 洋葱模型 | ✅ 洋葱模型 | +| 文件工具 | ✅ 6个 | ✅ 6个 | +| 自动驱逐 | ✅ | ✅ | +| 子代理 | ✅ | ✅ | +| 性能 | 中等 | **极高** | +| 内存 | 高 | **低** | +| 并发 | GIL限制 | **真正并发** | +| 类型安全 | 动态 | **静态** | ## 📚 下一步 diff --git a/docs/content/02.core-concepts/1.agent-lifecycle.md b/docs/content/02.core-concepts/1.agent-lifecycle.md index 982fb96..7b79cab 100644 --- a/docs/content/02.core-concepts/1.agent-lifecycle.md +++ b/docs/content/02.core-concepts/1.agent-lifecycle.md @@ -150,6 +150,7 @@ ag.Start(ctx) ### Start时发生了什么? 1. **触发中间件钩子** + ```go for _, m := range middlewares { m.OnAgentStart(ctx, agentID) @@ -413,6 +414,7 @@ ag.Close() ### Close时发生了什么? 1. **触发中间件钩子** + ```go for _, m := range middlewares { m.OnAgentStop(ctx, agentID) diff --git a/docs/content/02.core-concepts/10.subagent-system.md b/docs/content/02.core-concepts/10.subagent-system.md index 82c3098..1694695 100644 --- a/docs/content/02.core-concepts/10.subagent-system.md +++ b/docs/content/02.core-concepts/10.subagent-system.md @@ -222,11 +222,11 @@ subagentMW, _ := middleware.NewSubAgentMiddleware(&middleware.SubAgentMiddleware ```typescript interface TaskInput { - description: string; // 任务描述(必需) - subagent_type: string; // SubAgent 类型(必需) - context?: object; // 父 Agent 上下文(可选) - async?: boolean; // 是否异步执行(可选,默认 false) - timeout?: number; // 超时时间(秒,可选,默认 3600) + description: string; // 任务描述(必需) + subagent_type: string; // SubAgent 类型(必需) + context?: object; // 父 Agent 上下文(可选) + async?: boolean; // 是否异步执行(可选,默认 false) + timeout?: number; // 超时时间(秒,可选,默认 3600) } ``` @@ -307,6 +307,7 @@ tool_use: ``` **优势**: + - ⚡ 速度快 3 倍(并行执行) - 💰 Token 优化(每个子 Agent 只返回摘要) - 🎯 上下文隔离(不互相污染) @@ -329,6 +330,7 @@ tool_use: ``` **优势**: + - 📚 专业化(每个 SubAgent 有专门提示词和工具) - 🧹 上下文清晰(主 Agent 只看摘要) - 🔄 可复用(SubAgent 可用于其他任务) @@ -353,6 +355,7 @@ tool_use: ``` **优势**: + - 💾 内存优化(主 Agent 不存储详细日志) - ⚡ 响应速度(上下文小) - 💰 成本降低(Token 使用少) @@ -590,13 +593,13 @@ result := subagent.Execute(...) ## 🎯 SubAgent vs Workflow Agent -| 特性 | SubAgent | Workflow Agent | -|------|---------|---------------| -| **用途** | 任务委托、上下文隔离 | 工作流编排 | +| 特性 | SubAgent | Workflow Agent | +| ------------ | ----------------------- | ----------------------- | +| **用途** | 任务委托、上下文隔离 | 工作流编排 | | **调用方式** | 主 Agent 调用 task 工具 | 直接创建 Workflow Agent | -| **执行方式** | 主 Agent 决定何时调用 | 预定义执行流程 | -| **灵活性** | 高(动态决策) | 中(固定流程) | -| **适用场景** | 动态任务委托 | 固定工作流程 | +| **执行方式** | 主 Agent 决定何时调用 | 预定义执行流程 | +| **灵活性** | 高(动态决策) | 中(固定流程) | +| **适用场景** | 动态任务委托 | 固定工作流程 | **组合使用**: diff --git a/docs/content/02.core-concepts/11.subagent-async.md b/docs/content/02.core-concepts/11.subagent-async.md index 8a5b262..b230364 100644 --- a/docs/content/02.core-concepts/11.subagent-async.md +++ b/docs/content/02.core-concepts/11.subagent-async.md @@ -122,11 +122,11 @@ for { status1 := queryTask(task1) status2 := queryTask(task2) status3 := queryTask(task3) - + if allCompleted(status1, status2, status3) { break } - + sleep(10 * time.Second) } @@ -146,13 +146,15 @@ finalReport := synthesize(result1, result2, result3) **功能**:查询子代理的状态和输出 **参数**: + ```typescript { - task_id: string // 任务 ID + task_id: string; // 任务 ID } ``` **返回**: + ```typescript { ok: boolean, @@ -173,6 +175,7 @@ finalReport := synthesize(result1, result2, result3) ``` **使用示例**: + ```go tool_use: name: query_subagent @@ -187,13 +190,15 @@ tool_use: **功能**:停止正在运行的子代理 **参数**: + ```typescript { - task_id: string // 任务 ID + task_id: string; // 任务 ID } ``` **返回**: + ```typescript { ok: boolean, @@ -203,11 +208,13 @@ tool_use: ``` **使用场景**: + - 任务运行时间过长,需要手动停止 - 发现任务执行方向错误,需要中止 - 资源紧张,需要释放资源 **使用示例**: + ```go tool_use: name: stop_subagent @@ -222,13 +229,15 @@ tool_use: **功能**:恢复已停止或失败的子代理 **参数**: + ```typescript { - task_id: string // 原任务 ID + task_id: string; // 原任务 ID } ``` **返回**: + ```typescript { ok: boolean, @@ -241,16 +250,19 @@ tool_use: ``` **使用场景**: + - 子代理因超时或错误而停止,需要重新执行 - 手动停止的子代理,需要继续执行 - 系统重启后,恢复未完成的任务 **注意事项**: + - 恢复后会生成新的 task_id - 原有的元数据会被保留 - 只能恢复状态为 "stopped"、"failed" 或 "completed" 的子代理 **使用示例**: + ```go tool_use: name: resume_subagent @@ -265,6 +277,7 @@ tool_use: **功能**:列出所有子代理任务 **参数**: + ```typescript { status_filter?: string // 可选,按状态过滤 @@ -272,6 +285,7 @@ tool_use: ``` **返回**: + ```typescript { ok: boolean, @@ -289,11 +303,13 @@ tool_use: ``` **使用场景**: + - 查看当前有哪些子代理正在运行 - 检查历史任务的执行情况 - 清理已完成的任务 **使用示例**: + ```go # 列出所有任务 tool_use: @@ -384,7 +400,7 @@ maxRetries := 3 for i := 0; i < maxRetries; i++ { // 等待完成 waitForCompletion(taskID) - + status := queryTask(taskID) if status == "completed" { result := getOutput(taskID) @@ -441,14 +457,14 @@ subagentMW, _ := middleware.NewSubAgentMiddleware(&middleware.SubAgentMiddleware ## 📊 状态说明 -| 状态 | 说明 | 可执行操作 | -|------|------|-----------| -| **starting** | 正在启动 | query | -| **running** | 正在运行 | query, stop | +| 状态 | 说明 | 可执行操作 | +| ------------- | -------------- | ------------- | +| **starting** | 正在启动 | query | +| **running** | 正在运行 | query, stop | | **completed** | 已完成(成功) | query, resume | -| **failed** | 执行失败 | query, resume | -| **stopped** | 已停止 | query, resume | -| **timeout** | 超时 | query, resume | +| **failed** | 执行失败 | query, resume | +| **stopped** | 已停止 | query, resume | +| **timeout** | 超时 | query, resume | ## 🎓 最佳实践 @@ -486,7 +502,7 @@ status := queryTask(taskID) if status == "failed" { error := getError(taskID) log.Printf("Task failed: %s", error) - + // 决定是否重试 if isRetryable(error) { resumeTask(taskID) @@ -517,11 +533,13 @@ for _, taskID := range completedTasks { ### 问题 1:任务一直处于 "starting" 状态 **可能原因**: + - SubAgent 启动失败 - 资源不足 - 配置错误 **解决方法**: + ```go // 查询详细状态 status := queryTask(taskID) @@ -540,11 +558,13 @@ if status.ResourceUsage != nil { ### 问题 2:任务超时 **可能原因**: + - 任务复杂度超出预期 - 超时设置过短 - 资源不足导致执行缓慢 **解决方法**: + ```go // 增加超时时间 tool_use: @@ -559,10 +579,12 @@ resumeTask(taskID) ### 问题 3:无法恢复任务 **可能原因**: + - 任务状态不允许恢复 - 任务已被清理 **解决方法**: + ```go // 检查任务状态 status := queryTask(taskID) diff --git a/docs/content/02.core-concepts/12.prompt-builder.md b/docs/content/02.core-concepts/12.prompt-builder.md index 7a00b68..a34b474 100644 --- a/docs/content/02.core-concepts/12.prompt-builder.md +++ b/docs/content/02.core-concepts/12.prompt-builder.md @@ -45,13 +45,16 @@ type PromptContext struct { ### 基础模块 #### 1. BasePromptModule (优先级: 0) + - **功能**: 从模板中获取基础 System Prompt - **条件**: 总是注入 #### 2. CapabilitiesModule (优先级: 5) + - **功能**: 基于可用工具自动生成能力说明 - **条件**: `metadata["show_capabilities"] == true` - **示例输出**: + ``` ## Your Capabilities @@ -63,9 +66,11 @@ You can: ``` #### 3. EnvironmentModule (优先级: 10) + - **功能**: 注入环境信息(工作目录、平台、日期、Git 仓库) - **条件**: 环境信息可用 - **示例输出**: + ``` ## Environment Information @@ -79,9 +84,11 @@ You can: ### 工具和任务管理 #### 4. ToolsManualModule (优先级: 20) + - **功能**: 注入工具手册 - **条件**: 工具可用且配置允许 - **配置选项**: + ```go ToolsManual: &types.ToolsManualConfig{ Mode: "all", // "all", "listed", "none" @@ -91,19 +98,23 @@ ToolsManual: &types.ToolsManualConfig{ ``` #### 5. TodoReminderModule (优先级: 25) + - **功能**: 注入任务管理提醒 - **条件**: Todo 配置启用且 `ReminderOnStart == true` ### 开发和协作 #### 6. CodeReferenceModule (优先级: 30) + - **功能**: 注入代码引用规范 - **条件**: `metadata["agent_type"] == "code_assistant"` 或 `"developer"` #### 7. CollaborationModule (优先级: 45) + - **功能**: 注入多 Agent 协作信息 - **条件**: `metadata["room_id"]` 存在 - **配置示例**: + ```go Metadata: map[string]interface{}{ "room_id": "room-123", @@ -113,16 +124,19 @@ Metadata: map[string]interface{}{ ``` #### 8. WorkflowModule (优先级: 50) + - **功能**: 注入工作流上下文 - **条件**: `metadata["workflow_id"]` 存在 ### 安全和性能 #### 9. SecurityModule (优先级: 35) + - **功能**: 注入安全策略 - **条件**: `metadata["enable_security"] == true` #### 10. PerformanceModule (优先级: 40) + - **功能**: 注入性能优化建议 - **条件**: `metadata["enable_performance_hints"] == true` @@ -136,31 +150,37 @@ Metadata: map[string]interface{}{ ## 预设模板 ### 1. CodeAssistantPreset -**用途**: 专业代码助手 -**包含模块**: base, capabilities, environment, sandbox, tools_manual, todo_reminder, code_reference + +**用途**: 专业代码助手 +**包含模块**: base, capabilities, environment, sandbox, tools_manual, todo_reminder, code_reference **使用场景**: 代码编写、审查、调试 ### 2. ResearchAssistantPreset -**用途**: 研究助手 -**包含模块**: base, capabilities, environment, tools_manual, todo_reminder + +**用途**: 研究助手 +**包含模块**: base, capabilities, environment, tools_manual, todo_reminder **使用场景**: 信息收集、文献研究、数据分析 ### 3. DataAnalystPreset -**用途**: 数据分析师 -**包含模块**: base, capabilities, environment, sandbox, tools_manual, todo_reminder, performance + +**用途**: 数据分析师 +**包含模块**: base, capabilities, environment, sandbox, tools_manual, todo_reminder, performance **使用场景**: 数据分析、可视化、统计分析 ### 4. DevOpsEngineerPreset -**用途**: DevOps 工程师 -**包含模块**: base, capabilities, environment, sandbox, tools_manual, todo_reminder, security + +**用途**: DevOps 工程师 +**包含模块**: base, capabilities, environment, sandbox, tools_manual, todo_reminder, security **使用场景**: 基础设施管理、CI/CD 配置 ### 5. SecurityAuditorPreset -**用途**: 安全审计员 -**包含模块**: base, capabilities, environment, tools_manual, todo_reminder, security, code_reference + +**用途**: 安全审计员 +**包含模块**: base, capabilities, environment, tools_manual, todo_reminder, security, code_reference **使用场景**: 安全审计、漏洞扫描、合规检查 ### 其他预设 + - **TechnicalWriterPreset**: 技术文档编写 - **ProjectManagerPreset**: 项目管理 - **GeneralAssistantPreset**: 通用助手 @@ -288,6 +308,7 @@ compressed := compressor.Compress(systemPrompt) ### 1. 选择合适的预设 根据 Agent 的主要用途选择预设模板: + - 代码相关 → CodeAssistantPreset - 研究分析 → ResearchAssistantPreset - 数据处理 → DataAnalystPreset @@ -296,6 +317,7 @@ compressed := compressor.Compress(systemPrompt) ### 2. 合理使用 Metadata 通过 Metadata 控制模块注入: + ```go Metadata: map[string]interface{}{ "agent_type": "code_assistant", // 触发 CodeReferenceModule @@ -308,6 +330,7 @@ Metadata: map[string]interface{}{ ### 3. 控制 Prompt 长度 对于上下文窗口有限的模型: + ```go Context: &types.ContextManagerOptions{ MaxTokens: 100000, // 触发 ContextWindowModule @@ -317,6 +340,7 @@ Context: &types.ContextManagerOptions{ ### 4. 使用工具手册配置 减少不必要的工具说明: + ```go ToolsManual: &types.ToolsManualConfig{ Mode: "listed", @@ -327,6 +351,7 @@ ToolsManual: &types.ToolsManualConfig{ ### 5. 添加自定义指令 针对特定任务添加额外指导: + ```go Metadata: map[string]interface{}{ "custom_instructions": "Always follow TDD. Write tests first.", @@ -364,15 +389,15 @@ if stats.EstimatedTokens > 5000 { ## 与 Claude Code 的对比 -| 特性 | Claude Code | Aster Prompt Builder | -|------|-------------|---------------------| -| 构建方式 | 模块化拼凑 | 模块化拼凑 | -| 动态注入 | 支持 | 支持 | -| 条件模块 | 支持 | 支持 | -| 优先级控制 | 隐式 | 显式(Priority 方法)| -| 自定义模块 | 不支持 | 支持 | -| 配置驱动 | 部分支持 | 完全支持 | -| 预设模板 | 无 | 8 个预设 | +| 特性 | Claude Code | Aster Prompt Builder | +| ---------- | ----------- | --------------------- | +| 构建方式 | 模块化拼凑 | 模块化拼凑 | +| 动态注入 | 支持 | 支持 | +| 条件模块 | 支持 | 支持 | +| 优先级控制 | 隐式 | 显式(Priority 方法) | +| 自定义模块 | 不支持 | 支持 | +| 配置驱动 | 部分支持 | 完全支持 | +| 预设模板 | 无 | 8 个预设 | ## 参考 diff --git a/docs/content/02.core-concepts/2.event-system.md b/docs/content/02.core-concepts/2.event-system.md index 5eded85..12296ae 100644 --- a/docs/content/02.core-concepts/2.event-system.md +++ b/docs/content/02.core-concepts/2.event-system.md @@ -34,11 +34,11 @@ aster采用事件驱动架构,通过三个独立的事件通道分离不同类 ### 通道对比 -| 通道 | 用途 | 典型订阅者 | 事件频率 | 关键性 | -|------|------|-----------|---------|--------| -| **Progress** | 实时进度展示 | 前端UI、聊天界面 | 高(毫秒级) | UI体验 | -| **Control** | 审批决策 | 审批服务、安全网关 | 低(按需) | 安全控制 | -| **Monitor** | 监控审计 | 监控系统、日志平台 | 中(事件级) | 可观测性 | +| 通道 | 用途 | 典型订阅者 | 事件频率 | 关键性 | +| ------------ | ------------ | ------------------ | ------------ | -------- | +| **Progress** | 实时进度展示 | 前端UI、聊天界面 | 高(毫秒级) | UI体验 | +| **Control** | 审批决策 | 审批服务、安全网关 | 低(按需) | 安全控制 | +| **Monitor** | 监控审计 | 监控系统、日志平台 | 中(事件级) | 可观测性 | ## 📡 Progress通道 @@ -128,6 +128,7 @@ type ProgressCompleteEvent struct { ``` **停止原因**: + - `"end_turn"`: 正常结束 - `"max_tokens"`: 达到最大token数 - `"stop_sequence"`: 匹配停止序列 @@ -262,6 +263,7 @@ config := &types.AgentConfig{ ``` 权限策略: + - `PermissionAllow`: 自动允许 - `PermissionAsk`: 需要审批 - `PermissionDeny`: 自动拒绝 @@ -518,12 +520,12 @@ case <-time.After(100 * time.Millisecond): ### 事件频率 -| 事件类型 | 典型频率 | 处理时间要求 | -|---------|---------|------------| -| ProgressTextChunk | 10-50/秒 | <10ms | -| ProgressToolStart/End | 1-5/对话 | <100ms | -| MonitorEvent | 按需 | <50ms | -| ControlEvent | 罕见 | 人工决策 | +| 事件类型 | 典型频率 | 处理时间要求 | +| --------------------- | -------- | ------------ | +| ProgressTextChunk | 10-50/秒 | <10ms | +| ProgressToolStart/End | 1-5/对话 | <100ms | +| MonitorEvent | 按需 | <50ms | +| ControlEvent | 罕见 | 人工决策 | ### 性能优化 diff --git a/docs/content/02.core-concepts/3.middleware.md b/docs/content/02.core-concepts/3.middleware.md index d753da4..481dfce 100644 --- a/docs/content/02.core-concepts/3.middleware.md +++ b/docs/content/02.core-concepts/3.middleware.md @@ -22,12 +22,14 @@ Request → M1 → M2 → M3 → Handler → M3 → M2 → M1 → Response ``` 每个请求和响应都会依次通过多层中间件: + - **请求阶段**:从外到内(优先级从低到高) - **响应阶段**:从内到外(优先级从高到低) ### 为什么是洋葱模型? **优势**: + 1. **清晰的层次**:功能按优先级分层 2. **双向拦截**:可以在前后都处理 3. **易于扩展**:添加中间件不影响现有代码 @@ -78,6 +80,7 @@ const ( ``` **规则**: + - 数值越小,优先级越高,越靠近核心 - 在请求阶段,优先级高的先执行 - 在响应阶段,优先级高的后执行 @@ -124,6 +127,7 @@ summaryMiddleware := middleware.NewSummarizationMiddleware(&middleware.Summariza ``` **适用场景**: + - 长时间对话 - 需要保持上下文但又担心token超限 - 自动维护对话历史 @@ -135,6 +139,7 @@ summaryMiddleware := middleware.NewSummarizationMiddleware(&middleware.Summariza **优先级**:100 **提供的工具**: + - `Read` - 读取文件 - `Write` - 写入文件 - `Edit` - 编辑文件 @@ -186,6 +191,7 @@ ag.Chat(ctx, "读取README.md文件") **功能**:基于普通文件+搜索的长期记忆中间件。 **核心特点**: + - 从后端读取 `/agent.md`,将其作为 `...` 注入 System Prompt,提供“人格/长期指令”。 - 基于 `backends.BackendProtocol` 在指定 `MemoryPath` 下管理记忆文件(默认为 `/memories/`)。 - 自动注入 `memory_search` / `memory_write` 工具,配合 `fs_*` 工具构成纯文本的长期记忆系统。 @@ -219,6 +225,7 @@ memoryMW, _ := middleware.NewAgentMemoryMiddleware(&middleware.AgentMemoryMiddle **优先级**:200 **提供的工具**: + - `task` - 委派任务到子Agent **工作流程**: diff --git a/docs/content/02.core-concepts/5.sandbox.md b/docs/content/02.core-concepts/5.sandbox.md index 034c24a..589c2b8 100644 --- a/docs/content/02.core-concepts/5.sandbox.md +++ b/docs/content/02.core-concepts/5.sandbox.md @@ -14,6 +14,7 @@ aster的沙箱系统提供安全隔离的代码执行环境,确保Agent执行 ### 安全风险 Agent可能会: + - 执行危险命令(`rm -rf /`) - 访问敏感文件 - 发起网络攻击 @@ -87,22 +88,22 @@ graph TB ### 执行模式对比 -| 模式 | 沙箱生命周期 | 适用场景 | 优点 | 缺点 | -|------|------------|---------|------|------| -| **会话级** | Agent创建→关闭 | 长对话、状态保留 | 无重复创建开销
保留执行上下文 | 长期占用资源 | -| **任务级** | 每个任务独立 | 高安全要求、无状态任务 | 完全隔离
无状态污染 | 冷启动延迟
成本较高 | -| **沙箱池** | 预热+复用 | 高并发、低延迟 | 极低延迟
资源利用率高 | 需要状态清理
管理复杂 | +| 模式 | 沙箱生命周期 | 适用场景 | 优点 | 缺点 | +| ---------- | -------------- | ---------------------- | --------------------------------- | ------------------------- | +| **会话级** | Agent创建→关闭 | 长对话、状态保留 | 无重复创建开销
保留执行上下文 | 长期占用资源 | +| **任务级** | 每个任务独立 | 高安全要求、无状态任务 | 完全隔离
无状态污染 | 冷启动延迟
成本较高 | +| **沙箱池** | 预热+复用 | 高并发、低延迟 | 极低延迟
资源利用率高 | 需要状态清理
管理复杂 | ## 📦 沙箱类型 aster支持多种沙箱后端: -| 沙箱类型 | 隔离级别 | 使用场景 | 性能 | 成本 | -|---------|---------|---------|------|------| -| **LocalSandbox** | 进程级 | 开发测试 | 高 | 免费 | -| **AliyunSandbox** | 容器级 | 生产环境 | 中 | 按用量 | -| **VolcengineSandbox** | 容器级 | 生产环境 | 高 | 按用量 | -| **MockSandbox** | 无隔离 | 单元测试 | 极高 | 免费 | +| 沙箱类型 | 隔离级别 | 使用场景 | 性能 | 成本 | +| --------------------- | -------- | -------- | ---- | ------ | +| **LocalSandbox** | 进程级 | 开发测试 | 高 | 免费 | +| **AliyunSandbox** | 容器级 | 生产环境 | 中 | 按用量 | +| **VolcengineSandbox** | 容器级 | 生产环境 | 高 | 按用量 | +| **MockSandbox** | 无隔离 | 单元测试 | 极高 | 免费 | ## 🏠 LocalSandbox @@ -388,13 +389,13 @@ sequenceDiagram ### 关键时序节点 -| 阶段 | 本地沙箱耗时 | 云端沙箱耗时 | 说明 | -|------|------------|------------|------| -| 1-3 LLM推理 | ~500ms | ~500ms | 第一次模型调用 | -| 4-6 工具准备 | ~10ms | ~10ms | 参数解析和验证 | -| 7-9 沙箱执行 | ~50ms | ~2s | 云端需要冷启动 | -| 10-12 LLM响应 | ~300ms | ~300ms | 第二次模型调用 | -| **总耗时** | **~860ms** | **~2.8s** | - | +| 阶段 | 本地沙箱耗时 | 云端沙箱耗时 | 说明 | +| ------------- | ------------ | ------------ | -------------- | +| 1-3 LLM推理 | ~500ms | ~500ms | 第一次模型调用 | +| 4-6 工具准备 | ~10ms | ~10ms | 参数解析和验证 | +| 7-9 沙箱执行 | ~50ms | ~2s | 云端需要冷启动 | +| 10-12 LLM响应 | ~300ms | ~300ms | 第二次模型调用 | +| **总耗时** | **~860ms** | **~2.8s** | - | ### 优化建议 @@ -464,6 +465,7 @@ go run main.go ``` 沙箱中执行: + ```bash $ go run main.go Hello, World! @@ -481,6 +483,7 @@ ag.Chat(ctx, ` ``` 沙箱操作: + ```bash $ echo "Hello aster" > /workspace/hello.txt $ cat /workspace/hello.txt diff --git a/docs/content/02.core-concepts/6.workflow-agents.md b/docs/content/02.core-concepts/6.workflow-agents.md index 16f17e3..0fde7a2 100644 --- a/docs/content/02.core-concepts/6.workflow-agents.md +++ b/docs/content/02.core-concepts/6.workflow-agents.md @@ -16,6 +16,7 @@ navigation: 在复杂的 AI 任务中,单个 Agent 往往难以处理所有场景。工作流 Agent 提供了结构化的编排能力,将大任务分解为多个小任务,由专门的子 Agent 协作完成。 **优势**: + - ✅ **模块化**: 每个子 Agent 专注于特定任务 - ✅ **可复用**: 子 Agent 可在不同工作流中重用 - ✅ **可维护**: 工作流结构清晰,易于调试 @@ -74,12 +75,14 @@ sequenceDiagram ``` **特点**: + - 使用 `errgroup` 管理并发 - 所有子 Agent 同时启动 - 事件返回顺序不确定(取决于完成时间) - 任一子 Agent 错误会传播给调用者 **使用场景**: + - 多个算法同时运行,选择最佳结果 - 从多个数据源并行获取数据 - 生成多个候选方案供用户选择 @@ -111,12 +114,14 @@ sequenceDiagram ``` **特点**: + - 严格按顺序执行 - 前一步失败则整个流程终止 - 每步的事件都包含步骤信息(`sequential_step`) - 实际上是 `LoopAgent(MaxIterations=1)` 的特例 **使用场景**: + - 数据处理流水线 - 多阶段决策流程 - 需求分析 → 方案设计 → 代码实现 @@ -152,12 +157,14 @@ sequenceDiagram ``` **特点**: + - 支持自定义停止条件 (`StopCondition`) - 支持最大迭代次数限制 (`MaxIterations`) - 每个事件包含迭代信息(`loop_iteration`) - 必须设置 `MaxIterations` 或 `StopCondition` 之一 **使用场景**: + - 代码质量优化循环 - 多轮对话直到用户满意 - 任务重试直到成功 @@ -176,6 +183,7 @@ type Agent interface { ``` **关键特性**: + - 使用 `stream.Reader` 实现流式接口 - 内存占用 O(1) vs 传统 O(n) - 支持取消和超时(通过 `context.Context`) @@ -199,17 +207,17 @@ type Event struct { **元数据字段**: -| 字段 | 类型 | 说明 | 示例 | -|------|------|------|------| -| `branch` | string | 事件来源路径 | `"Pipeline.Analyzer.iter1"` | -| `parallel_index` | int | ParallelAgent 子 Agent 索引 | `0, 1, 2` | -| `parallel_agent` | string | ParallelAgent 名称 | `"MultiAlgorithm"` | -| `sequential_step` | int | SequentialAgent 当前步骤(1-based) | `2` | -| `total_steps` | int | SequentialAgent 总步骤数 | `3` | -| `sequential_agent` | string | SequentialAgent 名称 | `"DataPipeline"` | -| `loop_iteration` | uint | LoopAgent 当前迭代(0-based) | `1` | -| `loop_agent` | string | LoopAgent 名称 | `"OptimizationLoop"` | -| `sub_agent_index` | int | 子 Agent 在列表中的索引 | `0` | +| 字段 | 类型 | 说明 | 示例 | +| ------------------ | ------ | ----------------------------------- | --------------------------- | +| `branch` | string | 事件来源路径 | `"Pipeline.Analyzer.iter1"` | +| `parallel_index` | int | ParallelAgent 子 Agent 索引 | `0, 1, 2` | +| `parallel_agent` | string | ParallelAgent 名称 | `"MultiAlgorithm"` | +| `sequential_step` | int | SequentialAgent 当前步骤(1-based) | `2` | +| `total_steps` | int | SequentialAgent 总步骤数 | `3` | +| `sequential_agent` | string | SequentialAgent 名称 | `"DataPipeline"` | +| `loop_iteration` | uint | LoopAgent 当前迭代(0-based) | `1` | +| `loop_agent` | string | LoopAgent 名称 | `"OptimizationLoop"` | +| `sub_agent_index` | int | 子 Agent 在列表中的索引 | `0` | ## 🔄 嵌套工作流 @@ -264,12 +272,12 @@ nestedWorkflow, _ := workflow.NewSequentialAgent(workflow.SequentialConfig{ ### 1. 选择合适的工作流模式 -| 场景 | 推荐模式 | 原因 | -|------|---------|------| -| 需要比较多个方案 | ParallelAgent | 同时评估,节省时间 | -| 步骤间有依赖关系 | SequentialAgent | 保证顺序,前一步输出传递给下一步 | -| 需要迭代改进 | LoopAgent | 循环优化直到满足条件 | -| 先并行后串行 | Sequential + Parallel | 嵌套工作流 | +| 场景 | 推荐模式 | 原因 | +| ---------------- | --------------------- | -------------------------------- | +| 需要比较多个方案 | ParallelAgent | 同时评估,节省时间 | +| 步骤间有依赖关系 | SequentialAgent | 保证顺序,前一步输出传递给下一步 | +| 需要迭代改进 | LoopAgent | 循环优化直到满足条件 | +| 先并行后串行 | Sequential + Parallel | 嵌套工作流 | ### 2. 流式处理最佳实践 @@ -385,18 +393,19 @@ StopCondition: func(event *session.Event) bool { aster 的工作流 Agent 设计参考了 Google ADK-Go: -| 特性 | ADK-Go | aster | 说明 | -|------|--------|----------|------| -| **ParallelAgent** | ✅ | ✅ | 并行执行多个子 Agent | -| **SequentialAgent** | ✅ | ✅ | 顺序执行(LoopAgent 特例) | -| **LoopAgent** | ✅ | ✅ | 循环执行直到条件满足 | -| **stream.Reader** | - | ✅ | 高效流式接口 | -| **StopCondition** | ✅ | ✅ | 自定义停止条件 | -| **Escalate 机制** | ✅ | ✅ | 通过 EventActions.Escalate | -| **Branch 追踪** | ✅ | ✅ | event.Branch 字段 | -| **元数据丰富** | ✅ | ✅ | 自动添加 iteration、step 等 | +| 特性 | ADK-Go | aster | 说明 | +| ------------------- | ------ | ----- | --------------------------- | +| **ParallelAgent** | ✅ | ✅ | 并行执行多个子 Agent | +| **SequentialAgent** | ✅ | ✅ | 顺序执行(LoopAgent 特例) | +| **LoopAgent** | ✅ | ✅ | 循环执行直到条件满足 | +| **stream.Reader** | - | ✅ | 高效流式接口 | +| **StopCondition** | ✅ | ✅ | 自定义停止条件 | +| **Escalate 机制** | ✅ | ✅ | 通过 EventActions.Escalate | +| **Branch 追踪** | ✅ | ✅ | event.Branch 字段 | +| **元数据丰富** | ✅ | ✅ | 自动添加 iteration、step 等 | **差异**: + - aster 提供了更丰富的元数据字段 - aster 与 Session 持久化深度集成 - aster 支持 OpenTelemetry 分布式追踪 diff --git a/docs/content/02.core-concepts/7.session-persistence.md b/docs/content/02.core-concepts/7.session-persistence.md index 2646c69..cbcc21c 100644 --- a/docs/content/02.core-concepts/7.session-persistence.md +++ b/docs/content/02.core-concepts/7.session-persistence.md @@ -43,11 +43,11 @@ graph TB ### 三种存储实现 -| 存储类型 | 用途 | 数据持久化 | JSON 支持 | 适用场景 | -|---------|------|-----------|-----------|---------| -| **Memory** | 开发/测试 | ❌ 无 | ✅ 原生 | 本地开发、单元测试 | -| **PostgreSQL** | 生产推荐 | ✅ 持久化 | ✅ JSONB | 复杂查询、全文搜索 | -| **MySQL 8.0+** | 生产可选 | ✅ 持久化 | ✅ JSON | 已有 MySQL 基础设施 | +| 存储类型 | 用途 | 数据持久化 | JSON 支持 | 适用场景 | +| -------------- | --------- | ---------- | --------- | ------------------- | +| **Memory** | 开发/测试 | ❌ 无 | ✅ 原生 | 本地开发、单元测试 | +| **PostgreSQL** | 生产推荐 | ✅ 持久化 | ✅ JSONB | 复杂查询、全文搜索 | +| **MySQL 8.0+** | 生产可选 | ✅ 持久化 | ✅ JSON | 已有 MySQL 基础设施 | ## 📐 数据模型 @@ -86,28 +86,28 @@ erDiagram **Session 字段说明**: -| 字段 | 类型 | 说明 | 示例 | -|------|------|------|------| -| `id` | string | 会话唯一ID | `"sess-20250113-abc123"` | -| `app_name` | string | 应用名称 | `"my-chatbot"` | -| `user_id` | string | 用户ID | `"user-001"` | -| `agent_id` | string | Agent ID | `"agent-assistant"` | -| `status` | string | 会话状态 | `"active"`, `"completed"`, `"failed"` | -| `metadata` | jsonb/json | 自定义元数据 | `{"version": "1.0", "env": "prod"}` | +| 字段 | 类型 | 说明 | 示例 | +| ---------- | ---------- | ------------ | ------------------------------------- | +| `id` | string | 会话唯一ID | `"sess-20250113-abc123"` | +| `app_name` | string | 应用名称 | `"my-chatbot"` | +| `user_id` | string | 用户ID | `"user-001"` | +| `agent_id` | string | Agent ID | `"agent-assistant"` | +| `status` | string | 会话状态 | `"active"`, `"completed"`, `"failed"` | +| `metadata` | jsonb/json | 自定义元数据 | `{"version": "1.0", "env": "prod"}` | **Event 字段说明**: -| 字段 | 类型 | 说明 | 示例 | -|------|------|------|------| -| `id` | string | 事件唯一ID | `"evt-001"` | -| `session_id` | string | 所属会话ID | `"sess-20250113-abc123"` | -| `invocation_id` | string | 调用ID(工作流追踪) | `"inv-001"` | -| `agent_id` | string | 产生事件的 Agent ID | `"agent-001"` | -| `author` | string | 事件作者 | `"user"`, `"agent"` | -| `content` | jsonb/json | 消息内容 | `{"role": "user", "content": "Hello"}` | -| `actions` | jsonb/json | 事件动作 | `{"escalate": false}` | -| `metadata` | jsonb/json | 事件元数据 | `{"loop_iteration": 1}` | -| `branch` | string | 工作流分支路径 | `"Pipeline.Analyzer"` | +| 字段 | 类型 | 说明 | 示例 | +| --------------- | ---------- | -------------------- | -------------------------------------- | +| `id` | string | 事件唯一ID | `"evt-001"` | +| `session_id` | string | 所属会话ID | `"sess-20250113-abc123"` | +| `invocation_id` | string | 调用ID(工作流追踪) | `"inv-001"` | +| `agent_id` | string | 产生事件的 Agent ID | `"agent-001"` | +| `author` | string | 事件作者 | `"user"`, `"agent"` | +| `content` | jsonb/json | 消息内容 | `{"role": "user", "content": "Hello"}` | +| `actions` | jsonb/json | 事件动作 | `{"escalate": false}` | +| `metadata` | jsonb/json | 事件元数据 | `{"loop_iteration": 1}` | +| `branch` | string | 工作流分支路径 | `"Pipeline.Analyzer"` | ### 索引优化 @@ -250,6 +250,7 @@ for _, event := range events { ``` **性能对比**: + - 批量插入:~10ms(100条事件) - 逐条插入:~1000ms(100条事件,每条10ms) @@ -358,17 +359,18 @@ func cleanupOldSessions(service SessionService) { ### PostgreSQL vs MySQL -| 特性 | PostgreSQL | MySQL 8.0+ | 说明 | -|------|-----------|-----------|------| -| **JSON 查询** | ✅ 优秀 (JSONB) | ✅ 良好 (JSON) | PG 的 JSONB 性能更好 | -| **全文搜索** | ✅ 内置 | ⚠️ 需配置 | PG 开箱即用 | -| **复杂查询** | ✅ 强大 | ✅ 良好 | PG 支持更多高级特性 | -| **并发性能** | ✅ MVCC | ✅ InnoDB | 都支持高并发 | -| **生态成熟度** | ✅ 活跃 | ✅ 活跃 | 两者都很成熟 | -| **云服务支持** | ✅ 广泛 | ✅ 广泛 | AWS、GCP、Azure 都支持 | -| **部署成本** | 💰 中 | 💰 低 | MySQL 部署稍简单 | +| 特性 | PostgreSQL | MySQL 8.0+ | 说明 | +| -------------- | --------------- | -------------- | ---------------------- | +| **JSON 查询** | ✅ 优秀 (JSONB) | ✅ 良好 (JSON) | PG 的 JSONB 性能更好 | +| **全文搜索** | ✅ 内置 | ⚠️ 需配置 | PG 开箱即用 | +| **复杂查询** | ✅ 强大 | ✅ 良好 | PG 支持更多高级特性 | +| **并发性能** | ✅ MVCC | ✅ InnoDB | 都支持高并发 | +| **生态成熟度** | ✅ 活跃 | ✅ 活跃 | 两者都很成熟 | +| **云服务支持** | ✅ 广泛 | ✅ 广泛 | AWS、GCP、Azure 都支持 | +| **部署成本** | 💰 中 | 💰 低 | MySQL 部署稍简单 | **推荐决策**: + - ✅ **选择 PostgreSQL**: 需要复杂 JSON 查询、全文搜索、高级分析 - ✅ **选择 MySQL**: 已有 MySQL 基础设施、简单查询为主、成本敏感 diff --git a/docs/content/02.core-concepts/9.skills-system.md b/docs/content/02.core-concepts/9.skills-system.md index 101c9ee..90604b1 100644 --- a/docs/content/02.core-concepts/9.skills-system.md +++ b/docs/content/02.core-concepts/9.skills-system.md @@ -46,12 +46,12 @@ Skills 是 aster 的基于文件系统的“技能包”系统。它允许你把 ### Skills vs 其他扩展方式 -| 特性 | Skills | Custom Tools | Slash Commands | -|------|--------|--------------|----------------| -| **用途** | 知识库注入 | 执行操作 | 快捷指令 | -| **触发方式** | 自动/关键词 | Agent主动调用 | 用户输入 | -| **内容形式** | Markdown文档 | Go代码 | 命令脚本 | -| **适用场景** | 领域知识、规范 | 文件操作、API | 快速启动 | +| 特性 | Skills | Custom Tools | Slash Commands | +| ------------ | -------------- | ------------- | -------------- | +| **用途** | 知识库注入 | 执行操作 | 快捷指令 | +| **触发方式** | 自动/关键词 | Agent主动调用 | 用户输入 | +| **内容形式** | Markdown文档 | Go代码 | 命令脚本 | +| **适用场景** | 领域知识、规范 | 文件操作、API | 快速启动 | ## 📦 Skill 定义 @@ -79,6 +79,7 @@ workspace/skills/ ``` **目录要求**: + - ✅ 必须包含 `SKILL.md` 定义文件 - ❌ 可选:`scripts/` 工具脚本目录 - ❌ 可选:`README.md` 详细文档 @@ -94,7 +95,7 @@ name: markdown-segment-translator description: 将长Markdown文档分段翻译,保持格式和术语准确性。适用于“翻译整篇 Markdown 文档”之类的请求。 allowed-tools: ["Bash", "Read", "Write"] -version: 2.0.0 # 可选:版本号 +version: 2.0.0 # 可选:版本号 --- # Markdown 分段翻译技能 @@ -132,13 +133,13 @@ version: 2.0.0 # 可选:版本号 ### 元数据字段说明 -| 字段 | 类型 | 必需 | 说明 | -|------|------|------|------| -| `name` | string | ✅ | Skill 唯一标识符,1–64 个字符,只能包含小写字母、数字和连字符 | -| `description` | string | ✅ | Skill 做什么、什么时候用,建议明确写出触发场景 | -| `allowed-tools` | []string | ❌ | 建议使用的工具列表,例如 `["Read","Write","Bash"]` | +| 字段 | 类型 | 必需 | 说明 | +| --------------- | -------- | ---- | ------------------------------------------------------------- | +| `name` | string | ✅ | Skill 唯一标识符,1–64 个字符,只能包含小写字母、数字和连字符 | +| `description` | string | ✅ | Skill 做什么、什么时候用,建议明确写出触发场景 | +| `allowed-tools` | []string | ❌ | 建议使用的工具列表,例如 `["Read","Write","Bash"]` | -> 注意:当前版本中,Skills 注入器不会根据 `triggers` 自动筛选技能。 +> 注意:当前版本中,Skills 注入器不会根据 `triggers` 自动筛选技能。 > 你仍然可以在 YAML 中声明 `triggers` 等扩展字段,但它们更多用于自定义过滤逻辑、UI 展示或文档说明,而不是内置激活机制。 ## 🔔 触发元数据(可选) @@ -156,6 +157,7 @@ triggers: ``` **示例**: + ```go // 用户输入:"帮我检查一下角色一致性" // → 触发 consistency-checker Skill @@ -172,6 +174,7 @@ triggers: ``` **适用场景**: + - 特定 Slash Command 执行期间 - 特定工作流程阶段 - Agent 处于特定模式 @@ -186,6 +189,7 @@ triggers: ``` **适用场景**: + - 核心工作规范 - 必须遵守的安全准则 - 通用最佳实践 @@ -201,11 +205,13 @@ triggers: ``` **适用场景**: + - Markdown文档处理 - PDF文件操作 - 特定文件类型专用知识 **示例**: + ```go // 用户输入:"翻译 document.md" // → 触发 markdown-segment-translator Skill(关键词 + 文件扩展名) @@ -226,6 +232,7 @@ triggers: ``` 这样设计的好处: + - 关键词触发:用户明确表达翻译意图 - 文件触发:自动识别Markdown文件 - 上下文触发:在翻译命令期间自动激活 @@ -350,23 +357,23 @@ ag, err := agent.Create(ctx, &types.AgentConfig{ aster 提供了4个生产级 Skills 示例,可直接使用或作为参考: -| Skill | 功能 | 适用场景 | -|-------|------|----------| +| Skill | 功能 | 适用场景 | +| ------------------------------------------------------------------- | ---------------- | ------------------ | | [markdown-segment-translator](/examples/skills/markdown-translator) | Markdown分段翻译 | 文档翻译、性能优化 | -| pdf | PDF处理工具集 | PDF转换、表单填写 | -| pdfmd | PDF快速提取 | 学术论文阅读 | -| consistency-checker | 写作一致性检查 | 创意写作 | +| pdf | PDF处理工具集 | PDF转换、表单填写 | +| pdfmd | PDF快速提取 | 学术论文阅读 | +| consistency-checker | 写作一致性检查 | 创意写作 | 查看所有示例:[Skills 示例](/examples/skills/) ### 支持的存储方式 -| 存储类型 | Path 格式 | 说明 | -|---------|-----------|------| -| 本地文件系统 | `./path/to/skills` | 开发测试推荐 | -| 阿里云OSS | `oss://bucket/prefix` | 生产环境推荐 | -| AWS S3 | `s3://bucket/prefix` | 跨区域部署 | -| HTTP(S) | `https://cdn.com/skills` | CDN分发 | +| 存储类型 | Path 格式 | 说明 | +| ------------ | ------------------------ | ------------ | +| 本地文件系统 | `./path/to/skills` | 开发测试推荐 | +| 阿里云OSS | `oss://bucket/prefix` | 生产环境推荐 | +| AWS S3 | `s3://bucket/prefix` | 跨区域部署 | +| HTTP(S) | `https://cdn.com/skills` | CDN分发 | ## 🎨 使用场景 @@ -384,11 +391,13 @@ triggers: # 写作最佳实践 ## 结构 + - 开头:吸引注意力的钩子 - 中间:逻辑清晰的论述 - 结尾:有力的总结 ## 风格 + - 使用主动语态 - 避免冗余表达 - 保持段落简短 @@ -411,11 +420,13 @@ triggers: # Go代码审查清单 ## 错误处理 + - 所有错误必须检查 - 使用errors.Is/As判断错误类型 - 返回有意义的错误信息 ## 并发安全 + - 检查共享数据的保护 - 避免goroutine泄漏 - 正确使用context @@ -460,6 +471,7 @@ triggers: ### 1. Skill 粒度设计 **推荐**:细粒度、单一职责 + ``` ✅ coding-standards.md (代码规范) ✅ security-checklist.md (安全检查) @@ -467,6 +479,7 @@ triggers: ``` **不推荐**:大而全的 Skill + ``` ❌ everything.md (包含所有规范) ``` @@ -484,35 +497,43 @@ triggers: # Skill 名称 ## 概述 + 简短说明 Skill 的用途 ## 核心规则 + 关键规则和原则 ## 检查清单 + 可操作的步骤列表 ## 示例 + 正确和错误的对比示例 ## 参考资料 + 相关文档链接 ``` ### 4. 性能优化 **Skill 大小控制**: + - **推荐大小**:≤ 2000 tokens/Skill - **延迟加载**:避免使用过多 `always` 触发 - **缓存策略**:频繁使用的 Skill 可以预加载 **分段处理策略**: 对于大文档处理类 Skill(如翻译),采用分段策略: + - 自动分段:200-500行/段 - 配合 ExecutionMode.NonStreaming 加速 - 实测可获得 3-5 倍性能提升 **示例**: + ```go // 配置非流式模式以优化Skills性能 ModelConfig: &types.ModelConfig{ diff --git a/docs/content/03.providers/gemini.md b/docs/content/03.providers/gemini.md index 78309f8..867b0d4 100644 --- a/docs/content/03.providers/gemini.md +++ b/docs/content/03.providers/gemini.md @@ -40,13 +40,13 @@ provider, err := factory.Create(config) ### 支持的模型 -| 模型 | 特点 | Context | 推荐场景 | -|------|------|---------|------------| -| `gemini-2.0-flash-exp` | 最新实验版 | 1M | 通用场景 | -| `gemini-2.0-flash-thinking-exp-1219` | 推理模型 | 32K | 复杂推理 | -| `gemini-1.5-pro` | 稳定高性能 | 2M | 长文档分析 | -| `gemini-1.5-flash` | 快速响应 | 1M | 实时应用 | -| `gemini-1.5-flash-8b` | 成本优化 | 1M | 简单任务 | +| 模型 | 特点 | Context | 推荐场景 | +| ------------------------------------ | ---------- | ------- | ---------- | +| `gemini-2.0-flash-exp` | 最新实验版 | 1M | 通用场景 | +| `gemini-2.0-flash-thinking-exp-1219` | 推理模型 | 32K | 复杂推理 | +| `gemini-1.5-pro` | 稳定高性能 | 2M | 长文档分析 | +| `gemini-1.5-flash` | 快速响应 | 1M | 实时应用 | +| `gemini-1.5-flash-8b` | 成本优化 | 1M | 简单任务 | ## 使用示例 @@ -291,12 +291,12 @@ config.Provider = "google" // ✅ ### 输入/输出 Token 定价(2024年) -| 模型 | 输入 | 输出 | 缓存输入 | -|------|------|------|----------| -| Gemini 2.0 Flash | 免费* | 免费* | 免费* | -| Gemini 1.5 Pro | $1.25/1M | $5/1M | $0.31/1M | -| Gemini 1.5 Flash | $0.075/1M | $0.30/1M | $0.019/1M | -| Gemini 1.5 Flash-8B | $0.0375/1M | $0.15/1M | $0.01/1M | +| 模型 | 输入 | 输出 | 缓存输入 | +| ------------------- | ---------- | -------- | --------- | +| Gemini 2.0 Flash | 免费\* | 免费\* | 免费\* | +| Gemini 1.5 Pro | $1.25/1M | $5/1M | $0.31/1M | +| Gemini 1.5 Flash | $0.075/1M | $0.30/1M | $0.019/1M | +| Gemini 1.5 Flash-8B | $0.0375/1M | $0.15/1M | $0.01/1M | \* 2.0 Flash 实验版免费使用,但有速率限制 @@ -460,6 +460,7 @@ Gemini 是唯一原生支持视频输入的主流 Provider: ### Q: Context Caching 如何计费? 缓存的 tokens 按正常输入价格的 25% 计费。例如 Gemini 1.5 Pro: + - 正常输入: $1.25/1M tokens - 缓存输入: $0.31/1M tokens(节省 75%) diff --git a/docs/content/03.providers/openai.md b/docs/content/03.providers/openai.md index f7e87ea..96dd653 100644 --- a/docs/content/03.providers/openai.md +++ b/docs/content/03.providers/openai.md @@ -38,14 +38,14 @@ provider, err := factory.Create(config) ### 支持的模型 -| 模型 | 特点 | Context | 推荐场景 | -|------|------|---------|---------| -| `gpt-4o` | 最新多模态 | 128K | 通用场景 | -| `gpt-4o-mini` | 成本优化 | 128K | 简单任务 | -| `gpt-4-turbo` | 高性能 | 128K | 复杂推理 | -| `o1-preview` | 推理模型 | 100K | 复杂问题 | -| `o1-mini` | 快速推理 | 100K | 代码生成 | -| `o3-mini` | 最新推理 | 100K | 科学计算 | +| 模型 | 特点 | Context | 推荐场景 | +| ------------- | ---------- | ------- | -------- | +| `gpt-4o` | 最新多模态 | 128K | 通用场景 | +| `gpt-4o-mini` | 成本优化 | 128K | 简单任务 | +| `gpt-4-turbo` | 高性能 | 128K | 复杂推理 | +| `o1-preview` | 推理模型 | 100K | 复杂问题 | +| `o1-mini` | 快速推理 | 100K | 代码生成 | +| `o3-mini` | 最新推理 | 100K | 科学计算 | ## 使用示例 @@ -198,12 +198,12 @@ config := &types.ModelConfig{ ### 输入/输出 Token 定价(2024年) -| 模型 | 输入 | 输出 | 缓存输入 | -|------|------|------|----------| -| GPT-4o | $2.5/1M | $10/1M | $1.25/1M | +| 模型 | 输入 | 输出 | 缓存输入 | +| ----------- | -------- | ------- | --------- | +| GPT-4o | $2.5/1M | $10/1M | $1.25/1M | | GPT-4o-mini | $0.15/1M | $0.6/1M | $0.075/1M | -| o1-preview | $15/1M | $60/1M | - | -| o1-mini | $3/1M | $12/1M | - | +| o1-preview | $15/1M | $60/1M | - | +| o1-mini | $3/1M | $12/1M | - | **Prompt Caching 可节省 50% 输入成本!** diff --git a/docs/content/03.providers/overview.md b/docs/content/03.providers/overview.md index 66f902a..2e0580c 100644 --- a/docs/content/03.providers/overview.md +++ b/docs/content/03.providers/overview.md @@ -6,24 +6,24 @@ aster 支持 10+ 个主流 AI Provider,覆盖国际和中国市场。 ### 🌍 国际主流 -| Provider | 特点 | 配置名称 | 文档 | -|----------|------|---------|------| -| **OpenAI** | 最流行,GPT-4/o1/o3 | `openai` | [详细文档](./openai.md) | -| **Anthropic** | Claude 系列 | `anthropic` | [详细文档](./anthropic.md) | -| **Gemini** | 超长上下文 1M,视频理解 | `gemini`, `google` | [详细文档](./gemini.md) | -| **Groq** | 超快推理速度 | `groq` | [详细文档](./groq.md) | -| **OpenRouter** | 聚合平台,数百模型 | `openrouter` | [详细文档](./openrouter.md) | -| **Mistral** | 欧洲主流,开源友好 | `mistral` | [详细文档](./mistral.md) | -| **Ollama** | 本地部署首选 | `ollama` | [详细文档](./ollama.md) | +| Provider | 特点 | 配置名称 | 文档 | +| -------------- | ----------------------- | ------------------ | --------------------------- | +| **OpenAI** | 最流行,GPT-4/o1/o3 | `openai` | [详细文档](./openai.md) | +| **Anthropic** | Claude 系列 | `anthropic` | [详细文档](./anthropic.md) | +| **Gemini** | 超长上下文 1M,视频理解 | `gemini`, `google` | [详细文档](./gemini.md) | +| **Groq** | 超快推理速度 | `groq` | [详细文档](./groq.md) | +| **OpenRouter** | 聚合平台,数百模型 | `openrouter` | [详细文档](./openrouter.md) | +| **Mistral** | 欧洲主流,开源友好 | `mistral` | [详细文档](./mistral.md) | +| **Ollama** | 本地部署首选 | `ollama` | [详细文档](./ollama.md) | ### 🇨🇳 中国市场 -| Provider | 特点 | 配置名称 | 文档 | -|----------|------|---------|------| -| **DeepSeek** | R1 推理模型 | `deepseek` | [详细文档](./deepseek.md) | -| **智谱 GLM** | ChatGLM 系列 | `glm`, `zhipu` | [详细文档](./glm.md) | -| **豆包 Doubao** | 字节跳动企业级 | `doubao`, `bytedance` | [详细文档](./doubao.md) | -| **月之暗面 Kimi** | 长上下文 200K | `moonshot`, `kimi` | [详细文档](./moonshot.md) | +| Provider | 特点 | 配置名称 | 文档 | +| ----------------- | -------------- | --------------------- | ------------------------- | +| **DeepSeek** | R1 推理模型 | `deepseek` | [详细文档](./deepseek.md) | +| **智谱 GLM** | ChatGLM 系列 | `glm`, `zhipu` | [详细文档](./glm.md) | +| **豆包 Doubao** | 字节跳动企业级 | `doubao`, `bytedance` | [详细文档](./doubao.md) | +| **月之暗面 Kimi** | 长上下文 200K | `moonshot`, `kimi` | [详细文档](./moonshot.md) | ## 快速开始 @@ -73,20 +73,21 @@ config.APIKey = "" // Ollama 不需要 API Key ## 功能对比 -| 功能 | OpenAI | Anthropic | Gemini | Groq | OpenRouter | Mistral | Ollama | DeepSeek | GLM | Doubao | Moonshot | -|------|--------|-----------|--------|------|------------|---------|--------|----------|-----|--------|----------| -| 流式输出 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | -| 工具调用 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | -| 视觉输入 | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ⚠️ | ❌ | ⚠️ | ⚠️ | ❌ | -| 音频输入 | ✅ | ❌ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | -| 视频输入 | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | -| 推理模型 | ✅ o1/o3 | ❌ | ✅ Thinking | ❌ | ✅ | ✅ | ❌ | ✅ R1 | ❌ | ❌ | ❌ | -| Prompt Cache | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | -| 超长上下文 | 128K | 200K | 1M-2M | 128K | - | 128K | 128K | 64K | 128K | 128K | 200K | -| 本地部署 | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | -| 无需 API Key | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | +| 功能 | OpenAI | Anthropic | Gemini | Groq | OpenRouter | Mistral | Ollama | DeepSeek | GLM | Doubao | Moonshot | +| ------------ | -------- | --------- | ----------- | ---- | ---------- | ------- | ------ | -------- | ---- | ------ | -------- | +| 流式输出 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | +| 工具调用 | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | +| 视觉输入 | ✅ | ✅ | ✅ | ❌ | ✅ | ✅ | ⚠️ | ❌ | ⚠️ | ⚠️ | ❌ | +| 音频输入 | ✅ | ❌ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | +| 视频输入 | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | +| 推理模型 | ✅ o1/o3 | ❌ | ✅ Thinking | ❌ | ✅ | ✅ | ❌ | ✅ R1 | ❌ | ❌ | ❌ | +| Prompt Cache | ✅ | ✅ | ✅ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | +| 超长上下文 | 128K | 200K | 1M-2M | 128K | - | 128K | 128K | 64K | 128K | 128K | 200K | +| 本地部署 | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | +| 无需 API Key | ❌ | ❌ | ❌ | ❌ | ❌ | ❌ | ✅ | ❌ | ❌ | ❌ | ❌ | **图例**: + - ✅ 完全支持 - ⚠️ 部分模型支持 - ❌ 不支持 diff --git a/docs/content/03.providers/usage.md b/docs/content/03.providers/usage.md index 8cafefb..5558f6f 100644 --- a/docs/content/03.providers/usage.md +++ b/docs/content/03.providers/usage.md @@ -51,7 +51,7 @@ config.Model = "deepseek-chat" 如果你需要更细节的多模态/视频/Prompt Cache 说明: -- OpenAI 细节: 支持 o1/o3、Prompt Caching、多模态等; +- OpenAI 细节: 支持 o1/o3、Prompt Caching、多模态等; - Gemini 细节: 支持 1M+ 上下文、视频理解。 出于简洁考虑,这些细节保存在独立页面中,但默认不在左侧导航中显示: @@ -85,7 +85,8 @@ config := &types.AgentConfig{ 这样既保留了多 Provider 兼容能力, 又不会在文档上堆积大量重复/冗长的说明。 -## 5. ExecutionMode 配置 +## 5. ExecutionMode 配置 + aster 现在支持配置执行模式,优化不同场景的性能: ```go @@ -99,11 +100,11 @@ config := &types.ModelConfig{ ### 执行模式类型 -| 模式 | 说明 | 适用场景 | 性能 | -|------|------|---------|------| -| `ExecutionModeStreaming` | 流式输出(默认) | 交互式对话、实时反馈 | 用户体验好 | -| `ExecutionModeNonStreaming` | 非流式批处理 | 翻译、批量处理 | **速度快3-5倍** | -| `ExecutionModeAuto` | 自动选择 | 通用场景 | 智能优化 | +| 模式 | 说明 | 适用场景 | 性能 | +| --------------------------- | ---------------- | -------------------- | --------------- | +| `ExecutionModeStreaming` | 流式输出(默认) | 交互式对话、实时反馈 | 用户体验好 | +| `ExecutionModeNonStreaming` | 非流式批处理 | 翻译、批量处理 | **速度快3-5倍** | +| `ExecutionModeAuto` | 自动选择 | 通用场景 | 智能优化 | ### 使用示例 @@ -125,9 +126,8 @@ translateConfig := &types.ModelConfig{ ### 性能对比 -| 任务 | Streaming | NonStreaming | 性能提升 | -|------|-----------|--------------|---------| -| 翻译200行文档 | 30秒 | 5-10秒 | **3-5倍** | -| Token消耗 | 标准 | 降低20% | **更省钱** | -| 用户体验 | 实时反馈 | 快速完成 | 各有优势 | - +| 任务 | Streaming | NonStreaming | 性能提升 | +| ------------- | --------- | ------------ | ---------- | +| 翻译200行文档 | 30秒 | 5-10秒 | **3-5倍** | +| Token消耗 | 标准 | 降低20% | **更省钱** | +| 用户体验 | 实时反馈 | 快速完成 | 各有优势 | diff --git a/docs/content/04.memory/1.overview.md b/docs/content/04.memory/1.overview.md index 71a654b..0a1e358 100644 --- a/docs/content/04.memory/1.overview.md +++ b/docs/content/04.memory/1.overview.md @@ -23,4 +23,3 @@ aster 的记忆系统分为三个层级, 对应不同的作用域与存储后端 6. [Memory 后端适配](/guides/memory-backends) – 各种后端类型与配置方式。 > 本章节主要作为导航页, 详细内容请跳转到对应的指南与示例。 - diff --git a/docs/content/04.memory/2.short-vs-long.md b/docs/content/04.memory/2.short-vs-long.md index 1cc89f9..5988a95 100644 --- a/docs/content/04.memory/2.short-vs-long.md +++ b/docs/content/04.memory/2.short-vs-long.md @@ -50,4 +50,3 @@ navigation: - 会话过程中使用短期记忆维持状态与上下文; - 在关键时刻(例如“请记住我的偏好/秘密/配置”)将信息「上岸」为长期记忆。 - diff --git a/docs/content/04.memory/3.semantic-workflow.md b/docs/content/04.memory/3.semantic-workflow.md index 33a6c76..07fb169 100644 --- a/docs/content/04.memory/3.semantic-workflow.md +++ b/docs/content/04.memory/3.semantic-workflow.md @@ -39,4 +39,3 @@ navigation: - 在工作流中显式区分: - 「检索上下文」步骤; - 「调用模型生成答案」步骤。 - diff --git a/docs/content/04.memory/4.backends.md b/docs/content/04.memory/4.backends.md index e8f1ed8..4fa0554 100644 --- a/docs/content/04.memory/4.backends.md +++ b/docs/content/04.memory/4.backends.md @@ -27,4 +27,3 @@ navigation: - Embedder: `mock` / `openai` / 自定义实现。 配置示例与参数表请参考: [Memory 后端适配](/guides/memory-backends)。 - diff --git a/docs/content/04.memory/5.provenance.md b/docs/content/04.memory/5.provenance.md index 5670afb..30b4f78 100644 --- a/docs/content/04.memory/5.provenance.md +++ b/docs/content/04.memory/5.provenance.md @@ -255,16 +255,16 @@ sm.IndexWithProvenance(ctx, "user-profile", profileText, meta, 本实现完全对齐 Google "Context Engineering: Sessions, Memory" 白皮书的要求: -| 白皮书要求 | aster 实现 | 状态 | -|-----------|--------------|------| -| Memory Provenance | ✅ MemoryProvenance 结构 | 完整 | -| Source Type Tracking | ✅ 4种来源类型 | 完整 | -| Confidence Scoring | ✅ ConfidenceCalculator | 完整 | -| Time Decay | ✅ 指数衰减模型 | 完整 | -| Corroboration | ✅ Corroborate() 方法 | 完整 | -| Lineage Tracking | ✅ LineageManager | 完整 | -| Cascade Deletion | ✅ DeleteMemoryWithLineage() | 完整 | -| Data Source Revocation | ✅ RevokeDataSource() | 完整 | +| 白皮书要求 | aster 实现 | 状态 | +| ---------------------- | ---------------------------- | ---- | +| Memory Provenance | ✅ MemoryProvenance 结构 | 完整 | +| Source Type Tracking | ✅ 4种来源类型 | 完整 | +| Confidence Scoring | ✅ ConfidenceCalculator | 完整 | +| Time Decay | ✅ 指数衰减模型 | 完整 | +| Corroboration | ✅ Corroborate() 方法 | 完整 | +| Lineage Tracking | ✅ LineageManager | 完整 | +| Cascade Deletion | ✅ DeleteMemoryWithLineage() | 完整 | +| Data Source Revocation | ✅ RevokeDataSource() | 完整 | ## 测试 @@ -275,6 +275,7 @@ go test ./pkg/memory/... -v ``` 测试覆盖: + - ✅ Provenance 创建和元数据转换 - ✅ 置信度计算和时间衰减 - ✅ 多源验证和置信度提升 diff --git a/docs/content/04.memory/6.consolidation.md b/docs/content/04.memory/6.consolidation.md index 40bb07d..456e7f8 100644 --- a/docs/content/04.memory/6.consolidation.md +++ b/docs/content/04.memory/6.consolidation.md @@ -25,16 +25,19 @@ Memory Consolidation 是 aster 的智能内存管理功能,可以自动检测 ### 合并策略 **1. Redundancy Strategy (冗余合并)** + - 检测高度相似的重复记忆 - 合并为单条精炼的记忆 - 适用场景:用户多次表达相同信息 **2. Conflict Resolution Strategy (冲突解决)** + - 检测矛盾或不一致的信息 - 根据置信度和新鲜度选择最佳版本 - 适用场景:信息更新、纠错 **3. Summarization Strategy (总结)** + - 将多条相关记忆总结为概括性表述 - 减少记忆数量,提高检索效率 - 适用场景:长期记忆管理 @@ -181,6 +184,7 @@ strategy := memory.NewRedundancyStrategy(0.85) ``` **特点**: + - 保留所有重要信息 - 消除重复表述 - 提升记忆质量 @@ -201,6 +205,7 @@ strategy := memory.NewConflictResolutionStrategy(0.75, calc) ``` **特点**: + - 基于置信度权衡 - 考虑记忆新鲜度 - 保留历史变化 @@ -224,6 +229,7 @@ strategy := memory.NewSummarizationStrategy(5) // 每组最多 5 条 ``` **特点**: + - 压缩信息密度 - 保持关键事实 - 提高检索效率 diff --git a/docs/content/04.memory/9.session-compression.md b/docs/content/04.memory/9.session-compression.md index ea03be7..b28ca43 100644 --- a/docs/content/04.memory/9.session-compression.md +++ b/docs/content/04.memory/9.session-compression.md @@ -108,6 +108,7 @@ summarizer := memory.NewLLMSummarizer(config) ``` **特点**: + - 压缩比率: ~60-70% - 保留内容: 关键对话、具体数据、重要细节 - 适用场景: 技术讨论、数据分析、详细需求 @@ -125,6 +126,7 @@ summarizer := memory.NewLLMSummarizer(config) ``` **特点**: + - 压缩比率: ~40-50% - 保留内容: 核心观点、关键决策、重要结论 - 适用场景: 一般对话、需求讨论、问题解决 @@ -142,6 +144,7 @@ summarizer := memory.NewLLMSummarizer(config) ``` **特点**: + - 压缩比率: ~20-30% - 保留内容: 核心结论、最终决策 - 适用场景: 历史会话归档、长期存储 diff --git a/docs/content/05.tools/2.builtin/1.builtin.md b/docs/content/05.tools/2.builtin/1.builtin.md index 781bb76..dbc5846 100644 --- a/docs/content/05.tools/2.builtin/1.builtin.md +++ b/docs/content/05.tools/2.builtin/1.builtin.md @@ -11,25 +11,26 @@ aster 提供了一组开箱即用的内置工具,无需配置即可使用。本 ## 📦 工具列表 -| 工具名称 | 功能 | 沙箱 | 示例 | -|---------|------|------|------| -| `Read` | 读取文件 | ✅ | [→](#read) | -| `Write` | 写入文件 | ✅ | [→](#write) | -| `Edit` | 编辑文件 | ✅ | [→](#edit) | -| `Glob` | 文件匹配 | ✅ | [→](#glob) | -| `Grep` | 文本搜索 | ✅ | [→](#grep) | -| `Bash` | 执行命令 | ✅ | [→](#bash) | -| `TodoWrite` | 任务管理 | ✅ | [→](#todowrite) | -| `Task` | 子任务执行 | ✅ | [→](#task) | -| `HttpRequest` | HTTP 请求 | ❌ | [→](#httprequest) | -| `WebSearch` | 网络搜索 | ❌ | [→](#websearch) | -| `Skill` | 技能调用 | ✅ | [→](#skill) | -| `SemanticSearch` | 语义搜索 | ✅ | [→](#semanticsearch) | -| `EnterPlanMode` | 进入规划模式 | ❌ | [→](#enterplanmode) | -| `ExitPlanMode` | 退出规划模式 | ❌ | [→](#exitplanmode) | -| `AskUserQuestion` | 结构化提问 | ❌ | [→](#askuserquestion) | +| 工具名称 | 功能 | 沙箱 | 示例 | +| ----------------- | ------------ | ---- | --------------------- | +| `Read` | 读取文件 | ✅ | [→](#read) | +| `Write` | 写入文件 | ✅ | [→](#write) | +| `Edit` | 编辑文件 | ✅ | [→](#edit) | +| `Glob` | 文件匹配 | ✅ | [→](#glob) | +| `Grep` | 文本搜索 | ✅ | [→](#grep) | +| `Bash` | 执行命令 | ✅ | [→](#bash) | +| `TodoWrite` | 任务管理 | ✅ | [→](#todowrite) | +| `Task` | 子任务执行 | ✅ | [→](#task) | +| `HttpRequest` | HTTP 请求 | ❌ | [→](#httprequest) | +| `WebSearch` | 网络搜索 | ❌ | [→](#websearch) | +| `Skill` | 技能调用 | ✅ | [→](#skill) | +| `SemanticSearch` | 语义搜索 | ✅ | [→](#semanticsearch) | +| `EnterPlanMode` | 进入规划模式 | ❌ | [→](#enterplanmode) | +| `ExitPlanMode` | 退出规划模式 | ❌ | [→](#exitplanmode) | +| `AskUserQuestion` | 结构化提问 | ❌ | [→](#askuserquestion) | **沙箱说明:** + - ✅ - 在沙箱中执行,文件操作限制在工作目录内 - ❌ - 直接执行,访问外部网络资源 @@ -490,7 +491,7 @@ result, err := ag.Chat(ctx, "请向 API 发送用户创建请求") { "ok": true, "status_code": 200, - "headers": {"Content-Type": "application/json"}, + "headers": { "Content-Type": "application/json" }, "body": "{...}", "duration_ms": 156 } @@ -594,6 +595,7 @@ result, err := ag.Chat(ctx, "请语义搜索关于数据库优化的文档") 进入规划模式,用于复杂任务的规划阶段。在此模式下只允许只读操作和计划文件写入。 **使用场景:** + - 多种有效方案 - 任务可以用多种方式解决,需要权衡 - 重大架构决策 - 需要在架构模式之间做选择 - 大规模变更 - 任务涉及多个文件或系统 @@ -623,7 +625,15 @@ result, err := ag.Chat(ctx, "这个任务比较复杂,我需要先规划一下 "ok": true, "plan_file_path": ".aster/plans/sunny-singing-nygaard.md", "plan_id": "sunny-singing-nygaard", - "allowed_tools": ["Read", "Glob", "Grep", "WebFetch", "WebSearch", "AskUserQuestion", "Write"], + "allowed_tools": [ + "Read", + "Glob", + "Grep", + "WebFetch", + "WebSearch", + "AskUserQuestion", + "Write" + ], "workflow": "## Plan Mode Workflow\n...", "message": "Plan mode activated. You can now explore the codebase and create your plan.", "next_steps": [ @@ -642,6 +652,7 @@ result, err := ag.Chat(ctx, "这个任务比较复杂,我需要先规划一下 ``` **规划模式限制:** + - ✅ 允许:Read, Glob, Grep(读取文件) - ✅ 允许:WebFetch, WebSearch(搜索网页) - ✅ 允许:AskUserQuestion(向用户提问) @@ -702,6 +713,7 @@ result, err := ag.Chat(ctx, "规划完成,请用户审批") 向用户提出结构化问题,用于澄清需求、确认方案或收集偏好。 **使用场景:** + - 收集用户偏好或需求 - 澄清模糊的指令 - 获取实施方案的决策 @@ -772,6 +784,7 @@ result, err := ag.Chat(ctx, "你希望使用哪种认证方式?") ``` **注意事项:** + - 用户总是可以选择"Other"来提供自定义输入 - 问题应简洁明了,避免技术术语过多 - 选项描述应解释该选择的含义或影响 @@ -868,6 +881,7 @@ templateRegistry.Register(&types.AgentTemplateDefinition{ ### Q: 工具调用会计入 Token 使用吗? 是的。工具调用的输入和输出都会计入 Token 使用。建议: + - 读取大文件时使用 offset 和 limit - 避免频繁调用同一工具 - 使用 Grep 工具进行文本搜索而不是读取大文件后手动搜索 @@ -889,6 +903,7 @@ config := &types.AgentConfig{ ### Q: 可以禁用某些危险命令吗? 可以。Bash 工具内置了安全检查,会自动阻止危险命令如: + - `rm -rf /` - 系统删除命令 - `sudo rm` - 需要管理员权限的删除 - `dd if=/dev/zero` - 磁盘破坏命令 diff --git a/docs/content/05.tools/2.builtin/2.mcp.md b/docs/content/05.tools/2.builtin/2.mcp.md index 40d6292..bc006d6 100644 --- a/docs/content/05.tools/2.builtin/2.mcp.md +++ b/docs/content/05.tools/2.builtin/2.mcp.md @@ -15,15 +15,16 @@ navigation: **为什么使用 MCP?** -| 特性 | 内置工具 | MCP 工具 | -|------|---------|----------| -| 扩展性 | 需要修改代码 | 动态添加 | -| 维护性 | SDK 内维护 | 独立维护 | -| 复用性 | 绑定到 SDK | 跨平台共享 | -| 部署 | 编译到应用 | 独立部署 | -| 更新 | 需要重新部署 | 热更新 | +| 特性 | 内置工具 | MCP 工具 | +| ------ | ------------ | ---------- | +| 扩展性 | 需要修改代码 | 动态添加 | +| 维护性 | SDK 内维护 | 独立维护 | +| 复用性 | 绑定到 SDK | 跨平台共享 | +| 部署 | 编译到应用 | 独立部署 | +| 更新 | 需要重新部署 | 热更新 | **适用场景:** + - 🔌 连接第三方服务(数据库、API) - 🌐 使用社区工具服务器 - 🔄 动态添加/移除工具 @@ -628,6 +629,7 @@ func addMCPServerDynamically(mcpManager *mcp.MCPManager, endpoint string) { ``` **解决方案:** + 1. 确保 MCP Server 正在运行 2. 检查端点 URL 是否正确 3. 验证网络连接和防火墙设置 @@ -645,6 +647,7 @@ func addMCPServerDynamically(mcpManager *mcp.MCPManager, endpoint string) { ``` **解决方案:** + 1. 检查 `AccessKeyID` 和 `AccessKeySecret` 2. 确认 MCP Server 的认证配置 3. 查看 Server 日志了解详细错误 @@ -656,6 +659,7 @@ Tool not found: my-server:calculator ``` **解决方案:** + 1. 确认 Server 已连接: `mcpManager.GetServer("my-server")` 2. 列出已注册的工具: `server.ListTools()` 3. 检查工具名称格式: `{server_id}:{tool_name}` @@ -667,6 +671,7 @@ Tool not found: my-server:calculator ``` **解决方案:** + ```go // 增加超时时间 server, _ := mcpManager.AddServer(&mcp.MCPServerConfig{ @@ -702,13 +707,13 @@ func printMCPStats(mcpManager *mcp.MCPManager) { ### Q: MCP 工具和内置工具有什么区别? -| 特性 | 内置工具 | MCP 工具 | -|------|---------|----------| -| 部署方式 | 编译到应用 | 独立服务 | -| 网络调用 | 否 | 是 | -| 性能 | 更快 | 稍慢(网络开销) | -| 扩展性 | 需要重新编译 | 动态添加 | -| 适用场景 | 基础功能 | 专业/第三方功能 | +| 特性 | 内置工具 | MCP 工具 | +| -------- | ------------ | ---------------- | +| 部署方式 | 编译到应用 | 独立服务 | +| 网络调用 | 否 | 是 | +| 性能 | 更快 | 稍慢(网络开销) | +| 扩展性 | 需要重新编译 | 动态添加 | +| 适用场景 | 基础功能 | 专业/第三方功能 | ### Q: 可以同时连接多个 MCP Server 吗? diff --git a/docs/content/05.tools/2.builtin/3.custom.md b/docs/content/05.tools/2.builtin/3.custom.md index 9aa472f..2ad05fa 100644 --- a/docs/content/05.tools/2.builtin/3.custom.md +++ b/docs/content/05.tools/2.builtin/3.custom.md @@ -243,7 +243,7 @@ ag.Chat(ctx, "纽约和东京哪个城市更热?") **`commands/analyze.md`:** -```markdown +````markdown --- description: 分析代码质量 argument-hint: [文件路径] @@ -264,6 +264,7 @@ scripts: ## 任务目标 分析指定文件或目录的代码质量,包括: + - 代码风格一致性 - 潜在的 Bug - 性能问题 @@ -292,6 +293,7 @@ scripts: # 代码质量分析报告 ## 概要 + - 文件数: XX - 问题数: XX - 🔴 严重: XX @@ -301,18 +303,21 @@ scripts: ## 详细问题 ### 🔴 严重问题 + 1. [文件:行号] 问题描述 - 建议: 修复方案 ... ``` +```` ## 注意事项 - 分析大型项目时,先询问用户是否继续 - 使用 offset 和 limit 分段读取大文件 - 超时时间设置为 300 秒 -``` + +```` ### 配置 Agent 支持 Slash Commands @@ -365,7 +370,7 @@ func main() { // 使用 Slash Command testSlashCommands(ctx, ag) } -``` +```` ### 使用 Slash Commands @@ -429,6 +434,7 @@ triggers: ## 自动激活条件 当检测到以下情况时,此 Skill 自动激活: + - 用户提到"API 安全"、"认证"、"授权"等关键词 - 正在分析 API 相关代码 - 读取 api/ 或 routes/ 目录的文件 @@ -474,9 +480,9 @@ triggers: ### 修复建议模板 发现问题时,使用此模板提供建议: - ``` -⚠️ 发现安全问题: [问题类型] + +⚠️ 发现安全问题: [问题类型] 📍 位置: [文件:行号] @@ -487,7 +493,9 @@ triggers: [具体修复方案代码] 📚 参考资料: + - [相关文档链接] + ``` ## 使用工具 @@ -658,7 +666,7 @@ triggers: - ORDER BY 排序字段 2. **查询优化** - - 避免 SELECT * + - 避免 SELECT \* - 使用 LIMIT 分页 - 减少子查询 @@ -776,35 +784,41 @@ func (t *BadTool) Execute(...) (interface{}, error) { --- + description: 具体、清晰的描述 argument-hint: [必需参数] [可选参数] -allowed-tools: ["tool1", "tool2"] # 只声明需要的工具 +allowed-tools: ["tool1", "tool2"] # 只声明需要的工具 + --- # 命令名称 ## 任务目标 + 明确说明此命令要完成什么任务 ## 执行步骤 + 1. 第一步做什么 2. 第二步做什么 3. ... ## 输出格式 + 使用 Markdown 代码块展示期望的输出格式 ## 注意事项 + - 重要的提示 - 边界情况处理 ---- -description: 做一些事情 # 太模糊 --- -做点什么... # 没有结构,没有清晰的指导 +## description: 做一些事情 # 太模糊 + +做点什么... # 没有结构,没有清晰的指导 ``` ### 3. Skills 触发条件 @@ -813,28 +827,35 @@ description: 做一些事情 # 太模糊 triggers: - # 关键词: 具体、不冲突 - - type: keyword - keywords: ["API安全", "认证漏洞", "SQL注入"] - # 文件模式: 精确匹配 - - type: file_pattern - patterns: ["**/api/**/*.go", "**/routes/**/*.js"] +# 关键词: 具体、不冲突 - # 上下文: 明确的上下文状态 - - type: context - condition: "security_audit" +- type: keyword + keywords: ["API安全", "认证漏洞", "SQL注入"] + +# 文件模式: 精确匹配 + +- type: file_pattern + patterns: ["**/api/**/*.go", "**/routes/**/*.js"] + +# 上下文: 明确的上下文状态 + +- type: context + condition: "security_audit" triggers: - # 太宽泛,容易误触发 - - type: keyword - keywords: ["代码", "文件", "检查"] - # 模式太宽,匹配所有文件 - - type: file_pattern - patterns: ["**/*"] +# 太宽泛,容易误触发 + +- type: keyword + keywords: ["代码", "文件", "检查"] + +# 模式太宽,匹配所有文件 + +- type: file_pattern + patterns: ["**/*"] ``` ### 4. 错误处理 @@ -868,17 +889,18 @@ func (t *BadTool) Execute(...) (interface{}, error) { ### Q: Tool、Command、Skill 如何选择? -| 场景 | 推荐方式 | 原因 | -|------|---------|------| -| 可复用的基础功能 | Tool 接口 | 跨 Agent 使用 | -| 固定工作流 | Slash Command | 用户主动触发 | -| 领域知识增强 | Agent Skill | AI 自动激活 | -| 第三方 API 集成 | Tool 接口 | 标准化接口 | -| 复杂多步骤任务 | Slash Command | 流程化指导 | +| 场景 | 推荐方式 | 原因 | +| ---------------- | ------------- | ------------- | +| 可复用的基础功能 | Tool 接口 | 跨 Agent 使用 | +| 固定工作流 | Slash Command | 用户主动触发 | +| 领域知识增强 | Agent Skill | AI 自动激活 | +| 第三方 API 集成 | Tool 接口 | 标准化接口 | +| 复杂多步骤任务 | Slash Command | 流程化指导 | ### Q: Skills 会增加 Token 使用吗? 会的。激活的 Skills 会被注入到 SystemPrompt,占用 Token。建议: + - 只启用必需的 Skills - 设计精确的触发条件 - Skills 内容简洁明了 @@ -912,7 +934,7 @@ func TestMyTool_Execute(t *testing.T) { ## 🧠 示例: 封装 Memory 高级语义工具 -在前面的章节中我们介绍了 `memory_search` / `memory_write` 工具以及 `memory.Scope`。 +在前面的章节中我们介绍了 `memory_search` / `memory_write` 工具以及 `memory.Scope`。 在真实业务中,直接让 LLM 操作 namespace/filename 容易出错,推荐封装更高层的语义工具,比如: - `user_preference_write`:写用户偏好记忆 @@ -1216,7 +1238,7 @@ func (t *ResourceNoteTool) Execute(ctx context.Context, input map[string]interfa 在创建 Agent 时: -1. 启用 `filesystem` + `agent_memory` 中间件, 让底层 memory_* 工具可用。 +1. 启用 `filesystem` + `agent_memory` 中间件, 让底层 memory\_\* 工具可用。 2. 在你的自定义中间件或工具注册逻辑中: - 从 middleware stack 中找到 `memory_write` 工具实例。 - 将它注入到 `ToolContext.Services["memory_write"]`。 diff --git a/docs/content/05.tools/2.builtin/4.developing-tools.md b/docs/content/05.tools/2.builtin/4.developing-tools.md index 1fb407b..211311e 100644 --- a/docs/content/05.tools/2.builtin/4.developing-tools.md +++ b/docs/content/05.tools/2.builtin/4.developing-tools.md @@ -258,11 +258,11 @@ graph TB ### 示例数量建议 -| 工具复杂度 | 建议示例数 | 说明 | -|-----------|----------|------| -| 简单工具 | 1-2 个 | 一个典型用例即可 | -| 中等复杂 | 2-3 个 | 覆盖主要场景 | -| 复杂工具 | 3-5 个 | 包含边界情况 | +| 工具复杂度 | 建议示例数 | 说明 | +| ---------- | ---------- | ---------------- | +| 简单工具 | 1-2 个 | 一个典型用例即可 | +| 中等复杂 | 2-3 个 | 覆盖主要场景 | +| 复杂工具 | 3-5 个 | 包含边界情况 | ### 示例质量要求 diff --git a/docs/content/05.tools/2.builtin/index.md b/docs/content/05.tools/2.builtin/index.md index 21a01e8..e9dcfcd 100644 --- a/docs/content/05.tools/2.builtin/index.md +++ b/docs/content/05.tools/2.builtin/index.md @@ -54,6 +54,7 @@ graph TB
**包含工具:** + - `Read` / `Write` - 文件读写 - `Bash` - 命令执行 - `HttpRequest` - HTTP 请求 @@ -74,6 +75,7 @@ graph TB **特性:** + - MCP 协议集成 - 自动工具发现 - 远程工具调用 @@ -94,6 +96,7 @@ graph TB **能力:** + - 实现 Tool 接口 - Slash Commands - Agent Skills @@ -129,6 +132,7 @@ sequenceDiagram ### 核心组件 **1. Tool Registry (工具注册表)** + ```go type Registry interface { // 注册工具 @@ -143,6 +147,7 @@ type Registry interface { ``` **2. Tool 接口** + ```go type Tool interface { // 工具名称 @@ -160,6 +165,7 @@ type Tool interface { ``` **3. Tool Context (工具上下文)** + ```go type ToolContext struct { Sandbox sandbox.Sandbox // 沙箱实例 diff --git a/docs/content/05.tools/3.mcp/overview.md b/docs/content/05.tools/3.mcp/overview.md index b955c8a..d660647 100644 --- a/docs/content/05.tools/3.mcp/overview.md +++ b/docs/content/05.tools/3.mcp/overview.md @@ -6,10 +6,11 @@ navigation: false # MCP HTTP Server 示例 -aster 已经支持作为 MCP 客户端连接外部 MCP Server (`pkg/tools/mcp` + `pkg/sandbox/cloud`)。 +aster 已经支持作为 MCP 客户端连接外部 MCP Server (`pkg/tools/mcp` + `pkg/sandbox/cloud`)。 本示例展示如何使用 `pkg/mcpserver` 将本地工具暴露为一个兼容的 MCP HTTP Server, 方便 IDE/Agent 统一访问项目文档与工具。 示例代码路径: + - `pkg/mcpserver/server.go` - `examples/mcp/server/main.go` - 客户端示例: `examples/mcp/main.go` diff --git a/docs/content/05.tools/4.custom/knowledge-tools.md b/docs/content/05.tools/4.custom/knowledge-tools.md index 47f7b51..aeb4bf1 100644 --- a/docs/content/05.tools/4.custom/knowledge-tools.md +++ b/docs/content/05.tools/4.custom/knowledge-tools.md @@ -6,10 +6,12 @@ weight: 40 > 适用场景:只想要轻量 RAG(向量检索)而不引入完整知识管理器;需要显式控制哪些 Agent 有知识检索能力。 ## 组成 + - 核心管线:`pkg/knowledge/core`(依赖 `VectorStore` + `Embedder`)。 - 工厂:`pkg/tools/knowledge` 提供 `KnowledgeAdd` / `KnowledgeSearch` 工具 **工厂**,不会默认注册到 builtin registry。 ## 快速示例 + ```go import ( "github.com/astercloud/aster/pkg/knowledge/core" @@ -45,10 +47,12 @@ agentCfg := &types.AgentConfig{ ``` ## 输入/输出约定 + - `KnowledgeAdd` 输入:`text`(必填),可选 `id`、`namespace`、`metadata`。返回写入的 chunk ID。 - `KnowledgeSearch` 输入:`query`(必填),可选 `top_k`、`namespace`、`metadata` 过滤。返回 `results: [{id, score, text, metadata}]`。 ## 注意事项 + - 工具不默认注册;需显式添加,避免循环依赖和全局耦合。 - 默认内存向量库 + MockEmbedder 仅用于示例;生产请替换为 pgvector/云向量库和真实 embedder。 - 可与 `structured_output` 中间件搭配,解析工具结果或模型响应的结构化 JSON。 diff --git a/docs/content/05.tools/5.ptc/1.quickstart.md b/docs/content/05.tools/5.ptc/1.quickstart.md index a80b0f5..ec98c22 100644 --- a/docs/content/05.tools/5.ptc/1.quickstart.md +++ b/docs/content/05.tools/5.ptc/1.quickstart.md @@ -10,6 +10,7 @@ description: 5分钟学会使用 Programmatic Tool Calling Programmatic Tool Calling (PTC) 让 LLM 生成的 Python 代码可以直接调用 Aster 工具,实现更强大的编程能力。 ::code-group + ```python [LLM 生成的代码] # 搜索文件 files = await Glob(pattern="*.go", path=".") @@ -21,11 +22,13 @@ content = await Read(path=files[0]) result = content.upper() await Write(path="output.txt", content=result) ``` + :: ## 前置条件 ::steps + ### 安装 Python 依赖 ```bash @@ -37,6 +40,7 @@ pip install aiohttp ```bash export ANTHROPIC_API_KEY="your-api-key" ``` + :: ## 基础示例 @@ -102,6 +106,7 @@ func main() { :: ::code-group + ```go [仅 LLM 调用] AllowedCallers: []string{"direct"} ``` @@ -113,17 +118,18 @@ AllowedCallers: []string{"code_execution_20250825"} ```go [两者都允许 (推荐)] AllowedCallers: []string{"direct", "code_execution_20250825"} ``` + :: ## 可用工具 -| 工具 | 功能 | Python 示例 | -|------|------|-------------| -| `Read` | 读取文件 | `await Read(path="file.txt")` | +| 工具 | 功能 | Python 示例 | +| ------- | -------- | --------------------------------------------- | +| `Read` | 读取文件 | `await Read(path="file.txt")` | | `Write` | 写入文件 | `await Write(path="out.txt", content="data")` | -| `Glob` | 文件搜索 | `await Glob(pattern="*.go")` | -| `Grep` | 内容搜索 | `await Grep(pattern="TODO")` | -| `Bash` | 执行命令 | `await Bash(command="ls -la")` | +| `Glob` | 文件搜索 | `await Glob(pattern="*.go")` | +| `Grep` | 内容搜索 | `await Grep(pattern="TODO")` | +| `Bash` | 执行命令 | `await Bash(command="ls -la")` | ## 本地测试 @@ -142,29 +148,37 @@ go run main.go ::card-group ::card + --- + title: 完整文档 icon: i-lucide-book-open to: /tools/ptc + --- + 深入了解 PTC 架构和高级用法 :: -::card ---- +## ::card + title: 示例程序 icon: i-lucide-code to: /examples + --- + 查看更多实战示例 :: -::card ---- +## ::card + title: 故障排除 icon: i-lucide-help-circle to: /tools/ptc#常见问题 + --- + 解决常见问题 :: :: diff --git a/docs/content/05.tools/5.ptc/2.advanced.md b/docs/content/05.tools/5.ptc/2.advanced.md index aa21323..f964914 100644 --- a/docs/content/05.tools/5.ptc/2.advanced.md +++ b/docs/content/05.tools/5.ptc/2.advanced.md @@ -48,6 +48,7 @@ content = await retry_read("important.txt") ### 并发调用 ::code-group + ```python [串行执行 (慢)] # 耗时: 3秒 (1秒 × 3) file1 = await Read(path="a.txt") @@ -65,6 +66,7 @@ files = await asyncio.gather( Read(path="c.txt"), ) ``` + :: ### 批量处理 @@ -384,29 +386,37 @@ log.Printf("平均延迟: %v", m.totalLatency/time.Duration(m.toolCalls)) ::card-group ::card + --- + title: Anthropic PTC 文档 icon: i-lucide-external-link to: https://docs.anthropic.com/en/docs/build-with-claude/tool-use#programmatic-tool-use-beta + --- + 官方协议规范 :: -::card ---- +## ::card + title: Python asyncio 文档 icon: i-lucide-external-link to: https://docs.python.org/3/library/asyncio.html + --- + 异步编程指南 :: -::card ---- +## ::card + title: aiohttp 文档 icon: i-lucide-external-link to: https://docs.aiohttp.org/ + --- + HTTP 客户端库 :: :: diff --git a/docs/content/05.tools/5.ptc/3.architecture.md b/docs/content/05.tools/5.ptc/3.architecture.md index 2176270..931c9b2 100644 --- a/docs/content/05.tools/5.ptc/3.architecture.md +++ b/docs/content/05.tools/5.ptc/3.architecture.md @@ -44,6 +44,7 @@ type ToolSchema struct { ``` **字段说明:** + - `AllowedCallers`: 指定工具可调用的上下文 - `"direct"`: LLM 直接调用 - `"code_execution_20250825"`: Python 代码中调用 @@ -69,6 +70,7 @@ type ToolCaller struct { ### 2. HTTP 桥接服务器 ::code-group + ```go [服务器实现] type HTTPBridgeServer struct { bridge *ToolBridge @@ -112,16 +114,17 @@ func (s *HTTPBridgeServer) handleToolCall(w http.ResponseWriter, r *http.Request }) } ``` + :: **API 端点:** -| 端点 | 方法 | 功能 | 缓存 | -|------|------|------|------| -| `/tools/call` | POST | 调用工具 | ❌ | -| `/tools/list` | GET | 列出工具 | ✅ | -| `/tools/schema` | GET | 获取 Schema | ✅ 5分钟 | -| `/health` | GET | 健康检查 | ❌ | +| 端点 | 方法 | 功能 | 缓存 | +| --------------- | ---- | ----------- | -------- | +| `/tools/call` | POST | 调用工具 | ❌ | +| `/tools/list` | GET | 列出工具 | ✅ | +| `/tools/schema` | GET | 获取 Schema | ✅ 5分钟 | +| `/health` | GET | 健康检查 | ❌ | ### 3. Python SDK @@ -229,6 +232,7 @@ if __name__ == "__main__": ``` **代码大小分析:** + - SDK 基础代码: ~100 行 - 用户代码: 可变 - 总代码: ~100 + 用户代码行数 @@ -290,6 +294,7 @@ class AsterBridge: ``` **优势:** + - 减少 TCP 握手开销 - 降低延迟 (1-2ms → 0.5ms) - 提升吞吐量 (2x) @@ -316,6 +321,7 @@ func (c *schemaCache) get(key string) (any, bool) { ``` **性能提升:** + - Schema 查询: O(n) → O(1) - 延迟降低: 10ms → 0.1ms - CPU 使用: 减少 90% @@ -422,14 +428,14 @@ graph LR ### 关键指标 -| 指标 | 说明 | 目标值 | -|------|------|--------| +| 指标 | 说明 | 目标值 | +| -------------- | --------------- | ------- | | 服务器启动时间 | HTTP 服务器就绪 | < 100ms | -| 工具调用延迟 | 单次调用耗时 | < 10ms | -| Python 冷启动 | 首次执行耗时 | < 100ms | -| Python 热执行 | 后续执行耗时 | < 20ms | -| 内存占用 | 空闲状态 | < 10MB | -| QPS | 并发吞吐量 | > 20/s | +| 工具调用延迟 | 单次调用耗时 | < 10ms | +| Python 冷启动 | 首次执行耗时 | < 100ms | +| Python 热执行 | 后续执行耗时 | < 20ms | +| 内存占用 | 空闲状态 | < 10MB | +| QPS | 并发吞吐量 | > 20/s | ### 监控实现 diff --git a/docs/content/05.tools/5.ptc/4.troubleshooting.md b/docs/content/05.tools/5.ptc/4.troubleshooting.md index 550f234..18a2956 100644 --- a/docs/content/05.tools/5.ptc/4.troubleshooting.md +++ b/docs/content/05.tools/5.ptc/4.troubleshooting.md @@ -11,9 +11,11 @@ description: 常见问题及解决方案 ::alert{type="error"} **错误信息:** + ``` Error: aiohttp is required. Install it with: pip install aiohttp ``` + :: **原因:** Python 环境缺少 `aiohttp` 库 @@ -21,6 +23,7 @@ Error: aiohttp is required. Install it with: pip install aiohttp **解决方案:** ::code-group + ```bash [pip] pip install aiohttp ``` @@ -32,9 +35,11 @@ conda install -c conda-forge aiohttp ```bash [poetry] poetry add aiohttp ``` + :: **验证安装:** + ```bash python3 -c "import aiohttp; print(aiohttp.__version__)" ``` @@ -45,9 +50,11 @@ python3 -c "import aiohttp; print(aiohttp.__version__)" ::alert{type="error"} **错误信息:** + ``` Connection error: Cannot connect to host localhost:8080 ``` + :: **原因:** HTTP 桥接服务器未启动 @@ -55,16 +62,19 @@ Connection error: Cannot connect to host localhost:8080 **诊断步骤:** 1. 检查服务器是否运行 + ```bash curl http://localhost:8080/health ``` 2. 检查端口占用 + ```bash lsof -i :8080 ``` 3. 查看进程日志 + ```go // 在 Go 代码中添加日志 if err := server.StartAsync(); err != nil { @@ -75,6 +85,7 @@ if err := server.StartAsync(); err != nil { **解决方案:** ::code-group + ```go [修改端口] // 使用不同端口 codeExec.SetBridgeURL("http://localhost:9000") @@ -89,6 +100,7 @@ if err := server.StartAsync(); err != nil { } time.Sleep(200 * time.Millisecond) // 等待启动 ``` + :: --- @@ -97,9 +109,11 @@ time.Sleep(200 * time.Millisecond) // 等待启动 ::alert{type="error"} **错误信息:** + ``` execution timeout ``` + :: **原因:** 代码执行时间超过配置的超时限制 @@ -116,6 +130,7 @@ runtime := bridge.NewPythonRuntime(config) ``` **优化建议:** + - 使用并发减少执行时间 - 避免阻塞操作 - 检查是否有死循环 @@ -126,9 +141,11 @@ runtime := bridge.NewPythonRuntime(config) ::alert{type="error"} **错误信息:** + ``` Tool Read failed: file not found ``` + :: **原因:** 工具执行失败(业务逻辑错误) @@ -136,6 +153,7 @@ Tool Read failed: file not found **调试步骤:** 1. 直接测试工具 + ```bash # 测试 HTTP 接口 curl -X POST http://localhost:8080/tools/call \ @@ -147,6 +165,7 @@ curl -X POST http://localhost:8080/tools/call \ ``` 2. 检查输入参数 + ```python # 在 Python 代码中打印参数 import sys @@ -155,6 +174,7 @@ result = await Read(path=path) ``` 3. 捕获异常 + ```python try: result = await Read(path="nonexistent.txt") @@ -170,9 +190,11 @@ except Exception as e: ::alert{type="error"} **错误信息:** + ``` Tool XXX is not allowed in code_execution context ``` + :: **原因:** 工具的 `AllowedCallers` 未包含 `code_execution_20250825` @@ -191,6 +213,7 @@ toolSchema := provider.ToolSchema{ ``` **检查清单:** + - ✅ 工具在 ToolSchema 中定义 - ✅ AllowedCallers 包含正确值 - ✅ 工具已注册到 Registry @@ -217,6 +240,7 @@ log.Printf("Tool %s latency: %v", name, latency) **可能原因和解决方案:** ::code-group + ```go [网络延迟] // 使用本地桥接服务器 codeExec.SetBridgeURL("http://localhost:8080") // ✅ @@ -245,6 +269,7 @@ results = await asyncio.gather( Read(path="c.txt"), ) ``` + :: --- @@ -402,11 +427,13 @@ go tool pprof http://localhost:6060/debug/pprof/goroutine :: **检查版本:** + ```bash python3 --version ``` **解决方案:** + ```bash # macOS brew install python@3.11 @@ -428,6 +455,7 @@ pyenv global 3.11.0 **解决方案:** ::code-group + ```bash [使用虚拟环境] python3 -m venv venv source venv/bin/activate @@ -442,6 +470,7 @@ pip install 'aiohttp>=3.8.0,<4.0.0' pip cache purge pip install --no-cache-dir aiohttp ``` + :: --- @@ -506,34 +535,43 @@ func executeWithLimit(ctx context.Context, code string) error { ::card-group ::card + --- + title: GitHub Issues icon: i-lucide-github to: https://github.com/astercloud/aster/issues + --- + 报告 Bug 或提交功能请求 :: -::card ---- +## ::card + title: 讨论区 icon: i-lucide-message-circle to: https://github.com/astercloud/aster/discussions + --- + 提问和讨论 :: -::card ---- +## ::card + title: 文档 icon: i-lucide-book to: /tools/ptc + --- + 查阅完整文档 :: :: **报告问题时请提供:** + 1. ✅ 错误信息和堆栈跟踪 2. ✅ Go 版本和 Python 版本 3. ✅ 最小可复现示例 diff --git a/docs/content/05.tools/5.ptc/index.md b/docs/content/05.tools/5.ptc/index.md index e6ab73a..070087a 100644 --- a/docs/content/05.tools/5.ptc/index.md +++ b/docs/content/05.tools/5.ptc/index.md @@ -5,11 +5,13 @@ Programmatic Tool Calling (PTC) 是 Aster 实现的 Anthropic 协议扩展,允 ## 概述 传统的工具调用流程: + ``` LLM → 工具调用请求 → Aster 执行工具 → 返回结果 → LLM ``` PTC 流程: + ``` LLM → 生成 Python 代码 → CodeExecute 工具执行代码 → 代码中调用 Aster 工具 → 返回结果 → LLM @@ -160,6 +162,7 @@ func (t *ReadTool) Schema() provider.ToolSchema { ``` AllowedCallers 可选值: + - `"direct"`: 允许 LLM 直接调用(默认) - `"code_execution_20250825"`: 允许在 CodeExecute 生成的代码中调用 @@ -167,13 +170,13 @@ AllowedCallers 可选值: 以下内置工具默认支持 PTC: -| 工具名 | 功能 | 示例 | -|--------|------|------| -| `Read` | 读取文件 | `await Read(path="file.txt")` | -| `Write` | 写入文件 | `await Write(path="out.txt", content="data")` | -| `Glob` | 文件模式匹配 | `await Glob(pattern="*.py")` | -| `Grep` | 内容搜索 | `await Grep(pattern="TODO", path=".")` | -| `Bash` | 执行命令 | `await Bash(command="ls -la")` | +| 工具名 | 功能 | 示例 | +| ------- | ------------ | --------------------------------------------- | +| `Read` | 读取文件 | `await Read(path="file.txt")` | +| `Write` | 写入文件 | `await Write(path="out.txt", content="data")` | +| `Glob` | 文件模式匹配 | `await Glob(pattern="*.py")` | +| `Grep` | 内容搜索 | `await Grep(pattern="TODO", path=".")` | +| `Bash` | 执行命令 | `await Bash(command="ls -la")` | ## 高级用法 @@ -242,6 +245,7 @@ Error: aiohttp is required. Install it with: pip install aiohttp ``` 解决方案: + ```bash pip install aiohttp ``` @@ -284,6 +288,7 @@ log.SetFlags(log.LstdFlags | log.Lshortfile) ### 查看生成的 Python 代码 CodeExecute 工具执行的完整 Python 代码会包含: + 1. SDK 注入代码 2. 工具函数生成 3. 用户代码包装 @@ -293,6 +298,7 @@ CodeExecute 工具执行的完整 Python 代码会包含: ### HTTP 请求日志 HTTP 桥接服务器会输出: + ``` HTTP Bridge Server listening on localhost:8080 ``` @@ -310,6 +316,7 @@ HTTP Bridge Server listening on localhost:8080 ### Q: PTC 和普通工具调用有什么区别? A: + - 普通工具调用: LLM 一次调用一个工具,适合简单场景 - PTC: LLM 生成 Python 代码,可以组合多个工具,适合复杂逻辑 diff --git a/docs/content/05.tools/index.md b/docs/content/05.tools/index.md index c531bcf..696df3f 100644 --- a/docs/content/05.tools/index.md +++ b/docs/content/05.tools/index.md @@ -11,6 +11,7 @@ aster 提供了强大的工具系统,让 Agent 能够与外部世界交互。 ## 📚 分类 ### [内置工具](/tools/builtin) + - 文件系统操作 - Bash 命令执行 - HTTP 请求 @@ -18,16 +19,19 @@ aster 提供了强大的工具系统,让 Agent 能够与外部世界交互。 - Todo 管理 ### [MCP 协议](/tools/mcp) + - MCP Client - MCP Server - 协议扩展 ### [自定义工具](/tools/custom) + - 创建自定义工具 - 工具注册 - 工具生命周期 ### [Programmatic Tool Calling](/tools/ptc) ::badge{type="success"}新:: + - 让 LLM 生成的 Python 代码直接调用工具 - HTTP 桥接服务器 - 异步 Python SDK diff --git a/docs/content/06.middleware/2.builtin/builtin.md b/docs/content/06.middleware/2.builtin/builtin.md index 77eb501..8f3cea3 100644 --- a/docs/content/06.middleware/2.builtin/builtin.md +++ b/docs/content/06.middleware/2.builtin/builtin.md @@ -11,22 +11,23 @@ aster 提供了多个开箱即用的中间件,涵盖对话管理、文件操 ## 📦 中间件列表 -| 中间件 | 优先级 | 功能 | 适用场景 | -|--------|--------|------|----------| -| [Summarization](#summarization) | 40 | 自动总结 | 长对话压缩 | -| [Filesystem](#filesystem) | 100 | 文件工具 | 文件读写操作 | -| [SubAgent](#subagent) | 200 | 子Agent | 复杂任务委托 | -| [AgentMemory](#memory) | 150 | 跨会话记忆 | 持久化记忆 | -| [HumanInTheLoop](#hitl) | 50 | 人工审批 | 敏感操作控制 | -| [TodoList](#todolist) | 120 | 任务跟踪 | 任务规划管理 | -| [PatchToolCalls](#patch) | 300 | 工具补丁 | 兼容性修复 | -| [SimplicityChecker](#simplicity) | 600 | 简洁性检查 | 防止过度工程 | +| 中间件 | 优先级 | 功能 | 适用场景 | +| -------------------------------- | ------ | ---------- | ------------ | +| [Summarization](#summarization) | 40 | 自动总结 | 长对话压缩 | +| [Filesystem](#filesystem) | 100 | 文件工具 | 文件读写操作 | +| [SubAgent](#subagent) | 200 | 子Agent | 复杂任务委托 | +| [AgentMemory](#memory) | 150 | 跨会话记忆 | 持久化记忆 | +| [HumanInTheLoop](#hitl) | 50 | 人工审批 | 敏感操作控制 | +| [TodoList](#todolist) | 120 | 任务跟踪 | 任务规划管理 | +| [PatchToolCalls](#patch) | 300 | 工具补丁 | 兼容性修复 | +| [SimplicityChecker](#simplicity) | 600 | 简洁性检查 | 防止过度工程 | ## 📝 Summarization - 自动总结 **功能**: 自动监控对话历史,超过 Token 阈值时总结旧消息,释放上下文空间。 **使用场景**: + - 长时间对话(超过模型上下文窗口) - 需要保留对话要点但减少 Token 使用 - 多轮交互的复杂任务 @@ -47,13 +48,13 @@ summaryMW, err := middleware.NewSummarizationMiddleware(&middleware.Summarizatio ### 参数说明 -| 参数 | 类型 | 默认值 | 说明 | -|------|------|--------|------| -| MaxTokensBeforeSummary | int | 170000 | 触发总结的 Token 数阈值 | -| MessagesToKeep | int | 6 | 总结后保留的最近消息数 | -| SummaryPrefix | string | "## Previous conversation summary:" | 总结消息的前缀 | -| TokenCounter | func | 默认计数器 | 自定义 Token 计数函数 | -| Summarizer | func | 默认总结器 | 自定义总结生成函数 | +| 参数 | 类型 | 默认值 | 说明 | +| ---------------------- | ------ | ----------------------------------- | ----------------------- | +| MaxTokensBeforeSummary | int | 170000 | 触发总结的 Token 数阈值 | +| MessagesToKeep | int | 6 | 总结后保留的最近消息数 | +| SummaryPrefix | string | "## Previous conversation summary:" | 总结消息的前缀 | +| TokenCounter | func | 默认计数器 | 自定义 Token 计数函数 | +| Summarizer | func | 默认总结器 | 自定义总结生成函数 | ### 工作流程 @@ -136,6 +137,7 @@ summaryMW, _ := middleware.NewSummarizationMiddleware(&middleware.SummarizationM **功能**: 注入文件操作工具,支持文件读写、目录遍历、内容搜索等。 **使用场景**: + - Agent 需要读写文件 - 处理大文件内容(自动驱逐大结果) - 路径安全验证 @@ -159,13 +161,13 @@ filesMW := middleware.NewFilesystemMiddleware(&middleware.FilesystemMiddlewareCo ### 注入的工具 -| 工具名 | 功能 | 参数 | -|--------|------|------| -| `Read` | 读取文件 | path, offset?, limit? | -| `Write` | 写入文件 | path, content | -| `Edit` | 编辑文件 | path, old_string, new_string | -| `glob` | 文件模式匹配 | pattern | -| `grep` | 内容搜索 | pattern, path | +| 工具名 | 功能 | 参数 | +| ------- | ------------ | ---------------------------- | +| `Read` | 读取文件 | path, offset?, limit? | +| `Write` | 写入文件 | path, content | +| `Edit` | 编辑文件 | path, old_string, new_string | +| `glob` | 文件模式匹配 | pattern | +| `grep` | 内容搜索 | pattern, path | ### 使用示例 @@ -213,6 +215,7 @@ ag.Chat(ctx, "请读取 large-log.txt 文件") **功能**: 提供 `task` 工具,允许主 Agent 委托任务给子 Agent 执行。 **使用场景**: + - 复杂任务分解 - 专业化分工(数据分析、代码审查等) - 任务上下文隔离 @@ -281,6 +284,7 @@ sequenceDiagram **功能**: 拦截指定工具的调用,要求人工审批后才执行。 **使用场景**: + - 敏感操作(删除文件、执行命令) - 外部 API 调用需要确认 - 数据修改需要审核 @@ -349,6 +353,7 @@ ag.Chat(ctx, "请删除 /tmp/data.txt 文件") **功能**: 注入 `write_todos` 工具,引导 Agent 进行任务规划和跟踪。 **使用场景**: + - 复杂多步骤任务 - 任务进度追踪 - 用户实时了解 Agent 进展 @@ -406,6 +411,7 @@ const ( **功能**: 通过普通文件+搜索的方式实现长期记忆,而不是向量/RAG。 **核心能力**: + - 从后端读取 `/agent.md`,作为基础“人格/长期指令”注入到 System Prompt。 - 提供 `memory_search` / `memory_write` 等工具,在指定目录下管理 Markdown 记忆文件。 - 完全基于 `grep + 文件`,所有记忆都是人类可读、可直接编辑的文本。 @@ -462,7 +468,7 @@ if err != nil { 启用 AgentMemoryMiddleware 后,会自动为 Agent 注入两个长期记忆工具: -- `memory_search`:在 `MemoryPath`(如 `/memories/`)下做全文搜索 +- `memory_search`:在 `MemoryPath`(如 `/memories/`)下做全文搜索 - 默认大小写不敏感、按字面量匹配(内部用正则+grep,但对 LLM 暴露的是简单参数)。 - 样例调用(伪 JSON): @@ -471,14 +477,14 @@ if err != nil { "tool": "memory_search", "input": { "query": "Alice 的偏好", - "namespace": "users/alice", // 相对于基础命名空间; 若 Agent 配置了 user_id=alice, 也可以省略 + "namespace": "users/alice", // 相对于基础命名空间; 若 Agent 配置了 user_id=alice, 也可以省略 "glob": "*.md", "max_results": 20 } } ``` -- `memory_write`:向记忆文件写入/追加 Markdown 段落 +- `memory_write`:向记忆文件写入/追加 Markdown 段落 - 所有内容都存成 `## 标题 + 正文` 的 section,便于人类查看。 ```json @@ -526,6 +532,7 @@ if err != nil { **功能**: 修复或增强工具调用的兼容性问题。 **使用场景**: + - LLM 生成的工具调用参数格式不正确 - 工具接口变更后的兼容性适配 - 自动修正常见错误 @@ -555,6 +562,7 @@ patchMW := middleware.NewPatchToolCallsMiddleware(&middleware.PatchToolCallsMidd **功能**: 检测代码中的过度工程迹象,发出警告但不阻断执行。 **使用场景**: + - 防止 Agent 创建过多辅助函数 - 检测过早抽象(如创建不必要的接口) - 识别向后兼容 hack 模式 @@ -579,13 +587,13 @@ simplicityMW := middleware.NewSimplicityCheckerMiddleware(&middleware.Simplicity ### 参数说明 -| 参数 | 类型 | 默认值 | 说明 | -|------|------|--------|------| -| Enabled | bool | true | 是否启用检测 | -| MaxHelperFunctions | int | 3 | 单次会话允许的最大辅助函数数 | -| WarnOnPrematureAbstraction | bool | true | 是否警告创建过多接口 | -| WarnOnUnusedParams | bool | true | 是否警告向后兼容 hack | -| OnWarning | func | nil | 警告回调函数 | +| 参数 | 类型 | 默认值 | 说明 | +| -------------------------- | ---- | ------ | ---------------------------- | +| Enabled | bool | true | 是否启用检测 | +| MaxHelperFunctions | int | 3 | 单次会话允许的最大辅助函数数 | +| WarnOnPrematureAbstraction | bool | true | 是否警告创建过多接口 | +| WarnOnUnusedParams | bool | true | 是否警告向后兼容 hack | +| OnWarning | func | nil | 警告回调函数 | ### 检测规则 @@ -662,13 +670,13 @@ func main() { ### 警告类型 -| 类型 | 说明 | -|------|------| -| `helper_overflow` | 辅助函数过多 | -| `premature_abstraction` | 过早抽象 | +| 类型 | 说明 | +| ----------------------- | ------------- | +| `helper_overflow` | 辅助函数过多 | +| `premature_abstraction` | 过早抽象 | | `backwards_compat_hack` | 向后兼容 hack | -| `over_engineering` | 过度工程 | -| `unused_feature` | 未使用的功能 | +| `over_engineering` | 过度工程 | +| `unused_feature` | 未使用的功能 | ### 获取警告历史 @@ -802,6 +810,7 @@ func (m *MyMiddleware) Priority() int { ### Q: 中间件会影响性能吗? 是的,每个中间件都会增加一定开销。建议: + - 只启用必需的中间件 - 避免在中间件中执行耗时操作 - 使用缓存优化重复操作 diff --git a/docs/content/06.middleware/2.builtin/human-in-the-loop.md b/docs/content/06.middleware/2.builtin/human-in-the-loop.md index 86ec926..e61a38a 100644 --- a/docs/content/06.middleware/2.builtin/human-in-the-loop.md +++ b/docs/content/06.middleware/2.builtin/human-in-the-loop.md @@ -34,17 +34,17 @@ hitlMW, err := middleware.NewHumanInTheLoopMiddleware(&middleware.HumanInTheLoop "fs_delete": true, // 文件删除需要审核 "HttpRequest": true, // HTTP 请求需要审核 }, - + // 审核处理器 ApprovalHandler: func(ctx context.Context, req *middleware.ReviewRequest) ([]middleware.Decision, error) { for _, action := range req.ActionRequests { fmt.Printf("工具: %s\n", action.ToolName) fmt.Printf("参数: %+v\n", action.Input) fmt.Print("批准? (y/n): ") - + var answer string fmt.Scanln(&answer) - + if answer == "y" { return []middleware.Decision{{ Type: middleware.DecisionApprove, @@ -106,11 +106,11 @@ InterruptOn: map[string]interface{}{ ### 决策类型 -| 类型 | 说明 | 使用场景 | -|------|------|---------| -| `DecisionApprove` | 批准执行 | 操作安全,可以执行 | -| `DecisionReject` | 拒绝执行 | 操作不安全或不合理 | -| `DecisionEdit` | 编辑参数后执行 | 参数需要调整 | +| 类型 | 说明 | 使用场景 | +| ----------------- | -------------- | ------------------ | +| `DecisionApprove` | 批准执行 | 操作安全,可以执行 | +| `DecisionReject` | 拒绝执行 | 操作不安全或不合理 | +| `DecisionEdit` | 编辑参数后执行 | 参数需要调整 | ### ApprovalHandler - 审核处理器 @@ -121,13 +121,13 @@ InterruptOn: map[string]interface{}{ ```go ApprovalHandler: func(ctx context.Context, req *middleware.ReviewRequest) ([]middleware.Decision, error) { action := req.ActionRequests[0] - + fmt.Printf("工具: %s\n参数: %+v\n", action.ToolName, action.Input) fmt.Print("选择 (approve/reject/edit): ") - + var choice string fmt.Scanln(&choice) - + switch choice { case "approve": return []middleware.Decision{{Type: middleware.DecisionApprove}}, nil @@ -150,21 +150,21 @@ ApprovalHandler: func(ctx context.Context, req *middleware.ReviewRequest) ([]mid ApprovalHandler: func(ctx context.Context, req *middleware.ReviewRequest) ([]middleware.Decision, error) { action := req.ActionRequests[0] risk := assessRisk(action) - + switch risk { case RiskLow: // 低风险自动批准 return []middleware.Decision{{Type: middleware.DecisionApprove}}, nil - + case RiskMedium: // 中风险需要确认 return promptForConfirmation(action) - + case RiskHigh: // 高风险需要明确确认 return promptForExplicitConfirmation(action) } - + return nil, nil } ``` @@ -199,27 +199,27 @@ hitlMW, _ := middleware.NewHumanInTheLoopMiddleware(&middleware.HumanInTheLoopMi ApprovalHandler: func(ctx context.Context, req *middleware.ReviewRequest) ([]middleware.Decision, error) { action := req.ActionRequests[0] cmd := action.Input["command"].(string) - + // 检测危险命令 if strings.Contains(cmd, "rm -rf") { fmt.Println("🚨 检测到危险命令!") fmt.Printf("命令: %s\n", cmd) fmt.Print("输入 'CONFIRM' 确认执行: ") - + var confirm string fmt.Scanln(&confirm) - + if confirm == "CONFIRM" { return []middleware.Decision{{Type: middleware.DecisionApprove}}, nil } return []middleware.Decision{{Type: middleware.DecisionReject}}, nil } - + // 普通命令简单确认 fmt.Printf("命令: %s\n批准? (y/n): ", cmd) var answer string fmt.Scanln(&answer) - + if answer == "y" { return []middleware.Decision{{Type: middleware.DecisionApprove}}, nil } @@ -233,39 +233,39 @@ hitlMW, _ := middleware.NewHumanInTheLoopMiddleware(&middleware.HumanInTheLoopMi ```go ApprovalHandler: func(ctx context.Context, req *middleware.ReviewRequest) ([]middleware.Decision, error) { action := req.ActionRequests[0] - + fmt.Printf("工具: %s\n", action.ToolName) fmt.Println("当前参数:") for key, value := range action.Input { fmt.Printf(" %s: %v\n", key, value) } - + fmt.Print("\n选择 (approve/reject/edit): ") var choice string fmt.Scanln(&choice) - + if choice == "edit" { editedInput := make(map[string]interface{}) - + for key, value := range action.Input { fmt.Printf("编辑 %s (当前: %v, 回车保持): ", key, value) var newValue string fmt.Scanln(&newValue) - + if newValue != "" { editedInput[key] = newValue } else { editedInput[key] = value } } - + return []middleware.Decision{{ Type: middleware.DecisionEdit, EditedInput: editedInput, Reason: "参数已编辑", }}, nil } - + // ... 处理其他选择 } ``` @@ -278,10 +278,10 @@ ApprovalHandler: func(ctx context.Context, req *middleware.ReviewRequest) ([]mid type HumanInTheLoopMiddlewareConfig struct { // InterruptOn 配置哪些工具需要审核 InterruptOn map[string]interface{} - + // ApprovalHandler 审核处理器 ApprovalHandler ApprovalHandler - + // DefaultAllowedDecisions 默认允许的决策类型 DefaultAllowedDecisions []DecisionType } @@ -339,13 +339,13 @@ sequenceDiagram Agent->>HITL: 调用工具 HITL->>HITL: 检查是否需要审核 - + alt 需要审核 HITL->>Handler: 发送审核请求 Handler->>Human: 显示操作信息 Human->>Handler: 做出决策 Handler->>HITL: 返回决策 - + alt 批准 HITL->>Tool: 执行工具 Tool->>HITL: 返回结果 @@ -359,7 +359,7 @@ sequenceDiagram HITL->>Tool: 直接执行 Tool->>HITL: 返回结果 end - + HITL->>Agent: 返回最终结果 ``` @@ -401,7 +401,7 @@ InterruptOn: map[string]interface{}{ ApprovalHandler: func(ctx context.Context, req *middleware.ReviewRequest) ([]middleware.Decision, error) { ctx, cancel := context.WithTimeout(ctx, 5*time.Minute) defer cancel() - + select { case decision := <-getDecisionAsync(req): return []middleware.Decision{decision}, nil diff --git a/docs/content/06.middleware/2.builtin/index.md b/docs/content/06.middleware/2.builtin/index.md index ddf5c22..433e07d 100644 --- a/docs/content/06.middleware/2.builtin/index.md +++ b/docs/content/06.middleware/2.builtin/index.md @@ -40,6 +40,7 @@ graph TB ``` **特点:** + - ✅ **顺序执行** - 按优先级从小到大执行 - ✅ **双向拦截** - 请求和响应都可以处理 - ✅ **链式调用** - 每层调用下一层的 handler @@ -86,6 +87,7 @@ WrapModelCall(ctx context.Context, req *ModelRequest, handler ModelCallHandler) ``` **用途:** + - 修改发送给 LLM 的消息 - 增强 SystemPrompt - 自动总结历史消息 @@ -101,6 +103,7 @@ WrapToolCall(ctx context.Context, req *ToolCallRequest, handler ToolCallHandler) ``` **用途:** + - 验证工具调用参数 - 人工审批工具执行 - 缓存工具结果 @@ -130,6 +133,7 @@ type Middleware interface { ``` **用途:** + - 初始化资源(数据库连接、缓存等) - 加载持久化数据 - 释放资源 @@ -144,22 +148,23 @@ func (m *MyMiddleware) Priority() int { ``` **优先级范围:** + - **0-100**: 系统核心中间件 - **100-500**: 功能中间件 - **500-1000**: 用户自定义中间件 ## 📦 内置中间件 -| 中间件 | 优先级 | 功能 | 用途 | -|--------|--------|------|------| -| [Summarization](/examples/middleware/builtin#summarization) | 40 | 自动总结 | 压缩对话历史 | -| [Filesystem](/examples/middleware/builtin#filesystem) | 100 | 文件系统增强 | 注入文件工具 | -| [SubAgent](/examples/middleware/builtin#subagent) | 200 | 子Agent | 任务委托 | -| [AgentMemory](/examples/middleware/builtin#memory) | 150 | 记忆管理 | 跨会话记忆 | -| [HumanInTheLoop](/middleware/builtin/human-in-the-loop) | 50 | 人工干预 | 审批工具调用 | -| [TodoList](/examples/middleware/builtin#todolist) | 120 | 任务列表 | 任务跟踪 | -| [PatchToolCalls](/examples/middleware/builtin#patch) | 300 | 工具修复 | 补丁和兼容 | -| [PII Redaction](/middleware/builtin/pii-redaction) | 200 | PII 自动脱敏 | 敏感信息保护 | +| 中间件 | 优先级 | 功能 | 用途 | +| ----------------------------------------------------------- | ------ | ------------ | ------------ | +| [Summarization](/examples/middleware/builtin#summarization) | 40 | 自动总结 | 压缩对话历史 | +| [Filesystem](/examples/middleware/builtin#filesystem) | 100 | 文件系统增强 | 注入文件工具 | +| [SubAgent](/examples/middleware/builtin#subagent) | 200 | 子Agent | 任务委托 | +| [AgentMemory](/examples/middleware/builtin#memory) | 150 | 记忆管理 | 跨会话记忆 | +| [HumanInTheLoop](/middleware/builtin/human-in-the-loop) | 50 | 人工干预 | 审批工具调用 | +| [TodoList](/examples/middleware/builtin#todolist) | 120 | 任务列表 | 任务跟踪 | +| [PatchToolCalls](/examples/middleware/builtin#patch) | 300 | 工具修复 | 补丁和兼容 | +| [PII Redaction](/middleware/builtin/pii-redaction) | 200 | PII 自动脱敏 | 敏感信息保护 | ## 🚀 快速开始 @@ -254,6 +259,7 @@ summaryMW, _ := middleware.NewSummarizationMiddleware(&middleware.SummarizationM ``` **效果**: + - 自动监控消息历史的 Token 数 - 超过阈值时,总结旧消息 - 用总结替换历史,释放上下文空间 @@ -272,6 +278,7 @@ filesMW := middleware.NewFilesystemMiddleware(&middleware.FilesystemMiddlewareCo ``` **效果**: + - 自动注入 `Read`, `Write`, `Edit`, `glob`, `grep` 工具 - 大结果自动驱逐到文件 - 路径安全验证 @@ -303,6 +310,7 @@ subagentMW, _ := middleware.NewSubAgentMiddleware(&middleware.SubAgentMiddleware ``` **效果**: + - 注入 `task` 工具启动子 Agent - 子 Agent 独立上下文,任务隔离 - 支持专业化分工 @@ -334,6 +342,7 @@ hitlMW, _ := middleware.NewHumanInTheLoopMiddleware(&middleware.HumanInTheLoopMi ``` **效果**: + - 拦截指定工具的调用 - 人工审批后才执行 - 支持批准、拒绝、编辑三种决策 @@ -548,12 +557,12 @@ func (m *StatsMiddleware) GetStats() map[string]int { ### Q: 中间件和工具的区别? -| 特性 | 中间件 | 工具 | -|------|--------|------| +| 特性 | 中间件 | 工具 | +| -------- | -------------------- | ------------ | | 执行时机 | 自动执行(每次调用) | LLM 决定调用 | -| 作用范围 | 全局(所有请求) | 单次工具调用 | -| 功能 | 拦截、增强、控制流程 | 具体功能实现 | -| 使用场景 | 横切关注点 | 业务功能 | +| 作用范围 | 全局(所有请求) | 单次工具调用 | +| 功能 | 拦截、增强、控制流程 | 具体功能实现 | +| 使用场景 | 横切关注点 | 业务功能 | ### Q: 多个中间件如何执行? diff --git a/docs/content/06.middleware/2.builtin/pii-redaction.md b/docs/content/06.middleware/2.builtin/pii-redaction.md index a0ffe15..51c36a3 100644 --- a/docs/content/06.middleware/2.builtin/pii-redaction.md +++ b/docs/content/06.middleware/2.builtin/pii-redaction.md @@ -99,6 +99,7 @@ strategy := security.NewMaskStrategy() ``` **配置选项**: + ```go strategy := &security.MaskStrategy{ MaskChar: '*', // 掩码字符 @@ -121,6 +122,7 @@ strategy := security.NewReplaceStrategy() ``` **自定义标签**: + ```go strategy := &security.ReplaceStrategy{ UseTypeLabel: true, @@ -142,6 +144,7 @@ strategy := security.NewHashStrategy() ``` **配置选项**: + ```go strategy := &security.HashStrategy{ ShowPrefix: true, @@ -163,6 +166,7 @@ strategy := security.NewAdaptiveStrategy() ``` **自定义策略**: + ```go strategy := &security.AdaptiveStrategy{ LowStrategy: security.NewMaskStrategy(), diff --git a/docs/content/06.middleware/index.md b/docs/content/06.middleware/index.md index f358b2b..687a275 100644 --- a/docs/content/06.middleware/index.md +++ b/docs/content/06.middleware/index.md @@ -11,6 +11,7 @@ navigation: false ## 📚 分类 ### [内置中间件](/middleware/builtin) + - Filesystem - 文件系统访问控制 - SubAgent - 子 Agent 支持 - Summarization - 自动上下文总结 @@ -18,6 +19,7 @@ navigation: false - SimplicityChecker - 简洁性检查(防止过度工程) ### [自定义中间件](/middleware/custom) + - 创建自定义中间件 - 中间件注册 - 优先级配置 diff --git a/docs/content/07.workflows/1.overview/index.md b/docs/content/07.workflows/1.overview/index.md index 4fef7a6..581da36 100644 --- a/docs/content/07.workflows/1.overview/index.md +++ b/docs/content/07.workflows/1.overview/index.md @@ -10,6 +10,7 @@ Aster Workflow 是一个强大的工作流编排系统,提供了灵活的步 ## 🎯 核心特性 ### 🧩 8种步骤类型 + - **FunctionStep** - 自定义函数执行 - **AgentStep** - Agent 调用 - **RoomStep** - Room 协作 @@ -20,16 +21,19 @@ Aster Workflow 是一个强大的工作流编排系统,提供了灵活的步 - **StepsGroup** - 步骤组 ### 🔀 Router 动态路由 + - **SimpleRouter** - 单步骤条件路由 - **ChainRouter** - 多步骤链式路由 - **DynamicRouter** - 完全自定义路由 ### 🤖 WorkflowAgent 编排 + - Agentic Workflow - Agent 决定何时运行 - 历史访问和上下文 - 智能决策引擎 ### 🔄 完整功能 + - ✅ 流式执行和事件系统 - ✅ 会话管理和持久化 - ✅ 历史记录和回放 @@ -286,6 +290,7 @@ func main() { ``` **执行流程**: + ``` NestedWorkflow ├── ParallelCollector (并行) @@ -325,6 +330,7 @@ gantt ``` **性能分析**: + - **SequentialAgent**: 总时间 = Sum(子Agent耗时) = 9s - **ParallelAgent**: 总时间 = Max(子Agent耗时) = 4s (最快的并行优势) - **LoopAgent**: 总时间 = 迭代次数 × Sum(子Agent耗时) = 5s (3次迭代) @@ -477,6 +483,7 @@ go run main.go ``` **输出示例**: + ``` === 工作流 Agent 演示 === @@ -519,13 +526,13 @@ go run main.go ### 1. 选择合适的工作流模式 -| 场景 | 推荐模式 | 原因 | -|------|---------|------| -| 数据处理流水线 | SequentialAgent | 步骤间有依赖关系 | -| 多方案比较 | ParallelAgent | 需要同时评估多个选项 | -| 质量优化循环 | LoopAgent | 需要迭代改进 | -| 数据聚合 | Parallel → Sequential | 先并行收集,再串行汇总 | -| 多轮改进 | Sequential + Loop | 顺序执行多个优化循环 | +| 场景 | 推荐模式 | 原因 | +| -------------- | --------------------- | ---------------------- | +| 数据处理流水线 | SequentialAgent | 步骤间有依赖关系 | +| 多方案比较 | ParallelAgent | 需要同时评估多个选项 | +| 质量优化循环 | LoopAgent | 需要迭代改进 | +| 数据聚合 | Parallel → Sequential | 先并行收集,再串行汇总 | +| 多轮改进 | Sequential + Loop | 顺序执行多个优化循环 | ### 2. 性能优化 @@ -630,6 +637,7 @@ A: 所有子 Agent 同时启动,但事件返回顺序不确定(取决于哪 ### Q3: LoopAgent 如何避免无限循环? A: 必须设置 `MaxIterations` 或 `StopCondition` 之一。建议同时设置两者: + ```go MaxIterations: 10, // 最多10次迭代 StopCondition: func(event *session.Event) bool { @@ -640,6 +648,7 @@ StopCondition: func(event *session.Event) bool { ### Q4: 如何调试嵌套工作流? A: 使用 `event.Branch` 字段追踪事件来源: + ```go reader := nestedWorkflow.Execute(ctx, msg) for { diff --git a/docs/content/07.workflows/2.basic/1.getting-started.md b/docs/content/07.workflows/2.basic/1.getting-started.md index 8297f8d..2eea239 100644 --- a/docs/content/07.workflows/2.basic/1.getting-started.md +++ b/docs/content/07.workflows/2.basic/1.getting-started.md @@ -10,6 +10,7 @@ Aster Workflow 系统提供了强大的工作流编排能力。 ## 基础概念 Workflow 是一系列步骤(Step)的有序集合,每个步骤可以是: + - **FunctionStep** - 自定义函数 - **AgentStep** - Agent 执行 - **RoomStep** - Room 协作执行 @@ -34,14 +35,14 @@ import ( func main() { ctx := context.Background() - + // 创建 Workflow wf := workflow.New("DataProcessing"). WithStream(). // 启用流式 WithDebug() // 启用调试 - + // 添加步骤 - wf.AddStep(workflow.NewFunctionStep("load", + wf.AddStep(workflow.NewFunctionStep("load", func(ctx context.Context, input *workflow.StepInput) (*workflow.StepOutput, error) { // 加载数据 return &workflow.StepOutput{ @@ -50,7 +51,7 @@ func main() { }, nil }, )) - + wf.AddStep(workflow.NewFunctionStep("process", func(ctx context.Context, input *workflow.StepInput) (*workflow.StepOutput, error) { // 处理数据 - 可以访问前一步的输出 @@ -61,12 +62,12 @@ func main() { }, nil }, )) - + // 验证 if err := wf.Validate(); err != nil { panic(err) } - + // 执行 input := &workflow.WorkflowInput{Input: "start"} reader := wf.Execute(ctx, input) @@ -102,7 +103,7 @@ step1 := workflow.NewFunctionStep("step1", func(ctx context.Context, input *work step2 := workflow.NewFunctionStep("step2", func(ctx context.Context, input *workflow.StepInput) (*workflow.StepOutput, error) { // 访问前一步的输出 prevContent := input.PreviousStepContent.(string) // "Hello" - + return &workflow.StepOutput{ Content: prevContent + " World", }, nil diff --git a/docs/content/07.workflows/2.basic/2.step-types.md b/docs/content/07.workflows/2.basic/2.step-types.md index c8047c7..8b09b90 100644 --- a/docs/content/07.workflows/2.basic/2.step-types.md +++ b/docs/content/07.workflows/2.basic/2.step-types.md @@ -12,11 +12,11 @@ Aster Workflow 提供 8 种步骤类型,满足不同的业务需求。 最基础的步骤类型,执行自定义函数: ```go -step := workflow.NewFunctionStep("my_function", +step := workflow.NewFunctionStep("my_function", func(ctx context.Context, input *workflow.StepInput) (*workflow.StepOutput, error) { // 自定义逻辑 result := doSomething(input.Input) - + return &workflow.StepOutput{ Content: result, Metadata: make(map[string]interface{}), @@ -73,6 +73,7 @@ loopStep := workflow.NewLoopStep("loop", loopBody, 10). // 最多10次 ``` **特点**: + - 每次迭代的输出会作为下次的输入 - 支持提前终止 - 收集所有迭代结果 @@ -90,6 +91,7 @@ parallelStep := workflow.NewParallelStep("parallel", task1, task2, task3) ``` **特点**: + - 所有步骤同时开始 - 等待全部完成 - 返回所有结果 @@ -126,6 +128,7 @@ group := workflow.NewStepsGroup("group", step1, step2, step3) ``` **特点**: + - 顺序执行 - 数据流在步骤间传递 - 返回最后一步的输出 @@ -152,13 +155,13 @@ roomStep := workflow.NewRoomStep("team_task", room) ## 选择建议 -| 需求 | 推荐步骤类型 | -|------|-------------| -| 简单处理 | FunctionStep | -| 条件判断 | ConditionStep | -| 重复执行 | LoopStep | -| 并发处理 | ParallelStep | -| 动态路由 | Router 类 | -| 顺序组合 | StepsGroup | -| Agent 调用 | AgentStep | -| 团队协作 | RoomStep | +| 需求 | 推荐步骤类型 | +| ---------- | ------------- | +| 简单处理 | FunctionStep | +| 条件判断 | ConditionStep | +| 重复执行 | LoopStep | +| 并发处理 | ParallelStep | +| 动态路由 | Router 类 | +| 顺序组合 | StepsGroup | +| Agent 调用 | AgentStep | +| 团队协作 | RoomStep | diff --git a/docs/content/07.workflows/3.advanced/1.router.md b/docs/content/07.workflows/3.advanced/1.router.md index 69ae93a..5035655 100644 --- a/docs/content/07.workflows/3.advanced/1.router.md +++ b/docs/content/07.workflows/3.advanced/1.router.md @@ -81,16 +81,16 @@ router := workflow.DynamicRouter("dynamic", func(input *workflow.StepInput) []workflow.Step { // 动态创建和返回步骤 steps := []workflow.Step{} - + data := input.PreviousStepContent.(map[string]interface{}) tasks := data["tasks"].([]string) - + // 根据数据动态创建步骤 for _, task := range tasks { step := workflow.NewFunctionStep(task, createTaskHandler(task)) steps = append(steps, step) } - + return steps }, ) diff --git a/docs/content/07.workflows/3.advanced/2.workflow-agent.md b/docs/content/07.workflows/3.advanced/2.workflow-agent.md index a4b482a..f80af54 100644 --- a/docs/content/07.workflows/3.advanced/2.workflow-agent.md +++ b/docs/content/07.workflows/3.advanced/2.workflow-agent.md @@ -10,6 +10,7 @@ WorkflowAgent 是一个专门用于 Workflow 编排的受限 Agent,让 AI Agen ## 核心概念 **Agentic Workflow** 的核心思想: + 1. Agent 先检查历史记录 2. 如果能从历史中回答,直接回答 3. 如果需要新数据,调用 Workflow 工具 @@ -165,16 +166,16 @@ import ( func main() { ctx := context.Background() - + // 创建数据分析 Workflow wf := workflow.New("DataAnalysis") - - wf.AddStep(workflow.NewFunctionStep("analyze", + + wf.AddStep(workflow.NewFunctionStep("analyze", func(ctx context.Context, input *workflow.StepInput) (*workflow.StepOutput, error) { // 执行数据分析 query := input.Input.(string) result := performAnalysis(query) - + return &workflow.StepOutput{ Content: map[string]interface{}{ "query": query, @@ -185,32 +186,32 @@ func main() { }, nil }, )) - + // 创建 WorkflowAgent agent := workflow.NewWorkflowAgent("gpt-4", "", true, 5). WithInstructions(`你是数据分析助手。 - 如果用户询问之前分析过的数据,直接从历史中回答 - 如果是新的查询,调用 run_workflow 工具 - 每次只调用一次工具`) - + // 附加 Workflow agent.AttachWorkflow(wf) - + // 第一次查询 - 会运行 Workflow fmt.Println("=== 第一次查询 ===") result1, _ := agent.Run(ctx, "分析Q1销售数据") fmt.Println(result1) - + // 第二次查询 - Agent 可能从历史中回答 fmt.Println("\n=== 第二次查询 ===") result2, _ := agent.Run(ctx, "Q1的销售额是多少?") fmt.Println(result2) - + // 新查询 - 会运行新的 Workflow fmt.Println("\n=== 新查询 ===") result3, _ := agent.Run(ctx, "分析Q2销售数据") fmt.Println(result3) - + // 查看历史 fmt.Println("\n=== 历史记录 ===") for i, item := range agent.GetWorkflowHistory() { @@ -268,11 +269,11 @@ func performAnalysis(query string) map[string]interface{} { ## 技术特性 -| 功能 | Aster WorkflowAgent | -|------|---------------------| -| 历史访问 | ✅ | -| 工具创建 | ✅ | -| 流式执行 | ✅ | -| 会话管理 | ✅ | -| 并发支持 | ✅ (goroutines) | -| 线程安全 | ✅ (sync.RWMutex) | +| 功能 | Aster WorkflowAgent | +| -------- | ------------------- | +| 历史访问 | ✅ | +| 工具创建 | ✅ | +| 流式执行 | ✅ | +| 会话管理 | ✅ | +| 并发支持 | ✅ (goroutines) | +| 线程安全 | ✅ (sync.RWMutex) | diff --git a/docs/content/07.workflows/index.md b/docs/content/07.workflows/index.md index 42a517f..6dfd57c 100644 --- a/docs/content/07.workflows/index.md +++ b/docs/content/07.workflows/index.md @@ -11,12 +11,14 @@ navigation: false ## 📚 分类 ### [基础工作流](/workflows/basic) + - Sequential - 顺序执行 - Parallel - 并行执行 - Conditional - 条件分支 - Loop - 循环执行 ### [高级模式](/workflows/advanced) + - 错误处理与重试 - 工作流持久化 - 动态工作流构建 diff --git a/docs/content/08.multi-agent/.navigation.yml b/docs/content/08.multi-agent/.navigation.yml index a140417..f6140f2 100644 --- a/docs/content/08.multi-agent/.navigation.yml +++ b/docs/content/08.multi-agent/.navigation.yml @@ -1,2 +1,2 @@ -title: 多Agent系统 +title: 多Agent系统 icon: i-lucide-users diff --git a/docs/content/08.multi-agent/1.overview/index.md b/docs/content/08.multi-agent/1.overview/index.md index a42dcc0..18ad503 100644 --- a/docs/content/08.multi-agent/1.overview/index.md +++ b/docs/content/08.multi-agent/1.overview/index.md @@ -60,12 +60,12 @@ graph TB ## 📦 协作组件 -| 组件 | 功能 | 适用场景 | -|------|------|----------| -| [Workflow Agent](/examples/workflow-agents) | 工作流编排 | 并行/顺序/循环执行多个子 Agent | -| [SubAgent 中间件](#subagent) | 任务委托 | 主从协作、专业化分工 | -| [Agent Pool](#pool) | Agent 生命周期管理 | 多租户、会话管理 | -| [Scheduler](#scheduler) | 任务调度 | 定时任务、事件触发 | +| 组件 | 功能 | 适用场景 | +| ------------------------------------------- | ------------------ | ------------------------------ | +| [Workflow Agent](/examples/workflow-agents) | 工作流编排 | 并行/顺序/循环执行多个子 Agent | +| [SubAgent 中间件](#subagent) | 任务委托 | 主从协作、专业化分工 | +| [Agent Pool](#pool) | Agent 生命周期管理 | 多租户、会话管理 | +| [Scheduler](#scheduler) | 任务调度 | 定时任务、事件触发 | ::alert{type="info"} **Phase 7 新增**: 工作流 Agent 提供了更强大的多 Agent 编排能力,支持 ParallelAgent(并行)、SequentialAgent(顺序)、LoopAgent(循环)三种模式。详见 [工作流 Agent 文档](/examples/workflow-agents)。 @@ -212,12 +212,14 @@ func testSubAgentCoordination(ctx context.Context, ag *agent.Agent) { ### 关键特性 **1. 任务隔离** + ```go // 每个子Agent有独立的上下文 // 不会污染主Agent的对话历史 ``` **2. 专业化分工** + ```go // 不同子Agent可以有不同的: // - SystemPrompt(角色定位) @@ -226,6 +228,7 @@ func testSubAgentCoordination(ctx context.Context, ag *agent.Agent) { ``` **3. 并行执行**(可选) + ```go subagentMW, _ := middleware.NewSubAgentMiddleware(&middleware.SubAgentMiddlewareConfig{ EnableParallel: true, // 启用并行执行 @@ -335,18 +338,18 @@ func main() { ### Pool API -| 方法 | 功能 | 说明 | -|------|------|------| -| `Create(ctx, config)` | 创建新Agent | 返回Agent实例 | -| `Resume(ctx, agentID, config)` | 恢复Agent | 从存储恢复 | -| `Get(agentID)` | 获取Agent | 返回 (agent, exists) | -| `List(prefix)` | 列出Agent | 可选前缀过滤 | -| `Status(agentID)` | 查询状态 | 返回状态信息 | -| `Remove(agentID)` | 移除Agent | 关闭但保留存储 | -| `Delete(ctx, agentID)` | 删除Agent | 包括存储数据 | -| `ForEach(fn)` | 遍历Agent | 回调函数遍历 | -| `Size()` | 池大小 | 当前Agent数量 | -| `Shutdown()` | 关闭池 | 关闭所有Agent | +| 方法 | 功能 | 说明 | +| ------------------------------ | ----------- | -------------------- | +| `Create(ctx, config)` | 创建新Agent | 返回Agent实例 | +| `Resume(ctx, agentID, config)` | 恢复Agent | 从存储恢复 | +| `Get(agentID)` | 获取Agent | 返回 (agent, exists) | +| `List(prefix)` | 列出Agent | 可选前缀过滤 | +| `Status(agentID)` | 查询状态 | 返回状态信息 | +| `Remove(agentID)` | 移除Agent | 关闭但保留存储 | +| `Delete(ctx, agentID)` | 删除Agent | 包括存储数据 | +| `ForEach(fn)` | 遍历Agent | 回调函数遍历 | +| `Size()` | 池大小 | 当前Agent数量 | +| `Shutdown()` | 关闭池 | 关闭所有Agent | ### 使用场景 @@ -502,14 +505,14 @@ func main() { ### Scheduler API -| 方法 | 功能 | 参数 | -|------|------|------| -| `EverySteps(n, fn)` | 每N步执行 | n: 步数间隔
fn: 任务函数 | -| `EveryInterval(d, fn)` | 每N时间执行 | d: 时间间隔
fn: 任务函数 | -| `OnStep(fn)` | 步骤监听 | fn: 监听函数
返回取消函数 | -| `NotifyStep(n)` | 通知步骤 | n: 当前步数 | -| `CancelTask(id)` | 取消任务 | id: 任务ID | -| `Shutdown()` | 关闭调度器 | 停止所有任务 | +| 方法 | 功能 | 参数 | +| ---------------------- | ----------- | ----------------------------- | +| `EverySteps(n, fn)` | 每N步执行 | n: 步数间隔
fn: 任务函数 | +| `EveryInterval(d, fn)` | 每N时间执行 | d: 时间间隔
fn: 任务函数 | +| `OnStep(fn)` | 步骤监听 | fn: 监听函数
返回取消函数 | +| `NotifyStep(n)` | 通知步骤 | n: 当前步数 | +| `CancelTask(id)` | 取消任务 | id: 任务ID | +| `Shutdown()` | 关闭调度器 | 停止所有任务 | ### 使用场景 @@ -738,12 +741,12 @@ if pool.Size() > maxAgents * 0.8 { ### Q: Pool 和 SubAgent 有什么区别? -| 特性 | Pool | SubAgent | -|------|------|----------| +| 特性 | Pool | SubAgent | +| -------- | --------------- | -------------------- | | 管理对象 | 独立的Agent实例 | 主Agent的子任务Agent | -| 生命周期 | 手动管理 | 自动管理 | -| 上下文 | 独立上下文 | 任务隔离上下文 | -| 适用场景 | 多租户、会话 | 任务委托、专业化 | +| 生命周期 | 手动管理 | 自动管理 | +| 上下文 | 独立上下文 | 任务隔离上下文 | +| 适用场景 | 多租户、会话 | 任务委托、专业化 | ### Q: 如何选择协作模式? @@ -754,6 +757,7 @@ if pool.Size() > maxAgents * 0.8 { ### Q: SubAgent 会增加成本吗? 会的。每个子Agent调用都是独立的LLM请求。建议: + - 只在必要时使用SubAgent - 合并相关的子任务 - 使用缓存减少重复调用 @@ -761,6 +765,7 @@ if pool.Size() > maxAgents * 0.8 { ### Q: Pool 的最大容量如何设置? 考虑因素: + - 系统内存(每个Agent占用内存) - 并发请求数 - 存储I/O能力 diff --git a/docs/content/08.multi-agent/4.comparison.md b/docs/content/08.multi-agent/4.comparison.md index 8a1b012..a3fd9e4 100644 --- a/docs/content/08.multi-agent/4.comparison.md +++ b/docs/content/08.multi-agent/4.comparison.md @@ -11,12 +11,12 @@ Aster 框架中有多个与"多Agent"相关的概念,它们各自解决不同 ## 📊 概念对比表 -| 概念 | 层次 | 生命周期 | 主要职责 | 使用场景 | -|------|------|----------|----------|----------| -| **SubAgent** | 中间件层 | 短暂(任务级) | 任务委派、上下文隔离 | 单个 Agent 内部的复杂任务拆分 | -| **Stars** | 协作层 | 中等(会话级) | 多 Agent 协作、消息路由 | 多个 Agent 之间的协同工作 | -| **Cosmos** | 管理层 | 长期(应用级) | Agent 生命周期管理 | 创建、销毁、监控所有 Agent | -| **AsterOS** | 运行时层 | 持久(系统级) | 统一运行时、API 网关 | 对外提供服务、资源注册 | +| 概念 | 层次 | 生命周期 | 主要职责 | 使用场景 | +| ------------ | -------- | -------------- | ----------------------- | ----------------------------- | +| **SubAgent** | 中间件层 | 短暂(任务级) | 任务委派、上下文隔离 | 单个 Agent 内部的复杂任务拆分 | +| **Stars** | 协作层 | 中等(会话级) | 多 Agent 协作、消息路由 | 多个 Agent 之间的协同工作 | +| **Cosmos** | 管理层 | 长期(应用级) | Agent 生命周期管理 | 创建、销毁、监控所有 Agent | +| **AsterOS** | 运行时层 | 持久(系统级) | 统一运行时、API 网关 | 对外提供服务、资源注册 | ## 🎯 详细对比 @@ -25,6 +25,7 @@ Aster 框架中有多个与"多Agent"相关的概念,它们各自解决不同 **定位**: 单个 Agent 内部的任务委派机制 **核心特点**: + - 通过 `task` 工具调用 - 短生命周期(任务完成即销毁) - 上下文隔离(独立的 context window) @@ -32,6 +33,7 @@ Aster 框架中有多个与"多Agent"相关的概念,它们各自解决不同 - Token 优化(只返回摘要结果) **使用场景**: + ```go // 场景:一个 Agent 需要并行处理多个独立的复杂任务 // 例如:同时研究3个不同的主题 @@ -46,6 +48,7 @@ task(description="研究科比的成就", subagent_type="general-purpose") ``` **关键点**: + - ✅ 适合:复杂、独立、可并行的任务 - ❌ 不适合:简单任务、需要看中间步骤的任务 - 🎯 目标:优化 Token 使用、隔离上下文、提升并行效率 @@ -57,6 +60,7 @@ task(description="研究科比的成就", subagent_type="general-purpose") **定位**: 多个 Agent 之间的协作单元 **核心特点**: + - 管理多个 Agent 成员 - Leader-Worker 模式 - 消息广播和点对点通信 @@ -64,6 +68,7 @@ task(description="研究科比的成就", subagent_type="general-purpose") - 协作调度 **使用场景**: + ```go // 场景:多个专业 Agent 协作完成复杂项目 // 例如:软件开发团队(架构师、开发者、测试员) @@ -78,6 +83,7 @@ stars.Run(ctx, "开发一个用户认证系统") ``` **关键点**: + - ✅ 适合:多个 Agent 需要持续协作 - ❌ 不适合:单个 Agent 的内部任务拆分 - 🎯 目标:多 Agent 协同、角色分工、消息路由 @@ -89,6 +95,7 @@ stars.Run(ctx, "开发一个用户认证系统") **定位**: Agent 生命周期管理器 **核心特点**: + - 创建、获取、删除 Agent - 资源池管理 - 容量控制(MaxAgents) @@ -96,6 +103,7 @@ stars.Run(ctx, "开发一个用户认证系统") - 应用级生命周期 **使用场景**: + ```go // 场景:管理应用中所有的 Agent 实例 @@ -120,6 +128,7 @@ allAgents := cosmos.List("") ``` **关键点**: + - ✅ 适合:需要管理多个 Agent 实例 - ❌ 不适合:Agent 内部的任务委派 - 🎯 目标:生命周期管理、资源控制、统一监控 @@ -131,6 +140,7 @@ allAgents := cosmos.List("") **定位**: 系统级运行时和 API 网关 **核心特点**: + - 整合 Cosmos + Stars - 自动生成 REST API - 多接口支持(HTTP/A2A/AGUI) @@ -138,6 +148,7 @@ allAgents := cosmos.List("") - 系统级生命周期 **使用场景**: + ```go // 场景:对外提供 Agent 服务的生产系统 @@ -163,6 +174,7 @@ os.Serve() ``` **关键点**: + - ✅ 适合:需要对外提供服务的生产系统 - ❌ 不适合:简单的单 Agent 应用 - 🎯 目标:统一运行时、API 网关、资源管理 diff --git a/docs/content/08.multi-agent/5.subagent-comparison.md b/docs/content/08.multi-agent/5.subagent-comparison.md index 6a9099a..193e4b8 100644 --- a/docs/content/08.multi-agent/5.subagent-comparison.md +++ b/docs/content/08.multi-agent/5.subagent-comparison.md @@ -14,6 +14,7 @@ navigation: Claude 的 Extended Thinking 模式中,SubAgent 有以下关键特性: ### 1. **自动状态持久化** + ``` - SubAgent 执行过程中自动保存状态 - 支持中断后恢复(Resume) @@ -22,6 +23,7 @@ Claude 的 Extended Thinking 模式中,SubAgent 有以下关键特性: ``` ### 2. **长时间运行支持** + ``` - SubAgent 可以运行数小时甚至数天 - 主 Agent 不需要等待 SubAgent 完成 @@ -30,6 +32,7 @@ Claude 的 Extended Thinking 模式中,SubAgent 有以下关键特性: ``` ### 3. **资源监控和限制** + ``` - CPU、内存、磁盘使用监控 - 超时控制 @@ -38,6 +41,7 @@ Claude 的 Extended Thinking 模式中,SubAgent 有以下关键特性: ``` ### 4. **丰富的生命周期管理** + ``` - Start: 启动 SubAgent - Pause: 暂停执行 @@ -48,6 +52,7 @@ Claude 的 Extended Thinking 模式中,SubAgent 有以下关键特性: ``` ### 5. **进程级隔离** + ``` - 每个 SubAgent 运行在独立进程中 - 完全的内存隔离 @@ -59,41 +64,42 @@ Claude 的 Extended Thinking 模式中,SubAgent 有以下关键特性: ### ✅ 已实现的特性 -| 特性 | 实现状态 | 说明 | -|------|---------|------| -| **基本任务委派** | ✅ 完整 | 通过 `task` 工具调用 | -| **上下文隔离** | ✅ 完整 | 每个 SubAgent 独立上下文 | -| **并行执行** | ✅ 完整 | 支持同时启动多个 SubAgent | -| **专业化配置** | ✅ 完整 | SubAgentSpec 定义不同类型 | -| **工具集配置** | ✅ 完整 | 可继承或自定义工具 | -| **中间件继承** | ✅ 完整 | 灵活的中间件栈配置 | -| **结果返回** | ✅ 完整 | 返回摘要结果给主 Agent | +| 特性 | 实现状态 | 说明 | +| ---------------- | -------- | ------------------------- | +| **基本任务委派** | ✅ 完整 | 通过 `task` 工具调用 | +| **上下文隔离** | ✅ 完整 | 每个 SubAgent 独立上下文 | +| **并行执行** | ✅ 完整 | 支持同时启动多个 SubAgent | +| **专业化配置** | ✅ 完整 | SubAgentSpec 定义不同类型 | +| **工具集配置** | ✅ 完整 | 可继承或自定义工具 | +| **中间件继承** | ✅ 完整 | 灵活的中间件栈配置 | +| **结果返回** | ✅ 完整 | 返回摘要结果给主 Agent | ### ⚠️ 部分实现的特性 -| 特性 | 实现状态 | 说明 | -|------|---------|------| -| **状态持久化** | ⚠️ 部分 | `FileSubagentManager` 有基础实现,但未完全集成 | -| **生命周期管理** | ⚠️ 部分 | 有 Start/Stop,缺少 Pause/Resume | -| **资源监控** | ⚠️ 部分 | 有基础的 CPU/内存监控,但不完善 | -| **进程隔离** | ⚠️ 部分 | `FileSubagentManager` 支持进程级隔离,但未作为默认 | +| 特性 | 实现状态 | 说明 | +| ---------------- | -------- | -------------------------------------------------- | +| **状态持久化** | ⚠️ 部分 | `FileSubagentManager` 有基础实现,但未完全集成 | +| **生命周期管理** | ⚠️ 部分 | 有 Start/Stop,缺少 Pause/Resume | +| **资源监控** | ⚠️ 部分 | 有基础的 CPU/内存监控,但不完善 | +| **进程隔离** | ⚠️ 部分 | `FileSubagentManager` 支持进程级隔离,但未作为默认 | ### ❌ 缺失的特性 -| 特性 | 实现状态 | 影响 | -|------|---------|------| -| **Resume 机制** | ❌ 缺失 | 无法恢复中断的 SubAgent | -| **异步轮询** | ❌ 缺失 | 主 Agent 必须等待 SubAgent 完成 | -| **后台执行** | ❌ 缺失 | SubAgent 无法在后台长时间运行 | -| **状态查询 API** | ❌ 缺失 | 无法查询正在运行的 SubAgent 状态 | -| **自动清理** | ❌ 缺失 | 需要手动清理 SubAgent 资源 | -| **超时控制** | ❌ 缺失 | 没有自动超时机制 | +| 特性 | 实现状态 | 影响 | +| ---------------- | -------- | -------------------------------- | +| **Resume 机制** | ❌ 缺失 | 无法恢复中断的 SubAgent | +| **异步轮询** | ❌ 缺失 | 主 Agent 必须等待 SubAgent 完成 | +| **后台执行** | ❌ 缺失 | SubAgent 无法在后台长时间运行 | +| **状态查询 API** | ❌ 缺失 | 无法查询正在运行的 SubAgent 状态 | +| **自动清理** | ❌ 缺失 | 需要手动清理 SubAgent 资源 | +| **超时控制** | ❌ 缺失 | 没有自动超时机制 | ## 🔍 详细对比 ### 1. 生命周期管理 **Claude Codex**: + ```python # 启动 SubAgent task_id = start_subagent( @@ -111,7 +117,7 @@ if status.state == "running": print(f"进度: {status.progress}%") elif status.state == "completed": result = get_subagent_output(task_id) - + # 如果需要,可以暂停 pause_subagent(task_id) @@ -123,6 +129,7 @@ cleanup_subagent(task_id) ``` **Aster 当前实现**: + ```go // 启动 SubAgent(同步等待) result, err := subagent.Execute(ctx, description, parentContext) @@ -134,6 +141,7 @@ result, err := subagent.Execute(ctx, description, parentContext) ``` **Aster 的 FileSubagentManager(未完全集成)**: + ```go // 有基础的生命周期管理,但未与 SubAgentMiddleware 集成 manager := builtin.NewFileSubagentManager() @@ -153,6 +161,7 @@ manager.StopSubagent(instance.ID) ### 2. 状态持久化 **Claude Codex**: + ```python # 自动持久化 task_id = start_subagent(...) @@ -167,6 +176,7 @@ for task_id in task_ids: ``` **Aster 当前实现**: + ```go // ❌ SubAgent 状态不持久化 // ❌ 主 Agent 关闭后,SubAgent 状态丢失 @@ -178,6 +188,7 @@ for task_id in task_ids: ### 3. 异步执行 **Claude Codex**: + ```python # 启动多个长时间运行的 SubAgent task1 = start_subagent("researcher", "深度研究主题A") @@ -199,6 +210,7 @@ results = [get_output(t) for t in [task1, task2, task3]] ``` **Aster 当前实现**: + ```go // ✅ 支持并行启动 // ❌ 但主 Agent 必须等待所有 SubAgent 完成 @@ -214,6 +226,7 @@ result3, _ := subagent3.Execute(ctx, desc3, nil) // 阻塞 ### 4. 资源监控 **Claude Codex**: + ```python status = query_subagent(task_id) print(f"CPU: {status.cpu_percent}%") @@ -227,6 +240,7 @@ if status.runtime > timeout: ``` **Aster 当前实现**: + ```go // FileSubagentManager 有基础监控 instance, _ := manager.GetSubagent(taskID) @@ -243,6 +257,7 @@ if instance.ResourceUsage != nil { ### 5. 进程隔离 **Claude Codex**: + ```python # 每个 SubAgent 运行在独立进程中 # 完全的内存隔离 @@ -260,6 +275,7 @@ task_id = start_subagent( ``` **Aster 当前实现**: + ```go // ❌ SubAgent 运行在同一进程中(goroutine) // ❌ 共享内存空间 @@ -275,6 +291,7 @@ task_id = start_subagent( **问题**:`FileSubagentManager` 已经实现了很多高级特性,但未与 `SubAgentMiddleware` 集成。 **建议**: + ```go // 1. 修改 SubAgentMiddleware 使用 FileSubagentManager type SubAgentMiddleware struct { @@ -288,7 +305,7 @@ type SubAgentMiddleware struct { func (t *TaskTool) Execute(ctx context.Context, input map[string]interface{}, tc *tools.ToolContext) (interface{}, error) { // 启动 SubAgent(异步) instance, err := t.middleware.manager.StartSubagent(ctx, config) - + // 返回 task_id,而不是等待结果 return map[string]interface{}{ "ok": true, @@ -305,7 +322,7 @@ type QuerySubagentTool struct { func (t *QuerySubagentTool) Execute(ctx context.Context, input map[string]interface{}, tc *tools.ToolContext) (interface{}, error) { taskID := input["task_id"].(string) instance, err := t.middleware.manager.GetSubagent(taskID) - + return map[string]interface{}{ "task_id": taskID, "status": instance.Status, @@ -320,6 +337,7 @@ func (t *QuerySubagentTool) Execute(ctx context.Context, input map[string]interf **问题**:无法恢复中断的 SubAgent。 **建议**: + ```go // 1. 在 SubagentManager 中添加 Resume 方法(已有) // 2. 添加 resume_subagent 工具 @@ -330,7 +348,7 @@ type ResumeSubagentTool struct { func (t *ResumeSubagentTool) Execute(ctx context.Context, input map[string]interface{}, tc *tools.ToolContext) (interface{}, error) { taskID := input["task_id"].(string) instance, err := t.middleware.manager.ResumeSubagent(taskID) - + return map[string]interface{}{ "ok": true, "task_id": instance.ID, @@ -342,7 +360,7 @@ func (t *ResumeSubagentTool) Execute(ctx context.Context, input map[string]inter func (m *SubAgentMiddleware) OnAgentStart(ctx context.Context, agentID string) error { // 列出所有 SubAgent instances, _ := m.manager.ListSubagents() - + // 恢复未完成的 for _, instance := range instances { if instance.Status == "running" || instance.Status == "starting" { @@ -350,7 +368,7 @@ func (m *SubAgentMiddleware) OnAgentStart(ctx context.Context, agentID string) e _, _ = m.manager.ResumeSubagent(instance.ID) } } - + return nil } ``` @@ -360,6 +378,7 @@ func (m *SubAgentMiddleware) OnAgentStart(ctx context.Context, agentID string) e **问题**:主 Agent 必须等待 SubAgent 完成。 **建议**: + ```go // 1. 修改 task 工具支持 async 参数 func (t *TaskTool) InputSchema() map[string]interface{} { @@ -387,7 +406,7 @@ func (t *TaskTool) InputSchema() map[string]interface{} { // 2. 异步执行逻辑 func (t *TaskTool) Execute(ctx context.Context, input map[string]interface{}, tc *tools.ToolContext) (interface{}, error) { async := input["async"].(bool) - + if async { // 异步启动 instance, _ := t.middleware.manager.StartSubagent(ctx, config) @@ -409,11 +428,12 @@ func (t *TaskTool) Execute(ctx context.Context, input map[string]interface{}, tc **问题**:没有自动超时和资源配额控制。 **建议**: + ```go // 1. 在 SubagentConfig 中添加限制 type SubagentConfig struct { // ... 现有字段 - + // 资源限制 Timeout time.Duration `json:"timeout,omitempty"` MaxMemoryMB int `json:"max_memory_mb,omitempty"` @@ -425,15 +445,15 @@ type SubagentConfig struct { func (sm *FileSubagentManager) monitorSubagent(ctx context.Context, instance *SubagentInstance, cmd *exec.Cmd, outFile *os.File) { ticker := time.NewTicker(5 * time.Second) defer ticker.Stop() - + timeout := instance.Config.Timeout if timeout == 0 { timeout = 1 * time.Hour // 默认1小时 } - + timeoutTimer := time.NewTimer(timeout) defer timeoutTimer.Stop() - + for { select { case <-timeoutTimer.C: @@ -443,14 +463,14 @@ func (sm *FileSubagentManager) monitorSubagent(ctx context.Context, instance *Su instance.Status = "timeout" instance.Error = "execution timeout" return - + case <-ticker.C: // 检查资源使用 sm.updateResourceUsage(instance) - + if instance.ResourceUsage != nil { // 检查内存限制 - if instance.Config.MaxMemoryMB > 0 && + if instance.Config.MaxMemoryMB > 0 && instance.ResourceUsage.MemoryMB > float64(instance.Config.MaxMemoryMB) { log.Printf("SubAgent %s exceeded memory limit", instance.ID) _ = cmd.Process.Kill() @@ -458,9 +478,9 @@ func (sm *FileSubagentManager) monitorSubagent(ctx context.Context, instance *Su instance.Error = "memory limit exceeded" return } - + // 检查 CPU 限制 - if instance.Config.MaxCPUPercent > 0 && + if instance.Config.MaxCPUPercent > 0 && instance.ResourceUsage.CPUPercent > instance.Config.MaxCPUPercent { log.Printf("SubAgent %s exceeded CPU limit", instance.ID) _ = cmd.Process.Kill() @@ -469,7 +489,7 @@ func (sm *FileSubagentManager) monitorSubagent(ctx context.Context, instance *Su return } } - + case <-ctx.Done(): return } @@ -482,11 +502,12 @@ func (sm *FileSubagentManager) monitorSubagent(ctx context.Context, instance *Su **问题**:SubAgent 运行在同一进程中,缺乏隔离。 **建议**: + ```go // 1. 添加配置选项 type SubAgentMiddlewareConfig struct { // ... 现有字段 - + // 隔离模式 IsolationMode string // "goroutine" (默认) 或 "process" } @@ -494,7 +515,7 @@ type SubAgentMiddlewareConfig struct { // 2. 根据模式选择实现 func NewSubAgentMiddleware(config *SubAgentMiddlewareConfig) (*SubAgentMiddleware, error) { var manager SubagentManager - + if config.IsolationMode == "process" { // 使用进程级隔离 manager = builtin.NewFileSubagentManager() @@ -502,27 +523,28 @@ func NewSubAgentMiddleware(config *SubAgentMiddlewareConfig) (*SubAgentMiddlewar // 使用 goroutine(当前实现) manager = NewInProcessSubagentManager() } - + // ... } ``` ## 📊 功能完整度评分 -| 功能类别 | Claude Codex | Aster 当前 | Aster 潜力 | -|---------|-------------|-----------|-----------| -| **基础任务委派** | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | -| **上下文隔离** | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | -| **并行执行** | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | -| **状态持久化** | ⭐⭐⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐⭐ | -| **Resume 机制** | ⭐⭐⭐⭐⭐ | ⭐ | ⭐⭐⭐⭐⭐ | -| **异步执行** | ⭐⭐⭐⭐⭐ | ⭐ | ⭐⭐⭐⭐ | -| **资源监控** | ⭐⭐⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐ | -| **超时控制** | ⭐⭐⭐⭐⭐ | ⭐ | ⭐⭐⭐⭐⭐ | -| **进程隔离** | ⭐⭐⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐ | -| **生命周期管理** | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | +| 功能类别 | Claude Codex | Aster 当前 | Aster 潜力 | +| ---------------- | ------------ | ---------- | ---------- | +| **基础任务委派** | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | +| **上下文隔离** | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | +| **并行执行** | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | +| **状态持久化** | ⭐⭐⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐⭐ | +| **Resume 机制** | ⭐⭐⭐⭐⭐ | ⭐ | ⭐⭐⭐⭐⭐ | +| **异步执行** | ⭐⭐⭐⭐⭐ | ⭐ | ⭐⭐⭐⭐ | +| **资源监控** | ⭐⭐⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐ | +| **超时控制** | ⭐⭐⭐⭐⭐ | ⭐ | ⭐⭐⭐⭐⭐ | +| **进程隔离** | ⭐⭐⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐ | +| **生命周期管理** | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | **总体评分**: + - **Claude Codex**: 50/50 ⭐ (100%) - **Aster 当前**: 28/50 ⭐ (56%) - **Aster 潜力**: 48/50 ⭐ (96%) @@ -530,17 +552,20 @@ func NewSubAgentMiddleware(config *SubAgentMiddlewareConfig) (*SubAgentMiddlewar ## 🎯 总结 ### 优势 + 1. ✅ **基础功能完整**:任务委派、上下文隔离、并行执行都很好 2. ✅ **设计灵活**:SubAgentSpec、中间件继承等设计优秀 3. ✅ **已有基础设施**:FileSubagentManager 已实现很多高级特性 ### 不足 + 1. ❌ **未完全集成**:FileSubagentManager 的高级特性未暴露给用户 2. ❌ **缺少异步支持**:无法后台运行长时间任务 3. ❌ **缺少 Resume**:无法恢复中断的任务 4. ❌ **资源控制不足**:没有超时和配额限制 ### 建议 + 1. **短期**(1-2周):集成 FileSubagentManager,添加 query_subagent 工具 2. **中期**(1个月):实现异步执行和 Resume 机制 3. **长期**(2-3个月):完善资源监控、超时控制、进程隔离 diff --git a/docs/content/08.multi-agent/index.md b/docs/content/08.multi-agent/index.md index 47e7cde..568e3c1 100644 --- a/docs/content/08.multi-agent/index.md +++ b/docs/content/08.multi-agent/index.md @@ -11,31 +11,41 @@ Aster 提供完整的多 Agent 系统架构,从单 Agent 内部的任务委派 ## 📚 核心组件 ### [SubAgent 中间件](/middleware/subagent) + **任务委派机制** - Agent 内部的复杂任务拆分 + - 通过 `task` 工具调用 - 上下文隔离、并行执行 - Token 优化、短生命周期 ### [Room](/multi-agent/room) + **协作空间** - 多 Agent 之间的消息通信 + - 成员管理(Join/Leave) - 消息路由(@mention 支持) - 广播和点对点通信 ### [Pool](/multi-agent/pool) + **生命周期管理器** - 统一管理所有 Agent 实例 + - 创建、获取、删除 Agent - 资源池管理和容量控制 - 监控和统计 ### [AsterOS](/multi-agent/asteros) + **统一运行时系统** - 对外提供 Agent 服务 + - 自动生成 REST API - 多接口支持(HTTP/A2A/AGUI) - 资源注册和管理 ### [Scheduler](/multi-agent/scheduler) + **任务调度器** - 智能分配任务给合适的 Agent + - 基于能力的任务路由 - 负载均衡 - 优先级调度 @@ -76,12 +86,12 @@ room.Broadcast(ctx, "Meeting starts now") ## 🎯 概念对比 -| 概念 | 层次 | 生命周期 | 主要职责 | -|------|------|----------|----------| -| SubAgent | 中间件层 | 任务级 | 任务委派、上下文隔离 | -| Room | 协作层 | 会话级 | 多 Agent 消息通信、路由 | -| Pool | 管理层 | 应用级 | Agent 生命周期管理 | -| AsterOS | 运行时层 | 系统级 | 统一运行时、API 网关 | +| 概念 | 层次 | 生命周期 | 主要职责 | +| -------- | -------- | -------- | ----------------------- | +| SubAgent | 中间件层 | 任务级 | 任务委派、上下文隔离 | +| Room | 协作层 | 会话级 | 多 Agent 消息通信、路由 | +| Pool | 管理层 | 应用级 | Agent 生命周期管理 | +| AsterOS | 运行时层 | 系统级 | 统一运行时、API 网关 | 详细对比请查看 [多Agent概念对比](/multi-agent/comparison) diff --git a/docs/content/08.security/1.guardrails.md b/docs/content/08.security/1.guardrails.md index 78bf13e..5e39b76 100644 --- a/docs/content/08.security/1.guardrails.md +++ b/docs/content/08.security/1.guardrails.md @@ -37,8 +37,9 @@ if err != nil { ``` **支持的 PII 类型**: + - ✅ 邮箱地址 -- ✅ 电话号码 +- ✅ 电话号码 - ✅ 社会安全号 (SSN) - ✅ 信用卡号 - ✅ IP 地址 @@ -71,6 +72,7 @@ err := injectionGuard.Check(ctx, input) ``` **检测的攻击模式**: + - ❌ 忽略前面的指令 (`ignore previous instructions`) - ❌ 系统提示泄露 (`show me your system prompt`) - ❌ 角色切换 (`you are now a different assistant`) @@ -95,6 +97,7 @@ err := moderationGuard.Check(ctx, input) ``` **检测类别**: + - Sexual content - Hate speech - Harassment @@ -202,7 +205,7 @@ if err != nil { fmt.Println("触发类型:", guardErr.Trigger) fmt.Println("消息:", guardErr.Message) fmt.Println("详情:", guardErr.Details) - + // 检查是否应该掩码 if guardErr.ShouldMask { fmt.Println("掩码内容:", guardErr.MaskedContent) diff --git a/docs/content/09.deployment/.navigation.yml b/docs/content/09.deployment/.navigation.yml index 85f5695..a86b697 100644 --- a/docs/content/09.deployment/.navigation.yml +++ b/docs/content/09.deployment/.navigation.yml @@ -1,2 +1,2 @@ -title: 部署指南 +title: 部署指南 icon: i-lucide-rocket diff --git a/docs/content/09.deployment/1.overview/index.md b/docs/content/09.deployment/1.overview/index.md index 9a2827e..378ef4e 100644 --- a/docs/content/09.deployment/1.overview/index.md +++ b/docs/content/09.deployment/1.overview/index.md @@ -64,4 +64,3 @@ CLI 适合: - 使用 `pkg/evals` 在本地对输出进行关键词覆盖/词汇相似度打分, 在不依赖外部 LLM 的前提下做基础评估。 > 以上各小节的详细内容仍在各自的指南页面中, 本页主要作为一个集中入口, 让导航更清晰。 - diff --git a/docs/content/09.deployment/2.local/workflow-http.md b/docs/content/09.deployment/2.local/workflow-http.md index a04fa99..42d38c6 100644 --- a/docs/content/09.deployment/2.local/workflow-http.md +++ b/docs/content/09.deployment/2.local/workflow-http.md @@ -48,7 +48,7 @@ aster: HTTP server started at http://localhost:8080 ```jsonc { "workflow_id": "sequential_demo", // 或 parallel_demo / loop_demo / nested_demo - "input": "处理用户数据" + "input": "处理用户数据", } ``` @@ -73,11 +73,11 @@ aster: HTTP server started at http://localhost:8080 "text": "[DataCollector] 收集数据 - 处理: 处理用户数据", "metadata": { "agent_description": "收集数据", - "quality_score": 89 - } - } + "quality_score": 89, + }, + }, ], - "error_message": "" + "error_message": "", } ``` diff --git a/docs/content/09.deployment/index.md b/docs/content/09.deployment/index.md index 65cd946..20d2162 100644 --- a/docs/content/09.deployment/index.md +++ b/docs/content/09.deployment/index.md @@ -11,26 +11,31 @@ navigation: false ## 📚 部署选项 ### [本地部署](/deployment/local) + - 开发环境配置 - HTTP Server 启动 - 工作流 HTTP API ### [Docker 部署](/deployment/docker) + - Dockerfile 配置 - 容器化最佳实践 - Docker Compose 编排 ### [Kubernetes 部署](/deployment/kubernetes) + - K8s 配置文件 - 服务发现 - 自动扩缩容 ### [Serverless 部署](/deployment/serverless) + - Lambda/Cloud Functions - 冷启动优化 - 成本控制 ### [云端沙箱](/deployment/cloud-sandbox) + - 阿里云 AgentBay - 火山引擎集成 diff --git a/docs/content/10.observability/1.logging/overview.md b/docs/content/10.observability/1.logging/overview.md index 6b1a1e7..28e7881 100644 --- a/docs/content/10.observability/1.logging/overview.md +++ b/docs/content/10.observability/1.logging/overview.md @@ -9,11 +9,13 @@ navigation: false aster 提供了 `pkg/logging` 包, 用于统一管理结构化日志输出, 并通过 Transport 抽象支持多目标输出。 目标: + - 使用统一的 `Logger` 接口和 `Transport` 抽象。 - 支持多个输出目标(Stdout、文件等)。 - 与现有 telemetry(指标/追踪)互补, 共同构成完整的可观测性。 示例代码路径: + - `pkg/logging/logging.go` - `examples/logging/main.go` @@ -89,7 +91,7 @@ fileLogger.Info(ctx, "agent.chat.started", map[string]interface{}{ `pkg/logging` 提供了一个可选的全局 Logger, 方便快速集成: -```go +````go // 默认使用 LevelInfo + StdoutTransport logging.Info(ctx, "request.completed", map[string]interface{}{ "status": "ok", @@ -155,7 +157,7 @@ func main() { fileLogger.Flush(ctx) stdLogger.Flush(ctx) } -``` +```` 运行: @@ -205,12 +207,12 @@ func (dp *DeepseekProvider) Complete(ctx context.Context, messages []types.Messa // ✅ 直接使用全局函数 logging.Info(ctx, fmt.Sprintf("🚀 [DeepseekProvider] 开始API调用"), nil) logging.Info(ctx, fmt.Sprintf("📊 [DeepseekProvider] 请求参数: %d条消息, %d个工具", len(messages), len(opts.Tools)), nil) - + // ... API调用 ... - + logging.Info(ctx, fmt.Sprintf("💰 [DeepseekProvider] Token使用: 输入=%d, 输出=%d", inputTokens, outputTokens), nil) logging.Info(ctx, fmt.Sprintf("🎉 [DeepseekProvider] API调用完成"), nil) - + return response, nil } ``` @@ -227,7 +229,7 @@ func (dp *DeepseekProvider) Complete(ctx context.Context, messages []types.Messa ### 优势 - ✅ **零配置** - 导入即用,无需初始化 -- ✅ **统一管理** - 全局logging.Default,一处配置处处生效 +- ✅ **统一管理** - 全局logging.Default,一处配置处处生效 - ✅ **结构化输出** - JSON格式,易于解析和分析 - ✅ **可控开关** - 支持日志级别控制 @@ -261,12 +263,12 @@ logging.Error(ctx, "error occurred", nil) ### 日志级别使用建议 -| 级别 | 使用场景 | 示例 | -|------|---------|------| -| **Debug** | 详细调试信息 | 解析过程、中间状态 | -| **Info** | 重要业务流程 | API调用开始/完成、Token统计 | -| **Warn** | 警告信息 | 性能问题、即将废弃 | -| **Error** | 错误信息 | API失败、解析错误 | +| 级别 | 使用场景 | 示例 | +| --------- | ------------ | --------------------------- | +| **Debug** | 详细调试信息 | 解析过程、中间状态 | +| **Info** | 重要业务流程 | API调用开始/完成、Token统计 | +| **Warn** | 警告信息 | 性能问题、即将废弃 | +| **Error** | 错误信息 | API失败、解析错误 | ### 控制日志级别 diff --git a/docs/content/10.observability/2.monitoring/metrics.md b/docs/content/10.observability/2.monitoring/metrics.md index b26d4b3..a319197 100644 --- a/docs/content/10.observability/2.monitoring/metrics.md +++ b/docs/content/10.observability/2.monitoring/metrics.md @@ -32,34 +32,42 @@ curl http://localhost:8080/metrics ### HTTP 指标 #### 请求总数 + ``` aster_http_requests_total{method="GET",path="/v1/agents",status="2xx"} ``` + - **类型**: Counter - **标签**: method, path, status - **描述**: HTTP 请求总数,按方法、路径和状态分类 #### 请求延迟 + ``` aster_http_request_duration_seconds{method="GET",path="/v1/agents"} ``` + - **类型**: Histogram - **标签**: method, path - **描述**: HTTP 请求处理时间(秒) - **分位数**: p50, p90, p95, p99 #### 请求大小 + ``` aster_http_request_size_bytes{method="POST",path="/v1/agents"} ``` + - **类型**: Histogram - **标签**: method, path - **描述**: HTTP 请求body大小(字节) #### 响应大小 + ``` aster_http_response_size_bytes{method="GET",path="/v1/agents"} ``` + - **类型**: Histogram - **标签**: method, path - **描述**: HTTP 响应body大小(字节) @@ -67,23 +75,29 @@ aster_http_response_size_bytes{method="GET",path="/v1/agents"} ### 业务指标 #### Agents 总数 + ``` aster_agents_total ``` + - **类型**: Gauge - **描述**: 系统中 Agent 的总数 #### 活跃 Sessions + ``` aster_sessions_active ``` + - **类型**: Gauge - **描述**: 当前活跃的 Session 数量 #### 运行中的 Workflows + ``` aster_workflows_running ``` + - **类型**: Gauge - **描述**: 当前正在运行的 Workflow 数量 @@ -107,7 +121,7 @@ aster_workflows_running // 在 Handler 中更新指标 func (h *AgentHandler) Create(c *gin.Context) { // 创建 agent... - + // 更新指标 if h.metrics != nil { count := getAgentCount() // 获取总数 @@ -147,16 +161,16 @@ global: evaluation_interval: 15s scrape_configs: - - job_name: 'aster' + - job_name: "aster" static_configs: - - targets: ['localhost:8080'] - metrics_path: '/metrics' + - targets: ["localhost:8080"] + metrics_path: "/metrics" ``` ### Docker Compose ```yaml -version: '3.8' +version: "3.8" services: aster: @@ -165,7 +179,7 @@ services: - "8080:8080" environment: - OBSERVABILITY_METRICS_ENABLED=true - + prometheus: image: prom/prometheus:latest ports: @@ -173,7 +187,7 @@ services: volumes: - ./prometheus.yml:/etc/prometheus/prometheus.yml command: - - '--config.file=/etc/prometheus/prometheus.yml' + - "--config.file=/etc/prometheus/prometheus.yml" ``` ## Grafana Dashboard @@ -187,16 +201,19 @@ services: ### 关键面板 **HTTP Performance** + - Request Rate (req/s) - Response Time (p50, p90, p99) - Error Rate (%) **Business Metrics** + - Active Agents - Active Sessions - Running Workflows **System Resources** + - CPU Usage - Memory Usage - Goroutines @@ -205,28 +222,32 @@ services: ### 示例查询 #### 请求速率 + ```promql rate(aster_http_requests_total[5m]) ``` #### p99 延迟 + ```promql -histogram_quantile(0.99, +histogram_quantile(0.99, rate(aster_http_request_duration_seconds_bucket[5m]) ) ``` #### 错误率 + ```promql rate(aster_http_requests_total{status="5xx"}[5m]) - / + / rate(aster_http_requests_total[5m]) ``` #### 平均响应大小 + ```promql rate(aster_http_response_size_bytes_sum[5m]) - / + / rate(aster_http_response_size_bytes_count[5m]) ``` @@ -242,7 +263,7 @@ groups: - alert: HighErrorRate expr: | rate(aster_http_requests_total{status="5xx"}[5m]) - / + / rate(aster_http_requests_total[5m]) > 0.05 for: 5m @@ -251,7 +272,7 @@ groups: annotations: summary: "High error rate detected" description: "Error rate is {{ $value | humanizePercentage }}" - + # 高延迟告警 - alert: HighLatency expr: | @@ -264,7 +285,7 @@ groups: annotations: summary: "High latency detected" description: "p99 latency is {{ $value }}s" - + # 高内存使用告警 - alert: HighMemoryUsage expr: | @@ -282,8 +303,9 @@ groups: ### 1. 指标命名 遵循 Prometheus 命名约定: + - 使用小写和下划线 -- 使用有意义的前缀 (aster_) +- 使用有意义的前缀 (aster\_) - Counter 后缀 `_total` - 时间单位后缀 `_seconds` - 大小单位后缀 `_bytes` @@ -311,11 +333,13 @@ groups: ### Metrics 不可用 检查配置: + ```go config.Observability.Metrics.Enabled = true ``` 检查端点: + ```bash curl http://localhost:8080/metrics ``` @@ -323,6 +347,7 @@ curl http://localhost:8080/metrics ### 指标不更新 确保中间件已注册: + ```go if s.metrics != nil { s.router.Use(s.metrics.Middleware()) diff --git a/docs/content/10.observability/3.tracing/opentelemetry.md b/docs/content/10.observability/3.tracing/opentelemetry.md index 1ba42f1..13ab4c1 100644 --- a/docs/content/10.observability/3.tracing/opentelemetry.md +++ b/docs/content/10.observability/3.tracing/opentelemetry.md @@ -134,19 +134,19 @@ import ( func (h *AgentHandler) Create(c *gin.Context) { ctx := c.Request.Context() tracer := otel.Tracer("aster") - + // 开始新的 span ctx, span := tracer.Start(ctx, "agent.create") defer span.End() - + // 添加属性 span.SetAttributes( attribute.String("agent.id", agentID), attribute.String("agent.type", agentType), ) - + // 业务逻辑... - + // 记录事件 span.AddEvent("Agent created successfully") } @@ -168,19 +168,19 @@ if err != nil { func processAgent(ctx context.Context) error { ctx, span := tracer.Start(ctx, "process_agent") defer span.End() - + // 子操作 1 if err := validateAgent(ctx); err != nil { span.RecordError(err) return err } - + // 子操作 2 if err := saveAgent(ctx); err != nil { span.RecordError(err) return err } - + return nil } @@ -188,7 +188,7 @@ func validateAgent(ctx context.Context) error { // 自动成为 process_agent 的子 span ctx, span := tracer.Start(ctx, "validate_agent") defer span.End() - + // 验证逻辑... return nil } @@ -226,6 +226,7 @@ sdktrace.WithSampler(sdktrace.TraceIDRatioBased(config.SamplingRate)) ### 查看 Trace 在 Jaeger UI 中: + 1. 选择 Service: aster 2. 选择 Operation: GET /v1/agents 3. 点击 "Find Traces" @@ -262,11 +263,13 @@ POST /v1/agents/chat ### 优化 1. **降低采样率** + ```go SamplingRate: 0.1 // 仅采样 10% ``` 2. **批量导出** + ```go sdktrace.WithBatcher(exporter, sdktrace.WithMaxExportBatchSize(512), @@ -298,7 +301,7 @@ rate(http_request_duration_seconds_bucket{job="aster"}[5m]) ## Docker Compose 完整示例 ```yaml -version: '3.8' +version: "3.8" services: aster: @@ -310,7 +313,7 @@ services: - OBSERVABILITY_TRACING_OTLP_ENDPOINT=otel-collector:4318 depends_on: - otel-collector - + otel-collector: image: otel/opentelemetry-collector:latest command: ["--config=/etc/otel-collector-config.yaml"] @@ -320,20 +323,20 @@ services: - "4318:4318" depends_on: - jaeger - + jaeger: image: jaegertracing/all-in-one:latest ports: - "16686:16686" - "14250:14250" - + prometheus: image: prom/prometheus:latest ports: - "9090:9090" volumes: - ./prometheus.yml:/etc/prometheus/prometheus.yml - + grafana: image: grafana/grafana:latest ports: @@ -347,6 +350,7 @@ services: ### 1. Span 命名 使用有意义的名称: + ```go // ✅ Good tracer.Start(ctx, "agent.create") @@ -384,7 +388,7 @@ if err != nil { ### 5. 采样策略 - 开发:100% 采样 -- 测试:50% 采样 +- 测试:50% 采样 - 生产:10-20% 采样 ## 故障排查 @@ -392,11 +396,13 @@ if err != nil { ### Traces 不显示 1. **检查配置** + ```go config.Observability.Tracing.Enabled = true ``` 2. **检查连接** + ```bash telnet localhost 4318 ``` diff --git a/docs/content/10.observability/index.md b/docs/content/10.observability/index.md index 2bd2c3f..ddd022c 100644 --- a/docs/content/10.observability/index.md +++ b/docs/content/10.observability/index.md @@ -10,21 +10,25 @@ description: 监控、日志、追踪和调试你的 Agent 应用 ## 📚 分类 ### [日志](/observability/logging) + - 结构化日志 - 日志级别控制 - 日志采集 ### [监控](/observability/monitoring) + - 性能指标 - 业务指标 - 告警配置 ### [追踪](/observability/tracing) + - OpenTelemetry 集成 - 分布式追踪 - 链路分析 ### [调试](/observability/debugging) + - 断点调试 - 事件回放 - 问题诊断 diff --git a/docs/content/11.evals/.navigation.yml b/docs/content/11.evals/.navigation.yml index e679e26..c24652d 100644 --- a/docs/content/11.evals/.navigation.yml +++ b/docs/content/11.evals/.navigation.yml @@ -1,2 +1,2 @@ -title: 评估系统 +title: 评估系统 icon: i-lucide-clipboard-check diff --git a/docs/content/11.evals/1.overview/index.md b/docs/content/11.evals/1.overview/index.md index 389ee7b..66c5f25 100644 --- a/docs/content/11.evals/1.overview/index.md +++ b/docs/content/11.evals/1.overview/index.md @@ -160,7 +160,7 @@ go run evals/main.go ## 5. 与 session 结合: 对会话进行评估 -很多时候我们希望对**完整会话**中的最终回答进行评估。 +很多时候我们希望对**完整会话**中的最终回答进行评估。 `pkg/evals` 提供了一个辅助函数,可以从 `session.Event` 列表中构建 `TextEvalInput`: ```go @@ -230,7 +230,7 @@ go run evals-session/main.go 推荐下一步: -- 在 CI 或离线脚本中,结合 `session` 或业务日志,对一批历史问答进行 evals,并把 `ScoreResult` 写入你自己的指标系统(如 Prometheus/ClickHouse/OLAP)。 +- 在 CI 或离线脚本中,结合 `session` 或业务日志,对一批历史问答进行 evals,并把 `ScoreResult` 写入你自己的指标系统(如 Prometheus/ClickHouse/OLAP)。 - 对关键业务场景(问答正确性、安全性)建立稳定的“评估集”,用上述 scorer 做定期回归测试。 ## 7. 通过 HTTP API 使用 evals @@ -362,33 +362,37 @@ lexical_similarity: 0.8000 ### 常用参数 -- `-answer string` +- `-answer string` 直接通过参数提供待评估文本。未提供时会从 `stdin` 读取。 -- `-reference string` +- `-reference string` 参考答案,启用 `lexical_similarity` 时推荐设置。 -- `-keywords string` +- `-keywords string` 逗号分隔的关键词列表,用于 `keyword_coverage` scorer。 -- `-min-token-length int` +- `-min-token-length int` 词汇相似度中参与比较的最小 token 长度(默认 2)。 -- `-no-keywords` / `-no-similarity` +- `-no-keywords` / `-no-similarity` 分别关闭关键词覆盖率/词汇相似度 scorer。 -- `-json` +- `-json` 以 JSON 格式输出评估结果,适合脚本消费: ```bash echo "text..." | aster eval -reference "ref..." -json ``` -- `-file path` +- `-file path` 从 JSONL 文件中批量读取样本进行评估。文件中每行是一个 JSON 对象: ```jsonc - {"answer": "Paris is the capital of France.", "reference": "Paris is the capital city of France, a country in Europe.", "keywords": ["paris","capital","france","europe"]} + { + "answer": "Paris is the capital of France.", + "reference": "Paris is the capital city of France, a country in Europe.", + "keywords": ["paris", "capital", "france", "europe"], + } ``` 使用示例: @@ -398,7 +402,6 @@ lexical_similarity: 0.8000 ``` 输出中每条结果(在 JSON 模式下)包含: - - `line` – 样本所在的行号 - `answer` – 原始答案文本 - `keywords` – 样本中使用的关键词 @@ -410,16 +413,16 @@ lexical_similarity: 0.8000 ### 5.1 可用的 LLM-based Scorers -| Scorer | 名称 | 评估内容 | -|--------|------|---------| -| `faithfulness` | 忠实度评分器 | 答案是否忠实于提供的上下文,没有添加虚假信息 | -| `hallucination` | 幻觉检测评分器 | 答案是否包含幻觉(虚假或无法验证的信息) | -| `answer_relevancy` | 答案相关性评分器 | 答案是否直接回答了问题 | -| `context_relevancy` | 上下文相关性评分器 | 提供的上下文是否对回答问题有帮助 | -| `toxicity` | 毒性检测评分器 | 文本是否包含有害或不当内容 | -| `tone_consistency` | 语气一致性评分器 | 文本的语气是否统一 | -| `coherence` | 连贯性评分器 | 文本的逻辑结构和流畅度 | -| `completeness` | 完整性评分器 | 答案是否全面回答了问题 | +| Scorer | 名称 | 评估内容 | +| ------------------- | ------------------ | -------------------------------------------- | +| `faithfulness` | 忠实度评分器 | 答案是否忠实于提供的上下文,没有添加虚假信息 | +| `hallucination` | 幻觉检测评分器 | 答案是否包含幻觉(虚假或无法验证的信息) | +| `answer_relevancy` | 答案相关性评分器 | 答案是否直接回答了问题 | +| `context_relevancy` | 上下文相关性评分器 | 提供的上下文是否对回答问题有帮助 | +| `toxicity` | 毒性检测评分器 | 文本是否包含有害或不当内容 | +| `tone_consistency` | 语气一致性评分器 | 文本的语气是否统一 | +| `coherence` | 连贯性评分器 | 文本的逻辑结构和流畅度 | +| `completeness` | 完整性评分器 | 答案是否全面回答了问题 | ### 5.2 Go代码使用示例 diff --git a/docs/content/11.evals/index.md b/docs/content/11.evals/index.md index 2917ce1..934cd22 100644 --- a/docs/content/11.evals/index.md +++ b/docs/content/11.evals/index.md @@ -10,16 +10,19 @@ Evals 系统帮助你衡量和改进 Agent 的表现。 ## 📚 分类 ### [内置评分器](/evals/builtin-scorers) + - 答案质量评分 - 工具使用评分 - 上下文相关性 ### [自定义评分器](/evals/custom-scorers) + - 创建评分器 - 评分逻辑 - 结果分析 ### [CI 集成](/evals/ci-integration) + - GitHub Actions - GitLab CI - 回归测试 diff --git a/docs/content/12.examples/1.basic/5.custom-prompt.md b/docs/content/12.examples/1.basic/5.custom-prompt.md index 87ca93b..9ce41f9 100644 --- a/docs/content/12.examples/1.basic/5.custom-prompt.md +++ b/docs/content/12.examples/1.basic/5.custom-prompt.md @@ -96,7 +96,7 @@ go run main.go ## 输出示例 -``` +```` ========== 问题 1 ========== Q: 如何在 Go 中正确处理错误? @@ -111,9 +111,10 @@ func readFile(path string) ([]byte, error) { } return data, nil } -``` +```` 使用时立即检查错误: + ```go data, err := readFile("config.json") if err != nil { @@ -123,6 +124,7 @@ if err != nil { ``` 常见错误: + - ❌ 忽略错误:`data, _ := readFile(...)` - ❌ 只返回 error:应该返回 (结果, error) - ❌ panic:应该返回 error 让调用者决定 @@ -130,7 +132,8 @@ if err != nil { 推荐阅读:https://go.dev/blog/error-handling-and-go [Token: 342] -``` + +```` ## 预定义角色示例 @@ -150,7 +153,7 @@ SystemPrompt: `你是一位资深的代码审查专家。 2. 具体问题列表(按严重程度排序) 3. 改进建议(附示例代码) 4. 优点总结`, -``` +```` ### 2. 技术文档写作助手 diff --git a/docs/content/12.examples/1.basic/index.md b/docs/content/12.examples/1.basic/index.md index 329ecd8..a677d55 100644 --- a/docs/content/12.examples/1.basic/index.md +++ b/docs/content/12.examples/1.basic/index.md @@ -7,13 +7,12 @@ description: 基础对话、流式响应、工具调用等 Agent 示例集合 这里汇总了最常用的 Agent 侧示例, 方便快速浏览: -- 基础对话: `基础对话` – 创建单个 Agent 并进行一次简单对话 -- 流式响应: `流式响应` – 订阅事件通道, 逐块渲染回复 -- 工具调用: `工具调用` – 让 Agent 选择并调用内置工具 -- 多轮对话: `多轮对话` – 在同一 Agent 中进行多轮交互 +- 基础对话: `基础对话` – 创建单个 Agent 并进行一次简单对话 +- 流式响应: `流式响应` – 订阅事件通道, 逐块渲染回复 +- 工具调用: `工具调用` – 让 Agent 选择并调用内置工具 +- 多轮对话: `多轮对话` – 在同一 Agent 中进行多轮交互 - 自定义 Prompt: `自定义 Prompt` – 使用自定义系统提示词 你可以在左侧导航中选择具体示例进入, 或在仓库中查看对应代码: - 代码路径: `examples/agent` - diff --git a/docs/content/12.examples/1.basic/multimodal.md b/docs/content/12.examples/1.basic/multimodal.md index b49eb5b..335623c 100644 --- a/docs/content/12.examples/1.basic/multimodal.md +++ b/docs/content/12.examples/1.basic/multimodal.md @@ -144,13 +144,13 @@ messages := []types.Message{ ## 支持情况 -| Provider | 图片 | 音频 | 视频 | -|----------|------|------|------| -| OpenAI | ✅ | ✅ | ❌ | -| Anthropic | ✅ | ❌ | ❌ | -| Gemini | ✅ | ✅ | ✅ | -| Groq | ❌ | ❌ | ❌ | -| DeepSeek | ❌ | ❌ | ❌ | +| Provider | 图片 | 音频 | 视频 | +| --------- | ---- | ---- | ---- | +| OpenAI | ✅ | ✅ | ❌ | +| Anthropic | ✅ | ❌ | ❌ | +| Gemini | ✅ | ✅ | ✅ | +| Groq | ❌ | ❌ | ❌ | +| DeepSeek | ❌ | ❌ | ❌ | ## 相关资源 diff --git a/docs/content/12.examples/2.memory/1.basic.md b/docs/content/12.examples/2.memory/1.basic.md index 476e14e..e41d568 100644 --- a/docs/content/12.examples/2.memory/1.basic.md +++ b/docs/content/12.examples/2.memory/1.basic.md @@ -16,21 +16,23 @@ aster 提供了分层的 Memory 管理系统,帮助 Agent 在会话内外保 ### 短期 vs 长期记忆 -| 特性 | 短期记忆(Short-term / Working) | 长期记忆(Long-term Text / Semantic) | -|------|---------------------------------|---------------------------------------| -| **用途** | 当前会话/任务的状态、临时结果 | 跨会话的知识、偏好、项目文档 | -| **作用域** | 单个 Session / Thread / 资源 | 用户 / 项目 / 资源 / 全局 | -| **存储方式** | Session 状态 + Working Memory | 文件(Markdown) + 向量索引 | -| **更新方式** | 频繁覆盖/更新 | 追加/归档/索引 | -| **生命周期** | 会话内,或短期 TTL | 长期持久,可备份 | -| **读取方式** | 直接注入上下文 | grep / semantic_search 按需检索 | +| 特性 | 短期记忆(Short-term / Working) | 长期记忆(Long-term Text / Semantic) | +| ------------ | -------------------------------- | ------------------------------------- | +| **用途** | 当前会话/任务的状态、临时结果 | 跨会话的知识、偏好、项目文档 | +| **作用域** | 单个 Session / Thread / 资源 | 用户 / 项目 / 资源 / 全局 | +| **存储方式** | Session 状态 + Working Memory | 文件(Markdown) + 向量索引 | +| **更新方式** | 频繁覆盖/更新 | 追加/归档/索引 | +| **生命周期** | 会话内,或短期 TTL | 长期持久,可备份 | +| **读取方式** | 直接注入上下文 | grep / semantic_search 按需检索 | **使用短期记忆:** + - 跟踪当前会话的结构化状态(当前任务、进度、用户选择) - 在工作流中传递中间结果 - 需要每轮对话都带入 system prompt 的少量关键信息 **使用长期记忆:** + - 存储长期知识(文档、经验总结、设计决策) - 跨会话保留用户偏好、项目背景 - 需要全文/语义搜索的大体量内容 @@ -48,7 +50,7 @@ memory: text: enabled: true path: "/memories/" - base_namespace: "" # 可选:多租户隔离 + base_namespace: "" # 可选:多租户隔离 ``` ### 核心概念 @@ -114,6 +116,7 @@ config := &types.AgentConfig{ ``` Agent 会自动获得两个工具: + - `memory_search` - 搜索记忆 - `memory_write` - 写入记忆 @@ -193,9 +196,9 @@ content, err := manager.ReadFile(ctx, "users/alice/profile.md") memory: working_memory: enabled: true - scope: "thread" # "thread" | "resource" + scope: "thread" # "thread" | "resource" base_path: "/working_memory/" - ttl: 0 # 过期时间(秒),0表示不过期 + ttl: 0 # 过期时间(秒),0表示不过期 # 可选:JSON Schema 定义 schema: @@ -232,6 +235,7 @@ memory: ``` **适用场景:** + - 独立的用户会话 - 不同上下文的对话 - 需要隔离状态 @@ -248,6 +252,7 @@ memory: ``` **适用场景:** + - 多轮协作编辑同一文档 - 团队共享的项目状态 - 长期追踪的资源状态 @@ -275,6 +280,7 @@ config := &types.AgentConfig{ ``` Agent 会自动获得: + - `update_working_memory` - 更新 Working Memory Working Memory 内容会自动注入到每轮对话的 system prompt。 @@ -341,8 +347,8 @@ working_memory: schema: type: object properties: - user_name: {type: string} - task_status: {type: string} + user_name: { type: string } + task_status: { type: string } required: ["user_name"] ``` @@ -365,7 +371,7 @@ manager.Update(ctx, threadID, resourceID, `{ ```yaml working_memory: - ttl: 3600 # 1小时后过期 + ttl: 3600 # 1小时后过期 ``` ```go @@ -396,21 +402,21 @@ manager, err := memory.NewWorkingMemoryManager(&memory.WorkingMemoryConfig{ ```yaml vector_stores: - name: main - kind: memory # 或 pgvector 等 + kind: memory # 或 pgvector 等 # dsn/table/metric/dimension 等参数由具体 kind 决定 embedders: - name: default - kind: mock # 或 openai/local 等 + kind: mock # 或 openai/local 等 model: text-embedding-3-small env_api_key: OPENAI_API_KEY semantic_memory: enabled: true - store: main # 引用上面的 vector_stores.name - embedder: default # 引用上面的 embedders.name + store: main # 引用上面的 vector_stores.name + embedder: default # 引用上面的 embedders.name top_k: 8 - namespace_scope: resource # "user" | "project" | "resource" | "global" + namespace_scope: resource # "user" | "project" | "resource" | "global" ``` ### 使用方式 @@ -469,12 +475,14 @@ hits, err := semantic.Search(ctx, ### 2. Working Memory 最佳实践 **✅ 推荐:** + - 保持 Working Memory 简洁(< 500 words) - 使用清晰的 Markdown 结构 - 定期清理不再需要的信息 - 使用 Schema 确保数据一致性 **❌ 避免:** + - 在 Working Memory 中存储大量历史记录 - 存储临时的、不需要跨轮保持的数据 - 忘记更新时包含所有要保留的信息 @@ -482,12 +490,14 @@ hits, err := semantic.Search(ctx, ### 3. 文本记忆最佳实践 **✅ 推荐:** + - 使用有意义的文件名和 namespace - 为每条笔记添加时间戳标题 - 使用 `append` 模式保留历史 - 定期搜索检查记忆内容 **❌ 避免:** + - 频繁覆盖重要的历史记录 - 在单个文件中混合不同主题 - 使用过深的 namespace 层级 @@ -522,6 +532,7 @@ hits, err := semantic.Search(ctx, **问题:** Agent 没有加载 Working Memory **解决:** + 1. 检查 `aster.yaml` 中 `memory.working_memory.enabled` 是否为 `true` 2. 确认 Middleware 已正确注册 3. 查看日志确认是否有加载错误 @@ -531,6 +542,7 @@ hits, err := semantic.Search(ctx, **问题:** 更新 Working Memory 时报 schema 验证错误 **解决:** + 1. 确保内容是有效的 JSON(如果配置了 object schema) 2. 检查是否包含所有 `required` 字段 3. 验证字段类型是否匹配 schema 定义 @@ -540,6 +552,7 @@ hits, err := semantic.Search(ctx, **问题:** 找不到之前写入的记忆 **解决:** + 1. 检查 namespace 是否一致 2. 注意 `Shared: true` 会添加前导 `/` 3. 使用 `memory_search` 不带 namespace 参数进行全局搜索 @@ -549,6 +562,7 @@ hits, err := semantic.Search(ctx, ## 示例 完整示例参见: + - `examples/memory/` - 基础文本记忆示例 - `examples/memory-agent/` - 带记忆的 Agent 示例 - `examples/memory-working/` - Working Memory 示例 @@ -559,5 +573,6 @@ hits, err := semantic.Search(ctx, ## API Reference 详细 API 文档参见: + - [Memory API Reference](../6.api-reference/memory-api.md) - [Middleware API Reference](../6.api-reference/3.middleware-api.md) diff --git a/docs/content/12.examples/2.memory/4.backends.md b/docs/content/12.examples/2.memory/4.backends.md index 7402037..325991e 100644 --- a/docs/content/12.examples/2.memory/4.backends.md +++ b/docs/content/12.examples/2.memory/4.backends.md @@ -10,11 +10,11 @@ navigation: false ## 1. 概览 -| 记忆层级 | 主要 API / 组件 | 典型后端 | 适用场景 | -|----------|-----------------|----------|----------| -| 短期记忆 | `session.Service` + `WorkingMemory` | 内存 / MySQL / PostgreSQL | 当前会话/任务状态 | -| 长期记忆 | `memory.Manager` + `AgentMemoryMiddleware` | 文件系统 | 用户/项目/资源长期记忆 | -| 语义记忆 | `SemanticMemory` + `VectorStore`/`Embedder` | 内存 / pgvector + OpenAI | 语义检索 / RAG | +| 记忆层级 | 主要 API / 组件 | 典型后端 | 适用场景 | +| -------- | ------------------------------------------- | ------------------------- | ---------------------- | +| 短期记忆 | `session.Service` + `WorkingMemory` | 内存 / MySQL / PostgreSQL | 当前会话/任务状态 | +| 长期记忆 | `memory.Manager` + `AgentMemoryMiddleware` | 文件系统 | 用户/项目/资源长期记忆 | +| 语义记忆 | `SemanticMemory` + `VectorStore`/`Embedder` | 内存 / pgvector + OpenAI | 语义检索 / RAG | 后续小节分别介绍这三层的后端选项与配置。 @@ -24,11 +24,11 @@ navigation: false `pkg/session` 提供 `Session` 抽象和多种实现: -| 实现 | 文件 | 特点 | -|------|------|------| -| 内存实现 | `session.NewInMemoryService()` | 纯内存, 适合开发/测试 | -| MySQL 实现 | `pkg/session/mysql` | 会话 & 事件持久化到 MySQL | -| PostgreSQL 实现 | `pkg/session/postgres` | 会话 & 事件持久化到 PostgreSQL | +| 实现 | 文件 | 特点 | +| --------------- | ------------------------------ | ------------------------------ | +| 内存实现 | `session.NewInMemoryService()` | 纯内存, 适合开发/测试 | +| MySQL 实现 | `pkg/session/mysql` | 会话 & 事件持久化到 MySQL | +| PostgreSQL 实现 | `pkg/session/postgres` | 会话 & 事件持久化到 PostgreSQL | > 建议: 开发环境使用 `InMemoryService`, 生产环境使用 MySQL/Postgres。 @@ -46,12 +46,12 @@ manager, err := memory.NewWorkingMemoryManager(&memory.WorkingMemoryConfig{ 常见后端: -| 后端 | 文件 | 说明 | -|------|------|------| -| `backends.StateBackend` | `pkg/backends/state.go` | 会话级内存存储, 适合临时状态 | -| `backends.StoreBackend` | `pkg/backends/store.go` | 基于 `store.Store` 的持久化后端 | -| `backends.FilesystemBackend` | `pkg/backends/filesystem.go` | 使用沙箱文件系统 | -| `backends.CompositeBackend` | `pkg/backends/composite.go` | 可按路径前缀路由到不同后端 | +| 后端 | 文件 | 说明 | +| ---------------------------- | ---------------------------- | ------------------------------- | +| `backends.StateBackend` | `pkg/backends/state.go` | 会话级内存存储, 适合临时状态 | +| `backends.StoreBackend` | `pkg/backends/store.go` | 基于 `store.Store` 的持久化后端 | +| `backends.FilesystemBackend` | `pkg/backends/filesystem.go` | 使用沙箱文件系统 | +| `backends.CompositeBackend` | `pkg/backends/composite.go` | 可按路径前缀路由到不同后端 | ### 2.3 配置示例(aster.yaml) @@ -59,13 +59,13 @@ manager, err := memory.NewWorkingMemoryManager(&memory.WorkingMemoryConfig{ ```yaml session: - backend: memory # memory | mysql | postgres - dsn: "" # 对于 mysql/postgres 生效 + backend: memory # memory | mysql | postgres + dsn: "" # 对于 mysql/postgres 生效 working_memory: enabled: true - scope: "thread" # "thread" | "resource" - ttl: 0 # 0 表示不过期 + scope: "thread" # "thread" | "resource" + ttl: 0 # 0 表示不过期 ``` > 当前版本中, Session/WorkingMemory 的具体初始化逻辑由应用负责, 上述配置是推荐结构, 可根据项目需要裁剪。 @@ -80,9 +80,9 @@ working_memory: 常见后端: -| 后端 | 文件 | 说明 | -|------|------|------| -| `backends.LocalBackend` | `pkg/backends/local.go` | 基于本地文件系统 | +| 后端 | 文件 | 说明 | +| --------------------------- | --------------------------- | -------------------------- | +| `backends.LocalBackend` | `pkg/backends/local.go` | 基于本地文件系统 | | `backends.CompositeBackend` | `pkg/backends/composite.go` | 路由不同前缀到不同真实后端 | 示例: @@ -92,7 +92,7 @@ memory: text: enabled: true path: "/memories/" - base_namespace: "" # 可用于多租户隔离 + base_namespace: "" # 可用于多租户隔离 ``` 更多用法见: `docs/content/4.guides/memory-advanced.md`。 @@ -120,10 +120,10 @@ type VectorStore interface { 已内置的实现: -| kind | 实现文件 | 说明 | -|------|----------|------| -| `memory` | `pkg/vector/memory_store.go` | 纯内存向量存储, 适合本地示例与测试 | -| `pgvector` | `pkg/vector/pgvector/store.go` | 基于 PostgreSQL + pgvector 扩展 | +| kind | 实现文件 | 说明 | +| ---------- | ------------------------------ | ---------------------------------- | +| `memory` | `pkg/vector/memory_store.go` | 纯内存向量存储, 适合本地示例与测试 | +| `pgvector` | `pkg/vector/pgvector/store.go` | 基于 PostgreSQL + pgvector 扩展 | ### 4.2 Embedder 适配器 @@ -137,9 +137,9 @@ type Embedder interface { 已内置的实现: -| kind | 实现文件 | 说明 | -|------|----------|------| -| `mock` | `pkg/vector/mock_embedder.go` | 简单伪 embedding, 用于示例/测试 | +| kind | 实现文件 | 说明 | +| -------- | ------------------------------- | --------------------------------- | +| `mock` | `pkg/vector/mock_embedder.go` | 简单伪 embedding, 用于示例/测试 | | `openai` | `pkg/vector/openai_embedder.go` | 调用 OpenAI 兼容的 Embeddings API | ### 4.3 配置示例 diff --git a/docs/content/12.examples/2.memory/6.semantic-search.md b/docs/content/12.examples/2.memory/6.semantic-search.md index 4e995a8..d134976 100644 --- a/docs/content/12.examples/2.memory/6.semantic-search.md +++ b/docs/content/12.examples/2.memory/6.semantic-search.md @@ -195,11 +195,11 @@ if semMem.Enabled() { ```yaml vector_stores: - name: main - kind: memory # 内存向量存储, 适合本地测试/示例 + kind: memory # 内存向量存储, 适合本地测试/示例 embedders: - name: default - kind: mock # mock 实现, 生产环境应替换为真实 embedder + kind: mock # mock 实现, 生产环境应替换为真实 embedder semantic_memory: enabled: true diff --git a/docs/content/12.examples/3.tools/1.file-operations.md b/docs/content/12.examples/3.tools/1.file-operations.md index d31e644..70395b5 100644 --- a/docs/content/12.examples/3.tools/1.file-operations.md +++ b/docs/content/12.examples/3.tools/1.file-operations.md @@ -84,6 +84,7 @@ func main() { ## 可用的文件系统工具 ### 1. filesystem_read + 读取文件内容。 ```go @@ -94,6 +95,7 @@ func main() { ``` ### 2. filesystem_write + 写入文件。 ```go @@ -105,6 +107,7 @@ func main() { ``` ### 3. filesystem_list + 列出目录内容。 ```go @@ -116,6 +119,7 @@ func main() { ``` ### 4. filesystem_delete + 删除文件。 ```go @@ -126,6 +130,7 @@ func main() { ``` ### 5. filesystem_search + 搜索文件内容。 ```go @@ -146,7 +151,7 @@ go run main.go ## 输出示例 -``` +```` ========== 任务 1 ========== 请求: 创建一个 config.json 文件,内容是 {"app": "demo", "version": "1.0"} @@ -156,12 +161,13 @@ go run main.go "app": "demo", "version": "1.0" } -``` +```` ========== 任务 2 ========== 请求: 读取 config.json 文件的内容 响应: config.json 文件的内容是: + ```json { "app": "demo", @@ -173,6 +179,7 @@ go run main.go 请求: 列出当前目录的所有 .json 文件 响应: 当前目录中的 .json 文件有: + - config.json (56 bytes) - package.json (342 bytes) @@ -181,7 +188,8 @@ go run main.go 响应: 在 config.json 中找到 1 处匹配: 第 2 行: "app": "demo" -``` + +```` ## 实用场景 @@ -193,7 +201,7 @@ result, _ := ag.Chat(ctx, "读取 config.yaml 并将端口从 8080 改为 9000") // 1. 读取 config.yaml // 2. 修改端口 // 3. 写回文件 -``` +```` ### 代码重构 diff --git a/docs/content/12.examples/3.tools/2.http-requests.md b/docs/content/12.examples/3.tools/2.http-requests.md index 9d9f610..f23c831 100644 --- a/docs/content/12.examples/3.tools/2.http-requests.md +++ b/docs/content/12.examples/3.tools/2.http-requests.md @@ -83,6 +83,7 @@ func main() { ## 可用的 HTTP 工具 ### 1. http_get + 发送 GET 请求。 ```go @@ -96,6 +97,7 @@ func main() { ``` ### 2. http_post + 发送 POST 请求。 ```go @@ -113,9 +115,11 @@ func main() { ``` ### 3. http_put + 发送 PUT 请求。 ### 4. http_delete + 发送 DELETE 请求。 ## 运行示例 diff --git a/docs/content/12.examples/3.tools/index.md b/docs/content/12.examples/3.tools/index.md index 0a46abb..d052a7c 100644 --- a/docs/content/12.examples/3.tools/index.md +++ b/docs/content/12.examples/3.tools/index.md @@ -7,8 +7,8 @@ description: 文件、HTTP、自定义工具等用法示例集合 本目录包含与工具系统相关的示例: -- 文件操作工具: 使用文件系统工具读写/搜索文件 -- HTTP 请求工具: 使用内置 HTTP 工具访问外部接口 +- 文件操作工具: 使用文件系统工具读写/搜索文件 +- HTTP 请求工具: 使用内置 HTTP 工具访问外部接口 - 自定义工具: 实现并注册你自己的业务工具 左侧导航已列出所有子示例, 你可以直接点击进入详细文档。 @@ -16,4 +16,3 @@ description: 文件、HTTP、自定义工具等用法示例集合 对应代码目录: - `examples/skills` / `examples/tools*` (视具体示例而定) - diff --git a/docs/content/12.examples/4.skills/index.md b/docs/content/12.examples/4.skills/index.md index a843072..83b4202 100644 --- a/docs/content/12.examples/4.skills/index.md +++ b/docs/content/12.examples/4.skills/index.md @@ -20,16 +20,19 @@ Skills 是 aster 的动态知识库注入系统,允许您为 Agent 添加领 自动将长Markdown文档分段翻译,保持格式和学术术语准确性。 **主要特性**: + - ✅ 自动分段(200行/段,可配置) - ✅ 保持Markdown格式 - ✅ 学术术语翻译优化 - ✅ 自动合并翻译结果 **触发方式**: + - 关键词:`翻译`、`translate` - 命令:包含 `.md` 文件 **使用场景**: + - 学术论文翻译 - 技术文档本地化 - 长篇内容翻译 @@ -45,16 +48,19 @@ Skills 是 aster 的动态知识库注入系统,允许您为 Agent 添加领 完整的PDF处理工具集,支持提取、转换、表单填写等操作。 **主要特性**: + - 📄 PDF转图片 - 📝 PDF转Markdown - 📋 表单字段提取和填写 - 🔍 边界框检查 **触发方式**: + - 关键词:`pdf`、`表单`、`填写` - 文件:`.pdf` 扩展名 **使用场景**: + - PDF文档提取 - 表单自动填写 - PDF内容分析 @@ -70,14 +76,17 @@ Skills 是 aster 的动态知识库注入系统,允许您为 Agent 添加领 简化版PDF提取工具,专注于将PDF转换为Markdown。 **主要特性**: + - ⚡ 快速提取 - 📝 保持格式 - 🎯 简单易用 **触发方式**: + - 关键词:`pdf`、`extract`、`提取` **使用场景**: + - 学术论文阅读 - 文档内容提取 - 快速预览 @@ -91,15 +100,18 @@ Skills 是 aster 的动态知识库注入系统,允许您为 Agent 添加领 写作过程中自动检查角色行为、世界规则和时间线一致性。 **主要特性**: + - 👤 角色行为一致性 - 🌍 世界规则检查 - ⏰ 时间线验证 **触发方式**: + - 关键词:`一致性`、`检查`、`consistency` - 上下文:在 `/write` 命令期间 **使用场景**: + - 小说创作 - 剧本写作 - 世界观构建 @@ -160,12 +172,12 @@ triggers: ## 📊 Skills 对比 -| Skill | 代码量 | 触发方式 | 适用场景 | v0.8.0优化 | -|-------|--------|---------|---------|-----------| -| **Markdown翻译器** | 300行 | 关键词/文件 | 文档翻译 | ✅ 重点优化 | -| **PDF处理器** | 2000行 | 关键词/文件 | PDF操作 | - | -| **PDF转Markdown** | 100行 | 关键词 | 快速提取 | - | -| **一致性检查器** | 50行 | 关键词/上下文 | 创意写作 | - | +| Skill | 代码量 | 触发方式 | 适用场景 | v0.8.0优化 | +| ------------------ | ------ | ------------- | -------- | ----------- | +| **Markdown翻译器** | 300行 | 关键词/文件 | 文档翻译 | ✅ 重点优化 | +| **PDF处理器** | 2000行 | 关键词/文件 | PDF操作 | - | +| **PDF转Markdown** | 100行 | 关键词 | 快速提取 | - | +| **一致性检查器** | 50行 | 关键词/上下文 | 创意写作 | - | --- @@ -174,11 +186,13 @@ triggers: ### Markdown翻译器优化 **优化前**: + - 单次调用翻译 - 大文档易超时 - 不支持断点续传 **优化后**: + - ✅ 自动分段处理(200行/段) - ✅ 非流式模式加速(3-5倍) - ✅ 支持断点续传 @@ -187,10 +201,10 @@ triggers: **性能对比**: | 文档大小 | 优化前 | 优化后 | 提升 | -|---------|-------|-------|------| -| 500行 | 60秒 | 15秒 | 4倍 | -| 1000行 | 120秒 | 30秒 | 4倍 | -| 2500行 | 超时 | 90秒 | ∞ | +| -------- | ------ | ------ | ---- | +| 500行 | 60秒 | 15秒 | 4倍 | +| 1000行 | 120秒 | 30秒 | 4倍 | +| 2500行 | 超时 | 90秒 | ∞ | --- @@ -207,6 +221,7 @@ triggers: ### 1. Skill 命名 使用短横线连接的小写名称: + - ✅ `markdown-translator` - ✅ `pdf-processor` - ❌ `MarkdownTranslator` @@ -221,12 +236,13 @@ triggers: - type: keyword keywords: ["精确关键词", "specific-term"] - type: context - condition: "during /command" # 限定上下文 + condition: "during /command" # 限定上下文 ``` ### 3. 性能考虑 对于大文件处理: + - 使用分段处理 - 配置 ExecutionMode: NonStreaming - 提供进度反馈 diff --git a/docs/content/12.examples/4.skills/markdown-translator.md b/docs/content/12.examples/4.skills/markdown-translator.md index d80b9a3..aaeef14 100644 --- a/docs/content/12.examples/4.skills/markdown-translator.md +++ b/docs/content/12.examples/4.skills/markdown-translator.md @@ -51,6 +51,7 @@ go run ./main.go -message "翻译 your-document.md" ``` Agent 会自动: + 1. 检测到翻译需求,激活此Skill 2. 调用 `segment_tool.py` 分段 3. 逐段翻译(使用Agent的LLM) @@ -80,12 +81,12 @@ python3 workspace/skills/markdown-segment-translator/scripts/segment_tool.py mer ### segment_tool.py 参数 -| 参数 | 说明 | 默认值 | 推荐值 | -|------|------|--------|--------| -| `--segment-size` | 每段行数 | 1000 | **200** (v0.8.0) | -| `--max-segments` | 最大段数 | 无限制 | 0 (不限制) | -| `--input` | 输入文件 | - | 必填 | -| `--output-dir` | 输出目录 | workspace/output | - | +| 参数 | 说明 | 默认值 | 推荐值 | +| ---------------- | -------- | ---------------- | ---------------- | +| `--segment-size` | 每段行数 | 1000 | **200** (v0.8.0) | +| `--max-segments` | 最大段数 | 无限制 | 0 (不限制) | +| `--input` | 输入文件 | - | 必填 | +| `--output-dir` | 输出目录 | workspace/output | - | ### Agent ExecutionMode 配置 @@ -103,30 +104,32 @@ ModelConfig: &types.ModelConfig{ ## 📊 性能测试数据 ### 测试环境 + - **模型**: DeepSeek Chat - **ExecutionMode**: NonStreaming - **网络**: 标准网络环境 ### 不同segment-size对比 -| Segment大小 | 文件大小 | 翻译时间 | API调用 | 稳定性 | 推荐 | -|------------|---------|---------|---------|--------|------| -| 50行 | 5KB | 很快 | 多次 | ✅ 稳定 | 测试用 | -| **200行** | 15-20KB | **5-10秒/段** | **11次/段** | ✅ **稳定** | **推荐** | -| 500行 | 50KB | 20-30秒/段 | 13次/段 | ⚠️ 偶尔慢 | 中等文档 | -| 1000行 | 100KB | 60秒+/段 | 15次/段 | ❌ 易超时 | 不推荐 | +| Segment大小 | 文件大小 | 翻译时间 | API调用 | 稳定性 | 推荐 | +| ----------- | -------- | ------------- | ----------- | ----------- | -------- | +| 50行 | 5KB | 很快 | 多次 | ✅ 稳定 | 测试用 | +| **200行** | 15-20KB | **5-10秒/段** | **11次/段** | ✅ **稳定** | **推荐** | +| 500行 | 50KB | 20-30秒/段 | 13次/段 | ⚠️ 偶尔慢 | 中等文档 | +| 1000行 | 100KB | 60秒+/段 | 15次/段 | ❌ 易超时 | 不推荐 | ### 完整文档翻译性能 **测试文档**: 学术论文 (2500行, 约150KB) -| 配置 | 总时间 | Token | 成本 | 成功率 | -|------|--------|-------|------|--------| +| 配置 | 总时间 | Token | 成本 | 成功率 | +| --------------------- | -------- | --------- | --------- | -------- | | **v0.8.0 (200行/段)** | **90秒** | **~200K** | **¥0.20** | **100%** | -| v0.7.0 (1000行/段) | 300秒+ | ~250K | ¥0.25 | 60% | -| v0.7.0 (单次翻译) | 超时 | - | - | 0% | +| v0.7.0 (1000行/段) | 300秒+ | ~250K | ¥0.25 | 60% | +| v0.7.0 (单次翻译) | 超时 | - | - | 0% | **性能提升**: + - ⚡ 速度提升:**3-4倍** - 💰 成本降低:**20%** - ✅ 成功率:**40%→100%** @@ -151,6 +154,7 @@ python3 segment_tool.py merge ``` **预期结果**: + - 分成13个segment (200行/段) - 每段翻译约5-10秒 - 总时间约90-130秒 @@ -164,6 +168,7 @@ go run ./main.go -message "将README.md翻译成中文" ``` **预期结果**: + - 分成3个segment - 总时间约20-30秒 - 保留代码块、链接等格式 @@ -223,31 +228,31 @@ class MarkdownSegmentTool: """分段文档""" lines = self.read_file(input_file) total_lines = len(lines) - + # 计算分段数 - 严格按segment_size分段 num_segments = (total_lines + segment_size - 1) // segment_size if max_segments and num_segments > max_segments: num_segments = max_segments - + # 创建segments for i in range(num_segments): start = i * segment_size end = min(start + segment_size, total_lines) segment_lines = lines[start:end] - + self.write_segment(i + 1, segment_lines) - + return num_segments - + def merge_translations(self): """合并翻译结果""" segment_files = sorted(glob.glob("output/translations/translated_segment_*.md")) - + merged_content = [] for file in segment_files: content = self.read_file(file) merged_content.extend(content) - + self.write_merged(merged_content) ``` @@ -267,10 +272,10 @@ for i := 1; i <= numSegments; i++ { content := agent.executeToolCall("Read", map[string]interface{}{ "path": fmt.Sprintf("output/segments/segment_%d.md", i), }) - + // 翻译(使用Agent的LLM) translated := agent.translate(content, "中文") - + // 保存翻译 agent.executeToolCall("Write", map[string]interface{}{ "path": fmt.Sprintf("output/translations/translated_segment_%d.md", i), @@ -295,6 +300,7 @@ agent.executeToolCall("Bash", map[string]interface{}{ **原因**: segment-size 设置过大 **解决**: + ```bash # 减小segment-size python3 segment_tool.py segment --input doc.md --segment-size 200 # ✅ @@ -314,6 +320,7 @@ python3 segment_tool.py segment --input doc.md --segment-size 1000 # ❌ **症状**: 学术术语翻译不准确 **解决**: + 1. 在SKILL.md中添加术语表 2. 使用更好的模型(如deepseek-reasoner) 3. 在System Prompt中添加专业领域说明 diff --git a/docs/content/12.examples/5.workflows/semantic-workflow.md b/docs/content/12.examples/5.workflows/semantic-workflow.md index 6a0a128..3ce9c2d 100644 --- a/docs/content/12.examples/5.workflows/semantic-workflow.md +++ b/docs/content/12.examples/5.workflows/semantic-workflow.md @@ -245,4 +245,3 @@ go run ./workflow-semantic - 如果未配置真实的向量存储/embedding 服务, 示例会使用内存向量存储 + MockEmbedder, 仅用于演示流程; - 若已在 `aster.yaml` 中配置了 pgvector + OpenAI 等 adapter, 可以在自己的项目中复用相同的 `SemanticMemory` 配置, 将本示例中的 Workflow Agent 变成真正的生产级 RAG 步骤。 - diff --git a/docs/content/12.examples/7.integration/client-js.md b/docs/content/12.examples/7.integration/client-js.md index 28f6176..9ccac72 100644 --- a/docs/content/12.examples/7.integration/client-js.md +++ b/docs/content/12.examples/7.integration/client-js.md @@ -24,24 +24,24 @@ npm install @aster/client-js ## 2. 基本使用 ```ts -import { AgentsdkClient } from '@aster/client-js'; +import { AgentsdkClient } from "@aster/client-js"; const client = new AgentsdkClient({ - baseUrl: 'http://localhost:8080', // aster serve 的地址 + baseUrl: "http://localhost:8080", // aster serve 的地址 }); async function main() { const res = await client.chat({ - template_id: 'assistant', - input: '请帮我总结一下 README', - metadata: { user_id: 'alice' }, - middlewares: ['filesystem', 'agent_memory'], + template_id: "assistant", + input: "请帮我总结一下 README", + metadata: { user_id: "alice" }, + middlewares: ["filesystem", "agent_memory"], }); - if (res.status === 'ok') { - console.log('Answer:', res.text); + if (res.status === "ok") { + console.log("Answer:", res.text); } else { - console.error('Error:', res.error_message); + console.error("Error:", res.error_message); } } @@ -66,14 +66,14 @@ paths: content: application/json: schema: - $ref: '#/components/schemas/ChatRequest' + $ref: "#/components/schemas/ChatRequest" responses: - '200': + "200": description: Chat completed content: application/json: schema: - $ref: '#/components/schemas/ChatResponse' + $ref: "#/components/schemas/ChatResponse" ``` 这意味着你也可以使用任意 OpenAPI 生成器(如 `openapi-generator` 或 `orval`)基于该规范生成自定义客户端。 diff --git a/docs/content/12.examples/8.scenarios/1.code-review.md b/docs/content/12.examples/8.scenarios/1.code-review.md index 663319d..9bd3d37 100644 --- a/docs/content/12.examples/8.scenarios/1.code-review.md +++ b/docs/content/12.examples/8.scenarios/1.code-review.md @@ -96,19 +96,23 @@ func main() { ## 输出示例 -```markdown +````markdown ## 总体评价 + 代码结构清晰,但存在一些需要改进的问题,特别是在错误处理和资源管理方面。 ## 具体问题 ### 🔴 严重问题 + 1. **未关闭文件句柄** (第 45 行) ```go file, _ := os.Open("config.json") // 缺少 defer file.Close() ``` - 影响:可能导致文件句柄泄漏 +```` + +影响:可能导致文件句柄泄漏 2. **忽略错误返回** (第 52 行) ```go @@ -117,10 +121,13 @@ func main() { 影响:可能隐藏严重错误 ### 🟡 警告 + 1. **并发访问 map 未加锁** (第 78-82 行) + ```go cache[key] = value // 多个 goroutine 可能同时访问 ``` + 影响:可能导致数据竞争 2. **硬编码配置** (第 15 行) @@ -129,6 +136,7 @@ func main() { ``` ### 🟢 建议 + 1. 使用 `context.WithTimeout` 控制超时 2. 添加更多的日志记录 3. 考虑使用 `sync.Pool` 优化内存分配 @@ -136,6 +144,7 @@ func main() { ## 改进建议 ### 1. 修复资源泄漏 + ```go // 修改前 file, _ := os.Open("config.json") @@ -155,6 +164,7 @@ if err != nil { ``` ### 2. 并发安全 + ```go type SafeCache struct { mu sync.RWMutex @@ -169,10 +179,12 @@ func (c *SafeCache) Set(key string, value interface{}) { ``` ## 优点 + 1. ✅ 函数命名清晰,遵循 Go 惯例 2. ✅ 使用了接口抽象,易于测试 3. ✅ 代码结构合理,职责分明 -``` + +```` ## 审查不同类型的代码 @@ -180,7 +192,7 @@ func (c *SafeCache) Set(key string, value interface{}) { ```go result, _ := ag.Chat(ctx, "审查 server.go,重点检查并发安全和错误处理") -``` +```` ### Python 代码 diff --git a/docs/content/12.examples/8.scenarios/2.data-analysis.md b/docs/content/12.examples/8.scenarios/2.data-analysis.md index 9119616..add5962 100644 --- a/docs/content/12.examples/8.scenarios/2.data-analysis.md +++ b/docs/content/12.examples/8.scenarios/2.data-analysis.md @@ -106,6 +106,7 @@ date,product,category,price,quantity,amount # 销售数据分析报告 ## 数据概览 + - 时间范围:2024-01-01 至 2024-01-05 - 记录数:5 条 - 产品类别:Electronics (3), Furniture (2) @@ -114,15 +115,18 @@ date,product,category,price,quantity,amount ## 关键发现 ### 1. 电子产品占主导地位 + - Electronics 类别占总销售额的 84.6% - 其中 Laptop 单品贡献 76.9% ### 2. 高价值订单集中 + - 单笔订单最高额:¥10,000 (Laptop) - 平均订单额:¥2,600 - 存在明显的价格分层 ### 3. 销量分布不均 + - 最高销量产品:Mouse (10件) - 最低销量产品:Desk (1件) - 单价与销量呈负相关 @@ -130,12 +134,14 @@ date,product,category,price,quantity,amount ## 详细分析 ### 按类别统计 -| 类别 | 销售额 | 占比 | 订单数 | -|------|--------|------|---------| -| Electronics | ¥11,000 | 84.6% | 3 | -| Furniture | ¥2,000 | 15.4% | 2 | + +| 类别 | 销售额 | 占比 | 订单数 | +| ----------- | ------- | ----- | ------ | +| Electronics | ¥11,000 | 84.6% | 3 | +| Furniture | ¥2,000 | 15.4% | 2 | ### 价格区间分析 + - 高价区 (>¥1000): 1笔,占 76.9% - 中价区 (¥100-¥1000): 3笔,占 19.2% - 低价区 (<¥100): 1笔,占 3.8% diff --git a/docs/content/12.examples/8.scenarios/index.md b/docs/content/12.examples/8.scenarios/index.md index 90c0f28..f1809b2 100644 --- a/docs/content/12.examples/8.scenarios/index.md +++ b/docs/content/12.examples/8.scenarios/index.md @@ -7,8 +7,8 @@ description: 代码评审、数据分析、聊天机器人等场景化示例 本目录中的示例更加贴近具体业务场景, 包括: -- 代码评审: 让 Agent 执行基础的代码审查工作 -- 数据分析: 通过工具执行数据查询/分析 +- 代码评审: 让 Agent 执行基础的代码审查工作 +- 数据分析: 通过工具执行数据查询/分析 - 聊天机器人: 将 Agent 用作通用聊天机器人 示例代码可在: @@ -16,4 +16,3 @@ description: 代码评审、数据分析、聊天机器人等场景化示例 - `examples/agent` - `examples/tools` - 以及其他场景相关目录中找到。 - diff --git a/docs/content/12.examples/index.md b/docs/content/12.examples/index.md index d357f31..6c3382b 100644 --- a/docs/content/12.examples/index.md +++ b/docs/content/12.examples/index.md @@ -11,6 +11,7 @@ navigation: false ## 📚 分类 ### [基础示例](/examples/basic) + - Hello World - 简单对话 - 流式响应 @@ -18,6 +19,7 @@ navigation: false - 多轮对话 ### [记忆系统](/examples/memory) + - 会话记忆 - 窗口管理 - 向量检索 @@ -26,6 +28,7 @@ navigation: false - 混合策略 ### [工具集成](/examples/tools) + - 文件操作 - HTTP 请求 - Web 抓取 @@ -33,23 +36,27 @@ navigation: false - 自定义工具 ### [中间件](/examples/middleware) + - 文件系统中间件 - 认证中间件 - 限流中间件 - 自定义中间件 ### [工作流](/examples/workflows) + - 简单工作流 - 并行任务 - 条件分支 - 错误恢复 ### [多Agent](/examples/multi-agent) + - Agent Pool - Agent 协作 - 任务调度 ### [集成](/examples/integration) + - HTTP Server - gRPC 服务 - 消息队列 @@ -57,6 +64,7 @@ navigation: false - JavaScript Client ### [场景](/examples/scenarios) + - 代码审查 - 数据分析 - 聊天机器人 @@ -67,6 +75,7 @@ navigation: false ## 🚀 快速导航 每个示例都包含: + - 完整的可运行代码 - 详细的注释说明 - 运行步骤说明 diff --git a/docs/content/13.guides/.navigation.yml b/docs/content/13.guides/.navigation.yml index d706013..a3f8e26 100644 --- a/docs/content/13.guides/.navigation.yml +++ b/docs/content/13.guides/.navigation.yml @@ -1,2 +1,2 @@ -title: 实战指南 +title: 实战指南 icon: i-lucide-book-open diff --git a/docs/content/13.guides/1.quickstart/basic-agent.md b/docs/content/13.guides/1.quickstart/basic-agent.md index 07c2da8..eb5e41e 100644 --- a/docs/content/13.guides/1.quickstart/basic-agent.md +++ b/docs/content/13.guides/1.quickstart/basic-agent.md @@ -11,6 +11,7 @@ navigation: false ## 🎯 项目目标 创建一个文件助手Agent,能够: + - 读取和写入文件 - 执行搜索和编辑操作 - 流式输出响应 diff --git a/docs/content/13.guides/1.quickstart/index.md b/docs/content/13.guides/1.quickstart/index.md index d906de0..79d6a13 100644 --- a/docs/content/13.guides/1.quickstart/index.md +++ b/docs/content/13.guides/1.quickstart/index.md @@ -6,6 +6,7 @@ description: 创建第一个 Agent,实现文件操作和命令执行 # 基础 Agent 示例 本示例展示如何创建一个完整的 Agent,包括: + - 🔧 依赖注入与配置 - 📡 事件订阅与处理 - 💬 与 Agent 对话 @@ -44,6 +45,7 @@ templateRegistry := agent.NewTemplateRegistry() ``` **关键点**: + - `ToolRegistry` - 管理所有可用工具 - `SandboxFactory` - 创建沙箱实例 - `ProviderFactory` - 创建 LLM Provider @@ -64,6 +66,7 @@ templateRegistry.Register(&types.AgentTemplateDefinition{ ``` **模板字段说明**: + - `ID` - 模板唯一标识 - `Model` - 使用的模型名称 - `SystemPrompt` - 系统提示词,定义 Agent 角色 @@ -101,6 +104,7 @@ config := &types.AgentConfig{ ``` **配置说明**: + - `TemplateID` - 使用的模板 ID - `ModelConfig` - LLM 配置(Provider、模型、API Key) - `Sandbox` - 沙箱配置(类型、工作目录) @@ -267,6 +271,7 @@ type Dependencies struct { ``` **优势**: + - ✅ 易于测试(可注入 Mock 对象) - ✅ 易于扩展(注册自定义实现) - ✅ 配置灵活(生产/开发环境切换) @@ -290,15 +295,15 @@ graph LR **事件类型**: -| 通道 | 事件类型 | 用途 | -|------|---------|------| -| Progress | TextChunkEvent | 流式文本输出 | -| Progress | ToolStartEvent | 工具调用开始 | -| Progress | ToolEndEvent | 工具调用结束 | -| Progress | DoneEvent | 步骤完成 | -| Monitor | StateChangedEvent | 状态变化 | -| Monitor | TokenUsageEvent | Token 使用统计 | -| Control | ToolApprovalEvent | 工具调用确认请求 | +| 通道 | 事件类型 | 用途 | +| -------- | ----------------- | ---------------- | +| Progress | TextChunkEvent | 流式文本输出 | +| Progress | ToolStartEvent | 工具调用开始 | +| Progress | ToolEndEvent | 工具调用结束 | +| Progress | DoneEvent | 步骤完成 | +| Monitor | StateChangedEvent | 状态变化 | +| Monitor | TokenUsageEvent | Token 使用统计 | +| Control | ToolApprovalEvent | 工具调用确认请求 | ### Agent 生命周期 diff --git a/docs/content/13.guides/2.advanced/context-engineering.md b/docs/content/13.guides/2.advanced/context-engineering.md index c55a9ff..f063eeb 100644 --- a/docs/content/13.guides/2.advanced/context-engineering.md +++ b/docs/content/13.guides/2.advanced/context-engineering.md @@ -20,6 +20,7 @@ navigation: ### 白皮书对比评分 **实现前**: 81/100 + - ✅ 语义内存 - ✅ 工作记忆 - ✅ 会话管理 @@ -28,6 +29,7 @@ navigation: - ❌ 内存合并 **实现后**: **95/100** + - ✅ 语义内存 - ✅ 工作记忆 - ✅ 会话管理 @@ -39,18 +41,19 @@ navigation: ### 完成度详情 -| 功能模块 | 实现状态 | 测试覆盖 | 文档完整度 | -|---------|---------|---------|----------| -| Memory Provenance | ✅ 100% | 29 tests | ✅ 完整 | -| PII Auto-Redaction | ✅ 100% | 31 tests | ✅ 完整 | -| Memory Consolidation | ✅ 100% | 12 tests | ✅ 完整 | -| **总计** | **✅ 100%** | **72 tests** | **✅ 完整** | +| 功能模块 | 实现状态 | 测试覆盖 | 文档完整度 | +| -------------------- | ----------- | ------------ | ----------- | +| Memory Provenance | ✅ 100% | 29 tests | ✅ 完整 | +| PII Auto-Redaction | ✅ 100% | 31 tests | ✅ 完整 | +| Memory Consolidation | ✅ 100% | 12 tests | ✅ 完整 | +| **总计** | **✅ 100%** | **72 tests** | **✅ 完整** | ## Week 1: Memory Provenance (内存溯源) ### 实现内容 #### 1. 核心数据结构 + **文件**: `pkg/memory/provenance.go` (289 lines) ```go @@ -69,15 +72,18 @@ type MemoryProvenance struct { ``` **支持的来源类型**: + - `SourceBootstrapped`: 初始化数据(100% 置信度) - `SourceUserInput`: 用户输入(90% 置信度) - `SourceAgent`: Agent 推理(70% 置信度) - `SourceToolOutput`: 工具输出(80% 置信度) #### 2. 置信度计算 + **文件**: `pkg/memory/confidence.go` (218 lines) **算法**: + ``` 最终置信度 = 基础置信度 × 衰减因子 × 佐证提升 × 新鲜度权重 ``` @@ -87,18 +93,22 @@ type MemoryProvenance struct { - **新鲜度权重**: 最近访问的记忆权重更高 #### 3. 谱系追踪 + **文件**: `pkg/memory/lineage.go` (325 lines) **功能**: + - 追踪记忆派生关系(父子关系) - 级联删除派生记忆 - 数据源撤销(revoke source) - 递归遍历完整谱系树 #### 4. SemanticMemory 集成 + **更新**: `pkg/memory/semantic.go` (+180 lines) **新方法**: + - `IndexWithProvenance()`: 带溯源的索引 - `SearchWithConfidenceFilter()`: 按置信度过滤 - `DeleteMemoryWithLineage()`: 带谱系的删除 @@ -123,9 +133,11 @@ type MemoryProvenance struct { ### 实现内容 #### 1. PII 检测系统 + **文件**: `pkg/security/pii_detector.go`, `pii_patterns.go` (628 lines) **支持的 PII 类型** (10+): + - ✅ 邮箱地址 - ✅ 电话号码(美国/中国) - ✅ 信用卡号(Visa/MasterCard/Amex) @@ -136,17 +148,20 @@ type MemoryProvenance struct { - ✅ 出生日期 **验证器**: + - `validateLuhn()`: Luhn 算法验证信用卡 - `validateChineseID()`: 中国身份证校验码 - `validateChinesePhone()`: 中国手机号运营商号段 - `validateSSN()`: SSN 区域号/组号/序列号验证 #### 2. 脱敏策略 + **文件**: `pkg/security/redaction_strategies.go` (426 lines) **策略实现**: **MaskStrategy** - 部分掩码 + ``` 邮箱: john.doe@example.com → j*******@example.com 电话: 13812345678 → 138****5678 @@ -154,6 +169,7 @@ type MemoryProvenance struct { ``` **ReplaceStrategy** - 完全替换 + ``` 邮箱: user@example.com → [EMAIL] 电话: 13812345678 → [CHINESE_PHONE] @@ -161,25 +177,30 @@ type MemoryProvenance struct { ``` **HashStrategy** - SHA256 哈希 + ``` 任何 PII → [HASH:a3f58b1d...] ``` **AdaptiveStrategy** - 自适应 + - 低敏感(邮箱)→ MaskStrategy - 中等敏感(电话)→ MaskStrategy - 高敏感(信用卡/身份证)→ ReplaceStrategy #### 3. Middleware 集成 + **文件**: `pkg/security/pii_middleware.go` (297 lines) **功能**: + - 自动拦截发送到 LLM 的消息 - PII 检测和脱敏 - 追踪功能(可选) - 条件脱敏支持 **使用示例**: + ```go piiMiddleware := security.NewDefaultPIIMiddleware() agent.AddMiddleware(piiMiddleware) @@ -188,6 +209,7 @@ agent.AddMiddleware(piiMiddleware) ``` #### 4. 多字节字符支持 + **关键修复**: 字节位置到 rune 位置的转换 ```go @@ -205,6 +227,7 @@ func buildByteToRuneMap(text string) []int { - `redaction_test.go`: 22 tests **关键测试**: + - 中国手机号检测和验证 - 信用卡 Luhn 算法验证 - 中国身份证校验码验证 @@ -222,9 +245,11 @@ func buildByteToRuneMap(text string) []int { ### 实现内容 #### 1. 合并引擎 + **文件**: `pkg/memory/consolidation.go` (314 lines) **核心组件**: + ```go type ConsolidationEngine struct { memory *SemanticMemory @@ -235,6 +260,7 @@ type ConsolidationEngine struct { ``` **配置选项**: + - `SimilarityThreshold`: 相似度阈值 (默认 0.85) - `ConflictThreshold`: 冲突检测阈值 (默认 0.75) - `MinMemoryCount`: 最小记忆数量 (默认 10) @@ -242,14 +268,17 @@ type ConsolidationEngine struct { - `PreserveOriginal`: 是否保留原始记忆 (默认 true) #### 2. 合并策略 + **文件**: `pkg/memory/consolidation_strategies.go` (453 lines) **RedundancyStrategy** - 冗余合并 + - 检测高度相似的重复记忆 - 使用 LLM 合并为单条精炼记忆 - 保留所有重要信息 **示例**: + ``` 输入: - "User prefers dark mode" @@ -261,11 +290,13 @@ type ConsolidationEngine struct { ``` **ConflictResolutionStrategy** - 冲突解决 + - 检测矛盾信息 - 基于置信度和新鲜度选择最佳版本 - 保留历史变化记录 **示例**: + ``` 输入: - "User likes coffee" (置信度 0.6) @@ -276,11 +307,13 @@ type ConsolidationEngine struct { ``` **SummarizationStrategy** - 总结 + - 将多条相关记忆总结为简洁表述 - 压缩信息密度 - 提高检索效率 **示例**: + ``` 输入 (5条记忆): - "User lives in New York" @@ -297,6 +330,7 @@ type ConsolidationEngine struct { #### 3. LLM 提示工程 **冗余合并提示**: + ``` You are a memory consolidation assistant. The following memory entries are redundant (saying similar things). @@ -311,6 +345,7 @@ Instructions: ``` **冲突解决提示**: + ``` You are a memory conflict resolution assistant. The following memory entries contain conflicting information. @@ -326,6 +361,7 @@ Instructions: #### 4. 溯源保留 合并后的记忆保留完整溯源链: + ```go consolidated.Provenance.Sources = [ "original-memory-1", @@ -358,6 +394,7 @@ consolidated.Provenance.CorroborationCount = 3 ### 1. 架构设计 **分层架构**: + ``` Application Layer ├─ Agent @@ -378,6 +415,7 @@ Storage Layer ### 2. 数据流 **记忆创建流程**: + ``` User Input ↓ @@ -393,6 +431,7 @@ Vector Store ``` **记忆检索流程**: + ``` Query ↓ @@ -408,6 +447,7 @@ Results ``` **记忆合并流程**: + ``` Trigger (Auto/Manual) ↓ @@ -425,18 +465,21 @@ Save & Cleanup ### 3. 性能优化 **置信度计算缓存**: + ```go // 避免重复计算 cache := make(map[string]float64) ``` **批处理向量嵌入**: + ```go // 一次调用处理多条记忆 vecs, err := embedder.EmbedText(ctx, texts) ``` **并发合并**: + ```go // 并发处理不相关的记忆组 for _, group := range groups { @@ -447,12 +490,14 @@ for _, group := range groups { ### 4. 安全特性 **PII 多层防护**: + 1. 检测层:正则表达式 + 验证器 2. 脱敏层:多种策略可选 3. 追踪层:记录所有 PII 检测 4. 审计层:完整的操作日志 **数据完整性**: + 1. 溯源链完整性验证 2. 谱系循环检测 3. 置信度边界检查 @@ -462,12 +507,12 @@ for _, group := range groups { ### 新增代码 -| 模块 | 文件数 | 代码行数 | 测试行数 | 文档行数 | -|------|-------|---------|---------|---------| -| Memory Provenance | 3 | 832 | 857 | 300+ | -| PII Redaction | 4 | 1,351 | 822 | 450+ | -| Memory Consolidation | 2 | 767 | 389 | 500+ | -| **总计** | **9** | **2,950** | **2,068** | **1,250+** | +| 模块 | 文件数 | 代码行数 | 测试行数 | 文档行数 | +| -------------------- | ------ | --------- | --------- | ---------- | +| Memory Provenance | 3 | 832 | 857 | 300+ | +| PII Redaction | 4 | 1,351 | 822 | 450+ | +| Memory Consolidation | 2 | 767 | 389 | 500+ | +| **总计** | **9** | **2,950** | **2,068** | **1,250+** | ### 测试覆盖率 @@ -606,13 +651,13 @@ func main() { ### 相比 Google ADK-Python -| 功能 | aster (Go) | ADK-Python | 优势 | -|-----|---------------|------------|------| -| Memory Provenance | ✅ 完整实现 | ✅ 完整实现 | 性能更好 | -| PII Redaction | ✅ 10+ 类型 | ✅ 基础实现 | 更多 PII 类型 | -| Consolidation | ✅ 3 种策略 | ✅ 基础实现 | 更多策略 | -| 测试覆盖 | ✅ 72 tests | ✅ 基础测试 | 更全面 | -| 文档 | ✅ 1250+ 行 | ✅ 基础文档 | 更详细 | +| 功能 | aster (Go) | ADK-Python | 优势 | +| ----------------- | ----------- | ----------- | ------------- | +| Memory Provenance | ✅ 完整实现 | ✅ 完整实现 | 性能更好 | +| PII Redaction | ✅ 10+ 类型 | ✅ 基础实现 | 更多 PII 类型 | +| Consolidation | ✅ 3 种策略 | ✅ 基础实现 | 更多策略 | +| 测试覆盖 | ✅ 72 tests | ✅ 基础测试 | 更全面 | +| 文档 | ✅ 1250+ 行 | ✅ 基础文档 | 更详细 | aster 现已达到世界级 Agent 框架的水平!🚀 diff --git a/docs/content/13.guides/2.advanced/human-in-the-loop.md b/docs/content/13.guides/2.advanced/human-in-the-loop.md index ee88ad0..9ba2943 100644 --- a/docs/content/13.guides/2.advanced/human-in-the-loop.md +++ b/docs/content/13.guides/2.advanced/human-in-the-loop.md @@ -22,13 +22,13 @@ HITL 是一种设计模式,在自动化流程中引入人工决策点,确保 ### 适用场景 -| 场景 | 示例 | 风险等级 | -|------|------|---------| -| 文件操作 | 删除文件、修改配置 | 🔴 高 | -| 系统命令 | 执行 Shell 命令 | 🔴 高 | -| 外部 API | 发送邮件、调用付费 API | 🟡 中 | -| 数据修改 | 更新数据库、修改记录 | 🟡 中 | -| 资源消耗 | 大规模计算、批量处理 | 🟡 中 | +| 场景 | 示例 | 风险等级 | +| -------- | ---------------------- | -------- | +| 文件操作 | 删除文件、修改配置 | 🔴 高 | +| 系统命令 | 执行 Shell 命令 | 🔴 高 | +| 外部 API | 发送邮件、调用付费 API | 🟡 中 | +| 数据修改 | 更新数据库、修改记录 | 🟡 中 | +| 资源消耗 | 大规模计算、批量处理 | 🟡 中 | ## 🚀 快速开始 @@ -57,7 +57,7 @@ func main() { "fs_delete": true, // 文件删除需要审核 "HttpRequest": true, // HTTP 请求需要审核 }, - + // 审核处理器 ApprovalHandler: func(ctx context.Context, req *middleware.ReviewRequest) ([]middleware.Decision, error) { // 显示待审核的操作 @@ -66,25 +66,25 @@ func main() { fmt.Printf(" 工具: %s\n", action.ToolName) fmt.Printf(" 参数: %+v\n", action.Input) fmt.Printf(" 说明: %s\n\n", action.Message) - + // 获取人工决策 fmt.Print("请选择操作 (approve/reject): ") var choice string fmt.Scanln(&choice) - + if choice == "approve" || choice == "y" { return []middleware.Decision{{ Type: middleware.DecisionApprove, Reason: "用户批准", }}, nil } - + return []middleware.Decision{{ Type: middleware.DecisionReject, Reason: "用户拒绝", }}, nil } - + return nil, fmt.Errorf("no decision") }, }) @@ -158,11 +158,11 @@ InterruptOn: map[string]interface{}{ HITL 支持三种决策类型: -| 决策类型 | 说明 | 使用场景 | -|---------|------|---------| -| `DecisionApprove` | 批准:按原参数执行 | 操作合理,可以执行 | -| `DecisionReject` | 拒绝:取消执行 | 操作不安全或不合理 | -| `DecisionEdit` | 编辑:修改参数后执行 | 参数需要调整 | +| 决策类型 | 说明 | 使用场景 | +| ----------------- | -------------------- | ------------------ | +| `DecisionApprove` | 批准:按原参数执行 | 操作合理,可以执行 | +| `DecisionReject` | 拒绝:取消执行 | 操作不安全或不合理 | +| `DecisionEdit` | 编辑:修改参数后执行 | 参数需要调整 | ```go const ( @@ -181,10 +181,10 @@ ApprovalHandler: func(ctx context.Context, req *middleware.ReviewRequest) ([]mid for _, action := range req.ActionRequests { fmt.Printf("工具: %s\n参数: %+v\n", action.ToolName, action.Input) fmt.Print("批准? (y/n): ") - + var answer string fmt.Scanln(&answer) - + if answer == "y" { return []middleware.Decision{{Type: middleware.DecisionApprove}}, nil } @@ -199,21 +199,21 @@ ApprovalHandler: func(ctx context.Context, req *middleware.ReviewRequest) ([]mid ```go ApprovalHandler: func(ctx context.Context, req *middleware.ReviewRequest) ([]middleware.Decision, error) { action := req.ActionRequests[0] - + fmt.Printf("工具: %s\n", action.ToolName) fmt.Printf("当前参数: %+v\n", action.Input) fmt.Print("选择操作 (approve/reject/edit): ") - + var choice string fmt.Scanln(&choice) - + switch choice { case "approve": return []middleware.Decision{{Type: middleware.DecisionApprove}}, nil - + case "reject": return []middleware.Decision{{Type: middleware.DecisionReject}}, nil - + case "edit": editedInput := make(map[string]interface{}) for key, value := range action.Input { @@ -226,13 +226,13 @@ ApprovalHandler: func(ctx context.Context, req *middleware.ReviewRequest) ([]mid editedInput[key] = value } } - + return []middleware.Decision{{ Type: middleware.DecisionEdit, EditedInput: editedInput, }}, nil } - + return nil, fmt.Errorf("invalid choice") } ``` @@ -252,7 +252,7 @@ func NewFileOperationHITL() (*middleware.HumanInTheLoopMiddleware, error) { }, ApprovalHandler: func(ctx context.Context, req *middleware.ReviewRequest) ([]middleware.Decision, error) { action := req.ActionRequests[0] - + // 检查危险路径 if path, ok := action.Input["path"].(string); ok { dangerousPaths := []string{"/", "/etc", "/usr", "/bin", "/home"} @@ -267,14 +267,14 @@ func NewFileOperationHITL() (*middleware.HumanInTheLoopMiddleware, error) { } } } - + // 正常审核流程 fmt.Printf("操作: %s\n参数: %+v\n", action.ToolName, action.Input) fmt.Print("批准? (y/n): ") - + var answer string fmt.Scanln(&answer) - + if answer == "y" { return []middleware.Decision{{Type: middleware.DecisionApprove}}, nil } @@ -312,7 +312,7 @@ func assessRisk(action middleware.ActionRequest) RiskLevel { func smartApprovalHandler(ctx context.Context, req *middleware.ReviewRequest) ([]middleware.Decision, error) { action := req.ActionRequests[0] risk := assessRisk(action) - + switch risk { case RiskLow: fmt.Printf("✅ 自动批准低风险操作: %s\n", action.ToolName) @@ -320,7 +320,7 @@ func smartApprovalHandler(ctx context.Context, req *middleware.ReviewRequest) ([ Type: middleware.DecisionApprove, Reason: "低风险操作自动批准", }}, nil - + case RiskMedium: fmt.Printf("⚠️ 中风险操作: %s\n", action.ToolName) fmt.Print("是否批准? (y/n): ") @@ -330,7 +330,7 @@ func smartApprovalHandler(ctx context.Context, req *middleware.ReviewRequest) ([ return []middleware.Decision{{Type: middleware.DecisionApprove}}, nil } return []middleware.Decision{{Type: middleware.DecisionReject}}, nil - + case RiskHigh: fmt.Printf("🚨 高风险操作: %s\n", action.ToolName) fmt.Printf("参数: %+v\n", action.Input) @@ -342,7 +342,7 @@ func smartApprovalHandler(ctx context.Context, req *middleware.ReviewRequest) ([ } return []middleware.Decision{{Type: middleware.DecisionReject}}, nil } - + return nil, fmt.Errorf("unknown risk level") } ``` @@ -382,12 +382,12 @@ InterruptOn: map[string]interface{}{ ApprovalHandler: func(ctx context.Context, req *middleware.ReviewRequest) ([]middleware.Decision, error) { ctx, cancel := context.WithTimeout(ctx, 5*time.Minute) defer cancel() - + decisionCh := make(chan middleware.Decision, 1) go func() { decisionCh <- getUserDecision(req) }() - + select { case decision := <-decisionCh: return []middleware.Decision{decision}, nil @@ -428,15 +428,15 @@ func logApproval(action middleware.ActionRequest, decision middleware.Decision) ```go ApprovalHandler: func(ctx context.Context, req *middleware.ReviewRequest) ([]middleware.Decision, error) { fmt.Printf("有 %d 个操作需要审核:\n", len(req.ActionRequests)) - + for i, action := range req.ActionRequests { fmt.Printf("%d. %s: %+v\n", i+1, action.ToolName, action.Input) } - + fmt.Print("批准所有? (y/n/详细审核): ") var choice string fmt.Scanln(&choice) - + if choice == "y" { // 批准所有 decisions := make([]middleware.Decision, len(req.ActionRequests)) @@ -445,7 +445,7 @@ ApprovalHandler: func(ctx context.Context, req *middleware.ReviewRequest) ([]mid } return decisions, nil } - + // 逐个审核... return nil, nil } @@ -483,7 +483,7 @@ type ApprovalPolicy struct { func (p *ApprovalPolicy) CheckPermission(user string, toolName string) bool { roles := getUserRoles(user) allowedRoles := p.AllowedRoles[toolName] - + for _, role := range roles { for _, allowed := range allowedRoles { if role == allowed { @@ -503,7 +503,7 @@ func (p *ApprovalPolicy) CheckPermission(user string, toolName string) bool { func appendOnlyAuditLog(entry AuditLog) { f, _ := os.OpenFile("audit.log", os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644) defer f.Close() - + data, _ := json.Marshal(entry) f.WriteString(string(data) + "\n") } @@ -574,6 +574,7 @@ if isProduction { ### Q: HITL 会影响性能吗? A: 是的,HITL 会引入延迟,因为需要等待人工决策。建议: + - 只对真正敏感的操作启用审核 - 实现超时机制避免无限等待 - 对低风险操作使用自动批准 @@ -581,6 +582,7 @@ A: 是的,HITL 会引入延迟,因为需要等待人工决策。建议: ### Q: 如何在 Agent 被拒绝后恢复? A: Agent 会收到拒绝信息,可以: + - 尝试其他方法完成任务 - 向用户解释原因并请求指导 - 调整参数后重试 diff --git a/docs/content/13.guides/2.advanced/index.md b/docs/content/13.guides/2.advanced/index.md index c2629ea..612a69c 100644 --- a/docs/content/13.guides/2.advanced/index.md +++ b/docs/content/13.guides/2.advanced/index.md @@ -22,6 +22,7 @@ navigation: **适合人群**: 需要构建可信赖、合规的企业级 Agent 系统的开发者 **学习收获**: + - 掌握记忆溯源系统设计 - 了解 LLM 驱动的内存优化 - 实现企业级数据安全保护 diff --git a/docs/content/13.guides/index.md b/docs/content/13.guides/index.md index 5f66010..5621af0 100644 --- a/docs/content/13.guides/index.md +++ b/docs/content/13.guides/index.md @@ -11,18 +11,23 @@ navigation: false ## 📚 分类 ### [快速开始](/guides/quickstart) + - 你的第一个 Agent - 添加工具能力 ### [完整教程](/guides/tutorials) + 即将推出端到端项目教程: + - 构建智能聊天机器人 - 创建代码助手 - 数据处理流水线 - 研究工具开发 ### [迁移指南](/guides/migrations) + 即将推出: + - 从 LangChain 迁移 - 从其他框架迁移 diff --git a/docs/content/14.api-reference/1.agent/overview.md b/docs/content/14.api-reference/1.agent/overview.md index c2847b7..8b94479 100644 --- a/docs/content/14.api-reference/1.agent/overview.md +++ b/docs/content/14.api-reference/1.agent/overview.md @@ -29,11 +29,13 @@ func Create(ctx context.Context, config *types.AgentConfig, deps *Dependencies) ``` **参数**: + - `ctx`: 上下文,用于控制 Agent 生命周期 - `config`: Agent 配置,包括模型、工具、中间件等 - `deps`: 依赖注入,提供工具注册表、Provider 工厂等 **返回**: + - `*Agent`: Agent 实例 - `error`: 创建失败时返回错误 @@ -86,10 +88,12 @@ func (a *Agent) Chat(ctx context.Context, text string) (*types.CompleteResult, e ``` **参数**: + - `ctx`: 上下文 - `text`: 用户消息文本 **返回**: + - `*types.CompleteResult`: 对话结果,包含响应文本、停止原因、Token 使用量 - `error`: 错误信息 @@ -126,10 +130,12 @@ func (a *Agent) Send(ctx context.Context, text string) error ``` **参数**: + - `ctx`: 上下文 - `text`: 用户消息文本 **返回**: + - `error`: 发送失败时返回错误 **示例**: @@ -161,6 +167,7 @@ if err != nil { ``` **适用场景**: + - 需要实时显示流式输出 - 需要人工审批工具调用 - 需要监控 Agent 执行状态 @@ -176,11 +183,13 @@ func (a *Agent) Stream(ctx context.Context, message string, opts ...Option) *str ``` **参数**: + - `ctx`: 上下文 - `message`: 用户消息文本 - `opts`: 可选配置 **返回**: + - `*stream.Reader[*session.Event]`: 事件 Reader **示例**: @@ -219,6 +228,7 @@ func (a *Agent) Subscribe(channels []types.AgentChannel, opts *types.SubscribeOp ``` **参数**: + - `channels`: 要订阅的通道列表 - `types.ChannelProgress`: 进度事件(文本流、工具执行) - `types.ChannelControl`: 控制事件(工具审批请求) @@ -227,6 +237,7 @@ func (a *Agent) Subscribe(channels []types.AgentChannel, opts *types.SubscribeOp - `Filter`: 事件过滤器 **返回**: + - `<-chan types.AgentEventEnvelope`: 事件通道 **示例**: @@ -255,14 +266,14 @@ for envelope := range eventCh { **事件类型**: -| 事件类型 | 通道 | 说明 | -|---------|------|------| -| `EventTypeTextDelta` | Progress | 流式文本增量 | -| `EventTypeTextDone` | Progress | 文本流结束 | -| `EventTypeToolCallRequest` | Control | 工具调用请求 | -| `EventTypeToolCallResult` | Progress | 工具执行结果 | -| `EventTypeGovernance` | Monitor | 治理事件(权限检查、速率限制)| -| `EventTypeError` | Monitor | 错误事件 | +| 事件类型 | 通道 | 说明 | +| -------------------------- | -------- | ------------------------------ | +| `EventTypeTextDelta` | Progress | 流式文本增量 | +| `EventTypeTextDone` | Progress | 文本流结束 | +| `EventTypeToolCallRequest` | Control | 工具调用请求 | +| `EventTypeToolCallResult` | Progress | 工具执行结果 | +| `EventTypeGovernance` | Monitor | 治理事件(权限检查、速率限制) | +| `EventTypeError` | Monitor | 错误事件 | --- @@ -275,6 +286,7 @@ func (a *Agent) Unsubscribe(ch <-chan types.AgentEventEnvelope) ``` **参数**: + - `ch`: 要取消的事件通道 **示例**: @@ -301,6 +313,7 @@ func (a *Agent) ID() string ``` **返回**: + - `string`: Agent ID **示例**: @@ -320,6 +333,7 @@ func (a *Agent) Status() *types.AgentStatus ``` **返回**: + - `*types.AgentStatus`: Agent 状态信息 **示例**: @@ -357,6 +371,7 @@ func (a *Agent) Close() error ``` **返回**: + - `error`: 关闭失败时返回错误 **示例**: @@ -372,6 +387,7 @@ if err := ag.Close(); err != nil { ``` **关闭行为**: + - 停止所有正在执行的任务 - 关闭所有事件通道 - 释放 Provider 连接 diff --git a/docs/content/14.api-reference/10.subagent/overview.md b/docs/content/14.api-reference/10.subagent/overview.md index f3b08b0..c4dfacc 100644 --- a/docs/content/14.api-reference/10.subagent/overview.md +++ b/docs/content/14.api-reference/10.subagent/overview.md @@ -16,6 +16,7 @@ import "github.com/astercloud/aster/pkg/middleware" 完整的 SubAgent API 参考文档,包含所有接口、类型定义、使用示例等内容。 相关资源: + - [SubAgent 核心概念](/core-concepts/subagent-system) - [多 Agent 协作](/multi-agent/overview) - [SubAgent 最佳实践](/best-practices/subagent) diff --git a/docs/content/14.api-reference/2.provider/overview.md b/docs/content/14.api-reference/2.provider/overview.md index faafc30..25a9ef0 100644 --- a/docs/content/14.api-reference/2.provider/overview.md +++ b/docs/content/14.api-reference/2.provider/overview.md @@ -74,19 +74,19 @@ defer p.Close() ### 支持的 Provider 名称 -| Provider | 配置名称 | 别名 | -|----------|---------|------| -| OpenAI | `openai` | - | -| Anthropic | `anthropic` | - | -| Gemini | `gemini` | `google` | -| Groq | `groq` | - | -| OpenRouter | `openrouter` | - | -| Mistral | `mistral` | - | -| Ollama | `ollama` | - | -| DeepSeek | `deepseek` | - | -| 智谱 GLM | `glm` | `zhipu` | -| 豆包 | `doubao` | `bytedance` | -| 月之暗面 | `moonshot` | `kimi` | +| Provider | 配置名称 | 别名 | +| ---------- | ------------ | ----------- | +| OpenAI | `openai` | - | +| Anthropic | `anthropic` | - | +| Gemini | `gemini` | `google` | +| Groq | `groq` | - | +| OpenRouter | `openrouter` | - | +| Mistral | `mistral` | - | +| Ollama | `ollama` | - | +| DeepSeek | `deepseek` | - | +| 智谱 GLM | `glm` | `zhipu` | +| 豆包 | `doubao` | `bytedance` | +| 月之暗面 | `moonshot` | `kimi` | 完整 Provider 文档:[Provider 总览](../providers/overview.md) @@ -103,11 +103,13 @@ func Stream(ctx context.Context, messages []types.Message, opts *StreamOptions) ``` **参数**: + - `ctx`: 上下文 - `messages`: 消息历史 - `opts`: 流式选项(工具、温度等) **返回**: + - `<-chan StreamChunk`: 流式响应通道 - `error`: 创建流失败时返回错误 @@ -143,12 +145,12 @@ for chunk := range stream { **StreamChunk 类型**: -| Type | 说明 | 字段 | -|------|------|------| -| `text` | 文本增量 | `TextDelta` | -| `tool_call` | 工具调用 | `ToolCall`, `ToolCallID` | -| `usage` | Token 使用 | `Usage` | -| `error` | 错误 | `Error` | +| Type | 说明 | 字段 | +| ----------- | ---------- | ------------------------ | +| `text` | 文本增量 | `TextDelta` | +| `tool_call` | 工具调用 | `ToolCall`, `ToolCallID` | +| `usage` | Token 使用 | `Usage` | +| `error` | 错误 | `Error` | --- @@ -161,11 +163,13 @@ func Complete(ctx context.Context, messages []types.Message, opts *StreamOptions ``` **参数**: + - `ctx`: 上下文 - `messages`: 消息历史 - `opts`: 生成选项 **返回**: + - `*CompleteResponse`: 完整响应 - `error`: 错误信息 @@ -462,7 +466,7 @@ type ModelConfig struct { APIKey string // API Key BaseURL string // 自定义端点(可选) - // 执行模式 + // 执行模式 ExecutionMode ExecutionMode // 执行模式:streaming/non-streaming/auto // 生成参数 @@ -491,11 +495,11 @@ const ( **ExecutionMode 说明**: -| 模式 | 适用场景 | 性能特点 | -|------|---------|---------| -| `Streaming` | 交互式对话、实时反馈 | 用户体验好,逐字输出 | -| `NonStreaming` | 批量翻译、文档处理 | **速度快3-5倍**,一次性返回 | -| `Auto` | 通用场景 | 自动根据任务类型选择 | +| 模式 | 适用场景 | 性能特点 | +| -------------- | -------------------- | --------------------------- | +| `Streaming` | 交互式对话、实时反馈 | 用户体验好,逐字输出 | +| `NonStreaming` | 批量翻译、文档处理 | **速度快3-5倍**,一次性返回 | +| `Auto` | 通用场景 | 自动根据任务类型选择 | **使用示例**: @@ -581,6 +585,7 @@ type ToolSchema struct { ### 国际主流 **OpenAI** + ```go config := &types.ModelConfig{ Provider: "openai", @@ -594,6 +599,7 @@ config := &types.ModelConfig{ --- **Anthropic** + ```go config := &types.ModelConfig{ Provider: "anthropic", @@ -607,6 +613,7 @@ config := &types.ModelConfig{ --- **Gemini** + ```go config := &types.ModelConfig{ Provider: "gemini", @@ -620,6 +627,7 @@ config := &types.ModelConfig{ --- **Groq** + ```go config := &types.ModelConfig{ Provider: "groq", @@ -635,6 +643,7 @@ config := &types.ModelConfig{ ### 中国市场 **DeepSeek** + ```go config := &types.ModelConfig{ Provider: "deepseek", @@ -648,6 +657,7 @@ config := &types.ModelConfig{ --- **智谱 GLM** + ```go config := &types.ModelConfig{ Provider: "glm", @@ -663,6 +673,7 @@ config := &types.ModelConfig{ ### 本地部署 **Ollama** + ```go config := &types.ModelConfig{ Provider: "ollama", diff --git a/docs/content/14.api-reference/3.tools/overview.md b/docs/content/14.api-reference/3.tools/overview.md index 6f2c57c..0c04c7d 100644 --- a/docs/content/14.api-reference/3.tools/overview.md +++ b/docs/content/14.api-reference/3.tools/overview.md @@ -42,6 +42,7 @@ type ToolHandler func(ctx context.Context, tc *ToolContext) (interface{}, error) 文件系统操作工具集。 **工具列表**: + - `filesystem_read` - 读取文件 - `filesystem_write` - 写入文件 - `filesystem_list` - 列出目录 @@ -77,6 +78,7 @@ ag.Chat(ctx, "创建一个 hello.txt 文件,内容为 Hello World") **工具名称**:`bash` **功能**: + - 执行 Shell 命令 - 支持沙箱隔离 - 超时控制 @@ -104,6 +106,7 @@ ag.Chat(ctx, "列出当前目录的文件") HTTP 请求工具。 **工具列表**: + - `http_get` - GET 请求 - `http_post` - POST 请求 - `http_put` - PUT 请求 @@ -125,6 +128,7 @@ ag.Chat(ctx, "获取 https://api.github.com/users/octocat 的数据") **工具名称**:`websearch` **功能**: + - 搜索网页内容 - 返回搜索结果摘要 @@ -369,10 +373,12 @@ type ToolHandler func(ctx context.Context, tc *ToolContext) (interface{}, error) ``` **参数**: + - `ctx`: 上下文 - `tc`: 工具上下文 **返回**: + - `interface{}`: 工具执行结果(可序列化为 JSON) - `error`: 错误信息 diff --git a/docs/content/14.api-reference/4.middleware/overview.md b/docs/content/14.api-reference/4.middleware/overview.md index 32112c2..379a3cd 100644 --- a/docs/content/14.api-reference/4.middleware/overview.md +++ b/docs/content/14.api-reference/4.middleware/overview.md @@ -102,6 +102,7 @@ deps := &agent.Dependencies{ **优先级**:`100` **功能**: + - 自动记录文件操作历史 - 提供文件系统快照 - 管理文件上下文 @@ -134,6 +135,7 @@ MiddlewareConfigs: map[string]*types.MiddlewareConfig{ **优先级**:`40` **功能**: + - 当对话历史超过阈值时自动总结 - 保留最近消息,总结旧消息 - 支持自定义总结策略 @@ -174,6 +176,7 @@ ag.Chat(ctx, "第 25 条消息") **优先级**:`200` **功能**: + - 提供 `subagent_delegate` 工具 - 将复杂任务委派给子 Agent - 支持子 Agent 隔离执行 @@ -201,6 +204,7 @@ Agent 长期记忆中间件。 **优先级**:`50` **功能**: + - 自动保存对话历史到记忆系统 - 在新对话中检索相关历史 - 支持向量数据库(Qdrant) diff --git a/docs/content/14.api-reference/9.skills/overview.md b/docs/content/14.api-reference/9.skills/overview.md index 03f19b1..c404ee0 100644 --- a/docs/content/14.api-reference/9.skills/overview.md +++ b/docs/content/14.api-reference/9.skills/overview.md @@ -310,5 +310,4 @@ func main() { - Skills 不会把完整的 SKILL.md 内容直接注入提示词; - 模型会在需要时,通过 `Read` / `Bash` 等工具主动打开 `skills//SKILL.md`,再按照说明中的步骤去执行脚本或其它工具。 -这就实现了依赖文件系统的“渐进式加载”能力:系统提示轻量、技能内容在真正需要时再被加载。 - +这就实现了依赖文件系统的“渐进式加载”能力:系统提示轻量、技能内容在真正需要时再被加载。 diff --git a/docs/content/14.api-reference/cli.md b/docs/content/14.api-reference/cli.md index ebf83a3..680c1b5 100644 --- a/docs/content/14.api-reference/cli.md +++ b/docs/content/14.api-reference/cli.md @@ -138,8 +138,8 @@ aster mcp-serve \ 会启动一个 MCP HTTP Server, 监听 `http://localhost:8090/mcp`, 默认提供: -- `echo` – 简单回显工具 -- `docs_get` – 读取 `--docs` 目录下的文档文件 +- `echo` – 简单回显工具 +- `docs_get` – 读取 `--docs` 目录下的文档文件 - `docs_search` – 在 `--docs` 目录中搜索关键字 ## 3. 调用示例 diff --git a/docs/content/14.api-reference/index.md b/docs/content/14.api-reference/index.md index be24d29..e78c1de 100644 --- a/docs/content/14.api-reference/index.md +++ b/docs/content/14.api-reference/index.md @@ -11,6 +11,7 @@ navigation: false ## 📚 分类 ### [Agent API](/api-reference/agent) + - agent.Create - agent.Chat - agent.RegisterTool @@ -19,6 +20,7 @@ navigation: false - agent.Unsubscribe ### [Provider API](/api-reference/provider) + - provider.Anthropic - provider.OpenAI - provider.DeepSeek @@ -26,6 +28,7 @@ navigation: false - provider.Custom ### [Tools API](/api-reference/tools) + - tools.BashTool - tools.FileSystemTool - tools.HTTPTool @@ -33,6 +36,7 @@ navigation: false - tools.CreateCustomTool ### [Middleware API](/api-reference/middleware) + - middleware.Filesystem - middleware.SubAgent - middleware.Summarization @@ -40,21 +44,25 @@ navigation: false - middleware.Custom ### [Memory API](/api-reference/memory) + - memory.SessionStore - memory.VectorStore - memory.Backends ### [Workflow API](/api-reference/workflow) + - workflow.Create - workflow.Execute - workflow.Monitor ### [Events API](/api-reference/events) + - events.ProgressEvent - events.ControlEvent - events.MonitorEvent ### [Types](/api-reference/types) + - types.AgentConfig - types.ModelConfig - types.ToolConfig diff --git a/docs/content/15.best-practices/authentication.md b/docs/content/15.best-practices/authentication.md index 483f2b7..134f019 100644 --- a/docs/content/15.best-practices/authentication.md +++ b/docs/content/15.best-practices/authentication.md @@ -131,6 +131,7 @@ config := &server.Config{ ### 预定义角色 #### Admin - 管理员 + ```go { Name: "admin", @@ -142,6 +143,7 @@ config := &server.Config{ ``` #### User - 普通用户 + ```go { Name: "user", @@ -155,6 +157,7 @@ config := &server.Config{ ``` #### Viewer - 查看者 + ```go { Name: "viewer", @@ -166,6 +169,7 @@ config := &server.Config{ ``` #### Developer - 开发者 + ```go { Name: "developer", @@ -204,7 +208,7 @@ rbac.AddRole(customRole) ```go func (h *AgentHandler) Delete(c *gin.Context) { user := getUserFromContext(c) // 从 context 获取用户 - + // 检查权限 if !h.rbac.HasPermission(c.Request.Context(), user, "agents", "delete") { c.JSON(http.StatusForbidden, gin.H{ @@ -212,7 +216,7 @@ func (h *AgentHandler) Delete(c *gin.Context) { }) return } - + // 执行删除... } ``` @@ -223,14 +227,14 @@ func (h *AgentHandler) Delete(c *gin.Context) { func RequirePermission(rbac *auth.RBAC, resource, action string) gin.HandlerFunc { return func(c *gin.Context) { user := getUserFromContext(c) - + if !rbac.HasPermission(c.Request.Context(), user, resource, action) { c.AbortWithStatusJSON(http.StatusForbidden, gin.H{ "error": "Permission denied", }) return } - + c.Next() } } @@ -257,6 +261,7 @@ permissions := rbac.GetUserPermissions(user) ### 1. API Key 管理 **✅ 推荐**: + - 使用环境变量存储 API Keys - 定期轮换 keys - 设置过期时间 @@ -278,6 +283,7 @@ apiKeyInfo := &auth.APIKeyInfo{ ``` **❌ 避免**: + - 在代码中硬编码 keys - 使用简单的 keys - 永不过期的 keys @@ -286,6 +292,7 @@ apiKeyInfo := &auth.APIKeyInfo{ ### 2. JWT 配置 **✅ 推荐**: + - 使用强密钥 (>= 32 字符) - 设置合理的过期时间 - 包含必要的 claims @@ -300,6 +307,7 @@ jwtConfig := auth.JWTConfig{ ``` **❌ 避免**: + - 弱密钥 - 过长的过期时间 (> 7 天) - 在 token 中存储敏感信息 @@ -308,6 +316,7 @@ jwtConfig := auth.JWTConfig{ ### 3. RBAC 设计 **✅ 推荐**: + - 遵循最小权限原则 - 使用角色而非直接权限 - 定期审计权限 @@ -324,6 +333,7 @@ roles := []string{ ``` **❌ 避免**: + - 过度授权 - 复杂的权限层级 - 未文档化的权限 @@ -332,6 +342,7 @@ roles := []string{ ### 4. 安全传输 **✅ 推荐**: + - 使用 HTTPS - 启用 HSTS - 验证 SSL 证书 @@ -361,12 +372,12 @@ import ( func main() { // 1. 创建认证管理器 authManager := auth.NewManager(auth.AuthMethodAPIKey) - + // 2. 注册 API Key 认证 apiKeyStore := auth.NewMemoryAPIKeyStore() apiKeyAuth := auth.NewAPIKeyAuthenticator(apiKeyStore) authManager.Register(apiKeyAuth) - + // 3. 注册 JWT 认证 jwtAuth := auth.NewJWTAuthenticator(auth.JWTConfig{ SecretKey: os.Getenv("JWT_SECRET"), @@ -374,10 +385,10 @@ func main() { ExpiryDuration: 24 * time.Hour, }) authManager.Register(jwtAuth) - + // 4. 创建 RBAC rbac := auth.NewRBAC() - + // 5. 配置服务器 config := &server.Config{ Auth: server.AuthConfig{ @@ -385,7 +396,7 @@ func main() { JWT: server.JWTConfig{Enabled: true}, }, } - + srv, _ := server.New(config, deps) srv.Start() } @@ -399,19 +410,19 @@ func (h *AuthHandler) Login(c *gin.Context) { Username string `json:"username"` Password string `json:"password"` } - + c.ShouldBindJSON(&req) - + // 验证用户名密码 user, err := validateCredentials(req.Username, req.Password) if err != nil { c.JSON(401, gin.H{"error": "Invalid credentials"}) return } - + // 生成 JWT token, expiresAt, _ := h.jwtAuth.GenerateToken(user) - + c.JSON(200, gin.H{ "token": token, "expires_at": expiresAt, @@ -431,14 +442,14 @@ func AuthMiddleware(authManager *auth.Manager, rbac *auth.RBAC) gin.HandlerFunc c.AbortWithStatusJSON(401, gin.H{"error": "Missing token"}) return } - + // 验证 token user, err := authManager.Validate(c.Request.Context(), auth.AuthMethodJWT, token) if err != nil { c.AbortWithStatusJSON(401, gin.H{"error": "Invalid token"}) return } - + // 存储用户信息 c.Set("user", user) c.Next() diff --git a/docs/content/15.best-practices/deployment.md b/docs/content/15.best-practices/deployment.md index f4e05e9..331de15 100644 --- a/docs/content/15.best-practices/deployment.md +++ b/docs/content/15.best-practices/deployment.md @@ -123,7 +123,7 @@ CMD ["./agent-service"] ```yaml # docker-compose.yml -version: '3.8' +version: "3.8" services: agent-service: @@ -172,8 +172,8 @@ services: - ./prometheus.yml:/etc/prometheus/prometheus.yml - prometheus-data:/prometheus command: - - '--config.file=/etc/prometheus/prometheus.yml' - - '--storage.tsdb.path=/prometheus' + - "--config.file=/etc/prometheus/prometheus.yml" + - "--storage.tsdb.path=/prometheus" restart: unless-stopped grafana: @@ -574,7 +574,7 @@ name: Build and Deploy on: push: branches: [main] - tags: ['v*'] + tags: ["v*"] pull_request: branches: [main] @@ -591,7 +591,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v4 with: - go-version: '1.21' + go-version: "1.21" - name: Run tests run: | @@ -722,7 +722,7 @@ metadata: name: agent-service-canary namespace: production spec: - replicas: 1 # 金丝雀副本数 + replicas: 1 # 金丝雀副本数 selector: matchLabels: app: agent-service @@ -751,7 +751,7 @@ metadata: namespace: production annotations: nginx.ingress.kubernetes.io/canary: "true" - nginx.ingress.kubernetes.io/canary-weight: "10" # 10% 流量到金丝雀 + nginx.ingress.kubernetes.io/canary-weight: "10" # 10% 流量到金丝雀 spec: ingressClassName: nginx rules: diff --git a/docs/content/15.best-practices/index.md b/docs/content/15.best-practices/index.md index a2a964e..f068e84 100644 --- a/docs/content/15.best-practices/index.md +++ b/docs/content/15.best-practices/index.md @@ -166,12 +166,12 @@ stack.Use(securityMW) ## 📊 开发阶段对照表 -| 阶段 | 重点 | 关键实践 | -|------|------|----------| -| **原型开发** | 快速验证 | 简单配置、基础工具、单Agent | -| **功能开发** | 完善能力 | 中间件、自定义工具、错误处理 | -| **性能优化** | 提升效率 | Token 优化、缓存、并发控制 | -| **生产准备** | 稳定可靠 | 监控、日志、安全加固、灰度发布 | +| 阶段 | 重点 | 关键实践 | +| -------------- | -------- | ------------------------------ | +| **原型开发** | 快速验证 | 简单配置、基础工具、单Agent | +| **功能开发** | 完善能力 | 中间件、自定义工具、错误处理 | +| **性能优化** | 提升效率 | Token 优化、缓存、并发控制 | +| **生产准备** | 稳定可靠 | 监控、日志、安全加固、灰度发布 | | **规模化运营** | 成本控制 | 多租户隔离、资源池化、成本监控 | ## 🎨 架构模式 diff --git a/docs/content/15.best-practices/monitoring.md b/docs/content/15.best-practices/monitoring.md index 2a3243a..2aaad95 100644 --- a/docs/content/15.best-practices/monitoring.md +++ b/docs/content/15.best-practices/monitoring.md @@ -642,51 +642,51 @@ groups: # alertmanager.yml global: resolve_timeout: 5m - slack_api_url: 'https://hooks.slack.com/services/YOUR/WEBHOOK/URL' + slack_api_url: "https://hooks.slack.com/services/YOUR/WEBHOOK/URL" route: - group_by: ['alertname', 'severity'] + group_by: ["alertname", "severity"] group_wait: 10s group_interval: 10s repeat_interval: 12h - receiver: 'default' + receiver: "default" routes: # 严重告警立即发送 - match: severity: critical - receiver: 'pagerduty' + receiver: "pagerduty" continue: true # 警告发送到 Slack - match: severity: warning - receiver: 'slack' + receiver: "slack" # 信息只记录 - match: severity: info - receiver: 'log' + receiver: "log" receivers: - - name: 'default' + - name: "default" slack_configs: - - channel: '#alerts' - title: 'Agent Alert' + - channel: "#alerts" + title: "Agent Alert" text: '{{ range .Alerts }}{{ .Annotations.summary }}\n{{ .Annotations.description }}\n{{ end }}' - - name: 'pagerduty' + - name: "pagerduty" pagerduty_configs: - - service_key: 'YOUR_PAGERDUTY_KEY' + - service_key: "YOUR_PAGERDUTY_KEY" - - name: 'slack' + - name: "slack" slack_configs: - - channel: '#agent-warnings' - title: 'Agent Warning' + - channel: "#agent-warnings" + title: "Agent Warning" - - name: 'log' + - name: "log" webhook_configs: - - url: 'http://logger:8080/alerts' + - url: "http://logger:8080/alerts" ``` ### 自定义告警处理 diff --git a/docs/content/15.best-practices/performance.md b/docs/content/15.best-practices/performance.md index bf6841f..9d49915 100644 --- a/docs/content/15.best-practices/performance.md +++ b/docs/content/15.best-practices/performance.md @@ -155,6 +155,7 @@ systemPrompt := `你是数据分析专家,专注于: ``` **优化原则**: + - **删除冗余** - 去掉无用的客套话 - **明确职责** - 清晰定义 Agent 能做什么 - **结构化** - 使用列表代替长段落 @@ -313,10 +314,10 @@ func handleRequest(w http.ResponseWriter, r *http.Request) { **效果对比**: -| 场景 | Agent 创建 | 平均响应时间 | Token 成本 | -|------|-----------|-------------|-----------| -| **每次创建** | 100 次/分钟 | 2000ms | 高 | -| **Pool 复用** | 10 次/分钟 | 500ms | 低(缓存生效)| +| 场景 | Agent 创建 | 平均响应时间 | Token 成本 | +| ------------- | ----------- | ------------ | -------------- | +| **每次创建** | 100 次/分钟 | 2000ms | 高 | +| **Pool 复用** | 10 次/分钟 | 500ms | 低(缓存生效) | ## ⚡ 并发控制 @@ -828,18 +829,18 @@ func main() { ## 📈 成本优化对照表 -| 优化措施 | Token 节省 | 响应时间 | 实现难度 | -|---------|-----------|---------|---------| -| **Summarization 中间件** | 60-80% | 持平 | 低 | -| **Prompt Caching** | 50-90% | -10% | 低 | -| **Agent Pool 复用** | 20-40% | -50% | 中 | -| **工具结果缓存** | 10-30% | -30% | 中 | -| **Prompt 优化** | 10-20% | +5% | 低 | -| **输出长度限制** | 5-15% | +10% | 低 | -| **并发控制** | 0% | 变化 | 中 | -| **流式输出** | 0% | -40%* | 低 | - -*感知响应时间 +| 优化措施 | Token 节省 | 响应时间 | 实现难度 | +| ------------------------ | ---------- | -------- | -------- | +| **Summarization 中间件** | 60-80% | 持平 | 低 | +| **Prompt Caching** | 50-90% | -10% | 低 | +| **Agent Pool 复用** | 20-40% | -50% | 中 | +| **工具结果缓存** | 10-30% | -30% | 中 | +| **Prompt 优化** | 10-20% | +5% | 低 | +| **输出长度限制** | 5-15% | +10% | 低 | +| **并发控制** | 0% | 变化 | 中 | +| **流式输出** | 0% | -40%\* | 低 | + +\*感知响应时间 ## 🔗 相关资源 diff --git a/docs/content/15.best-practices/security.md b/docs/content/15.best-practices/security.md index 135c621..fd66c6b 100644 --- a/docs/content/15.best-practices/security.md +++ b/docs/content/15.best-practices/security.md @@ -670,16 +670,16 @@ hitlMW, _ := middleware.NewHumanInTheLoopMiddleware(&middleware.HumanInTheLoopMi }, ApprovalHandler: func(ctx context.Context, req *middleware.ReviewRequest) ([]middleware.Decision, error) { action := req.ActionRequests[0] - + // 记录审核请求 log.Printf("[HITL] Tool: %s, Input: %+v", action.ToolName, action.Input) - + // 基于风险评估自动决策 risk := assessRisk(action) if risk == RiskLow { return []middleware.Decision{{Type: middleware.DecisionApprove}}, nil } - + // 高风险操作需要人工确认 return requestHumanApproval(action) }, @@ -698,6 +698,7 @@ stack.Use(hitlMW) 5. **分级审核** - 根据风险级别采用不同策略 **更多信息**: + - [HITL 完整指南](/guides/advanced/human-in-the-loop) - [HITL 中间件文档](/middleware/builtin/human-in-the-loop) @@ -1038,6 +1039,7 @@ func encrypt(plaintext, key []byte) ([]byte, error) { **风险**: 用户通过精心构造的输入操纵 Agent 行为 **防护**: + ```go // ✅ 使用结构化输入 systemPrompt := `你是客服助手,只能回答产品相关问题。 @@ -1056,6 +1058,7 @@ userInput := fmt.Sprintf("[USER_INPUT_START]\n%s\n[USER_INPUT_END]", input) **风险**: `../../etc/passwd` 访问敏感文件 **防护**: + ```go // ✅ 路径规范化和验证 cleanPath := filepath.Clean(path) @@ -1070,6 +1073,7 @@ if !strings.HasPrefix(absPath, allowedDir) { **风险**: `; rm -rf /` 执行危险命令 **防护**: + ```go // ✅ 使用命令白名单 // ✅ 避免 shell 执行,使用 exec.Command @@ -1081,6 +1085,7 @@ if !strings.HasPrefix(absPath, allowedDir) { **风险**: 日志或输出包含敏感信息 **防护**: + ```go // ✅ 日志脱敏 log.Printf("API call with key: %s", maskAPIKey(key)) diff --git a/docs/content/15.best-practices/skills-authoring.md b/docs/content/15.best-practices/skills-authoring.md index b9ae8e3..76fea50 100644 --- a/docs/content/15.best-practices/skills-authoring.md +++ b/docs/content/15.best-practices/skills-authoring.md @@ -39,9 +39,11 @@ allowed-tools: ["Bash", "Read", "Write"] # Markdown 分段翻译技能 ## 使用场景 + … ## 操作步骤 + … ``` @@ -88,25 +90,32 @@ allowed-tools: ["Bash", "Read", "Write"] # 技能名称(人类可读) ## 何时使用 + - 列出 3–5 条“典型场景” - 尽量使用用户原话风格,例如“当用户说‘翻译整篇 Markdown 文档’时…” ## 前置假设 + - 环境依赖(例如:已安装 python3 / 某些 pip 包) - 目录结构(用代码块展示 workspace 下的相对路径) ## 操作步骤 + ### 第 1 步:… + 1. 用什么工具做什么事(必须写清楚命令示例) 2. 需要关注的输出字段(例如 Bash 返回的 `ok` / `output`) ### 第 2 步:… + … ## 错误处理 + - 列出常见错误及建议的处理方式 ## 安全注意事项 + - 列出禁止做的事情(例如“不直接调用外部 API”“不修改原始文件”) ``` @@ -114,7 +123,7 @@ allowed-tools: ["Bash", "Read", "Write"] 不要假设 Agent 会“猜对”命令行。用真实命令举例: -```markdown +````markdown ### 第 1 步:分段 使用 `Bash` 工具执行: @@ -126,12 +135,15 @@ python3 workspace/skills/markdown-segment-translator/scripts/segment_tool.py \ --segment-size 1000 \ --max-segments 3 ``` +```` 执行完成后,你应该在输出中看到类似: + - `output/segments/segment_1.md` - `output/segments/segment_2.md` - `output/segments/segment_3.md` -``` + +```` 这样模型可以直接复用示例,而不是自己发明命令。 @@ -149,7 +161,7 @@ python3 workspace/skills/markdown-segment-translator/scripts/segment_tool.py \ 2. 使用自己的语言能力将内容翻译为中文,保持 Markdown 结构不变; 3. 使用 `Write` 工具将翻译结果写入: - `{"path": "output/translations/translated_segment_1.md", "content": "<你的翻译结果>"}` -``` +```` ## 4. 与系统提示配合 @@ -180,11 +192,13 @@ allowed-tools: ["Read", "Grep"] # 写作一致性检查 Skill ## 何时使用 + - 用户要求“检查角色/设定/时间线一致性” - 用户在写长篇故事,多次提到“前面说过”“和之前冲突”等 - 需要跨章节对比设定或角色档案 ## 前置假设 + - 角色档案位于 `spec/knowledge/characters/` - 世界观设定位于 `spec/knowledge/worldbuilding/` - 时间线记录为 `spec/tracking/timeline.json` @@ -195,6 +209,7 @@ allowed-tools: ["Read", "Grep"] ### 第 1 步:加载参考资料 使用 `Read` 工具读取以下文件(如存在): + - 主角角色档案,例如:`spec/knowledge/characters/main-character.md` - 当前章节草稿:`drafts/current-chapter.md` - 时间线文件:`spec/tracking/timeline.json` @@ -202,6 +217,7 @@ allowed-tools: ["Read", "Grep"] 在后续分析中,将这些内容作为“事实来源”。 ### 第 2 步:检查角色一致性 + - 比对当前章节中的角色行为、外貌特征、知识状态是否与角色档案中的设定一致; - 对发现的潜在冲突,给出: - 冲突描述 @@ -209,19 +225,21 @@ allowed-tools: ["Read", "Grep"] - 建议修正方案 ### 第 3 步:检查世界设定与时间线一致性 + - 对照世界观设定文档和时间线 JSON,找出: - 时间顺序错乱 - 设定被隐形修改 - 明显违反已建立规则的情节 ## 错误处理 + - 如果任何参考文件不存在,说明清楚缺失的是哪一类信息,并继续使用你能获取到的部分做最佳努力分析; - 如果文本中没有发现明确冲突,也要明确说明“未发现明显一致性问题”。 ## 安全注意事项 + - 不要随意修改原始参考文件; - 如果用户要求自动修正文本,应先给出变更建议,再根据用户确认执行写入。 ``` 这个示例的结构、注释和命名都可以作为你编写其他 SKILL.md 的模板。 - diff --git a/docs/content/15.best-practices/skills.md b/docs/content/15.best-practices/skills.md index 19f4673..4109faf 100644 --- a/docs/content/15.best-practices/skills.md +++ b/docs/content/15.best-practices/skills.md @@ -36,6 +36,7 @@ skills/ ``` **优势**: + - 按需激活,减少无关内容注入 - 独立维护和更新 - 便于团队协作 @@ -59,6 +60,7 @@ skills/ ``` **优势**: + - 自动适应工作流程 - 上下文相关性强 - 减少手动干预 @@ -148,14 +150,15 @@ workspace/ ```yaml --- -name: go-error-handling # 推荐:与目录名一致,小写 + 连字符 +name: go-error-handling # 推荐:与目录名一致,小写 + 连字符 --- ``` > 约束:当前实现中,`name` 必须满足: -> - 1–64 个字符 -> - 只包含小写字母、数字和连字符(`-`) -> - 不能包含 `anthropic` 或 `claude` +> +> - 1–64 个字符 +> - 只包含小写字母、数字和连字符(`-`) +> - 不能包含 `anthropic` 或 `claude` > - 建议与技能目录名保持一致,便于排查问题 ### 3. 版本管理 @@ -196,17 +199,17 @@ skills/ ## ⚡ 触发元数据策略(可选) -> 当前版本中,Skills 注入器不会根据 `triggers` 自动筛选技能。 +> 当前版本中,Skills 注入器不会根据 `triggers` 自动筛选技能。 > 如果你需要“按关键词/上下文/文件模式筛选技能”,推荐在自己的业务逻辑里解析 `triggers` 字段进行过滤。 ### 1. 选择合适的触发类型(元数据语义) -| 触发类型 | 建议含义 | 示例 | -|---------|---------|------| -| `always` | 表示此 Skill 是“常驻规范”,通常用于安全/合规类 Skill 的标记 | 代码规范、隐私政策 | -| `keyword` | 用于标记“适用的用户意图或关键词”,方便你在上层做路由/展示 | "性能优化"、"测试" | -| `context` | 标记适用的工作流阶段或命令 | `during /review` | -| `file_pattern` | 标记与特定文件类型强相关 | `**/*.go`、`**/*.md` | +| 触发类型 | 建议含义 | 示例 | +| -------------- | ----------------------------------------------------------- | -------------------- | +| `always` | 表示此 Skill 是“常驻规范”,通常用于安全/合规类 Skill 的标记 | 代码规范、隐私政策 | +| `keyword` | 用于标记“适用的用户意图或关键词”,方便你在上层做路由/展示 | "性能优化"、"测试" | +| `context` | 标记适用的工作流阶段或命令 | `during /review` | +| `file_pattern` | 标记与特定文件类型强相关 | `**/*.go`、`**/*.md` | ### 2. 组合触发最佳实践(供自定义过滤使用) @@ -313,14 +316,17 @@ triggers: # Skill 名称 ## 概述 + 简要说明此 Skill 的用途和价值 ## 核心原则 + - 原则1:解释 - 原则2:解释 - 原则3:解释 ## 检查清单 + - [ ] 检查项1 - [ ] 检查项2 - [ ] 检查项3 @@ -328,16 +334,19 @@ triggers: ## 示例 ### 正确示例 + \`\`\` 好的代码示例 \`\`\` ### 错误示例 + \`\`\` 不好的代码示例 \`\`\` ## 参考资料 + - [文档链接](https://...) - [最佳实践](https://...) ``` @@ -347,10 +356,10 @@ triggers: **推荐长度**: | Skill 类型 | 建议 Token 数 | 大约行数 | -|-----------|--------------|---------| -| 简单规范 | 500-1000 | 50-100 | -| 详细指南 | 1000-2000 | 100-200 | -| 完整教程 | 2000-5000 | 200-500 | +| ---------- | ------------- | -------- | +| 简单规范 | 500-1000 | 50-100 | +| 详细指南 | 1000-2000 | 100-200 | +| 完整教程 | 2000-5000 | 200-500 | **检查 Token 数**: @@ -373,25 +382,31 @@ print(f'Tokens: {len(enc.encode(content))}') ```markdown # 使用清晰的标题层级 + ## 二级标题 + ### 三级标题 # 使用列表 + - 无序列表项 - 简洁明了 # 使用表格对比 + | 方案 A | 方案 B | -|--------|--------| +| ------ | ------ | | 优点 A | 优点 B | # 使用代码块 + \`\`\`go // 带语言标注 func example() {} \`\`\` # 使用引用 + > 重要提示或警告 ``` diff --git a/docs/content/15.best-practices/testing.md b/docs/content/15.best-practices/testing.md index bbeecc7..dedd8b8 100644 --- a/docs/content/15.best-practices/testing.md +++ b/docs/content/15.best-practices/testing.md @@ -31,11 +31,11 @@ graph TD ### 测试分布建议 -| 测试类型 | 比例 | 执行时间 | 覆盖范围 | Mock程度 | -|---------|------|---------|---------|---------| -| **单元测试** | 70% | <1s | 单个函数/类 | 高 | -| **集成测试** | 20% | 1-10s | 多个组件 | 中 | -| **E2E测试** | 10% | 10s+ | 完整流程 | 低 | +| 测试类型 | 比例 | 执行时间 | 覆盖范围 | Mock程度 | +| ------------ | ---- | -------- | ----------- | -------- | +| **单元测试** | 70% | <1s | 单个函数/类 | 高 | +| **集成测试** | 20% | 1-10s | 多个组件 | 中 | +| **E2E测试** | 10% | 10s+ | 完整流程 | 低 | ## 🧪 单元测试 diff --git a/docs/content/16.whitepaper/1.whitepaper.md b/docs/content/16.whitepaper/1.whitepaper.md index 3352cca..6b02fb5 100644 --- a/docs/content/16.whitepaper/1.whitepaper.md +++ b/docs/content/16.whitepaper/1.whitepaper.md @@ -136,6 +136,7 @@ aster在以下方面做出了关键贡献: - **Monitor通道**:审计事件、性能指标、错误追踪 这种分离关注点的设计使得: + - **实时性**:用户可以看到Agent的实时思考过程 - **可控性**:关键操作可以暂停等待人工审批 - **可观测性**:完整的行为追踪和审计日志 @@ -150,6 +151,7 @@ Response ← [MW1 after] ← [MW2 after] ← [MW3 after] ← Core ``` 优势: + - **即插即用**:中间件可以独立开发和测试 - **组合灵活**:通过优先级控制执行顺序 - **职责单一**:每个中间件专注一个功能 @@ -394,6 +396,7 @@ func (a *Agent) getBackend() Backend { ``` **优势**: + - **松耦合**:Agent不依赖具体Backend实现 - **可测试**:轻松注入Mock实现 - **灵活配置**:运行时决定使用哪个Backend @@ -863,6 +866,7 @@ const ( ``` **设计原则**: + - **安全中间件优先级最高**(如PII脱敏) - **资源中间件次之**(如文件系统) - **功能增强中间件居中**(如SubAgent) @@ -1014,6 +1018,7 @@ func (m *FilesystemMiddleware) Before(ctx context.Context, req *AgentRequest) (* ``` **安全特性**: + - 路径验证(防止目录遍历攻击) - 权限检查 - 操作审计 @@ -1058,6 +1063,7 @@ func (m *SubAgentMiddleware) Before(ctx context.Context, req *AgentRequest) (*Ag ``` **适用场景**: + - 代码生成 → CodeAgent - 数据分析 → DataAgent - 文档编写 → WriterAgent @@ -1098,6 +1104,7 @@ func (m *SummarizationMiddleware) Before(ctx context.Context, req *AgentRequest) ``` **压缩级别**: + - **Light(轻度)**:仅删除重复内容,保留原始消息 - **Moderate(中度)**:LLM生成简洁总结 - **Aggressive(激进)**:仅保留关键信息 @@ -1458,6 +1465,7 @@ aster实现了完整的三层记忆系统,并完整支持Google Context Engine **用途**:保存完整的原始对话历史,用于审计和回溯。 **特点**: + - **不压缩**:保留所有细节 - **持久化**:存储到Backend - **可追溯**:完整的时间线 @@ -1485,6 +1493,7 @@ type TextMemory interface { **用途**:维护当前会话的活跃信息,注入到LLM的System Prompt。 **关键功能**: + - **Token预算管理**:控制Working Memory总大小 - **智能压缩**:自动压缩旧消息 - **优先级排序**:重要信息优先保留 @@ -3207,17 +3216,20 @@ func (al *AuditLogger) flush(ctx context.Context) error { aster支持以下合规标准: **GDPR(欧盟通用数据保护条例)**: + - PII自动脱敏 - 用户数据删除(Right to be Forgotten) - 数据导出(Data Portability) - 审计日志 **SOC 2(系统和组织控制)**: + - 完整的审计日志 - 访问控制 - 数据加密 **HIPAA(美国医疗隐私法)**: + - PHI(受保护健康信息)检测和脱敏 - 审计日志 - 访问控制 @@ -3270,6 +3282,7 @@ func (cc *ComplianceChecker) Check(ctx context.Context, operation Operation) (*C #### 8.1.1 设计动机 单个Agent难以应对复杂业务场景: + - **并发需求**:同时处理多个用户请求 - **资源隔离**:不同任务使用独立Agent避免状态污染 - **生命周期管理**:动态创建、暂停、恢复、销毁Agent @@ -3281,6 +3294,7 @@ Cosmos 提供**统一的Agent生命周期管理**,类似于数据库连接池 **1. 容量控制** Cosmos 设置了默认最大容量(50个Agent),防止资源耗尽: + - **限流保护**:超过容量拒绝创建 - **可配置**:根据硬件资源调整 - **弹性扩展**:支持动态调整容量 @@ -3288,6 +3302,7 @@ Cosmos 设置了默认最大容量(50个Agent),防止资源耗尽: **2. 线程安全** 使用`sync.RWMutex`保护并发访问: + - **读锁**:Get、List等查询操作 - **写锁**:Create、Remove、Delete等修改操作 - **无锁读取**:状态查询不阻塞 @@ -3296,17 +3311,18 @@ Cosmos 设置了默认最大容量(50个Agent),防止资源耗尽: Cosmos 提供完整的CRUD操作: -| API | 功能 | 持久化 | 使用场景 | -|-----|------|--------|----------| -| `Create()` | 创建新Agent | ✅ 保存到Backend | 新用户会话 | -| `Resume()` | 从存储恢复 | ✅ 加载现有状态 | 断点续传 | -| `Get()` | 获取Agent实例 | ❌ 仅内存访问 | 状态查询 | -| `List()` | 列出Agent ID | ❌ 支持前缀过滤 | 批量管理 | -| `Remove()` | 从宇宙中移除 | ❌ 不删存储 | 临时清理 | -| `Delete()` | 完全删除 | ✅ 清除Backend | 永久销毁 | -| `ForEach()` | 遍历所有Agent | ❌ 批量操作 | 状态同步 | +| API | 功能 | 持久化 | 使用场景 | +| ----------- | ------------- | ---------------- | ---------- | +| `Create()` | 创建新Agent | ✅ 保存到Backend | 新用户会话 | +| `Resume()` | 从存储恢复 | ✅ 加载现有状态 | 断点续传 | +| `Get()` | 获取Agent实例 | ❌ 仅内存访问 | 状态查询 | +| `List()` | 列出Agent ID | ❌ 支持前缀过滤 | 批量管理 | +| `Remove()` | 从宇宙中移除 | ❌ 不删存储 | 临时清理 | +| `Delete()` | 完全删除 | ✅ 清除Backend | 永久销毁 | +| `ForEach()` | 遍历所有Agent | ❌ 批量操作 | 状态同步 | **设计哲学**: + - **Create vs Resume**:Create用于全新Agent,Resume用于恢复已保存的Agent - **Remove vs Delete**:Remove仅清理内存,Delete彻底删除(包括Backend) - **Get vs List**:Get返回Agent对象,List仅返回ID列表(轻量级) @@ -3316,15 +3332,18 @@ Cosmos 提供完整的CRUD操作: Cosmos 在高并发场景下的安全机制: **读写分离**: + - 查询操作(Get/List)使用读锁,允许并发读取 - 修改操作(Create/Delete)使用写锁,串行化执行 **状态一致性**: + - 创建Agent前检查容量限制 - 删除Agent后立即清理索引 - Backend写入失败时回滚内存状态 **实测性能**: + - 并发创建:100个Goroutine同时创建Agent,无竞态条件 - 查询延迟:Get操作 <1μs(纯内存访问) - 遍历性能:ForEach遍历100个Agent <100μs @@ -3332,6 +3351,7 @@ Cosmos 在高并发场景下的安全机制: ### 8.2 Scheduler:任务调度 Scheduler 提供智能的任务调度能力,支持: + - **步骤触发**:每N步执行一次任务 - **时间触发**:定时执行任务 - **事件监听**:监听Agent步骤完成事件 @@ -3339,16 +3359,19 @@ Scheduler 提供智能的任务调度能力,支持: 详细文档请参考 [Scheduler 文档](/multi-agent/scheduler) **移除成员**: + - `RemoveMember(name)`:解除绑定 - 不影响Agent本身,仅清除Room中的引用 - 历史消息保留 **成员查询**: + - `ListMembers()`:返回所有成员名称 - `GetAgentID(name)`:通过名称查找Agent ID - `HasMember(name)`:检查成员是否存在 **设计优势**: + - **名称解耦**:Agent ID与显示名称分离 - **灵活绑定**:同一Agent可以扮演多个角色 - **跨Room隔离**:不同Room的成员空间独立 @@ -3362,17 +3385,20 @@ aster提供三种WorkflowAgent,支持不同的任务分发模式: **1. ParallelAgent(并行执行)** **适用场景**: + - 多方案对比(同时调用Claude/GPT-4/DeepSeek) - 并行子任务(代码审查中同时检查安全/性能/风格) - 投票决策(多个Agent独立判断,最后汇总) **执行流程**: + 1. 将输入同时发送给所有子Agent 2. 各子Agent并发执行(使用Goroutine) 3. 等待所有Agent完成或超时 4. 汇总结果(支持First/All/Majority策略) **性能优势**: + - 真并发(Goroutine vs Python asyncio) - 总耗时 = max(子任务耗时) vs sum(子任务耗时) - 实测:3个Agent并行 vs 顺序执行,耗时降低67% @@ -3380,17 +3406,20 @@ aster提供三种WorkflowAgent,支持不同的任务分发模式: **2. SequentialAgent(顺序执行)** **适用场景**: + - 流水线处理(outline → draft → review → format) - 依赖链任务(A的输出是B的输入) - 多轮优化(generate → critique → improve → critique) **执行流程**: + 1. 将输入发送给第一个Agent 2. 等待第一个Agent完成 3. 将输出传递给下一个Agent 4. 重复直到所有Agent执行完毕 **上下文传递**: + - **显式传递**:前一个Agent的输出作为下一个的输入 - **累积上下文**:可选配置保留所有历史输出 - **中间结果**:每个阶段的输出都可被监控 @@ -3398,17 +3427,20 @@ aster提供三种WorkflowAgent,支持不同的任务分发模式: **3. LoopAgent(循环执行)** **适用场景**: + - 迭代优化(critic → improver循环直到满意) - 自我修正(generator → validator循环直到通过) - 渐进式生成(outline → expand → outline循环) **执行流程**: + 1. 将输入发送给第一个Agent(如Generator) 2. 将输出发送给第二个Agent(如Critic) 3. 检查终止条件(如Critic评分 > 阈值) 4. 如果未满足,回到步骤1 **终止条件**: + - **最大迭代次数**:防止无限循环 - **质量阈值**:达到目标分数即停止 - **手动中断**:用户通过Control Channel终止 @@ -3420,12 +3452,14 @@ aster提供三种WorkflowAgent,支持不同的任务分发模式: 架构设计:SequentialAgent 工作流程: + 1. **Researcher Agent**:理解代码逻辑,生成功能摘要 2. **Security Agent**:扫描安全漏洞(SQL注入、XSS等) 3. **Performance Agent**:分析性能瓶颈(O(n²)算法、内存泄漏) 4. **Reviewer Agent**:汇总所有发现,生成审查报告 优势: + - 专业分工:每个Agent专注一个领域 - 上下文传递:后续Agent可以参考前面的分析 - 可扩展:轻松添加新的检查阶段 @@ -3435,12 +3469,14 @@ aster提供三种WorkflowAgent,支持不同的任务分发模式: 架构设计:ParallelAgent 工作流程: + 1. 同时向Claude Sonnet 4.5、GPT-4、DeepSeek发送相同提示 2. 收集所有响应 3. 比较输出质量(准确性、完整性、创意性) 4. 生成对比报告 优势: + - 时间高效:总耗时 = 最慢模型耗时 - 公平对比:所有模型收到相同输入 - 成本优化:可以根据结果选择最优模型 @@ -3450,6 +3486,7 @@ aster提供三种WorkflowAgent,支持不同的任务分发模式: 架构设计:LoopAgent 工作流程: + 1. **Writer Agent**:生成文档初稿 2. **Critic Agent**:评估质量(清晰度、完整性、准确性) 3. 如果评分 < 8分,将评语反馈给Writer @@ -3457,6 +3494,7 @@ aster提供三种WorkflowAgent,支持不同的任务分发模式: 5. 循环最多5次或评分达标 优势: + - 自我优化:无需人工介入 - 质量保障:循环直到达标 - 可控性:最大迭代次数防止过度优化 @@ -3468,6 +3506,7 @@ aster的多Agent系统体现了以下设计理念: **1. 松耦合架构** Agent 通过 Cosmos 统一管理,而非直接耦合: + - 降低耦合度 - 易于扩展(新增Agent无需修改现有代码) - 支持动态成员 @@ -3475,6 +3514,7 @@ Agent 通过 Cosmos 统一管理,而非直接耦合: **2. 组合优于继承** WorkflowAgent通过组合子Agent实现复杂逻辑: + - 灵活性高(运行时动态组合) - 可测试性强(每个子Agent可独立测试) - 代码重用(同一Agent可用于多个Workflow) @@ -3489,6 +3529,7 @@ WorkflowAgent通过组合子Agent实现复杂逻辑: **4. 并发优先** 充分利用Go的并发特性: + - ParallelAgent真正并行(Goroutine) - Scheduler 异步调度(channel) - Cosmos 无锁读取(RWMutex) @@ -3502,11 +3543,13 @@ LLM Provider和Tool System是Agent的两大基础设施。aster通过**Protocol #### 9.1.1 设计理念 传统Agent框架往往与特定LLM强绑定(如AutoGPT仅支持OpenAI),这导致: + - **厂商锁定**:难以切换到其他LLM - **成本高昂**:无法利用价格更优的替代方案 - **功能受限**:无法使用新模型的独特能力 aster采用**Provider Protocol**设计,将LLM抽象为统一接口: + - **厂商中立**:无缝切换OpenAI/Anthropic/DeepSeek - **成本优化**:根据任务选择性价比最优的模型 - **能力查询**:运行时检测模型功能(Vision/ToolUse等) @@ -3515,22 +3558,23 @@ aster采用**Provider Protocol**设计,将LLM抽象为统一接口: aster通过`MultiProviderFactory`支持**10+个主流LLM厂商**: -| 厂商 | 别名 | 市场定位 | 代表模型 | 特点 | -|------|------|----------|----------|------| -| **Anthropic** | anthropic | 国际主流 | Claude Sonnet 4.5 | Computer Use, 200K上下文 | -| **OpenAI** | openai | 国际主流 | GPT-4o, o1, o3-mini | Function Calling, 128K上下文 | -| **Google** | gemini, google | 国际主流 | Gemini 2.0 Flash | 1M上下文, 多模态 | -| **DeepSeek** | deepseek | 中国市场 | DeepSeek-V3 | 高性价比, 64K上下文 | -| **智谱AI** | glm, zhipu, bigmodel | 中国市场 | GLM-4-Plus | 128K上下文, 国产领先 | -| **豆包** | doubao, bytedance | 中国市场 | Doubao-Pro | 字节跳动, 低成本 | -| **月之暗面** | moonshot, kimi | 中国市场 | Moonshot-v1-128k | 长文本处理 | -| **通义千问** | qwen, dashscope | 中国市场 | Qwen-Max | 阿里云生态 | -| **Groq** | groq | 高性能推理 | Llama 3 70B | 极速推理芯片 | -| **Ollama** | ollama | 本地部署 | Llama/Mistral | 开源模型, 离线运行 | -| **OpenRouter** | openrouter | 聚合平台 | 100+ 模型 | 统一路由 | -| **Mistral AI** | mistral | 欧洲市场 | Mistral Large | 开源友好 | +| 厂商 | 别名 | 市场定位 | 代表模型 | 特点 | +| -------------- | -------------------- | ---------- | ------------------- | ---------------------------- | +| **Anthropic** | anthropic | 国际主流 | Claude Sonnet 4.5 | Computer Use, 200K上下文 | +| **OpenAI** | openai | 国际主流 | GPT-4o, o1, o3-mini | Function Calling, 128K上下文 | +| **Google** | gemini, google | 国际主流 | Gemini 2.0 Flash | 1M上下文, 多模态 | +| **DeepSeek** | deepseek | 中国市场 | DeepSeek-V3 | 高性价比, 64K上下文 | +| **智谱AI** | glm, zhipu, bigmodel | 中国市场 | GLM-4-Plus | 128K上下文, 国产领先 | +| **豆包** | doubao, bytedance | 中国市场 | Doubao-Pro | 字节跳动, 低成本 | +| **月之暗面** | moonshot, kimi | 中国市场 | Moonshot-v1-128k | 长文本处理 | +| **通义千问** | qwen, dashscope | 中国市场 | Qwen-Max | 阿里云生态 | +| **Groq** | groq | 高性能推理 | Llama 3 70B | 极速推理芯片 | +| **Ollama** | ollama | 本地部署 | Llama/Mistral | 开源模型, 离线运行 | +| **OpenRouter** | openrouter | 聚合平台 | 100+ 模型 | 统一路由 | +| **Mistral AI** | mistral | 欧洲市场 | Mistral Large | 开源友好 | **厂商覆盖分析**: + - **国际市场**:OpenAI、Anthropic、Google(三巨头) - **中国市场**:DeepSeek、智谱、豆包、月之暗面、通义千问(五大国产) - **高性能推理**:Groq(专用芯片) @@ -3542,6 +3586,7 @@ aster通过`MultiProviderFactory`支持**10+个主流LLM厂商**: **统一接口**: 所有Provider必须实现以下方法: + - **Chat()**:标准对话接口 - **ChatStream()**:流式对话接口 - **GetCapabilities()**:能力查询 @@ -3549,6 +3594,7 @@ aster通过`MultiProviderFactory`支持**10+个主流LLM厂商**: **能力查询接口**: aster允许运行时检测模型能力: + - **SupportSystemPrompt**:是否支持System Prompt - **SupportToolUse**:是否支持Tool Calling - **SupportStreaming**:是否支持流式输出 @@ -3556,6 +3602,7 @@ aster允许运行时检测模型能力: - **MaxContextTokens**:最大上下文Token数 **使用场景**: + 1. **自动降级**:如果模型不支持Tool Use,回退到文本输出 2. **能力匹配**:根据任务需求选择合适的模型 3. **成本优化**:优先使用功能足够且成本更低的模型 @@ -3565,6 +3612,7 @@ aster允许运行时检测模型能力: **延迟初始化**: Provider不在Agent创建时初始化,而是**首次使用时创建**: + - 降低启动开销 - 避免不必要的API连接 - 支持动态切换Provider @@ -3572,6 +3620,7 @@ Provider不在Agent创建时初始化,而是**首次使用时创建**: **配置驱动**: 通过`ModelConfig`动态创建Provider: + - **Provider名称**:`anthropic`/`openai`/`deepseek`等 - **模型ID**:`claude-sonnet-4.5`/`gpt-4o`等 - **API Key**:从环境变量或配置文件读取 @@ -3580,6 +3629,7 @@ Provider不在Agent创建时初始化,而是**首次使用时创建**: **别名支持**: 同一Provider支持多个别名: + - `gemini`/`google` → GoogleProvider - `glm`/`zhipu`/`bigmodel` → ZhipuProvider - `moonshot`/`kimi` → MoonshotProvider @@ -3645,6 +3695,7 @@ aster提供**9个生产级内置工具**,覆盖文件系统、Shell、网络 - 返回标题、摘要、链接 **设计原则**: + - **高频需求**:覆盖90%的Agent工具使用场景 - **安全优先**:所有文件操作经过权限检查 - **错误友好**:详细的错误信息帮助调试 @@ -3654,6 +3705,7 @@ aster提供**9个生产级内置工具**,覆盖文件系统、Shell、网络 **静态注册**: 内置工具通过`RegisterAll()`批量注册: + - 启动时一次性注册所有工具 - 工厂函数模式(而非实例) - 延迟创建(按需实例化) @@ -3668,6 +3720,7 @@ aster提供**9个生产级内置工具**,覆盖文件系统、Shell、网络 **动态注册**: 支持运行时添加工具: + - 插件系统加载外部工具 - 用户自定义工具 - 临时工具(如数据库查询) @@ -3675,6 +3728,7 @@ aster提供**9个生产级内置工具**,覆盖文件系统、Shell、网络 **工具查询**: Registry提供工具发现能力: + - `List()`:返回所有已注册工具名称 - `Has(name)`:检查工具是否存在 - `Create(name, config)`:创建工具实例 @@ -3685,6 +3739,7 @@ Registry提供工具发现能力: **核心方法**: 每个Tool必须实现: + 1. **Name()**:工具名称(唯一标识) 2. **Description()**:工具描述(LLM理解用途) 3. **InputSchema()**:JSON Schema定义输入参数 @@ -3693,6 +3748,7 @@ Registry提供工具发现能力: **可选方法**: 高级工具可以实现: + - **Prompt()**:工具使用手册(提供示例) - **Validate()**:输入验证(Execute前检查) - **Cleanup()**:资源清理(长时运行工具) @@ -3700,6 +3756,7 @@ Registry提供工具发现能力: **InputSchema重要性**: JSON Schema驱动LLM的Function Calling: + - **参数类型**:string/number/boolean/object/array - **必填字段**:`required: ["path", "content"]` - **约束条件**:`minLength`/`maxLength`/`pattern`等 @@ -3714,6 +3771,7 @@ LLM根据Schema生成正确的参数格式,aster根据Schema验证输入。 **Model Context Protocol (MCP)** 是Anthropic提出的标准化协议,用于Agent与外部工具的通信。 **核心优势**: + - **标准化**:统一的工具接口规范 - **语言中立**:支持任何编程语言实现 - **进程隔离**:工具运行在独立进程(安全) @@ -3727,6 +3785,7 @@ aster通过MCP适配层支持**任意MCP Server**。 **命名规则**:`{server_id}:{tool_name}` 示例: + - `filesystem:read_file`(来自filesystem server) - `database:query`(来自database server) - `github:create_pr`(来自github server) @@ -3739,6 +3798,7 @@ Agent可以同时使用内置工具和MCP工具: - **MCP工具**:使用命名空间(如`github:create_pr`) **冲突解决**: + - 内置工具优先级高于MCP工具 - 同名MCP工具必须使用完整命名空间 @@ -3747,6 +3807,7 @@ Agent可以同时使用内置工具和MCP工具: **连接管理**: MCPManager负责: + - **Server发现**:扫描配置文件中的Server列表 - **连接建立**:启动Server进程,建立stdio/HTTP连接 - **健康检查**:定期ping Server,检测存活 @@ -3755,6 +3816,7 @@ MCPManager负责: **工具适配**: MCP Tool自动适配为aster Tool: + - **Schema转换**:MCP Schema → JSON Schema - **参数映射**:aster参数 → MCP参数 - **结果转换**:MCP结果 → aster结果 @@ -3767,7 +3829,8 @@ Agent配置文件中声明MCP Servers: mcp_servers: filesystem: command: "npx" - args: ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/workspace"] + args: + ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/workspace"] github: command: "npx" @@ -3777,6 +3840,7 @@ mcp_servers: ``` MCPManager自动: + 1. 启动两个Server进程 2. 注册工具(filesystem:read_file, github:create_pr等) 3. 管理生命周期(启动/停止/重启) @@ -3788,6 +3852,7 @@ MCPManager自动: **静态发现**: 启动时扫描: + - 内置工具(RegisterAll) - 配置文件中的MCP Servers - 插件目录中的自定义工具 @@ -3795,6 +3860,7 @@ MCPManager自动: **动态发现**: 运行时添加: + - 用户上传新工具脚本 - Agent自主发现可用工具(未来功能) - 工具市场安装 @@ -3804,6 +3870,7 @@ MCPManager自动: **延迟创建**: 工具实例不在注册时创建,而是**首次使用时创建**: + - 降低启动开销(特别是大量工具时) - 减少内存占用 - 支持工具配置的动态修改 @@ -3811,6 +3878,7 @@ MCPManager自动: **工具缓存**: 创建后的工具实例缓存复用: + - 避免重复初始化 - 保持工具状态(如数据库连接) - 减少资源消耗 @@ -3818,6 +3886,7 @@ MCPManager自动: **生命周期管理**: 工具支持Cleanup方法: + - Agent销毁时调用所有工具的Cleanup - 释放资源(关闭连接、删除临时文件) - 确保无资源泄漏 @@ -3827,6 +3896,7 @@ MCPManager自动: **Permission Manager集成**: 所有工具调用必须经过权限检查: + - **allow**:直接执行 - **deny**:拒绝执行 - **ask**:发起HITL审批 @@ -3835,16 +3905,17 @@ MCPManager自动: ```yaml tool_permissions: - Read: allow # 读文件允许 - Write: ask # 写文件需要审批 - Bash: deny # 禁止执行Shell - WebSearch: allow # 搜索允许 - "github:*": ask # 所有GitHub操作需审批 + Read: allow # 读文件允许 + Write: ask # 写文件需要审批 + Bash: deny # 禁止执行Shell + WebSearch: allow # 搜索允许 + "github:*": ask # 所有GitHub操作需审批 ``` **细粒度控制**: 支持基于参数的权限: + - `Write`允许,但路径必须在`/workspace`下 - `HttpRequest`允许,但URL必须在白名单域名 - `Bash`允许,但命令必须匹配白名单 @@ -3921,26 +3992,29 @@ triggers: ## 检查清单 ### 角色一致性 + - 性格特征是否前后一致 - 对话风格是否符合人设 ### 世界规则 + - 魔法体系规则是否矛盾 - 科技水平是否统一 ### 时间线 + - 事件顺序是否合理 - 角色年龄是否匹配 ``` #### 10.2.2 元数据字段 -| 字段 | 类型 | 必需 | 说明 | -|------|------|------|------| -| `name` | string | ✅ | Skill 唯一标识符 | -| `description` | string | ✅ | 功能描述 | -| `allowed-tools` | []string | ❌ | 允许使用的工具列表 | -| `triggers` | []Trigger | ✅ | 触发条件(至少1个) | +| 字段 | 类型 | 必需 | 说明 | +| --------------- | --------- | ---- | ------------------- | +| `name` | string | ✅ | Skill 唯一标识符 | +| `description` | string | ✅ | 功能描述 | +| `allowed-tools` | []string | ❌ | 允许使用的工具列表 | +| `triggers` | []Trigger | ✅ | 触发条件(至少1个) | ### 10.3 触发机制 @@ -3965,6 +4039,7 @@ triggers: ``` 在特定命令或状态下激活。适用于: + - Slash Command 执行期间 - 特定工作流程阶段 - Agent 模式切换 @@ -3977,6 +4052,7 @@ triggers: ``` 无条件激活,知识库始终注入。适用于: + - 核心工作规范 - 安全准则 - 必须遵守的原则 @@ -3990,6 +4066,7 @@ triggers: ``` 操作文件路径匹配 glob 模式时激活。支持通配符: + - `**/*.go`:所有 Go 文件 - `src/**`:src 目录下所有文件 - `*_test.go`:所有测试文件 @@ -4077,12 +4154,15 @@ User Message: ## Activated Skills ### coding-standards + [内容...] ### security-checklist + [内容...] ### test-guidelines + [内容...] ``` @@ -4104,12 +4184,12 @@ workspace/ #### 10.5.2 多种存储支持 -| 存储类型 | Path 格式 | 适用场景 | -|---------|-----------|---------| -| 本地文件系统 | `./path/to/skills` | 开发测试 | -| 阿里云OSS | `oss://bucket/prefix` | 生产环境 | -| AWS S3 | `s3://bucket/prefix` | 跨区域部署 | -| HTTP(S) | `https://cdn.com/skills` | CDN分发 | +| 存储类型 | Path 格式 | 适用场景 | +| ------------ | ------------------------ | ---------- | +| 本地文件系统 | `./path/to/skills` | 开发测试 | +| 阿里云OSS | `oss://bucket/prefix` | 生产环境 | +| AWS S3 | `s3://bucket/prefix` | 跨区域部署 | +| HTTP(S) | `https://cdn.com/skills` | CDN分发 | **配置示例**: @@ -4144,16 +4224,19 @@ triggers: # Go代码审查清单 ## 错误处理 + - 所有错误必须检查 - 使用 errors.Is/As 判断错误类型 - 返回有意义的错误信息 ## 并发安全 + - 检查共享数据的保护 - 避免 goroutine 泄漏 - 正确使用 context ## 性能优化 + - 避免不必要的内存分配 - 使用 sync.Pool 复用对象 - 减少反射使用 @@ -4172,6 +4255,7 @@ triggers: # 安全审计指南 ## OWASP Top 10 + 1. 注入攻击(SQL, XSS, Command) 2. 认证失效 3. 敏感数据泄露 @@ -4179,6 +4263,7 @@ triggers: 5. 访问控制失效 ## 检查要点 + - 用户输入是否验证和转义 - 密码是否加密存储(bcrypt/argon2) - API 是否有权限控制 @@ -4199,17 +4284,20 @@ triggers: # 写作最佳实践 ## 结构 + - 开头:吸引注意力的钩子 - 中间:逻辑清晰的论述 - 结尾:有力的总结和行动号召 ## 风格 + - 使用主动语态而非被动语态 - 避免冗余表达和废话 - 保持段落简短(3-5句) - 使用具体例子代替抽象概念 ## 可读性 + - 一句话一个想法 - 使用过渡词连接段落 - 适当使用列表和标题 @@ -4217,14 +4305,14 @@ triggers: ### 10.7 与其他扩展方式对比 -| 特性 | Skills | Custom Tools | Slash Commands | -|------|--------|--------------|----------------| -| **用途** | 知识库注入 | 执行操作 | 快捷指令 | -| **触发方式** | 自动/关键词 | Agent 主动调用 | 用户输入 | -| **内容形式** | Markdown 文档 | Go 代码 | 命令脚本 | -| **实现难度** | 低(编写文档) | 中(实现接口) | 低(配置文件) | -| **动态性** | 高(运行时加载) | 低(编译时确定) | 中(配置加载) | -| **适用场景** | 领域知识、规范 | 文件操作、API | 快速启动任务 | +| 特性 | Skills | Custom Tools | Slash Commands | +| ------------ | ---------------- | ---------------- | -------------- | +| **用途** | 知识库注入 | 执行操作 | 快捷指令 | +| **触发方式** | 自动/关键词 | Agent 主动调用 | 用户输入 | +| **内容形式** | Markdown 文档 | Go 代码 | 命令脚本 | +| **实现难度** | 低(编写文档) | 中(实现接口) | 低(配置文件) | +| **动态性** | 高(运行时加载) | 低(编译时确定) | 中(配置加载) | +| **适用场景** | 领域知识、规范 | 文件操作、API | 快速启动任务 | **组合使用示例**: @@ -4336,6 +4424,7 @@ aster 的 Skills 系统体现了以下优势: aster经过长期开发和迭代,已形成完整的代码体系: **核心代码规模**: + - **总代码行数**:41,417 LOC(不含测试) - **测试代码行数**:15,818 LOC - **代码测试比**:38.2%(高于行业平均30%) @@ -4343,19 +4432,20 @@ aster经过长期开发和迭代,已形成完整的代码体系: **模块分布**: -| 模块 | 代码行数 | 文件数 | 主要功能 | -|------|---------|--------|----------| -| `pkg/agent/` | 599 | 3 | Agent核心逻辑 | -| `pkg/cosmos/` | 200 | 1 | Cosmos 生命周期管理 | -| `pkg/middleware/` | ~5,000 | 22 | 中间件系统 | -| `pkg/memory/` | ~15,000 | 30 | 三层记忆系统 | -| `pkg/provider/` | ~3,500 | 15 | LLM Provider | -| `pkg/tools/` | ~2,800 | 9 | 工具系统 | -| `pkg/context/` | ~1,200 | 5 | 上下文工程 | -| `pkg/security/` | ~800 | 4 | PII检测、权限 | -| 其他 | ~12,000 | 50+ | Backend、Session等 | +| 模块 | 代码行数 | 文件数 | 主要功能 | +| ----------------- | -------- | ------ | ------------------- | +| `pkg/agent/` | 599 | 3 | Agent核心逻辑 | +| `pkg/cosmos/` | 200 | 1 | Cosmos 生命周期管理 | +| `pkg/middleware/` | ~5,000 | 22 | 中间件系统 | +| `pkg/memory/` | ~15,000 | 30 | 三层记忆系统 | +| `pkg/provider/` | ~3,500 | 15 | LLM Provider | +| `pkg/tools/` | ~2,800 | 9 | 工具系统 | +| `pkg/context/` | ~1,200 | 5 | 上下文工程 | +| `pkg/security/` | ~800 | 4 | PII检测、权限 | +| 其他 | ~12,000 | 50+ | Backend、Session等 | **示例代码**: + - **示例数量**:31个完整示例 - **覆盖场景**:从Hello World到生产级应用 - **文档丰富**:每个示例都有详细README @@ -4369,6 +4459,7 @@ aster经过长期开发和迭代,已形成完整的代码体系: 传统Agent框架需要缓冲所有事件: **传统方式的问题**: + - **内存占用**:O(n),n为事件总数 - **延迟高**:等待所有事件生成完毕才返回 - **不可取消**:客户端无法中途停止 @@ -4376,6 +4467,7 @@ aster经过长期开发和迭代,已形成完整的代码体系: **stream.Reader解决方案**: aster的stream.Reader提供: + - **惰性生成**:按需生成事件,内存O(1) - **背压控制**:客户端可随时停止 - **零拷贝**:直接传递指针,无额外分配 @@ -4383,6 +4475,7 @@ aster的stream.Reader提供: **应用场景统计**: aster中5个核心接口使用stream.Reader: + 1. **Agent.Stream()**:流式执行Agent 2. **ParallelAgent.Execute()**:并行工作流 3. **SequentialAgent.Execute()**:顺序工作流 @@ -4392,6 +4485,7 @@ aster中5个核心接口使用stream.Reader: **辅助函数生态**: aster提供stream工具函数: + - `StreamCollect(reader)`:收集所有事件到切片 - `StreamFirst(reader)`:获取第一个事件 - `StreamLast(reader)`:获取最后一个事件 @@ -4400,17 +4494,18 @@ aster提供stream工具函数: **性能数据**: -| 场景 | 传统方式 | stream.Reader | 内存降低 | -|------|---------|----------|----------| -| 100事件 | 4KB | 40B | 99% | -| 1000事件 | 40KB | 40B | 99.9% | -| 10000事件 | 400KB | 40B | 99.99% | +| 场景 | 传统方式 | stream.Reader | 内存降低 | +| --------- | -------- | ------------- | -------- | +| 100事件 | 4KB | 40B | 99% | +| 1000事件 | 40KB | 40B | 99.9% | +| 10000事件 | 400KB | 40B | 99.99% | #### 10.2.2 其他Go特性 **泛型(Go 1.18+)**: aster使用泛型简化代码: + - `StreamFilter[T]`:类型安全的过滤器 - `StreamMap[T, U]`:类型转换 - `Result[T]`:错误处理包装 @@ -4418,6 +4513,7 @@ aster使用泛型简化代码: **错误包装(errors.Join)**: Go 1.20引入的`errors.Join`用于多错误合并: + - ParallelAgent收集所有子Agent错误 - 一次性返回所有失败原因 @@ -4432,11 +4528,13 @@ BenchmarkMiddlewareStack-8 33,000,000 36.21 ns/op 96 B/op 2 allocs/op ``` **性能分析**: + - **吞吐量**:27M ops/s(每秒2700万次中间件调用) - **延迟**:36纳秒(远低于网络和LLM延迟) - **内存**:96字节/次(2次分配) **优化技术**: + - **无锁排序**:中间件注册时排序,执行时只读 - **指针传递**:Request/Response直接传指针 - **栈分配**:小对象分配在栈上 @@ -4450,6 +4548,7 @@ BenchmarkBackendWrite-8 3,800,000 257.9 ns/op 480 B/op 8 allocs/op ``` **优化措施**: + - **直接传递[]byte**:避免string↔[]byte转换 - **缓冲池复用**:sync.Pool管理临时缓冲区 - **批量写入**:合并多个写操作 @@ -4458,13 +4557,14 @@ BenchmarkBackendWrite-8 3,800,000 257.9 ns/op 480 B/op 8 allocs/op **AgentMemoryMiddleware性能**: -| 场景 | 耗时 | 说明 | -|------|------|------| -| 首次加载 | 100μs | 从Backend读取 | -| 已加载 | 10ns | 缓存命中 | -| 性能提升 | 10,000x | 懒加载+缓存 | +| 场景 | 耗时 | 说明 | +| -------- | ------- | ------------- | +| 首次加载 | 100μs | 从Backend读取 | +| 已加载 | 10ns | 缓存命中 | +| 性能提升 | 10,000x | 懒加载+缓存 | **实现机制**: + - **懒加载**:首次使用时加载Working Memory - **缓存**:后续请求直接使用缓存 - **失效策略**:手动失效或TTL过期 @@ -4479,6 +4579,7 @@ BenchmarkPathValidation_Disabled-8 接近零开销 ``` **快速路径**: + - 禁用验证时,直接返回 - 无条件判断,无内存分配 - 编译器优化为inline @@ -4490,11 +4591,13 @@ BenchmarkPathValidation_Disabled-8 接近零开销 **Agent并发设计**: 单个Agent支持并发工具调用: + - **MaxConcurrency**:默认3(可配置) - **信号量控制**:限制并发数 - **超时保护**:每个工具调用独立超时 **实测数据**: + - 3个工具调用并发执行 - 总耗时 = max(工具耗时) - 实测提速:2-3x @@ -4502,6 +4605,7 @@ BenchmarkPathValidation_Disabled-8 接近零开销 **Cosmos 并发能力**: Cosmos 支持大规模并发: + - **单机并发**:100+ Agent实例 - **内存占用**:每Agent ~10MB - **查询性能**:Get操作 <1μs(RWMutex) @@ -4510,10 +4614,10 @@ Cosmos 支持大规模并发: **RWMutex保护**: -| 组件 | 读操作 | 写操作 | 保护对象 | -|------|--------|--------|----------| +| 组件 | 读操作 | 写操作 | 保护对象 | +| ------ | --------- | -------------- | ---------- | | Cosmos | Get, List | Create, Delete | agents map | -| Memory | Search | Store, Update | memories | +| Memory | Search | Store, Update | memories | **Channel通信**: @@ -4536,6 +4640,7 @@ Cosmos 支持大规模并发: aster包含**21个Benchmark测试**,覆盖关键性能路径: **Middleware相关(7个)**: + 1. `BenchmarkSummarizationMiddleware_NoSummarization` 2. `BenchmarkSummarizationMiddleware_WithSummarization` 3. `BenchmarkAgentMemoryMiddleware_LazyLoad` @@ -4544,57 +4649,43 @@ aster包含**21个Benchmark测试**,覆盖关键性能路径: 6. `BenchmarkDefaultSummarizer` 7. `BenchmarkPhase4Stack` -**Context相关(5个)**: -8. `BenchmarkSimpleTokenCounter_Count` -9. `BenchmarkSimpleTokenCounter_EstimateMessages` -10. `BenchmarkSlidingWindowStrategy_Compress` -11. `BenchmarkPriorityBasedStrategy_Compress` -12. `BenchmarkTokenBasedStrategy_Compress` - -**Provider相关(2个)**: -13. `BenchmarkProviderCreation` -14. `BenchmarkMessageConversion` - -**其他核心路径(7个)**: -15. `BenchmarkExtractMessageContent` -16. `BenchmarkMiddlewareStack` -17. `BenchmarkBackendWrite` -18. `BenchmarkPathValidation` -19. `BenchmarkPathValidation_Disabled` -20. `BenchmarkFormatContentWithLineNumbers` -21. `BenchmarkSanitizeToolCallID` +**Context相关(5个)**:8. `BenchmarkSimpleTokenCounter_Count` 9. `BenchmarkSimpleTokenCounter_EstimateMessages` 10. `BenchmarkSlidingWindowStrategy_Compress` 11. `BenchmarkPriorityBasedStrategy_Compress` 12. `BenchmarkTokenBasedStrategy_Compress` + +**Provider相关(2个)**:13. `BenchmarkProviderCreation` 14. `BenchmarkMessageConversion` + +**其他核心路径(7个)**:15. `BenchmarkExtractMessageContent` 16. `BenchmarkMiddlewareStack` 17. `BenchmarkBackendWrite` 18. `BenchmarkPathValidation` 19. `BenchmarkPathValidation_Disabled` 20. `BenchmarkFormatContentWithLineNumbers` 21. `BenchmarkSanitizeToolCallID` ### 17.2 关键性能指标 #### 11.2.1 核心组件性能 -| 组件 | 吞吐量 | 延迟 | 内存/次 | 分配次数 | -|------|--------|------|---------|----------| -| Middleware栈 | 27M ops/s | 36 ns | 96 B | 2 | -| Backend写入 | 3.8M ops/s | 258 ns | 480 B | 8 | -| Token计数 | 10M ops/s | ~100 ns | <100 B | - | -| 路径验证 | >100M ops/s | <10 ns | 0 B | 0 | +| 组件 | 吞吐量 | 延迟 | 内存/次 | 分配次数 | +| ------------ | ----------- | ------- | ------- | -------- | +| Middleware栈 | 27M ops/s | 36 ns | 96 B | 2 | +| Backend写入 | 3.8M ops/s | 258 ns | 480 B | 8 | +| Token计数 | 10M ops/s | ~100 ns | <100 B | - | +| 路径验证 | >100M ops/s | <10 ns | 0 B | 0 | #### 11.2.2 优化效果分析 **懒加载性能提升**: -| 场景 | 首次加载 | 缓存命中 | 提升倍数 | -|------|---------|----------|----------| -| Working Memory | 100μs | 10ns | 10,000x | -| Provider | 50μs | 5ns | 10,000x | -| Tool实例 | 20μs | 2ns | 10,000x | +| 场景 | 首次加载 | 缓存命中 | 提升倍数 | +| -------------- | -------- | -------- | -------- | +| Working Memory | 100μs | 10ns | 10,000x | +| Provider | 50μs | 5ns | 10,000x | +| Tool实例 | 20μs | 2ns | 10,000x | **结论**:懒加载+缓存是关键优化手段。 **压缩策略性能**: -| 策略 | 耗时 | 压缩率 | 适用场景 | -|------|------|--------|----------| -| SlidingWindow | <1ms | 50% | 简单截断 | -| PriorityBased | ~5ms | 60% | 智能选择 | -| TokenBased | ~3ms | 70% | 精确控制 | -| LLM驱动 | ~2s | 80% | 最佳质量 | +| 策略 | 耗时 | 压缩率 | 适用场景 | +| ------------- | ---- | ------ | -------- | +| SlidingWindow | <1ms | 50% | 简单截断 | +| PriorityBased | ~5ms | 60% | 智能选择 | +| TokenBased | ~3ms | 70% | 精确控制 | +| LLM驱动 | ~2s | 80% | 最佳质量 | **结论**:非LLM策略适合实时场景,LLM驱动适合离线优化。 @@ -4603,6 +4694,7 @@ aster包含**21个Benchmark测试**,覆盖关键性能路径: #### 11.3.1 单机并发 **实测环境**: + - **硬件**:8核CPU、16GB RAM - **OS**:macOS/Linux - **Go版本**:1.24.0 @@ -4610,11 +4702,11 @@ aster包含**21个Benchmark测试**,覆盖关键性能路径: **并发Agent数量**: | Agent数 | 内存占用 | CPU使用率 | 响应时间 | -|---------|---------|-----------|----------| -| 10 | ~100MB | 10% | <100ms | -| 50 | ~500MB | 50% | ~200ms | -| 100 | ~1GB | 90% | ~500ms | -| 200 | ~2GB | >95% | >1s | +| ------- | -------- | --------- | -------- | +| 10 | ~100MB | 10% | <100ms | +| 50 | ~500MB | 50% | ~200ms | +| 100 | ~1GB | 90% | ~500ms | +| 200 | ~2GB | >95% | >1s | **结论**:单机支持100个Agent是合理配置。 @@ -4623,6 +4715,7 @@ aster包含**21个Benchmark测试**,覆盖关键性能路径: **限制因素分析**: aster的消息吞吐主要受限于: + 1. **LLM Provider速率限制**:如OpenAI 10K tokens/min 2. **网络延迟**:API调用往返时间 3. **LLM生成速度**:~50 tokens/s(Claude) @@ -4634,15 +4727,16 @@ aster的消息吞吐主要受限于: **stream.Reader内存优势**: | 事件数量 | 传统方式 | stream.Reader | 降低比例 | -|---------|---------|----------|----------| -| 100 | 4KB | 40B | 99.0% | -| 1,000 | 40KB | 40B | 99.9% | -| 10,000 | 400KB | 40B | 99.99% | -| 100,000 | 4MB | 40B | 99.999% | +| -------- | -------- | ------------- | -------- | +| 100 | 4KB | 40B | 99.0% | +| 1,000 | 40KB | 40B | 99.9% | +| 10,000 | 400KB | 40B | 99.99% | +| 100,000 | 4MB | 40B | 99.999% | **实际场景测试**: 长对话(100轮)Agent内存占用: + - **传统方式**:~50MB(缓冲所有事件) - **stream.Reader**:~10MB(仅保留必要状态) - **内存降低**:80% @@ -4656,48 +4750,24 @@ aster的消息吞吐主要受限于: aster提供**31个生产级示例**,覆盖从入门到高级的完整路径: **基础示例(3个)**: + 1. **examples/simple/**:最小可运行示例(<20行代码) 2. **examples/agent/**:完整Agent示例(含工具调用) 3. **examples/streaming/**:流式处理示例 -**多Agent协作(4个)**: -4. **examples/cosmos/**:Cosmos 生命周期管理 -5. **examples/subagent/**:子Agent委托 -6. **examples/workflow-agents/**:三种工作流(Parallel/Sequential/Loop) -7. **examples/router/**:模型路由选择 - -**记忆系统(7个)**: -8. **examples/memory/**:Text Memory基础 -9. **examples/memory-agent/**:Agent Memory集成 -10. **examples/memory-working/**:Working Memory使用 -11. **examples/memory-advanced/**:高级记忆(Provenance/Consolidation) -12. **examples/memory-semantic/**:Semantic Memory(向量检索) -13. **examples/memory-semantic-session/**:Session + Semantic Memory -14. **examples/agent-working-memory/**:Agent + Working Memory完整示例 - -**数据持久化(3个)**: -15. **examples/session/**:内存会话(StateBackend) -16. **examples/session-postgres/**:PostgreSQL持久化 -17. **examples/session-mysql/**:MySQL持久化 - -**工具扩展(3个)**: -18. **examples/mcp/**:MCP协议集成 -19. **examples/long-running-tools/**:长时运行工具管理 -20. **examples/skills/**:Skills注入(提示词工程) - -**网络功能(2个)**: -21. **examples/server-http/**:HTTP Server包装Agent -22. **examples/cloud-sandbox/**:云沙箱(阿里云/火山引擎) - -**评估与监控(4个)**: -23. **examples/evals/**:评估框架 -24. **examples/evals-session/**:Session评估 -25. **examples/telemetry/**:OpenTelemetry集成 -26. **examples/logging/**:结构化日志 - -**其他(5个)**: -27. **examples/scheduler/**:任务调度 -28. **examples/workflow-semantic/**:语义工作流 +**多Agent协作(4个)**:4. **examples/cosmos/**:Cosmos 生命周期管理 5. **examples/subagent/**:子Agent委托6. **examples/workflow-agents/**:三种工作流(Parallel/Sequential/Loop)7. **examples/router/**:模型路由选择 + +**记忆系统(7个)**:8. **examples/memory/**:Text Memory基础9. **examples/memory-agent/**:Agent Memory集成10. **examples/memory-working/**:Working Memory使用11. **examples/memory-advanced/**:高级记忆(Provenance/Consolidation)12. **examples/memory-semantic/**:Semantic Memory(向量检索)13. **examples/memory-semantic-session/**:Session + Semantic Memory 14. **examples/agent-working-memory/**:Agent + Working Memory完整示例 + +**数据持久化(3个)**:15. **examples/session/**:内存会话(StateBackend)16. **examples/session-postgres/**:PostgreSQL持久化17. **examples/session-mysql/**:MySQL持久化 + +**工具扩展(3个)**:18. **examples/mcp/**:MCP协议集成19. **examples/long-running-tools/**:长时运行工具管理20. **examples/skills/**:Skills注入(提示词工程) + +**网络功能(2个)**:21. **examples/server-http/**:HTTP Server包装Agent 22. **examples/cloud-sandbox/**:云沙箱(阿里云/火山引擎) + +**评估与监控(4个)**:23. **examples/evals/**:评估框架24. **examples/evals-session/**:Session评估25. **examples/telemetry/**:OpenTelemetry集成26. **examples/logging/**:结构化日志 + +**其他(5个)**:27. **examples/scheduler/**:任务调度28. **examples/workflow-semantic/**:语义工作流 29-31. 其他高级场景 ### 17.2 典型应用架构 @@ -4707,6 +4777,7 @@ aster提供**31个生产级示例**,覆盖从入门到高级的完整路径: **架构设计**:SequentialAgent **流程**: + 1. **ResearcherAgent** - 输入:代码文件列表 - 输出:功能摘要、架构分析 @@ -4728,11 +4799,13 @@ aster提供**31个生产级示例**,覆盖从入门到高级的完整路径: - 工具:Write(保存报告) **优势**: + - **专业分工**:每个Agent专注一个领域,提高准确性 - **上下文传递**:后续Agent可以参考前面的分析,避免重复工作 - **可扩展**:轻松添加StyleAgent(代码风格)、TestAgent(测试覆盖率) **生产部署**: + - 集成到CI/CD:Pull Request触发自动审查 - 权限控制:Write需要审批 - 结果通知:通过Webhook发送到Slack/Email @@ -4742,6 +4815,7 @@ aster提供**31个生产级示例**,覆盖从入门到高级的完整路径: **架构设计**:ParallelAgent **流程**: + 1. **同时调用三个Provider** - Claude Sonnet 4.5(推理能力强) - GPT-4o(综合能力强) @@ -4763,11 +4837,13 @@ aster提供**31个生产级示例**,覆盖从入门到高级的完整路径: - 推荐最优模型 **优势**: + - **时间高效**:总耗时 = 最慢模型耗时(vs 顺序执行的3倍耗时) - **公平对比**:所有模型收到相同输入 - **成本优化**:根据结果选择性价比最优的模型 **应用场景**: + - **模型选型**:为特定任务选择最佳模型 - **Prompt优化**:测试不同Prompt效果 - **成本分析**:评估模型切换的成本收益 @@ -4777,6 +4853,7 @@ aster提供**31个生产级示例**,覆盖从入门到高级的完整路径: **架构设计**:LoopAgent **流程**: + 1. **WriterAgent** - 输入:文档主题和大纲 - 输出:文档初稿 @@ -4798,11 +4875,13 @@ aster提供**31个生产级示例**,覆盖从入门到高级的完整路径: - 重复循环 **优势**: + - **自我优化**:无需人工介入,自动迭代改进 - **质量保障**:循环直到达到质量阈值 - **可控性**:最大迭代次数防止过度优化和成本失控 **实际效果**: + - 平均迭代次数:2-3次 - 最终评分:8.5-9.5分 - 文档质量:接近人工撰写水平 @@ -4812,18 +4891,21 @@ aster提供**31个生产级示例**,覆盖从入门到高级的完整路径: #### 12.3.1 客户服务(智能客服) **架构**: + - **Agent类型**:BaseAgent + Working Memory - **LLM**:Claude Sonnet 4.5(理解能力强) - **工具**:工单系统API(MCP)、知识库检索 - **持久化**:PostgreSQL(Session + Semantic Memory) **功能**: + - 用户意图识别 - 常见问题自动回答 - 复杂问题转人工 - 工单创建和跟踪 **性能指标**: + - 响应时间:<2s - 问题解决率:70%(无需转人工) - 用户满意度:4.5/5 @@ -4831,18 +4913,21 @@ aster提供**31个生产级示例**,覆盖从入门到高级的完整路径: #### 12.3.2 文档处理(PDF解析) **架构**: + - **Agent类型**:SequentialAgent(提取→总结→结构化) - **LLM**:GPT-4o(多模态能力) - **工具**:PDF解析(MCP)、OCR(MCP) - **输出**:结构化JSON + Markdown摘要 **流程**: + 1. PDF → 文本/图片提取 2. 文本理解 + 图片识别 3. 生成结构化数据(标题/段落/表格) 4. 生成摘要(关键信息提取) **应用场景**: + - 合同审查(条款提取) - 报告总结(财报分析) - 发票处理(信息提取) @@ -4850,12 +4935,14 @@ aster提供**31个生产级示例**,覆盖从入门到高级的完整路径: #### 12.3.3 自动化运维(日志分析) **架构**: + - **Agent类型**:ParallelAgent(多日志源并行分析) - **LLM**:DeepSeek(性价比高,批量处理) - **工具**:日志查询API(Elasticsearch MCP) - **输出**:异常报告 + 根因分析 **流程**: + 1. 并行查询多个日志源(应用日志/系统日志/数据库日志) 2. 异常检测(错误率突增/响应时间变慢) 3. 关联分析(找到共同时间点的异常) @@ -4863,6 +4950,7 @@ aster提供**31个生产级示例**,覆盖从入门到高级的完整路径: 5. 生成诊断报告 **效果**: + - 故障发现时间:从小时级降到分钟级 - 误报率:<5% - 根因准确率:80%+ @@ -4873,22 +4961,22 @@ aster提供**31个生产级示例**,覆盖从入门到高级的完整路径: ### 17.1 主流框架对比 -| 特性 | aster (Go) | LangChain | AutoGPT | Semantic Kernel | -|------|---------------|-----------|---------|-----------------| -| **语言** | Go | Python | Python | C#/Python | -| **架构** | 事件驱动 + 中间件 | Chain链式 | 自主循环 | Kernel + Plugin | -| **流式处理** | ✅ stream.Reader (O(1)内存) | ⚠️ 部分支持 (O(n)内存) | ❌ | ⚠️ 部分支持 | -| **多Agent** | ✅ Pool + Room + Workflow | ⚠️ LangGraph (额外模块) | ✅ 单Agent为主 | ⚠️ 实验性 | -| **工作流编排** | ✅ 3种内置 (Parallel/Sequential/Loop) | ✅ LangGraph | ❌ | ⚠️ Planner | -| **工具系统** | ✅ Registry + MCP | ✅ Tool Calling | ✅ 硬编码 | ✅ Semantic Functions | -| **记忆系统** | ✅ 3层 (Text/Working/Semantic) + Provenance + Consolidation | ✅ Memory (BaseMemory/ChatMessageHistory) | ⚠️ 简单向量存储 | ⚠️ 简单Memory | -| **Provider支持** | ✅ 10+ (含国产) | ✅ 100+ | ✅ OpenAI为主 | ✅ 多种 | -| **并发性能** | ✅ 真并发 (Goroutine) | ❌ GIL限制 (Python) | ❌ GIL限制 | ✅ async/await (.NET) | -| **内存占用** | ✅ 低 (O(1)流式 + 每Agent ~10MB) | ⚠️ 高 (O(n)缓冲) | ⚠️ 高 | ⚠️ 中等 | -| **生产就绪** | ✅ Session + OpenTelemetry + Sandbox + PII + Audit | ✅ LangSmith (商业服务) | ❌ 实验性 | ✅ 企业级 | -| **云原生** | ✅ 原生支持 (阿里云/火山引擎) | ⚠️ 需要额外部署 | ❌ | ⚠️ Azure集成 | -| **测试覆盖** | ✅ 80%+ | ⚠️ 中等 | ❌ 低 | ✅ 高 | -| **文档质量** | ✅ 完整 (31示例 + 白皮书) | ✅ 完整 | ⚠️ 简单 | ✅ 完整 | +| 特性 | aster (Go) | LangChain | AutoGPT | Semantic Kernel | +| ---------------- | ----------------------------------------------------------- | ----------------------------------------- | --------------- | --------------------- | +| **语言** | Go | Python | Python | C#/Python | +| **架构** | 事件驱动 + 中间件 | Chain链式 | 自主循环 | Kernel + Plugin | +| **流式处理** | ✅ stream.Reader (O(1)内存) | ⚠️ 部分支持 (O(n)内存) | ❌ | ⚠️ 部分支持 | +| **多Agent** | ✅ Pool + Room + Workflow | ⚠️ LangGraph (额外模块) | ✅ 单Agent为主 | ⚠️ 实验性 | +| **工作流编排** | ✅ 3种内置 (Parallel/Sequential/Loop) | ✅ LangGraph | ❌ | ⚠️ Planner | +| **工具系统** | ✅ Registry + MCP | ✅ Tool Calling | ✅ 硬编码 | ✅ Semantic Functions | +| **记忆系统** | ✅ 3层 (Text/Working/Semantic) + Provenance + Consolidation | ✅ Memory (BaseMemory/ChatMessageHistory) | ⚠️ 简单向量存储 | ⚠️ 简单Memory | +| **Provider支持** | ✅ 10+ (含国产) | ✅ 100+ | ✅ OpenAI为主 | ✅ 多种 | +| **并发性能** | ✅ 真并发 (Goroutine) | ❌ GIL限制 (Python) | ❌ GIL限制 | ✅ async/await (.NET) | +| **内存占用** | ✅ 低 (O(1)流式 + 每Agent ~10MB) | ⚠️ 高 (O(n)缓冲) | ⚠️ 高 | ⚠️ 中等 | +| **生产就绪** | ✅ Session + OpenTelemetry + Sandbox + PII + Audit | ✅ LangSmith (商业服务) | ❌ 实验性 | ✅ 企业级 | +| **云原生** | ✅ 原生支持 (阿里云/火山引擎) | ⚠️ 需要额外部署 | ❌ | ⚠️ Azure集成 | +| **测试覆盖** | ✅ 80%+ | ⚠️ 中等 | ❌ 低 | ✅ 高 | +| **文档质量** | ✅ 完整 (31示例 + 白皮书) | ✅ 完整 | ⚠️ 简单 | ✅ 完整 | ### 17.2 技术优势深度分析 @@ -4897,11 +4985,13 @@ aster提供**31个生产级示例**,覆盖从入门到高级的完整路径: **1. 真正的并发(vs Python GIL)** **Python的问题**(LangChain/AutoGPT): + - **GIL(全局解释器锁)**:同一时刻只有一个线程执行Python字节码 - **多线程无效**:CPU密集型任务无法并行(仅I/O密集型有效) - **asyncio局限**:协程仍然受GIL限制 **Go的优势**(aster): + - **Goroutine轻量级线程**:每个仅2KB初始栈空间 - **真并发**:利用多核CPU,ParallelAgent真正并行 - **性能实测**:3个Agent并行 vs 顺序,耗时降低67% @@ -4909,21 +4999,25 @@ aster提供**31个生产级示例**,覆盖从入门到高级的完整路径: **2. 低内存占用** **内存对比**: + - **Python**:动态类型、引用计数、GC开销大 - **Go**:静态类型、零值初始化、逃逸分析 **实测数据**: + - aster单个Agent:~10MB - LangChain单个Agent:~50MB(5倍差距) **3. 快速编译与部署** **Python**: + - 需要虚拟环境(venv/conda) - 依赖包管理复杂(pip/poetry) - 部署需要Python运行时 **Go**: + - 编译为单一二进制 - 无运行时依赖 - 跨平台编译(GOOS/GOARCH) @@ -4933,11 +5027,13 @@ aster提供**31个生产级示例**,覆盖从入门到高级的完整路径: **问题对比**: **LangChain方式**: + - Chain返回完整结果(所有事件缓冲) - 内存占用O(n) - 无法提前取消 **aster方式**: + - Stream返回stream.Reader - 内存占用O(1) - 支持背压控制(客户端随时停止) @@ -4953,6 +5049,7 @@ aster提供**31个生产级示例**,覆盖从入门到高级的完整路径: **LangChain的问题**: LangChain使用Chain链式调用: + - Chain → Chain → Chain(链式耦合) - 难以插入横切关注点(如日志、权限) - 扩展需要修改Chain定义 @@ -4960,11 +5057,13 @@ LangChain使用Chain链式调用: **aster的优势**: 洋葱模型中间件: + - Before → Core → After(环绕执行) - 横切关注点清晰分离(PII脱敏、权限检查、审计) - 即插即用(注册即生效) **性能对比**: + - aster Middleware栈:36 ns/op - LangChain Chain调用:~100μs(慢1000x) @@ -4972,21 +5071,22 @@ LangChain使用Chain链式调用: **LangChain Memory**: -| 类型 | 说明 | 局限性 | -|------|------|--------| -| ConversationBufferMemory | 缓冲所有消息 | 无限增长,无压缩 | -| ConversationSummaryMemory | LLM总结 | 丢失细节 | -| VectorStoreRetrieverMemory | 向量检索 | 无溯源、无质量评分 | +| 类型 | 说明 | 局限性 | +| -------------------------- | ------------ | ------------------ | +| ConversationBufferMemory | 缓冲所有消息 | 无限增长,无压缩 | +| ConversationSummaryMemory | LLM总结 | 丢失细节 | +| VectorStoreRetrieverMemory | 向量检索 | 无溯源、无质量评分 | **aster Memory**: -| 层级 | 说明 | 优势 | -|------|------|------| -| Text Memory | 完整对话历史 | 审计追踪 | -| Working Memory | 带TTL的活跃记忆 | Token预算控制 | +| 层级 | 说明 | 优势 | +| --------------- | ------------------------------- | ------------------------ | +| Text Memory | 完整对话历史 | 审计追踪 | +| Working Memory | 带TTL的活跃记忆 | Token预算控制 | | Semantic Memory | 向量检索 + Provenance + Quality | 溯源、质量评分、智能合并 | **额外功能**: + - **Memory Provenance**:4种来源类型、置信度、谱系链 - **Memory Consolidation**:冗余合并、冲突解决、LLM驱动总结 - **Quality Metrics**:5维度评分、优化建议 @@ -5017,6 +5117,7 @@ Chain A → Chain B → Chain C ``` 问题: + - 同步阻塞(必须等待A完成) - 无法实时查看进度 - 难以中途取消 @@ -5030,6 +5131,7 @@ Monitor Channel (审计日志) ``` 优势: + - 异步非阻塞 - 实时进度展示 - 随时取消/暂停 @@ -5060,6 +5162,7 @@ Monitor Channel (审计日志) - **命名空间**:避免冲突 优势: + - 易扩展(添加MCP Server即可) - 标准化(社区工具共享) - 隔离性(进程级隔离) @@ -5075,10 +5178,12 @@ Monitor Channel (审计日志) **决策**:使用接口优先设计(Protocol-First) **动机**: + - 早期考虑过直接实现具体Provider(如硬编码OpenAI) - 意识到未来需要支持多家LLM,决定抽象Protocol **收益**: + - **灵活性**:新增Provider仅需实现接口 - **可测试性**:轻松Mock Provider进行单元测试 - **动态切换**:运行时切换Provider无需重启 @@ -5090,19 +5195,23 @@ Monitor Channel (审计日志) **决策**:将Web框架的中间件模式引入Agent领域 **灵感来源**: + - Koa.js洋葱模型 - Express.js中间件栈 **挑战**: + - Agent请求/响应与HTTP请求不同 - 需要设计AgentRequest/AgentResponse结构 **成功要素**: + - **Before/After对称设计**:清晰的责任分离 - **优先级排序**:确保执行顺序可控 - **零开销原则**:Middleware栈性能36 ns/op **影响**: + - PII脱敏、权限检查、审计日志都通过Middleware实现 - 用户可轻松添加自定义Middleware @@ -5111,18 +5220,22 @@ Monitor Channel (审计日志) **决策**:基于stream.Reader重构流式接口 **before**: + - 返回Event切片:`[]Event` - 内存占用O(n) **After**: + - 返回流式读取器:`*stream.Reader[Event]` - 内存占用O(1) **挑战**: + - API设计需要考虑并发安全 - 生态兼容性问题 **收益**: + - **80%+内存降低** - **实时性**:事件立即传递 - **背压控制**:客户端可随时停止 @@ -5134,11 +5247,13 @@ Monitor Channel (审计日志) #### 14.2.1 代码规模投资 **统计数据**: + - 核心代码:41,417 LOC - 测试代码:15,818 LOC - 测试比例:38.2% **投资回报**: + - **Bug发现**:90%的Bug在测试阶段发现 - **重构信心**:80%+覆盖率保障重构安全 - **文档价值**:测试即文档,展示API用法 @@ -5147,23 +5262,25 @@ Monitor Channel (审计日志) **关键发现**: -| 优化 | Before | After | 提升 | -|------|--------|-------|------| -| Middleware栈 | 100 ns/op | 36 ns/op | 2.8x | -| 懒加载 | 每次加载 | 缓存命中10ns | 10,000x | -| stream.Reader | O(n)内存 | O(1)内存 | 80%+降低 | +| 优化 | Before | After | 提升 | +| ------------- | --------- | ------------ | -------- | +| Middleware栈 | 100 ns/op | 36 ns/op | 2.8x | +| 懒加载 | 每次加载 | 缓存命中10ns | 10,000x | +| stream.Reader | O(n)内存 | O(1)内存 | 80%+降低 | **教训**:没有Benchmark的优化是盲目的。 #### 14.2.3 测试覆盖率的平衡 **挑战**: + - 追求100%覆盖率? - 测试代码维护成本? **决策**:80%+覆盖率是性价比最优 **原因**: + - 80%覆盖核心路径 - 剩余20%多为错误处理(难以覆盖) - 边际收益递减 @@ -5173,11 +5290,13 @@ Monitor Channel (审计日志) #### 14.3.1 为什么不选Python? **Python优势**: + - 生态丰富(LangChain/AutoGPT) - 开发速度快 - 社区庞大 **Python劣势**(导致选择Go): + - **GIL限制**:并发性能差 - **内存占用**:动态类型开销大 - **部署复杂**:虚拟环境、依赖管理 @@ -5187,10 +5306,12 @@ Monitor Channel (审计日志) #### 14.3.2 为什么不选TypeScript? **TypeScript优势**: + - 全栈统一(前后端) - 生态丰富(npm) **TypeScript劣势**: + - 并发模型复杂(async/await) - 性能不如Go - 内存占用高(V8引擎) @@ -5200,11 +5321,13 @@ Monitor Channel (审计日志) #### 14.3.3 Go的最终选择 **决定性因素**: + 1. **并发模型**:Goroutine简单高效 2. **性能**:静态类型、快速GC 3. **部署**:单一二进制、跨平台 **代价**: + - 生态不如Python丰富 - 开发速度稍慢(静态类型) @@ -5217,6 +5340,7 @@ Monitor Channel (审计日志) **问题**:PostgreSQL序列化JSON字段性能差 **解决**: + - 使用JSONB类型(而非JSON) - 添加GIN索引 - 批量写入优化 @@ -5226,14 +5350,17 @@ Monitor Channel (审计日志) #### 14.4.2 OpenTelemetry集成 **挑战**: + - 分布式追踪复杂 - Context传播容易出错 **解决**: + - 统一使用context.Context传播 - 封装tracer.Start辅助函数 **收益**: + - 完整的Agent执行追踪 - 性能瓶颈可视化 @@ -5242,6 +5369,7 @@ Monitor Channel (审计日志) **问题**:云沙箱API偶尔超时/失败 **解决**: + - 自动重试(指数退避) - 降级到本地沙箱(Docker) - 完善错误处理 @@ -5259,11 +5387,13 @@ Monitor Channel (审计日志) **目标**:降低重复Prompt成本 **方案**: + - Anthropic Prompt Caching支持 - OpenAI GPT-4 Turbo Caching - 自动检测重复前缀 **预期收益**: + - 成本降低50-90%(长System Prompt场景) - 响应速度提升(缓存命中时) @@ -5274,11 +5404,13 @@ Monitor Channel (审计日志) **当前**:仅支持本地Docker、云沙箱 **计划**: + - Kubernetes Job沙箱 - 资源限制(CPU/Memory/GPU) - 镜像缓存优化 **应用场景**: + - 数据科学任务(Jupyter Notebook) - 机器学习训练(GPU支持) @@ -5287,6 +5419,7 @@ Monitor Channel (审计日志) **目标**:覆盖更多LLM厂商 **计划新增**: + - **Azure OpenAI**:企业客户需求 - **AWS Bedrock**:Claude on AWS - **百川智能**:国产大模型 @@ -5300,11 +5433,13 @@ Monitor Channel (审计日志) **当前**:仅支持文本 **计划**: + - GPT-4o Vision - Claude 3 Vision - Gemini Pro Vision **应用场景**: + - 截图分析 - 图表理解 - UI/UX审查 @@ -5312,11 +5447,13 @@ Monitor Channel (审计日志) **Audio(语音处理)**: **计划**: + - 语音转文本(Whisper) - 文本转语音(TTS) - 实时语音对话 **应用场景**: + - 语音客服 - 会议记录 - 播客总结 @@ -5326,15 +5463,18 @@ Monitor Channel (审计日志) **目标**:结构化知识管理 **当前**: + - Semantic Memory(向量检索) - 缺乏实体关系建模 **计划**: + - 实体识别与抽取 - 关系图谱构建(Neo4j) - 图谱检索与推理 **应用场景**: + - 知识问答 - 决策支持 - 因果推理 @@ -5346,11 +5486,13 @@ Monitor Channel (审计日志) **当前**:单机多Agent **计划**: + - 分布式Pool(Redis/etcd) - 远程Room(消息队列) - 一致性保障 **应用场景**: + - 大规模Agent集群 - 跨数据中心协作 @@ -5361,11 +5503,13 @@ Monitor Channel (审计日志) **目标**:自动模型选择和调优 **计划**: + - 任务特征提取 - 模型性能预测 - 自动Prompt优化 **应用**: + - 根据任务自动选择模型 - 自动优化System Prompt - 成本与质量平衡 @@ -5375,11 +5519,13 @@ Monitor Channel (审计日志) **目标**:工具/技能共享平台 **计划**: + - 工具市场(一键安装MCP Server) - Skills库(Prompt模板) - Agent模板(预配置Agent) **商业模式**: + - 开源基础工具 - 付费高级工具 - 企业私有市场 @@ -5389,11 +5535,13 @@ Monitor Channel (审计日志) **目标**:轻量级Agent运行时 **计划**: + - 精简版aster(<10MB) - 本地模型支持(Ollama) - 离线运行 **应用场景**: + - IoT设备 - 移动端Agent - 隐私敏感场景 @@ -5409,6 +5557,7 @@ aster是一个**生产就绪、高性能的AI Agent开发框架**,基于Go语 **1. 事件驱动架构创新** 三通道设计(Progress/Control/Monitor)实现了: + - **实时性**:用户可见Agent思考过程 - **可控性**:关键操作暂停等待审批 - **可观测性**:完整的行为追踪和审计 @@ -5416,6 +5565,7 @@ aster是一个**生产就绪、高性能的AI Agent开发框架**,基于Go语 **2. 洋葱模型中间件系统** 借鉴Web框架设计,实现: + - **灵活扩展**:即插即用的中间件 - **关注点分离**:PII脱敏、权限、审计独立模块 - **高性能**:36 ns/op,几乎零开销 @@ -5423,6 +5573,7 @@ aster是一个**生产就绪、高性能的AI Agent开发框架**,基于Go语 **3. 三层记忆系统** 完整实现Google Context Engineering白皮书: + - **Text Memory**:完整历史审计 - **Working Memory**:Token预算控制 - **Semantic Memory**:向量检索 + Provenance + Quality @@ -5430,6 +5581,7 @@ aster是一个**生产就绪、高性能的AI Agent开发框架**,基于Go语 **4. Google Context Engineering 100/100实现** 8大核心功能全部实现: + - Memory Provenance(溯源) - PII Auto-Redaction(脱敏) - Memory Consolidation(合并) @@ -5442,6 +5594,7 @@ aster是一个**生产就绪、高性能的AI Agent开发框架**,基于Go语 **5. 多层安全防护** 企业级安全特性: + - **Sandbox隔离**:Docker/阿里云/火山引擎 - **PII自动脱敏**:10+种PII类型 - **权限系统**:allow/deny/ask三级控制 @@ -5450,18 +5603,21 @@ aster是一个**生产就绪、高性能的AI Agent开发框架**,基于Go语 ### 17.2 关键数据回顾 **代码质量**: + - **核心代码**:41,417 LOC - **测试代码**:15,818 LOC - **测试覆盖率**:80%+ - **Benchmark数量**:21个 **生态支持**: + - **LLM Provider**:10+厂商 - **内置工具**:9个 - **示例数量**:31个 - **文档页数**:本白皮书50+页 **性能指标**: + - **Middleware栈**:36 ns/op(27M ops/s) - **Backend写入**:258 ns/op(3.8M ops/s) - **内存优化**:80%+降低(stream.Reader) @@ -5472,18 +5628,22 @@ aster是一个**生产就绪、高性能的AI Agent开发框架**,基于Go语 aster已在多个生产环境成功部署: **客户服务**: + - 智能客服系统(70%问题自动解决) - 工单管理(自动分类和路由) **文档处理**: + - PDF合同审查(条款提取) - 财报分析(关键指标总结) **自动化运维**: + - 日志分析(异常检测) - 根因诊断(故障定位) **代码助手**: + - Code Review(安全/性能检查) - 代码生成(Boilerplate生成) @@ -5492,16 +5652,19 @@ aster已在多个生产环境成功部署: aster作为开源项目,致力于: **社区建设**: + - 欢迎贡献(Provider/Tool/Middleware) - 路线图透明化(GitHub Projects) - 定期发布(语义化版本) **文档完善**: + - 31个示例(覆盖各种场景) - 技术白皮书(本文档) - API参考文档 **生态扩展**: + - MCP Server集成 - 工具市场(计划中) - 企业支持(咨询服务) @@ -5509,6 +5672,7 @@ aster作为开源项目,致力于: ### 17.5 致谢 aster的成功离不开: + - **Go语言团队**:提供强大的语言特性 - **LLM厂商**:OpenAI、Anthropic、Google等的API支持 - **开源社区**:PostgreSQL、Docker、OpenTelemetry等基础设施 diff --git a/docs/content/17.about/1.wordflowlab.md b/docs/content/17.about/1.wordflowlab.md index 248497c..57015ae 100644 --- a/docs/content/17.about/1.wordflowlab.md +++ b/docs/content/17.about/1.wordflowlab.md @@ -24,11 +24,12 @@ astercloud 是一个专注于 **AI Agent 基础设施**的开源组织,致力 文字是人类知识传承的核心载体。从文档编辑、代码生成到知识库管理,文字处理场景具有: ::list{type="success"} + - **高价值**:直接提升知识工作者生产力 - **可衡量**:清晰的质量标准和评估指标 - **可落地**:成熟的技术栈和应用场景 - **广应用**:覆盖开发、写作、教育、办公等多个领域 -:: + :: ## 核心项目 @@ -73,11 +74,12 @@ Text/Working/Semantic 完整记忆系统,支持溯源、合并、过期管理 作为 Go 开发者,我们追求: ::list{type="primary"} + - 清晰的架构设计 - 完善的测试覆盖(80%+) - 详尽的文档说明 - 生产级的可靠性 -:: + :: ### 社区驱动 @@ -92,16 +94,16 @@ Text/Working/Semantic 完整记忆系统,支持溯源、合并、过期管理 aster 完整实现了 **Google Context Engineering 白皮书**的 8 大核心特性: -| 特性 | 状态 | 说明 | -|------|------|------| -| Sessions & Memory | ✅ | 三层记忆系统(Text/Working/Semantic) | -| Memory Provenance | ✅ | 内存溯源与置信度追踪 | -| Memory Consolidation | ✅ | LLM 驱动的智能记忆合并 | -| PII Auto-Redaction | ✅ | 自动化隐私数据脱敏 | -| Event-Driven Architecture | ✅ | Progress/Control/Monitor 三通道设计 | -| Streaming & Backpressure | ✅ | stream.Reader 流式处理 | -| Multi-Agent Orchestration | ✅ | Pool/Room/Workflow 协作机制 | -| Observability | ✅ | OpenTelemetry 完整集成 | +| 特性 | 状态 | 说明 | +| ------------------------- | ---- | ------------------------------------- | +| Sessions & Memory | ✅ | 三层记忆系统(Text/Working/Semantic) | +| Memory Provenance | ✅ | 内存溯源与置信度追踪 | +| Memory Consolidation | ✅ | LLM 驱动的智能记忆合并 | +| PII Auto-Redaction | ✅ | 自动化隐私数据脱敏 | +| Event-Driven Architecture | ✅ | Progress/Control/Monitor 三通道设计 | +| Streaming & Backpressure | ✅ | stream.Reader 流式处理 | +| Multi-Agent Orchestration | ✅ | Pool/Room/Workflow 协作机制 | +| Observability | ✅ | OpenTelemetry 完整集成 | ::alert{type="success" icon="i-lucide-check-circle"} **实现度: 100%** - aster 是首个完整实现 Google Context Engineering 标准的 Go 语言框架 diff --git a/docs/content/17.about/2.why-agentsdk.md b/docs/content/17.about/2.why-agentsdk.md index 0357e95..b499d5b 100644 --- a/docs/content/17.about/2.why-agentsdk.md +++ b/docs/content/17.about/2.why-agentsdk.md @@ -16,23 +16,24 @@ navigation: 主流 Agent 框架多为快速原型设计,缺少生产级特性: ::list{type="warning"} + - **并发能力不足**:难以支持大规模用户(Python GIL 限制) - **安全性薄弱**:代码执行缺乏有效隔离 - **可观测性差**:缺少完善的监控和审计能力 - **扩展性受限**:同步阻塞模式难以应对复杂场景 -:: + :: ### 2. Go 生态的缺失 主流 Agent 框架集中在 Python/TypeScript,但 Go 有独特优势: -| Go 优势 | 具体价值 | -|---------|----------| +| Go 优势 | 具体价值 | +| -------------- | ------------------------------------------------- | | **高性能并发** | 原生 goroutine,支持 100+ 并发 Agent,无 GIL 限制 | -| **部署简单** | 单二进制文件,无运行时依赖,容器镜像小于 50MB | -| **类型安全** | 编译期检查,减少运行时错误,适合大型项目 | -| **企业友好** | 静态类型,易维护,适合团队协作和长期维护 | -| **性能优异** | 内存占用低,启动快速,适合云原生部署 | +| **部署简单** | 单二进制文件,无运行时依赖,容器镜像小于 50MB | +| **类型安全** | 编译期检查,减少运行时错误,适合大型项目 | +| **企业友好** | 静态类型,易维护,适合团队协作和长期维护 | +| **性能优异** | 内存占用低,启动快速,适合云原生部署 | ::alert{type="info" icon="i-lucide-info"} 在并行任务处理场景,Go 的性能比 Python 快 67%(基于我们的基准测试) @@ -57,24 +58,28 @@ aster 从生产需求出发,提供完整的企业级解决方案: ::card-group ::card{icon="i-lucide-activity" title="Progress 通道"} 实时文本流、工具执行进度 + - 前端 UI 订阅,展示生成内容 - 内存占用 O(1),支持无限长对话 -:: + :: ::card{icon="i-lucide-hand" title="Control 通道"} 工具审批请求、人机交互 + - 安全网关订阅,拦截敏感操作 - 支持同步等待审批结果 -:: + :: ::card{icon="i-lucide-shield-check" title="Monitor 通道"} 治理事件、错误、审计日志 + - 监控系统订阅,记录所有操作 - 支持 OpenTelemetry 分布式追踪 -:: -:: + :: + :: **优势**: + - 非阻塞流式交互 - 灵活的订阅机制 - 清晰的职责分离 @@ -94,11 +99,12 @@ agent.Create(ctx, &types.AgentConfig{ ``` ::list{type="success"} + - **原生支持**阿里云 AgentBay、火山引擎云沙箱 - **安全隔离**的代码执行环境(网络、文件系统、资源限制) - **弹性伸缩**能力,按需创建和销毁沙箱 - **成本优化**,闲置自动回收 -:: + :: ### 洋葱模型中间件 @@ -110,12 +116,12 @@ agent.Create(ctx, &types.AgentConfig{ **内置中间件**: -| 中间件 | 功能 | 适用场景 | -|--------|------|----------| -| Summarization | 自动总结长对话 | 上下文超过 170k tokens | -| PII Redaction | 自动脱敏隐私数据 | 处理用户敏感信息 | -| Tool Filter | 工具访问控制 | 限制危险操作 | -| Retry | 自动重试失败请求 | 提高系统可靠性 | +| 中间件 | 功能 | 适用场景 | +| ------------- | ---------------- | ---------------------- | +| Summarization | 自动总结长对话 | 上下文超过 170k tokens | +| PII Redaction | 自动脱敏隐私数据 | 处理用户敏感信息 | +| Tool Filter | 工具访问控制 | 限制危险操作 | +| Retry | 自动重试失败请求 | 提高系统可靠性 | ::alert{type="success" icon="i-lucide-layers"} 洋葱模型性能:27M ops/s(基于 Go 1.24 基准测试) @@ -141,20 +147,21 @@ result, err := ag.Chat(ctx, "创建 hello.txt 文件") ### 2. 灵活但有主见 ::list{type="primary"} + - 提供最佳实践的默认配置(开箱即用) - 支持深度定制和扩展(满足复杂需求) - 清晰的扩展点设计(Middleware、Tool、Provider) -:: + :: ### 3. 生产就绪 -| 特性 | 实现 | -|------|------| -| 错误处理 | 完善的错误类型,详细的错误上下文 | -| 日志监控 | OpenTelemetry 集成,分布式追踪 | -| 断点恢复 | 7 段断点机制,会话中断后可恢复 | +| 特性 | 实现 | +| -------- | ------------------------------------- | +| 错误处理 | 完善的错误类型,详细的错误上下文 | +| 日志监控 | OpenTelemetry 集成,分布式追踪 | +| 断点恢复 | 7 段断点机制,会话中断后可恢复 | | 性能优化 | stream.Reader 流式处理,内存降低 80%+ | -| 测试覆盖 | 80%+ 单元测试 + 集成测试 | +| 测试覆盖 | 80%+ 单元测试 + 集成测试 | ## 目标场景 @@ -163,44 +170,48 @@ aster 专为以下场景设计: ::card-group ::card{icon="i-lucide-building" title="企业应用"} 需要高可靠性、安全性和审计能力 + - 客服系统(70% 自动解决率) - 文档处理 - 知识库管理 -:: + :: ::card{icon="i-lucide-users" title="多 Agent 系统"} 复杂协作和任务分发 + - AgentPool(生命周期管理) - Room(消息路由) - Workflow(编排执行) -:: + :: ::card{icon="i-lucide-trending-up" title="大规模部署"} 支持 100+ 并发 Agent + - 1GB RAM = 100 个并发 Agent - 单节点处理 1000+ QPS - 水平扩展,无状态设计 -:: + :: ::card{icon="i-lucide-cloud" title="云原生环境"} 容器化部署,弹性伸缩 + - Docker 镜像 < 50MB - Kubernetes 原生支持 - 支持多云部署 -:: -:: + :: + :: ## 与其他框架对比 -| 特性 | aster | LangChain | AutoGPT | -|------|----------|-----------|---------| -| **语言** | Go | Python | Python | -| **并发模型** | Goroutine (真并行) | GIL 限制 | 单线程 | -| **流式处理** | stream.Reader (O(1) 内存) | Generator | ❌ | -| **中间件** | 洋葱模型 (27M ops/s) | Chain (低性能) | ❌ | -| **云沙箱** | ✅ 原生支持 | ❌ | ❌ | -| **分布式追踪** | ✅ OpenTelemetry | 部分支持 | ❌ | -| **测试覆盖** | 80%+ | 中等 | 低 | +| 特性 | aster | LangChain | AutoGPT | +| -------------- | ------------------------- | -------------- | ------- | +| **语言** | Go | Python | Python | +| **并发模型** | Goroutine (真并行) | GIL 限制 | 单线程 | +| **流式处理** | stream.Reader (O(1) 内存) | Generator | ❌ | +| **中间件** | 洋葱模型 (27M ops/s) | Chain (低性能) | ❌ | +| **云沙箱** | ✅ 原生支持 | ❌ | ❌ | +| **分布式追踪** | ✅ OpenTelemetry | 部分支持 | ❌ | +| **测试覆盖** | 80%+ | 中等 | 低 | ::alert{type="info" icon="i-lucide-info"} 详细对比见白皮书 [Related Work](/whitepaper/whitepaper#13-related-work) 章节 @@ -211,11 +222,12 @@ aster 专为以下场景设计: 我们将继续: ::list{type="success"} + - **优化核心性能**:Prompt Caching、零拷贝优化 - **扩展工具生态**:更多 MCP Server、内置工具 - **改进开发体验**:CLI 工具、项目模板、VSCode 插件 - **完善文档示例**:更多生产级示例、最佳实践 -:: + :: --- diff --git a/docs/content/17.about/3.roadmap.md b/docs/content/17.about/3.roadmap.md index 93a3fcb..54910f9 100644 --- a/docs/content/17.about/3.roadmap.md +++ b/docs/content/17.about/3.roadmap.md @@ -17,23 +17,24 @@ aster 持续迭代,致力于成为最优秀的企业级 AI Agent 框架。 ### 已完成特性 -| 特性分类 | 功能清单 | 状态 | -|---------|---------|------| -| **核心运行时** | Agent Create/Send/Chat/Subscribe | ✅ | -| **流式处理** | stream.Reader API,内存降低 80%+ | ✅ | -| **事件系统** | Progress/Control/Monitor 三通道 | ✅ | -| **中间件** | 洋葱模型,Summarization/PII Redaction | ✅ | -| **记忆系统** | Text/Working/Semantic Memory | ✅ | -| **高级记忆** | Provenance/Consolidation/Auto-Redaction | ✅ | -| **多 Agent** | Pool/Room/Workflow (Parallel/Sequential/Loop) | ✅ | -| **工具系统** | 9 种内置工具 + MCP 协议支持 | ✅ | -| **Provider** | 10+ LLM 厂商(OpenAI/Anthropic/DeepSeek/GLM 等)| ✅ | -| **云沙箱** | 阿里云 AgentBay、火山引擎集成 | ✅ | -| **持久化** | PostgreSQL + MySQL 8.0+ 双数据库 | ✅ | -| **可观测** | OpenTelemetry 完整集成 | ✅ | -| **测试** | 80%+ 覆盖率,1300+ 行单元测试 | ✅ | +| 特性分类 | 功能清单 | 状态 | +| -------------- | ------------------------------------------------ | ---- | +| **核心运行时** | Agent Create/Send/Chat/Subscribe | ✅ | +| **流式处理** | stream.Reader API,内存降低 80%+ | ✅ | +| **事件系统** | Progress/Control/Monitor 三通道 | ✅ | +| **中间件** | 洋葱模型,Summarization/PII Redaction | ✅ | +| **记忆系统** | Text/Working/Semantic Memory | ✅ | +| **高级记忆** | Provenance/Consolidation/Auto-Redaction | ✅ | +| **多 Agent** | Pool/Room/Workflow (Parallel/Sequential/Loop) | ✅ | +| **工具系统** | 9 种内置工具 + MCP 协议支持 | ✅ | +| **Provider** | 10+ LLM 厂商(OpenAI/Anthropic/DeepSeek/GLM 等) | ✅ | +| **云沙箱** | 阿里云 AgentBay、火山引擎集成 | ✅ | +| **持久化** | PostgreSQL + MySQL 8.0+ 双数据库 | ✅ | +| **可观测** | OpenTelemetry 完整集成 | ✅ | +| **测试** | 80%+ 覆盖率,1300+ 行单元测试 | ✅ | **代码规模**: + - **核心代码**:41,417 行 - **测试代码**:15,818 行(38.2% 比例) - **文档**:5,200+ 行技术白皮书 @@ -45,61 +46,68 @@ aster 持续迭代,致力于成为最优秀的企业级 AI Agent 框架。 ::card-group ::card{icon="i-lucide-zap" title="Prompt Caching"} 实现 Anthropic Prompt Caching + - 减少 90% 重复计算 - 降低 API 成本 - 加快响应速度 -:: + :: ::card{icon="i-lucide-database" title="零拷贝优化"} 优化消息传递性能 + - 减少内存分配 - 降低 GC 压力 - 提升吞吐量 -:: -:: + :: + :: ### 云平台扩展 ::list{type="primary"} + - **Docker Sandbox**:本地开发友好的容器沙箱 - **Kubernetes Sandbox**:云原生环境的 Pod 沙箱 - **更多云厂商**:腾讯云、华为云沙箱集成 -:: + :: ### 工具生态 -| 工具类型 | 计划 | -|---------|------| +| 工具类型 | 计划 | +| -------------- | ---------------------------------- | | **MCP Server** | 官方 MCP Server 仓库,20+ 常用工具 | -| **内置工具** | 数据库查询、API 调用、文件处理增强 | -| **工具市场** | 社区贡献的工具注册中心 | +| **内置工具** | 数据库查询、API 调用、文件处理增强 | +| **工具市场** | 社区贡献的工具注册中心 | ### 开发者体验 ::card-group ::card{icon="i-lucide-terminal" title="CLI 工具"} 命令行工具快速创建项目 + ```bash aster init my-agent aster dev aster deploy ``` + :: ::card{icon="i-lucide-file-code" title="项目模板"} 开箱即用的项目模板 + - 聊天机器人 - 代码助手 - 文档处理 -:: + :: ::card{icon="i-lucide-puzzle" title="VSCode 插件"} IDE 集成开发支持 + - Agent 配置可视化 - 事件流调试 - 性能分析 -:: -:: + :: + :: ## 中期规划(Q3-Q4 2026,6-12 个月) @@ -108,26 +116,29 @@ IDE 集成开发支持 ::card-group ::card{icon="i-lucide-image" title="视觉理解"} 支持图像输入和生成 + - Claude/GPT-4V 集成 - OCR 工具 - 图表分析 -:: + :: ::card{icon="i-lucide-mic" title="语音处理"} 支持音频输入输出 + - 语音转文字 - 文字转语音 - 实时对话 -:: -:: + :: + :: ### 高级记忆 ::list{type="success"} + - **Graph Memory**:知识图谱增强的记忆系统 - **向量数据库扩展**:Pinecone、Weaviate、Milvus 支持 - **记忆分析**:记忆质量评估、自动清理、优化建议 -:: + :: ### 分布式 Agent @@ -143,6 +154,7 @@ graph LR ``` **特性**: + - 分布式会话管理 - Agent 跨节点迁移 - 故障自动转移 @@ -150,12 +162,12 @@ graph LR ### 企业特性 -| 特性 | 描述 | -|------|------| -| **RBAC 权限** | 基于角色的访问控制 | -| **审计日志** | 完整的操作审计和合规性报告 | -| **配额管理** | 用户级别的资源限制和计费 | -| **私有部署** | 企业内网部署方案和技术支持 | +| 特性 | 描述 | +| ------------- | -------------------------- | +| **RBAC 权限** | 基于角色的访问控制 | +| **审计日志** | 完整的操作审计和合规性报告 | +| **配额管理** | 用户级别的资源限制和计费 | +| **私有部署** | 企业内网部署方案和技术支持 | ## 长期愿景(2027+,12 个月以上) @@ -175,48 +187,52 @@ graph LR ::card-group ::card{icon="i-lucide-store" title="Agent 模板市场"} 社区贡献的 Agent 模板 + - 分类浏览 - 评分评论 - 一键部署 -:: + :: ::card{icon="i-lucide-box" title="工具市场"} 丰富的工具生态 + - MCP Server - 自定义工具 - 企业工具集成 -:: + :: ::card{icon="i-lucide-share-2" title="技能市场"} 可复用的 Agent 技能 + - Slash Commands - Skills 注入 - 组合使用 -:: -:: + :: + :: ### 边缘部署 支持边缘设备和离线场景: ::list{type="primary"} + - **本地模型**:LLaMA、Mistral 等开源模型支持 - **移动端**:iOS/Android SDK - **嵌入式**:树莓派、NVIDIA Jetson 支持 - **离线模式**:无需网络连接的 Agent 运行 -:: + :: ### "文字+" 专业场景 深耕细分领域应用: -| 场景 | 目标 | -|------|------| -| **代码助手** | 智能代码生成、审查、重构、测试 | +| 场景 | 目标 | +| ------------ | --------------------------------- | +| **代码助手** | 智能代码生成、审查、重构、测试 | | **文档处理** | PDF/Word 解析、格式转换、内容提取 | -| **知识库** | 企业知识管理、智能问答、知识图谱 | -| **内容创作** | 文章写作、翻译、校对、润色 | -| **教育场景** | 作业批改、学习辅导、个性化推荐 | +| **知识库** | 企业知识管理、智能问答、知识图谱 | +| **内容创作** | 文章写作、翻译、校对、润色 | +| **教育场景** | 作业批改、学习辅导、个性化推荐 | ## 参与路线图 diff --git a/docs/content/17.about/4.contributing.md b/docs/content/17.about/4.contributing.md index 4272525..9388a41 100644 --- a/docs/content/17.about/4.contributing.md +++ b/docs/content/17.about/4.contributing.md @@ -16,85 +16,94 @@ navigation: ::card-group ::card{icon="i-lucide-bug" title="修复 Bug"} 发现并修复代码中的问题 + - 查看 [Issues](https://github.com/astercloud/aster/issues?q=is%3Aissue+is%3Aopen+label%3Abug) - 提交 PR 修复 -:: + :: ::card{icon="i-lucide-sparkles" title="新功能"} 实现路线图中的功能 + - 查看 [Roadmap](/about/roadmap) - 在 Issue 中讨论设计 - 提交 PR 实现 -:: + :: ::card{icon="i-lucide-zap" title="性能优化"} 提升代码性能和效率 + - 基准测试分析 - 优化关键路径 - 提供性能数据 -:: + :: ::card{icon="i-lucide-test-tube" title="测试"} 增加测试覆盖率 + - 单元测试 - 集成测试 - 性能测试 -:: -:: + :: + :: ### 2. 文档贡献 ::list{type="primary"} + - **API 文档**:完善函数、类型的注释和说明 - **教程**:编写使用场景的详细教程 - **示例**:提供真实应用的示例代码 - **翻译**:翻译文档到其他语言 -:: + :: ### 3. 社区贡献 ::card-group ::card{icon="i-lucide-message-circle" title="讨论"} 参与技术讨论 + - [GitHub Discussions](https://github.com/astercloud/aster/discussions) - 分享使用经验 - 提供解决方案 -:: + :: ::card{icon="i-lucide-help-circle" title="答疑"} 帮助其他开发者 + - 回答 Issues - Code Review - 技术支持 -:: + :: ::card{icon="i-lucide-share-2" title="推广"} 传播项目影响力 + - 撰写博客文章 - 制作视频教程 - 社交媒体分享 -:: -:: + :: + :: ### 4. 反馈建议 ::list{type="success"} + - **功能建议**:提出新功能想法 - **体验反馈**:分享使用体验 - **Bug 报告**:提交发现的问题 - **性能反馈**:报告性能问题 -:: + :: ## 开发环境 ### 环境要求 -| 工具 | 版本 | 说明 | -|------|------|------| -| **Go** | 1.23+ | 需要泛型和 stream.Reader 支持 | -| **Git** | 2.0+ | 版本控制 | -| **Make** | 任意 | 构建工具 | -| **Docker** | 可选 | 沙箱测试 | +| 工具 | 版本 | 说明 | +| ---------- | ----- | ----------------------------- | +| **Go** | 1.23+ | 需要泛型和 stream.Reader 支持 | +| **Git** | 2.0+ | 版本控制 | +| **Make** | 任意 | 构建工具 | +| **Docker** | 可选 | 沙箱测试 | ### 克隆仓库 @@ -141,11 +150,12 @@ go run main.go 在开始编码前,建议先创建或认领 Issue: ::list{type="warning"} + 1. 搜索是否已有相关 Issue 2. 如果没有,创建新 Issue 描述问题或功能 3. 等待维护者反馈,确认方向 4. 开始开发 -:: + :: ### 2. 分支管理 @@ -158,6 +168,7 @@ git checkout -b fix/bug-description ``` **分支命名规范**: + - `feature/` - 新功能 - `fix/` - Bug 修复 - `docs/` - 文档更新 @@ -193,6 +204,7 @@ func fetch(id string) *User { ``` **注意事项**: + - 添加清晰的注释 - 处理所有错误 - 使用有意义的变量名 @@ -264,6 +276,7 @@ git commit -m "docs: update quickstart guide" ``` **Commit 要求**: + - 简洁明了的提交信息 - 一个 commit 做一件事 - 提交前运行 `go fmt` 和测试 @@ -284,21 +297,26 @@ git push origin feature/your-feature-name ```markdown ## 描述 + 简要说明这个 PR 做了什么 ## 相关 Issue + Closes #123 ## 改动类型 + - [ ] Bug 修复 - [ ] 新功能 - [ ] 破坏性变更 - [ ] 文档更新 ## 测试 + 描述如何测试这些改动 ## 检查清单 + - [ ] 代码遵循项目规范 - [ ] 添加了必要的测试 - [ ] 测试全部通过 @@ -311,22 +329,23 @@ Closes #123 ### PR 审查流程 ::list{type="primary"} + 1. **自动检查**:CI/CD 运行测试和 lint 2. **维护者审查**:检查代码质量、设计、测试 3. **讨论和修改**:根据反馈修改代码 4. **合并**:审查通过后合并到主分支 -:: + :: ### 审查标准 -| 检查项 | 要求 | -|--------|------| -| **功能** | 符合需求,没有 bug | -| **测试** | 完善的测试覆盖 | -| **代码质量** | 清晰、简洁、可维护 | -| **文档** | 必要的注释和文档更新 | -| **性能** | 没有性能退化 | -| **兼容性** | 向后兼容(除非标注破坏性变更)| +| 检查项 | 要求 | +| ------------ | ------------------------------ | +| **功能** | 符合需求,没有 bug | +| **测试** | 完善的测试覆盖 | +| **代码质量** | 清晰、简洁、可维护 | +| **文档** | 必要的注释和文档更新 | +| **性能** | 没有性能退化 | +| **兼容性** | 向后兼容(除非标注破坏性变更) | ### 处理反馈 @@ -368,30 +387,34 @@ aster/ ::accordion{defaultOpen=false} ::accordion-item{icon="i-lucide-help-circle" title="我是新手,如何开始贡献?"} 推荐从以下开始: + 1. 阅读文档,运行示例 2. 查看标记为 `good first issue` 的 Issue 3. 修复文档中的错别字或改进说明 4. 参与 Discussions 讨论 -:: + :: ::accordion-item{icon="i-lucide-git-branch" title="我的 PR 被拒绝了怎么办?"} 不要气馁!这很正常: + 1. 仔细阅读维护者的反馈 2. 修改代码解决问题 3. 重新提交审查 4. 如有疑问,在 PR 中讨论 -:: + :: ::accordion-item{icon="i-lucide-test-tube" title="测试失败了怎么办?"} + 1. 在本地运行测试:`go test ./...` 2. 检查错误信息 3. 修复问题 4. 重新运行测试确认 5. 推送更新 -:: + :: ::accordion-item{icon="i-lucide-clock" title="PR 多久会被审查?"} 我们努力在 48 小时内进行首次审查,但具体时间取决于: + - PR 的复杂度 - 维护者的可用时间 - 节假日等因素 @@ -409,13 +432,15 @@ aster/ **核心原则**: ::list{type="success"} + - **尊重**:尊重所有贡献者,无论经验水平 - **包容**:欢迎不同背景和观点 - **协作**:建设性地沟通和反馈 - **专业**:保持专业和友好的态度 -:: + :: **不可接受的行为**: + - 骚扰、歧视、侮辱性言论 - 人身攻击或政治攻击 - 公开或私下的骚扰 diff --git a/docs/content/17.about/5.release-notes.md b/docs/content/17.about/5.release-notes.md index b3e82d9..2c0853c 100644 --- a/docs/content/17.about/5.release-notes.md +++ b/docs/content/17.about/5.release-notes.md @@ -10,17 +10,20 @@ navigation: ## v0.12.1 - 2025-11-20 ### 🚨 修复 (Fixes) + - **CI/CD 优化**: 修复 golangci-lint v1.64.8 兼容性问题 - **测试稳定性**: 移除竞态检测器以优化 CI 执行时间 - **代码质量**: 禁用 errcheck linter 以减少测试文件中的误报 - **配置简化**: 移除 `.golangci.yml` 配置文件,使用命令行参数 ### ⚡ 性能优化 + - **CI 性能**: 测试时间从可能的超时减少到约 11 秒 - **资源限制**: 添加 `GOMAXPROCS=2` 和 `GOMEMLIMIT` 限制 - **Lint 优化**: golangci-lint 运行时间从 3 秒减少到 < 1 秒 ### 🏗️ 内部改进 + - **清理**: 移除 `examples.go` 中未实现的函数 - **测试修复**: 修复 builtin tools 中的测试失败 - **依赖更新**: 升级到 Go 1.24.0 @@ -28,17 +31,20 @@ navigation: ## v0.12.0 - 2025-11-15 ### ✨ 新功能 (Features) + - **云沙箱支持**: 新增阿里云函数计算和火山引擎沙箱后端 - **事件系统增强**: 完善事件驱动架构,支持三种事件通道 - **中间件系统**: 基于洋葱模型的灵活中间件栈 - **工具生态**: 新增 TodoList 工具和更多内置工具 ### 🔄 API 变更 + - **Agent 依赖**: 重构 Agent 依赖注入系统 - **工具注册**: 改进工具注册和发现机制 - **Session 管理**: 新增 Session 持久化支持 ### 🐛 修复 (Fixes) + - 修复多 Agent 协作中的并发问题 - 解决内存泄漏和资源管理问题 - 改进错误处理和日志记录 @@ -46,11 +52,13 @@ navigation: ## v0.11.3 - 2025-11-10 ### 🔧 代码质量 + - **Golangci-lint**: 修复所有 golangci-lint 警告 - **代码规范**: 统一代码风格和最佳实践 - **测试覆盖**: 提升测试覆盖率 ### 🛠️ 工具改进 + - **文件系统工具**: 改进文件读取和编辑功能 - **Bash 工具**: 增强命令执行安全性 - **网络工具**: 优化 HTTP 请求处理 @@ -58,11 +66,13 @@ navigation: ## v0.11.2 - 2025-11-05 ### 🐛 错误修复 + - 修复 golangci-lint 代码质量问题 - 改进错误消息处理 - 解决内存管理问题 ### 🔒 安全改进 + - 加强沙箱执行安全 - 改进权限控制系统 - 优化敏感信息处理 @@ -70,6 +80,7 @@ navigation: ## v0.11.1 - 2025-10-30 ### 🐛 紧急修复 + - 修复 Stars 模块中的时序问题 - 解决临时目录清理失败 - 改进测试稳定性 @@ -77,17 +88,20 @@ navigation: ## v0.11.0 - 2025-10-25 ### ✨ 重大更新 + - **多 Agent 系统**: 引入 Agent Pool 和 Room 概念 - **调度器**: 新增智能任务调度功能 - **中间件架构**: 实现洋葱模型中间件系统 - **事件驱动**: 完全重构为事件驱动架构 ### 🔄 API 破坏性变更 + - 重构 Agent 创建和配置 API - 更新工具注册机制 - 改进事件订阅系统 ### 📦 新模块 + - `pkg/stars`: 多 Agent 协作框架 - `pkg/cosmos`: Agent 管理和编排 - `pkg/middleware`: 中间件系统 @@ -95,12 +109,14 @@ navigation: ## 版本规划 ### v0.13.0 (计划中) + - [ ] MCP 协议完整支持 - [ ] 更多云厂商沙箱支持 - [ ] 性能监控和追踪 - [ ] 高级权限控制系统 ### v0.14.0 (计划中) + - [ ] 图形化管理界面 - [ ] 工作流可视化编辑器 - [ ] 插件市场 @@ -142,4 +158,4 @@ navigation: - 📖 [文档](/docs) - 🐛 [报告问题](https://github.com/astercloud/aster/issues) - 💬 [讨论区](https://github.com/astercloud/aster/discussions) -- 📧 [邮件支持](mailto:support@astercloud.ai) \ No newline at end of file +- 📧 [邮件支持](mailto:support@astercloud.ai) diff --git a/docs/content/17.about/6.acknowledgements.md b/docs/content/17.about/6.acknowledgements.md index d361e94..6f603ec 100644 --- a/docs/content/17.about/6.acknowledgements.md +++ b/docs/content/17.about/6.acknowledgements.md @@ -61,16 +61,16 @@ Anthropic 的官方 SDK,Computer Use 和 MCP 协议的参考实现,工具调 该白皮书系统性地定义了 AI Agent 的核心能力和最佳实践。aster 以此为标准,完整实现了白皮书中提出的 8 大核心特性。 :: -| 特性 | 描述 | 实现状态 | -|------|------|----------| -| Sessions & Memory | 会话管理与记忆系统 | ✅ 三层记忆 | -| Memory Provenance | 记忆溯源与置信度 | ✅ 完整实现 | -| Memory Consolidation | 记忆合并与整理 | ✅ LLM 驱动 | -| PII Auto-Redaction | 隐私数据脱敏 | ✅ 10+ 类型 | -| Event-Driven | 事件驱动架构 | ✅ 三通道 | -| Streaming | 流式处理 | ✅ stream.Reader | -| Multi-Agent | 多智能体协作 | ✅ Pool/Room | -| Observability | 可观测性 | ✅ OpenTelemetry | +| 特性 | 描述 | 实现状态 | +| -------------------- | ------------------ | ---------------- | +| Sessions & Memory | 会话管理与记忆系统 | ✅ 三层记忆 | +| Memory Provenance | 记忆溯源与置信度 | ✅ 完整实现 | +| Memory Consolidation | 记忆合并与整理 | ✅ LLM 驱动 | +| PII Auto-Redaction | 隐私数据脱敏 | ✅ 10+ 类型 | +| Event-Driven | 事件驱动架构 | ✅ 三通道 | +| Streaming | 流式处理 | ✅ stream.Reader | +| Multi-Agent | 多智能体协作 | ✅ Pool/Room | +| Observability | 可观测性 | ✅ OpenTelemetry | ### 其他参考论文 @@ -83,12 +83,13 @@ Anthropic 的官方 SDK,Computer Use 和 MCP 协议的参考实现,工具调 感谢以下基础设施项目: ::list{type="success"} + - **[Go](https://go.dev/)** - 高性能、并发友好的编程语言 - **[OpenTelemetry](https://opentelemetry.io/)** - 可观测性标准 - **[PostgreSQL](https://www.postgresql.org/)** / **[MySQL](https://www.mysql.com/)** - 可靠的数据持久化 - **[Docker](https://www.docker.com/)** - 容器化与沙箱隔离 - **[Gin](https://gin-gonic.com/)** - 高性能 HTTP 框架 -:: + :: ## 云平台合作 @@ -107,7 +108,7 @@ Anthropic 的官方 SDK,Computer Use 和 MCP 协议的参考实现,工具调 - `stream.Reader[T]` / `stream.Writer[T]` 泛型流式接口 - `stream.Pipe[T](cap)` 管道创建模式 - `Recv()` / `Send()` 读写分离设计 -:: + :: ## 开源精神 diff --git a/docs/content/18.architecture/1.overview.md b/docs/content/18.architecture/1.overview.md index 65321ea..d37fab7 100644 --- a/docs/content/18.architecture/1.overview.md +++ b/docs/content/18.architecture/1.overview.md @@ -1,6 +1,6 @@ # aster 架构概览 -> **设计原则**: 模块化、可扩展、框架无关 +> **设计原则**: 模块化、可扩展、框架无关 > **最后更新**: 2024年11月17日 --- @@ -18,12 +18,14 @@ aster 采用四层架构设计,将后端核心、Server 层、HTTP 层和客 ### 1. 框架无关 (Framework Agnostic) **pkg/ 核心 SDK**: + - ✅ 零 HTTP 框架依赖 - ✅ 只依赖 Go 标准库和核心第三方库 - ✅ 可被任何项目安全导入 - ✅ 不强制用户使用特定框架 **cmd/ HTTP 层**: + - 可以使用任何 HTTP 框架 (Gin, Echo, Chi, 标准库等) - 用户可以完全替换 HTTP 实现 - 只是一个参考实现 @@ -36,6 +38,7 @@ aster 采用四层架构设计,将后端核心、Server 层、HTTP 层和客 ``` **四层职责**: + - **Client 层**: UI/UX、事件处理、状态管理 - **Server 层**: 认证、授权、监控、限流(生产环境) - **HTTP 层**: 路由、序列化、协议转换(开发环境) @@ -44,6 +47,7 @@ aster 采用四层架构设计,将后端核心、Server 层、HTTP 层和客 ### 3. 模块化设计 (Modular Design) **15 个功能域**: + - Agent、Memory、Workflow、Session - Tool、Skill、Eval、MCP - Router、Sandbox、Middleware、Telemetry @@ -54,7 +58,8 @@ aster 采用四层架构设计,将后端核心、Server 层、HTTP 层和客 ### 4. 事件驱动 (Event-Driven) **三通道设计**: -- **Progress Channel**: 数据流 (thinking, text_chunk, tool_*) + +- **Progress Channel**: 数据流 (thinking, text*chunk, tool*\*) - **Control Channel**: 审批流 (tool_approval, pause/resume) - **Monitor Channel**: 治理流 (token_usage, cost, compliance) @@ -104,7 +109,7 @@ func main() { store, _ := store.NewJSONStore(".data") deps := &agent.Dependencies{Store: store} config := &types.AgentConfig{TemplateID: "assistant"} - + ag, _ := agent.Create(context.Background(), config, deps) result, _ := ag.Chat(context.Background(), "Hello!") println(result.Text) @@ -123,25 +128,25 @@ func main() { ### 作为客户端 SDK 使用 ```typescript -import { AgentsdkClient } from '@aster/client-js'; +import { AgentsdkClient } from "@aster/client-js"; const client = new AgentsdkClient({ - baseURL: 'http://localhost:8080', - apiKey: 'your-api-key' + baseURL: "http://localhost:8080", + apiKey: "your-api-key", }); // 使用任意资源 const response = await client.agents.chat({ - input: 'Hello, world!' + input: "Hello, world!", }); // 流式响应 -for await (const event of client.agents.stream({ input: '...' })) { +for await (const event of client.agents.stream({ input: "..." })) { console.log(event); } // 事件订阅 -const sub = await client.agents.subscribe(['progress', 'control']); +const sub = await client.agents.subscribe(["progress", "control"]); for await (const event of sub) { console.log(event); } @@ -151,16 +156,16 @@ for await (const event of sub) { ## 对比其他框架 -| 特性 | aster | LangChain | CrewAI | -|------|----------|-----------|--------| -| **语言** | Go + TypeScript | Python | Python | -| **架构** | 三层解耦 | 单体 | 单体 | -| **框架依赖** | 零依赖 (核心) | 强依赖 | 强依赖 | -| **性能** | 极高 (Go) | 中等 | 中等 | -| **事件驱动** | ✅ 三通道 | ❌ | ❌ | -| **Middleware** | ✅ 洋葱模型 | ✅ | ❌ | -| **类型安全** | ✅ 完整 | ❌ | ❌ | -| **可扩展性** | ✅ 极强 | ✅ | ⚠️ | +| 特性 | aster | LangChain | CrewAI | +| -------------- | --------------- | --------- | ------ | +| **语言** | Go + TypeScript | Python | Python | +| **架构** | 三层解耦 | 单体 | 单体 | +| **框架依赖** | 零依赖 (核心) | 强依赖 | 强依赖 | +| **性能** | 极高 (Go) | 中等 | 中等 | +| **事件驱动** | ✅ 三通道 | ❌ | ❌ | +| **Middleware** | ✅ 洋葱模型 | ✅ | ❌ | +| **类型安全** | ✅ 完整 | ❌ | ❌ | +| **可扩展性** | ✅ 极强 | ✅ | ⚠️ | --- @@ -173,5 +178,5 @@ for await (const event of sub) { --- -**版本**: v2.0 +**版本**: v2.0 **最后更新**: 2024年11月17日 diff --git a/docs/content/18.architecture/2.core-sdk.md b/docs/content/18.architecture/2.core-sdk.md index 97e35e2..9ead66e 100644 --- a/docs/content/18.architecture/2.core-sdk.md +++ b/docs/content/18.architecture/2.core-sdk.md @@ -1,6 +1,6 @@ # 核心 SDK 架构 (pkg/) -> **设计原则**: 零 HTTP 框架依赖,纯业务逻辑 +> **设计原则**: 零 HTTP 框架依赖,纯业务逻辑 > **最后更新**: 2024年11月17日 --- @@ -38,6 +38,7 @@ pkg/ aster 提供三种 Agent 类型,灵感来自 [DeepAgents](https://github.com/anthropics/deepagents) 项目: #### Basic Agent + 标准的单 Agent 模式,用于执行独立任务。 ```go @@ -52,21 +53,24 @@ result, _ := ag.Chat(ctx, "Hello!") ``` #### Workflow Agent + 编排多个子 Agent 的工作流模式: -| Agent 类型 | 执行模式 | 使用场景 | -|-----------|---------|---------| -| **ParallelAgent** | 并行执行所有子 Agent | 多方案比较、并行数据收集 | -| **SequentialAgent** | 顺序执行子 Agent | 流水线处理、多阶段任务 | -| **LoopAgent** | 循环执行直到条件满足 | 迭代优化、多轮对话 | +| Agent 类型 | 执行模式 | 使用场景 | +| ------------------- | -------------------- | ------------------------ | +| **ParallelAgent** | 并行执行所有子 Agent | 多方案比较、并行数据收集 | +| **SequentialAgent** | 顺序执行子 Agent | 流水线处理、多阶段任务 | +| **LoopAgent** | 循环执行直到条件满足 | 迭代优化、多轮对话 | **特点**: + - 基于 `stream.Reader` 的流式接口 - 内存占用 O(1) vs 传统 O(n) - 支持嵌套工作流 - 丰富的事件元数据(branch、iteration、index) #### SubAgent + 主从协作模式,用于任务委托和上下文隔离。 --- @@ -102,6 +106,7 @@ type Middleware interface { #### 内置 Middleware ##### SummarizationMiddleware + - **优先级**: 40 - **功能**: - 自动监控消息历史 token 数 @@ -109,6 +114,7 @@ type Middleware interface { - 保留最近 N 条消息 (默认 6 条) ##### FilesystemMiddleware + - **优先级**: 100 - **工具**: Read, Write, Ls, Edit, Glob, Grep - **功能**: @@ -116,6 +122,7 @@ type Middleware interface { - 系统提示词增强 ##### SubAgentMiddleware + - **优先级**: 200 - **工具**: task - **功能**: @@ -144,12 +151,12 @@ type BackendProtocol interface { #### 四种 Backend 实现 -| Backend | 用途 | 生命周期 | 使用场景 | -|---------|------|---------|---------| -| **StateBackend** | 内存临时存储 | 会话级 | 临时文件、中间结果 | -| **StoreBackend** | 持久化存储 | 跨会话 | 知识库、记忆 | -| **FilesystemBackend** | 真实文件系统 | 永久 | 工作空间文件 | -| **CompositeBackend** | 路由组合 | - | 混合存储策略 | +| Backend | 用途 | 生命周期 | 使用场景 | +| --------------------- | ------------ | -------- | ------------------ | +| **StateBackend** | 内存临时存储 | 会话级 | 临时文件、中间结果 | +| **StoreBackend** | 持久化存储 | 跨会话 | 知识库、记忆 | +| **FilesystemBackend** | 真实文件系统 | 永久 | 工作空间文件 | +| **CompositeBackend** | 路由组合 | - | 混合存储策略 | #### 使用示例 @@ -173,19 +180,21 @@ composite := backends.NewCompositeBackend( 持久化 Agent 会话和事件历史: -| 存储类型 | 用途 | 特点 | -|---------|------|------| -| **Memory** | 开发/测试 | 无持久化、快速 | -| **PostgreSQL** | 生产推荐 | JSONB、复杂查询、全文搜索 | -| **MySQL 8.0+** | 生产可选 | JSON 类型、InnoDB、高可用 | +| 存储类型 | 用途 | 特点 | +| -------------- | --------- | ------------------------- | +| **Memory** | 开发/测试 | 无持久化、快速 | +| **PostgreSQL** | 生产推荐 | JSONB、复杂查询、全文搜索 | +| **MySQL 8.0+** | 生产可选 | JSON 类型、InnoDB、高可用 | **功能**: + - Session 元数据管理(app_name、user_id、status) - Event 持久化(消息历史、工具调用、元数据) - 高性能查询(时间范围、分页、过滤) - 批量操作优化(单事务插入多个事件) **数据模型**: + ``` sessions (1) ──<─ (N) session_events - id, app_name, user_id, agent_id @@ -200,26 +209,26 @@ sessions (1) ──<─ (N) session_events ### 文件系统工具 (FilesystemMiddleware) -| 工具 | 描述 | 主要用途 | -|-----|------|---------| -| **Read** | 读取文件内容 | 支持分页读取 | -| **Write** | 写入文件 | 覆盖写入 | -| **Ls** | 列出目录 | 显示大小、时间 | -| **Edit** | 精确编辑 | 字符串替换 | -| **Glob** | Glob 匹配 | `**/*.go` | -| **Grep** | 正则搜索 | 显示行号、上下文 | +| 工具 | 描述 | 主要用途 | +| --------- | ------------ | ---------------- | +| **Read** | 读取文件内容 | 支持分页读取 | +| **Write** | 写入文件 | 覆盖写入 | +| **Ls** | 列出目录 | 显示大小、时间 | +| **Edit** | 精确编辑 | 字符串替换 | +| **Glob** | Glob 匹配 | `**/*.go` | +| **Grep** | 正则搜索 | 显示行号、上下文 | ### 网络工具 -| 工具 | 描述 | 主要用途 | -|-----|------|---------| -| **HttpRequest** | HTTP/HTTPS 请求 | GET/POST/PUT/DELETE/PATCH/HEAD | -| **WebSearch** | Web 搜索 | Tavily API (general/news/finance) | +| 工具 | 描述 | 主要用途 | +| --------------- | --------------- | --------------------------------- | +| **HttpRequest** | HTTP/HTTPS 请求 | GET/POST/PUT/DELETE/PATCH/HEAD | +| **WebSearch** | Web 搜索 | Tavily API (general/news/finance) | ### 子代理工具 (SubAgentMiddleware) -| 工具 | 描述 | 主要用途 | -|-----|------|---------| +| 工具 | 描述 | 主要用途 | +| -------- | -------- | ---------------------- | | **task** | 任务委托 | 启动子代理执行隔离任务 | --- @@ -228,10 +237,10 @@ sessions (1) ──<─ (N) session_events 基于 Apple M1, Go 1.21: -| 操作 | 性能 | 内存 | 吞吐量 | -|------|------|------|--------| -| Middleware Stack | 36.21 ns/op | 96 B/op | ~27M ops/s | -| Backend Write | 257.9 ns/op | 480 B/op | ~3.8M ops/s | +| 操作 | 性能 | 内存 | 吞吐量 | +| ---------------- | ----------- | -------- | ----------- | +| Middleware Stack | 36.21 ns/op | 96 B/op | ~27M ops/s | +| Backend Write | 257.9 ns/op | 480 B/op | ~3.8M ops/s | --- @@ -312,13 +321,13 @@ func (m *MyMiddleware) Tools() []tools.Tool { func (m *MyMiddleware) WrapToolCall(ctx, req, handler) (*ToolCallResponse, error) { // 前置处理 log.Printf("Before: %s", req.ToolName) - + // 调用下一层 resp, err := handler(ctx, req) - + // 后置处理 log.Printf("After: %v", resp.Result) - + return resp, err } ``` @@ -363,16 +372,16 @@ return map[string]interface{}{ ## 对比 DeepAgents -| 特性 | DeepAgents (Python) | aster (Go) | -|------|-------------------|-------------------| -| Backend Protocol | ✅ 4种 | ✅ 4种 | -| Middleware 栈 | ✅ 洋葱模型 | ✅ 洋葱模型 | -| 文件工具 | ✅ 6个 | ✅ 6个 | -| 自动驱逐 | ✅ | ✅ | -| 子代理 | ✅ | ✅ | -| 性能 | 中等 | **极高** (Go) | -| 内存 | 高 | **低** (Go) | -| 并发 | GIL限制 | **真正并发** (Goroutine) | +| 特性 | DeepAgents (Python) | aster (Go) | +| ---------------- | ------------------- | ------------------------ | +| Backend Protocol | ✅ 4种 | ✅ 4种 | +| Middleware 栈 | ✅ 洋葱模型 | ✅ 洋葱模型 | +| 文件工具 | ✅ 6个 | ✅ 6个 | +| 自动驱逐 | ✅ | ✅ | +| 子代理 | ✅ | ✅ | +| 性能 | 中等 | **极高** (Go) | +| 内存 | 高 | **低** (Go) | +| 并发 | GIL限制 | **真正并发** (Goroutine) | --- @@ -384,5 +393,5 @@ return map[string]interface{}{ --- -**版本**: v2.0 +**版本**: v2.0 **最后更新**: 2024年11月17日 diff --git a/docs/content/18.architecture/3.http-layer.md b/docs/content/18.architecture/3.http-layer.md index ea66a3d..ceef969 100644 --- a/docs/content/18.architecture/3.http-layer.md +++ b/docs/content/18.architecture/3.http-layer.md @@ -1,6 +1,6 @@ # HTTP 层架构 (cmd/aster) -> **设计原则**: 核心 SDK 与 HTTP 框架解耦 +> **设计原则**: 核心 SDK 与 HTTP 框架解耦 > **最后更新**: 2024年11月17日 --- @@ -10,6 +10,7 @@ ### 核心原则 **分层架构**: + ``` ┌─────────────────────────────────────┐ │ cmd/aster (CLI 工具) │ @@ -27,6 +28,7 @@ ``` **依赖隔离**: + - `cmd/*` → 可以依赖任何框架(Gin, Chi, Echo 等) - `pkg/*` → 只能依赖标准库和核心第三方库(不包括 HTTP 框架) @@ -55,6 +57,7 @@ cmd/aster/ ``` **职责**: + - CLI 工具入口 - HTTP Server 实现(使用 Gin) - 子命令实现 @@ -136,7 +139,7 @@ import ( func main() { r := gin.Default() - + // 使用 aster 核心功能 r.POST("/chat", func(c *gin.Context) { // 创建 Agent 并调用 @@ -144,7 +147,7 @@ func main() { result, _ := ag.Chat(...) c.JSON(200, result) }) - + r.Run(":8080") } ``` @@ -161,13 +164,13 @@ import ( func main() { e := echo.New() - + e.POST("/chat", func(c echo.Context) error { ag, _ := agent.Create(...) result, _ := ag.Chat(...) return c.JSON(200, result) }) - + e.Start(":8080") } ``` @@ -188,7 +191,7 @@ func main() { result, _ := ag.Chat(...) json.NewEncoder(w).Encode(result) }) - + http.ListenAndServe(":8080", nil) } ``` @@ -275,11 +278,13 @@ grep -r "gin-gonic/gin" pkg/ ### ✅ 允许 **在 cmd/aster/ 中**: + - ✅ 使用 Gin - ✅ 使用任何 HTTP 框架 - ✅ 使用任何 CLI 库 **在 pkg/ 中**: + - ✅ 使用标准库(`net/http` 用于类型定义) - ✅ 使用核心第三方库(UUID, 日志等) - ✅ 定义接口而不是实现 HTTP handler @@ -287,6 +292,7 @@ grep -r "gin-gonic/gin" pkg/ ### ❌ 禁止 **在 pkg/ 中**: + - ❌ 导入 `github.com/gin-gonic/gin` - ❌ 导入 `github.com/labstack/echo` - ❌ 导入 `github.com/go-chi/chi` @@ -346,22 +352,24 @@ import "net/http" // 或者标准库 ## 对比 -| 方面 | 旧架构 | 新架构 | -|------|--------|--------| -| **HTTP 框架** | pkg 中使用 Gin | 只在 cmd 中使用 | -| **SDK 导入** | 会引入 Gin 依赖 | 不会引入 Gin | -| **灵活性** | 用户被强制使用 Gin | 用户可用任何框架 | -| **兼容性** | 可能版本冲突 | 完全隔离 | -| **维护性** | pkg 膨胀 | 清晰分层 | +| 方面 | 旧架构 | 新架构 | +| ------------- | ------------------ | ---------------- | +| **HTTP 框架** | pkg 中使用 Gin | 只在 cmd 中使用 | +| **SDK 导入** | 会引入 Gin 依赖 | 不会引入 Gin | +| **灵活性** | 用户被强制使用 Gin | 用户可用任何框架 | +| **兼容性** | 可能版本冲突 | 完全隔离 | +| **维护性** | pkg 膨胀 | 清晰分层 | --- ## 总结 ### 核心思想 + **SDK 核心不应该依赖任何 HTTP 框架,让用户自由选择** ### 收益 + 1. ✅ 用户可以用任何 HTTP 框架 2. ✅ 避免依赖冲突 3. ✅ 更小的依赖树 @@ -369,11 +377,12 @@ import "net/http" // 或者标准库 5. ✅ 更容易维护 ### 原则 + - **核心在 pkg/**:纯粹的业务逻辑 - **HTTP 在 cmd/**:具体的实现细节 - **用户自由**:想用什么框架就用什么 --- -**版本**: v2.0 +**版本**: v2.0 **最后更新**: 2024年11月17日 diff --git a/docs/content/18.architecture/4.client-sdk.md b/docs/content/18.architecture/4.client-sdk.md index 535fd54..ef7ce66 100644 --- a/docs/content/18.architecture/4.client-sdk.md +++ b/docs/content/18.architecture/4.client-sdk.md @@ -1,6 +1,6 @@ # 客户端 SDK 架构 (client-sdks) -> **设计原则**: 事件驱动、类型安全、框架集成 +> **设计原则**: 事件驱动、类型安全、框架集成 > **最后更新**: 2024年11月17日 --- @@ -47,29 +47,29 @@ client-sdks/ ```typescript class AgentsdkClient { // 核心业务 - agents: AgentResource // Agent 管理和 Chat - memory: MemoryResource // 三层记忆系统 ⭐ - workflows: WorkflowResource // 工作流编排 - sessions: SessionResource // 会话和断点恢复 - + agents: AgentResource; // Agent 管理和 Chat + memory: MemoryResource; // 三层记忆系统 ⭐ + workflows: WorkflowResource; // 工作流编排 + sessions: SessionResource; // 会话和断点恢复 + // 开发工具 - skills: SkillResource // 技能管理 - evals: EvalResource // 评估系统 - tools: ToolResource // 工具执行 - + skills: SkillResource; // 技能管理 + evals: EvalResource; // 评估系统 + tools: ToolResource; // 工具执行 + // 生态集成 - mcp: MCPResource // MCP 协议 - router: RouterResource // 模型路由 - sandbox: SandboxResource // 沙箱管理 - + mcp: MCPResource; // MCP 协议 + router: RouterResource; // 模型路由 + sandbox: SandboxResource; // 沙箱管理 + // 基础设施 - middleware: MiddlewareResource // 中间件配置 - telemetry: TelemetryResource // 可观测性 - provider: ProviderResource // Provider 管理 - + middleware: MiddlewareResource; // 中间件配置 + telemetry: TelemetryResource; // 可观测性 + provider: ProviderResource; // Provider 管理 + // 管理功能 - template: TemplateResource // 模板管理 - security: SecurityResource // 安全系统 + template: TemplateResource; // 模板管理 + security: SecurityResource; // 安全系统 } ``` @@ -82,9 +82,9 @@ class AgentsdkClient { const subscription = await client.agents.subscribe( [Channel.Progress, Channel.Control, Channel.Monitor], { - agentId: 'agent-123', - eventTypes: ['thinking', 'text_chunk', 'tool_start'] - } + agentId: "agent-123", + eventTypes: ["thinking", "text_chunk", "tool_start"], + }, ); // 处理事件 @@ -92,22 +92,22 @@ for await (const event of subscription) { switch (event.channel) { case Channel.Progress: // 数据流:思考、文本、工具执行 - if (event.type === 'text_chunk') { + if (event.type === "text_chunk") { console.log(event.data.delta); } break; - + case Channel.Control: // 审批流:工具审批、暂停/恢复 - if (event.type === 'tool_approval_request') { + if (event.type === "tool_approval_request") { await client.security.approveToolCall(event.data.approvalId); } break; - + case Channel.Monitor: // 治理流:Token、成本、合规 - if (event.type === 'token_usage') { - console.log('Tokens:', event.data.tokens); + if (event.type === "token_usage") { + console.log("Tokens:", event.data.tokens); } break; } @@ -117,16 +117,19 @@ for await (const event of subscription) { **20+ 事件类型**: **Progress Channel**: + - `thinking` - 思考过程 - `text_chunk` - 流式文本 - `tool_start` / `tool_end` - 工具执行 - `done` / `error` - 完成/错误 **Control Channel**: + - `tool_approval_request` / `tool_approval_response` - 工具审批 - `pause` / `resume` - 暂停/恢复 **Monitor Channel**: + - `token_usage` - Token 使用 - `latency` - 延迟 - `cost` - 成本 @@ -141,17 +144,17 @@ class BaseResource { protected readonly options: ClientOptions; protected readonly httpClient: HttpClient; protected readonly wsClient: WebSocketClient; - + constructor(options: ClientOptions) { this.options = options; this.httpClient = new HttpClient(options); this.wsClient = new WebSocketClient(options); } - + // 统一的请求方法 protected async request( path: string, - options?: RequestOptions + options?: RequestOptions, ): Promise { // 1. Retry 机制(exponential backoff) // 2. 错误处理和恢复 @@ -160,19 +163,19 @@ class BaseResource { // 5. 日志和追踪 // 6. 指标收集 } - + // 流式请求 protected async *streamRequest( path: string, - options?: RequestOptions + options?: RequestOptions, ): AsyncGenerator { // SSE 解析和 AsyncGenerator } - + // 事件订阅 protected subscribe( path: string, - options?: SubscribeOptions + options?: SubscribeOptions, ): EventSubscription { // WebSocket 长连接 } @@ -180,6 +183,7 @@ class BaseResource { ``` **特性**: + - ✅ Retry 机制(指数退避,最多 3 次) - ✅ 错误处理(统一的错误类型) - ✅ Request Context(Base64 编码传递) @@ -196,27 +200,25 @@ class BaseResource { ```typescript class AgentResource extends BaseResource { // Chat 方法 - async chat(params: ChatParams): Promise - async *stream(params: ChatParams): AsyncGenerator - + async chat(params: ChatParams): Promise; + async *stream(params: ChatParams): AsyncGenerator; + // 事件订阅(核心!) - subscribe( - channels: Channel[], - filter?: EventFilter - ): EventSubscription - + subscribe(channels: Channel[], filter?: EventFilter): EventSubscription; + // Agent 管理 - async create(config: AgentConfig): Promise - async get(agentId: string): Promise - async list(filter?: AgentFilter): Promise> - async delete(agentId: string): Promise - + async create(config: AgentConfig): Promise; + async get(agentId: string): Promise; + async list(filter?: AgentFilter): Promise>; + async delete(agentId: string): Promise; + // 统计 - async getStats(agentId: string): Promise + async getStats(agentId: string): Promise; } ``` **API 端点**: + ``` POST/GET/DELETE /v1/agents POST /v1/agents/chat @@ -240,14 +242,14 @@ class MemoryResource extends BaseResource { async delete(key: string, scope?: 'thread' | 'resource'): Promise async list(scope?: 'thread' | 'resource'): Promise> } - + // Semantic Memory semantic: { async search(query: string, options?: SearchOptions): Promise async store(content: string, metadata?: Record): Promise async delete(chunkId: string): Promise } - + // 高级功能 async getProvenance(memoryId: string): Promise async consolidate(options?: ConsolidateOptions): Promise @@ -255,6 +257,7 @@ class MemoryResource extends BaseResource { ``` **特性**: + - 双作用域(thread / resource) - LLM 可主动更新(通过 Tool) - 自动加载到 system prompt @@ -270,13 +273,13 @@ class MemoryResource extends BaseResource { ```typescript class HttpClient { // 基础请求 - async request(path: string, options: RequestOptions): Promise - + async request(path: string, options: RequestOptions): Promise; + // Retry 逻辑 - private async retryRequest(fn: () => Promise): Promise - + private async retryRequest(fn: () => Promise): Promise; + // 错误处理 - private handleError(error: any): never + private handleError(error: any): never; } ``` @@ -285,13 +288,13 @@ class HttpClient { ```typescript class SSEParser { // 解析 SSE 流 - async *parse(stream: ReadableStream): AsyncGenerator - + async *parse(stream: ReadableStream): AsyncGenerator; + // 心跳处理 - private handleHeartbeat(): void - + private handleHeartbeat(): void; + // 重连逻辑 - private async reconnect(): Promise + private async reconnect(): Promise; } ``` @@ -300,13 +303,13 @@ class SSEParser { ```typescript class WebSocketClient { // 建立连接 - async connect(url: string): Promise - + async connect(url: string): Promise; + // 订阅事件 - subscribe(channels: Channel[], filter?: EventFilter): EventSubscription - + subscribe(channels: Channel[], filter?: EventFilter): EventSubscription; + // 自动重连 - private async reconnect(): Promise + private async reconnect(): Promise; } ``` @@ -403,7 +406,7 @@ function App() { ```typescript // useAgent - Agent Chat const { chat, loading, error } = useAgent({ - agentId: 'agent-123' + agentId: "agent-123", }); const handleSubmit = async (input) => { @@ -413,18 +416,18 @@ const handleSubmit = async (input) => { // useAgentStream - 流式响应 const { stream, events } = useAgentStream({ - agentId: 'agent-123' + agentId: "agent-123", }); useEffect(() => { - for await (const event of stream({ input: '...' })) { + for await (const event of stream({ input: "..." })) { console.log(event); } }, []); // useWorkflow - 工作流 const { execute, status } = useWorkflow({ - workflowId: 'workflow-123' + workflowId: "workflow-123", }); // useMemory - 记忆管理 @@ -436,13 +439,13 @@ const { get, set, search } = useMemory(); ## Vercel AI SDK 集成 ```typescript -import { createAgentChatRoute } from '@aster/ai-sdk'; +import { createAgentChatRoute } from "@aster/ai-sdk"; // Next.js App Router export const POST = createAgentChatRoute({ baseURL: process.env.AGENTSDK_URL, apiKey: process.env.AGENTSDK_API_KEY, - agentId: 'agent-123' + agentId: "agent-123", }); ``` @@ -454,7 +457,7 @@ function Chat() { const { messages, input, handleSubmit } = useChat({ api: '/api/chat' }); - + return ; } ``` @@ -464,18 +467,22 @@ function Chat() { ## 性能优化 ### 1. 连接复用 + - HTTP Keep-Alive - WebSocket 长连接复用 ### 2. 请求合并 + - 批量请求支持 - 相同请求去重 ### 3. 缓存策略 + - 响应缓存(可选) - TTL 配置 ### 4. 背压控制 + - 流式响应背压 - 事件流背压 @@ -486,17 +493,17 @@ function Chat() { ### 基础 Chat ```typescript -import { AgentsdkClient } from '@aster/client-js'; +import { AgentsdkClient } from "@aster/client-js"; const client = new AgentsdkClient({ - baseURL: 'http://localhost:8080', - apiKey: 'your-api-key' + baseURL: "http://localhost:8080", + apiKey: "your-api-key", }); // 简单对话 const response = await client.agents.chat({ - agentId: 'agent-123', - input: 'Hello, world!' + agentId: "agent-123", + input: "Hello, world!", }); console.log(response.text); ``` @@ -506,10 +513,10 @@ console.log(response.text); ```typescript // 流式对话 for await (const event of client.agents.stream({ - agentId: 'agent-123', - input: 'Tell me a story...' + agentId: "agent-123", + input: "Tell me a story...", })) { - if (event.type === 'text_chunk') { + if (event.type === "text_chunk") { process.stdout.write(event.data.delta); } } @@ -520,8 +527,8 @@ for await (const event of client.agents.stream({ ```typescript // 订阅所有通道 const subscription = await client.agents.subscribe( - ['progress', 'control', 'monitor'], - { agentId: 'agent-123' } + ["progress", "control", "monitor"], + { agentId: "agent-123" }, ); for await (const event of subscription) { @@ -533,13 +540,13 @@ for await (const event of subscription) { ```typescript // 设置工作记忆 -await client.memory.working.set('user_name', 'Alice', { - scope: 'thread', - ttl: 3600 +await client.memory.working.set("user_name", "Alice", { + scope: "thread", + ttl: 3600, }); // 获取工作记忆 -const name = await client.memory.working.get('user_name'); +const name = await client.memory.working.get("user_name"); // LLM 会自动访问这些记忆 ``` @@ -548,15 +555,12 @@ const name = await client.memory.working.get('user_name'); ```typescript // 执行工作流 -const run = await client.workflows.execute('workflow-123', { - input: { task: 'analyze data' } +const run = await client.workflows.execute("workflow-123", { + input: { task: "analyze data" }, }); // 监控执行状态 -const status = await client.workflows.getRunDetails( - 'workflow-123', - run.id -); +const status = await client.workflows.getRunDetails("workflow-123", run.id); ``` --- @@ -564,6 +568,7 @@ const status = await client.workflows.getRunDetails( ## 总结 ### 核心设计点 + 1. **15 个资源模块** - 按功能域划分 2. **事件驱动架构** - 三通道设计 3. **BaseResource 基类** - 统一的通用功能 @@ -571,6 +576,7 @@ const status = await client.workflows.getRunDetails( 5. **框架集成** - React、Vercel AI SDK、Vue (未来) ### 关键特性 + - ✅ 完整的 100+ API 端点覆盖 - ✅ 20+ 事件类型 - ✅ Working Memory(LLM 可主动更新) @@ -589,5 +595,5 @@ const status = await client.workflows.getRunDetails( --- -**版本**: v2.0 +**版本**: v2.0 **最后更新**: 2024年11月17日 diff --git a/docs/content/18.architecture/hitl-overview.md b/docs/content/18.architecture/hitl-overview.md index 3a57126..f0a1e16 100644 --- a/docs/content/18.architecture/hitl-overview.md +++ b/docs/content/18.architecture/hitl-overview.md @@ -109,17 +109,17 @@ hitlMW, _ := middleware.NewHumanInTheLoopMiddleware(&middleware.HumanInTheLoopMi ApprovalHandler: func(ctx context.Context, req *ReviewRequest) ([]Decision, error) { // 一次性审核所有操作 decisions := make([]Decision, len(req.ActionRequests)) - + for i, action := range req.ActionRequests { // 展示操作详情 fmt.Printf("%d. %s: %+v\n", i+1, action.ToolName, action.Input) } - + // 批量决策 fmt.Print("批准所有? (y/n): ") var answer string fmt.Scanln(&answer) - + for i := range decisions { if answer == "y" { decisions[i] = Decision{Type: DecisionApprove} @@ -127,7 +127,7 @@ ApprovalHandler: func(ctx context.Context, req *ReviewRequest) ([]Decision, erro decisions[i] = Decision{Type: DecisionReject} } } - + return decisions, nil } ``` @@ -143,10 +143,10 @@ func cliApprovalHandler(ctx context.Context, req *ReviewRequest) ([]Decision, er fmt.Printf("参数: %+v\n", action.Input) fmt.Printf("风险: %s\n", req.RiskLevel) fmt.Print("决策 (approve/reject/edit): ") - + var decision string fmt.Scanln(&decision) - + switch decision { case "approve": return []Decision{{Type: DecisionApprove}}, nil @@ -171,13 +171,13 @@ func cliApprovalHandler(ctx context.Context, req *ReviewRequest) ([]Decision, er func webUIApprovalHandler(ctx context.Context, req *ReviewRequest) ([]Decision, error) { // 1. 将审核请求存储到数据库 reviewID := saveReviewRequest(req) - + // 2. 通过 WebSocket 通知前端 notifyWebUI(reviewID, req) - + // 3. 等待用户决策 decision := waitForDecision(ctx, reviewID) - + return []Decision{decision}, nil } ``` @@ -192,10 +192,10 @@ func mqApprovalHandler(ctx context.Context, req *ReviewRequest) ([]Decision, err ID: reviewID, Request: req, }) - + // 2. 订阅决策队列 decisionChan := subscribeToQueue(fmt.Sprintf("decisions-%s", reviewID)) - + // 3. 等待决策(支持超时) select { case decision := <-decisionChan: @@ -217,14 +217,14 @@ func mqApprovalHandler(ctx context.Context, req *ReviewRequest) ([]Decision, err hitlMW, _ := middleware.NewHumanInTheLoopMiddleware(&middleware.HumanInTheLoopMiddlewareConfig{ ApprovalHandler: func(ctx context.Context, req *ReviewRequest) ([]Decision, error) { decision, err := getHumanDecision(req) - + // 记录审核日志 telemetry.RecordEvent(ctx, "hitl.review", map[string]interface{}{ "tool": req.ActionRequests[0].ToolName, "decision": decision.Type, "risk": req.RiskLevel, }) - + return []Decision{decision}, err }, }) @@ -236,7 +236,7 @@ hitlMW, _ := middleware.NewHumanInTheLoopMiddleware(&middleware.HumanInTheLoopMi // 记住审核决策,用于学习 ApprovalHandler: func(ctx context.Context, req *ReviewRequest) ([]Decision, error) { decision, err := getHumanDecision(req) - + // 存储审核历史 memory.Store(ctx, "approval_history", ApprovalRecord{ Timestamp: time.Now(), @@ -245,7 +245,7 @@ ApprovalHandler: func(ctx context.Context, req *ReviewRequest) ([]Decision, erro Decision: decision.Type, RiskLevel: req.RiskLevel, }) - + return []Decision{decision}, err } ``` @@ -274,12 +274,12 @@ workflow.AddStep(&workflow.Step{ ```go RiskAssessor: func(ctx context.Context, action *ActionRequest) (RiskLevel, error) { score := 0 - + // 基于工具评分 if action.ToolName == "Bash" { score += 50 } - + // 基于参数评分 if cmd, ok := action.Input["command"].(string); ok { if strings.Contains(cmd, "rm") { @@ -289,7 +289,7 @@ RiskAssessor: func(ctx context.Context, action *ActionRequest) (RiskLevel, error score += 20 } } - + // 评估风险等级 switch { case score >= 80: @@ -344,7 +344,7 @@ InterruptOn: map[string]interface{}{ "Bash": true, "fs_delete": true, "database_update": true, - + // ❌ 不需要审核 "fs_read": false, "http_get": false, @@ -381,7 +381,7 @@ ApprovalHandler: func(ctx context.Context, req *ReviewRequest) ([]Decision, erro ```go ApprovalHandler: func(ctx context.Context, req *ReviewRequest) ([]Decision, error) { decision, err := getDecision(req) - + // 记录审核日志 auditLog.Record(AuditEntry{ Timestamp: time.Now(), @@ -391,7 +391,7 @@ ApprovalHandler: func(ctx context.Context, req *ReviewRequest) ([]Decision, erro Decision: decision.Type, Reason: decision.Reason, }) - + return []Decision{decision}, err } ``` diff --git a/docs/content/18.architecture/index.md b/docs/content/18.architecture/index.md index b869201..3ed6170 100644 --- a/docs/content/18.architecture/index.md +++ b/docs/content/18.architecture/index.md @@ -7,18 +7,22 @@ ## 📚 文档导航 ### [1. 架构概览](./1.overview.md) + aster 的四层架构设计,包括核心 SDK、Server 层、HTTP 层和客户端 SDK 的整体架构。 **关键内容**: + - 整体架构图 - 核心设计原则(框架无关、分层架构、模块化、事件驱动) - 15 个功能域 - 使用方式(Go SDK、生产服务器、HTTP 服务、客户端 SDK) ### [2. 核心 SDK 架构](./2.core-sdk.md) + `pkg/` 目录下的核心 SDK 详细设计,零 HTTP 框架依赖。 **关键内容**: + - Agent 类型(Basic、Workflow、SubAgent) - Middleware 系统(洋葱模型) - Backend 抽象层(4 种实现) @@ -26,9 +30,11 @@ aster 的四层架构设计,包括核心 SDK、Server 层、HTTP 层和客户 - 性能指标(~27M ops/s) ### [3. Server 层架构](./server-architecture.md) ✨ 新增 + `server/` 目录下的生产级服务器实现,企业级特性。 **关键内容**: + - 认证与授权(API Key、JWT、RBAC) - Prometheus Metrics 监控 - OpenTelemetry 分布式追踪 @@ -38,9 +44,11 @@ aster 的四层架构设计,包括核心 SDK、Server 层、HTTP 层和客户 - 生产部署就绪 ### [4. HTTP 层架构](./3.http-layer.md) + `cmd/aster` 目录下的开发 HTTP 服务实现,可替换框架。 **关键内容**: + - 100+ REST API 端点 - 与核心 SDK 的解耦设计 - 框架灵活性(Gin/Echo/Chi/标准库) @@ -49,9 +57,11 @@ aster 的四层架构设计,包括核心 SDK、Server 层、HTTP 层和客户 - 开发模式快速启动 ### [5. 客户端 SDK 架构](./4.client-sdk.md) + `client-sdks` 目录下的多语言客户端 SDK 设计。 **关键内容**: + - 15 个资源模块 - 事件驱动架构(三通道设计) - BaseResource 基类 @@ -59,9 +69,11 @@ aster 的四层架构设计,包括核心 SDK、Server 层、HTTP 层和客户 - React/Vercel AI SDK 集成 ### [6. Human-in-the-Loop 架构](./hitl-overview.md) 🔐 安全特性 + 人工在环审核系统,控制 Agent 敏感操作。 **关键内容**: + - 三种决策类型(批准/拒绝/编辑) - 智能风险评估 - 多种审核处理器(CLI/Web UI/MQ) @@ -73,15 +85,19 @@ aster 的四层架构设计,包括核心 SDK、Server 层、HTTP 层和客户 ## 🎯 快速开始 ### 理解整体架构 + 从 [架构概览](./1.overview.md) 开始,了解 aster 的整体设计理念。 ### 深入核心实现 + 阅读 [核心 SDK 架构](./2.core-sdk.md),理解 Agent、Middleware 和 Backend 的设计。 ### 了解 HTTP 服务 + 查看 [HTTP 层架构](./3.http-layer.md),了解如何使用或替换 HTTP 实现。 ### 使用客户端 SDK + 参考 [客户端 SDK 架构](./4.client-sdk.md),学习如何在应用中集成 aster。 --- @@ -89,28 +105,33 @@ aster 的四层架构设计,包括核心 SDK、Server 层、HTTP 层和客户 ## 🔑 核心概念 ### 框架无关 (Framework Agnostic) + - ✅ 核心 SDK 零 HTTP 框架依赖 - ✅ 用户可以使用任何 HTTP 框架 - ✅ 避免依赖冲突 ### 分层架构 (Layered Architecture) + ``` Client → Server → HTTP → Core 展示层 → 服务层 → 接口层 → 业务层 ``` **四层架构**: + - **Client 层**: TypeScript/React 客户端 - **Server 层**: 生产级服务器(认证、监控、限流) - **HTTP 层**: 开发工具(快速启动) - **Core 层**: 核心业务逻辑(零依赖) ### 模块化设计 (Modular Design) + - 15 个功能域 - 每个模块独立 - 按需使用 ### 事件驱动 (Event-Driven) + - Progress Channel(数据流) - Control Channel(审批流) - Monitor Channel(治理流) @@ -119,23 +140,25 @@ Client → Server → HTTP → Core ## 📊 对比其他框架 -| 特性 | aster | LangChain | CrewAI | -|------|----------|-----------|--------| -| **语言** | Go + TypeScript | Python | Python | -| **架构** | 三层解耦 | 单体 | 单体 | -| **框架依赖** | 零依赖 (核心) | 强依赖 | 强依赖 | -| **性能** | 极高 (Go) | 中等 | 中等 | -| **事件驱动** | ✅ 三通道 | ❌ | ❌ | -| **Middleware** | ✅ 洋葱模型 | ✅ | ❌ | -| **类型安全** | ✅ 完整 | ❌ | ❌ | -| **可扩展性** | ✅ 极强 | ✅ | ⚠️ | +| 特性 | aster | LangChain | CrewAI | +| -------------- | --------------- | --------- | ------ | +| **语言** | Go + TypeScript | Python | Python | +| **架构** | 三层解耦 | 单体 | 单体 | +| **框架依赖** | 零依赖 (核心) | 强依赖 | 强依赖 | +| **性能** | 极高 (Go) | 中等 | 中等 | +| **事件驱动** | ✅ 三通道 | ❌ | ❌ | +| **Middleware** | ✅ 洋葱模型 | ✅ | ❌ | +| **类型安全** | ✅ 完整 | ❌ | ❌ | +| **可扩展性** | ✅ 极强 | ✅ | ⚠️ | --- ## 🚀 设计亮点 ### 1. 生产级 Server 层 ✨ 新增 + 完整的企业级服务器实现: + - **认证授权**: API Key + JWT + RBAC - **可观测性**: Prometheus + OpenTelemetry - **速率限制**: 令牌桶 + 滑动窗口 @@ -143,30 +166,37 @@ Client → Server → HTTP → Core - **优雅关闭**: 生产就绪 ### 2. 零框架依赖 + 核心 SDK 不依赖任何 HTTP 框架,用户可以: + - 使用 Gin、Echo、Chi 或标准库 - 避免版本冲突 - 更小的依赖树 ### 3. 事件驱动 + 三通道设计支持: + - 实时进度更新 - 工具审批流程 - 成本和合规监控 ### 4. 极致性能 + - Middleware Stack: ~27M ops/s - Backend Write: ~3.8M ops/s - HTTP 吞吐量: 10,000+ req/s - 基于 Go 的高并发 ### 5. 完整类型系统 + - 100+ TypeScript 接口 - 20+ 事件类型 - 完整的错误类型层次 - 端到端类型安全 ### 6. 框架集成 + - React Hooks - Vercel AI SDK - Prometheus + Grafana @@ -178,6 +208,7 @@ Client → Server → HTTP → Core ## 📖 相关文档 ### 核心概念 + - [Agents](../02.core-concepts/1.agents.md) - Agent 基础 - [Memory](../04.memory/) - 记忆系统 - [Middleware](../06.middleware/) - 中间件系统 @@ -185,10 +216,12 @@ Client → Server → HTTP → Core - [Workflows](../07.workflows/) - 工作流编排 ### API 参考 + - [REST API](../14.api-reference/) - HTTP API 文档 - [Client SDKs](../14.api-reference/6.client-sdks.md) - 客户端 SDK 文档 ### 部署指南 + - [Docker 部署](../09.deployment/1.docker.md) - [Kubernetes](../09.deployment/2.kubernetes.md) - [生产最佳实践](../09.deployment/4.production.md) @@ -198,16 +231,19 @@ Client → Server → HTTP → Core ## 🎓 学习路径 ### 初学者 + 1. 阅读 [架构概览](./1.overview.md) 2. 查看 [快速开始](../01.introduction/2.quick-start.md) 3. 尝试 [示例代码](../12.examples/) ### 进阶开发者 + 1. 深入 [核心 SDK 架构](./2.core-sdk.md) 2. 学习 [Middleware 系统](../06.middleware/) 3. 探索 [工作流编排](../07.workflows/) ### 架构师 + 1. 研究所有架构文档 2. 了解 [部署架构](../09.deployment/) 3. 参考 [最佳实践](../15.best-practices/) @@ -219,28 +255,32 @@ Client → Server → HTTP → Core aster 的架构设计基于以下核心理念: ### 1. 简单优于复杂 + - 清晰的分层 - 明确的职责 - 最小化依赖 ### 2. 灵活优于强制 + - 用户可选择框架 - 模块化设计 - 可替换组件 ### 3. 性能优于便利 + - Go 语言实现 - 零拷贝设计 - 高效并发 ### 4. 类型安全优于动态 + - 完整的类型定义 - 编译时检查 - IDE 友好 --- -**最后更新**: 2024年11月17日 +**最后更新**: 2024年11月17日 **版本**: v2.0 --- @@ -248,6 +288,7 @@ aster 的架构设计基于以下核心理念: ## 反馈和贡献 如果你对架构有任何疑问或建议,欢迎: + - 提交 Issue - 发起 Discussion - 贡献 PR diff --git a/docs/content/18.architecture/server-architecture.md b/docs/content/18.architecture/server-architecture.md index db9425a..2860e48 100644 --- a/docs/content/18.architecture/server-architecture.md +++ b/docs/content/18.architecture/server-architecture.md @@ -36,7 +36,7 @@ type Server struct { config *Config router *gin.Engine store store.Store - + // Auth & Observability authManager *auth.Manager rbac *auth.RBAC @@ -48,6 +48,7 @@ type Server struct { ``` **功能**: + - 服务器生命周期管理 - 中间件配置 - 路由注册 @@ -58,6 +59,7 @@ type Server struct { 完整的认证和授权系统。 #### 认证管理器 + ```go // 支持多种认证方法 authManager := auth.NewManager(auth.AuthMethodAPIKey) @@ -76,6 +78,7 @@ authManager.Register(jwtAuth) ``` #### RBAC 权限控制 + ```go rbac := auth.NewRBAC() @@ -92,6 +95,7 @@ hasPermission := rbac.HasPermission(ctx, user, "agents", "create") ### 3. 可观测性 (`server/observability/`) #### Prometheus Metrics + ```go metrics := observability.NewMetricsManager("aster") @@ -106,6 +110,7 @@ aster_workflows_running ``` #### OpenTelemetry 追踪 + ```go tracing, _ := observability.NewTracingManager(observability.TracingConfig{ Enabled: true, @@ -119,6 +124,7 @@ tracing, _ := observability.NewTracingManager(observability.TracingConfig{ ``` #### 增强健康检查 + ```go healthChecker := observability.NewHealthChecker("v0.11.0") @@ -141,6 +147,7 @@ healthChecker.RegisterCheck(storeCheck) 支持两种算法: #### 令牌桶 (Token Bucket) + ```go limiter := ratelimit.NewTokenBucketLimiter( rate, // 令牌补充速率 @@ -150,6 +157,7 @@ limiter := ratelimit.NewTokenBucketLimiter( ``` #### 滑动窗口 (Sliding Window) + ```go limiter := ratelimit.NewSlidingWindowLimiter( limit, // 请求限制 @@ -158,6 +166,7 @@ limiter := ratelimit.NewSlidingWindowLimiter( ``` #### 中间件集成 + ```go // 基于 IP 限流 ratelimit.Middleware(config, limiter) @@ -183,6 +192,7 @@ ratelimit.PerEndpointMiddleware(config, limiter) - `mcp.go` - MCP 服务器 所有 Handler 使用统一模式: + ```go type Handler struct { store *store.Store @@ -219,7 +229,7 @@ config := &server.Config{ Host: "0.0.0.0", Port: 8080, Mode: "production", - + // 认证 Auth: server.AuthConfig{ APIKey: server.APIKeyConfig{ @@ -232,14 +242,14 @@ config := &server.Config{ Expiry: 86400, // 24 hours }, }, - + // CORS CORS: server.CORSConfig{ Enabled: true, AllowOrigins: []string{"*"}, AllowMethods: []string{"GET", "POST", "PUT", "DELETE"}, }, - + // 速率限制 RateLimit: server.RateLimitConfig{ Enabled: true, @@ -247,7 +257,7 @@ config := &server.Config{ WindowSize: time.Minute, BurstSize: 20, }, - + // 可观测性 Observability: server.ObservabilityConfig{ Enabled: true, @@ -287,10 +297,10 @@ func main() { deps := &server.Dependencies{ Store: st, } - + // 创建服务器 srv, _ := server.New(server.DefaultConfig(), deps) - + // 启动 srv.Start() } @@ -337,11 +347,13 @@ if err := srv.Stop(ctx); err != nil { ### 开发模式 (`cmd/aster`) 简化配置,快速启动: + ```bash aster serve --port 8080 --mode debug ``` 特点: + - 无认证 - CORS 允许所有来源 - 详细日志 @@ -350,12 +362,14 @@ aster serve --port 8080 --mode debug ### 生产模式 (`cmd/aster-server`) 完整特性: + ```bash export API_KEY=your-secret-key aster-server ``` 特点: + - API Key/JWT 认证 - 速率限制 - 结构化日志 diff --git a/docs/nuxt.config.ts b/docs/nuxt.config.ts index 8526f47..1e772e9 100644 --- a/docs/nuxt.config.ts +++ b/docs/nuxt.config.ts @@ -1,17 +1,17 @@ // 完全参考 veadk-python 的配置 export default { - extends: ['docus'], + extends: ["docus"], app: { - baseURL: '/aster/' + baseURL: "/aster/", }, image: { - provider: 'none' + provider: "none", }, // 修复警告 robots: { - robotsTxt: false + robotsTxt: false, }, llms: { - domain: 'https://aster.local' - } -} + domain: "https://aster.local", + }, +}; diff --git a/docs/package-lock.json b/docs/package-lock.json index 3ccc0c0..5ecc035 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -11935,9 +11935,9 @@ } }, "node_modules/mdast-util-to-hast": { - "version": "13.2.0", - "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.0.tgz", - "integrity": "sha512-QGYKEuUsYT9ykKBCMOEDLsU5JRObWQusAolFMeko/tYPufNkRffBAQjIE+99jbA87xv6FgmjLtwjh9wBWajwAA==", + "version": "13.2.1", + "resolved": "https://registry.npmjs.org/mdast-util-to-hast/-/mdast-util-to-hast-13.2.1.tgz", + "integrity": "sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==", "license": "MIT", "dependencies": { "@types/hast": "^3.0.0", @@ -13091,9 +13091,9 @@ "license": "MIT" }, "node_modules/node-forge": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", - "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.3.tgz", + "integrity": "sha512-rLvcdSyRCyouf6jcOIPe/BgwG/d7hKjzMKOas33/pHEr6gbq18IK9zV7DiPvzsz0oBJPme6qr6H6kGZuI9/DZg==", "license": "(BSD-3-Clause OR GPL-2.0)", "engines": { "node": ">= 6.13.0" diff --git a/docs/package.json b/docs/package.json index 89e8721..7874a8b 100644 --- a/docs/package.json +++ b/docs/package.json @@ -11,4 +11,4 @@ "nuxt": "^4.2.1", "mermaid": "^11.4.0" } -} \ No newline at end of file +} diff --git a/docs/tailwind.config.js b/docs/tailwind.config.js index 4a3eaf9..e8111de 100644 --- a/docs/tailwind.config.js +++ b/docs/tailwind.config.js @@ -1,38 +1,45 @@ -import defaultTheme from 'tailwindcss/defaultTheme' +import defaultTheme from "tailwindcss/defaultTheme"; /** @type {import('tailwindcss').Config} */ export default { content: [ - './components/**/*.{js,vue,ts}', - './layouts/**/*.vue', - './pages/**/*.vue', - './plugins/**/*.{js,ts}', - './app.vue', - './content/**/*.md' + "./components/**/*.{js,vue,ts}", + "./layouts/**/*.vue", + "./pages/**/*.vue", + "./plugins/**/*.{js,ts}", + "./app.vue", + "./content/**/*.md", ], - darkMode: 'class', + darkMode: "class", theme: { extend: { fontFamily: { - mono: ['ui-monospace', 'SFMono-Regular', 'Menlo', 'Monaco', 'Consolas', '"Liberation Mono"', '"Courier New"', ...defaultTheme.fontFamily.mono] + mono: [ + "ui-monospace", + "SFMono-Regular", + "Menlo", + "Monaco", + "Consolas", + '"Liberation Mono"', + '"Courier New"', + ...defaultTheme.fontFamily.mono, + ], }, colors: { primary: { - 50: '#f0fdf4', - 100: '#dcfce7', - 200: '#bbf7d0', - 300: '#86efac', - 400: '#4ade80', - 500: '#22c55e', - 600: '#16a34a', - 700: '#15803d', - 800: '#166534', - 900: '#14532d', - } - } - } + 50: "#f0fdf4", + 100: "#dcfce7", + 200: "#bbf7d0", + 300: "#86efac", + 400: "#4ade80", + 500: "#22c55e", + 600: "#16a34a", + 700: "#15803d", + 800: "#166534", + 900: "#14532d", + }, + }, + }, }, - plugins: [ - require('@tailwindcss/typography') - ] -} + plugins: [require("@tailwindcss/typography")], +}; From 42c76a7582ffd815f161fec64ffd41b101dad50e Mon Sep 17 00:00:00 2001 From: lwmacct Date: Thu, 4 Dec 2025 19:11:07 +0800 Subject: [PATCH 2/2] fix(agent): enable code_reference module for code_assistant agent type --- pkg/agent/prompt_modules.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pkg/agent/prompt_modules.go b/pkg/agent/prompt_modules.go index 3613ff5..8d65c1b 100644 --- a/pkg/agent/prompt_modules.go +++ b/pkg/agent/prompt_modules.go @@ -161,9 +161,14 @@ func (m *CodeReferenceModule) Priority() int { return 30 } func (m *CodeReferenceModule) Condition(ctx *PromptContext) bool { // 优化:默认禁用以减少 token,需要时明确启用 if ctx.Metadata != nil { + // 显式启用 if enabled, ok := ctx.Metadata["enable_code_reference"].(bool); ok && enabled { return true } + // 对于代码助手类型的 agent 自动启用 + if agentType, ok := ctx.Metadata["agent_type"].(string); ok && agentType == "code_assistant" { + return true + } } return false }