🎉 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

+106
View File
@@ -0,0 +1,106 @@
export interface OpenRouterModelEntry {
id: string
name: string
description?: string | null
context_length?: number | null
architecture?: {
modality?: string | null
input_modalities?: string[] | null
output_modalities?: string[] | null
tokenizer?: string | null
instruct_type?: string | null
} | null
pricing?: Record<string, string | undefined> | null
top_provider?: {
context_length?: number | null
max_completion_tokens?: number | null
is_moderated?: boolean | null
} | null
supported_parameters?: string[] | null
}
interface ModelQuery {
modelID?: string
providerID?: string
modelName?: string
contextWindow?: number
}
function normalize(value: string | undefined): string {
return (value ?? '').toLowerCase().replace(/[^a-z0-9]+/g, '')
}
function providerFromOpenRouterId(id: string): string {
return id.split('/')[0] ?? ''
}
function isFreeVariant(id: string): boolean {
return id.endsWith(':free')
}
function scoreModel(entry: OpenRouterModelEntry, query: ModelQuery): number {
const modelID = query.modelID ?? ''
const providerID = query.providerID ?? ''
const fullID = providerID && modelID ? `${providerID}/${modelID}` : modelID
const normalizedEntryID = normalize(entry.id)
const normalizedModelID = normalize(modelID)
const normalizedFullID = normalize(fullID)
const normalizedEntryName = normalize(entry.name)
const normalizedModelName = normalize(query.modelName)
let score = 0
if (entry.id === fullID) score += 1000
if (entry.id === modelID) score += 900
if (normalizedEntryID === normalizedFullID) score += 700
if (normalizedEntryID === normalizedModelID) score += 650
if (modelID && entry.id.endsWith(`/${modelID}`)) score += 600
if (normalizedModelID && normalizedEntryID.endsWith(normalizedModelID)) score += 450
if (normalizedModelName && normalizedEntryName.includes(normalizedModelName)) score += 250
const normalizedProvider = normalize(providerID)
if (normalizedProvider && normalize(providerFromOpenRouterId(entry.id)) === normalizedProvider) score += 150
if (query.contextWindow && entry.context_length) {
const distance = Math.abs(entry.context_length - query.contextWindow) / query.contextWindow
score += Math.max(0, 120 - distance * 120)
}
if (isFreeVariant(entry.id)) score -= 40
return score
}
export function selectOpenRouterModel(
catalog: OpenRouterModelEntry[],
query: ModelQuery,
): OpenRouterModelEntry | undefined {
let best: { entry: OpenRouterModelEntry; score: number } | undefined
for (const entry of catalog) {
const score = scoreModel(entry, query)
if (score <= 0) continue
if (!best || score > best.score) best = { entry, score }
}
return best?.entry
}
export function formatOpenRouterPricePerMillion(value: string | undefined): string {
if (value === undefined) return '—'
const perToken = Number(value)
if (!Number.isFinite(perToken)) return '—'
const perMillion = perToken * 1_000_000
if (perMillion === 0) return '$0/M'
if (perMillion < 0.01) return '<$0.01/M'
return `$${perMillion
.toFixed(perMillion >= 10 ? 2 : 4)
.replace(/0+$/, '')
.replace(/\.$/, '')}/M`
}
export function getModelProviderLabel(entry: OpenRouterModelEntry | undefined): string | undefined {
if (!entry) return undefined
const [provider] = entry.name.split(':')
return provider?.trim() || providerFromOpenRouterId(entry.id) || undefined
}