Files
nana-story/README.md
T
2026-07-29 10:14:21 +08:00

109 lines
5.5 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 听娜娜讲故事
`nana-story` 是一个本地优先、纯 BYOK 的 AI 对话游戏。V1 聚焦一段可回溯、可分支、状态可重放的单角色纵切。
## 当前阶段
M0 契约基线已建立;M1 状态、投影与持久化主链已经接通;M2 已具备可取消的真实模型
回合,以及面向长分支的上下文检查点与滚动压缩主链。Windows 原生构建基线已经建立,
真实在线 LAPP 与视觉验收仍待关闭。
目前包括:
- Tauri 2 + Vue 3 + TypeScript 工程;
- Rust workspace 与模块所有权边界;
- Rust 领域类型作为契约唯一事实来源;
- 生成的 JSON Schema 与 TypeScript DTO
- canonical `PlayerView` fixture
- 最小娜娜内容包;
- 原子化状态 reducer,覆盖关系、许诺、知识、持有物、时钟与判定;
- 保持同一语义的内存与 SQLite StoryStore,支持事务追加、恢复和回溯分叉;
- SQLite schema v3,以及从 schema v1 / v2 的无损迁移、旧库完整性校验、WAL、
busy timeout 与未来版本拒绝;
- 写入与恢复时的状态哈希校验;
- `RuntimeState → PlayerView` 脱敏投影与隐藏信息 canary 测试;
- `TurnPlan → reducer → SQLite → PlayerView` 单轮提交链;
- 随故事节点持久化并恢复 scene、expression、pose、beats 与 suggestions
- 确定性的场景上下文编译器,按固定顺序筛选角色卡、Persona、世界书、剧情事件与可见记忆;
- 缓存友好的 prompt schema v3:稳定资源前缀、当前分支检查点 / 原文尾部和动态本轮
内容各自分区;模型上下文窗口、输出上限、工具续调用与安全余量统一进入预算;
- 长分支超过预算时,由当前选中的同一个 LAPP 模型通过严格的摘要工具滚动压缩;摘要
只接受当前分支的玩家安全叙事投影,始终是可删除、可重建的非权威缓存;
- 检查点通过稳定前缀与叙事来源 SHA-256 校验,只能沿当前祖先链继承;损坏、过期或
来自兄弟分支的缓存不会参与提示词;
- 新检查点先作为待提交结果保留,最终与普通节点或重生成节点在同一存储事务中提交;
取消、超时、陈旧线路或无效输出不会留下半轮节点或孤立检查点;
- 可继续的模型回复会在提交前按同一模型预算验证其“下一轮最新原文”占用;即使输出
符合静态 Schema,只要会让后续回合永久无法编排,就不会写入线路;
- 内存与 SQLite 后端均覆盖 500 节点祖先链读取和检查点查找,不再沿用界面层的
200 节点深度限制;
- 引擎掌控的类型化隐藏检定循环,模型只收到定性结果,不能指定或读取骰点、难度与精确数值;
- 基于 `lapp-rs` 原生工具消息的 LAPP TurnPlan provider 与严格输出校验;
- 从任意当前线路历史节点创建真实持久化分支,旧线路与新线路保持隔离;
- 列出、重命名、切换故事线路,并在关闭应用后恢复最后活动线路;
- 应用内选择 LAPP profile 中声明了聊天与工具调用能力的模型,凭据仍只由 LAPP
Vault 即时解析;
- 应用内测试当前已应用模型的最小连接,不接收任意模型目标,也不返回供应商正文;
- 回合支持停止生成与 90 秒应用截止时间;取消、超时或无效输出都不能产生半轮节点;
- 缺凭据、配置错误、限流、供应商拒绝与网络不可用使用脱敏错误分类,并只允许一次
明确的安全重试;
- 可完整游玩的“天亮之前”纵切:接受许诺、隐藏搜索、获得车票、进入隧道、天亮前
归来并结算许诺;
- Turn 请求/结果校验、Fake Provider 与确定性世界书触发;
- 可交互的主演出屏、持有物/线索/许诺、关系与回溯面板。
浏览器模式继续使用确定性的本地 Turn adapter,方便无桌面壳开发;Tauri
模式已经通过 `submit_turn` 使用 SQLite 自动保存和恢复,并通过 `fork_branch`
创建持久化分支。线路选择和名称也保存在同一 SQLite 存档中。桌面端默认使用真实
LAPP provider;只有显式设置
`NANA_STORY_PROVIDER=demo` 时才启用确定性的娜娜纵切实现。
应用内“设置”只选择 LAPP profile 已有模型,不读取、保存或回显 API Key。若 profile
缺失,或没有声明 `chat``tool-call` 能力的启用模型,界面会明确显示不可用。
Rust 1.96 下的 workspace 共 215 项测试通过:Contracts 1、Domain 5、Engine 21、
Runtime 106、Store 65、Tauri 17;全 workspace Clippy、25 份契约 Schema 检查、
TypeScript 检查、29 项 Web 测试与生产构建均已通过。Windows 原生构建基线与复现
步骤见 [`docs/windows-developer-smoke.md`](docs/windows-developer-smoke.md),本轮
不据此宣称真实在线 LAPP 或窗口视觉验收已经完成。
## 开发
要求:
- Node.js 24+
- pnpm 10.29.2
- Rust 1.96
- 与本仓库同级的 `lapp-rs`,固定到 `lapp-rs.lock` 中的提交
```text
workspace/
├─ lapp-rs/
└─ nana-story/
```
```bash
pnpm install
pnpm verify
pnpm tauri dev
```
不配置 LAPP、仅运行确定性纵切时:
```bash
NANA_STORY_PROVIDER=demo pnpm tauri dev
```
只验证前端和已提交契约时可运行:
```bash
pnpm verify:web
```
## 边界
- 模型供应商协议与凭据处理属于 `lapp-rs`
- 前端只接收 `PlayerView`,不会得到完整 `RuntimeState`
- V1 不使用向量记忆库、导演 Agent 或多个完整角色。
- 模型与前端都不能直接修改运行时状态。