🎉 Initial commit: PiAgentUI — AI Agent Desktop & Web UI
Build & Push Frontend Docker Image / build-and-push (push) Canceled after 0s
Build Validation / validate (push) Canceled after 6s
Build & Push Backend Docker Image / build-and-push (push) Failing after 10m10s
Build & Push Gateway Docker Image / build-and-push (push) Failing after 10m9s

A professional workspace for AI coding agents with:
- Real-time streaming chat with SSE
- Session management (fork, clone, tree navigation)
- MCP tools browser & metadata panel
- Skills browser (global, project, package sources)
- Voice input & STT provider configuration
- Integrated terminal & file explorer
- Model selector with capability metadata
- Keyboard-first UI with command palette
- 8 languages (en, pt-BR, es, ja, zh-CN, ar, bn, hi)
- Tauri 2 desktop app
- React 19 + TypeScript + Vite 8 + Tailwind CSS 4
- Pi Agent extension runtime

Originally forked from OpenCodeUI, now an independent project.
License: GPL-3.0-only
This commit is contained in:
Evandro committed 2026-06-01 00:50:06 -03:00
commit b3489e1ede
983 files changed
+158475

No files matched your search

@@ -0,0 +1,86 @@
import { fireEvent, render, screen, waitFor } from '@testing-library/react'
import { beforeEach, describe, expect, it, vi } from 'vitest'
import { SttSettings } from './SttSettings'
import { getSttSettings, updateSttSettings } from '../../../api/stt'
vi.mock('../../../api/stt', () => ({
getSttSettings: vi.fn(),
updateSttSettings: vi.fn(),
}))
const SETTINGS = {
enabled: true,
providerKind: 'openai-compatible' as const,
mode: 'file' as const,
baseUrl: 'https://api.openai.com/v1',
apiKeyConfigured: true,
apiKeyRequired: true,
transcriptionEndpoint: '/audio/transcriptions',
transcriptionModel: 'gpt-4o-mini-transcribe',
language: 'pt',
insertMode: 'append' as const,
}
describe('SttSettings', () => {
beforeEach(() => {
vi.mocked(getSttSettings).mockReset()
vi.mocked(updateSttSettings).mockReset()
vi.mocked(getSttSettings).mockResolvedValue(SETTINGS)
vi.mocked(updateSttSettings).mockImplementation(async payload => ({
...SETTINGS,
...payload,
apiKeyConfigured: true,
language: payload.language ?? SETTINGS.language,
}))
})
it('uses the shared switch pattern for enabling voice transcription', async () => {
render(<SttSettings />)
const enableSwitch = await screen.findByRole('switch', { name: 'Enable voice transcription' })
expect(enableSwitch).toHaveAttribute('aria-checked', 'true')
expect(screen.queryByRole('checkbox')).not.toBeInTheDocument()
fireEvent.click(enableSwitch)
expect(enableSwitch).toHaveAttribute('aria-checked', 'false')
fireEvent.click(screen.getByRole('button', { name: 'Save transcription settings' }))
await waitFor(() => expect(updateSttSettings).toHaveBeenCalledWith(expect.objectContaining({ enabled: false })))
})
it('persists whether the STT provider requires an API key', async () => {
render(<SttSettings />)
const requireKeySwitch = await screen.findByRole('switch', { name: 'Require voice transcription API key' })
expect(requireKeySwitch).toHaveAttribute('aria-checked', 'true')
fireEvent.click(requireKeySwitch)
fireEvent.click(screen.getByRole('button', { name: 'Save transcription settings' }))
await waitFor(() =>
expect(updateSttSettings).toHaveBeenCalledWith(expect.objectContaining({ apiKeyRequired: false })),
)
})
it('shows one complete transcription configuration instead of split transcription cards', async () => {
render(<SttSettings />)
expect(await screen.findByText('Speech-to-text transcription')).toBeInTheDocument()
expect(screen.queryByText('Transcription provider')).not.toBeInTheDocument()
expect(screen.getByLabelText('Provider')).toHaveValue('openai-compatible')
expect(screen.getByLabelText('Base URL')).toHaveValue('https://api.openai.com/v1')
expect(screen.getByLabelText('Endpoint')).toHaveValue('/audio/transcriptions')
expect(screen.getByLabelText('Model')).toHaveValue('gpt-4o-mini-transcribe')
})
it('styles dropdown lists with the app select treatment', async () => {
render(<SttSettings />)
const insertMode = await screen.findByLabelText('Insert mode')
expect(insertMode).toHaveClass('appearance-none')
expect(insertMode.closest('[data-settings-select]')).toBeInTheDocument()
})
})