@trustgraph/react-state 1.6.1 → 1.7.2

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/dist/index.esm.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { useSocket, useConnectionState } from '@trustgraph/react-provider';
2
2
  export { ConnectionStateContext, SocketContext, SocketProvider } from '@trustgraph/react-provider';
3
- import { TG_EDGE, TG_REASONING, TG_EDGE_COUNT, TG_SELECTED_EDGE, TG_QUERY, PROV_STARTED_AT_TIME, TG_CONTENT, RDFS_LABEL as RDFS_LABEL$2, PROV_WAS_DERIVED_FROM, TG_REIFIES } from '@trustgraph/client';
3
+ import { RDF_TYPE as RDF_TYPE$1, TG_EDGE, TG_REASONING, TG_EDGE_COUNT, TG_SELECTED_EDGE, TG_QUERY, PROV_STARTED_AT_TIME, TG_CONTENT, TG, PROV_WAS_DERIVED_FROM, RDFS_LABEL as RDFS_LABEL$2, TG_REIFIES } from '@trustgraph/client';
4
4
  export { PROV, PROV_ACTIVITY, PROV_ENTITY, PROV_STARTED_AT_TIME, PROV_WAS_DERIVED_FROM, PROV_WAS_GENERATED_BY, RDF, RDFS, RDF_TYPE, SCHEMA, SCHEMA_AUTHOR, SCHEMA_DESCRIPTION, SCHEMA_KEYWORDS, SCHEMA_NAME, SKOS, SKOS_DEFINITION, TG, TG_CONTENT, TG_DOCUMENT, TG_EDGE, TG_EDGE_COUNT, TG_QUERY, TG_REASONING, TG_REIFIES, TG_SELECTED_EDGE } from '@trustgraph/client';
5
5
  import { jsx } from 'react/jsx-runtime';
6
6
  import { createContext, useContext, useEffect, useState, useRef, useCallback, useMemo } from 'react';
@@ -1844,20 +1844,20 @@ const useInference = ({ flow } = {}) => {
1844
1844
  * Agent inference with streaming callbacks and optional explainability
1845
1845
  */
1846
1846
  const agentMutation = useMutation({
1847
- mutationFn: async ({ input, callbacks, }) => {
1847
+ mutationFn: async ({ input, collection, callbacks, }) => {
1848
1848
  const wantsExplainability = !!callbacks?.onExplain;
1849
1849
  const explainEvents = wantsExplainability ? [] : undefined;
1850
1850
  return new Promise((resolve, reject) => {
1851
1851
  let fullAnswer = "";
1852
- const onThink = (thought, complete) => {
1853
- callbacks?.onThink?.(thought, complete);
1852
+ const onThink = (thought, complete, messageId) => {
1853
+ callbacks?.onThink?.(thought, complete, messageId);
1854
1854
  };
1855
- const onObserve = (observation, complete) => {
1856
- callbacks?.onObserve?.(observation, complete);
1855
+ const onObserve = (observation, complete, messageId) => {
1856
+ callbacks?.onObserve?.(observation, complete, messageId);
1857
1857
  };
1858
- const onAnswer = (answer, complete) => {
1858
+ const onAnswer = (answer, complete, messageId) => {
1859
1859
  fullAnswer += answer;
1860
- callbacks?.onAnswer?.(answer, complete);
1860
+ callbacks?.onAnswer?.(answer, complete, messageId);
1861
1861
  if (complete) {
1862
1862
  resolve(fullAnswer);
1863
1863
  }
@@ -1874,7 +1874,7 @@ const useInference = ({ flow } = {}) => {
1874
1874
  : undefined;
1875
1875
  socket
1876
1876
  .flow(effectiveFlow)
1877
- .agent(input, onThink, onObserve, onAnswer, onError, onExplain);
1877
+ .agent(input, onThink, onObserve, onAnswer, onError, onExplain, collection);
1878
1878
  });
1879
1879
  },
1880
1880
  });
@@ -1922,9 +1922,25 @@ const useExplainabilityStore = create()((set, get) => ({
1922
1922
  /**
1923
1923
  * Explainability utilities for parsing and structuring explain events
1924
1924
  */
1925
+ // Agent-specific predicates (not yet in client library)
1926
+ const TG_ACTION = TG + "action";
1927
+ const TG_ARGUMENTS = TG + "arguments";
1928
+ const TG_SUBAGENT_GOAL = TG + "subagentGoal";
1929
+ // RDF type URIs for agent events
1930
+ const TG_AGENT_QUESTION = TG + "AgentQuestion";
1931
+ const TG_ANALYSIS = TG + "Analysis";
1932
+ const TG_TOOL_USE = TG + "ToolUse";
1933
+ const TG_OBSERVATION = TG + "Observation";
1934
+ const TG_THOUGHT_TYPE = TG + "Thought";
1935
+ const TG_REFLECTION_TYPE = TG + "Reflection";
1936
+ const TG_CONCLUSION = TG + "Conclusion";
1937
+ const TG_ANSWER = TG + "Answer";
1938
+ const TG_FINDING = TG + "Finding";
1939
+ const TG_SYNTHESIS_TYPE = TG + "Synthesis";
1940
+ const TG_DECOMPOSITION = TG + "Decomposition";
1941
+ // ── Helpers ─────────────────────────────────────────────────────────
1925
1942
  /**
1926
- * Extract event type from explainId URI
1927
- * e.g., "urn:trustgraph:question:abc123" → "question"
1943
+ * Extract event type from explainId URI (graph-rag only)
1928
1944
  */
1929
1945
  function getEventType(explainId) {
1930
1946
  if (explainId.includes("question"))
@@ -1969,9 +1985,53 @@ function extractQuotedTriple(term) {
1969
1985
  }
1970
1986
  return null;
1971
1987
  }
1988
+ // ── Agent event type detection ──────────────────────────────────────
1989
+ /** Map RDF type URI → agent event type (first match wins) */
1990
+ const AGENT_TYPE_CHECKS = [
1991
+ [TG_AGENT_QUESTION, "agent-question"],
1992
+ [TG_DECOMPOSITION, "decomposition"],
1993
+ [TG_ANALYSIS, "analysis"],
1994
+ [TG_TOOL_USE, "analysis"],
1995
+ [TG_OBSERVATION, "reflection"],
1996
+ [TG_THOUGHT_TYPE, "reflection"],
1997
+ [TG_REFLECTION_TYPE, "reflection"],
1998
+ [TG_CONCLUSION, "conclusion"],
1999
+ [TG_FINDING, "conclusion"],
2000
+ [TG_SYNTHESIS_TYPE, "conclusion"],
2001
+ [TG_ANSWER, "conclusion"],
2002
+ ];
1972
2003
  /**
1973
- * Parse triples for a question event
2004
+ * Detect event type from RDF types in embedded triples.
2005
+ * Returns an agent event type if matched, "unknown" otherwise.
1974
2006
  */
2007
+ function getEventTypeFromTriples(triples) {
2008
+ const types = new Set();
2009
+ for (const t of triples) {
2010
+ if (getTermValue$1(t.p) === RDF_TYPE$1) {
2011
+ types.add(getTermValue$1(t.o));
2012
+ }
2013
+ }
2014
+ for (const [typeUri, eventType] of AGENT_TYPE_CHECKS) {
2015
+ if (types.has(typeUri))
2016
+ return eventType;
2017
+ }
2018
+ return "unknown";
2019
+ }
2020
+ /** Extract common fields (label, derivedFrom) from triples */
2021
+ function extractCommonFields(triples) {
2022
+ const derivedFrom = [];
2023
+ let label;
2024
+ for (const t of triples) {
2025
+ const p = getTermValue$1(t.p);
2026
+ const o = getTermValue$1(t.o);
2027
+ if (p === RDFS_LABEL$2 && o)
2028
+ label = o;
2029
+ if (p === PROV_WAS_DERIVED_FROM && o)
2030
+ derivedFrom.push(o);
2031
+ }
2032
+ return { label, derivedFrom };
2033
+ }
2034
+ // ── Graph-RAG parsers (existing) ────────────────────────────────────
1975
2035
  function parseQuestionTriples(explainId, explainGraph, triples) {
1976
2036
  const event = {
1977
2037
  type: "question",
@@ -1990,9 +2050,6 @@ function parseQuestionTriples(explainId, explainGraph, triples) {
1990
2050
  }
1991
2051
  return event;
1992
2052
  }
1993
- /**
1994
- * Parse triples for an exploration event
1995
- */
1996
2053
  function parseExplorationTriples(explainId, explainGraph, triples) {
1997
2054
  const event = {
1998
2055
  type: "exploration",
@@ -2008,9 +2065,6 @@ function parseExplorationTriples(explainId, explainGraph, triples) {
2008
2065
  }
2009
2066
  return event;
2010
2067
  }
2011
- /**
2012
- * Parse triples for a focus event
2013
- */
2014
2068
  function parseFocusTriples(explainId, explainGraph, triples) {
2015
2069
  const event = {
2016
2070
  type: "focus",
@@ -2027,9 +2081,6 @@ function parseFocusTriples(explainId, explainGraph, triples) {
2027
2081
  }
2028
2082
  return event;
2029
2083
  }
2030
- /**
2031
- * Parse triples for a synthesis event
2032
- */
2033
2084
  function parseSynthesisTriples(explainId, explainGraph, triples) {
2034
2085
  const event = {
2035
2086
  type: "synthesis",
@@ -2045,9 +2096,6 @@ function parseSynthesisTriples(explainId, explainGraph, triples) {
2045
2096
  }
2046
2097
  return event;
2047
2098
  }
2048
- /**
2049
- * Parse triples for an edge selection entity
2050
- */
2051
2099
  function parseEdgeSelectionTriples(triples) {
2052
2100
  let edge = null;
2053
2101
  let reasoning = null;
@@ -2062,10 +2110,109 @@ function parseEdgeSelectionTriples(triples) {
2062
2110
  }
2063
2111
  return { edge, reasoning };
2064
2112
  }
2113
+ // ── Agent parsers (new) ─────────────────────────────────────────────
2114
+ function parseAgentQuestionTriples(explainId, explainGraph, triples) {
2115
+ const { label, derivedFrom } = extractCommonFields(triples);
2116
+ const event = {
2117
+ type: "agent-question",
2118
+ explainId,
2119
+ explainGraph,
2120
+ label,
2121
+ derivedFrom,
2122
+ };
2123
+ for (const t of triples) {
2124
+ const p = getTermValue$1(t.p);
2125
+ const o = getTermValue$1(t.o);
2126
+ if (p === TG_QUERY)
2127
+ event.query = o;
2128
+ if (p === PROV_STARTED_AT_TIME)
2129
+ event.timestamp = o;
2130
+ }
2131
+ return event;
2132
+ }
2133
+ function parseDecompositionTriples(explainId, explainGraph, triples) {
2134
+ const { label, derivedFrom } = extractCommonFields(triples);
2135
+ const goals = [];
2136
+ for (const t of triples) {
2137
+ const p = getTermValue$1(t.p);
2138
+ const o = getTermValue$1(t.o);
2139
+ if (p === TG_SUBAGENT_GOAL && o)
2140
+ goals.push(o);
2141
+ }
2142
+ return {
2143
+ type: "decomposition",
2144
+ explainId,
2145
+ explainGraph,
2146
+ label,
2147
+ goals,
2148
+ derivedFrom,
2149
+ };
2150
+ }
2151
+ function parseAnalysisTriples(explainId, explainGraph, triples) {
2152
+ const { label, derivedFrom } = extractCommonFields(triples);
2153
+ const event = {
2154
+ type: "analysis",
2155
+ explainId,
2156
+ explainGraph,
2157
+ label,
2158
+ derivedFrom,
2159
+ };
2160
+ for (const t of triples) {
2161
+ const p = getTermValue$1(t.p);
2162
+ const o = getTermValue$1(t.o);
2163
+ if (p === TG_ACTION)
2164
+ event.action = o;
2165
+ if (p === TG_ARGUMENTS)
2166
+ event.arguments = o;
2167
+ }
2168
+ return event;
2169
+ }
2170
+ function parseReflectionTriples(explainId, explainGraph, triples) {
2171
+ const { label, derivedFrom } = extractCommonFields(triples);
2172
+ return {
2173
+ type: "reflection",
2174
+ explainId,
2175
+ explainGraph,
2176
+ label,
2177
+ derivedFrom,
2178
+ };
2179
+ }
2180
+ function parseConclusionTriples(explainId, explainGraph, triples) {
2181
+ const { label, derivedFrom } = extractCommonFields(triples);
2182
+ return {
2183
+ type: "conclusion",
2184
+ explainId,
2185
+ explainGraph,
2186
+ label,
2187
+ derivedFrom,
2188
+ };
2189
+ }
2190
+ // ── Unified parser ──────────────────────────────────────────────────
2065
2191
  /**
2066
- * Parse triples based on event type
2192
+ * 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).
2067
2195
  */
2068
2196
  function parseExplainTriples(explainId, explainGraph, triples) {
2197
+ if (triples.length === 0)
2198
+ return null;
2199
+ // Try RDF type detection first (agent events with embedded triples)
2200
+ const rdfEventType = getEventTypeFromTriples(triples);
2201
+ if (rdfEventType !== "unknown") {
2202
+ switch (rdfEventType) {
2203
+ case "agent-question":
2204
+ return parseAgentQuestionTriples(explainId, explainGraph, triples);
2205
+ case "decomposition":
2206
+ return parseDecompositionTriples(explainId, explainGraph, triples);
2207
+ case "analysis":
2208
+ return parseAnalysisTriples(explainId, explainGraph, triples);
2209
+ case "reflection":
2210
+ return parseReflectionTriples(explainId, explainGraph, triples);
2211
+ case "conclusion":
2212
+ return parseConclusionTriples(explainId, explainGraph, triples);
2213
+ }
2214
+ }
2215
+ // Fall back to URI pattern detection (graph-rag events)
2069
2216
  const eventType = getEventType(explainId);
2070
2217
  switch (eventType) {
2071
2218
  case "question":
@@ -2252,24 +2399,26 @@ const useProvenance = (options = {}) => {
2252
2399
  *
2253
2400
  * Processing strategy:
2254
2401
  * - Events are processed immediately as they arrive
2255
- * - Main event nodes (question, exploration, focus, synthesis) use
2256
- * stability-based retry: fetch until count > 0 AND stable
2257
- * - Edge sub-objects use simple retry-until-non-empty (fast)
2258
- * - All edge fetching + label resolution + provenance runs in parallel
2402
+ * - Explain triples are embedded directly in events (no store lookups)
2403
+ * - Edge labels are resolved via triple store queries
2404
+ * - Edge label resolution + provenance runs in parallel
2405
+ * - onUpdate callback fires on every session state change, allowing
2406
+ * callers to sync to external stores (e.g. Zustand)
2259
2407
  */
2260
2408
  /**
2261
2409
  * Hook for managing explainability during inference
2262
2410
  */
2263
2411
  const useExplainability = (options = {}) => {
2264
2412
  const { flow, collection = "default", traceProvenance = true, } = options;
2265
- const socket = useSocket();
2266
- const connectionState = useConnectionState();
2267
2413
  const sessionFlowId = useSessionStore((state) => state.flowId);
2268
2414
  const effectiveFlow = flow ?? sessionFlowId;
2269
2415
  const { traceEdgeProvenance, resolveLabel } = useProvenance({
2270
2416
  flow: effectiveFlow,
2271
2417
  collection,
2272
2418
  });
2419
+ // Keep onUpdate in a ref so it doesn't break memoisation
2420
+ const onUpdateRef = useRef(options.onUpdate);
2421
+ onUpdateRef.current = options.onUpdate;
2273
2422
  const [events, setEvents] = useState([]);
2274
2423
  const [session, setSession] = useState({});
2275
2424
  const [isUnpacking, setIsUnpacking] = useState(false);
@@ -2280,98 +2429,19 @@ const useExplainability = (options = {}) => {
2280
2429
  const unpackQueueRef = useRef([]);
2281
2430
  const isProcessingRef = useRef(false);
2282
2431
  /**
2283
- * Check if connected
2284
- */
2285
- const isConnected = useCallback(() => {
2286
- return (connectionState?.status === "authenticated" ||
2287
- connectionState?.status === "unauthenticated");
2288
- }, [connectionState]);
2289
- /**
2290
- * Single triple query (no retry)
2432
+ * Resolve a single edge: extract from embedded triples, resolve labels
2291
2433
  */
2292
- const fetchTriples = useCallback(async (explainId, explainGraph) => {
2293
- return socket
2294
- .flow(effectiveFlow)
2295
- .triplesQuery({ t: "i", i: explainId }, undefined, undefined, 100, collection, explainGraph);
2296
- }, [socket, effectiveFlow, collection]);
2297
- /**
2298
- * Stability-based retry for main event nodes.
2299
- * Retries until: count > 0 AND count matches previous fetch.
2300
- * Used for question, exploration, focus, synthesis nodes where the
2301
- * backend may write multiple triples incrementally.
2302
- */
2303
- const queryWithStabilityRetry = useCallback(async (explainId, explainGraph, timeoutMs = 5000) => {
2304
- if (!isConnected())
2305
- return [];
2306
- const retryDelay = 500;
2307
- const maxAttempts = Math.ceil(timeoutMs / retryDelay) + 1;
2308
- let prevCount = -1;
2309
- for (let attempt = 0; attempt < maxAttempts; attempt++) {
2310
- try {
2311
- const triples = await fetchTriples(explainId, explainGraph);
2312
- const count = triples.length;
2313
- if (count > 0 && count === prevCount) {
2314
- return triples;
2315
- }
2316
- prevCount = count;
2317
- if (attempt < maxAttempts - 1) {
2318
- await new Promise((r) => setTimeout(r, retryDelay));
2319
- }
2320
- }
2321
- catch (err) {
2322
- console.error("[explain] triple query failed:", explainId, err);
2323
- return [];
2324
- }
2325
- }
2326
- // Return last fetch if we got anything
2327
- if (prevCount > 0) {
2328
- try {
2329
- return await fetchTriples(explainId, explainGraph);
2330
- }
2331
- catch {
2332
- return [];
2333
- }
2334
- }
2335
- return [];
2336
- }, [fetchTriples, isConnected]);
2337
- /**
2338
- * Simple retry-until-non-empty for sub-objects (edge selections).
2339
- * These are small atomic writes — either fully there or not yet.
2340
- */
2341
- const queryWithSimpleRetry = useCallback(async (explainId, explainGraph, timeoutMs = 5000) => {
2342
- if (!isConnected())
2343
- return [];
2344
- const retryDelay = 300;
2345
- const maxAttempts = Math.ceil(timeoutMs / retryDelay) + 1;
2346
- for (let attempt = 0; attempt < maxAttempts; attempt++) {
2347
- try {
2348
- const triples = await fetchTriples(explainId, explainGraph);
2349
- if (triples.length > 0)
2350
- return triples;
2351
- if (attempt < maxAttempts - 1) {
2352
- await new Promise((r) => setTimeout(r, retryDelay));
2353
- }
2354
- }
2355
- catch (err) {
2356
- console.error("[explain] triple query failed:", explainId, err);
2357
- return [];
2358
- }
2359
- }
2360
- return [];
2361
- }, [fetchTriples, isConnected]);
2362
- /**
2363
- * Resolve a single edge: fetch triples, labels, and provenance in parallel
2364
- */
2365
- const resolveEdge = useCallback(async (edgeSelUri, explainGraph) => {
2366
- const triples = await queryWithSimpleRetry(edgeSelUri, explainGraph);
2367
- const { edge, reasoning } = parseEdgeSelectionTriples(triples);
2434
+ const resolveEdge = useCallback(async (edgeSelUri, allTriples) => {
2435
+ // Filter embedded triples for this edge selection URI
2436
+ const edgeTriples = allTriples.filter((t) => getTermValue$1(t.s) === edgeSelUri);
2437
+ const { edge, reasoning } = parseEdgeSelectionTriples(edgeTriples);
2368
2438
  if (!edge)
2369
2439
  return null;
2370
2440
  const selectedEdge = {
2371
2441
  edge,
2372
2442
  reasoning: reasoning || undefined,
2373
2443
  };
2374
- // Kick off labels and provenance in parallel
2444
+ // Kick off label resolution and provenance in parallel
2375
2445
  const [labels, provenanceChains] = await Promise.all([
2376
2446
  // Labels — all 3 in parallel
2377
2447
  Promise.all([
@@ -2389,13 +2459,13 @@ const useExplainability = (options = {}) => {
2389
2459
  selectedEdge.sources = provenanceChains.map((c) => c.chain).flat();
2390
2460
  }
2391
2461
  return selectedEdge;
2392
- }, [queryWithSimpleRetry, resolveLabel, traceProvenance, traceEdgeProvenance]);
2462
+ }, [resolveLabel, traceProvenance, traceEdgeProvenance]);
2393
2463
  /**
2394
2464
  * Unpack a focus event — resolve ALL edges in parallel
2395
2465
  */
2396
- const unpackFocusEvent = useCallback(async (focusEvent) => {
2466
+ const unpackFocusEvent = useCallback(async (focusEvent, allTriples) => {
2397
2467
  // Fire off all edge resolutions concurrently
2398
- const edgePromises = focusEvent.edgeSelectionUris.map((uri) => resolveEdge(uri, focusEvent.explainGraph));
2468
+ const edgePromises = focusEvent.edgeSelectionUris.map((uri) => resolveEdge(uri, allTriples));
2399
2469
  const results = await Promise.all(edgePromises);
2400
2470
  const selectedEdges = results.filter((e) => e !== null);
2401
2471
  return {
@@ -2403,50 +2473,62 @@ const useExplainability = (options = {}) => {
2403
2473
  selectedEdges,
2404
2474
  };
2405
2475
  }, [resolveEdge]);
2406
- /** Helper to update both state and ref together */
2476
+ /** Helper to update state, ref, and notify caller together */
2407
2477
  const updateSession = useCallback((updater) => {
2408
2478
  sessionRef.current = updater(sessionRef.current);
2409
2479
  setSession(updater);
2480
+ onUpdateRef.current?.(sessionRef.current);
2410
2481
  }, []);
2482
+ const AGENT_EVENT_TYPES = new Set([
2483
+ "agent-question", "decomposition", "analysis", "reflection", "conclusion",
2484
+ ]);
2411
2485
  /**
2412
2486
  * Process a single explain event
2413
2487
  */
2414
2488
  const processEvent = useCallback(async (event) => {
2415
- // Query triples for main event node (stability retry)
2416
- const triples = await queryWithStabilityRetry(event.explainId, event.explainGraph);
2489
+ // Use embedded triples directly from the event
2490
+ const triples = event.explainTriples ?? [];
2417
2491
  // Parse into structured data
2418
2492
  const parsed = parseExplainTriples(event.explainId, event.explainGraph, triples);
2419
2493
  if (!parsed)
2420
2494
  return;
2421
- // Update session based on event type
2422
- updateSession((prev) => {
2423
- const next = { ...prev };
2424
- switch (parsed.type) {
2425
- case "question":
2426
- next.question = parsed;
2427
- break;
2428
- case "exploration":
2429
- next.exploration = parsed;
2430
- break;
2431
- case "focus":
2432
- // Will be updated again after unpacking
2433
- next.focus = parsed;
2434
- break;
2435
- case "synthesis":
2436
- next.synthesis = parsed;
2437
- break;
2438
- }
2439
- return next;
2440
- });
2441
- // For focus events, unpack edges in parallel
2442
- if (parsed.type === "focus") {
2443
- const unpackedFocus = await unpackFocusEvent(parsed);
2495
+ if (AGENT_EVENT_TYPES.has(parsed.type)) {
2496
+ // Agent event — append to timeline
2444
2497
  updateSession((prev) => ({
2445
2498
  ...prev,
2446
- focus: unpackedFocus,
2499
+ agentSteps: [...(prev.agentSteps || []), parsed],
2447
2500
  }));
2448
2501
  }
2449
- }, [queryWithStabilityRetry, unpackFocusEvent, updateSession]);
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;
2519
+ }
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
+ }));
2529
+ }
2530
+ }
2531
+ }, [unpackFocusEvent, updateSession]);
2450
2532
  /**
2451
2533
  * Process the unpack queue
2452
2534
  */
@@ -2529,10 +2611,18 @@ const useChatSession = ({ flow } = {}) => {
2529
2611
  const { settings } = useSettings();
2530
2612
  // Explainability store for persisting sessions
2531
2613
  const addExplainSession = useExplainabilityStore((state) => state.addSession);
2532
- // Explainability hook for processing events (processes each event immediately)
2614
+ // Track the current explain session ID so onUpdate can target the right store key
2615
+ const explainSessionIdRef = useRef(undefined);
2616
+ // Explainability hook — onUpdate syncs every state change to the Zustand store
2533
2617
  const explainability = useExplainability({
2534
2618
  flow: effectiveFlow,
2535
2619
  collection: settings.collection,
2620
+ onUpdate: (session) => {
2621
+ const id = explainSessionIdRef.current;
2622
+ if (id) {
2623
+ addExplainSession(id, session);
2624
+ }
2625
+ },
2536
2626
  });
2537
2627
  const explainabilityRef = useRef(explainability);
2538
2628
  explainabilityRef.current = explainability;
@@ -2551,13 +2641,9 @@ const useChatSession = ({ flow } = {}) => {
2551
2641
  addActivity(ragActivity);
2552
2642
  let accumulated = "";
2553
2643
  let messageAdded = false;
2554
- // Check if explainability is enabled
2555
- const explainabilityEnabled = settings.featureSwitches.explainability;
2556
- const sessionId = explainabilityEnabled ? generateSessionId() : undefined;
2557
- // Reset explainability state for new query
2558
- if (explainabilityEnabled) {
2559
- explainabilityRef.current.reset();
2560
- }
2644
+ const sessionId = generateSessionId();
2645
+ explainabilityRef.current.reset();
2646
+ explainSessionIdRef.current = sessionId;
2561
2647
  try {
2562
2648
  // Execute Graph RAG with streaming and entity discovery
2563
2649
  const result = await inference.graphRag({
@@ -2573,41 +2659,20 @@ const useChatSession = ({ flow } = {}) => {
2573
2659
  onChunk: (chunk, complete) => {
2574
2660
  accumulated += chunk;
2575
2661
  if (!messageAdded) {
2576
- // Add empty message on first chunk (with session ID if enabled)
2577
2662
  addMessage("ai", accumulated, undefined, sessionId);
2578
2663
  messageAdded = true;
2579
2664
  }
2580
2665
  else {
2581
- // Update existing message with accumulated text
2582
2666
  updateLastMessage(accumulated);
2583
2667
  }
2584
2668
  },
2585
- // Wire up explainability callback if feature is enabled
2586
- ...(explainabilityEnabled && {
2587
- onExplain: (event) => {
2588
- console.log("[explain] event received:", event.explainId);
2589
- explainabilityRef.current.addEvent(event);
2590
- },
2591
- }),
2669
+ onExplain: (event) => {
2670
+ console.log("[explain] event received:", event.explainId);
2671
+ explainabilityRef.current.addEvent(event);
2672
+ },
2592
2673
  },
2593
2674
  });
2594
2675
  removeActivity(ragActivity);
2595
- // Store explainability session progressively — events are already being
2596
- // processed as they arrive. Wait for processing to finish, then snapshot.
2597
- if (explainabilityEnabled && sessionId) {
2598
- const waitAndStore = async () => {
2599
- // Poll until processing completes (events are processed as they arrive)
2600
- const maxWait = 30000;
2601
- let elapsed = 0;
2602
- while (explainabilityRef.current.isProcessingRef.current && elapsed < maxWait) {
2603
- await new Promise((r) => setTimeout(r, 500));
2604
- elapsed += 500;
2605
- }
2606
- const sess = explainabilityRef.current.sessionRef.current;
2607
- addExplainSession(sessionId, sess);
2608
- };
2609
- waitAndStore();
2610
- }
2611
2676
  // Start embeddings activity
2612
2677
  addActivity(embActivity);
2613
2678
  // Get labels for each entity
@@ -2695,9 +2760,13 @@ const useChatSession = ({ flow } = {}) => {
2695
2760
  let observationMessageAdded = false;
2696
2761
  let answerAccumulated = "";
2697
2762
  let answerMessageAdded = false;
2763
+ const sessionId = generateSessionId();
2764
+ explainabilityRef.current.reset();
2765
+ explainSessionIdRef.current = sessionId;
2698
2766
  try {
2699
2767
  const response = await inference.agent({
2700
2768
  input,
2769
+ collection: settings.collection,
2701
2770
  callbacks: {
2702
2771
  onThink: (thought, complete) => {
2703
2772
  thinkingAccumulated += thought;
@@ -2730,13 +2799,17 @@ const useChatSession = ({ flow } = {}) => {
2730
2799
  onAnswer: (answer, complete) => {
2731
2800
  answerAccumulated += answer;
2732
2801
  if (!answerMessageAdded) {
2733
- addMessage("ai", answerAccumulated, "answer");
2802
+ addMessage("ai", answerAccumulated, "answer", sessionId);
2734
2803
  answerMessageAdded = true;
2735
2804
  }
2736
2805
  else {
2737
2806
  updateLastMessage(answerAccumulated);
2738
2807
  }
2739
2808
  },
2809
+ onExplain: (event) => {
2810
+ console.log("[explain] agent event received:", event.explainId);
2811
+ explainabilityRef.current.addEvent(event);
2812
+ },
2740
2813
  },
2741
2814
  });
2742
2815
  removeActivity(activity);
@@ -3061,11 +3134,9 @@ const useEmbeddings = ({ flow, term }) => {
3061
3134
  };
3062
3135
  };
3063
3136
 
3064
- // @ts-nocheck
3065
3137
  /**
3066
3138
  * Custom hook for managing collection operations
3067
3139
  * Provides functionality for fetching, creating, updating, and deleting collections
3068
- * @returns {Object} Collections state and operations
3069
3140
  */
3070
3141
  const useCollections = () => {
3071
3142
  // WebSocket connection for communicating with the collection management service
@@ -5974,5 +6045,5 @@ const useDocumentsMetadata = (documentIds = []) => {
5974
6045
  };
5975
6046
  };
5976
6047
 
5977
- export { DEFAULT_SETTINGS, NotificationProvider, RDFS_LABEL, SETTINGS_STORAGE_KEY, createDocId, extractQuotedTriple, fileToBase64, generateFlowBlueprintId, getEventType, getTermValue$1 as getExplainTermValue, getTermValue$3 as getTermValue, getTriples, parseEdgeSelectionTriples, parseExplainTriples, parseExplorationTriples, parseFocusTriples, parseQuestionTriples, parseSynthesisTriples, prepareMetadata, textToBase64, useActivity, useAgentTools, useChat, useChatSession, useChunkedDownload, useChunkedUpload, useCollections, useConversation, useDocumentEmbeddingsQuery, useDocumentMetadata, useDocumentsMetadata, useEmbeddings, useEntityDetail, useExplainability, useExplainabilityStore, useFlowBlueprints, useFlowParameters, useFlows, useGraphEmbeddings, useGraphSubgraph, useInference, useKnowledgeCores, useLLMModels, useLibrary, useLoadStateStore, useMcpTools, useNlpQuery, useNodeDetails, useNotification, useOntologies, useParameterValidation, useProcessing, useProgressStateStore, usePrompts, useProvenance, useRowEmbeddingsQuery, useRowsQuery, useSchemas, useSearchStateStore, useSessionStore, useSettings, useStructuredQuery, useTokenCosts, useTriples, useVectorSearch, useWorkbenchStateStore, vectorSearch };
6048
+ export { DEFAULT_SETTINGS, NotificationProvider, RDFS_LABEL, SETTINGS_STORAGE_KEY, createDocId, extractQuotedTriple, fileToBase64, generateFlowBlueprintId, getEventType, getEventTypeFromTriples, getTermValue$1 as getExplainTermValue, getTermValue$3 as getTermValue, getTriples, parseEdgeSelectionTriples, parseExplainTriples, parseExplorationTriples, parseFocusTriples, parseQuestionTriples, parseSynthesisTriples, prepareMetadata, textToBase64, useActivity, useAgentTools, useChat, useChatSession, useChunkedDownload, useChunkedUpload, useCollections, useConversation, useDocumentEmbeddingsQuery, useDocumentMetadata, useDocumentsMetadata, useEmbeddings, useEntityDetail, useExplainability, useExplainabilityStore, useFlowBlueprints, useFlowParameters, useFlows, useGraphEmbeddings, useGraphSubgraph, useInference, useKnowledgeCores, useLLMModels, useLibrary, useLoadStateStore, useMcpTools, useNlpQuery, useNodeDetails, useNotification, useOntologies, useParameterValidation, useProcessing, useProgressStateStore, usePrompts, useProvenance, useRowEmbeddingsQuery, useRowsQuery, useSchemas, useSearchStateStore, useSessionStore, useSettings, useStructuredQuery, useTokenCosts, useTriples, useVectorSearch, useWorkbenchStateStore, vectorSearch };
5978
6049
  //# sourceMappingURL=index.esm.js.map