dsh-data-domain-knowledge 0.1.0-alpha.9 → 0.1.1-alpha.2
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 +118 -567
- package/cordis.patch.yml +5 -418
- package/eval/README.md +19 -8
- package/eval/benchmark-extraction-format.mjs +20 -0
- package/eval/evaluate-retrieval.mjs +17 -8
- package/eval/queries.example.jsonl +1 -0
- package/lib/client.js +4181 -3239
- package/lib/contract-envelope.d.ts +91 -0
- package/lib/contract-envelope.js +106 -0
- package/lib/contract-layout.d.ts +130 -0
- package/lib/contract-layout.js +138 -0
- package/lib/contract-refs.d.ts +39 -0
- package/lib/contract-refs.js +9 -0
- package/lib/contract-version.d.ts +311 -0
- package/lib/contract-version.js +270 -0
- package/lib/contract-wire.d.ts +147 -0
- package/lib/contract-wire.js +99 -0
- package/lib/contracts.d.ts +12 -0
- package/lib/contracts.js +12 -0
- package/lib/doc-page.js +2 -2
- package/lib/pages.js +3329 -1296
- package/lib/types/agent-behavior-rules.d.ts +10 -0
- package/lib/types/agent-behavior-rules.d.ts.map +1 -0
- package/lib/types/agent-behavior-rules.js +28 -0
- package/lib/types/agent-behavior-rules.js.map +1 -0
- package/lib/types/axis-registry.d.ts +37 -5
- package/lib/types/axis-registry.d.ts.map +1 -1
- package/lib/types/axis-registry.js +234 -26
- package/lib/types/axis-registry.js.map +1 -1
- package/lib/types/card-organize.d.ts +27 -12
- package/lib/types/card-organize.d.ts.map +1 -1
- package/lib/types/card-organize.js +58 -73
- package/lib/types/card-organize.js.map +1 -1
- package/lib/types/compiler/embedding-identity.d.ts +3 -0
- package/lib/types/compiler/embedding-identity.d.ts.map +1 -0
- package/lib/types/compiler/embedding-identity.js +24 -0
- package/lib/types/compiler/embedding-identity.js.map +1 -0
- package/lib/types/compiler/snapshot.d.ts +16 -0
- package/lib/types/compiler/snapshot.d.ts.map +1 -0
- package/lib/types/compiler/snapshot.js +2 -0
- package/lib/types/compiler/snapshot.js.map +1 -0
- package/lib/types/config-schema.d.ts +6 -3
- package/lib/types/config-schema.d.ts.map +1 -1
- package/lib/types/config-schema.js +6 -2
- package/lib/types/config-schema.js.map +1 -1
- package/lib/types/convert/host.d.ts +6 -5
- package/lib/types/convert/host.d.ts.map +1 -1
- package/lib/types/convert/host.js +58 -18
- package/lib/types/convert/host.js.map +1 -1
- package/lib/types/convert/ingest.d.ts +10 -1
- package/lib/types/convert/ingest.d.ts.map +1 -1
- package/lib/types/convert/ingest.js +68 -9
- package/lib/types/convert/ingest.js.map +1 -1
- package/lib/types/derive-contract.d.ts +3 -0
- package/lib/types/derive-contract.d.ts.map +1 -0
- package/lib/types/derive-contract.js +15 -0
- package/lib/types/derive-contract.js.map +1 -0
- package/lib/types/diagnosis/cards.d.ts +7 -3
- package/lib/types/diagnosis/cards.d.ts.map +1 -1
- package/lib/types/diagnosis/cards.js +13 -8
- package/lib/types/diagnosis/cards.js.map +1 -1
- package/lib/types/diagnosis/run.d.ts +4 -13
- package/lib/types/diagnosis/run.d.ts.map +1 -1
- package/lib/types/diagnosis/run.js +26 -16
- package/lib/types/diagnosis/run.js.map +1 -1
- package/lib/types/diagnosis/schema.js +2 -2
- package/lib/types/diagnosis/schema.js.map +1 -1
- package/lib/types/diagnosis/seed-source.d.ts +1 -1
- package/lib/types/diagnosis/seed-source.d.ts.map +1 -1
- package/lib/types/diagnosis/seed-source.js +5 -4
- package/lib/types/diagnosis/seed-source.js.map +1 -1
- package/lib/types/diagnosis/seed.d.ts +4 -4
- package/lib/types/diagnosis/seed.d.ts.map +1 -1
- package/lib/types/diagnosis/seed.js +6 -8
- package/lib/types/diagnosis/seed.js.map +1 -1
- package/lib/types/diagnosis/store.d.ts +24 -18
- package/lib/types/diagnosis/store.d.ts.map +1 -1
- package/lib/types/diagnosis/store.js +130 -65
- package/lib/types/diagnosis/store.js.map +1 -1
- package/lib/types/diagnosis/types.d.ts +47 -15
- package/lib/types/diagnosis/types.d.ts.map +1 -1
- package/lib/types/diagnosis/types.js.map +1 -1
- package/lib/types/environment/dsh-python.d.ts +77 -0
- package/lib/types/environment/dsh-python.d.ts.map +1 -0
- package/lib/types/environment/dsh-python.js +139 -0
- package/lib/types/environment/dsh-python.js.map +1 -0
- package/lib/types/environment/install.d.ts +15 -0
- package/lib/types/environment/install.d.ts.map +1 -0
- package/lib/types/environment/install.js +297 -0
- package/lib/types/environment/install.js.map +1 -0
- package/lib/types/environment/manifest.d.ts +208 -0
- package/lib/types/environment/manifest.d.ts.map +1 -0
- package/lib/types/environment/manifest.js +26 -0
- package/lib/types/environment/manifest.js.map +1 -0
- package/lib/types/environment/model-catalog.d.ts +223 -0
- package/lib/types/environment/model-catalog.d.ts.map +1 -0
- package/lib/types/environment/model-catalog.js +129 -0
- package/lib/types/environment/model-catalog.js.map +1 -0
- package/lib/types/environment/process.d.ts +10 -0
- package/lib/types/environment/process.d.ts.map +1 -0
- package/lib/types/environment/process.js +54 -0
- package/lib/types/environment/process.js.map +1 -0
- package/lib/types/environment/selection.d.ts +9 -0
- package/lib/types/environment/selection.d.ts.map +1 -0
- package/lib/types/environment/selection.js +29 -0
- package/lib/types/environment/selection.js.map +1 -0
- package/lib/types/environment/service.d.ts +64 -0
- package/lib/types/environment/service.d.ts.map +1 -0
- package/lib/types/environment/service.js +424 -0
- package/lib/types/environment/service.js.map +1 -0
- package/lib/types/environment/types.d.ts +56 -0
- package/lib/types/environment/types.d.ts.map +1 -0
- package/lib/types/environment/types.js +2 -0
- package/lib/types/environment/types.js.map +1 -0
- package/lib/types/events.d.ts +76 -0
- package/lib/types/events.d.ts.map +1 -0
- package/lib/types/events.js +52 -0
- package/lib/types/events.js.map +1 -0
- package/lib/types/extract-contract.d.ts +3 -0
- package/lib/types/extract-contract.d.ts.map +1 -0
- package/lib/types/extract-contract.js +41 -0
- package/lib/types/extract-contract.js.map +1 -0
- package/lib/types/extract-model.d.ts +5 -0
- package/lib/types/extract-model.d.ts.map +1 -1
- package/lib/types/extract-model.js.map +1 -1
- package/lib/types/extract-table-contract.d.ts +3 -0
- package/lib/types/extract-table-contract.d.ts.map +1 -0
- package/lib/types/extract-table-contract.js +27 -0
- package/lib/types/extract-table-contract.js.map +1 -0
- package/lib/types/extract-table.d.ts +8 -0
- package/lib/types/extract-table.d.ts.map +1 -0
- package/lib/types/extract-table.js +158 -0
- package/lib/types/extract-table.js.map +1 -0
- package/lib/types/extraction-runs.d.ts +30 -6
- package/lib/types/extraction-runs.d.ts.map +1 -1
- package/lib/types/extraction-runs.js +69 -8
- package/lib/types/extraction-runs.js.map +1 -1
- package/lib/types/fs-atomic.d.ts +0 -7
- package/lib/types/fs-atomic.d.ts.map +1 -1
- package/lib/types/fs-atomic.js +17 -2
- package/lib/types/fs-atomic.js.map +1 -1
- package/lib/types/images.d.ts +26 -0
- package/lib/types/images.d.ts.map +1 -0
- package/lib/types/images.js +196 -0
- package/lib/types/images.js.map +1 -0
- package/lib/types/index.d.ts +2 -2
- package/lib/types/index.d.ts.map +1 -1
- package/lib/types/index.js +598 -209
- package/lib/types/index.js.map +1 -1
- package/lib/types/intent/engine.d.ts +12 -4
- package/lib/types/intent/engine.d.ts.map +1 -1
- package/lib/types/intent/engine.js +43 -5
- package/lib/types/intent/engine.js.map +1 -1
- package/lib/types/intent/host.d.ts +5 -8
- package/lib/types/intent/host.d.ts.map +1 -1
- package/lib/types/intent/host.js +56 -11
- package/lib/types/intent/host.js.map +1 -1
- package/lib/types/intent/scope.d.ts +25 -0
- package/lib/types/intent/scope.d.ts.map +1 -0
- package/lib/types/intent/scope.js +116 -0
- package/lib/types/intent/scope.js.map +1 -0
- package/lib/types/intent/tools.d.ts +24 -20
- package/lib/types/intent/tools.d.ts.map +1 -1
- package/lib/types/intent/tools.js +65 -23
- package/lib/types/intent/tools.js.map +1 -1
- package/lib/types/intent/types.d.ts +11 -4
- package/lib/types/intent/types.d.ts.map +1 -1
- package/lib/types/knowledge-bases.d.ts +11 -5
- package/lib/types/knowledge-bases.d.ts.map +1 -1
- package/lib/types/knowledge-bases.js +52 -20
- package/lib/types/knowledge-bases.js.map +1 -1
- package/lib/types/knowledge-contract.d.ts +32 -0
- package/lib/types/knowledge-contract.d.ts.map +1 -0
- package/lib/types/knowledge-contract.js +116 -0
- package/lib/types/knowledge-contract.js.map +1 -0
- package/lib/types/knowledge.d.ts +31 -9
- package/lib/types/knowledge.d.ts.map +1 -1
- package/lib/types/knowledge.js +137 -60
- package/lib/types/knowledge.js.map +1 -1
- package/lib/types/layout.d.ts +10 -29
- package/lib/types/layout.d.ts.map +1 -1
- package/lib/types/layout.js +17 -36
- package/lib/types/layout.js.map +1 -1
- package/lib/types/materialize-snapshot.d.ts +49 -0
- package/lib/types/materialize-snapshot.d.ts.map +1 -0
- package/lib/types/materialize-snapshot.js +2 -0
- package/lib/types/materialize-snapshot.js.map +1 -0
- package/lib/types/migrate.d.ts +11 -0
- package/lib/types/migrate.d.ts.map +1 -1
- package/lib/types/migrate.js +83 -2
- package/lib/types/migrate.js.map +1 -1
- package/lib/types/model-text.d.ts +58 -1
- package/lib/types/model-text.d.ts.map +1 -1
- package/lib/types/model-text.js +85 -30
- package/lib/types/model-text.js.map +1 -1
- package/lib/types/oplog.d.ts.map +1 -1
- package/lib/types/oplog.js +7 -0
- package/lib/types/oplog.js.map +1 -1
- package/lib/types/organize-contract.d.ts +18 -0
- package/lib/types/organize-contract.d.ts.map +1 -0
- package/lib/types/organize-contract.js +82 -0
- package/lib/types/organize-contract.js.map +1 -0
- package/lib/types/pipeline/engine.d.ts +66 -0
- package/lib/types/pipeline/engine.d.ts.map +1 -0
- package/lib/types/pipeline/engine.js +352 -0
- package/lib/types/pipeline/engine.js.map +1 -0
- package/lib/types/pipeline/store.d.ts +73 -0
- package/lib/types/pipeline/store.d.ts.map +1 -0
- package/lib/types/pipeline/store.js +143 -0
- package/lib/types/pipeline/store.js.map +1 -0
- package/lib/types/pipeline/types.d.ts +102 -0
- package/lib/types/pipeline/types.d.ts.map +1 -0
- package/lib/types/pipeline/types.js +5 -0
- package/lib/types/pipeline/types.js.map +1 -0
- package/lib/types/present.d.ts +2 -0
- package/lib/types/present.d.ts.map +1 -1
- package/lib/types/present.js +9 -4
- package/lib/types/present.js.map +1 -1
- package/lib/types/preset-ids.d.ts +4 -0
- package/lib/types/preset-ids.d.ts.map +1 -0
- package/lib/types/preset-ids.js +6 -0
- package/lib/types/preset-ids.js.map +1 -0
- package/lib/types/query-analysis.d.ts +13 -1
- package/lib/types/query-analysis.d.ts.map +1 -1
- package/lib/types/query-analysis.js +62 -6
- package/lib/types/query-analysis.js.map +1 -1
- package/lib/types/recall-rank.d.ts +3 -3
- package/lib/types/recall-rank.d.ts.map +1 -1
- package/lib/types/recall-rank.js +4 -4
- package/lib/types/recall-rank.js.map +1 -1
- package/lib/types/retention.d.ts +39 -0
- package/lib/types/retention.d.ts.map +1 -0
- package/lib/types/retention.js +42 -0
- package/lib/types/retention.js.map +1 -0
- package/lib/types/retrieval/vector-index.d.ts +32 -0
- package/lib/types/retrieval/vector-index.d.ts.map +1 -0
- package/lib/types/retrieval/vector-index.js +15 -0
- package/lib/types/retrieval/vector-index.js.map +1 -0
- package/lib/types/retrieval/visibility.d.ts +6 -0
- package/lib/types/retrieval/visibility.d.ts.map +1 -0
- package/lib/types/retrieval/visibility.js +11 -0
- package/lib/types/retrieval/visibility.js.map +1 -0
- package/lib/types/runtime.d.ts +272 -27
- package/lib/types/runtime.d.ts.map +1 -1
- package/lib/types/runtime.js +2751 -537
- package/lib/types/runtime.js.map +1 -1
- package/lib/types/settings-schema.d.ts +17 -15
- package/lib/types/settings-schema.d.ts.map +1 -1
- package/lib/types/settings-schema.js +50 -47
- package/lib/types/settings-schema.js.map +1 -1
- package/lib/types/settings-volatile.d.ts +4 -4
- package/lib/types/settings-volatile.js +4 -4
- package/lib/types/source-evidence.d.ts +14 -0
- package/lib/types/source-evidence.d.ts.map +1 -0
- package/lib/types/source-evidence.js +36 -0
- package/lib/types/source-evidence.js.map +1 -0
- package/lib/types/store/axis-references.d.ts +5 -0
- package/lib/types/store/axis-references.d.ts.map +1 -0
- package/lib/types/store/axis-references.js +106 -0
- package/lib/types/store/axis-references.js.map +1 -0
- package/lib/types/store/derived.d.ts +12 -1
- package/lib/types/store/derived.d.ts.map +1 -1
- package/lib/types/store/derived.js +71 -12
- package/lib/types/store/derived.js.map +1 -1
- package/lib/types/store/knowledge-db.d.ts +31 -1
- package/lib/types/store/knowledge-db.d.ts.map +1 -1
- package/lib/types/store/knowledge-db.js +252 -18
- package/lib/types/store/knowledge-db.js.map +1 -1
- package/lib/types/store/migrate.d.ts.map +1 -1
- package/lib/types/store/migrate.js +17 -6
- package/lib/types/store/migrate.js.map +1 -1
- package/lib/types/trajectory-types.d.ts +172 -0
- package/lib/types/trajectory-types.d.ts.map +1 -0
- package/lib/types/trajectory-types.js +36 -0
- package/lib/types/trajectory-types.js.map +1 -0
- package/lib/types/types.d.ts +59 -27
- package/lib/types/types.d.ts.map +1 -1
- package/lib/types/types.js +6 -15
- package/lib/types/types.js.map +1 -1
- package/lib/types/wiki-finalize.d.ts +16 -0
- package/lib/types/wiki-finalize.d.ts.map +1 -1
- package/lib/types/wiki-finalize.js +26 -0
- package/lib/types/wiki-finalize.js.map +1 -1
- package/lib/types/wiki-materialize.d.ts +4 -0
- package/lib/types/wiki-materialize.d.ts.map +1 -1
- package/lib/types/wiki-materialize.js +21 -7
- package/lib/types/wiki-materialize.js.map +1 -1
- package/lib/types/wiki-trial-types.d.ts +87 -0
- package/lib/types/wiki-trial-types.d.ts.map +1 -1
- package/lib/types/wiki-trial-types.js +0 -16
- package/lib/types/wiki-trial-types.js.map +1 -1
- package/lib/types/wiki-trial.d.ts +40 -16
- package/lib/types/wiki-trial.d.ts.map +1 -1
- package/lib/types/wiki-trial.js +337 -224
- package/lib/types/wiki-trial.js.map +1 -1
- package/package.json +29 -20
- package/python/prepare-models.py +19 -0
- package/python/requirements.txt +8 -6
- package/scripts/doctor.mjs +13 -19
- package/scripts/environment.mjs +29 -0
- package/scripts/setup-embedding.sh +15 -5
- package/src/agent-behavior-rules.ts +37 -0
- package/src/axis-registry.ts +234 -27
- package/src/card-organize.ts +69 -75
- package/src/client/AgentBehaviorRulesCard.tsx +65 -0
- package/src/client/AttributionEventGuide.tsx +41 -39
- package/src/client/AxisRegistrySection.tsx +204 -164
- package/src/client/CompileDialogs.tsx +44 -29
- package/src/client/DeleteDocumentDialog.tsx +36 -5
- package/src/client/DirectoryPicker.tsx +0 -10
- package/src/client/EnvironmentSetup.tsx +243 -0
- package/src/client/ExpansionGraph.tsx +13 -7
- package/src/client/ExtractionTasksPage.tsx +578 -0
- package/src/client/GuideArchitectureCanvas.tsx +470 -0
- package/src/client/ImportFilesDialog.tsx +2 -13
- package/src/client/IntentLogic.tsx +2 -2
- package/src/client/IntentTab.tsx +118 -47
- package/src/client/KnowledgeBaseTab.tsx +277 -197
- package/src/client/KnowledgeLayerSection.tsx +24 -6
- package/src/client/KnowledgePanel.tsx +58 -93
- package/src/client/KnowledgeSettingsDrawer.tsx +90 -0
- package/src/client/ListPager.tsx +15 -5
- package/src/client/MaterializeTrajectoryView.tsx +124 -0
- package/src/client/NodeSettings.tsx +210 -89
- package/src/client/NormalizeTrajectoryView.tsx +136 -0
- package/src/client/PipelineNotice.tsx +26 -0
- package/src/client/PreviewSections.tsx +118 -51
- package/src/client/RecallPanel.tsx +89 -85
- package/src/client/TabGuide.tsx +159 -184
- package/src/client/TrialReportView.tsx +391 -214
- package/src/client/TypeDefinitionDrawer.tsx +150 -23
- package/src/client/WikiCardPreview.tsx +62 -16
- package/src/client/WikiFlowPanel.tsx +4 -4
- package/src/client/arch/NodeLogicPanel.tsx +3 -4
- package/src/client/arch/model.ts +6 -9
- package/src/client/architecture.tsx +23 -33
- package/src/client/attribution/AttributionGraph.tsx +10 -6
- package/src/client/attribution/AttributionTab.tsx +136 -84
- package/src/client/attribution/CaseView.tsx +3 -1
- package/src/client/attribution/EventView.tsx +108 -0
- package/src/client/attribution/RunView.tsx +2 -2
- package/src/client/attribution/StageChrome.tsx +34 -3
- package/src/client/attribution/ViewSwitch.tsx +20 -5
- package/src/client/attribution/graph-options.ts +47 -39
- package/src/client/attribution/model.ts +17 -10
- package/src/client/config-scope.ts +3 -3
- package/src/client/graph/palette.ts +165 -0
- package/src/client/index.ts +49 -42
- package/src/client/pages.css +459 -135
- package/src/client/pages.tsx +37 -9
- package/src/client/problem-domains.ts +1 -1
- package/src/client/session-remote.ts +9 -0
- package/src/client/styles.css +205 -62
- package/src/client/wiki-trial.ts +44 -3
- package/src/compiler/embedding-identity.ts +21 -0
- package/src/compiler/snapshot.ts +17 -0
- package/src/config-schema.ts +8 -3
- package/src/convert/host.ts +56 -21
- package/src/convert/ingest.ts +74 -10
- package/src/derive-contract.ts +14 -0
- package/src/diagnosis/cards.ts +13 -8
- package/src/diagnosis/run.ts +27 -17
- package/src/diagnosis/schema.ts +2 -2
- package/src/diagnosis/seed-source.ts +5 -4
- package/src/diagnosis/seed.ts +6 -8
- package/src/diagnosis/store.ts +138 -69
- package/src/diagnosis/types.ts +34 -15
- package/src/environment/dsh-python.ts +156 -0
- package/src/environment/install.ts +244 -0
- package/src/environment/manifest.ts +28 -0
- package/src/environment/model-catalog.ts +147 -0
- package/src/environment/process.ts +54 -0
- package/src/environment/selection.ts +29 -0
- package/src/environment/service.ts +348 -0
- package/src/environment/types.ts +45 -0
- package/src/events.ts +108 -0
- package/src/extract-contract.ts +42 -0
- package/src/extract-model.ts +10 -1
- package/src/extract-table-contract.ts +26 -0
- package/src/extract-table.ts +132 -0
- package/src/extraction-runs.ts +70 -11
- package/src/fs-atomic.ts +19 -2
- package/src/images.ts +203 -0
- package/src/index.ts +553 -205
- package/src/intent/README.md +8 -6
- package/src/intent/engine.ts +44 -6
- package/src/intent/host.ts +59 -18
- package/src/intent/scope.ts +125 -0
- package/src/intent/tools.ts +70 -28
- package/src/intent/types.ts +11 -4
- package/src/knowledge-bases.ts +56 -20
- package/src/knowledge-contract.ts +114 -0
- package/src/knowledge.ts +138 -69
- package/src/layout.ts +17 -37
- package/src/materialize-snapshot.ts +46 -0
- package/src/migrate.ts +75 -2
- package/src/model-text.ts +109 -4
- package/src/oplog.ts +7 -0
- package/src/organize-contract.ts +83 -0
- package/src/pipeline/engine.ts +323 -0
- package/src/pipeline/store.ts +147 -0
- package/src/pipeline/types.ts +93 -0
- package/src/present.ts +10 -4
- package/src/preset-ids.ts +6 -0
- package/src/python/embedding_worker.py +66 -2
- package/src/query-analysis.ts +68 -8
- package/src/recall-rank.ts +5 -5
- package/src/retention.ts +76 -0
- package/src/retrieval/vector-index.ts +45 -0
- package/src/retrieval/visibility.ts +14 -0
- package/src/runtime.ts +2708 -567
- package/src/settings-schema.ts +11 -8
- package/src/settings-volatile.ts +4 -4
- package/src/source-evidence.ts +37 -0
- package/src/store/axis-references.ts +96 -0
- package/src/store/derived.ts +70 -12
- package/src/store/knowledge-db.ts +248 -17
- package/src/store/migrate.ts +16 -6
- package/src/trajectory-types.ts +142 -0
- package/src/types.ts +61 -35
- package/src/wiki-finalize.ts +28 -0
- package/src/wiki-materialize.ts +25 -6
- package/src/wiki-trial-types.ts +83 -1
- package/src/wiki-trial.ts +357 -185
- package/lib/types/intent/preset-tools.d.ts +0 -37
- package/lib/types/intent/preset-tools.d.ts.map +0 -1
- package/lib/types/intent/preset-tools.js +0 -45
- package/lib/types/intent/preset-tools.js.map +0 -1
- package/preset/tita-data-agent/agent.cordis.yml +0 -394
- package/preset/tita-data-agent/preset.yml +0 -3
- package/scripts/install-agent-preset.mjs +0 -92
- package/scripts/sync-agent-preset.mjs +0 -188
- package/src/client/AgentPresetCard.tsx +0 -247
- package/src/client/agent-preset.ts +0 -121
- package/src/client/convert/ConvertPanel.tsx +0 -583
- package/src/client/convert/styles.css +0 -138
- package/src/client/convert/styles.ts +0 -49
- package/src/intent/preset-tools.ts +0 -48
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto'
|
|
2
|
+
import type { ModelCall } from '../extract-model.js'
|
|
3
|
+
import type { SourceRaw, WikiTypeDef } from '../types.js'
|
|
4
|
+
import type { TrialReport } from '../wiki-trial-types.js'
|
|
5
|
+
import { PipelineStore, type ExtractionCheckpoint } from './store.js'
|
|
6
|
+
import { PIPELINE_ACTIVE_STATES, PIPELINE_STAGE_LABEL, type MaterializationBatch, type MaterializationGroup, type PipelineAction, type PipelineModel, type PipelineSelection, type PipelineStage, type PipelineTask } from './types.js'
|
|
7
|
+
|
|
8
|
+
export interface PipelineSource extends SourceRaw { version: number; sourceHash: string }
|
|
9
|
+
export interface PipelineContext {
|
|
10
|
+
model: PipelineModel & { call?: ModelCall; why?: string }
|
|
11
|
+
note: string
|
|
12
|
+
profile?: WikiTypeDef
|
|
13
|
+
organize: boolean
|
|
14
|
+
format: 'json' | 'table'
|
|
15
|
+
}
|
|
16
|
+
export interface PipelineBuildResult { summary: string; skipped?: boolean }
|
|
17
|
+
export interface PipelineHost {
|
|
18
|
+
capture(): PipelineContext
|
|
19
|
+
serialize<T>(work: () => Promise<T>): Promise<T>
|
|
20
|
+
sources(): Promise<PipelineSource[]>
|
|
21
|
+
/** One source by id. Same shape as an element of `sources()`. */
|
|
22
|
+
source(sourceId: string): Promise<PipelineSource | undefined>
|
|
23
|
+
fingerprint(source: PipelineSource, context: PipelineContext): Promise<string>
|
|
24
|
+
extract(source: PipelineSource, context: PipelineContext, output: (text: string) => void): Promise<TrialReport>
|
|
25
|
+
normalize(source: PipelineSource, checkpoint: ExtractionCheckpoint, context: PipelineContext, force: boolean, output: (text: string) => void): Promise<{ reused: boolean; warnings: string[] }>
|
|
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
|
+
groups(context: PipelineContext): Promise<MaterializationBatch>
|
|
28
|
+
materialize(group: MaterializationGroup, context: PipelineContext, output: (text: string) => void, snapshot: unknown): Promise<void>
|
|
29
|
+
build(taskId: string, checkpoint: () => Promise<void>): Promise<PipelineBuildResult>
|
|
30
|
+
record(checkpoint: ExtractionCheckpoint): Promise<void>
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
class TaskCancelled extends Error {}
|
|
34
|
+
interface Control { pause: boolean; cancel: boolean; resume?: () => void }
|
|
35
|
+
|
|
36
|
+
/** One writer queue per base, shared with the legacy index builder. */
|
|
37
|
+
export class KnowledgePipeline {
|
|
38
|
+
private closed = false
|
|
39
|
+
private controls = new Map<string, Control>()
|
|
40
|
+
constructor(readonly store: PipelineStore, private readonly host: PipelineHost) {}
|
|
41
|
+
|
|
42
|
+
start(stage: PipelineStage, selection: PipelineSelection = {}): { task: PipelineTask; completion: Promise<PipelineTask> } {
|
|
43
|
+
if (this.closed) throw new Error('知识处理已关闭')
|
|
44
|
+
if (!['extract', 'normalize', 'derive', 'materialize', 'build', 'all'].includes(stage)) throw new Error('不支持的知识处理阶段')
|
|
45
|
+
for (const value of [selection.sourceIds, selection.groupKeys]) {
|
|
46
|
+
if (value !== undefined && (!Array.isArray(value) || value.length === 0 || value.some(id => typeof id !== 'string' || !id.trim()))) throw new Error('选择范围不能为空;不传范围表示处理当前阶段的全部待办')
|
|
47
|
+
}
|
|
48
|
+
const context = this.host.capture()
|
|
49
|
+
const { call: _call, why: _why, ...model } = context.model
|
|
50
|
+
const task: PipelineTask = {
|
|
51
|
+
id: `pipeline_${randomUUID()}`, stage, state: 'queued', selection: structuredClone(selection), model,
|
|
52
|
+
queuedAt: new Date().toISOString(), done: 0, total: 0, reused: 0, failed: 0,
|
|
53
|
+
summary: '等待运行', warnings: [],
|
|
54
|
+
}
|
|
55
|
+
this.store.putTask(task)
|
|
56
|
+
this.controls.set(task.id, { pause: false, cancel: false })
|
|
57
|
+
const completion = this.host.serialize(() => this.execute(task.id, context))
|
|
58
|
+
// Starting a background task must not create an unhandled rejection.
|
|
59
|
+
void completion.catch(() => undefined)
|
|
60
|
+
return { task, completion }
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
close(): void {
|
|
64
|
+
this.closed = true
|
|
65
|
+
for (const control of this.controls.values()) { control.cancel = true; control.pause = false; control.resume?.() }
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
control(id: string, action: PipelineAction): PipelineTask {
|
|
69
|
+
const task = this.store.task(id)
|
|
70
|
+
const control = this.controls.get(id)
|
|
71
|
+
if (!task || !control || !PIPELINE_ACTIVE_STATES.includes(task.state)) throw new Error('任务已结束;请重新运行所需阶段')
|
|
72
|
+
if (action === 'pause') {
|
|
73
|
+
control.pause = true
|
|
74
|
+
this.patch(id, { state: task.state === 'queued' ? 'paused' : 'pausing', summary: '当前文档或卡片处理完成后暂停' })
|
|
75
|
+
} else if (action === 'resume') {
|
|
76
|
+
if (!control.pause) throw new Error('任务没有暂停')
|
|
77
|
+
control.pause = false
|
|
78
|
+
this.patch(id, { state: task.startedAt ? 'running' : 'queued' })
|
|
79
|
+
control.resume?.()
|
|
80
|
+
control.resume = undefined
|
|
81
|
+
} else {
|
|
82
|
+
control.cancel = true
|
|
83
|
+
control.pause = false
|
|
84
|
+
this.patch(id, { state: 'cancelling', summary: '当前文档或卡片处理完成后停止' })
|
|
85
|
+
control.resume?.()
|
|
86
|
+
}
|
|
87
|
+
return this.store.task(id)!
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
private patch(id: string, patch: Partial<PipelineTask>): PipelineTask {
|
|
91
|
+
const task = { ...this.store.task(id)!, ...patch }
|
|
92
|
+
this.store.putTask(task)
|
|
93
|
+
return task
|
|
94
|
+
}
|
|
95
|
+
private finishStage(id: string, outcome?: Pick<PipelineBuildResult, 'summary' | 'skipped'>): void {
|
|
96
|
+
const task = this.store.task(id)!
|
|
97
|
+
if (task.currentStage) this.patch(id, { results: { ...task.results, [task.currentStage]: { done: task.done, total: task.total, reused: task.reused, failed: task.failed, ...outcome } } })
|
|
98
|
+
}
|
|
99
|
+
private async checkpoint(id: string): Promise<void> {
|
|
100
|
+
const control = this.controls.get(id)
|
|
101
|
+
while (control) {
|
|
102
|
+
if (control.cancel) throw new TaskCancelled('任务已停止,已完成的文档与阶段会保留')
|
|
103
|
+
if (!control.pause) return
|
|
104
|
+
this.patch(id, { state: 'paused', summary: '已暂停,可继续运行' })
|
|
105
|
+
await new Promise<void>(resolve => { control.resume = resolve })
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
private output(id: string, stage: Exclude<PipelineStage, 'all'>, sourceId?: string): { append: (text: string) => void; flush: () => void } {
|
|
109
|
+
let buffer = ''
|
|
110
|
+
let last = Date.now()
|
|
111
|
+
let bytes = 0
|
|
112
|
+
let capped = false
|
|
113
|
+
const flush = (): void => {
|
|
114
|
+
if (!buffer) return
|
|
115
|
+
this.store.event(id, 'output', buffer, sourceId, stage)
|
|
116
|
+
buffer = ''
|
|
117
|
+
last = Date.now()
|
|
118
|
+
}
|
|
119
|
+
let failure: unknown
|
|
120
|
+
const timer = setInterval(() => { try { flush() } catch (cause) { failure = cause; clearInterval(timer) } }, 250)
|
|
121
|
+
timer.unref()
|
|
122
|
+
return {
|
|
123
|
+
append: text => {
|
|
124
|
+
if (failure) throw failure
|
|
125
|
+
bytes += Buffer.byteLength(text)
|
|
126
|
+
if (bytes > 4 * 1024 * 1024) {
|
|
127
|
+
if (!capped) { flush(); this.store.event(id, 'warning', '实时预览超过 4 MB;完整返回保存在本次抽取报告中。', sourceId, stage); capped = true }
|
|
128
|
+
return
|
|
129
|
+
}
|
|
130
|
+
buffer += text
|
|
131
|
+
if (buffer.length >= 1024 || Date.now() - last >= 250) flush()
|
|
132
|
+
}, flush: () => { clearInterval(timer); if (failure) throw failure; flush() },
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
private async execute(id: string, context: PipelineContext): Promise<PipelineTask> {
|
|
136
|
+
const task = this.store.task(id)!
|
|
137
|
+
const stages: Exclude<PipelineStage, 'all'>[] = task.stage === 'all' ? (this.host.derive ? ['extract', 'normalize', 'derive', 'materialize', 'build'] : ['extract', 'normalize', 'materialize', 'build']) : [task.stage]
|
|
138
|
+
try {
|
|
139
|
+
await this.checkpoint(id)
|
|
140
|
+
this.patch(id, { state: 'running', startedAt: new Date().toISOString() })
|
|
141
|
+
const allSources = await this.host.sources()
|
|
142
|
+
const sourceIds = task.selection.sourceIds === undefined ? undefined : new Set(task.selection.sourceIds)
|
|
143
|
+
if (sourceIds && [...sourceIds].some(sourceId => !allSources.some(source => source.sourceId === sourceId))) throw new Error('选择范围中有已删除或不存在的来源')
|
|
144
|
+
const sources = allSources.filter(source => !sourceIds || sourceIds.has(source.sourceId))
|
|
145
|
+
/**
|
|
146
|
+
* 坐标仍有歧义、等归一的 Knowledge 条数。它不是失败,所以既不进 `failed`、
|
|
147
|
+
* 也不提前结束链路(否则一个歧义 mention 就能让整库索引永不发布);
|
|
148
|
+
* 但它也不是「全部完成」,所以最终状态报 `partial`。
|
|
149
|
+
*/
|
|
150
|
+
let deferred = 0
|
|
151
|
+
for (const stage of stages) {
|
|
152
|
+
await this.checkpoint(id)
|
|
153
|
+
this.patch(id, { currentStage: stage, done: 0, total: 0, reused: 0, failed: 0, summary: PIPELINE_STAGE_LABEL[stage] })
|
|
154
|
+
this.store.event(id, 'progress', PIPELINE_STAGE_LABEL[stage], undefined, stage)
|
|
155
|
+
if (stage === 'derive') {
|
|
156
|
+
if (!this.host.derive) throw new Error('当前运行时不支持 Case 提炼')
|
|
157
|
+
const output = this.output(id, stage)
|
|
158
|
+
try {
|
|
159
|
+
const result = await this.host.derive(task.selection.sourceIds, context, Boolean(task.selection.force), output.append, () => this.checkpoint(id))
|
|
160
|
+
this.patch(id, result)
|
|
161
|
+
this.finishStage(id, result)
|
|
162
|
+
} finally { output.flush() }
|
|
163
|
+
continue
|
|
164
|
+
}
|
|
165
|
+
if (stage === 'build') {
|
|
166
|
+
const result = await this.host.build(id, () => this.checkpoint(id))
|
|
167
|
+
this.patch(id, { done: 1, total: 1, summary: result.summary })
|
|
168
|
+
this.finishStage(id, result)
|
|
169
|
+
continue
|
|
170
|
+
}
|
|
171
|
+
if (stage === 'materialize') {
|
|
172
|
+
const batch = await this.host.groups(context)
|
|
173
|
+
const { groups } = batch
|
|
174
|
+
const selected = task.selection.groupKeys ? new Set(task.selection.groupKeys) : undefined
|
|
175
|
+
if (selected && [...selected].some(key => !groups.some(group => group.key === key))) throw new Error('选择的卡片分组已变化,请刷新待物化列表')
|
|
176
|
+
/**
|
|
177
|
+
* 来源范围对**任何**阶段都生效,不只对 `all`:`start()` 会校验 `sourceIds`
|
|
178
|
+
* 非空,调用方因此有理由认为它生效了。只对 `all` 生效等于静默忽略选择。
|
|
179
|
+
*/
|
|
180
|
+
const affectedSources = sourceIds ? new Set(sources.map(source => source.sourceId)) : undefined
|
|
181
|
+
const scoped = selected !== undefined || affectedSources !== undefined
|
|
182
|
+
const inScope = (group: MaterializationGroup): boolean => (!selected || selected.has(group.key)) && (!affectedSources || group.sourceIds.some(sourceId => affectedSources.has(sourceId)))
|
|
183
|
+
/**
|
|
184
|
+
* 待归一的量要**按选择范围**数,且两个原因分开说(0070)。
|
|
185
|
+
*
|
|
186
|
+
* 「坐标有歧义」与「来源变了、抽取结果还没归一」是两件事,报同一句话会让读的人
|
|
187
|
+
* 去查错的地方。更要紧的是范围:按 `sourceIds` / `groupKeys` 缩小的那一趟,
|
|
188
|
+
* 如果拿全库的数字报 `partial`,调用方会去重试一件它明确排除的事 —— 而它其实
|
|
189
|
+
* 全都做完了。坐标有歧义的那些行不属于任何分组,无法按来源归属,所以只在
|
|
190
|
+
* 没有选择范围时才计入。
|
|
191
|
+
*/
|
|
192
|
+
const ambiguous = scoped ? 0 : batch.blockedAmbiguous
|
|
193
|
+
const awaiting = scoped
|
|
194
|
+
? groups.filter(group => group.state === 'blocked' && inScope(group)).reduce((sum, group) => sum + group.knowledgeCount, 0)
|
|
195
|
+
: batch.blockedAwaitingNormalize
|
|
196
|
+
if (ambiguous > 0 || awaiting > 0) {
|
|
197
|
+
deferred = ambiguous + awaiting
|
|
198
|
+
const parts = [
|
|
199
|
+
ambiguous > 0 ? `${ambiguous} 条 Knowledge 因坐标歧义、方法不完整或 Case 引用过期暂不可发布` : '',
|
|
200
|
+
awaiting > 0 ? `${awaiting} 条 Knowledge 的来源已变化或新抽取待归一` : '',
|
|
201
|
+
].filter(Boolean)
|
|
202
|
+
const message = `${parts.join(';')},暂不物化;本次不影响索引构建。`
|
|
203
|
+
this.patch(id, { warnings: [...this.store.task(id)!.warnings, message] })
|
|
204
|
+
this.store.event(id, 'warning', message, undefined, stage)
|
|
205
|
+
}
|
|
206
|
+
const pending = groups.filter(group => group.state !== 'blocked' && inScope(group) && (task.selection.force || group.state !== 'current'))
|
|
207
|
+
this.patch(id, { total: pending.length })
|
|
208
|
+
for (const group of pending) {
|
|
209
|
+
await this.checkpoint(id)
|
|
210
|
+
const output = this.output(id, stage)
|
|
211
|
+
try { await this.host.materialize(group, context, output.append, batch.snapshot) }
|
|
212
|
+
catch (cause) {
|
|
213
|
+
if (cause instanceof TaskCancelled) throw cause
|
|
214
|
+
const message = `${group.title}:${cause instanceof Error ? cause.message : String(cause)}`
|
|
215
|
+
const current = this.store.task(id)!
|
|
216
|
+
this.patch(id, { failed: current.failed + 1, warnings: [...current.warnings, message] })
|
|
217
|
+
this.store.event(id, 'warning', message, undefined, stage)
|
|
218
|
+
}
|
|
219
|
+
finally { output.flush() }
|
|
220
|
+
const current = this.store.task(id)!
|
|
221
|
+
this.patch(id, { done: current.done + 1, summary: `已物化 ${current.done + 1}/${pending.length} 张:${group.title}` })
|
|
222
|
+
}
|
|
223
|
+
const current = this.store.task(id)!
|
|
224
|
+
/**
|
|
225
|
+
* 阶段结论要给 `summary`:任务列表的四段步轨读的是 `results[stage]`,
|
|
226
|
+
* 缺了它那一段会显示成「已完成」(成功色),而任务徽标写着「部分完成」——
|
|
227
|
+
* 同一件事在半个屏幕上两种说法。
|
|
228
|
+
*/
|
|
229
|
+
this.finishStage(id, {
|
|
230
|
+
summary: `已物化 ${current.done - current.failed}/${current.total} 张${deferred > 0 ? `;${deferred} 条待归一` : ''}${affectedSources !== undefined ? `(按来源范围缩小:${affectedSources.size} 份来源)` : ''}`,
|
|
231
|
+
})
|
|
232
|
+
/**
|
|
233
|
+
* **真的**有分组失败时才提前结束(含 `build`):这里与 `blocked` 的处理刻意不同。
|
|
234
|
+
*
|
|
235
|
+
* `blocked` 是「等归一」的待办,不是失败,所以它不阻断;而这里是某一张卡没写成功
|
|
236
|
+
* (模型报错、写库失败),此时发布索引等于把一个半成品当成品推给召回 ——
|
|
237
|
+
* 而重试的代价很小:已经物化好的那些分组指纹没变,下一次会被判成 `current` 直接跳过。
|
|
238
|
+
*/
|
|
239
|
+
if (current.failed) return this.patch(id, { state: current.failed === current.total ? 'failed' : 'partial', finishedAt: new Date().toISOString(), summary: `物化结束:成功 ${current.total - current.failed}/${current.total};已完成卡片保留,可重试。` })
|
|
240
|
+
continue
|
|
241
|
+
}
|
|
242
|
+
this.patch(id, { total: sources.length })
|
|
243
|
+
for (const source of sources) {
|
|
244
|
+
await this.checkpoint(id)
|
|
245
|
+
this.store.event(id, 'progress', `${PIPELINE_STAGE_LABEL[stage]}:${source.title}`, source.sourceId, stage)
|
|
246
|
+
const output = this.output(id, stage, source.sourceId)
|
|
247
|
+
let reused = false
|
|
248
|
+
try {
|
|
249
|
+
if (stage === 'extract') {
|
|
250
|
+
const fingerprint = await this.host.fingerprint(source, context)
|
|
251
|
+
const cached = task.selection.force ? undefined : this.store.cached(source.sourceId, source.version, fingerprint)
|
|
252
|
+
if (cached) { this.store.selectExtraction(source.sourceId, cached.id); reused = true }
|
|
253
|
+
else {
|
|
254
|
+
const report = await this.host.extract(source, context, output.append)
|
|
255
|
+
if (this.closed) throw new TaskCancelled('知识库已关闭,已完成结果保留')
|
|
256
|
+
const checkpoint: ExtractionCheckpoint = { id: `extract_${randomUUID()}`, sourceId: source.sourceId, sourceVersion: source.version, sourceHash: source.sourceHash, fingerprint, report, createdAt: new Date().toISOString() }
|
|
257
|
+
// The host checks the captured source version again before activation.
|
|
258
|
+
// Read that one source back, not the whole library: the old form re-hashed
|
|
259
|
+
// every document body once per document, which is O(N²) over a big base.
|
|
260
|
+
const current = await this.host.source(source.sourceId)
|
|
261
|
+
if (!current || current.version !== source.version || current.sourceHash !== source.sourceHash) {
|
|
262
|
+
await this.host.record(checkpoint)
|
|
263
|
+
this.store.event(id, 'report', checkpoint.id, source.sourceId, stage)
|
|
264
|
+
throw new Error('来源在抽取期间已变化;返回已保留在历史中,请抽取最新版本')
|
|
265
|
+
}
|
|
266
|
+
await this.host.record(checkpoint)
|
|
267
|
+
this.store.event(id, 'report', checkpoint.id, source.sourceId, stage)
|
|
268
|
+
/**
|
|
269
|
+
* 没通过校验时**要说清是哪一条不合格**(0070)。
|
|
270
|
+
*
|
|
271
|
+
* 原来只报一句 `model.why`(「抽取返回未通过校验」),"哪些引文对不上" 只留在
|
|
272
|
+
* 审计报告里,而人看不到那一层。现在把 `exceptions` 的前三条带进错误里 ——
|
|
273
|
+
* 面板上的失败行直接能读出原因。
|
|
274
|
+
*
|
|
275
|
+
* 这里**不缓存**这一份失败返回(试过,退回去了):缓存会让下一次重跑不再调模型,
|
|
276
|
+
* 而同一个阶段结束时的承诺是「可重试此阶段」——「重试」按下去什么都不发生,
|
|
277
|
+
* 比多花一次模型调用糟得多。完整返回已经由 `host.record` 收进审计库。
|
|
278
|
+
*/
|
|
279
|
+
if (report.model.parsed !== true) {
|
|
280
|
+
const detail = report.exceptions.slice(0, 3).map(item => `${item.step}:${item.message}`).join(';')
|
|
281
|
+
throw new Error(`${report.model.why ?? '抽取返回未通过校验'}${detail === '' ? '' : `(${detail})`}`)
|
|
282
|
+
}
|
|
283
|
+
this.store.saveExtraction(checkpoint)
|
|
284
|
+
}
|
|
285
|
+
} else {
|
|
286
|
+
const checkpoint = this.store.head(source.sourceId).extracted
|
|
287
|
+
if (!checkpoint) throw new Error('尚无抽取结果,请先运行抽取')
|
|
288
|
+
if (checkpoint.sourceVersion !== source.version || checkpoint.sourceHash !== source.sourceHash) throw new Error('抽取结果依据旧版来源,请先抽取最新版本')
|
|
289
|
+
const result = await this.host.normalize(source, checkpoint, context, task.selection.force === true, output.append)
|
|
290
|
+
reused = result.reused
|
|
291
|
+
if (result.warnings.length) this.patch(id, { warnings: [...this.store.task(id)!.warnings, ...result.warnings.map(warning => `${source.title}:${warning}`)] })
|
|
292
|
+
for (const warning of result.warnings) this.store.event(id, 'warning', warning, source.sourceId, stage)
|
|
293
|
+
}
|
|
294
|
+
} catch (cause) {
|
|
295
|
+
if (cause instanceof TaskCancelled) throw cause
|
|
296
|
+
const message = `${source.title}:${cause instanceof Error ? cause.message : String(cause)}`
|
|
297
|
+
const current = this.store.task(id)!
|
|
298
|
+
this.patch(id, { failed: current.failed + 1, warnings: [...current.warnings, message] })
|
|
299
|
+
this.store.event(id, 'warning', message, source.sourceId, stage)
|
|
300
|
+
} finally { output.flush() }
|
|
301
|
+
const current = this.store.task(id)!
|
|
302
|
+
this.patch(id, { done: current.done + 1, reused: current.reused + Number(reused), summary: `${PIPELINE_STAGE_LABEL[stage]} ${current.done + 1}/${sources.length}${reused ? ' · 复用已有结果' : ''}` })
|
|
303
|
+
}
|
|
304
|
+
this.finishStage(id)
|
|
305
|
+
if (this.store.task(id)!.failed > 0) {
|
|
306
|
+
const current = this.store.task(id)!
|
|
307
|
+
this.patch(id, { state: current.failed === current.total ? 'failed' : 'partial', finishedAt: new Date().toISOString(), summary: `${PIPELINE_STAGE_LABEL[stage]}结束:成功 ${current.total - current.failed}/${current.total},失败 ${current.failed};已完成结果保留,可重试此阶段。` })
|
|
308
|
+
return this.store.task(id)!
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
await this.checkpoint(id)
|
|
312
|
+
const current = this.store.task(id)!
|
|
313
|
+
/**
|
|
314
|
+
* `deferred > 0` 时状态是 `partial`:这一趟把能做的都做了(包括发布索引),
|
|
315
|
+
* 但还有一批分组在等归一。报 `succeeded` 会让人以为「物化完了」。
|
|
316
|
+
*/
|
|
317
|
+
const suffix = deferred > 0 ? ` · 另有 ${deferred} 条 Knowledge 待处理(坐标、来源、方法完整性或 Case 版本),暂未物化` : ''
|
|
318
|
+
return this.patch(id, { state: deferred > 0 ? 'partial' : 'succeeded', finishedAt: new Date().toISOString(), summary: (task.stage === 'all' ? `全链路完成 · 抽取 ${current.results?.extract?.done ?? 0} 份(复用 ${current.results?.extract?.reused ?? 0} 份) · 物化 ${current.results?.materialize?.done ?? 0} 张 · 索引已发布` : `${PIPELINE_STAGE_LABEL[task.stage]}完成 · 处理 ${current.done} 项 · 复用 ${current.reused} 项`) + suffix })
|
|
319
|
+
} catch (cause) {
|
|
320
|
+
return this.patch(id, { state: cause instanceof TaskCancelled ? 'cancelled' : 'failed', finishedAt: new Date().toISOString(), summary: cause instanceof Error ? cause.message : String(cause) })
|
|
321
|
+
} finally { this.controls.delete(id) }
|
|
322
|
+
}
|
|
323
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
import type { SqliteDatabase } from '../fts.js'
|
|
2
|
+
import { applyRetention } from '../retention.js'
|
|
3
|
+
import type { TrialReport } from '../wiki-trial-types.js'
|
|
4
|
+
import type { PipelineEvent, PipelineTask } from './types.js'
|
|
5
|
+
|
|
6
|
+
export interface ExtractionCheckpoint {
|
|
7
|
+
id: string
|
|
8
|
+
sourceId: string
|
|
9
|
+
sourceVersion: number
|
|
10
|
+
sourceHash: string
|
|
11
|
+
fingerprint: string
|
|
12
|
+
report: TrialReport
|
|
13
|
+
createdAt: string
|
|
14
|
+
normalized?: { report: TrialReport; knowledgeIds: Record<string, string>; eventIds: Record<string, string>; fingerprint: string; unresolvedKnowledgeIds?: string[] }
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/** Business checkpoints live with truth; execution history lives with extraction audits. */
|
|
18
|
+
export class PipelineStore {
|
|
19
|
+
constructor(readonly truth: SqliteDatabase, private readonly audit: SqliteDatabase) {
|
|
20
|
+
truth.exec(`
|
|
21
|
+
CREATE TABLE IF NOT EXISTS pipeline_extractions (
|
|
22
|
+
id TEXT PRIMARY KEY, source_id TEXT NOT NULL, source_version INTEGER NOT NULL,
|
|
23
|
+
source_hash TEXT NOT NULL, fingerprint TEXT NOT NULL, report TEXT NOT NULL,
|
|
24
|
+
normalized TEXT, created_at TEXT NOT NULL
|
|
25
|
+
);
|
|
26
|
+
CREATE INDEX IF NOT EXISTS pipeline_extract_cache ON pipeline_extractions(source_id, source_version, fingerprint);
|
|
27
|
+
CREATE TABLE IF NOT EXISTS pipeline_sources (source_id TEXT PRIMARY KEY, extracted_id TEXT, normalized_id TEXT);
|
|
28
|
+
CREATE TABLE IF NOT EXISTS pipeline_materializations (group_key TEXT PRIMARY KEY, fingerprint TEXT NOT NULL, card_id TEXT NOT NULL);
|
|
29
|
+
`)
|
|
30
|
+
audit.exec(`
|
|
31
|
+
CREATE TABLE IF NOT EXISTS pipeline_tasks (id TEXT PRIMARY KEY, queued_at TEXT NOT NULL, state TEXT NOT NULL, payload TEXT NOT NULL);
|
|
32
|
+
CREATE INDEX IF NOT EXISTS pipeline_tasks_time ON pipeline_tasks(queued_at DESC);
|
|
33
|
+
CREATE TABLE IF NOT EXISTS pipeline_events (
|
|
34
|
+
seq INTEGER PRIMARY KEY AUTOINCREMENT, task_id TEXT NOT NULL, kind TEXT NOT NULL,
|
|
35
|
+
text TEXT NOT NULL, source_id TEXT, at TEXT NOT NULL, stage TEXT
|
|
36
|
+
);
|
|
37
|
+
CREATE INDEX IF NOT EXISTS pipeline_events_task ON pipeline_events(task_id, seq);
|
|
38
|
+
`)
|
|
39
|
+
const eventColumns = audit.prepare('PRAGMA table_info(pipeline_events)').all() as Array<{ name: string }>
|
|
40
|
+
if (!eventColumns.some(column => column.name === 'stage')) audit.exec('ALTER TABLE pipeline_events ADD COLUMN stage TEXT')
|
|
41
|
+
// A new runtime never claims that an abandoned request is still running.
|
|
42
|
+
for (const task of (audit.prepare("SELECT payload FROM pipeline_tasks WHERE state IN ('queued','running','pausing','paused','cancelling')").all() as Array<{ payload: string }>).map(row => JSON.parse(row.payload) as PipelineTask)) {
|
|
43
|
+
if (['queued', 'running', 'pausing', 'paused', 'cancelling'].includes(task.state)) {
|
|
44
|
+
this.putTask({ ...task, state: 'interrupted', finishedAt: new Date().toISOString(), summary: '服务已重新启动;已完成的阶段保留,可重新运行此任务。' })
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
putTask(task: PipelineTask): void {
|
|
50
|
+
this.audit.prepare('INSERT INTO pipeline_tasks(id, queued_at, state, payload) VALUES (?, ?, ?, ?) ON CONFLICT(id) DO UPDATE SET state=excluded.state, payload=excluded.payload')
|
|
51
|
+
.run(task.id, task.queuedAt, task.state, JSON.stringify(task))
|
|
52
|
+
this.pruneAudit()
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* 审计库的保留上限(0070)。
|
|
57
|
+
*
|
|
58
|
+
* 实时预览每 250ms 或每 1KB 落一行,一次五分钟的抽取就能加一千行,而这里原来一条
|
|
59
|
+
* `DELETE` 都没有。上限是「水位以上保留」:升级那一刻已有的任务与事件一行不删
|
|
60
|
+
* (见 `retention.ts`)。任务的保留上限同时也是事件的:先按任务裁,再把已经不存在的
|
|
61
|
+
* 那些任务的事件(同样只在水位以上)删掉,最后兜一层总量。
|
|
62
|
+
*/
|
|
63
|
+
private pruneAudit(): void {
|
|
64
|
+
applyRetention(this.audit, 'pipeline_tasks', { table: 'pipeline_tasks', key: 'rowid', keep: 200 })
|
|
65
|
+
applyRetention(this.audit, 'pipeline_events', { table: 'pipeline_events', key: 'seq', keep: 50_000, where: 'task_id NOT IN (SELECT id FROM pipeline_tasks)' })
|
|
66
|
+
applyRetention(this.audit, 'pipeline_events', { table: 'pipeline_events', key: 'seq', keep: 50_000 })
|
|
67
|
+
}
|
|
68
|
+
task(id: string): PipelineTask | undefined {
|
|
69
|
+
const row = this.audit.prepare('SELECT payload FROM pipeline_tasks WHERE id=?').get(id) as { payload: string } | undefined
|
|
70
|
+
return row ? JSON.parse(row.payload) as PipelineTask : undefined
|
|
71
|
+
}
|
|
72
|
+
tasks(limit = 20, offset = 0): { tasks: PipelineTask[]; total: number } {
|
|
73
|
+
const rows = this.audit.prepare("SELECT payload FROM pipeline_tasks ORDER BY CASE WHEN state IN ('queued','running','pausing','paused','cancelling') THEN 0 ELSE 1 END, queued_at DESC LIMIT ? OFFSET ?")
|
|
74
|
+
.all(Math.max(1, Math.min(10000, limit)), Math.max(0, offset)) as Array<{ payload: string }>
|
|
75
|
+
const total = Number((this.audit.prepare('SELECT COUNT(*) AS n FROM pipeline_tasks').get() as { n: number }).n)
|
|
76
|
+
return { tasks: rows.map(row => JSON.parse(row.payload) as PipelineTask), total }
|
|
77
|
+
}
|
|
78
|
+
event(taskId: string, kind: PipelineEvent['kind'], text: string, sourceId?: string, stage?: PipelineEvent['stage']): void {
|
|
79
|
+
this.audit.prepare('INSERT INTO pipeline_events(task_id,kind,text,source_id,at,stage) VALUES (?,?,?,?,?,?)')
|
|
80
|
+
.run(taskId, kind, text, sourceId ?? null, new Date().toISOString(), stage ?? null)
|
|
81
|
+
}
|
|
82
|
+
events(taskId: string, after = 0, limit = 100): { events: PipelineEvent[]; next: number; hasMore: boolean } {
|
|
83
|
+
const take = Number.isFinite(limit) ? Math.max(1, Math.min(500, Math.trunc(limit))) : 100
|
|
84
|
+
after = Number.isFinite(after) ? Math.max(0, Math.trunc(after)) : 0
|
|
85
|
+
const rows = this.audit.prepare('SELECT * FROM pipeline_events WHERE task_id=? AND seq>? ORDER BY seq LIMIT ?')
|
|
86
|
+
.all(taskId, after, take + 1) as Array<Record<string, unknown>>
|
|
87
|
+
const hasMore = rows.length > take
|
|
88
|
+
const events = rows.slice(0, take).map(row => ({ seq: Number(row.seq), taskId: String(row.task_id), kind: String(row.kind) as PipelineEvent['kind'], text: String(row.text), ...(row.source_id ? { sourceId: String(row.source_id) } : {}), ...(row.stage ? { stage: String(row.stage) as PipelineEvent['stage'] } : {}), at: String(row.at) }))
|
|
89
|
+
return { events, next: events.at(-1)?.seq ?? after, hasMore }
|
|
90
|
+
}
|
|
91
|
+
checkpoint(id: string): ExtractionCheckpoint | undefined {
|
|
92
|
+
const row = this.truth.prepare('SELECT * FROM pipeline_extractions WHERE id=?').get(id) as Record<string, unknown> | undefined
|
|
93
|
+
return row ? { id: String(row.id), sourceId: String(row.source_id), sourceVersion: Number(row.source_version), sourceHash: String(row.source_hash), fingerprint: String(row.fingerprint), report: JSON.parse(String(row.report)), createdAt: String(row.created_at), ...(row.normalized ? { normalized: JSON.parse(String(row.normalized)) } : {}) } : undefined
|
|
94
|
+
}
|
|
95
|
+
cached(sourceId: string, version: number, fingerprint: string): ExtractionCheckpoint | undefined {
|
|
96
|
+
const row = this.truth.prepare('SELECT id FROM pipeline_extractions WHERE source_id=? AND source_version=? AND fingerprint=? ORDER BY created_at DESC, rowid DESC LIMIT 1')
|
|
97
|
+
.get(sourceId, version, fingerprint) as { id: string } | undefined
|
|
98
|
+
return row ? this.checkpoint(row.id) : undefined
|
|
99
|
+
}
|
|
100
|
+
head(sourceId: string): { extracted?: ExtractionCheckpoint; normalized?: ExtractionCheckpoint } {
|
|
101
|
+
const row = this.truth.prepare('SELECT extracted_id,normalized_id FROM pipeline_sources WHERE source_id=?').get(sourceId) as { extracted_id?: string; normalized_id?: string } | undefined
|
|
102
|
+
return { extracted: row?.extracted_id ? this.checkpoint(row.extracted_id) : undefined, normalized: row?.normalized_id ? this.checkpoint(row.normalized_id) : undefined }
|
|
103
|
+
}
|
|
104
|
+
saveExtraction(value: ExtractionCheckpoint): void {
|
|
105
|
+
this.truth.exec('SAVEPOINT pipeline_extract')
|
|
106
|
+
try {
|
|
107
|
+
this.truth.prepare('INSERT INTO pipeline_extractions(id,source_id,source_version,source_hash,fingerprint,report,created_at) VALUES (?,?,?,?,?,?,?)')
|
|
108
|
+
.run(value.id, value.sourceId, value.sourceVersion, value.sourceHash, value.fingerprint, JSON.stringify(value.report), value.createdAt)
|
|
109
|
+
this.selectExtraction(value.sourceId, value.id)
|
|
110
|
+
this.truth.exec('RELEASE pipeline_extract')
|
|
111
|
+
} catch (cause) { this.truth.exec('ROLLBACK TO pipeline_extract; RELEASE pipeline_extract'); throw cause }
|
|
112
|
+
}
|
|
113
|
+
selectExtraction(sourceId: string, id: string): void {
|
|
114
|
+
this.truth.prepare('INSERT INTO pipeline_sources(source_id,extracted_id) VALUES (?,?) ON CONFLICT(source_id) DO UPDATE SET extracted_id=excluded.extracted_id').run(sourceId, id)
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* 刷新一份抽取检查点的指纹(0070)。
|
|
118
|
+
*
|
|
119
|
+
* 指纹里含「本文提到的实体清单」,而归一会往注册表里学新实体 —— 它们本来就在这份
|
|
120
|
+
* 文档里,所以学完之后指纹必然变。不刷新的话,同一份未改动的文档下次抽取一定复用不上
|
|
121
|
+
* (每次都要再调一次模型)。归一成功后把这一行改成学完之后的值,复用才成立。
|
|
122
|
+
*/
|
|
123
|
+
refreshFingerprint(id: string, fingerprint: string): void {
|
|
124
|
+
this.truth.prepare('UPDATE pipeline_extractions SET fingerprint=? WHERE id=?').run(fingerprint, id)
|
|
125
|
+
}
|
|
126
|
+
saveNormalization(value: ExtractionCheckpoint, normalized: NonNullable<ExtractionCheckpoint['normalized']>): void {
|
|
127
|
+
this.truth.prepare('UPDATE pipeline_extractions SET normalized=? WHERE id=?').run(JSON.stringify(normalized), value.id)
|
|
128
|
+
this.truth.prepare('INSERT INTO pipeline_sources(source_id,normalized_id) VALUES (?,?) ON CONFLICT(source_id) DO UPDATE SET normalized_id=excluded.normalized_id').run(value.sourceId, value.id)
|
|
129
|
+
}
|
|
130
|
+
unresolvedKnowledge(): { ids: Set<string>; sources: Set<string> } {
|
|
131
|
+
const rows = this.truth.prepare('SELECT s.source_id, e.normalized FROM pipeline_sources s JOIN pipeline_extractions e ON e.id=s.normalized_id WHERE e.normalized IS NOT NULL').all() as Array<{ source_id: string; normalized: string }>
|
|
132
|
+
const ids = new Set<string>(); const sources = new Set<string>()
|
|
133
|
+
for (const row of rows) {
|
|
134
|
+
const pending = (JSON.parse(row.normalized) as NonNullable<ExtractionCheckpoint['normalized']>).unresolvedKnowledgeIds ?? []
|
|
135
|
+
if (pending.length) sources.add(row.source_id)
|
|
136
|
+
for (const id of pending) ids.add(id)
|
|
137
|
+
}
|
|
138
|
+
return { ids, sources }
|
|
139
|
+
}
|
|
140
|
+
materialization(key: string): { fingerprint: string; cardId: string } | undefined {
|
|
141
|
+
const row = this.truth.prepare('SELECT fingerprint,card_id FROM pipeline_materializations WHERE group_key=?').get(key) as { fingerprint: string; card_id: string } | undefined
|
|
142
|
+
return row ? { fingerprint: row.fingerprint, cardId: row.card_id } : undefined
|
|
143
|
+
}
|
|
144
|
+
materialized(key: string, fingerprint: string, cardId: string): void {
|
|
145
|
+
this.truth.prepare('INSERT INTO pipeline_materializations(group_key,fingerprint,card_id) VALUES (?,?,?) ON CONFLICT(group_key) DO UPDATE SET fingerprint=excluded.fingerprint,card_id=excluded.card_id').run(key, fingerprint, cardId)
|
|
146
|
+
}
|
|
147
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/** Shared, browser-safe contracts for independently runnable knowledge stages. */
|
|
2
|
+
export type PipelineStage = 'extract' | 'normalize' | 'derive' | 'materialize' | 'build' | 'all'
|
|
3
|
+
export type PipelineState = 'queued' | 'running' | 'pausing' | 'paused' | 'cancelling' | 'succeeded' | 'partial' | 'failed' | 'cancelled' | 'interrupted'
|
|
4
|
+
export type PipelineAction = 'pause' | 'resume' | 'cancel'
|
|
5
|
+
|
|
6
|
+
export interface PipelineSelection {
|
|
7
|
+
sourceIds?: string[]
|
|
8
|
+
groupKeys?: string[]
|
|
9
|
+
force?: boolean
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface PipelineModel {
|
|
13
|
+
provider?: string
|
|
14
|
+
model?: string
|
|
15
|
+
reasoningEffort?: string
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export interface PipelineTask {
|
|
19
|
+
id: string
|
|
20
|
+
stage: PipelineStage
|
|
21
|
+
state: PipelineState
|
|
22
|
+
selection: PipelineSelection
|
|
23
|
+
model: PipelineModel
|
|
24
|
+
queuedAt: string
|
|
25
|
+
startedAt?: string
|
|
26
|
+
finishedAt?: string
|
|
27
|
+
currentStage?: Exclude<PipelineStage, 'all'>
|
|
28
|
+
done: number
|
|
29
|
+
total: number
|
|
30
|
+
reused: number
|
|
31
|
+
failed: number
|
|
32
|
+
summary: string
|
|
33
|
+
warnings: string[]
|
|
34
|
+
results?: Partial<Record<Exclude<PipelineStage, 'all'>, { done: number; total: number; reused: number; failed: number; summary?: string; skipped?: boolean }>>
|
|
35
|
+
legacy?: boolean
|
|
36
|
+
reportId?: string
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface PipelineEvent {
|
|
40
|
+
seq: number
|
|
41
|
+
taskId: string
|
|
42
|
+
kind: 'output' | 'progress' | 'warning' | 'report'
|
|
43
|
+
text: string
|
|
44
|
+
sourceId?: string
|
|
45
|
+
stage?: Exclude<PipelineStage, 'all'>
|
|
46
|
+
at: string
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface MaterializationGroup {
|
|
50
|
+
wikiKind?: 'fact' | 'way'
|
|
51
|
+
key: string
|
|
52
|
+
title: string
|
|
53
|
+
coordinate: { objectId: string; actionId: string; sceneId: string }
|
|
54
|
+
knowledgeCount: number
|
|
55
|
+
eventCount: number
|
|
56
|
+
sourceIds: string[]
|
|
57
|
+
cardId?: string
|
|
58
|
+
state: 'new' | 'changed' | 'current' | 'withdrawn' | 'blocked'
|
|
59
|
+
reason?: string
|
|
60
|
+
fingerprint: string
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* 物化阶段的批(宿主产生、宿主消费)。
|
|
65
|
+
*
|
|
66
|
+
* `snapshot` 对引擎是**不透明的**:它的字段类型来自服务端模块(Knowledge / EventEntity /
|
|
67
|
+
* 图片 / 相关推荐),而那些模块都依赖 `node:*`。本模块被客户端 import 取值,所以这里
|
|
68
|
+
* 不能描述它 —— 真正的形状在 `materialize-snapshot.ts`,只有服务端看得见。
|
|
69
|
+
* 引擎只负责把 `snapshot` 原样传回 `materialize()`。
|
|
70
|
+
*/
|
|
71
|
+
export interface MaterializationBatch {
|
|
72
|
+
groups: MaterializationGroup[]
|
|
73
|
+
/** 坐标仍有歧义 + 等待归一,两部分的合计。 */
|
|
74
|
+
blocked: number
|
|
75
|
+
blockedAmbiguous: number
|
|
76
|
+
blockedAwaitingNormalize: number
|
|
77
|
+
snapshot: unknown
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export interface PipelineStatus {
|
|
81
|
+
sources: Array<{ id: string; title: string; version: number; extractionId?: string; normalizedId?: string; state: 'pending' | 'extracted' | 'normalized' | 'outdated' }>
|
|
82
|
+
groups: MaterializationGroup[]
|
|
83
|
+
blocked: number
|
|
84
|
+
pendingNew: number
|
|
85
|
+
pendingUpdated: number
|
|
86
|
+
pendingWithdrawn: number
|
|
87
|
+
indexPending: boolean
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export const PIPELINE_STAGE_LABEL: Record<PipelineStage, string> = {
|
|
91
|
+
extract: '抽取 Knowledge', normalize: '归一三轴与记录', derive: 'Case 提炼 Procedure', materialize: '组织 Wiki', build: '构建检索索引', all: '全链路运行',
|
|
92
|
+
}
|
|
93
|
+
export const PIPELINE_ACTIVE_STATES: readonly PipelineState[] = ['queued', 'running', 'pausing', 'paused', 'cancelling']
|
package/src/present.ts
CHANGED
|
@@ -54,6 +54,7 @@ function short(text: string, max = 48): string {
|
|
|
54
54
|
export interface ImportMetaSource { sourceId: string; title?: string; bytes: number }
|
|
55
55
|
export interface ImportMetaFailure { index: number; title?: string; code: string; message: string }
|
|
56
56
|
export interface ImportMetaCompile {
|
|
57
|
+
taskId?: string; state?: string
|
|
57
58
|
cardsCreated: number; cardsUpdated: number; cardsReused?: number
|
|
58
59
|
notesReused?: number; notesRecompiled?: number
|
|
59
60
|
sourcesExtracted?: number; sourcesSkipped?: number; cardsRemoved?: number
|
|
@@ -101,7 +102,7 @@ export function importCallView(args: { sources?: unknown[]; compile?: boolean })
|
|
|
101
102
|
return {
|
|
102
103
|
card: 'generic',
|
|
103
104
|
kind: 'edit',
|
|
104
|
-
title: `导入 ${count} 份来源${args?.compile ===
|
|
105
|
+
title: `导入 ${count} 份来源${args?.compile === true ? '并处理知识' : ''}`,
|
|
105
106
|
rawInput: titles.length > 0 ? titles.map(title => short(title)) : { 份数: count },
|
|
106
107
|
}
|
|
107
108
|
}
|
|
@@ -112,10 +113,15 @@ export function importResultMarkdown(meta: ImportMeta): string {
|
|
|
112
113
|
for (const item of meta.written) lines.push(`- ${item.title ? `**${short(item.title)}**` : item.sourceId} · ${item.bytes} 字符`)
|
|
113
114
|
for (const item of meta.failed) lines.push(`- 第 ${item.index + 1} 份${item.title ? `「${short(item.title)}」` : ''}失败:${item.code} ${item.message}`)
|
|
114
115
|
if (meta.compile) {
|
|
115
|
-
const { cardsCreated, cardsUpdated, cardsReused, notesReused, notesRecompiled, embedding, version } = meta.compile
|
|
116
|
+
const { cardsCreated, cardsUpdated, cardsReused, notesReused, notesRecompiled, embedding, version, state, taskId } = meta.compile
|
|
117
|
+
if (state) {
|
|
118
|
+
const label = state === 'succeeded' ? '已完成' : state === 'partial' ? '部分完成' : state === 'cancelled' ? '已停止' : '未完成'
|
|
119
|
+
lines.push('', `知识处理${label}:新建 ${cardsCreated} 张、更新 ${cardsUpdated} 张。${taskId ? `任务:${taskId}。` : ''}详情请打开「知识处理」页的运行记录。`)
|
|
120
|
+
return lines.join('\n')
|
|
121
|
+
}
|
|
116
122
|
lines.push('', `编译:新建 ${cardsCreated} 张、并入 ${cardsUpdated} 张、复用 ${cardsReused ?? 0} 张;召回片段复用 ${notesReused ?? 0} 条、重编 ${notesRecompiled ?? 0} 条;索引 v${version ?? '?'}${embedding ? `(向量 ${embedding})` : ''}。`)
|
|
117
123
|
} else {
|
|
118
|
-
lines.push('', '
|
|
124
|
+
lines.push('', '这次只保存来源(默认 `compile: false`)。下一步使用 `run_knowledge_pipeline` 分别抽取、归一、从 Case 提炼 Procedure、组织 Wiki,最后构建检索索引。')
|
|
119
125
|
}
|
|
120
126
|
return lines.join('\n')
|
|
121
127
|
}
|
|
@@ -314,7 +320,7 @@ export function addSourceCallView(args: { title?: string; content?: string }): {
|
|
|
314
320
|
}
|
|
315
321
|
|
|
316
322
|
export function addSourceResultMarkdown(meta: AddSourceMeta): string {
|
|
317
|
-
return `**来源已写入** —— 「${meta.title ? short(meta.title) : meta.sourceId}」(${meta.bytes} 字符)。\n\n下一步:\`
|
|
323
|
+
return `**来源已写入** —— 「${meta.title ? short(meta.title) : meta.sourceId}」(${meta.bytes} 字符)。\n\n下一步:\`run_knowledge_pipeline\` 分别抽取、归一、从 Case 提炼 Procedure、组织 Wiki,最后构建检索索引。`
|
|
318
324
|
}
|
|
319
325
|
|
|
320
326
|
export interface WriteCardsMeta {
|