@snoai/memory 0.0.0-stage → 1.0.1
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/LICENSE +176 -0
- package/README.md +33 -2
- package/config/b-profile-section-registry.json +118 -0
- package/config/llm/compiled/2026-05-19T230932Z/manifest.json +25 -0
- package/config/llm/compiled/2026-05-19T230932Z/registry-root.json +67 -0
- package/config/llm/compiled/2026-05-19T230932Z/resolved/mem_claw/openai_gpt_5_nano.json +5 -0
- package/config/llm/compiled/2026-05-19T230932Z/resolved/mem_claw/openrouter_auto.json +5 -0
- package/config/llm/compiled/2026-05-19T230932Z/resolved/mem_claw/sno_ai_extract.json +5 -0
- package/config/llm/compiled/2026-05-19T230932Z/source/mem_claw/openai_gpt_5_nano.mda +24 -0
- package/config/llm/compiled/2026-05-19T230932Z/source/mem_claw/openrouter_auto.mda +24 -0
- package/config/llm/compiled/2026-05-19T230932Z/source/mem_claw/sno_ai_extract.mda +24 -0
- package/config/llm/compiled/2026-07-21T001311Z/manifest.json +43 -0
- package/config/llm/compiled/2026-07-21T001311Z/registry-root.json +97 -0
- package/config/llm/compiled/2026-07-21T001311Z/resolved/mem_claw/openai_gpt_5_nano.json +5 -0
- package/config/llm/compiled/2026-07-21T001311Z/resolved/mem_claw/openrouter_auto.json +5 -0
- package/config/llm/compiled/2026-07-21T001311Z/resolved/mem_claw/sno_ai_extract.json +5 -0
- package/config/llm/compiled/2026-07-21T001311Z/resolved/mem_claw/sno_conflict_verdict.json +10 -0
- package/config/llm/compiled/2026-07-21T001311Z/resolved/mem_claw/sno_extract_chat.json +10 -0
- package/config/llm/compiled/2026-07-21T001311Z/resolved/mem_claw/sno_extract_profile.json +10 -0
- package/config/llm/compiled/2026-07-21T001311Z/source/mem_claw/openai_gpt_5_nano.mda +24 -0
- package/config/llm/compiled/2026-07-21T001311Z/source/mem_claw/openrouter_auto.mda +24 -0
- package/config/llm/compiled/2026-07-21T001311Z/source/mem_claw/sno_ai_extract.mda +24 -0
- package/config/llm/compiled/2026-07-21T001311Z/source/mem_claw/sno_conflict_verdict.mda +27 -0
- package/config/llm/compiled/2026-07-21T001311Z/source/mem_claw/sno_extract_chat.mda +27 -0
- package/config/llm/compiled/2026-07-21T001311Z/source/mem_claw/sno_extract_profile.mda +27 -0
- package/config/llm/compiled/2026-08-29T060335Z/manifest.json +43 -0
- package/config/llm/compiled/2026-08-29T060335Z/registry-root.json +97 -0
- package/config/llm/compiled/2026-08-29T060335Z/resolved/mem_claw/openai_gpt_5_nano.json +5 -0
- package/config/llm/compiled/2026-08-29T060335Z/resolved/mem_claw/openrouter_auto.json +5 -0
- package/config/llm/compiled/2026-08-29T060335Z/resolved/mem_claw/sno_ai_extract.json +5 -0
- package/config/llm/compiled/2026-08-29T060335Z/resolved/mem_claw/sno_conflict_verdict.json +10 -0
- package/config/llm/compiled/2026-08-29T060335Z/resolved/mem_claw/sno_extract_chat.json +10 -0
- package/config/llm/compiled/2026-08-29T060335Z/resolved/mem_claw/sno_extract_profile.json +10 -0
- package/config/llm/compiled/2026-08-29T060335Z/source/mem_claw/openai_gpt_5_nano.mda +24 -0
- package/config/llm/compiled/2026-08-29T060335Z/source/mem_claw/openrouter_auto.mda +24 -0
- package/config/llm/compiled/2026-08-29T060335Z/source/mem_claw/sno_ai_extract.mda +24 -0
- package/config/llm/compiled/2026-08-29T060335Z/source/mem_claw/sno_conflict_verdict.mda +27 -0
- package/config/llm/compiled/2026-08-29T060335Z/source/mem_claw/sno_extract_chat.mda +27 -0
- package/config/llm/compiled/2026-08-29T060335Z/source/mem_claw/sno_extract_profile.mda +27 -0
- package/config/llm/compiled/2026-09-04T004828Z/manifest.json +43 -0
- package/config/llm/compiled/2026-09-04T004828Z/registry-root.json +97 -0
- package/config/llm/compiled/2026-09-04T004828Z/resolved/mem_claw/openai_gpt_5_nano.json +5 -0
- package/config/llm/compiled/2026-09-04T004828Z/resolved/mem_claw/openrouter_auto.json +5 -0
- package/config/llm/compiled/2026-09-04T004828Z/resolved/mem_claw/sno_ai_extract.json +5 -0
- package/config/llm/compiled/2026-09-04T004828Z/resolved/mem_claw/sno_conflict_verdict.json +10 -0
- package/config/llm/compiled/2026-09-04T004828Z/resolved/mem_claw/sno_extract_chat.json +10 -0
- package/config/llm/compiled/2026-09-04T004828Z/resolved/mem_claw/sno_extract_profile.json +10 -0
- package/config/llm/compiled/2026-09-04T004828Z/source/mem_claw/openai_gpt_5_nano.mda +24 -0
- package/config/llm/compiled/2026-09-04T004828Z/source/mem_claw/openrouter_auto.mda +24 -0
- package/config/llm/compiled/2026-09-04T004828Z/source/mem_claw/sno_ai_extract.mda +24 -0
- package/config/llm/compiled/2026-09-04T004828Z/source/mem_claw/sno_conflict_verdict.mda +27 -0
- package/config/llm/compiled/2026-09-04T004828Z/source/mem_claw/sno_extract_chat.mda +27 -0
- package/config/llm/compiled/2026-09-04T004828Z/source/mem_claw/sno_extract_profile.mda +27 -0
- package/config/llm/current.json +4 -0
- package/config/llm/source/mem_claw/openai_gpt_5_nano.mda +24 -0
- package/config/llm/source/mem_claw/openrouter_auto.mda +24 -0
- package/config/llm/source/mem_claw/sno_ai_extract.mda +24 -0
- package/config/llm/source/mem_claw/sno_conflict_verdict.mda +27 -0
- package/config/llm/source/mem_claw/sno_extract_chat.mda +27 -0
- package/config/llm/source/mem_claw/sno_extract_profile.mda +27 -0
- package/config/llm.trust.json +37 -0
- package/dist/_types-CUKHSRkS.d.ts +103 -0
- package/dist/access-tracker-BbEvEocb.d.ts +110 -0
- package/dist/adapter-B7Jox9-6.d.ts +69 -0
- package/dist/adapter-XaRHZWZ2.js +333 -0
- package/dist/agent-llm-port-5oXgBpzJ.d.ts +53 -0
- package/dist/all-resources-BQK2ugjB.js +6379 -0
- package/dist/all-resources-Dij6l5h0.d.ts +18 -0
- package/dist/ambient-learning-text-normalizer-CxjATmMp.js +170 -0
- package/dist/ambient-learning-text-normalizer-_fH3LeuK.d.ts +10 -0
- package/dist/atomic-extraction-reply-BJ9XV_9s.js +863 -0
- package/dist/atomic-extraction-skill-CcXmuCqL.js +56 -0
- package/dist/atomic-memory-extraction-C5rmogoY.js +3605 -0
- package/dist/atomic-memory-extraction-d9EG-4ti.d.ts +327 -0
- package/dist/b-profile-section-dictionary-provider-BHkoNqgk.js +1812 -0
- package/dist/b-profile-section-dictionary-provider-BxbksLj3.d.ts +62 -0
- package/dist/best-effort-BPZSzKk0.d.ts +9 -0
- package/dist/calendar-instruction-CzqZbAPG.js +194 -0
- package/dist/capture-policy-detector-CxbHPkMX.d.ts +53 -0
- package/dist/capture-policy-detector-DaMfy9CZ.js +357 -0
- package/dist/classifier-DnbbtwTS.d.ts +272 -0
- package/dist/client.d.ts +34 -0
- package/dist/client.js +306 -0
- package/dist/coding-skin.d.ts +51 -0
- package/dist/coding-skin.js +55 -0
- package/dist/config-CL90qYva.js +2576 -0
- package/dist/connection-3IVXpuPE.d.ts +391 -0
- package/dist/connection-C9YD5sgm.js +297 -0
- package/dist/daily-log-generator-CH_KuWHs.js +469 -0
- package/dist/daily-log-generator-CsQPHl4A.d.ts +73 -0
- package/dist/daily-spend-estimator-DiwzBlo1.d.ts +8 -0
- package/dist/data-bootstrap-Bl3lthzE.d.ts +30 -0
- package/dist/data-bootstrap-P8sie9WA.js +172 -0
- package/dist/data-paths-C7sNdqvP.d.ts +22 -0
- package/dist/derived-suppression-cache-CI0durYx.d.ts +36 -0
- package/dist/diagnostic-encoder.d.ts +6 -0
- package/dist/diagnostic-encoder.js +29 -0
- package/dist/embedding-provider-client-Q_hJonK9.js +294 -0
- package/dist/embedding-provider-client-vynZMuit.d.ts +94 -0
- package/dist/entry-metadata-parser-BIVSMCIk.js +20 -0
- package/dist/error-D-wb-rZw.js +23 -0
- package/dist/error-signals-D8_3vYu4.d.ts +28 -0
- package/dist/error-signals-lMH2uAdV.js +134 -0
- package/dist/errors-CeVRxf9V.d.ts +49 -0
- package/dist/extraction-text-sanitizer-B_AhIecT.d.ts +32 -0
- package/dist/i18n-text-DbD6Qify.d.ts +13 -0
- package/dist/index-0aqS8pVF.d.ts +351 -0
- package/dist/index-BO4RU_mc.d.ts +650 -0
- package/dist/index-DL8AVj0Z.d.ts +571 -0
- package/dist/index.d.ts +65 -0
- package/dist/index.js +1201 -0
- package/dist/intent-analyzer-B5XVrWwe.d.ts +28 -0
- package/dist/internal/config/index.d.ts +2 -0
- package/dist/internal/config/index.js +581 -0
- package/dist/internal/config/plugin-config-schema.d.ts +2 -0
- package/dist/internal/config/plugin-config-schema.js +2 -0
- package/dist/internal/config/product-mode.d.ts +2 -0
- package/dist/internal/config/product-mode.js +36 -0
- package/dist/internal/config/settings.d.ts +2 -0
- package/dist/internal/config/settings.js +265 -0
- package/dist/internal/config/skill-categories.d.ts +4 -0
- package/dist/internal/config/skill-categories.js +68 -0
- package/dist/internal/config/skin-defaults.d.ts +6 -0
- package/dist/internal/config/skin-defaults.js +6 -0
- package/dist/internal/contract/discovery.d.ts +10 -0
- package/dist/internal/contract/discovery.js +53 -0
- package/dist/internal/contract/profile.d.ts +2 -0
- package/dist/internal/contract/profile.js +44 -0
- package/dist/internal/contract/routes.d.ts +2 -0
- package/dist/internal/contract/routes.js +62 -0
- package/dist/internal/engine/bindings/memory-cli-shared.d.ts +47 -0
- package/dist/internal/engine/bindings/memory-cli-shared.js +84 -0
- package/dist/internal/engine/bindings/memory-forget-tool.d.ts +5 -0
- package/dist/internal/engine/bindings/memory-forget-tool.js +66 -0
- package/dist/internal/engine/bindings/memory-list-tool.d.ts +5 -0
- package/dist/internal/engine/bindings/memory-list-tool.js +57 -0
- package/dist/internal/engine/bindings/memory-recall-tool.d.ts +10 -0
- package/dist/internal/engine/bindings/memory-recall-tool.js +283 -0
- package/dist/internal/engine/bindings/memory-reflection-resolve-tool.d.ts +5 -0
- package/dist/internal/engine/bindings/memory-reflection-resolve-tool.js +150 -0
- package/dist/internal/engine/bindings/memory-stats-tool.d.ts +5 -0
- package/dist/internal/engine/bindings/memory-stats-tool.js +43 -0
- package/dist/internal/engine/bindings/memory-store-tool.d.ts +5 -0
- package/dist/internal/engine/bindings/memory-store-tool.js +165 -0
- package/dist/internal/engine/bindings/memory-tool-access.d.ts +16 -0
- package/dist/internal/engine/bindings/memory-tool-access.js +46 -0
- package/dist/internal/engine/bindings/memory-tool-formatting.d.ts +62 -0
- package/dist/internal/engine/bindings/memory-tool-formatting.js +106 -0
- package/dist/internal/engine/bindings/memory-tool-results.d.ts +8 -0
- package/dist/internal/engine/bindings/memory-tool-results.js +41 -0
- package/dist/internal/engine/bindings/memory-tool-schemas.d.ts +109 -0
- package/dist/internal/engine/bindings/memory-tool-schemas.js +75 -0
- package/dist/internal/engine/bindings/memory-update-tool.d.ts +5 -0
- package/dist/internal/engine/bindings/memory-update-tool.js +127 -0
- package/dist/internal/engine/bindings/sno-station-mem-ambient-learning-hook.d.ts +14 -0
- package/dist/internal/engine/bindings/sno-station-mem-ambient-learning-hook.js +248 -0
- package/dist/internal/engine/bindings/sno-station-mem-auto-recall-hook.d.ts +12 -0
- package/dist/internal/engine/bindings/sno-station-mem-auto-recall-hook.js +324 -0
- package/dist/internal/engine/bindings/sno-station-mem-hook-types.d.ts +56 -0
- package/dist/internal/engine/bindings/sno-station-mem-hook-types.js +1 -0
- package/dist/internal/engine/bindings/sno-station-mem-insight-distill-factory.d.ts +14 -0
- package/dist/internal/engine/bindings/sno-station-mem-insight-distill-factory.js +119 -0
- package/dist/internal/engine/bindings/sno-station-mem-message-transcript.d.ts +52 -0
- package/dist/internal/engine/bindings/sno-station-mem-message-transcript.js +145 -0
- package/dist/internal/engine/bindings/sno-station-mem-reset-hook.d.ts +10 -0
- package/dist/internal/engine/bindings/sno-station-mem-reset-hook.js +9 -0
- package/dist/internal/engine/bindings/sno-station-mem-runtime-mode.d.ts +36 -0
- package/dist/internal/engine/bindings/sno-station-mem-runtime-mode.js +104 -0
- package/dist/internal/engine/bindings/sno-station-mem-session-state.d.ts +10 -0
- package/dist/internal/engine/bindings/sno-station-mem-session-state.js +27 -0
- package/dist/internal/engine/eval/trace.d.ts +2 -0
- package/dist/internal/engine/eval/trace.js +151 -0
- package/dist/internal/engine/extraction/ambient-learning-text-normalizer.d.ts +2 -0
- package/dist/internal/engine/extraction/ambient-learning-text-normalizer.js +2 -0
- package/dist/internal/engine/extraction/atomic-memory-extraction.d.ts +2 -0
- package/dist/internal/engine/extraction/atomic-memory-extraction.js +2 -0
- package/dist/internal/engine/extraction/b-profile-section-dictionary-provider.d.ts +2 -0
- package/dist/internal/engine/extraction/b-profile-section-dictionary-provider.js +2 -0
- package/dist/internal/engine/extraction/b-profile-section-rekey.d.ts +49 -0
- package/dist/internal/engine/extraction/b-profile-section-rekey.js +730 -0
- package/dist/internal/engine/extraction/capture-policy-detector.d.ts +2 -0
- package/dist/internal/engine/extraction/capture-policy-detector.js +2 -0
- package/dist/internal/engine/extraction/embedding-provider-client.d.ts +2 -0
- package/dist/internal/engine/extraction/embedding-provider-client.js +2 -0
- package/dist/internal/engine/extraction/extraction-text-sanitizer.d.ts +2 -0
- package/dist/internal/engine/extraction/extraction-text-sanitizer.js +114 -0
- package/dist/internal/engine/extraction/memory-metadata-codec.d.ts +3 -0
- package/dist/internal/engine/extraction/memory-metadata-codec.js +2 -0
- package/dist/internal/engine/extraction/memory-temporality-classifier.d.ts +2 -0
- package/dist/internal/engine/extraction/memory-temporality-classifier.js +2 -0
- package/dist/internal/engine/i18n/all-resources.d.ts +2 -0
- package/dist/internal/engine/i18n/all-resources.js +2 -0
- package/dist/internal/engine/i18n/locales.d.ts +2 -0
- package/dist/internal/engine/i18n/locales.js +19 -0
- package/dist/internal/engine/i18n/res/_types.d.ts +2 -0
- package/dist/internal/engine/i18n/res/_types.js +11 -0
- package/dist/internal/engine/observability/adapter.d.ts +2 -0
- package/dist/internal/engine/observability/adapter.js +2 -0
- package/dist/internal/engine/observability/best-effort.d.ts +2 -0
- package/dist/internal/engine/observability/best-effort.js +41 -0
- package/dist/internal/engine/observability/early-diagnostics.js +2 -0
- package/dist/internal/engine/observability/memory-snapshot.d.ts +2 -0
- package/dist/internal/engine/observability/memory-snapshot.js +44 -0
- package/dist/internal/engine/observability/observable-embedder.d.ts +2 -0
- package/dist/internal/engine/observability/observable-embedder.js +43 -0
- package/dist/internal/engine/observability/observable-llm-client.d.ts +2 -0
- package/dist/internal/engine/observability/observable-llm-client.js +98 -0
- package/dist/internal/engine/observability/observable-memory-store.d.ts +2 -0
- package/dist/internal/engine/observability/observable-memory-store.js +701 -0
- package/dist/internal/engine/observability/observable-retriever.d.ts +2 -0
- package/dist/internal/engine/observability/observable-retriever.js +95 -0
- package/dist/internal/engine/observability/runtime-diagnostics.d.ts +13 -0
- package/dist/internal/engine/observability/runtime-diagnostics.js +96 -0
- package/dist/internal/engine/observability/session-registry.d.ts +2 -0
- package/dist/internal/engine/observability/session-registry.js +58 -0
- package/dist/internal/engine/observability/version-metadata.d.ts +7 -0
- package/dist/internal/engine/observability/version-metadata.js +59 -0
- package/dist/internal/engine/operations/daily-spend-estimator.d.ts +2 -0
- package/dist/internal/engine/operations/daily-spend-estimator.js +97 -0
- package/dist/internal/engine/operations/learning-file-maintenance.d.ts +2 -0
- package/dist/internal/engine/operations/learning-file-maintenance.js +255 -0
- package/dist/internal/engine/operations/memory-tier-promoter.d.ts +2 -0
- package/dist/internal/engine/operations/memory-tier-promoter.js +95 -0
- package/dist/internal/engine/operations/runtime-audit-log.d.ts +3 -0
- package/dist/internal/engine/operations/runtime-audit-log.js +3 -0
- package/dist/internal/engine/provider/canonical-memory-corpus.d.ts +38 -0
- package/dist/internal/engine/provider/canonical-memory-corpus.js +253 -0
- package/dist/internal/engine/provider/provider-registration.d.ts +39 -0
- package/dist/internal/engine/provider/provider-registration.js +2 -0
- package/dist/internal/engine/provider/provider-row-renderer.d.ts +7 -0
- package/dist/internal/engine/provider/provider-row-renderer.js +53 -0
- package/dist/internal/engine/provider/provider-types.d.ts +2 -0
- package/dist/internal/engine/provider/provider-types.js +1 -0
- package/dist/internal/engine/reflection/daily-log-generator.d.ts +2 -0
- package/dist/internal/engine/reflection/daily-log-generator.js +2 -0
- package/dist/internal/engine/reflection/reflection-command-hooks.d.ts +2 -0
- package/dist/internal/engine/reflection/reflection-command-hooks.js +2 -0
- package/dist/internal/engine/reflection/reflection-deps.d.ts +2 -0
- package/dist/internal/engine/reflection/reflection-deps.js +1 -0
- package/dist/internal/engine/reflection/reflection-embedded-generator.d.ts +2 -0
- package/dist/internal/engine/reflection/reflection-embedded-generator.js +2 -0
- package/dist/internal/engine/reflection/reflection-injection-hooks.d.ts +2 -0
- package/dist/internal/engine/reflection/reflection-injection-hooks.js +219 -0
- package/dist/internal/engine/reflection/reflection-lifecycle-hooks.d.ts +2 -0
- package/dist/internal/engine/reflection/reflection-lifecycle-hooks.js +63 -0
- package/dist/internal/engine/reflection/strategy-hook-runner.d.ts +4 -0
- package/dist/internal/engine/reflection/strategy-hook-runner.js +3 -0
- package/dist/internal/engine/rem/classifier.d.ts +2 -0
- package/dist/internal/engine/rem/classifier.js +180 -0
- package/dist/internal/engine/rem/index.d.ts +4 -0
- package/dist/internal/engine/rem/index.js +2551 -0
- package/dist/internal/engine/rem/types.d.ts +2 -0
- package/dist/internal/engine/rem/types.js +40 -0
- package/dist/internal/engine/retrieval/access-tracker.d.ts +2 -0
- package/dist/internal/engine/retrieval/access-tracker.js +314 -0
- package/dist/internal/engine/retrieval/intent-analyzer.d.ts +2 -0
- package/dist/internal/engine/retrieval/intent-analyzer.js +27 -0
- package/dist/internal/engine/retrieval/retrieval-gate.d.ts +2 -0
- package/dist/internal/engine/retrieval/retrieval-gate.js +47 -0
- package/dist/internal/engine/retrieval/retriever.d.ts +2 -0
- package/dist/internal/engine/retrieval/retriever.js +2 -0
- package/dist/internal/engine/security/memory-scope-policy.d.ts +2 -0
- package/dist/internal/engine/security/memory-scope-policy.js +2 -0
- package/dist/internal/engine/security/redact.d.ts +2 -0
- package/dist/internal/engine/security/redact.js +34 -0
- package/dist/internal/engine/security/scopes.d.ts +3 -0
- package/dist/internal/engine/security/scopes.js +3 -0
- package/dist/internal/engine/shared/errors.d.ts +2 -0
- package/dist/internal/engine/shared/errors.js +66 -0
- package/dist/internal/engine/shared/i18n-text.d.ts +2 -0
- package/dist/internal/engine/shared/i18n-text.js +58 -0
- package/dist/internal/engine/shared/iso-date-time.d.ts +16 -0
- package/dist/internal/engine/shared/iso-date-time.js +40 -0
- package/dist/internal/engine/shared/lru.d.ts +2 -0
- package/dist/internal/engine/shared/lru.js +30 -0
- package/dist/internal/engine/shared/memory-kind-policy.d.ts +2 -0
- package/dist/internal/engine/shared/memory-kind-policy.js +64 -0
- package/dist/internal/engine/shared/paths.d.ts +3 -0
- package/dist/internal/engine/shared/paths.js +2 -0
- package/dist/internal/engine/shared/types.d.ts +3 -0
- package/dist/internal/engine/shared/types.js +25 -0
- package/dist/internal/engine/shared/utils.d.ts +2 -0
- package/dist/internal/engine/shared/utils.js +175 -0
- package/dist/internal/engine/telemetry/memory-telemetry-api.d.ts +134 -0
- package/dist/internal/engine/telemetry/memory-telemetry-api.js +730 -0
- package/dist/internal/engine/telemetry/memory-telemetry-observability.d.ts +24 -0
- package/dist/internal/engine/telemetry/memory-telemetry-observability.js +133 -0
- package/dist/internal/engine/telemetry/memory-telemetry-outbox.d.ts +2 -0
- package/dist/internal/engine/telemetry/memory-telemetry-outbox.js +443 -0
- package/dist/internal/engine/telemetry/memory-telemetry-types.d.ts +2 -0
- package/dist/internal/engine/telemetry/memory-telemetry-types.js +21 -0
- package/dist/internal/engine/telemetry/observe-ledger.d.ts +30 -0
- package/dist/internal/engine/telemetry/observe-ledger.js +111 -0
- package/dist/internal/model/agent-llm-port.d.ts +2 -0
- package/dist/internal/model/agent-llm-port.js +1 -0
- package/dist/internal/model/llm-client.d.ts +3 -0
- package/dist/internal/model/llm-client.js +3 -0
- package/dist/internal/model/llm-failure.d.ts +26 -0
- package/dist/internal/model/llm-failure.js +63 -0
- package/dist/internal/model/llm-mode-routing.d.ts +22 -0
- package/dist/internal/model/llm-mode-routing.js +37 -0
- package/dist/internal/store/atomic-memory-cutover-sql.d.ts +13 -0
- package/dist/internal/store/atomic-memory-cutover-sql.js +237 -0
- package/dist/internal/store/connection.d.ts +2 -0
- package/dist/internal/store/connection.js +2 -0
- package/dist/internal/store/data-bootstrap.d.ts +2 -0
- package/dist/internal/store/data-bootstrap.js +2 -0
- package/dist/internal/store/data-paths.d.ts +2 -0
- package/dist/internal/store/data-paths.js +65 -0
- package/dist/internal/store/maintenance.d.ts +75 -0
- package/dist/internal/store/maintenance.js +1401 -0
- package/dist/internal/store/memory-kinds-cutover-migrator.d.ts +28 -0
- package/dist/internal/store/memory-kinds-cutover-migrator.js +415 -0
- package/dist/internal/store/migrations.d.ts +27 -0
- package/dist/internal/store/migrations.js +201 -0
- package/dist/internal/store/sqlite-runtime.d.ts +2 -0
- package/dist/internal/store/sqlite-runtime.js +109 -0
- package/dist/internal/store/store.d.ts +3 -0
- package/dist/internal/store/store.js +2 -0
- package/dist/learning-file-maintenance-9b-Ut6Kv.d.ts +30 -0
- package/dist/llm-client-BSYUAcUb.js +1374 -0
- package/dist/llm-client-DOTSGzhe.d.ts +51 -0
- package/dist/locales-JxGmkG6t.d.ts +7 -0
- package/dist/log-site-catalog.generated-BMKWj-Nx.js +2321 -0
- package/dist/log-site-catalog.json +1 -0
- package/dist/lru-DyoaTyIs.d.ts +14 -0
- package/dist/memdump.d.ts +52 -0
- package/dist/memdump.js +163 -0
- package/dist/memory-entry-projector-DHo8jH10.js +1015 -0
- package/dist/memory-kind-policy-BiuRjSJc.d.ts +23 -0
- package/dist/memory-metadata-codec-DL1sbJiN.js +577 -0
- package/dist/memory-metadata-codec-DUvsYe_X.d.ts +68 -0
- package/dist/memory-runtime-DqUS4cWi.js +19459 -0
- package/dist/memory-scope-policy-1gg5QlWZ.d.ts +67 -0
- package/dist/memory-scope-policy-DICSCURA.js +283 -0
- package/dist/memory-snapshot-CqY1BUUA.d.ts +16 -0
- package/dist/memory-source-order-YMRoeDLd.js +134 -0
- package/dist/memory-store-base-CQ_bHlYA.d.ts +1094 -0
- package/dist/memory-store-shared-DqpWJXZZ.js +158 -0
- package/dist/memory-store-write-validation-B_hDG2zf.js +243 -0
- package/dist/memory-telemetry-incidents-BWA9kcZx.js +8 -0
- package/dist/memory-telemetry-metadata-CA7W8tK6.js +77 -0
- package/dist/memory-telemetry-outbox-ddTdImt7.d.ts +74 -0
- package/dist/memory-telemetry-receipts-MAJecvXQ.d.ts +34 -0
- package/dist/memory-telemetry-receipts-YsxbwOAf.js +91 -0
- package/dist/memory-telemetry-types-CufVmrCs.d.ts +14 -0
- package/dist/memory-temporality-classifier-BUjXG5o7.js +184 -0
- package/dist/memory-temporality-classifier-Brht5jyK.d.ts +43 -0
- package/dist/memory-tier-promoter-CqGxCkue.d.ts +43 -0
- package/dist/memory-tool-dependencies-CatGzI9R.d.ts +14 -0
- package/dist/memory-tool-dependencies-DjUoelnm.js +19 -0
- package/dist/model-call-table-CspopkBg.js +563 -0
- package/dist/model-reply-text-CKopStP2.js +334 -0
- package/dist/observable-embedder-CNNe9gkg.d.ts +17 -0
- package/dist/observable-llm-client-CRuKlefQ.d.ts +21 -0
- package/dist/observable-memory-store-CnGDpOY5.d.ts +73 -0
- package/dist/observable-retriever-Cooc62Qw.d.ts +23 -0
- package/dist/operation-cancellation-CTKWwNHk.js +81 -0
- package/dist/paths-qVF-5uBq.d.ts +1 -0
- package/dist/plugin-config-schema-C0UUbOmG.d.ts +413 -0
- package/dist/plugin-config-schema-YJLyIIcJ.js +361 -0
- package/dist/profile-TWPJ_myr.d.ts +13 -0
- package/dist/profile-section-writer-BhGKPBjw.js +2149 -0
- package/dist/provider-registration-CF1tg8Xy.js +721 -0
- package/dist/provider-runtime-types-DFhtdA6d.d.ts +134 -0
- package/dist/provider-types-CZGm6v88.d.ts +23 -0
- package/dist/redact-BTIZcHQL.d.ts +5 -0
- package/dist/reflection-command-hooks-ClUl-iv6.js +644 -0
- package/dist/reflection-command-hooks-G1-dI2Av.d.ts +32 -0
- package/dist/reflection-deps-Ccm2Jf5W.d.ts +19 -0
- package/dist/reflection-embedded-generator-BRvqV5N-.js +130 -0
- package/dist/reflection-embedded-generator-kfQfKEYV.d.ts +14 -0
- package/dist/reflection-injection-hooks-CS_uhjoD.d.ts +43 -0
- package/dist/reflection-lifecycle-hooks-CRSpUdLi.d.ts +27 -0
- package/dist/relation-dictionary-Cev1kyLe.js +4248 -0
- package/dist/release-download.d.ts +8 -0
- package/dist/release-download.js +32 -0
- package/dist/relevant-memories-context-m8nuFZcM.js +23 -0
- package/dist/rem-batch-executor-Dg2HgROM.js +2 -0
- package/dist/rem-batch-executor-DuC4nYyf.js +31640 -0
- package/dist/rem-consumer-retrieval-CR0dtcHR.js +246 -0
- package/dist/rem-trigger-Hn6od8IV.js +730 -0
- package/dist/resolver-Dy-hnjCR.js +103 -0
- package/dist/results-C3ZLroMb.js +140 -0
- package/dist/retrieval-gate-Bx2Zg7jD.d.ts +31 -0
- package/dist/retriever-Dxss5fRv.d.ts +469 -0
- package/dist/retriever-ZoLvPRHq.js +1757 -0
- package/dist/rolldown-runtime-D7D4PA-g.js +13 -0
- package/dist/routes-DLHT__Ay.js +60 -0
- package/dist/runtime-audit-log-BCeujlEp.js +430 -0
- package/dist/runtime-audit-log-zpQiR9HT.d.ts +149 -0
- package/dist/scopes-CSOn6zdd.js +71 -0
- package/dist/scopes-CtrY-YQ3.d.ts +23 -0
- package/dist/server-CSvxchqg.js +1412 -0
- package/dist/session-registry-DBoE7AvZ.d.ts +14 -0
- package/dist/sidecar/main.d.ts +1 -0
- package/dist/sidecar/main.js +56 -0
- package/dist/signed-registry-constants-Bv0fgZ8Q.d.ts +12 -0
- package/dist/signed-registry-constants-yq3DlG3B.js +82 -0
- package/dist/sno-station-mem-runtime-dependencies-CoWqUMbK.js +30 -0
- package/dist/sno-station-mem-runtime-dependencies-DHESIuPn.d.ts +31 -0
- package/dist/sqlite-runtime-L_ywirTm.d.ts +58 -0
- package/dist/store-C8sUTssE.d.ts +27 -0
- package/dist/store-nPql26YM.js +5830 -0
- package/dist/strategy-hook-runner-Bxy851Xx.d.ts +16 -0
- package/dist/strategy-hook-runner-Djify5Rw.js +110 -0
- package/dist/token-counter-BD1f48Km.js +73 -0
- package/dist/trace-C1JxMfs-.d.ts +86 -0
- package/dist/types-CWdhXLxr.d.ts +477 -0
- package/dist/types-pVomjzqR.d.ts +132 -0
- package/dist/unplaced-candidate-migration-CbQHzcEM.js +940 -0
- package/dist/utils-Ctb9aevJ.d.ts +34 -0
- package/drizzle/0000_initial.sql +10 -0
- package/drizzle/0001_virtual_tables.sql +34 -0
- package/drizzle/0002_add_indexes.sql +11 -0
- package/drizzle/0003_content_hash_lookup_index.sql +2 -0
- package/drizzle/0004_chunk_swap.sql +60 -0
- package/drizzle/0005_drop_legacy_vec_fts.sql +10 -0
- package/drizzle/0006_fts_simple.sql +45 -0
- package/drizzle/0007_restore_simple_fts.sql +40 -0
- package/drizzle/0008_widen_memory_hash_unique_index.sql +4 -0
- package/drizzle/0009_memory_telemetry.sql +109 -0
- package/drizzle/0010_provider_mappings.sql +27 -0
- package/drizzle/0011_db_optimization.sql +82 -0
- package/drizzle/0012_b_profile_lanes.sql +9 -0
- package/drizzle/0013_extraction_timestamps.sql +6 -0
- package/drizzle/0014_extraction_timestamp_source.sql +3 -0
- package/drizzle/0015_task_lifecycle_state.sql +101 -0
- package/drizzle/0016_task_lifecycle_legacy_migration.sql +144 -0
- package/drizzle/0017_unplaced_candidates.sql +15 -0
- package/drizzle/0018_rem_batch_chassis.sql +71 -0
- package/drizzle/0019_profile_recovery_entries.sql +17 -0
- package/drizzle/0020_rem_scan_retry_progress.down.sql +14 -0
- package/drizzle/0020_rem_scan_retry_progress.sql +24 -0
- package/drizzle/0021_rem_two_facet_storage.down.sql +14 -0
- package/drizzle/0021_rem_two_facet_storage.sql +42 -0
- package/drizzle/0022_rem_facet_chunk_versions.down.sql +4 -0
- package/drizzle/0022_rem_facet_chunk_versions.sql +4 -0
- package/drizzle/0023_rem_defect_ledger.sql +40 -0
- package/drizzle/0024_rem_unbuilt_foundations.down.sql +13 -0
- package/drizzle/0024_rem_unbuilt_foundations.sql +65 -0
- package/drizzle/0025_rem_journal_operation_constraint.sql +28 -0
- package/drizzle/0026_rem_journal_detail.sql +1 -0
- package/drizzle/0027_legacy_nodix_namespace.sql +3 -0
- package/drizzle/0028_memory_timezone.sql +23 -0
- package/drizzle/0029_rem_write_hash_symmetry.sql +17 -0
- package/drizzle/0030_atomic_memory_additive.sql +105 -0
- package/drizzle/0031_atomic_extraction_ledger.sql +23 -0
- package/drizzle/0032_atomic_memory_entities.sql +12 -0
- package/drizzle/0033_todo_own_store.sql +99 -0
- package/drizzle/meta/0000_snapshot.json +87 -0
- package/drizzle/meta/_journal.json +244 -0
- package/generated/rem-operations.json +1 -0
- package/package.json +126 -4
- package/scripts/download-simple-tokenizer.mjs +254 -0
- package/settings.default.json +243 -0
- package/skills/extract-atomic-memory/SKILL.md +298 -0
- package/skills/extract-atomic-memory/references/account-for-turns.md +9 -0
- package/skills/extract-atomic-memory/references/calendar-meaning.md +64 -0
- package/skills/extract-atomic-memory/references/capture.md +120 -0
- package/skills/extract-atomic-memory/references/enrichment.md +92 -0
- package/skills/extract-atomic-memory/references/missing-durable-half.md +6 -0
- package/skills/extract-atomic-memory/references/progress-classification.md +21 -0
- package/skills/extract-atomic-memory/references/resolve-subject.md +19 -0
- package/skills/extract-atomic-memory/references/surrounding-context.md +10 -0
- package/skills/extract-atomic-memory/references/user-subject-guard.md +29 -0
- package/skills/judge-group-closure/SKILL.md +25 -0
- package/skills/judge-rem-memory-updates/SKILL.md +56 -0
- package/skills/judge-rem-memory-updates/agents/openai.yaml +4 -0
- package/skills/judge-retired-position/SKILL.md +25 -0
- package/skills/judge-task-lifecycle/SKILL.md +45 -0
- package/skills/key-state-attribute/SKILL.md +16 -0
- package/skills/resolve-entity-identity/SKILL.md +24 -0
- package/skills/resolve-relative-time/SKILL.md +22 -0
- package/sqlite-extensions/LICENSE-simple-tokenizer +28 -0
- package/sqlite-extensions/LICENSE-sqlite-vec +21 -0
- package/sqlite-extensions/linux-arm64/vec0.so +0 -0
- package/sqlite-extensions/linux-x64/vec0.so +0 -0
|
@@ -0,0 +1,1374 @@
|
|
|
1
|
+
import { ct as FIXED_PROTOCOL_VALUE_69, d as FIXED_EXTERNAL_VALUE_8, f as FIXED_EXTERNAL_VALUE_9 } from "./signed-registry-constants-yq3DlG3B.js";
|
|
2
|
+
import { i as memoryOperationSignal, r as memoryOperationId, t as checkMemoryOperation } from "./operation-cancellation-CTKWwNHk.js";
|
|
3
|
+
import { t as MODEL_CALLS } from "./model-call-table-CspopkBg.js";
|
|
4
|
+
import { classifyLlmFailure, isCredentialFailure, isTransientLlmStatus } from "./internal/model/llm-failure.js";
|
|
5
|
+
import { a as repairCommonJson, i as previewText, n as readModelReplyJson, r as extractJsonFromResponse } from "./model-reply-text-CKopStP2.js";
|
|
6
|
+
import { resolveLlmRoute } from "./internal/model/llm-mode-routing.js";
|
|
7
|
+
import { countTokens } from "@snoai/chunking";
|
|
8
|
+
import { createLogger, withLogContext } from "@snoai/utils/logger";
|
|
9
|
+
import path from "node:path";
|
|
10
|
+
import { createHash, createPublicKey, randomUUID, verify } from "node:crypto";
|
|
11
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
12
|
+
import { existsSync } from "node:fs";
|
|
13
|
+
import { CallPipeline, ConfigRegistryManager, KeyPool, loadLlmixTrustManifest, registryRootOptionsFromTrustManifest } from "@snoai/llmix";
|
|
14
|
+
import { Buffer } from "node:buffer";
|
|
15
|
+
import { fileURLToPath } from "node:url";
|
|
16
|
+
//#region src/model/llmix-registry.ts
|
|
17
|
+
/** @file llmix-registry.ts
|
|
18
|
+
* @purpose Loads the bundled signed LLMIx registry for sno-station-mem.
|
|
19
|
+
* @boundary Trust-anchor verification and package-relative asset resolution only.
|
|
20
|
+
*/
|
|
21
|
+
const SNO_STATION_MEM_RELEASE_ANCHOR_URL = FIXED_EXTERNAL_VALUE_8;
|
|
22
|
+
const SNO_STATION_MEM_RELEASE_KEY_ID = FIXED_EXTERNAL_VALUE_9;
|
|
23
|
+
const SNO_STATION_MEM_RELEASE_ANCHOR_ATTEMPTS = 2;
|
|
24
|
+
const SNO_STATION_MEM_RELEASE_ANCHOR_RETRY_DELAY_MS = 50;
|
|
25
|
+
const ALLOWED_HTTP_ENDPOINT_HOSTS = /* @__PURE__ */ new Set(["localhost", "127.0.0.1"]);
|
|
26
|
+
function parsePresetId(preset) {
|
|
27
|
+
const [module, presetName] = preset.split("/");
|
|
28
|
+
if (!module || !presetName) throw new Error(`sno-station-mem llm-client: invalid LLMIx preset id "${preset}"`);
|
|
29
|
+
return {
|
|
30
|
+
module,
|
|
31
|
+
preset: presetName
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
function assertSupportedProvider(provider) {
|
|
35
|
+
if (provider === "openai" || provider === "openrouter" || provider === "sno-gpu") return provider;
|
|
36
|
+
throw new Error(`sno-station-mem llm-client: unsupported LLMIx provider "${provider}"`);
|
|
37
|
+
}
|
|
38
|
+
function resolveEndpointBase(baseSource, preservePath) {
|
|
39
|
+
let parsed;
|
|
40
|
+
try {
|
|
41
|
+
parsed = new URL(baseSource);
|
|
42
|
+
} catch {
|
|
43
|
+
throw new Error(`sno-station-mem llm-client: invalid extraction.llm.baseURL "${baseSource}"`);
|
|
44
|
+
}
|
|
45
|
+
if (parsed.protocol !== "https:" && !ALLOWED_HTTP_ENDPOINT_HOSTS.has(parsed.hostname)) throw new Error("sno-station-mem llm-client: extraction.llm.baseURL must use https");
|
|
46
|
+
if (parsed.protocol === "https:" && parsed.hostname.toLowerCase() === "api.openai.com") throw new Error("sno-station-mem llm-client: direct api.openai.com transport is forbidden; use local ccproxy or an explicit custom endpoint");
|
|
47
|
+
if (!preservePath) return parsed.origin;
|
|
48
|
+
const base = parsed.toString();
|
|
49
|
+
return base.endsWith("/") ? base : `${base}/`;
|
|
50
|
+
}
|
|
51
|
+
function packageRootFromImportMeta() {
|
|
52
|
+
const moduleDir = path.dirname(fileURLToPath(import.meta.url));
|
|
53
|
+
const bundledRoot = path.resolve(moduleDir, "..");
|
|
54
|
+
return [bundledRoot, path.resolve(moduleDir, "../..")].find(hasBundledRegistryAssets) ?? bundledRoot;
|
|
55
|
+
}
|
|
56
|
+
function hasBundledRegistryAssets(packageRoot) {
|
|
57
|
+
return existsSync(path.join(packageRoot, "config", "llm", "current.json")) && existsSync(path.join(packageRoot, "config", "llm.trust.json"));
|
|
58
|
+
}
|
|
59
|
+
function resolveBundledLlmixRegistryPaths(packageRoot = packageRootFromImportMeta()) {
|
|
60
|
+
const registryDir = path.join(packageRoot, "config", "llm");
|
|
61
|
+
const trustManifestPath = path.join(packageRoot, "config", "llm.trust.json");
|
|
62
|
+
if (!hasBundledRegistryAssets(packageRoot)) throw new Error("sno-station-mem LLMIx registry assets are missing from the installed package");
|
|
63
|
+
return {
|
|
64
|
+
registryDir,
|
|
65
|
+
trustManifestPath
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function isJsonObject(value) {
|
|
69
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
70
|
+
}
|
|
71
|
+
function readPublicKeyJwk(document) {
|
|
72
|
+
if (!isJsonObject(document) || document.id !== "did:web:www.sno.ai") return null;
|
|
73
|
+
const methods = document.verificationMethod;
|
|
74
|
+
if (!Array.isArray(methods)) return null;
|
|
75
|
+
for (const method of methods) {
|
|
76
|
+
if (!isJsonObject(method) || method.id !== SNO_STATION_MEM_RELEASE_KEY_ID) continue;
|
|
77
|
+
const jwk = method.publicKeyJwk;
|
|
78
|
+
if (isJsonObject(jwk) && jwk.kty === "OKP" && jwk.crv === "Ed25519" && typeof jwk.x === "string") return jwk;
|
|
79
|
+
}
|
|
80
|
+
return null;
|
|
81
|
+
}
|
|
82
|
+
function verifyEd25519(jwk, paeBytes, signature) {
|
|
83
|
+
const publicKey = createPublicKey({
|
|
84
|
+
key: jwk,
|
|
85
|
+
format: "jwk"
|
|
86
|
+
});
|
|
87
|
+
return verify(null, Buffer.from(paeBytes), publicKey, Buffer.from(signature, "base64"));
|
|
88
|
+
}
|
|
89
|
+
function releaseAnchorFailureMessage(error) {
|
|
90
|
+
if (!isJsonObject(error) || !isJsonObject(error.details)) return null;
|
|
91
|
+
const cause = error.details.cause;
|
|
92
|
+
if (typeof cause !== "string") return null;
|
|
93
|
+
return cause.includes("sno-station-mem LLMIx release anchor fetch") ? cause : null;
|
|
94
|
+
}
|
|
95
|
+
async function fetchReleaseAnchorOnce(fetchImpl, timeoutMs) {
|
|
96
|
+
const controller = new AbortController();
|
|
97
|
+
let timeout;
|
|
98
|
+
const timeoutPromise = new Promise((_resolve, reject) => {
|
|
99
|
+
timeout = setTimeout(() => {
|
|
100
|
+
controller.abort();
|
|
101
|
+
reject(/* @__PURE__ */ new Error(`sno-station-mem LLMIx release anchor fetch timed out after ${timeoutMs}ms`));
|
|
102
|
+
}, timeoutMs);
|
|
103
|
+
});
|
|
104
|
+
try {
|
|
105
|
+
return await Promise.race([fetchImpl(SNO_STATION_MEM_RELEASE_ANCHOR_URL, { signal: controller.signal }), timeoutPromise]);
|
|
106
|
+
} finally {
|
|
107
|
+
if (timeout !== void 0) clearTimeout(timeout);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
function isTransientAnchorResponse(response) {
|
|
111
|
+
return isTransientLlmStatus(response.status);
|
|
112
|
+
}
|
|
113
|
+
async function fetchReleaseAnchor(fetchImpl, timeoutMs) {
|
|
114
|
+
for (let attempt = 1; attempt <= SNO_STATION_MEM_RELEASE_ANCHOR_ATTEMPTS; attempt++) {
|
|
115
|
+
try {
|
|
116
|
+
const response = await fetchReleaseAnchorOnce(fetchImpl, timeoutMs);
|
|
117
|
+
if (attempt === SNO_STATION_MEM_RELEASE_ANCHOR_ATTEMPTS || !isTransientAnchorResponse(response)) return response;
|
|
118
|
+
} catch (error) {
|
|
119
|
+
if (attempt === SNO_STATION_MEM_RELEASE_ANCHOR_ATTEMPTS) throw error;
|
|
120
|
+
}
|
|
121
|
+
await new Promise((resolve) => setTimeout(resolve, SNO_STATION_MEM_RELEASE_ANCHOR_RETRY_DELAY_MS));
|
|
122
|
+
}
|
|
123
|
+
throw new Error("sno-station-mem LLMIx release anchor fetch exhausted");
|
|
124
|
+
}
|
|
125
|
+
function createSnoMemSnoStationMemDidWebVerifier(fetchImpl = globalThis.fetch, options = {}) {
|
|
126
|
+
const anchorTimeoutMs = options.anchorTimeoutMs ?? 5e3;
|
|
127
|
+
return { async verify(input) {
|
|
128
|
+
if (input.domain !== "www.sno.ai" || input.keyId !== SNO_STATION_MEM_RELEASE_KEY_ID) return false;
|
|
129
|
+
if (input.algorithm !== "ed25519") return false;
|
|
130
|
+
const response = await fetchReleaseAnchor(fetchImpl, anchorTimeoutMs);
|
|
131
|
+
if (!response.ok) return false;
|
|
132
|
+
const jwk = readPublicKeyJwk(await response.json());
|
|
133
|
+
if (jwk === null) return false;
|
|
134
|
+
return verifyEd25519(jwk, input.paeBytes, input.signature);
|
|
135
|
+
} };
|
|
136
|
+
}
|
|
137
|
+
async function openBundledLlmixRegistry(packageRoot, fetchImpl = globalThis.fetch, options = {}) {
|
|
138
|
+
const paths = resolveBundledLlmixRegistryPaths(packageRoot);
|
|
139
|
+
const trustManifest = await loadLlmixTrustManifest(paths.trustManifestPath);
|
|
140
|
+
const signedRoot = registryRootOptionsFromTrustManifest(trustManifest, { didWebVerifier: createSnoMemSnoStationMemDidWebVerifier(fetchImpl, options) });
|
|
141
|
+
try {
|
|
142
|
+
return await ConfigRegistryManager.open(paths.registryDir, { signedRoot });
|
|
143
|
+
} catch (error) {
|
|
144
|
+
const anchorFailure = releaseAnchorFailureMessage(error);
|
|
145
|
+
if (anchorFailure !== null) throw new Error(anchorFailure, { cause: error });
|
|
146
|
+
throw error;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
async function resolveBundledLlmixPreset(presetId) {
|
|
150
|
+
return loadBundledLlmixPreset(await openBundledLlmixRegistry(), presetId);
|
|
151
|
+
}
|
|
152
|
+
async function loadBundledLlmixPreset(registry, presetId) {
|
|
153
|
+
const id = parsePresetId(presetId);
|
|
154
|
+
const preset = await registry.getPreset(id.module, id.preset);
|
|
155
|
+
return {
|
|
156
|
+
preset: presetId,
|
|
157
|
+
provider: assertSupportedProvider(preset.provider),
|
|
158
|
+
model: preset.model,
|
|
159
|
+
...preset.providerOptions ? { providerOptions: preset.providerOptions } : {},
|
|
160
|
+
...preset.timeout?.totalTime ? { timeoutMs: preset.timeout.totalTime * 1e3 } : {}
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
function materializeBundledLlmixEndpoint(input) {
|
|
164
|
+
const path = input.preset.provider === "sno-gpu" ? input.preset.providerOptions?.["sno-gpu"]?.gpuPath : "chat/completions";
|
|
165
|
+
if (!path) throw new Error(`sno-station-mem llm-client: signed endpoint path missing from preset ${input.preset.preset}`);
|
|
166
|
+
return {
|
|
167
|
+
url: new URL(path, resolveEndpointBase(input.baseSource, input.preset.provider !== "sno-gpu")).toString(),
|
|
168
|
+
preset: input.preset
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
async function resolveConfiguredBundledLlmixEndpoint(input) {
|
|
172
|
+
const registry = await openBundledLlmixRegistry();
|
|
173
|
+
const configured = await loadBundledLlmixPreset(registry, input.configuredPresetId);
|
|
174
|
+
const endpointPresetId = input.selectEndpointPreset(configured.provider);
|
|
175
|
+
return materializeBundledLlmixEndpoint({
|
|
176
|
+
preset: endpointPresetId === input.configuredPresetId ? configured : await loadBundledLlmixPreset(registry, endpointPresetId),
|
|
177
|
+
baseSource: input.selectBaseSource(configured.provider)
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
//#endregion
|
|
181
|
+
//#region src/model/llm-endpoint-resolution.ts
|
|
182
|
+
const SNO_GPU_ORIGIN = "https://rt3-llm.sno.ai";
|
|
183
|
+
const PROVIDER_API_BASES = {
|
|
184
|
+
openai: FIXED_PROTOCOL_VALUE_69,
|
|
185
|
+
openrouter: "https://openrouter.ai/api/v1"
|
|
186
|
+
};
|
|
187
|
+
async function resolveSignedPreset(presetId) {
|
|
188
|
+
return resolveBundledLlmixPreset(presetId);
|
|
189
|
+
}
|
|
190
|
+
function selectEndpointPreset(input) {
|
|
191
|
+
return input.provider === "sno-gpu" ? MODEL_CALLS[input.callId].snoPreset : input.configuredPreset;
|
|
192
|
+
}
|
|
193
|
+
async function resolveLlmEndpoint(input) {
|
|
194
|
+
return {
|
|
195
|
+
...await resolveConfiguredBundledLlmixEndpoint({
|
|
196
|
+
configuredPresetId: input.configuredPreset,
|
|
197
|
+
selectEndpointPreset: (provider) => {
|
|
198
|
+
if (input.transport !== "chat-completions" && provider !== "sno-gpu") throw new Error(`sno-station-mem llm-client: ${provider} does not support ${input.transport}`);
|
|
199
|
+
return selectEndpointPreset({
|
|
200
|
+
configuredPreset: input.configuredPreset,
|
|
201
|
+
provider,
|
|
202
|
+
callId: input.callId
|
|
203
|
+
});
|
|
204
|
+
},
|
|
205
|
+
selectBaseSource: (provider) => input.baseOverride ?? (provider === "sno-gpu" ? SNO_GPU_ORIGIN : PROVIDER_API_BASES[provider])
|
|
206
|
+
}),
|
|
207
|
+
userBaseUrlOverride: input.baseOverride !== void 0
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
//#endregion
|
|
211
|
+
//#region src/model/llm-provider-transport.ts
|
|
212
|
+
const log$1 = createLogger("sno-station-mem:llm-provider-transport");
|
|
213
|
+
const routeInFlight = /* @__PURE__ */ new Map();
|
|
214
|
+
const providerResponses = new AsyncLocalStorage();
|
|
215
|
+
async function observeRequest(input, run) {
|
|
216
|
+
const route = createHash("sha256").update(input.endpoint).digest("hex");
|
|
217
|
+
const inFlight = (routeInFlight.get(route) ?? 0) + 1;
|
|
218
|
+
routeInFlight.set(route, inFlight);
|
|
219
|
+
const diagnostic = { started: performance.now() };
|
|
220
|
+
return withLogContext({ attempt_id: randomUUID() }, async () => {
|
|
221
|
+
let outcome = "failed";
|
|
222
|
+
let failure;
|
|
223
|
+
try {
|
|
224
|
+
const result = await run(diagnostic);
|
|
225
|
+
outcome = typeof result === "object" && result !== null && "content" in result && result.content === "" ? "empty_success" : "success";
|
|
226
|
+
return result;
|
|
227
|
+
} catch (error) {
|
|
228
|
+
failure = error;
|
|
229
|
+
outcome = getProviderTerminalCategory(error) ?? "failed";
|
|
230
|
+
throw error;
|
|
231
|
+
} finally {
|
|
232
|
+
const remaining = (routeInFlight.get(route) ?? 1) - 1;
|
|
233
|
+
if (remaining === 0) routeInFlight.delete(route);
|
|
234
|
+
else routeInFlight.set(route, remaining);
|
|
235
|
+
log$1.info("Model request completed", {
|
|
236
|
+
outcome,
|
|
237
|
+
error: failure,
|
|
238
|
+
call_id: input.slot ?? "unavailable",
|
|
239
|
+
destination: input.label ?? "unavailable",
|
|
240
|
+
route_hash: route,
|
|
241
|
+
transport: input.transport,
|
|
242
|
+
requested_model: input.model,
|
|
243
|
+
returned_model: diagnostic.returnedModel ?? "unavailable",
|
|
244
|
+
prompt_template_hash: input.promptTemplateHash ?? "unavailable",
|
|
245
|
+
extraction_skill_hash: input.extractionSkillHash ?? "unavailable",
|
|
246
|
+
prompt_template_unavailable_reason: input.promptTemplateHash ? void 0 : "caller_does_not_provide_template_identity",
|
|
247
|
+
config_hash: createHash("sha256").update(JSON.stringify({
|
|
248
|
+
...input,
|
|
249
|
+
endpoint: route
|
|
250
|
+
})).digest("hex"),
|
|
251
|
+
output_cap: input.cap ?? "unavailable",
|
|
252
|
+
timeout_ms: input.timeout,
|
|
253
|
+
sampling: {
|
|
254
|
+
source: Object.keys(input.sampling).length ? "sent" : "unknown",
|
|
255
|
+
values: input.sampling
|
|
256
|
+
},
|
|
257
|
+
in_flight_at_dispatch: inFlight,
|
|
258
|
+
status_code: diagnostic.status ?? "unavailable",
|
|
259
|
+
duration_ms: performance.now() - diagnostic.started,
|
|
260
|
+
dispatch_to_headers_ms: diagnostic.headersAt === void 0 ? "unavailable" : diagnostic.headersAt - diagnostic.started,
|
|
261
|
+
headers_to_body_ms: diagnostic.headersAt === void 0 || diagnostic.bodyAt === void 0 ? "unavailable" : diagnostic.bodyAt - diagnostic.headersAt,
|
|
262
|
+
first_token_ms: "unavailable",
|
|
263
|
+
first_token_reason: "non_streaming_transport",
|
|
264
|
+
server_queue_ms: "unavailable",
|
|
265
|
+
server_service_ms: "unavailable",
|
|
266
|
+
finish_reason: diagnostic.finishReason ?? "unavailable",
|
|
267
|
+
usage: diagnostic.usage ? {
|
|
268
|
+
source: diagnostic.usage.estimated ? "estimated" : "provider_reported",
|
|
269
|
+
...diagnostic.usage
|
|
270
|
+
} : { source: "unavailable" }
|
|
271
|
+
}, {
|
|
272
|
+
event_name: "llm.request.completed",
|
|
273
|
+
file: "packages/memory/src/model/llm-provider-transport.ts",
|
|
274
|
+
function: "observeRequest",
|
|
275
|
+
site_id: "llm.transport.request.completed"
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
const CCPROXY_OPENAI_BASE_URL = FIXED_PROTOCOL_VALUE_69;
|
|
281
|
+
const CCPROXY_PLACEHOLDER_API_KEY = "ccproxy-placeholder";
|
|
282
|
+
/** Keys from pipeline kwargs that belong in the chat/completions POST body. */
|
|
283
|
+
const FORWARDED_KWARGS = [
|
|
284
|
+
"temperature",
|
|
285
|
+
"top_p",
|
|
286
|
+
"max_tokens",
|
|
287
|
+
"max_completion_tokens",
|
|
288
|
+
"seed",
|
|
289
|
+
"response_format"
|
|
290
|
+
];
|
|
291
|
+
/** Assembles call body from validated inputs for deterministic LLM transport. */
|
|
292
|
+
function buildCallBody(kwargs, provider) {
|
|
293
|
+
const body = {};
|
|
294
|
+
for (const key of FORWARDED_KWARGS) {
|
|
295
|
+
if (provider === "sno-gpu" && key === "temperature") continue;
|
|
296
|
+
if (kwargs[key] != null) body[key] = kwargs[key];
|
|
297
|
+
}
|
|
298
|
+
return body;
|
|
299
|
+
}
|
|
300
|
+
function hasAbortSignalShape$1(value) {
|
|
301
|
+
return typeof value === "object" && value !== null && typeof value.aborted === "boolean" && typeof value.addEventListener === "function";
|
|
302
|
+
}
|
|
303
|
+
function requestAbortSignal(timeoutMs, callerSignal) {
|
|
304
|
+
const timeoutSignal = AbortSignal.timeout(Math.floor(timeoutMs));
|
|
305
|
+
if (!hasAbortSignalShape$1(callerSignal)) return {
|
|
306
|
+
signal: timeoutSignal,
|
|
307
|
+
timeoutSignal
|
|
308
|
+
};
|
|
309
|
+
return {
|
|
310
|
+
signal: callerSignal.aborted ? callerSignal : AbortSignal.any([timeoutSignal, callerSignal]),
|
|
311
|
+
timeoutSignal,
|
|
312
|
+
callerSignal
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
const PROVIDER_TERMINAL_ERROR_PREFIX = "sno-station-mem provider terminal";
|
|
316
|
+
var ProviderTerminalError = class extends Error {
|
|
317
|
+
category;
|
|
318
|
+
statusCode;
|
|
319
|
+
constructor(category, message, statusCode) {
|
|
320
|
+
super(`${PROVIDER_TERMINAL_ERROR_PREFIX} ${category}: ${message}`);
|
|
321
|
+
this.category = category;
|
|
322
|
+
this.name = "ProviderTerminalError";
|
|
323
|
+
this.statusCode = statusCode;
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
/** Recovers terminal transport semantics after CallPipeline serializes an error to text. */
|
|
327
|
+
function getProviderTerminalCategory(error) {
|
|
328
|
+
if (error instanceof ProviderTerminalError) return error.category;
|
|
329
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
330
|
+
const match = new RegExp(`^${PROVIDER_TERMINAL_ERROR_PREFIX} (cancelled|timeout|auth):`).exec(message);
|
|
331
|
+
return match?.[1] === "cancelled" || match?.[1] === "timeout" || match?.[1] === "auth" ? match[1] : null;
|
|
332
|
+
}
|
|
333
|
+
function abortedProviderCategory(requestAbort) {
|
|
334
|
+
if (requestAbort.callerSignal?.aborted) return "cancelled";
|
|
335
|
+
if (requestAbort.timeoutSignal.aborted) return "timeout";
|
|
336
|
+
return null;
|
|
337
|
+
}
|
|
338
|
+
function throwTerminalAbort(error, requestAbort) {
|
|
339
|
+
const category = abortedProviderCategory(requestAbort);
|
|
340
|
+
if (category) throw new ProviderTerminalError(category, error instanceof Error ? error.message : String(error), 499);
|
|
341
|
+
throw error;
|
|
342
|
+
}
|
|
343
|
+
function estimateTokens(text) {
|
|
344
|
+
return Math.max(1, countTokens(text));
|
|
345
|
+
}
|
|
346
|
+
function estimateUsage(messages, content) {
|
|
347
|
+
const inputTokens = estimateTokens(JSON.stringify(messages));
|
|
348
|
+
const outputTokens = estimateTokens(content);
|
|
349
|
+
return {
|
|
350
|
+
inputTokens,
|
|
351
|
+
outputTokens,
|
|
352
|
+
totalTokens: inputTokens + outputTokens,
|
|
353
|
+
estimated: true
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
function readProviderUsage(usage) {
|
|
357
|
+
if (typeof usage?.prompt_tokens === "number" && typeof usage.completion_tokens === "number" && typeof usage.total_tokens === "number") return {
|
|
358
|
+
inputTokens: usage.prompt_tokens,
|
|
359
|
+
outputTokens: usage.completion_tokens,
|
|
360
|
+
totalTokens: usage.total_tokens
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
function normalizeProviderUsage(usage, messages, content) {
|
|
364
|
+
return readProviderUsage(usage) ?? estimateUsage(messages, content);
|
|
365
|
+
}
|
|
366
|
+
function readProviderRequestId(bodyId, headers) {
|
|
367
|
+
return [bodyId, headers.get("x-request-id")].find((value) => typeof value === "string" && /^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/.test(value));
|
|
368
|
+
}
|
|
369
|
+
function notifyProviderResponse(callback, response) {
|
|
370
|
+
providerResponses.getStore()?.push(response);
|
|
371
|
+
callback?.(response);
|
|
372
|
+
}
|
|
373
|
+
/** A call that ended without an answer is still a trace for the request in flight. */
|
|
374
|
+
function recordProviderFailure(response) {
|
|
375
|
+
providerResponses.getStore()?.push(response);
|
|
376
|
+
}
|
|
377
|
+
/**
|
|
378
|
+
* The status line alone does not say what the provider objected to, and a 400 always does — it is
|
|
379
|
+
* the one class of failure where the server knows the answer and we were throwing it away. Measured
|
|
380
|
+
* 2026-08-12: a REM wave died on `B-profile extraction returned HTTP 400`, and the reason for it was
|
|
381
|
+
* unreachable without editing this file and re-running.
|
|
382
|
+
*
|
|
383
|
+
* Read only for a non-auth status: an auth failure's body is the one that can carry credential
|
|
384
|
+
* material back, and it is also the one status that needs no explanation.
|
|
385
|
+
*/
|
|
386
|
+
async function describeProviderFailure(response, diagnostic) {
|
|
387
|
+
let detail;
|
|
388
|
+
try {
|
|
389
|
+
detail = (await response.text()).trim();
|
|
390
|
+
if (diagnostic) diagnostic.bodyAt = performance.now();
|
|
391
|
+
} catch {
|
|
392
|
+
return `HTTP ${response.status}`;
|
|
393
|
+
}
|
|
394
|
+
if (detail.length === 0) return `HTTP ${response.status}`;
|
|
395
|
+
const collapsed = detail.replace(/\s+/g, " ");
|
|
396
|
+
const shown = collapsed.length > 500 ? `${collapsed.slice(0, 500)}…` : collapsed;
|
|
397
|
+
return `HTTP ${response.status}: ${shown}`;
|
|
398
|
+
}
|
|
399
|
+
/** Calls the fixed B-profile raw-completions route without transport-level retries. */
|
|
400
|
+
async function callSnoProfileCompletion(request) {
|
|
401
|
+
return observeRequest({
|
|
402
|
+
endpoint: request.endpointUrl,
|
|
403
|
+
model: request.model,
|
|
404
|
+
transport: "raw-completions",
|
|
405
|
+
slot: request.callId,
|
|
406
|
+
label: request.destination,
|
|
407
|
+
timeout: request.timeoutMs,
|
|
408
|
+
cap: request.singleTokenVerdict ? 1 : request.maxTokens,
|
|
409
|
+
sampling: {},
|
|
410
|
+
promptTemplateHash: request.promptTemplateHash,
|
|
411
|
+
extractionSkillHash: request.extractionSkillHash
|
|
412
|
+
}, async (diagnostic) => {
|
|
413
|
+
const requestAbort = requestAbortSignal(request.timeoutMs, request.signal);
|
|
414
|
+
let response;
|
|
415
|
+
try {
|
|
416
|
+
response = await fetch(request.endpointUrl, {
|
|
417
|
+
method: "POST",
|
|
418
|
+
signal: requestAbort.signal,
|
|
419
|
+
headers: {
|
|
420
|
+
"Content-Type": "application/json",
|
|
421
|
+
"X-Internal-Token": request.apiKey,
|
|
422
|
+
...request.requestId ? { "X-Request-ID": request.requestId } : {},
|
|
423
|
+
...request.operationId ? { "X-Sno-Operation": request.operationId } : {}
|
|
424
|
+
},
|
|
425
|
+
body: JSON.stringify({
|
|
426
|
+
model: request.model,
|
|
427
|
+
prompt: request.prompt,
|
|
428
|
+
...request.singleTokenVerdict ? { max_tokens: 1 } : request.maxTokens ? { max_tokens: request.maxTokens } : {}
|
|
429
|
+
})
|
|
430
|
+
});
|
|
431
|
+
diagnostic.headersAt = performance.now();
|
|
432
|
+
diagnostic.status = response.status;
|
|
433
|
+
} catch (error) {
|
|
434
|
+
throwTerminalAbort(error, requestAbort);
|
|
435
|
+
}
|
|
436
|
+
if (!response.ok) {
|
|
437
|
+
if (classifyLlmFailure({ status: response.status }).category === "auth") throw new ProviderTerminalError("auth", `B-profile extraction returned HTTP ${response.status}`, response.status);
|
|
438
|
+
const error = /* @__PURE__ */ new Error(`B-profile extraction returned ${await describeProviderFailure(response, diagnostic)}`);
|
|
439
|
+
error.statusCode = response.status;
|
|
440
|
+
throw error;
|
|
441
|
+
}
|
|
442
|
+
let body;
|
|
443
|
+
try {
|
|
444
|
+
body = await response.json();
|
|
445
|
+
diagnostic.bodyAt = performance.now();
|
|
446
|
+
} catch (error) {
|
|
447
|
+
throwTerminalAbort(error, requestAbort);
|
|
448
|
+
}
|
|
449
|
+
const content = body.choices?.[0]?.text;
|
|
450
|
+
if (typeof content !== "string") throw new Error("B-profile extraction response is missing choices[0].text");
|
|
451
|
+
const model = typeof body.model === "string" && body.model.trim() ? body.model : void 0;
|
|
452
|
+
const usage = readProviderUsage(body.usage);
|
|
453
|
+
diagnostic.returnedModel = model;
|
|
454
|
+
diagnostic.finishReason = body.choices?.[0]?.finish_reason;
|
|
455
|
+
diagnostic.usage = normalizeProviderUsage(body.usage, [request.prompt], content);
|
|
456
|
+
const requestId = readProviderRequestId(body.id, response.headers);
|
|
457
|
+
if (request.callId && request.destination) notifyProviderResponse(request.onProviderResponse, {
|
|
458
|
+
durationMs: performance.now() - diagnostic.started,
|
|
459
|
+
callId: request.callId,
|
|
460
|
+
destination: request.destination,
|
|
461
|
+
provider: "sno-gpu",
|
|
462
|
+
...requestId ? { requestId } : {},
|
|
463
|
+
...model ? { model } : {},
|
|
464
|
+
...usage ? { usage } : {}
|
|
465
|
+
});
|
|
466
|
+
return {
|
|
467
|
+
content,
|
|
468
|
+
model: model ?? request.model,
|
|
469
|
+
usage: normalizeProviderUsage(body.usage, [request.prompt], content)
|
|
470
|
+
};
|
|
471
|
+
});
|
|
472
|
+
}
|
|
473
|
+
function isCcproxyOpenAiBaseUrl(value) {
|
|
474
|
+
if (!value) return false;
|
|
475
|
+
try {
|
|
476
|
+
const configured = new URL(value);
|
|
477
|
+
const expected = new URL(CCPROXY_OPENAI_BASE_URL);
|
|
478
|
+
return configured.origin === expected.origin && configured.pathname.replace(/\/+$/, "") === expected.pathname.replace(/\/+$/, "");
|
|
479
|
+
} catch {
|
|
480
|
+
return false;
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
async function snoStationMemDispatch(ctx) {
|
|
484
|
+
const cfgExt = ctx.config;
|
|
485
|
+
const provider = ctx.provider;
|
|
486
|
+
if (provider !== "openai" && provider !== "openrouter" && provider !== "sno-gpu") throw new Error(`sno-station-mem llm-client: unsupported provider "${provider}"`);
|
|
487
|
+
const endpointUrl = cfgExt.endpointUrl;
|
|
488
|
+
if (typeof endpointUrl !== "string") throw new Error("sno-station-mem llm-client: resolved endpointUrl is required");
|
|
489
|
+
const timeoutMs = cfgExt.timeoutMs ?? 3e4;
|
|
490
|
+
const callBody = buildCallBody(ctx.kwargs, provider);
|
|
491
|
+
const sampling = Object.fromEntries([
|
|
492
|
+
"temperature",
|
|
493
|
+
"top_p",
|
|
494
|
+
"seed"
|
|
495
|
+
].flatMap((key) => callBody[key] === void 0 ? [] : [[key, callBody[key]]]));
|
|
496
|
+
return observeRequest({
|
|
497
|
+
endpoint: endpointUrl,
|
|
498
|
+
model: ctx.model,
|
|
499
|
+
transport: "chat-completions",
|
|
500
|
+
slot: cfgExt.callId,
|
|
501
|
+
label: cfgExt.destination,
|
|
502
|
+
timeout: timeoutMs,
|
|
503
|
+
cap: typeof callBody.max_tokens === "number" ? callBody.max_tokens : typeof callBody.max_completion_tokens === "number" ? callBody.max_completion_tokens : void 0,
|
|
504
|
+
sampling,
|
|
505
|
+
promptTemplateHash: cfgExt.promptTemplateHash,
|
|
506
|
+
extractionSkillHash: cfgExt.extractionSkillHash,
|
|
507
|
+
forwardedConfigHash: createHash("sha256").update(JSON.stringify({
|
|
508
|
+
response_format: callBody.response_format,
|
|
509
|
+
seed: callBody.seed,
|
|
510
|
+
max_tokens: callBody.max_tokens,
|
|
511
|
+
max_completion_tokens: callBody.max_completion_tokens,
|
|
512
|
+
temperature: callBody.temperature,
|
|
513
|
+
top_p: callBody.top_p
|
|
514
|
+
})).digest("hex")
|
|
515
|
+
}, async (diagnostic) => {
|
|
516
|
+
const requestAbort = requestAbortSignal(timeoutMs, cfgExt.signal);
|
|
517
|
+
const headers = { "Content-Type": "application/json" };
|
|
518
|
+
if (typeof cfgExt.requestId === "string") headers["X-Request-ID"] = cfgExt.requestId;
|
|
519
|
+
if (provider === "sno-gpu") {
|
|
520
|
+
headers["X-Internal-Token"] = ctx.apiKey;
|
|
521
|
+
if (typeof cfgExt.operationId === "string") headers["X-Sno-Operation"] = cfgExt.operationId;
|
|
522
|
+
} else headers.Authorization = `Bearer ${ctx.apiKey}`;
|
|
523
|
+
let response;
|
|
524
|
+
try {
|
|
525
|
+
response = await fetch(endpointUrl, {
|
|
526
|
+
method: "POST",
|
|
527
|
+
signal: requestAbort.signal,
|
|
528
|
+
headers,
|
|
529
|
+
body: JSON.stringify({
|
|
530
|
+
model: ctx.model,
|
|
531
|
+
messages: ctx.messages,
|
|
532
|
+
...callBody
|
|
533
|
+
})
|
|
534
|
+
});
|
|
535
|
+
diagnostic.headersAt = performance.now();
|
|
536
|
+
diagnostic.status = response.status;
|
|
537
|
+
} catch (error) {
|
|
538
|
+
const category = abortedProviderCategory(requestAbort);
|
|
539
|
+
if (category) throw new ProviderTerminalError(category, error instanceof Error ? error.message : String(error), 499);
|
|
540
|
+
throw error;
|
|
541
|
+
}
|
|
542
|
+
if (!response.ok) {
|
|
543
|
+
if (classifyLlmFailure({ status: response.status }).category === "auth") throw new ProviderTerminalError("auth", `HTTP ${response.status}`, response.status);
|
|
544
|
+
const err = new Error(await describeProviderFailure(response, diagnostic));
|
|
545
|
+
err.statusCode = response.status;
|
|
546
|
+
throw err;
|
|
547
|
+
}
|
|
548
|
+
let body;
|
|
549
|
+
try {
|
|
550
|
+
body = await response.json();
|
|
551
|
+
diagnostic.bodyAt = performance.now();
|
|
552
|
+
} catch (parseErr) {
|
|
553
|
+
if (abortedProviderCategory(requestAbort)) throwTerminalAbort(parseErr, requestAbort);
|
|
554
|
+
const err = /* @__PURE__ */ new Error(`Malformed response body: ${parseErr instanceof Error ? parseErr.message : String(parseErr)}`);
|
|
555
|
+
err.statusCode = 502;
|
|
556
|
+
throw err;
|
|
557
|
+
}
|
|
558
|
+
const rawContent = body.choices?.[0]?.message?.content;
|
|
559
|
+
if (typeof rawContent !== "string") {
|
|
560
|
+
const err = /* @__PURE__ */ new Error("Chat completion response is missing choices[0].message.content");
|
|
561
|
+
err.statusCode = 502;
|
|
562
|
+
throw err;
|
|
563
|
+
}
|
|
564
|
+
const content = rawContent;
|
|
565
|
+
const model = typeof body.model === "string" && body.model.trim() ? body.model : void 0;
|
|
566
|
+
const usage = readProviderUsage(body.usage);
|
|
567
|
+
diagnostic.returnedModel = model;
|
|
568
|
+
diagnostic.finishReason = body.choices?.[0]?.finish_reason;
|
|
569
|
+
diagnostic.usage = normalizeProviderUsage(body.usage, ctx.messages, content);
|
|
570
|
+
const requestId = readProviderRequestId(body.id, response.headers);
|
|
571
|
+
const onProviderResponse = cfgExt.onProviderResponse;
|
|
572
|
+
if (cfgExt.callId && cfgExt.destination) notifyProviderResponse(typeof onProviderResponse === "function" ? onProviderResponse : void 0, {
|
|
573
|
+
durationMs: performance.now() - diagnostic.started,
|
|
574
|
+
callId: cfgExt.callId,
|
|
575
|
+
destination: cfgExt.destination,
|
|
576
|
+
provider,
|
|
577
|
+
...requestId ? { requestId } : {},
|
|
578
|
+
...model ? { model } : {},
|
|
579
|
+
...usage ? { usage } : {}
|
|
580
|
+
});
|
|
581
|
+
return {
|
|
582
|
+
content,
|
|
583
|
+
model: model ?? ctx.model,
|
|
584
|
+
usage: normalizeProviderUsage(body.usage, ctx.messages, content)
|
|
585
|
+
};
|
|
586
|
+
});
|
|
587
|
+
}
|
|
588
|
+
async function callProvider(ctx) {
|
|
589
|
+
const cfgExt = ctx.config;
|
|
590
|
+
const rawCompletion = cfgExt.rawCompletion;
|
|
591
|
+
if (typeof rawCompletion === "object" && rawCompletion !== null) {
|
|
592
|
+
const raw = rawCompletion;
|
|
593
|
+
if (typeof raw.endpointUrl !== "string" || typeof raw.prompt !== "string" || typeof raw.timeoutMs !== "number") throw new Error("sno-station-mem llm-client: invalid raw profile completion config");
|
|
594
|
+
return {
|
|
595
|
+
...await callSnoProfileCompletion({
|
|
596
|
+
...cfgExt.promptTemplateHash ? { promptTemplateHash: cfgExt.promptTemplateHash } : {},
|
|
597
|
+
...cfgExt.extractionSkillHash ? { extractionSkillHash: cfgExt.extractionSkillHash } : {},
|
|
598
|
+
endpointUrl: raw.endpointUrl,
|
|
599
|
+
model: ctx.model,
|
|
600
|
+
apiKey: ctx.apiKey,
|
|
601
|
+
prompt: raw.prompt,
|
|
602
|
+
timeoutMs: raw.timeoutMs,
|
|
603
|
+
...cfgExt.callId ? { callId: cfgExt.callId } : {},
|
|
604
|
+
...cfgExt.destination ? { destination: cfgExt.destination } : {},
|
|
605
|
+
...cfgExt.onProviderResponse ? { onProviderResponse: cfgExt.onProviderResponse } : {},
|
|
606
|
+
...typeof raw.requestId === "string" ? { requestId: raw.requestId } : {},
|
|
607
|
+
...typeof raw.operationId === "string" ? { operationId: raw.operationId } : {},
|
|
608
|
+
...typeof raw.maxTokens === "number" ? { maxTokens: raw.maxTokens } : {},
|
|
609
|
+
...raw.singleTokenVerdict === true ? { singleTokenVerdict: true } : {},
|
|
610
|
+
...hasAbortSignalShape$1(raw.signal) ? { signal: raw.signal } : {}
|
|
611
|
+
}),
|
|
612
|
+
success: true
|
|
613
|
+
};
|
|
614
|
+
}
|
|
615
|
+
return {
|
|
616
|
+
...await snoStationMemDispatch(ctx),
|
|
617
|
+
success: true
|
|
618
|
+
};
|
|
619
|
+
}
|
|
620
|
+
function resolveProviderApiKey(config, resolved, userBaseUrlOverride) {
|
|
621
|
+
if (config.apiKey?.trim()) return config.apiKey;
|
|
622
|
+
if (resolved.provider === "openai" && (!userBaseUrlOverride || isCcproxyOpenAiBaseUrl(config.baseURL?.trim()))) return CCPROXY_PLACEHOLDER_API_KEY;
|
|
623
|
+
throw new Error(`sno-station-mem llm-client: missing API key for preset ${config.preset}; set snoGpu.apiKey`);
|
|
624
|
+
}
|
|
625
|
+
//#endregion
|
|
626
|
+
//#region src/model/llm-client.ts
|
|
627
|
+
const log = createLogger("sno-station-mem:llm-client");
|
|
628
|
+
let hostRequestsInFlight = 0;
|
|
629
|
+
/**
|
|
630
|
+
* Last-resort output cap for a raw-completion caller that set none. Every use is logged as an
|
|
631
|
+
* error naming the caller, because this exists to keep a broken call alive, not to spare anyone
|
|
632
|
+
* from choosing their own budget.
|
|
633
|
+
*/
|
|
634
|
+
const RAW_COMPLETION_FALLBACK_MAX_TOKENS = 4096;
|
|
635
|
+
/**
|
|
636
|
+
* How many times one request may be asked before an empty reply is accepted as the answer.
|
|
637
|
+
*
|
|
638
|
+
* The serving side answers an otherwise valid request with an empty body often enough to matter:
|
|
639
|
+
* measured 2026-08-17 against the live endpoint, 25% of 36 paired calls with `enable_thinking`
|
|
640
|
+
* and 31% without (llm-provider-transport.ts:242, where that fault is recorded as still open).
|
|
641
|
+
* An empty body is not a transport error, so the call pipeline never retried it, and every caller
|
|
642
|
+
* turned it into `null`. The REM replace clause stage then journals that null as
|
|
643
|
+
* `clause_parse_failed` and releases the pair, so the memory is never updated at all — measured
|
|
644
|
+
* 2026-08-26, 2 of 4 identical runs of `rem-replace-roundtrip-reopen` died that way on a
|
|
645
|
+
* two-clause fixture the model answers correctly 12 times out of 12 when asked directly.
|
|
646
|
+
*
|
|
647
|
+
* Asking again is all this does. It is bounded by attempt count AND by the caller's own deadline,
|
|
648
|
+
* so a slow endpoint cannot turn one request into three timeouts. It does not repair the
|
|
649
|
+
* serving-side fault and must not be read as having repaired it.
|
|
650
|
+
*/
|
|
651
|
+
const EMPTY_REPLY_ATTEMPTS = 3;
|
|
652
|
+
const JSON_SYSTEM_CONTENT = "You are a memory extraction assistant. Always respond with valid JSON only.";
|
|
653
|
+
const JSON_REPAIR_INSTRUCTION = "Your previous reply was not valid JSON. Respond with ONLY the JSON object, no prose.";
|
|
654
|
+
const REFLECTION_TEXT_SYSTEM_CONTENT = "You are a memory reflection assistant. Return concise plain text only.";
|
|
655
|
+
const CONFLICT_ADJUDICATION_SYSTEM_CONTENT = "You adjudicate memory conflicts. Follow the verdict contract and return only the requested JSON object or verdict token.";
|
|
656
|
+
var LlmClientTerminalError = class extends Error {
|
|
657
|
+
category;
|
|
658
|
+
requestTimedOut;
|
|
659
|
+
constructor(category, message, requestTimedOut = false) {
|
|
660
|
+
super(message);
|
|
661
|
+
this.category = category;
|
|
662
|
+
this.requestTimedOut = requestTimedOut;
|
|
663
|
+
this.name = "LlmClientTerminalError";
|
|
664
|
+
}
|
|
665
|
+
};
|
|
666
|
+
var ModelCallRefusedError = class extends Error {
|
|
667
|
+
callId;
|
|
668
|
+
destination;
|
|
669
|
+
reason;
|
|
670
|
+
constructor(callId, destination, reason) {
|
|
671
|
+
super(reason);
|
|
672
|
+
this.callId = callId;
|
|
673
|
+
this.destination = destination;
|
|
674
|
+
this.reason = reason;
|
|
675
|
+
this.name = "ModelCallRefusedError";
|
|
676
|
+
}
|
|
677
|
+
};
|
|
678
|
+
/**
|
|
679
|
+
* Whether a failure ends the whole run rather than costing one call.
|
|
680
|
+
*
|
|
681
|
+
* A real cancellation and an auth failure are terminal: nothing downstream should keep spending
|
|
682
|
+
* model time or, worse, keep writing. A timeout is NOT — the transport aborts on its own deadline
|
|
683
|
+
* and reports `cancelled` with `requestTimedOut` set, and treating that as a cancellation once
|
|
684
|
+
* cost an entire conversation for one slow call.
|
|
685
|
+
*
|
|
686
|
+
* SOURCE OF TRUTH. The same predicate is spelled out by hand in memory-extraction-pipeline.ts,
|
|
687
|
+
* task-lifecycle-route.ts, profile-section-writer.ts and b-profile-extraction.ts; those copies
|
|
688
|
+
* should be replaced by this import, and are flagged rather than changed here.
|
|
689
|
+
*/
|
|
690
|
+
function isTerminalLlmFailure(error) {
|
|
691
|
+
return error instanceof LlmClientTerminalError && (error.category === "cancelled" && !error.requestTimedOut || error.category === "auth");
|
|
692
|
+
}
|
|
693
|
+
function parseJsonResponse(raw, accept) {
|
|
694
|
+
const parsedValue = readModelReplyJson(raw, (value) => accept === void 0 || accept(value) ? { value } : void 0);
|
|
695
|
+
if (parsedValue !== void 0) return {
|
|
696
|
+
ok: true,
|
|
697
|
+
value: parsedValue.value
|
|
698
|
+
};
|
|
699
|
+
const jsonStr = extractJsonFromResponse(raw);
|
|
700
|
+
if (!jsonStr) return {
|
|
701
|
+
ok: false,
|
|
702
|
+
error: `no JSON found (chars=${raw.length}, preview=${JSON.stringify(previewText(raw))})`
|
|
703
|
+
};
|
|
704
|
+
try {
|
|
705
|
+
const value = JSON.parse(jsonStr);
|
|
706
|
+
if (accept && !accept(value)) return {
|
|
707
|
+
ok: false,
|
|
708
|
+
error: "caller check rejected payload"
|
|
709
|
+
};
|
|
710
|
+
return {
|
|
711
|
+
ok: true,
|
|
712
|
+
value
|
|
713
|
+
};
|
|
714
|
+
} catch (error) {
|
|
715
|
+
const repairedJsonStr = repairCommonJson(jsonStr);
|
|
716
|
+
if (repairedJsonStr !== jsonStr) try {
|
|
717
|
+
const value = JSON.parse(repairedJsonStr);
|
|
718
|
+
if (accept && !accept(value)) return {
|
|
719
|
+
ok: false,
|
|
720
|
+
error: "caller check rejected payload"
|
|
721
|
+
};
|
|
722
|
+
return {
|
|
723
|
+
ok: true,
|
|
724
|
+
value
|
|
725
|
+
};
|
|
726
|
+
} catch {
|
|
727
|
+
return {
|
|
728
|
+
ok: false,
|
|
729
|
+
error: `JSON.parse failed: ${error instanceof Error ? error.message : String(error)}; repair also failed (chars=${jsonStr.length})`
|
|
730
|
+
};
|
|
731
|
+
}
|
|
732
|
+
return {
|
|
733
|
+
ok: false,
|
|
734
|
+
error: `JSON.parse failed: ${error instanceof Error ? error.message : String(error)} (chars=${jsonStr.length})`
|
|
735
|
+
};
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
function buildPipelineConfig(preset, config, endpoint, request, destination, operationId) {
|
|
739
|
+
return {
|
|
740
|
+
provider: preset.provider,
|
|
741
|
+
model: preset.model,
|
|
742
|
+
...preset.providerOptions ? { providerOptions: preset.providerOptions } : {},
|
|
743
|
+
timeout: { totalTime: Math.ceil((request.timeoutMs ?? config.timeoutMs ?? preset.timeoutMs ?? 3e4) / 1e3) },
|
|
744
|
+
common: {
|
|
745
|
+
enableThinking: request.enableThinking ?? false,
|
|
746
|
+
maxOutputTokens: request.maxTokens ?? 4096
|
|
747
|
+
},
|
|
748
|
+
caching: { strategy: "disabled" },
|
|
749
|
+
preset: preset.preset,
|
|
750
|
+
baseUrl: endpoint.url,
|
|
751
|
+
endpointUrl: endpoint.url,
|
|
752
|
+
...endpoint.userBaseUrlOverride ? { userBaseUrlOverride: endpoint.userBaseUrlOverride } : {},
|
|
753
|
+
timeoutMs: request.timeoutMs ?? config.timeoutMs ?? preset.timeoutMs ?? 3e4,
|
|
754
|
+
callId: request.callId,
|
|
755
|
+
destination,
|
|
756
|
+
...request.requestId ? { requestId: request.requestId } : {},
|
|
757
|
+
...operationId ? { operationId } : {},
|
|
758
|
+
...request.promptTemplateHash ? { promptTemplateHash: request.promptTemplateHash } : {},
|
|
759
|
+
...request.extractionSkillHash ? { extractionSkillHash: request.extractionSkillHash } : {},
|
|
760
|
+
...request.signal ? { signal: request.signal } : {},
|
|
761
|
+
...config.onProviderResponse ? { onProviderResponse: config.onProviderResponse } : {}
|
|
762
|
+
};
|
|
763
|
+
}
|
|
764
|
+
function hasAbortSignalShape(value) {
|
|
765
|
+
return typeof value === "object" && value !== null && typeof value.aborted === "boolean" && typeof value.addEventListener === "function";
|
|
766
|
+
}
|
|
767
|
+
function readRequiredString(request, field) {
|
|
768
|
+
const value = request[field];
|
|
769
|
+
if (typeof value !== "string" || !value.trim()) throw new Error(`sno-station-mem llm-client: ${field} is required`);
|
|
770
|
+
return value;
|
|
771
|
+
}
|
|
772
|
+
function normalizeMemoryLlmRequest(value) {
|
|
773
|
+
if (typeof value !== "object" || value === null) throw new Error("sno-station-mem llm-client: structured request object is required");
|
|
774
|
+
const raw = value;
|
|
775
|
+
const prompt = readRequiredString(raw, "prompt");
|
|
776
|
+
const callId = readRequiredString(raw, "callId");
|
|
777
|
+
if (!(callId in MODEL_CALLS)) throw new Error(`Unknown model call id ${callId}`);
|
|
778
|
+
const timeoutMs = raw.timeoutMs;
|
|
779
|
+
if (timeoutMs !== void 0 && (!Number.isFinite(timeoutMs) || Number(timeoutMs) <= 0)) throw new Error("sno-station-mem llm-client: timeoutMs must be a positive number");
|
|
780
|
+
const maxTokens = raw.maxTokens;
|
|
781
|
+
if (maxTokens !== void 0 && (!Number.isInteger(maxTokens) || Number(maxTokens) <= 0)) throw new Error("sno-station-mem llm-client: maxTokens must be a positive integer");
|
|
782
|
+
const emptyReplyAttempts = raw.emptyReplyAttempts;
|
|
783
|
+
if (emptyReplyAttempts !== void 0 && (!Number.isInteger(emptyReplyAttempts) || Number(emptyReplyAttempts) < 1 || Number(emptyReplyAttempts) > EMPTY_REPLY_ATTEMPTS)) throw new Error(`sno-station-mem llm-client: emptyReplyAttempts must be an integer from 1 to ${EMPTY_REPLY_ATTEMPTS}`);
|
|
784
|
+
const enableThinking = raw.enableThinking;
|
|
785
|
+
if (enableThinking !== void 0 && typeof enableThinking !== "boolean") throw new Error("sno-station-mem llm-client: enableThinking must be a boolean");
|
|
786
|
+
const signal = raw.signal;
|
|
787
|
+
if (signal !== void 0 && !hasAbortSignalShape(signal)) throw new Error("sno-station-mem llm-client: signal must be an AbortSignal");
|
|
788
|
+
const requestId = raw.requestId;
|
|
789
|
+
if (requestId !== void 0 && (typeof requestId !== "string" || !/^[A-Za-z0-9][A-Za-z0-9._:-]{0,127}$/.test(requestId))) throw new Error("sno-station-mem llm-client: requestId must be a content-free correlation token");
|
|
790
|
+
return {
|
|
791
|
+
prompt,
|
|
792
|
+
...typeof raw.hostPrompt === "string" ? { hostPrompt: raw.hostPrompt } : {},
|
|
793
|
+
callId,
|
|
794
|
+
...timeoutMs !== void 0 ? { timeoutMs: Number(timeoutMs) } : {},
|
|
795
|
+
...maxTokens !== void 0 ? { maxTokens: Number(maxTokens) } : {},
|
|
796
|
+
...emptyReplyAttempts !== void 0 ? { emptyReplyAttempts: Number(emptyReplyAttempts) } : {},
|
|
797
|
+
...enableThinking !== void 0 ? { enableThinking } : {},
|
|
798
|
+
...requestId !== void 0 ? { requestId } : {},
|
|
799
|
+
...typeof raw.promptTemplateHash === "string" && /^[a-f0-9]{64}$/.test(raw.promptTemplateHash) ? { promptTemplateHash: raw.promptTemplateHash } : {},
|
|
800
|
+
...typeof raw.extractionSkillHash === "string" && /^[a-f0-9]{64}$/.test(raw.extractionSkillHash) ? { extractionSkillHash: raw.extractionSkillHash } : {},
|
|
801
|
+
...signal ? { signal } : {}
|
|
802
|
+
};
|
|
803
|
+
}
|
|
804
|
+
function textSystemContent(request) {
|
|
805
|
+
return MODEL_CALLS[request.callId].occasion === "conflictAdjudication" ? CONFLICT_ADJUDICATION_SYSTEM_CONTENT : REFLECTION_TEXT_SYSTEM_CONTENT;
|
|
806
|
+
}
|
|
807
|
+
/** Creates the LLM client facade with provider routing, key rotation, and JSON parsing. */
|
|
808
|
+
function createLlmClient(config) {
|
|
809
|
+
let presetPromise = null;
|
|
810
|
+
const getPreset = () => {
|
|
811
|
+
presetPromise ??= resolveSignedPreset(config.preset).catch((error) => {
|
|
812
|
+
presetPromise = null;
|
|
813
|
+
throw error;
|
|
814
|
+
});
|
|
815
|
+
return presetPromise;
|
|
816
|
+
};
|
|
817
|
+
const endpointPromises = /* @__PURE__ */ new Map();
|
|
818
|
+
const getEndpoint = (callId, transport) => {
|
|
819
|
+
const key = `${callId}:${transport}`;
|
|
820
|
+
let endpointPromise = endpointPromises.get(key);
|
|
821
|
+
if (!endpointPromise) {
|
|
822
|
+
endpointPromise = resolveLlmEndpoint({
|
|
823
|
+
configuredPreset: config.preset,
|
|
824
|
+
callId,
|
|
825
|
+
transport,
|
|
826
|
+
...config.baseURL ? { baseOverride: config.baseURL } : {}
|
|
827
|
+
}).catch((error) => {
|
|
828
|
+
endpointPromises.delete(key);
|
|
829
|
+
throw error;
|
|
830
|
+
});
|
|
831
|
+
endpointPromises.set(key, endpointPromise);
|
|
832
|
+
}
|
|
833
|
+
return endpointPromise;
|
|
834
|
+
};
|
|
835
|
+
const pipeline = new CallPipeline({
|
|
836
|
+
dispatch: callProvider,
|
|
837
|
+
maxRetries: 2,
|
|
838
|
+
retryBaseMs: 100,
|
|
839
|
+
retryMaxDelayMs: 500,
|
|
840
|
+
transformKwargsOverrides: { "sno-gpu": (_context, kwargs) => kwargs }
|
|
841
|
+
});
|
|
842
|
+
let lastError = null;
|
|
843
|
+
let lastUsage = null;
|
|
844
|
+
const resolveRequestTimeoutMs = (request) => request.timeoutMs ?? config.timeoutMs ?? 3e4;
|
|
845
|
+
const destinationFor = (request) => {
|
|
846
|
+
if (!config.routing) return "host";
|
|
847
|
+
const route = resolveLlmRoute({
|
|
848
|
+
callId: request.callId,
|
|
849
|
+
config: config.routing
|
|
850
|
+
});
|
|
851
|
+
return "off" in route ? "off" : route.destination;
|
|
852
|
+
};
|
|
853
|
+
/**
|
|
854
|
+
* Resolves the transport this facade can dispatch. A routed-OFF request is
|
|
855
|
+
* a graceful no-op (not an error), and an unavailable transport also skips.
|
|
856
|
+
* Neither case substitutes another tier.
|
|
857
|
+
*/
|
|
858
|
+
const resolveRequestTransport = (state, request) => {
|
|
859
|
+
if (!config.routing) return "chat-completions";
|
|
860
|
+
const decision = resolveLlmRoute({
|
|
861
|
+
callId: request.callId,
|
|
862
|
+
config: config.routing
|
|
863
|
+
});
|
|
864
|
+
if ("off" in decision) {
|
|
865
|
+
log.debug("Model client request diagnostic", {
|
|
866
|
+
call_id: request.callId,
|
|
867
|
+
destination: destinationFor(request),
|
|
868
|
+
error: `sno-station-mem: llm-client [${request.callId}] routed off (${decision.reason}); deterministic fallback applies`
|
|
869
|
+
}, {
|
|
870
|
+
event_name: "memory.llm_client.diagnostic",
|
|
871
|
+
file: "packages/memory/src/model/llm-client.ts",
|
|
872
|
+
function: "resolveRequestTransport",
|
|
873
|
+
site_id: "shared.llm-client.resolveRequestTransport.8f631601af"
|
|
874
|
+
});
|
|
875
|
+
return null;
|
|
876
|
+
}
|
|
877
|
+
if (decision.transport === "agent-host-seam") {
|
|
878
|
+
if (config.agentPort) return "agent-host-seam";
|
|
879
|
+
state.error = `sno-station-mem: llm-client [${request.callId}] routed to agent-host-seam but AgentLlmPort is unavailable`;
|
|
880
|
+
log.warn("Model client request diagnostic", {
|
|
881
|
+
call_id: request.callId,
|
|
882
|
+
destination: destinationFor(request),
|
|
883
|
+
error: state.error
|
|
884
|
+
}, {
|
|
885
|
+
event_name: "memory.llm_client.diagnostic",
|
|
886
|
+
file: "packages/memory/src/model/llm-client.ts",
|
|
887
|
+
function: "resolveRequestTransport",
|
|
888
|
+
site_id: "shared.llm-client.resolveRequestTransport.ffa933b519"
|
|
889
|
+
});
|
|
890
|
+
return null;
|
|
891
|
+
}
|
|
892
|
+
return decision.transport;
|
|
893
|
+
};
|
|
894
|
+
const requestContent = async (state, request, systemContent, prompt = request.prompt, forcedDestination) => {
|
|
895
|
+
checkMemoryOperation();
|
|
896
|
+
state.error = null;
|
|
897
|
+
state.usage = null;
|
|
898
|
+
const transport = forcedDestination === "host" ? "agent-host-seam" : resolveRequestTransport(state, request);
|
|
899
|
+
if (!transport) return null;
|
|
900
|
+
const route = config.routing ? resolveLlmRoute({
|
|
901
|
+
callId: request.callId,
|
|
902
|
+
config: config.routing
|
|
903
|
+
}) : null;
|
|
904
|
+
const destination = forcedDestination ?? (route && "destination" in route ? route.destination : "host");
|
|
905
|
+
if (transport === "agent-host-seam") {
|
|
906
|
+
const agentPort = config.agentPort;
|
|
907
|
+
if (!agentPort) throw new LlmClientTerminalError("transport", `sno-station-mem: llm-client [${request.callId}] AgentLlmPort is unavailable`);
|
|
908
|
+
config.onTransportAttempt?.({
|
|
909
|
+
callId: request.callId,
|
|
910
|
+
destination,
|
|
911
|
+
transport
|
|
912
|
+
});
|
|
913
|
+
const hostStarted = performance.now();
|
|
914
|
+
const hostInFlight = ++hostRequestsInFlight;
|
|
915
|
+
const result = await withLogContext({ attempt_id: randomUUID() }, async () => {
|
|
916
|
+
let outcome = "failed";
|
|
917
|
+
try {
|
|
918
|
+
const completion = await agentPort.complete({
|
|
919
|
+
system: systemContent,
|
|
920
|
+
prompt,
|
|
921
|
+
maxTokens: request.maxTokens ?? 4096,
|
|
922
|
+
...request.enableThinking !== void 0 ? { enableThinking: request.enableThinking } : {},
|
|
923
|
+
timeoutMs: resolveRequestTimeoutMs(request),
|
|
924
|
+
...request.signal ? { signal: request.signal } : {}
|
|
925
|
+
});
|
|
926
|
+
outcome = completion.kind;
|
|
927
|
+
return completion;
|
|
928
|
+
} finally {
|
|
929
|
+
hostRequestsInFlight -= 1;
|
|
930
|
+
log.info("Host model request completed", {
|
|
931
|
+
outcome,
|
|
932
|
+
transport: "agent-host-seam",
|
|
933
|
+
call_id: request.callId,
|
|
934
|
+
destination,
|
|
935
|
+
duration_ms: performance.now() - hostStarted,
|
|
936
|
+
in_flight_at_dispatch: hostInFlight,
|
|
937
|
+
requested_model: "unavailable",
|
|
938
|
+
returned_model: "unavailable",
|
|
939
|
+
usage: { source: "unavailable" },
|
|
940
|
+
prompt_template_hash: request.promptTemplateHash ?? "unavailable",
|
|
941
|
+
extraction_skill_hash: request.extractionSkillHash ?? "unavailable",
|
|
942
|
+
prompt_template_unavailable_reason: request.promptTemplateHash ? void 0 : "caller_does_not_provide_template_identity",
|
|
943
|
+
config_hash: createHash("sha256").update(JSON.stringify({
|
|
944
|
+
transport,
|
|
945
|
+
maxTokens: request.maxTokens ?? 4096,
|
|
946
|
+
timeoutMs: resolveRequestTimeoutMs(request)
|
|
947
|
+
})).digest("hex"),
|
|
948
|
+
output_cap: "unavailable",
|
|
949
|
+
passed_output_cap: request.maxTokens ?? 4096,
|
|
950
|
+
output_cap_reason: "host_may_strip_requested_cap",
|
|
951
|
+
timeout_ms: resolveRequestTimeoutMs(request),
|
|
952
|
+
sampling: { source: "unknown" },
|
|
953
|
+
finish_reason: "unavailable",
|
|
954
|
+
route: "agent-host-seam",
|
|
955
|
+
dispatch_to_headers_ms: "unavailable",
|
|
956
|
+
headers_to_body_ms: "unavailable",
|
|
957
|
+
first_token_ms: "unavailable",
|
|
958
|
+
provider_unavailable_reason: "host_port_does_not_report_provider_fields"
|
|
959
|
+
}, {
|
|
960
|
+
event_name: "llm.request.completed",
|
|
961
|
+
file: "packages/memory/src/model/llm-client.ts",
|
|
962
|
+
function: "requestContent",
|
|
963
|
+
site_id: "llm.host.request.completed"
|
|
964
|
+
});
|
|
965
|
+
}
|
|
966
|
+
});
|
|
967
|
+
if (result.kind === "cancelled") {
|
|
968
|
+
state.error = `[${request.callId}] agent-llm cancelled (${result.reason})`;
|
|
969
|
+
log.warn("Host model request cancelled", {
|
|
970
|
+
call_id: request.callId,
|
|
971
|
+
destination,
|
|
972
|
+
error: state.error
|
|
973
|
+
}, {
|
|
974
|
+
event_name: "memory.llm_client.diagnostic",
|
|
975
|
+
file: "packages/memory/src/model/llm-client.ts",
|
|
976
|
+
function: "requestContent",
|
|
977
|
+
site_id: "llm.client.host_cancelled"
|
|
978
|
+
});
|
|
979
|
+
throw new LlmClientTerminalError("cancelled", state.error, result.reason === "deadline" && !request.signal?.aborted);
|
|
980
|
+
}
|
|
981
|
+
if (result.kind === "error") {
|
|
982
|
+
state.error = `[${request.callId}] agent-llm ${result.category}: ${result.message}`;
|
|
983
|
+
recordProviderFailure({
|
|
984
|
+
callId: request.callId,
|
|
985
|
+
destination: "host",
|
|
986
|
+
provider: "agent-host-seam",
|
|
987
|
+
failure: `host_${result.category}`,
|
|
988
|
+
durationMs: performance.now() - hostStarted
|
|
989
|
+
});
|
|
990
|
+
log.warn("Host model request failed", {
|
|
991
|
+
call_id: request.callId,
|
|
992
|
+
destination,
|
|
993
|
+
failure_category: result.category,
|
|
994
|
+
error: state.error
|
|
995
|
+
}, {
|
|
996
|
+
event_name: "memory.llm_client.diagnostic",
|
|
997
|
+
file: "packages/memory/src/model/llm-client.ts",
|
|
998
|
+
function: "requestContent",
|
|
999
|
+
site_id: "llm.client.host_error"
|
|
1000
|
+
});
|
|
1001
|
+
if (config.refuseOnUnavailable && ([
|
|
1002
|
+
"auth",
|
|
1003
|
+
"credential-expired",
|
|
1004
|
+
"credential-revoked",
|
|
1005
|
+
"exhausted",
|
|
1006
|
+
"throttle"
|
|
1007
|
+
].includes(result.category) || result.message === "no-agent-endpoint" || result.message.includes("HTTP 503") || result.message.includes("worker-not-ready") || result.message.includes("stale-binding"))) throw new ModelCallRefusedError(request.callId, "host", result.message);
|
|
1008
|
+
if (isCredentialFailure(result.category)) throw new LlmClientTerminalError("auth", state.error);
|
|
1009
|
+
return null;
|
|
1010
|
+
}
|
|
1011
|
+
return {
|
|
1012
|
+
raw: result.text,
|
|
1013
|
+
transport
|
|
1014
|
+
};
|
|
1015
|
+
}
|
|
1016
|
+
const endpoint = await getEndpoint(request.callId, transport);
|
|
1017
|
+
checkMemoryOperation();
|
|
1018
|
+
const preset = endpoint.preset;
|
|
1019
|
+
const apiKey = resolveProviderApiKey(config, preset, endpoint.userBaseUrlOverride);
|
|
1020
|
+
const operationId = config.operationId ?? memoryOperationId();
|
|
1021
|
+
if (transport === "raw-completions") {
|
|
1022
|
+
if (preset.provider !== "sno-gpu") throw new Error("raw completion requires the sno-gpu provider");
|
|
1023
|
+
if (MODEL_CALLS[request.callId].replyParser.snoGpu !== "single-token-verdict" && !request.maxTokens) log.error("Model client request diagnostic", {
|
|
1024
|
+
call_id: request.callId,
|
|
1025
|
+
destination,
|
|
1026
|
+
error: `sno-station-mem llm-client: raw completion [${request.callId}] set no maxTokens; sending ${RAW_COMPLETION_FALLBACK_MAX_TOKENS} so the call still runs. Fix the caller — without a cap the serving side truncates at 16 tokens.`
|
|
1027
|
+
}, {
|
|
1028
|
+
event_name: "memory.llm_client.diagnostic",
|
|
1029
|
+
file: "packages/memory/src/model/llm-client.ts",
|
|
1030
|
+
function: "requestContent",
|
|
1031
|
+
site_id: "shared.llm-client.requestContent.ff17976562"
|
|
1032
|
+
});
|
|
1033
|
+
const pipelineConfig = {
|
|
1034
|
+
...buildPipelineConfig(preset, config, endpoint, request, destination, operationId),
|
|
1035
|
+
rawCompletion: {
|
|
1036
|
+
endpointUrl: endpoint.url,
|
|
1037
|
+
prompt,
|
|
1038
|
+
timeoutMs: resolveRequestTimeoutMs(request),
|
|
1039
|
+
maxTokens: request.maxTokens ?? RAW_COMPLETION_FALLBACK_MAX_TOKENS,
|
|
1040
|
+
...request.requestId ? { requestId: request.requestId } : {},
|
|
1041
|
+
...operationId ? { operationId } : {},
|
|
1042
|
+
...MODEL_CALLS[request.callId].replyParser.snoGpu === "single-token-verdict" ? { singleTokenVerdict: true } : {},
|
|
1043
|
+
...request.signal ? { signal: request.signal } : {}
|
|
1044
|
+
}
|
|
1045
|
+
};
|
|
1046
|
+
pipeline.setKeyPool(preset.provider, new KeyPool(apiKey.split(",")));
|
|
1047
|
+
config.onTransportAttempt?.({
|
|
1048
|
+
callId: request.callId,
|
|
1049
|
+
destination,
|
|
1050
|
+
transport
|
|
1051
|
+
});
|
|
1052
|
+
const response = await pipeline.call({
|
|
1053
|
+
config: pipelineConfig,
|
|
1054
|
+
messages: [prompt]
|
|
1055
|
+
});
|
|
1056
|
+
if (!response.success) {
|
|
1057
|
+
state.error = `sno-station-mem: llm-client [${request.callId}] pipeline error: ${response.error}`;
|
|
1058
|
+
log.warn("Raw model request failed", {
|
|
1059
|
+
call_id: request.callId,
|
|
1060
|
+
destination,
|
|
1061
|
+
error: state.error
|
|
1062
|
+
}, {
|
|
1063
|
+
event_name: "memory.llm_client.diagnostic",
|
|
1064
|
+
file: "packages/memory/src/model/llm-client.ts",
|
|
1065
|
+
function: "requestContent",
|
|
1066
|
+
site_id: "llm.client.raw_pipeline_failed"
|
|
1067
|
+
});
|
|
1068
|
+
const category = getProviderTerminalCategory(response.error);
|
|
1069
|
+
if (config.refuseOnUnavailable && (category === "auth" || classifyLlmFailure({ message: response.error }).category === "auth" || /(?:ECONNREFUSED|\b5\d\d\b)/i.test(response.error ?? ""))) throw new ModelCallRefusedError(request.callId, "sno-gpu", response.error ?? "model unavailable");
|
|
1070
|
+
if (category) throw new LlmClientTerminalError(category, state.error);
|
|
1071
|
+
return null;
|
|
1072
|
+
}
|
|
1073
|
+
state.usage = response.usage;
|
|
1074
|
+
return {
|
|
1075
|
+
raw: response.content,
|
|
1076
|
+
transport
|
|
1077
|
+
};
|
|
1078
|
+
}
|
|
1079
|
+
const pipelineConfig = buildPipelineConfig(preset, config, endpoint, request, destination, operationId);
|
|
1080
|
+
pipeline.setKeyPool(preset.provider, new KeyPool(apiKey.split(",")));
|
|
1081
|
+
config.onTransportAttempt?.({
|
|
1082
|
+
callId: request.callId,
|
|
1083
|
+
destination,
|
|
1084
|
+
transport
|
|
1085
|
+
});
|
|
1086
|
+
const response = await pipeline.call({
|
|
1087
|
+
config: pipelineConfig,
|
|
1088
|
+
messages: [{
|
|
1089
|
+
role: "system",
|
|
1090
|
+
content: systemContent
|
|
1091
|
+
}, {
|
|
1092
|
+
role: "user",
|
|
1093
|
+
content: prompt
|
|
1094
|
+
}]
|
|
1095
|
+
});
|
|
1096
|
+
if (!response.success) {
|
|
1097
|
+
state.error = `sno-station-mem: llm-client [${request.callId}] pipeline error: ${response.error}`;
|
|
1098
|
+
log.warn("Chat model request failed", {
|
|
1099
|
+
call_id: request.callId,
|
|
1100
|
+
destination,
|
|
1101
|
+
error: state.error
|
|
1102
|
+
}, {
|
|
1103
|
+
event_name: "memory.llm_client.diagnostic",
|
|
1104
|
+
file: "packages/memory/src/model/llm-client.ts",
|
|
1105
|
+
function: "requestContent",
|
|
1106
|
+
site_id: "llm.client.chat_pipeline_failed"
|
|
1107
|
+
});
|
|
1108
|
+
const category = getProviderTerminalCategory(response.error);
|
|
1109
|
+
if (config.refuseOnUnavailable && (category === "auth" || classifyLlmFailure({ message: response.error }).category === "auth" || /(?:ECONNREFUSED|\b5\d\d\b)/i.test(response.error ?? ""))) throw new ModelCallRefusedError(request.callId, "sno-gpu", response.error ?? "model unavailable");
|
|
1110
|
+
if (category) throw new LlmClientTerminalError(category, state.error);
|
|
1111
|
+
return null;
|
|
1112
|
+
}
|
|
1113
|
+
state.usage = response.usage;
|
|
1114
|
+
const raw = response.content;
|
|
1115
|
+
if (!raw) {
|
|
1116
|
+
state.error = `sno-station-mem: llm-client [${request.callId}] empty response from preset ${config.preset}`;
|
|
1117
|
+
log.warn("Model reply empty", {
|
|
1118
|
+
call_id: request.callId,
|
|
1119
|
+
destination,
|
|
1120
|
+
error: state.error
|
|
1121
|
+
}, {
|
|
1122
|
+
event_name: "memory.llm_client.diagnostic",
|
|
1123
|
+
file: "packages/memory/src/model/llm-client.ts",
|
|
1124
|
+
function: "requestContent",
|
|
1125
|
+
site_id: "llm.client.empty_reply"
|
|
1126
|
+
});
|
|
1127
|
+
return {
|
|
1128
|
+
raw: "",
|
|
1129
|
+
transport
|
|
1130
|
+
};
|
|
1131
|
+
}
|
|
1132
|
+
return {
|
|
1133
|
+
raw,
|
|
1134
|
+
transport
|
|
1135
|
+
};
|
|
1136
|
+
};
|
|
1137
|
+
const addUsage = (total, more) => total && more ? {
|
|
1138
|
+
inputTokens: total.inputTokens + more.inputTokens,
|
|
1139
|
+
outputTokens: total.outputTokens + more.outputTokens,
|
|
1140
|
+
totalTokens: total.totalTokens + more.totalTokens
|
|
1141
|
+
} : total ?? more;
|
|
1142
|
+
/**
|
|
1143
|
+
* Wraps `requestContent` with the bounded re-ask described on `EMPTY_REPLY_ATTEMPTS`. A `null`
|
|
1144
|
+
* result is returned untouched — it means no call was made, not that the model said nothing.
|
|
1145
|
+
*/
|
|
1146
|
+
const requestContentRetryingEmpty = async (state, request, systemContent, deadlineMs, prompt = request.prompt) => {
|
|
1147
|
+
let content = await requestContent(state, request, systemContent, prompt);
|
|
1148
|
+
let usage = state.usage;
|
|
1149
|
+
try {
|
|
1150
|
+
checkMemoryOperation();
|
|
1151
|
+
const attemptLimit = request.emptyReplyAttempts ?? EMPTY_REPLY_ATTEMPTS;
|
|
1152
|
+
for (let attempt = 2; attempt <= attemptLimit; attempt += 1) {
|
|
1153
|
+
if (content === null || content.raw.trim().length > 0) break;
|
|
1154
|
+
const remainingMs = deadlineMs - performance.now();
|
|
1155
|
+
if (remainingMs <= 0) break;
|
|
1156
|
+
log.debug("Retrying empty model reply", {
|
|
1157
|
+
call_id: request.callId,
|
|
1158
|
+
destination: destinationFor(request),
|
|
1159
|
+
attempt,
|
|
1160
|
+
attempt_limit: attemptLimit
|
|
1161
|
+
}, {
|
|
1162
|
+
event_name: "memory.llm_client.diagnostic",
|
|
1163
|
+
file: "packages/memory/src/model/llm-client.ts",
|
|
1164
|
+
function: "requestContentRetryingEmpty",
|
|
1165
|
+
site_id: "shared.llm-client.requestContentRetryingEmpty.cd874fefff"
|
|
1166
|
+
});
|
|
1167
|
+
content = await requestContent(state, {
|
|
1168
|
+
...request,
|
|
1169
|
+
timeoutMs: remainingMs
|
|
1170
|
+
}, systemContent, prompt);
|
|
1171
|
+
usage = addUsage(usage, state.usage);
|
|
1172
|
+
checkMemoryOperation();
|
|
1173
|
+
}
|
|
1174
|
+
} finally {
|
|
1175
|
+
state.usage = usage;
|
|
1176
|
+
}
|
|
1177
|
+
return content;
|
|
1178
|
+
};
|
|
1179
|
+
const requestContentWithHostFallback = async (state, request, systemContent, deadlineMs) => {
|
|
1180
|
+
let content = null;
|
|
1181
|
+
let snoError;
|
|
1182
|
+
try {
|
|
1183
|
+
content = await requestContentRetryingEmpty(state, request, systemContent, deadlineMs);
|
|
1184
|
+
} catch (error) {
|
|
1185
|
+
snoError = error;
|
|
1186
|
+
}
|
|
1187
|
+
if (destinationFor(request) !== "sno-gpu" || content?.raw.trim()) {
|
|
1188
|
+
if (snoError !== void 0) throw snoError;
|
|
1189
|
+
return content;
|
|
1190
|
+
}
|
|
1191
|
+
if (request.signal?.aborted || snoError instanceof LlmClientTerminalError && snoError.category === "cancelled" && !snoError.requestTimedOut) {
|
|
1192
|
+
if (snoError !== void 0) throw snoError;
|
|
1193
|
+
return content;
|
|
1194
|
+
}
|
|
1195
|
+
const originalLastError = state.error;
|
|
1196
|
+
const originalLastUsage = state.usage;
|
|
1197
|
+
const source = snoError instanceof Error ? snoError.message : originalLastError ?? "";
|
|
1198
|
+
const status = /\bHTTP ([1-5]\d\d)\b/.exec(source)?.[1];
|
|
1199
|
+
let snoFailure = "transport";
|
|
1200
|
+
if (status) snoFailure = `HTTP ${status}`;
|
|
1201
|
+
else if (content) snoFailure = "empty_reply";
|
|
1202
|
+
else if (snoError instanceof LlmClientTerminalError) snoFailure = snoError.category;
|
|
1203
|
+
else if (!config.apiKey?.trim()) snoFailure = "missing_key";
|
|
1204
|
+
const operationId = config.operationId ?? memoryOperationId();
|
|
1205
|
+
let hostFailure = "empty_reply";
|
|
1206
|
+
if (!config.agentPort) hostFailure = "port_unavailable";
|
|
1207
|
+
else if ([
|
|
1208
|
+
"E10",
|
|
1209
|
+
"P1",
|
|
1210
|
+
"REM1"
|
|
1211
|
+
].includes(request.callId) && !request.hostPrompt) hostFailure = "host_prompt_missing";
|
|
1212
|
+
else try {
|
|
1213
|
+
const host = await requestContent(state, request, systemContent, request.hostPrompt ?? request.prompt, "host");
|
|
1214
|
+
if (host?.raw.trim()) {
|
|
1215
|
+
log.info("Sno model call answered by host", {
|
|
1216
|
+
call_id: request.callId,
|
|
1217
|
+
operation_id: operationId,
|
|
1218
|
+
sno_failure: snoFailure,
|
|
1219
|
+
host_outcome: "answered",
|
|
1220
|
+
timeout_ms: resolveRequestTimeoutMs(request)
|
|
1221
|
+
}, {
|
|
1222
|
+
event_name: "memory.llm_client.fallback",
|
|
1223
|
+
file: "packages/memory/src/model/llm-client.ts",
|
|
1224
|
+
function: "requestContentWithHostFallback",
|
|
1225
|
+
site_id: "llm.client.fallback.answered"
|
|
1226
|
+
});
|
|
1227
|
+
state.usage = addUsage(originalLastUsage, state.usage);
|
|
1228
|
+
return host;
|
|
1229
|
+
}
|
|
1230
|
+
if (host === null) hostFailure = "host_error";
|
|
1231
|
+
} catch (error) {
|
|
1232
|
+
if (request.signal?.aborted) throw error;
|
|
1233
|
+
hostFailure = error instanceof LlmClientTerminalError ? error.category : "transport";
|
|
1234
|
+
}
|
|
1235
|
+
state.error = originalLastError;
|
|
1236
|
+
state.usage = originalLastUsage;
|
|
1237
|
+
log.warn("Sno model call and host fallback failed", {
|
|
1238
|
+
call_id: request.callId,
|
|
1239
|
+
operation_id: operationId,
|
|
1240
|
+
sno_failure: snoFailure,
|
|
1241
|
+
host_failure: hostFailure
|
|
1242
|
+
}, {
|
|
1243
|
+
event_name: "memory.llm_client.fallback",
|
|
1244
|
+
file: "packages/memory/src/model/llm-client.ts",
|
|
1245
|
+
function: "requestContentWithHostFallback",
|
|
1246
|
+
site_id: "llm.client.fallback.failed"
|
|
1247
|
+
});
|
|
1248
|
+
if (snoError !== void 0) throw snoError;
|
|
1249
|
+
return content;
|
|
1250
|
+
};
|
|
1251
|
+
return {
|
|
1252
|
+
/** Implements complete json as the local LLM transport operation. */
|
|
1253
|
+
async completeJson(input) {
|
|
1254
|
+
const state = {
|
|
1255
|
+
error: null,
|
|
1256
|
+
usage: null
|
|
1257
|
+
};
|
|
1258
|
+
const request = normalizeMemoryLlmRequest({
|
|
1259
|
+
...input,
|
|
1260
|
+
signal: memoryOperationSignal(input.signal)
|
|
1261
|
+
});
|
|
1262
|
+
checkMemoryOperation();
|
|
1263
|
+
const deadlineMs = performance.now() + resolveRequestTimeoutMs(request);
|
|
1264
|
+
try {
|
|
1265
|
+
let content = await requestContentWithHostFallback(state, request, JSON_SYSTEM_CONTENT, deadlineMs);
|
|
1266
|
+
if (content === null) return null;
|
|
1267
|
+
let parsed = parseJsonResponse(content.raw, input.accept);
|
|
1268
|
+
if (parsed.ok) return parsed.value;
|
|
1269
|
+
if (content.transport === "agent-host-seam" && destinationFor(request) !== "sno-gpu") {
|
|
1270
|
+
const remainingTimeoutMs = Math.floor(deadlineMs - performance.now());
|
|
1271
|
+
if (remainingTimeoutMs <= 0) {
|
|
1272
|
+
state.error = `sno-station-mem: llm-client [${request.callId}] deadline exhausted before JSON repair`;
|
|
1273
|
+
log.warn("Model repair deadline exhausted", {
|
|
1274
|
+
call_id: request.callId,
|
|
1275
|
+
destination: destinationFor(request),
|
|
1276
|
+
error: state.error
|
|
1277
|
+
}, {
|
|
1278
|
+
event_name: "memory.llm_client.diagnostic",
|
|
1279
|
+
file: "packages/memory/src/model/llm-client.ts",
|
|
1280
|
+
function: "completeJson",
|
|
1281
|
+
site_id: "llm.client.json.deadline_exhausted"
|
|
1282
|
+
});
|
|
1283
|
+
throw new LlmClientTerminalError("cancelled", state.error, true);
|
|
1284
|
+
}
|
|
1285
|
+
content = await requestContentRetryingEmpty(state, {
|
|
1286
|
+
...request,
|
|
1287
|
+
timeoutMs: remainingTimeoutMs
|
|
1288
|
+
}, JSON_SYSTEM_CONTENT, deadlineMs, `${request.prompt}\n\n${JSON_REPAIR_INSTRUCTION}`);
|
|
1289
|
+
if (content === null) return null;
|
|
1290
|
+
parsed = parseJsonResponse(content.raw, input.accept);
|
|
1291
|
+
if (parsed.ok) return parsed.value;
|
|
1292
|
+
}
|
|
1293
|
+
state.error = `sno-station-mem: llm-client [${request.callId}] ${parsed.error}`;
|
|
1294
|
+
log.warn("Model client request diagnostic", {
|
|
1295
|
+
operation: "completeJson",
|
|
1296
|
+
call_id: request.callId,
|
|
1297
|
+
destination: destinationFor(request),
|
|
1298
|
+
error: state.error
|
|
1299
|
+
}, {
|
|
1300
|
+
event_name: "memory.llm_client.diagnostic",
|
|
1301
|
+
file: "packages/memory/src/model/llm-client.ts",
|
|
1302
|
+
function: "completeJson",
|
|
1303
|
+
site_id: "shared.llm-client.completeJson.e04c8e7e82"
|
|
1304
|
+
});
|
|
1305
|
+
return null;
|
|
1306
|
+
} catch (err) {
|
|
1307
|
+
checkMemoryOperation();
|
|
1308
|
+
if (err instanceof LlmClientTerminalError || err instanceof ModelCallRefusedError) throw err;
|
|
1309
|
+
state.error = `sno-station-mem: llm-client [${request.callId}] request failed for preset ${config.preset}: ${err instanceof Error ? err.message : String(err)}`;
|
|
1310
|
+
log.warn("Model request failed", {
|
|
1311
|
+
call_id: request.callId,
|
|
1312
|
+
destination: destinationFor(request),
|
|
1313
|
+
error: state.error
|
|
1314
|
+
}, {
|
|
1315
|
+
event_name: "memory.llm_client.diagnostic",
|
|
1316
|
+
file: "packages/memory/src/model/llm-client.ts",
|
|
1317
|
+
function: "completeJson",
|
|
1318
|
+
site_id: "llm.client.json.request_failed"
|
|
1319
|
+
});
|
|
1320
|
+
return null;
|
|
1321
|
+
} finally {
|
|
1322
|
+
lastError = state.error;
|
|
1323
|
+
lastUsage = state.usage;
|
|
1324
|
+
}
|
|
1325
|
+
},
|
|
1326
|
+
async completeText(input) {
|
|
1327
|
+
const state = {
|
|
1328
|
+
error: null,
|
|
1329
|
+
usage: null
|
|
1330
|
+
};
|
|
1331
|
+
const request = normalizeMemoryLlmRequest({
|
|
1332
|
+
...input,
|
|
1333
|
+
signal: memoryOperationSignal(input.signal)
|
|
1334
|
+
});
|
|
1335
|
+
checkMemoryOperation();
|
|
1336
|
+
const deadlineMs = performance.now() + resolveRequestTimeoutMs(request);
|
|
1337
|
+
try {
|
|
1338
|
+
const text = (await requestContentWithHostFallback(state, request, textSystemContent(request), deadlineMs))?.raw.trim();
|
|
1339
|
+
return text && text.length > 0 ? text : null;
|
|
1340
|
+
} catch (err) {
|
|
1341
|
+
checkMemoryOperation();
|
|
1342
|
+
if (err instanceof LlmClientTerminalError || err instanceof ModelCallRefusedError) throw err;
|
|
1343
|
+
state.error = `sno-station-mem: llm-client [${request.callId}] request failed for preset ${config.preset}: ${err instanceof Error ? err.message : String(err)}`;
|
|
1344
|
+
log.warn("Model client request diagnostic", {
|
|
1345
|
+
call_id: request.callId,
|
|
1346
|
+
destination: destinationFor(request),
|
|
1347
|
+
error: state.error
|
|
1348
|
+
}, {
|
|
1349
|
+
event_name: "memory.llm_client.diagnostic",
|
|
1350
|
+
file: "packages/memory/src/model/llm-client.ts",
|
|
1351
|
+
function: "completeText",
|
|
1352
|
+
site_id: "shared.llm-client.completeText.ffa933b519"
|
|
1353
|
+
});
|
|
1354
|
+
return null;
|
|
1355
|
+
} finally {
|
|
1356
|
+
lastError = state.error;
|
|
1357
|
+
lastUsage = state.usage;
|
|
1358
|
+
}
|
|
1359
|
+
},
|
|
1360
|
+
getResolvedConfig() {
|
|
1361
|
+
return getPreset();
|
|
1362
|
+
},
|
|
1363
|
+
/** Returns last error from LLM transport state without side effects. */
|
|
1364
|
+
getLastError() {
|
|
1365
|
+
return lastError;
|
|
1366
|
+
},
|
|
1367
|
+
/** Returns provider usage from the last successful provider response. */
|
|
1368
|
+
getLastUsage() {
|
|
1369
|
+
return lastUsage;
|
|
1370
|
+
}
|
|
1371
|
+
};
|
|
1372
|
+
}
|
|
1373
|
+
//#endregion
|
|
1374
|
+
export { isTerminalLlmFailure as a, createLlmClient as i, LlmClientTerminalError as n, ModelCallRefusedError as r, JSON_SYSTEM_CONTENT as t };
|