diff --git a/apps/hub/src/index.ts b/apps/hub/src/index.ts index 8a467fd92..b113c9a34 100644 --- a/apps/hub/src/index.ts +++ b/apps/hub/src/index.ts @@ -2216,9 +2216,10 @@ export async function createHub(config: HubConfig) { // A connection completing through ANY door below — OAuth callback, // pasted key, MCP OAuth, keyless MCP preset — settles every room // waiting on that connector: the room's `connections/pending` entry - // clears (flipping the in-room connect card via `chat.settings`), and - // the host agent is woken via `dispatchTurn` without a forged - // signed-in-user timeline row. + // clears (flipping the in-room connect card via `chat.settings`). + // Rooms with `connections/pending` still wake the host agent via + // `dispatchTurn` without a forged signed-in-user timeline row; + // code-review template rooms are not woken on PAT settle. // // An inference provider's credential landing also re-checks every // live participant's deployed inference chain (CL-6687): a rotated diff --git a/packages/chat-ui/src/inference-failure.test.ts b/packages/chat-ui/src/inference-failure.test.ts index 80c9326d6..5ba8784b3 100644 --- a/packages/chat-ui/src/inference-failure.test.ts +++ b/packages/chat-ui/src/inference-failure.test.ts @@ -1,26 +1,23 @@ import { describe, expect, test } from "bun:test"; import { + CONSUMER_INFERENCE_FAILURE_NOTICE, consumerFacingInferenceText, isClassifiedInferenceFailureText, } from "./inference-failure"; describe("consumerFacingInferenceText", () => { - test("keeps the vendor preamble and drops [HTTP …] plus the raw provider message", () => { + test("maps a classified credential failure to one recovery sentence", () => { expect( consumerFacingInferenceText( "This agent could not complete your request due to a credential error [HTTP 401]: API key is invalid", ), - ).toBe( - "This agent could not complete your request due to a credential error", - ); + ).toBe(CONSUMER_INFERENCE_FAILURE_NOTICE); expect( consumerFacingInferenceText( "This agent could not complete your request because the API quota has been exhausted [HTTP 429]: rate limited", ), - ).toBe( - "This agent could not complete your request because the API quota has been exhausted", - ); + ).toBe(CONSUMER_INFERENCE_FAILURE_NOTICE); }); test("a forced [HTTP 401] dump is not consumer copy", () => { @@ -47,12 +44,15 @@ describe("isClassifiedInferenceFailureText", () => { ).toBe(true); }); - test("matches a credential_failure reply after HTTP/raw is stripped", () => { + test("a stripped credential_failure reply is recovery copy, not the classified preamble", () => { + const facing = consumerFacingInferenceText( + "This agent could not complete your request due to a credential error [HTTP 401]: invalid api key", + ); + expect(facing).toBe(CONSUMER_INFERENCE_FAILURE_NOTICE); + expect(facing.toLowerCase()).not.toContain("credential error"); expect( isClassifiedInferenceFailureText( - consumerFacingInferenceText( - "This agent could not complete your request due to a credential error [HTTP 401]: invalid api key", - ), + "This agent could not complete your request due to a credential error [HTTP 401]: invalid api key", ), ).toBe(true); }); diff --git a/packages/chat-ui/src/inference-failure.ts b/packages/chat-ui/src/inference-failure.ts index 0b3bb35a2..65906aab6 100644 --- a/packages/chat-ui/src/inference-failure.ts +++ b/packages/chat-ui/src/inference-failure.ts @@ -29,7 +29,10 @@ export const CLASSIFIED_INFERENCE_FAILURE_PREAMBLES: readonly string[] = [ "This agent could not complete your request because the API quota has been exhausted", ]; -export { consumerFacingInferenceText } from "@corbits/chat/consumer-inference-text"; +export { + CONSUMER_INFERENCE_FAILURE_NOTICE, + consumerFacingInferenceText, +} from "@corbits/chat/consumer-inference-text"; export function isClassifiedInferenceFailureText(text: string): boolean { return CLASSIFIED_INFERENCE_FAILURE_PREAMBLES.some((preamble) => diff --git a/packages/chat-ui/src/timeline.tsx b/packages/chat-ui/src/timeline.tsx index 6b3eadfea..8d21ffd2a 100644 --- a/packages/chat-ui/src/timeline.tsx +++ b/packages/chat-ui/src/timeline.tsx @@ -59,6 +59,7 @@ import type { ConnectGithubActions } from "./blocks/connect-github-actions"; import type { ConnectServiceActions } from "./blocks/connect-service-actions"; import { BlockPartView } from "./blocks/registry"; import { + CONSUMER_INFERENCE_FAILURE_NOTICE, consumerFacingInferenceText, isClassifiedInferenceFailureText, } from "./inference-failure"; @@ -551,7 +552,8 @@ function TextBubble({ {onFixConnection !== undefined && - isClassifiedInferenceFailureText(consumerText) && ( + (isClassifiedInferenceFailureText(text) || + consumerText === CONSUMER_INFERENCE_FAILURE_NOTICE) && (