@personaai/react 0.7.6 → 0.7.9

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.d.cts CHANGED
@@ -33,6 +33,11 @@ interface PersonaToolCall {
33
33
  seq?: number;
34
34
  /** Nested activity timeline — only present on `task` (subagent) tool calls. */
35
35
  subagentActivity?: PersonaSubagentActivityEntry[];
36
+ /** Present when this tool is backed by an interactive MCP Ext App. */
37
+ mcpApp?: {
38
+ resourceUri: string;
39
+ mcpId: string;
40
+ };
36
41
  }
37
42
  interface PersonaMessage {
38
43
  id: string;
@@ -268,6 +273,20 @@ interface UseChatOptions {
268
273
  * host app still owns starting/stopping the call itself (e.g. `voice.start()`/`voice.stop()`).
269
274
  */
270
275
  voice?: UseVoiceResult;
276
+ /**
277
+ * Caller-supplied context — never shown to the model in any form, unlike
278
+ * `contextOverride` (see {@link SendMessageOverride.contextOverride}).
279
+ * Only ever read live by an RCP tool's resolver at the moment it's
280
+ * actually called. Accepts a plain object, or a getter (`() => object`)
281
+ * so `sendMessage()` always reads your app's *current* state at send
282
+ * time — no ref, no effect to keep it in sync as the value changes (e.g.
283
+ * the user navigates to a different page mid-conversation). Shallow-merged
284
+ * with any call-level `sendMessage(text, { context })` override, which
285
+ * wins on key collisions. Must be a flat object of string/number/boolean
286
+ * values only, capped at 2000 bytes serialized — a violation is rejected
287
+ * with a 400, not silently truncated or coerced.
288
+ */
289
+ context?: Record<string, unknown> | (() => Record<string, unknown>);
271
290
  }
272
291
  interface SendMessageOverride {
273
292
  agentId?: string;
@@ -291,6 +310,13 @@ interface SendMessageOverride {
291
310
  * `@personaai/sdk`'s `SendMessageOptions.contextOverride`.
292
311
  */
293
312
  contextOverride?: string;
313
+ /**
314
+ * One-off override for this send only — shallow-merged on top of
315
+ * `useChat`'s hook-level `context` option (this wins on key collisions).
316
+ * Same shape/cap/contract as the hook-level option; see
317
+ * {@link UseChatOptions.context}.
318
+ */
319
+ context?: Record<string, unknown>;
294
320
  }
295
321
  /**
296
322
  * `useVoice`'s call state, driven by `voice_activity` events from the
@@ -335,6 +361,16 @@ interface UseVoiceOptions {
335
361
  * (rejected with a 400, not truncated).
336
362
  */
337
363
  contextOverride?: string;
364
+ /**
365
+ * Caller-supplied context — never shown to the model, only ever read live
366
+ * by an RCP tool's resolver. This is the **at-connect seed only**, passed
367
+ * to `start()`'s ticket-mint call. To refresh it for the rest of an
368
+ * already-open call (a voice call can run up to 15 minutes — long enough
369
+ * for the caller's own context to change), use the returned
370
+ * `updateContext()` instead, which sends it live over the open WebSocket
371
+ * with no reconnect and no interruption to the audio.
372
+ */
373
+ context?: Record<string, unknown>;
338
374
  }
339
375
  interface UseVoiceResult {
340
376
  state: PersonaVoiceState;
@@ -354,6 +390,15 @@ interface UseVoiceResult {
354
390
  mute: (muted: boolean) => void;
355
391
  /** Sends a typed message mid-call instead of speaking — the agent may reply in either voice or text. */
356
392
  sendText: (text: string) => void;
393
+ /**
394
+ * Live-refreshes context for the rest of this already-open call — merged
395
+ * into, not replacing, whatever context is already set (from `start()`'s
396
+ * `context` option or a previous `updateContext()` call). Sent directly
397
+ * over the open WebSocket (`{ type: 'voice.context', context }`); a no-op
398
+ * if the call isn't currently active. No reconnect, no dropped audio —
399
+ * the next tool call in this session reads the new value.
400
+ */
401
+ updateContext: (context: Record<string, unknown>) => void;
357
402
  }
358
403
 
359
404
  interface PersonaContextValue {
@@ -545,6 +590,19 @@ declare function useMcpConnections(options?: UseMcpConnectionsOptions): {
545
590
  refetch: () => Promise<PersonaMcpConnection[]>;
546
591
  };
547
592
 
593
+ interface UseMcpOptions {
594
+ /** Default MCP server ID for resource reads and tool calls */
595
+ mcpId?: string;
596
+ }
597
+ /**
598
+ * Hook for interacting with MCP servers connected via the Persona runtime.
599
+ * Provides helper functions for reading UI/data resources and calling server tools.
600
+ */
601
+ declare function useMcp(options?: UseMcpOptions): {
602
+ readResource: (uri: string, mcpId?: string) => Promise<any>;
603
+ callTool: (name: string, args?: Record<string, unknown>, mcpId?: string) => Promise<any>;
604
+ };
605
+
548
606
  /**
549
607
  * SSE transport for chat streams, with a React Native fallback.
550
608
  *
@@ -601,6 +659,6 @@ declare function supportsStreamingFetch(): boolean;
601
659
  */
602
660
  declare function openSSEStream(opts: OpenSSEOptions): Promise<SSEStream>;
603
661
 
604
- declare const VERSION = "0.7.3";
662
+ declare const VERSION = "0.7.9";
605
663
 
606
- export { type OpenSSEOptions, type PersonaAgentSummary, type PersonaClarificationQuestion, type PersonaFileItem, type PersonaHealthInfo, type PersonaHitlActionRequest, type PersonaInterrupt, type PersonaMcpConnection, type PersonaMemoryAgentGroup, type PersonaMemoryFile, type PersonaMemoryList, type PersonaMessage, type PersonaPresentedFile, PersonaProvider, type PersonaProviderProps, type PersonaResumeValue, type PersonaRole, type PersonaStreamingEvent, type PersonaSubagentActivityEntry, type PersonaThread, type PersonaTodo, type PersonaToolCall, type PersonaVoiceEndReason, type PersonaVoiceState, type PersonaVoiceToolCall, type PersonaVoiceTranscriptLine, type PersonaWorkspaceFile, type SSEReader, type SSEStream, type SendMessageOverride, type UseChatOptions, type UseMcpConnectionsOptions, type UseVoiceOptions, type UseVoiceResult, VERSION, openSSEStream, supportsStreamingFetch, useAgents, useChat, useConnection, useFiles, useMcpConnections, useMemory, usePersonaContext, useThreads, useVoice };
664
+ export { type OpenSSEOptions, type PersonaAgentSummary, type PersonaClarificationQuestion, type PersonaFileItem, type PersonaHealthInfo, type PersonaHitlActionRequest, type PersonaInterrupt, type PersonaMcpConnection, type PersonaMemoryAgentGroup, type PersonaMemoryFile, type PersonaMemoryList, type PersonaMessage, type PersonaPresentedFile, PersonaProvider, type PersonaProviderProps, type PersonaResumeValue, type PersonaRole, type PersonaStreamingEvent, type PersonaSubagentActivityEntry, type PersonaThread, type PersonaTodo, type PersonaToolCall, type PersonaVoiceEndReason, type PersonaVoiceState, type PersonaVoiceToolCall, type PersonaVoiceTranscriptLine, type PersonaWorkspaceFile, type SSEReader, type SSEStream, type SendMessageOverride, type UseChatOptions, type UseMcpConnectionsOptions, type UseMcpOptions, type UseVoiceOptions, type UseVoiceResult, VERSION, openSSEStream, supportsStreamingFetch, useAgents, useChat, useConnection, useFiles, useMcp, useMcpConnections, useMemory, usePersonaContext, useThreads, useVoice };
package/dist/index.d.ts CHANGED
@@ -33,6 +33,11 @@ interface PersonaToolCall {
33
33
  seq?: number;
34
34
  /** Nested activity timeline — only present on `task` (subagent) tool calls. */
35
35
  subagentActivity?: PersonaSubagentActivityEntry[];
36
+ /** Present when this tool is backed by an interactive MCP Ext App. */
37
+ mcpApp?: {
38
+ resourceUri: string;
39
+ mcpId: string;
40
+ };
36
41
  }
37
42
  interface PersonaMessage {
38
43
  id: string;
@@ -268,6 +273,20 @@ interface UseChatOptions {
268
273
  * host app still owns starting/stopping the call itself (e.g. `voice.start()`/`voice.stop()`).
269
274
  */
270
275
  voice?: UseVoiceResult;
276
+ /**
277
+ * Caller-supplied context — never shown to the model in any form, unlike
278
+ * `contextOverride` (see {@link SendMessageOverride.contextOverride}).
279
+ * Only ever read live by an RCP tool's resolver at the moment it's
280
+ * actually called. Accepts a plain object, or a getter (`() => object`)
281
+ * so `sendMessage()` always reads your app's *current* state at send
282
+ * time — no ref, no effect to keep it in sync as the value changes (e.g.
283
+ * the user navigates to a different page mid-conversation). Shallow-merged
284
+ * with any call-level `sendMessage(text, { context })` override, which
285
+ * wins on key collisions. Must be a flat object of string/number/boolean
286
+ * values only, capped at 2000 bytes serialized — a violation is rejected
287
+ * with a 400, not silently truncated or coerced.
288
+ */
289
+ context?: Record<string, unknown> | (() => Record<string, unknown>);
271
290
  }
272
291
  interface SendMessageOverride {
273
292
  agentId?: string;
@@ -291,6 +310,13 @@ interface SendMessageOverride {
291
310
  * `@personaai/sdk`'s `SendMessageOptions.contextOverride`.
292
311
  */
293
312
  contextOverride?: string;
313
+ /**
314
+ * One-off override for this send only — shallow-merged on top of
315
+ * `useChat`'s hook-level `context` option (this wins on key collisions).
316
+ * Same shape/cap/contract as the hook-level option; see
317
+ * {@link UseChatOptions.context}.
318
+ */
319
+ context?: Record<string, unknown>;
294
320
  }
295
321
  /**
296
322
  * `useVoice`'s call state, driven by `voice_activity` events from the
@@ -335,6 +361,16 @@ interface UseVoiceOptions {
335
361
  * (rejected with a 400, not truncated).
336
362
  */
337
363
  contextOverride?: string;
364
+ /**
365
+ * Caller-supplied context — never shown to the model, only ever read live
366
+ * by an RCP tool's resolver. This is the **at-connect seed only**, passed
367
+ * to `start()`'s ticket-mint call. To refresh it for the rest of an
368
+ * already-open call (a voice call can run up to 15 minutes — long enough
369
+ * for the caller's own context to change), use the returned
370
+ * `updateContext()` instead, which sends it live over the open WebSocket
371
+ * with no reconnect and no interruption to the audio.
372
+ */
373
+ context?: Record<string, unknown>;
338
374
  }
339
375
  interface UseVoiceResult {
340
376
  state: PersonaVoiceState;
@@ -354,6 +390,15 @@ interface UseVoiceResult {
354
390
  mute: (muted: boolean) => void;
355
391
  /** Sends a typed message mid-call instead of speaking — the agent may reply in either voice or text. */
356
392
  sendText: (text: string) => void;
393
+ /**
394
+ * Live-refreshes context for the rest of this already-open call — merged
395
+ * into, not replacing, whatever context is already set (from `start()`'s
396
+ * `context` option or a previous `updateContext()` call). Sent directly
397
+ * over the open WebSocket (`{ type: 'voice.context', context }`); a no-op
398
+ * if the call isn't currently active. No reconnect, no dropped audio —
399
+ * the next tool call in this session reads the new value.
400
+ */
401
+ updateContext: (context: Record<string, unknown>) => void;
357
402
  }
358
403
 
359
404
  interface PersonaContextValue {
@@ -545,6 +590,19 @@ declare function useMcpConnections(options?: UseMcpConnectionsOptions): {
545
590
  refetch: () => Promise<PersonaMcpConnection[]>;
546
591
  };
547
592
 
593
+ interface UseMcpOptions {
594
+ /** Default MCP server ID for resource reads and tool calls */
595
+ mcpId?: string;
596
+ }
597
+ /**
598
+ * Hook for interacting with MCP servers connected via the Persona runtime.
599
+ * Provides helper functions for reading UI/data resources and calling server tools.
600
+ */
601
+ declare function useMcp(options?: UseMcpOptions): {
602
+ readResource: (uri: string, mcpId?: string) => Promise<any>;
603
+ callTool: (name: string, args?: Record<string, unknown>, mcpId?: string) => Promise<any>;
604
+ };
605
+
548
606
  /**
549
607
  * SSE transport for chat streams, with a React Native fallback.
550
608
  *
@@ -601,6 +659,6 @@ declare function supportsStreamingFetch(): boolean;
601
659
  */
602
660
  declare function openSSEStream(opts: OpenSSEOptions): Promise<SSEStream>;
603
661
 
604
- declare const VERSION = "0.7.3";
662
+ declare const VERSION = "0.7.9";
605
663
 
606
- export { type OpenSSEOptions, type PersonaAgentSummary, type PersonaClarificationQuestion, type PersonaFileItem, type PersonaHealthInfo, type PersonaHitlActionRequest, type PersonaInterrupt, type PersonaMcpConnection, type PersonaMemoryAgentGroup, type PersonaMemoryFile, type PersonaMemoryList, type PersonaMessage, type PersonaPresentedFile, PersonaProvider, type PersonaProviderProps, type PersonaResumeValue, type PersonaRole, type PersonaStreamingEvent, type PersonaSubagentActivityEntry, type PersonaThread, type PersonaTodo, type PersonaToolCall, type PersonaVoiceEndReason, type PersonaVoiceState, type PersonaVoiceToolCall, type PersonaVoiceTranscriptLine, type PersonaWorkspaceFile, type SSEReader, type SSEStream, type SendMessageOverride, type UseChatOptions, type UseMcpConnectionsOptions, type UseVoiceOptions, type UseVoiceResult, VERSION, openSSEStream, supportsStreamingFetch, useAgents, useChat, useConnection, useFiles, useMcpConnections, useMemory, usePersonaContext, useThreads, useVoice };
664
+ export { type OpenSSEOptions, type PersonaAgentSummary, type PersonaClarificationQuestion, type PersonaFileItem, type PersonaHealthInfo, type PersonaHitlActionRequest, type PersonaInterrupt, type PersonaMcpConnection, type PersonaMemoryAgentGroup, type PersonaMemoryFile, type PersonaMemoryList, type PersonaMessage, type PersonaPresentedFile, PersonaProvider, type PersonaProviderProps, type PersonaResumeValue, type PersonaRole, type PersonaStreamingEvent, type PersonaSubagentActivityEntry, type PersonaThread, type PersonaTodo, type PersonaToolCall, type PersonaVoiceEndReason, type PersonaVoiceState, type PersonaVoiceToolCall, type PersonaVoiceTranscriptLine, type PersonaWorkspaceFile, type SSEReader, type SSEStream, type SendMessageOverride, type UseChatOptions, type UseMcpConnectionsOptions, type UseMcpOptions, type UseVoiceOptions, type UseVoiceResult, VERSION, openSSEStream, supportsStreamingFetch, useAgents, useChat, useConnection, useFiles, useMcp, useMcpConnections, useMemory, usePersonaContext, useThreads, useVoice };
package/dist/index.js CHANGED
@@ -642,10 +642,14 @@ function useChat(options = {}) {
642
642
  const resolvedThreadId = await (overrideOptions?.threadId ?? options.threadId);
643
643
  chatLogger.trace("resolved threadId", { threadId: resolvedThreadId });
644
644
  const token = getAuthToken ? await getAuthToken() : null;
645
+ const resolvedHookContext = typeof options.context === "function" ? options.context() : options.context;
646
+ const mergedContext = { ...resolvedHookContext, ...overrideOptions?.context };
647
+ const hasContext = Object.keys(mergedContext).length > 0;
645
648
  chatLogger.debug("opening SSE stream", {
646
649
  agentId: targetAgentId,
647
650
  hasToken: !!token,
648
- hasThreadId: !!resolvedThreadId
651
+ hasThreadId: !!resolvedThreadId,
652
+ hasContext
649
653
  });
650
654
  const stream = await openSSEStream({
651
655
  url: `${baseUrl}/chat`,
@@ -658,7 +662,8 @@ function useChat(options = {}) {
658
662
  messages: payloadMessages,
659
663
  threadId: resolvedThreadId,
660
664
  resume: overrideOptions?.resume,
661
- contextOverride: overrideOptions?.contextOverride
665
+ contextOverride: overrideOptions?.contextOverride,
666
+ ...hasContext ? { context: mergedContext } : {}
662
667
  }),
663
668
  signal: controller.signal
664
669
  });
@@ -860,6 +865,18 @@ function useChat(options = {}) {
860
865
  ];
861
866
  patchAssistant({});
862
867
  }
868
+ } else if (event.name === "mcp_app") {
869
+ const val = event.value;
870
+ if (val?.toolCallId && val?.resourceUri && val?.mcpId) {
871
+ const existing = toolCallsMap.get(val.toolCallId);
872
+ if (existing) {
873
+ existing.mcpApp = {
874
+ resourceUri: val.resourceUri,
875
+ mcpId: val.mcpId
876
+ };
877
+ patchAssistant({});
878
+ }
879
+ }
863
880
  }
864
881
  } else if (event.type === "RUN_ERROR") {
865
882
  chatLogger.warn("run error", {
@@ -1393,6 +1410,7 @@ function useVoice(options = {}) {
1393
1410
  const agentId = options.agentId || defaultAgentId;
1394
1411
  const threadId = options.threadId;
1395
1412
  const contextOverride = options.contextOverride;
1413
+ const context = options.context;
1396
1414
  const [state, setState] = useState4("idle");
1397
1415
  const [isMuted, setIsMuted] = useState4(false);
1398
1416
  const [transcript, setTranscript] = useState4(
@@ -1665,7 +1683,8 @@ function useVoice(options = {}) {
1665
1683
  voiceLogger.debug("start() called", {
1666
1684
  agentId,
1667
1685
  threadId,
1668
- hasContextOverride: !!contextOverride
1686
+ hasContextOverride: !!contextOverride,
1687
+ hasContext: !!context
1669
1688
  });
1670
1689
  try {
1671
1690
  const res = await fetchWithAuth("/voice/sessions", {
@@ -1674,7 +1693,8 @@ function useVoice(options = {}) {
1674
1693
  body: JSON.stringify({
1675
1694
  agentId,
1676
1695
  ...threadId ? { threadId } : {},
1677
- ...contextOverride ? { contextOverride } : {}
1696
+ ...contextOverride ? { contextOverride } : {},
1697
+ ...context ? { context } : {}
1678
1698
  })
1679
1699
  });
1680
1700
  if (!res.ok) {
@@ -1710,7 +1730,7 @@ function useVoice(options = {}) {
1710
1730
  }
1711
1731
  teardownAudio();
1712
1732
  }
1713
- }, [agentId, threadId, contextOverride, fetchWithAuth, handleMessage, teardownAudio, voiceLogger]);
1733
+ }, [agentId, threadId, contextOverride, context, fetchWithAuth, handleMessage, teardownAudio, voiceLogger]);
1714
1734
  const mute = useCallback4((muted) => {
1715
1735
  setIsMuted(muted);
1716
1736
  streamRef.current?.getAudioTracks().forEach((track) => {
@@ -1721,6 +1741,10 @@ function useVoice(options = {}) {
1721
1741
  if (!text?.trim() || wsRef.current?.readyState !== WebSocket.OPEN) return;
1722
1742
  wsRef.current.send(JSON.stringify({ type: "voice.text", text }));
1723
1743
  }, []);
1744
+ const updateContext = useCallback4((newContext) => {
1745
+ if (wsRef.current?.readyState !== WebSocket.OPEN) return;
1746
+ wsRef.current.send(JSON.stringify({ type: "voice.context", context: newContext }));
1747
+ }, []);
1724
1748
  return {
1725
1749
  state,
1726
1750
  isMuted,
@@ -1732,7 +1756,8 @@ function useVoice(options = {}) {
1732
1756
  start,
1733
1757
  stop,
1734
1758
  mute,
1735
- sendText
1759
+ sendText,
1760
+ updateContext
1736
1761
  };
1737
1762
  }
1738
1763
 
@@ -1962,6 +1987,47 @@ function useMcpConnections(options = {}) {
1962
1987
  };
1963
1988
  }
1964
1989
 
1990
+ // src/hooks/useMcp.ts
1991
+ import { useCallback as useCallback9 } from "react";
1992
+ function useMcp(options = {}) {
1993
+ const { fetchWithAuth } = usePersonaContext();
1994
+ const defaultMcpId = options.mcpId;
1995
+ const readResource = useCallback9(
1996
+ async (uri, mcpId) => {
1997
+ const id = mcpId ?? defaultMcpId;
1998
+ if (!id) throw new Error("MCP server ID is required to read resource");
1999
+ const res = await fetchWithAuth(
2000
+ `/mcps/${id}/resource?uri=${encodeURIComponent(uri)}`
2001
+ );
2002
+ if (!res.ok) {
2003
+ throw new Error(`Failed to read MCP resource: ${res.statusText}`);
2004
+ }
2005
+ return await res.json();
2006
+ },
2007
+ [fetchWithAuth, defaultMcpId]
2008
+ );
2009
+ const callTool = useCallback9(
2010
+ async (name, args, mcpId) => {
2011
+ const id = mcpId ?? defaultMcpId;
2012
+ if (!id) throw new Error("MCP server ID is required to call tool");
2013
+ const res = await fetchWithAuth(`/mcps/${id}/call-tool`, {
2014
+ method: "POST",
2015
+ headers: { "Content-Type": "application/json" },
2016
+ body: JSON.stringify({ name, arguments: args })
2017
+ });
2018
+ if (!res.ok) {
2019
+ throw new Error(`Failed to call MCP tool: ${res.statusText}`);
2020
+ }
2021
+ return await res.json();
2022
+ },
2023
+ [fetchWithAuth, defaultMcpId]
2024
+ );
2025
+ return {
2026
+ readResource,
2027
+ callTool
2028
+ };
2029
+ }
2030
+
1965
2031
  // src/index.ts
1966
2032
  import {
1967
2033
  createLogger as createLogger2,
@@ -1970,7 +2036,7 @@ import {
1970
2036
  getLogLevel,
1971
2037
  isLevelEnabled
1972
2038
  } from "@personaai/logger";
1973
- var VERSION = "0.7.3";
2039
+ var VERSION = "0.7.9";
1974
2040
  export {
1975
2041
  PersonaProvider,
1976
2042
  VERSION,
@@ -1985,6 +2051,7 @@ export {
1985
2051
  useChat,
1986
2052
  useConnection,
1987
2053
  useFiles,
2054
+ useMcp,
1988
2055
  useMcpConnections,
1989
2056
  useMemory,
1990
2057
  usePersonaContext,