@migor/agentia 0.8.2 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +283 -2
- package/README.en.md +2 -2
- package/README.md +7 -5
- package/dist/AGENTS.md +132 -8
- package/dist/core/limits.d.ts +226 -0
- package/dist/core/limits.js +216 -0
- package/dist/core/limits.js.map +1 -0
- package/dist/core/trace.d.ts +66 -2
- package/dist/core/trace.js +37 -2
- package/dist/core/trace.js.map +1 -1
- package/dist/engine/forwarded.d.ts +84 -0
- package/dist/engine/forwarded.js +39 -0
- package/dist/engine/forwarded.js.map +1 -0
- package/dist/engine/run-config.d.ts +4 -1
- package/dist/engine/run-config.js +14 -1
- package/dist/engine/run-config.js.map +1 -1
- package/dist/engine/spec.d.ts +26 -1
- package/dist/engine/spec.js.map +1 -1
- package/dist/engine/tracer.d.ts +68 -1
- package/dist/engine/tracer.js +136 -14
- package/dist/engine/tracer.js.map +1 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/integrations/adapter-options.d.ts +0 -7
- package/dist/integrations/adapter-options.js +2 -1
- package/dist/integrations/adapter-options.js.map +1 -1
- package/dist/integrations/mcp-stdio.js +9 -1
- package/dist/integrations/mcp-stdio.js.map +1 -1
- package/dist/integrations/metrics-state.d.ts +2 -1
- package/dist/integrations/metrics-state.js +6 -2
- package/dist/integrations/metrics-state.js.map +1 -1
- package/dist/runtime/run.d.ts +13 -1
- package/dist/runtime/run.js +14 -3
- package/dist/runtime/run.js.map +1 -1
- package/dist/toolkit/module.d.ts +29 -1
- package/dist/toolkit/module.js +16 -0
- package/dist/toolkit/module.js.map +1 -1
- package/dist/toolkit/skill.js +4 -13
- package/dist/toolkit/skill.js.map +1 -1
- package/dist/toolkit/subagent.js +6 -17
- package/dist/toolkit/subagent.js.map +1 -1
- package/dist/transport/async.d.ts +119 -0
- package/dist/transport/async.js +125 -9
- package/dist/transport/async.js.map +1 -1
- package/dist/transport/http-route.d.ts +6 -1
- package/dist/transport/http-route.js +9 -1
- package/dist/transport/http-route.js.map +1 -1
- package/dist/transport/http.js +99 -1
- package/dist/transport/http.js.map +1 -1
- package/dist/transport/sse.d.ts +6 -2
- package/dist/transport/sse.js +3 -2
- package/dist/transport/sse.js.map +1 -1
- package/dist/transport/task-events.d.ts +90 -0
- package/dist/transport/task-events.js +159 -0
- package/dist/transport/task-events.js.map +1 -0
- package/package.json +5 -3
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,286 @@
|
|
|
5
5
|
(0.x 阶段:minor 可含破坏性变更,每个破坏性变更都在对应版本的「迁移」小节里写明)。
|
|
6
6
|
决策的完整证据链在 `docs/spec.md` §10(带时间线的决策日志)。
|
|
7
7
|
|
|
8
|
+
## [0.9.0] - 2026-09-22
|
|
9
|
+
|
|
10
|
+
> 本版主题(窗口 `0.8.3 → 0.9.0`):**dev 调试环落地** —— `agentia dev` 从「`tsx watch` 跑你的
|
|
11
|
+
> `main.ts`」变成「**常驻 runner 子进程 + 本地 inspector 面板**驱动你的 `src/app.ts`」,
|
|
12
|
+
> 四个控件(能力选择 / 工作目录 / 多轮 / prompt)都在面板上;顺带补上「**中止在飞 run**」与
|
|
13
|
+
> 「**清空对话**」两个操作,以及一轮复核修复(9 条,含 5 条严重:窄窗口竞态、收尾路径、
|
|
14
|
+
> 同一事实两个表面口径不一致)。
|
|
15
|
+
>
|
|
16
|
+
> ⚠️ **含破坏性变更,但只在脚手架模板形态上**(下面的迁移小节写了要做什么动作):
|
|
17
|
+
> 模板把「装配」与「启动」拆成两个文件(新增 `src/app.ts` 工厂),老工程不迁移的话
|
|
18
|
+
> `agentia dev` 会**明确报错**(不是静默降级成一个驱动不了任何东西的空壳)。
|
|
19
|
+
> **框架本体的公共 API 无破坏性变更**:没有删签名、没有改默认行为 —— 已有工程照常
|
|
20
|
+
> `npm start`;受影响的是「在工程里敲 `agentia dev`」这条开发期路径。
|
|
21
|
+
|
|
22
|
+
### 破坏性变更 · 脚手架模板:装配与启动拆开(新增 `src/app.ts`)
|
|
23
|
+
|
|
24
|
+
**要做的动作**:把老工程 `src/main.ts` 里的 `createApp({...})` 整段搬进新的 `src/app.ts`,
|
|
25
|
+
包成一个**工厂函数**;`main.ts` 只留「读 `.env` → 调工厂 → `app.run` → 处理 `result.error`」。
|
|
26
|
+
|
|
27
|
+
**为什么**:`agentia dev` 的调试环要把「这次调哪个能力 / 工作目录是哪个」喂进 `createApp`,
|
|
28
|
+
而**只有调用者能设这些选项**。拆出工厂之后 CLI 才是调用者 ⇒ **工程里一个 dev 文件都不需要**
|
|
29
|
+
(只多一个**数据**文件 `src/dev.config.ts`)。不迁移的后果是**明确报错**,不是静默降级:
|
|
30
|
+
`agentia dev` 会指出 `src/app.ts` 缺失并打印迁移说明。
|
|
31
|
+
|
|
32
|
+
**最小迁移**(对着 `agentia create` 新生成的工程看最省事):
|
|
33
|
+
|
|
34
|
+
1. 新建 `src/app.ts`:把 `main.ts` 里的 `CAPABILITY_DIRS` + `discover` + `createApp({...})` 搬进去,
|
|
35
|
+
改成 `export async function createAgentApp(opts: CreateAgentAppOptions = {})`。老的那段可以**原样**搬
|
|
36
|
+
—— 第 3 步不做也能跑,只是面板上的「工作目录」旋钮不生效。
|
|
37
|
+
2. `src/main.ts` 改薄入口:`import { createAgentApp } from './app.js'`(**注意 `.js` 后缀**)→
|
|
38
|
+
`const app = await createAgentApp();`,删掉 `createApp` 的 import 与 `CAPABILITY_DIRS`。
|
|
39
|
+
3. (要「工作目录」真生效就得做)在 `providers` 里加 `{ provide: 'WORKDIR', useValue: opts.workdir ?? <项目根> }`,
|
|
40
|
+
并把需要工作目录的能力从 `discover` 挪到显式 `providers` 声明 `deps: ['WORKDIR']`
|
|
41
|
+
—— **`discover` 自动注册的 provider 没有 `deps`**,拿不到注入值。
|
|
42
|
+
4. (可选)新建 `src/dev.config.ts` 声明多轮(`export default { multiTurn: ['trip-planner'] }`),
|
|
43
|
+
并给 `.gitignore` 补一行 `.agentia/`(dev 环的对话历史落盘处)。
|
|
44
|
+
|
|
45
|
+
### 新增
|
|
46
|
+
|
|
47
|
+
- **面板的「中止」按钮:中止在飞的 run(`POST /run/abort`)。** 此前只做了「在飞时拒绝第二次
|
|
48
|
+
`POST /run`(409)」这一半 —— 后果不是小事:**一个卡住的 run 会让面板永久锁死**,
|
|
49
|
+
此后每次运行都 409,而面板**没有任何办法**解开它。
|
|
50
|
+
实现走 IPC 让 runner 自己 `abort()`,**不是**父进程杀子进程 —— 理由是 **trace**:
|
|
51
|
+
`RunInvocationOptions.signal` 是契约字段(原样送进引擎),中止后在回合边界以
|
|
52
|
+
`stopReason='aborted'` **正常返回**(`engine/loop-result.ts` 的 `abortedResult()`)
|
|
53
|
+
⇒ **trace 照常落盘**。杀进程那条路会把这次 run 的 trace 整个丢掉。
|
|
54
|
+
⚠️ signal 是**协作式**的:工具不读它就没人理(「MCP 在途中止 ⇒ Promise 永不 settle」正是这一类),
|
|
55
|
+
`running` 会永远为 `true` ⇒ 所以补一条兜底:**5 s(`ABORT_GRACE_MS`)后仍没结束就重启进程**,
|
|
56
|
+
此时这次 run 的 trace 会丢,面板**明说**这一点(不静默)。
|
|
57
|
+
- **面板的「清空对话」按钮(`POST /session/clear`)。** 清空 = **换一个 `sessionId`**,
|
|
58
|
+
**不删** `session.json` —— 后者是 `SessionStore` 的账,面板对它**只读**(写它会造出
|
|
59
|
+
「面板显示的对话」与「模型真正看到的对话」不一致)。旧对话仍在盘上、run 列表里也还指得到,
|
|
60
|
+
只是模型不再带着它跑。当前 id 落盘到 `.agentia/dev-session-id`(**不是** `session.json` 的一部分):
|
|
61
|
+
只放内存的话,重启 `npm run dev` 之后刚清空的对话会**自己回来**;该路径已在监视排除清单里,
|
|
62
|
+
写它不触发重启。id 由**父进程**决定并经 IPC 下传 —— 它是面板级状态,必须跨 runner 重启稳定。
|
|
63
|
+
|
|
64
|
+
### 变更
|
|
65
|
+
|
|
66
|
+
- **`agentia dev` 从「看 trace」补上「驱动 run」**:面板上多四组输入 —— prompt 输入框(带 `↑`/`↓` 历史)、
|
|
67
|
+
能力多选(缺省全选;收窄的是**菜单**,主 agent 仍在环里 —— 别的能力 `tools` 里的显式引用仍能调到
|
|
68
|
+
被排除的那个)、工作目录选择器、多轮开关(按能力声明,混选取 **OR** 且面板**标出来源**)。
|
|
69
|
+
`npm run dev -- "你的问题"` 仍可直接带上第一句。
|
|
70
|
+
- **文件监视收编进 CLI**:`agentia dev` 不再叠一层 `tsx watch`(旧形态有**两个重启主人**,保存的瞬间
|
|
71
|
+
恰好点运行会双双 spawn),自己按**允许清单**看文件 —— **`.md` 必须在里面**:文本资产
|
|
72
|
+
(`@Prompt` 拉的 `.md`、子 agent 的 `system.md`)不在 tsx 的 import 图里,旧实现改它们
|
|
73
|
+
**静默无感**(改了没反应、也不提示)。排除 `node_modules` / `dist` / `.git` / `.agentia` / `coverage`
|
|
74
|
+
—— `.agentia` 那条不是洁癖:它是 dev 环自己的对话历史,看它就变成「每次 run 重启一次」的自噬循环。
|
|
75
|
+
- **重启与不重启的边界**:改代码或改**能力选择** ⇒ 重启子进程;改**工作目录** / prompt / 多轮 ⇒ 不重启。
|
|
76
|
+
在飞 run 期间的重启**延后**到它结束。⚠️ 重启能力选择的理由**不是贵**(进程内重建实测 **2.6 ms**,
|
|
77
|
+
初稿的「几秒」高估约两个数量级),而是**回收口**:框架没有 `AgentApp.close()`,MCP 连接器由用户代码
|
|
78
|
+
持有 ⇒ 进程内反复重建会攒孤儿 MCP 子进程。配套硬约定(写进模板注释):**进程外资源一律在模块作用域
|
|
79
|
+
创建并注入**,不许在 provider 构造函数里建。
|
|
80
|
+
- **dev 环鉴权(两层,零依赖)**:`Origin` 校验(**缺失放行** / `Origin: null` **拒绝** / 跨源拒绝)
|
|
81
|
+
+ **每次启动生成的一次性 token**(首帧 `?t=` → `HttpOnly; SameSite=Strict` cookie;脚本走
|
|
82
|
+
`x-agentia-token` 头;`timingSafeEqual` 比较),**每个端点**都校验。token 挡的是**本机其它进程**
|
|
83
|
+
(它们能 `curl`、不受 `Origin` 约束),**别把它当网络边界** —— 面板只绑 `127.0.0.1`。
|
|
84
|
+
- **dev 环缺省预算护栏**:面板上「点一下 = 一次**真** run」⇒ 缺省套
|
|
85
|
+
`{ maxCostUsd: 1, maxTotalTokens: 200_000 }`(可用 `dev.config.ts` 的 `budget` 覆盖)。
|
|
86
|
+
- **模板 `@SubAgent` 的 `system` 改函数形态**(`() => asset(...)`):值形态在**类定义时**求值 ⇒
|
|
87
|
+
`system.md` 要重启进程才生效,而 `.md` 不在 tsx 的 import 图里 ⇒ 静默失效。
|
|
88
|
+
通则:**模块加载期读 = 冻;调用期读 = 热**。
|
|
89
|
+
- **去掉 `NODE_OPTIONS=--import` 注入**:子进程改跑 CLI 自己的 `dev-runner.js`,
|
|
90
|
+
连带那条 Node ≥ 20.6 / ≥ 18.19 的版本闸与字符串拼接一起删掉。
|
|
91
|
+
⚠️ 代价是顺序变成**承重的**:必须在 import 用户 `app.ts` **之前** `await registerTraceSink()`
|
|
92
|
+
—— `createApp` 在构造时就把 `defaultSinks` 快照下来了。
|
|
93
|
+
- **脚手架自带 `read-file` 工具**:读**工作目录**下的文本文件,根由 DI 注入(`WORKDIR`)——
|
|
94
|
+
它是「面板上那个文件夹选择器真的生效」的接线。越界**响亮报错**,不静默截断。
|
|
95
|
+
- **脚手架自带 `src/session-store.ts`**(`FileSessionStore`,**原子写**:临时文件 + rename)
|
|
96
|
+
与 `src/dev.config.ts`(**数据**,不是逻辑)。
|
|
97
|
+
|
|
98
|
+
### 修复(dev 环真跑一次抓出来的 —— 上面那些改动全绿时它们照样在)
|
|
99
|
+
|
|
100
|
+
- **`agentia dev` 起不来:`npx` 吞掉了 IPC 通道。** 子进程原本是 `spawn('npx', ['tsx', runner])`,
|
|
101
|
+
而 `npx` 是包装器、**不给孙进程转发 fd 3** ⇒ runner 里 `process.send` 是 `undefined`,
|
|
102
|
+
代码写的是 `process.send?.()`(可选链)⇒ 所有协议消息**静默丢弃**:面板等不到 `ready`、
|
|
103
|
+
`POST /run` 永远不回来,且进程会以 `code=0` **干净退出**(看起来像「用户代码跑完了」)。
|
|
104
|
+
改成 `node <tsx/cli>` 直起(`resolveTsxCli()`:用户工程优先,退到 CLI 自身;不走
|
|
105
|
+
`node_modules/.bin/tsx` —— Windows 上那是 `.cmd` shim,会绕回 CVE-2024-27980 那个坑)。
|
|
106
|
+
- **`npm run dev` 读不到 `.env`(`npm start` 读得到)。** 上一节把模板拆成 `app.ts` / `main.ts` 时,
|
|
107
|
+
`loadEnvFile()` 留在了 `main.ts`,而 dev 环只 import `app.ts`、**从不执行 `main.ts`**。
|
|
108
|
+
失败形状是静默的:用户看到「没配 key」,然后去怀疑框架。已挪进 `src/app.ts`。
|
|
109
|
+
⚠️ 当时**两处**断言都钉着这件事,但都指着 `main.ts` —— 断言存在 ≠ 钉对了位置,现已改成成对断言。
|
|
110
|
+
- **面板能力选择器空着且无解释。** `DevEvent` 有 restart / error / run-start / run-done,
|
|
111
|
+
**唯独没有「就绪」**;而面板加载时只查一次 `/api/dev`,那时 runner 还没装配完
|
|
112
|
+
(拿到的是父进程初值 `[]`)⇒ 菜单要等用户先跑一次才填上。新增 `{ kind: 'runner-ready' }` 广播。
|
|
113
|
+
- **「runner 没起来就退出」广播了一句更没用的原因。** `exit` 处理器先 `fail()`(reject)再同步
|
|
114
|
+
`emit`,而那时 `lastError` 还是 `null` ⇒ 面板收到笼统的「意外退出」,真正的原因只进了终端
|
|
115
|
+
(reject 要到下一个微任务才被 catch 接住)。改成先写 `lastError` 再 reject。
|
|
116
|
+
- **新增 `scripts/e2e-dev.ts`**:`agentia dev` 整条链真跑(此前**零覆盖**),四条行为断言
|
|
117
|
+
(IPC 就绪 / `.env` 生效 / 能力收窄真的收窄了请求体 / 改 `.md` 触发重启且能恢复)。
|
|
118
|
+
折进 `verify-all.sh` 第 7 步(`npm run e2e`),不加步骤。
|
|
119
|
+
- **中止的 run 被三个地方各自当成「失败」(同一个事实的三个影子)。** 引擎的 `abortedResult()`
|
|
120
|
+
**刻意**给已取消的 run 带上结构化 `error`(取消不是失败,但原因要可查),而 runner 的
|
|
121
|
+
`ok` 定义是 `!result.error` ⇒ **中止时 `ok` 也是 `false`**。于是:
|
|
122
|
+
① 面板把「我按的中止」显示成「run 失败(aborted):run 已被取消」;
|
|
123
|
+
② `dev.ts` 把它写进 `lastError` ⇒ 告警条上永远挂一条红字、且不会再消;
|
|
124
|
+
③ 终端打成「run 失败(stopReason=aborted)」。
|
|
125
|
+
三处统一为「**先认 `stopReason` 再认 `ok`**」,并把面板那一处的判别抽进 `panel-logic.ts`
|
|
126
|
+
(顺序是**语义**,不是渲染 —— 面板那份没有单测)。
|
|
127
|
+
判别口径此前只活在注释里,且**写错了**(写成「中止是正常返回、`ok` 两者都是 true」——
|
|
128
|
+
那是把「不抛异常」误当成「不设 `error`」)。
|
|
129
|
+
- **`watchTree` 的目录跳过判据是「半实现」的**(追一次**瞬时红**追出来的 —— 一次完整门禁里
|
|
130
|
+
CLI 套件红过一次、重跑又绿,没当噪声放过,连跑三次复现后隔离到 watch 用例)。
|
|
131
|
+
`WATCH_SKIP` / 点开头此前**只在「初始递归」那一个调用点**执行,而 watcher 回调里发现新目录时
|
|
132
|
+
调 `addDir` 走的是**另一条路**、那条路上一次判据都没有 ⇒ 行为是「启动时就存在的 `dist/` 不看、
|
|
133
|
+
**启动后才出现**的 `dist/` 看」。判据已收进 `addDir` **内部**(唯一一处),`root` 由调用方
|
|
134
|
+
显式豁免 —— 判据只看**目录名**、不看路径段(项目根本身就叫 `dist` / `.foo` 是合法的;
|
|
135
|
+
用绝对路径段去认 `dist` 会把整个项目判成「不该看」)。
|
|
136
|
+
⚠️ 真跑时的**第一层**防护是**监视根**:`devServer` 只 `watchTree(<projectRoot>/src)`,
|
|
137
|
+
而 `.agentia/` 与 `dist/` 在项目根、根本不在范围内。`WATCH_SKIP` 是**第二层**,两层都要有 ——
|
|
138
|
+
只靠根的话,哪天有人把根改成项目根,`.agentia/session.json` 会立刻变成
|
|
139
|
+
「每次多轮 run 重启一次子进程」的自噬循环。
|
|
140
|
+
⚠️ **这一轮最值钱的不是修好,而是照出一条「假守卫」**:我给 e2e 加了一条「重启次数总账 +
|
|
141
|
+
理由里不许出现 `.agentia` / `dist/`」的断言,反向验证时**单测红了、e2e 照样绿** ——
|
|
142
|
+
逐条排除后确认不是「修复没生效」也不是「断言写错」,而是这条缺陷在 e2e 里**不可达**
|
|
143
|
+
(监视根是 `src/`)。也就是说那条断言真正守的是「**监视根保持 `src/`**」,它**碰不到**
|
|
144
|
+
`WATCH_SKIP` 那条路。断言是真的、绿的、也是对的,只是它守的是**另一件事** ——
|
|
145
|
+
所以 dev.ts 与 e2e 两处的注释都已照实改准(说清哪条守哪件、以及它**不守**什么)。
|
|
146
|
+
- **改 `.env` 不会重启(文档承诺了、代码够不着)。** `WATCH_NAMES` 把 `.env` / `.env.local`
|
|
147
|
+
列进允许清单、`usage-guide` 也把 `.env` 写进「看什么」,但 `watchTree` 的根是
|
|
148
|
+
`<项目根>/src`,而这两份文件在**项目根** ⇒ 这条判据**没有任何一个 watch 够得着**,
|
|
149
|
+
改 `.env` 静默无感。与上面那条是同一类的两个面:**判据认得它**(`shouldWatch` 有单测、
|
|
150
|
+
写得也对)≠ **有人够得着它**(根在调用点决定)。
|
|
151
|
+
新增 `watchRootEnvFiles()` 单开一个 watch:**不递归**、且**只认名字**(不认扩展名 ——
|
|
152
|
+
项目根的 `package.json` 也不该由它管)。刻意**不**把 `watchTree` 的根抬到项目根:
|
|
153
|
+
那会把 `README.md` / `docs/` / `examples/` 全收进来,「改代码要重启」就变成「改任何文档也重启」。
|
|
154
|
+
两处 watch 共用抽出来的去抖器(各写一份会漂 —— 比如只有一处清理 `timer`,停机后仍会回调一次)。
|
|
155
|
+
⚠️ **这条只有真跑能守**:根是**调用点**决定的,`watchTree` 自己无从知道该看哪儿 ——
|
|
156
|
+
所以钉它的是 `scripts/e2e-dev.ts` 第 9-bis 步(真改一次项目根的 `.env`)。
|
|
157
|
+
|
|
158
|
+
### 修复(复核轮:四条窄窗口 / 口径缺陷 + 两条顺手抓出的)
|
|
159
|
+
|
|
160
|
+
同一天对这轮 dev 环改动做了一次逐条回读代码的复核(决策链见 `docs/spec.md` §10 2026-09-22 ⑦)。
|
|
161
|
+
下面每条都补了**反向验证**(把修复摘掉 ⇒ 新加的门禁真的会红):
|
|
162
|
+
|
|
163
|
+
- **并发闸没盖住「换能力选择 ⇒ 重启」那条路径**(双击运行会真并发两次)。受理到 run 真正发出去之间
|
|
164
|
+
有 `await restart(...)`,而 `running` 只在 run 发进通道之后才置位 ⇒ 两个请求双双通过检查,
|
|
165
|
+
runner 里两个 run 并发、`currentAbort` 被覆盖、CLI 侧记账挂到别人的 traceId 上。
|
|
166
|
+
现在多了个只给闸看的 `launching` 占位(刻意不并进 `running`:「中止」按钮据此仍只在真在飞时出现)。
|
|
167
|
+
- **Ctrl+C 会丢掉 SIGKILL 兜底 ⇒ 不响应 SIGTERM 的子进程树活成孤儿**。旧的 SIGINT 处理器固定
|
|
168
|
+
50 ms 就 `process.exit(0)`,而 `stopChild()` 给子进程的宽限期是 3 s(SIGTERM 后等满才补 SIGKILL)——
|
|
169
|
+
父进程先没,那段宽限连同兜底一起消失,`process.on('exit')` 那条也已空转。现在等收尾真的做完再退
|
|
170
|
+
(另有 5 s 硬上限兜「面板连接没关掉」这类卡死,再按一次 Ctrl+C 立即硬退)。
|
|
171
|
+
- **「中止」落在装配窗口里会被静默丢弃**。`runOnce` 是先 `await ensureApp(...)` 再建 AbortController,
|
|
172
|
+
窗口内到达的中止只能看到「没有在飞的 controller」⇒ run 照跑,而父进程 5 s 后把这次**健康的** run
|
|
173
|
+
升级成重启兜底(trace 丢掉、原因还写成「工具不响应 signal」)。现在窗口内的中止会被记住并立即补上。
|
|
174
|
+
- **被中止的 run 在面板上被标成「失败」**(通知条已修好,但 run 列表的红点与对话视图的红边走的是
|
|
175
|
+
`ok` —— 中止的 `ok` 同样是 `false`)。判别统一到 `panel-logic.runIsFailure`(先 `stopReason` 后 `ok`),
|
|
176
|
+
且**中止轮仍留在对话视图里**(框架只在成功路径回写会话,排除它会显示一份少了一轮的对话)。
|
|
177
|
+
- **会话文件损坏时只在 dev 环告警**(`FileSessionStore` 自己会响亮抛错,但框架在 load / append 里
|
|
178
|
+
刻意吞掉会话侧异常 —— 既定口径「辅助动作不击穿 run」)⇒ 历史被当成「第一轮」且新历史写不进去,
|
|
179
|
+
全程无声。现在 runner 在**启动期**探测一次,把原因送进既有的 warning 通道(面板告警条)。
|
|
180
|
+
- **`agentia dev -- "你的问题"`**:裸 CLI 形状会把分隔符 `--` 当成 prompt 传给模型
|
|
181
|
+
(`npm run dev -- "…"` 那条因为 npm 吃掉 `--` 而一直是对的,两条形状都文档化了)。现在两者都取到真 prompt。
|
|
182
|
+
- **模板 `read-file` 未归一化工作目录**:工作目录带尾斜杠时(面板输入框 / `dev.config.ts` / 从 Finder
|
|
183
|
+
粘过来都常见),越界判定 `abs.startsWith(root + '/')` 恒为假 ⇒ **每一次**调用都报「路径越出工作目录」。
|
|
184
|
+
那不是误报,是工具整个变坏,且错误归因会把模型带偏。
|
|
185
|
+
- **模板 subagent 的 `system.md` 补上「你的回复就是报告」约定**:模板这轮把 `system` 改成了**函数形态**
|
|
186
|
+
(改 `.md` 立刻生效),而框架只对**值形态**追加 `REPORT_HINT` ⇒ 函数形态下子代理不知道自己的最终回复
|
|
187
|
+
就是交回主 agent 的交付物,措辞差异没有任何测试看得见。约定现在写在模板自己那份 `system.md` 里。
|
|
188
|
+
|
|
189
|
+
### 文档
|
|
190
|
+
|
|
191
|
+
- `docs/usage-guide.md` §2.1 / §2.2(新):脚手架文件分工 + `agentia dev` 的四组输入 / 监视规则 /
|
|
192
|
+
重启边界 / 鉴权 / 成本 / 会话历史;§6.4 补「对话历史从哪来」与**两层「历史」**的区别
|
|
193
|
+
(prompt 回显模型看不见;对话历史真的进上下文,且只在开了多轮时出现)。
|
|
194
|
+
§2.2 另补一条「**看哪里**」—— 此前只写了「看什么扩展名」,没写监视根(`<项目根>/src` 整棵树
|
|
195
|
+
+ 项目根单独的 `.env` / `.env.local`)⇒ 读者无从知道「改项目根的 `README.md` 不触发重启」。
|
|
196
|
+
- `docs/spec.md` §10 2026-09-22 ②:本轮决策记录,含「**P0–P2 全程零框架改动**」的逐项核对。
|
|
197
|
+
§10 2026-09-22 ③:真跑探针抓出的两个缺陷与三条修复(含反向验证记录)。
|
|
198
|
+
§10 2026-09-22 ④:拿功能文档逐项对照做审计 —— 又抓出两处「文档里有、代码里没有」,
|
|
199
|
+
以及「同一条事实的第三个影子」(中止的 `ok` 是 `false`)。
|
|
200
|
+
§10 2026-09-22 ⑤:追一次瞬时红 → `WATCH_SKIP` 的半实现 + 那条「守了另一件事」的假守卫。
|
|
201
|
+
§10 2026-09-22 ⑥:拿 ⑤ 的「监视根」去核每条判据 → `.env` 是一条**够不着**的判据
|
|
202
|
+
(含「判据的正确性 vs 可达性」与「探针别用写死序号」两条可复用的教训)。
|
|
203
|
+
- `docs/guards.md` §1.4:新增五条守卫登记(面板纯逻辑 + watch 允许清单 / dev 环鉴权与 HTTP 面 /
|
|
204
|
+
生成物能力名一致性 / `agentia dev` 整链真跑 / `.env` 接线成对断言),并随 ④ 扩面
|
|
205
|
+
(`nextSessionId` / `runDoneNotice` / `POST /run/abort` / `POST /session/clear` /
|
|
206
|
+
面板 import 名单反向全覆盖 / e2e 第 10-11 步)、随 ⑤ 再扩面(`watchTree` 的**动态新增目录**
|
|
207
|
+
用例 + e2e 第 12 步重启总账,并注明 e2e 第 12 步**不守**什么)、随 ⑥ 三度扩面
|
|
208
|
+
(`watchRootEnvFiles` 的名字过滤用例 + e2e 第 9-bis 步改项目根 `.env`)。
|
|
209
|
+
§2 尾注补三条可复用的自查问。
|
|
210
|
+
- `docs/plans/2026-09-11-dev-inspector.md`:非目标清单修订 —— **`run 重放执行` 仍然不做**,
|
|
211
|
+
面板做的是「发一次**新的** run」,两者相邻但不同。
|
|
212
|
+
|
|
213
|
+
## [0.8.3] - 2026-09-21
|
|
214
|
+
|
|
215
|
+
### 变更
|
|
216
|
+
|
|
217
|
+
> 本版主题(窗口 `0.8.2 → 0.8.3`,含 #115 与 #116):**增量 trace 出口落地**。记账与交付之间
|
|
218
|
+
> 此前**没有缝** —— `TraceRecorder` 的唯一出口是收尾的 `snapshot()`,所以「等不了 run 收尾」
|
|
219
|
+
> 的消费者(终端面板 / SSE 前端 / 异步任务进度流)拿不到任何东西。本版补上那条缝,顺手把
|
|
220
|
+
> spec §7 F3 的两条后置项与 §9.4 的记录成本问题同日收口。
|
|
221
|
+
> **框架 API 无破坏性变更**:只新增(`onTraceEvent` / `traceLimits.maxEvents` /
|
|
222
|
+
> `AsyncRunner.streamBufferEvents` / `GET /tasks/:id/stream` / `/run` SSE 的 `trace.event` 帧),
|
|
223
|
+
> **既有签名、既有三帧 SSE、既有默认行为逐字不变** —— 不认识新帧的老客户端行为零变化。
|
|
224
|
+
> #116 全部落在**仓库自身**(守卫 + 一次行为等价的重构),不含任何运行时行为变更。
|
|
225
|
+
|
|
226
|
+
### 新增
|
|
227
|
+
|
|
228
|
+
- **`onTraceEvent`:run 进行中逐笔拿记账事件**。`RunInvocationOptions.onTraceEvent`(单次)与
|
|
229
|
+
`AppOptions.onTraceEvent`(应用级缺省)**叠加**(应用级在前)而不是覆盖 —— 观察者是注册不是
|
|
230
|
+
值覆盖,覆盖会让「某次 run 顺手传了个面板回调」把应用级那条静默顶掉。载荷是
|
|
231
|
+
`TraceRecordEvent`(`span.begin` / `span.end` / `span.event` / `span.attribute` / `span.link`,
|
|
232
|
+
**增量 + 此刻的拷贝**)。
|
|
233
|
+
四条纪律:同步派发不 await(订阅者是观察者,不该把 run 变成它的调度)、抛错被吞(与
|
|
234
|
+
`flushSinks` 同款)、无订阅者零派发、**seq 每次记账动作都占号**(与有没有订阅者无关 ——
|
|
235
|
+
否则「订阅晚的人」看到的序号会与一直订阅的人不一致,重放与去重都会错位)。
|
|
236
|
+
它与 `TraceSink` **不互相替代**:sink 是收尾拿整棵、不保证运行期可见;这条是运行期逐笔、
|
|
237
|
+
不保证送达。要「收尾的整棵」继续用 sink。
|
|
238
|
+
- **`POST /run` 的 SSE 新增一族 `trace.event` 帧**。帧名取**一族** + body 里带 `type`,而不是
|
|
239
|
+
每类型一帧:将来加新事件类型时,老客户端只是漏掉一种 `type`,而不是漏掉一种**帧名**(后者
|
|
240
|
+
更隐蔽)。既有三帧(`text.delta` / `run.end` / `error`)逐字未变。
|
|
241
|
+
- **`GET /tasks/:id/stream`:异步任务的进度流**。从头重放 → 转实时 → 终态以 `task.end` 收口关流;
|
|
242
|
+
`Last-Event-ID` / `?from=` 指**流自己的序号**(一个任务可能跨多个 run 段 —— HITL 挂起→恢复、
|
|
243
|
+
崩溃重投,每段是独立的一次 run、`seq` 从 1 重来,而流的读者要的是一条**连续的**流)。
|
|
244
|
+
四条边界:`awaiting_approval` **不是终态**(流继续开着 —— 关掉的话「等审批结果的前端」正好在
|
|
245
|
+
最需要的时候断线);这条流的读者是**旁观者**,背压 / 断开**不 abort 任务**(与 `/run` 的 SSE
|
|
246
|
+
刻意相反:那里的下游是 run 的所有者,背压等于「别继续烧 token 了」);跨进程(别的 runner 跑的
|
|
247
|
+
任务、同一个 store)→ 一帧 `stream.unavailable` + 终态 `task.end`,**不假装实时**;缓冲超限 →
|
|
248
|
+
丢最旧并先发一帧 `stream.truncated`(**不静默**)。缓冲用 `AsyncRunner` 的
|
|
249
|
+
`streamBufferEvents` 调(缺省每任务 500 条;终态流只留最近 16 条)。事件**不落 store** 是有意
|
|
250
|
+
的:实测事件数 = 2 × 工具调用、正文 KB 级 ⇒ 每条工具调用要把 KB 级正文写库两次(写放大),而
|
|
251
|
+
宿主本来就有自己的总线(`onTraceEvent` 就是给它的缝)。
|
|
252
|
+
- **`traceLimits.maxEvents`:整条 trace 的事件总数上限**。超限即**停止记账**,交付时在 run 根写
|
|
253
|
+
一笔 `trace.truncated{droppedEvents, limit}` —— 缺口位置可预测(尾巴)且**有计数**。
|
|
254
|
+
刻意**不做**环形缓冲(丢最旧、留最近):那会让 trace 中间出现空洞,而空洞比「尾巴截断」难解释
|
|
255
|
+
得多(「这一回合怎么没有工具事件」)。`0` = 一条都不记(**有意义的值**,仍有计数);不设 = 不限。
|
|
256
|
+
坏值(NaN / ±Infinity / 负数 / 小数)在 run 入口抛 `TypeError` —— 静默接受会让闸门**形同不存在**
|
|
257
|
+
(`NaN` 让 `>=` 恒假),而使用者以为自己设了上限。
|
|
258
|
+
与既有的 `maxEventChars` **正交**:一个管「单个事件正文多长」、一个管「多少」。
|
|
259
|
+
|
|
260
|
+
### 文档
|
|
261
|
+
|
|
262
|
+
- `docs/usage-guide.md`:`onTraceEvent` / `traceLimits` / `streamBufferEvents` 与
|
|
263
|
+
`GET /tasks/:id/stream` 的用法;§7 边界表补任务进度流的边界(内存 / 跨进程)。
|
|
264
|
+
- `docs/observability.md`:采样在「不内建」之外补上**可算 + 可数** —— §2.3 新增采样率换算表,
|
|
265
|
+
示例 `sampleSink` 增加丢弃计数(`dropped()` / `onDrop`)。**框架仍然不内建采样器**(既有决策
|
|
266
|
+
不变:采样是配方 2.3,`examples/observability` 已有成品;再造一个就是同一件事的两份实现)。
|
|
267
|
+
- `docs/spec.md` §9.4 从「唯一剩下的开放问题」变为**决定**:默认全量、截断默认开、采样不内建,
|
|
268
|
+
框架侧只新增「数量上限 + 丢弃计数」这一件 —— 让「少记了数据」可数。
|
|
269
|
+
- **一处面向使用者的说明被更正**:`formatTraceparent` 的 flags 继续恒 `00`,但理由从「本框架
|
|
270
|
+
不采样」改为**「运行期不可知」** —— 记录 / 导出决策发生在**收尾之后**,出站调用发生在
|
|
271
|
+
**运行期**,那时没有答案。所以它**不会**跟随采样率变成 `01`:原理由在采样成为推荐配法后已不
|
|
272
|
+
严谨,若照它改成「跟随采样」反而是错的。
|
|
273
|
+
|
|
274
|
+
### 仓库自身(不面向使用者)
|
|
275
|
+
|
|
276
|
+
- **`docs/guards.md` §2 从 4 行清到 1 行** —— 三条待守形状建成了机器守卫(`0` 的语义真源 /
|
|
277
|
+
穷尽转发 / 队列消费者配方门禁),细节见该文件 §1.2 / §1.3。顺带登记了两个此前无人写明的事实:
|
|
278
|
+
`intervalMs` 在 `Scheduler.every`(必须 > 0)与 `metricsSink`(`0` = 立即导出)里**同名反义**;
|
|
279
|
+
数量类旋钮里只有 `mapWithConcurrency` 把 `0` 读作「不限」(`maxRetries` / `maxEvents` /
|
|
280
|
+
`maxIterations` 都是「就是不做」)。
|
|
281
|
+
- `scripts/verify-all.sh` 与 CI 的**步数不变**:新增检查一律折进已有步骤(步骤数写在 CI 的必需
|
|
282
|
+
状态检查名里,加一步就要同时改 workflow 与分支保护)。
|
|
283
|
+
|
|
284
|
+
**迁移**:无(框架 API 无破坏性变更,既有代码不需要任何改动)。若你的宿主自己解析 `/run` 的 SSE,
|
|
285
|
+
它**不需要**认识新的 `trace.event` 帧 —— 不认识就忽略,行为与升级前逐字一致。要消费增量事件,
|
|
286
|
+
新接 `onTraceEvent`(程序内)或 `GET /tasks/:id/stream`(远程看进度)即可。
|
|
287
|
+
|
|
8
288
|
## [0.8.2] - 2026-09-21
|
|
9
289
|
|
|
10
290
|
### 变更
|
|
@@ -499,7 +779,6 @@
|
|
|
499
779
|
「手写转发列表不得漏字段」形状,历史事故 = `runAgentScoped` 漏 `toolTimeoutMs`)—— 待口径判定:
|
|
500
780
|
转发,或在 `types.ts` 注明「只作用本层循环」。
|
|
501
781
|
|
|
502
|
-
## [Unreleased]
|
|
503
782
|
|
|
504
783
|
## [0.6.3] - 2026-09-18
|
|
505
784
|
|
|
@@ -864,7 +1143,9 @@
|
|
|
864
1143
|
首个公开发布:`@migor/agentia` + `@migor/cli`(scope `@migor/*`),两包版本同步。
|
|
865
1144
|
框架本体单包;CLI 独立成包(workspaces)。
|
|
866
1145
|
|
|
867
|
-
[Unreleased]: https://github.com/retrychx/agentia/compare/v0.
|
|
1146
|
+
[Unreleased]: https://github.com/retrychx/agentia/compare/v0.9.0...HEAD
|
|
1147
|
+
[0.9.0]: https://github.com/retrychx/agentia/releases/tag/v0.9.0
|
|
1148
|
+
[0.8.3]: https://github.com/retrychx/agentia/releases/tag/v0.8.3
|
|
868
1149
|
[0.8.2]: https://github.com/retrychx/agentia/releases/tag/v0.8.2
|
|
869
1150
|
[0.8.1]: https://github.com/retrychx/agentia/releases/tag/v0.8.1
|
|
870
1151
|
[0.8.0]: https://github.com/retrychx/agentia/releases/tag/v0.8.0
|
package/README.en.md
CHANGED
|
@@ -42,7 +42,7 @@ $EDITOR my-app/.env # put ANTHROPIC_API_KEY here (export works too —
|
|
|
42
42
|
agentia create my-app
|
|
43
43
|
cd my-app && npm install
|
|
44
44
|
agentia g tool weather # create src/tools/weather/index.ts and register it
|
|
45
|
-
agentia dev #
|
|
45
|
+
agentia dev # local inspector panel (drive a run, pick capabilities/workdir)
|
|
46
46
|
```
|
|
47
47
|
|
|
48
48
|
Four self-describing directories hold capabilities — the directory name **is** the kind:
|
|
@@ -141,7 +141,7 @@ One run == one trace (`traceId === runId`), **built in from turn 0** — not a b
|
|
|
141
141
|
| Production observability recipes | [`docs/observability.md`](./docs/observability.md) |
|
|
142
142
|
| Examples (complete app / minimal deploy / observability) | [`examples/`](./examples/) |
|
|
143
143
|
| Design spec & roadmap | [`docs/spec.md`](./docs/spec.md) · [`docs/roadmap.md`](./docs/roadmap.md) |
|
|
144
|
-
| Website · Playground | [agentia-web.pages.dev](https://agentia-web.pages.dev) · [playground](https://agentia-web.pages.dev/playground
|
|
144
|
+
| Website · Playground | [agentia-web.pages.dev](https://agentia-web.pages.dev) · [playground](https://agentia-web.pages.dev/playground) |
|
|
145
145
|
|
|
146
146
|
## Contributing
|
|
147
147
|
|
package/README.md
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
npx @migor/cli create my-app # 脚手架(含 .env / .env.example)
|
|
23
23
|
cd my-app && npm install # 框架与 CLI 都装进工程
|
|
24
24
|
$EDITOR .env # 填 ANTHROPIC_API_KEY(也可直接 export,真实环境变量优先)
|
|
25
|
-
npm run dev # = agentia dev
|
|
25
|
+
npm run dev # = agentia dev:本地 inspector 面板(输入 prompt / 选能力 / 选工作目录)
|
|
26
26
|
# 可选:ANTHROPIC_BASE_URL(兼容端点)、AGENTIA_MODEL(缺省 claude-opus-5)
|
|
27
27
|
|
|
28
28
|
# 工程内直接用:npx agentia g tool fetch-weather / npx agentia doctor / npx agentia --version
|
|
@@ -31,10 +31,12 @@ npm run dev # = agentia dev:tsx watch + 本地 inspec
|
|
|
31
31
|
# 想全局装(到处都能敲 agentia):npm i -g @migor/cli
|
|
32
32
|
```
|
|
33
33
|
|
|
34
|
-
> 框架**不自动**读 `.env`:脚手架 `src/
|
|
34
|
+
> 框架**不自动**读 `.env`:脚手架 `src/app.ts` 的 `loadEnvFile()` 负责把它读进 `process.env`。
|
|
35
|
+
> 放在**装配模块**(app.ts)而不是启动入口(main.ts),是因为 `agentia dev` 只 import app.ts、
|
|
36
|
+
> 从不执行 main.ts —— 写错一侧会让 `npm run dev` 静默读不到 `.env` 而 `npm start` 读得到。
|
|
35
37
|
> 真实环境变量优先(CI / docker / 命令行永远赢过文件),`loadEnvFile({ override: true })` 才反过来。
|
|
36
38
|
|
|
37
|
-
> **版本**:`0.
|
|
39
|
+
> **版本**:`0.9.0`(`@migor/agentia` 与 `@migor/cli` 均已发布到 npm)。`examples/` **刻意**用
|
|
38
40
|
> `file:../..` 指向本仓库而不是 npm 版本 —— 跑的是**工作区代码**,理由见
|
|
39
41
|
> [`examples/README.md`](examples/README.md) 的「依赖说明」。
|
|
40
42
|
|
|
@@ -56,7 +58,7 @@ agentia g tool weather # 生成 src/tools/weather/index.ts 并
|
|
|
56
58
|
agentia g subagent doc-reviewer # 生成 src/subagents/doc-reviewer/{index.ts,system.md}
|
|
57
59
|
agentia g skill note-writer # 生成 src/skills/note-writer/index.ts
|
|
58
60
|
agentia g prompt style-guide # 生成 src/prompts/style-guide/{index.ts,asset.md}
|
|
59
|
-
agentia dev #
|
|
61
|
+
agentia dev # 本地 inspector 面板:输入 prompt 驱动一次 run + 看 trace
|
|
60
62
|
```
|
|
61
63
|
|
|
62
64
|
**目录约定**:四分类目录,一能力一文件夹 —— `src/tools/` · `src/skills/` · `src/prompts/` · `src/subagents/`。
|
|
@@ -379,4 +381,4 @@ npm run e2e # 端到端:CLI 脚手架 → 装配 mock run;再真跑
|
|
|
379
381
|
- 生产可观测配方(落库检索 / 日志关联 / 采样 / 脱敏):[`docs/observability.md`](docs/observability.md)
|
|
380
382
|
- 完整示例(四类能力 + 三种触发 + 全观测栈):[`examples/complete/`](examples/complete/)
|
|
381
383
|
- 最小部署示例:[`examples/deploy/`](examples/deploy/)
|
|
382
|
-
- 官网:[agentia-web.pages.dev](https://agentia-web.pages.dev)([在线 Playground](https://agentia-web.pages.dev/playground
|
|
384
|
+
- 官网:[agentia-web.pages.dev](https://agentia-web.pages.dev)([在线 Playground](https://agentia-web.pages.dev/playground) · [文档](https://agentia-web.pages.dev/docs))
|