agenr 1.3.0 → 1.4.0
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 +19 -0
- package/README.md +38 -16
- package/dist/{chunk-2FKQCRGD.js → chunk-DSP74MEN.js} +22 -0
- package/dist/cli.js +34 -4
- package/dist/internal-recall-eval-server.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,24 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.4.0] - 2026-03-30
|
|
4
|
+
|
|
5
|
+
Configurable summary models, surgeon personal knowledge protection, and documentation overhaul.
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
|
|
9
|
+
- **Configurable continuity and episode summary models.** New `continuityModel` and `episodeModel` fields in the OpenClaw plugin config (`plugins.entries.agenr.config`) allow overriding the model used for continuity and episode summary generation independently. Falls back to the agent's primary model when unset. Use a fast model like `openai/gpt-5.4-mini` for these structured extraction tasks instead of burning Opus tokens.
|
|
10
|
+
- **Personal knowledge protection in surgeon.** The surgeon retirement pass now has explicit guidance that personal facts (family, pets, hardware, contacts, identity, physical environment) are durable by nature. Only retires personal entries when contradicted or clearly duplicated — not for low recall or moderate importance.
|
|
11
|
+
- **Corpus age awareness in surgeon.** The `_meta` table now tracks `last_bulk_ingest_at`, surfaced via `get_health_stats`. The surgeon heavily discounts `recall_count = 0` when the corpus was rebuilt within 30 days, preventing mass retirements of freshly ingested entries.
|
|
12
|
+
- **New documentation: `docs/EPISODES.md`.** Comprehensive episodic memory docs covering lifecycle, CLI usage, recall modes, temporal window parser, search modes, embeddings, session discovery, and architecture.
|
|
13
|
+
- **New documentation: `docs/SURGEON.md`.** Comprehensive surgeon docs covering tools, CLI commands, dry-run vs apply, budget governance, configuration, protection thresholds, and audit history.
|
|
14
|
+
|
|
15
|
+
### Changed
|
|
16
|
+
|
|
17
|
+
- **Continuity summary timeout increased.** Inner timeout bumped from 15s to 30s, read-time wrapper from 20s to 35s. Prevents timeout failures when using slower models for continuity summaries.
|
|
18
|
+
- **Updated `docs/RECALL.md`.** Added unified recall mode routing (`auto`/`entries`/`episodes`), auto-routing rules, temporal window parser reference, and episode search pipeline documentation.
|
|
19
|
+
- **Updated `docs/INGEST.md`.** Added episode ingest section with full flag documentation, behavior differences from entry ingest, session discovery, surface reconstruction, and practical examples.
|
|
20
|
+
- **Updated `README.md`.** Added episodic memory and surgeon to features list, CLI commands table, and new "How Episodes Work" and "How the Surgeon Works" sections with doc links.
|
|
21
|
+
|
|
3
22
|
## [1.3.0] - 2026-03-30
|
|
4
23
|
|
|
5
24
|
Episodic memory — session-level temporal recall for the brain.
|
package/README.md
CHANGED
|
@@ -14,18 +14,20 @@ Local-first, durable memory infrastructure for AI agents.
|
|
|
14
14
|
|
|
15
15
|
## What is agenr?
|
|
16
16
|
|
|
17
|
-
agenr gives agents a persistent brain: a local SQLite database of durable knowledge that survives across sessions, tools, and agent restarts. Instead of relying on fragile prompt state or file-based scratch memory, agents can ingest transcripts, extract decisions and lessons, store them as typed entries, and recall them later with semantic search and memory-aware ranking.
|
|
17
|
+
agenr gives agents a persistent brain: a local SQLite database of durable knowledge that survives across sessions, tools, and agent restarts. Instead of relying on fragile prompt state or file-based scratch memory, agents can ingest transcripts, extract decisions and lessons, store them as typed entries, generate episodic summaries of what happened, and recall them later with semantic search and memory-aware ranking.
|
|
18
18
|
|
|
19
|
-
It exists because most agent runtimes forget everything important between sessions. Even when a tool has a built-in memory feature, it is often lossy, file-based, or tightly coupled to one surface. agenr keeps memory structured and queryable: facts, decisions, preferences, lessons,
|
|
19
|
+
It exists because most agent runtimes forget everything important between sessions. Even when a tool has a built-in memory feature, it is often lossy, file-based, or tightly coupled to one surface. agenr keeps memory structured and queryable: facts, decisions, preferences, lessons, tasks, milestones, relationships, and session-level episodes live in one local store instead of getting flattened into prompt text.
|
|
20
20
|
|
|
21
|
-
What makes agenr different is the combination of local-first storage, semantic embeddings, hybrid recall, and adapter-friendly architecture. The core is hexagonal, so multiple agent systems can share the same brain over time. Today the production adapter is the OpenClaw memory plugin, published separately as `@agenr/openclaw-plugin`, and the CLI provides offline ingest and
|
|
21
|
+
What makes agenr different is the combination of local-first storage, semantic embeddings, hybrid recall, episodic temporal memory, and adapter-friendly architecture. The core is hexagonal, so multiple agent systems can share the same brain over time. Today the production adapter is the OpenClaw memory plugin, published separately as `@agenr/openclaw-plugin`, and the CLI provides offline ingest, recall, and maintenance against that same database.
|
|
22
22
|
|
|
23
23
|
## Features
|
|
24
24
|
|
|
25
|
-
- Hybrid recall: vector similarity, lexical FTS, temporal awareness, recency decay, and importance weighting.
|
|
25
|
+
- Hybrid recall for durable knowledge: vector similarity, lexical FTS, temporal awareness, recency decay, and importance weighting.
|
|
26
|
+
- Episodic memory: session-level summaries with temporal filtering and optional semantic episode search for questions like "what happened yesterday?"
|
|
26
27
|
- LLM-powered knowledge extraction from conversation transcripts.
|
|
27
28
|
- Semantic deduplication using exact hashes, normalized hashes, embeddings, and within-run clustering.
|
|
28
|
-
- Session continuity with predecessor resolution, recent transcript tails, and LLM-generated
|
|
29
|
+
- Session continuity with predecessor resolution, recent transcript tails, and LLM-generated continuity summaries.
|
|
30
|
+
- Surgeon retirement pass for corpus maintenance: inspect stale candidates, simulate recall impact, and retire semantically obsolete knowledge with audit history.
|
|
29
31
|
- Agent tools for `store`, `recall`, `retire`, `update`, and `trace` through the OpenClaw plugin.
|
|
30
32
|
- Native OpenClaw memory plugin that replaces OpenClaw's built-in memory slot.
|
|
31
33
|
- Local-first storage with SQLite/libSQL. Memory stays on your machine; only model and embedding calls leave it.
|
|
@@ -46,7 +48,7 @@ It walks through:
|
|
|
46
48
|
- model selection filtered by the auth method you chose
|
|
47
49
|
- OpenAI embedding key setup
|
|
48
50
|
- OpenClaw detection and optional plugin installation
|
|
49
|
-
- session scanning and optional bulk ingestion of existing transcripts
|
|
51
|
+
- session scanning and optional bulk ingestion of existing transcripts into durable entries and episodic summaries
|
|
50
52
|
|
|
51
53
|
Run `agenr init` again any time you want to re-run onboarding, reinstall the plugin, or ingest another batch of existing sessions.
|
|
52
54
|
|
|
@@ -109,10 +111,10 @@ Key config fields:
|
|
|
109
111
|
|
|
110
112
|
| Field | What it does |
|
|
111
113
|
| -------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
112
|
-
| `auth` | Authentication method: `openai-api-key`, `openai-subscription`, `anthropic-api-key`, `anthropic-oauth`, or `anthropic-token`.
|
|
114
|
+
| `auth` | Authentication method: `openai-api-key`, `openai-subscription`, `anthropic-api-key`, `anthropic-oauth`, or `anthropic-token`. |
|
|
113
115
|
| `provider` / `model` | Default LLM provider and model used for extraction tasks unless overridden. |
|
|
114
116
|
| `credentials` | Stored manual credentials. Today that can include `openaiApiKey`, `anthropicApiKey`, and `anthropicOauthToken`. The config file is written with locked-down permissions (`0600`). |
|
|
115
|
-
| `credentials.openaiApiKey` | OpenAI key used for embeddings, and also for extraction when `auth` is `openai-api-key`. Older configs may still rely on legacy `embeddingApiKey` or `apiKey` fallback fields.
|
|
117
|
+
| `credentials.openaiApiKey` | OpenAI key used for embeddings, and also for extraction when `auth` is `openai-api-key`. Older configs may still rely on legacy `embeddingApiKey` or `apiKey` fallback fields. |
|
|
116
118
|
| `embeddingModel` | Embedding model. Defaults to `text-embedding-3-small`. |
|
|
117
119
|
| `extractionModel` / `dedupModel` | Optional per-pipeline overrides so extraction and dedup can use different provider/model pairs. |
|
|
118
120
|
| `extractionContext` | Optional user context injected into extraction prompts to help the model decide what is worth remembering. |
|
|
@@ -128,7 +130,7 @@ Important: when agenr is running as an OpenClaw plugin, session summaries use Op
|
|
|
128
130
|
|
|
129
131
|
## CLI Commands
|
|
130
132
|
|
|
131
|
-
The
|
|
133
|
+
The CLI surface is still intentionally compact, but it now covers setup, recall, ingest, and corpus maintenance.
|
|
132
134
|
|
|
133
135
|
| Command | What it does |
|
|
134
136
|
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------ |
|
|
@@ -138,6 +140,10 @@ The current CLI surface is intentionally small. Today the `db` group only expose
|
|
|
138
140
|
| `agenr ingest <path>` | Default durable-entry ingest shorthand. Equivalent to `agenr ingest entries <path>`. |
|
|
139
141
|
| `agenr ingest entries <path>` | Bulk-ingest one file or directory of OpenClaw transcript files into durable knowledge entries. |
|
|
140
142
|
| `agenr ingest episodes <path>` | Backfill episodic summaries from OpenClaw session transcripts, including rotated `.reset.*` and `.deleted.*` files. |
|
|
143
|
+
| `agenr surgeon run` | Execute the surgeon retirement pass. Dry-run by default; add `--apply` to mutate the corpus. |
|
|
144
|
+
| `agenr surgeon status` | Show corpus health plus the latest surgeon run summary. |
|
|
145
|
+
| `agenr surgeon history` | Show recent surgeon runs. |
|
|
146
|
+
| `agenr surgeon actions <run>` | Show the audit trail for one surgeon run. |
|
|
141
147
|
| `agenr db reset` | Delete and recreate the knowledge database. |
|
|
142
148
|
|
|
143
149
|
The OpenClaw plugin also gives the agent five tools directly inside the runtime: `agenr_store`, `agenr_recall`, `agenr_retire`, `agenr_update`, and `agenr_trace`.
|
|
@@ -148,12 +154,15 @@ Examples:
|
|
|
148
154
|
# Recall knowledge
|
|
149
155
|
agenr recall "what decisions did we make about the API?"
|
|
150
156
|
|
|
151
|
-
# Ingest transcripts
|
|
157
|
+
# Ingest transcripts into durable entries
|
|
152
158
|
agenr ingest ~/.openclaw/agents/main/sessions/
|
|
153
159
|
|
|
154
|
-
# Backfill
|
|
160
|
+
# Backfill episodic summaries
|
|
155
161
|
agenr ingest episodes ~/.openclaw/agents/main/sessions/ --recent 30d
|
|
156
162
|
|
|
163
|
+
# Run the surgeon retirement pass (dry-run by default)
|
|
164
|
+
agenr surgeon run --budget 2.00
|
|
165
|
+
|
|
157
166
|
# Reset the database
|
|
158
167
|
agenr db reset
|
|
159
168
|
```
|
|
@@ -172,7 +181,20 @@ Recall is a hybrid pipeline. Agenr embeds the query, retrieves candidates throug
|
|
|
172
181
|
|
|
173
182
|
## How Ingestion Works
|
|
174
183
|
|
|
175
|
-
|
|
184
|
+
Agenr has two ingest pipelines over the same transcript corpus:
|
|
185
|
+
|
|
186
|
+
- `agenr ingest entries <path>` extracts durable typed knowledge such as facts, decisions, preferences, lessons, milestones, and relationships.
|
|
187
|
+
- `agenr ingest episodes <path>` generates one narrative summary per session so the brain can answer temporal questions like "what happened last week?"
|
|
188
|
+
|
|
189
|
+
Both paths parse OpenClaw transcripts first, but they optimize for different outputs: entry ingest distills durable knowledge and runs semantic dedup across the whole ingest batch, while episode ingest does a session-by-session preflight pass, uses `sessions.json` metadata when available, reconstructs missing surface metadata for rotated files, and writes episodic summaries. Details: [docs/INGEST.md](./docs/INGEST.md) and [docs/STORE.md](./docs/STORE.md).
|
|
190
|
+
|
|
191
|
+
## How Episodes Work
|
|
192
|
+
|
|
193
|
+
Episodes are session-level memory artifacts stored separately from durable entries. They preserve temporal narrative: what happened in a session, when it happened, which agent/session it belonged to, and optionally an embedding for semantic episode search. Recall can route narrative or time-bounded questions toward episodes automatically, or combine episode and entry results in mixed mode. For implementation details and the episode recall model, see [docs/EPISODES.md](./docs/EPISODES.md).
|
|
194
|
+
|
|
195
|
+
## How the Surgeon Works
|
|
196
|
+
|
|
197
|
+
The surgeon is a maintenance pass for the durable-memory corpus. It evaluates retirement candidates, inspects related context, can simulate recall impact before mutation, and records runs plus per-action audit history in the database. `agenr surgeon run` is safe by default because it starts in dry-run mode; `--apply` is the explicit mutation switch. For runtime details, governance, and audit behavior, see [docs/SURGEON.md](./docs/SURGEON.md).
|
|
176
198
|
|
|
177
199
|
## Development
|
|
178
200
|
|
|
@@ -188,10 +210,10 @@ pnpm check # format + lint + typecheck + test
|
|
|
188
210
|
| Problem | What to check |
|
|
189
211
|
| ----------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
190
212
|
| `agenr init` cannot complete setup | Re-run `agenr setup` and verify the selected auth method is actually available. Subscription flows depend on the relevant external login being present, and non-OpenAI extraction setups still need a separate OpenAI embedding key. |
|
|
191
|
-
| `openclaw plugins install @agenr/openclaw-plugin` fails | Make sure the `openclaw` CLI is installed and on `PATH`. For local development, run `pnpm build` and use `plugins.load.paths` instead.
|
|
192
|
-
| `agenr recall` or `agenr_recall` fails with embedding/auth errors | Embeddings always use OpenAI. Confirm `credentials.openaiApiKey` is configured, or re-run `agenr setup` to set the embedding key explicitly.
|
|
193
|
-
| SQLite says the database is locked | Avoid running multiple writers against the same DB at once. Stop overlapping ingest/reset runs, restart the OpenClaw gateway if needed, then retry.
|
|
194
|
-
| OpenClaw does not pick up the plugin | Restart the gateway, confirm `plugins.slots.memory` is `agenr`, confirm `plugins.allow` contains `agenr`, and for dev installs confirm `plugins.load.paths` points at the built `packages/openclaw-plugin` directory.
|
|
213
|
+
| `openclaw plugins install @agenr/openclaw-plugin` fails | Make sure the `openclaw` CLI is installed and on `PATH`. For local development, run `pnpm build` and use `plugins.load.paths` instead. |
|
|
214
|
+
| `agenr recall` or `agenr_recall` fails with embedding/auth errors | Embeddings always use OpenAI. Confirm `credentials.openaiApiKey` is configured, or re-run `agenr setup` to set the embedding key explicitly. |
|
|
215
|
+
| SQLite says the database is locked | Avoid running multiple writers against the same DB at once. Stop overlapping ingest/reset runs, restart the OpenClaw gateway if needed, then retry. |
|
|
216
|
+
| OpenClaw does not pick up the plugin | Restart the gateway, confirm `plugins.slots.memory` is `agenr`, confirm `plugins.allow` contains `agenr`, and for dev installs confirm `plugins.load.paths` points at the built `packages/openclaw-plugin` directory. |
|
|
195
217
|
|
|
196
218
|
## License
|
|
197
219
|
|
|
@@ -947,6 +947,7 @@ var SCHEMA_VERSION = "4";
|
|
|
947
947
|
var VECTOR_INDEX_NAME = "idx_entries_embedding";
|
|
948
948
|
var EPISODE_VECTOR_INDEX_NAME = "idx_episodes_embedding";
|
|
949
949
|
var BULK_WRITE_STATE_META_KEY = "bulk_write_state";
|
|
950
|
+
var LAST_BULK_INGEST_META_KEY = "last_bulk_ingest_at";
|
|
950
951
|
var CREATE_ENTRIES_TABLE_SQL = `
|
|
951
952
|
CREATE TABLE IF NOT EXISTS entries (
|
|
952
953
|
id TEXT PRIMARY KEY,
|
|
@@ -1386,8 +1387,28 @@ async function finalizeBulkWrites(db) {
|
|
|
1386
1387
|
sql: "DELETE FROM _meta WHERE key = ?",
|
|
1387
1388
|
args: [BULK_WRITE_STATE_META_KEY]
|
|
1388
1389
|
});
|
|
1390
|
+
await db.execute({
|
|
1391
|
+
sql: `
|
|
1392
|
+
INSERT INTO _meta (key, value)
|
|
1393
|
+
VALUES (?, ?)
|
|
1394
|
+
ON CONFLICT(key) DO UPDATE SET value = excluded.value
|
|
1395
|
+
`,
|
|
1396
|
+
args: [LAST_BULK_INGEST_META_KEY, (/* @__PURE__ */ new Date()).toISOString()]
|
|
1397
|
+
});
|
|
1389
1398
|
});
|
|
1390
1399
|
}
|
|
1400
|
+
async function getLastBulkIngestAt(db) {
|
|
1401
|
+
try {
|
|
1402
|
+
const result = await db.execute({
|
|
1403
|
+
sql: "SELECT value FROM _meta WHERE key = ? LIMIT 1",
|
|
1404
|
+
args: [LAST_BULK_INGEST_META_KEY]
|
|
1405
|
+
});
|
|
1406
|
+
const row = result.rows[0];
|
|
1407
|
+
return row?.value ? String(row.value) : null;
|
|
1408
|
+
} catch {
|
|
1409
|
+
return null;
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1391
1412
|
async function getSchemaVersion(db) {
|
|
1392
1413
|
try {
|
|
1393
1414
|
const result = await db.execute("SELECT value FROM _meta WHERE key = 'schema_version' LIMIT 1");
|
|
@@ -2227,6 +2248,7 @@ export {
|
|
|
2227
2248
|
getEntry,
|
|
2228
2249
|
retireEntry,
|
|
2229
2250
|
updateEntry,
|
|
2251
|
+
getLastBulkIngestAt,
|
|
2230
2252
|
createDatabase,
|
|
2231
2253
|
DEFAULT_SURGEON_COST_CAP,
|
|
2232
2254
|
DEFAULT_SURGEON_DAILY_COST_CAP,
|
package/dist/cli.js
CHANGED
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
deserializeTags,
|
|
21
21
|
getAuthMethodDefinition,
|
|
22
22
|
getEntry,
|
|
23
|
+
getLastBulkIngestAt,
|
|
23
24
|
isAgenrAuthMethod,
|
|
24
25
|
mapEntryRow,
|
|
25
26
|
readBoolean,
|
|
@@ -34,7 +35,7 @@ import {
|
|
|
34
35
|
retireEntry,
|
|
35
36
|
updateEntry,
|
|
36
37
|
writeConfig
|
|
37
|
-
} from "./chunk-
|
|
38
|
+
} from "./chunk-DSP74MEN.js";
|
|
38
39
|
import {
|
|
39
40
|
parseRelativeDate,
|
|
40
41
|
recall
|
|
@@ -7659,6 +7660,12 @@ function getSurgeonSystemPrompt() {
|
|
|
7659
7660
|
"",
|
|
7660
7661
|
"Use `source_file` and `source_context` as provenance clues. A transcript path, session file, or narrow snippet can explain why something looks like a temporary handoff or progress artifact. Provenance is evidence, not a retirement reason by itself.",
|
|
7661
7662
|
"",
|
|
7663
|
+
"## Corpus Age Awareness",
|
|
7664
|
+
"",
|
|
7665
|
+
"`get_health_stats` returns `lastBulkIngestAt` - the timestamp of the most recent bulk ingest (corpus rebuild). When the corpus has been recently rebuilt (within the last 30 days), treat `recall_count = 0` as carrying almost no signal. Every entry in a freshly rebuilt corpus starts at zero recalls regardless of its actual importance. In this window, weight content value, type durability, and subject uniqueness much more heavily than recall history.",
|
|
7666
|
+
"",
|
|
7667
|
+
"Even outside the rebuild window, never use `recall_count = 0` as the sole or primary retirement reason. Zero recall is a weak staleness signal that must be combined with other evidence: content obsolescence, clear supersession, or expired temporal relevance.",
|
|
7668
|
+
"",
|
|
7662
7669
|
"## Budget Awareness",
|
|
7663
7670
|
"",
|
|
7664
7671
|
"Use your budget carefully, but do not stop early just because a batch looks healthy. Keep paginating while candidates remain and your budget allows it. `complete_pass` will reject shallow completion when too much of the candidate pool remains unexplored.",
|
|
@@ -7718,6 +7725,20 @@ function getSurgeonRetirementPassPrompt() {
|
|
|
7718
7725
|
"- `lesson` - Rarely retire unless the lesson is tied to a tool, pattern, or situation that no longer applies.",
|
|
7719
7726
|
"- `relationship` - Retire when the relationship is clearly outdated or no longer real.",
|
|
7720
7727
|
"",
|
|
7728
|
+
"## Personal Knowledge",
|
|
7729
|
+
"",
|
|
7730
|
+
"Personal facts about the user - family members, pets, relationships, hardware, home setup, contact information, vehicles, physical environment, and identity details - are durable by nature even when importance is moderate. These entries represent the user's life context, not transient project state. They have lasting retrieval value because future sessions need this context to be helpful and personable.",
|
|
7731
|
+
"",
|
|
7732
|
+
"Retire personal knowledge entries only when:",
|
|
7733
|
+
"- Explicitly contradicted by a newer entry (for example, a pet has passed away or a family member has moved)",
|
|
7734
|
+
"- The entry is a clear duplicate of another active entry with identical or better coverage",
|
|
7735
|
+
"",
|
|
7736
|
+
"Do NOT retire personal knowledge entries because:",
|
|
7737
|
+
"- They have low or zero recall count",
|
|
7738
|
+
"- They have moderate importance (5-7)",
|
|
7739
|
+
"- They lack project tags",
|
|
7740
|
+
"- They seem like trivia - if it's about the user's life, it is not trivia to them",
|
|
7741
|
+
"",
|
|
7721
7742
|
"## Common Retirement Patterns",
|
|
7722
7743
|
"",
|
|
7723
7744
|
"- Old unrecalled temporaries",
|
|
@@ -7726,6 +7747,12 @@ function getSurgeonRetirementPassPrompt() {
|
|
|
7726
7747
|
"- Resolved problems and obsolete workarounds",
|
|
7727
7748
|
"- Older entries that are clearly covered better by newer entries on the same subject or cluster",
|
|
7728
7749
|
"",
|
|
7750
|
+
"## What Looks Like a Pattern But Is Not",
|
|
7751
|
+
"",
|
|
7752
|
+
"- Personal facts with zero recall - these are the user's life, not expired project context",
|
|
7753
|
+
"- Hardware, infrastructure, and environment details - these have ongoing operational value",
|
|
7754
|
+
"- Contact information and identity details - the user expects the system to know these",
|
|
7755
|
+
"",
|
|
7729
7756
|
"Use `source_file` and `source_context` to judge whether an entry came from a narrow session artifact, a handoff, a progress note, or a durable source. Provenance can explain why a memory existed and whether it was meant to last.",
|
|
7730
7757
|
"",
|
|
7731
7758
|
"## Budget Awareness",
|
|
@@ -8035,18 +8062,20 @@ function createHealthStatsTool(deps) {
|
|
|
8035
8062
|
description: "Inspect current corpus health and the latest surgeon run summary.",
|
|
8036
8063
|
parameters: GET_HEALTH_STATS_SCHEMA,
|
|
8037
8064
|
async execute() {
|
|
8038
|
-
const [health, lastRun] = await Promise.all([
|
|
8065
|
+
const [health, lastRun, lastBulkIngestAt] = await Promise.all([
|
|
8039
8066
|
getSurgeonHealthStats(deps.executor, {
|
|
8040
8067
|
protectRecalledDays: deps.protection.protectRecalledDays,
|
|
8041
8068
|
protectMinImportance: deps.protection.protectMinImportance,
|
|
8042
8069
|
now: deps.now()
|
|
8043
8070
|
}),
|
|
8044
|
-
getLastSurgeonRun(deps.executor)
|
|
8071
|
+
getLastSurgeonRun(deps.executor),
|
|
8072
|
+
getLastBulkIngestAt(deps.db)
|
|
8045
8073
|
]);
|
|
8046
8074
|
return toolResult({
|
|
8047
8075
|
now: deps.now().toISOString(),
|
|
8048
8076
|
health,
|
|
8049
|
-
lastRun
|
|
8077
|
+
lastRun,
|
|
8078
|
+
lastBulkIngestAt
|
|
8050
8079
|
});
|
|
8051
8080
|
}
|
|
8052
8081
|
};
|
|
@@ -8641,6 +8670,7 @@ async function runSurgeon(options, deps) {
|
|
|
8641
8670
|
budgetTracker
|
|
8642
8671
|
});
|
|
8643
8672
|
const tools = createSurgeonTools({
|
|
8673
|
+
db: deps.db,
|
|
8644
8674
|
executor: deps.db,
|
|
8645
8675
|
runId,
|
|
8646
8676
|
project: options.project,
|