feat(web,docs): 前端支持模型下拉选择并更新 README 专家系统章节
- 前端类型 ExpertItem/SubagentItem 新增 provider/model 字段,新增 ModelOptionsResponse 类型 - API 层 createExpert/updateExpert/updateSubagent payload 支持 provider/model,新增 listModelOptions - ConfigPage 专家/子代理模态框新增模型配置 SectionCard(Provider/Model 下拉框,留空继承默认) - 空字符串转 undefined 传后端,避免 P0 反序列化为 Some(vec![]) 导致全禁 - README 新增第 8 节专家系统,更新子代理 SUBAGENT.md 字段说明(含 provider/model 和子代理黑白名单) - README 新增 max_nesting_depth 配置项说明,重排后续章节编号
This commit is contained in:
parent
dc9211548a
commit
5ff1e8455c
157
README.md
157
README.md
@ -142,7 +142,8 @@ Agent 执行层 (Agent) ◄─────────────────
|
|||||||
- src/client:WebSocket CLI 客户端实现
|
- src/client:WebSocket CLI 客户端实现
|
||||||
- src/command:命令系统,包括处理器、适配器、上下文和响应处理
|
- src/command:命令系统,包括处理器、适配器、上下文和响应处理
|
||||||
- src/config:配置解析与默认值定义
|
- src/config:配置解析与默认值定义
|
||||||
- src/domain:领域模型,包含消息和工具定义
|
- src/domain:领域模型,包含消息、工具定义和能力策略(CapabilityPolicy)
|
||||||
|
- src/experts:专家系统,支持基于文件系统的专家发现、加载和运行时管理
|
||||||
- src/gateway:网关生命周期、InboundProcessor、OutboundDispatcher、SessionManager,以及消息执行、调度任务执行、Prompt 注入、历史压缩和记忆维护编排
|
- src/gateway:网关生命周期、InboundProcessor、OutboundDispatcher、SessionManager,以及消息执行、调度任务执行、Prompt 注入、历史压缩和记忆维护编排
|
||||||
- src/providers:不同 LLM Provider 的统一抽象,当前支持 openai 和 anthropic
|
- src/providers:不同 LLM Provider 的统一抽象,当前支持 openai 和 anthropic
|
||||||
- src/tools:内置工具集合与 ToolRegistry
|
- src/tools:内置工具集合与 ToolRegistry
|
||||||
@ -502,17 +503,88 @@ tools 配置示例:
|
|||||||
|
|
||||||
注意:bash 和 shell 是同一个工具在不同平台上的名称,运行时自动检测。
|
注意:bash 和 shell 是同一个工具在不同平台上的名称,运行时自动检测。
|
||||||
|
|
||||||
## 8. 子代理系统
|
## 8. 专家系统
|
||||||
|
|
||||||
|
PicoBot 支持基于文件系统的专家系统,用于给主智能体注入特定角色的行为语气和系统能力配置。专家类似于技能,但作用于主智能体本身,而非作为子任务执行。
|
||||||
|
|
||||||
|
### 8.1 专家发现位置
|
||||||
|
|
||||||
|
按从低到高优先级合并,后加载来源可覆盖同名专家:
|
||||||
|
|
||||||
|
- 用户级:`~/.picobot/experts/*/EXPERT.md`
|
||||||
|
- 项目级:`.picobot/experts/*/EXPERT.md`
|
||||||
|
|
||||||
|
### 8.2 EXPERT.md 格式
|
||||||
|
|
||||||
|
```md
|
||||||
|
---
|
||||||
|
description: Rust 架构审查专家
|
||||||
|
name: rust-reviewer # 可选,省略时使用目录名
|
||||||
|
allowed_skills: [code-review-skill] # 可选,技能白名单(仅这些技能可用)
|
||||||
|
denied_skills: [shell-exec] # 可选,技能黑名单(这些技能被禁用)
|
||||||
|
allowed_tools: [read, bash, web_fetch] # 可选,工具白名单(仅这些工具可用)
|
||||||
|
denied_tools: [task] # 可选,工具黑名单(这些工具被禁用)
|
||||||
|
allowed_subagents: [general] # 可选,子代理白名单(仅允许创建这些子代理类型)
|
||||||
|
denied_subagents: [explore] # 可选,子代理黑名单(禁止创建这些子代理类型)
|
||||||
|
provider: deepseek # 可选,覆盖 provider(引用 config.json 的 providers 表)
|
||||||
|
model: deepseek-chat # 可选,覆盖 model(引用 config.json 的 models 表)
|
||||||
|
---
|
||||||
|
|
||||||
|
你是一个专注于 Rust 项目的架构审查专家。
|
||||||
|
|
||||||
|
你应该:
|
||||||
|
1. 重点关注模块解耦性和依赖方向
|
||||||
|
2. 检查是否存在循环依赖
|
||||||
|
3. 提出符合 Rust 惯用法的改进建议
|
||||||
|
4. 关注错误处理和资源管理
|
||||||
|
```
|
||||||
|
|
||||||
|
### 8.3 字段说明
|
||||||
|
|
||||||
|
| 字段 | 类型 | 必填 | 说明 |
|
||||||
|
|------|------|------|------|
|
||||||
|
| `description` | string | 是 | 简短描述,用于专家选择 |
|
||||||
|
| `name` | string | 否 | 专家名称,默认取目录名 |
|
||||||
|
| `allowed_skills` | array | 否 | 技能白名单,指定后仅这些技能可用;不指定则不限制 |
|
||||||
|
| `denied_skills` | array | 否 | 技能黑名单,指定后这些技能被禁用;在白名单之后应用 |
|
||||||
|
| `allowed_tools` | array | 否 | 工具白名单,指定后仅这些工具可用;不指定则不限制 |
|
||||||
|
| `denied_tools` | array | 否 | 工具黑名单,指定后这些工具被禁用;在白名单之后应用 |
|
||||||
|
| `allowed_subagents` | array | 否 | 子代理白名单,指定后仅允许创建这些类型的子代理;不指定则不限制 |
|
||||||
|
| `denied_subagents` | array | 否 | 子代理黑名单,指定后禁止创建这些类型的子代理;在白名单之后应用 |
|
||||||
|
| `provider` | string | 否 | 覆盖 provider,引用 `config.json` 的 `providers` 表中的键名;不指定则继承主智能体 |
|
||||||
|
| `model` | string | 否 | 覆盖 model,引用 `config.json` 的 `models` 表中的键名;不指定则继承主智能体 |
|
||||||
|
|
||||||
|
> **能力过滤语义**:与子代理一致,`allowed_*` 与 `denied_*` 可共存,生效顺序为:先应用白名单(取交集),再扣除黑名单。四类能力(tools/skills/subagents)独立过滤,互不影响。全部不指定时,主智能体使用完整工具集和技能集。
|
||||||
|
>
|
||||||
|
> **模型覆盖语义**:`provider` 和 `model` 字段独立可选,可只覆盖其一。引用不存在的 provider/model 名会阻止会话并明确反馈。不指定时继承主智能体的 provider/model 配置。
|
||||||
|
>
|
||||||
|
> **专家与子代理的区别**:专家配置作用于主智能体(影响 system prompt 和能力策略),子代理配置作用于独立执行上下文(影响子任务的行为和能力)。两者各自独立,子代理不继承专家的能力策略。
|
||||||
|
|
||||||
|
### 8.4 专家管理
|
||||||
|
|
||||||
|
专家支持通过 Web UI 或 API 进行运行时管理:
|
||||||
|
|
||||||
|
- 查看专家列表(含来源、禁用状态)
|
||||||
|
- 创建/更新/删除专家
|
||||||
|
- 按作用域(用户级/项目级)禁用/启用专家
|
||||||
|
- 配置能力策略(工具/技能/子代理黑白名单)和模型覆盖
|
||||||
|
|
||||||
|
专家启用/禁用状态写入独立状态文件:
|
||||||
|
|
||||||
|
- 用户级状态:`~/.picobot/expert-state.json`
|
||||||
|
- 项目级状态:`.picobot/expert-state.json`
|
||||||
|
|
||||||
|
## 9. 子代理系统
|
||||||
|
|
||||||
PicoBot 支持通过 `task` 工具创建子代理来处理复杂多步骤任务。子代理在一个独立的执行上下文中运行,拥有独立的会话历史和工具权限。
|
PicoBot 支持通过 `task` 工具创建子代理来处理复杂多步骤任务。子代理在一个独立的执行上下文中运行,拥有独立的会话历史和工具权限。
|
||||||
|
|
||||||
### 8.1 内置子代理类型
|
### 9.1 内置子代理类型
|
||||||
|
|
||||||
- **general**:通用型子代理,适合处理复杂多步骤任务。可以使用读写文件、执行命令、HTTP 请求等完整工具集。
|
- **general**:通用型子代理,适合处理复杂多步骤任务。可以使用读写文件、执行命令、HTTP 请求等完整工具集。
|
||||||
|
|
||||||
> 如需只读探索型子代理,可通过自定义子代理配合 `allowed_tools` 白名单实现(见下文)。
|
> 如需只读探索型子代理,可通过自定义子代理配合 `allowed_tools` 白名单实现(见下文)。
|
||||||
|
|
||||||
### 8.2 自定义子代理
|
### 9.2 自定义子代理
|
||||||
|
|
||||||
用户可以在文件系统上定义新的子代理类型,类似于技能的加载方式。子代理定义文件采用 YAML frontmatter + body 的格式。
|
用户可以在文件系统上定义新的子代理类型,类似于技能的加载方式。子代理定义文件采用 YAML frontmatter + body 的格式。
|
||||||
|
|
||||||
@ -541,6 +613,12 @@ prompt_template: |
|
|||||||
注意: 你是一个只读代理,禁止执行任何修改操作。
|
注意: 你是一个只读代理,禁止执行任何修改操作。
|
||||||
allowed_tools: [read, bash, web_fetch] # 可选,工具白名单(仅这些工具可用)
|
allowed_tools: [read, bash, web_fetch] # 可选,工具白名单(仅这些工具可用)
|
||||||
denied_tools: [task] # 可选,工具黑名单(这些工具被禁用)
|
denied_tools: [task] # 可选,工具黑名单(这些工具被禁用)
|
||||||
|
allowed_skills: [code-review-skill] # 可选,技能白名单(仅这些技能可用)
|
||||||
|
denied_skills: [shell-exec] # 可选,技能黑名单(这些技能被禁用)
|
||||||
|
allowed_subagents: [general] # 可选,子代理白名单(仅允许创建这些子代理类型)
|
||||||
|
denied_subagents: [explore] # 可选,子代理黑名单(禁止创建这些子代理类型)
|
||||||
|
provider: deepseek # 可选,覆盖 provider(引用 config.json 的 providers 表)
|
||||||
|
model: deepseek-chat # 可选,覆盖 model(引用 config.json 的 models 表)
|
||||||
max_execution_secs: 600 # 可选,覆盖默认执行时间
|
max_execution_secs: 600 # 可选,覆盖默认执行时间
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -559,9 +637,17 @@ max_execution_secs: 600 # 可选,覆盖默认执行时间
|
|||||||
| `prompt_template` | string | 是 | 提示词模板,支持变量插值 |
|
| `prompt_template` | string | 是 | 提示词模板,支持变量插值 |
|
||||||
| `allowed_tools` | array | 否 | 工具白名单,指定后仅这些工具可用;不指定则不限制 |
|
| `allowed_tools` | array | 否 | 工具白名单,指定后仅这些工具可用;不指定则不限制 |
|
||||||
| `denied_tools` | array | 否 | 工具黑名单,指定后这些工具被禁用;在白名单之后应用 |
|
| `denied_tools` | array | 否 | 工具黑名单,指定后这些工具被禁用;在白名单之后应用 |
|
||||||
|
| `allowed_skills` | array | 否 | 技能白名单,指定后仅这些技能可用;不指定则不限制 |
|
||||||
|
| `denied_skills` | array | 否 | 技能黑名单,指定后这些技能被禁用;在白名单之后应用 |
|
||||||
|
| `allowed_subagents` | array | 否 | 子代理白名单,指定后仅允许创建这些类型的子代理;不指定则不限制 |
|
||||||
|
| `denied_subagents` | array | 否 | 子代理黑名单,指定后禁止创建这些类型的子代理;在白名单之后应用 |
|
||||||
|
| `provider` | string | 否 | 覆盖 provider,引用 `config.json` 的 `providers` 表中的键名;不指定则继承主智能体 |
|
||||||
|
| `model` | string | 否 | 覆盖 model,引用 `config.json` 的 `models` 表中的键名;不指定则继承主智能体 |
|
||||||
| `max_execution_secs` | integer | 否 | 最大执行时间(秒) |
|
| `max_execution_secs` | integer | 否 | 最大执行时间(秒) |
|
||||||
|
|
||||||
> **工具过滤语义**:`allowed_tools` 与 `denied_tools` 可共存。生效顺序为:先应用白名单(取交集),再扣除黑名单。两者都不指定时,子代理使用完整工具集。当子代理嵌套深度达到 `max_nesting_depth`(默认 2,即孙代理)时,始终移除 `task` 工具以防无限嵌套。白名单中未注册的工具名会被静默跳过。
|
> **能力过滤语义**:`allowed_*` 与 `denied_*` 可共存。生效顺序为:先应用白名单(取交集),再扣除黑名单。四类能力(tools/skills/subagents)独立过滤,互不影响。全部不指定时,子代理使用完整工具集和技能集。当子代理嵌套深度达到 `max_nesting_depth` 时,始终移除 `task` 工具以防无限嵌套。白名单中未注册的工具/技能名会被静默跳过。
|
||||||
|
>
|
||||||
|
> **模型覆盖语义**:`provider` 和 `model` 字段独立可选,可只覆盖其一。引用不存在的 provider/model 名会导致子代理创建失败并反馈给主智能体重试。不指定时继承主智能体的 provider/model 配置。
|
||||||
|
|
||||||
#### 模板变量
|
#### 模板变量
|
||||||
|
|
||||||
@ -586,23 +672,34 @@ max_execution_secs: 600 # 可选,覆盖默认执行时间
|
|||||||
|
|
||||||
如果指定的子代理类型不存在,系统会自动回退到 `general` 类型。
|
如果指定的子代理类型不存在,系统会自动回退到 `general` 类型。
|
||||||
|
|
||||||
### 8.3 子代理配置
|
### 9.3 子代理配置
|
||||||
|
|
||||||
```json
|
```json
|
||||||
{
|
{
|
||||||
"subagents": {
|
"subagents": {
|
||||||
"enabled": true,
|
"enabled": true,
|
||||||
"sources": ["user", "project"]
|
"sources": ["user", "project"]
|
||||||
|
},
|
||||||
|
"tools": {
|
||||||
|
"task": {
|
||||||
|
"enabled": true,
|
||||||
|
"max_nesting_depth": 2,
|
||||||
|
"max_execution_secs": 3600,
|
||||||
|
"ttl_hours": 24
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
| 字段 | 默认值 | 说明 |
|
| 字段 | 默认值 | 说明 |
|
||||||
|------|--------|------|
|
|------|--------|------|
|
||||||
| `enabled` | `true` | 是否启用自定义子代理发现 |
|
| `subagents.enabled` | `true` | 是否启用自定义子代理发现 |
|
||||||
| `sources` | `["user", "project"]` | 定义来源优先级 |
|
| `subagents.sources` | `["user", "project"]` | 定义来源优先级 |
|
||||||
|
| `tools.task.max_nesting_depth` | `2` | 子代理最大嵌套深度(0=禁止嵌套,1=仅子代理,2=子代理+孙代理) |
|
||||||
|
| `tools.task.max_execution_secs` | `3600` | 子代理默认最大执行时间(秒) |
|
||||||
|
| `tools.task.ttl_hours` | `24` | 子代理任务 TTL(小时) |
|
||||||
|
|
||||||
## 9. 工具机制
|
## 10. 工具机制
|
||||||
|
|
||||||
PicoBot 的 Agent 是围绕工具调用构建的。当前默认注册的工具包括:
|
PicoBot 的 Agent 是围绕工具调用构建的。当前默认注册的工具包括:
|
||||||
|
|
||||||
@ -632,7 +729,7 @@ PicoBot 的 Agent 是围绕工具调用构建的。当前默认注册的工具
|
|||||||
- bash / shell / http_request / web_fetch 让 Agent 具备更强的外部交互能力(bash 和 shell 是同一工具在不同平台的名称)
|
- bash / shell / http_request / web_fetch 让 Agent 具备更强的外部交互能力(bash 和 shell 是同一工具在不同平台的名称)
|
||||||
- task 允许 Agent 创建独立上下文的子代理来处理复杂多步骤任务,支持内置类型(general)和用户自定义类型
|
- task 允许 Agent 创建独立上下文的子代理来处理复杂多步骤任务,支持内置类型(general)和用户自定义类型
|
||||||
|
|
||||||
### 9.1 MCP 工具集成
|
### 10.1 MCP 工具集成
|
||||||
|
|
||||||
PicoBot 支持通过 MCP (Model Context Protocol) 扩展工具能力,可以连接外部 MCP servers 并自动发现其提供的工具。配置格式兼容 Claude Desktop / Cursor。
|
PicoBot 支持通过 MCP (Model Context Protocol) 扩展工具能力,可以连接外部 MCP servers 并自动发现其提供的工具。配置格式兼容 Claude Desktop / Cursor。
|
||||||
|
|
||||||
@ -709,18 +806,18 @@ MCP 工具会自动注册到 ToolRegistry,命名格式为 `mcp_{server_key}_{t
|
|||||||
- 通过 Tool trait 适配器接入,无需修改核心代码
|
- 通过 Tool trait 适配器接入,无需修改核心代码
|
||||||
- 连接失败不影响 Gateway 运行
|
- 连接失败不影响 Gateway 运行
|
||||||
|
|
||||||
## 10. 调度器机制
|
## 11. 调度器机制
|
||||||
|
|
||||||
PicoBot 带有一个基于 SQLite 的调度器,而不是纯内存或 JSON 文件驱动的任务系统。
|
PicoBot 带有一个基于 SQLite 的调度器,而不是纯内存或 JSON 文件驱动的任务系统。
|
||||||
|
|
||||||
### 10.1 支持的调度类型
|
### 11.1 支持的调度类型
|
||||||
|
|
||||||
- delay:延迟执行一次
|
- delay:延迟执行一次
|
||||||
- interval:固定间隔执行
|
- interval:固定间隔执行
|
||||||
- at:某个绝对时间执行一次
|
- at:某个绝对时间执行一次
|
||||||
- cron:cron 表达式调度
|
- cron:cron 表达式调度
|
||||||
|
|
||||||
### 10.2 支持的任务类型
|
### 11.2 支持的任务类型
|
||||||
|
|
||||||
- internal_event:内部事件
|
- internal_event:内部事件
|
||||||
- outbound_message:直接向目标通道发消息
|
- outbound_message:直接向目标通道发消息
|
||||||
@ -743,7 +840,7 @@ silent_agent_task 和 agent_task 使用同一套 Agent 执行能力,但路由
|
|||||||
- 执行失败时会向主 chat 发送一条失败通知,便于用户感知异常
|
- 执行失败时会向主 chat 发送一条失败通知,便于用户感知异常
|
||||||
- 后台任务的历史、压缩和会话内上下文会留在独立会话中,不污染主会话
|
- 后台任务的历史、压缩和会话内上下文会留在独立会话中,不污染主会话
|
||||||
|
|
||||||
### 10.3 运行时管理
|
### 11.3 运行时管理
|
||||||
|
|
||||||
通过 scheduler_manage 可以进行:
|
通过 scheduler_manage 可以进行:
|
||||||
|
|
||||||
@ -837,15 +934,15 @@ silent_agent_task 和 agent_task 使用同一套 Agent 执行能力,但路由
|
|||||||
- agent_task:用户需要直接收到结果,例如日报提醒、定时播报、定时外发通知
|
- agent_task:用户需要直接收到结果,例如日报提醒、定时播报、定时外发通知
|
||||||
- silent_agent_task:任务需要长期积累独立上下文或后台整理材料,但不应污染主会话,例如周报草稿整理、周期性资料汇总、后台分析任务
|
- silent_agent_task:任务需要长期积累独立上下文或后台整理材料,但不应污染主会话,例如周报草稿整理、周期性资料汇总、后台分析任务
|
||||||
|
|
||||||
## 11. 渠道与运行方式
|
## 12. 渠道与运行方式
|
||||||
|
|
||||||
### 11.1 当前支持的通道
|
### 12.1 当前支持的通道
|
||||||
|
|
||||||
- WebSocket CLI 客户端
|
- WebSocket CLI 客户端
|
||||||
- 飞书通道
|
- 飞书通道
|
||||||
- 微信通道
|
- 微信通道
|
||||||
|
|
||||||
### 11.2 Gateway 接口
|
### 12.2 Gateway 接口
|
||||||
|
|
||||||
网关当前暴露:
|
网关当前暴露:
|
||||||
|
|
||||||
@ -853,7 +950,7 @@ silent_agent_task 和 agent_task 使用同一套 Agent 执行能力,但路由
|
|||||||
- /ws:CLI 客户端连接入口
|
- /ws:CLI 客户端连接入口
|
||||||
- /:Web UI 前端(已嵌入二进制,无需外部文件)
|
- /:Web UI 前端(已嵌入二进制,无需外部文件)
|
||||||
|
|
||||||
### 11.3 Web UI
|
### 12.3 Web UI
|
||||||
|
|
||||||
PicoBot 内置 Web 前端,在编译时已打包进二进制文件。启动网关后可直接访问:
|
PicoBot 内置 Web 前端,在编译时已打包进二进制文件。启动网关后可直接访问:
|
||||||
|
|
||||||
@ -866,7 +963,7 @@ http://127.0.0.1:19876/
|
|||||||
- 支持 SPA 前端路由
|
- 支持 SPA 前端路由
|
||||||
- 开发模式下可通过 `STATIC_DIR` 环境变量使用磁盘文件(支持热更新)
|
- 开发模式下可通过 `STATIC_DIR` 环境变量使用磁盘文件(支持热更新)
|
||||||
|
|
||||||
### 11.4 CLI 使用方式
|
### 12.4 CLI 使用方式
|
||||||
|
|
||||||
程序提供两个主命令:
|
程序提供两个主命令:
|
||||||
|
|
||||||
@ -893,7 +990,7 @@ CLI 中已实现的交互命令包括:
|
|||||||
- /clear
|
- /clear
|
||||||
- /quit
|
- /quit
|
||||||
|
|
||||||
## 12. 配置说明
|
## 13. 配置说明
|
||||||
|
|
||||||
配置默认从以下位置加载:
|
配置默认从以下位置加载:
|
||||||
|
|
||||||
@ -960,9 +1057,9 @@ CLI 中已实现的交互命令包括:
|
|||||||
- tools:工具启用/禁用配置(通过 disabled 列表指定禁用的工具)
|
- tools:工具启用/禁用配置(通过 disabled 列表指定禁用的工具)
|
||||||
- time.timezone:时区,默认应使用 IANA 时区名,例如 Asia/Shanghai
|
- time.timezone:时区,默认应使用 IANA 时区名,例如 Asia/Shanghai
|
||||||
|
|
||||||
## 13. 快速开始
|
## 14. 快速开始
|
||||||
|
|
||||||
### 13.1 准备配置
|
### 14.1 准备配置
|
||||||
|
|
||||||
1. 复制并修改 config.json,或把配置放到 ~/.picobot/config.json
|
1. 复制并修改 config.json,或把配置放到 ~/.picobot/config.json
|
||||||
2. 配置好 Provider 的 base_url、api_key、model_id
|
2. 配置好 Provider 的 base_url、api_key、model_id
|
||||||
@ -1008,7 +1105,7 @@ CLI 中已实现的交互命令包括:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
### 13.2 构建与启动
|
### 14.2 构建与启动
|
||||||
|
|
||||||
> **Windows 用户注意:** Windows 默认不包含 `make` 命令。你可以通过以下方式之一来构建:
|
> **Windows 用户注意:** Windows 默认不包含 `make` 命令。你可以通过以下方式之一来构建:
|
||||||
>
|
>
|
||||||
@ -1081,7 +1178,7 @@ $env:STATIC_DIR="static"; cargo run -- gateway
|
|||||||
| `make run` | `cargo run --release -- gateway` | `cargo run --release -- gateway` |
|
| `make run` | `cargo run --release -- gateway` | `cargo run --release -- gateway` |
|
||||||
| `make check` | `cd web && npm run build && cargo check && cargo clippy` | `cd web; npm run build; cd ..; cargo check; cargo clippy` |
|
| `make check` | `cd web && npm run build && cargo check && cargo clippy` | `cd web; npm run build; cd ..; cargo check; cargo clippy` |
|
||||||
|
|
||||||
### 13.3 启动本地 CLI
|
### 14.3 启动本地 CLI
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cargo run -- agent
|
cargo run -- agent
|
||||||
@ -1099,13 +1196,13 @@ ws://127.0.0.1:19876/ws
|
|||||||
cargo run -- agent --gateway-url ws://127.0.0.1:19876/ws
|
cargo run -- agent --gateway-url ws://127.0.0.1:19876/ws
|
||||||
```
|
```
|
||||||
|
|
||||||
### 13.4 检查服务状态
|
### 14.4 检查服务状态
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl http://127.0.0.1:19876/health
|
curl http://127.0.0.1:19876/health
|
||||||
```
|
```
|
||||||
|
|
||||||
## 14. 目录结构
|
## 15. 目录结构
|
||||||
|
|
||||||
```text
|
```text
|
||||||
PicoBot/
|
PicoBot/
|
||||||
@ -1117,7 +1214,8 @@ PicoBot/
|
|||||||
│ ├── client/ # WebSocket CLI 客户端
|
│ ├── client/ # WebSocket CLI 客户端
|
||||||
│ ├── command/ # 命令系统(处理器、适配器、上下文)
|
│ ├── command/ # 命令系统(处理器、适配器、上下文)
|
||||||
│ ├── config/ # 配置解析
|
│ ├── config/ # 配置解析
|
||||||
│ ├── domain/ # 领域模型(消息、工具定义)
|
│ ├── domain/ # 领域模型(消息、工具定义、能力策略)
|
||||||
|
│ ├── experts/ # 专家系统(发现、加载、运行时管理)
|
||||||
│ ├── gateway/ # Gateway、Session 编排、WS/HTTP 控制面、执行服务
|
│ ├── gateway/ # Gateway、Session 编排、WS/HTTP 控制面、执行服务
|
||||||
│ ├── logging/ # 日志配置
|
│ ├── logging/ # 日志配置
|
||||||
│ ├── mcp/ # MCP 集成(客户端管理、工具适配器、配置)
|
│ ├── mcp/ # MCP 集成(客户端管理、工具适配器、配置)
|
||||||
@ -1136,7 +1234,7 @@ PicoBot/
|
|||||||
└── config.json
|
└── config.json
|
||||||
```
|
```
|
||||||
|
|
||||||
## 15. 测试与维护建议
|
## 16. 测试与维护建议
|
||||||
|
|
||||||
当前 tests 目录中已经包含 Provider 集成测试和工具调用相关测试,但部分测试依赖外部 API Key,需要先准备 tests/test.env。
|
当前 tests 目录中已经包含 Provider 集成测试和工具调用相关测试,但部分测试依赖外部 API Key,需要先准备 tests/test.env。
|
||||||
|
|
||||||
@ -1150,13 +1248,14 @@ PicoBot/
|
|||||||
- src/bus/message.rs:消息结构变更(如 OutboundMessage 新增 session_id)
|
- src/bus/message.rs:消息结构变更(如 OutboundMessage 新增 session_id)
|
||||||
- src/command/handlers/:命令处理器实现
|
- src/command/handlers/:命令处理器实现
|
||||||
|
|
||||||
## 16. 总结
|
## 17. 总结
|
||||||
|
|
||||||
PicoBot 当前已经具备一个可长期运行 Agent 系统的关键组件:
|
PicoBot 当前已经具备一个可长期运行 Agent 系统的关键组件:
|
||||||
|
|
||||||
- 有入口:Gateway + Channel
|
- 有入口:Gateway + Channel
|
||||||
- 有状态:SQLite + Session 恢复
|
- 有状态:SQLite + Session 恢复
|
||||||
- 有能力:工具调用 + 技能系统 + MCP 扩展 + 可自定义子代理
|
- 有能力:工具调用 + 技能系统 + MCP 扩展 + 可自定义子代理
|
||||||
|
- 有角色:专家系统 + 能力策略(工具/技能/子代理黑白名单)+ 模型独立覆盖
|
||||||
- 有记忆:长期记忆 + 自动维护摘要
|
- 有记忆:长期记忆 + 自动维护摘要
|
||||||
- 有计划:Scheduler + agent_task
|
- 有计划:Scheduler + agent_task
|
||||||
|
|
||||||
|
|||||||
@ -7,6 +7,7 @@ export const API = {
|
|||||||
skills: '/api/skills',
|
skills: '/api/skills',
|
||||||
skillsToggle: '/api/skills/toggle',
|
skillsToggle: '/api/skills/toggle',
|
||||||
tools: '/api/tools',
|
tools: '/api/tools',
|
||||||
|
modelOptions: '/api/model-options',
|
||||||
subagents: '/api/subagents',
|
subagents: '/api/subagents',
|
||||||
subagentsToggle: '/api/subagents/toggle',
|
subagentsToggle: '/api/subagents/toggle',
|
||||||
subagentsUpdate: '/api/subagents/update',
|
subagentsUpdate: '/api/subagents/update',
|
||||||
|
|||||||
@ -1,10 +1,14 @@
|
|||||||
import { API, apiGetSilent } from './client'
|
import { API, apiGetSilent } from './client'
|
||||||
import type { ExpertListResponse, ExpertItem, CapabilityPolicy } from '../components/Settings/types'
|
import type { ExpertListResponse, ExpertItem, CapabilityPolicy, ModelOptionsResponse } from '../components/Settings/types'
|
||||||
|
|
||||||
export function listExperts(): Promise<ExpertListResponse | null> {
|
export function listExperts(): Promise<ExpertListResponse | null> {
|
||||||
return apiGetSilent<ExpertListResponse>(API.experts)
|
return apiGetSilent<ExpertListResponse>(API.experts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function listModelOptions(): Promise<ModelOptionsResponse | null> {
|
||||||
|
return apiGetSilent<ModelOptionsResponse>(API.modelOptions)
|
||||||
|
}
|
||||||
|
|
||||||
export async function toggleExpert(name: string, scope: string, enabled: boolean): Promise<Response> {
|
export async function toggleExpert(name: string, scope: string, enabled: boolean): Promise<Response> {
|
||||||
return fetch(API.expertsToggle, {
|
return fetch(API.expertsToggle, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
@ -13,7 +17,7 @@ export async function toggleExpert(name: string, scope: string, enabled: boolean
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function createExpert(payload: { name: string; description: string; body: string; scope: string; capability?: CapabilityPolicy }): Promise<Response> {
|
export async function createExpert(payload: { name: string; description: string; body: string; scope: string; capability?: CapabilityPolicy; provider?: string; model?: string }): Promise<Response> {
|
||||||
return fetch(API.expertsCreate, {
|
return fetch(API.expertsCreate, {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
@ -21,7 +25,7 @@ export async function createExpert(payload: { name: string; description: string;
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function updateExpert(payload: { name: string; scope: string; description?: string; body?: string; capability?: CapabilityPolicy }): Promise<Response> {
|
export async function updateExpert(payload: { name: string; scope: string; description?: string; body?: string; capability?: CapabilityPolicy; provider?: string; model?: string }): Promise<Response> {
|
||||||
return fetch(API.expertsUpdate, {
|
return fetch(API.expertsUpdate, {
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
headers: { 'Content-Type': 'application/json' },
|
headers: { 'Content-Type': 'application/json' },
|
||||||
|
|||||||
@ -18,6 +18,8 @@ export async function updateSubagent(payload: {
|
|||||||
description?: string
|
description?: string
|
||||||
body?: string
|
body?: string
|
||||||
capability?: CapabilityPolicy
|
capability?: CapabilityPolicy
|
||||||
|
provider?: string
|
||||||
|
model?: string
|
||||||
}): Promise<Response> {
|
}): Promise<Response> {
|
||||||
return fetch(API.subagentsUpdate, {
|
return fetch(API.subagentsUpdate, {
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
|
|||||||
@ -16,6 +16,7 @@ import type {
|
|||||||
CapabilityPolicy,
|
CapabilityPolicy,
|
||||||
KnownSource,
|
KnownSource,
|
||||||
SchedulerConfig, ChannelConfig,
|
SchedulerConfig, ChannelConfig,
|
||||||
|
ModelOptionsResponse,
|
||||||
} from './types'
|
} from './types'
|
||||||
import { TABS, inputCls, selectCls, TIMEZONE_OPTIONS } from './constants'
|
import { TABS, inputCls, selectCls, TIMEZONE_OPTIONS } from './constants'
|
||||||
import { Field, Toggle, TagEditor, SectionCard, SourceEditor, MapEntryHeader, CheckboxList, ModalHeader, ModalFooter } from './ui'
|
import { Field, Toggle, TagEditor, SectionCard, SourceEditor, MapEntryHeader, CheckboxList, ModalHeader, ModalFooter } from './ui'
|
||||||
@ -23,7 +24,7 @@ import { getAppConfig, updateAppConfig, restartGateway, checkHealth } from '../.
|
|||||||
import { listSkills, toggleSkill } from '../../api/skills'
|
import { listSkills, toggleSkill } from '../../api/skills'
|
||||||
import { listTools } from '../../api/tools'
|
import { listTools } from '../../api/tools'
|
||||||
import { listSubagents, toggleSubagent, updateSubagent } from '../../api/subagents'
|
import { listSubagents, toggleSubagent, updateSubagent } from '../../api/subagents'
|
||||||
import { listExperts, toggleExpert, createExpert, updateExpert, deleteExpert } from '../../api/experts'
|
import { listExperts, toggleExpert, createExpert, updateExpert, deleteExpert, listModelOptions } from '../../api/experts'
|
||||||
import { getMcpStatus } from '../../api/mcp'
|
import { getMcpStatus } from '../../api/mcp'
|
||||||
export { getSelectedExpert, selectExpert } from '../../api/experts'
|
export { getSelectedExpert, selectExpert } from '../../api/experts'
|
||||||
|
|
||||||
@ -56,6 +57,7 @@ export function ConfigPage({ onClose, onSaveConnection, initialTab }: ConfigPage
|
|||||||
const [subagentListLoading, setSubagentListLoading] = useState(false)
|
const [subagentListLoading, setSubagentListLoading] = useState(false)
|
||||||
const [expertList, setExpertList] = useState<ExpertListResponse | null>(null)
|
const [expertList, setExpertList] = useState<ExpertListResponse | null>(null)
|
||||||
const [expertListLoading, setExpertListLoading] = useState(false)
|
const [expertListLoading, setExpertListLoading] = useState(false)
|
||||||
|
const [modelOptions, setModelOptions] = useState<ModelOptionsResponse | null>(null)
|
||||||
const [editingExpert, setEditingExpert] = useState<{
|
const [editingExpert, setEditingExpert] = useState<{
|
||||||
mode: 'create' | 'edit'
|
mode: 'create' | 'edit'
|
||||||
name?: string
|
name?: string
|
||||||
@ -63,6 +65,8 @@ export function ConfigPage({ onClose, onSaveConnection, initialTab }: ConfigPage
|
|||||||
nameField: string
|
nameField: string
|
||||||
description: string
|
description: string
|
||||||
body: string
|
body: string
|
||||||
|
provider: string
|
||||||
|
model: string
|
||||||
allowedSkills: string[]
|
allowedSkills: string[]
|
||||||
deniedSkills: string[]
|
deniedSkills: string[]
|
||||||
allowedTools: string[]
|
allowedTools: string[]
|
||||||
@ -75,6 +79,8 @@ export function ConfigPage({ onClose, onSaveConnection, initialTab }: ConfigPage
|
|||||||
const [editingSubagent, setEditingSubagent] = useState<{
|
const [editingSubagent, setEditingSubagent] = useState<{
|
||||||
name: string
|
name: string
|
||||||
description: string
|
description: string
|
||||||
|
provider: string
|
||||||
|
model: string
|
||||||
allowedSkills: string[]
|
allowedSkills: string[]
|
||||||
deniedSkills: string[]
|
deniedSkills: string[]
|
||||||
allowedTools: string[]
|
allowedTools: string[]
|
||||||
@ -119,7 +125,7 @@ export function ConfigPage({ onClose, onSaveConnection, initialTab }: ConfigPage
|
|||||||
return toggleSubagent(name, scope, enabled)
|
return toggleSubagent(name, scope, enabled)
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const updateSubagentCb = useCallback(async (payload: { name: string; description?: string; body?: string; capability?: CapabilityPolicy }) => {
|
const updateSubagentCb = useCallback(async (payload: { name: string; description?: string; body?: string; capability?: CapabilityPolicy; provider?: string; model?: string }) => {
|
||||||
return updateSubagent(payload)
|
return updateSubagent(payload)
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
@ -134,11 +140,11 @@ export function ConfigPage({ onClose, onSaveConnection, initialTab }: ConfigPage
|
|||||||
return toggleExpert(name, scope, enabled)
|
return toggleExpert(name, scope, enabled)
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const createExpertCb = useCallback(async (payload: { name: string; description: string; body: string; scope: string; capability?: CapabilityPolicy }) => {
|
const createExpertCb = useCallback(async (payload: { name: string; description: string; body: string; scope: string; capability?: CapabilityPolicy; provider?: string; model?: string }) => {
|
||||||
return createExpert(payload)
|
return createExpert(payload)
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const updateExpertCb = useCallback(async (payload: { name: string; scope: string; description?: string; body?: string; capability?: CapabilityPolicy }) => {
|
const updateExpertCb = useCallback(async (payload: { name: string; scope: string; description?: string; body?: string; capability?: CapabilityPolicy; provider?: string; model?: string }) => {
|
||||||
return updateExpert(payload)
|
return updateExpert(payload)
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
@ -175,13 +181,14 @@ export function ConfigPage({ onClose, onSaveConnection, initialTab }: ConfigPage
|
|||||||
if (activeTab === 'subagents') fetchSubagentList()
|
if (activeTab === 'subagents') fetchSubagentList()
|
||||||
}, [activeTab, fetchSubagentList])
|
}, [activeTab, fetchSubagentList])
|
||||||
|
|
||||||
// Fetch skills + tools when experts/subagents tab is selected (for capability CheckboxList)
|
// Fetch skills + tools + model options when experts/subagents tab is selected (for capability CheckboxList & provider/model dropdowns)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (activeTab === 'experts' || activeTab === 'subagents') {
|
if (activeTab === 'experts' || activeTab === 'subagents') {
|
||||||
if (!skillList) fetchSkillList()
|
if (!skillList) fetchSkillList()
|
||||||
if (!toolList) fetchToolList()
|
if (!toolList) fetchToolList()
|
||||||
|
if (!modelOptions) listModelOptions().then(data => { if (data) setModelOptions(data) })
|
||||||
}
|
}
|
||||||
}, [activeTab, fetchSkillList, fetchToolList, skillList, toolList])
|
}, [activeTab, fetchSkillList, fetchToolList, skillList, toolList, modelOptions])
|
||||||
|
|
||||||
// experts tab 编辑专家时也需要子代理勾选列表,按需加载(subagents tab 由下方独立 useEffect 刷新)
|
// experts tab 编辑专家时也需要子代理勾选列表,按需加载(subagents tab 由下方独立 useEffect 刷新)
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@ -707,6 +714,8 @@ export function ConfigPage({ onClose, onSaveConnection, initialTab }: ConfigPage
|
|||||||
setEditingSubagent({
|
setEditingSubagent({
|
||||||
name: subagent.name,
|
name: subagent.name,
|
||||||
description: subagent.description,
|
description: subagent.description,
|
||||||
|
provider: subagent.provider ?? '',
|
||||||
|
model: subagent.model ?? '',
|
||||||
allowedSkills: subagent.capability?.allowed_skills ?? [],
|
allowedSkills: subagent.capability?.allowed_skills ?? [],
|
||||||
deniedSkills: subagent.capability?.denied_skills ?? [],
|
deniedSkills: subagent.capability?.denied_skills ?? [],
|
||||||
allowedTools: subagent.capability?.allowed_tools ?? [],
|
allowedTools: subagent.capability?.allowed_tools ?? [],
|
||||||
@ -781,7 +790,7 @@ export function ConfigPage({ onClose, onSaveConnection, initialTab }: ConfigPage
|
|||||||
<button
|
<button
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setEditingExpertError('')
|
setEditingExpertError('')
|
||||||
setEditingExpert({ mode: 'create', scope: 'project', nameField: '', description: '', body: '', allowedSkills: [], deniedSkills: [], allowedTools: [], deniedTools: [], allowedSubagents: [], deniedSubagents: [] })
|
setEditingExpert({ mode: 'create', scope: 'project', nameField: '', description: '', body: '', provider: '', model: '', allowedSkills: [], deniedSkills: [], allowedTools: [], deniedTools: [], allowedSubagents: [], deniedSubagents: [] })
|
||||||
}}
|
}}
|
||||||
className="flex items-center gap-2 px-4 py-2.5 rounded-xl border border-dashed border-[var(--border-color)] text-[var(--text-muted)] hover:text-[var(--accent-cyan)] hover:border-[var(--accent-cyan)]/30 transition-colors text-sm w-full justify-center"
|
className="flex items-center gap-2 px-4 py-2.5 rounded-xl border border-dashed border-[var(--border-color)] text-[var(--text-muted)] hover:text-[var(--accent-cyan)] hover:border-[var(--accent-cyan)]/30 transition-colors text-sm w-full justify-center"
|
||||||
>
|
>
|
||||||
@ -840,6 +849,8 @@ export function ConfigPage({ onClose, onSaveConnection, initialTab }: ConfigPage
|
|||||||
nameField: expert.name,
|
nameField: expert.name,
|
||||||
description: expert.description,
|
description: expert.description,
|
||||||
body: expert.body ?? '',
|
body: expert.body ?? '',
|
||||||
|
provider: expert.provider ?? '',
|
||||||
|
model: expert.model ?? '',
|
||||||
allowedSkills: expert.capability?.allowed_skills ?? [],
|
allowedSkills: expert.capability?.allowed_skills ?? [],
|
||||||
deniedSkills: expert.capability?.denied_skills ?? [],
|
deniedSkills: expert.capability?.denied_skills ?? [],
|
||||||
allowedTools: expert.capability?.allowed_tools ?? [],
|
allowedTools: expert.capability?.allowed_tools ?? [],
|
||||||
@ -947,6 +958,8 @@ export function ConfigPage({ onClose, onSaveConnection, initialTab }: ConfigPage
|
|||||||
description: editingExpert.description,
|
description: editingExpert.description,
|
||||||
body: editingExpert.body,
|
body: editingExpert.body,
|
||||||
capability,
|
capability,
|
||||||
|
provider: editingExpert.provider || undefined,
|
||||||
|
model: editingExpert.model || undefined,
|
||||||
}
|
}
|
||||||
const resp = isEdit
|
const resp = isEdit
|
||||||
? await updateExpertCb({ ...payload, scope: 'project' })
|
? await updateExpertCb({ ...payload, scope: 'project' })
|
||||||
@ -1008,6 +1021,28 @@ export function ConfigPage({ onClose, onSaveConnection, initialTab }: ConfigPage
|
|||||||
/>
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
</SectionCard>
|
</SectionCard>
|
||||||
|
<SectionCard title="模型配置" subtitle="留空继承默认">
|
||||||
|
<Field label="Provider" hint="留空继承默认配置">
|
||||||
|
<select
|
||||||
|
value={editingExpert.provider}
|
||||||
|
onChange={e => setEditingExpert(prev => prev ? { ...prev, provider: e.target.value } : prev)}
|
||||||
|
className={selectCls}
|
||||||
|
>
|
||||||
|
<option value="">继承默认</option>
|
||||||
|
{(modelOptions?.providers ?? []).map(p => <option key={p} value={p}>{p}</option>)}
|
||||||
|
</select>
|
||||||
|
</Field>
|
||||||
|
<Field label="Model" hint="留空继承默认配置">
|
||||||
|
<select
|
||||||
|
value={editingExpert.model}
|
||||||
|
onChange={e => setEditingExpert(prev => prev ? { ...prev, model: e.target.value } : prev)}
|
||||||
|
className={selectCls}
|
||||||
|
>
|
||||||
|
<option value="">继承默认</option>
|
||||||
|
{(modelOptions?.models ?? []).map(m => <option key={m} value={m}>{m}</option>)}
|
||||||
|
</select>
|
||||||
|
</Field>
|
||||||
|
</SectionCard>
|
||||||
<SectionCard title="技能能力" subtitle="白名单取交集,黑名单扣除">
|
<SectionCard title="技能能力" subtitle="白名单取交集,黑名单扣除">
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
|
||||||
<Field label="允许的技能(白名单)" hint="留空表示不限">
|
<Field label="允许的技能(白名单)" hint="留空表示不限">
|
||||||
@ -1133,6 +1168,8 @@ export function ConfigPage({ onClose, onSaveConnection, initialTab }: ConfigPage
|
|||||||
name: editingSubagent.name,
|
name: editingSubagent.name,
|
||||||
description: editingSubagent.description,
|
description: editingSubagent.description,
|
||||||
capability,
|
capability,
|
||||||
|
provider: editingSubagent.provider || undefined,
|
||||||
|
model: editingSubagent.model || undefined,
|
||||||
})
|
})
|
||||||
const data = await resp.json().catch(() => ({}))
|
const data = await resp.json().catch(() => ({}))
|
||||||
if (!resp.ok) {
|
if (!resp.ok) {
|
||||||
@ -1179,6 +1216,28 @@ export function ConfigPage({ onClose, onSaveConnection, initialTab }: ConfigPage
|
|||||||
/>
|
/>
|
||||||
</Field>
|
</Field>
|
||||||
</SectionCard>
|
</SectionCard>
|
||||||
|
<SectionCard title="模型配置" subtitle="留空继承默认">
|
||||||
|
<Field label="Provider" hint="留空继承默认配置">
|
||||||
|
<select
|
||||||
|
value={editingSubagent.provider}
|
||||||
|
onChange={e => setEditingSubagent(prev => prev ? { ...prev, provider: e.target.value } : prev)}
|
||||||
|
className={selectCls}
|
||||||
|
>
|
||||||
|
<option value="">继承默认</option>
|
||||||
|
{(modelOptions?.providers ?? []).map(p => <option key={p} value={p}>{p}</option>)}
|
||||||
|
</select>
|
||||||
|
</Field>
|
||||||
|
<Field label="Model" hint="留空继承默认配置">
|
||||||
|
<select
|
||||||
|
value={editingSubagent.model}
|
||||||
|
onChange={e => setEditingSubagent(prev => prev ? { ...prev, model: e.target.value } : prev)}
|
||||||
|
className={selectCls}
|
||||||
|
>
|
||||||
|
<option value="">继承默认</option>
|
||||||
|
{(modelOptions?.models ?? []).map(m => <option key={m} value={m}>{m}</option>)}
|
||||||
|
</select>
|
||||||
|
</Field>
|
||||||
|
</SectionCard>
|
||||||
<SectionCard title="技能能力" subtitle="白名单取交集,黑名单扣除">
|
<SectionCard title="技能能力" subtitle="白名单取交集,黑名单扣除">
|
||||||
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
|
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
|
||||||
<Field label="允许的技能(白名单)" hint="留空表示不限。仅勾选的 SKILL.md 技能可见">
|
<Field label="允许的技能(白名单)" hint="留空表示不限。仅勾选的 SKILL.md 技能可见">
|
||||||
|
|||||||
@ -52,6 +52,12 @@ export interface ToolsListResponse {
|
|||||||
tools: ToolItem[]
|
tools: ToolItem[]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** GET /api/model-options 返回可用的 provider/model 名列表(供专家/子代理编辑下拉框) */
|
||||||
|
export interface ModelOptionsResponse {
|
||||||
|
providers: string[]
|
||||||
|
models: string[]
|
||||||
|
}
|
||||||
|
|
||||||
export interface CapabilityPolicy {
|
export interface CapabilityPolicy {
|
||||||
allowed_skills?: string[]
|
allowed_skills?: string[]
|
||||||
denied_skills: string[]
|
denied_skills: string[]
|
||||||
@ -67,6 +73,8 @@ export interface SubagentItem {
|
|||||||
source: string
|
source: string
|
||||||
disabled_in_scopes: string[]
|
disabled_in_scopes: string[]
|
||||||
capability?: CapabilityPolicy
|
capability?: CapabilityPolicy
|
||||||
|
provider?: string
|
||||||
|
model?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SubagentListResponse {
|
export interface SubagentListResponse {
|
||||||
@ -84,6 +92,8 @@ export interface ExpertItem {
|
|||||||
body?: string
|
body?: string
|
||||||
disabled_in_scopes: string[]
|
disabled_in_scopes: string[]
|
||||||
capability?: CapabilityPolicy
|
capability?: CapabilityPolicy
|
||||||
|
provider?: string
|
||||||
|
model?: string
|
||||||
}
|
}
|
||||||
export interface ExpertListResponse {
|
export interface ExpertListResponse {
|
||||||
experts_system_enabled: boolean
|
experts_system_enabled: boolean
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user