@schlessera/brain-ui-react 0.21.0 → 0.23.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 (52) hide show
  1. package/dist/components/chat/renderers/claude-tools.d.ts.map +1 -1
  2. package/dist/components/chat/renderers/claude-tools.js +21 -1
  3. package/dist/components/chat/renderers/claude-tools.js.map +1 -1
  4. package/dist/components/chat/renderers/index.d.ts.map +1 -1
  5. package/dist/components/chat/renderers/index.js +2 -0
  6. package/dist/components/chat/renderers/index.js.map +1 -1
  7. package/dist/components/chat/renderers/pi-tools.d.ts +3 -0
  8. package/dist/components/chat/renderers/pi-tools.d.ts.map +1 -0
  9. package/dist/components/chat/renderers/pi-tools.js +112 -0
  10. package/dist/components/chat/renderers/pi-tools.js.map +1 -0
  11. package/dist/components/chat/risk-hints.d.ts +14 -2
  12. package/dist/components/chat/risk-hints.d.ts.map +1 -1
  13. package/dist/components/chat/risk-hints.js +54 -19
  14. package/dist/components/chat/risk-hints.js.map +1 -1
  15. package/dist/components/chat/tool-call-timeline.d.ts +1 -1
  16. package/dist/components/chat/tool-call-timeline.d.ts.map +1 -1
  17. package/dist/components/chat/tool-call-timeline.js +25 -14
  18. package/dist/components/chat/tool-call-timeline.js.map +1 -1
  19. package/dist/components/settings/models-tab.d.ts.map +1 -1
  20. package/dist/components/settings/models-tab.js +2 -1
  21. package/dist/components/settings/models-tab.js.map +1 -1
  22. package/dist/components/settings/pi-accounts.d.ts +13 -0
  23. package/dist/components/settings/pi-accounts.d.ts.map +1 -0
  24. package/dist/components/settings/pi-accounts.js +146 -0
  25. package/dist/components/settings/pi-accounts.js.map +1 -0
  26. package/dist/hooks/use-websocket.d.ts.map +1 -1
  27. package/dist/hooks/use-websocket.js +26 -2
  28. package/dist/hooks/use-websocket.js.map +1 -1
  29. package/dist/lib/api-client.d.ts +42 -0
  30. package/dist/lib/api-client.d.ts.map +1 -1
  31. package/dist/lib/api-client.js +18 -0
  32. package/dist/lib/api-client.js.map +1 -1
  33. package/dist/lib/tool-names.d.ts.map +1 -1
  34. package/dist/lib/tool-names.js +5 -1
  35. package/dist/lib/tool-names.js.map +1 -1
  36. package/dist/stores/chat-store.d.ts +8 -0
  37. package/dist/stores/chat-store.d.ts.map +1 -1
  38. package/dist/stores/chat-store.js +4 -0
  39. package/dist/stores/chat-store.js.map +1 -1
  40. package/dist/styles.css +1 -1
  41. package/package.json +2 -2
  42. package/src/components/chat/renderers/claude-tools.tsx +32 -1
  43. package/src/components/chat/renderers/index.ts +2 -0
  44. package/src/components/chat/renderers/pi-tools.tsx +144 -0
  45. package/src/components/chat/risk-hints.ts +73 -25
  46. package/src/components/chat/tool-call-timeline.tsx +57 -16
  47. package/src/components/settings/models-tab.tsx +3 -0
  48. package/src/components/settings/pi-accounts.tsx +258 -0
  49. package/src/hooks/use-websocket.ts +29 -2
  50. package/src/lib/api-client.ts +52 -0
  51. package/src/lib/tool-names.ts +6 -1
  52. package/src/stores/chat-store.ts +16 -0
@@ -80,6 +80,30 @@ export interface BackendInfo {
80
80
  };
81
81
  }
82
82
 
83
+ /** Auth status of one configured pi provider (mirror of the server view). */
84
+ export interface PiAuthProviderStatus {
85
+ providerId: string;
86
+ /** Human label for the credential, e.g. "OpenAI (ChatGPT Plus/Pro)". */
87
+ name: string;
88
+ configured: boolean;
89
+ source?: string;
90
+ /** Whether this provider can be signed in through the UI. */
91
+ oauth: boolean;
92
+ }
93
+
94
+ /** One OAuth device-code login flow (mirror of the server view). */
95
+ export interface PiLoginFlow {
96
+ id: string;
97
+ providerId: string;
98
+ status: "pending" | "success" | "error" | "cancelled";
99
+ userCode?: string;
100
+ verificationUri?: string;
101
+ intervalSeconds?: number;
102
+ expiresInSeconds?: number;
103
+ error?: string;
104
+ startedAt: number;
105
+ }
106
+
83
107
  async function fetchJson<T>(path: string, init?: RequestInit): Promise<T> {
84
108
  const res = await fetch(`${apiBase()}${path}`, {
85
109
  ...init,
@@ -209,6 +233,34 @@ export const api = {
209
233
  /** Pricing-table freshness for the Activity staleness indicator (see `PricingState`). */
210
234
  pricingState: () => fetchJson<PricingState>("/models/pricing"),
211
235
 
236
+ /** Auth status of configured pi providers; empty when pi is not in play. */
237
+ piAuthProviders: () =>
238
+ fetchJson<{ providers: PiAuthProviderStatus[] }>("/pi-auth/providers"),
239
+
240
+ /** Start an OAuth device-code login; resolves once the user code exists. */
241
+ piAuthStart: (providerId: string) =>
242
+ fetchJson<{ flow: PiLoginFlow }>("/pi-auth/login", {
243
+ method: "POST",
244
+ body: JSON.stringify({ providerId }),
245
+ }),
246
+
247
+ /** Poll one login flow. */
248
+ piAuthFlow: (id: string) =>
249
+ fetchJson<{ flow: PiLoginFlow }>(`/pi-auth/login/${encodeURIComponent(id)}`),
250
+
251
+ /** Abort a pending login flow. */
252
+ piAuthCancel: (id: string) =>
253
+ fetchJson<{ ok: boolean }>(`/pi-auth/login/${encodeURIComponent(id)}`, {
254
+ method: "DELETE",
255
+ }),
256
+
257
+ /** Remove the stored credential for a pi provider. */
258
+ piAuthLogout: (providerId: string) =>
259
+ fetchJson<{ ok: boolean }>("/pi-auth/logout", {
260
+ method: "POST",
261
+ body: JSON.stringify({ providerId }),
262
+ }),
263
+
212
264
  /** Force a discovery refresh, bypassing the TTL. */
213
265
  refreshModels: () =>
214
266
  fetchJson<ModelCatalogResponse>("/models/refresh", { method: "POST" }),
@@ -21,7 +21,12 @@ export function normalizeToolName(name: string): string {
21
21
  : name;
22
22
  }
23
23
 
24
+ // The pi backend registers its ask-user tool under the bare name.
25
+ const PI_ASK_USER_TOOL_NAME = "ask_user";
26
+
24
27
  export const isAskUserTool = (name: string | undefined): boolean =>
25
- !!name && normalizeToolName(name) === ASK_USER_TOOL_NAME;
28
+ !!name &&
29
+ (normalizeToolName(name) === ASK_USER_TOOL_NAME ||
30
+ name === PI_ASK_USER_TOOL_NAME);
26
31
  export const isLocationTool = (name: string | undefined): boolean =>
27
32
  !!name && normalizeToolName(name) === GET_LOCATION_TOOL_NAME;
@@ -123,6 +123,12 @@ interface ChatState {
123
123
  * absence of a running/queued turn.
124
124
  */
125
125
  runStates: Record<string, "streaming" | "queued" | "idle">;
126
+ /**
127
+ * Backend that owns each session, from `session_info` (or the session list
128
+ * for history sessions). Scopes tool-call renderer resolution per backend;
129
+ * absence falls back to the deployment default.
130
+ */
131
+ backendIds: Record<string, string>;
126
132
  /**
127
133
  * Per-session note attached to a `queued` status — the host sends one once a
128
134
  * session's follow-up queue grows heavy. Cleared when the session leaves the
@@ -190,6 +196,8 @@ interface ChatState {
190
196
  state: "streaming" | "queued" | "idle",
191
197
  note?: string
192
198
  ) => void;
199
+ /** Record which backend owns a session (idempotent). */
200
+ setSessionBackend: (sessionId: string, backendId: string) => void;
193
201
  }
194
202
 
195
203
  let messageCounter = 0;
@@ -350,6 +358,7 @@ export const useChatStore = create<ChatState>((set, get) => {
350
358
  activeSessionId: readPersistedSessionId(),
351
359
  runStates: {},
352
360
  queueNotes: {},
361
+ backendIds: {},
353
362
 
354
363
  // createIfMissing: a user-initiated send must never be dropped, even when
355
364
  // the active session's buffer hasn't been materialized yet (cold start
@@ -659,6 +668,13 @@ export const useChatStore = create<ChatState>((set, get) => {
659
668
  return { runStates, queueNotes };
660
669
  }),
661
670
 
671
+ setSessionBackend: (sessionId, backendId) =>
672
+ set((state) =>
673
+ state.backendIds[sessionId] === backendId
674
+ ? state
675
+ : { backendIds: { ...state.backendIds, [sessionId]: backendId } }
676
+ ),
677
+
662
678
  clearMessages: () => {
663
679
  const state = get();
664
680
  if (state.draft) revokeAttachmentUrls(state.draft.messages);