agenr 0.8.8 → 0.8.9
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 +13 -0
- package/dist/cli-main.d.ts +12 -0
- package/dist/cli-main.js +73 -12
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,18 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [0.8.9]
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- feat(extractor): broadened extraction prompt to capture personal user context (health, diet, family, occupation, location, values) even from casual or passing mentions; added 6-month durability test heuristic to distinguish durable personal facts from transient states (issue #173)
|
|
7
|
+
- feat(extractor): new few-shot examples for RELATIONSHIP, PREFERENCE, FACT, and EVENT types covering personal context scenarios with scoring rationale
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
- fix(ingest): suppress redundant whole-file ignored-params warning; now fires once per ingest run via shared ExtractRunOnceFlags object instead of once per file (issue #168)
|
|
11
|
+
- fix(ingest): silence SQLITE_ERROR vector-index-not-found pre-fetch error during bulk ingest when vector index is intentionally absent; all other pre-fetch errors still log (issue #168)
|
|
12
|
+
- fix(ingest): detect .jsonl.reset.TIMESTAMP session files as JSONL adapter by extending suffix-stripping regex to handle both .deleted and .reset suffixes (issue #169)
|
|
13
|
+
- fix(consolidate): added merge system prompt constraint that expiry must be exactly permanent or temporary, never a date or timestamp; complements existing runtime fallback (issue #172)
|
|
14
|
+
- fix(daemon): daemon install plist now uses the runtime CLI path resolved from argv[1] via the injected argvFn, preventing hardcoded npm global paths from breaking pnpm installs (issue #174)
|
|
15
|
+
|
|
3
16
|
## [0.8.8]
|
|
4
17
|
|
|
5
18
|
### Fixed
|
package/dist/cli-main.d.ts
CHANGED
|
@@ -170,6 +170,16 @@ interface ExtractChunkCompleteResult {
|
|
|
170
170
|
durationMs?: number;
|
|
171
171
|
warnings: string[];
|
|
172
172
|
}
|
|
173
|
+
/**
|
|
174
|
+
* Shared mutable state object passed across multiple extractKnowledgeFromChunks
|
|
175
|
+
* calls (e.g., across files in a single ingest run) to suppress duplicate
|
|
176
|
+
* one-time warnings. When undefined, all warnings fire on every call,
|
|
177
|
+
* preserving backward-compatible behavior for callers that do not share state.
|
|
178
|
+
*/
|
|
179
|
+
interface ExtractRunOnceFlags {
|
|
180
|
+
/** Set to true after the whole-file ignored-params warning fires once. */
|
|
181
|
+
hasWarnedWholeFileIgnoredParams?: boolean;
|
|
182
|
+
}
|
|
173
183
|
declare function extractKnowledgeFromChunks(params: {
|
|
174
184
|
file: string;
|
|
175
185
|
chunks: TranscriptChunk[];
|
|
@@ -192,6 +202,8 @@ declare function extractKnowledgeFromChunks(params: {
|
|
|
192
202
|
embeddingApiKey?: string;
|
|
193
203
|
noPreFetch?: boolean;
|
|
194
204
|
embedFn?: (texts: string[], apiKey: string) => Promise<number[][]>;
|
|
205
|
+
/** Shared warning state across calls; pass one object per ingest run to dedupe one-time logs. */
|
|
206
|
+
onceFlags?: ExtractRunOnceFlags;
|
|
195
207
|
}): Promise<ExtractChunksResult>;
|
|
196
208
|
|
|
197
209
|
interface ResolveLlmClientInput {
|
package/dist/cli-main.js
CHANGED
|
@@ -7088,7 +7088,8 @@ function buildMergeContext(cluster) {
|
|
|
7088
7088
|
"Merge the provided related entries into one canonical entry.",
|
|
7089
7089
|
"Only include information explicitly stated in the source entries. Do not infer or add details not present.",
|
|
7090
7090
|
"Prefer preserving temporal changes in the merged narrative.",
|
|
7091
|
-
"Call merge_entries with your final merged result."
|
|
7091
|
+
"Call merge_entries with your final merged result.",
|
|
7092
|
+
'expiry must be exactly the string "permanent" or "temporary" -- never a date, timestamp, or other value.'
|
|
7092
7093
|
].join("\n");
|
|
7093
7094
|
let contentLimit;
|
|
7094
7095
|
let payload = formatClusterEntries(cluster, contentLimit);
|
|
@@ -11164,7 +11165,7 @@ var vscodeCopilotAdapter = {
|
|
|
11164
11165
|
|
|
11165
11166
|
// src/adapters/registry.ts
|
|
11166
11167
|
async function detectAdapter(filePath) {
|
|
11167
|
-
const strippedPath = filePath.replace(/\.deleted\.[^/\\]+$/, "");
|
|
11168
|
+
const strippedPath = filePath.replace(/\.(deleted|reset)\.[^/\\]+$/, "");
|
|
11168
11169
|
const ext = path23.extname(strippedPath).toLowerCase();
|
|
11169
11170
|
if (ext === ".jsonl") {
|
|
11170
11171
|
const firstLine = await readFirstNonEmptyLine(filePath);
|
|
@@ -11725,15 +11726,15 @@ var SUBMIT_DEDUPED_KNOWLEDGE_TOOL = {
|
|
|
11725
11726
|
// src/extractor.ts
|
|
11726
11727
|
var SYSTEM_PROMPT = `You are a selective memory extraction engine. Extract only knowledge worth remembering beyond the immediate step.
|
|
11727
11728
|
|
|
11728
|
-
Default action: SKIP. Most chunks should produce zero entries.
|
|
11729
|
+
Default action: SKIP. Most chunks should produce zero entries. Personal disclosures (health, diet, family structure, pets, occupation, location, values, relationships) are high-signal -- do not skip them just because the mention is brief or incidental. Apply the durability gate below to all entries including personal ones.
|
|
11729
11730
|
|
|
11730
11731
|
## Types
|
|
11731
11732
|
|
|
11732
|
-
FACT \u2014 Verifiable information about a system, project, person, or concept.
|
|
11733
|
+
FACT \u2014 Verifiable information about a system, project, person, or concept. Personal facts count as first-class entries: health conditions, family members, pets, where the user lives or works, occupation, hobbies, recurring habits, and lifestyle circumstances.
|
|
11733
11734
|
DECISION \u2014 A choice that constrains future options. Requires BOTH the choice AND the rationale. If rationale is missing, use fact or event instead.
|
|
11734
11735
|
PREFERENCE \u2014 A stated or demonstrated preference that should influence future behavior.
|
|
11735
11736
|
LESSON \u2014 An insight from experience that should change future behavior.
|
|
11736
|
-
EVENT \u2014 A significant milestone, launch, or
|
|
11737
|
+
EVENT \u2014 A significant milestone, launch, completion, or one-time life moment. Includes project launches, deployments, merges; and personal milestones like starting a new job, relocating, major health events, or notable personal experiences. NOT recurring habits or routines (those are FACT or PREFERENCE). NOT "the assistant ran git status." NOT vague references with no anchoring detail. If a personal behavior is described as newly begun, prefer EVENT for the initiation; use FACT if the stable ongoing state is also established in the same context.
|
|
11737
11738
|
RELATIONSHIP \u2014 A connection between named entities. Content must include both entities and the relation.
|
|
11738
11739
|
TODO \u2014 A persistent future action not completed in this chunk and not a one-step session instruction.
|
|
11739
11740
|
|
|
@@ -11756,7 +11757,7 @@ Do NOT emit a completion event for:
|
|
|
11756
11757
|
## Durability Gate
|
|
11757
11758
|
|
|
11758
11759
|
Only extract if useful in future conversations/tasks after the current immediate execution.
|
|
11759
|
-
If uncertain whether durable, skip.
|
|
11760
|
+
If uncertain whether durable, apply the 6-month test: would knowing this fact 6 months from now still help an AI assist this person? Health conditions, family structure, location, diet, pets, occupation, values -> YES, extract. Current mood, today's plans, this week's weather -> NO, skip. Personal disclosures are durable by default -- if a user reveals something true about themselves, capture it even if mentioned casually or as an aside.
|
|
11760
11761
|
|
|
11761
11762
|
## Importance (1-10)
|
|
11762
11763
|
|
|
@@ -11843,8 +11844,9 @@ If you cannot name a concrete topic, skip the entry.
|
|
|
11843
11844
|
5. Code-level implementation details likely to churn (unless architecture-level decision)
|
|
11844
11845
|
6. One workflow split into multiple near-duplicate entries \u2014 merge into one
|
|
11845
11846
|
7. Minor rephrases/duplicates of another extracted entry
|
|
11846
|
-
8.
|
|
11847
|
+
8. Pure pleasantries with no personal content: greetings, acknowledgments, filler phrases that reveal nothing about the user ("how are you", "thanks", "sounds good", "got it"). Do NOT suppress personal disclosures just because they appear inside casual phrasing or as asides. "I follow keto so no carbs -- anyway, back to the project" contains an extractable preference even though the user pivoted away. The pivot does not cancel the fact. Test: does the underlying disclosure reveal something true and durable about the user? If yes, extract it.
|
|
11847
11848
|
9. Transient implementation status unless it represents a milestone, decision, or lesson
|
|
11849
|
+
10. Transient personal states: current mood, today's fatigue, this week's busyness, temporary travel plans, passing weather references. These are not personal facts. Extract only if the condition is recurring or structural ("I'm always exhausted" may indicate a chronic health pattern worth capturing; "I'm tired today" does not).
|
|
11848
11850
|
|
|
11849
11851
|
## Explicit Memory Requests
|
|
11850
11852
|
|
|
@@ -11949,6 +11951,17 @@ RELATIONSHIP:
|
|
|
11949
11951
|
"source_context": "Architecture discussion about memory integration"
|
|
11950
11952
|
}
|
|
11951
11953
|
|
|
11954
|
+
RELATIONSHIP:
|
|
11955
|
+
{
|
|
11956
|
+
"type": "relationship",
|
|
11957
|
+
"subject": "user and sister Sarah",
|
|
11958
|
+
"content": "User's sister Sarah lives nearby and they see each other regularly. She helps with childcare.",
|
|
11959
|
+
"importance": 7,
|
|
11960
|
+
"expiry": "permanent",
|
|
11961
|
+
"tags": ["family", "personal", "relationship"],
|
|
11962
|
+
"source_context": "User mentioned sister while discussing weekend plans"
|
|
11963
|
+
}
|
|
11964
|
+
|
|
11952
11965
|
TODO:
|
|
11953
11966
|
{
|
|
11954
11967
|
"type": "todo",
|
|
@@ -12015,6 +12028,39 @@ PREFERENCE:
|
|
|
12015
12028
|
"source_context": "User mentioned scheduling preference during calendar discussion -- scored 6 not 8 because no parallel session needs to act on this immediately; it is a low-urgency convenience preference"
|
|
12016
12029
|
}
|
|
12017
12030
|
|
|
12031
|
+
PREFERENCE:
|
|
12032
|
+
{
|
|
12033
|
+
"type": "preference",
|
|
12034
|
+
"subject": "user dietary preference",
|
|
12035
|
+
"content": "User follows a strict ketogenic diet and avoids carbohydrates. Do not suggest high-carb meals, recipes, or foods.",
|
|
12036
|
+
"importance": 7,
|
|
12037
|
+
"expiry": "permanent",
|
|
12038
|
+
"tags": ["diet", "keto", "personal", "health"],
|
|
12039
|
+
"source_context": "User mentioned diet as an aside mid-conversation -- scored 7 because future sessions about food, health, or restaurants need this; the casual phrasing does not reduce its durability"
|
|
12040
|
+
}
|
|
12041
|
+
|
|
12042
|
+
FACT:
|
|
12043
|
+
{
|
|
12044
|
+
"type": "fact",
|
|
12045
|
+
"subject": "user morning routine",
|
|
12046
|
+
"content": "User wakes at 6:15 AM and goes to the gym every weekday morning before work.",
|
|
12047
|
+
"importance": 6,
|
|
12048
|
+
"expiry": "permanent",
|
|
12049
|
+
"tags": ["routine", "health", "personal"],
|
|
12050
|
+
"source_context": "User described morning routine while discussing their schedule -- scored 6 not 8 because this is low-urgency biographical context; no parallel session needs to act on it immediately"
|
|
12051
|
+
}
|
|
12052
|
+
|
|
12053
|
+
EVENT:
|
|
12054
|
+
{
|
|
12055
|
+
"type": "event",
|
|
12056
|
+
"subject": "user job change",
|
|
12057
|
+
"content": "User started a new senior engineering role at a new company. This is a recent career change.",
|
|
12058
|
+
"importance": 7,
|
|
12059
|
+
"expiry": "permanent",
|
|
12060
|
+
"tags": ["career", "work", "personal"],
|
|
12061
|
+
"source_context": "User mentioned new job while discussing their schedule -- scored 7 not 9 because this is a significant life milestone worth preserving but does not require immediate cross-session action"
|
|
12062
|
+
}
|
|
12063
|
+
|
|
12018
12064
|
// NOTE: These examples are drawn from OpenClaw transcripts (agent role labels, tool-verified claims). They provide soft cross-platform guidance for hedged-claim handling; mechanical enforcement (importance cap + unverified tag) is applied for openclaw, codex, and claude-code via applyConfidenceCap().
|
|
12019
12065
|
Example: hedged agent claim (correct handling):
|
|
12020
12066
|
{
|
|
@@ -12459,6 +12505,10 @@ var ParseResponseError = class extends Error {
|
|
|
12459
12505
|
function normalize3(value) {
|
|
12460
12506
|
return value.trim().toLowerCase();
|
|
12461
12507
|
}
|
|
12508
|
+
function isVectorIndexNotFoundMessage(message) {
|
|
12509
|
+
const normalized = message.toLowerCase();
|
|
12510
|
+
return normalized.includes("vector index") && normalized.includes("not found");
|
|
12511
|
+
}
|
|
12462
12512
|
async function preFetchRelated(chunkText2, db, embeddingApiKey, embedFn = embed, onVerbose) {
|
|
12463
12513
|
const run = async () => {
|
|
12464
12514
|
try {
|
|
@@ -12490,7 +12540,11 @@ async function preFetchRelated(chunkText2, db, embeddingApiKey, embedFn = embed,
|
|
|
12490
12540
|
onVerbose?.(`[pre-fetch] ${above.length} above threshold ${PREFETCH_SIMILARITY_THRESHOLD}`);
|
|
12491
12541
|
return above.slice(0, MAX_PREFETCH_RESULTS).map((candidate) => candidate.entry);
|
|
12492
12542
|
} catch (error) {
|
|
12493
|
-
|
|
12543
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
12544
|
+
if (isVectorIndexNotFoundMessage(message)) {
|
|
12545
|
+
return [];
|
|
12546
|
+
}
|
|
12547
|
+
onVerbose?.(`[pre-fetch] skipped: ${message}`);
|
|
12494
12548
|
return [];
|
|
12495
12549
|
}
|
|
12496
12550
|
};
|
|
@@ -13251,10 +13305,15 @@ async function extractKnowledgeFromChunks(params) {
|
|
|
13251
13305
|
let effectiveNoPreFetch = wholeFileMode ? true : params.noPreFetch ?? false;
|
|
13252
13306
|
if (wholeFileMode && params.verbose) {
|
|
13253
13307
|
const ignoredParamsLine = "[whole-file] interChunkDelayMs and llmConcurrency have no effect in whole-file mode";
|
|
13254
|
-
if (params.
|
|
13255
|
-
params.onVerbose
|
|
13256
|
-
|
|
13257
|
-
|
|
13308
|
+
if (!params.onceFlags?.hasWarnedWholeFileIgnoredParams) {
|
|
13309
|
+
if (params.onVerbose) {
|
|
13310
|
+
params.onVerbose(ignoredParamsLine);
|
|
13311
|
+
} else {
|
|
13312
|
+
console.warn(ignoredParamsLine);
|
|
13313
|
+
}
|
|
13314
|
+
if (params.onceFlags) {
|
|
13315
|
+
params.onceFlags.hasWarnedWholeFileIgnoredParams = true;
|
|
13316
|
+
}
|
|
13258
13317
|
}
|
|
13259
13318
|
}
|
|
13260
13319
|
if (wholeFileMode) {
|
|
@@ -14545,6 +14604,7 @@ async function runIngestCommand(inputPaths, options, deps) {
|
|
|
14545
14604
|
let totalChunksFailed = 0;
|
|
14546
14605
|
let filesWithChunkFailures = 0;
|
|
14547
14606
|
const chunkStatsByFile = /* @__PURE__ */ new Map();
|
|
14607
|
+
const extractOnceFlags = { hasWarnedWholeFileIgnoredParams: false };
|
|
14548
14608
|
let firstPassFailedIndexSet = /* @__PURE__ */ new Set();
|
|
14549
14609
|
let bulkTeardownComplete = false;
|
|
14550
14610
|
let bulkVectorRebuildDurationSeconds = null;
|
|
@@ -14699,6 +14759,7 @@ async function runIngestCommand(inputPaths, options, deps) {
|
|
|
14699
14759
|
db: options.noPreFetch ? void 0 : db,
|
|
14700
14760
|
embeddingApiKey: options.noPreFetch ? void 0 : embeddingApiKey ?? void 0,
|
|
14701
14761
|
noPreFetch: options.noPreFetch === true,
|
|
14762
|
+
onceFlags: extractOnceFlags,
|
|
14702
14763
|
onVerbose: verbose ? (line) => {
|
|
14703
14764
|
clack4.log.info(line, clackOutput);
|
|
14704
14765
|
} : void 0,
|