Merge remote-tracking branch 'origin/master' into xtr/react-loop-simplification

# Conflicts:
#	.agents/notes/implemented/architecture/2026-07-22-unified-send-and-coalesced-user-messages.i18n.yaml
#	.agents/notes/implemented/architecture/2026-07-22-unified-send-and-coalesced-user-messages.md
#	.agents/notes/implemented/architecture/2026-07-22-unified-send-and-coalesced-user-messages.zh.md
#	.agents/notes/implemented/feature/2026-07-21-tui-skill-slash-command.i18n.yaml
#	.agents/notes/implemented/feature/2026-07-21-tui-skill-slash-command.md
#	.agents/notes/implemented/feature/2026-07-21-tui-skill-slash-command.zh.md
#	.agents/notes/implemented/simplification/2026-07-17-one-send-one-turn.i18n.yaml
#	.agents/notes/implemented/simplification/2026-07-17-one-send-one-turn.md
#	.agents/notes/implemented/simplification/2026-07-17-one-send-one-turn.zh.md
#	docs/architecture.i18n.yaml
#	docs/cordis-catalog/events.md
#	docs/cordis-catalog/services.md
#	docs/core-data-structures/core.i18n.yaml
#	docs/core-data-structures/core.md
#	docs/core-data-structures/core.zh.md
#	docs/defensive-patterns.i18n.yaml
#	packages/client/runtime/src/client/sessions/session.ts
#	packages/client/runtime/tests/queue-store.spec.ts
#	packages/context/time-context/tests/time-context.spec.ts
#	packages/context/workspace-context/tests/workspace-context.spec.ts
#	packages/cordis/tool-cordis/src/api-catalog.ts
#	packages/core/agent-loop/README.i18n.yaml
#	packages/core/agent-loop/README.md
#	packages/core/agent-loop/README.zh.md
#	packages/core/agent-loop/src/agent.ts
#	packages/core/agent/README.i18n.yaml
#	packages/core/agent/README.md
#	packages/core/agent/README.zh.md
#	packages/core/agent/src/types.ts
#	packages/core/agent/tests/agent.spec.ts
#	packages/core/scope/src/scoped-events.generated.ts
#	packages/goal/command-goal/tests/command-goal.spec.ts
#	packages/goal/goal-session/src/index.ts
#	packages/goal/goal-session/tests/goal-session.spec.ts
#	packages/goal/goal/tests/goal.spec.ts
#	packages/goal/goal/tests/projection.spec.ts
#	packages/goal/tool-goal/tests/tool-goal.spec.ts
#	packages/host/apiproxy/src/api-proxy.ts
#	packages/host/apiproxy/src/api/events.schema.ts
#	packages/host/apiproxy/src/api/events.ts
#	packages/host/apiproxy/tests/api-proxy-workspace.spec.ts
#	packages/llm/llm/README.i18n.yaml
#	packages/llm/llm/README.zh.md
#	packages/llm/llm/src/index.ts
#	packages/pty/pty-local/tests/index.spec.ts
#	packages/pty/pty-local/tests/local.spec.ts
#	packages/pty/pty/tests/service.spec.ts
#	packages/pty/tool-pty/tests/loader-composition.spec.ts
#	packages/pty/tool-pty/tests/tools.spec.ts
#	packages/skill/tool-skill/tests/tool-skill.spec.ts
#	packages/tasks/tasks-local/tests/tasks.spec.ts
#	packages/ui/tui/src/index.ts
#	packages/ui/tui/tests/harness.ts
#	packages/ui/tui/tests/tui.spec.ts
#	scripts/gen-cordis-catalog.ts
#	scripts/type-equiv.manifest.json
This commit is contained in:
_Kerman
2026-07-30 14:04:53 +08:00
1175 changed files with 49683 additions and 8452 deletions
@@ -1,6 +1,6 @@
# Bilingual-pair consistency record (docs/i18n/README.md): the git blob hash of each
# side as of the last confirmed-consistent state. Both languages carry equal authority;
# after editing either side, bring the other along and re-record with:
# pnpm run verify-translation-pairing --write
# pnpm run verify-translation-pairing --write packages/compact/compact-tool-result-prune/README.md
README.md: edeba52b189b3cee5530faf7efc04043a326917f
README.zh.md: fa471c0817cc937162b386cd3d249ce5ecd8c3ff
README.zh.md: 1b42a9db5d3288c6610e431c57403858a238c07a
@@ -2,31 +2,31 @@
[English](README.md) | 中文
可安全回放、不依赖模型的剪枝服务(`ctx.toolResultPrune`)。它会将超出预算的 `tool/result` 表层节点改写为有界头部、固定省略标记和有界尾部,同时在仅追加会话日志中保留完整原始事件。
可安全回放、不依赖模型的剪枝服务(`ctx.toolResultPrune`)。它会将超出预算的 `tool/result` 表层节点改写为长度受限的头部、固定省略标记和长度受限的尾部,同时在仅追加会话日志中保留完整原始事件。
这是 [`dsh-compact-basic`](../compact-basic/README.md) 的具体配套服务,不是压缩后端或面向模型的工具。Compact-basic 通过可选的 `ctx.get('toolResultPrune')` 读取它,因此两个包都保持可独立组合。
这是 [`dsh-compact-basic`](../compact-basic/README.md) 的具体配套服务,不是压缩compaction后端或面向模型的工具。Compact-basic 通过可选的 `ctx.get('toolResultPrune')` 读取它,因此两个包package)仍可各自独立组合。
## 服务 API
`pruneSession(session)` 会扫描当前表层的一个稳定快照。每个超出预算的工具结果都会被一个新追加的 `tool/result` 替换,其携带 `{ surfaceOp: { op: 'replace', start: originalSeq, end: originalSeq }, sourceEventSeqs: [originalSeq] }`。替换会展开完整原始数据,只更改 `content`,保留 `turn``step``callId`、错误字段、`meta` 以及后续添加的数据。原始事件仍可用于持久化、回放和精确日志检查。
`pruneSession(session)` 会扫描当前表层的一个稳定快照。每个超出预算的工具结果都会被一个新追加的 `tool/result` 替换,其携带 `{ surfaceOp: { op: 'replace', start: originalSeq, end: originalSeq }, sourceEventSeqs: [originalSeq] }`。替换会展开完整原始数据,只更改 `content`,保留 `turn``step``callId`、错误字段、`meta` 以及以后新增的数据字段。原始事件仍可用于持久化、回放和精确日志检查。
当会话拒绝替换时,该方法会同步抛出异常。本次 pass 中较早提交的替换仍然持久
当会话拒绝替换时,该方法会同步抛出异常。本次扫描中先前已提交的替换仍会保留
`measureContent(blocks)` 会统计 `text` 块中的 Unicode 码点。`pruneContent(blocks)` 会返回有界替换;如果内容已在阈值内,则返回 `null`。非文本块保持原始相对位置;文本切片绝不会拆分 UTF-16 surrogate pair,但可能拆分由多个码点组成的 grapheme cluster
`measureContent(blocks)` 会统计 `text` 块中的 Unicode 码点。`pruneContent(blocks)` 会返回长度受限的替换;如果内容已在阈值内,则返回 `null`。非文本块保持原始相对位置;文本切片绝不会拆分 UTF-16 代理项对,但可能拆分由多个码点组成的字素簇
每个发出的结果在文本码点上都精确包含已配置的头部预算、固定标记和尾部预算,不大于 `thresholdChars`,且严格小于触发输入。因此第二次 pass 不会发出替换。
每个发出的结果在文本码点上都精确包含已配置的头部预算、固定标记和尾部预算,不大于 `thresholdChars`,且严格小于触发输入。因此第二次扫描不会发出替换。
## 配置
无法识别的 key 会使插件在构造时失败。已解析配置与输入脱离,并且深度不可变。
无法识别的配置键会使插件在构造时失败。已解析配置与输入脱离,并且深度不可变。
| Key | 必填 | 含义 |
| 配置键 | 必填 | 含义 |
|---|---|---|
| `thresholdChars` | 否(默认 `8192`) | 合并文本超过此 Unicode 码点数时剪枝。 |
| `headChars` | 否(默认 `4096`) | 保留的开头 Unicode 码点数。 |
| `tailChars` | 否(默认 `1024`) | 保留的末尾 Unicode 码点数。 |
所有值都必须是整数;阈值必须为正数,头部/尾部必须为非负数。`headChars + marker + tailChars` 必须能容纳在 `thresholdChars`,因此有效配置可以剪枝每个超出预算的结果,不会增长或重复改写。
所有值都必须是整数;阈值必须为正数,头部/尾部必须为非负数。`headChars + marker + tailChars` 之和不得超过 `thresholdChars`,因此有效配置可以剪枝每个超出预算的结果,不会增长或重复改写。
## 用法
@@ -45,7 +45,7 @@ export function apply(ctx: Context): void {
#### 模型看到的内容
一旦压缩触发器成立,后续请求看到保留的头部、`\n\n[... tool result middle pruned ...]\n\n` 和保留的尾部,用它们替换已移除文本。富内容块保持顺序。模型不会看到原文的第二份副本。
一旦满足压缩触发条件,后续请求看到的将是保留的头部、`\n\n[... tool result middle pruned ...]\n\n` 和保留的尾部,而非被移除文本。非文本块保持原有顺序。模型不会看到原文的第二份副本。
#### Token 影响
@@ -59,4 +59,4 @@ export function apply(ctx: Context): void {
- **字符预算不是 token 预算**:不同提供方的 token 密度各异,因此 `ctx.tokenMeter` 仍负责判定剪枝是否缓解了请求压力。
- **剪枝只基于语法**:它保留开头与结尾,不解释中间哪些行在语义上重要。
- **Grapheme cluster 可能被拆分**:按码点切片可保护 surrogate pair,但不会执行感知 locale 的 grapheme 分割。
- **字素簇可能被拆分**:按码点切片可保护代理项对,但不会执行感知区域设置的字素簇分割。