@migor/agentia 0.10.0 → 0.10.1
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 +148 -1
- package/README.md +1 -1
- package/dist/AGENTS.md +36 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/package.json +3 -2
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,152 @@
|
|
|
5
5
|
(0.x 阶段:minor 可含破坏性变更,每个破坏性变更都在对应版本的「迁移」小节里写明)。
|
|
6
6
|
决策的完整证据链在 `docs/spec.md` §10(带时间线的决策日志)。
|
|
7
7
|
|
|
8
|
+
## [0.10.1] - 2026-10-05
|
|
9
|
+
|
|
10
|
+
> 本版主题(窗口 `0.10.0 → 0.10.1`):**从「看得见一次 run」到「留得下、比得出」**,外加给两块
|
|
11
|
+
> 长期没有闸门的地方补上闸门。三块 —— ① dev 面板:每次 run 收尾把 trace 落盘,成为
|
|
12
|
+
> `report` / `diff` / `harvest` / `export` 四个命令的现成输入,并支持**并排比两条 run**
|
|
13
|
+
> (含「改一句 prompt 立刻重跑对照」的自动补对);② `packages/trace-view`:补规模棘轮 +
|
|
14
|
+
> 三条最该有的行为断言(树形状 / 错误行 / usage 汇总);③ `docs/usage-guide.md` §7 补登记
|
|
15
|
+
> 两条**有病例、可复现**的长跑边界。
|
|
16
|
+
> **无破坏性变更**;`@migor/agentia` 框架代码**零改动**(本轮发布面里唯一碰到 `src/` 的是
|
|
17
|
+
> 版本常量那一行)⇒ 既有使用者**不需要任何动作**。
|
|
18
|
+
> ⚠️ **一处新增的用户可见文件**:跑 `agentia dev` 会往工程根的 `.agentia/` 追加
|
|
19
|
+
> `traces.jsonl`,**只增不减**(`.agentia/` 已 gitignore;要清是用户自己 `rm`)。
|
|
20
|
+
|
|
21
|
+
### dev 调试工作台:trace 落盘 + 并排 A/B(2026-10-05)
|
|
22
|
+
|
|
23
|
+
- **是什么**:`agentia dev` 的本地面板从「看一条 run 的调用树」扩成「**比两条 run 差在哪**」。
|
|
24
|
+
两件事:① 每次 run 收尾把 trace 追加落盘到 `.agentia/traces.jsonl`;② run 列表支持
|
|
25
|
+
**⌘/Ctrl + 单击**选两条,右栏切**双栏**并排两棵调用树,顶部一条差异摘要
|
|
26
|
+
(run 级 summary + 逐 span 字段级差异)。设计稿 `docs/plans/2026-10-05-dev-workbench.md`。
|
|
27
|
+
- **落盘换来什么**:那个文件的格式**恰好就是** `agentia report` / `diff` / `harvest` /
|
|
28
|
+
`export` 四个命令的输入(`jsonlTraceSink` 的契约)⇒ 面板里跑过的每一次 run,
|
|
29
|
+
立刻变成「哪个能力慢/贵/爱失败」「改 prompt 后轨迹漂没漂」的现成输入。
|
|
30
|
+
开发期最贵的一件事是「拿不到刚才那次 run 的数据」,这一行就解决它。
|
|
31
|
+
- **并排 A/B 的判据(三档,显式不静默)**:能力选择与工作目录是 **app 级**的
|
|
32
|
+
(换它们要重启进程)⇒ 两条跨了能力选择的 run,`runConfigSnapshot` 整个变了,
|
|
33
|
+
diff 出来的差异**多半与「我改的那句话」无关**。所以跨能力 / 跨目录 / 元信息缺失
|
|
34
|
+
都给**显式降级提示**(含可执行的出路),而不是静默给一份没意义的 diff。
|
|
35
|
+
可比时**不显示**提示条 —— 每次都飘噪声等于没有提示。
|
|
36
|
+
- **三条如实标注的边界**:① `traces.jsonl` **只增不减**(`.agentia/` 已 gitignore;
|
|
37
|
+
要清是用户自己 `rm`);② 落盘是**同步写**(`appendFileSync`),大 trace 会占 runner
|
|
38
|
+
事件循环 —— dev 场景单条以百 KB 计,且 `traceLimits.maxEvents` 本来兜上限;
|
|
39
|
+
③ **并排是「事后回看」,不是「同时跑」** —— 单飞闸没解除(解除会连带改变
|
|
40
|
+
「文件变更延后重启」的语义,而那条判据是刻意单源化的),真并发另议。
|
|
41
|
+
- **守卫**:compare 路由三态(顺序 / 可比性 / 归一化)与判据六条都有单测,且做过
|
|
42
|
+
**变异反向验证**(路由顺序反了、判据写死、`rootSpanId` 缺失 —— 三个变异都被咬住)。
|
|
43
|
+
另给 e2e 加了落盘断言(逐行可解析 + **traceId 不重复**:重复行 = sink 被注册两次)。
|
|
44
|
+
- **一处自认的债**:`normalizeForDiff` 存在只因 `diffTraces` 的 `pushAttrDiffs` /
|
|
45
|
+
`pushEventDiffs` 不接受 `undefined`,而 `packages/cli/src/diff.ts` 是框架
|
|
46
|
+
`src/engine/trace-diff.ts` 的**逐字同形移植副本** ⇒ 根治要框架侧一起改
|
|
47
|
+
(`?? {}` / `?? []`),属 `src/` 语义变更。本次取「消费侧归一化」的零核心改动解。
|
|
48
|
+
**零 `src/` 改动** ⇒ 按 `CONTRIBUTING.md` 的判据不写 spec §10。
|
|
49
|
+
- **顺带补的面板测试债**:上面这批面板代码里**能单测的判断已从 HTML 搬进
|
|
50
|
+
`panel-logic`**(`compareView` 三态视图 / `diffSideLabel` 缺侧标签 /
|
|
51
|
+
`diffValueText` 取值 / `diffFetchErrorText` 失败文案)—— 搬**不是**新写,
|
|
52
|
+
是把已存在的行为从「无测试区」挪进 `panel-logic.test.mjs` 的射程。
|
|
53
|
+
⚠️ **剩下的 DOM 接线补不了**(本仓无 jsdom,硬加会引入 DOM 依赖)⇒ 只有
|
|
54
|
+
`scripts/e2e-dev.ts` 间接兜。如实标注,不假装已覆盖。
|
|
55
|
+
- **入库前评审修掉三处**:① **并排态下普通单击切 run 时不复位 DOM** —— 只清了选择,
|
|
56
|
+
右栏与差异摘要**留在屏幕上**(内容还是上一对的)而选中标记已经消失,用户按看到的读
|
|
57
|
+
会张冠李戴。这是本档**唯一用户可见**的缺陷;修法 = 清空必须走 `exitCompare()`,
|
|
58
|
+
并抽出 `resetCompareDom()` 消掉三处逐字重复的复位序列;**另补一条文本层守卫 W4**
|
|
59
|
+
(`state.compare = []` 只许出现在 `exitCompare` 里)—— 面板无 jsdom 单测,
|
|
60
|
+
这是唯一能防它回归的机制。② `refreshCompare` 读不到某条 run 时**静默留白**
|
|
61
|
+
(看起来像「这条没有调用树」,真相是它已被内存 ring 淘汰)⇒ 改为显式说出来。
|
|
62
|
+
③ 删掉只写不读的 `state.diff` 字段 —— 它的注释还承诺了一个**并不存在**的「读取中…」
|
|
63
|
+
渲染。另修:`comparability` 的长 JSDoc 错挂到 `capsKey` 头上(它自己反而没有注释)、
|
|
64
|
+
一条与上一条**同一对 run 同一断言**的死断言(`bothFull`)。
|
|
65
|
+
- **A/B 闭环补最后一跳**:上面那条「改一句 prompt 就能**立刻重跑对照**」此前要手动
|
|
66
|
+
⌘ 点两条才进并排(三步)。现在 —— **已选一条、还没选第二条**时,新 run 一收尾
|
|
67
|
+
就自动补上第二条并进双栏,**并播一条 notice** 说清屏幕为什么变了。判定
|
|
68
|
+
`autoPairTarget` 在 `panel-logic`(6 个断言 + 变异验证),三种情况**刻意不自动**:
|
|
69
|
+
空选择(替用户决定)、已选两条(会挤掉刚选的)、同一条。⚠️ 这是「事后回看」的
|
|
70
|
+
自动化,**单飞闸仍未解除**(真并发要改「文件变更延后重启」那条单源化判据,
|
|
71
|
+
见设计稿 §8)。DOM 接线本身**无自动化覆盖**(无 jsdom),只有 e2e 间接兜。
|
|
72
|
+
|
|
73
|
+
### `packages/trace-view`:补规模守卫 + 补三条最该有的行为断言(2026-10-05)
|
|
74
|
+
|
|
75
|
+
- **规模棘轮**(新增 `test/structure.test.js`):逐文件 `LINE_BUDGET` + **反向**检查
|
|
76
|
+
(表里有、盘上没了 ⇒ 基线该调低,否则登记项失效后守卫「看起来在管」而实际不管)+
|
|
77
|
+
一条「基线表不许有重复键」的自检。**这道守卫买的不是「今天的健康」**(实测
|
|
78
|
+
`src/` 846 行、测试 904 行、体量完全健康),**是「它开始变大时有人被叫醒」** ——
|
|
79
|
+
2026-09-23 刚在 CLI 上治过一模一样的病(`dev.ts` 长到 1148 行、长出隐式状态机,
|
|
80
|
+
靠人工回看才发现)。
|
|
81
|
+
- **三条行为断言**(新增 `test/tree.test.js`,9 个用例):补的是 `renderTrace`
|
|
82
|
+
里**注释最密、却一直没有断言**的三块 ——
|
|
83
|
+
① **树形状**:三层嵌套的树形前缀(`└─` / `├─` / 竖线缩进)与「事件与子 span 按发生
|
|
84
|
+
顺序混排」(拍平成「先全部事件、再全部子 span」会让用户看到因果倒置);
|
|
85
|
+
② **错误行**:失败 span 的类名 / `meta` 带 `error.type` / **原文单独起一行**(只塞
|
|
86
|
+
`title` 等于没显示 —— 首次运行最常见的「没配 API key」就靠这一行定位)、run 根失败
|
|
87
|
+
时根行也标红(已修过的缺陷,防回退)、**正常 span 不加 error 类**(防「三态塌两态」
|
|
88
|
+
导致满屏红);
|
|
89
|
+
③ **usage 汇总**:**只累加 `llm.turn`**(capability span 的 usage 是子 span 聚合,
|
|
90
|
+
重复计入会双算,而页面上看不出异常 —— 最坏的静默错),且**成对**钉「两个 turn 累加成
|
|
91
|
+
两倍」(否则「压根不累加」也能绿);另钉「每行显示自己那份 usage」与「根未结束不收尾」。
|
|
92
|
+
- ⚠️ **新写的断言里三条是我自己写错的**(都被现有代码正确地打红、查证后是断言错不是代码错):
|
|
93
|
+
① 以为 `m1` 是根的独子(实际它还有兄弟 `sibling` ⇒ 只能是 `├─`);
|
|
94
|
+
② 以为「混排」是事件行插到**别的** span 行之间(实际混排发生在**同一个父节点的孩子
|
|
95
|
+
列表**里,事件是所属 span 的子节点);③ 根失败的 status 写在了 trace 顶层
|
|
96
|
+
(渲染器读的是**根 span 自己**的 `status`)。⇒ 三条都已写进注释,说明读的是哪个字段。
|
|
97
|
+
- **两处变异反向验证**(都被咬住):usage 去掉 `llm.turn` 判据 ⇒ 双算 200 被抓到;
|
|
98
|
+
树形缩进恒空 ⇒ 平铺被抓到。**零 `src/` 改动。**
|
|
99
|
+
- **同批复核又修掉两处**:① 结构守卫里那条关于重复键的注释**事实错误** ——
|
|
100
|
+
原文说「本文件是 `.mjs`(ESM 严格模式)⇒ 重复键是 SyntaxError、import 就炸」,
|
|
101
|
+
**实测证伪**:`{ a: 1, a: 2 }` 写进 `.mjs` 是 exit 0、输出 `{ a: 2 }`(ES6 起对象
|
|
102
|
+
字面量的重复键是合法的)。⇒ 那条自检**不是备份,是唯一防线** —— 变异实测:把重复键
|
|
103
|
+
补在**表尾**时「单文件不超基线」那条**照样绿**(后写的值覆盖前者,反而更宽松),
|
|
104
|
+
只有它红。② `tree.test.js` 里一条断言消息夹着**两个 U+FFFD 替换字符** ——
|
|
105
|
+
assert 失败时唯一给线索的那句话是乱码。
|
|
106
|
+
|
|
107
|
+
### 文档 · `§7 已知边界` 补登记两条长跑边界(2026-10-02)
|
|
108
|
+
|
|
109
|
+
- **是什么**:`docs/usage-guide.md` §7 补两行 —— ① 缺省**不裁剪**上下文:不注入 `contextPolicy`
|
|
110
|
+
就一个回合都不裁,长跑成本随**回合数平方增长**(框架给了缝与参考实现 `createBudgetPolicy`,
|
|
111
|
+
但**不替你决定**,因为裁剪有损);② 回给模型的 `tool_result` **不截断、也没有大小闸**
|
|
112
|
+
(`maxEventChars` / `traceContent` 只管**记账侧**),长跑需要一个**宿主侧的输出上限**,
|
|
113
|
+
否则下一回合以 api 错误收尾。
|
|
114
|
+
- **为什么该补**:§7 是「使用者判断『我能不能用这个框架』的唯一依据」,这两条**有病例、
|
|
115
|
+
可复现、可量化**却没登记。更糟的是第 ② 条**已登记了一半**(「`contextPolicy` 不进子循环 ⇒
|
|
116
|
+
撞上限以 api 错误收尾」)—— **一半的边界比没有更危险**:读表的人会推出「那主循环是安全的」。
|
|
117
|
+
- **病例(TB 4.0 实跑,286 个 trial)**:① 上下文**一次都没被裁剪过**(发生过回落的
|
|
118
|
+
trial = **0 / 286**);单次请求的输入 token 从 ~1000 涨到 **619,119**,且
|
|
119
|
+
`sum(steps.prompt_tokens) == final_metrics.total_prompt_tokens` ⇒ 每回合把整段历史**重发**一遍。
|
|
120
|
+
② 有一条 PTY 回显洪水在 trace 里落了 **1.69 亿字符**(单条 `tool_result` 的 content;
|
|
121
|
+
JSON 序列化后 1.84 亿、整个 `trajectory.json` **184 MB**)—— 该 trial 共 **9 步**、
|
|
122
|
+
总输入仅 **10252 token**,洪水恰好在收尾前,**下一步没有真实请求**才侥幸过关。
|
|
123
|
+
- ⚠️ **这两个数不是一回事**(本次差点读错):**trace 里记了多少 ≠ 模型看到了多少**。
|
|
124
|
+
`maxEventChars` / `traceContent` 都在**记账侧**。拿 trace 体积推断上下文之前,先与 usage 对账。
|
|
125
|
+
- **登记形态是 1 pin + 1 gap**:`tool_result` 那条有真门禁 —— `tests/engine/eventChars.test.ts`
|
|
126
|
+
的用例「回给模型的 tool_result 不受截断影响(截断只在记账侧)」正是为它立的 ⇒ `pin`;
|
|
127
|
+
缺省不裁剪那条只有**配置读数**(`run-config.test.ts` 钉 `config.contextPolicy === false`),
|
|
128
|
+
把 `turn.ts` 里的判据改掉它**照旧绿** ⇒ `gap`(「变假时没有用例会红」就是 gap 的定义)。
|
|
129
|
+
- **刻意不做两件事**:① **不写**独立的「工具输出截断配方」—— 目前只有一个使用方(TB),
|
|
130
|
+
且它的诉求恰恰是「**不要**截断」(评测要原始输出);此刻写配方必然是两边折中的空话
|
|
131
|
+
(本仓判据:先有病例,再有设备)。② **不改**「缺省不裁剪」的行为 —— 改缺省 = 替宿主做
|
|
132
|
+
**有损**决策 + 逼核心变厚,与「只给缝、不给策略」冲突。框架这里是对的,欠的只是说明书。
|
|
133
|
+
- **顺手订正一处长期没人发现的读数**:`docs/guards.md` §1.4 的登记行写着「§7 的 **88 行**」,
|
|
134
|
+
而它当时就是错的(实际 90)⇒ 改为 **92**。`guards-registry.test.ts` 只查「清单里的路径
|
|
135
|
+
真实存在」+ 条目密度下限,**不查数字** —— 这类读数没有守卫盯。
|
|
136
|
+
- **去掉一个会腐烂的数**:`examples/terminal-bench/README.md` 原写「`cat` 大文件会让 trace 到
|
|
137
|
+
**几 MB**」,实测上界 **184 MB**(差两个数量级)⇒ 改成**定性 + 现算路径**,
|
|
138
|
+
而不是换一个新的会腐烂的数。
|
|
139
|
+
- **零语义变更 ⇒ 不新增 `docs/spec.md` §10 节**:按 `CONTRIBUTING.md`「**语义变更**要同步 §10」,
|
|
140
|
+
本轮只补登记**既存事实**、未改任何行为(`src/` 零改动)⇒ 不写决策条目。
|
|
141
|
+
- 影响面:`docs/usage-guide.md` §7、`tests/docs/boundary-table.test.ts`(`REGISTRY` +2 条 +
|
|
142
|
+
5 处写死读数)、`docs/guards.md` §1.4、`examples/terminal-bench/README.md`、本节。
|
|
143
|
+
**框架代码零改动。**
|
|
144
|
+
|
|
145
|
+
### 依赖
|
|
146
|
+
|
|
147
|
+
- 开发依赖:`@anthropic-ai/sdk` → 0.131.0 —— **不影响运行时面**:`src/` 不 import 它,
|
|
148
|
+
它只在 devDependencies 里做「core 消息类型族 ↔ SDK 结构兼容」那道门禁(`src/index.ts`
|
|
149
|
+
有说明),而那道门禁在本版是绿的。
|
|
150
|
+
- 官网(不随包发布):`astro` → 7.3.5。构建与产物形状由 `verify-all` 第 8 步
|
|
151
|
+
(`build:website` + 按产物形状核 404 / robots / sitemap / llms.txt)在 PR 阶段验证,
|
|
152
|
+
真实部署只在 main 上跑 —— 本版已随 main 的 CI 部署通过。
|
|
153
|
+
|
|
8
154
|
## [0.10.0] - 2026-09-29
|
|
9
155
|
|
|
10
156
|
> 本版主题(窗口 `0.9.5 → 0.10.0`):**从「跑得起来」到「敢上线、也找得到」**。
|
|
@@ -2733,7 +2879,8 @@ toolkit 142 / runtime 55 / engine 403 / container 10 / store 55 —— 全绿。
|
|
|
2733
2879
|
首个公开发布:`@migor/agentia` + `@migor/cli`(scope `@migor/*`),两包版本同步。
|
|
2734
2880
|
框架本体单包;CLI 独立成包(workspaces)。
|
|
2735
2881
|
|
|
2736
|
-
[Unreleased]: https://github.com/retrychx/agentia/compare/v0.10.
|
|
2882
|
+
[Unreleased]: https://github.com/retrychx/agentia/compare/v0.10.1...HEAD
|
|
2883
|
+
[0.10.1]: https://github.com/retrychx/agentia/releases/tag/v0.10.1
|
|
2737
2884
|
[0.10.0]: https://github.com/retrychx/agentia/releases/tag/v0.10.0
|
|
2738
2885
|
[0.9.5]: https://github.com/retrychx/agentia/releases/tag/v0.9.5
|
|
2739
2886
|
[0.9.4]: https://github.com/retrychx/agentia/releases/tag/v0.9.4
|
package/README.md
CHANGED
|
@@ -42,7 +42,7 @@ npm run dev # = agentia dev:本地 inspector 面板
|
|
|
42
42
|
> 从不执行 main.ts —— 写错一侧会让 `npm run dev` 静默读不到 `.env` 而 `npm start` 读得到。
|
|
43
43
|
> 真实环境变量优先(CI / docker / 命令行永远赢过文件),`loadEnvFile({ override: true })` 才反过来。
|
|
44
44
|
|
|
45
|
-
> **版本**:`0.10.
|
|
45
|
+
> **版本**:`0.10.1`(`@migor/agentia` 与 `@migor/cli` 均已发布到 npm)。`examples/` **刻意**用
|
|
46
46
|
> `file:../..` 指向本仓库而不是 npm 版本 —— 跑的是**工作区代码**,理由见
|
|
47
47
|
> [`examples/README.md`](examples/README.md) 的「依赖说明」。
|
|
48
48
|
|
package/dist/AGENTS.md
CHANGED
|
@@ -198,6 +198,40 @@ token 的作用是挡住**本机其它进程**,别把它当网络边界:这
|
|
|
198
198
|
当前用哪个 id 记在 `.agentia/dev-session-id`(**不是** `session.json` 的一部分):只放内存的话,
|
|
199
199
|
重启 `npm run dev` 之后刚清空的对话会**自己回来**。有 run 在飞时不能清空(会 409)。
|
|
200
200
|
|
|
201
|
+
**每次 run 的 trace 都落盘**:收尾时追加一行到 `.agentia/traces.jsonl`(已被 `.gitignore` 挡住)。
|
|
202
|
+
那个格式**恰好就是** `agentia report` / `diff` / `harvest` / `export` 四个命令的输入 ——
|
|
203
|
+
所以面板里跑过的每一次 run,都可以直接:
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
agentia report .agentia/traces.jsonl # 哪个能力慢 / 贵 / 爱失败
|
|
207
|
+
agentia diff .agentia/traces.jsonl ... # 改 prompt 前后逐 span 比对(有差异时退出码 1)
|
|
208
|
+
agentia harvest .agentia/traces.jsonl --failed # 失败的 run → eval 用例骨架
|
|
209
|
+
agentia export .agentia/traces.jsonl # → 训练数据集 JSONL
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
落盘**不替代**右栏的实时树:那是两条缝(落盘管「事后能查」,`onTraceEvent` 管「此刻看到」)。
|
|
213
|
+
三条如实标注:① 文件**只增不减**(要清是你自己 `rm`);② 落盘是**同步写**,单条 trace 以百 KB
|
|
214
|
+
计、且 `traceLimits.maxEvents` 本来兜上限;③ 面板的 run 列表是**内存** ring(50 条),
|
|
215
|
+
重启就空了 —— 落盘让数据**没丢**,但面板不会替你回看历史。
|
|
216
|
+
|
|
217
|
+
**并排 A/B(比两条 run差在哪)**:run 列表里 **⌘/Ctrl + 单击**选两条(再点一次取消、
|
|
218
|
+
选第三条挤掉最早那条),右栏切**双栏**并排两棵调用树,顶部一条差异摘要
|
|
219
|
+
(run 级 summary + 逐 span 字段级差异,与 `agentia diff` 逐字同源)。
|
|
220
|
+
|
|
221
|
+
⚠️ **可比性分三档,显式不静默**:能力选择与工作目录是 **app 级**的(换它们要重启进程)⇒
|
|
222
|
+
两条跨了能力选择的 run,配置整个变了,diff 出来的差异**多半与你改的那句话无关**。
|
|
223
|
+
所以跨能力 / 跨目录 / 元信息缺失都给出**显式降级提示**(含可执行的出路:建议只改 prompt 后重跑),
|
|
224
|
+
而不是静默给一份没意义的 diff。可比时**不显示**提示条(每次都飘噪声等于没有提示)。
|
|
225
|
+
|
|
226
|
+
⚠️ **并排是「事后回看」,不是「同时跑」**:单飞闸没解除 —— 解除会连带改变「文件变更延后重启」
|
|
227
|
+
的语义(两条判据今天刻意共用同一条忙闲判据),且 A/B 的收益全在「事后并排看差在哪」,
|
|
228
|
+
同时跑还多烧一倍 token。普通单击任意一条即退出并排。
|
|
229
|
+
|
|
230
|
+
**重跑后自动补对**:已经选了一条(还没选第二条)时,新 run 一收尾就**自动**并排 ——
|
|
231
|
+
面板会播一条 notice 说清「为什么屏幕变双栏了」。三种情况**不**自动:空选择(没表达
|
|
232
|
+
对比意图,自动切双栏是替用户决定)、已选两条(再塞一条会挤掉你刚选的)、同一条。
|
|
233
|
+
所以「改一句 prompt → 重跑 → 看差在哪」是**两步**,不是三步。
|
|
234
|
+
|
|
201
235
|
**中止在飞的 run**:run 跑着的时候输入条上会多一个**「■ 中止」**按钮(没在飞时不显示)。
|
|
202
236
|
点了之后:
|
|
203
237
|
- run 在**回合边界**以 `stopReason='aborted'` **正常收尾**,**trace 照常落盘**(面板也会说「已中止」,
|
|
@@ -1672,6 +1706,7 @@ const callable = {
|
|
|
1672
1706
|
| 任务进度流的边界(内存 / 跨进程) | `GET /tasks/:id/stream` 的事件缓冲在**跑任务的进程内存**里:每任务最近 500 条(可用 `AsyncRunner` 的 `streamBufferEvents` 调,须为正整数,坏值构造期抛错),超限丢**最旧**并先发一帧 `stream.truncated`;终态流只留最近 16 条。**没跑完**的流另有一道**缓冲配额**(`streamNonTerminalBuffers`,缺省 32 条流;`0` = 不留):超出即从最旧、**没有订阅者**的流开始回收**回放历史** —— 表项与序号都留着,连上来的读者先收一帧 `stream.truncated` 再转实时(**不会**变成 `stream.unavailable`,那是对别的进程说的话);正在被订阅的流不受配额约束(不抽走正在读的数据)。**跨进程**(队列消费者在别的进程)时没有实时流:发一帧 `stream.unavailable` 后**立即收口** —— 任务已终态则补 `task.end`(随后关连接);**非终态**则补一帧 `stream.closed`(流级收尾,不是伪造终态)并关连接,客户端此后应转去轮询 `GET /tasks/:id`。要跨进程实时请用 `onTraceEvent` 把事件转发到宿主自己的总线(Redis Streams / Kafka) |
|
|
1673
1707
|
| 异步任务的**排队段**边界(内存) | `concurrency` 管「同时在跑几个」,**不管**「跑不上、排在后面」那一段 —— 缺省**排队段无上限**:`submit` 总是收单、`POST /tasks` 总是 202,灌多少就在内存里排多少(每条 = 一条记录 + 一棵悬挂的 `#execute` promise + 一个槽位等待者)。要背压就配 `AsyncRunner({ maxQueued })`:超限 `submit` 抛 `TaskQueueFullError`、HTTP 回 **503 + `Retry-After`**(**只在 `submit` 判** —— 恢复路径推进的是已受理任务,拦下来等于把它搁死在 store 里;幂等键命中的重复提交也不吃 503)。`runner.queued` 是实时读数(与闸同一判据)。⚠️ 进程内拒单**不等于**集群级背压:多副本各算各的,要全局就得上队列 |
|
|
1674
1708
|
| `traceLimits` 与 `maxEventChars` 各管一头 | `maxEventChars` 管**单个事件正文多长**(既有),`traceLimits.maxEvents` 管**整条 trace 记多少条记录事件**(本版)。两者正交、都「不设 = 不限」;超限即**停止记账**,并在 run 根留**两笔** `trace.truncated`:**起点标记** `{limit}`(断点在这里)+ **收尾摘要** `{droppedEvents, limit}`(丢了多少)—— 两笔**同时**进交付的 trace 与 `onTraceEvent` 增量流(⇒ 按 `seq` 折回仍逐字等于收尾那份;两笔簿记**不占** `maxEvents` 配额)。⚠️ 实测 `maxEventChars: false` + 大出参会让 trace 放大 **13.7×**(`npm run bench:trace` 可复现)—— 先收长度再谈采样,收益顺序比反过来大 |
|
|
1709
|
+
| 回给模型的 `tool_result` **不截断、也没有大小闸** | `maxEventChars` / `traceContent` 管的是**记账侧**(trace 记多长、记不记正文)—— 回给模型的工具结果**永远完整**,框架里没有「单条工具结果超过多大就裁」的那条缝。一次 `cat` 大文件、一次刷屏回显就能让**下一回合**的输入爆掉上下文窗口,以 api 错误收尾(长跑里尤其容易撞)。要设输出上限请在**工具实现内部**做(按行数 / 字节截断并附「已截断」标记)—— 框架不替你兜 |
|
|
1675
1710
|
| **采样是导出决策,不是记账决策** | 采样在 `sink` 外做(配方见 `docs/observability.md` 2.3):被采样掉的 trace 在框架内**仍然完整记账**,只是没发给下游。所以别拿「有采样」当「可以少记账」;也正因如此,出站 `traceparent` 的 flags 恒 `00`(记录/导出决策发生在收尾之后,运行期不可知——不替下游声明) |
|
|
1676
1711
|
| 菜单漂移只**标记**、不判失败 | 续跑时未决 tool_use 的工具不在当前菜单 ⇒ 三处信号(`menu.drift` 事件 / 父 span attribute / `console.warn`),run **照常收尾**(那些 tool_use 以 `unknown tool` 回给模型)。**射程如实标注**:判据只看**名字** —— 「工具还在、schema 变了」能被 `tools.menuHash` 比出来,但**不会**在续跑时报 `menu.drift`;**只改 `description`** 连签名都不变(有意:润色文案不算漂移)。严格模式(带具名 error 的收尾)与「结果级字段」记在 spec §11 开放项 |
|
|
1677
1712
|
| `approve` 只收**待决的** id(多一个 → 400 整批拒) | `decisions` 的键必须都在该任务的 `pendingApprovals` 里(调用方从记录的 `pendingApprovals` 读)。多出任何一个 ⇒ **400 + 整批拒 + 记录一字不动**。不校验的代价(已修,2026-09-28 外部深评):多出来的键会写进 `TaskRecord.approvals`,随每次 `save` 全文重写、且终态也不清 ⇒ 一个**认证调用方**单次请求就能把记录撑大(实证:一次 5000 个无关键 = +419 KB),反复调用可无限叠加 |
|
|
@@ -1745,6 +1780,7 @@ const callable = {
|
|
|
1745
1780
|
| Scheduler 调度表不落库 | `every` / `at` 的调度本身只在内存:已 submit 的任务记录能经 `resumePending` 续跑,但「未来某刻再触发」的调度在重启后不存在(远期单发由宿主自己的 cron 驱动)。另:`drain()` 不停 Scheduler —— 停机窗口内到点的 tick 会打一条触发失败日志(无害但吵),介意就 `scheduler.stop()` 先行 |
|
|
1746
1781
|
| file store 的撕裂写只在启动时自愈 | 写入中途失败(磁盘满等)留下的残行由 `healTail` 在**构造期**修复;同进程内继续 append 会把新记录粘在残行尾部、下次启动时一起丢弃 —— 磁盘满告警后先恢复写入能力再继续依赖它 |
|
|
1747
1782
|
| 终态落库失败 ⇒ 重启会重跑 | AsyncRunner 终态 `save` 失败**不遮罩主流程**(「不击穿业务」的代价):store 抖动时任务可能永远停在 `running`,重启后 `resumePending` 会重跑一个**实际已成功**(副作用已发生)的任务 —— 所以副作用工具必须自身幂等。**但失败本身不再静默**:`new AsyncRunner(app, { onPersistError })` 会收到 `{ record, error, phase }`(`phase: 'initial' \| 'outcome'`,后者就是这条)。⚠️ 框架**修不了**它(写不进去就是写不进去)—— 出口的职责是让你能对账、让「记录无声丢失」不再是默认行为(与 `createOtlpExporter({ onExportError })` 同因同形) |
|
|
1783
|
+
| 缺省**不裁剪**上下文(长跑每回合重发全量历史 ⇒ 成本随回合数平方增长) | `contextPolicy` 不注入就一个回合都不裁:每回合把**整段历史**重发给模型,于是回合数翻倍、总输入约翻两番。框架给了缝与一份参考实现(`createBudgetPolicy`),但**不替你决定** —— 裁剪有损(截在哪、留什么会影响答案),是宿主的策略。长任务(几十回合以上)请在 `createApp` 里显式注入 `contextPolicy` |
|
|
1748
1784
|
| `contextPolicy` 不进子循环 | 应用级 `contextPolicy` / `onText` 只对主循环生效:@SubAgent / @Skill 的子运行不做上下文裁剪(长跑子 agent 撞上下文上限会以 api 错误收尾)。预算护栏(`maxTotalTokens` / `maxCostUsd`)正常透传 |
|
|
1749
1785
|
| 记忆没有删除语义 | `MemoryStore` 只有 load/save:run 内 `ctx.delete` 掉的键回写时不会从 store 移除(下一轮水合会复活)。要真删请直接操作 store 实现 |
|
|
1750
1786
|
| 同 keys 的并发回写不合并 | CAS(`loadWithRev` + `saveIfRev`)只做到「冲突时**不写 + 出声**」:框架**不合并、不重试**(合并语义是 store 与宿主的决定,配方见 §6.5)。只有 `load` / `save` 的 store 连冲突都**看不见** —— 版本号是唯一依据,没有它就检测不了覆盖;`InMemoryMemoryStore` 的版本粒度是**整店一个计数**(宁可多报冲突,不漏报真实覆盖) |
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const AGENTIA_VERSION = "0.10.
|
|
1
|
+
export declare const AGENTIA_VERSION = "0.10.1";
|
|
2
2
|
export type { Trace, Span, SpanEvent, SpanError, SpanId, SpanKind, SpanLink, SpanStatus, TraceId, TraceContext, TraceSink, TraceRecordEvent, CapabilityType, Usage, Score, } from './core/trace.js';
|
|
3
3
|
export { attachScore, parseTraceparent } from './core/trace.js';
|
|
4
4
|
export type { AgentTool, ApprovalDecision, JsonSchema, ModelClient, RecorderBackend, SchemaInput, SchemaType, ToolRunContext, TypedSchema, } from './core/tool.js';
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@migor/agentia",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.1",
|
|
4
4
|
"description": "面向应用开发的声明式 agent 服务开发框架:装饰器 + DI 声明四类能力,主 agent 编排执行;每次 run 产出结构化结果与可观测调用树(trace、成本、指标),交付可直接上线的服务。",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -63,12 +63,13 @@
|
|
|
63
63
|
"e2e:mcp:server": "tsx scripts/e2e-mcp-server.ts",
|
|
64
64
|
"e2e:soak": "tsx scripts/e2e-soak.ts",
|
|
65
65
|
"e2e:soak:app": "npm run build && tsx scripts/e2e-soak-app.ts",
|
|
66
|
+
"e2e:soak:suspend": "tsx scripts/e2e-soak-suspend.ts",
|
|
66
67
|
"bench:trace": "tsx scripts/bench-trace-cost.ts",
|
|
67
68
|
"bench:assembly": "tsx scripts/bench-app-assembly.ts",
|
|
68
69
|
"bench:otlp": "tsx scripts/bench-otlp-snapshot.ts"
|
|
69
70
|
},
|
|
70
71
|
"devDependencies": {
|
|
71
|
-
"@anthropic-ai/sdk": "^0.
|
|
72
|
+
"@anthropic-ai/sdk": "^0.131.0",
|
|
72
73
|
"@biomejs/biome": "^2.5.14",
|
|
73
74
|
"@grpc/grpc-js": "^1.14.5",
|
|
74
75
|
"@grpc/proto-loader": "^0.8.1",
|