From 78ba62e18558bb6d5407810807301cc611773d42 Mon Sep 17 00:00:00 2001
From: Abhishek Kumar
Date: Sun, 31 May 2026 13:05:22 +0530
Subject: [PATCH] feat: banner if API is not reachable
---
CONTRIBUTING.md | 6 +-
README.zh-CN.md | 6 +-
api/services/workflow/dto.py | 3 +-
docs/deployment/heroku.mdx | 2 +-
docs/integrations/overview.mdx | 2 +-
pipecat | 2 +-
ui/src/app/api/config/version/route.ts | 48 +++++++++++--
.../components/EndCallToolConfig.tsx | 9 +--
.../components/HttpApiToolConfig.tsx | 9 +--
.../components/TransferCallToolConfig.tsx | 8 +--
ui/src/components/flow/TextOrAudioInput.tsx | 21 +++++-
ui/src/components/flow/edges/CustomEdge.tsx | 7 +-
ui/src/components/layout/AppLayout.tsx | 47 ++++++++++++-
ui/src/context/AppConfigContext.tsx | 70 +++++++++++++------
ui/src/lib/apiClient.ts | 6 +-
15 files changed, 181 insertions(+), 65 deletions(-)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 631f446..131db75 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -4,7 +4,7 @@ Welcome to Dograh AI! ❤️ Thank you for your interest in contributing to the
Dograh AI is a comprehensive voice agent platform that helps developers build, test, and deploy conversational AI systems with minimal setup. This guide will help you understand the project structure, set up your development environment, and start contributing effectively.
-👉 Join our community → [Dograh Community Slack](https://join.slack.com/t/dograh-community/shared_invite/zt-3czr47sw5-MSg1J0kJ7IMPOCHF~03auQ)
+👉 Join our community → [Dograh Community Slack](https://join.slack.com/t/dograh-community/shared_invite/zt-3zjb5vwvl-j7hRz3_F1SOn5cH~jm5f5g)
## 🏗️ Project Overview
@@ -40,7 +40,7 @@ Please refer to our [Development Setup documentation](https://docs.dograh.com/co
**Before You Start**
- Check existing [GitHub Issues](../../issues) for similar work
-- Join our [Slack community](https://join.slack.com/t/dograh-community/shared_invite/zt-3czr47sw5-MSg1J0kJ7IMPOCHF~03auQ) to discuss your plans
+- Join our [Slack community](https://join.slack.com/t/dograh-community/shared_invite/zt-3zjb5vwvl-j7hRz3_F1SOn5cH~jm5f5g) to discuss your plans
- Look for issues tagged `good first issue` for beginner-friendly tasks
**During Development**
@@ -58,6 +58,6 @@ Our Slack community is the heart of Dograh AI development:
- **Connect**: Meet other contributors and maintainers
- **Stay Updated**: Learn about contribution opportunities and releases
-👉 **Join us**: [Dograh Community Slack](https://join.slack.com/t/dograh-community/shared_invite/zt-3czr47sw5-MSg1J0kJ7IMPOCHF~03auQ)
+👉 **Join us**: [Dograh Community Slack](https://join.slack.com/t/dograh-community/shared_invite/zt-3zjb5vwvl-j7hRz3_F1SOn5cH~jm5f5g)
Thank you for helping us keep voice AI open and accessible! 🎉
diff --git a/README.zh-CN.md b/README.zh-CN.md
index 0ab8448..3b2af0d 100644
--- a/README.zh-CN.md
+++ b/README.zh-CN.md
@@ -15,7 +15,7 @@
-
+
diff --git a/api/services/workflow/dto.py b/api/services/workflow/dto.py
index c22f804..60aad75 100644
--- a/api/services/workflow/dto.py
+++ b/api/services/workflow/dto.py
@@ -244,7 +244,8 @@ class _ToolDocumentRefsMixin(BaseModel):
"display_name": "Greeting Text",
"description": (
"Text spoken via TTS at the start of the call. Supports "
- "{{template_variables}}. Leave empty to skip the greeting."
+ "{{template_variables}}. Leave empty to skip the greeting. "
+ "Not supported with realtime (speech-to-speech) models."
),
"display_options": DisplayOptions(show={"greeting_type": ["text"]}),
"placeholder": "Hi {{first_name}}, this is Sarah from Acme.",
diff --git a/docs/deployment/heroku.mdx b/docs/deployment/heroku.mdx
index 063e75d..f91721e 100644
--- a/docs/deployment/heroku.mdx
+++ b/docs/deployment/heroku.mdx
@@ -41,4 +41,4 @@ One-click Heroku deployment is in development. This will include:
- Environment variable configuration guide
- Scaling and monitoring instructions
-For updates on Heroku deployment availability, please [join our Slack community](https://join.slack.com/t/dograh-community/shared_invite/zt-3czr47sw5-MSg1J0kJ7IMPOCHF~03auQ) or watch our GitHub repository for announcements.
\ No newline at end of file
+For updates on Heroku deployment availability, please [join our Slack community](https://join.slack.com/t/dograh-community/shared_invite/zt-3zjb5vwvl-j7hRz3_F1SOn5cH~jm5f5g) or watch our GitHub repository for announcements.
\ No newline at end of file
diff --git a/docs/integrations/overview.mdx b/docs/integrations/overview.mdx
index 67696b2..35d7abb 100644
--- a/docs/integrations/overview.mdx
+++ b/docs/integrations/overview.mdx
@@ -47,4 +47,4 @@ Our integration system follows these core principles:
- Check provider-specific documentation for detailed setup instructions
- Visit our [GitHub Issues](https://github.com/dograh-hq/dograh/issues) for community support
-- Join our [Slack community](https://join.slack.com/t/dograh-community/shared_invite/zt-3czr47sw5-MSg1J0kJ7IMPOCHF~03auQ) for assistance
\ No newline at end of file
+- Join our [Slack community](https://join.slack.com/t/dograh-community/shared_invite/zt-3zjb5vwvl-j7hRz3_F1SOn5cH~jm5f5g) for assistance
\ No newline at end of file
diff --git a/pipecat b/pipecat
index b0ac013..6e410e0 160000
--- a/pipecat
+++ b/pipecat
@@ -1 +1 @@
-Subproject commit b0ac013a08cf74131a93afc5213af6b4802e5871
+Subproject commit 6e410e06cc9f71fbadfb3850f87848d2288d6651
diff --git a/ui/src/app/api/config/version/route.ts b/ui/src/app/api/config/version/route.ts
index 37609df..05900db 100644
--- a/ui/src/app/api/config/version/route.ts
+++ b/ui/src/app/api/config/version/route.ts
@@ -1,32 +1,64 @@
import { NextResponse } from "next/server";
-import { healthApiV1HealthGet } from "@/client/sdk.gen";
import type { HealthResponse } from "@/client/types.gen";
+import { getServerBackendUrl } from "@/lib/apiClient";
// Import version from package.json at build time
import packageJson from "../../../../../package.json";
+const HEALTHCHECK_TIMEOUT_MS = 3000;
+
+function trimTrailingSlash(url: string) {
+ return url.endsWith("/") ? url.slice(0, -1) : url;
+}
+
+function getHealthcheckFailureMessage(error: unknown, backendUrl: string) {
+ const errorName =
+ error && typeof error === "object" && "name" in error
+ ? String((error as { name?: unknown }).name)
+ : "";
+
+ if (errorName === "AbortError" || errorName === "TimeoutError") {
+ return `Backend health check timed out after ${HEALTHCHECK_TIMEOUT_MS}ms while trying to reach ${backendUrl}.`;
+ }
+
+ return `Backend is not reachable at ${backendUrl}.`;
+}
+
export async function GET() {
const uiVersion = packageJson.version || "dev";
+ const backendUrl = trimTrailingSlash(getServerBackendUrl());
+ const healthcheckUrl = `${backendUrl}/api/v1/health`;
let apiVersion = "unknown";
let deploymentMode = "oss";
let authProvider = "local";
let turnEnabled = false;
let forceTurnRelay = false;
+ let backendStatus: "reachable" | "unreachable" = "unreachable";
+ let backendMessage: string | null = `Backend is not reachable at ${backendUrl}.`;
try {
- const response = await healthApiV1HealthGet();
- if (response.data) {
- const data = response.data as HealthResponse;
+ const response = await fetch(healthcheckUrl, {
+ cache: "no-store",
+ signal: AbortSignal.timeout(HEALTHCHECK_TIMEOUT_MS),
+ });
+
+ if (!response.ok) {
+ backendMessage = `Backend health check at ${healthcheckUrl} returned HTTP ${response.status}.`;
+ } else {
+ const data = (await response.json()) as HealthResponse;
apiVersion = data.version;
deploymentMode = data.deployment_mode;
authProvider = data.auth_provider;
turnEnabled = Boolean(data.turn_enabled);
forceTurnRelay = Boolean(data.force_turn_relay);
+ backendStatus = "reachable";
+ backendMessage = null;
}
- } catch {
+ } catch (error) {
apiVersion = "unavailable";
+ backendMessage = getHealthcheckFailureMessage(error, backendUrl);
}
return NextResponse.json({
@@ -36,5 +68,11 @@ export async function GET() {
authProvider,
turnEnabled,
forceTurnRelay,
+ backend: {
+ status: backendStatus,
+ url: backendUrl,
+ healthcheckUrl,
+ message: backendMessage,
+ },
});
}
diff --git a/ui/src/app/tools/[toolUuid]/components/EndCallToolConfig.tsx b/ui/src/app/tools/[toolUuid]/components/EndCallToolConfig.tsx
index a3717ca..d5c9b23 100644
--- a/ui/src/app/tools/[toolUuid]/components/EndCallToolConfig.tsx
+++ b/ui/src/app/tools/[toolUuid]/components/EndCallToolConfig.tsx
@@ -1,9 +1,7 @@
"use client";
-import { AlertCircle } from "lucide-react";
-
import type { RecordingResponseSchema } from "@/client/types.gen";
-import { RecordingSelect } from "@/components/flow/TextOrAudioInput";
+import { RecordingSelect, StaticTextWarning } from "@/components/flow/TextOrAudioInput";
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
@@ -144,10 +142,7 @@ export function EndCallToolConfig({
{messageType === "custom" && (
-
-
- This text is spoken as-is. For multilingual workflows, choose your phrasing carefully.
-
+
{messageType === "custom" && (
-
-
- This text is spoken as-is. For multilingual workflows, choose your phrasing carefully.
-
+
onCustomMessageChange(e.target.value)}
diff --git a/ui/src/components/flow/TextOrAudioInput.tsx b/ui/src/components/flow/TextOrAudioInput.tsx
index 1f575d8..c5c8792 100644
--- a/ui/src/components/flow/TextOrAudioInput.tsx
+++ b/ui/src/components/flow/TextOrAudioInput.tsx
@@ -1,4 +1,4 @@
-import { Check, ChevronDown, Pause, Play, Search } from "lucide-react";
+import { AlertCircle, Check, ChevronDown, Pause, Play, Search } from "lucide-react";
import { useMemo, useState } from "react";
import type { RecordingResponseSchema } from "@/client/types.gen";
@@ -10,6 +10,25 @@ import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group";
import { useAudioPlayback } from "@/hooks/useAudioPlayback";
import { cn } from "@/lib/utils";
+/**
+ * Amber caveat shown next to free-text fields that are spoken aloud via TTS
+ * (greetings, transition speech, custom tool messages). Two warnings: the text
+ * is voiced verbatim (matters for multilingual flows), and realtime
+ * (speech-to-speech) models have no TTS stage, so static text is never spoken —
+ * a pre-recorded audio file should be used instead.
+ */
+export function StaticTextWarning() {
+ return (
+
+
+
+ This text is spoken as-is. For multilingual workflows, choose your phrasing carefully.
+ Realtime (speech-to-speech) models can't play static text.
+
+