@personaai/react 0.7.5 → 0.7.8
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.cjs +25 -6
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +50 -0
- package/dist/index.d.ts +50 -0
- package/dist/index.js +25 -6
- package/dist/index.js.map +1 -1
- package/package.json +82 -82
package/dist/index.d.cts
CHANGED
|
@@ -268,6 +268,20 @@ interface UseChatOptions {
|
|
|
268
268
|
* host app still owns starting/stopping the call itself (e.g. `voice.start()`/`voice.stop()`).
|
|
269
269
|
*/
|
|
270
270
|
voice?: UseVoiceResult;
|
|
271
|
+
/**
|
|
272
|
+
* Caller-supplied context — never shown to the model in any form, unlike
|
|
273
|
+
* `contextOverride` (see {@link SendMessageOverride.contextOverride}).
|
|
274
|
+
* Only ever read live by an RCP tool's resolver at the moment it's
|
|
275
|
+
* actually called. Accepts a plain object, or a getter (`() => object`)
|
|
276
|
+
* so `sendMessage()` always reads your app's *current* state at send
|
|
277
|
+
* time — no ref, no effect to keep it in sync as the value changes (e.g.
|
|
278
|
+
* the user navigates to a different page mid-conversation). Shallow-merged
|
|
279
|
+
* with any call-level `sendMessage(text, { context })` override, which
|
|
280
|
+
* wins on key collisions. Must be a flat object of string/number/boolean
|
|
281
|
+
* values only, capped at 2000 bytes serialized — a violation is rejected
|
|
282
|
+
* with a 400, not silently truncated or coerced.
|
|
283
|
+
*/
|
|
284
|
+
context?: Record<string, unknown> | (() => Record<string, unknown>);
|
|
271
285
|
}
|
|
272
286
|
interface SendMessageOverride {
|
|
273
287
|
agentId?: string;
|
|
@@ -291,6 +305,13 @@ interface SendMessageOverride {
|
|
|
291
305
|
* `@personaai/sdk`'s `SendMessageOptions.contextOverride`.
|
|
292
306
|
*/
|
|
293
307
|
contextOverride?: string;
|
|
308
|
+
/**
|
|
309
|
+
* One-off override for this send only — shallow-merged on top of
|
|
310
|
+
* `useChat`'s hook-level `context` option (this wins on key collisions).
|
|
311
|
+
* Same shape/cap/contract as the hook-level option; see
|
|
312
|
+
* {@link UseChatOptions.context}.
|
|
313
|
+
*/
|
|
314
|
+
context?: Record<string, unknown>;
|
|
294
315
|
}
|
|
295
316
|
/**
|
|
296
317
|
* `useVoice`'s call state, driven by `voice_activity` events from the
|
|
@@ -325,6 +346,26 @@ interface UseVoiceOptions {
|
|
|
325
346
|
* leave undefined) to start a fresh conversation.
|
|
326
347
|
*/
|
|
327
348
|
threadId?: string;
|
|
349
|
+
/**
|
|
350
|
+
* Caller-supplied context appended to the Agent's system instruction for
|
|
351
|
+
* this call — same field/cap/contract as `useChat`'s `sendMessage(text, {
|
|
352
|
+
* contextOverride })`. Unlike text chat, this is a **one-time append at
|
|
353
|
+
* connect**, not re-applied per turn: Gemini Live's system instruction is
|
|
354
|
+
* fixed for the whole call, so changing it means ending this call and
|
|
355
|
+
* starting a new `start()`. Capped at 4000 characters server-side
|
|
356
|
+
* (rejected with a 400, not truncated).
|
|
357
|
+
*/
|
|
358
|
+
contextOverride?: string;
|
|
359
|
+
/**
|
|
360
|
+
* Caller-supplied context — never shown to the model, only ever read live
|
|
361
|
+
* by an RCP tool's resolver. This is the **at-connect seed only**, passed
|
|
362
|
+
* to `start()`'s ticket-mint call. To refresh it for the rest of an
|
|
363
|
+
* already-open call (a voice call can run up to 15 minutes — long enough
|
|
364
|
+
* for the caller's own context to change), use the returned
|
|
365
|
+
* `updateContext()` instead, which sends it live over the open WebSocket
|
|
366
|
+
* with no reconnect and no interruption to the audio.
|
|
367
|
+
*/
|
|
368
|
+
context?: Record<string, unknown>;
|
|
328
369
|
}
|
|
329
370
|
interface UseVoiceResult {
|
|
330
371
|
state: PersonaVoiceState;
|
|
@@ -344,6 +385,15 @@ interface UseVoiceResult {
|
|
|
344
385
|
mute: (muted: boolean) => void;
|
|
345
386
|
/** Sends a typed message mid-call instead of speaking — the agent may reply in either voice or text. */
|
|
346
387
|
sendText: (text: string) => void;
|
|
388
|
+
/**
|
|
389
|
+
* Live-refreshes context for the rest of this already-open call — merged
|
|
390
|
+
* into, not replacing, whatever context is already set (from `start()`'s
|
|
391
|
+
* `context` option or a previous `updateContext()` call). Sent directly
|
|
392
|
+
* over the open WebSocket (`{ type: 'voice.context', context }`); a no-op
|
|
393
|
+
* if the call isn't currently active. No reconnect, no dropped audio —
|
|
394
|
+
* the next tool call in this session reads the new value.
|
|
395
|
+
*/
|
|
396
|
+
updateContext: (context: Record<string, unknown>) => void;
|
|
347
397
|
}
|
|
348
398
|
|
|
349
399
|
interface PersonaContextValue {
|
package/dist/index.d.ts
CHANGED
|
@@ -268,6 +268,20 @@ interface UseChatOptions {
|
|
|
268
268
|
* host app still owns starting/stopping the call itself (e.g. `voice.start()`/`voice.stop()`).
|
|
269
269
|
*/
|
|
270
270
|
voice?: UseVoiceResult;
|
|
271
|
+
/**
|
|
272
|
+
* Caller-supplied context — never shown to the model in any form, unlike
|
|
273
|
+
* `contextOverride` (see {@link SendMessageOverride.contextOverride}).
|
|
274
|
+
* Only ever read live by an RCP tool's resolver at the moment it's
|
|
275
|
+
* actually called. Accepts a plain object, or a getter (`() => object`)
|
|
276
|
+
* so `sendMessage()` always reads your app's *current* state at send
|
|
277
|
+
* time — no ref, no effect to keep it in sync as the value changes (e.g.
|
|
278
|
+
* the user navigates to a different page mid-conversation). Shallow-merged
|
|
279
|
+
* with any call-level `sendMessage(text, { context })` override, which
|
|
280
|
+
* wins on key collisions. Must be a flat object of string/number/boolean
|
|
281
|
+
* values only, capped at 2000 bytes serialized — a violation is rejected
|
|
282
|
+
* with a 400, not silently truncated or coerced.
|
|
283
|
+
*/
|
|
284
|
+
context?: Record<string, unknown> | (() => Record<string, unknown>);
|
|
271
285
|
}
|
|
272
286
|
interface SendMessageOverride {
|
|
273
287
|
agentId?: string;
|
|
@@ -291,6 +305,13 @@ interface SendMessageOverride {
|
|
|
291
305
|
* `@personaai/sdk`'s `SendMessageOptions.contextOverride`.
|
|
292
306
|
*/
|
|
293
307
|
contextOverride?: string;
|
|
308
|
+
/**
|
|
309
|
+
* One-off override for this send only — shallow-merged on top of
|
|
310
|
+
* `useChat`'s hook-level `context` option (this wins on key collisions).
|
|
311
|
+
* Same shape/cap/contract as the hook-level option; see
|
|
312
|
+
* {@link UseChatOptions.context}.
|
|
313
|
+
*/
|
|
314
|
+
context?: Record<string, unknown>;
|
|
294
315
|
}
|
|
295
316
|
/**
|
|
296
317
|
* `useVoice`'s call state, driven by `voice_activity` events from the
|
|
@@ -325,6 +346,26 @@ interface UseVoiceOptions {
|
|
|
325
346
|
* leave undefined) to start a fresh conversation.
|
|
326
347
|
*/
|
|
327
348
|
threadId?: string;
|
|
349
|
+
/**
|
|
350
|
+
* Caller-supplied context appended to the Agent's system instruction for
|
|
351
|
+
* this call — same field/cap/contract as `useChat`'s `sendMessage(text, {
|
|
352
|
+
* contextOverride })`. Unlike text chat, this is a **one-time append at
|
|
353
|
+
* connect**, not re-applied per turn: Gemini Live's system instruction is
|
|
354
|
+
* fixed for the whole call, so changing it means ending this call and
|
|
355
|
+
* starting a new `start()`. Capped at 4000 characters server-side
|
|
356
|
+
* (rejected with a 400, not truncated).
|
|
357
|
+
*/
|
|
358
|
+
contextOverride?: string;
|
|
359
|
+
/**
|
|
360
|
+
* Caller-supplied context — never shown to the model, only ever read live
|
|
361
|
+
* by an RCP tool's resolver. This is the **at-connect seed only**, passed
|
|
362
|
+
* to `start()`'s ticket-mint call. To refresh it for the rest of an
|
|
363
|
+
* already-open call (a voice call can run up to 15 minutes — long enough
|
|
364
|
+
* for the caller's own context to change), use the returned
|
|
365
|
+
* `updateContext()` instead, which sends it live over the open WebSocket
|
|
366
|
+
* with no reconnect and no interruption to the audio.
|
|
367
|
+
*/
|
|
368
|
+
context?: Record<string, unknown>;
|
|
328
369
|
}
|
|
329
370
|
interface UseVoiceResult {
|
|
330
371
|
state: PersonaVoiceState;
|
|
@@ -344,6 +385,15 @@ interface UseVoiceResult {
|
|
|
344
385
|
mute: (muted: boolean) => void;
|
|
345
386
|
/** Sends a typed message mid-call instead of speaking — the agent may reply in either voice or text. */
|
|
346
387
|
sendText: (text: string) => void;
|
|
388
|
+
/**
|
|
389
|
+
* Live-refreshes context for the rest of this already-open call — merged
|
|
390
|
+
* into, not replacing, whatever context is already set (from `start()`'s
|
|
391
|
+
* `context` option or a previous `updateContext()` call). Sent directly
|
|
392
|
+
* over the open WebSocket (`{ type: 'voice.context', context }`); a no-op
|
|
393
|
+
* if the call isn't currently active. No reconnect, no dropped audio —
|
|
394
|
+
* the next tool call in this session reads the new value.
|
|
395
|
+
*/
|
|
396
|
+
updateContext: (context: Record<string, unknown>) => void;
|
|
347
397
|
}
|
|
348
398
|
|
|
349
399
|
interface PersonaContextValue {
|
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
|
});
|
|
@@ -1392,6 +1397,8 @@ function useVoice(options = {}) {
|
|
|
1392
1397
|
const voiceLogger = useMemo3(() => logger.child("voice"), [logger]);
|
|
1393
1398
|
const agentId = options.agentId || defaultAgentId;
|
|
1394
1399
|
const threadId = options.threadId;
|
|
1400
|
+
const contextOverride = options.contextOverride;
|
|
1401
|
+
const context = options.context;
|
|
1395
1402
|
const [state, setState] = useState4("idle");
|
|
1396
1403
|
const [isMuted, setIsMuted] = useState4(false);
|
|
1397
1404
|
const [transcript, setTranscript] = useState4(
|
|
@@ -1661,14 +1668,21 @@ function useVoice(options = {}) {
|
|
|
1661
1668
|
setToolCalls([]);
|
|
1662
1669
|
acceptedTurnSeqRef.current = 0;
|
|
1663
1670
|
setState("connecting");
|
|
1664
|
-
voiceLogger.debug("start() called", {
|
|
1671
|
+
voiceLogger.debug("start() called", {
|
|
1672
|
+
agentId,
|
|
1673
|
+
threadId,
|
|
1674
|
+
hasContextOverride: !!contextOverride,
|
|
1675
|
+
hasContext: !!context
|
|
1676
|
+
});
|
|
1665
1677
|
try {
|
|
1666
1678
|
const res = await fetchWithAuth("/voice/sessions", {
|
|
1667
1679
|
method: "POST",
|
|
1668
1680
|
headers: { "Content-Type": "application/json" },
|
|
1669
1681
|
body: JSON.stringify({
|
|
1670
1682
|
agentId,
|
|
1671
|
-
...threadId ? { threadId } : {}
|
|
1683
|
+
...threadId ? { threadId } : {},
|
|
1684
|
+
...contextOverride ? { contextOverride } : {},
|
|
1685
|
+
...context ? { context } : {}
|
|
1672
1686
|
})
|
|
1673
1687
|
});
|
|
1674
1688
|
if (!res.ok) {
|
|
@@ -1704,7 +1718,7 @@ function useVoice(options = {}) {
|
|
|
1704
1718
|
}
|
|
1705
1719
|
teardownAudio();
|
|
1706
1720
|
}
|
|
1707
|
-
}, [agentId, threadId, fetchWithAuth, handleMessage, teardownAudio, voiceLogger]);
|
|
1721
|
+
}, [agentId, threadId, contextOverride, context, fetchWithAuth, handleMessage, teardownAudio, voiceLogger]);
|
|
1708
1722
|
const mute = useCallback4((muted) => {
|
|
1709
1723
|
setIsMuted(muted);
|
|
1710
1724
|
streamRef.current?.getAudioTracks().forEach((track) => {
|
|
@@ -1715,6 +1729,10 @@ function useVoice(options = {}) {
|
|
|
1715
1729
|
if (!text?.trim() || wsRef.current?.readyState !== WebSocket.OPEN) return;
|
|
1716
1730
|
wsRef.current.send(JSON.stringify({ type: "voice.text", text }));
|
|
1717
1731
|
}, []);
|
|
1732
|
+
const updateContext = useCallback4((newContext) => {
|
|
1733
|
+
if (wsRef.current?.readyState !== WebSocket.OPEN) return;
|
|
1734
|
+
wsRef.current.send(JSON.stringify({ type: "voice.context", context: newContext }));
|
|
1735
|
+
}, []);
|
|
1718
1736
|
return {
|
|
1719
1737
|
state,
|
|
1720
1738
|
isMuted,
|
|
@@ -1726,7 +1744,8 @@ function useVoice(options = {}) {
|
|
|
1726
1744
|
start,
|
|
1727
1745
|
stop,
|
|
1728
1746
|
mute,
|
|
1729
|
-
sendText
|
|
1747
|
+
sendText,
|
|
1748
|
+
updateContext
|
|
1730
1749
|
};
|
|
1731
1750
|
}
|
|
1732
1751
|
|