diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4767c7f..24b0e2e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -73,18 +73,20 @@ EvoScientist-WebUI/ scripts/ # assemble-standalone.mjs (packs dist/, strips *.map) src/ app/ - api/ # thin same-origin server routes - evosci-config/ # detect backend port - skills/ # install / list / remove skills - memory/ # read / edit global memory - workspace/ # browse / edit / download files - components/ # React components (chat, panels, dialogs) - hooks/ # useChat, useThreads, useAsyncAgents, … - page.tsx # multi-view shell (routes via nuqs) - components/ # shared UI primitives - lib/ # client + server helpers (asyncAgents, memory, …) - server/ # server-only fs helpers with path guards - providers/ # Theme / Client providers + api/ # thin same-origin server routes (browser → local disk) + evosci-config/ # detect backend port from EvoScientist config + skills/ # list / install / uninstall + remote EvoSkills catalog + memory/ # global memory CRUD + observation graph + executions + workspace/ # browse / read / edit / upload / download-zip files + components/ # feature UI: chat, inspector, memory, schedule, skills, dialogs + hooks/ # useChat, useThreads, useAsyncAgents, useScheduledTasks, + # useAvailableModels, useMemoryActivity, useAutoNotify + page.tsx # three-column shell (thread · chat · inspector); nuqs routing + components/ui/ # shared shadcn/ui primitives + lib/ # client helpers (asyncAgents, cronUtils, modelCommand, + # observationGraph, fileLink, summarization, …) + server/ # server-only fs helpers (workspace / memory / skills) w/ path guards + providers/ # ClientProvider (SDK) · ChatProvider · ThemeProvider ``` ## Architecture & connection contract @@ -95,7 +97,7 @@ Three independent layers: 2. **Next `/api/` routes** (server tool layer, same-origin) — the reason distribution is `output: "standalone"` rather than a static export. 3. **Backend** (EvoScientist's `langgraph dev`, default port `6174`) — the anchor process: runs async agents, holds state, serves the SDK. -The backend exposes graphs `EvoScientist` (main, UI-locked), `writing-agent`, `data-analysis-agent`, and the `evomemory` workers. The UI filters thread lists by `metadata.graph_id == "EvoScientist"` so worker/sub-agent threads stay hidden. +The backend exposes graphs `EvoScientist` (main, UI-locked), `writing-agent`, `data-analysis-agent`, the `scheduler` graph (LangGraph crons behind **Scheduled Tasks**), and the `evomemory` workers. The UI filters thread lists by `metadata.graph_id == "EvoScientist"` so worker/sub-agent threads stay hidden. ## Code style diff --git a/README.md b/README.md index e6c915a..99233f7 100644 --- a/README.md +++ b/README.md @@ -28,12 +28,17 @@ ## ✨ Features -- **💬 Streaming Chat** — Real-time responses with Markdown, GFM tables, code highlighting, and collapsible thinking/reasoning blocks. +- **💬 Streaming Chat** — Real-time responses with Markdown, GFM tables, math (KaTeX), code highlighting, zoomable Mermaid diagrams, and collapsible thinking/reasoning blocks. +- **🧬 Per-Thread Model Picker** — Switch models per conversation with the `/model` command or a clickable model pill; the choice is persisted to the thread and folded into the next run. - **👋 Human-in-the-Loop** — Approve / reject / edit tool calls, and answer the agent's structured questions (text + multiple-choice) inline. - **⚡ Per-Thread Auto-Approve** — Persisted per conversation; survives view and thread switches and reloads. +- **⌨️ Message Queue** — Type while the agent is busy: queue, edit, reorder, steer, or drain follow-up messages without interrupting the active run. - **🤖 Sub-Agent Activity** — Live step tracking for sub-agents, rendered exactly like the main agent (tool calls + paired results + tables). - **🗂️ Workspace Browser** — Tree and by-type (Papers / Figures / Data / Code) views with preview, edit, download, and zip-all. -- **🧠 Memory Browser** — View, edit, and manage EvoScientist's global cross-session memory, with "recently updated" highlights and a nav badge. +- **🔗 Click-to-Open File Links** — File paths in agent output are clickable — open them straight from chat in a workspace or memory viewer. +- **🧠 EvoMemory Browser** — EvoScientist's global cross-session memory across three tabs: **Identity** (editable profile files), **Knowledge** (an interactive force-directed observation graph), and **History** (execution + observation timeline). +- **⏰ Scheduled Tasks** — Schedule recurring research runs (daily / weekly / monthly / custom cron) with a visual builder, templates, and Run-now — backed by LangGraph crons. +- **📊 Research Dashboard** — The chat's empty state surfaces recent memory activity, scheduled tasks, threads, and files, with one-click jump-in. - **🔌 Skills Marketplace** — Install, update, and uninstall the official [EvoSkills](https://github.com/EvoScientist/EvoSkills) catalog with version detection and a detail dialog. - **📡 Agents Monitor Board** — Watch async background agents (writing / data-analysis) with real run status, live duration, and a side-chat for direct worker debugging. - **🔁 Async Agent Communication** — Optional per-thread auto-report loops finished background results back to the main agent. @@ -43,6 +48,7 @@ ## 📖 Table of Contents +- [✨ Features](#-features) - [📦 Prerequisites](#-prerequisites) - [⚡ Quick Start](#-quick-start) - [🔑 Configuration](#-configuration) diff --git a/scripts/assemble-standalone.mjs b/scripts/assemble-standalone.mjs index ebc9229..2bed798 100644 --- a/scripts/assemble-standalone.mjs +++ b/scripts/assemble-standalone.mjs @@ -27,8 +27,8 @@ if (existsSync(PUBLIC)) { } // Next copies the whole project root into the standalone bundle. Prune it down -// to just the runtime essentials (drops src/, configs, and local notes like -// CLAUDE.md/AGENTS.md so they never get published). +// to just the runtime essentials (drops src/, configs, and local notes so +// they never get published). const KEEP = new Set([ "server.js", ".next", diff --git a/src/app/components/AgentsPanel.tsx b/src/app/components/AgentsPanel.tsx index 2850f53..8df7ccb 100644 --- a/src/app/components/AgentsPanel.tsx +++ b/src/app/components/AgentsPanel.tsx @@ -122,7 +122,7 @@ export function AgentsPanel({ onReportToMainChat }: AgentsPanelProps) { // Hidden power-user feature: a tiny composer per expanded task that sends a // message straight to that sub-agent's own thread. Note this is a SIDE channel // — the reply lands in the sub-agent's thread (shown here), the main agent - // doesn't see it (see CLAUDE.md §3 Agents board: no auto loop-back to parent). + // doesn't see it — there is no auto loop-back to the parent agent. const [chatInput, setChatInput] = useState>({}); const [chatBusy, setChatBusy] = useState>({}); const [chatError, setChatError] = useState>({}); diff --git a/src/app/components/ChatInterface.tsx b/src/app/components/ChatInterface.tsx index e8f6180..845fa44 100644 --- a/src/app/components/ChatInterface.tsx +++ b/src/app/components/ChatInterface.tsx @@ -289,7 +289,7 @@ export const ChatInterface = React.memo( cancelled = true; }; }, []); - // Messages typed while the agent is busy (Claude Code-style queue). They + // Messages typed while the agent is busy are queued. They // drain one-per-idle-window into the thread once it's free. A ref mirrors the // latest queue so event handlers (key ↑, edit) read current state without // being recreated; queueIdRef hands out stable keys. @@ -857,7 +857,7 @@ export const ChatInterface = React.memo( // Can't compose with no assistant, a pending interrupt, or files still // uploading. (Unlike before, isLoading is NOT a blocker — see below.) if (!assistant || hasPendingInterrupt || isUploadingFiles) return; - // Agent busy → queue it (Claude Code style). The queue drains and sends + // Agent busy → queue it. The queue drains and sends // automatically once this turn finishes (or is stopped); the message is // appended as the next turn — it never replaces what's already running. if (isLoading) { @@ -912,7 +912,7 @@ export const ChatInterface = React.memo( }); }, []); - // Codex-style "Steer": prioritize this instruction without interrupting the + // "Steer": prioritize this instruction without interrupting the // active run. It remains in our visible queue and drains in the next idle // window, which preserves the same non-interrupting contract. const steerQueuedMessage = useCallback((id: number) => { diff --git a/src/app/components/HealthIndicator.tsx b/src/app/components/HealthIndicator.tsx index 8454954..0d3e466 100644 --- a/src/app/components/HealthIndicator.tsx +++ b/src/app/components/HealthIndicator.tsx @@ -21,7 +21,7 @@ const POLL_INTERVAL_MS = 10_000; const REQUEST_TIMEOUT_MS = 4_000; // Theme tokens (light + dark defined in globals.css). The base's shadcn -// primary/secondary background tokens are dead in this fork (see CLAUDE.md), so +// primary/secondary background tokens are dead in this fork, so // we reference CSS vars directly via arbitrary-value classes (the entries below). // NOTE: never put a bracketed class literal in a comment — Tailwind's content // scanner picks it up and emits real (sometimes invalid) CSS. diff --git a/src/app/globals.css b/src/app/globals.css index e24122f..d4d3674 100644 --- a/src/app/globals.css +++ b/src/app/globals.css @@ -10,8 +10,8 @@ :root { /* App-specific color variables */ - /* App-specific colors — warm "paper" palette in the Claude Code desktop - style. Light mode: ivory background, true-white cards, warm charcoal text. */ + /* App-specific colors — warm "paper" palette. Light mode: ivory + background, true-white cards, warm charcoal text. */ --color-primary: #33302a; --color-user-message: #0e5c6e; --color-user-message-bg: #e6f2f5; diff --git a/src/lib/asyncAgents.ts b/src/lib/asyncAgents.ts index 30cfb03..4f86153 100644 --- a/src/lib/asyncAgents.ts +++ b/src/lib/asyncAgents.ts @@ -172,7 +172,7 @@ export function formatAsyncUpdateMessage(task: AsyncTaskReportTarget): string { } // Theme dot + label + pulse per status. CSS vars referenced via arbitrary-value -// classes (the base's semantic bg tokens are dead in this fork — see CLAUDE.md). +// classes (the base's semantic bg tokens are dead in this fork). // NOTE: never put a bracketed class literal in a comment (Tailwind scans those). export const ASYNC_STATUS_META: Record< AsyncAgentStatus, diff --git a/tailwind.config.mjs b/tailwind.config.mjs index f776a74..8f00f60 100644 --- a/tailwind.config.mjs +++ b/tailwind.config.mjs @@ -5,7 +5,7 @@ import tailwindcssAnimate from "tailwindcss-animate"; /** @type {import('tailwindcss').Config} */ export default { - content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"], + content: ["./src/**/*.{js,ts,jsx,tsx}"], darkMode: "class", theme: { extend: {