Initial commit
This commit is contained in:
150
docs/architecture.md
Normal file
150
docs/architecture.md
Normal file
@@ -0,0 +1,150 @@
|
||||
# 整体架构
|
||||
|
||||
## 1. 方向
|
||||
|
||||
**标签驱动黑板** + **agent tool loop** + **5 相位阶段机** + **skill 能力库**。
|
||||
|
||||
```text
|
||||
Skill 包(orchestrator manifest + workers/*/SKILL.md) 静态能力定义
|
||||
Session + 黑板 tag 一次运行的实参
|
||||
Book 跨 Session 的项目与资产
|
||||
|
||||
Agent(总管) running 相位内 tool loop,调度 invoke 哪个 skill
|
||||
Runtime 拼接上下文、校验 tool、写黑板、驱动阶段机边界
|
||||
阶段机 谁可动、何时等用户、产物生命周期——不是流水线剧本
|
||||
```
|
||||
|
||||
核心文档:
|
||||
|
||||
```text
|
||||
docs/tag-blackboard.md 黑板、标签、分工
|
||||
docs/context-assembly.md ★ 上下文拼接(上半固定、下半动态)
|
||||
docs/tool-contracts.md 总管 / worker tool
|
||||
docs/runtime-state-machine.md 5 相位、tool 边界
|
||||
docs/book-storage.md 长期存储(过程 / 资产 / 游玩)
|
||||
docs/skill-design-guide.md 新 skill 包设计方法
|
||||
docs/implementation-guide.md 代码文件职责
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 术语
|
||||
|
||||
| 词 | 含义 |
|
||||
|----|------|
|
||||
| **skill** | `SKILL.md` 定义的能力(设计期能力库中的一条) |
|
||||
| **worker** | 某 skill 被 invoke 的一次执行 |
|
||||
| **stage** | 业务阶段:`design`(实例化)→ `play`(运行)→ `done` |
|
||||
| **phase** | 运行相位:`idle` \| `running` \| `waiting_user` \| `done` \| `error` |
|
||||
|
||||
不使用 **step** 指代设计步骤编号,避免与管道混淆。
|
||||
|
||||
---
|
||||
|
||||
## 3. Agent tool loop
|
||||
|
||||
```text
|
||||
用户硬事件(输入 / 确认 / 验收)
|
||||
→ phase = running,toolLoopBurst 计数归零
|
||||
→ while running && burst < N:
|
||||
LLM(messages, tools)
|
||||
→ 循环 tool(read_blackboard …)→ 结果 append 到 messages
|
||||
→ 边界 tool(run_worker / ask_user / finish)→ 退出 burst
|
||||
→ 若需用户 → waiting_user
|
||||
```
|
||||
|
||||
- **burst 上限 N**:两次用户操作之间的最大推理轮数,非 Session 终身额度。
|
||||
- **循环 tool**:不改 phase,只追加 agent 对话。
|
||||
- **边界 tool**:触发阶段机转移(等用户、跑 worker、结束)。
|
||||
|
||||
代码:`src/main-agent/tool-loop.ts`、`src/runtime/phase-runtime.ts`。
|
||||
|
||||
目标态:worker 执行也用 tool loop(`submit` / `ask_user`),上下文仍由 Runtime 拼接,见 `docs/tool-contracts.md`。
|
||||
|
||||
---
|
||||
|
||||
## 4. 阶段机做什么
|
||||
|
||||
阶段机 **不是** 编排表执行器,而是:
|
||||
|
||||
```text
|
||||
1. Actor 门禁 此刻用户 / agent / worker 谁在场
|
||||
2. Tool 边界 当前态允许哪些 tool
|
||||
3. 事实生命周期 draft → accepted;用户才能 accept
|
||||
4. 等待原因 waitingReason 细分等什么
|
||||
```
|
||||
|
||||
业务「先跑哪个 skill」由 **agent 在 tool loop 里决定**,不由 orchestrator 逐步剧本写死。
|
||||
|
||||
---
|
||||
|
||||
## 5. 实例化:skill 能力库
|
||||
|
||||
实例化 = agent 在 `design` stage 按需 invoke **instantiate skill**(原「设计步骤」),不是固定 1→14 管道。
|
||||
|
||||
```text
|
||||
交互范式 skill → 产出 设计.run_skill清单(run 阶段需要哪些 skill)
|
||||
每个 run skill 倒推 → 缺什么 instantiate skill → agent invoke
|
||||
declare_instance_ready → 进入 play stage
|
||||
```
|
||||
|
||||
orchestrator.md = **manifest**(有哪些 skill、约束、验收策略),不是逐步思维链。
|
||||
|
||||
---
|
||||
|
||||
## 6. 上下文拼接
|
||||
|
||||
**上半固定、下半动态**。规则在 skill 定义 + 实例 contextProfile;Runtime 执行。
|
||||
见 `docs/context-assembly.md`。
|
||||
|
||||
---
|
||||
|
||||
## 7. 模块
|
||||
|
||||
```text
|
||||
phase-machine.ts 纯函数:event → phase(边界规则)
|
||||
phase-runtime.ts Session IO、tool loop 驱动、worker 执行
|
||||
main-agent/ tool loop、tool 定义
|
||||
worker/executor.ts assembleWorkerContext、run skill
|
||||
blackboard.ts tag 池
|
||||
skills/loader.ts 解析 orchestrator + SKILL.md
|
||||
book/ Book、快照、持久化
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. 数据流(目标态)
|
||||
|
||||
```text
|
||||
选 orchestrator 包
|
||||
→ design:agent burst → invoke instantiate skills → 设计.* tag
|
||||
→ declare ready → play
|
||||
→ play:用户输入 → agent burst → invoke run skills → 运行.* tag
|
||||
→ 过程/资产/游玩 归档 Book(见 book-storage.md)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. 边界
|
||||
|
||||
```text
|
||||
Agent 调度 skill;read_blackboard;不传 inputTags;不写黑板(边界 tool 除外)
|
||||
Runtime 拼接上下文;校验 tool;写黑板;执行 worker
|
||||
Worker LLM 在拼接后的 prompt 内产出;submit 写 declared outputTags
|
||||
用户 approve、accept、输入
|
||||
阶段机 只响应 event,不调 LLM
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. 实现进度(摘要)
|
||||
|
||||
```text
|
||||
✅ phase-machine、phase-runtime、skills loader
|
||||
✅ 总管 tool loop(read_blackboard、run_worker、…)
|
||||
⬜ toolLoopBurst 按用户事件归零
|
||||
⬜ assembleWorkerContext(contextSegments)
|
||||
⬜ worker tool loop
|
||||
⬜ Book:designTrace / CardAsset / PlayBook
|
||||
⬜ orchestrator 从编排表迁为 manifest
|
||||
```
|
||||
246
docs/book-storage.md
Normal file
246
docs/book-storage.md
Normal file
@@ -0,0 +1,246 @@
|
||||
# Book 存储模型
|
||||
|
||||
## 1. 定位
|
||||
|
||||
Book = **长期项目容器**。Session = 一次打开的运行进程。黑板 = Session 内运行时 tag。
|
||||
|
||||
存储须同时满足:
|
||||
|
||||
```text
|
||||
1. 保存「创建过程」(designTrace / playTrace)
|
||||
2. 保存「创建结果」(可复用资产,如角色卡)
|
||||
3. 保存「游玩过程」(对话、轮次、变量、存档点)
|
||||
```
|
||||
|
||||
第一版约束:不存 API key;历史与当前分离;accepted 才升为「当前事实」。
|
||||
|
||||
---
|
||||
|
||||
## 2. 三种 Book 形态
|
||||
|
||||
| 形态 | 用途 | 典型 kind |
|
||||
|------|------|-----------|
|
||||
| **CardBook** | 创作角色卡(design stage) | `character_card_design` |
|
||||
| **CardAsset** | 从 CardBook 导出的可复用卡 | 资产条目,可挂卡库 |
|
||||
| **PlayBook** | 用某张卡(+ 可选世界)游玩 | `character_card_play` / `roleplay` |
|
||||
| **ProjectBook** | 小说等项目(沿用) | `novel` |
|
||||
|
||||
同一用户可:CardBook 创作 → 导出 CardAsset → 新建 PlayBook 引用该卡。
|
||||
|
||||
---
|
||||
|
||||
## 3. CardBook(创建角色卡)
|
||||
|
||||
### 3.1 存什么
|
||||
|
||||
```ts
|
||||
type CardBook = {
|
||||
id: string;
|
||||
title: string;
|
||||
orchestratorId: string;
|
||||
lifecycleStage: "design" | "archived";
|
||||
|
||||
/** 创作过程:可时间线展示、可续作设计 */
|
||||
designTrace: DesignTraceEntry[];
|
||||
|
||||
/** 运行时黑板快照(设计.* tag) */
|
||||
designArtifacts: TaggedArtifact[];
|
||||
|
||||
/** 用户可见对话;agent tool 对话可另存 agentTrace */
|
||||
messages: PersistedChatMessage[];
|
||||
|
||||
runSkillManifest?: RunSkillManifest; // 设计完成后:建议如何游玩
|
||||
readiness?: InstanceReadiness;
|
||||
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
};
|
||||
```
|
||||
|
||||
```ts
|
||||
type DesignTraceEntry = {
|
||||
at: string;
|
||||
type:
|
||||
| "user_input"
|
||||
| "agent_tool"
|
||||
| "skill_invoked"
|
||||
| "user_confirmed"
|
||||
| "user_rejected"
|
||||
| "declare_ready";
|
||||
skillId?: string;
|
||||
tool?: string;
|
||||
summary: string;
|
||||
outputTags?: string[];
|
||||
};
|
||||
```
|
||||
|
||||
**过程** = `designTrace` + `messages`(+ 可选 `agentTrace`)。
|
||||
**不是**预定实体槽填表;agent 调了哪些 instantiate skill,过程里就记哪些。
|
||||
|
||||
### 3.2 导出 CardAsset(创建结果)
|
||||
|
||||
```ts
|
||||
type CardAsset = {
|
||||
id: string;
|
||||
cardBookId: string;
|
||||
title: string;
|
||||
tags: Record<string, string>; // 角色卡.确认稿、角色.设定、口吻…
|
||||
runSkillManifest?: RunSkillManifest;
|
||||
confirmedAt: string;
|
||||
};
|
||||
```
|
||||
|
||||
游玩时 **加载 CardAsset**,不必重跑完整 design。
|
||||
|
||||
---
|
||||
|
||||
## 4. PlayBook(游玩角色卡 / 扮演)
|
||||
|
||||
```ts
|
||||
type PlayBook = {
|
||||
id: string;
|
||||
title: string;
|
||||
orchestratorId: string;
|
||||
lifecycleStage: "play" | "archived";
|
||||
|
||||
cardRef: { assetId: string; version?: string };
|
||||
worldRef?: { assetId?: string };
|
||||
|
||||
contextProfile: ContextProfile; // 实例化选的 variant
|
||||
runSkillManifest: RunSkillManifest;
|
||||
|
||||
playTrace: PlayTraceEntry[];
|
||||
runState: {
|
||||
turn: number;
|
||||
variables: Record<string, unknown>;
|
||||
eventStream: string;
|
||||
};
|
||||
|
||||
messages: PersistedChatMessage[];
|
||||
snapshotIds: string[];
|
||||
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
};
|
||||
```
|
||||
|
||||
```ts
|
||||
type PlayTraceEntry = {
|
||||
at: string;
|
||||
turn?: number;
|
||||
type: "user_input" | "skill_invoked" | "artifact" | "snapshot";
|
||||
skillId?: string;
|
||||
summary: string;
|
||||
};
|
||||
```
|
||||
|
||||
**游玩过程** = `playTrace` + `messages` + `runState`。
|
||||
**游玩存档** = `RunSnapshot`(kind=`run`),见 `run-snapshot.md`。
|
||||
|
||||
---
|
||||
|
||||
## 5. ProjectBook(小说等)
|
||||
|
||||
保留原 `BookProject` + `BookContentRecord` 思路:
|
||||
|
||||
```ts
|
||||
type BookProject = {
|
||||
id: string;
|
||||
title: string;
|
||||
orchestratorId: string;
|
||||
kind: "novel" | "forum" | "weird_rules" | "custom";
|
||||
lifecycleStage: "design" | "play" | "done";
|
||||
currentContentId?: string;
|
||||
historyContentIds: string[];
|
||||
designTrace?: DesignTraceEntry[];
|
||||
sessionIds: string[];
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
};
|
||||
```
|
||||
|
||||
小说正文仍用 `BookContentRecord`(outline/chapter);design 阶段 tag 可进 `designArtifacts`。
|
||||
|
||||
---
|
||||
|
||||
## 6. Session 与 Book
|
||||
|
||||
```text
|
||||
Session(PersistedBookSession)
|
||||
当前打开的 working copy:RuntimeSession + 黑板 + messages
|
||||
关闭时可合并进 Book 的 trace / runState
|
||||
|
||||
Book
|
||||
稳定事实 + 过程记录 + 资产引用
|
||||
|
||||
沉淀规则
|
||||
design accepted tag → CardBook.designArtifacts / 导出 CardAsset
|
||||
play accepted tag → PlayBook.runState + 黑板归档
|
||||
draft / rejected → trace 记一笔,默认不升 current
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. 与状态机
|
||||
|
||||
```text
|
||||
worker_completed → draft
|
||||
user_accepted_artifact / no_confirmation / programmatic_pass
|
||||
→ 可写 Book(由 Runtime,非 agent 直接写)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. 与黑板
|
||||
|
||||
| 阶段 | 黑板前缀示例 | 归档到 |
|
||||
|------|--------------|--------|
|
||||
| design | `设计.*`、`用户.需求` | CardBook / ProjectBook design |
|
||||
| play | `运行.*`、`世界.*`、`输出.*` | PlayBook runState |
|
||||
|
||||
上下文拼接读黑板;Book 存 **确认稿与过程**,见 `context-assembly.md`。
|
||||
|
||||
---
|
||||
|
||||
## 9. 存储布局(建议)
|
||||
|
||||
```text
|
||||
books/{bookId}/project.json
|
||||
books/{bookId}/design-artifacts.json
|
||||
books/{bookId}/traces.jsonl
|
||||
books/{bookId}/contents/{contentId}.json # 小说正文
|
||||
assets/cards/{assetId}.json # CardAsset 卡库
|
||||
books/{bookId}/snapshots/{snapshotId}.json
|
||||
sessions/{sessionId}.json # 可选 working copy
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. 实现优先级
|
||||
|
||||
```text
|
||||
P0 文档对齐(本文)
|
||||
P1 designTrace / playTrace 写入
|
||||
P2 CardAsset 导出与 PlayBook.cardRef
|
||||
P3 与现有 PersistedBookSession / RunSnapshot 字段合并
|
||||
P4 卡库 UI、跨 Book 引用
|
||||
```
|
||||
|
||||
代码现状:`src/types/book.ts`、`run-snapshot.ts` 仍为简化模型,实现时按本文扩展。
|
||||
|
||||
---
|
||||
|
||||
## 11. 角色卡流程示例
|
||||
|
||||
```text
|
||||
1. 新建 CardBook → design stage
|
||||
2. 用户与 agent 迭代 → designTrace 追加
|
||||
3. invoke persona-* skills → 设计.* tag
|
||||
4. 用户确认 → 导出 CardAsset
|
||||
5. 新建 PlayBook,cardRef = assetId
|
||||
6. play stage:每轮 playTrace + messages
|
||||
7. 手动 PlaySnapshot 存档
|
||||
8. 下次打开 PlayBook 或读 snapshot 续玩
|
||||
```
|
||||
|
||||
创建过程、卡本身、游玩过程 **三者分开存**,互不覆盖。
|
||||
189
docs/context-assembly.md
Normal file
189
docs/context-assembly.md
Normal file
@@ -0,0 +1,189 @@
|
||||
# 上下文拼接
|
||||
|
||||
## 1. 定位
|
||||
|
||||
Worker / skill 执行时,Runtime 将黑板 tag 与固定体裁说明拼成 LLM prompt。
|
||||
**拼接规则在 skill 定义期定制;拼接执行由 Runtime 机械完成;agent 不临场改 inputTags。**
|
||||
|
||||
详见 `docs/worker-skill-format.md`(字段)、`docs/tag-blackboard.md`(标签原则)。
|
||||
|
||||
---
|
||||
|
||||
## 2. 上半固定、下半动态
|
||||
|
||||
每条 worker prompt 分为两段:
|
||||
|
||||
```text
|
||||
┌─ 上半:固定上下文(Static)────────────────────────┐
|
||||
│ shared-context.md(包级体裁约束) │
|
||||
│ worker SKILL.md 正文(能力说明、自检) │
|
||||
│ contextSegments 中 tier=static 的 tag │
|
||||
│ 例:角色卡.确认稿、世界.蓝图、设计.交互范式 │
|
||||
└────────────────────────────────────────────────────┘
|
||||
┌─ 下半:动态上下文(Dynamic)────────────────────────┐
|
||||
│ contextSegments 中 tier=dynamic 的 tag │
|
||||
│ 例:运行.事件流、可见信息、用户.最新输入 │
|
||||
│ 按 policy 裁剪(tail_lines、tail_tokens、concat) │
|
||||
└────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
原则:
|
||||
|
||||
```text
|
||||
越稳定、越少改 → 越靠上(static)
|
||||
越增量、每轮变 → 越靠下(dynamic)
|
||||
```
|
||||
|
||||
**不是** agent 在游玩时自由往 prompt 里插段落;agent 只决定 **invoke 哪个 skill**;该 skill 的契约决定看见什么。
|
||||
|
||||
---
|
||||
|
||||
## 3. 三分工
|
||||
|
||||
| 谁 | 管什么 | 何时定 |
|
||||
|----|--------|--------|
|
||||
| **Skill 定义**(`workers/*/SKILL.md`) | inputTags、contextSegments、tier、policy、隔离 | 写 skill 时 |
|
||||
| **实例 manifest** | 启用哪些 run skill、`contextProfile` 选哪档 variant | 实例化时 agent 产出 |
|
||||
| **Agent** | 何时 invoke 哪个 skill;可用 read_blackboard 辅助决策 | 运行中 |
|
||||
| **Runtime** | `assembleWorkerContext()` 唯一拼接点 | 每次 invoke |
|
||||
|
||||
---
|
||||
|
||||
## 4. contextSegments(Worker Skill 字段)
|
||||
|
||||
在 `SKILL.md` frontmatter 声明(`inputTags` 仍保留,作为取数白名单):
|
||||
|
||||
```yaml
|
||||
contextSegments:
|
||||
- id: persona
|
||||
tier: static
|
||||
tags: ["角色卡.确认稿"]
|
||||
label: "## 角色设定"
|
||||
- id: world
|
||||
tier: static
|
||||
tags: ["世界.蓝图"]
|
||||
label: "## 世界"
|
||||
- id: history
|
||||
tier: dynamic
|
||||
tags: ["运行.事件流"]
|
||||
policy: tail_lines_80
|
||||
- id: turn
|
||||
tier: dynamic
|
||||
tags: ["可见信息", "用户.最新输入"]
|
||||
label: "## 本轮"
|
||||
```
|
||||
|
||||
| 字段 | 含义 |
|
||||
|------|------|
|
||||
| `tier` | `static`(上半)或 `dynamic`(下半) |
|
||||
| `tags` | 从黑板取的 pattern,须在 `inputTags` 内 |
|
||||
| `label` | 拼进 prompt 的 Markdown 标题(可选) |
|
||||
| `policy` | 动态段裁剪,见 §5 |
|
||||
|
||||
未声明 `contextSegments` 时,Runtime 回退:按 `inputTags` 顺序输出 JSON `inputs`(当前实现)。
|
||||
|
||||
---
|
||||
|
||||
## 5. 动态段裁剪 policy
|
||||
|
||||
| policy | 行为 |
|
||||
|--------|------|
|
||||
| `latest` | 每 pattern 取最新一条(默认) |
|
||||
| `concat` | 同 pattern 多条合并 |
|
||||
| `tail_lines_N` | 事件流等取最后 N 行 |
|
||||
| `tail_tokens_N` | 按估算 token 截断(预留) |
|
||||
|
||||
上下文过长时:
|
||||
|
||||
1. 优先靠 policy 裁剪动态段
|
||||
2. 实例 manifest 可覆盖 variant(如 `historyPolicy: last_10_turns`)
|
||||
3. agent 可 invoke 显式 **compress-history** skill 写摘要 tag(调度 skill,不是随手删 prompt)
|
||||
|
||||
---
|
||||
|
||||
## 6. contextProfile(实例 manifest)
|
||||
|
||||
实例化阶段产出(写入 `设计.run_skill清单` 或 Book manifest),agent **只选预置档位**,不列 tag:
|
||||
|
||||
```json
|
||||
{
|
||||
"runSkills": ["world-simulator", "narrator"],
|
||||
"contextProfile": {
|
||||
"narrator": { "variant": "card_rp", "historyPolicy": "last_15_turns" },
|
||||
"world-simulator": { "variant": "light_rules" }
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`variant` 在 skill 包内预定义多组 `contextSegments` 覆盖或 policy 差异。
|
||||
例:`narrator` 的 `card_rp` 强制 static 含 `角色卡.确认稿`;`short_emotion_flow` 缩短 dynamic 历史。
|
||||
|
||||
---
|
||||
|
||||
## 7. 隔离
|
||||
|
||||
与 `inputTags` 正交,由 skill 声明 `contextIsolation`:
|
||||
|
||||
```yaml
|
||||
contextIsolation: none | role_pov | blind_review
|
||||
```
|
||||
|
||||
- `role_pov`:role-decide 等,Runtime 调用 `filterInputsForRolePerspective`
|
||||
- `blind_review`:review 不可见指定 tag(如 `核心.危险.隐藏`)
|
||||
|
||||
隔离在 **取数之后、拼接之前** 应用。
|
||||
|
||||
---
|
||||
|
||||
## 8. 与 agent tool loop 的边界
|
||||
|
||||
两套上下文 **不得混用**:
|
||||
|
||||
| | Agent tool loop `messages[]` | Worker prompt |
|
||||
|--|------------------------------|---------------|
|
||||
| 用途 | 总管推理、选 skill | 具体 skill 执行 |
|
||||
| 内容 | tool 结果、read_blackboard | assembleWorkerContext 输出 |
|
||||
| 增长 | 两次用户操作之间的 burst 内累积 | 每次 invoke 按契约重建 |
|
||||
|
||||
总管 `read_blackboard` **不注入** worker prompt;只帮助 agent 决定下一个 `run_worker`。
|
||||
|
||||
---
|
||||
|
||||
## 9. 拼接结果形态(目标)
|
||||
|
||||
```text
|
||||
system:
|
||||
{shared-context}
|
||||
{worker SKILL body}
|
||||
{固定输出协议}
|
||||
|
||||
user:
|
||||
{按 segment 顺序格式化的 Markdown 或结构化块}
|
||||
```
|
||||
|
||||
实现:`src/worker/executor.ts` → `assembleWorkerContext()`(待从纯 JSON inputs 升级)。
|
||||
|
||||
---
|
||||
|
||||
## 10. 设计 checklist
|
||||
|
||||
```text
|
||||
□ 列出 static / dynamic 各需要哪些 tag
|
||||
□ static 写入 contextSegments tier=static
|
||||
□ dynamic 写入 tier=dynamic 并选 policy
|
||||
□ inputTags 覆盖 segments 中全部 pattern
|
||||
□ 画隔离表:谁不可见哪些 tag
|
||||
□ 若有多游玩模式,在包内预置 contextProfile variant
|
||||
□ 实例化 manifest 只选 variant,不临场改 tag 列表
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 11. 相关文档
|
||||
|
||||
| 文档 | 关系 |
|
||||
|------|------|
|
||||
| `worker-skill-format.md` | frontmatter 字段定义 |
|
||||
| `skill-design-guide.md` | 如何倒推 tag 与 skill 能力 |
|
||||
| `tag-blackboard.md` | 标签命名与黑板 |
|
||||
| `tool-contracts.md` | agent 不得传 inputTags |
|
||||
83
docs/creation-playbook.md
Normal file
83
docs/creation-playbook.md
Normal file
@@ -0,0 +1,83 @@
|
||||
# 创作流程指南(Creation Playbook)
|
||||
|
||||
## 0. 内容在哪
|
||||
|
||||
**流程定义在 skill 包里**(orchestrator manifest + `workers/*/SKILL.md`)。本文只保留概念。
|
||||
|
||||
写新包 → `skill-design-guide.md` → 新建 `skills/.../orchestrator.md`。
|
||||
|
||||
---
|
||||
|
||||
## 1. 定位
|
||||
|
||||
```text
|
||||
Orchestrator 包 能力库 + manifest(静态)
|
||||
黑板 tag 一次 Session 的实参(动态)
|
||||
Book 跨 Session:过程、资产、游玩
|
||||
```
|
||||
|
||||
| 层 | 管什么 |
|
||||
|----|--------|
|
||||
| **运行相位** | `idle` / `running` / `waiting_user` — 系统在等什么 |
|
||||
| **业务 stage** | `design`(实例化)→ `play`(运行)→ `done` |
|
||||
| **Agent** | tool loop 内 invoke 哪个 skill |
|
||||
| **Skill** | 读哪些 tag、写哪些 tag、上下文怎么拼 |
|
||||
| **Book** | 长期存储,见 `book-storage.md` |
|
||||
|
||||
---
|
||||
|
||||
## 2. 启动
|
||||
|
||||
```text
|
||||
skill_selection 选 orchestrator 包
|
||||
intake 启动询问(最小信息)
|
||||
design stage agent 按需 invoke instantiate skill
|
||||
declare ready 进入 play
|
||||
play stage 用户输入 → agent burst → run skill
|
||||
done 归档 Book
|
||||
```
|
||||
|
||||
`startupCompleted` / `instanceReady`:agent 声明 + 程序校验「当前 run_skill清单 可运行」,非固定 prerequisite 打勾。
|
||||
|
||||
---
|
||||
|
||||
## 3. Agent 与 Runtime
|
||||
|
||||
| | Agent | Runtime |
|
||||
|--|-------|---------|
|
||||
| 决定 | invoke 哪个 skill、何时 ask_user/finish | — |
|
||||
| 拼接上下文 | 只用 read_blackboard 辅助决策 | assembleWorkerContext |
|
||||
| 写黑板 | 否(边界 tool 驱动 worker 写) | 校验 outputTags 后写入 |
|
||||
|
||||
Agent **不指定 inputTags**。见 `context-assembly.md`。
|
||||
|
||||
---
|
||||
|
||||
## 4. Tool loop burst
|
||||
|
||||
每次用户硬事件后,agent 进入 `running`,在 **burst 上限内** 多轮 tool;碰到边界 tool 或需用户则停。
|
||||
见 `tool-contracts.md`、`runtime-state-machine.md`。
|
||||
|
||||
---
|
||||
|
||||
## 5. 角色卡(一种 Book 形态)
|
||||
|
||||
```text
|
||||
创建过程 designTrace + 对话 → CardBook(design)
|
||||
创建结果 角色卡.确认稿 等 → CardAsset(可导入资产)
|
||||
游玩过程 playTrace + runState → PlayBook
|
||||
游玩存档 PlaySnapshot
|
||||
```
|
||||
|
||||
不拆独立 author/play 包;见 `book-storage.md` §角色卡。
|
||||
|
||||
---
|
||||
|
||||
## 6. 相关文档
|
||||
|
||||
| 文档 | 关系 |
|
||||
|------|------|
|
||||
| `architecture.md` | 总览 |
|
||||
| `skill-design-guide.md` | 设计方法 |
|
||||
| `context-assembly.md` | 上下文拼接 |
|
||||
| `tag-blackboard.md` | 标签 |
|
||||
354
docs/implementation-guide.md
Normal file
354
docs/implementation-guide.md
Normal file
@@ -0,0 +1,354 @@
|
||||
# 实现指南
|
||||
|
||||
## 1. 写代码的规则
|
||||
|
||||
```text
|
||||
1. 先读文档,再写对应文件。
|
||||
2. 一次只写一个文件(或一组强绑定的 types + 实现)。
|
||||
3. 每写完一个文件,对照本文档的「文件职责」自检。
|
||||
4. 文件行为与文档冲突时,先改文档,再改代码。
|
||||
5. 不要跳步实现:下游文件不能先于上游文件。
|
||||
```
|
||||
|
||||
文档是规格,代码是文档的实现。
|
||||
|
||||
---
|
||||
|
||||
## 2. 文档地图
|
||||
|
||||
| 文档 | 管什么 |
|
||||
|---|---|
|
||||
| `tag-blackboard.md` | **★ 主规格**:标签黑板、skill 分工 |
|
||||
| `context-assembly.md` | **★ 上下文拼接**:上半固定、下半动态 |
|
||||
| `architecture.md` | 总览、agent tool loop、模块边界 |
|
||||
| `runtime-state-machine.md` | 5 相位、tool 边界、burst |
|
||||
| `tool-contracts.md` | 总管 / worker tool |
|
||||
| `orchestrator-skill-format.md` | manifest 写法(非编排表) |
|
||||
| `worker-skill-format.md` | SKILL.md、contextSegments |
|
||||
| `skill-format.md` | 包存储、registry |
|
||||
| `skill-design-guide.md` | 新包设计方法 |
|
||||
| `creation-playbook.md` | 创作流程概念 |
|
||||
| `book-storage.md` | Book、CardAsset、PlayBook、过程存储 |
|
||||
| `run-snapshot.md` | 手动存档 |
|
||||
| `preset-format.md` | 预设导入 |
|
||||
| `implementation-guide.md` | 本文件:文件顺序与职责 |
|
||||
|
||||
---
|
||||
|
||||
## 3. 实现分期
|
||||
|
||||
### Phase A0 — 可运行阶段机(当前优先)
|
||||
|
||||
目标:**不依赖 LLM**,阶段机整体可运行、可手动驱动、可脚本跑通最小闭环。
|
||||
|
||||
| # | 文件 | 状态 | 干嘛的 |
|
||||
|---|---|---|---|
|
||||
| A06 | `src/types/runtime.ts` | done | 5 相位、事件、会话类型 |
|
||||
| A09 | `src/runtime/phase-machine.ts` | done | 纯函数:`applyEvent`,不调 LLM |
|
||||
| A20 | `src/runtime/phase-runtime.ts` | done | 运行层:处理 effects,stub worker |
|
||||
| A21 | `src/cli/phase-demo.ts` | done | 交互式演示 CLI,手动发事件 |
|
||||
| A22 | `tests/phase-runtime.test.ts` | done | 闭环 + worker 中途提问测试 |
|
||||
|
||||
**运行方式:**
|
||||
```bash
|
||||
npm run phase-script # 非交互,自动跑最小闭环
|
||||
npm run phase-demo # 交互,手动 /decide /approve /worker-ask
|
||||
npm run phase-demo -- --auto # worker 自动占位完成
|
||||
```
|
||||
|
||||
### Phase A1 — 总管 LLM 接入(阶段机之上)
|
||||
|
||||
目标:在 PhaseRuntime 之上接 Main Agent,不改动 phase-machine 规则。
|
||||
|
||||
| # | 文件 | 状态 | 干嘛的 |
|
||||
|---|---|---|---|
|
||||
| A11–A19 | blackboard、llm、main-agent、orchestrator、run.ts | done | 带 Mock/真实 LLM 的完整栈 |
|
||||
| A15 | `src/main-agent/prompts.ts` | todo | prompt 拆分 |
|
||||
|
||||
### Phase A2 — Skill 层(创作指南)
|
||||
|
||||
目标:`skills/` 批量存储 SKILL.md;启动第一个询问是选 skill;总管读 activeSkill。
|
||||
|
||||
| # | 文件 | 状态 | 干嘛的 |
|
||||
|---|---|---|---|
|
||||
| S00 | `skills/registry.yaml` | done | skill 索引 |
|
||||
| S01 | `skills/novel-standard/SKILL.md` | done | 小说指南(含启动询问) |
|
||||
| S02 | `skills/theater-roleplay/SKILL.md` | done | 剧场指南(含启动询问) |
|
||||
| S03 | `src/skills/types.ts` | todo | ParsedSkill、SkillIndexEntry |
|
||||
| S04 | `src/skills/loader.ts` | todo | 解析 SKILL.md |
|
||||
| S05 | `src/skills/registry.ts` | todo | listSkills() |
|
||||
| S06 | `src/skills/resolver.ts` | todo | 推断当前 stage |
|
||||
| S07 | `src/main-agent/skill-context.ts` | todo | 注入总管 prompt |
|
||||
| S08 | `src/runtime/phase-machine.ts` | todo | 增加 skill_selection / skill_selected |
|
||||
| S09 | `src/cli/phase-demo.ts` | todo | 启动时 /select-skill |
|
||||
|
||||
详见 `docs/skill-format.md` §5。
|
||||
|
||||
### Phase B — Tool Call 化
|
||||
|
||||
目标:总管 / worker 从 JSON 决策改为 tool call;Runtime 做 tool 校验与事件转换。
|
||||
|
||||
### Phase C — 真实 Worker
|
||||
|
||||
目标:outline / drafting 等固定 worker 接真实 LLM;worker 可中途 ask_user。
|
||||
|
||||
### Phase D — 持久化
|
||||
|
||||
目标:book 存储;preset 导入。
|
||||
|
||||
### Phase E — 标签黑板迁移(当前文档已完成,代码待做)
|
||||
|
||||
目标:代码与 `tag-blackboard.md` 对齐。
|
||||
|
||||
| # | 文件 | 状态 | 干嘛的 |
|
||||
|---|---|---|---|
|
||||
| E01 | `src/types/blackboard.ts` | done | `BlackboardItem`、按 tag 查询 |
|
||||
| E02 | `src/blackboard/blackboard.ts` | done | listTagIndex、前缀匹配 |
|
||||
| E03 | `src/skills/types.ts` + `loader.ts` | done | 解析 inputTags / outputTags(兼容 outputKeys) |
|
||||
| E04 | `src/worker/executor.ts` | done | 按 tag 取 context,校验 outputTags |
|
||||
| E05 | `src/types/runtime.ts` + `main-agent.ts` + `phase-runtime` | done | 决策去掉 keys;runtime 按 Worker Skill 执行 |
|
||||
| E06 | `skills/novel/weird-rules-short/` | todo | tag 化 skill 样板 + inputTags frontmatter |
|
||||
| E07 | `skills/novel/quick-write/` | todo | 简易全量 LLM skill |
|
||||
|
||||
编排写在各包 `orchestrator.md`,不单独维护 execution-flow YAML。
|
||||
|
||||
---
|
||||
|
||||
## 4. Phase A 文件顺序
|
||||
|
||||
按序号逐个实现。状态列:`done` = 已有初版,`todo` = 未写或未按文档对齐。
|
||||
|
||||
### 4.1 项目配置
|
||||
|
||||
| # | 文件 | 状态 | 干嘛的 |
|
||||
|---|---|---|---|
|
||||
| A01 | `package.json` | done | 项目元数据、npm scripts(dev / test / demo) |
|
||||
| A02 | `tsconfig.json` | done | TypeScript 编译选项 |
|
||||
| A03 | `vitest.config.ts` | done | 测试入口配置 |
|
||||
| A04 | `.env.example` | done | LLM API 环境变量模板,不含真实 key |
|
||||
| A05 | `.gitignore` | done | 忽略 node_modules、dist、.env |
|
||||
|
||||
**A01 职责:** 声明依赖(typescript、tsx、vitest)和三条命令。不含业务逻辑。
|
||||
|
||||
---
|
||||
|
||||
### 4.2 类型层(只放数据结构,不含逻辑)
|
||||
|
||||
| # | 文件 | 状态 | 干嘛的 | 对应文档 |
|
||||
|---|---|---|---|---|
|
||||
| A06 | `src/types/runtime.ts` | done | 相位、事件、会话、产物、ResumeContext | `runtime-state-machine.md` §2–5 |
|
||||
| A07 | `src/types/blackboard.ts` | done | BlackboardItem、TagIndex | `tag-blackboard.md` §2 |
|
||||
| A08 | `src/types/tools.ts` | todo | 总管 tool、worker tool 的参数与结果类型 | `tool-contracts.md` |
|
||||
|
||||
**A06 职责:**
|
||||
- 定义 `RuntimePhase`(5 种)
|
||||
- 定义 `WaitingReason`(waiting_user 的子原因)
|
||||
- 定义 `RuntimeEvent`(唯一改变相位的输入)
|
||||
- 定义 `RuntimeSession`(运行时快照)
|
||||
- 定义 `PhaseEffect`(阶段机产生的副作用,如 invoke_main_agent)
|
||||
|
||||
**A07 职责(Phase E 迁移后):**
|
||||
- 定义 `BlackboardItem`(id、tag、content、source、metadata)
|
||||
- 定义 `BlackboardTagIndex`(给总管:tag + source,无 content)
|
||||
- 定义 `BlackboardWrite`(worker 写回)
|
||||
|
||||
**A08 职责(Phase B 再写):**
|
||||
- `MainAgentToolName`、`WorkerToolName`
|
||||
- 每个 tool 的 params / result 类型
|
||||
- tool → event 映射表(类型级注释)
|
||||
|
||||
---
|
||||
|
||||
### 4.3 阶段机(纯函数,不调用 LLM)
|
||||
|
||||
| # | 文件 | 状态 | 干嘛的 | 对应文档 |
|
||||
|---|---|---|---|---|
|
||||
| A09 | `src/runtime/phase-machine.ts` | done | 5 相位阶段机:`applyEvent`、`canApplyEvent` | `runtime-state-machine.md` §6–8 |
|
||||
| A10 | `src/runtime/state-machine.ts` | done | 废弃别名,re-export phase-machine | — |
|
||||
|
||||
**A09 职责:**
|
||||
- `createSession()` — 创建 idle 会话
|
||||
- `getAllowedEvents()` — 当前相位允许哪些事件
|
||||
- `canApplyEvent()` — 事件是否合法(含 waitingReason 校验)
|
||||
- `applyEvent()` — 纯函数:session + event → 新 session + effects
|
||||
- `createArtifact()` — 创建产物记录
|
||||
|
||||
**约束:**
|
||||
- 不 import llm、blackboard、main-agent
|
||||
- 不做 IO
|
||||
- 所有相位转移必须写进 history
|
||||
|
||||
**A10 职责:** 兼容旧 import 路径,后续可删。
|
||||
|
||||
---
|
||||
|
||||
### 4.4 黑板
|
||||
|
||||
| # | 文件 | 状态 | 干嘛的 | 对应文档 |
|
||||
|---|---|---|---|---|
|
||||
| A11 | `src/blackboard/blackboard.ts` | done | listTagIndex、queryByPatterns、write | `tag-blackboard.md` §2 |
|
||||
|
||||
**A11 职责:**
|
||||
- `listTagIndex()` — 给总管
|
||||
- `queryByPatterns()` — 给 worker 注入
|
||||
- `write()` — 按 tag 写回
|
||||
- `getContentByTag()` / `getLatestByTag()`
|
||||
|
||||
---
|
||||
|
||||
### 4.5 配置与 LLM
|
||||
|
||||
| # | 文件 | 状态 | 干嘛的 | 对应文档 |
|
||||
|---|---|---|---|---|
|
||||
| A12 | `src/config/env.ts` | done | 从环境变量读 baseUrl、apiKey、model | `architecture.md` §2 config |
|
||||
| A13 | `src/llm/client.ts` | done | OpenAI 兼容 API + MockLlmProvider | — |
|
||||
|
||||
**A12 职责:**
|
||||
- `loadLlmConfig()` — 必须有 key,否则抛错
|
||||
- `loadLlmConfigOptional()` — 无 key 返回 null,CLI 切 mock
|
||||
|
||||
**A13 职责:**
|
||||
- `LlmProvider` 接口:`complete(messages) → string`
|
||||
- `OpenAiCompatibleProvider` — 真实 API 调用
|
||||
- `MockLlmProvider` — 测试 / demo 用预设响应
|
||||
- apiKey 不出现在 session 或项目文件里
|
||||
|
||||
---
|
||||
|
||||
### 4.6 总管 LLM
|
||||
|
||||
| # | 文件 | 状态 | 干嘛的 | 对应文档 |
|
||||
|---|---|---|---|---|
|
||||
| A14 | `src/main-agent/main-agent.ts` | done | 总管:只选 worker,读 tag 索引 | `tag-blackboard.md` §6 |
|
||||
| A15 | `src/main-agent/prompts.ts` | todo | 总管 prompt 拆分 | `tag-blackboard.md` §6 |
|
||||
|
||||
**A14 职责:**
|
||||
- `MainAgent.decide(context)` — 调 LLM,返回 `MainAgentDecision`
|
||||
- `parseMainAgentDecision(raw)` — 解析 JSON(Phase B 改为 parse tool calls)
|
||||
- `buildMainAgentUserPrompt(context)` — 拼 user prompt
|
||||
- `DEFAULT_WORKERS` — 第一版可用 worker 列表
|
||||
|
||||
**约束:**
|
||||
- 总管不读黑板 value
|
||||
- 总管不直接改 phase
|
||||
- 不含 question-worker(提问是 worker 能力)
|
||||
|
||||
**A15 职责(可选拆分):** 把 prompt 从 main-agent.ts 抽出来,方便迭代。
|
||||
|
||||
---
|
||||
|
||||
### 4.7 编排层
|
||||
|
||||
| # | 文件 | 状态 | 干嘛的 | 对应文档 |
|
||||
|---|---|---|---|---|
|
||||
| A16 | `src/runtime/orchestrator.ts` | deprecated | 旧入口;用 phase-runtime | `architecture.md` |
|
||||
|
||||
**A16 职责:**
|
||||
- `RuntimeOrchestrator` — 对外 API:start、submitUserInput、approve、accept 等
|
||||
- `dispatch(event)` — 调 `applyEvent`,处理 `PhaseEffect`
|
||||
- `runMainAgent()` — phase=running 时调总管
|
||||
- `runStubWorker()` — 第一版占位 worker(Phase C 替换)
|
||||
- `resumeStubWorker()` — worker 中途提问后恢复
|
||||
|
||||
**约束:**
|
||||
- 唯一调用阶段机和总管的地方
|
||||
- user 事件(approve / accept)只从 CLI / API 进入,不从 LLM 进入
|
||||
|
||||
---
|
||||
|
||||
### 4.8 入口与测试
|
||||
|
||||
| # | 文件 | 状态 | 干嘛的 |
|
||||
|---|---|---|---|
|
||||
| A17 | `src/cli/run.ts` | done | 交互式 CLI:输入、/approve、/accept、/status |
|
||||
| A18 | `tests/phase-machine.test.ts` | done | 阶段机单元测试 |
|
||||
| A19 | `tests/orchestrator.test.ts` | done | 编排层 + Mock LLM 集成测试 |
|
||||
|
||||
**A17 职责:**
|
||||
- 读 stdin,转成 orchestrator 方法调用
|
||||
- 打印 `phase` + `waitingReason`
|
||||
- `--mock` 或无 API key 时用 MockLlmProvider
|
||||
|
||||
---
|
||||
|
||||
## 5. Phase B 文件顺序(下一步)
|
||||
|
||||
| # | 文件 | 干嘛的 |
|
||||
|---|---|---|
|
||||
| B01 | `src/types/tools.ts` | tool 类型定义 |
|
||||
| B02 | `src/runtime/tool-registry.ts` | 注册 tool、校验参数、tool → event |
|
||||
| B03 | `src/main-agent/main-agent.ts` | 改为 tool calling 模式 |
|
||||
| B04 | `src/runtime/tool-handlers/main-agent.ts` | 总管 tool 处理器 |
|
||||
| B05 | `src/runtime/tool-handlers/worker.ts` | worker tool 处理器(ask_user / submit) |
|
||||
|
||||
**B02 职责:**
|
||||
- 白名单:当前 phase + waitingReason 下允许哪些 tool
|
||||
- LLM 调了不允许的 tool → 拒绝,不转事件
|
||||
|
||||
---
|
||||
|
||||
## 6. Phase C 文件顺序
|
||||
|
||||
| # | 文件 | 干嘛的 |
|
||||
|---|---|---|
|
||||
| C01 | `src/workers/types.ts` | WorkerDefinition、WorkerRunOutcome |
|
||||
| C02 | `src/workers/base-worker.ts` | prompt 拼接、tool 执行循环 |
|
||||
| C03 | `src/workers/outline-worker.ts` | 大纲 worker |
|
||||
| C04 | `src/workers/drafting-worker.ts` | 正文 worker |
|
||||
| C05 | `src/runtime/worker-runner.ts` | 替代 orchestrator 里的 stub |
|
||||
|
||||
**WorkerRunOutcome(Phase C 核心):**
|
||||
|
||||
```ts
|
||||
type WorkerRunOutcome =
|
||||
| { kind: "complete"; writes: BlackboardWrite[]; summary: string }
|
||||
| { kind: "suspend"; questions: string[]; partialWrites?: BlackboardWrite[] }
|
||||
| { kind: "fail"; reason: string };
|
||||
```
|
||||
|
||||
- `complete` → `worker_completed` 事件
|
||||
- `suspend` → `worker_needs_input` 事件
|
||||
- `fail` → `runtime_failed` 事件
|
||||
|
||||
---
|
||||
|
||||
## 7. Phase D 文件顺序
|
||||
|
||||
| # | 文件 | 干嘛的 |
|
||||
|---|---|---|
|
||||
| D01 | `src/flows/types.ts` | ExecutionFlow、ExecutionStep |
|
||||
| D02 | `src/flows/ghostwriting-flow.ts` | 代笔 flow 配置 |
|
||||
| D03 | `src/book-storage/store.ts` | Book 持久化 |
|
||||
| D04 | `src/preset/importer.ts` | SillyTavern 预设导入 |
|
||||
|
||||
---
|
||||
|
||||
## 8. 单文件完成检查清单
|
||||
|
||||
每写完一个文件,确认:
|
||||
|
||||
```text
|
||||
[ ] 文件顶部的职责是否只对应文档里的一节
|
||||
[ ] 是否 import 了不该 import 的上层模块(阶段机不应 import LLM)
|
||||
[ ] 是否有对应测试(内核文件必须有)
|
||||
[ ] 是否更新了本表的状态列(done / todo)
|
||||
[ ] 是否在 PR / 提交说明里写「这个文件干嘛的」一句话
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. 当前进度
|
||||
|
||||
```text
|
||||
Phase A0(可运行阶段机) ✅ 完成
|
||||
phase-machine + phase-runtime + phase-demo + 测试
|
||||
|
||||
Phase A1(总管 LLM) ✅ 有初版(orchestrator + run.ts)
|
||||
下一步:orchestrator 应基于 PhaseRuntime 重构
|
||||
|
||||
Phase B(tool call) 未开始
|
||||
Phase C(真实 worker) 未开始
|
||||
Phase D(flow / 存储) 未开始
|
||||
```
|
||||
|
||||
**下一个应写文件:** 让 `orchestrator.ts` 内部组合 `PhaseRuntime`,而不是重复阶段机逻辑。写之前会先说明该文件职责。
|
||||
184
docs/orchestrator-skill-format.md
Normal file
184
docs/orchestrator-skill-format.md
Normal file
@@ -0,0 +1,184 @@
|
||||
# 总管 Skill 格式(Orchestrator / Manifest)
|
||||
|
||||
## 1. 定位
|
||||
|
||||
**orchestrator.md** = 本包的 **manifest**:注册有哪些 skill、如何验收、如何声明 instance ready。
|
||||
**不**写逐步流水线剧本;**不**写「总管思维链」逐步调度。
|
||||
|
||||
```text
|
||||
用户选包
|
||||
→ design:agent 按需 invoke instantiate skill
|
||||
→ declare ready → play:agent invoke run skill
|
||||
→ done:归档 Book
|
||||
```
|
||||
|
||||
| 谁决定 | 什么 |
|
||||
|--------|------|
|
||||
| **Agent** | 何时 invoke 哪个 skill(tool loop) |
|
||||
| **Manifest** | 可用 skill 列表、验收策略、readiness 规则 |
|
||||
| **Worker SKILL.md** | inputTags、contextSegments、怎么做 |
|
||||
|
||||
`shared-context.md`:包级 **固定上下文上半**,注入各 worker prompt。总管不读。
|
||||
|
||||
见 `architecture.md`、`skill-design-guide.md`、`context-assembly.md`。
|
||||
|
||||
---
|
||||
|
||||
## 2. 存储位置
|
||||
|
||||
```text
|
||||
skills/novel/weird-rules-short/
|
||||
├── orchestrator.md
|
||||
├── shared-context.md # 可选
|
||||
└── workers/
|
||||
└── write-rules/SKILL.md
|
||||
```
|
||||
|
||||
- 文件固定名 **`orchestrator.md`**。
|
||||
- `registry.yaml` 的 `path` 指向它。
|
||||
|
||||
---
|
||||
|
||||
## 3. Frontmatter
|
||||
|
||||
```yaml
|
||||
---
|
||||
name: weird-rules-short
|
||||
description: >-
|
||||
何时选用:用户要写规则怪谈、守则类短篇。
|
||||
category: novel
|
||||
bookKind: novel
|
||||
workers:
|
||||
- write-rules
|
||||
- review-infer
|
||||
- review-author
|
||||
sharedContext: shared-context.md
|
||||
---
|
||||
```
|
||||
|
||||
| 字段 | 用途 |
|
||||
|------|------|
|
||||
| `description` | 何时选本包 |
|
||||
| `workers` | run / design 可调度 skill id 白名单(loader 用) |
|
||||
| `bookKind` | Book 存储形态 |
|
||||
|
||||
---
|
||||
|
||||
## 4. 正文章节(推荐)
|
||||
|
||||
```markdown
|
||||
# 标题
|
||||
|
||||
## 启动询问 # 最小 intake
|
||||
## Skill 注册表 # instantiate + run skill 清单与说明(见 §5)
|
||||
## 验收策略 # 哪些 skill 产出需 user_confirmed / approve
|
||||
## Instance Ready # 按 run_skill清单 的动态最低可行性
|
||||
## contextProfile # 可选 variant 说明(见 context-assembly.md)
|
||||
## 用户回合 # user-turn 等(可选)
|
||||
## 禁用行为
|
||||
```
|
||||
|
||||
**不应出现:**
|
||||
|
||||
- 逐步 **Worker 编排表** / **总管思维链**(已废弃为主流程)
|
||||
- `inputTags` / `outputTags` 列表 → 在 `workers/*/SKILL.md`
|
||||
- 写作细则 → Worker SKILL 正文
|
||||
|
||||
---
|
||||
|
||||
## 5. Skill 注册表(替代编排表)
|
||||
|
||||
列出本包 **能力库**,供 agent `list_workers` 与 manifest 校验:
|
||||
|
||||
```markdown
|
||||
## Skill 注册表
|
||||
|
||||
### Instantiate(design stage)
|
||||
|
||||
| id | 说明 | 典型 outputTags |
|
||||
|----|------|-----------------|
|
||||
| interaction-paradigm | 定交互范式与 run_skill清单 | 设计.run_skill清单 |
|
||||
| world-blueprint | 世界背景 | 设计.世界.蓝图 |
|
||||
| persona-draft | 角色卡草稿 | 角色卡.草稿 |
|
||||
|
||||
### Run(play stage)
|
||||
|
||||
| id | 说明 | 默认 acceptance |
|
||||
|----|------|-----------------|
|
||||
| write-rules | 写规则 | user_confirmed |
|
||||
| review-infer | 读者视角验收 | programmatic_review |
|
||||
```
|
||||
|
||||
agent **按需 invoke**,不必按表顺序跑全。
|
||||
|
||||
---
|
||||
|
||||
## 6. 启动询问与 Instance Ready
|
||||
|
||||
**启动询问:** 只收集 agent 无法从空推断的最小信息 → `用户.需求` 等。
|
||||
|
||||
**Instance Ready:** 不写死「14 步全完成」,而写:
|
||||
|
||||
```markdown
|
||||
## Instance Ready
|
||||
|
||||
当 `设计.run_skill清单` 已 accepted,且清单中每个 run skill 的
|
||||
**最低 input 要求**(见各 SKILL.md)已在黑板存在或已记录跳过理由。
|
||||
由 agent `declare_instance_ready` + Runtime 校验。
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. 验收策略
|
||||
|
||||
```markdown
|
||||
## 验收策略
|
||||
|
||||
| skill | requiresApproval | acceptanceMode |
|
||||
|-------|------------------|----------------|
|
||||
| setup-scenario | true | user_confirmed |
|
||||
| world-engine | false | no_confirmation |
|
||||
| present-round | false | user_confirmed |
|
||||
```
|
||||
|
||||
agent 通过 `run_worker(..., requiresApproval)` 触发;默认值也可写在 manifest 供 Runtime 填充。
|
||||
|
||||
---
|
||||
|
||||
## 8. contextProfile
|
||||
|
||||
若同一 skill 有多种游玩/创作模式,在 manifest 列出 variant 名与含义;实例化写入 Book。
|
||||
格式见 `context-assembly.md`。
|
||||
|
||||
---
|
||||
|
||||
## 9. 与 Worker SKILL 的关系
|
||||
|
||||
```text
|
||||
orchestrator.md 注册 + 验收 + readiness
|
||||
workers/*/SKILL.md 能力 + 上下文契约(contextSegments)
|
||||
```
|
||||
|
||||
Prompt 注入:
|
||||
|
||||
```text
|
||||
Agent:session 摘要 + tool;可用 read_blackboard
|
||||
Worker:shared-context + SKILL + assembleWorkerContext(上固定下动态)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. 迁移说明
|
||||
|
||||
旧包中的 `## Worker 编排`、`## 总管思维链` 仍可作为 **人工参考**,但新包与 world-simulator **不应**以此为主流程。
|
||||
Runtime 目标态以 agent tool loop + manifest 注册表为准。
|
||||
|
||||
---
|
||||
|
||||
## 11. 相关文档
|
||||
|
||||
| 文档 | 关系 |
|
||||
|------|------|
|
||||
| `skill-design-guide.md` | 设计方法 |
|
||||
| `worker-skill-format.md` | SKILL.md 字段 |
|
||||
| `creation-playbook.md` | 概念 |
|
||||
297
docs/preset-format.md
Normal file
297
docs/preset-format.md
Normal file
@@ -0,0 +1,297 @@
|
||||
# 预设格式
|
||||
|
||||
## 1. 定位
|
||||
|
||||
Preset 是一次 LLM 请求的上下文编排资产。它负责描述 prompt manager 中有哪些条目、这些条目的启用状态与排列顺序,以及本次生成使用哪些模型参数。
|
||||
|
||||
第一版的 preset 目标是兼容 SillyTavern 类预设文件中的核心部分,而不是完整复刻 SillyTavern 的所有扩展能力。
|
||||
|
||||
需要支持的内容:
|
||||
|
||||
```text
|
||||
prompts
|
||||
prompt manager 条目列表。每个条目描述一段可插入上下文的 prompt。
|
||||
|
||||
prompt_order
|
||||
条目顺序与启用关系。它决定本次请求实际按什么顺序装配 prompt。
|
||||
|
||||
generation parameters
|
||||
生成参数,例如 temperature、top_p、top_k、min_p、frequency_penalty、presence_penalty、max tokens 等。
|
||||
```
|
||||
|
||||
第一版不支持的内容:
|
||||
|
||||
```text
|
||||
regex_scripts
|
||||
正则隐藏、正文提取、格式美化等后处理脚本。
|
||||
|
||||
extension scripts
|
||||
预设内携带的前端脚本、按钮、插件配置。
|
||||
|
||||
UI-only fields
|
||||
只影响 SillyTavern 界面展示、不影响 LLM 请求组装的字段。
|
||||
```
|
||||
|
||||
## 2. 从 SillyTavern 预设中读取什么
|
||||
|
||||
一个真实的 SillyTavern 预设通常同时包含 prompt manager 条目、顺序关系、生成参数和扩展配置。我们的导入器只读取前三类。
|
||||
|
||||
### 2.1 Prompt 条目
|
||||
|
||||
从 `prompts` 数组读取 prompt manager 条目。
|
||||
|
||||
典型字段:
|
||||
|
||||
```ts
|
||||
type ImportedPromptEntry = {
|
||||
identifier: string;
|
||||
name: string;
|
||||
enabled: boolean;
|
||||
role: "system" | "user" | "assistant";
|
||||
content?: string;
|
||||
injection_position?: number;
|
||||
injection_depth?: number;
|
||||
injection_order?: number;
|
||||
system_prompt?: boolean;
|
||||
marker?: boolean;
|
||||
forbid_overrides?: boolean;
|
||||
};
|
||||
```
|
||||
|
||||
字段含义:
|
||||
|
||||
```text
|
||||
identifier
|
||||
条目唯一标识。prompt_order 通过它引用条目。
|
||||
|
||||
name
|
||||
给用户看的条目名称。
|
||||
|
||||
enabled
|
||||
条目自身默认启用状态。最终是否启用还需要结合 prompt_order。
|
||||
|
||||
role
|
||||
条目插入请求时使用的消息角色。
|
||||
|
||||
content
|
||||
条目文本。部分内置 marker 条目可能没有 content,需要运行时从 session 或角色数据中补齐。
|
||||
|
||||
injection_position / injection_depth / injection_order
|
||||
SillyTavern 的插入位置、深度和顺序信息。第一版先保留,不完全模拟深度插入语义。
|
||||
|
||||
system_prompt / marker
|
||||
标识这个条目是不是内置占位条目,例如角色描述、世界书、聊天历史等。
|
||||
|
||||
forbid_overrides
|
||||
标识条目是否禁止被覆盖。第一版先保留字段,不实现复杂覆盖策略。
|
||||
```
|
||||
|
||||
### 2.2 顺序与启用关系
|
||||
|
||||
从 `prompt_order` 读取实际装配顺序。
|
||||
|
||||
典型字段:
|
||||
|
||||
```ts
|
||||
type ImportedPromptOrder = Array<{
|
||||
character_id: number;
|
||||
order: Array<{
|
||||
identifier: string;
|
||||
enabled: boolean;
|
||||
}>;
|
||||
}>;
|
||||
```
|
||||
|
||||
第一版采用的规则:
|
||||
|
||||
```text
|
||||
1. 以 prompt_order[0].order 作为主顺序。
|
||||
2. 按 order 数组顺序遍历 identifier。
|
||||
3. 找到对应 prompts 条目。
|
||||
4. 只有 order.enabled 和 prompt.enabled 都为 true 时,条目才参与本轮上下文装配。
|
||||
5. 如果 prompt_order 引用了不存在的 identifier,导入时记录 warning,但不阻断导入。
|
||||
6. 如果 prompts 中存在但 prompt_order 未引用,默认不参与请求,但保留在 preset 中。
|
||||
```
|
||||
|
||||
`prompt_order` 比 `prompts` 中的排列更重要。`prompts` 是条目仓库,`prompt_order` 才是实际启用的编排表。
|
||||
|
||||
### 2.3 生成参数
|
||||
|
||||
从预设顶层读取生成参数。
|
||||
|
||||
第一版优先支持这些字段:
|
||||
|
||||
```ts
|
||||
type ImportedGenerationParameters = {
|
||||
temperature?: number;
|
||||
top_p?: number;
|
||||
top_k?: number;
|
||||
min_p?: number;
|
||||
frequency_penalty?: number;
|
||||
presence_penalty?: number;
|
||||
repetition_penalty?: number;
|
||||
openai_max_context?: number;
|
||||
openai_max_tokens?: number;
|
||||
stream_openai?: boolean;
|
||||
reasoning_effort?: string;
|
||||
verbosity?: string;
|
||||
seed?: number;
|
||||
n?: number;
|
||||
};
|
||||
```
|
||||
|
||||
字段分为两类:
|
||||
|
||||
```text
|
||||
通用采样参数
|
||||
temperature、top_p、top_k、min_p、frequency_penalty、presence_penalty、repetition_penalty。
|
||||
|
||||
请求容量与行为参数
|
||||
openai_max_context、openai_max_tokens、stream_openai、reasoning_effort、verbosity、seed、n。
|
||||
```
|
||||
|
||||
不同供应商不一定支持全部字段。导入后应先保存原始字段,再由 LLM adapter 决定哪些字段可以发送。
|
||||
|
||||
## 3. 内部归一化格式
|
||||
|
||||
导入 SillyTavern preset 后,不应该直接在业务层使用原始 JSON。需要归一化成我们自己的结构。
|
||||
|
||||
```ts
|
||||
type PresetPackage = {
|
||||
id: string;
|
||||
name: string;
|
||||
source: "native" | "sillytavern";
|
||||
prompts: PresetPromptEntry[];
|
||||
promptOrder: PresetPromptOrderItem[];
|
||||
generation: GenerationParameters;
|
||||
unsupported: UnsupportedPresetSection[];
|
||||
raw?: unknown;
|
||||
};
|
||||
|
||||
type PresetPromptEntry = {
|
||||
id: string;
|
||||
name: string;
|
||||
enabled: boolean;
|
||||
role: "system" | "user" | "assistant";
|
||||
content: string;
|
||||
marker: boolean;
|
||||
sourceIdentifier: string;
|
||||
injection?: {
|
||||
position?: number;
|
||||
depth?: number;
|
||||
order?: number;
|
||||
};
|
||||
};
|
||||
|
||||
type PresetPromptOrderItem = {
|
||||
promptId: string;
|
||||
enabled: boolean;
|
||||
orderIndex: number;
|
||||
};
|
||||
|
||||
type GenerationParameters = {
|
||||
temperature?: number;
|
||||
topP?: number;
|
||||
topK?: number;
|
||||
minP?: number;
|
||||
frequencyPenalty?: number;
|
||||
presencePenalty?: number;
|
||||
repetitionPenalty?: number;
|
||||
maxContextTokens?: number;
|
||||
maxOutputTokens?: number;
|
||||
stream?: boolean;
|
||||
reasoningEffort?: string;
|
||||
verbosity?: string;
|
||||
seed?: number;
|
||||
variants?: number;
|
||||
};
|
||||
|
||||
type UnsupportedPresetSection = {
|
||||
path: string;
|
||||
reason: string;
|
||||
};
|
||||
```
|
||||
|
||||
归一化后的 `PresetPackage` 是系统内部唯一使用的 preset 结构。原始 SillyTavern JSON 只作为导入来源和调试证据保留。
|
||||
|
||||
## 4. 上下文装配规则
|
||||
|
||||
一次请求的上下文装配按以下顺序执行:
|
||||
|
||||
```text
|
||||
1. 读取 PresetPackage.promptOrder。
|
||||
2. 过滤 enabled=false 的顺序项。
|
||||
3. 找到对应 PresetPromptEntry。
|
||||
4. 再过滤 entry.enabled=false 的条目。
|
||||
5. 对 marker 条目进行运行时替换。
|
||||
6. 对普通 content 条目进行变量替换。
|
||||
7. 按 role 合并成 LLM messages。
|
||||
8. 应用 generation 参数。
|
||||
```
|
||||
|
||||
其中 marker 条目用于挂载运行时上下文:
|
||||
|
||||
```text
|
||||
charDescription
|
||||
可以映射为当前创作项目的设定说明。
|
||||
|
||||
charPersonality
|
||||
可以映射为文风、叙事人称、角色行为约束。
|
||||
|
||||
worldInfoBefore / worldInfoAfter
|
||||
可以映射为长期设定、世界观、知识库片段。
|
||||
|
||||
scenario
|
||||
可以映射为当前创作目标或当前阶段说明。
|
||||
|
||||
chatHistory
|
||||
可以映射为历史会话、已有正文、用户反馈摘要。
|
||||
```
|
||||
|
||||
这些映射不是 SillyTavern 原义的完整复刻,而是为了兼容预设资产,让它们能服务我们的写作 agent。
|
||||
|
||||
## 5. 与创作流程的关系
|
||||
|
||||
Preset 不决定创作流程,也不决定验收模式。
|
||||
|
||||
```text
|
||||
Preset
|
||||
决定本轮请求如何拼接 prompt、哪些条目启用、使用哪些生成参数。
|
||||
|
||||
Execution Flow
|
||||
决定阶段顺序、每阶段使用哪个 worker、每阶段采用哪种验收模式。
|
||||
|
||||
Worker
|
||||
决定某个创作能力如何执行,例如大纲、剧情线、文风、正文草稿。
|
||||
|
||||
Runtime Session
|
||||
记录当前事实、历史事件、产物和审批结果。
|
||||
```
|
||||
|
||||
因此,同一个 preset 可以用于多个创作流程;同一个创作流程也可以切换不同 preset。二者是正交关系。
|
||||
|
||||
## 6. 第一版导入策略
|
||||
|
||||
第一版导入器只做保守转换:
|
||||
|
||||
```text
|
||||
保留 prompts。
|
||||
保留 prompt_order。
|
||||
保留生成参数。
|
||||
记录但忽略 regex_scripts。
|
||||
记录但忽略 extension scripts。
|
||||
记录未知字段,不丢弃原始 JSON。
|
||||
```
|
||||
|
||||
导入结果应该给用户可读的报告:
|
||||
|
||||
```text
|
||||
导入 prompt 条目数量
|
||||
启用条目数量
|
||||
未被 prompt_order 引用的条目数量
|
||||
缺失 identifier 的 order 项
|
||||
已读取的生成参数
|
||||
被忽略的扩展字段
|
||||
```
|
||||
|
||||
这个报告比静默导入更重要。预设文件经常很大,且混有脚本、正则、UI 配置和模型参数,必须让用户知道哪些内容真正进入了我们的运行时。
|
||||
53
docs/run-snapshot.md
Normal file
53
docs/run-snapshot.md
Normal file
@@ -0,0 +1,53 @@
|
||||
# Book 快照
|
||||
|
||||
用户手动保存、多档位;与自动续作 `session.json` 分离。
|
||||
|
||||
## 两种 kind(更新语义)
|
||||
|
||||
| kind | 名称 | 何时存 | 存什么 |
|
||||
|------|------|--------|--------|
|
||||
| **`instance`** | 设计完成 / 资产截面 | design 完成或从 play 剥离设定 | **CardAsset 级** tag(角色卡.确认稿、世界蓝图…);**不含**轮次、事件流 |
|
||||
| **`run`** | 游玩存档 | play 任意时刻 | instance 层 + `运行.*`、轮次、变量、对话 |
|
||||
|
||||
```text
|
||||
CardBook design 完成 → 可存 instance(导出角色卡 / 世界设定)
|
||||
PlayBook 进行中 → 可存 run(第 N 轮续玩)
|
||||
```
|
||||
|
||||
**instance** 不再表示「14 步 pipeline 填完」,而是 **agent declare ready 时的可复用资产截面**。详见 `book-storage.md`。
|
||||
|
||||
## 与三种存储需求
|
||||
|
||||
| 需求 | 用什么 |
|
||||
|------|--------|
|
||||
| 创建角色卡**过程** | CardBook `designTrace` + messages(快照不替代,须 Book 级) |
|
||||
| 创建好的**卡** | CardAsset 或 `instance` 快照 |
|
||||
| 游玩**过程** | PlayBook `playTrace` + `run` 快照 |
|
||||
|
||||
## 与自动续作
|
||||
|
||||
| | `session.json` | `run-snapshots/` |
|
||||
|--|----------------|------------------|
|
||||
| 触发 | 自动 | 用户手动 |
|
||||
| 数量 | 每 Book 1 份 | 多档、可命名 |
|
||||
| 打开作品 | 默认恢复 | 选档 **加载** |
|
||||
|
||||
## API
|
||||
|
||||
```text
|
||||
GET /api/books/:bookId/saves
|
||||
POST /api/books/:bookId/saves { label, kind: "instance"|"run", note?, sessionId? }
|
||||
POST /api/books/:bookId/saves/:id/load
|
||||
DELETE /api/books/:bookId/saves/:id
|
||||
```
|
||||
|
||||
## 实现
|
||||
|
||||
```text
|
||||
src/types/run-snapshot.ts
|
||||
src/book/run-snapshot-store.ts
|
||||
src/book/snapshot-filters.ts instance 时剥离 运行.* 等
|
||||
src/server/session-manager.ts
|
||||
```
|
||||
|
||||
存储:`books/{bookId}/run-snapshots/{id}.json`
|
||||
136
docs/runtime-state-machine.md
Normal file
136
docs/runtime-state-machine.md
Normal file
@@ -0,0 +1,136 @@
|
||||
# 运行阶段机
|
||||
|
||||
## 1. 定位
|
||||
|
||||
阶段机 = **并发与权限模型**:谁在场、哪些 tool 可用、何时必须等用户、产物何时算事实。
|
||||
|
||||
**不是** 流水线执行器;「下一步 invoke 哪个 skill」由 agent tool loop 决定。
|
||||
|
||||
```text
|
||||
业务 stage(Book / Session)
|
||||
design(实例化)→ play(运行)→ done
|
||||
|
||||
运行相位(RuntimePhase)
|
||||
idle | running | waiting_user | done | error
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 五个运行相位
|
||||
|
||||
```ts
|
||||
type RuntimePhase = "idle" | "running" | "waiting_user" | "done" | "error";
|
||||
```
|
||||
|
||||
| phase | 含义 |
|
||||
|-------|------|
|
||||
| `idle` | 会话已创建 |
|
||||
| `running` | agent burst 或 worker 执行中 |
|
||||
| `waiting_user` | 等用户(见 waitingReason) |
|
||||
| `done` | 正常结束 |
|
||||
| `error` | 不可恢复 |
|
||||
|
||||
---
|
||||
|
||||
## 3. waitingReason
|
||||
|
||||
```ts
|
||||
type WaitingReason =
|
||||
| { kind: "skill_selection"; availableSkills: SkillIndexEntry[] }
|
||||
| { kind: "intake"; prompt: string }
|
||||
| { kind: "input"; message?: string }
|
||||
| { kind: "approve_step"; decisionId: string }
|
||||
| { kind: "review_artifact"; artifactId: string }
|
||||
| { kind: "worker_questions"; workerId: string; questions: string[] }
|
||||
| { kind: "revision"; instruction?: string };
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 阶段机 vs tool
|
||||
|
||||
| 角色 | 说明 |
|
||||
|------|------|
|
||||
| **循环 tool** | 仅当 `running` 且无阻塞 worker;结果进 agent messages |
|
||||
| **边界 tool** | 触发 phase / waitingReason 变化 |
|
||||
| **用户 event** | 唯一 approve、accept;burst 计数归零 |
|
||||
| **Worker** | `running` 且 `currentWorkerId` set 时,总管暂停 |
|
||||
|
||||
目标态工具表见 `tool-contracts.md`。
|
||||
|
||||
---
|
||||
|
||||
## 5. Tool loop burst
|
||||
|
||||
```text
|
||||
用户硬事件
|
||||
→ toolLoopBurstCount = 0
|
||||
→ phase = running(若适用)
|
||||
→ agent while burst < maxBurst:
|
||||
循环 tool …
|
||||
边界 tool → 可能 waiting_user / 启动 worker
|
||||
→ worker 完成 → 按 acceptanceMode 可能 waiting_user
|
||||
```
|
||||
|
||||
`maxBurst`:**两次用户操作之间**的上限(默认 12)。
|
||||
|
||||
---
|
||||
|
||||
## 6. 典型转移(简化)
|
||||
|
||||
```text
|
||||
idle → skill_selection
|
||||
skill_selected → intake 或 input
|
||||
intake 完成 / confirm → running → agent burst
|
||||
running → run_worker → approve_step 或 worker 执行
|
||||
worker_completed → review_artifact(user_confirmed)
|
||||
user_accepted → running → agent burst
|
||||
finish → done
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. 会话结构
|
||||
|
||||
```ts
|
||||
type RuntimeSession = {
|
||||
id: string;
|
||||
phase: RuntimePhase;
|
||||
waitingReason?: WaitingReason;
|
||||
currentWorkerId?: string;
|
||||
acceptanceMode?: AcceptanceMode;
|
||||
resumeContext?: ResumeContext;
|
||||
slots: Record<string, unknown>;
|
||||
artifacts: ArtifactRecord[];
|
||||
pendingDecision?: MainAgentDecision;
|
||||
history: RuntimeEvent[];
|
||||
// 目标:toolLoopBurstCount, lifecycleStage
|
||||
};
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. 产物生命周期
|
||||
|
||||
```text
|
||||
drafted → under_review → accepted | rejected | revision_requested
|
||||
accepted 前不得当下游事实
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 9. 与编排表的关系
|
||||
|
||||
**已废弃为主流程:** orchestrator「思维链 / 逐步编排表」驱动步骤。
|
||||
orchestrator 改为 **skill 注册表 + 验收策略**;阶段机不解析「第几步」。
|
||||
|
||||
`semi_auto` / `pauseCheckpoint` 仍可作为可选策略,由 manifest 声明,第一版未实现。
|
||||
|
||||
---
|
||||
|
||||
## 10. 代码
|
||||
|
||||
`src/runtime/phase-machine.ts` — 纯函数 `applyEvent`
|
||||
`src/runtime/phase-runtime.ts` — Session IO、tool loop 入口
|
||||
|
||||
旧 11 态已合并为 5 phase + waitingReason。
|
||||
184
docs/skill-design-guide.md
Normal file
184
docs/skill-design-guide.md
Normal file
@@ -0,0 +1,184 @@
|
||||
# Skill 设计指南
|
||||
|
||||
指导 **如何从零设计一个 orchestrator 包**(skill 能力库 + run skill 组合)。
|
||||
格式见 `skill-format.md`、`orchestrator-skill-format.md`、`worker-skill-format.md`;上下文见 `context-assembly.md`。
|
||||
|
||||
**设计顺序:**
|
||||
|
||||
```text
|
||||
1. 用户意图 → run skill 清单(交互范式 skill 产出)
|
||||
2. 每个 run skill 倒推需要哪些 instantiate skill / tag
|
||||
3. 定义各 skill 的 inputTags、outputTags、contextSegments
|
||||
4. 上下文隔离与验收边界
|
||||
5. orchestrator manifest(能力注册,非逐步剧本)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 1. 实例化:agent 选 skill,不是填步骤
|
||||
|
||||
### 1.1 两层倒推
|
||||
|
||||
```text
|
||||
用户意图(长篇 / 短篇 / 思想实验 / 角色卡扮演 …)
|
||||
→ 交互范式 skill:产出 设计.run_skill清单
|
||||
→ 每个 run skill 需要什么输入?
|
||||
→ agent 按需 invoke instantiate skill(能力库中的 SKILL.md)
|
||||
→ declare_instance_ready → play stage
|
||||
```
|
||||
|
||||
**能力库**(如 world-simulator 包内十几个 instantiate skill)不是 1→N 管道;agent 跳过不需要的 skill,并记录 `设计.跳过.{skillId}`。
|
||||
|
||||
### 1.2 示例:不同意图的 run skill 组合
|
||||
|
||||
| 用户意图 | run skill 示例 | 实例化倒推 |
|
||||
|----------|----------------|------------|
|
||||
| 长篇小说 | 变量管理、大纲推荐、转述者、世界机 | 变量目录 skill、叙事指南、世界蓝图… |
|
||||
| 短篇 | 情感流生成器 | 美学纲领、情感曲线约定 |
|
||||
| 思想实验 | 世界模拟器 | 规则、行动格式;**无**转述者 |
|
||||
| 角色卡扮演 | 转述者(+ 可选世界机) | 角色卡确认稿、口吻、回复格式 |
|
||||
|
||||
### 1.3 run 阶段交互形态
|
||||
|
||||
agent 在 play stage 的 burst 内调度 run skill,形态因包而异:
|
||||
|
||||
| 形态 | 适用 | sketch |
|
||||
|------|------|--------|
|
||||
| 单 skill 直出 | 简单大纲 | `outline` |
|
||||
| 行动–反应循环 | 博弈、世界模拟 | 世界机 ↔ 角色决策 ↔ 展示 |
|
||||
| 分叉验收 | 规则怪谈 | `write` → 双 `review` |
|
||||
|
||||
形态写在各 skill 的 **能力说明**里,**不**写进全局编排表逐步剧本。
|
||||
|
||||
---
|
||||
|
||||
## 2. 暂停与用户
|
||||
|
||||
### 2.1 边界 tool 即暂停
|
||||
|
||||
agent tool loop 在下列情况 **退出 burst**,进入 `waiting_user`:
|
||||
|
||||
```text
|
||||
ask_user / review_blackboard
|
||||
run_worker + requiresApproval
|
||||
worker 完成 + user_confirmed → review_artifact
|
||||
worker ask_user → worker_questions
|
||||
```
|
||||
|
||||
暂停策略写在 orchestrator manifest 的 **验收策略**,不是「第几步必须停」的管道表。
|
||||
|
||||
### 2.2 user-turn
|
||||
|
||||
用户亲自决策的环节:独立 skill,`用户.最新输入` 写入与 LLM 角色同形 tag,供世界机裁决。见 `worker-skill-format.md`。
|
||||
|
||||
---
|
||||
|
||||
## 3. 上下文:上半固定、下半动态
|
||||
|
||||
每个 skill(`SKILL.md`)声明:
|
||||
|
||||
```text
|
||||
inputTags / outputTags 黑板接口
|
||||
contextSegments static(上)+ dynamic(下)
|
||||
contextIsolation 谁看不见什么
|
||||
contextProfile variants 实例化时选档位
|
||||
```
|
||||
|
||||
原则:**稳定在上、增量在下**;Runtime 拼接,agent 不改。
|
||||
全文见 `docs/context-assembly.md`。
|
||||
|
||||
### 3.1 分层示例(roleplay-game-theory)
|
||||
|
||||
| tier | 含义 | tag 示例 |
|
||||
|------|------|----------|
|
||||
| static | 前提、实体设定 | `情境.实验.设定`、`角色.{id}.设定` |
|
||||
| dynamic | 历史、本轮 | `运行.事件流`、`可见信息` |
|
||||
|
||||
---
|
||||
|
||||
## 4. 倒推标签
|
||||
|
||||
对每个 skill 填表:
|
||||
|
||||
```text
|
||||
skill id | 职责 | stage(design/play) | inputTags | outputTags | contextSegments | 验收者
|
||||
```
|
||||
|
||||
### 4.1 角色扮演博弈(摘录)
|
||||
|
||||
| skill | 读取 | 写入 | 验收 |
|
||||
|-------|------|------|------|
|
||||
| setup-scenario | `用户.博弈需求` | 情境、规则、角色设定 | 用户 |
|
||||
| world-engine | 情境、规则、事件流、行动 | 可见信息、事件流 | 程序 |
|
||||
| role-decide | 本人设定、事件流、可见信息 | `.思考`、`.行动` | 程序 |
|
||||
| present-round | 本轮产物 | `输出.用户展示` | 用户 |
|
||||
|
||||
展示类 skill 单独存在;agent 调度,不拼长文。
|
||||
|
||||
---
|
||||
|
||||
## 5. 上下文隔离(必查)
|
||||
|
||||
```text
|
||||
□ 哪些 tag 只给用户、不注入生产 skill?
|
||||
□ 盲读 review 不可见哪些 tag?
|
||||
□ 草稿 vs 确认稿:下游何时可当作事实?
|
||||
□ 多角色:role_pov 是否生效?
|
||||
```
|
||||
|
||||
靠 `inputTags` + `contextIsolation` + Runtime 过滤,不靠 prompt 口头禁止。
|
||||
|
||||
---
|
||||
|
||||
## 6. orchestrator manifest(非编排表)
|
||||
|
||||
orchestrator.md 应包含:
|
||||
|
||||
```text
|
||||
□ 启动询问(最小 intake)
|
||||
□ instantiate skill 注册表(id、stage、description)
|
||||
□ run skill 注册表
|
||||
□ 验收策略(哪些 skill 产出需 user_confirmed)
|
||||
□ contextProfile 可选 variant 说明
|
||||
□ declare_instance_ready 最低可行性(按 run_skill清单 动态校验)
|
||||
```
|
||||
|
||||
**不应包含:** 逐步思维链、「第 5 步必须跑 world-engine」类管道脚本。
|
||||
|
||||
---
|
||||
|
||||
## 7. checklist
|
||||
|
||||
```text
|
||||
□ 1. 一句话:本包 play stage 的交互形态
|
||||
□ 2. 交互范式 skill 产出 run_skill清单 的 schema
|
||||
□ 3. 每个 run skill 倒推 instantiate skill 需求
|
||||
□ 4. 各 SKILL.md:input/output、contextSegments、隔离
|
||||
□ 5. shared-context.md(static 上半)
|
||||
□ 6. manifest:注册表 + 验收 + readiness
|
||||
□ 7. skills/README.md 注册
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. 示例包
|
||||
|
||||
| 包 | 特点 |
|
||||
|----|------|
|
||||
| `basic` | 单 run skill,最小上下文 |
|
||||
| `weird-rules-short` | 分叉验收 |
|
||||
| `roleplay-game-theory` | 行动–反应循环 |
|
||||
| `world-simulator`(规划) | 大能力库 + agent 实例化 |
|
||||
|
||||
对照时复用 **方法**,不照搬 tag 名或 skill 数量。
|
||||
|
||||
---
|
||||
|
||||
## 9. 相关文档
|
||||
|
||||
| 文档 | 关系 |
|
||||
|------|------|
|
||||
| `context-assembly.md` | 拼接规格 |
|
||||
| `creation-playbook.md` | 概念 |
|
||||
| `orchestrator-skill-format.md` | manifest 写法 |
|
||||
| `book-storage.md` | 过程与资产归档 |
|
||||
510
docs/skill-format.md
Normal file
510
docs/skill-format.md
Normal file
@@ -0,0 +1,510 @@
|
||||
# Skill 格式与存储
|
||||
|
||||
## 1. 定位:两层 Skill
|
||||
|
||||
本项目有 **两种 Skill 文档**,不要混在一个文件里:
|
||||
|
||||
| 类型 | 路径 | 消费者 | 写什么 |
|
||||
|------|------|--------|--------|
|
||||
| **总管 Skill** | `skills/{bookKind}/{name}/orchestrator.md` | Main Agent | **何时**调哪个 worker、验收方式、启动询问 |
|
||||
| **Worker Skill** | `workers/{workerId}/SKILL.md` | Worker Agent | **inputTags/outputTags**、怎么做 |
|
||||
|
||||
```text
|
||||
选 weird-rules-short(总管 Skill)
|
||||
→ 总管:brief 齐了 → run ruleset-worker,input=[project.brief]
|
||||
→ Worker:读 workers/ruleset-worker/SKILL.md → 写 core / rules / commentary
|
||||
→ 总管:rules accepted → run review-worker
|
||||
→ Worker:读 workers/review-worker/SKILL.md → 评估怎么做
|
||||
```
|
||||
|
||||
**何时评估** = 总管 Skill 的 Worker 编排表。
|
||||
**如何评估** = review-worker 的 Worker Skill。
|
||||
|
||||
详细规范:
|
||||
|
||||
- 总管 Skill → `docs/orchestrator-skill-format.md`
|
||||
- Worker Skill → `docs/worker-skill-format.md`
|
||||
|
||||
旧称「Skill = 创作说明书」仍成立,但说明书 **拆成编排(总管)与执行(worker)两份**。
|
||||
|
||||
```text
|
||||
会话开始
|
||||
→ 询问 1:选哪个总管 Skill(skills/{bookKind}/{name}/orchestrator.md)
|
||||
→ 加载总管 Skill
|
||||
→ 询问 2:读总管 Skill「## 启动询问」
|
||||
→ 之后总管按「Worker 编排」调度;Worker 读本 skill 包内 workers/{id}/SKILL.md
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 2. 存储位置
|
||||
|
||||
Skill 以 **Skill 包(skill pack)** 为单位:一个总管 + 其专属 workers,**同包绑定,不跨包复用 worker**。
|
||||
|
||||
```text
|
||||
skills/
|
||||
├── registry.yaml
|
||||
├── novel/ # Book 形态
|
||||
│ ├── basic/
|
||||
│ │ └── orchestrator.md # 总管 Skill
|
||||
│ ├── weird-rules-short/
|
||||
│ │ ├── orchestrator.md # 总管:何时调谁、黑板 key
|
||||
│ │ └── workers/ # 本总管专属,不与其他 skill 共享
|
||||
│ │ ├── write-rules/
|
||||
│ │ │ └── SKILL.md # 规则怪谈:怎么写规则+解析
|
||||
│ │ └── review/
|
||||
│ │ └── SKILL.md # 规则怪谈:怎么检查
|
||||
│ └── novel-standard/
|
||||
│ ├── orchestrator.md
|
||||
│ └── workers/
|
||||
│ ├── outline/SKILL.md
|
||||
│ └── drafting/SKILL.md
|
||||
└── dialogue/
|
||||
└── theater-roleplay/
|
||||
├── orchestrator.md
|
||||
└── workers/
|
||||
└── turn/SKILL.md
|
||||
```
|
||||
|
||||
规则:
|
||||
|
||||
```text
|
||||
第一层文件夹 = bookKind(novel | dialogue),决定 Book 存储结构
|
||||
第二层文件夹 = 一个 skill 包,名与 frontmatter.name 一致
|
||||
orchestrator.md 总管 Skill(编排、启动询问、验收)
|
||||
workers/{id}/ 本包专属 worker;id 在包内唯一即可
|
||||
Worker 不复用:novel-standard 的 outline worker ≠ weird-rules-short 的任何 worker
|
||||
registry.yaml 的 path 指向 orchestrator.md,如 novel/weird-rules-short/orchestrator.md
|
||||
```
|
||||
|
||||
**为何不复用 worker:** 同一「产出形状」(如规则表)在不同总管下的写法、Rubric、自检完全不同;共享 worker 会把体裁细节塞进总管或搞混上下文。需要相似流程时 **复制 worker 包再改**,而不是引用全局 worker。
|
||||
|
||||
与 Cursor skill 的区别:
|
||||
|
||||
| | Cursor Skill | 本项目 Skill |
|
||||
|---|---|---|
|
||||
| 位置 | `.cursor/skills/` | `skills/` |
|
||||
| 触发 | Agent 自动或显式引用 | **会话开始必须选一个** |
|
||||
| 内容 | 通用任务指南 | **创作流程 + 思维链 + 询问策略** |
|
||||
| 消费者 | Cursor Agent | 总管 LLM |
|
||||
|
||||
---
|
||||
|
||||
## 3. SKILL.md 结构
|
||||
|
||||
### 3.0 两层分类(重要)
|
||||
|
||||
Skill 分类分**两层**,不要混为一层:
|
||||
|
||||
```text
|
||||
第一层:Book 形态(category / bookKind,选定后不可换)
|
||||
novel 类小说存储:卷、章、大纲、正文(含各类小说子类型)
|
||||
dialogue 多轮多角色对话:回合、角色、场景(roleplay / 剧场)
|
||||
|
||||
第二层:具体 Skill 包(name,用户启动时选)
|
||||
每个包 = orchestrator.md + workers/,不是 category 下的平铺 .md 枚举。
|
||||
```
|
||||
|
||||
示例:
|
||||
|
||||
```text
|
||||
category: novel ← 第一层:Book 怎么存
|
||||
name: novel-standard ← 第二层:标准长篇流程
|
||||
name: weird-rules-short ← 第二层:规则怪谈短篇(仍是 novel Book)
|
||||
name: basic ← 第二层:最小演示
|
||||
|
||||
category: dialogue
|
||||
name: theater-roleplay ← 第二层:剧场式多角色互动
|
||||
```
|
||||
|
||||
**不要把「规则怪谈」做成与 novel 平级的 category。**
|
||||
规则怪谈是 **novel 形态下的专精 skill**,用 `name` + `tags` 区分:
|
||||
|
||||
```yaml
|
||||
---
|
||||
name: weird-rules-short
|
||||
description: 短篇规则怪谈:从隐含核心反推护命规则,再成章撰写。
|
||||
category: novel
|
||||
bookKind: novel
|
||||
tags: [novel, weird_rules, short, horror]
|
||||
---
|
||||
```
|
||||
|
||||
| 层级 | 字段 | 谁选 | 例子 |
|
||||
|---|---|---|---|
|
||||
| Book 形态 | `category` / `bookKind` | 选 skill 时确定,之后不变 | `novel` / `dialogue` |
|
||||
| 具体流程 | `name` | 启动询问 1:选哪个 SKILL.md | `weird-rules-short` |
|
||||
| 体裁标签 | `tags` | 可选,供匹配与过滤 | `weird_rules`, `standard` |
|
||||
|
||||
启动 UI 可以按 `category` 分组展示,组内列出多个 `name`(如「小说」下:标准长篇、规则怪谈短篇、…)。
|
||||
|
||||
参考 Cursor `SKILL.md`:YAML frontmatter + Markdown 正文。
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: novel-standard
|
||||
description: >-
|
||||
标准长篇小说创作:先简报、再大网、事件细化、正文。
|
||||
适用于用户要写小说、章节、大纲时使用。
|
||||
category: novel
|
||||
version: 1
|
||||
defaultFlowId: ghostwriting-flow
|
||||
tags: [novel, outline, draft]
|
||||
---
|
||||
|
||||
# 标准小说创作
|
||||
|
||||
## 启动询问
|
||||
|
||||
(流程 2:选 skill 后向用户展示什么、必收集项、写入 book.brief)
|
||||
|
||||
## 创作总纲
|
||||
|
||||
(给总管:这类内容是什么、总体顺序、禁忌)
|
||||
|
||||
## 总管思维链
|
||||
|
||||
(每轮决策前先检查什么、如何选 worker)
|
||||
|
||||
## 推荐阶段
|
||||
|
||||
(brief → outline → plotline → style → draft)
|
||||
|
||||
## 询问策略
|
||||
|
||||
### 总管应先问
|
||||
### 交给 Worker 问
|
||||
|
||||
## 推荐 Worker
|
||||
|
||||
## 示例
|
||||
```
|
||||
|
||||
### 3.1 Frontmatter 字段
|
||||
|
||||
```yaml
|
||||
---
|
||||
name: novel-standard # 必需,唯一 id,[a-z0-9-]
|
||||
description: > # 必需,供启动时向用户展示、供总管匹配
|
||||
第三人称描述 WHAT + WHEN。
|
||||
category: novel # 必需:Book 形态,见 §3.0
|
||||
bookKind: novel # 建议与 category 对齐;选定后 Book 结构固定
|
||||
version: 1
|
||||
defaultFlowId: ghostwriting-flow # 可选,绑定 execution flow
|
||||
defaultPresetId: writing-default # 可选
|
||||
tags: [novel, standard] # 体裁/子类型标签,如 weird_rules、short
|
||||
suggestedWorkers: # 可选,本 skill 常用 worker
|
||||
- outline-worker
|
||||
- plotline-worker
|
||||
- drafting-worker
|
||||
---
|
||||
```
|
||||
|
||||
| 字段 | 必需 | 用途 |
|
||||
|---|---|---|
|
||||
| `name` | ✅ | skill id;通常与文件名一致(不含 .md) |
|
||||
| `description` | ✅ | 启动选择列表展示;总管判断用户描述是否匹配 |
|
||||
| `category` | ✅ | 与 `bookKind` 一致:`novel` \| `dialogue` |
|
||||
| `bookKind` | 建议 | 选定后 Book 结构固定;缺省时由所在文件夹推断 |
|
||||
| `tags` | | 体裁细分:`weird_rules`、`standard` 等 |
|
||||
| `path` | registry | 相对路径,如 `novel/weird-rules-short.md` |
|
||||
| `defaultFlowId` | | 选中后默认 execution flow |
|
||||
| `suggestedWorkers` | | 总管选 worker 时的白名单提示 |
|
||||
|
||||
### 3.2 撰写标准:写作生命周期(推荐)
|
||||
|
||||
Skill 文件本质上是**给 LLM 与 Runtime 读的字符串规格**。下面这套「触发 → 写前 → 写中 → 写后 → 质量维度」与现有阶段机、验收模式对齐,**应作为所有 skill `.md` 的撰写标准**。
|
||||
|
||||
```text
|
||||
┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
|
||||
│ 触发条件 │ → │ 写作前 │ → │ 写作中 │ → │ 写作后 │ → │ 质量维度 │
|
||||
│ 何时激活 │ │ 需求分析 │ │ 分步引导 │ │ 自检润色 │ │ 可量化 Rubric│
|
||||
└─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘ └─────────────┘
|
||||
frontmatter 启动询问 推荐阶段 自检清单 质量评估标准
|
||||
+ tags + 创作总纲 + 示例/约束 + 验收策略 + 接受度(预留)
|
||||
+ 询问策略 + 禁用行为
|
||||
```
|
||||
|
||||
#### 与正文章节的对应关系
|
||||
|
||||
| 生命周期 | 对应章节 | 写什么 |
|
||||
|---|---|---|
|
||||
| **触发条件** | frontmatter `description` + `tags` | 何时应选本 skill;用户说什么话时应匹配(如「规则怪谈」「短篇怪谈」) |
|
||||
| **写作前 · 需求分析** | `## 启动询问` + `## 创作总纲` | 对象、受众、语气、目标、禁忌;**禁止直接动笔**;写入哪个 key |
|
||||
| **写作中 · 分步引导** | `## 推荐阶段` + `## 示例` + `## 禁用行为` | 阶段链、每步约束、好/坏示例;对应 worker 与产出 key |
|
||||
| **写作后 · 自检润色** | `## 自检清单` + `## 验收策略` | 产出前检查点;LLM 自审 vs 人工 vs 程序验收 |
|
||||
| **质量评估** | `## 质量评估标准` | 可量化维度 + 各 stage 的 acceptanceMode |
|
||||
| **编排** | `## 总管思维链` + `## 询问策略` + `## 推荐 Worker` | 总管如何调度;谁向用户提问 |
|
||||
|
||||
不必每个 skill 都写独立 `# 写作前` 大标题;**用统一章节名即可**,内容覆盖上表即可。
|
||||
|
||||
#### `## 质量评估标准`(必需)
|
||||
|
||||
避免只写「写得更好」。每个 skill 应列出 **可检查的质量维度**,格式建议:
|
||||
|
||||
```markdown
|
||||
## 质量评估标准
|
||||
|
||||
| 维度 | 说明 | 检查方式 |
|
||||
|---|---|---|
|
||||
| 完整性 | 是否满足启动询问中的必收集项 | programmatic / 人工 |
|
||||
| 体裁符合 | 是否符合创作总纲(如规则怪谈:规则可反推危险) | LLM 自审 + 人工 |
|
||||
| 一致性 | 与已 accepted 上游产物是否矛盾 | programmatic |
|
||||
| **接受度** | 用户/系统是否接受该产物(预留) | user_confirmed → 记录 accept/reject |
|
||||
|
||||
各 stage 默认 acceptanceMode 见「验收策略」。
|
||||
```
|
||||
|
||||
**「接受度」维度(预留):**
|
||||
|
||||
- 第一版:**不强制数值打分**;用阶段机的 `user_accepted_artifact` / `reject` 记录二元结果即可。
|
||||
- 后续可在 Book / Session 元数据写入 `acceptanceScore` 或 `acceptanceNotes`(字符串或 1–5 分),与 Skill Rubric 对齐。
|
||||
- Skill 里写清楚:**接受度由验收事件沉淀,不由 LLM 自报分数代替人工。**
|
||||
|
||||
#### `## 自检清单`(必需)
|
||||
|
||||
写作后、提交验收前,worker 或总管应过的检查点(字符串列表即可):
|
||||
|
||||
```markdown
|
||||
## 自检清单
|
||||
|
||||
### rules.draft 提交前
|
||||
- [ ] 每条规则能否对应非玄学的危险动机?
|
||||
- [ ] 是否未直接写出 core.danger?
|
||||
- [ ] 是否无「违反即抹杀」空规则?
|
||||
|
||||
### content.chapter.* 提交前
|
||||
- [ ] 是否遵守 rules.draft 已 accepted 版本?
|
||||
- [ ] …
|
||||
```
|
||||
|
||||
与 `programmatic_review` 的关系:自检清单 = LLM/人读的规范;程序验收 = 可机械执行的子集。
|
||||
|
||||
#### 模板骨架(`skills/{bookKind}/{name}.md`)
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: …
|
||||
description: … # 触发条件(WHEN)
|
||||
tags: …
|
||||
category / bookKind: …
|
||||
suggestedWorkers: …
|
||||
---
|
||||
|
||||
# 标题
|
||||
|
||||
## 启动询问 # 写作前 · 需求分析
|
||||
## 创作总纲
|
||||
## 总管思维链
|
||||
## 推荐阶段 # 写作中 · 分步引导
|
||||
## 询问策略
|
||||
## 推荐 Worker
|
||||
## 示例 # 写作中 · 约束与范例
|
||||
## 禁用行为
|
||||
## 自检清单 # 写作后
|
||||
## 验收策略 # 写作后 · 与 acceptanceMode 绑定
|
||||
## 质量评估标准 # Rubric + 接受度(预留)
|
||||
## Book 结构 # 可选,novel / dialogue 形态说明
|
||||
```
|
||||
|
||||
代码当前**结构化解析**的仍主要是 `## 启动询问`;其余章节整段注入总管 prompt(待 `buildSkillContext`)。**全部是 Markdown 字符串,不矛盾。**
|
||||
|
||||
### 3.3 正文必需章节(检查清单)
|
||||
|
||||
| 章节 | 生命周期 | 内容 |
|
||||
|---|---|---|
|
||||
| frontmatter | 触发 | name、description、tags、bookKind |
|
||||
| **启动询问** | 写前 | 必收集项、写入 key |
|
||||
| **创作总纲** | 写前 | 顺序、边界、体裁原则 |
|
||||
| **推荐阶段** | 写中 | 阶段链、worker、产出 key、prerequisites |
|
||||
| **示例** | 写中 | 好/坏对照或完整流程范例 |
|
||||
| **禁用行为** | 写中 | 绝对不要做的事 |
|
||||
| **自检清单** | 写后 | 提交验收前的检查点 |
|
||||
| **验收策略** | 写后 | 各 stage 的 acceptanceMode |
|
||||
| **质量评估标准** | 质量 | 可量化维度 + **接受度(预留)** |
|
||||
| **总管思维链** | 编排 | 每轮决策检查 |
|
||||
| **询问策略** | 编排 | 总管问 vs worker 问 |
|
||||
| **推荐 Worker** | 编排 | 与 suggestedWorkers 一致 |
|
||||
|
||||
可选:`## Book 结构`、`examples.md` 外链。
|
||||
|
||||
---
|
||||
|
||||
## 4. registry.yaml(可选)
|
||||
|
||||
启动时列举可用 skill,不必扫描目录:
|
||||
|
||||
```yaml
|
||||
skills:
|
||||
- name: novel-standard
|
||||
description: 标准长篇小说:大纲 → 事件 → 正文
|
||||
category: novel
|
||||
- name: weird-rules-short
|
||||
description: 短篇规则怪谈:隐含核心 → 护命规则 → 成章
|
||||
category: novel
|
||||
- name: theater-roleplay
|
||||
description: 剧场式角色扮演:角色 → 场景 → 回合互动
|
||||
category: dialogue
|
||||
- name: forum-thread
|
||||
description: 论坛体连载:楼主身份 → 回帖风格 → 楼层
|
||||
category: novel
|
||||
```
|
||||
|
||||
若无 `registry.yaml`,Runtime 扫描 `skills/novel/*.md` 与 `skills/dialogue/*.md`。
|
||||
**registry 列举的是第二层 skill(name),不是 category。**
|
||||
|
||||
---
|
||||
|
||||
## 5. 会话启动:第一个询问是选 Skill
|
||||
|
||||
Skill 选择发生在**任何创作逻辑之前**。
|
||||
|
||||
### 5.1 启动转移
|
||||
|
||||
```text
|
||||
idle
|
||||
session_started
|
||||
→ waiting_user(skill_selection)
|
||||
```
|
||||
|
||||
新增 `waitingReason`:
|
||||
|
||||
```ts
|
||||
| { kind: "skill_selection"; availableSkills: SkillIndexEntry[] }
|
||||
```
|
||||
|
||||
### 5.2 向用户展示
|
||||
|
||||
```text
|
||||
请选择创作类型:
|
||||
|
||||
【小说】(Book 形态:卷 / 章)
|
||||
1. novel-standard — 标准长篇:大纲 → 事件 → 正文
|
||||
2. weird-rules-short — 短篇规则怪谈:核心 → 规则 → 成章
|
||||
3. basic — 最小演示
|
||||
|
||||
【对话】(Book 形态:回合 / 多角色)
|
||||
4. theater-roleplay — 剧场式角色扮演
|
||||
|
||||
也可直接描述你想写什么,我会帮你匹配 skill name。
|
||||
```
|
||||
|
||||
### 5.3 用户回答方式
|
||||
|
||||
```text
|
||||
输入编号或 name:novel-standard
|
||||
输入自然语言:我想写一个剧场扮演
|
||||
输入自定义:用 novel-standard,但是偏悬疑
|
||||
```
|
||||
|
||||
Runtime 解析为 `skill_selected` 事件:
|
||||
|
||||
```ts
|
||||
{ type: "skill_selected"; payload: { skillId: string; userHint?: string } }
|
||||
```
|
||||
|
||||
然后:
|
||||
|
||||
```text
|
||||
加载 skills/{skillId}/SKILL.md
|
||||
解析 ## 启动询问 → session.slots.activeSkill
|
||||
→ waiting_user(input)
|
||||
message 来自 SKILL.md「启动询问·向用户展示」
|
||||
必收集项 / 写入目标 同样来自该节
|
||||
```
|
||||
|
||||
### 5.4 两阶段启动
|
||||
|
||||
```text
|
||||
询问 1(系统) skill_selection 「用哪个 skill?」→ registry / description
|
||||
询问 2(skill) input 「启动询问」章节 → 每类内容问的不同
|
||||
```
|
||||
|
||||
**只有询问 1 是系统固定的。询问 2 及之后所有创作逻辑,都在 SKILL.md 里。**
|
||||
|
||||
---
|
||||
|
||||
## 6. 总管如何使用已选 Skill
|
||||
|
||||
`session.slots.activeSkill` 加载后,总管 prompt 注入:
|
||||
|
||||
```text
|
||||
当前 skill: novel-standard
|
||||
category: novel
|
||||
创作总纲: (SKILL.md 摘要或全文)
|
||||
当前推荐阶段: outline(由 resolver 根据黑板推断)
|
||||
询问策略: 总管应先问 brief;outline 细节交给 worker
|
||||
建议 worker: outline-worker, drafting-worker
|
||||
defaultFlowId: ghostwriting-flow
|
||||
```
|
||||
|
||||
总管决策仍通过 tool / JSON 决策,**不**直接改 phase。
|
||||
|
||||
---
|
||||
|
||||
## 7. 示例
|
||||
|
||||
完整示例见仓库内真实文件(不要只在文档里维护一份):
|
||||
|
||||
```text
|
||||
skills/novel/weird-rules-short.md
|
||||
skills/dialogue/theater-roleplay.md
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 8. 解析与加载(将来代码)
|
||||
|
||||
| 文件 | 干嘛的 |
|
||||
|---|---|
|
||||
| `src/skills/types.ts` | SkillIndexEntry、ParsedSkill 类型 |
|
||||
| `src/skills/loader.ts` | 扫描 skills/、解析 frontmatter + 正文 |
|
||||
| `src/skills/registry.ts` | 读 registry.yaml 或目录扫描 |
|
||||
| `src/skills/resolver.ts` | 根据黑板 index 推断当前 stage |
|
||||
|
||||
加载流程:
|
||||
|
||||
```text
|
||||
listSkills() → SkillIndexEntry[]
|
||||
loadSkill(skillId) → ParsedSkill(含 startupInquiry 解析自 ## 启动询问)
|
||||
selectSkill(session, skillId) → session.slots.activeSkill
|
||||
getStartupPrompt(activeSkill) → 流程 2 展示文案
|
||||
buildSkillContext(activeSkill, blackboardIndex) → 总管 prompt 片段
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 10. 与 creation-playbook.md 的关系
|
||||
|
||||
`creation-playbook.md` 描述**概念与数据结构**(Playbook、Stage、InquiryPolicy)。
|
||||
|
||||
**本文件**描述**落盘格式**(SKILL.md 怎么写、放哪、启动时怎么选)。
|
||||
|
||||
关系:
|
||||
|
||||
```text
|
||||
Creation Playbook(概念)
|
||||
= SKILL.md(存储)+ stages.yaml(可选结构化)
|
||||
+ session.slots.activeSkill(运行时)
|
||||
```
|
||||
|
||||
`creation-playbook.md` 中的 TS 类型,实现时可从 SKILL.md 解析或从 stages.yaml 读取。
|
||||
|
||||
---
|
||||
|
||||
## 11. 第一版范围
|
||||
|
||||
```text
|
||||
skills/ 目录 + 2 个示例 SKILL.md(novel、theater)
|
||||
启动 → skill_selection → 用户选择 → 加载 skill
|
||||
总管 prompt 注入 skill 摘要
|
||||
registry.yaml 可选
|
||||
```
|
||||
|
||||
不做:
|
||||
|
||||
```text
|
||||
skill 可视化编辑器
|
||||
运行时 LLM 自动生成 skill
|
||||
与 Cursor .cursor/skills 混用(路径独立)
|
||||
```
|
||||
573
docs/tag-blackboard.md
Normal file
573
docs/tag-blackboard.md
Normal file
@@ -0,0 +1,573 @@
|
||||
# 标签驱动黑板
|
||||
|
||||
## 1. 定位
|
||||
|
||||
本系统用于多 worker 协作式文本生成,覆盖:
|
||||
|
||||
```text
|
||||
简易小说快速撰写(quick-write)
|
||||
规则怪谈 / 短篇结构化创作(weird-rules-short 等)
|
||||
长篇小说 / 交互式写作助手(interactive-novel,TODO)
|
||||
场景扮演模拟(scene-roleplay,TODO)
|
||||
角色扮演 / 角色卡互动(并入 scene-roleplay 的 instantiate + run,见 §2)
|
||||
```
|
||||
|
||||
核心思想:
|
||||
|
||||
```text
|
||||
黑板 = 标签化数据池
|
||||
标签 = skill 之间的接口
|
||||
skill = SKILL.md 定义的能力;worker = 一次 invoke
|
||||
Agent = tool loop 内调度 invoke 哪个 skill
|
||||
Runtime = 按 skill 契约拼接上下文(上半固定、下半动态)
|
||||
```
|
||||
|
||||
一句话:**标签驱动 + agent 选 skill + Runtime 拼上下文**——不是固定流水线,也不是 LLM 自由分发上下文。
|
||||
|
||||
上下文拼接见 `docs/context-assembly.md`。不要让 agent 临场改 inputTags;分发由 `inputTags` + `contextSegments` 静态声明。
|
||||
|
||||
---
|
||||
|
||||
## 2. Skill 定义、实例化与 Book
|
||||
|
||||
### 2.1 类比
|
||||
|
||||
```text
|
||||
Skill 包(orchestrator manifest + workers) = 能力定义(静态)
|
||||
Session + 黑板 tag = 一次运行的实参
|
||||
Book = 过程、资产、游玩(见 book-storage.md)
|
||||
play stage = agent invoke run skill
|
||||
```
|
||||
|
||||
**写角色卡、收集设定、启动询问** 都不是独立「产品模式」,而是 **实例化阶段** 的不同形态:把 prerequisite tags 写满,然后才进入运行阶段。
|
||||
|
||||
### 2.2 三层阶段(勿混淆)
|
||||
|
||||
```text
|
||||
运行相位(RuntimePhase)
|
||||
idle | running | waiting_user | done | error
|
||||
系统在等什么。见 runtime-state-machine.md
|
||||
|
||||
业务 stage(Book / Session)
|
||||
design(实例化)→ play(运行)→ done
|
||||
|
||||
tag 阶段(黑板条目 tag 名中的段)
|
||||
候选 | 草稿 | 确认稿 | 当前 | 更新
|
||||
单条数据的 lifecycle
|
||||
```
|
||||
|
||||
业务 stage **写在各 skill 的 orchestrator.md**,不扩运行相位 enum。
|
||||
|
||||
### 2.3 实例化(design)
|
||||
|
||||
**职责:** agent 按需 invoke instantiate skill,沉淀 `设计.*` tag;产出 `设计.run_skill清单` 后 declare ready。
|
||||
|
||||
```text
|
||||
选 orchestrator 包
|
||||
→ design stage:启动询问 → agent invoke instantiate skill(能力库)
|
||||
→ declare_instance_ready
|
||||
→ play stage:agent invoke run skill
|
||||
→ done → 归档 Book(过程 + 资产,见 book-storage.md)
|
||||
```
|
||||
|
||||
可从 Book / CardAsset 加载已有 tag,跳过部分 instantiate skill。
|
||||
|
||||
运行相位上,实例化阶段多为 `waiting_user(input)`(启动询问、总管 ask_user);实例化也可调用 **setup worker**,但仍是 worker(固定 inputTags/outputTags),不是第二个生产总管。
|
||||
|
||||
### 2.4 每个 skill 声明什么
|
||||
|
||||
在 orchestrator.md 中写清(见 orchestrator-skill-format.md):
|
||||
|
||||
```text
|
||||
## 启动询问 / ## 实例化
|
||||
prerequisiteTags:本 skill 运行前必须有的 tag
|
||||
instanceReadyWhen:何时可进入 run stage(文字条件 + tag 列表)
|
||||
写入目标 tag(可多个;不必再塞进单一 book.brief)
|
||||
|
||||
## 阶段定义
|
||||
instantiate(或沿用 stageId brief)→ run(write / review …)→ done
|
||||
|
||||
## Worker 编排
|
||||
仅 run stage 及之后调度生产 worker;instantiate 阶段只 ask_user 或 run setup worker
|
||||
```
|
||||
|
||||
### 2.5 已有雏形:weird-rules-short
|
||||
|
||||
| 业务 stage | 现 stageId | 含义 |
|
||||
|---|---|---|
|
||||
| 实例化 | `brief` | 启动询问 → `book.brief`(≈ `需求.核心要点`)→ `startupCompleted` |
|
||||
| 运行 | `write` | `write-rules` 产出规则与 core |
|
||||
| 运行 | `review` | 双验收 worker |
|
||||
| 结束 | `done` | finish |
|
||||
|
||||
`basic` 同理:`brief` = 实例化,`outline` worker = 运行。
|
||||
文档与实现迁移时,可将 stageId 改名为 `instantiate`,或保留 `brief` 但在 ## 阶段定义 注明 **brief ≡ instantiate**。
|
||||
|
||||
### 2.6 角色卡
|
||||
|
||||
不再单独维护 `character-card-author` skill 包。角色设定、口吻、行为边界等 tag 在 **扮演类 skill 的 instantiate 段** 收集或生成(可选 setup worker)。
|
||||
若需跨 Session 复用,将 `角色.A.设定`、`角色卡.确认稿` 等 **确认稿** 存入 Book,新 Session **加载 Book** 而非再跑完整实例化。
|
||||
|
||||
### 2.7 Book 与黑板
|
||||
|
||||
```text
|
||||
黑板(Session 内) 运行时 tag 池;worker 读写
|
||||
Book(项目级) 长期实例;accepted 确认稿归档;下一场 Session 可加载
|
||||
```
|
||||
|
||||
详见 `docs/book-storage.md`。Session 是一次运行;Book 是一个创作项目(一本小说、一个扮演项目)。
|
||||
|
||||
---
|
||||
|
||||
## 3. 黑板条目
|
||||
|
||||
### 2.1 最小结构
|
||||
|
||||
```ts
|
||||
type BlackboardItem = {
|
||||
id: string;
|
||||
tag: string;
|
||||
content: string;
|
||||
source: string;
|
||||
metadata?: Record<string, unknown>;
|
||||
};
|
||||
```
|
||||
|
||||
### 2.2 可选增强
|
||||
|
||||
```ts
|
||||
type BlackboardItem = {
|
||||
id: string;
|
||||
tag: string;
|
||||
content: string;
|
||||
source: string;
|
||||
scope?: string;
|
||||
createdAt?: number;
|
||||
updatedAt?: number;
|
||||
dependencies?: string[];
|
||||
metadata?: Record<string, unknown>;
|
||||
};
|
||||
```
|
||||
|
||||
### 2.3 字段含义
|
||||
|
||||
```text
|
||||
id 唯一标识,追踪与依赖
|
||||
tag 标签本体,决定身份与消费路径(核心)
|
||||
content 具体内容(字符串)
|
||||
source 产生该条目的 worker id,调试用
|
||||
scope 作用范围,如当前章节、场景、项目(可选)
|
||||
dependencies 依赖的其他黑板条目 id(可选)
|
||||
metadata 置信度、真实性、控制模式等(不参与基础路由)
|
||||
```
|
||||
|
||||
注意:
|
||||
|
||||
```text
|
||||
tag 是核心路由依据。
|
||||
source 不是路由依据,只用于调试与溯源。
|
||||
metadata 不参与基础路由,除非某 skill 明确约定。
|
||||
```
|
||||
|
||||
**已废弃:** 旧模型的 `key`、`summary`、`tags[]`、`readableBy`、`writableBy` 作为路由字段。迁移期代码可能仍保留 `BlackboardEntry`,以本文为准逐步替换。
|
||||
|
||||
---
|
||||
|
||||
## 4. 标签原则
|
||||
|
||||
标签不是信息分类学,而是 **工作流接口**。
|
||||
|
||||
### 3.1 设计原则
|
||||
|
||||
```text
|
||||
标签越少越好,但必须能区分不同消费路径。
|
||||
两个信息若永远被同一批 worker 消费,可合并 tag。
|
||||
若在不同阶段被不同 worker 消费,必须拆分 tag。
|
||||
若可能被误当成事实,必须加阶段段。
|
||||
若涉及角色私有认知,tag 里必须体现角色归属。
|
||||
```
|
||||
|
||||
### 3.2 推荐格式
|
||||
|
||||
```text
|
||||
对象.内容
|
||||
对象.内容.阶段
|
||||
领域.对象.内容.阶段
|
||||
```
|
||||
|
||||
不强制四段式;按复杂度逐级增加。
|
||||
|
||||
示例:
|
||||
|
||||
```text
|
||||
大纲.草稿
|
||||
事件.草稿
|
||||
正文.草稿
|
||||
正文.确认稿
|
||||
|
||||
角色.A.行动.候选
|
||||
角色.A.台词.候选
|
||||
角色.A.内心想法.候选
|
||||
角色.A.记忆.当前
|
||||
```
|
||||
|
||||
### 3.3 标签替代的旧字段
|
||||
|
||||
```text
|
||||
角色.A.内心想法.候选
|
||||
```
|
||||
|
||||
已表达:归属 A、类型为内心想法、阶段为候选、消费路径由声明 inputTags 的 worker 决定。
|
||||
|
||||
**不需要** 再写 `owner`、`visibleTo`、`type=action` 等平行字段。
|
||||
|
||||
### 3.4 匹配规则(Runtime)
|
||||
|
||||
Worker frontmatter 声明 `inputTags`:
|
||||
|
||||
```yaml
|
||||
inputTags:
|
||||
- "需求.核心要点" # 精确匹配
|
||||
- "角色.A.*" # 前缀匹配:tag 以「角色.A.」开头
|
||||
- "大纲.*.草稿" # 前缀匹配
|
||||
```
|
||||
|
||||
规则:
|
||||
|
||||
```text
|
||||
无通配 → 精确匹配 tag
|
||||
以 .* 结尾 → 前缀匹配(实现优先于完整正则)
|
||||
多条命中 → 默认按 updatedAt 取最新;或 worker 声明 inputMerge: concat | latest
|
||||
```
|
||||
|
||||
总管调度时也可对 **tag 索引**(不含 content)做存在性判断,例如「是否有 规则.确认稿」。
|
||||
|
||||
---
|
||||
|
||||
## 5. 阶段标签
|
||||
|
||||
阶段表示同一类信息在不同生命周期下的语义。
|
||||
|
||||
```text
|
||||
候选 worker 生成的可能内容,不等于事实
|
||||
草稿 生成中的文本或结构
|
||||
确认稿 用户或流程确认,可进入长期状态
|
||||
当前 当前生效状态
|
||||
更新 状态变化结果
|
||||
```
|
||||
|
||||
重要规则:
|
||||
|
||||
```text
|
||||
候选 ≠ 已发生。
|
||||
草稿 ≠ 确认稿。
|
||||
角色行动候选不能直接写入长期记忆。
|
||||
长期记忆优先从正文.确认稿 与明确 记忆.更新 生成。
|
||||
```
|
||||
|
||||
验收(`user_confirmed` / `programmatic_review`)通过后,Runtime 将对应产物 tag 从 `.草稿` 升级为 `.确认稿`(或写入新的确认稿条目并标记旧草稿 superseded)。
|
||||
|
||||
---
|
||||
|
||||
## 6. Worker
|
||||
|
||||
每个 worker 是固定的标签消费者和生产者。
|
||||
|
||||
### 5.1 类型
|
||||
|
||||
```ts
|
||||
type WorkerDefinition = {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
inputTags: string[];
|
||||
outputTags: string[];
|
||||
inputMerge?: "latest" | "concat";
|
||||
run: (context: WorkerContext) => Promise<WorkerResult>;
|
||||
};
|
||||
|
||||
type WorkerContext = {
|
||||
taskId: string;
|
||||
workerId: string;
|
||||
items: BlackboardItem[];
|
||||
params?: Record<string, unknown>;
|
||||
};
|
||||
|
||||
type WorkerResult = {
|
||||
items: BlackboardItem[];
|
||||
logs?: string[];
|
||||
askUser?: string[];
|
||||
};
|
||||
```
|
||||
|
||||
### 5.2 规则
|
||||
|
||||
```text
|
||||
worker 只能读取 inputTags 声明的标签(含前缀规则)。
|
||||
worker 只能输出 outputTags 声明的标签。
|
||||
worker 不读取全量黑板。
|
||||
LLM 不决定自己能看什么。
|
||||
Runtime 校验 outputs 的 tag ⊆ outputTags。
|
||||
```
|
||||
|
||||
### 5.3 Worker Skill 落盘
|
||||
|
||||
见 `docs/worker-skill-format.md`。正文写「怎么做」;`inputTags` / `outputTags` 写在 frontmatter。
|
||||
|
||||
### 5.4 ask_user
|
||||
|
||||
提问是 worker **能力**,不是独立 worker。中途提问时 `resumeContext` 保存 workerId,**不**保存 inputTags(恢复时仍从 Worker Skill 读 inputTags)。
|
||||
|
||||
---
|
||||
|
||||
## 7. 总管(Main Agent)
|
||||
|
||||
总管只负责流程推进。
|
||||
|
||||
### 6.1 职责
|
||||
|
||||
```text
|
||||
判断当前任务属于哪种 skill / 业务阶段
|
||||
选择下一个 worker(run_worker)
|
||||
判断是否需要追问用户(ask_user)
|
||||
判断是否需要用户确认下一步(requiresApproval)
|
||||
判断是否 finish
|
||||
```
|
||||
|
||||
### 6.2 不负责
|
||||
|
||||
```text
|
||||
不决定某条信息给谁看
|
||||
不手动拼接 worker 上下文
|
||||
不让 LLM 判断信息权限
|
||||
不把全量黑板交给 worker
|
||||
不在 run_worker 里指定 inputTags / outputTags
|
||||
```
|
||||
|
||||
### 6.3 决策结构
|
||||
|
||||
```ts
|
||||
type MainAgentDecision = {
|
||||
id: string;
|
||||
action: "ask_user" | "run_worker" | "create_temp_worker" | "review_blackboard" | "finish";
|
||||
reason: string;
|
||||
workerId?: string;
|
||||
requiresApproval: boolean;
|
||||
statePatchAllowed: false;
|
||||
};
|
||||
```
|
||||
|
||||
执行链:
|
||||
|
||||
```text
|
||||
总管选择 worker
|
||||
→ Runtime 读取该 worker 的 inputTags
|
||||
→ 从黑板取匹配条目,组装 WorkerContext
|
||||
→ 调用 worker
|
||||
→ worker 输出固定 outputTags
|
||||
→ 写回黑板
|
||||
→ 按 acceptanceMode 验收
|
||||
```
|
||||
|
||||
Tool 合约见 `docs/tool-contracts.md`。
|
||||
|
||||
---
|
||||
|
||||
## 8. Skill 包与 manifest
|
||||
|
||||
Skill 包 = `orchestrator.md`(manifest)+ `workers/*/SKILL.md`。详见 `orchestrator-skill-format.md`。
|
||||
|
||||
manifest 包含:
|
||||
|
||||
```text
|
||||
Skill 注册表(instantiate + run)
|
||||
验收策略
|
||||
Instance Ready 规则
|
||||
```
|
||||
|
||||
**不写** 逐步编排表。inputTags / contextSegments 在 Worker SKILL.md。
|
||||
|
||||
### 8.1 已启用包
|
||||
|
||||
| 包 | 说明 |
|
||||
|---|---|
|
||||
| `novel/basic` | 演示:需求 → 大纲 |
|
||||
| `novel/weird-rules-short` | 规则怪谈:写 + 双验收 |
|
||||
|
||||
### 8.2 规划包(见 `skills/README.md`)
|
||||
|
||||
| 包 | 说明 |
|
||||
|---|---|
|
||||
| `novel/quick-write` | **简易档**:几乎无 tag 路由,上下文全量给 LLM |
|
||||
| `novel/interactive-novel` | 长篇 / 写作助手:instantiate + 多轮 run |
|
||||
| `novel/novel-standard` | 标准流水线(或与 interactive 合并) |
|
||||
| `dialogue/scene-roleplay` | 场景扮演(含角色设定 instantiate + 互动 run) |
|
||||
|
||||
---
|
||||
|
||||
## 9. 各模式核心 tag(参考)
|
||||
|
||||
实现 skill 时从下列词汇出发,不必一次全部实现。
|
||||
|
||||
### 8.1 简易小说(quick-write)
|
||||
|
||||
极简;可大量依赖 session + 全量上下文,tag 仅作交付锚点:
|
||||
|
||||
```text
|
||||
用户.输入
|
||||
需求.摘要
|
||||
正文.草稿
|
||||
正文.确认稿
|
||||
```
|
||||
|
||||
### 8.2 结构化短篇(如 weird-rules-short)
|
||||
|
||||
迁移目标示例(与现 key 对照实施):
|
||||
|
||||
```text
|
||||
需求.核心要点 ← book.brief
|
||||
核心.危险.隐藏 ← core.danger
|
||||
规则.草稿 ← rules.draft
|
||||
规则.说明.草稿 ← rules.commentary
|
||||
验收.读者视角.记录 ← review.infer.notes
|
||||
验收.作者视角.记录 ← review.author.notes
|
||||
```
|
||||
|
||||
### 8.3 交互式长篇
|
||||
|
||||
```text
|
||||
用户.原始输入 | 用户.意图转述 | 用户.确认结果
|
||||
项目.设定 | 项目.风格要求
|
||||
大纲.当前 | 大纲.候选修改 | 大纲.确认稿
|
||||
事件.当前 | 事件.确认稿
|
||||
正文.原文 | 正文.续写锚点 | 正文.草稿 | 正文.确认稿
|
||||
记忆.长期摘要 | 记忆.确认稿
|
||||
```
|
||||
|
||||
### 8.4 场景扮演
|
||||
|
||||
```text
|
||||
用户.行动输入 | 用户.行动意图
|
||||
世界.规则 | 世界.当前状态 | 世界.隐藏状态
|
||||
场景.可见信息 | 场景.隐藏信息
|
||||
角色.{id}.记忆 | 信念 | 行动.候选 | 台词.候选
|
||||
行动.裁决结果
|
||||
输出.场景反馈
|
||||
更新.世界状态 | 更新.角色状态
|
||||
```
|
||||
|
||||
### 8.5 角色卡
|
||||
|
||||
撰写:`角色卡.草稿` → `角色卡.确认稿`
|
||||
游玩:读 `角色卡.确认稿` + `用户.控制模式` + `NPC.*`
|
||||
|
||||
---
|
||||
|
||||
## 10. 正文 worker 与角色候选
|
||||
|
||||
角色 worker 输出 `角色.*.台词.候选` 等,**不**直接进入正文事实。
|
||||
|
||||
正文 worker 读取候选 + 风格约束,输出 `正文.草稿`;用户确认后为 `正文.确认稿`。
|
||||
|
||||
```text
|
||||
角色候选 → 提供意图
|
||||
正文 worker → 文本化、风格化、叙事化
|
||||
正文.确认稿 → 最终发生与表达
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 11. 可选增强
|
||||
|
||||
### 10.1 采用记录
|
||||
|
||||
```text
|
||||
tag: 采用.记录
|
||||
```
|
||||
|
||||
记录正文采用了哪些候选条目,避免未采用候选污染记忆。早期可省略,记忆 worker 只从 `正文.确认稿` 抽取。
|
||||
|
||||
### 10.2 真实性 / 置信度(metadata)
|
||||
|
||||
```ts
|
||||
type TruthMode =
|
||||
| "truth" | "belief" | "claim" | "lie" | "rumor" | "plan" | "unknown";
|
||||
```
|
||||
|
||||
不参与基础路由。
|
||||
|
||||
### 10.3 RAG
|
||||
|
||||
RAG 不替代黑板。检索结果也应写成 tag,例如 `角色.A.相关记忆摘要`,由 worker 通过 inputTags 读取。
|
||||
|
||||
---
|
||||
|
||||
## 12. 与阶段机的关系
|
||||
|
||||
运行相位、业务 stage、tag 阶段 **三者正交**(详见 §2.2):
|
||||
|
||||
```text
|
||||
运行相位 系统在等什么(见 runtime-state-machine.md)
|
||||
业务 stage instantiate → run → done(orchestrator.md;brief 即 instantiate)
|
||||
tag 阶段 黑板条目 lifecycle(候选 / 草稿 / 确认稿)
|
||||
```
|
||||
|
||||
实例化阶段在运行相位上通常体现为 `waiting_user(input)`;进入 run stage 后为 `running` + worker 验收循环。
|
||||
阶段机 enum 不增加 `instantiate` 相位——业务 stage 由 orchestrator + tag 索引判断。
|
||||
|
||||
阶段机规则本身不因 tag 迁移而改变。变的是:黑板读写、worker 上下文、总管决策字段。
|
||||
|
||||
---
|
||||
|
||||
## 13. 与 Book 存储
|
||||
|
||||
Book 存长期实例;黑板存 **当前 Session** 的运行时 tag。实例化产物与 run 阶段确认稿可归档到 Book。
|
||||
详见 `docs/book-storage.md` 与 §2.7。
|
||||
|
||||
---
|
||||
|
||||
## 14. 实现原则(必须遵守)
|
||||
|
||||
```text
|
||||
1. worker 不读取全量黑板(quick-write 等显式声明全量 inputTags 的 skill 除外)。
|
||||
2. worker 只能读取 inputTags 声明的标签。
|
||||
3. worker 只能输出 outputTags 声明的标签。
|
||||
4. LLM 不决定上下文分发。
|
||||
5. 总管 run_worker 时不带 inputTags / outputTags。
|
||||
6. 标签是 worker 之间的接口。
|
||||
7. 候选不等于事实;草稿不等于确认稿。
|
||||
8. 正文 worker 可重写角色候选产物。
|
||||
9. 长期记忆优先从正文.确认稿 更新。
|
||||
10. 简单 skill 用简单 tag;复杂 skill 再增加对象与阶段段。
|
||||
11. 角色卡与设定在 instantiate 阶段写入 tag;跨 Session 复用走 Book 加载,不单独 author skill 包。
|
||||
12. 代码与旧文档冲突时,以本文为准改代码。
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 15. 代码迁移顺序(参考)
|
||||
|
||||
```text
|
||||
1. src/types/blackboard.ts → BlackboardItem + listByTag / matchPrefix
|
||||
2. src/skills/types.ts + loader → 解析 inputTags / outputTags
|
||||
3. src/worker/executor.ts → 按 tag 组装 context,校验 outputTags
|
||||
4. src/types/runtime.ts + main-agent → 决策去掉 inputKeys / outputKeys
|
||||
5. skills/novel/weird-rules-short → 第一个 tag 化样板
|
||||
6. skills/novel/quick-write → 简易全量 LLM 档
|
||||
```
|
||||
|
||||
当前代码仍为旧 key 模型;实现前以本文为规格。
|
||||
|
||||
---
|
||||
|
||||
## 16. 相关文档
|
||||
|
||||
| 文档 | 内容 |
|
||||
|---|---|
|
||||
| `orchestrator-skill-format.md` | 总管 orchestrator.md 写法 |
|
||||
| `worker-skill-format.md` | Worker SKILL.md 写法 |
|
||||
| `tool-contracts.md` | 总管 / worker tool |
|
||||
| `skill-format.md` | Skill 包存储 |
|
||||
| `runtime-state-machine.md` | 5 相位阶段机 |
|
||||
| `implementation-guide.md` | 写代码顺序 |
|
||||
| `skills/README.md` | Skill 包索引与 TODO |
|
||||
125
docs/tool-contracts.md
Normal file
125
docs/tool-contracts.md
Normal file
@@ -0,0 +1,125 @@
|
||||
# Tool 合约
|
||||
|
||||
## 1. 定位
|
||||
|
||||
LLM 通过 **tool call** 表达意图;Runtime 校验后执行 tool 或转为 **RuntimeEvent** 改变 phase。
|
||||
|
||||
**真 tool loop**:循环 tool 的返回值 append 到 agent `messages[]`;边界 tool 结束 burst。
|
||||
不依赖「副作用列表」隐式推进(迁移方向,见 `architecture.md`)。
|
||||
|
||||
黑板与上下文:`tag-blackboard.md`、`context-assembly.md`。
|
||||
|
||||
---
|
||||
|
||||
## 2. 调用者
|
||||
|
||||
| 调用者 | 可用 tool | 禁止 |
|
||||
|--------|-----------|------|
|
||||
| 总管 Agent | 见 §3 | 改 phase 直接写黑板;传 inputTags;accept 产物 |
|
||||
| Worker LLM | `ask_user`、`submit`(目标态) | 调度其他 skill;写未声明 tag |
|
||||
| 用户 / CLI | submit_input、approve、reject、accept | — |
|
||||
| Runtime | 发射 event、拼接上下文、执行 worker | — |
|
||||
|
||||
---
|
||||
|
||||
## 3. 总管 Tool
|
||||
|
||||
### 3.1 循环 tool(burst 内,不改 phase)
|
||||
|
||||
| name | 作用 |
|
||||
|------|------|
|
||||
| `read_blackboard` | `tags: string[]` 读正文 |
|
||||
| `list_workers` | 当前包可调度 skill 列表 |
|
||||
| `list_artifacts` | 产物状态 |
|
||||
|
||||
### 3.2 边界 tool(结束 burst)
|
||||
|
||||
| name | 行为 |
|
||||
|------|------|
|
||||
| `run_worker` | 执行 skill;`requiresApproval` → `approve_step` |
|
||||
| `ask_user` | `waiting_user(input)` |
|
||||
| `review_blackboard` | 向用户展示概况 → `input` |
|
||||
| `finish` | `done` |
|
||||
|
||||
```ts
|
||||
type RunWorkerParams = {
|
||||
workerId: string;
|
||||
reason: string;
|
||||
requiresApproval: boolean;
|
||||
roleId?: string;
|
||||
};
|
||||
```
|
||||
|
||||
Runtime 从 Worker Skill 读 `inputTags` / `outputTags`,总管 **不得传入**。
|
||||
|
||||
### 3.3 Tool loop burst
|
||||
|
||||
```text
|
||||
计数器 toolLoopBurstCount 在每次用户硬事件时归零:
|
||||
user_submitted_input、user_confirmed_intake、user_approved_next_step、
|
||||
user_rejected_next_step、user_accepted_artifact、user_rejected_artifact、…
|
||||
|
||||
running 内每轮 LLM+tool 使 burst+1;超过 maxBurst(默认 12,可配置)→ 强制 waiting_user
|
||||
```
|
||||
|
||||
**maxBurst = 两次用户操作之间的上限**,非 Session 累计。
|
||||
|
||||
代码:`src/main-agent/tool-loop.ts`、`src/runtime/tool-registry.ts`。
|
||||
|
||||
---
|
||||
|
||||
## 4. Worker Tool(目标态)
|
||||
|
||||
| name | 行为 |
|
||||
|------|------|
|
||||
| `ask_user` | `worker_questions` + resumeContext |
|
||||
| `submit` | 校验 tag ⊆ outputTags → 写黑板 → `worker_completed` |
|
||||
|
||||
Phase A 仍用 JSON `outputs` + `askUser`,语义等价。
|
||||
|
||||
---
|
||||
|
||||
## 5. 用户硬事件
|
||||
|
||||
| waitingReason | 用户动作 |
|
||||
|---------------|----------|
|
||||
| `skill_selection` | 选包 |
|
||||
| `intake` / `input` | 输入 |
|
||||
| `approve_step` | approve / reject |
|
||||
| `review_artifact` | accept / reject |
|
||||
| `worker_questions` | 输入 |
|
||||
| `revision` | 输入修改说明 |
|
||||
|
||||
---
|
||||
|
||||
## 6. 校验
|
||||
|
||||
```text
|
||||
1. phase + waitingReason 允许该 actor
|
||||
2. tool 参数 schema
|
||||
3. workerId ∈ manifest 注册表
|
||||
4. submit tag ⊆ outputTags
|
||||
5. 总管不得带 inputTags
|
||||
6. burst ≤ maxBurst
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 7. 代码对应
|
||||
|
||||
| 章节 | 文件 |
|
||||
|------|------|
|
||||
| 总管 tool loop | `src/main-agent/tool-loop.ts` |
|
||||
| tool 定义 | `src/main-agent/tools.ts` |
|
||||
| 解析/校验 | `src/runtime/tool-registry.ts` |
|
||||
| worker | `src/worker/executor.ts` |
|
||||
| 阶段机 | `src/runtime/phase-machine.ts` |
|
||||
|
||||
---
|
||||
|
||||
## 8. 已废弃
|
||||
|
||||
- 总管 JSON 一次性决策(保留 fallback 解析)
|
||||
- `inputKeys` / `outputKeys`
|
||||
- orchestrator 思维链逐步调度
|
||||
- 以 `PhaseEffect.invoke_main_agent` 链为主的路径(迁向 burst 入口)
|
||||
279
docs/worker-skill-format.md
Normal file
279
docs/worker-skill-format.md
Normal file
@@ -0,0 +1,279 @@
|
||||
# Worker Skill 格式
|
||||
|
||||
## 1. 定位
|
||||
|
||||
**Worker Skill** 服务 **Worker Agent**:规定 **读哪些 tag、写哪些 tag、怎么做** 本阶段产出。
|
||||
|
||||
Worker **从属于某一个总管 Skill 包**,不与其它 skill 共享。
|
||||
|
||||
```text
|
||||
总管:run_worker(write-rules)
|
||||
→ Runtime 读 workers/write-rules/SKILL.md 的 inputTags / outputTags
|
||||
→ 从黑板取匹配条目 → Worker 执行 → 写回 outputTags
|
||||
```
|
||||
|
||||
规格背景见 `docs/tag-blackboard.md`、`docs/context-assembly.md`。
|
||||
|
||||
---
|
||||
|
||||
## 2. 存储位置
|
||||
|
||||
```text
|
||||
skills/novel/weird-rules-short/
|
||||
├── orchestrator.md
|
||||
└── workers/
|
||||
├── write-rules/SKILL.md
|
||||
└── review-infer/SKILL.md
|
||||
```
|
||||
|
||||
- 目录名 = 包内 **worker id**。
|
||||
- 文件统一 **`SKILL.md`**。
|
||||
- **没有** 全局共享 worker 目录。
|
||||
|
||||
---
|
||||
|
||||
## 3. Frontmatter
|
||||
|
||||
```yaml
|
||||
---
|
||||
id: write-rules
|
||||
skill: weird-rules-short
|
||||
name: 规则与解析创作
|
||||
description: >-
|
||||
从 需求.核心要点 推演内部核心,产出规则与说明。
|
||||
version: 1
|
||||
inputTags:
|
||||
- "需求.核心要点"
|
||||
- "验收.读者视角.记录"
|
||||
- "验收.作者视角.记录"
|
||||
- "用户.修改说明"
|
||||
outputTags:
|
||||
- "核心.危险.隐藏"
|
||||
- "规则.草稿"
|
||||
- "规则.说明.草稿"
|
||||
inputMerge: latest
|
||||
---
|
||||
```
|
||||
|
||||
| 字段 | 用途 |
|
||||
|------|------|
|
||||
| `id` | 包内 skill id,与 manifest 注册表一致 |
|
||||
| `skill` | 所属 orchestrator 包 name |
|
||||
| `inputTags` | Runtime 从黑板取数的 tag(精确或 `前缀.*`) |
|
||||
| `outputTags` | 允许写回的 tag;Runtime 校验 |
|
||||
| `inputMerge` | 可选,`latest`(默认)或 `concat` |
|
||||
| `contextSegments` | 可选,上下文拼接:上半 static、下半 dynamic(见 §3.1) |
|
||||
| `contextIsolation` | 可选:`none` \| `role_pov` \| `blind_review` |
|
||||
|
||||
### 3.1 contextSegments(上下文拼接)
|
||||
|
||||
见 `docs/context-assembly.md`。示例:
|
||||
|
||||
```yaml
|
||||
contextSegments:
|
||||
- id: brief
|
||||
tier: static
|
||||
tags: ["book.brief"]
|
||||
label: "## 创作需求"
|
||||
- id: history
|
||||
tier: dynamic
|
||||
tags: ["运行.事件流"]
|
||||
policy: tail_lines_80
|
||||
- id: turn
|
||||
tier: dynamic
|
||||
tags: ["可见信息", "用户.最新输入"]
|
||||
label: "## 本轮"
|
||||
```
|
||||
|
||||
未声明时 Runtime 回退为 JSON `inputs`(当前实现)。
|
||||
|
||||
**review-infer 示例**(不得读隐藏核心):
|
||||
|
||||
```yaml
|
||||
inputTags:
|
||||
- "需求.核心要点"
|
||||
- "规则.草稿"
|
||||
- "规则.说明.草稿"
|
||||
outputTags:
|
||||
- "验收.读者视角.记录"
|
||||
```
|
||||
|
||||
**review-author 示例**(可读隐藏核心):
|
||||
|
||||
```yaml
|
||||
inputTags:
|
||||
- "需求.核心要点"
|
||||
- "核心.危险.隐藏"
|
||||
- "规则.草稿"
|
||||
- "规则.说明.草稿"
|
||||
outputTags:
|
||||
- "验收.作者视角.记录"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 4. 正文章节
|
||||
|
||||
```markdown
|
||||
# 标题
|
||||
|
||||
## 角色与口吻
|
||||
## 能力范围 # 能做什么 / 不能做什么
|
||||
## 思维链与自检
|
||||
## 上下文用法 # 各 inputTag 如何使用(不重复 frontmatter 列表)
|
||||
## 输出格式 # 各 outputTag 的 content 格式
|
||||
## 示例 # 可选
|
||||
```
|
||||
|
||||
正文中用 **tag 名** 指代上下文,例如「读 `需求.核心要点`」而非旧 key `book.brief`。
|
||||
|
||||
### 评估类 Worker
|
||||
|
||||
总管 orchestrator 只写:`rules 确认后 → run review-infer`。
|
||||
|
||||
本 SKILL 写 **评估怎么做**、verdict 写入 `验收.*.记录` 的 JSON 形状等。
|
||||
|
||||
### 用户回合 worker(user-turn)
|
||||
|
||||
**用途:** 该环节 **完全由用户输入** 组成,LLM 不替用户选行动(21 点玩家、线下人类一方等)。
|
||||
|
||||
**与 role-decide 的区别:**
|
||||
|
||||
| | role-decide | user-turn |
|
||||
|--|-------------|-----------|
|
||||
| 决策 | LLM 产出 `.思考` + `.行动` | 用户经 ask_user 提供;worker **只**写 `.行动` |
|
||||
| LLM | 需要 | 仅需展示/校验/格式化(可无生成模型) |
|
||||
|
||||
**frontmatter 示例:**
|
||||
|
||||
```yaml
|
||||
id: user-turn
|
||||
skill: blackjack-roleplay
|
||||
name: 用户回合
|
||||
description: 展示局面,收集用户合法行动,写入角色.用户.行动
|
||||
inputTags:
|
||||
- "角色.用户.可见信息"
|
||||
- "场景.公开叙述"
|
||||
outputTags:
|
||||
- "角色.用户.行动"
|
||||
```
|
||||
|
||||
**SKILL 正文要点:**
|
||||
|
||||
```markdown
|
||||
## 角色
|
||||
你是 **用户操作的采集器**,不是玩家 AI。禁止替用户选择行动。
|
||||
|
||||
## 执行
|
||||
1. 读可见信息与合法行动集
|
||||
2. ask_user:简短展示局面 + 列出可选行动
|
||||
3. 校验用户输入是否在合法集内;不合法则再问
|
||||
4. 写 `角色.用户.行动`(行动选择 + 可选说话)
|
||||
|
||||
## 禁止
|
||||
- 调用 LLM 模拟用户策略
|
||||
- 写入 `.思考`(用户无内心 tag,或仅 UI 留空)
|
||||
```
|
||||
|
||||
编排:总管在轮到用户时 `run_worker(user-turn)`;world-engine 与 role-decide **同一套** 读 `.行动` 规则。
|
||||
|
||||
---
|
||||
|
||||
## 5. 运行时输出协议
|
||||
|
||||
Worker LLM 返回 JSON(Phase A);Phase B 改为 tool call。语义不变:
|
||||
|
||||
```json
|
||||
{
|
||||
"outputs": {
|
||||
"规则.草稿": "...",
|
||||
"规则.说明.草稿": "..."
|
||||
},
|
||||
"summary": "50字以内摘要",
|
||||
"askUser": null
|
||||
}
|
||||
```
|
||||
|
||||
- `outputs` 的 key 必须是 **outputTags 中的 tag**(或与 tag 一一映射的别名,由 Runtime 归一化)。
|
||||
- 缺信息时 `askUser` 提问,不臆造。
|
||||
|
||||
Runtime 写黑板:
|
||||
|
||||
```ts
|
||||
{
|
||||
id: "...",
|
||||
tag: "规则.草稿",
|
||||
content: "...",
|
||||
source: "write-rules",
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 6. ask_user
|
||||
|
||||
任何 worker 可中途提问。Runtime 暂停并保存 `resumeContext`(workerId 等);恢复时 **重新** 从 SKILL 读 inputTags,不依赖总管。
|
||||
|
||||
---
|
||||
|
||||
## 7. 命名原则
|
||||
|
||||
Worker id 按 **本包流程职责** 命名,包内唯一:
|
||||
|
||||
| 包 | worker id | 职责 |
|
||||
|----|-----------|------|
|
||||
| weird-rules-short | write-rules | 写规则 |
|
||||
| weird-rules-short | review-infer | 读者视角验收 |
|
||||
| novel-standard | outline | 大纲 |
|
||||
|
||||
不要设计全局共享 worker id。
|
||||
|
||||
---
|
||||
|
||||
## 8. 与代码的关系
|
||||
|
||||
| 文档 | 代码 |
|
||||
|------|------|
|
||||
| frontmatter inputTags / outputTags | `src/skills/loader.ts` → `ParsedWorkerSkill` |
|
||||
| 运行时取数 | `src/worker/executor.ts` |
|
||||
| 角色 worker 独立 LLM | `llmProfileId` / `llm-bindings.yaml` | `src/skills/worker-llm.ts` |
|
||||
|
||||
当前代码仍为旧 `inputKeys` / `outputKeys` 模型;迁移以 `tag-blackboard.md` 为准。
|
||||
|
||||
---
|
||||
|
||||
## 9. Worker 独立 LLM(可选,预留多 AI 博弈)
|
||||
|
||||
默认:worker 与会话 **同一 ApiProfile**(设置页当前选中的 profile)。
|
||||
|
||||
### 9.1 Worker SKILL frontmatter
|
||||
|
||||
```yaml
|
||||
llmProfileId: "<profiles.json 中的 ApiProfile.id>"
|
||||
```
|
||||
|
||||
省略 = 走 skill 包 `llm-bindings.yaml` 或会话默认。
|
||||
|
||||
### 9.2 Skill 包 llm-bindings.yaml
|
||||
|
||||
```yaml
|
||||
defaultProfileId: null # null = 会话默认
|
||||
|
||||
workers:
|
||||
world-engine: {}
|
||||
role-decide:
|
||||
byRole:
|
||||
A: "<profile-id-1>"
|
||||
B: "<profile-id-2>"
|
||||
```
|
||||
|
||||
Runtime 解析顺序见 `src/skills/worker-llm.ts`。
|
||||
`role-decide` 按 `slots.世界.当前角色.id` 匹配 `byRole`。
|
||||
|
||||
### 9.3 设计意图
|
||||
|
||||
- 配置仍在 **profiles.json**(或 .env),不在 SKILL 里写密钥
|
||||
- 同一 skill 可让不同角色用不同模型/API,实现真实多 agent 博弈
|
||||
- 总管 LLM 不受 worker 绑定影响(始终会话默认)
|
||||
|
||||
---
|
||||
Reference in New Issue
Block a user