@schlessera/brain-ui-server 0.15.0 → 0.16.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 +3 -0
- package/dist/agent/backend.d.ts.map +1 -1
- package/dist/agent/backend.js +6 -2
- package/dist/agent/backend.js.map +1 -1
- package/dist/app.d.ts +9 -0
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +37 -6
- package/dist/app.js.map +1 -1
- package/dist/config/env.d.ts +8 -0
- package/dist/config/env.d.ts.map +1 -1
- package/dist/config/env.js +48 -0
- package/dist/config/env.js.map +1 -1
- package/dist/cron/scheduler.d.ts +3 -0
- package/dist/cron/scheduler.d.ts.map +1 -1
- package/dist/cron/scheduler.js +11 -3
- package/dist/cron/scheduler.js.map +1 -1
- package/dist/db/client.d.ts +10 -1
- package/dist/db/client.d.ts.map +1 -1
- package/dist/db/client.js +5 -14
- package/dist/db/client.js.map +1 -1
- package/dist/db/settings.d.ts +2 -1
- package/dist/db/settings.d.ts.map +1 -1
- package/dist/db/settings.js +6 -2
- package/dist/db/settings.js.map +1 -1
- package/dist/index.d.ts +4 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -2
- package/dist/index.js.map +1 -1
- package/dist/middleware/auth.d.ts +3 -2
- package/dist/middleware/auth.d.ts.map +1 -1
- package/dist/middleware/auth.js +28 -9
- package/dist/middleware/auth.js.map +1 -1
- package/dist/middleware/passkeys.d.ts +10 -0
- package/dist/middleware/passkeys.d.ts.map +1 -1
- package/dist/middleware/passkeys.js +19 -3
- package/dist/middleware/passkeys.js.map +1 -1
- package/dist/observability/index.d.ts +73 -0
- package/dist/observability/index.d.ts.map +1 -0
- package/dist/observability/index.js +74 -0
- package/dist/observability/index.js.map +1 -0
- package/dist/observability/loggers.d.ts +62 -0
- package/dist/observability/loggers.d.ts.map +1 -0
- package/dist/observability/loggers.js +109 -0
- package/dist/observability/loggers.js.map +1 -0
- package/dist/observability/meter.d.ts +39 -0
- package/dist/observability/meter.d.ts.map +1 -0
- package/dist/observability/meter.js +95 -0
- package/dist/observability/meter.js.map +1 -0
- package/dist/observability/types.d.ts +67 -0
- package/dist/observability/types.d.ts.map +1 -0
- package/dist/observability/types.js +44 -0
- package/dist/observability/types.js.map +1 -0
- package/dist/routes/brain.d.ts.map +1 -1
- package/dist/routes/brain.js +9 -1
- package/dist/routes/brain.js.map +1 -1
- package/dist/routes/files.d.ts +2 -0
- package/dist/routes/files.d.ts.map +1 -1
- package/dist/routes/files.js +7 -7
- package/dist/routes/files.js.map +1 -1
- package/dist/routes/graph.d.ts +2 -0
- package/dist/routes/graph.d.ts.map +1 -1
- package/dist/routes/graph.js +7 -7
- package/dist/routes/graph.js.map +1 -1
- package/dist/routes/health.d.ts +3 -0
- package/dist/routes/health.d.ts.map +1 -1
- package/dist/routes/health.js +3 -0
- package/dist/routes/health.js.map +1 -1
- package/dist/routes/models.d.ts +3 -0
- package/dist/routes/models.d.ts.map +1 -1
- package/dist/routes/models.js +5 -1
- package/dist/routes/models.js.map +1 -1
- package/dist/routes/render.d.ts +2 -1
- package/dist/routes/render.d.ts.map +1 -1
- package/dist/routes/render.js +2 -2
- package/dist/routes/render.js.map +1 -1
- package/dist/routes/share.d.ts +3 -0
- package/dist/routes/share.d.ts.map +1 -1
- package/dist/routes/share.js +3 -3
- package/dist/routes/share.js.map +1 -1
- package/dist/share/staging.d.ts +3 -2
- package/dist/share/staging.d.ts.map +1 -1
- package/dist/share/staging.js +12 -4
- package/dist/share/staging.js.map +1 -1
- package/dist/voice/keyterm-builder.d.ts +4 -1
- package/dist/voice/keyterm-builder.d.ts.map +1 -1
- package/dist/voice/keyterm-builder.js +13 -6
- package/dist/voice/keyterm-builder.js.map +1 -1
- package/dist/ws/bridge.d.ts.map +1 -1
- package/dist/ws/bridge.js +6 -1
- package/dist/ws/bridge.js.map +1 -1
- package/dist/ws/connection.d.ts +15 -0
- package/dist/ws/connection.d.ts.map +1 -1
- package/dist/ws/connection.js +55 -8
- package/dist/ws/connection.js.map +1 -1
- package/dist/ws/dispatch.d.ts +22 -1
- package/dist/ws/dispatch.d.ts.map +1 -1
- package/dist/ws/dispatch.js +33 -15
- package/dist/ws/dispatch.js.map +1 -1
- package/dist/ws/host.d.ts +37 -0
- package/dist/ws/host.d.ts.map +1 -1
- package/dist/ws/host.js +37 -0
- package/dist/ws/host.js.map +1 -1
- package/dist/ws/rate-limit.d.ts +58 -0
- package/dist/ws/rate-limit.d.ts.map +1 -0
- package/dist/ws/rate-limit.js +62 -0
- package/dist/ws/rate-limit.js.map +1 -0
- package/dist/ws/run-session.d.ts +3 -0
- package/dist/ws/run-session.d.ts.map +1 -1
- package/dist/ws/run-session.js +23 -5
- package/dist/ws/run-session.js.map +1 -1
- package/dist/ws/turns.d.ts +13 -0
- package/dist/ws/turns.d.ts.map +1 -1
- package/dist/ws/turns.js +11 -1
- package/dist/ws/turns.js.map +1 -1
- package/package.json +5 -3
- package/src/agent/backend.ts +8 -6
- package/src/app.ts +46 -6
- package/src/config/env.ts +57 -0
- package/src/cron/scheduler.ts +14 -3
- package/src/db/client.ts +16 -5
- package/src/db/settings.ts +7 -2
- package/src/index.ts +37 -2
- package/src/middleware/auth.ts +30 -14
- package/src/middleware/passkeys.ts +29 -5
- package/src/observability/index.ts +150 -0
- package/src/observability/loggers.ts +174 -0
- package/src/observability/meter.ts +190 -0
- package/src/observability/types.ts +101 -0
- package/src/routes/brain.ts +10 -1
- package/src/routes/files.ts +9 -8
- package/src/routes/graph.ts +9 -8
- package/src/routes/health.ts +7 -0
- package/src/routes/models.ts +8 -5
- package/src/routes/render.ts +3 -2
- package/src/routes/share.ts +6 -3
- package/src/share/staging.ts +18 -4
- package/src/voice/keyterm-builder.ts +17 -8
- package/src/ws/bridge.ts +5 -1
- package/src/ws/connection.ts +63 -12
- package/src/ws/dispatch.ts +44 -15
- package/src/ws/host.ts +54 -0
- package/src/ws/rate-limit.ts +86 -0
- package/src/ws/run-session.ts +26 -7
- package/src/ws/turns.ts +19 -3
package/dist/ws/run-session.js
CHANGED
|
@@ -29,8 +29,11 @@ export async function runSession(host, initial) {
|
|
|
29
29
|
}
|
|
30
30
|
const { backend, profileId: initialProfileId } = target;
|
|
31
31
|
if (target.droppedPin) {
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
host.log.emit({
|
|
33
|
+
severityText: "WARN",
|
|
34
|
+
body: "pinned profile unavailable; running on the default profile",
|
|
35
|
+
attributes: { "session.id": initial.sessionId, profile: target.droppedPin },
|
|
36
|
+
});
|
|
34
37
|
host.sendToClients({
|
|
35
38
|
type: "status",
|
|
36
39
|
status: "thinking",
|
|
@@ -41,6 +44,8 @@ export async function runSession(host, initial) {
|
|
|
41
44
|
const turn = {
|
|
42
45
|
sessionId: initial.sessionId ?? null,
|
|
43
46
|
turnId: crypto.randomUUID(),
|
|
47
|
+
// Only meaningful when the client had no session id to send.
|
|
48
|
+
draftId: initial.sessionId ? null : (initial.draftId ?? null),
|
|
44
49
|
providerId: initialProfileId ?? null,
|
|
45
50
|
backend,
|
|
46
51
|
abortController: new AbortController(),
|
|
@@ -66,7 +71,11 @@ export async function runSession(host, initial) {
|
|
|
66
71
|
const abortController = new AbortController();
|
|
67
72
|
turn.abortController = abortController;
|
|
68
73
|
const timeoutHandle = setTimeout(() => {
|
|
69
|
-
|
|
74
|
+
host.log.emit({
|
|
75
|
+
severityText: "WARN",
|
|
76
|
+
body: "turn timed out",
|
|
77
|
+
attributes: { "timeout.ms": host.turnTimeoutMs },
|
|
78
|
+
});
|
|
70
79
|
abortController.abort();
|
|
71
80
|
// Reject any pending interactive request for this turn too. A bridge
|
|
72
81
|
// that awaits askUser/approval without racing the abort signal would
|
|
@@ -119,7 +128,7 @@ function formatMb(bytes) {
|
|
|
119
128
|
}
|
|
120
129
|
/** Dispatch a chat_message: follow-up to a running session, or a new session. */
|
|
121
130
|
export async function handleChatMessage(host, ws, msg) {
|
|
122
|
-
const { text, attachments, sessionId, providerId: requestedProviderId, client } = msg;
|
|
131
|
+
const { text, attachments, sessionId, providerId: requestedProviderId, client, draftId } = msg;
|
|
123
132
|
const { coordinator } = host;
|
|
124
133
|
const runningTurn = sessionId ? coordinator.bySession.get(sessionId) : undefined;
|
|
125
134
|
if (runningTurn && sessionId) {
|
|
@@ -164,7 +173,15 @@ export async function handleChatMessage(host, ws, msg) {
|
|
|
164
173
|
? `Queue is holding ${formatMb(total)} across ${runningTurn.queue.length} messages (limit ${formatMb(QUEUE_MAX_BYTES)}).`
|
|
165
174
|
: undefined;
|
|
166
175
|
if (detail) {
|
|
167
|
-
|
|
176
|
+
host.log.emit({
|
|
177
|
+
severityText: "WARN",
|
|
178
|
+
body: "session follow-up queue is heavy",
|
|
179
|
+
attributes: {
|
|
180
|
+
"session.id": sessionId,
|
|
181
|
+
size: formatMb(total),
|
|
182
|
+
queued: runningTurn.queue.length,
|
|
183
|
+
},
|
|
184
|
+
});
|
|
168
185
|
}
|
|
169
186
|
host.sendToClients(withSessionId({ type: "status", status: "queued", ...(detail ? { detail } : {}) }, sessionId));
|
|
170
187
|
}
|
|
@@ -190,6 +207,7 @@ export async function handleChatMessage(host, ws, msg) {
|
|
|
190
207
|
attachments,
|
|
191
208
|
providerId: requestedProviderId,
|
|
192
209
|
...(client ? { client } : {}),
|
|
210
|
+
...(draftId ? { draftId } : {}),
|
|
193
211
|
});
|
|
194
212
|
}
|
|
195
213
|
//# sourceMappingURL=run-session.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run-session.js","sourceRoot":"","sources":["../../src/ws/run-session.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC3D,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEjD,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,gBAAgB,EAAe,MAAM,WAAW,CAAC;AAE9F;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,IAAY,EACZ,
|
|
1
|
+
{"version":3,"file":"run-session.js","sourceRoot":"","sources":["../../src/ws/run-session.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC3D,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AACxD,OAAO,EAAE,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAEjD,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,gBAAgB,EAAe,MAAM,WAAW,CAAC;AAE9F;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,IAAY,EACZ,OAQC;IAED,MAAM,EAAE,WAAW,EAAE,GAAG,IAAI,CAAC;IAC7B,WAAW,CAAC,gBAAgB,IAAI,CAAC,CAAC;IAClC,IAAI,MAAqD,CAAC;IAC1D,IAAI,CAAC;QACH,MAAM,GAAG,MAAM,iBAAiB,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,SAAS,EAAE,OAAO,CAAC,UAAU,CAAC,CAAC;IACvG,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,CAAC,aAAa,CAAC;YACjB,IAAI,EAAE,OAAO;YACb,IAAI,EAAE,eAAe;YACrB,OAAO,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;YACzD,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC/D,CAAC,CAAC;QACH,OAAO;IACT,CAAC;YAAS,CAAC;QACT,WAAW,CAAC,gBAAgB,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,WAAW,CAAC,gBAAgB,GAAG,CAAC,CAAC,CAAC;IAC/E,CAAC;IAED,MAAM,EAAE,OAAO,EAAE,SAAS,EAAE,gBAAgB,EAAE,GAAG,MAAM,CAAC;IACxD,IAAI,MAAM,CAAC,UAAU,EAAE,CAAC;QACtB,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;YACZ,YAAY,EAAE,MAAM;YACpB,IAAI,EAAE,4DAA4D;YAClE,UAAU,EAAE,EAAE,YAAY,EAAE,OAAO,CAAC,SAAS,EAAE,OAAO,EAAE,MAAM,CAAC,UAAU,EAAE;SAC5E,CAAC,CAAC;QACH,IAAI,CAAC,aAAa,CAAC;YACjB,IAAI,EAAE,QAAQ;YACd,MAAM,EAAE,UAAU;YAClB,MAAM,EAAE,iBAAiB,MAAM,CAAC,UAAU,4CAA4C;YACtF,GAAG,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,OAAO,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC/D,CAAC,CAAC;IACL,CAAC;IACD,MAAM,IAAI,GAAgB;QACxB,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,IAAI;QACpC,MAAM,EAAE,MAAM,CAAC,UAAU,EAAE;QAC3B,6DAA6D;QAC7D,OAAO,EAAE,OAAO,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,OAAO,IAAI,IAAI,CAAC;QAC7D,UAAU,EAAE,gBAAgB,IAAI,IAAI;QACpC,OAAO;QACP,eAAe,EAAE,IAAI,eAAe,EAAE;QACtC,aAAa,EAAE,UAAU,CAAC,GAAG,EAAE,GAAE,CAAC,EAAE,CAAC,CAAC;QACtC,KAAK,EAAE,EAAE;QACT,SAAS,EAAE,KAAK;KACjB,CAAC;IACF,YAAY,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;IACjC,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC9B,IAAI,IAAI,CAAC,SAAS;QAAE,WAAW,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC;IAEpE,IAAI,SAAS,GAAG,gBAAgB,CAAC;IACjC,IAAI,QAAQ,GAAG,OAAO,CAAC,SAAS,CAAC;IACjC,IAAI,IAAI,GAA0B;QAChC,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,WAAW,EAAE,OAAO,CAAC,WAAW;QAChC,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACtD,CAAC;IAEF,IAAI,CAAC;QACH,OAAO,IAAI,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,CAAC;YAC/B,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;YAC3C,IAAI,GAAG,IAAI,CAAC;YAEZ,MAAM,eAAe,GAAG,IAAI,eAAe,EAAE,CAAC;YAC9C,IAAI,CAAC,eAAe,GAAG,eAAe,CAAC;YACvC,MAAM,aAAa,GAAG,UAAU,CAAC,GAAG,EAAE;gBACpC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;oBACZ,YAAY,EAAE,MAAM;oBACpB,IAAI,EAAE,gBAAgB;oBACtB,UAAU,EAAE,EAAE,YAAY,EAAE,IAAI,CAAC,aAAa,EAAE;iBACjD,CAAC,CAAC;gBACH,eAAe,CAAC,KAAK,EAAE,CAAC;gBACxB,qEAAqE;gBACrE,qEAAqE;gBACrE,oEAAoE;gBACpE,gEAAgE;gBAChE,WAAW,CAAC,mBAAmB,CAAC,IAAI,EAAE,gBAAgB,CAAC,CAAC;YAC1D,CAAC,EAAE,IAAI,CAAC,aAAa,CAAC,CAAC;YACvB,IAAI,CAAC,aAAa,GAAG,aAAa,CAAC;YAEnC,MAAM,MAAM,GAAG,UAAU,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,CAAC,EAAE,CAAC,CAAC;YACxD,IAAI,CAAC;gBACH,MAAM,OAAO,CAAC,SAAS,CAAC;oBACtB,MAAM,EAAE,IAAI;oBACZ,WAAW;oBACX,SAAS,EAAE,QAAQ;oBACnB,SAAS;oBACT,MAAM,EAAE,eAAe,CAAC,MAAM;oBAC9B,MAAM;oBACN,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;iBAC9B,CAAC,CAAC;YACL,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,aAAa,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,CAAC,CAAC;YACjC,CAAC;oBAAS,CAAC;gBACT,YAAY,CAAC,aAAa,CAAC,CAAC;YAC9B,CAAC;YAED,sEAAsE;YACtE,yEAAyE;YACzE,qEAAqE;YACrE,2EAA2E;YAC3E,QAAQ,GAAG,IAAI,CAAC,SAAS,IAAI,QAAQ,CAAC;YACtC,SAAS,GAAG,IAAI,CAAC,UAAU,IAAI,SAAS,CAAC;YAEzC,IAAI,CAAC,IAAI,CAAC,SAAS,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC7C,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,EAAG,CAAC;gBAC3B,iEAAiE;gBACjE,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC,UAAU,EAAE,CAAC;YACpC,CAAC;QACH,CAAC;IACH,CAAC;YAAS,CAAC;QACT,IAAI,IAAI,CAAC,SAAS;YAAE,WAAW,CAAC,SAAS,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;QACjE,WAAW,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;QACjC,WAAW,CAAC,mBAAmB,CAAC,IAAI,EAAE,eAAe,CAAC,CAAC;IACzD,CAAC;AACH,CAAC;AAED,qFAAqF;AACrF,SAAS,QAAQ,CAAC,KAAa;IAC7B,OAAO,GAAG,CAAC,KAAK,GAAG,IAAI,GAAG,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC;AAClD,CAAC;AAED,iFAAiF;AACjF,MAAM,CAAC,KAAK,UAAU,iBAAiB,CACrC,IAAY,EACZ,EAAa,EACb,GAOC;IAED,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,SAAS,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,EAAE,OAAO,EAAE,GAAG,GAAG,CAAC;IAC/F,MAAM,EAAE,WAAW,EAAE,GAAG,IAAI,CAAC;IAC7B,MAAM,WAAW,GAAG,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,SAAS,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAEjF,IAAI,WAAW,IAAI,SAAS,EAAE,CAAC;QAC7B,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,CAAC;QACpC,4DAA4D;QAC5D,IAAI,OAAO,CAAC,YAAY,CAAC,QAAQ,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;YACtD,oEAAoE;YACpE,qEAAqE;YACrE,oEAAoE;YACpE,OAAO,CAAC,QAAQ,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;gBACvE,IAAI,CAAC,aAAa,CAChB,aAAa,CACX,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,iBAAiB,EAAE,OAAO,EAAE,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,EACrG,WAAW,CACZ,CACF,CAAC;YACJ,CAAC,CAAC,CAAC;QACL,CAAC;aAAM,CAAC;YACN,MAAM,KAAK,GAAmB,EAAE,IAAI,EAAE,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;YACnF,MAAM,MAAM,GAAG,WAAW,CAAC,WAAW,CAAC,CAAC;YACxC,MAAM,QAAQ,GAAG,mBAAmB,CAAC,KAAK,CAAC,CAAC;YAC5C,yEAAyE;YACzE,yEAAyE;YACzE,qDAAqD;YACrD,MAAM,UAAU,GAAG,MAAM,GAAG,QAAQ,GAAG,eAAe,CAAC;YACvD,MAAM,SAAS,GAAG,WAAW,CAAC,KAAK,CAAC,MAAM,IAAI,iBAAiB,CAAC;YAEhE,IAAI,UAAU,IAAI,SAAS,EAAE,CAAC;gBAC5B,IAAI,CAAC,WAAW,CACd,EAAE;gBACF,gEAAgE;gBAChE,2DAA2D;gBAC3D,aAAa,CACX;oBACE,IAAI,EAAE,OAAO;oBACb,IAAI,EAAE,oBAAoB;oBAC1B,OAAO,EAAE,UAAU;wBACjB,CAAC,CAAC,iCAAiC,QAAQ,CAAC,MAAM,CAAC,OAAO,QAAQ,CAAC,eAAe,CAAC,wBAAwB,QAAQ,CAAC,QAAQ,CAAC,6BAA6B;wBAC1J,CAAC,CAAC,iCAAiC,iBAAiB,sCAAsC;iBAC7F,EACD,SAAS,CACV,CACF,CAAC;gBACF,OAAO;YACT,CAAC;YAED,kEAAkE;YAClE,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC9B,MAAM,KAAK,GAAG,MAAM,GAAG,QAAQ,CAAC;YAChC,yEAAyE;YACzE,4EAA4E;YAC5E,MAAM,MAAM,GACV,KAAK,IAAI,gBAAgB;gBACvB,CAAC,CAAC,oBAAoB,QAAQ,CAAC,KAAK,CAAC,WAAW,WAAW,CAAC,KAAK,CAAC,MAAM,oBAAoB,QAAQ,CAAC,eAAe,CAAC,IAAI;gBACzH,CAAC,CAAC,SAAS,CAAC;YAChB,IAAI,MAAM,EAAE,CAAC;gBACX,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC;oBACZ,YAAY,EAAE,MAAM;oBACpB,IAAI,EAAE,kCAAkC;oBACxC,UAAU,EAAE;wBACV,YAAY,EAAE,SAAS;wBACvB,IAAI,EAAE,QAAQ,CAAC,KAAK,CAAC;wBACrB,MAAM,EAAE,WAAW,CAAC,KAAK,CAAC,MAAM;qBACjC;iBACF,CAAC,CAAC;YACL,CAAC;YACD,IAAI,CAAC,aAAa,CAChB,aAAa,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,SAAS,CAAC,CAC9F,CAAC;QACJ,CAAC;QACD,OAAO;IACT,CAAC;IAED,yEAAyE;IACzE,MAAM,GAAG,GAAG,IAAI,CAAC,qBAAqB,EAAE,CAAC;IACzC,IAAI,WAAW,CAAC,OAAO,CAAC,IAAI,GAAG,WAAW,CAAC,gBAAgB,IAAI,GAAG,EAAE,CAAC;QACnE,IAAI,CAAC,WAAW,CAAC,EAAE,EAAE;YACnB,IAAI,EAAE,OAAO;YACb,IAAI,EAAE,eAAe;YACrB,OAAO,EAAE,qCAAqC,GAAG,4BAA4B;YAC7E,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SACpC,CAAC,CAAC;QACH,OAAO;IACT,CAAC;IAED,IAAI,SAAS,EAAE,CAAC;QACd,IAAI,CAAC,aAAa,CAAC,aAAa,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,EAAE,SAAS,CAAC,CAAC,CAAC;IACvF,CAAC;IACD,KAAK,UAAU,CAAC,IAAI,EAAE;QACpB,IAAI;QACJ,SAAS;QACT,WAAW;QACX,UAAU,EAAE,mBAAmB;QAC/B,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC7B,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAChC,CAAC,CAAC;AACL,CAAC"}
|
package/dist/ws/turns.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Logger } from "@opentelemetry/api-logs";
|
|
1
2
|
import type { AgentBackend, PermissionDecision, AskUserResult, LocationFix } from "@schlessera/brain-ui-sdk/server";
|
|
2
3
|
import type { ChatImageAttachment, ClientEnvironment } from "@schlessera/brain-ui-sdk/protocol";
|
|
3
4
|
export interface QueuedFollowUp {
|
|
@@ -35,6 +36,12 @@ export interface RunningTurn {
|
|
|
35
36
|
timeoutHandle: ReturnType<typeof setTimeout>;
|
|
36
37
|
queue: QueuedFollowUp[];
|
|
37
38
|
cancelled: boolean;
|
|
39
|
+
/**
|
|
40
|
+
* Correlation id the client minted for this NEW conversation, echoed back on
|
|
41
|
+
* `session_info` so the client can tell its own turn's identity from a
|
|
42
|
+
* background turn's. Null on a resumed session or a client that sent none.
|
|
43
|
+
*/
|
|
44
|
+
draftId: string | null;
|
|
38
45
|
}
|
|
39
46
|
export interface PendingApproval {
|
|
40
47
|
turn: RunningTurn;
|
|
@@ -66,6 +73,12 @@ export interface PendingMask {
|
|
|
66
73
|
* explicit object with a defined lifecycle.
|
|
67
74
|
*/
|
|
68
75
|
export declare class TurnCoordinator {
|
|
76
|
+
/**
|
|
77
|
+
* Where collisions are reported. Assigned by the owning WsHost so the
|
|
78
|
+
* coordinator reports through the same consumer as everything else; absent
|
|
79
|
+
* (a bare coordinator in a test) means silence.
|
|
80
|
+
*/
|
|
81
|
+
log?: Logger;
|
|
69
82
|
readonly running: Set<RunningTurn>;
|
|
70
83
|
readonly bySession: Map<string, RunningTurn>;
|
|
71
84
|
startingSessions: number;
|
package/dist/ws/turns.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"turns.d.ts","sourceRoot":"","sources":["../../src/ws/turns.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EACZ,kBAAkB,EAClB,aAAa,EACb,WAAW,EACZ,MAAM,iCAAiC,CAAC;AACzC,OAAO,KAAK,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,mCAAmC,CAAC;AAEhG,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,mBAAmB,EAAE,CAAC;IACnC,yEAAyE;IACzE,MAAM,CAAC,EAAE,iBAAiB,CAAC;CAC5B;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,cAAc,GAAG,MAAM,CAMjE;AAED,mEAAmE;AACnE,wBAAgB,WAAW,CAAC,IAAI,EAAE,WAAW,GAAG,MAAM,CAIrD;AAED;;;;GAIG;AACH,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,uFAAuF;IACvF,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,OAAO,EAAE,YAAY,CAAC;IACtB,eAAe,EAAE,eAAe,CAAC;IACjC,aAAa,EAAE,UAAU,CAAC,OAAO,UAAU,CAAC,CAAC;IAC7C,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,SAAS,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"turns.d.ts","sourceRoot":"","sources":["../../src/ws/turns.ts"],"names":[],"mappings":"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"}
|
package/dist/ws/turns.js
CHANGED
|
@@ -30,6 +30,12 @@ export function queuedBytes(turn) {
|
|
|
30
30
|
* explicit object with a defined lifecycle.
|
|
31
31
|
*/
|
|
32
32
|
export class TurnCoordinator {
|
|
33
|
+
/**
|
|
34
|
+
* Where collisions are reported. Assigned by the owning WsHost so the
|
|
35
|
+
* coordinator reports through the same consumer as everything else; absent
|
|
36
|
+
* (a bare coordinator in a test) means silence.
|
|
37
|
+
*/
|
|
38
|
+
log;
|
|
33
39
|
running = new Set();
|
|
34
40
|
bySession = new Map();
|
|
35
41
|
startingSessions = 0;
|
|
@@ -103,7 +109,11 @@ export class TurnCoordinator {
|
|
|
103
109
|
collidesAcrossTurns(map, id, turn) {
|
|
104
110
|
const existing = map.get(id);
|
|
105
111
|
if (existing && existing.turn !== turn) {
|
|
106
|
-
|
|
112
|
+
this.log?.emit({
|
|
113
|
+
severityText: "ERROR",
|
|
114
|
+
body: "interactive id collision: already pending for another turn",
|
|
115
|
+
attributes: { "request.id": id },
|
|
116
|
+
});
|
|
107
117
|
return true;
|
|
108
118
|
}
|
|
109
119
|
return false;
|
package/dist/ws/turns.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"turns.js","sourceRoot":"","sources":["../../src/ws/turns.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"turns.js","sourceRoot":"","sources":["../../src/ws/turns.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@schlessera/brain-ui-server",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.16.0",
|
|
4
4
|
"description": "brain-kit chat-UI server: Hono app factory, WebSocket turn coordinator, auth (password/passkeys/tailscale/proxy), session catalog, and brain/files/voice routes",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"keywords": [
|
|
@@ -45,8 +45,10 @@
|
|
|
45
45
|
"prepublishOnly": "bun ../../scripts/check-dist.ts"
|
|
46
46
|
},
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@
|
|
49
|
-
"@
|
|
48
|
+
"@opentelemetry/api": "^1.9.1",
|
|
49
|
+
"@opentelemetry/api-logs": "0.221.0",
|
|
50
|
+
"@schlessera/brain-render-template": "0.16.0",
|
|
51
|
+
"@schlessera/brain-ui-sdk": "0.16.0",
|
|
50
52
|
"@simplewebauthn/server": "^13.3.2",
|
|
51
53
|
"hono": "^4",
|
|
52
54
|
"ignore": "^7.0.5",
|
package/src/agent/backend.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Logger } from "@opentelemetry/api-logs";
|
|
1
2
|
import { createRequire } from "module";
|
|
2
3
|
import type { AgentConfig } from "../config/env.js";
|
|
3
4
|
import type { ProviderInfo } from "@schlessera/brain-ui-sdk";
|
|
@@ -499,7 +500,8 @@ export function createStaticBackendRegistry(
|
|
|
499
500
|
function makeRegistry(
|
|
500
501
|
getRegistry: () => Promise<RegistrySnapshot>,
|
|
501
502
|
getHidden: () => string[],
|
|
502
|
-
getModelSource: () => Promise<ModelDiscoverySource | null
|
|
503
|
+
getModelSource: () => Promise<ModelDiscoverySource | null>,
|
|
504
|
+
log?: Logger
|
|
503
505
|
): BackendRegistry {
|
|
504
506
|
let profileSnapshot: ProfileSnapshot | null = null;
|
|
505
507
|
|
|
@@ -536,11 +538,11 @@ function makeRegistry(
|
|
|
536
538
|
try {
|
|
537
539
|
return new Set(getHidden());
|
|
538
540
|
} catch (err) {
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
}
|
|
543
|
-
);
|
|
541
|
+
log?.emit({
|
|
542
|
+
severityText: "WARN",
|
|
543
|
+
body: "could not read hidden models; treating none as hidden",
|
|
544
|
+
attributes: { error: err instanceof Error ? err.message : String(err) },
|
|
545
|
+
});
|
|
544
546
|
return new Set();
|
|
545
547
|
}
|
|
546
548
|
}
|
package/src/app.ts
CHANGED
|
@@ -45,6 +45,7 @@ import { WsHost } from "./ws/host.js";
|
|
|
45
45
|
import { createWsUpgrade, websocket } from "./ws/connection.js";
|
|
46
46
|
import { createSessionCatalog } from "./ws/session-catalog.js";
|
|
47
47
|
import type { KeytermSettings } from "./voice/keyterm-builder.js";
|
|
48
|
+
import { createObservability, type Observability } from "./observability/index.js";
|
|
48
49
|
|
|
49
50
|
export type { AppRenderer };
|
|
50
51
|
|
|
@@ -81,6 +82,12 @@ export interface CreateAppOptions {
|
|
|
81
82
|
turnTimeoutMs?: number;
|
|
82
83
|
/** Backend registry override (tests/embedders); default is built from config. */
|
|
83
84
|
registry?: BackendRegistry;
|
|
85
|
+
/**
|
|
86
|
+
* Where this app reports. Defaults to the console consumer; a test passes
|
|
87
|
+
* `createRecordingObservability()` and then asserts on what the server
|
|
88
|
+
* actually said, through the same emission path production uses.
|
|
89
|
+
*/
|
|
90
|
+
observability?: Observability;
|
|
84
91
|
}
|
|
85
92
|
|
|
86
93
|
/** What `createApp` hands back to the deployment shell. */
|
|
@@ -99,6 +106,8 @@ export interface BrainUiApp {
|
|
|
99
106
|
db: Database;
|
|
100
107
|
/** The WebSocket coordinator (turn state, clients, catalog, registry). */
|
|
101
108
|
wsHost: WsHost;
|
|
109
|
+
/** Where this app reports — resolved or injected. */
|
|
110
|
+
observability: Observability;
|
|
102
111
|
/** True while any session has a running turn. */
|
|
103
112
|
isTurnActive(): boolean;
|
|
104
113
|
/** Cancel every running turn (used on shutdown). Returns true if any was. */
|
|
@@ -136,14 +145,19 @@ export function createApp(options: CreateAppOptions = {}): BrainUiApp {
|
|
|
136
145
|
// silently fall back to the resolved path.
|
|
137
146
|
const config: ServerConfig =
|
|
138
147
|
options.dbPath !== undefined ? { ...resolved, dbPath: options.dbPath } : resolved;
|
|
148
|
+
// First thing built, because everything below may want to report — including
|
|
149
|
+
// the auth validation that can refuse to boot and the migration runner.
|
|
150
|
+
const observability =
|
|
151
|
+
options.observability ?? createObservability({ minSeverity: config.logLevel });
|
|
139
152
|
const auth: AuthRuntime = { ...config.auth, host: config.host };
|
|
140
153
|
|
|
141
154
|
const app = new Hono();
|
|
142
|
-
const
|
|
155
|
+
const authLog = observability.logger("auth");
|
|
156
|
+
const authMode = resolveAuthMode(auth, authLog);
|
|
143
157
|
// Validate inside the factory, not the bin entry: every consumer of the app
|
|
144
158
|
// (a deployment bin, tests, another embedder) gets the same refuse-to-boot
|
|
145
159
|
// guarantee on an unsafe auth configuration.
|
|
146
|
-
assertAuthConfig(authMode, auth);
|
|
160
|
+
assertAuthConfig(authMode, auth, authLog);
|
|
147
161
|
assertPasskeyConfig(config.webauthn);
|
|
148
162
|
// A missing (or unrecognized) agent backend refuses to boot HERE, not on the
|
|
149
163
|
// first turn — otherwise /api/health reports healthy while every turn is
|
|
@@ -154,9 +168,9 @@ export function createApp(options: CreateAppOptions = {}): BrainUiApp {
|
|
|
154
168
|
// Per-instance state: the app's own database, the brain CLI wrapper, the
|
|
155
169
|
// backend registry, and the WebSocket host. No module-level singletons —
|
|
156
170
|
// two apps with different configuration coexist in one process.
|
|
157
|
-
const db = createUiDb(config.dbPath);
|
|
171
|
+
const db = createUiDb(config.dbPath, { log: observability.logger("db") });
|
|
158
172
|
const brain = createBrainClient({ brainPath: config.brainPath });
|
|
159
|
-
const cron = createCronScheduler({ db, brain });
|
|
173
|
+
const cron = createCronScheduler({ db, brain, log: observability.logger("cron") });
|
|
160
174
|
const registry =
|
|
161
175
|
options.registry ??
|
|
162
176
|
createBackendRegistry({
|
|
@@ -166,10 +180,12 @@ export function createApp(options: CreateAppOptions = {}): BrainUiApp {
|
|
|
166
180
|
});
|
|
167
181
|
const host = new WsHost({
|
|
168
182
|
registry,
|
|
183
|
+
observability,
|
|
169
184
|
catalog: createSessionCatalog(() => db),
|
|
170
185
|
...(options.appName ? { appName: options.appName } : {}),
|
|
171
186
|
...(options.turnTimeoutMs ? { turnTimeoutMs: options.turnTimeoutMs } : {}),
|
|
172
187
|
maxConcurrentSessions: () => config.maxConcurrentSessions,
|
|
188
|
+
wsRate: config.wsRate,
|
|
173
189
|
});
|
|
174
190
|
const wsUpgrade = createWsUpgrade(host);
|
|
175
191
|
const passkeyCtx: PasskeyContext = {
|
|
@@ -177,6 +193,10 @@ export function createApp(options: CreateAppOptions = {}): BrainUiApp {
|
|
|
177
193
|
webauthn: config.webauthn,
|
|
178
194
|
auth,
|
|
179
195
|
allowedOrigins: config.allowedOrigins,
|
|
196
|
+
log: observability.logger("passkeys"),
|
|
197
|
+
failures: observability.meter("auth").createCounter("auth.failures", {
|
|
198
|
+
description: "Failed authentication ceremonies, by reason",
|
|
199
|
+
}),
|
|
180
200
|
};
|
|
181
201
|
const keyterms: KeytermSettings = {
|
|
182
202
|
brainPath: config.brainPath,
|
|
@@ -234,6 +254,9 @@ export function createApp(options: CreateAppOptions = {}): BrainUiApp {
|
|
|
234
254
|
sourceCommit: config.sourceCommit,
|
|
235
255
|
getCronStatus: () => cron.getCronStatus(),
|
|
236
256
|
isTurnActive: () => host.coordinator.isTurnActive(),
|
|
257
|
+
// Undefined when the injected consumer cannot be read back (a real OTel
|
|
258
|
+
// SDK exports elsewhere), in which case the field is simply absent.
|
|
259
|
+
getMetrics: () => observability.metrics?.snapshot(),
|
|
237
260
|
})
|
|
238
261
|
);
|
|
239
262
|
app.route(
|
|
@@ -269,8 +292,24 @@ export function createApp(options: CreateAppOptions = {}): BrainUiApp {
|
|
|
269
292
|
if (options.staticRoot) {
|
|
270
293
|
const staticRoot = options.staticRoot;
|
|
271
294
|
app.use("/*", serveStatic({ root: staticRoot }));
|
|
272
|
-
|
|
273
|
-
|
|
295
|
+
|
|
296
|
+
// SPA fallback, served directly rather than through serveStatic({ path }).
|
|
297
|
+
//
|
|
298
|
+
// That helper resolves its path the same way it resolves `root` — against
|
|
299
|
+
// the process working directory — so `join(staticRoot, "index.html")`
|
|
300
|
+
// only lands correctly when `staticRoot` is itself cwd-relative. It is in
|
|
301
|
+
// the shipped layout, which is why this went unnoticed; an embedder
|
|
302
|
+
// passing an absolute directory, or a process that changed cwd, got a
|
|
303
|
+
// fallback that silently 404ed every deep link. Reading the file
|
|
304
|
+
// ourselves removes the ambiguity for both cases.
|
|
305
|
+
const indexPath = join(staticRoot, "index.html");
|
|
306
|
+
app.get("*", async (c) => {
|
|
307
|
+
const file = Bun.file(indexPath);
|
|
308
|
+
if (!(await file.exists())) return c.notFound();
|
|
309
|
+
return new Response(file, {
|
|
310
|
+
headers: { "Content-Type": "text/html; charset=utf-8" },
|
|
311
|
+
});
|
|
312
|
+
});
|
|
274
313
|
}
|
|
275
314
|
|
|
276
315
|
return {
|
|
@@ -280,6 +319,7 @@ export function createApp(options: CreateAppOptions = {}): BrainUiApp {
|
|
|
280
319
|
authMode,
|
|
281
320
|
db,
|
|
282
321
|
wsHost: host,
|
|
322
|
+
observability,
|
|
283
323
|
isTurnActive: () => host.coordinator.isTurnActive(),
|
|
284
324
|
cancelActiveTurns: () => host.coordinator.cancelAll("Server shutting down"),
|
|
285
325
|
close: () => {
|
package/src/config/env.ts
CHANGED
|
@@ -15,6 +15,8 @@
|
|
|
15
15
|
|
|
16
16
|
import { join } from "path";
|
|
17
17
|
|
|
18
|
+
import { SEVERITIES, type Severity } from "../observability/types.js";
|
|
19
|
+
|
|
18
20
|
// --- descriptor -------------------------------------------------------------
|
|
19
21
|
|
|
20
22
|
export interface EnvVarDescriptor {
|
|
@@ -63,6 +65,31 @@ export const ENV_VARS: readonly EnvVarDescriptor[] = [
|
|
|
63
65
|
default: "(empty)",
|
|
64
66
|
required: false,
|
|
65
67
|
},
|
|
68
|
+
{
|
|
69
|
+
name: "BRAIN_UI_WS_RATE",
|
|
70
|
+
description:
|
|
71
|
+
"Sustained inbound WebSocket frames per second per connection. 0 " +
|
|
72
|
+
"disables metering entirely.",
|
|
73
|
+
default: "20",
|
|
74
|
+
required: false,
|
|
75
|
+
},
|
|
76
|
+
{
|
|
77
|
+
name: "BRAIN_UI_WS_BURST",
|
|
78
|
+
description:
|
|
79
|
+
"Inbound WebSocket frames absorbable in one burst before the sustained " +
|
|
80
|
+
"rate applies. Opening the app legitimately fires several at once.",
|
|
81
|
+
default: "60",
|
|
82
|
+
required: false,
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
name: "BRAIN_UI_LOG_LEVEL",
|
|
86
|
+
description:
|
|
87
|
+
"Minimum severity the console log consumer emits: TRACE, DEBUG, INFO, " +
|
|
88
|
+
"WARN, ERROR or FATAL. Case-insensitive; an unrecognised value falls " +
|
|
89
|
+
"back to the default rather than silencing the server.",
|
|
90
|
+
default: "INFO",
|
|
91
|
+
required: false,
|
|
92
|
+
},
|
|
66
93
|
{
|
|
67
94
|
name: "SOURCE_COMMIT",
|
|
68
95
|
description: "Git SHA reported by /api/status (baked at image build time).",
|
|
@@ -305,6 +332,10 @@ export interface ServerConfig {
|
|
|
305
332
|
sourceCommit: string;
|
|
306
333
|
allowedOrigins: string[];
|
|
307
334
|
maxConcurrentSessions: number;
|
|
335
|
+
/** Threshold for the console log consumer (BRAIN_UI_LOG_LEVEL). */
|
|
336
|
+
logLevel: Severity;
|
|
337
|
+
/** Inbound WebSocket frame metering, per connection. */
|
|
338
|
+
wsRate: { ratePerSecond: number; burst: number };
|
|
308
339
|
auth: AuthConfig;
|
|
309
340
|
webauthn: WebAuthnConfig;
|
|
310
341
|
agent: AgentConfig;
|
|
@@ -326,6 +357,27 @@ function flag(raw: string | undefined): boolean {
|
|
|
326
357
|
return raw === "1";
|
|
327
358
|
}
|
|
328
359
|
|
|
360
|
+
/**
|
|
361
|
+
* A log threshold, defaulting to INFO.
|
|
362
|
+
*
|
|
363
|
+
* An unrecognised value falls back rather than throwing: a typo in a log level
|
|
364
|
+
* must never be the reason a server refuses to boot, and silently emitting
|
|
365
|
+
* nothing would be worse than emitting too much.
|
|
366
|
+
*/
|
|
367
|
+
/** A non-negative number, falling back rather than throwing on nonsense. */
|
|
368
|
+
function positiveNumber(raw: string | undefined, fallback: number): number {
|
|
369
|
+
if (raw === undefined || raw.trim() === "") return fallback;
|
|
370
|
+
const n = Number(raw);
|
|
371
|
+
return Number.isFinite(n) && n >= 0 ? n : fallback;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
function parseSeverity(raw: string | undefined): Severity {
|
|
375
|
+
const upper = raw?.trim().toUpperCase();
|
|
376
|
+
return (SEVERITIES as readonly string[]).includes(upper ?? "")
|
|
377
|
+
? (upper as Severity)
|
|
378
|
+
: "INFO";
|
|
379
|
+
}
|
|
380
|
+
|
|
329
381
|
const AUTH_MODES: readonly AuthModeName[] = ["password", "tailscale", "proxy", "none"];
|
|
330
382
|
|
|
331
383
|
/**
|
|
@@ -380,6 +432,11 @@ export function resolveServerConfig(env: EnvRecord = process.env): ServerConfig
|
|
|
380
432
|
modelDiscovery,
|
|
381
433
|
modelTtlMs: ttlHours * 60 * 60 * 1000,
|
|
382
434
|
},
|
|
435
|
+
logLevel: parseSeverity(env.BRAIN_UI_LOG_LEVEL),
|
|
436
|
+
wsRate: {
|
|
437
|
+
ratePerSecond: positiveNumber(env.BRAIN_UI_WS_RATE, 20),
|
|
438
|
+
burst: positiveNumber(env.BRAIN_UI_WS_BURST, 60),
|
|
439
|
+
},
|
|
383
440
|
voice: {
|
|
384
441
|
provider: env.VOICE_PROVIDER?.trim().toLowerCase() || null,
|
|
385
442
|
deepgramApiKey: env.DEEPGRAM_API_KEY || null,
|
package/src/cron/scheduler.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { Database } from "bun:sqlite";
|
|
2
|
+
import type { Logger } from "@opentelemetry/api-logs";
|
|
2
3
|
import type { BrainClient } from "../brain/client.js";
|
|
3
4
|
|
|
4
5
|
// Scheduling is owned by the container crontab (config/crontab) — sync at
|
|
@@ -25,8 +26,10 @@ interface CronJob {
|
|
|
25
26
|
export function createCronScheduler(deps: {
|
|
26
27
|
db: Database;
|
|
27
28
|
brain: BrainClient;
|
|
29
|
+
/** Where run outcomes are reported; absent means silence. */
|
|
30
|
+
log?: Logger;
|
|
28
31
|
}): CronScheduler {
|
|
29
|
-
const { db, brain } = deps;
|
|
32
|
+
const { db, brain, log } = deps;
|
|
30
33
|
|
|
31
34
|
const jobs: CronJob[] = [
|
|
32
35
|
{
|
|
@@ -57,14 +60,22 @@ export function createCronScheduler(deps: {
|
|
|
57
60
|
db.prepare(
|
|
58
61
|
"UPDATE cron_runs SET status = 'success', finished_at = ?, duration_ms = ? WHERE job_name = ? AND started_at = ?"
|
|
59
62
|
).run(Date.now(), durationMs, job.name, startedAt);
|
|
60
|
-
|
|
63
|
+
log?.emit({
|
|
64
|
+
severityText: "INFO",
|
|
65
|
+
body: "job completed",
|
|
66
|
+
attributes: { job: job.name, "duration.ms": durationMs },
|
|
67
|
+
});
|
|
61
68
|
} catch (err) {
|
|
62
69
|
const durationMs = Date.now() - startedAt;
|
|
63
70
|
const message = err instanceof Error ? err.message : String(err);
|
|
64
71
|
db.prepare(
|
|
65
72
|
"UPDATE cron_runs SET status = 'error', finished_at = ?, duration_ms = ?, error_message = ? WHERE job_name = ? AND started_at = ?"
|
|
66
73
|
).run(Date.now(), durationMs, message, job.name, startedAt);
|
|
67
|
-
|
|
74
|
+
log?.emit({
|
|
75
|
+
severityText: "ERROR",
|
|
76
|
+
body: "job failed",
|
|
77
|
+
attributes: { job: job.name, error: message },
|
|
78
|
+
});
|
|
68
79
|
}
|
|
69
80
|
}
|
|
70
81
|
|
package/src/db/client.ts
CHANGED
|
@@ -2,6 +2,8 @@ import { Database } from "bun:sqlite";
|
|
|
2
2
|
import { readdirSync, readFileSync } from "fs";
|
|
3
3
|
import { join } from "path";
|
|
4
4
|
|
|
5
|
+
import type { Logger } from "@opentelemetry/api-logs";
|
|
6
|
+
|
|
5
7
|
/**
|
|
6
8
|
* The UI's OWN SQLite database (sessions, passkeys, settings, cron runs) —
|
|
7
9
|
* distinct from the brain database, which is opened read-only via
|
|
@@ -11,15 +13,24 @@ import { join } from "path";
|
|
|
11
13
|
* it to every consumer, so two apps with different configuration can coexist
|
|
12
14
|
* in one process and a test gets an isolated database by construction.
|
|
13
15
|
*/
|
|
14
|
-
export
|
|
16
|
+
export interface CreateUiDbOptions {
|
|
17
|
+
/**
|
|
18
|
+
* Where migration progress is reported. Optional so a test can open a
|
|
19
|
+
* database without wiring observability; absent means silence, never
|
|
20
|
+
* console output.
|
|
21
|
+
*/
|
|
22
|
+
log?: Logger;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function createUiDb(dbPath: string, options: CreateUiDbOptions = {}): Database {
|
|
15
26
|
const db = new Database(dbPath, { create: true });
|
|
16
27
|
db.exec("PRAGMA journal_mode = WAL");
|
|
17
28
|
db.exec("PRAGMA foreign_keys = ON");
|
|
18
|
-
runMigrations(db);
|
|
29
|
+
runMigrations(db, options.log);
|
|
19
30
|
return db;
|
|
20
31
|
}
|
|
21
32
|
|
|
22
|
-
function runMigrations(database: Database) {
|
|
33
|
+
function runMigrations(database: Database, log?: Logger) {
|
|
23
34
|
// Ensure _migrations table exists
|
|
24
35
|
database.exec(`
|
|
25
36
|
CREATE TABLE IF NOT EXISTS _migrations (
|
|
@@ -39,7 +50,7 @@ function runMigrations(database: Database) {
|
|
|
39
50
|
.filter((f) => f.endsWith(".sql"))
|
|
40
51
|
.sort();
|
|
41
52
|
} catch {
|
|
42
|
-
|
|
53
|
+
log?.emit({ severityText: "WARN", body: "no migrations directory; skipping migrations" });
|
|
43
54
|
return;
|
|
44
55
|
}
|
|
45
56
|
|
|
@@ -53,7 +64,7 @@ function runMigrations(database: Database) {
|
|
|
53
64
|
for (const file of files) {
|
|
54
65
|
if (applied.has(file)) continue;
|
|
55
66
|
|
|
56
|
-
|
|
67
|
+
log?.emit({ severityText: "INFO", body: "applying migration", attributes: { file } });
|
|
57
68
|
const sql = readFileSync(join(migrationsDir, file), "utf-8");
|
|
58
69
|
|
|
59
70
|
database.transaction(() => {
|
package/src/db/settings.ts
CHANGED
|
@@ -6,11 +6,12 @@
|
|
|
6
6
|
// corrupt row degrades to the caller's fallback rather than throwing, because
|
|
7
7
|
// a bad preference must never take a route down.
|
|
8
8
|
|
|
9
|
+
import type { Logger } from "@opentelemetry/api-logs";
|
|
9
10
|
import type { Database } from "bun:sqlite";
|
|
10
11
|
|
|
11
12
|
const HIDDEN_MODELS_KEY = "models.hidden";
|
|
12
13
|
|
|
13
|
-
export function getSetting<T>(db: Database, key: string, fallback: T): T {
|
|
14
|
+
export function getSetting<T>(db: Database, key: string, fallback: T, log?: Logger): T {
|
|
14
15
|
const row = db
|
|
15
16
|
.query("SELECT value FROM settings WHERE key = ?")
|
|
16
17
|
.get(key) as { value: string } | null;
|
|
@@ -18,7 +19,11 @@ export function getSetting<T>(db: Database, key: string, fallback: T): T {
|
|
|
18
19
|
try {
|
|
19
20
|
return JSON.parse(row.value) as T;
|
|
20
21
|
} catch {
|
|
21
|
-
|
|
22
|
+
log?.emit({
|
|
23
|
+
severityText: "WARN",
|
|
24
|
+
body: "corrupt JSON in settings; using fallback",
|
|
25
|
+
attributes: { key },
|
|
26
|
+
});
|
|
22
27
|
return fallback;
|
|
23
28
|
}
|
|
24
29
|
}
|
package/src/index.ts
CHANGED
|
@@ -58,8 +58,12 @@ export {
|
|
|
58
58
|
|
|
59
59
|
// WebSocket internals for embedders and tests.
|
|
60
60
|
export { WsHost, type WsHostOptions } from "./ws/host.js";
|
|
61
|
-
export { createWsUpgrade, websocket } from "./ws/connection.js";
|
|
62
|
-
export {
|
|
61
|
+
export { createWsUpgrade, createWsHandlers, websocket } from "./ws/connection.js";
|
|
62
|
+
export {
|
|
63
|
+
handleClientMessage,
|
|
64
|
+
turnIdMatches,
|
|
65
|
+
type ConnectionState,
|
|
66
|
+
} from "./ws/dispatch.js";
|
|
63
67
|
export { resolveTurnTarget } from "./ws/routing.js";
|
|
64
68
|
export {
|
|
65
69
|
createSessionCatalog,
|
|
@@ -74,6 +78,37 @@ export { createBrainClient, type BrainClient } from "./brain/client.js";
|
|
|
74
78
|
// intake route also sweeps opportunistically on every share.
|
|
75
79
|
export { pruneShareStaging, shareStagingRoot } from "./share/staging.js";
|
|
76
80
|
|
|
81
|
+
// Observability: the producing side is the OpenTelemetry API, the consuming
|
|
82
|
+
// side is ours. Swap the consumer to change where a deployment reports; a test
|
|
83
|
+
// swaps in the recording one and asserts on what the server actually said.
|
|
84
|
+
export {
|
|
85
|
+
createObservability,
|
|
86
|
+
createRecordingObservability,
|
|
87
|
+
createSilentObservability,
|
|
88
|
+
createConsoleLoggerProvider,
|
|
89
|
+
createRecordingLoggerProvider,
|
|
90
|
+
createSilentLoggerProvider,
|
|
91
|
+
createInMemoryMeterProvider,
|
|
92
|
+
SEVERITIES,
|
|
93
|
+
severityRank,
|
|
94
|
+
seriesKey,
|
|
95
|
+
} from "./observability/index.js";
|
|
96
|
+
export type {
|
|
97
|
+
Observability,
|
|
98
|
+
ObservabilityOptions,
|
|
99
|
+
RecordingObservability,
|
|
100
|
+
RecordingLoggerProvider,
|
|
101
|
+
InMemoryMeterProvider,
|
|
102
|
+
LogReader,
|
|
103
|
+
LogWriter,
|
|
104
|
+
MetricsReader,
|
|
105
|
+
Severity,
|
|
106
|
+
CapturedLog,
|
|
107
|
+
LogQuery,
|
|
108
|
+
MetricPoint,
|
|
109
|
+
MetricSnapshot,
|
|
110
|
+
} from "./observability/index.js";
|
|
111
|
+
|
|
77
112
|
// Voice keyterm cache rebuild (used by deployments after `brain sync`).
|
|
78
113
|
export {
|
|
79
114
|
buildKeyterms,
|