evolcore 0.0.25 → 0.0.26
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 +607 -565
- package/LICENSE +21 -21
- package/README.md +455 -455
- package/bin/codex-managed-acl.ps1 +160 -160
- package/bin/codex-managed-hook.mjs +208 -208
- package/bin/ec-safe-output.js +327 -327
- package/bin/ec.js +40 -29
- package/bin/install-codex-managed-hooks.mjs +582 -555
- package/dist/agents/baseagent.js +96 -46
- package/dist/agents/claude-runner.js +50 -12
- package/dist/agents/codex/app-server-client.js +13 -5
- package/dist/agents/codex/catalog.js +1 -1
- package/dist/agents/codex/diagnostics.js +34 -1
- package/dist/agents/codex-runner.js +121 -38
- package/dist/agents/ecagent-runner.js +4 -9
- package/dist/agents/gemini-runner.js +2 -7
- package/dist/agents/runner-types.js +25 -17
- package/dist/aun/aid/agentmd.js +81 -8
- package/dist/aun/aid/client.js +1 -1
- package/dist/aun/aid/identity.js +1 -1
- package/dist/aun/aid/index.js +1 -1
- package/dist/aun/aid/store.js +17 -13
- package/dist/aun/menu-client.js +74 -0
- package/dist/aun/msg/group.js +1 -1
- package/dist/aun/msg/managed-operation.js +1 -1
- package/dist/aun/msg/p2p.js +6 -1
- package/dist/aun/msg/upload.js +30 -22
- package/dist/channels/aun.js +329 -94
- package/dist/cli/agent-command.js +105 -84
- package/dist/cli/agent-create.js +112 -10
- package/dist/cli/agent.js +16 -5
- package/dist/cli/aun-commands.js +297 -296
- package/dist/cli/bench.js +20 -20
- package/dist/cli/config.js +47 -28
- package/dist/cli/contact.js +70 -13
- package/dist/cli/ctl-command.js +22 -22
- package/dist/cli/daemon-commands.js +105 -40
- package/dist/cli/diag.js +31 -0
- package/dist/cli/fs-command.js +67 -67
- package/dist/cli/handoff-command.js +41 -9
- package/dist/cli/index.js +83 -77
- package/dist/cli/link-rules.js +21 -21
- package/dist/cli/managed-command-guard.js +3 -0
- package/dist/cli/menu-client.js +46 -31
- package/dist/cli/net-check.js +22 -22
- package/dist/cli/queue-command.js +29 -29
- package/dist/cli/response.js +30 -30
- package/dist/cli/restart-monitor.js +87 -40
- package/dist/cli/stats.js +51 -51
- package/dist/cli/trigger-command.js +56 -56
- package/dist/config/builtin-roles.js +1 -0
- package/dist/config/config-operation-service.js +145 -0
- package/dist/config/contact-operation-service.js +96 -7
- package/dist/config/resolved-config-op.js +27 -7
- package/dist/core/agent-application-service.js +2 -1
- package/dist/core/auth/authorization-audit.js +20 -12
- package/dist/core/auth/operation-authorizer.js +25 -4
- package/dist/core/auth/operation-catalog.js +35 -4
- package/dist/core/auth/remote-access-store.js +40 -1
- package/dist/core/bootstrap-service.js +1 -1
- package/dist/core/command/command-handler.js +83 -26
- package/dist/core/command/diag-service.js +118 -0
- package/dist/core/command/menu-catalog.js +12 -3
- package/dist/core/command/menu-handler.js +47 -26
- package/dist/core/command/menu-protocol.js +5 -0
- package/dist/core/command/menu-token-store.js +41 -8
- package/dist/core/command/slash-gate.js +34 -4
- package/dist/core/command/slash-handler.js +86 -21
- package/dist/core/handoff/runtime.js +205 -27
- package/dist/core/handoff/store.js +193 -4
- package/dist/core/message/im-renderer.js +72 -21
- package/dist/core/message/message-bridge.js +69 -9
- package/dist/core/message/message-queue.js +26 -0
- package/dist/core/message/message-utils.js +1 -0
- package/dist/core/message/response-engine.js +47 -28
- package/dist/core/model/catalog-service.js +79 -49
- package/dist/core/model/context-window-suffix.js +33 -0
- package/dist/core/model/model-catalog.js +1 -1
- package/dist/core/model/model-permission.js +12 -3
- package/dist/core/permission/ec-command-parser.js +51 -12
- package/dist/core/permission/sandbox-runtime.js +36 -14
- package/dist/core/permission/tool-policy.js +2 -1
- package/dist/index.js +280 -163
- package/dist/ipc.js +54 -2
- package/dist/response-system/engines/v1/proactive-flow.js +59 -2
- package/dist/stats/billing.js +41 -15
- package/dist/stats/db.js +159 -159
- package/dist/stats/eck-vars.js +9 -9
- package/dist/stats/price-resolver.js +28 -10
- package/dist/stats/query.js +139 -139
- package/dist/stats/role-budget.js +6 -6
- package/dist/stats/writer.js +51 -51
- package/dist/utils/cross-platform.js +30 -1
- package/dist/utils/error-dict.json +160 -160
- package/dist/utils/error-utils.js +21 -0
- package/dist/utils/evolcore-version.js +129 -0
- package/dist/utils/logger.js +3 -1
- package/dist/utils/macos-autostart.js +22 -22
- package/dist/utils/model-prices.jsonl +23 -23
- package/dist/utils/npm-ops.js +176 -35
- package/dist/utils/welcome.js +22 -22
- package/ecagent/LICENSE +21 -21
- package/ecagent/NOTICE +11 -11
- package/ecagent/README.md +61 -61
- package/ecagent/dist/harness/compaction/branch-summarization.js +30 -30
- package/ecagent/dist/harness/compaction/compaction.js +83 -83
- package/ecagent/dist/harness/messages.js +7 -7
- package/kits/docs/GUIDE.md +20 -20
- package/kits/docs/INDEX.md +66 -66
- package/kits/docs/aun/CHEATSHEET.md +19 -19
- package/kits/docs/aun/SYNC_PROTOCOL.md +15 -15
- package/kits/docs/channels/aun.md +56 -56
- package/kits/docs/channels/feishu.md +56 -56
- package/kits/docs/context-assembly.md +364 -364
- package/kits/docs/eck_templates/GUIDE.template.md +22 -22
- package/kits/docs/eck_templates/INDEX.template.md +28 -28
- package/kits/docs/eck_templates/path-registry.template.md +33 -33
- package/kits/docs/eck_templates/runtime.template.md +19 -19
- package/kits/docs/evolcore/INDEX.md +71 -71
- package/kits/docs/evolcore/agent-create.md +170 -165
- package/kits/docs/evolcore/agent.md +66 -66
- package/kits/docs/evolcore/aid.md +60 -60
- package/kits/docs/evolcore/codex-windows-sandbox.md +146 -146
- package/kits/docs/evolcore/config.md +202 -195
- package/kits/docs/evolcore/contact.md +75 -68
- package/kits/docs/evolcore/ctl.md +46 -46
- package/kits/docs/evolcore/event.md +216 -216
- package/kits/docs/evolcore/fs-architecture.md +1215 -1215
- package/kits/docs/evolcore/fs.md +110 -110
- package/kits/docs/evolcore/group-collaboration.md +243 -243
- package/kits/docs/evolcore/group-fs.md +17 -17
- package/kits/docs/evolcore/group-rules.md +251 -251
- package/kits/docs/evolcore/group.md +152 -152
- package/kits/docs/evolcore/menu-client.md +42 -34
- package/kits/docs/evolcore/model.md +50 -50
- package/kits/docs/evolcore/msg.md +166 -165
- package/kits/docs/evolcore/response.md +75 -75
- package/kits/docs/evolcore/rpc.md +37 -37
- package/kits/docs/evolcore/self-summary.md +29 -29
- package/kits/docs/evolcore/stats.md +83 -83
- package/kits/docs/evolcore/storage.md +50 -50
- package/kits/docs/evolcore/trigger.md +575 -575
- package/kits/docs/identity/AID_PROFILE_SPEC.md +26 -26
- package/kits/docs/identity/PATH_OPS.md +16 -16
- package/kits/docs/identity/ROLE_DETAIL.md +25 -25
- package/kits/docs/identity/identity-tools.md +26 -26
- package/kits/docs/path-registry.md +62 -62
- package/kits/docs/prompt-loading-architecture.md +269 -269
- package/kits/docs/venues/aun-group.md +45 -45
- package/kits/docs/venues/aun-private.md +10 -10
- package/kits/docs/venues/client-desktop.md +10 -10
- package/kits/docs/venues/client-mobile.md +10 -10
- package/kits/docs/venues/feishu-group.md +13 -13
- package/kits/docs/venues/feishu-private.md +9 -9
- package/kits/docs/venues/group.md +37 -25
- package/kits/docs/venues/private.md +10 -10
- package/kits/eck_manifest.auxiliary.json +43 -43
- package/kits/eck_manifest.json +190 -190
- package/kits/eck_message_manifest.json +74 -74
- package/kits/migrations/README-role-config-v4.md +32 -32
- package/kits/migrations/migrate-contact-book-v2.mjs +748 -748
- package/kits/migrations/migrate-role-config-v4.mjs +614 -614
- package/kits/migrations/migrate-role-config-v5.mjs +365 -365
- package/kits/migrations/rename-config-file.mjs +99 -99
- package/kits/rules/01-overview.md +162 -162
- package/kits/rules/02-navigation.md +96 -96
- package/kits/rules/03-identity.md +36 -36
- package/kits/rules/04-relation.md +75 -75
- package/kits/rules/05-venue.md +60 -60
- package/kits/rules/06-channel.md +63 -63
- package/kits/schemas/_meta.json +53 -53
- package/kits/schemas/agent-config.schema.1.json +177 -177
- package/kits/schemas/agent-config.schema.10.json +395 -395
- package/kits/schemas/agent-config.schema.11.json +421 -421
- package/kits/schemas/agent-config.schema.12.json +427 -427
- package/kits/schemas/agent-config.schema.2.json +239 -239
- package/kits/schemas/agent-config.schema.3.json +119 -119
- package/kits/schemas/agent-config.schema.4.json +208 -208
- package/kits/schemas/agent-config.schema.5.json +326 -326
- package/kits/schemas/agent-config.schema.6.json +322 -322
- package/kits/schemas/agent-config.schema.7.json +303 -303
- package/kits/schemas/agent-config.schema.8.json +304 -304
- package/kits/schemas/agent-config.schema.9.json +364 -364
- package/kits/schemas/contact-book.schema.1.json +36 -36
- package/kits/schemas/contact-book.schema.2.json +43 -43
- package/kits/schemas/contact-book.schema.3.json +67 -67
- package/kits/schemas/daemon.schema.1.json +91 -91
- package/kits/schemas/daemon.schema.2.json +101 -101
- package/kits/schemas/daemon.schema.3.json +123 -123
- package/kits/schemas/daemon.schema.4.json +136 -136
- package/kits/schemas/daemon.schema.5.json +135 -135
- package/kits/schemas/daemon.schema.6.json +131 -131
- package/kits/schemas/defaults.schema.1.json +81 -81
- package/kits/schemas/defaults.schema.2.json +85 -85
- package/kits/schemas/defaults.schema.3.json +73 -73
- package/kits/schemas/defaults.schema.4.json +107 -107
- package/kits/schemas/defaults.schema.5.json +119 -119
- package/kits/schemas/menu-exec-schema-commands.md +208 -208
- package/kits/schemas/migrations/README.md +30 -30
- package/kits/schemas/relation-config.schema.1.json +158 -158
- package/kits/schemas/relation-config.schema.2.json +73 -73
- package/kits/schemas/relation-config.schema.3.json +50 -50
- package/kits/schemas/relation-config.schema.4.json +47 -47
- package/kits/schemas/relation-config.schema.5.json +47 -47
- package/kits/schemas/relation-config.schema.6.json +46 -46
- package/kits/schemas/relation-config.schema.7.json +59 -59
- package/kits/schemas/relation-config.schema.8.json +103 -103
- package/kits/schemas/role-config.schema.1.json +201 -201
- package/kits/schemas/role-registry.schema.1.json +35 -35
- package/kits/schemas/single-session.schema.1.json +31 -31
- package/kits/schemas/single-session.schema.2.json +57 -57
- package/kits/schemas/single-session.schema.3.json +32 -32
- package/kits/templates/bootstrap-welcome.md +17 -17
- package/kits/templates/message-fragments/handoff-context-to-target.md +9 -9
- package/kits/templates/message-fragments/handoff-request-to-target.md +19 -19
- package/kits/templates/message-fragments/handoff-response-to-origin.md +9 -9
- package/kits/templates/message-fragments/inject-default.md +2 -2
- package/kits/templates/message-fragments/item.md +2 -2
- package/kits/templates/roles/admin.json +92 -92
- package/kits/templates/roles/member.json +96 -96
- package/kits/templates/roles/owner.json +9 -9
- package/kits/templates/roles/visitor.json +85 -85
- package/kits/templates/system-fragments/baseagent.md +14 -14
- package/kits/templates/system-fragments/bootstrap.md +31 -29
- package/kits/templates/system-fragments/channel.md +64 -64
- package/kits/templates/system-fragments/commands.md +28 -28
- package/kits/templates/system-fragments/identity.md +13 -13
- package/kits/templates/system-fragments/relation.md +19 -19
- package/kits/templates/system-fragments/session.md +59 -59
- package/kits/templates/system-fragments/venue.md +31 -31
- package/package.json +100 -98
|
@@ -1,367 +1,367 @@
|
|
|
1
|
-
# 上下文组装机制(manifest)
|
|
2
|
-
|
|
3
|
-
ECK 把"每条消息该给 base agent 看哪些上下文"这件事,交给一份 **manifest** 声明式描述,由 `renderKitSections`(`src/agents/kit-renderer.ts`)在每次处理消息时执行。本文是这套机制的完整参考。
|
|
4
|
-
|
|
5
|
-
> 本文是按需载入文档。日常对话不需要读它——只有在排查"为什么某段上下文没出现/出现了"、要改 manifest、或要看实际渲染结果时才 Read。
|
|
6
|
-
|
|
7
|
-
## 三个阶段
|
|
8
|
-
|
|
9
|
-
evolcore 收到消息 → 构造一份 **vars**(运行时变量,见下)→ `renderKitSections`:
|
|
10
|
-
|
|
11
|
-
1. **选段**:按 manifest 顺序遍历每个 section,用它的 `when` 条件 + 当前 vars 判断是否加载。
|
|
12
|
-
2. **渲染**:解析 section 路径里的 `$NAME` / `{{key}}` 占位符定位文件;`needsInjection:true` 的文件再跑一遍模板渲染(条件块 + 变量替换)。
|
|
13
|
-
3. **拼装**:所有命中的文件内容包进一个 `<system-reminder>` 块,作为 system prompt 的一部分注入。
|
|
14
|
-
|
|
15
|
-
整个过程对每次消息执行一次,结果同时落盘到调试目录(见"调试机制")。
|
|
16
|
-
|
|
17
|
-
## manifest 文件位置
|
|
18
|
-
|
|
19
|
-
| 文件 | 角色 | 性质 |
|
|
20
|
-
|------|------|------|
|
|
21
|
-
| `$KITS/eck_manifest.json` | 基础 manifest(开发时维护) | 只读 |
|
|
22
|
-
| `$ECK/eck_manifest.json` | 用户覆盖(可选,默认不存在) | 可写 |
|
|
23
|
-
|
|
24
|
-
加载时合并两者(见"合并与覆盖")。manifest 只加载一次并缓存。
|
|
25
|
-
|
|
26
|
-
## 多 manifest:按会话原型(sessionType)选清单
|
|
27
|
-
|
|
28
|
-
不同**会话原型**加载不同的 manifest 文件,各自走同一引擎、同一两级覆盖机制:
|
|
29
|
-
|
|
30
|
-
| 会话原型(`session.sessionType`) | manifest 文件 | 用途 |
|
|
31
|
-
|------|------|------|
|
|
32
|
-
| `main`(默认) | `eck_manifest.json` | 主会话,完整上下文 |
|
|
33
|
-
| `auxiliary` | `eck_manifest.auxiliary.json` | 辅助会话(双会话模式),精简上下文 |
|
|
34
|
-
| 未来:`approval` / `goal` / ... | `eck_manifest.<type>.json` | 权限审批 / 目标管理等专用会话 |
|
|
35
|
-
|
|
36
|
-
**映射由 agent config 的 `sessionManifests` 字段定义**(走 config 分级覆盖:关系/环境/agent 级):
|
|
37
|
-
|
|
38
|
-
```jsonc
|
|
39
|
-
// $AGENT_DIR/config.json
|
|
40
|
-
{
|
|
41
|
-
"sessionManifests": {
|
|
42
|
-
"main": "eck_manifest.json", // 缺省可省略,兜底就是它
|
|
43
|
-
"auxiliary": "eck_manifest.auxiliary.json"
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
渲染时按 `session.sessionType`(缺省 `'main'`)查 `sessionManifests`,取不到则回退 `eck_manifest.json`。
|
|
49
|
-
**每个 manifest 文件各自两级合并**(`$KITS/<file>` + `$ECK/<file>`),互不干扰。
|
|
50
|
-
|
|
51
|
-
## section 字段
|
|
52
|
-
|
|
53
|
-
manifest 是 `{ "$schema_version": 1, "sections": [...] }`。每个 section:
|
|
54
|
-
|
|
55
|
-
| 字段 | 必填 | 含义 |
|
|
56
|
-
|------|------|------|
|
|
57
|
-
| `id` | ✓ | 唯一标识,覆盖合并的键 |
|
|
58
|
-
| `type` | ✓ | `file`(单文件)或 `directory`(整目录) |
|
|
59
|
-
| `file` | type=file | 文件路径,可含 `$NAME` / `{{key}}` |
|
|
60
|
-
| `path` | type=directory | 目录路径 |
|
|
61
|
-
| `pattern` | | 目录匹配 glob,默认 `*.md`(支持 `*` 和 `{a,b}`) |
|
|
62
|
-
| `maxFiles` | | type=directory:最多加载文件数,默认 20。超出停止加载并注入截断说明 |
|
|
63
|
-
| `maxBytes` | | type=directory:最多加载总字节,默认 40960(40KB)。超出停止加载并注入截断说明(至少保留 1 个文件) |
|
|
64
|
-
| `order` | ✓ | 排序,**升序**决定上下文中出现的先后 |
|
|
65
|
-
| `needsInjection` | ✓ | `true`=按模板渲染(解析 `{{}}` 条件与变量);`false`=原样读入 |
|
|
66
|
-
| `when` | ✓ | 加载条件,`"always"` 或条件对象(见下) |
|
|
67
|
-
| `enabled` | | `false` 时整段跳过 |
|
|
68
|
-
| `loop` | | 三段式循环:`{ forEach, childFile, separator? }`。有 loop 时 file 作 wrapper,见"三段式循环" |
|
|
69
|
-
| `description` | | 调试输出里的人类可读标签 |
|
|
70
|
-
|
|
71
|
-
### 三段式循环(wrapper + forEach + child)
|
|
72
|
-
|
|
73
|
-
批量数据(如一批消息)用 `loop` 字段做"包裹层 + 循环体"渲染,避免手写重复模板:
|
|
74
|
-
|
|
75
|
-
```jsonc
|
|
76
|
-
{
|
|
77
|
-
"id": "batch-messages",
|
|
78
|
-
"type": "file",
|
|
79
|
-
"file": "$KITS_.../batch-wrapper.md", // ① wrapper:包裹模板,含 {{@loop}} 占位
|
|
80
|
-
"loop": {
|
|
81
|
-
"forEach": "items", // ② 循环 vars 里的数组变量
|
|
82
|
-
"childFile": "$KITS_.../batch-item.md", // ③ 每元素渲染的子模板
|
|
83
|
-
"separator": "\n" // 元素间分隔符,默认 "\n"
|
|
84
|
-
},
|
|
85
|
-
"needsInjection": true,
|
|
86
|
-
"order": 5,
|
|
87
|
-
"when": "always"
|
|
88
|
-
}
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
**wrapper 模板**(`{{@loop}}` 处填入循环结果):
|
|
92
|
-
```
|
|
93
|
-
【批次 剩余{{remainingInQueue}}条 | 主队列{{pendingCount}}】
|
|
94
|
-
{{@loop}}
|
|
95
|
-
【批次结束】
|
|
96
|
-
```
|
|
97
|
-
|
|
98
|
-
**childFile 模板**(每个元素,可访问元素字段 + 外层 vars + `{{@index}}`):
|
|
99
|
-
```
|
|
100
|
-
[{{@index}}] {{peerName}}: {{content}}
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
**渲染规则**:
|
|
104
|
-
- 对 `vars[forEach]` 数组每个元素渲染 childFile(对象元素 → 字段可用 `{{field}}`;标量 → `{{.}}`),以 `separator` 连接
|
|
105
|
-
- wrapper 单独渲染(其变量如 `remainingInQueue` 来自 vars),`{{@loop}}` 位置**字面量填入**循环结果 → 循环结果不被二次解析
|
|
106
|
-
- childFile 内可再嵌套 `{{#each}}` 或另一个占位,支持多层
|
|
107
|
-
- 空数组 / 非数组 → 循环结果为空串
|
|
108
|
-
- wrapper 不含 `{{@loop}}` → 循环结果追加到 wrapper 末尾(容错)
|
|
109
|
-
|
|
110
|
-
> **消息渲染层的 loop**:`eck_message_manifest.json` 里的 loop 段是**批次包裹层**——
|
|
111
|
-
> child 由 message-renderer 的逐条渲染(`renderOneItem`,自带 content 哨兵)产出,
|
|
112
|
-
> 用户消息文本里的 `{{}}` 不会被二次解析。批次 vars(remainingInQueue 等)从 sessionVars 透传。
|
|
113
|
-
> 详见 `prompt-loading-architecture.md`。
|
|
114
|
-
|
|
115
|
-
### 清单顶层字段
|
|
116
|
-
|
|
117
|
-
除 `sections` 外,manifest 顶层还支持全局限额(总闸,跨所有段累计):
|
|
118
|
-
|
|
119
|
-
| 字段 | 默认 | 含义 |
|
|
120
|
-
|------|------|------|
|
|
121
|
-
| `$schema_version` | — | 版本号 |
|
|
122
|
-
| `mode` | patch | `patch`(合并)/ `replace`(完全替换),见"合并与覆盖" |
|
|
123
|
-
| `totalMaxFiles` | 50 | 整个清单渲染最多文件数。达到后停止加载后续所有段 |
|
|
124
|
-
| `totalMaxBytes` | 102400(100KB) | 整个清单渲染最多总字节。达到后停止加载后续所有段 |
|
|
125
|
-
|
|
126
|
-
## 目录加载限额(安全保护)
|
|
127
|
-
|
|
128
|
-
`type: directory` 段加载整个目录,若目录内容失控会撑爆提示词。两层限额保护:
|
|
129
|
-
|
|
130
|
-
- **单目录限额**(`maxFiles` 20 / `maxBytes` 40KB):单个目录段最多加载多少。超出时停止加载该目录后续文件,并在该段末尾注入一行截断说明:
|
|
131
|
-
`[注意] 目录 $KITS_RULES 未完整加载:N 个文件未加载(达文件数上限 20 个)。`
|
|
132
|
-
- **总闸限额**(`totalMaxFiles` 50 / `totalMaxBytes` 100KB):整个清单所有段加起来的上限。达到后停止加载后续所有命中段,末尾注入总截断说明,**带上未加载的 section id 集合**:
|
|
133
|
-
`[注意] 上下文清单总量超限(>50 文件 / >100KB),以下 section 未加载:goal-fragment, extra-docs。`
|
|
134
|
-
|
|
135
|
-
> **注**:字节按文件原始内容(`rawContent`)计,不含渲染后变化,也不含截断说明行本身。
|
|
136
|
-
> 单目录"至少保留 1 个文件"——避免单个超大文件导致整段为空。
|
|
137
|
-
> 截断信息同时写入调试输出(`manifest-*.md`),便于排查。
|
|
138
|
-
|
|
139
|
-
> **现状**:当前唯一目录段 `$KITS_RULES` = 6 文件 / ~18KB,远低于默认限额,不受影响。
|
|
140
|
-
> 新增规则文档时注意别让该目录逼近 40KB。
|
|
141
|
-
|
|
142
|
-
## when 条件求值
|
|
143
|
-
|
|
144
|
-
`when` 是 `"always"` 或一个对象。求值规则(`evaluateWhen`):
|
|
145
|
-
|
|
146
|
-
| 写法 | 含义 |
|
|
147
|
-
|------|------|
|
|
148
|
-
| `"always"` | 恒为真 |
|
|
149
|
-
| `{ "var": "X", "eq": V }` | `vars.X === V`;`eq:null` 匹配"未注入"(null/undefined) |
|
|
150
|
-
| `{ "var": "X", "neq": V }` | `vars.X !== V`;`neq:null` 匹配"已注入" |
|
|
151
|
-
| `{ "var": "X", "in": [...] }` | `vars.X` 在数组内 |
|
|
152
|
-
| `{ "var": "X", "nin": [...] }` | `vars.X` 不在数组内 |
|
|
153
|
-
| `{ "any": ["A","B"] }` | A、B 任一为真值 |
|
|
154
|
-
| `{ "all": ["A","B"] }` | A、B 全为真值 |
|
|
155
|
-
|
|
156
|
-
"真值"判定:非 `undefined`/`null`/`false`/`""`/`0`。
|
|
157
|
-
|
|
158
|
-
典型用法:`{ "var": "chatType", "neq": null }` = "非 coding 场景才加载";`{ "var": "groupId", "neq": null }` = "群聊才加载"。
|
|
159
|
-
|
|
160
|
-
## 合并与覆盖
|
|
161
|
-
|
|
162
|
-
无 `$ECK/eck_manifest.json` 时,直接用基础 manifest。存在时:
|
|
163
|
-
|
|
164
|
-
- 覆盖文件含 `"mode": "replace"` → **完全替换**,只用覆盖文件的 sections。
|
|
165
|
-
- 否则 **patch 合并**:以 `id` 为键,覆盖文件里同 id 的字段浅合并进基础 section(`{...base, ...override}`),新 id 追加。
|
|
166
|
-
- 旧 patch 中的 `relation-group-profile` 已废弃并会被忽略;群与私聊 profile 统一通过 `peer-profile` 配置,避免同一文件重复加载。`mode: "replace"` 不做此兼容处理。
|
|
167
|
-
|
|
168
|
-
合并后统一按 `order` 升序排序。改某段行为(如关掉某层、调顺序、换条件)优先用覆盖文件,不动基础 manifest。
|
|
169
|
-
|
|
170
|
-
### 覆盖示例
|
|
171
|
-
|
|
172
|
-
禁用某段:
|
|
173
|
-
|
|
174
|
-
```json
|
|
175
|
-
{ "sections": [ { "id": "venue-client", "enabled": false } ] }
|
|
176
|
-
```
|
|
177
|
-
|
|
178
|
-
改加载条件(仅 owner/admin 才载入对端档案):
|
|
179
|
-
|
|
180
|
-
```json
|
|
181
|
-
{ "sections": [ { "id": "peer-profile", "when": { "var": "peerRole", "in": ["owner", "admin"] } } ] }
|
|
182
|
-
```
|
|
183
|
-
|
|
184
|
-
新增自定义段:
|
|
185
|
-
|
|
186
|
-
```json
|
|
187
|
-
{
|
|
188
|
-
"sections": [
|
|
189
|
-
{
|
|
190
|
-
"id": "my-custom-context",
|
|
191
|
-
"type": "file",
|
|
192
|
-
"file": "$AGENT_DIR/custom/my-rules.md",
|
|
193
|
-
"order": 25,
|
|
194
|
-
"needsInjection": false,
|
|
195
|
-
"when": "always",
|
|
196
|
-
"description": "我的自定义规则"
|
|
197
|
-
}
|
|
198
|
-
]
|
|
199
|
-
}
|
|
200
|
-
```
|
|
201
|
-
|
|
202
|
-
完全替换(忽略基础 manifest):
|
|
203
|
-
|
|
204
|
-
```json
|
|
205
|
-
{ "$schema_version": 1, "mode": "replace", "sections": [ ... ] }
|
|
206
|
-
```
|
|
207
|
-
|
|
208
|
-
## 路径与模板渲染
|
|
209
|
-
|
|
210
|
-
### 路径占位符(所有 section 的 file/path)
|
|
211
|
-
|
|
212
|
-
- `$NAME`(大写)→ 从 vars 取真值,如 `$KITS_DOCS` → 包内文档目录。
|
|
213
|
-
- `{{key}}` → 从 vars 取真值,如 `{{chatType}}` → `private`,`{{peerKey}}` → `aun#alice.aid.pub`。
|
|
214
|
-
|
|
215
|
-
manifest 中常用路径变量的展开值:
|
|
216
|
-
|
|
217
|
-
| 变量 | 展开为 |
|
|
218
|
-
|------|--------|
|
|
219
|
-
| `$PACKAGE_ROOT` | evolcore 包根 |
|
|
220
|
-
| `$EVOLCORE_HOME` | 用户数据根(默认 `~/.evolcore`) |
|
|
221
|
-
| `$KITS` | `$PACKAGE_ROOT/kits` |
|
|
222
|
-
| `$KITS_RULES` | `$KITS/rules` |
|
|
223
|
-
| `$KITS_DOCS` | `$KITS/docs` |
|
|
224
|
-
| `$KITS_TEMPLATES` | `$KITS/templates` |
|
|
225
|
-
| `$KITS_FRAGMENTS` | `$KITS_TEMPLATES/system-fragments` |
|
|
226
|
-
| `$ECK` | `$EVOLCORE_HOME/eck` |
|
|
227
|
-
| `$AGENT_DIR` | `$EVOLCORE_HOME/agents/<selfAid>` |
|
|
228
|
-
| `$PERSONAL_DIR` | `$AGENT_DIR/personal` |
|
|
229
|
-
| `$RELATIONS_DIR` | `$AGENT_DIR/relations` |
|
|
230
|
-
| `$VENUES_DIR` | `$AGENT_DIR/venues` |
|
|
231
|
-
|
|
232
|
-
任一占位符解析为空 → 该 section 视为"未解析",跳过(调试输出标 `unresolved-vars`)。文件不存在 → 标 `not-exist`,也跳过。这是**正常机制**:很多 section 靠"路径解析不出来"自然落选(如 coding 场景没有 `$PERSONAL_DIR`)。
|
|
233
|
-
|
|
234
|
-
### 模板渲染(仅 needsInjection:true 的文件)
|
|
235
|
-
|
|
236
|
-
读入跑三遍:
|
|
237
|
-
|
|
238
|
-
1. **条件块**(内层优先,可嵌套):
|
|
239
|
-
- `{{?key}}...{{/}}` — key 为真值才保留
|
|
240
|
-
- `{{?key=value}}...{{/}}` — `String(vars.key)===value` 才保留
|
|
241
|
-
- `{{?key!=value}}...{{/}}` — 不等才保留
|
|
242
|
-
2. **变量替换**:`{{key}}` 替换为值,非真值替换为空串。
|
|
243
|
-
3. **清理**:删掉空行。
|
|
244
|
-
|
|
245
|
-
`needsInjection:false` 的文件原样读入,不做任何替换(如 rules 目录、persona.md、各 venue 文档)。
|
|
246
|
-
|
|
247
|
-
## 运行时变量(vars)目录
|
|
248
|
-
|
|
249
|
-
vars 由 evolcore 在 `message-processor.ts` 按当前会话构造。分两类:
|
|
250
|
-
|
|
251
|
-
**路径类**(供占位符展开成真实路径):
|
|
252
|
-
`EVOLCORE_HOME`、`PACKAGE_ROOT`、`CURRENT_PROJECT`、`KITS`、`KITS_RULES`、`KITS_DOCS`、`KITS_TEMPLATES`、`KITS_FRAGMENTS`、`PERSONAL_DIR`、`RELATIONS_DIR`、`VENUES_DIR`。
|
|
253
|
-
|
|
254
|
-
**内容/场景类**(供 when 判断与模板替换):
|
|
255
|
-
|
|
256
|
-
| 变量 | 含义 |
|
|
257
|
-
|------|------|
|
|
258
|
-
| `selfAid` / `selfName` | 当前 agent 身份 |
|
|
259
|
-
| `hasPersona` / `hasWorkingMemory` | 是否有人格 / 当前关注 |
|
|
260
|
-
| `peerId` / `peerKey` / `peerName` | 对端原生 ID / 跨渠道键 / 显示名 |
|
|
261
|
-
| `peerRole` / `peerType` | 对端角色(owner/admin/member/visitor/自定义角色/none)/ 类型(human/agent) |
|
|
262
|
-
| `groupId` | 群 ID(群聊时) |
|
|
263
|
-
| `chatType` | `private` / `group` / `null`(coding) |
|
|
264
|
-
| `channel` | 渠道类型(aun/feishu/...)|
|
|
265
|
-
| `mentionMode` | 群 @ 处理模式(mention-only/disabled) |
|
|
266
|
-
| `clientType` | 客户端类型(desktop/web/mobile) |
|
|
267
|
-
| `permissionMode` / `readonly` | 权限模式 / 是否只读 |
|
|
268
|
-
| `capabilities` | 当前渠道能力(图片输入/输出、文件发送) |
|
|
269
|
-
| `project` / `CURRENT_PROJECT` | 项目目录名 / 完整路径 |
|
|
270
|
-
| `sessionId` / `sessionName` / `sessionKey` / `sessionCreatedAt` / `threadId` | 会话标识与元信息 |
|
|
271
|
-
| `chatMode` | `interactive` / `proactive` |
|
|
272
|
-
| `baseAgent` / `baseAgentName` / `baseAgentModel` / `agentSessionId` | base agent 信息 |
|
|
273
|
-
|
|
274
|
-
coding 场景(无 channel/无身份)下,`chatType`、`channel`、`selfAid`、`peer*` 等均为空——这正是身份/关系/环境/渠道层落选的原因。
|
|
275
|
-
|
|
276
|
-
## 三种加载方式
|
|
277
|
-
|
|
278
|
-
| 加载方式 | 决策者 | 驱动方式 | 例子 |
|
|
279
|
-
|---------|-------|---------|------|
|
|
280
|
-
| **全量加载** | manifest | `when: "always"` | rules/ 核心规则、session 参数 |
|
|
281
|
-
| **按条件自动加载** | manifest | `when` 条件 + 路径存在性 | 身份层(chatType 非空时)、对端档案(peerKey 非空时) |
|
|
282
|
-
| **按需加载** | agent 自主 | agent 在对话中主动 Read 文件 | 查阅 `$KITS_DOCS/` 下的详细参考文档 |
|
|
283
|
-
|
|
284
|
-
前两种由 manifest 控制,第三种由 agent 根据各层文档中的"按需加载指引"自主决定。
|
|
285
|
-
|
|
286
|
-
## 默认 manifest 的段(按 order)
|
|
287
|
-
|
|
288
|
-
| order | id | 类型 | 加载条件(when) | inject |
|
|
289
|
-
|-------|----|----|------------------|--------|
|
|
290
|
-
| 10 | rules | 目录 `$KITS_RULES` | always | ✗ |
|
|
291
|
-
| 20 | identity-layer | fragment | chatType≠null | ✓ |
|
|
1
|
+
# 上下文组装机制(manifest)
|
|
2
|
+
|
|
3
|
+
ECK 把"每条消息该给 base agent 看哪些上下文"这件事,交给一份 **manifest** 声明式描述,由 `renderKitSections`(`src/agents/kit-renderer.ts`)在每次处理消息时执行。本文是这套机制的完整参考。
|
|
4
|
+
|
|
5
|
+
> 本文是按需载入文档。日常对话不需要读它——只有在排查"为什么某段上下文没出现/出现了"、要改 manifest、或要看实际渲染结果时才 Read。
|
|
6
|
+
|
|
7
|
+
## 三个阶段
|
|
8
|
+
|
|
9
|
+
evolcore 收到消息 → 构造一份 **vars**(运行时变量,见下)→ `renderKitSections`:
|
|
10
|
+
|
|
11
|
+
1. **选段**:按 manifest 顺序遍历每个 section,用它的 `when` 条件 + 当前 vars 判断是否加载。
|
|
12
|
+
2. **渲染**:解析 section 路径里的 `$NAME` / `{{key}}` 占位符定位文件;`needsInjection:true` 的文件再跑一遍模板渲染(条件块 + 变量替换)。
|
|
13
|
+
3. **拼装**:所有命中的文件内容包进一个 `<system-reminder>` 块,作为 system prompt 的一部分注入。
|
|
14
|
+
|
|
15
|
+
整个过程对每次消息执行一次,结果同时落盘到调试目录(见"调试机制")。
|
|
16
|
+
|
|
17
|
+
## manifest 文件位置
|
|
18
|
+
|
|
19
|
+
| 文件 | 角色 | 性质 |
|
|
20
|
+
|------|------|------|
|
|
21
|
+
| `$KITS/eck_manifest.json` | 基础 manifest(开发时维护) | 只读 |
|
|
22
|
+
| `$ECK/eck_manifest.json` | 用户覆盖(可选,默认不存在) | 可写 |
|
|
23
|
+
|
|
24
|
+
加载时合并两者(见"合并与覆盖")。manifest 只加载一次并缓存。
|
|
25
|
+
|
|
26
|
+
## 多 manifest:按会话原型(sessionType)选清单
|
|
27
|
+
|
|
28
|
+
不同**会话原型**加载不同的 manifest 文件,各自走同一引擎、同一两级覆盖机制:
|
|
29
|
+
|
|
30
|
+
| 会话原型(`session.sessionType`) | manifest 文件 | 用途 |
|
|
31
|
+
|------|------|------|
|
|
32
|
+
| `main`(默认) | `eck_manifest.json` | 主会话,完整上下文 |
|
|
33
|
+
| `auxiliary` | `eck_manifest.auxiliary.json` | 辅助会话(双会话模式),精简上下文 |
|
|
34
|
+
| 未来:`approval` / `goal` / ... | `eck_manifest.<type>.json` | 权限审批 / 目标管理等专用会话 |
|
|
35
|
+
|
|
36
|
+
**映射由 agent config 的 `sessionManifests` 字段定义**(走 config 分级覆盖:关系/环境/agent 级):
|
|
37
|
+
|
|
38
|
+
```jsonc
|
|
39
|
+
// $AGENT_DIR/config.json
|
|
40
|
+
{
|
|
41
|
+
"sessionManifests": {
|
|
42
|
+
"main": "eck_manifest.json", // 缺省可省略,兜底就是它
|
|
43
|
+
"auxiliary": "eck_manifest.auxiliary.json"
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
渲染时按 `session.sessionType`(缺省 `'main'`)查 `sessionManifests`,取不到则回退 `eck_manifest.json`。
|
|
49
|
+
**每个 manifest 文件各自两级合并**(`$KITS/<file>` + `$ECK/<file>`),互不干扰。
|
|
50
|
+
|
|
51
|
+
## section 字段
|
|
52
|
+
|
|
53
|
+
manifest 是 `{ "$schema_version": 1, "sections": [...] }`。每个 section:
|
|
54
|
+
|
|
55
|
+
| 字段 | 必填 | 含义 |
|
|
56
|
+
|------|------|------|
|
|
57
|
+
| `id` | ✓ | 唯一标识,覆盖合并的键 |
|
|
58
|
+
| `type` | ✓ | `file`(单文件)或 `directory`(整目录) |
|
|
59
|
+
| `file` | type=file | 文件路径,可含 `$NAME` / `{{key}}` |
|
|
60
|
+
| `path` | type=directory | 目录路径 |
|
|
61
|
+
| `pattern` | | 目录匹配 glob,默认 `*.md`(支持 `*` 和 `{a,b}`) |
|
|
62
|
+
| `maxFiles` | | type=directory:最多加载文件数,默认 20。超出停止加载并注入截断说明 |
|
|
63
|
+
| `maxBytes` | | type=directory:最多加载总字节,默认 40960(40KB)。超出停止加载并注入截断说明(至少保留 1 个文件) |
|
|
64
|
+
| `order` | ✓ | 排序,**升序**决定上下文中出现的先后 |
|
|
65
|
+
| `needsInjection` | ✓ | `true`=按模板渲染(解析 `{{}}` 条件与变量);`false`=原样读入 |
|
|
66
|
+
| `when` | ✓ | 加载条件,`"always"` 或条件对象(见下) |
|
|
67
|
+
| `enabled` | | `false` 时整段跳过 |
|
|
68
|
+
| `loop` | | 三段式循环:`{ forEach, childFile, separator? }`。有 loop 时 file 作 wrapper,见"三段式循环" |
|
|
69
|
+
| `description` | | 调试输出里的人类可读标签 |
|
|
70
|
+
|
|
71
|
+
### 三段式循环(wrapper + forEach + child)
|
|
72
|
+
|
|
73
|
+
批量数据(如一批消息)用 `loop` 字段做"包裹层 + 循环体"渲染,避免手写重复模板:
|
|
74
|
+
|
|
75
|
+
```jsonc
|
|
76
|
+
{
|
|
77
|
+
"id": "batch-messages",
|
|
78
|
+
"type": "file",
|
|
79
|
+
"file": "$KITS_.../batch-wrapper.md", // ① wrapper:包裹模板,含 {{@loop}} 占位
|
|
80
|
+
"loop": {
|
|
81
|
+
"forEach": "items", // ② 循环 vars 里的数组变量
|
|
82
|
+
"childFile": "$KITS_.../batch-item.md", // ③ 每元素渲染的子模板
|
|
83
|
+
"separator": "\n" // 元素间分隔符,默认 "\n"
|
|
84
|
+
},
|
|
85
|
+
"needsInjection": true,
|
|
86
|
+
"order": 5,
|
|
87
|
+
"when": "always"
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
**wrapper 模板**(`{{@loop}}` 处填入循环结果):
|
|
92
|
+
```
|
|
93
|
+
【批次 剩余{{remainingInQueue}}条 | 主队列{{pendingCount}}】
|
|
94
|
+
{{@loop}}
|
|
95
|
+
【批次结束】
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
**childFile 模板**(每个元素,可访问元素字段 + 外层 vars + `{{@index}}`):
|
|
99
|
+
```
|
|
100
|
+
[{{@index}}] {{peerName}}: {{content}}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
**渲染规则**:
|
|
104
|
+
- 对 `vars[forEach]` 数组每个元素渲染 childFile(对象元素 → 字段可用 `{{field}}`;标量 → `{{.}}`),以 `separator` 连接
|
|
105
|
+
- wrapper 单独渲染(其变量如 `remainingInQueue` 来自 vars),`{{@loop}}` 位置**字面量填入**循环结果 → 循环结果不被二次解析
|
|
106
|
+
- childFile 内可再嵌套 `{{#each}}` 或另一个占位,支持多层
|
|
107
|
+
- 空数组 / 非数组 → 循环结果为空串
|
|
108
|
+
- wrapper 不含 `{{@loop}}` → 循环结果追加到 wrapper 末尾(容错)
|
|
109
|
+
|
|
110
|
+
> **消息渲染层的 loop**:`eck_message_manifest.json` 里的 loop 段是**批次包裹层**——
|
|
111
|
+
> child 由 message-renderer 的逐条渲染(`renderOneItem`,自带 content 哨兵)产出,
|
|
112
|
+
> 用户消息文本里的 `{{}}` 不会被二次解析。批次 vars(remainingInQueue 等)从 sessionVars 透传。
|
|
113
|
+
> 详见 `prompt-loading-architecture.md`。
|
|
114
|
+
|
|
115
|
+
### 清单顶层字段
|
|
116
|
+
|
|
117
|
+
除 `sections` 外,manifest 顶层还支持全局限额(总闸,跨所有段累计):
|
|
118
|
+
|
|
119
|
+
| 字段 | 默认 | 含义 |
|
|
120
|
+
|------|------|------|
|
|
121
|
+
| `$schema_version` | — | 版本号 |
|
|
122
|
+
| `mode` | patch | `patch`(合并)/ `replace`(完全替换),见"合并与覆盖" |
|
|
123
|
+
| `totalMaxFiles` | 50 | 整个清单渲染最多文件数。达到后停止加载后续所有段 |
|
|
124
|
+
| `totalMaxBytes` | 102400(100KB) | 整个清单渲染最多总字节。达到后停止加载后续所有段 |
|
|
125
|
+
|
|
126
|
+
## 目录加载限额(安全保护)
|
|
127
|
+
|
|
128
|
+
`type: directory` 段加载整个目录,若目录内容失控会撑爆提示词。两层限额保护:
|
|
129
|
+
|
|
130
|
+
- **单目录限额**(`maxFiles` 20 / `maxBytes` 40KB):单个目录段最多加载多少。超出时停止加载该目录后续文件,并在该段末尾注入一行截断说明:
|
|
131
|
+
`[注意] 目录 $KITS_RULES 未完整加载:N 个文件未加载(达文件数上限 20 个)。`
|
|
132
|
+
- **总闸限额**(`totalMaxFiles` 50 / `totalMaxBytes` 100KB):整个清单所有段加起来的上限。达到后停止加载后续所有命中段,末尾注入总截断说明,**带上未加载的 section id 集合**:
|
|
133
|
+
`[注意] 上下文清单总量超限(>50 文件 / >100KB),以下 section 未加载:goal-fragment, extra-docs。`
|
|
134
|
+
|
|
135
|
+
> **注**:字节按文件原始内容(`rawContent`)计,不含渲染后变化,也不含截断说明行本身。
|
|
136
|
+
> 单目录"至少保留 1 个文件"——避免单个超大文件导致整段为空。
|
|
137
|
+
> 截断信息同时写入调试输出(`manifest-*.md`),便于排查。
|
|
138
|
+
|
|
139
|
+
> **现状**:当前唯一目录段 `$KITS_RULES` = 6 文件 / ~18KB,远低于默认限额,不受影响。
|
|
140
|
+
> 新增规则文档时注意别让该目录逼近 40KB。
|
|
141
|
+
|
|
142
|
+
## when 条件求值
|
|
143
|
+
|
|
144
|
+
`when` 是 `"always"` 或一个对象。求值规则(`evaluateWhen`):
|
|
145
|
+
|
|
146
|
+
| 写法 | 含义 |
|
|
147
|
+
|------|------|
|
|
148
|
+
| `"always"` | 恒为真 |
|
|
149
|
+
| `{ "var": "X", "eq": V }` | `vars.X === V`;`eq:null` 匹配"未注入"(null/undefined) |
|
|
150
|
+
| `{ "var": "X", "neq": V }` | `vars.X !== V`;`neq:null` 匹配"已注入" |
|
|
151
|
+
| `{ "var": "X", "in": [...] }` | `vars.X` 在数组内 |
|
|
152
|
+
| `{ "var": "X", "nin": [...] }` | `vars.X` 不在数组内 |
|
|
153
|
+
| `{ "any": ["A","B"] }` | A、B 任一为真值 |
|
|
154
|
+
| `{ "all": ["A","B"] }` | A、B 全为真值 |
|
|
155
|
+
|
|
156
|
+
"真值"判定:非 `undefined`/`null`/`false`/`""`/`0`。
|
|
157
|
+
|
|
158
|
+
典型用法:`{ "var": "chatType", "neq": null }` = "非 coding 场景才加载";`{ "var": "groupId", "neq": null }` = "群聊才加载"。
|
|
159
|
+
|
|
160
|
+
## 合并与覆盖
|
|
161
|
+
|
|
162
|
+
无 `$ECK/eck_manifest.json` 时,直接用基础 manifest。存在时:
|
|
163
|
+
|
|
164
|
+
- 覆盖文件含 `"mode": "replace"` → **完全替换**,只用覆盖文件的 sections。
|
|
165
|
+
- 否则 **patch 合并**:以 `id` 为键,覆盖文件里同 id 的字段浅合并进基础 section(`{...base, ...override}`),新 id 追加。
|
|
166
|
+
- 旧 patch 中的 `relation-group-profile` 已废弃并会被忽略;群与私聊 profile 统一通过 `peer-profile` 配置,避免同一文件重复加载。`mode: "replace"` 不做此兼容处理。
|
|
167
|
+
|
|
168
|
+
合并后统一按 `order` 升序排序。改某段行为(如关掉某层、调顺序、换条件)优先用覆盖文件,不动基础 manifest。
|
|
169
|
+
|
|
170
|
+
### 覆盖示例
|
|
171
|
+
|
|
172
|
+
禁用某段:
|
|
173
|
+
|
|
174
|
+
```json
|
|
175
|
+
{ "sections": [ { "id": "venue-client", "enabled": false } ] }
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
改加载条件(仅 owner/admin 才载入对端档案):
|
|
179
|
+
|
|
180
|
+
```json
|
|
181
|
+
{ "sections": [ { "id": "peer-profile", "when": { "var": "peerRole", "in": ["owner", "admin"] } } ] }
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
新增自定义段:
|
|
185
|
+
|
|
186
|
+
```json
|
|
187
|
+
{
|
|
188
|
+
"sections": [
|
|
189
|
+
{
|
|
190
|
+
"id": "my-custom-context",
|
|
191
|
+
"type": "file",
|
|
192
|
+
"file": "$AGENT_DIR/custom/my-rules.md",
|
|
193
|
+
"order": 25,
|
|
194
|
+
"needsInjection": false,
|
|
195
|
+
"when": "always",
|
|
196
|
+
"description": "我的自定义规则"
|
|
197
|
+
}
|
|
198
|
+
]
|
|
199
|
+
}
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
完全替换(忽略基础 manifest):
|
|
203
|
+
|
|
204
|
+
```json
|
|
205
|
+
{ "$schema_version": 1, "mode": "replace", "sections": [ ... ] }
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## 路径与模板渲染
|
|
209
|
+
|
|
210
|
+
### 路径占位符(所有 section 的 file/path)
|
|
211
|
+
|
|
212
|
+
- `$NAME`(大写)→ 从 vars 取真值,如 `$KITS_DOCS` → 包内文档目录。
|
|
213
|
+
- `{{key}}` → 从 vars 取真值,如 `{{chatType}}` → `private`,`{{peerKey}}` → `aun#alice.aid.pub`。
|
|
214
|
+
|
|
215
|
+
manifest 中常用路径变量的展开值:
|
|
216
|
+
|
|
217
|
+
| 变量 | 展开为 |
|
|
218
|
+
|------|--------|
|
|
219
|
+
| `$PACKAGE_ROOT` | evolcore 包根 |
|
|
220
|
+
| `$EVOLCORE_HOME` | 用户数据根(默认 `~/.evolcore`) |
|
|
221
|
+
| `$KITS` | `$PACKAGE_ROOT/kits` |
|
|
222
|
+
| `$KITS_RULES` | `$KITS/rules` |
|
|
223
|
+
| `$KITS_DOCS` | `$KITS/docs` |
|
|
224
|
+
| `$KITS_TEMPLATES` | `$KITS/templates` |
|
|
225
|
+
| `$KITS_FRAGMENTS` | `$KITS_TEMPLATES/system-fragments` |
|
|
226
|
+
| `$ECK` | `$EVOLCORE_HOME/eck` |
|
|
227
|
+
| `$AGENT_DIR` | `$EVOLCORE_HOME/agents/<selfAid>` |
|
|
228
|
+
| `$PERSONAL_DIR` | `$AGENT_DIR/personal` |
|
|
229
|
+
| `$RELATIONS_DIR` | `$AGENT_DIR/relations` |
|
|
230
|
+
| `$VENUES_DIR` | `$AGENT_DIR/venues` |
|
|
231
|
+
|
|
232
|
+
任一占位符解析为空 → 该 section 视为"未解析",跳过(调试输出标 `unresolved-vars`)。文件不存在 → 标 `not-exist`,也跳过。这是**正常机制**:很多 section 靠"路径解析不出来"自然落选(如 coding 场景没有 `$PERSONAL_DIR`)。
|
|
233
|
+
|
|
234
|
+
### 模板渲染(仅 needsInjection:true 的文件)
|
|
235
|
+
|
|
236
|
+
读入跑三遍:
|
|
237
|
+
|
|
238
|
+
1. **条件块**(内层优先,可嵌套):
|
|
239
|
+
- `{{?key}}...{{/}}` — key 为真值才保留
|
|
240
|
+
- `{{?key=value}}...{{/}}` — `String(vars.key)===value` 才保留
|
|
241
|
+
- `{{?key!=value}}...{{/}}` — 不等才保留
|
|
242
|
+
2. **变量替换**:`{{key}}` 替换为值,非真值替换为空串。
|
|
243
|
+
3. **清理**:删掉空行。
|
|
244
|
+
|
|
245
|
+
`needsInjection:false` 的文件原样读入,不做任何替换(如 rules 目录、persona.md、各 venue 文档)。
|
|
246
|
+
|
|
247
|
+
## 运行时变量(vars)目录
|
|
248
|
+
|
|
249
|
+
vars 由 evolcore 在 `message-processor.ts` 按当前会话构造。分两类:
|
|
250
|
+
|
|
251
|
+
**路径类**(供占位符展开成真实路径):
|
|
252
|
+
`EVOLCORE_HOME`、`PACKAGE_ROOT`、`CURRENT_PROJECT`、`KITS`、`KITS_RULES`、`KITS_DOCS`、`KITS_TEMPLATES`、`KITS_FRAGMENTS`、`PERSONAL_DIR`、`RELATIONS_DIR`、`VENUES_DIR`。
|
|
253
|
+
|
|
254
|
+
**内容/场景类**(供 when 判断与模板替换):
|
|
255
|
+
|
|
256
|
+
| 变量 | 含义 |
|
|
257
|
+
|------|------|
|
|
258
|
+
| `selfAid` / `selfName` | 当前 agent 身份 |
|
|
259
|
+
| `hasPersona` / `hasWorkingMemory` | 是否有人格 / 当前关注 |
|
|
260
|
+
| `peerId` / `peerKey` / `peerName` | 对端原生 ID / 跨渠道键 / 显示名 |
|
|
261
|
+
| `peerRole` / `peerType` | 对端角色(owner/admin/member/visitor/自定义角色/none)/ 类型(human/agent) |
|
|
262
|
+
| `groupId` | 群 ID(群聊时) |
|
|
263
|
+
| `chatType` | `private` / `group` / `null`(coding) |
|
|
264
|
+
| `channel` | 渠道类型(aun/feishu/...)|
|
|
265
|
+
| `mentionMode` | 群 @ 处理模式(mention-only/disabled) |
|
|
266
|
+
| `clientType` | 客户端类型(desktop/web/mobile) |
|
|
267
|
+
| `permissionMode` / `readonly` | 权限模式 / 是否只读 |
|
|
268
|
+
| `capabilities` | 当前渠道能力(图片输入/输出、文件发送) |
|
|
269
|
+
| `project` / `CURRENT_PROJECT` | 项目目录名 / 完整路径 |
|
|
270
|
+
| `sessionId` / `sessionName` / `sessionKey` / `sessionCreatedAt` / `threadId` | 会话标识与元信息 |
|
|
271
|
+
| `chatMode` | `interactive` / `proactive` |
|
|
272
|
+
| `baseAgent` / `baseAgentName` / `baseAgentModel` / `agentSessionId` | base agent 信息 |
|
|
273
|
+
|
|
274
|
+
coding 场景(无 channel/无身份)下,`chatType`、`channel`、`selfAid`、`peer*` 等均为空——这正是身份/关系/环境/渠道层落选的原因。
|
|
275
|
+
|
|
276
|
+
## 三种加载方式
|
|
277
|
+
|
|
278
|
+
| 加载方式 | 决策者 | 驱动方式 | 例子 |
|
|
279
|
+
|---------|-------|---------|------|
|
|
280
|
+
| **全量加载** | manifest | `when: "always"` | rules/ 核心规则、session 参数 |
|
|
281
|
+
| **按条件自动加载** | manifest | `when` 条件 + 路径存在性 | 身份层(chatType 非空时)、对端档案(peerKey 非空时) |
|
|
282
|
+
| **按需加载** | agent 自主 | agent 在对话中主动 Read 文件 | 查阅 `$KITS_DOCS/` 下的详细参考文档 |
|
|
283
|
+
|
|
284
|
+
前两种由 manifest 控制,第三种由 agent 根据各层文档中的"按需加载指引"自主决定。
|
|
285
|
+
|
|
286
|
+
## 默认 manifest 的段(按 order)
|
|
287
|
+
|
|
288
|
+
| order | id | 类型 | 加载条件(when) | inject |
|
|
289
|
+
|-------|----|----|------------------|--------|
|
|
290
|
+
| 10 | rules | 目录 `$KITS_RULES` | always | ✗ |
|
|
291
|
+
| 20 | identity-layer | fragment | chatType≠null | ✓ |
|
|
292
292
|
| 21 | persona | `$PERSONAL_DIR/persona.md` | chatType≠null | ✗ |
|
|
293
293
|
| 21.5 | personal-profile | `$PERSONAL_DIR/personal.md` | chatType≠null | ✗ |
|
|
294
294
|
| 22 | working-memory | `$PERSONAL_DIR/memory/working.md` | chatType≠null | ✗ |
|
|
295
|
-
| 30 | relation-layer | fragment | chatType∈{private,group} | ✓ |
|
|
296
|
-
| 35 | peer-profile | `$RELATIONS_DIR/{{peerKey}}/profile.md` | peerKey≠null | ✗ |
|
|
297
|
-
| 40 | venue-fragment | fragment | chatType≠null | ✓ |
|
|
298
|
-
| 41 | venue-chattype | `$KITS_DOCS/venues/{{chatType}}.md` | chatType≠null | ✗ |
|
|
299
|
-
| 42 | venue-channel-chattype | `$KITS_DOCS/venues/{{channel}}-{{chatType}}.md` | chatType≠null | ✗ |
|
|
300
|
-
| 44 | venue-client | `$KITS_DOCS/venues/client-{{clientType}}.md` | clientType≠null | ✗ |
|
|
301
|
-
| 50 | channel-layer | fragment | channel≠null | ✓ |
|
|
302
|
-
| 55 | commands | fragment | channel≠null | ✓ |
|
|
303
|
-
| 60 | session | fragment | always | ✓ |
|
|
304
|
-
| 70 | baseagent | fragment | baseAgent≠null | ✓ |
|
|
305
|
-
|
|
306
|
-
> 注意:`session`(60) 是 `always`,`baseagent`(70) 只看 `baseAgent` 是否注入——这两段**与 chatType 无关**,coding 场景也会加载。所谓"coding 仅 rules"是近似说法:精确地说 coding 场景命中的是 rules + session + baseagent(其余因 chatType/channel 为空而落选)。
|
|
307
|
-
|
|
308
|
-
## 环境层文档目录结构
|
|
309
|
-
|
|
310
|
-
venue-* 段从随包发布的通用文档(只读)取文件:
|
|
311
|
-
|
|
312
|
-
```
|
|
313
|
-
$KITS_DOCS/venues/ 通用环境文档(随包发布,只读)
|
|
314
|
-
├── private.md 单聊场景通用指引
|
|
315
|
-
├── group.md 群聊场景通用指引
|
|
316
|
-
├── aun-private.md AUN 单聊特有
|
|
317
|
-
├── aun-group.md AUN 群聊特有
|
|
318
|
-
├── feishu-private.md 飞书单聊特有
|
|
319
|
-
├── feishu-group.md 飞书群聊特有
|
|
320
|
-
├── client-desktop.md 桌面端环境
|
|
321
|
-
├── client-mobile.md 移动端环境
|
|
322
|
-
└── ...
|
|
323
|
-
```
|
|
324
|
-
|
|
325
|
-
> **注意**:具体群/私聊实例的 profile 数据落**关系层** `$RELATIONS_DIR/<peerKey>/profile.md`,
|
|
326
|
-
> 统一由 `peer-profile` 段注入,不在 venues 目录;群不会再通过另一个 section 重复加载。
|
|
327
|
-
|
|
328
|
-
## 输出结构
|
|
329
|
-
|
|
330
|
-
所有命中 section 的文件内容拼成一个块,注入 system prompt:
|
|
331
|
-
|
|
332
|
-
```
|
|
333
|
-
<system-reminder>
|
|
334
|
-
EvolCore Context Kit documents are shown below.
|
|
335
|
-
|
|
336
|
-
Contenu de <展示路径> (<id — description>):
|
|
337
|
-
|
|
338
|
-
<文件内容>
|
|
339
|
-
|
|
340
|
-
...(每个文件一段,按 order)
|
|
341
|
-
|
|
342
|
-
IMPORTANT: Use this context when it affects the current interaction.
|
|
343
|
-
</system-reminder>
|
|
344
|
-
```
|
|
345
|
-
|
|
346
|
-
展示路径会把绝对路径回缩成 `$KITS_RULES`/`$AGENT_DIR` 等别名。`needsInjection:true` 的段额外单独汇总到 `fragments-*.md` 调试文件(见下)。
|
|
347
|
-
|
|
348
|
-
## 调试机制(看实际渲染结果)
|
|
349
|
-
|
|
350
|
-
每次渲染都把结果落盘到 **`$EVOLCORE_HOME/data/eck-debug/`**,文件名带时间戳(`<字段>-YYYY-MM-DD-HH-MM-SS`):
|
|
351
|
-
|
|
352
|
-
| 文件 | 内容 |
|
|
353
|
-
|------|------|
|
|
354
|
-
| `vars-<ts>.json` | 本次注入的全部 vars 真值 + 每个变量的中文说明 |
|
|
355
|
-
| `context-<ts>.md` | 最终注入 base agent 的完整 `<system-reminder>` 块(即上面"输出结构"的实际产物) |
|
|
356
|
-
| `fragments-<ts>.md` | 仅经过模板渲染(needsInjection)的段,单独汇总,便于核对 `{{}}` 替换是否正确 |
|
|
357
|
-
| `manifest-<ts>.md` | **诊断报告**:每个 section 的 when 是否通过、路径解析状态(ok/unresolved-vars/not-exist/skipped)、是否被用上、是否注入;含未解析占位符清单 |
|
|
358
|
-
|
|
359
|
-
排查"某段为什么没出现":看 `manifest-<ts>.md` 里该 section 的 `status` 和 `unresolved tokens`。看"实际给 agent 的全文":读 `context-<ts>.md`。
|
|
360
|
-
|
|
361
|
-
调试文件保留 24 小时,`cleanEckDebug` 自动清理过期的。
|
|
362
|
-
|
|
363
|
-
## 缓存与热加载
|
|
364
|
-
|
|
365
|
-
- **manifest 缓存**:`_manifestCache`,进程内只加载一次。改了 manifest 需触发 `invalidateKitCache()`(或重启)才生效。
|
|
366
|
-
- **文件内容缓存**:`_sessionPathCache` 按 `sessionId` 缓存已读文件内容;`invalidateSessionCache(sessionId)` 清单个会话。
|
|
367
|
-
- rules / fragments / docs 这些 `kits/` 下的文件,改完一般随会话重建生效(缓存按会话隔离);manifest 本身的结构改动需要 invalidate。
|
|
295
|
+
| 30 | relation-layer | fragment | chatType∈{private,group} | ✓ |
|
|
296
|
+
| 35 | peer-profile | `$RELATIONS_DIR/{{peerKey}}/profile.md` | peerKey≠null | ✗ |
|
|
297
|
+
| 40 | venue-fragment | fragment | chatType≠null | ✓ |
|
|
298
|
+
| 41 | venue-chattype | `$KITS_DOCS/venues/{{chatType}}.md` | chatType≠null | ✗ |
|
|
299
|
+
| 42 | venue-channel-chattype | `$KITS_DOCS/venues/{{channel}}-{{chatType}}.md` | chatType≠null | ✗ |
|
|
300
|
+
| 44 | venue-client | `$KITS_DOCS/venues/client-{{clientType}}.md` | clientType≠null | ✗ |
|
|
301
|
+
| 50 | channel-layer | fragment | channel≠null | ✓ |
|
|
302
|
+
| 55 | commands | fragment | channel≠null | ✓ |
|
|
303
|
+
| 60 | session | fragment | always | ✓ |
|
|
304
|
+
| 70 | baseagent | fragment | baseAgent≠null | ✓ |
|
|
305
|
+
|
|
306
|
+
> 注意:`session`(60) 是 `always`,`baseagent`(70) 只看 `baseAgent` 是否注入——这两段**与 chatType 无关**,coding 场景也会加载。所谓"coding 仅 rules"是近似说法:精确地说 coding 场景命中的是 rules + session + baseagent(其余因 chatType/channel 为空而落选)。
|
|
307
|
+
|
|
308
|
+
## 环境层文档目录结构
|
|
309
|
+
|
|
310
|
+
venue-* 段从随包发布的通用文档(只读)取文件:
|
|
311
|
+
|
|
312
|
+
```
|
|
313
|
+
$KITS_DOCS/venues/ 通用环境文档(随包发布,只读)
|
|
314
|
+
├── private.md 单聊场景通用指引
|
|
315
|
+
├── group.md 群聊场景通用指引
|
|
316
|
+
├── aun-private.md AUN 单聊特有
|
|
317
|
+
├── aun-group.md AUN 群聊特有
|
|
318
|
+
├── feishu-private.md 飞书单聊特有
|
|
319
|
+
├── feishu-group.md 飞书群聊特有
|
|
320
|
+
├── client-desktop.md 桌面端环境
|
|
321
|
+
├── client-mobile.md 移动端环境
|
|
322
|
+
└── ...
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
> **注意**:具体群/私聊实例的 profile 数据落**关系层** `$RELATIONS_DIR/<peerKey>/profile.md`,
|
|
326
|
+
> 统一由 `peer-profile` 段注入,不在 venues 目录;群不会再通过另一个 section 重复加载。
|
|
327
|
+
|
|
328
|
+
## 输出结构
|
|
329
|
+
|
|
330
|
+
所有命中 section 的文件内容拼成一个块,注入 system prompt:
|
|
331
|
+
|
|
332
|
+
```
|
|
333
|
+
<system-reminder>
|
|
334
|
+
EvolCore Context Kit documents are shown below.
|
|
335
|
+
|
|
336
|
+
Contenu de <展示路径> (<id — description>):
|
|
337
|
+
|
|
338
|
+
<文件内容>
|
|
339
|
+
|
|
340
|
+
...(每个文件一段,按 order)
|
|
341
|
+
|
|
342
|
+
IMPORTANT: Use this context when it affects the current interaction.
|
|
343
|
+
</system-reminder>
|
|
344
|
+
```
|
|
345
|
+
|
|
346
|
+
展示路径会把绝对路径回缩成 `$KITS_RULES`/`$AGENT_DIR` 等别名。`needsInjection:true` 的段额外单独汇总到 `fragments-*.md` 调试文件(见下)。
|
|
347
|
+
|
|
348
|
+
## 调试机制(看实际渲染结果)
|
|
349
|
+
|
|
350
|
+
每次渲染都把结果落盘到 **`$EVOLCORE_HOME/data/eck-debug/`**,文件名带时间戳(`<字段>-YYYY-MM-DD-HH-MM-SS`):
|
|
351
|
+
|
|
352
|
+
| 文件 | 内容 |
|
|
353
|
+
|------|------|
|
|
354
|
+
| `vars-<ts>.json` | 本次注入的全部 vars 真值 + 每个变量的中文说明 |
|
|
355
|
+
| `context-<ts>.md` | 最终注入 base agent 的完整 `<system-reminder>` 块(即上面"输出结构"的实际产物) |
|
|
356
|
+
| `fragments-<ts>.md` | 仅经过模板渲染(needsInjection)的段,单独汇总,便于核对 `{{}}` 替换是否正确 |
|
|
357
|
+
| `manifest-<ts>.md` | **诊断报告**:每个 section 的 when 是否通过、路径解析状态(ok/unresolved-vars/not-exist/skipped)、是否被用上、是否注入;含未解析占位符清单 |
|
|
358
|
+
|
|
359
|
+
排查"某段为什么没出现":看 `manifest-<ts>.md` 里该 section 的 `status` 和 `unresolved tokens`。看"实际给 agent 的全文":读 `context-<ts>.md`。
|
|
360
|
+
|
|
361
|
+
调试文件保留 24 小时,`cleanEckDebug` 自动清理过期的。
|
|
362
|
+
|
|
363
|
+
## 缓存与热加载
|
|
364
|
+
|
|
365
|
+
- **manifest 缓存**:`_manifestCache`,进程内只加载一次。改了 manifest 需触发 `invalidateKitCache()`(或重启)才生效。
|
|
366
|
+
- **文件内容缓存**:`_sessionPathCache` 按 `sessionId` 缓存已读文件内容;`invalidateSessionCache(sessionId)` 清单个会话。
|
|
367
|
+
- rules / fragments / docs 这些 `kits/` 下的文件,改完一般随会话重建生效(缓存按会话隔离);manifest 本身的结构改动需要 invalidate。
|