@wrongstack/webui 0.1.9 → 0.2.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/dist/assets/index-C1jTV4WR.js +609 -0
- package/dist/assets/index-CRAjL4S_.css +1 -0
- package/dist/index.css +25 -0
- package/dist/index.css.map +1 -1
- package/dist/index.html +2 -2
- package/dist/index.js +4920 -4595
- package/dist/index.js.map +1 -1
- package/dist/server/entry.js +98 -33
- package/dist/server/entry.js.map +1 -1
- package/dist/server/index.js +98 -33
- package/dist/server/index.js.map +1 -1
- package/package.json +4 -4
- package/dist/assets/index-DfJLWoIU.css +0 -1
- package/dist/assets/index-Dt6Hlw_3.js +0 -607
package/dist/server/entry.js
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
import * as fs from "fs/promises";
|
|
4
4
|
import * as os from "os";
|
|
5
5
|
import * as path from "path";
|
|
6
|
-
import { WebSocketServer, WebSocket } from "ws";
|
|
7
6
|
import {
|
|
8
7
|
Agent,
|
|
9
8
|
AutoCompactionMiddleware,
|
|
@@ -14,6 +13,7 @@ import {
|
|
|
14
13
|
DefaultErrorHandler,
|
|
15
14
|
DefaultLogger,
|
|
16
15
|
DefaultMemoryStore,
|
|
16
|
+
DefaultModeStore,
|
|
17
17
|
DefaultModelsRegistry,
|
|
18
18
|
DefaultPathResolver,
|
|
19
19
|
DefaultPermissionPolicy,
|
|
@@ -22,25 +22,22 @@ import {
|
|
|
22
22
|
DefaultSecretVault,
|
|
23
23
|
DefaultSessionStore,
|
|
24
24
|
DefaultSkillLoader,
|
|
25
|
-
DefaultModeStore,
|
|
26
25
|
DefaultSystemPromptBuilder,
|
|
27
26
|
DefaultTokenCounter,
|
|
28
27
|
EventBus,
|
|
29
28
|
HybridCompactor,
|
|
30
29
|
ProviderRegistry,
|
|
31
|
-
ToolRegistry,
|
|
32
30
|
TOKENS,
|
|
33
|
-
|
|
31
|
+
ToolRegistry,
|
|
34
32
|
atomicWrite,
|
|
33
|
+
createDefaultPipelines,
|
|
35
34
|
migratePlaintextSecrets,
|
|
36
35
|
resolveWstackPaths
|
|
37
36
|
} from "@wrongstack/core";
|
|
38
|
-
import {
|
|
39
|
-
|
|
40
|
-
makeProviderFromConfig
|
|
41
|
-
} from "@wrongstack/providers";
|
|
37
|
+
import { buildProviderFactoriesFromRegistry, makeProviderFromConfig } from "@wrongstack/providers";
|
|
38
|
+
import { forgetTool, rememberTool } from "@wrongstack/tools";
|
|
42
39
|
import { builtinTools } from "@wrongstack/tools/builtin";
|
|
43
|
-
import {
|
|
40
|
+
import { WebSocket, WebSocketServer } from "ws";
|
|
44
41
|
async function bootConfig() {
|
|
45
42
|
const cwd = process.cwd();
|
|
46
43
|
const pathResolver = new DefaultPathResolver(cwd);
|
|
@@ -99,11 +96,14 @@ async function startWebUI(opts = {}) {
|
|
|
99
96
|
container.bind(TOKENS.RetryPolicy, () => new DefaultRetryPolicy());
|
|
100
97
|
container.bind(TOKENS.ErrorHandler, () => new DefaultErrorHandler());
|
|
101
98
|
container.bind(TOKENS.ModelsRegistry, () => modelsRegistry);
|
|
102
|
-
container.bind(
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
99
|
+
container.bind(
|
|
100
|
+
TOKENS.PermissionPolicy,
|
|
101
|
+
() => new DefaultPermissionPolicy({
|
|
102
|
+
trustFile: wpaths.projectTrust,
|
|
103
|
+
yolo: false,
|
|
104
|
+
promptDelegate: void 0
|
|
105
|
+
})
|
|
106
|
+
);
|
|
107
107
|
const providerRegistry = new ProviderRegistry();
|
|
108
108
|
try {
|
|
109
109
|
const factories = await buildProviderFactoriesFromRegistry({
|
|
@@ -254,10 +254,24 @@ async function startWebUI(opts = {}) {
|
|
|
254
254
|
mode: modeId
|
|
255
255
|
};
|
|
256
256
|
}
|
|
257
|
-
const
|
|
258
|
-
|
|
257
|
+
const verifyClient = (info) => {
|
|
258
|
+
const origin = info.origin;
|
|
259
|
+
if (!origin) return true;
|
|
260
|
+
try {
|
|
261
|
+
const { hostname } = new URL(origin);
|
|
262
|
+
return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "::1";
|
|
263
|
+
} catch {
|
|
264
|
+
return false;
|
|
265
|
+
}
|
|
266
|
+
};
|
|
267
|
+
const wssPrimary = new WebSocketServer({
|
|
268
|
+
port: wsPort2,
|
|
269
|
+
host: wsHost2,
|
|
270
|
+
verifyClient
|
|
271
|
+
});
|
|
272
|
+
const wssSecondary = wsHost2 === "127.0.0.1" ? new WebSocketServer({ port: wsPort2, host: "::1", verifyClient }) : null;
|
|
259
273
|
const clients = /* @__PURE__ */ new Map();
|
|
260
|
-
let
|
|
274
|
+
let runLock = null;
|
|
261
275
|
console.log(
|
|
262
276
|
`[WebUI] WebSocket server running on ws://${wsHost2}:${wsPort2}` + (wssSecondary ? ` (and ws://[::1]:${wsPort2})` : "")
|
|
263
277
|
);
|
|
@@ -271,6 +285,9 @@ async function startWebUI(opts = {}) {
|
|
|
271
285
|
events.on("provider.text_delta", (e) => {
|
|
272
286
|
broadcast({ type: "provider.text_delta", payload: { text: e.text, messageId: "current" } });
|
|
273
287
|
});
|
|
288
|
+
events.on("provider.thinking_delta", (e) => {
|
|
289
|
+
broadcast({ type: "provider.thinking_delta", payload: { text: e.text } });
|
|
290
|
+
});
|
|
274
291
|
events.on("tool.started", (e) => {
|
|
275
292
|
broadcast({
|
|
276
293
|
type: "tool.started",
|
|
@@ -392,10 +409,20 @@ async function startWebUI(opts = {}) {
|
|
|
392
409
|
switch (msg.type) {
|
|
393
410
|
case "user_message": {
|
|
394
411
|
const content = msg.payload.content;
|
|
395
|
-
|
|
396
|
-
|
|
412
|
+
if (runLock) {
|
|
413
|
+
send(ws, {
|
|
414
|
+
type: "error",
|
|
415
|
+
payload: {
|
|
416
|
+
phase: "user_message",
|
|
417
|
+
message: "Agent is already processing a request. Wait for the current run to finish."
|
|
418
|
+
}
|
|
419
|
+
});
|
|
420
|
+
break;
|
|
421
|
+
}
|
|
422
|
+
runLock = new AbortController();
|
|
423
|
+
const thisRun = runLock;
|
|
397
424
|
try {
|
|
398
|
-
const result = await agent.run(content, { signal:
|
|
425
|
+
const result = await agent.run(content, { signal: thisRun.signal });
|
|
399
426
|
send(ws, {
|
|
400
427
|
type: "run.result",
|
|
401
428
|
payload: {
|
|
@@ -418,12 +445,14 @@ async function startWebUI(opts = {}) {
|
|
|
418
445
|
}
|
|
419
446
|
});
|
|
420
447
|
} finally {
|
|
421
|
-
|
|
448
|
+
if (runLock === thisRun) {
|
|
449
|
+
runLock = null;
|
|
450
|
+
}
|
|
422
451
|
}
|
|
423
452
|
break;
|
|
424
453
|
}
|
|
425
454
|
case "abort":
|
|
426
|
-
|
|
455
|
+
runLock?.abort();
|
|
427
456
|
broadcast({ type: "error", payload: { phase: "abort", message: "User aborted" } });
|
|
428
457
|
break;
|
|
429
458
|
case "ping":
|
|
@@ -469,10 +498,7 @@ async function startWebUI(opts = {}) {
|
|
|
469
498
|
return String(c);
|
|
470
499
|
}
|
|
471
500
|
};
|
|
472
|
-
const sysTokens = context.systemPrompt.reduce(
|
|
473
|
-
(acc, b) => acc + estimate(b.text ?? ""),
|
|
474
|
-
0
|
|
475
|
-
);
|
|
501
|
+
const sysTokens = context.systemPrompt.reduce((acc, b) => acc + estimate(b.text ?? ""), 0);
|
|
476
502
|
const tools = toolRegistry.list();
|
|
477
503
|
const toolBreakdown = tools.map((t) => {
|
|
478
504
|
const schema = t.inputSchema ?? {};
|
|
@@ -512,7 +538,11 @@ async function startWebUI(opts = {}) {
|
|
|
512
538
|
total,
|
|
513
539
|
systemPrompt: sysTokens,
|
|
514
540
|
tools: { total: toolTokens, count: tools.length, breakdown: toolBreakdown },
|
|
515
|
-
messages: {
|
|
541
|
+
messages: {
|
|
542
|
+
total: msgTokens,
|
|
543
|
+
count: context.messages.length,
|
|
544
|
+
breakdown: messageBreakdown
|
|
545
|
+
}
|
|
516
546
|
}
|
|
517
547
|
});
|
|
518
548
|
break;
|
|
@@ -787,7 +817,11 @@ async function startWebUI(opts = {}) {
|
|
|
787
817
|
const { text, scope } = msg.payload;
|
|
788
818
|
try {
|
|
789
819
|
const removed = await memoryStore.forget(text, scope ?? "project-memory");
|
|
790
|
-
sendResult(
|
|
820
|
+
sendResult(
|
|
821
|
+
ws,
|
|
822
|
+
removed > 0,
|
|
823
|
+
removed > 0 ? `Removed ${removed} entr${removed === 1 ? "y" : "ies"}` : "No matching entries"
|
|
824
|
+
);
|
|
791
825
|
} catch (err) {
|
|
792
826
|
sendResult(ws, false, err instanceof Error ? err.message : String(err));
|
|
793
827
|
}
|
|
@@ -820,7 +854,11 @@ async function startWebUI(opts = {}) {
|
|
|
820
854
|
} catch (err) {
|
|
821
855
|
send(ws, {
|
|
822
856
|
type: "skills.list",
|
|
823
|
-
payload: {
|
|
857
|
+
payload: {
|
|
858
|
+
skills: [],
|
|
859
|
+
enabled: true,
|
|
860
|
+
error: err instanceof Error ? err.message : String(err)
|
|
861
|
+
}
|
|
824
862
|
});
|
|
825
863
|
}
|
|
826
864
|
break;
|
|
@@ -895,7 +933,8 @@ async function startWebUI(opts = {}) {
|
|
|
895
933
|
for (const e of entries) {
|
|
896
934
|
if (results.length >= 600) return;
|
|
897
935
|
if (e.name.startsWith(".") && e.name !== ".wrongstack" && e.name !== ".env.example") {
|
|
898
|
-
if (e.name !== ".gitignore" && e.name !== ".eslintrc" && e.name !== ".prettierrc")
|
|
936
|
+
if (e.name !== ".gitignore" && e.name !== ".eslintrc" && e.name !== ".prettierrc")
|
|
937
|
+
continue;
|
|
899
938
|
}
|
|
900
939
|
const childRel = rel ? `${rel}/${e.name}` : e.name;
|
|
901
940
|
if (e.isDirectory()) {
|
|
@@ -949,7 +988,11 @@ async function startWebUI(opts = {}) {
|
|
|
949
988
|
} catch (err) {
|
|
950
989
|
send(ws, {
|
|
951
990
|
type: "modes.list",
|
|
952
|
-
payload: {
|
|
991
|
+
payload: {
|
|
992
|
+
modes: [],
|
|
993
|
+
activeId: "default",
|
|
994
|
+
error: err instanceof Error ? err.message : String(err)
|
|
995
|
+
}
|
|
953
996
|
});
|
|
954
997
|
}
|
|
955
998
|
break;
|
|
@@ -965,6 +1008,22 @@ async function startWebUI(opts = {}) {
|
|
|
965
1008
|
await modeStore.setActiveMode(id);
|
|
966
1009
|
}
|
|
967
1010
|
modeId = id;
|
|
1011
|
+
const modePrompt2 = id === "default" ? "" : (await modeStore.getMode(id))?.prompt ?? "";
|
|
1012
|
+
const freshBuilder = new DefaultSystemPromptBuilder({
|
|
1013
|
+
memoryStore,
|
|
1014
|
+
skillLoader,
|
|
1015
|
+
modeStore,
|
|
1016
|
+
modeId: id,
|
|
1017
|
+
modePrompt: modePrompt2,
|
|
1018
|
+
modelCapabilities
|
|
1019
|
+
});
|
|
1020
|
+
context.systemPrompt = await freshBuilder.build({
|
|
1021
|
+
cwd: projectRoot,
|
|
1022
|
+
projectRoot,
|
|
1023
|
+
tools: toolRegistry.list(),
|
|
1024
|
+
provider: config.provider,
|
|
1025
|
+
model: config.model
|
|
1026
|
+
});
|
|
968
1027
|
sendResult(ws, true, `Switched to mode "${id}"`);
|
|
969
1028
|
broadcast({
|
|
970
1029
|
type: "session.start",
|
|
@@ -1126,7 +1185,9 @@ async function startWebUI(opts = {}) {
|
|
|
1126
1185
|
baseUrl: payload.baseUrl
|
|
1127
1186
|
};
|
|
1128
1187
|
if (payload.apiKey) {
|
|
1129
|
-
newProv.apiKeys = [
|
|
1188
|
+
newProv.apiKeys = [
|
|
1189
|
+
{ label: "default", apiKey: payload.apiKey, createdAt: (/* @__PURE__ */ new Date()).toISOString() }
|
|
1190
|
+
];
|
|
1130
1191
|
newProv.activeKey = "default";
|
|
1131
1192
|
}
|
|
1132
1193
|
providers[payload.id] = newProv;
|
|
@@ -1153,7 +1214,11 @@ async function startWebUI(opts = {}) {
|
|
|
1153
1214
|
const shutdown = async () => {
|
|
1154
1215
|
console.log("[WebUI] Shutting down...");
|
|
1155
1216
|
try {
|
|
1156
|
-
await session.append({
|
|
1217
|
+
await session.append({
|
|
1218
|
+
type: "session_end",
|
|
1219
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1220
|
+
usage: tokenCounter.total()
|
|
1221
|
+
});
|
|
1157
1222
|
await session.close();
|
|
1158
1223
|
} catch (e) {
|
|
1159
1224
|
console.warn("[WebUI] Error closing session:", e);
|