2026-05-08 10:12:31 +08:00
|
|
|
|
# 云枢·Agent 版本变更日志
|
|
|
|
|
|
|
|
|
|
|
|
> 坐看云卷云舒,静听花开花落
|
|
|
|
|
|
|
2026-05-16 17:21:29 +08:00
|
|
|
|
## [2.3.0] - 2026-05-16
|
|
|
|
|
|
|
|
|
|
|
|
### 日志系统 + 性能优化 + 安全加固
|
|
|
|
|
|
|
|
|
|
|
|
#### 日志系统
|
|
|
|
|
|
|
|
|
|
|
|
引入 `charmbracelet/log` v2 作为结构化日志库,取代零散的 `log.Printf` / `fmt.Fprintln(os.Stderr, ...)`:
|
|
|
|
|
|
|
|
|
|
|
|
| 组件 | 说明 |
|
|
|
|
|
|
|------|------|
|
|
|
|
|
|
| `logger.go` | charmbracelet/log 全局实例,输出到 stderr |
|
|
|
|
|
|
| `log.go` | log.yml 持久化(YAML 序列追加)、双写 wrapper、`yunshu log` 命令 |
|
|
|
|
|
|
|
|
|
|
|
|
日志流向:
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
warnLog/errorLog/infoLog
|
|
|
|
|
|
├─ logToStderr ? → charmbracelet/log → stderr(交互模式默认关闭,/log on 开启)
|
|
|
|
|
|
└─ 始终写入 → appendLog → log.yml(YAML 序列,位于 ~/.config/yunshu/log.yml)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
新增日志点:
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
[INFO] task(weather) 开始
|
|
|
|
|
|
[INFO] 子 Agent 开始 agent=weather
|
|
|
|
|
|
[INFO] LLM 调用完成 tokens=1420 duration=3.2s
|
|
|
|
|
|
[INFO] task(weather) 完成
|
|
|
|
|
|
[WARN] 解析缓存失败 agent=weather err=...
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
`yunshu log` 子命令:
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
yunshu log → 全量显示(时间倒序)
|
|
|
|
|
|
yunshu log --top N → 只看最后 N 条
|
|
|
|
|
|
yunshu log --level warn → 过滤级别
|
|
|
|
|
|
yunshu log --clear → 清空
|
|
|
|
|
|
yunshu log --watch → 监听模式(2s 轮询)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
#### 流式输出
|
|
|
|
|
|
|
|
|
|
|
|
LLM 响应改为 SSE 流式输出,按 `\n\n` 段落边界缓冲后经 mdprint 渲染到 stdout:
|
|
|
|
|
|
|
|
|
|
|
|
| 组件 | 文件 | 说明 |
|
|
|
|
|
|
|------|------|------|
|
|
|
|
|
|
| SSE 类型 | `llm.go` | `sseChunk`/`sseDelta`/`sseToolCallDelta` 等 |
|
|
|
|
|
|
| `CallLLMStream` | `llm.go` | 请求加 `stream: true`,`bufio.Reader` 逐行解析 |
|
|
|
|
|
|
| 段落缓冲 | `llm.go` | `blockBuf` + `tryFlushBlocks`:检测最后一个 `\n\n`,完成块过 mdprint,残段续传 |
|
|
|
|
|
|
| 流结束刷残段 | `llm.go` | 末尾 `mdprint.Print(blockBuf)` 兜底 |
|
|
|
|
|
|
| 重建响应 | `llm.go` | tool_call 按 index 累积 + SSE 碎片合并 |
|
|
|
|
|
|
|
|
|
|
|
|
关键设计:
|
|
|
|
|
|
|
|
|
|
|
|
```
|
|
|
|
|
|
LLM SSE → blockBuf += content
|
|
|
|
|
|
tryFlushBlocks:
|
|
|
|
|
|
├─ 有 \n\n → 之前的部分 mdprint.Print(complete)
|
|
|
|
|
|
│ → 剩余部分留在 blockBuf
|
|
|
|
|
|
└─ 无 \n\n → stay
|
|
|
|
|
|
流结束 → mdprint.Print(blockBuf)
|
|
|
|
|
|
```
|
|
|
|
|
|
|
|
|
|
|
|
Prompt 适配(`agents/dialog-agent.md`):
|
|
|
|
|
|
- 新增"流式输出原则":先调工具,不要先说话
|
|
|
|
|
|
- 调度表 `回应 → task(profile)` 改为 `静默调 task,拿到结果后再回应`
|
|
|
|
|
|
|
|
|
|
|
|
#### 性能优化
|
|
|
|
|
|
|
|
|
|
|
|
| 优化 | 改动 | 效果 |
|
|
|
|
|
|
|------|------|------|
|
|
|
|
|
|
| note-sub 一步完成 | prompt 收紧:read→write→立即返回 | note 保存从 ~50s 降至 ~10s |
|
|
|
|
|
|
| dialog 合并 obs+summary | 单 Agent 查询跳过观察和摘要;综合查询合并为一轮 | 节省 ~30s |
|
|
|
|
|
|
| maxToolCalls=2 | RunSubAgent 超限兜底 | 防止死循环 |
|
|
|
|
|
|
|
|
|
|
|
|
#### 代码加固
|
|
|
|
|
|
|
|
|
|
|
|
| 改动 | 文件 | 说明 |
|
|
|
|
|
|
|------|------|------|
|
|
|
|
|
|
| LLM 延迟加载 | `llm.go` | `init()` → `sync.Once`,`--help` 不再读 config |
|
|
|
|
|
|
| 路径安全检查 | `tool.go` | `safeMemoryPath()`:Clean + EvalSymlinks + Rel 三段校验 |
|
|
|
|
|
|
| 静默错误 → warnLog | 8 处 across runtime/tool/registry | 所有 `json.Unmarshal` / `yaml.Unmarshal` 吞掉的错误改为结构化日志 |
|
|
|
|
|
|
| 对话记忆修剪 | `runtime.go` | `LoadSession` 只返回最近 40 条消息 |
|
|
|
|
|
|
| Onboard 补齐 | `onboard.go` | `ensureUserConfig()` 创建 user.md/soul.md/notes/ |
|
|
|
|
|
|
| 热加载 | `main.go` | 交互模式每轮 `ScanAgents()`,新增 agent 即时生效 |
|
|
|
|
|
|
|
|
|
|
|
|
#### UX 改进
|
|
|
|
|
|
|
|
|
|
|
|
- 交互模式默认不显示日志(`/log on` 开启)
|
|
|
|
|
|
- `--help` 移除环境变量章节,增加 `log` 命令说明
|
|
|
|
|
|
- 单次查询模式保留日志显示
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## [2.2.0] - 2026-05-16
|
|
|
|
|
|
|
|
|
|
|
|
### 存储重组:session 目录 + .yml 统一后缀
|
|
|
|
|
|
|
|
|
|
|
|
#### 目录结构调整
|
|
|
|
|
|
|
|
|
|
|
|
| 旧路径 | 新路径 | 原因 |
|
|
|
|
|
|
|--------|--------|------|
|
|
|
|
|
|
| `session.json` | `session/session.json` | 对话会话文件归入 session 目录 |
|
|
|
|
|
|
| `context/dialog.yaml` | `session/dialog.yml` | context 语义模糊,与 session 合并;.yml 后缀 |
|
|
|
|
|
|
| `config.yaml` | `config.yml` | 统一后缀 |
|
|
|
|
|
|
| `log.yaml` | `log.yml` | 统一后缀 |
|
|
|
|
|
|
| `context/` | 已删除 | 文件移至 session/ |
|
|
|
|
|
|
|
|
|
|
|
|
所有 yaml 文件统一使用 `.yml` 后缀。配置文件、对话摘要、日志文件全部一致性调整。
|
|
|
|
|
|
|
|
|
|
|
|
#### 代码改动
|
|
|
|
|
|
|
|
|
|
|
|
| 文件 | 改动 |
|
|
|
|
|
|
|------|------|
|
|
|
|
|
|
| `runtime.go` | `sessionPath()` 改为 `session/session.json` |
|
|
|
|
|
|
| `config.go` | `LoadConfig`/`SaveConfig` 读写 `config.yml` |
|
|
|
|
|
|
| `onboard.go` | 提示信息改为 `config.yml` |
|
|
|
|
|
|
| `main.go` | 新增 `migrateFilePaths()` 处理所有旧路径迁移 |
|
|
|
|
|
|
| `tool.go` | 描述字符串更新 `context/`→`session/`,`.yaml`→`.yml` |
|
|
|
|
|
|
| `agents/dialog-agent.md` | 所有 `context/dialog.yaml`→`session/dialog.yml` |
|
|
|
|
|
|
| `docs/` | 存储树、写入策略、编码规范全部同步更新 |
|
|
|
|
|
|
|
|
|
|
|
|
#### 迁移逻辑
|
|
|
|
|
|
|
|
|
|
|
|
`migrateFilePaths()` 在启动时自动处理:
|
|
|
|
|
|
- `config.yaml` → 复制到 `config.yml`,删除旧文件
|
|
|
|
|
|
- `session.json` → 复制到 `session/session.json`,删除旧文件
|
|
|
|
|
|
- `context/dialog.yaml` → 复制到 `session/dialog.yml`,删除旧文件及空目录
|
|
|
|
|
|
- `log.yaml` → 复制到 `log.yml`,删除旧文件
|
|
|
|
|
|
|
|
|
|
|
|
所有迁移仅在目标文件不存在时执行,支持幂等。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
## [2.1.0] - 2026-05-16
|
|
|
|
|
|
|
|
|
|
|
|
### 用户画像 + 备忘录系统
|
|
|
|
|
|
|
|
|
|
|
|
#### 拆分 memory.json
|
|
|
|
|
|
|
|
|
|
|
|
旧的 `memory.json` 一锅烩,现在拆成**按用途分文件**:
|
|
|
|
|
|
|
|
|
|
|
|
| 旧文件 | 新文件 | 格式 | 维护者 |
|
|
|
|
|
|
|--------|--------|------|--------|
|
|
|
|
|
|
| `memory.json["personality"]` | `config/soul.md` | Markdown | 用户手动编辑 |
|
|
|
|
|
|
| `memory.json["dialog_context"]` | `context/dialog.yaml` | YAML | dialog 每轮写入 |
|
|
|
|
|
|
| `memory.json["agent_errors"]` | `log.yaml` | YAML | 系统追加 |
|
|
|
|
|
|
| (不存在) | `config/user.md` | Markdown | profile-sub 维护 |
|
|
|
|
|
|
| (不存在) | `notes.md` + `notes/*.md` | Markdown | note-sub 维护 |
|
|
|
|
|
|
|
|
|
|
|
|
迁移逻辑在 `main.go:migrateMemoryJSON()`,启动时自动检测并迁移,确认完成后再删除 `memory.json`。
|
|
|
|
|
|
|
|
|
|
|
|
#### 新增子 Agent
|
|
|
|
|
|
|
|
|
|
|
|
| Agent | 文件 | 用途 |
|
|
|
|
|
|
|-------|------|------|
|
|
|
|
|
|
| profile-sub | `agents/profile-sub.md` | 从对话中提取用户画像,增量合并到 `config/user.md` |
|
|
|
|
|
|
| note-sub | `agents/note-sub.md` | 笔记管理。默认 `notes.md` 列表,复杂内容可存为 `notes/{name}.md` |
|
|
|
|
|
|
|
|
|
|
|
|
#### memory.read/write 工具改造
|
|
|
|
|
|
|
|
|
|
|
|
从旧的 flat JSON key-value 改为路径路由:
|
|
|
|
|
|
|
|
|
|
|
|
- `.md` 文件 → 全文覆写(`memory.write("config/user.md", markdown_str)`)
|
|
|
|
|
|
- `.yaml` 文件 → 合并写入(`memory.write("context/dialog.yaml", {topic, last_agent})`)
|
|
|
|
|
|
- 目录 → 返回文件列表
|
|
|
|
|
|
- 安全检查:拦截 `..` 遍历和绝对路径
|
|
|
|
|
|
- 目录自动创建
|
|
|
|
|
|
|
|
|
|
|
|
#### dialog-agent.md 更新
|
|
|
|
|
|
|
|
|
|
|
|
- 新增调度规则:检测用户透露个人信息 → 调 `task("profile", ...)` 提取画像
|
|
|
|
|
|
- 新增调度规则:检测"帮我记住" → 调 `task("note", ...)` 存备忘录
|
|
|
|
|
|
- 对话摘要改为写入 `context/dialog.yaml`,而非旧 `memory.json["dialog_context"]`
|
|
|
|
|
|
- 用户画像改为读取 `config/user.md`
|
|
|
|
|
|
- 新增观察规则:每轮回复后向 `## AI观察到` 段写入语气/情绪/性格观察
|
|
|
|
|
|
|
|
|
|
|
|
#### heading-aware merge
|
|
|
|
|
|
|
|
|
|
|
|
`memory.write` 对 `.md` 文件由全文覆写改为按 `##` 标题合并:
|
|
|
|
|
|
|
|
|
|
|
|
- `memory.write("config/user.md", "## 画像\n...")` 只替换 `## 画像` 段,`## AI观察到` 段不受影响
|
|
|
|
|
|
- 同一 writer 可多次写入同一标题,每次覆盖该段内容
|
|
|
|
|
|
- 不同 writer 写不同标题,互不干扰
|
|
|
|
|
|
- 底层函数 `mdMerge()` 按 `##` 拆分 → 标题匹配 → 重组
|
|
|
|
|
|
|
|
|
|
|
|
#### profile-sub.md 更新
|
|
|
|
|
|
|
|
|
|
|
|
- 改为写 `## 画像` 段(不再写整篇 user.md)
|
|
|
|
|
|
- 文档规范化:给出 `## 画像` 格式示例
|
|
|
|
|
|
- 强调不破坏其他段(`## AI观察到` 等)
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### 发布会:会议室架构核心引擎就绪
|
|
|
|
|
|
|
|
|
|
|
|
**架构规划:会议室模式**(阶段一全部完成,超计划交付)
|
|
|
|
|
|
|
|
|
|
|
|
#### 核心引擎
|
|
|
|
|
|
|
|
|
|
|
|
| 组件 | 文件 | 说明 |
|
|
|
|
|
|
|------|------|------|
|
|
|
|
|
|
| Agent 注册中心 | `registry.go` | `ScanAgents()` 按 `type`(main/sub) 分类,用户目录覆盖 |
|
|
|
|
|
|
| 子 Agent 隔离运行 | `runtime.go`: `RunSubAgent` | 隔离 LLM 循环,返回 `---RESULT---`/`---TEXT---` |
|
|
|
|
|
|
| 主 Agent 循环 | `runtime.go`: `RunAgent` | session 持久化 + mdprint 渲染 |
|
|
|
|
|
|
| 缓存系统 | `runtime.go`: cache 辅助 | SHA256[:6] 拼 key,惰性过期 |
|
|
|
|
|
|
| 工具目录生成 | `catalog.go` | `GenerateToolsYAML`、`BuildSubAgentPrompt` |
|
|
|
|
|
|
|
|
|
|
|
|
#### 新增工具
|
|
|
|
|
|
|
|
|
|
|
|
| 工具 | 注册方式 | 说明 |
|
|
|
|
|
|
|------|---------|------|
|
|
|
|
|
|
| `task` | `NewTool[TaskInput]` | 调度子 Agent + 缓存管理 |
|
|
|
|
|
|
| `memory.read` | `NewTool[MemoryReadInput]` | 读 `~/.config/yunshu/memory.json` |
|
|
|
|
|
|
| `memory.write` | `NewTool[MemoryWriteInput]` | 写长期记忆,value 支持任意 JSON 类型 |
|
|
|
|
|
|
|
|
|
|
|
|
#### 实际子 Agent
|
|
|
|
|
|
|
|
|
|
|
|
| Agent | 文件 | 状态 |
|
|
|
|
|
|
|-------|------|------|
|
|
|
|
|
|
| dialog-agent.md | `agents/dialog-agent.md` | 主持者(type:main)含多步骤编排指令 |
|
|
|
|
|
|
| weather-sub.md | `agents/weather-sub.md` | 天气子 Agent(type:sub),Markdown 排版 + 生活建议 |
|
|
|
|
|
|
|
|
|
|
|
|
### ✨ 计划外新增
|
|
|
|
|
|
|
|
|
|
|
|
#### 泛型 + 反射工具注册(`toolschema.go`)
|
|
|
|
|
|
|
|
|
|
|
|
受 Charmbracelet/Fantasy 启发,引入 `NewTool[T any]()` 泛型构造函数:
|
|
|
|
|
|
|
|
|
|
|
|
- 输入结构体 `json`/`description`/`enum` tags → 自动反射生成 JSON Schema
|
|
|
|
|
|
- 消除 ~120 行手写 Schema 模板代码(旧的 `ToolParameter`/`ToolProperty` 类型已删除)
|
|
|
|
|
|
- handler 内参数为类型安全的结构体字段,无需 `args["x"].(string)` 类型断言
|
|
|
|
|
|
- 支持嵌套结构体、slice、map、基础类型、interface{} 类型
|
|
|
|
|
|
|
|
|
|
|
|
#### 多步骤编排(runtime 改造)
|
|
|
|
|
|
|
|
|
|
|
|
移除 `capturedOutput` 覆写机制,子 Agent 结果作为普通工具响应留在对话上下文中:
|
|
|
|
|
|
|
|
|
|
|
|
- 主 Agent 可以连续多次调 `task()`(weather → train → hotel)
|
|
|
|
|
|
- 每次返回后 LLM 继续推理,决定下一步
|
|
|
|
|
|
- 信息收集完毕再综合回答,不再被 `capturedOutput` 截断
|
|
|
|
|
|
- 单步骤查询(如纯天气)行为不变,LLM 按 prompt 指令直接输出子 Agent 结果
|
|
|
|
|
|
|
|
|
|
|
|
#### 其他变更
|
|
|
|
|
|
|
|
|
|
|
|
- `http-get.headers` 从 JSON 字符串改为 `map[string]string`,LLM 直接传对象
|
|
|
|
|
|
- `memory.write.value` 从 `string` 改为 `interface{}`,直接存储任意 JSON 值
|
|
|
|
|
|
- `types.go`:删除旧的 `ToolParameter`/`ToolProperty` 结构体,新增 `Schema(map[string]any)` 类型
|
|
|
|
|
|
- `catalog.go`:`buildToolList` 适配新版 Schema
|
|
|
|
|
|
- `agents/dialog-agent.md`:加入多步骤编排指令 + 数据传递说明
|
|
|
|
|
|
|
|
|
|
|
|
### 文档更新
|
|
|
|
|
|
|
|
|
|
|
|
- `docs/architecture.md`:更新工具列表、核心流程、当前状态
|
|
|
|
|
|
- `docs/AGENTS.md`:工具注册规范更新为 `NewTool[T]` 方式
|
|
|
|
|
|
- `docs/会议室架构计划书.md`:添加实现状态标记、多步骤编排章节、泛型注册章节
|
|
|
|
|
|
|
|
|
|
|
|
---
|
2026-05-11 08:32:30 +08:00
|
|
|
|
|
|
|
|
|
|
### 架构规划:会议室模式
|
|
|
|
|
|
|
|
|
|
|
|
完成从单 Agent 到"会议室架构"的完整设计,核心变更:
|
|
|
|
|
|
|
|
|
|
|
|
**新增角色体系**:
|
|
|
|
|
|
- `type: main` — 主持者(对话 Agent),唯一用户入口
|
|
|
|
|
|
- `type: sub` — 发言人(领域子 Agent),被 `task` 调才说话
|
|
|
|
|
|
|
|
|
|
|
|
**新增工具**(待实现):
|
|
|
|
|
|
- `task` — 调度子 Agent + 缓存管理
|
|
|
|
|
|
- `memory.read` / `memory.write` — 长期记忆读写
|
|
|
|
|
|
|
|
|
|
|
|
**新增 Cache 机制**:
|
|
|
|
|
|
- 子 Agent Frontmatter 声明 `cache.ttl` + `cache.keys`
|
|
|
|
|
|
- `task` 工具机械化拼 key、查/写缓存
|
|
|
|
|
|
- 一个 Agent 一个缓存 JSON 文件,子 Agent 无感知
|
|
|
|
|
|
|
|
|
|
|
|
**设计文档**:
|
|
|
|
|
|
- `docs/会议室架构计划书.md` — 完整架构方案
|
|
|
|
|
|
- `docs/architecture.md` — 更新后续演进章节
|
|
|
|
|
|
- `docs/AGENTS.md` — 更新 Agent 定义规范(type, cache 字段)
|
|
|
|
|
|
- `docs/taolun.md` — 追加 2026-05-11 讨论历史
|
|
|
|
|
|
|
|
|
|
|
|
**MSN 天气接口更新**:
|
|
|
|
|
|
- 新增 `hourlyforecast` 端点文档
|
|
|
|
|
|
- 标记 `weathertrends` 为已失效
|
|
|
|
|
|
- 更新 `skills/msn-weather-api/SKILL.md` 和 `agents/weather-agent.md`
|
|
|
|
|
|
|
|
|
|
|
|
### 技术细节
|
|
|
|
|
|
- Frontmatter 新增 `type` 字段(main/sub)
|
|
|
|
|
|
- Frontmatter 新增 `cache` 字段(`{ttl: int, keys: [string]}`)
|
|
|
|
|
|
- 用户配置目录 `~/.config/yunshu/` 下可选覆盖 agents/
|
|
|
|
|
|
- 详见 `docs/会议室架构计划书.md`
|
|
|
|
|
|
|
2026-05-09 03:55:56 +08:00
|
|
|
|
## [1.1.0] - 2026-05-09
|
|
|
|
|
|
|
2026-05-09 03:58:21 +08:00
|
|
|
|
### 发布摘要
|
|
|
|
|
|
第二版发布。核心变化:Markdown 渲染器从"一行流"重构为 AST 架构,新增终端视觉系统(标题符号 + Monet 配色),Go 版本升级至 1.25,项目结构从 `src/` 扁平目录重组为根目录 + `pkg/` 子包架构。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### 新增:pkg/mdprint — Markdown → ANSI 渲染引擎
|
|
|
|
|
|
|
|
|
|
|
|
从头编写的 AST 架构渲染引擎,替代原来的"一行流"字符串匹配逻辑:
|
|
|
|
|
|
|
|
|
|
|
|
**块级解析**(`parse.go`):有限状态机逐行扫描,识别 7 种块级元素
|
|
|
|
|
|
| 类型 | 语法 | 解析策略 |
|
|
|
|
|
|
|------|------|---------|
|
|
|
|
|
|
| Heading | `#` ~ `######` | 前缀匹配,记录级别 |
|
|
|
|
|
|
| CodeBlock | ` ``` ` fence | 状态切换,支持语言标识 |
|
|
|
|
|
|
| Blockquote | `>` 前缀 | 前缀剥离,递归解析 |
|
|
|
|
|
|
| List | `-` / `*` / `1.` | 前缀匹配,自动编号检测 |
|
|
|
|
|
|
| Table | `|` 分隔 | 行首检测,首行为表头 |
|
|
|
|
|
|
| ThematicBreak | `---` 独占一行 | 精确匹配 |
|
|
|
|
|
|
| Paragraph | 默认兜底 | 连续非空文本块合并 |
|
|
|
|
|
|
|
|
|
|
|
|
**行内解析**(`inline.go`):递归下降扫描,支持 4 种行内元素嵌套
|
|
|
|
|
|
| 类型 | 语法 | 特性 |
|
|
|
|
|
|
|------|------|------|
|
|
|
|
|
|
| Bold | `**text**` | 可嵌套 Italic / Code / Link |
|
|
|
|
|
|
| Italic | `*text*` | 可嵌套 Bold / Code / Link |
|
|
|
|
|
|
| Code | `` `text` `` | 原始文本(内部不解析) |
|
|
|
|
|
|
| Link | `[text](url)` | text 可嵌套 Bold / Italic |
|
|
|
|
|
|
|
|
|
|
|
|
**ANSI 渲染**(`render.go`):type switch 按节点类型分发,标题按级别分配颜色和符号
|
|
|
|
|
|
|
|
|
|
|
|
**测试覆盖**:19 个单元测试,覆盖所有块级/行内类型的正常、边界和嵌套场景
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### 新增:标题视觉系统
|
|
|
|
|
|
|
|
|
|
|
|
用符号 `▪` / `▫` 替代 Markdown 原生 `#` 前缀,视觉效果更接近"标题"而非"标记":
|
|
|
|
|
|
|
|
|
|
|
|
| 级别 | 符号 | 字体 | 色彩(Monet 睡莲) | 色值 |
|
|
|
|
|
|
|------|------|------|-------------------|------|
|
|
|
|
|
|
| H1 | `▪` | 加粗 | 雾蓝灰 | `#6B8E9B` |
|
|
|
|
|
|
| H2 | `▪` | 加粗 | 鼠尾草绿 | `#89A894` |
|
|
|
|
|
|
| H3 | `▪` | 加粗 | 薄荷青 | `#A6C0B5` |
|
|
|
|
|
|
| H4 | `▫` | 加粗 | 淡紫粉 | `#C3B1BD` |
|
|
|
|
|
|
| H5 | `▫` | 加粗 | 暖灰绿 | `#7B8E8A` |
|
|
|
|
|
|
| H6 | 无 | 加粗(Dim) | 浅灰 | 继承 |
|
|
|
|
|
|
|
|
|
|
|
|
排版规则:所有标题前插空行,H1 前后各插空行,`---` 横线前后空行,响应与输入之间空行,输出末尾空行。
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### 新增:pkg/style — 终端颜色样式库
|
|
|
|
|
|
|
|
|
|
|
|
在原有 8 色 ANSI 基础上新增 24-bit 真彩色支持:
|
|
|
|
|
|
|
|
|
|
|
|
- `Fg(color)` / `Bg(color)`:保留原有 8 色 API
|
|
|
|
|
|
- `FgHex("#RRGGBB")` / `BgHex("#RRGGBB")`:新增真彩色,输出 `\033[38;2;R;G;Bm` 格式
|
|
|
|
|
|
- 所有 `.Render(text)` 使用统一占位板 `.codes []string`,颜色和样式可组合
|
|
|
|
|
|
- `NO_COLOR` / `TERM=dumb` 环境变量自动禁用颜色
|
|
|
|
|
|
|
|
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
|
|
### 新增:pkg/termui — 终端输入组件
|
|
|
|
|
|
|
|
|
|
|
|
提供三个交互式输入函数,统一使用 `bufio.NewReader(os.Stdin)` + `ensureLineMode()` 解决 Windows 控制台输入问题:
|
|
|
|
|
|
|
|
|
|
|
|
| 函数 | 用途 | 特性 |
|
|
|
|
|
|
|------|------|------|
|
|
|
|
|
|
| `ReadLine()` | 基础行输入 | 去除 `\r\n` |
|
|
|
|
|
|
| `TextInput()` | 文本输入 | 支持默认值、必填校验、自定义验证器 |
|
|
|
|
|
|
| `PasswordInput()` | 密码输入 | 输入后隐藏回显,用 `*` 遮盖 |
|
|
|
|
|
|
| `Confirm()` | 确认提示 | 支持 Y/n / y/N 默认值 |
|
|
|
|
|
|
|
|
|
|
|
|
---
|
2026-05-09 03:55:56 +08:00
|
|
|
|
|
|
|
|
|
|
### 修复
|
2026-05-09 03:58:21 +08:00
|
|
|
|
|
|
|
|
|
|
1. **行内解析器未闭合分隔符死循环**:扫描 `*` / `` ` `` 分隔符时未处理文件末尾无闭合标记的情况,改为找到匹配闭合或到达末尾时终止
|
|
|
|
|
|
2. **代码 fence 不识语言标识**:` ```go `、` ```json ` 等带语言的 fence 被当作文本行,改为行首 ` ``` ` 后允许非空白后缀
|
|
|
|
|
|
3. **Windows 控制台输入模式冲突**:`bufio.Scanner` 在 Windows 控制台因 `ENABLE_WINDOW_INPUT` 标志导致 `Scan()` 永久阻塞。改为每轮输入前调用 `GetConsoleMode` + `SetConsoleMode` 确保模式为 `ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_PROCESSED_INPUT`,并使用 `bufio.NewReader.ReadString('\n')` 替代 Scanner
|
|
|
|
|
|
4. **尝试自实现 Tab 补全未成功**(后放弃):raw mode + `ReadConsoleInputW` 方案遇到光标位置计算不一致问题,最终回退到简单 `ReadLine()`。后续如需补全功能引入第三方库
|
|
|
|
|
|
|
|
|
|
|
|
---
|
2026-05-09 03:55:56 +08:00
|
|
|
|
|
|
|
|
|
|
### 变更
|
2026-05-09 03:58:21 +08:00
|
|
|
|
|
|
|
|
|
|
- **项目结构重组**:`src/` 目录删除,全部 `.go` 文件移至根目录;新增 `pkg/` 子包,按职责分离为 `mdprint/`、`style/`、`termui/`
|
|
|
|
|
|
- **模块名修改**:`yunshu` → `hub.gaomia.site/titor/YunShu`
|
|
|
|
|
|
- **Go 版本升级**:`1.21` → `1.25.0`
|
|
|
|
|
|
- **`Completer` 类型和 `ReadLineWithCompletion` 函数移除**:`completer.go` 清空,相关测试删除
|
|
|
|
|
|
- **`.gitignore` 修复**:`yunshu.exe` → `yunshu.exe*`(避免调试版本遗漏)
|
|
|
|
|
|
|
|
|
|
|
|
---
|
2026-05-09 03:55:56 +08:00
|
|
|
|
|
|
|
|
|
|
### 技术栈
|
2026-05-09 03:58:21 +08:00
|
|
|
|
- **语言**:Go 1.25.0
|
|
|
|
|
|
- **依赖**:仅 `gopkg.in/yaml.v3`
|
|
|
|
|
|
- **默认 LLM**:豆包(火山引擎)`doubao-seed-2-0-pro-260215`
|
|
|
|
|
|
- **数据源**:MSN 天气非公开 API(`assets.msn.cn`)
|
|
|
|
|
|
- **运行平台**:Windows 10+(基于 kernel32 控制台 API,ANSI VT 处理)
|
|
|
|
|
|
- **输入编码**:UTF-8(通过 `SetConsoleOutputCP(65001)` 设置控制台代码页)
|
2026-05-09 03:55:56 +08:00
|
|
|
|
|
2026-05-08 10:59:07 +08:00
|
|
|
|
## [1.0.0] - 2026-05-08
|
|
|
|
|
|
|
|
|
|
|
|
### 发布说明
|
|
|
|
|
|
第一个稳定发布版本。云枢·Agent 作为可独立运行的 Agent 系统,支持通过 LLM + 工具注册表 + 外挂 Agent 定义实现自然语言驱动的天气查询。
|
|
|
|
|
|
|
|
|
|
|
|
### 功能
|
|
|
|
|
|
- 三层分离架构:Agent Skill(行为)↔ 普通 Skill(知识)↔ Tool(确定性执行)
|
|
|
|
|
|
- 外挂 Agent 定义:`.md` 文件即 Agent,YAML frontmatter + Markdown body
|
|
|
|
|
|
- 4 个内置工具:`http-get`、`skill`、`read-file`、`geocode`
|
|
|
|
|
|
- Session 会话管理:`~/.config/yunshu/session.json` 持久化对话历史
|
|
|
|
|
|
- 交互模式 + 单次查询双模式运行
|
|
|
|
|
|
- `onboard` 交互式初始化向导
|
|
|
|
|
|
- 双路径搜索:项目目录优先,`~/.config/yunshu/` 后备
|
|
|
|
|
|
- 旧配置自动迁移:`~/.config/weather-cli/` → `~/.config/yunshu/`
|
|
|
|
|
|
- LLM 配置:支持配置文件 + 环境变量双重配置,兼容 OpenAI Chat Completion API
|
|
|
|
|
|
|
|
|
|
|
|
### 技术栈
|
|
|
|
|
|
- 语言:Go 1.21
|
|
|
|
|
|
- 依赖:仅 `gopkg.in/yaml.v3`
|
|
|
|
|
|
- 默认 LLM:豆包(火山引擎)`doubao-seed-2-0-pro-260215`
|
|
|
|
|
|
- 数据源:MSN 天气非公开 API(`assets.msn.cn`)
|
|
|
|
|
|
|
|
|
|
|
|
## [1.0.0-rc.1] - 2026-05-07
|
2026-05-08 10:12:31 +08:00
|
|
|
|
|
|
|
|
|
|
### 重大变更
|
|
|
|
|
|
- **项目更名**:weather-cia → **云枢·Agent**(英文名 YunShu / yunshu)
|
|
|
|
|
|
- **配置目录迁移**:`~/.config/weather-cli/` → `~/.config/yunshu/`(自动迁移)
|
|
|
|
|
|
- 二进制名称改为 `yunshu`
|
|
|
|
|
|
|
|
|
|
|
|
## [0.3.0] - 2026-05-07
|
|
|
|
|
|
|
|
|
|
|
|
### 新增
|
|
|
|
|
|
- `geocode` 工具:通过 wttr.in 查询城市坐标,支持中文和英文城市名
|
|
|
|
|
|
- `skills/geocoding/SKILL.md`:地理编码验证规则(同名城市检测、国家核对)
|
|
|
|
|
|
- 架构分离:agent skill 只放行为,普通 skill 只放知识,tool 负责确定性执行
|
|
|
|
|
|
|
|
|
|
|
|
### 变更
|
|
|
|
|
|
- `agents/weather-agent.md` 精简为纯行为定义(去掉所有 MSN API 内联细节,改为按需加载 skill)
|
|
|
|
|
|
- 城市定位方式:从静态 cities.json 查表 → 调用 `geocode` 工具实时查询
|
|
|
|
|
|
- `agents/weather-agent.md` tools 新增 `geocode`
|
|
|
|
|
|
- session 文件从项目目录移至 `~/.config/weather-cli/session.json`
|
|
|
|
|
|
|
|
|
|
|
|
## [0.2.0] - 2026-05-07
|
|
|
|
|
|
|
|
|
|
|
|
### 新增
|
|
|
|
|
|
- `onboard` 子命令:交互式初始化向导,引导用户配置 LLM 连接信息
|
|
|
|
|
|
- 全局配置文件 `~/.config/weather-cli/config.yaml`,存储 LLM host/model/key
|
|
|
|
|
|
- 双路径搜索机制:项目目录优先,`~/.config/weather-cli/` 后备
|
|
|
|
|
|
- 首次运行检测:未配置时提示用户运行 `weather-cia onboard`
|
|
|
|
|
|
|
|
|
|
|
|
### 变更
|
|
|
|
|
|
- 项目重命名为 `weather-cia`
|
|
|
|
|
|
- 配置加载改为:配置文件 → 环境变量(环境变量优先级更高)
|
|
|
|
|
|
- Agent/skill 搜索路径扩展:项目目录 → 全局配置目录
|
|
|
|
|
|
- `onboard` 自动复制默认 agents/skills/data 到全局配置目录
|
|
|
|
|
|
|
|
|
|
|
|
## [0.1.0] - 2026-05-07
|
|
|
|
|
|
|
|
|
|
|
|
### 新增
|
|
|
|
|
|
- 项目初始化,基于 Go 实现的轻量级 agent 框架
|
|
|
|
|
|
- 核心架构:.md 文件定义 agent 行为,代码只负责加载和执行
|
|
|
|
|
|
- 工具系统:声明式注册(http-get, skill, read-file)
|
|
|
|
|
|
- Session 会话管理:session.json 记录对话历史,支持上下文追问
|
|
|
|
|
|
- 天气情报官 agent(weather-agent.md):通过 MSN 天气 API 查询实时天气和预报
|
|
|
|
|
|
- MSN 天气 API Skill(msn-weather-api/SKILL.md):API 知识按需加载
|
|
|
|
|
|
- 内置 42 个中国城市经纬度数据库(data/cities.json)
|
|
|
|
|
|
- 支持单次查询和交互模式两种运行方式
|
|
|
|
|
|
- 默认集成豆包(火山引擎)LLM,通过环境变量可切换
|
|
|
|
|
|
|
|
|
|
|
|
### 技术细节
|
|
|
|
|
|
- 语言:Go 1.21
|
|
|
|
|
|
- 依赖:仅 gopkg.in/yaml.v3(用于解析 frontmatter)
|
|
|
|
|
|
- API 兼容 OpenAI Chat Completion 格式
|
|
|
|
|
|
- 环境变量:`OPENAI_API_KEY`(必填)、`LLM_ENDPOINT`、`LLM_MODEL`
|