@agenr/openclaw-plugin 0.12.2 → 0.13.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 CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.12.3] - 2026-03-22
4
+
5
+ ### Fixed
6
+
7
+ - **Plugin DB tables in core schema.** `session_projects`, `seen_sessions`, and `session_identity_breadcrumbs` tables are now created as part of the main schema init, fixing `SQLITE_ERROR: no such table: session_projects` errors when calling `agenr_set_session_project` or `agenr_get_session_project`. Previously these tables depended on a lazy plugin-db init path that could fail to run.
8
+ - **Tool schema Codex compatibility.** Replaced `Type.Union([Type.Literal(...)])` with `Type.String({ enum: [...] })` for the `expiry` and recall `context` fields in tool schemas. Codex and other providers that reject `anyOf`/`oneOf` at top level now get clean schemas.
9
+ - **Support-aware cluster validation.** Consolidation cluster validation now uses support-aware entry resolution, preventing false merge candidates from stale or unsupported cluster assignments.
10
+
3
11
  ## [0.12.2] - 2026-03-22
4
12
 
5
13
  ### Recall Scoping Fixes
package/dist/index.js CHANGED
@@ -107,7 +107,7 @@ var init_logger = __esm({
107
107
  });
108
108
 
109
109
  // src/db/schema/definitions.ts
110
- var CREATE_IDX_ENTRIES_EMBEDDING_SQL, CREATE_ENTRIES_FTS_TABLE_SQL, CREATE_ENTRIES_FTS_TRIGGER_AI_SQL, CREATE_ENTRIES_FTS_TRIGGER_AD_SQL, CREATE_ENTRIES_FTS_TRIGGER_AU_SQL, CREATE_TABLE_AND_TRIGGER_STATEMENTS, COLUMN_MIGRATIONS, CREATE_INDEX_STATEMENTS;
110
+ var CREATE_IDX_ENTRIES_EMBEDDING_SQL, CREATE_ENTRIES_FTS_TABLE_SQL, CREATE_ENTRIES_FTS_TRIGGER_AI_SQL, CREATE_ENTRIES_FTS_TRIGGER_AD_SQL, CREATE_ENTRIES_FTS_TRIGGER_AU_SQL, CREATE_SEEN_SESSIONS_TABLE_SQL, CREATE_SEEN_SESSIONS_SEEN_AT_INDEX_SQL, CREATE_SESSION_PROJECTS_TABLE_SQL, CREATE_SESSION_IDENTITY_BREADCRUMBS_TABLE_SQL, CREATE_SESSION_IDENTITY_BREADCRUMBS_UPDATED_AT_INDEX_SQL, ADD_SESSION_PROJECT_STATE_COLUMN_SQL, OPENCLAW_PLUGIN_SCHEMA_STATEMENTS, OPENCLAW_PLUGIN_COLUMN_MIGRATIONS, CREATE_TABLE_AND_TRIGGER_STATEMENTS, COLUMN_MIGRATIONS, CREATE_INDEX_STATEMENTS;
111
111
  var init_definitions = __esm({
112
112
  "src/db/schema/definitions.ts"() {
113
113
  "use strict";
@@ -146,6 +146,60 @@ var init_definitions = __esm({
146
146
  WHERE new.retired = 0 AND new.superseded_by IS NULL;
147
147
  END
148
148
  `;
149
+ CREATE_SEEN_SESSIONS_TABLE_SQL = `
150
+ CREATE TABLE IF NOT EXISTS seen_sessions (
151
+ dedupe_key TEXT PRIMARY KEY,
152
+ seen_at INTEGER NOT NULL
153
+ )
154
+ `;
155
+ CREATE_SEEN_SESSIONS_SEEN_AT_INDEX_SQL = `
156
+ CREATE INDEX IF NOT EXISTS idx_seen_sessions_seen_at
157
+ ON seen_sessions(seen_at)
158
+ `;
159
+ CREATE_SESSION_PROJECTS_TABLE_SQL = `
160
+ CREATE TABLE IF NOT EXISTS session_projects (
161
+ session_key TEXT PRIMARY KEY,
162
+ project TEXT NOT NULL,
163
+ state TEXT NOT NULL DEFAULT 'set',
164
+ updated_at TEXT NOT NULL
165
+ )
166
+ `;
167
+ CREATE_SESSION_IDENTITY_BREADCRUMBS_TABLE_SQL = `
168
+ CREATE TABLE IF NOT EXISTS session_identity_breadcrumbs (
169
+ session_id TEXT PRIMARY KEY,
170
+ session_key TEXT,
171
+ family TEXT NOT NULL,
172
+ lane_id TEXT,
173
+ origin_surface TEXT,
174
+ delivery_channel TEXT,
175
+ family_source TEXT,
176
+ lane_source TEXT,
177
+ created_at TEXT NOT NULL,
178
+ updated_at TEXT NOT NULL
179
+ )
180
+ `;
181
+ CREATE_SESSION_IDENTITY_BREADCRUMBS_UPDATED_AT_INDEX_SQL = `
182
+ CREATE INDEX IF NOT EXISTS idx_session_identity_breadcrumbs_updated_at
183
+ ON session_identity_breadcrumbs(updated_at)
184
+ `;
185
+ ADD_SESSION_PROJECT_STATE_COLUMN_SQL = `
186
+ ALTER TABLE session_projects
187
+ ADD COLUMN state TEXT NOT NULL DEFAULT 'set'
188
+ `;
189
+ OPENCLAW_PLUGIN_SCHEMA_STATEMENTS = [
190
+ CREATE_SEEN_SESSIONS_TABLE_SQL,
191
+ CREATE_SEEN_SESSIONS_SEEN_AT_INDEX_SQL,
192
+ CREATE_SESSION_PROJECTS_TABLE_SQL,
193
+ CREATE_SESSION_IDENTITY_BREADCRUMBS_TABLE_SQL,
194
+ CREATE_SESSION_IDENTITY_BREADCRUMBS_UPDATED_AT_INDEX_SQL
195
+ ];
196
+ OPENCLAW_PLUGIN_COLUMN_MIGRATIONS = [
197
+ {
198
+ table: "session_projects",
199
+ column: "state",
200
+ sql: ADD_SESSION_PROJECT_STATE_COLUMN_SQL
201
+ }
202
+ ];
149
203
  CREATE_TABLE_AND_TRIGGER_STATEMENTS = [
150
204
  `
151
205
  CREATE TABLE IF NOT EXISTS _meta (
@@ -419,9 +473,11 @@ var init_definitions = __esm({
419
473
  CREATE_ENTRIES_FTS_TABLE_SQL,
420
474
  CREATE_ENTRIES_FTS_TRIGGER_AI_SQL,
421
475
  CREATE_ENTRIES_FTS_TRIGGER_AD_SQL,
422
- CREATE_ENTRIES_FTS_TRIGGER_AU_SQL
476
+ CREATE_ENTRIES_FTS_TRIGGER_AU_SQL,
477
+ ...OPENCLAW_PLUGIN_SCHEMA_STATEMENTS
423
478
  ];
424
479
  COLUMN_MIGRATIONS = [
480
+ ...OPENCLAW_PLUGIN_COLUMN_MIGRATIONS,
425
481
  {
426
482
  table: "co_recall_edges",
427
483
  column: "edge_type",
@@ -8552,6 +8608,7 @@ function formatMidSessionRecall(results, options = {}) {
8552
8608
 
8553
8609
  // src/runtime/openclaw-defaults.ts
8554
8610
  init_client();
8611
+ init_schema();
8555
8612
 
8556
8613
  // src/db/signals.ts
8557
8614
  async function fetchNewSignalEntries(db, sinceSeq, minImportance, limit, maxAgeSec = 0) {
@@ -8668,7 +8725,9 @@ function resolveOpenClawPluginDbDefaults() {
8668
8725
  return {
8669
8726
  getDb: shared.getDbFn,
8670
8727
  initDb: shared.initDbFn,
8671
- closeDb: shared.closeDbFn
8728
+ closeDb: shared.closeDbFn,
8729
+ pluginSchemaStatements: OPENCLAW_PLUGIN_SCHEMA_STATEMENTS,
8730
+ pluginColumnMigrations: OPENCLAW_PLUGIN_COLUMN_MIGRATIONS
8672
8731
  };
8673
8732
  }
8674
8733
  function resolveOpenClawSignalDefaults() {
@@ -8688,46 +8747,6 @@ function resolveOpenClawHandoffDefaults() {
8688
8747
  }
8689
8748
 
8690
8749
  // src/openclaw-plugin/plugin-db.ts
8691
- var CREATE_SEEN_SESSIONS_TABLE_SQL = `
8692
- CREATE TABLE IF NOT EXISTS seen_sessions (
8693
- dedupe_key TEXT PRIMARY KEY,
8694
- seen_at INTEGER NOT NULL
8695
- )
8696
- `;
8697
- var CREATE_SEEN_SESSIONS_SEEN_AT_INDEX_SQL = `
8698
- CREATE INDEX IF NOT EXISTS idx_seen_sessions_seen_at
8699
- ON seen_sessions(seen_at)
8700
- `;
8701
- var CREATE_SESSION_PROJECTS_TABLE_SQL = `
8702
- CREATE TABLE IF NOT EXISTS session_projects (
8703
- session_key TEXT PRIMARY KEY,
8704
- project TEXT NOT NULL,
8705
- state TEXT NOT NULL DEFAULT 'set',
8706
- updated_at TEXT NOT NULL
8707
- )
8708
- `;
8709
- var CREATE_SESSION_IDENTITY_BREADCRUMBS_TABLE_SQL = `
8710
- CREATE TABLE IF NOT EXISTS session_identity_breadcrumbs (
8711
- session_id TEXT PRIMARY KEY,
8712
- session_key TEXT,
8713
- family TEXT NOT NULL,
8714
- lane_id TEXT,
8715
- origin_surface TEXT,
8716
- delivery_channel TEXT,
8717
- family_source TEXT,
8718
- lane_source TEXT,
8719
- created_at TEXT NOT NULL,
8720
- updated_at TEXT NOT NULL
8721
- )
8722
- `;
8723
- var CREATE_SESSION_IDENTITY_BREADCRUMBS_UPDATED_AT_INDEX_SQL = `
8724
- CREATE INDEX IF NOT EXISTS idx_session_identity_breadcrumbs_updated_at
8725
- ON session_identity_breadcrumbs(updated_at)
8726
- `;
8727
- var ADD_SESSION_PROJECT_STATE_COLUMN_SQL = `
8728
- ALTER TABLE session_projects
8729
- ADD COLUMN state TEXT NOT NULL DEFAULT 'set'
8730
- `;
8731
8750
  var PLUGIN_DB_STATE_KEY = "__agenrOpenClawPluginDbState";
8732
8751
  function getPluginDbState() {
8733
8752
  const globalState = globalThis;
@@ -8747,18 +8766,19 @@ function closePluginDbState(state) {
8747
8766
  state.init = null;
8748
8767
  }
8749
8768
  async function ensurePluginDbTables(client) {
8750
- await resolveOpenClawPluginDbDefaults().initDb(client);
8751
- await client.execute(CREATE_SEEN_SESSIONS_TABLE_SQL);
8752
- await client.execute(CREATE_SEEN_SESSIONS_SEEN_AT_INDEX_SQL);
8753
- await client.execute(CREATE_SESSION_PROJECTS_TABLE_SQL);
8754
- await client.execute(CREATE_SESSION_IDENTITY_BREADCRUMBS_TABLE_SQL);
8755
- await client.execute(CREATE_SESSION_IDENTITY_BREADCRUMBS_UPDATED_AT_INDEX_SQL);
8756
- const sessionProjectsInfo = await client.execute("PRAGMA table_info(session_projects)");
8757
- const hasStateColumn = sessionProjectsInfo.rows.some(
8758
- (row) => String(row.name) === "state"
8759
- );
8760
- if (!hasStateColumn) {
8761
- await client.execute(ADD_SESSION_PROJECT_STATE_COLUMN_SQL);
8769
+ const defaults = resolveOpenClawPluginDbDefaults();
8770
+ await defaults.initDb(client);
8771
+ for (const statement of defaults.pluginSchemaStatements) {
8772
+ await client.execute(statement);
8773
+ }
8774
+ for (const migration of defaults.pluginColumnMigrations) {
8775
+ const tableInfo = await client.execute(`PRAGMA table_info(${migration.table})`);
8776
+ const hasColumn2 = tableInfo.rows.some(
8777
+ (row) => String(row.name) === migration.column
8778
+ );
8779
+ if (!hasColumn2) {
8780
+ await client.execute(migration.sql);
8781
+ }
8762
8782
  }
8763
8783
  }
8764
8784
  function registerDbShutdown(state) {
@@ -33348,11 +33368,7 @@ async function runClearSessionProjectTool(sessionKey, pluginConfig) {
33348
33368
  }
33349
33369
 
33350
33370
  // src/openclaw-plugin/hooks/register-tools.ts
33351
- var EXPIRY_SCHEMA = Type6.Union([
33352
- Type6.Literal("core"),
33353
- Type6.Literal("permanent"),
33354
- Type6.Literal("temporary")
33355
- ]);
33371
+ var EXPIRY_SCHEMA = Type6.String({ enum: ["core", "permanent", "temporary"] });
33356
33372
  function optionalExpirySchema(description) {
33357
33373
  return Type6.Optional({
33358
33374
  ...EXPIRY_SCHEMA,
@@ -33398,12 +33414,10 @@ function registerAgenrTools(api, params) {
33398
33414
  parameters: Type6.Object({
33399
33415
  query: Type6.Optional(Type6.String({ description: "What to search for." })),
33400
33416
  context: Type6.Optional(
33401
- Type6.Union(
33402
- [Type6.Literal("default"), Type6.Literal("session-start"), Type6.Literal("browse")],
33403
- {
33404
- description: "Use session-start for fast bootstrap without embedding. Use browse for recency-dominant temporal browsing with secondary importance tie-breaking (no query needed, no semantic search)."
33405
- }
33406
- )
33417
+ Type6.String({
33418
+ enum: ["default", "session-start", "browse"],
33419
+ description: "Use session-start for fast bootstrap without embedding. Use browse for recency-dominant temporal browsing with secondary importance tie-breaking (no query needed, no semantic search)."
33420
+ })
33407
33421
  ),
33408
33422
  limit: Type6.Optional(Type6.Number({ description: "Max results (default: 10)." })),
33409
33423
  types: Type6.Optional(Type6.String({ description: "Comma-separated entry types to filter." })),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agenr/openclaw-plugin",
3
- "version": "0.12.2",
3
+ "version": "0.13.0",
4
4
  "description": "agenr memory plugin for OpenClaw — lightweight plugin-only package without the CLI",
5
5
  "license": "AGPL-3.0",
6
6
  "author": "agenr-ai",
@@ -26,7 +26,8 @@
26
26
  "dependencies": {
27
27
  "@libsql/client": "^0.17.2",
28
28
  "@mariozechner/pi-ai": "^0.61.1",
29
- "@sinclair/typebox": "^0.34.48"
29
+ "@sinclair/typebox": "^0.34.48",
30
+ "agenr": "0.13.0"
30
31
  },
31
32
  "openclaw": {
32
33
  "extensions": [
@@ -39,4 +40,4 @@
39
40
  "memory",
40
41
  "plugin"
41
42
  ]
42
- }
43
+ }
@@ -0,0 +1,77 @@
1
+ ---
2
+ name: agenr
3
+ description: Use when storing new knowledge (decisions, preferences, lessons, todos) or recalling context mid-session. The agenr plugin auto-injects memory at session start - this skill covers proactive store and on-demand recall.
4
+ ---
5
+
6
+ ## agenr_store
7
+
8
+ Use proactively for durable knowledge - decisions, preferences, lessons, and facts that future sessions need to make better decisions.
9
+
10
+ **The future-session test:** Before storing, ask: "If I woke up in a fresh session and recalled this, would it change how I act?" If the answer is just "it tells me something that already happened and is done" - do not store it.
11
+
12
+ **Store:**
13
+ - Architecture decisions and design rationale
14
+ - Workflow constraints and operational rules
15
+ - Lessons learned from problems (recurring bugs, what worked, what did not)
16
+ - User preferences and working-style observations
17
+ - Durable facts about systems, environments, people, projects
18
+ - Important open risks or unresolved hazards
19
+
20
+ **Do not store:**
21
+ - Version or release shipping events ("v1.2.3 shipped") - changelogs are the system of record
22
+ - Issue or PR filing records ("filed #123, #124") - the issue tracker is the system of record
23
+ - Phase plans or release packaging decisions - transient coordination artifacts, stale within a session
24
+ - Progress snapshots ("3 of 5 tasks done") - stale within minutes
25
+ - Prompt file paths or internal build logistics - look-up-able, not memory-worthy
26
+ - Anything whose only value is duplicating files, the issue tracker, or git history
27
+
28
+ Do not ask before storing - but do ask whether future-you needs it.
29
+
30
+ Required: `type`, `content`, `importance`.
31
+ Optional: `subject` (short label), `tags` (array), `scope` (`private`|`personal`|`public`), `project`, `platform`, `source`.
32
+
33
+ Types: `fact | decision | preference | todo | lesson | event | relationship`
34
+ Do not store secrets/credentials, temporary state, or verbatim conversation.
35
+
36
+ ### Importance calibration
37
+
38
+ - **10**: Once-per-project permanent constraints. At most 1-2 per project lifetime.
39
+ - **9**: Critical breaking changes or immediate cross-session decisions. At most 1 per significant session, often 0.
40
+ - **8**: Things an active parallel session would act on right now. Fires a cross-session signal. Use conservatively.
41
+ - **7**: Default. Project facts, decisions, preferences, milestones. No signal fired.
42
+ - **6**: Routine dev observations (verified X, tests passing). Cap here unless the result is surprising.
43
+ - **5**: Borderline. Only store if clearly durable beyond today.
44
+ - **Importance is not recency.** Something that just happened is not automatically important. A shipping event is importance 5-6 at best unless it teaches a lesson. A recurring operational hazard is importance 7-8 because it affects future decisions.
45
+
46
+ Entries at 7 are saved silently. Use 8+ only if other active sessions need to know NOW.
47
+
48
+ ### Confidence-aware extraction (OpenClaw transcripts)
49
+
50
+ OpenClaw transcripts include `[user]` / `[assistant]` role labels. The extractor uses this signal:
51
+ - Hedged or unverified assistant factual claims are tagged `unverified` and hard-capped at importance 5.
52
+ - Tool-verified assistant claims follow normal importance rules.
53
+ - User messages are never capped.
54
+
55
+ This means: if you say something unverified, it will be stored at max importance 5. To store a fact at higher importance, verify it with a tool call first.
56
+
57
+ ## agenr_recall
58
+
59
+ Use mid-session when you need context you don't already have. Session-start recall is handled automatically - do not call at turn 1 unless you need extra context beyond the injected summary.
60
+
61
+ Parameters:
62
+ - `query` (required): semantic search string
63
+ - `limit`: max results (default 10)
64
+ - `context`: `"default"` (semantic+vector) or `"session-start"` (fast bootstrap)
65
+ - `since`: lower date bound - only entries newer than this (ISO or relative, e.g. `"7d"`, `"2026-01-01"`)
66
+ - `until`: upper date bound - only entries older than this ceiling (e.g. `"7d"` = entries created before 7 days ago). Use with `since` for a date window.
67
+ - `types`: comma-separated entry types (`fact,decision,preference,todo,lesson,event`)
68
+ - `platform`: filter by platform (`openclaw`, `claude-code`, `codex`)
69
+ - `project`: filter by project scope (pass `*` for all projects)
70
+
71
+ ## agenr_retire
72
+
73
+ Soft-deletes an entry. Use when something is outdated, wrong, or superseded. Pass `entry_id` (from recall results) and optionally `reason` and `persist: true` to write to the retirements ledger.
74
+
75
+ ## agenr_extract
76
+
77
+ Extracts structured knowledge entries from raw text without storing them. Useful for previewing what would be stored from a block of text before committing.