@v587d/capital-generation 0.0.0-stage → 2.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +814 -0
- package/LICENSE +21 -0
- package/README.md +118 -2
- package/assets/cg-icon.png +0 -0
- package/capital-config/client.js +28 -0
- package/capital-config/client.src.cjs +388 -0
- package/capital-config/index.js +113 -0
- package/capital-config/package.json +36 -0
- package/capital-watchlist/client.js +182 -0
- package/capital-watchlist/client.src.cjs +1229 -0
- package/capital-watchlist/index.js +772 -0
- package/capital-watchlist/package.json +37 -0
- package/chart-ui/README.md +112 -0
- package/chart-ui/client.js +16 -0
- package/chart-ui/client.src.cjs +126 -0
- package/chart-ui/index.js +205 -0
- package/chart-ui/package.json +30 -0
- package/cordis.patch.yml +72 -0
- package/lib/agents/bash-guard.d.ts +55 -0
- package/lib/agents/bash-guard.js +162 -0
- package/lib/agents/root-tool-policy.d.ts +164 -0
- package/lib/agents/root-tool-policy.js +309 -0
- package/lib/chart/artifact-ref.d.ts +65 -0
- package/lib/chart/artifact-ref.js +107 -0
- package/lib/chart/downsample.d.ts +8 -0
- package/lib/chart/downsample.js +53 -0
- package/lib/chart/errors.d.ts +16 -0
- package/lib/chart/errors.js +15 -0
- package/lib/chart/events.d.ts +120 -0
- package/lib/chart/events.js +471 -0
- package/lib/chart/html.d.ts +21 -0
- package/lib/chart/html.js +154 -0
- package/lib/chart/runtime.d.ts +20 -0
- package/lib/chart/runtime.js +270 -0
- package/lib/chart/series.d.ts +102 -0
- package/lib/chart/series.js +424 -0
- package/lib/chart/source-token.d.ts +64 -0
- package/lib/chart/source-token.js +217 -0
- package/lib/chart/spec.d.ts +58 -0
- package/lib/chart/spec.js +265 -0
- package/lib/chart/tool.d.ts +86 -0
- package/lib/chart/tool.js +288 -0
- package/lib/chart/vendor/LICENSE +201 -0
- package/lib/chart/vendor/VERSION.json +8 -0
- package/lib/chart/vendor/lightweight-charts.standalone.production.js +7 -0
- package/lib/data-collector/args.d.ts +38 -0
- package/lib/data-collector/args.js +114 -0
- package/lib/data-collector/dataset-tools.d.ts +3 -0
- package/lib/data-collector/dataset-tools.js +421 -0
- package/lib/data-collector/describe.d.ts +99 -0
- package/lib/data-collector/describe.js +256 -0
- package/lib/data-collector/hub.d.ts +187 -0
- package/lib/data-collector/hub.js +469 -0
- package/lib/data-collector/query-time.d.ts +58 -0
- package/lib/data-collector/query-time.js +101 -0
- package/lib/data-collector/query.d.ts +57 -0
- package/lib/data-collector/query.js +473 -0
- package/lib/data-collector/store.d.ts +499 -0
- package/lib/data-collector/store.js +1486 -0
- package/lib/data-collector/time-axis.d.ts +169 -0
- package/lib/data-collector/time-axis.js +419 -0
- package/lib/data-collector/tools.d.ts +32 -0
- package/lib/data-collector/tools.js +216 -0
- package/lib/index.d.ts +275 -0
- package/lib/index.js +458 -0
- package/lib/net/eastmoney-client.d.ts +104 -0
- package/lib/net/eastmoney-client.js +118 -0
- package/lib/net/throttle.d.ts +16 -0
- package/lib/net/throttle.js +34 -0
- package/lib/ocr/client.d.ts +82 -0
- package/lib/ocr/client.js +281 -0
- package/lib/ocr/markdown.d.ts +75 -0
- package/lib/ocr/markdown.js +209 -0
- package/lib/ocr/store.d.ts +119 -0
- package/lib/ocr/store.js +226 -0
- package/lib/sources/eastmoney-http.d.ts +2 -0
- package/lib/sources/eastmoney-http.js +1253 -0
- package/lib/sources/fuyao-core.d.ts +52 -0
- package/lib/sources/fuyao-core.js +96 -0
- package/lib/sources/fuyao-rest.d.ts +14 -0
- package/lib/sources/fuyao-rest.js +2057 -0
- package/lib/sources/security-code.d.ts +27 -0
- package/lib/sources/security-code.js +104 -0
- package/lib/sources/security-identity.d.ts +24 -0
- package/lib/sources/security-identity.js +89 -0
- package/lib/sources/tencent-http.d.ts +2 -0
- package/lib/sources/tencent-http.js +1053 -0
- package/lib/sources/wind-mcp.d.ts +8 -0
- package/lib/sources/wind-mcp.js +593 -0
- package/lib/time/tools.d.ts +74 -0
- package/lib/time/tools.js +464 -0
- package/lib/tool-exec.d.ts +29 -0
- package/lib/tool-exec.js +17 -0
- package/lib/web-retriever/engines.d.ts +61 -0
- package/lib/web-retriever/engines.js +202 -0
- package/lib/web-retriever/html-markdown.d.ts +50 -0
- package/lib/web-retriever/html-markdown.js +321 -0
- package/lib/web-retriever/local-fetch.d.ts +121 -0
- package/lib/web-retriever/local-fetch.js +562 -0
- package/lib/web-retriever/retriever.d.ts +58 -0
- package/lib/web-retriever/retriever.js +94 -0
- package/lib/web-retriever/sources.d.ts +235 -0
- package/lib/web-retriever/sources.js +961 -0
- package/lib/web-retriever/tools.d.ts +50 -0
- package/lib/web-retriever/tools.js +1029 -0
- package/lib/web-retriever/wind-client.d.ts +69 -0
- package/lib/web-retriever/wind-client.js +311 -0
- package/locale/en.json +6 -0
- package/locale/zh.json +6 -0
- package/package.json +84 -4
- package/preset/capital-generation/README.md +161 -0
- package/preset/capital-generation/agent.patch.yml +509 -0
- package/preset/capital-generation/skills/capital-chart-protocol/SKILL.md +137 -0
- package/preset/capital-generation/skills/capital-data-protocol/SKILL.md +416 -0
- package/preset/capital-generation/skills/capital-orchestration/SKILL.md +174 -0
- package/preset/capital-generation/skills/capital-visualization-protocol/SKILL.md +296 -0
- package/preset/capital-generation/skills/capital-web-protocol/SKILL.md +240 -0
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: capital-data-protocol
|
|
3
|
+
description: Use when composing or reading a Capital data message — data_request, per-Dataset dataset_ready, data_failed, data_collection_completed, profile and query payloads, freshness, capability selection, retry discipline, and disclosure fields.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Capital 数据协议(完整版)
|
|
7
|
+
|
|
8
|
+
主 Agent 与 `data_collector` / `data_junior` 之间的消息载荷契约。三个角色的 persona 只保留
|
|
9
|
+
每轮都要生效的硬规则;字段级细节、示例与重试表在本文件。载荷即接口,字段名、数值、日期
|
|
10
|
+
一律不改写。
|
|
11
|
+
|
|
12
|
+
## 0. 谁读哪一节(三个角色动手前都应先加载本 skill)
|
|
13
|
+
|
|
14
|
+
| 角色 | 需要 | 说明 |
|
|
15
|
+
|---|---|---|
|
|
16
|
+
| 主 Agent | §1、§3、§4、§5 | 发请求、收回传、输出披露字段 |
|
|
17
|
+
| `data_collector` | §1、§1.1、§2、§5 | 收请求、能力发现两步、回传载荷、重试纪律 |
|
|
18
|
+
| `data_junior` | §3、§3.1、§4、§5 | 质检回传、数据缺口、受控查询、重试纪律 |
|
|
19
|
+
|
|
20
|
+
## 1. 数据请求(主 Agent → data_collector)
|
|
21
|
+
|
|
22
|
+
```json
|
|
23
|
+
{
|
|
24
|
+
"type": "data_request",
|
|
25
|
+
"task_id": "task_01J...",
|
|
26
|
+
"description": "贵州茅台近一年日线",
|
|
27
|
+
"capability": "history",
|
|
28
|
+
"params": { "thscode": "600519.SH", "interval": "1d" },
|
|
29
|
+
"force_refresh": false
|
|
30
|
+
}
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
| 字段 | 规则 |
|
|
34
|
+
|------|------|
|
|
35
|
+
| `type` | 固定 `data_request` |
|
|
36
|
+
| `task_id` | 同一任务复用同一个值,便于回传对账 |
|
|
37
|
+
| `description` | 用自然语言写清要什么数据;也可含标的、区间、频率 |
|
|
38
|
+
| `capability` | 可选。明确知道能力名时才指定;省略时由 `data_collector` 走下面 §1.1 的两步发现 |
|
|
39
|
+
| `params` | 按该 capability 的 `input_schema` 填写;标的使用完整代码(如 `600519.SH`),不自行拼接交易所后缀。腾讯 fallback 使用 `tencent_quote` / `tencent_kline`,不要改写成已有 `quote` / `history` |
|
|
40
|
+
| `force_refresh` | `false`/省略:宿主可复用当前 session 内未过期且满足该能力缓存新鲜度的 Dataset;`true`:强制重新取数并生成新的不可变 Dataset,**绝不覆盖旧文件**。用户要求“现在/最新”的快照时传 `true`;保留 7 天不代表行情仍是最新 |
|
|
41
|
+
|
|
42
|
+
硬规则:
|
|
43
|
+
|
|
44
|
+
- 委派消息只带需求与参数,**不带任何内部数据源键名**,也不携带原始数据行。
|
|
45
|
+
- 能力名一律以 `list_capabilities` 返回的目录为准,不要编造。
|
|
46
|
+
- 本角色只收结构化行集:公告 / 研报 / 新闻**正文**不是数据集的内容,回告主 Agent 改走 `web_retriever`;
|
|
47
|
+
行上的标题、简称这类标注字段算数据,整篇正文不算。
|
|
48
|
+
- 一次 `request_data` 只请求一个能力,按已发现的依赖与证据价值串行推进;**没有单回合能力数量上限**。先确定问题所需事实与缺口,再按来源、资产类型、时间粒度挑相关能力;不为凑数量遍历目录。遇到 `data_gap` 可继续补数,数据充分或上游不可用时停止。
|
|
49
|
+
- 含义相近的能力不自动互换:例如 Fuyao `history` 仅日线,腾讯 `tencent_kline` 支持近期分钟线;按 `describe_capability` 核对粒度、字段与单位,来源切换须写进回传。
|
|
50
|
+
- `task_id` 由主 Agent 在本轮首次委派前确定;同一用户任务的 data_collector、data_junior 与 visualization 必须原样复用。data_collector 不得自行生成或改写 task_id,缺失时应拒绝请求并回告主 Agent。
|
|
51
|
+
|
|
52
|
+
## 1.1 能力发现(data_collector 侧:两步,且各只做一次)
|
|
53
|
+
|
|
54
|
+
| 步 | 工具 | 得到什么 | 调用纪律 |
|
|
55
|
+
|----|------|----------|----------|
|
|
56
|
+
| ① | `list_capabilities()` | 纯文本能力目录:**一行一条** `capability\|summary\|paginated`(1=分页、0=不分页) | **一个任务只调一次**;目录已在本 session 历史里,重复调用只会白占上下文 |
|
|
57
|
+
| ② | `describe_capability({ capability })` | 该能力的完整 `description` / `input_schema` / `output_fields`(逐行字段字典) | 一次只传**一个**名字、**不传逗号**;同一个能力描述一次即可;要几个能力就分别调用几次 |
|
|
58
|
+
|
|
59
|
+
- 读目录时**按行切**:一行就是一条能力,取第一个 `|` 前面的部分当 `capability` 原样复制;摘要里出现的
|
|
60
|
+
`\|`、`\n` 是转义字符,不是分隔符。
|
|
61
|
+
- `output_fields` 每行是 `字段路径:类型[:说明]`:后缀 `?` 表示上游可能给 `null`,`[].` 表示该字段在数组
|
|
62
|
+
元素上(`item[].thscode`),说明段写 `取值 a/b` 时该字段只允许这几个值。按它写 `query_dataset` 的
|
|
63
|
+
`select` / `filters` 列名,大小写与下划线原样照抄。
|
|
64
|
+
- 目录刻意不含参数与输出结构:全量 schema 约 23KB,会被工具结果剪枝器(阈值 8192)截断中间
|
|
65
|
+
部分,导致排在中间的能力在发现阶段不可见。目录只负责"选哪个",详情负责"怎么填"。
|
|
66
|
+
- **一个任务只调一次 `list_capabilities`**;**同一个能力只描述一次**,重复调用只会白占上下文。
|
|
67
|
+
- 不查 `input_schema` 就填 `params` 属于违规;`params` 的取值与约束一律以 `describe_capability` 为准。
|
|
68
|
+
|
|
69
|
+
`describe_capability` 的错误按 code 处置,不要盲目重试:
|
|
70
|
+
|
|
71
|
+
| code | 含义 | 正确动作 |
|
|
72
|
+
|------|------|----------|
|
|
73
|
+
| `capability_required` | 没给名字(缺失或空白) | 先调一次 `list_capabilities`,把目录里的名字原样传入 |
|
|
74
|
+
| `capability_invalid` | 不是字符串 / 超长 / 含逗号 | 改成单个字符串名字后重试一次;多个能力分多次调用 |
|
|
75
|
+
| `capability_unknown` | 名字不在目录里(错误信息会列出全部可用名字) | 从列出的名字里原文复制重来;不编造、不缩写、不改写 |
|
|
76
|
+
| `capability_catalog_empty` | 当前没有任何已注册能力(数据源注册没生效;**缺凭据不会让目录变空**,只会在取数那一刻点名凭据失败) | **不要重试**(此刻任何名字都会失败);用 `dc_status` 核对 `registered_capabilities` 与 `api_key`,如实回告主 Agent |
|
|
77
|
+
| `request_params_invalid` | `request_data` 的 `params` 不符合该能力契约(错误会保留具体字段原因) | 先按错误中的 capability 调 `describe_capability({"capability":"..."})`,重新读取 `input_schema`,修正后只重试一次;不要凭记忆猜参数。网络、超时、落盘错误不要走这条路径 |
|
|
78
|
+
|
|
79
|
+
## 2. 逐份回传(data_collector → 主 Agent)
|
|
80
|
+
|
|
81
|
+
每次 `request_data` 返回后立即 `send_message`,成功时每条只含**一份** DatasetRef(缓存命中也一样):
|
|
82
|
+
|
|
83
|
+
```json
|
|
84
|
+
{
|
|
85
|
+
"type": "dataset_ready",
|
|
86
|
+
"task_id": "task_01J...",
|
|
87
|
+
"request_index": 1,
|
|
88
|
+
"datasets": [
|
|
89
|
+
{
|
|
90
|
+
"dataset_id": "ds_01J...",
|
|
91
|
+
"artifact_ref": "workspace://capital-data/datasets/ds_01J...",
|
|
92
|
+
"format": "json_rows",
|
|
93
|
+
"capability": "history",
|
|
94
|
+
"source_label": "fuyao",
|
|
95
|
+
"schema": { "columns": ["date_ms", "open_price", "high_price", "low_price", "close_price", "volume", "turnover"] },
|
|
96
|
+
"row_count": 240,
|
|
97
|
+
"captured_at": 1780000000000,
|
|
98
|
+
"retention_until": 1780604800000
|
|
99
|
+
}
|
|
100
|
+
]
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
某次请求最终失败也立即回告(`request_index` 从本次委派的 1 开始,翻页或重复能力也各占一次):
|
|
105
|
+
|
|
106
|
+
```json
|
|
107
|
+
{ "type": "data_failed", "task_id": "task_01J...", "request_index": 2, "capability": "history", "error": "request timed out" }
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
所有请求处理完后**另发一条**终结消息,即使全部失败也必须发:
|
|
111
|
+
|
|
112
|
+
```json
|
|
113
|
+
{
|
|
114
|
+
"type": "data_collection_completed",
|
|
115
|
+
"task_id": "task_01J...",
|
|
116
|
+
"dataset_ids": ["ds_01J..."],
|
|
117
|
+
"failed": [{ "request_index": 2, "capability": "history", "error": "request timed out" }],
|
|
118
|
+
"gaps": ["尚未取得该标的的历史分钟线"]
|
|
119
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
硬规则:
|
|
123
|
+
|
|
124
|
+
- 回传必须携带结构化载荷;可以附表格或摘要,但**禁止只回传 markdown 汇总**。
|
|
125
|
+
- 每份成功 Dataset(含缓存命中)立刻通知主 Agent,下一次 `request_data` 不必等 data_junior 处理完;分页若每页都调用 `request_data`,每页分别通知。终结消息只汇总 id / 失败 / 缺口,不重复塞 DatasetRef,也不由 data_collector 直接找 data_junior。
|
|
126
|
+
- `data_failed` 只结束该次请求;只有 `data_collection_completed` 才结束本次委派。未发出终结消息前,主 Agent 不得把任意一次进度通知或子 Agent 结算当作取数完成。若 junior 在已结算后发 `data_gap`,主 Agent 再次委派同一个 collector,此次补数也须逐份回传并另发终结消息。
|
|
127
|
+
- 每个 `data_failed` 和终结消息里的失败项必须包含真实 `error`,只有工具返回了 `code` 才附带原值,不能把错误文本编造成 code。
|
|
128
|
+
- `dataset_id` / `artifact_ref` / `capability` / `source_label` / `schema` / `row_count` /
|
|
129
|
+
`captured_at` / `retention_until` 按工具返回**原样填入**,字段名、数值、日期不改写。
|
|
130
|
+
- 载荷中不得出现原始数据行、内部数据源键名或文件绝对路径。
|
|
131
|
+
- 主 Agent 收到后把 DatasetRef 记入委派清单,后续引用一律原样转达 `artifact_ref`,
|
|
132
|
+
不自行改写、不自行拼路径。
|
|
133
|
+
- Dataset 默认保留 **7 天**(以 `retention_until` 为准),到期后需重新取数。
|
|
134
|
+
|
|
135
|
+
## 3.0 读取 Dataset 的默认入口:`describe_dataset`
|
|
136
|
+
|
|
137
|
+
`data_junior` 读一份 Dataset 用 **`describe_dataset`**(一次调用完成 inspect + profile + 可选 queries),
|
|
138
|
+
**不要再走 `inspect_dataset → profile_dataset → query_dataset` 三步**——那三步只保留给单点复核。
|
|
139
|
+
|
|
140
|
+
```json
|
|
141
|
+
{
|
|
142
|
+
"dataset_id": "ds_01J...",
|
|
143
|
+
"task_id": "task_01J...",
|
|
144
|
+
"columns_of_interest": ["close_price", "volume"],
|
|
145
|
+
"queries": [
|
|
146
|
+
{ "group_by": ["report_type"], "aggregates": [{ "function": "count", "as": "n" }], "limit": 20 }
|
|
147
|
+
]
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
- **一次一份**:一次调用只传一个 `dataset_id`。本轮有多份数据时,**在同一条 assistant 消息里一次发完**
|
|
152
|
+
多个调用(宿主会并发执行,结果一起返回),不要一份一份等。
|
|
153
|
+
- 返回 = inspect 元数据(`artifact_ref` / `capability` / `source_label` / `captured_at` / `retention_until` /
|
|
154
|
+
`query_access.shape`)+ profile 四类事实(`statistics` / `categories` / `time_facts` / `structure`)+
|
|
155
|
+
`profile_ref` + 每条 query 的 `result`,或该条自己的 `error`(单条失败不影响其余)。
|
|
156
|
+
- `shape = document` 时 queries **不执行**(宿主跳过并在 `warnings` 说明);文档内容在 `document`。
|
|
157
|
+
- `columns_of_interest` 只对这些列返回 `statistics` / `categories` / `schema`(并同样收窄 `time_facts` 的首末值投影;时间列永远保留),是收窄结果体积的唯一手段。
|
|
158
|
+
- **体积闸门**:结果超过 7000 码点时返回
|
|
159
|
+
`{"status":"too_large","profile_ref":"...","columns":[...],"hint":"..."}`,而不是超长载荷。
|
|
160
|
+
按 hint 用 `columns_of_interest`(或减少 `queries`,一次最多 8 条)重发一次;文档型按 hint 直接调
|
|
161
|
+
`profile_dataset`。**看到 `too_large` 不是失败**——它带着完整列名,用来让你收窄。
|
|
162
|
+
- 单点复核(只看元数据 / 只要一份完整 profile / 补一条查询)仍可用 `inspect_dataset`、`profile_dataset`、
|
|
163
|
+
`query_dataset`。
|
|
164
|
+
|
|
165
|
+
## 3. 质检请求与回传(主 Agent ↔ data_junior)
|
|
166
|
+
|
|
167
|
+
请求:
|
|
168
|
+
|
|
169
|
+
```json
|
|
170
|
+
{
|
|
171
|
+
"type": "profile_request",
|
|
172
|
+
"task_id": "task_01J...",
|
|
173
|
+
"dataset_ids": ["ds_01J..."],
|
|
174
|
+
"question": "检查数据质量并给出基础统计"
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
- `dataset_ids` 一律取 `dataset_ready` 回传中的 `dataset_id` 原样值。
|
|
179
|
+
- 只带 DatasetRef 标识与问题描述,**绝不带原始数据行**。
|
|
180
|
+
|
|
181
|
+
回传:
|
|
182
|
+
|
|
183
|
+
```json
|
|
184
|
+
{
|
|
185
|
+
"type": "dataset_profile_completed",
|
|
186
|
+
"task_id": "task_01J...",
|
|
187
|
+
"dataset_id": "ds_01J...",
|
|
188
|
+
"profile_ref": "workspace://capital-data/profiles/p_01J...",
|
|
189
|
+
"row_count": 240,
|
|
190
|
+
"columns": ["date", "open", "high", "low", "close", "volume"],
|
|
191
|
+
"schema": {
|
|
192
|
+
"close": { "contract_type": "number", "inferred_type": "number", "missing_count": 0, "null_count": 0, "invalid_count": 0 }
|
|
193
|
+
},
|
|
194
|
+
"validation": { "status": "pass", "violations": [] },
|
|
195
|
+
"quality": { "missing_values": 0, "duplicate_rows": 0, "time_ordered": true },
|
|
196
|
+
"warnings": []
|
|
197
|
+
}
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
- `schema` 是字段类型和计数的有限摘要;完整 profile 以 `profile_ref` 为准,不把完整 profile 或 raw rows 放进消息。
|
|
201
|
+
- `validation.status=fail` 表示 profile 发现结构化 violations,不表示原始 Dataset 被删除或不可用。
|
|
202
|
+
- 主 Agent 可以在 collector 继续取数时逐份委派 data_junior,显式说「只到 profile」(包括必要的受控 queries);后续只送新到的 dataset_id,不重做已完成的 profile。等 `data_collection_completed` 和补数据回执后,再指示同一个 junior 综合已有结果并完成可视化 gate。
|
|
203
|
+
|
|
204
|
+
失败:`{ "type": "profile_failed", "task_id": "task_01J...", "error": "...", "code": "..." }`
|
|
205
|
+
|
|
206
|
+
`profile_dataset` 的四类事实(回传时按需引用,不要把整份 profile 抄进消息):
|
|
207
|
+
|
|
208
|
+
| 事实块 | 回答什么问题 |
|
|
209
|
+
|--------|--------------|
|
|
210
|
+
| `statistics`(count/sum/min/max/mean/分位数) | 合计多少、覆盖多少条、区间与集中度 |
|
|
211
|
+
| `categories`(distinct_count + 最多 5 个高频取值) | 有哪些类别、分布如何;`truncated=true` 表示未列全 |
|
|
212
|
+
| `time_facts`(覆盖范围 + 首行/末行取值 + `axis` + `windows`) | 最新值、区间涨跌,以及**这份数据的时间轴怎么读**(见 §3.2)。**必须**用 `first`/`last`;min/max 只是区间极值,把它讲成走势就是编造 |
|
|
213
|
+
| `structure`(路径 + total_elements 或 sampled_elements) | 嵌套里一共有多少条。对象字段用 `.name`、数组元素用 `[]`,未抽样时例如 `sub_tab[].fund_list` 的 `total_elements=40` 就是 40 只基金;若出现 `sampled_elements=50`,只能说明实际检查了 50 项,不是完整数量 |
|
|
214
|
+
|
|
215
|
+
### 3.2 时间轴:日历由宿主换算,不要自己算毫秒
|
|
216
|
+
|
|
217
|
+
`time_facts` 除覆盖范围与首末行外,还给出**这份数据的时间轴怎么读**:
|
|
218
|
+
|
|
219
|
+
| 字段 | 含义 | 怎么用 |
|
|
220
|
+
|---|---|---|
|
|
221
|
+
| `axis.value_format` | `epoch_ms`(毫秒整数时间列)/ `date_string`(已是 `YYYY-MM-DD`)/ `unknown`(推断不出:先 inspect 或显式传 `time_column`) | `unknown` 时不要假设粒度 |
|
|
222
|
+
| `axis.time_zone` / `axis.utc_offset` | 该列**自身观测到**的时区偏移(如 `Asia/Shanghai` / `+08:00`) | 判断"某天"的边界一律按它,不要按 UTC 猜 |
|
|
223
|
+
| `axis.aligned_to` | `local_midnight` = 取值是当地 00:00 的瞬间(A 股日线的 `date_ms` 就是这样) | 这种列的"当天"要用 `>= 当天午夜` 且 `<= 当天日末` 两个条件才算 |
|
|
224
|
+
| `covered_from_iso` / `covered_to_iso` | 覆盖范围的可读日期 | 回答"数据到哪天",不要再做 epoch→日期换算 |
|
|
225
|
+
| `windows[]` | 近 1 月 / 近 3 月 / 近 1 年 / 年初至今的现成边界:`value_ge`、`value_le`(可直接填进 filter)与 `data_from`、`data_to`(该窗口在数据里**真实存在**的首末日期) | 命中就直接用;`data_from` 已把非交易日夹到相邻交易日 |
|
|
226
|
+
|
|
227
|
+
需要 `windows` 之外的窗口(任意区间、某年某月、历年 10 月)时:
|
|
228
|
+
|
|
229
|
+
1. 调 `resolve_data_time_range`,传 `dataset_id` + `period`(可选 `anchor_date`);它按该 Dataset
|
|
230
|
+
时间列自身的偏移返回 `bounds.bound_ge` / `bounds.bound_le` 与 `range`、`data` 日期;
|
|
231
|
+
2. 把 `bound_ge` / `bound_le` 原样填进 filter,**不要**自己把日期算成毫秒。
|
|
232
|
+
|
|
233
|
+
`query_dataset` 的 filter 也**直接接受日历写法**(宿主按同一套偏移换算):
|
|
234
|
+
|
|
235
|
+
```jsonc
|
|
236
|
+
// 三种写法都表示"从 2026-08-23 起",选一种即可
|
|
237
|
+
{ "column": "date_ms", "operator": ">=", "value": "2026-08-23" }
|
|
238
|
+
{ "column": "date_ms", "operator": ">=", "value": "2026-08" }
|
|
239
|
+
{ "column": "date_ms", "operator": ">=", "value": { "period": "last_1_month" } }
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
- `>=` 取该日当地午夜、`<=` 取该日当地日末、`=` 自动展开成"这一天"的上下界;省略锚点的
|
|
243
|
+
`period` 以该 Dataset 最后一天为准(数据陈旧时相对期不会落空);
|
|
244
|
+
- 结果里时间列会附一列 `*_iso` 可读日期(原值保留,不替换);
|
|
245
|
+
- `>`、`<`、`!=`、`in` 配日期串会报 `query_type_conflict`:日期只有"整天"语义,用它们等于
|
|
246
|
+
悄悄换一天;要哪几天就直接写 `>=` / `<=`。
|
|
247
|
+
|
|
248
|
+
**硬规则:看到 epoch 毫秒要经过加减乘除才能得出结论时,就是走错了路。** 时间换算一律交给
|
|
249
|
+
`time_facts.axis`、`windows` 与 `resolve_data_time_range`;自己心算毫秒既慢又必然算错口径。
|
|
250
|
+
|
|
251
|
+
文档型 Dataset(顶层是文档对象、没有行数组,如财务指标、回测结果):`profile_dataset` 返回
|
|
252
|
+
`structure` 结构摘要 + `document` 有界内容(`$` 是文档根),**没有**行列统计,也不包含行数据专用的 `schema`/`validation`;`query_dataset`
|
|
253
|
+
对它无效。`document.truncated=true` 时必须按 `omitted` 逐条说明省略了哪个路径、保留多少、
|
|
254
|
+
省略多少,不得只说「已截断」。
|
|
255
|
+
|
|
256
|
+
硬规则:字段按工具返回原样填入;统计项只报告可计算的部分,数据不足如实说明;
|
|
257
|
+
profile 失败不影响原始 Dataset,可按指示重试。
|
|
258
|
+
|
|
259
|
+
### 3.3 bash:派生算术的兜底,不是第二条取数通道
|
|
260
|
+
|
|
261
|
+
只有 data_junior 有 `bash`。它存在的唯一理由是 `query_dataset` 的聚合只有
|
|
262
|
+
`count / min / max / avg / sum`——**变化量、增幅、CAGR、比值、单位换算**这类派生指标没有宿主
|
|
263
|
+
工具,硬心算既慢又容易错。
|
|
264
|
+
|
|
265
|
+
**可以做的**(拿手里已有的数字算):
|
|
266
|
+
|
|
267
|
+
```bash
|
|
268
|
+
node -e 'const a=98.2,b=120.5; console.log(((b-a)/a*100).toFixed(2))' # 区间涨幅
|
|
269
|
+
python3 -c "print((120.5/98.2)**(252/60)-1)" # 年化
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
**不许做的**(这是纪律,不是沙箱限制——沙箱只拦写,不拦读与网络):
|
|
273
|
+
|
|
274
|
+
| 不许 | 为什么 | 正确做法 |
|
|
275
|
+
|---|---|---|
|
|
276
|
+
| 读 `capital-data/**`、`raw.json` | 原始行**永不**进入你的上下文;而且工具结果会被剪枝成 head+tail,读了也算错 | 数值走 `describe_dataset` / `query_dataset` 的统计与聚合 |
|
|
277
|
+
| 读 `~/.dsh/**`、`sessions/**` | 那是宿主凭据与全部会话日志 | 不碰;需要元数据用工具回执 |
|
|
278
|
+
| 读 / 改 `preset/`、`src/`、`test/` | 那是装配与门禁本身 | 不碰 |
|
|
279
|
+
| `curl` / `wget` / 任何网络请求、`git clone`、`npm i`、`pip install` | 你的角色没有网络能力,外部材料只经主 Agent 转交 `web_retriever` | 缺外部事实就在回传里写明缺口 |
|
|
280
|
+
| 申请更高权限(`sandbox_permissions`) | 委派会话的审批策略被框架固定为 `never`,必然失败 | 不要试;缺数据发 `data_gap` |
|
|
281
|
+
|
|
282
|
+
另外两条:
|
|
283
|
+
|
|
284
|
+
- **输出只留结论数字**:bash 的工具结果同样会过剪枝器(>8192 字符中间段被剪掉),把中间过程
|
|
285
|
+
打印出来只会挤掉真正要看的东西;回传时注明算法与口径(如「按首末收盘价、未复权」)。
|
|
286
|
+
- **时间窗仍归宿主**:窗口边界一律用 `time_facts.windows` / `resolve_data_time_range`
|
|
287
|
+
(§3.2),不要用 `date` 命令自己造边界——口径错了数字就全错,而且没人会发现。
|
|
288
|
+
|
|
289
|
+
`profile_dataset` 的统计项:数值字段的 count 与 sum(合计多少、覆盖多少条)、字符串字段的
|
|
290
|
+
`distinct_count` 与高频取值、字段类型(observed / contract)、缺失值与显式 null、类型冲突、
|
|
291
|
+
重复主键、时间范围、最小/最大/均值/分位数——**只报告可计算的部分**,数据不足就如实说明。
|
|
292
|
+
|
|
293
|
+
## 3.1 数据缺口(data_junior → 主 Agent,中途主动发起)
|
|
294
|
+
|
|
295
|
+
data_junior 发现「问题需要的那份数据还没取」时(不是「数据里没有」),不等回合结束,
|
|
296
|
+
直接用 `send_message` 发一次:
|
|
297
|
+
|
|
298
|
+
```json
|
|
299
|
+
{
|
|
300
|
+
"type": "data_gap",
|
|
301
|
+
"task_id": "task_01J...",
|
|
302
|
+
"dataset_id": "ds_01J...",
|
|
303
|
+
"need": "该指数在 2025-06-30 的成分股权重明细",
|
|
304
|
+
"reason": "现有 Dataset 只有指数点位,没有成分字段",
|
|
305
|
+
"suggested_capability": "index_constituents",
|
|
306
|
+
"blocking": true
|
|
307
|
+
}
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
| 字段 | 规则 |
|
|
311
|
+
|------|------|
|
|
312
|
+
| `type` | 固定 `data_gap` |
|
|
313
|
+
| `task_id` / `dataset_id` | 必须带:主 Agent 可能同时在等多个回传,靠这两个字段对上号 |
|
|
314
|
+
| `need` | 用自然语言写清缺什么数据(标的、区间、口径) |
|
|
315
|
+
| `reason` | 说明为什么现有 Dataset 不够,避免主 Agent 重复取已有的数据 |
|
|
316
|
+
| `suggested_capability` | 可选。只能是**手上 DatasetRef 里出现过的 capability 原值**,或整个省略;不要为了填空编造能力名 |
|
|
317
|
+
| `blocking` | `true` = 不补齐无法继续,可以停在本轮等回信;`false` = 还有别的能先做 |
|
|
318
|
+
|
|
319
|
+
硬规则:
|
|
320
|
+
|
|
321
|
+
- `data_gap` 是请求不是结论。发出后不得把「无法确认」当终局;同一条缺口只发一次。
|
|
322
|
+
- 子 Agent **不得自行取数**,也不得直接找 `data_collector`:取数一律由主 Agent 中继。
|
|
323
|
+
- 主 Agent 处置:按委派清单复用对应角色取数 → 把新 DatasetRef 用 `send_message` 发回
|
|
324
|
+
**同一个**子 Agent(禁止新建同角色)→ 它接着做完。同参数的重新取数会命中宿主复用,
|
|
325
|
+
不会重复访问上游,所以该重取就重取。
|
|
326
|
+
- 取数失败时主 Agent 必须回一条失败消息(`data_failed` 或说明性文本)给它,
|
|
327
|
+
不能让它一直等:框架没有超时与订阅机制。
|
|
328
|
+
- **结束本轮 ≠ 任务完成。** 等数据的子 Agent 会先结束回合,结算通知里那句
|
|
329
|
+
「finished and will do no further work unless you send it more」在此时是误导;
|
|
330
|
+
清单里标为「等数据」的子 Agent,收到结算通知后不要认定完成、也不要新建。
|
|
331
|
+
- 只有确认「数据里确实没有该字段」时才回传能力边界,并写明是数据没有、不是没拿到数据。
|
|
332
|
+
|
|
333
|
+
## 4. 受控查询(主 Agent ↔ data_junior)
|
|
334
|
+
|
|
335
|
+
请求:
|
|
336
|
+
|
|
337
|
+
```json
|
|
338
|
+
{
|
|
339
|
+
"type": "query_request",
|
|
340
|
+
"task_id": "task_01J...",
|
|
341
|
+
"dataset_id": "ds_01J...",
|
|
342
|
+
"query": {
|
|
343
|
+
"dataset_id": "ds_01J...",
|
|
344
|
+
"select": ["symbol", "rows", "avg_close"],
|
|
345
|
+
"filters": [{ "column": "close_price", "operator": ">", "value": 100 }],
|
|
346
|
+
"group_by": ["symbol"],
|
|
347
|
+
"aggregates": [
|
|
348
|
+
{ "function": "count", "as": "rows" },
|
|
349
|
+
{ "function": "avg", "column": "close_price", "as": "avg_close" }
|
|
350
|
+
],
|
|
351
|
+
"order_by": [{ "column": "avg_close", "direction": "desc" }],
|
|
352
|
+
"limit": 100
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
- `query` 是固定 JSON QuerySpec,不是 SQL、表达式或脚本;`query_request` 消息可以原样作为 `query_dataset` 工具参数传入,宿主会展开其中的 `query`;也可直接传扁平 QuerySpec。`type` / `task_id` 只属于消息 envelope,不进入实际执行 QuerySpec。
|
|
358
|
+
- 只支持 `=`、`!=`、`>`、`>=`、`<`、`<=`、`in`、`is_null`、`not_null`,以及 `count`、`min`、`max`、`avg`、`sum`。
|
|
359
|
+
- 必须有 `group_by` 或聚合;`select` 可省略,省略时默认返回分组列与聚合别名;显式 `select` 只能引用分组列或聚合别名。禁止 join、window、having、自定义函数和 raw rows 投影。
|
|
360
|
+
- 默认 `error_policy=skip_with_warning`:过滤或数值聚合遇到不兼容脏值时排除该值并在 `warnings` 披露;需要类型全量一致时显式使用 `error_policy=strict`。
|
|
361
|
+
- 数组/对象字段(`select`、`group_by`、`aggregates`、`order_by`、`filters`)传**真正的 JSON 数组**,不要序列化成字符串再传;`limit` 传数字。宿主对字符串化的 JSON 做了宽容解析(实测模型很常这么传),但不要依赖它。
|
|
362
|
+
- **时间列筛选写日历,不写毫秒**:`date_ms` 这类 epoch 列的 filter 值可直接写 `"2026-08-23"`、
|
|
363
|
+
`"2026-08"`、`"2026"` 或 `{ "period": "last_1_month" }`,宿主按该列自身偏移换算边界并自动在结果
|
|
364
|
+
里补 `*_iso`。写法、可用的 period 词表与禁止的算子见 §3.2——**不要**自己把日期算成毫秒。
|
|
365
|
+
同一条 QuerySpec 在 **`describe_dataset` 的 `queries` 与 `query_dataset` 里完全等价**(同一份归一、
|
|
366
|
+
同样的错误码),不必因为"想确认某个入口行不行"而重复试。
|
|
367
|
+
- `query_dataset` 取不到原始行:`select` 只能引用分组列或聚合别名,所以「首末/最新值」要用
|
|
368
|
+
profile 的 `time_facts`——`time_facts` 已经给了首末行取值,不要用 query 去取。
|
|
369
|
+
- `query_dataset` 是受控分组/聚合透视查询,不是通用 raw.json 读取器,也不替代基础描述性 profile。对市场指数、指数组成、基金重仓股等不适合当前 QuerySpec 的数据,不要强行改写查询;不足以回答时如实回传能力边界。自定义查询脚本和自定义执行脚本属于后续 `data_analyst`,不得转移给 data_junior。
|
|
370
|
+
|
|
371
|
+
完成回传:
|
|
372
|
+
|
|
373
|
+
```json
|
|
374
|
+
{
|
|
375
|
+
"type": "dataset_query_completed",
|
|
376
|
+
"task_id": "task_01J...",
|
|
377
|
+
"dataset_id": "ds_01J...",
|
|
378
|
+
"query_result": {
|
|
379
|
+
"columns": ["symbol", "rows", "avg_close"],
|
|
380
|
+
"rows": [{ "symbol": "600519.SH", "rows": 20, "avg_close": 1680.5 }],
|
|
381
|
+
"matched_row_count": 20,
|
|
382
|
+
"group_count": 1,
|
|
383
|
+
"returned_count": 1,
|
|
384
|
+
"limit": 100,
|
|
385
|
+
"warnings": []
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
失败:`{ "type": "query_failed", "task_id": "task_01J...", "dataset_id": "ds_01J...", "error": "...", "code": "query_type_conflict" }`
|
|
391
|
+
|
|
392
|
+
- `query_result.rows` 只能是有限分组键与聚合结果,不得出现未聚合 Dataset row、文件路径、内部路由键或凭据。
|
|
393
|
+
|
|
394
|
+
## 5. 重试纪律
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
| 错误类型 | 例子 | 处理 |
|
|
398
|
+
|----------|------|------|
|
|
399
|
+
| 参数类 | 缺参、格式错、枚举越界 | 对照 `input_schema` 的 enum/description 修正后重试 |
|
|
400
|
+
| 瞬时类 | 限流、上游超时、网络 | 重试 1 次 |
|
|
401
|
+
| 执行超时 | 约 30 秒超时 | 重试 1 次 |
|
|
402
|
+
| 数据源/环境 | 无可用数据源、workspace 只读、落盘失败(`workspace_not_writable`) | 不回退、不假装成功,如实回传 `error`/`code` |
|
|
403
|
+
| 网页获取 | 网络或服务错误 | 最多重试 1 次,仍失败如实回传 |
|
|
404
|
+
|
|
405
|
+
底线:绝不幻觉填充数据,绝不用编造的来源补位,绝不声称数据已保存;
|
|
406
|
+
同一请求重试 2 次仍失败就回传 `failed` 并注明已重试,不再继续。
|
|
407
|
+
|
|
408
|
+
## 5. 输出必须披露的字段
|
|
409
|
+
|
|
410
|
+
- `capability`、`source_label`、抓取时间 `captured_at`;
|
|
411
|
+
- 交易日 / 报告期、时区;
|
|
412
|
+
- 缺失字段与数据截止时间;
|
|
413
|
+
- 情景假设标注为条件假设,不是统计概率或收益承诺。
|
|
414
|
+
|
|
415
|
+
原始数据行永远不进入主 Agent 的上下文:主 Agent 只拿到 DatasetRef、profile_ref 与元数据。
|
|
416
|
+
与第三方网页比对仅用于异常抽样核对,不把任何单一来源表述成绝对真实。
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: capital-orchestration
|
|
3
|
+
description: Use when delegating in Capital mode — running the per-round list_agents preflight, matching or reusing a data_collector / data_junior / web_retriever child by role label, deciding which role owns a request, recording a delegation checklist, or handling a preflight anomaly. Also indexes the exact data payloads in capital-data-protocol.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Capital 委派编排(完整版)
|
|
7
|
+
|
|
8
|
+
主 persona 只保留每轮都要生效的硬规则;本文件是同一套编排的完整细则、异常分支与清单格式。
|
|
9
|
+
规则冲突时以主 persona 为准。
|
|
10
|
+
|
|
11
|
+
## 1. 每轮预检(不可跳过)
|
|
12
|
+
|
|
13
|
+
- 触发点:**每次新的用户请求或新一轮任务**。在"本轮第一次调用任何创建工具"之前完成。
|
|
14
|
+
- 创建工具指:`subagent_data_collector`、`subagent_data_junior`、`subagent_web_retriever`、
|
|
15
|
+
`subagent`,以及今后新增的任何委派工具。
|
|
16
|
+
- 查询方式:`list_agents(scope="children")`,一次即可。
|
|
17
|
+
- 不要把它当成"仅在会话恢复时才做的回忆步骤":上一轮查到的空列表不能代替本轮查询。
|
|
18
|
+
- 一次查询结果覆盖本轮所有角色,不要为每个角色重复查询;等待回传期间也不要轮询。
|
|
19
|
+
|
|
20
|
+
## 1.1 Canonical task_id(不可分叉)
|
|
21
|
+
|
|
22
|
+
主 Agent 在本轮第一次委派前先确定一个唯一的 `task_id`,并把它原样写入所有 `data_collector`、`data_junior` 和需要可视化的任务 prompt。子 Agent 不得自行生成替代 task_id;收到缺失或不同值时必须回告主 Agent,不要默默创建新任务。
|
|
23
|
+
|
|
24
|
+
委派清单的 `task_id` 是授权账本,不是描述性备注。`DatasetRef.task_id`、`profile_ref.task_id`、`chart_source_ref` 和 `chart_ref` 必须能沿同一个值对账。引用 chart receipt 前先核对它绑定的 task;若错误返回 `expected_task_id`,使用错误中给出的实际绑定值修正,不要猜测或反复试不同 id。
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
只处理 `kind=child` 的条目。按 `label` 精确匹配三个稳定角色标签:`data_collector`、
|
|
28
|
+
`data_junior`、`web_retriever`。
|
|
29
|
+
|
|
30
|
+
1. **标签非标准但已映射**:历史 child 的 label 仍是旧任务标题时,只要委派清单或工具回执
|
|
31
|
+
已经把它映射到某个角色的 durable id,就必须沿用该 id,不得因为 label 非标准而新建。
|
|
32
|
+
2. **状态判定**:同角色只要存在 `running`、`idle` 或 `ready` 任一状态,立即用该 id 调用
|
|
33
|
+
`send_message` 派发本次任务。
|
|
34
|
+
- `running` 会在其最近的 step 边界接收消息;
|
|
35
|
+
- `idle` 会开始一个新回合;
|
|
36
|
+
- `ready` 会冷恢复后继续。
|
|
37
|
+
不得因为"空闲""上一任务已完成""任务标题变了""想并行"而创建第二个同角色 Agent。
|
|
38
|
+
3. **诊断/暂时不可用**:已记录 id 但列表出现 diagnostic 或暂时不可用,先用该 id 尝试
|
|
39
|
+
`send_message`,或重新 `list_agents` 核验;不得直接创建第二个同角色 Agent。
|
|
40
|
+
4. **确实不存在**:只有确认该 child 不存在且没有可用复用 id,才进入创建分支。
|
|
41
|
+
|
|
42
|
+
### 2.1 ID 纪律(防长上下文抄错 id)
|
|
43
|
+
|
|
44
|
+
child id 是随机 UUID、无语义可校验,长会话里凭记忆/从历史轮次复述 id 极易抄错,甚至把
|
|
45
|
+
A 角色的请求投给 B 角色。官方机制是 **`list_agents` 即权威 id 存储**——id 不需要被记住,
|
|
46
|
+
只需要在用之前 freshly 查一次:
|
|
47
|
+
|
|
48
|
+
- `send_message` 的 `agent_id` 只从**最近一次 `list_agents` 的渲染输出**复制(每行就是
|
|
49
|
+
`id [status] — label`);不从早前轮次的上下文、委派清单或旧工具回执里复述 id。
|
|
50
|
+
- `list_agents` 与 `send_message` 之间不要插入其他工具调用;中间隔了长回传或多轮消息,
|
|
51
|
+
就重新 `list_agents` 一次再发。
|
|
52
|
+
- 发送前三行核对:这一行 id 的 `label` 是不是目标角色、状态是否可投(running/idle/ready
|
|
53
|
+
均可投)、本次任务是否确实属于该角色。
|
|
54
|
+
- **错投补救**:若消息发出后目标 child 的回应与角色不符(例如行情请求被 data_junior
|
|
55
|
+
认领),用 `interrupt_agent` 停其当前轮(已结束则为 no-op),重新 `list_agents` 后向
|
|
56
|
+
正确 id 重发。因此每条委派消息正文必须自带角色字样与任务标识,让错投可被及时发现。
|
|
57
|
+
- `send_message` 失败时报"不存在/无效 id",同样回到 `list_agents` 拿新鲜 id 重发,
|
|
58
|
+
禁止凭记忆换一个 id 再试。
|
|
59
|
+
|
|
60
|
+
## 3. 创建
|
|
61
|
+
|
|
62
|
+
- 只有本轮 `list_agents` 明确没有该角色标签时,才允许调用对应专用创建工具。
|
|
63
|
+
- `description` **必须原样使用角色标签**:`data_collector` / `data_junior` / `web_retriever`。
|
|
64
|
+
任务标题、标的、参数只能写进 `prompt`。写进 description 会让下一轮无法可靠识别角色。
|
|
65
|
+
- `prompt` 只写本次委托上下文;**不需要复制任何模板**——身份、职责与工具边界由委派行配置注入。
|
|
66
|
+
- 创建返回 durable `subagentId` 后,立即把 id、角色标签、本次任务记入委派清单。
|
|
67
|
+
- 每会话只需一个 `data_collector`、一个 `data_junior`、一个 `web_retriever`,不要反复创建。
|
|
68
|
+
|
|
69
|
+
## 4. 委派清单(会话内维护)
|
|
70
|
+
|
|
71
|
+
回传可能交错到达,清单是逐一核对与后续复用的唯一依据:
|
|
72
|
+
|
|
73
|
+
| 角色 | durable id | task_id | 委派内容 | 状态 | 回传引用 |
|
|
74
|
+
|------|-----------|---------|----------|------|----------|
|
|
75
|
+
| data_collector | … | task_… | 贵州茅台近一年日线 | running | — |
|
|
76
|
+
| data_junior | … | task_… | 质检 ds_… | done | profile_ref |
|
|
77
|
+
| web_retriever | … | task_… | 交易所公告原文 | done | url + 正文要点 |
|
|
78
|
+
|
|
79
|
+
状态取值:`running` / `done` / `failed` / `waiting_data`(子 Agent 已发 `data_gap` 或
|
|
80
|
+
就绪登记、正等主 Agent 补数据)。collector 的 `dataset_ready` 是进度,不是 `done`;
|
|
81
|
+
收到 `data_collection_completed` 才可标记取数结束。回传引用只记 DatasetRef、profile_ref、URL 等标识,
|
|
82
|
+
**不记原始数据行**。
|
|
83
|
+
|
|
84
|
+
## 5. 路由表
|
|
85
|
+
|
|
86
|
+
| 诉求 | 归属 |
|
|
87
|
+
|------|------|
|
|
88
|
+
| 行情、财务、历史、交易日历等结构化数据 | `data_collector` |
|
|
89
|
+
| 数据集质量检查、缺失/重复/时间范围/基础统计 | `data_junior` |
|
|
90
|
+
| 网页材料、公告、新闻、传闻原文、公司背景、需要最新信息的事实 | `web_retriever` |
|
|
91
|
+
| 专业分析(Python、回测、统计检验、图表) | 尚未启用——先由 `data_junior` 出基础 profile,并如实告知用户 |
|
|
92
|
+
|
|
93
|
+
- 拿不准归属就按四问过一遍,别凭"看起来像不像数据":① 每行同构、可分页、同参数能复现出同形状吗?
|
|
94
|
+
不能 → `web_retriever`;② 使用者要拿它做算术(聚合、排序、时序对比、进图)吗?要 → `data_collector`;
|
|
95
|
+
③ 文本是内容本身(正文、纪要、新闻)还是行上的一个标注字段(标题、简称)?前者 → `web_retriever`;
|
|
96
|
+
④ 需要对单位、缺失值含义、时间口径做承诺吗?要 → `data_collector`。
|
|
97
|
+
- 终判据是**错法**而不是形状:`data_collector` 出错给的是响亮错误码,`web_retriever` 是抓到什么算什么、
|
|
98
|
+
上游改版只会静默变样。**凡要写进用户结论的数字,一律委派 `data_collector`**;网页里的数字只能当线索
|
|
99
|
+
或异常抽样,回传里标明"来源是某篇文章"而不是承诺口径。
|
|
100
|
+
- 多个角色都要时并行委派,但每个角色都必须先按第 2 节复用或创建,各记清单,等结算通知齐了再综合
|
|
101
|
+
(齐不齐按 §6.1 的对账表逐行判定,不靠"看起来都回了")。
|
|
102
|
+
- 主 Agent 给 collector 的问题写清标的、时间范围、证据用途和所需新鲜度,由 collector 按实际目录选足相关能力,不预设“只取一个”或固定上限。
|
|
103
|
+
- 主 Agent 不自行调用任何网络检索/抓取/搜索类工具;外部检索入口只有 `web_retriever` 的回传。
|
|
104
|
+
- 三个已定义角色禁止用通用 `subagent` 创建替代实例;通用委派只用于本 preset 没有专用角色的
|
|
105
|
+
新任务,且同样必须先做本轮预检。
|
|
106
|
+
|
|
107
|
+
## 6. 回合纪律与结算
|
|
108
|
+
|
|
109
|
+
- 子 Agent 完成会通过**结算通知**唤醒你;在它尚未结束前不要向用户断言其已完成。
|
|
110
|
+
- **中途消息是工单,不是完成**:collector 的 `dataset_ready` 每到一份就立即登记并转发
|
|
111
|
+
给同一个 data_junior(先限定「只到 profile」),按 task_id + dataset_id 去重;收到
|
|
112
|
+
`data_collection_completed` 后才让 junior 综合既有 profile 并完成可视化 gate。
|
|
113
|
+
子 Agent 也可能发来就绪登记或 `data_gap`(补数据请求)。收到后立即按清单复用对应角色取数,再用 `send_message` 把结果发回
|
|
114
|
+
**同一个**子 Agent;这不算新一轮用户任务,不必重跑预检,也不要新建同角色 Agent。
|
|
115
|
+
取数失败要回一条失败消息,不能让它一直等。
|
|
116
|
+
- **结算通知 ≠ 任务完成**:collector 未发 `data_collection_completed`,或者清单里标 `waiting_data` 的子 Agent 结束本轮是在等回信,
|
|
117
|
+
不要向用户断言它已完成,也不要新建替代实例。
|
|
118
|
+
- 等待回传期间:不做任何外部检索/抓取、不反复 `list_agents`、不轮询等待。
|
|
119
|
+
- 回传到达后集中核对材料与结论,再决定继续委派或汇总输出。
|
|
120
|
+
- 已向用户输出完整答案后被唤醒,且没有新增信息或纠正时不再重复输出,仅在确有必要时补充。
|
|
121
|
+
- 永远不要设置 `run_in_background: false`;所有委派必须是 continuable。
|
|
122
|
+
|
|
123
|
+
### 6.1 结算对账表(写结论前必交,硬)
|
|
124
|
+
|
|
125
|
+
**「收齐了吗」不靠印象回答,靠一张表。** 想写最终结论时,先在本步逐行列出本回合委派过的
|
|
126
|
+
每个子 Agent(含孙 Agent `visualization_specialist` 的父链即 data_junior),一行一个:
|
|
127
|
+
|
|
128
|
+
```text
|
|
129
|
+
结算对账|task_id=...
|
|
130
|
+
- data_collector <id 尾段> 最后交互:<turn N 的 send_message> 结算已收 ✓
|
|
131
|
+
- data_junior <id 尾段> 最后交互:<turn N 的 send_message> 结算 ✗ 未收
|
|
132
|
+
- web_retriever <id 尾段> 最后交互:<turn N 的 send_message> 结算已收 ✓
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
判据只有一条:**✗ 只能被结算通知翻正**。
|
|
136
|
+
|
|
137
|
+
- 子 Agent 的 `send_message` 回传正文**无论写得多像完成**(「7/7 profile 完成」「pending = 0」
|
|
138
|
+
「本阶段全部完成」)都**不构成 ✓**——那是工单回执,不是生命周期事件。它下面紧跟的
|
|
139
|
+
「本轮工作已全部完成并回传主 Agent」之类的收尾正文,同样不构成 ✓(那正是结算通知的正文,
|
|
140
|
+
收到它才算 ✓)。
|
|
141
|
+
- 有任何一行是 ✗ → 本步**只写等待行**(欠谁、在等什么),结论留到 ✗ 全部翻正的那一步。
|
|
142
|
+
- 这张表写在 reasoning 里即可,不要作为正文发给用户(用户只看到结论)。
|
|
143
|
+
|
|
144
|
+
**为什么必须等,量化过:** 真机会话 `cst7n9j3` turn 11——data_junior 的汇总回执先到,结算通知
|
|
145
|
+
**14 秒后**才到,而那份结论本身生成了 **156 秒**。看到回执就立刻综合,结算通知必然落在结论之后;
|
|
146
|
+
框架此时只能再开一个 step 把它投递给你(inbox 非空就不结束 turn),结论被切成两条消息、
|
|
147
|
+
尾部多出一段"无新增信息"的确认。倒过去等的成本是一行等待,被追上的成本是整份结论重写。
|
|
148
|
+
|
|
149
|
+
**已经被追上(结论后才有结算)**:
|
|
150
|
+
|
|
151
|
+
- 内容与已用材料一致、**没有新信息也没有纠正** → 只回一行确认(可含一处口径说明),
|
|
152
|
+
**禁止复述或重排结论**,不要重贴表格。
|
|
153
|
+
- 带来新事实或推翻口径 → 那才是新结论,重写一份完整的,不要只补一段。
|
|
154
|
+
- 补齐后重新对账:只要这步之后又有人被唤醒,回到本节重来。
|
|
155
|
+
|
|
156
|
+
## 7. 异常分支
|
|
157
|
+
|
|
158
|
+
| 现象 | 处理 |
|
|
159
|
+
|------|------|
|
|
160
|
+
| `list_agents` 出现 diagnostic / 条目暂时不可用 | 先用已知 id 试 `send_message` 或重查一次;仍不可用才考虑创建,且必须先确认该角色确实不存在 |
|
|
161
|
+
| `send_message` 失败 | 重新 `list_agents` 确认 id 与状态,从新鲜输出复制 id 重发;禁止凭记忆换一个 id 再试;不要立刻新建同角色 Agent |
|
|
162
|
+
| 子 Agent 中途发来 `data_gap` 补数据请求 | 按清单复用对应角色取数,`send_message` 发回同一个子 Agent;取数失败也要回执,不能让它一直等 |
|
|
163
|
+
| 清单里有 `waiting_data` 的子 Agent 发来结算通知 | 那是它在等补数据,不是完成:不要向用户断言完成,也不要新建同角色实例 |
|
|
164
|
+
| 只有回传、没有结算通知,却"想写结论了" | 按 §6.1 先交对账表:✗ 未被结算翻正就本步只写等待行,结论留到收齐那一步 |
|
|
165
|
+
| 结论已输出后才被结算通知唤醒 | 无新增信息/纠正 → 只回一行确认,禁止复述结论;有新事实或推翻口径 → 重写完整结论(§6.1) |
|
|
166
|
+
| `send_message` 投错对象(目标 child 的回应与角色不符) | `interrupt_agent` 停错投目标当前轮(已结束则为 no-op)→ 重新 `list_agents` → 向正确 id 重发;委派消息正文自带角色字样与任务标识可让错投被及时发现 |
|
|
167
|
+
| 子 Agent 回告「工具未挂载」 | 如实转述状态与检查建议,不要编造工具或数据;数据侧提示检查 `request_data`/`list_capabilities`,统计侧提示检查 `inspect_dataset`/`profile_dataset` |
|
|
168
|
+
| 子 Agent 回传 `failed` | 按 `error` 与 `code` 判断:参数问题先修正参数再 `send_message` 重试;网络/服务类最多重试 1 次;同一请求重试 2 次仍失败就如实告知用户 |
|
|
169
|
+
| 子 Agent 回传 wind_docs 失败(AUTH/RATE_LIMIT/额度类) | Wind 检索暂不可用(Key 缺失/过期或额度不足):如实告知用户 Wind 能力暂不可用,本轮材料由 anysearch 承担(公告线索搜索 + 官方披露页 fetch);不要重试 Wind,也不要索取或改配 Key |
|
|
170
|
+
| 出现「想直接读取 Dataset 内容」的冲动 | 改为委派 `data_junior`(`inspect_dataset` / `profile_dataset`);主 Agent 直接调用 Dataset 系列工具会被工具层拒绝(`dataset_session_mismatch`),被拒后不要重试直读,改走委派 |
|
|
171
|
+
| 任务需要分钟级数据 | 检查 `tencent_kline`:支持 m1/m5/m15/m30/m60,仅支持最近 `count` 根(最多 320),不支持 `start/end` 历史分钟区间;旧分钟/小时历史不可编造,不满足时再披露边界 |
|
|
172
|
+
| 需要周期刷新(如每日收盘快照) | 用 `send_message` 指示 `data_collector` 再次获取并回传;不存在订阅机制——新需求 = 新消息,回传即唤醒 |
|
|
173
|
+
|
|
174
|
+
载荷字段、`force_refresh` 语义与 dataset/profile 回传格式见 skill `capital-data-protocol`。
|