@bytexbyte/nxtlinq-ai-agent-ui-react-development 0.3.4 → 2.0.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 (136) hide show
  1. package/dist/context/ChatBotContext.d.ts.map +1 -1
  2. package/dist/context/ChatBotContext.js +179 -160
  3. package/dist/index.d.ts +1 -1
  4. package/dist/index.d.ts.map +1 -1
  5. package/dist/permissionState.d.ts +53 -0
  6. package/dist/permissionState.d.ts.map +1 -0
  7. package/dist/permissionState.js +217 -0
  8. package/dist/types/ChatBotTypes.d.ts +6 -5
  9. package/dist/types/ChatBotTypes.d.ts.map +1 -1
  10. package/dist/ui/ModelSelector.js +2 -2
  11. package/dist/ui/PermissionForm.d.ts.map +1 -1
  12. package/dist/ui/PermissionForm.js +14 -28
  13. package/package.json +3 -3
  14. package/src/context/ChatBotContext.tsx +252 -195
  15. package/src/index.ts +0 -1
  16. package/src/permissionState.ts +313 -0
  17. package/src/types/ChatBotTypes.ts +7 -7
  18. package/src/ui/ModelSelector.tsx +5 -5
  19. package/src/ui/PermissionForm.tsx +20 -31
  20. package/dist/NxtlinqAgentChat.d.ts +0 -26
  21. package/dist/NxtlinqAgentChat.d.ts.map +0 -1
  22. package/dist/NxtlinqAgentChat.js +0 -28
  23. package/dist/components/AgentAssistantShell.d.ts +0 -5
  24. package/dist/components/AgentAssistantShell.d.ts.map +0 -1
  25. package/dist/components/AgentAssistantShell.js +0 -52
  26. package/dist/components/AgentComposer.d.ts +0 -3
  27. package/dist/components/AgentComposer.d.ts.map +0 -1
  28. package/dist/components/AgentComposer.js +0 -60
  29. package/dist/components/AgentMessageList.d.ts +0 -3
  30. package/dist/components/AgentMessageList.d.ts.map +0 -1
  31. package/dist/components/AgentMessageList.js +0 -37
  32. package/dist/components/AgentRemoteAudio.d.ts +0 -4
  33. package/dist/components/AgentRemoteAudio.d.ts.map +0 -1
  34. package/dist/components/AgentRemoteAudio.js +0 -34
  35. package/dist/components/AgentVoiceBar.d.ts +0 -3
  36. package/dist/components/AgentVoiceBar.d.ts.map +0 -1
  37. package/dist/components/AgentVoiceBar.js +0 -91
  38. package/dist/components/PresetMessageChips.d.ts +0 -3
  39. package/dist/components/PresetMessageChips.d.ts.map +0 -1
  40. package/dist/components/PresetMessageChips.js +0 -23
  41. package/dist/context/AgentAssistantContext.d.ts +0 -32
  42. package/dist/context/AgentAssistantContext.d.ts.map +0 -1
  43. package/dist/context/AgentAssistantContext.js +0 -179
  44. package/dist/legacy/assets/images/adiSideItalicDataUri.d.ts +0 -2
  45. package/dist/legacy/assets/images/adiSideItalicDataUri.d.ts.map +0 -1
  46. package/dist/legacy/assets/images/adiSideItalicDataUri.js +0 -1
  47. package/dist/legacy/chatbot/ChatBot.d.ts +0 -5
  48. package/dist/legacy/chatbot/ChatBot.d.ts.map +0 -1
  49. package/dist/legacy/chatbot/ChatBot.js +0 -35
  50. package/dist/legacy/chatbot/context/ChatBotContext.d.ts +0 -5
  51. package/dist/legacy/chatbot/context/ChatBotContext.d.ts.map +0 -1
  52. package/dist/legacy/chatbot/context/ChatBotContext.js +0 -2922
  53. package/dist/legacy/chatbot/types/ChatBotTypes.d.ts +0 -166
  54. package/dist/legacy/chatbot/types/ChatBotTypes.d.ts.map +0 -1
  55. package/dist/legacy/chatbot/types/ChatBotTypes.js +0 -1
  56. package/dist/legacy/chatbot/ui/BerifyMeModal.d.ts +0 -17
  57. package/dist/legacy/chatbot/ui/BerifyMeModal.d.ts.map +0 -1
  58. package/dist/legacy/chatbot/ui/BerifyMeModal.js +0 -110
  59. package/dist/legacy/chatbot/ui/ChatBotHeader.d.ts +0 -15
  60. package/dist/legacy/chatbot/ui/ChatBotHeader.d.ts.map +0 -1
  61. package/dist/legacy/chatbot/ui/ChatBotHeader.js +0 -62
  62. package/dist/legacy/chatbot/ui/ChatBotUI.d.ts +0 -3
  63. package/dist/legacy/chatbot/ui/ChatBotUI.d.ts.map +0 -1
  64. package/dist/legacy/chatbot/ui/ChatBotUI.js +0 -557
  65. package/dist/legacy/chatbot/ui/MessageInput.d.ts +0 -3
  66. package/dist/legacy/chatbot/ui/MessageInput.d.ts.map +0 -1
  67. package/dist/legacy/chatbot/ui/MessageInput.js +0 -321
  68. package/dist/legacy/chatbot/ui/MessageList.d.ts +0 -4
  69. package/dist/legacy/chatbot/ui/MessageList.d.ts.map +0 -1
  70. package/dist/legacy/chatbot/ui/MessageList.js +0 -455
  71. package/dist/legacy/chatbot/ui/ModelSelector.d.ts +0 -4
  72. package/dist/legacy/chatbot/ui/ModelSelector.d.ts.map +0 -1
  73. package/dist/legacy/chatbot/ui/ModelSelector.js +0 -122
  74. package/dist/legacy/chatbot/ui/NotificationModal.d.ts +0 -15
  75. package/dist/legacy/chatbot/ui/NotificationModal.d.ts.map +0 -1
  76. package/dist/legacy/chatbot/ui/NotificationModal.js +0 -53
  77. package/dist/legacy/chatbot/ui/PermissionForm.d.ts +0 -8
  78. package/dist/legacy/chatbot/ui/PermissionForm.d.ts.map +0 -1
  79. package/dist/legacy/chatbot/ui/PermissionForm.js +0 -465
  80. package/dist/legacy/chatbot/ui/PresetMessages.d.ts +0 -4
  81. package/dist/legacy/chatbot/ui/PresetMessages.d.ts.map +0 -1
  82. package/dist/legacy/chatbot/ui/PresetMessages.js +0 -33
  83. package/dist/legacy/chatbot/ui/VoiceModePanel.d.ts +0 -3
  84. package/dist/legacy/chatbot/ui/VoiceModePanel.d.ts.map +0 -1
  85. package/dist/legacy/chatbot/ui/VoiceModePanel.js +0 -95
  86. package/dist/legacy/chatbot/ui/chatBotHeaderParts.d.ts +0 -15
  87. package/dist/legacy/chatbot/ui/chatBotHeaderParts.d.ts.map +0 -1
  88. package/dist/legacy/chatbot/ui/chatBotHeaderParts.js +0 -50
  89. package/dist/legacy/chatbot/ui/styles/isolatedStyles.d.ts +0 -73
  90. package/dist/legacy/chatbot/ui/styles/isolatedStyles.d.ts.map +0 -1
  91. package/dist/legacy/chatbot/ui/styles/isolatedStyles.js +0 -985
  92. package/dist/legacy/index.d.ts +0 -14
  93. package/dist/legacy/index.d.ts.map +0 -1
  94. package/dist/legacy/index.js +0 -12
  95. package/dist/theme/defaultTheme.d.ts +0 -3
  96. package/dist/theme/defaultTheme.d.ts.map +0 -1
  97. package/dist/theme/defaultTheme.js +0 -20
  98. package/dist/types.d.ts +0 -62
  99. package/dist/types.d.ts.map +0 -1
  100. package/dist/types.js +0 -1
  101. package/dist/voice/useVoiceConnectOrchestration.d.ts +0 -21
  102. package/dist/voice/useVoiceConnectOrchestration.d.ts.map +0 -1
  103. package/dist/voice/useVoiceConnectOrchestration.js +0 -86
  104. package/dist/voice/useVoiceMicState.d.ts +0 -15
  105. package/dist/voice/useVoiceMicState.d.ts.map +0 -1
  106. package/dist/voice/useVoiceMicState.js +0 -94
  107. package/dist/voice/useVoiceSilenceCommit.d.ts +0 -10
  108. package/dist/voice/useVoiceSilenceCommit.d.ts.map +0 -1
  109. package/dist/voice/useVoiceSilenceCommit.js +0 -67
  110. package/dist/voice/useVoiceTranscriptMessages.d.ts +0 -18
  111. package/dist/voice/useVoiceTranscriptMessages.d.ts.map +0 -1
  112. package/dist/voice/useVoiceTranscriptMessages.js +0 -132
  113. package/dist/voice/useWsRealtimeAudio.d.ts +0 -18
  114. package/dist/voice/useWsRealtimeAudio.d.ts.map +0 -1
  115. package/dist/voice/useWsRealtimeAudio.js +0 -102
  116. package/dist/voice/voiceMicConstants.d.ts +0 -4
  117. package/dist/voice/voiceMicConstants.d.ts.map +0 -1
  118. package/dist/voice/voiceMicConstants.js +0 -10
  119. package/dist/voice/voiceUserBubble.d.ts +0 -10
  120. package/dist/voice/voiceUserBubble.d.ts.map +0 -1
  121. package/dist/voice/voiceUserBubble.js +0 -52
  122. package/dist/voice/ws/BrowserWsPcmPlayer.d.ts +0 -23
  123. package/dist/voice/ws/BrowserWsPcmPlayer.d.ts.map +0 -1
  124. package/dist/voice/ws/BrowserWsPcmPlayer.js +0 -137
  125. package/dist/voice/ws/BrowserWsPcmRecorder.d.ts +0 -17
  126. package/dist/voice/ws/BrowserWsPcmRecorder.d.ts.map +0 -1
  127. package/dist/voice/ws/BrowserWsPcmRecorder.js +0 -71
  128. package/dist/voice/ws/float32ToPcm16.d.ts +0 -2
  129. package/dist/voice/ws/float32ToPcm16.d.ts.map +0 -1
  130. package/dist/voice/ws/float32ToPcm16.js +0 -8
  131. package/dist/voice/ws/voiceSilenceConstants.d.ts +0 -5
  132. package/dist/voice/ws/voiceSilenceConstants.d.ts.map +0 -1
  133. package/dist/voice/ws/voiceSilenceConstants.js +0 -4
  134. package/dist/voice/ws/wsRealtimeConstants.d.ts +0 -2
  135. package/dist/voice/ws/wsRealtimeConstants.d.ts.map +0 -1
  136. package/dist/voice/ws/wsRealtimeConstants.js +0 -1
@@ -0,0 +1,313 @@
1
+ import type { AIT, RuntimeAITResult } from '@bytexbyte/nxtlinq-ai-agent-core-development';
2
+ import * as React from 'react';
3
+
4
+ const useCommitPhaseEffect = typeof window === 'undefined'
5
+ ? React.useEffect
6
+ : React.useLayoutEffect;
7
+
8
+ export function commitProviderRuntime<T, E>(
9
+ identityRef: React.MutableRefObject<T>,
10
+ identity: T,
11
+ environment: E,
12
+ publishEnvironment: (environment: E) => void,
13
+ ): void {
14
+ identityRef.current = identity;
15
+ publishEnvironment(environment);
16
+ }
17
+
18
+ export function useProviderRuntimeCommit<T, E>(
19
+ identityRef: React.MutableRefObject<T>,
20
+ identity: T,
21
+ environment: E,
22
+ publishEnvironment: (environment: E) => void,
23
+ ): void {
24
+ useCommitPhaseEffect(() => {
25
+ commitProviderRuntime(
26
+ identityRef,
27
+ identity,
28
+ environment,
29
+ publishEnvironment,
30
+ );
31
+ }, [environment, identity, identityRef, publishEnvironment]);
32
+ }
33
+
34
+ function stableUnique(values: readonly string[]): string[] {
35
+ const seen = new Set<string>();
36
+ const result: string[] = [];
37
+ for (const value of values) {
38
+ if (!seen.has(value)) {
39
+ seen.add(value);
40
+ result.push(value);
41
+ }
42
+ }
43
+ return result;
44
+ }
45
+
46
+ export function replaceCurrentMaximumDenyList(
47
+ persistedDeniedPermissions: readonly string[],
48
+ maximumPermissions: readonly string[],
49
+ checkedPermissions: readonly string[],
50
+ ): string[] {
51
+ const maximum = new Set(maximumPermissions);
52
+ const checked = new Set(checkedPermissions);
53
+ for (const permission of checked) {
54
+ if (!maximum.has(permission)) {
55
+ throw new Error(`Permission is outside the authoritative maximum: ${permission}`);
56
+ }
57
+ }
58
+
59
+ const retainedOutsideMaximum = persistedDeniedPermissions.filter(
60
+ (permission) => !maximum.has(permission),
61
+ );
62
+ const deniedInsideMaximum = maximumPermissions.filter(
63
+ (permission) => !checked.has(permission),
64
+ );
65
+ return stableUnique([...retainedOutsideMaximum, ...deniedInsideMaximum]);
66
+ }
67
+
68
+ export function removeOneDeniedPermission(
69
+ persistedDeniedPermissions: readonly string[],
70
+ permission: string,
71
+ ): string[] {
72
+ return stableUnique(persistedDeniedPermissions).filter((value) => value !== permission);
73
+ }
74
+
75
+ export type RuntimeAITContext = {
76
+ controller: string;
77
+ serviceId: string;
78
+ roles?: string[];
79
+ permissionGroup?: string;
80
+ };
81
+
82
+ export function runtimeAITContextKey(context: RuntimeAITContext): string {
83
+ return JSON.stringify([
84
+ context.controller,
85
+ context.serviceId,
86
+ context.roles === undefined ? null : [...context.roles],
87
+ context.permissionGroup ?? null,
88
+ ]);
89
+ }
90
+
91
+ export function runtimeAITSubjectKey(context: RuntimeAITContext): string {
92
+ return JSON.stringify([context.controller, context.serviceId]);
93
+ }
94
+
95
+ export function runtimeAuthorizationMatchesContext(
96
+ authorizationContextKey: string | null,
97
+ renderedContext: RuntimeAITContext | null,
98
+ ): boolean {
99
+ return authorizationContextKey === (
100
+ renderedContext ? runtimeAITContextKey(renderedContext) : null
101
+ );
102
+ }
103
+
104
+ export class StaleRuntimeAITResponseError extends Error {
105
+ constructor() {
106
+ super('Stale runtime AIT response was discarded');
107
+ this.name = 'StaleRuntimeAITResponseError';
108
+ }
109
+ }
110
+
111
+ /**
112
+ * Owns the authoritative recompute lifecycle. Only the newest request for the
113
+ * active captured context may write state; its failures clear state first.
114
+ */
115
+ export class RuntimeAITRecomputeCoordinator {
116
+ private activeContextKey: string | null = null;
117
+ private activeContext: RuntimeAITContext | null = null;
118
+ private generation = 0;
119
+
120
+ commitContext(
121
+ context: RuntimeAITContext | null,
122
+ invalidate: () => void,
123
+ ): boolean {
124
+ const nextKey = context ? runtimeAITContextKey(context) : null;
125
+ if (nextKey === this.activeContextKey) {
126
+ return false;
127
+ }
128
+ this.activeContextKey = nextKey;
129
+ this.activeContext = context ? {
130
+ controller: context.controller,
131
+ serviceId: context.serviceId,
132
+ ...(context.roles !== undefined ? { roles: [...context.roles] } : {}),
133
+ ...(context.permissionGroup !== undefined
134
+ ? { permissionGroup: context.permissionGroup }
135
+ : {}),
136
+ } : null;
137
+ this.generation += 1;
138
+ invalidate();
139
+ return true;
140
+ }
141
+
142
+ getActiveContext(): RuntimeAITContext | null {
143
+ return this.activeContext ? {
144
+ controller: this.activeContext.controller,
145
+ serviceId: this.activeContext.serviceId,
146
+ ...(this.activeContext.roles !== undefined
147
+ ? { roles: [...this.activeContext.roles] }
148
+ : {}),
149
+ ...(this.activeContext.permissionGroup !== undefined
150
+ ? { permissionGroup: this.activeContext.permissionGroup }
151
+ : {}),
152
+ } : null;
153
+ }
154
+
155
+ isContextActive(context: RuntimeAITContext): boolean {
156
+ return runtimeAITContextKey(context) === this.activeContextKey;
157
+ }
158
+
159
+ assertContextActive(context: RuntimeAITContext): void {
160
+ if (!this.isContextActive(context)) {
161
+ throw new StaleRuntimeAITResponseError();
162
+ }
163
+ }
164
+
165
+ async run<T>(
166
+ context: RuntimeAITContext,
167
+ request: () => Promise<T>,
168
+ apply: (result: T, context: RuntimeAITContext) => void,
169
+ clear: () => void,
170
+ ): Promise<T> {
171
+ this.assertContextActive(context);
172
+ const contextKey = runtimeAITContextKey(context);
173
+ const generation = ++this.generation;
174
+
175
+ try {
176
+ const result = await request();
177
+ if (generation !== this.generation || contextKey !== this.activeContextKey) {
178
+ throw new StaleRuntimeAITResponseError();
179
+ }
180
+ apply(result, context);
181
+ return result;
182
+ } catch (error) {
183
+ if (
184
+ !(error instanceof StaleRuntimeAITResponseError)
185
+ && generation === this.generation
186
+ && contextKey === this.activeContextKey
187
+ ) {
188
+ clear();
189
+ }
190
+ throw error;
191
+ }
192
+ }
193
+ }
194
+
195
+ export function useRuntimeAITContextCommit(
196
+ coordinator: RuntimeAITRecomputeCoordinator,
197
+ context: RuntimeAITContext | null,
198
+ invalidate: () => void,
199
+ ): void {
200
+ const contextKey = context ? runtimeAITContextKey(context) : null;
201
+ useCommitPhaseEffect(() => {
202
+ coordinator.commitContext(context, invalidate);
203
+ }, [contextKey, coordinator, invalidate]);
204
+ }
205
+
206
+ export async function dispatchRuntimeAITCompleteReplacement(
207
+ coordinator: RuntimeAITRecomputeCoordinator,
208
+ context: RuntimeAITContext,
209
+ update: () => Promise<unknown>,
210
+ converge: (subjectKey: string) => Promise<void>,
211
+ clear: () => void,
212
+ ): Promise<void> {
213
+ const subjectKey = runtimeAITSubjectKey(context);
214
+ coordinator.assertContextActive(context);
215
+
216
+ let updateFailed = false;
217
+ let updateError: unknown;
218
+ try {
219
+ await update();
220
+ } catch (error) {
221
+ updateFailed = true;
222
+ updateError = error;
223
+ }
224
+
225
+ try {
226
+ await converge(subjectKey);
227
+ } catch (error) {
228
+ if (!updateFailed) {
229
+ throw error;
230
+ }
231
+ }
232
+
233
+ if (updateFailed) {
234
+ if (!coordinator.isContextActive(context)) {
235
+ throw new StaleRuntimeAITResponseError();
236
+ }
237
+ clear();
238
+ throw updateError;
239
+ }
240
+ coordinator.assertContextActive(context);
241
+ }
242
+
243
+ /** Serializes reads, complete replacements, and convergence for one persistence subject. */
244
+ export class RuntimeAITMutationQueue {
245
+ private readonly tails = new Map<string, Promise<void>>();
246
+
247
+ async run<T>(subjectKey: string, mutation: () => Promise<T>): Promise<T> {
248
+ const previous = this.tails.get(subjectKey) ?? Promise.resolve();
249
+ const result = previous.catch(() => undefined).then(mutation);
250
+ const tail = result.then(() => undefined, () => undefined);
251
+ this.tails.set(subjectKey, tail);
252
+ try {
253
+ return await result;
254
+ } finally {
255
+ if (this.tails.get(subjectKey) === tail) {
256
+ this.tails.delete(subjectKey);
257
+ }
258
+ }
259
+ }
260
+ }
261
+
262
+ export type RuntimeAuthorizationState = {
263
+ ait: AIT | null;
264
+ maximumPermissions: string[];
265
+ effectivePermissions: string[];
266
+ deniedPermissions: string[];
267
+ selectedRuleId: string | null;
268
+ selectedRuleType: RuntimeAITResult['selectedRuleType'];
269
+ expiresAt: string | null;
270
+ grantActive: boolean;
271
+ unavailable: boolean;
272
+ };
273
+
274
+ export function runtimeAuthorizationState(
275
+ result: RuntimeAITResult,
276
+ controller: string,
277
+ serviceId: string,
278
+ ): RuntimeAuthorizationState {
279
+ return {
280
+ ait: result.aitId
281
+ ? {
282
+ aitId: result.aitId,
283
+ controller,
284
+ serviceId,
285
+ metadata: { permissions: [...result.effectivePermissions] },
286
+ }
287
+ : null,
288
+ maximumPermissions: [...result.maximumPermissions],
289
+ effectivePermissions: [...result.effectivePermissions],
290
+ deniedPermissions: [...result.deniedPermissions],
291
+ selectedRuleId: result.selectedRuleId,
292
+ selectedRuleType: result.selectedRuleType,
293
+ expiresAt: result.expiresAt,
294
+ grantActive: result.grantActive,
295
+ unavailable: false,
296
+ };
297
+ }
298
+
299
+ export function unavailableRuntimeAuthorization(
300
+ persistedDeniedPermissions: readonly string[],
301
+ ): RuntimeAuthorizationState {
302
+ return {
303
+ ait: null,
304
+ maximumPermissions: [],
305
+ effectivePermissions: [],
306
+ deniedPermissions: [...persistedDeniedPermissions],
307
+ selectedRuleId: null,
308
+ selectedRuleType: 'none',
309
+ expiresAt: null,
310
+ grantActive: false,
311
+ unavailable: true,
312
+ };
313
+ }
@@ -24,11 +24,6 @@ export interface NovaError {
24
24
  error: string;
25
25
  }
26
26
 
27
- export interface AITMetadata {
28
- permissions: string[];
29
- issuedBy: string;
30
- }
31
-
32
27
  // AI Model related types
33
28
  export interface AIModel {
34
29
  label: string;
@@ -62,6 +57,8 @@ export interface ChatBotProps {
62
57
  token: string;
63
58
  } | undefined>;
64
59
  permissionGroup?: string;
60
+ /** Ordered runtime identity-provider roles. Order is preserved for Group fallback. */
61
+ roles?: string[];
65
62
  children?: React.ReactNode;
66
63
  // AI Model related properties
67
64
  onModelChange?: (model: AIModel) => void;
@@ -108,6 +105,9 @@ export interface ChatBotContextType {
108
105
  hitAddress: string | null;
109
106
  ait: AIT | null;
110
107
  permissions: string[];
108
+ maximumPermissions: string[];
109
+ deniedPermissions: string[];
110
+ runtimePermissionsUnavailable: boolean;
111
111
  availablePermissions: ServicePermission[];
112
112
  showPermissionForm: boolean;
113
113
  isPermissionFormOpen: boolean;
@@ -155,7 +155,6 @@ export interface ChatBotContextType {
155
155
  setIsOpen: (open: boolean) => void;
156
156
  setShowPermissionForm: (show: boolean) => void;
157
157
  setIsPermissionFormOpen: (open: boolean) => void;
158
- setPermissions: (permissions: string[]) => void;
159
158
  setIsDisabled: (disabled: boolean) => void;
160
159
  setIsWalletLoading: (loading: boolean) => void;
161
160
  setNotification: (notification: any) => void;
@@ -203,8 +202,9 @@ export interface ChatBotContextType {
203
202
  onVerifyWallet: (method: 'berifyme' | 'custom') => Promise<void>;
204
203
  serviceId: string;
205
204
  permissionGroup?: string;
205
+ roles?: string[];
206
206
 
207
207
  // Props
208
208
  props: ChatBotProps;
209
209
  nxtlinqApi: AITApi;
210
- }
210
+ }
@@ -15,10 +15,10 @@ export const ModelSelector: React.FC = () => {
15
15
 
16
16
  // Safety check: ensure selectedModelIndex is within bounds
17
17
  const safeSelectedModelIndex = selectedModelIndex >= availableModels.length ? 0 : selectedModelIndex;
18
-
18
+
19
19
  // Check if current service is Adilas
20
20
  const isAdilasService = walletTextUtils.isAdilasService(serviceId);
21
-
21
+
22
22
  // Get fallback model label (first available model or 'Unknown')
23
23
  // For Adilas, we don't show the label, only the image
24
24
  const fallbackModelLabel = availableModels.length > 0
@@ -120,7 +120,7 @@ export const ModelSelector: React.FC = () => {
120
120
  font-size: 12px !important;
121
121
  font-weight: 500 !important;
122
122
  gap: 6px !important;
123
-
123
+
124
124
  &:hover {
125
125
  background-color: rgba(255, 255, 255, 0.2) !important;
126
126
  }
@@ -159,7 +159,7 @@ export const ModelSelector: React.FC = () => {
159
159
  color: ${index === safeSelectedModelIndex ? '#007bff' : '#333'} !important;
160
160
  font-size: 12px !important;
161
161
  border-bottom: ${index < availableModels.length - 1 ? '1px solid #eee' : 'none'} !important;
162
-
162
+
163
163
  &:hover {
164
164
  background-color: ${index === safeSelectedModelIndex ? '#f0f0f0' : '#f8f9fa'} !important;
165
165
  }
@@ -187,4 +187,4 @@ export const ModelSelector: React.FC = () => {
187
187
  )}
188
188
  </div>
189
189
  );
190
- };
190
+ };
@@ -13,7 +13,8 @@ export const PermissionForm: React.FC<PermissionFormProps> = ({ onClose }) => {
13
13
  const {
14
14
  hitAddress,
15
15
  permissions,
16
- setPermissions,
16
+ availablePermissions,
17
+ runtimePermissionsUnavailable,
17
18
  setIsDisabled,
18
19
  onSave,
19
20
  onConnectWallet,
@@ -22,15 +23,12 @@ export const PermissionForm: React.FC<PermissionFormProps> = ({ onClose }) => {
22
23
  walletInfo,
23
24
  onVerifyWallet,
24
25
  serviceId,
25
- nxtlinqApi,
26
- permissionGroup,
27
26
  isAITLoading,
28
27
  isWalletLoading = false,
29
28
  refreshAIT,
30
29
  props
31
30
  } = useChatBot();
32
31
 
33
- const [availablePermissions, setAvailablePermissions] = React.useState<any[]>([]);
34
32
  const [isSaving, setIsSaving] = React.useState(false);
35
33
  const [tempPermissions, setTempPermissions] = React.useState<string[]>(permissions);
36
34
  const [hasUserInteracted, setHasUserInteracted] = React.useState(false);
@@ -63,28 +61,6 @@ export const PermissionForm: React.FC<PermissionFormProps> = ({ onClose }) => {
63
61
  // eslint-disable-next-line react-hooks/exhaustive-deps
64
62
  }, [isAllSelected, availablePermissions.length]);
65
63
 
66
- const fetchAvailablePermissions = async () => {
67
- if (!serviceId) return;
68
-
69
- try {
70
- const result = await nxtlinqApi.permissions.getServicePermissions({
71
- serviceId,
72
- ...(permissionGroup && { groupName: permissionGroup })
73
- });
74
- if ('error' in result) {
75
- console.error('Failed to fetch permissions:', result.error);
76
- return;
77
- }
78
- setAvailablePermissions(result.permissions);
79
- } catch (error) {
80
- console.error('Error fetching permissions:', error);
81
- }
82
- };
83
-
84
- React.useEffect(() => {
85
- fetchAvailablePermissions();
86
- }, [serviceId, nxtlinqApi, permissionGroup]);
87
-
88
64
  // Refresh wallet info when component mounts or when hitAddress changes
89
65
  React.useEffect(() => {
90
66
  if (hitAddress) {
@@ -114,8 +90,6 @@ export const PermissionForm: React.FC<PermissionFormProps> = ({ onClose }) => {
114
90
  const handleSave = async () => {
115
91
  setIsSaving(true);
116
92
  try {
117
- // Update the actual permissions with temp permissions
118
- setPermissions(tempPermissions);
119
93
  await onSave(tempPermissions);
120
94
  setHasUserInteracted(false);
121
95
  } finally {
@@ -481,6 +455,21 @@ export const PermissionForm: React.FC<PermissionFormProps> = ({ onClose }) => {
481
455
  `}>
482
456
  Loading permissions...
483
457
  </div>
458
+ ) : runtimePermissionsUnavailable ? (
459
+ <div css={css`
460
+ background-color: #fff4e5 !important;
461
+ padding: 16px !important;
462
+ border-radius: 8px !important;
463
+ border: 1px solid #ffb74d !important;
464
+ text-align: center !important;
465
+ color: #8a4b00 !important;
466
+ `}>
467
+ Permissions are unavailable. Retry to load the authoritative state.
468
+ <button type="button" onClick={() => refreshAIT()} css={css`
469
+ display: block !important;
470
+ margin: 12px auto 0 !important;
471
+ `}>Retry</button>
472
+ </div>
484
473
  ) : (
485
474
  <div css={css`
486
475
  background-color: #f8f9fa !important;
@@ -548,7 +537,7 @@ export const PermissionForm: React.FC<PermissionFormProps> = ({ onClose }) => {
548
537
  setIsDisabled(false);
549
538
  }
550
539
  }}
551
- disabled={isAITLoading || isOtherPermissionDisabled}
540
+ disabled={isAITLoading || runtimePermissionsUnavailable || isOtherPermissionDisabled}
552
541
  css={css`
553
542
  margin: 0 !important;
554
543
  width: 18px !important;
@@ -600,7 +589,7 @@ export const PermissionForm: React.FC<PermissionFormProps> = ({ onClose }) => {
600
589
  </button>
601
590
  <button
602
591
  onClick={handleSave}
603
- disabled={!hasPermissionChanges() || isSaving || isAITLoading}
592
+ disabled={!hasPermissionChanges() || isSaving || isAITLoading || runtimePermissionsUnavailable}
604
593
  css={css`
605
594
  padding: 10px 20px !important;
606
595
  background-color: ${!hasPermissionChanges() || isSaving || isAITLoading ? '#e9ecef' : '#007bff'} !important;
@@ -629,4 +618,4 @@ export const PermissionForm: React.FC<PermissionFormProps> = ({ onClose }) => {
629
618
  )}
630
619
  </div>
631
620
  );
632
- };
621
+ };
@@ -1,26 +0,0 @@
1
- import React from 'react';
2
- import type { NxtlinqAgentChatProps } from './types';
3
- /**
4
- * Drop-in React Web assistant UI wired to `@bytexbyte/nxtlinq-ai-agent-web-development`.
5
- *
6
- * @example
7
- * ```tsx
8
- * import { NxtlinqAgentChat } from '@bytexbyte/nxtlinq-ai-agent-ui-react-development';
9
- *
10
- * export default function Page() {
11
- * return (
12
- * <NxtlinqAgentChat
13
- * style={{ height: '100vh' }}
14
- * serviceId="..."
15
- * apiKey="..."
16
- * apiSecret="..."
17
- * environment="staging"
18
- * pseudoId={userId}
19
- * loadHistoryOnMount
20
- * />
21
- * );
22
- * }
23
- * ```
24
- */
25
- export declare function NxtlinqAgentChat({ title, placeholder, presetMessages, loadHistoryOnMount, historyLast, enableVoice, enableFileUpload, startInVoiceMode, startWithMicMuted, holdMicDuringAssistant, theme, style, headerStyle, onMessage, onError, onToolUse, children, fetchImpl, getTimezone, resetOnIdentityChange, ...agentConfig }: NxtlinqAgentChatProps): React.ReactElement;
26
- //# sourceMappingURL=NxtlinqAgentChat.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"NxtlinqAgentChat.d.ts","sourceRoot":"","sources":["../src/NxtlinqAgentChat.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,SAAS,CAAC;AAErD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,gBAAgB,CAAC,EAC/B,KAAK,EACL,WAAW,EACX,cAAc,EACd,kBAA0B,EAC1B,WAAW,EACX,WAAkB,EAClB,gBAAuB,EACvB,gBAAwB,EACxB,iBAAwB,EACxB,sBAA6B,EAC7B,KAAK,EACL,KAAK,EACL,WAAW,EACX,SAAS,EACT,OAAO,EACP,SAAS,EACT,QAAQ,EACR,SAAS,EACT,WAAW,EACX,qBAAqB,EACrB,GAAG,WAAW,EACf,EAAE,qBAAqB,GAAG,KAAK,CAAC,YAAY,CA6B5C"}
@@ -1,28 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "@emotion/react/jsx-runtime";
2
- import { NxtlinqAgentProvider } from '@bytexbyte/nxtlinq-ai-agent-web-development';
3
- import { AgentAssistantShell } from './components/AgentAssistantShell';
4
- /**
5
- * Drop-in React Web assistant UI wired to `@bytexbyte/nxtlinq-ai-agent-web-development`.
6
- *
7
- * @example
8
- * ```tsx
9
- * import { NxtlinqAgentChat } from '@bytexbyte/nxtlinq-ai-agent-ui-react-development';
10
- *
11
- * export default function Page() {
12
- * return (
13
- * <NxtlinqAgentChat
14
- * style={{ height: '100vh' }}
15
- * serviceId="..."
16
- * apiKey="..."
17
- * apiSecret="..."
18
- * environment="staging"
19
- * pseudoId={userId}
20
- * loadHistoryOnMount
21
- * />
22
- * );
23
- * }
24
- * ```
25
- */
26
- export function NxtlinqAgentChat({ title, placeholder, presetMessages, loadHistoryOnMount = false, historyLast, enableVoice = true, enableFileUpload = true, startInVoiceMode = false, startWithMicMuted = true, holdMicDuringAssistant = true, theme, style, headerStyle, onMessage, onError, onToolUse, children, fetchImpl, getTimezone, resetOnIdentityChange, ...agentConfig }) {
27
- return (_jsxs(NxtlinqAgentProvider, { fetchImpl: fetchImpl, getTimezone: getTimezone, resetOnIdentityChange: resetOnIdentityChange, onMessage: onMessage, onError: onError, onToolUse: onToolUse, ...agentConfig, children: [_jsx(AgentAssistantShell, { title: title, placeholder: placeholder, presetMessages: presetMessages, loadHistoryOnMount: loadHistoryOnMount, historyLast: historyLast, enableVoice: enableVoice, enableFileUpload: enableFileUpload, startInVoiceMode: startInVoiceMode, startWithMicMuted: startWithMicMuted, holdMicDuringAssistant: holdMicDuringAssistant, theme: theme, style: style, headerStyle: headerStyle }), children] }));
28
- }
@@ -1,5 +0,0 @@
1
- import React from 'react';
2
- import type { NxtlinqAgentChatProps } from '../types';
3
- export type AgentAssistantShellProps = Pick<NxtlinqAgentChatProps, 'title' | 'placeholder' | 'presetMessages' | 'enableVoice' | 'enableFileUpload' | 'theme' | 'style' | 'headerStyle' | 'loadHistoryOnMount' | 'historyLast' | 'startInVoiceMode' | 'startWithMicMuted' | 'holdMicDuringAssistant'>;
4
- export declare function AgentAssistantShell(props: AgentAssistantShellProps): React.ReactElement;
5
- //# sourceMappingURL=AgentAssistantShell.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"AgentAssistantShell.d.ts","sourceRoot":"","sources":["../../src/components/AgentAssistantShell.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsC,MAAM,OAAO,CAAC;AAK3D,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,UAAU,CAAC;AAOtD,MAAM,MAAM,wBAAwB,GAAG,IAAI,CACzC,qBAAqB,EACnB,OAAO,GACP,aAAa,GACb,gBAAgB,GAChB,aAAa,GACb,kBAAkB,GAClB,OAAO,GACP,OAAO,GACP,aAAa,GACb,oBAAoB,GACpB,aAAa,GACb,kBAAkB,GAClB,mBAAmB,GACnB,wBAAwB,CAC3B,CAAC;AA2DF,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,wBAAwB,GAAG,KAAK,CAAC,YAAY,CAiBvF"}
@@ -1,52 +0,0 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "@emotion/react/jsx-runtime";
2
- import { useEffect, useRef, useState } from 'react';
3
- import { AgentAssistantProvider, useAgentAssistant, } from '../context/AgentAssistantContext';
4
- import { AgentComposer } from './AgentComposer';
5
- import { AgentMessageList } from './AgentMessageList';
6
- import { AgentRemoteAudio } from './AgentRemoteAudio';
7
- import { AgentVoiceBar } from './AgentVoiceBar';
8
- import { PresetMessageChips } from './PresetMessageChips';
9
- function AgentAssistantInner({ title, headerStyle, style, loadHistoryOnMount, historyLast, startInVoiceMode, }) {
10
- const { theme, loadHistory, startVoice, isVoiceAvailable } = useAgentAssistant();
11
- const [historyReady, setHistoryReady] = useState(!loadHistoryOnMount);
12
- const voiceAutoStartRef = useRef(false);
13
- useEffect(() => {
14
- if (loadHistoryOnMount) {
15
- void loadHistory({ last: historyLast ?? 50 }).finally(() => setHistoryReady(true));
16
- }
17
- }, [loadHistory, loadHistoryOnMount, historyLast]);
18
- useEffect(() => {
19
- if (!startInVoiceMode || !isVoiceAvailable || voiceAutoStartRef.current)
20
- return;
21
- voiceAutoStartRef.current = true;
22
- void startVoice();
23
- }, [startInVoiceMode, isVoiceAvailable, startVoice]);
24
- return (_jsxs("div", { style: {
25
- display: 'flex',
26
- flexDirection: 'column',
27
- flex: 1,
28
- minHeight: 0,
29
- backgroundColor: theme.colors.background,
30
- ...style,
31
- }, children: [_jsx("header", { style: {
32
- padding: theme.spacing.md,
33
- borderBottom: `1px solid ${theme.colors.border}`,
34
- backgroundColor: theme.colors.surface,
35
- fontSize: theme.typography.titleSize,
36
- fontWeight: 600,
37
- color: theme.colors.assistantText,
38
- ...headerStyle,
39
- }, children: title ?? 'AI Assistant' }), _jsx(PresetMessageChips, {}), historyReady ? _jsx(AgentMessageList, {}) : _jsx("div", { style: { flex: 1 } }), _jsx(AgentVoiceBar, {}), _jsx(AgentComposer, {}), _jsx(AgentRemoteAudio, {})] }));
40
- }
41
- export function AgentAssistantShell(props) {
42
- return (_jsx(AgentAssistantProvider, { ui: {
43
- title: props.title,
44
- placeholder: props.placeholder,
45
- presetMessages: props.presetMessages,
46
- enableVoice: props.enableVoice,
47
- enableFileUpload: props.enableFileUpload,
48
- theme: props.theme,
49
- startWithMicMuted: props.startWithMicMuted,
50
- holdMicDuringAssistant: props.holdMicDuringAssistant,
51
- }, children: _jsx(AgentAssistantInner, { ...props }) }));
52
- }
@@ -1,3 +0,0 @@
1
- import React from 'react';
2
- export declare function AgentComposer(): React.ReactElement | null;
3
- //# sourceMappingURL=AgentComposer.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"AgentComposer.d.ts","sourceRoot":"","sources":["../../src/components/AgentComposer.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAC;AAG1B,wBAAgB,aAAa,IAAI,KAAK,CAAC,YAAY,GAAG,IAAI,CAkIzD"}