@agenr/openclaw-plugin 0.10.1
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 +2363 -0
- package/LICENSE +661 -0
- package/README.md +321 -0
- package/dist/index.d.ts +338 -0
- package/dist/index.js +39399 -0
- package/openclaw.plugin.json +159 -0
- package/package.json +37 -0
- package/skills/SKILL.md +56 -0
package/README.md
ADDED
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
```text
|
|
2
|
+
█████╗ ██████╗ ███████╗███╗ ██╗██████╗
|
|
3
|
+
██╔══██╗██╔════╝ ██╔════╝████╗ ██║██╔══██╗
|
|
4
|
+
███████║██║ ███╗█████╗ ██╔██╗ ██║██████╔╝
|
|
5
|
+
██╔══██║██║ ██║██╔══╝ ██║╚██╗██║██╔══██╗
|
|
6
|
+
██║ ██║╚██████╔╝███████╗██║ ╚████║██║ ██║
|
|
7
|
+
╚═╝ ╚═╝ ╚═════╝ ╚══════╝╚═╝ ╚═══╝╚═╝ ╚═╝
|
|
8
|
+
AGENt memoRy
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
# AGENR
|
|
12
|
+
|
|
13
|
+
**AY-JEN-ER** - Human memory for AI agents.
|
|
14
|
+
|
|
15
|
+
This README is the overview and quick start. Canonical mechanism docs live in [docs/ARCHITECTURE.md](./docs/ARCHITECTURE.md) and [docs/OPENCLAW.md](./docs/OPENCLAW.md).
|
|
16
|
+
|
|
17
|
+
AGENR is a local, structured, universal, living memory layer for AI agents. It tackles session amnesia, multi-surface fragmentation, and vendor lock-in together so you get one person, many agents, one brain.
|
|
18
|
+
|
|
19
|
+
It extracts structured knowledge from conversation transcripts - facts, decisions, preferences, todos, relationships, events, lessons - and stores them in a local database with semantic search. Entries strengthen when reinforced, decay when stale, and resolve contradictions. Your memory stays on your machine.
|
|
20
|
+
|
|
21
|
+
More: [Vision](./docs/vision.md) | [Roadmap](./docs/roadmap.md) | [Architecture](./docs/ARCHITECTURE.md) | [OpenClaw guide](./docs/OPENCLAW.md)
|
|
22
|
+
|
|
23
|
+
## Quick Start
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
pnpm install -g agenr
|
|
27
|
+
agenr init
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
That's it. The interactive wizard handles everything: auth setup, platform detection, plugin installation, session ingestion, and watcher configuration. Run `agenr init` again anytime to reconfigure.
|
|
31
|
+
|
|
32
|
+
## What It Does
|
|
33
|
+
|
|
34
|
+
- **Extract** - An LLM reads your transcripts and pulls out structured entries. Smart filtering removes noise (tool calls, file contents, boilerplate - about 80% of a typical session) before the LLM sees it. Hedged or unverified agent claims are capped at importance 5 with an `unverified` tag.
|
|
35
|
+
- **Store** - Entries get embedded and compared against existing knowledge. Near-duplicates reinforce existing entries. New information gets inserted. Online dedup catches copies in real-time.
|
|
36
|
+
- **Recall** - Semantic search plus memory-aware ranking. Entries you recall often score higher. Stale entries decay. Contradicted entries get penalized.
|
|
37
|
+
- **Consolidate** - Periodic cleanup: rule-based expiry first, then optional LLM-assisted merging for entries that say the same thing differently.
|
|
38
|
+
|
|
39
|
+
```text
|
|
40
|
+
Transcript -> Filter -> Extract -> Store -> Recall
|
|
41
|
+
80% LLM dedup semantic
|
|
42
|
+
noise typed + embed + memory-
|
|
43
|
+
removed entries + dedup aware
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## What You Need
|
|
47
|
+
|
|
48
|
+
An **OpenAI API key** for embeddings (`text-embedding-3-small`). Embeddings cost fractions of a penny per operation - a full ingestion of 100+ session transcripts runs about $0.10 total.
|
|
49
|
+
|
|
50
|
+
For the LLM extraction step, AGENR supports:
|
|
51
|
+
- **OpenAI API key** (recommended) - `gpt-4.1` is highly recommended for best extraction quality; `gpt-4.1-mini` is the default and works well if cost is a concern; `gpt-4.1-nano` is the budget option
|
|
52
|
+
- **OpenAI Pro subscription** - no API key needed
|
|
53
|
+
- **Anthropic Claude subscription** - no API key needed
|
|
54
|
+
|
|
55
|
+
The `agenr init` wizard walks you through all of this.
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
export OPENAI_API_KEY=sk-... # for embeddings + extraction
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Platform Setup
|
|
62
|
+
|
|
63
|
+
### OpenClaw (recommended)
|
|
64
|
+
|
|
65
|
+
`agenr init` auto-detects OpenClaw, installs the native plugin, and restarts the gateway. The plugin handles everything automatically: session-start context injection (recent turns, core recall, browse recall, and a memory index), mid-session signals when important entries arrive, cross-session handoff summaries, and native `agenr_recall`, `agenr_store`, `agenr_extract`, `agenr_retire`, `agenr_update`, and session-project tools.
|
|
66
|
+
|
|
67
|
+
No AGENTS.md edits needed. No MCP config needed. The bundled SKILL.md loads automatically and instructs the agent when to call `agenr_store` proactively.
|
|
68
|
+
|
|
69
|
+
**Manual alternative:**
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
openclaw plugins install agenr
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
> **Security notice:** The OpenClaw plugin runs recall, store, extract, retire, update, and trace flows through shared in-process agenr services. It does not shell out to the agenr CLI, read your OpenClaw credentials, or send data anywhere except your configured model and embedding providers. The plugin source is open and auditable.
|
|
76
|
+
|
|
77
|
+
Optional config in `openclaw.json`:
|
|
78
|
+
|
|
79
|
+
```json
|
|
80
|
+
{
|
|
81
|
+
"plugins": {
|
|
82
|
+
"entries": {
|
|
83
|
+
"agenr": {
|
|
84
|
+
"config": {
|
|
85
|
+
"budget": 2000,
|
|
86
|
+
"signalMinImportance": 8,
|
|
87
|
+
"signalCooldownMs": 30000,
|
|
88
|
+
"signalMaxPerSession": 10
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Signal config controls how often mid-session notifications fire. See [docs/OPENCLAW.md](./docs/OPENCLAW.md) for all available options.
|
|
97
|
+
|
|
98
|
+
### Claude Code
|
|
99
|
+
|
|
100
|
+
```bash
|
|
101
|
+
agenr init --platform claude-code
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Adds the `agenr_recall` instruction block to `~/.claude/CLAUDE.md` and wires `.mcp.json`.
|
|
105
|
+
|
|
106
|
+
### Codex
|
|
107
|
+
|
|
108
|
+
```bash
|
|
109
|
+
agenr init --platform codex
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
Adds the `agenr_recall` instruction block to `~/.codex/AGENTS.md` and wires `~/.codex/config.toml`.
|
|
113
|
+
|
|
114
|
+
### Cursor
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
agenr init --platform cursor
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Adds instructions to `.cursor/rules/agenr.mdc` and wires `.cursor/mcp.json`.
|
|
121
|
+
|
|
122
|
+
### Windsurf
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
agenr init --platform windsurf
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
Adds instructions to `~/.codeium/windsurf/memories/global_rules.md` and wires `.mcp.json`.
|
|
129
|
+
|
|
130
|
+
### Generic / Any MCP Tool
|
|
131
|
+
|
|
132
|
+
```bash
|
|
133
|
+
agenr init # auto-detects platform, falls back to generic AGENTS.md
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Or start `agenr mcp` as a stdio MCP server and configure it in your tool's MCP settings manually. Your agent gets `agenr_recall`, `agenr_extract`, `agenr_retire`, and `agenr_update` as tools.
|
|
137
|
+
|
|
138
|
+
## How Memory Works
|
|
139
|
+
|
|
140
|
+
### Extraction & Storage
|
|
141
|
+
|
|
142
|
+
AGENR reads your session transcripts, filters out noise, and extracts structured knowledge entries. Each entry has a type, subject, content, importance, and expiry. Near-duplicates are caught automatically - if you discussed the same decision in three sessions, you get one entry with higher confirmations, not three copies.
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
agenr ingest ~/.openclaw/agents/main/sessions/ --glob '**/*.jsonl'
|
|
146
|
+
|
|
147
|
+
[1/108] session-abc123.jsonl (1.2MB) - 12 extracted, 10 stored, 1 skipped (duplicate), 1 reinforced
|
|
148
|
+
[2/108] session-def456.jsonl (800KB) - 8 extracted, 7 stored, 0 skipped, 1 reinforced
|
|
149
|
+
...
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
### Recall (semantic + memory-aware)
|
|
153
|
+
|
|
154
|
+
```bash
|
|
155
|
+
agenr recall "package manager"
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
```text
|
|
159
|
+
1 results (46ms)
|
|
160
|
+
1. [decision] project tooling: We switched this project to pnpm.
|
|
161
|
+
importance=7 | today | recalled 3 times
|
|
162
|
+
tags: tooling, package-manager
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Recall supports date range queries (`--since 14d --until 7d`), temporal browse mode (`--browse --since 1d`), and around-date targeting (`--around 2026-02-15 --around-radius 14`) to rank entries by distance from a specific date.
|
|
166
|
+
|
|
167
|
+
### Cross-session Handoff
|
|
168
|
+
|
|
169
|
+
When you start a new OpenClaw session, agenr injects a startup context assembled from four pieces:
|
|
170
|
+
|
|
171
|
+
1. **Recent turns** - the last few user/assistant turns from the previous session file for immediate continuity
|
|
172
|
+
2. **Core recall** - universal core memory plus project-tagged core memory for configured `coreProjects`
|
|
173
|
+
3. **Browse recall** - recent high-value memory, scoped by explicit session project when one exists, otherwise limited to universal / NULL-project entries
|
|
174
|
+
4. **Memory index** - a compact breadcrumb list of available projects and memory buckets
|
|
175
|
+
|
|
176
|
+
The plugin formats those pieces into startup markdown, applies selector and budget limits, and records only the entries that were actually rendered so startup and mid-session recall can dedupe cleanly.
|
|
177
|
+
|
|
178
|
+
When a session ends, the plugin writes a handoff using a fallback-first strategy: it stores a lightweight fallback entry immediately, then attempts an LLM-upgraded handoff summary. If the LLM upgrade succeeds, the fallback is retired. On the next session start, surfaced handoff entries are consumed and retired after use.
|
|
179
|
+
|
|
180
|
+
See [docs/OPENCLAW.md](./docs/OPENCLAW.md) for the current startup flow and [docs/OPENCLAW_HANDOFFS.md](./docs/OPENCLAW_HANDOFFS.md) for the detailed handoff lifecycle.
|
|
181
|
+
|
|
182
|
+
### Consolidation
|
|
183
|
+
|
|
184
|
+
Periodic cleanup merges near-duplicates and expires stale entries. Run manually or let the init wizard prompt you after a bulk ingest:
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
agenr consolidate
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
## Advanced
|
|
191
|
+
|
|
192
|
+
### Multi-instance & DB Isolation
|
|
193
|
+
|
|
194
|
+
When running multiple OpenClaw instances (or mixing OpenClaw and Codex), each instance gets registered in a global projects map at `~/.agenr/config.json`. By default, all instances share `~/.agenr/knowledge.db` with data separated by project tags.
|
|
195
|
+
|
|
196
|
+
For non-default OpenClaw paths, the init wizard offers isolated databases:
|
|
197
|
+
|
|
198
|
+
```text
|
|
199
|
+
~/.agenr/knowledge.db # shared (default)
|
|
200
|
+
~/my-openclaw/agenr-data/knowledge.db # isolated
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
The wizard writes the isolated DB path directly to the OpenClaw plugin config so no manual editing is needed.
|
|
204
|
+
|
|
205
|
+
### Manual Ingest
|
|
206
|
+
|
|
207
|
+
```bash
|
|
208
|
+
agenr ingest <paths...> --bulk --workers 10 --whole-file
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
The init wizard offers cost estimation before ingestion using model pricing, showing estimated token counts and costs for recent (last 7 days) vs full history ingestion.
|
|
212
|
+
|
|
213
|
+
### Live Watching & Watcher
|
|
214
|
+
|
|
215
|
+
The watcher tails your session files, extracts new knowledge every few minutes, and stores it. If you ingested history first, watch resumes right where ingest left off.
|
|
216
|
+
|
|
217
|
+
```bash
|
|
218
|
+
# Watch your sessions directory
|
|
219
|
+
agenr watch --platform openclaw
|
|
220
|
+
|
|
221
|
+
# Install as a background daemon (macOS launchd, 120s interval)
|
|
222
|
+
agenr watcher install
|
|
223
|
+
agenr watcher status
|
|
224
|
+
agenr watcher logs
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### Benchmarking
|
|
228
|
+
|
|
229
|
+
Evaluate extraction quality against scored rubrics:
|
|
230
|
+
|
|
231
|
+
```bash
|
|
232
|
+
agenr benchmark
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
Runs extraction against benchmark session fixtures, scores results against rubric JSON, and reports per-session plus overall metrics (recall, partial recall, precision proxy, composite score, pass rate). Supports multi-run aggregation with mean/min/stdev reporting.
|
|
236
|
+
|
|
237
|
+
### MCP Integration (manual)
|
|
238
|
+
|
|
239
|
+
If you prefer manual MCP setup over `agenr init`, start the stdio server:
|
|
240
|
+
|
|
241
|
+
```bash
|
|
242
|
+
agenr mcp
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
This exposes four MCP tools: `agenr_recall`, `agenr_extract`, `agenr_retire`, and `agenr_update`. Persistent session capture comes from watcher ingestion and platform integrations rather than an MCP `agenr_store` tool.
|
|
246
|
+
|
|
247
|
+
## Commands
|
|
248
|
+
|
|
249
|
+
| Command | What it does |
|
|
250
|
+
| --- | --- |
|
|
251
|
+
| `agenr init` | Interactive setup wizard: auth, platform detection, plugin install, ingestion, watcher. Replaces the old `setup` flow. Use `--platform` to skip auto-detection. |
|
|
252
|
+
| `agenr setup` | Configure LLM provider, auth, and model defaults (also available inside `init`) |
|
|
253
|
+
| `agenr config` | Show and update agenr configuration |
|
|
254
|
+
| `agenr auth` | Authentication status and diagnostics |
|
|
255
|
+
| `agenr ingest <paths...>` | Bulk-ingest files and directories |
|
|
256
|
+
| `agenr synthetic` | Generate synthetic recall signals from existing DB entries (no re-ingest required) |
|
|
257
|
+
| `agenr extract <files...>` | Extract knowledge entries from text files |
|
|
258
|
+
| `agenr store [files...]` | Store entries with semantic dedup |
|
|
259
|
+
| `agenr recall [query]` | Semantic + memory-aware recall. Use `--since`/`--until` for date ranges, `--around` for target-date ranking, `--browse` for temporal mode. |
|
|
260
|
+
| `agenr retire [subject]` | Retire a stale entry (hidden, not deleted). Match by subject or `--id`. |
|
|
261
|
+
| `agenr update --id <id> --importance <n>` | Update an entry in place. Currently supports importance only. |
|
|
262
|
+
| `agenr watch [file]` | Live-watch files/directories, auto-extract knowledge |
|
|
263
|
+
| `agenr watcher install` | Install background watch daemon (macOS launchd) |
|
|
264
|
+
| `agenr watcher status` | Show daemon status (running/stopped, pid, watched file, recent logs) |
|
|
265
|
+
| `agenr watcher logs` | Stream or show recent daemon logs |
|
|
266
|
+
| `agenr consolidate` | Clean up and merge near-duplicates |
|
|
267
|
+
| `agenr benchmark` | Run extraction against benchmark fixtures and score results |
|
|
268
|
+
| `agenr context` | Generate context file for AI tool integration |
|
|
269
|
+
| `agenr health` | Show database health and forgetting candidates |
|
|
270
|
+
| `agenr mcp` | Start MCP server (stdio) |
|
|
271
|
+
| `agenr todo <subcommand>` | Manage todos in the knowledge base |
|
|
272
|
+
| `agenr db <cmd>` | Database management (stats, version, export, reset, path, check, rebuild-index) |
|
|
273
|
+
|
|
274
|
+
Full reference: [docs/CLI.md](./docs/CLI.md) | [docs/CONFIGURATION.md](./docs/CONFIGURATION.md)
|
|
275
|
+
|
|
276
|
+
## Architecture
|
|
277
|
+
|
|
278
|
+
- **Runtime:** Node.js 20+, TypeScript, ESM
|
|
279
|
+
- **Storage:** libsql/SQLite - default at `~/.agenr/knowledge.db`, optionally isolated per instance
|
|
280
|
+
- **Embeddings:** OpenAI `text-embedding-3-small`, 1024 dimensions
|
|
281
|
+
- **Recall scoring:** Vector similarity x recency x memory strength (max(importance, recall strength)), with contradiction penalties
|
|
282
|
+
- **Global config:** `~/.agenr/config.json` - stores auth, model, and a projects map keyed by directory path with platform, project slug, and optional isolated DB path per instance
|
|
283
|
+
|
|
284
|
+
Deep dive: [docs/ARCHITECTURE.md](./docs/ARCHITECTURE.md)
|
|
285
|
+
|
|
286
|
+
## Status
|
|
287
|
+
|
|
288
|
+
The core pipeline is stable and tested. We use it daily managing thousands of knowledge entries across OpenClaw sessions.
|
|
289
|
+
|
|
290
|
+
**Shipped:** extraction, storage, recall (semantic + browse), MCP integration, online dedup, consolidation, smart filtering, live watching, daemon mode, cross-session handoff (LLM-summarized), three-phase context injection, interactive init wizard, cost estimation, DB isolation, benchmarking.
|
|
291
|
+
|
|
292
|
+
**Next:** GUI Management Console (browse, search, and curate your knowledge database visually), Cursor live signals, Claude Code UserPromptSubmit adapter, transitive project dependencies.
|
|
293
|
+
|
|
294
|
+
## Philosophy
|
|
295
|
+
|
|
296
|
+
The big labs are building bigger brains. agenr is building better continuity.
|
|
297
|
+
|
|
298
|
+
The product bet is that memory should be local, structured, universal, and living: local because it is yours, structured because "what did we decide?" needs a real answer, universal because it should work across surfaces, and living because stale or contradicted memory must be maintained rather than merely accumulated.
|
|
299
|
+
|
|
300
|
+
For the product thesis, see [docs/vision.md](./docs/vision.md).
|
|
301
|
+
|
|
302
|
+
## Troubleshooting
|
|
303
|
+
|
|
304
|
+
| Problem | Fix |
|
|
305
|
+
|---|---|
|
|
306
|
+
| `agenr init` wizard fails to detect platform | Pass `--platform openclaw` (or `codex`, `claude-code`, etc.) explicitly |
|
|
307
|
+
| Plugin install fails during wizard | Run `openclaw plugins install agenr` manually, then `openclaw gateway restart` |
|
|
308
|
+
| Embeddings fail | Set `OPENAI_API_KEY` env var or `agenr config set-key openai <key>` |
|
|
309
|
+
| Database locked | Wait for consolidation to finish, or check `~/.agenr/consolidation.lock` |
|
|
310
|
+
| Recall returns nothing after force-kill | `agenr db rebuild-index` (vector index corruption) |
|
|
311
|
+
| Extraction fails mid-file | Retry - dedup skips already-stored entries |
|
|
312
|
+
| Stale handoff entries persist | Run `agenr recall --browse --since 1d` to check, then `agenr retire --id <id>` |
|
|
313
|
+
| Gateway doesn't pick up plugin | Run `openclaw gateway restart` after plugin install |
|
|
314
|
+
|
|
315
|
+
## License
|
|
316
|
+
|
|
317
|
+
AGPL-3.0 - [LICENSE](./LICENSE)
|
|
318
|
+
|
|
319
|
+
## Contributing
|
|
320
|
+
|
|
321
|
+
See [CONTRIBUTING.md](./CONTRIBUTING.md)
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,338 @@
|
|
|
1
|
+
import { Model, Api, Context, SimpleStreamOptions, AssistantMessageEvent, AssistantMessage } from '@mariozechner/pi-ai';
|
|
2
|
+
import * as _sinclair_typebox from '@sinclair/typebox';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Handoff transcript helpers - reading, parsing, building, and formatting
|
|
6
|
+
* transcript content for session handoff summaries.
|
|
7
|
+
*/
|
|
8
|
+
type HandoffMessage = {
|
|
9
|
+
role: "user" | "assistant";
|
|
10
|
+
content: string;
|
|
11
|
+
timestamp: string;
|
|
12
|
+
};
|
|
13
|
+
declare function getBaseSessionPath(filePath: string): string;
|
|
14
|
+
declare function readSessionsJson(sessionsDir: string): Promise<Record<string, unknown>>;
|
|
15
|
+
declare function readAndParseSessionJsonl(sessionFile: string): Promise<unknown[]>;
|
|
16
|
+
declare function getSurfaceForSessionFile(sessionFilePath: string, sessionsJson: Record<string, unknown>, sessionsDir?: string): string;
|
|
17
|
+
declare function readMessagesFromJsonl(filePath: string): Promise<HandoffMessage[]>;
|
|
18
|
+
declare function findPriorResetFile(sessionsDir: string, currentSessionFile: string): Promise<string | null>;
|
|
19
|
+
declare function buildTranscript(messages: HandoffMessage[], surface: string): string;
|
|
20
|
+
declare function buildMergedTranscript(priorMessages: HandoffMessage[], priorSurface: string, currentMessages: HandoffMessage[], currentSurface: string): string;
|
|
21
|
+
declare function capTranscriptLength(params: {
|
|
22
|
+
priorMessages: HandoffMessage[];
|
|
23
|
+
priorSurface: string;
|
|
24
|
+
currentMessages: HandoffMessage[];
|
|
25
|
+
currentSurface: string;
|
|
26
|
+
maxChars: number;
|
|
27
|
+
}): string;
|
|
28
|
+
|
|
29
|
+
type RecallIntentFamily = "generic" | "invariant_lookup" | "prerequisite_step" | "policy_bundle_lookup";
|
|
30
|
+
/**
|
|
31
|
+
* Stable, product-level semantics for the bounded recall decision layer.
|
|
32
|
+
* Keep lexical hits, thresholds, and other heuristic internals in trace data.
|
|
33
|
+
*/
|
|
34
|
+
type RecallReasonCode = "sufficient_direct_support" | "sufficient_composite_support" | "subject_mismatch" | "no_answer_bearing_support" | "ambiguous_competing_support" | "support_set_too_diffuse" | "support_below_confidence_floor";
|
|
35
|
+
type RecallSupportMode = "single" | "pair" | "continuity_bundle";
|
|
36
|
+
/**
|
|
37
|
+
* Additive recall payload emitted only when the bounded MVP layer is allowed to
|
|
38
|
+
* intervene. Absence means generic retrieval fallback, not an implicit abstain.
|
|
39
|
+
*
|
|
40
|
+
* In this MVP, `abstain` means the supported-intent post-retrieval pass found
|
|
41
|
+
* no single-support winner above its confidence and ambiguity guardrails.
|
|
42
|
+
*/
|
|
43
|
+
interface RecallDecision {
|
|
44
|
+
decision: "answer" | "abstain";
|
|
45
|
+
intent: RecallIntentFamily;
|
|
46
|
+
reasonCodes: RecallReasonCode[];
|
|
47
|
+
supportMode?: RecallSupportMode;
|
|
48
|
+
supportIds: string[];
|
|
49
|
+
surfacedIds: string[];
|
|
50
|
+
competingIds: string[];
|
|
51
|
+
}
|
|
52
|
+
interface RecallCategoryRollupFacetSummary {
|
|
53
|
+
facet: string;
|
|
54
|
+
label: string;
|
|
55
|
+
summary: string;
|
|
56
|
+
evidence_ids: string[];
|
|
57
|
+
evidence_subjects: string[];
|
|
58
|
+
}
|
|
59
|
+
interface RecallCategoryRollupSummary {
|
|
60
|
+
mode: "category_rollup";
|
|
61
|
+
path: "category_rollup_synthesis_v1";
|
|
62
|
+
style: "broad_synthesis" | "project_story";
|
|
63
|
+
kind: "family" | "personal_life" | "work" | "project";
|
|
64
|
+
target: string;
|
|
65
|
+
subject?: string;
|
|
66
|
+
narrative: string;
|
|
67
|
+
coverage: "broad" | "partial" | "sparse";
|
|
68
|
+
evidence_ids: string[];
|
|
69
|
+
evidence_subjects: string[];
|
|
70
|
+
evidence_count: number;
|
|
71
|
+
covered_facets: string[];
|
|
72
|
+
facet_summaries: RecallCategoryRollupFacetSummary[];
|
|
73
|
+
low_coverage_note?: string;
|
|
74
|
+
project_rollup?: {
|
|
75
|
+
kind: "project_history_v1";
|
|
76
|
+
project_subject: string;
|
|
77
|
+
prioritized_facets: Array<"project_scope" | "architecture" | "implementation" | "validation" | "follow_up">;
|
|
78
|
+
section_order: string[];
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
type SimpleAssistantStream = AsyncIterable<AssistantMessageEvent> & {
|
|
83
|
+
result: () => Promise<AssistantMessage>;
|
|
84
|
+
};
|
|
85
|
+
type StreamSimpleFn = (model: Model<Api>, context: Context, options?: SimpleStreamOptions) => SimpleAssistantStream;
|
|
86
|
+
|
|
87
|
+
declare const OPENCLAW_MEMORY_RELIABILITY_DIAGNOSTIC_SCHEMA_VERSION: "openclaw-memory-reliability-diagnostic-v1";
|
|
88
|
+
type DiagnosticSessionProjectState = "set" | "cleared" | "unset" | "not-applicable";
|
|
89
|
+
type DiagnosticWriteAttributionSurface = "native-store" | "watcher" | "handoff" | "openclaw-bridge-store";
|
|
90
|
+
type DiagnosticWriteAttributionSource = "tool-project" | "session-project" | "plugin-default" | "watcher-fallback" | "entry-project" | "shared-attribution" | "bridge-fallback" | "none";
|
|
91
|
+
type DiagnosticWriteAttributionReason = "explicit-tool-project" | "explicit-session-project" | "explicit-session-cleared" | "session-project-not-worthy" | "plugin-default-project" | "watcher-inferred-project" | "existing-entry-project" | "shared-project-attribution" | "bridge-fallback-project" | "no-project-candidate";
|
|
92
|
+
type DiagnosticWriteAttributionKind = "explicit" | "inferred" | "default" | "shared" | "fallback" | "global";
|
|
93
|
+
interface WriteAttributionResolutionDiagnostic {
|
|
94
|
+
kind: "openclaw-memory-reliability-diagnostic";
|
|
95
|
+
schemaVersion: typeof OPENCLAW_MEMORY_RELIABILITY_DIAGNOSTIC_SCHEMA_VERSION;
|
|
96
|
+
decisionClass: "write-attribution-resolution";
|
|
97
|
+
ownerSubsystem: "write-attribution";
|
|
98
|
+
laneHint: "cross-surface-scope-attribution";
|
|
99
|
+
surface: DiagnosticWriteAttributionSurface;
|
|
100
|
+
inputs: {
|
|
101
|
+
explicitProjectProvided: boolean;
|
|
102
|
+
sessionProjectState: DiagnosticSessionProjectState;
|
|
103
|
+
defaultProjectPresent: boolean;
|
|
104
|
+
fallbackProjectPresent: boolean;
|
|
105
|
+
entryProjectPresent: boolean;
|
|
106
|
+
upstreamAttributionPresent: boolean;
|
|
107
|
+
};
|
|
108
|
+
outcome: {
|
|
109
|
+
project: string | null;
|
|
110
|
+
source: DiagnosticWriteAttributionSource;
|
|
111
|
+
reason: DiagnosticWriteAttributionReason;
|
|
112
|
+
attributionKind: DiagnosticWriteAttributionKind;
|
|
113
|
+
sessionProjectGate: "batch" | "entry" | "not-applicable";
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
type DiagnosticSurfacedMemorySurface = "session-start" | "mid-session-recall" | "agent-tool-recall";
|
|
117
|
+
type DiagnosticSurfacedMemoryStage = "browse-admitted" | "selector-shaped" | "render-input" | "retrieved" | "prompt-visible" | "nudge-candidates";
|
|
118
|
+
type DiagnosticSurfacedMemorySource = "plugin-injection" | "agent-tool-output";
|
|
119
|
+
type DiagnosticSurfacedMemoryOwnershipClass = "startup-pre-prompt-candidate" | "startup-render-input-candidate" | "startup-prompt-visible-before-reset-owned" | "mid-session-retrieved-candidate" | "mid-session-prompt-visible-dedupe-only" | "mid-session-nudge-candidate" | "agent-tool-prompt-visible-dedupe-only";
|
|
120
|
+
type DiagnosticSurfacedMemoryReason = "startup-pre-prompt-stage" | "startup-render-input-stage" | "startup-prompt-visible-stage" | "mid-session-retrieved-stage" | "mid-session-prompt-visible-stage" | "mid-session-nudge-stage" | "agent-tool-prompt-visible-stage";
|
|
121
|
+
interface SurfacedMemoryOwnershipDiagnostic {
|
|
122
|
+
kind: "openclaw-memory-reliability-diagnostic";
|
|
123
|
+
schemaVersion: typeof OPENCLAW_MEMORY_RELIABILITY_DIAGNOSTIC_SCHEMA_VERSION;
|
|
124
|
+
decisionClass: "surfaced-memory-ownership-classification";
|
|
125
|
+
ownerSubsystem: "surfaced-memory-contract";
|
|
126
|
+
laneHint: "user-facing-surfacing";
|
|
127
|
+
surface: DiagnosticSurfacedMemorySurface;
|
|
128
|
+
stage: DiagnosticSurfacedMemoryStage;
|
|
129
|
+
source?: DiagnosticSurfacedMemorySource;
|
|
130
|
+
ownershipClass: DiagnosticSurfacedMemoryOwnershipClass;
|
|
131
|
+
reason: DiagnosticSurfacedMemoryReason;
|
|
132
|
+
outcome: {
|
|
133
|
+
promptVisible: boolean;
|
|
134
|
+
dedupeEligible: boolean;
|
|
135
|
+
beforeResetOwned: boolean;
|
|
136
|
+
handoffConsumptionEligible: boolean;
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
interface RecallSurfaceSelection {
|
|
141
|
+
authoritative: boolean;
|
|
142
|
+
abstained: boolean;
|
|
143
|
+
surfacedIds: string[];
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
type RecallEntry = {
|
|
147
|
+
type: string;
|
|
148
|
+
subject: string;
|
|
149
|
+
content: string;
|
|
150
|
+
importance?: number;
|
|
151
|
+
};
|
|
152
|
+
type RecallResult = {
|
|
153
|
+
query: string;
|
|
154
|
+
decision?: RecallDecision;
|
|
155
|
+
rollupSummary?: RecallCategoryRollupSummary;
|
|
156
|
+
surfaceSelection?: RecallSurfaceSelection;
|
|
157
|
+
results: Array<{
|
|
158
|
+
entry: RecallEntry & Record<string, unknown>;
|
|
159
|
+
score: number;
|
|
160
|
+
category?: string;
|
|
161
|
+
}>;
|
|
162
|
+
};
|
|
163
|
+
type RecallResultItems = RecallResult["results"];
|
|
164
|
+
|
|
165
|
+
type MidSessionMemoryItems = RecallResultItems;
|
|
166
|
+
interface PromptVisibleAgentToolRecallMemory {
|
|
167
|
+
surface: "agent-tool-recall";
|
|
168
|
+
stage: "prompt-visible";
|
|
169
|
+
visibility: "prompt-visible";
|
|
170
|
+
source: "agent-tool-output";
|
|
171
|
+
query: string;
|
|
172
|
+
items: MidSessionMemoryItems;
|
|
173
|
+
memoryReliabilityDiagnostic?: SurfacedMemoryOwnershipDiagnostic;
|
|
174
|
+
}
|
|
175
|
+
interface PromptVisibleAgentToolRecallMemoryBookkeeping {
|
|
176
|
+
surface: "agent-tool-recall";
|
|
177
|
+
stage: "prompt-visible";
|
|
178
|
+
visibility: "prompt-visible";
|
|
179
|
+
source: PromptVisibleAgentToolRecallMemory["source"];
|
|
180
|
+
surfacedEntryIds: string[];
|
|
181
|
+
beforeResetOwnedEntryIds: string[];
|
|
182
|
+
memoryReliabilityDiagnostic?: SurfacedMemoryOwnershipDiagnostic;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
type BeforeAgentStartEvent = {
|
|
186
|
+
prompt?: string;
|
|
187
|
+
messages?: unknown[];
|
|
188
|
+
[key: string]: unknown;
|
|
189
|
+
};
|
|
190
|
+
type PluginHookAgentContext = {
|
|
191
|
+
sessionKey?: string;
|
|
192
|
+
sessionId?: string;
|
|
193
|
+
agentId?: string;
|
|
194
|
+
workspaceDir?: string;
|
|
195
|
+
[key: string]: unknown;
|
|
196
|
+
};
|
|
197
|
+
type BeforeAgentStartResult = {
|
|
198
|
+
prependContext?: string;
|
|
199
|
+
};
|
|
200
|
+
type BeforePromptBuildEvent = {
|
|
201
|
+
prompt?: string;
|
|
202
|
+
messages?: unknown[];
|
|
203
|
+
[key: string]: unknown;
|
|
204
|
+
};
|
|
205
|
+
type BeforePromptBuildResult = {
|
|
206
|
+
systemPrompt?: string;
|
|
207
|
+
prependContext?: string;
|
|
208
|
+
prependSystemContext?: string;
|
|
209
|
+
};
|
|
210
|
+
type BeforeResetEvent = {
|
|
211
|
+
sessionFile?: string;
|
|
212
|
+
messages?: unknown[];
|
|
213
|
+
reason?: string;
|
|
214
|
+
[key: string]: unknown;
|
|
215
|
+
};
|
|
216
|
+
type PluginLogger = {
|
|
217
|
+
debug?: (message: string) => void;
|
|
218
|
+
info?: (message: string) => void;
|
|
219
|
+
warn: (message: string) => void;
|
|
220
|
+
error: (message: string) => void;
|
|
221
|
+
};
|
|
222
|
+
type PluginToolResult = {
|
|
223
|
+
content: Array<{
|
|
224
|
+
type: "text";
|
|
225
|
+
text: string;
|
|
226
|
+
}>;
|
|
227
|
+
details?: Record<string, unknown>;
|
|
228
|
+
agentToolRecallSurface?: PromptVisibleAgentToolRecallMemoryBookkeeping;
|
|
229
|
+
};
|
|
230
|
+
type PluginTool = {
|
|
231
|
+
name: string;
|
|
232
|
+
label?: string;
|
|
233
|
+
description: string;
|
|
234
|
+
parameters: _sinclair_typebox.TObject;
|
|
235
|
+
execute: (toolCallId: string, params: Record<string, unknown>) => Promise<PluginToolResult>;
|
|
236
|
+
};
|
|
237
|
+
type PluginToolOptions = {
|
|
238
|
+
name?: string;
|
|
239
|
+
names?: string[];
|
|
240
|
+
optional?: boolean;
|
|
241
|
+
};
|
|
242
|
+
type InternalHookEvent = {
|
|
243
|
+
type: "command" | "session" | "agent" | "gateway" | "message";
|
|
244
|
+
action: string;
|
|
245
|
+
sessionKey: string;
|
|
246
|
+
context: Record<string, unknown>;
|
|
247
|
+
timestamp: Date;
|
|
248
|
+
messages: string[];
|
|
249
|
+
};
|
|
250
|
+
type InternalHookHandler = (event: InternalHookEvent) => Promise<void> | void;
|
|
251
|
+
type PluginHookOptions = {
|
|
252
|
+
priority?: number;
|
|
253
|
+
entry?: unknown;
|
|
254
|
+
name?: string;
|
|
255
|
+
description?: string;
|
|
256
|
+
register?: boolean;
|
|
257
|
+
};
|
|
258
|
+
type PluginApi = {
|
|
259
|
+
id: string;
|
|
260
|
+
name: string;
|
|
261
|
+
version?: string;
|
|
262
|
+
pluginConfig?: Record<string, unknown>;
|
|
263
|
+
logger: PluginLogger;
|
|
264
|
+
registerTool?: (tool: PluginTool, opts?: PluginToolOptions) => void;
|
|
265
|
+
registerHook?: (events: string | string[], handler: InternalHookHandler, opts?: PluginHookOptions) => void;
|
|
266
|
+
on: {
|
|
267
|
+
(hook: "before_agent_start", handler: (event: BeforeAgentStartEvent, ctx: PluginHookAgentContext) => Promise<BeforeAgentStartResult | undefined> | BeforeAgentStartResult | undefined): void;
|
|
268
|
+
(hook: "before_prompt_build", handler: (event: BeforePromptBuildEvent, ctx: PluginHookAgentContext) => Promise<BeforePromptBuildResult | undefined> | BeforePromptBuildResult | undefined): void;
|
|
269
|
+
(hook: "before_reset", handler: (event: BeforeResetEvent, ctx: PluginHookAgentContext) => Promise<void> | void): void;
|
|
270
|
+
};
|
|
271
|
+
};
|
|
272
|
+
|
|
273
|
+
type OpenClawWriteAttributionSurface = "native-store" | "watcher" | "handoff";
|
|
274
|
+
type OpenClawWriteAttributionSource = "tool-project" | "session-project" | "plugin-default" | "watcher-fallback" | "entry-project" | "none";
|
|
275
|
+
type OpenClawWriteAttributionReason = "explicit-tool-project" | "explicit-session-project" | "explicit-session-cleared" | "session-project-not-worthy" | "plugin-default-project" | "watcher-inferred-project" | "existing-entry-project" | "no-project-candidate";
|
|
276
|
+
type OpenClawWriteAttributionKind = "explicit" | "inferred" | "default" | "global";
|
|
277
|
+
type OpenClawWriteAttributionResolution = {
|
|
278
|
+
surface: OpenClawWriteAttributionSurface;
|
|
279
|
+
project: string | null;
|
|
280
|
+
source: OpenClawWriteAttributionSource;
|
|
281
|
+
reason: OpenClawWriteAttributionReason;
|
|
282
|
+
attributionKind: OpenClawWriteAttributionKind;
|
|
283
|
+
sessionProjectGate: "batch" | "entry" | "not-applicable";
|
|
284
|
+
strictnessRelevant: false;
|
|
285
|
+
dependencyExpansionRelevant: false;
|
|
286
|
+
memoryReliabilityDiagnostic?: WriteAttributionResolutionDiagnostic;
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
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>;
|
|
290
|
+
interface RunHandoffForSessionOptions {
|
|
291
|
+
messages: unknown[];
|
|
292
|
+
sessionFile: string | null;
|
|
293
|
+
sessionId: string;
|
|
294
|
+
sessionKey: string;
|
|
295
|
+
agentId: string;
|
|
296
|
+
budget: number;
|
|
297
|
+
defaultProject: string | undefined;
|
|
298
|
+
projectAttribution?: OpenClawWriteAttributionResolution;
|
|
299
|
+
storeConfig: Record<string, unknown>;
|
|
300
|
+
sessionsDir: string;
|
|
301
|
+
includeBackground?: boolean;
|
|
302
|
+
logEnabled?: boolean;
|
|
303
|
+
logDir?: string;
|
|
304
|
+
debugEnabled?: boolean;
|
|
305
|
+
logger: PluginLogger | undefined;
|
|
306
|
+
source: "before_reset" | "command" | "session_start";
|
|
307
|
+
dbPath?: string;
|
|
308
|
+
summarizeSessionForHandoffImpl?: typeof summarizeSessionForHandoff;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
declare function stripInjectedContext(text: string): string;
|
|
312
|
+
|
|
313
|
+
type RunHandoffForSessionArgs = Omit<RunHandoffForSessionOptions, "summarizeSessionForHandoffImpl">;
|
|
314
|
+
declare const plugin: {
|
|
315
|
+
id: string;
|
|
316
|
+
name: string;
|
|
317
|
+
description: string;
|
|
318
|
+
register(api: PluginApi): void;
|
|
319
|
+
};
|
|
320
|
+
declare const __testing: {
|
|
321
|
+
clearState(): void;
|
|
322
|
+
readSessionsJson: typeof readSessionsJson;
|
|
323
|
+
readAndParseSessionJsonl: typeof readAndParseSessionJsonl;
|
|
324
|
+
getBaseSessionPath: typeof getBaseSessionPath;
|
|
325
|
+
getSurfaceForSessionFile: typeof getSurfaceForSessionFile;
|
|
326
|
+
readMessagesFromJsonl: typeof readMessagesFromJsonl;
|
|
327
|
+
stripInjectedContext: typeof stripInjectedContext;
|
|
328
|
+
findPriorResetFile: typeof findPriorResetFile;
|
|
329
|
+
buildTranscript: typeof buildTranscript;
|
|
330
|
+
buildMergedTranscript: typeof buildMergedTranscript;
|
|
331
|
+
capTranscriptLength: typeof capTranscriptLength;
|
|
332
|
+
HANDOFF_SUMMARY_SYSTEM_PROMPT: string;
|
|
333
|
+
HANDOFF_SUMMARY_SYSTEM_PROMPT_WITH_BACKGROUND: string;
|
|
334
|
+
summarizeSessionForHandoff: typeof summarizeSessionForHandoff;
|
|
335
|
+
runHandoffForSession(opts: RunHandoffForSessionArgs): Promise<void>;
|
|
336
|
+
};
|
|
337
|
+
|
|
338
|
+
export { __testing, plugin as default };
|