Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@
targetUrl = url ?? BuildFoundryUrl(foundryEndpoint.TrimEnd('/'), agent, sessionId, apiVersion);
var token = await GetEntraTokenAsync();
headers["Authorization"] = $"Bearer {token}";
headers["Foundry-Features"] = "HostedAgents=V1Preview";
}
else
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
* • serves the static page (chat_client/index.html) on / and /index.html;
* • upgrades inbound /invocations_ws to a WebSocket;
* • opens an outbound WebSocket to the Foundry hosted agent endpoint
* with Authorization: Bearer <Entra token> + Foundry-Features headers;
* with Authorization: Bearer <Entra token> header;
* • forwards binary and text frames in both directions verbatim.
*
* Run:
Expand Down Expand Up @@ -108,7 +108,6 @@

using var upstream = new ClientWebSocket();
upstream.Options.SetRequestHeader("Authorization", $"Bearer {token}");
upstream.Options.SetRequestHeader("Foundry-Features", "HostedAgents=V1Preview");
try
{
await upstream.ConnectAsync(new Uri(foundryWsUrl), ctx.RequestAborted);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,6 @@ async def _warmup_session(args, session_id: str) -> None:
return
headers = {
"Authorization": f"Bearer {token}",
"Foundry-Features": "HostedAgents=V1Preview",
}
print(f"[proxy] warming up sandbox session={session_id}")
try:
Expand All @@ -165,7 +164,6 @@ async def handler(browser_ws):
return
headers = {
"Authorization": f"Bearer {token}",
"Foundry-Features": "HostedAgents=V1Preview",
}
print(f"[proxy] {peer} -> {url}")
try:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,6 @@ def main() -> int:
token = _entra_token()
headers = {
"Authorization": f"Bearer {token}",
"Foundry-Features": "HostedAgents=V1Preview",
}
else:
url = args.url or "ws://localhost:8088/invocations_ws"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,6 @@ async def _warmup_session(args, session_id: str) -> None:
return
headers = {
"Authorization": f"Bearer {token}",
"Foundry-Features": "HostedAgents=V1Preview",
}
print(f"[proxy] warming up sandbox session={session_id}")
try:
Expand All @@ -165,7 +164,6 @@ async def handler(browser_ws):
return
headers = {
"Authorization": f"Bearer {token}",
"Foundry-Features": "HostedAgents=V1Preview",
}
print(f"[proxy] {peer} -> {url}")
try:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,6 @@ def main() -> int:
token = _entra_token()
headers = {
"Authorization": f"Bearer {token}",
"Foundry-Features": "HostedAgents=V1Preview",
}
else:
url = args.url or "ws://localhost:8088/invocations_ws"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ The proxy:
`LIVEKIT_AGENT_NAME` (Foundry-hosted mode).
- In Foundry mode, fetches an Entra Bearer token via
`az account get-access-token --resource https://ai.azure.com` and
attaches it + the `Foundry-Features: HostedAgents=V1Preview` header.
attaches it as the `Authorization` header.
- Forwards signaling JSON verbatim in both directions.

## Install
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,5 +91,4 @@ def resolve() -> tuple[str, str, dict[str, str]]:
logger.info("foundry mode session_id=%s", sid)
return url, sid, {
"Authorization": f"Bearer {token}",
"Foundry-Features": "HostedAgents=V1Preview",
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ A real-time voice agent hosted as a **Bring Your Own** WebSocket container that

Why a single `/invocations_ws` endpoint? This sample lives under the `bring-your-own/invocations_ws/` tree, where the Foundry contract is "one duplex WebSocket called `invocations_ws`". We keep that surface here but use the WebSocket purely for **WebRTC signaling** (offer / answer / ICE candidates / ICE config). Audio still flows over the WebRTC peer connection and never touches the signaling WebSocket.

The browser client lives in [`chat_client/`](chat_client/) — a small FastAPI portal that terminates the browser's WebSocket, attaches the Entra token + `Foundry-Features` header in hosted mode, and forwards signaling JSON to the upstream `/invocations_ws`. The same proxy works against either a local server or the Foundry-hosted agent.
The browser client lives in [`chat_client/`](chat_client/) — a small FastAPI portal that terminates the browser's WebSocket, attaches the Entra token as the `Authorization` header in hosted mode, and forwards signaling JSON to the upstream `/invocations_ws`. The same proxy works against either a local server or the Foundry-hosted agent.

## ⚠️ Security Warning

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ The proxy:
`PIPECAT_WEBRTC_AGENT_NAME` (Foundry-hosted mode).
- In Foundry mode, fetches an Entra Bearer token via
`az account get-access-token --resource https://ai.azure.com` and
attaches it + the `Foundry-Features: HostedAgents=V1Preview` header.
attaches it as the `Authorization` header.
- Forwards signaling JSON verbatim in both directions.

## Install
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,5 +91,4 @@ def resolve() -> tuple[str, str, dict[str, str]]:
logger.info("foundry mode session_id=%s", sid)
return url, sid, {
"Authorization": f"Bearer {token}",
"Foundry-Features": "HostedAgents=V1Preview",
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ The proxy:
`PIPECAT_WEBSOCKET_AGENT_NAME` (Foundry-hosted mode).
- In Foundry mode, fetches an Entra Bearer token via
`az account get-access-token --resource https://ai.azure.com` and
attaches it + the `Foundry-Features: HostedAgents=V1Preview` header.
attaches it as the `Authorization` header.
- Transcodes between the browser's simple PCM/JSON wire format and
pipecat's protobuf framing so the page stays protocol-agnostic.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ def resolve() -> tuple[str, str, dict[str, str]]:
"""Return ``(upstream_url, session_id, headers)``.

Local mode: ``(LOCAL_URL value, "", {})`` — no auth.
Foundry mode: ``(public_url, generated_sid, {Authorization, Foundry-Features})``.
Foundry mode: ``(public_url, generated_sid, {Authorization})``.
"""
local = os.environ.get(LOCAL_ENV, "").strip()
if local:
Expand All @@ -95,5 +95,4 @@ def resolve() -> tuple[str, str, dict[str, str]]:
logger.info("foundry mode session_id=%s", sid)
return url, sid, {
"Authorization": f"Bearer {token}",
"Foundry-Features": "HostedAgents=V1Preview",
}
Loading