diff --git a/Makefile b/Makefile index 92d8b6e..a5cb9b8 100644 --- a/Makefile +++ b/Makefile @@ -7,8 +7,9 @@ BACKEND := backend FRONTEND := frontend PORT ?= 3000 DOCKER_USER ?= xprilion -VERSION ?= 0.2.0 +VERSION ?= 0.3.0 DOCKER_COMPOSE := docker compose +LOGO_SRC := assets/full-logo.png # ─── Setup ──────────────────────────────────────────────── @@ -240,6 +241,40 @@ docs-docker: ## Run docs in Docker (port 4000) docs-build: ## Build docs to site/docs/.vitepress/dist cd site && npx vitepress build docs +# ─── Logo Generation ───────────────────────────────────── + +.PHONY: logo +logo: ## Generate all logo sizes from assets/full-logo.png + @echo "Generating logo sizes from $(LOGO_SRC)..." + @mkdir -p $(FRONTEND)/public site/docs/public + @# Favicons for webapp + sips -z 16 16 $(LOGO_SRC) --out $(FRONTEND)/public/favicon-16x16.png + sips -z 32 32 $(LOGO_SRC) --out $(FRONTEND)/public/favicon-32x32.png + sips -z 180 180 $(LOGO_SRC) --out $(FRONTEND)/public/apple-touch-icon.png + sips -z 192 192 $(LOGO_SRC) --out $(FRONTEND)/public/logo-192.png + sips -z 512 512 $(LOGO_SRC) --out $(FRONTEND)/public/logo-512.png + @# Generate .ico from 32x32 (copy as favicon.ico for browsers) + cp $(FRONTEND)/public/favicon-32x32.png $(FRONTEND)/public/favicon.ico + @# Logo for header/nav + sips -z 64 64 $(LOGO_SRC) --out $(FRONTEND)/public/logo-64.png + @# OG image (1200x630 for social sharing - pad/crop as needed) + sips -z 630 630 $(LOGO_SRC) --out $(FRONTEND)/public/og-image-square.png + sips -p 630 1200 $(FRONTEND)/public/og-image-square.png --out $(FRONTEND)/public/og-image.png + rm $(FRONTEND)/public/og-image-square.png + @# Copy to docs site + cp $(FRONTEND)/public/favicon-16x16.png site/docs/public/ + cp $(FRONTEND)/public/favicon-32x32.png site/docs/public/ + cp $(FRONTEND)/public/favicon.ico site/docs/public/ + cp $(FRONTEND)/public/apple-touch-icon.png site/docs/public/ + cp $(FRONTEND)/public/logo-64.png site/docs/public/ + cp $(FRONTEND)/public/logo-192.png site/docs/public/ + cp $(FRONTEND)/public/logo-512.png site/docs/public/ + cp $(FRONTEND)/public/og-image.png site/docs/public/ + @# Full logo for README + cp $(LOGO_SRC) assets/logo.png + sips -z 200 200 $(LOGO_SRC) --out assets/logo-200.png + @echo "Done! Logo sizes generated in frontend/public/, site/docs/public/, and assets/" + # ─── Cleanup ───────────────────────────────────────────── .PHONY: clean diff --git a/README.md b/README.md index 5eabea9..01e9458 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,12 @@ -# OpenMLR +

+ OpenMLR Logo +

-A self-hosted ML research agent that plans, researches, writes papers, and executes code — all in one conversation. +

OpenMLR

+ +

+ A self-hosted ML research agent that plans, researches, writes papers, and executes code — all in one conversation. +

[![Deploy to Render](https://render.com/images/deploy-to-render-button.svg)](https://render.com/deploy?repo=https://github.com/xprilion/OpenMLR) [![Deploy to Heroku](https://www.herokucdn.com/deploy/button.svg)](https://www.heroku.com/deploy?template=https://github.com/xprilion/OpenMLR) @@ -16,6 +22,7 @@ A self-hosted ML research agent that plans, researches, writes papers, and execu - **Plan + Execute modes** — Plan mode gathers context; Execute mode does the work. Toggle with `Cmd+M`. - **Paper research** — OpenAlex, Semantic Scholar, arXiv, CrossRef, Papers With Code. Reads full papers, crawls citation graphs. - **Paper writing** — Section-by-section drafting with auto-save. Export to Markdown/LaTeX. +- **Compute environments** — Execute code on local Docker, SSH remotes, or Modal cloud. Probe GPU/CPU capabilities. - **Background jobs** — Celery + Redis. Close the browser, come back later. - **Multi-provider LLMs** — OpenAI, Anthropic, OpenRouter, plus local models (Ollama, LM Studio). - **MCP servers** — Connect external tools via the Model Context Protocol. diff --git a/assets/full-logo.png b/assets/full-logo.png new file mode 100644 index 0000000..46280a1 Binary files /dev/null and b/assets/full-logo.png differ diff --git a/assets/logo-200.png b/assets/logo-200.png new file mode 100644 index 0000000..aa833a5 Binary files /dev/null and b/assets/logo-200.png differ diff --git a/assets/logo.png b/assets/logo.png new file mode 100644 index 0000000..46280a1 Binary files /dev/null and b/assets/logo.png differ diff --git a/backend/openmlr/app.py b/backend/openmlr/app.py index b150bfc..66f1d03 100644 --- a/backend/openmlr/app.py +++ b/backend/openmlr/app.py @@ -52,7 +52,7 @@ async def lifespan(app: FastAPI): app = FastAPI( title="OpenMLR", description="ML research intern — reads papers, trains models, writes papers", - version="2.0.0", + version="0.3.0", lifespan=lifespan, ) diff --git a/backend/openmlr/routes/health.py b/backend/openmlr/routes/health.py index 0ba4fc2..f4fea71 100644 --- a/backend/openmlr/routes/health.py +++ b/backend/openmlr/routes/health.py @@ -6,7 +6,7 @@ router = APIRouter(tags=["health"]) -VERSION = "0.1.0" +VERSION = "0.3.0" @router.get("/api/health") diff --git a/backend/pyproject.toml b/backend/pyproject.toml index f9a1a48..aebbc44 100644 --- a/backend/pyproject.toml +++ b/backend/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "openmlr" -version = "0.2.0" +version = "0.3.0" description = "OpenMLR — an ML research intern that reads papers, trains models, and ships code" requires-python = ">=3.12" license = { text = "MIT" } diff --git a/backend/tests/test_app.py b/backend/tests/test_app.py index 0137534..2a94fdc 100644 --- a/backend/tests/test_app.py +++ b/backend/tests/test_app.py @@ -12,7 +12,7 @@ async def test_app_title(self): assert app.title == "OpenMLR" async def test_app_version(self): - assert app.version == "2.0.0" + assert app.version == "0.3.0" async def test_app_routers_registered(self): route_paths = [r.path for r in app.routes] diff --git a/frontend/index.html b/frontend/index.html index 719cbfe..59a99c5 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -4,6 +4,31 @@ OpenMLR + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/frontend/public/apple-touch-icon.png b/frontend/public/apple-touch-icon.png new file mode 100644 index 0000000..77b19e6 Binary files /dev/null and b/frontend/public/apple-touch-icon.png differ diff --git a/frontend/public/favicon-16x16.png b/frontend/public/favicon-16x16.png new file mode 100644 index 0000000..bcb8446 Binary files /dev/null and b/frontend/public/favicon-16x16.png differ diff --git a/frontend/public/favicon-32x32.png b/frontend/public/favicon-32x32.png new file mode 100644 index 0000000..7a8927e Binary files /dev/null and b/frontend/public/favicon-32x32.png differ diff --git a/frontend/public/favicon.ico b/frontend/public/favicon.ico new file mode 100644 index 0000000..7a8927e Binary files /dev/null and b/frontend/public/favicon.ico differ diff --git a/frontend/public/logo-192.png b/frontend/public/logo-192.png new file mode 100644 index 0000000..47bed11 Binary files /dev/null and b/frontend/public/logo-192.png differ diff --git a/frontend/public/logo-512.png b/frontend/public/logo-512.png new file mode 100644 index 0000000..b218d03 Binary files /dev/null and b/frontend/public/logo-512.png differ diff --git a/frontend/public/logo-64.png b/frontend/public/logo-64.png new file mode 100644 index 0000000..6e94409 Binary files /dev/null and b/frontend/public/logo-64.png differ diff --git a/frontend/public/manifest.json b/frontend/public/manifest.json new file mode 100644 index 0000000..c8bb1b3 --- /dev/null +++ b/frontend/public/manifest.json @@ -0,0 +1,21 @@ +{ + "name": "OpenMLR", + "short_name": "OpenMLR", + "description": "AI-powered ML Research Agent that plans tasks, researches papers, writes drafts, and executes code", + "start_url": "/", + "display": "standalone", + "background_color": "#0f172a", + "theme_color": "#3b82f6", + "icons": [ + { + "src": "/logo-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/logo-512.png", + "sizes": "512x512", + "type": "image/png" + } + ] +} diff --git a/frontend/public/og-image.png b/frontend/public/og-image.png new file mode 100644 index 0000000..49ff457 Binary files /dev/null and b/frontend/public/og-image.png differ diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index c3cd07f..806ce81 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -555,6 +555,7 @@ function ChatUI({ {/* Header */}
+ OpenMLR OpenMLR
-

OpenMLR

-

ML Research Intern

+
+ OpenMLR +

OpenMLR

+

ML Research Intern

+
{isFirstUser && (
diff --git a/site/docs/.vitepress/config.ts b/site/docs/.vitepress/config.ts index b4ec036..9295d0d 100644 --- a/site/docs/.vitepress/config.ts +++ b/site/docs/.vitepress/config.ts @@ -10,9 +10,15 @@ export default defineConfig({ cleanUrls: true, head: [ + // Favicons + ["link", { rel: "icon", type: "image/png", sizes: "32x32", href: "/favicon-32x32.png" }], + ["link", { rel: "icon", type: "image/png", sizes: "16x16", href: "/favicon-16x16.png" }], + ["link", { rel: "apple-touch-icon", sizes: "180x180", href: "/apple-touch-icon.png" }], + ["link", { rel: "icon", href: "/favicon.ico" }], + // Basic meta ["meta", { name: "author", content: "Anubhav Singh" }], - ["meta", { name: "theme-color", content: "#3eaf7c" }], + ["meta", { name: "theme-color", content: "#3b82f6" }], [ "meta", { @@ -48,6 +54,9 @@ export default defineConfig({ }, ], ["meta", { property: "og:url", content: "https://openmlr.dev" }], + ["meta", { property: "og:image", content: "https://openmlr.dev/og-image.png" }], + ["meta", { property: "og:image:width", content: "1200" }], + ["meta", { property: "og:image:height", content: "630" }], // Twitter Card ["meta", { name: "twitter:card", content: "summary_large_image" }], @@ -60,6 +69,7 @@ export default defineConfig({ "AI-powered ML Research Agent that plans tasks, researches papers, writes drafts, and executes code", }, ], + ["meta", { name: "twitter:image", content: "https://openmlr.dev/og-image.png" }], ], // Sitemap generation @@ -76,6 +86,7 @@ export default defineConfig({ "configuration", "modes", "tools", + "compute", "architecture", "agent-harness", "api", @@ -93,6 +104,7 @@ export default defineConfig({ }, themeConfig: { + logo: "/logo-64.png", nav: [ { text: "Home", link: "/" }, { text: "Setup", link: "/setup" }, @@ -113,6 +125,7 @@ export default defineConfig({ items: [ { text: "Modes (Plan / Execute)", link: "/modes" }, { text: "Agent Tools", link: "/tools" }, + { text: "Compute Environments", link: "/compute" }, ], }, { diff --git a/site/docs/changelog.md b/site/docs/changelog.md index 8998ef7..f2ce445 100644 --- a/site/docs/changelog.md +++ b/site/docs/changelog.md @@ -5,6 +5,35 @@ description: OpenMLR version history and release notes. Track new features, impr # Changelog +## v0.3.0 + +Compute environments, UI improvements, and bug fixes. + +### Compute Environments +- **Multi-backend compute** — Execute code on local Docker, SSH remotes, or Modal cloud +- **SSH key management** — Generate Ed25519/RSA keys, upload existing keys via Settings > Compute +- **Compute probing** — Detect OS, GPUs (with CUDA version), Python versions, and disk space +- **Compute selection** — Switch between configured compute nodes mid-conversation +- **Connection pooling** — SSH connections are reused across tool calls for performance +- **Docker-in-Docker detection** — Worker container executes commands directly when already in Docker + +### UI Improvements +- **Collapsible Tasks & Resources** — Click section headers in the right panel to collapse/expand +- **Fixed right panel layout** — Right panel no longer causes page scroll issues when toggled +- **Improved scroll behavior** — Message list scrolls correctly without affecting page layout + +### Bug Fixes +- Fixed `scrollIntoView` causing entire page to scroll when RightPanel is open +- Fixed `_get_draft` database call using wrong function name +- Fixed test suite failures related to async database mocking + +### Internal +- Added `_running_in_container()` detection for Docker Compose worker environments +- Improved test coverage for compute and writing tools +- Updated Settings nav to reflect current menu structure + +--- + ## v0.2.0 Major rewrite of the mode system, paper writing, processing architecture, and UI routing. diff --git a/site/docs/compute.md b/site/docs/compute.md new file mode 100644 index 0000000..ae58b1c --- /dev/null +++ b/site/docs/compute.md @@ -0,0 +1,152 @@ +--- +title: Compute Environments - OpenMLR +description: Configure and manage compute environments in OpenMLR. Local Docker, SSH remotes, and Modal cloud execution for ML research tasks. +--- + +# Compute Environments + +OpenMLR supports multiple compute backends for code execution. Configure compute nodes in **Settings > Compute** to run experiments on local Docker containers, remote SSH servers, or Modal cloud sandboxes. + +## Overview + +| Type | Description | Best For | +|------|-------------|----------| +| **Local** | Docker containers on your machine | Development, quick tests | +| **SSH** | Remote servers via SSH | GPU clusters, lab machines | +| **Modal** | Serverless cloud compute | Scalable GPU workloads | + +## Local Compute + +Executes commands in Docker containers on the host machine. + +### Configuration + +| Field | Required | Description | +|-------|----------|-------------| +| Name | Yes | Unique identifier for this node | +| Workspace | No | Host directory to mount (default: current directory) | + +### How It Works + +1. Commands run inside a Docker container (`python:3.12-slim` by default) +2. The workspace directory is mounted at `/workspace` in the container +3. Results are captured and returned to the agent + +### Docker-in-Docker vs Direct Execution + +When running OpenMLR in Docker Compose: +- The worker container detects it's already inside a container +- Commands execute directly in the worker container (no nested Docker) +- File operations use the mounted workspace + +When running natively: +- Commands spawn isolated Docker containers +- Each execution gets a fresh environment + +## SSH Compute + +Execute commands on remote machines via SSH. Ideal for GPU clusters or dedicated lab machines. + +### Configuration + +| Field | Required | Description | +|-------|----------|-------------| +| Name | Yes | Unique identifier | +| Host | Yes | Hostname or IP address | +| Port | No | SSH port (default: 22) | +| Username | Yes | SSH username | +| Key | Yes | SSH private key (managed in Settings > Compute > Keys) | +| Workspace | No | Remote directory for file operations | + +### SSH Key Management + +1. Go to **Settings > Compute** +2. Click **Manage Keys** +3. Generate a new Ed25519 or RSA key pair, or upload an existing key +4. Copy the public key to your remote server's `~/.ssh/authorized_keys` + +### Connection Pooling + +SSH connections are pooled and reused across tool calls to minimize connection overhead. Idle connections are automatically cleaned up after 5 minutes. + +## Modal Compute + +Run code on [Modal](https://modal.com) serverless infrastructure. Great for GPU workloads without managing infrastructure. + +### Configuration + +| Field | Required | Description | +|-------|----------|-------------| +| Name | Yes | Unique identifier | +| GPU | No | GPU type (`T4`, `A10G`, `A100`, etc.) | +| Timeout | No | Maximum execution time in seconds | + +### Environment Variables + +Set Modal credentials via environment variables or Settings > Providers: + +```bash +MODAL_TOKEN_ID=your-token-id +MODAL_TOKEN_SECRET=your-token-secret +``` + +### GPU Options + +| GPU | VRAM | Best For | +|-----|------|----------| +| `T4` | 16GB | Inference, small training | +| `A10G` | 24GB | Medium training, fine-tuning | +| `A100` | 40/80GB | Large model training | + +## Compute Tools + +The agent has access to compute-related tools: + +| Tool | Mode | Description | +|------|------|-------------| +| `compute_list` | Plan, Execute | List available compute nodes | +| `compute_probe` | Plan, Execute | Probe node capabilities (OS, GPU, Python versions) | +| `compute_select` | Execute | Switch to a different compute node | + +### Probing Capabilities + +The `compute_probe` tool returns: +- Operating system and architecture +- Available GPUs with VRAM, CUDA version, driver version +- Python versions installed +- Available disk space + +Example output: +``` +OS: Linux x86_64 (Ubuntu 22.04) +GPUs: + - NVIDIA A100-SXM4-80GB (80GB) + CUDA: 12.4, Driver: 545.23.08 +Python: 3.12, 3.11, 3.10 +Disk: 850GB free +``` + +## Setting a Default Node + +1. Go to **Settings > Compute** +2. Click the star icon next to a node to set it as default +3. New conversations will use this node for execution + +## Workspace Isolation + +Each conversation gets its own workspace directory: +- **Local**: `workspaces/{conversation_uuid}/` +- **SSH**: `{remote_workspace}/{conversation_uuid}/` +- **Modal**: Ephemeral filesystem per execution + +Files created during execution persist within the conversation but are isolated from other conversations. + +## Security Considerations + +- **Local**: Commands run in Docker containers with limited host access +- **SSH**: Use dedicated keys with restricted permissions; consider a separate user for OpenMLR +- **Modal**: Code runs in isolated serverless containers + +::: warning +Never expose compute nodes with unrestricted access. Use SSH keys without passphrases only in trusted environments. +::: diff --git a/site/docs/public/apple-touch-icon.png b/site/docs/public/apple-touch-icon.png new file mode 100644 index 0000000..77b19e6 Binary files /dev/null and b/site/docs/public/apple-touch-icon.png differ diff --git a/site/docs/public/favicon-16x16.png b/site/docs/public/favicon-16x16.png new file mode 100644 index 0000000..bcb8446 Binary files /dev/null and b/site/docs/public/favicon-16x16.png differ diff --git a/site/docs/public/favicon-32x32.png b/site/docs/public/favicon-32x32.png new file mode 100644 index 0000000..7a8927e Binary files /dev/null and b/site/docs/public/favicon-32x32.png differ diff --git a/site/docs/public/favicon.ico b/site/docs/public/favicon.ico new file mode 100644 index 0000000..7a8927e Binary files /dev/null and b/site/docs/public/favicon.ico differ diff --git a/site/docs/public/logo-192.png b/site/docs/public/logo-192.png new file mode 100644 index 0000000..47bed11 Binary files /dev/null and b/site/docs/public/logo-192.png differ diff --git a/site/docs/public/logo-512.png b/site/docs/public/logo-512.png new file mode 100644 index 0000000..b218d03 Binary files /dev/null and b/site/docs/public/logo-512.png differ diff --git a/site/docs/public/logo-64.png b/site/docs/public/logo-64.png new file mode 100644 index 0000000..6e94409 Binary files /dev/null and b/site/docs/public/logo-64.png differ diff --git a/site/docs/public/og-image.png b/site/docs/public/og-image.png new file mode 100644 index 0000000..49ff457 Binary files /dev/null and b/site/docs/public/og-image.png differ