feat: allow turn credentials fetching from embed agent

This commit is contained in:
Abhishek Kumar 2026-02-04 13:52:44 +05:30
parent a235d21d69
commit 6ccc6492ee
5 changed files with 160 additions and 15 deletions

View file

@ -28,6 +28,7 @@
workflowRunId: null,
connectionStatus: 'idle', // idle, connecting, connected, failed
audioElement: null,
turnCredentials: null, // TURN server credentials
callbacks: {
onReady: null,
onCallStart: null,
@ -680,14 +681,62 @@
state.sessionToken = data.session_token;
state.workflowRunId = data.workflow_run_id;
state.workflowId = data.config.workflow_id;
// Fetch TURN credentials after session initialization
await fetchTurnCredentials();
}
/**
* Fetch TURN credentials for WebRTC connection
*/
async function fetchTurnCredentials() {
if (!state.sessionToken) {
console.warn('Dograh Widget: No session token available for TURN credentials');
return;
}
try {
const response = await fetch(`${state.config.apiBaseUrl}/api/v1/public/embed/turn-credentials/${state.sessionToken}`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'Origin': window.location.origin
}
});
if (response.ok) {
state.turnCredentials = await response.json();
console.log(`TURN credentials obtained, TTL: ${state.turnCredentials.ttl}s`);
} else if (response.status === 503) {
// TURN not configured on server - this is OK, we'll use STUN only
console.log('TURN server not configured, using STUN only');
} else {
console.warn(`Failed to fetch TURN credentials: ${response.status}`);
}
} catch (error) {
console.warn('Failed to fetch TURN credentials, continuing without TURN:', error);
}
}
/**
* Create WebRTC peer connection
*/
function createWebRTCConnection() {
// Build ICE servers list
const iceServers = [{ urls: ['stun:stun.l.google.com:19302'] }];
// Add TURN server if credentials are available
if (state.turnCredentials && state.turnCredentials.uris && state.turnCredentials.uris.length > 0) {
iceServers.push({
urls: state.turnCredentials.uris,
username: state.turnCredentials.username,
credential: state.turnCredentials.password
});
console.log(`TURN server configured with ${state.turnCredentials.uris.length} URIs`);
}
const config = {
iceServers: [{ urls: ['stun:stun.l.google.com:19302'] }]
iceServers: iceServers
};
state.pc = new RTCPeerConnection(config);

View file

@ -95,9 +95,9 @@ const BrowserCall = ({ workflowId, workflowRunId, accessToken, initialContextVar
return (
<>
<div className="flex h-full w-full">
<div className="flex h-screen w-full overflow-hidden">
{/* Main content - 2/3 width when panel visible, full width otherwise */}
<div className="w-2/3 h-full">
<div className="w-2/3 h-full overflow-y-auto">
<div className="flex justify-center items-center h-full px-8">
<Card className="w-full max-w-xl">
<CardHeader>
@ -141,7 +141,7 @@ const BrowserCall = ({ workflowId, workflowRunId, accessToken, initialContextVar
</div>
{/* Show transcript panel */}
<div className="w-1/3 h-full shrink-0">
<div className="w-1/3 h-full shrink-0 overflow-hidden">
<RealtimeFeedback
mode="live"
messages={feedbackMessages}

View file

@ -150,7 +150,7 @@ export default function WorkflowRunPage() {
}
else if (workflowRun?.is_completed) {
returnValue = (
<div className="flex h-full w-full">
<div className="flex h-screen w-full overflow-hidden">
{/* Main content - 2/3 width */}
<div className="w-2/3 h-full flex items-center justify-center overflow-y-auto">
<div className="w-full max-w-4xl space-y-6 p-6">
@ -254,7 +254,7 @@ export default function WorkflowRunPage() {
</div>
{/* Transcript panel - 1/3 width */}
<div className="w-1/3 h-full shrink-0">
<div className="w-1/3 h-full shrink-0 overflow-hidden">
<RealtimeFeedback mode="historical" logs={workflowRun?.logs} />
</div>
</div>