@loom-framework/backend 0.1.0-alpha.3 → 0.1.0-alpha.4
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/dist/ai/button-resolver.d.ts +17 -0
- package/dist/ai/button-resolver.d.ts.map +1 -0
- package/dist/ai/button-resolver.js +40 -0
- package/dist/ai/button-resolver.js.map +1 -0
- package/dist/ai/index.d.ts +1 -0
- package/dist/ai/index.d.ts.map +1 -1
- package/dist/ai/index.js +1 -0
- package/dist/ai/index.js.map +1 -1
- package/dist/bin.js +0 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -7
- package/dist/index.js.map +1 -1
- package/dist/routes/chat.d.ts +31 -0
- package/dist/routes/chat.d.ts.map +1 -0
- package/dist/routes/chat.js +216 -0
- package/dist/routes/chat.js.map +1 -0
- package/dist/routes/index.d.ts +2 -0
- package/dist/routes/index.d.ts.map +1 -1
- package/dist/routes/index.js +1 -0
- package/dist/routes/index.js.map +1 -1
- package/dist/routes/upload.d.ts +1 -1
- package/dist/routes/upload.js +1 -1
- package/package.json +12 -13
- package/dist/websocket/index.d.ts +0 -33
- package/dist/websocket/index.d.ts.map +0 -1
- package/dist/websocket/index.js +0 -373
- package/dist/websocket/index.js.map +0 -1
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Button Resolver - Resolve AI button prompts from configuration
|
|
3
|
+
*
|
|
4
|
+
* Shared between the SSE chat route and other modules.
|
|
5
|
+
*/
|
|
6
|
+
import type { LoomConfig } from '@loom-framework/core';
|
|
7
|
+
/**
|
|
8
|
+
* Resolve prompt from AI button configuration.
|
|
9
|
+
* - Static buttons: return prompt directly
|
|
10
|
+
* - Template buttons: substitute {{var}} with context values
|
|
11
|
+
* Returns null if button not found or context is incomplete.
|
|
12
|
+
*/
|
|
13
|
+
export declare function resolveButtonPrompt(buttonId: string, context: Record<string, string> | undefined, config: LoomConfig): {
|
|
14
|
+
prompt: string;
|
|
15
|
+
error?: string;
|
|
16
|
+
} | null;
|
|
17
|
+
//# sourceMappingURL=button-resolver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"button-resolver.d.ts","sourceRoot":"","sources":["../../src/ai/button-resolver.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAEvD;;;;;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"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Button Resolver - Resolve AI button prompts from configuration
|
|
3
|
+
*
|
|
4
|
+
* Shared between the SSE chat route and other modules.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Resolve prompt from AI button configuration.
|
|
8
|
+
* - Static buttons: return prompt directly
|
|
9
|
+
* - Template buttons: substitute {{var}} with context values
|
|
10
|
+
* Returns null if button not found or context is incomplete.
|
|
11
|
+
*/
|
|
12
|
+
export function resolveButtonPrompt(buttonId, context, config) {
|
|
13
|
+
const button = config.aiButtons?.find((b) => b.id === buttonId);
|
|
14
|
+
if (!button) {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
// Static prompt
|
|
18
|
+
if (button.prompt) {
|
|
19
|
+
return { prompt: button.prompt };
|
|
20
|
+
}
|
|
21
|
+
// Template prompt
|
|
22
|
+
if (button.promptTemplate) {
|
|
23
|
+
const missing = (button.contextVars || []).filter((v) => !context || context[v] === undefined);
|
|
24
|
+
if (missing.length > 0) {
|
|
25
|
+
return {
|
|
26
|
+
prompt: '',
|
|
27
|
+
error: `Missing context variables: ${missing.join(', ')}. Required: ${button.contextVars.join(', ')}`,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
let resolved = button.promptTemplate;
|
|
31
|
+
if (context) {
|
|
32
|
+
for (const [key, value] of Object.entries(context)) {
|
|
33
|
+
resolved = resolved.replace(new RegExp(`\\{\\{${key}\\}\\}`, 'g'), value);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return { prompt: resolved };
|
|
37
|
+
}
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
//# sourceMappingURL=button-resolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"button-resolver.js","sourceRoot":"","sources":["../../src/ai/button-resolver.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH;;;;;GAKG;AACH,MAAM,UAAU,mBAAmB,CACjC,QAAgB,EAChB,OAA2C,EAC3C,MAAkB;IAElB,MAAM,MAAM,GAAG,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,QAAQ,CAAC,CAAC;IAChE,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,IAAI,CAAC;IACd,CAAC;IAED,gBAAgB;IAChB,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QAClB,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;IACnC,CAAC;IAED,kBAAkB;IAClB,IAAI,MAAM,CAAC,cAAc,EAAE,CAAC;QAC1B,MAAM,OAAO,GAAG,CAAC,MAAM,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,MAAM,CAC/C,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,IAAI,OAAO,CAAC,CAAC,CAAC,KAAK,SAAS,CAC5C,CAAC;QACF,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACvB,OAAO;gBACL,MAAM,EAAE,EAAE;gBACV,KAAK,EAAE,8BAA8B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,eAAe,MAAM,CAAC,WAAY,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE;aACvG,CAAC;QACJ,CAAC;QAED,IAAI,QAAQ,GAAG,MAAM,CAAC,cAAc,CAAC;QACrC,IAAI,OAAO,EAAE,CAAC;YACZ,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;gBACnD,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,MAAM,CAAC,SAAS,GAAG,QAAQ,EAAE,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC;YAC5E,CAAC;QACH,CAAC;QACD,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC;IAC9B,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
|
package/dist/ai/index.d.ts
CHANGED
|
@@ -7,4 +7,5 @@ export { SessionManager } from './session-manager.js';
|
|
|
7
7
|
export type { SessionRecord, SessionMessage, SessionFileRef } from './session-manager.js';
|
|
8
8
|
export { parseClaudeOutput } from './output-parser.js';
|
|
9
9
|
export type { ParserLogger, ParserLogEntry } from './output-parser.js';
|
|
10
|
+
export { resolveButtonPrompt } from './button-resolver.js';
|
|
10
11
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/ai/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ai/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,YAAY,EAAE,uBAAuB,EAAE,YAAY,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AACzG,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC1F,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ai/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAC/C,YAAY,EAAE,uBAAuB,EAAE,YAAY,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AACzG,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAC1F,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AACvD,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACvE,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC"}
|
package/dist/ai/index.js
CHANGED
package/dist/ai/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ai/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ai/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAE/C,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AAEtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAEvD,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC"}
|
package/dist/bin.js
CHANGED
|
File without changes
|
package/dist/index.d.ts
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
* @loom-framework/backend - Main Server
|
|
3
3
|
*
|
|
4
4
|
* Assembles Fastify server with:
|
|
5
|
-
* -
|
|
6
|
-
* - REST routes for DataAdapter CRUD + health check
|
|
5
|
+
* - HTTP SSE chat route (Ant Design X compatible)
|
|
6
|
+
* - REST routes for DataAdapter CRUD + health check + sessions
|
|
7
7
|
* - Static file serving for production mode
|
|
8
8
|
* - Configuration from loom.config.ts
|
|
9
9
|
*/
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,OAAO,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,OAAO,MAAM,SAAS,CAAC;AAK9B,OAAO,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAS5F,MAAM,WAAW,iBAAiB;IAChC,uDAAuD;IACvD,WAAW,EAAE,MAAM,CAAC;IACpB,uDAAuD;IACvD,YAAY,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC;IACrC,kEAAkE;IAClE,MAAM,CAAC,EAAE,QAAQ,CAAC;IAClB,qEAAqE;IACrE,OAAO,CAAC,EAAE,WAAW,CAAC;IACtB,mBAAmB;IACnB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,qBAAa,UAAU;IACrB,OAAO,CAAC,MAAM,CAAc;IAC5B,OAAO,CAAC,MAAM,CAAY;IAC1B,OAAO,CAAC,OAAO,CAAe;IAC9B,OAAO,CAAC,cAAc,CAAkB;IACxC,OAAO,CAAC,iBAAiB,CAAuB;IAChD,OAAO,CAAC,OAAO,CAA8B;IAC7C,OAAO,CAAC,WAAW,CAAS;IAC5B,OAAO,CAAC,OAAO,CAAoB;gBAEvB,OAAO,EAAE,iBAAiB;IAKtC;;OAEG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IA2EjC;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAO5B;;OAEG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAQ3B,0CAA0C;IAC1C,UAAU,IAAI,UAAU,CAAC,OAAO,OAAO,CAAC;IAIxC,gCAAgC;IAChC,SAAS,IAAI,UAAU;IAIvB,iCAAiC;IACjC,UAAU,IAAI,WAAW;IAIzB;;OAEG;IACH,OAAO,CAAC,aAAa;CAUtB;AAED;;GAEG;AACH,wBAAsB,WAAW,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC,CAK1E"}
|
package/dist/index.js
CHANGED
|
@@ -2,14 +2,13 @@
|
|
|
2
2
|
* @loom-framework/backend - Main Server
|
|
3
3
|
*
|
|
4
4
|
* Assembles Fastify server with:
|
|
5
|
-
* -
|
|
6
|
-
* - REST routes for DataAdapter CRUD + health check
|
|
5
|
+
* - HTTP SSE chat route (Ant Design X compatible)
|
|
6
|
+
* - REST routes for DataAdapter CRUD + health check + sessions
|
|
7
7
|
* - Static file serving for production mode
|
|
8
8
|
* - Configuration from loom.config.ts
|
|
9
9
|
*/
|
|
10
10
|
import Fastify from 'fastify';
|
|
11
11
|
import cors from '@fastify/cors';
|
|
12
|
-
import websocket from '@fastify/websocket';
|
|
13
12
|
import staticPlugin from '@fastify/static';
|
|
14
13
|
import path from 'path';
|
|
15
14
|
import { FileSystemAdapter, loadConfig } from '@loom-framework/core';
|
|
@@ -17,8 +16,7 @@ import { SQLiteAdapter } from '@loom-framework/core';
|
|
|
17
16
|
import { ClaudeCodeEngine } from './ai/engine.js';
|
|
18
17
|
import { SessionManager } from './ai/session-manager.js';
|
|
19
18
|
import { AIInteractionLogger } from './observe/index.js';
|
|
20
|
-
import {
|
|
21
|
-
import { registerDataRoutes, registerHealthRoute, registerUploadRoutes } from './routes/index.js';
|
|
19
|
+
import { registerDataRoutes, registerHealthRoute, registerUploadRoutes, registerChatRoutes } from './routes/index.js';
|
|
22
20
|
export class LoomServer {
|
|
23
21
|
config;
|
|
24
22
|
engine;
|
|
@@ -67,7 +65,6 @@ export class LoomServer {
|
|
|
67
65
|
if (serverConfig.cors !== false) {
|
|
68
66
|
await this.fastify.register(cors, { origin: true });
|
|
69
67
|
}
|
|
70
|
-
await this.fastify.register(websocket);
|
|
71
68
|
// Static file serving in production
|
|
72
69
|
if (serverConfig.staticDir) {
|
|
73
70
|
const staticDir = path.resolve(this.projectRoot, serverConfig.staticDir);
|
|
@@ -81,7 +78,7 @@ export class LoomServer {
|
|
|
81
78
|
registerHealthRoute(this.fastify, this.adapter);
|
|
82
79
|
registerDataRoutes(this.fastify, this.adapter);
|
|
83
80
|
registerUploadRoutes(this.fastify, { projectRoot: this.projectRoot });
|
|
84
|
-
|
|
81
|
+
registerChatRoutes(this.fastify, {
|
|
85
82
|
engine: this.engine,
|
|
86
83
|
sessionManager: this.sessionManager,
|
|
87
84
|
config: this.config,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,OAAO,MAAM,SAAS,CAAC;AAC9B,OAAO,IAAI,MAAM,eAAe,CAAC;AACjC,OAAO,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chat SSE Route - HTTP Server-Sent Events streaming for AI chat
|
|
3
|
+
*
|
|
4
|
+
* Replaces WebSocket with HTTP SSE for AI conversation streaming.
|
|
5
|
+
* Ant Design X (useXChat + XRequest) natively consumes this format.
|
|
6
|
+
*
|
|
7
|
+
* POST /api/v1/chat
|
|
8
|
+
* Body: { content, session_id, button_id?, context?, files? }
|
|
9
|
+
* Response: SSE stream with data lines containing JSON chunks
|
|
10
|
+
*
|
|
11
|
+
* GET /api/v1/sessions - List sessions
|
|
12
|
+
* POST /api/v1/sessions - Create session
|
|
13
|
+
* GET /api/v1/sessions/:id - Load session
|
|
14
|
+
* DELETE /api/v1/sessions/:id - Delete session
|
|
15
|
+
*/
|
|
16
|
+
import type { FastifyInstance } from 'fastify';
|
|
17
|
+
import type { AIEngine, LoomConfig } from '@loom-framework/core';
|
|
18
|
+
import { SessionManager } from '../ai/session-manager.js';
|
|
19
|
+
import { AIInteractionLogger } from '../observe/index.js';
|
|
20
|
+
export interface ChatRouteOptions {
|
|
21
|
+
engine: AIEngine;
|
|
22
|
+
sessionManager: SessionManager;
|
|
23
|
+
config: LoomConfig;
|
|
24
|
+
logger?: AIInteractionLogger;
|
|
25
|
+
projectRoot: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Register chat SSE route and session REST routes
|
|
29
|
+
*/
|
|
30
|
+
export declare function registerChatRoutes(fastify: FastifyInstance, options: ChatRouteOptions): void;
|
|
31
|
+
//# sourceMappingURL=chat.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../src/routes/chat.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,eAAe,EAAgC,MAAM,SAAS,CAAC;AAC7E,OAAO,KAAK,EACV,QAAQ,EACR,UAAU,EAEX,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,cAAc,EAAuB,MAAM,0BAA0B,CAAC;AAC/E,OAAO,EAAE,mBAAmB,EAAyB,MAAM,qBAAqB,CAAC;AAIjF,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,QAAQ,CAAC;IACjB,cAAc,EAAE,cAAc,CAAC;IAC/B,MAAM,EAAE,UAAU,CAAC;IACnB,MAAM,CAAC,EAAE,mBAAmB,CAAC;IAC7B,WAAW,EAAE,MAAM,CAAC;CACrB;AAqDD;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,gBAAgB,GACxB,IAAI,CAgKN"}
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Chat SSE Route - HTTP Server-Sent Events streaming for AI chat
|
|
3
|
+
*
|
|
4
|
+
* Replaces WebSocket with HTTP SSE for AI conversation streaming.
|
|
5
|
+
* Ant Design X (useXChat + XRequest) natively consumes this format.
|
|
6
|
+
*
|
|
7
|
+
* POST /api/v1/chat
|
|
8
|
+
* Body: { content, session_id, button_id?, context?, files? }
|
|
9
|
+
* Response: SSE stream with data lines containing JSON chunks
|
|
10
|
+
*
|
|
11
|
+
* GET /api/v1/sessions - List sessions
|
|
12
|
+
* POST /api/v1/sessions - Create session
|
|
13
|
+
* GET /api/v1/sessions/:id - Load session
|
|
14
|
+
* DELETE /api/v1/sessions/:id - Delete session
|
|
15
|
+
*/
|
|
16
|
+
import { saveUploadedFile } from './upload.js';
|
|
17
|
+
import { resolveButtonPrompt } from '../ai/button-resolver.js';
|
|
18
|
+
// ── Route Registration ──
|
|
19
|
+
/**
|
|
20
|
+
* Register chat SSE route and session REST routes
|
|
21
|
+
*/
|
|
22
|
+
export function registerChatRoutes(fastify, options) {
|
|
23
|
+
const { engine, sessionManager, config, logger, projectRoot } = options;
|
|
24
|
+
// POST /api/v1/chat — SSE streaming AI response
|
|
25
|
+
fastify.post('/api/v1/chat', async (request, reply) => {
|
|
26
|
+
const body = request.body;
|
|
27
|
+
const { content, session_id, button_id, context, files } = body;
|
|
28
|
+
if (!content && !button_id) {
|
|
29
|
+
return reply.status(400).send({ error: 'content or button_id is required' });
|
|
30
|
+
}
|
|
31
|
+
if (!session_id) {
|
|
32
|
+
return reply.status(400).send({ error: 'session_id is required' });
|
|
33
|
+
}
|
|
34
|
+
// Set SSE headers
|
|
35
|
+
reply.raw.writeHead(200, {
|
|
36
|
+
'Content-Type': 'text/event-stream',
|
|
37
|
+
'Cache-Control': 'no-cache',
|
|
38
|
+
Connection: 'keep-alive',
|
|
39
|
+
'X-Accel-Buffering': 'no', // Disable nginx buffering
|
|
40
|
+
});
|
|
41
|
+
const messageId = generateMessageId();
|
|
42
|
+
const startTime = Date.now();
|
|
43
|
+
// Handle file uploads
|
|
44
|
+
const uploadedFiles = [];
|
|
45
|
+
if (files && files.length > 0 && projectRoot) {
|
|
46
|
+
for (const file of files) {
|
|
47
|
+
if (file.content) {
|
|
48
|
+
try {
|
|
49
|
+
const result = await saveUploadedFile(projectRoot, session_id, file.name, file.content);
|
|
50
|
+
uploadedFiles.push({ name: file.name, path: result.path });
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
fastify.log.warn('Failed to save uploaded file %s: %s', file.name, err);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
// Resolve prompt: AI button or direct content
|
|
59
|
+
let prompt;
|
|
60
|
+
if (button_id) {
|
|
61
|
+
const resolved = resolveButtonPrompt(button_id, context, config);
|
|
62
|
+
if (!resolved) {
|
|
63
|
+
sendSSE(reply, { type: 'error', error: `AI button "${button_id}" not found`, message_id: messageId, session_id });
|
|
64
|
+
endSSE(reply);
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
if (resolved.error) {
|
|
68
|
+
sendSSE(reply, { type: 'error', error: resolved.error, message_id: messageId, session_id });
|
|
69
|
+
endSSE(reply);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
prompt = resolved.prompt;
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
prompt = content;
|
|
76
|
+
}
|
|
77
|
+
// Get or create session
|
|
78
|
+
const session = await sessionManager.getOrCreate(session_id);
|
|
79
|
+
// Add user message to session
|
|
80
|
+
const userMsg = {
|
|
81
|
+
id: messageId,
|
|
82
|
+
role: 'user',
|
|
83
|
+
content: prompt,
|
|
84
|
+
timestamp: new Date().toISOString(),
|
|
85
|
+
files: files?.map((f) => ({ uid: f.uid, name: f.name, size: f.size, type: f.type })),
|
|
86
|
+
};
|
|
87
|
+
await sessionManager.addMessages(session_id, [userMsg]);
|
|
88
|
+
// Call AI engine and stream chunks
|
|
89
|
+
let aiContent = '';
|
|
90
|
+
let claudeSessionId;
|
|
91
|
+
let usage;
|
|
92
|
+
try {
|
|
93
|
+
for await (const chunk of engine.call(prompt, {
|
|
94
|
+
sessionId: session_id,
|
|
95
|
+
resumeSessionId: session.claudeSessionId,
|
|
96
|
+
files: uploadedFiles.length > 0 ? uploadedFiles : undefined,
|
|
97
|
+
})) {
|
|
98
|
+
if (chunk.type === 'content' && chunk.content) {
|
|
99
|
+
aiContent += chunk.content;
|
|
100
|
+
sendSSE(reply, { type: 'chunk', content: chunk.content, message_id: messageId, session_id });
|
|
101
|
+
}
|
|
102
|
+
else if (chunk.type === 'session_info') {
|
|
103
|
+
claudeSessionId = chunk.sessionId;
|
|
104
|
+
if (chunk.usage)
|
|
105
|
+
usage = chunk.usage;
|
|
106
|
+
}
|
|
107
|
+
else if (chunk.type === 'error' && chunk.error) {
|
|
108
|
+
sendSSE(reply, { type: 'error', error: chunk.error, message_id: messageId, session_id });
|
|
109
|
+
}
|
|
110
|
+
else if (chunk.type === 'tool_call') {
|
|
111
|
+
sendSSE(reply, { type: 'tool_call', tool: chunk.toolName || 'unknown', status: 'started' });
|
|
112
|
+
}
|
|
113
|
+
else if (chunk.type === 'tool_result') {
|
|
114
|
+
sendSSE(reply, { type: 'tool_call', tool: chunk.toolName || 'unknown', status: 'completed', result: chunk.toolResult });
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
catch (error) {
|
|
119
|
+
fastify.log.error('AI engine exception: %s', error);
|
|
120
|
+
recordLog(logger, session_id, messageId, prompt, '', startTime, [], [], error instanceof Error ? error.message : String(error), fastify);
|
|
121
|
+
sendSSE(reply, { type: 'error', error: `Processing error: ${error}`, message_id: messageId, session_id });
|
|
122
|
+
endSSE(reply);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
// Send completion
|
|
126
|
+
const completePayload = {
|
|
127
|
+
type: 'done',
|
|
128
|
+
content: aiContent || '(empty response)',
|
|
129
|
+
message_id: messageId,
|
|
130
|
+
session_id,
|
|
131
|
+
};
|
|
132
|
+
if (claudeSessionId)
|
|
133
|
+
completePayload.claude_session_id = claudeSessionId;
|
|
134
|
+
if (usage)
|
|
135
|
+
completePayload.usage = usage;
|
|
136
|
+
sendSSE(reply, completePayload);
|
|
137
|
+
// Persist assistant message
|
|
138
|
+
const assistantMsg = {
|
|
139
|
+
id: messageId,
|
|
140
|
+
role: 'assistant',
|
|
141
|
+
content: aiContent || '(empty response)',
|
|
142
|
+
timestamp: new Date().toISOString(),
|
|
143
|
+
};
|
|
144
|
+
await sessionManager.addMessages(session_id, [assistantMsg], claudeSessionId, usage);
|
|
145
|
+
// Record log
|
|
146
|
+
recordLog(logger, session_id, messageId, prompt, aiContent || '(empty response)', startTime, [], [], undefined, fastify, usage);
|
|
147
|
+
endSSE(reply);
|
|
148
|
+
});
|
|
149
|
+
// GET /api/v1/sessions — List sessions
|
|
150
|
+
fastify.get('/api/v1/sessions', async (_request, reply) => {
|
|
151
|
+
const sessions = await sessionManager.listSessions();
|
|
152
|
+
return reply.send(sessions);
|
|
153
|
+
});
|
|
154
|
+
// POST /api/v1/sessions — Create session
|
|
155
|
+
fastify.post('/api/v1/sessions', async (request, reply) => {
|
|
156
|
+
const body = request.body;
|
|
157
|
+
const session = await sessionManager.createSession(body?.id);
|
|
158
|
+
return reply.code(201).send(session);
|
|
159
|
+
});
|
|
160
|
+
// GET /api/v1/sessions/:id — Load session
|
|
161
|
+
fastify.get('/api/v1/sessions/:id', async (request, reply) => {
|
|
162
|
+
const { id } = request.params;
|
|
163
|
+
const session = await sessionManager.readSession(id);
|
|
164
|
+
if (!session)
|
|
165
|
+
return reply.status(404).send({ error: 'Session not found' });
|
|
166
|
+
return reply.send(session);
|
|
167
|
+
});
|
|
168
|
+
// DELETE /api/v1/sessions/:id — Delete session
|
|
169
|
+
fastify.delete('/api/v1/sessions/:id', async (request, reply) => {
|
|
170
|
+
const { id } = request.params;
|
|
171
|
+
const success = await sessionManager.deleteSession(id);
|
|
172
|
+
if (!success)
|
|
173
|
+
return reply.status(404).send({ error: 'Session not found' });
|
|
174
|
+
return reply.send({ success: true });
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
// ── SSE Helpers ──
|
|
178
|
+
function sendSSE(reply, event) {
|
|
179
|
+
try {
|
|
180
|
+
reply.raw.write(`data: ${JSON.stringify(event)}\n\n`);
|
|
181
|
+
}
|
|
182
|
+
catch {
|
|
183
|
+
// Client may have disconnected
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
function endSSE(reply) {
|
|
187
|
+
try {
|
|
188
|
+
reply.raw.end();
|
|
189
|
+
}
|
|
190
|
+
catch {
|
|
191
|
+
// Already closed
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
function generateMessageId() {
|
|
195
|
+
return `msg_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;
|
|
196
|
+
}
|
|
197
|
+
function recordLog(logger, sessionId, messageId, prompt, response, startTime, mcpCalls, cliCalls, error, fastify, usage) {
|
|
198
|
+
if (!logger)
|
|
199
|
+
return;
|
|
200
|
+
const logEntry = {
|
|
201
|
+
sessionId,
|
|
202
|
+
messageId,
|
|
203
|
+
timestamp: new Date().toISOString(),
|
|
204
|
+
prompt,
|
|
205
|
+
response,
|
|
206
|
+
duration: Date.now() - startTime,
|
|
207
|
+
usage: usage ? { inputTokens: usage.inputTokens, outputTokens: usage.outputTokens } : undefined,
|
|
208
|
+
mcpCalls,
|
|
209
|
+
cliCalls,
|
|
210
|
+
error,
|
|
211
|
+
};
|
|
212
|
+
logger.log(logEntry).catch((err) => {
|
|
213
|
+
fastify.log.warn('Failed to write interaction log: %s', err);
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
//# sourceMappingURL=chat.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat.js","sourceRoot":"","sources":["../../src/routes/chat.ts"],"names":[],"mappings":"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"}
|
package/dist/routes/index.d.ts
CHANGED
|
@@ -4,4 +4,6 @@
|
|
|
4
4
|
export { registerDataRoutes } from './data.js';
|
|
5
5
|
export { registerHealthRoute } from './health.js';
|
|
6
6
|
export { registerUploadRoutes, saveUploadedFile } from './upload.js';
|
|
7
|
+
export { registerChatRoutes } from './chat.js';
|
|
8
|
+
export type { ChatRouteOptions } from './chat.js';
|
|
7
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;AAClD,OAAO,EAAE,oBAAoB,EAAE,gBAAgB,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"}
|
package/dist/routes/index.js
CHANGED
package/dist/routes/index.js.map
CHANGED
|
@@ -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;AAClD,OAAO,EAAE,oBAAoB,EAAE,gBAAgB,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"}
|
package/dist/routes/upload.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Upload Routes - File upload and static serving
|
|
3
3
|
*
|
|
4
|
-
* Handles base64 file uploads via
|
|
4
|
+
* Handles base64 file uploads via SSE chat and provides
|
|
5
5
|
* static file serving for uploaded files.
|
|
6
6
|
*/
|
|
7
7
|
import type { FastifyInstance } from 'fastify';
|
package/dist/routes/upload.js
CHANGED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@loom-framework/backend",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
4
|
-
"description": "Loom framework backend - AI communication,
|
|
3
|
+
"version": "0.1.0-alpha.4",
|
|
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.3"
|
|
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,33 +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
|
-
projectRoot: string;
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* Register WebSocket route and event handlers on a Fastify instance
|
|
21
|
-
*/
|
|
22
|
-
export declare function registerWebSocket(fastify: FastifyInstance, options: WebSocketHandlerOptions): void;
|
|
23
|
-
/**
|
|
24
|
-
* Resolve prompt from AI button configuration.
|
|
25
|
-
* - Static buttons: return prompt directly
|
|
26
|
-
* - Template buttons: substitute {{var}} with context values
|
|
27
|
-
* Returns null if button not found or context is incomplete.
|
|
28
|
-
*/
|
|
29
|
-
export declare function resolveButtonPrompt(buttonId: string, context: Record<string, string> | undefined, config: LoomConfig): {
|
|
30
|
-
prompt: string;
|
|
31
|
-
error?: string;
|
|
32
|
-
} | null;
|
|
33
|
-
//# 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,EAMX,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,cAAc,EAAuB,MAAM,0BAA0B,CAAC;AAC/E,OAAO,EAAE,mBAAmB,EAAyB,MAAM,qBAAqB,CAAC;AAGjF,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;IAC7B,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,eAAe,EACxB,OAAO,EAAE,uBAAuB,GAC/B,IAAI,CA0CN;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"}
|
package/dist/websocket/index.js
DELETED
|
@@ -1,373 +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 { saveUploadedFile } from '../routes/upload.js';
|
|
9
|
-
/**
|
|
10
|
-
* Register WebSocket route and event handlers on a Fastify instance
|
|
11
|
-
*/
|
|
12
|
-
export function registerWebSocket(fastify, options) {
|
|
13
|
-
const { engine, sessionManager, config, logger, projectRoot } = options;
|
|
14
|
-
fastify.register(async function (instance) {
|
|
15
|
-
instance.get('/ws', { websocket: true }, (socket, _req) => {
|
|
16
|
-
instance.log.info('WebSocket client connected');
|
|
17
|
-
// Send welcome message on connection
|
|
18
|
-
try {
|
|
19
|
-
socket.send(JSON.stringify({
|
|
20
|
-
type: 'welcome',
|
|
21
|
-
content: '欢迎使用 Loom AI 助手!您可以向我提问或使用 AI 按钮触发功能。',
|
|
22
|
-
message_id: `welcome_${Date.now()}`,
|
|
23
|
-
session_id: '',
|
|
24
|
-
}));
|
|
25
|
-
}
|
|
26
|
-
catch (err) {
|
|
27
|
-
instance.log.error('Error sending welcome message: %s', err);
|
|
28
|
-
}
|
|
29
|
-
socket.on('message', async (raw) => {
|
|
30
|
-
try {
|
|
31
|
-
const event = JSON.parse(raw.toString());
|
|
32
|
-
// Handle heartbeat ping
|
|
33
|
-
if (event.type === 'ping') {
|
|
34
|
-
socket.send(JSON.stringify({ type: 'pong', timestamp: Date.now() }));
|
|
35
|
-
return;
|
|
36
|
-
}
|
|
37
|
-
await handleEvent(event, socket, instance, engine, sessionManager, config, logger, projectRoot);
|
|
38
|
-
}
|
|
39
|
-
catch (err) {
|
|
40
|
-
instance.log.error('Error handling WebSocket message: %s', err);
|
|
41
|
-
}
|
|
42
|
-
});
|
|
43
|
-
socket.on('close', () => {
|
|
44
|
-
instance.log.info('WebSocket client disconnected');
|
|
45
|
-
});
|
|
46
|
-
socket.on('error', (err) => {
|
|
47
|
-
instance.log.error('WebSocket error: %s', err);
|
|
48
|
-
});
|
|
49
|
-
});
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Resolve prompt from AI button configuration.
|
|
54
|
-
* - Static buttons: return prompt directly
|
|
55
|
-
* - Template buttons: substitute {{var}} with context values
|
|
56
|
-
* Returns null if button not found or context is incomplete.
|
|
57
|
-
*/
|
|
58
|
-
export function resolveButtonPrompt(buttonId, context, config) {
|
|
59
|
-
const button = config.aiButtons?.find((b) => b.id === buttonId);
|
|
60
|
-
if (!button) {
|
|
61
|
-
return null;
|
|
62
|
-
}
|
|
63
|
-
// Static prompt
|
|
64
|
-
if (button.prompt) {
|
|
65
|
-
return { prompt: button.prompt };
|
|
66
|
-
}
|
|
67
|
-
// Template prompt
|
|
68
|
-
if (button.promptTemplate) {
|
|
69
|
-
const missing = (button.contextVars || []).filter((v) => !context || context[v] === undefined);
|
|
70
|
-
if (missing.length > 0) {
|
|
71
|
-
return {
|
|
72
|
-
prompt: '',
|
|
73
|
-
error: `Missing context variables: ${missing.join(', ')}. Required: ${button.contextVars.join(', ')}`,
|
|
74
|
-
};
|
|
75
|
-
}
|
|
76
|
-
let resolved = button.promptTemplate;
|
|
77
|
-
if (context) {
|
|
78
|
-
for (const [key, value] of Object.entries(context)) {
|
|
79
|
-
resolved = resolved.replace(new RegExp(`\\{\\{${key}\\}\\}`, 'g'), value);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
return { prompt: resolved };
|
|
83
|
-
}
|
|
84
|
-
return null;
|
|
85
|
-
}
|
|
86
|
-
/**
|
|
87
|
-
* Route incoming WebSocket events to their handlers
|
|
88
|
-
*/
|
|
89
|
-
async function handleEvent(event, socket, fastify, engine, sessionManager, config, logger, projectRoot) {
|
|
90
|
-
switch (event.type) {
|
|
91
|
-
case 'user_message':
|
|
92
|
-
await handleUserMessage(event, socket, fastify, engine, sessionManager, config, logger, projectRoot);
|
|
93
|
-
break;
|
|
94
|
-
case 'new_session':
|
|
95
|
-
await handleNewSession(socket, fastify, sessionManager);
|
|
96
|
-
break;
|
|
97
|
-
case 'load_session':
|
|
98
|
-
await handleLoadSession(event, socket, fastify, sessionManager);
|
|
99
|
-
break;
|
|
100
|
-
case 'list_sessions':
|
|
101
|
-
await handleListSessions(socket, fastify, sessionManager);
|
|
102
|
-
break;
|
|
103
|
-
case 'delete_session':
|
|
104
|
-
await handleDeleteSession(event, socket, fastify, sessionManager);
|
|
105
|
-
break;
|
|
106
|
-
default:
|
|
107
|
-
fastify.log.warn('Unknown WebSocket event type: %s', event.type);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
/**
|
|
111
|
-
* Handle user_message: stream AI response back to client
|
|
112
|
-
*/
|
|
113
|
-
async function handleUserMessage(event, socket, fastify, engine, sessionManager, config, logger, projectRoot) {
|
|
114
|
-
const messageId = generateMessageId();
|
|
115
|
-
const startTime = Date.now();
|
|
116
|
-
fastify.log.info('User message on session %s', event.session_id);
|
|
117
|
-
// Handle file uploads from event.files
|
|
118
|
-
const uploadedFiles = [];
|
|
119
|
-
if (event.files && event.files.length > 0 && projectRoot) {
|
|
120
|
-
for (const file of event.files) {
|
|
121
|
-
if (file.content) {
|
|
122
|
-
try {
|
|
123
|
-
const result = await saveUploadedFile(projectRoot, event.session_id, file.name, file.content);
|
|
124
|
-
uploadedFiles.push({ name: file.name, path: result.path });
|
|
125
|
-
}
|
|
126
|
-
catch (err) {
|
|
127
|
-
fastify.log.warn('Failed to save uploaded file %s: %s', file.name, err);
|
|
128
|
-
}
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
// Resolve prompt: AI button or direct content
|
|
133
|
-
let prompt;
|
|
134
|
-
if (event.buttonId) {
|
|
135
|
-
const resolved = resolveButtonPrompt(event.buttonId, event.context, config);
|
|
136
|
-
if (!resolved) {
|
|
137
|
-
socket.send(JSON.stringify({
|
|
138
|
-
type: 'error',
|
|
139
|
-
error: `AI button "${event.buttonId}" not found in configuration`,
|
|
140
|
-
session_id: event.session_id,
|
|
141
|
-
}));
|
|
142
|
-
return;
|
|
143
|
-
}
|
|
144
|
-
if (resolved.error) {
|
|
145
|
-
socket.send(JSON.stringify({
|
|
146
|
-
type: 'error',
|
|
147
|
-
error: resolved.error,
|
|
148
|
-
session_id: event.session_id,
|
|
149
|
-
}));
|
|
150
|
-
return;
|
|
151
|
-
}
|
|
152
|
-
prompt = resolved.prompt;
|
|
153
|
-
fastify.log.info('AI button "%s" resolved to prompt: %s', event.buttonId, prompt.slice(0, 80));
|
|
154
|
-
}
|
|
155
|
-
else {
|
|
156
|
-
prompt = event.content;
|
|
157
|
-
}
|
|
158
|
-
// Get or create session
|
|
159
|
-
const session = await sessionManager.getOrCreate(event.session_id);
|
|
160
|
-
// Add user message to session
|
|
161
|
-
const userMsg = {
|
|
162
|
-
id: messageId,
|
|
163
|
-
role: 'user',
|
|
164
|
-
content: prompt,
|
|
165
|
-
timestamp: new Date().toISOString(),
|
|
166
|
-
};
|
|
167
|
-
await sessionManager.addMessages(event.session_id, [userMsg]);
|
|
168
|
-
// Send initial "processing" chunk
|
|
169
|
-
sendChunk(socket, '正在处理...', messageId, event.session_id, false);
|
|
170
|
-
// Call AI engine
|
|
171
|
-
let aiContent = '';
|
|
172
|
-
let claudeSessionId;
|
|
173
|
-
let usage;
|
|
174
|
-
try {
|
|
175
|
-
for await (const chunk of engine.call(prompt, {
|
|
176
|
-
sessionId: event.session_id,
|
|
177
|
-
resumeSessionId: session.claudeSessionId,
|
|
178
|
-
files: uploadedFiles.length > 0 ? uploadedFiles : undefined,
|
|
179
|
-
})) {
|
|
180
|
-
if (chunk.type === 'content' && chunk.content) {
|
|
181
|
-
aiContent += chunk.content;
|
|
182
|
-
sendChunk(socket, chunk.content, messageId, event.session_id, false);
|
|
183
|
-
}
|
|
184
|
-
else if (chunk.type === 'session_info') {
|
|
185
|
-
claudeSessionId = chunk.sessionId;
|
|
186
|
-
if (chunk.usage)
|
|
187
|
-
usage = chunk.usage;
|
|
188
|
-
}
|
|
189
|
-
else if (chunk.type === 'error' && chunk.error) {
|
|
190
|
-
fastify.log.error('AI engine error: %s', chunk.error);
|
|
191
|
-
sendChunk(socket, `\n\nError: ${chunk.error}`, messageId, event.session_id, false);
|
|
192
|
-
}
|
|
193
|
-
else if (chunk.type === 'tool_call') {
|
|
194
|
-
// Forward tool call events to frontend
|
|
195
|
-
const toolCallEvent = {
|
|
196
|
-
type: 'tool_call',
|
|
197
|
-
tool: chunk.toolName || 'unknown',
|
|
198
|
-
status: 'started',
|
|
199
|
-
};
|
|
200
|
-
socket.send(JSON.stringify(toolCallEvent));
|
|
201
|
-
}
|
|
202
|
-
else if (chunk.type === 'tool_result') {
|
|
203
|
-
// Forward tool result events to frontend
|
|
204
|
-
const toolResultEvent = {
|
|
205
|
-
type: 'tool_call',
|
|
206
|
-
tool: chunk.toolName || 'unknown',
|
|
207
|
-
status: 'completed',
|
|
208
|
-
result: chunk.toolResult,
|
|
209
|
-
};
|
|
210
|
-
socket.send(JSON.stringify(toolResultEvent));
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
catch (error) {
|
|
215
|
-
fastify.log.error('AI engine exception: %s', error);
|
|
216
|
-
recordLog(logger, event.session_id, messageId, prompt, '', startTime, [], [], error instanceof Error ? error.message : String(error), fastify);
|
|
217
|
-
sendComplete(socket, `\n\nProcessing error: ${error}`, messageId, event.session_id, usage);
|
|
218
|
-
return;
|
|
219
|
-
}
|
|
220
|
-
// Send completion event
|
|
221
|
-
const completePayload = {
|
|
222
|
-
type: 'assistant_complete',
|
|
223
|
-
content: aiContent || '(empty response)',
|
|
224
|
-
message_id: messageId,
|
|
225
|
-
session_id: event.session_id,
|
|
226
|
-
is_complete: true,
|
|
227
|
-
};
|
|
228
|
-
if (claudeSessionId) {
|
|
229
|
-
completePayload.claude_session_id = claudeSessionId;
|
|
230
|
-
}
|
|
231
|
-
if (usage) {
|
|
232
|
-
completePayload.usage = usage;
|
|
233
|
-
}
|
|
234
|
-
socket.send(JSON.stringify(completePayload));
|
|
235
|
-
// Persist assistant message to session
|
|
236
|
-
const assistantMsg = {
|
|
237
|
-
id: messageId,
|
|
238
|
-
role: 'assistant',
|
|
239
|
-
content: aiContent || '(empty response)',
|
|
240
|
-
timestamp: new Date().toISOString(),
|
|
241
|
-
};
|
|
242
|
-
await sessionManager.addMessages(event.session_id, [assistantMsg], claudeSessionId, usage);
|
|
243
|
-
// Record interaction log
|
|
244
|
-
recordLog(logger, event.session_id, messageId, prompt, aiContent || '(empty response)', startTime, [], [], undefined, fastify, usage);
|
|
245
|
-
}
|
|
246
|
-
/**
|
|
247
|
-
* Handle new_session event
|
|
248
|
-
*/
|
|
249
|
-
async function handleNewSession(socket, fastify, sessionManager) {
|
|
250
|
-
const session = await sessionManager.createSession();
|
|
251
|
-
fastify.log.info('Created new session: %s', session.id);
|
|
252
|
-
socket.send(JSON.stringify({
|
|
253
|
-
type: 'session_created',
|
|
254
|
-
session_id: session.id,
|
|
255
|
-
session: {
|
|
256
|
-
id: session.id,
|
|
257
|
-
title: session.title,
|
|
258
|
-
createdAt: session.createdAt,
|
|
259
|
-
updatedAt: session.updatedAt,
|
|
260
|
-
messages: [],
|
|
261
|
-
},
|
|
262
|
-
}));
|
|
263
|
-
}
|
|
264
|
-
/**
|
|
265
|
-
* Handle load_session event
|
|
266
|
-
*/
|
|
267
|
-
async function handleLoadSession(event, socket, fastify, sessionManager) {
|
|
268
|
-
const session = await sessionManager.readSession(event.session_id);
|
|
269
|
-
if (session) {
|
|
270
|
-
fastify.log.info('Loaded session: %s', event.session_id);
|
|
271
|
-
socket.send(JSON.stringify({
|
|
272
|
-
type: 'session_loaded',
|
|
273
|
-
session_id: event.session_id,
|
|
274
|
-
session: {
|
|
275
|
-
id: session.id,
|
|
276
|
-
title: session.title,
|
|
277
|
-
createdAt: session.createdAt,
|
|
278
|
-
updatedAt: session.updatedAt,
|
|
279
|
-
messages: session.messages,
|
|
280
|
-
usage: session.usage,
|
|
281
|
-
},
|
|
282
|
-
}));
|
|
283
|
-
}
|
|
284
|
-
else {
|
|
285
|
-
fastify.log.warn('Session not found: %s', event.session_id);
|
|
286
|
-
socket.send(JSON.stringify({
|
|
287
|
-
type: 'error',
|
|
288
|
-
error: 'Session not found',
|
|
289
|
-
session_id: event.session_id,
|
|
290
|
-
}));
|
|
291
|
-
}
|
|
292
|
-
}
|
|
293
|
-
/**
|
|
294
|
-
* Handle list_sessions event
|
|
295
|
-
*/
|
|
296
|
-
async function handleListSessions(socket, _fastify, sessionManager) {
|
|
297
|
-
const sessions = await sessionManager.listSessions();
|
|
298
|
-
socket.send(JSON.stringify({
|
|
299
|
-
type: 'sessions_list',
|
|
300
|
-
sessions: sessions.map((s) => ({
|
|
301
|
-
id: s.id,
|
|
302
|
-
title: s.title,
|
|
303
|
-
createdAt: s.createdAt,
|
|
304
|
-
updatedAt: s.updatedAt,
|
|
305
|
-
messageCount: s.messages.length,
|
|
306
|
-
})),
|
|
307
|
-
}));
|
|
308
|
-
}
|
|
309
|
-
/**
|
|
310
|
-
* Handle delete_session event
|
|
311
|
-
*/
|
|
312
|
-
async function handleDeleteSession(event, socket, fastify, sessionManager) {
|
|
313
|
-
const success = await sessionManager.deleteSession(event.session_id);
|
|
314
|
-
if (success) {
|
|
315
|
-
fastify.log.info('Deleted session: %s', event.session_id);
|
|
316
|
-
socket.send(JSON.stringify({
|
|
317
|
-
type: 'session_deleted',
|
|
318
|
-
session_id: event.session_id,
|
|
319
|
-
}));
|
|
320
|
-
}
|
|
321
|
-
else {
|
|
322
|
-
socket.send(JSON.stringify({
|
|
323
|
-
type: 'error',
|
|
324
|
-
error: 'Failed to delete session',
|
|
325
|
-
session_id: event.session_id,
|
|
326
|
-
}));
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
|
-
// ── Helpers ──
|
|
330
|
-
function sendChunk(socket, content, messageId, sessionId, isComplete) {
|
|
331
|
-
const event = {
|
|
332
|
-
type: 'assistant_chunk',
|
|
333
|
-
content,
|
|
334
|
-
message_id: messageId,
|
|
335
|
-
session_id: sessionId,
|
|
336
|
-
is_complete: isComplete,
|
|
337
|
-
};
|
|
338
|
-
socket.send(JSON.stringify(event));
|
|
339
|
-
}
|
|
340
|
-
function sendComplete(socket, content, messageId, sessionId, usage) {
|
|
341
|
-
const event = {
|
|
342
|
-
type: 'assistant_complete',
|
|
343
|
-
content,
|
|
344
|
-
message_id: messageId,
|
|
345
|
-
session_id: sessionId,
|
|
346
|
-
is_complete: true,
|
|
347
|
-
usage,
|
|
348
|
-
};
|
|
349
|
-
socket.send(JSON.stringify(event));
|
|
350
|
-
}
|
|
351
|
-
function generateMessageId() {
|
|
352
|
-
return `msg_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`;
|
|
353
|
-
}
|
|
354
|
-
function recordLog(logger, sessionId, messageId, prompt, response, startTime, mcpCalls, cliCalls, error, fastify, usage) {
|
|
355
|
-
if (!logger)
|
|
356
|
-
return;
|
|
357
|
-
const logEntry = {
|
|
358
|
-
sessionId,
|
|
359
|
-
messageId,
|
|
360
|
-
timestamp: new Date().toISOString(),
|
|
361
|
-
prompt,
|
|
362
|
-
response,
|
|
363
|
-
duration: Date.now() - startTime,
|
|
364
|
-
usage: usage ? { inputTokens: usage.inputTokens, outputTokens: usage.outputTokens } : undefined,
|
|
365
|
-
mcpCalls,
|
|
366
|
-
cliCalls,
|
|
367
|
-
error,
|
|
368
|
-
};
|
|
369
|
-
logger.log(logEntry).catch((err) => {
|
|
370
|
-
fastify.log.warn('Failed to write interaction log: %s', err);
|
|
371
|
-
});
|
|
372
|
-
}
|
|
373
|
-
//# 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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"}
|