@v587d/capital-generation 2.10.0 → 2.10.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.
Files changed (37) hide show
  1. package/CHANGELOG.md +40 -0
  2. package/README.md +5 -4
  3. package/chart-ui/package.json +1 -1
  4. package/config/client.js +8 -6
  5. package/config/client.src.cjs +74 -34
  6. package/config/index.js +8 -2
  7. package/config/package.json +1 -1
  8. package/lib/agents/selected-skills-provider.d.ts +29 -10
  9. package/lib/agents/selected-skills-provider.js +262 -139
  10. package/lib/agents/skill-usage.d.ts +22 -0
  11. package/lib/agents/skill-usage.js +92 -0
  12. package/lib/capital-settings.d.ts +12 -1
  13. package/lib/capital-settings.js +23 -3
  14. package/lib/index.d.ts +6 -3
  15. package/lib/index.js +10 -19
  16. package/lib/root-extras-entry.d.ts +2 -5
  17. package/lib/root-extras-entry.js +1 -3
  18. package/lib/selected-skills-entry.d.ts +14 -0
  19. package/lib/selected-skills-entry.js +43 -0
  20. package/lib/web-retriever/local-fetch.d.ts +1 -1
  21. package/lib/web-retriever/local-fetch.js +1 -1
  22. package/lib/web-retriever/wind-client.d.ts +1 -1
  23. package/lib/web-retriever/wind-client.js +1 -1
  24. package/package.json +10 -2
  25. package/preset/capital-generation/agent.patch.yml +34 -16
  26. package/preset/capital-generation/skills/capital-data-query/SKILL.md +19 -0
  27. package/preset/capital-generation/skills/capital-equity-research/SKILL.md +4 -0
  28. package/preset/capital-generation/skills/capital-event-impact/SKILL.md +3 -0
  29. package/preset/capital-generation/skills/capital-orchestration/SKILL.md +7 -9
  30. package/preset/capital-generation/skills/capital-portfolio-review/SKILL.md +3 -0
  31. package/preset/capital-generation/skills/capital-web-evidence/SKILL.md +1 -0
  32. package/preset/capital-generation/skills/capital-web-protocol/SKILL.md +3 -0
  33. package/selected-skills/README.md +5 -4
  34. package/selected-skills/ROUTING.md +88 -0
  35. package/selected-skills/catalog.js +32 -121
  36. package/selected-skills/routing.js +1036 -0
  37. package/watchlist/package.json +1 -1
@@ -6,7 +6,7 @@
6
6
  */
7
7
  import type { Context } from '@deepseek-ai/cordis';
8
8
  import type { RetrieverConfig } from './retriever-config.js';
9
- import type { SelectedSkillSelection } from './agents/selected-skills-provider.js';
9
+ import type { SelectedSkillSelection, SelectedSkillsMode } from './agents/selected-skills-provider.js';
10
10
  export declare const CAPITAL_CONFIG_ENTRY_ID = "capital-config";
11
11
  /** Fields this repo consumes (the host half owns the rest). */
12
12
  export interface CapitalConfigSlice {
@@ -15,7 +15,18 @@ export interface CapitalConfigSlice {
15
15
  customPersona?: string;
16
16
  retriever?: RetrieverConfig;
17
17
  selectedSkills?: SelectedSkillSelection;
18
+ selectedSkillsMode?: SelectedSkillsMode;
18
19
  }
20
+ export type CapitalEntrySource = 'settings-describe' | 'config-editor';
21
+ /**
22
+ * Settings first, then the config-editor save layer. The selected-skill provider and the
23
+ * persona section live in a separate preset row; reading only `settings.describe()` there
24
+ * made a saved toggle look all-off whenever the settings projection was not ready.
25
+ */
26
+ export declare function readCapitalEntry(ctx: Context): {
27
+ value?: Record<string, unknown>;
28
+ source?: CapitalEntrySource;
29
+ };
19
30
  export declare function readCapitalConfig(ctx: Context): CapitalConfigSlice;
20
31
  /** Flat credential refs needed by the collector domain (same shape as `CollectorConfig`). */
21
32
  export declare function readCollectorConfig(ctx: Context): {
@@ -1,12 +1,32 @@
1
1
  export const CAPITAL_CONFIG_ENTRY_ID = 'capital-config';
2
- export function readCapitalConfig(ctx) {
2
+ /**
3
+ * Settings first, then the config-editor save layer. The selected-skill provider and the
4
+ * persona section live in a separate preset row; reading only `settings.describe()` there
5
+ * made a saved toggle look all-off whenever the settings projection was not ready.
6
+ */
7
+ export function readCapitalEntry(ctx) {
3
8
  try {
4
9
  const settings = ctx.get('settings');
5
- return settings?.describe?.().find((entry) => entry?.ns === CAPITAL_CONFIG_ENTRY_ID)?.value ?? {};
10
+ const value = settings?.describe?.().find((entry) => entry?.ns === CAPITAL_CONFIG_ENTRY_ID)?.value;
11
+ if (value !== null && typeof value === 'object' && !Array.isArray(value)) {
12
+ return { value: value, source: 'settings-describe' };
13
+ }
6
14
  }
7
15
  catch {
8
- return {};
9
16
  }
17
+ try {
18
+ const editor = ctx.get('configEditor');
19
+ const value = editor?.entries?.().find((row) => row?.options?.id === CAPITAL_CONFIG_ENTRY_ID)?.options?.config;
20
+ if (value !== null && typeof value === 'object' && !Array.isArray(value)) {
21
+ return { value: value, source: 'config-editor' };
22
+ }
23
+ }
24
+ catch {
25
+ }
26
+ return {};
27
+ }
28
+ export function readCapitalConfig(ctx) {
29
+ return (readCapitalEntry(ctx).value ?? {});
10
30
  }
11
31
  /** Flat credential refs needed by the collector domain (same shape as `CollectorConfig`). */
12
32
  export function readCollectorConfig(ctx) {
package/lib/index.d.ts CHANGED
@@ -1,15 +1,16 @@
1
1
  import { Context } from '@deepseek-ai/cordis';
2
2
  import z from '@deepseek-ai/schemastery';
3
- import { type SelectedSkillSelection } from './agents/selected-skills-provider.js';
3
+ import { type SelectedSkillSelection, type SelectedSkillsMode } from './agents/selected-skills-provider.js';
4
+ import { CAPITAL_CONFIG_ENTRY_ID } from './capital-settings.js';
4
5
  import { type RetrieverConfig } from './retriever-config.js';
5
6
  export { LOCAL_FETCH_DEFAULTS, PADDLE_OCR_DEFAULTS, resolveLocalFetchConfig, type LocalFetchConfig, type PaddleOcrConfig, type RetrieverConfig, type WindDocsConfig, } from './retriever-config.js';
6
7
  export { resolveUserCustomizationSection } from './user-customization.js';
7
8
  export declare const name = "capital-generation";
8
- /** Entry id shared by `cordis.patch.yml`, `config/index.js` and `client.src.cjs`; drift hides the settings card. */
9
- export declare const CAPITAL_CONFIG_ENTRY_ID = "capital-config";
9
+ export { CAPITAL_CONFIG_ENTRY_ID };
10
10
  export interface Config {
11
11
  customPersona?: string;
12
12
  selectedSkills?: SelectedSkillSelection;
13
+ selectedSkillsMode?: SelectedSkillsMode;
13
14
  fuyaoCredentialRef?: string;
14
15
  ftshareCredentialRef?: string;
15
16
  retriever?: RetrieverConfig;
@@ -21,6 +22,7 @@ export declare const Config: z<Schemastery.ObjectS<NoInfer<{
21
22
  }>>, Schemastery.ObjectT<NoInfer<{
22
23
  [k: string]: z<boolean, boolean, "defined">;
23
24
  }>>, "defined">;
25
+ selectedSkillsMode: z<"manual" | "auto", "manual" | "auto", "defined">;
24
26
  fuyaoCredentialRef: z<string, string, "defined">;
25
27
  ftshareCredentialRef: z<string, string, "defined">;
26
28
  retriever: z<Schemastery.ObjectS<NoInfer<{
@@ -107,6 +109,7 @@ export declare const Config: z<Schemastery.ObjectS<NoInfer<{
107
109
  }>>, Schemastery.ObjectT<NoInfer<{
108
110
  [k: string]: z<boolean, boolean, "defined">;
109
111
  }>>, "defined">;
112
+ selectedSkillsMode: z<"manual" | "auto", "manual" | "auto", "defined">;
110
113
  fuyaoCredentialRef: z<string, string, "defined">;
111
114
  ftshareCredentialRef: z<string, string, "defined">;
112
115
  retriever: z<Schemastery.ObjectS<NoInfer<{
package/lib/index.js CHANGED
@@ -10,6 +10,7 @@ import { registerChartTool } from './chart/tool.js';
10
10
  import { createChartEventPublisher } from './chart/events.js';
11
11
  import { chartEventContextOf } from './chart/event-context.js';
12
12
  import { SELECTED_SKILL_CATALOG } from './agents/selected-skills-provider.js';
13
+ import { CAPITAL_CONFIG_ENTRY_ID, readCapitalEntry } from './capital-settings.js';
13
14
  import { registerChartSourceTool } from './chart/source-token.js';
14
15
  import { registerSourceTools, registerWebRetrieverTools } from './web-retriever/tools.js';
15
16
  import { LOCAL_FETCH_DEFAULTS, PADDLE_OCR_DEFAULTS, } from './retriever-config.js';
@@ -17,8 +18,7 @@ import { createRetrieverRuntime } from './retriever-runtime.js';
17
18
  export { LOCAL_FETCH_DEFAULTS, PADDLE_OCR_DEFAULTS, resolveLocalFetchConfig, } from './retriever-config.js';
18
19
  export { resolveUserCustomizationSection } from './user-customization.js';
19
20
  export const name = 'capital-generation';
20
- /** Entry id shared by `cordis.patch.yml`, `config/index.js` and `client.src.cjs`; drift hides the settings card. */
21
- export const CAPITAL_CONFIG_ENTRY_ID = 'capital-config';
21
+ export { CAPITAL_CONFIG_ENTRY_ID };
22
22
  const WindDocsSchema = z.object({
23
23
  endpoint: z.string().default('').description('可选:覆盖 Wind 文档检索端点'),
24
24
  credentialRef: z.string().default('').description('可选:DSH credentials 引用名,空 = WIND_API_KEY'),
@@ -51,13 +51,16 @@ const RetrieverSchema = z.object({
51
51
  // Derive toggles from the catalog: a hand-copied list silently drops defaults at the entry→plugin boundary.
52
52
  const SelectedSkillsSchema = z.object(Object.fromEntries(SELECTED_SKILL_CATALOG.map(({ key, name }) => [
53
53
  key,
54
- z.boolean().default(false).description(`Enable the community experiment "${name}" for the Auto mode root Agent`),
54
+ z.boolean().default(false).description(`Enable the community method "${name}" for the Capital role(s) that own it`),
55
55
  ]))).default(Object.fromEntries(SELECTED_SKILL_CATALOG.map(({ key }) => [key, false])));
56
56
  export const Config = z.object({
57
57
  customPersona: z.string()
58
58
  .default('')
59
59
  .description('自动模式的附加人设文本(独立 section,非 deployment:persona);核心安全约束始终保留'),
60
- selectedSkills: SelectedSkillsSchema.description('Community selected-skill experiments; default off and visible only to the Auto mode root Agent'),
60
+ selectedSkills: SelectedSkillsSchema.description('Community selected methods; default off, each visible only to the Capital role(s) that own it'),
61
+ selectedSkillsMode: z.union(['manual', 'auto'])
62
+ .default('manual')
63
+ .description('精选 Skill 暴露方式:manual = 只用勾选;auto = 按角色开放全部方法,运行期忽略勾选'),
61
64
  fuyaoCredentialRef: z.string()
62
65
  .default('FUYAO_API_KEY')
63
66
  .description('Fuyao credentials 引用名,空 = FUYAO_API_KEY'),
@@ -70,22 +73,10 @@ export const Config = z.object({
70
73
  /** Fallback order: settings.describe → configEditor.entries → boot preset, so unreadable never
71
74
  * reads as "all toggles off". Resolve services per call: boot fibers apply in parallel. */
72
75
  export function readCapitalSettings(ctx, bootConfig) {
73
- const settings = ctx.get('settings');
74
- try {
75
- const resolved = settings?.describe?.().find((entry) => entry.ns === CAPITAL_CONFIG_ENTRY_ID)?.value;
76
+ const entry = readCapitalEntry(ctx);
77
+ if (entry.value !== undefined) {
76
78
  // Re-parse through this plugin's schema: fills defaults and surfaces schema drift.
77
- if (resolved && typeof resolved === 'object')
78
- return { config: Config(resolved), source: 'settings-describe' };
79
- }
80
- catch {
81
- }
82
- const configEditor = ctx.get('configEditor');
83
- try {
84
- const raw = configEditor?.entries?.().find((row) => row?.options?.id === CAPITAL_CONFIG_ENTRY_ID)?.options?.config;
85
- if (raw && typeof raw === 'object')
86
- return { config: Config(raw), source: 'config-editor' };
87
- }
88
- catch {
79
+ return { config: Config(entry.value), source: entry.source ?? 'settings-describe' };
89
80
  }
90
81
  return { config: bootConfig, source: 'preset' };
91
82
  }
@@ -1,15 +1,12 @@
1
1
  /**
2
- * `tools/root-extras` row: root-only selected-skills provider and the `customPersona`
3
- * system-prompt section. This row registers no tools; both pieces re-read settings
4
- * every turn so saved changes apply on the next step.
2
+ * `tools/root-extras` row: the `customPersona` system-prompt section. Root-only; this row
3
+ * registers no tools. Selected skills moved to the role-scoped `tools/selected-skills` row.
5
4
  */
6
5
  import type { Context } from '@deepseek-ai/cordis';
7
- import { type SelectedSkillSelection } from './agents/selected-skills-provider.js';
8
6
  export declare const name = "capital-root-extras";
9
7
  export declare const inject: string[];
10
8
  interface RootExtrasConfig {
11
9
  customPersona?: string;
12
- selectedSkills?: SelectedSkillSelection;
13
10
  }
14
11
  /** Re-read per turn so a settings save applies to the same session on the next step. */
15
12
  export declare function readRootExtrasConfig(ctx: Context): RootExtrasConfig;
@@ -1,4 +1,3 @@
1
- import { registerRootSelectedSkills } from './agents/selected-skills-provider.js';
2
1
  import { userCustomizationSection } from './user-customization.js';
3
2
  import { readCapitalConfig } from './capital-settings.js';
4
3
  export const name = 'capital-root-extras';
@@ -6,10 +5,9 @@ export const inject = ['systemPrompt'];
6
5
  /** Re-read per turn so a settings save applies to the same session on the next step. */
7
6
  export function readRootExtrasConfig(ctx) {
8
7
  const config = readCapitalConfig(ctx);
9
- return { customPersona: config.customPersona, selectedSkills: config.selectedSkills };
8
+ return { customPersona: config.customPersona };
10
9
  }
11
10
  export function apply(ctx) {
12
- registerRootSelectedSkills(ctx, () => readRootExtrasConfig(ctx).selectedSkills ?? {});
13
11
  let lastPersonaError;
14
12
  const section = userCustomizationSection(() => readRootExtrasConfig(ctx).customPersona, (error) => {
15
13
  const message = error instanceof Error ? error.message : String(error);
@@ -0,0 +1,14 @@
1
+ /**
2
+ * `tools/selected-skills` row: role-scoped selected-skill catalog plus its role prompt section.
3
+ * The row is mounted once per Capital preset (`config.role`) and registers into that Agent's
4
+ * own scope only; it never writes to the preset standing scope or the host scope.
5
+ */
6
+ import type { Context } from '@deepseek-ai/cordis';
7
+ import { type SelectedSkillRole } from './agents/selected-skills-provider.js';
8
+ export declare const name = "capital-selected-skills";
9
+ export declare const inject: string[];
10
+ interface Config {
11
+ role?: SelectedSkillRole;
12
+ }
13
+ export declare function apply(ctx: Context, config?: Config): void;
14
+ export {};
@@ -0,0 +1,43 @@
1
+ import { registerSelectedSkills, renderSelectedSkillsBrief, SELECTED_SKILL_ENTRY_ROLES, } from './agents/selected-skills-provider.js';
2
+ import { readCapitalConfig } from './capital-settings.js';
3
+ export const name = 'capital-selected-skills';
4
+ export const inject = ['systemPrompt'];
5
+ const SECTION_NAME = 'capital:selected-skills';
6
+ /** After the persona, before the user-customization section (order 100). */
7
+ const SECTION_ORDER = 60;
8
+ const accessOf = (ctx) => ({
9
+ selection: () => readCapitalConfig(ctx).selectedSkills ?? {},
10
+ mode: () => (readCapitalConfig(ctx).selectedSkillsMode === 'auto' ? 'auto' : 'manual'),
11
+ });
12
+ export function apply(ctx, config = {}) {
13
+ const role = config.role ?? 'main';
14
+ if (!SELECTED_SKILL_ENTRY_ROLES.includes(role)) {
15
+ throw new Error(`capital-selected-skills: unknown role "${String(role)}"`);
16
+ }
17
+ registerSelectedSkills(ctx, role, accessOf(ctx));
18
+ let lastRenderError;
19
+ ctx.effect(() => {
20
+ const dispose = ctx.systemPrompt.section({
21
+ name: SECTION_NAME,
22
+ order: SECTION_ORDER,
23
+ // Upstream-derived prose can contain `{{...}}`; this section is literal.
24
+ interpolate: false,
25
+ text: (context) => {
26
+ try {
27
+ // dsh-agent passes its Agent as the assembly scope; the usage ledger is keyed by session.
28
+ const agent = context?.agent;
29
+ return renderSelectedSkillsBrief(role, accessOf(ctx), agent);
30
+ }
31
+ catch (error) {
32
+ const message = error instanceof Error ? error.message : String(error);
33
+ if (message !== lastRenderError) {
34
+ lastRenderError = message;
35
+ ctx.logger?.warn?.(`capital-generation: selected skill prompt unreadable (${message})`);
36
+ }
37
+ return '';
38
+ }
39
+ },
40
+ });
41
+ return typeof dispose === 'function' ? dispose : () => { };
42
+ }, 'capital-generation.selected-skills()');
43
+ }
@@ -3,7 +3,7 @@
3
3
  * Known limit: DNS resolves per request but the IP is not pinned to the connection,
4
4
  * so a rebinding window remains (same trade-off as dsh-search-first).
5
5
  */
6
- export declare const LOCAL_FETCH_CLIENT_VERSION = "2.10.0";
6
+ export declare const LOCAL_FETCH_CLIENT_VERSION = "2.10.1";
7
7
  export declare const LOCAL_FETCH_MAX_URL_LENGTH = 2048;
8
8
  export type LocalFetchErrorCode = 'ABORTED' | 'TIMEOUT' | 'INVALID_URL' | 'BLOCKED_URL' | 'DNS' | 'REDIRECT' | 'HTTP' | 'TOO_LARGE' | 'UNSUPPORTED_CONTENT_TYPE';
9
9
  export declare class LocalFetchError extends Error {
@@ -4,7 +4,7 @@
4
4
  * so a rebinding window remains (same trade-off as dsh-search-first).
5
5
  */
6
6
  import { htmlToMarkdown, stripInvisibleText } from './html-markdown.js';
7
- export const LOCAL_FETCH_CLIENT_VERSION = '2.10.0';
7
+ export const LOCAL_FETCH_CLIENT_VERSION = '2.10.1';
8
8
  export const LOCAL_FETCH_MAX_URL_LENGTH = 2048;
9
9
  export class LocalFetchError extends Error {
10
10
  code;
@@ -35,7 +35,7 @@ export interface WindCallResult {
35
35
  code?: WindErrorCode;
36
36
  }
37
37
  /** Must match `package.json` version; a test pins the two together. */
38
- export declare const WIND_CLIENT_VERSION = "2.10.0";
38
+ export declare const WIND_CLIENT_VERSION = "2.10.1";
39
39
  export interface WindClient {
40
40
  callTool(toolName: string, args: Record<string, unknown>, signal?: AbortSignal): Promise<WindCallResult>;
41
41
  }
@@ -19,7 +19,7 @@ export const WIND_SERVER_ENDPOINTS = {
19
19
  analytics_data: 'https://mcp.wind.com.cn/vserver_analytics_data/mcp/',
20
20
  };
21
21
  /** Must match `package.json` version; a test pins the two together. */
22
- export const WIND_CLIENT_VERSION = '2.10.0';
22
+ export const WIND_CLIENT_VERSION = '2.10.1';
23
23
  function errorText(error) {
24
24
  return error instanceof Error ? error.message : String(error);
25
25
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@v587d/capital-generation",
3
- "version": "2.10.0",
3
+ "version": "2.10.1",
4
4
  "description": "Capital Generation:面向中国散户的 AI 投资助手插件(自动模式 Agent Preset)",
5
5
  "icon": "assets/cg-icon.png",
6
6
  "author": "v587d",
@@ -82,6 +82,11 @@
82
82
  "import": "./lib/root-extras-entry.js",
83
83
  "default": "./lib/root-extras-entry.js"
84
84
  },
85
+ "./tools/selected-skills": {
86
+ "types": "./lib/selected-skills-entry.d.ts",
87
+ "import": "./lib/selected-skills-entry.js",
88
+ "default": "./lib/selected-skills-entry.js"
89
+ },
85
90
  "./tools/time": {
86
91
  "types": "./lib/time-entry.d.ts",
87
92
  "import": "./lib/time-entry.js",
@@ -103,6 +108,8 @@
103
108
  "watchlist",
104
109
  "preset",
105
110
  "selected-skills/catalog.js",
111
+ "selected-skills/routing.js",
112
+ "selected-skills/ROUTING.md",
106
113
  "selected-skills/README.md",
107
114
  "selected-skills/investment-skills",
108
115
  "selected-skills/china-stock-research-skills",
@@ -146,7 +153,8 @@
146
153
  "docs:capabilities": "npm run build && node scripts/gen-capability-table.mjs",
147
154
  "verify:sessions": "node scripts/verify-sessions.mjs",
148
155
  "audit:tool-errors": "node scripts/audit-tool-errors.mjs",
149
- "ptc:report": "node scripts/ptc-session-report.mjs"
156
+ "ptc:report": "node scripts/ptc-session-report.mjs",
157
+ "report:skill-usage": "node scripts/skill-usage-report.mjs"
150
158
  },
151
159
  "peerDependencies": {
152
160
  "@deepseek-ai/cordis": "^4.0.2",
@@ -118,7 +118,7 @@
118
118
  config:
119
119
  id: capital-data-junior
120
120
  name: 分析师
121
- description: 分析师(内部角色):读取同一会话中已经取回的数据,做质量检查、统计汇总,并判断是否需要图表;需要时委派绘图专员。通常由自动模式委派;单独打开时没有取数入口,也读不到别的会话的数据。
121
+ description: 分析师(内部角色):读取同一会话中已经取回的数据,做质量检查、统计汇总与假设建模,并判断是否需要图表;需要时委派绘图专员。通常由自动模式委派;单独打开时没有取数入口,也读不到别的会话的数据。
122
122
  order: 5
123
123
  plugins:
124
124
  - id: persona
@@ -126,10 +126,10 @@
126
126
  config:
127
127
  prefix: |-
128
128
  # ROLE & IDENTITY
129
- 你是数据分析师(data_junior):接收只含
130
- DatasetRef 标识与问题的 profile_request / query_request,用 describe_dataset 一次完成
131
- inspect/profile/受控 query(单点复核用 inspect_dataset / profile_dataset / query_dataset)。
132
- 描述完成后必须加载可视化协议,按 gate 决定是否创建 visualization_specialist;若创建则等其终态,再用 send_message 回传。载荷中不得出现原始数据行。你不是投资分析师
129
+ 你是数据分析师(data_junior):接收主 Agent 的 profile_request / query_request
130
+ (DatasetRef + 问题;describe_dataset 一次完成描述,单点复核才用 inspect/profile/query_dataset),
131
+ 以及无 Dataset 的假设建模请求(假设与口径由主 Agent 给)。有 Dataset 时按 DUTIES 6 出图;
132
+ 创建 specialist 后等终态再回传。载荷中不得出现原始数据行。你不是投资分析师
133
133
  (不做投资判断、不输出买卖建议),也不改写原始 Dataset。你是主 Agent 的直接子 Agent,
134
134
  与 data_collector 是兄弟:你不会被 data_collector 创建或指挥,互通一律经主 Agent 中继;
135
135
  visualization_specialist 是你的异步子 Agent,不向主 Agent 直接发消息。
@@ -137,8 +137,10 @@
137
137
 
138
138
  # DUTIES
139
139
  0. 第一步先加载协议:Dataset 工具前先 skill capital-data-profile(必须 tools.skill,别直调);写 query_request
140
- 或做算术再加 skill capital-data-query;描述后无条件加载 skill capital-visualization-protocol,
141
- 再选择 gate。载荷样例、事实读法、data_gap 与 QuerySpec 细则都在 skill 里。
140
+ 或做算术再加 skill capital-data-query;描述后无条件加载可视化协议 capital-visualization-protocol,
141
+ 再选择 gate。
142
+ 0.1 无 Dataset 的假设建模:跳过数据 profile 与可视化 gate,按 capital-data-query 的「无数据建模」节算;
143
+ 缺关键输入回传 model_input_gap,不引入外部数据、不写买卖建议。
142
144
  1. 启动自检:先看 SDK 有无 tools.describe_dataset,没有就 send_message 回告;正常时登记 data_junior_ready。
143
145
 
144
146
  2. 只用受控工具:dataset_ids 按主 Agent 转发的原样使用;一切路径都是 opaque
@@ -153,8 +155,7 @@
153
155
  5. 回传:用 tools.send_message 逐份回传结构化载荷(type / task_id / dataset_id / profile_ref
154
156
  或 query_result),字段按工具返回原样填入——字段名、数值、日期一律不改写;可附表或
155
157
  摘要,禁止只回传 markdown 汇总。失败回传 profile_failed / query_failed 与 error/code,
156
- 绝不编造统计或查询结果;失败不影响原始 Dataset,可按主 Agent 指示重试。
157
- 同一 task_id + dataset_id 已完成 profile 不重复做;后续汇总/出图复用已有 profile。
158
+ 绝不编造统计或查询结果;失败不影响原始 Dataset,可按主 Agent 指示重试。同一 task_id + dataset_id 已完成 profile 不重复做。
158
159
  6. 可视化 gate 是硬步骤:每份 profile 后都跑,触发它的是数据与问题,不是用户是否说“要图”。用户明确要求图表时不得 not_needed;profile 显示时间序列、OHLC+volume、多期比较或多个可比数值序列时必须选择 recommended,先 prepare_chart_source,再调用 subagent_visualization_specialist。只有字段/数据不足、视图无法表达或 token 无法安全签发时才可 blocked;简单标量/少量 KPI、纯文本或表格更清楚时才可 not_needed。委派 prompt 显式限定“只到 profile”或“不要图”时仍给 gate 结论但不出图,并写明未出图是委派收窄而非数据不支持;prompt 只带 refs、有限事实与视图意图。
159
160
  7. 出图 barrier:有 specialist 时,等每颗 specialist 的回传与结算通知都齐(rendered / skipped / failed),再回传 profile 与 chart_ref。
160
161
 
@@ -183,6 +184,10 @@
183
184
 
184
185
  - id: tool-skill
185
186
  name: '@deepseek-ai/dsh-tool-skill'
187
+ - id: capital-selected-skills
188
+ name: '@v587d/capital-generation/tools/selected-skills'
189
+ config:
190
+ role: data_junior
186
191
 
187
192
  # PTC: presentation is preset-scoped; the host runtime (dsh-base) stays per-call.
188
193
  - id: tool-presentation
@@ -344,6 +349,10 @@
344
349
 
345
350
  - id: tool-skill
346
351
  name: '@deepseek-ai/dsh-tool-skill'
352
+ - id: capital-selected-skills
353
+ name: '@v587d/capital-generation/tools/selected-skills'
354
+ config:
355
+ role: web_retriever
347
356
 
348
357
  # ── compaction: both rows must live in one realm; thresholdChars 8192 is the instance-wide single value ──
349
358
  - id: compaction
@@ -443,6 +452,10 @@
443
452
 
444
453
  - id: tool-skill
445
454
  name: '@deepseek-ai/dsh-tool-skill'
455
+ - id: capital-selected-skills
456
+ name: '@v587d/capital-generation/tools/selected-skills'
457
+ config:
458
+ role: data_analyst
446
459
 
447
460
  # ── compaction: both rows must live in one realm; thresholdChars 8192 is the instance-wide single value ──
448
461
  - id: compaction
@@ -501,10 +514,10 @@
501
514
  6. 用户要求实际持仓或投资组合复盘时先加载 skill capital-portfolio-review;自选股不等于持仓。重叠请求以主问题为准,确需另一任务范围时再叠加相应 skill。
502
515
 
503
516
  # OUTPUT CONVENTIONS
504
- 关键指标与截止用表格;子 Agent 回传按原样引用。
517
+ 关键指标与截止用表格;子 Agent 回传按原样引用。「使用的方法」节只在动态清单非空时写:逐个点名并说明用途,不得漏。
505
518
  图表由 data_junior 的可视化 gate 统一出品:你不画图、不评价图;派的时机与收窄见下方「数据调度纪律」。
506
519
  图表交付:收到 chart_refs 后调用一次 present_charts(一次传全部 ref;refs 丢了就传 task_id)——它只记录清单,宿主会在最终答复前写入答复末尾的「交付」行,提前调用不会落进中间轮。正文不要提图表、不在正文里罗列图表文件 / 路径 / HTML。图表是呈现不是分析:不用图推断数字,数值结论一律以 profile / query 回传为准。
507
- 最终答(硬):必须自足——结论、关键证据与来源标注、局限与风险、观察 / 验证 / 防守选项;归因准确。**禁止“分析已完成 / 结论见上 / 如上”这类指针式收尾**:界面只展示最后一轮答复、前面轮次会被折叠,指针句会让用户什么也看不到。被通知唤醒且无新增信息时:不输出可见正文(让上一条完整结论成为最后一轮),或重发一份自足总结;绝不写指针句。
520
+ 最终答(硬):必须自足——结论、关键证据与来源标注、局限与风险、观察 / 验证 / 防守选项;归因准确。**禁止“分析已完成 / 结论见上 / 如上”这类指针式收尾**:界面只展示最后一轮答复、前面轮次会被折叠,指针句会让用户什么也看不到。被通知唤醒且无新增信息时:不输出可见正文(让上一条完整结论成为最后一轮),或重发一份自足总结;绝不写「无新增信息」「结论见上」这类占位句。
508
521
 
509
522
  # RULES & DISCIPLINE
510
523
  读文件只用 read:只读 skill 分册与工作区文件;不读 capital-data/ 落盘(原始行不进入上下文),不读 ~/.dsh/;
@@ -532,11 +545,12 @@
532
545
  subagent_data_collector / subagent_data_junior / subagent_web_retriever;subagent_visualization_specialist 不是你的 direct-child 创建工具,只能由 data_junior 在可视化 gate 后调用;description 必须等于角色标签;参数写 prompt,不需要复制任何模板。返回 durable id 后立即记入委派清单;每会话只需一个同角色 Agent,不要反复创建。
533
546
 
534
547
  4. 路由(硬)
535
- a. 行情/财务/历史→data_collector;质检/统计/可视化编排→data_junior;
536
- 网页事实 → web_retriever。prompt 带已消歧标的与完整代码;多角色可并行,但先复用/创建并记清单。
548
+ a. 行情/财务/历史→data_collector;质检/建模(DCF、估值、三表、情景、敏感性等,含纯算术)/统计/可视化编排→data_junior;
549
+ 网页事实 → web_retriever。即使不取数、只有用户假设也交 data_junior:你只给假设与口径,不自己算。
550
+ prompt 带已消歧标的与完整代码;多角色可并行,但先复用/创建并记清单。
537
551
 
538
552
  b. 主 Agent 禁止自行检索;宿主若仍暴露 web_search / web_fetch,也不得调用。
539
- 本插件的检索与具名来源工具不在你的工具表里;外部检索只经 web_retriever 回传。
553
+ 外部检索只经 web_retriever 回传。
540
554
  工作目录里的本地 PDF / 图片可直接用 ocr 解析(外部链接仍走委派)。
541
555
 
542
556
  c. data_collector、data_junior、web_retriever 是兄弟子 Agent,互通经主 Agent 中继;
@@ -578,7 +592,7 @@
578
592
 
579
593
  2. 委派写明问题、标的、时间窗、所需新鲜度与证据用途,让 data_collector 按目录选足相关能力;
580
594
  不预设能力数量,不带内部源键名;载荷与重试表 → skill capital-data-protocol,
581
- 读回 junior 的 profile / query 回传 → skill capital-data-profile / capital-data-query。
595
+
582
596
  禁止任何消息携带完整原始 rows。
583
597
 
584
598
  3. 每收到一份 dataset_ready 就登记 DatasetRef。结构化数据到达就必须派 data_junior 做
@@ -588,7 +602,7 @@
588
602
  只在收到 data_collection_completed 后才判定取数结束;等 junior 已收数据的 profile
589
603
  和补数缺口对齐后,再让它复用已有 profile 汇总并完成可视化 gate;用户明确不要图时
590
604
  把「不要图」一并传入,由 junior 停在 gate 结论;把 profile_ref / chart_refs 记入委派清单
591
- (chart_refs 是最终答复前 present_charts 的入参,不要丢);失败按 error/code 修正或指示重试。
605
+ (chart_refs 不要丢);失败按 error/code 修正或指示重试。
592
606
 
593
607
  4. 输出必须披露 capability、source_label、captured_at 与缺失字段。
594
608
  原始行永不进入你的上下文;网页比对仅作异常抽样,不写成绝对真实。
@@ -678,6 +692,10 @@
678
692
 
679
693
  - id: tool-skill
680
694
  name: '@deepseek-ai/dsh-tool-skill'
695
+ - id: capital-selected-skills
696
+ name: '@v587d/capital-generation/tools/selected-skills'
697
+ config:
698
+ role: main
681
699
 
682
700
  # ── compaction: both rows must live in one realm; thresholdChars 8192 is the instance-wide single value ──
683
701
  - id: compaction
@@ -5,6 +5,7 @@ description: Use when aggregating a Dataset or computing a derived number — th
5
5
 
6
6
  # Capital 数据协议 · 第三册:受控查询与派生算术
7
7
 
8
+ > **定位**:本册只定义受控查询与派生算术;DCF、三表、风险建模等方法在精选方法层,命中时按角色目录另行加载。
8
9
  本册是数据协议的第三册(§3.3 run_code 只做派生算术 / §4 受控查询)。时间轴与 `time_facts` 在第二册
9
10
  `capital-data-profile` §3.2,载荷契约与重试纪律在第一册 `capital-data-protocol`。
10
11
 
@@ -75,6 +76,24 @@ N 日均量必须写明。
75
76
  重复主键、时间范围、最小/最大/均值/分位数——**只报告可计算的部分**,数据不足就如实说明。
76
77
 
77
78
 
79
+ ### 3.4 无 Dataset 的假设建模
80
+
81
+ 主 Agent 交来的假设建模请求没有 `DatasetRef`:营收、利润率、税率、WACC、永续增长、股本等都由
82
+ prompt 给定。它仍然走 `run_code`,但**不是**取数,也不套数据 profile / 可视化 gate。
83
+
84
+ - **只算假设,不补外部事实**:不得用记忆、网页或 `fetch` 填市场价格、财报、无风险利率;缺什么就
85
+ 在回传里列什么。需要真实数据时回传 `model_input_gap`,由主 Agent 交 `data_collector` 取回后再算。
86
+ - **缺关键输入**:`model_input_gap` 写明缺项、为什么影响结论,以及可选的 illustrative 默认值(必须
87
+ 标成假设,不能与用户给定值混在一列)。不要直接问用户——你不在用户对话里。
88
+ - **回传形状**:`type: "model_result"` + `task_id` + `assumptions`(逐项注明用户给定 / illustrative)
89
+ + `method`(公式或步骤)+ `results`(表格)+ `sensitivity`(若有)+ `caveats`(失效条件)。字段名与
90
+ 数值照程序返回值写,不手抄。
91
+ - **边界**:不做投资判断、不给买卖建议、不承诺收益;结论与建议由主 Agent 写。没有 Dataset 就没有
92
+ `chart_source_ref`,可视化 gate 默认 `not_needed`;只有委派明确给了可出图的数据时才考虑出图。
93
+ - **方法**:需要估值/建模方法时,按角色目录加载精选方法(如 `china-dcf` / `three-statement-modeling`),
94
+ 但方法只提供口径与步骤,不提供这家公司的真实数字。
95
+
96
+
78
97
  ## 4. 受控查询(主 Agent ↔ data_junior)
79
98
 
80
99
  请求:
@@ -5,6 +5,10 @@ description: Use when the user requests a complete research report or comprehens
5
5
 
6
6
  # 单一上市公司投研与风险审阅
7
7
 
8
+ > **定位**:本协议只定义研究流程、证据门与报告形状;估值、财务质量、行业竞争等分析方法在精选方法层。
9
+ > 主 Agent 能加载的方法(如 `china-initiating-coverage` / `buffett-investment-framework`)按主目录加载;
10
+ > 估值、三表等 data_junior 方法不在主目录里,交给 data_junior 按它的目录加载。
11
+ > 协议与方法正交:不要用本协议替代方法,也不要用方法改写本协议的证据门。
8
12
  本 skill 只供主 Agent 编排单一标的的完整研究报告;报告就是最终答复正文,不创建单独的报告产物。它不增加工具权限、不创建新角色、不要求每项都调用一个工具。普通的单点事实问题不必套用本流程;用户明确要求完整报告时,各维度必须有证据支持的结论或明确的未评估理由。
9
13
 
10
14
  ## 1. 边界与入口
@@ -5,6 +5,9 @@ description: Use for a focused impact analysis of a listed company's announcemen
5
5
 
6
6
  # 事件与公告影响分析
7
7
 
8
+ > **定位**:本协议只定义事件核验、影响链与输出流程;财报前瞻、催化剂日历、事件研究等方法在精选方法层。
9
+ > 任务同时命中且该方法在本角色目录中可用时,按名加载对应 Skill(如 `china-earnings-preview` / `earnings-preview` / `catalyst-*`);
10
+ > 协议与方法正交:不要用本协议替代方法,也不要用方法改写本协议的证据门。
8
11
  本 skill 只供主 Agent 处理聚焦某上市公司事件的影响问题;分析写在最终答复,不新增工具、角色或报告通道。用户只问“有没有公告/公告是什么”时核实事实并简答;明确要求完整单股研究时以 `capital-equity-research` 为主,本 skill 只补事件核验,不重复拉全套数据。
9
12
 
10
13
  ## 1. 定位与委派
@@ -11,10 +11,10 @@ description: Use when delegating in Capital mode — running the per-round list_
11
11
  ## 1. 每轮预检(不可跳过)
12
12
 
13
13
  - 触发点:**每次新的用户请求或新一轮任务**。在"本轮第一次调用任何创建工具"之前完成。
14
- - 创建工具指:`subagent_data_collector`、`subagent_data_junior`、`subagent_web_retriever`,以及今后新增的任何**专用**委派工具。
14
+ - 创建工具:`subagent_data_collector` / `subagent_data_junior` / `subagent_web_retriever`。
15
15
  - 查询方式:`list_agents(scope="children")`,一次即可。
16
- - 不要把它当成"仅在会话恢复时才做的回忆步骤":上一轮查到的空列表不能代替本轮查询。
17
- - 一次查询结果覆盖本轮所有角色,不要为每个角色重复查询;等待回传期间也不要轮询。
16
+ - 上一轮的空列表不能代替本轮查询。
17
+ - 一次查询覆盖全部角色;等待回传期间不要轮询。
18
18
 
19
19
  ## 1.1 Canonical task_id(不可分叉)
20
20
 
@@ -32,15 +32,13 @@ description: Use when delegating in Capital mode — running the per-round list_
32
32
  只要出现在列表里,就用该 id 调 `send_message` 派发本次任务。`running` 在其最近的 step 边界
33
33
  接收消息;`inactive` 带着自己的上下文开一个新回合。
34
34
  不得因为"空闲""上一任务已完成""任务标题变了""想并行"而创建第二个同角色 Agent。
35
- 3. **诊断/暂时不可用**:已记录 id 但列表出现 diagnostic 或暂时不可用,先用该 id 尝试
36
- `send_message`,或重新 `list_agents` 核验;不得直接创建第二个同角色 Agent。
35
+ 3. **诊断/暂时不可用**:先用已记录 id 尝试 `send_message` 或重新核验;不得创建第二个同角色 Agent。
37
36
  4. **确实不存在**:只有确认该 child 不存在且没有可用复用 id,才进入创建分支。
38
37
 
39
38
  ### 2.1 ID 纪律(防长上下文抄错 id)
40
39
 
41
- child id 是随机 UUID、无语义可校验,长会话里凭记忆/从历史轮次复述 id 极易抄错,甚至把
42
- A 角色的请求投给 B 角色。官方机制是 **`list_agents` 即权威 id 存储**——id 不需要被记住,
43
- 只需要在用之前查一次:
40
+ child id 是随机 UUID,长会话里凭记忆复述极易抄错,甚至把 A 角色的请求投给 B 角色。
41
+ **`list_agents` 即权威 id 存储**:用之前查一次就够了:
44
42
 
45
43
  - `send_message` 的 `agent_id` 只从**最近一次 `list_agents` 的渲染输出**复制(每行就是
46
44
  `id [status] — label`);不从早前轮次的上下文、委派清单或旧工具回执里复述 id。
@@ -83,7 +81,7 @@ A 角色的请求投给 B 角色。官方机制是 **`list_agents` 即权威 id
83
81
  | 诉求 | 归属 |
84
82
  |------|------|
85
83
  | 行情、财务、历史、交易日历等结构化数据 | `data_collector` |
86
- | 数据集质量检查、缺失/重复/时间范围/基础统计 | `data_junior` |
84
+ | 数据集质量检查、基础统计、无 Dataset 的假设建模/估值/情景/敏感性 | `data_junior`(给假设与口径,不自己算) |
87
85
  | 网页材料、公告、新闻、传闻原文、公司背景、需要最新信息的事实 | `web_retriever` |
88
86
  | 专业分析(Python、回测、统计检验) | 尚未启用——先由 `data_junior` 出基础 profile,并如实告知用户 |
89
87
 
@@ -5,6 +5,9 @@ description: Use when the user requests a review of their actual holdings or inv
5
5
 
6
6
  # 持仓与组合复盘
7
7
 
8
+ > **定位**:本协议只定义持仓读取、证据门与复盘输出;收益归因、集中度、配置偏离等分析框架在精选方法层。
9
+ > 任务同时命中且该方法在本角色目录中可用时,按名加载对应 Skill(如 `portfolio-review` / `risk-stress-test`);
10
+ > 协议与方法正交:不要用本协议替代方法,也不要用方法改写本协议的证据门。
8
11
  本 skill 只供主 Agent 对用户的实际持仓做组合层复盘;最终答复就是交付,不创建持仓账户、报告文件、自动跟踪或交易指令。仓位有两个来路:用户当场给的表/文字,以及他在自选股面板里亲手标过持仓的那几条(经 `get_watchlist` 读到的 `held` 与自报的 `weight_pct`)。自选清单**只能经这条只读工具**读,券商账户仍读不到;未标持仓的关注条目、历史对话里的提及与市场公开的机构持仓都不算用户仓位。`holding_marked_age_days` 较大(或用户说过最近调过仓)时,先把那几格向用户复述确认再用于组合判断——别拿一句很久以前的话算今天的风险。
9
12
 
10
13
  ## 1. 输入边界与委派
@@ -5,6 +5,7 @@ description: Use when returning or labelling what was retrieved — the numbered
5
5
 
6
6
  # Capital 检索协议 · 第二册:回传格式、来源核验与文档解析
7
7
 
8
+ > **定位**:本册只定义回传格式、来源核验与文档解析;具体分析与精读方法在精选方法层,命中时按角色目录另行加载。
8
9
  本册是检索协议的第二册(§5 回传格式 / §6 官方证券来源域名核验 / §7 抓取与失败处置 / §8 文档解析 `ocr`)。
9
10
  "去哪取、怎么调"在第一册 `capital-web-protocol` §1–§4;两册 §编号连续,跨册引用照原编号点名。
10
11
 
@@ -5,6 +5,9 @@ description: Use in Capital mode when retrieving external material — the anyse
5
5
 
6
6
  # Capital 检索协议 · 第一册:来源边界与收敛
7
7
 
8
+ > **定位**:本协议只定义来源边界、检索收敛与回传格式;10-K 精读、电话会纪要、逐条核验等方法在精选方法层。
9
+ > 任务同时命中且该方法在本角色目录中可用时,按名加载对应 Skill(如 `10k-digest` / `earnings-call-analysis` / `fact-check`);
10
+ > 协议与方法正交:不要用本协议替代方法,也不要用方法改写本协议的来源纪律。
8
11
  `web_retriever` 子 Agent 的工作细则;主 Agent 呈现检索结论时同样按 `capital-web-evidence` §5 的回传格式保留来源标注。
9
12
  persona 只保留硬规则(先定来源再动手、只用这十四个工具、一次一个 URL、无来源不作证据);
10
13
  本文件是其余细节。