@remnic/core 1.1.4 → 1.1.5
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 +16 -16
- package/dist/access-http.d.ts +7 -7
- package/dist/access-http.js +10 -10
- package/dist/access-mcp.d.ts +7 -7
- package/dist/access-mcp.js +9 -9
- package/dist/access-schema.d.ts +89 -4
- package/dist/access-schema.js +1 -1
- package/dist/{access-service-CtXFnprR.d.ts → access-service-CWYIkMwY.d.ts} +16 -12
- package/dist/access-service.d.ts +7 -7
- package/dist/access-service.js +7 -7
- package/dist/active-memory-bridge.d.ts +1 -1
- package/dist/active-recall.d.ts +1 -1
- package/dist/behavior-learner.d.ts +1 -1
- package/dist/behavior-signals.d.ts +1 -1
- package/dist/bootstrap.d.ts +6 -6
- package/dist/briefing.d.ts +2 -2
- package/dist/briefing.js +3 -3
- package/dist/buffer-surprise-report.d.ts +1 -1
- package/dist/buffer.d.ts +2 -2
- package/dist/calibration.d.ts +1 -1
- package/dist/causal-behavior.d.ts +1 -1
- package/dist/causal-consolidation.d.ts +2 -2
- package/dist/causal-consolidation.js +3 -3
- package/dist/{chunk-F5VQOQ2E.js → chunk-3YBRSJ52.js} +2 -2
- package/dist/{chunk-Y4A6M3B6.js → chunk-46AIFPQM.js} +2 -2
- package/dist/{chunk-CUI2STX6.js → chunk-4CVIF7UZ.js} +12 -6
- package/dist/chunk-4CVIF7UZ.js.map +1 -0
- package/dist/{chunk-MUELDH4F.js → chunk-57SNKQNS.js} +2 -2
- package/dist/{chunk-EGEPUGN4.js → chunk-5XVDDCMH.js} +2 -2
- package/dist/{chunk-NZS2BLTP.js → chunk-7NFZWXAY.js} +711 -22
- package/dist/chunk-7NFZWXAY.js.map +1 -0
- package/dist/{chunk-XRCYKJ3V.js → chunk-DKVEJTLC.js} +61 -18
- package/dist/chunk-DKVEJTLC.js.map +1 -0
- package/dist/{chunk-AEMBDV7M.js → chunk-DTDB6YS2.js} +13 -8
- package/dist/chunk-DTDB6YS2.js.map +1 -0
- package/dist/{chunk-AGZHRWPT.js → chunk-ERWKQVCX.js} +2 -2
- package/dist/{chunk-TIFRGAKO.js → chunk-FG5R5AQF.js} +5 -5
- package/dist/{chunk-52PDY6GD.js → chunk-FLHPNR5W.js} +2 -2
- package/dist/{chunk-JWSENLQI.js → chunk-H62HCANJ.js} +3 -1
- package/dist/{chunk-JWSENLQI.js.map → chunk-H62HCANJ.js.map} +1 -1
- package/dist/{chunk-W7WWT4FJ.js → chunk-HPJPGIGN.js} +2 -2
- package/dist/{chunk-ZIBOQULP.js → chunk-KCZZLFW5.js} +2 -2
- package/dist/{chunk-47WOM4YW.js → chunk-MJPNOMY4.js} +2 -2
- package/dist/{chunk-HIRKCQGF.js → chunk-OAIXBFAH.js} +17 -17
- package/dist/{chunk-HIRKCQGF.js.map → chunk-OAIXBFAH.js.map} +1 -1
- package/dist/{chunk-RILIVK4O.js → chunk-RICG4UNC.js} +28 -2
- package/dist/chunk-RICG4UNC.js.map +1 -0
- package/dist/{chunk-SMA4IMHV.js → chunk-SGTA3HJC.js} +3 -3
- package/dist/{chunk-VTJVUHRK.js → chunk-SRBJUAMP.js} +1 -1
- package/dist/chunk-SRBJUAMP.js.map +1 -0
- package/dist/{chunk-V7TEH5I2.js → chunk-TMPLRVHD.js} +2 -2
- package/dist/{chunk-43EKP2UK.js → chunk-TOC3VOOF.js} +1 -1
- package/dist/{chunk-43EKP2UK.js.map → chunk-TOC3VOOF.js.map} +1 -1
- package/dist/{chunk-USFPPRAF.js → chunk-WMK6YP7C.js} +5 -3
- package/dist/chunk-WMK6YP7C.js.map +1 -0
- package/dist/{chunk-LW2NMHDW.js → chunk-Y6EPN6XF.js} +2 -2
- package/dist/{chunk-XQ4EJLUD.js → chunk-Z665HFAD.js} +2 -2
- package/dist/{cli-lMql2FCr.d.ts → cli-CWLyGroU.d.ts} +4 -4
- package/dist/cli.d.ts +8 -8
- package/dist/cli.js +20 -20
- package/dist/{codex-materialize-CQlLTzke.d.ts → codex-materialize-XRen3WAz.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/consolidation-provenance-check.d.ts +2 -2
- package/dist/consolidation-undo.d.ts +2 -2
- 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/{engine-O6YWKQM3.js → engine-WJ7K6AZ2.js} +4 -4
- package/dist/entity-retrieval.d.ts +2 -2
- package/dist/entity-retrieval.js +3 -3
- package/dist/entity-schema.d.ts +1 -1
- package/dist/explicit-capture.d.ts +6 -6
- package/dist/extraction-judge-telemetry.d.ts +1 -1
- package/dist/extraction-judge-training.d.ts +1 -1
- package/dist/extraction-judge.d.ts +1 -1
- package/dist/extraction.d.ts +1 -1
- package/dist/fallback-llm.d.ts +1 -1
- package/dist/identity-continuity.d.ts +1 -1
- package/dist/importance.d.ts +1 -1
- package/dist/index.d.ts +13 -13
- package/dist/index.js +38 -24
- package/dist/index.js.map +1 -1
- package/dist/intent.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/memory-action-policy.d.ts +1 -1
- package/dist/memory-cache.d.ts +1 -1
- package/dist/{memory-governance-JZHZDOLN.js → memory-governance-KXMAURFF.js} +4 -4
- package/dist/memory-lifecycle-ledger-utils.d.ts +1 -1
- package/dist/{memory-projection-store-CY8TU40w.d.ts → memory-projection-store-ConH7gNj.d.ts} +1 -1
- package/dist/memory-projection-store.d.ts +2 -2
- package/dist/memory-worth-outcomes.d.ts +2 -2
- package/dist/models-json.d.ts +1 -1
- package/dist/native-knowledge.d.ts +1 -1
- package/dist/operator-toolkit.d.ts +2 -2
- package/dist/operator-toolkit.js +6 -6
- package/dist/{orchestrator-ChkesB8U.d.ts → orchestrator-BHkiEBbd.d.ts} +36 -11
- package/dist/orchestrator.d.ts +6 -6
- package/dist/orchestrator.js +11 -11
- package/dist/patterns-cli.d.ts +1 -1
- package/dist/policy-runtime.d.ts +1 -1
- package/dist/{port-hqGnoStS.d.ts → port-DZHdlUId.d.ts} +1 -1
- package/dist/qmd-recall-cache.d.ts +2 -2
- package/dist/qmd.d.ts +2 -2
- 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-state.d.ts +1 -1
- package/dist/recall-tag-filter.d.ts +1 -1
- package/dist/recall-xray-cli.d.ts +1 -1
- package/dist/recall-xray-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 +2 -2
- package/dist/recall-xray.js +2 -2
- package/dist/resolve-auth-token.d.ts +1 -1
- package/dist/resume-bundles.js +2 -2
- package/dist/retrieval-agents.d.ts +2 -2
- package/dist/retrieval-tiers.d.ts +1 -1
- package/dist/schemas.d.ts +32 -32
- package/dist/{semantic-consolidation-ByBXb-sf.d.ts → semantic-consolidation-Cxj-inGC.d.ts} +2 -2
- package/dist/semantic-consolidation.d.ts +3 -3
- package/dist/semantic-consolidation.js +3 -3
- 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/signal.d.ts +1 -1
- package/dist/storage.d.ts +2 -2
- package/dist/storage.js +2 -2
- package/dist/summarizer.d.ts +1 -1
- package/dist/summary-snapshot.d.ts +1 -1
- package/dist/temporal-supersession.d.ts +2 -2
- package/dist/temporal-validity.d.ts +1 -1
- package/dist/threading.d.ts +1 -1
- package/dist/tier-migration.d.ts +3 -3
- package/dist/tier-routing.d.ts +1 -1
- package/dist/topics.d.ts +1 -1
- package/dist/transcript.d.ts +1 -1
- package/dist/types-B49NzJ5q.d.ts +2707 -0
- package/dist/types.d.ts +1 -2668
- 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/dist/chunk-AEMBDV7M.js.map +0 -1
- package/dist/chunk-CUI2STX6.js.map +0 -1
- package/dist/chunk-NZS2BLTP.js.map +0 -1
- package/dist/chunk-RILIVK4O.js.map +0 -1
- package/dist/chunk-USFPPRAF.js.map +0 -1
- package/dist/chunk-VTJVUHRK.js.map +0 -1
- package/dist/chunk-XRCYKJ3V.js.map +0 -1
- /package/dist/{chunk-F5VQOQ2E.js.map → chunk-3YBRSJ52.js.map} +0 -0
- /package/dist/{chunk-Y4A6M3B6.js.map → chunk-46AIFPQM.js.map} +0 -0
- /package/dist/{chunk-MUELDH4F.js.map → chunk-57SNKQNS.js.map} +0 -0
- /package/dist/{chunk-EGEPUGN4.js.map → chunk-5XVDDCMH.js.map} +0 -0
- /package/dist/{chunk-AGZHRWPT.js.map → chunk-ERWKQVCX.js.map} +0 -0
- /package/dist/{chunk-TIFRGAKO.js.map → chunk-FG5R5AQF.js.map} +0 -0
- /package/dist/{chunk-52PDY6GD.js.map → chunk-FLHPNR5W.js.map} +0 -0
- /package/dist/{chunk-W7WWT4FJ.js.map → chunk-HPJPGIGN.js.map} +0 -0
- /package/dist/{chunk-ZIBOQULP.js.map → chunk-KCZZLFW5.js.map} +0 -0
- /package/dist/{chunk-47WOM4YW.js.map → chunk-MJPNOMY4.js.map} +0 -0
- /package/dist/{chunk-SMA4IMHV.js.map → chunk-SGTA3HJC.js.map} +0 -0
- /package/dist/{chunk-V7TEH5I2.js.map → chunk-TMPLRVHD.js.map} +0 -0
- /package/dist/{chunk-LW2NMHDW.js.map → chunk-Y6EPN6XF.js.map} +0 -0
- /package/dist/{chunk-XQ4EJLUD.js.map → chunk-Z665HFAD.js.map} +0 -0
- /package/dist/{engine-O6YWKQM3.js.map → engine-WJ7K6AZ2.js.map} +0 -0
- /package/dist/{memory-governance-JZHZDOLN.js.map → memory-governance-KXMAURFF.js.map} +0 -0
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
CompoundingEngine,
|
|
3
3
|
SharedContextManager,
|
|
4
4
|
defaultTierMigrationCycleBudget
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-Z665HFAD.js";
|
|
6
6
|
import {
|
|
7
7
|
applyUtilityPromotionRuntimePolicy,
|
|
8
8
|
applyUtilityRankingRuntimeDelta,
|
|
@@ -142,7 +142,7 @@ import {
|
|
|
142
142
|
buildEntityRecallSection,
|
|
143
143
|
entityRecentTranscriptLookbackHours,
|
|
144
144
|
readRecentEntityTranscriptEntries
|
|
145
|
-
} from "./chunk-
|
|
145
|
+
} from "./chunk-FLHPNR5W.js";
|
|
146
146
|
import {
|
|
147
147
|
buildCompressionGuidelinesMarkdown,
|
|
148
148
|
computeCompressionGuidelineCandidate,
|
|
@@ -152,16 +152,16 @@ import {
|
|
|
152
152
|
import {
|
|
153
153
|
RoutingRulesStore,
|
|
154
154
|
normalizeReplaySessionKey
|
|
155
|
-
} from "./chunk-
|
|
155
|
+
} from "./chunk-SRBJUAMP.js";
|
|
156
156
|
import {
|
|
157
157
|
searchVerifiedEpisodes
|
|
158
|
-
} from "./chunk-
|
|
158
|
+
} from "./chunk-5XVDDCMH.js";
|
|
159
159
|
import {
|
|
160
160
|
ThreadingManager
|
|
161
161
|
} from "./chunk-JRNQ3RNA.js";
|
|
162
162
|
import {
|
|
163
163
|
searchVerifiedSemanticRules
|
|
164
|
-
} from "./chunk-
|
|
164
|
+
} from "./chunk-HPJPGIGN.js";
|
|
165
165
|
import {
|
|
166
166
|
searchWorkProductLedgerEntries
|
|
167
167
|
} from "./chunk-CULXMQJH.js";
|
|
@@ -181,7 +181,7 @@ import {
|
|
|
181
181
|
createConversationIndexRuntime,
|
|
182
182
|
createSearchBackend,
|
|
183
183
|
writeConversationChunks
|
|
184
|
-
} from "./chunk-
|
|
184
|
+
} from "./chunk-TMPLRVHD.js";
|
|
185
185
|
import {
|
|
186
186
|
parseQmdExplain
|
|
187
187
|
} from "./chunk-WSZIHQBK.js";
|
|
@@ -228,7 +228,7 @@ import {
|
|
|
228
228
|
materializeAfterSemanticConsolidation,
|
|
229
229
|
parseConsolidationResponse,
|
|
230
230
|
parseOperatorAwareConsolidationResponse
|
|
231
|
-
} from "./chunk-
|
|
231
|
+
} from "./chunk-ERWKQVCX.js";
|
|
232
232
|
import {
|
|
233
233
|
FallbackLlmClient
|
|
234
234
|
} from "./chunk-CRU27Q4J.js";
|
|
@@ -263,7 +263,7 @@ import {
|
|
|
263
263
|
} from "./chunk-EQINRHYR.js";
|
|
264
264
|
import {
|
|
265
265
|
buildXraySnapshot
|
|
266
|
-
} from "./chunk-
|
|
266
|
+
} from "./chunk-WMK6YP7C.js";
|
|
267
267
|
import {
|
|
268
268
|
shouldSkipImplicitExtraction
|
|
269
269
|
} from "./chunk-3FPTCC3Z.js";
|
|
@@ -303,7 +303,7 @@ import {
|
|
|
303
303
|
normalizeAttributePairs,
|
|
304
304
|
normalizeEntityName,
|
|
305
305
|
parseEntityFile
|
|
306
|
-
} from "./chunk-
|
|
306
|
+
} from "./chunk-46AIFPQM.js";
|
|
307
307
|
import {
|
|
308
308
|
attachCitation,
|
|
309
309
|
hasCitationForTemplate,
|
|
@@ -311,7 +311,7 @@ import {
|
|
|
311
311
|
} from "./chunk-4KAN3GZ3.js";
|
|
312
312
|
import {
|
|
313
313
|
confidenceTier
|
|
314
|
-
} from "./chunk-
|
|
314
|
+
} from "./chunk-TOC3VOOF.js";
|
|
315
315
|
import {
|
|
316
316
|
isActiveMemoryStatus
|
|
317
317
|
} from "./chunk-RULE4VG5.js";
|
|
@@ -1613,7 +1613,7 @@ function getTaxonomyFilePath(memoryDir) {
|
|
|
1613
1613
|
// src/lcm/schema.ts
|
|
1614
1614
|
import path4 from "path";
|
|
1615
1615
|
import { mkdir as mkdir4 } from "fs/promises";
|
|
1616
|
-
var LCM_SCHEMA_VERSION =
|
|
1616
|
+
var LCM_SCHEMA_VERSION = 2;
|
|
1617
1617
|
function openLcmDatabase(memoryDir) {
|
|
1618
1618
|
const dbPath = path4.join(memoryDir, "state", "lcm.sqlite");
|
|
1619
1619
|
const db = openBetterSqlite3(dbPath);
|
|
@@ -1662,6 +1662,23 @@ function createTables(db) {
|
|
|
1662
1662
|
CREATE INDEX IF NOT EXISTS idx_lcm_messages_session
|
|
1663
1663
|
ON lcm_messages(session_id, turn_index);
|
|
1664
1664
|
|
|
1665
|
+
CREATE TABLE IF NOT EXISTS lcm_message_parts (
|
|
1666
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
1667
|
+
message_id INTEGER NOT NULL REFERENCES lcm_messages(id) ON DELETE CASCADE,
|
|
1668
|
+
ordinal INTEGER NOT NULL,
|
|
1669
|
+
kind TEXT NOT NULL,
|
|
1670
|
+
payload TEXT NOT NULL,
|
|
1671
|
+
tool_name TEXT,
|
|
1672
|
+
file_path TEXT,
|
|
1673
|
+
created_at TEXT NOT NULL
|
|
1674
|
+
);
|
|
1675
|
+
CREATE INDEX IF NOT EXISTS idx_lcm_message_parts_msg
|
|
1676
|
+
ON lcm_message_parts(message_id, ordinal);
|
|
1677
|
+
CREATE INDEX IF NOT EXISTS idx_lcm_message_parts_tool
|
|
1678
|
+
ON lcm_message_parts(tool_name);
|
|
1679
|
+
CREATE INDEX IF NOT EXISTS idx_lcm_message_parts_file
|
|
1680
|
+
ON lcm_message_parts(file_path);
|
|
1681
|
+
|
|
1665
1682
|
CREATE TABLE IF NOT EXISTS lcm_summary_nodes (
|
|
1666
1683
|
id TEXT PRIMARY KEY,
|
|
1667
1684
|
session_id TEXT NOT NULL,
|
|
@@ -1714,6 +1731,423 @@ function createTables(db) {
|
|
|
1714
1731
|
);
|
|
1715
1732
|
}
|
|
1716
1733
|
|
|
1734
|
+
// src/message-parts/index.ts
|
|
1735
|
+
var LCM_MESSAGE_PART_KINDS = [
|
|
1736
|
+
"text",
|
|
1737
|
+
"tool_call",
|
|
1738
|
+
"tool_result",
|
|
1739
|
+
"patch",
|
|
1740
|
+
"file_read",
|
|
1741
|
+
"file_write",
|
|
1742
|
+
"step_start",
|
|
1743
|
+
"step_finish",
|
|
1744
|
+
"snapshot",
|
|
1745
|
+
"retry"
|
|
1746
|
+
];
|
|
1747
|
+
var SECRET_KEY_RE = /(api[_-]?key|authorization|bearer|credential|password|secret|token)/i;
|
|
1748
|
+
var MAX_PAYLOAD_STRING = 8e3;
|
|
1749
|
+
var MAX_FILE_SCAN_CHARS = 2e4;
|
|
1750
|
+
function isLcmMessagePartKind(value) {
|
|
1751
|
+
return typeof value === "string" && LCM_MESSAGE_PART_KINDS.includes(value);
|
|
1752
|
+
}
|
|
1753
|
+
function parseMessageParts(input, options = {}) {
|
|
1754
|
+
const explicit = normalizeExplicitParts(input);
|
|
1755
|
+
if (explicit.length > 0) return explicit;
|
|
1756
|
+
const format = options.sourceFormat ?? inferSourceFormat(input);
|
|
1757
|
+
switch (format) {
|
|
1758
|
+
case "openai":
|
|
1759
|
+
return withRenderedFallback(parseOpenAiMessageParts(input, options), options);
|
|
1760
|
+
case "anthropic":
|
|
1761
|
+
return withRenderedFallback(parseAnthropicMessageParts(input, options), options);
|
|
1762
|
+
case "openclaw":
|
|
1763
|
+
return withRenderedFallback(parseOpenClawMessageParts(input, options), options);
|
|
1764
|
+
case "lossless-claw":
|
|
1765
|
+
case "remnic":
|
|
1766
|
+
return withRenderedFallback(normalizeExplicitParts(input), options);
|
|
1767
|
+
default:
|
|
1768
|
+
return renderedFallbackParts(options);
|
|
1769
|
+
}
|
|
1770
|
+
}
|
|
1771
|
+
function normalizeExplicitParts(input) {
|
|
1772
|
+
const rawParts = pickArray(input, "parts") ?? pickArray(input, "message_parts");
|
|
1773
|
+
if (!rawParts) return [];
|
|
1774
|
+
const parts = [];
|
|
1775
|
+
rawParts.forEach((raw, index) => {
|
|
1776
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return;
|
|
1777
|
+
const obj = raw;
|
|
1778
|
+
const kind = normalizeKind(obj.kind ?? obj.type);
|
|
1779
|
+
if (!kind) return;
|
|
1780
|
+
const payload = obj.payload && typeof obj.payload === "object" && !Array.isArray(obj.payload) ? obj.payload : { value: sanitizePayload(obj) };
|
|
1781
|
+
const toolName = asNonEmptyString(obj.toolName ?? obj.tool_name ?? obj.name);
|
|
1782
|
+
const filePath = asNonEmptyString(obj.filePath ?? obj.file_path ?? obj.path);
|
|
1783
|
+
const ordinal = typeof obj.ordinal === "number" && Number.isInteger(obj.ordinal) ? Math.max(0, obj.ordinal) : index;
|
|
1784
|
+
parts.push({
|
|
1785
|
+
ordinal,
|
|
1786
|
+
kind,
|
|
1787
|
+
payload: sanitizePayload(payload),
|
|
1788
|
+
toolName,
|
|
1789
|
+
filePath,
|
|
1790
|
+
createdAt: asNonEmptyString(obj.createdAt ?? obj.created_at)
|
|
1791
|
+
});
|
|
1792
|
+
});
|
|
1793
|
+
return parts;
|
|
1794
|
+
}
|
|
1795
|
+
function parseOpenAiMessageParts(input, _options = {}) {
|
|
1796
|
+
const items = gatherOpenAiItems(input);
|
|
1797
|
+
const parts = [];
|
|
1798
|
+
for (const item of items) {
|
|
1799
|
+
const type = asNonEmptyString(item.type) ?? asNonEmptyString(item.kind);
|
|
1800
|
+
if (!type) continue;
|
|
1801
|
+
if (isOpenAiContentBlock(item)) {
|
|
1802
|
+
const text = asNonEmptyString(item.text ?? item.content);
|
|
1803
|
+
if (text) parts.push(makePart("text", { type, text }, { filePath: firstFilePath(text) }));
|
|
1804
|
+
continue;
|
|
1805
|
+
}
|
|
1806
|
+
if (type === "message") {
|
|
1807
|
+
for (const block of gatherContentBlocks(item.content)) {
|
|
1808
|
+
const text = asNonEmptyString(block.text ?? block.content);
|
|
1809
|
+
if (text) parts.push(makePart("text", { type, text }, { filePath: firstFilePath(text) }));
|
|
1810
|
+
}
|
|
1811
|
+
continue;
|
|
1812
|
+
}
|
|
1813
|
+
if (type === "function_call") {
|
|
1814
|
+
const toolName = asNonEmptyString(item.name ?? item.tool_name);
|
|
1815
|
+
const payload = {
|
|
1816
|
+
id: item.id ?? item.call_id,
|
|
1817
|
+
name: toolName,
|
|
1818
|
+
arguments: parseMaybeJson(item.arguments)
|
|
1819
|
+
};
|
|
1820
|
+
parts.push(classifyToolPart(toolName, payload));
|
|
1821
|
+
continue;
|
|
1822
|
+
}
|
|
1823
|
+
if (type === "function_call_output") {
|
|
1824
|
+
const output = asNonEmptyString(item.output) ?? JSON.stringify(sanitizePayload(item.output ?? item));
|
|
1825
|
+
parts.push(makePart("tool_result", { id: item.id ?? item.call_id, output }, {
|
|
1826
|
+
filePath: firstFilePath(output)
|
|
1827
|
+
}));
|
|
1828
|
+
continue;
|
|
1829
|
+
}
|
|
1830
|
+
if (type === "reasoning") {
|
|
1831
|
+
parts.push(makePart("step_start", { type, summary: sanitizePayload(item.summary ?? item) }));
|
|
1832
|
+
continue;
|
|
1833
|
+
}
|
|
1834
|
+
if (type === "retry") {
|
|
1835
|
+
parts.push(makePart("retry", { type, item: sanitizePayload(item) }));
|
|
1836
|
+
}
|
|
1837
|
+
}
|
|
1838
|
+
return withOrdinals(parts);
|
|
1839
|
+
}
|
|
1840
|
+
function parseAnthropicMessageParts(input, _options = {}) {
|
|
1841
|
+
const blocks = gatherContentBlocks(
|
|
1842
|
+
Array.isArray(input) ? input : input && typeof input === "object" ? input.content : input
|
|
1843
|
+
);
|
|
1844
|
+
const parts = [];
|
|
1845
|
+
for (const block of blocks) {
|
|
1846
|
+
const type = asNonEmptyString(block.type);
|
|
1847
|
+
if (type === "text") {
|
|
1848
|
+
const text = asNonEmptyString(block.text);
|
|
1849
|
+
if (text) parts.push(makePart("text", { type, text }, { filePath: firstFilePath(text) }));
|
|
1850
|
+
continue;
|
|
1851
|
+
}
|
|
1852
|
+
if (type === "tool_use") {
|
|
1853
|
+
const toolName = asNonEmptyString(block.name);
|
|
1854
|
+
parts.push(classifyToolPart(toolName, {
|
|
1855
|
+
id: block.id,
|
|
1856
|
+
name: toolName,
|
|
1857
|
+
input: sanitizePayload(block.input)
|
|
1858
|
+
}));
|
|
1859
|
+
continue;
|
|
1860
|
+
}
|
|
1861
|
+
if (type === "tool_result") {
|
|
1862
|
+
const content = block.content;
|
|
1863
|
+
const rendered = renderUnknownContent(content);
|
|
1864
|
+
parts.push(makePart("tool_result", { id: block.tool_use_id, content: sanitizePayload(content) }, {
|
|
1865
|
+
filePath: firstFilePath(rendered)
|
|
1866
|
+
}));
|
|
1867
|
+
continue;
|
|
1868
|
+
}
|
|
1869
|
+
if (type === "thinking") {
|
|
1870
|
+
parts.push(makePart("step_start", {
|
|
1871
|
+
type,
|
|
1872
|
+
thinking: truncateString(asNonEmptyString(block.thinking) ?? ""),
|
|
1873
|
+
signature: asNonEmptyString(block.signature)
|
|
1874
|
+
}));
|
|
1875
|
+
continue;
|
|
1876
|
+
}
|
|
1877
|
+
if (type === "redacted_thinking") {
|
|
1878
|
+
parts.push(makePart("step_finish", { type }));
|
|
1879
|
+
}
|
|
1880
|
+
}
|
|
1881
|
+
return withOrdinals(parts);
|
|
1882
|
+
}
|
|
1883
|
+
function parseOpenClawMessageParts(input, options = {}) {
|
|
1884
|
+
const explicit = normalizeExplicitParts(input);
|
|
1885
|
+
if (explicit.length > 0) return explicit;
|
|
1886
|
+
if (!input || typeof input !== "object") return [];
|
|
1887
|
+
const obj = input;
|
|
1888
|
+
const content = obj.content;
|
|
1889
|
+
if (Array.isArray(content)) {
|
|
1890
|
+
const hasOpenAiBlocks = content.some(isOpenAiContentBlock);
|
|
1891
|
+
if (hasOpenAiBlocks) return parseOpenAiMessageParts(content, options);
|
|
1892
|
+
const hasAnthropicBlocks = content.some(
|
|
1893
|
+
(block) => block && typeof block === "object" && typeof block.type === "string"
|
|
1894
|
+
);
|
|
1895
|
+
if (hasAnthropicBlocks) return parseAnthropicMessageParts({ content }, options);
|
|
1896
|
+
}
|
|
1897
|
+
const toolName = asNonEmptyString(obj.toolName ?? obj.tool_name ?? obj.name);
|
|
1898
|
+
if (toolName) {
|
|
1899
|
+
return withOrdinals([
|
|
1900
|
+
classifyToolPart(toolName, {
|
|
1901
|
+
name: toolName,
|
|
1902
|
+
input: sanitizePayload(obj.input ?? obj.arguments ?? obj.params),
|
|
1903
|
+
output: sanitizePayload(obj.output ?? obj.result)
|
|
1904
|
+
})
|
|
1905
|
+
]);
|
|
1906
|
+
}
|
|
1907
|
+
const rendered = options.renderedContent ?? asNonEmptyString(obj.content);
|
|
1908
|
+
return rendered ? withOrdinals(partsFromRenderedText(rendered)) : [];
|
|
1909
|
+
}
|
|
1910
|
+
function partsFromRenderedText(text) {
|
|
1911
|
+
if (text.includes("*** Begin Patch")) {
|
|
1912
|
+
const paths2 = extractFilePaths(text);
|
|
1913
|
+
const patchPaths = extractPatchPaths(text);
|
|
1914
|
+
return withOrdinals((patchPaths.length > 0 ? patchPaths : paths2).map(
|
|
1915
|
+
(filePath) => makePart("patch", { text: truncateString(text) }, { filePath })
|
|
1916
|
+
));
|
|
1917
|
+
}
|
|
1918
|
+
const paths = extractFilePaths(text);
|
|
1919
|
+
if (paths.length === 0) return [];
|
|
1920
|
+
return withOrdinals(paths.map(
|
|
1921
|
+
(filePath) => makePart("file_read", { text: truncateString(text) }, { filePath })
|
|
1922
|
+
));
|
|
1923
|
+
}
|
|
1924
|
+
function inferSourceFormat(input) {
|
|
1925
|
+
if (input && typeof input === "object") {
|
|
1926
|
+
const obj = input;
|
|
1927
|
+
const explicit = asNonEmptyString(obj.sourceFormat ?? obj.source_format);
|
|
1928
|
+
if (explicit === "openai" || explicit === "anthropic" || explicit === "openclaw" || explicit === "lossless-claw" || explicit === "remnic") {
|
|
1929
|
+
return explicit;
|
|
1930
|
+
}
|
|
1931
|
+
if (Array.isArray(obj.output)) return "openai";
|
|
1932
|
+
if (isOpenAiResponseItem(obj)) return "openai";
|
|
1933
|
+
if (Array.isArray(obj.content) && obj.content.some(isOpenAiContentBlock)) return "openai";
|
|
1934
|
+
if (Array.isArray(obj.content)) return "anthropic";
|
|
1935
|
+
}
|
|
1936
|
+
if (Array.isArray(input)) {
|
|
1937
|
+
return input.some(
|
|
1938
|
+
(item) => isRecord(item) && (isOpenAiResponseItem(item) || isOpenAiContentBlock(item))
|
|
1939
|
+
) ? "openai" : "anthropic";
|
|
1940
|
+
}
|
|
1941
|
+
return void 0;
|
|
1942
|
+
}
|
|
1943
|
+
function isOpenAiResponseItem(obj) {
|
|
1944
|
+
const type = asNonEmptyString(obj.type ?? obj.kind);
|
|
1945
|
+
return type === "message" || type === "function_call" || type === "function_call_output" || type === "reasoning" || type === "retry";
|
|
1946
|
+
}
|
|
1947
|
+
function isOpenAiContentBlock(value) {
|
|
1948
|
+
if (!isRecord(value)) return false;
|
|
1949
|
+
const type = asNonEmptyString(value.type);
|
|
1950
|
+
return type === "input_text" || type === "output_text" || type === "input_image" || type === "input_file" || type === "refusal";
|
|
1951
|
+
}
|
|
1952
|
+
function gatherOpenAiItems(input) {
|
|
1953
|
+
if (Array.isArray(input)) return input.filter(isRecord);
|
|
1954
|
+
if (!isRecord(input)) return [];
|
|
1955
|
+
if (Array.isArray(input.output)) return input.output.filter(isRecord);
|
|
1956
|
+
if (Array.isArray(input.items)) return input.items.filter(isRecord);
|
|
1957
|
+
return [input];
|
|
1958
|
+
}
|
|
1959
|
+
function gatherContentBlocks(input) {
|
|
1960
|
+
if (Array.isArray(input)) return input.filter(isRecord);
|
|
1961
|
+
if (typeof input === "string") return [{ type: "text", text: input }];
|
|
1962
|
+
if (isRecord(input)) return [input];
|
|
1963
|
+
return [];
|
|
1964
|
+
}
|
|
1965
|
+
function classifyToolPart(toolName, payload) {
|
|
1966
|
+
const normalized = (toolName ?? "").toLowerCase();
|
|
1967
|
+
const rendered = renderUnknownContent(payload);
|
|
1968
|
+
const filePath = firstFilePathFromObject(payload) ?? firstFilePath(rendered) ?? null;
|
|
1969
|
+
if (normalized.includes("apply_patch") || rendered.includes("*** Begin Patch")) {
|
|
1970
|
+
return makePart("patch", payload, { toolName, filePath: filePath ?? extractPatchPaths(rendered)[0] ?? null });
|
|
1971
|
+
}
|
|
1972
|
+
if (/(write|edit|multiedit|create|save)/i.test(normalized)) {
|
|
1973
|
+
return makePart("file_write", payload, { toolName, filePath });
|
|
1974
|
+
}
|
|
1975
|
+
if (/(read|grep|glob|search|list|ls)/i.test(normalized)) {
|
|
1976
|
+
return makePart("file_read", payload, { toolName, filePath });
|
|
1977
|
+
}
|
|
1978
|
+
return makePart("tool_call", payload, { toolName, filePath });
|
|
1979
|
+
}
|
|
1980
|
+
function makePart(kind, payload, options = {}) {
|
|
1981
|
+
return {
|
|
1982
|
+
kind,
|
|
1983
|
+
payload: sanitizePayload(payload),
|
|
1984
|
+
toolName: options.toolName ?? null,
|
|
1985
|
+
filePath: options.filePath ?? null
|
|
1986
|
+
};
|
|
1987
|
+
}
|
|
1988
|
+
function withOrdinals(parts) {
|
|
1989
|
+
return parts.map((part, ordinal) => ({ ...part, ordinal: part.ordinal ?? ordinal }));
|
|
1990
|
+
}
|
|
1991
|
+
function withRenderedFallback(parts, options) {
|
|
1992
|
+
return parts.length > 0 ? parts : renderedFallbackParts(options);
|
|
1993
|
+
}
|
|
1994
|
+
function renderedFallbackParts(options) {
|
|
1995
|
+
const rendered = asNonEmptyString(options.renderedContent);
|
|
1996
|
+
return rendered ? partsFromRenderedText(rendered) : [];
|
|
1997
|
+
}
|
|
1998
|
+
function normalizeKind(value) {
|
|
1999
|
+
if (isLcmMessagePartKind(value)) return value;
|
|
2000
|
+
if (value === "tool_use" || value === "function_call") return "tool_call";
|
|
2001
|
+
if (value === "function_call_output") return "tool_result";
|
|
2002
|
+
if (value === "thinking" || value === "reasoning") return "step_start";
|
|
2003
|
+
return null;
|
|
2004
|
+
}
|
|
2005
|
+
function pickArray(input, key) {
|
|
2006
|
+
if (!input || typeof input !== "object" || Array.isArray(input)) return null;
|
|
2007
|
+
const value = input[key];
|
|
2008
|
+
return Array.isArray(value) ? value : null;
|
|
2009
|
+
}
|
|
2010
|
+
function asNonEmptyString(value) {
|
|
2011
|
+
if (typeof value !== "string") return null;
|
|
2012
|
+
const trimmed = value.trim();
|
|
2013
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
2014
|
+
}
|
|
2015
|
+
function isRecord(value) {
|
|
2016
|
+
return !!value && typeof value === "object" && !Array.isArray(value);
|
|
2017
|
+
}
|
|
2018
|
+
function parseMaybeJson(value) {
|
|
2019
|
+
if (typeof value !== "string") return sanitizePayload(value);
|
|
2020
|
+
try {
|
|
2021
|
+
return sanitizePayload(JSON.parse(value));
|
|
2022
|
+
} catch {
|
|
2023
|
+
return truncateString(value);
|
|
2024
|
+
}
|
|
2025
|
+
}
|
|
2026
|
+
function sanitizePayload(value, depth = 0) {
|
|
2027
|
+
if (value === null || value === void 0) return value;
|
|
2028
|
+
if (typeof value === "string") return truncateString(value);
|
|
2029
|
+
if (typeof value === "number" || typeof value === "boolean") return value;
|
|
2030
|
+
if (Array.isArray(value)) {
|
|
2031
|
+
if (depth >= 4) return "[truncated]";
|
|
2032
|
+
return value.slice(0, 100).map((item) => sanitizePayload(item, depth + 1));
|
|
2033
|
+
}
|
|
2034
|
+
if (typeof value === "object") {
|
|
2035
|
+
if (depth >= 4) return "[truncated]";
|
|
2036
|
+
const out = {};
|
|
2037
|
+
for (const [key, child] of Object.entries(value)) {
|
|
2038
|
+
out[key] = SECRET_KEY_RE.test(key) ? "[redacted]" : sanitizePayload(child, depth + 1);
|
|
2039
|
+
}
|
|
2040
|
+
return out;
|
|
2041
|
+
}
|
|
2042
|
+
return String(value);
|
|
2043
|
+
}
|
|
2044
|
+
function truncateString(value) {
|
|
2045
|
+
return value.length > MAX_PAYLOAD_STRING ? `${value.slice(0, MAX_PAYLOAD_STRING)}...[truncated]` : value;
|
|
2046
|
+
}
|
|
2047
|
+
function renderUnknownContent(value) {
|
|
2048
|
+
if (typeof value === "string") return value;
|
|
2049
|
+
try {
|
|
2050
|
+
return JSON.stringify(value ?? "");
|
|
2051
|
+
} catch {
|
|
2052
|
+
return String(value ?? "");
|
|
2053
|
+
}
|
|
2054
|
+
}
|
|
2055
|
+
function firstFilePathFromObject(value) {
|
|
2056
|
+
if (!isRecord(value)) return null;
|
|
2057
|
+
const keys = ["file_path", "filePath", "path", "filename", "cwd"];
|
|
2058
|
+
for (const key of keys) {
|
|
2059
|
+
const candidate = asNonEmptyString(value[key]);
|
|
2060
|
+
if (candidate) return candidate;
|
|
2061
|
+
}
|
|
2062
|
+
for (const child of Object.values(value)) {
|
|
2063
|
+
if (typeof child === "string") {
|
|
2064
|
+
const fromText = extractPatchPaths(child)[0] ?? firstFilePath(child);
|
|
2065
|
+
if (fromText) return fromText;
|
|
2066
|
+
}
|
|
2067
|
+
if (isRecord(child)) {
|
|
2068
|
+
const nested = firstFilePathFromObject(child);
|
|
2069
|
+
if (nested) return nested;
|
|
2070
|
+
}
|
|
2071
|
+
}
|
|
2072
|
+
return null;
|
|
2073
|
+
}
|
|
2074
|
+
function firstFilePath(text) {
|
|
2075
|
+
return extractFilePaths(text)[0] ?? null;
|
|
2076
|
+
}
|
|
2077
|
+
function extractFilePaths(text) {
|
|
2078
|
+
const out = /* @__PURE__ */ new Set();
|
|
2079
|
+
let token = "";
|
|
2080
|
+
const scanLength = Math.min(text.length, MAX_FILE_SCAN_CHARS);
|
|
2081
|
+
for (let index = 0; index <= scanLength; index += 1) {
|
|
2082
|
+
const char = index < scanLength ? text[index] : " ";
|
|
2083
|
+
if (isFilePathTokenSeparator(char)) {
|
|
2084
|
+
addFilePathCandidate(out, token);
|
|
2085
|
+
token = "";
|
|
2086
|
+
continue;
|
|
2087
|
+
}
|
|
2088
|
+
token += char;
|
|
2089
|
+
if (token.length > 512) {
|
|
2090
|
+
addFilePathCandidate(out, token);
|
|
2091
|
+
token = "";
|
|
2092
|
+
}
|
|
2093
|
+
}
|
|
2094
|
+
return [...out].slice(0, 20);
|
|
2095
|
+
}
|
|
2096
|
+
function isFilePathTokenSeparator(char) {
|
|
2097
|
+
return char === " " || char === "\n" || char === "\r" || char === " " || char === '"' || char === "'" || char === "`" || char === "(" || char === ")" || char === "[" || char === "]" || char === "{" || char === "}" || char === "<" || char === ">" || char === ",";
|
|
2098
|
+
}
|
|
2099
|
+
function addFilePathCandidate(out, raw) {
|
|
2100
|
+
const candidate = trimFilePathPunctuation(raw);
|
|
2101
|
+
if (candidate.length === 0 || candidate.includes("://")) return;
|
|
2102
|
+
if (isLikelyFilePath(candidate)) out.add(candidate);
|
|
2103
|
+
}
|
|
2104
|
+
function trimFilePathPunctuation(raw) {
|
|
2105
|
+
let start = 0;
|
|
2106
|
+
let end = raw.length;
|
|
2107
|
+
while (start < end && isLeadingFilePathPunctuation(raw[start])) start += 1;
|
|
2108
|
+
while (end > start && isTrailingFilePathPunctuation(raw[end - 1])) end -= 1;
|
|
2109
|
+
return raw.slice(start, end);
|
|
2110
|
+
}
|
|
2111
|
+
function isLeadingFilePathPunctuation(char) {
|
|
2112
|
+
return char === ":" || char === ";" || char === "!" || char === "?" || char === "|" || char === "*" || char === "=";
|
|
2113
|
+
}
|
|
2114
|
+
function isTrailingFilePathPunctuation(char) {
|
|
2115
|
+
return char === "." || char === ":" || char === ";" || char === "!" || char === "?" || char === "|" || char === "*" || char === "=";
|
|
2116
|
+
}
|
|
2117
|
+
function isLikelyFilePath(value) {
|
|
2118
|
+
if (value.startsWith("/") || value.startsWith("./") || value.startsWith("../") || value.startsWith("~/")) {
|
|
2119
|
+
return hasValidFileExtension(value);
|
|
2120
|
+
}
|
|
2121
|
+
if (value.includes("/")) return hasValidFileExtension(value);
|
|
2122
|
+
return hasValidFileExtension(value);
|
|
2123
|
+
}
|
|
2124
|
+
function hasValidFileExtension(value) {
|
|
2125
|
+
const lastSlash = value.lastIndexOf("/");
|
|
2126
|
+
const basename = value.slice(lastSlash + 1);
|
|
2127
|
+
const dot = basename.lastIndexOf(".");
|
|
2128
|
+
if (dot <= 0 || dot === basename.length - 1) return false;
|
|
2129
|
+
const ext = basename.slice(dot + 1);
|
|
2130
|
+
if (ext.length < 1 || ext.length > 12) return false;
|
|
2131
|
+
for (const char of ext) {
|
|
2132
|
+
if (!isFileExtensionChar(char)) return false;
|
|
2133
|
+
}
|
|
2134
|
+
return true;
|
|
2135
|
+
}
|
|
2136
|
+
function isFileExtensionChar(char) {
|
|
2137
|
+
const code = char.charCodeAt(0);
|
|
2138
|
+
return code >= 48 && code <= 57 || code >= 65 && code <= 90 || code >= 97 && code <= 122 || char === "_" || char === "+" || char === "-";
|
|
2139
|
+
}
|
|
2140
|
+
function extractPatchPaths(text) {
|
|
2141
|
+
const out = /* @__PURE__ */ new Set();
|
|
2142
|
+
for (const line of text.split(/\r?\n/)) {
|
|
2143
|
+
const match = line.match(/^\*\*\* (?:Add|Update|Delete) File: (.+)$/);
|
|
2144
|
+
if (match?.[1]) out.add(match[1].trim());
|
|
2145
|
+
const move = line.match(/^\*\*\* Move to: (.+)$/);
|
|
2146
|
+
if (move?.[1]) out.add(move[1].trim());
|
|
2147
|
+
}
|
|
2148
|
+
return [...out].slice(0, 20);
|
|
2149
|
+
}
|
|
2150
|
+
|
|
1717
2151
|
// src/lcm/archive.ts
|
|
1718
2152
|
function estimateTokens(text) {
|
|
1719
2153
|
return Math.ceil(text.length / 4);
|
|
@@ -1724,7 +2158,7 @@ var LcmArchive = class {
|
|
|
1724
2158
|
}
|
|
1725
2159
|
db;
|
|
1726
2160
|
/** Append a message to the archive. Returns the row id. */
|
|
1727
|
-
appendMessage(sessionId, turnIndex, role, content, metadata) {
|
|
2161
|
+
appendMessage(sessionId, turnIndex, role, content, metadata, parts) {
|
|
1728
2162
|
const tokenCount = estimateTokens(content);
|
|
1729
2163
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1730
2164
|
const metaJson = metadata ? JSON.stringify(metadata) : null;
|
|
@@ -1735,18 +2169,58 @@ var LcmArchive = class {
|
|
|
1735
2169
|
const result = stmt.run(sessionId, turnIndex, role, content, tokenCount, now, metaJson);
|
|
1736
2170
|
const rowId = Number(result.lastInsertRowid);
|
|
1737
2171
|
this.db.prepare("INSERT INTO lcm_messages_fts (rowid, content) VALUES (?, ?)").run(rowId, content);
|
|
2172
|
+
if (parts && parts.length > 0) {
|
|
2173
|
+
this.insertMessageParts(rowId, parts, now);
|
|
2174
|
+
}
|
|
1738
2175
|
return rowId;
|
|
1739
2176
|
}
|
|
1740
2177
|
/** Append multiple messages in a single transaction. */
|
|
1741
|
-
appendMessages(sessionId, messages) {
|
|
2178
|
+
appendMessages(sessionId, messages, options = {}) {
|
|
1742
2179
|
if (messages.length === 0) return;
|
|
2180
|
+
const captureMessageParts = options.messagePartsEnabled !== false;
|
|
1743
2181
|
const txn = this.db.transaction(() => {
|
|
1744
2182
|
for (const msg of messages) {
|
|
1745
|
-
|
|
2183
|
+
const explicitParts = msg.parts && msg.parts.length > 0 ? msg.parts : void 0;
|
|
2184
|
+
const rawContent = msg.rawContent ?? msg.content;
|
|
2185
|
+
const parts = captureMessageParts ? explicitParts ?? parseMessageParts(rawContent, {
|
|
2186
|
+
sourceFormat: msg.sourceFormat,
|
|
2187
|
+
renderedContent: msg.content
|
|
2188
|
+
}) : void 0;
|
|
2189
|
+
this.appendMessage(
|
|
2190
|
+
sessionId,
|
|
2191
|
+
msg.turnIndex,
|
|
2192
|
+
msg.role,
|
|
2193
|
+
msg.content,
|
|
2194
|
+
msg.metadata,
|
|
2195
|
+
parts
|
|
2196
|
+
);
|
|
1746
2197
|
}
|
|
1747
2198
|
});
|
|
1748
2199
|
txn();
|
|
1749
2200
|
}
|
|
2201
|
+
insertMessageParts(messageId, parts, fallbackCreatedAt) {
|
|
2202
|
+
if (parts.length === 0) return;
|
|
2203
|
+
const stmt = this.db.prepare(`
|
|
2204
|
+
INSERT INTO lcm_message_parts (message_id, ordinal, kind, payload, tool_name, file_path, created_at)
|
|
2205
|
+
VALUES (?, ?, ?, ?, ?, ?, ?)
|
|
2206
|
+
`);
|
|
2207
|
+
for (let index = 0; index < parts.length; index += 1) {
|
|
2208
|
+
const part = parts[index];
|
|
2209
|
+
const rawPart = part;
|
|
2210
|
+
const toolName = part.toolName ?? asNullableString(rawPart.tool_name);
|
|
2211
|
+
const filePath = part.filePath ?? asNullableString(rawPart.file_path);
|
|
2212
|
+
const createdAt = part.createdAt ?? asNullableString(rawPart.created_at);
|
|
2213
|
+
stmt.run(
|
|
2214
|
+
messageId,
|
|
2215
|
+
part.ordinal ?? index,
|
|
2216
|
+
part.kind,
|
|
2217
|
+
JSON.stringify(part.payload ?? {}),
|
|
2218
|
+
toolName ?? null,
|
|
2219
|
+
filePath ?? null,
|
|
2220
|
+
createdAt ?? fallbackCreatedAt
|
|
2221
|
+
);
|
|
2222
|
+
}
|
|
2223
|
+
}
|
|
1750
2224
|
/** Get the highest turn_index for a session, or -1 if none. */
|
|
1751
2225
|
getMaxTurnIndex(sessionId) {
|
|
1752
2226
|
const row = this.db.prepare("SELECT MAX(turn_index) as max_turn FROM lcm_messages WHERE session_id = ?").get(sessionId);
|
|
@@ -1868,6 +2342,55 @@ var LcmArchive = class {
|
|
|
1868
2342
|
return [];
|
|
1869
2343
|
}
|
|
1870
2344
|
}
|
|
2345
|
+
searchStructuredParts(query, limit, sessionId) {
|
|
2346
|
+
const cappedLimit = Math.max(0, Math.min(20, Math.floor(limit)));
|
|
2347
|
+
if (cappedLimit === 0) return [];
|
|
2348
|
+
const fileTerms = extractStructuredFileTerms(query);
|
|
2349
|
+
const toolTerms = extractStructuredToolTerms(query);
|
|
2350
|
+
if (fileTerms.length === 0 && toolTerms.length === 0) return [];
|
|
2351
|
+
const matchWhere = [];
|
|
2352
|
+
const whereParams = [];
|
|
2353
|
+
for (const term of fileTerms) {
|
|
2354
|
+
matchWhere.push("(p.file_path = ? OR p.file_path LIKE ? ESCAPE '\\')");
|
|
2355
|
+
whereParams.push(term, `%${escapeLike(term)}%`);
|
|
2356
|
+
}
|
|
2357
|
+
for (const term of toolTerms) {
|
|
2358
|
+
matchWhere.push("p.tool_name LIKE ? ESCAPE '\\'");
|
|
2359
|
+
whereParams.push(`%${escapeLike(term)}%`);
|
|
2360
|
+
}
|
|
2361
|
+
const where = [`(${matchWhere.join(" OR ")})`];
|
|
2362
|
+
if (sessionId) {
|
|
2363
|
+
where.push("m.session_id = ?");
|
|
2364
|
+
whereParams.push(sessionId);
|
|
2365
|
+
}
|
|
2366
|
+
const exactFileScoreParams = [...fileTerms];
|
|
2367
|
+
const sqlParams = [...exactFileScoreParams, ...whereParams, cappedLimit];
|
|
2368
|
+
const rows = this.db.prepare(`
|
|
2369
|
+
SELECT
|
|
2370
|
+
p.id AS part_id,
|
|
2371
|
+
p.message_id AS message_id,
|
|
2372
|
+
m.turn_index AS turn_index,
|
|
2373
|
+
m.role AS role,
|
|
2374
|
+
m.content AS content,
|
|
2375
|
+
m.session_id AS session_id,
|
|
2376
|
+
p.kind AS kind,
|
|
2377
|
+
p.tool_name AS tool_name,
|
|
2378
|
+
p.file_path AS file_path,
|
|
2379
|
+
p.payload AS payload,
|
|
2380
|
+
CASE
|
|
2381
|
+
WHEN p.file_path IN (${fileTerms.map(() => "?").join(",") || "NULL"}) THEN 3
|
|
2382
|
+
WHEN p.file_path IS NOT NULL THEN 2
|
|
2383
|
+
WHEN p.tool_name IS NOT NULL THEN 1
|
|
2384
|
+
ELSE 0
|
|
2385
|
+
END AS score
|
|
2386
|
+
FROM lcm_message_parts p
|
|
2387
|
+
JOIN lcm_messages m ON m.id = p.message_id
|
|
2388
|
+
WHERE ${where.join(" AND ")}
|
|
2389
|
+
ORDER BY score DESC, m.turn_index DESC, p.ordinal ASC
|
|
2390
|
+
LIMIT ?
|
|
2391
|
+
`).all(...sqlParams);
|
|
2392
|
+
return rows;
|
|
2393
|
+
}
|
|
1871
2394
|
/** Get total message count for a session. */
|
|
1872
2395
|
getMessageCount(sessionId) {
|
|
1873
2396
|
const row = this.db.prepare("SELECT COUNT(*) as cnt FROM lcm_messages WHERE session_id = ?").get(sessionId);
|
|
@@ -2019,6 +2542,72 @@ var STOPWORDS = /* @__PURE__ */ new Set([
|
|
|
2019
2542
|
"we",
|
|
2020
2543
|
"they"
|
|
2021
2544
|
]);
|
|
2545
|
+
function extractStructuredFileTerms(query) {
|
|
2546
|
+
const terms = /* @__PURE__ */ new Set();
|
|
2547
|
+
for (const raw of splitQueryTerms(query)) {
|
|
2548
|
+
const cleaned = trimStructuredQueryTerm(raw);
|
|
2549
|
+
if (cleaned.includes("/") || hasStructuredFileExtension(cleaned)) {
|
|
2550
|
+
terms.add(cleaned);
|
|
2551
|
+
const basename = cleaned.split("/").pop();
|
|
2552
|
+
if (basename && basename !== cleaned) terms.add(basename);
|
|
2553
|
+
}
|
|
2554
|
+
}
|
|
2555
|
+
return [...terms].filter((term) => term.length > 1).slice(0, 12);
|
|
2556
|
+
}
|
|
2557
|
+
function splitQueryTerms(query) {
|
|
2558
|
+
const terms = [];
|
|
2559
|
+
let term = "";
|
|
2560
|
+
for (const char of query.slice(0, 2e4)) {
|
|
2561
|
+
if (char === " " || char === "\n" || char === "\r" || char === " ") {
|
|
2562
|
+
if (term.length > 0) terms.push(term);
|
|
2563
|
+
term = "";
|
|
2564
|
+
continue;
|
|
2565
|
+
}
|
|
2566
|
+
term += char;
|
|
2567
|
+
if (term.length > 512) {
|
|
2568
|
+
terms.push(term);
|
|
2569
|
+
term = "";
|
|
2570
|
+
}
|
|
2571
|
+
}
|
|
2572
|
+
if (term.length > 0) terms.push(term);
|
|
2573
|
+
return terms;
|
|
2574
|
+
}
|
|
2575
|
+
function trimStructuredQueryTerm(raw) {
|
|
2576
|
+
const leading = /* @__PURE__ */ new Set(["`", "'", '"', "(", "[", "{"]);
|
|
2577
|
+
const trailing = /* @__PURE__ */ new Set(["`", "'", '"', ",", ".", "?", "!", ":", ";", ")", "]", "}"]);
|
|
2578
|
+
let start = 0;
|
|
2579
|
+
let end = raw.length;
|
|
2580
|
+
while (start < end && leading.has(raw[start])) start += 1;
|
|
2581
|
+
while (end > start && trailing.has(raw[end - 1])) end -= 1;
|
|
2582
|
+
return raw.slice(start, end);
|
|
2583
|
+
}
|
|
2584
|
+
function hasStructuredFileExtension(value) {
|
|
2585
|
+
const slash = value.lastIndexOf("/");
|
|
2586
|
+
const basename = value.slice(slash + 1);
|
|
2587
|
+
const dot = basename.lastIndexOf(".");
|
|
2588
|
+
if (dot <= 0 || dot === basename.length - 1) return false;
|
|
2589
|
+
const ext = basename.slice(dot + 1);
|
|
2590
|
+
if (ext.length < 1 || ext.length > 12) return false;
|
|
2591
|
+
for (const char of ext) {
|
|
2592
|
+
const code = char.charCodeAt(0);
|
|
2593
|
+
const valid = code >= 48 && code <= 57 || code >= 65 && code <= 90 || code >= 97 && code <= 122 || char === "_" || char === "+" || char === "-";
|
|
2594
|
+
if (!valid) return false;
|
|
2595
|
+
}
|
|
2596
|
+
return true;
|
|
2597
|
+
}
|
|
2598
|
+
function extractStructuredToolTerms(query) {
|
|
2599
|
+
const lower = query.toLowerCase();
|
|
2600
|
+
if (!/\b(tool|command|invocation|called|used|ran|read|write|patch|edit|grep|search)\b/.test(lower)) {
|
|
2601
|
+
return [];
|
|
2602
|
+
}
|
|
2603
|
+
return query.replace(/[^\w.-]/g, " ").split(/\s+/).filter((term) => term.length > 2 && !STOPWORDS.has(term.toLowerCase())).slice(0, 8);
|
|
2604
|
+
}
|
|
2605
|
+
function escapeLike(value) {
|
|
2606
|
+
return value.replace(/[\\%_]/g, (char) => `\\${char}`);
|
|
2607
|
+
}
|
|
2608
|
+
function asNullableString(value) {
|
|
2609
|
+
return typeof value === "string" && value.trim().length > 0 ? value : null;
|
|
2610
|
+
}
|
|
2022
2611
|
function sanitizeFtsQuery(raw) {
|
|
2023
2612
|
const words = raw.replace(/[^\w\s]/g, " ").split(/\s+/).filter((w) => w.length > 1 && !STOPWORDS.has(w.toLowerCase()));
|
|
2024
2613
|
if (words.length === 0) {
|
|
@@ -2488,7 +3077,9 @@ function extractLcmConfig(cfg) {
|
|
|
2488
3077
|
maxDepth: cfg.lcmMaxDepth ?? 5,
|
|
2489
3078
|
deterministicMaxTokens: cfg.lcmDeterministicMaxTokens ?? 512,
|
|
2490
3079
|
archiveRetentionDays: cfg.lcmArchiveRetentionDays ?? 90,
|
|
2491
|
-
recallBudgetShare: cfg.lcmRecallBudgetShare ?? 0.15
|
|
3080
|
+
recallBudgetShare: cfg.lcmRecallBudgetShare ?? 0.15,
|
|
3081
|
+
messagePartsEnabled: cfg.messagePartsEnabled === true,
|
|
3082
|
+
messagePartsRecallMaxResults: typeof cfg.messagePartsRecallMaxResults === "number" ? Math.max(0, Math.floor(cfg.messagePartsRecallMaxResults)) : 6
|
|
2492
3083
|
};
|
|
2493
3084
|
}
|
|
2494
3085
|
var LcmEngine = class {
|
|
@@ -2620,9 +3211,14 @@ var LcmEngine = class {
|
|
|
2620
3211
|
const newMessages = messages.map((m, i) => ({
|
|
2621
3212
|
turnIndex: currentMax + 1 + i,
|
|
2622
3213
|
role: m.role,
|
|
2623
|
-
content: m.content
|
|
3214
|
+
content: m.content,
|
|
3215
|
+
parts: this.config.messagePartsEnabled ? m.parts : void 0,
|
|
3216
|
+
rawContent: this.config.messagePartsEnabled ? m.rawContent : void 0,
|
|
3217
|
+
sourceFormat: this.config.messagePartsEnabled ? m.sourceFormat : void 0
|
|
2624
3218
|
}));
|
|
2625
|
-
this.archive.appendMessages(sessionId, newMessages
|
|
3219
|
+
this.archive.appendMessages(sessionId, newMessages, {
|
|
3220
|
+
messagePartsEnabled: this.config.messagePartsEnabled
|
|
3221
|
+
});
|
|
2626
3222
|
try {
|
|
2627
3223
|
await this.summarizer.summarizeIncremental(sessionId);
|
|
2628
3224
|
} catch (err) {
|
|
@@ -2700,6 +3296,28 @@ var LcmEngine = class {
|
|
|
2700
3296
|
budgetChars: effectiveBudget
|
|
2701
3297
|
});
|
|
2702
3298
|
}
|
|
3299
|
+
async searchStructuredParts(sessionId, query, limit = this.config.messagePartsRecallMaxResults) {
|
|
3300
|
+
if (!this.config.enabled || !this.config.messagePartsEnabled) return [];
|
|
3301
|
+
await this.ensureInitialized();
|
|
3302
|
+
if (!this.archive) return [];
|
|
3303
|
+
return this.archive.searchStructuredParts(query, limit, sessionId);
|
|
3304
|
+
}
|
|
3305
|
+
formatStructuredRecall(matches, budgetChars) {
|
|
3306
|
+
if (matches.length === 0 || budgetChars <= 0) return "";
|
|
3307
|
+
const lines = [];
|
|
3308
|
+
let used = "## Structured Session Matches\n\n".length;
|
|
3309
|
+
for (const match of matches) {
|
|
3310
|
+
const label = match.file_path ? `${match.kind} ${match.file_path}` : match.tool_name ? `${match.kind} ${match.tool_name}` : match.kind;
|
|
3311
|
+
const excerpt = match.content.replace(/\s+/g, " ").slice(0, 220);
|
|
3312
|
+
const line = `- turn ${match.turn_index} (${match.role}): ${label} \u2014 ${excerpt}`;
|
|
3313
|
+
if (used + line.length + 1 > budgetChars) break;
|
|
3314
|
+
lines.push(line);
|
|
3315
|
+
used += line.length + 1;
|
|
3316
|
+
}
|
|
3317
|
+
return lines.length > 0 ? `## Structured Session Matches
|
|
3318
|
+
|
|
3319
|
+
${lines.join("\n")}` : "";
|
|
3320
|
+
}
|
|
2703
3321
|
/** Flush pending summaries before compaction (called from before_compaction hook). */
|
|
2704
3322
|
async preCompactionFlush(sessionId) {
|
|
2705
3323
|
if (!this.config.enabled) return;
|
|
@@ -4933,7 +5551,7 @@ ${doc.content}` : doc.content,
|
|
|
4933
5551
|
}
|
|
4934
5552
|
async runDeepSleepGovernanceNow(options) {
|
|
4935
5553
|
const targetStorage = options?.storage ?? this.storage;
|
|
4936
|
-
const { runMemoryGovernance } = await import("./memory-governance-
|
|
5554
|
+
const { runMemoryGovernance } = await import("./memory-governance-KXMAURFF.js");
|
|
4937
5555
|
const { summarizeGovernanceResultForDreams } = await import("./dreams-ledger-LR2NBAZE.js");
|
|
4938
5556
|
const govResult = await runMemoryGovernance({
|
|
4939
5557
|
memoryDir: targetStorage.dir,
|
|
@@ -7027,6 +7645,7 @@ ${r.snippet.trim()}
|
|
|
7027
7645
|
let recalledMemoryIds = [];
|
|
7028
7646
|
let recalledMemoryPaths = [];
|
|
7029
7647
|
let xrayRecalledResults = [];
|
|
7648
|
+
const lcmStructuredXrayResults = [];
|
|
7030
7649
|
const xrayBranchPoolSize = {
|
|
7031
7650
|
hot_qmd: 0,
|
|
7032
7651
|
hot_embedding: 0,
|
|
@@ -8950,6 +9569,32 @@ ${tmtNode.summary}`
|
|
|
8950
9569
|
}
|
|
8951
9570
|
if (this.lcmEngine?.enabled && recallMode !== "minimal" && recallMode !== "no_recall") {
|
|
8952
9571
|
try {
|
|
9572
|
+
const structuredMatches = await this.lcmEngine.searchStructuredParts(
|
|
9573
|
+
sessionKey ?? "default",
|
|
9574
|
+
retrievalQuery
|
|
9575
|
+
);
|
|
9576
|
+
const structuredSection = this.lcmEngine.formatStructuredRecall(
|
|
9577
|
+
structuredMatches,
|
|
9578
|
+
Math.ceil(this.config.recallBudgetChars * 0.08)
|
|
9579
|
+
);
|
|
9580
|
+
if (structuredSection) {
|
|
9581
|
+
const structuredAppended = this.appendRecallSection(
|
|
9582
|
+
sectionBuckets,
|
|
9583
|
+
"lcm-message-parts",
|
|
9584
|
+
structuredSection
|
|
9585
|
+
);
|
|
9586
|
+
if (structuredAppended) {
|
|
9587
|
+
for (const match of structuredMatches) {
|
|
9588
|
+
lcmStructuredXrayResults.push({
|
|
9589
|
+
memoryId: `lcm-message-part-${match.part_id}`,
|
|
9590
|
+
path: `lcm://${match.session_id}/turn/${match.turn_index}/part/${match.part_id}`,
|
|
9591
|
+
servedBy: match.file_path ? "lcm-file-parts" : "lcm-tool-parts",
|
|
9592
|
+
scoreDecomposition: { final: match.score },
|
|
9593
|
+
admittedBy: ["lcm-message-parts"]
|
|
9594
|
+
});
|
|
9595
|
+
}
|
|
9596
|
+
}
|
|
9597
|
+
}
|
|
8953
9598
|
const lcmSection = await this.lcmEngine.assembleRecall(
|
|
8954
9599
|
sessionKey ?? "default",
|
|
8955
9600
|
this.config.recallBudgetChars
|
|
@@ -9850,10 +10495,17 @@ _Context: ${topQuestion.context}_`
|
|
|
9850
10495
|
admitted: recalledMemoryIds.length
|
|
9851
10496
|
}
|
|
9852
10497
|
];
|
|
10498
|
+
if (lcmStructuredXrayResults.length > 0) {
|
|
10499
|
+
filters.push({
|
|
10500
|
+
name: "lcm-message-parts",
|
|
10501
|
+
considered: lcmStructuredXrayResults.length,
|
|
10502
|
+
admitted: lcmStructuredXrayResults.length
|
|
10503
|
+
});
|
|
10504
|
+
}
|
|
9853
10505
|
this.lastXraySnapshot = buildXraySnapshot({
|
|
9854
10506
|
query: retrievalQuery,
|
|
9855
10507
|
tierExplain: null,
|
|
9856
|
-
results,
|
|
10508
|
+
results: [...results, ...lcmStructuredXrayResults],
|
|
9857
10509
|
filters,
|
|
9858
10510
|
budget: {
|
|
9859
10511
|
chars: this.getRecallBudgetChars(options.budgetCharsOverride),
|
|
@@ -10020,13 +10672,28 @@ _Context: ${topQuestion.context}_`
|
|
|
10020
10672
|
role: turn.role,
|
|
10021
10673
|
content: turn.content,
|
|
10022
10674
|
timestamp: turn.timestamp,
|
|
10023
|
-
sessionKey: key
|
|
10675
|
+
sessionKey: key,
|
|
10676
|
+
parts: turn.parts,
|
|
10677
|
+
rawContent: turn.rawContent,
|
|
10678
|
+
sourceFormat: turn.sourceFormat
|
|
10024
10679
|
});
|
|
10025
10680
|
bySession.set(key, list);
|
|
10026
10681
|
}
|
|
10027
10682
|
const replayTasks = [];
|
|
10028
10683
|
for (const [key, sessionTurns] of bySession.entries()) {
|
|
10029
10684
|
if (sessionTurns.length === 0) continue;
|
|
10685
|
+
if (options.archiveLcm !== false && this.lcmEngine?.enabled) {
|
|
10686
|
+
await this.lcmEngine.observeMessages(
|
|
10687
|
+
key,
|
|
10688
|
+
sessionTurns.map((turn) => ({
|
|
10689
|
+
role: turn.role,
|
|
10690
|
+
content: turn.content,
|
|
10691
|
+
parts: turn.parts,
|
|
10692
|
+
rawContent: turn.rawContent,
|
|
10693
|
+
sourceFormat: turn.sourceFormat
|
|
10694
|
+
}))
|
|
10695
|
+
);
|
|
10696
|
+
}
|
|
10030
10697
|
replayTasks.push(
|
|
10031
10698
|
new Promise((resolve, reject) => {
|
|
10032
10699
|
void this.queueBufferedExtraction(sessionTurns, "trigger_mode", {
|
|
@@ -10115,10 +10782,25 @@ _Context: ${topQuestion.context}_`
|
|
|
10115
10782
|
role: turn.role,
|
|
10116
10783
|
content: turn.content,
|
|
10117
10784
|
timestamp: turn.timestamp,
|
|
10118
|
-
sessionKey
|
|
10785
|
+
sessionKey,
|
|
10786
|
+
parts: turn.parts,
|
|
10787
|
+
rawContent: turn.rawContent,
|
|
10788
|
+
sourceFormat: turn.sourceFormat
|
|
10119
10789
|
});
|
|
10120
10790
|
}
|
|
10121
10791
|
if (sessionTurns.length === 0) return;
|
|
10792
|
+
if (this.lcmEngine?.enabled) {
|
|
10793
|
+
await this.lcmEngine.observeMessages(
|
|
10794
|
+
sessionKey,
|
|
10795
|
+
sessionTurns.map((turn) => ({
|
|
10796
|
+
role: turn.role,
|
|
10797
|
+
content: turn.content,
|
|
10798
|
+
parts: turn.parts,
|
|
10799
|
+
rawContent: turn.rawContent,
|
|
10800
|
+
sourceFormat: turn.sourceFormat
|
|
10801
|
+
}))
|
|
10802
|
+
);
|
|
10803
|
+
}
|
|
10122
10804
|
await new Promise((resolve, reject) => {
|
|
10123
10805
|
void this.queueBufferedExtraction(sessionTurns, "trigger_mode", {
|
|
10124
10806
|
skipDedupeCheck: true,
|
|
@@ -14040,6 +14722,13 @@ export {
|
|
|
14040
14722
|
openLcmDatabase,
|
|
14041
14723
|
ensureLcmStateDir,
|
|
14042
14724
|
applyLcmSchema,
|
|
14725
|
+
isLcmMessagePartKind,
|
|
14726
|
+
parseMessageParts,
|
|
14727
|
+
normalizeExplicitParts,
|
|
14728
|
+
parseOpenAiMessageParts,
|
|
14729
|
+
parseAnthropicMessageParts,
|
|
14730
|
+
parseOpenClawMessageParts,
|
|
14731
|
+
partsFromRenderedText,
|
|
14043
14732
|
projectNamespaceName,
|
|
14044
14733
|
branchNamespaceName,
|
|
14045
14734
|
resolveCodingNamespaceOverlay,
|
|
@@ -14072,4 +14761,4 @@ export {
|
|
|
14072
14761
|
resolvePersistedMemoryRelativePath,
|
|
14073
14762
|
Orchestrator
|
|
14074
14763
|
};
|
|
14075
|
-
//# sourceMappingURL=chunk-
|
|
14764
|
+
//# sourceMappingURL=chunk-7NFZWXAY.js.map
|