@remnic/core 9.3.733 → 9.3.734
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/dist/access-boundary.d.ts +10 -10
- package/dist/access-boundary.js +9 -9
- package/dist/access-cli.js +25 -23
- package/dist/access-cli.js.map +1 -1
- package/dist/access-http.d.ts +10 -10
- package/dist/access-http.js +14 -14
- package/dist/access-mcp.d.ts +10 -10
- package/dist/access-mcp.js +13 -13
- package/dist/access-operations-batch.js +11 -11
- package/dist/access-operations.d.ts +10 -10
- package/dist/access-operations.js +12 -12
- package/dist/{access-service-Byoe3HsT.d.ts → access-service-rjFfmfKB.d.ts} +4 -4
- package/dist/access-service.d.ts +10 -10
- package/dist/access-service.js +8 -8
- package/dist/access-surface-catalog.d.ts +10 -10
- package/dist/action-confidence.d.ts +1 -1
- package/dist/active-memory-bridge.d.ts +1 -1
- package/dist/active-memory-bridge.js +3 -2
- package/dist/active-recall.d.ts +1 -1
- package/dist/behavior-learner.d.ts +1 -1
- package/dist/behavior-signals.d.ts +1 -1
- package/dist/bootstrap.d.ts +9 -9
- package/dist/briefing.d.ts +1 -1
- package/dist/buffer-surprise-report.d.ts +1 -1
- package/dist/buffer.d.ts +1 -1
- package/dist/calibration.d.ts +1 -1
- package/dist/capabilities.d.ts +97 -2
- package/dist/capabilities.js +11 -3
- package/dist/{catalog-DM1nk7cM.d.ts → catalog-DHYXzM4-.d.ts} +2 -2
- package/dist/causal-behavior.d.ts +1 -1
- package/dist/causal-consolidation.d.ts +1 -1
- package/dist/causal-trajectory-graph.d.ts +1 -1
- package/dist/{chunk-24D66MMN.js → chunk-2L5RTVMO.js} +7 -4
- package/dist/chunk-2L5RTVMO.js.map +1 -0
- package/dist/{chunk-KQYGNGON.js → chunk-3QETM5NG.js} +6 -3
- package/dist/chunk-3QETM5NG.js.map +1 -0
- package/dist/{chunk-ZQUAVZNG.js → chunk-54RCE5Z3.js} +7 -4
- package/dist/chunk-54RCE5Z3.js.map +1 -0
- package/dist/{chunk-NOU77OHX.js → chunk-5DIKZKOD.js} +2 -2
- package/dist/{chunk-CGPHMNL4.js → chunk-5OYHJIJN.js} +10 -6
- package/dist/chunk-5OYHJIJN.js.map +1 -0
- package/dist/{chunk-LUCARK4W.js → chunk-6U7TES2M.js} +29 -28
- package/dist/chunk-6U7TES2M.js.map +1 -0
- package/dist/{chunk-FFUCCKPN.js → chunk-7FPJFCXL.js} +10 -7
- package/dist/chunk-7FPJFCXL.js.map +1 -0
- package/dist/{chunk-PMAQRUN4.js → chunk-CILX2XW7.js} +5 -2
- package/dist/chunk-CILX2XW7.js.map +1 -0
- package/dist/{chunk-ZVHRSR2R.js → chunk-ET5HXSQL.js} +6 -3
- package/dist/chunk-ET5HXSQL.js.map +1 -0
- package/dist/{chunk-KSJCXXOU.js → chunk-FAGERSH2.js} +6 -3
- package/dist/chunk-FAGERSH2.js.map +1 -0
- package/dist/{chunk-FYWUNVFZ.js → chunk-IDIXGGDN.js} +6 -6
- package/dist/{chunk-CX77GNMB.js → chunk-IWMGBNXY.js} +6 -3
- package/dist/chunk-IWMGBNXY.js.map +1 -0
- package/dist/{chunk-GGL34GCW.js → chunk-IZLTOS5L.js} +7 -4
- package/dist/chunk-IZLTOS5L.js.map +1 -0
- package/dist/{chunk-HHNSLPX7.js → chunk-K7PAILHO.js} +10 -9
- package/dist/chunk-K7PAILHO.js.map +1 -0
- package/dist/{chunk-UZYLX7M6.js → chunk-LV32K4OP.js} +9 -6
- package/dist/chunk-LV32K4OP.js.map +1 -0
- package/dist/{chunk-HJWQJUKQ.js → chunk-NDYQIN6C.js} +3 -3
- package/dist/{chunk-DKT3X5C3.js → chunk-PEF2XOIV.js} +7 -4
- package/dist/chunk-PEF2XOIV.js.map +1 -0
- package/dist/{chunk-646B5ERJ.js → chunk-PKO5NJ65.js} +51 -48
- package/dist/chunk-PKO5NJ65.js.map +1 -0
- package/dist/{chunk-QZHF4BWN.js → chunk-Q5LGXWNG.js} +6 -6
- package/dist/{chunk-ESF7TRYJ.js → chunk-SHJGBAIW.js} +37 -2
- package/dist/{chunk-ESF7TRYJ.js.map → chunk-SHJGBAIW.js.map} +1 -1
- package/dist/{chunk-O4ZIBPIW.js → chunk-T7CGPTFU.js} +3 -3
- package/dist/{chunk-PLBIPT6I.js → chunk-TJSQHO4Q.js} +7 -4
- package/dist/chunk-TJSQHO4Q.js.map +1 -0
- package/dist/{chunk-6TUWSUUD.js → chunk-UF3N7IRP.js} +26 -24
- package/dist/chunk-UF3N7IRP.js.map +1 -0
- package/dist/{chunk-P3VJCTVE.js → chunk-UH3NYOHN.js} +4 -3
- package/dist/chunk-UH3NYOHN.js.map +1 -0
- package/dist/{chunk-J6BH2OBA.js → chunk-UK6U5C3N.js} +8 -5
- package/dist/chunk-UK6U5C3N.js.map +1 -0
- package/dist/{chunk-OTQE66IX.js → chunk-V5OVSGB6.js} +6 -3
- package/dist/chunk-V5OVSGB6.js.map +1 -0
- package/dist/{chunk-H3MB3F62.js → chunk-WHQ2JB35.js} +4 -3
- package/dist/chunk-WHQ2JB35.js.map +1 -0
- package/dist/{chunk-NIZQH6AU.js → chunk-WTTVFSCO.js} +8 -7
- package/dist/chunk-WTTVFSCO.js.map +1 -0
- package/dist/{chunk-OUITHS6V.js → chunk-Z7J3OAPR.js} +357 -325
- package/dist/chunk-Z7J3OAPR.js.map +1 -0
- package/dist/{cli-Dt-tuiYH.d.ts → cli-XVpmSoQs.d.ts} +3 -3
- package/dist/cli.d.ts +11 -11
- package/dist/cli.js +20 -20
- package/dist/compounding/engine.d.ts +3 -2
- package/dist/compounding/engine.js +2 -1
- package/dist/compounding/preference-consolidator.d.ts +1 -1
- package/dist/compression-optimizer.d.ts +1 -1
- package/dist/config.d.ts +1 -1
- package/dist/connectors/codex-materialize-runner.d.ts +1 -1
- package/dist/connectors/codex-materialize.d.ts +1 -1
- package/dist/connectors/index.d.ts +1 -1
- package/dist/consolidation-provenance-check.d.ts +1 -1
- package/dist/consolidation-undo.d.ts +1 -1
- package/dist/contradiction/index.d.ts +2 -2
- package/dist/contradiction/index.js +2 -1
- package/dist/{contradiction-scan-HWGEOUDS.js → contradiction-scan-OUHMCUBT.js} +3 -2
- package/dist/conversation-index/backend.d.ts +1 -1
- package/dist/conversation-index/chunker.d.ts +1 -1
- package/dist/conversation-index/faiss-adapter.d.ts +1 -1
- package/dist/conversation-index/indexer.d.ts +1 -1
- package/dist/conversation-index/search.d.ts +1 -1
- package/dist/day-summary.d.ts +1 -1
- package/dist/delinearize.d.ts +1 -1
- package/dist/direct-answer-wiring.d.ts +1 -1
- package/dist/direct-answer.d.ts +1 -1
- package/dist/embedding-fallback.d.ts +1 -1
- package/dist/embedding-fallback.js +2 -2
- package/dist/enrichment/index.d.ts +1 -1
- package/dist/entity-retrieval.d.ts +1 -1
- package/dist/entity-retrieval.js +2 -1
- package/dist/entity-schema.d.ts +1 -1
- package/dist/explicit-capture.d.ts +9 -9
- package/dist/explicit-capture.js +2 -1
- package/dist/extraction-faithfulness.d.ts +1 -1
- package/dist/extraction-judge-telemetry.d.ts +1 -1
- package/dist/extraction-judge-training.d.ts +1 -1
- package/dist/extraction-judge.d.ts +1 -1
- package/dist/extraction.d.ts +1 -1
- package/dist/extraction.js +3 -3
- package/dist/fallback-llm.d.ts +1 -1
- package/dist/{first-start-migration-OOR57AYR.js → first-start-migration-W4U6XDKI.js} +7 -6
- package/dist/first-start-migration-W4U6XDKI.js.map +1 -0
- package/dist/graph-dashboard-diff.d.ts +1 -1
- package/dist/graph-dashboard-key.d.ts +1 -1
- package/dist/graph-dashboard-parser.d.ts +1 -1
- package/dist/graph-edge-reinforcement.d.ts +1 -1
- package/dist/graph-snapshot.d.ts +1 -1
- package/dist/graph.d.ts +1 -1
- package/dist/identity-continuity.d.ts +1 -1
- package/dist/importance.d.ts +1 -1
- package/dist/index.d.ts +12 -12
- package/dist/index.js +43 -43
- package/dist/intent.d.ts +1 -1
- package/dist/lcm/engine.d.ts +1 -1
- package/dist/lcm/index.d.ts +1 -1
- package/dist/lcm/tools.d.ts +1 -1
- package/dist/lifecycle.d.ts +1 -1
- package/dist/live-connectors-runner.d.ts +1 -1
- package/dist/local-llm.d.ts +1 -1
- package/dist/local-llm.js +2 -1
- package/dist/local-model-endpoint.d.ts +1 -1
- package/dist/maintenance/memory-governance.d.ts +1 -1
- package/dist/mcp-memory-inspector-app.d.ts +10 -10
- package/dist/memory-action-policy.d.ts +1 -1
- package/dist/memory-cache.d.ts +1 -1
- package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
- package/dist/memory-projection-store.d.ts +1 -1
- package/dist/memory-provenance.d.ts +1 -1
- package/dist/memory-worth-outcomes.d.ts +1 -1
- package/dist/models-json.d.ts +1 -1
- package/dist/namespaces/migrate.d.ts +2 -2
- package/dist/namespaces/migrate.js +6 -6
- package/dist/namespaces/principal.d.ts +1 -1
- package/dist/namespaces/principal.js +2 -1
- package/dist/namespaces/search.d.ts +1 -1
- package/dist/namespaces/search.js +4 -4
- package/dist/namespaces/storage.d.ts +2 -2
- package/dist/namespaces/storage.js +2 -1
- package/dist/native-knowledge.d.ts +1 -1
- package/dist/operator-toolkit.d.ts +1 -1
- package/dist/operator-toolkit.js +11 -11
- package/dist/orchestration/compression-guideline-coordinator.d.ts +1 -1
- package/dist/orchestration/maintenance.d.ts +2 -2
- package/dist/orchestration/maintenance.js +6 -5
- package/dist/{orchestrator-B4KjaOtY.d.ts → orchestrator-BXi-gadS.d.ts} +66 -5
- package/dist/orchestrator.d.ts +5 -5
- package/dist/orchestrator.js +20 -18
- package/dist/patterns-cli.d.ts +1 -1
- package/dist/policy-runtime.d.ts +1 -1
- package/dist/provenance.d.ts +1 -1
- package/dist/qmd-recall-cache.d.ts +1 -1
- package/dist/qmd.d.ts +1 -1
- package/dist/recall-disclosure-escalation.d.ts +1 -1
- package/dist/recall-explain-renderer.d.ts +1 -1
- package/dist/recall-planner-llm.d.ts +1 -1
- package/dist/recall-state.d.ts +1 -1
- package/dist/recall-tag-filter.d.ts +1 -1
- package/dist/recall-xray-cli.d.ts +1 -1
- package/dist/recall-xray-renderer.d.ts +1 -1
- package/dist/recall-xray.d.ts +1 -1
- package/dist/resolve-auth-token.d.ts +1 -1
- package/dist/retrieval-agents.d.ts +1 -1
- package/dist/retrieval-tiers.d.ts +1 -1
- package/dist/routing/engine.d.ts +1 -1
- package/dist/routing/store.d.ts +1 -1
- package/dist/schemas.d.ts +22 -22
- package/dist/search/embed-helper.d.ts +1 -1
- package/dist/search/embed-helper.js +2 -2
- package/dist/search/factory.d.ts +1 -1
- package/dist/search/factory.js +3 -3
- package/dist/search/index.d.ts +1 -1
- package/dist/search/index.js +3 -3
- package/dist/search/lancedb-backend.d.ts +1 -1
- package/dist/search/meilisearch-backend.d.ts +1 -1
- package/dist/search/noop-backend.d.ts +1 -1
- package/dist/search/orama-backend.d.ts +1 -1
- package/dist/search/port.d.ts +1 -1
- package/dist/search/remote-backend.d.ts +1 -1
- package/dist/{semantic-SLAa_prH.d.ts → semantic-DJR8_DMQ.d.ts} +1 -1
- package/dist/{semantic-consolidation-CstTvHPo.d.ts → semantic-consolidation-DeL5grLx.d.ts} +1 -1
- package/dist/semantic-consolidation.d.ts +2 -2
- package/dist/semantic-rule-verifier.d.ts +1 -1
- package/dist/session-observer-bands.d.ts +1 -1
- package/dist/session-observer-state.d.ts +1 -1
- package/dist/shared-context/manager.d.ts +1 -1
- package/dist/signal.d.ts +1 -1
- package/dist/storage.d.ts +1 -1
- package/dist/summarizer.d.ts +1 -1
- package/dist/summarizer.js +3 -2
- package/dist/summary-snapshot.d.ts +1 -1
- package/dist/temporal-supersession.d.ts +1 -1
- package/dist/temporal-validity.d.ts +1 -1
- package/dist/threading.d.ts +1 -1
- package/dist/tier-migration.d.ts +1 -1
- package/dist/tier-routing.d.ts +1 -1
- package/dist/{tier-stats-3LYQ3VV5.js → tier-stats-LSM35HZY.js} +5 -2
- package/dist/tier-stats-LSM35HZY.js.map +1 -0
- package/dist/topics.d.ts +1 -1
- package/dist/transcript.d.ts +1 -1
- package/dist/transfer/types.d.ts +12 -12
- package/dist/trust-score-stage.d.ts +1 -1
- package/dist/trust-score.d.ts +1 -1
- package/dist/{types-VkxElCHR.d.ts → types-CpFz51Pv.d.ts} +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/utility-runtime.d.ts +1 -1
- package/package.json +2 -2
- package/src/access-service.ts +42 -37
- package/src/active-memory-bridge.ts +2 -1
- package/src/admin/admin-surfaces.ts +2 -1
- package/src/capabilities.test.ts +178 -0
- package/src/capabilities.ts +197 -0
- package/src/cli.ts +13 -9
- package/src/compounding/engine.ts +4 -3
- package/src/contradiction/contradiction-scan.ts +4 -3
- package/src/embedding-fallback.ts +5 -2
- package/src/entity-retrieval.ts +3 -2
- package/src/explicit-capture.ts +2 -1
- package/src/extraction.ts +6 -3
- package/src/local-llm.ts +4 -3
- package/src/maintenance/first-start-migration.ts +6 -3
- package/src/maintenance/namespace-maintenance-fanout.ts +2 -1
- package/src/maintenance/namespace-planner.ts +4 -3
- package/src/maintenance/tier-stats.ts +2 -1
- package/src/namespaces/catalog.ts +2 -1
- package/src/namespaces/migrate.ts +2 -1
- package/src/namespaces/principal.ts +6 -5
- package/src/namespaces/scope-profiles.ts +2 -1
- package/src/namespaces/search.ts +2 -1
- package/src/namespaces/storage.ts +4 -3
- package/src/operator-toolkit.ts +19 -18
- package/src/orchestration/maintenance.ts +8 -4
- package/src/orchestration/semantic-consolidation-coordinator.ts +454 -0
- package/src/orchestration/tier-migration-coordinator.ts +5 -4
- package/src/orchestrator.ts +78 -417
- package/src/scopes/scope-plan.ts +3 -2
- package/src/search/embed-helper.ts +5 -2
- package/src/search/factory.ts +9 -6
- package/src/summarizer.ts +3 -2
- package/dist/chunk-24D66MMN.js.map +0 -1
- package/dist/chunk-646B5ERJ.js.map +0 -1
- package/dist/chunk-6TUWSUUD.js.map +0 -1
- package/dist/chunk-CGPHMNL4.js.map +0 -1
- package/dist/chunk-CX77GNMB.js.map +0 -1
- package/dist/chunk-DKT3X5C3.js.map +0 -1
- package/dist/chunk-FFUCCKPN.js.map +0 -1
- package/dist/chunk-GGL34GCW.js.map +0 -1
- package/dist/chunk-H3MB3F62.js.map +0 -1
- package/dist/chunk-HHNSLPX7.js.map +0 -1
- package/dist/chunk-J6BH2OBA.js.map +0 -1
- package/dist/chunk-KQYGNGON.js.map +0 -1
- package/dist/chunk-KSJCXXOU.js.map +0 -1
- package/dist/chunk-LUCARK4W.js.map +0 -1
- package/dist/chunk-NIZQH6AU.js.map +0 -1
- package/dist/chunk-OTQE66IX.js.map +0 -1
- package/dist/chunk-OUITHS6V.js.map +0 -1
- package/dist/chunk-P3VJCTVE.js.map +0 -1
- package/dist/chunk-PLBIPT6I.js.map +0 -1
- package/dist/chunk-PMAQRUN4.js.map +0 -1
- package/dist/chunk-UZYLX7M6.js.map +0 -1
- package/dist/chunk-ZQUAVZNG.js.map +0 -1
- package/dist/chunk-ZVHRSR2R.js.map +0 -1
- package/dist/first-start-migration-OOR57AYR.js.map +0 -1
- package/dist/tier-stats-3LYQ3VV5.js.map +0 -1
- /package/dist/{chunk-NOU77OHX.js.map → chunk-5DIKZKOD.js.map} +0 -0
- /package/dist/{chunk-FYWUNVFZ.js.map → chunk-IDIXGGDN.js.map} +0 -0
- /package/dist/{chunk-HJWQJUKQ.js.map → chunk-NDYQIN6C.js.map} +0 -0
- /package/dist/{chunk-QZHF4BWN.js.map → chunk-Q5LGXWNG.js.map} +0 -0
- /package/dist/{chunk-O4ZIBPIW.js.map → chunk-T7CGPTFU.js.map} +0 -0
- /package/dist/{contradiction-scan-HWGEOUDS.js.map → contradiction-scan-OUHMCUBT.js.map} +0 -0
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/orchestration/maintenance.ts"],"sourcesContent":["/**\n * Maintenance scheduler — extracted from the orchestrator (issue #1526 PR1).\n *\n * Owns the WHEN of memory maintenance:\n * - cron auto-registration (writes jobs.json entries the OpenClaw cron\n * daemon picks up)\n * - debounced + singleflight QMD index maintenance (re-index + embed\n * after writes)\n * - consolidation scheduling trigger (count + interval gated)\n *\n * Does NOT own the WHAT — the actual job runners (runSemanticConsolidation,\n * runPatternReinforcement, runDeepSleepGovernanceNow, runConsolidation)\n * remain on the orchestrator because they need the full LLM + extraction\n * dependency surface. The scheduler invokes consolidation through a\n * callback so the orchestrator stays the source of truth for that work.\n *\n * Behavior-preserving move from orchestrator.ts. No logic changes — the\n * orchestrator keeps thin delegating methods so existing tests that stub\n * `orchestrator.requestQmdMaintenance` etc. continue to work.\n */\n\nimport { existsSync } from \"node:fs\";\nimport path from \"node:path\";\n\nimport type { PluginConfig } from \"../types.js\";\nimport type { SearchBackend } from \"../search/port.js\";\nimport {\n NamespaceSearchRouter,\n type NamespaceUpdateResult,\n} from \"../namespaces/search.js\";\nimport type { NamespaceCatalog } from \"../namespaces/catalog.js\";\nimport {\n planNamespaceMaintenance,\n runNamespaceMaintenanceBatchPlan,\n type NamespaceMaintenancePlan,\n type NamespaceMaintenanceSkipReason,\n} from \"../maintenance/namespace-planner.js\";\nimport {\n ensureContradictionScanCron,\n ensureDaySummaryCron,\n ensureGraphEdgeDecayCron,\n ensureNightlyGovernanceCron,\n ensurePatternReinforcementCron,\n ensureProceduralMiningCron,\n graphEdgeDecayCadenceToCronExpr,\n} from \"../maintenance/memory-governance-cron.js\";\nimport { resolveHomeDir } from \"../runtime/env.js\";\nimport { log } from \"../logger.js\";\n\n/** Reason a QMD maintenance pass was skipped, used for status recording. */\nfunction qmdMaintenanceSkipReasonForError(\n error: unknown,\n): NamespaceMaintenanceSkipReason | null {\n const message = error instanceof Error ? error.message : String(error);\n return /^QMD (?:update|embed) skipped by .*min-interval gate$/.test(message)\n ? \"throttled\"\n : null;\n}\n\n/** Dependencies injected by the orchestrator. All stable references. */\nexport interface MaintenanceSchedulerDeps {\n config: PluginConfig;\n /** Live accessor — the orchestrator can reassign its qmd backend after\n * construction (e.g. swap to NoopSearchBackend when the collection is\n * missing), and the scheduler must always observe the current backend. */\n getQmd: () => SearchBackend;\n namespaceSearchRouter: NamespaceSearchRouter;\n namespaceCatalog: NamespaceCatalog;\n}\n\n/**\n * Schedules and debounces memory maintenance work. Owns the cadence +\n * singleflight state that previously lived as private orchestrator fields.\n *\n * The orchestrator constructs one instance in its constructor and delegates\n * the public scheduling entrypoints to it. Job execution stays on the\n * orchestrator (LLM-heavy) and is invoked through callbacks.\n */\nexport class MaintenanceScheduler {\n // ── Consolidation scheduling state ──\n private nonZeroExtractionsSinceConsolidation = 0;\n private lastConsolidationRunAtMs = 0;\n private consolidationInFlight = false;\n\n // ── QMD maintenance scheduling state ──\n private qmdMaintenanceTimer: NodeJS.Timeout | null = null;\n private qmdMaintenancePending = false;\n private qmdMaintenanceInFlight = false;\n private lastQmdEmbedAtMs = 0;\n private lastQmdEmbedAtMsByNamespace = new Map<string, number>();\n\n constructor(private readonly deps: MaintenanceSchedulerDeps) {}\n\n // ───────────────────────────────────────────────────────────────────────\n // Cron auto-registration\n // ───────────────────────────────────────────────────────────────────────\n\n /**\n * Register every cron job the daemon should run, gated by its config flag.\n * Each registration is independent and non-fatal — a failure in one does\n * not block the others (mirrors the orchestrator's prior sequential try/\n * catch behavior exactly).\n *\n * Returns when all eligible registrations have completed so callers that\n * `await deferredReady` can rely on jobs.json being current.\n */\n async autoRegisterCrons(_signal: AbortSignal): Promise<void> {\n if (this.deps.config.daySummaryEnabled) {\n try {\n await this.autoRegisterDaySummaryCron();\n } catch (err) {\n log.debug(`day-summary cron auto-register failed (non-fatal): ${err}`);\n }\n }\n if (this.deps.config.nightlyGovernanceCronAutoRegister) {\n try {\n await this.autoRegisterNightlyGovernanceCron();\n } catch (err) {\n log.debug(`nightly governance cron auto-register failed (non-fatal): ${err}`);\n }\n }\n if (this.deps.config.procedural?.proceduralMiningCronAutoRegister) {\n try {\n await this.autoRegisterProceduralMiningCron();\n } catch (err) {\n log.debug(`procedural mining cron auto-register failed (non-fatal): ${err}`);\n }\n }\n if (this.deps.config.contradictionScan?.enabled) {\n try {\n await this.autoRegisterContradictionScanCron();\n } catch (err) {\n log.debug(`contradiction scan cron auto-register failed (non-fatal): ${err}`);\n }\n }\n if (this.deps.config.patternReinforcementEnabled) {\n try {\n await this.autoRegisterPatternReinforcementCron();\n } catch (err) {\n log.debug(`pattern reinforcement cron auto-register failed (non-fatal): ${err}`);\n }\n }\n if (this.deps.config.graphEdgeDecayEnabled) {\n try {\n await this.autoRegisterGraphEdgeDecayCron();\n } catch (err) {\n log.debug(`graph edge decay cron auto-register failed (non-fatal): ${err}`);\n }\n }\n }\n\n async autoRegisterDaySummaryCron(): Promise<void> {\n const home = resolveHomeDir();\n const jobsPath = path.join(home, \".openclaw\", \"cron\", \"jobs.json\");\n\n try {\n if (!existsSync(jobsPath)) {\n log.debug(\"day-summary cron: jobs.json not found, skipping auto-register\");\n return;\n }\n\n // Resolve an OpenClaw cron-routing model only in gateway mode. In plugin\n // mode, summaryModel is a direct-client model id for Remnic's own LLM\n // calls and may be unroutable as an OpenClaw agentTurn model.\n const rawSummaryModel = this.deps.config.summaryModel;\n const taskPrimary = this.deps.config.taskModelChain?.primary;\n const isGateway = this.deps.config.modelSource === \"gateway\";\n const model = isGateway ? (rawSummaryModel || taskPrimary || undefined) : undefined;\n // Attach task-chain fallbacks only when the model matches the task-chain\n // primary. If summaryModel is a distinct override, its fallbacks would\n // be unrelated to the task chain. Also append gateway default models as\n // tail fallbacks (de-duped) so a task-chain outage doesn't stop the cron\n // before reaching the gateway default chain. Mirrors hourly cron pattern.\n const fallbacks: string[] = [];\n if (model && taskPrimary && model === taskPrimary) {\n const seen = new Set<string>(model ? [model] : []);\n const addUnique = (value: string | undefined) => {\n if (typeof value !== \"string\") return;\n const trimmed = value.trim();\n if (trimmed.length > 0 && !seen.has(trimmed)) {\n seen.add(trimmed);\n fallbacks.push(trimmed);\n }\n };\n for (const fb of this.deps.config.taskModelChain?.fallbacks ?? []) addUnique(fb);\n const gwDefaults = this.deps.config.gatewayConfig?.agents?.defaults?.model;\n addUnique(gwDefaults?.primary);\n if (Array.isArray(gwDefaults?.fallbacks)) {\n for (const fb of gwDefaults.fallbacks) addUnique(fb);\n }\n }\n\n const timezone =\n this.deps.config.daySummaryTimezone ||\n Intl.DateTimeFormat().resolvedOptions().timeZone;\n\n const result = await ensureDaySummaryCron(jobsPath, {\n timezone,\n ...(model ? { model } : {}),\n ...(fallbacks.length > 0 ? { fallbacks } : {}),\n });\n if (result.created) {\n log.info(\n `day-summary cron auto-registered (${result.jobId}, 23:47 ${timezone}${model ? `, model: ${model}` : \"\"})`,\n );\n } else if (result.updated) {\n log.info(\n `day-summary cron reconciled (${result.jobId}, timezone: ${timezone}${model ? `, model: ${model}` : \"\"})`,\n );\n } else {\n log.debug(\"day-summary cron already up to date\");\n }\n } catch (err) {\n log.debug(`day-summary cron auto-register error: ${err}`);\n }\n }\n\n async autoRegisterNightlyGovernanceCron(): Promise<void> {\n const home = resolveHomeDir();\n const jobsPath = path.join(home, \".openclaw\", \"cron\", \"jobs.json\");\n\n try {\n if (!existsSync(jobsPath)) {\n log.debug(\"nightly governance cron: jobs.json not found, skipping auto-register\");\n return;\n }\n\n const created = await ensureNightlyGovernanceCron(jobsPath, {\n timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,\n });\n if (created.created) {\n log.info(\n `nightly governance cron auto-registered (${created.jobId}, 02:23 ${Intl.DateTimeFormat().resolvedOptions().timeZone})`,\n );\n } else {\n log.debug(\"nightly governance cron already exists, skipping auto-register\");\n }\n } catch (err) {\n log.debug(`nightly governance cron auto-register error: ${err}`);\n }\n }\n\n async autoRegisterProceduralMiningCron(): Promise<void> {\n const home = resolveHomeDir();\n const jobsPath = path.join(home, \".openclaw\", \"cron\", \"jobs.json\");\n try {\n if (!existsSync(jobsPath)) {\n log.debug(\"procedural mining cron: jobs.json not found, skipping auto-register\");\n return;\n }\n const created = await ensureProceduralMiningCron(jobsPath, {\n timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,\n });\n if (created.created) {\n log.info(`procedural mining cron auto-registered (${created.jobId})`);\n } else {\n log.debug(\"procedural mining cron already exists, skipping auto-register\");\n }\n } catch (err) {\n log.debug(`procedural mining cron auto-register error: ${err}`);\n }\n }\n\n async autoRegisterContradictionScanCron(): Promise<void> {\n const home = resolveHomeDir();\n const jobsPath = path.join(home, \".openclaw\", \"cron\", \"jobs.json\");\n try {\n if (!existsSync(jobsPath)) {\n log.debug(\"contradiction scan cron: jobs.json not found, skipping auto-register\");\n return;\n }\n const created = await ensureContradictionScanCron(jobsPath, {\n timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,\n });\n if (created.created) {\n log.info(`contradiction scan cron auto-registered (${created.jobId})`);\n } else {\n log.debug(\"contradiction scan cron already exists, skipping auto-register\");\n }\n } catch (err) {\n log.debug(`contradiction scan cron auto-register error: ${err}`);\n }\n }\n\n async autoRegisterPatternReinforcementCron(): Promise<void> {\n const home = resolveHomeDir();\n const jobsPath = path.join(home, \".openclaw\", \"cron\", \"jobs.json\");\n try {\n if (!existsSync(jobsPath)) {\n log.debug(\"pattern reinforcement cron: jobs.json not found, skipping auto-register\");\n return;\n }\n const created = await ensurePatternReinforcementCron(jobsPath, {\n timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,\n });\n if (created.created) {\n log.info(`pattern reinforcement cron auto-registered (${created.jobId})`);\n } else {\n log.debug(\"pattern reinforcement cron already exists, skipping auto-register\");\n }\n } catch (err) {\n log.debug(`pattern reinforcement cron auto-register error: ${err}`);\n }\n }\n\n async autoRegisterGraphEdgeDecayCron(): Promise<void> {\n const home = resolveHomeDir();\n const jobsPath = path.join(home, \".openclaw\", \"cron\", \"jobs.json\");\n try {\n if (!existsSync(jobsPath)) {\n log.debug(\"graph edge decay cron: jobs.json not found, skipping auto-register\");\n return;\n }\n const scheduleExpr = graphEdgeDecayCadenceToCronExpr(\n this.deps.config.graphEdgeDecayCadenceMs,\n );\n const created = await ensureGraphEdgeDecayCron(jobsPath, {\n timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,\n scheduleExpr,\n });\n if (created.created) {\n log.info(`graph edge decay cron auto-registered (${created.jobId}, ${scheduleExpr})`);\n } else {\n log.debug(\"graph edge decay cron already exists, skipping auto-register\");\n }\n } catch (err) {\n log.debug(`graph edge decay cron auto-register error: ${err}`);\n }\n }\n\n // ───────────────────────────────────────────────────────────────────────\n // Consolidation scheduling\n // ───────────────────────────────────────────────────────────────────────\n\n /**\n * Maybe trigger a background consolidation pass after an extraction.\n * Counted + interval gated so a burst of extractions does not fan into a\n * burst of consolidation passes. The consolidation runner itself is\n * passed in as a callback because it lives on the orchestrator (LLM +\n * storage dependency surface) and is not owned by this module.\n */\n maybeScheduleConsolidation(\n nonZeroExtraction: boolean,\n runConsolidation: () => Promise<unknown>,\n ): void {\n if (nonZeroExtraction) this.nonZeroExtractionsSinceConsolidation += 1;\n if (\n this.deps.config.consolidationRequireNonZeroExtraction &&\n !nonZeroExtraction\n ) {\n return;\n }\n if (\n this.nonZeroExtractionsSinceConsolidation <\n this.deps.config.consolidateEveryN\n ) {\n return;\n }\n\n const now = Date.now();\n if (\n now - this.lastConsolidationRunAtMs <\n this.deps.config.consolidationMinIntervalMs\n ) {\n return;\n }\n if (this.consolidationInFlight) return;\n\n this.consolidationInFlight = true;\n this.lastConsolidationRunAtMs = now;\n this.nonZeroExtractionsSinceConsolidation = 0;\n runConsolidation()\n .catch((err) => log.error(\"background consolidation failed\", err))\n .finally(() => {\n this.consolidationInFlight = false;\n });\n }\n\n /** Whether a background consolidation pass is currently running. Exposed so\n * the orchestrator's waitForConsolidationIdle can poll idle state without\n * owning the cadence state (issue #1526 PR1). */\n isConsolidationInFlight(): boolean {\n return this.consolidationInFlight;\n }\n\n /** Whether a debounced QMD maintenance pass is armed and waiting for the\n * debounce timer. Exposed so drain/teardown diagnostics (e.g. the bench\n * adapter) can observe scheduler idle state after the #1526 PR1 extraction\n * moved this flag off the orchestrator. */\n isQmdMaintenancePending(): boolean {\n return this.qmdMaintenancePending;\n }\n\n /** Whether a QMD maintenance pass is currently running (singleflight guard).\n * Exposed for drain/teardown diagnostics (see isQmdMaintenancePending). */\n isQmdMaintenanceInFlight(): boolean {\n return this.qmdMaintenanceInFlight;\n }\n // ───────────────────────────────────────────────────────────────────────\n // QMD maintenance scheduling (debounced + singleflight)\n // ───────────────────────────────────────────────────────────────────────\n\n /** Internal: queue a debounced QMD maintenance pass. */\n private requestQmdMaintenance(): void {\n if (!this.deps.getQmd().isAvailable()) return;\n if (!this.deps.config.qmdMaintenanceEnabled) return;\n\n this.qmdMaintenancePending = true;\n if (this.qmdMaintenanceTimer) return;\n\n this.qmdMaintenanceTimer = setTimeout(() => {\n this.qmdMaintenanceTimer = null;\n this.runQmdMaintenance().catch((err) =>\n log.debug(`background qmd maintenance failed: ${err}`),\n );\n }, this.deps.config.qmdMaintenanceDebounceMs);\n }\n\n /**\n * Public entrypoint for tool-driven QMD maintenance requests.\n * Routes through existing debounced/singleflight maintenance controls.\n */\n requestQmdMaintenanceForTool(reason: string): void {\n try {\n this.requestQmdMaintenance();\n } catch (err) {\n const msg = err instanceof Error ? err.message : String(err);\n log.warn(`qmd maintenance request failed (${reason}): ${msg}`);\n }\n }\n\n /** Internal: run a single QMD maintenance pass under singleflight guard. */\n async runQmdMaintenance(): Promise<void> {\n if (this.qmdMaintenanceInFlight) return;\n if (!this.qmdMaintenancePending) return;\n this.qmdMaintenanceInFlight = true;\n this.qmdMaintenancePending = false;\n\n try {\n if (this.deps.config.namespacesEnabled) {\n // Include cataloged dynamic namespaces, not just the configured set\n // (NGnei), but run through the namespace-aware maintenance planner so\n // each namespace is budgeted, lock-protected, and status-recorded\n // independently (issue #1500).\n const plan = await this.namespaceMaintenancePlan(\"qmd\");\n const now = Date.now();\n const lastEmbedAtByNamespace = this.lastQmdEmbedAtMsByNamespace;\n const dueEmbedNamespaces = (namespaces: string[]): string[] => {\n if (!this.deps.config.qmdAutoEmbedEnabled) return [];\n return namespaces.filter(\n (namespace) =>\n now - (lastEmbedAtByNamespace.get(namespace) ?? 0) >=\n this.deps.config.qmdEmbedMinIntervalMs,\n );\n };\n const markEmbedded = (namespaces: string[]): void => {\n if (namespaces.length === 0) return;\n for (const namespace of namespaces) {\n lastEmbedAtByNamespace.set(namespace, now);\n }\n this.lastQmdEmbedAtMs = now;\n };\n await runNamespaceMaintenanceBatchPlan(\n this.deps.config,\n plan,\n async (candidates) => {\n const namespaces = candidates.map((candidate) => candidate.namespace);\n const embedNamespaces = dueEmbedNamespaces(namespaces);\n let result: NamespaceUpdateResult;\n try {\n result = await this.deps.namespaceSearchRouter.updateNamespacesDetailed(\n namespaces,\n undefined,\n { strict: true },\n );\n } catch (error) {\n if (\n embedNamespaces.length > 0 &&\n qmdMaintenanceSkipReasonForError(error) === \"throttled\"\n ) {\n await this.deps.namespaceSearchRouter.embedNamespaces(embedNamespaces, {\n strict: true,\n });\n markEmbedded(embedNamespaces);\n }\n throw error;\n }\n if (result.backendCount <= 0) {\n throw new Error(\"no eligible QMD backend for selected namespaces\");\n }\n if (result.eligibleNamespaces.length !== namespaces.length) {\n const eligible = new Set(result.eligibleNamespaces);\n const missing = namespaces.filter(\n (namespace) => !eligible.has(namespace),\n );\n throw new Error(\n `QMD backend ineligible for selected namespaces (${missing.length})`,\n );\n }\n if (embedNamespaces.length > 0) {\n await this.deps.namespaceSearchRouter.embedNamespaces(embedNamespaces, {\n strict: true,\n });\n markEmbedded(embedNamespaces);\n }\n return { itemCount: result.backendCount };\n },\n this.deps.namespaceCatalog,\n {\n skipReasonForError: qmdMaintenanceSkipReasonForError,\n },\n );\n } else {\n await this.deps.getQmd().update();\n const now = Date.now();\n if (\n this.deps.config.qmdAutoEmbedEnabled &&\n now - this.lastQmdEmbedAtMs >= this.deps.config.qmdEmbedMinIntervalMs\n ) {\n await this.deps.getQmd().embed();\n this.lastQmdEmbedAtMs = now;\n }\n }\n } finally {\n this.qmdMaintenanceInFlight = false;\n if (this.qmdMaintenancePending) {\n this.requestQmdMaintenance();\n }\n }\n }\n\n /** Build the namespace-aware maintenance plan for one job. */\n private async namespaceMaintenancePlan(\n jobName: string,\n ): Promise<NamespaceMaintenancePlan> {\n return planNamespaceMaintenance(this.deps.config, {\n jobName,\n catalog: this.deps.namespaceCatalog,\n });\n }\n\n // ───────────────────────────────────────────────────────────────────────\n // Lifecycle\n // ───────────────────────────────────────────────────────────────────────\n\n /**\n * Clear any pending debounce timer. Called from the orchestrator's\n * destroy() so a late tick does not fire on a torn-down instance.\n */\n dispose(): void {\n if (this.qmdMaintenanceTimer) {\n clearTimeout(this.qmdMaintenanceTimer);\n this.qmdMaintenanceTimer = null;\n }\n this.qmdMaintenancePending = false;\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/active-memory-bridge.ts"],"sourcesContent":["import { canReadNamespace, defaultNamespaceForPrincipal, resolvePrincipal } from \"./namespaces/principal.js\";\nimport type { MemoryFile, PluginConfig } from \"./types.js\";\nimport { collapseWhitespace, truncateCodePointSafe } from \"./whitespace.js\";\nimport { isHandleToken } from \"./recall-handles.js\";\n\nexport interface ActiveMemoryMetadata {\n type?: \"fact\" | \"preference\";\n topic?: string;\n updatedAt?: string;\n sourceUri?: string;\n}\n\nexport interface ActiveMemorySearchResult {\n id: string;\n score: number;\n text: string;\n metadata?: ActiveMemoryMetadata;\n}\n\nexport interface ActiveMemorySearchOutput {\n results: ActiveMemorySearchResult[];\n truncated: boolean;\n}\n\nexport interface ActiveMemoryGetOutput {\n id?: string;\n text?: string;\n metadata?: ActiveMemoryMetadata;\n error?: \"not_found\";\n}\n\nexport interface ActiveMemoryRecallParams {\n query: string;\n limit?: number;\n sessionKey: string;\n filters?: Record<string, unknown>;\n snippetMaxChars?: number;\n}\n\ninterface ActiveMemoryScopedOrchestrator {\n config?: PluginConfig;\n resolvePrincipal?: (sessionKey?: string) => string | undefined;\n resolveSelfNamespace?: (sessionKey?: string) => string;\n}\n\ntype ActiveMemorySearchCandidate = {\n id?: string;\n score?: number;\n snippet?: string;\n text?: string;\n path?: string;\n metadata?: Record<string, unknown>;\n};\n\nfunction isArtifactPath(value: string | undefined): boolean {\n return typeof value === \"string\" && /(?:^|[\\\\/])artifacts(?:[\\\\/]|$)/i.test(value);\n}\n\nfunction clampLimit(value: number | undefined): number {\n if (typeof value !== \"number\" || !Number.isFinite(value)) return 8;\n return Math.max(1, Math.min(50, Math.floor(value)));\n}\n\nfunction truncateSnippet(value: string, maxChars: number): string {\n const compact = collapseWhitespace(value);\n return truncateCodePointSafe(compact, maxChars);\n}\n\nfunction pickMetadata(value: Record<string, unknown> | undefined): ActiveMemoryMetadata | undefined {\n if (!value) return undefined;\n const metadata: ActiveMemoryMetadata = {};\n if (typeof value.type === \"string\") metadata.type = value.type as ActiveMemoryMetadata[\"type\"];\n if (typeof value.topic === \"string\") metadata.topic = value.topic;\n if (typeof value.updatedAt === \"string\") metadata.updatedAt = value.updatedAt;\n if (typeof value.sourceUri === \"string\") metadata.sourceUri = value.sourceUri;\n return Object.keys(metadata).length > 0 ? metadata : undefined;\n}\n\nfunction resolveActiveMemoryNamespace(\n orchestrator: ActiveMemoryScopedOrchestrator,\n sessionKey: string | undefined,\n requestedNamespace: string | undefined,\n): string {\n const explicitNamespace =\n typeof requestedNamespace === \"string\" && requestedNamespace.trim().length > 0\n ? requestedNamespace.trim()\n : undefined;\n const config = orchestrator.config;\n\n if (config?.namespacesEnabled === false) {\n if (typeof orchestrator.resolveSelfNamespace === \"function\") {\n return orchestrator.resolveSelfNamespace(sessionKey);\n }\n return \"default\";\n }\n\n if (!config) {\n if (explicitNamespace) return explicitNamespace;\n if (typeof orchestrator.resolveSelfNamespace === \"function\") {\n return orchestrator.resolveSelfNamespace(sessionKey);\n }\n return \"default\";\n }\n\n const principal =\n typeof orchestrator.resolvePrincipal === \"function\"\n ? orchestrator.resolvePrincipal(sessionKey)\n : resolvePrincipal(sessionKey, config);\n if (config.namespacesEnabled && !principal) {\n throw new Error(\"authentication required: namespaces are enabled and no principal was supplied\");\n }\n if (explicitNamespace) {\n if (!canReadNamespace(principal, explicitNamespace, config)) {\n throw new Error(`namespace ${explicitNamespace} is not readable for principal ${principal}`);\n }\n return explicitNamespace;\n }\n if (typeof orchestrator.resolveSelfNamespace === \"function\") {\n return orchestrator.resolveSelfNamespace(sessionKey);\n }\n return defaultNamespaceForPrincipal(principal, config);\n}\n\nexport async function recallForActiveMemory(\n orchestrator: {\n config?: PluginConfig;\n resolvePrincipal?: (sessionKey?: string) => string | undefined;\n resolveSelfNamespace?: (sessionKey?: string) => string;\n searchAcrossNamespaces: (params: {\n query: string;\n maxResults?: number;\n namespaces?: string[];\n mode?: string;\n }) => Promise<ActiveMemorySearchCandidate[]>;\n },\n params: ActiveMemoryRecallParams,\n): Promise<ActiveMemorySearchOutput> {\n const limit = clampLimit(params.limit);\n const requestedResults = Math.min(200, limit + 20);\n const snippetMaxChars =\n typeof params.snippetMaxChars === \"number\" && Number.isFinite(params.snippetMaxChars)\n ? Math.max(1, Math.min(4000, Math.floor(params.snippetMaxChars)))\n : 600;\n const namespace = resolveActiveMemoryNamespace(\n orchestrator,\n params.sessionKey,\n typeof params.filters?.namespace === \"string\" ? params.filters.namespace : undefined,\n );\n\n const raw = await orchestrator.searchAcrossNamespaces({\n query: params.query,\n maxResults: requestedResults,\n namespaces: [namespace],\n mode: \"search\",\n });\n const visible = raw.filter((candidate) => !isArtifactPath(candidate.path));\n\n return {\n results: visible.slice(0, limit).map((candidate, index) => ({\n id: candidate.id ?? candidate.path ?? `memory-${index + 1}`,\n score: typeof candidate.score === \"number\" ? candidate.score : 0,\n text: truncateSnippet(candidate.snippet ?? candidate.text ?? \"\", snippetMaxChars),\n metadata: pickMetadata(candidate.metadata),\n })),\n truncated: visible.length > limit,\n };\n}\n\nfunction buildActiveMemoryMetadataFromMemory(memory: MemoryFile): ActiveMemoryMetadata | undefined {\n const metadata: ActiveMemoryMetadata = {};\n if (typeof memory.frontmatter.category === \"string\") {\n const category = memory.frontmatter.category;\n if (category === \"fact\" || category === \"preference\") {\n metadata.type = category;\n }\n }\n if (Array.isArray(memory.frontmatter.tags) && memory.frontmatter.tags.length > 0) {\n metadata.topic = memory.frontmatter.tags[0];\n }\n if (typeof memory.frontmatter.updated === \"string\") metadata.updatedAt = memory.frontmatter.updated;\n if (typeof memory.frontmatter.source === \"string\") metadata.sourceUri = memory.frontmatter.source;\n return Object.keys(metadata).length > 0 ? metadata : undefined;\n}\n\nexport async function getMemoryForActiveMemory(\n orchestrator: {\n config?: PluginConfig;\n resolvePrincipal?: (sessionKey?: string) => string;\n resolveSelfNamespace?: (sessionKey?: string) => string;\n getStorageForNamespace?: (namespace: string) => Promise<{\n getMemoryById?: (id: string) => Promise<MemoryFile | null>;\n }>;\n storage?: {\n getMemoryById?: (id: string) => Promise<MemoryFile | null>;\n };\n /** Issue #1582 — resolves a `[m:xxxx]` handle to a memory id (orchestrator). */\n resolveMemoryIdOrHandle?: (ref: string, sessionKey?: string) => string;\n },\n id: string,\n options: {\n namespace?: string;\n sessionKey?: string;\n } = {},\n): Promise<ActiveMemoryGetOutput> {\n const namespace = resolveActiveMemoryNamespace(\n orchestrator,\n options.sessionKey,\n options.namespace,\n );\n\n const storage =\n typeof orchestrator.getStorageForNamespace === \"function\"\n ? await orchestrator.getStorageForNamespace(namespace)\n : orchestrator.storage;\n\n // Issue #1582 — resolve a `[m:xxxx]` handle to its memory id against the\n // caller's session before the storage read, so OpenClaw active-memory agents\n // can cite injected handles through the SAME shared path as memory_get /\n // correction (cursor review). Raw ids pass through unchanged.\n //\n // A handle that misses, collides, or has no session key becomes not_found —\n // the SAME behavior a bad raw id yields below — instead of throwing, so an\n // active-memory caller gets a uniform not-found contract (cursor review).\n let resolvedId = id;\n if (isHandleToken(id) && typeof orchestrator.resolveMemoryIdOrHandle === \"function\") {\n try {\n resolvedId = orchestrator.resolveMemoryIdOrHandle(id, options.sessionKey);\n } catch {\n return { error: \"not_found\" };\n }\n }\n const memory = await storage?.getMemoryById?.(resolvedId);\n if (!memory) return { error: \"not_found\" };\n return {\n id: resolvedId,\n text: collapseWhitespace(memory.content),\n metadata: buildActiveMemoryMetadataFromMemory(memory),\n };\n}\n"],"mappings":"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","names":[]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/summarizer.ts"],"sourcesContent":["import { mkdir, readFile, writeFile, readdir } from \"node:fs/promises\";\nimport path from \"node:path\";\nimport { z } from \"zod\";\nimport { log } from \"./logger.js\";\nimport { LocalLlmClient } from \"./local-llm.js\";\nimport { FallbackLlmClient, fallbackLlmRuntimeContextFromConfig, gatewayTaskChainOptions } from \"./fallback-llm.js\";\nimport { ModelRegistry } from \"./model-registry.js\";\nimport { extractJsonCandidates } from \"./json-extract.js\";\nimport type { HourlySummary, TranscriptEntry, PluginConfig, GatewayConfig } from \"./types.js\";\nimport type { TranscriptManager } from \"./transcript.js\";\nimport { readSummarySnapshot, upsertSummarySnapshot, writeSummarySnapshot } from \"./summary-snapshot.js\";\nimport {\n encodeStoragePathSegment,\n resolveSafeStoragePath,\n} from \"./storage-paths.js\";\nimport { sessionStoragePaths } from \"./session-identity.js\";\n\n// Schema for LLM summary output\nconst HourlySummarySchema = z.object({\n bullets: z\n .array(z.string().trim().min(1))\n .min(1)\n .describe(\"3-5 bullet points summarizing the hour's activity\"),\n});\n\ntype HourlySummaryResult = z.infer<typeof HourlySummarySchema>;\n\nconst HourlySummaryExtendedSchema = z.object({\n topics: z.array(z.string()).default([]),\n decisions: z.array(z.string()).default([]),\n actionItems: z.array(z.string()).default([]),\n rejected: z.array(z.string()).default([]),\n});\n\ntype HourlySummaryExtendedResult = z.infer<typeof HourlySummaryExtendedSchema>;\n\ntype HourlySummaryExtendedMeta = {\n userTurns: number;\n assistantTurns: number;\n toolCalls: number;\n toolCounts: Record<string, number>;\n};\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n}\n\nexport class HourlySummarizer {\n private summariesDir: string;\n private config: PluginConfig;\n private localLlm: LocalLlmClient;\n private fallbackLlm: FallbackLlmClient;\n private modelRegistry: ModelRegistry;\n private transcript?: TranscriptManager;\n\n constructor(config: PluginConfig, gatewayConfig?: GatewayConfig, modelRegistry?: ModelRegistry, transcript?: TranscriptManager) {\n this.config = config;\n this.summariesDir = path.join(config.memoryDir, \"summaries\", \"hourly\");\n this.modelRegistry = modelRegistry ?? new ModelRegistry(config.memoryDir);\n this.transcript = transcript;\n\n // Initialize local LLM client with shared model registry\n this.localLlm = new LocalLlmClient(config, this.modelRegistry);\n\n // Initialize fallback client with gateway config\n this.fallbackLlm = new FallbackLlmClient(\n gatewayConfig,\n fallbackLlmRuntimeContextFromConfig(config),\n );\n\n if (!gatewayConfig?.agents?.defaults?.model?.primary && !config.localLlmEnabled && config.modelSource !== \"gateway\") {\n log.warn(\"no gateway default AI and local LLM disabled — hourly summarization disabled\");\n }\n }\n\n private get useGatewayModelSource(): boolean {\n return this.config.modelSource === \"gateway\";\n }\n\n private get shouldUseLocalLlm(): boolean {\n return this.config.localLlmEnabled && !this.useGatewayModelSource;\n }\n\n private withGatewayAgent(options: import(\"./fallback-llm.js\").FallbackLlmOptions): import(\"./fallback-llm.js\").FallbackLlmOptions {\n if (!this.useGatewayModelSource) return options;\n // Shared resolution (taskModelChain > gatewayAgentId) — gotcha #22. Issue #1365.\n return { ...options, ...gatewayTaskChainOptions(this.config) };\n }\n\n async initialize(): Promise<void> {\n await mkdir(this.summariesDir, { recursive: true });\n log.info(\"hourly summarizer initialized\");\n }\n\n private async summarySessionDir(sessionKey: string): Promise<string> {\n return resolveSafeStoragePath(\n this.summariesDir,\n encodeStoragePathSegment(sessionKey, \"session\"),\n );\n }\n\n private async legacySummarySessionDir(sessionKey: string): Promise<string | null> {\n if (sessionKey.includes(\"\\0\")) return null;\n try {\n return await resolveSafeStoragePath(this.summariesDir, sessionKey);\n } catch {\n return null;\n }\n }\n\n private summaryDateString(hour: string): string {\n const dateStr = hour.slice(0, 10);\n if (!/^\\d{4}-\\d{2}-\\d{2}$/.test(dateStr)) {\n throw new Error(`invalid hourly summary timestamp: ${hour}`);\n }\n return dateStr;\n }\n\n // Generate summary for a specific hour and session\n async generateSummary(\n sessionKey: string,\n hourStart: Date,\n entries: TranscriptEntry[]\n ): Promise<HourlySummary | null> {\n if (entries.length === 0) return null;\n\n // Format entries for the LLM\n const conversation = entries\n .map((e) => `[${e.role}] ${e.content}`)\n .join(\"\\n\\n\");\n\n if (this.config.hourlySummariesExtendedEnabled) {\n const extended = await this.generateExtended(sessionKey, hourStart, conversation, entries);\n if (!extended) return null;\n const meta: HourlySummaryExtendedMeta = {\n userTurns: entries.filter((e) => e.role === \"user\").length,\n assistantTurns: entries.filter((e) => e.role === \"assistant\").length,\n toolCalls: extended._meta.toolCalls,\n toolCounts: extended._meta.toolCounts,\n };\n // Keep HourlySummary surface stable; encode \"topics\" as bullets for recall injection.\n const base: HourlySummary = {\n hour: hourStart.toISOString(),\n sessionKey,\n bullets: extended.topics.length > 0 ? extended.topics.slice(0, 5) : [\"(summary generated)\"],\n turnCount: entries.length,\n generatedAt: new Date().toISOString(),\n };\n const withExtras = base as any;\n withExtras._extended = extended;\n withExtras._extendedMeta = meta;\n return base;\n }\n\n const hourIso = hourStart.toISOString();\n const startTime = Date.now();\n\n // Try local LLM first if enabled\n if (this.shouldUseLocalLlm) {\n try {\n const localResult = await this.generateWithLocalLlm(conversation);\n if (localResult) {\n const durationMs = Date.now() - startTime;\n log.debug(\n `generated hourly summary for ${sessionKey} at ${hourIso} in ${durationMs}ms using local LLM`\n );\n return {\n hour: hourIso,\n sessionKey,\n bullets: localResult.bullets,\n turnCount: entries.length,\n generatedAt: new Date().toISOString(),\n };\n }\n // Local failed, fall back if allowed\n if (!this.config.localLlmFallback) {\n log.warn(\"summary generation: local LLM failed and fallback disabled\");\n return null;\n }\n log.info(\"summary generation: local LLM unavailable, falling back to gateway default AI\");\n } catch (err) {\n if (!this.config.localLlmFallback) {\n log.warn(\"summary generation: local LLM error and fallback disabled:\", err);\n return null;\n }\n log.info(\"summary generation: local LLM error, falling back to gateway default AI:\", err);\n }\n }\n\n // Fall back to gateway's default AI\n log.info(\"summary generation: falling back to gateway default AI\");\n\n try {\n const messages = [\n {\n role: \"system\" as const,\n content: `You are a conversation summarization system. Summarize the following conversation transcript into 3-5 concise bullet points.\n\nGuidelines:\n- Focus on what was accomplished, decided, or discussed\n- Include specific topics, projects, or entities mentioned\n- Note any significant user requests or agent actions\n- Keep bullets brief but informative (1-2 sentences each)\n- Skip trivial greetings or meta-conversation\n- Use present tense for ongoing work, past for completed items\n\nRespond with valid JSON matching this schema:\n{\n \"bullets\": [\"bullet 1\", \"bullet 2\", \"bullet 3\"]\n}`,\n },\n { role: \"user\" as const, content: `Summarize this conversation:\\n\\n${conversation}` },\n ];\n\n const result = await this.fallbackLlm.parseWithSchema(\n messages,\n HourlySummarySchema,\n this.withGatewayAgent({ temperature: 0.3, maxTokens: 8192 }),\n );\n\n const durationMs = Date.now() - startTime;\n\n if (result) {\n log.debug(\n `generated hourly summary for ${sessionKey} at ${hourIso} in ${durationMs}ms via fallback`,\n );\n return {\n hour: hourIso,\n sessionKey,\n bullets: result.bullets,\n turnCount: entries.length,\n generatedAt: new Date().toISOString(),\n };\n }\n\n log.warn(\"summary generation fallback returned no parsed output\");\n return null;\n } catch (err) {\n log.error(\"summary generation fallback failed\", err);\n return null;\n }\n }\n\n private async generateExtended(\n sessionKey: string,\n hourStart: Date,\n conversation: string,\n entries: TranscriptEntry[],\n ): Promise<(HourlySummaryExtendedResult & { _meta: HourlySummaryExtendedMeta }) | null> {\n const hourIso = hourStart.toISOString();\n const startTime = Date.now();\n\n const hourEnd = new Date(hourStart.getTime() + 60 * 60 * 1000);\n let toolCounts: Record<string, number> = {};\n if (this.config.hourlySummariesIncludeToolStats && this.transcript) {\n const uses = await this.transcript.readToolUse(sessionKey, hourStart, hourEnd);\n for (const u of uses) toolCounts[u.tool] = (toolCounts[u.tool] ?? 0) + 1;\n }\n\n const sys = `You are a conversation summarization system.\\n\\nSummarize the hour into structured sections.\\n\\nReturn valid JSON matching:\\n{\\n \\\"topics\\\": [\\\"...\\\"],\\n \\\"decisions\\\": [\\\"...\\\"],\\n \\\"actionItems\\\": [\\\"...\\\"],\\n \\\"rejected\\\": [\\\"...\\\"]\\n}\\n\\nGuidelines:\\n- Prefer concrete topics and decisions.\\n- Action items should be imperative.\\n- Rejected ideas are things that were explicitly discarded or reversed.\\n- If there are none for a section, return an empty array.\\n`;\n\n const toolStatsLine = Object.keys(toolCounts).length > 0\n ? `Tools used (counts): ${Object.entries(toolCounts).sort((a,b)=>b[1]-a[1]).slice(0,10).map(([k,v])=>`${k}=${v}`).join(\", \")}\\n\\n`\n : \"\";\n const userTurns = entries.filter((e) => e.role === \"user\").length;\n const assistantTurns = entries.filter((e) => e.role === \"assistant\").length;\n const toolCalls = Object.values(toolCounts).reduce((a,b)=>a+b,0);\n const statsLine = `Stats: userTurns=${userTurns}, assistantTurns=${assistantTurns}, toolCalls=${toolCalls}\\n\\n`;\n\n const user = `Hour: ${hourIso}\\nSession: ${sessionKey}\\n\\n${statsLine}${toolStatsLine}Conversation:\\n${conversation}\\n`;\n\n // Try local LLM first if enabled\n if (this.shouldUseLocalLlm) {\n try {\n const contextSizes = this.modelRegistry.calculateContextSizes(this.config.localLlmModel, this.config.localLlmMaxContext);\n const truncated = user.length > contextSizes.maxInputChars ? user.slice(0, contextSizes.maxInputChars) + \"\\n\\n[truncated]\" : user;\n const response = await this.localLlm.chatCompletion(\n [\n { role: \"system\", content: \"Output valid JSON only.\" },\n { role: \"user\", content: sys + \"\\n\\n\" + truncated },\n ],\n {\n temperature: 0.2,\n maxTokens: contextSizes.maxOutputTokens,\n operation: \"hourly_summary_extended\",\n priority: \"background\",\n },\n );\n if (response?.content) {\n const content = response.content.trim();\n for (const candidate of extractJsonCandidates(content)) {\n try {\n const parsed = JSON.parse(candidate);\n const result = HourlySummaryExtendedSchema.parse(parsed);\n log.debug(\n `generated extended hourly summary for ${sessionKey} at ${hourIso} in ${Date.now() - startTime}ms (local)`,\n );\n return { ...result, _meta: { userTurns, assistantTurns, toolCalls, toolCounts } };\n } catch {\n // keep trying candidates\n }\n }\n }\n } catch (err) {\n if (!this.config.localLlmFallback) return null;\n log.info(\"extended summary: local failed, falling back:\", err);\n }\n }\n\n try {\n const result = await this.fallbackLlm.parseWithSchema(\n [\n { role: \"system\" as const, content: sys },\n { role: \"user\" as const, content: user },\n ],\n HourlySummaryExtendedSchema,\n this.withGatewayAgent({ temperature: 0.2, maxTokens: 2048 }),\n );\n if (result) {\n log.debug(`generated extended hourly summary for ${sessionKey} at ${hourIso} in ${Date.now() - startTime}ms (fallback)`);\n return { ...result, _meta: { userTurns, assistantTurns, toolCalls, toolCounts } };\n }\n return null;\n } catch (err) {\n log.error(\"extended summary generation failed\", err);\n return null;\n }\n }\n\n /**\n * Generate summary using local LLM with JSON mode.\n * Uses dynamic context sizing based on model capabilities.\n */\n private async generateWithLocalLlm(conversation: string): Promise<HourlySummaryResult | null> {\n // Get dynamic context sizes based on model capabilities\n const contextSizes = this.modelRegistry.calculateContextSizes(\n this.config.localLlmModel,\n this.config.localLlmMaxContext\n );\n log.debug(`Summarizer model context: ${contextSizes.description}`);\n\n const maxConversationChars = contextSizes.maxInputChars;\n const truncatedConversation = conversation.length > maxConversationChars\n ? conversation.slice(0, maxConversationChars) + \"\\n\\n[truncated]\"\n : conversation;\n\n const instructions = `You are a conversation summarization system. Summarize the following conversation transcript into 3-5 concise bullet points.\n\nGuidelines:\n- Focus on what was accomplished, decided, or discussed\n- Include specific topics, projects, or entities mentioned\n- Note any significant user requests or agent actions\n- Keep bullets brief but informative (1-2 sentences each)\n- Skip trivial greetings or meta-conversation\n- Use present tense for ongoing work, past for completed items\n\nRespond with valid JSON matching this schema:\n{\n \"bullets\": [\"bullet 1\", \"bullet 2\", \"bullet 3\"]\n}`;\n\n const fullPrompt = `${instructions}\\n\\nConversation to summarize:\\n${truncatedConversation}`;\n\n const response = await this.localLlm.chatCompletion(\n [\n { role: \"system\", content: \"You are a conversation summarization system. Output valid JSON only.\" },\n { role: \"user\", content: fullPrompt },\n ],\n {\n temperature: 0.3,\n maxTokens: contextSizes.maxOutputTokens,\n operation: \"hourly_summary\",\n priority: \"background\",\n },\n );\n\n if (!response?.content) {\n return null;\n }\n\n try {\n // Parse JSON response\n const content = response.content.trim();\n for (const candidate of extractJsonCandidates(content)) {\n try {\n const parsed = JSON.parse(candidate);\n return HourlySummarySchema.parse(parsed);\n } catch {\n // keep trying candidates\n }\n }\n return null;\n } catch (err) {\n log.warn(\"local LLM summary: failed to parse JSON response:\", err);\n return null;\n }\n }\n\n // Save summary to file\n async saveSummary(summary: HourlySummary): Promise<void> {\n const sessionDir = await this.summarySessionDir(summary.sessionKey);\n await mkdir(sessionDir, { recursive: true });\n\n // Format date as YYYY-MM-DD for the filename\n const dateStr = this.summaryDateString(summary.hour);\n const filePath = await resolveSafeStoragePath(sessionDir, `${dateStr}.md`);\n\n // Format hour as HH:00 for display\n const hourStr = summary.hour.slice(11, 13);\n\n // Build markdown content\n const lines: string[] = [];\n\n // Check if file exists to append or create\n let existingContent = \"\";\n try {\n existingContent = await readFile(filePath, \"utf-8\");\n } catch {\n // File doesn't exist yet, will create new\n }\n\n // Check if this hour already exists (idempotent)\n const hourHeader = `## ${hourStr}:00`;\n if (existingContent.includes(hourHeader)) {\n // Replace existing hour section\n const headerMatch = new RegExp(`(^|\\\\n)${escapeRegExp(hourHeader)}\\\\n`).exec(existingContent);\n const sectionStart = headerMatch\n ? headerMatch.index + headerMatch[1].length\n : existingContent.indexOf(hourHeader);\n const nextHeaderPattern = /\\n## \\d{2}:00\\n/g;\n nextHeaderPattern.lastIndex = sectionStart + hourHeader.length;\n const nextHeader = nextHeaderPattern.exec(existingContent);\n const beforeHour = existingContent.slice(0, sectionStart);\n const afterHour = nextHeader\n ? existingContent.slice(nextHeader.index + 1)\n : \"\";\n const newSection = this.formatHourSection(summary, hourHeader);\n existingContent = beforeHour + newSection.trimEnd() + (afterHour ? \"\\n\\n\" + afterHour : \"\\n\");\n\n await writeFile(filePath, existingContent, \"utf-8\");\n log.debug(`updated hourly summary for ${summary.sessionKey} at ${hourStr}:00`);\n } else {\n // Append new hour section\n const newSection = this.formatHourSection(summary, hourHeader);\n\n if (existingContent) {\n // Add to existing file\n await writeFile(filePath, existingContent.trimEnd() + \"\\n\\n\" + newSection, \"utf-8\");\n } else {\n // Create new file with header\n const header = `# Hourly Summaries — ${dateStr}\\n\\n*Session: ${summary.sessionKey}*\\n`;\n await writeFile(filePath, header + \"\\n\" + newSection, \"utf-8\");\n }\n log.debug(`saved hourly summary for ${summary.sessionKey} at ${hourStr}:00`);\n }\n try {\n await upsertSummarySnapshot(this.config.memoryDir, summary);\n } catch (error) {\n log.warn(\n `hourly summarizer: failed to update summary snapshot for ${summary.sessionKey} (fail-open): ${String(error)}`,\n );\n }\n }\n\n private formatHourSection(summary: HourlySummary, hourHeader: string): string {\n const ext = (summary as any)._extended as (HourlySummaryExtendedResult & { _meta?: HourlySummaryExtendedMeta }) | undefined;\n const meta = (summary as any)._extendedMeta as HourlySummaryExtendedMeta | undefined;\n const lines: string[] = [hourHeader, \"\"];\n\n if (this.config.hourlySummariesExtendedEnabled && ext) {\n lines.push(\"### Topics Discussed\");\n for (const t of ext.topics) lines.push(`- ${t}`);\n lines.push(\"\");\n lines.push(\"### Decisions Made\");\n for (const d of ext.decisions) lines.push(`- ${d}`);\n lines.push(\"\");\n lines.push(\"### Action Items\");\n for (const a of ext.actionItems) lines.push(`- ${a}`);\n lines.push(\"\");\n lines.push(\"### Rejected Ideas / Reversals\");\n for (const r of ext.rejected) lines.push(`- ${r}`);\n lines.push(\"\");\n if (meta && Object.keys(meta.toolCounts).length > 0) {\n lines.push(\"### Tools Used\");\n const top = Object.entries(meta.toolCounts)\n .sort((a, b) => b[1] - a[1])\n .slice(0, 12);\n for (const [name, count] of top) lines.push(`- ${name}: ${count}`);\n lines.push(\"\");\n }\n lines.push(\"### Stats\");\n lines.push(`- Turns: ${summary.turnCount}`);\n if (meta) {\n lines.push(`- User turns: ${meta.userTurns}`);\n lines.push(`- Assistant turns: ${meta.assistantTurns}`);\n lines.push(`- Tool calls: ${meta.toolCalls}`);\n }\n lines.push(\"\");\n return lines.join(\"\\n\");\n }\n\n for (const bullet of summary.bullets) lines.push(`- ${bullet}`);\n lines.push(` *(${summary.turnCount} turns)*`);\n lines.push(\"\");\n return lines.join(\"\\n\");\n }\n\n // Read recent summaries for recall injection\n async readRecent(sessionKey: string, hours: number): Promise<HourlySummary[]> {\n try {\n const cutoffTime = Date.now() - hours * 60 * 60 * 1000;\n\n const snapshot = await readSummarySnapshot(this.config.memoryDir, sessionKey);\n if (snapshot) {\n return snapshot\n .filter((s) => new Date(s.hour).getTime() >= cutoffTime)\n .sort((a, b) => new Date(b.hour).getTime() - new Date(a.hour).getTime());\n }\n\n const summaries: HourlySummary[] = [];\n const encodedDir = await this.summarySessionDir(sessionKey);\n const legacyDir = await this.legacySummarySessionDir(sessionKey);\n const seenDirs = new Set<string>();\n\n for (const sessionDir of [encodedDir, legacyDir]) {\n if (!sessionDir || seenDirs.has(sessionDir)) continue;\n seenDirs.add(sessionDir);\n const parsed = await this.readSummaryDir(sessionDir, sessionKey);\n summaries.push(...parsed);\n }\n\n const byHour = new Map<string, HourlySummary>();\n for (const summary of summaries) {\n if (!byHour.has(summary.hour)) byHour.set(summary.hour, summary);\n }\n\n const sortedSummaries = Array.from(byHour.values()).sort(\n (a, b) => new Date(b.hour).getTime() - new Date(a.hour).getTime(),\n );\n\n // Filter to recent hours while materializing the full parsed history.\n const recent = sortedSummaries.filter(\n (s) => new Date(s.hour).getTime() >= cutoffTime,\n );\n\n if (sortedSummaries.length > 0) {\n try {\n await writeSummarySnapshot(\n this.config.memoryDir,\n sessionKey,\n sortedSummaries,\n );\n } catch (error) {\n log.warn(\n `hourly summarizer: failed to materialize summary snapshot for ${sessionKey} (fail-open): ${String(error)}`,\n );\n }\n }\n\n return recent;\n } catch {\n // Directory doesn't exist or error reading\n return [];\n }\n }\n\n private async readSummaryDir(\n sessionDir: string,\n sessionKey: string,\n ): Promise<HourlySummary[]> {\n let files: string[];\n try {\n files = await readdir(sessionDir);\n } catch {\n return [];\n }\n\n const summaries: HourlySummary[] = [];\n const mdFiles = files.filter((f) => f.endsWith(\".md\"));\n for (const file of mdFiles) {\n const filePath = await resolveSafeStoragePath(sessionDir, file).catch(() => null);\n if (filePath === null) continue;\n\n try {\n const content = await readFile(filePath, \"utf-8\");\n summaries.push(...this.parseSummaryFile(content, sessionKey, file));\n } catch {\n // Skip unreadable summary files.\n }\n }\n\n return summaries;\n }\n\n private parseSummaryFile(\n content: string,\n sessionKey: string,\n filename: string\n ): HourlySummary[] {\n const summaries: HourlySummary[] = [];\n\n // Extract date from filename (YYYY-MM-DD.md)\n const dateMatch = filename.match(/^(\\d{4}-\\d{2}-\\d{2})\\.md$/);\n if (!dateMatch) return summaries;\n const dateStr = dateMatch[1];\n\n // Split by hour sections\n const hourSections = content.split(/\\n## (\\d{2}):00\\n/);\n\n // First element is the header, skip it\n for (let i = 1; i < hourSections.length; i += 2) {\n const hourStr = hourSections[i];\n const sectionContent = hourSections[i + 1] || \"\";\n\n // Parse bullets\n const bullets: string[] = [];\n const lines = sectionContent.split(\"\\n\");\n let turnCount = 0;\n\n let inTopics = false;\n let sawExtendedTopicsHeader = false;\n for (const line of lines) {\n if (line.startsWith(\"### Topics\")) {\n inTopics = true;\n sawExtendedTopicsHeader = true;\n continue;\n }\n if (line.startsWith(\"### \") && !line.startsWith(\"### Topics\")) {\n inTopics = false;\n }\n const bulletMatch = line.match(/^- (.+)$/);\n if (bulletMatch) {\n // For extended format, only treat topic bullets as recall bullets.\n if (!sawExtendedTopicsHeader || inTopics) bullets.push(bulletMatch[1]);\n }\n const turnMatch = line.match(/\\((\\d+) turns?\\)/);\n if (turnMatch) turnCount = parseInt(turnMatch[1], 10);\n }\n\n if (bullets.length > 0) {\n summaries.push({\n hour: `${dateStr}T${hourStr}:00:00.000Z`,\n sessionKey,\n bullets,\n turnCount,\n generatedAt: \"\", // Not stored in file, not needed for recall\n });\n }\n }\n\n return summaries;\n }\n\n // Format summaries for recall injection\n formatForRecall(summaries: HourlySummary[], maxCount: number): string {\n if (summaries.length === 0) return \"\";\n\n const limited = summaries.slice(0, maxCount);\n const lines: string[] = [`## Recent Activity (last ${limited.length} hours)`];\n\n for (const summary of limited) {\n const hourStr = summary.hour.slice(11, 16); // HH:MM\n for (const bullet of summary.bullets) {\n lines.push(`- ${hourStr}: ${bullet}`);\n }\n }\n\n return lines.join(\"\\n\");\n }\n\n // Main entry point for cron job\n async runHourly(): Promise<void> {\n log.debug(\"running hourly summary generation\");\n\n // Get active sessions from transcript\n const sessions = await this.getActiveSessions();\n\n for (const sessionKey of sessions) {\n // Calculate the hour we want to summarize (previous hour)\n const now = new Date();\n const hourStart = new Date(now.getTime() - 60 * 60 * 1000);\n hourStart.setMinutes(0, 0, 0);\n const hourEnd = new Date(hourStart.getTime() + 60 * 60 * 1000);\n\n // Get entries for this session in the target hour\n const entries = await this.getTranscriptEntries(sessionKey, hourStart, hourEnd);\n\n if (entries.length === 0) {\n log.debug(`no transcript entries for ${sessionKey} at ${hourStart.toISOString()}`);\n continue;\n }\n\n // Generate and save summary\n const summary = await this.generateSummary(sessionKey, hourStart, entries);\n if (summary) {\n await this.saveSummary(summary);\n log.info(`generated hourly summary for ${sessionKey} (${entries.length} turns)`);\n }\n }\n }\n\n // Get list of active sessions from transcript directory\n private async getActiveSessions(): Promise<string[]> {\n const transcriptDir = await resolveSafeStoragePath(\n this.config.memoryDir,\n \"transcripts\",\n ).catch(() => null);\n if (transcriptDir === null) return [];\n\n try {\n const sessionKeys = new Set<string>();\n const typeEntries = await readdir(transcriptDir, { withFileTypes: true });\n for (const typeEnt of typeEntries) {\n if (!typeEnt.isDirectory()) continue;\n const typeDir = await resolveSafeStoragePath(transcriptDir, typeEnt.name).catch(() => null);\n if (typeDir === null) continue;\n const idEntries = await readdir(typeDir, { withFileTypes: true });\n for (const idEnt of idEntries) {\n if (!idEnt.isDirectory()) continue;\n const chanDir = await resolveSafeStoragePath(typeDir, idEnt.name).catch(() => null);\n if (chanDir === null) continue;\n const files = (await readdir(chanDir)).filter((f) => f.endsWith(\".jsonl\")).sort();\n for (const file of files) {\n const transcriptPath = await resolveSafeStoragePath(chanDir, file).catch(() => null);\n if (transcriptPath === null) continue;\n await this.collectTranscriptSessionKeys(transcriptPath, sessionKeys);\n }\n }\n }\n return Array.from(sessionKeys);\n } catch {\n return [];\n }\n }\n\n private async collectTranscriptSessionKeys(\n transcriptPath: string,\n sessionKeys: Set<string>,\n ): Promise<void> {\n try {\n const raw = await readFile(transcriptPath, \"utf-8\");\n for (const line of raw.split(\"\\n\")) {\n if (!line.trim()) continue;\n try {\n const entry = JSON.parse(line) as TranscriptEntry;\n if (typeof entry.sessionKey === \"string\" && entry.sessionKey.length > 0) {\n sessionKeys.add(entry.sessionKey);\n }\n } catch {\n // ignore malformed transcript lines\n }\n }\n } catch {\n // ignore unreadable transcript files\n }\n }\n\n // Get transcript entries for a session within a time range\n private async getTranscriptEntries(\n sessionKey: string,\n startTime: Date,\n endTime: Date\n ): Promise<TranscriptEntry[]> {\n // Shared session-identity layer (issue #1496, rule #22). Arbitrary keys\n // route to `session/<hash>`; legacy `agent:<id>:...` keep their paths. The\n // shared helper also supplies the read-back-only candidate dirs (mirrors\n // TranscriptManager) so legacy `other/default` AND old `parts.length >= 3`\n // data stays discoverable here too.\n const paths = sessionStoragePaths(sessionKey);\n\n try {\n const transcriptRoot = path.join(this.config.memoryDir, \"transcripts\");\n const candidateDirs = new Set(\n [paths.dir, paths.alternateDir, paths.legacyDir, ...paths.readbackDirs].filter(\n (dir): dir is string => typeof dir === \"string\" && dir.length > 0,\n ),\n );\n const entries: TranscriptEntry[] = [];\n // Dedup identical raw rows that a partially-applied migration may have\n // left in both the primary dir and a read-back dir (issue #1496, cursor\n // review). Exact raw JSONL line is the stable identity.\n const seenRawLines = new Set<string>();\n\n // Read all daily transcript files in the directory\n for (const candidateDir of candidateDirs) {\n const transcriptDir = await resolveSafeStoragePath(transcriptRoot, candidateDir).catch(() => null);\n if (transcriptDir === null) continue;\n\n const files = await readdir(transcriptDir).catch(() => []);\n for (const file of files) {\n if (!file.endsWith(\".jsonl\")) continue;\n\n const transcriptPath = await resolveSafeStoragePath(transcriptDir, file).catch(() => null);\n if (transcriptPath === null) continue;\n\n try {\n const content = await readFile(transcriptPath, \"utf-8\");\n const lines = content.trim().split(\"\\n\");\n\n for (const line of lines) {\n if (!line.trim()) continue;\n try {\n const entry = JSON.parse(line) as TranscriptEntry;\n const entryTime = new Date(entry.timestamp).getTime();\n\n if (\n entry.sessionKey === sessionKey &&\n entryTime >= startTime.getTime() &&\n entryTime < endTime.getTime() &&\n !seenRawLines.has(line)\n ) {\n seenRawLines.add(line);\n entries.push(entry);\n }\n } catch {\n // Skip malformed lines\n }\n }\n } catch {\n // Skip unreadable files\n }\n }\n }\n\n return entries;\n } catch {\n return [];\n }\n }\n}\n"],"mappings":"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","names":[]}
|