@y9931666/dsh-plugin-crossfire 0.1.1 → 0.1.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/README.md +2 -0
  2. package/lib/client.js +160 -19
  3. package/lib/index.js +1 -1
  4. package/package.json +1 -1
  5. package/release-notes/v0.1.2.md +44 -0
  6. package/release-notes/v0.1.3.md +21 -0
  7. package/lib/types/budget.d.ts +0 -86
  8. package/lib/types/client/ReviewCard.d.ts +0 -41
  9. package/lib/types/client/SettingsView.d.ts +0 -34
  10. package/lib/types/client/brand.d.ts +0 -55
  11. package/lib/types/client/defectTitle.d.ts +0 -23
  12. package/lib/types/client/index.d.ts +0 -21
  13. package/lib/types/client/locales.d.ts +0 -19
  14. package/lib/types/client/merge.d.ts +0 -27
  15. package/lib/types/client/promptView.d.ts +0 -63
  16. package/lib/types/client/session-cache.d.ts +0 -49
  17. package/lib/types/client/slot-boundary.d.ts +0 -46
  18. package/lib/types/client/wire.d.ts +0 -192
  19. package/lib/types/dimensions.d.ts +0 -47
  20. package/lib/types/engine.d.ts +0 -172
  21. package/lib/types/etag.d.ts +0 -40
  22. package/lib/types/expert-events.d.ts +0 -110
  23. package/lib/types/export-md.d.ts +0 -21
  24. package/lib/types/harness-compat.d.ts +0 -104
  25. package/lib/types/index.d.ts +0 -89
  26. package/lib/types/members.d.ts +0 -143
  27. package/lib/types/noise.d.ts +0 -29
  28. package/lib/types/preferences.d.ts +0 -134
  29. package/lib/types/prompt.d.ts +0 -16
  30. package/lib/types/redteam.d.ts +0 -115
  31. package/lib/types/review.d.ts +0 -152
  32. package/lib/types/rpc.d.ts +0 -176
  33. package/lib/types/split.d.ts +0 -156
  34. package/lib/types/state.d.ts +0 -84
  35. package/lib/types/tools.d.ts +0 -59
  36. package/lib/types/types.d.ts +0 -308
  37. package/lib/types/version.d.ts +0 -18
  38. package/lib/types/web-guard.d.ts +0 -55
@@ -1,176 +0,0 @@
1
- /**
2
- * Crossfire 的浏览器面:一个 `dispatch`(RPC)+ 一个快照收集器(GET)。
3
- *
4
- * ## 两条传输,同一份 dispatch
5
- *
6
- * 1. 插件自有的 web POST 路由 `/plugins/dsh-plugin-crossfire/rpc`(首选:任何带 web
7
- * 服务的 profile 都可达);
8
- * 2. 宿主通用 connection 通道(兜底,经 `ctx.get` 懒取)。
9
- *
10
- * ## O1:卡片按钮**直推** host 状态机
11
- *
12
- * 这是 crossfire 与圆桌会议最重要的编排差异。圆桌的 UI 只能写"用户行为队列",
13
- * 等主持人下一轮执行;针锋的按钮直接调用这里的 `crossfire/review.advance`,
14
- * 因此用户点"开审"不必等一整个模型回合。
15
- *
16
- * 代价是:**RPC 路径没有 `exec.agent`**。凡是需要父 Agent 的动作(拉起子代理)
17
- * 就得先按会话 id 把 Agent 找回来(`ctx.agents.get`);找不到(会话已冷)时如实
18
- * 失败并让用户改用对话触发,而不是假装成功。
19
- *
20
- * ## 一条不可越界的规则
21
- *
22
- * `crossfire/defect.setStatus` **只允许人从界面调用**。它没有对应的 agent 工具,
23
- * 也永远不该有:表态权是这个插件存在的理由本身。
24
- *
25
- * @module dsh-plugin-crossfire/rpc
26
- */
27
- import type { Context } from '@deepseek-ai/cordis';
28
- import { type PreferenceStore } from './preferences.ts';
29
- import { exportFile } from './review.ts';
30
- import type { ToolsConfig } from './tools.ts';
31
- import { type CrossfireRecord, type Intensity } from './types.ts';
32
- /** 插件自有 RPC 路由(浏览器半体优先走这条)。 */
33
- export declare const RPC_ROUTE = "/plugins/dsh-plugin-crossfire/rpc";
34
- /** 插件自有快照路由(卡片每秒轮询它)。 */
35
- export declare const STATE_ROUTE = "/plugins/dsh-plugin-crossfire/state";
36
- /** 运行时依赖:偏好存储 + 工具/引擎共用的配置(单一来源)。 */
37
- export interface CrossfireRuntime {
38
- prefs: PreferenceStore;
39
- tools: ToolsConfig;
40
- }
41
- /** RPC 失败包封。 */
42
- export interface RpcFailure {
43
- ok: false;
44
- error: {
45
- code: string;
46
- message: string;
47
- };
48
- }
49
- /** RPC 结果包封(成功 / 失败二选一)。 */
50
- export type RpcResult = {
51
- ok: true;
52
- value: unknown;
53
- } | RpcFailure;
54
- /** dispatch 的类型:端点名 + 载荷 → 结果包封。 */
55
- export type RpcDispatch = (endpoint: string, payload: unknown) => Promise<RpcResult>;
56
- /** 卡片所需的评审快照(刻意不含 workspace 绝对路径之外的任何隐私内容)。 */
57
- export interface ReviewSnapshot {
58
- reviewId: string;
59
- status: CrossfireRecord['status'];
60
- subjectTitle: string;
61
- subjectContent: string;
62
- subjectSource: string;
63
- stanceText: string;
64
- stanceOrigin: string;
65
- dimensions: string[];
66
- intensity: Intensity;
67
- intensityLabel: string;
68
- reviewPass: number;
69
- maxReviewPass: number;
70
- experts: {
71
- key: string;
72
- dimension: string;
73
- status: string;
74
- defectCount: number;
75
- reportCount?: number;
76
- /** 实际模型路由;未指定(继承主持人)时两个字段都不出现。 */
77
- provider?: string;
78
- model?: string;
79
- /** 用户补充的角色定位(专家列表里可编辑)。 */
80
- role?: string;
81
- note?: string;
82
- }[];
83
- defects: {
84
- id: string;
85
- expertKey: string;
86
- dimension: string;
87
- dimensionFallback?: boolean;
88
- content: string;
89
- quote?: string;
90
- evidence?: {
91
- kind: 'repro' | 'argument';
92
- text: string;
93
- };
94
- strikesStance?: boolean;
95
- status: 'pending' | 'endorsed' | 'rejected';
96
- rejectReason?: string;
97
- /** 复审核对结论;`verdict` 缺席 = 尚未判断(**不是**"未修复")。 */
98
- recheck?: {
99
- pass: number;
100
- verdict?: string;
101
- note?: string;
102
- };
103
- }[];
104
- counts: {
105
- total: number;
106
- pending: number;
107
- endorsed: number;
108
- rejected: number;
109
- strikes: number;
110
- };
111
- budget: {
112
- maxRounds: number;
113
- maxTokens: number;
114
- usedRounds: number;
115
- usedTokens: number;
116
- };
117
- startedAt: number;
118
- updatedAt: number;
119
- /** 这份评审所在的状态根(客户端回传后可免去再次遍历工作区)。 */
120
- stateRoot: string;
121
- }
122
- /** 把记录收敛成卡片快照。 */
123
- export declare function snapshotOf(record: CrossfireRecord, stateRoot: string): ReviewSnapshot;
124
- /** 身份判定的结果。 */
125
- export type ActorVerdict = {
126
- ok: true;
127
- bound: boolean;
128
- } | {
129
- ok: false;
130
- code: 'no-actor' | 'foreign-owner';
131
- message: string;
132
- };
133
- /**
134
- * 判定"谁在操作这一场评审"。
135
- *
136
- * ## 为什么必须是严格的(这里出过一个真实的安全缺陷)
137
- *
138
- * 会话 id 在这个插件里**同时是凭据和权限**:`load()` 用它做归属校验,
139
- * `review.advance` 的 attack 分支又用它换回 live Agent 去拉起专家。原先的写法把
140
- * 空会话当成"跳过校验",于是当客户端没把 session 送进来时:
141
- *
142
- * - 归属校验整条短路(任何会话都能操作任何记录);
143
- * - 而 attack 又会退回用**记录里的 owner** 换 Agent,照样把专家拉起来。
144
- *
145
- * 结果是一条能真正干活的越权通道,而且它的成功响应与合法调用完全同形 —— 验收时
146
- * 根本分不出来。红队在验收流程里抓到了这一点。
147
- *
148
- * 所以现在的规则是:**必须声称一个会话**。规则本身是纯函数,因此可以被测试直接
149
- * 钉住(`test/rpc-identity.test.mjs`),而不是只靠人工点一次按钮。
150
- *
151
- * @param ownerSessionId - 记录里的 owner(早期数据可能没有)。
152
- * @param actorSession - 调用方声称的会话 id(缺失时为 `''`)。
153
- */
154
- export declare function judgeActor(ownerSessionId: string | undefined, actorSession: string): ActorVerdict;
155
- /** 收集全部评审快照(卡片轮询的数据源)。 */
156
- export declare function collectSnapshots(ctx: Context, stateDir: string, session: string): Promise<{
157
- reviews: ReviewSnapshot[];
158
- note?: string;
159
- }>;
160
- /** 注册 RPC 端点,返回可复用的 `dispatch`。 */
161
- export declare function registerRpc(ctx: Context, runtime: CrossfireRuntime): RpcDispatch;
162
- /**
163
- * 从界面直接开一场评审。
164
- *
165
- * 与 `crossfire_open` 工具同源,区别只是工作区来自会话 id 而不是 `exec.agent`。
166
- */
167
- export declare function openReviewFromRpc(ctx: Context, runtime: CrossfireRuntime, input: {
168
- session: string;
169
- title: string;
170
- content: string;
171
- dimensions?: unknown;
172
- intensity?: unknown;
173
- stance?: string;
174
- }): Promise<RpcResult>;
175
- /** 导出路径(批 4 的下载按钮用)。 */
176
- export { exportFile };
@@ -1,156 +0,0 @@
1
- /**
2
- * 观点拆分:把红队专家的一条发言拆成 1~3 条独立缺陷,用户即可对单条缺陷
3
- * 「认定/驳回」。
4
- *
5
- * 三道防线(沿用圆桌里被真实数据验证过的设计,**不要改**):
6
- * ① JSON schema 严格约束输出(tools 参数 + temperature 0)
7
- * ② 任何解析失败 → 返回 null,由调用方整条兜底(seq=0)
8
- * ③ quote 必须是发言原文的子串(规范化后 indexOf),否则丢弃该 quote
9
- *
10
- * crossfire 相对圆桌的三处改动:
11
- * - **维度归一化**:拆分结果里的 dimension 不再直接采信,一律过
12
- * `resolveDimension`,保证落库的 dimension 一定 ∈ `allowed`;
13
- * - **打穿标记**:每条缺陷可带 `strikesStance`(是否打穿了用户立场里的某条理由);
14
- * - 工具名与 system 提示词按 crossfire 改写。
15
- *
16
- * @module dsh-plugin-crossfire/split
17
- */
18
- /** 一条拆分结果(= 一条待裁决的缺陷)。 */
19
- export interface SplitLine {
20
- content: string;
21
- quote?: string;
22
- /** 归一化后的维度,只要 `allowed` 非空就一定 ∈ allowed。 */
23
- dimension: string;
24
- /** true = 模型给的原始维度越界/缺失,落库时被归一化过。 */
25
- dimensionFallback?: boolean;
26
- /** 是否打穿了用户在「立场」里给出的某条理由。 */
27
- strikesStance?: boolean;
28
- /** 证据分级(C1):代码/bug 类 = repro(可复现步骤);设计类 = argument(论证链)。 */
29
- evidence?: {
30
- kind: 'repro' | 'argument';
31
- text: string;
32
- };
33
- }
34
- /** 拆分调用的模型路由配置(默认 deepseek-official/deepseek-v4-flash,实测可用)。 */
35
- export interface ReviewSplitConfig {
36
- provider: string;
37
- model: string;
38
- /** 每条发言最多拆几条缺陷(默认 3)。 */
39
- maxOpinions: number;
40
- /**
41
- * 拆分阶段的 LLM 并发上限(默认 4;`1` = 串行)。
42
- *
43
- * 它是"收集"这一步的墙钟时间决定项:一条发言一次往返,此前是串行 `await`,一场
44
- * 21 条发言的评审就是 21 次串行往返(红队评审抓出的性能缺陷)。上限刻意不高 ——
45
- * 这些请求打同一个 provider,拉满只会撞速率限制反而更慢。
46
- *
47
- * 放在这里而不是插件 Config:两个调用点(工具与 RPC 直推)读的都是同一个
48
- * `reviewSplit`,因此两边的并发行为天然一致,不会分叉。
49
- */
50
- llmConcurrency?: number;
51
- }
52
- /** 最小化 LLM 服务形状(与 ctx.llm.stream 结构兼容)。 */
53
- export interface SplitLlmLike {
54
- stream(options: {
55
- provider: string;
56
- model: string;
57
- messages: {
58
- id: string;
59
- role: 'user';
60
- content: {
61
- type: 'text';
62
- text: string;
63
- }[];
64
- source: {
65
- kind: 'user';
66
- };
67
- }[];
68
- system?: string;
69
- tools?: {
70
- name: string;
71
- description: string;
72
- parameters: Record<string, unknown>;
73
- }[];
74
- temperature?: number;
75
- maxTokens?: number;
76
- signal?: AbortSignal;
77
- }): AsyncIterable<unknown>;
78
- }
79
- /** 拆分工具的 JSON schema(防线①)。导出以便测试断言 schema 形状。 */
80
- export declare const SPLIT_TOOL: {
81
- readonly name: "split_crossfire_defect";
82
- readonly description: "把一条红队专家发言拆成 1~3 条独立缺陷(每条缺陷只含一个问题)。";
83
- readonly parameters: {
84
- readonly type: "object";
85
- readonly additionalProperties: false;
86
- readonly properties: {
87
- readonly defects: {
88
- readonly type: "array";
89
- readonly minItems: 1;
90
- readonly maxItems: 3;
91
- readonly items: {
92
- readonly type: "object";
93
- readonly additionalProperties: false;
94
- readonly properties: {
95
- readonly content: {
96
- readonly type: "string";
97
- readonly description: "单条缺陷的完整表述。";
98
- };
99
- readonly quote: {
100
- readonly type: "string";
101
- readonly description: "发言原文中与该缺陷对应的子串(可选,必须逐字来自发言原文)。";
102
- };
103
- readonly dimension: {
104
- readonly type: "string";
105
- readonly description: "缺陷所属维度。必须逐字取自给定清单 allowed 中的一项,不得自创。";
106
- };
107
- readonly strikes_stance: {
108
- readonly type: "boolean";
109
- readonly description: "该缺陷是否打穿了用户在「立场」里给出的某条理由。";
110
- };
111
- readonly evidence: {
112
- readonly type: "object";
113
- readonly description: "证据分级(C1):代码/bug 类缺陷填 repro(附可复现步骤 1. 2. 3.);设计类缺陷填 argument(附论证链,不编造伪复现步骤)。无法给出证据时省略该字段。";
114
- readonly additionalProperties: false;
115
- readonly properties: {
116
- readonly kind: {
117
- readonly type: "string";
118
- readonly enum: readonly ["repro", "argument"];
119
- readonly description: "repro=可复现步骤(代码/bug 类);argument=论证链(设计类)。";
120
- };
121
- readonly text: {
122
- readonly type: "string";
123
- readonly description: "证据正文:复现步骤(编号 1. 2. 3.)或论证链,≤600 字符。";
124
- };
125
- };
126
- readonly required: readonly ["kind", "text"];
127
- };
128
- };
129
- readonly required: readonly ["content", "dimension"];
130
- };
131
- };
132
- };
133
- readonly required: readonly ["defects"];
134
- };
135
- };
136
- /**
137
- * 判定这段文字里专家自己写的「针对立场」结论是不是**打穿**。
138
- *
139
- * ## 为什么不能只写 `includes('打穿')`(这是真实存在的坑)
140
- *
141
- * `未打穿` 的后两个字就是 `打穿`,纯子串匹配会把"没打穿"读成"打穿了",方向整个反过来。
142
- * 所以这里匹配有界的标记(`针对立场…:打穿|未打穿`)并**显式取反**:只有 `未` 缺席时
143
- * 才算打穿;标记压根不存在(含 `undefined`)也一律算没打穿。
144
- *
145
- * 之所以要有这个本地判定:专家的信封格式是**固定**的,报告正文里本来就写着结论。
146
- * 模型拆分失败退到本地启发式({@link splitByMarkers})时不该把这个信号丢掉 ——
147
- * 那正是"打穿立场"标签永远显示不出来的原因之一。
148
- */
149
- export declare function stanceMarkerStrikes(text: string | undefined): boolean;
150
- export declare function splitByMarkers(content: string, allowed: readonly string[]): SplitLine[] | null;
151
- /**
152
- * 拆分一条发言为若干独立缺陷;任何失败返回 null(调用方整条兜底)。
153
- * quote 与发言原文做规范化子串校验(防线③),不匹配即丢弃。
154
- * dimension 一律过 `resolveDimension`(落库值必须 ∈ allowed)。
155
- */
156
- export declare function splitUtterance(llm: SplitLlmLike, config: ReviewSplitConfig, expertKey: string, content: string, allowed: readonly string[], stance: string): Promise<SplitLine[] | null>;
@@ -1,84 +0,0 @@
1
- /**
2
- * Crossfire durable state:`<workspace>/<stateDir>/crossfire/<reviewId>/` 下的
3
- * 原子文件持久化 + 进程内串行锁。
4
- *
5
- * 目录布局(与圆桌会议的**关键差异**:多一层 `crossfire/` 命名空间,因为本
6
- * 插件不依附任何一场会议,可以完全不开会直接审):
7
- *
8
- * <stateRoot>/crossfire/<reviewId>/review.json — 评审记录(主文档)
9
- * <stateRoot>/crossfire/<reviewId>/transcript.jsonl — 红队发言(append-only)
10
- * <stateRoot>/crossfire/<reviewId>/user-actions.jsonl — 用户行为队列
11
- * <stateRoot>/crossfire/<reviewId>/export.md — 导出物
12
- *
13
- * 三条铁律(沿用圆桌已验证的契约):
14
- * 1. **读失败绝不抛给调用方**:坏 JSON / 缺文件一律返回 undefined 或空集,
15
- * 由调用方决定降级方式。状态损坏不能让整张卡片从界面上消失。
16
- * 2. **写必须原子**:优先宿主 `@deepseek-ai/dsh-atomic-write`(带 Windows
17
- * 瞬时 EACCES/EBUSY 重试),否则本地同目录 tmp + rename 兜底。
18
- * 3. **坏行必须被计数**:`user-actions.jsonl` 的半行 JSON 若被静默跳过,
19
- * 那条用户操作就永久丢失且无人知道(圆桌 A2 的真实教训)。
20
- *
21
- * @module dsh-plugin-crossfire/state
22
- */
23
- /** 本插件在状态根下的固定命名空间目录名。 */
24
- export declare const CROSSFIRE_NAMESPACE = "crossfire";
25
- /** Stable directory id from a display name (keeps CJK, lowercases latin). */
26
- export declare function sanitizeKey(value: string): string;
27
- /**
28
- * Serialize async operations sharing one key inside this process.
29
- *
30
- * 注意(已知限制,写在任务书里):这是**进程内**锁,跨进程不互斥。多窗口同时
31
- * 操作同一场评审时,后写者覆盖前者,只靠原子写保证文件不会写坏。v0.1.0 接受。
32
- */
33
- export declare function withCrossfireLock<T>(key: string, operation: () => Promise<T>): Promise<T>;
34
- /** 锁 key:同一场评审的操作互相串行。 */
35
- export declare function reviewLockKey(stateRoot: string, reviewId: string): string;
36
- /** Absolute state root under a workspace. */
37
- export declare function stateRootOf(workspace: string, stateDir: string): string;
38
- /** `<stateRoot>/crossfire` —— 本插件的命名空间目录。 */
39
- export declare function crossfireRootOf(stateRoot: string): string;
40
- /** Absolute directory of one review. */
41
- export declare function reviewDirOf(stateRoot: string, reviewId: string): string;
42
- /** 生成一个可读、可排序、无碰撞的评审 id:`x-<yyyyMMdd-HHmmss>-<4位>`。 */
43
- export declare function newReviewId(now?: number, random?: string): string;
44
- /** Atomically publish a UTF-8 text file. */
45
- export declare function writeTextAtomic(file: string, text: string): Promise<void>;
46
- /**
47
- * 原子写一份**带 UTF-8 BOM** 的文本,供人用记事本直接打开。
48
- *
49
- * 为什么单独一个函数:Windows 记事本对"无 BOM 的 UTF-8"时常误判成 ANSI,中文变乱码。
50
- * 而 `.md` 扩展名在不少机器上被别的程序抢走,双击进不了记事本。所以导出时额外写一份
51
- * `.txt`(带 BOM)—— 用户反馈"导出来的产物我无法用记事本查看"就是这个原因。
52
- *
53
- * BOM 只加在这份人读副本上:`.md` 保持无 BOM,交给 Markdown 渲染器更干净。
54
- */
55
- export declare function writeTextAtomicWithBom(file: string, text: string): Promise<void>;
56
- /** Atomically publish a JSON file (same-directory tmp + rename). */
57
- export declare function writeJsonAtomic(file: string, value: unknown): Promise<void>;
58
- /** 确保目录存在(幂等)。 */
59
- export declare function ensureDir(dir: string): Promise<void>;
60
- /**
61
- * 读一个 JSON 文件;**不存在或损坏都返回 undefined**(铁律 1)。
62
- *
63
- * 调用方拿到 undefined 时应当降级,而不是把异常抛给用户界面。
64
- */
65
- export declare function readJsonFile<T>(file: string): Promise<T | undefined>;
66
- /** 追加一条 JSONL 记录(自动建目录)。 */
67
- export declare function appendJsonLine(file: string, value: unknown): Promise<void>;
68
- /** 读取 JSONL 的结果:合法条目 + **被丢弃的坏行数**(铁律 3)。 */
69
- export interface JsonLinesReport<T> {
70
- items: T[];
71
- /** 无法解析的行数。非 0 时调用方必须如实告知用户,不许静默吞掉。 */
72
- malformed: number;
73
- }
74
- /**
75
- * 读 JSONL;坏行被跳过但**计数**。
76
- *
77
- * 容忍被截断的尾行(进程在写一半时崩溃留下的半行 JSON),但它同样计入
78
- * `malformed` —— 因为那条记录确实丢了。
79
- */
80
- export declare function readJsonLines<T>(file: string): Promise<JsonLinesReport<T>>;
81
- /** 列出状态根下的全部评审 id(按名字排序,名字本身按时间可排)。 */
82
- export declare function listReviewIds(stateRoot: string): Promise<string[]>;
83
- /** 删除一场评审的全部落盘记录(幂等;目录不存在不算错误)。 */
84
- export declare function removeReviewDir(stateRoot: string, reviewId: string): Promise<void>;
@@ -1,59 +0,0 @@
1
- /**
2
- * `crossfire_*` 模型面向的工具。
3
- *
4
- * ## 编排模型(与圆桌会议的根本差异)
5
- *
6
- * 圆桌是"主持人统筹":模型负责建会、拉人、转述、聚合、推进每一轮。crossfire 不
7
- * 需要这些 —— 卡片上的按钮经 RPC 直接驱动 host 状态机(O1 决策)。所以这里的工具
8
- * 面刻意小:**六步、每步一件事、每步可单独重试**,模型只在"推不动了"的时候介入。
9
- *
10
- * 状态机(见 review.ts):
11
- * draft --open--> attacking --attack--> judging --collect--> settled --finish-->
12
- * settled --recheck--> attacking(复审:只核对旧账,不许开新战线)
13
- *
14
- * ## 一条不可越界的规则
15
- *
16
- * **没有任何"代表态"的工具。** 缺陷的认定 / 驳回只能由人在卡片上操作,因此这里
17
- * 找不到 `crossfire_decide` 这类入口,而且不该有人加上它 —— 表态权是这个插件
18
- * 存在的理由本身。
19
- *
20
- * @module dsh-plugin-crossfire/tools
21
- */
22
- import type { Context } from '@deepseek-ai/cordis';
23
- import type { ReviewSplitConfig } from './split.ts';
24
- import type { Intensity } from './types.ts';
25
- /** 设置页那一层(每次调用实时读取,因此改设置对新建评审立即生效)。 */
26
- export interface ReviewDefaults {
27
- intensity: Intensity;
28
- maxRounds: number;
29
- maxTokens: number;
30
- expertMaxTokens: number;
31
- expertMaxOpinions: number;
32
- customDimensions: string[];
33
- }
34
- /** 工具运行时配置。 */
35
- export interface ToolsConfig {
36
- stateDir: string;
37
- memberProvider: string;
38
- maxExperts: number;
39
- memberMaxDepth?: number;
40
- /**
41
- * 专家**继承主持人**时实际生效的模型路由。
42
- *
43
- * 只为可观测性:开打时把这个生效值写回专家记录,卡片才能把"继承"画成真实品牌
44
- * (DeepSeek 的蓝色 DS 块),而不是中性灰 `?`。它不参与任何路由决策。
45
- */
46
- defaultProvider?: string;
47
- defaultModel?: string;
48
- /** 观点拆分的 LLM 路由(不可用时自动退到本地兜底)。 */
49
- reviewSplit: ReviewSplitConfig;
50
- /** 实时读取的默认值。 */
51
- getDefaults: () => ReviewDefaults;
52
- }
53
- export declare function registerCrossfireTools(ctx: Context, config: ToolsConfig): void;
54
- /**
55
- * 归属识别说明:`crossfire_report` 只认**专家索引**(expert-events 的进程内
56
- * childId → 评审位置)。专家是通过 `startContinuable` 拉起的子代理,唯一可靠的
57
- * 归属线索就是它的 childId。刻意不去"扫所有评审找 ownerSessionId 匹配" ——
58
- * 那样会让一个普通会话冒充专家提交发言。
59
- */