@trustgraph/react-state 0.2.0 → 0.3.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 CHANGED
@@ -17,150 +17,6 @@ React state management hooks for TrustGraph applications. Provides TanStack Quer
17
17
  npm install @trustgraph/react-state @trustgraph/react-provider @trustgraph/client
18
18
  ```
19
19
 
20
- ## Building from Scratch
21
-
22
- New to TrustGraph? Here's how to build your first app from a blank slate.
23
-
24
- ### 1. Create a new React + TypeScript project
25
-
26
- ```bash
27
- # Create a new Vite project with React + TypeScript
28
- npm create vite@latest my-trustgraph-app -- --template react-ts
29
- cd my-trustgraph-app
30
- ```
31
-
32
- ### 2. Install TrustGraph dependencies
33
-
34
- ```bash
35
- # Vite scaffolds with React 19, but TrustGraph currently uses React 18
36
- npm install react@^18.0.0 react-dom@^18.0.0
37
-
38
- # Install TrustGraph packages
39
- npm install @trustgraph/react-state @trustgraph/react-provider @trustgraph/client
40
-
41
- # Install required peer dependencies
42
- npm install @tanstack/react-query zustand
43
-
44
- # Install a toast/notification library (optional, we'll use console for this example)
45
- ```
46
-
47
- ### 3. Configure WebSocket proxy
48
-
49
- The TrustGraph client connects to `ws://HOSTNAME:PORT/api/socket` in your application's address space. You need to proxy this to the TrustGraph API gateway (typically port 8088, path `/api/v1/socket`).
50
-
51
- For Vite, create or update `vite.config.ts`:
52
-
53
- ```typescript
54
- import { defineConfig } from "vite";
55
- import react from "@vitejs/plugin-react";
56
-
57
- export default defineConfig({
58
- plugins: [react()],
59
- server: {
60
- proxy: {
61
- "/api/socket": {
62
- target: "ws://localhost:8088",
63
- ws: true,
64
- rewrite: (path) => path.replace(/^\/api\/socket/, "/api/v1/socket"),
65
- },
66
- },
67
- },
68
- });
69
- ```
70
-
71
- **For production deployments**, configure your web server (nginx, Apache, etc.) to proxy `/api/socket` to your TrustGraph API gateway:
72
-
73
- ```nginx
74
- # nginx example
75
- location /api/socket {
76
- proxy_pass http://trustgraph-api:8088/api/v1/socket;
77
- proxy_http_version 1.1;
78
- proxy_set_header Upgrade $http_upgrade;
79
- proxy_set_header Connection "upgrade";
80
- }
81
- ```
82
-
83
- ### 4. Set up the provider wrapper
84
-
85
- Create or update `src/App.tsx`:
86
-
87
- ```typescript
88
- import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
89
- import { SocketProvider } from "@trustgraph/react-provider";
90
- import { NotificationProvider, NotificationHandler } from "@trustgraph/react-state";
91
- import MyFirstComponent from "./MyFirstComponent";
92
-
93
- // Simple console-based notification handler for development
94
- const notificationHandler: NotificationHandler = {
95
- success: (msg) => console.log("✓", msg),
96
- error: (msg) => console.error("✗", msg),
97
- warning: (msg) => console.warn("⚠", msg),
98
- info: (msg) => console.info("ℹ", msg),
99
- };
100
-
101
- const queryClient = new QueryClient();
102
-
103
- function App() {
104
- return (
105
- <QueryClientProvider client={queryClient}>
106
- <NotificationProvider handler={notificationHandler}>
107
- <SocketProvider user="my-user" apiKey="">
108
- <MyFirstComponent />
109
- </SocketProvider>
110
- </NotificationProvider>
111
- </QueryClientProvider>
112
- );
113
- }
114
-
115
- export default App;
116
- ```
117
-
118
- ### 5. Create your first component
119
-
120
- Create `src/MyFirstComponent.tsx`:
121
-
122
- ```typescript
123
- import { useFlows, useSettings } from "@trustgraph/react-state";
124
-
125
- function MyFirstComponent() {
126
- const { flows, isLoading } = useFlows();
127
- const { settings } = useSettings();
128
-
129
- if (isLoading) return <div>Loading flows...</div>;
130
-
131
- return (
132
- <div>
133
- <h1>My TrustGraph App</h1>
134
- <p>User: {settings.user}</p>
135
- <p>Collection: {settings.collection}</p>
136
- <h2>Available Flows:</h2>
137
- <ul>
138
- {flows?.map((flow) => (
139
- <li key={flow.id}>{flow.id}</li>
140
- ))}
141
- </ul>
142
- </div>
143
- );
144
- }
145
-
146
- export default MyFirstComponent;
147
- ```
148
-
149
- ### 6. Run your app
150
-
151
- ```bash
152
- npm run dev
153
- ```
154
-
155
- Open http://localhost:5173 and you should see your flows!
156
-
157
- ### 7. Next Steps
158
-
159
- - Add a chat interface with `useConversation` and `useChatSession`
160
- - Query knowledge graphs with `useEntityDetail` and `useGraphSubgraph`
161
- - Upload documents with `useLibrary`
162
- - Perform vector searches with `useVectorSearch`
163
-
164
20
  ## Quick Start
165
21
 
166
22
  ### 1. Set up providers
@@ -295,11 +151,10 @@ const handler: NotificationHandler = {
295
151
  - `useCollections()` - Manage document collections
296
152
  - `useKnowledgeCores()` - Manage knowledge cores
297
153
 
298
- #### Chat & Inference
154
+ #### Query & Chat
299
155
 
300
- - `useConversation()` - Chat conversation state (messages, input, mode)
301
- - `useInference()`- Low-level LLM inference (graphRag, textCompletion, agent)
302
- - `useChatSession()` / `useChat()` - High-level chat session management
156
+ - `useChat()` - Chat interface operations
157
+ - `useChatQuery()` - Chat query management
303
158
  - `useStructuredQuery()` - Structured query operations
304
159
  - `useObjectsQuery()` - Object queries
305
160
  - `useNlpQuery()` - Natural language processing queries
@@ -326,10 +181,9 @@ const handler: NotificationHandler = {
326
181
 
327
182
  - `useProgressStateStore()` - Activity indicators and error state
328
183
  - `useSessionStore()` - Session and flow state
329
- - `useConversation()` - Chat conversation state (messages, input, chat mode)
184
+ - `useChatStateStore()` - Chat message history
330
185
  - `useWorkbenchStateStore()` - Workbench UI state (selected entity, tool, etc.)
331
186
  - `useLoadStateStore()` - Document loading state
332
- - `useSearchStateStore()` - Search results state
333
187
 
334
188
  ### Utility Hooks
335
189
 
@@ -341,10 +195,9 @@ const handler: NotificationHandler = {
341
195
  ### Managing Documents
342
196
 
343
197
  ```typescript
344
- import { useLibrary, useSettings } from "@trustgraph/react-state";
198
+ import { useLibrary } from "@trustgraph/react-state";
345
199
 
346
200
  function DocumentManager() {
347
- const { settings } = useSettings();
348
201
  const {
349
202
  documents,
350
203
  isLoading,
@@ -365,17 +218,7 @@ function DocumentManager() {
365
218
  files,
366
219
  params: { title: "My Document", keywords: [] },
367
220
  mimeType: "application/pdf",
368
- onSuccess: () => console.log("Uploaded successfully"),
369
- });
370
- };
371
-
372
- const handleSubmit = (ids: string[]) => {
373
- submitDocuments({
374
- ids,
375
- flow: "my-flow",
376
- tags: ["important"],
377
- collection: settings.collection,
378
- onSuccess: () => console.log("Submitted for processing"),
221
+ user: "current-user",
379
222
  });
380
223
  };
381
224
 
@@ -417,95 +260,6 @@ function SettingsPanel() {
417
260
  }
418
261
  ```
419
262
 
420
- ### Chat Interface (3-Hook Architecture)
421
-
422
- The chat system is split into three composable hooks:
423
-
424
- ```typescript
425
- import { useConversation, useInference, useChatSession, useSettings } from "@trustgraph/react-state";
426
-
427
- // Option 1: High-level chat (easiest)
428
- function SimpleChatUI() {
429
- const messages = useConversation((state) => state.messages);
430
- const input = useConversation((state) => state.input);
431
- const setInput = useConversation((state) => state.setInput);
432
- const { submitMessage, isSubmitting } = useChatSession();
433
-
434
- return (
435
- <div>
436
- {messages.map((msg, i) => (
437
- <div key={i}>{msg.role}: {msg.text}</div>
438
- ))}
439
- <input value={input} onChange={(e) => setInput(e.target.value)} />
440
- <button onClick={() => submitMessage({ input })} disabled={isSubmitting}>
441
- Send
442
- </button>
443
- </div>
444
- );
445
- }
446
-
447
- // Option 2: Low-level inference (for custom UIs)
448
- function CustomInferenceUI() {
449
- const { settings } = useSettings();
450
- const inference = useInference();
451
- const [result, setResult] = useState("");
452
-
453
- const handleQuery = async () => {
454
- const response = await inference.graphRag({
455
- input: "What is TrustGraph?",
456
- options: {
457
- entityLimit: 10,
458
- tripleLimit: 10,
459
- },
460
- collection: settings.collection,
461
- });
462
- setResult(response.response);
463
- };
464
-
465
- return (
466
- <div>
467
- <button onClick={handleQuery}>Query</button>
468
- <div>{result}</div>
469
- </div>
470
- );
471
- }
472
- ```
473
-
474
- ### Multi-Collection Apps
475
-
476
- Query multiple collections side-by-side:
477
-
478
- ```typescript
479
- import { useEntityDetail, useSessionStore, useSettings } from "@trustgraph/react-state";
480
-
481
- function MultiCollectionView({ entityUri }: { entityUri: string }) {
482
- const flowId = useSessionStore((state) => state.flowId);
483
- const { settings } = useSettings();
484
-
485
- // Query same entity from different collections
486
- const prodData = useEntityDetail(entityUri, flowId, "production");
487
- const stagingData = useEntityDetail(entityUri, flowId, "staging");
488
- const defaultData = useEntityDetail(entityUri, flowId, settings.collection);
489
-
490
- return (
491
- <div>
492
- <div>
493
- <h3>Production</h3>
494
- {prodData.detail?.triples.length} triples
495
- </div>
496
- <div>
497
- <h3>Staging</h3>
498
- {stagingData.detail?.triples.length} triples
499
- </div>
500
- <div>
501
- <h3>Default ({settings.collection})</h3>
502
- {defaultData.detail?.triples.length} triples
503
- </div>
504
- </div>
505
- );
506
- }
507
- ```
508
-
509
263
  ### Using Progress Indicators
510
264
 
511
265
  ```typescript
@@ -530,126 +284,6 @@ function MyComponent() {
530
284
  }
531
285
  ```
532
286
 
533
- ## Common Patterns
534
-
535
- ### Handling Settings Loading State
536
-
537
- Settings are loaded asynchronously. Always check `isLoaded` before accessing settings values:
538
-
539
- ```typescript
540
- import { useSettings, useEntityDetail } from "@trustgraph/react-state";
541
-
542
- function EntityView({ entityUri }: { entityUri: string }) {
543
- const { settings, isLoaded } = useSettings();
544
- const flowId = useSessionStore((state) => state.flowId);
545
-
546
- // Wait for settings to load before querying
547
- const { detail } = useEntityDetail(
548
- entityUri,
549
- flowId,
550
- settings?.collection || "default"
551
- );
552
-
553
- if (!isLoaded) {
554
- return <div>Loading settings...</div>;
555
- }
556
-
557
- return <div>{detail?.triples.length} triples</div>;
558
- }
559
- ```
560
-
561
- ### Using Default Collection from Settings
562
-
563
- Most hooks require an explicit `collection` parameter. Use settings as the default source:
564
-
565
- ```typescript
566
- import { useSettings, useLibrary } from "@trustgraph/react-state";
567
-
568
- function DocumentSubmit() {
569
- const { settings } = useSettings();
570
- const library = useLibrary();
571
-
572
- const handleSubmit = (ids: string[], flow: string) => {
573
- library.submitDocuments({
574
- ids,
575
- flow,
576
- tags: ["important"],
577
- collection: settings?.collection || "default", // Use settings with fallback
578
- onSuccess: () => console.log("Submitted"),
579
- });
580
- };
581
-
582
- return <button onClick={() => handleSubmit(["doc1"], "flow1")}>Submit</button>;
583
- }
584
- ```
585
-
586
- ### Querying Multiple Collections
587
-
588
- Override the default collection to query multiple collections side-by-side:
589
-
590
- ```typescript
591
- import { useEntityDetail, useSettings } from "@trustgraph/react-state";
592
-
593
- function MultiCollectionComparison({ entityUri }: { entityUri: string }) {
594
- const { settings } = useSettings();
595
- const flowId = useSessionStore((state) => state.flowId);
596
-
597
- // Query same entity from different collections
598
- const prod = useEntityDetail(entityUri, flowId, "production");
599
- const staging = useEntityDetail(entityUri, flowId, "staging");
600
- const defaultData = useEntityDetail(entityUri, flowId, settings?.collection || "default");
601
-
602
- return (
603
- <div>
604
- <h3>Production: {prod.detail?.triples.length} triples</h3>
605
- <h3>Staging: {staging.detail?.triples.length} triples</h3>
606
- <h3>Default: {defaultData.detail?.triples.length} triples</h3>
607
- </div>
608
- );
609
- }
610
- ```
611
-
612
- ### Composing Inference and Conversation Hooks
613
-
614
- For custom chat UIs, compose the low-level hooks directly:
615
-
616
- ```typescript
617
- import { useConversation, useInference, useSettings } from "@trustgraph/react-state";
618
-
619
- function CustomChatUI() {
620
- const messages = useConversation((state) => state.messages);
621
- const input = useConversation((state) => state.input);
622
- const setInput = useConversation((state) => state.setInput);
623
- const addMessage = useConversation((state) => state.addMessage);
624
-
625
- const { settings } = useSettings();
626
- const inference = useInference();
627
-
628
- const handleSubmit = async () => {
629
- addMessage("user", input);
630
- setInput("");
631
-
632
- const result = await inference.graphRag({
633
- input,
634
- options: { entityLimit: 10, tripleLimit: 10 },
635
- collection: settings?.collection || "default",
636
- });
637
-
638
- addMessage("ai", result.response);
639
- };
640
-
641
- return (
642
- <div>
643
- {messages.map((msg, i) => (
644
- <div key={i}>{msg.role}: {msg.text}</div>
645
- ))}
646
- <input value={input} onChange={(e) => setInput(e.target.value)} />
647
- <button onClick={handleSubmit}>Send</button>
648
- </div>
649
- );
650
- }
651
- ```
652
-
653
287
  ## Type Exports
654
288
 
655
289
  The package re-exports types from `@trustgraph/client` for convenience:
package/dist/index.cjs CHANGED
@@ -2667,7 +2667,7 @@ const useGraphSubgraph = (entityUri, flowId, collection) => {
2667
2667
  },
2668
2668
  onSuccess: (newGraph) => {
2669
2669
  // Update the cache with the new graph data
2670
- queryClient.setQueryData(["graph-subgraph", { entityUri, flowId }], newGraph);
2670
+ queryClient.setQueryData(["graph-subgraph", { entityUri, flowId, collection }], newGraph);
2671
2671
  },
2672
2672
  onError: (err) => {
2673
2673
  console.log("Graph update error:", err);
@@ -2684,7 +2684,7 @@ const useGraphSubgraph = (entityUri, flowId, collection) => {
2684
2684
  },
2685
2685
  onSuccess: (newGraph) => {
2686
2686
  // Update the cache with the new graph data
2687
- queryClient.setQueryData(["graph-subgraph", { entityUri, flowId }], newGraph);
2687
+ queryClient.setQueryData(["graph-subgraph", { entityUri, flowId, collection }], newGraph);
2688
2688
  },
2689
2689
  onError: (err) => {
2690
2690
  console.log("Relationship navigation error:", err);
@@ -3237,7 +3237,12 @@ const useVectorSearch = () => {
3237
3237
  setSearchParams(null);
3238
3238
  return;
3239
3239
  }
3240
- setSearchParams({ flow: flow || "default", term, limit: limit || 10, collection });
3240
+ setSearchParams({
3241
+ flow: flow || "default",
3242
+ term,
3243
+ limit: limit || 10,
3244
+ collection,
3245
+ });
3241
3246
  };
3242
3247
  // Return vector search state and operations for use in components
3243
3248
  return {
@@ -3316,7 +3321,9 @@ const useInference = () => {
3316
3321
  const graphRagMutation = reactQuery.useMutation({
3317
3322
  mutationFn: async ({ input, options, collection, }) => {
3318
3323
  // Execute Graph RAG request
3319
- const response = await socket.flow(flowId).graphRag(input, options || {}, collection);
3324
+ const response = await socket
3325
+ .flow(flowId)
3326
+ .graphRag(input, options || {}, collection);
3320
3327
  // Get embeddings for entity discovery
3321
3328
  const embeddings = await socket.flow(flowId).embeddings(input);
3322
3329
  // Query graph embeddings to find entities
@@ -3354,7 +3361,9 @@ const useInference = () => {
3354
3361
  callbacks?.onError?.(error);
3355
3362
  reject(new Error(error));
3356
3363
  };
3357
- socket.flow(flowId).agent(input, onThink, onObserve, onAnswer, onError);
3364
+ socket
3365
+ .flow(flowId)
3366
+ .agent(input, onThink, onObserve, onAnswer, onError);
3358
3367
  });
3359
3368
  },
3360
3369
  });
@@ -3791,9 +3800,7 @@ const useCollections = () => {
3791
3800
  const deleteCollectionsMutation = reactQuery.useMutation({
3792
3801
  mutationFn: ({ collections, onSuccess }) => {
3793
3802
  // Execute deletion requests in parallel for all collection IDs
3794
- return Promise.all(collections.map((collection) => socket
3795
- .collectionManagement()
3796
- .deleteCollection(collection))).then(() => {
3803
+ return Promise.all(collections.map((collection) => socket.collectionManagement().deleteCollection(collection))).then(() => {
3797
3804
  // Execute success callback if provided
3798
3805
  if (onSuccess)
3799
3806
  onSuccess();