dsh-data-domain-knowledge 0.1.1-alpha.2 → 0.1.1-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 +33 -16
- package/lib/client.js +1042 -2097
- package/lib/contract-refs.d.ts +0 -1
- package/lib/doc-page.js +1 -1
- package/lib/pages.js +2489 -1060
- package/lib/types/agent-behavior-rules.d.ts.map +1 -1
- package/lib/types/agent-behavior-rules.js +3 -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 +11 -2
- package/lib/types/convert/host.js.map +1 -1
- package/lib/types/convert/ingest.d.ts +14 -20
- package/lib/types/convert/ingest.d.ts.map +1 -1
- package/lib/types/convert/ingest.js +8 -5
- package/lib/types/convert/ingest.js.map +1 -1
- package/lib/types/diagnosis/store.d.ts +2 -2
- package/lib/types/diagnosis/store.d.ts.map +1 -1
- package/lib/types/diagnosis/store.js +10 -2
- package/lib/types/diagnosis/store.js.map +1 -1
- package/lib/types/diagnosis/types.d.ts +1 -1
- package/lib/types/diagnosis/types.js +1 -1
- package/lib/types/extract-model.d.ts +3 -0
- package/lib/types/extract-model.d.ts.map +1 -1
- package/lib/types/extract-model.js.map +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 +99 -91
- package/lib/types/index.js.map +1 -1
- package/lib/types/knowledge-bases.d.ts +3 -0
- package/lib/types/knowledge-bases.d.ts.map +1 -1
- package/lib/types/knowledge-bases.js +22 -2
- package/lib/types/knowledge-bases.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/model-text.d.ts +7 -0
- package/lib/types/model-text.d.ts.map +1 -1
- package/lib/types/model-text.js +31 -9
- package/lib/types/model-text.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 +28 -4
- package/lib/types/pipeline/engine.d.ts.map +1 -1
- package/lib/types/pipeline/engine.js +68 -15
- package/lib/types/pipeline/engine.js.map +1 -1
- package/lib/types/pipeline/progress.d.ts +12 -0
- package/lib/types/pipeline/progress.d.ts.map +1 -0
- package/lib/types/pipeline/progress.js +37 -0
- package/lib/types/pipeline/progress.js.map +1 -0
- package/lib/types/pipeline/resumable-extract.d.ts +45 -0
- package/lib/types/pipeline/resumable-extract.d.ts.map +1 -0
- package/lib/types/pipeline/resumable-extract.js +262 -0
- package/lib/types/pipeline/resumable-extract.js.map +1 -0
- package/lib/types/pipeline/store.d.ts +8 -2
- package/lib/types/pipeline/store.d.ts.map +1 -1
- package/lib/types/pipeline/store.js +27 -5
- package/lib/types/pipeline/store.js.map +1 -1
- package/lib/types/pipeline/types.d.ts +56 -0
- package/lib/types/pipeline/types.d.ts.map +1 -1
- package/lib/types/pipeline/types.js +18 -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/retrieval/scope.d.ts +17 -0
- package/lib/types/retrieval/scope.d.ts.map +1 -0
- package/lib/types/retrieval/scope.js +11 -0
- package/lib/types/retrieval/scope.js.map +1 -0
- package/lib/types/runtime.d.ts +75 -14
- package/lib/types/runtime.d.ts.map +1 -1
- package/lib/types/runtime.js +454 -198
- 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 +34 -0
- package/lib/types/source-identity.d.ts.map +1 -0
- package/lib/types/source-identity.js +85 -0
- package/lib/types/source-identity.js.map +1 -0
- package/lib/types/source-read.d.ts +18 -0
- package/lib/types/source-read.d.ts.map +1 -0
- package/lib/types/source-read.js +49 -0
- package/lib/types/source-read.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 +5 -29
- package/lib/types/store/knowledge-db.d.ts.map +1 -1
- package/lib/types/store/knowledge-db.js +57 -2
- package/lib/types/store/knowledge-db.js.map +1 -1
- package/lib/types/store/source-identity.d.ts +8 -0
- package/lib/types/store/source-identity.d.ts.map +1 -0
- package/lib/types/store/source-identity.js +56 -0
- package/lib/types/store/source-identity.js.map +1 -0
- package/lib/types/types.d.ts +46 -5
- 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/lib/types/wiki-trial-types.d.ts +3 -0
- package/lib/types/wiki-trial-types.d.ts.map +1 -1
- package/lib/types/wiki-trial.d.ts +3 -3
- package/lib/types/wiki-trial.d.ts.map +1 -1
- package/lib/types/wiki-trial.js +14 -3
- package/lib/types/wiki-trial.js.map +1 -1
- package/package.json +16 -16
- package/scripts/doctor.mjs +0 -7
- package/scripts/setup-embedding.sh +0 -0
- package/src/agent-behavior-rules.ts +3 -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/AxisRegistrySection.tsx +1 -1
- package/src/client/CompileSettingsView.tsx +473 -0
- package/src/client/DirectoryPicker.tsx +0 -2
- package/src/client/ExtractionTasksPage.tsx +557 -423
- 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 +141 -148
- package/src/client/KnowledgePanel.tsx +16 -9
- package/src/client/OperationLogTab.tsx +1 -1
- package/src/client/PipelineRunView.tsx +173 -0
- 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 +305 -180
- package/src/client/pages.tsx +7 -12
- package/src/client/styles.css +15 -96
- package/src/config-schema.ts +1 -1
- package/src/convert/host.ts +13 -5
- package/src/convert/ingest.ts +20 -7
- package/src/diagnosis/store.ts +7 -2
- package/src/diagnosis/types.ts +1 -1
- package/src/extract-model.ts +3 -0
- package/src/images.ts +1 -1
- package/src/index.ts +92 -97
- package/src/knowledge-bases.ts +23 -3
- 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/model-text.ts +33 -11
- package/src/organize-contract.ts +2 -1
- package/src/pipeline/engine.ts +85 -22
- package/src/pipeline/progress.ts +40 -0
- package/src/pipeline/resumable-extract.ts +233 -0
- package/src/pipeline/store.ts +28 -6
- package/src/pipeline/types.ts +47 -2
- 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/retrieval/scope.ts +10 -0
- package/src/runtime.ts +412 -206
- package/src/settings-volatile.ts +0 -7
- package/src/source-identity.ts +85 -0
- package/src/source-read.ts +47 -0
- package/src/store/axis-references.ts +5 -3
- package/src/store/knowledge-db.ts +54 -2
- package/src/store/source-identity.ts +42 -0
- package/src/types.ts +18 -5
- package/src/wiki-availability.ts +37 -0
- package/src/wiki-finalize.ts +9 -25
- package/src/wiki-links.ts +120 -0
- package/src/wiki-trial-types.ts +3 -2
- package/src/wiki-trial.ts +17 -6
- 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/client/TypeDefinitionDrawer.tsx +0 -195
- 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/lib/types/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { newSourceId } from './source-identity.js';
|
|
1
2
|
import { embeddingModel } from './environment/model-catalog.js';
|
|
2
3
|
import { createReadStream } from 'node:fs';
|
|
3
4
|
import { readFile, stat } from 'node:fs/promises';
|
|
@@ -14,21 +15,17 @@ import { KnowledgeEnvironment } from './environment/service.js';
|
|
|
14
15
|
import { DOC_PAGE_CHARS, DOC_PAGE_CHARS_MAX, documentContentPage } from './document-page.js';
|
|
15
16
|
import { runWikiTrial, trialSummary } from './wiki-trial.js';
|
|
16
17
|
import { extractionRunId } from './extraction-runs.js';
|
|
17
|
-
import {
|
|
18
|
+
import { DEFAULT_EXTRACTION_TIMEOUT_MINUTES, PIPELINE_ACTIVE_STATES, isExtractionTimeoutMinutes } from './pipeline/types.js';
|
|
19
|
+
import { agentLayout, defaultAgentRoot, ensureAgentLayout, knowledgeBaseRoot, memoryRoot, resourceRegistry, resourceRoot, } from './layout.js';
|
|
18
20
|
import { PickerError, createDirectory, listDirectory, pickDirectory, pickerKind, pickerOf, } from './directory-picker.js';
|
|
19
21
|
import { KNOWLEDGE_SETTINGS_SCHEMA, SETTINGS_NAMESPACE } from './settings-schema.js';
|
|
20
22
|
import { DEFAULT_KB_ID, KnowledgeBases } from './knowledge-bases.js';
|
|
21
23
|
import { ImagePublishError, publishKnowledgeImage } from './images.js';
|
|
22
24
|
import { applyConvert, CONVERT_SETTINGS_NAMESPACE, CONVERT_SETTINGS_SCHEMA, MOUNT_PATH as CONVERT_MOUNT_PATH, } from './convert/host.js';
|
|
23
|
-
import { applyIntent, INTENT_MOUNT_PATH, INTENT_SERVICE, } from './intent/host.js';
|
|
24
|
-
import { registerIntentTools } from './intent/tools.js';
|
|
25
25
|
export * from './types.js';
|
|
26
26
|
export * from './runtime.js';
|
|
27
27
|
export * from './knowledge-bases.js';
|
|
28
|
-
export * from './intent/types.js';
|
|
29
|
-
export * from './intent/engine.js';
|
|
30
28
|
export { applyConvert as applyConvertHost, CONVERT_SETTINGS_NAMESPACE, CONVERT_MOUNT_PATH };
|
|
31
|
-
export { applyIntent as applyIntentHost, INTENT_MOUNT_PATH, INTENT_SERVICE };
|
|
32
29
|
export const name = 'dsh-data-domain-knowledge';
|
|
33
30
|
/**
|
|
34
31
|
* `settings` 在 0.1.7 之后**不再需要**:设置已经是本 entry 的 config
|
|
@@ -51,6 +48,7 @@ export { CONVERT_SETTINGS_SCHEMA };
|
|
|
51
48
|
*/
|
|
52
49
|
import { Config } from './config-schema.js';
|
|
53
50
|
import { buildModelRequest, callModelWithRetry, collectModelText } from './model-text.js';
|
|
51
|
+
import { agentRecallEnvelope } from './recall-delivery.js';
|
|
54
52
|
import { addSourceCallView, addSourceMetaOf, addSourceResultMarkdown, importCallView, importMetaOf, importResultMarkdown, recallCallView, recallMetaOf, recallResultMarkdown, rebuildCallView, rebuildMetaOf, rebuildResultMarkdown, writeCardsCallView, writeCardsMetaOf, writeCardsResultMarkdown, } from './present.js';
|
|
55
53
|
export { Config };
|
|
56
54
|
/**
|
|
@@ -137,7 +135,7 @@ function lineageOf(args, exec) {
|
|
|
137
135
|
if (sessionId)
|
|
138
136
|
lineage.sessionId = sessionId;
|
|
139
137
|
const fields = [
|
|
140
|
-
['turnId', 'turn_id'], ['
|
|
138
|
+
['turnId', 'turn_id'], ['taskId', 'task_id'],
|
|
141
139
|
['subtaskId', 'subtask_id'], ['parentSubtaskId', 'parent_subtask_id'], ['runId', 'run_id'], ['traceId', 'trace_id'], ['domain', 'domain'],
|
|
142
140
|
];
|
|
143
141
|
for (const [target, source] of fields)
|
|
@@ -149,7 +147,6 @@ function lineageFromUrl(url) {
|
|
|
149
147
|
return lineageOf({
|
|
150
148
|
session_key: url.searchParams.get('session_key') ?? undefined,
|
|
151
149
|
turn_id: url.searchParams.get('turn_id') ?? undefined,
|
|
152
|
-
intent_id: url.searchParams.get('intent_id') ?? undefined,
|
|
153
150
|
task_id: url.searchParams.get('task_id') ?? undefined,
|
|
154
151
|
subtask_id: url.searchParams.get('subtask_id') ?? undefined,
|
|
155
152
|
parent_subtask_id: url.searchParams.get('parent_subtask_id') ?? undefined,
|
|
@@ -335,8 +332,7 @@ export function apply(ctx, pluginConfig = {}) {
|
|
|
335
332
|
/**
|
|
336
333
|
* 这两组的把手,`loader/volatile-update` 时调 `reprocess()` 按新值重灌。
|
|
337
334
|
*
|
|
338
|
-
*
|
|
339
|
-
* `applyIntent`)。
|
|
335
|
+
* 先声明后赋值:事件只在运行时触发,转换宿主在下面的 `applyConvert` 中装配。
|
|
340
336
|
*/
|
|
341
337
|
let convertHost;
|
|
342
338
|
/**
|
|
@@ -361,6 +357,7 @@ export function apply(ctx, pluginConfig = {}) {
|
|
|
361
357
|
*/
|
|
362
358
|
/** 注册表在默认 runtime 之后才构造;用一个可替换的读取器避开构造期 TDZ。 */
|
|
363
359
|
let compileModelForBase = () => ({ ...DEFAULT_COMPILE_MODEL });
|
|
360
|
+
let extractionTimeoutForBase = () => DEFAULT_EXTRACTION_TIMEOUT_MINUTES;
|
|
364
361
|
const modelSeamFor = (kbId = DEFAULT_KB_ID) => {
|
|
365
362
|
/**
|
|
366
363
|
* **只能用 `ctx.get(name)`,不能用属性访问。**
|
|
@@ -411,7 +408,9 @@ export function apply(ctx, pluginConfig = {}) {
|
|
|
411
408
|
provider,
|
|
412
409
|
model,
|
|
413
410
|
...(effectiveReasoningEffort ? { reasoningEffort: effectiveReasoningEffort } : {}),
|
|
414
|
-
|
|
411
|
+
...(configured.maxTokens !== undefined ? { maxTokens: configured.maxTokens } : {}),
|
|
412
|
+
call: async ({ system, prompt, sessionId, onUsage, onDelta, signal, retryAttempts, maxTokens }) => {
|
|
413
|
+
const outputLimit = maxTokens ?? configured.maxTokens;
|
|
415
414
|
/**
|
|
416
415
|
* 先走 DSH 的公开解析接口,再开始发 prompt。这样固定模型过期、默认模型失效时,
|
|
417
416
|
* 编译会在模型调用边界明确失败,而不是落成一次看似成功的规则抽取。
|
|
@@ -421,6 +420,7 @@ export function apply(ctx, pluginConfig = {}) {
|
|
|
421
420
|
await llm.resolveCallConfig({
|
|
422
421
|
provider, model,
|
|
423
422
|
...(effectiveReasoningEffort ? { reasoningEffort: effectiveReasoningEffort } : {}),
|
|
423
|
+
...(outputLimit !== undefined ? { maxTokens: outputLimit } : {}),
|
|
424
424
|
});
|
|
425
425
|
}
|
|
426
426
|
catch (cause) {
|
|
@@ -438,7 +438,7 @@ export function apply(ctx, pluginConfig = {}) {
|
|
|
438
438
|
* (OpenCode 系路由回 400 `MissingSessionID`)。
|
|
439
439
|
*/
|
|
440
440
|
const request = buildModelRequest({
|
|
441
|
-
provider, model, reasoningEffort: effectiveReasoningEffort, system, prompt,
|
|
441
|
+
provider, model, reasoningEffort: effectiveReasoningEffort, maxTokens: outputLimit, system, prompt,
|
|
442
442
|
// 运行时按知识库给;接缝被单独调用时(测试)退回一个稳定值,
|
|
443
443
|
// 而不是留空 —— 留空会在 OpenCode 路由上 400。
|
|
444
444
|
sessionId: sessionId ?? 'knowledge:default',
|
|
@@ -456,12 +456,13 @@ export function apply(ctx, pluginConfig = {}) {
|
|
|
456
456
|
* 所以缓存亲和仍然成立。不可重试的错误(凭据、请求体、截断、用户取消)
|
|
457
457
|
* 由 `isRetryableModelFailure` 放行,不在错的地方多等两分钟。
|
|
458
458
|
*/
|
|
459
|
-
return callModelWithRetry(onDeltaOfAttempt => collectModelText(llm.stream(request), onUsage, onDeltaOfAttempt), { ...(onDelta ? { onDelta } : {}) });
|
|
459
|
+
return callModelWithRetry(onDeltaOfAttempt => collectModelText(llm.stream({ ...request, ...(signal ? { signal } : {}) }), onUsage, onDeltaOfAttempt), { ...(onDelta ? { onDelta } : {}), attempts: retryAttempts, signal });
|
|
460
460
|
},
|
|
461
461
|
};
|
|
462
462
|
};
|
|
463
463
|
let environment;
|
|
464
464
|
const runtimeOptions = () => ({
|
|
465
|
+
extractionTimeoutMinutes: () => extractionTimeoutForBase(DEFAULT_KB_ID),
|
|
465
466
|
environmentGuard: kind => environment.requireReady(kind),
|
|
466
467
|
// 0029:家当目录。配置里三个路径为空时,运行时从这里解析模型与解释器。
|
|
467
468
|
resourceRoot: resourceRoot(config.agentRoot),
|
|
@@ -501,6 +502,7 @@ export function apply(ctx, pluginConfig = {}) {
|
|
|
501
502
|
runtimeOptions: () => ({ resourceRoot: resourceRoot(config.agentRoot), modelSeam: modelSeamFor, environmentGuard: kind => environment.requireReady(kind) }),
|
|
502
503
|
});
|
|
503
504
|
compileModelForBase = id => bases.compileModelOf(id);
|
|
505
|
+
extractionTimeoutForBase = id => bases.extractionTimeoutMinutesOf(id);
|
|
504
506
|
runtime.baseId = bases.defaultId;
|
|
505
507
|
activeKnowledgeBases = bases;
|
|
506
508
|
environment = new KnowledgeEnvironment({
|
|
@@ -587,7 +589,10 @@ export function apply(ctx, pluginConfig = {}) {
|
|
|
587
589
|
const item = models.find(model => model.provider === requestedProvider && model.id === requestedModel);
|
|
588
590
|
if (item) {
|
|
589
591
|
try {
|
|
590
|
-
|
|
592
|
+
const info = await llm.resolveModelInfo(requestedProvider, requestedModel);
|
|
593
|
+
item.reasoning = info.reasoning;
|
|
594
|
+
if (info.defaultMaxTokens !== undefined)
|
|
595
|
+
item.defaultMaxTokens = info.defaultMaxTokens;
|
|
591
596
|
}
|
|
592
597
|
catch (cause) {
|
|
593
598
|
failures.push(`思考强度目录:${cause instanceof Error ? cause.message : String(cause)}`);
|
|
@@ -725,7 +730,7 @@ export function apply(ctx, pluginConfig = {}) {
|
|
|
725
730
|
/**
|
|
726
731
|
* 交付物落在**工作项目**下:`<工作区>/output/<日期>/`,不是 Agent 根路径。
|
|
727
732
|
*
|
|
728
|
-
*
|
|
733
|
+
* 根路径下的几段(知识 / 记忆 / 家当)是**这个 Agent 自己的东西**,跨项目
|
|
729
734
|
* 累积;交付物是**某个项目的产物**,换一个项目打开就不该再看见。两者判据不同,
|
|
730
735
|
* 所以落点也不同。
|
|
731
736
|
*
|
|
@@ -745,26 +750,6 @@ export function apply(ctx, pluginConfig = {}) {
|
|
|
745
750
|
return target ? { runtime: target, knowledgeRoot: target.rootDir } : undefined;
|
|
746
751
|
},
|
|
747
752
|
});
|
|
748
|
-
// 意图记录模块 (issue 0020). The 意图 view was already one of this plugin's
|
|
749
|
-
// five panel tabs, but its Host lived in a second mount unit; 0020 folds it in
|
|
750
|
-
// so the declared information architecture and the code layout agree again.
|
|
751
|
-
// It keeps the `intent_record` / `intent_store_view` tools and `/intent/**` audit endpoints,
|
|
752
|
-
// and — critically — the `titaDataAgentIntent` Cordis service that `data-table`
|
|
753
|
-
// resolves by name.
|
|
754
|
-
// 意图只保留固定的会话审计契约;可编辑词表不再属于插件配置。
|
|
755
|
-
applyIntent(ctx, {
|
|
756
|
-
intentRoot: () => intentRoot(config.agentRoot),
|
|
757
|
-
});
|
|
758
|
-
// `applyIntent` provides this service from the same plugin fiber. During
|
|
759
|
-
// `apply()`, that fiber is still starting, so Cordis's default strict lookup
|
|
760
|
-
// hides the just-provided service until startup completes. The non-strict
|
|
761
|
-
// lookup is safe here because `applyIntent` ran immediately above.
|
|
762
|
-
const intentService = ctx.get(INTENT_SERVICE, false);
|
|
763
|
-
/**
|
|
764
|
-
* `intent_*` 工具在 Host 层注册,使标准模式可以调用它们;工具执行端只接受
|
|
765
|
-
* standard 会话,其他 preset 不会写入或读取意图记录。
|
|
766
|
-
*/
|
|
767
|
-
ctx.effect(() => registerIntentTools(ctx, intentService), 'tita knowledge: global intent tools');
|
|
768
753
|
/**
|
|
769
754
|
* 规则正文由当前会话 preset 决定;设置里的 volatile 引用在每次组装提示词时解包,
|
|
770
755
|
* 因此开关保存后立即生效,不需要重建 Agent 会话。
|
|
@@ -806,50 +791,39 @@ export function apply(ctx, pluginConfig = {}) {
|
|
|
806
791
|
return Promise.resolve({ kind: 'ask', reason: '该操作会写入 Tita Knowledge Store,需要本轮用户审批。' });
|
|
807
792
|
return next();
|
|
808
793
|
});
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
794
|
+
const scopeParameters = { object_id: { type: 'string', description: 'Known Object ID. Omit for all; empty matches empty only.' }, action_id: { type: 'string' }, scene_id: { type: 'string' } };
|
|
795
|
+
const scopeOf = (args) => ({ objectId: args.object_id, actionId: args.action_id, sceneId: args.scene_id, wikiKind: args.wiki_kind });
|
|
796
|
+
ctx.tools.register(tool('recall_knowledge', 'Search H2 sections, rank and deduplicate Wiki files, then deliver complete Wiki Fact / Wiki Way within the budget. Query the current subquestion for methods. top_k counts distinct Wiki candidates; top_n counts delivered hit files. Optional known coordinate IDs and wiki_kind filter every retrieval route before ranking. foundCandidates and contentDelivered distinguish matches from delivered bodies. For budget omissions call read_knowledge_wiki with budget.omitted[].read.args. Scores indicate retrieval relevance, not factual truth. Historical Case does not prove the present root cause.', {
|
|
797
|
+
query: { type: 'string', required: true }, ...scopeParameters, wiki_kind: { type: 'string', enum: ['fact', 'way'] },
|
|
798
|
+
limit: { type: 'integer', description: 'Compatibility alias for top_k.' }, top_k: { type: 'integer', description: 'Distinct Wiki candidates, 1–50.' }, top_n: { type: 'integer', description: 'Maximum complete hit Wiki files to deliver, no more than top_k.' },
|
|
799
|
+
rerank: { type: 'boolean' }, context_max_chars: { type: 'integer', description: 'Complete-context character budget; 0 explicitly disables the limit. Omitted files have stable read references in budget.omitted. overflowPath is a local diagnostic file, not the Agent continuation contract.' },
|
|
800
|
+
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' },
|
|
801
|
+
}, 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, lineageOf(args, exec), { ...scopeOf(args), contextTopN: args.top_n, rerank: args.rerank, contextMaxChars: args.context_max_chars }))), {
|
|
802
|
+
call: recallCallView, meta: (args, value) => recallMetaOf({ ...dataOf(value), query: args?.query }), result: resultViewOf(recallResultMarkdown),
|
|
814
803
|
}));
|
|
815
|
-
ctx.tools.register(tool('
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
return failure({ cases: [], missing_ids: [] }, 'CASE_IDS_REQUIRED', '请传入 Wiki 的 case_refs 中的 Case ID。', false);
|
|
825
|
-
if (ids.length > 50)
|
|
826
|
-
return failure({ cases: [], missing_ids: [] }, 'CASE_IDS_LIMIT', '一次最多读取 50 个 Case ID。', false);
|
|
827
|
-
if (args.version !== undefined && (ids.length !== 1 || !Number.isInteger(args.version) || args.version < 1))
|
|
828
|
-
return failure({ cases: [], missing_ids: ids }, 'CASE_VERSION_INVALID', '读取历史版本时,请传一个 Case ID 和正整数 version。', false);
|
|
829
|
-
const records = await Promise.all(ids.map(id => target.readCase(id, args.version)));
|
|
830
|
-
return success({ cases: records.filter(record => record !== undefined), missing_ids: ids.filter((_, index) => records[index] === undefined) });
|
|
831
|
-
})));
|
|
832
|
-
ctx.tools.register(tool('get_knowledge_events', 'Read Event records referenced by recalled WikiCards. Pass event IDs from card metadata.event_refs; the result includes full timelines, evidence, outcomes, and missing fields.', {
|
|
833
|
-
event_ids: { type: 'array', required: true, description: 'Event IDs from WikiCard metadata.event_refs; maximum 50 IDs.' },
|
|
834
|
-
kb: { type: 'string' }, session_key: { type: 'string' }, task_id: { type: 'string' }, subtask_id: { type: 'string' },
|
|
835
|
-
run_id: { type: 'string' }, turn_id: { type: 'string' }, trace_id: { type: 'string' }, domain: { type: 'string' },
|
|
836
|
-
}, async (args) => withRuntime(args.kb, async (target) => {
|
|
837
|
-
const ids = [...new Set((Array.isArray(args.event_ids) ? args.event_ids : [])
|
|
838
|
-
.filter((id) => typeof id === 'string' && id.trim() !== '').map(id => id.trim()))];
|
|
839
|
-
if (ids.length === 0)
|
|
840
|
-
return failure({ events: [], missing_ids: [] }, 'EVENT_IDS_REQUIRED', '请传入 WikiCard 的 event_refs 中的 Event ID。', false);
|
|
841
|
-
if (ids.length > 50)
|
|
842
|
-
return failure({ events: [], missing_ids: [] }, 'EVENT_IDS_LIMIT', '一次最多读取 50 个 Event ID;请分批读取该 WikiCard 的 event_refs。', false);
|
|
843
|
-
const byId = new Map((await target.loadEvents()).map(event => [event.id, event]));
|
|
844
|
-
const events = ids.flatMap(id => {
|
|
845
|
-
const event = byId.get(id);
|
|
846
|
-
return event ? [event] : [];
|
|
847
|
-
});
|
|
848
|
-
return success({ events, missing_ids: ids.filter(id => !byId.has(id)) });
|
|
849
|
-
})));
|
|
804
|
+
ctx.tools.register(tool('read_knowledge_wiki', 'Read a complete Wiki through a stable target or browse an Object directory. Omitted axes mean all; empty axes mean empty only. Directory mode omits content by default. include_content requests complete files within max_chars. If a file does not fit, follow nextRead for explicit body pages, concatenate them and read all conditions before applying a Procedure. expected_version prevents mixing Wiki versions. contentPage is partial unless contentComplete is true. Outgoing links and backlinks are independently bounded by link_limit; advance link_offset using links.nextOffset. Follow only relevant links.', {
|
|
805
|
+
target: { type: 'string' }, ...scopeParameters, object: { type: 'string' }, wiki_kind: { type: 'string', enum: ['fact', 'way'] },
|
|
806
|
+
include_content: { type: 'boolean' }, limit: { type: 'integer' }, offset: { type: 'integer' }, max_chars: { type: 'integer' }, content_offset: { type: 'integer' }, content_max_chars: { type: 'integer' }, expected_version: { type: 'integer' }, link_limit: { type: 'integer' }, link_offset: { type: 'integer' }, kb: { type: 'string' },
|
|
807
|
+
}, async (args) => withRuntime(args.kb, target => target.readWiki({ ...scopeOf(args), target: args.target, object: args.object, includeContent: args.include_content, limit: args.limit, offset: args.offset, maxChars: args.max_chars, contentOffset: args.content_offset, contentMaxChars: args.content_max_chars, expectedVersion: args.expected_version, linkLimit: args.link_limit, linkOffset: args.link_offset }))));
|
|
808
|
+
ctx.tools.register(tool('get_knowledge_cases', 'Find historical Case by current subquestion or exact coordinates, or read referenced case_ids. Search returns a paged directory with version-pinned nextRead references; ID reads include full records within max_chars. Pass one case_id and its version to read historical evidence. Oversized records use explicit contentPage JSON pages; concatenate and parse before using them. Historical actions, observations and outcomes do not prove the current cause.', {
|
|
809
|
+
case_ids: { type: 'array', description: '1–50 known Case IDs; omit for search.' }, query: { type: 'string' }, ...scopeParameters,
|
|
810
|
+
version: { type: 'integer' }, include_content: { type: 'boolean' }, limit: { type: 'integer' }, offset: { type: 'integer' }, max_chars: { type: 'integer' }, content_offset: { type: 'integer' },
|
|
811
|
+
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' },
|
|
812
|
+
}, async (args) => withRuntime(args.kb, target => target.queryCases({ ...scopeOf(args), ids: args.case_ids, version: args.version, query: args.query, includeContent: args.include_content, limit: args.limit, offset: args.offset, maxChars: args.max_chars, contentOffset: args.content_offset }))));
|
|
850
813
|
ctx.tools.register(tool('check_knowledge_embeddings', 'Inspect the local embedding provider and binary/int8 vector index without loading the model.', { kb: { type: 'string' }, session_key: { type: 'string' } }, async (args) => withRuntime(args.kb, target => target.embeddingHealth())));
|
|
851
814
|
ctx.tools.register(tool('query_knowledge_graph', 'Query entities, neighbors, paths, lists and relation types in the compiled knowledge graph.', { action: { type: 'string', enum: ['entity', 'neighbors', 'path', 'list', 'types'], required: true }, entity_id: { type: 'string' }, id: { type: 'string' }, entity_type: { type: 'string' }, from_id: { type: 'string' }, to_id: { type: 'string' }, type: { type: 'string' }, status: { type: 'string' }, include_problem: { type: 'boolean' }, limit: { type: 'integer' }, depth: { type: 'integer' }, 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.graphQuery(args.action, args.entity_id ?? args.id, args.entity_type ?? args.type, args.depth ?? 1, { fromId: args.from_id, toId: args.to_id, status: args.status, includeProblem: args.include_problem ?? false, limit: args.limit ?? 50 }, lineageOf(args, exec)))));
|
|
852
|
-
ctx.tools.register(tool('query_source_truth', 'Read
|
|
815
|
+
ctx.tools.register(tool('query_source_truth', 'Read a precise Source Raw using source_id plus the evidence version, optional content_hash and [start,end) UTF-16 offsets. Prefer readRef returned by knowledge tools. IDs are opaque and scoped to kb; never infer one from a title, path, hash or external_id. Unknown IDs, unavailable versions and mismatched hashes or quotes fail explicitly; there is no fallback to another source. Exact-read offset is relative to the selected range; follow nextRead to continue. Without source_id, query discovers sources and returns version-pinned readRef for precise follow-up. Discovery uses source_offset for source pages and offset for text pages; advance with returnedChars and nextSourceOffset. Do not apply incomplete evidence.', {
|
|
816
|
+
source_id: { type: 'string' }, version: { type: 'integer' }, content_hash: { type: 'string' }, start: { type: 'integer' }, end: { type: 'integer' }, quote: { type: 'string' }, query: { type: 'string' }, limit: { type: 'integer' }, max_chars: { type: 'integer' }, offset: { type: 'integer' }, source_offset: { type: 'integer' }, 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' },
|
|
817
|
+
}, async (args, exec) => withRuntime(args.kb, async (target) => {
|
|
818
|
+
if (args.source_id !== undefined) {
|
|
819
|
+
if (args.query !== undefined || args.source_offset !== undefined)
|
|
820
|
+
return failure({}, 'SOURCE_SELECTION_CONFLICT', '精确读取 source_id 时不要传 query 或 source_offset。', false);
|
|
821
|
+
return target.readSource({ sourceId: args.source_id, version: args.version, contentHash: args.content_hash, start: args.start, end: args.end, quote: args.quote, maxChars: args.max_chars, offset: args.offset }, lineageOf(args, exec));
|
|
822
|
+
}
|
|
823
|
+
if (typeof args.query !== 'string' || !args.query.trim() || [args.version, args.content_hash, args.start, args.end, args.quote].some(value => value !== undefined))
|
|
824
|
+
return failure({}, 'SOURCE_QUERY_REQUIRED', '搜索请传非空 query;版本、哈希和引文范围读取必须提供 source_id。', false);
|
|
825
|
+
return target.sourceTruth(args.query, args.limit ?? 20, args.max_chars ?? 40000, lineageOf(args, exec), args.offset ?? 0, args.source_offset ?? 0);
|
|
826
|
+
})));
|
|
853
827
|
/**
|
|
854
828
|
* 知识库 id 的**发现入口**。
|
|
855
829
|
*
|
|
@@ -900,7 +874,13 @@ export function apply(ctx, pluginConfig = {}) {
|
|
|
900
874
|
});
|
|
901
875
|
const imagePublishDescription = 'Publish one local image into a knowledge base assets bucket without user approval. Pass exactly one of `file_path` or `content_base64` (standard Base64 or a data URI); optional `filename` overrides the stored name, and optional `mime_type` must match the file bytes. Supports PNG, JPEG, GIF, WebP, AVIF, BMP and SVG up to 20 MiB. Returns the local asset URL and Markdown image reference.';
|
|
902
876
|
ctx.tools.register(tool('image_publish', imagePublishDescription, imagePublishParameters, publishImage));
|
|
903
|
-
ctx.tools.register(tool('
|
|
877
|
+
ctx.tools.register(tool('allocate_source_ids', 'Allocate opaque Source Raw IDs before import. Keep one ID per independent input; reuse it across conversion, transport retries, renames and updates. IDs are not reserved documents until imported. Existing sources keep their current IDs. Never allocate a new ID to update an existing source.', { count: { type: 'integer', description: '1–100, default 1.' } }, async (args) => {
|
|
878
|
+
const count = args.count ?? 1;
|
|
879
|
+
if (!Number.isInteger(count) || count < 1 || count > 100)
|
|
880
|
+
return failure({ source_ids: [] }, 'SOURCE_COUNT_INVALID', 'count 必须为 1–100。', false);
|
|
881
|
+
return success({ source_ids: Array.from({ length: count }, () => newSourceId()) });
|
|
882
|
+
}));
|
|
883
|
+
ctx.tools.register(tool('add_source', 'Add or update Source Raw. For links/platform documents pass source_url or source_identity: identity lookup reuses the existing source_id, otherwise allocates one. For independent files first use allocate_source_ids and retain the ID across retries. Updates use the known source_id and preferably expected_version from an exact read (0 means create only). Titles, paths, body hashes and arbitrary external_id are not update keys. A preallocated unused ID may resolve to an existing document; always use the returned sourceId. Known IDs with contradictory origin fail. Returns a version-pinned readRef. DSH requests one user approval before execution.', { title: { type: 'string' }, content: { type: 'string', required: true }, external_id: { type: 'string' }, metadata: { type: 'json' }, source_id: { type: 'string' }, source_url: { type: 'string', description: 'Explicit acquisition URL, preserving query and fragment. Do not copy an unverified link from body text.' }, source_identity: { type: 'json', description: '{system, scope, document_id, document_type?, url?}; native identity requires system, scope and document_id. URL-only identity can use {url, scope?}.' }, expected_version: { type: 'integer' }, allow_duplicate_title: { type: 'boolean', description: '默认 false:标题与已有来源重复时拒收(SOURCE_TITLE_DUPLICATED),要求改标题。传 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) => (typeof args.source_id !== 'string' || !args.source_id.trim()) && args.source_url === undefined && args.source_identity === undefined ? failure({ sourceId: '' }, 'SOURCE_ID_REQUIRED', '请先分配 source_id;重试或更新复用已有 ID。', false) : withRuntime(args.kb, target => target.addSource({ title: args.title, content: args.content, externalId: args.external_id, metadata: args.metadata, sourceId: args.source_id, sourceUrl: args.source_url, sourceIdentity: args.source_identity, expectedVersion: args.expected_version, ...(args.allow_duplicate_title === true ? { allowDuplicateTitle: true } : {}), lineage: lineageOf(args, exec) })), {
|
|
904
884
|
call: addSourceCallView,
|
|
905
885
|
meta: (args, value) => addSourceMetaOf(args, dataOf(value)),
|
|
906
886
|
result: resultViewOf(addSourceResultMarkdown),
|
|
@@ -916,10 +896,10 @@ export function apply(ctx, pluginConfig = {}) {
|
|
|
916
896
|
* 两者的差别只在「一次多少份」,落盘路径、分类闸门、编译链路完全共用 ——
|
|
917
897
|
* 这个工具的 `execute` 就是循环调 `importSources`,而后者逐条调 `addSource`。
|
|
918
898
|
*
|
|
919
|
-
* `compile`
|
|
920
|
-
*
|
|
899
|
+
* `compile` 默认关闭:先保存来源,再由调用方决定何时处理。显式 true 才跑全链路;
|
|
900
|
+
* 未触发处理时工具返回 `compile: null`。
|
|
921
901
|
*/
|
|
922
|
-
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) }));
|
|
902
|
+
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?, source_url?, source_identity?, expected_version?, title?, content, external_id?, metadata?, allow_duplicate_title? };链接提供 source_url 或 source_identity,先查来源映射;独立文件先分配 source_id,重试沿用;以后续返回的 sourceId 为准;更新旧来源必须传其 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) => Array.isArray(args.sources) && args.sources.some(item => (typeof item?.source_id !== 'string' || !item.source_id.trim()) && item?.source_url === undefined && item?.source_identity === undefined) ? failure({}, 'SOURCE_ID_REQUIRED', '请先为每个输入分配 source_id;重试或更新沿用已有 ID。', false) : withRuntime(args.kb, target => target.importSources({ sources: (Array.isArray(args.sources) ? args.sources : []).map(item => ({ ...(item?.source_id ? { sourceId: item.source_id } : {}), ...(item?.expected_version === undefined ? {} : { expectedVersion: item.expected_version }), ...(item?.source_url === undefined ? {} : { sourceUrl: item.source_url }), ...(item?.source_identity === undefined ? {} : { sourceIdentity: item.source_identity }), ...(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) }));
|
|
923
903
|
/**
|
|
924
904
|
* `propose_wiki_cards` —— 把一批卡片**直接写进 `02_wiki`**(工具名不变,语义在 0044 改了)。
|
|
925
905
|
*
|
|
@@ -1063,6 +1043,19 @@ export function apply(ctx, pluginConfig = {}) {
|
|
|
1063
1043
|
return sendEnvelope(res, resolved.failure);
|
|
1064
1044
|
return send(res, 200, success(await resolved.runtime.stats()));
|
|
1065
1045
|
} },
|
|
1046
|
+
{ kind: 'exact', path: '/knowledge/wiki', handler: async (req, res) => {
|
|
1047
|
+
if (req.method !== 'GET')
|
|
1048
|
+
return send(res, 405, envelopeError('METHOD_NOT_ALLOWED', 'Wiki 读取只接受 GET'));
|
|
1049
|
+
const url = query(req);
|
|
1050
|
+
const resolved = resolveBase(url.searchParams.get('kb'));
|
|
1051
|
+
if ('failure' in resolved)
|
|
1052
|
+
return sendEnvelope(res, resolved.failure);
|
|
1053
|
+
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,
|
|
1054
|
+
actionId: url.searchParams.get('action_id') ?? undefined, sceneId: url.searchParams.get('scene_id') ?? undefined, wikiKind: (url.searchParams.get('wiki_kind') ?? undefined),
|
|
1055
|
+
includeContent: url.searchParams.has('include_content') ? url.searchParams.get('include_content') === 'true' : undefined,
|
|
1056
|
+
...Object.fromEntries([['max_chars', 'maxChars'], ['content_offset', 'contentOffset'], ['content_max_chars', 'contentMaxChars'], ['expected_version', 'expectedVersion'], ['link_limit', 'linkLimit'], ['link_offset', 'linkOffset']].filter(([key]) => url.searchParams.has(key)).map(([key, field]) => [field, Number(url.searchParams.get(key))])),
|
|
1057
|
+
limit: url.searchParams.has('limit') ? Number(url.searchParams.get('limit')) : undefined, offset: url.searchParams.has('offset') ? Number(url.searchParams.get('offset')) : undefined }));
|
|
1058
|
+
} },
|
|
1066
1059
|
{ kind: 'exact', path: '/knowledge/cases', handler: async (req, res) => {
|
|
1067
1060
|
if (req.method !== 'GET')
|
|
1068
1061
|
return send(res, 405, envelopeError('METHOD_NOT_ALLOWED', 'Case 只接受 GET'));
|
|
@@ -1089,6 +1082,7 @@ export function apply(ctx, pluginConfig = {}) {
|
|
|
1089
1082
|
const rerankParam = url.searchParams.get('rerank');
|
|
1090
1083
|
// 响应里始终带 routes + backend,前端据此显示「Coordinate / 关键词 / 向量」三路状态。
|
|
1091
1084
|
return send(res, 200, await resolved.runtime.recall(url.searchParams.get('query') ?? '', topK === null ? undefined : Number(topK), url.searchParams.get('include_problems') === 'true', (url.searchParams.get('mode') ?? undefined), lineageFromUrl(url), {
|
|
1085
|
+
...scopeOf(Object.fromEntries(['object_id', 'action_id', 'scene_id', 'wiki_kind'].filter(key => url.searchParams.has(key)).map(key => [key, url.searchParams.get(key)]))),
|
|
1092
1086
|
...(topN === null ? {} : { contextTopN: Number(topN) }),
|
|
1093
1087
|
...(rerankParam === null ? {} : { rerank: rerankParam !== 'false' && rerankParam !== '0' }),
|
|
1094
1088
|
...(url.searchParams.get('context_max_chars') === null ? {} : { contextMaxChars: Number(url.searchParams.get('context_max_chars')) }),
|
|
@@ -1191,7 +1185,7 @@ export function apply(ctx, pluginConfig = {}) {
|
|
|
1191
1185
|
const pipeline = await resolved.runtime.pipeline();
|
|
1192
1186
|
const limit = Math.min(100, Math.max(1, Number(url.searchParams.get('limit')) || 20));
|
|
1193
1187
|
const offset = Math.max(0, Number(url.searchParams.get('offset')) || 0);
|
|
1194
|
-
return send(res, 200, success({ ...pipeline.store.tasks(limit, offset), extractions: await resolved.runtime.listExtractionRuns({ limit, offset }) }));
|
|
1188
|
+
return send(res, 200, success({ ...pipeline.store.tasks(limit, offset), activeTasks: pipeline.store.activeTasks(), extractions: await resolved.runtime.listExtractionRuns({ limit, offset }) }));
|
|
1195
1189
|
}
|
|
1196
1190
|
catch (cause) {
|
|
1197
1191
|
return send(res, 400, envelopeError('PIPELINE_HISTORY_FAILED', cause instanceof Error ? cause.message : String(cause)));
|
|
@@ -1213,6 +1207,8 @@ export function apply(ctx, pluginConfig = {}) {
|
|
|
1213
1207
|
return send(res, 200, success({ task, ...pipeline.store.events(id, Math.max(0, Number(url.searchParams.get('after')) || 0)) }));
|
|
1214
1208
|
if (req.method !== 'POST')
|
|
1215
1209
|
return send(res, 405, envelopeError('METHOD_NOT_ALLOWED', '任务只接受 GET 或 POST'));
|
|
1210
|
+
if (body.action === 'retry' && PIPELINE_ACTIVE_STATES.includes(task.state))
|
|
1211
|
+
throw new Error('任务仍在运行,请先停止或等待完成');
|
|
1216
1212
|
if (body.action === 'retry')
|
|
1217
1213
|
return send(res, 202, success({ task: pipeline.start(task.stage, { ...task.selection, force: false }).task }));
|
|
1218
1214
|
if (!['pause', 'resume', 'cancel'].includes(body.action))
|
|
@@ -1323,8 +1319,13 @@ export function apply(ctx, pluginConfig = {}) {
|
|
|
1323
1319
|
sources: (Array.isArray(body.sources) ? body.sources : []).map((item) => ({
|
|
1324
1320
|
...(item?.title ? { title: String(item.title) } : {}),
|
|
1325
1321
|
content: item?.content,
|
|
1322
|
+
...(item?.source_id ? { sourceId: String(item.source_id) } : {}),
|
|
1323
|
+
...(item?.source_url === undefined ? {} : { sourceUrl: item.source_url }),
|
|
1324
|
+
...(item?.source_identity === undefined ? {} : { sourceIdentity: item.source_identity }),
|
|
1325
|
+
...(item?.expected_version === undefined ? {} : { expectedVersion: item.expected_version }),
|
|
1326
1326
|
...(item?.external_id ? { externalId: String(item.external_id) } : {}),
|
|
1327
1327
|
...(item?.metadata && typeof item.metadata === 'object' ? { metadata: item.metadata } : {}),
|
|
1328
|
+
...(item?.allow_duplicate_title === true ? { allowDuplicateTitle: true } : {}),
|
|
1328
1329
|
})),
|
|
1329
1330
|
compile: body.compile === true,
|
|
1330
1331
|
lineage: lineageOf(body),
|
|
@@ -1341,7 +1342,7 @@ export function apply(ctx, pluginConfig = {}) {
|
|
|
1341
1342
|
const resolved = resolveBase(body.kb ?? query(req).searchParams.get('kb'));
|
|
1342
1343
|
if ('failure' in resolved)
|
|
1343
1344
|
return sendEnvelope(res, resolved.failure);
|
|
1344
|
-
return send(res, 200, await resolved.runtime.addSource({ title: body.title, content: body.content, externalId: body.external_id, metadata: body.metadata, sourceId: body.source_id, ...(body.allow_duplicate_title === true ? { allowDuplicateTitle: true } : {}), lineage: lineageOf(body) }));
|
|
1345
|
+
return send(res, 200, await resolved.runtime.addSource({ title: body.title, content: body.content, externalId: body.external_id, metadata: body.metadata, sourceId: body.source_id, sourceUrl: body.source_url, sourceIdentity: body.source_identity, expectedVersion: body.expected_version, ...(body.allow_duplicate_title === true ? { allowDuplicateTitle: true } : {}), lineage: lineageOf(body) }));
|
|
1345
1346
|
}
|
|
1346
1347
|
if (req.method !== 'GET')
|
|
1347
1348
|
return send(res, 405, envelopeError('METHOD_NOT_ALLOWED', '该 knowledge endpoint 只接受 GET 或 POST'));
|
|
@@ -1349,6 +1350,11 @@ export function apply(ctx, pluginConfig = {}) {
|
|
|
1349
1350
|
const resolved = resolveBase(url.searchParams.get('kb'));
|
|
1350
1351
|
if ('failure' in resolved)
|
|
1351
1352
|
return sendEnvelope(res, resolved.failure);
|
|
1353
|
+
if (url.searchParams.has('source_id'))
|
|
1354
|
+
return sendEnvelope(res, await resolved.runtime.readSource({ sourceId: url.searchParams.get('source_id'),
|
|
1355
|
+
contentHash: url.searchParams.get('content_hash') ?? undefined, quote: url.searchParams.get('quote') ?? undefined,
|
|
1356
|
+
...Object.fromEntries([['version', 'version'], ['start', 'start'], ['end', 'end'], ['offset', 'offset'], ['max_chars', 'maxChars']].filter(([key]) => url.searchParams.has(key)).map(([key, field]) => [field, Number(url.searchParams.get(key))])),
|
|
1357
|
+
}, lineageFromUrl(url)));
|
|
1352
1358
|
return send(res, 200, await resolved.runtime.sourceTruth(url.searchParams.get('query') ?? '', Number(url.searchParams.get('limit') ?? 20) || 20, Number(url.searchParams.get('max_chars') ?? 40000) || 40000, lineageFromUrl(url), Number(url.searchParams.get('offset') ?? 0) || 0, Number(url.searchParams.get('source_offset') ?? 0) || 0));
|
|
1353
1359
|
}
|
|
1354
1360
|
catch (cause) {
|
|
@@ -1972,9 +1978,8 @@ export function apply(ctx, pluginConfig = {}) {
|
|
|
1972
1978
|
* ```
|
|
1973
1979
|
* /knowledge/pages/trial?kb=<知识库 id> 抽取试跑
|
|
1974
1980
|
* /knowledge/pages/run?kb=<库 id>&run=<轨迹 id> 一次抽取的完整报告
|
|
1975
|
-
* /knowledge/pages/tasks?kb=<知识库 id>
|
|
1981
|
+
* /knowledge/pages/tasks?kb=<知识库 id> 知识处理与编译设置
|
|
1976
1982
|
* /knowledge/pages/help/compile 编译链路
|
|
1977
|
-
* /knowledge/pages/help/intent 意图的逻辑
|
|
1978
1983
|
* /knowledge/pages/help/overview?node=... 五个 Tab 的方案说明
|
|
1979
1984
|
* ```
|
|
1980
1985
|
*
|
|
@@ -2002,12 +2007,10 @@ export function apply(ctx, pluginConfig = {}) {
|
|
|
2002
2007
|
: rest[1] === 'run'
|
|
2003
2008
|
? '抽取轨迹'
|
|
2004
2009
|
: rest[1] === 'tasks'
|
|
2005
|
-
? '
|
|
2006
|
-
: rest[1] === 'help' && rest[2] === '
|
|
2007
|
-
? '
|
|
2008
|
-
: rest[1] === 'help' && rest[2] === '
|
|
2009
|
-
? '编译链路'
|
|
2010
|
-
: rest[1] === 'help' && rest[2] === 'overview' ? 'Agent 方案说明' : '整页';
|
|
2010
|
+
? '知识处理'
|
|
2011
|
+
: rest[1] === 'help' && rest[2] === 'compile'
|
|
2012
|
+
? '编译链路'
|
|
2013
|
+
: rest[1] === 'help' && rest[2] === 'overview' ? 'Agent 方案说明' : '整页';
|
|
2011
2014
|
res.writeHead(200, { 'content-type': 'text/html; charset=utf-8', 'cache-control': 'no-cache' });
|
|
2012
2015
|
res.end(standalonePageHtml(title));
|
|
2013
2016
|
return;
|
|
@@ -2039,6 +2042,8 @@ export function apply(ctx, pluginConfig = {}) {
|
|
|
2039
2042
|
if (rest.length === 2) {
|
|
2040
2043
|
if (method === 'PATCH') {
|
|
2041
2044
|
const body = await readBody(req);
|
|
2045
|
+
if (body.extractionTimeoutMinutes !== undefined && !isExtractionTimeoutMinutes(body.extractionTimeoutMinutes))
|
|
2046
|
+
return send(res, 400, envelopeError('EXTRACTION_TIMEOUT_INVALID', '文档抽取时限只能选择 30、60 或 100 分钟,最大 100 分钟。'));
|
|
2042
2047
|
if (body.compileModel && typeof body.compileModel === 'object') {
|
|
2043
2048
|
const selection = body.compileModel;
|
|
2044
2049
|
const catalog = await compileModelCatalog(baseId);
|
|
@@ -2046,6 +2051,8 @@ export function apply(ctx, pluginConfig = {}) {
|
|
|
2046
2051
|
const model = selection.mode === 'fixed' ? selection.model : catalog.default.model;
|
|
2047
2052
|
if (selection.mode !== 'fixed' && selection.mode !== 'default')
|
|
2048
2053
|
return send(res, 400, envelopeError('MODEL_INVALID', '请选择跟随默认或固定模型'));
|
|
2054
|
+
if (selection.maxTokens !== undefined && (!Number.isSafeInteger(selection.maxTokens) || selection.maxTokens <= 0))
|
|
2055
|
+
return send(res, 400, envelopeError('MODEL_INVALID', '单次最大输出必须是正整数 token;留空表示跟随模型默认。'));
|
|
2049
2056
|
if (selection.mode === 'fixed' && (!provider || !model))
|
|
2050
2057
|
return send(res, 400, envelopeError('MODEL_INVALID', '固定模型需要 provider 和 model'));
|
|
2051
2058
|
const llm = ctx.get('llm');
|
|
@@ -2055,7 +2062,7 @@ export function apply(ctx, pluginConfig = {}) {
|
|
|
2055
2062
|
const effort = info?.reasoning?.efforts.find(item => item.id === selection.reasoningEffort);
|
|
2056
2063
|
if (selection.reasoningEffort && !effort)
|
|
2057
2064
|
throw new Error('所选模型不支持这个思考强度,请重新选择');
|
|
2058
|
-
await llm.resolveCallConfig({ provider, model, ...(effort ? { reasoningEffort: effort.id } : {}) });
|
|
2065
|
+
await llm.resolveCallConfig({ provider, model, ...(effort ? { reasoningEffort: effort.id } : {}), ...(selection.maxTokens !== undefined ? { maxTokens: selection.maxTokens } : {}) });
|
|
2059
2066
|
}
|
|
2060
2067
|
catch (cause) {
|
|
2061
2068
|
return send(res, 400, envelopeError('MODEL_INVALID', cause instanceof Error ? cause.message : String(cause)));
|
|
@@ -2067,6 +2074,7 @@ export function apply(ctx, pluginConfig = {}) {
|
|
|
2067
2074
|
const updated = await bases.update(baseId, {
|
|
2068
2075
|
name: body.name, description: body.description,
|
|
2069
2076
|
extractionNote: typeof body.extractionNote === 'string' ? body.extractionNote : undefined,
|
|
2077
|
+
extractionTimeoutMinutes: body.extractionTimeoutMinutes,
|
|
2070
2078
|
compileModel: body.compileModel && typeof body.compileModel === 'object'
|
|
2071
2079
|
? body.compileModel
|
|
2072
2080
|
: undefined,
|