summaryrefslogtreecommitdiffhomepage
path: root/packages/api/src
AgeCommit message (Collapse)Author
2026-05-23feat: fallback model range slider with live label, model-changed eventAdam Malczewski
- Added model-changed event: backend emits it on fallback, frontend updates tab keyId/modelId - Range slider embedded inside active agent card when >1 model configured - Live label updates on drag (oninput), backend call only on release (onchange) - Slider auto-positions when fallback occurs via model-changed WS event
2026-05-23feat: key fallback using agent models[] hierarchy, background tool modes, ↵Adam Malczewski
copy truncation - Agent rate-limit fallback now iterates through agent's configured models[] in strict order - Frontend sends agentModels with each /chat request; backend uses buildFallbackSequence() - Emits notice event on fallback so chat shows which key failed and what's being tried next - Child agents inherit parent's agentModels for fallback - Added statusCode propagation from AI SDK errors for programmatic 429 detection - Copy button truncates all tool results at 300 chars (was 200 for 4 specific tools) - run_shell, summon, youtube_transcribe: background mode support - summon: blocking mode by default with getResult callback
2026-05-23feat: relative working directory support and subagent tab cwd propagationAdam Malczewski
- Resolve relative cwd paths (e.g. ./subtask) against parent's working directory at runtime - check-dir endpoint resolves relative paths and returns the resolved absolute path - AgentBuilder shows resolved path below input for relative paths, updated helper text - tab-created event now includes workingDirectory so subagent tabs display their cwd in sidebar - Add workingDirectory to tab-created AgentEvent type definition - spawnChildAgent stores resolved absolute path instead of raw relative path
2026-05-23feat: add is_subagent flag to agents, fix all lint/type/test issuesAdam Malczewski
- Add is_subagent checkbox to agent editor; subagents are hidden from Chat Settings - Add is_subagent field to AgentDefinition type, TOML serialization, and API route - Filter subagents from ModelSelector agent list - Fix all biome lint/format errors across codebase (useLiteralKeys, noNonNullAssertion, noExplicitAny, formatting, import sorting) - Fix svelte-check errors (type narrowing in SkillsBrowser, ToolPermissions, SidebarPanel) - Fix a11y warnings in App.svelte (label-control associations) - Fix test mocks missing BackgroundShellStore, BackgroundTranscriptStore, createWebSearchTool, createYoutubeTranscribeTool - Update stale 409 test to match current message-queuing behavior - Exclude packaging/ and release/ dirs from biome to avoid linting stale build artifacts
2026-05-23feat: youtube_transcribe blocks with polling, interruptible with background ↵Adam Malczewski
retrieve - youtube_transcribe now polls until transcript is ready (waits estimated_seconds - 2s, min 2s) - Times out after 10 minutes of polling - When user interrupts, polling continues in background with youtube_transcribe_<uuid> job ID - BackgroundTranscriptStore holds polling jobs, retrieve tool resolves them - ToolCallDisplay shows 'interrupted' badge (blue) when result contains [USER INTERRUPT] - Applies to all interruptible tools: run_shell, youtube_transcribe, retrieve
2026-05-23feat: web_search + youtube_transcribe tools, shell interrupt backgrounding, ↵Adam Malczewski
fixes - Add web_search tool (Firecrawl POST to /v1/search with query, limit, lang, country, scrapeOptions) - Add youtube_transcribe tool (GET to transcriber service, handles completed/queued/failed statuses) - Both tools registered for parent agents (always) and child agents (permission-gated) - Added to summon enum, TOOL_DESCRIPTIONS, and core exports - Shell interrupt: run_shell now races against user queue interrupt - When interrupted, command continues in background with run_shell_<uuid> job ID - BackgroundShellStore holds running processes, auto-cleans 10min after completion - retrieve tool extended to handle both agent IDs and shell job IDs - Tool error detection: results starting with 'Error:' now marked isError in UI - Fix TS error: cast unavailMatch[1] regex capture group to string - Docker: network_mode host for Tailscale/LAN access to external services - Bun.serve idleTimeout set to 60s (was default 10s) - KeyUsage: clearer message when OpenCode usage data unavailable - Firecrawl: only send scrapeOptions when scrape=true (avoid 400 on instances without scrape support)
2026-05-22feat: message queue/interrupt system, CORS fix, mobile fixes, chat splittingAdam Malczewski
- Add message queue allowing users to send messages while agent is running - Queue messages are injected into tool results as [USER INTERRUPT] - Retrieve tool interrupted via Promise.race when user message arrives - Queued messages show with 'queued' badge and cancel button - Consumed messages repositioned and chat splits at interrupt point - New assistant message block created after interrupt for clean flow - Add POST /chat/cancel endpoint for cancelling queued messages - Fix CORS to allow any origin (Tailscale/LAN access) - Fix crypto.randomUUID fallback for non-secure contexts (HTTP) - Fix frontend API URL derivation from page hostname - Auto-create DB tab if missing on processMessage (foreign key fix) - Add error logging to processMessage catch block - Fix working directory input sync on agent switch - Fix agent mode button to re-apply agent settings
2026-05-22feat: add/remove keys from UI, backend URL setting, user service, Docker fixAdam Malczewski
- Add POST /models/add-key and POST /models/remove-key API endpoints - Add 'Add New Key' modal (page-level) with provider selection - Add remove button per key in Model Status view - Add configurable backend URL setting in Settings panel with localStorage persistence - Convert systemd service from system to user service (systemctl --user) - Fix Docker entrypoint to chown all nested node_modules dirs - Update dispatch.toml credential paths to use -pro/-max naming - Make API port configurable via PORT env var (default 3000, prod 18390)
2026-05-22feat: Arch Linux packaging with Electron frontend, systemd backend service, ↵Adam Malczewski
and Windows exe build - Add Electron wrapper (main.cjs, preload.cjs) for desktop frontend - Add systemd service unit, env config, and sysusers for backend API - Add PKGBUILD and .install for Arch package (makepkg -si) - Add desktop entry, SVG/PNG icon, and wrapper scripts - Add bin/build-pkg, bin/install-pkg, bin/windows-pkg scripts - Make API port configurable via PORT env var (default 3000, prod 18390) - Add electron-builder config for Windows exe cross-compilation - Set vite base to './' for Electron file:// loading
2026-05-22feat: agent builder, CWD support, auto-save, UI polish, unavailable tool ↵Adam Malczewski
handling - Agent Builder: full CRUD with card grid, drag-and-drop model reorder, edit/delete - Auto-save on edit with 600ms debounce, AbortController for concurrency, fieldset disabled until name entered - Agent definitions stored as TOML with cwd field, loaded from global/project dirs - Working directory: per-tab CWD override in Chat Settings, agent default CWD, auto-create on first message - CWD validation: check-dir endpoint with ~ expansion, real-time validity indicator - Subagent CWD validated against parent's effective CWD using path.relative - Unavailable tool calls: caught gracefully, shown as tool call with error badge, model retries - UI: tab bar border radius, sidebar border removed, chat input ghost style, scroll-to-bottom rectangle - Skills dir collapse uses CSS rotation, Model Choice renamed to Chat Settings, System Prompt view removed - Reusable SkillsBrowser/ToolPermissions with external mode for Agent Builder - ModelSelector: Agent/Manual toggle, agent list, Agent Settings link - Page router, skills recursive scanning, bin/up gopass removed, docker volume mounts
2026-05-22feat: two-row tab bar with temp/persistent subagent tabs, tab persistenceAdam Malczewski
- Split tab bar into user tabs (top) and subagent tabs (bottom row) - Bottom row only visible when active user tab has child agents - Parent user tab stays highlighted when viewing a subagent tab - Temp tabs auto-disappear when agent completes, click to promote to persistent - 'Open Tab' button on summon tool calls to view/reopen subagent history - Reopening archived tabs fetches full chat history from backend - Add parent_tab_id column to DB with safe ALTER TABLE migration - Persist keyId, modelId, parentTabId on child tab creation - Flush partial assistant messages on abort/error (finally block) - Defensive JSON.parse in message restoration - Allow all Vite hosts for local development - Fix nested button in ToolCallDisplay (button inside button)
2026-05-22fix: child tabs now show correct key/model in Model Choice viewAdam Malczewski
Include keyId and modelId in the tab-created WebSocket event so child agent tabs inherit the parent's model selection on the frontend.
2026-05-22feat: agent summoning system, todo improvements, security fixes, ↵Adam Malczewski
double-execution bug fix - Add summon/retrieve tools for spawning child agents in new tabs - summon: non-blocking, returns agent_id immediately - retrieve: blocking, waits for child to finish, returns result - Child tools are intersected with parent permissions (no privilege escalation) - Working directory validated to stay within workspace - Abort controller stops orphaned agents on tab close - Rename task_list tool to todo with comprehensive usage guidance in system prompt - Rename PermissionLog.svelte to ToolPermissions.svelte - Add 'Summon agents' toggle to tool permissions UI - Redesign TaskListPanel with DaisyUI checkboxes (indeterminate for in-progress) - Remove 'blocked' status from task system - Add tab-created WebSocket event for child agent tab visibility - Add HMR cleanup for WebSocket connections (close stale connections on hot reload) - Fix ensureAssistantMessage to not throw on closed tabs - Fix double tool execution: remove execute from AI SDK tool() in registry.ts (agent.ts already executes tools manually via executeToolWithStreaming) - Fix all pre-existing test failures (missing mocks, stale API signatures) - Add debug info to copy button (tab ID, injected skills, all tab IDs) - Add tab ID and tools to conversation copy output
2026-05-21feat: skills system with toggle/inject, tab bar UX, streaming dedup fixAdam Malczewski
- Add skills toggle system: check skills in sidebar to inject with next message - Auto-check default skills on new tab creation for first-message injection - Track injected skills per tab with visual highlights in skills browser - Redesign tab bar: double-click background for new tab, larger close button - Update default system prompt - Fix streaming text duplication: change WS callbacks from array to Set - Fix biome config: exclude references/ directory - Auto-format with biome
2026-05-21feat: system prompt editor, tool permissions save-on-send, responsive ↵Adam Malczewski
sidebar, UI polish - System Prompt sidebar view: editable textarea, save-on-send, reset button - Tool permissions: save-on-send pattern (not immediate), reset button - Dynamic system prompt: buildSystemPrompt reads from DB, tool list auto-generated - Responsive sidebar: overlay on small screens with backdrop - Chat bubbles: user=fit-width, assistant=full-width - Fix infinite loops (use onMount for data fetching) - Fix sendMessage race condition (await settings saves before chat POST) - Model selector: auto-open model modal after key selection - Rename views: Permissions->Tools, Tab Settings->Model Choice - Shared appSettings store for cross-component reactive state - Delete old chat.svelte.ts
2026-05-21feat: tool permission toggles, settings improvements, UI polishAdam Malczewski
- Tool permissions (read, edit, bash) stored in DB and control Agent tool registration - Agent invalidated when permissions change; cache warning in Permissions panel - Default: read=allow, edit=ask, bash=ask (matches UI checkboxes) - Settings: auto-save title model on selection (removed save button) - Settings: auto-expand thinking checkbox with shared reactive store - Permissions panel: renamed from Permission Log, shows tool toggles + collapsible log - Sidebar: renamed Current Model to Model Choice - Chat input: allow typing while agent runs (just disable send) - Chat cursor: fix doubled rectangle (removed unicode char) - Generic GET/PUT /tabs/settings/:key endpoints for key-value settings
2026-05-21feat: tab system with per-tab agents, DB persistence, and DaisyUI tabs-lift UIAdam Malczewski
- Add tabs, messages, and settings tables to SQLite database - Backend: refactor AgentManager to manage per-tab Agent instances via Map<tabId, TabAgent> - Backend: WebSocket events tagged with tabId for multiplexing - Backend: tab CRUD routes (create, list, update, archive, messages) - Backend: persist user and assistant messages to DB during chat - Frontend: new tabStore replaces single chatStore with multi-tab reactive state - Frontend: TabBar component using DaisyUI tabs-lift style with status dots - Frontend: Settings sidebar panel for title generation model selection - Frontend: wire ChatPanel, ChatInput, Header to use tabStore - Fix HMR listener accumulation via wsClient.clearCallbacks() - Delete old single-chat chatStore (chat.svelte.ts)
2026-05-21refactor: gut model/tag/fallback/agent-template system, fix Docker setupAdam Malczewski
- Remove ModelResolver, model definitions, model tags, fallback order, agent templates - Remove all [[models]], [agents], and fallback from dispatch.toml and config schema - ModelRegistry is now a pure key-state manager - dispatch.toml reduced to keys + permissions only - Docker: fix entrypoint for existing UID, skip bun install in frontend container - Docker: scoped build cache prune in bin/clean
2026-05-21feat: SQLite database for all credentials, keys, wake schedule, and usage cacheAdam Malczewski
- Add SQLite database at ~/.local/share/dispatch/dispatch.db with tables: credentials, api_keys, wake_schedule, usage_cache - Store Claude OAuth credentials in DB with import button in Model Status UI - Store OpenCode/Copilot API keys in DB with paste-to-import modal - Store OpenCode cookie and workspace IDs in DB - Migrate wake schedule from .wake-schedule.json to DB - Migrate usage cache from in-memory Map + localStorage to DB - Remove all env var and file fallbacks — DB is the single source of truth - Add seed scripts: bin/import-credentials.ts, bin/seed-opencode-keys.ts - Docker: container runs as host UID/GID with matching home directory - Clean up dispatch.toml: remove env fields, update comments - Progress bar time markers for usage cycle tracking
2026-05-21fix: wake scheduler persistence/retry, credential filtering, usage cache and ↵Adam Malczewski
display names - Wake scheduler: fix Bun timer leak, make recurring daily, persist to disk, retry failed wakes every 5min for 30min, start at boot - Key usage: localStorage cache survives page refresh, spinner during all refreshes, show cached data immediately - Credential filtering: key-usage and wake only use configured credentials_file, exclude unconfigured accounts - Display: remove counter suffix from Claude labels, format opencode/copilot key names
2026-05-21fix: backend wake scheduler with atomic toggle API, American time displayAdam Malczewski
- Replaced POST /wake-schedule (full-replace) with POST /wake-schedule/toggle (atomic single-hour toggle) to eliminate race conditions between frontend and scheduler - Recursive setTimeout prevents overlapping wake executions - HMR-safe via global timer reference - Frontend now uses toggle endpoint instead of full schedule POST - Display shows reset time (wake hour + 5h) in American 12h format e.g. '8:15 → Reset at 1:00 PM' instead of European 24h
2026-05-20feat: Claude Reset scheduler + fix key config and Claude groupingAdam Malczewski
- Added claude-pro key pointing to default credentials, claude-max pointing to .credentials-2.json (docker path /root/.claude/) - POST /models/wake sends 'hi' to haiku for all Claude accounts - ClaudeReset.svelte: 2 AM rows + 2 PM rows of 6 hour blocks each (12-hour American format). Click blocks to schedule wake at :15 - Key Usage now groups all Claude accounts under one 'Claude' card instead of duplicating under claude-pro and claude-max cards
2026-05-20feat: key usage shows all keys at once, removes dropdown, multi-account ClaudeAdam Malczewski
- /key-usage route now returns all Claude accounts (not just first) - Added ClaudeAccountUsage type for per-account data - Frontend shows all keys stacked in scrollable cards - Each Claude account rendered separately with label + subscription badge - Removed key selector dropdown
2026-05-20feat: key usage panel — display usage data for Claude, OpenCode, and CopilotAdam Malczewski
Adds 'Key Usage' to the sidebar dropdown with per-provider live usage: - Claude: 5-hour and weekly utilization bars with reset timestamps (normalizes Anthropic's 0-100% API response to 0-1 internally) - OpenCode: Scrapes usage from workspace page via OPENCODE_COOKIE session cookie, mapping key IDs to OPENCODE_WS1_ID/OPENCODE_WS2_ID - Copilot: Fetches from api.github.com/copilot_internal/user with entitlement/remaining/quota reset tracking New files: opencode.ts, copilot.ts (usage fetchers), KeyUsage.svelte New route: GET /models/key-usage?keyId=X dispatches by provider
2026-05-20feat: claude max oauth support with multi-account switching, reasoning ↵Adam Malczewski
effort, and dynamic model listing
2026-05-20feat: phase 3 — config, skills, model groups, task list, and sidebar UIAdam Malczewski
- Config system: TOML-based dispatch.toml with hot-reload via chokidar - Model/key resolution: tag-based model selection, key fallback chains - Skills system: directory loader with TOML frontmatter, agent mappings - Task list tool: add/update/list/get operations with WebSocket events - API routes: GET /config, /skills, /skills/:name, /models, /models/resolve - Frontend: sidebar with model status, task list, config viewer, skills browser, permission log - Sliding sidebar animation using CSS transitions (not Svelte transitions)
2026-05-19feat: Phase 2 — shell permissions, tree-sitter analysis, permission UIAdam Malczewski
Permission engine: - Rule-based engine: wildcard matching, last-match-wins, reject cascade - PermissionService with pending/approved state, PermissionChecker interface - dispatch.yaml config loader with per-permission pattern rules Shell tool: - run_shell tool with child_process spawn, timeout, streaming output - Tree-sitter static analysis (web-tree-sitter + tree-sitter-bash WASM) - BashArity command normalization for 'always allow' patterns - FILE_COMMANDS set: rm, cp, mv, mkdir, ls, find, grep, cat, etc. Agent loop refactored: - Removed maxSteps, manual step loop with tool execution - Permission checks on shell commands (external_directory only) - Permission checks on file tools outside workspace boundary - Symlink bypass fix (realpathSync), .. false positive fix - Shell output streaming via Promise.race + setImmediate polling API layer: - PermissionManager wraps PermissionService, broadcasts via WebSocket - WebSocket handles permission-reply messages from frontend - Config loaded from dispatch.yaml, converted to ruleset Frontend: - Permission prompt modal (native dialog, focus trap, ARIA) - Always-allow confirmation flow with pattern preview - Shell output display (live streaming + final parsed result) - Permission log panel (fixed bottom-right overlay) - Exit code badge (green 0, red non-zero) 134 tests, typecheck clean on all 3 packages
2026-05-19fix: review findings — multi-turn history, race condition, collapse UIAdam Malczewski
- Core: toCoreMessages now includes tool calls and tool results in history - Core: isError read from step tool results instead of hardcoded false - API: status set synchronously before async generator to prevent race - Frontend: DaisyUI collapse-open class applied dynamically on expanded state - Frontend: removed duplicate isConnected update in wsClient.onEvent
2026-05-19fix: DeepSeek reasoning_content dropped on multi-step tool callsAdam Malczewski
- Base URL corrected: zen/v1 -> zen/go/v1 (opencode-go provider) - Model changed: deepseek-v4-flash-free -> deepseek-v4-flash - Added wrapLanguageModel middleware to inject reasoning_content via providerMetadata.openaiCompatible before each stream call - Fixed test mocks: removed vi.importActual (unsupported in Bun), added tool factory mocks, preserved real tool export in ai mock - Added 11 tests for the normalizeMessages middleware
2026-05-19Phase 1: single agent + basic UIAdam Malczewski
- Bun monorepo with @dispatch/core, @dispatch/api, @dispatch/frontend - Agent runtime with Vercel AI SDK, streaming via WebSocket - Tools: read_file, write_file, list_files (scoped to working directory) - Hono API server with POST /chat, GET /status, GET /health, WS /ws - Svelte 5 + DaisyUI frontend with chat UI, theme switcher, copy button - OpenCode Go (Zen) as LLM provider, deepseek-v4-flash-free model - Docker setup (dev + prod) with bin/ scripts and gopass secrets - Biome v2 linting/formatting, Vitest tests (44 passing) - Debug info attached to error messages for diagnostics