@vanira/sdk-react-native 0.0.2
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/README.md +239 -0
- package/package.json +53 -0
- package/src/__tests__/WebRTCClient.integration.test.ts +396 -0
- package/src/__tests__/adapters.test.ts +475 -0
- package/src/__tests__/httpResponse.test.ts +25 -0
- package/src/__tests__/mocks/react-native-incall-manager.ts +8 -0
- package/src/__tests__/mocks/react-native-permissions.ts +15 -0
- package/src/__tests__/mocks/react-native-webrtc.ts +6 -0
- package/src/__tests__/mocks/react-native.ts +28 -0
- package/src/__tests__/preset.test.ts +239 -0
- package/src/__tests__/resolveRuntimeConfig.test.ts +90 -0
- package/src/__tests__/storage.test.ts +211 -0
- package/src/__tests__/webrtcSignaling.test.ts +42 -0
- package/src/adapters/PeerConnectionAdapter.ts +101 -0
- package/src/adapters/browser/BrowserAudioAdapter.ts +43 -0
- package/src/adapters/browser/BrowserDataChannelAdapter.ts +69 -0
- package/src/adapters/browser/BrowserMediaAdapter.ts +15 -0
- package/src/adapters/browser/BrowserPeerAdapter.ts +14 -0
- package/src/adapters/browser/index.ts +4 -0
- package/src/adapters/interfaces.ts +84 -0
- package/src/adapters/react-native/RNAudioAdapter.ts +42 -0
- package/src/adapters/react-native/RNDataChannelAdapter.ts +79 -0
- package/src/adapters/react-native/RNMediaAdapter.ts +46 -0
- package/src/adapters/react-native/RNPeerAdapter.ts +28 -0
- package/src/adapters/react-native/callAudioRouting.ts +115 -0
- package/src/adapters/react-native/decodeUtf8.ts +72 -0
- package/src/adapters/react-native/index.ts +4 -0
- package/src/adapters/react-native/rnUploadFile.ts +76 -0
- package/src/adapters/storage/BrowserDualStorageAdapter.ts +71 -0
- package/src/adapters/storage/MemoryStorageAdapter.ts +50 -0
- package/src/adapters/storage/StorageAdapter.ts +21 -0
- package/src/adapters/storage/createSyncStorageAdapter.ts +40 -0
- package/src/adapters/storage/index.ts +7 -0
- package/src/api/services/ChatService.ts +304 -0
- package/src/api/services/ConfigService.ts +33 -0
- package/src/assets/icons.js +35 -0
- package/src/cdn.ts +68 -0
- package/src/core/CallSessionStore.ts +137 -0
- package/src/core/DraggableController.ts +83 -0
- package/src/core/SessionManager.ts +322 -0
- package/src/core/VaniraAI.ts +464 -0
- package/src/core/WebRTCClient.ts +1012 -0
- package/src/core/httpResponse.ts +22 -0
- package/src/core/iceServers.ts +18 -0
- package/src/core/toolCallNormalize.ts +80 -0
- package/src/core/voice-client.js +236 -0
- package/src/core/webrtcSignaling.ts +72 -0
- package/src/index.js +34 -0
- package/src/index.ts +6 -0
- package/src/platforms/browser.ts +67 -0
- package/src/platforms/react-native.ts +105 -0
- package/src/presets/BookingCalendarModal.tsx +457 -0
- package/src/presets/CameraModal.tsx +576 -0
- package/src/presets/DynamicFormModal.tsx +378 -0
- package/src/presets/NativePresetRenderer.tsx +350 -0
- package/src/presets/NavigateHandler.tsx +75 -0
- package/src/presets/PresetHost.tsx +155 -0
- package/src/presets/PresetShellModal.tsx +97 -0
- package/src/presets/UploadModal.tsx +321 -0
- package/src/presets/calendar/calendarUtils.ts +386 -0
- package/src/presets/call/CallSpeakerToggle.tsx +59 -0
- package/src/presets/call/callAudioRouting.ts +2 -0
- package/src/presets/call/useCallSpeaker.ts +31 -0
- package/src/presets/camera/cameraPermissions.ts +18 -0
- package/src/presets/camera/cameraStream.ts +19 -0
- package/src/presets/camera/cameraUtils.ts +21 -0
- package/src/presets/camera/useLivenessFlow.ts +95 -0
- package/src/presets/chalkboard/ChalkboardOverlay.tsx +156 -0
- package/src/presets/chalkboard/EraseTextHandler.tsx +95 -0
- package/src/presets/chalkboard/TypeTextHandler.tsx +107 -0
- package/src/presets/chalkboard/boardAbort.ts +36 -0
- package/src/presets/chalkboard/boardQueue.ts +620 -0
- package/src/presets/chalkboard/chalkboardSession.ts +75 -0
- package/src/presets/chalkboard/drawUtils.ts +123 -0
- package/src/presets/chalkboard/textUtils.ts +109 -0
- package/src/presets/clipRegion/ClipRegionModal.tsx +261 -0
- package/src/presets/clipRegion/clipRegionBridge.ts +19 -0
- package/src/presets/form/formValidation.ts +104 -0
- package/src/presets/form/parseFormFields.ts +171 -0
- package/src/presets/host/HostElementPresetHandler.tsx +155 -0
- package/src/presets/host/hostPresetBridge.ts +71 -0
- package/src/presets/index.ts +63 -0
- package/src/presets/liveScreen/CloseLiveScreenHandler.tsx +36 -0
- package/src/presets/liveScreen/LiveScreenCaptureHost.tsx +312 -0
- package/src/presets/liveScreen/LiveScreenHandler.tsx +25 -0
- package/src/presets/liveScreen/LiveScreenPipOverlay.tsx +6 -0
- package/src/presets/liveScreen/liveScreenSession.ts +73 -0
- package/src/presets/liveVision/CloseLiveVisionHandler.tsx +29 -0
- package/src/presets/liveVision/LiveVisionCameraHost.tsx +317 -0
- package/src/presets/liveVision/LiveVisionHandler.tsx +26 -0
- package/src/presets/liveVision/LiveVisionPipOverlay.tsx +7 -0
- package/src/presets/liveVision/liveVisionFrameLoop.ts +38 -0
- package/src/presets/liveVision/liveVisionSession.ts +75 -0
- package/src/presets/liveVision/liveVisionUpload.ts +62 -0
- package/src/presets/navigation/internalRouteRegistry.ts +25 -0
- package/src/presets/navigation/navigationBridge.ts +76 -0
- package/src/presets/navigation/navigationTypes.ts +12 -0
- package/src/presets/parseToolCall.ts +60 -0
- package/src/presets/presetClientAdapter.ts +29 -0
- package/src/presets/presetCompletion.ts +91 -0
- package/src/presets/presetEventHelpers.ts +45 -0
- package/src/presets/registry.ts +128 -0
- package/src/presets/streaming/mediaFrameUpload.ts +93 -0
- package/src/presets/types.ts +74 -0
- package/src/presets/upload/pickUploadFile.ts +256 -0
- package/src/presets/upload/uploadFormats.ts +163 -0
- package/src/presets/upload/uploadUtils.ts +68 -0
- package/src/react/PresetRenderer.tsx +144 -0
- package/src/react/index.ts +1 -0
- package/src/runtime/browserRuntime.ts +54 -0
- package/src/runtime/platform.ts +17 -0
- package/src/runtime/reactNativeRuntime.ts +68 -0
- package/src/runtime/resolveRuntimeConfig.ts +75 -0
- package/src/runtime/runtimeBundles.ts +74 -0
- package/src/runtime/types.ts +135 -0
- package/src/types/react-native-incall-manager.d.ts +17 -0
- package/src/types/react-native-webrtc.d.ts +47 -0
- package/src/types.ts +133 -0
- package/src/ui/VaniraWidget.ts +87 -0
- package/src/ui/abstraction/AbstractWidgetProvider.ts +18 -0
- package/src/ui/abstraction/interfaces.ts +12 -0
- package/src/ui/adapters/VaniraChatAdapter.ts +42 -0
- package/src/ui/components/AvatarView.ts +81 -0
- package/src/ui/components/ChatWindow.ts +263 -0
- package/src/ui/components/FloatingButton.ts +163 -0
- package/src/ui/components/FloatingWelcomeChips.ts +137 -0
- package/src/ui/components/Panel.ts +120 -0
- package/src/ui/components/VoiceOrb.ts +79 -0
- package/src/ui/components/VoiceOverlay.ts +497 -0
- package/src/ui/components/index.ts +7 -0
- package/src/ui/factory/WidgetFactory.ts +16 -0
- package/src/ui/icons_data.ts +2 -0
- package/src/ui/presets/WidgetPresetRenderer.ts +1802 -0
- package/src/ui/presets/types.ts +16 -0
- package/src/ui/providers/VaniraInternalProvider.ts +1066 -0
- package/src/ui/styles/index.ts +323 -0
- package/src/ui/styles/keyframes.ts +76 -0
- package/src/ui/styles/theme.ts +57 -0
- package/src/ui/styles/widget.css.ts +838 -0
- package/src/ui/utils.ts +37 -0
- package/src/ui/views/AbstractChatView.ts +93 -0
- package/src/ui/views/AbstractVoiceView.ts +57 -0
- package/src/ui/views/AvatarOnlyView.ts +78 -0
- package/src/ui/views/ChatAvatarView.ts +66 -0
- package/src/ui/views/ChatOnlyView.ts +28 -0
- package/src/ui/views/ChatVoiceView.ts +15 -0
- package/src/ui/views/VoiceOnlyView.ts +25 -0
- package/src/ui/views/index.ts +5 -0
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type {VaniraAI} from '../core/VaniraAI';
|
|
2
|
+
import type {PresetClient} from './types';
|
|
3
|
+
|
|
4
|
+
/** Map VaniraAI public API → PresetClient (web PresetRenderer contract). */
|
|
5
|
+
export function toPresetClient(ai: VaniraAI | null): PresetClient | null {
|
|
6
|
+
if (!ai) {
|
|
7
|
+
return null;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
return {
|
|
11
|
+
sendToolResult: (toolCallId, result) => ai.sendToolResult(toolCallId, result),
|
|
12
|
+
sendToolError: (toolCallId, error) => ai.sendToolError(toolCallId, error),
|
|
13
|
+
sendContextUpdate: data => ai.updateContext(data),
|
|
14
|
+
triggerActionInterrupt: () => ai.interruptAudioOnly(),
|
|
15
|
+
sendActionTrigger: (actionName, data) => {
|
|
16
|
+
ai.sendEvent('client_action_trigger', {
|
|
17
|
+
data: {
|
|
18
|
+
action_name: actionName,
|
|
19
|
+
data,
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
},
|
|
23
|
+
uploadMedia: (file, reason, message) =>
|
|
24
|
+
ai.uploadMedia(file, reason, message),
|
|
25
|
+
sendEvent: (event, payload) => ai.sendEvent(event, payload ?? {}),
|
|
26
|
+
serverUrl: ai.serverUrl,
|
|
27
|
+
callId: ai.callId,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import type {PresetClient} from './types';
|
|
2
|
+
import type {PresetId} from './types';
|
|
3
|
+
|
|
4
|
+
/** Web PresetRenderer.tsx onComplete wrapper (calendar uses sendActionTrigger). */
|
|
5
|
+
export function completePreset(
|
|
6
|
+
client: PresetClient | null,
|
|
7
|
+
presetId: PresetId,
|
|
8
|
+
toolCallId: string,
|
|
9
|
+
clientFields: Record<string, unknown>,
|
|
10
|
+
payload: Record<string, unknown>,
|
|
11
|
+
toolName?: string,
|
|
12
|
+
): void {
|
|
13
|
+
if (!client) {
|
|
14
|
+
return;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
if (payload.media_id || payload.url) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (
|
|
22
|
+
presetId === 'vanira_type_text' ||
|
|
23
|
+
presetId === 'vanira_erase_text' ||
|
|
24
|
+
presetId === 'vanira_draw'
|
|
25
|
+
) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
if (presetId === 'vanira_calendar') {
|
|
30
|
+
client.triggerActionInterrupt?.();
|
|
31
|
+
const actionName = String(
|
|
32
|
+
clientFields.action_name || 'calendar_slot_selected',
|
|
33
|
+
);
|
|
34
|
+
client.sendActionTrigger?.(actionName, payload);
|
|
35
|
+
return;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (presetId === 'vanira_form') {
|
|
39
|
+
client.triggerActionInterrupt?.();
|
|
40
|
+
const actionName = String(
|
|
41
|
+
clientFields.action_name ||
|
|
42
|
+
`user_submitted_${toolName || 'collect_user_data'}`,
|
|
43
|
+
);
|
|
44
|
+
client.sendActionTrigger?.(actionName, payload);
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
if (presetId === 'vanira_navigate') {
|
|
49
|
+
client.triggerActionInterrupt?.();
|
|
50
|
+
const actionName = String(
|
|
51
|
+
clientFields.action_name ||
|
|
52
|
+
`user_submitted_${toolName || 'navigate_user'}`,
|
|
53
|
+
);
|
|
54
|
+
client.sendActionTrigger?.(actionName, payload);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
if (toolCallId) {
|
|
59
|
+
client.sendToolResult(toolCallId, payload);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/** Web PresetRenderer.tsx onCancel wrapper. */
|
|
64
|
+
export function cancelPreset(
|
|
65
|
+
client: PresetClient | null,
|
|
66
|
+
presetId: PresetId,
|
|
67
|
+
toolCallId: string,
|
|
68
|
+
reason?: string,
|
|
69
|
+
): void {
|
|
70
|
+
if (!client || !toolCallId) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
if (
|
|
75
|
+
presetId === 'vanira_type_text' ||
|
|
76
|
+
presetId === 'vanira_erase_text' ||
|
|
77
|
+
presetId === 'vanira_draw'
|
|
78
|
+
) {
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const message = reason || 'User cancelled the action';
|
|
83
|
+
if (client.sendToolError) {
|
|
84
|
+
client.sendToolError(toolCallId, message);
|
|
85
|
+
} else {
|
|
86
|
+
client.sendToolResult(toolCallId, {
|
|
87
|
+
status: 'cancelled',
|
|
88
|
+
reason: message,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type {ClientToolCall} from '../core/VaniraAI';
|
|
2
|
+
import {parseToolCall} from './parseToolCall';
|
|
3
|
+
|
|
4
|
+
type RawToolCall = {
|
|
5
|
+
name?: string;
|
|
6
|
+
tool_name?: string;
|
|
7
|
+
arguments?: Record<string, unknown>;
|
|
8
|
+
args?: Record<string, unknown>;
|
|
9
|
+
client_fields?: Record<string, unknown>;
|
|
10
|
+
tool_call_id?: string;
|
|
11
|
+
call_id?: string;
|
|
12
|
+
execution_mode?: string;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
function normalizeRawToolCall(raw: unknown): RawToolCall {
|
|
16
|
+
if (!raw || typeof raw !== 'object') {
|
|
17
|
+
return {};
|
|
18
|
+
}
|
|
19
|
+
let data = (raw as {data?: RawToolCall}).data ?? (raw as RawToolCall);
|
|
20
|
+
const nested = (data as {tool_call?: RawToolCall}).tool_call;
|
|
21
|
+
if (nested && typeof nested === 'object') {
|
|
22
|
+
data = nested;
|
|
23
|
+
}
|
|
24
|
+
return data;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function extractPresetId(toolCall: unknown): string | undefined {
|
|
28
|
+
return parseToolCall(toolCall)?.presetId;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function extractToolName(toolCall: unknown): string {
|
|
32
|
+
const data = normalizeRawToolCall(toolCall);
|
|
33
|
+
const name = data.name ?? data.tool_name;
|
|
34
|
+
return typeof name === 'string' ? name : '';
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function toClientToolCallPayload(toolCall: ClientToolCall) {
|
|
38
|
+
return {
|
|
39
|
+
name: toolCall.name,
|
|
40
|
+
arguments: toolCall.arguments,
|
|
41
|
+
tool_call_id: toolCall.tool_call_id,
|
|
42
|
+
execution_mode: toolCall.execution_mode,
|
|
43
|
+
client_fields: toolCall.client_fields,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
/** Single source of truth for built-in client preset IDs (web parity). */
|
|
2
|
+
export const VaniraPresetId = {
|
|
3
|
+
Form: 'vanira_form',
|
|
4
|
+
Calendar: 'vanira_calendar',
|
|
5
|
+
Navigate: 'vanira_navigate',
|
|
6
|
+
Upload: 'vanira_upload',
|
|
7
|
+
Camera: 'vanira_camera',
|
|
8
|
+
HighlightElement: 'vanira_highlight_element',
|
|
9
|
+
ClickElement: 'vanira_click_element',
|
|
10
|
+
SelectOption: 'vanira_select_option',
|
|
11
|
+
SetDate: 'vanira_set_date',
|
|
12
|
+
TypeText: 'vanira_type_text',
|
|
13
|
+
EraseText: 'vanira_erase_text',
|
|
14
|
+
Draw: 'vanira_draw',
|
|
15
|
+
LiveVision: 'vanira_live_vision',
|
|
16
|
+
CloseLiveCamera: 'vanira_close_live_camera',
|
|
17
|
+
LiveScreen: 'vanira_live_screen',
|
|
18
|
+
CloseLiveScreen: 'vanira_close_live_screen',
|
|
19
|
+
ClipRegion: 'vanira_clip_region',
|
|
20
|
+
} as const;
|
|
21
|
+
|
|
22
|
+
export type VaniraPresetIdValue =
|
|
23
|
+
(typeof VaniraPresetId)[keyof typeof VaniraPresetId];
|
|
24
|
+
|
|
25
|
+
export const VANIRA_PRESET_IDS: readonly VaniraPresetIdValue[] =
|
|
26
|
+
Object.values(VaniraPresetId);
|
|
27
|
+
|
|
28
|
+
const presetIdSet = new Set<string>(VANIRA_PRESET_IDS);
|
|
29
|
+
|
|
30
|
+
export const FIRE_AND_FORGET_PRESET_IDS = new Set<VaniraPresetIdValue>([
|
|
31
|
+
VaniraPresetId.Camera,
|
|
32
|
+
VaniraPresetId.LiveVision,
|
|
33
|
+
VaniraPresetId.LiveScreen,
|
|
34
|
+
]);
|
|
35
|
+
|
|
36
|
+
export const NON_INTERACTIVE_PRESET_IDS = new Set<VaniraPresetIdValue>([
|
|
37
|
+
VaniraPresetId.Navigate,
|
|
38
|
+
VaniraPresetId.HighlightElement,
|
|
39
|
+
VaniraPresetId.ClickElement,
|
|
40
|
+
VaniraPresetId.SelectOption,
|
|
41
|
+
VaniraPresetId.SetDate,
|
|
42
|
+
VaniraPresetId.TypeText,
|
|
43
|
+
VaniraPresetId.EraseText,
|
|
44
|
+
VaniraPresetId.Draw,
|
|
45
|
+
VaniraPresetId.LiveVision,
|
|
46
|
+
VaniraPresetId.CloseLiveCamera,
|
|
47
|
+
VaniraPresetId.LiveScreen,
|
|
48
|
+
VaniraPresetId.CloseLiveScreen,
|
|
49
|
+
]);
|
|
50
|
+
|
|
51
|
+
export const BOARD_QUEUED_PRESET_IDS = new Set<VaniraPresetIdValue>([
|
|
52
|
+
VaniraPresetId.TypeText,
|
|
53
|
+
VaniraPresetId.EraseText,
|
|
54
|
+
VaniraPresetId.Draw,
|
|
55
|
+
]);
|
|
56
|
+
|
|
57
|
+
export const TOOL_NAME_TO_PRESET_ID: Record<string, VaniraPresetIdValue> = {
|
|
58
|
+
vanira_calendar: VaniraPresetId.Calendar,
|
|
59
|
+
display_booking_calendar: VaniraPresetId.Calendar,
|
|
60
|
+
vanira_form: VaniraPresetId.Form,
|
|
61
|
+
collect_user_data: VaniraPresetId.Form,
|
|
62
|
+
open_form_to_collect_user_data: VaniraPresetId.Form,
|
|
63
|
+
vanira_camera: VaniraPresetId.Camera,
|
|
64
|
+
open_camera: VaniraPresetId.Camera,
|
|
65
|
+
vanira_upload: VaniraPresetId.Upload,
|
|
66
|
+
request_file_upload: VaniraPresetId.Upload,
|
|
67
|
+
navigate_user: VaniraPresetId.Navigate,
|
|
68
|
+
highlight_ui_element: VaniraPresetId.HighlightElement,
|
|
69
|
+
click_element: VaniraPresetId.ClickElement,
|
|
70
|
+
click_ui_element: VaniraPresetId.ClickElement,
|
|
71
|
+
select_option: VaniraPresetId.SelectOption,
|
|
72
|
+
select_dropdown_option: VaniraPresetId.SelectOption,
|
|
73
|
+
set_date: VaniraPresetId.SetDate,
|
|
74
|
+
set_input_date: VaniraPresetId.SetDate,
|
|
75
|
+
type_in_input: VaniraPresetId.TypeText,
|
|
76
|
+
write_on_white_board: VaniraPresetId.TypeText,
|
|
77
|
+
erase_text: VaniraPresetId.EraseText,
|
|
78
|
+
draw_on_board: VaniraPresetId.Draw,
|
|
79
|
+
draw_shapes: VaniraPresetId.Draw,
|
|
80
|
+
open_live_camera: VaniraPresetId.LiveVision,
|
|
81
|
+
close_live_camera: VaniraPresetId.CloseLiveCamera,
|
|
82
|
+
open_live_screen: VaniraPresetId.LiveScreen,
|
|
83
|
+
share_screen: VaniraPresetId.LiveScreen,
|
|
84
|
+
close_live_screen: VaniraPresetId.CloseLiveScreen,
|
|
85
|
+
clip_region: VaniraPresetId.ClipRegion,
|
|
86
|
+
clip_page_region: VaniraPresetId.ClipRegion,
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
export function isVaniraPresetId(
|
|
90
|
+
value: string | undefined | null,
|
|
91
|
+
): value is VaniraPresetIdValue {
|
|
92
|
+
return !!value && presetIdSet.has(value);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function isNonInteractivePreset(value: string | undefined | null): boolean {
|
|
96
|
+
return isVaniraPresetId(value) && NON_INTERACTIVE_PRESET_IDS.has(value);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export function isBoardQueuedPreset(
|
|
100
|
+
value: string | undefined | null,
|
|
101
|
+
): value is VaniraPresetIdValue {
|
|
102
|
+
return isVaniraPresetId(value) && BOARD_QUEUED_PRESET_IDS.has(value);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function isFireAndForgetPreset(
|
|
106
|
+
value: string | undefined | null,
|
|
107
|
+
): boolean {
|
|
108
|
+
return isVaniraPresetId(value) && FIRE_AND_FORGET_PRESET_IDS.has(value);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export function resolvePresetId(
|
|
112
|
+
clientFields?: Record<string, unknown> | null,
|
|
113
|
+
args?: Record<string, unknown> | null,
|
|
114
|
+
toolName?: string,
|
|
115
|
+
): VaniraPresetIdValue | undefined {
|
|
116
|
+
const fromFields = clientFields?.preset_id;
|
|
117
|
+
if (typeof fromFields === 'string' && isVaniraPresetId(fromFields)) {
|
|
118
|
+
return fromFields;
|
|
119
|
+
}
|
|
120
|
+
const fromArgs = args?.preset_id;
|
|
121
|
+
if (typeof fromArgs === 'string' && isVaniraPresetId(fromArgs)) {
|
|
122
|
+
return fromArgs;
|
|
123
|
+
}
|
|
124
|
+
if (toolName && TOOL_NAME_TO_PRESET_ID[toolName]) {
|
|
125
|
+
return TOOL_NAME_TO_PRESET_ID[toolName];
|
|
126
|
+
}
|
|
127
|
+
return undefined;
|
|
128
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import type {PresetClient} from '../types';
|
|
2
|
+
|
|
3
|
+
export function resolveUploadBase(serverUrl: string): string {
|
|
4
|
+
if (!serverUrl) {
|
|
5
|
+
return '';
|
|
6
|
+
}
|
|
7
|
+
try {
|
|
8
|
+
return new URL(serverUrl).origin;
|
|
9
|
+
} catch {
|
|
10
|
+
return serverUrl.replace(/\/webrtc.*$/, '').replace(/\/$/, '');
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export async function uploadStreamingFrame(
|
|
15
|
+
client: PresetClient,
|
|
16
|
+
sessionId: string,
|
|
17
|
+
frameUri: string,
|
|
18
|
+
reason: string,
|
|
19
|
+
): Promise<{media_id: string; url: string}> {
|
|
20
|
+
const uploadBase = resolveUploadBase(client.serverUrl ?? '');
|
|
21
|
+
const callId = client.callId ?? '';
|
|
22
|
+
const uploadUrl = `${uploadBase}/media/upload`;
|
|
23
|
+
|
|
24
|
+
const form = new FormData();
|
|
25
|
+
form.append('file', {
|
|
26
|
+
uri: frameUri,
|
|
27
|
+
type: 'image/jpeg',
|
|
28
|
+
name: `frame_${sessionId}.jpg`,
|
|
29
|
+
} as unknown as Blob);
|
|
30
|
+
form.append('call_id', callId);
|
|
31
|
+
form.append('reason', reason);
|
|
32
|
+
|
|
33
|
+
const res = await fetch(uploadUrl, {method: 'POST', body: form});
|
|
34
|
+
if (!res.ok) {
|
|
35
|
+
throw new Error(`Upload HTTP ${res.status}`);
|
|
36
|
+
}
|
|
37
|
+
const data = (await res.json()) as {media_id?: string; url?: string};
|
|
38
|
+
if (!data.media_id || !data.url) {
|
|
39
|
+
throw new Error('Upload response missing media_id/url');
|
|
40
|
+
}
|
|
41
|
+
return {media_id: data.media_id, url: data.url};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function sendMediaFrameEvent(
|
|
45
|
+
client: PresetClient,
|
|
46
|
+
sessionId: string,
|
|
47
|
+
frameSeq: number,
|
|
48
|
+
media_id: string,
|
|
49
|
+
media_url: string,
|
|
50
|
+
reason: string,
|
|
51
|
+
extra?: Record<string, unknown>,
|
|
52
|
+
): void {
|
|
53
|
+
client.sendEvent?.('client_media_frame', {
|
|
54
|
+
data: {
|
|
55
|
+
session_id: sessionId,
|
|
56
|
+
frame_seq: frameSeq,
|
|
57
|
+
media_id,
|
|
58
|
+
media_url,
|
|
59
|
+
content_type: 'image/jpeg',
|
|
60
|
+
reason,
|
|
61
|
+
...extra,
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export async function captureAndSendStreamingFrame(
|
|
67
|
+
client: PresetClient,
|
|
68
|
+
sessionId: string,
|
|
69
|
+
frameUri: string,
|
|
70
|
+
reason: string,
|
|
71
|
+
frameSeq: number,
|
|
72
|
+
isSessionActive: () => boolean,
|
|
73
|
+
extra?: Record<string, unknown>,
|
|
74
|
+
): Promise<number> {
|
|
75
|
+
if (!isSessionActive()) {
|
|
76
|
+
return frameSeq;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const {media_id, url} = await uploadStreamingFrame(
|
|
80
|
+
client,
|
|
81
|
+
sessionId,
|
|
82
|
+
frameUri,
|
|
83
|
+
reason,
|
|
84
|
+
);
|
|
85
|
+
|
|
86
|
+
if (!isSessionActive()) {
|
|
87
|
+
return frameSeq;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const nextSeq = frameSeq + 1;
|
|
91
|
+
sendMediaFrameEvent(client, sessionId, nextSeq, media_id, url, reason, extra);
|
|
92
|
+
return nextSeq;
|
|
93
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared preset types for RN native UI layer.
|
|
3
|
+
* Payload shapes mirror WidgetPresetRenderer PresetContext + web tool_call normalization.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
VaniraPresetId,
|
|
8
|
+
type VaniraPresetIdValue,
|
|
9
|
+
VANIRA_PRESET_IDS,
|
|
10
|
+
} from './registry';
|
|
11
|
+
|
|
12
|
+
export type PresetId = VaniraPresetIdValue;
|
|
13
|
+
|
|
14
|
+
export const KNOWN_PRESET_IDS: PresetId[] = [...VANIRA_PRESET_IDS];
|
|
15
|
+
|
|
16
|
+
/** Mirrors WidgetPresetRenderer knownPresets in PresetRenderer.tsx (interactive popup subset). */
|
|
17
|
+
export const PRESET_RENDERER_KNOWN_PRESETS = [
|
|
18
|
+
VaniraPresetId.Form,
|
|
19
|
+
VaniraPresetId.Calendar,
|
|
20
|
+
VaniraPresetId.Navigate,
|
|
21
|
+
VaniraPresetId.Upload,
|
|
22
|
+
VaniraPresetId.Camera,
|
|
23
|
+
VaniraPresetId.HighlightElement,
|
|
24
|
+
VaniraPresetId.ClickElement,
|
|
25
|
+
VaniraPresetId.SelectOption,
|
|
26
|
+
VaniraPresetId.SetDate,
|
|
27
|
+
VaniraPresetId.TypeText,
|
|
28
|
+
VaniraPresetId.EraseText,
|
|
29
|
+
VaniraPresetId.Draw,
|
|
30
|
+
VaniraPresetId.ClipRegion,
|
|
31
|
+
] as const;
|
|
32
|
+
|
|
33
|
+
export type ParsedToolCall = {
|
|
34
|
+
raw: unknown;
|
|
35
|
+
name: string;
|
|
36
|
+
toolCallId: string;
|
|
37
|
+
arguments: Record<string, unknown>;
|
|
38
|
+
clientFields: Record<string, unknown>;
|
|
39
|
+
presetId?: string;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export type PresetContext = {
|
|
43
|
+
toolCallId: string;
|
|
44
|
+
presetId: PresetId;
|
|
45
|
+
clientFields: Record<string, unknown>;
|
|
46
|
+
args: Record<string, unknown>;
|
|
47
|
+
toolCall: unknown;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export type PresetClient = {
|
|
51
|
+
sendToolResult: (toolCallId: string, result: Record<string, unknown>) => void;
|
|
52
|
+
sendToolError: (toolCallId: string, error: string) => void;
|
|
53
|
+
sendContextUpdate?: (data: Record<string, unknown>) => void;
|
|
54
|
+
triggerActionInterrupt?: () => void;
|
|
55
|
+
sendActionTrigger?: (actionName: string, data: Record<string, unknown>) => void;
|
|
56
|
+
uploadMedia?: (
|
|
57
|
+
file: Blob | {uri: string; type: string; name: string},
|
|
58
|
+
reason?: string,
|
|
59
|
+
message?: string,
|
|
60
|
+
) => Promise<{media_id: string; url: string}>;
|
|
61
|
+
sendEvent?: (event: string, payload?: Record<string, unknown>) => void;
|
|
62
|
+
serverUrl?: string;
|
|
63
|
+
callId?: string;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export type NativePresetRendererProps = {
|
|
67
|
+
client: PresetClient | null;
|
|
68
|
+
toolCall: unknown | null;
|
|
69
|
+
onCustomTool?: (toolCall: unknown) => void;
|
|
70
|
+
/** Full teardown — stops live vision, board, etc. */
|
|
71
|
+
onDismiss?: () => void;
|
|
72
|
+
/** Clear active tool UI only (live vision session keeps running). */
|
|
73
|
+
onReleaseToolCall?: () => void;
|
|
74
|
+
};
|