chore: update AGENTS.md

This commit is contained in:
Acbox
2026-02-28 21:13:55 +08:00
parent cc5f00355f
commit fab5ae6320
2 changed files with 455 additions and 42 deletions
+142 -42
View File
@@ -2,7 +2,7 @@
## Project Overview
Memoh is a multi-member, structured long-memory, containerized AI agent system platform. Users can create AI bots and chat with them via Telegram, Discord, Lark (Feishu), and more. Every bot has an independent container and memory system, allowing it to edit files, execute commands, and build itself — providing a secure, flexible, and scalable solution for multi-bot management.
Memoh is a multi-member, structured long-memory, containerized AI agent system platform. Users can create AI bots and chat with them via Telegram, Discord, Lark (Feishu), Email, and more. Every bot has an independent container and memory system, allowing it to edit files, execute commands, and build itself — providing a secure, flexible, and scalable solution for multi-bot management.
## Architecture Overview
@@ -11,13 +11,13 @@ The system consists of three core services:
| Service | Tech Stack | Port | Description |
|---------|-----------|------|-------------|
| **Server** (Backend) | Go + Echo | 8080 | Main service: REST API, auth, database, container management |
| **Agent Gateway** | Bun + Elysia | 8081 | AI chat gateway: handles chat requests and tool execution |
| **Agent Gateway** | Bun + Elysia | 8081 | AI chat gateway: handles chat requests, tool execution, and SSE streaming |
| **Web** (Frontend) | Vue 3 + Vite | 8082 | Management UI: visual configuration for Bots, Models, Channels, etc. |
Infrastructure dependencies:
- **PostgreSQL** — Relational data storage
- **Qdrant** — Vector database for memory semantic search
- **Containerd** — Container runtime providing isolated environments per bot
- **Containerd** — Container runtime providing isolated environments per bot (Linux); Apple Virtualization on macOS
## Tech Stack
@@ -27,22 +27,31 @@ Infrastructure dependencies:
- **Database Driver**: pgx/v5
- **Code Generation**: sqlc (SQL → Go)
- **API Docs**: Swagger/OpenAPI (swaggo)
- **Containers**: containerd v2
- **Containers**: containerd v2 (Linux), Apple Virtualization (macOS)
### Agent Gateway (TypeScript)
### Agent Gateway & Agent Library (TypeScript)
- **Runtime**: Bun
- **Framework**: Elysia
- **Framework**: Elysia (gateway), Vercel AI SDK (agent core)
- **AI Providers**: Anthropic, OpenAI, Google (via Vercel AI SDK)
- **Tools**: MCP, Web Search, Subagent, Skill
### Frontend (TypeScript)
- **Framework**: Vue 3 (Composition API)
- **Build Tool**: Vite
- **State Management**: Pinia + Pinia Colada
- **UI**: Tailwind CSS + custom component library (`@memoh/ui`) + Reka UI
- **UI**: Tailwind CSS 4 + custom component library (`@memoh/ui`) + Reka UI
- **i18n**: vue-i18n
- **Markdown**: markstream-vue + Shiki + Mermaid + KaTeX
- **Package Manager**: pnpm monorepo
### Tooling
- **Task Runner**: mise
- **Package Managers**: pnpm (frontend monorepo), Go modules (backend)
- **Linting**: ESLint + typescript-eslint + vue-eslint-parser
- **Testing**: Vitest
- **Typo Checker**: typos
- **Version Management**: bumpp
- **SDK Generation**: @hey-api/openapi-ts
## Project Structure
@@ -50,38 +59,93 @@ Infrastructure dependencies:
Memoh/
├── cmd/ # Go application entry points
│ ├── agent/ # Main backend server (main.go)
│ ├── mcp/ # MCP server binary
│ └── cli/ # CLI tool
├── internal/ # Go backend core code
│ ├── handlers/ # HTTP handlers (REST API)
│ ├── services/ # Business logic services
│ ├── db/ # Database layer
│ ├── mcp/ # MCP server binary (stdio transport)
│ └── memoh/ # Unified binary wrapper (Cobra CLI)
├── internal/ # Go backend core code (domain packages)
│ ├── accounts/ # User account management (CRUD, password hashing)
│ ├── attachment/ # Attachment normalization (MIME types, base64)
│ ├── auth/ # JWT authentication middleware and utilities
│ ├── bind/ # Channel identity-to-user binding code management
│ ├── boot/ # Runtime configuration provider (container backend detection)
│ ├── bots/ # Bot management (CRUD, lifecycle)
│ ├── bun/ # Bun runtime manager (agent gateway process lifecycle)
│ ├── channel/ # Channel adapter system (Telegram, Discord, Feishu, Local, Email)
│ ├── config/ # Configuration loading and parsing (TOML)
│ ├── containerd/ # Container runtime abstraction (containerd / Apple Virtualization)
│ ├── conversation/ # Conversation management and flow resolver
│ ├── db/ # Database connection and migration utilities
│ │ └── sqlc/ # ⚠️ Auto-generated by sqlc — DO NOT modify manually
│ ├── channel/ # Channel adapters (Telegram, Feishu, Local)
│ ├── memory/ # Memory / embedding system
│ ├── mcp/ # MCP protocol implementation
│ ├── conversation/ # Conversation flow management
│ ├── bots/ # Bot management
── containerd/ # Container management
├── agent/ # Agent Gateway (Bun/Elysia)
│ ├── email/ # Email provider and outbox management (Mailgun, generic SMTP)
│ ├── embedded/ # Embedded filesystem assets (web, agent, bun)
│ ├── embeddings/ # Embedding model resolver
│ ├── handlers/ # HTTP request handlers (REST API endpoints)
│ ├── healthcheck/ # Health check adapter system (MCP, channel checkers)
── heartbeat/ # Heartbeat scheduling service (cron-based)
├── identity/ # Identity type utilities (human vs bot)
│ ├── inbox/ # Bot inbox service (notifications, triggers)
│ ├── logger/ # Structured logging (slog)
│ ├── mcp/ # MCP protocol manager (container lifecycle, tool gateway)
│ ├── media/ # Content-addressed media asset service
│ ├── memory/ # Long-term memory system (Qdrant, BM25, LLM extraction)
│ ├── message/ # Message persistence and event publishing
│ ├── models/ # LLM model management (CRUD, variants)
│ ├── policy/ # Access policy resolution (guest access, bot type)
│ ├── preauth/ # Pre-authentication key management
│ ├── providers/ # LLM provider management (OpenAI, Anthropic, etc.)
│ ├── prune/ # Text pruning utilities (truncation with head/tail)
│ ├── schedule/ # Scheduled task service (cron)
│ ├── searchproviders/ # Search engine provider management (Brave, etc.)
│ ├── server/ # HTTP server wrapper (Echo setup, middleware, shutdown)
│ ├── settings/ # Bot settings management
│ ├── storage/ # Storage provider interface (filesystem, container FS)
│ ├── subagent/ # Sub-agent management (CRUD)
│ └── version/ # Build-time version information
├── agent/ # Agent Gateway service (Bun/Elysia)
│ └── src/
├── packages/ # Frontend monorepo
├── web/ # Main web app (Vue 3)
├── ui/ # Shared UI component library
├── sdk/ # TypeScript SDK (auto-generated from OpenAPI)
├── cli/ # TypeScript CLI
│ └── config/ # Shared configuration utilities
│ ├── index.ts # Elysia server entry point
├── modules/ # Route modules (chat, stream, trigger)
├── middlewares/ # CORS, error handling, bearer auth
├── utils/ # SSE utilities
└── models.ts # Zod request schemas
├── packages/ # TypeScript monorepo
│ ├── agent/ # Core agent library (@memoh/agent)
│ │ └── src/
│ │ ├── agent.ts # Agent creation and streaming logic
│ │ ├── model.ts # Model configuration and creation
│ │ ├── tools/ # Tool implementations (MCP, web, subagent, skill)
│ │ ├── prompts/ # System/heartbeat/schedule/subagent prompts
│ │ ├── types/ # TypeScript type definitions
│ │ └── utils/ # Attachments, headers, filesystem utilities
│ ├── web/ # Main web app (@memoh/web, Vue 3)
│ ├── ui/ # Shared UI component library (@memoh/ui)
│ ├── sdk/ # TypeScript SDK (@memoh/sdk, auto-generated from OpenAPI)
│ ├── cli/ # CLI tool (@memoh/cli, Commander.js)
│ └── config/ # Shared configuration utilities (@memoh/config)
├── spec/ # OpenAPI specifications (swagger.json, swagger.yaml)
├── db/ # Database
│ ├── migrations/ # SQL migration files
│ └── queries/ # SQL query files (sqlc input)
├── conf/ # Configuration templates (app.example.toml, app.dev.toml, app.docker.toml)
├── conf/ # Configuration templates
│ ├── app.example.toml # Default configuration template
│ ├── app.dev.toml # Development configuration
│ ├── app.docker.toml # Docker deployment configuration
│ ├── app.apple.toml # macOS (Apple Virtualization) configuration
│ └── app.windows.toml # Windows configuration
├── devenv/ # Development environment (docker-compose for local infra)
├── docker/ # Docker build & runtime (Dockerfiles, entrypoints, nginx.conf)
├── docker/ # Docker build & runtime (Dockerfiles, entrypoints, nginx)
├── docs/ # Documentation site
├── scripts/ # Utility scripts
├── assets/ # Static assets (images, etc.)
├── data/ # Runtime data directory
├── docker-compose.yml # Docker Compose orchestration (production)
├── mise.toml # mise tasks and tool version definitions
── sqlc.yaml # sqlc code generation config
── sqlc.yaml # sqlc code generation config
├── openapi-ts.config.ts # SDK generation config (@hey-api/openapi-ts)
├── bump.config.ts # Version bumping config (bumpp)
├── vitest.config.ts # Test framework config (Vitest)
├── tsconfig.json # TypeScript monorepo config
├── eslint.config.mjs # ESLint config
└── typos.toml # Typo checker config
```
## Development Guide
@@ -107,6 +171,11 @@ Memoh/
| `mise run sdk-generate` | Generate TypeScript SDK (depends on swagger-generate) |
| `mise run db-up` | Initialize and migrate the database |
| `mise run db-down` | Drop the database |
| `mise run build-embedded-assets` | Build and stage embedded web/agent/bun assets |
| `mise run build-unified` | Build unified memoh binary |
| `mise run release` | Release new version (bumpp) |
| `mise run release-binaries` | Build release archive for target (requires TARGET_OS TARGET_ARCH) |
| `mise run install-cli` | Install CLI locally |
### Docker Deployment
@@ -144,53 +213,84 @@ Migrations live in `db/migrations/` and follow a dual-update convention:
### API Development Workflow
1. Write handlers in `internal/handlers/` with swaggo annotations.
2. Run `mise run swagger-generate` to update the OpenAPI docs.
2. Run `mise run swagger-generate` to update the OpenAPI docs (output in `spec/`).
3. Run `mise run sdk-generate` to update the frontend TypeScript SDK (`packages/sdk/`).
4. The frontend calls APIs via the auto-generated `@memoh/sdk`.
### Agent Development
- The core agent logic lives in `packages/agent/` (`@memoh/agent`), providing reusable agent streaming, tool execution, and prompt management.
- The Agent Gateway (`agent/`) is a thin Elysia HTTP service that uses `@memoh/agent` for processing.
- AI model providers (Anthropic, OpenAI, Google) are integrated via Vercel AI SDK.
- Tools (MCP, web search, subagent, skill) are defined in `packages/agent/src/tools/`.
- Prompt templates (system, heartbeat, schedule, subagent) are in `packages/agent/src/prompts/`.
### Frontend Development
- Use Vue 3 Composition API with `<script setup>` style.
- Shared components belong in `packages/ui/`.
- API calls use the auto-generated `@memoh/sdk`.
- State management uses Pinia; data fetching uses Pinia Colada.
- i18n via vue-i18n.
### Container Management
- In Docker deployment, containerd runs inside the server container.
- On macOS, Apple Virtualization is used as container backend.
- Each bot has its own isolated container instance.
## Database Tables
| Table | Description |
|-------|-------------|
| `users` | User accounts (admin/member roles) |
| `channel_identities` | Unified identity system (cross-platform) |
| `bots` | Bot definitions with model references |
| `users` | User accounts (username, email, role, display_name, avatar) |
| `channel_identities` | Unified inbound identity subject (cross-platform) |
| `user_channel_bindings` | Outbound delivery config per user/channel |
| `llm_providers` | LLM provider configurations (name, base_url, api_key) |
| `search_providers` | Search engine provider configurations |
| `models` | Model definitions (chat/embedding types, modalities, reasoning) |
| `model_variants` | Model variant definitions (weight, metadata) |
| `bots` | Bot definitions with model references and settings |
| `bot_members` | Bot membership (owner/admin/member) |
| `mcp_connections` | MCP connection configurations per bot |
| `bot_channel_configs` | Per-bot channel configurations |
| `bot_channel_routes` | Conversation route mapping |
| `bot_history_messages` | Unified message history |
| `llm_providers` | LLM provider configurations |
| `models` | Model definitions (chat/embedding types) |
| `mcp_connections` | MCP connection configurations |
| `bot_preauth_keys` | Bot pre-authentication keys |
| `channel_identity_bind_codes` | One-time codes for channel identity → user linking |
| `bot_channel_routes` | Conversation route mapping (inbound thread → bot history) |
| `bot_history_messages` | Unified message history under bot scope |
| `bot_history_message_assets` | Message → content_hash asset links |
| `containers` | Bot container instances |
| `snapshots` | Container snapshots |
| `container_versions` | Container version tracking |
| `lifecycle_events` | Container lifecycle events |
| `schedule` | Scheduled tasks (cron) |
| `subagents` | Sub-agent definitions |
| `search_providers` | Search engine provider configurations |
| `storage_providers` | Pluggable object storage backends |
| `bot_storage_bindings` | Per-bot storage backend selection |
| `bot_inbox` | Per-bot inbox (notifications, triggers) |
| `bot_heartbeat_logs` | Heartbeat execution records |
| `email_providers` | Pluggable email service backends (Mailgun, generic SMTP) |
| `bot_email_bindings` | Per-bot email provider binding with permissions |
| `email_outbox` | Outbound email audit log |
## Configuration
The main configuration file is `config.toml` (copied from `conf/app.example.toml` or `conf/app.dev.toml` for development), containing:
The main configuration file is `config.toml` (copied from `conf/app.example.toml` or environment-specific templates for development), containing:
- `[log]` — Logging configuration (level, format)
- `[server]` — HTTP listen address
- `[admin]` — Admin account credentials
- `[auth]` — JWT authentication settings
- `[containerd]` — Container runtime socket path
- `[containerd]` — Container runtime configuration (socket path, namespace)
- `[mcp]` — MCP image and data configuration
- `[postgres]` — PostgreSQL connection
- `[qdrant]` — Qdrant vector database connection
- `[agent_gateway]` — Agent Gateway address
- `[web]` — Web frontend address
- `[brave]` — Brave Search API configuration
Configuration templates available in `conf/`:
- `app.example.toml` — Default template
- `app.dev.toml` — Development (connects to devenv docker-compose)
- `app.docker.toml` — Docker deployment
- `app.apple.toml` — macOS (Apple Virtualization backend)
- `app.windows.toml` — Windows
+313
View File
@@ -0,0 +1,313 @@
# Web Frontend (packages/web)
## Overview
`@memoh/web` is the management UI for Memoh, built with Vue 3 + Vite. It provides visual configuration for bots, models, channels, memory, and more.
## Tech Stack
| Category | Technology |
|----------|-----------|
| Framework | Vue 3 (Composition API, `<script setup>`) |
| Build | Vite 7 + `@vitejs/plugin-vue` |
| CSS | Tailwind CSS 4 (CSS-based config, no `tailwind.config.*`) |
| UI Library | `@memoh/ui` (built on Reka UI + class-variance-authority) |
| State | Pinia 3 + `pinia-plugin-persistedstate` |
| Data Fetching | Pinia Colada (`@pinia/colada`) + `@memoh/sdk` |
| Forms | vee-validate + `@vee-validate/zod` + Zod |
| i18n | vue-i18n (en / zh) |
| Icons | FontAwesome (primary) + lucide-vue-next (secondary) |
| Toast | vue-sonner |
| Tables | @tanstack/vue-table |
| Markdown | markstream-vue + Shiki + Mermaid + KaTeX |
| Utilities | @vueuse/core |
| TypeScript | ~5.9 (strict mode) |
## Directory Structure
```
src/
├── App.vue # Root component (RouterView + Toaster)
├── main.ts # App entry (plugins, global components, API client setup)
├── router.ts # Route definitions and auth guard
├── style.css # Tailwind imports, CSS variables, theme tokens
├── i18n.ts # vue-i18n configuration
├── assets/ # Static assets
├── components/ # Shared components
│ ├── sidebar/ # App sidebar navigation
│ ├── main-container/ # Main content area (header + breadcrumb + content)
│ ├── master-detail-sidebar-layout/ # Master-detail layout pattern
│ ├── data-table/ # TanStack table wrapper
│ ├── form-dialog-shell/ # Dialog wrapper for forms
│ ├── confirm-popover/ # Confirmation popover
│ ├── loading-button/ # Button with loading state
│ ├── status-dot/ # Status indicator dot
│ ├── warning-banner/ # Warning banner
│ ├── search-provider-logo/ # Search provider icons
│ ├── searchable-select-popover/ # Searchable dropdown
│ ├── add-platform/ # Add platform dialog
│ ├── add-provider/ # Add LLM provider dialog
│ ├── create-model/ # Create model dialog
│ └── chat-list/ # Chat list helpers
├── composables/ # Reusable composition functions
│ ├── api/ # API-related composables (chat, SSE, platform)
│ ├── useDialogMutation.ts # Mutation wrapper with toast error handling
│ ├── useRetryingStream.ts # SSE retry with exponential backoff
│ ├── useSyncedQueryParam.ts # URL query param sync
│ ├── useBotStatusMeta.ts # Bot status metadata
│ ├── useAvatarInitials.ts # Avatar initial generation
│ ├── useClipboard.ts # Clipboard utilities
│ └── useKeyValueTags.ts # Tag management
├── constants/ # Constants (client types, etc.)
├── i18n/locales/ # Translation files (en.json, zh.json)
├── layout/
│ └── main-layout/ # Top-level layout (SidebarProvider)
├── lib/
│ └── api-client.ts # SDK client setup (base URL, auth interceptor)
├── pages/ # Route page components
│ ├── login/ # Login page
│ ├── main-section/ # Authenticated layout wrapper
│ ├── home/ # Home page
│ ├── chat/ # Chat interface (SSE streaming)
│ ├── bots/ # Bot list + detail (tabs: overview, memory, channels, etc.)
│ ├── models/ # LLM provider & model management
│ ├── search-providers/ # Search provider management
│ ├── email-providers/ # Email provider management
│ ├── settings/ # User settings (profile, password, theme, channels)
│ └── platform/ # Platform management
├── store/ # Pinia stores
│ ├── user.ts # User state, JWT token, login/logout
│ ├── settings.ts # UI settings (theme, language)
│ ├── capabilities.ts # Server capabilities (container backend)
│ └── chat-list.ts # Chat state, messages, SSE streaming
└── utils/ # Utility functions
├── api-error.ts # API error message extraction
├── date-time.ts # Date/time formatting
├── channel-icons.ts # Channel platform icons
└── key-value-tags.ts # Tag ↔ Record conversion
```
## Routes
| Path | Name | Component | Description |
|------|------|-----------|-------------|
| `/login` | Login | `login/index.vue` | Login form (no auth required) |
| `/chat` | chat | `chat/index.vue` | Chat interface with bot sidebar |
| `/home` | home | `home/index.vue` | Home dashboard |
| `/bots` | bots | `bots/index.vue` | Bot list grid |
| `/bots/:botId` | bot-detail | `bots/detail.vue` | Bot detail with tabs |
| `/models` | models | `models/index.vue` | LLM provider & model management |
| `/search-providers` | search-providers | `search-providers/index.vue` | Search provider management |
| `/email-providers` | email-providers | `email-providers/index.vue` | Email provider management |
| `/settings` | settings | `settings/index.vue` | User settings |
| `/platform` | platform | `platform/index.vue` | Platform management |
Auth guard: all routes except `/login` require `localStorage.getItem('token')`. Logged-in users accessing `/login` are redirected to `/chat`.
## Layout System
Three-tier layout architecture:
1. **MainLayout** (`layout/main-layout/`) — Top-level wrapper using `SidebarProvider` from `@memoh/ui`. Provides `#sidebar` and `#main` slots.
2. **Sidebar** (`components/sidebar/`) — Collapsible navigation with logo, menu items, and user avatar footer. Active route highlighting.
3. **MainContainer** (`components/main-container/`) — Header (sidebar trigger + breadcrumb) + scrollable content area with `<KeepAlive>` wrapped `<RouterView>`.
Several pages use **MasterDetailSidebarLayout** (`components/master-detail-sidebar-layout/`) for left-sidebar + detail-panel patterns (chat, models, search providers, email providers).
## CSS & Theming
### Tailwind CSS 4
CSS-based configuration in `style.css` (no `tailwind.config.*` file):
```css
@import "tailwindcss";
```
Design tokens are CSS custom properties in `:root` / `.dark` using OKLCH color space:
- Colors: `--background`, `--foreground`, `--primary`, `--secondary`, `--muted`, `--accent`, `--destructive`, `--border`, `--input`, `--ring`
- Sidebar: `--sidebar-background`, `--sidebar-foreground`, `--sidebar-primary`, etc.
- Radius: `--radius` with size variants
- Chart: `--chart-1` through `--chart-5`
Tokens are mapped to Tailwind via `@theme inline` block in `style.css`.
### Dark Mode
- CSS: `@custom-variant dark (&:is(.dark *))` in `style.css`
- Runtime: `useColorMode` from `@vueuse/core` in `store/settings.ts`
- Storage: theme preference persisted via `useStorage`
- Usage: `dark:` variant classes (e.g., `dark:bg-gray-900`)
### Styling Convention
- **Utility-first**: Tailwind classes as primary styling method. Minimal `<style>` blocks.
- **Semantic tokens**: Use theme variables (`text-foreground`, `bg-background`, `text-muted-foreground`) instead of raw colors.
- **No scoped CSS modules**: Styling is done inline via utility classes.
### CSS Imports (main.ts)
```
style.css — Tailwind + theme tokens
markstream-vue/index.css — Markdown rendering
katex/dist/katex.min.css — Math rendering
vue-sonner/style.css — Toast notifications (in App.vue)
```
## UI Components (@memoh/ui)
`@memoh/ui` provides 40+ components built on Reka UI primitives + Tailwind + class-variance-authority:
- **Form**: `Form`, `FormField`, `FormItem`, `FormControl`, `FormLabel`, `FormMessage`
- **Input**: `Input`, `Textarea`, `InputGroup`, `NativeSelect`, `Combobox`, `TagsInput`
- **Selection**: `Select`, `RadioGroup`, `Checkbox`, `Switch`
- **Layout**: `Card`, `Separator`, `Sheet`, `Sidebar`, `ScrollArea`, `Collapsible`
- **Overlays**: `Dialog`, `Popover`, `Tooltip`, `DropdownMenu`, `ContextMenu`
- **Data**: `Table`, `Badge`, `Avatar`, `Skeleton`, `Empty`
- **Navigation**: `Breadcrumb`, `Tabs`, `Pagination`
- **Feedback**: `Button`, `ButtonGroup`, `Spinner`, `Alert`
### Form Pattern (vee-validate + Zod)
```vue
<script setup>
const form = useForm({
validationSchema: toTypedSchema(z.object({
name: z.string().min(1),
})),
})
</script>
<template>
<FormField v-slot="{ componentField }" name="name">
<FormItem>
<Label>Name</Label>
<FormControl>
<Input v-bind="componentField" />
</FormControl>
<FormMessage />
</FormItem>
</FormField>
</template>
```
### Icon Usage
- **FontAwesome** (primary): Global `<FontAwesomeIcon :icon="['fas', 'robot']" />`, icons registered in `main.ts`
- **Lucide** (secondary): Direct imports `<Sun />`, `<Moon />`, used for theme toggle
### Notification Pattern
```typescript
import { toast } from 'vue-sonner'
toast.success(t('common.saved'))
toast.error(resolveApiErrorMessage(error, 'Failed'))
```
## Data Fetching
### API Client Setup (`lib/api-client.ts`)
- SDK: `@memoh/sdk` auto-generated from OpenAPI via `@hey-api/openapi-ts`
- Base URL: `VITE_API_URL` env var (defaults to `/api`, proxied by Vite dev server to backend)
- Auth: Request interceptor attaches `Authorization: Bearer ${token}` from localStorage
- 401 handling: Response interceptor removes token and redirects to `/login`
### Pinia Colada (Server State)
Primary data fetching mechanism for CRUD operations:
```typescript
// Query — auto-generated from SDK
const { data, isLoading } = useQuery(getBotsQuery())
// Custom query with dynamic key
const { data } = useQuery({
key: () => ['bot-settings', botId.value],
query: async () => {
const { data } = await getBotsByBotIdSettings({
path: { bot_id: botId.value },
throwOnError: true,
})
return data
},
enabled: () => !!botId.value,
})
// Mutation with cache invalidation
const queryCache = useQueryCache()
const { mutateAsync } = useMutation({
mutation: async (body) => {
const { data } = await putBotsByBotIdSettings({
path: { bot_id: botId.value },
body,
throwOnError: true,
})
return data
},
onSettled: () => queryCache.invalidateQueries({
key: ['bot-settings', botId.value],
}),
})
```
SDK also generates colada helpers: `getBotsQuery()`, `postBotsMutation()`, query key factories.
### Pinia Stores (Client State)
| Store | Purpose |
|-------|---------|
| `user` | JWT token (`useLocalStorage`), user info, login/logout |
| `settings` | Theme (dark/light), language (en/zh), persisted |
| `capabilities` | Server feature flags (container backend, snapshot support) |
| `chat-list` | Chat messages, streaming state, SSE event processing |
Stores use Composition API style (`defineStore(() => { ... })`), with persistence via `pinia-plugin-persistedstate`.
### SSE Streaming (Chat)
Chat responses are streamed via Server-Sent Events:
- **Endpoints**: `/bots/{bot_id}/web/stream` (chat), `/bots/{bot_id}/messages/events` (real-time updates)
- **Parsing**: `composables/api/useChat.sse.ts` reads `ReadableStream<Uint8Array>` and parses SSE `data:` lines
- **Events**: `text_delta`, `reasoning_delta`, `tool_call_start/end`, `attachment_delta`, `processing_completed/failed`
- **Retry**: `useRetryingStream` composable provides exponential backoff for reconnection
- **State**: `store/chat-list.ts` processes streaming events into reactive message blocks in real-time
- **Abort**: Stream cancellation via `AbortSignal`
### Error Handling
- **Global**: `utils/api-error.ts``resolveApiErrorMessage()` extracts error from `message`, `error`, `detail` fields
- **Mutations**: `useDialogMutation` composable wraps mutations with automatic `toast.error()` on failure
- **SDK**: All calls use `throwOnError: true`; try/catch at component level
- **Streams**: `processing_failed` / `error` events appended to message blocks
## i18n
- Plugin: vue-i18n (Composition API, `legacy: false`)
- Locales: `en` (English, default), `zh` (Chinese)
- Files: `src/i18n/locales/en.json`, `src/i18n/locales/zh.json`
- Usage: `const { t } = useI18n()``t('bots.title')`
- Key namespaces: `common`, `auth`, `sidebar`, `settings`, `chat`, `models`, `provider`, `searchProvider`, `emailProvider`, `mcp`, `bots`, `home`
## Vite Configuration
- Dev server port: 8082 (from `config.toml`)
- Proxy: `/api` → backend (default `http://localhost:8080`)
- Aliases: `@``./src`, `#``../ui/src`
- Config: reads from `../../config.toml` via `@memoh/config`
## Development Rules
- Use Vue 3 Composition API with `<script setup>` exclusively.
- Style with Tailwind utility classes; avoid `<style>` blocks.
- Use semantic color tokens (`text-foreground`, `bg-background`) instead of raw colors.
- Use `@memoh/ui` components for all UI primitives; do not import Reka UI directly.
- Use Pinia Colada (`useQuery`/`useMutation`) for server state; use Pinia stores for client state only.
- API calls must go through `@memoh/sdk`; never call `fetch()` directly.
- All user-facing strings must use i18n keys (`t('key')`) — never hardcode text.
- Forms must use vee-validate + Zod schemas via `toTypedSchema()`.
- Error messages via `resolveApiErrorMessage()` + `toast.error()`.
- Page components go in `pages/{feature}/`; page-specific sub-components go in `pages/{feature}/components/`.
- Shared components go in `components/`.
- Composables go in `composables/`; API-specific composables in `composables/api/`.