From f5f39d7edfab308f1c369be89f1d07685a4231ca Mon Sep 17 00:00:00 2001 From: KaviiSuri Date: Sat, 14 Mar 2026 14:32:04 +0530 Subject: [PATCH 1/2] feat(web): add docsUrl for providers to install from --- .../components/chat/ProviderStatusBanner.tsx | 19 +++++++++++++++- apps/web/src/lib/utils.ts | 8 +++++++ apps/web/src/session-logic.ts | 22 ++++++++++++++++--- 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/apps/web/src/components/chat/ProviderStatusBanner.tsx b/apps/web/src/components/chat/ProviderStatusBanner.tsx index e709e75da3..73ba4ba405 100644 --- a/apps/web/src/components/chat/ProviderStatusBanner.tsx +++ b/apps/web/src/components/chat/ProviderStatusBanner.tsx @@ -2,6 +2,8 @@ import { PROVIDER_DISPLAY_NAMES, type ServerProvider } from "@t3tools/contracts" import { memo } from "react"; import { Alert, AlertDescription, AlertTitle } from "../ui/alert"; import { CircleAlertIcon } from "lucide-react"; +import { PROVIDER_OPTIONS } from "~/session-logic"; +import { ensureSentenceEnds } from "~/lib/utils"; export const ProviderStatusBanner = memo(function ProviderStatusBanner({ status, @@ -19,13 +21,28 @@ export const ProviderStatusBanner = memo(function ProviderStatusBanner({ : `${providerLabel} provider has limited availability.`; const title = `${providerLabel} provider status`; + const opts = PROVIDER_OPTIONS.find((opt) => opt.value === status.provider); + return (
{title} - {status.message ?? defaultMessage} + {ensureSentenceEnds(status.message ?? defaultMessage)} + {opts?.docsUrl ? ( + <> + {" "} + + Installation Guide + + + ) : null}
diff --git a/apps/web/src/lib/utils.ts b/apps/web/src/lib/utils.ts index b5834606b1..7a7c3fd037 100644 --- a/apps/web/src/lib/utils.ts +++ b/apps/web/src/lib/utils.ts @@ -34,3 +34,11 @@ export const newProjectId = (): ProjectId => ProjectId.makeUnsafe(randomUUID()); export const newThreadId = (): ThreadId => ThreadId.makeUnsafe(randomUUID()); export const newMessageId = (): MessageId => MessageId.makeUnsafe(randomUUID()); + +export const ensureSentenceEnds = (value: string): string => { + const trimmed = value.trim(); + if ([".", "!", "?"].includes(trimmed.at(-1) ?? "")) { + return trimmed; + } + return `${trimmed}.`; +}; diff --git a/apps/web/src/session-logic.ts b/apps/web/src/session-logic.ts index 83a95d6313..bcdbe30673 100644 --- a/apps/web/src/session-logic.ts +++ b/apps/web/src/session-logic.ts @@ -26,10 +26,26 @@ export const PROVIDER_OPTIONS: Array<{ value: ProviderPickerKind; label: string; available: boolean; + docsUrl: string | null; }> = [ - { value: "codex", label: "Codex", available: true }, - { value: "claudeAgent", label: "Claude", available: true }, - { value: "cursor", label: "Cursor", available: false }, + { + value: "codex", + label: "Codex", + available: true, + docsUrl: "https://developers.openai.com/codex/cli/#cli-setup", + }, + { + value: "claudeAgent", + label: "Claude", + available: true, + docsUrl: "https://code.claude.com/docs/en/quickstart#step-1-install-claude-code", + }, + { + value: "cursor", + label: "Cursor", + available: false, + docsUrl: "https://cursor.com/docs/cli/installation#installation", + }, ]; export interface WorkLogEntry { From a97baa0dc6b68ac44b3b7ea5b757309ec59492ed Mon Sep 17 00:00:00 2001 From: KaviiSuri Date: Sun, 15 Mar 2026 22:50:55 +0530 Subject: [PATCH 2/2] make docs required --- apps/web/src/session-logic.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/web/src/session-logic.ts b/apps/web/src/session-logic.ts index bcdbe30673..541c98252f 100644 --- a/apps/web/src/session-logic.ts +++ b/apps/web/src/session-logic.ts @@ -26,7 +26,7 @@ export const PROVIDER_OPTIONS: Array<{ value: ProviderPickerKind; label: string; available: boolean; - docsUrl: string | null; + docsUrl: string; }> = [ { value: "codex",