Refactor almost all modules#72
Merged
Merged
Conversation
Move chatEventPayload/chatControlPayload/chatEventType/trim helpers out of internal/server into a standalone internal/chatwire package so the session layer can shape events at ingress without an import cycle. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ifecycle New conversation stream store: one ordered event log per conversation with gateway-assigned monotonic seq, exactly-once run_finished, supersession-based run handoff, persistent subscribers with overflow-resume, retention decoupled from run lifecycle, snapshot hydration for late joiners, pending-run binding for draft conversations, and a chat activity hub whose events are composed inside the locked transitions (run ids from birth). Additive — the legacy chat run store still serves traffic until the cutover. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Replace the per-run chat relay with the conversation stream store end to end: - delete manager_chat_runs.go (run state machine, conversation claim map, runEpoch, per-run subscribers) and route agent dispatch through the normalizing ingress; agent-sent history running/idle events are dropped — activity now derives from run lifecycle transitions with run ids from birth - new WS contract: persistent per-conversation chat.subscribe with stream_epoch/after_seq resume and reset semantics, first-class conversation_id/run_id/seq on every chat.event, chat.activity broadcast hub, chat.command_update for pre-stream command outcomes; chat.replay and chat.subscription_end are gone - cancel keeps the run alive in a cancelling state until the agent's terminal signal, with a 15s force-finish watchdog; startup watchdog fails commands whose run never settles - remove the unused POST /api/chat/commands endpoint, its rate limiter and CSRF helper (origin checks move to http_origin.go), and the per-connection history running/idle run_id enrichment - rewrite gateway chat tests against the new contract (websocket chat suite, session integration suite) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
New web/src/lib/chat/stream modules implementing the client half of the conversation-scoped protocol: - ConversationStreamClient: persistent per-conversation registrations inside the socket layer with automatic seq-cursor resume on every reconnect, pre-sync event buffering, gap-triggered resync, and overflow recovery - transcriptStore: GUI-style committed/settled/live split — replies settle in the tail with unchanged ids and fold into committed at the next run_started; optimistic user entries adopted by client_request_id; id-preserving history merge; rebased truncation; snapshot rebuild - activityStore: single source for running dots, fed by chat.activity and history.list hydration - ChatCommandPipeline: optimistic echo + command_update outcomes (bound/queued_in_gui/failed) with a 60s pending watchdog - gatewaySocket: chat generators, per-run subscriptions, __gatewayRunId metadata and subscription_end handling removed; chatCommand promise, stream client wiring into auth/disconnect, chat.activity / chat.command_update fan-out; chat streams now count toward shouldMaintainConnection - pushChatEvent gains entryIdPrefix so entries of different runs never collide on id Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
GatewayApp.tsx drops from 6656 to 4533 lines: transcript rendering sources from per-conversation transcript stores (committed + tail), busy and sidebar dots derive from the activity store and command pipeline, and the displayed conversation holds one persistent stream subscription regardless of running state — GUI queue auto-sends simply flow in. sendChat shrinks to a pipeline submission with command_update-driven draft binding; cancel no longer marks terminal locally; edit_resend truncation rides the rebased stream event; the queued_in_gui delayed reloads and all fifteen recovery layers are gone (page-restore rehydration, completed markers, hydration blocks, draft adoption windows, per-run abort registries). Rendering: GatewayTranscript consumes disjoint committed/tail entries (tail dedup helpers deleted); run_started performs the single scroll-compensated flushSync fold; Markdown render mode is fixed per entry birth (live-born entries stay in streaming mode forever, shikiTheme passes in both modes) so the reply-end streaming→static reflow cannot occur. Tests: socket suite rewritten for the persistent subscribe/resume contract; history-chat-ui covers the id-preserving quiet merge; queue helper module trimmed to its one live export. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Remove chatwire.ControlPayload/IsTerminalControl (the ingress no longer forwards raw controls), collapse the webui ChatEvent union's control and runtime_snapshot variants into the two data events that still exist on the wire (user_message, rebased), and drop the dead "failed" branch from pushChatEvent. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Gateway: - runtime snapshots carry as_of_seq (the log seq they represent through) so clients rebuilding from a snapshot drop the overlapping buffered replay instead of double-applying it - chat.activity events carry client_request_id, letting the command pipeline settle pendings from the always-on activity channel (no spurious startup timeout after switching conversations away) - token-recreated streams after a gateway restart mark runNeedsSnapshot so late joiners hydrate instead of getting a silently incomplete replay - the reaper spares silent runs while the runtime heartbeat reports busy (a 12-minute quiet tool call is no longer force-failed) and can now also reap orphaned queued activities; the runtime-idle heuristic that could kill GUI-local runs is gone - chat.subscribe/unsubscribe execute inline on the read loop so a re-subscribe's frame order can never let the stale unsubscribe cancel the fresh subscription (StrictMode double-effect) - WatchChatCommand cleanup closes the channel (one goroutine no longer leaks per submitted command); activity replay channels are sized to the replay (blocking send under both store mutexes could deadlock all chat ingest) - supersession-started runs keep their seeded user_message inside the eviction-protected window WebUI: - transcript stores gain an idempotency seq cursor: re-subscribe replays and snapshot+replay overlaps no longer duplicate bubbles or reply text; resets zero the cursor and fold (not drop) the settled tail - run_finished respects run ownership: stray terminals for non-active runs never settle the streaming tail, and the settle sweep leaves other runs' seeded/optimistic entries live - pipeline settlement is strict-identity (runId or own client_request_id) — foreign runs can no longer disarm the startup watchdog - activityStore hydration is an ordered merge and re-hydrates after an offline/online transition (no phantom running dots) - second send while pending parks into the GUI queue instead of erroring; quiet refresh can no longer truncate long transcripts; history merges upgrade tail entries in place so the latest exchange stays edit-resendable; parked/failed edit_resends restore the optimistically truncated transcript Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Queue-bound prompt flash: sending while a run is streaming used to show the user bubble for an instant before the prompt landed in the GUI queue, on every viewer. Two sources, both removed: - the gateway now defers seeded payloads for commands accepted while another run is active — they reach the log only when the run actually starts (or fails, for error context) and are dropped when the desktop parks the prompt, making the agent's echo authoritative for queued items - the webui command pipeline gains optimistic:false, used by the queue-destined composer path so no local echo is inserted at all Transcript render misalignment: applyHistorySnapshot matched entries with a dedup-key -> single-entry map, so a history snapshot containing repeated keys (identical re-sent prompts, id-less tool calls sharing name+round across runs) let several entries adopt the same rendered id — duplicate React keys corrupt the row virtualizer's measurement cache and rows collapse onto each other (and extra occurrences were silently dropped). The merge is now occurrence-aware: per-key queues consumed in transcript order (committed copies before tail copies), with merged ids guaranteed unique. The transcript renderer additionally suffixes any duplicate row key as a defensive backstop for the virtualizer. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Replace the char-count text summary (contentChars=/oldChars=/newChars=) in the collapsed Write/Edit tool bar with a green +N/red -N line-diff badge (FileChangeBadge + animated OdometerNumber), mirrored across agent-gateway/web and agent-gui. Falls back to total line counts when the streaming preview meta reports truncation or the diff exceeds the 200k-char budget. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
- Add biome to gateway WebUI (same config as GUI) and format all web sources; fix the lint errors surfaced on both ends (unused imports, assignments in expressions, useless switch case, optional chain) - Align both biome configs: legacy a11y rules downgraded to warn, CSS progressive-enhancement fallbacks exempted from noDuplicateProperties - Add scripts/check-mirror.mjs + scripts/mirror-manifest.json to enforce byte-identical GUI/WebUI mirrored files - CI: lint both frontends, typecheck GUI build, run mirror check Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
gateway:tunnel-state previously carried two unrelated revision domains (local desired-state counter vs gateway process counter), which defeated the panel's monotonic guard: a gateway restart froze the GUI panel and a dropped link kept the health badge green. All emissions now go through a single publish path that stamps a store-level monotonic emit_seq and caches before emitting, and every disconnect path emits a local agent_online=false state. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Replaces the polling-based freshness model for git/file-tree panels with a best-effort invalidation push: a Rust notify-based watcher per workspace (250ms debounce, .git noise filtering, changedPaths capped at 64 with a truncated flag, per-workdir monotonic revision, mtime-sampling fallback) emits workspace:activity Tauri events and forwards to the gateway via new WorkspaceActivityEvent/WorkspaceWatchRequest envelope messages (field 90). The gateway fans out to workspace.subscribe WS subscribers, tunnel-hub style, and replays the declarative watch set on agent reconnect. Both frontends share a byte-identical WorkspaceActivityClient contract and a useWorkspaceInvalidation hook (dirty-while-hidden, flush-on-activate, refetch on reset/revision regression). Consumers land with the panel rewrites. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Persisted dock state now records user intent only: activeTabId, tabOrder (which may hold live/dead/not-yet-loaded session ids), singleton tools keyed by kind, and merge bookkeeping. Terminal tab existence is derived from live sessions at render time, which structurally removes the passive reconcile effect that raced session-list loading (pruning persisted tabs and broadcasting the damage to other clients) along with the "+2 beats the echo" version hack. - normalize keeps unknown tabOrder ids and never resets activeTabId; the legacy tabs shape migrates in place (terminal entries dropped) - version stamping is centralized in updateRightDockProjectState (stateVersion+1, writerId, lastUsedAt); merge orders writers by (stateVersion, writerId) so ties converge symmetrically - project buckets evict by lastUsedAt LRU instead of insertion-order break at 100, and empty-bucket tombstones expire after 90 days - session-list mutations compute first and notify outside state updaters (StrictMode-safe); manual 20-field session comparison replaced - sessionsLoaded threads from both integration points so the loading window renders a fallback without writing settings - concurrent close tracking uses a Set; four pure-logic dock files are now byte-identical mirrors enforced by scripts/check-mirror.mjs Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…daries RightDockContent drops from 45 props / hardcoded branches to a registry loop: each tool definition now carries isAvailable/render and reads a RightDockToolContext (clients, capabilities, fileTree/git/ssh callbacks, openExternal) provided by a memoized RightDockPanel. Both integration points memoize projectState/fileTreeState and stabilize every callback so the memo boundary actually holds — unrelated ChatPage/GatewayApp state changes no longer re-render the dock subtree. Every panel now receives an `active` prop (consumed by the panel rewrites that follow), and each end gains a thin non-mirrored WorkspaceActivityClient adapter (Tauri events / gatewaySocket). Panel, TabStrip, Launcher, Content, Context and registry are byte-identical mirrors (12 files enforced in CI); the GUI keeps its taller header via a CSS override instead of divergent markup, and the launcher trigger uses buttonVariants directly to erase the Base UI/Radix asChild split. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Git review: the 5.6k-line panel splits into git-review/ modules with a context-fed data hook. History signatures no longer embed the status signature, so agent writes stop resetting pagination/selection/diff; all polling and the unscoped liveagent:git-changed broadcast are gone in favor of workspace-activity invalidation (10s active-only fallback when no push client); per-cwd epochs retire the stale-response and swallowed-interaction races; the overlay scrollbar becomes a lifecycle-safe hook merging both ends' one-sided fixes; diff chunks parse lazily via IntersectionObserver; menu clamps are measured. File tree: rewritten under file-tree/ with a virtualized flat list, request dedup held in refs (not updater side effects), per-path epochs, reference-preserving merges, targeted subtree refresh from activity.changedPaths, a correct rename remap for expanded paths, single-source expanded-state sync, LRU project buckets, and clipboard/ error-copy hardening. The fileTree uiState drops its redundant stateVersion; revision now means reveal-nonce only. Terminals and tunnels: XTermViewport resets and replays the snapshot on stream gaps or truncation instead of appending duplicates, renders the cached snapshot while attach retries, keys errors by session id (with a per-session error map in the panel), and rebinds on client change. LocalTunnelPanel clears its snapshot across client swaps, prunes orphan row state, isolates check-all errors, and moves the TTL countdown into a memoized leaf gated by active. SshTunnelPanel claims created sessions by returned id instead of guessing by host (no more swallowed auth prompts), gates latency probes on active with stable deps, tracks concurrent closes in a Set, and gains autofocus parity; the WebUI drops its duplicate 5s ssh reconcile poll for an activate-time catch-up. All rewritten panels are byte-identical mirrors (27 files enforced); GitBranchSelector consumes activity invalidation on both ends. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…rotocol Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- structured evidence args on write/update/apply_batch; Rust renders the canonical evidence frontmatter and owns the confidence contract - mutation responses report appliedConfidence/autoDowngraded - new memory_quota_summary command (per-scope used/headroom/unreviewed age) - organize_runs schema v4: additive migration, phase/final_count/ compression/token-usage columns, trimmedProtocol renamed to report - apply_batch accepts op=accept for the single persistence path Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- lib/memory/schema.ts single source for enums, plan/decision shapes,
confidence contract; lib/memory/config.ts owns every magic number
- api.ts rewritten on the schema: evidence pass-through, quota summary,
organize-run v4 report
- prompts/ split by audience (shared/injection/extraction/managerTool);
extraction prompt targets the SubmitMemoryPlan tool-call protocol with
no hardcoded status sentinels
- extraction/planTool.ts per-item validation + single apply_batch mapping;
extraction/{context,gating}.ts compact window, deterministic workspace-
mutation digest, language-neutral skip heuristics
- memoryTools.ts rewritten: structured evidence to Rust (client
frontmatter serializer deleted), auto-downgrade surfaced in results
- delete dead memoryFrontmatter.ts and memoryPrompt.ts; new test/memory
suite (51 tests)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…oller - extractionEngine: compact self-contained context (last-4-turn window + deterministic workspace-mutation digest + candidates/rejections), one SubmitMemoryPlan submission, single-tool forced retry when missing, single memory_apply_batch persistence, summary-model fallback absorbed, i18n status text (Chinese sentinels deleted) - extractionController: synchronous gate+claim (fixes throttle TOCTOU), per-run AbortController detached from the chat request signal (a new turn no longer kills in-flight writes), coalesce-skip queue, dispose on conversation delete (fixes state leak), LRU-capped state - turn runners + ChatPage rewired; delete silentMemoryExtraction*, memoryProtocol, memoryExtractor, memoryDecisionLog, memoryPolicy and their legacy tests (8 files) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- organizer/pipeline.ts: pure clustering/risk/gate stages ported from the 1575-line headless React runner; single coercion helpers; typed review items and rejection buckets - organizer/runRecord.ts: OrganizeRunReportV4 replaces organizerProtocol's defensive normalization — one version check, no key-spelling probes; pre-v4 runs degrade to read-only summaries - organizer/quota.ts: quota ladder (normal/notice/degraded/critical/ exhausted) drives the prompt compression target and panel banner - organizer/service.ts: one-shot wake timer (nothing armed while disabled, no mount-time forced claim), poke() replaces the window CustomEvent bus, explicit scan→cluster→plan→gate→apply phase updates, quota headroom and token usage recorded on the run - useMemoryOrganizer hook + MemoryOrganizerHost replace the runner mount; MemoryOrganizerRunner.tsx deleted Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- pages/settings/memory/: platform adapter (base-ui vs radix Select, buildModelOptions path, organizer poke) + five byte-mirrored components (panelModel, useMemoryPanelData, MemoryPanel, OrganizerHistoryModal, MemorySettingsDrawer); the 2501-line panel forks on both ends die - organize-run polling only while a run is pending/running; idle panels never poll - history modal consumes the typed v4 run record; pre-v4 runs degrade to read-only summaries; manual apply writes back plain-array state - settings drawer surfaces the quota ladder banner from memory_quota_summary - gateway web: memory domain files byte-mirrored, organizerProtocol and the runner stub deleted, radix platform adapter added - scripts/mirror-manifest.json now enforces 10 memory files (37 total); api.ts compat re-exports removed Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- docs/features/memory.md: module table, evidence contract, quota ladder, SubmitMemoryPlan extraction protocol, organizer phases, mirror discipline, refreshed troubleshooting entries - mark the May organizer-optimization proposals (phases/quota/schema-v4) as landed by the memory-system rewrite Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ebar state layer Both frontends get a lib/sidebar module (store, reconcile, openController, scope, backend) driving the chat history sidebar via server-authoritative reconcile, replacing the old historyListScope/historySync/useChatHistoryList hooks that tracked history state ad hoc per page.
Long version strings could overflow the fixed-width version selector; clip with truncate and show the full label via title/tooltip instead.
…main Consolidates the previously separate hooks and cron subsystems, which had three uncoordinated writers (UI full-table replace, LLM incremental edits, executor self-decrement) with no version control, into a single services/automation store with revision-CAS applies, notifier-broadcast snapshots, a persisted prompt-run lease queue, and a differential scheduler. Hooks and cron settings move out of AppSettings into their own read-only, revisioned snapshots synced over the settings channel. Mirrors the change across agent-gui and agent-gateway/web per the shared settings/hub UI convention.
Adds a --hub-canvas token (darker than --background in dark mode) so background-tinted glass panels on the MCP/Skills/status hub pages read as elevated surfaces instead of blending into a gray fog, plus matching dark: border/background/shadow variants across cards, tab bars, and icon tiles.
Pass -w <pid> so the keep-awake assertion is scoped to this process: if the app crashes without running stop(), caffeinate exits on its own instead of blocking system sleep until reboot.
Even out the Advanced Options toggle grid (sm:grid-cols-2 xl:grid-cols-3 instead of a ragged 4-col layout for 6 items), extract SectionCardHeader/ ToggleOptionCard helpers for consistent card structure, clean up the Gateway Connection field spacing, and move hardcoded connection-status strings into i18n. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Replace the delegate/subagent implementation with a single lib/subagents domain (pure domain -> ipc -> runtime -> tool adapters), a structured zero-inference model API, and a redesigned persistence and UI protocol. - TS: delete lib/tools/delegate/* and lib/chat/subagent/*; new four-layer lib/subagents with SubagentConversationStore as the single source of truth and a provision/execute/settle/report run state machine - API: structured agents array with atomic validation and structured errors listing roster + enabled templates; agent_spec manifests, task_intent, and all prompt-text heuristics removed; SendMessage recipients validated against the roster; template.enabled honored - Persistence: turn-boundary incremental run saves (interrupted runs resume from the last completed round), persistence failures surfaced to the model, new cancelled status; Rust subagent_store.rs with schema v2 (versioned drop-and-recreate, no event table) and a 12-command camelCase surface; delegate.rs -> subagent_worktree.rs - UI: subagent_batch/subagent_card/subagent_message protocol shared byte-identically via lib/subagents/protocol.ts (mirror-manifest); placeholder cards parse the structured agents array; rejected Agent calls now render visibly in both frontends - Tests: 81 behavioral tests in test/subagents plus rewritten registry, messages, and Rust suites; docs updated Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… state Safari can fire compositionend before the confirming Enter's keydown with isComposing already false, so a bare Enter suppression window plus a short post-composition tail is needed to keep IME confirmation from sending the message. Also dedupes commit tooltip re-renders, drops large-paste map entries when their chip is removed via native editing, guards mention suggestion selection against a detached text node, and avoids redundant mention refetches when the cached snapshot still covers the narrowed query. Mirrored across agent-gateway/web and agent-gui per dual-frontend UI parity. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
… while scrolling Cap the branch dropdown to 66vh of the viewport (via the available-height CSS var) instead of only scrolling once it hits the window edge, mark the currently tracked remote branch with a checkmark like local branches, and restructure the popup into a flex layout so the repo/refresh header and create-branch footer stay fixed while only the branch list scrolls. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…iders Extract Anthropic/Gemini thinking-runtime resolution and the OpenAI reasoning-effort clamp out of streamByApi.ts into thinkingLevels.ts, the single source of truth for provider thinking-level mapping. Prefer catalog-declared compat.forceAdaptiveThinking / thinkingLevelMap over id heuristics, guard the Claude version regex against date-suffixed ids, and add clampOpenAIReasoningEffort to downgrade xhigh/minimal on models that don't support them. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…popup motion The tailwindcss-animate classes on DropdownMenuContent were dead (the plugin is not installed on either end), so the sidebar context menus popped in and out with no transition. Key the motion off each end's real popup primitive instead: Base UI data-starting/ending-style transitions in the GUI, Radix data-state keyframes in the WebUI. Menus now grow from the anchor origin with a side-aware slide and staggered item entrance, fade out quickly on close, and disable entirely under prefers-reduced-motion. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…rites The Gateway WebUI and GUI CI jobs were failing on tests that still referenced APIs removed by the automation domain rewrite (504f57a) and the subagent system rewrite (41c0137): - hook-lifecycle: drop messageUpdated/message_update and tool_execution_update, match the 8-event lifecycle driven once per tool execution - normalization/web-settings: delete normalizeConversationHook and normalizeCronTask tests; validation moved to Rust services/automation/validate.rs and is covered by its tests - chatUi-agent: rewrite delegate-agent card tests against the structured agents protocol (buildSubagentPlaceholderToolCalls, subagent_batch/subagent_card details) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Drop the unused in-memory sqlite helper and stale imports left in the system and terminal test modules, and mark truncate_process_error as macos-only since its sole caller is behind the same cfg. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.