@bytexbyte/nxtlinq-ai-agent-ui-react-native-development 0.2.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.
Files changed (98) hide show
  1. package/dist/NxtlinqAgentAssistant.d.ts +29 -0
  2. package/dist/NxtlinqAgentAssistant.d.ts.map +1 -0
  3. package/dist/NxtlinqAgentAssistant.js +32 -0
  4. package/dist/components/AgentAssistantShell.d.ts +7 -0
  5. package/dist/components/AgentAssistantShell.d.ts.map +1 -0
  6. package/dist/components/AgentAssistantShell.js +77 -0
  7. package/dist/components/AgentComposer.d.ts +3 -0
  8. package/dist/components/AgentComposer.d.ts.map +1 -0
  9. package/dist/components/AgentComposer.js +56 -0
  10. package/dist/components/AgentMessageList.d.ts +3 -0
  11. package/dist/components/AgentMessageList.d.ts.map +1 -0
  12. package/dist/components/AgentMessageList.js +91 -0
  13. package/dist/components/AgentRemoteAudio.d.ts +14 -0
  14. package/dist/components/AgentRemoteAudio.d.ts.map +1 -0
  15. package/dist/components/AgentRemoteAudio.js +62 -0
  16. package/dist/components/AgentVoiceBar.d.ts +3 -0
  17. package/dist/components/AgentVoiceBar.d.ts.map +1 -0
  18. package/dist/components/AgentVoiceBar.js +133 -0
  19. package/dist/components/PresetMessageChips.d.ts +3 -0
  20. package/dist/components/PresetMessageChips.d.ts.map +1 -0
  21. package/dist/components/PresetMessageChips.js +39 -0
  22. package/dist/components/VoiceGreetTrigger.d.ts +10 -0
  23. package/dist/components/VoiceGreetTrigger.d.ts.map +1 -0
  24. package/dist/components/VoiceGreetTrigger.js +99 -0
  25. package/dist/components/VoiceIcons.d.ts +12 -0
  26. package/dist/components/VoiceIcons.d.ts.map +1 -0
  27. package/dist/components/VoiceIcons.js +17 -0
  28. package/dist/components/VoiceImageInput.d.ts +10 -0
  29. package/dist/components/VoiceImageInput.d.ts.map +1 -0
  30. package/dist/components/VoiceImageInput.js +100 -0
  31. package/dist/components/VoiceWaveform.d.ts +7 -0
  32. package/dist/components/VoiceWaveform.d.ts.map +1 -0
  33. package/dist/components/VoiceWaveform.js +64 -0
  34. package/dist/context/AgentAssistantContext.d.ts +45 -0
  35. package/dist/context/AgentAssistantContext.d.ts.map +1 -0
  36. package/dist/context/AgentAssistantContext.js +244 -0
  37. package/dist/index.d.ts +16 -0
  38. package/dist/index.d.ts.map +1 -0
  39. package/dist/index.js +14 -0
  40. package/dist/theme/defaultTheme.d.ts +3 -0
  41. package/dist/theme/defaultTheme.d.ts.map +1 -0
  42. package/dist/theme/defaultTheme.js +33 -0
  43. package/dist/types.d.ts +103 -0
  44. package/dist/types.d.ts.map +1 -0
  45. package/dist/types.js +1 -0
  46. package/dist/voice/AudioSessionWaker.d.ts +18 -0
  47. package/dist/voice/AudioSessionWaker.d.ts.map +1 -0
  48. package/dist/voice/AudioSessionWaker.js +49 -0
  49. package/dist/voice/TextTtsPlayer.d.ts +21 -0
  50. package/dist/voice/TextTtsPlayer.d.ts.map +1 -0
  51. package/dist/voice/TextTtsPlayer.js +91 -0
  52. package/dist/voice/VoiceAutoGreetBinder.d.ts +6 -0
  53. package/dist/voice/VoiceAutoGreetBinder.d.ts.map +1 -0
  54. package/dist/voice/VoiceAutoGreetBinder.js +25 -0
  55. package/dist/voice/useVoiceAutoGreet.d.ts +24 -0
  56. package/dist/voice/useVoiceAutoGreet.d.ts.map +1 -0
  57. package/dist/voice/useVoiceAutoGreet.js +64 -0
  58. package/dist/voice/useVoiceMicState.d.ts +24 -0
  59. package/dist/voice/useVoiceMicState.d.ts.map +1 -0
  60. package/dist/voice/useVoiceMicState.js +84 -0
  61. package/dist/voice/voiceMicConstants.d.ts +5 -0
  62. package/dist/voice/voiceMicConstants.d.ts.map +1 -0
  63. package/dist/voice/voiceMicConstants.js +11 -0
  64. package/dist/voice/voiceWaveformConstants.d.ts +6 -0
  65. package/dist/voice/voiceWaveformConstants.d.ts.map +1 -0
  66. package/dist/voice/voiceWaveformConstants.js +7 -0
  67. package/dist/voice/webrtcAudioGain.d.ts +6 -0
  68. package/dist/voice/webrtcAudioGain.d.ts.map +1 -0
  69. package/dist/voice/webrtcAudioGain.js +11 -0
  70. package/dist/voice/writeTtsCacheFile.d.ts +9 -0
  71. package/dist/voice/writeTtsCacheFile.d.ts.map +1 -0
  72. package/dist/voice/writeTtsCacheFile.js +37 -0
  73. package/package.json +64 -0
  74. package/src/NxtlinqAgentAssistant.tsx +103 -0
  75. package/src/components/AgentAssistantShell.tsx +167 -0
  76. package/src/components/AgentComposer.tsx +117 -0
  77. package/src/components/AgentMessageList.tsx +187 -0
  78. package/src/components/AgentRemoteAudio.tsx +105 -0
  79. package/src/components/AgentVoiceBar.tsx +232 -0
  80. package/src/components/PresetMessageChips.tsx +64 -0
  81. package/src/components/VoiceGreetTrigger.tsx +158 -0
  82. package/src/components/VoiceIcons.tsx +32 -0
  83. package/src/components/VoiceImageInput.tsx +178 -0
  84. package/src/components/VoiceWaveform.tsx +84 -0
  85. package/src/context/AgentAssistantContext.tsx +369 -0
  86. package/src/index.ts +59 -0
  87. package/src/react-native.d.ts +42 -0
  88. package/src/theme/defaultTheme.ts +35 -0
  89. package/src/types.ts +107 -0
  90. package/src/voice/AudioSessionWaker.tsx +94 -0
  91. package/src/voice/TextTtsPlayer.tsx +151 -0
  92. package/src/voice/VoiceAutoGreetBinder.tsx +38 -0
  93. package/src/voice/useVoiceAutoGreet.ts +95 -0
  94. package/src/voice/useVoiceMicState.ts +116 -0
  95. package/src/voice/voiceMicConstants.ts +14 -0
  96. package/src/voice/voiceWaveformConstants.ts +10 -0
  97. package/src/voice/webrtcAudioGain.ts +21 -0
  98. package/src/voice/writeTtsCacheFile.ts +47 -0
@@ -0,0 +1,99 @@
1
+ import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
+ import { uriToVoiceImageAttachment } from '@bytexbyte/nxtlinq-ai-agent-react-native-development';
3
+ import { useCallback, useState } from 'react';
4
+ import { ActivityIndicator, Pressable, StyleSheet, Text, View, } from 'react-native';
5
+ import { useAgentAssistant } from '../context/AgentAssistantContext';
6
+ function buildGreetingText(config) {
7
+ if (config.text?.trim())
8
+ return config.text.trim();
9
+ const product = config.productName?.trim();
10
+ return product
11
+ ? `Hi! Please give me a brief introduction to ${product}.`
12
+ : 'Hi! Please say hello and introduce yourself.';
13
+ }
14
+ /**
15
+ * P0 / QA: manually fire the same payload as {@link useVoiceAutoGreet} (product image + intro text).
16
+ */
17
+ export function VoiceGreetTrigger({ config }) {
18
+ const { theme, interactionMode, isVoiceActive, isVoiceChannelReady, triggerVoiceGreeting, } = useAgentAssistant();
19
+ const [busy, setBusy] = useState(false);
20
+ const [error, setError] = useState(null);
21
+ const [hint, setHint] = useState(null);
22
+ const sendGreet = useCallback(async () => {
23
+ if (!isVoiceActive) {
24
+ setError('Start voice mode first');
25
+ return;
26
+ }
27
+ if (!isVoiceChannelReady) {
28
+ setError('Voice channel not ready — wait for Listening');
29
+ return;
30
+ }
31
+ setBusy(true);
32
+ setError(null);
33
+ setHint(null);
34
+ try {
35
+ const imageUrl = config.productImageUrl?.trim();
36
+ let attachments = config.attachments;
37
+ if (!attachments?.length && imageUrl) {
38
+ try {
39
+ attachments = [await uriToVoiceImageAttachment(imageUrl, 'product.jpg')];
40
+ }
41
+ catch (imgErr) {
42
+ console.warn('[nxtlinq] greet image skipped:', imgErr);
43
+ }
44
+ }
45
+ await triggerVoiceGreeting({
46
+ text: buildGreetingText(config),
47
+ attachments,
48
+ skipUserMessage: config.skipUserMessage ?? true,
49
+ }, { waitForChannel: true, timeoutMs: 12000 });
50
+ setHint('Opening greet sent');
51
+ }
52
+ catch (e) {
53
+ const message = e instanceof Error ? e.message : String(e);
54
+ setError(message);
55
+ console.warn('[nxtlinq] triggerVoiceGreeting failed:', message);
56
+ }
57
+ finally {
58
+ setBusy(false);
59
+ }
60
+ }, [
61
+ config,
62
+ isVoiceActive,
63
+ isVoiceChannelReady,
64
+ triggerVoiceGreeting,
65
+ ]);
66
+ if (interactionMode !== 'voice')
67
+ return null;
68
+ const imageNote = config.productImageUrl?.trim()
69
+ ? '(含產品圖)'
70
+ : '(僅文字)';
71
+ return (_jsxs(View, { style: [
72
+ styles.box,
73
+ {
74
+ borderTopColor: theme.colors.border,
75
+ backgroundColor: theme.colors.background,
76
+ padding: theme.spacing.sm,
77
+ },
78
+ ], children: [_jsxs(Text, { style: { color: theme.colors.mutedText, fontSize: theme.typography.captionSize }, children: ["Voice opening greet (manual test)", imageNote] }), !isVoiceChannelReady ? (_jsx(Text, { style: {
79
+ color: theme.colors.mutedText,
80
+ fontSize: theme.typography.captionSize,
81
+ marginTop: theme.spacing.xs,
82
+ }, children: "Waiting for voice channel\u2026" })) : null, error ? (_jsx(Text, { style: { color: theme.colors.error, fontSize: theme.typography.captionSize }, children: error })) : null, hint ? (_jsx(Text, { style: { color: theme.colors.primary, fontSize: theme.typography.captionSize }, children: hint })) : null, _jsx(Pressable, { onPress: () => void sendGreet(), disabled: busy || !isVoiceChannelReady, style: ({ pressed }) => [
83
+ styles.btn,
84
+ {
85
+ backgroundColor: theme.colors.voiceSpeaking,
86
+ marginTop: theme.spacing.xs,
87
+ opacity: pressed || busy || !isVoiceChannelReady ? 0.6 : 1,
88
+ },
89
+ ], children: busy ? (_jsx(ActivityIndicator, { color: theme.colors.primaryText, size: "small" })) : (_jsx(Text, { style: { color: theme.colors.primaryText, fontWeight: '600' }, children: "Send opening greet" })) })] }));
90
+ }
91
+ const styles = StyleSheet.create({
92
+ box: { borderTopWidth: StyleSheet.hairlineWidth },
93
+ btn: {
94
+ paddingHorizontal: 14,
95
+ paddingVertical: 10,
96
+ borderRadius: 8,
97
+ alignItems: 'center',
98
+ },
99
+ });
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ type IconProps = {
3
+ size?: number;
4
+ color?: string;
5
+ };
6
+ export declare function MicIcon({ size, color }: IconProps): React.ReactElement;
7
+ export declare function MicOffIcon({ size, color }: IconProps): React.ReactElement;
8
+ export declare function StopIcon({ size, color }: IconProps): React.ReactElement;
9
+ /** Loudspeaker — assistant audio output (Material volume-up). */
10
+ export declare function SpeakerIcon({ size, color, }: IconProps): React.ReactElement;
11
+ export {};
12
+ //# sourceMappingURL=VoiceIcons.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VoiceIcons.d.ts","sourceRoot":"","sources":["../../src/components/VoiceIcons.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,KAAK,SAAS,GAAG;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC;AAOF,wBAAgB,OAAO,CAAC,EAAE,IAAS,EAAE,KAAiB,EAAE,EAAE,SAAS,GAAG,KAAK,CAAC,YAAY,CAEvF;AAED,wBAAgB,UAAU,CAAC,EAAE,IAAS,EAAE,KAAiB,EAAE,EAAE,SAAS,GAAG,KAAK,CAAC,YAAY,CAE1F;AAED,wBAAgB,QAAQ,CAAC,EAAE,IAAS,EAAE,KAAiB,EAAE,EAAE,SAAS,GAAG,KAAK,CAAC,YAAY,CAExF;AAED,iEAAiE;AACjE,wBAAgB,WAAW,CAAC,EAC1B,IAAS,EACT,KAAiB,GAClB,EAAE,SAAS,GAAG,KAAK,CAAC,YAAY,CAEhC"}
@@ -0,0 +1,17 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import MaterialIcons from 'react-native-vector-icons/MaterialIcons';
3
+ /** Typed wrapper — avoids React 18 JSX/classic Component mismatch in package `tsc`. */
4
+ const MaterialIcon = MaterialIcons;
5
+ export function MicIcon({ size = 24, color = '#4b5563' }) {
6
+ return _jsx(MaterialIcon, { name: "mic", size: size, color: color });
7
+ }
8
+ export function MicOffIcon({ size = 24, color = '#ef4444' }) {
9
+ return _jsx(MaterialIcon, { name: "mic-off", size: size, color: color });
10
+ }
11
+ export function StopIcon({ size = 24, color = '#4b5563' }) {
12
+ return _jsx(MaterialIcon, { name: "stop", size: size, color: color });
13
+ }
14
+ /** Loudspeaker — assistant audio output (Material volume-up). */
15
+ export function SpeakerIcon({ size = 24, color = '#ec4899', }) {
16
+ return _jsx(MaterialIcon, { name: "volume-up", size: size, color: color });
17
+ }
@@ -0,0 +1,10 @@
1
+ import React from 'react';
2
+ export type VoiceImageInputProps = {
3
+ /** Demo default image URL (HTTPS) for one-tap send. */
4
+ demoImageUrl?: string;
5
+ };
6
+ /**
7
+ * P0 test UI: send image (optional text) during an active voice session (SDK-2).
8
+ */
9
+ export declare function VoiceImageInput({ demoImageUrl }: VoiceImageInputProps): React.ReactElement | null;
10
+ //# sourceMappingURL=VoiceImageInput.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VoiceImageInput.d.ts","sourceRoot":"","sources":["../../src/components/VoiceImageInput.tsx"],"names":[],"mappings":"AACA,OAAO,KAAgC,MAAM,OAAO,CAAC;AAWrD,MAAM,MAAM,oBAAoB,GAAG;IACjC,uDAAuD;IACvD,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB,CAAC;AAKF;;GAEG;AACH,wBAAgB,eAAe,CAAC,EAAE,YAAY,EAAE,EAAE,oBAAoB,GAAG,KAAK,CAAC,YAAY,GAAG,IAAI,CAuIjG"}
@@ -0,0 +1,100 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { uriToVoiceImageAttachment } from '@bytexbyte/nxtlinq-ai-agent-react-native-development';
3
+ import { useCallback, useState } from 'react';
4
+ import { ActivityIndicator, Pressable, StyleSheet, Text, TextInput, View, } from 'react-native';
5
+ import { useAgentAssistant } from '../context/AgentAssistantContext';
6
+ const IMAGE_ONLY_HINT = 'Please describe this image or tell me what you would like to know about it.';
7
+ /**
8
+ * P0 test UI: send image (optional text) during an active voice session (SDK-2).
9
+ */
10
+ export function VoiceImageInput({ demoImageUrl }) {
11
+ const { theme, interactionMode, isVoiceChannelReady, sendVoiceUserInput, } = useAgentAssistant();
12
+ const [imageUrl, setImageUrl] = useState(demoImageUrl ?? '');
13
+ const [busy, setBusy] = useState(false);
14
+ const [error, setError] = useState(null);
15
+ const [sentHint, setSentHint] = useState(null);
16
+ const sendImage = useCallback(async (url) => {
17
+ const trimmed = url.trim();
18
+ if (!trimmed) {
19
+ setError('Enter an image URL');
20
+ return;
21
+ }
22
+ if (!isVoiceChannelReady) {
23
+ setError('Voice channel is not ready yet — wait for Listening');
24
+ return;
25
+ }
26
+ setBusy(true);
27
+ setError(null);
28
+ setSentHint(null);
29
+ try {
30
+ const attachment = await uriToVoiceImageAttachment(trimmed, 'voice-image.jpg');
31
+ sendVoiceUserInput({
32
+ text: IMAGE_ONLY_HINT,
33
+ attachments: [attachment],
34
+ clientMessageId: `user_img_${Date.now()}`,
35
+ });
36
+ setSentHint('Image sent');
37
+ }
38
+ catch (e) {
39
+ const message = e instanceof Error ? e.message : String(e);
40
+ setError(message);
41
+ console.warn('[nxtlinq] sendVoiceUserInput image failed:', message);
42
+ }
43
+ finally {
44
+ setBusy(false);
45
+ }
46
+ }, [isVoiceChannelReady, sendVoiceUserInput]);
47
+ if (interactionMode !== 'voice')
48
+ return null;
49
+ return (_jsxs(View, { style: [
50
+ styles.box,
51
+ {
52
+ borderTopColor: theme.colors.border,
53
+ backgroundColor: theme.colors.background,
54
+ padding: theme.spacing.sm,
55
+ },
56
+ ], children: [_jsx(Text, { style: { color: theme.colors.mutedText, fontSize: theme.typography.captionSize }, children: "Send image during voice (P0 test)" }), !isVoiceChannelReady ? (_jsx(Text, { style: {
57
+ color: theme.colors.mutedText,
58
+ fontSize: theme.typography.captionSize,
59
+ marginTop: theme.spacing.xs,
60
+ }, children: "Waiting for voice channel\u2026" })) : null, _jsx(TextInput, { value: imageUrl, onChangeText: setImageUrl, placeholder: "HTTPS image URL or data URI", placeholderTextColor: theme.colors.mutedText, autoCapitalize: "none", style: [
61
+ styles.input,
62
+ {
63
+ borderColor: theme.colors.border,
64
+ color: theme.colors.assistantText,
65
+ marginTop: theme.spacing.xs,
66
+ },
67
+ ] }), error ? (_jsx(Text, { style: { color: theme.colors.error, fontSize: theme.typography.captionSize }, children: error })) : null, sentHint ? (_jsx(Text, { style: { color: theme.colors.primary, fontSize: theme.typography.captionSize }, children: sentHint })) : null, _jsxs(View, { style: [styles.row, { marginTop: theme.spacing.xs }], children: [_jsx(Pressable, { onPress: () => sendImage(imageUrl), disabled: busy || !isVoiceChannelReady, style: ({ pressed }) => [
68
+ styles.btn,
69
+ {
70
+ backgroundColor: theme.colors.primary,
71
+ opacity: pressed || busy || !isVoiceChannelReady ? 0.6 : 1,
72
+ },
73
+ ], children: busy ? (_jsx(ActivityIndicator, { color: theme.colors.primaryText, size: "small" })) : (_jsx(Text, { style: { color: theme.colors.primaryText, fontWeight: '600' }, children: "Send image" })) }), demoImageUrl ? (_jsx(Pressable, { onPress: () => sendImage(demoImageUrl), disabled: busy || !isVoiceChannelReady, style: ({ pressed }) => [
74
+ styles.btn,
75
+ {
76
+ backgroundColor: theme.colors.surface,
77
+ borderWidth: 1,
78
+ borderColor: theme.colors.border,
79
+ opacity: pressed || busy || !isVoiceChannelReady ? 0.6 : 1,
80
+ },
81
+ ], children: _jsx(Text, { style: { color: theme.colors.assistantText }, children: "Product image" }) })) : null] })] }));
82
+ }
83
+ const styles = StyleSheet.create({
84
+ box: { borderTopWidth: StyleSheet.hairlineWidth },
85
+ input: {
86
+ borderWidth: 1,
87
+ borderRadius: 8,
88
+ paddingHorizontal: 10,
89
+ paddingVertical: 8,
90
+ fontSize: 14,
91
+ },
92
+ row: { flexDirection: 'row', gap: 8 },
93
+ btn: {
94
+ paddingHorizontal: 14,
95
+ paddingVertical: 8,
96
+ borderRadius: 8,
97
+ minWidth: 72,
98
+ alignItems: 'center',
99
+ },
100
+ });
@@ -0,0 +1,7 @@
1
+ import React from 'react';
2
+ /**
3
+ * Polls `getOutputAudioLevel()` while the assistant is speaking (Berify-aligned).
4
+ * JeannieVoiceWaveform uses `active && audible` — not during user mic / idle.
5
+ */
6
+ export declare function VoiceWaveform(): React.ReactElement | null;
7
+ //# sourceMappingURL=VoiceWaveform.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"VoiceWaveform.d.ts","sourceRoot":"","sources":["../../src/components/VoiceWaveform.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsC,MAAM,OAAO,CAAC;AAW3D;;;GAGG;AACH,wBAAgB,aAAa,IAAI,KAAK,CAAC,YAAY,GAAG,IAAI,CAsDzD"}
@@ -0,0 +1,64 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useEffect, useRef, useState } from 'react';
3
+ import { StyleSheet, View } from 'react-native';
4
+ import { useAgentAssistant } from '../context/AgentAssistantContext';
5
+ import { WAVEFORM_ACTIVE_STATUSES, WAVEFORM_AUDIBLE_HOLD_MS, WAVEFORM_AUDIBLE_THRESHOLD, } from '../voice/voiceWaveformConstants';
6
+ const BAR_COUNT = 12;
7
+ /**
8
+ * Polls `getOutputAudioLevel()` while the assistant is speaking (Berify-aligned).
9
+ * JeannieVoiceWaveform uses `active && audible` — not during user mic / idle.
10
+ */
11
+ export function VoiceWaveform() {
12
+ const { theme, interactionMode, voiceStatus, getOutputAudioLevel } = useAgentAssistant();
13
+ const [levels, setLevels] = useState(() => Array(BAR_COUNT).fill(0));
14
+ const lastAudibleAtRef = useRef(0);
15
+ useEffect(() => {
16
+ if (interactionMode !== 'voice') {
17
+ setLevels(Array(BAR_COUNT).fill(0));
18
+ return;
19
+ }
20
+ const id = setInterval(() => {
21
+ const now = Date.now();
22
+ const statusActive = WAVEFORM_ACTIVE_STATUSES.has(voiceStatus);
23
+ const rawLevel = getOutputAudioLevel();
24
+ if (rawLevel > WAVEFORM_AUDIBLE_THRESHOLD) {
25
+ lastAudibleAtRef.current = now;
26
+ }
27
+ const audible = now - lastAudibleAtRef.current < WAVEFORM_AUDIBLE_HOLD_MS;
28
+ const effectiveActive = statusActive && audible;
29
+ const scaled = effectiveActive ? rawLevel : 0;
30
+ setLevels((prev) => [...prev.slice(1), scaled]);
31
+ }, 100);
32
+ return () => clearInterval(id);
33
+ }, [interactionMode, voiceStatus, getOutputAudioLevel]);
34
+ if (interactionMode !== 'voice')
35
+ return null;
36
+ return (_jsx(View, { style: [
37
+ styles.row,
38
+ {
39
+ paddingHorizontal: theme.spacing.md,
40
+ paddingBottom: theme.spacing.sm,
41
+ backgroundColor: theme.colors.surface,
42
+ },
43
+ ], children: levels.map((level, i) => (_jsx(View, { style: [
44
+ styles.bar,
45
+ {
46
+ height: 8 + level * 28,
47
+ backgroundColor: theme.colors.voiceSpeaking,
48
+ opacity: 0.35 + level * 0.65,
49
+ },
50
+ ] }, `bar-${i}`))) }));
51
+ }
52
+ const styles = StyleSheet.create({
53
+ row: {
54
+ flexDirection: 'row',
55
+ alignItems: 'flex-end',
56
+ justifyContent: 'center',
57
+ gap: 3,
58
+ minHeight: 40,
59
+ },
60
+ bar: {
61
+ width: 4,
62
+ borderRadius: 2,
63
+ },
64
+ });
@@ -0,0 +1,45 @@
1
+ import type { VoiceStatus } from '@bytexbyte/nxtlinq-ai-agent-core-development';
2
+ import { type UseNxtlinqAgentResult, type UseNxtlinqVoiceResult } from '@bytexbyte/nxtlinq-ai-agent-react-native-development';
3
+ import React, { type ReactNode } from 'react';
4
+ import type { AgentAssistantTheme, NxtlinqAgentAssistantProps, PresetMessage } from '../types';
5
+ export type InteractionMode = 'text' | 'voice';
6
+ export type AgentAssistantContextValue = UseNxtlinqAgentResult & UseNxtlinqVoiceResult & {
7
+ theme: AgentAssistantTheme;
8
+ title: string;
9
+ placeholder: string;
10
+ presetMessages: PresetMessage[];
11
+ interactionMode: InteractionMode;
12
+ setInteractionMode: (mode: InteractionMode) => void;
13
+ inputText: string;
14
+ setInputText: (text: string) => void;
15
+ isVoiceAvailable: boolean;
16
+ isVoiceConnecting: boolean;
17
+ isMicMuted: boolean;
18
+ isMicHeldForAssistant: boolean;
19
+ toggleVoiceMicMute: () => void;
20
+ sendText: () => Promise<void>;
21
+ selectPreset: (preset: PresetMessage) => Promise<void>;
22
+ /** True when voice data channel is open and ready for user_input. */
23
+ isVoiceChannelReady: boolean;
24
+ postTextTts: (text: string) => Promise<{
25
+ audio: ArrayBuffer;
26
+ mimeType: string;
27
+ }>;
28
+ buildTextTtsPlaybackUri: (result: {
29
+ audio: ArrayBuffer;
30
+ mimeType: string;
31
+ }) => string;
32
+ playMessageTts: (messageId: string, text: string) => Promise<void>;
33
+ playingMessageId: string | null;
34
+ isTextTtsAvailable: boolean;
35
+ };
36
+ export type AgentAssistantProviderProps = {
37
+ children: ReactNode;
38
+ ui: Pick<NxtlinqAgentAssistantProps, 'title' | 'placeholder' | 'presetMessages' | 'enableVoice' | 'theme' | 'startWithMicMuted' | 'holdMicDuringAssistant' | 'textTtsVolume' | 'voiceRemoteAudioGain'> & {
39
+ webrtcEnabled: boolean;
40
+ };
41
+ };
42
+ export declare function AgentAssistantProvider({ children, ui, }: AgentAssistantProviderProps): React.ReactElement;
43
+ export declare function useAgentAssistant(): AgentAssistantContextValue;
44
+ export declare function voiceStatusLabel(status: VoiceStatus): string;
45
+ //# sourceMappingURL=AgentAssistantContext.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AgentAssistantContext.d.ts","sourceRoot":"","sources":["../../src/context/AgentAssistantContext.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8CAA8C,CAAC;AAChF,OAAO,EAGL,KAAK,qBAAqB,EAC1B,KAAK,qBAAqB,EAC3B,MAAM,sDAAsD,CAAC;AAC9D,OAAO,KAAK,EAAE,EAOZ,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AAEf,OAAO,KAAK,EAAE,mBAAmB,EAAE,0BAA0B,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAK/F,MAAM,MAAM,eAAe,GAAG,MAAM,GAAG,OAAO,CAAC;AAE/C,MAAM,MAAM,0BAA0B,GAAG,qBAAqB,GAC5D,qBAAqB,GAAG;IACxB,KAAK,EAAE,mBAAmB,CAAC;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,aAAa,EAAE,CAAC;IAChC,eAAe,EAAE,eAAe,CAAC;IACjC,kBAAkB,EAAE,CAAC,IAAI,EAAE,eAAe,KAAK,IAAI,CAAC;IACpD,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,iBAAiB,EAAE,OAAO,CAAC;IAC3B,UAAU,EAAE,OAAO,CAAC;IACpB,qBAAqB,EAAE,OAAO,CAAC;IAC/B,kBAAkB,EAAE,MAAM,IAAI,CAAC;IAC/B,QAAQ,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9B,YAAY,EAAE,CAAC,MAAM,EAAE,aAAa,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACvD,qEAAqE;IACrE,mBAAmB,EAAE,OAAO,CAAC;IAC7B,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC;QAAE,KAAK,EAAE,WAAW,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACjF,uBAAuB,EAAE,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,WAAW,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,KAAK,MAAM,CAAC;IACtF,cAAc,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;IACnE,gBAAgB,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,kBAAkB,EAAE,OAAO,CAAC;CAC7B,CAAC;AAIF,MAAM,MAAM,2BAA2B,GAAG;IACxC,QAAQ,EAAE,SAAS,CAAC;IACpB,EAAE,EAAE,IAAI,CACN,0BAA0B,EACxB,OAAO,GACP,aAAa,GACb,gBAAgB,GAChB,aAAa,GACb,OAAO,GACP,mBAAmB,GACnB,wBAAwB,GACxB,eAAe,GACf,sBAAsB,CACzB,GAAG;QACF,aAAa,EAAE,OAAO,CAAC;KACxB,CAAC;CACH,CAAC;AAEF,wBAAgB,sBAAsB,CAAC,EACrC,QAAQ,EACR,EAAE,GACH,EAAE,2BAA2B,GAAG,KAAK,CAAC,YAAY,CAiRlD;AAED,wBAAgB,iBAAiB,IAAI,0BAA0B,CAQ9D;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,CAU5D"}
@@ -0,0 +1,244 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { useNxtlinqAgent, useNxtlinqVoice, } from '@bytexbyte/nxtlinq-ai-agent-react-native-development';
3
+ import React, { createContext, useCallback, useContext, useEffect, useMemo, useState, } from 'react';
4
+ import { defaultAgentAssistantTheme } from '../theme/defaultTheme';
5
+ import { useVoiceMicState } from '../voice/useVoiceMicState';
6
+ import { waitForIOSVoiceCaptureRelease } from '@bytexbyte/nxtlinq-ai-agent-react-native-development';
7
+ import { isTextTtsPlayerSupported, TextTtsPlayer } from '../voice/TextTtsPlayer';
8
+ const AgentAssistantContext = createContext(null);
9
+ export function AgentAssistantProvider({ children, ui, }) {
10
+ const agent = useNxtlinqAgent();
11
+ const voice = useNxtlinqVoice();
12
+ const theme = useMemo(() => ({
13
+ ...defaultAgentAssistantTheme,
14
+ ...ui.theme,
15
+ colors: { ...defaultAgentAssistantTheme.colors, ...ui.theme?.colors },
16
+ spacing: { ...defaultAgentAssistantTheme.spacing, ...ui.theme?.spacing },
17
+ radius: { ...defaultAgentAssistantTheme.radius, ...ui.theme?.radius },
18
+ typography: {
19
+ ...defaultAgentAssistantTheme.typography,
20
+ ...ui.theme?.typography,
21
+ },
22
+ }), [ui.theme]);
23
+ const [interactionMode, setInteractionModeState] = useState('text');
24
+ const [inputText, setInputText] = useState('');
25
+ const [isVoiceConnecting, setIsVoiceConnecting] = useState(false);
26
+ const [playingMessageId, setPlayingMessageId] = useState(null);
27
+ const textTtsPlayerRef = React.useRef(null);
28
+ const ttsRequestIdRef = React.useRef(0);
29
+ const voiceConnectChainRef = React.useRef(Promise.resolve());
30
+ const isVoiceAvailable = Boolean(ui.webrtcEnabled && ui.enableVoice !== false);
31
+ const micStartsMuted = ui.startWithMicMuted ?? true;
32
+ const { isMicMuted, isMicHeldForAssistant, toggleVoiceMicMute, prepareForVoiceConnect, resetMicState, clearAssistantMicHold, } = useVoiceMicState(voice, isVoiceConnecting, {
33
+ startWithMicMuted: micStartsMuted,
34
+ // Decoupled: open-mic demo can start unmuted yet still mute during assistant TTS.
35
+ holdMicDuringAssistant: ui.holdMicDuringAssistant ?? true,
36
+ });
37
+ const setInteractionMode = useCallback((mode) => {
38
+ if (mode === 'text' && interactionMode === 'voice') {
39
+ void (async () => {
40
+ await voice.stopVoice('switch_to_text');
41
+ await waitForIOSVoiceCaptureRelease();
42
+ resetMicState();
43
+ })();
44
+ }
45
+ setInteractionModeState(mode);
46
+ }, [interactionMode, voice, resetMicState]);
47
+ useEffect(() => {
48
+ if (interactionMode === 'text' && voice.voiceSessionId != null) {
49
+ void (async () => {
50
+ await voice.stopVoice('mode_text_cleanup');
51
+ await waitForIOSVoiceCaptureRelease();
52
+ resetMicState();
53
+ })();
54
+ }
55
+ }, [interactionMode, voice.voiceSessionId, voice, resetMicState]);
56
+ const sendText = useCallback(async () => {
57
+ const text = inputText.trim();
58
+ if (!text || agent.isLoading)
59
+ return;
60
+ setInputText('');
61
+ await agent.sendMessage(text);
62
+ }, [agent, inputText]);
63
+ const selectPreset = useCallback(async (preset) => {
64
+ if (preset.autoSend) {
65
+ await agent.sendMessage(preset.text);
66
+ }
67
+ else {
68
+ setInputText(preset.text);
69
+ }
70
+ }, [agent]);
71
+ const wrappedStartVoice = useCallback((options) => {
72
+ const connect = async () => {
73
+ if (voice.voiceSessionId != null) {
74
+ await voice.stopVoice('restart_voice');
75
+ await waitForIOSVoiceCaptureRelease();
76
+ }
77
+ prepareForVoiceConnect();
78
+ setInteractionModeState('voice');
79
+ setIsVoiceConnecting(true);
80
+ try {
81
+ const session = await voice.startVoice({
82
+ startWithMicMuted: micStartsMuted,
83
+ ...options,
84
+ onOpen: () => {
85
+ if (!micStartsMuted) {
86
+ voice.muteMic(false);
87
+ }
88
+ options?.onOpen?.();
89
+ },
90
+ onClose: (reason) => {
91
+ resetMicState();
92
+ const userInitiated = reason === 'switch_to_text' ||
93
+ reason === 'client_stop' ||
94
+ reason === 'mode_text_cleanup';
95
+ if (userInitiated) {
96
+ setInteractionModeState('text');
97
+ }
98
+ else {
99
+ console.warn('[nxtlinq] voice session closed:', reason);
100
+ }
101
+ options?.onClose?.(reason);
102
+ },
103
+ onError: (err) => {
104
+ resetMicState();
105
+ console.warn('[nxtlinq] voice session error:', err.message);
106
+ options?.onError?.(err);
107
+ },
108
+ });
109
+ return session;
110
+ }
111
+ catch (err) {
112
+ setInteractionModeState('text');
113
+ resetMicState();
114
+ throw err;
115
+ }
116
+ finally {
117
+ setIsVoiceConnecting(false);
118
+ }
119
+ };
120
+ const next = voiceConnectChainRef.current.then(connect, connect);
121
+ voiceConnectChainRef.current = next.catch(() => undefined);
122
+ return next;
123
+ }, [voice, prepareForVoiceConnect, resetMicState, micStartsMuted, ui.voiceRemoteAudioGain]);
124
+ const wrappedStopVoice = useCallback(async () => {
125
+ await voice.stopVoice('client_stop');
126
+ await waitForIOSVoiceCaptureRelease();
127
+ resetMicState();
128
+ setInteractionModeState('text');
129
+ }, [voice, resetMicState]);
130
+ const wrappedInterrupt = useCallback(() => {
131
+ voice.interrupt();
132
+ clearAssistantMicHold();
133
+ }, [voice, clearAssistantMicHold]);
134
+ const isVoiceChannelReady = interactionMode === 'voice' &&
135
+ voice.voiceSessionId != null &&
136
+ (Boolean(agent.agent.getVoiceSession()?.isAppChannelOpen()) ||
137
+ voice.voiceStatus === 'listening');
138
+ const postTextTts = useCallback((text) => agent.agent.postTextTts(text), [agent.agent]);
139
+ const buildTextTtsPlaybackUri = useCallback((result) => agent.agent.buildTextTtsPlaybackUri(result), [agent.agent]);
140
+ const playMessageTts = useCallback(async (messageId, text) => {
141
+ const trimmed = text.trim();
142
+ if (!trimmed)
143
+ return;
144
+ const player = textTtsPlayerRef.current;
145
+ if (!player?.isAvailable) {
146
+ throw new Error('Text TTS playback requires react-native-video in your app (see Berify Jeannie).');
147
+ }
148
+ const requestId = ++ttsRequestIdRef.current;
149
+ player.stop();
150
+ setPlayingMessageId(messageId);
151
+ try {
152
+ const result = await postTextTts(trimmed);
153
+ if (ttsRequestIdRef.current !== requestId)
154
+ return;
155
+ player.play(result);
156
+ }
157
+ catch (err) {
158
+ if (ttsRequestIdRef.current === requestId) {
159
+ setPlayingMessageId(null);
160
+ }
161
+ throw err;
162
+ }
163
+ }, [postTextTts]);
164
+ const isTextTtsAvailable = isTextTtsPlayerSupported();
165
+ const value = useMemo(() => ({
166
+ ...agent,
167
+ ...voice,
168
+ isVoiceActive: interactionMode === 'voice' && voice.voiceSessionId != null,
169
+ startVoice: wrappedStartVoice,
170
+ stopVoice: wrappedStopVoice,
171
+ interrupt: wrappedInterrupt,
172
+ isMicMuted,
173
+ isMicHeldForAssistant,
174
+ toggleVoiceMicMute,
175
+ theme,
176
+ title: ui.title ?? 'AI Assistant',
177
+ placeholder: ui.placeholder ?? 'Type a message…',
178
+ presetMessages: ui.presetMessages ?? [],
179
+ interactionMode,
180
+ setInteractionMode,
181
+ inputText,
182
+ setInputText,
183
+ isVoiceAvailable,
184
+ isVoiceConnecting,
185
+ isVoiceChannelReady,
186
+ postTextTts,
187
+ buildTextTtsPlaybackUri,
188
+ playMessageTts,
189
+ playingMessageId,
190
+ isTextTtsAvailable,
191
+ sendText,
192
+ selectPreset,
193
+ }), [
194
+ agent,
195
+ voice,
196
+ wrappedStartVoice,
197
+ wrappedStopVoice,
198
+ wrappedInterrupt,
199
+ isMicMuted,
200
+ isMicHeldForAssistant,
201
+ toggleVoiceMicMute,
202
+ theme,
203
+ ui.title,
204
+ ui.placeholder,
205
+ ui.presetMessages,
206
+ interactionMode,
207
+ inputText,
208
+ isVoiceAvailable,
209
+ isVoiceConnecting,
210
+ isVoiceChannelReady,
211
+ postTextTts,
212
+ buildTextTtsPlaybackUri,
213
+ playMessageTts,
214
+ playingMessageId,
215
+ isTextTtsAvailable,
216
+ sendText,
217
+ selectPreset,
218
+ voice.voiceStatus,
219
+ ]);
220
+ return (_jsxs(AgentAssistantContext.Provider, { value: value, children: [children, _jsx(TextTtsPlayer, { playerRef: textTtsPlayerRef, volume: ui.textTtsVolume ?? 1, onPlayingChange: (playing) => {
221
+ if (!playing)
222
+ setPlayingMessageId(null);
223
+ }, onError: (message) => {
224
+ console.warn('[nxtlinq] TTS playback:', message);
225
+ } })] }));
226
+ }
227
+ export function useAgentAssistant() {
228
+ const ctx = useContext(AgentAssistantContext);
229
+ if (!ctx) {
230
+ throw new Error('useAgentAssistant must be used within <NxtlinqAgentAssistant> or <AgentAssistantProvider>');
231
+ }
232
+ return ctx;
233
+ }
234
+ export function voiceStatusLabel(status) {
235
+ const labels = {
236
+ idle: 'Ready',
237
+ listening: 'Listening',
238
+ transcribing: 'Transcribing',
239
+ thinking: 'Thinking',
240
+ generating: 'Generating',
241
+ speaking: 'Speaking',
242
+ };
243
+ return labels[status] ?? status;
244
+ }
@@ -0,0 +1,16 @@
1
+ export { NxtlinqAgentAssistant } from './NxtlinqAgentAssistant';
2
+ export type { NxtlinqAgentAssistantProps, AgentAssistantTheme, PresetMessage, Message, ToolUse, } from './types';
3
+ export { defaultAgentAssistantTheme } from './theme/defaultTheme';
4
+ export { AgentAssistantProvider, useAgentAssistant, voiceStatusLabel, type AgentAssistantContextValue, type InteractionMode, } from './context/AgentAssistantContext';
5
+ export { AgentMessageList } from './components/AgentMessageList';
6
+ export { AgentComposer } from './components/AgentComposer';
7
+ export { AgentVoiceBar } from './components/AgentVoiceBar';
8
+ export { AgentRemoteAudio } from './components/AgentRemoteAudio';
9
+ export { AudioSessionWaker } from './voice/AudioSessionWaker';
10
+ export { PresetMessageChips } from './components/PresetMessageChips';
11
+ export { AgentAssistantShell } from './components/AgentAssistantShell';
12
+ export { VoiceGreetTrigger } from './components/VoiceGreetTrigger';
13
+ export { NxtlinqAgentProvider, useNxtlinqAgent, useNxtlinqVoice, createNxtlinqAgentRN, type NxtlinqAgentProviderProps, type RNWebRTCModule, } from '@bytexbyte/nxtlinq-ai-agent-react-native-development';
14
+ export type { AgentEnvironment, AgentConfig, Attachment, AgentResponse, SendMessageOptions, NxtlinqAgentSnapshot, StartVoiceSessionOptions, VoiceSession, VoiceStatus, } from '@bytexbyte/nxtlinq-ai-agent-core-development';
15
+ export { NxtlinqAgent, setApiHosts, VoiceNotSupportedError, mapServerHistoryToMessages, appendServerHistoryIntoMessages, STORAGE_KEYS, } from '@bytexbyte/nxtlinq-ai-agent-core-development';
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAEhE,YAAY,EACV,0BAA0B,EAC1B,mBAAmB,EACnB,aAAa,EACb,OAAO,EACP,OAAO,GACR,MAAM,SAAS,CAAC;AAEjB,OAAO,EAAE,0BAA0B,EAAE,MAAM,sBAAsB,CAAC;AAElE,OAAO,EACL,sBAAsB,EACtB,iBAAiB,EACjB,gBAAgB,EAChB,KAAK,0BAA0B,EAC/B,KAAK,eAAe,GACrB,MAAM,iCAAiC,CAAC;AAEzC,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,EAAE,mBAAmB,EAAE,MAAM,kCAAkC,CAAC;AACvE,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AAGnE,OAAO,EACL,oBAAoB,EACpB,eAAe,EACf,eAAe,EACf,oBAAoB,EACpB,KAAK,yBAAyB,EAC9B,KAAK,cAAc,GACpB,MAAM,sDAAsD,CAAC;AAE9D,YAAY,EACV,gBAAgB,EAChB,WAAW,EACX,UAAU,EACV,aAAa,EACb,kBAAkB,EAClB,oBAAoB,EACpB,wBAAwB,EACxB,YAAY,EACZ,WAAW,GACZ,MAAM,8CAA8C,CAAC;AAEtD,OAAO,EACL,YAAY,EACZ,WAAW,EACX,sBAAsB,EACtB,0BAA0B,EAC1B,+BAA+B,EAC/B,YAAY,GACb,MAAM,8CAA8C,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,14 @@
1
+ export { NxtlinqAgentAssistant } from './NxtlinqAgentAssistant';
2
+ export { defaultAgentAssistantTheme } from './theme/defaultTheme';
3
+ export { AgentAssistantProvider, useAgentAssistant, voiceStatusLabel, } from './context/AgentAssistantContext';
4
+ export { AgentMessageList } from './components/AgentMessageList';
5
+ export { AgentComposer } from './components/AgentComposer';
6
+ export { AgentVoiceBar } from './components/AgentVoiceBar';
7
+ export { AgentRemoteAudio } from './components/AgentRemoteAudio';
8
+ export { AudioSessionWaker } from './voice/AudioSessionWaker';
9
+ export { PresetMessageChips } from './components/PresetMessageChips';
10
+ export { AgentAssistantShell } from './components/AgentAssistantShell';
11
+ export { VoiceGreetTrigger } from './components/VoiceGreetTrigger';
12
+ // Headless SDK re-exports for apps that compose custom layouts
13
+ export { NxtlinqAgentProvider, useNxtlinqAgent, useNxtlinqVoice, createNxtlinqAgentRN, } from '@bytexbyte/nxtlinq-ai-agent-react-native-development';
14
+ export { NxtlinqAgent, setApiHosts, VoiceNotSupportedError, mapServerHistoryToMessages, appendServerHistoryIntoMessages, STORAGE_KEYS, } from '@bytexbyte/nxtlinq-ai-agent-core-development';