Skip to content

feat: add Regent orchestrator as persistent right sidebar#1

Open
soyboyscout wants to merge 2 commits intomainfrom
feat/regent-sidebar-panel
Open

feat: add Regent orchestrator as persistent right sidebar#1
soyboyscout wants to merge 2 commits intomainfrom
feat/regent-sidebar-panel

Conversation

@soyboyscout
Copy link
Member

@soyboyscout soyboyscout commented Mar 3, 2026

Summary

  • Replace full-page Regent route with a persistent right sidebar panel featuring vertical thread tabs and Tambo-powered AI chat
  • Add Regent toggle button to TopBar (diamond icon) matching the existing sidebar/context panel toggle pattern
  • Add session-aware Tambo tools and custom components (SessionCard, TaskOverview) for orchestrating agent sessions

Test plan

  • 118/118 test suites pass (3131 tests), including new RightPanel tests
  • Production build succeeds
  • Visual QA: Regent panel opens/closes via TopBar toggle button
  • Visual QA: Vertical thread tabs switch between Regent threads
  • Visual QA: Context panel and Regent panel toggle independently
  • TypeScript: 0 errors in changed files (pre-existing type issues in unrelated test files only)

Summary by cubic

Adds Regent as a persistent right sidebar with Tambo-powered chat and vertical thread tabs, replacing the old full-page route. A diamond button in the TopBar toggles it independently of the Context panel, with a solid background and proper placement below the TopBar on mobile.

  • New Features

    • RegentSidebar with vertical tabs to switch/create Tambo threads.
    • Tambo chat with session-aware tools and components (SessionCard, TaskOverview).
    • New store state: regentPanelOpen and rightPanelActiveTab; panel mounts app-wide and overlays on mobile.
    • Panel and TopBar toggle render only when a Tambo API key is set; solid bg and mobile positioning fix included.
  • Migration

    • Set VITE_TAMBO_API_KEY in your env (see .env.example), then reinstall deps and restart.

Written for commit 775a6eb. Summary will update on new commits.

Summary by CodeRabbit

  • New Features

    • Regent AI chat panel with thread management and persistent sidebar
    • Session Card UI showing session details, status, and quick navigation
    • Task Overview component summarizing tasks across sessions
    • Top bar toggle to show/hide the Regent panel
    • Session introspection tools providing session lists, messages, tasks, diffs, and summaries
  • Chores

    • Added TAMBO API env key example and support packages
  • Tests

    • Added comprehensive tests for Regent UI, session components, tools, and panels

EntelligenceAI PR Summary

This PR integrates Tambo AI chat functionality with a new collapsible Regent sidebar panel featuring thread management and session monitoring tools.

  • Added Tambo AI SDK packages and React Query dependencies to package.json
  • Created RegentPanel with chat interface, streaming support, and custom component rendering (SessionCard, TaskOverview)
  • Implemented RightPanel with VerticalTabBar for thread navigation and responsive mobile/desktop layouts
  • Built six session management tools: listSessions, getSessionMessages, getSessionTasks, getSessionStatus, getSessionDiff, getAllSessionsSummary
  • Added SessionCard component with real-time status indicators and metadata display
  • Created TaskOverview component with status-based grouping and truncation logic
  • Extended Zustand store with regentPanelOpen and rightPanelActiveTab state management
  • Added TopBar toggle button for Regent panel control with conditional rendering
  • Refactored App.tsx to replace task panel toggle with persistent RegentSidebar
  • Added comprehensive test coverage for all new components and tools
  • Configured VITE_TAMBO_API_KEY environment variable

Confidence Score: 2/5 - Changes Needed

  • Two existing unresolved correctness issues involve type mismatches that will cause runtime failures: propsSchema allowing null but typed as string, and outputSchema declaring object but returning JSON string
  • New UI bug causes 44px viewport overflow which degrades user experience but is not critical
  • The existing type contract violations in session-tools.ts will lead to validation failures at runtime, representing significant functional issues
  • While no critical security issues exist, the combination of runtime-breaking type mismatches warrants fixing before merge
Files requiring special attention
  • web/src/regent/tools/session-tools.ts
  • web/src/regent/components/SessionCard.tsx
  • web/src/components/RightPanel.tsx

Replace the full-page Regent route with a persistent right sidebar panel
that includes vertical thread tabs and an AI chat interface powered by
Tambo. Users can now interact with the Regent without leaving their
current session.

- Add RegentSidebar component with vertical tab bar for thread switching
- Add Regent toggle button to TopBar (diamond icon, matches sidebar pattern)
- Add store state for regentPanelOpen and rightPanelActiveTab
- Split RegentPanel into RegentProvider + RegentChat exports
- Add session-aware Tambo tools and custom components (SessionCard, TaskOverview)
- Remove Regent from sidebar navigation and routing
- Remove inline collapsed Context button (TopBar toggle handles it)
- Add VITE_TAMBO_API_KEY to .env.example
Copilot AI review requested due to automatic review settings March 3, 2026 00:44
@matter-ai-bot
Copy link

matter-ai-bot bot commented Mar 3, 2026

Caution

PR Summary Skipped - Monthly Quota Exceeded

PR summary skipped as you have reached the free tier limit of 50 PR summaries per month. Please upgrade to a paid plan for MatterAI.

Current Plan: Free Tier
Free Tier Limit: 25 PR Summaries per month
Current Usage: 25 PR Summaries
Resets in: 28 days

Upgrade your plan on the console here: https://app.matterai.so/ai-code-reviews?tab=Billing

@coderabbitai
Copy link

coderabbitai bot commented Mar 3, 2026

📝 Walkthrough

Walkthrough

Adds Tambo AI integration: new Regent chat UI (RegentPanel, RegentSidebar), session-focused Tambo tools, task/session display components, store state for panel control, package deps, env var, and related tests and mocks.

Changes

Cohort / File(s) Summary
Configuration & Dependencies
web/.env.example, web/package.json
Added VITE_TAMBO_API_KEY env key and four dependencies: @tambo-ai/client, @tambo-ai/react, @tambo-ai/typescript-sdk, @tanstack/react-query.
App integration & TopBar
web/src/App.tsx, web/src/components/TopBar.tsx, web/src/App.test.tsx
Integrated RegentSidebar into App, removed manual open button; TopBar gains a conditional Regent panel toggle; tests add mocks for RightPanel/Regent availability.
Right-side UI (sidebar & tabs)
web/src/components/RightPanel.tsx, web/src/components/RightPanel.test.tsx
New RegentSidebar with mobile backdrop, responsive panel, vertical thread tab bar, new-thread flow and thread switching; comprehensive tests for tabs, open/close, and actions.
Regent chat provider & chat UI
web/src/components/RegentPanel.tsx
New RegentProvider and RegentChat components, TAMBO provider wiring, message streaming/submit handling, component rendering for embeds, and hasTamboApiKey check.
Session & Task components
web/src/regent/components/SessionCard.tsx, web/src/regent/components/TaskOverview.tsx, web/src/regent/components/SessionCard.test.tsx, web/src/regent/components/TaskOverview.test.tsx
Added SessionCard (with navigation and export metadata) and TaskOverview (grouped task view, truncation + summaries) plus tests verifying rendering, counts, labels, and interactions.
Session tools (Tambo tools)
web/src/regent/tools/session-tools.ts, web/src/regent/tools/session-tools.test.ts
Introduced six Tambo tools (listSessions, getSessionMessages, getSessionTasks, getSessionStatus, getSessionDiff, getAllSessionsSummary) returning JSON; extensive unit tests covering behaviors and edge cases.
State/store updates
web/src/store.ts
Added regentPanelOpen and rightPanelActiveTab to AppState with setters and reset behavior; responsive default for panel open.
Test adjustments & mocks
web/src/components/TopBar.test.tsx, other test mocks
Added/updated mocks to control hasTamboApiKey and RightPanel internals across tests.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant UI as App/TopBar/RightPanel
    participant Store as useStore
    participant Regent as RegentProvider/RegentChat
    participant Tambo as Tambo API / Threads DB

    User->>UI: Click "Toggle Regent panel" / open sidebar
    UI->>Store: setRegentPanelOpen(true)
    Store-->>UI: regentPanelOpen=true
    UI->>Regent: render RegentProvider (apiKey via env)
    Regent->>Tambo: fetch thread list (useTamboThreadList)
    Tambo-->>Regent: thread list
    Regent-->>UI: render VerticalTabBar with threads
    User->>UI: Click thread tab (id)
    UI->>Store: setRightPanelActiveTab(id)
    UI->>Regent: useTambo.switchThread(id)
    Regent->>Tambo: request thread messages / stream
    Tambo-->>Regent: stream messages
    Regent-->>UI: update RegentChat feed (auto-scroll)
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 Hopped in with a tiny key,

Whispered "Regent, come play with me!"
Threads unfurl and tasks take flight,
Sidebar glowing through the night.
Tools and chats in tidy rows — hooray!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and accurately describes the main change: adding a Regent orchestrator as a persistent right sidebar component to the application.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch feat/regent-sidebar-panel

Tip

Try Coding Plans. Let us write the prompt for your AI agent so you can ship faster (with fewer bugs).
Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@qodo-code-review
Copy link

Review Summary by Qodo

Add Regent orchestrator as persistent right sidebar with Tambo AI integration

✨ Enhancement

Grey Divider

Walkthroughs

Description
• Add Regent orchestrator as persistent right sidebar with vertical thread tabs
• Implement session-aware Tambo tools for AI-powered agent orchestration
• Add Regent toggle button to TopBar matching existing sidebar pattern
• Create custom Tambo components (SessionCard, TaskOverview) for session management
• Add store state for regentPanelOpen and rightPanelActiveTab
Diagram
flowchart LR
  A["Store State<br/>regentPanelOpen<br/>rightPanelActiveTab"] -->|manages| B["RegentSidebar<br/>Vertical Tabs"]
  B -->|renders| C["RegentChat<br/>Tambo Provider"]
  C -->|uses| D["Session Tools<br/>listSessions<br/>getSessionMessages<br/>getSessionTasks"]
  D -->|powers| E["Custom Components<br/>SessionCard<br/>TaskOverview"]
  F["TopBar<br/>Regent Toggle"] -->|controls| A
  G["Tambo API<br/>Threads & Messages"] -->|feeds| C
Loading

Grey Divider

File Changes

1. web/src/regent/tools/session-tools.ts ✨ Enhancement +261/-0

Session-aware Tambo tools for agent orchestration

web/src/regent/tools/session-tools.ts


2. web/src/regent/tools/session-tools.test.ts 🧪 Tests +259/-0

Comprehensive tests for session tools

web/src/regent/tools/session-tools.test.ts


3. web/src/components/RegentPanel.tsx ✨ Enhancement +159/-0

Regent chat interface with Tambo provider

web/src/components/RegentPanel.tsx


View more (13)
4. web/src/components/RightPanel.tsx ✨ Enhancement +121/-0

Regent sidebar with vertical thread tabs

web/src/components/RightPanel.tsx


5. web/src/components/RightPanel.test.tsx 🧪 Tests +149/-0

Tests for Regent sidebar component

web/src/components/RightPanel.test.tsx


6. web/src/regent/components/SessionCard.tsx ✨ Enhancement +149/-0

Session status card component for Tambo

web/src/regent/components/SessionCard.tsx


7. web/src/regent/components/SessionCard.test.tsx 🧪 Tests +80/-0

Tests for session card component

web/src/regent/components/SessionCard.test.tsx


8. web/src/regent/components/TaskOverview.tsx ✨ Enhancement +125/-0

Aggregated task overview component for Tambo

web/src/regent/components/TaskOverview.tsx


9. web/src/regent/components/TaskOverview.test.tsx 🧪 Tests +89/-0

Tests for task overview component

web/src/regent/components/TaskOverview.test.tsx


10. web/src/store.ts ✨ Enhancement +12/-0

Add regent panel state and actions

web/src/store.ts


11. web/src/App.tsx ✨ Enhancement +5/-17

Integrate RegentSidebar and remove inline context button

web/src/App.tsx


12. web/src/App.test.tsx 🧪 Tests +4/-0

Mock RightPanel component in tests

web/src/App.test.tsx


13. web/src/components/TopBar.tsx ✨ Enhancement +19/-0

Add Regent toggle button with diamond icon

web/src/components/TopBar.tsx


14. web/src/components/TopBar.test.tsx 🧪 Tests +4/-0

Mock hasTamboApiKey in TopBar tests

web/src/components/TopBar.test.tsx


15. web/package.json Dependencies +4/-0

Add Tambo and React Query dependencies

web/package.json


16. web/.env.example ⚙️ Configuration changes +1/-0

Add VITE_TAMBO_API_KEY environment variable

web/.env.example


Grey Divider

Qodo Logo

@qodo-code-review
Copy link

qodo-code-review bot commented Mar 3, 2026

Code Review by Qodo

🐞 Bugs (4) 📘 Rule violations (4) 📎 Requirement gaps (0)

Grey Divider


Action required

1. RegentPanel missing .test.tsx 📘 Rule violation ⛯ Reliability
Description
web/src/components/RegentPanel.tsx is a new component but there is no corresponding
RegentPanel.test.tsx providing render, axe, and interaction coverage. This violates the baseline
frontend component test requirement and risks regressions in the Regent chat/provider UI.
Code

web/src/components/RegentPanel.tsx[R1-16]

+import { useRef, useEffect, type ReactNode } from "react";
+import {
+  TamboProvider,
+  useTambo,
+  useTamboThreadInput,
+  ComponentRenderer,
+} from "@tambo-ai/react";
+import { sessionTools } from "../regent/tools/session-tools.js";
+import { sessionCardTamboComponent } from "../regent/components/SessionCard.js";
+import { taskOverviewTamboComponent } from "../regent/components/TaskOverview.js";
+
+const TAMBO_API_KEY = (import.meta as unknown as Record<string, Record<string, string>>).env?.VITE_TAMBO_API_KEY;
+
+export function hasTamboApiKey(): boolean {
+  return !!TAMBO_API_KEY;
+}
Evidence
Compliance rule 2 requires every new/modified component under web/src/components/ to have a
.test.tsx with render, toHaveNoViolations() (axe), and interaction coverage. The PR adds
RegentPanel.tsx (new component exports), but no matching RegentPanel.test.tsx is present.

CLAUDE.md
web/src/components/RegentPanel.tsx[1-16]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`web/src/components/RegentPanel.tsx` is a new frontend component but it does not have a corresponding `RegentPanel.test.tsx` that includes (1) a render test, (2) an axe accessibility scan assertion using `toHaveNoViolations()`, and (3) interaction/state behavior tests.
## Issue Context
Compliance requires baseline test coverage for each new/modified component under `web/src/components/`. This PR introduces the Regent chat/provider UI, including API-key gating and a composer.
## Fix Focus Areas
- web/src/components/RegentPanel.tsx[1-159]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


2. RightPanel.test.tsx missing axe 📘 Rule violation ⛯ Reliability
Description
web/src/components/RightPanel.test.tsx includes render and interaction checks but does not run an
axe accessibility scan with toHaveNoViolations(). This violates the required accessibility
baseline for new/modified components.
Code

web/src/components/RightPanel.test.tsx[R1-149]

+// @vitest-environment jsdom
+import { render, screen, fireEvent } from "@testing-library/react";
+import "@testing-library/jest-dom";
+import { describe, it, expect, vi, beforeEach } from "vitest";
+
+const mockSwitchThread = vi.fn();
+const mockStartNewThread = vi.fn();
+
+vi.mock("@tambo-ai/react", () => ({
+  TamboProvider: ({ children }: { children: React.ReactNode }) => <div data-testid="tambo-provider">{children}</div>,
+  useTambo: () => ({
+    messages: [],
+    isStreaming: false,
+    currentThreadId: "thread-1",
+    switchThread: mockSwitchThread,
+    startNewThread: mockStartNewThread,
+    client: {},
+    thread: undefined,
+    streamingState: { status: "idle" },
+    isWaiting: false,
+    isIdle: true,
+    registerComponent: vi.fn(),
+    registerTool: vi.fn(),
+    registerTools: vi.fn(),
+    componentList: new Map(),
+    toolRegistry: new Map(),
+    initThread: vi.fn(),
+    dispatch: vi.fn(),
+    cancelRun: vi.fn(),
+    authState: { status: "identified" },
+    isIdentified: true,
+    updateThreadName: vi.fn(),
+  }),
+  useTamboThreadInput: () => ({
+    value: "",
+    setValue: vi.fn(),
+    submit: vi.fn(),
+    isPending: false,
+  }),
+  useTamboThreadList: () => ({
+    data: {
+      threads: [
+        { id: "thread-1", name: "Thread One", runStatus: "idle", createdAt: "2025-01-01", updatedAt: "2025-01-01" },
+        { id: "thread-2", name: "Thread Two", runStatus: "idle", createdAt: "2025-01-01", updatedAt: "2025-01-01" },
+      ],
+      hasMore: false,
+    },
+    isLoading: false,
+    isError: false,
+  }),
+  ComponentRenderer: () => null,
+}));
+
+const workerStub = vi.hoisted(() => {
+  return vi.fn().mockImplementation(() => ({
+    postMessage: vi.fn(),
+    terminate: vi.fn(),
+    addEventListener: vi.fn(),
+    removeEventListener: vi.fn(),
+    onmessage: null,
+    onerror: null,
+  }));
+});
+
+vi.stubGlobal("Worker", workerStub);
+
+vi.mock("../regent/tools/session-tools.js", () => ({
+  sessionTools: [],
+}));
+
+vi.mock("../regent/components/SessionCard.js", () => ({
+  sessionCardTamboComponent: {
+    name: "SessionCard",
+    description: "test",
+    component: () => null,
+    propsSchema: { type: "object" as const, properties: {}, required: [] },
+  },
+  SessionCard: () => null,
+}));
+
+vi.mock("../regent/components/TaskOverview.js", () => ({
+  taskOverviewTamboComponent: {
+    name: "TaskOverview",
+    description: "test",
+    component: () => null,
+    propsSchema: { type: "object" as const, properties: {}, required: [] },
+  },
+  TaskOverview: () => null,
+}));
+
+import { RegentSidebar } from "./RightPanel.js";
+import { useStore } from "../store.js";
+
+beforeEach(() => {
+  vi.clearAllMocks();
+  useStore.setState({
+    regentPanelOpen: true,
+    rightPanelActiveTab: "",
+  });
+});
+
+describe("RegentSidebar", () => {
+  it("renders Regent thread tabs from Tambo thread list", () => {
+    render(<RegentSidebar />);
+    expect(screen.getByTitle("Thread One")).toBeInTheDocument();
+    expect(screen.getByTitle("Thread Two")).toBeInTheDocument();
+  });
+
+  it("shows new thread button", () => {
+    render(<RegentSidebar />);
+    expect(screen.getByTitle("New Regent thread")).toBeInTheDocument();
+  });
+
+  it("renders RegentChat when panel is open", () => {
+    render(<RegentSidebar />);
+    expect(screen.getByPlaceholderText("Ask the Regent...")).toBeInTheDocument();
+  });
+
+  it("switching to a thread tab calls switchThread", () => {
+    render(<RegentSidebar />);
+    fireEvent.click(screen.getByTitle("Thread Two"));
+    expect(mockSwitchThread).toHaveBeenCalledWith("thread-2");
+  });
+
+  it("collapses panel when closed", () => {
+    useStore.setState({ regentPanelOpen: false });
+    const { container } = render(<RegentSidebar />);
+    const panelWrapper = container.querySelector(".translate-x-full");
+    expect(panelWrapper).toBeInTheDocument();
+  });
+
+  it("clicking new thread button calls startNewThread", () => {
+    render(<RegentSidebar />);
+    fireEvent.click(screen.getByTitle("New Regent thread"));
+    expect(mockStartNewThread).toHaveBeenCalled();
+  });
+
+  it("shows diamond header icon in vertical tab bar", () => {
+    render(<RegentSidebar />);
+    const tabBar = screen.getByTitle("New Regent thread").parentElement;
+    expect(tabBar).toBeInTheDocument();
+  });
+
+  it("shows numbered tabs for each thread", () => {
+    render(<RegentSidebar />);
+    expect(screen.getByText("1")).toBeInTheDocument();
+    expect(screen.getByText("2")).toBeInTheDocument();
+  });
+});
Evidence
Rule 2 requires an axe accessibility scan assertion (toHaveNoViolations()) in the component test.
The RightPanel.test.tsx file contains multiple tests but no axe(...) invocation or
expect(...).toHaveNoViolations() assertion.

CLAUDE.md
web/src/components/RightPanel.test.tsx[1-5]
web/src/components/RightPanel.test.tsx[102-149]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`web/src/components/RightPanel.test.tsx` lacks the required axe accessibility test (`expect(results).toHaveNoViolations()`).
## Issue Context
Other component tests in the repo use `vitest-axe` (dynamic import) to enforce a baseline accessibility check. Rule 2 requires this for each new/modified component test.
## Fix Focus Areas
- web/src/components/RightPanel.test.tsx[1-149]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


3. Tambo key exposed client 🐞 Bug ⛨ Security
Description
Regent reads VITE_TAMBO_API_KEY from the Vite client environment and passes it to TamboProvider,
which means the key is shipped to every browser. If the key is privileged, it can be extracted and
abused (billing/tenant access).
Code

web/src/components/RegentPanel.tsx[R12-16]

+const TAMBO_API_KEY = (import.meta as unknown as Record<string, Record<string, string>>).env?.VITE_TAMBO_API_KEY;
+
+export function hasTamboApiKey(): boolean {
+  return !!TAMBO_API_KEY;
+}
Evidence
The PR introduces a Vite-exposed env var for a Tambo API key and uses it directly in the React
client when creating the TamboProvider.

web/.env.example[1-3]
web/src/components/RegentPanel.tsx[12-16]
web/src/components/RegentPanel.tsx[139-145]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`VITE_TAMBO_API_KEY` is consumed in the browser and passed to `TamboProvider`, which ships the key to all clients. If the key is privileged, it can be extracted from the JS bundle/devtools and reused.
### Issue Context
This app already has an authenticated backend API layer (`/api` with Bearer auth). Prefer using that backend to hold third-party secrets and/or mint scoped, short-lived tokens.
### Fix Focus Areas
- web/src/components/RegentPanel.tsx[12-16]
- web/src/components/RegentPanel.tsx[139-145]
- web/.env.example[1-3]
- web/src/api.ts[5-13]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View more (1)
4. Hard-coded Tambo userKey 🐞 Bug ⛨ Security
Description
TamboProvider is initialized with a constant userKey ("companion-user"), so different authenticated
users/devices can share the same Tambo identity and potentially see each other’s threads/history.
This is a privacy/security risk for an app with auth tokens.
Code

web/src/components/RegentPanel.tsx[R140-144]

+    <TamboProvider
+      apiKey={TAMBO_API_KEY}
+      userKey="companion-user"
+      tools={sessionTools}
+      components={[sessionCardTamboComponent, taskOverviewTamboComponent]}
Evidence
The provider uses a single shared Tambo user identity while the application itself supports
authenticated users via an auth token, implying multiple principals should be isolated.

web/src/components/RegentPanel.tsx[139-145]
web/src/store.ts[33-44]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`userKey` is hard-coded to a constant value, which collapses all users into one shared Tambo identity and can mix threads/history across users.
### Issue Context
The UI uses an auth token (`companion_auth_token`) and tracks authentication state in the store, so multiple distinct principals are expected.
### Fix Focus Areas
- web/src/components/RegentPanel.tsx[139-145]
- web/src/store.ts[33-44]
- web/src/api.ts[5-13]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

5. New tests lack comments 📘 Rule violation ⛯ Reliability
Description
Newly added test files do not include comments documenting what they validate and important
context/edge cases. This reduces maintainability and violates the test documentation requirement.
Code

web/src/components/RightPanel.test.tsx[R1-35]

+// @vitest-environment jsdom
+import { render, screen, fireEvent } from "@testing-library/react";
+import "@testing-library/jest-dom";
+import { describe, it, expect, vi, beforeEach } from "vitest";
+
+const mockSwitchThread = vi.fn();
+const mockStartNewThread = vi.fn();
+
+vi.mock("@tambo-ai/react", () => ({
+  TamboProvider: ({ children }: { children: React.ReactNode }) => <div data-testid="tambo-provider">{children}</div>,
+  useTambo: () => ({
+    messages: [],
+    isStreaming: false,
+    currentThreadId: "thread-1",
+    switchThread: mockSwitchThread,
+    startNewThread: mockStartNewThread,
+    client: {},
+    thread: undefined,
+    streamingState: { status: "idle" },
+    isWaiting: false,
+    isIdle: true,
+    registerComponent: vi.fn(),
+    registerTool: vi.fn(),
+    registerTools: vi.fn(),
+    componentList: new Map(),
+    toolRegistry: new Map(),
+    initThread: vi.fn(),
+    dispatch: vi.fn(),
+    cancelRun: vi.fn(),
+    authState: { status: "identified" },
+    isIdentified: true,
+    updateThreadName: vi.fn(),
+  }),
+  useTamboThreadInput: () => ({
+    value: "",
Evidence
Rule 5 requires newly created tests to include comments explaining intent and important context/edge
cases. The new test files shown contain test cases but no explanatory comments beyond the
environment directive.

CLAUDE.md
web/src/components/RightPanel.test.tsx[1-8]
web/src/regent/components/SessionCard.test.tsx[1-35]
web/src/regent/components/TaskOverview.test.tsx[1-25]
web/src/regent/tools/session-tools.test.ts[1-16]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
New test files were added without comments documenting what they validate and important context/edge cases.
## Issue Context
Rule 5 requires comments for newly created tests to improve long-term maintainability. This PR introduces several new test suites (RightPanel/Regent components and tools) that rely on non-obvious mocking (e.g., `Worker`, `@tambo-ai/react` hook mocks).
## Fix Focus Areas
- web/src/components/RightPanel.test.tsx[1-149]
- web/src/regent/components/SessionCard.test.tsx[1-80]
- web/src/regent/components/TaskOverview.test.tsx[1-89]
- web/src/regent/tools/session-tools.test.ts[1-259]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


6. RegentChat missing Playground mock 📘 Rule violation ⛯ Reliability
Description
The new Regent chat/sidebar UI is part of a message/chat flow but is not represented with mocked
states in web/src/components/Playground.tsx. This reduces the ability to manually review Regent
chat UI states in the centralized playground.
Code

web/src/components/RightPanel.tsx[R85-117]

+export function RegentSidebar() {
+  const regentPanelOpen = useStore((s) => s.regentPanelOpen);
+  const hasApiKey = hasTamboApiKey();
+
+  if (!hasApiKey) return null;
+
+  return (
+    <RegentProvider>
+      {/* Mobile overlay backdrop */}
+      {regentPanelOpen && (
+        <div
+          className="fixed inset-0 bg-black/30 z-30 lg:hidden"
+          onClick={() => useStore.getState().setRegentPanelOpen(false)}
+        />
+      )}
+
+      <div
+        className={`
+          fixed inset-y-0 right-0 lg:relative lg:inset-auto z-40 lg:z-auto
+          h-full shrink-0 transition-all duration-200 pt-safe lg:pt-0
+          ${regentPanelOpen ? "w-full lg:w-[340px] translate-x-0" : "w-0 translate-x-full lg:w-0 lg:translate-x-full"}
+          overflow-hidden
+        `}
+      >
+        <div className="flex h-full w-full">
+          {/* Chat content area */}
+          <div className="flex-1 min-w-0 overflow-hidden border-l border-cc-border">
+            <RegentChat />
+          </div>
+
+          {/* Vertical tab bar */}
+          <VerticalTabBar />
+        </div>
Evidence
Rule 6 requires message/chat-flow UI components to be represented in Playground.tsx with mocked
states. The PR adds the Regent chat UI via RegentSidebar rendering RegentChat, while the
Playground render sections shown do not include any Regent/RightPanel mock state or preview.

CLAUDE.md
web/src/components/RightPanel.tsx[85-117]
web/src/components/Playground.tsx[645-666]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
Regent chat/sidebar UI was added but `web/src/components/Playground.tsx` was not updated to include mocked Regent chat states.
## Issue Context
Rule 6 requires message/chat-flow UI components to be represented in the Playground for manual review. Regent introduces a new chat feed + composer and should have a mock preview similar to other chat/message components.
## Fix Focus Areas
- web/src/components/RightPanel.tsx[85-121]
- web/src/components/RegentPanel.tsx[18-117]
- web/src/components/Playground.tsx[612-760]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


7. RegentPanel imported in TopBar 🐞 Bug ➹ Performance
Description
TopBar imports hasTamboApiKey from RegentPanel, which also imports @tambo-ai/react, making
Regent/Tambo code more likely to be included in the initial TopBar bundle even when Regent is never
opened. This can increase initial load cost and complicate non-browser/test environments unless
carefully tree-shaken/lazy-loaded.
Code

web/src/components/TopBar.tsx[5]

+import { hasTamboApiKey } from "./RegentPanel.js";
Evidence
TopBar eagerly imports a helper from RegentPanel; that module imports Tambo React bindings, tying
Regent dependencies to a core, always-rendered component.

web/src/components/TopBar.tsx[1-6]
web/src/components/RegentPanel.tsx[2-7]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`TopBar` imports from `RegentPanel`, which imports `@tambo-ai/react`. This couples a core, always-mounted component to potentially heavy Regent/Tambo dependencies.
### Issue Context
Even if bundlers tree-shake, the import structure makes it easier to accidentally retain more code in the entry bundle and harder to keep Regent optional.
### Fix Focus Areas
- web/src/components/TopBar.tsx[1-6]
- web/src/components/RegentPanel.tsx[2-7]
- web/src/components/TopBar.tsx[260-275]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


View more (1)
8. API key gating inconsistent 🐞 Bug ⛯ Reliability
Description
hasTamboApiKey only checks truthiness (no trim), and RegentSidebar returns null when missing, which
prevents the user-facing “Regent requires a Tambo API key” UI from ever being shown via the sidebar.
A whitespace-only key will be treated as present and can lead to confusing runtime failures.
Code

web/src/components/RightPanel.tsx[R85-90]

+export function RegentSidebar() {
+  const regentPanelOpen = useStore((s) => s.regentPanelOpen);
+  const hasApiKey = hasTamboApiKey();
+
+  if (!hasApiKey) return null;
+
Evidence
RegentProvider implements a helpful missing-key screen, but RegentSidebar short-circuits before
rendering it; additionally, key validation is looser than existing env handling patterns (which
trim).

web/src/components/RegentPanel.tsx[12-16]
web/src/components/RegentPanel.tsx[124-137]
web/src/components/RightPanel.tsx[85-90]
web/src/analytics.ts[9-13]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The API-key presence check is too lax (`!!key`), and the sidebar short-circuits on missing keys, preventing the intended missing-key UI from being reachable.
### Issue Context
Other env-based config in the app uses `.trim()` and treats whitespace as missing.
### Fix Focus Areas
- web/src/components/RegentPanel.tsx[12-16]
- web/src/components/RegentPanel.tsx[124-137]
- web/src/components/RightPanel.tsx[85-90]
- web/src/components/TopBar.tsx[260-275]
- web/src/analytics.ts[9-13]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

ⓘ The new review experience is currently in Beta. Learn more

Grey Divider

Qodo Logo

@socket-security
Copy link

socket-security bot commented Mar 3, 2026

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Added@​tambo-ai/​client@​0.0.17610010090100
Added@​tambo-ai/​typescript-sdk@​0.93.17810010099100
Added@​tambo-ai/​react@​1.1.07910010099100
Added@​tanstack/​react-query@​5.90.21991008898100

View full report

@gemini-code-assist
Copy link

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request significantly enhances the user experience by transforming the Regent orchestrator into a persistent, interactive right sidebar. This change integrates AI-powered chat capabilities, allowing users to manage and query agent sessions directly from a convenient panel. The update streamlines workflow by providing quick access to session details and tasks, moving away from a full-page view to a more integrated and responsive design.

Highlights

  • Regent Orchestrator UI Rework: The full-page Regent route has been replaced with a persistent right sidebar panel, improving accessibility and integration within the application layout.
  • Tambo AI Integration: The Regent panel now features Tambo-powered AI chat, enabling session-aware interactions. This includes the addition of Tambo AI client, React, and TypeScript SDK dependencies.
  • New UI Components for AI Interaction: Introduced SessionCard and TaskOverview components, which are custom Tambo components designed to display agent session information and aggregated task summaries within the AI chat interface.
  • TopBar Toggle for Regent Panel: A new toggle button (diamond icon) has been added to the TopBar to control the visibility of the Regent right sidebar, consistent with existing sidebar/context panel toggle patterns.
  • Session-Aware AI Tools: A suite of new Tambo tools (listSessions, getSessionMessages, getSessionTasks, getSessionStatus, getSessionDiff, getAllSessionsSummary) has been implemented to allow the AI orchestrator to query and interact with active agent session data.
Changelog
  • web/.env.example
    • Added VITE_TAMBO_API_KEY environment variable for Tambo AI integration.
  • web/package.json
    • Added @tambo-ai/client, @tambo-ai/react, and @tambo-ai/typescript-sdk dependencies.
    • Added @tanstack/react-query dependency.
  • web/src/App.test.tsx
    • Mocked RegentSidebar component for testing purposes.
  • web/src/App.tsx
    • Imported RegentSidebar component.
    • Removed the old task panel open button and mobile overlay backdrop logic.
    • Integrated RegentSidebar as a persistent component in the main application layout.
  • web/src/components/RegentPanel.tsx
    • Added RegentPanel component, which provides the core TamboProvider and RegentChat functionality.
    • Implemented RegentChat for displaying AI messages and handling user input.
    • Included logic to check for VITE_TAMBO_API_KEY and display a warning if missing.
  • web/src/components/RightPanel.test.tsx
    • Added comprehensive tests for the RegentSidebar component, covering thread rendering, new thread creation, and panel collapse behavior.
  • web/src/components/RightPanel.tsx
    • Added RegentSidebar component, which orchestrates the Regent chat interface.
    • Implemented VerticalTabBar for managing multiple Regent threads.
    • Managed panel visibility and responsiveness for mobile and desktop views.
  • web/src/components/TopBar.test.tsx
    • Mocked hasTamboApiKey function for testing the TopBar component.
  • web/src/components/TopBar.tsx
    • Imported hasTamboApiKey function.
    • Added state variables regentPanelOpen and setRegentPanelOpen to manage the Regent panel's visibility.
    • Included a new toggle button in the TopBar to open and close the Regent panel.
  • web/src/regent/components/SessionCard.test.tsx
    • Added tests for the SessionCard component, verifying rendering of session details, status, and navigation behavior.
  • web/src/regent/components/SessionCard.tsx
    • Added SessionCard component to display a summary of an agent session.
    • Defined sessionCardTamboComponent for integration with Tambo AI, including its props schema and description.
  • web/src/regent/components/TaskOverview.test.tsx
    • Added tests for the TaskOverview component, checking summary counts, task display, and overflow handling.
  • web/src/regent/components/TaskOverview.tsx
    • Added TaskOverview component to present an aggregated view of tasks across multiple sessions.
    • Defined taskOverviewTamboComponent for integration with Tambo AI, including its props schema and description.
  • web/src/regent/tools/session-tools.test.ts
    • Added tests for the various session-related Tambo tools, ensuring correct data retrieval and filtering.
  • web/src/regent/tools/session-tools.ts
    • Added a collection of Tambo tools (listSessions, getSessionMessages, getSessionTasks, getSessionStatus, getSessionDiff, getAllSessionsSummary) to enable AI interaction with session data.
    • Implemented logic to fetch and format session-related information from the application store.
  • web/src/store.ts
    • Added regentPanelOpen and rightPanelActiveTab properties to the AppState interface.
    • Added setRegentPanelOpen and setRightPanelActiveTab actions to manage the state of the Regent panel.
    • Initialized regentPanelOpen based on window width and rightPanelActiveTab in the initial state.
Activity
  • All 118 test suites, including new RightPanel tests, passed successfully (3131 tests).
  • The production build completed without issues.
  • Visual QA confirmed that the Regent panel opens and closes correctly via the TopBar toggle button.
  • Visual QA verified that vertical thread tabs correctly switch between Regent threads.
  • Visual QA confirmed that the context panel and Regent panel toggle independently.
  • TypeScript checks reported 0 errors in changed files, with pre-existing type issues only in unrelated test files.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a significant new feature: the Regent orchestrator as a persistent right sidebar. The implementation is comprehensive, adding new components, AI tools via Tambo, and extensive tests. The code is generally well-structured. I've identified one high-severity issue concerning a hardcoded user key that could lead to data leakage, and a couple of medium-severity issues related to a potential bug from an incomplete useEffect dependency array and a schema inconsistency. Addressing these points will improve the robustness and security of the new feature.

return (
<TamboProvider
apiKey={TAMBO_API_KEY}
userKey="companion-user"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The userKey for TamboProvider is hardcoded to "companion-user". If this application is used by multiple users, they will all share the same Tambo user profile, including chat threads and history. This is a potential data privacy and security issue.

The userKey should be a unique identifier for each authenticated user. You could use a user ID from your authentication system, for example.

<TamboProvider
  apiKey={TAMBO_API_KEY}
  userKey={getUniqueUserId()} // e.g., from auth context or store
  tools={sessionTools}
  components={[sessionCardTamboComponent, taskOverviewTamboComponent]}
>

Comment on lines +33 to +37
useEffect(() => {
if (currentThreadId && currentThreadId !== activeTab) {
setActiveTab(currentThreadId);
}
}, [currentThreadId]);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The useEffect hook has an incomplete dependency array. It is missing activeTab. This could lead to using a stale value of activeTab inside the effect's closure, potentially causing bugs where the UI does not update as expected when the current thread changes.

Suggested change
useEffect(() => {
if (currentThreadId && currentThreadId !== activeTab) {
setActiveTab(currentThreadId);
}
}, [currentThreadId]);
useEffect(() => {
if (currentThreadId && currentThreadId !== activeTab) {
setActiveTab(currentThreadId);
}
}, [currentThreadId, activeTab, setActiveTab]);

Comment on lines +108 to +116
items: {
type: "object" as const,
properties: {
sessionName: { type: "string" as const },
subject: { type: "string" as const },
status: { type: "string" as const },
activeForm: { type: "string" as const },
},
},

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The JSON schema for the tasks array items is missing the required field. This makes all properties of a task item optional from the schema's perspective, which is inconsistent with the TaskEntry TypeScript interface where sessionName, subject, and status are required. This could lead to unexpected behavior if the AI provides incomplete task objects.

        items: {
          type: "object" as const,
          properties: {
            sessionName: { type: "string" as const },
            subject: { type: "string" as const },
            status: { type: "string" as const },
            activeForm: { type: "string" as const },
          },
          required: ["sessionName", "subject", "status"],
        },

Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

4 issues found across 16 files

Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name="web/src/regent/components/TaskOverview.tsx">

<violation number="1" location="web/src/regent/components/TaskOverview.tsx:113">
P2: `status` is too loosely validated in `propsSchema`; unsupported values are accepted but then omitted from all rendered groups.</violation>
</file>

<file name="web/src/components/RegentPanel.tsx">

<violation number="1" location="web/src/components/RegentPanel.tsx:142">
P1: Hardcoded `userKey` makes all users share the same Tambo identity, which can leak/mix thread data across users.</violation>
</file>

<file name="web/src/regent/tools/session-tools.ts">

<violation number="1" location="web/src/regent/tools/session-tools.ts:17">
P2: Tool implementations return stringified JSON while `outputSchema` declares structured object output, creating a schema/output type mismatch.</violation>
</file>

<file name="web/src/regent/components/SessionCard.tsx">

<violation number="1" location="web/src/regent/components/SessionCard.tsx:129">
P2: `propsSchema` incorrectly rejects nullable values for `currentTask` and `gitBranch` even though the component contract allows `null`.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

return (
<TamboProvider
apiKey={TAMBO_API_KEY}
userKey="companion-user"
Copy link

@cubic-dev-ai cubic-dev-ai bot Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1: Hardcoded userKey makes all users share the same Tambo identity, which can leak/mix thread data across users.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At web/src/components/RegentPanel.tsx, line 142:

<comment>Hardcoded `userKey` makes all users share the same Tambo identity, which can leak/mix thread data across users.</comment>

<file context>
@@ -0,0 +1,159 @@
+  return (
+    <TamboProvider
+      apiKey={TAMBO_API_KEY}
+      userKey="companion-user"
+      tools={sessionTools}
+      components={[sessionCardTamboComponent, taskOverviewTamboComponent]}
</file context>
Fix with Cubic

properties: {
sessionName: { type: "string" as const },
subject: { type: "string" as const },
status: { type: "string" as const },
Copy link

@cubic-dev-ai cubic-dev-ai bot Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: status is too loosely validated in propsSchema; unsupported values are accepted but then omitted from all rendered groups.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At web/src/regent/components/TaskOverview.tsx, line 113:

<comment>`status` is too loosely validated in `propsSchema`; unsupported values are accepted but then omitted from all rendered groups.</comment>

<file context>
@@ -0,0 +1,125 @@
+          properties: {
+            sessionName: { type: "string" as const },
+            subject: { type: "string" as const },
+            status: { type: "string" as const },
+            activeForm: { type: "string" as const },
+          },
</file context>
Fix with Cubic

tool: async () => {
const store = getStore();
const sessions = store.sdkSessions.filter((s) => !s.archived);
return JSON.stringify(
Copy link

@cubic-dev-ai cubic-dev-ai bot Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: Tool implementations return stringified JSON while outputSchema declares structured object output, creating a schema/output type mismatch.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At web/src/regent/tools/session-tools.ts, line 17:

<comment>Tool implementations return stringified JSON while `outputSchema` declares structured object output, creating a schema/output type mismatch.</comment>

<file context>
@@ -0,0 +1,261 @@
+  tool: async () => {
+    const store = getStore();
+    const sessions = store.sdkSessions.filter((s) => !s.archived);
+    return JSON.stringify(
+      sessions.map((s) => ({
+        sessionId: s.sessionId,
</file context>
Fix with Cubic

type: "number" as const,
description: "Number of pending permission requests",
},
currentTask: {
Copy link

@cubic-dev-ai cubic-dev-ai bot Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2: propsSchema incorrectly rejects nullable values for currentTask and gitBranch even though the component contract allows null.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At web/src/regent/components/SessionCard.tsx, line 129:

<comment>`propsSchema` incorrectly rejects nullable values for `currentTask` and `gitBranch` even though the component contract allows `null`.</comment>

<file context>
@@ -0,0 +1,149 @@
+        type: "number" as const,
+        description: "Number of pending permission requests",
+      },
+      currentTask: {
+        type: "string" as const,
+        description: "Currently active task description, or null",
</file context>
Fix with Cubic

Copy link

@entelligence-ai-pr-reviews entelligence-ai-pr-reviews bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Walkthrough

This PR integrates Tambo AI chat functionality into the web application through a new collapsible Regent sidebar panel. The implementation adds the Tambo AI SDK and React Query dependencies, creates a chat interface with thread management, and implements six session management tools for AI agent interactions. The sidebar features responsive design with mobile/desktop layouts, thread navigation tabs, and conditional rendering based on API key presence. State management is extended to control panel visibility and active tabs. Comprehensive test coverage is added for all new components, and the TopBar receives a toggle button for panel control.

Changes

File(s) Summary
web/.env.example Added VITE_TAMBO_API_KEY environment variable for Tambo service integration.
web/package.json Added four new dependencies: @tambo-ai/client, @tambo-ai/react, @tambo-ai/typescript-sdk, and @tanstack/react-query.
web/src/components/RegentPanel.tsx Introduced new Regent AI chat panel with three components: RegentChat (message display and streaming), RegentProvider (Tambo SDK wrapper with session tools), and RegentPanel (main export). Includes hasTamboApiKey() utility function.
web/src/components/RightPanel.tsx Implemented collapsible sidebar with VerticalTabBar (thread navigation with up to 20 tabs) and RegentSidebar (responsive container with mobile/desktop layouts). Integrates Tambo hooks and Zustand store for state management.
web/src/regent/components/SessionCard.tsx Created SessionCard component displaying session metadata with real-time status indicators, helper functions for status visualization, and Tambo component registry integration.
web/src/regent/components/TaskOverview.tsx Added TaskOverview component with status-based task grouping (in-progress, pending, completed), truncation logic, and Tambo component configuration export.
web/src/regent/tools/session-tools.ts Implemented six AI agent tools: listSessions, getSessionMessages, getSessionTasks, getSessionStatus, getSessionDiff, and getAllSessionsSummary with JSON schemas for type safety.
web/src/App.tsx Replaced conditional task panel toggle button with persistent RegentSidebar component, removing desktop-only floating button with 'Context' label.
web/src/components/TopBar.tsx Added Regent panel toggle button with conditional rendering based on API key presence, using diamond-shaped SVG icon and active/inactive styling.
web/src/store.ts Added regentPanelOpen (defaults to true for viewports >= 1280px) and rightPanelActiveTab state properties with corresponding setters and reset logic.
web/src/App.test.tsx
web/src/components/TopBar.test.tsx Added mocks for RegentSidebar and hasTamboApiKey function to isolate component testing.
web/src/components/RightPanel.test.tsx
web/src/regent/components/SessionCard.test.tsx
web/src/regent/components/TaskOverview.test.tsx
web/src/regent/tools/session-tools.test.ts Added comprehensive test suites covering rendering, user interactions, state management, conditional logic, and edge cases using Vitest and React Testing Library.

🔗 Cross-Repository Impact Analysis

Enable automatic detection of breaking changes across your dependent repositories. → Set up now

Learn more about Cross-Repository Analysis

What It Does

  • Automatically identifies repositories that depend on this code
  • Analyzes potential breaking changes across your entire codebase
  • Provides risk assessment before merging to prevent cross-repo issues

How to Enable

  1. Visit Settings → Code Management
  2. Configure repository dependencies
  3. Future PRs will automatically include cross-repo impact analysis!

Benefits

  • 🛡️ Prevent breaking changes across repositories
  • 🔍 Catch integration issues before they reach production
  • 📊 Better visibility into your multi-repo architecture

Comment on lines +126 to +132
type: "number" as const,
description: "Number of pending permission requests",
},
currentTask: {
type: "string" as const,
description: "Currently active task description, or null",
},

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correctness: The propsSchema for currentTask and gitBranch defines the type as string, but the SessionCardProps interface and the schema's own descriptions allow null. This mismatch causes valid null values to be rejected by validation or tooling consuming this schema. Update the schema to accept null.

🤖 AI Agent Prompt for Cursor/Windsurf

📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue

In `web/src/regent/components/SessionCard.tsx` around lines 126-132, update the `propsSchema` definitions for `currentTask` and `gitBranch` to allow `null` (e.g., `type: ["string", "null"] as const`). This keeps the schema consistent with the component props that allow `null`.

Comment on lines +35 to +37
outputSchema: {
type: "object" as const,
properties: {},

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correctness: ⚠️ outputSchema declares an object, but the tool returns a JSON string. This type mismatch violates the tool's contract and leads to runtime failures during output validation. Align the schema with the actual return type (or return a real object/array). Apply the same fix to the other new tools returning JSON.stringify(...).

🤖 AI Agent Prompt for Cursor/Windsurf

📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue

In `web/src/regent/tools/session-tools.ts` around lines 35-37, the tool returns `JSON.stringify(...)` but `outputSchema` is declared as an object. Update `outputSchema` to `type: "string"` (or return a real object) to avoid output validation errors. Apply the same alignment to all newly added tools that return JSON strings.

Comment on lines +1 to +16
import { useRef, useEffect, type ReactNode } from "react";
import {
TamboProvider,
useTambo,
useTamboThreadInput,
ComponentRenderer,
} from "@tambo-ai/react";
import { sessionTools } from "../regent/tools/session-tools.js";
import { sessionCardTamboComponent } from "../regent/components/SessionCard.js";
import { taskOverviewTamboComponent } from "../regent/components/TaskOverview.js";

const TAMBO_API_KEY = (import.meta as unknown as Record<string, Record<string, string>>).env?.VITE_TAMBO_API_KEY;

export function hasTamboApiKey(): boolean {
return !!TAMBO_API_KEY;
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

1. regentpanel missing .test.tsx 📘 Rule violation ⛯ Reliability

web/src/components/RegentPanel.tsx is a new component but there is no corresponding
RegentPanel.test.tsx providing render, axe, and interaction coverage. This violates the baseline
frontend component test requirement and risks regressions in the Regent chat/provider UI.
Agent Prompt
## Issue description
`web/src/components/RegentPanel.tsx` is a new frontend component but it does not have a corresponding `RegentPanel.test.tsx` that includes (1) a render test, (2) an axe accessibility scan assertion using `toHaveNoViolations()`, and (3) interaction/state behavior tests.

## Issue Context
Compliance requires baseline test coverage for each new/modified component under `web/src/components/`. This PR introduces the Regent chat/provider UI, including API-key gating and a composer.

## Fix Focus Areas
- web/src/components/RegentPanel.tsx[1-159]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +1 to +149
// @vitest-environment jsdom
import { render, screen, fireEvent } from "@testing-library/react";
import "@testing-library/jest-dom";
import { describe, it, expect, vi, beforeEach } from "vitest";

const mockSwitchThread = vi.fn();
const mockStartNewThread = vi.fn();

vi.mock("@tambo-ai/react", () => ({
TamboProvider: ({ children }: { children: React.ReactNode }) => <div data-testid="tambo-provider">{children}</div>,
useTambo: () => ({
messages: [],
isStreaming: false,
currentThreadId: "thread-1",
switchThread: mockSwitchThread,
startNewThread: mockStartNewThread,
client: {},
thread: undefined,
streamingState: { status: "idle" },
isWaiting: false,
isIdle: true,
registerComponent: vi.fn(),
registerTool: vi.fn(),
registerTools: vi.fn(),
componentList: new Map(),
toolRegistry: new Map(),
initThread: vi.fn(),
dispatch: vi.fn(),
cancelRun: vi.fn(),
authState: { status: "identified" },
isIdentified: true,
updateThreadName: vi.fn(),
}),
useTamboThreadInput: () => ({
value: "",
setValue: vi.fn(),
submit: vi.fn(),
isPending: false,
}),
useTamboThreadList: () => ({
data: {
threads: [
{ id: "thread-1", name: "Thread One", runStatus: "idle", createdAt: "2025-01-01", updatedAt: "2025-01-01" },
{ id: "thread-2", name: "Thread Two", runStatus: "idle", createdAt: "2025-01-01", updatedAt: "2025-01-01" },
],
hasMore: false,
},
isLoading: false,
isError: false,
}),
ComponentRenderer: () => null,
}));

const workerStub = vi.hoisted(() => {
return vi.fn().mockImplementation(() => ({
postMessage: vi.fn(),
terminate: vi.fn(),
addEventListener: vi.fn(),
removeEventListener: vi.fn(),
onmessage: null,
onerror: null,
}));
});

vi.stubGlobal("Worker", workerStub);

vi.mock("../regent/tools/session-tools.js", () => ({
sessionTools: [],
}));

vi.mock("../regent/components/SessionCard.js", () => ({
sessionCardTamboComponent: {
name: "SessionCard",
description: "test",
component: () => null,
propsSchema: { type: "object" as const, properties: {}, required: [] },
},
SessionCard: () => null,
}));

vi.mock("../regent/components/TaskOverview.js", () => ({
taskOverviewTamboComponent: {
name: "TaskOverview",
description: "test",
component: () => null,
propsSchema: { type: "object" as const, properties: {}, required: [] },
},
TaskOverview: () => null,
}));

import { RegentSidebar } from "./RightPanel.js";
import { useStore } from "../store.js";

beforeEach(() => {
vi.clearAllMocks();
useStore.setState({
regentPanelOpen: true,
rightPanelActiveTab: "",
});
});

describe("RegentSidebar", () => {
it("renders Regent thread tabs from Tambo thread list", () => {
render(<RegentSidebar />);
expect(screen.getByTitle("Thread One")).toBeInTheDocument();
expect(screen.getByTitle("Thread Two")).toBeInTheDocument();
});

it("shows new thread button", () => {
render(<RegentSidebar />);
expect(screen.getByTitle("New Regent thread")).toBeInTheDocument();
});

it("renders RegentChat when panel is open", () => {
render(<RegentSidebar />);
expect(screen.getByPlaceholderText("Ask the Regent...")).toBeInTheDocument();
});

it("switching to a thread tab calls switchThread", () => {
render(<RegentSidebar />);
fireEvent.click(screen.getByTitle("Thread Two"));
expect(mockSwitchThread).toHaveBeenCalledWith("thread-2");
});

it("collapses panel when closed", () => {
useStore.setState({ regentPanelOpen: false });
const { container } = render(<RegentSidebar />);
const panelWrapper = container.querySelector(".translate-x-full");
expect(panelWrapper).toBeInTheDocument();
});

it("clicking new thread button calls startNewThread", () => {
render(<RegentSidebar />);
fireEvent.click(screen.getByTitle("New Regent thread"));
expect(mockStartNewThread).toHaveBeenCalled();
});

it("shows diamond header icon in vertical tab bar", () => {
render(<RegentSidebar />);
const tabBar = screen.getByTitle("New Regent thread").parentElement;
expect(tabBar).toBeInTheDocument();
});

it("shows numbered tabs for each thread", () => {
render(<RegentSidebar />);
expect(screen.getByText("1")).toBeInTheDocument();
expect(screen.getByText("2")).toBeInTheDocument();
});
});

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

2. rightpanel.test.tsx missing axe 📘 Rule violation ⛯ Reliability

web/src/components/RightPanel.test.tsx includes render and interaction checks but does not run an
axe accessibility scan with toHaveNoViolations(). This violates the required accessibility
baseline for new/modified components.
Agent Prompt
## Issue description
`web/src/components/RightPanel.test.tsx` lacks the required axe accessibility test (`expect(results).toHaveNoViolations()`).

## Issue Context
Other component tests in the repo use `vitest-axe` (dynamic import) to enforce a baseline accessibility check. Rule 2 requires this for each new/modified component test.

## Fix Focus Areas
- web/src/components/RightPanel.test.tsx[1-149]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +12 to +16
const TAMBO_API_KEY = (import.meta as unknown as Record<string, Record<string, string>>).env?.VITE_TAMBO_API_KEY;

export function hasTamboApiKey(): boolean {
return !!TAMBO_API_KEY;
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

3. Tambo key exposed client 🐞 Bug ⛨ Security

Regent reads VITE_TAMBO_API_KEY from the Vite client environment and passes it to TamboProvider,
which means the key is shipped to every browser. If the key is privileged, it can be extracted and
abused (billing/tenant access).
Agent Prompt
### Issue description
`VITE_TAMBO_API_KEY` is consumed in the browser and passed to `TamboProvider`, which ships the key to all clients. If the key is privileged, it can be extracted from the JS bundle/devtools and reused.

### Issue Context
This app already has an authenticated backend API layer (`/api` with Bearer auth). Prefer using that backend to hold third-party secrets and/or mint scoped, short-lived tokens.

### Fix Focus Areas
- web/src/components/RegentPanel.tsx[12-16]
- web/src/components/RegentPanel.tsx[139-145]
- web/.env.example[1-3]
- web/src/api.ts[5-13]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Comment on lines +140 to +144
<TamboProvider
apiKey={TAMBO_API_KEY}
userKey="companion-user"
tools={sessionTools}
components={[sessionCardTamboComponent, taskOverviewTamboComponent]}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Action required

4. Hard-coded tambo userkey 🐞 Bug ⛨ Security

TamboProvider is initialized with a constant userKey ("companion-user"), so different authenticated
users/devices can share the same Tambo identity and potentially see each other’s threads/history.
This is a privacy/security risk for an app with auth tokens.
Agent Prompt
### Issue description
`userKey` is hard-coded to a constant value, which collapses all users into one shared Tambo identity and can mix threads/history across users.

### Issue Context
The UI uses an auth token (`companion_auth_token`) and tracks authentication state in the store, so multiple distinct principals are expected.

### Fix Focus Areas
- web/src/components/RegentPanel.tsx[139-145]
- web/src/store.ts[33-44]
- web/src/api.ts[5-13]

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools

Copy link

@chatgpt-codex-connector chatgpt-codex-connector bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: bc9552a24b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +103 to +105
fixed inset-y-0 right-0 lg:relative lg:inset-auto z-40 lg:z-auto
h-full shrink-0 transition-all duration-200 pt-safe lg:pt-0
${regentPanelOpen ? "w-full lg:w-[340px] translate-x-0" : "w-0 translate-x-full lg:w-0 lg:translate-x-full"}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Add a mobile close affordance for the Regent sidebar

On small screens this panel expands to w-full (lg:w-[340px] only applies on desktop), so it covers the entire viewport; because the only close path is the backdrop click behind it and there is no in-panel close button, users who open Regent on mobile can get stuck with no visible way to dismiss it except reloading. This is reproducible whenever VITE_TAMBO_API_KEY is set and the Regent toggle is used on a phone-sized viewport.

Useful? React with 👍 / 👎.

Comment on lines +103 to +106
it("renders Regent thread tabs from Tambo thread list", () => {
render(<RegentSidebar />);
expect(screen.getByTitle("Thread One")).toBeInTheDocument();
expect(screen.getByTitle("Thread Two")).toBeInTheDocument();

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Decouple RightPanel tests from Tambo env configuration

These tests assume RegentSidebar renders, but the component short-circuits to null when hasTamboApiKey() is false; since this file does not mock that guard (unlike TopBar.test.tsx), the assertions become environment-dependent and will fail in CI configurations without VITE_TAMBO_API_KEY (I checked .github/workflows/ci.yml, which only injects PostHog vars for test/build jobs).

Useful? React with 👍 / 👎.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (8)
web/src/components/TopBar.test.tsx (1)

15-17: Add test coverage for Regent panel toggle.

The mock sets hasTamboApiKey to always return false, which prevents testing the Regent toggle functionality. Consider adding a test case that mocks hasTamboApiKey to return true and verifies:

  1. The Regent toggle button is rendered
  2. Clicking the button calls setRegentPanelOpen
  3. Active/inactive styling is applied correctly

Also, the mock store state (lines 19-39) should include regentPanelOpen and setRegentPanelOpen to prevent potential runtime errors if hasTamboApiKey returns true:

regentPanelOpen: false,
setRegentPanelOpen: vi.fn(),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/components/TopBar.test.tsx` around lines 15 - 17, Update the test to
cover the Regent panel toggle by adding a case where the mocked hasTamboApiKey
returns true and asserting the toggle behavior: adjust the mock of
hasTamboApiKey to return true for that test, ensure the mocked store includes
regentPanelOpen (e.g., false) and setRegentPanelOpen (a vi.fn()) so the
component can render, then verify the Regent toggle button is rendered, simulate
a click and assert setRegentPanelOpen was called, and finally assert the button
receives the correct active/inactive styling after toggling; reference the
mocked function hasTamboApiKey and the store props regentPanelOpen and
setRegentPanelOpen when making these changes.
web/src/components/RegentPanel.tsx (2)

12-12: Simplify the Vite environment variable access.

The type assertion chain is verbose. Vite provides built-in types for import.meta.env. Consider using the standard pattern:

-const TAMBO_API_KEY = (import.meta as unknown as Record<string, Record<string, string>>).env?.VITE_TAMBO_API_KEY;
+const TAMBO_API_KEY = import.meta.env.VITE_TAMBO_API_KEY as string | undefined;

If the project lacks Vite client types, add them in tsconfig.json via "types": ["vite/client"].

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/components/RegentPanel.tsx` at line 12, Replace the verbose type
assertion used to read the env var for TAMBO_API_KEY by using Vite's built-in
import.meta.env access: reference import.meta.env.VITE_TAMBO_API_KEY when
defining TAMBO_API_KEY (symbol: TAMBO_API_KEY in RegentPanel.tsx) and, if TS
errors occur, enable Vite client types by adding "types": ["vite/client"] to the
tsconfig.json compilerOptions.types so the standard typed import.meta.env is
available.

141-142: Consider dynamic user identification for Tambo.

The userKey is hardcoded as "companion-user", which means all users of the application will share the same Tambo identity. This could lead to:

  • Thread history mixing between different users
  • Incorrect context in AI responses
  • Privacy concerns in multi-user deployments

If this is intentional for a single-user scenario, consider adding a comment explaining the design decision. Otherwise, derive the userKey from user authentication state or a unique identifier.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/components/RegentPanel.tsx` around lines 141 - 142, The userKey prop
on the RegentPanel/Tambo integration is hardcoded as "companion-user"
(userKey="companion-user"), which will merge identities across users; change
userKey to a per-user unique value (e.g., derive from your auth/session user id,
currentUser.id, or a generated per-session UUID passed into the component) so
each user gets a distinct Tambo identity and thread history, or if a
single-shared identity is intentional add a clear inline comment on the
RegentPanel/Tambo call explaining that design choice and the reason for using a
static userKey.
web/.env.example (1)

3-3: Consider adding a comment for obtaining the Tambo API key.

For better developer experience, consider adding a comment indicating where developers can obtain a Tambo API key:

 VITE_POSTHOG_KEY=phc_your_project_key
 VITE_POSTHOG_HOST=https://us.i.posthog.com
+# Get your Tambo API key from https://tambo.ai (or relevant URL)
 VITE_TAMBO_API_KEY=your_tambo_api_key
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/.env.example` at line 3, Add a one-line comment above the
VITE_TAMBO_API_KEY entry in web/.env.example that tells developers where to
obtain the Tambo API key (e.g., link to Tambo signup or docs) and any required
scope/format, referencing the VITE_TAMBO_API_KEY variable so it's clear which
env value the comment applies to.
web/src/regent/components/SessionCard.tsx (1)

129-136: Schema doesn't indicate nullable fields.

The currentTask and gitBranch props accept null per the TypeScript interface (lines 12-13), but the JSON schema doesn't indicate this. Consider adding nullable: true or using a union type if the schema consumer needs to know these can be null.

💡 Optional schema improvement
       currentTask: {
         type: "string" as const,
         description: "Currently active task description, or null",
+        nullable: true,
       },
       gitBranch: {
         type: "string" as const,
         description: "Git branch name, or null",
+        nullable: true,
       },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/regent/components/SessionCard.tsx` around lines 129 - 136, The JSON
schema for the SessionCard props declares currentTask and gitBranch as type
"string" but the TypeScript interface allows null; update the schema for the
properties currentTask and gitBranch in SessionCard.tsx so consumers know they
can be null — either add "nullable: true" to each property or change the type to
a union that accepts null (e.g., type ["string", "null"]) so the schema matches
the TypeScript interface.
web/src/components/RightPanel.tsx (1)

33-37: Missing dependency in useEffect.

The setActiveTab function is used inside the effect but not included in the dependency array. While Zustand selectors are typically stable, including it follows React best practices and satisfies the exhaustive-deps lint rule.

♻️ Suggested fix
   useEffect(() => {
     if (currentThreadId && currentThreadId !== activeTab) {
       setActiveTab(currentThreadId);
     }
-  }, [currentThreadId]);
+  }, [currentThreadId, activeTab, setActiveTab]);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/components/RightPanel.tsx` around lines 33 - 37, The useEffect that
synchronizes currentThreadId to activeTab is missing setActiveTab in its
dependency array; update the effect watching [currentThreadId] to include
setActiveTab as well (i.e., [currentThreadId, setActiveTab]) so the effect
references are stable and satisfy exhaustive-deps while keeping the logic inside
useEffect (currentThreadId, activeTab, setActiveTab).
web/src/components/RightPanel.test.tsx (1)

138-142: Consider strengthening the diamond icon assertion.

This test only verifies that the "New Regent thread" button has a parent element, which doesn't actually confirm the diamond icon is rendered. Consider querying for the SVG element or using a more specific assertion.

💡 Suggested improvement
   it("shows diamond header icon in vertical tab bar", () => {
     render(<RegentSidebar />);
-    const tabBar = screen.getByTitle("New Regent thread").parentElement;
-    expect(tabBar).toBeInTheDocument();
+    // Query the header icon SVG in the vertical tab bar
+    const headerSection = screen.getByTitle("New Regent thread").closest('[class*="flex-col"]');
+    const diamondIcon = headerSection?.querySelector('svg');
+    expect(diamondIcon).toBeInTheDocument();
   });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/components/RightPanel.test.tsx` around lines 138 - 142, The test
"shows diamond header icon in vertical tab bar" currently only checks
parentElement existence; update it to assert the actual diamond icon is rendered
by querying the SVG/icon node inside the tab bar. In RightPanel.test.tsx (the
test with render(<RegentSidebar />) and const tabBar = screen.getByTitle("New
Regent thread").parentElement), replace or extend the expect to look for the SVG
element (e.g., querySelector('svg') on tabBar or use
screen.getByRole/getByTitle/getByTestId for the diamond icon) and assert it is
in the document and visible, or assert a specific icon CSS class or aria-label
that the RegentSidebar renders for the diamond icon.
web/src/regent/tools/session-tools.ts (1)

30-39: Consider defining meaningful output schemas.

All tools use empty output schemas (properties: {}). While this works, defining actual schemas would improve documentation and enable better tooling/validation for consumers of the Tambo API.

Also applies to: 73-77, 105-109, 147-151, 193-197, 248-252

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/regent/tools/session-tools.ts` around lines 30 - 39, Several tool
definitions in session-tools.ts currently use empty outputSchema objects
(outputSchema: { properties: {} }) which provide no validation or documentation;
for each tool definition where you see outputSchema and inputSchema declared
(the blocks with type: "object" as const and properties: {}), replace the empty
properties with meaningful JSON Schema properties and required arrays that
reflect the tool's actual return shape (e.g., string/number/boolean fields,
nested objects, arrays), update inputSchema similarly where inputs are
non-empty, and ensure any shared types are imported or exported as TypeScript
types/interfaces; update all occurrences (the repeated schema blocks in this
file) so consumers of the Tambo API get concrete schemas and validation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@web/package.json`:
- Around line 56-59: The package.json lists pre-1.0 Tambo packages (notably
"@tambo-ai/client" at ^0.0.1 and "@tambo-ai/typescript-sdk" at ^0.93.1) which
may be unstable; confirm with the Tambo AI team that these exact releases are
production-ready, then pin those dependencies to exact versions (remove ^ and
use exact version strings) for "@tambo-ai/client", "@tambo-ai/react" and
"@tambo-ai/typescript-sdk" to avoid automatic minor/patch upgrades and reduce
risk of unexpected breaking changes during installs.

In `@web/src/components/RegentPanel.tsx`:
- Around line 75-79: The ComponentRenderer is being passed an empty-string
fallback for threadId which violates its requirement for a valid thread ID; in
RegentPanel replace the current rendering logic so that ComponentRenderer (used
in the JSX block with props content, threadId, messageId) is only rendered when
currentThreadId is non-null/defined (i.e., guard the render with a check for
currentThreadId) or ensure currentThreadId is resolved earlier; update the JSX
around ComponentRenderer to skip rendering when currentThreadId is falsy rather
than passing "".

---

Nitpick comments:
In `@web/.env.example`:
- Line 3: Add a one-line comment above the VITE_TAMBO_API_KEY entry in
web/.env.example that tells developers where to obtain the Tambo API key (e.g.,
link to Tambo signup or docs) and any required scope/format, referencing the
VITE_TAMBO_API_KEY variable so it's clear which env value the comment applies
to.

In `@web/src/components/RegentPanel.tsx`:
- Line 12: Replace the verbose type assertion used to read the env var for
TAMBO_API_KEY by using Vite's built-in import.meta.env access: reference
import.meta.env.VITE_TAMBO_API_KEY when defining TAMBO_API_KEY (symbol:
TAMBO_API_KEY in RegentPanel.tsx) and, if TS errors occur, enable Vite client
types by adding "types": ["vite/client"] to the tsconfig.json
compilerOptions.types so the standard typed import.meta.env is available.
- Around line 141-142: The userKey prop on the RegentPanel/Tambo integration is
hardcoded as "companion-user" (userKey="companion-user"), which will merge
identities across users; change userKey to a per-user unique value (e.g., derive
from your auth/session user id, currentUser.id, or a generated per-session UUID
passed into the component) so each user gets a distinct Tambo identity and
thread history, or if a single-shared identity is intentional add a clear inline
comment on the RegentPanel/Tambo call explaining that design choice and the
reason for using a static userKey.

In `@web/src/components/RightPanel.test.tsx`:
- Around line 138-142: The test "shows diamond header icon in vertical tab bar"
currently only checks parentElement existence; update it to assert the actual
diamond icon is rendered by querying the SVG/icon node inside the tab bar. In
RightPanel.test.tsx (the test with render(<RegentSidebar />) and const tabBar =
screen.getByTitle("New Regent thread").parentElement), replace or extend the
expect to look for the SVG element (e.g., querySelector('svg') on tabBar or use
screen.getByRole/getByTitle/getByTestId for the diamond icon) and assert it is
in the document and visible, or assert a specific icon CSS class or aria-label
that the RegentSidebar renders for the diamond icon.

In `@web/src/components/RightPanel.tsx`:
- Around line 33-37: The useEffect that synchronizes currentThreadId to
activeTab is missing setActiveTab in its dependency array; update the effect
watching [currentThreadId] to include setActiveTab as well (i.e.,
[currentThreadId, setActiveTab]) so the effect references are stable and satisfy
exhaustive-deps while keeping the logic inside useEffect (currentThreadId,
activeTab, setActiveTab).

In `@web/src/components/TopBar.test.tsx`:
- Around line 15-17: Update the test to cover the Regent panel toggle by adding
a case where the mocked hasTamboApiKey returns true and asserting the toggle
behavior: adjust the mock of hasTamboApiKey to return true for that test, ensure
the mocked store includes regentPanelOpen (e.g., false) and setRegentPanelOpen
(a vi.fn()) so the component can render, then verify the Regent toggle button is
rendered, simulate a click and assert setRegentPanelOpen was called, and finally
assert the button receives the correct active/inactive styling after toggling;
reference the mocked function hasTamboApiKey and the store props regentPanelOpen
and setRegentPanelOpen when making these changes.

In `@web/src/regent/components/SessionCard.tsx`:
- Around line 129-136: The JSON schema for the SessionCard props declares
currentTask and gitBranch as type "string" but the TypeScript interface allows
null; update the schema for the properties currentTask and gitBranch in
SessionCard.tsx so consumers know they can be null — either add "nullable: true"
to each property or change the type to a union that accepts null (e.g., type
["string", "null"]) so the schema matches the TypeScript interface.

In `@web/src/regent/tools/session-tools.ts`:
- Around line 30-39: Several tool definitions in session-tools.ts currently use
empty outputSchema objects (outputSchema: { properties: {} }) which provide no
validation or documentation; for each tool definition where you see outputSchema
and inputSchema declared (the blocks with type: "object" as const and
properties: {}), replace the empty properties with meaningful JSON Schema
properties and required arrays that reflect the tool's actual return shape
(e.g., string/number/boolean fields, nested objects, arrays), update inputSchema
similarly where inputs are non-empty, and ensure any shared types are imported
or exported as TypeScript types/interfaces; update all occurrences (the repeated
schema blocks in this file) so consumers of the Tambo API get concrete schemas
and validation.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between af57d92 and bc9552a.

📒 Files selected for processing (16)
  • web/.env.example
  • web/package.json
  • web/src/App.test.tsx
  • web/src/App.tsx
  • web/src/components/RegentPanel.tsx
  • web/src/components/RightPanel.test.tsx
  • web/src/components/RightPanel.tsx
  • web/src/components/TopBar.test.tsx
  • web/src/components/TopBar.tsx
  • web/src/regent/components/SessionCard.test.tsx
  • web/src/regent/components/SessionCard.tsx
  • web/src/regent/components/TaskOverview.test.tsx
  • web/src/regent/components/TaskOverview.tsx
  • web/src/regent/tools/session-tools.test.ts
  • web/src/regent/tools/session-tools.ts
  • web/src/store.ts

Comment on lines +56 to +59
"@tambo-ai/client": "^0.0.1",
"@tambo-ai/react": "^1.1.0",
"@tambo-ai/typescript-sdk": "^0.93.1",
"@tanstack/react-query": "^5.90.21",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check if Tambo packages exist on npm and their versions

echo "=== Checking `@tambo-ai/client` ==="
curl -s https://registry.npmjs.org/@tambo-ai/client 2>/dev/null | jq -r '.name, .["dist-tags"], (.versions | keys | reverse | .[0:5])' 2>/dev/null || echo "Not found or private"

echo -e "\n=== Checking `@tambo-ai/react` ==="
curl -s https://registry.npmjs.org/@tambo-ai/react 2>/dev/null | jq -r '.name, .["dist-tags"], (.versions | keys | reverse | .[0:5])' 2>/dev/null || echo "Not found or private"

echo -e "\n=== Checking `@tambo-ai/typescript-sdk` ==="
curl -s https://registry.npmjs.org/@tambo-ai/typescript-sdk 2>/dev/null | jq -r '.name, .["dist-tags"], (.versions | keys | reverse | .[0:5])' 2>/dev/null || echo "Not found or private"

echo -e "\n=== Checking `@tanstack/react-query` ==="
curl -s https://registry.npmjs.org/@tanstack/react-query 2>/dev/null | jq -r '.name, .["dist-tags"].latest' 2>/dev/null || echo "Not found"

Repository: CodeCraftersLLC/companion

Length of output: 561


Verify stability of @tambo-ai/client before production use.

The @tambo-ai/client package is at version 0.0.1—the only available release on npm. This extremely early version indicates the package is in initial development stages and may be unstable. Additionally, the @tambo-ai/typescript-sdk is at version 0.93.1, which, while more mature, is still pre-1.0 and subject to breaking changes.

Consider:

  1. Verifying with the Tambo AI team that these versions are production-ready.
  2. Pinning to exact versions for all Tambo packages to prevent unexpected breaking changes during dependency updates.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/package.json` around lines 56 - 59, The package.json lists pre-1.0 Tambo
packages (notably "@tambo-ai/client" at ^0.0.1 and "@tambo-ai/typescript-sdk" at
^0.93.1) which may be unstable; confirm with the Tambo AI team that these exact
releases are production-ready, then pin those dependencies to exact versions
(remove ^ and use exact version strings) for "@tambo-ai/client",
"@tambo-ai/react" and "@tambo-ai/typescript-sdk" to avoid automatic minor/patch
upgrades and reduce risk of unexpected breaking changes during installs.

Comment on lines +75 to +79
<ComponentRenderer
content={content}
threadId={currentThreadId ?? ""}
messageId={msg.id}
/>
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🌐 Web query:

@tambo-ai/react ComponentRenderer threadId prop documentation

💡 Result:

In @tambo-ai/react (React SDK 1.0+), ComponentRenderer expects a threadId prop that is the ID of the thread that the message (and its component content block) belongs to—you pass it alongside the content block and the messageId when rendering a "component" content block. [1]

You can typically source that ID from useTambo()’s currentThreadId (or from your thread object, e.g. thread.id). [2]

Example (from the migration docs):

<ComponentRenderer
  content={block}
  threadId={threadId}
  messageId={message.id}
  fallback={<div>Unknown component: {block.name}</div>}
/>
``` [1]

**Sources:** [1] [2]

---

🏁 Script executed:

```shell
# Search for ComponentRenderer imports and usage in the codebase
rg "ComponentRenderer" --type tsx --type ts -B 2 -A 5

Repository: CodeCraftersLLC/companion

Length of output: 96


🏁 Script executed:

# Find the file and examine the context around the flagged lines
cat -n web/src/components/RegentPanel.tsx | sed -n '60,90p'

Repository: CodeCraftersLLC/companion

Length of output: 1336


🏁 Script executed:

# Check for type definitions or documentation for ComponentRenderer
fd -e d.ts -e ts | xargs rg "ComponentRenderer" -l

Repository: CodeCraftersLLC/companion

Length of output: 53


Remove empty string fallback for threadId—ComponentRenderer requires a valid thread ID.

The @tambo-ai/react ComponentRenderer expects threadId to be "the ID of the thread that the message belongs to." Passing an empty string when currentThreadId is null does not meet this requirement and may cause runtime errors or unexpected behavior. Either ensure currentThreadId is always available at this point, or skip rendering the component entirely when the thread ID is unavailable.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/components/RegentPanel.tsx` around lines 75 - 79, The
ComponentRenderer is being passed an empty-string fallback for threadId which
violates its requirement for a valid thread ID; in RegentPanel replace the
current rendering logic so that ComponentRenderer (used in the JSX block with
props content, threadId, messageId) is only rendered when currentThreadId is
non-null/defined (i.e., guard the render with a check for currentThreadId) or
ensure currentThreadId is resolved earlier; update the JSX around
ComponentRenderer to skip rendering when currentThreadId is falsy rather than
passing "".

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces “Regent” as a persistent right-side panel (instead of a full-page route) and wires it into the existing UI/store to support multi-thread Tambo chat plus session-orchestration tools/components.

Changes:

  • Added Regent right sidebar with vertical thread tabs and a TopBar toggle (gated by Tambo API key).
  • Introduced Tambo session-aware tools plus Regent UI components (SessionCard, TaskOverview).
  • Extended global store state for Regent panel open/active-thread tracking and updated tests/docs/env.

Reviewed changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
web/src/store.ts Adds Regent panel UI state + actions to the global store.
web/src/regent/tools/session-tools.ts Implements Tambo tools for listing sessions/messages/tasks/status/diff.
web/src/regent/tools/session-tools.test.ts Adds unit tests for the new session tools.
web/src/regent/components/TaskOverview.tsx Adds aggregated task overview component + Tambo component registration.
web/src/regent/components/TaskOverview.test.tsx Adds TaskOverview rendering tests.
web/src/regent/components/SessionCard.tsx Adds session summary card + Tambo component registration.
web/src/regent/components/SessionCard.test.tsx Adds SessionCard interaction/render tests.
web/src/components/TopBar.tsx Adds Regent toggle button to TopBar (gated by API key).
web/src/components/TopBar.test.tsx Mocks Regent gating for TopBar tests.
web/src/components/RightPanel.tsx Adds RegentSidebar + vertical thread tab bar and panel layout.
web/src/components/RightPanel.test.tsx Adds RegentSidebar behavior tests (thread tabs/new thread/panel collapse).
web/src/components/RegentPanel.tsx Adds Tambo provider + chat UI (RegentChat) + hasTamboApiKey gating.
web/src/App.tsx Renders RegentSidebar persistently at app root and adjusts task panel comment.
web/src/App.test.tsx Mocks RegentSidebar for App tests.
web/package.json Adds Tambo + React Query dependencies.
web/.env.example Documents VITE_TAMBO_API_KEY.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +14 to +18
tool: async () => {
const store = getStore();
const sessions = store.sdkSessions.filter((s) => !s.archived);
return JSON.stringify(
sessions.map((s) => ({
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The tools are returning JSON-serialized strings (JSON.stringify(...)), but outputSchema is declared as an object. If Tambo validates or uses the schema for function-calling, this mismatch can break tool execution or degrade model behavior. Either return a real JS object/array that matches outputSchema (preferred), or change outputSchema to type "string" and document that the payload is JSON-encoded (apply consistently across all tools in this file).

Copilot uses AI. Check for mistakes.
Comment on lines +167 to +171
return JSON.stringify({
sessionId: args.sessionId,
cwd: sdkSession.cwd,
changedFileCount: files.length,
files: files.slice(0, 30).map((f) => ({
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

api.getChangedFiles(cwd, ...) returns repo-wide paths (not scoped to cwd). Here changedFileCount/files are computed from the full repo diff, which can report changes outside the session working directory. Filter the returned files to those within sdkSession.cwd (same prefix filtering used in App.tsx/DiffPanel.tsx) before counting and slicing.

Suggested change
return JSON.stringify({
sessionId: args.sessionId,
cwd: sdkSession.cwd,
changedFileCount: files.length,
files: files.slice(0, 30).map((f) => ({
const cwdPrefix =
sdkSession.cwd.endsWith("/") || sdkSession.cwd.endsWith("\\")
? sdkSession.cwd
: sdkSession.cwd + "/";
const filteredFiles = files.filter((f) => {
return f.path === sdkSession.cwd || f.path.startsWith(cwdPrefix);
});
return JSON.stringify({
sessionId: args.sessionId,
cwd: sdkSession.cwd,
changedFileCount: filteredFiles.length,
files: filteredFiles.slice(0, 30).map((f) => ({

Copilot uses AI. Check for mistakes.
Comment on lines +12 to +16
const TAMBO_API_KEY = (import.meta as unknown as Record<string, Record<string, string>>).env?.VITE_TAMBO_API_KEY;

export function hasTamboApiKey(): boolean {
return !!TAMBO_API_KEY;
}
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TAMBO_API_KEY is read via a broad cast on import.meta and cached at module load. This bypasses the repo’s ImportMetaEnv typing and makes tests harder to control with vi.stubEnv(). Prefer using import.meta.env.VITE_TAMBO_API_KEY directly, and add VITE_TAMBO_API_KEY to src/vite-env.d.ts (like analytics.ts does for PostHog).

Copilot uses AI. Check for mistakes.
Comment on lines +140 to +145
<TamboProvider
apiKey={TAMBO_API_KEY}
userKey="companion-user"
tools={sessionTools}
components={[sessionCardTamboComponent, taskOverviewTamboComponent]}
>
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

userKey is hard-coded to "companion-user". If Tambo uses userKey to scope threads/history, this will mix thread identity across all users/browsers sharing the same API key (and can lead to unexpected data cross-talk). Generate a stable per-browser/user key (e.g., persisted UUID in localStorage, or derived from an authenticated user id) instead of a constant.

Copilot uses AI. Check for mistakes.
Comment on lines +39 to +42
{inProgress.map((t, i) => (
<TaskRow key={`ip-${i}`} task={t} />
))}
</div>
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Task rows use array indices as React keys. When tasks change order or move between sections (pending → in_progress → completed), React can reuse DOM nodes incorrectly and show stale content. Prefer a stable unique key (e.g., task.id) and include it in TaskEntry, or derive a stable composite key (sessionName + subject + status) if no id is available.

Copilot uses AI. Check for mistakes.
Comment on lines +91 to +99
import { RegentSidebar } from "./RightPanel.js";
import { useStore } from "../store.js";

beforeEach(() => {
vi.clearAllMocks();
useStore.setState({
regentPanelOpen: true,
rightPanelActiveTab: "",
});
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test relies on hasTamboApiKey() being true, but RegentPanel reads VITE_TAMBO_API_KEY at module import time and there’s no stub/mock here. On machines/CI without that env var, RegentSidebar will return null and these assertions will fail. Consider mocking ./RegentPanel.js in this test (like TopBar.test does), or refactor RegentPanel to read import.meta.env at runtime so you can vi.stubEnv() + dynamic import reliably.

Copilot uses AI. Check for mistakes.
Comment on lines +14 to 15
import { RegentSidebar } from "./components/RightPanel.js";
import { UpdateBanner } from "./components/UpdateBanner.js";
Copy link

Copilot AI Mar 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RegentSidebar (and its Tambo dependencies) is imported and rendered unconditionally at the app root. This means everyone pays the bundle/runtime cost for @tambo-ai/* even when Regent is disabled (no API key). Consider code-splitting RegentSidebar behind a lightweight API-key check (or behind the toggle) using React.lazy/dynamic import so the optional feature doesn’t impact initial load for all users.

Copilot uses AI. Check for mistakes.
Add bg-cc-bg for solid background and use top-11 positioning on mobile
so the panel renders below the TopBar instead of covering it.
@matter-ai-bot
Copy link

matter-ai-bot bot commented Mar 3, 2026

Caution

PR Summary Skipped - Monthly Quota Exceeded

PR summary skipped as you have reached the free tier limit of 50 PR summaries per month. Please upgrade to a paid plan for MatterAI.

Current Plan: Free Tier
Free Tier Limit: 25 PR Summaries per month
Current Usage: 25 PR Summaries
Resets in: 28 days

Upgrade your plan on the console here: https://app.matterai.so/ai-code-reviews?tab=Billing

Comment on lines +100 to +101

<div

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correctness: Combining top-11, bottom-0, and h-full on the fixed sidebar causes it to overflow the viewport by 44px (the top-11 offset), which will hide content at the bottom of the panel. To fix this while preserving the desktop layout, remove the base h-full and use lg:h-full instead. This allows the top and bottom properties to correctly constrain the height on mobile.

🤖 AI Agent Prompt for Cursor/Windsurf

📋 Copy this prompt to your AI coding assistant (Cursor, Windsurf, etc.) to get help fixing this issue

In `web/src/components/RightPanel.tsx`, remove the `h-full` class from the Regent panel wrapper that now uses `top-11 bottom-0`. Keeping `h-full` with top/bottom causes the panel to overflow the viewport. Let top/bottom define the height or replace with a calc height.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
web/src/components/RightPanel.tsx (2)

33-37: Complete the effect dependencies for state sync.

On Line 37, the effect reads activeTab and setActiveTab but only depends on currentThreadId. Adding all referenced values keeps sync behavior deterministic.

Suggested change
   useEffect(() => {
     if (currentThreadId && currentThreadId !== activeTab) {
       setActiveTab(currentThreadId);
     }
-  }, [currentThreadId]);
+  }, [currentThreadId, activeTab, setActiveTab]);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/components/RightPanel.tsx` around lines 33 - 37, The useEffect in
RightPanel (the effect that checks currentThreadId and sets activeTab)
references activeTab and setActiveTab but only lists currentThreadId in its
dependency array; update the effect’s dependencies to include activeTab and
setActiveTab so the effect runs deterministically whenever any referenced value
changes (i.e., change the dependency array on the useEffect that contains
currentThreadId, activeTab, setActiveTab).

53-79: Add explicit accessible names for thread/action buttons.

On Lines 53-79, the controls are number-only/icon-only visually. Add explicit ARIA labels (and selected state) so screen readers can identify the active thread and “new thread” action reliably.

Suggested change
             <button
               key={thread.id}
               type="button"
               onClick={() => handleTabClick(thread.id)}
+              aria-label={thread.name || `Regent thread ${i + 1}`}
+              aria-current={isActive ? "true" : undefined}
               title={thread.name || `Regent thread ${i + 1}`}
               className={`flex items-center justify-center w-full h-10 transition-colors cursor-pointer ${
                 isActive
                   ? "bg-cc-active text-cc-fg border-l-2 border-cc-accent"
                   : "text-cc-muted hover:text-cc-fg hover:bg-cc-hover"
               }`}
             >
@@
       <button
         type="button"
         onClick={handleNewThread}
+        aria-label="Start new Regent thread"
         title="New Regent thread"
         className="flex items-center justify-center w-full h-10 text-cc-muted hover:text-cc-fg hover:bg-cc-hover transition-colors cursor-pointer border-t border-cc-border"
       >
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/components/RightPanel.tsx` around lines 53 - 79, The thread buttons
(rendered in the loop using thread.id, thread.name and onClick ->
handleTabClick) and the "new thread" button (handleNewThread) lack explicit
accessible names and state; add an aria-label to each thread button (e.g., use
thread.name if present or `Regent thread ${i+1}`) and expose the active state
via aria-pressed or aria-current/aria-selected when isActive is true, and add an
explicit aria-label like "New Regent thread" to the new-thread button so screen
readers can identify the action and the selected thread reliably.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@web/src/components/RightPanel.tsx`:
- Around line 33-37: The useEffect in RightPanel (the effect that checks
currentThreadId and sets activeTab) references activeTab and setActiveTab but
only lists currentThreadId in its dependency array; update the effect’s
dependencies to include activeTab and setActiveTab so the effect runs
deterministically whenever any referenced value changes (i.e., change the
dependency array on the useEffect that contains currentThreadId, activeTab,
setActiveTab).
- Around line 53-79: The thread buttons (rendered in the loop using thread.id,
thread.name and onClick -> handleTabClick) and the "new thread" button
(handleNewThread) lack explicit accessible names and state; add an aria-label to
each thread button (e.g., use thread.name if present or `Regent thread ${i+1}`)
and expose the active state via aria-pressed or aria-current/aria-selected when
isActive is true, and add an explicit aria-label like "New Regent thread" to the
new-thread button so screen readers can identify the action and the selected
thread reliably.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bc9552a and 775a6eb.

📒 Files selected for processing (1)
  • web/src/components/RightPanel.tsx

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants