@oobe-protocol-labs/sap-mcp-server 0.9.22 → 0.9.36
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/.env.example +23 -9
- package/CHANGELOG.md +124 -6
- package/README.md +8 -7
- package/USER_DOCS/00_START_HERE.md +9 -1
- package/USER_DOCS/01_HOSTED_REMOTE_MCP.md +1 -1
- package/USER_DOCS/03_PAYMENTS_X402_PAYSH.md +1 -1
- package/USER_DOCS/04_CLIENT_CONFIGS.md +3 -3
- package/USER_DOCS/06_DESKTOP_GUI_WIZARD.md +5 -5
- package/config.example.json +5 -4
- package/dist/config/env.d.ts +22 -0
- package/dist/config/env.d.ts.map +1 -1
- package/dist/config/env.js +26 -8
- package/dist/config/env.js.map +1 -1
- package/dist/config/mcp-client-injection.d.ts.map +1 -1
- package/dist/config/mcp-client-injection.js +34 -5
- package/dist/config/mcp-client-injection.js.map +1 -1
- package/dist/config/paths.d.ts +9 -1
- package/dist/config/paths.d.ts.map +1 -1
- package/dist/config/paths.js +15 -1
- package/dist/config/paths.js.map +1 -1
- package/dist/config/profiles.d.ts +5 -0
- package/dist/config/profiles.d.ts.map +1 -1
- package/dist/config/profiles.js +37 -9
- package/dist/config/profiles.js.map +1 -1
- package/dist/config/wizard.d.ts.map +1 -1
- package/dist/config/wizard.js +44 -1
- package/dist/config/wizard.js.map +1 -1
- package/dist/config-cli.d.ts.map +1 -1
- package/dist/config-cli.js +17 -1
- package/dist/config-cli.js.map +1 -1
- package/dist/core/constants.d.ts +1 -1
- package/dist/core/constants.js +1 -1
- package/dist/core/logger.js +1 -1
- package/dist/memory/async-processor.d.ts +107 -0
- package/dist/memory/async-processor.d.ts.map +1 -0
- package/dist/memory/async-processor.js +204 -0
- package/dist/memory/async-processor.js.map +1 -0
- package/dist/memory/auto-record.d.ts +47 -0
- package/dist/memory/auto-record.d.ts.map +1 -0
- package/dist/memory/auto-record.js +133 -0
- package/dist/memory/auto-record.js.map +1 -0
- package/dist/memory/database.d.ts +103 -0
- package/dist/memory/database.d.ts.map +1 -0
- package/dist/memory/database.js +337 -0
- package/dist/memory/database.js.map +1 -0
- package/dist/memory/hermes-bridge.d.ts +70 -0
- package/dist/memory/hermes-bridge.d.ts.map +1 -0
- package/dist/memory/hermes-bridge.js +155 -0
- package/dist/memory/hermes-bridge.js.map +1 -0
- package/dist/memory/index.d.ts +23 -0
- package/dist/memory/index.d.ts.map +1 -0
- package/dist/memory/index.js +22 -0
- package/dist/memory/index.js.map +1 -0
- package/dist/memory/memory-store.d.ts +76 -0
- package/dist/memory/memory-store.d.ts.map +1 -0
- package/dist/memory/memory-store.js +231 -0
- package/dist/memory/memory-store.js.map +1 -0
- package/dist/memory/stream-buffer-store.d.ts +69 -0
- package/dist/memory/stream-buffer-store.d.ts.map +1 -0
- package/dist/memory/stream-buffer-store.js +182 -0
- package/dist/memory/stream-buffer-store.js.map +1 -0
- package/dist/memory/tool-call-store.d.ts +68 -0
- package/dist/memory/tool-call-store.d.ts.map +1 -0
- package/dist/memory/tool-call-store.js +189 -0
- package/dist/memory/tool-call-store.js.map +1 -0
- package/dist/memory/types.d.ts +197 -0
- package/dist/memory/types.d.ts.map +1 -0
- package/dist/memory/types.js +15 -0
- package/dist/memory/types.js.map +1 -0
- package/dist/memory/utils.d.ts +30 -0
- package/dist/memory/utils.d.ts.map +1 -0
- package/dist/memory/utils.js +47 -0
- package/dist/memory/utils.js.map +1 -0
- package/dist/payments/hosted-tool-eligibility.d.ts.map +1 -1
- package/dist/payments/hosted-tool-eligibility.js +4 -6
- package/dist/payments/hosted-tool-eligibility.js.map +1 -1
- package/dist/payments/monetization-gate.d.ts +39 -0
- package/dist/payments/monetization-gate.d.ts.map +1 -1
- package/dist/payments/monetization-gate.js +165 -11
- package/dist/payments/monetization-gate.js.map +1 -1
- package/dist/payments/pay-sh-spec.d.ts.map +1 -1
- package/dist/payments/pay-sh-spec.js +4 -2
- package/dist/payments/pay-sh-spec.js.map +1 -1
- package/dist/payments/pricing.d.ts +3 -1
- package/dist/payments/pricing.d.ts.map +1 -1
- package/dist/payments/pricing.js +137 -56
- package/dist/payments/pricing.js.map +1 -1
- package/dist/payments/x402-paid-call.d.ts.map +1 -1
- package/dist/payments/x402-paid-call.js +26 -2
- package/dist/payments/x402-paid-call.js.map +1 -1
- package/dist/premium/builtin-plugins.d.ts +42 -0
- package/dist/premium/builtin-plugins.d.ts.map +1 -1
- package/dist/premium/builtin-plugins.js +91 -10
- package/dist/premium/builtin-plugins.js.map +1 -1
- package/dist/premium/manifest-builder.d.ts.map +1 -1
- package/dist/premium/manifest-builder.js +43 -7
- package/dist/premium/manifest-builder.js.map +1 -1
- package/dist/premium/meme-radar-capabilities.js +9 -9
- package/dist/premium/meme-radar-capabilities.js.map +1 -1
- package/dist/premium/plugin-validator.d.ts.map +1 -1
- package/dist/premium/plugin-validator.js +62 -1
- package/dist/premium/plugin-validator.js.map +1 -1
- package/dist/premium/provider-bridge.d.ts +25 -1
- package/dist/premium/provider-bridge.d.ts.map +1 -1
- package/dist/premium/provider-bridge.js +130 -20
- package/dist/premium/provider-bridge.js.map +1 -1
- package/dist/premium/session-manager.d.ts.map +1 -1
- package/dist/premium/session-manager.js +12 -3
- package/dist/premium/session-manager.js.map +1 -1
- package/dist/premium/tech-fundamentals-capabilities.js +5 -5
- package/dist/premium/tech-fundamentals-capabilities.js.map +1 -1
- package/dist/premium/trading-capabilities.js +5 -5
- package/dist/premium/trading-capabilities.js.map +1 -1
- package/dist/premium/webhook-engine.d.ts.map +1 -1
- package/dist/premium/webhook-engine.js +7 -1
- package/dist/premium/webhook-engine.js.map +1 -1
- package/dist/prompts/context/sap-agent-context.prompt.js +4 -3
- package/dist/prompts/context/sap-agent-context.prompt.js.map +1 -1
- package/dist/prompts/context/sap-agent-intent-router.prompt.js +1 -1
- package/dist/prompts/payments/explain-x402-settlement.prompt.js +1 -1
- package/dist/remote/premium-routes.d.ts.map +1 -1
- package/dist/remote/premium-routes.js +3 -2
- package/dist/remote/premium-routes.js.map +1 -1
- package/dist/remote/public-home/sections.d.ts.map +1 -1
- package/dist/remote/public-home/sections.js +2 -3
- package/dist/remote/public-home/sections.js.map +1 -1
- package/dist/remote/public-home/styles.d.ts +1 -1
- package/dist/remote/public-home/styles.js +2 -2
- package/dist/remote/server.d.ts.map +1 -1
- package/dist/remote/server.js +19 -4
- package/dist/remote/server.js.map +1 -1
- package/dist/server/server-metadata.js +1 -1
- package/dist/strategies/strategy-store.d.ts +82 -0
- package/dist/strategies/strategy-store.d.ts.map +1 -0
- package/dist/strategies/strategy-store.js +165 -0
- package/dist/strategies/strategy-store.js.map +1 -0
- package/dist/tools/agent-start-tool.d.ts.map +1 -1
- package/dist/tools/agent-start-tool.js +103 -16
- package/dist/tools/agent-start-tool.js.map +1 -1
- package/dist/tools/client-sdk-tools.d.ts.map +1 -1
- package/dist/tools/client-sdk-tools.js +156 -12
- package/dist/tools/client-sdk-tools.js.map +1 -1
- package/dist/tools/estimate-tool-cost.d.ts.map +1 -1
- package/dist/tools/estimate-tool-cost.js +11 -4
- package/dist/tools/estimate-tool-cost.js.map +1 -1
- package/dist/tools/index.d.ts +1 -0
- package/dist/tools/index.d.ts.map +1 -1
- package/dist/tools/index.js +2 -0
- package/dist/tools/index.js.map +1 -1
- package/dist/tools/magicblock-tools.js +8 -8
- package/dist/tools/magicblock-tools.js.map +1 -1
- package/dist/tools/memory-tools.d.ts +26 -0
- package/dist/tools/memory-tools.d.ts.map +1 -0
- package/dist/tools/memory-tools.js +533 -0
- package/dist/tools/memory-tools.js.map +1 -0
- package/dist/tools/perp-tools.d.ts +7 -9
- package/dist/tools/perp-tools.d.ts.map +1 -1
- package/dist/tools/perp-tools.js +404 -367
- package/dist/tools/perp-tools.js.map +1 -1
- package/dist/tools/premium-tools.d.ts.map +1 -1
- package/dist/tools/premium-tools.js +8 -2
- package/dist/tools/premium-tools.js.map +1 -1
- package/dist/tools/profile-tools.d.ts.map +1 -1
- package/dist/tools/profile-tools.js +18 -1
- package/dist/tools/profile-tools.js.map +1 -1
- package/dist/tools/quick-context-tool.d.ts.map +1 -1
- package/dist/tools/quick-context-tool.js +101 -9
- package/dist/tools/quick-context-tool.js.map +1 -1
- package/dist/tools/register-tools.d.ts.map +1 -1
- package/dist/tools/register-tools.js +3 -0
- package/dist/tools/register-tools.js.map +1 -1
- package/dist/tools/sap-sdk-tools.d.ts.map +1 -1
- package/dist/tools/sap-sdk-tools.js +14 -13
- package/dist/tools/sap-sdk-tools.js.map +1 -1
- package/dist/tools/session-context-packet.d.ts +19 -0
- package/dist/tools/session-context-packet.d.ts.map +1 -0
- package/dist/tools/session-context-packet.js +256 -0
- package/dist/tools/session-context-packet.js.map +1 -0
- package/dist/tools/skills-tools.d.ts +10 -0
- package/dist/tools/skills-tools.d.ts.map +1 -1
- package/dist/tools/skills-tools.js +19 -0
- package/dist/tools/skills-tools.js.map +1 -1
- package/dist/tools/transaction-tools.d.ts +1 -0
- package/dist/tools/transaction-tools.d.ts.map +1 -1
- package/dist/tools/transaction-tools.js +248 -9
- package/dist/tools/transaction-tools.js.map +1 -1
- package/dist/tools/x402-paid-call-tool.d.ts.map +1 -1
- package/dist/tools/x402-paid-call-tool.js +55 -21
- package/dist/tools/x402-paid-call-tool.js.map +1 -1
- package/dist/wizard-core/desktop-flow.d.ts.map +1 -1
- package/dist/wizard-core/desktop-flow.js +4 -2
- package/dist/wizard-core/desktop-flow.js.map +1 -1
- package/docs/06_PAYMENTS_X402_AND_PAYSH.md +38 -13
- package/docs/07_ENDPOINTS_AND_CLIENTS.md +1 -1
- package/docs/09_TOOLS_SKILLS_AND_AGENT_GUIDE.md +14 -6
- package/docs/13_BOUNTY_PROGRAM_PROPOSAL.md +1 -1
- package/docs/14_DESKTOP_WIZARD_RELEASE.md +3 -3
- package/docs/15_DASHBOARD_SCREENSHARE_SCRIPT.md +1 -1
- package/docs/BRANCH_AND_CI.md +2 -2
- package/docs/README.md +1 -1
- package/package.json +3 -1
- package/server.json +3 -3
- package/skills/README.md +3 -3
- package/skills/sap-agent-registry/SKILL.md +2 -2
- package/skills/sap-agentkit/SKILL.md +10 -4
- package/skills/sap-defi/SKILL.md +42 -5
- package/skills/sap-discovery-indexing/SKILL.md +4 -3
- package/skills/sap-market-data/SKILL.md +9 -5
- package/skills/sap-mcp/SKILL.md +37 -24
- package/skills/sap-mcp/TOOL_REFERENCE.md +9 -8
- package/skills/sap-operations/SKILL.md +5 -4
- package/skills/sap-payments-x402/SKILL.md +34 -19
- package/assets/logos/drift.svg +0 -12
|
@@ -0,0 +1,337 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module memory/database
|
|
3
|
+
* @description Thread-safe SQLite database manager for the SAP MCP agent memory subsystem.
|
|
4
|
+
*
|
|
5
|
+
* Uses better-sqlite3 (synchronous, native, FTS5-enabled) with WAL mode for
|
|
6
|
+
* concurrent read access. The database is a singleton — one connection per process.
|
|
7
|
+
*
|
|
8
|
+
* Design principles:
|
|
9
|
+
* - Synchronous I/O: better-sqlite3 is synchronous, no async overhead, no callback hell.
|
|
10
|
+
* - WAL mode: readers don't block writers, crash-safe via WAL journal.
|
|
11
|
+
* - Prepared statements: cached for performance, reused across calls.
|
|
12
|
+
* - FTS5: inverted full-text index for relevance-ranked retrieval.
|
|
13
|
+
* - Schema versioning: idempotent migrations on init.
|
|
14
|
+
* - Graceful degradation: if the DB can't be opened, tools return empty results.
|
|
15
|
+
*/
|
|
16
|
+
import Database from 'better-sqlite3';
|
|
17
|
+
import { mkdirSync, statSync } from 'fs';
|
|
18
|
+
import { dirname, join } from 'path';
|
|
19
|
+
import { logger } from '../core/logger.js';
|
|
20
|
+
import { getMemoryDir } from '../config/paths.js';
|
|
21
|
+
/**
|
|
22
|
+
* @name SCHEMA_VERSION
|
|
23
|
+
* @description Current schema version. Increment when the schema changes.
|
|
24
|
+
* The database tracks this in the `_meta` table and runs migrations as needed.
|
|
25
|
+
*/
|
|
26
|
+
const SCHEMA_VERSION = 1;
|
|
27
|
+
/**
|
|
28
|
+
* @name DEFAULT_CONFIG
|
|
29
|
+
* @description Default memory configuration. The DB is stored in
|
|
30
|
+
* ~/.config/mcp-sap/memory/ which is the standard SAP MCP config directory.
|
|
31
|
+
*/
|
|
32
|
+
export const DEFAULT_CONFIG = {
|
|
33
|
+
dbPath: join(getMemoryDir(), 'agent-memory.db'),
|
|
34
|
+
enableWal: true,
|
|
35
|
+
maxPayloadBytes: 8192,
|
|
36
|
+
relevanceDecayPerDay: 0.01,
|
|
37
|
+
minRelevanceThreshold: 0.05,
|
|
38
|
+
toolCallRetentionDays: 90,
|
|
39
|
+
maxStreamBufferSize: 10_000,
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* @name MemoryDatabase
|
|
43
|
+
* @description Thread-safe singleton managing the SQLite connection for agent memory.
|
|
44
|
+
*
|
|
45
|
+
* The class lazily initializes the database on first access and caches prepared
|
|
46
|
+
* statements for performance. All methods are synchronous (better-sqlite3 is
|
|
47
|
+
* synchronous by design). The database runs in WAL mode for concurrent reads.
|
|
48
|
+
*
|
|
49
|
+
* If the database cannot be opened (e.g. disk full, permissions), the instance
|
|
50
|
+
* enters a degraded mode where all queries return empty results instead of
|
|
51
|
+
* crashing the MCP server.
|
|
52
|
+
*/
|
|
53
|
+
export class MemoryDatabase {
|
|
54
|
+
db = null;
|
|
55
|
+
config;
|
|
56
|
+
degraded = false;
|
|
57
|
+
initialized = false;
|
|
58
|
+
statements = new Map();
|
|
59
|
+
constructor(config = {}) {
|
|
60
|
+
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* @name init
|
|
64
|
+
* @description Initializes the database connection, creates the schema, and
|
|
65
|
+
* enables WAL mode. Called lazily on first query.
|
|
66
|
+
*/
|
|
67
|
+
init() {
|
|
68
|
+
if (this.initialized)
|
|
69
|
+
return;
|
|
70
|
+
this.initialized = true;
|
|
71
|
+
try {
|
|
72
|
+
// Ensure the directory exists.
|
|
73
|
+
const dir = dirname(this.config.dbPath);
|
|
74
|
+
mkdirSync(dir, { recursive: true });
|
|
75
|
+
// Open the database with better-sqlite3.
|
|
76
|
+
this.db = new Database(this.config.dbPath);
|
|
77
|
+
// Enable WAL mode for concurrent read access and crash safety.
|
|
78
|
+
if (this.config.enableWal) {
|
|
79
|
+
this.db.pragma('journal_mode = WAL');
|
|
80
|
+
this.db.pragma('synchronous = NORMAL');
|
|
81
|
+
this.db.pragma('wal_autocheckpoint = 1000');
|
|
82
|
+
}
|
|
83
|
+
// Set busy timeout to 5 seconds for concurrent access.
|
|
84
|
+
this.db.pragma('busy_timeout = 5000');
|
|
85
|
+
// Run schema migrations.
|
|
86
|
+
this.runMigrations();
|
|
87
|
+
// Prepare cached statements.
|
|
88
|
+
this.prepareStatements();
|
|
89
|
+
logger.info('Memory database initialized', {
|
|
90
|
+
path: this.config.dbPath,
|
|
91
|
+
wal: this.config.enableWal,
|
|
92
|
+
schemaVersion: SCHEMA_VERSION,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
catch (error) {
|
|
96
|
+
logger.error('Memory database initialization failed — entering degraded mode', {
|
|
97
|
+
error: error instanceof Error ? error.message : String(error),
|
|
98
|
+
path: this.config.dbPath,
|
|
99
|
+
});
|
|
100
|
+
this.degraded = true;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* @name getDb
|
|
105
|
+
* @description Returns the underlying Database instance. Throws if degraded.
|
|
106
|
+
* @internal
|
|
107
|
+
*/
|
|
108
|
+
getDb() {
|
|
109
|
+
if (this.degraded || !this.db) {
|
|
110
|
+
throw new Error('Memory database is in degraded mode — queries return empty results.');
|
|
111
|
+
}
|
|
112
|
+
return this.db;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* @name isDegraded
|
|
116
|
+
* @description Returns true if the database is in degraded mode (init failed).
|
|
117
|
+
*/
|
|
118
|
+
isDegraded() {
|
|
119
|
+
return this.degraded;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* @name getStatement
|
|
123
|
+
* @description Returns a cached prepared statement by key.
|
|
124
|
+
* @internal
|
|
125
|
+
*/
|
|
126
|
+
getStatement(key) {
|
|
127
|
+
return this.statements.get(key);
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* @name close
|
|
131
|
+
* @description Closes the database connection gracefully.
|
|
132
|
+
*/
|
|
133
|
+
close() {
|
|
134
|
+
if (this.db) {
|
|
135
|
+
try {
|
|
136
|
+
this.db.close();
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
// Best-effort close.
|
|
140
|
+
}
|
|
141
|
+
this.db = null;
|
|
142
|
+
}
|
|
143
|
+
this.statements.clear();
|
|
144
|
+
this.initialized = false;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* @name getDbSize
|
|
148
|
+
* @description Returns the database file size in bytes.
|
|
149
|
+
*/
|
|
150
|
+
getDbSize() {
|
|
151
|
+
try {
|
|
152
|
+
return statSync(this.config.dbPath).size;
|
|
153
|
+
}
|
|
154
|
+
catch {
|
|
155
|
+
return 0;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
// ── Schema Migrations ──────────────────────────────────────────────────────
|
|
159
|
+
/**
|
|
160
|
+
* @name runMigrations
|
|
161
|
+
* @description Runs idempotent schema migrations. Each migration checks if
|
|
162
|
+
* the current schema version is below the target and applies changes.
|
|
163
|
+
* @internal
|
|
164
|
+
*/
|
|
165
|
+
runMigrations() {
|
|
166
|
+
if (!this.db)
|
|
167
|
+
return;
|
|
168
|
+
// Create _meta table if it doesn't exist.
|
|
169
|
+
this.db.exec(`
|
|
170
|
+
CREATE TABLE IF NOT EXISTS _meta (
|
|
171
|
+
key TEXT PRIMARY KEY,
|
|
172
|
+
value TEXT NOT NULL
|
|
173
|
+
);
|
|
174
|
+
`);
|
|
175
|
+
// Get current schema version.
|
|
176
|
+
const versionRow = this.db.prepare('SELECT value FROM _meta WHERE key = ?').get('schema_version');
|
|
177
|
+
const currentVersion = versionRow ? parseInt(versionRow.value, 10) : 0;
|
|
178
|
+
if (currentVersion < 1) {
|
|
179
|
+
this.migrateToV1();
|
|
180
|
+
}
|
|
181
|
+
// Update schema version.
|
|
182
|
+
this.db.prepare('INSERT OR REPLACE INTO _meta (key, value) VALUES (?, ?)').run('schema_version', SCHEMA_VERSION.toString());
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* @name migrateToV1
|
|
186
|
+
* @description Creates the initial schema: tool_calls, agent_memory,
|
|
187
|
+
* stream_buffers, and their FTS5 indexes.
|
|
188
|
+
* @internal
|
|
189
|
+
*/
|
|
190
|
+
migrateToV1() {
|
|
191
|
+
if (!this.db)
|
|
192
|
+
return;
|
|
193
|
+
this.db.exec(`
|
|
194
|
+
-- Tool call history
|
|
195
|
+
CREATE TABLE IF NOT EXISTS tool_calls (
|
|
196
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
197
|
+
tool_name TEXT NOT NULL,
|
|
198
|
+
session_id TEXT,
|
|
199
|
+
caller_profile TEXT,
|
|
200
|
+
input TEXT,
|
|
201
|
+
output TEXT,
|
|
202
|
+
outcome TEXT NOT NULL DEFAULT 'success',
|
|
203
|
+
cost_usd REAL DEFAULT 0,
|
|
204
|
+
tx_signature TEXT,
|
|
205
|
+
latency_ms INTEGER,
|
|
206
|
+
created_at TEXT DEFAULT (datetime('now')),
|
|
207
|
+
updated_at TEXT DEFAULT (datetime('now'))
|
|
208
|
+
);
|
|
209
|
+
|
|
210
|
+
CREATE INDEX IF NOT EXISTS idx_tool_calls_tool ON tool_calls(tool_name);
|
|
211
|
+
CREATE INDEX IF NOT EXISTS idx_tool_calls_session ON tool_calls(session_id);
|
|
212
|
+
CREATE INDEX IF NOT EXISTS idx_tool_calls_outcome ON tool_calls(outcome);
|
|
213
|
+
CREATE INDEX IF NOT EXISTS idx_tool_calls_created ON tool_calls(created_at);
|
|
214
|
+
|
|
215
|
+
-- FTS5 inverted index for tool call search
|
|
216
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS tool_calls_fts USING fts5(
|
|
217
|
+
tool_name,
|
|
218
|
+
input,
|
|
219
|
+
output,
|
|
220
|
+
content='tool_calls',
|
|
221
|
+
content_rowid='id'
|
|
222
|
+
);
|
|
223
|
+
|
|
224
|
+
-- Triggers to keep FTS index in sync with tool_calls
|
|
225
|
+
CREATE TRIGGER IF NOT EXISTS tool_calls_ai AFTER INSERT ON tool_calls BEGIN
|
|
226
|
+
INSERT INTO tool_calls_fts(rowid, tool_name, input, output)
|
|
227
|
+
VALUES (new.id, new.tool_name, new.input, new.output);
|
|
228
|
+
END;
|
|
229
|
+
|
|
230
|
+
CREATE TRIGGER IF NOT EXISTS tool_calls_ad AFTER DELETE ON tool_calls BEGIN
|
|
231
|
+
INSERT INTO tool_calls_fts(tool_calls_fts, rowid, tool_name, input, output)
|
|
232
|
+
VALUES ('delete', old.id, old.tool_name, old.input, old.output);
|
|
233
|
+
END;
|
|
234
|
+
|
|
235
|
+
CREATE TRIGGER IF NOT EXISTS tool_calls_au AFTER UPDATE ON tool_calls BEGIN
|
|
236
|
+
INSERT INTO tool_calls_fts(tool_calls_fts, rowid, tool_name, input, output)
|
|
237
|
+
VALUES ('delete', old.id, old.tool_name, old.input, old.output);
|
|
238
|
+
INSERT INTO tool_calls_fts(rowid, tool_name, input, output)
|
|
239
|
+
VALUES (new.id, new.tool_name, new.input, new.output);
|
|
240
|
+
END;
|
|
241
|
+
|
|
242
|
+
-- Agent memory — LLM-generated summaries
|
|
243
|
+
CREATE TABLE IF NOT EXISTS agent_memory (
|
|
244
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
245
|
+
memory_type TEXT NOT NULL,
|
|
246
|
+
category TEXT NOT NULL,
|
|
247
|
+
summary TEXT NOT NULL,
|
|
248
|
+
source_tool_calls TEXT,
|
|
249
|
+
relevance_score REAL DEFAULT 0.5,
|
|
250
|
+
created_at TEXT DEFAULT (datetime('now')),
|
|
251
|
+
expires_at TEXT,
|
|
252
|
+
last_accessed_at TEXT DEFAULT (datetime('now'))
|
|
253
|
+
);
|
|
254
|
+
|
|
255
|
+
CREATE INDEX IF NOT EXISTS idx_agent_memory_category ON agent_memory(category);
|
|
256
|
+
CREATE INDEX IF NOT EXISTS idx_agent_memory_relevance ON agent_memory(relevance_score);
|
|
257
|
+
CREATE INDEX IF NOT EXISTS idx_agent_memory_type ON agent_memory(memory_type);
|
|
258
|
+
|
|
259
|
+
-- FTS5 inverted index for agent memory search
|
|
260
|
+
CREATE VIRTUAL TABLE IF NOT EXISTS agent_memory_fts USING fts5(
|
|
261
|
+
memory_type,
|
|
262
|
+
category,
|
|
263
|
+
summary,
|
|
264
|
+
content='agent_memory',
|
|
265
|
+
content_rowid='id'
|
|
266
|
+
);
|
|
267
|
+
|
|
268
|
+
-- Triggers to keep FTS index in sync with agent_memory
|
|
269
|
+
CREATE TRIGGER IF NOT EXISTS agent_memory_ai AFTER INSERT ON agent_memory BEGIN
|
|
270
|
+
INSERT INTO agent_memory_fts(rowid, memory_type, category, summary)
|
|
271
|
+
VALUES (new.id, new.memory_type, new.category, new.summary);
|
|
272
|
+
END;
|
|
273
|
+
|
|
274
|
+
CREATE TRIGGER IF NOT EXISTS agent_memory_ad AFTER DELETE ON agent_memory BEGIN
|
|
275
|
+
INSERT INTO agent_memory_fts(agent_memory_fts, rowid, memory_type, category, summary)
|
|
276
|
+
VALUES ('delete', old.id, old.memory_type, old.category, old.summary);
|
|
277
|
+
END;
|
|
278
|
+
|
|
279
|
+
CREATE TRIGGER IF NOT EXISTS agent_memory_au AFTER UPDATE ON agent_memory BEGIN
|
|
280
|
+
INSERT INTO agent_memory_fts(agent_memory_fts, rowid, memory_type, category, summary)
|
|
281
|
+
VALUES ('delete', old.id, old.memory_type, old.category, old.summary);
|
|
282
|
+
INSERT INTO agent_memory_fts(rowid, memory_type, category, summary)
|
|
283
|
+
VALUES (new.id, new.memory_type, new.category, new.summary);
|
|
284
|
+
END;
|
|
285
|
+
|
|
286
|
+
-- Stream buffer events
|
|
287
|
+
CREATE TABLE IF NOT EXISTS stream_buffers (
|
|
288
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
289
|
+
stream_type TEXT NOT NULL,
|
|
290
|
+
event_id TEXT NOT NULL,
|
|
291
|
+
event_type TEXT NOT NULL,
|
|
292
|
+
payload TEXT NOT NULL,
|
|
293
|
+
consumed INTEGER DEFAULT 0,
|
|
294
|
+
created_at TEXT DEFAULT (datetime('now'))
|
|
295
|
+
);
|
|
296
|
+
|
|
297
|
+
CREATE INDEX IF NOT EXISTS idx_stream_buffers_type ON stream_buffers(stream_type);
|
|
298
|
+
CREATE INDEX IF NOT EXISTS idx_stream_buffers_consumed ON stream_buffers(consumed);
|
|
299
|
+
CREATE INDEX IF NOT EXISTS idx_stream_buffers_created ON stream_buffers(created_at);
|
|
300
|
+
CREATE UNIQUE INDEX IF NOT EXISTS idx_stream_buffers_event ON stream_buffers(stream_type, event_id);
|
|
301
|
+
`);
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* @name prepareStatements
|
|
305
|
+
* @description Pre-compiles and caches frequently used SQL statements.
|
|
306
|
+
* @internal
|
|
307
|
+
*/
|
|
308
|
+
prepareStatements() {
|
|
309
|
+
if (!this.db)
|
|
310
|
+
return;
|
|
311
|
+
// Tool calls
|
|
312
|
+
this.statements.set('insert_tool_call', this.db.prepare(`INSERT INTO tool_calls (tool_name, session_id, caller_profile, input, output, outcome, cost_usd, tx_signature, latency_ms)
|
|
313
|
+
VALUES (@toolName, @sessionId, @callerProfile, @input, @output, @outcome, @costUsd, @txSignature, @latencyMs)`));
|
|
314
|
+
this.statements.set('count_tool_calls', this.db.prepare('SELECT COUNT(*) as count FROM tool_calls'));
|
|
315
|
+
this.statements.set('count_tool_calls_by_outcome', this.db.prepare('SELECT outcome, COUNT(*) as count FROM tool_calls GROUP BY outcome'));
|
|
316
|
+
this.statements.set('last_tool_call_at', this.db.prepare('SELECT created_at FROM tool_calls ORDER BY id DESC LIMIT 1'));
|
|
317
|
+
// Agent memory
|
|
318
|
+
this.statements.set('insert_memory', this.db.prepare(`INSERT INTO agent_memory (memory_type, category, summary, source_tool_calls, relevance_score, expires_at)
|
|
319
|
+
VALUES (@memoryType, @category, @summary, @sourceToolCalls, @relevanceScore, @expiresAt)`));
|
|
320
|
+
this.statements.set('count_memory', this.db.prepare('SELECT COUNT(*) as count FROM agent_memory'));
|
|
321
|
+
this.statements.set('count_memory_by_type', this.db.prepare('SELECT memory_type, COUNT(*) as count FROM agent_memory GROUP BY memory_type'));
|
|
322
|
+
this.statements.set('last_memory_at', this.db.prepare('SELECT created_at FROM agent_memory ORDER BY id DESC LIMIT 1'));
|
|
323
|
+
this.statements.set('update_memory_access', this.db.prepare('UPDATE agent_memory SET last_accessed_at = datetime(\'now\') WHERE id = ?'));
|
|
324
|
+
// Stream buffers
|
|
325
|
+
this.statements.set('count_pending_streams', this.db.prepare('SELECT COUNT(*) as count FROM stream_buffers WHERE consumed = 0'));
|
|
326
|
+
this.statements.set('insert_stream_event', this.db.prepare(`INSERT OR IGNORE INTO stream_buffers (stream_type, event_id, event_type, payload, consumed)
|
|
327
|
+
VALUES (@streamType, @eventId, @eventType, @payload, 0)`));
|
|
328
|
+
this.statements.set('consume_stream_events', this.db.prepare('UPDATE stream_buffers SET consumed = 1 WHERE stream_type = ? AND id <= ?'));
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* @name memoryDatabase
|
|
333
|
+
* @description Singleton instance of the memory database.
|
|
334
|
+
* Lazily initialized on first access. Shared across all memory tools.
|
|
335
|
+
*/
|
|
336
|
+
export const memoryDatabase = new MemoryDatabase();
|
|
337
|
+
//# sourceMappingURL=database.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"database.js","sourceRoot":"","sources":["../../src/memory/database.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module memory/hermes-bridge
|
|
3
|
+
* @description Cross-session integration with Hermes Agent session database.
|
|
4
|
+
*
|
|
5
|
+
* If the user has Hermes Agent installed (detected via ~/.hermes/ directory),
|
|
6
|
+
* the memory subsystem can query Hermes session history for cross-session
|
|
7
|
+
* context. This enables the agent to recall relevant conversations from
|
|
8
|
+
* previous Hermes sessions while keeping the data local.
|
|
9
|
+
*
|
|
10
|
+
* If Hermes is not installed, all bridge functions return empty results —
|
|
11
|
+
* the memory subsystem operates standalone.
|
|
12
|
+
*/
|
|
13
|
+
/**
|
|
14
|
+
* @name HermesBridge
|
|
15
|
+
* @description Bridges the SAP MCP memory subsystem with Hermes Agent session data.
|
|
16
|
+
*
|
|
17
|
+
* Detection: checks for ~/.hermes/ directory. If present, the bridge can query
|
|
18
|
+
* the Hermes SQLite session database for relevant past conversations.
|
|
19
|
+
*/
|
|
20
|
+
export declare class HermesBridge {
|
|
21
|
+
private readonly hermesDir;
|
|
22
|
+
private readonly hermesDbPath;
|
|
23
|
+
private available;
|
|
24
|
+
constructor();
|
|
25
|
+
/**
|
|
26
|
+
* @name isAvailable
|
|
27
|
+
* @description Checks whether Hermes Agent is installed on this machine.
|
|
28
|
+
* Caches the result to avoid repeated filesystem checks.
|
|
29
|
+
*/
|
|
30
|
+
isAvailable(): boolean;
|
|
31
|
+
/**
|
|
32
|
+
* @name getHermesDir
|
|
33
|
+
* @description Returns the Hermes installation directory.
|
|
34
|
+
*/
|
|
35
|
+
getHermesDir(): string;
|
|
36
|
+
/**
|
|
37
|
+
* @name searchSessions
|
|
38
|
+
* @description Searches Hermes session history for relevant past conversations.
|
|
39
|
+
*
|
|
40
|
+
* This is a lightweight bridge — it reads the Hermes session database using
|
|
41
|
+
* the same better-sqlite3 driver (opening a read-only connection). The query
|
|
42
|
+
* uses FTS5 if the Hermes DB has it, otherwise falls back to LIKE search.
|
|
43
|
+
*
|
|
44
|
+
* @param query - Search query (natural language).
|
|
45
|
+
* @param limit - Max results. Default 5.
|
|
46
|
+
* @returns Array of session snippets with timestamps.
|
|
47
|
+
*/
|
|
48
|
+
searchSessions(query: string, limit?: number): Array<{
|
|
49
|
+
sessionId: string;
|
|
50
|
+
title: string;
|
|
51
|
+
snippet: string;
|
|
52
|
+
timestamp: string;
|
|
53
|
+
}>;
|
|
54
|
+
/**
|
|
55
|
+
* @name getRecentSessions
|
|
56
|
+
* @description Returns recent Hermes sessions for context injection.
|
|
57
|
+
* @param limit - Max sessions. Default 3.
|
|
58
|
+
*/
|
|
59
|
+
getRecentSessions(limit?: number): Array<{
|
|
60
|
+
sessionId: string;
|
|
61
|
+
title: string;
|
|
62
|
+
timestamp: string;
|
|
63
|
+
}>;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* @name hermesBridge
|
|
67
|
+
* @description Singleton instance of the Hermes bridge.
|
|
68
|
+
*/
|
|
69
|
+
export declare const hermesBridge: HermesBridge;
|
|
70
|
+
//# sourceMappingURL=hermes-bridge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hermes-bridge.d.ts","sourceRoot":"","sources":["../../src/memory/hermes-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAUH;;;;;;GAMG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;IACnC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAS;IACtC,OAAO,CAAC,SAAS,CAAwB;;IAOzC;;;;OAIG;IACH,WAAW,IAAI,OAAO;IAWtB;;;OAGG;IACH,YAAY,IAAI,MAAM;IAItB;;;;;;;;;;;OAWG;IACH,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,KAAK,SAAI,GAAG,KAAK,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IAsDzH;;;;OAIG;IACH,iBAAiB,CAAC,KAAK,SAAI,GAAG,KAAK,CAAC;QAAE,SAAS,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;CA0B7F;AAED;;;GAGG;AACH,eAAO,MAAM,YAAY,cAAqB,CAAC"}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module memory/hermes-bridge
|
|
3
|
+
* @description Cross-session integration with Hermes Agent session database.
|
|
4
|
+
*
|
|
5
|
+
* If the user has Hermes Agent installed (detected via ~/.hermes/ directory),
|
|
6
|
+
* the memory subsystem can query Hermes session history for cross-session
|
|
7
|
+
* context. This enables the agent to recall relevant conversations from
|
|
8
|
+
* previous Hermes sessions while keeping the data local.
|
|
9
|
+
*
|
|
10
|
+
* If Hermes is not installed, all bridge functions return empty results —
|
|
11
|
+
* the memory subsystem operates standalone.
|
|
12
|
+
*/
|
|
13
|
+
import { existsSync } from 'fs';
|
|
14
|
+
import { join } from 'path';
|
|
15
|
+
import { homedir } from 'os';
|
|
16
|
+
import { createRequire } from 'module';
|
|
17
|
+
import { logger } from '../core/logger.js';
|
|
18
|
+
const require = createRequire(import.meta.url);
|
|
19
|
+
/**
|
|
20
|
+
* @name HermesBridge
|
|
21
|
+
* @description Bridges the SAP MCP memory subsystem with Hermes Agent session data.
|
|
22
|
+
*
|
|
23
|
+
* Detection: checks for ~/.hermes/ directory. If present, the bridge can query
|
|
24
|
+
* the Hermes SQLite session database for relevant past conversations.
|
|
25
|
+
*/
|
|
26
|
+
export class HermesBridge {
|
|
27
|
+
hermesDir;
|
|
28
|
+
hermesDbPath;
|
|
29
|
+
available = null;
|
|
30
|
+
constructor() {
|
|
31
|
+
this.hermesDir = join(homedir(), '.hermes');
|
|
32
|
+
this.hermesDbPath = join(this.hermesDir, 'sessions.db');
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* @name isAvailable
|
|
36
|
+
* @description Checks whether Hermes Agent is installed on this machine.
|
|
37
|
+
* Caches the result to avoid repeated filesystem checks.
|
|
38
|
+
*/
|
|
39
|
+
isAvailable() {
|
|
40
|
+
if (this.available !== null)
|
|
41
|
+
return this.available;
|
|
42
|
+
this.available = existsSync(this.hermesDir);
|
|
43
|
+
if (this.available) {
|
|
44
|
+
logger.info('Hermes Agent detected — cross-session bridge enabled', {
|
|
45
|
+
hermesDir: this.hermesDir,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
return this.available;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* @name getHermesDir
|
|
52
|
+
* @description Returns the Hermes installation directory.
|
|
53
|
+
*/
|
|
54
|
+
getHermesDir() {
|
|
55
|
+
return this.hermesDir;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* @name searchSessions
|
|
59
|
+
* @description Searches Hermes session history for relevant past conversations.
|
|
60
|
+
*
|
|
61
|
+
* This is a lightweight bridge — it reads the Hermes session database using
|
|
62
|
+
* the same better-sqlite3 driver (opening a read-only connection). The query
|
|
63
|
+
* uses FTS5 if the Hermes DB has it, otherwise falls back to LIKE search.
|
|
64
|
+
*
|
|
65
|
+
* @param query - Search query (natural language).
|
|
66
|
+
* @param limit - Max results. Default 5.
|
|
67
|
+
* @returns Array of session snippets with timestamps.
|
|
68
|
+
*/
|
|
69
|
+
searchSessions(query, limit = 5) {
|
|
70
|
+
if (!this.isAvailable())
|
|
71
|
+
return [];
|
|
72
|
+
if (!existsSync(this.hermesDbPath))
|
|
73
|
+
return [];
|
|
74
|
+
try {
|
|
75
|
+
// Use dynamic import to avoid loading better-sqlite3 if Hermes is not present.
|
|
76
|
+
const Database = require('better-sqlite3');
|
|
77
|
+
const db = new Database(this.hermesDbPath, { readonly: true });
|
|
78
|
+
try {
|
|
79
|
+
// Try FTS5 search first (if Hermes has it).
|
|
80
|
+
const ftsResults = db.prepare(`SELECT s.id, s.title, substr(m.content, 1, 200) as snippet, s.created_at
|
|
81
|
+
FROM messages m
|
|
82
|
+
JOIN sessions s ON s.id = m.session_id
|
|
83
|
+
WHERE m.content MATCH ?
|
|
84
|
+
ORDER BY s.created_at DESC
|
|
85
|
+
LIMIT ?`).all(query, limit);
|
|
86
|
+
return ftsResults.map(r => ({
|
|
87
|
+
sessionId: r.id,
|
|
88
|
+
title: r.title ?? 'Untitled',
|
|
89
|
+
snippet: r.snippet,
|
|
90
|
+
timestamp: r.created_at,
|
|
91
|
+
}));
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
// FTS not available — try LIKE search.
|
|
95
|
+
const likeResults = db.prepare(`SELECT s.id, s.title, substr(m.content, 1, 200) as snippet, s.created_at
|
|
96
|
+
FROM messages m
|
|
97
|
+
JOIN sessions s ON s.id = m.session_id
|
|
98
|
+
WHERE m.content LIKE ?
|
|
99
|
+
ORDER BY s.created_at DESC
|
|
100
|
+
LIMIT ?`).all(`%${query}%`, limit);
|
|
101
|
+
return likeResults.map(r => ({
|
|
102
|
+
sessionId: r.id,
|
|
103
|
+
title: r.title ?? 'Untitled',
|
|
104
|
+
snippet: r.snippet,
|
|
105
|
+
timestamp: r.created_at,
|
|
106
|
+
}));
|
|
107
|
+
}
|
|
108
|
+
finally {
|
|
109
|
+
db.close();
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
catch (error) {
|
|
113
|
+
logger.debug('Hermes bridge query failed', {
|
|
114
|
+
error: error instanceof Error ? error.message : String(error),
|
|
115
|
+
});
|
|
116
|
+
return [];
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* @name getRecentSessions
|
|
121
|
+
* @description Returns recent Hermes sessions for context injection.
|
|
122
|
+
* @param limit - Max sessions. Default 3.
|
|
123
|
+
*/
|
|
124
|
+
getRecentSessions(limit = 3) {
|
|
125
|
+
if (!this.isAvailable())
|
|
126
|
+
return [];
|
|
127
|
+
if (!existsSync(this.hermesDbPath))
|
|
128
|
+
return [];
|
|
129
|
+
try {
|
|
130
|
+
const Database = require('better-sqlite3');
|
|
131
|
+
const db = new Database(this.hermesDbPath, { readonly: true });
|
|
132
|
+
try {
|
|
133
|
+
const results = db.prepare(`SELECT id, title, created_at FROM sessions
|
|
134
|
+
ORDER BY created_at DESC LIMIT ?`).all(limit);
|
|
135
|
+
return results.map(r => ({
|
|
136
|
+
sessionId: r.id,
|
|
137
|
+
title: r.title ?? 'Untitled',
|
|
138
|
+
timestamp: r.created_at,
|
|
139
|
+
}));
|
|
140
|
+
}
|
|
141
|
+
finally {
|
|
142
|
+
db.close();
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
return [];
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* @name hermesBridge
|
|
152
|
+
* @description Singleton instance of the Hermes bridge.
|
|
153
|
+
*/
|
|
154
|
+
export const hermesBridge = new HermesBridge();
|
|
155
|
+
//# sourceMappingURL=hermes-bridge.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hermes-bridge.js","sourceRoot":"","sources":["../../src/memory/hermes-bridge.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module memory
|
|
3
|
+
* @description SAP MCP local agent memory subsystem — SQLite FTS5 backed.
|
|
4
|
+
*
|
|
5
|
+
* Exports all stores and types for use by the MCP tool registration layer.
|
|
6
|
+
*
|
|
7
|
+
* Architecture:
|
|
8
|
+
* - database.ts: Thread-safe singleton SQLite connection with WAL mode + FTS5.
|
|
9
|
+
* - tool-call-store.ts: Records and searches tool call history.
|
|
10
|
+
* - memory-store.ts: Manages LLM-generated agent memories with relevance decay.
|
|
11
|
+
* - stream-buffer-store.ts: Buffers premium stream events for offline consumption.
|
|
12
|
+
* - types.ts: Type definitions.
|
|
13
|
+
* - utils.ts: Utility functions (truncate, decay, expiry).
|
|
14
|
+
*/
|
|
15
|
+
export { MemoryDatabase, memoryDatabase, DEFAULT_CONFIG } from './database.js';
|
|
16
|
+
export { ToolCallStore, toolCallStore } from './tool-call-store.js';
|
|
17
|
+
export { MemoryStore, memoryStore } from './memory-store.js';
|
|
18
|
+
export { StreamBufferStore, streamBufferStore } from './stream-buffer-store.js';
|
|
19
|
+
export { AsyncMemoryProcessor, asyncMemoryProcessor } from './async-processor.js';
|
|
20
|
+
export { recordToolCall } from './auto-record.js';
|
|
21
|
+
export { HermesBridge, hermesBridge } from './hermes-bridge.js';
|
|
22
|
+
export type { ToolCallRecord, ToolCallOutcome, AgentMemoryRecord, MemoryType, StreamBufferRecord, MemorySearchResult, MemoryQueryOptions, MemoryStats, MemoryPruneResult, MemoryConfig, } from './types.js';
|
|
23
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/memory/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/E,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACpE,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAChF,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAClF,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAChE,YAAY,EACV,cAAc,EACd,eAAe,EACf,iBAAiB,EACjB,UAAU,EACV,kBAAkB,EAClB,kBAAkB,EAClB,kBAAkB,EAClB,WAAW,EACX,iBAAiB,EACjB,YAAY,GACb,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @module memory
|
|
3
|
+
* @description SAP MCP local agent memory subsystem — SQLite FTS5 backed.
|
|
4
|
+
*
|
|
5
|
+
* Exports all stores and types for use by the MCP tool registration layer.
|
|
6
|
+
*
|
|
7
|
+
* Architecture:
|
|
8
|
+
* - database.ts: Thread-safe singleton SQLite connection with WAL mode + FTS5.
|
|
9
|
+
* - tool-call-store.ts: Records and searches tool call history.
|
|
10
|
+
* - memory-store.ts: Manages LLM-generated agent memories with relevance decay.
|
|
11
|
+
* - stream-buffer-store.ts: Buffers premium stream events for offline consumption.
|
|
12
|
+
* - types.ts: Type definitions.
|
|
13
|
+
* - utils.ts: Utility functions (truncate, decay, expiry).
|
|
14
|
+
*/
|
|
15
|
+
export { MemoryDatabase, memoryDatabase, DEFAULT_CONFIG } from './database.js';
|
|
16
|
+
export { ToolCallStore, toolCallStore } from './tool-call-store.js';
|
|
17
|
+
export { MemoryStore, memoryStore } from './memory-store.js';
|
|
18
|
+
export { StreamBufferStore, streamBufferStore } from './stream-buffer-store.js';
|
|
19
|
+
export { AsyncMemoryProcessor, asyncMemoryProcessor } from './async-processor.js';
|
|
20
|
+
export { recordToolCall } from './auto-record.js';
|
|
21
|
+
export { HermesBridge, hermesBridge } from './hermes-bridge.js';
|
|
22
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/memory/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,cAAc,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/E,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACpE,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAChF,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAClF,OAAO,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC"}
|