@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.
Files changed (144) hide show
  1. package/README.md +3 -0
  2. package/dist/agent/backend.d.ts.map +1 -1
  3. package/dist/agent/backend.js +6 -2
  4. package/dist/agent/backend.js.map +1 -1
  5. package/dist/app.d.ts +9 -0
  6. package/dist/app.d.ts.map +1 -1
  7. package/dist/app.js +37 -6
  8. package/dist/app.js.map +1 -1
  9. package/dist/config/env.d.ts +8 -0
  10. package/dist/config/env.d.ts.map +1 -1
  11. package/dist/config/env.js +48 -0
  12. package/dist/config/env.js.map +1 -1
  13. package/dist/cron/scheduler.d.ts +3 -0
  14. package/dist/cron/scheduler.d.ts.map +1 -1
  15. package/dist/cron/scheduler.js +11 -3
  16. package/dist/cron/scheduler.js.map +1 -1
  17. package/dist/db/client.d.ts +10 -1
  18. package/dist/db/client.d.ts.map +1 -1
  19. package/dist/db/client.js +5 -14
  20. package/dist/db/client.js.map +1 -1
  21. package/dist/db/settings.d.ts +2 -1
  22. package/dist/db/settings.d.ts.map +1 -1
  23. package/dist/db/settings.js +6 -2
  24. package/dist/db/settings.js.map +1 -1
  25. package/dist/index.d.ts +4 -2
  26. package/dist/index.d.ts.map +1 -1
  27. package/dist/index.js +6 -2
  28. package/dist/index.js.map +1 -1
  29. package/dist/middleware/auth.d.ts +3 -2
  30. package/dist/middleware/auth.d.ts.map +1 -1
  31. package/dist/middleware/auth.js +28 -9
  32. package/dist/middleware/auth.js.map +1 -1
  33. package/dist/middleware/passkeys.d.ts +10 -0
  34. package/dist/middleware/passkeys.d.ts.map +1 -1
  35. package/dist/middleware/passkeys.js +19 -3
  36. package/dist/middleware/passkeys.js.map +1 -1
  37. package/dist/observability/index.d.ts +73 -0
  38. package/dist/observability/index.d.ts.map +1 -0
  39. package/dist/observability/index.js +74 -0
  40. package/dist/observability/index.js.map +1 -0
  41. package/dist/observability/loggers.d.ts +62 -0
  42. package/dist/observability/loggers.d.ts.map +1 -0
  43. package/dist/observability/loggers.js +109 -0
  44. package/dist/observability/loggers.js.map +1 -0
  45. package/dist/observability/meter.d.ts +39 -0
  46. package/dist/observability/meter.d.ts.map +1 -0
  47. package/dist/observability/meter.js +95 -0
  48. package/dist/observability/meter.js.map +1 -0
  49. package/dist/observability/types.d.ts +67 -0
  50. package/dist/observability/types.d.ts.map +1 -0
  51. package/dist/observability/types.js +44 -0
  52. package/dist/observability/types.js.map +1 -0
  53. package/dist/routes/brain.d.ts.map +1 -1
  54. package/dist/routes/brain.js +9 -1
  55. package/dist/routes/brain.js.map +1 -1
  56. package/dist/routes/files.d.ts +2 -0
  57. package/dist/routes/files.d.ts.map +1 -1
  58. package/dist/routes/files.js +7 -7
  59. package/dist/routes/files.js.map +1 -1
  60. package/dist/routes/graph.d.ts +2 -0
  61. package/dist/routes/graph.d.ts.map +1 -1
  62. package/dist/routes/graph.js +7 -7
  63. package/dist/routes/graph.js.map +1 -1
  64. package/dist/routes/health.d.ts +3 -0
  65. package/dist/routes/health.d.ts.map +1 -1
  66. package/dist/routes/health.js +3 -0
  67. package/dist/routes/health.js.map +1 -1
  68. package/dist/routes/models.d.ts +3 -0
  69. package/dist/routes/models.d.ts.map +1 -1
  70. package/dist/routes/models.js +5 -1
  71. package/dist/routes/models.js.map +1 -1
  72. package/dist/routes/render.d.ts +2 -1
  73. package/dist/routes/render.d.ts.map +1 -1
  74. package/dist/routes/render.js +2 -2
  75. package/dist/routes/render.js.map +1 -1
  76. package/dist/routes/share.d.ts +3 -0
  77. package/dist/routes/share.d.ts.map +1 -1
  78. package/dist/routes/share.js +3 -3
  79. package/dist/routes/share.js.map +1 -1
  80. package/dist/share/staging.d.ts +3 -2
  81. package/dist/share/staging.d.ts.map +1 -1
  82. package/dist/share/staging.js +12 -4
  83. package/dist/share/staging.js.map +1 -1
  84. package/dist/voice/keyterm-builder.d.ts +4 -1
  85. package/dist/voice/keyterm-builder.d.ts.map +1 -1
  86. package/dist/voice/keyterm-builder.js +13 -6
  87. package/dist/voice/keyterm-builder.js.map +1 -1
  88. package/dist/ws/bridge.d.ts.map +1 -1
  89. package/dist/ws/bridge.js +6 -1
  90. package/dist/ws/bridge.js.map +1 -1
  91. package/dist/ws/connection.d.ts +15 -0
  92. package/dist/ws/connection.d.ts.map +1 -1
  93. package/dist/ws/connection.js +55 -8
  94. package/dist/ws/connection.js.map +1 -1
  95. package/dist/ws/dispatch.d.ts +22 -1
  96. package/dist/ws/dispatch.d.ts.map +1 -1
  97. package/dist/ws/dispatch.js +33 -15
  98. package/dist/ws/dispatch.js.map +1 -1
  99. package/dist/ws/host.d.ts +37 -0
  100. package/dist/ws/host.d.ts.map +1 -1
  101. package/dist/ws/host.js +37 -0
  102. package/dist/ws/host.js.map +1 -1
  103. package/dist/ws/rate-limit.d.ts +58 -0
  104. package/dist/ws/rate-limit.d.ts.map +1 -0
  105. package/dist/ws/rate-limit.js +62 -0
  106. package/dist/ws/rate-limit.js.map +1 -0
  107. package/dist/ws/run-session.d.ts +3 -0
  108. package/dist/ws/run-session.d.ts.map +1 -1
  109. package/dist/ws/run-session.js +23 -5
  110. package/dist/ws/run-session.js.map +1 -1
  111. package/dist/ws/turns.d.ts +13 -0
  112. package/dist/ws/turns.d.ts.map +1 -1
  113. package/dist/ws/turns.js +11 -1
  114. package/dist/ws/turns.js.map +1 -1
  115. package/package.json +5 -3
  116. package/src/agent/backend.ts +8 -6
  117. package/src/app.ts +46 -6
  118. package/src/config/env.ts +57 -0
  119. package/src/cron/scheduler.ts +14 -3
  120. package/src/db/client.ts +16 -5
  121. package/src/db/settings.ts +7 -2
  122. package/src/index.ts +37 -2
  123. package/src/middleware/auth.ts +30 -14
  124. package/src/middleware/passkeys.ts +29 -5
  125. package/src/observability/index.ts +150 -0
  126. package/src/observability/loggers.ts +174 -0
  127. package/src/observability/meter.ts +190 -0
  128. package/src/observability/types.ts +101 -0
  129. package/src/routes/brain.ts +10 -1
  130. package/src/routes/files.ts +9 -8
  131. package/src/routes/graph.ts +9 -8
  132. package/src/routes/health.ts +7 -0
  133. package/src/routes/models.ts +8 -5
  134. package/src/routes/render.ts +3 -2
  135. package/src/routes/share.ts +6 -3
  136. package/src/share/staging.ts +18 -4
  137. package/src/voice/keyterm-builder.ts +17 -8
  138. package/src/ws/bridge.ts +5 -1
  139. package/src/ws/connection.ts +63 -12
  140. package/src/ws/dispatch.ts +44 -15
  141. package/src/ws/host.ts +54 -0
  142. package/src/ws/rate-limit.ts +86 -0
  143. package/src/ws/run-session.ts +26 -7
  144. package/src/ws/turns.ts +19 -3
@@ -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
- console.warn(`[agent] session ${initial.sessionId} pinned profile "${target.droppedPin}" ` +
33
- `is unavailable; running on the default profile.`);
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
- console.log("[agent] Turn timed out after", host.turnTimeoutMs, "ms");
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
- console.warn(`[ws] session ${sessionId} queue at ${formatMb(total)} across ${runningTurn.queue.length} messages`);
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":"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"}
1
+ {"version":3,"file":"run-session.js","sourceRoot":"","sources":["../../src/ws/run-session.ts"],"names":[],"mappings":"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"}
@@ -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;
@@ -1 +1 @@
1
- {"version":3,"file":"turns.d.ts","sourceRoot":"","sources":["../../src/ws/turns.ts"],"names":[],"mappings":"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"}
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
- console.error(`[ws] interactive id collision: "${id}" is already pending for another turn`);
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;
@@ -1 +1 @@
1
- {"version":3,"file":"turns.js","sourceRoot":"","sources":["../../src/ws/turns.ts"],"names":[],"mappings":"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"}
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.15.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
- "@schlessera/brain-render-template": "0.15.0",
49
- "@schlessera/brain-ui-sdk": "0.15.0",
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",
@@ -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
- console.warn(
540
- `[models] Could not read hidden models: ${
541
- err instanceof Error ? err.message : String(err)
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 authMode = resolveAuthMode(auth);
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
- // SPA fallback
273
- app.get("*", serveStatic({ path: join(staticRoot, "index.html") }));
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,
@@ -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
- console.log(`[cron] ${job.name} completed in ${durationMs}ms`);
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
- console.error(`[cron] ${job.name} failed: ${message}`);
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 function createUiDb(dbPath: string): Database {
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
- console.warn("[db] No migrations directory found, skipping migrations");
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
- console.log(`[db] Applying migration: ${file}`);
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(() => {
@@ -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
- console.warn(`[settings] Corrupt JSON for "${key}"; using fallback`);
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 { handleClientMessage } from "./ws/dispatch.js";
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,