feat(robot): connect provisioning hotspots in app
This commit is contained in:
@@ -35,8 +35,15 @@ const SAFE_ERROR_MESSAGES: Record<string, string> = {
|
||||
AI_HARDWARE_INVALID_RESPONSE: 'AI hardware service returned an invalid response',
|
||||
AI_HARDWARE_PROVISIONING_DISABLED: 'AI hardware guided provisioning is not enabled',
|
||||
AI_HARDWARE_PORTAL_OPEN_FAILED: 'AI hardware provisioning portal could not be opened',
|
||||
AI_HARDWARE_HOTSPOT_UNSUPPORTED: 'Robot hotspot connection is not supported on this platform',
|
||||
AI_HARDWARE_HOTSPOT_PERMISSION_DENIED: 'Permission to access nearby Robot hotspots was denied',
|
||||
AI_HARDWARE_HOTSPOT_BUSY: 'Another Robot hotspot operation is in progress',
|
||||
AI_HARDWARE_HOTSPOT_CANDIDATE_EXPIRED: 'The Robot hotspot selection expired; scan again',
|
||||
AI_HARDWARE_HOTSPOT_SCAN_FAILED: 'Robot hotspots could not be scanned',
|
||||
AI_HARDWARE_HOTSPOT_CONNECT_FAILED: 'The Robot hotspot could not be connected',
|
||||
};
|
||||
const OPERATION_ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
||||
const HOTSPOT_CANDIDATE_ID = /^[A-Za-z0-9_-]{1,128}$/;
|
||||
|
||||
export type AiHardwareStatus =
|
||||
| 'unprovisioned'
|
||||
@@ -67,6 +74,24 @@ export type AiHardwareProvisioningCapabilities = {
|
||||
guidedHotspotBinding: boolean;
|
||||
};
|
||||
|
||||
export type AiHardwareProvisioningHotspot = {
|
||||
candidateId: string;
|
||||
ssid: string;
|
||||
signalPercent: number;
|
||||
connected: boolean;
|
||||
};
|
||||
|
||||
export type AiHardwareProvisioningHotspotScan = {
|
||||
platform: 'windows' | 'macos';
|
||||
hotspots: AiHardwareProvisioningHotspot[];
|
||||
};
|
||||
|
||||
export type AiHardwareProvisioningHotspotConnection = {
|
||||
connected: true;
|
||||
candidateId: string;
|
||||
ssid: string;
|
||||
};
|
||||
|
||||
export type AiHardwareAgentConfiguration = AiHardwareAgent & {
|
||||
system_prompt: string | null;
|
||||
lang_code: string | null;
|
||||
@@ -360,6 +385,41 @@ function readPortalOpened(value: unknown): { opened: true } {
|
||||
return { opened: true };
|
||||
}
|
||||
|
||||
function readProvisioningHotspot(value: unknown): AiHardwareProvisioningHotspot {
|
||||
if (!isRecord(value)
|
||||
|| !hasOnlyKeys(value, ['candidate_id', 'ssid', 'signal_percent', 'connected'])
|
||||
|| typeof value.candidate_id !== 'string' || !HOTSPOT_CANDIDATE_ID.test(value.candidate_id)
|
||||
|| typeof value.ssid !== 'string' || value.ssid.length < 1 || value.ssid.length > 32
|
||||
|| !isInteger(value.signal_percent, 0, 100)
|
||||
|| typeof value.connected !== 'boolean') invalidPayload();
|
||||
return {
|
||||
candidateId: value.candidate_id,
|
||||
ssid: value.ssid,
|
||||
signalPercent: value.signal_percent,
|
||||
connected: value.connected,
|
||||
};
|
||||
}
|
||||
|
||||
function readProvisioningHotspotScan(value: unknown): AiHardwareProvisioningHotspotScan {
|
||||
if (!isRecord(value)
|
||||
|| !hasOnlyKeys(value, ['platform', 'hotspots'])
|
||||
|| (value.platform !== 'windows' && value.platform !== 'macos')
|
||||
|| !Array.isArray(value.hotspots) || value.hotspots.length > 64) invalidPayload();
|
||||
return {
|
||||
platform: value.platform,
|
||||
hotspots: value.hotspots.map(readProvisioningHotspot),
|
||||
};
|
||||
}
|
||||
|
||||
function readProvisioningHotspotConnection(value: unknown): AiHardwareProvisioningHotspotConnection {
|
||||
if (!isRecord(value)
|
||||
|| !hasOnlyKeys(value, ['connected', 'candidate_id', 'ssid'])
|
||||
|| value.connected !== true
|
||||
|| typeof value.candidate_id !== 'string' || !HOTSPOT_CANDIDATE_ID.test(value.candidate_id)
|
||||
|| typeof value.ssid !== 'string' || value.ssid.length < 1 || value.ssid.length > 32) invalidPayload();
|
||||
return { connected: true, candidateId: value.candidate_id, ssid: value.ssid };
|
||||
}
|
||||
|
||||
function throwEnvelopeError(envelope: MainEnvelope): never {
|
||||
const status = isInteger(envelope.status, 400, 599) ? envelope.status : 502;
|
||||
const code = typeof envelope.code === 'string' && /^[A-Za-z0-9._-]{1,128}$/.test(envelope.code)
|
||||
@@ -536,6 +596,25 @@ export async function openAiHardwareProvisioningPortal(): Promise<{ opened: true
|
||||
) as Promise<{ opened: true }>;
|
||||
}
|
||||
|
||||
export async function scanAiHardwareProvisioningHotspots(): Promise<AiHardwareProvisioningHotspotScan> {
|
||||
return request(
|
||||
'/provisioning-hotspots/scan',
|
||||
jsonInit('POST', {}),
|
||||
readProvisioningHotspotScan,
|
||||
) as Promise<AiHardwareProvisioningHotspotScan>;
|
||||
}
|
||||
|
||||
export async function connectAiHardwareProvisioningHotspot(
|
||||
candidateId: string,
|
||||
): Promise<AiHardwareProvisioningHotspotConnection> {
|
||||
if (!HOTSPOT_CANDIDATE_ID.test(candidateId)) throw new TypeError('candidateId is invalid');
|
||||
return request(
|
||||
'/provisioning-hotspots/connect',
|
||||
jsonInit('POST', { candidate_id: candidateId }),
|
||||
readProvisioningHotspotConnection,
|
||||
) as Promise<AiHardwareProvisioningHotspotConnection>;
|
||||
}
|
||||
|
||||
export async function getAiHardwareConfigurationCatalog(
|
||||
ttsModelId?: string,
|
||||
): Promise<AiHardwareConfigurationCatalog> {
|
||||
|
||||
Reference in New Issue
Block a user