init repo
This commit is contained in:
@@ -0,0 +1,45 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: Agent 构建与 SKILL 注入
|
||||
系统 SHALL 提供一个 Agent 构建函数/类,接受 SKILL 列表和 LLM 配置,创建一个集成了 SKILL 上下文的 LlamaIndex AgentWorkflow。
|
||||
|
||||
#### Scenario: 使用 SKILL 列表创建 Agent
|
||||
- **WHEN** 调用 Agent 构建函数,传入一个包含 2 个 Skill 实例的列表和 LLM 配置
|
||||
- **THEN** 创建的 AgentWorkflow 的 system prompt 中包含这 2 个 Skill 的 `name`、`description` 和 `body` 内容
|
||||
|
||||
#### Scenario: 无 SKILL 创建 Agent
|
||||
- **WHEN** 调用 Agent 构建函数,传入空的 SKILL 列表
|
||||
- **THEN** 创建的 AgentWorkflow 仅包含基础 system prompt,不含任何 SKILL 上下文
|
||||
|
||||
### Requirement: System Prompt 组装
|
||||
系统 SHALL 按照固定格式将多个 SKILL 的内容组装到 system prompt 中,每个 SKILL 之间用分隔符隔开。
|
||||
|
||||
#### Scenario: 多 SKILL 的 prompt 格式
|
||||
- **WHEN** 注入 2 个名为 "skill-a" 和 "skill-b" 的 SKILL
|
||||
- **THEN** 生成的 system prompt 依次包含基础 prompt、"## Active Skills" 标题、每个 SKILL 的 "### Skill: {name}" 标题及其 body 内容,SKILL 之间用 `---` 分隔
|
||||
|
||||
#### Scenario: SKILL 顺序保持一致
|
||||
- **WHEN** 按 ["skill-b", "skill-a"] 顺序注入 SKILL
|
||||
- **THEN** system prompt 中 skill-b 的内容出现在 skill-a 之前
|
||||
|
||||
### Requirement: Agent 对话执行
|
||||
系统 SHALL 提供运行 Agent 的能力,接受用户输入并返回 LLM 响应。
|
||||
|
||||
#### Scenario: 单轮对话
|
||||
- **WHEN** 向 Agent 发送一条用户消息
|
||||
- **THEN** Agent 调用 LLM 并返回文本响应
|
||||
|
||||
#### Scenario: 带工具的对话
|
||||
- **WHEN** Agent 配置了工具函数,且用户消息触发了工具调用
|
||||
- **THEN** Agent 执行工具调用并将结果整合到最终响应中
|
||||
|
||||
### Requirement: 工具注册
|
||||
系统 SHALL 支持在创建 Agent 时注册 Python 可调用函数作为工具。
|
||||
|
||||
#### Scenario: 注册 Python 函数为工具
|
||||
- **WHEN** 传入一个带 docstring 的 Python 函数到 Agent 构建函数的 `tools` 参数
|
||||
- **THEN** 该函数被注册为 LlamaIndex 工具,Agent 可在对话中调用它
|
||||
|
||||
#### Scenario: 无工具的 Agent
|
||||
- **WHEN** 创建 Agent 时不传入任何工具
|
||||
- **THEN** Agent 正常运行,仅进行对话,不进行工具调用
|
||||
@@ -0,0 +1,38 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: SKILL.md 文件解析
|
||||
系统 SHALL 能够解析符合标准格式的 SKILL.md 文件,提取 YAML frontmatter 中的元数据和 Markdown 正文中的指令内容。
|
||||
|
||||
#### Scenario: 解析标准 SKILL.md 文件
|
||||
- **WHEN** 提供一个包含 YAML frontmatter(`---` 分隔)和 Markdown 正文的 SKILL.md 文件路径
|
||||
- **THEN** 系统返回一个 Skill 对象,包含 `name`(str)、`description`(str)、`metadata`(dict)和 `body`(str)字段
|
||||
|
||||
#### Scenario: 解析缺少必填字段的 SKILL.md
|
||||
- **WHEN** 提供的 SKILL.md 文件的 frontmatter 中缺少 `name` 字段
|
||||
- **THEN** 系统抛出 `SkillLoadError` 异常,包含明确的错误描述
|
||||
|
||||
#### Scenario: 解析无 frontmatter 的文件
|
||||
- **WHEN** 提供的文件不包含 YAML frontmatter(无 `---` 分隔符)
|
||||
- **THEN** 系统抛出 `SkillLoadError` 异常,提示文件格式不合法
|
||||
|
||||
### Requirement: Skill 数据模型
|
||||
系统 SHALL 提供一个 `Skill` 数据类(dataclass 或 Pydantic model),用于表示解析后的 SKILL 实例。
|
||||
|
||||
#### Scenario: Skill 数据模型包含所有必要字段
|
||||
- **WHEN** 创建一个 Skill 实例
|
||||
- **THEN** 该实例 MUST 包含以下字段:`name`(str,必填)、`description`(str,必填)、`body`(str,必填)、`metadata`(dict,可选,默认空 dict)、`source_path`(Path | None,可选)
|
||||
|
||||
#### Scenario: Skill 实例不可变
|
||||
- **WHEN** 尝试修改已创建的 Skill 实例的 `name` 字段
|
||||
- **THEN** 系统抛出异常(frozen dataclass / immutable model)
|
||||
|
||||
### Requirement: Frontmatter 元数据提取
|
||||
系统 SHALL 从 YAML frontmatter 中提取以下标准字段:`name`、`description`、`license`、`compatibility`、`metadata`(包含 `author`、`version`、`generatedBy`)。
|
||||
|
||||
#### Scenario: 提取完整的 metadata
|
||||
- **WHEN** SKILL.md 的 frontmatter 包含 `metadata: { author: "test", version: "1.0" }`
|
||||
- **THEN** 解析结果的 `metadata` 字段为 `{"author": "test", "version": "1.0"}`
|
||||
|
||||
#### Scenario: metadata 缺失时使用默认值
|
||||
- **WHEN** SKILL.md 的 frontmatter 不包含 `metadata` 字段
|
||||
- **THEN** 解析结果的 `metadata` 字段为空 dict `{}`
|
||||
@@ -0,0 +1,57 @@
|
||||
## ADDED Requirements
|
||||
|
||||
### Requirement: SKILL 目录扫描
|
||||
系统 SHALL 能够扫描指定目录,自动发现并加载所有 SKILL.md 文件。
|
||||
|
||||
#### Scenario: 扫描包含多个 SKILL 的目录
|
||||
- **WHEN** 指定一个包含 3 个子目录、每个子目录有一个 SKILL.md 文件的目录路径
|
||||
- **THEN** 系统返回 3 个 Skill 实例的列表
|
||||
|
||||
#### Scenario: 扫描空目录
|
||||
- **WHEN** 指定一个不包含任何 SKILL.md 文件的目录路径
|
||||
- **THEN** 系统返回空列表,不抛出异常
|
||||
|
||||
#### Scenario: 扫描不存在的目录
|
||||
- **WHEN** 指定一个不存在的目录路径
|
||||
- **THEN** 系统抛出 `FileNotFoundError` 异常
|
||||
|
||||
#### Scenario: 跳过无效的 SKILL 文件
|
||||
- **WHEN** 目录中包含 2 个有效 SKILL.md 和 1 个格式错误的 SKILL.md
|
||||
- **THEN** 系统返回 2 个有效 Skill 实例,并通过日志记录无效文件的错误信息
|
||||
|
||||
### Requirement: SKILL 注册表
|
||||
系统 SHALL 提供一个 SkillRegistry 类,用于管理已注册的 SKILL 实例。
|
||||
|
||||
#### Scenario: 注册 SKILL
|
||||
- **WHEN** 调用 `registry.register(skill)` 注册一个 Skill 实例
|
||||
- **THEN** 该 Skill 被存储在注册表中,可通过 `registry.get(skill.name)` 获取
|
||||
|
||||
#### Scenario: 注册同名 SKILL 覆盖
|
||||
- **WHEN** 先后注册两个 `name` 相同但 `body` 不同的 Skill
|
||||
- **THEN** 注册表中保留后注册的 Skill,前一个被覆盖
|
||||
|
||||
#### Scenario: 注销 SKILL
|
||||
- **WHEN** 调用 `registry.unregister("skill-name")`
|
||||
- **THEN** 该 SKILL 从注册表中移除,`registry.get("skill-name")` 返回 None
|
||||
|
||||
#### Scenario: 注销不存在的 SKILL
|
||||
- **WHEN** 调用 `registry.unregister("nonexistent")`
|
||||
- **THEN** 不抛出异常,静默忽略
|
||||
|
||||
### Requirement: 列出所有已注册 SKILL
|
||||
系统 SHALL 提供查询所有已注册 SKILL 的能力。
|
||||
|
||||
#### Scenario: 列出所有 SKILL
|
||||
- **WHEN** 注册了 3 个 SKILL 后调用 `registry.list_skills()`
|
||||
- **THEN** 返回包含 3 个 Skill 实例的列表
|
||||
|
||||
#### Scenario: 空注册表列出 SKILL
|
||||
- **WHEN** 未注册任何 SKILL 时调用 `registry.list_skills()`
|
||||
- **THEN** 返回空列表
|
||||
|
||||
### Requirement: 从目录批量加载到注册表
|
||||
系统 SHALL 提供一个便捷方法,将目录扫描和注册合并为一步操作。
|
||||
|
||||
#### Scenario: 从目录加载所有 SKILL
|
||||
- **WHEN** 调用 `registry.load_from_directory(path)` 传入包含 3 个有效 SKILL.md 的目录
|
||||
- **THEN** 注册表中包含 3 个 SKILL,可通过 `registry.list_skills()` 获取
|
||||
Reference in New Issue
Block a user