soulbridge 0.0.20 → 0.0.22

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.
@@ -8,7 +8,7 @@ export * from './types.ts';
8
8
  export type { SoulStore } from './store.ts';
9
9
  export { openSqlite, SCHEMA_VERSION, AFFECT_RETENTION_MS, DbNewerThanBinaryError } from './sqlite.ts';
10
10
  export { buildContext, styleDirectives, DEFAULT_MAX_CHARS, AFFECT_BUDGET, AFFECT_WINDOW_MS, } from './context.ts';
11
- export { reflect, ruleExtract, nextEmotion, isCorrection, correctionRule } from './reflect.ts';
11
+ export { reflect, ruleExtract, nextEmotion, isCorrection, correctionRule, isQuestion } from './reflect.ts';
12
12
  export { rank, scoreMemory, tokenize, relevance } from './scoring.ts';
13
13
  export * from './affect/index.ts';
14
14
  export { measureStyle } from './style/measure.ts';
@@ -7,7 +7,7 @@
7
7
  export * from './types.js';
8
8
  export { openSqlite, SCHEMA_VERSION, AFFECT_RETENTION_MS, DbNewerThanBinaryError } from './sqlite.js';
9
9
  export { buildContext, styleDirectives, DEFAULT_MAX_CHARS, AFFECT_BUDGET, AFFECT_WINDOW_MS, } from './context.js';
10
- export { reflect, ruleExtract, nextEmotion, isCorrection, correctionRule } from './reflect.js';
10
+ export { reflect, ruleExtract, nextEmotion, isCorrection, correctionRule, isQuestion } from './reflect.js';
11
11
  export { rank, scoreMemory, tokenize, relevance } from './scoring.js';
12
12
  export * from './affect/index.js';
13
13
  export { measureStyle } from './style/measure.js';
@@ -44,6 +44,13 @@ export declare function gateDrafts(drafts: Draft[]): {
44
44
  accepted: Draft[];
45
45
  rejected: DraftRejection[];
46
46
  };
47
+ /**
48
+ * A question is not a statement to remember.
49
+ *
50
+ * Measured case: "我们这个记忆会记住日常生活吗?" was stored as a fact because a
51
+ * trigger word matched before anything looked at the sentence type.
52
+ */
53
+ export declare function isQuestion(text: string): boolean;
47
54
  export declare function ruleExtract(turns: Turn[]): Draft[];
48
55
  /** Corrections raise tension and lower passion; an ordinary session lets tension decay. */
49
56
  export declare function nextEmotion(current: Emotion, turns: Turn[]): Emotion;
@@ -121,11 +121,25 @@ export function gateDrafts(drafts) {
121
121
  }
122
122
  return { accepted, rejected };
123
123
  }
124
+ /**
125
+ * A question is not a statement to remember.
126
+ *
127
+ * Measured case: "我们这个记忆会记住日常生活吗?" was stored as a fact because a
128
+ * trigger word matched before anything looked at the sentence type.
129
+ */
130
+ export function isQuestion(text) {
131
+ const trimmed = text.trim();
132
+ if (trimmed.endsWith('?') || trimmed.endsWith('?'))
133
+ return true;
134
+ return /(吗|呢)[。.!!~~]?$/.test(trimmed);
135
+ }
124
136
  export function ruleExtract(turns) {
125
137
  const drafts = [];
126
138
  for (const turn of turns) {
127
139
  if (turn.role !== 'user')
128
140
  continue;
141
+ if (isQuestion(turn.content))
142
+ continue;
129
143
  for (const rule of RULES) {
130
144
  if (!rule.match(turn.content))
131
145
  continue;
@@ -1,3 +1,4 @@
1
+ import { DatabaseSync } from 'node:sqlite';
1
2
  import type { SoulStore } from './store.ts';
2
3
  export declare const SCHEMA_VERSION = 2;
3
4
  export declare const AFFECT_RETENTION_MS: number;
@@ -6,4 +7,13 @@ export declare class DbNewerThanBinaryError extends Error {
6
7
  readonly dbVersion: number;
7
8
  constructor(dbVersion: number);
8
9
  }
10
+ /**
11
+ * Copy the database aside before a schema upgrade.
12
+ *
13
+ * In WAL mode the most recent commits can live in the `-wal` sidecar, so a copy
14
+ * of the main file alone can be missing data exactly when it matters. Checkpoint
15
+ * first (TRUNCATE moves the WAL back into the main file and empties it), then
16
+ * copy. Exported for the upgrade test.
17
+ */
18
+ export declare function backupBeforeUpgrade(db: DatabaseSync, file: string, from: number): void;
9
19
  export declare function openSqlite(file: string): SoulStore;
@@ -148,12 +148,22 @@ function upgradeToV3(db) {
148
148
  )`);
149
149
  db.exec('CREATE INDEX IF NOT EXISTS idx_corrections ON corrections(soul_id, user_id, at DESC)');
150
150
  }
151
- function backupBeforeUpgrade(file, from) {
151
+ /**
152
+ * Copy the database aside before a schema upgrade.
153
+ *
154
+ * In WAL mode the most recent commits can live in the `-wal` sidecar, so a copy
155
+ * of the main file alone can be missing data exactly when it matters. Checkpoint
156
+ * first (TRUNCATE moves the WAL back into the main file and empties it), then
157
+ * copy. Exported for the upgrade test.
158
+ */
159
+ export function backupBeforeUpgrade(db, file, from) {
152
160
  if (file === ':memory:' || !existsSync(file))
153
161
  return;
154
162
  const backup = `${file}.bak-v${from}`;
155
- if (!existsSync(backup))
156
- copyFileSync(file, backup);
163
+ if (existsSync(backup))
164
+ return;
165
+ db.exec('PRAGMA wal_checkpoint(TRUNCATE);');
166
+ copyFileSync(file, backup);
157
167
  }
158
168
  export function openSqlite(file) {
159
169
  const db = new DatabaseSync(file);
@@ -166,7 +176,7 @@ export function openSqlite(file) {
166
176
  throw new DbNewerThanBinaryError(version);
167
177
  }
168
178
  if (version < SCHEMA_VERSION) {
169
- backupBeforeUpgrade(file, version);
179
+ backupBeforeUpgrade(db, file, version);
170
180
  if (version < 2)
171
181
  upgradeToV2(db);
172
182
  if (version < 3)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "soulbridge",
3
- "version": "0.0.20",
3
+ "version": "0.0.22",
4
4
  "description": "A personality layer for any agent: continuity, forgetting, and growth across tools.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",