@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.
- package/dist/context/ChatBotContext.d.ts.map +1 -1
- package/dist/context/ChatBotContext.js +179 -160
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/permissionState.d.ts +53 -0
- package/dist/permissionState.d.ts.map +1 -0
- package/dist/permissionState.js +217 -0
- package/dist/types/ChatBotTypes.d.ts +6 -5
- package/dist/types/ChatBotTypes.d.ts.map +1 -1
- package/dist/ui/ModelSelector.js +2 -2
- package/dist/ui/PermissionForm.d.ts.map +1 -1
- package/dist/ui/PermissionForm.js +14 -28
- package/package.json +3 -3
- package/src/context/ChatBotContext.tsx +252 -195
- package/src/index.ts +0 -1
- package/src/permissionState.ts +313 -0
- package/src/types/ChatBotTypes.ts +7 -7
- package/src/ui/ModelSelector.tsx +5 -5
- package/src/ui/PermissionForm.tsx +20 -31
- package/dist/NxtlinqAgentChat.d.ts +0 -26
- package/dist/NxtlinqAgentChat.d.ts.map +0 -1
- package/dist/NxtlinqAgentChat.js +0 -28
- package/dist/components/AgentAssistantShell.d.ts +0 -5
- package/dist/components/AgentAssistantShell.d.ts.map +0 -1
- package/dist/components/AgentAssistantShell.js +0 -52
- package/dist/components/AgentComposer.d.ts +0 -3
- package/dist/components/AgentComposer.d.ts.map +0 -1
- package/dist/components/AgentComposer.js +0 -60
- package/dist/components/AgentMessageList.d.ts +0 -3
- package/dist/components/AgentMessageList.d.ts.map +0 -1
- package/dist/components/AgentMessageList.js +0 -37
- package/dist/components/AgentRemoteAudio.d.ts +0 -4
- package/dist/components/AgentRemoteAudio.d.ts.map +0 -1
- package/dist/components/AgentRemoteAudio.js +0 -34
- package/dist/components/AgentVoiceBar.d.ts +0 -3
- package/dist/components/AgentVoiceBar.d.ts.map +0 -1
- package/dist/components/AgentVoiceBar.js +0 -91
- package/dist/components/PresetMessageChips.d.ts +0 -3
- package/dist/components/PresetMessageChips.d.ts.map +0 -1
- package/dist/components/PresetMessageChips.js +0 -23
- package/dist/context/AgentAssistantContext.d.ts +0 -32
- package/dist/context/AgentAssistantContext.d.ts.map +0 -1
- package/dist/context/AgentAssistantContext.js +0 -179
- package/dist/legacy/assets/images/adiSideItalicDataUri.d.ts +0 -2
- package/dist/legacy/assets/images/adiSideItalicDataUri.d.ts.map +0 -1
- package/dist/legacy/assets/images/adiSideItalicDataUri.js +0 -1
- package/dist/legacy/chatbot/ChatBot.d.ts +0 -5
- package/dist/legacy/chatbot/ChatBot.d.ts.map +0 -1
- package/dist/legacy/chatbot/ChatBot.js +0 -35
- package/dist/legacy/chatbot/context/ChatBotContext.d.ts +0 -5
- package/dist/legacy/chatbot/context/ChatBotContext.d.ts.map +0 -1
- package/dist/legacy/chatbot/context/ChatBotContext.js +0 -2922
- package/dist/legacy/chatbot/types/ChatBotTypes.d.ts +0 -166
- package/dist/legacy/chatbot/types/ChatBotTypes.d.ts.map +0 -1
- package/dist/legacy/chatbot/types/ChatBotTypes.js +0 -1
- package/dist/legacy/chatbot/ui/BerifyMeModal.d.ts +0 -17
- package/dist/legacy/chatbot/ui/BerifyMeModal.d.ts.map +0 -1
- package/dist/legacy/chatbot/ui/BerifyMeModal.js +0 -110
- package/dist/legacy/chatbot/ui/ChatBotHeader.d.ts +0 -15
- package/dist/legacy/chatbot/ui/ChatBotHeader.d.ts.map +0 -1
- package/dist/legacy/chatbot/ui/ChatBotHeader.js +0 -62
- package/dist/legacy/chatbot/ui/ChatBotUI.d.ts +0 -3
- package/dist/legacy/chatbot/ui/ChatBotUI.d.ts.map +0 -1
- package/dist/legacy/chatbot/ui/ChatBotUI.js +0 -557
- package/dist/legacy/chatbot/ui/MessageInput.d.ts +0 -3
- package/dist/legacy/chatbot/ui/MessageInput.d.ts.map +0 -1
- package/dist/legacy/chatbot/ui/MessageInput.js +0 -321
- package/dist/legacy/chatbot/ui/MessageList.d.ts +0 -4
- package/dist/legacy/chatbot/ui/MessageList.d.ts.map +0 -1
- package/dist/legacy/chatbot/ui/MessageList.js +0 -455
- package/dist/legacy/chatbot/ui/ModelSelector.d.ts +0 -4
- package/dist/legacy/chatbot/ui/ModelSelector.d.ts.map +0 -1
- package/dist/legacy/chatbot/ui/ModelSelector.js +0 -122
- package/dist/legacy/chatbot/ui/NotificationModal.d.ts +0 -15
- package/dist/legacy/chatbot/ui/NotificationModal.d.ts.map +0 -1
- package/dist/legacy/chatbot/ui/NotificationModal.js +0 -53
- package/dist/legacy/chatbot/ui/PermissionForm.d.ts +0 -8
- package/dist/legacy/chatbot/ui/PermissionForm.d.ts.map +0 -1
- package/dist/legacy/chatbot/ui/PermissionForm.js +0 -465
- package/dist/legacy/chatbot/ui/PresetMessages.d.ts +0 -4
- package/dist/legacy/chatbot/ui/PresetMessages.d.ts.map +0 -1
- package/dist/legacy/chatbot/ui/PresetMessages.js +0 -33
- package/dist/legacy/chatbot/ui/VoiceModePanel.d.ts +0 -3
- package/dist/legacy/chatbot/ui/VoiceModePanel.d.ts.map +0 -1
- package/dist/legacy/chatbot/ui/VoiceModePanel.js +0 -95
- package/dist/legacy/chatbot/ui/chatBotHeaderParts.d.ts +0 -15
- package/dist/legacy/chatbot/ui/chatBotHeaderParts.d.ts.map +0 -1
- package/dist/legacy/chatbot/ui/chatBotHeaderParts.js +0 -50
- package/dist/legacy/chatbot/ui/styles/isolatedStyles.d.ts +0 -73
- package/dist/legacy/chatbot/ui/styles/isolatedStyles.d.ts.map +0 -1
- package/dist/legacy/chatbot/ui/styles/isolatedStyles.js +0 -985
- package/dist/legacy/index.d.ts +0 -14
- package/dist/legacy/index.d.ts.map +0 -1
- package/dist/legacy/index.js +0 -12
- package/dist/theme/defaultTheme.d.ts +0 -3
- package/dist/theme/defaultTheme.d.ts.map +0 -1
- package/dist/theme/defaultTheme.js +0 -20
- package/dist/types.d.ts +0 -62
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -1
- package/dist/voice/useVoiceConnectOrchestration.d.ts +0 -21
- package/dist/voice/useVoiceConnectOrchestration.d.ts.map +0 -1
- package/dist/voice/useVoiceConnectOrchestration.js +0 -86
- package/dist/voice/useVoiceMicState.d.ts +0 -15
- package/dist/voice/useVoiceMicState.d.ts.map +0 -1
- package/dist/voice/useVoiceMicState.js +0 -94
- package/dist/voice/useVoiceSilenceCommit.d.ts +0 -10
- package/dist/voice/useVoiceSilenceCommit.d.ts.map +0 -1
- package/dist/voice/useVoiceSilenceCommit.js +0 -67
- package/dist/voice/useVoiceTranscriptMessages.d.ts +0 -18
- package/dist/voice/useVoiceTranscriptMessages.d.ts.map +0 -1
- package/dist/voice/useVoiceTranscriptMessages.js +0 -132
- package/dist/voice/useWsRealtimeAudio.d.ts +0 -18
- package/dist/voice/useWsRealtimeAudio.d.ts.map +0 -1
- package/dist/voice/useWsRealtimeAudio.js +0 -102
- package/dist/voice/voiceMicConstants.d.ts +0 -4
- package/dist/voice/voiceMicConstants.d.ts.map +0 -1
- package/dist/voice/voiceMicConstants.js +0 -10
- package/dist/voice/voiceUserBubble.d.ts +0 -10
- package/dist/voice/voiceUserBubble.d.ts.map +0 -1
- package/dist/voice/voiceUserBubble.js +0 -52
- package/dist/voice/ws/BrowserWsPcmPlayer.d.ts +0 -23
- package/dist/voice/ws/BrowserWsPcmPlayer.d.ts.map +0 -1
- package/dist/voice/ws/BrowserWsPcmPlayer.js +0 -137
- package/dist/voice/ws/BrowserWsPcmRecorder.d.ts +0 -17
- package/dist/voice/ws/BrowserWsPcmRecorder.d.ts.map +0 -1
- package/dist/voice/ws/BrowserWsPcmRecorder.js +0 -71
- package/dist/voice/ws/float32ToPcm16.d.ts +0 -2
- package/dist/voice/ws/float32ToPcm16.d.ts.map +0 -1
- package/dist/voice/ws/float32ToPcm16.js +0 -8
- package/dist/voice/ws/voiceSilenceConstants.d.ts +0 -5
- package/dist/voice/ws/voiceSilenceConstants.d.ts.map +0 -1
- package/dist/voice/ws/voiceSilenceConstants.js +0 -4
- package/dist/voice/ws/wsRealtimeConstants.d.ts +0 -2
- package/dist/voice/ws/wsRealtimeConstants.d.ts.map +0 -1
- 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
|
+
}
|
package/src/ui/ModelSelector.tsx
CHANGED
|
@@ -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
|
-
|
|
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"}
|
package/dist/NxtlinqAgentChat.js
DELETED
|
@@ -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 +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"}
|