| author | |
| committer | |
| log | 315b27385d7eb36a56b410fa8b624fc2ed246278 |
| tree | 5621d9b87ba171649b450da2accc3c9fcc569792 |
| parent | 719c905eacdcb04e11dd4ce1e515a44455ed0874 |
| signature | Signed by PGP key B5690EEEBB952194 |
Co-authored-by: codex <codex@users.noreply.github.com>4 files changed, 25 insertions(+), 22 deletions(-)
apps/web/src/components/ChatView.tsx+2-2| ... | @@ -22,7 +22,7 @@ import { | ... | @@ -22,7 +22,7 @@ import { |
| 22 | TerminalOpenInput, | 22 | TerminalOpenInput, |
| 23 | } from "@t3tools/contracts"; | 23 | } from "@t3tools/contracts"; |
| 24 | import { | 24 | import { |
| 25 | connectionStatusText, | 25 | connectionStatusTitle, |
| 26 | type EnvironmentConnectionPresentation, | 26 | type EnvironmentConnectionPresentation, |
| 27 | } from "@t3tools/client-runtime/connection"; | 27 | } from "@t3tools/client-runtime/connection"; |
| 28 | import { | 28 | import { |
| ... | @@ -1815,7 +1815,7 @@ function ChatViewContent(props: ChatViewProps) { | ... | @@ -1815,7 +1815,7 @@ function ChatViewContent(props: ChatViewProps) { |
| 1815 | id: `environment-unavailable:${activeEnvironmentUnavailableState.environmentId}`, | 1815 | id: `environment-unavailable:${activeEnvironmentUnavailableState.environmentId}`, |
| 1816 | variant: connection.phase === "error" ? "error" : "warning", | 1816 | variant: connection.phase === "error" ? "error" : "warning", |
| 1817 | icon: <WifiOffIcon />, | 1817 | icon: <WifiOffIcon />, |
| 1818 | title: `${activeEnvironmentUnavailableState.label}: ${connectionStatusText(connection)}`, | 1818 | title: `${activeEnvironmentUnavailableState.label}: ${connectionStatusTitle(connection)}`, |
| 1819 | description: | 1819 | description: |
| 1820 | connection.error ?? | 1820 | connection.error ?? |
| 1821 | "Reconnect this environment before sending messages or running actions.", | 1821 | "Reconnect this environment before sending messages or running actions.", |
apps/web/src/components/chat/ChatComposer.tsx+6-13| ... | @@ -18,10 +18,7 @@ import { | ... | @@ -18,10 +18,7 @@ import { |
| 18 | PROVIDER_SEND_TURN_MAX_ATTACHMENTS, | 18 | PROVIDER_SEND_TURN_MAX_ATTACHMENTS, |
| 19 | PROVIDER_SEND_TURN_MAX_IMAGE_BYTES, | 19 | PROVIDER_SEND_TURN_MAX_IMAGE_BYTES, |
| 20 | } from "@t3tools/contracts"; | 20 | } from "@t3tools/contracts"; |
| 21 | import { | 21 | import type { EnvironmentConnectionPresentation } from "@t3tools/client-runtime/connection"; |
| 22 | connectionStatusText, | ||
| 23 | type EnvironmentConnectionPresentation, | ||
| 24 | } from "@t3tools/client-runtime/connection"; | ||
| 25 | import { serializeComposerFileLink } from "@t3tools/shared/composerTrigger"; | 22 | import { serializeComposerFileLink } from "@t3tools/shared/composerTrigger"; |
| 26 | import { createModelSelection, normalizeModelSlug } from "@t3tools/shared/model"; | 23 | import { createModelSelection, normalizeModelSlug } from "@t3tools/shared/model"; |
| 27 | import { | 24 | import { |
| ... | @@ -2577,15 +2574,11 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps) | ... | @@ -2577,15 +2574,11 @@ export const ChatComposer = memo(function ChatComposer(props: ChatComposerProps) |
| 2577 | ? "Add feedback to refine the plan, or leave this blank to implement it" | 2574 | ? "Add feedback to refine the plan, or leave this blank to implement it" |
| 2578 | : projectSelectionRequired | 2575 | : projectSelectionRequired |
| 2579 | ? "Choose a project above to start a thread" | 2576 | ? "Choose a project above to start a thread" |
| 2580 | : environmentUnavailable | 2577 | : noProviderAvailable |
| 2581 | ? `${environmentUnavailable.label}: ${connectionStatusText( | 2578 | ? "Enable a provider in Settings to send a message" |
| 2582 | environmentUnavailable.connection, | 2579 | : phase === "disconnected" |
| 2583 | )}` | 2580 | ? "Ask for follow-up changes or attach images" |
| 2584 | : noProviderAvailable | 2581 | : "Ask anything, @tag files/folders, $use skills, or / for commands" |
| 2585 | ? "Enable a provider in Settings to send a message" | ||
| 2586 | : phase === "disconnected" | ||
| 2587 | ? "Ask for follow-up changes or attach images" | ||
| 2588 | : "Ask anything, @tag files/folders, $use skills, or / for commands" | ||
| 2589 | } | 2582 | } |
| 2590 | disabled={isConnecting || isComposerApprovalState || projectSelectionRequired} | 2583 | disabled={isConnecting || isComposerApprovalState || projectSelectionRequired} |
| 2591 | /> | 2584 | /> |
packages/client-runtime/src/connection/presentation.test.ts+10-7| ... | @@ -12,6 +12,7 @@ import { | ... | @@ -12,6 +12,7 @@ import { |
| 12 | connectionCatalogDisplayUrl, | 12 | connectionCatalogDisplayUrl, |
| 13 | connectionPhaseMessage, | 13 | connectionPhaseMessage, |
| 14 | connectionStatusText, | 14 | connectionStatusText, |
| 15 | connectionStatusTitle, | ||
| 15 | presentEnvironmentConnection, | 16 | presentEnvironmentConnection, |
| 16 | presentConnectionState, | 17 | presentConnectionState, |
| 17 | } from "./presentation.ts"; | 18 | } from "./presentation.ts"; |
| ... | @@ -123,13 +124,15 @@ describe("connection presentation", () => { | ... | @@ -123,13 +124,15 @@ describe("connection presentation", () => { |
| 123 | }); | 124 | }); |
| 124 | 125 | ||
| 125 | it("combines reconnect progress with the latest failure", () => { | 126 | it("combines reconnect progress with the latest failure", () => { |
| 126 | expect( | 127 | const connection = { |
| 127 | connectionStatusText({ | 128 | phase: "reconnecting", |
| 128 | phase: "reconnecting", | 129 | error: "Relay request timed out.", |
| 129 | error: "Relay request timed out.", | 130 | traceId: "trace-retry", |
| 130 | traceId: "trace-retry", | 131 | } as const; |
| 131 | }), | 132 | expect(connectionStatusText(connection)).toBe( |
| 132 | ).toBe("Failed to connect. Reconnecting... Reason: Relay request timed out."); | 133 | "Failed to connect. Reconnecting... Reason: Relay request timed out.", |
| 134 | ); | ||
| 135 | expect(connectionStatusTitle(connection)).toBe("Failed to connect. Reconnecting..."); | ||
| 133 | }); | 136 | }); |
| 134 | 137 | ||
| 135 | it("presents the supervisor's offline state without consulting shell state", () => { | 138 | it("presents the supervisor's offline state without consulting shell state", () => { |
packages/client-runtime/src/connection/presentation.ts+7| ... | @@ -76,6 +76,13 @@ export function connectionStatusText(connection: EnvironmentConnectionPresentati | ... | @@ -76,6 +76,13 @@ export function connectionStatusText(connection: EnvironmentConnectionPresentati |
| 76 | } | 76 | } |
| 77 | } | 77 | } |
| 78 | 78 | ||
| 79 | export function connectionStatusTitle(connection: EnvironmentConnectionPresentation): string { | ||
| 80 | if (connection.phase === "reconnecting" && connection.error) { | ||
| 81 | return "Failed to connect. Reconnecting..."; | ||
| 82 | } | ||
| 83 | return connectionStatusText({ ...connection, error: null }); | ||
| 84 | } | ||
| 85 | |||
| 79 | export function presentEnvironmentConnection( | 86 | export function presentEnvironmentConnection( |
| 80 | state: SupervisorConnectionState, | 87 | state: SupervisorConnectionState, |
| 81 | ): EnvironmentConnectionPresentation { | 88 | ): EnvironmentConnectionPresentation { |