@thincoder/core 0.9.1 → 0.9.3
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 +63 -0
- package/LICENSE +21 -0
- package/README.md +90 -0
- package/advisor/loop.mjs +2 -2
- package/advisor/run.mjs +1 -1
- package/agent/completion.mjs +3 -1
- package/agent/family-tools.mjs +24 -11
- package/agent/helpers.mjs +11 -2
- package/agent/run-stages.mjs +27 -5
- package/agent/setup-reminders.mjs +67 -11
- package/agent/setup.mjs +6 -0
- package/agent/write-gate.mjs +5 -5
- package/agent-tools/advisor-async.mjs +4 -4
- package/agent-tools/advisor.mjs +3 -3
- package/agent-tools/async-discard.mjs +1 -1
- package/agent-tools/audit-block.mjs +106 -0
- package/agent-tools/batch-lifecycle.mjs +301 -0
- package/agent-tools/batch-segment.mjs +16 -263
- package/agent-tools/batch-skeleton.mjs +156 -0
- package/agent-tools/batch.mjs +410 -0
- package/agent-tools/context.mjs +174 -0
- package/agent-tools/eng.mjs +4 -0
- package/agent-tools/goal.mjs +7 -0
- package/agent-tools/parent-channel.mjs +18 -1
- package/agent-tools/plan.mjs +39 -5
- package/agent-tools/read-history.mjs +122 -24
- package/agent-tools/settings.mjs +4 -2
- package/agent-tools/subagent-async.mjs +3 -3
- package/agent-tools/subagent-spawn.mjs +29 -101
- package/agent-tools/task.mjs +11 -0
- package/agent-tools.mjs +9 -2
- package/agent.mjs +10 -4
- package/config.mjs +1 -1
- package/context.mjs +66 -121
- package/fts-text.mjs +41 -0
- package/generate-title.mjs +6 -6
- package/i18n.mjs +4 -4
- package/ledger-cmd.mjs +30 -7
- package/ledger-db.mjs +22 -2
- package/ledger-executors.mjs +103 -0
- package/ledger-surface.mjs +15 -8
- package/ledger.mjs +15 -4
- package/manifest.mjs +172 -60
- package/memory/core.mjs +4 -18
- package/memory/schema.mjs +4 -11
- package/package.json +22 -1
- package/prompts/advisor-design.md +1 -1
- package/prompts/advisor-round2.md +1 -1
- package/prompts/advisor-round3.md +1 -1
- package/prompts/common.md +3 -3
- package/prompts/discipline-engineering.md +17 -2
- package/prompts/persona-eng-coder.md +1 -1
- package/prompts/persona-eng-designer.md +1 -1
- package/prompts/persona-engineering.md +9 -6
- package/session-gc.mjs +129 -74
- package/session-index-build.mjs +298 -0
- package/session-index-cmd.mjs +61 -0
- package/session-index-pass.mjs +95 -0
- package/session-index-query.mjs +102 -0
- package/session-index.mjs +285 -0
- package/session-lifecycle.mjs +18 -5
- package/session-slots-manifest.mjs +55 -3
- package/session-stale.mjs +247 -0
- package/token-window.mjs +188 -0
- package/tools/bash.mjs +4 -15
- package/tools/execute.mjs +5 -13
- package/tools/git-checkpoint.mjs +1 -1
- package/tools/git-ext.mjs +23 -20
- package/tools/git-run.mjs +141 -0
- package/tools/git.mjs +56 -45
- package/tools/index.mjs +3 -1
- package/tools/process-tree.mjs +20 -0
- package/tools/shared.mjs +8 -4
- package/traces/trace-cleanup.mjs +109 -0
- package/traces/trace-store.mjs +32 -36
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Changelog(@thincoder/core)
|
|
2
|
+
|
|
3
|
+
All notable changes to the core package are documented here.
|
|
4
|
+
Format: Keep a Changelog · 中文 · 号在发布时定(CalVer——见 `docs/RELEASE.md` §4)。
|
|
5
|
+
|
|
6
|
+
## [0.9.3] — 2026-09-22
|
|
7
|
+
|
|
8
|
+
> 0.9.2 → 0.9.3(月内序号——发布时定号)
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **派生会话索引库**(`node:sqlite` · 零新依赖):`read_history` 超大会话不再整档拒(>50k 消息经索引可查)+ `path:"all"` 跨会话检索(行携 `session.file` 回查锚)+ `tool_calls` 携参数;索引从记录段增量建 · 可重建(丢/坏自愈)· 主存(会话文件)零改。
|
|
13
|
+
- **子代理「系统固块」**:机制性指令(审计五锚 + 批档行)改由 spawn 单点写入并拼进 system 面(前缀缓存契约——同 child 连跑 `systemPrompt` 逐字节相等)。
|
|
14
|
+
- **进程族单源**:`killProcessTree` 收口为 `tools/process-tree.mjs`(核 / VSC 本地副本全消除)。
|
|
15
|
+
- **退出即释放会话认领**:正常退出释放本进程认领(端标记保留作路标)——重启恢复不再依赖进程探测兜底。
|
|
16
|
+
- **认领释放扩面**:ACP `session/close` · 跨 cwd 释放 · 被占槽返回可区分信号(零写)。
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
|
|
20
|
+
- **批档工具词面协议结构化**:`batch status` enum 化(散文走 `note`)+ `create` 补 `source` / `prev` 前缀归一 / 占位自动;append/status 占位残留机检(fail-closed)。
|
|
21
|
+
- **工程模式 `task` 工具机械停用**(追踪面 = 批档 + 台账;普通模式零改)。
|
|
22
|
+
- **设置面**:敏感键谓词导出 + 非敏感父对象 JSON 化渲染(`[object Object]` 瑕疙消除)。
|
|
23
|
+
- FTS 语言面外提 `fts-text.mjs`(`segmentCJK` / `buildFtsQuery` 单源 + re-export 面)。
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
|
|
27
|
+
- 会话索引自愈链(坏库 / 删库现场保留 + 重建)· 段轮转与等长改写的水位判别 · 源消失级联清行。
|
|
28
|
+
|
|
29
|
+
## [0.9.2] — 2026-09-21
|
|
30
|
+
|
|
31
|
+
> 0.9.1 → 0.9.2(月内序号——发布时定号)
|
|
32
|
+
|
|
33
|
+
### Added
|
|
34
|
+
|
|
35
|
+
- **PROJECT-MANIFEST 模型(按用点解析)**:项目发现五级梯(会话锚 → 带档祖先 → 一层子档 → 工作区……)+ owning-ancestor 归属 + 建档流;整档缺失不再静默(启动降级 + 明示提示)。
|
|
36
|
+
- **批档生命周期工具** `batch`(create / append / status / close——原 `batch_segment` 更名,别名保留)。
|
|
37
|
+
- **台账执行人列**(F-LX1):executor 归属 + 判存活显示。
|
|
38
|
+
- **信号行两档标签**(digest / ask)+ ask 参数 + 起始行(F-UC8)。
|
|
39
|
+
- **会话认领释放**(F-CR1/CR2):释放 + 拒绝零写入。
|
|
40
|
+
|
|
41
|
+
### Changed
|
|
42
|
+
|
|
43
|
+
- **非阻塞启动**:异步会话 GC · 陈旧清扫 · traces 清理(启动不再被大扫除卡住)。
|
|
44
|
+
- **工程模式排除 `plan` 角色**(FR31——装配 / 命令 / 残留三面一致)。
|
|
45
|
+
- **包面**:README 补建(static 工具口径收正)+ LICENSE + npm 元数据;`files` 白名单不变。
|
|
46
|
+
|
|
47
|
+
### Fixed
|
|
48
|
+
|
|
49
|
+
- 批别名残留(测试断言 / 提示词文档引用 / 错误串)· VSC 子代理块标题行与 CLI 对齐(标题段补全)。
|
|
50
|
+
|
|
51
|
+
## [0.9.1] — 2026-09-21
|
|
52
|
+
|
|
53
|
+
> 核首发(2026-09 当月推导——registry 无号 ⇒ `0.<当月>.1`;首发即本段 ✗ 无更早历史——核内容此前散在两产品仓 ✗ 无独立版本号可考 ✗)。
|
|
54
|
+
|
|
55
|
+
### Added
|
|
56
|
+
|
|
57
|
+
- **核包首发 `@thincoder/core@0.9.1`**:两产品共享机制收敛后的单一权威源——agent 执行环 / 子代理调度(spawn-gate · async 池 · notify_parent)· advisor 评审 · provider 层(SSE 流式 · thinking 映射 · 重试)· 记忆三层 · 工具系统 · 会话存储 · MCP 客户端 · git 集成 · 台账。
|
|
58
|
+
- **提示词与工具文档随包分发**:`prompts/` 15 档 + `tool-docs/` 24 档(一致性断言 D 对象——与 CLI 装机目录 / vsix 三处逐字相等)。
|
|
59
|
+
- **发布门禁**:`prepublishOnly` = `npm test`(与 CLI/VSC 门禁对称——2026-09-21 首发 补上)。
|
|
60
|
+
|
|
61
|
+
### Changed
|
|
62
|
+
|
|
63
|
+
- 两产品 `dependencies` 同步收正 `^0.1.0 → ^0.9.1`(声明面与 registry 实发对齐——断言 A)。
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ThinCoder contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# @thincoder/core
|
|
2
|
+
|
|
3
|
+
**The shared core of the ThinCoder products — the mechanisms and the prompt content behind the ThinCoder CLI and the ThinCoder VS Code extension.**
|
|
4
|
+
|
|
5
|
+
Both products are thin shells: this package owns everything they have in common — the agent loop and subagent
|
|
6
|
+
scheduling, the advisor review system, the provider layer (SSE streaming, thinking-mode mapping, retries, rate
|
|
7
|
+
gating), the three-layer memory with its code and document indexes, the built-in tool system, session storage,
|
|
8
|
+
the MCP client, git and checkpoint integration, the ledger — plus the prompt texts and tool descriptions the
|
|
9
|
+
two products assemble their model context from.
|
|
10
|
+
|
|
11
|
+
The core has **zero third-party dependencies**: Node.js standard library only, pure ESM (`.mjs`), no build step.
|
|
12
|
+
|
|
13
|
+
## Requirements
|
|
14
|
+
|
|
15
|
+
- **Node.js >= 22.13.0** — the floor comes from the built-in `node:sqlite` module (usable without a flag since 22.13.0), which the memory and ledger modules use.
|
|
16
|
+
|
|
17
|
+
## Install
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install @thincoder/core
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
The package is a library — it ships no CLI of its own. Most users never install it directly: the two products
|
|
24
|
+
declare it as a dependency (`thincoder`, the CLI, and `thincoder-vscode`, the VS Code extension). Install it
|
|
25
|
+
directly when you build your own tooling on the shared core.
|
|
26
|
+
|
|
27
|
+
## Importing
|
|
28
|
+
|
|
29
|
+
There is no bare-root entry point — `import "@thincoder/core"` does not resolve (`ERR_PACKAGE_PATH_NOT_EXPORTED`).
|
|
30
|
+
Every import is a subpath, and subpaths map 1:1 onto files in the package (`exports` is `{ "./*": "./*" }`), so
|
|
31
|
+
include the `.mjs` extension:
|
|
32
|
+
|
|
33
|
+
```js
|
|
34
|
+
import { loadConfig } from "@thincoder/core/config.mjs"
|
|
35
|
+
import { createAgent } from "@thincoder/core/agent.mjs"
|
|
36
|
+
import { chat } from "@thincoder/core/provider/index.mjs"
|
|
37
|
+
import { put, putMarkdown } from "@thincoder/core/memory.mjs"
|
|
38
|
+
import { runAdvisorReview } from "@thincoder/core/advisor/run.mjs"
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Nested paths work the same way (`@thincoder/core/git/checkpoint.mjs`, `@thincoder/core/mcp/transport-stdio.mjs`).
|
|
42
|
+
|
|
43
|
+
## What's inside
|
|
44
|
+
|
|
45
|
+
| Area | Modules |
|
|
46
|
+
|---|---|
|
|
47
|
+
| Agent loop, subagents | `agent.mjs` · `agent/` · `agent-tools/` |
|
|
48
|
+
| Advisor review, consultation, escalate | `advisor/` · `agent-tools/consult.mjs` · `agent-tools/escalate-async.mjs` |
|
|
49
|
+
| Provider layer (streaming, thinking mapping, retries, rate gate) | `provider/` |
|
|
50
|
+
| Memory, embedding, code/doc indexes | `memory.mjs` · `memory/` · `embedding.mjs` |
|
|
51
|
+
| Built-in tools | `tools/` |
|
|
52
|
+
| Sessions | `session.mjs` · `session-*.mjs` |
|
|
53
|
+
| MCP client | `mcp.mjs` · `mcp/` |
|
|
54
|
+
| Git, checkpoints, team-memory sync | `git/` |
|
|
55
|
+
| Ledger, traces | `ledger.mjs` · `traces/` |
|
|
56
|
+
|
|
57
|
+
## Shared prompt content
|
|
58
|
+
|
|
59
|
+
The two products author no slot prompts or tool-description bodies of their own: both assemble their model
|
|
60
|
+
context from the texts in this package. `prompt-files.mjs` resolves them relative to the package itself, so the
|
|
61
|
+
same files are loaded in every delivery state (local link, npm install, packaged extension).
|
|
62
|
+
|
|
63
|
+
- `prompts/` — the slot-based prompt texts: personas, the common layer, the discipline layers, and the advisor
|
|
64
|
+
and consultation modules.
|
|
65
|
+
- `tool-docs/` — one file per static built-in tool; these texts are what the model reads as tool descriptions.
|
|
66
|
+
|
|
67
|
+
A prompt rule or a tool-description body is edited in exactly one place, and both products pick it up with the
|
|
68
|
+
next release. The exception is two tool-face anchors — the bash terminal face in `tool-docs/bash.md` and the
|
|
69
|
+
question-panel availability line in `tool-docs/question.md`: each product supplies those two values from its own
|
|
70
|
+
`src/prompt-injections.mjs`, because they describe behavior that differs between the CLI and the extension.
|
|
71
|
+
|
|
72
|
+
## Versioning
|
|
73
|
+
|
|
74
|
+
Version numbers are calendar-based (CalVer): `year.month.monthly-count`, where the year segment counts from
|
|
75
|
+
2026 (`0` = 2026). `0.9.1` is therefore the first core release of September 2026.
|
|
76
|
+
|
|
77
|
+
The number marks release time, not API compatibility — read `CHANGELOG.md` for what changed.
|
|
78
|
+
Per-release notes and artifacts: `CHANGELOG.md` in this package and the [GitHub Releases](https://github.com/xinbo-tech/thincoder/releases) page.
|
|
79
|
+
|
|
80
|
+
## Contributing
|
|
81
|
+
|
|
82
|
+
The core lives in `thincoder-core/` of the ThinCoder repository; bug reports and questions go to the
|
|
83
|
+
repository issue tracker. Two conventions shape every change: pure ESM `.mjs` with no build step, and
|
|
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 offline unit suite; it runs again on release through `prepublishOnly`.
|
|
86
|
+
Mechanism design documents live in the repository under `docs/core/design/`.
|
|
87
|
+
|
|
88
|
+
## License
|
|
89
|
+
|
|
90
|
+
MIT — see `LICENSE`.
|
package/advisor/loop.mjs
CHANGED
|
@@ -11,7 +11,7 @@ import { chat } from "../provider/core.mjs"
|
|
|
11
11
|
import { providerSpec, assistantToolCallMessage } from "../config.mjs"
|
|
12
12
|
import { toOpenAISchema } from "../tools/index.mjs"
|
|
13
13
|
import { truncateAdvisorResult } from "./truncate.mjs"
|
|
14
|
-
import {
|
|
14
|
+
import { batchTool } from "../agent-tools/batch.mjs"
|
|
15
15
|
import {
|
|
16
16
|
estimateTokens, compactMessages, shouldBudgetNudge, budgetNudgeText, timeoutTail, renderTimeline,
|
|
17
17
|
MAX_ADVISOR_TURNS, advisorContextBudget, TOOL_TIMEOUT_MS, REVIEW_TIMEOUT_MS, MAX_RESULT_CHARS,
|
|
@@ -42,7 +42,7 @@ function advisorToolsFor(agent, reviewType = "code", batchDoc = null) {
|
|
|
42
42
|
const tools = [readTool, globTool, grepTool, lsTool, lspTool, advisorCodeSearchTool(agent)]
|
|
43
43
|
// §2.20.3(第 4 批):**只有绑定了批次档的设计评审**额外拿到写通道——代码评审工具集
|
|
44
44
|
// 逐字节不变(零 git + 只读不变量,§2.20.8 #1);未绑定 → 不挂载(fail-closed)。
|
|
45
|
-
if (reviewType === "design" && batchDoc) tools.push(
|
|
45
|
+
if (reviewType === "design" && batchDoc) tools.push(batchTool(batchDoc, { review: true }))
|
|
46
46
|
return { schemas: tools.map(toOpenAISchema), byName: new Map(tools.map((t) => [t.name, t])) }
|
|
47
47
|
}
|
|
48
48
|
// Test seam: the tool set is pure(恒在六工具 + 批次档绑定條件)。
|
package/advisor/run.mjs
CHANGED
|
@@ -10,7 +10,7 @@ import { buildObjectDeclarationBlock, buildDesignApprovalBlock } from "./message
|
|
|
10
10
|
import { appendCitationReport } from "./citations.mjs"
|
|
11
11
|
import { runAdvisorToolLoop } from "./loop.mjs"
|
|
12
12
|
import { advisorIncompleteMarker, estimateTokens } from "./compaction.mjs"
|
|
13
|
-
import { batchDocForReview } from "../agent-tools/batch
|
|
13
|
+
import { batchDocForReview } from "../agent-tools/batch.mjs"
|
|
14
14
|
|
|
15
15
|
// 拆分后 import 面(既有导出名逐一保面——re-export;谓词为本批新增)。
|
|
16
16
|
export { ADVISOR_THINKING_PLACEHOLDER, MAX_RESULT_CHARS, renderTimeline as _renderTimeline } from "./compaction.mjs"
|
package/agent/completion.mjs
CHANGED
|
@@ -53,7 +53,9 @@ export function handleCompletion(agent, response, depth, turn, guardPushbacks, h
|
|
|
53
53
|
// pending item can't be resolved). After the single reminder the model is free
|
|
54
54
|
// to finish — updating the task list (task tool) resets the budget, so a fresh
|
|
55
55
|
// list state earns one fresh reminder.
|
|
56
|
-
|
|
56
|
+
// F10(催更门连带):工程模式下 task 工具机械停用(装配摘除 + execute 拒)⇒ 不再发指向被拒
|
|
57
|
+
// 工具的提醒(死胡同提醒防线);列表本体与 `_taskPushbacks` 预算语义零改。
|
|
58
|
+
if (depth === 0 && !agent.config?.agent?.engineering && agent.tasks.some((t) => t.status === "pending") && (agent._taskPushbacks ?? 0) < 1) {
|
|
57
59
|
agent._taskPushbacks = (agent._taskPushbacks ?? 0) + 1
|
|
58
60
|
const pending = agent.tasks.filter((t) => t.status === "pending").map((t) => t.title).join(", ")
|
|
59
61
|
pushReal(agent, { role: "assistant", content: response.content })
|
package/agent/family-tools.mjs
CHANGED
|
@@ -6,7 +6,9 @@
|
|
|
6
6
|
* (消灭「同一角色矩阵两份实现」= 本批缺陷的类根因);端差(VSC 装饰链 / settings 追加 /
|
|
7
7
|
* consult 池来源)经 `decorate` 注入——**不传 = 核默认形态**(CLI = 迁出前逐字)。
|
|
8
8
|
*
|
|
9
|
-
* 返回 =
|
|
9
|
+
* 返回 = 家族段数组(**非**工程模式:`[task, plan, timer, ...depth 家族 / 角色段]`;工程模式:
|
|
10
|
+
* 固定段 = `[timer]`——plan 不入表(FR31 ① / KD8)· task 不入表(F10——工程模式机械停用,
|
|
11
|
+
* 同 KD8 卸载处置))——**不含** `agent.tools`
|
|
10
12
|
* 展开与 `extraTools`(调用点各自展开:核 `agent/setup.mjs` 两段式)。
|
|
11
13
|
*
|
|
12
14
|
* 登记册**动态**载入:`agent-tools.mjs` 静态图经 consult/subagent 族可达核 agent 栈
|
|
@@ -20,11 +22,11 @@ export async function assembleFamilyTools({
|
|
|
20
22
|
role = null, // string 子代理角色(eng-coder / eng-designer / coder / consult / explore / …)
|
|
21
23
|
engineering = false, // boolean depth-0 role enum 注入用(工程模式)
|
|
22
24
|
consultModels = [], // array consult 池([] ⇒ consult 工具不注册)
|
|
23
|
-
batchDoc = null, // string
|
|
25
|
+
batchDoc = null, // string 批次档绑定路径(eng 角色 → batchTool 绑定)
|
|
24
26
|
decorate = null, // object 端差面:{ subagent?, consultStart?, consultStop?, settings? }
|
|
25
27
|
} = {}) {
|
|
26
28
|
// CORE-UNIFICATION TOOLS #83:consult 家族随统一登记册自 `../agent-tools.mjs` 取用(单一来源)
|
|
27
|
-
const { planTool, subagentTool, taskTool, skillTool, goalTool, verifyTool, recentChangesTool, timerTool, advisorTool, engTool, readHistoryTool,
|
|
29
|
+
const { planTool, subagentTool, taskTool, skillTool, goalTool, verifyTool, recentChangesTool, timerTool, advisorTool, engTool, readHistoryTool, contextTool, batchTool, consultStartTool, consultStopTool, parentChannelTool } = await import("../agent-tools.mjs")
|
|
28
30
|
// 写命令(主 agent 专用)——动态 import 且**仅 depth===0 载入**(ledger 链静态达 node:sqlite——
|
|
29
31
|
// W8 契约②;子代理路径不注册 = 零载入——depth>0 解构得空、不引用即无副作用)
|
|
30
32
|
const { ledgerAddTool, ledgerUpdateTool, ledgerCloseTool } = depth === 0 ? await import("../ledger.mjs") : {}
|
|
@@ -137,7 +139,7 @@ export async function assembleFamilyTools({
|
|
|
137
139
|
: []
|
|
138
140
|
|
|
139
141
|
const depthOnly = depth === 0
|
|
140
|
-
? [decorate?.subagent ?? filteredSubagent, skillTool, goalTool, engTool, verifyTool, recentChangesTool, readHistoryTool, advisorTool,
|
|
142
|
+
? [decorate?.subagent ?? filteredSubagent, skillTool, goalTool, engTool, verifyTool, recentChangesTool, readHistoryTool, contextTool, advisorTool, batchTool(null),
|
|
141
143
|
...consultTools,
|
|
142
144
|
// 台账写命令(M2——仅主 agent;查询面 ledger_count 住基础集 tools/index.mjs)。
|
|
143
145
|
// fail-closed:子代理不挂载 = 写面机械不可达。
|
|
@@ -156,19 +158,30 @@ export async function assembleFamilyTools({
|
|
|
156
158
|
// eng-coder: advisor + verify + the §18 audit-only subagent channel (D-E3).
|
|
157
159
|
// eng-designer (§2.15 D): the survey-only subagent channel alone — no advisor
|
|
158
160
|
// (it does not fire reviews) and no verify (its deliverable is documents, not code).
|
|
159
|
-
// §
|
|
160
|
-
// `
|
|
161
|
-
//
|
|
161
|
+
// BATCH-RECORD §4.3 挂载表(批次档生命周期工具化批):eng 两分支各挂主名 `batch`
|
|
162
|
+
// (绑定段 append/status;目标 = spawn 绑定 `child._batchDoc`)——§2.20.3 的 batch_segment
|
|
163
|
+
// 挂载形态已随单名化收口退役(过渡别名 §4.14 不入生产挂载面);depth-0 主 agent 同表挂载
|
|
164
|
+
// `batch`(D-BR18 扩权——create/close + append §1/§4/§6 + status §1(轮 2 裁定②:§4/§6
|
|
165
|
+
// 状态面走普通文档写),目标走可选 path / 在飞扫描)。
|
|
166
|
+
// SUBAGENT-UPSTREAM-CHANNEL(AGENT-LOOP-UPSTREAM.md §6.27.4 装配接线):子代理上行通道
|
|
162
167
|
// (`notify_parent`)随 depth>0 段**前置**——4 处携带 = eng-coder / eng-designer / coder / 兜底段
|
|
163
168
|
// (未列名 depth>0 role 落同一兜底段 ⇒ 亦装配;语义 =「depth>0 且非 consult 皆装配」);
|
|
164
169
|
// 计数口径:`consult` 分支不入 ⇒ 「5 个插入点」读法已作废(实读 `thincoder-core/agent/family-tools.mjs:165-169`)。
|
|
165
170
|
// consult 段不入(其角色语义 = 父发起的一次性会诊,父在其 settle 前不期望中途对话)。
|
|
166
|
-
: engChildRole === "eng-coder" ? [parentChannelTool, advisorTool, verifyTool,
|
|
167
|
-
: engChildRole === "eng-designer" ? [parentChannelTool,
|
|
171
|
+
: engChildRole === "eng-coder" ? [parentChannelTool, advisorTool, verifyTool, batchTool(batchDoc), ...(engChildSubagent ? [engChildSubagent] : [])]
|
|
172
|
+
: engChildRole === "eng-designer" ? [parentChannelTool, batchTool(batchDoc), ...(engChildSubagent ? [engChildSubagent] : [])]
|
|
168
173
|
: role === "coder" ? [parentChannelTool, verifyTool, advisorTool]
|
|
169
174
|
: role === "consult" ? [recentChangesTool]
|
|
170
175
|
: [parentChannelTool]
|
|
171
176
|
|
|
172
|
-
//
|
|
173
|
-
|
|
177
|
+
// 固定段(装配序 = agent.tools → 固定段 → 家族段 → extraTools):timer 全模式全深度;
|
|
178
|
+
// plan 随模式位——ENG-PLAN-EXCLUSION(FR31 ① · KD8 卸载而非「注册 + 报错」· KD11 全深度两端);
|
|
179
|
+
// task 随模式位——F10(task 工程模式机械停用;同 KD8 处置:**不入表**——模型不可见、零 token 税;
|
|
180
|
+
// execute 层另有机械拒兜底,见 `agent-tools/task.mjs`)。
|
|
181
|
+
// 工程模式固定段 = plan / task 皆**不入表**;普通模式固定段逐字不变(FR31 边界 / F10 边界)。
|
|
182
|
+
// 判据 = 单一模式位 `engineering`(不带深度分支——子代理面随同排除,role enum
|
|
183
|
+
// `:44-49` + spawn 门 / task execute 门已同向)。
|
|
184
|
+
return engineering
|
|
185
|
+
? [timerTool, ...depthOnly]
|
|
186
|
+
: [taskTool, planTool, timerTool, ...depthOnly]
|
|
174
187
|
}
|
package/agent/helpers.mjs
CHANGED
|
@@ -386,13 +386,22 @@ export const ENG_OFF_REMINDER =
|
|
|
386
386
|
"Changes go through the normal workflow: you may edit files directly, advisor/verify " +
|
|
387
387
|
"guards apply per config.]"
|
|
388
388
|
|
|
389
|
-
/** Manual-tier auto-turn digest domain (
|
|
389
|
+
/** Manual-tier auto-turn digest domain (normal-mode base — engineering variant =
|
|
390
|
+
* AUTO_TURN_DIGEST_DOMAIN_ENG below): organize-only. Mechanism = AGENT-LOOP-ASYNC-POOL.md §6.8;
|
|
391
|
+
* mode variant text = TOOLS.md §6.15.3.
|
|
390
392
|
* Injected per manual auto-turn run — writes/execute/spawns/questions are also
|
|
391
393
|
* mechanically denied (no permission handler + spawn gate); this steers first. */
|
|
392
394
|
export const AUTO_TURN_DIGEST_DOMAIN =
|
|
393
395
|
"[System reminder: auto-turn — background async subagents finished while there was no user message, and this turn runs automatically to digest their reports (the finished-report reminders above). No one is waiting for this reply, so organize only: 1) summarize each finished report's key points into this conversation for the user to read later; 2) update the task list with the task tool (allowed) to mark finished work done; 3) write decision points with a suggested next step as text — do not execute it. FORBIDDEN this turn (mechanically enforced): modifying files, bash/execute/verify, spawning subagents, asking questions — those need a real user message. End the turn once the summaries are written.]"
|
|
394
396
|
|
|
395
|
-
/**
|
|
397
|
+
/** Engineering-mode auto-turn digest domain variant (mode = `agent.config.agent.engineering`;
|
|
398
|
+
* clause 2 drops the task-tool pointer — F10: the task tool is disabled in engineering mode,
|
|
399
|
+
* the batch record + ledger are the tracking authority). Single line, verbatim from the
|
|
400
|
+
* design doc (TOOLS.md §6.15.3); mechanism = AGENT-LOOP-ASYNC-POOL.md §6.8. Content authority = parent side. */
|
|
401
|
+
export const AUTO_TURN_DIGEST_DOMAIN_ENG =
|
|
402
|
+
"[System reminder: auto-turn — background async subagents finished while there was no user message, and this turn runs automatically to digest their reports (the finished-report reminders above). No one is waiting for this reply, so organize only: 1) summarize each finished report's key points into this conversation for the user to read later; 2) (engineering mode: the task tool is disabled — no task-list update is expected this turn; the batch record + ledger are the tracking authority and are updated in real user turns); 3) write decision points with a suggested next step as text — do not execute it. FORBIDDEN this turn (mechanically enforced): modifying files, bash/execute/verify, spawning subagents, asking questions — those need a real user message. End the turn once the summaries are written.]"
|
|
403
|
+
|
|
404
|
+
/** Up-stream wake-turn domain (AGENT-LOOP-UPSTREAM.md §6.27.12.8): a running subagent sent
|
|
396
405
|
* an in-flight message and is waiting for the reply — the digest domain's "No one is waiting
|
|
397
406
|
* for this reply" is the opposite of the truth, so the wake turn gets its own text.
|
|
398
407
|
* Verbatim from the design doc (single line — no newlines). Content authority = parent side. */
|
package/agent/run-stages.mjs
CHANGED
|
@@ -11,10 +11,10 @@ import { compressIfNeeded, compressFallback, COMPRESS_FAILURE_LIMIT } from "../c
|
|
|
11
11
|
import { ensureAutoReminder, injectEngineeringReminder, ContinueError, snapshotGuard } from "./helpers.mjs"
|
|
12
12
|
import { pushManifestStateReminder } from "./setup-reminders.mjs"
|
|
13
13
|
import { cleanupConsultSessions } from "../agent-tools/consult.mjs"
|
|
14
|
-
import { logEvent } from "../log.mjs"
|
|
14
|
+
import { logEvent, errText } from "../log.mjs"
|
|
15
15
|
// ASYNC-RESULT-CONTAINER.md D1:池 accessor(absorb 双池——advisor 独立池无队列)
|
|
16
16
|
import { getAsyncPool, releaseSettledEntry } from "../agent-tools/async-settle.mjs"
|
|
17
|
-
// 批 4 CLI-ASYNC-DISCARD(AGENT-LOOP-
|
|
17
|
+
// 批 4 CLI-ASYNC-DISCARD(AGENT-LOOP-ASYNC-POOL.md §6.20):中止分支「只清已死」收尾单点
|
|
18
18
|
import { discardAbortedPool, discardAbortedAdvisors } from "../agent-tools/async-discard.mjs"
|
|
19
19
|
// R10 L3 (MULTI-INSTANCE-COLLAB §2a.5 D-L3a):回合末域登记 flush(写工具钩子累积 →
|
|
20
20
|
// 整写一次本实例 peers 文件——无写入跳过;失败容忍不抛)
|
|
@@ -59,11 +59,28 @@ export function injectResponseReminders(agent, response) {
|
|
|
59
59
|
* 计数复位(recentCallSigs——runAgent 回合级局部——经 ctx 传对象引用)/压缩完成事件
|
|
60
60
|
* /AUTO 提醒重注入。失败:AbortError 透传;计数 + Q3 onCompressFail;
|
|
61
61
|
* COMPRESS_FAILURE_LIMIT 连续失败降级 compressFallback(确定性截断——不发 LLM)。
|
|
62
|
+
* 模型主动压缩(`context` 工具)由本点消费(§6.16.2——取用即清槽;no-op 与失败各落一行注记)。
|
|
62
63
|
*/
|
|
63
64
|
export async function runCompactionCheck(agent, ctx) {
|
|
64
65
|
const { threshold, callbacks, compactionOverhead, signal, recentCallSigs } = ctx
|
|
66
|
+
// F-CC2(CONTEXT-COMPACTION.md §6.16.2):模型主动压缩(`context` 工具)在**本安全点**消费——
|
|
67
|
+
// 取用即清槽(失败不重放;重发由模型再调);`force` 只跳过阈值早退(模型判定优先于阈值),
|
|
68
|
+
// 其余全同(同 splitHistory / 同尾部预算 / 同摘要链 / 同回注 / 同基线失效)。
|
|
69
|
+
const pending = agent._pendingCompact
|
|
70
|
+
agent._pendingCompact = null
|
|
65
71
|
try {
|
|
66
|
-
|
|
72
|
+
let compacted = await compressIfNeeded(
|
|
73
|
+
agent, threshold, callbacks,
|
|
74
|
+
pending ? { ...compactionOverhead, force: true, focus: pending.focus } : compactionOverhead,
|
|
75
|
+
signal,
|
|
76
|
+
)
|
|
77
|
+
if (!compacted && pending) {
|
|
78
|
+
// 强制面无可压(短历史无中段)⇒ 记 no-op 注记后**照常**跑阈值面(阈值面不因模型请求让位)
|
|
79
|
+
const { compactNoopNote } = await import("../agent-tools/context.mjs")
|
|
80
|
+
agent.history.push({ role: "user", content: compactNoopNote(), transient: true })
|
|
81
|
+
compacted = await compressIfNeeded(agent, threshold, callbacks, compactionOverhead, signal)
|
|
82
|
+
}
|
|
83
|
+
if (compacted) {
|
|
67
84
|
agent._compressFailures = 0
|
|
68
85
|
agent._planReminderAtLen = 0 // After compression history shrinks, reset cadence so reminders resume
|
|
69
86
|
recentCallSigs.length = 0 // After compression history is rebuilt, reset stall detection counter
|
|
@@ -79,6 +96,11 @@ export async function runCompactionCheck(agent, ctx) {
|
|
|
79
96
|
// Q3 (CONTEXT-COMPACTION §7 D-C1): a failed compression is surfaced to the panel;
|
|
80
97
|
// COMPRESS_FAILURE_LIMIT consecutive failures still degrade to compressFallback.
|
|
81
98
|
callbacks?.onCompressFail?.(compressError)
|
|
99
|
+
if (pending) {
|
|
100
|
+
// 失败注记(§6.16.2 回执面②):模型面告知缺口——既有失败链 / 面板面零改,仅补一行机器注记
|
|
101
|
+
const { compactFailureNote } = await import("../agent-tools/context.mjs")
|
|
102
|
+
agent.history.push({ role: "user", content: compactFailureNote(errText(compressError), agent._compressFailures), transient: true })
|
|
103
|
+
}
|
|
82
104
|
if (agent._compressFailures >= COMPRESS_FAILURE_LIMIT) {
|
|
83
105
|
agent._compressFailures = 0
|
|
84
106
|
if (compressFallback(agent)) callbacks.onCompress?.(agent._lastCompressInfo ?? {})
|
|
@@ -151,7 +173,7 @@ export async function finalizeAgentTurn(agent, ctx) {
|
|
|
151
173
|
// driver aborts them on its own abort unwind.
|
|
152
174
|
// Async subagent turn-end handling (AGENT-LOOP.md §15 D-A3 + §17 D-S1). Lifecycle:
|
|
153
175
|
// - Ctrl+C (plain abort): children were aborted with the parent signal — discard dead
|
|
154
|
-
// entries (tombstone/out-of-pool/notice — AGENT-LOOP-
|
|
176
|
+
// entries (tombstone/out-of-pool/notice — AGENT-LOOP-ASYNC-POOL.md §6.20; no stale
|
|
155
177
|
// errors injected — user explicitly stopped); consultation sessions are cross-turn
|
|
156
178
|
// background work since R17 — the abort branch is the ONLY normal-path place that
|
|
157
179
|
// aborts them (cleanupConsultSessions marks stopped → they never reach the digest).
|
|
@@ -205,7 +227,7 @@ export async function finalizeAgentTurn(agent, ctx) {
|
|
|
205
227
|
}
|
|
206
228
|
|
|
207
229
|
/**
|
|
208
|
-
* Turn-end async subagent collection (AGENT-LOOP.md §
|
|
230
|
+
* Turn-end async subagent collection (AGENT-LOOP-ASYNC-POOL.md §6.8 — D-S1 + suspension supersede):
|
|
209
231
|
* two modes, selected by the caller's driver context (17.5.2/17.5.4 #2):
|
|
210
232
|
* - suspDriven=false (fallback — headless/direct runAgent callers without a
|
|
211
233
|
* suspension driver): inject every entry that SETTLED during this run
|
|
@@ -19,16 +19,20 @@
|
|
|
19
19
|
* pushManifestStateReminder carries the project phase as a self-healing single live line.
|
|
20
20
|
* #34 adds the per-turn value refresh (mtime-gated re-read — §2.6 ③b / KD-M1-17..M1-19):
|
|
21
21
|
* the line always carries the CURRENT on-disk phase, not the assembly-time snapshot.
|
|
22
|
+
* 2026-09-21(#188):**状态选行**(③' `projectView(agent.cwd)` —— KD-M1-26)——`ok` ⇒ 相位行
|
|
23
|
+
* (逐字零改);`no-project` / `ambiguous` ⇒ 报明行;`missing` / `invalid` ⇒ 有既往好值保守沿用、
|
|
24
|
+
* 无 ⇒ 报明行;无锚 ⇒ **零 I/O / 零报明**(KD-M1-27)。报明行构造 = `manifestReportLine` 四态。
|
|
22
25
|
*
|
|
23
26
|
* #113(S1 续轮第二批——VSC 侧并入 ④ 段):`pushInjections`(机器行专用注入——编辑器上下文
|
|
24
27
|
* 等端侧采集内容;同文去重)与 `appendImagePointer`(粘贴图指引——非多模态模型可见报错)
|
|
25
28
|
* 两档并入——内容由端采集 / 传入(核内零端名),核供注入纪律单点。
|
|
26
29
|
*/
|
|
27
30
|
import { statSync } from "node:fs"
|
|
31
|
+
import { resolve } from "node:path"
|
|
28
32
|
import { END } from "../session-slots.mjs"
|
|
29
33
|
import { peerInstances } from "../peer-instances.mjs"
|
|
30
34
|
import { specForModel } from "../config.mjs"
|
|
31
|
-
import { manifestFilePath, readManifest } from "../manifest.mjs"
|
|
35
|
+
import { manifestFilePath, readManifest, projectView } from "../manifest.mjs"
|
|
32
36
|
|
|
33
37
|
/** env-state line builder — pure, unit-testable.
|
|
34
38
|
* §6.11(F1):slot 字段入行——位置在 model 后 resumed 前(N3:无绑定 → 显式 null——
|
|
@@ -71,6 +75,39 @@ export function manifestStateLine({ phase }) {
|
|
|
71
75
|
return `${MANIFEST_LINE_PREFIX}phase: ${phase}${discipline ? ` (discipline: ${discipline})` : ""}.]`
|
|
72
76
|
}
|
|
73
77
|
|
|
78
|
+
/**
|
|
79
|
+
* 报明行构造 — pure, unit-testable(**本批新增**——`docs/core/design/MANIFEST.md` §2.6 条 1b /
|
|
80
|
+
* KD-M1-26):`projectView` 四非 ok 态各自的行文,**逐字**(同族前缀 `MANIFEST_LINE_PREFIX`——
|
|
81
|
+
* 报明行与相位行共用单活体机制)。歧义行按 `matched` **两变体**(`manifest` = 带档级「marker
|
|
82
|
+
* directories」/ `git` = 裸仓档「repositories … (none carries …)」——同口径 = `TOOLS.md` §6.13 A22);
|
|
83
|
+
* `candidates` 按名排序(判据同 `discoverProjects`)、`<abs…>` 以「、」连接;`errors` 逐条以「;」连接。
|
|
84
|
+
* `ok` / 未知态 ⇒ `null`(无报明行——相位行归 `manifestStateLine`)。
|
|
85
|
+
* @param {{state?:string, cwd?:string, root?:string|null, path?:string|null, candidates?:string[], errors?:string[], matched?:string|null}} p 行素材(= `projectView` 返回面 + 锚)
|
|
86
|
+
* @returns {string|null} 行文 / null(非报明态)
|
|
87
|
+
*/
|
|
88
|
+
export function manifestReportLine({ state, cwd, root, path, candidates, errors, matched } = {}) {
|
|
89
|
+
if (state === "no-project") {
|
|
90
|
+
return `${MANIFEST_LINE_PREFIX}none — no project at ${cwd} (no manifest on the ancestor chain, none below). ` +
|
|
91
|
+
`Parameters fall back to defaults. Create PROJECT-MANIFEST.json here to land a project (git optional).]`
|
|
92
|
+
}
|
|
93
|
+
if (state === "ambiguous") {
|
|
94
|
+
const list = candidates ?? []
|
|
95
|
+
const head = matched === "git"
|
|
96
|
+
? `ambiguous — ${list.length} candidate repositories under ${cwd} (none carries PROJECT-MANIFEST.json):`
|
|
97
|
+
: `ambiguous — ${list.length} candidate marker directories under ${cwd}:`
|
|
98
|
+
return `${MANIFEST_LINE_PREFIX}${head} ${list.join("、")} — target the intended one explicitly (the mechanism never picks).]`
|
|
99
|
+
}
|
|
100
|
+
if (state === "missing") {
|
|
101
|
+
return `${MANIFEST_LINE_PREFIX}missing — the resolved project root ${root} has no PROJECT-MANIFEST.json; ` +
|
|
102
|
+
`project parameters fall back to defaults until the file is generated.]`
|
|
103
|
+
}
|
|
104
|
+
if (state === "invalid") {
|
|
105
|
+
return `${MANIFEST_LINE_PREFIX}invalid — ${path} is not a usable declaration: ${(errors ?? []).join(";")}; ` +
|
|
106
|
+
`project parameters fall back to defaults until fixed.]`
|
|
107
|
+
}
|
|
108
|
+
return null // ok / 未知态——无报明行(相位行归 manifestStateLine)
|
|
109
|
+
}
|
|
110
|
+
|
|
74
111
|
/**
|
|
75
112
|
* ③b 取值前置步(#34——`docs/core/design/MANIFEST.md` §2.6 条 3 · KD-M1-17–M1-19):数据档
|
|
76
113
|
* mtime 门控重读——盘上 mtime ≠ `agent._manifestMtime`(含缓存未设 = 首次观测)⇒ `readManifest`
|
|
@@ -79,7 +116,7 @@ export function manifestStateLine({ phase }) {
|
|
|
79
116
|
* 沿用上次已知好值,缓存不推进(⇒ 下回合重试,自愈)。路径 = `manifestFilePath(agent.cwd)`
|
|
80
117
|
* (项目根解析与读点同源——KD-M1-18,非「锚目录 + 档名」);缓存载体 = `agent._manifestMtime`
|
|
81
118
|
* (per-agent——KD-M1-19,同族先例 `agent._slotMtime`)。本步失败只降级注入面(运行期),
|
|
82
|
-
*
|
|
119
|
+
* 与**会话起点动作**两分——见 §2.5「运行期失败退化 vs 会话起点动作」(本批收正条名)。
|
|
83
120
|
* @param {object} agent 主 agent(`agent.cwd` / `agent.manifest`)
|
|
84
121
|
*/
|
|
85
122
|
function refreshManifest(agent) {
|
|
@@ -104,26 +141,45 @@ function refreshManifest(agent) {
|
|
|
104
141
|
|
|
105
142
|
/**
|
|
106
143
|
* 情境行注入(#28——`docs/core/design/MANIFEST.md` §2.6 模块契约):manifest 的
|
|
107
|
-
* `phase` 逐回合进模型上下文(判据序 ①–⑥ + 取值前置步 ③b = §2.6 表;#34
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
* 压缩面零触碰)。`transient:true` ⇒ 不进人读线(`_fullHistory`)。
|
|
111
|
-
* @param {object} agent 主 agent(`agent.manifest` / `agent.history` / `agent.cwd`——③b
|
|
144
|
+
* `phase` 逐回合进模型上下文(判据序 ①–⑥ + 取值前置步 ③b = §2.6 表;#34 起值变由盘面驱动;
|
|
145
|
+
* 本批 + ③' 状态选行 / 报明行入口)。**自愈单活体**——同文活体在 → 幂等(零历史变更);值变 →
|
|
146
|
+
* 就地摘旧行 + 落新行(保 `history` 数组引用);压缩 / 会话重建吞行 → 下一回合重推(不落 system
|
|
147
|
+
* 槽——架构 E5.1 #5,`context.mjs` 压缩面零触碰)。`transient:true` ⇒ 不进人读线(`_fullHistory`)。
|
|
148
|
+
* @param {object} agent 主 agent(`agent.manifest` / `agent.history` / `agent.cwd`——③'/③b)
|
|
112
149
|
* @param {{depth?: number}} [opts] 注入深度(仅 depth-0)
|
|
113
150
|
* @returns {boolean} 是否落新行(测试断言用)
|
|
114
151
|
*/
|
|
115
152
|
export function pushManifestStateReminder(agent, { depth = 0 } = {}) {
|
|
116
153
|
if (depth !== 0) return false // ① 仅 depth-0(子代理读任务书——架构 §2.4 M5 零 manifest 读面)
|
|
117
154
|
if (agent.config?.agent?.engineering !== true) return false // ② 模式门:仅工程模式
|
|
118
|
-
|
|
119
|
-
|
|
155
|
+
let line
|
|
156
|
+
if (!agent.cwd) {
|
|
157
|
+
// ③ 无锚门(KD-M1-27——**零 I/O / 零报明**):状态无从解析 ⇒ 沿用内存值(有 ⇒ 相位行;
|
|
158
|
+
// 无既往好值 ⇒ 零注入)。既有无 cwd 夹具用例零改(§2.6 条 3 边界同源)。
|
|
159
|
+
if (!agent.manifest) return false
|
|
160
|
+
line = manifestStateLine({ phase: agent.manifest.phase })
|
|
161
|
+
} else {
|
|
162
|
+
// ③' 状态选行(KD-M1-26——**每回合实读**,成本两轴见 §2.6 条 3):projectView 五态 ⇒ 选行。
|
|
163
|
+
const view = projectView(agent.cwd)
|
|
164
|
+
refreshManifest(agent) // ③b 取值前置步(#34):mtime 门控重读——相位行须取刷新后的值
|
|
165
|
+
if (view.state === "ok") {
|
|
166
|
+
const phase = (agent.manifest ?? view.manifest)?.phase
|
|
167
|
+
line = phase === undefined ? null : manifestStateLine({ phase })
|
|
168
|
+
} else if (view.state === "no-project" || view.state === "ambiguous") {
|
|
169
|
+
line = manifestReportLine({ ...view, cwd: resolve(agent.cwd) }) // 本批新报明格(无项目 / 歧义)
|
|
170
|
+
} else if (agent.manifest) {
|
|
171
|
+
line = manifestStateLine({ phase: agent.manifest.phase }) // missing / invalid:有既往好值 ⇒ 保守沿用
|
|
172
|
+
} else {
|
|
173
|
+
line = manifestReportLine({ ...view, cwd: resolve(agent.cwd) }) // 首观即失败 ⇒ 至少可见一次(KD-M1-26)
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
if (!line) return false
|
|
120
177
|
const history = agent.history
|
|
121
|
-
const line = manifestStateLine({ phase: agent.manifest.phase })
|
|
122
178
|
// ④ 同文 user 行已在(活体)→ 幂等——零历史变更(同文口径 = pushInjections 的 history.some)
|
|
123
179
|
if (history.some((m) => m.content === line)) return false
|
|
124
180
|
// ⑤ 值已变 → 就地 splice 摘旧行(`role === "user"` 全匹配),保 history 数组引用。会话重建后
|
|
125
181
|
// `_manifestLine` 不随历史回来 → 先按行族前缀从 history 认领现存活体(否则旧行残留 +
|
|
126
|
-
// 新行入列 = 双活体,违 §2.6
|
|
182
|
+
// 新行入列 = 双活体,违 §2.6 定案「单活体」)。相位行 ↔ 报明行**同族前缀**⇒ 互相换位同机制。
|
|
127
183
|
let old = agent._manifestLine
|
|
128
184
|
if (!old) {
|
|
129
185
|
for (const m of history) {
|
package/agent/setup.mjs
CHANGED
|
@@ -212,6 +212,12 @@ export async function prepareRun(agent, input, callbacks, {
|
|
|
212
212
|
// let——下方按 projectRules / skills listing 尾部追加(L326/L331 +=)再赋值;
|
|
213
213
|
// const 声明会 TypeError: Assignment to constant variable(每次 run 必炸)。
|
|
214
214
|
let systemPrompt = base
|
|
215
|
+
// 派单固块(台账 #23 · AGENT-LOOP-SUBAGENT.md §6.26):spawn 级固定的机制性指令(批次档路径行 /
|
|
216
|
+
// 审计模板)随 system 面下发——固块值在 child 生命周期内恒定 ⇒ run 内前缀逐字节稳定(前缀缓存
|
|
217
|
+
// 不破),且不在 `agent.history` 内 ⇒ 压缩只重建 history(吞不掉)。拼接位 = 槽位装配之后、
|
|
218
|
+
// 项目指令之前;`_spawnSystemBlock` 为 null/undefined ⇒ 分支不进(depth-0 / explore / plan /
|
|
219
|
+
// consult 的 system 逐字节同改前)。
|
|
220
|
+
if (agent._spawnSystemBlock) systemPrompt += `\n\n${agent._spawnSystemBlock}`
|
|
215
221
|
|
|
216
222
|
// Time injection deliberately does NOT live here: system prompts must be byte-identical
|
|
217
223
|
// across runs (provider prefix caches). The time rides a transient user reminder per turn
|
package/agent/write-gate.mjs
CHANGED
|
@@ -10,9 +10,9 @@
|
|
|
10
10
|
* 展开走 `docRootPaths`)。缺 `docRoot` 键 → `readManifest`
|
|
11
11
|
* 的 fillDefaults 已补默认(架构 §2.3 E2 便利 fallback 落点);整档缺失 / 非法 JSON →
|
|
12
12
|
* `{ok:false}` → 回退 DEFAULT_MANIFEST.docRoot(本函数是壳门之下的便利层——E2 的
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* setup.mjs
|
|
13
|
+
* 「整档缺失」由壳面 requireManifest 按用点处置(判 + 报明 / 建档,**不抛**——
|
|
14
|
+
* 启动侧恒不拒,KD-M1-25;**工程模式会话**口径——普通会话装配钩子零 manifest I/O,
|
|
15
|
+
* KD-M1-12):CLI make-agent.mjs / VSC setup.mjs 同判);读错(权限等)→ 上抛不伪装成缺失(manifest.mjs 契约)。
|
|
16
16
|
* M6 的 `advisor.mjs` design-review 分类分支消费本导出
|
|
17
17
|
* (KD-M6-1——同源不重复实现;落 dispatch.mjs 会让 advisor 反向 import 门禁簇成环)。
|
|
18
18
|
* 2. `freezeWindowConflict(agent, absPaths)` —— D5 冻结窗口判据组装:被审文件集 =
|
|
@@ -37,8 +37,8 @@ const REVIEW_ROOT_KEYS = ["requirements", "specs", "design", "modules", "batches
|
|
|
37
37
|
* 评审目标解析单点(M4 §2.1#1):读 manifest `docRoot` → 评审对象 / 被审文件的绝对路径
|
|
38
38
|
* 集合(目录级,反斜杠归一;子键值形态 = 串 | 多根数组,逐键经 `docRootPaths` 展开)。
|
|
39
39
|
* 缺 `docRoot` 键 → readManifest 已补默认;整档缺失 / 非法 →
|
|
40
|
-
* `{ok:false}` → 回退 DEFAULT_MANIFEST.docRoot(便利层——E2
|
|
41
|
-
* requireManifest
|
|
40
|
+
* `{ok:false}` → 回退 DEFAULT_MANIFEST.docRoot(便利层——E2 的「整档缺失」由壳面
|
|
41
|
+
* requireManifest 按用点处置(判 + 报明 / 建档,**不抛**——启动侧恒不拒,KD-M1-25;**工程模式会话**口径——KD-M1-12),本函数不重复拦);
|
|
42
42
|
* 读错(权限等)→ 上抛 fail-closed。
|
|
43
43
|
* @param {Object} agent
|
|
44
44
|
* @returns {string[]} 评审目标目录的绝对路径(去重)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* advisor-async.mjs — async advisor reviews (AGENT-LOOP-
|
|
2
|
+
* advisor-async.mjs — async advisor reviews (AGENT-LOOP-ASYNC-POOL.md §6.10 — R13, 2026-09-06).
|
|
3
3
|
*
|
|
4
4
|
* The advisor tool runs reviews in a background pool at depth 0 (default async —
|
|
5
5
|
* ruling ②-3 A): the launch returns an ack, the turn ends naturally, the session
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
* 3. the async pool (agent._asyncAdvisors — ADVISOR_POOL_LIMIT = 4 default,
|
|
21
21
|
* agent.poolLimits.advisor configurable — POOL-CONFIG-UNIFIED; same-scope
|
|
22
22
|
* running launches are refused at once — never queued (F-5); over-limit +
|
|
23
|
-
* DIFFERENT scope launches QUEUE (ED-4 2026-09-16 — AGENT-LOOP-
|
|
23
|
+
* DIFFERENT scope launches QUEUE (ED-4 2026-09-16 — AGENT-LOOP-ASYNC-POOL.md §6.10:
|
|
24
24
|
* agent._asyncAdvisorQueue, ack {queued, position}, slot release auto-start,
|
|
25
25
|
* queued cancel dequeue+renumber — the former over-limit refusal ②-6a is
|
|
26
26
|
* retired); cancel (ruling ②-6b — directed abort → cancelled settle: no
|
|
@@ -280,7 +280,7 @@ function relayAdvisorOutput(callbacks, prefix, chunk) {
|
|
|
280
280
|
}
|
|
281
281
|
}
|
|
282
282
|
|
|
283
|
-
// ─── ED-4(2026-09-16 · AGENT-LOOP-
|
|
283
|
+
// ─── ED-4(2026-09-16 · AGENT-LOOP-ASYNC-POOL.md §6.10):评审池排队(槽释放自动起跑)────────
|
|
284
284
|
|
|
285
285
|
/** 排队出队单点(ED-4):`_asyncAdvisorQueue` 剔除目标条目 + 余项 position 按 `1..n`
|
|
286
286
|
* 重编号;读面经**载体吸收**(`carrierField`——#21⑤b):部分 parent(只携池 + `history`)
|
|
@@ -368,7 +368,7 @@ export function launchAsyncAdvisor(parent, ctx, launch) {
|
|
|
368
368
|
const idFields = { type: reviewType, scope: scopeSummary(documents?.length ? documents : paths), round: `${(run?.round ?? 0) + 1}/uncapped`, criterion: "scope-in-flight" }
|
|
369
369
|
return { error: withIdentityLine(`Advisor: 此 scope 已有评审在跑——settle 后逐个发起 — ${scopeNote}; round/prior continuation would be ambiguous while it is in flight — wait for it to settle, then launch the next review.`, idFields) }
|
|
370
370
|
}
|
|
371
|
-
// ED-4(AGENT-LOOP-
|
|
371
|
+
// ED-4(AGENT-LOOP-ASYNC-POOL.md §6.10):池满 + 异 scope ⇒ 排队(非拒)——ack 含 queued +
|
|
372
372
|
// position;running 计数只算 running 条目(排队不占槽)。原 ②-6a 拒发退役。
|
|
373
373
|
const queued = runningAdvisorCount(parent) >= limit
|
|
374
374
|
parent._asyncAdvisors ??= new Map()
|