@lelouchhe/webagent 0.2.1 → 0.2.2
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/lib/bridge.js +284 -0
- package/lib/config.js +62 -0
- package/lib/daemon.js +278 -0
- package/lib/event-handler.js +106 -0
- package/lib/push-service.js +166 -0
- package/lib/routes.js +945 -0
- package/lib/server.js +82 -0
- package/lib/session-manager.js +277 -0
- package/lib/shared/constants.js +17 -0
- package/lib/sse-manager.js +80 -0
- package/lib/store.js +174 -0
- package/lib/title-service.js +74 -0
- package/lib/types.js +13 -0
- package/package.json +4 -3
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
const TITLE_MODEL = "claude-haiku-4.5";
|
|
2
|
+
export class TitleService {
|
|
3
|
+
titleSessionId = null;
|
|
4
|
+
activeSourceSessions = new Set();
|
|
5
|
+
cancelledSourceSessions = new Set();
|
|
6
|
+
defaultCwd;
|
|
7
|
+
store;
|
|
8
|
+
sessions;
|
|
9
|
+
constructor(store, sessions, defaultCwd) {
|
|
10
|
+
this.store = store;
|
|
11
|
+
this.sessions = sessions;
|
|
12
|
+
this.defaultCwd = defaultCwd;
|
|
13
|
+
}
|
|
14
|
+
/** Generate a title for the session (non-blocking, fire-and-forget). */
|
|
15
|
+
generate(bridge, userMessage, sessionId, onTitle) {
|
|
16
|
+
if (this.sessions.sessionHasTitle.has(sessionId) || this.activeSourceSessions.has(sessionId))
|
|
17
|
+
return;
|
|
18
|
+
this._generate(bridge, userMessage, sessionId).then((title) => {
|
|
19
|
+
if (title && onTitle)
|
|
20
|
+
onTitle(title);
|
|
21
|
+
}).catch((err) => {
|
|
22
|
+
console.error(`[title] generation failed:`, err);
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
async _generate(bridge, userMessage, sessionId) {
|
|
26
|
+
this.activeSourceSessions.add(sessionId);
|
|
27
|
+
const tsId = await this.ensureTitleSession(bridge);
|
|
28
|
+
if (!tsId) {
|
|
29
|
+
this.activeSourceSessions.delete(sessionId);
|
|
30
|
+
this.cancelledSourceSessions.delete(sessionId);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
try {
|
|
34
|
+
const prompt = `Generate a short title (max 30 chars, no quotes) for a chat that starts with this message. Reply with ONLY the title, nothing else:\n\n${userMessage.slice(0, 500)}`;
|
|
35
|
+
const title = await bridge.promptForText(tsId, prompt);
|
|
36
|
+
if (!title || this.cancelledSourceSessions.has(sessionId))
|
|
37
|
+
return;
|
|
38
|
+
// User may have set a title while generation was in flight
|
|
39
|
+
if (this.sessions.sessionHasTitle.has(sessionId))
|
|
40
|
+
return;
|
|
41
|
+
const cleaned = title.replace(/^["']|["']$/g, "").trim().slice(0, 30);
|
|
42
|
+
if (!cleaned)
|
|
43
|
+
return;
|
|
44
|
+
this.store.updateSessionTitle(sessionId, cleaned);
|
|
45
|
+
this.sessions.sessionHasTitle.add(sessionId);
|
|
46
|
+
return cleaned;
|
|
47
|
+
}
|
|
48
|
+
finally {
|
|
49
|
+
this.activeSourceSessions.delete(sessionId);
|
|
50
|
+
this.cancelledSourceSessions.delete(sessionId);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
async cancel(sessionId, bridge) {
|
|
54
|
+
this.cancelledSourceSessions.add(sessionId);
|
|
55
|
+
if (!this.titleSessionId || !this.activeSourceSessions.has(sessionId))
|
|
56
|
+
return;
|
|
57
|
+
await bridge.cancel(this.titleSessionId);
|
|
58
|
+
}
|
|
59
|
+
/** Ensure the dedicated title session exists. Returns session ID or null. */
|
|
60
|
+
async ensureTitleSession(bridge) {
|
|
61
|
+
if (this.titleSessionId)
|
|
62
|
+
return this.titleSessionId;
|
|
63
|
+
try {
|
|
64
|
+
const id = await bridge.newSession(this.defaultCwd, { silent: true });
|
|
65
|
+
this.sessions.liveSessions.add(id);
|
|
66
|
+
await bridge.setConfigOption(id, "model", TITLE_MODEL).catch(() => []);
|
|
67
|
+
this.titleSessionId = id;
|
|
68
|
+
return id;
|
|
69
|
+
}
|
|
70
|
+
catch {
|
|
71
|
+
return null;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
package/lib/types.js
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lelouchhe/webagent",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "A terminal-style web UI for ACP-compatible agents",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -30,10 +30,11 @@
|
|
|
30
30
|
"config.toml"
|
|
31
31
|
],
|
|
32
32
|
"scripts": {
|
|
33
|
-
"
|
|
33
|
+
"compile": "tsc -p tsconfig.build.json",
|
|
34
|
+
"prepublishOnly": "npm run compile && npm run build",
|
|
34
35
|
"build": "node scripts/build.js",
|
|
35
36
|
"start": "node --experimental-strip-types src/server.ts --config config.toml",
|
|
36
|
-
"test": "
|
|
37
|
+
"test": "npm run compile && node --experimental-strip-types --test test/*.test.ts",
|
|
37
38
|
"test:e2e": "playwright test",
|
|
38
39
|
"dev": "node scripts/build.js --watch & node --experimental-strip-types --watch src/server.ts --config config.dev.toml",
|
|
39
40
|
"dev:start": "node scripts/build.js --dev && node --experimental-strip-types src/server.ts --config config.dev.toml &",
|