@trustgraph/react-state 1.7.2 → 2.0.3

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 (55) hide show
  1. package/dist/index.cjs +767 -480
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.d.ts +9 -3
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/index.esm.js +752 -480
  6. package/dist/index.esm.js.map +1 -1
  7. package/dist/model/schema-types.d.ts +16 -0
  8. package/dist/model/schema-types.d.ts.map +1 -0
  9. package/dist/state/agent-tools.d.ts +1 -1
  10. package/dist/state/agent-tools.d.ts.map +1 -1
  11. package/dist/state/auth.d.ts +36 -0
  12. package/dist/state/auth.d.ts.map +1 -0
  13. package/dist/state/chunked-download.d.ts.map +1 -1
  14. package/dist/state/chunked-upload.d.ts.map +1 -1
  15. package/dist/state/collections.d.ts.map +1 -1
  16. package/dist/state/document-embeddings-query.d.ts.map +1 -1
  17. package/dist/state/document-metadata.d.ts +1 -1
  18. package/dist/state/document-metadata.d.ts.map +1 -1
  19. package/dist/state/embeddings.d.ts +1 -1
  20. package/dist/state/embeddings.d.ts.map +1 -1
  21. package/dist/state/explainability.d.ts +1 -1
  22. package/dist/state/explainability.d.ts.map +1 -1
  23. package/dist/state/flow-blueprints.d.ts +1 -1
  24. package/dist/state/flow-blueprints.d.ts.map +1 -1
  25. package/dist/state/flow-parameters.d.ts.map +1 -1
  26. package/dist/state/flows.d.ts +1 -1
  27. package/dist/state/flows.d.ts.map +1 -1
  28. package/dist/state/graph-query.d.ts +1 -1
  29. package/dist/state/knowledge-cores.d.ts +2 -2
  30. package/dist/state/knowledge-cores.d.ts.map +1 -1
  31. package/dist/state/library.d.ts.map +1 -1
  32. package/dist/state/llm-models.d.ts +2 -2
  33. package/dist/state/llm-models.d.ts.map +1 -1
  34. package/dist/state/mcp-tools.d.ts +1 -1
  35. package/dist/state/mcp-tools.d.ts.map +1 -1
  36. package/dist/state/nlp-query.d.ts.map +1 -1
  37. package/dist/state/ontologies.d.ts.map +1 -1
  38. package/dist/state/processing.d.ts.map +1 -1
  39. package/dist/state/prompts.d.ts.map +1 -1
  40. package/dist/state/provenance.d.ts +3 -2
  41. package/dist/state/provenance.d.ts.map +1 -1
  42. package/dist/state/row-embeddings-query.d.ts.map +1 -1
  43. package/dist/state/rows-query.d.ts.map +1 -1
  44. package/dist/state/schemas.d.ts.map +1 -1
  45. package/dist/state/settings.d.ts +1 -1
  46. package/dist/state/structured-query.d.ts.map +1 -1
  47. package/dist/state/token-costs.d.ts +2 -2
  48. package/dist/state/token-costs.d.ts.map +1 -1
  49. package/dist/state/triples.d.ts +5 -10
  50. package/dist/state/triples.d.ts.map +1 -1
  51. package/dist/state/workspace.d.ts +32 -0
  52. package/dist/state/workspace.d.ts.map +1 -0
  53. package/dist/utils/explainability.d.ts +22 -24
  54. package/dist/utils/explainability.d.ts.map +1 -1
  55. package/package.json +8 -7
package/dist/index.cjs CHANGED
@@ -150,148 +150,6 @@ const useSessionStore = zustand.create()((set) => ({
150
150
  })),
151
151
  }));
152
152
 
153
- const useConversation = zustand.create()((set) => ({
154
- messages: [],
155
- input: "",
156
- chatMode: "graph-rag",
157
- setMessages: (v) => set(() => ({
158
- messages: v,
159
- })),
160
- addMessage: (role, text, type, explainSessionId) => set((state) => ({
161
- messages: [
162
- ...state.messages,
163
- {
164
- role: role,
165
- text: text,
166
- type: type || "normal",
167
- explainSessionId,
168
- },
169
- ],
170
- })),
171
- updateLastMessage: (text, explainSessionId) => set((state) => {
172
- if (state.messages.length === 0)
173
- return state;
174
- const messages = [...state.messages];
175
- messages[messages.length - 1] = {
176
- ...messages[messages.length - 1],
177
- text: text,
178
- ...(explainSessionId !== undefined && { explainSessionId }),
179
- };
180
- return { messages };
181
- }),
182
- setInput: (v) => set(() => ({
183
- input: v,
184
- })),
185
- setChatMode: (mode) => set(() => ({
186
- chatMode: mode,
187
- })),
188
- }));
189
-
190
- // Zustand state management library for creating stores
191
- /**
192
- * Zustand store for managing the main workbench application state
193
- * Provides centralized state management for tool navigation and entity selection
194
- */
195
- const useWorkbenchStateStore = zustand.create()((set) => ({
196
- // Initial state values
197
- selected: undefined, // No entity selected by default
198
- tool: "chat", // Default tool is the chat interface
199
- entities: [], // Empty entities list by default
200
- // Entity selection functions
201
- setSelected: (e) => set(() => ({
202
- selected: e,
203
- })),
204
- // Clear the current entity selection
205
- unsetSelected: () => set(() => ({
206
- selected: undefined,
207
- })),
208
- // Tool/page navigation function
209
- setTool: (v) => set(() => ({
210
- tool: v,
211
- })),
212
- // Update the list of available entities
213
- setEntities: (v) => set(() => ({
214
- entities: v,
215
- })),
216
- }));
217
-
218
- // Zustand state management library for creating stores
219
- /**
220
- * Zustand store for managing document loading state
221
- * Provides centralized state management for the document upload/loading workflow
222
- */
223
- const useLoadStateStore = zustand.create()((set) => ({
224
- // Initial state values
225
- title: "", // Empty title by default
226
- comments: "", // Empty comments by default
227
- url: "", // Empty URL by default
228
- keywords: [], // No keywords by default
229
- operation: "upload-pdf", // Default operation is PDF upload
230
- files: [], // No files selected by default
231
- uploaded: [], // No files uploaded yet
232
- text: "", // Empty text content by default
233
- // Setter functions for document metadata
234
- setTitle: (v) => set(() => ({
235
- title: v,
236
- })),
237
- setComments: (v) => set(() => ({
238
- comments: v,
239
- })),
240
- setUrl: (v) => set(() => ({
241
- url: v,
242
- })),
243
- setKeywords: (v) => set(() => ({
244
- keywords: v,
245
- })),
246
- // Setter function for processing operation type
247
- setOperation: (v) => set(() => ({
248
- operation: v,
249
- })),
250
- // Setter functions for file management
251
- setFiles: (v) => set(() => ({
252
- files: v,
253
- })),
254
- setUploaded: (v) => set(() => ({
255
- uploaded: v,
256
- })),
257
- // Add a single file to the uploaded list (preserving existing uploads)
258
- addUploaded: (v) => set((state) => ({
259
- uploaded: [...state.uploaded, v],
260
- })),
261
- setText: (v) => set(() => ({
262
- text: v,
263
- })),
264
- // Remove a specific file from the selected files list
265
- removeFile: (v) => set((state) => ({
266
- files: Array.from(state.files).filter((f) => f != v),
267
- })),
268
- // Text upload counter management
269
- textUploads: 0, // Initial counter value
270
- setTextUploads: (v) => set(() => ({
271
- textUploads: v,
272
- })),
273
- // Increment the text upload counter (useful for generating unique IDs)
274
- incTextUploads: () => set((state) => ({
275
- textUploads: state.textUploads + 1,
276
- })),
277
- }));
278
-
279
- // Zustand store for managing search functionality state
280
- const useSearchStateStore = zustand.create()((set) => ({
281
- // Initial state: no search results and empty search input
282
- rows: [],
283
- input: "",
284
- // Replace the entire rows array with new search results
285
- // Note: This completely overwrites the previous results
286
- setRows: (v) => set(() => ({
287
- rows: v,
288
- })),
289
- // Update the search input string (typically bound to search input field)
290
- setInput: (v) => set(() => ({
291
- input: v,
292
- })),
293
- }));
294
-
295
153
  const DEFAULT_SETTINGS = {
296
154
  user: "trustgraph", // Default user ID
297
155
  collection: "default", // Default collection ID
@@ -477,38 +335,485 @@ const useSettings = () => {
477
335
  const exportSettings = () => {
478
336
  return JSON.stringify(settings, null, 2);
479
337
  };
480
- // Helper function to import settings from JSON
481
- const importSettings = (jsonString) => {
338
+ // Helper function to import settings from JSON
339
+ const importSettings = (jsonString) => {
340
+ try {
341
+ const imported = JSON.parse(jsonString);
342
+ const validatedSettings = mergeWithDefaults(imported);
343
+ saveSettings(validatedSettings);
344
+ }
345
+ catch (error) {
346
+ notify.error("Failed to import settings: Invalid JSON format");
347
+ throw error;
348
+ }
349
+ };
350
+ // Return the public API for the hook
351
+ return {
352
+ // Settings data and state
353
+ settings,
354
+ isLoaded: !settingsQuery.isLoading,
355
+ isLoading: settingsQuery.isLoading,
356
+ error: settingsQuery.error,
357
+ // Settings operations
358
+ updateSetting,
359
+ saveSettings,
360
+ resetSettings,
361
+ exportSettings,
362
+ importSettings,
363
+ // Loading states for individual operations
364
+ isSaving: updateSettingsMutation.isPending,
365
+ isResetting: resetSettingsMutation.isPending,
366
+ // Manual refetch function
367
+ refetch: settingsQuery.refetch,
368
+ };
369
+ };
370
+
371
+ // Active workspace is tied to the authenticated session, so it lives in
372
+ // sessionStorage alongside the auth token rather than localStorage.
373
+ const WORKSPACE_STORAGE_KEY = "tg.workspace.active";
374
+ const readSession$1 = () => {
375
+ try {
376
+ return sessionStorage.getItem(WORKSPACE_STORAGE_KEY);
377
+ }
378
+ catch {
379
+ return null;
380
+ }
381
+ };
382
+ const writeSession$1 = (value) => {
383
+ try {
384
+ if (value === null)
385
+ sessionStorage.removeItem(WORKSPACE_STORAGE_KEY);
386
+ else
387
+ sessionStorage.setItem(WORKSPACE_STORAGE_KEY, value);
388
+ }
389
+ catch {
390
+ /* ignore */
391
+ }
392
+ };
393
+ const useWorkspaceStore = zustand.create((set) => ({
394
+ activeWorkspace: readSession$1(),
395
+ generation: 0,
396
+ initActiveWorkspace: (id) => set((s) => {
397
+ if (s.activeWorkspace)
398
+ return s;
399
+ writeSession$1(id);
400
+ return { activeWorkspace: id };
401
+ }),
402
+ setActiveWorkspace: (id) => {
403
+ writeSession$1(id);
404
+ set((s) => ({ activeWorkspace: id, generation: s.generation + 1 }));
405
+ },
406
+ bumpGeneration: () => set((s) => ({ generation: s.generation + 1 })),
407
+ clearActiveWorkspace: () => {
408
+ writeSession$1(null);
409
+ set({ activeWorkspace: null });
410
+ },
411
+ }));
412
+ // Discover the workspaces the caller can access (one for an ordinary
413
+ // user, all for an admin — driven entirely by what the gateway returns).
414
+ const useWorkspaces = () => {
415
+ const socket = reactProvider.useSocket();
416
+ const connectionState = reactProvider.useConnectionState();
417
+ const isSocketReady = connectionState?.status === "authenticated";
418
+ const query = reactQuery.useQuery({
419
+ queryKey: ["workspaces"],
420
+ enabled: isSocketReady,
421
+ queryFn: () => socket.iam().listMyWorkspaces(),
422
+ });
423
+ return {
424
+ workspaces: query.data || [],
425
+ isLoading: query.isLoading,
426
+ isError: query.isError,
427
+ error: query.error,
428
+ refetch: query.refetch,
429
+ };
430
+ };
431
+ // The caller's own user record, including their home/default workspace.
432
+ const useWhoami = () => {
433
+ const socket = reactProvider.useSocket();
434
+ const connectionState = reactProvider.useConnectionState();
435
+ const isSocketReady = connectionState?.status === "authenticated";
436
+ const query = reactQuery.useQuery({
437
+ queryKey: ["whoami"],
438
+ enabled: isSocketReady,
439
+ queryFn: () => socket.iam().whoami(),
440
+ });
441
+ return {
442
+ whoami: query.data,
443
+ isLoading: query.isLoading,
444
+ isError: query.isError,
445
+ error: query.error,
446
+ refetch: query.refetch,
447
+ };
448
+ };
449
+ // Bootstrap + keep the socket's outbound workspace in sync. Mount once,
450
+ // high in the tree (e.g. in the authenticated app shell).
451
+ const useWorkspaceSync = () => {
452
+ const socket = reactProvider.useSocket();
453
+ const activeWorkspace = useWorkspaceStore((s) => s.activeWorkspace);
454
+ const initActiveWorkspace = useWorkspaceStore((s) => s.initActiveWorkspace);
455
+ const setActiveWorkspace = useWorkspaceStore((s) => s.setActiveWorkspace);
456
+ const { whoami } = useWhoami();
457
+ const { workspaces } = useWorkspaces();
458
+ // Until we know the stored workspace is valid, don't stamp it on the
459
+ // socket — use empty string so the gateway falls back to the token's
460
+ // default. This prevents a stale/deleted workspace in sessionStorage
461
+ // from poisoning every request (including the whoami/list calls we
462
+ // need to detect the problem).
463
+ const validated = workspaces.length > 0 && activeWorkspace
464
+ ? workspaces.some((w) => w.id === activeWorkspace)
465
+ : false;
466
+ // Adopt the user's default workspace when we have no active one yet.
467
+ react.useEffect(() => {
468
+ if (!activeWorkspace && whoami?.default_workspace) {
469
+ initActiveWorkspace(whoami.default_workspace);
470
+ }
471
+ }, [activeWorkspace, whoami, initActiveWorkspace]);
472
+ // If the stored workspace no longer exists, fall back to the user's
473
+ // default workspace.
474
+ react.useEffect(() => {
475
+ if (!activeWorkspace || !whoami?.default_workspace || workspaces.length === 0)
476
+ return;
477
+ if (!validated) {
478
+ setActiveWorkspace(whoami.default_workspace);
479
+ }
480
+ }, [activeWorkspace, workspaces, whoami, validated, setActiveWorkspace]);
481
+ // Only stamp a validated workspace onto the socket.
482
+ // Bump generation so hooks that depend on it re-fire with the
483
+ // workspace now set on the socket.
484
+ const bumpGeneration = useWorkspaceStore((s) => s.bumpGeneration);
485
+ react.useEffect(() => {
486
+ socket.workspace = validated ? activeWorkspace : "";
487
+ if (validated)
488
+ bumpGeneration();
489
+ }, [socket, activeWorkspace, validated, bumpGeneration]);
490
+ };
491
+ // Active workspace + the switcher action for components.
492
+ const useWorkspace = () => {
493
+ const socket = reactProvider.useSocket();
494
+ const queryClient = reactQuery.useQueryClient();
495
+ const activeWorkspace = useWorkspaceStore((s) => s.activeWorkspace);
496
+ const generation = useWorkspaceStore((s) => s.generation);
497
+ const setActiveWorkspace = useWorkspaceStore((s) => s.setActiveWorkspace);
498
+ const setFlowId = useSessionStore((s) => s.setFlowId);
499
+ const { updateSetting } = useSettings();
500
+ const { workspaces } = useWorkspaces();
501
+ const { whoami } = useWhoami();
502
+ // Switching workspace is a full context reset: collections, flows,
503
+ // documents and config all re-scope. Reset the inner context (flow +
504
+ // collection) to defaults and invalidate every cache so all pages
505
+ // refetch under the new workspace.
506
+ const switchWorkspace = react.useCallback((id) => {
507
+ if (!id || id === activeWorkspace)
508
+ return;
509
+ // Set synchronously so refetches triggered below already carry it.
510
+ socket.workspace = id;
511
+ setActiveWorkspace(id);
512
+ setFlowId("default");
513
+ updateSetting("collection", "default");
514
+ // Wipe workspace-scoped caches so stale data from the previous
515
+ // workspace can't bleed through, then invalidate to trigger refetches.
516
+ const keep = ["workspaces", "whoami", "settings"];
517
+ queryClient.removeQueries({
518
+ predicate: (q) => !keep.includes(q.queryKey[0]),
519
+ });
520
+ queryClient.invalidateQueries();
521
+ }, [
522
+ activeWorkspace,
523
+ socket,
524
+ setActiveWorkspace,
525
+ setFlowId,
526
+ updateSetting,
527
+ queryClient,
528
+ ]);
529
+ return {
530
+ activeWorkspace,
531
+ workspaces,
532
+ defaultWorkspace: whoami?.default_workspace ?? null,
533
+ generation,
534
+ switchWorkspace,
535
+ };
536
+ };
537
+
538
+ const useConversation = zustand.create()((set) => ({
539
+ messages: [],
540
+ input: "",
541
+ chatMode: "graph-rag",
542
+ setMessages: (v) => set(() => ({
543
+ messages: v,
544
+ })),
545
+ addMessage: (role, text, type, explainSessionId) => set((state) => ({
546
+ messages: [
547
+ ...state.messages,
548
+ {
549
+ role: role,
550
+ text: text,
551
+ type: type || "normal",
552
+ explainSessionId,
553
+ },
554
+ ],
555
+ })),
556
+ updateLastMessage: (text, explainSessionId) => set((state) => {
557
+ if (state.messages.length === 0)
558
+ return state;
559
+ const messages = [...state.messages];
560
+ messages[messages.length - 1] = {
561
+ ...messages[messages.length - 1],
562
+ text: text,
563
+ ...(explainSessionId !== undefined && { explainSessionId }),
564
+ };
565
+ return { messages };
566
+ }),
567
+ setInput: (v) => set(() => ({
568
+ input: v,
569
+ })),
570
+ setChatMode: (mode) => set(() => ({
571
+ chatMode: mode,
572
+ })),
573
+ }));
574
+
575
+ // Zustand state management library for creating stores
576
+ /**
577
+ * Zustand store for managing the main workbench application state
578
+ * Provides centralized state management for tool navigation and entity selection
579
+ */
580
+ const useWorkbenchStateStore = zustand.create()((set) => ({
581
+ // Initial state values
582
+ selected: undefined, // No entity selected by default
583
+ tool: "chat", // Default tool is the chat interface
584
+ entities: [], // Empty entities list by default
585
+ // Entity selection functions
586
+ setSelected: (e) => set(() => ({
587
+ selected: e,
588
+ })),
589
+ // Clear the current entity selection
590
+ unsetSelected: () => set(() => ({
591
+ selected: undefined,
592
+ })),
593
+ // Tool/page navigation function
594
+ setTool: (v) => set(() => ({
595
+ tool: v,
596
+ })),
597
+ // Update the list of available entities
598
+ setEntities: (v) => set(() => ({
599
+ entities: v,
600
+ })),
601
+ }));
602
+
603
+ // Zustand state management library for creating stores
604
+ /**
605
+ * Zustand store for managing document loading state
606
+ * Provides centralized state management for the document upload/loading workflow
607
+ */
608
+ const useLoadStateStore = zustand.create()((set) => ({
609
+ // Initial state values
610
+ title: "", // Empty title by default
611
+ comments: "", // Empty comments by default
612
+ url: "", // Empty URL by default
613
+ keywords: [], // No keywords by default
614
+ operation: "upload-pdf", // Default operation is PDF upload
615
+ files: [], // No files selected by default
616
+ uploaded: [], // No files uploaded yet
617
+ text: "", // Empty text content by default
618
+ // Setter functions for document metadata
619
+ setTitle: (v) => set(() => ({
620
+ title: v,
621
+ })),
622
+ setComments: (v) => set(() => ({
623
+ comments: v,
624
+ })),
625
+ setUrl: (v) => set(() => ({
626
+ url: v,
627
+ })),
628
+ setKeywords: (v) => set(() => ({
629
+ keywords: v,
630
+ })),
631
+ // Setter function for processing operation type
632
+ setOperation: (v) => set(() => ({
633
+ operation: v,
634
+ })),
635
+ // Setter functions for file management
636
+ setFiles: (v) => set(() => ({
637
+ files: v,
638
+ })),
639
+ setUploaded: (v) => set(() => ({
640
+ uploaded: v,
641
+ })),
642
+ // Add a single file to the uploaded list (preserving existing uploads)
643
+ addUploaded: (v) => set((state) => ({
644
+ uploaded: [...state.uploaded, v],
645
+ })),
646
+ setText: (v) => set(() => ({
647
+ text: v,
648
+ })),
649
+ // Remove a specific file from the selected files list
650
+ removeFile: (v) => set((state) => ({
651
+ files: Array.from(state.files).filter((f) => f != v),
652
+ })),
653
+ // Text upload counter management
654
+ textUploads: 0, // Initial counter value
655
+ setTextUploads: (v) => set(() => ({
656
+ textUploads: v,
657
+ })),
658
+ // Increment the text upload counter (useful for generating unique IDs)
659
+ incTextUploads: () => set((state) => ({
660
+ textUploads: state.textUploads + 1,
661
+ })),
662
+ }));
663
+
664
+ // Zustand store for managing search functionality state
665
+ const useSearchStateStore = zustand.create()((set) => ({
666
+ // Initial state: no search results and empty search input
667
+ rows: [],
668
+ input: "",
669
+ // Replace the entire rows array with new search results
670
+ // Note: This completely overwrites the previous results
671
+ setRows: (v) => set(() => ({
672
+ rows: v,
673
+ })),
674
+ // Update the search input string (typically bound to search input field)
675
+ setInput: (v) => set(() => ({
676
+ input: v,
677
+ })),
678
+ }));
679
+
680
+ const TOKEN_STORAGE_KEY = "tg.auth.token";
681
+ const EXPIRES_STORAGE_KEY = "tg.auth.expires";
682
+ const readSession = (key) => {
683
+ try {
684
+ return sessionStorage.getItem(key);
685
+ }
686
+ catch {
687
+ return null;
688
+ }
689
+ };
690
+ const writeSession = (key, value) => {
691
+ try {
692
+ if (value === null)
693
+ sessionStorage.removeItem(key);
694
+ else
695
+ sessionStorage.setItem(key, value);
696
+ }
697
+ catch {
698
+ /* ignore */
699
+ }
700
+ };
701
+ const initialToken = readSession(TOKEN_STORAGE_KEY);
702
+ const initialExpires = readSession(EXPIRES_STORAGE_KEY);
703
+ const useAuthStore = zustand.create((set) => ({
704
+ token: initialToken,
705
+ jwtExpires: initialExpires,
706
+ status: initialToken ? "authenticated" : "idle",
707
+ error: null,
708
+ setToken: (token, expires) => {
709
+ writeSession(TOKEN_STORAGE_KEY, token);
710
+ writeSession(EXPIRES_STORAGE_KEY, expires ?? null);
711
+ set({
712
+ token,
713
+ jwtExpires: expires ?? null,
714
+ status: "authenticated",
715
+ error: null,
716
+ });
717
+ },
718
+ clearToken: () => {
719
+ writeSession(TOKEN_STORAGE_KEY, null);
720
+ writeSession(EXPIRES_STORAGE_KEY, null);
721
+ set({
722
+ token: null,
723
+ jwtExpires: null,
724
+ status: "idle",
725
+ error: null,
726
+ });
727
+ },
728
+ setStatus: (status, error) => set({ status, error: error ?? null }),
729
+ }));
730
+ // Module-level AuthApi singleton. Configurable via configureAuthApi() — the
731
+ // demo (or any consumer) can override URLs / fetchImpl before any hook
732
+ // runs.
733
+ let authApiSingleton = client.createAuthApi();
734
+ const configureAuthApi = (options) => {
735
+ authApiSingleton = client.createAuthApi(options);
736
+ };
737
+ const getAuthApi = () => authApiSingleton;
738
+ const useAuth = () => {
739
+ const token = useAuthStore((s) => s.token);
740
+ const jwtExpires = useAuthStore((s) => s.jwtExpires);
741
+ const status = useAuthStore((s) => s.status);
742
+ const error = useAuthStore((s) => s.error);
743
+ return {
744
+ token,
745
+ jwtExpires,
746
+ status,
747
+ error,
748
+ isAuthenticated: status === "authenticated" && !!token,
749
+ };
750
+ };
751
+ const useLogin = () => {
752
+ const setToken = useAuthStore((s) => s.setToken);
753
+ const setStatus = useAuthStore((s) => s.setStatus);
754
+ const status = useAuthStore((s) => s.status);
755
+ const error = useAuthStore((s) => s.error);
756
+ const login = react.useCallback(async (username, password, default_workspace) => {
757
+ setStatus("logging-in", null);
482
758
  try {
483
- const imported = JSON.parse(jsonString);
484
- const validatedSettings = mergeWithDefaults(imported);
485
- saveSettings(validatedSettings);
759
+ const result = await getAuthApi().login(username, password, default_workspace);
760
+ setToken(result.jwt, result.jwtExpires);
761
+ return true;
486
762
  }
487
- catch (error) {
488
- notify.error("Failed to import settings: Invalid JSON format");
489
- throw error;
763
+ catch (e) {
764
+ const message = e instanceof client.AuthError
765
+ ? e.message
766
+ : e instanceof Error
767
+ ? e.message
768
+ : "login failed";
769
+ setStatus("auth-failed", message);
770
+ return false;
490
771
  }
491
- };
492
- // Return the public API for the hook
772
+ }, [setToken, setStatus]);
493
773
  return {
494
- // Settings data and state
495
- settings,
496
- isLoaded: !settingsQuery.isLoading,
497
- isLoading: settingsQuery.isLoading,
498
- error: settingsQuery.error,
499
- // Settings operations
500
- updateSetting,
501
- saveSettings,
502
- resetSettings,
503
- exportSettings,
504
- importSettings,
505
- // Loading states for individual operations
506
- isSaving: updateSettingsMutation.isPending,
507
- isResetting: resetSettingsMutation.isPending,
508
- // Manual refetch function
509
- refetch: settingsQuery.refetch,
774
+ login,
775
+ isLoading: status === "logging-in",
776
+ error,
510
777
  };
511
778
  };
779
+ const useLogout = () => {
780
+ const clearToken = useAuthStore((s) => s.clearToken);
781
+ return react.useCallback(() => clearToken(), [clearToken]);
782
+ };
783
+ const useBootstrapStatus = () => {
784
+ const [phase, setPhase] = react.useState("checking");
785
+ const [error, setError] = react.useState(null);
786
+ const cancelled = react.useRef(false);
787
+ const check = react.useCallback(async () => {
788
+ setPhase("checking");
789
+ setError(null);
790
+ try {
791
+ const result = await getAuthApi().bootstrapStatus();
792
+ if (cancelled.current)
793
+ return;
794
+ setPhase(result.bootstrapAvailable ? "needs-bootstrap" : "normal");
795
+ }
796
+ catch (e) {
797
+ if (cancelled.current)
798
+ return;
799
+ const message = e instanceof Error ? e.message : "bootstrap-status failed";
800
+ // Distinguish "service unreachable" (likely pre-bootstrap or down)
801
+ // from other errors. The IAM spec doesn't define a separate signal
802
+ // for pre-bootstrap, so we treat any failure to reach the endpoint
803
+ // as pre-bootstrap territory and let the operator interpret.
804
+ setError(message);
805
+ setPhase("pre-bootstrap");
806
+ }
807
+ }, []);
808
+ react.useEffect(() => {
809
+ cancelled.current = false;
810
+ check();
811
+ return () => {
812
+ cancelled.current = true;
813
+ };
814
+ }, [check]);
815
+ return { phase, error, refetch: check };
816
+ };
512
817
 
513
818
  /**
514
819
  * Custom hook for managing flow operations
@@ -524,8 +829,7 @@ const useFlows = () => {
524
829
  // Hook for displaying user notifications
525
830
  const notify = useNotification();
526
831
  // Only enable queries when socket is connected and ready
527
- const isSocketReady = connectionState?.status === "authenticated" ||
528
- connectionState?.status === "unauthenticated";
832
+ const isSocketReady = connectionState?.status === "authenticated";
529
833
  /**
530
834
  * Query for fetching all flows
531
835
  * Uses React Query for caching and background refetching
@@ -746,8 +1050,7 @@ const useLibrary = () => {
746
1050
  // Hook for displaying user notifications
747
1051
  const notify = useNotification();
748
1052
  // Only enable queries when socket is connected and ready
749
- const isSocketReady = connectionState?.status === "authenticated" ||
750
- connectionState?.status === "unauthenticated";
1053
+ const isSocketReady = connectionState?.status === "authenticated";
751
1054
  /**
752
1055
  * Query for fetching all documents from the library
753
1056
  * Uses React Query for caching and background refetching
@@ -916,57 +1219,35 @@ const useLibrary = () => {
916
1219
  };
917
1220
  };
918
1221
 
919
- // @ts-nocheck
920
- /**
921
- * Custom hook for managing token cost operations
922
- * Provides functionality for fetching, deleting, and updating token costs
923
- * for AI models
924
- * @returns {Object} Token cost state and operations
925
- */
926
1222
  const useTriples = ({ flow, s, p, o, limit, collection }) => {
927
- // WebSocket connection for communicating with the configuration service
928
1223
  const socket = reactProvider.useSocket();
929
- // Hook for displaying user notifications
930
1224
  const notify = useNotification();
931
- // Settings for default collection
932
1225
  const { settings } = useSettings();
933
- // Session state for default flow ID
1226
+ const connectionState = reactProvider.useConnectionState();
1227
+ const isSocketReady = connectionState?.status === "authenticated";
934
1228
  const sessionFlowId = useSessionStore((state) => state.flowId);
935
- // Use explicit param if provided, otherwise fall back to session state
936
1229
  const effectiveFlow = flow ?? sessionFlowId;
937
- /**
938
- * Query for fetching all token costs
939
- * Uses React Query for caching and background refetching
940
- */
1230
+ const effectiveCollection = collection || settings.collection;
941
1231
  const query = reactQuery.useQuery({
942
- queryKey: ["triples", { flow: effectiveFlow, s, p, o, limit }],
1232
+ queryKey: ["triples", { flow: effectiveFlow, s, p, o, limit, collection: effectiveCollection }],
1233
+ enabled: isSocketReady,
943
1234
  queryFn: () => {
944
1235
  return socket
945
1236
  .flow(effectiveFlow)
946
- .triplesQuery(s, p, o, limit, collection || settings.collection)
947
- .then((x) => {
948
- if (x["error"]) {
949
- console.log("Error:", x);
950
- throw x.error.message;
951
- }
952
- return x;
953
- })
1237
+ .triplesQuery(s, p, o, limit, effectiveCollection)
954
1238
  .catch((err) => {
955
- console.log("Error:", err);
956
- notify.error(err);
1239
+ const message = err instanceof Error ? err.message : String(err);
1240
+ notify.error(message);
1241
+ throw err;
957
1242
  });
958
1243
  },
959
1244
  });
960
- // Show loading indicators for long-running operations
961
1245
  useActivity(query.isLoading, "Loading triples");
962
- // Return token cost state and operations for use in components
963
1246
  return {
964
- // Token cost query state
965
- triples: query.data,
1247
+ triples: (query.data ?? []),
966
1248
  isLoading: query.isLoading,
967
1249
  isError: query.isError,
968
1250
  error: query.error,
969
- // Manual refetch function
970
1251
  refetch: query.refetch,
971
1252
  };
972
1253
  };
@@ -1922,11 +2203,13 @@ const useExplainabilityStore = zustand.create()((set, get) => ({
1922
2203
  /**
1923
2204
  * Explainability utilities for parsing and structuring explain events
1924
2205
  */
1925
- // Agent-specific predicates (not yet in client library)
2206
+ // Predicates not yet in client library
1926
2207
  const TG_ACTION = client.TG + "action";
1927
2208
  const TG_ARGUMENTS = client.TG + "arguments";
1928
2209
  const TG_SUBAGENT_GOAL = client.TG + "subagentGoal";
1929
- // RDF type URIs for agent events
2210
+ const TG_CONCEPT = client.TG_CONCEPT;
2211
+ const TG_ENTITY = client.TG + "entity";
2212
+ // RDF type URIs
1930
2213
  const TG_AGENT_QUESTION = client.TG + "AgentQuestion";
1931
2214
  const TG_ANALYSIS = client.TG + "Analysis";
1932
2215
  const TG_TOOL_USE = client.TG + "ToolUse";
@@ -1934,13 +2217,14 @@ const TG_OBSERVATION = client.TG + "Observation";
1934
2217
  const TG_THOUGHT_TYPE = client.TG + "Thought";
1935
2218
  const TG_REFLECTION_TYPE = client.TG + "Reflection";
1936
2219
  const TG_CONCLUSION = client.TG + "Conclusion";
1937
- const TG_ANSWER = client.TG + "Answer";
1938
2220
  const TG_FINDING = client.TG + "Finding";
1939
- const TG_SYNTHESIS_TYPE = client.TG + "Synthesis";
1940
2221
  const TG_DECOMPOSITION = client.TG + "Decomposition";
2222
+ const TG_GROUNDING = client.TG + "Grounding";
2223
+ const TG_EXPLORATION_TYPE = client.TG + "Exploration";
2224
+ const TG_FOCUS_TYPE = client.TG + "Focus";
1941
2225
  // ── Helpers ─────────────────────────────────────────────────────────
1942
2226
  /**
1943
- * Extract event type from explainId URI (graph-rag only)
2227
+ * Extract event type from explainId URI (graph-rag fallback)
1944
2228
  */
1945
2229
  function getEventType(explainId) {
1946
2230
  if (explainId.includes("question"))
@@ -1953,9 +2237,6 @@ function getEventType(explainId) {
1953
2237
  return "synthesis";
1954
2238
  return "unknown";
1955
2239
  }
1956
- /**
1957
- * Get term value from a Term object
1958
- */
1959
2240
  function getTermValue$1(term) {
1960
2241
  if (!term)
1961
2242
  return "";
@@ -1964,7 +2245,6 @@ function getTermValue$1(term) {
1964
2245
  if (term.t === "l")
1965
2246
  return term.v || "";
1966
2247
  if (term.t === "t" && term.tr) {
1967
- // Quoted triple - return a serialized form
1968
2248
  const s = getTermValue$1(term.tr.s);
1969
2249
  const p = getTermValue$1(term.tr.p);
1970
2250
  const o = getTermValue$1(term.tr.o);
@@ -1972,9 +2252,6 @@ function getTermValue$1(term) {
1972
2252
  }
1973
2253
  return "";
1974
2254
  }
1975
- /**
1976
- * Extract quoted triple from a Term
1977
- */
1978
2255
  function extractQuotedTriple(term) {
1979
2256
  if (term.t === "t" && term.tr) {
1980
2257
  return {
@@ -1985,9 +2262,15 @@ function extractQuotedTriple(term) {
1985
2262
  }
1986
2263
  return null;
1987
2264
  }
1988
- // ── Agent event type detection ──────────────────────────────────────
1989
- /** Map RDF type URI → agent event type (first match wins) */
1990
- const AGENT_TYPE_CHECKS = [
2265
+ // ── RDF type detection ──────────────────────────────────────────────
2266
+ /**
2267
+ * Map RDF type URI → event type (first match wins).
2268
+ * Agent-specific types only — shared types like tg:Synthesis and
2269
+ * tg:Answer are excluded to avoid catching graph-rag events.
2270
+ * Grounding, Exploration, Focus are included since they now carry
2271
+ * embedded triples with their RDF type.
2272
+ */
2273
+ const RDF_TYPE_CHECKS = [
1991
2274
  [TG_AGENT_QUESTION, "agent-question"],
1992
2275
  [TG_DECOMPOSITION, "decomposition"],
1993
2276
  [TG_ANALYSIS, "analysis"],
@@ -1997,12 +2280,12 @@ const AGENT_TYPE_CHECKS = [
1997
2280
  [TG_REFLECTION_TYPE, "reflection"],
1998
2281
  [TG_CONCLUSION, "conclusion"],
1999
2282
  [TG_FINDING, "conclusion"],
2000
- [TG_SYNTHESIS_TYPE, "conclusion"],
2001
- [TG_ANSWER, "conclusion"],
2283
+ [TG_GROUNDING, "grounding"],
2284
+ [TG_EXPLORATION_TYPE, "exploration"],
2285
+ [TG_FOCUS_TYPE, "focus"],
2002
2286
  ];
2003
2287
  /**
2004
2288
  * Detect event type from RDF types in embedded triples.
2005
- * Returns an agent event type if matched, "unknown" otherwise.
2006
2289
  */
2007
2290
  function getEventTypeFromTriples(triples) {
2008
2291
  const types = new Set();
@@ -2011,7 +2294,7 @@ function getEventTypeFromTriples(triples) {
2011
2294
  types.add(getTermValue$1(t.o));
2012
2295
  }
2013
2296
  }
2014
- for (const [typeUri, eventType] of AGENT_TYPE_CHECKS) {
2297
+ for (const [typeUri, eventType] of RDF_TYPE_CHECKS) {
2015
2298
  if (types.has(typeUri))
2016
2299
  return eventType;
2017
2300
  }
@@ -2031,38 +2314,69 @@ function extractCommonFields(triples) {
2031
2314
  }
2032
2315
  return { label, derivedFrom };
2033
2316
  }
2034
- // ── Graph-RAG parsers (existing) ────────────────────────────────────
2317
+ /**
2318
+ * Extract inline edges from triples (tg:edge quoted triples + concept/score).
2319
+ * Groups by edge selection subject URI to associate edge, concept, and score.
2320
+ * Returns SelectedEdge objects with URIs — labels resolved later.
2321
+ */
2322
+ function extractInlineEdges(triples) {
2323
+ const bySubject = new Map();
2324
+ for (const t of triples) {
2325
+ const s = getTermValue$1(t.s);
2326
+ const p = getTermValue$1(t.p);
2327
+ if (p === client.TG_EDGE && t.o.t === "t" && t.o.tr) {
2328
+ const edge = extractQuotedTriple(t.o);
2329
+ if (edge) {
2330
+ const existing = bySubject.get(s) || { edge };
2331
+ existing.edge = edge;
2332
+ bySubject.set(s, existing);
2333
+ }
2334
+ }
2335
+ else if (p === TG_CONCEPT) {
2336
+ const concept = getTermValue$1(t.o);
2337
+ if (concept) {
2338
+ const existing = bySubject.get(s) || { edge: { s: "", p: "", o: "" } };
2339
+ existing.concept = concept;
2340
+ bySubject.set(s, existing);
2341
+ }
2342
+ }
2343
+ else if (p === client.TG_SCORE) {
2344
+ const scoreStr = getTermValue$1(t.o);
2345
+ if (scoreStr) {
2346
+ const existing = bySubject.get(s) || { edge: { s: "", p: "", o: "" } };
2347
+ existing.score = parseFloat(scoreStr);
2348
+ bySubject.set(s, existing);
2349
+ }
2350
+ }
2351
+ }
2352
+ return Array.from(bySubject.values()).filter(se => se.edge.s !== "");
2353
+ }
2354
+ // ── Parsers ─────────────────────────────────────────────────────────
2035
2355
  function parseQuestionTriples(explainId, explainGraph, triples) {
2036
- const event = {
2037
- type: "question",
2038
- explainId,
2039
- explainGraph,
2040
- };
2041
- for (const triple of triples) {
2042
- const p = getTermValue$1(triple.p);
2043
- const o = getTermValue$1(triple.o);
2044
- if (p === client.TG_QUERY) {
2356
+ const event = { type: "question", explainId, explainGraph };
2357
+ for (const t of triples) {
2358
+ const p = getTermValue$1(t.p);
2359
+ const o = getTermValue$1(t.o);
2360
+ if (p === client.TG_QUERY)
2045
2361
  event.query = o;
2046
- }
2047
- else if (p === client.PROV_STARTED_AT_TIME) {
2362
+ else if (p === client.PROV_STARTED_AT_TIME)
2048
2363
  event.timestamp = o;
2049
- }
2050
2364
  }
2051
2365
  return event;
2052
2366
  }
2053
2367
  function parseExplorationTriples(explainId, explainGraph, triples) {
2054
- const event = {
2055
- type: "exploration",
2056
- explainId,
2057
- explainGraph,
2058
- };
2059
- for (const triple of triples) {
2060
- const p = getTermValue$1(triple.p);
2061
- const o = getTermValue$1(triple.o);
2062
- if (p === client.TG_EDGE_COUNT) {
2368
+ const event = { type: "exploration", explainId, explainGraph };
2369
+ const entities = [];
2370
+ for (const t of triples) {
2371
+ const p = getTermValue$1(t.p);
2372
+ const o = getTermValue$1(t.o);
2373
+ if (p === client.TG_EDGE_COUNT)
2063
2374
  event.edgeCount = parseInt(o, 10);
2064
- }
2375
+ if (p === TG_ENTITY && o)
2376
+ entities.push(o);
2065
2377
  }
2378
+ if (entities.length > 0)
2379
+ event.entities = entities;
2066
2380
  return event;
2067
2381
  }
2068
2382
  function parseFocusTriples(explainId, explainGraph, triples) {
@@ -2072,53 +2386,64 @@ function parseFocusTriples(explainId, explainGraph, triples) {
2072
2386
  explainGraph,
2073
2387
  edgeSelectionUris: [],
2074
2388
  };
2075
- for (const triple of triples) {
2076
- const p = getTermValue$1(triple.p);
2077
- const o = getTermValue$1(triple.o);
2389
+ // Collect edge selection URIs (old format)
2390
+ for (const t of triples) {
2391
+ const p = getTermValue$1(t.p);
2392
+ const o = getTermValue$1(t.o);
2078
2393
  if (p === client.TG_SELECTED_EDGE && typeof o === "string") {
2079
2394
  event.edgeSelectionUris.push(o);
2080
2395
  }
2081
2396
  }
2397
+ // Extract inline edges (new format: tg:edge with quoted triples)
2398
+ const inlineEdges = extractInlineEdges(triples);
2399
+ if (inlineEdges.length > 0) {
2400
+ event.selectedEdges = inlineEdges;
2401
+ }
2082
2402
  return event;
2083
2403
  }
2084
2404
  function parseSynthesisTriples(explainId, explainGraph, triples) {
2085
- const event = {
2086
- type: "synthesis",
2087
- explainId,
2088
- explainGraph,
2089
- };
2090
- for (const triple of triples) {
2091
- const p = getTermValue$1(triple.p);
2092
- const o = getTermValue$1(triple.o);
2093
- if (p === client.TG_CONTENT) {
2405
+ const event = { type: "synthesis", explainId, explainGraph };
2406
+ for (const t of triples) {
2407
+ const p = getTermValue$1(t.p);
2408
+ const o = getTermValue$1(t.o);
2409
+ if (p === client.TG_CONTENT)
2094
2410
  event.contentLength = o.length;
2095
- }
2096
2411
  }
2097
2412
  return event;
2098
2413
  }
2099
2414
  function parseEdgeSelectionTriples(triples) {
2100
2415
  let edge = null;
2101
- let reasoning = null;
2416
+ let concept = null;
2417
+ let score = null;
2102
2418
  for (const triple of triples) {
2103
2419
  const p = getTermValue$1(triple.p);
2104
- if (p === client.TG_EDGE) {
2420
+ if (p === client.TG_EDGE)
2105
2421
  edge = extractQuotedTriple(triple.o);
2422
+ else if (p === TG_CONCEPT)
2423
+ concept = getTermValue$1(triple.o);
2424
+ else if (p === client.TG_SCORE) {
2425
+ const v = getTermValue$1(triple.o);
2426
+ if (v)
2427
+ score = parseFloat(v);
2106
2428
  }
2107
- else if (p === client.TG_REASONING) {
2108
- reasoning = getTermValue$1(triple.o);
2109
- }
2110
2429
  }
2111
- return { edge, reasoning };
2430
+ return { edge, concept, score };
2431
+ }
2432
+ function parseGroundingTriples(explainId, explainGraph, triples) {
2433
+ const { label, derivedFrom } = extractCommonFields(triples);
2434
+ const concepts = [];
2435
+ for (const t of triples) {
2436
+ const p = getTermValue$1(t.p);
2437
+ const o = getTermValue$1(t.o);
2438
+ if (p === TG_CONCEPT && o)
2439
+ concepts.push(o);
2440
+ }
2441
+ return { type: "grounding", explainId, explainGraph, label, concepts, derivedFrom };
2112
2442
  }
2113
- // ── Agent parsers (new) ─────────────────────────────────────────────
2114
2443
  function parseAgentQuestionTriples(explainId, explainGraph, triples) {
2115
2444
  const { label, derivedFrom } = extractCommonFields(triples);
2116
2445
  const event = {
2117
- type: "agent-question",
2118
- explainId,
2119
- explainGraph,
2120
- label,
2121
- derivedFrom,
2446
+ type: "agent-question", explainId, explainGraph, label, derivedFrom,
2122
2447
  };
2123
2448
  for (const t of triples) {
2124
2449
  const p = getTermValue$1(t.p);
@@ -2139,23 +2464,12 @@ function parseDecompositionTriples(explainId, explainGraph, triples) {
2139
2464
  if (p === TG_SUBAGENT_GOAL && o)
2140
2465
  goals.push(o);
2141
2466
  }
2142
- return {
2143
- type: "decomposition",
2144
- explainId,
2145
- explainGraph,
2146
- label,
2147
- goals,
2148
- derivedFrom,
2149
- };
2467
+ return { type: "decomposition", explainId, explainGraph, label, goals, derivedFrom };
2150
2468
  }
2151
2469
  function parseAnalysisTriples(explainId, explainGraph, triples) {
2152
2470
  const { label, derivedFrom } = extractCommonFields(triples);
2153
2471
  const event = {
2154
- type: "analysis",
2155
- explainId,
2156
- explainGraph,
2157
- label,
2158
- derivedFrom,
2472
+ type: "analysis", explainId, explainGraph, label, derivedFrom,
2159
2473
  };
2160
2474
  for (const t of triples) {
2161
2475
  const p = getTermValue$1(t.p);
@@ -2169,34 +2483,22 @@ function parseAnalysisTriples(explainId, explainGraph, triples) {
2169
2483
  }
2170
2484
  function parseReflectionTriples(explainId, explainGraph, triples) {
2171
2485
  const { label, derivedFrom } = extractCommonFields(triples);
2172
- return {
2173
- type: "reflection",
2174
- explainId,
2175
- explainGraph,
2176
- label,
2177
- derivedFrom,
2178
- };
2486
+ return { type: "reflection", explainId, explainGraph, label, derivedFrom };
2179
2487
  }
2180
2488
  function parseConclusionTriples(explainId, explainGraph, triples) {
2181
2489
  const { label, derivedFrom } = extractCommonFields(triples);
2182
- return {
2183
- type: "conclusion",
2184
- explainId,
2185
- explainGraph,
2186
- label,
2187
- derivedFrom,
2188
- };
2490
+ return { type: "conclusion", explainId, explainGraph, label, derivedFrom };
2189
2491
  }
2190
2492
  // ── Unified parser ──────────────────────────────────────────────────
2191
2493
  /**
2192
2494
  * Parse triples into a structured event.
2193
- * Tries RDF type detection first (agent events), then URI patterns (graph-rag).
2194
- * Returns null for events with no triples (inner graph-rag plumbing).
2495
+ * Tries RDF type detection first, then URI patterns as fallback.
2496
+ * Returns null for events with no triples.
2195
2497
  */
2196
2498
  function parseExplainTriples(explainId, explainGraph, triples) {
2197
2499
  if (triples.length === 0)
2198
2500
  return null;
2199
- // Try RDF type detection first (agent events with embedded triples)
2501
+ // Try RDF type detection first
2200
2502
  const rdfEventType = getEventTypeFromTriples(triples);
2201
2503
  if (rdfEventType !== "unknown") {
2202
2504
  switch (rdfEventType) {
@@ -2210,6 +2512,12 @@ function parseExplainTriples(explainId, explainGraph, triples) {
2210
2512
  return parseReflectionTriples(explainId, explainGraph, triples);
2211
2513
  case "conclusion":
2212
2514
  return parseConclusionTriples(explainId, explainGraph, triples);
2515
+ case "grounding":
2516
+ return parseGroundingTriples(explainId, explainGraph, triples);
2517
+ case "exploration":
2518
+ return parseExplorationTriples(explainId, explainGraph, triples);
2519
+ case "focus":
2520
+ return parseFocusTriples(explainId, explainGraph, triples);
2213
2521
  }
2214
2522
  }
2215
2523
  // Fall back to URI pattern detection (graph-rag events)
@@ -2230,8 +2538,10 @@ function parseExplainTriples(explainId, explainGraph, triples) {
2230
2538
 
2231
2539
  /**
2232
2540
  * Hook for tracing provenance chains in the knowledge graph
2233
- * Follows prov:wasDerivedFrom relationships from any entity to its source documents
2541
+ * Follows tg:contains to find subgraphs, then prov:wasDerivedFrom
2542
+ * to trace chunk → page → document chains
2234
2543
  */
2544
+ const TG_CONTAINS = client.TG + "contains";
2235
2545
  /**
2236
2546
  * Hook for tracing provenance chains
2237
2547
  */
@@ -2248,8 +2558,7 @@ const useProvenance = (options = {}) => {
2248
2558
  * Check if connected
2249
2559
  */
2250
2560
  const isConnected = react.useCallback(() => {
2251
- return (connectionState?.status === "authenticated" ||
2252
- connectionState?.status === "unauthenticated");
2561
+ return (connectionState?.status === "authenticated");
2253
2562
  }, [connectionState]);
2254
2563
  /**
2255
2564
  * Query for rdfs:label of a URI
@@ -2328,13 +2637,13 @@ const useProvenance = (options = {}) => {
2328
2637
  }
2329
2638
  }, [maxDepth, resolveLabel, queryDerivedFrom]);
2330
2639
  /**
2331
- * Query for statements that reify an edge via tg:reifies
2640
+ * Find subgraphs that contain an edge via tg:contains with a quoted triple
2332
2641
  */
2333
- const queryReifyingStatements = react.useCallback(async (s, p, o) => {
2642
+ const queryContainingSubgraphs = react.useCallback(async (s, p, o) => {
2334
2643
  if (!isConnected())
2335
2644
  return [];
2336
2645
  try {
2337
- // Build the quoted triple term
2646
+ // Build the quoted triple term for the edge
2338
2647
  const quotedTriple = {
2339
2648
  t: "t",
2340
2649
  tr: {
@@ -2347,7 +2656,7 @@ const useProvenance = (options = {}) => {
2347
2656
  };
2348
2657
  const triples = await socket
2349
2658
  .flow(effectiveFlow)
2350
- .triplesQuery(undefined, { t: "i", i: client.TG_REIFIES }, quotedTriple, 10, collection);
2659
+ .triplesQuery(undefined, { t: "i", i: TG_CONTAINS }, quotedTriple, 10, collection);
2351
2660
  return triples.map((t) => getTermValue$1(t.s));
2352
2661
  }
2353
2662
  catch {
@@ -2355,20 +2664,21 @@ const useProvenance = (options = {}) => {
2355
2664
  }
2356
2665
  }, [socket, effectiveFlow, collection, isConnected]);
2357
2666
  /**
2358
- * Trace provenance for an edge - finds reifying statements and traces each
2667
+ * Trace provenance for an edge find containing subgraph, then follow
2668
+ * wasDerivedFrom chain: subgraph → chunk → page → document
2359
2669
  */
2360
2670
  const traceEdgeProvenance = react.useCallback(async (s, p, o) => {
2361
2671
  setIsTracing(true);
2362
2672
  try {
2363
- // Find statements that reify this edge
2364
- const stmtUris = await queryReifyingStatements(s, p, o);
2365
- // For each reifying statement, trace its provenance chain
2673
+ // Find subgraphs containing this edge
2674
+ const subgraphUris = await queryContainingSubgraphs(s, p, o);
2366
2675
  const chains = [];
2367
- for (const stmtUri of stmtUris) {
2368
- // Get the wasDerivedFrom source for this statement
2369
- const sourceUri = await queryDerivedFrom(stmtUri);
2370
- if (sourceUri) {
2371
- const chain = await traceChain(sourceUri);
2676
+ for (const subgraphUri of subgraphUris) {
2677
+ // Follow wasDerivedFrom from the subgraph to the chunk
2678
+ const chunkUri = await queryDerivedFrom(subgraphUri);
2679
+ if (chunkUri) {
2680
+ // Trace the full chain from chunk upward
2681
+ const chain = await traceChain(chunkUri);
2372
2682
  chains.push(chain);
2373
2683
  }
2374
2684
  }
@@ -2377,7 +2687,7 @@ const useProvenance = (options = {}) => {
2377
2687
  finally {
2378
2688
  setIsTracing(false);
2379
2689
  }
2380
- }, [queryReifyingStatements, queryDerivedFrom, traceChain]);
2690
+ }, [queryContainingSubgraphs, queryDerivedFrom, traceChain]);
2381
2691
  /**
2382
2692
  * Clear the label cache
2383
2693
  */
@@ -2434,12 +2744,13 @@ const useExplainability = (options = {}) => {
2434
2744
  const resolveEdge = react.useCallback(async (edgeSelUri, allTriples) => {
2435
2745
  // Filter embedded triples for this edge selection URI
2436
2746
  const edgeTriples = allTriples.filter((t) => getTermValue$1(t.s) === edgeSelUri);
2437
- const { edge, reasoning } = parseEdgeSelectionTriples(edgeTriples);
2747
+ const { edge, concept, score } = parseEdgeSelectionTriples(edgeTriples);
2438
2748
  if (!edge)
2439
2749
  return null;
2440
2750
  const selectedEdge = {
2441
2751
  edge,
2442
- reasoning: reasoning || undefined,
2752
+ concept: concept || undefined,
2753
+ score: score ?? undefined,
2443
2754
  };
2444
2755
  // Kick off label resolution and provenance in parallel
2445
2756
  const [labels, provenanceChains] = await Promise.all([
@@ -2479,56 +2790,82 @@ const useExplainability = (options = {}) => {
2479
2790
  setSession(updater);
2480
2791
  onUpdateRef.current?.(sessionRef.current);
2481
2792
  }, []);
2482
- const AGENT_EVENT_TYPES = new Set([
2793
+ const AGENT_STEP_TYPES = new Set([
2483
2794
  "agent-question", "decomposition", "analysis", "reflection", "conclusion",
2795
+ "grounding",
2484
2796
  ]);
2797
+ /**
2798
+ * Resolve labels for inline edges (edges already extracted, just need labels)
2799
+ */
2800
+ const resolveEdgeLabels = react.useCallback(async (focusEvent) => {
2801
+ if (!focusEvent.selectedEdges || focusEvent.selectedEdges.length === 0) {
2802
+ return focusEvent;
2803
+ }
2804
+ const resolved = await Promise.all(focusEvent.selectedEdges.map(async (se) => {
2805
+ const [sLabel, pLabel, oLabel] = await Promise.all([
2806
+ resolveLabel(se.edge.s),
2807
+ resolveLabel(se.edge.p),
2808
+ resolveLabel(se.edge.o),
2809
+ ]);
2810
+ let sources;
2811
+ if (traceProvenance) {
2812
+ const chains = await traceEdgeProvenance(se.edge.s, se.edge.p, se.edge.o);
2813
+ if (chains.length > 0) {
2814
+ sources = chains.map((c) => c.chain).flat();
2815
+ }
2816
+ }
2817
+ return {
2818
+ ...se,
2819
+ labels: { s: sLabel, p: pLabel, o: oLabel },
2820
+ sources,
2821
+ };
2822
+ }));
2823
+ return { ...focusEvent, selectedEdges: resolved };
2824
+ }, [resolveLabel, traceProvenance, traceEdgeProvenance]);
2485
2825
  /**
2486
2826
  * Process a single explain event
2487
2827
  */
2488
2828
  const processEvent = react.useCallback(async (event) => {
2489
- // Use embedded triples directly from the event
2490
2829
  const triples = event.explainTriples ?? [];
2491
- // Parse into structured data
2492
2830
  const parsed = parseExplainTriples(event.explainId, event.explainGraph, triples);
2493
2831
  if (!parsed)
2494
2832
  return;
2495
- if (AGENT_EVENT_TYPES.has(parsed.type)) {
2496
- // Agent event — append to timeline
2833
+ if (AGENT_STEP_TYPES.has(parsed.type)) {
2834
+ // Agent step — append to timeline
2497
2835
  updateSession((prev) => ({
2498
2836
  ...prev,
2499
2837
  agentSteps: [...(prev.agentSteps || []), parsed],
2500
2838
  }));
2501
2839
  }
2502
- else {
2503
- // Graph-RAG event — populate fixed fields
2504
- updateSession((prev) => {
2505
- const next = { ...prev };
2506
- switch (parsed.type) {
2507
- case "question":
2508
- next.question = parsed;
2509
- break;
2510
- case "exploration":
2511
- next.exploration = parsed;
2512
- break;
2513
- case "focus":
2514
- next.focus = parsed;
2515
- break;
2516
- case "synthesis":
2517
- next.synthesis = parsed;
2518
- break;
2840
+ // Graph-RAG fields — populate regardless (agent produces these too)
2841
+ switch (parsed.type) {
2842
+ case "question":
2843
+ updateSession((prev) => ({ ...prev, question: parsed }));
2844
+ break;
2845
+ case "exploration":
2846
+ updateSession((prev) => ({ ...prev, exploration: parsed }));
2847
+ break;
2848
+ case "focus": {
2849
+ updateSession((prev) => ({ ...prev, focus: parsed }));
2850
+ // Resolve labels for inline edges, or unpack old-format edges
2851
+ const focusEvent = parsed;
2852
+ if (focusEvent.selectedEdges && focusEvent.selectedEdges.length > 0) {
2853
+ // New format: edges already extracted, resolve labels
2854
+ const resolved = await resolveEdgeLabels(focusEvent);
2855
+ updateSession((prev) => ({ ...prev, focus: resolved }));
2519
2856
  }
2520
- return next;
2521
- });
2522
- // For focus events, unpack edges (labels still need store lookup)
2523
- if (parsed.type === "focus") {
2524
- const unpackedFocus = await unpackFocusEvent(parsed, triples);
2525
- updateSession((prev) => ({
2526
- ...prev,
2527
- focus: unpackedFocus,
2528
- }));
2857
+ else if (focusEvent.edgeSelectionUris.length > 0) {
2858
+ // Old format: unpack edge selection URIs
2859
+ const unpacked = await unpackFocusEvent(focusEvent, triples);
2860
+ updateSession((prev) => ({ ...prev, focus: unpacked }));
2861
+ }
2862
+ break;
2529
2863
  }
2864
+ case "synthesis":
2865
+ updateSession((prev) => ({ ...prev, synthesis: parsed }));
2866
+ break;
2530
2867
  }
2531
- }, [unpackFocusEvent, updateSession]);
2868
+ }, [unpackFocusEvent, resolveEdgeLabels, updateSession]);
2532
2869
  /**
2533
2870
  * Process the unpack queue
2534
2871
  */
@@ -2893,8 +3230,7 @@ const useStructuredQuery = () => {
2893
3230
  // Settings for default collection
2894
3231
  const { settings } = useSettings();
2895
3232
  // Only enable operations when socket is connected and ready
2896
- const isSocketReady = connectionState?.status === "authenticated" ||
2897
- connectionState?.status === "unauthenticated";
3233
+ const isSocketReady = connectionState?.status === "authenticated";
2898
3234
  // Mutation for executing structured queries from natural language
2899
3235
  const structuredQueryMutation = reactQuery.useMutation({
2900
3236
  mutationFn: async ({ question, collection, }) => {
@@ -2950,8 +3286,7 @@ const useRowEmbeddingsQuery = ({ flow } = {}) => {
2950
3286
  const sessionFlowId = useSessionStore((state) => state.flowId);
2951
3287
  const { settings } = useSettings();
2952
3288
  const effectiveFlow = flow ?? sessionFlowId;
2953
- const isSocketReady = connectionState?.status === "authenticated" ||
2954
- connectionState?.status === "unauthenticated";
3289
+ const isSocketReady = connectionState?.status === "authenticated";
2955
3290
  const mutation = reactQuery.useMutation({
2956
3291
  mutationFn: async ({ vectors, schemaName, collection, indexName, limit = 10, }) => {
2957
3292
  if (!isSocketReady) {
@@ -2991,8 +3326,7 @@ const useDocumentEmbeddingsQuery = ({ flow } = {}) => {
2991
3326
  const sessionFlowId = useSessionStore((state) => state.flowId);
2992
3327
  const { settings } = useSettings();
2993
3328
  const effectiveFlow = flow ?? sessionFlowId;
2994
- const isSocketReady = connectionState?.status === "authenticated" ||
2995
- connectionState?.status === "unauthenticated";
3329
+ const isSocketReady = connectionState?.status === "authenticated";
2996
3330
  const mutation = reactQuery.useMutation({
2997
3331
  mutationFn: async ({ vectors, user, collection, limit = 10, }) => {
2998
3332
  if (!isSocketReady) {
@@ -3038,8 +3372,7 @@ const useRowsQuery = ({ flow } = {}) => {
3038
3372
  // Settings for default collection
3039
3373
  const { settings } = useSettings();
3040
3374
  // Only enable operations when socket is connected and ready
3041
- const isSocketReady = connectionState?.status === "authenticated" ||
3042
- connectionState?.status === "unauthenticated";
3375
+ const isSocketReady = connectionState?.status === "authenticated";
3043
3376
  // Mutation for executing GraphQL rows queries
3044
3377
  const rowsQueryMutation = reactQuery.useMutation({
3045
3378
  mutationFn: async ({ query, collection, variables, operationName, }) => {
@@ -3088,8 +3421,7 @@ const useEmbeddings = ({ flow, term }) => {
3088
3421
  const socket = reactProvider.useSocket();
3089
3422
  const connectionState = reactProvider.useConnectionState();
3090
3423
  // Only enable queries when socket is connected and ready
3091
- const isSocketReady = connectionState?.status === "authenticated" ||
3092
- connectionState?.status === "unauthenticated";
3424
+ const isSocketReady = connectionState?.status === "authenticated";
3093
3425
  // Hook for displaying user notifications
3094
3426
  const notify = useNotification();
3095
3427
  // Session state for default flow ID
@@ -3147,8 +3479,7 @@ const useCollections = () => {
3147
3479
  // Hook for displaying user notifications
3148
3480
  const notify = useNotification();
3149
3481
  // Only enable queries when socket is connected and ready
3150
- const isSocketReady = connectionState?.status === "authenticated" ||
3151
- connectionState?.status === "unauthenticated";
3482
+ const isSocketReady = connectionState?.status === "authenticated";
3152
3483
  /**
3153
3484
  * Query for fetching all collections from the collection management service
3154
3485
  * Uses React Query for caching and background refetching
@@ -3252,8 +3583,7 @@ const useNlpQuery = ({ flow } = {}) => {
3252
3583
  // Use explicit param if provided, otherwise fall back to session state
3253
3584
  const effectiveFlow = flow ?? sessionFlowId;
3254
3585
  // Only enable operations when socket is connected and ready
3255
- const isSocketReady = connectionState?.status === "authenticated" ||
3256
- connectionState?.status === "unauthenticated";
3586
+ const isSocketReady = connectionState?.status === "authenticated";
3257
3587
  // Mutation for converting natural language to GraphQL
3258
3588
  const nlpQueryMutation = reactQuery.useMutation({
3259
3589
  mutationFn: async ({ question, maxResults, }) => {
@@ -3303,8 +3633,7 @@ const useProcessing = () => {
3303
3633
  const socket = reactProvider.useSocket();
3304
3634
  const connectionState = reactProvider.useConnectionState();
3305
3635
  // Only enable queries when socket is connected and ready
3306
- const isSocketReady = connectionState?.status === "authenticated" ||
3307
- connectionState?.status === "unauthenticated";
3636
+ const isSocketReady = connectionState?.status === "authenticated";
3308
3637
  /**
3309
3638
  * Query for fetching all processing
3310
3639
  * Uses React Query for caching and background refetching
@@ -3347,8 +3676,7 @@ const useAgentTools = () => {
3347
3676
  // Notification system for user feedback
3348
3677
  const notify = useNotification();
3349
3678
  // Only enable queries when socket is connected and ready
3350
- const isSocketReady = connectionState?.status === "authenticated" ||
3351
- connectionState?.status === "unauthenticated";
3679
+ const isSocketReady = connectionState?.status === "authenticated";
3352
3680
  // Query to fetch all agent tools
3353
3681
  // Gets all tools directly from the 'tool' configuration type
3354
3682
  const toolsQuery = reactQuery.useQuery({
@@ -3510,8 +3838,7 @@ const useMcpTools = () => {
3510
3838
  // Notification system for user feedback
3511
3839
  const notify = useNotification();
3512
3840
  // Only enable queries when socket is connected and ready
3513
- const isSocketReady = connectionState?.status === "authenticated" ||
3514
- connectionState?.status === "unauthenticated";
3841
+ const isSocketReady = connectionState?.status === "authenticated";
3515
3842
  // Query to fetch all MCP tools
3516
3843
  // Uses the list operation to get all MCP tools directly
3517
3844
  const toolsQuery = reactQuery.useQuery({
@@ -3670,8 +3997,7 @@ const usePrompts = () => {
3670
3997
  // Notification system for user feedback
3671
3998
  const notify = useNotification();
3672
3999
  // Only enable queries when socket is connected and ready
3673
- const isSocketReady = connectionState?.status === "authenticated" ||
3674
- connectionState?.status === "unauthenticated";
4000
+ const isSocketReady = connectionState?.status === "authenticated";
3675
4001
  // Query to fetch the system prompt configuration
3676
4002
  // System prompt defines the AI assistant's behavior and instructions
3677
4003
  const systemPromptQuery = reactQuery.useQuery({
@@ -3691,22 +4017,21 @@ const usePrompts = () => {
3691
4017
  },
3692
4018
  });
3693
4019
  // Query to fetch all prompt templates
3694
- // First gets the template index (list of template IDs), then fetches each template's configuration
4020
+ // Lists prompt config keys, filters for template.* prefix, then fetches each template's configuration
3695
4021
  const promptsQuery = reactQuery.useQuery({
3696
4022
  queryKey: ["prompts"],
3697
4023
  enabled: isSocketReady,
3698
4024
  queryFn: () => {
3699
- // Step 1: Get the template index (array of template IDs)
3700
4025
  return socket
3701
4026
  .config()
3702
- .getConfig([{ type: "prompt", key: "template-index" }])
4027
+ .list("prompt")
3703
4028
  .then((res) => {
3704
- if (res["error"]) {
3705
- console.log("Error:", res);
3706
- throw res.error.message;
3707
- }
3708
- const promptIds = JSON.parse(res.values[0].value);
3709
- // Step 2: Fetch configuration for each template using their IDs
4029
+ const keys = res?.directory || [];
4030
+ const promptIds = keys
4031
+ .filter((k) => k.startsWith("template."))
4032
+ .map((k) => k.slice("template.".length));
4033
+ if (promptIds.length === 0)
4034
+ return [];
3710
4035
  return socket
3711
4036
  .config()
3712
4037
  .getConfig(promptIds.map((id) => ({
@@ -3718,7 +4043,6 @@ const usePrompts = () => {
3718
4043
  console.log("Error:", r);
3719
4044
  throw r.error.message;
3720
4045
  }
3721
- // Parse template configurations and pair them with their IDs
3722
4046
  const config = r.values.map((c) => JSON.parse(c.value));
3723
4047
  return promptIds.map((id, ix) => [id, config[ix]]);
3724
4048
  });
@@ -3791,41 +4115,24 @@ const usePrompts = () => {
3791
4115
  },
3792
4116
  });
3793
4117
  // Mutation for creating a new prompt template
3794
- // Updates both the template index and creates the template configuration
3795
4118
  const createPromptMutation = reactQuery.useMutation({
3796
4119
  mutationFn: ({ id, prompt, onSuccess }) => {
3797
- // Step 1: Get current template index
3798
4120
  return socket
3799
4121
  .config()
3800
- .getConfig([{ type: "prompt", key: "template-index" }])
3801
- .then((res) => JSON.parse(res.values[0].value))
3802
- .then((existingIds) => {
3803
- // Step 2: Add new template ID to the index
3804
- const newIds = [...existingIds, id];
3805
- // Step 3: Update both the template index and create the new template configuration
3806
- return socket
3807
- .config()
3808
- .putConfig([
3809
- {
3810
- type: "prompt",
3811
- key: "template-index",
3812
- value: JSON.stringify(newIds),
3813
- },
3814
- {
3815
- type: "prompt",
3816
- key: "template." + id,
3817
- value: JSON.stringify(prompt),
3818
- },
3819
- ])
3820
- .then((x) => {
3821
- if (x["error"]) {
3822
- console.log("Error:", x);
3823
- throw x.error.message;
3824
- }
3825
- // Execute callback if provided
3826
- if (onSuccess)
3827
- onSuccess();
3828
- });
4122
+ .putConfig([
4123
+ {
4124
+ type: "prompt",
4125
+ key: "template." + id,
4126
+ value: JSON.stringify(prompt),
4127
+ },
4128
+ ])
4129
+ .then((x) => {
4130
+ if (x["error"]) {
4131
+ console.log("Error:", x);
4132
+ throw x.error.message;
4133
+ }
4134
+ if (onSuccess)
4135
+ onSuccess();
3829
4136
  });
3830
4137
  },
3831
4138
  onError: (err) => {
@@ -3839,45 +4146,21 @@ const usePrompts = () => {
3839
4146
  },
3840
4147
  });
3841
4148
  // Mutation for deleting a prompt template
3842
- // Removes the template from both the index and deletes its configuration
3843
4149
  const deletePromptMutation = reactQuery.useMutation({
3844
4150
  mutationFn: ({ id, onSuccess }) => {
3845
- // Step 1: Get current template index
3846
4151
  return socket
3847
4152
  .config()
3848
- .getConfig([{ type: "prompt", key: "template-index" }])
3849
- .then((res) => JSON.parse(res.values[0].value))
3850
- .then((existingIds) => {
3851
- // Step 2: Remove the template ID from the index
3852
- const newIds = existingIds.filter((existingId) => existingId !== id);
3853
- // Step 3: Update the template index
3854
- return socket
3855
- .config()
3856
- .putConfig([
3857
- {
3858
- type: "prompt",
3859
- key: "template-index",
3860
- value: JSON.stringify(newIds),
3861
- },
3862
- ])
3863
- .then(() => {
3864
- // Step 4: Delete the template configuration
3865
- return socket.config().deleteConfig([
3866
- {
3867
- type: "prompt",
3868
- key: "template." + id,
3869
- },
3870
- ]);
3871
- })
3872
- .then((x) => {
3873
- if (x["error"]) {
3874
- console.log("Error:", x);
3875
- throw x.error.message;
3876
- }
3877
- // Execute callback if provided
3878
- if (onSuccess)
3879
- onSuccess();
3880
- });
4153
+ .deleteConfig({
4154
+ type: "prompt",
4155
+ key: "template." + id,
4156
+ })
4157
+ .then((x) => {
4158
+ if (x["error"]) {
4159
+ console.log("Error:", x);
4160
+ throw x.error.message;
4161
+ }
4162
+ if (onSuccess)
4163
+ onSuccess();
3881
4164
  });
3882
4165
  },
3883
4166
  onError: (err) => {
@@ -3932,8 +4215,7 @@ const useSchemas = () => {
3932
4215
  const queryClient = reactQuery.useQueryClient();
3933
4216
  const notify = useNotification();
3934
4217
  // Only enable queries when socket is connected and ready
3935
- const isSocketReady = connectionState?.status === "authenticated" ||
3936
- connectionState?.status === "unauthenticated";
4218
+ const isSocketReady = connectionState?.status === "authenticated";
3937
4219
  const schemasQuery = reactQuery.useQuery({
3938
4220
  queryKey: ["schemas"],
3939
4221
  enabled: isSocketReady,
@@ -4063,8 +4345,7 @@ const useOntologies = () => {
4063
4345
  const queryClient = reactQuery.useQueryClient();
4064
4346
  const notify = useNotification();
4065
4347
  // Only enable queries when socket is connected and ready
4066
- const isSocketReady = connectionState?.status === "authenticated" ||
4067
- connectionState?.status === "unauthenticated";
4348
+ const isSocketReady = connectionState?.status === "authenticated";
4068
4349
  const ontologiesQuery = reactQuery.useQuery({
4069
4350
  queryKey: ["ontologies"],
4070
4351
  enabled: isSocketReady,
@@ -4202,8 +4483,7 @@ const useKnowledgeCores = () => {
4202
4483
  // Hook for displaying user notifications
4203
4484
  const notify = useNotification();
4204
4485
  // Only enable queries when socket is connected and ready
4205
- const isSocketReady = connectionState?.status === "authenticated" ||
4206
- connectionState?.status === "unauthenticated";
4486
+ const isSocketReady = connectionState?.status === "authenticated";
4207
4487
  /**
4208
4488
  * Query for fetching all knowledge cores
4209
4489
  * Uses React Query for caching and background refetching
@@ -4305,8 +4585,7 @@ const useTokenCosts = () => {
4305
4585
  // Hook for displaying user notifications
4306
4586
  const notify = useNotification();
4307
4587
  // Only enable queries when socket is connected and ready
4308
- const isSocketReady = connectionState?.status === "authenticated" ||
4309
- connectionState?.status === "unauthenticated";
4588
+ const isSocketReady = connectionState?.status === "authenticated";
4310
4589
  /**
4311
4590
  * Query for fetching all token costs
4312
4591
  * Uses React Query for caching and background refetching
@@ -4437,8 +4716,7 @@ const useLLMModels = () => {
4437
4716
  const connectionState = reactProvider.useConnectionState();
4438
4717
  const queryClient = reactQuery.useQueryClient();
4439
4718
  const notify = useNotification();
4440
- const isSocketReady = connectionState?.status === "authenticated" ||
4441
- connectionState?.status === "unauthenticated";
4719
+ const isSocketReady = connectionState?.status === "authenticated";
4442
4720
  // Fetch the llm-model parameter type
4443
4721
  const paramTypesQuery = reactQuery.useQuery({
4444
4722
  queryKey: ["llm-models"],
@@ -4524,8 +4802,7 @@ const useFlowBlueprints = () => {
4524
4802
  // Hook for displaying user notifications
4525
4803
  const notify = useNotification();
4526
4804
  // Only enable queries when socket is connected and ready
4527
- const isSocketReady = connectionState?.status === "authenticated" ||
4528
- connectionState?.status === "unauthenticated";
4805
+ const isSocketReady = connectionState?.status === "authenticated";
4529
4806
  /**
4530
4807
  * Query for fetching all flow blueprintes
4531
4808
  * Uses React Query for caching and background refetching
@@ -4798,8 +5075,7 @@ const generateFlowBlueprintId = (baseName = "flow-class") => {
4798
5075
  const useFlowParameters = (flowBlueprintName) => {
4799
5076
  const socket = reactProvider.useSocket();
4800
5077
  const connectionState = reactProvider.useConnectionState();
4801
- const isSocketReady = connectionState?.status === "authenticated" ||
4802
- connectionState?.status === "unauthenticated";
5078
+ const isSocketReady = connectionState?.status === "authenticated";
4803
5079
  /**
4804
5080
  * Query for fetching parameter definitions for a flow blueprint
4805
5081
  */
@@ -5428,8 +5704,9 @@ const useNodeDetails = (nodeId, flowId) => {
5428
5704
  };
5429
5705
  };
5430
5706
 
5431
- // Default chunk size: 5MB (matches backend default)
5432
- const DEFAULT_CHUNK_SIZE$1 = 5 * 1024 * 1024;
5707
+ // Default chunk size: 2MB (base64 + JSON encoding inflates ~4x on the wire,
5708
+ // Pulsar message limit is around 3MB raw)
5709
+ const DEFAULT_CHUNK_SIZE$1 = 2 * 1024 * 1024;
5433
5710
  // Maximum parallel chunk uploads
5434
5711
  const DEFAULT_PARALLEL_UPLOADS = 3;
5435
5712
  /**
@@ -5546,8 +5823,7 @@ const useChunkedUpload = (options = {}) => {
5546
5823
  const upload = react.useCallback(async (params) => {
5547
5824
  const { file, title, comments = "", tags = [], collection, documentId } = params;
5548
5825
  // Validate connection
5549
- if (connectionState?.status !== "authenticated" &&
5550
- connectionState?.status !== "unauthenticated") {
5826
+ if (connectionState?.status !== "authenticated") {
5551
5827
  const error = "Not connected to server";
5552
5828
  updateProgress({ status: "error", error });
5553
5829
  onError?.(error);
@@ -5638,8 +5914,7 @@ const useChunkedUpload = (options = {}) => {
5638
5914
  const resume = react.useCallback(async (params) => {
5639
5915
  const { uploadId, file } = params;
5640
5916
  // Validate connection
5641
- if (connectionState?.status !== "authenticated" &&
5642
- connectionState?.status !== "unauthenticated") {
5917
+ if (connectionState?.status !== "authenticated") {
5643
5918
  const error = "Not connected to server";
5644
5919
  updateProgress({ status: "error", error });
5645
5920
  onError?.(error);
@@ -5858,8 +6133,7 @@ const useChunkedDownload = (options = {}) => {
5858
6133
  const download = react.useCallback((params) => {
5859
6134
  const { documentId, mimeType = "application/octet-stream", filename } = params;
5860
6135
  // Validate connection
5861
- if (connectionState?.status !== "authenticated" &&
5862
- connectionState?.status !== "unauthenticated") {
6136
+ if (connectionState?.status !== "authenticated") {
5863
6137
  const error = "Not connected to server";
5864
6138
  updateProgress({ status: "error", error });
5865
6139
  onError?.(error);
@@ -5984,8 +6258,7 @@ const useDocumentMetadata = (options = {}) => {
5984
6258
  const { documentId, enabled } = options;
5985
6259
  const socket = reactProvider.useSocket();
5986
6260
  const connectionState = reactProvider.useConnectionState();
5987
- const isSocketReady = connectionState?.status === "authenticated" ||
5988
- connectionState?.status === "unauthenticated";
6261
+ const isSocketReady = connectionState?.status === "authenticated";
5989
6262
  const query = reactQuery.useQuery({
5990
6263
  queryKey: ["document-metadata", documentId],
5991
6264
  enabled: isSocketReady && !!documentId && (enabled !== false),
@@ -6010,8 +6283,7 @@ const useDocumentsMetadata = (documentIds = []) => {
6010
6283
  const socket = reactProvider.useSocket();
6011
6284
  const connectionState = reactProvider.useConnectionState();
6012
6285
  const queryClient = reactQuery.useQueryClient();
6013
- const isSocketReady = connectionState?.status === "authenticated" ||
6014
- connectionState?.status === "unauthenticated";
6286
+ const isSocketReady = connectionState?.status === "authenticated";
6015
6287
  const query = reactQuery.useQuery({
6016
6288
  queryKey: ["documents-metadata", documentIds],
6017
6289
  enabled: isSocketReady && documentIds.length > 0,
@@ -6125,6 +6397,10 @@ Object.defineProperty(exports, "TG", {
6125
6397
  enumerable: true,
6126
6398
  get: function () { return client.TG; }
6127
6399
  });
6400
+ Object.defineProperty(exports, "TG_CONCEPT", {
6401
+ enumerable: true,
6402
+ get: function () { return client.TG_CONCEPT; }
6403
+ });
6128
6404
  Object.defineProperty(exports, "TG_CONTENT", {
6129
6405
  enumerable: true,
6130
6406
  get: function () { return client.TG_CONTENT; }
@@ -6145,14 +6421,14 @@ Object.defineProperty(exports, "TG_QUERY", {
6145
6421
  enumerable: true,
6146
6422
  get: function () { return client.TG_QUERY; }
6147
6423
  });
6148
- Object.defineProperty(exports, "TG_REASONING", {
6149
- enumerable: true,
6150
- get: function () { return client.TG_REASONING; }
6151
- });
6152
6424
  Object.defineProperty(exports, "TG_REIFIES", {
6153
6425
  enumerable: true,
6154
6426
  get: function () { return client.TG_REIFIES; }
6155
6427
  });
6428
+ Object.defineProperty(exports, "TG_SCORE", {
6429
+ enumerable: true,
6430
+ get: function () { return client.TG_SCORE; }
6431
+ });
6156
6432
  Object.defineProperty(exports, "TG_SELECTED_EDGE", {
6157
6433
  enumerable: true,
6158
6434
  get: function () { return client.TG_SELECTED_EDGE; }
@@ -6161,6 +6437,7 @@ exports.DEFAULT_SETTINGS = DEFAULT_SETTINGS;
6161
6437
  exports.NotificationProvider = NotificationProvider;
6162
6438
  exports.RDFS_LABEL = RDFS_LABEL;
6163
6439
  exports.SETTINGS_STORAGE_KEY = SETTINGS_STORAGE_KEY;
6440
+ exports.configureAuthApi = configureAuthApi;
6164
6441
  exports.createDocId = createDocId;
6165
6442
  exports.extractQuotedTriple = extractQuotedTriple;
6166
6443
  exports.fileToBase64 = fileToBase64;
@@ -6180,6 +6457,9 @@ exports.prepareMetadata = prepareMetadata;
6180
6457
  exports.textToBase64 = textToBase64;
6181
6458
  exports.useActivity = useActivity;
6182
6459
  exports.useAgentTools = useAgentTools;
6460
+ exports.useAuth = useAuth;
6461
+ exports.useAuthStore = useAuthStore;
6462
+ exports.useBootstrapStatus = useBootstrapStatus;
6183
6463
  exports.useChat = useChat;
6184
6464
  exports.useChatSession = useChatSession;
6185
6465
  exports.useChunkedDownload = useChunkedDownload;
@@ -6203,6 +6483,8 @@ exports.useKnowledgeCores = useKnowledgeCores;
6203
6483
  exports.useLLMModels = useLLMModels;
6204
6484
  exports.useLibrary = useLibrary;
6205
6485
  exports.useLoadStateStore = useLoadStateStore;
6486
+ exports.useLogin = useLogin;
6487
+ exports.useLogout = useLogout;
6206
6488
  exports.useMcpTools = useMcpTools;
6207
6489
  exports.useNlpQuery = useNlpQuery;
6208
6490
  exports.useNodeDetails = useNodeDetails;
@@ -6223,6 +6505,11 @@ exports.useStructuredQuery = useStructuredQuery;
6223
6505
  exports.useTokenCosts = useTokenCosts;
6224
6506
  exports.useTriples = useTriples;
6225
6507
  exports.useVectorSearch = useVectorSearch;
6508
+ exports.useWhoami = useWhoami;
6226
6509
  exports.useWorkbenchStateStore = useWorkbenchStateStore;
6510
+ exports.useWorkspace = useWorkspace;
6511
+ exports.useWorkspaceStore = useWorkspaceStore;
6512
+ exports.useWorkspaceSync = useWorkspaceSync;
6513
+ exports.useWorkspaces = useWorkspaces;
6227
6514
  exports.vectorSearch = vectorSearch;
6228
6515
  //# sourceMappingURL=index.cjs.map