agenr 0.9.17 → 0.9.18
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/CHANGELOG.md +31 -0
- package/dist/cli-main.js +22 -270
- package/dist/openclaw-plugin/index.d.ts +2 -1
- package/dist/openclaw-plugin/index.js +590 -69
- package/openclaw.plugin.json +27 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,36 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.9.18 (2026-02-28)
|
|
4
|
+
|
|
5
|
+
### Features
|
|
6
|
+
- OpenClaw plugin: subsequent-turn auto-recall with heuristic message
|
|
7
|
+
classifier. Messages are classified as trivial (skip), normal (5 results),
|
|
8
|
+
or complex (8 results) based on entity detection, temporal references,
|
|
9
|
+
and explicit recall phrases. Queries built from a sliding window of
|
|
10
|
+
recent messages with Jaccard similarity dedup. Recalled entries are
|
|
11
|
+
deduplicated against session-start context. Configurable via
|
|
12
|
+
midSessionRecall plugin config.
|
|
13
|
+
|
|
14
|
+
### Bug Fixes
|
|
15
|
+
- MCP: fix stdout corruption during store and contradiction checks.
|
|
16
|
+
Diagnostic logs in db/store.ts and db/contradiction.ts were writing to
|
|
17
|
+
stdout via console.log, corrupting MCP JSON-RPC framing. Routed all
|
|
18
|
+
diagnostic logging to stderr via console.error.
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
- Removed agenr_store tool from MCP server. Coding agents should rely on
|
|
22
|
+
Watcher for knowledge ingest from session transcripts. Reduces MCP
|
|
23
|
+
surface area and eliminates stdout corruption risk.
|
|
24
|
+
- Removed store option from agenr_extract MCP tool. Extract now returns
|
|
25
|
+
extracted entries without storing them.
|
|
26
|
+
|
|
27
|
+
### Tests
|
|
28
|
+
- 16-case message classifier test suite
|
|
29
|
+
- Query builder, similarity check, and state management tests
|
|
30
|
+
- Integration tests for mid-session recall in before_prompt_build
|
|
31
|
+
- MCP stdout corruption test
|
|
32
|
+
- Updated MCP server tests for removed store tool and extract store option
|
|
33
|
+
|
|
3
34
|
## 0.9.17 - 2026-02-27
|
|
4
35
|
|
|
5
36
|
### Changed
|
package/dist/cli-main.js
CHANGED
|
@@ -5604,14 +5604,14 @@ async function classifyConflict(llmClient, newEntry, existing, model, config) {
|
|
|
5604
5604
|
verbose: false
|
|
5605
5605
|
});
|
|
5606
5606
|
if (response.stopReason === "error" || response.errorMessage) {
|
|
5607
|
-
console.
|
|
5607
|
+
console.error(
|
|
5608
5608
|
`[contradiction] LLM judge error: ${response.errorMessage ?? "unknown stop reason"}`
|
|
5609
5609
|
);
|
|
5610
5610
|
return llmErrorResult();
|
|
5611
5611
|
}
|
|
5612
5612
|
const parsed = extractJudgeArgs(response);
|
|
5613
5613
|
if (!parsed) {
|
|
5614
|
-
console.
|
|
5614
|
+
console.error("[contradiction] LLM judge returned unparseable response");
|
|
5615
5615
|
return llmErrorResult();
|
|
5616
5616
|
}
|
|
5617
5617
|
return {
|
|
@@ -5620,7 +5620,7 @@ async function classifyConflict(llmClient, newEntry, existing, model, config) {
|
|
|
5620
5620
|
explanation: parsed.explanation
|
|
5621
5621
|
};
|
|
5622
5622
|
} catch (err) {
|
|
5623
|
-
console.
|
|
5623
|
+
console.error(
|
|
5624
5624
|
`[contradiction] LLM judge call failed: ${err instanceof Error ? err.message : String(err)}`
|
|
5625
5625
|
);
|
|
5626
5626
|
return llmErrorResult();
|
|
@@ -5724,7 +5724,7 @@ async function resolveConflict(db, newEntryId, newEntry, conflict, subjectIndex,
|
|
|
5724
5724
|
conflict.result.confidence,
|
|
5725
5725
|
"coexist"
|
|
5726
5726
|
);
|
|
5727
|
-
console.
|
|
5727
|
+
console.error(
|
|
5728
5728
|
`[contradiction] resolution: coexist (events are immutable) entry=${conflict.existingEntryId.slice(0, 8)}`
|
|
5729
5729
|
);
|
|
5730
5730
|
return { action: "coexist", reason: "events are immutable" };
|
|
@@ -5753,7 +5753,7 @@ async function resolveConflict(db, newEntryId, newEntry, conflict, subjectIndex,
|
|
|
5753
5753
|
conflict.result.confidence,
|
|
5754
5754
|
"auto-superseded"
|
|
5755
5755
|
);
|
|
5756
|
-
console.
|
|
5756
|
+
console.error(
|
|
5757
5757
|
`[contradiction] resolution: auto-superseded entry=${conflict.existingEntryId.slice(0, 8)} (${conflict.existingType} confidence=${conflict.result.confidence.toFixed(2)})`
|
|
5758
5758
|
);
|
|
5759
5759
|
return {
|
|
@@ -5770,7 +5770,7 @@ async function resolveConflict(db, newEntryId, newEntry, conflict, subjectIndex,
|
|
|
5770
5770
|
conflict.result.confidence,
|
|
5771
5771
|
"pending"
|
|
5772
5772
|
);
|
|
5773
|
-
console.
|
|
5773
|
+
console.error(
|
|
5774
5774
|
`[contradiction] resolution: flagged for review entry=${conflict.existingEntryId.slice(0, 8)} (${conflict.result.relation} confidence=${conflict.result.confidence.toFixed(2)})`
|
|
5775
5775
|
);
|
|
5776
5776
|
return { action: "flagged", reason: "needs human review" };
|
|
@@ -5784,7 +5784,7 @@ async function resolveConflict(db, newEntryId, newEntry, conflict, subjectIndex,
|
|
|
5784
5784
|
conflict.result.confidence,
|
|
5785
5785
|
"pending"
|
|
5786
5786
|
);
|
|
5787
|
-
console.
|
|
5787
|
+
console.error(
|
|
5788
5788
|
`[contradiction] resolution: flagged for review entry=${conflict.existingEntryId.slice(0, 8)} (high-confidence supersedes blocked by importance)`
|
|
5789
5789
|
);
|
|
5790
5790
|
return { action: "flagged", reason: "high-confidence supersession blocked by importance" };
|
|
@@ -5797,7 +5797,7 @@ async function resolveConflict(db, newEntryId, newEntry, conflict, subjectIndex,
|
|
|
5797
5797
|
conflict.result.confidence,
|
|
5798
5798
|
"coexist"
|
|
5799
5799
|
);
|
|
5800
|
-
console.
|
|
5800
|
+
console.error(
|
|
5801
5801
|
`[contradiction] resolution: coexist entry=${conflict.existingEntryId.slice(0, 8)}`
|
|
5802
5802
|
);
|
|
5803
5803
|
return { action: "coexist", reason: "entries can coexist" };
|
|
@@ -7474,7 +7474,7 @@ async function storeEntries(db, entries, apiKey, options = {}) {
|
|
|
7474
7474
|
}
|
|
7475
7475
|
if (!entityHintsPromise) {
|
|
7476
7476
|
entityHintsPromise = getDistinctEntities(db).catch((err) => {
|
|
7477
|
-
console.
|
|
7477
|
+
console.error(
|
|
7478
7478
|
`[store] entity hints lookup failed, proceeding without hints: ${err instanceof Error ? err.message : String(err)}`
|
|
7479
7479
|
);
|
|
7480
7480
|
return [];
|
|
@@ -7679,7 +7679,7 @@ async function storeEntries(db, entries, apiKey, options = {}) {
|
|
|
7679
7679
|
}
|
|
7680
7680
|
if ((processed.mutation.kind === "add" || processed.mutation.kind === "add_related") && options.llmClient && options.contradictionEnabled !== false && processed.mutation.embedding) {
|
|
7681
7681
|
await contradictionSubjectIndex.ensureInitialized(db);
|
|
7682
|
-
console.
|
|
7682
|
+
console.error(
|
|
7683
7683
|
`[contradiction] checking entry: type=${normalizedEntry.type} subject="${normalizedEntry.subject}" subjectKey=${normalizedEntry.subjectKey ?? "none"}`
|
|
7684
7684
|
);
|
|
7685
7685
|
const conflicts = await detectContradictions(
|
|
@@ -7700,11 +7700,11 @@ async function storeEntries(db, entries, apiKey, options = {}) {
|
|
|
7700
7700
|
}
|
|
7701
7701
|
);
|
|
7702
7702
|
if (conflicts.length === 0) {
|
|
7703
|
-
console.
|
|
7703
|
+
console.error("[contradiction] no conflicts detected");
|
|
7704
7704
|
} else {
|
|
7705
|
-
console.
|
|
7705
|
+
console.error(`[contradiction] found ${conflicts.length} conflict(s):`);
|
|
7706
7706
|
for (const c of conflicts) {
|
|
7707
|
-
console.
|
|
7707
|
+
console.error(
|
|
7708
7708
|
`[contradiction] vs entry=${c.existingEntryId.slice(0, 8)} relation=${c.result.relation} confidence=${c.result.confidence.toFixed(2)} explanation="${c.result.explanation.slice(0, 80)}"`
|
|
7709
7709
|
);
|
|
7710
7710
|
}
|
|
@@ -20756,15 +20756,13 @@ function normalizeSlugList(value) {
|
|
|
20756
20756
|
function isPlatform(value) {
|
|
20757
20757
|
return PLATFORM_VALUES.includes(value);
|
|
20758
20758
|
}
|
|
20759
|
-
function buildSystemPromptBlock(
|
|
20759
|
+
function buildSystemPromptBlock(_projectSlug) {
|
|
20760
20760
|
return [
|
|
20761
|
-
"You have access to agenr_recall
|
|
20761
|
+
"You have access to agenr_recall for persistent memory across sessions.",
|
|
20762
20762
|
"",
|
|
20763
20763
|
'On session start, call agenr_recall with context="session-start" to load prior knowledge for this project. Mid-session, call agenr_recall with a query when you need context you do not have.',
|
|
20764
20764
|
"",
|
|
20765
|
-
|
|
20766
|
-
"",
|
|
20767
|
-
"Do not store: secrets/credentials, temporary state, verbatim conversation, or information already in files."
|
|
20765
|
+
"Do NOT call agenr_store. That tool has been removed. Your session transcript is automatically ingested by the Watcher, which extracts valuable knowledge after the session ends. Focus on your task - the memory system captures insights for you."
|
|
20768
20766
|
].join("\n");
|
|
20769
20767
|
}
|
|
20770
20768
|
async function pathExists(targetPath) {
|
|
@@ -22427,7 +22425,6 @@ var RpcError = class extends Error {
|
|
|
22427
22425
|
}
|
|
22428
22426
|
};
|
|
22429
22427
|
var KNOWLEDGE_TYPE_SET2 = new Set(KNOWLEDGE_TYPES);
|
|
22430
|
-
var SCOPE_LEVEL_SET = new Set(SCOPE_LEVELS);
|
|
22431
22428
|
var TOOL_DEFINITIONS = [
|
|
22432
22429
|
{
|
|
22433
22430
|
name: "agenr_recall",
|
|
@@ -22491,56 +22488,6 @@ var TOOL_DEFINITIONS = [
|
|
|
22491
22488
|
}
|
|
22492
22489
|
}
|
|
22493
22490
|
},
|
|
22494
|
-
{
|
|
22495
|
-
name: "agenr_store",
|
|
22496
|
-
description: "Store new knowledge entries in the database.",
|
|
22497
|
-
inputSchema: {
|
|
22498
|
-
type: "object",
|
|
22499
|
-
additionalProperties: false,
|
|
22500
|
-
required: ["entries"],
|
|
22501
|
-
properties: {
|
|
22502
|
-
platform: {
|
|
22503
|
-
type: "string",
|
|
22504
|
-
description: "Optional platform tag for all entries: openclaw, claude-code, codex."
|
|
22505
|
-
},
|
|
22506
|
-
project: {
|
|
22507
|
-
type: "string",
|
|
22508
|
-
description: "Optional project tag for all entries (lowercase)."
|
|
22509
|
-
},
|
|
22510
|
-
entries: {
|
|
22511
|
-
type: "array",
|
|
22512
|
-
items: {
|
|
22513
|
-
type: "object",
|
|
22514
|
-
additionalProperties: false,
|
|
22515
|
-
required: ["content", "type"],
|
|
22516
|
-
properties: {
|
|
22517
|
-
content: { type: "string", minLength: 1 },
|
|
22518
|
-
type: {
|
|
22519
|
-
type: "string",
|
|
22520
|
-
enum: [...KNOWLEDGE_TYPES]
|
|
22521
|
-
},
|
|
22522
|
-
importance: {
|
|
22523
|
-
type: "integer",
|
|
22524
|
-
minimum: 1,
|
|
22525
|
-
maximum: 10,
|
|
22526
|
-
default: 7
|
|
22527
|
-
},
|
|
22528
|
-
source: { type: "string" },
|
|
22529
|
-
tags: {
|
|
22530
|
-
type: "array",
|
|
22531
|
-
items: { type: "string" }
|
|
22532
|
-
},
|
|
22533
|
-
scope: {
|
|
22534
|
-
type: "string",
|
|
22535
|
-
enum: [...SCOPE_LEVELS],
|
|
22536
|
-
default: "personal"
|
|
22537
|
-
}
|
|
22538
|
-
}
|
|
22539
|
-
}
|
|
22540
|
-
}
|
|
22541
|
-
}
|
|
22542
|
-
}
|
|
22543
|
-
},
|
|
22544
22491
|
{
|
|
22545
22492
|
name: "agenr_extract",
|
|
22546
22493
|
description: "Extract knowledge entries from raw text.",
|
|
@@ -22554,11 +22501,6 @@ var TOOL_DEFINITIONS = [
|
|
|
22554
22501
|
minLength: 1,
|
|
22555
22502
|
description: "Raw text to extract knowledge from."
|
|
22556
22503
|
},
|
|
22557
|
-
store: {
|
|
22558
|
-
type: "boolean",
|
|
22559
|
-
default: false,
|
|
22560
|
-
description: "Whether to store extracted entries."
|
|
22561
|
-
},
|
|
22562
22504
|
source: {
|
|
22563
22505
|
type: "string",
|
|
22564
22506
|
description: "Optional source label for extracted entries."
|
|
@@ -22717,95 +22659,6 @@ function parseCsvProjects(input) {
|
|
|
22717
22659
|
}
|
|
22718
22660
|
return parsed;
|
|
22719
22661
|
}
|
|
22720
|
-
function normalizeTags3(value) {
|
|
22721
|
-
if (!Array.isArray(value)) {
|
|
22722
|
-
return [];
|
|
22723
|
-
}
|
|
22724
|
-
return Array.from(
|
|
22725
|
-
new Set(
|
|
22726
|
-
value.filter((item) => typeof item === "string").map((item) => item.trim().toLowerCase()).filter((item) => item.length > 0)
|
|
22727
|
-
)
|
|
22728
|
-
);
|
|
22729
|
-
}
|
|
22730
|
-
function parseScope(value) {
|
|
22731
|
-
if (value === void 0 || value === null || String(value).trim().length === 0) {
|
|
22732
|
-
return "personal";
|
|
22733
|
-
}
|
|
22734
|
-
if (typeof value !== "string") {
|
|
22735
|
-
throw new RpcError(JSON_RPC_INVALID_PARAMS, "scope must be a string");
|
|
22736
|
-
}
|
|
22737
|
-
const normalized = value.trim().toLowerCase();
|
|
22738
|
-
if (!SCOPE_LEVEL_SET.has(normalized)) {
|
|
22739
|
-
throw new RpcError(JSON_RPC_INVALID_PARAMS, `Invalid scope: ${value}`);
|
|
22740
|
-
}
|
|
22741
|
-
return normalized;
|
|
22742
|
-
}
|
|
22743
|
-
function normalizeImportance2(value) {
|
|
22744
|
-
const parsed = value === void 0 ? 7 : Number(value);
|
|
22745
|
-
if (!Number.isInteger(parsed) || parsed < 1 || parsed > 10) {
|
|
22746
|
-
throw new RpcError(JSON_RPC_INVALID_PARAMS, "importance must be an integer between 1 and 10");
|
|
22747
|
-
}
|
|
22748
|
-
return parsed;
|
|
22749
|
-
}
|
|
22750
|
-
function inferSubject(content) {
|
|
22751
|
-
const trimmed = content.trim();
|
|
22752
|
-
if (!trimmed) {
|
|
22753
|
-
return "memory";
|
|
22754
|
-
}
|
|
22755
|
-
const firstClause = trimmed.split(/[.!?:;]\s/)[0].trim();
|
|
22756
|
-
if (!firstClause) {
|
|
22757
|
-
return "memory";
|
|
22758
|
-
}
|
|
22759
|
-
if (firstClause.length <= 80) {
|
|
22760
|
-
return firstClause;
|
|
22761
|
-
}
|
|
22762
|
-
const cut = firstClause.lastIndexOf(" ", 80);
|
|
22763
|
-
return cut > 0 ? firstClause.slice(0, cut) : firstClause.slice(0, 80);
|
|
22764
|
-
}
|
|
22765
|
-
function parseStoreEntries(rawEntries) {
|
|
22766
|
-
if (!Array.isArray(rawEntries)) {
|
|
22767
|
-
throw new RpcError(JSON_RPC_INVALID_PARAMS, "entries must be an array");
|
|
22768
|
-
}
|
|
22769
|
-
return rawEntries.map((raw, index) => {
|
|
22770
|
-
if (!isRecord2(raw)) {
|
|
22771
|
-
throw new RpcError(JSON_RPC_INVALID_PARAMS, `entries[${index}] must be an object`);
|
|
22772
|
-
}
|
|
22773
|
-
const type = typeof raw.type === "string" ? raw.type.trim().toLowerCase() : "";
|
|
22774
|
-
if (!type || !KNOWLEDGE_TYPE_SET2.has(type)) {
|
|
22775
|
-
throw new RpcError(JSON_RPC_INVALID_PARAMS, `entries[${index}].type is invalid`);
|
|
22776
|
-
}
|
|
22777
|
-
const content = typeof raw.content === "string" ? raw.content.trim() : "";
|
|
22778
|
-
if (!content) {
|
|
22779
|
-
throw new RpcError(JSON_RPC_INVALID_PARAMS, `entries[${index}].content is required`);
|
|
22780
|
-
}
|
|
22781
|
-
const importance = (() => {
|
|
22782
|
-
try {
|
|
22783
|
-
return normalizeImportance2(raw.importance);
|
|
22784
|
-
} catch {
|
|
22785
|
-
throw new RpcError(
|
|
22786
|
-
JSON_RPC_INVALID_PARAMS,
|
|
22787
|
-
`entries[${index}].importance must be an integer between 1 and 10`
|
|
22788
|
-
);
|
|
22789
|
-
}
|
|
22790
|
-
})();
|
|
22791
|
-
const source = typeof raw.source === "string" && raw.source.trim().length > 0 ? raw.source.trim() : "mcp:agenr_store";
|
|
22792
|
-
const subject = typeof raw.subject === "string" && raw.subject.trim().length > 0 ? raw.subject.trim() : inferSubject(content);
|
|
22793
|
-
const scope = parseScope(raw.scope);
|
|
22794
|
-
return {
|
|
22795
|
-
type,
|
|
22796
|
-
subject,
|
|
22797
|
-
content,
|
|
22798
|
-
importance,
|
|
22799
|
-
expiry: "temporary",
|
|
22800
|
-
tags: normalizeTags3(raw.tags),
|
|
22801
|
-
scope,
|
|
22802
|
-
source: {
|
|
22803
|
-
file: source,
|
|
22804
|
-
context: "stored via MCP tool"
|
|
22805
|
-
}
|
|
22806
|
-
};
|
|
22807
|
-
});
|
|
22808
|
-
}
|
|
22809
22662
|
function formatDate(value) {
|
|
22810
22663
|
if (!value) {
|
|
22811
22664
|
return "unknown-date";
|
|
@@ -22857,15 +22710,7 @@ function formatBrowseText(results) {
|
|
|
22857
22710
|
}
|
|
22858
22711
|
return lines.join("\n");
|
|
22859
22712
|
}
|
|
22860
|
-
function
|
|
22861
|
-
const total = result.added + result.updated + result.skipped + result.superseded;
|
|
22862
|
-
const parts = [`${result.added} new`, `${result.updated} updated`, `${result.skipped} duplicates skipped`];
|
|
22863
|
-
if (result.superseded > 0) {
|
|
22864
|
-
parts.push(`${result.superseded} superseded`);
|
|
22865
|
-
}
|
|
22866
|
-
return `Stored ${total} entries (${parts.join(", ")}).`;
|
|
22867
|
-
}
|
|
22868
|
-
function formatExtractedText(entries, stored) {
|
|
22713
|
+
function formatExtractedText(entries) {
|
|
22869
22714
|
const lines = [`Extracted ${entries.length} entries from text:`, ""];
|
|
22870
22715
|
for (let i = 0; i < entries.length; i += 1) {
|
|
22871
22716
|
const entry = entries[i];
|
|
@@ -22874,12 +22719,6 @@ function formatExtractedText(entries, stored) {
|
|
|
22874
22719
|
}
|
|
22875
22720
|
lines.push(`[${i + 1}] (${entry.type}) ${entry.content}`);
|
|
22876
22721
|
}
|
|
22877
|
-
if (stored) {
|
|
22878
|
-
lines.push("");
|
|
22879
|
-
lines.push(
|
|
22880
|
-
`Stored: ${stored.added} new, ${stored.updated} updated, ${stored.skipped} duplicates skipped, ${stored.superseded} superseded.`
|
|
22881
|
-
);
|
|
22882
|
-
}
|
|
22883
22722
|
return lines.join("\n");
|
|
22884
22723
|
}
|
|
22885
22724
|
function extractIdForError(raw) {
|
|
@@ -22919,7 +22758,6 @@ function createMcpServer(options = {}, deps = {}) {
|
|
|
22919
22758
|
closeDbFn: deps.closeDbFn ?? closeDb,
|
|
22920
22759
|
recallFn: deps.recallFn ?? recall,
|
|
22921
22760
|
updateRecallMetadataFn: deps.updateRecallMetadataFn ?? updateRecallMetadata,
|
|
22922
|
-
storeEntriesFn: deps.storeEntriesFn ?? storeEntries,
|
|
22923
22761
|
retireEntriesFn: deps.retireEntriesFn ?? retireEntries,
|
|
22924
22762
|
parseTranscriptFileFn: deps.parseTranscriptFileFn ?? parseTranscriptFile,
|
|
22925
22763
|
extractKnowledgeFromChunksFn: deps.extractKnowledgeFromChunksFn ?? extractKnowledgeFromChunks,
|
|
@@ -23153,56 +22991,11 @@ function createMcpServer(options = {}, deps = {}) {
|
|
|
23153
22991
|
}
|
|
23154
22992
|
return formatRecallText(query || context, filtered);
|
|
23155
22993
|
}
|
|
23156
|
-
async function callStoreTool(args) {
|
|
23157
|
-
if (!hasOwn(args, "entries")) {
|
|
23158
|
-
throw new RpcError(JSON_RPC_INVALID_PARAMS, "entries is required");
|
|
23159
|
-
}
|
|
23160
|
-
const platformRaw = typeof args.platform === "string" ? args.platform.trim() : "";
|
|
23161
|
-
const platform = platformRaw ? normalizeKnowledgePlatform(platformRaw) : null;
|
|
23162
|
-
if (platformRaw && !platform) {
|
|
23163
|
-
throw new RpcError(
|
|
23164
|
-
JSON_RPC_INVALID_PARAMS,
|
|
23165
|
-
`platform must be one of: ${KNOWLEDGE_PLATFORMS.join(", ")}`
|
|
23166
|
-
);
|
|
23167
|
-
}
|
|
23168
|
-
const projectRaw = typeof args.project === "string" ? args.project.trim() : "";
|
|
23169
|
-
const explicitProject = projectRaw ? normalizeProject(projectRaw) : null;
|
|
23170
|
-
if (projectRaw && !explicitProject) {
|
|
23171
|
-
throw new RpcError(JSON_RPC_INVALID_PARAMS, "project must be a non-empty string");
|
|
23172
|
-
}
|
|
23173
|
-
const scoped = !explicitProject ? await loadScopedProjectConfig() : null;
|
|
23174
|
-
const project = explicitProject ?? scoped?.project ?? null;
|
|
23175
|
-
const parsed = parseStoreEntries(args.entries);
|
|
23176
|
-
const entries = platform || project ? parsed.map((entry) => ({
|
|
23177
|
-
...entry,
|
|
23178
|
-
...platform ? { platform } : {},
|
|
23179
|
-
...project ? { project } : {}
|
|
23180
|
-
})) : parsed;
|
|
23181
|
-
const db = await ensureDb();
|
|
23182
|
-
const config = resolvedDeps.readConfigFn(env);
|
|
23183
|
-
const aggressiveDedup = config?.dedup?.aggressive === true;
|
|
23184
|
-
const configDedupThreshold = typeof config?.dedup?.threshold === "number" ? config.dedup.threshold : void 0;
|
|
23185
|
-
const contradictionEnabled = config?.contradiction?.enabled !== false;
|
|
23186
|
-
const dedupClient = resolvedDeps.createLlmClientFn({ config, env });
|
|
23187
|
-
const apiKey = resolvedDeps.resolveEmbeddingApiKeyFn(config, env);
|
|
23188
|
-
const result = await resolvedDeps.storeEntriesFn(db, entries, apiKey, {
|
|
23189
|
-
sourceFile: "mcp:agenr_store",
|
|
23190
|
-
onlineDedup: true,
|
|
23191
|
-
llmClient: dedupClient,
|
|
23192
|
-
aggressiveDedup,
|
|
23193
|
-
dedupThreshold: configDedupThreshold,
|
|
23194
|
-
contradictionEnabled,
|
|
23195
|
-
config: config ?? void 0,
|
|
23196
|
-
dbPath: options.dbPath
|
|
23197
|
-
});
|
|
23198
|
-
return formatStoreSummary(result);
|
|
23199
|
-
}
|
|
23200
22994
|
async function callExtractTool(args) {
|
|
23201
22995
|
const text4 = typeof args.text === "string" ? args.text : "";
|
|
23202
22996
|
if (!text4.trim()) {
|
|
23203
22997
|
throw new RpcError(JSON_RPC_INVALID_PARAMS, "text is required");
|
|
23204
22998
|
}
|
|
23205
|
-
const shouldStore = args.store === true;
|
|
23206
22999
|
const sourceLabel = typeof args.source === "string" && args.source.trim().length > 0 ? args.source.trim() : void 0;
|
|
23207
23000
|
const tempDir = await resolvedDeps.mkdtempFn(path31.join(resolvedDeps.tmpdirFn(), "agenr-mcp-"));
|
|
23208
23001
|
const tempFile = path31.join(tempDir, "input.txt");
|
|
@@ -23226,32 +23019,7 @@ function createMcpServer(options = {}, deps = {}) {
|
|
|
23226
23019
|
context: entry.source.context
|
|
23227
23020
|
}
|
|
23228
23021
|
}));
|
|
23229
|
-
|
|
23230
|
-
if (shouldStore && extractedEntries.length > 0) {
|
|
23231
|
-
const db = await ensureDb();
|
|
23232
|
-
const apiKey = resolvedDeps.resolveEmbeddingApiKeyFn(config, env);
|
|
23233
|
-
const contradictionEnabled = config?.contradiction?.enabled !== false;
|
|
23234
|
-
stored = await resolvedDeps.storeEntriesFn(db, extractedEntries, apiKey, {
|
|
23235
|
-
sourceFile: sourceLabel ?? "mcp:agenr_extract",
|
|
23236
|
-
onlineDedup: true,
|
|
23237
|
-
llmClient: client,
|
|
23238
|
-
contradictionEnabled,
|
|
23239
|
-
config: config ?? void 0,
|
|
23240
|
-
dbPath: options.dbPath
|
|
23241
|
-
});
|
|
23242
|
-
} else if (shouldStore) {
|
|
23243
|
-
stored = {
|
|
23244
|
-
added: 0,
|
|
23245
|
-
updated: 0,
|
|
23246
|
-
skipped: 0,
|
|
23247
|
-
superseded: 0,
|
|
23248
|
-
llm_dedup_calls: 0,
|
|
23249
|
-
relations_created: 0,
|
|
23250
|
-
total_entries: 0,
|
|
23251
|
-
duration_ms: 0
|
|
23252
|
-
};
|
|
23253
|
-
}
|
|
23254
|
-
return formatExtractedText(extractedEntries, stored);
|
|
23022
|
+
return formatExtractedText(extractedEntries);
|
|
23255
23023
|
} finally {
|
|
23256
23024
|
await resolvedDeps.rmFn(tempDir, { recursive: true, force: true });
|
|
23257
23025
|
}
|
|
@@ -23310,22 +23078,6 @@ function createMcpServer(options = {}, deps = {}) {
|
|
|
23310
23078
|
content: [{ type: "text", text: result }]
|
|
23311
23079
|
};
|
|
23312
23080
|
}
|
|
23313
|
-
if (params.name === "agenr_store") {
|
|
23314
|
-
const result = await callStoreTool(params.args);
|
|
23315
|
-
const storeArgsEntries = Array.isArray(params.args.entries) ? params.args.entries : [];
|
|
23316
|
-
const firstEntry = storeArgsEntries[0];
|
|
23317
|
-
await appendMcpLog({
|
|
23318
|
-
tool: "agenr_store",
|
|
23319
|
-
count: storeArgsEntries.length,
|
|
23320
|
-
firstType: typeof firstEntry?.type === "string" ? firstEntry.type : void 0,
|
|
23321
|
-
firstSubject: typeof firstEntry?.subject === "string" ? firstEntry.subject.slice(0, 80) : void 0,
|
|
23322
|
-
firstImportance: typeof firstEntry?.importance === "number" ? firstEntry.importance : void 0,
|
|
23323
|
-
project: typeof params.args.project === "string" ? params.args.project : void 0
|
|
23324
|
-
});
|
|
23325
|
-
return {
|
|
23326
|
-
content: [{ type: "text", text: result }]
|
|
23327
|
-
};
|
|
23328
|
-
}
|
|
23329
23081
|
if (params.name === "agenr_extract") {
|
|
23330
23082
|
return {
|
|
23331
23083
|
content: [{ type: "text", text: await callExtractTool(params.args) }]
|
|
@@ -23783,8 +23535,8 @@ async function runRecallCommand(queryInput, options, deps) {
|
|
|
23783
23535
|
budget,
|
|
23784
23536
|
nonCoreLimit: limit
|
|
23785
23537
|
});
|
|
23786
|
-
finalResults = grouped.results;
|
|
23787
|
-
budgetUsed =
|
|
23538
|
+
finalResults = grouped.results.slice(0, limit);
|
|
23539
|
+
budgetUsed = finalResults.reduce((sum, item) => sum + estimateEntryTokens(item), 0);
|
|
23788
23540
|
} else {
|
|
23789
23541
|
const baseResults = await resolvedDeps.recallFn(db, queryForRecall, apiKey);
|
|
23790
23542
|
if (budget === void 0) {
|
|
@@ -24187,7 +23939,7 @@ function readStdin() {
|
|
|
24187
23939
|
process.stdin.on("error", reject);
|
|
24188
23940
|
});
|
|
24189
23941
|
}
|
|
24190
|
-
function
|
|
23942
|
+
function normalizeTags3(value) {
|
|
24191
23943
|
if (!Array.isArray(value)) {
|
|
24192
23944
|
return [];
|
|
24193
23945
|
}
|
|
@@ -24248,7 +24000,7 @@ function normalizeEntry(raw, fallbackFile) {
|
|
|
24248
24000
|
content,
|
|
24249
24001
|
importance,
|
|
24250
24002
|
expiry,
|
|
24251
|
-
tags:
|
|
24003
|
+
tags: normalizeTags3(record.tags),
|
|
24252
24004
|
created_at: normalizeCreatedAt2(record.created_at),
|
|
24253
24005
|
source: {
|
|
24254
24006
|
file: sourceFile,
|
|
@@ -92,7 +92,7 @@ declare function capTranscriptLength(params: {
|
|
|
92
92
|
currentSurface: string;
|
|
93
93
|
maxChars: number;
|
|
94
94
|
}): string;
|
|
95
|
-
declare function summarizeSessionForHandoff(currentRawMessages: BeforeResetEvent["messages"], sessionsDir: string, currentSessionFile: string, logger: PluginApi["logger"], includeBackground: boolean, streamSimpleImpl?: StreamSimpleFn, logEnabled?: boolean, logDir?: string): Promise<string | null>;
|
|
95
|
+
declare function summarizeSessionForHandoff(currentRawMessages: BeforeResetEvent["messages"], sessionsDir: string, currentSessionFile: string, logger: PluginApi["logger"], includeBackground: boolean, streamSimpleImpl?: StreamSimpleFn, logEnabled?: boolean, logDir?: string, debugEnabled?: boolean): Promise<string | null>;
|
|
96
96
|
declare function runHandoffForSession(opts: {
|
|
97
97
|
messages: unknown[];
|
|
98
98
|
sessionFile: string | null;
|
|
@@ -107,6 +107,7 @@ declare function runHandoffForSession(opts: {
|
|
|
107
107
|
includeBackground?: boolean;
|
|
108
108
|
logEnabled?: boolean;
|
|
109
109
|
logDir?: string;
|
|
110
|
+
debugEnabled?: boolean;
|
|
110
111
|
logger: PluginLogger | undefined;
|
|
111
112
|
source: "before_reset" | "command" | "session_start";
|
|
112
113
|
dbPath?: string;
|