@remnic/core 9.3.637 → 9.3.639
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-cli.js +29 -29
- package/dist/access-http.d.ts +56 -5
- package/dist/access-http.js +15 -13
- package/dist/access-mcp.d.ts +4 -4
- package/dist/access-mcp.js +14 -12
- package/dist/access-schema.d.ts +3 -0
- package/dist/access-schema.js +1 -1
- package/dist/{access-service-GVOE5U3C.d.ts → access-service-jyYute38.d.ts} +4 -2
- package/dist/access-service.d.ts +4 -4
- package/dist/access-service.js +12 -10
- package/dist/action-confidence.d.ts +1 -1
- package/dist/active-memory-bridge.d.ts +1 -1
- package/dist/active-recall.d.ts +1 -1
- package/dist/active-recall.js +1 -1
- package/dist/{auto-sync-RFADEHIQ.js → auto-sync-54QQHOG5.js} +4 -4
- package/dist/behavior-learner.d.ts +1 -1
- package/dist/behavior-signals.d.ts +1 -1
- package/dist/bootstrap.d.ts +3 -3
- package/dist/briefing.d.ts +1 -1
- package/dist/briefing.js +3 -3
- 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/calibration.js +1 -1
- package/dist/causal-behavior.d.ts +1 -1
- package/dist/causal-behavior.js +2 -2
- package/dist/causal-chain.js +2 -2
- package/dist/causal-consolidation.d.ts +1 -1
- package/dist/causal-consolidation.js +7 -7
- package/dist/causal-retrieval.js +2 -2
- package/dist/causal-trajectory-graph.js +1 -1
- package/dist/causal-trajectory.js +1 -1
- package/dist/{chunk-TFICNXXU.js → chunk-2BHNQRE5.js} +1153 -294
- package/dist/chunk-2BHNQRE5.js.map +1 -0
- package/dist/{chunk-3RDYU3JS.js → chunk-3AZDLWDW.js} +3 -3
- package/dist/{chunk-FPNQF475.js → chunk-3F7RMHC4.js} +1 -1
- package/dist/chunk-3F7RMHC4.js.map +1 -0
- package/dist/{chunk-3EJ5OOZ3.js → chunk-3SF7QNKF.js} +3 -3
- package/dist/{chunk-NFNQ7TWF.js → chunk-4VTVCWVB.js} +20 -12
- package/dist/chunk-4VTVCWVB.js.map +1 -0
- package/dist/{chunk-XM6M6DHG.js → chunk-52XI77OQ.js} +204 -13
- package/dist/chunk-52XI77OQ.js.map +1 -0
- package/dist/{chunk-6BDVBBBY.js → chunk-666A3MOW.js} +88 -30
- package/dist/chunk-666A3MOW.js.map +1 -0
- package/dist/{chunk-242XFZ36.js → chunk-7OH7KPF5.js} +2 -2
- package/dist/{chunk-HZVIYZYN.js → chunk-7R37SOT4.js} +6 -6
- package/dist/{chunk-7A2QKUUA.js → chunk-7XRSLMUD.js} +2 -2
- package/dist/{chunk-723OMPUI.js → chunk-A3BS64GV.js} +7 -1
- package/dist/chunk-A3BS64GV.js.map +1 -0
- package/dist/{chunk-JCLECECB.js → chunk-A3UPMOJZ.js} +2 -2
- package/dist/{chunk-YCX45GOQ.js → chunk-AFH2JXSF.js} +2 -2
- package/dist/{chunk-BK35NOJL.js → chunk-BB6FNMMB.js} +52 -6
- package/dist/chunk-BB6FNMMB.js.map +1 -0
- package/dist/{chunk-3XNMN242.js → chunk-BTY5XQG3.js} +7 -7
- package/dist/{chunk-QHXW3LZV.js → chunk-C3EJ3UIS.js} +3 -3
- package/dist/{chunk-A3HKTPPV.js → chunk-C63WC454.js} +12 -1
- package/dist/chunk-C63WC454.js.map +1 -0
- package/dist/{chunk-4S3N6HFG.js → chunk-C6XO6ONP.js} +2 -2
- package/dist/{chunk-WD2W4234.js → chunk-CDHRUNBX.js} +11 -2
- package/dist/chunk-CDHRUNBX.js.map +1 -0
- package/dist/{chunk-YQNADJCT.js → chunk-CMZLMIZI.js} +2 -2
- package/dist/{chunk-KVDUDYEN.js → chunk-DDRNDPX4.js} +2 -2
- package/dist/{chunk-PW6GURU3.js → chunk-EKIQBGAY.js} +2 -2
- package/dist/{chunk-QJGTSCJN.js → chunk-FGRV3X3Y.js} +19 -19
- package/dist/{chunk-2IT7WFYE.js → chunk-FWIROLS6.js} +2 -1
- package/dist/chunk-FWIROLS6.js.map +1 -0
- package/dist/{chunk-X7EJF46S.js → chunk-H4RWKZE2.js} +2 -2
- package/dist/{chunk-A6D7A2FW.js → chunk-IHG27THY.js} +4 -4
- package/dist/{chunk-PUEAEQSN.js → chunk-ISMZIMD3.js} +2 -2
- package/dist/{chunk-LEG7XWS2.js → chunk-IXSTQGYV.js} +2 -2
- package/dist/{chunk-CMN5AWAZ.js → chunk-J2KFC47S.js} +2 -2
- package/dist/{chunk-K47C6M2C.js → chunk-M75TBFKQ.js} +2 -2
- package/dist/{chunk-7V2SGZ3H.js → chunk-NE566K4E.js} +2 -2
- package/dist/{chunk-YROCXMCK.js → chunk-RJGPH2Q3.js} +2 -2
- package/dist/{chunk-UXFOGILU.js → chunk-SBHQBC37.js} +2 -2
- package/dist/{chunk-QYGIQ5NM.js → chunk-SHHT4JTC.js} +2 -2
- package/dist/{chunk-TQOU3VAT.js → chunk-SSOMTUCA.js} +1 -1
- package/dist/{chunk-NRST7W5Q.js → chunk-UI2UP7XX.js} +2 -2
- package/dist/{chunk-C4KKM62E.js → chunk-UU5LHD6J.js} +2 -2
- package/dist/{chunk-EWC6W6AB.js → chunk-UXA5L2DZ.js} +2 -2
- package/dist/{chunk-XL7FK7PJ.js → chunk-Y56J7CXW.js} +33 -16
- package/dist/{chunk-XL7FK7PJ.js.map → chunk-Y56J7CXW.js.map} +1 -1
- package/dist/{cli-B-fHk59D.d.ts → cli-A4AIhv9e.d.ts} +3 -3
- package/dist/cli.d.ts +5 -5
- package/dist/cli.js +28 -27
- package/dist/compounding/engine.d.ts +1 -1
- package/dist/compounding/engine.js +3 -3
- 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/config.js +1 -1
- package/dist/connectors/codex-materialize-runner.d.ts +1 -1
- package/dist/connectors/codex-materialize-runner.js +3 -3
- package/dist/connectors/codex-materialize.d.ts +1 -1
- package/dist/connectors/index.d.ts +1 -1
- package/dist/connectors/index.js +3 -3
- package/dist/consolidation-provenance-check.d.ts +1 -1
- package/dist/consolidation-undo.d.ts +1 -1
- package/dist/contradiction/index.d.ts +1 -1
- 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/enrichment/index.d.ts +1 -1
- package/dist/entity-retrieval.d.ts +1 -1
- package/dist/entity-retrieval.js +3 -3
- package/dist/entity-schema.d.ts +1 -1
- package/dist/explicit-capture.d.ts +3 -3
- 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-judge.js +2 -2
- package/dist/extraction.d.ts +1 -1
- package/dist/extraction.js +2 -2
- package/dist/fallback-llm.d.ts +1 -1
- package/dist/fallback-llm.js +1 -1
- package/dist/{graph-edge-decay-5ZOK7ZNO.js → graph-edge-decay-PUFNHOBS.js} +2 -2
- package/dist/graph-snapshot.js +2 -2
- package/dist/graph.d.ts +3 -0
- package/dist/graph.js +1 -1
- package/dist/identity-continuity.d.ts +1 -1
- package/dist/importance.d.ts +1 -1
- package/dist/index.d.ts +9 -9
- package/dist/index.js +40 -40
- 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/maintenance/memory-governance-cron.d.ts +8 -0
- package/dist/maintenance/memory-governance-cron.js +1 -1
- package/dist/maintenance/memory-governance.d.ts +1 -1
- package/dist/maintenance/memory-governance.js +3 -3
- package/dist/maintenance/rebuild-memory-lifecycle-ledger.js +3 -3
- package/dist/maintenance/rebuild-memory-projection.js +4 -4
- package/dist/mcp-memory-inspector-app.d.ts +4 -4
- 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 +1 -1
- package/dist/namespaces/migrate.js +4 -4
- package/dist/namespaces/principal.d.ts +1 -1
- package/dist/namespaces/search.d.ts +1 -1
- package/dist/namespaces/storage.d.ts +1 -1
- package/dist/namespaces/storage.js +3 -3
- package/dist/native-knowledge.d.ts +1 -1
- package/dist/operator-toolkit.d.ts +1 -1
- package/dist/operator-toolkit.js +8 -8
- package/dist/{orchestrator-CoqytbK_.d.ts → orchestrator-BEDTiuEO.d.ts} +20 -5
- package/dist/orchestrator.d.ts +3 -3
- package/dist/orchestrator.js +24 -24
- package/dist/patterns-cli.d.ts +1 -1
- package/dist/policy-runtime.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-explain-renderer.js +3 -3
- package/dist/recall-planner-llm.d.ts +1 -1
- package/dist/recall-planner-llm.js +1 -1
- package/dist/recall-state.d.ts +3 -1
- package/dist/recall-state.js +1 -1
- package/dist/recall-tag-filter.d.ts +1 -1
- package/dist/recall-xray-cli.d.ts +1 -1
- package/dist/recall-xray-cli.js +4 -4
- package/dist/recall-xray-renderer.d.ts +1 -1
- package/dist/recall-xray-renderer.js +3 -3
- package/dist/recall-xray.d.ts +1 -1
- package/dist/recall-xray.js +2 -2
- package/dist/resolve-auth-token.d.ts +1 -1
- package/dist/resume-bundles.js +4 -4
- 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/search/embed-helper.d.ts +1 -1
- package/dist/search/factory.d.ts +1 -1
- package/dist/search/index.d.ts +1 -1
- 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-consolidation-BPs6BURk.d.ts → semantic-consolidation-Byut1ufK.d.ts} +1 -1
- package/dist/semantic-consolidation.d.ts +2 -2
- package/dist/semantic-consolidation.js +4 -4
- package/dist/semantic-rule-promotion.js +3 -3
- package/dist/semantic-rule-verifier.d.ts +1 -1
- package/dist/semantic-rule-verifier.js +3 -3
- 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/storage.js +2 -2
- package/dist/summarizer.d.ts +1 -1
- package/dist/summarizer.js +3 -3
- 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/topics.d.ts +1 -1
- package/dist/transcript.d.ts +1 -1
- package/dist/transcript.js +2 -2
- package/dist/{types-CpMPD8xl.d.ts → types-BzA1FKbg.d.ts} +4 -0
- package/dist/types.d.ts +1 -1
- package/dist/types.js +1 -1
- package/dist/utility-runtime.d.ts +1 -1
- package/dist/verified-recall.js +3 -3
- package/package.json +1 -1
- package/src/access-http.test.ts +110 -2
- package/src/access-http.ts +117 -1
- package/src/access-mcp.ts +15 -6
- package/src/access-schema.ts +14 -0
- package/src/access-service-namespace.test.ts +740 -0
- package/src/access-service.ts +226 -4
- package/src/config.ts +14 -0
- package/src/fallback-llm.ts +16 -0
- package/src/graph.ts +39 -17
- package/src/index.ts +9 -1
- package/src/maintenance/memory-governance-cron.ts +113 -30
- package/src/orchestrator.ts +1456 -336
- package/src/recall-state.ts +3 -0
- package/src/types.ts +4 -0
- package/dist/chunk-2IT7WFYE.js.map +0 -1
- package/dist/chunk-6BDVBBBY.js.map +0 -1
- package/dist/chunk-723OMPUI.js.map +0 -1
- package/dist/chunk-A3HKTPPV.js.map +0 -1
- package/dist/chunk-BK35NOJL.js.map +0 -1
- package/dist/chunk-FPNQF475.js.map +0 -1
- package/dist/chunk-NFNQ7TWF.js.map +0 -1
- package/dist/chunk-TFICNXXU.js.map +0 -1
- package/dist/chunk-WD2W4234.js.map +0 -1
- package/dist/chunk-XM6M6DHG.js.map +0 -1
- /package/dist/{auto-sync-RFADEHIQ.js.map → auto-sync-54QQHOG5.js.map} +0 -0
- /package/dist/{chunk-3RDYU3JS.js.map → chunk-3AZDLWDW.js.map} +0 -0
- /package/dist/{chunk-3EJ5OOZ3.js.map → chunk-3SF7QNKF.js.map} +0 -0
- /package/dist/{chunk-242XFZ36.js.map → chunk-7OH7KPF5.js.map} +0 -0
- /package/dist/{chunk-HZVIYZYN.js.map → chunk-7R37SOT4.js.map} +0 -0
- /package/dist/{chunk-7A2QKUUA.js.map → chunk-7XRSLMUD.js.map} +0 -0
- /package/dist/{chunk-JCLECECB.js.map → chunk-A3UPMOJZ.js.map} +0 -0
- /package/dist/{chunk-YCX45GOQ.js.map → chunk-AFH2JXSF.js.map} +0 -0
- /package/dist/{chunk-3XNMN242.js.map → chunk-BTY5XQG3.js.map} +0 -0
- /package/dist/{chunk-QHXW3LZV.js.map → chunk-C3EJ3UIS.js.map} +0 -0
- /package/dist/{chunk-4S3N6HFG.js.map → chunk-C6XO6ONP.js.map} +0 -0
- /package/dist/{chunk-YQNADJCT.js.map → chunk-CMZLMIZI.js.map} +0 -0
- /package/dist/{chunk-KVDUDYEN.js.map → chunk-DDRNDPX4.js.map} +0 -0
- /package/dist/{chunk-PW6GURU3.js.map → chunk-EKIQBGAY.js.map} +0 -0
- /package/dist/{chunk-QJGTSCJN.js.map → chunk-FGRV3X3Y.js.map} +0 -0
- /package/dist/{chunk-X7EJF46S.js.map → chunk-H4RWKZE2.js.map} +0 -0
- /package/dist/{chunk-A6D7A2FW.js.map → chunk-IHG27THY.js.map} +0 -0
- /package/dist/{chunk-PUEAEQSN.js.map → chunk-ISMZIMD3.js.map} +0 -0
- /package/dist/{chunk-LEG7XWS2.js.map → chunk-IXSTQGYV.js.map} +0 -0
- /package/dist/{chunk-CMN5AWAZ.js.map → chunk-J2KFC47S.js.map} +0 -0
- /package/dist/{chunk-K47C6M2C.js.map → chunk-M75TBFKQ.js.map} +0 -0
- /package/dist/{chunk-7V2SGZ3H.js.map → chunk-NE566K4E.js.map} +0 -0
- /package/dist/{chunk-YROCXMCK.js.map → chunk-RJGPH2Q3.js.map} +0 -0
- /package/dist/{chunk-UXFOGILU.js.map → chunk-SBHQBC37.js.map} +0 -0
- /package/dist/{chunk-QYGIQ5NM.js.map → chunk-SHHT4JTC.js.map} +0 -0
- /package/dist/{chunk-TQOU3VAT.js.map → chunk-SSOMTUCA.js.map} +0 -0
- /package/dist/{chunk-NRST7W5Q.js.map → chunk-UI2UP7XX.js.map} +0 -0
- /package/dist/{chunk-C4KKM62E.js.map → chunk-UU5LHD6J.js.map} +0 -0
- /package/dist/{chunk-EWC6W6AB.js.map → chunk-UXA5L2DZ.js.map} +0 -0
- /package/dist/{graph-edge-decay-5ZOK7ZNO.js.map → graph-edge-decay-PUFNHOBS.js.map} +0 -0
|
@@ -65,7 +65,7 @@ async function ensureCronJob(jobsPath, jobId, buildJob, options = {}) {
|
|
|
65
65
|
}
|
|
66
66
|
const desired = buildJob();
|
|
67
67
|
const existing = jobs[existingIndex];
|
|
68
|
-
const next = mergeCronJobUpdate(existing, desired, options.updateFields);
|
|
68
|
+
const next = mergeCronJobUpdate(existing, desired, options.updateFields, options.deepMerge);
|
|
69
69
|
if (stableJson(existing) === stableJson(next)) {
|
|
70
70
|
return { created: false, updated: false, jobId };
|
|
71
71
|
}
|
|
@@ -82,18 +82,39 @@ async function ensureCronJob(jobsPath, jobId, buildJob, options = {}) {
|
|
|
82
82
|
await releaseLock();
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
|
-
function
|
|
86
|
-
|
|
85
|
+
function deepMergeObjects(target, source) {
|
|
86
|
+
const result = { ...target };
|
|
87
|
+
for (const [key, value] of Object.entries(source)) {
|
|
88
|
+
if (value === null) {
|
|
89
|
+
delete result[key];
|
|
90
|
+
} else if (value && typeof value === "object" && !Array.isArray(value) && result[key] && typeof result[key] === "object" && !Array.isArray(result[key])) {
|
|
91
|
+
result[key] = deepMergeObjects(
|
|
92
|
+
result[key],
|
|
93
|
+
value
|
|
94
|
+
);
|
|
95
|
+
} else {
|
|
96
|
+
result[key] = value;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
return result;
|
|
100
|
+
}
|
|
101
|
+
function mergeCronJobUpdate(existing, desired, updateFields, deepMerge) {
|
|
102
|
+
let next = { ...existing };
|
|
103
|
+
if (!updateFields && !deepMerge) {
|
|
87
104
|
return desired;
|
|
88
105
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
106
|
+
if (updateFields) {
|
|
107
|
+
for (const field of updateFields) {
|
|
108
|
+
if (Object.prototype.hasOwnProperty.call(desired, field)) {
|
|
109
|
+
next[field] = desired[field];
|
|
110
|
+
} else {
|
|
111
|
+
delete next[field];
|
|
112
|
+
}
|
|
95
113
|
}
|
|
96
114
|
}
|
|
115
|
+
if (deepMerge) {
|
|
116
|
+
next = deepMergeObjects(next, deepMerge);
|
|
117
|
+
}
|
|
97
118
|
return next;
|
|
98
119
|
}
|
|
99
120
|
function stableJson(value) {
|
|
@@ -108,26 +129,63 @@ function stableJson(value) {
|
|
|
108
129
|
}
|
|
109
130
|
async function ensureDaySummaryCron(jobsPath, options) {
|
|
110
131
|
const agentId = typeof options.agentId === "string" && options.agentId.trim().length > 0 ? options.agentId.trim() : "main";
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
132
|
+
const daySummaryParams = JSON.stringify({ timeZone: options.timezone });
|
|
133
|
+
const payload = {
|
|
134
|
+
kind: "agentTurn",
|
|
135
|
+
timeoutSeconds: 900,
|
|
136
|
+
thinking: "off",
|
|
137
|
+
message: `You are OpenClaw automation. Call tool engram.day_summary with params ${daySummaryParams} (it will auto-gather today's facts for that timezone). If successful output exactly NO_REPLY. On error output one concise line. Do NOT use message tool.`
|
|
138
|
+
};
|
|
139
|
+
if (options.model) {
|
|
140
|
+
payload.model = options.model;
|
|
141
|
+
}
|
|
142
|
+
if (options.fallbacks && options.fallbacks.length > 0) {
|
|
143
|
+
payload.fallbacks = options.fallbacks;
|
|
144
|
+
}
|
|
145
|
+
return ensureCronJob(
|
|
146
|
+
jobsPath,
|
|
147
|
+
DAY_SUMMARY_CRON_ID,
|
|
148
|
+
() => ({
|
|
149
|
+
id: DAY_SUMMARY_CRON_ID,
|
|
150
|
+
agentId,
|
|
151
|
+
name: "Remnic Day Summary (auto)",
|
|
152
|
+
enabled: true,
|
|
153
|
+
schedule: {
|
|
154
|
+
kind: "cron",
|
|
155
|
+
expr: "47 23 * * *",
|
|
156
|
+
tz: options.timezone
|
|
157
|
+
},
|
|
158
|
+
sessionTarget: "isolated",
|
|
159
|
+
wakeMode: "now",
|
|
160
|
+
// Mirror model at job root for backward compat with older OpenClaw
|
|
161
|
+
// builds that read root model instead of payload.model.
|
|
162
|
+
...options.model ? { model: options.model } : {},
|
|
163
|
+
payload,
|
|
164
|
+
delivery: { mode: "none" }
|
|
165
|
+
}),
|
|
166
|
+
// Reconcile on every startup so model/timezone changes propagate.
|
|
167
|
+
// Issue #1474 (model reconcile) + #1475 (timezone reconcile).
|
|
168
|
+
// Only update managed leaves to avoid clobbering user edits to
|
|
169
|
+
// schedule.expr, payload.message, payload.timeoutSeconds, etc.
|
|
170
|
+
// Only reconcile agentId when explicitly provided, so manually-set
|
|
171
|
+
// cron personas are preserved.
|
|
172
|
+
{
|
|
173
|
+
updateExisting: true,
|
|
174
|
+
updateFields: options.hasExplicitAgentId ? ["agentId"] : [],
|
|
175
|
+
deepMerge: {
|
|
176
|
+
schedule: { tz: options.timezone },
|
|
177
|
+
// Mirror model at job root for backward compat with older OpenClaw
|
|
178
|
+
// builds that read root model instead of payload.model.
|
|
179
|
+
model: options.model ?? null,
|
|
180
|
+
// Always write model/fallbacks so stale values are cleared when
|
|
181
|
+
// an operator removes summaryModel or taskModelChain from config.
|
|
182
|
+
payload: {
|
|
183
|
+
model: options.model ?? null,
|
|
184
|
+
fallbacks: options.fallbacks && options.fallbacks.length > 0 ? options.fallbacks : null
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
);
|
|
131
189
|
}
|
|
132
190
|
async function ensureNightlyGovernanceCron(jobsPath, options) {
|
|
133
191
|
const recentDays = typeof options.recentDays === "number" && Number.isFinite(options.recentDays) ? Math.max(1, Math.floor(options.recentDays)) : 2;
|
|
@@ -288,4 +346,4 @@ export {
|
|
|
288
346
|
ensureGraphEdgeDecayCron,
|
|
289
347
|
graphEdgeDecayCadenceToCronExpr
|
|
290
348
|
};
|
|
291
|
-
//# sourceMappingURL=chunk-
|
|
349
|
+
//# sourceMappingURL=chunk-666A3MOW.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/maintenance/memory-governance-cron.ts"],"sourcesContent":["import { mkdir, readFile, rename, rm, stat, writeFile } from \"node:fs/promises\";\nimport path from \"node:path\";\n\nconst DAY_SUMMARY_CRON_ID = \"engram-day-summary\";\nconst GOVERNANCE_CRON_ID = \"engram-nightly-governance\";\nconst PROCEDURAL_MINING_CRON_ID = \"engram-procedural-mining\";\nconst CONTRADICTION_SCAN_CRON_ID = \"engram-contradiction-scan\";\nconst PATTERN_REINFORCEMENT_CRON_ID = \"engram-pattern-reinforcement\";\nconst GRAPH_EDGE_DECAY_CRON_ID = \"engram-graph-edge-decay\";\n\ntype CronJobsShape =\n | Array<Record<string, unknown>>\n | {\n jobs: Array<Record<string, unknown>>;\n [key: string]: unknown;\n };\n\nasync function acquireCronJobsLock(jobsPath: string): Promise<() => Promise<void>> {\n const lockPath = `${jobsPath}.lock`;\n const start = Date.now();\n const staleMs = 30_000;\n const timeoutMs = 5_000;\n await mkdir(path.dirname(lockPath), { recursive: true });\n\n while (Date.now() - start < timeoutMs) {\n try {\n await mkdir(lockPath);\n return async () => {\n try {\n await rm(lockPath, { recursive: true, force: true });\n } catch {\n // Lock cleanup should not fail cron registration.\n }\n };\n } catch (error) {\n const code = (error as NodeJS.ErrnoException).code;\n if (code !== \"EEXIST\") {\n throw error;\n }\n try {\n const lockStat = await stat(lockPath);\n if (Date.now() - lockStat.mtimeMs > staleMs) {\n await rm(lockPath, { recursive: true, force: true });\n continue;\n }\n } catch {\n // Lock may have been released between stat/rm attempts.\n }\n await new Promise((resolve) => setTimeout(resolve, 25));\n }\n }\n\n throw new Error(`cron jobs lock acquisition timed out after ${timeoutMs}ms`);\n}\n\nfunction parseCronJobsShape(raw: string): { parsed: CronJobsShape; jobs: Array<Record<string, unknown>> } {\n const parsed = JSON.parse(raw) as CronJobsShape;\n const jobs = Array.isArray(parsed) ? parsed : Array.isArray(parsed.jobs) ? parsed.jobs : null;\n if (!jobs) {\n throw new Error(\"jobs.json has unexpected structure\");\n }\n return { parsed, jobs };\n}\n\nasync function writeCronJobsAtomic(jobsPath: string, value: CronJobsShape): Promise<void> {\n const tempPath = `${jobsPath}.${process.pid}.${Date.now()}.tmp`;\n await writeFile(tempPath, JSON.stringify(value, null, 2) + \"\\n\", \"utf-8\");\n await rename(tempPath, jobsPath);\n}\n\nexport async function ensureCronJob(\n jobsPath: string,\n jobId: string,\n buildJob: () => Record<string, unknown>,\n options: {\n updateExisting?: boolean;\n updateFields?: string[];\n deepMerge?: Record<string, unknown>;\n } = {},\n): Promise<{ created: boolean; updated: boolean; jobId: string }> {\n const releaseLock = await acquireCronJobsLock(jobsPath);\n try {\n const raw = await readFile(jobsPath, \"utf-8\");\n const { parsed, jobs } = parseCronJobsShape(raw);\n\n const existingIndex = jobs.findIndex((job) => job.id === jobId);\n if (existingIndex >= 0) {\n if (!options.updateExisting) {\n return { created: false, updated: false, jobId };\n }\n\n const desired = buildJob();\n const existing = jobs[existingIndex];\n const next = mergeCronJobUpdate(existing, desired, options.updateFields, options.deepMerge);\n if (stableJson(existing) === stableJson(next)) {\n return { created: false, updated: false, jobId };\n }\n\n jobs[existingIndex] = next;\n const output = Array.isArray(parsed) ? jobs : { ...parsed, jobs };\n await writeCronJobsAtomic(jobsPath, output);\n return { created: false, updated: true, jobId };\n }\n\n jobs.push(buildJob());\n const output = Array.isArray(parsed) ? jobs : { ...parsed, jobs };\n await writeCronJobsAtomic(jobsPath, output);\n return { created: true, updated: false, jobId };\n } finally {\n await releaseLock();\n }\n}\n\nfunction deepMergeObjects(\n target: Record<string, unknown>,\n source: Record<string, unknown>,\n): Record<string, unknown> {\n const result = { ...target };\n for (const [key, value] of Object.entries(source)) {\n if (value === null) {\n // null means \"remove this key\"\n delete result[key];\n } else if (\n value && typeof value === \"object\" && !Array.isArray(value) &&\n result[key] && typeof result[key] === \"object\" && !Array.isArray(result[key])\n ) {\n result[key] = deepMergeObjects(\n result[key] as Record<string, unknown>,\n value as Record<string, unknown>,\n );\n } else {\n result[key] = value;\n }\n }\n return result;\n}\n\nfunction mergeCronJobUpdate(\n existing: Record<string, unknown>,\n desired: Record<string, unknown>,\n updateFields?: string[],\n deepMerge?: Record<string, unknown>,\n): Record<string, unknown> {\n let next = { ...existing };\n\n if (!updateFields && !deepMerge) {\n return desired;\n }\n\n if (updateFields) {\n for (const field of updateFields) {\n if (Object.prototype.hasOwnProperty.call(desired, field)) {\n next[field] = desired[field];\n } else {\n delete next[field];\n }\n }\n }\n\n if (deepMerge) {\n next = deepMergeObjects(next, deepMerge);\n }\n\n return next;\n}\n\nfunction stableJson(value: unknown): string {\n if (Array.isArray(value)) {\n return `[${value.map((item) => stableJson(item)).join(\",\")}]`;\n }\n if (value && typeof value === \"object\") {\n const record = value as Record<string, unknown>;\n return `{${Object.keys(record)\n .sort()\n .map((key) => `${JSON.stringify(key)}:${stableJson(record[key])}`)\n .join(\",\")}}`;\n }\n return JSON.stringify(value);\n}\n\nexport async function ensureDaySummaryCron(\n jobsPath: string,\n options: {\n timezone: string;\n agentId?: string;\n /** Whether agentId was explicitly provided (vs defaulted to \"main\"). */\n hasExplicitAgentId?: boolean;\n /** Optional model override (e.g. from summaryModel or taskModelChain.primary). */\n model?: string;\n /** Optional fallbacks to include alongside the model. */\n fallbacks?: string[];\n },\n): Promise<{ created: boolean; updated: boolean; jobId: string }> {\n const agentId =\n typeof options.agentId === \"string\" && options.agentId.trim().length > 0\n ? options.agentId.trim()\n : \"main\";\n const daySummaryParams = JSON.stringify({ timeZone: options.timezone });\n\n const payload: Record<string, unknown> = {\n kind: \"agentTurn\",\n timeoutSeconds: 900,\n thinking: \"off\",\n message:\n `You are OpenClaw automation. Call tool engram.day_summary with params ${daySummaryParams} (it will auto-gather today's facts for that timezone). If successful output exactly NO_REPLY. On error output one concise line. Do NOT use message tool.`,\n };\n if (options.model) {\n payload.model = options.model;\n }\n if (options.fallbacks && options.fallbacks.length > 0) {\n payload.fallbacks = options.fallbacks;\n }\n\n return ensureCronJob(\n jobsPath,\n DAY_SUMMARY_CRON_ID,\n () => ({\n id: DAY_SUMMARY_CRON_ID,\n agentId,\n name: \"Remnic Day Summary (auto)\",\n enabled: true,\n schedule: {\n kind: \"cron\",\n expr: \"47 23 * * *\",\n tz: options.timezone,\n },\n sessionTarget: \"isolated\",\n wakeMode: \"now\",\n // Mirror model at job root for backward compat with older OpenClaw\n // builds that read root model instead of payload.model.\n ...(options.model ? { model: options.model } : {}),\n payload,\n delivery: { mode: \"none\" },\n }),\n // Reconcile on every startup so model/timezone changes propagate.\n // Issue #1474 (model reconcile) + #1475 (timezone reconcile).\n // Only update managed leaves to avoid clobbering user edits to\n // schedule.expr, payload.message, payload.timeoutSeconds, etc.\n // Only reconcile agentId when explicitly provided, so manually-set\n // cron personas are preserved.\n {\n updateExisting: true,\n updateFields: options.hasExplicitAgentId ? [\"agentId\"] : [],\n deepMerge: {\n schedule: { tz: options.timezone },\n // Mirror model at job root for backward compat with older OpenClaw\n // builds that read root model instead of payload.model.\n model: options.model ?? null,\n // Always write model/fallbacks so stale values are cleared when\n // an operator removes summaryModel or taskModelChain from config.\n payload: {\n model: options.model ?? null,\n fallbacks: (options.fallbacks && options.fallbacks.length > 0)\n ? options.fallbacks\n : null,\n },\n },\n },\n );\n}\n\nexport async function ensureNightlyGovernanceCron(\n jobsPath: string,\n options: {\n timezone: string;\n agentId?: string;\n recentDays?: number;\n maxMemories?: number;\n batchSize?: number;\n scheduleExpr?: string;\n },\n): Promise<{ created: boolean; jobId: string }> {\n const recentDays =\n typeof options.recentDays === \"number\" && Number.isFinite(options.recentDays)\n ? Math.max(1, Math.floor(options.recentDays))\n : 2;\n const maxMemories =\n typeof options.maxMemories === \"number\" && Number.isFinite(options.maxMemories)\n ? Math.max(1, Math.floor(options.maxMemories))\n : 500;\n const batchSize =\n typeof options.batchSize === \"number\" && Number.isFinite(options.batchSize)\n ? Math.max(1, Math.floor(options.batchSize))\n : 100;\n const scheduleExpr =\n typeof options.scheduleExpr === \"string\" && options.scheduleExpr.trim().length > 0\n ? options.scheduleExpr.trim()\n : \"23 2 * * *\";\n const agentId =\n typeof options.agentId === \"string\" && options.agentId.trim().length > 0\n ? options.agentId.trim()\n : \"main\";\n\n return ensureCronJob(jobsPath, GOVERNANCE_CRON_ID, () => ({\n id: GOVERNANCE_CRON_ID,\n agentId,\n name: \"Remnic Nightly Governance (batched)\",\n enabled: true,\n schedule: {\n kind: \"cron\",\n expr: scheduleExpr,\n tz: options.timezone,\n },\n sessionTarget: \"isolated\",\n wakeMode: \"now\",\n payload: {\n kind: \"agentTurn\",\n timeoutSeconds: 900,\n thinking: \"off\",\n message:\n \"You are OpenClaw automation. Call the tool `engram.memory_governance_run` with params \" +\n `{\"mode\": \"apply\", \"recentDays\": ${recentDays}, \"maxMemories\": ${maxMemories}, \"batchSize\": ${batchSize}}` +\n \". If successful output exactly NO_REPLY. On error output one concise line. Do NOT use message tool.\",\n },\n delivery: { mode: \"none\" },\n }));\n}\n\nexport async function ensureProceduralMiningCron(\n jobsPath: string,\n options: {\n timezone: string;\n agentId?: string;\n scheduleExpr?: string;\n },\n): Promise<{ created: boolean; jobId: string }> {\n const scheduleExpr =\n typeof options.scheduleExpr === \"string\" && options.scheduleExpr.trim().length > 0\n ? options.scheduleExpr.trim()\n : \"17 3 * * *\";\n const agentId =\n typeof options.agentId === \"string\" && options.agentId.trim().length > 0\n ? options.agentId.trim()\n : \"main\";\n\n return ensureCronJob(jobsPath, PROCEDURAL_MINING_CRON_ID, () => ({\n id: PROCEDURAL_MINING_CRON_ID,\n agentId,\n name: \"Remnic Procedural Mining (nightly)\",\n enabled: true,\n schedule: {\n kind: \"cron\",\n expr: scheduleExpr,\n tz: options.timezone,\n },\n sessionTarget: \"isolated\",\n wakeMode: \"now\",\n payload: {\n kind: \"agentTurn\",\n timeoutSeconds: 900,\n thinking: \"off\",\n message:\n \"You are OpenClaw automation. Call tool `engram.procedure_mining_run` with empty params. \" +\n \"If successful output exactly NO_REPLY. On error output one concise line. Do NOT use message tool.\",\n },\n delivery: { mode: \"none\" },\n }));\n}\n\nexport async function ensureContradictionScanCron(\n jobsPath: string,\n options: {\n timezone: string;\n agentId?: string;\n scheduleExpr?: string;\n },\n): Promise<{ created: boolean; jobId: string }> {\n const scheduleExpr =\n typeof options.scheduleExpr === \"string\" && options.scheduleExpr.trim().length > 0\n ? options.scheduleExpr.trim()\n : \"37 3 * * *\";\n const agentId =\n typeof options.agentId === \"string\" && options.agentId.trim().length > 0\n ? options.agentId.trim()\n : \"main\";\n\n return ensureCronJob(jobsPath, CONTRADICTION_SCAN_CRON_ID, () => ({\n id: CONTRADICTION_SCAN_CRON_ID,\n agentId,\n name: \"Remnic Contradiction Scan (nightly)\",\n enabled: true,\n schedule: {\n kind: \"cron\",\n expr: scheduleExpr,\n tz: options.timezone,\n },\n sessionTarget: \"isolated\",\n wakeMode: \"now\",\n payload: {\n kind: \"agentTurn\",\n timeoutSeconds: 900,\n thinking: \"off\",\n message:\n \"You are OpenClaw automation. Call tool `engram.contradiction_scan_run` with empty params. \" +\n \"If successful output exactly NO_REPLY. On error output one concise line. Do NOT use message tool.\",\n },\n delivery: { mode: \"none\" },\n }));\n}\n\nexport async function ensurePatternReinforcementCron(\n jobsPath: string,\n options: {\n timezone: string;\n agentId?: string;\n /**\n * Cron expression. Default `\"53 4 * * 0\"` — Sunday 04:53 in the\n * configured timezone, deliberately offset from sibling crons\n * (`23 2 * * *`, `17 3 * * *`, `37 3 * * *`) so the maintenance\n * passes don't pile up on the same minute.\n */\n scheduleExpr?: string;\n },\n): Promise<{ created: boolean; jobId: string }> {\n const scheduleExpr =\n typeof options.scheduleExpr === \"string\" && options.scheduleExpr.trim().length > 0\n ? options.scheduleExpr.trim()\n : \"53 4 * * 0\";\n const agentId =\n typeof options.agentId === \"string\" && options.agentId.trim().length > 0\n ? options.agentId.trim()\n : \"main\";\n\n return ensureCronJob(jobsPath, PATTERN_REINFORCEMENT_CRON_ID, () => ({\n id: PATTERN_REINFORCEMENT_CRON_ID,\n agentId,\n name: \"Remnic Pattern Reinforcement (weekly)\",\n enabled: true,\n schedule: {\n kind: \"cron\",\n expr: scheduleExpr,\n tz: options.timezone,\n },\n sessionTarget: \"isolated\",\n wakeMode: \"now\",\n payload: {\n kind: \"agentTurn\",\n timeoutSeconds: 900,\n thinking: \"off\",\n message:\n \"You are OpenClaw automation. Call tool `engram.pattern_reinforcement_run` with empty params. \" +\n \"If successful output exactly NO_REPLY. On error output one concise line. Do NOT use message tool.\",\n },\n delivery: { mode: \"none\" },\n }));\n}\n\n/**\n * Register a cron job that runs the graph-edge-decay maintenance pass\n * (issue #681 PR 2/3). Default schedule is weekly on Sunday 04:13 — the\n * cadence is configurable via `scheduleExpr`. Cadence is also expressible\n * in milliseconds via `Config.graphEdgeDecayCadenceMs`; the orchestrator\n * picks the right cron expression for sub-daily, daily, or weekly cadence.\n */\nexport async function ensureGraphEdgeDecayCron(\n jobsPath: string,\n options: {\n timezone: string;\n agentId?: string;\n scheduleExpr?: string;\n },\n): Promise<{ created: boolean; jobId: string }> {\n const scheduleExpr =\n typeof options.scheduleExpr === \"string\" && options.scheduleExpr.trim().length > 0\n ? options.scheduleExpr.trim()\n : \"13 4 * * 0\";\n const agentId =\n typeof options.agentId === \"string\" && options.agentId.trim().length > 0\n ? options.agentId.trim()\n : \"main\";\n\n const scheduleLabel = graphEdgeDecayScheduleLabel(scheduleExpr);\n\n return ensureCronJob(\n jobsPath,\n GRAPH_EDGE_DECAY_CRON_ID,\n () => ({\n id: GRAPH_EDGE_DECAY_CRON_ID,\n agentId,\n // Schedule label reflects the actual cron expression (`daily` /\n // `weekly` / `custom`) so cron dashboards do not show \"weekly\"\n // when the schedule is in fact daily — Cursor review on PR #729.\n name: `Remnic Graph Edge Decay (${scheduleLabel})`,\n enabled: true,\n schedule: {\n kind: \"cron\",\n expr: scheduleExpr,\n tz: options.timezone,\n },\n sessionTarget: \"isolated\",\n wakeMode: \"now\",\n payload: {\n kind: \"agentTurn\",\n timeoutSeconds: 900,\n thinking: \"off\",\n message:\n \"You are OpenClaw automation. Call tool `engram.graph_edge_decay_run` with empty params. \" +\n \"If successful output exactly NO_REPLY. On error output one concise line. Do NOT use message tool.\",\n },\n delivery: { mode: \"none\" },\n }),\n {\n updateExisting: true,\n updateFields: [\"name\", \"schedule\"],\n },\n );\n}\n\n/**\n * Pick a cron expression that approximates a cadence in milliseconds.\n *\n * - cadence <= 1 day → daily at 04:13. Sub-daily cadence is not natively\n * expressible in 5-field cron without hour/minute step patterns; daily\n * preserves the previous conservative behavior for those values.\n * - cadence > 1 day → weekly on Sunday 04:13. Multi-day intervals like\n * 2-6 days cannot be represented accurately by a portable 5-field cron\n * expression, and daily would run more often than requested.\n *\n * Operators who need finer-grained control should set `scheduleExpr`\n * directly via `ensureGraphEdgeDecayCron`.\n */\nexport function graphEdgeDecayCadenceToCronExpr(cadenceMs: number): string {\n if (!Number.isFinite(cadenceMs) || cadenceMs <= 0) {\n return \"13 4 * * 0\";\n }\n const day = 24 * 60 * 60 * 1000;\n if (cadenceMs <= day) return \"13 4 * * *\";\n return \"13 4 * * 0\";\n}\n\n/**\n * Derive a human-friendly schedule label (\"daily\" / \"weekly\" / \"custom\")\n * for the given cron expression. Used to keep the cron job name in\n * sync with the actual schedule (Cursor review on PR #729).\n */\nfunction graphEdgeDecayScheduleLabel(scheduleExpr: string): string {\n if (scheduleExpr === \"13 4 * * *\") return \"daily\";\n if (scheduleExpr === \"13 4 * * 0\") return \"weekly\";\n return \"custom\";\n}\n"],"mappings":"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","names":["output"]}
|
|
@@ -6,7 +6,7 @@ import {
|
|
|
6
6
|
} from "./chunk-SFQ6QNL7.js";
|
|
7
7
|
import {
|
|
8
8
|
StorageManager
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-SHHT4JTC.js";
|
|
10
10
|
import {
|
|
11
11
|
buildLifecycleEventsForMemory,
|
|
12
12
|
sortMemoryLifecycleEvents
|
|
@@ -74,4 +74,4 @@ export {
|
|
|
74
74
|
backupExistingLedger,
|
|
75
75
|
rebuildMemoryLifecycleLedger
|
|
76
76
|
};
|
|
77
|
-
//# sourceMappingURL=chunk-
|
|
77
|
+
//# sourceMappingURL=chunk-7OH7KPF5.js.map
|
|
@@ -9,6 +9,11 @@ import {
|
|
|
9
9
|
import {
|
|
10
10
|
LocalLlmClient
|
|
11
11
|
} from "./chunk-77NAFXUD.js";
|
|
12
|
+
import {
|
|
13
|
+
FallbackLlmClient,
|
|
14
|
+
fallbackLlmRuntimeContextFromConfig,
|
|
15
|
+
gatewayTaskChainOptions
|
|
16
|
+
} from "./chunk-A3BS64GV.js";
|
|
12
17
|
import {
|
|
13
18
|
encodeStoragePathSegment,
|
|
14
19
|
encodeStoragePathSegmentWithHash,
|
|
@@ -16,11 +21,6 @@ import {
|
|
|
16
21
|
resolveSafeStoragePath,
|
|
17
22
|
storagePathHash
|
|
18
23
|
} from "./chunk-FF4KLI5W.js";
|
|
19
|
-
import {
|
|
20
|
-
FallbackLlmClient,
|
|
21
|
-
fallbackLlmRuntimeContextFromConfig,
|
|
22
|
-
gatewayTaskChainOptions
|
|
23
|
-
} from "./chunk-723OMPUI.js";
|
|
24
24
|
import {
|
|
25
25
|
extractJsonCandidates
|
|
26
26
|
} from "./chunk-RGMVMVMF.js";
|
|
@@ -709,4 +709,4 @@ ${truncatedConversation}`;
|
|
|
709
709
|
export {
|
|
710
710
|
HourlySummarizer
|
|
711
711
|
};
|
|
712
|
-
//# sourceMappingURL=chunk-
|
|
712
|
+
//# sourceMappingURL=chunk-7R37SOT4.js.map
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
} from "./chunk-3UXOZBHV.js";
|
|
8
8
|
import {
|
|
9
9
|
StorageManager
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-SHHT4JTC.js";
|
|
11
11
|
import {
|
|
12
12
|
isSafeRouteNamespace
|
|
13
13
|
} from "./chunk-U3PN77QT.js";
|
|
@@ -118,4 +118,4 @@ export {
|
|
|
118
118
|
runCodexMaterialize,
|
|
119
119
|
runPostConsolidationMaterialize
|
|
120
120
|
};
|
|
121
|
-
//# sourceMappingURL=chunk-
|
|
121
|
+
//# sourceMappingURL=chunk-7XRSLMUD.js.map
|
|
@@ -55,6 +55,12 @@ var BUILT_IN_PROVIDER_FALLBACKS = {
|
|
|
55
55
|
api: "anthropic-messages",
|
|
56
56
|
models: [],
|
|
57
57
|
[PROVIDER_API_KEY_FIELD]: MANAGED_SECRETREF_MARKER
|
|
58
|
+
},
|
|
59
|
+
openai: {
|
|
60
|
+
baseUrl: "https://api.openai.com/v1",
|
|
61
|
+
api: "openai-responses",
|
|
62
|
+
models: [],
|
|
63
|
+
[PROVIDER_API_KEY_FIELD]: MANAGED_SECRETREF_MARKER
|
|
58
64
|
}
|
|
59
65
|
};
|
|
60
66
|
var FallbackLlmClient = class {
|
|
@@ -692,4 +698,4 @@ export {
|
|
|
692
698
|
fallbackLlmRuntimeContextFromConfig,
|
|
693
699
|
FallbackLlmClient
|
|
694
700
|
};
|
|
695
|
-
//# sourceMappingURL=chunk-
|
|
701
|
+
//# sourceMappingURL=chunk-A3BS64GV.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/fallback-llm.ts"],"sourcesContent":["import { log } from \"./logger.js\";\nimport path from \"node:path\";\nimport type { AgentPersonaModelConfig, GatewayConfig, ModelProviderConfig, PluginConfig } from \"./types.js\";\nimport { extractJsonCandidates } from \"./json-extract.js\";\nimport {\n buildChatCompletionTemperature,\n buildChatCompletionTokenLimit,\n shouldAssumeOpenAiChatCompletions,\n} from \"./openai-chat-compat.js\";\nimport {\n resolveProviderApiKey,\n getGatewayRuntimeAuthForModel,\n type GetRuntimeAuthForModelFn,\n type ResolveApiKeyFn,\n} from \"./resolve-provider-secret.js\";\nimport { loadModelsJsonProviders } from \"./models-json.js\";\nimport { callCodexCliFallback } from \"./codex-cli-fallback.js\";\nimport { resolveHomeDir } from \"./runtime/env.js\";\nimport { expandTildePath } from \"./utils/path.js\";\n\nexport interface FallbackLlmOptions {\n temperature?: number;\n maxTokens?: number;\n timeoutMs?: number;\n signal?: AbortSignal;\n /** Explicit \"provider/model\" override to try before the configured chain. */\n model?: string;\n /** Explicit model chain override to use instead of the configured agent/default chain. */\n modelChain?: AgentPersonaModelConfig;\n /** Override which agent persona's model chain to use (by ID from agents.list[]). */\n agentId?: string;\n}\n\nexport interface FallbackLlmAvailabilityOptions {\n agentId?: string;\n modelChain?: AgentPersonaModelConfig;\n}\n\n/**\n * Resolve the gateway routing options Remnic's background tasks should pass to\n * FallbackLlmClient — extraction, fact/profile/identity consolidation,\n * summarization, calibration, and causal/semantic consolidation. Single source\n * of truth so every task path stays consistent and can't diverge (gotcha #22):\n * in gateway mode an explicit `taskModelChain` wins over the gateway agent\n * persona; otherwise the persona (if any) is used. Returns `{}` in plugin mode\n * because the chain resolves through gateway providers only. Issue #1365.\n */\nexport function gatewayTaskChainOptions(\n config: Pick<PluginConfig, \"modelSource\" | \"taskModelChain\" | \"gatewayAgentId\">,\n): Pick<FallbackLlmOptions, \"modelChain\" | \"agentId\"> {\n if (config.modelSource !== \"gateway\") return {};\n if (config.taskModelChain) return { modelChain: config.taskModelChain };\n return config.gatewayAgentId ? { agentId: config.gatewayAgentId } : {};\n}\n\nexport interface FallbackLlmResponse {\n content: string;\n modelUsed: string;\n usage?: {\n inputTokens?: number;\n outputTokens?: number;\n totalTokens?: number;\n };\n}\n\nexport interface FallbackLlmRuntimeContext {\n agentDir?: string;\n getRuntimeAuthForModel?: GetRuntimeAuthForModelFn | null;\n resolveApiKeyForProvider?: ResolveApiKeyFn | null;\n workspaceDir?: string;\n}\n\nexport function fallbackLlmRuntimeContextFromConfig(\n config: Pick<\n GatewayBackedRuntimeConfig,\n \"providerApiKeyResolver\" | \"runtimeAuthForModelResolver\" | \"workspaceDir\"\n >,\n overrides: FallbackLlmRuntimeContext = {},\n): FallbackLlmRuntimeContext {\n return {\n workspaceDir: config.workspaceDir,\n resolveApiKeyForProvider: config.providerApiKeyResolver,\n getRuntimeAuthForModel: config.runtimeAuthForModelResolver,\n ...overrides,\n };\n}\n\ntype GatewayBackedRuntimeConfig = {\n providerApiKeyResolver?: ResolveApiKeyFn | null;\n runtimeAuthForModelResolver?: GetRuntimeAuthForModelFn | null;\n workspaceDir?: string;\n};\n\ninterface ModelRef {\n providerId: string;\n modelId: string;\n providerConfig: ModelProviderConfig;\n modelString: string;\n}\n\nconst PROVIDER_ALIASES: Record<string, readonly string[]> = {\n \"openai-codex\": [\"codex\"],\n codex: [\"openai-codex\"],\n \"claude-cli\": [\"anthropic\"],\n};\n\nconst LEGACY_PROVIDER_IDS = new Set([\"openai-codex\", \"claude-cli\"]);\n\nconst MANAGED_SECRETREF_MARKER = [\"secretref\", \"managed\"].join(\"-\");\nconst PROVIDER_API_KEY_FIELD = [\"api\", \"Key\"].join(\"\") as keyof ModelProviderConfig;\n\n/**\n * Built-in provider fallbacks for providers that are commonly configured via\n * OAuth or gateway-managed auth rather than an explicit apiKey in\n * openclaw.json. These entries let resolveProviderConfig() succeed so the\n * chain proceeds to tryModel() → resolveRuntimeAuth(), which is where the\n * gateway's native OAuth token exchange happens.\n *\n * Without these, OAuth-only providers like `openai` are rejected with\n * \"provider not found\" before runtime auth is ever attempted.\n */\nconst BUILT_IN_PROVIDER_FALLBACKS: Record<string, ModelProviderConfig> = {\n anthropic: {\n baseUrl: \"https://api.anthropic.com/v1\",\n api: \"anthropic-messages\",\n models: [],\n [PROVIDER_API_KEY_FIELD]: MANAGED_SECRETREF_MARKER,\n },\n openai: {\n baseUrl: \"https://api.openai.com/v1\",\n api: \"openai-responses\",\n models: [],\n [PROVIDER_API_KEY_FIELD]: MANAGED_SECRETREF_MARKER,\n },\n};\n\n/**\n * Generic fallback LLM client that uses the gateway's default AI configuration\n * and walks through the full fallback chain (primary + fallbacks).\n * Supports OpenAI and Anthropic API formats.\n */\nexport class FallbackLlmClient {\n private gatewayConfig: GatewayConfig | undefined;\n private runtimeContext: FallbackLlmRuntimeContext;\n\n constructor(\n gatewayConfig?: GatewayConfig,\n runtimeContext: FallbackLlmRuntimeContext = {},\n ) {\n this.gatewayConfig = gatewayConfig;\n this.runtimeContext = {\n ...runtimeContext,\n workspaceDir:\n normalizeRuntimePath(runtimeContext.workspaceDir) ??\n readGatewayWorkspaceDir(gatewayConfig) ??\n defaultOpenClawWorkspaceDir(),\n };\n }\n\n /**\n * Check if fallback is available (gateway config has at least one model).\n */\n isAvailable(agentIdOrOptions?: string | FallbackLlmAvailabilityOptions): boolean {\n const options = typeof agentIdOrOptions === \"string\"\n ? { agentId: agentIdOrOptions }\n : (agentIdOrOptions ?? {});\n const models = this.getModelChain(options.agentId, undefined, options.modelChain);\n return models.length > 0;\n }\n\n /**\n * Make a chat completion request using the gateway's default AI chain.\n * Tries primary first, then each fallback in order.\n * When agentId is provided, uses that agent persona's model chain instead of defaults.\n */\n async chatCompletion(\n messages: Array<{ role: \"system\" | \"user\" | \"assistant\"; content: string }>,\n options: FallbackLlmOptions = {},\n ): Promise<FallbackLlmResponse | null> {\n const models = this.getModelChain(options.agentId, options.model, options.modelChain);\n if (models.length === 0) {\n log.warn(\"fallback LLM: no models configured in gateway\");\n return null;\n }\n\n const runChain = async (\n runOptions: FallbackLlmOptions,\n ): Promise<FallbackLlmResponse | null> => {\n // Try each model in the chain\n for (let i = 0; i < models.length; i++) {\n if (runOptions.signal?.aborted) {\n throw abortReason(runOptions.signal);\n }\n const model = models[i];\n const isFallback = i > 0;\n\n try {\n const result = await this.tryModel(model, messages, runOptions);\n if (result) {\n if (isFallback) {\n log.debug(`fallback LLM: succeeded using ${model.modelString} (fallback ${i})`);\n }\n return {\n content: result.content,\n modelUsed: model.modelString,\n usage: result.usage,\n };\n }\n } catch (err) {\n if (runOptions.signal?.aborted) {\n throw abortReason(runOptions.signal);\n }\n const errorMsg = err instanceof Error ? err.message : String(err);\n log.debug(`fallback LLM: ${model.modelString} failed (${errorMsg}), trying next...`);\n // Continue to next model in chain\n }\n }\n\n log.warn(`fallback LLM: all ${models.length} models in chain failed`);\n return null;\n };\n\n if (typeof options.timeoutMs === \"number\") {\n if (options.timeoutMs <= 0) {\n log.warn(\"fallback LLM: timed out before request started\");\n return null;\n }\n let timeoutHandle: ReturnType<typeof setTimeout> | undefined;\n const controller = new AbortController();\n const onCallerAbort = (): void => {\n controller.abort(abortReason(options.signal));\n };\n options.signal?.addEventListener(\"abort\", onCallerAbort, { once: true });\n if (options.signal?.aborted) {\n onCallerAbort();\n }\n const timedOptions = { ...options, signal: controller.signal };\n const chain = runChain(timedOptions);\n chain.catch(() => {});\n try {\n return await Promise.race([\n chain,\n new Promise<null>((resolve) => {\n timeoutHandle = setTimeout(() => {\n log.warn(`fallback LLM: timed out after ${options.timeoutMs}ms`);\n controller.abort(\n new Error(`fallback LLM timed out after ${options.timeoutMs}ms`),\n );\n resolve(null);\n }, options.timeoutMs);\n }),\n ]);\n } finally {\n if (timeoutHandle) clearTimeout(timeoutHandle);\n options.signal?.removeEventListener(\"abort\", onCallerAbort);\n }\n }\n\n return await runChain(options);\n }\n\n /**\n * Make a request with structured output (Zod schema).\n * Returns parsed JSON or null on failure.\n */\n async parseWithSchema<T>(\n messages: Array<{ role: \"system\" | \"user\" | \"assistant\"; content: string }>,\n schema: { parse: (data: unknown) => T },\n options: FallbackLlmOptions = {},\n ): Promise<T | null> {\n const detailed = await this.parseWithSchemaDetailed(messages, schema, options);\n return detailed?.result ?? null;\n }\n\n /**\n * Like parseWithSchema but also returns the model that was used,\n * so callers can emit accurate trace events.\n */\n async parseWithSchemaDetailed<T>(\n messages: Array<{ role: \"system\" | \"user\" | \"assistant\"; content: string }>,\n schema: { parse: (data: unknown) => T },\n options: FallbackLlmOptions = {},\n ): Promise<{ result: T; modelUsed: string } | null> {\n const response = await this.chatCompletion(messages, options);\n if (!response?.content) return null;\n\n try {\n const candidates = extractJsonCandidates(response.content);\n for (const c of candidates) {\n try {\n const parsed = JSON.parse(c);\n return { result: schema.parse(parsed), modelUsed: response.modelUsed };\n } catch {\n // keep trying other candidates\n }\n }\n return null;\n } catch (err) {\n log.warn(\"fallback LLM: failed to parse structured output:\", err);\n return null;\n }\n }\n\n /**\n * Get the full model chain from gateway config.\n * Returns array of models in order: [primary, fallback1, fallback2, ...]\n *\n * When modelChainOverride is provided, uses it instead of any configured\n * agent/default chain. Otherwise, when agentId is provided, looks up the\n * matching entry in agents.list[] and uses that persona's model chain.\n * Falls back to agents.defaults.model if agentId is not found or not provided.\n */\n private getModelChain(\n agentId?: string,\n modelOverride?: string,\n modelChainOverride?: AgentPersonaModelConfig,\n ): ModelRef[] {\n const chain: ModelRef[] = [];\n const providers = this.gatewayConfig?.models?.providers ?? {};\n\n // Resolve the model config: explicit task chain, agent persona chain, or global defaults\n let modelConfig: AgentPersonaModelConfig | undefined;\n\n if (modelChainOverride?.primary) {\n modelConfig = modelChainOverride;\n log.debug(\"fallback LLM: using explicit model chain override\");\n } else if (modelChainOverride) {\n log.warn(\"fallback LLM: ignoring explicit model chain override without primary model\");\n }\n\n if (!modelConfig && agentId) {\n const persona = this.gatewayConfig?.agents?.list?.find(\n (a) => a.id === agentId,\n );\n if (persona?.model) {\n modelConfig = persona.model;\n log.debug(`fallback LLM: using agent persona \"${agentId}\" model chain`);\n } else {\n log.warn(\n `fallback LLM: agent persona \"${agentId}\" not found or has no model config, falling back to defaults`,\n );\n }\n }\n\n if (!modelConfig) {\n modelConfig = this.gatewayConfig?.agents?.defaults?.model;\n }\n\n // Build list of model strings: primary + fallbacks\n const modelStrings: string[] = [];\n\n const addModelString = (value: unknown): void => {\n if (typeof value !== \"string\") return;\n const trimmed = value.trim();\n if (trimmed.length > 0 && !modelStrings.includes(trimmed)) {\n modelStrings.push(trimmed);\n }\n };\n\n addModelString(modelOverride);\n addModelString(modelConfig?.primary);\n\n if (Array.isArray(modelConfig?.fallbacks)) {\n for (const fb of modelConfig.fallbacks) {\n addModelString(fb);\n }\n }\n\n // Parse each model string and look up provider config\n for (const modelString of modelStrings) {\n const modelRef = this.parseModelString(modelString, providers);\n if (modelRef) {\n chain.push(modelRef);\n }\n }\n\n // Implicit last-resort: when a task-specific modelChain override is active,\n // append the gateway default model so a stale or exhausted taskModelChain\n // never leaves the chain empty — Remnic should never be the reason a chat is\n // interrupted by a flush failure. Keyed on `modelChainOverride?.primary` —\n // the SAME activation condition chain resolution uses above — so a\n // primary-less override (e.g. {}) that falls through to a persona/default\n // chain does NOT get the default appended (gotcha #39). Issue #1365 / PR #1370.\n if (modelChainOverride?.primary && modelStrings.length > 0) {\n // Append the FULL gateway default chain (primary + fallbacks), not just\n // the primary — if the default primary is also unreachable, a listed\n // default fallback may still succeed (cursor review #1425).\n const defaults = this.gatewayConfig?.agents?.defaults?.model;\n const defaultStrings: string[] = [\n ...(typeof defaults?.primary === \"string\" ? [defaults.primary] : []),\n ...(Array.isArray(defaults?.fallbacks) ? defaults.fallbacks : []),\n ];\n for (const candidate of defaultStrings) {\n if (typeof candidate !== \"string\") continue;\n const trimmed = candidate.trim();\n if (trimmed.length === 0 || modelStrings.includes(trimmed)) continue;\n const defaultRef = this.parseModelString(trimmed, providers);\n if (defaultRef) {\n chain.push(defaultRef);\n modelStrings.push(trimmed); // keep dedupe correct for later default fallbacks\n log.debug(\n `fallback LLM: appended gateway default model \"${trimmed}\" as implicit last resort`,\n );\n }\n }\n }\n\n return chain;\n }\n\n /**\n * Parse a \"provider/model\" string and look up its config.\n */\n private parseModelString(\n modelString: string,\n providers: Record<string, ModelProviderConfig>,\n ): ModelRef | null {\n // Parse \"provider/model\" format (e.g., \"openai/gpt-5.5\", \"anthropic/claude-opus-4-6\")\n const parts = modelString.split(\"/\");\n if (parts.length < 2) {\n log.warn(`fallback LLM: invalid model format: ${modelString}`);\n return null;\n }\n\n const requestedProviderId = parts[0];\n const modelId = parts.slice(1).join(\"/\"); // Handle cases like \"openai/gpt-5.5\"\n\n // Respect the active gateway config first so profile-local overrides and\n // credentials win. Fall back to the materialized models.json only when\n // the provider is absent from the loaded config (for built-in providers\n // registered by the gateway at runtime).\n const resolvedProvider = this.resolveProviderConfig(requestedProviderId, providers);\n const providerConfig = resolvedProvider?.config;\n if (!providerConfig) {\n log.warn(\n `fallback LLM: provider not found: ${requestedProviderId} ` +\n `(tried: ${this.providerResolutionCandidates(requestedProviderId).join(\", \")})`,\n );\n return null;\n }\n\n return {\n providerId: resolvedProvider.providerId,\n modelId,\n providerConfig,\n modelString,\n };\n }\n\n private resolveProviderConfig(\n providerId: string,\n providers: Record<string, ModelProviderConfig>,\n ): { providerId: string; config: ModelProviderConfig } | null {\n const candidates = this.providerResolutionCandidates(providerId);\n const aliasCandidates = candidates.filter((candidate) => candidate !== providerId);\n const fallbackCandidates = LEGACY_PROVIDER_IDS.has(providerId)\n ? [...aliasCandidates, providerId]\n : [providerId, ...aliasCandidates];\n for (const candidate of candidates) {\n const config = providers[candidate];\n if (config) {\n if (candidate !== providerId) {\n log.debug(`fallback LLM: provider \"${providerId}\" resolved via alias \"${candidate}\"`);\n }\n return { providerId: candidate, config };\n }\n }\n for (const candidate of fallbackCandidates) {\n const config = this.resolveFromModelsJson(candidate);\n if (config) {\n if (candidate !== providerId) {\n log.debug(`fallback LLM: provider \"${providerId}\" resolved via models.json alias \"${candidate}\"`);\n }\n return { providerId: candidate, config };\n }\n const builtInConfig = BUILT_IN_PROVIDER_FALLBACKS[candidate];\n if (builtInConfig) {\n if (candidate === providerId) {\n log.debug(`fallback LLM: provider \"${providerId}\" resolved from built-in defaults`);\n return { providerId, config: builtInConfig };\n }\n log.debug(`fallback LLM: provider \"${providerId}\" resolved via built-in alias \"${candidate}\"`);\n return { providerId: candidate, config: builtInConfig };\n }\n }\n return null;\n }\n\n private providerResolutionCandidates(providerId: string): string[] {\n const candidates = [providerId, ...(PROVIDER_ALIASES[providerId] ?? [])];\n return [...new Set(candidates)];\n }\n\n /**\n * Look up a provider from the gateway's materialized models.json, which\n * contains all providers including built-in ones (openai-codex, google-vertex,\n * etc.) that aren't in the user's openclaw.json but are registered by\n * gateway plugins. Returns null if the provider isn't found there either.\n */\n private resolveFromModelsJson(providerId: string): ModelProviderConfig | null {\n const allProviders = loadModelsJsonProviders();\n const config = allProviders[providerId];\n if (config) {\n log.debug(`fallback LLM: resolved provider \"${providerId}\" from models.json (api: ${config.api ?? \"default\"})`);\n return config;\n }\n return null;\n }\n\n /**\n * Try to call a single model.\n *\n * Uses the gateway's native getRuntimeAuthForModel when available — this\n * handles all provider-specific auth transforms (OAuth token exchange,\n * base URL overrides for codex/copilot/etc.) through the same codepath\n * the gateway itself uses. Falls back to resolveProviderApiKey for\n * simpler providers or when the runtime module isn't loaded.\n */\n private async tryModel(\n model: ModelRef,\n messages: Array<{ role: \"system\" | \"user\" | \"assistant\"; content: string }>,\n options: FallbackLlmOptions,\n ): Promise<{ content: string; usage?: FallbackLlmResponse[\"usage\"] } | null> {\n // Try the gateway's native runtime auth first — it handles all provider-\n // specific transforms (OAuth exchange, base URL rewrite, etc.)\n const runtimeAuth = model.providerConfig.api === \"codex-cli\"\n ? null\n : await this.resolveRuntimeAuth(model);\n const effectiveBaseUrl = runtimeAuth?.baseUrl ?? model.providerConfig.baseUrl;\n const resolvedApiKey = runtimeAuth?.apiKey\n ?? (\n model.providerConfig.api === \"codex-cli\" && model.providerConfig.apiKey === undefined\n ? undefined\n : await this.resolveFallbackApiKey(model)\n );\n\n // If the raw key looks like an unresolved secret ref and resolution fails,\n // skip this provider entirely so the chain falls through to the next.\n const rawKey = model.providerConfig.apiKey;\n const needsResolution = rawKey === \"secretref-managed\"\n || (typeof rawKey === \"object\" && rawKey !== null);\n if (needsResolution && !resolvedApiKey) {\n throw new Error(`API key for provider \"${model.providerId}\" could not be resolved from secret ref`);\n }\n\n const effectiveConfig: ModelProviderConfig = {\n ...model.providerConfig,\n baseUrl: effectiveBaseUrl,\n ...(resolvedApiKey ? { apiKey: resolvedApiKey } : {}),\n };\n\n if (model.providerConfig.api === \"anthropic-messages\") {\n return await this.callAnthropic(effectiveConfig, model.modelId, messages, options);\n }\n\n if (model.providerConfig.api === \"codex-cli\") {\n return await callCodexCliFallback(\n effectiveConfig,\n model.modelId,\n messages,\n { timeoutMs: options.timeoutMs, signal: options.signal },\n );\n }\n\n if (model.providerConfig.api === \"ollama-chat\") {\n return await this.callOllamaChat(effectiveConfig, model.modelId, messages, options);\n }\n\n if (\n model.providerConfig.api === \"openai-responses\" ||\n model.providerConfig.api === \"openai-codex-responses\" ||\n model.providerConfig.api === \"azure-openai-responses\"\n ) {\n return await this.callOpenAIResponses(\n effectiveConfig,\n model.modelId,\n messages,\n options,\n );\n }\n\n // For OpenAI-compatible chat-completions APIs (openai-completions,\n // ollama, etc.) and unknown formats, use chat completions — the gateway's\n // runtime auth resolver returns request-ready base URL and credentials for\n // most providers.\n return await this.callOpenAI(\n effectiveConfig,\n model.modelId,\n messages,\n options,\n shouldAssumeOpenAiChatCompletions(effectiveConfig.baseUrl),\n );\n }\n\n /**\n * Resolve request-ready auth through the gateway's native runtime, which\n * handles provider-specific transforms (OAuth token exchange for codex/copilot,\n * base URL rewrite, etc.). Returns null if the runtime isn't available.\n */\n private async resolveRuntimeAuth(\n model: ModelRef,\n ): Promise<{ apiKey?: string; baseUrl?: string } | null> {\n try {\n const getRuntimeAuth = await getGatewayRuntimeAuthForModel({\n getRuntimeAuthForModel: this.runtimeContext.getRuntimeAuthForModel,\n });\n if (!getRuntimeAuth) return null;\n\n const result = await getRuntimeAuth({\n model: {\n provider: model.providerId,\n id: model.modelId,\n api: model.providerConfig.api,\n baseUrl: model.providerConfig.baseUrl,\n },\n cfg: this.gatewayConfig,\n workspaceDir: this.runtimeContext.workspaceDir,\n });\n\n if (result?.apiKey || result?.baseUrl) {\n log.debug(\n `fallback LLM: resolved runtime auth for \"${model.modelString}\" (source: ${result.source ?? \"unknown\"}, mode: ${result.mode ?? \"unknown\"})`,\n );\n return { apiKey: result.apiKey, baseUrl: result.baseUrl };\n }\n } catch (err) {\n log.debug(\n `fallback LLM: gateway runtime auth failed for \"${model.modelString}\": ${err instanceof Error ? err.message : String(err)}`,\n );\n }\n return null;\n }\n\n /**\n * Resolve API key through the existing provider-level resolution (env vars,\n * secret refs, etc.). Used as fallback when gateway runtime auth isn't available.\n */\n private async resolveFallbackApiKey(model: ModelRef): Promise<string | undefined> {\n return resolveProviderApiKey(\n model.providerId,\n model.providerConfig.apiKey,\n this.gatewayConfig,\n this.runtimeContext.agentDir,\n {\n resolveApiKeyForProvider: this.runtimeContext.resolveApiKeyForProvider,\n },\n );\n }\n\n /**\n * Call OpenAI-compatible API.\n */\n private async callOpenAI(\n config: ModelProviderConfig,\n modelId: string,\n messages: Array<{ role: \"system\" | \"user\" | \"assistant\"; content: string }>,\n options: FallbackLlmOptions,\n assumeOpenAI: boolean,\n ): Promise<{ content: string; usage?: FallbackLlmResponse[\"usage\"] } | null> {\n const base = config.baseUrl.replace(/\\/$/, \"\");\n const url = base.endsWith(\"/v1\")\n ? `${base}/chat/completions`\n : `${base}/v1/chat/completions`;\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n ...config.headers,\n };\n\n // Handle auth — apiKey is already resolved to a string by tryModel()\n if (config.apiKey && typeof config.apiKey === \"string\") {\n if (config.authHeader !== false) {\n headers[\"Authorization\"] = `Bearer ${config.apiKey}`;\n }\n }\n\n const body = {\n model: modelId,\n messages,\n ...buildChatCompletionTemperature(modelId, options.temperature ?? 0.3, {\n assumeOpenAI,\n }),\n ...buildChatCompletionTokenLimit(modelId, options.maxTokens ?? 4096, {\n assumeOpenAI,\n }),\n };\n\n const response = await fetch(url, {\n method: \"POST\",\n headers,\n signal: options.signal,\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`OpenAI API error: ${response.status} ${error}`);\n }\n\n const data = (await response.json()) as {\n choices: Array<{\n message: {\n content: string;\n };\n }>;\n usage?: {\n prompt_tokens?: number;\n completion_tokens?: number;\n total_tokens?: number;\n };\n };\n\n const content = data.choices?.[0]?.message?.content;\n if (!content) {\n throw new Error(\"Empty response from OpenAI API\");\n }\n\n return {\n content,\n usage: data.usage\n ? {\n inputTokens: data.usage.prompt_tokens,\n outputTokens: data.usage.completion_tokens,\n totalTokens: data.usage.total_tokens,\n }\n : undefined,\n };\n }\n\n /**\n * Call Ollama's native /api/chat transport. This lets benchmark-isolated\n * gateway configs route Remnic's own internal LLM calls to Ollama Cloud\n * without requiring an OpenAI-compatible shim.\n */\n private async callOllamaChat(\n config: ModelProviderConfig,\n modelId: string,\n messages: Array<{ role: \"system\" | \"user\" | \"assistant\"; content: string }>,\n options: FallbackLlmOptions,\n ): Promise<{ content: string; usage?: FallbackLlmResponse[\"usage\"] } | null> {\n const base = config.baseUrl.replace(/\\/$/, \"\");\n const url = base.endsWith(\"/api\") ? `${base}/chat` : `${base}/api/chat`;\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n ...config.headers,\n };\n if (config.apiKey && typeof config.apiKey === \"string\" && config.authHeader !== false) {\n headers.Authorization = `Bearer ${config.apiKey}`;\n }\n\n const response = await fetch(url, {\n method: \"POST\",\n headers,\n signal: options.signal,\n body: JSON.stringify({\n model: modelId,\n messages,\n stream: false,\n ...(config.disableThinking ? { think: false } : {}),\n options: {\n temperature: options.temperature ?? 0.3,\n num_predict: options.maxTokens ?? 4096,\n },\n }),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Ollama API error: ${response.status} ${error}`);\n }\n\n const data = (await response.json()) as {\n message?: { content?: string };\n response?: string;\n prompt_eval_count?: number;\n eval_count?: number;\n };\n const content = data.message?.content ?? data.response;\n if (!content) {\n throw new Error(\"Empty response from Ollama API\");\n }\n\n const inputTokens = data.prompt_eval_count ?? 0;\n const outputTokens = data.eval_count ?? 0;\n return {\n content,\n usage: {\n inputTokens,\n outputTokens,\n totalTokens: inputTokens + outputTokens,\n },\n };\n }\n\n /**\n * Call an OpenAI-compatible Responses API.\n */\n private async callOpenAIResponses(\n config: ModelProviderConfig,\n modelId: string,\n messages: Array<{ role: \"system\" | \"user\" | \"assistant\"; content: string }>,\n options: FallbackLlmOptions,\n ): Promise<{ content: string; usage?: FallbackLlmResponse[\"usage\"] } | null> {\n const base = config.baseUrl.replace(/\\/$/, \"\");\n const url = base.endsWith(\"/v1\")\n ? `${base}/responses`\n : `${base}/v1/responses`;\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n ...config.headers,\n };\n\n if (config.apiKey && typeof config.apiKey === \"string\" && config.authHeader !== false) {\n headers[\"Authorization\"] = `Bearer ${config.apiKey}`;\n }\n\n const instructions = messages\n .filter((message) => message.role === \"system\")\n .map((message) => message.content)\n .join(\"\\n\\n\")\n .trim();\n const input = messages\n .filter((message) => message.role !== \"system\")\n .map((message) => ({\n role: message.role,\n content: [{\n type: message.role === \"assistant\" ? \"output_text\" : \"input_text\",\n text: message.content,\n }],\n }));\n\n const body: Record<string, unknown> = {\n model: modelId,\n input,\n max_output_tokens: Math.max(0, Math.floor(options.maxTokens ?? 4096)),\n ...buildChatCompletionTemperature(modelId, options.temperature ?? 0.3, {\n assumeOpenAI: shouldAssumeOpenAiChatCompletions(config.baseUrl),\n }),\n };\n if (instructions.length > 0) {\n body.instructions = instructions;\n }\n\n const response = await fetch(url, {\n method: \"POST\",\n headers,\n signal: options.signal,\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`OpenAI Responses API error: ${response.status} ${error}`);\n }\n\n const data = (await response.json()) as {\n output_text?: string;\n output?: Array<{\n type?: string;\n text?: string;\n content?: Array<{\n type?: string;\n text?: string;\n }>;\n }>;\n usage?: {\n input_tokens?: number;\n output_tokens?: number;\n total_tokens?: number;\n };\n };\n\n const outputText = extractResponsesOutputText(data);\n if (!outputText) {\n throw new Error(\"Empty response from OpenAI Responses API\");\n }\n\n return {\n content: outputText,\n usage: data.usage\n ? {\n inputTokens: data.usage.input_tokens,\n outputTokens: data.usage.output_tokens,\n totalTokens: data.usage.total_tokens,\n }\n : undefined,\n };\n }\n\n /**\n * Call Anthropic Messages API.\n */\n private async callAnthropic(\n config: ModelProviderConfig,\n modelId: string,\n messages: Array<{ role: \"system\" | \"user\" | \"assistant\"; content: string }>,\n options: FallbackLlmOptions,\n ): Promise<{ content: string; usage?: FallbackLlmResponse[\"usage\"] } | null> {\n const base = config.baseUrl.replace(/\\/$/, \"\");\n const url = base.endsWith(\"/v1\")\n ? `${base}/messages`\n : `${base}/v1/messages`;\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"anthropic-version\": \"2023-06-01\",\n ...config.headers,\n };\n\n // Handle auth - Anthropic uses x-api-key header (apiKey resolved by tryModel)\n if (config.apiKey && typeof config.apiKey === \"string\") {\n headers[\"x-api-key\"] = config.apiKey;\n }\n\n // Extract system message (Anthropic handles it separately)\n const systemMessage = messages.find((m) => m.role === \"system\")?.content;\n const nonSystemMessages = messages.filter((m) => m.role !== \"system\");\n\n // Convert messages to Anthropic format\n const anthropicMessages = nonSystemMessages.map((m) => ({\n role: m.role,\n content: m.content,\n }));\n\n const body: Record<string, unknown> = {\n model: modelId,\n messages: anthropicMessages,\n max_tokens: options.maxTokens ?? 4096,\n temperature: options.temperature ?? 0.3,\n };\n\n if (systemMessage) {\n body.system = systemMessage;\n }\n\n const response = await fetch(url, {\n method: \"POST\",\n headers,\n signal: options.signal,\n body: JSON.stringify(body),\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`Anthropic API error: ${response.status} ${error}`);\n }\n\n const data = (await response.json()) as {\n content: Array<{\n type: string;\n text: string;\n }>;\n usage?: {\n input_tokens?: number;\n output_tokens?: number;\n };\n };\n\n const content = data.content?.[0]?.text;\n if (!content) {\n throw new Error(\"Empty response from Anthropic API\");\n }\n\n return {\n content,\n usage: data.usage\n ? {\n inputTokens: data.usage.input_tokens,\n outputTokens: data.usage.output_tokens,\n totalTokens: (data.usage.input_tokens ?? 0) + (data.usage.output_tokens ?? 0),\n }\n : undefined,\n };\n }\n}\n\nfunction abortReason(signal: AbortSignal | undefined): Error {\n const reason = signal?.reason;\n return reason instanceof Error ? reason : new Error(\"fallback LLM request aborted\");\n}\n\nfunction normalizeRuntimePath(value: unknown): string | undefined {\n if (typeof value !== \"string\") return undefined;\n const trimmed = value.trim();\n return trimmed.length > 0 ? expandTildePath(trimmed) : undefined;\n}\n\nfunction readGatewayWorkspaceDir(gatewayConfig: GatewayConfig | undefined): string | undefined {\n if (!gatewayConfig || typeof gatewayConfig !== \"object\") return undefined;\n const raw = gatewayConfig as Record<string, unknown>;\n return (\n normalizeRuntimePath(raw.workspaceDir) ??\n normalizeRuntimePath(raw.workspacePath) ??\n normalizeRuntimePath(raw.workspace)\n );\n}\n\nfunction defaultOpenClawWorkspaceDir(): string {\n return path.join(resolveHomeDir(), \".openclaw\", \"workspace\");\n}\n\nfunction extractResponsesOutputText(data: {\n output_text?: string;\n output?: Array<{\n type?: string;\n text?: string;\n content?: Array<{\n type?: string;\n text?: string;\n }>;\n }>;\n}): string | null {\n if (typeof data.output_text === \"string\" && data.output_text.trim().length > 0) {\n return data.output_text;\n }\n\n const chunks: string[] = [];\n for (const item of data.output ?? []) {\n if (typeof item.text === \"string\" && item.text.trim().length > 0) {\n chunks.push(item.text);\n }\n for (const part of item.content ?? []) {\n if (\n (part.type === \"output_text\" || part.type === \"text\") &&\n typeof part.text === \"string\" &&\n part.text.trim().length > 0\n ) {\n chunks.push(part.text);\n }\n }\n }\n\n const joined = chunks.join(\"\\n\").trim();\n return joined.length > 0 ? joined : null;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AACA,OAAO,UAAU;AA8CV,SAAS,wBACd,QACoD;AACpD,MAAI,OAAO,gBAAgB,UAAW,QAAO,CAAC;AAC9C,MAAI,OAAO,eAAgB,QAAO,EAAE,YAAY,OAAO,eAAe;AACtE,SAAO,OAAO,iBAAiB,EAAE,SAAS,OAAO,eAAe,IAAI,CAAC;AACvE;AAmBO,SAAS,oCACd,QAIA,YAAuC,CAAC,GACb;AAC3B,SAAO;AAAA,IACL,cAAc,OAAO;AAAA,IACrB,0BAA0B,OAAO;AAAA,IACjC,wBAAwB,OAAO;AAAA,IAC/B,GAAG;AAAA,EACL;AACF;AAeA,IAAM,mBAAsD;AAAA,EAC1D,gBAAgB,CAAC,OAAO;AAAA,EACxB,OAAO,CAAC,cAAc;AAAA,EACtB,cAAc,CAAC,WAAW;AAC5B;AAEA,IAAM,sBAAsB,oBAAI,IAAI,CAAC,gBAAgB,YAAY,CAAC;AAElE,IAAM,2BAA2B,CAAC,aAAa,SAAS,EAAE,KAAK,GAAG;AAClE,IAAM,yBAAyB,CAAC,OAAO,KAAK,EAAE,KAAK,EAAE;AAYrD,IAAM,8BAAmE;AAAA,EACvE,WAAW;AAAA,IACT,SAAS;AAAA,IACT,KAAK;AAAA,IACL,QAAQ,CAAC;AAAA,IACT,CAAC,sBAAsB,GAAG;AAAA,EAC5B;AAAA,EACA,QAAQ;AAAA,IACN,SAAS;AAAA,IACT,KAAK;AAAA,IACL,QAAQ,CAAC;AAAA,IACT,CAAC,sBAAsB,GAAG;AAAA,EAC5B;AACF;AAOO,IAAM,oBAAN,MAAwB;AAAA,EACrB;AAAA,EACA;AAAA,EAER,YACE,eACA,iBAA4C,CAAC,GAC7C;AACA,SAAK,gBAAgB;AACrB,SAAK,iBAAiB;AAAA,MACpB,GAAG;AAAA,MACH,cACE,qBAAqB,eAAe,YAAY,KAChD,wBAAwB,aAAa,KACrC,4BAA4B;AAAA,IAChC;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,YAAY,kBAAqE;AAC/E,UAAM,UAAU,OAAO,qBAAqB,WACxC,EAAE,SAAS,iBAAiB,IAC3B,oBAAoB,CAAC;AAC1B,UAAM,SAAS,KAAK,cAAc,QAAQ,SAAS,QAAW,QAAQ,UAAU;AAChF,WAAO,OAAO,SAAS;AAAA,EACzB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,eACJ,UACA,UAA8B,CAAC,GACM;AACrC,UAAM,SAAS,KAAK,cAAc,QAAQ,SAAS,QAAQ,OAAO,QAAQ,UAAU;AACpF,QAAI,OAAO,WAAW,GAAG;AACvB,UAAI,KAAK,+CAA+C;AACxD,aAAO;AAAA,IACT;AAEA,UAAM,WAAW,OACf,eACwC;AAExC,eAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,YAAI,WAAW,QAAQ,SAAS;AAC9B,gBAAM,YAAY,WAAW,MAAM;AAAA,QACrC;AACA,cAAM,QAAQ,OAAO,CAAC;AACtB,cAAM,aAAa,IAAI;AAEvB,YAAI;AACF,gBAAM,SAAS,MAAM,KAAK,SAAS,OAAO,UAAU,UAAU;AAC9D,cAAI,QAAQ;AACV,gBAAI,YAAY;AACd,kBAAI,MAAM,iCAAiC,MAAM,WAAW,cAAc,CAAC,GAAG;AAAA,YAChF;AACA,mBAAO;AAAA,cACL,SAAS,OAAO;AAAA,cAChB,WAAW,MAAM;AAAA,cACjB,OAAO,OAAO;AAAA,YAChB;AAAA,UACF;AAAA,QACF,SAAS,KAAK;AACZ,cAAI,WAAW,QAAQ,SAAS;AAC9B,kBAAM,YAAY,WAAW,MAAM;AAAA,UACrC;AACA,gBAAM,WAAW,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAChE,cAAI,MAAM,iBAAiB,MAAM,WAAW,YAAY,QAAQ,mBAAmB;AAAA,QAErF;AAAA,MACF;AAEA,UAAI,KAAK,qBAAqB,OAAO,MAAM,yBAAyB;AACpE,aAAO;AAAA,IACT;AAEA,QAAI,OAAO,QAAQ,cAAc,UAAU;AACzC,UAAI,QAAQ,aAAa,GAAG;AAC1B,YAAI,KAAK,gDAAgD;AACzD,eAAO;AAAA,MACT;AACA,UAAI;AACJ,YAAM,aAAa,IAAI,gBAAgB;AACvC,YAAM,gBAAgB,MAAY;AAChC,mBAAW,MAAM,YAAY,QAAQ,MAAM,CAAC;AAAA,MAC9C;AACA,cAAQ,QAAQ,iBAAiB,SAAS,eAAe,EAAE,MAAM,KAAK,CAAC;AACvE,UAAI,QAAQ,QAAQ,SAAS;AAC3B,sBAAc;AAAA,MAChB;AACA,YAAM,eAAe,EAAE,GAAG,SAAS,QAAQ,WAAW,OAAO;AAC7D,YAAM,QAAQ,SAAS,YAAY;AACnC,YAAM,MAAM,MAAM;AAAA,MAAC,CAAC;AACpB,UAAI;AACF,eAAO,MAAM,QAAQ,KAAK;AAAA,UACxB;AAAA,UACA,IAAI,QAAc,CAAC,YAAY;AAC7B,4BAAgB,WAAW,MAAM;AAC/B,kBAAI,KAAK,iCAAiC,QAAQ,SAAS,IAAI;AAC/D,yBAAW;AAAA,gBACT,IAAI,MAAM,gCAAgC,QAAQ,SAAS,IAAI;AAAA,cACjE;AACA,sBAAQ,IAAI;AAAA,YACd,GAAG,QAAQ,SAAS;AAAA,UACtB,CAAC;AAAA,QACH,CAAC;AAAA,MACH,UAAE;AACA,YAAI,cAAe,cAAa,aAAa;AAC7C,gBAAQ,QAAQ,oBAAoB,SAAS,aAAa;AAAA,MAC5D;AAAA,IACF;AAEA,WAAO,MAAM,SAAS,OAAO;AAAA,EAC/B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,gBACJ,UACA,QACA,UAA8B,CAAC,GACZ;AACnB,UAAM,WAAW,MAAM,KAAK,wBAAwB,UAAU,QAAQ,OAAO;AAC7E,WAAO,UAAU,UAAU;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,wBACJ,UACA,QACA,UAA8B,CAAC,GACmB;AAClD,UAAM,WAAW,MAAM,KAAK,eAAe,UAAU,OAAO;AAC5D,QAAI,CAAC,UAAU,QAAS,QAAO;AAE/B,QAAI;AACF,YAAM,aAAa,sBAAsB,SAAS,OAAO;AACzD,iBAAW,KAAK,YAAY;AAC1B,YAAI;AACF,gBAAM,SAAS,KAAK,MAAM,CAAC;AAC3B,iBAAO,EAAE,QAAQ,OAAO,MAAM,MAAM,GAAG,WAAW,SAAS,UAAU;AAAA,QACvE,QAAQ;AAAA,QAER;AAAA,MACF;AACA,aAAO;AAAA,IACT,SAAS,KAAK;AACZ,UAAI,KAAK,oDAAoD,GAAG;AAChE,aAAO;AAAA,IACT;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWQ,cACN,SACA,eACA,oBACY;AACZ,UAAM,QAAoB,CAAC;AAC3B,UAAM,YAAY,KAAK,eAAe,QAAQ,aAAa,CAAC;AAG5D,QAAI;AAEJ,QAAI,oBAAoB,SAAS;AAC/B,oBAAc;AACd,UAAI,MAAM,mDAAmD;AAAA,IAC/D,WAAW,oBAAoB;AAC7B,UAAI,KAAK,4EAA4E;AAAA,IACvF;AAEA,QAAI,CAAC,eAAe,SAAS;AAC3B,YAAM,UAAU,KAAK,eAAe,QAAQ,MAAM;AAAA,QAChD,CAAC,MAAM,EAAE,OAAO;AAAA,MAClB;AACA,UAAI,SAAS,OAAO;AAClB,sBAAc,QAAQ;AACtB,YAAI,MAAM,sCAAsC,OAAO,eAAe;AAAA,MACxE,OAAO;AACL,YAAI;AAAA,UACF,gCAAgC,OAAO;AAAA,QACzC;AAAA,MACF;AAAA,IACF;AAEA,QAAI,CAAC,aAAa;AAChB,oBAAc,KAAK,eAAe,QAAQ,UAAU;AAAA,IACtD;AAGA,UAAM,eAAyB,CAAC;AAEhC,UAAM,iBAAiB,CAAC,UAAyB;AAC/C,UAAI,OAAO,UAAU,SAAU;AAC/B,YAAM,UAAU,MAAM,KAAK;AAC3B,UAAI,QAAQ,SAAS,KAAK,CAAC,aAAa,SAAS,OAAO,GAAG;AACzD,qBAAa,KAAK,OAAO;AAAA,MAC3B;AAAA,IACF;AAEA,mBAAe,aAAa;AAC5B,mBAAe,aAAa,OAAO;AAEnC,QAAI,MAAM,QAAQ,aAAa,SAAS,GAAG;AACzC,iBAAW,MAAM,YAAY,WAAW;AACtC,uBAAe,EAAE;AAAA,MACnB;AAAA,IACF;AAGA,eAAW,eAAe,cAAc;AACtC,YAAM,WAAW,KAAK,iBAAiB,aAAa,SAAS;AAC7D,UAAI,UAAU;AACZ,cAAM,KAAK,QAAQ;AAAA,MACrB;AAAA,IACF;AASA,QAAI,oBAAoB,WAAW,aAAa,SAAS,GAAG;AAI1D,YAAM,WAAW,KAAK,eAAe,QAAQ,UAAU;AACvD,YAAM,iBAA2B;AAAA,QAC/B,GAAI,OAAO,UAAU,YAAY,WAAW,CAAC,SAAS,OAAO,IAAI,CAAC;AAAA,QAClE,GAAI,MAAM,QAAQ,UAAU,SAAS,IAAI,SAAS,YAAY,CAAC;AAAA,MACjE;AACA,iBAAW,aAAa,gBAAgB;AACtC,YAAI,OAAO,cAAc,SAAU;AACnC,cAAM,UAAU,UAAU,KAAK;AAC/B,YAAI,QAAQ,WAAW,KAAK,aAAa,SAAS,OAAO,EAAG;AAC5D,cAAM,aAAa,KAAK,iBAAiB,SAAS,SAAS;AAC3D,YAAI,YAAY;AACd,gBAAM,KAAK,UAAU;AACrB,uBAAa,KAAK,OAAO;AACzB,cAAI;AAAA,YACF,iDAAiD,OAAO;AAAA,UAC1D;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAEA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKQ,iBACN,aACA,WACiB;AAEjB,UAAM,QAAQ,YAAY,MAAM,GAAG;AACnC,QAAI,MAAM,SAAS,GAAG;AACpB,UAAI,KAAK,uCAAuC,WAAW,EAAE;AAC7D,aAAO;AAAA,IACT;AAEA,UAAM,sBAAsB,MAAM,CAAC;AACnC,UAAM,UAAU,MAAM,MAAM,CAAC,EAAE,KAAK,GAAG;AAMvC,UAAM,mBAAmB,KAAK,sBAAsB,qBAAqB,SAAS;AAClF,UAAM,iBAAiB,kBAAkB;AACzC,QAAI,CAAC,gBAAgB;AACnB,UAAI;AAAA,QACF,qCAAqC,mBAAmB,YAC7C,KAAK,6BAA6B,mBAAmB,EAAE,KAAK,IAAI,CAAC;AAAA,MAC9E;AACA,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,MACL,YAAY,iBAAiB;AAAA,MAC7B;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,sBACN,YACA,WAC4D;AAC5D,UAAM,aAAa,KAAK,6BAA6B,UAAU;AAC/D,UAAM,kBAAkB,WAAW,OAAO,CAAC,cAAc,cAAc,UAAU;AACjF,UAAM,qBAAqB,oBAAoB,IAAI,UAAU,IACzD,CAAC,GAAG,iBAAiB,UAAU,IAC/B,CAAC,YAAY,GAAG,eAAe;AACnC,eAAW,aAAa,YAAY;AAClC,YAAM,SAAS,UAAU,SAAS;AAClC,UAAI,QAAQ;AACV,YAAI,cAAc,YAAY;AAC5B,cAAI,MAAM,2BAA2B,UAAU,yBAAyB,SAAS,GAAG;AAAA,QACtF;AACA,eAAO,EAAE,YAAY,WAAW,OAAO;AAAA,MACzC;AAAA,IACF;AACA,eAAW,aAAa,oBAAoB;AAC1C,YAAM,SAAS,KAAK,sBAAsB,SAAS;AACnD,UAAI,QAAQ;AACV,YAAI,cAAc,YAAY;AAC5B,cAAI,MAAM,2BAA2B,UAAU,qCAAqC,SAAS,GAAG;AAAA,QAClG;AACA,eAAO,EAAE,YAAY,WAAW,OAAO;AAAA,MACzC;AACA,YAAM,gBAAgB,4BAA4B,SAAS;AAC3D,UAAI,eAAe;AACjB,YAAI,cAAc,YAAY;AAC5B,cAAI,MAAM,2BAA2B,UAAU,mCAAmC;AAClF,iBAAO,EAAE,YAAY,QAAQ,cAAc;AAAA,QAC7C;AACA,YAAI,MAAM,2BAA2B,UAAU,kCAAkC,SAAS,GAAG;AAC7F,eAAO,EAAE,YAAY,WAAW,QAAQ,cAAc;AAAA,MACxD;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA,EAEQ,6BAA6B,YAA8B;AACjE,UAAM,aAAa,CAAC,YAAY,GAAI,iBAAiB,UAAU,KAAK,CAAC,CAAE;AACvE,WAAO,CAAC,GAAG,IAAI,IAAI,UAAU,CAAC;AAAA,EAChC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQQ,sBAAsB,YAAgD;AAC5E,UAAM,eAAe,wBAAwB;AAC7C,UAAM,SAAS,aAAa,UAAU;AACtC,QAAI,QAAQ;AACV,UAAI,MAAM,oCAAoC,UAAU,4BAA4B,OAAO,OAAO,SAAS,GAAG;AAC9G,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,MAAc,SACZ,OACA,UACA,SAC2E;AAG3E,UAAM,cAAc,MAAM,eAAe,QAAQ,cAC7C,OACA,MAAM,KAAK,mBAAmB,KAAK;AACvC,UAAM,mBAAmB,aAAa,WAAW,MAAM,eAAe;AACtE,UAAM,iBAAiB,aAAa,WAEhC,MAAM,eAAe,QAAQ,eAAe,MAAM,eAAe,WAAW,SACxE,SACA,MAAM,KAAK,sBAAsB,KAAK;AAK9C,UAAM,SAAS,MAAM,eAAe;AACpC,UAAM,kBAAkB,WAAW,uBAC7B,OAAO,WAAW,YAAY,WAAW;AAC/C,QAAI,mBAAmB,CAAC,gBAAgB;AACtC,YAAM,IAAI,MAAM,yBAAyB,MAAM,UAAU,yCAAyC;AAAA,IACpG;AAEA,UAAM,kBAAuC;AAAA,MAC3C,GAAG,MAAM;AAAA,MACT,SAAS;AAAA,MACT,GAAI,iBAAiB,EAAE,QAAQ,eAAe,IAAI,CAAC;AAAA,IACrD;AAEA,QAAI,MAAM,eAAe,QAAQ,sBAAsB;AACrD,aAAO,MAAM,KAAK,cAAc,iBAAiB,MAAM,SAAS,UAAU,OAAO;AAAA,IACnF;AAEA,QAAI,MAAM,eAAe,QAAQ,aAAa;AAC5C,aAAO,MAAM;AAAA,QACX;AAAA,QACA,MAAM;AAAA,QACN;AAAA,QACA,EAAE,WAAW,QAAQ,WAAW,QAAQ,QAAQ,OAAO;AAAA,MACzD;AAAA,IACF;AAEA,QAAI,MAAM,eAAe,QAAQ,eAAe;AAC9C,aAAO,MAAM,KAAK,eAAe,iBAAiB,MAAM,SAAS,UAAU,OAAO;AAAA,IACpF;AAEA,QACE,MAAM,eAAe,QAAQ,sBAC7B,MAAM,eAAe,QAAQ,4BAC7B,MAAM,eAAe,QAAQ,0BAC7B;AACA,aAAO,MAAM,KAAK;AAAA,QAChB;AAAA,QACA,MAAM;AAAA,QACN;AAAA,QACA;AAAA,MACF;AAAA,IACF;AAMA,WAAO,MAAM,KAAK;AAAA,MAChB;AAAA,MACA,MAAM;AAAA,MACN;AAAA,MACA;AAAA,MACA,kCAAkC,gBAAgB,OAAO;AAAA,IAC3D;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAc,mBACZ,OACuD;AACvD,QAAI;AACF,YAAM,iBAAiB,MAAM,8BAA8B;AAAA,QACzD,wBAAwB,KAAK,eAAe;AAAA,MAC9C,CAAC;AACD,UAAI,CAAC,eAAgB,QAAO;AAE5B,YAAM,SAAS,MAAM,eAAe;AAAA,QAClC,OAAO;AAAA,UACL,UAAU,MAAM;AAAA,UAChB,IAAI,MAAM;AAAA,UACV,KAAK,MAAM,eAAe;AAAA,UAC1B,SAAS,MAAM,eAAe;AAAA,QAChC;AAAA,QACA,KAAK,KAAK;AAAA,QACV,cAAc,KAAK,eAAe;AAAA,MACpC,CAAC;AAED,UAAI,QAAQ,UAAU,QAAQ,SAAS;AACrC,YAAI;AAAA,UACF,4CAA4C,MAAM,WAAW,cAAc,OAAO,UAAU,SAAS,WAAW,OAAO,QAAQ,SAAS;AAAA,QAC1I;AACA,eAAO,EAAE,QAAQ,OAAO,QAAQ,SAAS,OAAO,QAAQ;AAAA,MAC1D;AAAA,IACF,SAAS,KAAK;AACZ,UAAI;AAAA,QACF,kDAAkD,MAAM,WAAW,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG,CAAC;AAAA,MAC3H;AAAA,IACF;AACA,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,sBAAsB,OAA8C;AAChF,WAAO;AAAA,MACL,MAAM;AAAA,MACN,MAAM,eAAe;AAAA,MACrB,KAAK;AAAA,MACL,KAAK,eAAe;AAAA,MACpB;AAAA,QACE,0BAA0B,KAAK,eAAe;AAAA,MAChD;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,WACZ,QACA,SACA,UACA,SACA,cAC2E;AAC3E,UAAM,OAAO,OAAO,QAAQ,QAAQ,OAAO,EAAE;AAC7C,UAAM,MAAM,KAAK,SAAS,KAAK,IAC3B,GAAG,IAAI,sBACP,GAAG,IAAI;AAEX,UAAM,UAAkC;AAAA,MACtC,gBAAgB;AAAA,MAChB,GAAG,OAAO;AAAA,IACZ;AAGA,QAAI,OAAO,UAAU,OAAO,OAAO,WAAW,UAAU;AACtD,UAAI,OAAO,eAAe,OAAO;AAC/B,gBAAQ,eAAe,IAAI,UAAU,OAAO,MAAM;AAAA,MACpD;AAAA,IACF;AAEA,UAAM,OAAO;AAAA,MACX,OAAO;AAAA,MACP;AAAA,MACA,GAAG,+BAA+B,SAAS,QAAQ,eAAe,KAAK;AAAA,QACrE;AAAA,MACF,CAAC;AAAA,MACD,GAAG,8BAA8B,SAAS,QAAQ,aAAa,MAAM;AAAA,QACnE;AAAA,MACF,CAAC;AAAA,IACH;AAEA,UAAM,WAAW,MAAM,MAAM,KAAK;AAAA,MAChC,QAAQ;AAAA,MACR;AAAA,MACA,QAAQ,QAAQ;AAAA,MAChB,MAAM,KAAK,UAAU,IAAI;AAAA,IAC3B,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,QAAQ,MAAM,SAAS,KAAK;AAClC,YAAM,IAAI,MAAM,qBAAqB,SAAS,MAAM,IAAI,KAAK,EAAE;AAAA,IACjE;AAEA,UAAM,OAAQ,MAAM,SAAS,KAAK;AAalC,UAAM,UAAU,KAAK,UAAU,CAAC,GAAG,SAAS;AAC5C,QAAI,CAAC,SAAS;AACZ,YAAM,IAAI,MAAM,gCAAgC;AAAA,IAClD;AAEA,WAAO;AAAA,MACL;AAAA,MACA,OAAO,KAAK,QACR;AAAA,QACE,aAAa,KAAK,MAAM;AAAA,QACxB,cAAc,KAAK,MAAM;AAAA,QACzB,aAAa,KAAK,MAAM;AAAA,MAC1B,IACA;AAAA,IACN;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAc,eACZ,QACA,SACA,UACA,SAC2E;AAC3E,UAAM,OAAO,OAAO,QAAQ,QAAQ,OAAO,EAAE;AAC7C,UAAM,MAAM,KAAK,SAAS,MAAM,IAAI,GAAG,IAAI,UAAU,GAAG,IAAI;AAC5D,UAAM,UAAkC;AAAA,MACtC,gBAAgB;AAAA,MAChB,GAAG,OAAO;AAAA,IACZ;AACA,QAAI,OAAO,UAAU,OAAO,OAAO,WAAW,YAAY,OAAO,eAAe,OAAO;AACrF,cAAQ,gBAAgB,UAAU,OAAO,MAAM;AAAA,IACjD;AAEA,UAAM,WAAW,MAAM,MAAM,KAAK;AAAA,MAChC,QAAQ;AAAA,MACR;AAAA,MACA,QAAQ,QAAQ;AAAA,MAChB,MAAM,KAAK,UAAU;AAAA,QACnB,OAAO;AAAA,QACP;AAAA,QACA,QAAQ;AAAA,QACR,GAAI,OAAO,kBAAkB,EAAE,OAAO,MAAM,IAAI,CAAC;AAAA,QACjD,SAAS;AAAA,UACP,aAAa,QAAQ,eAAe;AAAA,UACpC,aAAa,QAAQ,aAAa;AAAA,QACpC;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,QAAQ,MAAM,SAAS,KAAK;AAClC,YAAM,IAAI,MAAM,qBAAqB,SAAS,MAAM,IAAI,KAAK,EAAE;AAAA,IACjE;AAEA,UAAM,OAAQ,MAAM,SAAS,KAAK;AAMlC,UAAM,UAAU,KAAK,SAAS,WAAW,KAAK;AAC9C,QAAI,CAAC,SAAS;AACZ,YAAM,IAAI,MAAM,gCAAgC;AAAA,IAClD;AAEA,UAAM,cAAc,KAAK,qBAAqB;AAC9C,UAAM,eAAe,KAAK,cAAc;AACxC,WAAO;AAAA,MACL;AAAA,MACA,OAAO;AAAA,QACL;AAAA,QACA;AAAA,QACA,aAAa,cAAc;AAAA,MAC7B;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,oBACZ,QACA,SACA,UACA,SAC2E;AAC3E,UAAM,OAAO,OAAO,QAAQ,QAAQ,OAAO,EAAE;AAC7C,UAAM,MAAM,KAAK,SAAS,KAAK,IAC3B,GAAG,IAAI,eACP,GAAG,IAAI;AAEX,UAAM,UAAkC;AAAA,MACtC,gBAAgB;AAAA,MAChB,GAAG,OAAO;AAAA,IACZ;AAEA,QAAI,OAAO,UAAU,OAAO,OAAO,WAAW,YAAY,OAAO,eAAe,OAAO;AACrF,cAAQ,eAAe,IAAI,UAAU,OAAO,MAAM;AAAA,IACpD;AAEA,UAAM,eAAe,SAClB,OAAO,CAAC,YAAY,QAAQ,SAAS,QAAQ,EAC7C,IAAI,CAAC,YAAY,QAAQ,OAAO,EAChC,KAAK,MAAM,EACX,KAAK;AACR,UAAM,QAAQ,SACX,OAAO,CAAC,YAAY,QAAQ,SAAS,QAAQ,EAC7C,IAAI,CAAC,aAAa;AAAA,MACjB,MAAM,QAAQ;AAAA,MACd,SAAS,CAAC;AAAA,QACR,MAAM,QAAQ,SAAS,cAAc,gBAAgB;AAAA,QACrD,MAAM,QAAQ;AAAA,MAChB,CAAC;AAAA,IACH,EAAE;AAEJ,UAAM,OAAgC;AAAA,MACpC,OAAO;AAAA,MACP;AAAA,MACA,mBAAmB,KAAK,IAAI,GAAG,KAAK,MAAM,QAAQ,aAAa,IAAI,CAAC;AAAA,MACpE,GAAG,+BAA+B,SAAS,QAAQ,eAAe,KAAK;AAAA,QACrE,cAAc,kCAAkC,OAAO,OAAO;AAAA,MAChE,CAAC;AAAA,IACH;AACA,QAAI,aAAa,SAAS,GAAG;AAC3B,WAAK,eAAe;AAAA,IACtB;AAEA,UAAM,WAAW,MAAM,MAAM,KAAK;AAAA,MAChC,QAAQ;AAAA,MACR;AAAA,MACA,QAAQ,QAAQ;AAAA,MAChB,MAAM,KAAK,UAAU,IAAI;AAAA,IAC3B,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,QAAQ,MAAM,SAAS,KAAK;AAClC,YAAM,IAAI,MAAM,+BAA+B,SAAS,MAAM,IAAI,KAAK,EAAE;AAAA,IAC3E;AAEA,UAAM,OAAQ,MAAM,SAAS,KAAK;AAiBlC,UAAM,aAAa,2BAA2B,IAAI;AAClD,QAAI,CAAC,YAAY;AACf,YAAM,IAAI,MAAM,0CAA0C;AAAA,IAC5D;AAEA,WAAO;AAAA,MACL,SAAS;AAAA,MACT,OAAO,KAAK,QACR;AAAA,QACE,aAAa,KAAK,MAAM;AAAA,QACxB,cAAc,KAAK,MAAM;AAAA,QACzB,aAAa,KAAK,MAAM;AAAA,MAC1B,IACA;AAAA,IACN;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAc,cACZ,QACA,SACA,UACA,SAC2E;AAC3E,UAAM,OAAO,OAAO,QAAQ,QAAQ,OAAO,EAAE;AAC7C,UAAM,MAAM,KAAK,SAAS,KAAK,IAC3B,GAAG,IAAI,cACP,GAAG,IAAI;AAEX,UAAM,UAAkC;AAAA,MACtC,gBAAgB;AAAA,MAChB,qBAAqB;AAAA,MACrB,GAAG,OAAO;AAAA,IACZ;AAGA,QAAI,OAAO,UAAU,OAAO,OAAO,WAAW,UAAU;AACtD,cAAQ,WAAW,IAAI,OAAO;AAAA,IAChC;AAGA,UAAM,gBAAgB,SAAS,KAAK,CAAC,MAAM,EAAE,SAAS,QAAQ,GAAG;AACjE,UAAM,oBAAoB,SAAS,OAAO,CAAC,MAAM,EAAE,SAAS,QAAQ;AAGpE,UAAM,oBAAoB,kBAAkB,IAAI,CAAC,OAAO;AAAA,MACtD,MAAM,EAAE;AAAA,MACR,SAAS,EAAE;AAAA,IACb,EAAE;AAEF,UAAM,OAAgC;AAAA,MACpC,OAAO;AAAA,MACP,UAAU;AAAA,MACV,YAAY,QAAQ,aAAa;AAAA,MACjC,aAAa,QAAQ,eAAe;AAAA,IACtC;AAEA,QAAI,eAAe;AACjB,WAAK,SAAS;AAAA,IAChB;AAEA,UAAM,WAAW,MAAM,MAAM,KAAK;AAAA,MAChC,QAAQ;AAAA,MACR;AAAA,MACA,QAAQ,QAAQ;AAAA,MAChB,MAAM,KAAK,UAAU,IAAI;AAAA,IAC3B,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,QAAQ,MAAM,SAAS,KAAK;AAClC,YAAM,IAAI,MAAM,wBAAwB,SAAS,MAAM,IAAI,KAAK,EAAE;AAAA,IACpE;AAEA,UAAM,OAAQ,MAAM,SAAS,KAAK;AAWlC,UAAM,UAAU,KAAK,UAAU,CAAC,GAAG;AACnC,QAAI,CAAC,SAAS;AACZ,YAAM,IAAI,MAAM,mCAAmC;AAAA,IACrD;AAEA,WAAO;AAAA,MACL;AAAA,MACA,OAAO,KAAK,QACR;AAAA,QACE,aAAa,KAAK,MAAM;AAAA,QACxB,cAAc,KAAK,MAAM;AAAA,QACzB,cAAc,KAAK,MAAM,gBAAgB,MAAM,KAAK,MAAM,iBAAiB;AAAA,MAC7E,IACA;AAAA,IACN;AAAA,EACF;AACF;AAEA,SAAS,YAAY,QAAwC;AAC3D,QAAM,SAAS,QAAQ;AACvB,SAAO,kBAAkB,QAAQ,SAAS,IAAI,MAAM,8BAA8B;AACpF;AAEA,SAAS,qBAAqB,OAAoC;AAChE,MAAI,OAAO,UAAU,SAAU,QAAO;AACtC,QAAM,UAAU,MAAM,KAAK;AAC3B,SAAO,QAAQ,SAAS,IAAI,gBAAgB,OAAO,IAAI;AACzD;AAEA,SAAS,wBAAwB,eAA8D;AAC7F,MAAI,CAAC,iBAAiB,OAAO,kBAAkB,SAAU,QAAO;AAChE,QAAM,MAAM;AACZ,SACE,qBAAqB,IAAI,YAAY,KACrC,qBAAqB,IAAI,aAAa,KACtC,qBAAqB,IAAI,SAAS;AAEtC;AAEA,SAAS,8BAAsC;AAC7C,SAAO,KAAK,KAAK,eAAe,GAAG,aAAa,WAAW;AAC7D;AAEA,SAAS,2BAA2B,MAUlB;AAChB,MAAI,OAAO,KAAK,gBAAgB,YAAY,KAAK,YAAY,KAAK,EAAE,SAAS,GAAG;AAC9E,WAAO,KAAK;AAAA,EACd;AAEA,QAAM,SAAmB,CAAC;AAC1B,aAAW,QAAQ,KAAK,UAAU,CAAC,GAAG;AACpC,QAAI,OAAO,KAAK,SAAS,YAAY,KAAK,KAAK,KAAK,EAAE,SAAS,GAAG;AAChE,aAAO,KAAK,KAAK,IAAI;AAAA,IACvB;AACA,eAAW,QAAQ,KAAK,WAAW,CAAC,GAAG;AACrC,WACG,KAAK,SAAS,iBAAiB,KAAK,SAAS,WAC9C,OAAO,KAAK,SAAS,YACrB,KAAK,KAAK,KAAK,EAAE,SAAS,GAC1B;AACA,eAAO,KAAK,KAAK,IAAI;AAAA,MACvB;AAAA,IACF;AAAA,EACF;AAEA,QAAM,SAAS,OAAO,KAAK,IAAI,EAAE,KAAK;AACtC,SAAO,OAAO,SAAS,IAAI,SAAS;AACtC;","names":[]}
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
import {
|
|
5
5
|
compareEntityTimestamps,
|
|
6
6
|
normalizeEntityName
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-SHHT4JTC.js";
|
|
8
8
|
import {
|
|
9
9
|
sanitizeMemoryContent
|
|
10
10
|
} from "./chunk-FVQJYWH7.js";
|
|
@@ -677,4 +677,4 @@ export {
|
|
|
677
677
|
entityIndexVersion,
|
|
678
678
|
entityRecentTranscriptLookbackHours
|
|
679
679
|
};
|
|
680
|
-
//# sourceMappingURL=chunk-
|
|
680
|
+
//# sourceMappingURL=chunk-A3UPMOJZ.js.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ALL_CATEGORY_DIRS,
|
|
3
3
|
NamespaceStorageRouter
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-IXSTQGYV.js";
|
|
5
5
|
import {
|
|
6
6
|
namespaceCollectionName
|
|
7
7
|
} from "./chunk-LASA46TQ.js";
|
|
@@ -202,4 +202,4 @@ export {
|
|
|
202
202
|
verifyNamespaces,
|
|
203
203
|
runNamespaceMigration
|
|
204
204
|
};
|
|
205
|
-
//# sourceMappingURL=chunk-
|
|
205
|
+
//# sourceMappingURL=chunk-AFH2JXSF.js.map
|
|
@@ -6,10 +6,10 @@ import {
|
|
|
6
6
|
} from "./chunk-7WV3F5DQ.js";
|
|
7
7
|
import {
|
|
8
8
|
EngramMcpServer
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-4VTVCWVB.js";
|
|
10
10
|
import {
|
|
11
11
|
EngramAccessInputError
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-52XI77OQ.js";
|
|
13
13
|
import {
|
|
14
14
|
projectTagProjectId
|
|
15
15
|
} from "./chunk-EDQVAMQI.js";
|
|
@@ -21,7 +21,7 @@ import {
|
|
|
21
21
|
} from "./chunk-DEUNUKTD.js";
|
|
22
22
|
import {
|
|
23
23
|
isRecallDisclosure
|
|
24
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-3F7RMHC4.js";
|
|
25
25
|
import {
|
|
26
26
|
expandTildePath
|
|
27
27
|
} from "./chunk-EYIEWJNI.js";
|
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
} from "./chunk-2ODBA7MQ.js";
|
|
31
31
|
import {
|
|
32
32
|
validateRequest
|
|
33
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-CDHRUNBX.js";
|
|
34
34
|
import {
|
|
35
35
|
OFFLINE_SYNC_APPLY_MAX_BODY_BYTES,
|
|
36
36
|
OFFLINE_SYNC_FILE_CONTENT_MAX_CHUNK_BYTES,
|
|
@@ -163,6 +163,8 @@ var EngramAccessHttpServer = class {
|
|
|
163
163
|
maxBodyBytes;
|
|
164
164
|
adminConsoleEnabled;
|
|
165
165
|
adminConsolePublicDir;
|
|
166
|
+
adminConsolePrefillToken;
|
|
167
|
+
adminControls;
|
|
166
168
|
trustPrincipalHeader;
|
|
167
169
|
adapterRegistry;
|
|
168
170
|
writeRequestTimestamps = [];
|
|
@@ -192,6 +194,8 @@ var EngramAccessHttpServer = class {
|
|
|
192
194
|
this.maxBodyBytes = Number.isFinite(options.maxBodyBytes) ? Math.max(1, Math.floor(options.maxBodyBytes ?? 131072)) : 131072;
|
|
193
195
|
this.adminConsoleEnabled = options.adminConsoleEnabled !== false;
|
|
194
196
|
this.adminConsolePublicDir = options.adminConsolePublicDir ?? defaultAdminConsolePublicDir;
|
|
197
|
+
this.adminConsolePrefillToken = options.adminConsolePrefillToken === true ? this.authToken : void 0;
|
|
198
|
+
this.adminControls = options.adminControls;
|
|
195
199
|
this.trustPrincipalHeader = options.trustPrincipalHeader === true;
|
|
196
200
|
this.adapterRegistry = options.enableAdapters !== false ? options.adapterRegistry ?? new AdapterRegistry() : null;
|
|
197
201
|
this.mcpServer = new EngramMcpServer(this.service, {
|
|
@@ -408,6 +412,30 @@ var EngramAccessHttpServer = class {
|
|
|
408
412
|
});
|
|
409
413
|
return;
|
|
410
414
|
}
|
|
415
|
+
if (req.method === "GET" && (pathname === "/engram/v1/admin/dashboard" || pathname === "/remnic/v1/admin/dashboard")) {
|
|
416
|
+
if (!this.adminControls) {
|
|
417
|
+
this.respondJson(res, 404, { error: "admin_controls_unavailable", code: "admin_controls_unavailable" });
|
|
418
|
+
return;
|
|
419
|
+
}
|
|
420
|
+
this.respondJson(res, 200, await this.adminControls.status());
|
|
421
|
+
return;
|
|
422
|
+
}
|
|
423
|
+
if (req.method === "PATCH" && (pathname === "/engram/v1/admin/config" || pathname === "/remnic/v1/admin/config")) {
|
|
424
|
+
if (!this.adminControls?.update) {
|
|
425
|
+
this.respondJson(res, 404, { error: "admin_controls_unavailable", code: "admin_controls_unavailable" });
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
try {
|
|
429
|
+
this.respondJson(res, 200, await this.adminControls.update(await this.readJsonBody(req)));
|
|
430
|
+
} catch (error) {
|
|
431
|
+
throw new HttpError(
|
|
432
|
+
400,
|
|
433
|
+
error instanceof Error ? error.message : "invalid_admin_config_patch",
|
|
434
|
+
"invalid_admin_config_patch"
|
|
435
|
+
);
|
|
436
|
+
}
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
411
439
|
if (req.method === "POST" && pathname === "/engram/v1/recall") {
|
|
412
440
|
const body = await this.readValidatedBody(req, "recall");
|
|
413
441
|
const codingContext = "codingContext" in body ? body.codingContext : void 0;
|
|
@@ -1729,7 +1757,7 @@ var EngramAccessHttpServer = class {
|
|
|
1729
1757
|
return true;
|
|
1730
1758
|
}
|
|
1731
1759
|
if (pathname === "/remnic/ui/" || pathname === "/engram/ui/") {
|
|
1732
|
-
await this.
|
|
1760
|
+
await this.respondAdminConsoleShell(req, res, pathname);
|
|
1733
1761
|
return true;
|
|
1734
1762
|
}
|
|
1735
1763
|
if (pathname === "/remnic/ui/app.js" || pathname === "/engram/ui/app.js") {
|
|
@@ -1738,6 +1766,24 @@ var EngramAccessHttpServer = class {
|
|
|
1738
1766
|
}
|
|
1739
1767
|
return false;
|
|
1740
1768
|
}
|
|
1769
|
+
async respondAdminConsoleShell(req, res, pathname) {
|
|
1770
|
+
try {
|
|
1771
|
+
let body = await readFile(path.join(this.adminConsolePublicDir, "index.html"), "utf-8");
|
|
1772
|
+
const canPrefillToken = this.adminConsolePrefillToken && this.isAuthorized(req, pathname);
|
|
1773
|
+
if (canPrefillToken) {
|
|
1774
|
+
const script = `<script>window.__REMNIC_ADMIN_CONSOLE_PREFILL_TOKEN__=${JSON.stringify(this.adminConsolePrefillToken)};</script>`;
|
|
1775
|
+
body = body.includes("</head>") ? body.replace("</head>", `${script}</head>`) : `${script}${body}`;
|
|
1776
|
+
res.setHeader("cache-control", "private, no-store");
|
|
1777
|
+
}
|
|
1778
|
+
res.setHeader("vary", "authorization");
|
|
1779
|
+
res.statusCode = 200;
|
|
1780
|
+
res.setHeader("content-type", "text/html; charset=utf-8");
|
|
1781
|
+
res.setHeader("content-length", String(Buffer.byteLength(body)));
|
|
1782
|
+
res.end(body);
|
|
1783
|
+
} catch {
|
|
1784
|
+
this.respondJson(res, 404, { error: "not_found" });
|
|
1785
|
+
}
|
|
1786
|
+
}
|
|
1741
1787
|
async respondStatic(res, filePath, contentType) {
|
|
1742
1788
|
try {
|
|
1743
1789
|
const body = await readFile(filePath, "utf-8");
|
|
@@ -1977,4 +2023,4 @@ function positiveIntQueryParam(value, label) {
|
|
|
1977
2023
|
export {
|
|
1978
2024
|
EngramAccessHttpServer
|
|
1979
2025
|
};
|
|
1980
|
-
//# sourceMappingURL=chunk-
|
|
2026
|
+
//# sourceMappingURL=chunk-BB6FNMMB.js.map
|