dsh-data-domain-knowledge 0.1.0-alpha.2 → 0.1.0-alpha.4
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/README.md +147 -19
- package/cordis.patch.yml +25 -10
- package/lib/client.js +6400 -3326
- package/lib/doc-page.js +7761 -0
- package/lib/types/convert/host.d.ts.map +1 -1
- package/lib/types/convert/host.js +63 -11
- package/lib/types/convert/host.js.map +1 -1
- package/lib/types/convert/ingest.d.ts +7 -4
- package/lib/types/convert/ingest.d.ts.map +1 -1
- package/lib/types/convert/ingest.js +52 -14
- package/lib/types/convert/ingest.js.map +1 -1
- package/lib/types/convert/types.d.ts +2 -2
- package/lib/types/convert/types.d.ts.map +1 -1
- package/lib/types/convert/types.js +2 -2
- package/lib/types/convert/types.js.map +1 -1
- package/lib/types/diagnosis/cards.d.ts +8 -7
- package/lib/types/diagnosis/cards.d.ts.map +1 -1
- package/lib/types/diagnosis/cards.js +119 -49
- package/lib/types/diagnosis/cards.js.map +1 -1
- package/lib/types/diagnosis/run.d.ts +57 -0
- package/lib/types/diagnosis/run.d.ts.map +1 -0
- package/lib/types/diagnosis/run.js +245 -0
- package/lib/types/diagnosis/run.js.map +1 -0
- package/lib/types/diagnosis/schema.d.ts +25 -2
- package/lib/types/diagnosis/schema.d.ts.map +1 -1
- package/lib/types/diagnosis/schema.js +64 -25
- package/lib/types/diagnosis/schema.js.map +1 -1
- package/lib/types/diagnosis/seed-source.d.ts +17 -2
- package/lib/types/diagnosis/seed-source.d.ts.map +1 -1
- package/lib/types/diagnosis/seed-source.js +19 -2
- package/lib/types/diagnosis/seed-source.js.map +1 -1
- package/lib/types/diagnosis/seed.d.ts +32 -42
- package/lib/types/diagnosis/seed.d.ts.map +1 -1
- package/lib/types/diagnosis/seed.js +187 -51
- package/lib/types/diagnosis/seed.js.map +1 -1
- package/lib/types/diagnosis/store.d.ts +95 -25
- package/lib/types/diagnosis/store.d.ts.map +1 -1
- package/lib/types/diagnosis/store.js +297 -166
- package/lib/types/diagnosis/store.js.map +1 -1
- package/lib/types/diagnosis/types.d.ts +168 -16
- package/lib/types/diagnosis/types.d.ts.map +1 -1
- package/lib/types/diagnosis/types.js +1 -1
- package/lib/types/diagnosis/types.js.map +1 -1
- package/lib/types/document-page.d.ts +39 -0
- package/lib/types/document-page.d.ts.map +1 -0
- package/lib/types/document-page.js +43 -0
- package/lib/types/document-page.js.map +1 -0
- package/lib/types/extract-model.d.ts +67 -27
- package/lib/types/extract-model.d.ts.map +1 -1
- package/lib/types/extract-model.js +225 -97
- package/lib/types/extract-model.js.map +1 -1
- package/lib/types/extract.d.ts +16 -0
- package/lib/types/extract.d.ts.map +1 -1
- package/lib/types/extract.js +19 -2
- package/lib/types/extract.js.map +1 -1
- package/lib/types/fs-atomic.d.ts +11 -0
- package/lib/types/fs-atomic.d.ts.map +1 -0
- package/lib/types/fs-atomic.js +41 -0
- package/lib/types/fs-atomic.js.map +1 -0
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/index.js +466 -63
- package/lib/types/index.js.map +1 -1
- package/lib/types/intent/types.js +1 -1
- package/lib/types/intent/types.js.map +1 -1
- package/lib/types/knowledge-bases.d.ts +23 -12
- package/lib/types/knowledge-bases.d.ts.map +1 -1
- package/lib/types/knowledge-bases.js +37 -44
- package/lib/types/knowledge-bases.js.map +1 -1
- package/lib/types/layout.d.ts +3 -3
- package/lib/types/layout.d.ts.map +1 -1
- package/lib/types/layout.js +4 -4
- package/lib/types/layout.js.map +1 -1
- package/lib/types/migrate.d.ts +1 -1
- package/lib/types/migrate.js +2 -2
- package/lib/types/migrate.js.map +1 -1
- package/lib/types/model-text.d.ts +99 -0
- package/lib/types/model-text.d.ts.map +1 -0
- package/lib/types/model-text.js +103 -0
- package/lib/types/model-text.js.map +1 -0
- package/lib/types/present.d.ts +239 -0
- package/lib/types/present.d.ts.map +1 -0
- package/lib/types/present.js +255 -0
- package/lib/types/present.js.map +1 -0
- package/lib/types/recall-rank.d.ts +37 -0
- package/lib/types/recall-rank.d.ts.map +1 -1
- package/lib/types/recall-rank.js +41 -1
- package/lib/types/recall-rank.js.map +1 -1
- package/lib/types/runtime.d.ts +564 -31
- package/lib/types/runtime.d.ts.map +1 -1
- package/lib/types/runtime.js +2645 -292
- package/lib/types/runtime.js.map +1 -1
- package/lib/types/settings-schema.d.ts +4 -2
- package/lib/types/settings-schema.d.ts.map +1 -1
- package/lib/types/settings-schema.js +2 -0
- package/lib/types/settings-schema.js.map +1 -1
- package/lib/types/source-images.d.ts +118 -0
- package/lib/types/source-images.d.ts.map +1 -0
- package/lib/types/source-images.js +288 -0
- package/lib/types/source-images.js.map +1 -0
- package/lib/types/types.d.ts +356 -28
- package/lib/types/types.d.ts.map +1 -1
- package/lib/types/types.js +112 -18
- package/lib/types/types.js.map +1 -1
- package/lib/types/wiki-finalize.d.ts +140 -0
- package/lib/types/wiki-finalize.d.ts.map +1 -0
- package/lib/types/wiki-finalize.js +269 -0
- package/lib/types/wiki-finalize.js.map +1 -0
- package/lib/types/wiki-types.d.ts +10 -2
- package/lib/types/wiki-types.d.ts.map +1 -1
- package/lib/types/wiki-types.js +27 -30
- package/lib/types/wiki-types.js.map +1 -1
- package/package.json +4 -3
- package/preset/tita-data-agent/agent.cordis.yml +25 -10
- package/src/client/DirectoryPicker.tsx +12 -12
- package/src/client/DrawerSection.tsx +18 -0
- package/src/client/InfoHint.tsx +21 -8
- package/src/client/IntentTab.tsx +20 -26
- package/src/client/KnowledgeBaseTab.tsx +458 -158
- package/src/client/KnowledgePanel.tsx +44 -10
- package/src/client/KnowledgeStepRail.tsx +3 -0
- package/src/client/KnowledgeToolRow.tsx +331 -0
- package/src/client/NodeSettings.tsx +20 -22
- package/src/client/PreviewSections.tsx +178 -43
- package/src/client/RecallPanel.tsx +418 -127
- package/src/client/TypeDefinitionDrawer.tsx +154 -54
- package/src/client/WikiCardReview.tsx +266 -0
- package/src/client/WikiFlowCard.tsx +57 -95
- package/src/client/WikiTypeEditor.tsx +197 -95
- package/src/client/arch/AgentArchitectureGraph.tsx +30 -14
- package/src/client/arch/NodeLogicPanel.tsx +6 -3
- package/src/client/arch/model.ts +164 -26
- package/src/client/architecture.css +25 -10
- package/src/client/architecture.tsx +66 -41
- package/src/client/asset-images.ts +125 -0
- package/src/client/attribution/AttributionGraph.tsx +481 -34
- package/src/client/attribution/AttributionTab.tsx +501 -106
- package/src/client/attribution/CaseView.tsx +9 -14
- package/src/client/attribution/GraphStage.tsx +25 -18
- package/src/client/attribution/RunView.tsx +27 -9
- package/src/client/attribution/StageChrome.tsx +280 -140
- package/src/client/attribution/graph-options.ts +611 -47
- package/src/client/attribution/model.ts +559 -30
- package/src/client/convert/ConvertPanel.tsx +36 -4
- package/src/client/doc-page.css +134 -0
- package/src/client/doc-page.tsx +242 -0
- package/src/client/index.ts +18 -0
- package/src/client/panel-state.ts +105 -0
- package/src/client/problem-domains.ts +1 -1
- package/src/client/request.ts +36 -0
- package/src/client/styles.css +397 -54
- package/src/client/useFitScale.ts +15 -2
- package/src/client/wiki-type-groups.ts +86 -0
- package/src/convert/host.ts +68 -9
- package/src/convert/ingest.ts +61 -18
- package/src/convert/types.ts +2 -2
- package/src/diagnosis/cards.ts +120 -50
- package/src/diagnosis/run.ts +251 -0
- package/src/diagnosis/schema.ts +67 -26
- package/src/diagnosis/seed-source.ts +29 -4
- package/src/diagnosis/seed.ts +187 -85
- package/src/diagnosis/store.ts +310 -173
- package/src/diagnosis/types.ts +181 -16
- package/src/document-page.ts +51 -0
- package/src/extract-model.ts +254 -99
- package/src/extract.ts +35 -3
- package/src/fs-atomic.ts +41 -0
- package/src/index.ts +499 -62
- package/src/intent/types.ts +1 -1
- package/src/knowledge-bases.ts +50 -49
- package/src/layout.ts +4 -4
- package/src/migrate.ts +2 -2
- package/src/model-text.ts +126 -0
- package/src/present.ts +367 -0
- package/src/recall-rank.ts +57 -2
- package/src/runtime.ts +2802 -293
- package/src/settings-schema.ts +2 -0
- package/src/source-images.ts +326 -0
- package/src/types.ts +446 -45
- package/src/wiki-finalize.ts +310 -0
- package/src/wiki-types.ts +28 -32
package/src/client/arch/model.ts
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
*/
|
|
22
22
|
|
|
23
23
|
import {
|
|
24
|
-
NODE_LANES, NODE_META, NODE_STATUS_LABEL, NODE_STATUS_SHORT,
|
|
24
|
+
NODE_LANES, NODE_META, NODE_STATUS_LABEL, NODE_STATUS_SHORT, memoryCountOf, nodeMetrics, sourceCountOf,
|
|
25
25
|
type KnowledgeStats, type LaneId, type LaneMeta, type NodeId, type NodeMetric, type NodeStatus,
|
|
26
26
|
} from '../architecture.tsx'
|
|
27
27
|
import { PROBLEM_BASE_NOTE, PROBLEM_DOMAINS, type ProblemDomain } from '../problem-domains.ts'
|
|
@@ -40,12 +40,54 @@ export const GUTTER = 116
|
|
|
40
40
|
export const NODE_W = 180
|
|
41
41
|
/** 卡片高度要装下四层:标题行、两行说明、统计行。 */
|
|
42
42
|
export const NODE_H = 96
|
|
43
|
-
/**
|
|
43
|
+
/** 竖排两到三张时用的规格。两张那一列装得下计数行,三张那一列装不下。 */
|
|
44
44
|
export const NODE_H_STACKED = 80
|
|
45
|
+
/**
|
|
46
|
+
* 一列竖排**三张**时的卡片高度(2026-09-26 加画布带来的第三张)。
|
|
47
|
+
*
|
|
48
|
+
* 它比两排矮一档,不是审美选择,是算术:三张要挤进同一条带,而带高是全图共享的。
|
|
49
|
+
* 内容也正好只差一行 —— 这一列的 Table / Notebook / 画布都没有计数行,两行文字
|
|
50
|
+
* (标题 + 说明)加 8px 上下内边距正好 52px;而情节 / 操作记忆两张带计数行,需要 73px,
|
|
51
|
+
* 所以它们仍用 80。写死一个高度给两种内容,不是裁掉计数就是白留一条空带。
|
|
52
|
+
*/
|
|
53
|
+
export const NODE_H_STACKED_TRIO = 52
|
|
45
54
|
export const COL_GAP = 32
|
|
46
|
-
/**
|
|
47
|
-
*
|
|
48
|
-
|
|
55
|
+
/**
|
|
56
|
+
* 竖排卡片之间的间隙。**它与卡片高度一起决定列间距**,所以只写一处:
|
|
57
|
+
* 两张那一列 = 2×80 + 14 = 174,三张那一列 = 3×52 + 2×14 = 184。
|
|
58
|
+
*/
|
|
59
|
+
export const STACK_GAP = 14
|
|
60
|
+
/**
|
|
61
|
+
* **先写「哪一列竖排几张」,再算带高。**
|
|
62
|
+
*
|
|
63
|
+
* 带高由最高的一列决定(`CONTENT_H`),而带高又决定画布高度 —— 都是模块初始化的常量,
|
|
64
|
+
* 所以这张表必须在它们之前出现。它与 `ARCH_SLOTS` 里的 `stack` 序号是同一件事的两面,
|
|
65
|
+
* 测试会断言两者一致(一处写三张、另一处只放两张是最容易犯的错,而且肉眼看不出来)。
|
|
66
|
+
*/
|
|
67
|
+
export const STACK_COLUMNS: ReadonlyArray<{ lane: number; col: number; count: number }> = [
|
|
68
|
+
{ lane: 0, col: 4, count: 3 },
|
|
69
|
+
{ lane: 2, col: 3, count: 2 },
|
|
70
|
+
]
|
|
71
|
+
|
|
72
|
+
/** 一列竖排 `count` 张时的卡片高度。 */
|
|
73
|
+
export function stackHeight(count: number): number {
|
|
74
|
+
return count >= 3 ? NODE_H_STACKED_TRIO : NODE_H_STACKED
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* 一列竖排 `count` 张时需要的内容区高度 = `count × 卡高 + (count-1) × 间隙`。
|
|
79
|
+
*
|
|
80
|
+
* 卡片在列内**等距**排:第 i 张的中心偏移 = (i - (count-1)/2) × (卡高 + 间隙)。
|
|
81
|
+
* 所以最外两张的外沿正好落在 ±CONTENT_H/2 上,不多不少。
|
|
82
|
+
*/
|
|
83
|
+
export function columnHeight(count: number): number {
|
|
84
|
+
return count <= 0 ? 0 : count * stackHeight(count) + (count - 1) * STACK_GAP
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/** 一列竖排 `count` 张时,第 `index` 张相对带中心线的偏移。 */
|
|
88
|
+
export function stackOffset(count: number, index: number): number {
|
|
89
|
+
return (index - (count - 1) / 2) * (stackHeight(count) + STACK_GAP)
|
|
90
|
+
}
|
|
49
91
|
/** 带名条的高度:一枚字母徽标 + 链路名。 */
|
|
50
92
|
export const LANE_HEAD_H = 30
|
|
51
93
|
/**
|
|
@@ -62,8 +104,8 @@ export const LANE_HEAD_W = 224
|
|
|
62
104
|
*/
|
|
63
105
|
export const BAND_GAP = 24
|
|
64
106
|
export const LANE_PAD = 12
|
|
65
|
-
/**
|
|
66
|
-
export const CONTENT_H =
|
|
107
|
+
/** 带的内容区高度:**由最高的那一列决定**(三张 52 的那列 = 184),单节点在其中居中。 */
|
|
108
|
+
export const CONTENT_H = Math.max(...STACK_COLUMNS.map(column => columnHeight(column.count)))
|
|
67
109
|
/** 带高 = 带名条 + 上下内边距 + 内容区。三条带等高,网格才对得齐。 */
|
|
68
110
|
export const BAND_H = LANE_HEAD_H + LANE_PAD + CONTENT_H + LANE_PAD
|
|
69
111
|
/** 两条带的上沿间距 = 带高 + 通道。 */
|
|
@@ -140,15 +182,16 @@ export interface ArchBox { x: number; y: number; width: number; height: number }
|
|
|
140
182
|
* 出来,经过记忆与质量门,最后回到最左边的「资金化」—— 反向流不是排版花招,
|
|
141
183
|
* 它就是闭环的方向,也是 A→C 那条连线能画得短的原因。
|
|
142
184
|
*/
|
|
143
|
-
interface Slot { lane: number; col: number; stack?:
|
|
185
|
+
interface Slot { lane: number; col: number; /** 在竖排里的序号(0 起)。见 `STACK_COLUMNS`。 */ stack?: number }
|
|
144
186
|
|
|
145
187
|
export const ARCH_SLOTS: Record<NodeId, Slot> = {
|
|
146
188
|
conversation: { lane: 0, col: 0 },
|
|
147
189
|
intent: { lane: 0, col: 1 },
|
|
148
190
|
runtime: { lane: 0, col: 2 },
|
|
149
191
|
answer: { lane: 0, col: 3 },
|
|
150
|
-
'data-sheet': { lane: 0, col: 4, stack:
|
|
151
|
-
'data-notebook': { lane: 0, col: 4, stack:
|
|
192
|
+
'data-sheet': { lane: 0, col: 4, stack: 0 },
|
|
193
|
+
'data-notebook': { lane: 0, col: 4, stack: 1 },
|
|
194
|
+
'data-canvas': { lane: 0, col: 4, stack: 2 },
|
|
152
195
|
|
|
153
196
|
'source-raw': { lane: 1, col: 0 },
|
|
154
197
|
compile: { lane: 1, col: 1 },
|
|
@@ -159,8 +202,8 @@ export const ARCH_SLOTS: Record<NodeId, Slot> = {
|
|
|
159
202
|
'funded-value': { lane: 2, col: 0 },
|
|
160
203
|
'daily-update': { lane: 2, col: 1 },
|
|
161
204
|
'memory-quality': { lane: 2, col: 2 },
|
|
162
|
-
'episodic-memory': { lane: 2, col: 3, stack:
|
|
163
|
-
'procedural-memory': { lane: 2, col: 3, stack:
|
|
205
|
+
'episodic-memory': { lane: 2, col: 3, stack: 0 },
|
|
206
|
+
'procedural-memory': { lane: 2, col: 3, stack: 1 },
|
|
164
207
|
interaction: { lane: 2, col: 4 },
|
|
165
208
|
}
|
|
166
209
|
|
|
@@ -182,14 +225,14 @@ export function isDecoration(id: string): boolean {
|
|
|
182
225
|
|
|
183
226
|
export function boxOf(id: NodeId): ArchBox {
|
|
184
227
|
const slot = ARCH_SLOTS[id]
|
|
185
|
-
const
|
|
228
|
+
const column = STACK_COLUMNS.find(item => item.lane === slot.lane && item.col === slot.col)
|
|
229
|
+
const height = column ? stackHeight(column.count) : NODE_H
|
|
186
230
|
const center = laneCenter(slot.lane)
|
|
187
|
-
const y = slot.stack
|
|
188
|
-
? center + (slot.stack === 'upper' ? -STACK_OFFSET : STACK_OFFSET)
|
|
189
|
-
: center
|
|
231
|
+
const y = column ? center + stackOffset(column.count, slot.stack ?? 0) : center
|
|
190
232
|
return { x: columnX(slot.col), y, width: NODE_W, height }
|
|
191
233
|
}
|
|
192
234
|
|
|
235
|
+
|
|
193
236
|
// ----------------------------------------------------------------- 连边
|
|
194
237
|
|
|
195
238
|
/**
|
|
@@ -222,6 +265,8 @@ export const ARCH_EDGES: ArchEdge[] = [
|
|
|
222
265
|
{ id: 'a3', source: 'runtime', target: 'answer', kind: 'flow' },
|
|
223
266
|
{ id: 'a4', source: 'answer', target: 'data-sheet', kind: 'branch' },
|
|
224
267
|
{ id: 'a5', source: 'answer', target: 'data-notebook', kind: 'branch' },
|
|
268
|
+
// 画布与 Table / Notebook 是同一格的三种输出产物,所以也是同一种边。
|
|
269
|
+
{ id: 'a6', source: 'answer', target: 'data-canvas', kind: 'branch' },
|
|
225
270
|
|
|
226
271
|
// B · 知识编译与召回链路(写入侧 → 读取侧)
|
|
227
272
|
{ id: 'b1', source: 'source-raw', target: 'compile', kind: 'flow' },
|
|
@@ -246,6 +291,77 @@ export const ARCH_EDGES: ArchEdge[] = [
|
|
|
246
291
|
{ id: 'x4', source: 'context', target: 'runtime', kind: 'inject', label: 'Context Pack 注入' },
|
|
247
292
|
]
|
|
248
293
|
|
|
294
|
+
/**
|
|
295
|
+
* 「同一个发点出去的两条以上」或「汇进同一个落点的两条以上」的边 —— 它们**走一条总线**。
|
|
296
|
+
*
|
|
297
|
+
* ## 为什么不能各走各的(2026-09-26 GUI 反馈)
|
|
298
|
+
*
|
|
299
|
+
* 原来 `branch` 用 `router: { type: 'orth' }`。路由器是**每条边各算各的**:它把每条线
|
|
300
|
+
* 连到「离自己最近的那两个边界点」,于是回答那一格的右边被三条线在三个高度上分别咬开 ——
|
|
301
|
+
* 一张卡片伸出三根箭头,各自还带一个小台阶。用户的原话是「箭头改成从一个地方出,
|
|
302
|
+
* 这样样式不好看」。
|
|
303
|
+
*
|
|
304
|
+
* ## 判据是**边的邻居**,不是边的种类
|
|
305
|
+
*
|
|
306
|
+
* 一个节点只要有两条及以上的同带相邻列连线,那几条就共用一段总线。所以 2026-09-26 把
|
|
307
|
+
* 画布加成第三张输出产物时,这条规则**没有改一个字** —— 它自己就把新边算了进去。
|
|
308
|
+
* 反过来若按「`branch` 就走总线」写,多对一的那种(情节 / 操作记忆 → 记忆质量检查,
|
|
309
|
+
* 那是两条 `flow`)就漏了,而它们看着是同一毛病。
|
|
310
|
+
*
|
|
311
|
+
* 跨链路的四条长线不在这里:它们不同带,本来就有自己的正交路由与避障。
|
|
312
|
+
*/
|
|
313
|
+
const BUS_EDGE_IDS: ReadonlySet<string> = (() => {
|
|
314
|
+
const local = ARCH_EDGES.filter(edge => {
|
|
315
|
+
const from = ARCH_SLOTS[edge.source]
|
|
316
|
+
const to = ARCH_SLOTS[edge.target]
|
|
317
|
+
return from !== undefined && to !== undefined && from.lane === to.lane && Math.abs(from.col - to.col) === 1
|
|
318
|
+
})
|
|
319
|
+
const out = new Map<string, number>()
|
|
320
|
+
const into = new Map<string, number>()
|
|
321
|
+
for (const edge of local) {
|
|
322
|
+
out.set(edge.source, (out.get(edge.source) ?? 0) + 1)
|
|
323
|
+
into.set(edge.target, (into.get(edge.target) ?? 0) + 1)
|
|
324
|
+
}
|
|
325
|
+
return new Set(local
|
|
326
|
+
.filter(edge => (out.get(edge.source) ?? 0) > 1 || (into.get(edge.target) ?? 0) > 1)
|
|
327
|
+
.map(edge => edge.id))
|
|
328
|
+
})()
|
|
329
|
+
|
|
330
|
+
/** 这条边是否参与总线(测试与 `toGraphData` 读它,两处不可能各算一遍)。 */
|
|
331
|
+
export function isBusEdge(edgeId: string): boolean {
|
|
332
|
+
return BUS_EDGE_IDS.has(edgeId)
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* 一条总线上的**拐点**。给 G6 的 `controlPoints`,它就按我们算的点画,不再自己找出口。
|
|
337
|
+
*
|
|
338
|
+
* 从发点出来先汇到一个 x(两条列之间的中线),再竖直走到目标那一行,最后横向进盒子:
|
|
339
|
+
*
|
|
340
|
+
* ```
|
|
341
|
+
* 回答 ──┐ 拐点 1 把三条边锁在同一个 y(发点的中心),
|
|
342
|
+
* ├──▶ Table 所以三根箭头从**同一个点**出来;
|
|
343
|
+
* ├──▶ Notebook 拐点 2 各自落在目标那一行。
|
|
344
|
+
* └──▶ 画布
|
|
345
|
+
* ```
|
|
346
|
+
*
|
|
347
|
+
* 一对多是「汇出去再分开」,多对一是「各自汇过来再进同一个点」—— 同一组拐点同时满足
|
|
348
|
+
* 两种读法:前者共用第一段,后者共用最后一段。
|
|
349
|
+
*
|
|
350
|
+
* 返回 `null` 表示不必给拐点:不在总线上,或者发点与落点本来就同高(那时一条直线就是
|
|
351
|
+
* 总线,它的出口与总线的出口是同一个点)。
|
|
352
|
+
*/
|
|
353
|
+
export function busControlPoints(edge: ArchEdge): Array<[number, number]> | null {
|
|
354
|
+
if (!BUS_EDGE_IDS.has(edge.id)) return null
|
|
355
|
+
const from = boxOf(edge.source)
|
|
356
|
+
const to = boxOf(edge.target)
|
|
357
|
+
if (Math.abs(from.y - to.y) < 0.5) return null
|
|
358
|
+
const goingRight = to.x > from.x
|
|
359
|
+
const startX = from.x + (goingRight ? NODE_W / 2 : -NODE_W / 2)
|
|
360
|
+
const endX = to.x + (goingRight ? -NODE_W / 2 : NODE_W / 2)
|
|
361
|
+
const trunkX = (startX + endX) / 2
|
|
362
|
+
return [[trunkX, from.y], [trunkX, to.y]]
|
|
363
|
+
}
|
|
364
|
+
|
|
249
365
|
/**
|
|
250
366
|
* 边的外观。灰 / 蓝两档,没有第三档色相。
|
|
251
367
|
*
|
|
@@ -316,21 +432,39 @@ function escapeHtml(value: string): string {
|
|
|
316
432
|
/**
|
|
317
433
|
* 一张节点卡片的 DOM 字符串。
|
|
318
434
|
*
|
|
319
|
-
* 用 G6 的 HTML 节点(而不是 canvas
|
|
320
|
-
*
|
|
321
|
-
*
|
|
435
|
+
* 用 G6 的 HTML 节点(而不是 canvas 文本)是因为这张卡片要写**三层信息**:
|
|
436
|
+
* 标题、一句话说明、数据统计。canvas 文本只有一种字号与字重,三层挤成一样大
|
|
437
|
+
* 就等于没有层次。
|
|
322
438
|
*
|
|
323
439
|
* 关键样式全部内联:卡片是画布里的 DOM,不保证和插件样式表同时到位,
|
|
324
440
|
* 靠类名会得到一张没有边框的白块。类名只用于选中态这类可选增强。
|
|
325
441
|
*
|
|
326
|
-
* 视觉上是「白卡 + 1px 发丝边 + 6px 圆角 +
|
|
327
|
-
*
|
|
442
|
+
* 视觉上是「白卡 + 1px 发丝边 + 6px 圆角 + 几乎看不见的投影」。
|
|
443
|
+
*
|
|
444
|
+
* ## 状态字(宿主 / 待实现 / 已实现)从卡片上撤掉了(2026-09-26)
|
|
445
|
+
*
|
|
446
|
+
* 它原来在每一张卡的右上角:一枚小圆点 + 一个词。撤掉的理由不是「不好看」,
|
|
447
|
+
* 是**它同时出现十六次,于是十几张卡片的标题全被它挤窄**(`shortTitle` 就是为它
|
|
448
|
+
* 让位而存在的),而它说的是同一件事的四个值。
|
|
449
|
+
*
|
|
450
|
+
* 实现状态没有丢,只是换了三个更合适的地方:
|
|
451
|
+
* - 每条链路的名条上写着**逐带计数**(`A 已实现 1 · 宿主 5 · …`)——「整条链路做完了没」
|
|
452
|
+
* 本来就比「这一格做完了没」更接近用户要问的。
|
|
453
|
+
* - 点开任意节点,浮层标题旁就是同一档状态(`Badge` + `statusNote` 依据)。
|
|
454
|
+
* - 卡片自身的 `title` 悬停仍然给出完整状态依据,无障碍列表也照旧逐节点列出。
|
|
328
455
|
*/
|
|
329
456
|
export function cardHtml(id: NodeId, metrics: NodeMetric[], selected = false): string {
|
|
330
457
|
const meta = NODE_META[id]
|
|
331
458
|
const lane = LANE_PALETTE[meta.lane]
|
|
332
|
-
const
|
|
333
|
-
const
|
|
459
|
+
const slot = ARCH_SLOTS[id]
|
|
460
|
+
const column = STACK_COLUMNS.find(item => item.lane === slot.lane && item.col === slot.col)
|
|
461
|
+
const compact = column !== undefined
|
|
462
|
+
/**
|
|
463
|
+
* 竖排卡片的内边距**收到 8px**:三张那一列的高度是 52(见 `NODE_H_STACKED_TRIO`),
|
|
464
|
+
* 而「标题 16 + 间隙 5 + 说明 15」已经占掉 36 —— 上下各 8 正好 52,各 10 就溢出 4px。
|
|
465
|
+
* 这一列没有计数行,所以省下的就是这一圈的空气。
|
|
466
|
+
*/
|
|
467
|
+
const padY = compact ? 8 : 10
|
|
334
468
|
/**
|
|
335
469
|
* 卡片上最多两个计数,而且是**一行纯文字**,不是会自动换行的 chip 组。
|
|
336
470
|
*
|
|
@@ -342,11 +476,10 @@ export function cardHtml(id: NodeId, metrics: NodeMetric[], selected = false): s
|
|
|
342
476
|
const chips = metrics.slice(0, 2).map(metric =>
|
|
343
477
|
`<span style="display:inline-flex;align-items:baseline;gap:3px;white-space:nowrap;font-size:10px;line-height:16px;color:${INK_FAINT}">${escapeHtml(metric.label)}<b style="color:${INK};font-weight:600;font-variant-numeric:tabular-nums">${escapeHtml(metric.value)}</b></span>`).join('')
|
|
344
478
|
// 悬停给出完整名字与状态依据:卡片上的名字可能被省略号截短,但信息不能丢。
|
|
345
|
-
return `<div class="tita-archCard${selected ? ' tita-archCardOn' : ''}" title="${escapeHtml(`${meta.title} —— ${meta.statusNote}`)}" style="box-sizing:border-box;width:100%;height:100%;display:flex;flex-direction:column;gap:5px;padding
|
|
479
|
+
return `<div class="tita-archCard${selected ? ' tita-archCardOn' : ''}" title="${escapeHtml(`${meta.title} —— ${meta.statusNote}`)}" style="box-sizing:border-box;width:100%;height:100%;display:flex;flex-direction:column;gap:5px;padding:${padY}px 11px;border-radius:6px;background:${SURFACE};border:1px solid ${selected ? lane.accent : RULE};box-shadow:${selected ? `0 0 0 3px ${lane.soft}` : '0 1px 2px rgba(16,24,40,.04)'};font-family:${FONT};overflow:hidden">
|
|
346
480
|
<div style="display:flex;align-items:center;gap:6px">
|
|
347
481
|
<span style="width:6px;height:6px;border-radius:999px;background:${lane.accent};flex:0 0 auto"></span>
|
|
348
482
|
<strong style="font-size:12.5px;font-weight:600;color:${INK};line-height:1.25;white-space:nowrap;overflow:hidden;text-overflow:ellipsis">${escapeHtml(meta.shortTitle ?? meta.title)}</strong>
|
|
349
|
-
<span style="margin-left:auto;flex:0 0 auto;display:inline-flex;align-items:center;gap:4px;font-size:10px;font-weight:600;color:${status.text}"><i style="width:5px;height:5px;border-radius:999px;background:${status.dot}"></i>${escapeHtml(NODE_STATUS_SHORT[meta.status])}</span>
|
|
350
483
|
</div>
|
|
351
484
|
<div style="font-size:11px;line-height:1.4;color:${INK_MUTED};display:-webkit-box;-webkit-line-clamp:${compact ? 1 : 2};-webkit-box-orient:vertical;overflow:hidden">${escapeHtml(meta.subtitle)}</div>
|
|
352
485
|
${chips ? `<div style="margin-top:auto;display:flex;align-items:baseline;gap:10px;overflow:hidden">${chips}</div>` : ''}
|
|
@@ -526,7 +659,7 @@ function decorations(): ArchNodeDatum[] {
|
|
|
526
659
|
|
|
527
660
|
/** 带上按阅读顺序排好的节点(自进化带是反向的,由 ARCH_SLOTS 的列号决定)。 */
|
|
528
661
|
export function nodesOfLane(lane: number): NodeId[] {
|
|
529
|
-
const rank = (slot: Slot): number => slot.stack
|
|
662
|
+
const rank = (slot: Slot): number => slot.stack ?? 0
|
|
530
663
|
return (Object.keys(ARCH_SLOTS) as NodeId[])
|
|
531
664
|
.filter(id => ARCH_SLOTS[id].lane === lane)
|
|
532
665
|
.sort((left, right) => ARCH_SLOTS[left].col - ARCH_SLOTS[right].col || rank(ARCH_SLOTS[left]) - rank(ARCH_SLOTS[right]))
|
|
@@ -582,6 +715,11 @@ export function toGraphData(stats: KnowledgeStats, version: number, selected: No
|
|
|
582
715
|
// 正交 + 自动避障:这几条是长线,斜着连会横穿中间的卡片。
|
|
583
716
|
style.radius = 10
|
|
584
717
|
style.router = { type: 'shortest-path', enableObstacleAvoidance: true, offset: 14, gridSize: 8 }
|
|
718
|
+
} else if (busControlPoints(edge) !== null) {
|
|
719
|
+
// 总线上的边:拐点是我们算的,**不要路由器** —— 路由器每条边各找一个出口,
|
|
720
|
+
// 那正是「三根箭头从三个高度出来、各自还带一个小台阶」的原因。
|
|
721
|
+
style.radius = 8
|
|
722
|
+
style.controlPoints = busControlPoints(edge)
|
|
585
723
|
} else if (edge.kind === 'branch') {
|
|
586
724
|
style.radius = 8
|
|
587
725
|
style.router = { type: 'orth', padding: 14 }
|
|
@@ -16,20 +16,26 @@
|
|
|
16
16
|
|
|
17
17
|
/* ---------------------------------------------------------------- 版式 */
|
|
18
18
|
|
|
19
|
-
/*
|
|
20
|
-
|
|
19
|
+
/* **一块画布,带一圈发丝线。**
|
|
20
|
+
0042 撤过这圈边框(那时它同时接管视口与滚动条,两种语汇缝在一起,两头都不像)。
|
|
21
|
+
0050 又把它加回来:现在这一栏既不拖也不滚,「图在哪」不再有歧义,一圈边框正好
|
|
22
|
+
回答「这张图画在哪一块里」—— 没有它,图与面板底色之间连边界都没有。
|
|
23
|
+
高度由面板给(`flex: 1 1 auto`),底色显式给一个:全屏时这一块要自己不透明,
|
|
24
|
+
否则背后是浏览器的黑底。全屏是独占一屏,那一档不要圆角(贴边更像全屏)。 */
|
|
21
25
|
.tita-archStage {
|
|
22
26
|
position: relative;
|
|
23
27
|
display: flex;
|
|
24
28
|
min-width: 0;
|
|
29
|
+
min-height: 0;
|
|
30
|
+
flex: 1 1 auto;
|
|
25
31
|
flex-direction: column;
|
|
26
32
|
border: 1px solid var(--tita-line);
|
|
27
33
|
border-radius: 10px;
|
|
28
|
-
background: var(--tita-
|
|
34
|
+
background: var(--tita-canvas);
|
|
29
35
|
overflow: hidden;
|
|
30
36
|
}
|
|
31
|
-
|
|
32
37
|
.tita-archStage:fullscreen { border: 0; border-radius: 0; }
|
|
38
|
+
|
|
33
39
|
.tita-archStage:fullscreen .tita-archPane { flex: 1 1 auto; min-height: 0; }
|
|
34
40
|
|
|
35
41
|
/* 画布那一列。**浮层的定位上下文是它**,不是整块表面 —— 否则右上角那排操作
|
|
@@ -65,18 +71,27 @@
|
|
|
65
71
|
|
|
66
72
|
/* 画布容器:**画布永远是设计尺寸,缩放由板上的 transform 承担**。
|
|
67
73
|
这张画布设计宽 1172px、高 1132px(三条链路 + 一条问题域带),宿主右侧栏只有
|
|
68
|
-
380–840px
|
|
69
|
-
正好等于栏宽(没有可滚的余量),`1:1` 档下板保持设计尺寸、由滚动条承载。
|
|
74
|
+
380–840px。所以外层不去「适配」画布,而是按缩放比把整块板缩下来。
|
|
70
75
|
缩放比由组件按设计常量算出(`CANVAS_WIDTH/HEIGHT`),不写进 CSS,避免两处各写一份。 */
|
|
71
|
-
.tita-archScroll { width: 100%; min-width: 0; overflow: auto; background: var(--tita-
|
|
72
|
-
|
|
76
|
+
.tita-archScroll { width: 100%; min-width: 0; overflow: auto; background: var(--tita-canvas); }
|
|
77
|
+
/* 舞台模式:**整图居中摆好**(0050)。
|
|
78
|
+
`fit: 'both'` 之下图永远完整落在框里,所以「适应」档既没有可滚余量、也不需要拖拽;
|
|
79
|
+
`safe center` 而不是 `center`:1:1 档放不下时,普通居中会把左上角推到视口外
|
|
80
|
+
且滚不回去,`safe` 让它退回从左上角开始、由滚动条负责其余部分。
|
|
81
|
+
`overflow: auto` 保留 —— 1:1 档的出路就是它。 */
|
|
82
|
+
.tita-archScrollStage {
|
|
83
|
+
display: flex;
|
|
73
84
|
flex: 1 1 auto;
|
|
74
85
|
min-height: 0;
|
|
75
|
-
/* 全屏下 `fit` 档两边都可能有余量,居中;`safe` 保证 1:1 档溢出时左上角不被裁掉。 */
|
|
76
|
-
display: flex;
|
|
77
86
|
align-items: safe center;
|
|
78
87
|
justify-content: safe center;
|
|
79
88
|
}
|
|
89
|
+
/* **按比例定尺寸的框。** `transform` 不改布局尺寸,只写 transform 的话滚动区永远是
|
|
90
|
+
1172×1132 —— 「适应」档缩到 0.32 也照样能往虚空里拖出 770px。框的尺寸等于缩完的
|
|
91
|
+
尺寸,于是可平移的范围正好是图的边界:适应档只有纵向,1:1 档两个方向。 */
|
|
92
|
+
.tita-archFrame { position: relative; flex: 0 0 auto; overflow: hidden; }
|
|
93
|
+
/* 全屏:同一套居中规则(居中已经写在 `.tita-archScrollStage` 上),这里只把高度交回面板。 */
|
|
94
|
+
.tita-archStage:fullscreen .tita-archScroll { flex: 1 1 auto; min-height: 0; }
|
|
80
95
|
.tita-archBoard { min-width: 0; flex: 0 0 auto; }
|
|
81
96
|
.tita-archCanvas { width: 100%; height: 100%; min-width: 0; }
|
|
82
97
|
|
|
@@ -12,7 +12,7 @@
|
|
|
12
12
|
|
|
13
13
|
import {
|
|
14
14
|
BarChart3, Box, BrainCircuit, ClipboardCheck, Clock3, Database, FileCode2, FileText,
|
|
15
|
-
Gauge, GitBranch, HardDrive, Layers3, MessageCircle, RefreshCw, Search, Share2,
|
|
15
|
+
Gauge, GitBranch, HardDrive, Layers3, MessageCircle, PenTool, RefreshCw, Search, Share2,
|
|
16
16
|
Table2, UserRound,
|
|
17
17
|
} from '@tita-data-agent/ui/icons'
|
|
18
18
|
import type { LucideIcon } from '@tita-data-agent/ui/icons'
|
|
@@ -37,11 +37,28 @@ export type PanelTab = 'overview' | 'intent' | 'knowledge' | 'attribution' | 'me
|
|
|
37
37
|
* 合并不是因为「两个阶段变成一个」—— 它们在流水线上仍然是两步。合的是**界面**:
|
|
38
38
|
* 这两栏回答的是同一个问题(「跑一次真实召回,结果长什么样」),而且分成两栏时
|
|
39
39
|
* 用户必须先跑「召回」再切到「重排」才能看到同一次运行的全貌,两栏各自还有一个
|
|
40
|
-
* 测试按钮和一套 topK/topN
|
|
40
|
+
* 测试按钮和一套 topK/topN 输入。一栏里从上到下就是一条链:两路各自命中什么 →
|
|
41
41
|
* 融合后的排序 → cross-encoder 丢了多少 → 最终进上下文的 topN。
|
|
42
42
|
*/
|
|
43
43
|
export type KnowledgeTab = 'source-raw' | 'wiki' | 'graph' | 'recall'
|
|
44
44
|
|
|
45
|
+
/**
|
|
46
|
+
* 「回答 / 数据工具」这个节点能打开的**工作区页面**。
|
|
47
|
+
*
|
|
48
|
+
* 三个 kind 各由一个别的插件注册(`dsh-data-table` / `dsh-data-notebook` /
|
|
49
|
+
* `dsh-data-excalidraw`)—— 这里只写 kind 字符串,不 import 它们的代码,所以某个
|
|
50
|
+
* 插件没装时按钮依然在,宿主会就着这个 kind 显示「没有页面类型能打开它」。
|
|
51
|
+
*
|
|
52
|
+
* 联合写在一处:`NodeLogicPanel` 用它画按钮、`KnowledgePanel` 转发它、客户端入口
|
|
53
|
+
* 把它交给宿主的 `openTab`。三处各写一份,迟早出现「面板多了一个按钮,入口的类型
|
|
54
|
+
* 还不认它」——加画布这次就正好会踩到。
|
|
55
|
+
*
|
|
56
|
+
* 「回答 / 数据工具」的输出产物就是这三样:可编辑表格、可复现 Notebook、可编辑画布。
|
|
57
|
+
* 画布是 2026-09-26 补上的第四个出口:Excalidraw 画布已经在宿主里跑着,而这张架构图
|
|
58
|
+
* 上原先只列了 Table 与 Notebook,读起来像是「Agent 出不了图」。
|
|
59
|
+
*/
|
|
60
|
+
export type WorkspaceTabKind = 'data-sheet' | 'data-notebook' | 'data-excalidraw'
|
|
61
|
+
|
|
45
62
|
/**
|
|
46
63
|
* 五个分栏的顺序、名字与图标。**定义在这里而不是在 `KnowledgeBaseTab` 里**:
|
|
47
64
|
* 渲染它的地方有两个 —— 面板外壳顶部那一条分栏 tab,和知识库内容本身。
|
|
@@ -83,7 +100,7 @@ export const NODE_LANES: LaneMeta[] = [
|
|
|
83
100
|
]
|
|
84
101
|
|
|
85
102
|
export type NodeId =
|
|
86
|
-
| 'conversation' | 'intent' | 'runtime' | 'answer' | 'data-sheet' | 'data-notebook'
|
|
103
|
+
| 'conversation' | 'intent' | 'runtime' | 'answer' | 'data-sheet' | 'data-notebook' | 'data-canvas'
|
|
87
104
|
| 'source-raw' | 'compile' | 'build' | 'recall' | 'context'
|
|
88
105
|
| 'interaction' | 'episodic-memory' | 'procedural-memory' | 'memory-quality' | 'daily-update' | 'funded-value'
|
|
89
106
|
|
|
@@ -103,9 +120,12 @@ export const NODE_STATUS_LABEL: Record<NodeStatus, string> = {
|
|
|
103
120
|
}
|
|
104
121
|
|
|
105
122
|
/**
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
123
|
+
* 带名条上的状态文字(`A 宿主 5 · 部分实现 1 · …`)。**只有「宿主提供」需要缩短** ——
|
|
124
|
+
* 它是四个字,而带名条右侧那条计数是十几个字挤在一行里。
|
|
125
|
+
* 面板、卡片悬停与无障碍列表读的仍是完整措辞,缩的只是带名条那一处。
|
|
126
|
+
*
|
|
127
|
+
* 它原来还负责卡片右上角那枚状态字;2026-09-26 那枚撤掉了(同时出现十六次,
|
|
128
|
+
* 把每张卡的标题都挤窄),卡片上的状态现在只在悬停的 `title` 里。
|
|
109
129
|
*/
|
|
110
130
|
export const NODE_STATUS_SHORT: Record<NodeStatus, string> = {
|
|
111
131
|
...NODE_STATUS_LABEL,
|
|
@@ -113,25 +133,17 @@ export const NODE_STATUS_SHORT: Record<NodeStatus, string> = {
|
|
|
113
133
|
}
|
|
114
134
|
|
|
115
135
|
/**
|
|
116
|
-
*
|
|
117
|
-
*
|
|
118
|
-
* 「已实现」是常态,所以它拿绿(`--tita-success`,白底 5.7:1);「部分实现」是唯一需要
|
|
119
|
-
* 人动手的一档,拿琥珀(`--tita-warning`,5.4:1);「待实现」和「宿主提供」都不是我们的
|
|
120
|
-
* 进度,拿两级灰:文字分两级(faint / muted),圆点合并成 faint 一档 —— 共享词表里只有
|
|
121
|
-
* 三级墨色,而这两档圆点本来就只差一格,区分它们的是文字。
|
|
122
|
-
* 四档不各配一个背景色药丸 —— 那样四张卡片并排时,颜色比标题还响。
|
|
136
|
+
* 状态色表**已删除**(2026-09-26),连同它最后一个消费者。
|
|
123
137
|
*
|
|
124
|
-
*
|
|
125
|
-
*
|
|
138
|
+
* 它服务的是卡片右上角那枚「小圆点 + 状态字」。那枚撤掉之后,画布上唯一的状态读数
|
|
139
|
+
* 是问题域带名条里一行灰字计数(`A 宿主 5 · 部分实现 1 · …`)—— 计数不分色。
|
|
140
|
+
* 也就是说四档状态在画布上不再有「颜色」这个说法,留下一张 `fill/text/dot` 的表
|
|
141
|
+
* 只会让人以为某处还在按它上色。
|
|
126
142
|
*
|
|
127
|
-
*
|
|
143
|
+
* 状态**照旧要如实标注**,只是改由这三处承担:带名条的逐带计数、点开节点后浮层标题
|
|
144
|
+
* 旁的 `Badge`(`NodeLogicPanel` 的 `STATUS_BADGE`)、以及卡片悬停 `title` 与无障碍
|
|
145
|
+
* 列表里的 `statusNote` 依据。
|
|
128
146
|
*/
|
|
129
|
-
export const NODE_STATUS_TONE: Record<NodeStatus, { fill: string; text: string; dot: string }> = {
|
|
130
|
-
live: { fill: 'var(--tita-tone-green-tint)', text: 'var(--tita-success)', dot: 'var(--tita-success)' },
|
|
131
|
-
partial: { fill: 'var(--tita-tone-amber-tint)', text: 'var(--tita-warning)', dot: 'var(--tita-warning)' },
|
|
132
|
-
planned: { fill: 'var(--tita-surface-muted)', text: 'var(--tita-ink-faint)', dot: 'var(--tita-ink-faint)' },
|
|
133
|
-
host: { fill: 'var(--tita-surface-muted)', text: 'var(--tita-ink-muted)', dot: 'var(--tita-ink-faint)' },
|
|
134
|
-
}
|
|
135
147
|
|
|
136
148
|
/** 一个执行步骤。/ `state` 决定面板里显示对勾、半勾还是空心圈。 */
|
|
137
149
|
export interface NodeStep {
|
|
@@ -145,6 +157,10 @@ export interface NodeMeta {
|
|
|
145
157
|
/**
|
|
146
158
|
* 卡片上的短名。只给放不进 180px 卡片的标题用 —— 卡片是示意图,它旁边还站着
|
|
147
159
|
* 十来个同宽的字;面板里写的始终是完整名字,卡片的 `title` 悬停也给出完整名字。
|
|
160
|
+
*
|
|
161
|
+
* 右上角那枚状态字撤掉之后(2026-09-26),卡片的标题行确实空出了一截。这里**没有**
|
|
162
|
+
* 因此把短名换回全名:短名当初是按「180px 里读得顺」挑的,不只是为了躲开那枚状态字,
|
|
163
|
+
* 而且面板与悬停里全名一直都在。哪条短名读起来不如全名,单独改那一条即可。
|
|
148
164
|
*/
|
|
149
165
|
shortTitle?: string
|
|
150
166
|
subtitle: string
|
|
@@ -204,13 +220,13 @@ icon: Box, lane: 'interaction',
|
|
|
204
220
|
},
|
|
205
221
|
answer: {
|
|
206
222
|
title: '回答 / 数据工具', subtitle: '生成结果、可视化与方案',
|
|
207
|
-
detail: '输出解释、引用和数据结果,并把结构化结果继续交给 Table
|
|
208
|
-
input: '模型回答 + 工具返回值', output: '可读回答、可编辑表格、可复现 Notebook',
|
|
223
|
+
detail: '输出解释、引用和数据结果,并把结构化结果继续交给 Table、Notebook 或画布处理。',
|
|
224
|
+
input: '模型回答 + 工具返回值', output: '可读回答、可编辑表格、可复现 Notebook、可编辑画布',
|
|
209
225
|
steps: [
|
|
210
226
|
{ label: '回答与引用', detail: '每一条结论都能指回 wiki 与 SourceRaw', state: 'done' },
|
|
211
|
-
{ label: '转交数据工具', detail: '结构化结果可继续在 Table / Notebook
|
|
227
|
+
{ label: '转交数据工具', detail: '结构化结果可继续在 Table / Notebook / 画布里加工', state: 'done' },
|
|
212
228
|
],
|
|
213
|
-
status: 'host', statusNote: '回答渲染与 Table / Notebook
|
|
229
|
+
status: 'host', statusNote: '回答渲染与 Table / Notebook / 画布由宿主工作区提供。',
|
|
214
230
|
icon: BarChart3, lane: 'interaction',
|
|
215
231
|
},
|
|
216
232
|
'data-sheet': {
|
|
@@ -229,6 +245,14 @@ icon: Table2, lane: 'interaction',
|
|
|
229
245
|
status: 'host', statusNote: '属于 `dsh-data-notebook` 插件,这里只画调用关系。',
|
|
230
246
|
icon: FileCode2, lane: 'interaction',
|
|
231
247
|
},
|
|
248
|
+
'data-canvas': {
|
|
249
|
+
title: '画布', subtitle: '生成 / 编辑 Excalidraw 画布',
|
|
250
|
+
detail: '把结构化结果画成一张可继续手工编辑的画布:架构草图、流程、方案对比。它是「输出产物」里唯一能被人接着改的那一种。',
|
|
251
|
+
input: '结构化结果 / 画布指令', output: '可编辑的画布文件与导出图',
|
|
252
|
+
steps: [{ label: '打开画布面板', detail: '由宿主的 Excalidraw 插件承载', state: 'done' }],
|
|
253
|
+
status: 'host', statusNote: '属于 `dsh-data-excalidraw` 插件,这里只画调用关系。',
|
|
254
|
+
icon: PenTool, lane: 'interaction',
|
|
255
|
+
},
|
|
232
256
|
|
|
233
257
|
'source-raw': {
|
|
234
258
|
title: 'SourceRaw', subtitle: '原始可追溯文档',
|
|
@@ -248,12 +272,12 @@ icon: Database, lane: 'knowledge', tab: 'knowledge', knowledgeTab: 'source-raw',
|
|
|
248
272
|
detail: '把 SourceRaw 按主题聚合为 wiki 卡片,并切分出召回单元 wikiNotes。类型与名称一起定,判重按 slug。',
|
|
249
273
|
input: 'SourceRaw 文档 + Wiki 类型注册表', output: 'wiki 卡片(含版本)+ 可召回的 wikiNotes',
|
|
250
274
|
steps: [
|
|
251
|
-
{ label: '
|
|
252
|
-
{ label: '
|
|
253
|
-
{ label: '
|
|
254
|
-
{ label: '
|
|
275
|
+
{ label: '抽取实体', detail: '模型按每个 wiki 类型的必填小节与字段抽实体(规则抽取兜底:正文标题、[[链接]]、frontmatter candidates)', state: 'done' },
|
|
276
|
+
{ label: '合并实体', detail: '按 entityId / title / aliases 比对,同指一物就追加正文与 source_refs,related ≠ same', state: 'done' },
|
|
277
|
+
{ label: '写入 wiki', detail: '命中则增量追加,未命中则新建;缺必填小节 / 字段也照写,只标成待补', state: 'done' },
|
|
278
|
+
{ label: '编译结果', detail: '索引页、断链、相关卡片与三层质检,不调模型', state: 'done' },
|
|
255
279
|
],
|
|
256
|
-
status: '
|
|
280
|
+
status: 'live', statusNote: '四段都已实现:按 schema 抽实体、判重合并、直接入库,收尾段写索引页与相关卡片并检查断链(模型不可用时退回规则抽取,此时正文按小节切)。入库后的 review 与备注在卡片的预览侧栏里。',
|
|
257
281
|
icon: RefreshCw, lane: 'knowledge', tab: 'knowledge', knowledgeTab: 'wiki',
|
|
258
282
|
},
|
|
259
283
|
build: {
|
|
@@ -270,15 +294,15 @@ icon: RefreshCw, lane: 'knowledge', tab: 'knowledge', knowledgeTab: 'wiki',
|
|
|
270
294
|
icon: HardDrive, lane: 'knowledge', tab: 'knowledge', knowledgeTab: 'graph',
|
|
271
295
|
},
|
|
272
296
|
recall: {
|
|
273
|
-
title: '召回', subtitle: 'wikiNotes
|
|
274
|
-
detail: '对 wikiNotes
|
|
297
|
+
title: '召回', subtitle: 'wikiNotes 两路召回(关键词 / 向量)',
|
|
298
|
+
detail: '对 wikiNotes 做两路召回(关键词、向量),融合后取 topK;知识图谱不给候选,只给已在候选池里的条目加权。',
|
|
275
299
|
input: '查询语句 + topK + 路线', output: '带命中路线与得分的 wikiNotes',
|
|
276
300
|
steps: [
|
|
277
|
-
{ label: '
|
|
301
|
+
{ label: '两路并行召回', detail: 'FTS 关键词 + 向量近邻(图谱只加权,不给候选)', state: 'done' },
|
|
278
302
|
{ label: '融合与截断', detail: '按融合分数排序取 topK,逐条标明是哪一路命中的', state: 'done' },
|
|
279
303
|
{ label: '回溯父级 wiki', detail: '每条 wikiNote 通过 wikiId 解析回权威卡片', state: 'done' },
|
|
280
304
|
],
|
|
281
|
-
status: 'live', statusNote: '
|
|
305
|
+
status: 'live', statusNote: '两路召回与召回测试(含命中切片、得分、路线)都在知识库 → 召回重排里可跑。',
|
|
282
306
|
icon: Search, lane: 'knowledge', tab: 'knowledge', knowledgeTab: 'recall',
|
|
283
307
|
},
|
|
284
308
|
context: {
|
|
@@ -391,11 +415,12 @@ export interface KnowledgeStats {
|
|
|
391
415
|
cardsRemoved?: number
|
|
392
416
|
notesReused?: number
|
|
393
417
|
notesRecompiled?: number
|
|
394
|
-
/** Pass 0 · 候选抽取 + 归一的诚实计数(0028)。 */
|
|
418
|
+
/** Pass 0 · 候选抽取 + 归一的诚实计数(0028 / v1.5)。 */
|
|
395
419
|
candidatesExtracted?: number
|
|
396
420
|
candidatesRejected?: number
|
|
397
|
-
cardsCreated
|
|
398
|
-
|
|
421
|
+
/** v1.5:Pass 0 只提议,不落卡 —— 这两个计数数的是**提议**(原名 cardsCreated / cardsMerged)。 */
|
|
422
|
+
proposalsCreated?: number
|
|
423
|
+
proposalsMerged?: number
|
|
399
424
|
relationsExtracted?: number
|
|
400
425
|
relationsDropped?: number
|
|
401
426
|
sourcesExtracted?: number
|
|
@@ -417,9 +442,9 @@ export interface KnowledgeStats {
|
|
|
417
442
|
searchBackend?: string
|
|
418
443
|
}
|
|
419
444
|
|
|
420
|
-
/** SourceRaw 计数有两个来源:`stats.sourceCount` 与磁盘布局 `
|
|
445
|
+
/** SourceRaw 计数有两个来源:`stats.sourceCount` 与磁盘布局 `01_source_raw`。 */
|
|
421
446
|
export function sourceCountOf(stats: KnowledgeStats): number {
|
|
422
|
-
return stats.sourceCount ?? Number(stats.layout?.['
|
|
447
|
+
return stats.sourceCount ?? Number(stats.layout?.['01_source_raw'] ?? 0)
|
|
423
448
|
}
|
|
424
449
|
|
|
425
450
|
/** wikiNotes 计数在接口里有 `notes` / `units` 两个别名。 */
|
|
@@ -504,7 +529,7 @@ export function metricsByNode(stats: KnowledgeStats, version: number): Partial<R
|
|
|
504
529
|
|
|
505
530
|
/** 节点在图上出现的顺序:按链路,再按链内阅读顺序。它就是键盘可达列表的顺序。 */
|
|
506
531
|
export const NODE_ORDER: NodeId[] = [
|
|
507
|
-
'conversation', 'intent', 'runtime', 'answer', 'data-sheet', 'data-notebook',
|
|
532
|
+
'conversation', 'intent', 'runtime', 'answer', 'data-sheet', 'data-notebook', 'data-canvas',
|
|
508
533
|
'source-raw', 'compile', 'build', 'recall', 'context',
|
|
509
534
|
'interaction', 'episodic-memory', 'procedural-memory', 'memory-quality', 'daily-update', 'funded-value',
|
|
510
535
|
]
|