dsh-data-domain-knowledge 0.1.1-alpha.2 → 0.1.1-alpha.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 (189) hide show
  1. package/README.md +23 -16
  2. package/lib/client.js +596 -841
  3. package/lib/contract-refs.d.ts +0 -1
  4. package/lib/doc-page.js +7 -7
  5. package/lib/pages.js +928 -1145
  6. package/lib/types/agent-behavior-rules.d.ts.map +1 -1
  7. package/lib/types/agent-behavior-rules.js +1 -2
  8. package/lib/types/agent-behavior-rules.js.map +1 -1
  9. package/lib/types/axis-contract.js +1 -1
  10. package/lib/types/axis-contract.js.map +1 -1
  11. package/lib/types/card-organize.d.ts +2 -1
  12. package/lib/types/card-organize.d.ts.map +1 -1
  13. package/lib/types/card-organize.js +5 -3
  14. package/lib/types/card-organize.js.map +1 -1
  15. package/lib/types/config-schema.d.ts +1 -1
  16. package/lib/types/config-schema.js +1 -1
  17. package/lib/types/convert/host.d.ts +2 -3
  18. package/lib/types/convert/host.d.ts.map +1 -1
  19. package/lib/types/convert/host.js +5 -2
  20. package/lib/types/convert/host.js.map +1 -1
  21. package/lib/types/convert/ingest.d.ts +2 -0
  22. package/lib/types/convert/ingest.d.ts.map +1 -1
  23. package/lib/types/convert/ingest.js +1 -0
  24. package/lib/types/convert/ingest.js.map +1 -1
  25. package/lib/types/diagnosis/types.d.ts +1 -1
  26. package/lib/types/diagnosis/types.js +1 -1
  27. package/lib/types/images.js +1 -1
  28. package/lib/types/index.d.ts +0 -4
  29. package/lib/types/index.d.ts.map +1 -1
  30. package/lib/types/index.js +30 -41
  31. package/lib/types/index.js.map +1 -1
  32. package/lib/types/knowledge-contract.d.ts +6 -0
  33. package/lib/types/knowledge-contract.d.ts.map +1 -1
  34. package/lib/types/knowledge-contract.js +6 -2
  35. package/lib/types/knowledge-contract.js.map +1 -1
  36. package/lib/types/layout.d.ts +9 -26
  37. package/lib/types/layout.d.ts.map +1 -1
  38. package/lib/types/layout.js +10 -28
  39. package/lib/types/layout.js.map +1 -1
  40. package/lib/types/materialize-snapshot.d.ts +5 -0
  41. package/lib/types/materialize-snapshot.d.ts.map +1 -1
  42. package/lib/types/migrate.d.ts +3 -1
  43. package/lib/types/migrate.d.ts.map +1 -1
  44. package/lib/types/migrate.js +3 -1
  45. package/lib/types/migrate.js.map +1 -1
  46. package/lib/types/organize-contract.d.ts.map +1 -1
  47. package/lib/types/organize-contract.js +2 -1
  48. package/lib/types/organize-contract.js.map +1 -1
  49. package/lib/types/pipeline/engine.d.ts +1 -0
  50. package/lib/types/pipeline/engine.d.ts.map +1 -1
  51. package/lib/types/pipeline/engine.js +9 -3
  52. package/lib/types/pipeline/engine.js.map +1 -1
  53. package/lib/types/pipeline/types.d.ts +6 -0
  54. package/lib/types/pipeline/types.d.ts.map +1 -1
  55. package/lib/types/pipeline/types.js.map +1 -1
  56. package/lib/types/present.d.ts +1 -1
  57. package/lib/types/present.js +1 -1
  58. package/lib/types/preset-ids.d.ts +0 -1
  59. package/lib/types/preset-ids.d.ts.map +1 -1
  60. package/lib/types/preset-ids.js +0 -3
  61. package/lib/types/preset-ids.js.map +1 -1
  62. package/lib/types/query-analysis.d.ts +0 -5
  63. package/lib/types/query-analysis.d.ts.map +1 -1
  64. package/lib/types/query-analysis.js +0 -16
  65. package/lib/types/query-analysis.js.map +1 -1
  66. package/lib/types/recall-delivery.d.ts +36 -0
  67. package/lib/types/recall-delivery.d.ts.map +1 -0
  68. package/lib/types/recall-delivery.js +16 -0
  69. package/lib/types/recall-delivery.js.map +1 -0
  70. package/lib/types/runtime.d.ts +26 -12
  71. package/lib/types/runtime.d.ts.map +1 -1
  72. package/lib/types/runtime.js +231 -106
  73. package/lib/types/runtime.js.map +1 -1
  74. package/lib/types/settings-volatile.d.ts +0 -7
  75. package/lib/types/settings-volatile.d.ts.map +1 -1
  76. package/lib/types/settings-volatile.js +0 -7
  77. package/lib/types/settings-volatile.js.map +1 -1
  78. package/lib/types/source-identity.d.ts +3 -0
  79. package/lib/types/source-identity.d.ts.map +1 -0
  80. package/lib/types/source-identity.js +5 -0
  81. package/lib/types/source-identity.js.map +1 -0
  82. package/lib/types/store/axis-references.d.ts.map +1 -1
  83. package/lib/types/store/axis-references.js +5 -3
  84. package/lib/types/store/axis-references.js.map +1 -1
  85. package/lib/types/store/knowledge-db.d.ts +1 -1
  86. package/lib/types/store/knowledge-db.d.ts.map +1 -1
  87. package/lib/types/store/knowledge-db.js +16 -2
  88. package/lib/types/store/knowledge-db.js.map +1 -1
  89. package/lib/types/types.d.ts +5 -4
  90. package/lib/types/types.d.ts.map +1 -1
  91. package/lib/types/types.js +6 -3
  92. package/lib/types/types.js.map +1 -1
  93. package/lib/types/wiki-availability.d.ts +11 -0
  94. package/lib/types/wiki-availability.d.ts.map +1 -0
  95. package/lib/types/wiki-availability.js +39 -0
  96. package/lib/types/wiki-availability.js.map +1 -0
  97. package/lib/types/wiki-finalize.d.ts +4 -2
  98. package/lib/types/wiki-finalize.d.ts.map +1 -1
  99. package/lib/types/wiki-finalize.js +9 -27
  100. package/lib/types/wiki-finalize.js.map +1 -1
  101. package/lib/types/wiki-links.d.ts +35 -0
  102. package/lib/types/wiki-links.d.ts.map +1 -0
  103. package/lib/types/wiki-links.js +129 -0
  104. package/lib/types/wiki-links.js.map +1 -0
  105. package/package.json +16 -16
  106. package/scripts/doctor.mjs +0 -7
  107. package/scripts/setup-embedding.sh +0 -0
  108. package/src/agent-behavior-rules.ts +1 -2
  109. package/src/axis-contract.ts +1 -1
  110. package/src/card-organize.ts +5 -3
  111. package/src/client/AttributionEventGuide.tsx +3 -3
  112. package/src/client/AxisMatrix.tsx +86 -19
  113. package/src/client/DirectoryPicker.tsx +0 -2
  114. package/src/client/GuideArchitectureCanvas.tsx +5 -12
  115. package/src/client/ImportFilesDialog.tsx +1 -0
  116. package/src/client/InfoHint.tsx +1 -1
  117. package/src/client/KnowledgeBaseTab.tsx +113 -39
  118. package/src/client/KnowledgePanel.tsx +16 -9
  119. package/src/client/OperationLogTab.tsx +1 -1
  120. package/src/client/RecallPanel.tsx +5 -16
  121. package/src/client/TabGuide.tsx +3 -7
  122. package/src/client/WikiFlowPanel.tsx +10 -11
  123. package/src/client/arch/NodeLogicPanel.tsx +3 -3
  124. package/src/client/arch/model.ts +5 -113
  125. package/src/client/architecture.css +1 -1
  126. package/src/client/architecture.tsx +13 -27
  127. package/src/client/attribution/AttributionTab.tsx +141 -10
  128. package/src/client/pages.css +2 -2
  129. package/src/client/pages.tsx +4 -11
  130. package/src/client/styles.css +15 -96
  131. package/src/config-schema.ts +1 -1
  132. package/src/convert/host.ts +7 -5
  133. package/src/convert/ingest.ts +3 -0
  134. package/src/diagnosis/types.ts +1 -1
  135. package/src/images.ts +1 -1
  136. package/src/index.ts +27 -49
  137. package/src/knowledge-contract.ts +7 -2
  138. package/src/layout.ts +10 -32
  139. package/src/materialize-snapshot.ts +1 -0
  140. package/src/migrate.ts +3 -1
  141. package/src/organize-contract.ts +2 -1
  142. package/src/pipeline/engine.ts +9 -3
  143. package/src/pipeline/types.ts +2 -0
  144. package/src/present.ts +1 -1
  145. package/src/preset-ids.ts +0 -4
  146. package/src/query-analysis.ts +0 -20
  147. package/src/recall-delivery.ts +19 -0
  148. package/src/runtime.ts +220 -102
  149. package/src/settings-volatile.ts +0 -7
  150. package/src/source-identity.ts +4 -0
  151. package/src/store/axis-references.ts +5 -3
  152. package/src/store/knowledge-db.ts +14 -2
  153. package/src/types.ts +6 -4
  154. package/src/wiki-availability.ts +37 -0
  155. package/src/wiki-finalize.ts +9 -25
  156. package/src/wiki-links.ts +120 -0
  157. package/lib/types/intent/engine.d.ts +0 -122
  158. package/lib/types/intent/engine.d.ts.map +0 -1
  159. package/lib/types/intent/engine.js +0 -488
  160. package/lib/types/intent/engine.js.map +0 -1
  161. package/lib/types/intent/host.d.ts +0 -68
  162. package/lib/types/intent/host.d.ts.map +0 -1
  163. package/lib/types/intent/host.js +0 -249
  164. package/lib/types/intent/host.js.map +0 -1
  165. package/lib/types/intent/scope.d.ts +0 -25
  166. package/lib/types/intent/scope.d.ts.map +0 -1
  167. package/lib/types/intent/scope.js +0 -116
  168. package/lib/types/intent/scope.js.map +0 -1
  169. package/lib/types/intent/store.d.ts +0 -33
  170. package/lib/types/intent/store.d.ts.map +0 -1
  171. package/lib/types/intent/store.js +0 -239
  172. package/lib/types/intent/store.js.map +0 -1
  173. package/lib/types/intent/tools.d.ts +0 -62
  174. package/lib/types/intent/tools.d.ts.map +0 -1
  175. package/lib/types/intent/tools.js +0 -130
  176. package/lib/types/intent/tools.js.map +0 -1
  177. package/lib/types/intent/types.d.ts +0 -170
  178. package/lib/types/intent/types.d.ts.map +0 -1
  179. package/lib/types/intent/types.js +0 -56
  180. package/lib/types/intent/types.js.map +0 -1
  181. package/src/client/IntentLogic.tsx +0 -192
  182. package/src/client/IntentTab.tsx +0 -343
  183. package/src/intent/README.md +0 -42
  184. package/src/intent/engine.ts +0 -515
  185. package/src/intent/host.ts +0 -315
  186. package/src/intent/scope.ts +0 -125
  187. package/src/intent/store.ts +0 -218
  188. package/src/intent/tools.ts +0 -154
  189. package/src/intent/types.ts +0 -229
package/src/index.ts CHANGED
@@ -38,7 +38,7 @@ import { runWikiTrial, trialSummary } from './wiki-trial.js'
38
38
  import { extractionRunId } from './extraction-runs.js'
39
39
  import type { PipelineStage } from './pipeline/types.js'
40
40
  import {
41
- agentLayout, defaultAgentRoot, ensureAgentLayout, intentRoot, knowledgeBaseRoot,
41
+ agentLayout, defaultAgentRoot, ensureAgentLayout, knowledgeBaseRoot,
42
42
  memoryRoot, resourceRegistry, resourceRoot, type AgentLayout,
43
43
  } from './layout.js'
44
44
  import {
@@ -55,21 +55,11 @@ import {
55
55
  type ConvertHost,
56
56
  } from './convert/host.js'
57
57
  import type { ConvertPluginConfig } from './convert/types.js'
58
- import {
59
- applyIntent, INTENT_MOUNT_PATH, INTENT_SERVICE,
60
- type IntentHost,
61
- type IntentLineageService,
62
- type IntentService,
63
- } from './intent/host.js'
64
- import { registerIntentTools } from './intent/tools.js'
65
58
 
66
59
  export * from './types.js'
67
60
  export * from './runtime.js'
68
61
  export * from './knowledge-bases.js'
69
- export * from './intent/types.js'
70
- export * from './intent/engine.js'
71
62
  export { applyConvert as applyConvertHost, CONVERT_SETTINGS_NAMESPACE, CONVERT_MOUNT_PATH, type ConvertHost }
72
- export { applyIntent as applyIntentHost, INTENT_MOUNT_PATH, INTENT_SERVICE, type IntentHost, type IntentLineageService }
73
63
 
74
64
  export const name = 'dsh-data-domain-knowledge'
75
65
  /**
@@ -93,6 +83,7 @@ export { CONVERT_SETTINGS_SCHEMA }
93
83
  */
94
84
  import { Config, type KnowledgePluginConfig } from './config-schema.js'
95
85
  import { buildModelRequest, callModelWithRetry, collectModelText } from './model-text.js'
86
+ import { agentRecallEnvelope } from './recall-delivery.js'
96
87
  import {
97
88
  addSourceCallView, addSourceMetaOf, addSourceResultMarkdown,
98
89
  importCallView, importMetaOf, importResultMarkdown,
@@ -123,7 +114,7 @@ type WebServerLike = { register(route: { kind: 'exact' | 'prefix'; path: string;
123
114
  * `src/client/KnowledgeToolRow.tsx` 读它渲染专用卡片(值必须是 JSON 可序列化的 ——
124
115
  * 会话日志会整份校验,塞个函数或 Date 会在写日志时炸)。
125
116
  *
126
- * `call` / `result` 是与工具名无关的渲染意图(标题 / 分类 / 一段 Markdown),
117
+ * `call` / `result` 是与工具名无关的渲染参数(标题 / 分类 / 一段 Markdown),
127
118
  * 给终端界面和「没有专用卡片的界面」兜底。三个都是**纯函数**:界面在实时流和会话回放
128
119
  * 两条路径上都会调它们。
129
120
  *
@@ -212,7 +203,7 @@ function lineageOf(args: Args, exec?: ToolRunContext): LineageContext | undefine
212
203
  const sessionId = typeof args.session_key === 'string' && args.session_key.trim() ? args.session_key.trim() : exec?.agent?.session.header.id
213
204
  if (sessionId) lineage.sessionId = sessionId
214
205
  const fields: Array<[keyof LineageContext, string]> = [
215
- ['turnId', 'turn_id'], ['intentId', 'intent_id'], ['taskId', 'task_id'],
206
+ ['turnId', 'turn_id'], ['taskId', 'task_id'],
216
207
  ['subtaskId', 'subtask_id'], ['parentSubtaskId', 'parent_subtask_id'], ['runId', 'run_id'], ['traceId', 'trace_id'], ['domain', 'domain'],
217
208
  ]
218
209
  for (const [target, source] of fields) if (typeof args[source] === 'string' && args[source].trim()) lineage[target] = args[source].trim().slice(0, 160)
@@ -223,7 +214,6 @@ function lineageFromUrl(url: URL): LineageContext | undefined {
223
214
  return lineageOf({
224
215
  session_key: url.searchParams.get('session_key') ?? undefined,
225
216
  turn_id: url.searchParams.get('turn_id') ?? undefined,
226
- intent_id: url.searchParams.get('intent_id') ?? undefined,
227
217
  task_id: url.searchParams.get('task_id') ?? undefined,
228
218
  subtask_id: url.searchParams.get('subtask_id') ?? undefined,
229
219
  parent_subtask_id: url.searchParams.get('parent_subtask_id') ?? undefined,
@@ -407,8 +397,7 @@ export function apply(ctx: Context, pluginConfig: KnowledgePluginConfig = {}): v
407
397
  /**
408
398
  * 这两组的把手,`loader/volatile-update` 时调 `reprocess()` 按新值重灌。
409
399
  *
410
- * 先声明后赋值:事件只在运行时触发,而两组的装配在下面(`applyConvert` /
411
- * `applyIntent`)。
400
+ * 先声明后赋值:事件只在运行时触发,转换宿主在下面的 `applyConvert` 中装配。
412
401
  */
413
402
  let convertHost: ConvertHost | undefined
414
403
  /**
@@ -806,7 +795,7 @@ export function apply(ctx: Context, pluginConfig: KnowledgePluginConfig = {}): v
806
795
  /**
807
796
  * 交付物落在**工作项目**下:`<工作区>/output/<日期>/`,不是 Agent 根路径。
808
797
  *
809
- * 根路径下的四段(知识 / 记忆 / 意图 / 家当)是**这个 Agent 自己的东西**,跨项目
798
+ * 根路径下的几段(知识 / 记忆 / 家当)是**这个 Agent 自己的东西**,跨项目
810
799
  * 累积;交付物是**某个项目的产物**,换一个项目打开就不该再看见。两者判据不同,
811
800
  * 所以落点也不同。
812
801
  *
@@ -827,30 +816,6 @@ export function apply(ctx: Context, pluginConfig: KnowledgePluginConfig = {}): v
827
816
  },
828
817
  })
829
818
 
830
- // 意图记录模块 (issue 0020). The 意图 view was already one of this plugin's
831
- // five panel tabs, but its Host lived in a second mount unit; 0020 folds it in
832
- // so the declared information architecture and the code layout agree again.
833
- // It keeps the `intent_record` / `intent_store_view` tools and `/intent/**` audit endpoints,
834
- // and — critically — the `titaDataAgentIntent` Cordis service that `data-table`
835
- // resolves by name.
836
- // 意图只保留固定的会话审计契约;可编辑词表不再属于插件配置。
837
- applyIntent(ctx, {
838
- intentRoot: () => intentRoot(config.agentRoot),
839
- })
840
- // `applyIntent` provides this service from the same plugin fiber. During
841
- // `apply()`, that fiber is still starting, so Cordis's default strict lookup
842
- // hides the just-provided service until startup completes. The non-strict
843
- // lookup is safe here because `applyIntent` ran immediately above.
844
- const intentService = ctx.get(INTENT_SERVICE, false) as IntentService
845
- /**
846
- * `intent_*` 工具在 Host 层注册,使标准模式可以调用它们;工具执行端只接受
847
- * standard 会话,其他 preset 不会写入或读取意图记录。
848
- */
849
- ctx.effect(
850
- () => registerIntentTools(ctx as unknown as { tools: { register(definition: unknown): unknown } }, intentService),
851
- 'tita knowledge: global intent tools',
852
- )
853
-
854
819
  /**
855
820
  * 规则正文由当前会话 preset 决定;设置里的 volatile 引用在每次组装提示词时解包,
856
821
  * 因此开关保存后立即生效,不需要重建 Agent 会话。
@@ -895,12 +860,16 @@ export function apply(ctx: Context, pluginConfig: KnowledgePluginConfig = {}): v
895
860
  if (writeTools.has(exec.name)) return Promise.resolve({ kind: 'ask', reason: '该操作会写入 Tita Knowledge Store,需要本轮用户审批。' })
896
861
  return next()
897
862
  })
898
- ctx.tools.register(tool('recall_knowledge', 'Recall Wiki Fact and Wiki Way through H2 title and body search. Use the current subquestion as query when seeking a Procedure. Return complete Wiki files with conditions and evidence. Use get_knowledge_cases for historical Case evidence; a past root cause does not establish the current root cause.', { query: { type: 'string', required: true }, limit: { type: 'integer' }, top_k: { type: 'integer' }, top_n: { type: 'integer' }, rerank: { type: 'boolean' }, context_max_chars: { type: 'integer', description: '这次召回的上下文字符上限;省略则用设置里的值(默认 20000,0 = 不限)。超出部分落在系统临时目录,响应里的 budget.overflow_path 就是它的绝对路径 —— 需要更多信息时直接读那个文件。' }, include_problems: { type: 'boolean' }, mode: { type: 'string', enum: ['fts', 'vector', 'hybrid'] }, kb: { type: 'string' }, session_key: { type: 'string' }, task_id: { type: 'string' }, subtask_id: { type: 'string' }, parent_subtask_id: { type: 'string' }, run_id: { type: 'string' }, turn_id: { type: 'string' }, trace_id: { type: 'string' }, domain: { type: 'string' } }, async (args, exec) => withRuntime(args.kb, target => target.recall(args.query, args.top_k ?? args.limit, args.include_problems ?? false, args.mode as RecallMode | undefined, lineageOf(args, exec), { contextTopN: args.top_n, rerank: args.rerank, ...(typeof args.context_max_chars === 'number' ? { contextMaxChars: args.context_max_chars } : {}) })), {
863
+ ctx.tools.register(tool('recall_knowledge', 'Recall Wiki Fact and Wiki Way through H2 title and body search. Use the current subquestion as query when seeking a Procedure. Return complete Wiki files with conditions and evidence. Follow Wiki links with read_knowledge_wiki; browse Object coordinates with its object_id filter. Use get_knowledge_cases for historical Case evidence; a past root cause does not establish the current root cause.', { query: { type: 'string', required: true }, limit: { type: 'integer' }, top_k: { type: 'integer' }, top_n: { type: 'integer' }, rerank: { type: 'boolean' }, context_max_chars: { type: 'integer', description: '这次召回的上下文字符上限;省略则用设置里的值(默认 20000,0 = 不限)。超出部分落在系统临时目录,响应里的 budget.overflow_path 就是它的绝对路径 —— 需要更多信息时直接读那个文件。' }, include_problems: { type: 'boolean' }, mode: { type: 'string', enum: ['fts', 'vector', 'hybrid'] }, kb: { type: 'string' }, session_key: { type: 'string' }, task_id: { type: 'string' }, subtask_id: { type: 'string' }, parent_subtask_id: { type: 'string' }, run_id: { type: 'string' }, turn_id: { type: 'string' }, trace_id: { type: 'string' }, domain: { type: 'string' } }, async (args, exec) => withRuntime(args.kb, async target => agentRecallEnvelope(await target.recall(args.query, args.top_k ?? args.limit, args.include_problems ?? false, args.mode as RecallMode | undefined, lineageOf(args, exec), { contextTopN: args.top_n, rerank: args.rerank, ...(typeof args.context_max_chars === 'number' ? { contextMaxChars: args.context_max_chars } : {}) }))), {
899
864
  call: recallCallView,
900
865
  // 查询词从参数来,命中从结果来 —— 两者拼成一张能看懂的账本。
901
866
  meta: (args, value) => recallMetaOf({ ...dataOf(value), query: args?.query }),
902
867
  result: resultViewOf(recallResultMarkdown),
903
868
  }))
869
+ ctx.tools.register(tool('read_knowledge_wiki', 'Read a complete Wiki through a [[type/entityId|label]] link or stable target. Browse an Object by object_id or unique object name; optional action_id, scene_id and wiki_kind select exact coordinates. Omitted axes mean all; empty axes match empty only. Object browsing returns a paged directory by default. Set include_content to read complete selected files. Follow outgoing links and backlinks as needed; do not fetch every neighbor automatically.', {
870
+ target: { type: 'string' }, object_id: { type: 'string' }, object: { type: 'string' }, action_id: { type: 'string' }, scene_id: { type: 'string' }, wiki_kind: { type: 'string', enum: ['fact', 'way'] },
871
+ include_content: { type: 'boolean' }, limit: { type: 'integer' }, offset: { type: 'integer' }, kb: { type: 'string' },
872
+ }, async args => withRuntime(args.kb, target => target.readWiki({ target: args.target, objectId: args.object_id, object: args.object, actionId: args.action_id, sceneId: args.scene_id, wikiKind: args.wiki_kind as 'fact' | 'way' | undefined, includeContent: args.include_content, limit: args.limit, offset: args.offset }))))
904
873
  ctx.tools.register(tool('get_knowledge_cases', 'Read historical Case records referenced by Wiki metadata.case_refs. Timelines are evidence from a past instance, not proof of the present diagnosis.', {
905
874
  case_ids: { type: 'array', required: true, description: 'Case IDs from Wiki metadata.case_refs; maximum 50 IDs.' },
906
875
  version: { type: 'integer', description: 'Optional historical Case version from metadata.case_refs; requires exactly one case ID.' },
@@ -1000,10 +969,10 @@ export function apply(ctx: Context, pluginConfig: KnowledgePluginConfig = {}): v
1000
969
  * 两者的差别只在「一次多少份」,落盘路径、分类闸门、编译链路完全共用 ——
1001
970
  * 这个工具的 `execute` 就是循环调 `importSources`,而后者逐条调 `addSource`。
1002
971
  *
1003
- * `compile` 默认开:批量导入的意图几乎总是「进来就能用」。关掉它的场景是「先全部
1004
- * 落盘、稍后统一编译」——那时卡片还没生成,工具返回里会明说 `compile: null`。
972
+ * `compile` 默认关闭:先保存来源,再由调用方决定何时处理。显式 true 才跑全链路;
973
+ * 未触发处理时工具返回 `compile: null`。
1005
974
  */
1006
- ctx.tools.register(tool('import_sources', 'Import many SourceRaw documents in one call. By default only stores sources. Explicit compile:true runs extract, normalize, materialize, and index publication for the imported documents. Per-source import failures are reported without aborting the batch. DSH requests one user approval before execution.', { sources: { type: 'array', required: true, description: `来源数组,每项 { title?, content, external_id?, metadata?, allow_duplicate_title? };一次最多 ${MAX_IMPORT_SOURCES} 份,超了请分批。标题与已有来源重复的那一份会被拒(SOURCE_TITLE_DUPLICATED),逐条报出来而不是整批失败` }, compile: { type: 'boolean', description: '默认 false:只保存来源;显式 true 才运行完整抽取、归一与物化' }, kb: { type: 'string' }, session_key: { type: 'string' }, task_id: { type: 'string' }, subtask_id: { type: 'string' }, run_id: { type: 'string' }, turn_id: { type: 'string' }, trace_id: { type: 'string' }, domain: { type: 'string' } }, async (args, exec) => withRuntime(args.kb, target => target.importSources({ sources: (Array.isArray(args.sources) ? args.sources : []).map(item => ({ ...(item?.title ? { title: item.title } : {}), content: item?.content, ...(item?.external_id ? { externalId: item.external_id } : {}), ...(item?.metadata ? { metadata: item.metadata } : {}), ...(item?.allow_duplicate_title === true ? { allowDuplicateTitle: true } : {}) })), compile: args.compile === true, lineage: lineageOf(args, exec) })), { call: importCallView, meta: (_args, value) => importMetaOf(dataOf(value)), result: resultViewOf(importResultMarkdown) }))
975
+ ctx.tools.register(tool('import_sources', 'Import many SourceRaw documents in one call. By default only stores sources. Explicit compile:true runs extract, normalize, materialize, and index publication for the imported documents. Per-source import failures are reported without aborting the batch. DSH requests one user approval before execution.', { sources: { type: 'array', required: true, description: `来源数组,每项 { source_id?, title?, content, external_id?, metadata?, allow_duplicate_title? };文件导入前分配唯一 source_id,重试沿用;更新旧来源必须传其 source_id;一次最多 ${MAX_IMPORT_SOURCES} 份,超了请分批。标题与已有来源重复的那一份会被拒(SOURCE_TITLE_DUPLICATED),逐条报出来而不是整批失败` }, compile: { type: 'boolean', description: '默认 false:只保存来源;显式 true 才运行完整抽取、归一与物化' }, kb: { type: 'string' }, session_key: { type: 'string' }, task_id: { type: 'string' }, subtask_id: { type: 'string' }, run_id: { type: 'string' }, turn_id: { type: 'string' }, trace_id: { type: 'string' }, domain: { type: 'string' } }, async (args, exec) => withRuntime(args.kb, target => target.importSources({ sources: (Array.isArray(args.sources) ? args.sources : []).map(item => ({ ...(item?.source_id ? { sourceId: item.source_id } : {}), ...(item?.title ? { title: item.title } : {}), content: item?.content, ...(item?.external_id ? { externalId: item.external_id } : {}), ...(item?.metadata ? { metadata: item.metadata } : {}), ...(item?.allow_duplicate_title === true ? { allowDuplicateTitle: true } : {}) })), compile: args.compile === true, lineage: lineageOf(args, exec) })), { call: importCallView, meta: (_args, value) => importMetaOf(dataOf(value)), result: resultViewOf(importResultMarkdown) }))
1007
976
  /**
1008
977
  * `propose_wiki_cards` —— 把一批卡片**直接写进 `02_wiki`**(工具名不变,语义在 0044 改了)。
1009
978
  *
@@ -1146,6 +1115,16 @@ export function apply(ctx: Context, pluginConfig: KnowledgePluginConfig = {}): v
1146
1115
  if ('failure' in resolved) return sendEnvelope(res, resolved.failure)
1147
1116
  return send(res, 200, success(await resolved.runtime.stats()))
1148
1117
  } },
1118
+ { kind: 'exact' as const, path: '/knowledge/wiki', handler: async (req: IncomingMessage, res: ServerResponse) => {
1119
+ if (req.method !== 'GET') return send(res, 405, envelopeError('METHOD_NOT_ALLOWED', 'Wiki 读取只接受 GET'))
1120
+ const url = query(req)
1121
+ const resolved = resolveBase(url.searchParams.get('kb'))
1122
+ if ('failure' in resolved) return sendEnvelope(res, resolved.failure)
1123
+ return sendEnvelope(res, await resolved.runtime.readWiki({ target: url.searchParams.get('target') ?? undefined, objectId: url.searchParams.get('object_id') ?? undefined, object: url.searchParams.get('object') ?? undefined,
1124
+ actionId: url.searchParams.get('action_id') ?? undefined, sceneId: url.searchParams.get('scene_id') ?? undefined, wikiKind: (url.searchParams.get('wiki_kind') ?? undefined) as 'fact' | 'way' | undefined,
1125
+ includeContent: url.searchParams.has('include_content') ? url.searchParams.get('include_content') === 'true' : undefined,
1126
+ limit: url.searchParams.has('limit') ? Number(url.searchParams.get('limit')) : undefined, offset: url.searchParams.has('offset') ? Number(url.searchParams.get('offset')) : undefined }))
1127
+ } },
1149
1128
  { kind: 'exact' as const, path: '/knowledge/cases', handler: async (req: IncomingMessage, res: ServerResponse) => {
1150
1129
  if (req.method !== 'GET') return send(res, 405, envelopeError('METHOD_NOT_ALLOWED', 'Case 只接受 GET'))
1151
1130
  const resolved = resolveBase(query(req).searchParams.get('kb'))
@@ -1362,8 +1341,10 @@ export function apply(ctx: Context, pluginConfig: KnowledgePluginConfig = {}): v
1362
1341
  sources: (Array.isArray(body.sources) ? body.sources : []).map((item: Record<string, unknown>) => ({
1363
1342
  ...(item?.title ? { title: String(item.title) } : {}),
1364
1343
  content: item?.content as string,
1344
+ ...(item?.source_id ? { sourceId: String(item.source_id) } : {}),
1365
1345
  ...(item?.external_id ? { externalId: String(item.external_id) } : {}),
1366
1346
  ...(item?.metadata && typeof item.metadata === 'object' ? { metadata: item.metadata as Record<string, unknown> } : {}),
1347
+ ...(item?.allow_duplicate_title === true ? { allowDuplicateTitle: true } : {}),
1367
1348
  })),
1368
1349
  compile: body.compile === true,
1369
1350
  lineage: lineageOf(body),
@@ -1966,7 +1947,6 @@ export function apply(ctx: Context, pluginConfig: KnowledgePluginConfig = {}): v
1966
1947
  * /knowledge/pages/run?kb=<库 id>&run=<轨迹 id> 一次抽取的完整报告
1967
1948
  * /knowledge/pages/tasks?kb=<知识库 id> 抽取任务
1968
1949
  * /knowledge/pages/help/compile 编译链路
1969
- * /knowledge/pages/help/intent 意图的逻辑
1970
1950
  * /knowledge/pages/help/overview?node=... 五个 Tab 的方案说明
1971
1951
  * ```
1972
1952
  *
@@ -1993,9 +1973,7 @@ export function apply(ctx: Context, pluginConfig: KnowledgePluginConfig = {}): v
1993
1973
  ? '抽取轨迹'
1994
1974
  : rest[1] === 'tasks'
1995
1975
  ? '抽取任务'
1996
- : rest[1] === 'help' && rest[2] === 'intent'
1997
- ? '意图的逻辑'
1998
- : rest[1] === 'help' && rest[2] === 'compile'
1976
+ : rest[1] === 'help' && rest[2] === 'compile'
1999
1977
  ? '编译链路'
2000
1978
  : rest[1] === 'help' && rest[2] === 'overview' ? 'Agent 方案说明' : '整页'
2001
1979
  res.writeHead(200, { 'content-type': 'text/html; charset=utf-8', 'cache-control': 'no-cache' })
@@ -18,8 +18,13 @@ export interface KnowledgeContent {
18
18
  }
19
19
 
20
20
  export function wikiProjection(kind: KnowledgeKind, coordinate: { objectId: string; actionId: string; sceneId: string }): { objectId: string; actionId: string; sceneId: string } | undefined {
21
- if (kind === 'case' || !coordinate.objectId || (kind === 'procedure' && !coordinate.actionId)) return undefined
22
- return { objectId: coordinate.objectId, actionId: kind === 'procedure' ? coordinate.actionId : '', sceneId: '' }
21
+ if (kind === 'case' || !coordinate.objectId) return undefined
22
+ return { ...coordinate }
23
+ }
24
+
25
+ /** Wiki identity preserves the full coordinate and separates Fact from Way. Empty axes are exact values. */
26
+ export function wikiGroupKey(kind: WikiKind, coordinate: { objectId: string; actionId: string; sceneId: string }): string {
27
+ return `wiki:${kind}:${coordinate.objectId}\u0001${coordinate.actionId}\u0001${coordinate.sceneId}`
23
28
  }
24
29
 
25
30
  export function procedureText(value: ProcedureContent): string {
package/src/layout.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Tita Agent 在磁盘上的布局(0029 定四段,0032 扩到六段,0062 v2 **取消了知识库里的段**)。
2
+ * Tita Agent 在磁盘上的布局(Agent 根路径固定四段,知识库内部不再使用段目录)。
3
3
  *
4
4
  * ## 为什么要有这个文件
5
5
  *
@@ -8,7 +8,7 @@
8
8
  * 都可能指向不同的卷,于是「这个 Agent 的东西在哪」这个问题没有唯一答案 ——
9
9
  * 备份要记得两个路径,换机器要改两处,用户也没法一眼看出磁盘上哪块是它的。
10
10
  *
11
- * 现在**只有一个设置**:Tita Agent 根路径。根路径下固定六段,职责互不重叠:
11
+ * 现在**只有一个设置**:Tita Agent 根路径。根路径下固定四段,职责互不重叠:
12
12
  *
13
13
  * ```
14
14
  * <agentRoot>/
@@ -24,7 +24,6 @@
24
24
  * extraction-runs.sqlite 抽取轨迹
25
25
  * access-audit.ndjson 访问审计
26
26
  * feedback.ndjson 反馈
27
- * intent/ 意图:intent.db(会话审计留痕)
28
27
  * tmp/ 运行期临时文件:转换工作区、任务状态
29
28
  * <YYYY-MM-DD>/ 二级按日期分桶
30
29
  * resource/ Agent 跑起来所需要的家当(不是它的产出)
@@ -100,11 +99,7 @@
100
99
  * 不可重建的命名决定。按原理 5 的判据(「要不要跟着知识一起备份、迁移、删除」)它们
101
100
  * 必须跟着知识走,所以 0062 把它们搬进了 `knowledge.db`。今天 `memory/` 里**没有一样
102
101
  * 东西是不可重建的知识**,这才是这条原理想要的终态。
103
- * 6. **意图(`intent/`)与记忆平级,但它不分库。** 意图是**会话级**的:同一句话
104
- * 在哪个知识库下说,理解方式不该变。它的两份东西 —— 分类/act 注册表(配置)
105
- * 与每轮记录(留痕)—— 原来一个住在宿主的 settings 文档里、一个只在内存里,
106
- * 都不是「这个 Agent 自己的文件」;落进根路径之后,它们和知识、记忆一样可以
107
- * 被备份、被 diff、被用户直接读。
102
+ * 6. 会话目标由当前请求和坐标直接提供,不在 Agent 根路径下复制分类词表或会话记录库。
108
103
  *
109
104
  * 这个文件是布局的**唯一真源**:运行时、知识库注册表、转换内核、设置面板读到的
110
105
  * 都是这里算出来的路径,不在别处再拼一次字符串。
@@ -121,8 +116,8 @@ import { basename, dirname, join, resolve } from 'node:path'
121
116
  *
122
117
  * 分两组看,判据不同:
123
118
  *
124
- * - **Agent 自己的东西**:`domain_knowledge`(知识)、`memory`(记忆)、`intent`
125
- * (意图记录)、`tmp`(运行期临时态)。判据是「能不能重建」。
119
+ * - **Agent 自己的东西**:`domain_knowledge`(知识)、`memory`(审计与版本记录)、
120
+ * `tmp`(运行期临时态)。判据是「能不能重建」。
126
121
  * - **跑起来所需的依赖**:`resource`(模型、Python 环境、注册表)。判据是「属于谁」。
127
122
  *
128
123
  * **`output` 不在这里。** 交付物是**某个工作项目的产物**,不是这个 Agent 的固有状态:
@@ -130,7 +125,7 @@ import { basename, dirname, join, resolve } from 'node:path'
130
125
  * 所以它落在**当前工作区**的 `output/<日期>/` 下,而不是跟着 Agent 的家走。
131
126
  * 约定写在知识插件追加到标准模式系统提示词的行为规则里。
132
127
  */
133
- export const AGENT_DIRS = ['domain_knowledge', 'memory', 'intent', 'tmp', 'resource'] as const
128
+ export const AGENT_DIRS = ['domain_knowledge', 'memory', 'tmp', 'resource'] as const
134
129
  export type AgentDirName = typeof AGENT_DIRS[number]
135
130
 
136
131
  /** 知识树那一段的目录名。 */
@@ -162,19 +157,10 @@ export const RESOURCE_DIR = 'resource'
162
157
  * 反馈与访问审计。它从知识树里**搬出来**了,理由见文件头第 5 条原理。
163
158
  */
164
159
  export const MEMORY_DIR = 'memory'
165
- /**
166
- * 意图那一段的目录名(0032)。
167
- *
168
- * 里面装的是意图的**会话审计留痕**:`intent.db`(当前记录 + 追加历史)。旧的
169
- * `records.ndjson` 只在首次打开时迁移,不再继续写入。
170
- * 分类与 act 是固定契约,不属于 Agent 的可编辑配置。
171
- */
172
- export const INTENT_DIR = 'intent'
173
-
174
160
  /**
175
161
  * 默认根路径:`~/.dsh/tita-agent`。
176
162
  *
177
- * `.dsh` 是 DSH 的用户级数据根;`tita-agent` 是本插件的专属目录。知识、记忆、意图、
163
+ * `.dsh` 是 DSH 的用户级数据根;`tita-agent` 是本插件的专属目录。知识、记忆、
178
164
  * 临时态与运行所需家当都收在这里,用户不需要再管理一条插件自己的路径。
179
165
  */
180
166
  export function defaultAgentRoot(): string {
@@ -223,7 +209,7 @@ export function knowledgeBaseRoot(agentRoot: string, kbId: string): string {
223
209
  * 交付物的落点:`<工作区>/output`。
224
210
  *
225
211
  * 刻意**不**由 `agentRoot` 推出来。交付物是**某个工作项目的产物** —— 同一个 Agent
226
- * 换一个项目打开,不该再看见上一个项目产出的图和数据。知识、记忆、意图记录是 Agent
212
+ * 换一个项目打开,不该再看见上一个项目产出的图和数据。知识与记忆是 Agent
227
213
  * 自己的、跨项目累积的东西,所以留在 `agentRoot`;交付物属于项目,所以跟着项目走。
228
214
  *
229
215
  * 二级目录按日期分桶(`output/<YYYY-MM-DD>/`),由转换内核的 `bucketByDay` 打开;
@@ -297,11 +283,9 @@ export interface AgentLayout {
297
283
  resource: string
298
284
  /** 记忆那一段(版本快照 / 反馈 / 访问审计),二级按知识库 id 分叉(0032)。 */
299
285
  memory: string
300
- /** 意图那一段(intent.db)(0032)。 */
301
- intent: string
302
286
  }
303
287
 
304
- /** 由根路径算出六段布局。纯函数,测试直接断言。 */
288
+ /** 由根路径算出四段布局。纯函数,测试直接断言。 */
305
289
  export function agentLayout(agentRoot: string): AgentLayout {
306
290
  const root = resolve(agentRoot)
307
291
  return {
@@ -310,7 +294,6 @@ export function agentLayout(agentRoot: string): AgentLayout {
310
294
  tmp: join(root, TMP_DIR),
311
295
  resource: join(root, RESOURCE_DIR),
312
296
  memory: join(root, MEMORY_DIR),
313
- intent: join(root, INTENT_DIR),
314
297
  }
315
298
  }
316
299
 
@@ -326,11 +309,6 @@ export function memoryRoot(agentRoot: string, kbId: string): string {
326
309
  return join(resolve(agentRoot), MEMORY_DIR, kbId)
327
310
  }
328
311
 
329
- /** `<agentRoot>/intent`:会话意图审计留痕(0032)。意图不分库。 */
330
- export function intentRoot(agentRoot: string): string {
331
- return join(resolve(agentRoot), INTENT_DIR)
332
- }
333
-
334
312
  /**
335
313
  * 一个知识库根目录里**固定存在的三样东西**(PRD v2 §0.2)。
336
314
  *
@@ -396,7 +374,7 @@ export function looksLikeLegacyKnowledgeRoot(path: string): boolean {
396
374
  */
397
375
  export function ensureAgentLayout(agentRoot: string): AgentLayout {
398
376
  const layout = agentLayout(agentRoot)
399
- for (const dir of [layout.domainKnowledge, layout.tmp, layout.resource, layout.memory, layout.intent]) {
377
+ for (const dir of [layout.domainKnowledge, layout.tmp, layout.resource, layout.memory]) {
400
378
  try {
401
379
  mkdirSync(dir, { recursive: true })
402
380
  } catch {
@@ -33,6 +33,7 @@ export interface MaterializationSnapshot {
33
33
  blockedAmbiguous: number
34
34
  /** 来源已变化 / 新抽取尚未归一的 Knowledge 条数。 */
35
35
  blockedAwaitingNormalize: number
36
+ blockedItems: Array<{ knowledgeId: string; sourceIds: string[]; groupKey?: string }>
36
37
  /** key → 这一组参与成卡的知识。 */
37
38
  knowledge: Map<string, Knowledge[]>
38
39
  /** key → 这一组的 Event。 */
package/src/migrate.ts CHANGED
@@ -87,7 +87,9 @@ function skipped(reason: string, from?: string, to?: string): MigrationOutcome {
87
87
  * 把旧版完整的 Agent 根目录合并到新的固定根目录。
88
88
  *
89
89
  * 这和 `migrateLegacyKnowledgeTree` 不同:后者只认识一棵知识库树,而这里要把
90
- * `domain_knowledge`、`memory`、`intent`、`resource` 与 `tmp` 一起搬走。目标里已经有
90
+ * `domain_knowledge`、`memory`、`resource` 与 `tmp` 一起搬走。历史 `intent` 目录不再由插件
91
+ * 读取或迁移;如果它仍在旧根路径中,会阻止旧根目录被清空,保留原始数据供用户自行处理。
92
+ * 目标里已经有
91
93
  * 同名目录时逐层合并,任何同名文件都不覆盖,并把冲突留下来交给界面报告。
92
94
  */
93
95
  export function migrateLegacyAgentRoot(input: { agentRoot: string; legacyRoot: string }): MigrationOutcome {
@@ -19,7 +19,7 @@ export function buildOrganizeSystem(wikiKind: 'fact' | 'way' = 'fact'): string {
19
19
  return [
20
20
  '你在把一批已经抽好的知识组织成一张 Wiki 卡片。',
21
21
  '',
22
- `文件类型:${wikiKind === 'way' ? 'Wiki Way;同 Object + Action 的 Procedure' : 'Wiki Fact;同 Object 的 Fact'}。Scene 可以不同,必须保留每条的条件、状态与限制。`,
22
+ `文件类型:${wikiKind === 'way' ? 'Wiki Way;同一 Object × Action × Scene 坐标下的 Procedure' : 'Wiki Fact;同一 Object × Action × Scene 坐标下的 Fact'}。不得把不同坐标的内容合并。空坐标分量不表示通用,保留每条的条件、状态与限制。`,
23
23
  '这些条目是 Knowledge 真源。你不许新增、',
24
24
  '删除或改动它们说的事实。你能做的是:分小节、定顺序、把它们改写成读得下去的',
25
25
  '叙述、给卡片起一个自然的标题、写一句概述。',
@@ -33,6 +33,7 @@ export function buildOrganizeSystem(wikiKind: 'fact' | 'way' = 'fact'): string {
33
33
  '3. **每句都要挂引用。** 陈述事实的句子末尾挂 `[^知识id]`,可以挂多个。',
34
34
  ' 只有很短的导语(「这一节讲取数流程」)可以不挂。长句子不挂引用 = 没有来源的',
35
35
  ' 断言,整份方案会被打回。',
36
+ '涉及其他 Object 的定义或方法时,使用给定目标的双链,不把另一份 Wiki 的全文复制进来。无法唯一定位时保留对象原名,由程序补充导航,不编造链接或新坐标。',
36
37
  '4. **标题只做归纳,不要机械拼接。** 标题要能让人一眼知道卡片讲什么;不要照抄候选卡名,',
37
38
  ' 不要写成「对象的动作」「动作的动作」这类重复结构,不要加入知识里没有的新事实。',
38
39
  ' 保留区分这张卡所需的业务对象、字段名和动作词。知识条目附带的原文标题路径是定位线索,',
@@ -26,6 +26,7 @@ export interface PipelineHost {
26
26
  derive?(sourceIds: string[] | undefined, context: PipelineContext, force: boolean, output: (text: string) => void, checkpoint: () => Promise<void>): Promise<{ done: number; total: number; reused: number; summary: string }>
27
27
  groups(context: PipelineContext): Promise<MaterializationBatch>
28
28
  materialize(group: MaterializationGroup, context: PipelineContext, output: (text: string) => void, snapshot: unknown): Promise<void>
29
+ link?(): Promise<string>
29
30
  build(taskId: string, checkpoint: () => Promise<void>): Promise<PipelineBuildResult>
30
31
  record(checkpoint: ExtractionCheckpoint): Promise<void>
31
32
  }
@@ -186,10 +187,13 @@ export class KnowledgePipeline {
186
187
  * 「坐标有歧义」与「来源变了、抽取结果还没归一」是两件事,报同一句话会让读的人
187
188
  * 去查错的地方。更要紧的是范围:按 `sourceIds` / `groupKeys` 缩小的那一趟,
188
189
  * 如果拿全库的数字报 `partial`,调用方会去重试一件它明确排除的事 —— 而它其实
189
- * 全都做完了。坐标有歧义的那些行不属于任何分组,无法按来源归属,所以只在
190
- * 没有选择范围时才计入。
190
+ * 全都做完了。被阻断的 Knowledge 保留来源归属和可确定的分组键,因此也按
191
+ * 同一选择范围计数;尚无坐标的行只参与来源范围与全库统计。
191
192
  */
192
- const ambiguous = scoped ? 0 : batch.blockedAmbiguous
193
+ const ambiguous = scoped
194
+ ? (batch.blockedItems ?? []).filter(item => (!affectedSources || item.sourceIds.some(id => affectedSources.has(id)))
195
+ && (!selected || (item.groupKey !== undefined && selected.has(item.groupKey)))).length
196
+ : batch.blockedAmbiguous
193
197
  const awaiting = scoped
194
198
  ? groups.filter(group => group.state === 'blocked' && inScope(group)).reduce((sum, group) => sum + group.knowledgeCount, 0)
195
199
  : batch.blockedAwaitingNormalize
@@ -220,6 +224,8 @@ export class KnowledgePipeline {
220
224
  const current = this.store.task(id)!
221
225
  this.patch(id, { done: current.done + 1, summary: `已物化 ${current.done + 1}/${pending.length} 张:${group.title}` })
222
226
  }
227
+ await this.checkpoint(id)
228
+ if (this.host.link) this.store.event(id, 'output', await this.host.link(), undefined, stage)
223
229
  const current = this.store.task(id)!
224
230
  /**
225
231
  * 阶段结论要给 `summary`:任务列表的四段步轨读的是 `results[stage]`,
@@ -74,6 +74,8 @@ export interface MaterializationBatch {
74
74
  blocked: number
75
75
  blockedAmbiguous: number
76
76
  blockedAwaitingNormalize: number
77
+ /** Rows outside publishable groups still retain their source scope. */
78
+ blockedItems?: Array<{ knowledgeId: string; sourceIds: string[]; groupKey?: string }>
77
79
  snapshot: unknown
78
80
  }
79
81
 
package/src/present.ts CHANGED
@@ -13,7 +13,7 @@
13
13
  * 1. `presentationMeta` —— 结构化的小账本,随 `tool/result` 落进会话日志,
14
14
  * Web 端的卡片读它渲染(`src/client/KnowledgeToolRow.tsx`)。它必须
15
15
  * **可 JSON 序列化**(会话日志会整份校验),所以这里不塞函数、不塞 Date;
16
- * 2. `present*View` —— 与工具名无关的渲染意图(标题 / 分类 / 一段 Markdown),
16
+ * 2. `present*View` —— 与工具名无关的渲染参数(标题 / 分类 / 一段 Markdown),
17
17
  * 给终端界面和「没有专用卡片的界面」用。
18
18
  *
19
19
  * ## 一条规矩:数字必须来自真实的产物
package/src/preset-ids.ts CHANGED
@@ -1,6 +1,2 @@
1
1
  /** Preset ids persisted in DSH session headers. */
2
2
  export const STANDARD_PRESET_ID = 'standard'
3
-
4
- export function isIntentEnabledPreset(presetId: unknown): boolean {
5
- return presetId === STANDARD_PRESET_ID
6
- }
@@ -2,8 +2,6 @@ import type { AxisEntity, AxisKind, AxisRelation } from './axis-registry.js'
2
2
  import { normalizeAxisName } from './axis-registry.js'
3
3
  import type { CardCoordinate } from './types.js'
4
4
 
5
- export type QueryIntent = 'lookup' | 'explain' | 'procedure' | 'troubleshoot' | 'compare' | 'unknown'
6
-
7
5
  export interface QueryAxisMatch {
8
6
  id: string
9
7
  kind: AxisKind
@@ -30,7 +28,6 @@ export interface QueryRelationCandidate extends QueryCoordinateCandidate {
30
28
 
31
29
  export interface QueryAnalysis {
32
30
  query: string
33
- intent: { id: QueryIntent; confidence: number }
34
31
  axes: Record<AxisKind, QueryAxisMatch[]>
35
32
  coordinates: QueryCoordinateCandidate[]
36
33
  unresolved: string[]
@@ -39,22 +36,6 @@ export interface QueryAnalysis {
39
36
  type RegistryEntity = AxisEntity & { aliases: string[] }
40
37
  type CoordinateCard = { cardKey: string; coordinate?: CardCoordinate }
41
38
 
42
- const INTENT_RULES: Array<{ id: Exclude<QueryIntent, 'unknown'>; confidence: number; terms: string[] }> = [
43
- { id: 'troubleshoot', confidence: 0.9, terms: ['怎么排查', '如何排查', '异常', '报错', '失败', '原因', '为什么', '定位', '故障', '不工作'] },
44
- { id: 'procedure', confidence: 0.88, terms: ['怎么做', '如何做', '怎么', '如何', '步骤', '流程', '操作', '配置', '接入', '实现'] },
45
- { id: 'compare', confidence: 0.86, terms: ['区别', '差异', '对比', '比较', '哪个好', '不同点'] },
46
- { id: 'explain', confidence: 0.86, terms: ['什么是', '是什么', '定义', '含义', '解释', '指什么'] },
47
- { id: 'lookup', confidence: 0.78, terms: ['多少', '口径', '计算', '查询', '查看', '数据', '指标', '有哪些'] },
48
- ]
49
-
50
- function classifyIntent(query: string): QueryAnalysis['intent'] {
51
- const normalized = normalizeAxisName(query)
52
- for (const rule of INTENT_RULES) {
53
- if (rule.terms.some(term => normalized.includes(normalizeAxisName(term)))) return { id: rule.id, confidence: rule.confidence }
54
- }
55
- return { id: 'unknown', confidence: 0.35 }
56
- }
57
-
58
39
  function validMention(mention: string): boolean {
59
40
  const normalized = normalizeAxisName(mention)
60
41
  // 单字中文命中率很高,不能作为坐标证据;两个字符以上的中文或 ASCII 标识可以保留。
@@ -187,7 +168,6 @@ export function analyzeQuery(query: string, entities: RegistryEntity[], cards: C
187
168
  .filter(kind => axes[kind].length === 0)
188
169
  return {
189
170
  query,
190
- intent: classifyIntent(query),
191
171
  axes,
192
172
  coordinates: coordinateCandidates(axes, cards),
193
173
  unresolved,
@@ -0,0 +1,19 @@
1
+ import type { ContextItem, Envelope, RecallHit, RecallResult } from './types.js'
2
+
3
+ const compactHit = (hit: RecallHit) => ({ unitId: hit.unitId, entityId: hit.entityId, entityType: hit.entityType, title: hit.title,
4
+ ...(hit.heading ? { heading: hit.heading } : {}), score: hit.score,
5
+ ...(hit.rerankScore === undefined ? {} : { rerankScore: hit.rerankScore }) })
6
+
7
+ /** Section references explain retrieval; the complete body is already in item.wiki. */
8
+ export const agentContextItem = (item: ContextItem) => ({ ...item,
9
+ ...(item.note ? { note: compactHit(item.note) } : {}), notes: item.notes.map(compactHit),
10
+ })
11
+
12
+ /** Agent delivery carries each complete Wiki once, only inside the budgeted context. */
13
+ export function agentRecallEnvelope(value: Envelope<RecallResult>): Envelope<unknown> {
14
+ return { ...value, data: { ...value.data,
15
+ hits: value.data.hits.map(compactHit),
16
+ wiki: value.data.wiki.map(card => ({ entityId: card.entityId, entityType: card.entityType, title: card.title })),
17
+ context: value.data.context.map(agentContextItem),
18
+ } }
19
+ }