Skip to content

Frontend Architecture

The RTC Agent frontend is a component library built on Lit Web Components. It exposes only a single <rtc-agent> component to the outside world, containing 57 sub-components internally, managed by 23 Controllers, with data distributed to child components via @lit/context.

File Explorer

File Explorer: Left panel shows the virtual file system directory tree (functions/, scenarios/, scripts/), right panel is an editor with live preview. All file data is stored in the browser’s IndexedDB.

Settings UI

Settings UI: Supports theme switching, language selection, font size adjustment, and other personalization options.

ComponentPurposeReplacement
rtc-chat-layoutTwo-column chat layout (session tree + content)Replaces legacy rtc-content-wrapper
rtc-session-treeVS Code-style session tree sidebarNew
rtc-session-tree-itemTree node (recursive rendering)New
rtc-session-tab-barBrowser-style tab barNew
rtc-session-tabIndividual tabNew
rtc-settings-panelSettings side drawer panelNew
rtc-settings-layoutSettings two-column layoutNew
rtc-settings-navSettings category navigationNew
rtc-file-preview-areaAttachment preview area (horizontal scrolling thumbnail list)New
rtc-file-thumbnailFile thumbnail (upload progress, delete, preview)New
rtc-file-preview-modalFullscreen file preview modal (image/text)New

Host applications only need to import a single component to access all functionality:

AttributeDescriptionExample
themeTheme switchinglight / dark / system
langInterface languagezh-CN / en-US
app-labelTitle bar text + bubble tooltip"RTC Assistant"
database-nameIndexedDB name prefix"my-app-rtc"
server-urlServer address"https://rtc.example.com"
redirect-uriOAuth callback address"/auth/callback.html"
bubble-iconSVG/HTML inside the minimized bubbleCustom icon
logoCustom brand Logo (separate light/dark variants){ light: '<svg>...', dark: '<svg>...' }
worker-urlSharedWorker file URL"/rtc-agent/shared-worker.js"
scenarios-urlScenarios document URL"https://..."
agentConfigDeclarative function registration (recommended)JSON config object

For detailed API documentation, see Component API.

ControllerContextDescription
SessionTreeControllerSessionTreeContextManages session tree structure, expand/collapse state
NotificationControllerNotificationContextManages notification state, sounds, focus detection
SettingsControllerSettingsContextManages global settings, localStorage persistence

Additionally, the following auxiliary modules exist:

ModuleDescription
LocaleController / i18nInternationalization support, runtime language switching
SessionTabControllerManages tab state (SessionTabContext)
ToastControllerManages Toast notification display
PrincipleDescription
Controllers do not reference each otherEach Controller independently manages its own state slice
Root component orchestrates<rtc-agent> acts as the hub, coordinating cross-Controller communication
Context distributionState is distributed to child components via @lit/context, avoiding prop drilling
Data layer isolationThe Persistence Controller manages all IndexedDB reads and writes

💡 Why not global state? Web Components run inside the host application’s page and may have multiple instances. For example, a page might embed both a “Customer Support Assistant” and a “Data Analysis Assistant” as two <rtc-agent> elements — they need independent sessions, messages, and auth state. Controller + Context ensures each instance’s state is fully isolated with no interference.

RTC Agent includes an offline-first file storage system that distributes FileStorage instances to child components via FileStorageContext. All file operations are first written to local IndexedDB cache, then synced to S3 in the background, ensuring availability in offline scenarios.

FileStorage Core API:

MethodDescription
cacheFileForUpload(file)Cache file to local IndexedDB, calculate MD5, return FileInfo (including md5, ext, size)
upload(options)Upload file to S3, supports onProgress callback, returns FileInfo (including syncStatus)
download(md5, ext, options?)Download file, prefers local cache; falls back to S3 on cache miss
getThumbnailUrl(identifier)Get image thumbnail URL (returns blob URL, must call releaseThumbnailUrl() to release)
getPresignedUrl(identifier, expires)Get S3 presigned URL (for fallback scenarios)
list(filter?)List files with pagination and filtering support
delete(identifier)Delete file (both local cache and S3)
getCacheStats()Get cache statistics (file count, space usage)

Offline-First Features:

  • File uploads are first written to local cache (syncStatus: 'pending'), thumbnails are immediately visible
  • When network recovers, files are automatically synced to S3 in the background (syncStatus: 'synced')
  • Downloads prefer local cache; only requests S3 on cache miss
  • Supports interruption recovery: resumeInterruptedUploads() resumes incomplete upload tasks
InteractionImplementation
DragTitle bar serves as the drag handle
Resize8 resize handles — 4 corners + 4 edges
KeyboardArrow keys to move, Shift to accelerate
Viewport constraintAlways stays within the visible area
LayerContentCustomization Method
Design TokensSpacing, typography, border radius, shadows, transitions, z-indexOverride CSS variables
Color Themeslight / dark color schemesSwitch via theme attribute
CSS VariablesWindow size, bubble size--rtc-* prefixed variables

File Upload Flow:

  1. Trigger: Click the attach button to open the file picker, or use Ctrl+V / Cmd+V to paste files from the clipboard
  2. Local Cache: Files are first written to local IndexedDB cache (FileStorage.cacheFileForUpload()), generating a real fileid (in md5.ext format)
  3. Instant Preview: Thumbnails display immediately (rtc-file-thumbnail loads from FileStorage cache), no need to wait for S3 upload
  4. Background Upload: Background call to FileStorage.upload() uploads to S3, showing real-time upload progress (0-100%)
  5. State Management: Each file has three states — loading (uploading), loaded (success), error (failed)
  6. Retry Mechanism: Failed uploads show a retry button; clicking it re-uploads the file
  7. Send Condition: The send button is enabled only after all files are uploaded; when sent, the file list is submitted with the message
FeatureBehavior
Auto-scrollAutomatically scrolls to the bottom when new messages arrive
Smart pausePauses auto-scroll when the user manually scrolls up
New message indicatorShows a “New messages” button when the user is not at the bottom
RenderingMarkdown rendering + code highlighting

When the user types text starting with /, command input mode is triggered:

CommandTypeFunction
/compactRPCManually trigger context compression
/loopLocal + RPCLoop execution (scheduled / dynamic)
/goalPromptGoal-driven; AI sets completion criteria, Judge model checks

See Commands.

The frontend project adopts a multi-layer testing strategy covering unit tests, integration tests, and end-to-end tests to ensure correct component behavior and stable cross-module collaboration.

ToolPurposeConfig Location
VitestUnit tests & integration testspackages/*/vitest.config.ts
PlaywrightEnd-to-end tests (E2E)packages/component/playwright.config.ts
jsdomBrowser API simulation (Vitest environment)test-setup.ts polyfills IndexedDB, matchMedia, ResizeObserver, etc.
fake-indexeddbPure-JS IndexedDB implementation for Dexie in testsAuto-imported in test-setup.ts
PackageUnit Test FilesDescription
@rtc-agent/component62Covers all Controllers, components, factory functions, event system, authentication flows
@rtc-agent/persistence12Covers IndexedDB operations, entity repository, transactions, offset manager, script engine
@rtc-agent/client1Covers WebSocket client, offset sync, gap-fill logic
@rtc-agent/worker1Covers SharedWorker core message routing
E2E (Playwright)6Covers debug API, business flows, advanced interactions, doc reconciliation, script execution

Currently 835+ unit test cases, all passing.

终端窗口
# Run all unit tests (from web-components root)
pnpm test
# Run unit tests for the component package only
pnpm --filter @rtc-agent/component test
# Run E2E tests (requires Vite dev server)
pnpm --filter @rtc-agent/component test:e2e
# Run a specific test file
npx vitest run packages/component/src/controllers/auth.controller.test.ts
# Watch mode (recommended during development)
npx vitest

packages/component/src/test-helpers.ts provides test infrastructure:

UtilityDescription
fixture(template, options?)Creates a Lit component test fixture, automatically waits for the update cycle to complete
nextFrame()Waits one frame to ensure Lit has finished rendering
cleanupFixtures()Cleans up all created test fixtures to prevent cross-test pollution
provideContext()Injects @lit/context during the setup phase, ensuring context is ready before the component’s first update

E2E tests rely on the window.rtcAgentDebug API exposed by the debug page (/debug/index.html). This API is automatically installed in dev mode and provides the following capabilities:

MethodDescription
waitForReady(timeout?)Wait for the <rtc-agent> component to be ready
sendMessage(text)Send a message
getSessionController()Get the session controller
getActions(controller)Get a specific controller’s actions

GitHub Actions CI runs automatically on every push/PR:

终端窗口
pnpm install → pnpm build → pnpm typecheck → pnpm test

Node.js version: 24. Tests run on the ubuntu-latest environment.

ScenarioStrategy
Large message listsPaginated loading (cursor pagination); first load shows the latest 50
Long conversation scrollingVirtual scroll optimization (future release)
Markdown renderingOn-demand rendering; code highlighting loaded lazily
IndexedDB reads/writesUnified by Persistence Controller; batch operations reduce IO
FeatureImplementation
Keyboard navigationTab to switch focus, Enter to activate, Esc to close dialogs
ARIA labelsAll interactive elements have aria-label
Screen readerMessage list uses role="log"; new messages announced automatically
High contrastSupports system high-contrast mode