agent-world 0.11.1 → 0.12.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/README.md +17 -7
- package/dist/cli/commands.d.ts +109 -0
- package/dist/cli/commands.js +2024 -0
- package/dist/cli/display.d.ts +124 -0
- package/dist/cli/display.js +381 -0
- package/dist/cli/hitl.d.ts +33 -0
- package/dist/cli/hitl.js +81 -0
- package/dist/cli/index.d.ts +2 -0
- package/dist/cli/stream.d.ts +41 -0
- package/dist/cli/stream.js +222 -0
- package/dist/core/activity-tracker.d.ts +16 -0
- package/dist/core/activity-tracker.d.ts.map +1 -0
- package/dist/core/activity-tracker.js +91 -0
- package/dist/core/activity-tracker.js.map +1 -0
- package/dist/core/ai-commands.d.ts +16 -0
- package/dist/core/ai-commands.d.ts.map +1 -0
- package/dist/core/ai-commands.js +24 -0
- package/dist/core/ai-commands.js.map +1 -0
- package/dist/core/ai-sdk-patch.d.ts +24 -0
- package/dist/core/ai-sdk-patch.d.ts.map +1 -0
- package/dist/core/ai-sdk-patch.js +169 -0
- package/dist/core/ai-sdk-patch.js.map +1 -0
- package/dist/core/anthropic-direct.d.ts +52 -0
- package/dist/core/anthropic-direct.d.ts.map +1 -0
- package/dist/core/anthropic-direct.js +301 -0
- package/dist/core/anthropic-direct.js.map +1 -0
- package/dist/core/approval-cache.d.ts +104 -0
- package/dist/core/approval-cache.d.ts.map +1 -0
- package/dist/core/approval-cache.js +150 -0
- package/dist/core/approval-cache.js.map +1 -0
- package/dist/core/chat-constants.d.ts +20 -0
- package/dist/core/chat-constants.d.ts.map +1 -0
- package/dist/core/chat-constants.js +22 -0
- package/dist/core/chat-constants.js.map +1 -0
- package/dist/core/create-agent-tool.d.ts +66 -0
- package/dist/core/create-agent-tool.d.ts.map +1 -0
- package/dist/core/create-agent-tool.js +212 -0
- package/dist/core/create-agent-tool.js.map +1 -0
- package/dist/core/events/approval-checker.d.ts +61 -0
- package/dist/core/events/approval-checker.d.ts.map +1 -0
- package/dist/core/events/approval-checker.js +226 -0
- package/dist/core/events/approval-checker.js.map +1 -0
- package/dist/core/events/index.d.ts +25 -0
- package/dist/core/events/index.d.ts.map +1 -0
- package/dist/core/events/index.js +30 -0
- package/dist/core/events/index.js.map +1 -0
- package/dist/core/events/memory-manager.d.ts +73 -0
- package/dist/core/events/memory-manager.d.ts.map +1 -0
- package/dist/core/events/memory-manager.js +1218 -0
- package/dist/core/events/memory-manager.js.map +1 -0
- package/dist/core/events/mention-logic.d.ts +39 -0
- package/dist/core/events/mention-logic.d.ts.map +1 -0
- package/dist/core/events/mention-logic.js +163 -0
- package/dist/core/events/mention-logic.js.map +1 -0
- package/dist/core/events/orchestrator.d.ts +69 -0
- package/dist/core/events/orchestrator.d.ts.map +1 -0
- package/dist/core/events/orchestrator.js +883 -0
- package/dist/core/events/orchestrator.js.map +1 -0
- package/dist/core/events/persistence.d.ts +41 -0
- package/dist/core/events/persistence.d.ts.map +1 -0
- package/dist/core/events/persistence.js +296 -0
- package/dist/core/events/persistence.js.map +1 -0
- package/dist/core/events/publishers.d.ts +81 -0
- package/dist/core/events/publishers.d.ts.map +1 -0
- package/dist/core/events/publishers.js +272 -0
- package/dist/core/events/publishers.js.map +1 -0
- package/dist/core/events/subscribers.d.ts +45 -0
- package/dist/core/events/subscribers.d.ts.map +1 -0
- package/dist/core/events/subscribers.js +288 -0
- package/dist/core/events/subscribers.js.map +1 -0
- package/dist/core/events/tool-bridge-logging.d.ts +28 -0
- package/dist/core/events/tool-bridge-logging.d.ts.map +1 -0
- package/dist/core/events/tool-bridge-logging.js +94 -0
- package/dist/core/events/tool-bridge-logging.js.map +1 -0
- package/dist/core/events-metadata.d.ts +72 -0
- package/dist/core/events-metadata.d.ts.map +1 -0
- package/dist/core/events-metadata.js +167 -0
- package/dist/core/events-metadata.js.map +1 -0
- package/dist/core/events.d.ts +186 -0
- package/dist/core/events.d.ts.map +1 -0
- package/dist/core/events.js +1248 -0
- package/dist/core/events.js.map +1 -0
- package/dist/core/export.d.ts +106 -0
- package/dist/core/export.d.ts.map +1 -0
- package/dist/core/export.js +705 -0
- package/dist/core/export.js.map +1 -0
- package/dist/core/file-tools.d.ts +114 -0
- package/dist/core/file-tools.d.ts.map +1 -0
- package/dist/core/file-tools.js +370 -0
- package/dist/core/file-tools.js.map +1 -0
- package/dist/core/google-direct.d.ts +58 -0
- package/dist/core/google-direct.d.ts.map +1 -0
- package/dist/core/google-direct.js +298 -0
- package/dist/core/google-direct.js.map +1 -0
- package/dist/core/hitl.d.ts +54 -0
- package/dist/core/hitl.d.ts.map +1 -0
- package/dist/core/hitl.js +153 -0
- package/dist/core/hitl.js.map +1 -0
- package/dist/core/index.d.ts +59 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +70 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/llm-config.d.ts +128 -0
- package/dist/core/llm-config.d.ts.map +1 -0
- package/dist/core/llm-config.js +164 -0
- package/dist/core/llm-config.js.map +1 -0
- package/dist/core/llm-manager.d.ts +163 -0
- package/dist/core/llm-manager.d.ts.map +1 -0
- package/dist/core/llm-manager.js +669 -0
- package/dist/core/llm-manager.js.map +1 -0
- package/dist/core/load-skill-tool.d.ts +55 -0
- package/dist/core/load-skill-tool.d.ts.map +1 -0
- package/dist/core/load-skill-tool.js +468 -0
- package/dist/core/load-skill-tool.js.map +1 -0
- package/dist/core/logger.d.ts +88 -0
- package/dist/core/logger.d.ts.map +1 -0
- package/dist/core/logger.js +358 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/managers.d.ts +131 -0
- package/dist/core/managers.d.ts.map +1 -0
- package/dist/core/managers.js +1223 -0
- package/dist/core/managers.js.map +1 -0
- package/dist/core/mcp-server-registry.d.ts +304 -0
- package/dist/core/mcp-server-registry.d.ts.map +1 -0
- package/dist/core/mcp-server-registry.js +1769 -0
- package/dist/core/mcp-server-registry.js.map +1 -0
- package/dist/core/mcp-tools.d.ts +56 -0
- package/dist/core/mcp-tools.d.ts.map +1 -0
- package/dist/core/mcp-tools.js +186 -0
- package/dist/core/mcp-tools.js.map +1 -0
- package/dist/core/message-prep.d.ts +81 -0
- package/dist/core/message-prep.d.ts.map +1 -0
- package/dist/core/message-prep.js +223 -0
- package/dist/core/message-prep.js.map +1 -0
- package/dist/core/message-processing-control.d.ts +54 -0
- package/dist/core/message-processing-control.d.ts.map +1 -0
- package/dist/core/message-processing-control.js +139 -0
- package/dist/core/message-processing-control.js.map +1 -0
- package/dist/core/openai-direct.d.ts +80 -0
- package/dist/core/openai-direct.d.ts.map +1 -0
- package/dist/core/openai-direct.js +374 -0
- package/dist/core/openai-direct.js.map +1 -0
- package/dist/core/shell-cmd-tool.d.ts +235 -0
- package/dist/core/shell-cmd-tool.d.ts.map +1 -0
- package/dist/core/shell-cmd-tool.js +1157 -0
- package/dist/core/shell-cmd-tool.js.map +1 -0
- package/dist/core/shell-process-registry.d.ts +88 -0
- package/dist/core/shell-process-registry.d.ts.map +1 -0
- package/dist/core/shell-process-registry.js +309 -0
- package/dist/core/shell-process-registry.js.map +1 -0
- package/dist/core/skill-registry.d.ts +75 -0
- package/dist/core/skill-registry.d.ts.map +1 -0
- package/dist/core/skill-registry.js +369 -0
- package/dist/core/skill-registry.js.map +1 -0
- package/dist/core/skill-script-runner.d.ts +89 -0
- package/dist/core/skill-script-runner.d.ts.map +1 -0
- package/dist/core/skill-script-runner.js +274 -0
- package/dist/core/skill-script-runner.js.map +1 -0
- package/dist/core/skill-selector.d.ts +65 -0
- package/dist/core/skill-selector.d.ts.map +1 -0
- package/dist/core/skill-selector.js +190 -0
- package/dist/core/skill-selector.js.map +1 -0
- package/dist/core/skill-settings.d.ts +20 -0
- package/dist/core/skill-settings.d.ts.map +1 -0
- package/dist/core/skill-settings.js +40 -0
- package/dist/core/skill-settings.js.map +1 -0
- package/dist/core/storage/agent-storage.d.ts +134 -0
- package/dist/core/storage/agent-storage.d.ts.map +1 -0
- package/dist/core/storage/agent-storage.js +498 -0
- package/dist/core/storage/agent-storage.js.map +1 -0
- package/dist/core/storage/eventStorage/fileEventStorage.d.ts +100 -0
- package/dist/core/storage/eventStorage/fileEventStorage.d.ts.map +1 -0
- package/dist/core/storage/eventStorage/fileEventStorage.js +494 -0
- package/dist/core/storage/eventStorage/fileEventStorage.js.map +1 -0
- package/dist/core/storage/eventStorage/index.d.ts +31 -0
- package/dist/core/storage/eventStorage/index.d.ts.map +1 -0
- package/dist/core/storage/eventStorage/index.js +31 -0
- package/dist/core/storage/eventStorage/index.js.map +1 -0
- package/dist/core/storage/eventStorage/memoryEventStorage.d.ts +87 -0
- package/dist/core/storage/eventStorage/memoryEventStorage.d.ts.map +1 -0
- package/dist/core/storage/eventStorage/memoryEventStorage.js +244 -0
- package/dist/core/storage/eventStorage/memoryEventStorage.js.map +1 -0
- package/dist/core/storage/eventStorage/sqliteEventStorage.d.ts +45 -0
- package/dist/core/storage/eventStorage/sqliteEventStorage.d.ts.map +1 -0
- package/dist/core/storage/eventStorage/sqliteEventStorage.js +301 -0
- package/dist/core/storage/eventStorage/sqliteEventStorage.js.map +1 -0
- package/dist/core/storage/eventStorage/types.d.ts +142 -0
- package/dist/core/storage/eventStorage/types.d.ts.map +1 -0
- package/dist/core/storage/eventStorage/types.js +43 -0
- package/dist/core/storage/eventStorage/types.js.map +1 -0
- package/dist/core/storage/eventStorage/validation.d.ts +30 -0
- package/dist/core/storage/eventStorage/validation.d.ts.map +1 -0
- package/dist/core/storage/eventStorage/validation.js +68 -0
- package/dist/core/storage/eventStorage/validation.js.map +1 -0
- package/dist/core/storage/legacy-migrations.d.ts +45 -0
- package/dist/core/storage/legacy-migrations.d.ts.map +1 -0
- package/dist/core/storage/legacy-migrations.js +295 -0
- package/dist/core/storage/legacy-migrations.js.map +1 -0
- package/dist/core/storage/memory-storage.d.ts +105 -0
- package/dist/core/storage/memory-storage.d.ts.map +1 -0
- package/dist/core/storage/memory-storage.js +415 -0
- package/dist/core/storage/memory-storage.js.map +1 -0
- package/dist/core/storage/migration-runner.d.ts +96 -0
- package/dist/core/storage/migration-runner.d.ts.map +1 -0
- package/dist/core/storage/migration-runner.js +306 -0
- package/dist/core/storage/migration-runner.js.map +1 -0
- package/dist/core/storage/queue-storage.d.ts +147 -0
- package/dist/core/storage/queue-storage.d.ts.map +1 -0
- package/dist/core/storage/queue-storage.js +290 -0
- package/dist/core/storage/queue-storage.js.map +1 -0
- package/dist/core/storage/skill-storage.d.ts +136 -0
- package/dist/core/storage/skill-storage.d.ts.map +1 -0
- package/dist/core/storage/skill-storage.js +474 -0
- package/dist/core/storage/skill-storage.js.map +1 -0
- package/dist/core/storage/sqlite-schema.d.ts +95 -0
- package/dist/core/storage/sqlite-schema.d.ts.map +1 -0
- package/dist/core/storage/sqlite-schema.js +156 -0
- package/dist/core/storage/sqlite-schema.js.map +1 -0
- package/dist/core/storage/sqlite-storage.d.ts +146 -0
- package/dist/core/storage/sqlite-storage.d.ts.map +1 -0
- package/dist/core/storage/sqlite-storage.js +709 -0
- package/dist/core/storage/sqlite-storage.js.map +1 -0
- package/dist/core/storage/storage-factory.d.ts +61 -0
- package/dist/core/storage/storage-factory.d.ts.map +1 -0
- package/dist/core/storage/storage-factory.js +794 -0
- package/dist/core/storage/storage-factory.js.map +1 -0
- package/dist/core/storage/validation.d.ts +36 -0
- package/dist/core/storage/validation.d.ts.map +1 -0
- package/dist/core/storage/validation.js +79 -0
- package/dist/core/storage/validation.js.map +1 -0
- package/dist/core/storage/world-storage.d.ts +114 -0
- package/dist/core/storage/world-storage.d.ts.map +1 -0
- package/dist/core/storage/world-storage.js +378 -0
- package/dist/core/storage/world-storage.js.map +1 -0
- package/dist/core/subscription.d.ts +43 -0
- package/dist/core/subscription.d.ts.map +1 -0
- package/dist/core/subscription.js +227 -0
- package/dist/core/subscription.js.map +1 -0
- package/dist/core/tool-utils.d.ts +80 -0
- package/dist/core/tool-utils.d.ts.map +1 -0
- package/dist/core/tool-utils.js +273 -0
- package/dist/core/tool-utils.js.map +1 -0
- package/dist/core/types.d.ts +595 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +158 -0
- package/dist/core/types.js.map +1 -0
- package/dist/core/utils.d.ts +138 -0
- package/dist/core/utils.d.ts.map +1 -0
- package/dist/core/utils.js +478 -0
- package/dist/core/utils.js.map +1 -0
- package/dist/core/world-class.d.ts +43 -0
- package/dist/core/world-class.d.ts.map +1 -0
- package/dist/core/world-class.js +90 -0
- package/dist/core/world-class.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/public/assets/agent-sprites-DJFgj-zP.png +0 -0
- package/dist/public/assets/border-KHK37r8y.svg +83 -0
- package/dist/public/assets/index-C9kPXL6G.css +1 -0
- package/dist/public/assets/index-DOQEHGWt.js +96 -0
- package/dist/public/index.html +21 -0
- package/dist/server/api.d.ts +2 -0
- package/dist/server/api.js +1124 -0
- package/dist/server/index.d.ts +29 -0
- package/dist/server/sse-handler.d.ts +62 -0
- package/dist/server/sse-handler.js +234 -0
- package/package.json +15 -3
- package/scripts/launch-electron.js +0 -58
|
@@ -0,0 +1,709 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SQLite Storage Implementation for Agent World System
|
|
3
|
+
*
|
|
4
|
+
* Features:
|
|
5
|
+
* - Full implementation of StorageAPI interface for SQLite backend
|
|
6
|
+
* - Complete chat operations with proper TypeScript types (WorldChat, ChatData, etc.)
|
|
7
|
+
* - Enhanced snapshot operations for world state preservation and restoration
|
|
8
|
+
* - Enhanced archive management with rich metadata and search capabilities
|
|
9
|
+
* - Optimized queries with prepared statements and transactions
|
|
10
|
+
* - Data integrity with foreign key constraints and validation
|
|
11
|
+
* - Migration support from file-based storage
|
|
12
|
+
* - Performance monitoring and analytics
|
|
13
|
+
*
|
|
14
|
+
* Enhanced Chat Features:
|
|
15
|
+
* - Full CRUD operations for world chats with proper type safety
|
|
16
|
+
* - Snapshot storage and restoration with atomic transactions
|
|
17
|
+
* - Foreign key relationships ensuring data consistency
|
|
18
|
+
* - Efficient querying with indexed columns
|
|
19
|
+
*
|
|
20
|
+
* Enhanced Archive Features:
|
|
21
|
+
* - Rich archive metadata (session names, reasons, statistics)
|
|
22
|
+
* - Content-based search across archived conversations
|
|
23
|
+
* - Archive usage analytics and trends
|
|
24
|
+
* - Efficient querying by date, agent, participants
|
|
25
|
+
* - Export capabilities in various formats
|
|
26
|
+
*
|
|
27
|
+
* Implementation:
|
|
28
|
+
* - Maintains compatibility with existing storage interfaces
|
|
29
|
+
* - Uses proper async/await patterns for SQLite operations
|
|
30
|
+
* - Implements batch operations for efficiency
|
|
31
|
+
* - Provides transaction support for data consistency
|
|
32
|
+
* - Includes comprehensive error handling and validation
|
|
33
|
+
* - Complete type safety with proper TypeScript interfaces
|
|
34
|
+
*
|
|
35
|
+
* Recent Changes:
|
|
36
|
+
* - 2026-02-13: Added atomic compare-and-set chat title update helper (`updateChatNameIfCurrent`).
|
|
37
|
+
* - 2026-02-13: Fixed migration directory resolution so Electron runtimes launched from `electron/` still run root `migrations/`.
|
|
38
|
+
* - 2025-08-01: Added proper TypeScript types for all chat operations
|
|
39
|
+
* - 2025-08-01: Implemented restoreFromSnapshot with atomic transactions
|
|
40
|
+
* - 2025-08-01: Enhanced type safety removing any types
|
|
41
|
+
* - 2025-08-06: Fixed initialization order - migration check before schema initialization
|
|
42
|
+
* - 2025-11-02: Integrated SQL migration runner, removed legacy migrations
|
|
43
|
+
*/
|
|
44
|
+
import { createSQLiteSchemaContext, validateIntegrity as schemaValidateIntegrity, getDatabaseStats as schemaGetDatabaseStats, closeSchema } from './sqlite-schema.js';
|
|
45
|
+
import { runMigrations } from './migration-runner.js';
|
|
46
|
+
import * as path from 'path';
|
|
47
|
+
import * as fs from 'fs';
|
|
48
|
+
import { fileURLToPath } from 'url';
|
|
49
|
+
export async function createSQLiteStorageContext(config) {
|
|
50
|
+
const schemaCtx = await createSQLiteSchemaContext(config);
|
|
51
|
+
return {
|
|
52
|
+
schemaCtx,
|
|
53
|
+
db: schemaCtx.db,
|
|
54
|
+
isInitialized: false
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
function resolveMigrationsDir() {
|
|
58
|
+
const moduleDir = path.dirname(fileURLToPath(import.meta.url));
|
|
59
|
+
const candidates = [
|
|
60
|
+
path.join(process.cwd(), 'migrations'),
|
|
61
|
+
path.resolve(process.cwd(), '..', 'migrations'),
|
|
62
|
+
path.resolve(moduleDir, '../../migrations'),
|
|
63
|
+
path.resolve(moduleDir, '../../../migrations')
|
|
64
|
+
];
|
|
65
|
+
for (const candidate of candidates) {
|
|
66
|
+
if (fs.existsSync(candidate)) {
|
|
67
|
+
return candidate;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return candidates[0];
|
|
71
|
+
}
|
|
72
|
+
async function ensureInitialized(ctx) {
|
|
73
|
+
if (!ctx.isInitialized) {
|
|
74
|
+
const migrationsDir = resolveMigrationsDir();
|
|
75
|
+
// Always run migrations - this handles both fresh databases (starting with 0000)
|
|
76
|
+
// and existing databases that need updates
|
|
77
|
+
await runMigrations({
|
|
78
|
+
db: ctx.schemaCtx.db,
|
|
79
|
+
migrationsDir
|
|
80
|
+
});
|
|
81
|
+
ctx.isInitialized = true;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Utility to initialize the database schema and insert a default world and agent if not present.
|
|
86
|
+
* This is useful for first-time setup or testing.
|
|
87
|
+
*/
|
|
88
|
+
export async function initializeWithDefaults(ctx) {
|
|
89
|
+
await ensureInitialized(ctx);
|
|
90
|
+
// Insert default world if not exists
|
|
91
|
+
const defaultWorldId = 'default-world';
|
|
92
|
+
// Only create the default world if no worlds exist in the database
|
|
93
|
+
const worldCountRow = await get(ctx, `SELECT COUNT(*) as count FROM worlds`);
|
|
94
|
+
if (worldCountRow && worldCountRow.count === 0) {
|
|
95
|
+
const defaultWorldId = 'default-world';
|
|
96
|
+
await run(ctx, `
|
|
97
|
+
INSERT INTO worlds (id, name, description, turn_limit, updated_at)
|
|
98
|
+
VALUES (?, ?, ?, ?, CURRENT_TIMESTAMP)
|
|
99
|
+
`, defaultWorldId, 'Default World', 'The default world for Agent World system.', 100);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
async function run(ctx, sql, ...params) {
|
|
103
|
+
return new Promise((resolve, reject) => {
|
|
104
|
+
ctx.db.run(sql, params, function (err) {
|
|
105
|
+
if (err)
|
|
106
|
+
reject(err);
|
|
107
|
+
else
|
|
108
|
+
resolve(this);
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
async function get(ctx, sql, ...params) {
|
|
113
|
+
return new Promise((resolve, reject) => {
|
|
114
|
+
ctx.db.get(sql, params, (err, row) => {
|
|
115
|
+
if (err)
|
|
116
|
+
reject(err);
|
|
117
|
+
else
|
|
118
|
+
resolve(row);
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
async function all(ctx, sql, ...params) {
|
|
123
|
+
return new Promise((resolve, reject) => {
|
|
124
|
+
ctx.db.all(sql, params, (err, rows) => {
|
|
125
|
+
if (err)
|
|
126
|
+
reject(err);
|
|
127
|
+
else
|
|
128
|
+
resolve(rows || []);
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
// WORLD OPERATIONS
|
|
133
|
+
export async function saveWorld(ctx, worldData) {
|
|
134
|
+
await ensureInitialized(ctx);
|
|
135
|
+
// Use INSERT with ON CONFLICT UPDATE instead of INSERT OR REPLACE to avoid foreign key cascade issues
|
|
136
|
+
await run(ctx, `
|
|
137
|
+
INSERT INTO worlds (id, name, description, turn_limit, main_agent, chat_llm_provider, chat_llm_model, current_chat_id, mcp_config, variables, updated_at)
|
|
138
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP)
|
|
139
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
140
|
+
name = excluded.name,
|
|
141
|
+
description = excluded.description,
|
|
142
|
+
turn_limit = excluded.turn_limit,
|
|
143
|
+
main_agent = excluded.main_agent,
|
|
144
|
+
chat_llm_provider = excluded.chat_llm_provider,
|
|
145
|
+
chat_llm_model = excluded.chat_llm_model,
|
|
146
|
+
current_chat_id = excluded.current_chat_id,
|
|
147
|
+
variables = excluded.variables,
|
|
148
|
+
mcp_config = excluded.mcp_config,
|
|
149
|
+
updated_at = CURRENT_TIMESTAMP
|
|
150
|
+
`, worldData.id, worldData.name, worldData.description, worldData.turnLimit, worldData.mainAgent, worldData.chatLLMProvider, worldData.chatLLMModel, worldData.currentChatId, worldData.mcpConfig, worldData.variables);
|
|
151
|
+
}
|
|
152
|
+
export async function loadWorld(ctx, worldId) {
|
|
153
|
+
await ensureInitialized(ctx);
|
|
154
|
+
const result = await get(ctx, `
|
|
155
|
+
SELECT id, name, description, turn_limit as turnLimit,
|
|
156
|
+
main_agent as mainAgent,
|
|
157
|
+
chat_llm_provider as chatLLMProvider, chat_llm_model as chatLLMModel,
|
|
158
|
+
current_chat_id as currentChatId, mcp_config as mcpConfig,
|
|
159
|
+
variables as variables
|
|
160
|
+
FROM worlds WHERE id = ?
|
|
161
|
+
`, worldId);
|
|
162
|
+
return result || null;
|
|
163
|
+
}
|
|
164
|
+
export async function deleteWorld(ctx, worldId) {
|
|
165
|
+
await ensureInitialized(ctx);
|
|
166
|
+
try {
|
|
167
|
+
const result = await run(ctx, `DELETE FROM worlds WHERE id = ?`, worldId);
|
|
168
|
+
return result.changes > 0;
|
|
169
|
+
}
|
|
170
|
+
catch {
|
|
171
|
+
return false;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
export async function listWorlds(ctx) {
|
|
175
|
+
await ensureInitialized(ctx);
|
|
176
|
+
const results = await all(ctx, `
|
|
177
|
+
SELECT id, name, description, turn_limit as turnLimit,
|
|
178
|
+
main_agent as mainAgent,
|
|
179
|
+
chat_llm_provider as chatLLMProvider, chat_llm_model as chatLLMModel,
|
|
180
|
+
current_chat_id as currentChatId, mcp_config as mcpConfig,
|
|
181
|
+
variables as variables
|
|
182
|
+
FROM worlds
|
|
183
|
+
ORDER BY name
|
|
184
|
+
`);
|
|
185
|
+
return results || [];
|
|
186
|
+
}
|
|
187
|
+
// AGENT OPERATIONS
|
|
188
|
+
export async function saveAgent(ctx, worldId, agent) {
|
|
189
|
+
await ensureInitialized(ctx);
|
|
190
|
+
await run(ctx, `
|
|
191
|
+
INSERT OR REPLACE INTO agents (
|
|
192
|
+
id, world_id, name, type, status, provider, model, system_prompt,
|
|
193
|
+
temperature, max_tokens, auto_reply, llm_call_count, last_active, last_llm_call
|
|
194
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
195
|
+
`, agent.id, worldId, agent.name, agent.type, agent.status || 'inactive', agent.provider, agent.model, agent.systemPrompt, agent.temperature, agent.maxTokens, agent.autoReply === false ? 0 : 1, agent.llmCallCount, agent.lastActive?.toISOString(), agent.lastLLMCall?.toISOString());
|
|
196
|
+
if (agent.memory && agent.memory.length > 0) {
|
|
197
|
+
await saveAgentMemory(ctx, worldId, agent.id, agent.memory);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
export async function loadAgent(ctx, worldId, agentId) {
|
|
201
|
+
await ensureInitialized(ctx);
|
|
202
|
+
const agentData = await get(ctx, `
|
|
203
|
+
SELECT id, name, type, status, provider, model, system_prompt as systemPrompt,
|
|
204
|
+
temperature, max_tokens as maxTokens, auto_reply as autoReply, llm_call_count as llmCallCount,
|
|
205
|
+
created_at as createdAt, last_active as lastActive, last_llm_call as lastLLMCall
|
|
206
|
+
FROM agents WHERE id = ? AND world_id = ?
|
|
207
|
+
`, agentId, worldId);
|
|
208
|
+
if (!agentData)
|
|
209
|
+
return null;
|
|
210
|
+
const memoryData = await all(ctx, `
|
|
211
|
+
SELECT role, content, sender, chat_id as chatId, message_id as messageId, reply_to_message_id as replyToMessageId,
|
|
212
|
+
tool_calls as toolCalls, tool_call_id as toolCallId, created_at as createdAt
|
|
213
|
+
FROM agent_memory
|
|
214
|
+
WHERE agent_id = ? AND world_id = ?
|
|
215
|
+
ORDER BY created_at ASC
|
|
216
|
+
`, agentId, worldId);
|
|
217
|
+
const agent = {
|
|
218
|
+
...agentData,
|
|
219
|
+
autoReply: agentData.autoReply === 0 ? false : true,
|
|
220
|
+
createdAt: agentData.createdAt ? new Date(agentData.createdAt) : new Date(),
|
|
221
|
+
lastActive: agentData.lastActive ? new Date(agentData.lastActive) : new Date(),
|
|
222
|
+
lastLLMCall: agentData.lastLLMCall ? new Date(agentData.lastLLMCall) : undefined,
|
|
223
|
+
memory: memoryData.map(msg => ({
|
|
224
|
+
...msg,
|
|
225
|
+
createdAt: msg.createdAt ? new Date(msg.createdAt) : new Date(),
|
|
226
|
+
chatId: msg.chatId, // Preserve chatId field
|
|
227
|
+
tool_calls: msg.toolCalls ? JSON.parse(msg.toolCalls) : undefined,
|
|
228
|
+
tool_call_id: msg.toolCallId || undefined
|
|
229
|
+
})),
|
|
230
|
+
};
|
|
231
|
+
return agent;
|
|
232
|
+
}
|
|
233
|
+
export async function deleteAgent(ctx, worldId, agentId) {
|
|
234
|
+
await ensureInitialized(ctx);
|
|
235
|
+
try {
|
|
236
|
+
const result = await run(ctx, `
|
|
237
|
+
DELETE FROM agents WHERE id = ? AND world_id = ?
|
|
238
|
+
`, agentId, worldId);
|
|
239
|
+
return result.changes > 0;
|
|
240
|
+
}
|
|
241
|
+
catch {
|
|
242
|
+
return false;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
export async function listAgents(ctx, worldId) {
|
|
246
|
+
await ensureInitialized(ctx);
|
|
247
|
+
const agents = await all(ctx, `
|
|
248
|
+
SELECT id, name, type, status, provider, model, system_prompt as systemPrompt,
|
|
249
|
+
temperature, max_tokens as maxTokens, auto_reply as autoReply, llm_call_count as llmCallCount,
|
|
250
|
+
created_at as createdAt, last_active as lastActive, last_llm_call as lastLLMCall
|
|
251
|
+
FROM agents WHERE world_id = ?
|
|
252
|
+
ORDER BY name
|
|
253
|
+
`, worldId);
|
|
254
|
+
const result = [];
|
|
255
|
+
for (const agentData of agents) {
|
|
256
|
+
const memoryData = await all(ctx, `
|
|
257
|
+
SELECT role, content, sender, chat_id as chatId, message_id as messageId, reply_to_message_id as replyToMessageId,
|
|
258
|
+
tool_calls as toolCalls, tool_call_id as toolCallId, created_at as createdAt
|
|
259
|
+
FROM agent_memory
|
|
260
|
+
WHERE agent_id = ? AND world_id = ?
|
|
261
|
+
ORDER BY created_at ASC
|
|
262
|
+
`, agentData.id, worldId);
|
|
263
|
+
const agent = {
|
|
264
|
+
...agentData,
|
|
265
|
+
autoReply: agentData.autoReply === 0 ? false : true,
|
|
266
|
+
createdAt: agentData.createdAt ? new Date(agentData.createdAt) : new Date(),
|
|
267
|
+
lastActive: agentData.lastActive ? new Date(agentData.lastActive) : new Date(),
|
|
268
|
+
lastLLMCall: agentData.lastLLMCall ? new Date(agentData.lastLLMCall) : undefined,
|
|
269
|
+
memory: memoryData.map(msg => ({
|
|
270
|
+
...msg,
|
|
271
|
+
createdAt: msg.createdAt ? new Date(msg.createdAt) : new Date(),
|
|
272
|
+
chatId: msg.chatId, // Preserve chatId field
|
|
273
|
+
replyToMessageId: msg.replyToMessageId, // Preserve replyToMessageId field
|
|
274
|
+
tool_calls: msg.tool_calls ? JSON.parse(msg.tool_calls) : undefined // Parse JSON string to object
|
|
275
|
+
})),
|
|
276
|
+
};
|
|
277
|
+
result.push(agent);
|
|
278
|
+
}
|
|
279
|
+
return result;
|
|
280
|
+
}
|
|
281
|
+
export async function saveAgentMemory(ctx, worldId, agentId, memory) {
|
|
282
|
+
await run(ctx, `DELETE FROM agent_memory WHERE agent_id = ? AND world_id = ?`, agentId, worldId);
|
|
283
|
+
// CRITICAL: Filter out system messages - they should NEVER be saved to storage
|
|
284
|
+
// System messages are generated dynamically during LLM preparation
|
|
285
|
+
const filteredMemory = memory.filter(msg => msg.role !== 'system');
|
|
286
|
+
if (filteredMemory.length < memory.length) {
|
|
287
|
+
const logger = await import('../logger.js').then(m => m.logger);
|
|
288
|
+
logger.warn('Filtered out system messages from agent memory before saving to SQLite', {
|
|
289
|
+
agentId,
|
|
290
|
+
worldId,
|
|
291
|
+
removedCount: memory.length - filteredMemory.length,
|
|
292
|
+
remainingCount: filteredMemory.length
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
for (const message of filteredMemory) {
|
|
296
|
+
await run(ctx, `
|
|
297
|
+
INSERT INTO agent_memory (agent_id, world_id, role, content, sender, chat_id, message_id, reply_to_message_id, tool_calls, tool_call_id, created_at)
|
|
298
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
299
|
+
`, agentId, worldId, message.role, message.content, message.sender, message.chatId, message.messageId, message.replyToMessageId, message.tool_calls ? JSON.stringify(message.tool_calls) : null, message.tool_call_id || null, message.createdAt instanceof Date ? message.createdAt.toISOString() : (message.createdAt || new Date().toISOString()));
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
// MEMORY CLEANUP OPERATIONS
|
|
303
|
+
export async function deleteMemoryByChatId(ctx, worldId, chatId) {
|
|
304
|
+
await ensureInitialized(ctx);
|
|
305
|
+
const result = await run(ctx, `
|
|
306
|
+
DELETE FROM agent_memory WHERE world_id = ? AND chat_id = ?
|
|
307
|
+
`, worldId, chatId);
|
|
308
|
+
return result.changes || 0;
|
|
309
|
+
}
|
|
310
|
+
// GET MEMORY (aggregated across agents for a given chat)
|
|
311
|
+
export async function getMemory(ctx, worldId, chatId) {
|
|
312
|
+
await ensureInitialized(ctx);
|
|
313
|
+
const rows = await all(ctx, `
|
|
314
|
+
SELECT role, content, sender, chat_id as chatId, message_id as messageId, reply_to_message_id as replyToMessageId,
|
|
315
|
+
tool_calls as toolCalls, tool_call_id as toolCallId, agent_id as agentId, created_at as createdAt
|
|
316
|
+
FROM agent_memory
|
|
317
|
+
WHERE world_id = ? AND (? = '' OR chat_id = ?)
|
|
318
|
+
ORDER BY datetime(created_at) ASC, rowid ASC
|
|
319
|
+
`, worldId, chatId || '', chatId || '');
|
|
320
|
+
return (rows || []).map((r) => ({
|
|
321
|
+
role: r.role,
|
|
322
|
+
content: r.content,
|
|
323
|
+
sender: r.sender,
|
|
324
|
+
chatId: r.chatId,
|
|
325
|
+
messageId: r.messageId,
|
|
326
|
+
replyToMessageId: r.replyToMessageId, // FIX: Include replyToMessageId from database
|
|
327
|
+
tool_calls: r.toolCalls ? JSON.parse(r.toolCalls) : undefined,
|
|
328
|
+
tool_call_id: r.toolCallId || undefined,
|
|
329
|
+
agentId: r.agentId,
|
|
330
|
+
createdAt: r.createdAt ? new Date(r.createdAt) : new Date()
|
|
331
|
+
}));
|
|
332
|
+
}
|
|
333
|
+
// BATCH OPERATIONS
|
|
334
|
+
export async function saveAgentsBatch(ctx, worldId, agents) {
|
|
335
|
+
await ensureInitialized(ctx);
|
|
336
|
+
for (const agent of agents) {
|
|
337
|
+
await saveAgent(ctx, worldId, agent);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
export async function loadAgentsBatch(ctx, worldId, agentIds) {
|
|
341
|
+
await ensureInitialized(ctx);
|
|
342
|
+
const agents = [];
|
|
343
|
+
for (const agentId of agentIds) {
|
|
344
|
+
const agent = await loadAgent(ctx, worldId, agentId);
|
|
345
|
+
if (agent)
|
|
346
|
+
agents.push(agent);
|
|
347
|
+
}
|
|
348
|
+
return agents;
|
|
349
|
+
}
|
|
350
|
+
// INTEGRITY OPERATIONS
|
|
351
|
+
export async function validateIntegrity(ctx, worldId, agentId) {
|
|
352
|
+
await ensureInitialized(ctx);
|
|
353
|
+
const schemaValidation = await schemaValidateIntegrity(ctx.schemaCtx);
|
|
354
|
+
if (!schemaValidation.isValid)
|
|
355
|
+
return false;
|
|
356
|
+
try {
|
|
357
|
+
if (agentId) {
|
|
358
|
+
const agent = await get(ctx, `
|
|
359
|
+
SELECT id FROM agents WHERE id = ? AND world_id = ?
|
|
360
|
+
`, agentId, worldId);
|
|
361
|
+
return !!agent;
|
|
362
|
+
}
|
|
363
|
+
else {
|
|
364
|
+
const world = await get(ctx, `SELECT id FROM worlds WHERE id = ?`, worldId);
|
|
365
|
+
return !!world;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
catch {
|
|
369
|
+
return false;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
export async function repairData(ctx, worldId, agentId) {
|
|
373
|
+
await ensureInitialized(ctx);
|
|
374
|
+
return false;
|
|
375
|
+
}
|
|
376
|
+
// CHAT HISTORY OPERATIONS
|
|
377
|
+
export async function saveChatData(ctx, worldId, chat) {
|
|
378
|
+
await ensureInitialized(ctx);
|
|
379
|
+
await run(ctx, `
|
|
380
|
+
INSERT INTO world_chats (id, world_id, name, description, message_count, tags, updated_at)
|
|
381
|
+
VALUES (?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP)
|
|
382
|
+
ON CONFLICT(id) DO UPDATE SET
|
|
383
|
+
name = excluded.name,
|
|
384
|
+
description = excluded.description,
|
|
385
|
+
message_count = excluded.message_count,
|
|
386
|
+
tags = excluded.tags,
|
|
387
|
+
updated_at = CURRENT_TIMESTAMP
|
|
388
|
+
`, chat.id, worldId, chat.name, chat.description, chat.messageCount || 0);
|
|
389
|
+
}
|
|
390
|
+
export async function loadChatData(ctx, worldId, chatId) {
|
|
391
|
+
await ensureInitialized(ctx);
|
|
392
|
+
const result = await get(ctx, `
|
|
393
|
+
SELECT id, world_id as worldId, name, description, message_count as messageCount,
|
|
394
|
+
tags, created_at as createdAt, updated_at as updatedAt
|
|
395
|
+
FROM world_chats
|
|
396
|
+
WHERE id = ? AND world_id = ?
|
|
397
|
+
`, chatId, worldId);
|
|
398
|
+
if (!result)
|
|
399
|
+
return null;
|
|
400
|
+
// Load chat if exists
|
|
401
|
+
const chat = await get(ctx, `
|
|
402
|
+
SELECT snapshot_data as snapshotData, captured_at as capturedAt, version
|
|
403
|
+
FROM chat_snapshots
|
|
404
|
+
WHERE chat_id = ? AND world_id = ?
|
|
405
|
+
ORDER BY captured_at DESC
|
|
406
|
+
LIMIT 1
|
|
407
|
+
`, chatId, worldId);
|
|
408
|
+
return {
|
|
409
|
+
...result,
|
|
410
|
+
createdAt: new Date(result.createdAt),
|
|
411
|
+
updatedAt: new Date(result.updatedAt),
|
|
412
|
+
tags: JSON.parse(result.tags || '[]'),
|
|
413
|
+
chat: chat ? {
|
|
414
|
+
...JSON.parse(chat.snapshotData),
|
|
415
|
+
metadata: {
|
|
416
|
+
...JSON.parse(chat.snapshotData).metadata,
|
|
417
|
+
capturedAt: new Date(chat.capturedAt),
|
|
418
|
+
version: chat.version
|
|
419
|
+
}
|
|
420
|
+
} : undefined
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
export async function deleteChatData(ctx, worldId, chatId) {
|
|
424
|
+
await ensureInitialized(ctx);
|
|
425
|
+
const result = await run(ctx, `
|
|
426
|
+
DELETE FROM world_chats WHERE id = ? AND world_id = ?
|
|
427
|
+
`, chatId, worldId);
|
|
428
|
+
return result.changes > 0;
|
|
429
|
+
}
|
|
430
|
+
export async function listChatHistories(ctx, worldId) {
|
|
431
|
+
await ensureInitialized(ctx);
|
|
432
|
+
const results = await all(ctx, `
|
|
433
|
+
SELECT id, name, description, message_count as messageCount,
|
|
434
|
+
tags, created_at as createdAt, updated_at as updatedAt
|
|
435
|
+
FROM world_chats
|
|
436
|
+
WHERE world_id = ?
|
|
437
|
+
ORDER BY updated_at DESC
|
|
438
|
+
`, worldId);
|
|
439
|
+
return results.map(chat => ({
|
|
440
|
+
...chat,
|
|
441
|
+
createdAt: new Date(chat.createdAt),
|
|
442
|
+
updatedAt: new Date(chat.updatedAt),
|
|
443
|
+
tags: JSON.parse(chat.tags || '[]')
|
|
444
|
+
}));
|
|
445
|
+
}
|
|
446
|
+
export async function updateChatData(ctx, worldId, chatId, updates) {
|
|
447
|
+
await ensureInitialized(ctx);
|
|
448
|
+
const setClauses = [];
|
|
449
|
+
const params = [];
|
|
450
|
+
if (updates.name !== undefined) {
|
|
451
|
+
setClauses.push('name = ?');
|
|
452
|
+
params.push(updates.name);
|
|
453
|
+
}
|
|
454
|
+
if (updates.description !== undefined) {
|
|
455
|
+
setClauses.push('description = ?');
|
|
456
|
+
params.push(updates.description);
|
|
457
|
+
}
|
|
458
|
+
if (updates.tags !== undefined) {
|
|
459
|
+
setClauses.push('tags = ?');
|
|
460
|
+
params.push(JSON.stringify(updates.tags));
|
|
461
|
+
}
|
|
462
|
+
if (updates.messageCount !== undefined) {
|
|
463
|
+
setClauses.push('message_count = ?');
|
|
464
|
+
params.push(updates.messageCount);
|
|
465
|
+
}
|
|
466
|
+
if (setClauses.length === 0) {
|
|
467
|
+
return await loadChatData(ctx, worldId, chatId);
|
|
468
|
+
}
|
|
469
|
+
setClauses.push('updated_at = CURRENT_TIMESTAMP');
|
|
470
|
+
params.push(chatId, worldId);
|
|
471
|
+
await run(ctx, `
|
|
472
|
+
UPDATE world_chats
|
|
473
|
+
SET ${setClauses.join(', ')}
|
|
474
|
+
WHERE id = ? AND world_id = ?
|
|
475
|
+
`, ...params);
|
|
476
|
+
return await loadChatData(ctx, worldId, chatId);
|
|
477
|
+
}
|
|
478
|
+
export async function updateChatNameIfCurrent(ctx, worldId, chatId, expectedName, nextName) {
|
|
479
|
+
await ensureInitialized(ctx);
|
|
480
|
+
const result = await run(ctx, `
|
|
481
|
+
UPDATE world_chats
|
|
482
|
+
SET name = ?, updated_at = CURRENT_TIMESTAMP
|
|
483
|
+
WHERE id = ? AND world_id = ? AND name = ?
|
|
484
|
+
`, nextName, chatId, worldId, expectedName);
|
|
485
|
+
return (result.changes || 0) > 0;
|
|
486
|
+
}
|
|
487
|
+
// CHAT OPERATIONS
|
|
488
|
+
export async function saveWorldChat(ctx, worldId, chatId, chat) {
|
|
489
|
+
await ensureInitialized(ctx);
|
|
490
|
+
await run(ctx, `
|
|
491
|
+
INSERT INTO chat_snapshots (chat_id, world_id, snapshot_data, version)
|
|
492
|
+
VALUES (?, ?, ?, ?)
|
|
493
|
+
`, chatId, worldId, JSON.stringify(chat), chat.metadata?.version || '1.0');
|
|
494
|
+
}
|
|
495
|
+
export async function loadWorldChatFull(ctx, worldId, chatId) {
|
|
496
|
+
await ensureInitialized(ctx);
|
|
497
|
+
// Get the chat metadata
|
|
498
|
+
const result = await get(ctx, `
|
|
499
|
+
SELECT id, name, description, message_count as messageCount,
|
|
500
|
+
tags, created_at as createdAt, updated_at as updatedAt
|
|
501
|
+
FROM world_chats
|
|
502
|
+
WHERE id = ? AND world_id = ?
|
|
503
|
+
`, chatId, worldId);
|
|
504
|
+
if (!result)
|
|
505
|
+
return null;
|
|
506
|
+
// Get the chat snapshot data
|
|
507
|
+
const chat = await get(ctx, `
|
|
508
|
+
SELECT snapshot_data as snapshotData, captured_at as capturedAt, version
|
|
509
|
+
FROM chat_snapshots
|
|
510
|
+
WHERE chat_id = ? AND world_id = ?
|
|
511
|
+
ORDER BY captured_at DESC
|
|
512
|
+
LIMIT 1
|
|
513
|
+
`, chatId, worldId);
|
|
514
|
+
if (!chat)
|
|
515
|
+
return null; // No snapshot data found
|
|
516
|
+
const snapshotData = JSON.parse(chat.snapshotData);
|
|
517
|
+
// Return merged WorldChat with snapshot fields accessible directly
|
|
518
|
+
// This matches the web interface expectation
|
|
519
|
+
return {
|
|
520
|
+
// Chat metadata (ChatInfo + worldId)
|
|
521
|
+
id: result.id,
|
|
522
|
+
worldId: worldId,
|
|
523
|
+
name: result.name,
|
|
524
|
+
description: result.description,
|
|
525
|
+
createdAt: new Date(result.createdAt),
|
|
526
|
+
updatedAt: new Date(result.updatedAt),
|
|
527
|
+
messageCount: result.messageCount,
|
|
528
|
+
tags: JSON.parse(result.tags || '[]'),
|
|
529
|
+
// Snapshot data (core WorldChat fields)
|
|
530
|
+
world: snapshotData.world,
|
|
531
|
+
agents: snapshotData.agents,
|
|
532
|
+
messages: snapshotData.messages,
|
|
533
|
+
metadata: {
|
|
534
|
+
...snapshotData.metadata,
|
|
535
|
+
capturedAt: new Date(chat.capturedAt),
|
|
536
|
+
version: chat.version
|
|
537
|
+
}
|
|
538
|
+
}; // Use 'as any' since this is a merged type that differs between web and core
|
|
539
|
+
}
|
|
540
|
+
export async function loadWorldChat(ctx, worldId, chatId) {
|
|
541
|
+
await ensureInitialized(ctx);
|
|
542
|
+
const result = await get(ctx, `
|
|
543
|
+
SELECT snapshot_data as snapshotData, captured_at as capturedAt, version
|
|
544
|
+
FROM chat_snapshots
|
|
545
|
+
WHERE chat_id = ? AND world_id = ?
|
|
546
|
+
ORDER BY captured_at DESC
|
|
547
|
+
LIMIT 1
|
|
548
|
+
`, chatId, worldId);
|
|
549
|
+
if (!result)
|
|
550
|
+
return null;
|
|
551
|
+
const chat = JSON.parse(result.snapshotData);
|
|
552
|
+
return {
|
|
553
|
+
...chat,
|
|
554
|
+
metadata: {
|
|
555
|
+
...chat.metadata,
|
|
556
|
+
capturedAt: new Date(result.capturedAt),
|
|
557
|
+
version: result.version
|
|
558
|
+
}
|
|
559
|
+
};
|
|
560
|
+
}
|
|
561
|
+
export async function restoreFromWorldChat(ctx, worldId, chat) {
|
|
562
|
+
await ensureInitialized(ctx);
|
|
563
|
+
try {
|
|
564
|
+
// Begin transaction for atomic restore
|
|
565
|
+
await run(ctx, 'BEGIN TRANSACTION');
|
|
566
|
+
// Restore world data
|
|
567
|
+
if (chat.world) {
|
|
568
|
+
await run(ctx, `
|
|
569
|
+
UPDATE worlds
|
|
570
|
+
SET name = ?, description = ?, turn_limit = ?, main_agent = ?, chat_llm_provider = ?, chat_llm_model = ?
|
|
571
|
+
WHERE id = ?
|
|
572
|
+
`, chat.world.name, chat.world.description, chat.world.turnLimit, chat.world.mainAgent, chat.world.chatLLMProvider, chat.world.chatLLMModel, worldId);
|
|
573
|
+
}
|
|
574
|
+
// Clear existing agents for this world
|
|
575
|
+
await run(ctx, 'DELETE FROM agents WHERE world_id = ?', worldId);
|
|
576
|
+
// Restore agents
|
|
577
|
+
if (chat.agents && chat.agents.length > 0) {
|
|
578
|
+
for (const agent of chat.agents) {
|
|
579
|
+
await run(ctx, `
|
|
580
|
+
INSERT INTO agents (
|
|
581
|
+
id, world_id, name, type, status, provider, model, system_prompt,
|
|
582
|
+
temperature, max_tokens, auto_reply, created_at, last_active, llm_call_count, last_llm_call
|
|
583
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
584
|
+
`, agent.id, worldId, agent.name, agent.type, agent.status || 'active', agent.provider, agent.model, agent.systemPrompt, agent.temperature, agent.maxTokens, agent.autoReply === false ? 0 : 1, agent.createdAt instanceof Date ? agent.createdAt.toISOString() : agent.createdAt, agent.lastActive instanceof Date ? agent.lastActive.toISOString() : agent.lastActive, agent.llmCallCount || 0, agent.lastLLMCall instanceof Date ? agent.lastLLMCall.toISOString() : agent.lastLLMCall);
|
|
585
|
+
// Clear and restore agent memory
|
|
586
|
+
await run(ctx, 'DELETE FROM agent_memory WHERE agent_id = ? AND world_id = ?', agent.id, worldId);
|
|
587
|
+
if (agent.memory && agent.memory.length > 0) {
|
|
588
|
+
for (const message of agent.memory) {
|
|
589
|
+
await run(ctx, `
|
|
590
|
+
INSERT INTO agent_memory (agent_id, world_id, role, content, sender, chat_id, message_id, reply_to_message_id, tool_calls, tool_call_id, created_at)
|
|
591
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
592
|
+
`, agent.id, worldId, message.role, message.content, message.sender, message.chatId, message.messageId, message.replyToMessageId, message.tool_calls ? JSON.stringify(message.tool_calls) : null, message.tool_call_id || null, message.createdAt instanceof Date ? message.createdAt.toISOString() : (message.createdAt || new Date().toISOString()));
|
|
593
|
+
}
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
await run(ctx, 'COMMIT');
|
|
598
|
+
return true;
|
|
599
|
+
}
|
|
600
|
+
catch (error) {
|
|
601
|
+
await run(ctx, 'ROLLBACK');
|
|
602
|
+
console.error('[sqlite-storage] Failed to restore from world chat:', error);
|
|
603
|
+
return false;
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
// ARCHIVE OPERATIONS
|
|
607
|
+
export async function archiveAgentMemory(ctx, worldId, agentId, memory, metadata) {
|
|
608
|
+
await ensureInitialized(ctx);
|
|
609
|
+
const participants = metadata?.participants || [...new Set(memory.map(m => m.sender).filter(Boolean))];
|
|
610
|
+
const firstMessage = memory.length > 0 ? memory[0] : null;
|
|
611
|
+
const lastMessage = memory.length > 0 ? memory[memory.length - 1] : null;
|
|
612
|
+
const startTime = metadata?.startTime || (firstMessage?.createdAt ? (firstMessage.createdAt instanceof Date ? firstMessage.createdAt.toISOString() : firstMessage.createdAt) : new Date().toISOString());
|
|
613
|
+
const endTime = metadata?.endTime || (lastMessage?.createdAt ? (lastMessage.createdAt instanceof Date ? lastMessage.createdAt.toISOString() : lastMessage.createdAt) : new Date().toISOString());
|
|
614
|
+
const archiveResult = await run(ctx, `
|
|
615
|
+
INSERT INTO memory_archives (
|
|
616
|
+
agent_id, world_id, session_name, archive_reason, message_count,
|
|
617
|
+
start_time, end_time, participants, tags
|
|
618
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
619
|
+
`, agentId, worldId, metadata?.sessionName, metadata?.archiveReason, memory.length, startTime, endTime, JSON.stringify(participants), JSON.stringify(metadata?.tags || []));
|
|
620
|
+
const archiveId = archiveResult.lastID;
|
|
621
|
+
for (const message of memory) {
|
|
622
|
+
await run(ctx, `
|
|
623
|
+
INSERT INTO archived_messages (
|
|
624
|
+
archive_id, role, content, sender, original_created_at
|
|
625
|
+
) VALUES (?, ?, ?, ?, ?)
|
|
626
|
+
`, archiveId, message.role, message.content, message.sender, message.createdAt instanceof Date ? message.createdAt.toISOString() : (message.createdAt || new Date().toISOString()));
|
|
627
|
+
}
|
|
628
|
+
return archiveId;
|
|
629
|
+
}
|
|
630
|
+
// SEARCH AND STATS
|
|
631
|
+
export async function searchArchives(ctx, options) {
|
|
632
|
+
await ensureInitialized(ctx);
|
|
633
|
+
const archives = await all(ctx, `
|
|
634
|
+
SELECT id, agent_id as agentId, world_id as worldId,
|
|
635
|
+
session_name as sessionName, archive_reason as archiveReason,
|
|
636
|
+
message_count as messageCount, start_time as startTime,
|
|
637
|
+
end_time as endTime, participants, tags,
|
|
638
|
+
created_at as createdAt
|
|
639
|
+
FROM memory_archives
|
|
640
|
+
WHERE world_id = ?
|
|
641
|
+
ORDER BY created_at DESC
|
|
642
|
+
LIMIT 50
|
|
643
|
+
`, options.worldId || '');
|
|
644
|
+
const result = archives.map(archive => ({
|
|
645
|
+
...archive,
|
|
646
|
+
startTime: archive.startTime ? new Date(archive.startTime) : undefined,
|
|
647
|
+
endTime: archive.endTime ? new Date(archive.endTime) : undefined,
|
|
648
|
+
participants: JSON.parse(archive.participants || '[]'),
|
|
649
|
+
tags: JSON.parse(archive.tags || '[]'),
|
|
650
|
+
createdAt: new Date(archive.createdAt)
|
|
651
|
+
}));
|
|
652
|
+
return {
|
|
653
|
+
archives: result,
|
|
654
|
+
totalCount: result.length,
|
|
655
|
+
hasMore: false
|
|
656
|
+
};
|
|
657
|
+
}
|
|
658
|
+
export async function getArchiveStatistics(ctx, worldId, agentId) {
|
|
659
|
+
await ensureInitialized(ctx);
|
|
660
|
+
const basicStats = await get(ctx, `
|
|
661
|
+
SELECT COUNT(*) as totalArchives,
|
|
662
|
+
SUM(message_count) as totalMessages,
|
|
663
|
+
AVG(message_count) as averageSessionLength
|
|
664
|
+
FROM memory_archives
|
|
665
|
+
WHERE world_id = ?
|
|
666
|
+
`, worldId);
|
|
667
|
+
return {
|
|
668
|
+
totalArchives: basicStats?.totalArchives || 0,
|
|
669
|
+
totalMessages: basicStats?.totalMessages || 0,
|
|
670
|
+
averageSessionLength: basicStats?.averageSessionLength || 0,
|
|
671
|
+
mostActiveAgent: '',
|
|
672
|
+
archiveFrequency: {}
|
|
673
|
+
};
|
|
674
|
+
}
|
|
675
|
+
export async function exportArchive(ctx, archiveId, options) {
|
|
676
|
+
await ensureInitialized(ctx);
|
|
677
|
+
const archive = await get(ctx, `
|
|
678
|
+
SELECT * FROM memory_archives WHERE id = ?
|
|
679
|
+
`, archiveId);
|
|
680
|
+
if (!archive)
|
|
681
|
+
throw new Error('Archive not found');
|
|
682
|
+
let messages = [];
|
|
683
|
+
if (options.includeMessages) {
|
|
684
|
+
messages = await all(ctx, `
|
|
685
|
+
SELECT role, content, sender, original_created_at as createdAt
|
|
686
|
+
FROM archived_messages
|
|
687
|
+
WHERE archive_id = ?
|
|
688
|
+
ORDER BY id ASC
|
|
689
|
+
`, archiveId);
|
|
690
|
+
}
|
|
691
|
+
const exportData = {
|
|
692
|
+
metadata: options.includeMetadata ? {
|
|
693
|
+
id: archive.id,
|
|
694
|
+
agentId: archive.agent_id,
|
|
695
|
+
worldId: archive.world_id,
|
|
696
|
+
sessionName: archive.session_name,
|
|
697
|
+
createdAt: archive.created_at
|
|
698
|
+
} : undefined,
|
|
699
|
+
messages: options.includeMessages ? messages : undefined
|
|
700
|
+
};
|
|
701
|
+
return JSON.stringify(exportData, null, 2);
|
|
702
|
+
}
|
|
703
|
+
export async function close(ctx) {
|
|
704
|
+
return closeSchema(ctx.schemaCtx);
|
|
705
|
+
}
|
|
706
|
+
export async function getDatabaseStats(ctx) {
|
|
707
|
+
return schemaGetDatabaseStats(ctx.schemaCtx);
|
|
708
|
+
}
|
|
709
|
+
//# sourceMappingURL=sqlite-storage.js.map
|