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.
- package/README.md +23 -16
- package/lib/client.js +596 -841
- package/lib/contract-refs.d.ts +0 -1
- package/lib/doc-page.js +7 -7
- package/lib/pages.js +928 -1145
- package/lib/types/agent-behavior-rules.d.ts.map +1 -1
- package/lib/types/agent-behavior-rules.js +1 -2
- package/lib/types/agent-behavior-rules.js.map +1 -1
- package/lib/types/axis-contract.js +1 -1
- package/lib/types/axis-contract.js.map +1 -1
- package/lib/types/card-organize.d.ts +2 -1
- package/lib/types/card-organize.d.ts.map +1 -1
- package/lib/types/card-organize.js +5 -3
- package/lib/types/card-organize.js.map +1 -1
- package/lib/types/config-schema.d.ts +1 -1
- package/lib/types/config-schema.js +1 -1
- package/lib/types/convert/host.d.ts +2 -3
- package/lib/types/convert/host.d.ts.map +1 -1
- package/lib/types/convert/host.js +5 -2
- package/lib/types/convert/host.js.map +1 -1
- package/lib/types/convert/ingest.d.ts +2 -0
- package/lib/types/convert/ingest.d.ts.map +1 -1
- package/lib/types/convert/ingest.js +1 -0
- package/lib/types/convert/ingest.js.map +1 -1
- package/lib/types/diagnosis/types.d.ts +1 -1
- package/lib/types/diagnosis/types.js +1 -1
- package/lib/types/images.js +1 -1
- package/lib/types/index.d.ts +0 -4
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/index.js +30 -41
- package/lib/types/index.js.map +1 -1
- package/lib/types/knowledge-contract.d.ts +6 -0
- package/lib/types/knowledge-contract.d.ts.map +1 -1
- package/lib/types/knowledge-contract.js +6 -2
- package/lib/types/knowledge-contract.js.map +1 -1
- package/lib/types/layout.d.ts +9 -26
- package/lib/types/layout.d.ts.map +1 -1
- package/lib/types/layout.js +10 -28
- package/lib/types/layout.js.map +1 -1
- package/lib/types/materialize-snapshot.d.ts +5 -0
- package/lib/types/materialize-snapshot.d.ts.map +1 -1
- package/lib/types/migrate.d.ts +3 -1
- package/lib/types/migrate.d.ts.map +1 -1
- package/lib/types/migrate.js +3 -1
- package/lib/types/migrate.js.map +1 -1
- package/lib/types/organize-contract.d.ts.map +1 -1
- package/lib/types/organize-contract.js +2 -1
- package/lib/types/organize-contract.js.map +1 -1
- package/lib/types/pipeline/engine.d.ts +1 -0
- package/lib/types/pipeline/engine.d.ts.map +1 -1
- package/lib/types/pipeline/engine.js +9 -3
- package/lib/types/pipeline/engine.js.map +1 -1
- package/lib/types/pipeline/types.d.ts +6 -0
- package/lib/types/pipeline/types.d.ts.map +1 -1
- package/lib/types/pipeline/types.js.map +1 -1
- package/lib/types/present.d.ts +1 -1
- package/lib/types/present.js +1 -1
- package/lib/types/preset-ids.d.ts +0 -1
- package/lib/types/preset-ids.d.ts.map +1 -1
- package/lib/types/preset-ids.js +0 -3
- package/lib/types/preset-ids.js.map +1 -1
- package/lib/types/query-analysis.d.ts +0 -5
- package/lib/types/query-analysis.d.ts.map +1 -1
- package/lib/types/query-analysis.js +0 -16
- package/lib/types/query-analysis.js.map +1 -1
- package/lib/types/recall-delivery.d.ts +36 -0
- package/lib/types/recall-delivery.d.ts.map +1 -0
- package/lib/types/recall-delivery.js +16 -0
- package/lib/types/recall-delivery.js.map +1 -0
- package/lib/types/runtime.d.ts +26 -12
- package/lib/types/runtime.d.ts.map +1 -1
- package/lib/types/runtime.js +231 -106
- package/lib/types/runtime.js.map +1 -1
- package/lib/types/settings-volatile.d.ts +0 -7
- package/lib/types/settings-volatile.d.ts.map +1 -1
- package/lib/types/settings-volatile.js +0 -7
- package/lib/types/settings-volatile.js.map +1 -1
- package/lib/types/source-identity.d.ts +3 -0
- package/lib/types/source-identity.d.ts.map +1 -0
- package/lib/types/source-identity.js +5 -0
- package/lib/types/source-identity.js.map +1 -0
- package/lib/types/store/axis-references.d.ts.map +1 -1
- package/lib/types/store/axis-references.js +5 -3
- package/lib/types/store/axis-references.js.map +1 -1
- package/lib/types/store/knowledge-db.d.ts +1 -1
- package/lib/types/store/knowledge-db.d.ts.map +1 -1
- package/lib/types/store/knowledge-db.js +16 -2
- package/lib/types/store/knowledge-db.js.map +1 -1
- package/lib/types/types.d.ts +5 -4
- package/lib/types/types.d.ts.map +1 -1
- package/lib/types/types.js +6 -3
- package/lib/types/types.js.map +1 -1
- package/lib/types/wiki-availability.d.ts +11 -0
- package/lib/types/wiki-availability.d.ts.map +1 -0
- package/lib/types/wiki-availability.js +39 -0
- package/lib/types/wiki-availability.js.map +1 -0
- package/lib/types/wiki-finalize.d.ts +4 -2
- package/lib/types/wiki-finalize.d.ts.map +1 -1
- package/lib/types/wiki-finalize.js +9 -27
- package/lib/types/wiki-finalize.js.map +1 -1
- package/lib/types/wiki-links.d.ts +35 -0
- package/lib/types/wiki-links.d.ts.map +1 -0
- package/lib/types/wiki-links.js +129 -0
- package/lib/types/wiki-links.js.map +1 -0
- package/package.json +16 -16
- package/scripts/doctor.mjs +0 -7
- package/scripts/setup-embedding.sh +0 -0
- package/src/agent-behavior-rules.ts +1 -2
- package/src/axis-contract.ts +1 -1
- package/src/card-organize.ts +5 -3
- package/src/client/AttributionEventGuide.tsx +3 -3
- package/src/client/AxisMatrix.tsx +86 -19
- package/src/client/DirectoryPicker.tsx +0 -2
- package/src/client/GuideArchitectureCanvas.tsx +5 -12
- package/src/client/ImportFilesDialog.tsx +1 -0
- package/src/client/InfoHint.tsx +1 -1
- package/src/client/KnowledgeBaseTab.tsx +113 -39
- package/src/client/KnowledgePanel.tsx +16 -9
- package/src/client/OperationLogTab.tsx +1 -1
- package/src/client/RecallPanel.tsx +5 -16
- package/src/client/TabGuide.tsx +3 -7
- package/src/client/WikiFlowPanel.tsx +10 -11
- package/src/client/arch/NodeLogicPanel.tsx +3 -3
- package/src/client/arch/model.ts +5 -113
- package/src/client/architecture.css +1 -1
- package/src/client/architecture.tsx +13 -27
- package/src/client/attribution/AttributionTab.tsx +141 -10
- package/src/client/pages.css +2 -2
- package/src/client/pages.tsx +4 -11
- package/src/client/styles.css +15 -96
- package/src/config-schema.ts +1 -1
- package/src/convert/host.ts +7 -5
- package/src/convert/ingest.ts +3 -0
- package/src/diagnosis/types.ts +1 -1
- package/src/images.ts +1 -1
- package/src/index.ts +27 -49
- package/src/knowledge-contract.ts +7 -2
- package/src/layout.ts +10 -32
- package/src/materialize-snapshot.ts +1 -0
- package/src/migrate.ts +3 -1
- package/src/organize-contract.ts +2 -1
- package/src/pipeline/engine.ts +9 -3
- package/src/pipeline/types.ts +2 -0
- package/src/present.ts +1 -1
- package/src/preset-ids.ts +0 -4
- package/src/query-analysis.ts +0 -20
- package/src/recall-delivery.ts +19 -0
- package/src/runtime.ts +220 -102
- package/src/settings-volatile.ts +0 -7
- package/src/source-identity.ts +4 -0
- package/src/store/axis-references.ts +5 -3
- package/src/store/knowledge-db.ts +14 -2
- package/src/types.ts +6 -4
- package/src/wiki-availability.ts +37 -0
- package/src/wiki-finalize.ts +9 -25
- package/src/wiki-links.ts +120 -0
- package/lib/types/intent/engine.d.ts +0 -122
- package/lib/types/intent/engine.d.ts.map +0 -1
- package/lib/types/intent/engine.js +0 -488
- package/lib/types/intent/engine.js.map +0 -1
- package/lib/types/intent/host.d.ts +0 -68
- package/lib/types/intent/host.d.ts.map +0 -1
- package/lib/types/intent/host.js +0 -249
- package/lib/types/intent/host.js.map +0 -1
- package/lib/types/intent/scope.d.ts +0 -25
- package/lib/types/intent/scope.d.ts.map +0 -1
- package/lib/types/intent/scope.js +0 -116
- package/lib/types/intent/scope.js.map +0 -1
- package/lib/types/intent/store.d.ts +0 -33
- package/lib/types/intent/store.d.ts.map +0 -1
- package/lib/types/intent/store.js +0 -239
- package/lib/types/intent/store.js.map +0 -1
- package/lib/types/intent/tools.d.ts +0 -62
- package/lib/types/intent/tools.d.ts.map +0 -1
- package/lib/types/intent/tools.js +0 -130
- package/lib/types/intent/tools.js.map +0 -1
- package/lib/types/intent/types.d.ts +0 -170
- package/lib/types/intent/types.d.ts.map +0 -1
- package/lib/types/intent/types.js +0 -56
- package/lib/types/intent/types.js.map +0 -1
- package/src/client/IntentLogic.tsx +0 -192
- package/src/client/IntentTab.tsx +0 -343
- package/src/intent/README.md +0 -42
- package/src/intent/engine.ts +0 -515
- package/src/intent/host.ts +0 -315
- package/src/intent/scope.ts +0 -125
- package/src/intent/store.ts +0 -218
- package/src/intent/tools.ts +0 -154
- 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,
|
|
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`
|
|
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'], ['
|
|
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
|
-
*
|
|
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
|
-
*
|
|
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
|
-
*
|
|
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] === '
|
|
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
|
|
22
|
-
return {
|
|
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 在磁盘上的布局(
|
|
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.
|
|
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
|
|
125
|
-
*
|
|
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', '
|
|
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
|
-
*
|
|
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
|
|
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`、`
|
|
90
|
+
* `domain_knowledge`、`memory`、`resource` 与 `tmp` 一起搬走。历史 `intent` 目录不再由插件
|
|
91
|
+
* 读取或迁移;如果它仍在旧根路径中,会阻止旧根目录被清空,保留原始数据供用户自行处理。
|
|
92
|
+
* 目标里已经有
|
|
91
93
|
* 同名目录时逐层合并,任何同名文件都不覆盖,并把冲突留下来交给界面报告。
|
|
92
94
|
*/
|
|
93
95
|
export function migrateLegacyAgentRoot(input: { agentRoot: string; legacyRoot: string }): MigrationOutcome {
|
package/src/organize-contract.ts
CHANGED
|
@@ -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
|
|
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
|
' 保留区分这张卡所需的业务对象、字段名和动作词。知识条目附带的原文标题路径是定位线索,',
|
package/src/pipeline/engine.ts
CHANGED
|
@@ -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
|
|
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]`,
|
package/src/pipeline/types.ts
CHANGED
|
@@ -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` ——
|
|
16
|
+
* 2. `present*View` —— 与工具名无关的渲染参数(标题 / 分类 / 一段 Markdown),
|
|
17
17
|
* 给终端界面和「没有专用卡片的界面」用。
|
|
18
18
|
*
|
|
19
19
|
* ## 一条规矩:数字必须来自真实的产物
|
package/src/preset-ids.ts
CHANGED
package/src/query-analysis.ts
CHANGED
|
@@ -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
|
+
}
|