@loom-framework/backend 0.1.0-alpha.1 → 0.1.0-alpha.10

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.
Files changed (42) hide show
  1. package/dist/ai/button-resolver.d.ts +17 -0
  2. package/dist/ai/button-resolver.d.ts.map +1 -0
  3. package/dist/ai/button-resolver.js +40 -0
  4. package/dist/ai/button-resolver.js.map +1 -0
  5. package/dist/ai/engine.d.ts +14 -0
  6. package/dist/ai/engine.d.ts.map +1 -1
  7. package/dist/ai/engine.js +74 -23
  8. package/dist/ai/engine.js.map +1 -1
  9. package/dist/ai/index.d.ts +3 -1
  10. package/dist/ai/index.d.ts.map +1 -1
  11. package/dist/ai/index.js +1 -0
  12. package/dist/ai/index.js.map +1 -1
  13. package/dist/ai/output-parser.d.ts +14 -7
  14. package/dist/ai/output-parser.d.ts.map +1 -1
  15. package/dist/ai/output-parser.js +126 -117
  16. package/dist/ai/output-parser.js.map +1 -1
  17. package/dist/ai/session-manager.d.ts +11 -2
  18. package/dist/ai/session-manager.d.ts.map +1 -1
  19. package/dist/ai/session-manager.js +88 -12
  20. package/dist/ai/session-manager.js.map +1 -1
  21. package/dist/bin.js +0 -0
  22. package/dist/index.d.ts +2 -2
  23. package/dist/index.d.ts.map +1 -1
  24. package/dist/index.js +6 -7
  25. package/dist/index.js.map +1 -1
  26. package/dist/routes/chat.d.ts +31 -0
  27. package/dist/routes/chat.d.ts.map +1 -0
  28. package/dist/routes/chat.js +216 -0
  29. package/dist/routes/chat.js.map +1 -0
  30. package/dist/routes/index.d.ts +3 -0
  31. package/dist/routes/index.d.ts.map +1 -1
  32. package/dist/routes/index.js +2 -0
  33. package/dist/routes/index.js.map +1 -1
  34. package/dist/routes/upload.d.ts +24 -0
  35. package/dist/routes/upload.d.ts.map +1 -0
  36. package/dist/routes/upload.js +67 -0
  37. package/dist/routes/upload.js.map +1 -0
  38. package/package.json +12 -13
  39. package/dist/websocket/index.d.ts +0 -32
  40. package/dist/websocket/index.d.ts.map +0 -1
  41. package/dist/websocket/index.js +0 -320
  42. package/dist/websocket/index.js.map +0 -1
@@ -3,4 +3,7 @@
3
3
  */
4
4
  export { registerDataRoutes } from './data.js';
5
5
  export { registerHealthRoute } from './health.js';
6
+ export { registerUploadRoutes, saveUploadedFile } from './upload.js';
7
+ export { registerChatRoutes } from './chat.js';
8
+ export type { ChatRouteOptions } from './chat.js';
6
9
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/routes/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/routes/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACrE,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAC/C,YAAY,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC"}
@@ -3,4 +3,6 @@
3
3
  */
4
4
  export { registerDataRoutes } from './data.js';
5
5
  export { registerHealthRoute } from './health.js';
6
+ export { registerUploadRoutes, saveUploadedFile } from './upload.js';
7
+ export { registerChatRoutes } from './chat.js';
6
8
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/routes/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/routes/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAC/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACrE,OAAO,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Upload Routes - File upload and static serving
3
+ *
4
+ * Handles base64 file uploads via SSE chat and provides
5
+ * static file serving for uploaded files.
6
+ */
7
+ import type { FastifyInstance } from 'fastify';
8
+ export interface UploadRouteOptions {
9
+ /** Project root directory */
10
+ projectRoot: string;
11
+ }
12
+ /**
13
+ * Register upload and static file serving routes
14
+ */
15
+ export declare function registerUploadRoutes(fastify: FastifyInstance, options: UploadRouteOptions): void;
16
+ /**
17
+ * Save an uploaded file from base64 data
18
+ * Returns the relative URL path for accessing the file
19
+ */
20
+ export declare function saveUploadedFile(projectRoot: string, sessionId: string, filename: string, base64Data: string): Promise<{
21
+ url: string;
22
+ path: string;
23
+ }>;
24
+ //# sourceMappingURL=upload.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upload.d.ts","sourceRoot":"","sources":["../../src/routes/upload.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAI/C,MAAM,WAAW,kBAAkB;IACjC,6BAA6B;IAC7B,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,kBAAkB,GAC1B,IAAI,CA8CN;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CACpC,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,GACjB,OAAO,CAAC;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC,CAYxC"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Upload Routes - File upload and static serving
3
+ *
4
+ * Handles base64 file uploads via SSE chat and provides
5
+ * static file serving for uploaded files.
6
+ */
7
+ import { promises as fs } from 'fs';
8
+ import path from 'path';
9
+ /**
10
+ * Register upload and static file serving routes
11
+ */
12
+ export function registerUploadRoutes(fastify, options) {
13
+ const uploadsDir = path.join(options.projectRoot, '.loom', 'uploads');
14
+ // Ensure uploads directory exists
15
+ fs.mkdir(uploadsDir, { recursive: true }).catch(() => { });
16
+ // Serve uploaded files: GET /uploads/:sessionId/:filename
17
+ fastify.get('/uploads/:sessionId/:filename', async (request, reply) => {
18
+ const { sessionId, filename } = request.params;
19
+ // Sanitize path components to prevent directory traversal
20
+ const sanitizedSessionId = sessionId.replace(/[^a-zA-Z0-9_-]/g, '');
21
+ const sanitizedFilename = filename.replace(/[^a-zA-Z0-9._-]/g, '');
22
+ if (!sanitizedSessionId || !sanitizedFilename) {
23
+ return reply.status(400).send({ error: 'Invalid path parameters' });
24
+ }
25
+ const filePath = path.join(uploadsDir, sanitizedSessionId, sanitizedFilename);
26
+ // Ensure resolved path is within uploads directory
27
+ const resolvedPath = path.resolve(filePath);
28
+ if (!resolvedPath.startsWith(path.resolve(uploadsDir))) {
29
+ return reply.status(403).send({ error: 'Access denied' });
30
+ }
31
+ try {
32
+ const buffer = await fs.readFile(filePath);
33
+ const ext = path.extname(sanitizedFilename).toLowerCase();
34
+ const contentTypes = {
35
+ '.png': 'image/png',
36
+ '.jpg': 'image/jpeg',
37
+ '.jpeg': 'image/jpeg',
38
+ '.gif': 'image/gif',
39
+ '.pdf': 'application/pdf',
40
+ '.txt': 'text/plain',
41
+ '.json': 'application/json',
42
+ '.csv': 'text/csv',
43
+ };
44
+ reply.header('Content-Type', contentTypes[ext] || 'application/octet-stream');
45
+ return reply.send(buffer);
46
+ }
47
+ catch {
48
+ return reply.status(404).send({ error: 'File not found' });
49
+ }
50
+ });
51
+ }
52
+ /**
53
+ * Save an uploaded file from base64 data
54
+ * Returns the relative URL path for accessing the file
55
+ */
56
+ export async function saveUploadedFile(projectRoot, sessionId, filename, base64Data) {
57
+ const uploadsDir = path.join(projectRoot, '.loom', 'uploads', sessionId);
58
+ await fs.mkdir(uploadsDir, { recursive: true });
59
+ const filePath = path.join(uploadsDir, filename);
60
+ const buffer = Buffer.from(base64Data, 'base64');
61
+ await fs.writeFile(filePath, buffer);
62
+ return {
63
+ url: `/uploads/${sessionId}/${filename}`,
64
+ path: filePath,
65
+ };
66
+ }
67
+ //# sourceMappingURL=upload.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upload.js","sourceRoot":"","sources":["../../src/routes/upload.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@loom-framework/backend",
3
- "version": "0.1.0-alpha.1",
4
- "description": "Loom framework backend - AI communication, WebSocket proxy, REST routes",
3
+ "version": "0.1.0-alpha.10",
4
+ "description": "Loom framework backend - AI communication, SSE chat, REST routes",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",
@@ -17,21 +17,20 @@
17
17
  "bin": {
18
18
  "loom-server": "./dist/bin.js"
19
19
  },
20
- "dependencies": {
21
- "fastify": "^5.2.0",
22
- "@fastify/websocket": "^11.0.0",
23
- "@fastify/cors": "^10.0.0",
24
- "@fastify/static": "^8.0.0",
25
- "@loom-framework/core": "0.1.0-alpha.1"
26
- },
27
- "devDependencies": {
28
- "typescript": "^5.6.0"
29
- },
30
20
  "scripts": {
31
21
  "build": "tsc",
32
22
  "dev": "tsc --watch",
33
23
  "start": "node dist/bin.js",
34
24
  "clean": "rm -rf dist",
35
25
  "lint": "tsc --noEmit"
26
+ },
27
+ "dependencies": {
28
+ "@loom-framework/core": "workspace:*",
29
+ "fastify": "^5.2.0",
30
+ "@fastify/cors": "^10.0.0",
31
+ "@fastify/static": "^8.0.0"
32
+ },
33
+ "devDependencies": {
34
+ "typescript": "^5.6.0"
36
35
  }
37
- }
36
+ }
@@ -1,32 +0,0 @@
1
- /**
2
- * WebSocket Handler - Transparent proxy between client and AIEngine
3
- *
4
- * Event protocol:
5
- * - user_message → AIEngine.call() → stream assistant_chunk / assistant_complete
6
- * - Session CRUD: new_session / load_session / list_sessions / delete_session
7
- */
8
- import type { FastifyInstance } from 'fastify';
9
- import type { AIEngine, LoomConfig } from '@loom-framework/core';
10
- import { SessionManager } from '../ai/session-manager.js';
11
- import { AIInteractionLogger } from '../observe/index.js';
12
- export interface WebSocketHandlerOptions {
13
- engine: AIEngine;
14
- sessionManager: SessionManager;
15
- config: LoomConfig;
16
- logger?: AIInteractionLogger;
17
- }
18
- /**
19
- * Register WebSocket route and event handlers on a Fastify instance
20
- */
21
- export declare function registerWebSocket(fastify: FastifyInstance, options: WebSocketHandlerOptions): void;
22
- /**
23
- * Resolve prompt from AI button configuration.
24
- * - Static buttons: return prompt directly
25
- * - Template buttons: substitute {{var}} with context values
26
- * Returns null if button not found or context is incomplete.
27
- */
28
- export declare function resolveButtonPrompt(buttonId: string, context: Record<string, string> | undefined, config: LoomConfig): {
29
- prompt: string;
30
- error?: string;
31
- } | null;
32
- //# sourceMappingURL=index.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/websocket/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAE/C,OAAO,KAAK,EACV,QAAQ,EACR,UAAU,EAKX,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,cAAc,EAAuB,MAAM,0BAA0B,CAAC;AAC/E,OAAO,EAAE,mBAAmB,EAAyB,MAAM,qBAAqB,CAAC;AAEjF,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,QAAQ,CAAC;IACjB,cAAc,EAAE,cAAc,CAAC;IAC/B,MAAM,EAAE,UAAU,CAAC;IACnB,MAAM,CAAC,EAAE,mBAAmB,CAAC;CAC9B;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,uBAAuB,GAC/B,IAAI,CAyBN;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,EAC3C,MAAM,EAAE,UAAU,GACjB;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAiC3C"}
@@ -1,320 +0,0 @@
1
- /**
2
- * WebSocket Handler - Transparent proxy between client and AIEngine
3
- *
4
- * Event protocol:
5
- * - user_message → AIEngine.call() → stream assistant_chunk / assistant_complete
6
- * - Session CRUD: new_session / load_session / list_sessions / delete_session
7
- */
8
- /**
9
- * Register WebSocket route and event handlers on a Fastify instance
10
- */
11
- export function registerWebSocket(fastify, options) {
12
- const { engine, sessionManager, config, logger } = options;
13
- fastify.register(async function (instance) {
14
- instance.get('/ws', { websocket: true }, (socket, _req) => {
15
- instance.log.info('WebSocket client connected');
16
- socket.on('message', async (raw) => {
17
- try {
18
- const event = JSON.parse(raw.toString());
19
- await handleEvent(event, socket, instance, engine, sessionManager, config, logger);
20
- }
21
- catch (err) {
22
- instance.log.error('Error handling WebSocket message: %s', err);
23
- }
24
- });
25
- socket.on('close', () => {
26
- instance.log.info('WebSocket client disconnected');
27
- });
28
- socket.on('error', (err) => {
29
- instance.log.error('WebSocket error: %s', err);
30
- });
31
- });
32
- });
33
- }
34
- /**
35
- * Resolve prompt from AI button configuration.
36
- * - Static buttons: return prompt directly
37
- * - Template buttons: substitute {{var}} with context values
38
- * Returns null if button not found or context is incomplete.
39
- */
40
- export function resolveButtonPrompt(buttonId, context, config) {
41
- const button = config.aiButtons?.find((b) => b.id === buttonId);
42
- if (!button) {
43
- return null;
44
- }
45
- // Static prompt
46
- if (button.prompt) {
47
- return { prompt: button.prompt };
48
- }
49
- // Template prompt
50
- if (button.promptTemplate) {
51
- const missing = (button.contextVars || []).filter((v) => !context || context[v] === undefined);
52
- if (missing.length > 0) {
53
- return {
54
- prompt: '',
55
- error: `Missing context variables: ${missing.join(', ')}. Required: ${button.contextVars.join(', ')}`,
56
- };
57
- }
58
- let resolved = button.promptTemplate;
59
- if (context) {
60
- for (const [key, value] of Object.entries(context)) {
61
- resolved = resolved.replace(new RegExp(`\\{\\{${key}\\}\\}`, 'g'), value);
62
- }
63
- }
64
- return { prompt: resolved };
65
- }
66
- return null;
67
- }
68
- /**
69
- * Route incoming WebSocket events to their handlers
70
- */
71
- async function handleEvent(event, socket, fastify, engine, sessionManager, config, logger) {
72
- switch (event.type) {
73
- case 'user_message':
74
- await handleUserMessage(event, socket, fastify, engine, sessionManager, config, logger);
75
- break;
76
- case 'new_session':
77
- await handleNewSession(socket, fastify, sessionManager);
78
- break;
79
- case 'load_session':
80
- await handleLoadSession(event, socket, fastify, sessionManager);
81
- break;
82
- case 'list_sessions':
83
- await handleListSessions(socket, fastify, sessionManager);
84
- break;
85
- case 'delete_session':
86
- await handleDeleteSession(event, socket, fastify, sessionManager);
87
- break;
88
- default:
89
- fastify.log.warn('Unknown WebSocket event type: %s', event.type);
90
- }
91
- }
92
- /**
93
- * Handle user_message: stream AI response back to client
94
- */
95
- async function handleUserMessage(event, socket, fastify, engine, sessionManager, config, logger) {
96
- const messageId = generateMessageId();
97
- const startTime = Date.now();
98
- fastify.log.info('User message on session %s', event.session_id);
99
- // Resolve prompt: AI button or direct content
100
- let prompt;
101
- if (event.buttonId) {
102
- const resolved = resolveButtonPrompt(event.buttonId, event.context, config);
103
- if (!resolved) {
104
- socket.send(JSON.stringify({
105
- type: 'error',
106
- error: `AI button "${event.buttonId}" not found in configuration`,
107
- session_id: event.session_id,
108
- }));
109
- return;
110
- }
111
- if (resolved.error) {
112
- socket.send(JSON.stringify({
113
- type: 'error',
114
- error: resolved.error,
115
- session_id: event.session_id,
116
- }));
117
- return;
118
- }
119
- prompt = resolved.prompt;
120
- fastify.log.info('AI button "%s" resolved to prompt: %s', event.buttonId, prompt.slice(0, 80));
121
- }
122
- else {
123
- prompt = event.content;
124
- }
125
- // Get or create session
126
- const session = await sessionManager.getOrCreate(event.session_id);
127
- // Add user message to session
128
- const userMsg = {
129
- id: messageId,
130
- role: 'user',
131
- content: prompt,
132
- timestamp: new Date().toISOString(),
133
- };
134
- await sessionManager.addMessages(event.session_id, [userMsg]);
135
- // Send initial "processing" chunk
136
- sendChunk(socket, '正在处理...', messageId, event.session_id, false);
137
- // Call AI engine
138
- let aiContent = '';
139
- let claudeSessionId;
140
- let usage;
141
- try {
142
- for await (const chunk of engine.call(prompt, {
143
- sessionId: event.session_id,
144
- resumeSessionId: session.claudeSessionId,
145
- })) {
146
- if (chunk.type === 'content' && chunk.content) {
147
- aiContent += chunk.content;
148
- sendChunk(socket, chunk.content, messageId, event.session_id, false);
149
- }
150
- else if (chunk.type === 'session_info') {
151
- claudeSessionId = chunk.sessionId;
152
- if (chunk.usage)
153
- usage = chunk.usage;
154
- }
155
- else if (chunk.type === 'error' && chunk.error) {
156
- fastify.log.error('AI engine error: %s', chunk.error);
157
- sendChunk(socket, `\n\nError: ${chunk.error}`, messageId, event.session_id, false);
158
- }
159
- }
160
- }
161
- catch (error) {
162
- fastify.log.error('AI engine exception: %s', error);
163
- recordLog(logger, event.session_id, messageId, prompt, '', startTime, [], [], error instanceof Error ? error.message : String(error), fastify);
164
- sendComplete(socket, `\n\nProcessing error: ${error}`, messageId, event.session_id, usage);
165
- return;
166
- }
167
- // Send completion event
168
- const completePayload = {
169
- type: 'assistant_complete',
170
- content: aiContent || '(empty response)',
171
- message_id: messageId,
172
- session_id: event.session_id,
173
- is_complete: true,
174
- };
175
- if (claudeSessionId) {
176
- completePayload.claude_session_id = claudeSessionId;
177
- }
178
- if (usage) {
179
- completePayload.usage = usage;
180
- }
181
- socket.send(JSON.stringify(completePayload));
182
- // Persist assistant message to session
183
- const assistantMsg = {
184
- id: messageId,
185
- role: 'assistant',
186
- content: aiContent || '(empty response)',
187
- timestamp: new Date().toISOString(),
188
- };
189
- await sessionManager.addMessages(event.session_id, [assistantMsg], claudeSessionId, usage);
190
- // Record interaction log
191
- recordLog(logger, event.session_id, messageId, prompt, aiContent || '(empty response)', startTime, [], [], undefined, fastify, usage);
192
- }
193
- /**
194
- * Handle new_session event
195
- */
196
- async function handleNewSession(socket, fastify, sessionManager) {
197
- const session = await sessionManager.createSession();
198
- fastify.log.info('Created new session: %s', session.id);
199
- socket.send(JSON.stringify({
200
- type: 'session_created',
201
- session_id: session.id,
202
- session: {
203
- id: session.id,
204
- title: session.title,
205
- createdAt: session.createdAt,
206
- updatedAt: session.updatedAt,
207
- messages: [],
208
- },
209
- }));
210
- }
211
- /**
212
- * Handle load_session event
213
- */
214
- async function handleLoadSession(event, socket, fastify, sessionManager) {
215
- const session = await sessionManager.readSession(event.session_id);
216
- if (session) {
217
- fastify.log.info('Loaded session: %s', event.session_id);
218
- socket.send(JSON.stringify({
219
- type: 'session_loaded',
220
- session_id: event.session_id,
221
- session: {
222
- id: session.id,
223
- title: session.title,
224
- createdAt: session.createdAt,
225
- updatedAt: session.updatedAt,
226
- messages: session.messages,
227
- usage: session.usage,
228
- },
229
- }));
230
- }
231
- else {
232
- fastify.log.warn('Session not found: %s', event.session_id);
233
- socket.send(JSON.stringify({
234
- type: 'error',
235
- error: 'Session not found',
236
- session_id: event.session_id,
237
- }));
238
- }
239
- }
240
- /**
241
- * Handle list_sessions event
242
- */
243
- async function handleListSessions(socket, _fastify, sessionManager) {
244
- const sessions = await sessionManager.listSessions();
245
- socket.send(JSON.stringify({
246
- type: 'sessions_list',
247
- sessions: sessions.map((s) => ({
248
- id: s.id,
249
- title: s.title,
250
- createdAt: s.createdAt,
251
- updatedAt: s.updatedAt,
252
- messageCount: s.messages.length,
253
- })),
254
- }));
255
- }
256
- /**
257
- * Handle delete_session event
258
- */
259
- async function handleDeleteSession(event, socket, fastify, sessionManager) {
260
- const success = await sessionManager.deleteSession(event.session_id);
261
- if (success) {
262
- fastify.log.info('Deleted session: %s', event.session_id);
263
- socket.send(JSON.stringify({
264
- type: 'session_deleted',
265
- session_id: event.session_id,
266
- }));
267
- }
268
- else {
269
- socket.send(JSON.stringify({
270
- type: 'error',
271
- error: 'Failed to delete session',
272
- session_id: event.session_id,
273
- }));
274
- }
275
- }
276
- // ── Helpers ──
277
- function sendChunk(socket, content, messageId, sessionId, isComplete) {
278
- const event = {
279
- type: 'assistant_chunk',
280
- content,
281
- message_id: messageId,
282
- session_id: sessionId,
283
- is_complete: isComplete,
284
- };
285
- socket.send(JSON.stringify(event));
286
- }
287
- function sendComplete(socket, content, messageId, sessionId, usage) {
288
- const event = {
289
- type: 'assistant_complete',
290
- content,
291
- message_id: messageId,
292
- session_id: sessionId,
293
- is_complete: true,
294
- usage,
295
- };
296
- socket.send(JSON.stringify(event));
297
- }
298
- function generateMessageId() {
299
- return `msg_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;
300
- }
301
- function recordLog(logger, sessionId, messageId, prompt, response, startTime, mcpCalls, cliCalls, error, fastify, usage) {
302
- if (!logger)
303
- return;
304
- const logEntry = {
305
- sessionId,
306
- messageId,
307
- timestamp: new Date().toISOString(),
308
- prompt,
309
- response,
310
- duration: Date.now() - startTime,
311
- usage: usage ? { inputTokens: usage.inputTokens, outputTokens: usage.outputTokens } : undefined,
312
- mcpCalls,
313
- cliCalls,
314
- error,
315
- };
316
- logger.log(logEntry).catch((err) => {
317
- fastify.log.warn('Failed to write interaction log: %s', err);
318
- });
319
- }
320
- //# sourceMappingURL=index.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/websocket/index.ts"],"names":[],"mappings":"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"}