@schlessera/brain-ui-server 0.33.1 → 0.34.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 +11 -0
- package/dist/agent/backend.d.ts +17 -219
- package/dist/agent/backend.d.ts.map +1 -1
- package/dist/agent/backend.js +212 -471
- package/dist/agent/backend.js.map +1 -1
- package/dist/app.d.ts.map +1 -1
- package/dist/app.js +2 -1
- package/dist/app.js.map +1 -1
- package/dist/config/env.d.ts +4 -4
- package/dist/config/env.d.ts.map +1 -1
- package/dist/routes/pi-auth.d.ts.map +1 -1
- package/dist/routes/pi-auth.js +14 -6
- package/dist/routes/pi-auth.js.map +1 -1
- package/dist/routes/web-search.d.ts.map +1 -1
- package/dist/routes/web-search.js +12 -8
- package/dist/routes/web-search.js.map +1 -1
- package/package.json +3 -3
- package/src/agent/backend.ts +281 -793
- package/src/app.ts +2 -1
- package/src/config/env.ts +4 -4
- package/src/routes/pi-auth.ts +13 -8
- package/src/routes/web-search.ts +12 -10
package/src/app.ts
CHANGED
|
@@ -170,7 +170,8 @@ export function createApp(options: CreateAppOptions = {}): BrainUiApp {
|
|
|
170
170
|
assertPasskeyConfig(config.webauthn);
|
|
171
171
|
// A missing (or unrecognized) agent backend refuses to boot HERE, not on the
|
|
172
172
|
// first turn — otherwise /api/health reports healthy while every turn is
|
|
173
|
-
// guaranteed to fail.
|
|
173
|
+
// guaranteed to fail. Descriptor loading and profile validation happen here;
|
|
174
|
+
// backend construction and model discovery remain lazy.
|
|
174
175
|
// Skipped when the embedder injects its own registry.
|
|
175
176
|
if (!options.registry) assertBackendResolvable(config.agent);
|
|
176
177
|
|
package/src/config/env.ts
CHANGED
|
@@ -447,12 +447,12 @@ export interface AgentConfig {
|
|
|
447
447
|
confirmBashPatterns: string[] | null;
|
|
448
448
|
claudeCodePath: string;
|
|
449
449
|
defaultModel: string;
|
|
450
|
-
/** Raw BRAIN_UI_CLAUDE_PROFILES JSON, parsed
|
|
450
|
+
/** Raw BRAIN_UI_CLAUDE_PROFILES JSON, parsed at boot and again by the registry. */
|
|
451
451
|
profilesJson: string | null;
|
|
452
452
|
/**
|
|
453
|
-
* Raw BRAIN_UI_PI_PROFILES JSON, parsed
|
|
454
|
-
* backend runs alongside the Claude backend and these
|
|
455
|
-
* picker.
|
|
453
|
+
* Raw BRAIN_UI_PI_PROFILES JSON, parsed at boot and again by the registry.
|
|
454
|
+
* When set, the pi backend runs alongside the Claude backend and these
|
|
455
|
+
* profiles join the picker.
|
|
456
456
|
*/
|
|
457
457
|
piProfilesJson: string | null;
|
|
458
458
|
modelDiscovery: boolean;
|
package/src/routes/pi-auth.ts
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
|
|
17
17
|
import { Hono } from "hono";
|
|
18
18
|
import type { AgentConfig } from "../config/env.js";
|
|
19
|
-
import {
|
|
19
|
+
import { loadBackendDescriptor, loadBackendModule } from "../agent/backend.js";
|
|
20
20
|
import { readJsonBody } from "../middleware/body-limit.js";
|
|
21
21
|
import { requireJson } from "../middleware/origin.js";
|
|
22
22
|
|
|
@@ -64,10 +64,15 @@ export function createPiAuthRoutes(deps: PiAuthRoutesDeps): Hono {
|
|
|
64
64
|
* Vendors the deployment actually configured — the only providers this
|
|
65
65
|
* surface may touch. Empty when pi is not in play at all.
|
|
66
66
|
*/
|
|
67
|
-
function allowedProviders(): string[] {
|
|
68
|
-
const
|
|
69
|
-
|
|
70
|
-
|
|
67
|
+
async function allowedProviders(): Promise<string[]> {
|
|
68
|
+
const descriptor = await loadBackendDescriptor("pi", deps.importer);
|
|
69
|
+
const parsed = descriptor.profileSchema.parse(agent.piProfilesJson, {
|
|
70
|
+
occupiedProfiles: [],
|
|
71
|
+
});
|
|
72
|
+
if (!parsed.ok) throw new Error(parsed.errors[0]?.message ?? "Invalid pi profiles.");
|
|
73
|
+
const fromProfiles = parsed.profiles
|
|
74
|
+
.map((profile) => profile.vendor)
|
|
75
|
+
.filter((vendor): vendor is string => typeof vendor === "string");
|
|
71
76
|
return [...new Set(fromProfiles)];
|
|
72
77
|
}
|
|
73
78
|
|
|
@@ -101,7 +106,7 @@ export function createPiAuthRoutes(deps: PiAuthRoutesDeps): Hono {
|
|
|
101
106
|
// Not-configured is a normal state, not an error: the client hides the
|
|
102
107
|
// whole card on an empty list.
|
|
103
108
|
if (!piConfigured()) return c.json({ providers: [] });
|
|
104
|
-
const providers = allowedProviders();
|
|
109
|
+
const providers = await allowedProviders();
|
|
105
110
|
if (providers.length === 0) return c.json({ providers: [] });
|
|
106
111
|
const auth = await getAuth();
|
|
107
112
|
return c.json({ providers: await auth.status(providers) });
|
|
@@ -116,7 +121,7 @@ export function createPiAuthRoutes(deps: PiAuthRoutesDeps): Hono {
|
|
|
116
121
|
if (!piConfigured()) {
|
|
117
122
|
return c.json({ error: "The pi backend is not configured." }, 409);
|
|
118
123
|
}
|
|
119
|
-
if (!providerId || !allowedProviders().includes(providerId)) {
|
|
124
|
+
if (!providerId || !(await allowedProviders()).includes(providerId)) {
|
|
120
125
|
return c.json({ error: "Unknown provider." }, 400);
|
|
121
126
|
}
|
|
122
127
|
const auth = await getAuth();
|
|
@@ -149,7 +154,7 @@ export function createPiAuthRoutes(deps: PiAuthRoutesDeps): Hono {
|
|
|
149
154
|
providerId?: unknown;
|
|
150
155
|
} | null;
|
|
151
156
|
const providerId = typeof body?.providerId === "string" ? body.providerId : "";
|
|
152
|
-
if (!providerId || !allowedProviders().includes(providerId)) {
|
|
157
|
+
if (!providerId || !(await allowedProviders()).includes(providerId)) {
|
|
153
158
|
return c.json({ error: "Unknown provider." }, 400);
|
|
154
159
|
}
|
|
155
160
|
const auth = await getAuth();
|
package/src/routes/web-search.ts
CHANGED
|
@@ -44,7 +44,7 @@ import {
|
|
|
44
44
|
} from "@schlessera/brain-ui-sdk/server";
|
|
45
45
|
import type { AgentConfig } from "../config/env.js";
|
|
46
46
|
import { resolveWebSearchEnv } from "../config/env.js";
|
|
47
|
-
import {
|
|
47
|
+
import { loadBackendDescriptor, loadBackendModule } from "../agent/backend.js";
|
|
48
48
|
|
|
49
49
|
/** One toggleable provider, as the Settings UI renders it. */
|
|
50
50
|
export interface WebSearchProviderView {
|
|
@@ -142,17 +142,19 @@ export function createWebSearchRoutes(deps: WebSearchRoutesDeps): Hono {
|
|
|
142
142
|
* createApp refuses to boot on it — but a throw would take the whole
|
|
143
143
|
* settings card down over a label, so it degrades to an empty list.
|
|
144
144
|
*/
|
|
145
|
-
const appliesTo = (): string[] => {
|
|
145
|
+
const appliesTo = async (): Promise<string[]> => {
|
|
146
146
|
try {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
147
|
+
const descriptor = await loadBackendDescriptor("pi", deps.importer);
|
|
148
|
+
const parsed = descriptor.profileSchema.parse(agent.piProfilesJson ?? null, {
|
|
149
|
+
occupiedProfiles: [],
|
|
150
|
+
});
|
|
151
|
+
return parsed.ok ? parsed.profiles.map((profile) => profile.label) : [];
|
|
150
152
|
} catch {
|
|
151
153
|
return [];
|
|
152
154
|
}
|
|
153
155
|
};
|
|
154
156
|
|
|
155
|
-
function view(): WebSearchConfigView {
|
|
157
|
+
async function view(): Promise<WebSearchConfigView> {
|
|
156
158
|
const config = readConfig(configPath());
|
|
157
159
|
const override = readWebSearchOverride(config);
|
|
158
160
|
const order = orderByCost(readWebSearchRouting(config));
|
|
@@ -161,7 +163,7 @@ export function createWebSearchRoutes(deps: WebSearchRoutesDeps): Hono {
|
|
|
161
163
|
configured: true,
|
|
162
164
|
order,
|
|
163
165
|
overriddenBy: override,
|
|
164
|
-
appliesTo: appliesTo(),
|
|
166
|
+
appliesTo: await appliesTo(),
|
|
165
167
|
providers: WEB_SEARCH_PROVIDERS.map((p) => ({
|
|
166
168
|
id: p.id,
|
|
167
169
|
label: p.label,
|
|
@@ -180,13 +182,13 @@ export function createWebSearchRoutes(deps: WebSearchRoutesDeps): Hono {
|
|
|
180
182
|
}
|
|
181
183
|
|
|
182
184
|
return new Hono()
|
|
183
|
-
.get("/web-search", (c) => {
|
|
185
|
+
.get("/web-search", async (c) => {
|
|
184
186
|
// Not-configured is a normal state, not an error: the client hides the
|
|
185
187
|
// whole card (same convention as /pi-auth/providers).
|
|
186
188
|
if (!piConfigured()) {
|
|
187
189
|
return c.json({ configured: false, order: [], overriddenBy: null, appliesTo: [], providers: [] });
|
|
188
190
|
}
|
|
189
|
-
return c.json(view());
|
|
191
|
+
return c.json(await view());
|
|
190
192
|
})
|
|
191
193
|
.put("/web-search", requireJson(), async (c) => {
|
|
192
194
|
if (!piConfigured()) {
|
|
@@ -317,6 +319,6 @@ export function createWebSearchRoutes(deps: WebSearchRoutesDeps): Hono {
|
|
|
317
319
|
/* config written; cache clearing is an optimization */
|
|
318
320
|
}
|
|
319
321
|
|
|
320
|
-
return c.json(view());
|
|
322
|
+
return c.json(await view());
|
|
321
323
|
});
|
|
322
324
|
}
|