@avantf/dsh-mem 0.6.3 → 0.7.0

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.
@@ -1,7 +1,7 @@
1
1
  {
2
- "@deepseek-ai/dsh-system-prompt": "0.2.0-rc.2",
3
- "@deepseek-ai/dsh-tools": "0.2.0-rc.2",
4
- "@deepseek-ai/dsh-typert-protocol": "0.2.0-rc.2",
5
- "@deepseek-ai/dsh-typert-registry": "0.2.0-rc.2",
6
- "@deepseek-ai/dsh-util-values": "0.2.0-rc.2"
2
+ "@deepseek-ai/dsh-system-prompt": "0.2.1-rc.2",
3
+ "@deepseek-ai/dsh-tools": "0.2.1-rc.2",
4
+ "@deepseek-ai/dsh-typert-protocol": "0.2.1-rc.2",
5
+ "@deepseek-ai/dsh-typert-registry": "0.2.1-rc.2",
6
+ "@deepseek-ai/dsh-util-values": "0.2.1-rc.2"
7
7
  }
@@ -15,7 +15,7 @@ import type { AvantfLogger } from '../../mem-contract/index.js';
15
15
  * UNCOMMENTED line is warned about by the loader, so a wrong name here would be a trap rather than a
16
16
  * hint. `config_files.spec.ts` pins the ones this template names.
17
17
  */
18
- export declare const DEFAULT_COMMON_CONFIG = "# avantf-mem \u516C\u5171\u914D\u7F6E\uFF08\u5206\u5C42\u7B2C\u2461\u5C42\uFF09\u3002\u8FD9\u91CC\u5168\u662F\u6CE8\u91CA\uFF1A\u5220\u6389/\u7559\u7A7A = \u7528\u5185\u5EFA\u9ED8\u8BA4\uFF0C\u53D6\u6D88\u6CE8\u91CA\u5373\u751F\u6548\u3002\n# \u5206\u5C42\uFF08\u4F4E\u2192\u9AD8\uFF09\uFF1A\u2460 \u5185\u5EFA\u9ED8\u8BA4 \u2192 \u2461 \u672C\u6587\u4EF6 \u2192 \u2462 \u540C\u76EE\u5F55\u7684 memory.yaml / knowledge.yaml\uFF08\u7F3A\u5931=\u4E0D\u8986\u76D6\uFF09\n# \u2192 \u2463 \u73AF\u5883\u53D8\u91CF \u2192 \u2464 \u63D2\u4EF6/CLI \u663E\u5F0F\u4F20\u53C2\n# \u6240\u6709\u53EF\u7F16\u8F91\u6587\u672C\u90FD\u5728 ~/.avantf \u4E0B\uFF1Aconfigs/*.yaml\uFF08\u672C\u76EE\u5F55\uFF09\u4E0E prompts/*.md\uFF08\u6A21\u578B\u63D0\u793A\u8BCD\uFF09\u3002\n\n# \u6570\u636E\u6839\u4E0D\u5728\u8FD9\u91CC\u914D\uFF1A\u5B83\u7531 \u2463 AVANTF_HOME\uFF08\u6216 CLI --data-home\u3001\u63D2\u4EF6 profile \u7684 dataHome\uFF09\u51B3\u5B9A \u2014\u2014\n# \u672C\u6587\u4EF6\u5C31\u5728\u6570\u636E\u6839\u91CC\u9762\uFF0C\u89E3\u6790\u6839\u7684\u65F6\u5019\u8FD8\u6CA1\u8BFB\u5230\u5B83\uFF0C\u6240\u4EE5\u5199\u5728\u8FD9\u91CC\u7684 dataHome \u5BF9\u6570\u636E\u6839\u65E0\u6548\uFF08DESIGN \u00A73\uFF09\u3002\n\n# semantic: # \u5D4C\u5165\u540E\u7AEF\uFF08\u8BB0\u5FC6\u4E0E\u77E5\u8BC6\u5171\u7528\uFF0C\u8DE8\u5E93\u5206\u6570\u624D\u53EF\u6BD4\uFF09\n# backend: local_bge\n# local_model: Xenova/bge-base-zh-v1.5 # \u5FC5\u987B\u662F ONNX \u4ED3\u5E93\n# dim: 768\n# auto_download: true\n# auto_migrate: true # \u6362\u6A21\u578B/\u5BBD\u5EA6\u540E\u81EA\u52A8\u5206\u6279\u91CD\u7B97\u65E7\u7A7A\u95F4\u7684\u5411\u91CF\uFF08\u9ED8\u8BA4\u5F00\uFF09\uFF1B\u5173\u6389\u53EA\u5269\u542F\u52A8\u544A\u8B66 + vectors --fix\n# \u26A0\uFE0F cache_dir / mirror \u7531\u5BB6\u65CF\u5E95\u5EA7 @avantf/dsh-plugin-base \u7BA1\u7406\uFF1A\u5199\u5728\u8FD9\u91CC\u4F1A\u88AB\u5FFD\u7565\u5E76\u544A\u8B66\u3002\n# \u7F13\u5B58\u76EE\u5F55\u7528\u73AF\u5883\u53D8\u91CF AVANTF_MEM_MODEL_CACHE\uFF0C\u955C\u50CF\u7528 AVANTF_MEM_MODEL_MIRROR\uFF08\u6216 HF_ENDPOINT\uFF09\u3002\n\n# vectorStore:\n# backend: auto # auto = \u8D8A\u8FC7\u9608\u503C\u81EA\u52A8\u4ECE local_numpy \u8FC1\u5230 hnswlib\n# auto_thresholds:\n# hnswlib: 2000\n# hnswlib_ef_search: 256 # ANN \u7684\u53EC\u56DE/\u901F\u5EA6\u65CB\u94AE\uFF0C\u8BED\u6599\u53D8\u5927\u5148\u8C03\u5B83\n\n# retriever: # \u4E09\u6761\u68C0\u7D22\u817F\u5728\u878D\u5408\u91CC\u7684\u6743\u91CD\u4E0E\"\u76F8\u5173\u6027\u95E8\u69DB\"\n# weight_semantic: 0.55\n# weight_fts: 0.30\n# weight_jaccard: 0.15\n# # \u7EDD\u5BF9\u95E8\u69DB\u6253\u5728\u6BCF\u6761\u817F\u7684\u539F\u59CB\u5206\u4E0A\u3001fuse() \u4E4B\u524D\uFF08\u878D\u5408\u5206\u53EA\u5728\u4E00\u6B21\u67E5\u8BE2\u5185\u53EF\u6BD4\uFF0C\u4E0D\u80FD\u5F53\u95E8\u69DB\uFF09\u3002\n# # 0 = \u5173\u95ED\u8BE5\u95E8\u69DB\uFF1B\u5206\u6570\u7B49\u4E8E\u95E8\u69DB\u4FDD\u7559\u3002\u8BED\u4E49\u540E\u7AEF\u4E0D\u53EF\u7528\u65F6 min_fts_terms \u7684\u751F\u6548\u503C\u653E\u5BBD\u5230 1\u3002\n# min_semantic_similarity: 0.5 # \u8BED\u4E49\u817F\u4F59\u5F26\uFF1B0.5 \u53EA\u5BF9 bge-base-zh-v1.5/768\uFF08mean pooling\uFF09\u6807\u5B9A\u8FC7\uFF0C\u6362\u6A21\u578B\u8981\u91CD\u6807\n# min_fts_terms: 2 # FTS \u817F\uFF1A\u8FD9\u4E00\u884C\u547D\u4E2D\u51E0\u4E2A\u4E0D\u540C\u7684\u67E5\u8BE2\u8BCD\u5143\uFF08\u62C9\u4E01\u8BCD\u22655\u5B57\u7B26 + CJK 3-gram\uFF09\n# min_jaccard: 0.2 # \u5B9E\u4F53\u817F\uFF1A\u951A\u70B9\u5B9E\u4F53\u7684 Jaccard\uFF08\u4E8B\u5B9E\u5BBD\u5EA6\u9971\u548C\uFF09\uFF1B2 \u5B9E\u4F53\u547D\u4E2D 1 \u4E2A\u6B63\u597D 0.2\n# # P-11 \u4E2D\u6587\u65F6\u95F4\u7A97\u817F\uFF08\u9ED8\u8BA4\u5173\uFF09\uFF1A\u5F00\u542F\u540E\uFF0C\u5E26\u4E2D\u6587\u65F6\u95F4\u8868\u8FBE\u7684\u67E5\u8BE2\uFF08\u4E0A\u4E2A\u6708 / \u6700\u8FD1\u4E09\u5929 / 2026\u5E749\u6708 \u2026\uFF09\n# # \u4F1A\u989D\u5916\u628A\"\u4E8B\u4EF6\u65F6\u95F4 valid_from \u843D\u5728\u8BE5\u7A97\u53E3\"\u7684\u6D3B\u8DC3\u4E8B\u5B9E\u4F5C\u4E3A\u4E00\u6761\u817F\u53C2\u4E0E\u878D\u5408\u3002\u5B83\u662F**\u52A0\u4E00\u6761\u817F\u3001\u4E0D\u662F\u8FC7\u6EE4\u5668**\uFF1A\n# # \u53EA\u589E\u52A0\u5019\u9009\uFF0C\u7EDD\u4E0D\u5220\u6389\u8BED\u4E49 / FTS / \u5B9E\u4F53\u817F\u5DF2\u7ECF\u627E\u5230\u7684\u4E8B\u5B9E\uFF1B\u6CA1\u6709\u4E8B\u4EF6\u65F6\u95F4\u7684\u4E8B\u5B9E\u4E0D\u4F5C\u4E3A\u8BE5\u817F\u5019\u9009\uFF0C\n# # \u4E5F**\u4E0D\u56DE\u9000\u5230\u5199\u5165\u65F6\u95F4 created_at**\u3002\u5B83\u5171\u7528 jaccard \u6743\u91CD\u4F4D\uFF08\u5BF9\u5916\u7684\u4E09\u952E\u6743\u91CD\u4E0D\u53D8\uFF09\u3002\n# # \u4EC0\u4E48\u65F6\u5019\u8BE5\u5F00\uFF1A\u5148\u7528 mem_admin stats \u770B validity.coverage\uFF08\u6709\u591A\u5C11\u6D3B\u8DC3\u4E8B\u5B9E\u5E26\u4E8B\u4EF6\u65F6\u95F4\uFF09\uFF0C\n# # \u518D\u7528\u56DE\u5F52\u7F51\u786E\u8BA4\u5B83\u786E\u5B9E\u6539\u5584\u65F6\u95F4\u7C7B\u67E5\u8BE2\u2014\u2014\u8986\u76D6\u7387\u22480 \u65F6\u5B83\u7B49\u4E8E\u6CA1\u5F00\u3002\u5199\u5165\u4E8B\u4EF6\u65F6\u95F4\u7528 mem_remember \u7684 event_date\u3002\n# time_window: false\n\n# lifecycle:\n# purge_after_archived_days: 365 # \u5F52\u6863\u4E8B\u5B9E\u7684\u7269\u7406\u6E05\u7406\u7A97\u53E3\uFF08\u6D3B\u8DC3\u65E5\uFF09\n# contradiction_threshold: 0.6\n\n# trust:\n# decay_per_day: 0.0055\u2026\n# presence:\n# heartbeat_minutes: 60 # \u5E38\u9A7B\u8FDB\u7A0B\u7684\u5FC3\u8DF3\uFF08\u6D3B\u8DC3\u65E5\u65F6\u949F\u4E0E\u751F\u547D\u5468\u671F\u626B\u63CF\uFF09\n\n# tools: # \u5916\u90E8\u4E8C\u8FDB\u5236\uFF08pandoc\uFF09\u7684\u53D7\u7BA1\u76EE\u5F55\n# dir: '' # \u7559\u7A7A = \u5BB6\u65CF\u6839 tools\uFF08~/.avantf/env/tools\uFF09\uFF1BAVANTF_TOOLS_DIR \u53EF\u8986\u76D6\n# auto_install: true\n";
18
+ export declare const DEFAULT_COMMON_CONFIG = "# avantf-mem \u516C\u5171\u914D\u7F6E\uFF08\u5206\u5C42\u7B2C\u2461\u5C42\uFF09\u3002\u8FD9\u91CC\u5168\u662F\u6CE8\u91CA\uFF1A\u5220\u6389/\u7559\u7A7A = \u7528\u5185\u5EFA\u9ED8\u8BA4\uFF0C\u53D6\u6D88\u6CE8\u91CA\u5373\u751F\u6548\u3002\n# \u5206\u5C42\uFF08\u4F4E\u2192\u9AD8\uFF09\uFF1A\u2460 \u5185\u5EFA\u9ED8\u8BA4 \u2192 \u2461 \u672C\u6587\u4EF6 \u2192 \u2462 \u540C\u76EE\u5F55\u7684 memory.yaml / knowledge.yaml\uFF08\u7F3A\u5931=\u4E0D\u8986\u76D6\uFF09\n# \u2192 \u2463 \u73AF\u5883\u53D8\u91CF \u2192 \u2464 \u63D2\u4EF6/CLI \u663E\u5F0F\u4F20\u53C2\n# \u6240\u6709\u53EF\u7F16\u8F91\u6587\u672C\u90FD\u5728 ~/.avantf \u4E0B\uFF1Aconfigs/*.yaml\uFF08\u672C\u76EE\u5F55\uFF09\u4E0E prompts/*.md\uFF08\u6A21\u578B\u63D0\u793A\u8BCD\uFF09\u3002\n\n# \u6570\u636E\u6839\u4E0D\u5728\u8FD9\u91CC\u914D\uFF1A\u5B83\u7531 \u2463 AVANTF_HOME\uFF08\u5BB6\u65CF\u6839\uFF1A\u540C\u65F6\u51B3\u5B9A\u6570\u636E\u6839\u4E0E models/tools\uFF09\u51B3\u5B9A \u2014\u2014\n# \u53EA\u60F3\u6362\u6570\u636E\u6839\u3001\u4E0D\u642C\u6A21\u578B\u7F13\u5B58\u65F6\u7528 CLI \u7684 \u2464 \u663E\u5F0F\u53C2\u6570 avantf-mem --data-home <path>\uFF08\u63D2\u4EF6\u5219\u662F profile \u7684\n# dataHome\uFF0C\u5C5E \u2461\uFF09\u3002\u672C\u6587\u4EF6\u5C31\u5728\u6570\u636E\u6839\u91CC\u9762\uFF0C\u89E3\u6790\u6839\u65F6\u8FD8\u6CA1\u8BFB\u5230\u5B83\uFF0C\u6240\u4EE5\u5199\u5728\u8FD9\u91CC\u7684 dataHome \u5BF9\u6570\u636E\u6839\u65E0\u6548\uFF08DESIGN \u00A73\uFF09\u3002\n\n# semantic: # \u5D4C\u5165\u540E\u7AEF\uFF08\u8BB0\u5FC6\u4E0E\u77E5\u8BC6\u5171\u7528\uFF0C\u8DE8\u5E93\u5206\u6570\u624D\u53EF\u6BD4\uFF09\n# backend: local_bge\n# local_model: Xenova/bge-base-zh-v1.5 # \u5FC5\u987B\u662F ONNX \u4ED3\u5E93\n# dim: 768\n# auto_download: true\n# auto_migrate: true # \u6362\u6A21\u578B/\u5BBD\u5EA6\u540E\u81EA\u52A8\u5206\u6279\u91CD\u7B97\u65E7\u7A7A\u95F4\u7684\u5411\u91CF\uFF08\u9ED8\u8BA4\u5F00\uFF09\uFF1B\u5173\u6389\u53EA\u5269\u542F\u52A8\u544A\u8B66 + vectors --fix\n# \u26A0\uFE0F cache_dir / mirror \u7531\u5BB6\u65CF\u5E95\u5EA7 @avantf/dsh-plugin-base \u7BA1\u7406\uFF1A\u5199\u5728\u8FD9\u91CC\u4F1A\u88AB\u5FFD\u7565\u5E76\u544A\u8B66\u3002\n# \u7F13\u5B58\u76EE\u5F55\u7528\u73AF\u5883\u53D8\u91CF AVANTF_MEM_MODEL_CACHE\uFF0C\u955C\u50CF\u7528 AVANTF_MEM_MODEL_MIRROR\uFF08\u6216 HF_ENDPOINT\uFF09\u3002\n\n# vectorStore:\n# backend: auto # auto = \u8D8A\u8FC7\u9608\u503C\u81EA\u52A8\u4ECE local_numpy \u8FC1\u5230 hnswlib\n# auto_thresholds:\n# hnswlib: 2000\n# hnswlib_ef_search: 256 # ANN \u7684\u53EC\u56DE/\u901F\u5EA6\u65CB\u94AE\uFF0C\u8BED\u6599\u53D8\u5927\u5148\u8C03\u5B83\n\n# retriever: # \u4E09\u6761\u68C0\u7D22\u817F\u5728\u878D\u5408\u91CC\u7684\u6743\u91CD\u4E0E\"\u76F8\u5173\u6027\u95E8\u69DB\"\n# weight_semantic: 0.55\n# weight_fts: 0.30\n# weight_jaccard: 0.15\n# # \u7EDD\u5BF9\u95E8\u69DB\u6253\u5728\u6BCF\u6761\u817F\u7684\u539F\u59CB\u5206\u4E0A\u3001fuse() \u4E4B\u524D\uFF08\u878D\u5408\u5206\u53EA\u5728\u4E00\u6B21\u67E5\u8BE2\u5185\u53EF\u6BD4\uFF0C\u4E0D\u80FD\u5F53\u95E8\u69DB\uFF09\u3002\n# # 0 = \u5173\u95ED\u8BE5\u95E8\u69DB\uFF1B\u5206\u6570\u7B49\u4E8E\u95E8\u69DB\u4FDD\u7559\u3002\u8BED\u4E49\u540E\u7AEF\u4E0D\u53EF\u7528\u65F6 min_fts_terms \u7684\u751F\u6548\u503C\u653E\u5BBD\u5230 1\u3002\n# min_semantic_similarity: 0.5 # \u8BED\u4E49\u817F\u4F59\u5F26\uFF1B0.5 \u53EA\u5BF9 bge-base-zh-v1.5/768\uFF08mean pooling\uFF09\u6807\u5B9A\u8FC7\uFF0C\u6362\u6A21\u578B\u8981\u91CD\u6807\n# min_fts_terms: 2 # FTS \u817F\uFF1A\u8FD9\u4E00\u884C\u547D\u4E2D\u51E0\u4E2A\u4E0D\u540C\u7684\u67E5\u8BE2\u8BCD\u5143\uFF08\u62C9\u4E01\u8BCD\u22655\u5B57\u7B26 + CJK 3-gram\uFF09\n# min_jaccard: 0.2 # \u5B9E\u4F53\u817F\uFF1A\u951A\u70B9\u5B9E\u4F53\u7684 Jaccard\uFF08\u4E8B\u5B9E\u5BBD\u5EA6\u9971\u548C\uFF09\uFF1B2 \u5B9E\u4F53\u547D\u4E2D 1 \u4E2A\u6B63\u597D 0.2\n# # P-11 \u4E2D\u6587\u65F6\u95F4\u7A97\u817F\uFF08\u9ED8\u8BA4\u5173\uFF09\uFF1A\u5F00\u542F\u540E\uFF0C\u5E26\u4E2D\u6587\u65F6\u95F4\u8868\u8FBE\u7684\u67E5\u8BE2\uFF08\u4E0A\u4E2A\u6708 / \u6700\u8FD1\u4E09\u5929 / 2026\u5E749\u6708 \u2026\uFF09\n# # \u4F1A\u989D\u5916\u628A\"\u4E8B\u4EF6\u65F6\u95F4 valid_from \u843D\u5728\u8BE5\u7A97\u53E3\"\u7684\u6D3B\u8DC3\u4E8B\u5B9E\u4F5C\u4E3A\u4E00\u6761\u817F\u53C2\u4E0E\u878D\u5408\u3002\u5B83\u662F**\u52A0\u4E00\u6761\u817F\u3001\u4E0D\u662F\u8FC7\u6EE4\u5668**\uFF1A\n# # \u53EA\u589E\u52A0\u5019\u9009\uFF0C\u7EDD\u4E0D\u5220\u6389\u8BED\u4E49 / FTS / \u5B9E\u4F53\u817F\u5DF2\u7ECF\u627E\u5230\u7684\u4E8B\u5B9E\uFF1B\u6CA1\u6709\u4E8B\u4EF6\u65F6\u95F4\u7684\u4E8B\u5B9E\u4E0D\u4F5C\u4E3A\u8BE5\u817F\u5019\u9009\uFF0C\n# # \u4E5F**\u4E0D\u56DE\u9000\u5230\u5199\u5165\u65F6\u95F4 created_at**\u3002\u5B83\u5171\u7528 jaccard \u6743\u91CD\u4F4D\uFF08\u5BF9\u5916\u7684\u4E09\u952E\u6743\u91CD\u4E0D\u53D8\uFF09\u3002\n# # \u4EC0\u4E48\u65F6\u5019\u8BE5\u5F00\uFF1A\u5148\u7528 mem_admin stats \u770B validity.coverage\uFF08\u6709\u591A\u5C11\u6D3B\u8DC3\u4E8B\u5B9E\u5E26\u4E8B\u4EF6\u65F6\u95F4\uFF09\uFF0C\n# # \u518D\u7528\u56DE\u5F52\u7F51\u786E\u8BA4\u5B83\u786E\u5B9E\u6539\u5584\u65F6\u95F4\u7C7B\u67E5\u8BE2\u2014\u2014\u8986\u76D6\u7387\u22480 \u65F6\u5B83\u7B49\u4E8E\u6CA1\u5F00\u3002\u5199\u5165\u4E8B\u4EF6\u65F6\u95F4\u7528 mem_remember \u7684 event_date\u3002\n# time_window: false\n\n# lifecycle:\n# purge_after_archived_days: 365 # \u5F52\u6863\u4E8B\u5B9E\u7684\u7269\u7406\u6E05\u7406\u7A97\u53E3\uFF08\u6D3B\u8DC3\u65E5\uFF09\n# contradiction_threshold: 0.6\n\n# trust:\n# decay_per_day: 0.0055\u2026\n# presence:\n# heartbeat_minutes: 60 # \u5E38\u9A7B\u8FDB\u7A0B\u7684\u5FC3\u8DF3\uFF08\u6D3B\u8DC3\u65E5\u65F6\u949F\u4E0E\u751F\u547D\u5468\u671F\u626B\u63CF\uFF09\n\n# tools: # \u5916\u90E8\u4E8C\u8FDB\u5236\uFF08pandoc\uFF09\u7684\u53D7\u7BA1\u76EE\u5F55\n# dir: '' # \u7559\u7A7A = \u5BB6\u65CF\u6839 tools\uFF08~/.avantf/env/tools\uFF09\uFF1BAVANTF_TOOLS_DIR \u53EF\u8986\u76D6\n# auto_install: true\n";
19
19
  /**
20
20
  * Ensure the common config exists with content, and hand back the path either way.
21
21
  *
@@ -115,6 +115,12 @@ export declare class ChunksDao {
115
115
  * This is what lets the shared repair flow read "what is stale" cheaply per slice instead of
116
116
  * re-scanning and hashing the corpus (`corpusState` reads every text; a batched migration must
117
117
  * not).
118
+ *
119
+ * The JS rule itself is `store/vector_space.ts` (`classifyVectorSpace` / `countVectorSpace`), and
120
+ * this projection is bound to it by the cross assertions in
121
+ * `test/knowledge_vector_migration.spec.ts` (the startup warning's count, the health count and the
122
+ * migration's `remaining` all have to be the same number). NOTHING here changes when the JS rule
123
+ * changes: the mirror is checked, not shared.
118
124
  */
119
125
  vectorSpaceCounts(space: string, expectedBytes: number): {
120
126
  stale: number;
@@ -8,10 +8,28 @@
8
8
  * The SQL lives here like every other aggregate. The store decides WHICH source a write carries
9
9
  * (and refuses to invent one when the caller gave none); the DAO only records and reads rows.
10
10
  */
11
+ import type { FactSourceView } from '../../../mem-contract/index.js';
11
12
  import type { Db } from '../port.js';
12
- /** The closed `kind` vocabulary, spelled once so the store and the tests share it. */
13
+ /**
14
+ * The kind axis is the CONTRACT's, not a second list: `FactSourceView['kind']` is what `admin detail`
15
+ * renders and what the writer below records, so deriving the type from it is what makes "the closed
16
+ * vocabulary" one thing. (Before, the array here and the union in `types.ts` were two independent
17
+ * spellings that happened to agree.)
18
+ */
19
+ export type FactSourceKind = FactSourceView['kind'];
20
+ /**
21
+ * The closed `kind` vocabulary, spelled once so the store and the tests share it.
22
+ *
23
+ * The `satisfies` pins every member to the contract's union; the `Exclude` below pins the other
24
+ * direction, so a kind the contract ADDS fails to compile here instead of silently never being
25
+ * recorded.
26
+ */
13
27
  export declare const FACT_SOURCE_KINDS: readonly ["session", "kb_doc", "tool", "manual"];
14
- export type FactSourceKind = (typeof FACT_SOURCE_KINDS)[number];
28
+ /**
29
+ * The FALLBACK kind: a `source_ref` without a recognized `kind:` prefix is `manual` with the
30
+ * reference kept VERBATIM (the tool contract says so, and "no shape guessing" is the point).
31
+ */
32
+ export declare const FACT_SOURCE_FALLBACK_KIND: "manual";
15
33
  /** One provenance row as the read surfaces render it. */
16
34
  export interface FactSource {
17
35
  kind: FactSourceKind;
@@ -21,10 +39,14 @@ export interface FactSource {
21
39
  * Derive `(kind, ref)` from the single `source_ref` the write face accepts.
22
40
  *
23
41
  * The tool takes ONE string (the plan adds no second parameter), so the kind axis is spelled by a
24
- * `kind:` prefix — `session:…` / `kb_doc:…` / `tool:…` — and anything else is `manual` with the
25
- * reference kept VERBATIM. No shape guessing: a bare `domain:source:title` becomes a `manual`
26
- * source whose ref is exactly what the caller wrote, which is strictly more honest than inventing
27
- * a category from how the string looks.
42
+ * `kind:` prefix — `session:…` / `kb_doc:…` / `tool:…` — and anything else, INCLUDING the fallback
43
+ * kind's own name, is `manual` with the reference kept VERBATIM. No shape guessing: a bare
44
+ * `domain:source:title` becomes a `manual` source whose ref is exactly what the caller wrote, which
45
+ * is strictly more honest than inventing a category from how the string looks.
46
+ *
47
+ * The prefix table comes from {@link FACT_SOURCE_KINDS} (see {@link FACT_SOURCE_PREFIX_KINDS}) rather
48
+ * than from a hand-written alternation, which is what keeps the recognized set and the recorded set
49
+ * from being two lists.
28
50
  */
29
51
  export declare function classifySourceRef(sourceRef: string): {
30
52
  kind: FactSourceKind;
@@ -0,0 +1,25 @@
1
+ /**
2
+ * The two page/result defaults the engine falls back to when neither the caller nor the config says
3
+ * anything — spelled ONCE, because each of them used to be written in two or three places.
4
+ *
5
+ * They are the ENGINE's consumption points of numbers the CONTRACT documents:
6
+ *
7
+ * - `DEFAULT_SEARCH_LIMIT` — `query`'s own input schema carries `.default(10)`
8
+ * (`contract/src/tools.ts`), and the recall actions' descriptions say "默认 10"; the recall union
9
+ * itself is `.optional()`, so the engine is what applies it. It reaches `hybridSearch` (a
10
+ * non-finite limit) and the cross-store router.
11
+ * - `DEFAULT_LIST_LIMIT` — the documented page for `admin list` and `kb_list` ("默认 50" /
12
+ * "缺省 50", same file).
13
+ *
14
+ * The cross-layer equation is pinned by `test/hybrid.spec.ts` against the contract's parsed schema,
15
+ * so a contract default moving and this constant not moving is a red test rather than a silent
16
+ * off-by-page behaviour. (These live here rather than in the contract because `@avantf/mem-contract`
17
+ * is consumed as built output: a constant added there is only visible to this engine after the
18
+ * contract is rebuilt, which a source-only change may not assume.)
19
+ *
20
+ * @module defaults
21
+ */
22
+ /** Page of a recall/query result when the caller gave no usable `limit`. */
23
+ export declare const DEFAULT_SEARCH_LIMIT = 10;
24
+ /** Page of a listing surface (`admin list`, `kb_list`) when the caller gave no `limit`. */
25
+ export declare const DEFAULT_LIST_LIMIT = 50;
@@ -16,10 +16,12 @@
16
16
  import type { KbAddRequest, ToolEnvelope, ToolSpec } from '../mem-contract/index.js';
17
17
  import type { AvantfRuntime } from './runtime.js';
18
18
  /**
19
- * The default page for a model-facing `kb_list`.
19
+ * The default page for a model-facing `kb_list` — the SAME page the operator's `admin list` uses.
20
20
  *
21
21
  * Without one, `kb_list` on a large library read and parsed EVERY managed file (resolving a path
22
- * needs the file's frontmatter to detect collisions) to answer a question nobody asked in full.
22
+ * needs the file's frontmatter to detect collisions) to answer a question nobody asked in full. The
23
+ * two surfaces were separate literals; the contract documents both as 50, so they are one constant
24
+ * (`src/defaults.ts`).
23
25
  */
24
26
  export declare const KB_LIST_DEFAULT_LIMIT = 50;
25
27
  /**
@@ -0,0 +1,288 @@
1
+ import { EXPORT_STATUSES, type ExportStatus, type RememberRequest } from '../mem-contract/index.js';
2
+ /**
3
+ * The runtime slice these flows actually touch.
4
+ *
5
+ * Narrow on purpose: export reads two config fields, import/merge also call the store's `add` path.
6
+ * Keeping the parameter structural (rather than the whole `AvantfRuntime`) is what lets the admin
7
+ * dispatcher — an object literal whose `closed` getter is attached only at return time — pass
8
+ * itself in without a cast, and it documents that these flows cannot reach any other store face.
9
+ */
10
+ export interface FactsIoRuntime {
11
+ config: {
12
+ home: string;
13
+ memory: {
14
+ db: {
15
+ path: string;
16
+ };
17
+ };
18
+ };
19
+ remember(req: RememberRequest): Promise<unknown>;
20
+ }
21
+ /** The document's discriminator. A file without it is not an export of this tool. */
22
+ export declare const FACTS_EXPORT_FORMAT = "avantf-mem-facts";
23
+ /**
24
+ * The version THIS build writes: 2 (v1 + the facts columns v1 did not carry).
25
+ *
26
+ * Versions are additive by design: v2 adds OPTIONAL fields, so a v1 document is still the same
27
+ * shape minus the new keys. A version outside {@link FACTS_EXPORT_VERSIONS} must be refused, never
28
+ * guessed at.
29
+ */
30
+ export declare const FACTS_EXPORT_VERSION = 2;
31
+ /** A version this build can READ. v1 documents are what users already have on disk. */
32
+ export declare const FACTS_EXPORT_VERSIONS: readonly [1, 2];
33
+ /** The version literal, so a parsed document can say which field set it came from. */
34
+ export type FactsExportVersion = (typeof FACTS_EXPORT_VERSIONS)[number];
35
+ /**
36
+ * `--status` values accepted by `export` (the whole DB, or one status).
37
+ *
38
+ * Re-exported from the contract, where the admin action and the CLI flag read the same set. The
39
+ * engine's public face keeps the name its callers already import.
40
+ */
41
+ export { EXPORT_STATUSES, type ExportStatus };
42
+ /** One `fact_sources` row, copied verbatim. */
43
+ export interface ExportedFactSource {
44
+ kind: string;
45
+ ref: string;
46
+ }
47
+ /**
48
+ * One fact, as it stands in the source database.
49
+ *
50
+ * Every field is part of the documented format even when v1 import ignores it — the point of the
51
+ * document is that a later restore does not have to invent what was never written down.
52
+ */
53
+ export interface ExportedFact {
54
+ /** Source-local row id. For reports/debugging ONLY; content is the identity. */
55
+ source_id: number;
56
+ content: string;
57
+ category: string;
58
+ status: string;
59
+ created_at: string | null;
60
+ updated_at: string | null;
61
+ ttl_days: number;
62
+ pinned: boolean;
63
+ pinned_at: string | null;
64
+ trust_score: number;
65
+ assert_count: number;
66
+ helpful_count: number;
67
+ last_reinforced_at: string | null;
68
+ sources: ExportedFactSource[];
69
+ valid_from: string | null;
70
+ valid_to: string | null;
71
+ supersedes_source_id: number | null;
72
+ /** `null` for an active row; the archive bookkeeping for an archived one. */
73
+ archive: {
74
+ at: string | null;
75
+ reason: string | null;
76
+ } | null;
77
+ /** Active-day clock at the last trust settle — the decay baseline. v1 had no such column. */
78
+ settle_clock?: number | null;
79
+ /** Reinforcement events inside the current 24h window. */
80
+ bonus_count?: number | null;
81
+ /** Calendar start of that window. */
82
+ bonus_window_at?: string | null;
83
+ /** How many times this fact was RETURNED by a retrieval leg (local usage stat, still stored). */
84
+ retrieval_count?: number | null;
85
+ last_retrieved_at?: string | null;
86
+ /** Mirror bookkeeping (a fact copied between libraries); informational, restored verbatim. */
87
+ mirror_source?: string | null;
88
+ mirror_target?: string | null;
89
+ /**
90
+ * The DERIVED-STATE stamps. Exported for completeness/diagnostics, but restore deliberately does
91
+ * not trust them: it stamps `entities_version = 0` (so the entity sweep rebuilds) and
92
+ * `conflict_checked = 1` (no corpus-wide conflict re-scan after a rebuild).
93
+ */
94
+ entities_version?: number | null;
95
+ conflict_checked?: number | null;
96
+ }
97
+ /** The single JSON document `export` writes (and `import`/`restore` read). */
98
+ export interface FactsExportDocument {
99
+ format: typeof FACTS_EXPORT_FORMAT;
100
+ /** The version the document was WRITTEN as (1 or 2); this build writes 2. */
101
+ version: FactsExportVersion;
102
+ exported_at: string;
103
+ source: {
104
+ data_home: string;
105
+ db: string;
106
+ /** The SOURCE database's whole-DB status counts, independent of `--status`. */
107
+ counts: {
108
+ active: number;
109
+ archived: number;
110
+ };
111
+ };
112
+ facts: ExportedFact[];
113
+ }
114
+ /** How v1 import may treat the provenance embedded in the document. */
115
+ export interface ImportOptions {
116
+ /** Plan only: no write, and the report gets `would_import`. */
117
+ dryRun?: boolean;
118
+ /** Fallback provenance when the document has none (the CLI passes `import:<file>`). */
119
+ sourceRef?: string;
120
+ /**
121
+ * Use `sources[0].ref` when present (the default, and the import contract).
122
+ *
123
+ * `merge` turns this OFF: its documented provenance is `merge:<absolute source path>` for every
124
+ * imported row, so a merge must not start attributing rows to whatever the other host recorded.
125
+ */
126
+ preferEmbeddedSources?: boolean;
127
+ }
128
+ /** One row the store refused; the rest of the import continues. */
129
+ export interface ImportFailure {
130
+ /** The document's `source_id`, or `null` when the row was too malformed to have one. */
131
+ source_id: number | null;
132
+ error: string;
133
+ }
134
+ /** Source id → target id for one fact this invocation actually CREATED. */
135
+ export interface ImportNewId {
136
+ source_id: number | null;
137
+ new_fact_id: number;
138
+ }
139
+ /**
140
+ * Counts of values v1 could not carry, over the facts this invocation imported (or, for a dry run,
141
+ * planned to import). `1` per fact that actually carried the value; `0` when there was nothing to
142
+ * lose. See the module doc for why these are losses rather than silent successes.
143
+ */
144
+ export interface MetadataDropped {
145
+ timestamps: number;
146
+ trust: number;
147
+ assert_count: number;
148
+ helpful_count: number;
149
+ pinned: number;
150
+ supersedes: number;
151
+ }
152
+ /** The single JSON object `import` prints (`file` is added by the CLI, which knows the argument). */
153
+ export interface ImportReport {
154
+ /** The input form this run detected: an export document. */
155
+ mode: 'json';
156
+ version: number;
157
+ total: number;
158
+ imported: number;
159
+ /** Present on `--dry-run` only; the number of facts that WOULD be written. */
160
+ would_import?: number;
161
+ skipped_existing: number;
162
+ skipped_archived: number;
163
+ failed: ImportFailure[];
164
+ new_ids: ImportNewId[];
165
+ metadata_dropped: MetadataDropped;
166
+ }
167
+ /** The db→db variant's report. Field names kept from the original `merge` output. */
168
+ export interface MergeReport {
169
+ /** The input form this run detected: a SQLite source database. */
170
+ mode: 'db';
171
+ source: string;
172
+ source_active: number;
173
+ added: number;
174
+ would_add: number;
175
+ skipped_existing: number;
176
+ skipped_archived: number;
177
+ failed: {
178
+ source_fact_id: number | null;
179
+ error: string;
180
+ }[];
181
+ new_ids: {
182
+ source_fact_id: number | null;
183
+ new_fact_id: number;
184
+ }[];
185
+ }
186
+ export interface MergeOptions {
187
+ /** Provenance for rows without an embedded source; default `merge:<absolute source path>`. */
188
+ sourceRef?: string;
189
+ /** Plan only: no model warmup, no write, `added` stays 0. */
190
+ dryRun?: boolean;
191
+ }
192
+ /**
193
+ * Export THIS runtime's memory facts. Read-only: the store's own connection is never asked to write
194
+ * (and this command needs no embedding model — the rows are already there).
195
+ */
196
+ export declare function exportFacts(rt: FactsIoRuntime, options?: {
197
+ status?: ExportStatus;
198
+ }): FactsExportDocument;
199
+ /**
200
+ * The compression containers `export` can write. `none` is plain minified JSON (the format's
201
+ * canonical text, and what stdout always carries).
202
+ */
203
+ export type FactsExportCodec = 'brotli' | 'gzip' | 'none';
204
+ /**
205
+ * The one serialization. MINIFIED by default: the document is a machine artifact that gets
206
+ * compressed, and indentation only makes the uncompressed fallback bigger. `pretty` exists for
207
+ * debugging (a human reading a diff), never as the default — and it is the ONLY mode that appends
208
+ * the trailing newline that used to be unconditional.
209
+ */
210
+ export declare function serializeFactsExport(doc: FactsExportDocument, options?: {
211
+ pretty?: boolean;
212
+ }): string;
213
+ /**
214
+ * Serialize + compress in one step. gzip uses level 9; brotli uses quality 11 and tells the encoder
215
+ * the input size, which is the smallest output either library produces for a one-shot export.
216
+ *
217
+ * `codec` defaults to `none` so a caller that says nothing gets the canonical minified JSON.
218
+ */
219
+ export declare function encodeFactsExport(doc: FactsExportDocument, options?: {
220
+ codec?: FactsExportCodec;
221
+ pretty?: boolean;
222
+ }): Buffer;
223
+ /** The document an encoded file carries, plus the container it actually turned out to be. */
224
+ export interface DecodedFactsExport {
225
+ doc: FactsExportDocument;
226
+ codec: FactsExportCodec;
227
+ }
228
+ /**
229
+ * Whether these bytes are a SQLite database, decided by the FILE HEADER.
230
+ *
231
+ * `mem_admin import` takes either an export document or another host's `memory.db`, and the only
232
+ * honest discriminator is the content: the export containers (plain / gzip / brotli) never start with
233
+ * the SQLite header, and a `.db` file renamed to `.json` still is one. Kept here, beside
234
+ * {@link decodeFactsExport}, so both content sniffers live together.
235
+ */
236
+ export declare function isSqliteDatabase(bytes: Buffer): boolean;
237
+ /**
238
+ * The same check for a PATH, reading only the 16-byte header.
239
+ *
240
+ * A `memory.db` can be hundreds of MiB; deciding which flow to take must not read it into memory
241
+ * first. The JSON path still reads the whole document (it has to decode it), but the db path hands the
242
+ * path straight to the read-only opener.
243
+ */
244
+ export declare function isSqliteDatabaseFile(path: string): boolean;
245
+ /**
246
+ * Decode one export file from its BYTES. The file name is deliberately not an input: gzip has a
247
+ * magic header, brotli does not, and a pre-compression export is plain JSON — so the only reliable
248
+ * discriminator is the content itself (a brotli file renamed to `.json` still imports, and a plain
249
+ * JSON file renamed to `.json.br` does too).
250
+ *
251
+ * Order, and why: gzip magic → gunzip (a corrupt gzip is refused as gzip, not silently "JSON");
252
+ * otherwise UTF-8 JSON (the backward-compatible path for every old pretty file); only when JSON
253
+ * parsing fails, brotli (its decoder rejects non-brotli input, so this cannot shadow a JSON
254
+ * document). A document that IS JSON but has the wrong format/version throws its own error right
255
+ * away — {@link parseFactsExport} is the format gate, not a fallback.
256
+ */
257
+ export declare function decodeFactsExport(bytes: Buffer): DecodedFactsExport;
258
+ /**
259
+ * Resolve the container for a file export: an explicit flag wins, then the extension (`.br` /
260
+ * `.gz`), then plain minified JSON. Shared by the CLI and `/mem` so the two surfaces cannot
261
+ * disagree about what `--out backup.json.gz` means.
262
+ */
263
+ export declare function codecForExportPath(path: string, explicit?: FactsExportCodec): FactsExportCodec;
264
+ /**
265
+ * Parse and validate an export document TEXT (the stdin entry point). Top-level format errors are
266
+ * FATAL (the caller must write nothing); a malformed individual fact is NOT — {@link importFacts}
267
+ * collects it in `failed` and keeps going. Restore is STRICTER by construction: it validates every
268
+ * row before opening its transaction, because skipping a row would produce a different history.
269
+ */
270
+ export declare function parseFactsExport(text: string): FactsExportDocument;
271
+ /**
272
+ * Import one export document into `rt`'s memory store.
273
+ *
274
+ * Order of decisions per fact: archived → skipped_archived (v1 never revives); content already in
275
+ * the target (or planned by an earlier row of this same document) → skipped_existing; otherwise the
276
+ * store's add path runs. A row the store refuses is collected in `failed` and the loop continues.
277
+ */
278
+ export declare function importFacts(rt: FactsIoRuntime, doc: FactsExportDocument, options?: ImportOptions): Promise<ImportReport>;
279
+ /**
280
+ * `merge` — the db→document→import form of the same union.
281
+ *
282
+ * The source is another host's file: opened read-only, never migrated, never written. The document is
283
+ * built in memory and handed to {@link importFacts}, so merge and `import` share one per-fact add
284
+ * path (and one failure-collection rule). Its provenance stays `merge:<absolute source path>` even
285
+ * when the source rows carry their own sources — that is the documented merge contract and the
286
+ * reason {@link ImportOptions.preferEmbeddedSources} can be turned off.
287
+ */
288
+ export declare function mergeDb(rt: FactsIoRuntime, dbPath: string, options?: MergeOptions): Promise<MergeReport>;
@@ -21,6 +21,10 @@ export * from './trustHeartbeat.js';
21
21
  export * from './runtime.js';
22
22
  export * from './store/memory.js';
23
23
  export * from './store/knowledge.js';
24
+ export { normalizeWrite } from './store/common.js';
25
+ export * from './facts_io.js';
26
+ export * from './maintenance_paths.js';
27
+ export * from './store/facts_restore.js';
24
28
  export * from './store/vector_repair.js';
25
29
  export * from './store/hybrid.js';
26
30
  export * from './store/source_picker.js';
@@ -0,0 +1,41 @@
1
+ import type { FactsExportCodec } from './facts_io.js';
2
+ /** Hard cap on a file a maintenance action will read (import / merge / restore_snapshot). */
3
+ export declare const MAINTENANCE_MAX_FILE_BYTES: number;
4
+ /** Where an export lands when the caller does not name a file. */
5
+ export declare const MAINTENANCE_BACKUP_DIRNAME = "backups";
6
+ /**
7
+ * `<data home>/backups/memory-YYYYMMDD-HHMMSS.<ext>` — never inside `memory/`.
8
+ *
9
+ * Brotli is the default because it is the smallest (measured: 70.6 KiB vs 92.3 gzip vs 300.0 plain
10
+ * for 233 facts). A caller that passes another codec keeps the file name truthful by changing the
11
+ * suffix along with the bytes.
12
+ */
13
+ export declare function defaultFactsExportPath(home: string, now?: Date, codec?: FactsExportCodec): string;
14
+ /** A resolved export destination, plus whether this call will overwrite an existing file. */
15
+ export interface MaintenanceExportTarget {
16
+ file: string;
17
+ existed: boolean;
18
+ }
19
+ /**
20
+ * Resolve an export destination inside the data root.
21
+ *
22
+ * The TARGET may not exist yet (that is the normal case), so containment is established on the
23
+ * nearest existing ancestor: every component below it is one this call will create, and a
24
+ * not-yet-created component cannot be a symlink. When the target DOES exist, its realpath is
25
+ * checked — a symlink pointing outside is refused rather than followed.
26
+ */
27
+ export declare function resolveMaintenanceExportTarget(home: string, input?: string): MaintenanceExportTarget;
28
+ /**
29
+ * Resolve an INPUT file (import / merge / restore_snapshot) inside the data root.
30
+ *
31
+ * The file must exist, be a regular file, and be no larger than {@link MAINTENANCE_MAX_FILE_BYTES}.
32
+ * A symlink to a regular file INSIDE the root is usable; a symlink that escapes it is refused before
33
+ * the size or existence of the outside target is examined.
34
+ */
35
+ export declare function resolveMaintenanceInputFile(home: string, input: string): string;
36
+ /**
37
+ * Write a file atomically: a sibling temp file, then one `rename` (same directory, so the rename
38
+ * cannot cross a filesystem). An overwrite is therefore either the old bytes or the new bytes, never
39
+ * a truncated export. The temp file is removed when anything fails.
40
+ */
41
+ export declare function writeFileAtomic(path: string, bytes: Buffer | string): void;
@@ -55,22 +55,6 @@ export interface WarmOptions {
55
55
  * path keeps it, because there the caller only sees this logger.
56
56
  */
57
57
  export declare function warmModels(rt: AvantfRuntime, options?: WarmOptions, reportFinal?: boolean): Promise<boolean>;
58
- /**
59
- * Warm ONLY the embedding model: load it from `semantic.cache_dir` and mark the engine ready.
60
- *
61
- * Split out of {@link warmModels} for the plugin's envinit path. There the framework fetches the
62
- * model in the BACKGROUND, so the warm has to wait for the item to settle instead of running at
63
- * mount — and the runtime's own constructor warm is deferred for exactly that reason
64
- * (`RuntimeOptions.managedRoots` → `deferWarm`), which is what stops it racing the install and
65
- * leaving a second copy behind. While the item is unsettled NOTHING warms; this function is the
66
- * explicit "files are there now, look" step, and it still runs when the item skipped/failed so
67
- * `semantic.auto_download` can decide between the runtime's own fetch and degradation.
68
- *
69
- * @param rt - the runtime whose memory store owns the semantic backend.
70
- * @param reportFinal - log the one-line verdict (default `true`).
71
- * @returns whether the semantic path is available.
72
- */
73
- export declare function warmSemantic(rt: AvantfRuntime, reportFinal?: boolean): Promise<boolean>;
74
58
  /**
75
59
  * Wait out the startup gate — the host readiness signal (bounded by {@link WAIT_FOR_HOST_MS}) and,
76
60
  * when asked, one quiet turn of the event loop.
@@ -88,18 +72,6 @@ export declare function warmSemantic(rt: AvantfRuntime, reportFinal?: boolean):
88
72
  * @returns how long the idle gate waited (ms), or `0` when it was not requested.
89
73
  */
90
74
  export declare function awaitStartupGate(options?: WarmOptions): Promise<number>;
91
- /**
92
- * Warm ONLY the tokenizer, after the host-readiness signal and (when asked) an idle event loop.
93
- *
94
- * nodejieba loads its dictionary lazily on the FIRST `tag()` (measured ~950 ms, after which a call
95
- * is 0.1 ms), so without this the first write/query of a session pays it while the user waits. Its
96
- * cost belongs to startup, and an unavailable jieba is worth saying out loud — entity extraction
97
- * silently degrades to the regex fallback (weaker entity/jaccard legs).
98
- *
99
- * @param rt - the runtime whose logger reports the outcome.
100
- * @param options - the host-readiness signal and the idle gate (see {@link WarmOptions}).
101
- */
102
- export declare function warmTokenizer(rt: AvantfRuntime, options?: WarmOptions): Promise<void>;
103
75
  /**
104
76
  * Non-blocking embedding warm, for a caller that knows the model files are already on disk.
105
77
  *
@@ -160,48 +132,7 @@ export interface ProvisionSweepResult {
160
132
  * @returns whether the sweep ran or was skipped for incompatibility.
161
133
  */
162
134
  export declare function provisionToolchainAsync(rt: AvantfRuntime, options?: ProvisionSweepOptions): Promise<ProvisionSweepResult>;
163
- /** The artifact id, used in the startup log and in the model artifact's errors. */
164
- export declare const MODEL_ARTIFACT_ID = "model";
165
135
  /** The environment a model-artifact call runs under: the runtime that owns the model cache. */
166
136
  export interface ModelArtifactEnv {
167
137
  runtime: AvantfRuntime;
168
138
  }
169
- /** The slice of an artifact call this module needs (`@avantf/mem-provision`'s InstallContext). */
170
- interface ModelInstallContext {
171
- logger: {
172
- info(message: string): void;
173
- warn(message: string): void;
174
- error(message: string): void;
175
- };
176
- artifactEnv?: unknown;
177
- config: {
178
- auto_install: boolean;
179
- };
180
- }
181
- /**
182
- * The embedding model (plus the nodejieba tokenizer it shares its warm-up budget with) as an
183
- * ARTIFACT, so the startup sweep in `@avantf/mem-provision` is the only initialization path.
184
- *
185
- * It used to be a parallel model warm-up call beside the tools sweep, which meant two
186
- * startup mechanisms with two logging vocabularies and no single place that answered "is this host
187
- * fully provisioned?". The model has no pinned version and no managed directory of its own ON THIS
188
- * (the flat `<repo>/<file>` layout the transformers.js cache reads), so it
189
- * declares neither; its `isPresent` is `false` because "is the model warm?" is not a question that
190
- * can be answered without attempting the warm-up, and the warm-up is cheap when the cache is
191
- * already there (measured ~1.2 s, in the background). The DSH plugin uses this sweep only when the
192
- * family framework is unavailable — with the framework up, `mem:model` owns the model root instead
193
- * and this artifact is not registered.
194
- */
195
- export declare const modelArtifact: {
196
- id: string;
197
- title: string;
198
- verb: string;
199
- isPresent(): Promise<boolean>;
200
- install(ctx: ModelInstallContext): Promise<void>;
201
- verify(ctx: {
202
- logger: ModelInstallContext["logger"];
203
- }): Promise<void>;
204
- };
205
- /** Register the model artifact once per process (idempotent for a test that mounts twice). */
206
- export declare function registerModelArtifact(): void;
207
- export {};