@agentmemory/agentmemory 0.8.6 → 0.8.8
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/README.md +5 -9
- package/dist/cli.mjs +4 -4
- package/dist/index.mjs +281 -157
- package/dist/index.mjs.map +1 -1
- package/dist/{src-DjVaT_sI.mjs → src-CneY0pgf.mjs} +279 -158
- package/dist/src-CneY0pgf.mjs.map +1 -0
- package/dist/{standalone-C7tRDaiu.mjs → standalone-Qmvspmgi.mjs} +2 -2
- package/dist/{standalone-C7tRDaiu.mjs.map → standalone-Qmvspmgi.mjs.map} +1 -1
- package/dist/standalone.mjs +1 -1
- package/dist/standalone.mjs.map +1 -1
- package/dist/{tools-registry-BYzapMJi.mjs → tools-registry-BuDo4gKj.mjs} +6 -3
- package/dist/tools-registry-BuDo4gKj.mjs.map +1 -0
- package/iii-config.docker.yaml +51 -0
- package/package.json +2 -1
- package/plugin/.claude-plugin/plugin.json +1 -1
- package/dist/src-DjVaT_sI.mjs.map +0 -1
- package/dist/tools-registry-BYzapMJi.mjs.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as jaccardSimilarity, i as generateId, n as STREAM, r as fingerprintId, t as KV } from "./cli.mjs";
|
|
2
|
-
import { a as getEnvVar, c as
|
|
2
|
+
import { a as getEnvVar, c as isConsolidationEnabled, d as loadConfig, f as loadEmbeddingConfig, h as loadTeamConfig, i as getConsolidationDecayDays, l as isGraphExtractionEnabled, m as loadSnapshotConfig, n as VERSION, p as loadFallbackConfig, r as detectEmbeddingProvider, s as isAutoCompressEnabled, t as getVisibleTools, u as loadClaudeBridgeConfig } from "./tools-registry-BuDo4gKj.mjs";
|
|
3
3
|
import { execFile } from "node:child_process";
|
|
4
4
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
5
5
|
import { dirname, join, resolve, sep } from "node:path";
|
|
@@ -1777,164 +1777,95 @@ function withKeyedLock(key, fn) {
|
|
|
1777
1777
|
}
|
|
1778
1778
|
|
|
1779
1779
|
//#endregion
|
|
1780
|
-
//#region src/functions/
|
|
1781
|
-
function
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
}
|
|
1842
|
-
});
|
|
1843
|
-
sdk.triggerVoid("stream::set", {
|
|
1844
|
-
stream_name: STREAM.name,
|
|
1845
|
-
group_id: STREAM.viewerGroup,
|
|
1846
|
-
item_id: obsId,
|
|
1847
|
-
data: {
|
|
1848
|
-
type: "raw",
|
|
1849
|
-
observation: raw,
|
|
1850
|
-
sessionId: payload.sessionId
|
|
1851
|
-
}
|
|
1852
|
-
});
|
|
1853
|
-
const session = await kv.get(KV.sessions, payload.sessionId);
|
|
1854
|
-
if (session) await kv.set(KV.sessions, payload.sessionId, {
|
|
1855
|
-
...session,
|
|
1856
|
-
observationCount: (session.observationCount || 0) + 1
|
|
1857
|
-
});
|
|
1858
|
-
sdk.triggerVoid("mem::compress", {
|
|
1859
|
-
observationId: obsId,
|
|
1860
|
-
sessionId: payload.sessionId,
|
|
1861
|
-
raw
|
|
1862
|
-
});
|
|
1863
|
-
ctx.logger.info("Observation captured", {
|
|
1864
|
-
obsId,
|
|
1865
|
-
sessionId: payload.sessionId,
|
|
1866
|
-
hook: payload.hookType
|
|
1867
|
-
});
|
|
1868
|
-
return { observationId: obsId };
|
|
1869
|
-
});
|
|
1870
|
-
});
|
|
1871
|
-
}
|
|
1872
|
-
|
|
1873
|
-
//#endregion
|
|
1874
|
-
//#region src/prompts/compression.ts
|
|
1875
|
-
const COMPRESSION_SYSTEM = `You are a memory compression engine for an AI coding agent. Your job is to extract the essential information from a tool usage observation and compress it into structured data.
|
|
1876
|
-
|
|
1877
|
-
Output EXACTLY this XML format with no additional text:
|
|
1878
|
-
|
|
1879
|
-
<observation>
|
|
1880
|
-
<type>one of: file_read, file_write, file_edit, command_run, search, web_fetch, conversation, error, decision, discovery, subagent, notification, task, other</type>
|
|
1881
|
-
<title>Short descriptive title (max 80 chars)</title>
|
|
1882
|
-
<subtitle>One-line context (optional)</subtitle>
|
|
1883
|
-
<facts>
|
|
1884
|
-
<fact>Specific factual detail 1</fact>
|
|
1885
|
-
<fact>Specific factual detail 2</fact>
|
|
1886
|
-
</facts>
|
|
1887
|
-
<narrative>2-3 sentence summary of what happened and why it matters</narrative>
|
|
1888
|
-
<concepts>
|
|
1889
|
-
<concept>technical concept or pattern</concept>
|
|
1890
|
-
</concepts>
|
|
1891
|
-
<files>
|
|
1892
|
-
<file>path/to/file</file>
|
|
1893
|
-
</files>
|
|
1894
|
-
<importance>1-10 scale, 10 being critical architectural decision</importance>
|
|
1895
|
-
</observation>
|
|
1896
|
-
|
|
1897
|
-
Rules:
|
|
1898
|
-
- Be concise but preserve ALL technically relevant details
|
|
1899
|
-
- File paths must be exact
|
|
1900
|
-
- Importance: 1-3 for routine reads, 4-6 for edits/commands, 7-9 for architectural decisions, 10 for breaking changes
|
|
1901
|
-
- Concepts should be reusable search terms (e.g., "React hooks", "SQL migration", "auth middleware")
|
|
1902
|
-
- Strip any secrets, tokens, or credentials from the output`;
|
|
1903
|
-
function buildCompressionPrompt(observation) {
|
|
1904
|
-
const parts = [`Timestamp: ${observation.timestamp}`, `Hook: ${observation.hookType}`];
|
|
1905
|
-
if (observation.toolName) parts.push(`Tool: ${observation.toolName}`);
|
|
1906
|
-
if (observation.toolInput) {
|
|
1907
|
-
const input = typeof observation.toolInput === "string" ? observation.toolInput : JSON.stringify(observation.toolInput, null, 2);
|
|
1908
|
-
parts.push(`Input:\n${truncate(input, 4e3)}`);
|
|
1909
|
-
}
|
|
1910
|
-
if (observation.toolOutput) {
|
|
1911
|
-
const output = typeof observation.toolOutput === "string" ? observation.toolOutput : JSON.stringify(observation.toolOutput, null, 2);
|
|
1912
|
-
parts.push(`Output:\n${truncate(output, 4e3)}`);
|
|
1780
|
+
//#region src/functions/compress-synthetic.ts
|
|
1781
|
+
function inferType(toolName, hookType) {
|
|
1782
|
+
if (hookType === "post_tool_failure") return "error";
|
|
1783
|
+
if (hookType === "prompt_submit") return "conversation";
|
|
1784
|
+
if (hookType === "subagent_stop" || hookType === "task_completed") return "subagent";
|
|
1785
|
+
if (hookType === "notification") return "notification";
|
|
1786
|
+
if (!toolName) return "other";
|
|
1787
|
+
const n = toolName.replace(/([a-z])([A-Z])/g, "$1_$2").replace(/[-\s]+/g, "_").toLowerCase();
|
|
1788
|
+
const hasWord = (word) => new RegExp(`(^|_)${word}(_|$)`).test(n) || n === word || n.endsWith(word) || n.startsWith(word);
|
|
1789
|
+
if ([
|
|
1790
|
+
"fetch",
|
|
1791
|
+
"http",
|
|
1792
|
+
"web"
|
|
1793
|
+
].some(hasWord)) return "web_fetch";
|
|
1794
|
+
if ([
|
|
1795
|
+
"grep",
|
|
1796
|
+
"search",
|
|
1797
|
+
"glob",
|
|
1798
|
+
"find"
|
|
1799
|
+
].some(hasWord)) return "search";
|
|
1800
|
+
if ([
|
|
1801
|
+
"bash",
|
|
1802
|
+
"shell",
|
|
1803
|
+
"exec",
|
|
1804
|
+
"run"
|
|
1805
|
+
].some(hasWord)) return "command_run";
|
|
1806
|
+
if ([
|
|
1807
|
+
"edit",
|
|
1808
|
+
"update",
|
|
1809
|
+
"patch",
|
|
1810
|
+
"replace"
|
|
1811
|
+
].some(hasWord)) return "file_edit";
|
|
1812
|
+
if (["write", "create"].some(hasWord)) return "file_write";
|
|
1813
|
+
if (["read", "view"].some(hasWord)) return "file_read";
|
|
1814
|
+
if (["task", "agent"].some(hasWord)) return "subagent";
|
|
1815
|
+
return "other";
|
|
1816
|
+
}
|
|
1817
|
+
function extractFiles$1(input) {
|
|
1818
|
+
if (!input || typeof input !== "object") return [];
|
|
1819
|
+
const o = input;
|
|
1820
|
+
const out = /* @__PURE__ */ new Set();
|
|
1821
|
+
for (const key of [
|
|
1822
|
+
"file_path",
|
|
1823
|
+
"filepath",
|
|
1824
|
+
"path",
|
|
1825
|
+
"filePath",
|
|
1826
|
+
"file",
|
|
1827
|
+
"pattern"
|
|
1828
|
+
]) {
|
|
1829
|
+
const v = o[key];
|
|
1830
|
+
if (typeof v === "string" && v.length > 0 && v.length < 512) out.add(v);
|
|
1831
|
+
}
|
|
1832
|
+
return [...out];
|
|
1833
|
+
}
|
|
1834
|
+
function stringifyForNarrative(v) {
|
|
1835
|
+
if (v == null) return "";
|
|
1836
|
+
if (typeof v === "string") return v;
|
|
1837
|
+
try {
|
|
1838
|
+
return JSON.stringify(v);
|
|
1839
|
+
} catch {
|
|
1840
|
+
return String(v);
|
|
1913
1841
|
}
|
|
1914
|
-
if (observation.userPrompt) parts.push(`User prompt:\n${truncate(observation.userPrompt, 2e3)}`);
|
|
1915
|
-
return parts.join("\n\n");
|
|
1916
|
-
}
|
|
1917
|
-
function truncate(s, max) {
|
|
1918
|
-
return s.length > max ? s.slice(0, max) + "\n[...truncated]" : s;
|
|
1919
1842
|
}
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
//#region src/prompts/xml.ts
|
|
1923
|
-
const VALID_TAG = /^[a-zA-Z_][a-zA-Z0-9_-]*$/;
|
|
1924
|
-
function getXmlTag(xml, tag) {
|
|
1925
|
-
if (!VALID_TAG.test(tag)) return "";
|
|
1926
|
-
const match = xml.match(new RegExp(`<${tag}>([\\s\\S]*?)</${tag}>`));
|
|
1927
|
-
return match ? match[1].trim() : "";
|
|
1843
|
+
function truncate$1(s, n) {
|
|
1844
|
+
return s.length > n ? s.slice(0, n - 1) + "…" : s;
|
|
1928
1845
|
}
|
|
1929
|
-
function
|
|
1930
|
-
|
|
1931
|
-
const
|
|
1932
|
-
|
|
1933
|
-
const
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1846
|
+
function buildSyntheticCompression(raw) {
|
|
1847
|
+
const toolName = raw.toolName ?? raw.hookType;
|
|
1848
|
+
const inputStr = stringifyForNarrative(raw.toolInput);
|
|
1849
|
+
const outputStr = stringifyForNarrative(raw.toolOutput);
|
|
1850
|
+
const narrativeParts = [
|
|
1851
|
+
raw.userPrompt ?? "",
|
|
1852
|
+
inputStr,
|
|
1853
|
+
outputStr
|
|
1854
|
+
].filter((s) => s.length > 0);
|
|
1855
|
+
return {
|
|
1856
|
+
id: raw.id,
|
|
1857
|
+
sessionId: raw.sessionId,
|
|
1858
|
+
timestamp: raw.timestamp,
|
|
1859
|
+
type: inferType(toolName, raw.hookType),
|
|
1860
|
+
title: truncate$1(toolName || "observation", 80),
|
|
1861
|
+
subtitle: inputStr ? truncate$1(inputStr, 120) : void 0,
|
|
1862
|
+
facts: [],
|
|
1863
|
+
narrative: truncate$1(narrativeParts.join(" | "), 400),
|
|
1864
|
+
concepts: [],
|
|
1865
|
+
files: extractFiles$1(raw.toolInput),
|
|
1866
|
+
importance: 5,
|
|
1867
|
+
confidence: .3
|
|
1868
|
+
};
|
|
1938
1869
|
}
|
|
1939
1870
|
|
|
1940
1871
|
//#endregion
|
|
@@ -2105,6 +2036,192 @@ function registerSearchFunction(sdk, kv) {
|
|
|
2105
2036
|
});
|
|
2106
2037
|
}
|
|
2107
2038
|
|
|
2039
|
+
//#endregion
|
|
2040
|
+
//#region src/functions/observe.ts
|
|
2041
|
+
function registerObserveFunction(sdk, kv, dedupMap, maxObservationsPerSession) {
|
|
2042
|
+
sdk.registerFunction({
|
|
2043
|
+
id: "mem::observe",
|
|
2044
|
+
description: "Capture and store a tool-use observation"
|
|
2045
|
+
}, async (payload) => {
|
|
2046
|
+
const ctx = getContext();
|
|
2047
|
+
if (!payload?.sessionId || typeof payload.sessionId !== "string" || !payload.hookType || typeof payload.hookType !== "string" || !payload.timestamp || typeof payload.timestamp !== "string") return {
|
|
2048
|
+
success: false,
|
|
2049
|
+
error: "Invalid payload: sessionId, hookType, and timestamp are required"
|
|
2050
|
+
};
|
|
2051
|
+
const obsId = generateId("obs");
|
|
2052
|
+
let dedupHash;
|
|
2053
|
+
if (dedupMap) {
|
|
2054
|
+
const d = typeof payload.data === "object" && payload.data !== null ? payload.data : {};
|
|
2055
|
+
const toolName = d["tool_name"] || payload.hookType;
|
|
2056
|
+
dedupHash = dedupMap.computeHash(payload.sessionId, toolName, d["tool_input"]);
|
|
2057
|
+
if (dedupMap.isDuplicate(dedupHash)) return {
|
|
2058
|
+
deduplicated: true,
|
|
2059
|
+
sessionId: payload.sessionId
|
|
2060
|
+
};
|
|
2061
|
+
}
|
|
2062
|
+
let sanitizedRaw = payload.data;
|
|
2063
|
+
try {
|
|
2064
|
+
const sanitized = stripPrivateData(JSON.stringify(payload.data));
|
|
2065
|
+
sanitizedRaw = JSON.parse(sanitized);
|
|
2066
|
+
} catch {
|
|
2067
|
+
sanitizedRaw = stripPrivateData(String(payload.data));
|
|
2068
|
+
}
|
|
2069
|
+
const raw = {
|
|
2070
|
+
id: obsId,
|
|
2071
|
+
sessionId: payload.sessionId,
|
|
2072
|
+
timestamp: payload.timestamp,
|
|
2073
|
+
hookType: payload.hookType,
|
|
2074
|
+
raw: sanitizedRaw
|
|
2075
|
+
};
|
|
2076
|
+
if (typeof sanitizedRaw === "object" && sanitizedRaw !== null) {
|
|
2077
|
+
const d = sanitizedRaw;
|
|
2078
|
+
if (payload.hookType === "post_tool_use" || payload.hookType === "post_tool_failure") {
|
|
2079
|
+
raw.toolName = d["tool_name"];
|
|
2080
|
+
raw.toolInput = d["tool_input"];
|
|
2081
|
+
raw.toolOutput = d["tool_output"] || d["error"];
|
|
2082
|
+
}
|
|
2083
|
+
if (payload.hookType === "prompt_submit") raw.userPrompt = d["prompt"];
|
|
2084
|
+
}
|
|
2085
|
+
return withKeyedLock(`obs:${payload.sessionId}`, async () => {
|
|
2086
|
+
if (maxObservationsPerSession && maxObservationsPerSession > 0) {
|
|
2087
|
+
if ((await kv.list(KV.observations(payload.sessionId))).length >= maxObservationsPerSession) return {
|
|
2088
|
+
success: false,
|
|
2089
|
+
error: `Session observation limit reached (${maxObservationsPerSession})`
|
|
2090
|
+
};
|
|
2091
|
+
}
|
|
2092
|
+
await kv.set(KV.observations(payload.sessionId), obsId, raw);
|
|
2093
|
+
if (dedupMap && dedupHash) dedupMap.record(dedupHash);
|
|
2094
|
+
sdk.triggerVoid("stream::set", {
|
|
2095
|
+
stream_name: STREAM.name,
|
|
2096
|
+
group_id: STREAM.group(payload.sessionId),
|
|
2097
|
+
item_id: obsId,
|
|
2098
|
+
data: {
|
|
2099
|
+
type: "raw",
|
|
2100
|
+
observation: raw
|
|
2101
|
+
}
|
|
2102
|
+
});
|
|
2103
|
+
sdk.triggerVoid("stream::set", {
|
|
2104
|
+
stream_name: STREAM.name,
|
|
2105
|
+
group_id: STREAM.viewerGroup,
|
|
2106
|
+
item_id: obsId,
|
|
2107
|
+
data: {
|
|
2108
|
+
type: "raw",
|
|
2109
|
+
observation: raw,
|
|
2110
|
+
sessionId: payload.sessionId
|
|
2111
|
+
}
|
|
2112
|
+
});
|
|
2113
|
+
const session = await kv.get(KV.sessions, payload.sessionId);
|
|
2114
|
+
if (session) await kv.set(KV.sessions, payload.sessionId, {
|
|
2115
|
+
...session,
|
|
2116
|
+
observationCount: (session.observationCount || 0) + 1
|
|
2117
|
+
});
|
|
2118
|
+
if (isAutoCompressEnabled()) sdk.triggerVoid("mem::compress", {
|
|
2119
|
+
observationId: obsId,
|
|
2120
|
+
sessionId: payload.sessionId,
|
|
2121
|
+
raw
|
|
2122
|
+
});
|
|
2123
|
+
else {
|
|
2124
|
+
const synthetic = buildSyntheticCompression(raw);
|
|
2125
|
+
await kv.set(KV.observations(payload.sessionId), obsId, synthetic);
|
|
2126
|
+
getSearchIndex().add(synthetic);
|
|
2127
|
+
sdk.triggerVoid("stream::set", {
|
|
2128
|
+
stream_name: STREAM.name,
|
|
2129
|
+
group_id: STREAM.group(payload.sessionId),
|
|
2130
|
+
item_id: obsId,
|
|
2131
|
+
data: {
|
|
2132
|
+
type: "compressed",
|
|
2133
|
+
observation: synthetic
|
|
2134
|
+
}
|
|
2135
|
+
});
|
|
2136
|
+
sdk.triggerVoid("stream::set", {
|
|
2137
|
+
stream_name: STREAM.name,
|
|
2138
|
+
group_id: STREAM.viewerGroup,
|
|
2139
|
+
item_id: obsId,
|
|
2140
|
+
data: {
|
|
2141
|
+
type: "compressed",
|
|
2142
|
+
observation: synthetic,
|
|
2143
|
+
sessionId: payload.sessionId
|
|
2144
|
+
}
|
|
2145
|
+
});
|
|
2146
|
+
}
|
|
2147
|
+
ctx.logger.info("Observation captured", {
|
|
2148
|
+
obsId,
|
|
2149
|
+
sessionId: payload.sessionId,
|
|
2150
|
+
hook: payload.hookType,
|
|
2151
|
+
compress: isAutoCompressEnabled() ? "llm" : "synthetic"
|
|
2152
|
+
});
|
|
2153
|
+
return { observationId: obsId };
|
|
2154
|
+
});
|
|
2155
|
+
});
|
|
2156
|
+
}
|
|
2157
|
+
|
|
2158
|
+
//#endregion
|
|
2159
|
+
//#region src/prompts/compression.ts
|
|
2160
|
+
const COMPRESSION_SYSTEM = `You are a memory compression engine for an AI coding agent. Your job is to extract the essential information from a tool usage observation and compress it into structured data.
|
|
2161
|
+
|
|
2162
|
+
Output EXACTLY this XML format with no additional text:
|
|
2163
|
+
|
|
2164
|
+
<observation>
|
|
2165
|
+
<type>one of: file_read, file_write, file_edit, command_run, search, web_fetch, conversation, error, decision, discovery, subagent, notification, task, other</type>
|
|
2166
|
+
<title>Short descriptive title (max 80 chars)</title>
|
|
2167
|
+
<subtitle>One-line context (optional)</subtitle>
|
|
2168
|
+
<facts>
|
|
2169
|
+
<fact>Specific factual detail 1</fact>
|
|
2170
|
+
<fact>Specific factual detail 2</fact>
|
|
2171
|
+
</facts>
|
|
2172
|
+
<narrative>2-3 sentence summary of what happened and why it matters</narrative>
|
|
2173
|
+
<concepts>
|
|
2174
|
+
<concept>technical concept or pattern</concept>
|
|
2175
|
+
</concepts>
|
|
2176
|
+
<files>
|
|
2177
|
+
<file>path/to/file</file>
|
|
2178
|
+
</files>
|
|
2179
|
+
<importance>1-10 scale, 10 being critical architectural decision</importance>
|
|
2180
|
+
</observation>
|
|
2181
|
+
|
|
2182
|
+
Rules:
|
|
2183
|
+
- Be concise but preserve ALL technically relevant details
|
|
2184
|
+
- File paths must be exact
|
|
2185
|
+
- Importance: 1-3 for routine reads, 4-6 for edits/commands, 7-9 for architectural decisions, 10 for breaking changes
|
|
2186
|
+
- Concepts should be reusable search terms (e.g., "React hooks", "SQL migration", "auth middleware")
|
|
2187
|
+
- Strip any secrets, tokens, or credentials from the output`;
|
|
2188
|
+
function buildCompressionPrompt(observation) {
|
|
2189
|
+
const parts = [`Timestamp: ${observation.timestamp}`, `Hook: ${observation.hookType}`];
|
|
2190
|
+
if (observation.toolName) parts.push(`Tool: ${observation.toolName}`);
|
|
2191
|
+
if (observation.toolInput) {
|
|
2192
|
+
const input = typeof observation.toolInput === "string" ? observation.toolInput : JSON.stringify(observation.toolInput, null, 2);
|
|
2193
|
+
parts.push(`Input:\n${truncate(input, 4e3)}`);
|
|
2194
|
+
}
|
|
2195
|
+
if (observation.toolOutput) {
|
|
2196
|
+
const output = typeof observation.toolOutput === "string" ? observation.toolOutput : JSON.stringify(observation.toolOutput, null, 2);
|
|
2197
|
+
parts.push(`Output:\n${truncate(output, 4e3)}`);
|
|
2198
|
+
}
|
|
2199
|
+
if (observation.userPrompt) parts.push(`User prompt:\n${truncate(observation.userPrompt, 2e3)}`);
|
|
2200
|
+
return parts.join("\n\n");
|
|
2201
|
+
}
|
|
2202
|
+
function truncate(s, max) {
|
|
2203
|
+
return s.length > max ? s.slice(0, max) + "\n[...truncated]" : s;
|
|
2204
|
+
}
|
|
2205
|
+
|
|
2206
|
+
//#endregion
|
|
2207
|
+
//#region src/prompts/xml.ts
|
|
2208
|
+
const VALID_TAG = /^[a-zA-Z_][a-zA-Z0-9_-]*$/;
|
|
2209
|
+
function getXmlTag(xml, tag) {
|
|
2210
|
+
if (!VALID_TAG.test(tag)) return "";
|
|
2211
|
+
const match = xml.match(new RegExp(`<${tag}>([\\s\\S]*?)</${tag}>`));
|
|
2212
|
+
return match ? match[1].trim() : "";
|
|
2213
|
+
}
|
|
2214
|
+
function getXmlChildren(xml, parentTag, childTag) {
|
|
2215
|
+
if (!VALID_TAG.test(parentTag) || !VALID_TAG.test(childTag)) return [];
|
|
2216
|
+
const parentMatch = xml.match(new RegExp(`<${parentTag}>([\\s\\S]*?)</${parentTag}>`));
|
|
2217
|
+
if (!parentMatch) return [];
|
|
2218
|
+
const items = [];
|
|
2219
|
+
const re = new RegExp(`<${childTag}>([\\s\\S]*?)</${childTag}>`, "g");
|
|
2220
|
+
let m;
|
|
2221
|
+
while ((m = re.exec(parentMatch[1])) !== null) items.push(m[1].trim());
|
|
2222
|
+
return items;
|
|
2223
|
+
}
|
|
2224
|
+
|
|
2108
2225
|
//#endregion
|
|
2109
2226
|
//#region src/eval/schemas.ts
|
|
2110
2227
|
const HookTypeEnum = z.enum([
|
|
@@ -3897,7 +4014,9 @@ function registerExportImportFunction(sdk, kv) {
|
|
|
3897
4014
|
"0.8.3",
|
|
3898
4015
|
"0.8.4",
|
|
3899
4016
|
"0.8.5",
|
|
3900
|
-
"0.8.6"
|
|
4017
|
+
"0.8.6",
|
|
4018
|
+
"0.8.7",
|
|
4019
|
+
"0.8.8"
|
|
3901
4020
|
]).has(importData.version)) return {
|
|
3902
4021
|
success: false,
|
|
3903
4022
|
error: `Unsupported export version: ${importData.version}`
|
|
@@ -13814,6 +13933,8 @@ async function main() {
|
|
|
13814
13933
|
}
|
|
13815
13934
|
registerConsolidationPipelineFunction(sdk, kv, provider);
|
|
13816
13935
|
console.log(`[agentmemory] Consolidation pipeline: registered (CONSOLIDATION_ENABLED=${isConsolidationEnabled() ? "true" : "false"})`);
|
|
13936
|
+
if (isAutoCompressEnabled()) console.log(`[agentmemory] WARNING: AGENTMEMORY_AUTO_COMPRESS=true — every PostToolUse observation will be sent to your LLM provider for compression. This spends API tokens proportional to your session tool-use frequency (see #138). Set AGENTMEMORY_AUTO_COMPRESS=false to disable.`);
|
|
13937
|
+
else console.log(`[agentmemory] Auto-compress: OFF (default, #138) — observations indexed via zero-LLM synthetic compression. Set AGENTMEMORY_AUTO_COMPRESS=true to opt-in to LLM-powered summaries (uses your API key).`);
|
|
13817
13938
|
const teamConfig = loadTeamConfig();
|
|
13818
13939
|
if (teamConfig) {
|
|
13819
13940
|
registerTeamFunction(sdk, kv, teamConfig);
|
|
@@ -13939,4 +14060,4 @@ main().catch((err) => {
|
|
|
13939
14060
|
|
|
13940
14061
|
//#endregion
|
|
13941
14062
|
export { };
|
|
13942
|
-
//# sourceMappingURL=src-
|
|
14063
|
+
//# sourceMappingURL=src-CneY0pgf.mjs.map
|