@thincoder/core 0.10.4 → 0.10.6
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 +39 -1
- package/README.md +1 -1
- package/advisor/compaction.mjs +11 -6
- package/advisor/run.mjs +4 -4
- package/agent/assemble.mjs +1 -1
- package/agent/chat-call.mjs +1 -1
- package/agent/child-marks.mjs +2 -2
- package/agent/digest-account.mjs +5 -4
- package/agent/dispatch-gates.mjs +8 -0
- package/agent/dispatch.mjs +39 -18
- package/agent/family-tools.mjs +22 -11
- package/agent/helpers.mjs +4 -3
- package/agent/light-round.mjs +66 -0
- package/agent/post-turn.mjs +8 -4
- package/agent/run-stages.mjs +5 -3
- package/agent/run-start.mjs +3 -2
- package/agent/setup-reminders.mjs +1 -1
- package/agent/setup.mjs +18 -3
- package/agent/subagent-event.mjs +1 -1
- package/agent/suspension.mjs +8 -5
- package/agent/timers.mjs +56 -5
- package/agent/turn-loop.mjs +5 -3
- package/agent/write-gate.mjs +7 -7
- package/agent-tools/advisor-async.mjs +2 -2
- package/agent-tools/advisor-settle.mjs +2 -2
- package/agent-tools/advisor.mjs +1 -1
- package/agent-tools/async-discard.mjs +34 -0
- package/agent-tools/async-settle.mjs +3 -2
- package/agent-tools/audit-block.mjs +1 -1
- package/agent-tools/bash-async.mjs +1 -1
- package/agent-tools/batch-lifecycle.mjs +35 -14
- package/agent-tools/batch-paths.mjs +4 -4
- package/agent-tools/batch-skeleton.mjs +29 -11
- package/agent-tools/batch.mjs +28 -15
- package/agent-tools/browser-async.mjs +198 -0
- package/agent-tools/checkpoint.mjs +1 -1
- package/agent-tools/design-slots.mjs +232 -0
- package/agent-tools/digest-budget.mjs +1 -1
- package/agent-tools/manifest.mjs +193 -0
- package/agent-tools/parent-channel.mjs +7 -4
- package/agent-tools/review-facts.mjs +13 -13
- package/agent-tools/settings.mjs +1 -1
- package/agent-tools/skill.mjs +1 -1
- package/agent-tools/subagent-async.mjs +21 -12
- package/agent-tools/subagent-scheduler.mjs +8 -5
- package/agent-tools/subagent-spawn.mjs +29 -55
- package/agent-tools/subagent.mjs +21 -8
- package/agent-tools/timer.mjs +186 -12
- package/agent-tools/zero-write-watch.mjs +2 -2
- package/agent-tools.mjs +2 -1
- package/agent.mjs +1 -1
- package/attachments.mjs +1 -1
- package/browser/actions.mjs +163 -0
- package/browser/cdp.mjs +161 -0
- package/browser/clipboard.mjs +142 -0
- package/browser/input-actions.mjs +197 -0
- package/browser/input.mjs +256 -0
- package/browser/launch.mjs +143 -0
- package/browser/queue.mjs +171 -0
- package/browser/session.mjs +494 -0
- package/browser/snapshot.mjs +270 -0
- package/config-io.mjs +18 -13
- package/config-migrate.mjs +13 -29
- package/config-presets.mjs +33 -29
- package/config.mjs +68 -25
- package/context-degrade.mjs +1 -1
- package/context-echo.mjs +1 -1
- package/context-push.mjs +2 -2
- package/context.mjs +1 -1
- package/conventions.mjs +2 -2
- package/declaration.mjs +18 -2
- package/file-links.mjs +1 -1
- package/file-refs.mjs +1 -1
- package/history-window.mjs +1 -1
- package/i18n.mjs +2 -0
- package/ledger-cmd.mjs +62 -16
- package/ledger-db.mjs +6 -0
- package/ledger-surface.mjs +49 -5
- package/ledger-tools.mjs +16 -8
- package/ledger.mjs +9 -16
- package/log.mjs +1 -1
- package/manifest-discovery.mjs +1 -1
- package/manifest-schema.mjs +1 -1
- package/mcp/transport-stdio.mjs +1 -1
- package/mcp.mjs +1 -1
- package/memory/code-index.mjs +1 -1
- package/memory/code-search.mjs +1 -1
- package/memory/code-sync.mjs +1 -1
- package/memory/docs.mjs +6 -2
- package/memory/file-list.mjs +1 -1
- package/memory/file-walk.mjs +17 -5
- package/memory/maintain.mjs +410 -0
- package/memory/memory-tool.mjs +21 -6
- package/memory/schema.mjs +19 -7
- package/memory/sweep.mjs +8 -5
- package/memory/sync-tail.mjs +16 -10
- package/model-ref.mjs +16 -13
- package/model-specs.mjs +21 -9
- package/package.json +2 -1
- package/peer-instances.mjs +1 -1
- package/permission.mjs +33 -0
- package/process-probe.mjs +2 -2
- package/prompts/advisor-design.md +4 -2
- package/prompts/advisor-round1.md +1 -1
- package/prompts/advisor-round2.md +1 -1
- package/prompts/advisor-round3.md +1 -1
- package/prompts/common.md +36 -2
- package/prompts/consult-base.md +1 -1
- package/prompts/discipline-engineering.md +32 -15
- package/prompts/discipline-normal.md +46 -2
- package/prompts/persona-eng-designer.md +6 -6
- package/prompts/persona-engineering.md +14 -6
- package/prompts/persona-normal.md +2 -0
- package/prompts/subagent-base.md +3 -0
- package/provider/core.mjs +6 -0
- package/provider/errors.mjs +5 -3
- package/provider/google.mjs +9 -8
- package/provider/list-models.mjs +3 -2
- package/provider/sse.mjs +3 -0
- package/provider-flows.mjs +14 -15
- package/proxy-chunked.mjs +102 -0
- package/proxy-target.mjs +54 -0
- package/proxy-transport.mjs +298 -0
- package/proxy.mjs +17 -248
- package/session-gc.mjs +2 -2
- package/session-lifecycle.mjs +18 -14
- package/session-slot-claims.mjs +2 -2
- package/session-slots-manifest.mjs +1 -1
- package/session-slots.mjs +3 -3
- package/team-ledger.mjs +282 -0
- package/team.mjs +223 -0
- package/tool-docs/bash.md +1 -0
- package/tool-docs/batch.md +1 -1
- package/tool-docs/browser.md +48 -0
- package/tool-docs/ledger.md +3 -3
- package/tool-docs/manifest.md +16 -0
- package/tool-docs/memory.md +1 -0
- package/tool-docs/notify_parent.md +5 -0
- package/tool-docs/process.md +4 -4
- package/tool-docs/question.md +1 -0
- package/tool-docs/subagent.md +4 -3
- package/tool-docs/team_ledger.md +9 -0
- package/tool-docs/timer.md +6 -0
- package/tool-docs/wait_for.md +1 -0
- package/tools/browser.mjs +161 -0
- package/tools/git.mjs +1 -1
- package/tools/index.mjs +3 -0
- package/tools/ops.mjs +26 -10
- package/tools/repomap.mjs +1 -1
- package/tools/write-path.mjs +2 -2
- package/traces/trace-cleanup.mjs +1 -1
- package/traces/trace-store.mjs +1 -1
- package/vision-reader.mjs +10 -16
package/CHANGELOG.md
CHANGED
|
@@ -3,7 +3,45 @@
|
|
|
3
3
|
All notable changes to the core package are documented here.
|
|
4
4
|
Format: Keep a Changelog · 中文 · 号在发布时定(CalVer——见 `docs/RELEASE.md` §4)。
|
|
5
5
|
|
|
6
|
-
## [
|
|
6
|
+
## [0.10.6] — 2026-10-13
|
|
7
|
+
|
|
8
|
+
> 0.10.5 → 0.10.6(月内 +1——发布时定号;P0 热修)
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- **核包 `files` 白名单补 `browser/`**(P0——0.10.5 装机缺该目录 ⇒ CLI 装后启动崩(`ERR_MODULE_NOT_FOUND`):`tools/browser.mjs:13-15` ∥ `permission.mjs:16` 引 `../browser/*` 而白名单未列;台账 #1362)。发布守则教训:白名单须覆盖运行时引用闭包——发布预检现只对根 `.mjs` ∥ `prompts/` ∥ `tool-docs/` 计数(引闭包断言待另轮补,已登记)。
|
|
13
|
+
|
|
14
|
+
## [0.10.5] — 2026-10-13
|
|
15
|
+
|
|
16
|
+
> 0.10.4 → 0.10.5(月内 +1——发布时定号)
|
|
17
|
+
|
|
18
|
+
### Added
|
|
19
|
+
|
|
20
|
+
- **浏览器工具输入域(#1045)**:`press` ∥ `hover` ∥ `wheel` ∥ `mouse` ∥ `drag` ∥ `touch` ∥ `insert` ∥ `clipboard` 八动作面(回执带来源标记)∥ 异步任务 + kill 缝 ∥ 动作预算与会话自愈。
|
|
21
|
+
- **`manifest` 工具(#1098)**:读 ∥ 初始化 ∥ 白名单点写(`docRoot`/`checkConfig`/`index` 子键;整对象写与表外键拒);设计门辖区 = manifest 树(#1104)。
|
|
22
|
+
- **索引自维护(#1096)**:幽灵行 GC ∥ 压实 ∥ 备份轮换 + `memory maintain` action;记忆索引行预算面向面收正(#1107)。
|
|
23
|
+
- **disk-root 启动门(#1080/#1081)**:磁盘根启动拦截 ∥ 索引排除名。
|
|
24
|
+
- **团队核件(B1)**:`teamVerify` 登录校验缝(三端共用);**团队台账核工具 `team_ledger`**(五 action——写三仅主会话 ∥ 子代理只读变体 ∥ 仓派生原文上送 ∥ 登录态门零 fetch)。
|
|
25
|
+
- **台账工具面深化**:证据语义(append 缺省 ∥ `replace` 旗)∥ 家族锚解析(`discoverFamily` anchor-local)。
|
|
26
|
+
- **提示词纪律线族**:每个配置项须有配置 UI(用户裁定)∥ 用户视角门(U1/U2 注册)∥ 平实写作 ∥ 禁以用户名义裁定 ∥ 工程判断 ∥ 任务书再派生(#969)∥ 上抛标记(#970)∥ 板-域-文件三层结构(#956)∥ 子代理报告四列表格 ∥ **上抛前先读档**(#1328——上抛须携已查证据行)。
|
|
27
|
+
- provider 配置一致性(核 + CLI 双舱);gemini-3.8/3.7 flash 规格行(#1198)。
|
|
28
|
+
|
|
29
|
+
### Changed
|
|
30
|
+
|
|
31
|
+
- **provider 默认模型清退**(通道模型退役——五舱随动)。
|
|
32
|
+
- gemini 思考签名捕获/传递(#1205——工具环内保真);代理分块/传输拆分;会话槽面。
|
|
33
|
+
- 普通模式批档作者缝 + 工作管理说课(#1111)。
|
|
34
|
+
- 测试术语统一(unit / integration——单元测试件为开发期工具,永不入任何闸)。
|
|
35
|
+
|
|
36
|
+
### Fixed
|
|
37
|
+
|
|
38
|
+
- 主会话异步交付两点(投递 ∥ 消费时点收正)。
|
|
39
|
+
- provider 探测随 per-provider 代理 ∥ loopback 恒直连(#1026)。
|
|
40
|
+
- 上下文预算 = 可用窗口推导(advisor ∥ agent 压实不再越界)。
|
|
41
|
+
- 陈旧注释 ∥ 字符串 ∥ 死导入清扫(#1131)。
|
|
42
|
+
- 台账状态行写后即时刷新(库变更 `fs.watch` 去抖 ⇒ 写后 ≤~0.5s 重扫)。
|
|
43
|
+
|
|
44
|
+
## [0.10.4] — 2026-10-05
|
|
7
45
|
|
|
8
46
|
> 0.10.3 → 0.10.4(月内 +1——发布时定号)
|
|
9
47
|
|
package/README.md
CHANGED
|
@@ -82,7 +82,7 @@ Per-release notes and artifacts: `CHANGELOG.md` in this package and the [GitHub
|
|
|
82
82
|
The core lives in `thincoder-core/` of the ThinCoder repository; bug reports and questions go to the
|
|
83
83
|
repository issue tracker. Two conventions shape every change: pure ESM `.mjs` with no build step, and
|
|
84
84
|
zero third-party dependencies — if the Node.js standard library can do it, no third-party package is
|
|
85
|
-
allowed. `npm test` runs the
|
|
85
|
+
allowed. `npm test` runs the test entry (`node test/run.mjs`); after the 2026-09-28 full reset the test manifest is empty (zero tests = green — collection self-checks still run). Unit tests live as batch-local files under `docs/batches/` in the repository — current state: `docs/core/design/TESTING.md` §2.3. It runs again on release through `prepublishOnly`.
|
|
86
86
|
Mechanism design documents live in the repository under `docs/core/design/`.
|
|
87
87
|
|
|
88
88
|
## License
|
package/advisor/compaction.mjs
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* advisor-loop-split 批:loop 的压缩检查点归位本档(`compactContextIfNeeded`——`context_limit` 尾串生成点同迁;时间线面 ⇒ `advisor/timeline.mjs`)。
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import { providerSpec } from "../config.mjs" // 第 25 批:预算派生(与 loop.mjs:12
|
|
13
|
+
import { providerSpec, outputReserve, usableWindow } from "../config.mjs" // 第 25 批:预算派生(与 loop.mjs:12 同源导入);`outputReserve`/`usableWindow` = 2026-10-06 预留裁定(#975)
|
|
14
14
|
// B4(群 B 批,ADVISOR-GUARDS.md §9——F32):CJK 加权单源(provider/rate.mjs 叶子向无环)
|
|
15
15
|
import { estimateText } from "../provider/rate.mjs"
|
|
16
16
|
|
|
@@ -22,14 +22,19 @@ export const MAX_ADVISOR_TURNS = 100
|
|
|
22
22
|
|
|
23
23
|
// Context window limits
|
|
24
24
|
// 上下文预算(第 25 批——120K 硬编码退场):预算跟随评审模型窗口(providerSpec:
|
|
25
|
-
// 模型规格表 × provider 级 context
|
|
26
|
-
//
|
|
27
|
-
|
|
25
|
+
// 模型规格表 × provider 级 context 覆盖)**扣完成预留**(2026-10-06 裁定——预留坐在窗口里 ⇒
|
|
26
|
+
// 压缩先行、不判死;基数 = 可用窗口,见 advisorContextBudget)。头寸用途 = chars/4 估算误差 +
|
|
27
|
+
// 响应/协议开销(内存不构成约束——`ADVISOR-GUARDS.md §8`);判死线仍是宿主机自限线,服务端窗口约束不变。
|
|
28
|
+
export const CONTEXT_LIMIT_RATIO = 0.8 // 判死线 = 可用窗口 × 0.8
|
|
28
29
|
const COMPACT_TRIGGER_RATIO = 0.8 // 压缩触发 = 判死线 × 0.8(既有关系零改)
|
|
29
30
|
|
|
30
|
-
/** 评审上下文预算(纯函数——两档阈值可机测;provider 为 null 时退化默认规格)。
|
|
31
|
+
/** 评审上下文预算(纯函数——两档阈值可机测;provider 为 null 时退化默认规格)。
|
|
32
|
+
* 基数 = **可用窗口 = 窗口 − 完成预留**(#975/用户 2026-10-06 裁定——预留坐在窗口里 ⇒
|
|
33
|
+
* 先压缩、不许 provider 先拒:provider 口径 = 输入 + max_tokens ≤ 窗口;预留 = `outputReserve`)。 */
|
|
31
34
|
export function advisorContextBudget(provider) {
|
|
32
|
-
const
|
|
35
|
+
const spec = providerSpec(provider)
|
|
36
|
+
const usable = usableWindow(spec.context, outputReserve(provider, spec))
|
|
37
|
+
const limit = Math.floor(usable * CONTEXT_LIMIT_RATIO)
|
|
33
38
|
return { limit, compactAt: Math.floor(limit * COMPACT_TRIGGER_RATIO) }
|
|
34
39
|
}
|
|
35
40
|
|
package/advisor/run.mjs
CHANGED
|
@@ -32,10 +32,10 @@ export function resolveAdvisorProvider(agent) {
|
|
|
32
32
|
const provider = findProvider(agent.providers?.length ? agent.providers : agent.config?.providersList ?? [agent.provider], cfg.provider)
|
|
33
33
|
// F-2a (MODEL-400-FIX):无 cfg.model 时渠道克隆须重派生 model——渠道裸克隆会丢 model 键
|
|
34
34
|
// → 无 model 请求 → serde 400。
|
|
35
|
-
//
|
|
36
|
-
//
|
|
37
|
-
//
|
|
38
|
-
const result = cfg.model ? { ...provider, model: cfg.model } : { ...provider, model:
|
|
35
|
+
// 2026-10-09 清除批(与 CLI `cmd-advisor` 同族收正):模型面 = **父解析单档**——渠条目不携
|
|
36
|
+
// 模型(渠道单值模型退场)⇒ 无 cfg.model 取父运行模型 `agent.provider?.model`;两者皆无 →
|
|
37
|
+
// chat 前 `assertProviderModel` fail-fast(不静默)。
|
|
38
|
+
const result = cfg.model ? { ...provider, model: cfg.model } : { ...provider, model: agent.provider?.model }
|
|
39
39
|
// 台账 #329 / `MODEL-SPECS.md §15.4-3`:off 形须**活着到达载荷层**——载荷层 off 门首款 = `provider.thinking === null`
|
|
40
40
|
// (`thincoder-core/provider/core.mjs:213-219`);归一为 `undefined` 会让该门永不开(effort 族 advisor
|
|
41
41
|
// 关思考静默失效)。显式 off 同清**继承档**(渠条目自带 / 主 provider 的 `reasoningEffort` 不得随行——
|
package/agent/assemble.mjs
CHANGED
|
@@ -65,7 +65,7 @@ export async function assembleAgent({ cwd, deps = {}, toolsFinalize = null }) {
|
|
|
65
65
|
const config = D.loadConfig()
|
|
66
66
|
const provider = config.provider
|
|
67
67
|
const providers = config.providersList
|
|
68
|
-
//
|
|
68
|
+
// 代理注入(逐渠独立:provider.proxy ∧ `proxy.uri` 在案 ⇒ 该渠模型请求经代理——无全局闸,2026-10-08);config.provider 是 loadConfig 里的
|
|
69
69
|
// 独立拷贝 —— 同步注入结果(proxyUri)。
|
|
70
70
|
const injectProxy = D.injectProxy ?? (await import("../proxy.mjs")).injectProxy
|
|
71
71
|
injectProxy(providers, config)
|
package/agent/chat-call.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* agent/chat-call.mjs — 单回合模型调用(2026-09-29 P2 三拆:agent.mjs runAgent 段 4 逐字迁入 +
|
|
3
3
|
* `streamOutputAllowed` 定义随迁——agent.mjs re-export 保 import 面)。
|
|
4
|
-
* 接口 = callModelTurn(agent, ctx) → response;错误走原样:AbortError
|
|
4
|
+
* 接口 = callModelTurn(agent, ctx) → response;错误走原样:AbortError-中断分支处理完照旧 `throw e`,
|
|
5
5
|
* 由 runAgent 的 catch/finally 收束。
|
|
6
6
|
*/
|
|
7
7
|
import { chat } from "../provider/index.mjs"
|
package/agent/child-marks.mjs
CHANGED
|
@@ -3,8 +3,8 @@
|
|
|
3
3
|
*
|
|
4
4
|
* 收编自 `spawn-child.mjs`(2026-09-20 端差·显示面消差批 §2.2 X6 实现轮):端壳侧需**静态**
|
|
5
5
|
* 导入锚点做块头注记判定,而 `spawn-child.mjs` 静态链经核 agent 栈可达 `node:sqlite`
|
|
6
|
-
* ⇒ 端壳静态闭包禁达(W8 契约②判据(现载体 =
|
|
7
|
-
*
|
|
6
|
+
* ⇒ 端壳静态闭包禁达(W8 契约②判据(现载体 = 单元测试档 `docs/batches/2026-09-29-residuals-round2.test.mjs`;
|
|
7
|
+
* 单元测试树重建时回迁端侧单元测试档):fail-closed 红)⇒ 锚点下沉**零依赖叶**(先例 = `relay-prefix.mjs` 同因下沉)。`spawn-child.mjs`
|
|
8
8
|
* 原样再导出 ⇒ 既有 import 面(核 agent-tools 族 / CLI `tool-events.mjs`)零改。
|
|
9
9
|
*
|
|
10
10
|
* 语义:消费端用 `includes()` 检出锚点 ⇒ 合成块头注记("work may be partial")——两端各一处:
|
package/agent/digest-account.mjs
CHANGED
|
@@ -35,13 +35,14 @@ export function isDigestRound(opts) {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
/**
|
|
38
|
-
* 投递门控(§6.31.4
|
|
39
|
-
* - `!_daDelivered`
|
|
38
|
+
* 投递门控(§6.31.4 单点谓词;批 async-delivery-formalize 2026-10-12 · §6.34 收窄):
|
|
39
|
+
* - `!_daDelivered` ∧ 本回合 = 系统轮(`autoTurn`)⇒ 投(首次投递——**用户回合零投递**);
|
|
40
40
|
* - `_daRetry` ∧ 本回合 = 消化轮 ⇒ 投(重投经消化轮回路);
|
|
41
41
|
* - 其余 ⇒ 跳过(防重复注入)。
|
|
42
|
+
* 注:`autoTurn` 判据由调用方(`run-start.mjs` 会话态支)传入;回退面(非会话态支)不经本谓词。
|
|
42
43
|
*/
|
|
43
|
-
export function shouldDeliverEntry(entry, digestRound) {
|
|
44
|
-
if (entry?._daDelivered !== true) return true
|
|
44
|
+
export function shouldDeliverEntry(entry, digestRound, autoTurn) {
|
|
45
|
+
if (entry?._daDelivered !== true) return autoTurn === true
|
|
45
46
|
return entry._daRetry === true && digestRound === true
|
|
46
47
|
}
|
|
47
48
|
|
package/agent/dispatch-gates.mjs
CHANGED
|
@@ -76,6 +76,11 @@ export function isSubagentReadonlyAction(toolName, args) {
|
|
|
76
76
|
const action = args?.action
|
|
77
77
|
return action === "list" || action === "get"
|
|
78
78
|
}
|
|
79
|
+
// manifest read 只读格(`MANIFEST.md` §2.10 · 台账 #1098——settings list/get 同分类;init / write 保持侧效门)
|
|
80
|
+
if (toolName === "manifest") {
|
|
81
|
+
const action = args?.action
|
|
82
|
+
return action === "read"
|
|
83
|
+
}
|
|
79
84
|
// #9(TOOLS.md §6.19):process 动作分级——list 保持只读分类(planMode 放行/免审批/可批并行);
|
|
80
85
|
// kill 是破坏性动作(审批门 + planMode 拒)。
|
|
81
86
|
if (toolName === "process") return args?.action !== "kill"
|
|
@@ -87,6 +92,9 @@ export function isSubagentReadonlyAction(toolName, args) {
|
|
|
87
92
|
if (action === "observe") return true
|
|
88
93
|
// AGENT-LOOP-SUBAGENT.md §6.7.2 panel view 面(freeze 缺省/空 = 视图请求——readonly;非空 freeze 归控制类)
|
|
89
94
|
if (action === "panel" && (args.freeze === undefined || args.freeze === null || String(args.freeze) === "")) return true
|
|
95
|
+
// DESIGN-TOKEN-SETTLEMENT.md §10 F-SL1(2026-10-07 批 ledger-tool):design-slots = 只读清点
|
|
96
|
+
// (同 status / observe——planMode 放行 / 免审批 / digest 放行;工程模式父侧门在执行器内)。
|
|
97
|
+
if (action === "design-slots") return true
|
|
90
98
|
return false
|
|
91
99
|
}
|
|
92
100
|
export function isSubagentControlAction(toolName, args) {
|
package/agent/dispatch.mjs
CHANGED
|
@@ -7,9 +7,12 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { FILE_MUTATORS, toolTouchPaths } from "./helpers.mjs"
|
|
9
9
|
import { runHooks } from "../hooks.mjs"
|
|
10
|
-
import { isCodePath,
|
|
10
|
+
import { isCodePath, declarationForTarget } from "../conventions.mjs"
|
|
11
|
+
import { manifestFilePath } from "../manifest.mjs"
|
|
11
12
|
import { resolve, relative } from "node:path"
|
|
12
13
|
import { anyLiveDesignSlot } from "../token-ttl.mjs"
|
|
14
|
+
// F-LC5(LIGHT-CHANNEL §2.8 · 2026-10-09):轻通道轮在盘谓词(代码笔通路——两件双在盘 ⇒ 父侧代码笔放行)。
|
|
15
|
+
import { lightRoundOpen } from "./light-round.mjs"
|
|
13
16
|
// M4 写权门禁(模块设计 §2.1#2):冻结窗口判据组装(被审文件集 = 声明文档集 + 批次档
|
|
14
17
|
// 的合流点)落 write-gate.mjs 单一权威源——本档只 import 消费(KD-M4-4 拆分点)。
|
|
15
18
|
import { freezeWindowConflict, batchRecordWriteConflict } from "./write-gate.mjs"
|
|
@@ -83,28 +86,46 @@ export async function executeToolCalls(agent, toolByName, toolCalls, callbacks,
|
|
|
83
86
|
// design token. The project can declare its own code paths (the manifest's
|
|
84
87
|
// `codePaths`) so a non-src layout is not silently exempted. Mechanically
|
|
85
88
|
// blocks "talk then code".
|
|
89
|
+
// F-LC5(LIGHT-CHANNEL §2.8 · 2026-10-09):轻通道轮在盘 = 机械开路——轮次台账行(在途 · title 携「收尾链
|
|
90
|
+
// 待跑」· 携指针)与所指轮档(§1 状态行「进行中」)双在盘期间父侧代码笔放行(谓词 fail-closed)。
|
|
91
|
+
// 查找面 = 会话锚 + 其直接子目录一层(纯向下——工作区锚会话同判)。
|
|
92
|
+
// F11(#1104 · PORTABILITY §3.9 / D20):辖域 = 目标所属项目——逐目标沿祖先链取最近带档
|
|
93
|
+
// 目录(`declarationForTarget`——nearest wins ∥ 纯向上 ∥ 发现梯不参与);出辖(祖先链无档)
|
|
94
|
+
// ⇒ 放行(门只管 manifest 树以内的内容)。相对形先按会话 cwd 解析(cwd 只是相对基,非声明源);
|
|
95
|
+
// 在辖目标按所属项目装载声明,项目内判定(code 段 ∥ 兜底 fail-closed ∥ doc·temp·aux·state 豁免)零改。
|
|
86
96
|
// DESIGN-TOKEN-SETTLEMENT D3(2026-09-08):资格判据 = 权威槽"任一活槽存在"
|
|
87
97
|
// (anyLiveDesignSlot——查内存 Map,miss 回读槽文件——单值镜像 `_engDesignToken`
|
|
88
98
|
// 已退役,门禁不再读镜像——AC4)。
|
|
89
99
|
if (agent.config?.agent?.engineering && depth === 0
|
|
90
100
|
&& !anyLiveDesignSlot(agent)
|
|
91
|
-
&& FILE_MUTATORS.has(toolCall.name)
|
|
101
|
+
&& FILE_MUTATORS.has(toolCall.name)
|
|
102
|
+
&& !(await lightRoundOpen(agent))) {
|
|
92
103
|
const paths = toolTouchPaths(tool, args)
|
|
93
|
-
|
|
94
|
-
//
|
|
95
|
-
//
|
|
96
|
-
//
|
|
97
|
-
//
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
+
// Unknown/missing paths (non-string / empty — nothing to judge) block conservatively.
|
|
105
|
+
// Known paths are judged per target: resolve against the session cwd first, then
|
|
106
|
+
// classify on the ABSOLUTE form against the target's OWNING PROJECT declaration
|
|
107
|
+
// (the segment face anchors at that project's root — D17). Out of jurisdiction ⇒ the
|
|
108
|
+
// target passes; non-string / empty targets keep blocking above (nothing to judge).
|
|
109
|
+
let blocked = false
|
|
110
|
+
let noteConv = null // first undeclared-and-blocked target's project (hint pointer — #1102)
|
|
111
|
+
for (const p of paths) {
|
|
112
|
+
if (typeof p !== "string" || p.trim() === "") { blocked = true; continue }
|
|
113
|
+
const abs = resolve(agent.cwd, p)
|
|
114
|
+
const conv = declarationForTarget(abs)
|
|
115
|
+
if (!conv || !isCodePath(abs, conv)) continue
|
|
116
|
+
blocked = true
|
|
117
|
+
if (!noteConv && !conv.declared) noteConv = conv
|
|
118
|
+
}
|
|
119
|
+
if (blocked) {
|
|
120
|
+
// Undeclared project → point at ITS declaration file (§4.3 降级可见契约; #1102).
|
|
121
|
+
const convNote = noteConv
|
|
122
|
+
? ` — this path was classified as product code by the default conventions (code paths: ${noteConv.codePaths.join(", ")}); declare project conventions in ${manifestFilePath(noteConv.root)} to adjust.`
|
|
123
|
+
: ""
|
|
104
124
|
prepared.push({
|
|
105
125
|
toolCall, tool, denied: true,
|
|
106
126
|
reason: "engineering design gate",
|
|
107
|
-
hint: `Engineering mode: write the design document first(location per your project's document conventions), then call advisor with type='design' to review it, and wait for user approval. Implementation is done by eng-coder subagents.${convNote}
|
|
127
|
+
hint: `Engineering mode: write the design document first(location per your project's document conventions), then call advisor with type='design' to review it, and wait for user approval. Implementation is done by eng-coder subagents.${convNote} ` +
|
|
128
|
+
`If this is a light-channel code pen: the gate looks for the round from the session anchor and its direct subdirectories — book the round first (an in-flight batch record plus a 在途 ledger row carrying 「收尾链待跑」 pointing at the record); code pens pass once that is on disk.`,
|
|
108
129
|
})
|
|
109
130
|
continue
|
|
110
131
|
}
|
|
@@ -113,14 +134,14 @@ export async function executeToolCalls(agent, toolByName, toolCalls, callbacks,
|
|
|
113
134
|
// E(第 11 批·F17/ADVISOR-GUARDS.md §5 E-3d):D5 冻结窗口写前拦截——设计评审在途(点火 → 结算)期间,
|
|
114
135
|
// 父侧对被审文件集(声明文档集 + 批次档)的写入会被拒绝:在途写使本轮结算 stale——pass 轮
|
|
115
136
|
// = token 直接丢失(实证:第 10 批 id=20 整轮作废)。工具面 = FILE_MUTATORS ∪ `file_ops`
|
|
116
|
-
// (E2
|
|
117
|
-
// agent/write-gate.mjs 的 freezeWindowConflict
|
|
118
|
-
// 同 docAbs / 同 normAbs
|
|
137
|
+
// (E2——冻结分支覆盖范围;批次档分支仍 = FILE_MUTATORS:与变更记账同集——不记入日志的写面既不判 stale 也不拦);判据与 reviewIsStale 同源、单一权威源 =
|
|
138
|
+
// agent/write-gate.mjs 的 freezeWindowConflict(声明文档集分支 = inflightDesignReviewConflict
|
|
139
|
+
// 同 docAbs / 同 normAbs;批次档分支 = run.batchDoc——M4 合流点,仅扫 running 未取消的设计条目)。
|
|
119
140
|
// 位置:只读 / autoApprove 短路之前——审批不得绕过冻结;拒绝 = 可见 denied + 逃生门
|
|
120
141
|
// (先 cancel → 改 → 重发)。
|
|
121
142
|
if (FILE_MUTATORS.has(toolCall.name) || toolCall.name === "file_ops") {
|
|
122
143
|
// #327:单源谓词(同集合内两处消费共用);#309 批次档写门与 D5 冻结窗同区、共用同一路径集。
|
|
123
|
-
// E2(parity-b1 §2.5——缺省取核形):外门扩 `file_ops
|
|
144
|
+
// E2(parity-b1 §2.5——缺省取核形):外门扩 `file_ops`(冻结窗覆盖范围与端壳对齐——`file_ops`
|
|
124
145
|
// 的 move ∕ copy ∕ rename 亦为写面);**批次档写门判据集不变**(= `FILE_MUTATORS`,file_ops 不入)。
|
|
125
146
|
const absPaths = toolTouchPaths(tool, args)
|
|
126
147
|
.filter((p) => typeof p === "string" && p)
|
package/agent/family-tools.mjs
CHANGED
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
*
|
|
14
14
|
* 登记册**动态**载入:`agent-tools.mjs` 静态图经 consult/subagent 族可达核 agent 栈
|
|
15
15
|
* (`../agent/setup.mjs` → `../memory.mjs` → `node:sqlite`)——静态引入会破端壳 W8 契约②
|
|
16
|
-
* (W8 契约②判据(现载体 =
|
|
16
|
+
* (W8 契约②判据(现载体 = 单元测试档 `docs/batches/2026-09-29-residuals-round2.test.mjs`;单元测试树重建时回迁端侧单元测试档):端壳静态链不得到达 `node:sqlite`)。
|
|
17
17
|
* 核内先例 = 登记册头注「Loaded from agent.mjs via dynamic import to avoid ESM circular
|
|
18
18
|
* dependencies」(本档先于 `agent/setup.mjs` 的调用点载入,同一语义)。
|
|
19
19
|
*/
|
|
@@ -22,14 +22,17 @@ export async function assembleFamilyTools({
|
|
|
22
22
|
role = null, // string 子代理角色(eng-coder / eng-designer / coder / consult / explore / …)
|
|
23
23
|
engineering = false, // boolean depth-0 role enum 注入用(工程模式)
|
|
24
24
|
consultModels = [], // array consult 池([] ⇒ consult 工具不注册)
|
|
25
|
-
batchDoc = null, // string 批次档绑定路径(eng
|
|
25
|
+
batchDoc = null, // string 批次档绑定路径(eng 角色恒挂 ∥ 普通面 coder 携绑定挂——batchTool 绑定)
|
|
26
26
|
decorate = null, // object 端差面:{ subagent?, consultStart?, consultStop?, settings? }
|
|
27
27
|
} = {}) {
|
|
28
28
|
// CORE-UNIFICATION TOOLS #83:consult 家族随统一登记册自 `../agent-tools.mjs` 取用(单一来源)
|
|
29
|
-
const { planTool, subagentTool, taskTool, skillTool, goalTool, verifyTool, recentChangesTool, timerTool, advisorTool, engTool, readHistoryTool, contextTool, batchTool, consultStartTool, consultStopTool, parentChannelTool } = await import("../agent-tools.mjs")
|
|
29
|
+
const { planTool, subagentTool, taskTool, skillTool, goalTool, verifyTool, recentChangesTool, timerTool, advisorTool, engTool, readHistoryTool, contextTool, batchTool, manifestTool, consultStartTool, consultStopTool, parentChannelTool } = await import("../agent-tools.mjs")
|
|
30
30
|
// 台账统一入口(2026-10-05 统一入口批——台账 #923):全量变体 = depth-0 段 ∥ 只读变体 = 全部
|
|
31
31
|
// depth>0 段。动态 import——ledger 链静态达 node:sqlite(W8 契约②);两变体同名单对象、schema 窄化。
|
|
32
32
|
const { ledgerTool, ledgerReadTool } = await import("../ledger.mjs")
|
|
33
|
+
// 团队台账核工具(2026-10-13 team-ledger 批——TEAM-LEDGER.md §2.5):全量五 action = depth-0 段 ∥ 只读
|
|
34
|
+
// 变体(query/count)= 全部 depth>0 段(写三 schema 级不可达——D-TL5)。动态 import 同律(沿上条)。
|
|
35
|
+
const { teamLedgerTool, teamLedgerReadTool } = await import("../team-ledger.mjs")
|
|
33
36
|
|
|
34
37
|
// withPool: decorate the consult_start description with the CURRENT candidate pool
|
|
35
38
|
// so the model knows which models it can pick (CLI parity with the plugin). The
|
|
@@ -143,6 +146,11 @@ export async function assembleFamilyTools({
|
|
|
143
146
|
...consultTools,
|
|
144
147
|
// 台账全量变体(五 action——仅主 agent 装配;fail-closed:子代理段只挂读变体 = 写面机械不可达)
|
|
145
148
|
ledgerTool,
|
|
149
|
+
// 团队台账全量变体(五 action——同律:子代理段只挂读变体;登录态门在工具内)
|
|
150
|
+
teamLedgerTool,
|
|
151
|
+
// manifest 工具(`MANIFEST.md` §2.10 · 2026-10-08 · 台账 #1098):主 agent 读写出口——
|
|
152
|
+
// **两模式同挂**(需求未设模式门);子代理各段零挂(未装配 = 权限面第一道)。
|
|
153
|
+
manifestTool,
|
|
146
154
|
// 端差(decorate.settings——VSC depth-0 主 agent 面;缺省不追加):核默认形态里
|
|
147
155
|
// settings 住**基础集**(`tools/index.mjs` `assembleBuiltinTools`),端侧自持清单
|
|
148
156
|
// 无该面 ⇒ 端以 decorate 补位(收敛通道 = 将来去 decorate 项即归核位)。
|
|
@@ -160,19 +168,22 @@ export async function assembleFamilyTools({
|
|
|
160
168
|
// BATCH-RECORD §4.3 挂载表(批次档生命周期工具化批):eng 两分支各挂主名 `batch`
|
|
161
169
|
// (绑定段 append/status;目标 = spawn 绑定 `child._batchDoc`)——BATCH-RECORD.md §4.2 的 batch_segment
|
|
162
170
|
// 挂载形态已随单名化收口退役;depth-0 主 agent 同表挂载
|
|
163
|
-
// `batch`(D-BR18 扩权——create/close + append §1/§4/§6
|
|
164
|
-
// 状态面走普通文档写),目标走可选 path / 在飞扫描)。
|
|
171
|
+
// `batch`(D-BR18 扩权——create/close + append/status 域随模式(工程面 = append §1/§4/§6 ∥ status §1;普通面 =
|
|
172
|
+
// append §1/§2/§4/§5/§6 ∥ status §1/§2/§5)(轮 2 裁定②:§4/§6 状态面走普通文档写),目标走可选 path / 在飞扫描)。
|
|
173
|
+
// §4.16(2026-10-09):coder 分支**携绑定追加** `batchTool(batchDoc)`——未绑定不挂载
|
|
174
|
+
// (工具不在表 = 语法面不可达——同评审面先例);绑定值 = spawn 可选绑定 `child._batchDoc`。
|
|
165
175
|
// SUBAGENT-UPSTREAM-CHANNEL(AGENT-LOOP-UPSTREAM.md §6.27.4 装配接线):子代理上行通道
|
|
166
176
|
// (`notify_parent`)随 depth>0 段**前置**——4 处携带 = eng-coder / eng-designer / coder / 兜底段
|
|
167
177
|
// (未列名 depth>0 role 落同一兜底段 ⇒ 亦装配;语义 =「depth>0 且非 consult 皆装配」);
|
|
168
178
|
// 计数口径:`consult` 分支不入 ⇒ 「5 个插入点」读法已作废(实读 `thincoder-core/agent/family-tools.mjs:165-169`)。
|
|
169
179
|
// consult 段不入(其角色语义 = 父发起的一次性会诊,父在其 settle 前不期望中途对话)。
|
|
170
|
-
// 台账只读变体(query / count)——全部 depth>0 角色段(含 consult ∕ 兜底;写三 schema
|
|
171
|
-
|
|
172
|
-
: engChildRole === "eng-
|
|
173
|
-
:
|
|
174
|
-
: role === "
|
|
175
|
-
: [
|
|
180
|
+
// 台账只读变体(query / count)——全部 depth>0 角色段(含 consult ∕ 兜底;写三 schema 级不可达);
|
|
181
|
+
// 团队台账只读变体(team-ledger 批)同律。
|
|
182
|
+
: engChildRole === "eng-coder" ? [parentChannelTool, ledgerReadTool, teamLedgerReadTool, advisorTool, verifyTool, batchTool(batchDoc), ...(engChildSubagent ? [engChildSubagent] : [])]
|
|
183
|
+
: engChildRole === "eng-designer" ? [parentChannelTool, ledgerReadTool, teamLedgerReadTool, batchTool(batchDoc), ...(engChildSubagent ? [engChildSubagent] : [])]
|
|
184
|
+
: role === "coder" ? [parentChannelTool, ledgerReadTool, teamLedgerReadTool, verifyTool, advisorTool, ...(batchDoc ? [batchTool(batchDoc)] : [])]
|
|
185
|
+
: role === "consult" ? [recentChangesTool, ledgerReadTool, teamLedgerReadTool]
|
|
186
|
+
: [parentChannelTool, ledgerReadTool, teamLedgerReadTool]
|
|
176
187
|
|
|
177
188
|
// 固定段(装配序 = agent.tools → 固定段 → 家族段 → extraTools):timer 全模式全深度;
|
|
178
189
|
// plan 随模式位——ENG-PLAN-EXCLUSION(FR31 ① · KD8 卸载而非「注册 + 报错」· KD11 全深度两端);
|
package/agent/helpers.mjs
CHANGED
|
@@ -203,7 +203,7 @@ export function _clearGitFailureCooldownForTests(cwd) {
|
|
|
203
203
|
gitFailureCooldowns.delete(cwd)
|
|
204
204
|
}
|
|
205
205
|
|
|
206
|
-
/** Git context 纯格式化(branch/log/status = trim
|
|
206
|
+
/** Git context 纯格式化(branch/log/status = trim 后原串)——独立导出供单元测试锁字节
|
|
207
207
|
* parity(现拼装逐字节保留——detached/dirty>20 截断/clean 三形态——VSC 镜像)。 */
|
|
208
208
|
export function composeGitContext({ branch, log, status }) {
|
|
209
209
|
const dirty = status ? status.split("\n").length : 0
|
|
@@ -377,12 +377,13 @@ export const SUBAGENT_TOOL_EXCLUSIONS = new Set(["question"])
|
|
|
377
377
|
/** Apply the depth>0 exclusion set — always returns a NEW array (parent table untouched).
|
|
378
378
|
* #9(TOOLS.md §6.19):`bash` 的 `async` 参仅 depth-0——子代副本删参(照 `family-tools.mjs:98`
|
|
379
379
|
* 先例;返回值仍恒新数组、未命中条目原对象直传)。运行期第二道在 `tools/bash.mjs` execute
|
|
380
|
-
* (照 `read_image`「schema 门 +
|
|
380
|
+
* (照 `read_image`「schema 门 + 运行期第二道」双线先例);批 browser-async-fix(#1045)同线
|
|
381
|
+
* 扩至 `browser` 的 `async` 参(运行期第二道在 `tools/browser.mjs` execute)。 */
|
|
381
382
|
export function excludeSubagentTools(tools) {
|
|
382
383
|
return tools
|
|
383
384
|
.filter((t) => !SUBAGENT_TOOL_EXCLUSIONS.has(t.name))
|
|
384
385
|
.map((t) => {
|
|
385
|
-
if (t.name
|
|
386
|
+
if (!(t.name === "bash" || t.name === "browser") || !t.parameters?.properties || !("async" in t.parameters.properties)) return t
|
|
386
387
|
const { async: _asyncDrop, ...restProps } = t.parameters.properties
|
|
387
388
|
return { ...t, parameters: { ...t.parameters, properties: restProps } }
|
|
388
389
|
})
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* agent/light-round.mjs — 轻通道代码笔通路谓词(F-LC5 · 设计 = `docs/core/design/LIGHT-CHANNEL.md` §2.8)。
|
|
3
|
+
*
|
|
4
|
+
* `lightRoundOpen(agent)`:闸读判据——**两件双在盘**才算轻通道轮在盘:
|
|
5
|
+
* ① 轮次台账行:`status = 在途` ∧ `title` 携「收尾链待跑」(轮型标记 = 闸凭据)∧ `task_book` 非空;
|
|
6
|
+
* ② 该指针指向的轮次批档:`§1` 状态行 = 「进行中」(判定器单源 = `readBatchStatusLine`)。
|
|
7
|
+
* 查找面(纯向下)= 会话锚 + 其直接子目录一层(候选枚举单源 = `ledgerChildren`——与族发现同级判据
|
|
8
|
+
* 同源;不递归 ∥ 不取同胞):逐候选查行 ∥ 以各候选为基解析指针(台账写门同式)。歧义候选
|
|
9
|
+
* (`projectRootView` 判 `ambiguous`——如工作区锚自身)⇒ 跳过该候选、照查其余(既定观察态,非读错);
|
|
10
|
+
* 候选读错 ∥ 不可判 ⇒ 停本候选(总判不因他候选读错而失——开路凭据仍是「两件校验全过」)。
|
|
11
|
+
* 语义:开门动作 ≡ 开轮两件落盘(「启动即挂账」本体——无独立于账的开门面);单件不放行
|
|
12
|
+
* (轮档独在 ∥ 行独在 ∥ 无标记 ∥ 行非在途 ∥ 指针失据 ∥ 档已收口 ⇒ 皆 false);收口即自闭
|
|
13
|
+
* (信号生命周期 = 账生命周期——零撤销动作 ∥ 零跨轮残留)。
|
|
14
|
+
* 读错 ∥ 不可判 ⇒ `false`(fail-closed——照拦;被拦时文案不因读错而变)。
|
|
15
|
+
* 只读:台账 = `ledgerQuery` **动态 import**(`ledger-db.mjs` 静态 import node:sqlite ⇒
|
|
16
|
+
* 消费侧静态 import 破 W8 契约②);批档 = 一次 `readFileSync`。
|
|
17
|
+
*/
|
|
18
|
+
import { readFileSync } from "node:fs"
|
|
19
|
+
import { resolve } from "node:path"
|
|
20
|
+
import { projectRootView, resolveProjectRoot } from "../manifest.mjs"
|
|
21
|
+
import { resolveDeclaredRef } from "../declaration.mjs"
|
|
22
|
+
import { readBatchStatusLine } from "../agent-tools/batch-skeleton.mjs"
|
|
23
|
+
|
|
24
|
+
/** 轮型标记(§2.3 开轮形升格为闸凭据;全链批行无此标记 ⇒ 不构成信号)。 */
|
|
25
|
+
const ROUND_MARKER = "收尾链待跑"
|
|
26
|
+
|
|
27
|
+
/** 轻通道轮在盘谓词(异步 · 只读 · fail-closed)。契约见头注。
|
|
28
|
+
* @param {object} agent — 会话 agent(读 `cwd`)
|
|
29
|
+
* @returns {Promise<boolean>} true = 放行(在盘轮次);读错 ∥ 不可判 ⇒ false(照拦)
|
|
30
|
+
*/
|
|
31
|
+
export async function lightRoundOpen(agent) {
|
|
32
|
+
try {
|
|
33
|
+
const cwd = agent?.cwd
|
|
34
|
+
if (typeof cwd !== "string" || cwd.trim() === "") return false
|
|
35
|
+
// W8 契约②:node:sqlite 链只经动态 import 进入(勿升静态)——候选枚举与逐候选查行同取本档公共面。
|
|
36
|
+
const { ledgerChildren, ledgerQuery } = await import("../ledger.mjs")
|
|
37
|
+
const anchor = resolve(cwd)
|
|
38
|
+
// 候选面 = 锚自身 + 直接子目录一层(纯向下;子项枚举单源 = `ledgerChildren`)。
|
|
39
|
+
const candidates = [anchor, ...ledgerChildren(anchor).map((p) => p.root)]
|
|
40
|
+
for (const cand of candidates) {
|
|
41
|
+
// 歧义候选(≥2 候选项目——`projectRootView`)⇒ 跳过、照查其余(歧义锚不充当项目 = AC-M2-19 同判;
|
|
42
|
+
// `openLedger` 歧义拒 = AC-M2-17——既定观察态,非读错)。
|
|
43
|
+
if (projectRootView(cand).state === "ambiguous") continue
|
|
44
|
+
let rows
|
|
45
|
+
try { rows = ledgerQuery({ cwd: cand, status: "在途" }) } catch { continue } // 候选读错 ⇒ 停本候选
|
|
46
|
+
if (!Array.isArray(rows) || rows.length === 0) continue
|
|
47
|
+
// 指针基准 = 台账写门同式(`ledger-cmd.mjs` assertTaskBookGate 同一子表达式)——以各候选为基。
|
|
48
|
+
const base = resolveProjectRoot(cand) ?? resolve(cand ?? ".")
|
|
49
|
+
for (const row of rows) {
|
|
50
|
+
if (!String(row?.title ?? "").includes(ROUND_MARKER)) continue // 无标记 ⇒ 非轻通道轮(全链批行)
|
|
51
|
+
const taskBook = row?.task_book
|
|
52
|
+
if (typeof taskBook !== "string" || taskBook.trim() === "") continue // 缺指针 ⇒ 单件不放行
|
|
53
|
+
const part = taskBook.split("§")[0].trim() // 台账写门同式:首个 § 前子串
|
|
54
|
+
if (part === "") continue
|
|
55
|
+
const hit = resolveDeclaredRef(base, part)
|
|
56
|
+
if (!hit.ok) continue // 指针失据 ⇒ 不放行
|
|
57
|
+
let src
|
|
58
|
+
try { src = readFileSync(hit.abs, "utf8") } catch { continue } // 档读不到 ⇒ 不放行
|
|
59
|
+
if (readBatchStatusLine(src) === "open") return true // 两件双在盘 ⇒ 放行
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return false
|
|
63
|
+
} catch {
|
|
64
|
+
return false // 读错 ∥ 不可判 ⇒ fail-closed(照拦)
|
|
65
|
+
}
|
|
66
|
+
}
|
package/agent/post-turn.mjs
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* stall detection, and goal status tracking.
|
|
5
5
|
*/
|
|
6
6
|
import { escapeXml, tryCanonicalize, DEFAULT_GOAL_TURNS } from "./helpers.mjs"
|
|
7
|
-
import { takeExpiredTimers, injectTimerReminders } from "./timers.mjs"
|
|
7
|
+
import { takeExpiredTimers, injectTimerReminders, timerWakeEnabled } from "./timers.mjs"
|
|
8
8
|
|
|
9
9
|
export const STALL_WINDOW_SIZE = 5
|
|
10
10
|
export const STALL_THRESHOLD = 3
|
|
@@ -14,11 +14,15 @@ export const GOAL_BUDGET_WARN_RATIO = 0.75
|
|
|
14
14
|
* Inject all post-turn events into agent history.
|
|
15
15
|
* Must be called after every tool-execution turn within runAgent's loop.
|
|
16
16
|
*/
|
|
17
|
-
export function injectPostTurn(agent, results, recentCallSigs, callbacks, turn) {
|
|
17
|
+
export function injectPostTurn(agent, results, recentCallSigs, callbacks, turn, { suspDriven = false } = {}) {
|
|
18
18
|
// Expired timers — inject reminders when thinking budget is up
|
|
19
19
|
// AGENT-LOOP-ASYNC-POOL.md §6.30.2:过滤 / 注入语义单源于 `agent/timers.mjs`(CLI 空闲闩 /
|
|
20
|
-
// 挂起窗同读);本处 =
|
|
21
|
-
|
|
20
|
+
// 挂起窗同读);本处 = 回合边界轮询调用点。
|
|
21
|
+
// 批 async-delivery-formalize(§6.34.2 行 5):驱动面 ∧ `timerWakeEnabled` ⇒ 不在工具轮收尾注入
|
|
22
|
+
// (到期件留在途零出列)——交付交空闲面(挂起窗 ∥ 前台空闲闩);开关关 ∨ 回退面 ⇒ 逐字保持。
|
|
23
|
+
if (!(suspDriven && timerWakeEnabled(agent))) {
|
|
24
|
+
injectTimerReminders(agent, takeExpiredTimers(agent))
|
|
25
|
+
}
|
|
22
26
|
|
|
23
27
|
// Pending reminders
|
|
24
28
|
if (agent._pendingReminders.length > 0) {
|
package/agent/run-stages.mjs
CHANGED
|
@@ -18,7 +18,7 @@ import { carrierField, getAsyncPool, releaseSettledEntry } from "../agent-tools/
|
|
|
18
18
|
import { accountDigestRound, isDigestRound } from "./digest-account.mjs"
|
|
19
19
|
// 批 4 CLI-ASYNC-DISCARD(AGENT-LOOP-ASYNC-POOL.md §6.20):中止分支「只清已死」收尾单点
|
|
20
20
|
// (#9:+ 后台 bash 任务族——逐条杀树 + 出池 + 墓碑)
|
|
21
|
-
import { discardAbortedPool, discardAbortedAdvisors, discardAbortedBgTasks } from "../agent-tools/async-discard.mjs"
|
|
21
|
+
import { discardAbortedPool, discardAbortedAdvisors, discardAbortedBgTasks, discardAbortedBrowserTasks } from "../agent-tools/async-discard.mjs"
|
|
22
22
|
// R10 L3 (MULTI-INSTANCE-COLLAB §2a.5 D-L3a):回合末域登记 flush(写工具钩子累积 →
|
|
23
23
|
// 整写一次本实例 peers 文件——无写入跳过;失败容忍不抛)
|
|
24
24
|
import { flushPeerDomains } from "../peer-domains.mjs"
|
|
@@ -206,14 +206,16 @@ export async function finalizeAgentTurn(agent, ctx) {
|
|
|
206
206
|
const subPool = getAsyncPool(agent, "subagent")
|
|
207
207
|
const advPool = getAsyncPool(agent, "advisor")
|
|
208
208
|
const bgPool = getAsyncPool(agent, "bg") // #9:后台 bash 任务池(第三域)
|
|
209
|
-
|
|
210
|
-
|
|
209
|
+
const brPool = getAsyncPool(agent, "browser") // 批 browser-async-fix:后台浏览器动作池(第四域)
|
|
210
|
+
if ((subPool?.size ?? 0) > 0 || (advPool?.size ?? 0) > 0 || (bgPool?.size ?? 0) > 0 || (brPool?.size ?? 0) > 0) {
|
|
211
|
+
logEvent("ev:stopped", { poolN: (subPool?.size ?? 0) + (advPool?.size ?? 0) + (bgPool?.size ?? 0) + (brPool?.size ?? 0), where: "turn-end-abort" })
|
|
211
212
|
}
|
|
212
213
|
// §6.20:只清已死条目(存活/已 settle 留池——收尾见 async-discard.mjs;原无条件清池已弃);
|
|
213
214
|
// #9:后台 bash 任务同面(杀 ⟺ 控制器已中止——逐条杀树 + 出池 + 墓碑)。
|
|
214
215
|
discardAbortedPool(agent)
|
|
215
216
|
discardAbortedAdvisors(agent)
|
|
216
217
|
discardAbortedBgTasks(agent)
|
|
218
|
+
discardAbortedBrowserTasks(agent) // 批 browser-async-fix:后台浏览器动作同面(不杀浏览器)
|
|
217
219
|
// R17: the consult family dies with the user stop (marked stopped — no digest).
|
|
218
220
|
cleanupConsultSessions(agent)
|
|
219
221
|
// ASYNC-RESULT-CONTAINER.md D2:pending 单容器——中止丢弃 consult/escalate 族停靠
|
package/agent/run-start.mjs
CHANGED
|
@@ -43,10 +43,11 @@ export async function beginRun(agent, input, callbacks, {
|
|
|
43
43
|
const { injectAsyncResult } = await import("../agent-tools/subagent.mjs")
|
|
44
44
|
const { injectConsultResult } = await import("../agent-tools/consult.mjs")
|
|
45
45
|
const digestRound = isDigestRound({ autoTurn, upstreamTurn, timerTurn })
|
|
46
|
-
// 投递门控两态(§6.31.4
|
|
46
|
+
// 投递门控两态(§6.31.4 · §6.34 收窄):首投**仅系统轮**(`autoTurn`——用户回合零注入)∥ 重投仅消化轮;
|
|
47
|
+
// 注入后**留容器**(不 splice)。
|
|
47
48
|
// 注入抛错 ⇒ 未投条目(`_daDelivered` 未置)留容器待下轮——收窄既有「splice 先取尽」的丢失窗。
|
|
48
49
|
for (const e of [...pendingAsync]) {
|
|
49
|
-
if (!shouldDeliverEntry(e, digestRound)) continue
|
|
50
|
+
if (!shouldDeliverEntry(e, digestRound, autoTurn)) continue
|
|
50
51
|
if (e.role === "consult") await injectConsultResult(agent, e)
|
|
51
52
|
else await injectAsyncResult(agent, e)
|
|
52
53
|
e._daDelivered = true
|
|
@@ -34,7 +34,7 @@ import { peerInstances } from "../peer-instances.mjs"
|
|
|
34
34
|
import { specForModel } from "../config.mjs"
|
|
35
35
|
import { manifestFilePath, readManifest, projectView } from "../manifest.mjs"
|
|
36
36
|
|
|
37
|
-
/** env-state line builder — 对入参 + 进程端名确定(§6.20 端名缝 sessionEnd();setSessionEnd 注入 ⇒
|
|
37
|
+
/** env-state line builder — 对入参 + 进程端名确定(§6.20 端名缝 sessionEnd();setSessionEnd 注入 ⇒ 单元测试可用)。
|
|
38
38
|
* §6.11(F1):slot 字段入行——位置在 model 后 resumed 前(N3:无绑定 → 显式 null——
|
|
39
39
|
* 不读 manifest active 共享指针——粘性 _slot 才是"本 agent 之槽")。 */
|
|
40
40
|
export function envStateLine({ mode, model, slot, resumed }) {
|
package/agent/setup.mjs
CHANGED
|
@@ -110,10 +110,25 @@ export async function prepareRun(agent, input, callbacks, {
|
|
|
110
110
|
// §6.10 修法 B(TUI 假死批):回合召回注入 = **depth-0 门**——子代理(depth > 0)不注入
|
|
111
111
|
// 相关文档 / 相关记忆两块(同函数其余自动注入全为 depth-0 门;需求锚 = F-M7 + 核 §4.11)。
|
|
112
112
|
if (agent.memory && depth === 0) {
|
|
113
|
-
|
|
113
|
+
// ── 文档检索注入:§6.15 origin 集 + #1100 声明源保底名额(两路分取——总上限 2×DOC_SEARCH_LIMIT)──
|
|
114
|
+
// 无声明源(origin 集 ≤1)⇒ 原单调用路径逐字保留;有声明源 ⇒ 两路 `Promise.all` 并行:
|
|
115
|
+
// 本仓路(origin = 项目)∥ 声明源路(集 − 本仓),各 DOC_SEARCH_LIMIT——合并序 = 本仓 ≤5 在前
|
|
116
|
+
// + 声明 ≤5 补位(两路 origin 集互斥 ⇒ 行不可能重复,无需去重)。配额机制 = `docs/core/design/AGENT-LOOP.md` §6.3。
|
|
117
|
+
const originSet = searchOrigins(agent.memory)
|
|
118
|
+
let docs
|
|
119
|
+
if (originSet.length > 1) {
|
|
120
|
+
const project = normalizeOrigin(agent.memory.codeOrigin)
|
|
121
|
+
const [localDocs, declaredDocs] = await Promise.all([
|
|
122
|
+
docSearch(agent.memory, input, { limit: DOC_SEARCH_LIMIT, origins: [project] }),
|
|
123
|
+
docSearch(agent.memory, input, { limit: DOC_SEARCH_LIMIT, origins: originSet.filter((o) => o !== project) }),
|
|
124
|
+
])
|
|
125
|
+
docs = [...localDocs, ...declaredDocs]
|
|
126
|
+
} else {
|
|
127
|
+
docs = await docSearch(agent.memory, input, { limit: DOC_SEARCH_LIMIT })
|
|
128
|
+
}
|
|
114
129
|
if (docs.length > 0) {
|
|
115
|
-
// §6.14 B3 + §6.15:origin 集限定 + 有界计数(子查询 LIMIT = WARN+1
|
|
116
|
-
const origins =
|
|
130
|
+
// §6.14 B3 + §6.15:origin 集限定 + 有界计数(子查询 LIMIT = WARN+1 形——越界回「+」形(WARN 值);跨 origin 全扫不再回升)
|
|
131
|
+
const origins = originSet
|
|
117
132
|
const bound = INDEX_ORIGIN_ROW_WARN + 1
|
|
118
133
|
const countFilter = origins.length === 1 ? " WHERE origin = ?" : origins.length > 1 ? ` WHERE origin IN (${origins.map(() => "?").join(", ")})` : ""
|
|
119
134
|
const countRow = agent.memory.db.prepare(
|
package/agent/subagent-event.mjs
CHANGED
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
* 文法:`⟦ev⟧<小写名>\x1e<字段…>`(字段以 RS 分隔)。终止符约束 load-bearing:正文含
|
|
13
13
|
* `⟦ev⟧` 而无 RS 终止符 ⇒ 非事件形态 ⇒ null ⇒ 消费方照常转发(不吞真实正文)。
|
|
14
14
|
* 逐事件字段序 = 发射侧单源(各发射点既有构造——本批零改发射侧);投影映射以样本逐字
|
|
15
|
-
*
|
|
15
|
+
* 钉住(单元测试档 T-862-1…6)——发射侧改字段序 = 契约面变更(设计档 §12.3)。
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
/** 事件 token 哨兵串(D1)——LLM 正常内容混淆概率极低;字段分隔用 RS (\x1e)。 */
|