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,378 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* World Storage Module - File I/O Operations for World Data and Chat Operations
|
|
3
|
+
*
|
|
4
|
+
* Logger Category: storage.query
|
|
5
|
+
* Purpose: World and chat data file I/O operations
|
|
6
|
+
*
|
|
7
|
+
* Enable with: LOG_STORAGE_QUERY=debug npm run server
|
|
8
|
+
*
|
|
9
|
+
* What you'll see:
|
|
10
|
+
* - World config saves and loads
|
|
11
|
+
* - Chat data operations
|
|
12
|
+
* - Memory aggregation queries
|
|
13
|
+
* - File operation errors
|
|
14
|
+
*
|
|
15
|
+
* Features:
|
|
16
|
+
* - World configuration persistence to config.json with flattened structure
|
|
17
|
+
* - Complete chat operations with file-based storage (chats directory)
|
|
18
|
+
* - Cross-agent memory aggregation for world-level chat sessions
|
|
19
|
+
* - Kebab-case directory naming from world names
|
|
20
|
+
* - Clean separation of storage data from runtime objects
|
|
21
|
+
* - Handles World serialization without EventEmitter and agents Map
|
|
22
|
+
* - Complete isolation from other internal modules
|
|
23
|
+
* - Explicit rootPath parameter handling (no environment variables)
|
|
24
|
+
* - Cascade deletion for data integrity (world → agents/chats, chat → messages)
|
|
25
|
+
*
|
|
26
|
+
* Core Functions:
|
|
27
|
+
* - saveWorld: Save world config.json with flat structure (excludes runtime properties: eventEmitter, agents, chats, eventStorage, _eventPersistenceCleanup)
|
|
28
|
+
* - loadWorld: Load world configuration from file
|
|
29
|
+
* - deleteWorld: Remove world directory and all contents (cascades to agents and chats)
|
|
30
|
+
* - listWorlds: Scan and load all worlds in root directory
|
|
31
|
+
* - worldExists: Check if world directory exists
|
|
32
|
+
*
|
|
33
|
+
* Changes:
|
|
34
|
+
* - 2026-02-13: Added compare-and-set chat title helper (`updateChatNameIfCurrent`) for safer concurrent title commits.
|
|
35
|
+
* - 2025-11-01: Explicitly exclude runtime properties (eventEmitter, agents, chats, eventStorage, _eventPersistenceCleanup) from saveWorld
|
|
36
|
+
* - getWorldDir: Get world directory path
|
|
37
|
+
* - ensureWorldDirectory: Create world directory structure
|
|
38
|
+
*
|
|
39
|
+
* Chat Functions:
|
|
40
|
+
* - saveChatData: Save complete chat data with metadata and content
|
|
41
|
+
* - loadChatData: Load complete chat data with Date reconstruction
|
|
42
|
+
* - deleteChatData: Remove chat files and cascade delete associated messages from agent memory
|
|
43
|
+
* - listChatHistories: List all chat metadata for a world
|
|
44
|
+
* - updateChatData: Update existing chat with partial data
|
|
45
|
+
* - getMemory: Aggregate memory across all agents for chat sessions
|
|
46
|
+
*
|
|
47
|
+
* Version: 2.1.0 - Added cascade deletion for chat operations
|
|
48
|
+
* Date: 2025-10-30
|
|
49
|
+
* Version: 2.2.0 - Updated to structured logging (storage.query)
|
|
50
|
+
* Date: 2025-10-31
|
|
51
|
+
*/
|
|
52
|
+
import { promises as fs } from 'fs';
|
|
53
|
+
import * as path from 'path';
|
|
54
|
+
import { toKebabCase } from '../utils.js';
|
|
55
|
+
import { createCategoryLogger } from '../logger.js';
|
|
56
|
+
import { listAgents, loadAgent, deleteMemoryByChatId } from './agent-storage.js';
|
|
57
|
+
const logger = createCategoryLogger('storage.query');
|
|
58
|
+
// Extract readdir and exists from fs for convenience
|
|
59
|
+
const { readdir, access } = fs;
|
|
60
|
+
const exists = async (path) => {
|
|
61
|
+
try {
|
|
62
|
+
await access(path);
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
/**
|
|
70
|
+
* File utility functions
|
|
71
|
+
*/
|
|
72
|
+
async function writeJsonFile(filePath, data) {
|
|
73
|
+
await fs.writeFile(filePath, JSON.stringify(data, null, 2), 'utf8');
|
|
74
|
+
}
|
|
75
|
+
async function readJsonFile(filePath) {
|
|
76
|
+
const content = await fs.readFile(filePath, 'utf8');
|
|
77
|
+
return JSON.parse(content);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* World directory and file path utilities
|
|
81
|
+
*/
|
|
82
|
+
export function getWorldDir(rootPath, worldId) {
|
|
83
|
+
const normalizedWorldId = toKebabCase(worldId);
|
|
84
|
+
return path.join(rootPath, normalizedWorldId);
|
|
85
|
+
}
|
|
86
|
+
export async function ensureWorldDirectory(root, worldId) {
|
|
87
|
+
const worldDir = getWorldDir(root, worldId);
|
|
88
|
+
await fs.mkdir(worldDir, { recursive: true });
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Check if world exists on disk
|
|
92
|
+
*/
|
|
93
|
+
export async function worldExists(root, worldId) {
|
|
94
|
+
try {
|
|
95
|
+
const worldDir = getWorldDir(root, worldId);
|
|
96
|
+
const configPath = path.join(worldDir, 'config.json');
|
|
97
|
+
await fs.access(configPath);
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Save world to disk
|
|
106
|
+
*/
|
|
107
|
+
export async function saveWorld(root, worldData) {
|
|
108
|
+
await ensureWorldDirectory(root, worldData.id);
|
|
109
|
+
const worldDir = getWorldDir(root, worldData.id);
|
|
110
|
+
const configPath = path.join(worldDir, 'config.json');
|
|
111
|
+
const mcpConfigPath = path.join(worldDir, 'mcp.json');
|
|
112
|
+
// Exclude runtime properties and mcpConfig from config.json
|
|
113
|
+
const { mcpConfig, eventEmitter, agents, chats, eventStorage, _eventPersistenceCleanup, ...configData } = worldData;
|
|
114
|
+
// Save main config without runtime properties
|
|
115
|
+
await writeJsonFile(configPath, configData);
|
|
116
|
+
// Save mcpConfig to separate file if it exists
|
|
117
|
+
if (mcpConfig !== undefined && mcpConfig !== null) {
|
|
118
|
+
try {
|
|
119
|
+
// Validate that mcpConfig is valid JSON
|
|
120
|
+
const parsedConfig = JSON.parse(mcpConfig);
|
|
121
|
+
await writeJsonFile(mcpConfigPath, parsedConfig);
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
// If mcpConfig is not valid JSON, save it as-is (could be a string)
|
|
125
|
+
await writeJsonFile(mcpConfigPath, { config: mcpConfig });
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
// Remove mcp.json if mcpConfig is null/undefined
|
|
130
|
+
try {
|
|
131
|
+
await fs.unlink(mcpConfigPath);
|
|
132
|
+
}
|
|
133
|
+
catch {
|
|
134
|
+
// File might not exist, ignore error
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Load world from disk
|
|
140
|
+
*/
|
|
141
|
+
export async function loadWorld(root, worldId) {
|
|
142
|
+
try {
|
|
143
|
+
const worldDir = getWorldDir(root, worldId);
|
|
144
|
+
const configPath = path.join(worldDir, 'config.json');
|
|
145
|
+
const mcpConfigPath = path.join(worldDir, 'mcp.json');
|
|
146
|
+
const worldData = await readJsonFile(configPath);
|
|
147
|
+
// Reconstruct Date objects
|
|
148
|
+
if (worldData.createdAt)
|
|
149
|
+
worldData.createdAt = new Date(worldData.createdAt);
|
|
150
|
+
if (worldData.lastUpdated)
|
|
151
|
+
worldData.lastUpdated = new Date(worldData.lastUpdated);
|
|
152
|
+
// Load mcpConfig from separate file if it exists
|
|
153
|
+
try {
|
|
154
|
+
const mcpData = await readJsonFile(mcpConfigPath);
|
|
155
|
+
// If mcpData has a 'config' field, it was stored as a wrapped string
|
|
156
|
+
if (mcpData && typeof mcpData === 'object' && 'config' in mcpData) {
|
|
157
|
+
worldData.mcpConfig = mcpData.config;
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
// Otherwise, stringify the JSON object
|
|
161
|
+
worldData.mcpConfig = JSON.stringify(mcpData);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
catch {
|
|
165
|
+
// mcp.json doesn't exist or can't be read, set to null for backward compatibility
|
|
166
|
+
worldData.mcpConfig = null;
|
|
167
|
+
}
|
|
168
|
+
return worldData;
|
|
169
|
+
}
|
|
170
|
+
catch {
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Delete world from disk
|
|
176
|
+
*/
|
|
177
|
+
export async function deleteWorld(root, worldId) {
|
|
178
|
+
try {
|
|
179
|
+
const worldDir = getWorldDir(root, worldId);
|
|
180
|
+
await fs.rm(worldDir, { recursive: true, force: true });
|
|
181
|
+
return true;
|
|
182
|
+
}
|
|
183
|
+
catch {
|
|
184
|
+
return false;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
/**
|
|
188
|
+
* List all worlds in root directory
|
|
189
|
+
*/
|
|
190
|
+
export async function listWorlds(root) {
|
|
191
|
+
try {
|
|
192
|
+
const entries = await fs.readdir(root, { withFileTypes: true });
|
|
193
|
+
const worlds = [];
|
|
194
|
+
for (const entry of entries) {
|
|
195
|
+
if (entry.isDirectory()) {
|
|
196
|
+
const worldData = await loadWorld(root, entry.name);
|
|
197
|
+
if (worldData) {
|
|
198
|
+
worlds.push(worldData);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
return worlds.sort((a, b) => new Date(b.lastUpdated).getTime() - new Date(a.lastUpdated).getTime());
|
|
203
|
+
}
|
|
204
|
+
catch {
|
|
205
|
+
return [];
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
/**
|
|
209
|
+
* Chat directory and file path utilities
|
|
210
|
+
*/
|
|
211
|
+
export function getChatDir(rootPath, worldId) {
|
|
212
|
+
const worldDir = getWorldDir(rootPath, worldId);
|
|
213
|
+
return path.join(worldDir, 'chats');
|
|
214
|
+
}
|
|
215
|
+
export function getChatFilePath(rootPath, worldId, chatId) {
|
|
216
|
+
const chatDir = getChatDir(rootPath, worldId);
|
|
217
|
+
return path.join(chatDir, `${chatId}.json`);
|
|
218
|
+
}
|
|
219
|
+
export async function ensureChatDirectory(rootPath, worldId) {
|
|
220
|
+
const chatDir = getChatDir(rootPath, worldId);
|
|
221
|
+
await fs.mkdir(chatDir, { recursive: true });
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Save chat data (metadata + content) to disk
|
|
225
|
+
*/
|
|
226
|
+
export async function saveChatData(rootPath, worldId, chatData) {
|
|
227
|
+
await ensureChatDirectory(rootPath, worldId);
|
|
228
|
+
// Save the complete ChatData object
|
|
229
|
+
const chatPath = getChatFilePath(rootPath, worldId, chatData.id);
|
|
230
|
+
await writeJsonFile(chatPath, chatData);
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Load chat data (metadata + content) from disk
|
|
234
|
+
*/
|
|
235
|
+
export async function loadChatData(rootPath, worldId, chatId) {
|
|
236
|
+
try {
|
|
237
|
+
const chatPath = getChatFilePath(rootPath, worldId, chatId);
|
|
238
|
+
const chatData = await readJsonFile(chatPath);
|
|
239
|
+
// Reconstruct Date objects
|
|
240
|
+
if (chatData.createdAt)
|
|
241
|
+
chatData.createdAt = new Date(chatData.createdAt);
|
|
242
|
+
if (chatData.updatedAt)
|
|
243
|
+
chatData.updatedAt = new Date(chatData.updatedAt);
|
|
244
|
+
return chatData;
|
|
245
|
+
}
|
|
246
|
+
catch (error) {
|
|
247
|
+
logger.error('Failed to load chat data', {
|
|
248
|
+
error: error instanceof Error ? error.message : String(error),
|
|
249
|
+
worldId,
|
|
250
|
+
chatId
|
|
251
|
+
});
|
|
252
|
+
return null;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Update chat data on disk
|
|
257
|
+
*/
|
|
258
|
+
export async function updateChatData(rootPath, worldId, chatId, updates) {
|
|
259
|
+
const chatData = await loadChatData(rootPath, worldId, chatId);
|
|
260
|
+
if (!chatData)
|
|
261
|
+
return null;
|
|
262
|
+
// Apply updates to metadata
|
|
263
|
+
if (updates.name !== undefined)
|
|
264
|
+
chatData.name = updates.name;
|
|
265
|
+
if (updates.description !== undefined)
|
|
266
|
+
chatData.description = updates.description;
|
|
267
|
+
// Update timestamps
|
|
268
|
+
chatData.updatedAt = new Date();
|
|
269
|
+
await saveChatData(rootPath, worldId, chatData);
|
|
270
|
+
return chatData;
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Compare-and-set chat name on disk.
|
|
274
|
+
* Updates name only when the current name exactly matches expectedName.
|
|
275
|
+
*/
|
|
276
|
+
export async function updateChatNameIfCurrent(rootPath, worldId, chatId, expectedName, nextName) {
|
|
277
|
+
const chatData = await loadChatData(rootPath, worldId, chatId);
|
|
278
|
+
if (!chatData)
|
|
279
|
+
return false;
|
|
280
|
+
if (chatData.name !== expectedName)
|
|
281
|
+
return false;
|
|
282
|
+
chatData.name = nextName;
|
|
283
|
+
chatData.updatedAt = new Date();
|
|
284
|
+
await saveChatData(rootPath, worldId, chatData);
|
|
285
|
+
return true;
|
|
286
|
+
}
|
|
287
|
+
/**
|
|
288
|
+
* Delete chat data from disk with cascade deletion of associated messages
|
|
289
|
+
*/
|
|
290
|
+
export async function deleteChatData(rootPath, worldId, chatId) {
|
|
291
|
+
try {
|
|
292
|
+
// Delete the chat file
|
|
293
|
+
const chatPath = getChatFilePath(rootPath, worldId, chatId);
|
|
294
|
+
await fs.unlink(chatPath);
|
|
295
|
+
// Cascade delete: Remove all agent memory messages with this chatId
|
|
296
|
+
await deleteMemoryByChatId(rootPath, worldId, chatId);
|
|
297
|
+
return true;
|
|
298
|
+
}
|
|
299
|
+
catch {
|
|
300
|
+
return false;
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* List chat histories (metadata only)
|
|
305
|
+
*/
|
|
306
|
+
export async function listChatHistories(rootPath, worldId) {
|
|
307
|
+
try {
|
|
308
|
+
const chatDir = getChatDir(rootPath, worldId);
|
|
309
|
+
if (!await exists(chatDir)) {
|
|
310
|
+
return [];
|
|
311
|
+
}
|
|
312
|
+
const files = await readdir(chatDir);
|
|
313
|
+
const chatFiles = files.filter((file) => file.endsWith('.json'));
|
|
314
|
+
const chats = [];
|
|
315
|
+
for (const file of chatFiles) {
|
|
316
|
+
const chatId = file.replace('.json', '');
|
|
317
|
+
const chatData = await loadChatData(rootPath, worldId, chatId);
|
|
318
|
+
if (chatData) {
|
|
319
|
+
// Extract just the metadata
|
|
320
|
+
const chatInfo = {
|
|
321
|
+
id: chatData.id,
|
|
322
|
+
worldId: worldId,
|
|
323
|
+
name: chatData.name,
|
|
324
|
+
description: chatData.description,
|
|
325
|
+
createdAt: chatData.createdAt,
|
|
326
|
+
updatedAt: chatData.updatedAt,
|
|
327
|
+
messageCount: chatData.messageCount,
|
|
328
|
+
};
|
|
329
|
+
chats.push(chatInfo);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
return chats.sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime());
|
|
333
|
+
}
|
|
334
|
+
catch (error) {
|
|
335
|
+
logger.error('Failed to list chat histories', {
|
|
336
|
+
error: error instanceof Error ? error.message : String(error),
|
|
337
|
+
worldId
|
|
338
|
+
});
|
|
339
|
+
return [];
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Get aggregated memory across all agents for a given chat
|
|
344
|
+
* Filters messages by chatId and includes agentId for proper message attribution
|
|
345
|
+
*/
|
|
346
|
+
export async function getMemory(rootPath, worldId, chatId) {
|
|
347
|
+
try {
|
|
348
|
+
const agents = await listAgents(rootPath, worldId);
|
|
349
|
+
const messages = [];
|
|
350
|
+
for (const agent of agents) {
|
|
351
|
+
const fullAgent = await loadAgent(rootPath, worldId, agent.id);
|
|
352
|
+
const mem = fullAgent?.memory || [];
|
|
353
|
+
for (const m of mem) {
|
|
354
|
+
if (!chatId || m.chatId === chatId) {
|
|
355
|
+
// Ensure agentId is included in the message
|
|
356
|
+
const messageWithAgentId = { ...m, agentId: agent.id };
|
|
357
|
+
messages.push(messageWithAgentId);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
// Sort by createdAt ascending
|
|
362
|
+
messages.sort((a, b) => {
|
|
363
|
+
const at = a.createdAt ? new Date(a.createdAt).getTime() : 0;
|
|
364
|
+
const bt = b.createdAt ? new Date(b.createdAt).getTime() : 0;
|
|
365
|
+
return at - bt;
|
|
366
|
+
});
|
|
367
|
+
return messages;
|
|
368
|
+
}
|
|
369
|
+
catch (error) {
|
|
370
|
+
logger.error('Failed to get aggregated memory', {
|
|
371
|
+
error: error instanceof Error ? error.message : String(error),
|
|
372
|
+
worldId,
|
|
373
|
+
chatId
|
|
374
|
+
});
|
|
375
|
+
return [];
|
|
376
|
+
}
|
|
377
|
+
}
|
|
378
|
+
//# sourceMappingURL=world-storage.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"world-storage.js","sourceRoot":"","sources":["../../../core/storage/world-storage.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* World Subscription Runtime
|
|
3
|
+
*
|
|
4
|
+
* Features:
|
|
5
|
+
* - Manages world lifecycle subscriptions and realtime event forwarding.
|
|
6
|
+
* - Registers message/world/sse/system listeners for subscribed clients.
|
|
7
|
+
* - Tracks active world runtimes for core operations that need the live emitter.
|
|
8
|
+
*
|
|
9
|
+
* Implementation Notes:
|
|
10
|
+
* - Keeps forwarding listeners optional based on client callback capabilities.
|
|
11
|
+
* - Uses world-id keyed runtime tracking with safe register/unregister semantics.
|
|
12
|
+
*
|
|
13
|
+
* Recent Changes:
|
|
14
|
+
* - 2026-02-14: Added active runtime world tracking and `getActiveSubscribedWorld()` for core edit-message resubmission to publish on live emitters.
|
|
15
|
+
*/
|
|
16
|
+
import { World } from './types.js';
|
|
17
|
+
import { type LogLevel } from './logger.js';
|
|
18
|
+
export interface LogStreamEvent {
|
|
19
|
+
level: LogLevel;
|
|
20
|
+
category: string;
|
|
21
|
+
message: string;
|
|
22
|
+
timestamp: string;
|
|
23
|
+
data?: any;
|
|
24
|
+
messageId: string;
|
|
25
|
+
}
|
|
26
|
+
export interface ClientConnection {
|
|
27
|
+
isOpen: boolean;
|
|
28
|
+
onWorldEvent?: (eventType: string, eventData: any) => void;
|
|
29
|
+
onError?: (error: string) => void;
|
|
30
|
+
onLog?: (logEvent: LogStreamEvent) => void;
|
|
31
|
+
}
|
|
32
|
+
export interface WorldSubscription {
|
|
33
|
+
world: World;
|
|
34
|
+
unsubscribe: () => Promise<void>;
|
|
35
|
+
refresh: () => Promise<World>;
|
|
36
|
+
destroy: () => Promise<void>;
|
|
37
|
+
}
|
|
38
|
+
export declare function getActiveSubscribedWorld(worldIdentifier: string): World | null;
|
|
39
|
+
export declare function startWorld(world: World, client: ClientConnection): Promise<WorldSubscription>;
|
|
40
|
+
export declare function subscribeWorld(worldIdentifier: string, client: ClientConnection): Promise<WorldSubscription | null>;
|
|
41
|
+
export declare function setupWorldEventListeners(world: World, client: ClientConnection): Map<string, (...args: any[]) => void>;
|
|
42
|
+
export declare function cleanupWorldSubscription(world: World, worldEventListeners: Map<string, (...args: any[]) => void>): Promise<void>;
|
|
43
|
+
//# sourceMappingURL=subscription.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subscription.d.ts","sourceRoot":"","sources":["../../core/subscription.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAEnC,OAAO,EAAwB,KAAK,QAAQ,EAAwB,MAAM,aAAa,CAAC;AAYxF,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,QAAQ,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;CACnB;AAGD,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,OAAO,CAAC;IAChB,YAAY,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,KAAK,IAAI,CAAC;IAC3D,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,KAAK,CAAC,EAAE,CAAC,QAAQ,EAAE,cAAc,KAAK,IAAI,CAAC;CAC5C;AAGD,MAAM,WAAW,iBAAiB;IAChC,KAAK,EAAE,KAAK,CAAC;IACb,WAAW,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,OAAO,EAAE,MAAM,OAAO,CAAC,KAAK,CAAC,CAAC;IAC9B,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;CAC9B;AAwBD,wBAAgB,wBAAwB,CAAC,eAAe,EAAE,MAAM,GAAG,KAAK,GAAG,IAAI,CAW9E;AAGD,wBAAsB,UAAU,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,gBAAgB,GAAG,OAAO,CAAC,iBAAiB,CAAC,CAwFnG;AAGD,wBAAsB,cAAc,CAClC,eAAe,EAAE,MAAM,EACvB,MAAM,EAAE,gBAAgB,GACvB,OAAO,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAmCnC;AAGD,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,gBAAgB,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC,CAiDtH;AAGD,wBAAsB,wBAAwB,CAAC,KAAK,EAAE,KAAK,EAAE,mBAAmB,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAetI"}
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* World Subscription Runtime
|
|
3
|
+
*
|
|
4
|
+
* Features:
|
|
5
|
+
* - Manages world lifecycle subscriptions and realtime event forwarding.
|
|
6
|
+
* - Registers message/world/sse/system listeners for subscribed clients.
|
|
7
|
+
* - Tracks active world runtimes for core operations that need the live emitter.
|
|
8
|
+
*
|
|
9
|
+
* Implementation Notes:
|
|
10
|
+
* - Keeps forwarding listeners optional based on client callback capabilities.
|
|
11
|
+
* - Uses world-id keyed runtime tracking with safe register/unregister semantics.
|
|
12
|
+
*
|
|
13
|
+
* Recent Changes:
|
|
14
|
+
* - 2026-02-14: Added active runtime world tracking and `getActiveSubscribedWorld()` for core edit-message resubmission to publish on live emitters.
|
|
15
|
+
*/
|
|
16
|
+
import { getWorld } from './managers.js';
|
|
17
|
+
import { createCategoryLogger, addLogStreamCallback } from './logger.js';
|
|
18
|
+
import { subscribeAgentToMessages, subscribeWorldToMessages } from './events/index.js';
|
|
19
|
+
function toKebabCase(name) {
|
|
20
|
+
return name.toLowerCase().replace(/[^a-z0-9]/g, '-').replace(/-+/g, '-').replace(/^-|-$/g, '');
|
|
21
|
+
}
|
|
22
|
+
// Create subscription category logger (part of core functionality)
|
|
23
|
+
const logger = createCategoryLogger('world.subscription');
|
|
24
|
+
const activeSubscribedWorlds = new Map();
|
|
25
|
+
function registerActiveSubscribedWorld(world) {
|
|
26
|
+
const worldId = String(world?.id || '').trim();
|
|
27
|
+
if (!worldId)
|
|
28
|
+
return;
|
|
29
|
+
const existing = activeSubscribedWorlds.get(worldId) ?? new Set();
|
|
30
|
+
existing.add(world);
|
|
31
|
+
activeSubscribedWorlds.set(worldId, existing);
|
|
32
|
+
}
|
|
33
|
+
function unregisterActiveSubscribedWorld(world) {
|
|
34
|
+
const worldId = String(world?.id || '').trim();
|
|
35
|
+
if (!worldId)
|
|
36
|
+
return;
|
|
37
|
+
const existing = activeSubscribedWorlds.get(worldId);
|
|
38
|
+
if (!existing)
|
|
39
|
+
return;
|
|
40
|
+
existing.delete(world);
|
|
41
|
+
if (existing.size === 0) {
|
|
42
|
+
activeSubscribedWorlds.delete(worldId);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
export function getActiveSubscribedWorld(worldIdentifier) {
|
|
46
|
+
const resolvedWorldId = toKebabCase(String(worldIdentifier || '').trim());
|
|
47
|
+
if (!resolvedWorldId)
|
|
48
|
+
return null;
|
|
49
|
+
const activeWorldSet = activeSubscribedWorlds.get(resolvedWorldId);
|
|
50
|
+
if (!activeWorldSet || activeWorldSet.size === 0)
|
|
51
|
+
return null;
|
|
52
|
+
for (const world of activeWorldSet.values()) {
|
|
53
|
+
return world;
|
|
54
|
+
}
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
// Start world with event listeners - extracted from subscribeWorld
|
|
58
|
+
export async function startWorld(world, client) {
|
|
59
|
+
// Only set up forwarding listeners when the client actually wants them.
|
|
60
|
+
let worldEventListeners = new Map();
|
|
61
|
+
if (client && (client.onWorldEvent || client.onLog)) {
|
|
62
|
+
worldEventListeners = setupWorldEventListeners(world, client);
|
|
63
|
+
}
|
|
64
|
+
let currentWorld = world;
|
|
65
|
+
registerActiveSubscribedWorld(currentWorld);
|
|
66
|
+
// Subscribe all loaded agents to world messages (moved from getFullWorld)
|
|
67
|
+
for (const agent of currentWorld.agents.values()) {
|
|
68
|
+
subscribeAgentToMessages(currentWorld, agent);
|
|
69
|
+
}
|
|
70
|
+
subscribeWorldToMessages(currentWorld);
|
|
71
|
+
// Helper function to destroy current world instance
|
|
72
|
+
const destroyCurrentWorld = async () => {
|
|
73
|
+
if (currentWorld) {
|
|
74
|
+
unregisterActiveSubscribedWorld(currentWorld);
|
|
75
|
+
// Clean up all event listeners
|
|
76
|
+
await cleanupWorldSubscription(currentWorld, worldEventListeners);
|
|
77
|
+
// Remove all listeners from the EventEmitter to prevent memory leaks
|
|
78
|
+
currentWorld.eventEmitter.removeAllListeners();
|
|
79
|
+
// Clear agents map references
|
|
80
|
+
currentWorld.agents.clear();
|
|
81
|
+
logger.debug('World instance destroyed', { worldId: currentWorld.id });
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
// Return subscription object with cleanup methods
|
|
85
|
+
return {
|
|
86
|
+
get world() {
|
|
87
|
+
if (!currentWorld) {
|
|
88
|
+
throw new Error('World subscription has been destroyed');
|
|
89
|
+
}
|
|
90
|
+
return currentWorld;
|
|
91
|
+
},
|
|
92
|
+
unsubscribe: async () => {
|
|
93
|
+
await destroyCurrentWorld();
|
|
94
|
+
currentWorld = null;
|
|
95
|
+
},
|
|
96
|
+
destroy: async () => {
|
|
97
|
+
await destroyCurrentWorld();
|
|
98
|
+
currentWorld = null;
|
|
99
|
+
},
|
|
100
|
+
refresh: async () => {
|
|
101
|
+
const worldId = currentWorld?.id || '';
|
|
102
|
+
logger.debug('Refreshing world subscription', { worldId });
|
|
103
|
+
// Destroy the old world instance completely
|
|
104
|
+
await destroyCurrentWorld();
|
|
105
|
+
// Create a completely new world instance
|
|
106
|
+
const refreshedWorld = await getWorld(worldId);
|
|
107
|
+
if (!refreshedWorld) {
|
|
108
|
+
throw new Error(`Failed to refresh world: ${worldId}`);
|
|
109
|
+
}
|
|
110
|
+
// Update current references
|
|
111
|
+
currentWorld = refreshedWorld;
|
|
112
|
+
registerActiveSubscribedWorld(currentWorld);
|
|
113
|
+
// Set up new event listeners on the fresh world only if client wants forwarding
|
|
114
|
+
if (client && (client.onWorldEvent || client.onLog)) {
|
|
115
|
+
worldEventListeners = setupWorldEventListeners(currentWorld, client);
|
|
116
|
+
}
|
|
117
|
+
else {
|
|
118
|
+
worldEventListeners = new Map();
|
|
119
|
+
}
|
|
120
|
+
// Subscribe all loaded agents to world messages (moved from getFullWorld)
|
|
121
|
+
for (const agent of currentWorld.agents.values()) {
|
|
122
|
+
subscribeAgentToMessages(currentWorld, agent);
|
|
123
|
+
}
|
|
124
|
+
logger.debug('World subscription refreshed', {
|
|
125
|
+
worldId: currentWorld.id,
|
|
126
|
+
agentCount: currentWorld.agents.size
|
|
127
|
+
});
|
|
128
|
+
return currentWorld;
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
// World subscription management
|
|
133
|
+
export async function subscribeWorld(worldIdentifier, client) {
|
|
134
|
+
try {
|
|
135
|
+
// Load world using core manager (convert to kebab-case internally)
|
|
136
|
+
const worldId = toKebabCase(worldIdentifier);
|
|
137
|
+
const currentWorld = await getWorld(worldId);
|
|
138
|
+
if (!currentWorld) {
|
|
139
|
+
if (client.onError) {
|
|
140
|
+
client.onError(`World not found: ${worldIdentifier}`);
|
|
141
|
+
}
|
|
142
|
+
return null;
|
|
143
|
+
}
|
|
144
|
+
// MCP servers will be started on-demand in getMCPToolsForWorld()
|
|
145
|
+
if (currentWorld.mcpConfig) {
|
|
146
|
+
logger.debug(`World ${worldId} has MCP config - servers will start on-demand`);
|
|
147
|
+
}
|
|
148
|
+
// Use startWorld function to create the subscription
|
|
149
|
+
const subscription = await startWorld(currentWorld, client);
|
|
150
|
+
// MCP servers use connection pooling and will be cleaned up automatically
|
|
151
|
+
// when the Express app shuts down
|
|
152
|
+
return subscription;
|
|
153
|
+
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
logger.error('World subscription failed', {
|
|
156
|
+
worldIdentifier,
|
|
157
|
+
error: error instanceof Error ? error.message : error
|
|
158
|
+
});
|
|
159
|
+
if (client.onError) {
|
|
160
|
+
client.onError(`Failed to subscribe to world: ${error instanceof Error ? error.message : error}`);
|
|
161
|
+
}
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
// Set up event listeners for world events with client connection forwarding
|
|
166
|
+
export function setupWorldEventListeners(world, client) {
|
|
167
|
+
const listeners = new Map();
|
|
168
|
+
// System events
|
|
169
|
+
const systemListener = (eventData) => {
|
|
170
|
+
if (client.onWorldEvent) {
|
|
171
|
+
client.onWorldEvent('system', eventData);
|
|
172
|
+
}
|
|
173
|
+
};
|
|
174
|
+
world.eventEmitter.on('system', systemListener);
|
|
175
|
+
listeners.set('system', systemListener);
|
|
176
|
+
// Message events
|
|
177
|
+
const messageListener = (eventData) => {
|
|
178
|
+
if (client.onWorldEvent) {
|
|
179
|
+
client.onWorldEvent('message', eventData);
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
world.eventEmitter.on('message', messageListener);
|
|
183
|
+
listeners.set('message', messageListener);
|
|
184
|
+
// SSE events
|
|
185
|
+
const sseListener = (eventData) => {
|
|
186
|
+
if (client.onWorldEvent) {
|
|
187
|
+
client.onWorldEvent('sse', eventData);
|
|
188
|
+
}
|
|
189
|
+
};
|
|
190
|
+
world.eventEmitter.on('sse', sseListener);
|
|
191
|
+
listeners.set('sse', sseListener);
|
|
192
|
+
// World events (includes activity tracking)
|
|
193
|
+
// Note: 'world' channel receives WorldActivityEventPayload for activity tracking
|
|
194
|
+
const worldActivityListener = (eventData) => {
|
|
195
|
+
if (client.onWorldEvent) {
|
|
196
|
+
client.onWorldEvent('world', eventData);
|
|
197
|
+
}
|
|
198
|
+
};
|
|
199
|
+
world.eventEmitter.on('world', worldActivityListener);
|
|
200
|
+
listeners.set('world', worldActivityListener);
|
|
201
|
+
// Log streaming - set up if client has onLog callback
|
|
202
|
+
if (client.onLog) {
|
|
203
|
+
const logUnsubscribe = addLogStreamCallback((logEvent) => {
|
|
204
|
+
client.onLog(logEvent);
|
|
205
|
+
});
|
|
206
|
+
listeners.set('logStream', logUnsubscribe);
|
|
207
|
+
}
|
|
208
|
+
return listeners;
|
|
209
|
+
}
|
|
210
|
+
// Clean up world subscription and event listeners
|
|
211
|
+
export async function cleanupWorldSubscription(world, worldEventListeners) {
|
|
212
|
+
try {
|
|
213
|
+
// Remove all event listeners
|
|
214
|
+
for (const [eventType, listener] of worldEventListeners.entries()) {
|
|
215
|
+
world.eventEmitter.removeListener(eventType, listener);
|
|
216
|
+
}
|
|
217
|
+
worldEventListeners.clear();
|
|
218
|
+
logger.debug('World subscription cleanup completed', { worldId: world.id });
|
|
219
|
+
}
|
|
220
|
+
catch (error) {
|
|
221
|
+
logger.error('World subscription cleanup failed', {
|
|
222
|
+
worldId: world.id,
|
|
223
|
+
error: error instanceof Error ? error.message : error
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
//# sourceMappingURL=subscription.js.map
|