diff --git a/.github/AGENTS.md b/.github/AGENTS.md new file mode 100644 index 000000000..105dd8ff3 --- /dev/null +++ b/.github/AGENTS.md @@ -0,0 +1,35 @@ +# GitHub Automation DOX + +## Purpose + +- Own repository automation that runs on GitHub, including workflows and release-planning scripts. +- Keep CI, Docker publishing, stale issue handling, and release-note generation aligned with repository release rules. + +## Ownership + +- `workflows/` contains GitHub Actions workflow definitions. +- `scripts/` contains Python helpers called by workflows. +- Root-level release rules remain in the root `AGENTS.md`; this file owns automation-specific details. + +## Local Contracts + +- Docker publishing lives in `workflows/docker-publish.yml` and delegates planning to `scripts/docker_release_plan.py`. +- Releasable tags are `vX.Y` tags at or above `v1.0`, matching the workflow environment. +- Release-note generation reads `scripts/openrouter_release_notes_system_prompt.md` from the repository root and requires OpenRouter credentials from workflow environment variables. +- Keep workflow secrets in GitHub Actions secrets or environment variables. Do not commit credentials, tokens, or generated release bodies containing private data. +- Workflow scripts must fail loudly with actionable messages when required environment variables or git refs are missing. + +## Work Guidance + +- Prefer deterministic, testable Python for workflow planning logic instead of complex inline shell in YAML. +- Preserve manual dispatch behavior when changing Docker publishing. +- Keep branch, tag, and release behavior synchronized between workflow YAML, release scripts, tests, and root documentation. + +## Verification + +- Run `pytest tests/test_docker_release_plan.py` after changing Docker publish planning or release workflow behavior. +- Run targeted tests for any changed script that already has coverage. + +## Child DOX Index + +No child DOX files. diff --git a/AGENTS.md b/AGENTS.md index 63a3fe050..31ab6a620 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -3,11 +3,11 @@ [Generated using reconnaissance on 2026-02-22] ## Quick Reference -Tech Stack: Python 3.12+ | Flask | Alpine.js | LiteLLM | WebSocket (Socket.io) -Dev Server: python run_ui.py (runs on http://localhost:50001 by default) +Tech Stack: Framework Python 3.12+ | Agent execution Python 3.13 in Docker | Flask | Alpine.js | LiteLLM | WebSocket (Socket.io) +Dev Server: python run_ui.py (discover host/port from startup output or runtime configuration; do not assume a default port) Run Tests: pytest (standard) or pytest tests/test_name.py (file-scoped) Documentation: README.md | docs/ -Frontend Deep Dives: [Component System](docs/agents/AGENTS.components.md) | [Modal System](docs/agents/AGENTS.modals.md) | [Plugin Architecture](docs/agents/AGENTS.plugins.md) | [Banners & Discovery](docs/agents/AGENTS.banners.md) +Frontend & Plugin DOX: [WebUI](webui/AGENTS.md) | [Components](webui/components/AGENTS.md) | [Frontend JS](webui/js/AGENTS.md) | [Plugins](plugins/AGENTS.md) --- @@ -41,25 +41,26 @@ Primary Language(s): Python, JavaScript (ES Modules) Do not combine these commands; run them individually: ```bash pip install -r requirements.txt -pip install -r requirements2.txt ``` - Start WebUI: python run_ui.py +- Discover the WebUI URL from startup output, launcher/Docker port mappings, or explicit `--host`/`--port`/`WEB_UI_PORT` configuration; do not hardcode a default port. --- ## Docker Environment -When running in Docker, Agent Zero uses two distinct Python runtimes to isolate the framework from the code being executed: +When running in Docker, Agent Zero uses two distinct Python runtimes to isolate the framework itself from code executed on behalf of the agent: ### 1. Framework Runtime (/opt/venv-a0) - Version: Python 3.12.4 -- Purpose: Runs the Agent Zero backend, API, and core logic. -- Packages: Contains all dependencies from requirements.txt. +- Purpose: Runs the Agent Zero framework itself: WebUI backend, API, core loop, scheduler, framework imports, and plugin hooks/tools that execute inside the framework process. +- Packages: Contains framework dependencies from requirements.txt. +- Verification: Use this runtime for framework/backend import checks, WebUI startup checks, and plugin hook behavior unless the code explicitly switches environments. -### 2. Execution Runtime (/opt/venv) +### 2. Agent Execution Runtime (/opt/venv) - Version: Python 3.13 -- Purpose: Default environment for the interactive terminal and the agent's code execution tool. -- Behavior: This is the environment active when you docker exec into the container. Packages installed by the agent via pip install during a task are stored here. +- Purpose: Default Python environment for the agent's terminal/code-execution tasks and user code run by the agent. +- Behavior: Packages installed by the agent during a task belong here so task dependencies do not pollute or prove the framework runtime. Do not use this runtime as evidence that framework imports, WebUI startup, or plugin hooks work. --- @@ -87,9 +88,9 @@ When running in Docker, Agent Zero uses two distinct Python runtimes to isolate ├── agents/ # Agent profiles (prompts and config) ├── prompts/ # System and message prompt templates ├── knowledge/ -│ └── main/about/ # Agent self-knowledge (indexed into vector DB for runtime recall) +│ └── main/about/ # Agent self-knowledge reference material │ ├── identity.md # Philosophy, principles, project context -│ ├── architecture.md # Agent loop, memory pipeline, multi-agent, extensions +│ ├── architecture.md # Agent loop, multi-agent coordination, extensions │ ├── capabilities.md # Detailed capabilities and limitations │ ├── configuration.md # LLM roles, providers, profiles, plugins, settings │ └── setup-and-deployment.md # Docker deployment, updates, troubleshooting @@ -97,15 +98,16 @@ When running in Docker, Agent Zero uses two distinct Python runtimes to isolate ``` Key Files: -- agent.py: Defines AgentContext and the main Agent class. +- agent.py: Defines AgentContext, LoopData virtual prompt areas (Protocol before history and Extras after history), and the main Agent class. - helpers/plugins.py: Plugin discovery and configuration logic. - webui/js/AlpineStore.js: Store factory for reactive frontend state. - helpers/api.py: Base class for all API endpoints. +- models.py: LLM provider configuration and LiteLLM wrappers; framework LiteLLM defaults such as `drop_params=True` are merged with `litellm_global_kwargs`, configured values override framework defaults, documented module-level switches such as `drop_params` are applied to LiteLLM, and merged kwargs are passed per call. - scripts/openrouter_release_notes_system_prompt.md: Editable system prompt used to generate GitHub release notes during Docker publishing. -- knowledge/main/about/: Agent self-knowledge files, indexed into the vector DB for runtime recall. Not user-facing docs - written for the agent's internal reference. -- docs/agents/AGENTS.components.md: Deep dive into the frontend component architecture. -- docs/agents/AGENTS.modals.md: Guide to the stacked modal system. -- docs/agents/AGENTS.plugins.md: Comprehensive guide to the full-stack plugin system. +- knowledge/main/about/: Agent self-knowledge files. Not user-facing docs - written for the agent's internal reference. +- webui/components/AGENTS.md: DOX contract for Alpine component architecture. +- webui/js/AGENTS.md: DOX contract for frontend infrastructure, modal stack, API helpers, and extension loading. +- plugins/AGENTS.md: DOX contract for bundled and custom plugin architecture; `usr/plugins/` remains ignored user state. --- @@ -240,7 +242,6 @@ If pip install fails, try running in a clean virtual environment: python -m venv .venv source .venv/bin/activate pip install -r requirements.txt -pip install -r requirements2.txt ``` ### WebSocket Connection Failures @@ -249,5 +250,124 @@ pip install -r requirements2.txt --- -*Last updated: 2026-03-25* +*Last updated: 2026-06-01* *Maintained by: Agent Zero Core Team* + + +# DOX framework + +- DOX is highly performant AGENTS.md hierarchy installed here +- Agent must follow DOX instructions across any edits + +## Core Contract + +- AGENTS.md files are binding work contracts for their subtrees +- Work products, source materials, instructions, records, assets, and durable docs must stay understandable from the nearest applicable AGENTS.md plus every parent AGENTS.md above it + +## Read Before Editing + +1. Read the root AGENTS.md +2. Identify every file or folder you expect to touch +3. Walk from the repository root to each target path +4. Read every AGENTS.md found along each route +5. If a parent AGENTS.md lists a child AGENTS.md whose scope contains the path, read that child and continue from there +6. Use the nearest AGENTS.md as the local contract and parent docs for repo-wide rules +7. If docs conflict, the closer doc controls local work details, but no child doc may weaken DOX + +Do not rely on prior context. Re-read the applicable DOX chain in the current session before editing. + +## Update After Editing + +Every meaningful change requires a DOX pass before the task is done. + +Update the closest owning AGENTS.md when a change affects: + +- purpose, scope, ownership, or responsibilities +- durable structure, contracts, workflows, or operating rules +- required inputs, outputs, permissions, constraints, side effects, or artifacts +- user preferences about behavior, communication, process, organization, or quality +- AGENTS.md creation, deletion, move, rename, or index contents + +Update parent docs when parent-level structure, ownership, workflow, or child index changes. Update child docs when parent changes alter local rules. Remove stale or contradictory text immediately. Small edits that do not change behavior or contracts may leave docs unchanged, but the DOX pass still must happen. + +Do not create or update DOX docs for changes confined to ignored runtime or user-state folders under `usr/` or `tmp/` unless the user explicitly asks for those folders to be documented. + +## Hierarchy + +- Root AGENTS.md is the DOX rail: project-wide instructions, global preferences, durable workflow rules, and the top-level Child DOX Index +- Child AGENTS.md files own domain-specific instructions and their own Child DOX Index +- Each parent explains what its direct children cover and what stays owned by the parent +- The closer a doc is to the work, the more specific and practical it must be + +## Child Doc Shape + +- Create a child AGENTS.md when a folder becomes a durable boundary with its own purpose, rules, responsibilities, workflow, materials, or quality standards +- Work Guidance must reflect the current standards of the project or user instructions; if there are no specific standards or instructions yet, leave it empty +- Verification must reflect an existing check; if no verification framework exists yet, leave it empty and update it when one exists + +Default section order: +- Purpose +- Ownership +- Local Contracts +- Work Guidance +- Verification +- Child DOX Index + +## Style + +- Keep docs concise, current, and operational +- Document stable contracts, not diary entries +- Put broad rules in parent docs and concrete details in child docs +- Prefer direct bullets with explicit names +- Do not duplicate rules across many files unless each scope needs a local version +- Delete stale notes instead of explaining history +- Trim obvious statements, repeated rules, misplaced detail, and warnings for risks that no longer exist + +## Closeout + +1. Re-check changed paths against the DOX chain +2. Update nearest owning docs and any affected parents or children +3. Refresh every affected Child DOX Index +4. Remove stale or contradictory text +5. Run existing verification when relevant +6. Report any docs intentionally left unchanged and why + +## User Preferences + +- Do not document changes in `usr/` or `tmp/`; treat both as ignored runtime/user-state folders unless explicitly requested otherwise. + +## Child DOX Index + +Direct child DOX files: + +| Child | Scope | +| --- | --- | +| [.github/AGENTS.md](.github/AGENTS.md) | GitHub Actions workflows and release automation scripts. | +| [agents/AGENTS.md](agents/AGENTS.md) | Bundled agent profiles, profile-local prompts, and profile-local tools. | +| [api/AGENTS.md](api/AGENTS.md) | HTTP API handlers and WebSocket handler entry points. | +| [conf/AGENTS.md](conf/AGENTS.md) | Repository-shipped configuration defaults and templates. | +| [docker/AGENTS.md](docker/AGENTS.md) | Docker build contexts, image definitions, and runtime compose files. | +| [docs/AGENTS.md](docs/AGENTS.md) | Human-facing documentation, developer guides, screenshots, and agent deep dives. | +| [extensions/AGENTS.md](extensions/AGENTS.md) | Core lifecycle extension hook implementations for backend and WebUI surfaces. | +| [helpers/AGENTS.md](helpers/AGENTS.md) | Shared backend framework utilities and cross-cutting runtime services. | +| [knowledge/AGENTS.md](knowledge/AGENTS.md) | Built-in agent self-knowledge and indexed reference material. | +| [lib/AGENTS.md](lib/AGENTS.md) | Lightweight browser-side helper scripts outside the main WebUI bundle. | +| [plugins/AGENTS.md](plugins/AGENTS.md) | Bundled system plugins shipped with the framework. | +| [prompts/AGENTS.md](prompts/AGENTS.md) | Core prompt templates loaded by agents and framework workflows. | +| [scripts/AGENTS.md](scripts/AGENTS.md) | Repository maintenance scripts invoked by automation or maintainers. | +| [skills/AGENTS.md](skills/AGENTS.md) | Bundled Agent Zero skills and their agent-facing instructions. | +| [tests/AGENTS.md](tests/AGENTS.md) | Pytest regression and contract tests. | +| [tools/AGENTS.md](tools/AGENTS.md) | Core agent tool implementations. | +| [webui/AGENTS.md](webui/AGENTS.md) | Flask-served Alpine.js WebUI shell, frontend modules, components, CSS, assets, and vendor libraries. | + +Intentionally unindexed local or generated roots: + +| Path | Reason | +| --- | --- | +| `.conda/`, `.venv/` | Local Python environments. | +| `.pytest_cache/`, `__pycache__/` | Generated test and bytecode caches. | +| `.vscode/`, `.windsurf/` | Editor-local configuration and assistant metadata. | +| `logs/` | Runtime output. | +| `tmp/` | Ignored runtime caches, uploads, and generated working files; do not document changes here unless explicitly requested. | +| `usr/` | Ignored local user data, settings, plugins, uploads, chats, and workdirs; do not document changes here unless explicitly requested. | +| `python/` | Generated or legacy runtime cache mirror; current source lives in root-level `api/`, `helpers/`, `tools/`, and `extensions/`. | diff --git a/README.md b/README.md index 9b1dc4acf..45efd23d1 100644 --- a/README.md +++ b/README.md @@ -3,36 +3,62 @@ Agent Zero Banner # Agent Zero -### A full Linux system for your AI agent. +### Give your agent a full Linux computer. -Agent Zero is an open, dynamic, organic agentic framework. One Docker container ships a full Linux system with a desktop and a plugin hub that the agent can extend using Skills. +Agent Zero is an open agent framework for work that needs more than chat: a Dockerized Linux desktop, a browser with DOM annotation, live document cowork, projects, skills, plugins, and a bridge back to your host machine. [![Website](https://img.shields.io/badge/Website-agent--zero.ai-0A192F?style=for-the-badge&logo=vercel&logoColor=white)](https://agent-zero.ai) [![Docs](https://img.shields.io/badge/Docs-Read%20the%20guides-1F6FEB?style=for-the-badge&logo=readthedocs&logoColor=white)](./docs/) [![Discord](https://img.shields.io/badge/Discord-Join%20us-5865F2?style=for-the-badge&logo=discord&logoColor=white)](https://discord.gg/B8KZKNsPpj) [![GitHub Sponsors](https://img.shields.io/badge/Sponsors-Thank%20you-FF69B4?style=for-the-badge&logo=githubsponsors&logoColor=white)](https://github.com/sponsors/agent0ai) - -[Install](#how-to-install) | -[What's Different](#what-makes-agent-zero-different) | -[A0 CLI](#a0-cli-connector-extend-onto-your-host-machine) | -[Docs](#documentation) - [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/agent0ai/agent-zero) -[Ask ChatGPT](https://chatgpt.com/?q=Analyze%20this%3A%20https%3A%2F%2Fgithub.com%2Fagent0ai%2Fagent-zero) | -[Ask Claude](https://claude.ai/new?q=Analyze%20this%3A%20https%3A%2F%2Fgithub.com%2Fagent0ai%2Fagent-zero) +[Quick Start](#quick-start) | +[Why Agent Zero](#why-agent-zero) | +[Try These First](#try-these-first) | +[Deep Dives](#deep-dives) | +[Docs](#documentation)
- -Agent Zero Installation Guide - +Agent Zero driving Blender in its built-in XFCE desktop
-# What Makes Agent Zero Different +# Why Agent Zero -## How To Install +| Feature | Why it matters | +| --- | --- | +| **Full Linux desktop** | The agent can use real GUI software, terminals, files, and desktop apps inside the Canvas. | +| **Browser DOM annotation** | Click page elements and turn them into inspect, change, lift, or review instructions. | +| **Live document cowork** | Edit Markdown, Writer, Spreadsheet, and Presentation files together instead of losing work in chat. | +| **Plugin Hub** | Install 100+ community plugins or publish your own extension points. | +| **Projects and memory** | Keep files, instructions, secrets, memories, repositories, and model presets isolated per project. | +| **Host-machine bridge** | Connect with the A0 CLI so the same agent can work in your real local repositories. | +| **Multi-agent cooperation** | Let agents delegate research, coding, analysis, or review tasks to focused subagents. | +| **Transparent internals** | Prompts, tools, plugins, skills, and settings are inspectable and editable. | + +# Quick Start + +## Recommended: A0 Launcher + +The desktop **A0 Launcher** is the fastest guided path on a personal machine. Download it, open it, and let it check Docker, create Instances, manage ports, and connect to local or remote Agent Zero installs. + +Agent Zero runs wherever Docker runs, from a $6 VPS or Raspberry Pi to a local workstation or GPU server. + +| Architecture | macOS | Linux | Windows | +| --- | --- | --- | --- | +| x86 | [Mac Intel](https://github.com/agent0ai/a0-launcher/releases/download/v1.2/a0-launcher-1.2-macos-x64.dmg) | [Linux x86](https://github.com/agent0ai/a0-launcher/releases/download/v1.2/a0-launcher-1.2-linux-x64.AppImage) | [Windows x86](https://github.com/agent0ai/a0-launcher/releases/download/v1.2/a0-launcher-1.2-windows-x64.exe) | +| ARM64 | [Mac Apple Silicon](https://github.com/agent0ai/a0-launcher/releases/download/v1.2/a0-launcher-1.2-macos-arm64.dmg) | [Linux ARM64](https://github.com/agent0ai/a0-launcher/releases/download/v1.2/a0-launcher-1.2-linux-arm64.AppImage) | [Windows ARM64](https://github.com/agent0ai/a0-launcher/releases/download/v1.2/a0-launcher-1.2-windows-arm64.exe) | + +See the [A0 Launcher v1.2 release](https://github.com/agent0ai/a0-launcher/releases/tag/v1.2) for release notes and updater metadata. See the [Launcher guide](./docs/guides/launcher.md) for the first-run walkthrough. + +
+Other install paths + +## A0 Install + +Use **A0 Install** when you want the terminal path: SSH sessions, servers, recovery shells, or a scriptable setup. It creates Dockerized Agent Zero instances, mounts each instance's data into `/a0/usr` inside the container, and uses a reuse-before-setup policy: it tries your current Docker CLI configuration, `DOCKER_HOST`, Docker contexts, and known local Docker-compatible endpoints before setting up a runtime. ### macOS / Linux @@ -46,7 +72,21 @@ curl -fsSL https://bash.agent-zero.ai | bash irm https://ps.agent-zero.ai | iex ``` -### Docker already installed? Run this directly +### Headless / scripted + +For servers and automation, run the installer in Quick Start mode so it creates one instance and exits without opening menus: + +```bash +curl -fsSL https://bash.agent-zero.ai | bash -s -- --quick-start --name agent-zero --port 5080 +``` + +```powershell +& ([scriptblock]::Create((irm https://ps.agent-zero.ai))) -QuickStart -Name agent-zero -Port 5080 +``` + +Use `--skip-runtime-setup` / `-SkipRuntimeSetup` when Docker must already be working and the installer should not try to set up a runtime. See the [A0 Install repository](https://github.com/agent0ai/a0-install) for all installer flags. + +## Docker already installed? Run this directly ```bash docker run -p 80:80 -v a0_usr:/a0/usr agent0ai/agent-zero @@ -54,10 +94,27 @@ docker run -p 80:80 -v a0_usr:/a0/usr agent0ai/agent-zero Open the Web UI, configure your LLM provider, and start with a concrete task. For the full setup and onboarding experience, see the [Installation guide](./docs/setup/installation.md). -## A Real Linux Desktop in the Canvas +
-Agent Zero driving Blender in its built-in XFCE desktop -
+## Troubleshooting + +- **Docker is not running:** start Docker Desktop or your Docker service, then reopen the Launcher or rerun the install command. +- **Port 80 is already in use:** use the Launcher to pick another port, or run Docker directly with `-p 5080:80` and open `http://localhost:5080`. +- **Installing on a server:** use the A0 Install Quick Start command with `--quick-start --name agent-zero --port 5080`. +- **Still blocked:** see the [Troubleshooting guide](./docs/guides/troubleshooting.md). + +# Try These First + +- **Annotate a design you like:** "Open this template site in the Browser. I'll annotate the hero section - re-implement it in my project's React + Tailwind stack." +- **Cowork on a spreadsheet:** "Create an editable ODS budget model with assumptions and monthly projections." +- **Drive a desktop app:** "Use the Linux Desktop to open Blender and create a simple 3D logo for me." +- **Review a web UI:** "Open my local app in the Browser. I will annotate the page with comments; then implement the requested UI fixes." +- **Create a specialist:** "Create an Agent Profile for financial analysis with cautious reasoning, clear assumptions, and spreadsheet-first deliverables." +- **Recover a workspace:** "Show me recent Time Travel snapshots and explain what changed before I revert anything." + +# Deep Dives + +## A Real Linux Desktop in the Canvas Agent Zero opens its own Linux desktop inside the right-side Canvas. Not a remote VM, not a shared clipboard, but a real XFCE desktop session running in the container. @@ -81,7 +138,7 @@ Annotate mode turns any webpage into an interactive directive surface. Click an - **Lift it** - see a card, hero, or component on someone else's site that you like? Capture it and have the agent re-implement it in your own project's stack. - **Comment it** - leave actionable notes pinned to elements during a UI review; the agent reads the comments and ships the fixes. -The Docker browser is the default live Browser surface. Browser history keeps screenshots of important steps, so older chats can still show what the agent saw. The Browser also supports Chrome extensions inside the Docker browser, and **Bring Your Own Browser** through the A0 CLI Connector lets the agent drive Chrome/Edge/Chromium on your own machine. +The Docker browser is the default live Browser surface. Browser history keeps screenshots of important steps, so older chats can still show what the agent saw. The Browser also supports Chrome extensions inside the Docker browser, and **Bring Your Own Browser** through the A0 CLI Connector lets the agent drive Chrome, Edge, Brave, Opera, Vivaldi, or Chromium on your own machine. See the [Browser guide](./docs/guides/browser.md) for screenshots, settings, host-browser setup, and troubleshooting. @@ -186,31 +243,9 @@ Almost nothing is hidden. Prompts live in `prompts/`, tools live in `tools/` or Agent Zero supports plugins, MCP, A2A, custom tools, custom prompts, project-scoped configuration, environment-based deployment settings, and a Web UI designed to keep the agent's work readable in real time. -## Try These First +## Time Travel -- **Annotate a design you like:** "Open this template site in the Browser. I'll annotate the hero section - re-implement it in my project's React + Tailwind stack." -- **Cowork on a spreadsheet:** "Create an editable ODS budget model with assumptions and monthly projections." -- **Drive a desktop app:** "Use the Linux Desktop to open Blender and create a simple 3D logo for me." -- **Review a web UI:** "Open my local app in the Browser. I will annotate the page with comments; then implement the requested UI fixes." -- **Create a specialist:** "Create an Agent Profile for financial analysis with cautious reasoning, clear assumptions, and spreadsheet-first deliverables." -- **Recover a workspace:** "Show me recent Time Travel snapshots and explain what changed before I revert anything." - -## Agent Zero and Space Agent - -Agent Zero is the open framework and Linux-powered agent workbench. - -[Space Agent](https://github.com/agent0ai/space-agent) is our newer product direction for the agent-shaped workspace: a Space the agent can reshape from inside your browser, with live demos, a desktop app, and a path to running a real server for yourself or your team. - -

- Watch Space Agent on YouTube -

- -If you want the raw power and deep customizability of an agent with a full Linux system, start here with Agent Zero. If you want the polished Space experience for easier personal, team, desktop, or self-hosted use, explore [Space Agent](https://github.com/agent0ai/space-agent). - - -## Time Travel (powered by Space Agent) - -Time Travel gives Agent Zero-owned `/a0/usr` workspaces snapshot history, diff inspection, travel, and revert. It is designed for recoverable agent work: see what changed, compare files, inspect a past state, and roll back when needed. Try it in Space Agent as well (link above). +Time Travel gives Agent Zero-owned `/a0/usr` workspaces snapshot history, diff inspection, travel, and revert. It is designed for recoverable agent work: see what changed, compare files, inspect a past state, and roll back when needed. Time Travel @@ -228,17 +263,6 @@ It is not a replacement for Git or backups. It is a practical safety layer for t - **Client/project isolation:** keep memory, secrets, instructions, files, and model choices separated by project. - **Scheduled operations:** run recurring checks and monitoring tasks with project-scoped context and credentials. -## Safety Model - -Agent Zero is powerful because it can use a real environment. - -- Keep it running inside Docker or another isolated environment. -- Do not mount your entire home directory unless you understand the risk. -- Grant A0 CLI Read+Write access and remote code execution only for machines and workspaces you trust. -- Store credentials in project secrets or settings, not in prompts or public files. -- Review actions that touch accounts, money, production systems, or private data. -- Keep backups for important workspaces. - ## Documentation | I want to... | Start here | @@ -274,3 +298,16 @@ You can help by improving docs, creating skills, publishing plugins, testing mod - [YouTube](https://www.youtube.com/@AgentZeroFW) for demos and tutorials. - [X](https://x.com/Agent0ai), [LinkedIn](https://www.linkedin.com/company/109758317), and [Warpcast](https://warpcast.com/agent-zero) for updates. - [GitHub Issues](https://github.com/agent0ai/agent-zero/issues) for bugs and feature requests. + +[Space Agent](https://github.com/agent0ai/space-agent) is the related, more polished product direction for the agent-shaped workspace. Agent Zero remains the open framework and Linux-powered workbench. + +## Safety Model + +Agent Zero is powerful because it can use a real environment. + +- Keep it running inside Docker or another isolated environment. +- Do not mount your entire home directory unless you understand the risk. +- Grant A0 CLI Read+Write access and remote code execution only for machines and workspaces you trust. +- Store credentials in project secrets or settings, not in prompts or public files. +- Review actions that touch accounts, money, production systems, or private data. +- Keep backups for important workspaces. diff --git a/agent.py b/agent.py index 149c900e3..f8c902da7 100644 --- a/agent.py +++ b/agent.py @@ -1,4 +1,4 @@ -import asyncio, random, string, threading +import asyncio, json, random, re, string, threading from collections import OrderedDict from dataclasses import dataclass, field @@ -32,6 +32,15 @@ from typing import Callable from helpers.localization import Localization from helpers import extension from helpers.errors import RepairableException, InterventionException, HandledException +from helpers.llm_result import ( + LLMResult, + RESPONSE_METADATA_KEY, + function_call_output_item, + metadata_from_llm_result, + result_from_metadata, +) +from helpers.litellm_transport import ResponsesTransport +from helpers.responses_tools import build_responses_function_tools, original_tool_name class AgentContextType(Enum): USER = "user" @@ -329,6 +338,8 @@ class LoopData: self.system = [] self.user_message: history.Message | None = None self.history_output: list[history.OutputMessage] = [] + self.protocol_temporary: OrderedDict[str, history.MessageContent] = OrderedDict() + self.protocol_persistent: OrderedDict[str, history.MessageContent] = OrderedDict() self.extras_temporary: OrderedDict[str, history.MessageContent] = OrderedDict() self.extras_persistent: OrderedDict[str, history.MessageContent] = OrderedDict() self.last_response = "" @@ -346,6 +357,9 @@ class Agent: DATA_NAME_SUPERIOR = "_superior" DATA_NAME_SUBORDINATE = "_subordinate" DATA_NAME_CTX_WINDOW = "ctx_window" + DATA_NAME_RESPONSES_STATE = "responses_state" + DATA_NAME_RESPONSES_TOOL_NAME_MAP = "responses_tool_name_map" + DATA_NAME_RESPONSES_COMPUTER_SESSION = "responses_computer_session_id" @extension.extensible def __init__( @@ -468,11 +482,12 @@ class Agent: return stop_response # call main LLM - agent_response, _reasoning = await self.call_chat_model( + llm_result = await self.call_chat_model_turn( messages=prompt, response_callback=stream_callback, reasoning_callback=reasoning_callback, ) + agent_response = llm_result.response await self.handle_intervention(agent_response) # Notify extensions to finalize their stream filters @@ -492,7 +507,12 @@ class Agent: ): # if assistant_response is the same as last message in history, let him know # Append the assistant's response to the history log_item = self.loop_data.params_temporary.get("log_item_generating") - self.hist_add_ai_response(agent_response, id=log_item.id if log_item else "") + assistant_message = self.hist_add_ai_response( + agent_response, + id=log_item.id if log_item else "", + llm_result=llm_result, + ) + self._remember_llm_result_state(llm_result, assistant_message) # Append warning message to the history warning_msg = self.read_prompt("fw.msg_repeat.md") wmsg = self.hist_add_warning(message=warning_msg) @@ -504,9 +524,16 @@ class Agent: else: # otherwise proceed with tool # Append the assistant's response to the history log_item = self.loop_data.params_temporary.get("log_item_generating") - self.hist_add_ai_response(agent_response, id=log_item.id if log_item else "") + assistant_message = self.hist_add_ai_response( + agent_response, + id=log_item.id if log_item else "", + llm_result=llm_result, + ) + self._remember_llm_result_state(llm_result, assistant_message) # process tools requested in agent message - tools_result = await self.process_tools(agent_response) + tools_result = await self.process_llm_result_tools( + llm_result + ) if tools_result: # final response of message loop available return tools_result # break the execution if the task is done @@ -555,24 +582,28 @@ class Agent: # concatenate system prompt system_text = "\n\n".join(loop_data.system) - # join extras - extras = history.Message( # type: ignore[abstract] - False, - content=self.read_prompt( - "agent.context.extras.md", - extras=dirty_json.stringify( - {**loop_data.extras_persistent, **loop_data.extras_temporary} - ), - ), - ).output() + # join protocol and extras + protocol = self._build_context_message( + "agent.context.protocol.md", + "protocol", + {**loop_data.protocol_persistent, **loop_data.protocol_temporary}, + include_empty=False, + ) + extras = self._build_context_message( + "agent.context.extras.md", + "extras", + {**loop_data.extras_persistent, **loop_data.extras_temporary}, + include_empty=True, + ) + loop_data.protocol_temporary.clear() loop_data.extras_temporary.clear() - # convert history + extras to LLM format + # convert protocol + history + extras to LLM format history_langchain: list[BaseMessage] = history.output_langchain( - loop_data.history_output + extras + protocol + loop_data.history_output + extras ) - # build full prompt from system prompt, message history and extrS + # build full prompt from system prompt, protocol, message history and extras full_prompt: list[BaseMessage] = [ SystemMessage(content=system_text), *history_langchain, @@ -590,6 +621,24 @@ class Agent: return full_prompt + def _build_context_message( + self, + prompt_file: str, + variable_name: str, + values: dict[str, history.MessageContent], + include_empty: bool, + ) -> list[history.OutputMessage]: + if not include_empty and not values: + return [] + + return history.Message( # type: ignore[abstract] + False, + content=self.read_prompt( + prompt_file, + **{variable_name: dirty_json.stringify(values)}, + ), + ).output() + @extension.extensible async def handle_exception(self, location: str, exception: Exception): if exception: @@ -664,7 +713,12 @@ class Agent: @extension.extensible def hist_add_message( - self, ai: bool, content: history.MessageContent, tokens: int = 0, id: str = "" + self, + ai: bool, + content: history.MessageContent, + tokens: int = 0, + id: str = "", + metadata: dict[str, Any] | None = None, ): self.last_message = Localization.get().now() # Allow extensions to process content before adding to history @@ -673,7 +727,11 @@ class Agent: "hist_add_before", self, content_data=content_data, ai=ai ) return self.history.add_message( - ai=ai, content=content_data["content"], tokens=tokens, id=id + ai=ai, + content=content_data["content"], + tokens=tokens, + id=id, + metadata=metadata, ) @extension.extensible @@ -706,10 +764,17 @@ class Agent: return msg @extension.extensible - def hist_add_ai_response(self, message: str, id: str = ""): + def hist_add_ai_response( + self, message: str, id: str = "", llm_result: LLMResult | None = None + ): self.loop_data.last_response = message content = self.parse_prompt("fw.ai_response.md", message=message) - return self.hist_add_message(True, content=content, id=id) + return self.hist_add_message( + True, + content=content, + id=id, + metadata=metadata_from_llm_result(llm_result), + ) @extension.extensible def hist_add_warning(self, message: history.MessageContent, id: str = ""): @@ -719,13 +784,28 @@ class Agent: @extension.extensible def hist_add_tool_result(self, tool_name: str, tool_result: str, **kwargs): msg_id = kwargs.pop("id", "") + responses_item = kwargs.pop("_responses_output_item", None) or kwargs.pop( + "responses_item", None + ) + metadata = ( + { + RESPONSE_METADATA_KEY: { + "input_items": [responses_item], + "output_items": [], + "mode": "responses", + "state": "provider", + } + } + if isinstance(responses_item, dict) + else None + ) data = { "tool_name": tool_name, "tool_result": tool_result, **kwargs, } extension.call_extensions_sync("hist_add_tool_result", self, data=data) - return self.hist_add_message(False, content=data, id=msg_id) + return self.hist_add_message(False, content=data, id=msg_id, metadata=metadata) def concat_messages( self, messages @@ -830,6 +910,164 @@ class Agent: return response, reasoning + @extension.extensible + async def call_chat_model_turn( + self, + messages: list[BaseMessage], + response_callback: Callable[[str, str], Awaitable[str | None]] | None = None, + reasoning_callback: Callable[[str, str], Awaitable[None]] | None = None, + background: bool = False, + explicit_caching: bool = True, + ) -> LLMResult: + model = self.get_chat_model() + model_kwargs = getattr(model, "kwargs", {}) if model else {} + if isinstance(model_kwargs, dict) and model_kwargs.get("responses_delete_on_chat_delete") is False: + self.set_data("responses_delete_on_chat_delete", False) + response_tools, name_map = build_responses_function_tools(self) + self.set_data(Agent.DATA_NAME_RESPONSES_TOOL_NAME_MAP, name_map) + + call_data = { + "model": model, + "messages": messages, + "response_callback": response_callback, + "reasoning_callback": reasoning_callback, + "background": background, + "explicit_caching": explicit_caching, + "a0_responses_function_tools": response_tools, + } + + previous_state = self._responses_state_for_model(model) + if previous_state: + history_counter = int(previous_state.get("history_counter", 0) or 0) + call_data["previous_response_id"] = previous_state.get("response_id", "") + call_data["responses_input_items"] = self._responses_input_items_since( + model, + history_counter, + ) + call_data["responses_local_input_items"] = self._responses_prompt_input_items( + model, + messages, + ) + + await extension.call_extensions_async( + "chat_model_call_before", self, call_data=call_data + ) + + turn_kwargs = { + "a0_responses_function_tools": call_data.get( + "a0_responses_function_tools" + ), + "responses_local_input_items": call_data.get( + "responses_local_input_items" + ), + } + for key in ( + "responses_builtin_tools", + "responses_state", + "previous_response_id", + "responses_input_items", + ): + if call_data.get(key) is not None: + turn_kwargs[key] = call_data.get(key) + + llm_result = await call_data["model"].unified_turn( + messages=call_data["messages"], + reasoning_callback=call_data["reasoning_callback"], + response_callback=call_data["response_callback"], + rate_limiter_callback=( + self.rate_limiter_callback if not call_data["background"] else None + ), + explicit_caching=call_data["explicit_caching"], + **turn_kwargs, + ) + + downgraded = llm_result.capability.get("builtin_tool_downgrades") + if downgraded: + self.context.log.log( + type="info", + heading="Responses capability downgrade", + content=( + "Provider rejected Responses built-in tool(s); omitted: " + + ", ".join(str(item) for item in downgraded) + ), + ) + + await extension.call_extensions_async( + "chat_model_call_after", + self, + call_data=call_data, + response=llm_result.response, + reasoning=llm_result.reasoning, + ) + + return llm_result + + def _responses_state_for_model(self, model: Any) -> dict[str, Any]: + state = self.get_data(Agent.DATA_NAME_RESPONSES_STATE) + if not isinstance(state, dict): + return {} + provider_model_key = str(getattr(model, "model_name", "") or "") + if state.get("provider_model_key") != provider_model_key: + return {} + if not state.get("response_id"): + return {} + return state + + def _responses_input_items_since( + self, model: Any, sequence: int + ) -> list[dict[str, Any]]: + items: list[dict[str, Any]] = [] + for message in self.history.messages_since(sequence): + items.extend(self._responses_input_items_for_message(model, message)) + return items + + def _responses_input_items_for_message( + self, model: Any, message: history.Message + ) -> list[dict[str, Any]]: + result = result_from_metadata(message.metadata) + if result: + if message.ai and result.output_items: + return [item.to_dict() for item in result.output_items] + if not message.ai and result.input_items: + return [dict(item) for item in result.input_items] + + output = message.output() + langchain_messages = history.output_langchain(output) + if hasattr(model, "_convert_messages"): + converted = model._convert_messages(langchain_messages) + return ResponsesTransport.input_from_messages(converted) + return [] + + def _responses_prompt_input_items( + self, model: Any, messages: list[BaseMessage] + ) -> list[dict[str, Any]]: + if not hasattr(model, "_convert_messages"): + return [] + converted = model._convert_messages(messages) + return ResponsesTransport.input_from_messages(converted) + + def _remember_llm_result_state( + self, llm_result: LLMResult, history_message: history.Message + ) -> None: + if not llm_result.response_id: + return + current = self.get_data(Agent.DATA_NAME_RESPONSES_STATE) + response_ids = [] + if isinstance(current, dict) and isinstance(current.get("response_ids"), list): + response_ids = [str(item) for item in current["response_ids"] if item] + if llm_result.response_id not in response_ids: + response_ids.append(llm_result.response_id) + self.set_data( + Agent.DATA_NAME_RESPONSES_STATE, + { + "response_id": llm_result.response_id, + "previous_response_id": llm_result.previous_response_id, + "provider_model_key": llm_result.provider_model_key, + "history_counter": history_message.sequence, + "response_ids": response_ids, + }, + ) + @extension.extensible async def rate_limiter_callback( self, message: str, key: str, total: int, limit: int @@ -863,6 +1101,310 @@ class Agent: while self.context.paused: await asyncio.sleep(0.1) + async def process_llm_result_tools(self, llm_result: LLMResult): + await self._log_response_builtin_items(llm_result) + if llm_result.function_calls: + for function_call in llm_result.function_calls: + name_map = self.get_data(Agent.DATA_NAME_RESPONSES_TOOL_NAME_MAP) + tool_name = original_tool_name(function_call.name, name_map) + response_item_factory = lambda response, call=function_call: function_call_output_item( + call.call_id, + response.message, + ) + result = await self._execute_tool_request( + tool_name=tool_name, + tool_args=function_call.arguments, + message=llm_result.response, + raw_tool_name=tool_name, + responses_item_factory=response_item_factory, + ) + if result: + return result + return None + if llm_result.builtin_items and not llm_result.response: + return None + if ( + llm_result.mode == "responses" + and llm_result.response + and extract_tools.json_parse_dirty(llm_result.response) is None + ): + return llm_result.response + return await self.process_tools(llm_result.response) + + async def _execute_tool_request( + self, + tool_name: str, + tool_args: dict, + message: str, + raw_tool_name: str = "", + responses_item_factory: Callable[[Any], dict[str, Any]] | None = None, + ): + raw_tool_name = raw_tool_name or tool_name + tool_method = None + tool = None + + try: + import helpers.mcp_handler as mcp_helper + + mcp_tool_candidate = mcp_helper.MCPConfig.get_instance().get_tool( + self, tool_name + ) + if mcp_tool_candidate: + tool = mcp_tool_candidate + except ImportError: + PrintStyle( + background_color="black", font_color="yellow", padding=True + ).print("MCP helper module not found. Skipping MCP tool lookup.") + except Exception as e: + PrintStyle(background_color="black", font_color="red", padding=True).print( + f"Failed to get MCP tool '{tool_name}': {e}" + ) + + if not tool: + tool = self.get_tool( + name=tool_name, + method=tool_method, + args=tool_args, + message=message, + loop_data=self.loop_data, + ) + + if not tool: + error_detail = ( + f"Tool '{raw_tool_name}' not found or could not be initialized." + ) + wmsg = self.hist_add_warning(error_detail) + PrintStyle(font_color="red", padding=True).print(error_detail) + self.context.log.log( + type="warning", + content=f"{self.agent_name}: {error_detail}", + id=wmsg.id, + ) + return None + + self.loop_data.current_tool = tool # type: ignore + try: + await self.handle_intervention() + + await tool.before_execution(**tool_args) + await self.handle_intervention() + + await extension.call_extensions_async( + "tool_execute_before", + self, + tool_args=tool_args or {}, + tool_name=tool_name, + ) + + response = await tool.execute(**tool_args) + await self.handle_intervention() + + await extension.call_extensions_async( + "tool_execute_after", + self, + response=response, + tool_name=tool_name, + ) + + if responses_item_factory: + response.additional = { + **(response.additional or {}), + "_responses_output_item": responses_item_factory(response), + } + + await tool.after_execution(response) + await self.handle_intervention() + + if response.break_loop: + self._clear_responses_pending_state() + return response.message + finally: + self.loop_data.current_tool = None + return None + + async def _log_response_builtin_items(self, llm_result: LLMResult) -> None: + for item in llm_result.builtin_items: + if item.type == "computer_call": + await self._handle_responses_computer_call(item.data) + continue + if item.type == "mcp_approval_request": + self._handle_responses_mcp_approval_request(item.data) + continue + self.context.log.log( + type="info", + heading=f"Responses tool item: {item.type}", + content=json.dumps(item.data, ensure_ascii=False, default=str), + ) + + async def _handle_responses_computer_call(self, item: dict[str, Any]) -> None: + safety_checks = item.get("pending_safety_checks") or item.get("safety_checks") + if safety_checks: + message = ( + "Responses computer_call requested safety-check acknowledgement. " + "Agent Zero requires explicit user acknowledgement before executing it." + ) + output_item = { + "type": "computer_call_output", + "call_id": str(item.get("call_id") or item.get("id") or ""), + "output": {"type": "input_text", "text": message}, + } + self.hist_add_tool_result( + "computer_call", + message, + responses_item=output_item, + ) + self.context.log.log(type="warning", content=message) + return + + args = self._computer_call_args(item) + if not args: + message = "Responses computer_call action is unsupported by Agent Zero." + output_item = { + "type": "computer_call_output", + "call_id": str(item.get("call_id") or item.get("id") or ""), + "output": {"type": "input_text", "text": message}, + } + self.hist_add_tool_result( + "computer_call", + message, + responses_item=output_item, + ) + self.context.log.log(type="warning", content=message) + return + + if args.get("action") != "start_session" and not args.get("session_id"): + session_id = str( + self.get_data(Agent.DATA_NAME_RESPONSES_COMPUTER_SESSION) or "" + ) + if session_id: + args["session_id"] = session_id + + response_item_factory = lambda response: self._computer_call_output_item( + item, + response, + ) + result = await self._execute_tool_request( + tool_name="computer_use_remote", + tool_args=args, + message=json.dumps(item, ensure_ascii=False, default=str), + raw_tool_name="computer_call", + responses_item_factory=response_item_factory, + ) + _ = result + + def _handle_responses_mcp_approval_request(self, item: dict[str, Any]) -> None: + request_id = str( + item.get("approval_request_id") or item.get("id") or item.get("call_id") or "" + ) + message = ( + "Responses MCP approval request received. Agent Zero denied it because " + "provider-hosted MCP approval requires explicit user approval." + ) + output_item = { + "type": "mcp_approval_response", + "approval_request_id": request_id, + "approve": False, + } + self.hist_add_tool_result( + "mcp_approval_request", + message, + responses_item=output_item, + ) + self.context.log.log( + type="warning", + heading="Responses MCP approval required", + content=message, + ) + + def _computer_call_args(self, item: dict[str, Any]) -> dict[str, Any]: + action = item.get("action") + action_data = dict(action) if isinstance(action, dict) else {} + action_type = str( + action_data.get("type") + or action_data.get("action") + or item.get("action_type") + or "" + ).strip().lower() + args: dict[str, Any] = {} + + if action_type in {"screenshot", "capture"}: + args["action"] = "capture" + elif action_type in {"move", "mousemove"}: + args.update({"action": "move", "x": action_data.get("x"), "y": action_data.get("y")}) + elif action_type in {"click", "double_click"}: + args.update( + { + "action": "click", + "x": action_data.get("x"), + "y": action_data.get("y"), + "button": action_data.get("button", "left"), + "count": 2 if action_type == "double_click" else action_data.get("count", 1), + } + ) + elif action_type == "scroll": + args.update( + { + "action": "scroll", + "dx": action_data.get("dx", action_data.get("scroll_x", 0)), + "dy": action_data.get("dy", action_data.get("scroll_y", 0)), + } + ) + elif action_type in {"keypress", "key"}: + args.update( + { + "action": "key", + "keys": action_data.get("keys") or action_data.get("key"), + } + ) + elif action_type in {"type", "input_text"}: + args.update({"action": "type", "text": action_data.get("text", "")}) + else: + return {} + + session_id = item.get("session_id") or action_data.get("session_id") + if session_id: + args["session_id"] = session_id + return args + + def _computer_call_output_item( + self, source_item: dict[str, Any], response: Any + ) -> dict[str, Any]: + output: dict[str, Any] = { + "type": "input_text", + "text": str(getattr(response, "message", "") or ""), + } + additional = getattr(response, "additional", None) + raw_content = additional.get("raw_content") if isinstance(additional, dict) else None + if isinstance(raw_content, list): + for content in raw_content: + if not isinstance(content, dict): + continue + if content.get("type") != "image_url": + continue + image_url = content.get("image_url") + url = image_url.get("url") if isinstance(image_url, dict) else image_url + if url: + output = {"type": "input_image", "image_url": url} + break + + session_id_match = re_search_session_id(str(getattr(response, "message", "") or "")) + if session_id_match: + self.set_data(Agent.DATA_NAME_RESPONSES_COMPUTER_SESSION, session_id_match) + + return { + "type": "computer_call_output", + "call_id": str(source_item.get("call_id") or source_item.get("id") or ""), + "output": output, + } + + def _clear_responses_pending_state(self) -> None: + state = self.get_data(Agent.DATA_NAME_RESPONSES_STATE) + if isinstance(state, dict): + state = dict(state) + state.pop("response_id", None) + state.pop("previous_response_id", None) + self.set_data(Agent.DATA_NAME_RESPONSES_STATE, state) + @extension.extensible async def process_tools(self, msg: str): # search for tool usage requests in agent message @@ -1037,3 +1579,8 @@ class Agent: loop_data=loop_data, **kwargs, ) + + +def re_search_session_id(text: str) -> str: + match = re.search(r"session_id=([A-Za-z0-9_.:-]+)", text or "") + return match.group(1) if match else "" diff --git a/agents/AGENTS.md b/agents/AGENTS.md new file mode 100644 index 000000000..ae6bda3c5 --- /dev/null +++ b/agents/AGENTS.md @@ -0,0 +1,44 @@ +# Agent Profiles DOX + +## Purpose + +- Own bundled agent profiles, profile-specific prompts, and profile-local tools. +- Keep profile behavior understandable without requiring edits to core framework prompts. + +## Ownership + +- Each direct profile directory owns its `agent.yaml`, optional `prompts/`, optional `tools/`, and optional `extensions/`. +- `_example/` demonstrates profile layout and should stay suitable as a reference. +- User-created local profiles belong under `usr/agents/`, not here, unless they are intended to ship with the product. + +## Local Contracts + +- `agent.yaml` is the profile entry point and must stay valid YAML. +- Profile prompt overrides should be narrow and named to match the core prompt they extend or replace. +- Profile-local tools must follow the same `Tool` contract as root `tools/`. +- Do not put secrets, provider API keys, local paths, or user-specific settings in bundled profiles. + +## Work Guidance + +- Prefer small profile-specific prompt files over duplicating large core prompts. +- Keep examples generic and runnable in a clean checkout. +- When changing profile behavior, check how the WebUI profile picker and backend profile loader discover profiles. + +## Verification + +- Run `pytest` or targeted tests covering profile loading when changing `agent.yaml` structure or profile discovery. +- Manually inspect YAML validity for changed profiles if no targeted test exists. + +## Child DOX Index + +Direct child DOX files: + +| Child | Scope | +| --- | --- | +| [_example/AGENTS.md](_example/AGENTS.md) | Reference profile demonstrating profile-local prompts, tools, and extensions. | +| [agent0/AGENTS.md](agent0/AGENTS.md) | Main user-facing Agent Zero profile metadata. | +| [default/AGENTS.md](default/AGENTS.md) | Base profile metadata and inherited prompt specifics. | +| [developer/AGENTS.md](developer/AGENTS.md) | Software development specialist profile. | +| [hacker/AGENTS.md](hacker/AGENTS.md) | Cyber security and penetration testing specialist profile. | +| [researcher/AGENTS.md](researcher/AGENTS.md) | Research, data analysis, and reporting specialist profile. | +| [tiny-local/AGENTS.md](tiny-local/AGENTS.md) | Small/local model profile with an action-first communication prompt. | diff --git a/agents/_example/AGENTS.md b/agents/_example/AGENTS.md new file mode 100644 index 000000000..555428ee6 --- /dev/null +++ b/agents/_example/AGENTS.md @@ -0,0 +1,33 @@ +# Example Agent Profile DOX + +## Purpose + +- Own the reference profile used to demonstrate bundled profile layout. +- Show how profile-local prompts, tools, and extensions fit beside `agent.yaml`. + +## Ownership + +- `agent.yaml` owns the example profile metadata. +- `prompts/` owns prompt override examples. +- `tools/` owns profile-local tool examples. +- `extensions/` owns profile-local lifecycle extension examples. + +## Local Contracts + +- Keep this profile generic, minimal, and safe to copy into user or plugin profile work. +- Do not add product behavior here that should live in a real bundled profile. +- Profile-local tools and extensions must follow the same contracts as root tools and extensions. + +## Work Guidance + +- Prefer simple examples that illustrate structure over complex behavior. +- Update related skill guidance when the example profile layout changes. + +## Verification + +- Manually inspect YAML and prompt filenames after edits. +- Run profile-loading tests when changing discovery or profile schema assumptions. + +## Child DOX Index + +No child DOX files. diff --git a/agents/agent0/AGENTS.md b/agents/agent0/AGENTS.md new file mode 100644 index 000000000..65528190a --- /dev/null +++ b/agents/agent0/AGENTS.md @@ -0,0 +1,31 @@ +# Agent 0 Profile DOX + +## Purpose + +- Own the main user-facing Agent Zero profile metadata. +- Keep the primary assistant profile discoverable and distinct from subordinate specialist profiles. + +## Ownership + +- `agent.yaml` owns the profile title, description, and delegation context. +- Prompt behavior is inherited from the default profile unless a local prompt override is added. + +## Local Contracts + +- Keep `Agent 0` suitable as the direct conversation agent for the system. +- Do not add narrow specialist behavior that belongs in `developer/`, `researcher/`, `hacker/`, or a custom user profile. +- Do not store user-specific preferences, provider settings, or secrets in this profile. + +## Work Guidance + +- Keep metadata concise because it appears in profile selection and delegation contexts. +- Coordinate substantial behavior changes with default prompts and WebUI profile selection. + +## Verification + +- Manually inspect `agent.yaml` for valid YAML after edits. +- Run profile-loading tests when changing schema or discovery behavior. + +## Child DOX Index + +No child DOX files. diff --git a/agents/default/AGENTS.md b/agents/default/AGENTS.md new file mode 100644 index 000000000..130d84cc1 --- /dev/null +++ b/agents/default/AGENTS.md @@ -0,0 +1,32 @@ +# Default Agent Profile DOX + +## Purpose + +- Own base profile metadata and default prompt specifics inherited by specialized profiles. +- Provide the shared behavior layer for bundled and custom profiles. + +## Ownership + +- `agent.yaml` owns default profile metadata. +- `agent.system.main.specifics.md` owns default profile-specific system prompt content. +- Additional prompt overrides under this directory become shared defaults unless a child profile overrides them. + +## Local Contracts + +- Keep default behavior broad, framework-compatible, and safe for inheritance. +- Avoid role-specific instructions that belong in specialist profiles. +- Prompt filenames must match the framework prompt override names they target. + +## Work Guidance + +- Prefer small, explicit prompt changes with clear inheritance impact. +- Check bundled specialist profiles after changing default behavior. + +## Verification + +- Manually inspect YAML and prompt rendering assumptions after edits. +- Run prompt/profile tests when changing inherited prompt behavior. + +## Child DOX Index + +No child DOX files. diff --git a/agents/developer/AGENTS.md b/agents/developer/AGENTS.md new file mode 100644 index 000000000..b2d189fff --- /dev/null +++ b/agents/developer/AGENTS.md @@ -0,0 +1,32 @@ +# Developer Agent Profile DOX + +## Purpose + +- Own the bundled software development specialist profile. +- Keep development, debugging, refactoring, and architecture behavior separate from general agent defaults. + +## Ownership + +- `agent.yaml` owns title, description, and delegation context for software development work. +- `prompts/` owns developer-specific prompt overrides when present. +- `extensions/` owns developer-specific lifecycle hooks when present. + +## Local Contracts + +- Keep this profile focused on software engineering tasks. +- Do not hardcode repository-local credentials, paths, or project-specific conventions. +- Prompt overrides must preserve the framework tool-call and response contracts. + +## Work Guidance + +- Align developer behavior with the root engineering and tool contracts. +- Prefer profile prompt edits over core prompt edits when the behavior is specific to development tasks. + +## Verification + +- Manually inspect `agent.yaml` for valid YAML after edits. +- Run prompt/profile tests when changing profile loading or developer prompt behavior. + +## Child DOX Index + +No child DOX files. diff --git a/agents/developer/prompts/agent.system.main.communication.md b/agents/developer/prompts/agent.system.main.communication.md index 18251a64b..8f02165be 100644 --- a/agents/developer/prompts/agent.system.main.communication.md +++ b/agents/developer/prompts/agent.system.main.communication.md @@ -2,9 +2,9 @@ ### Initial Interview -When 'Master Developer' agent receives a development task, it must execute a comprehensive requirements elicitation protocol to ensure complete specification of all parameters, constraints, and success criteria before initiating autonomous development operations. +When 'Master Developer' agent receives a development task, first decide whether the request is already actionable. For clear, bounded coding tasks, infer reasonable defaults from the repository, inspect local specs/tests, implement, and verify. Ask the user only when ambiguity blocks safe progress, would change the deliverable materially, or risks destructive/unwanted work. -The agent SHALL conduct a structured interview process to establish: +For broad or underspecified development mandates, conduct a structured interview process to establish: - **Scope Boundaries**: Precise delineation of features, modules, and integrations included/excluded from the development mandate - **Technical Requirements**: Expected performance benchmarks, scalability needs, from prototype to production-grade implementations - **Output Specifications**: Deliverable preferences (source code, containers, documentation), deployment targets, testing requirements @@ -13,7 +13,7 @@ The agent SHALL conduct a structured interview process to establish: - **Timeline Parameters**: Sprint cycles, release deadlines, milestone deliverables, continuous deployment schedules - **Success Metrics**: Explicit criteria for determining code quality, system performance, and feature completeness -The agent must utilize the 'response' tool iteratively until achieving complete clarity on all dimensions. Only when the agent can execute the entire development lifecycle without further clarification should autonomous work commence. This front-loaded investment in requirements understanding prevents costly refactoring and ensures alignment with user expectations. +Use the 'response' tool iteratively only for blocking questions. Do not ask an interview when the user asked for a small script, bug fix, refactor, test addition, or inspection task that can be handled from local context. For these tasks, move quickly through inspect -> implement -> test -> cleanup -> concise final report. ### Thinking (thoughts) @@ -80,4 +80,4 @@ Exactly one JSON object per response cycle. } ~~~ -{{ include "agent.system.main.communication_additions.md" }} \ No newline at end of file +{{ include "agent.system.main.communication_additions.md" }} diff --git a/agents/developer/prompts/agent.system.main.specifics.md b/agents/developer/prompts/agent.system.main.specifics.md index ca0e23d1b..5a857e7d7 100644 --- a/agents/developer/prompts/agent.system.main.specifics.md +++ b/agents/developer/prompts/agent.system.main.specifics.md @@ -40,6 +40,10 @@ You are Agent Zero 'Master Developer' - an autonomous intelligence system engine 4. **Innovation Focus**: Leverage cutting-edge technologies while maintaining pragmatic stability requirements 5. **Practical Delivery**: Ship working software that solves real problems with elegant, maintainable solutions +### Delivery Discipline + +For coding-agent and terminal-heavy tasks, scale the core coding discipline rather than replacing it. Read repository facts first, keep edits scoped, delegate only bounded components with testable outputs, verify integration points and exact artifacts, clean generated work, and report only what was checked. + Your expertise enables transformation of complex technical challenges into elegant, scalable solutions that power mission-critical systems at the highest performance levels. diff --git a/agents/hacker/AGENTS.md b/agents/hacker/AGENTS.md new file mode 100644 index 000000000..9daeaed00 --- /dev/null +++ b/agents/hacker/AGENTS.md @@ -0,0 +1,31 @@ +# Hacker Agent Profile DOX + +## Purpose + +- Own the bundled cyber security and penetration testing specialist profile. +- Keep security-audit behavior scoped to this profile instead of default agent behavior. + +## Ownership + +- `agent.yaml` owns title, description, and delegation context for security work. +- `prompts/` owns security-specific prompt overrides when present. + +## Local Contracts + +- Keep the profile focused on authorized security analysis, vulnerability research, and defensive audit tasks. +- Do not add secrets, target-specific credentials, or local environment assumptions. +- Preserve the framework tool-call contract and safety expectations. + +## Work Guidance + +- Keep security instructions operational and bounded to legitimate testing contexts. +- Coordinate broad safety changes with core prompts and relevant tests. + +## Verification + +- Manually inspect `agent.yaml` for valid YAML after edits. +- Run prompt/profile tests when changing profile discovery or security prompt behavior. + +## Child DOX Index + +No child DOX files. diff --git a/agents/researcher/AGENTS.md b/agents/researcher/AGENTS.md new file mode 100644 index 000000000..dd7e41def --- /dev/null +++ b/agents/researcher/AGENTS.md @@ -0,0 +1,31 @@ +# Researcher Agent Profile DOX + +## Purpose + +- Own the bundled research, data analysis, and reporting specialist profile. +- Keep evidence-gathering and report-oriented behavior separate from general defaults. + +## Ownership + +- `agent.yaml` owns title, description, and delegation context for research work. +- `prompts/` owns researcher-specific prompt overrides when present. + +## Local Contracts + +- Keep this profile focused on information gathering, analysis, synthesis, and reporting. +- Do not bake in project-specific sources, credentials, or local paths. +- Preserve the framework tool-call and response contracts. + +## Work Guidance + +- Prefer prompt changes that improve citation, evidence handling, and analysis quality for research tasks. +- Coordinate broad research behavior changes with document or browser plugin contracts when relevant. + +## Verification + +- Manually inspect `agent.yaml` for valid YAML after edits. +- Run prompt/profile tests when changing discovery or researcher prompt behavior. + +## Child DOX Index + +No child DOX files. diff --git a/agents/tiny-local/AGENTS.md b/agents/tiny-local/AGENTS.md new file mode 100644 index 000000000..86715f4dc --- /dev/null +++ b/agents/tiny-local/AGENTS.md @@ -0,0 +1,38 @@ +# Tiny Local Agent Profile DOX + +## Purpose + +- Own the bundled Tiny Local profile for small/local chat models. +- Keep local-model behavior prompt-only and isolated from core framework execution. + +## Ownership + +- `agent.yaml` owns profile metadata for discovery and profile switching. +- `prompts/agent.system.main.communication.md` owns the local-model communication contract. +- `prompts/agent.system.main.solving.md` owns the local-model problem-solving contract and suppresses inherited visible reasoning requirements. +- `prompts/fw.msg_repeat.md` owns Tiny Local's profile-specific recovery instructions when the framework rejects a duplicate assistant message. +- `prompts/agent.system.tools.md` owns the Tiny Local tools wrapper and final output-shape reminder after tool listing. +- `prompts/agent.system.tool.*.md` files own Tiny Local-specific tool examples that avoid inherited reasoning fields and repeated writes. + +## Local Contracts + +- Preserve the normal Agent Zero tool-call shape: `tool_name` plus `tool_args`. +- Do not add parser repair, duplicate suppression runtime, model transport, or text-editor runtime behavior here. +- Duplicate-message handling may be tightened through profile prompts only. +- Keep prompt text short enough for small local models to follow. +- Treat continuation requests such as `proceed` or `continue` as commands to execute the next unfinished step, not as prompts for another status response. +- Do not include user-specific provider names, API keys, local paths, or secrets. + +## Work Guidance + +- Prefer prompt wording changes over new files when tightening this profile, except when replacing inherited tool examples for local-model compliance. +- Keep this profile suitable for Ollama, LM Studio, Qwen, and comparable local models. + +## Verification + +- Render the `tiny-local` system prompt after communication prompt changes. +- Run `pytest tests/test_default_prompt_budget.py` for prompt and profile regressions. + +## Child DOX Index + +No child DOX files. diff --git a/agents/tiny-local/agent.yaml b/agents/tiny-local/agent.yaml new file mode 100644 index 000000000..413dcbfbf --- /dev/null +++ b/agents/tiny-local/agent.yaml @@ -0,0 +1,3 @@ +title: Tiny Local +description: Action-first profile for small local models that need a minimal tool-call contract. +context: Use this agent when running small local chat models through Ollama, LM Studio, or similar providers and the model tends to explain actions instead of calling tools. diff --git a/agents/tiny-local/prompts/agent.system.main.communication.md b/agents/tiny-local/prompts/agent.system.main.communication.md new file mode 100644 index 000000000..65f79edef --- /dev/null +++ b/agents/tiny-local/prompts/agent.system.main.communication.md @@ -0,0 +1,31 @@ +## Communication + +You are Agent Zero. Act on the user's behalf. + +When the user asks you to do something, do it directly. Do not explain how the user could do it themselves. + +Your visible assistant message must be exactly one valid JSON object. + +Use exactly these top-level fields: `"tool_name"` and `"tool_args"`. + +Do not include markdown fences, prose before the JSON, prose after the JSON, hidden reasoning, analysis, thoughts, or headlines. + +Choose a tool from the tools listed in this system prompt. Do not invent tool names, action names, or generic names such as `read`, `write`, `terminal`, or `multi`. + +For a final user-facing answer, use the `response` tool. + +Use `response` only when the work is complete, blocked, or the user is only acknowledging completed work. + +If the user says "proceed", "continue", "go ahead", "do it", "excellent proceed", or similar after you named a next step or there is unfinished work, do not answer with a promise or status update. Call the next appropriate tool. + +Final-answer shape: + +`{"tool_name":"response","tool_args":{"text":"Answer briefly."}}` + +For work that requires a command, file action, browser action, or any other available tool, call the appropriate tool immediately. Do not explain what command the user could run manually. + +If the framework warns that your prior message was malformed, repeated, or reasoning-only, output a corrected JSON tool request immediately without explaining the warning. + +When the warning says you sent the same message again, do not resend the same JSON. Change the tool, action, arguments, or final answer so the next message is meaningfully different. + +{{ include "agent.system.main.communication_additions.md" }} diff --git a/agents/tiny-local/prompts/agent.system.main.solving.md b/agents/tiny-local/prompts/agent.system.main.solving.md new file mode 100644 index 000000000..2e410be4a --- /dev/null +++ b/agents/tiny-local/prompts/agent.system.main.solving.md @@ -0,0 +1,18 @@ +## Problem Solving + +Act directly and keep hidden reasoning out of the visible JSON. + +For simple questions, answer with the `response` tool. + +Continuation words such as "proceed", "continue", "go ahead", "do it", and "excellent proceed" mean execute the next unfinished step. Do not respond by saying you will begin, continue, start, proceed, or investigate. Use a real tool call unless the task is already complete or blocked. + +For tasks that need shell commands, files, browser actions, or other capabilities: +- choose the appropriate listed tool immediately +- keep one tool call per turn unless the `parallel` tool is listed and truly useful +- inspect outputs before deciding the next tool call +- never claim success from timeout output or a still-running command +- after a successful tool result, do not repeat the same exact tool call +- after a repeated-message warning, do not repeat the same status response or exact tool request; choose the next different executable action or report a blocker +- when finished, use the `response` tool with a brief result + +Do not include `thoughts`, `headline`, analysis, plans, or prose outside the JSON object. diff --git a/agents/tiny-local/prompts/agent.system.tool.code_exe.md b/agents/tiny-local/prompts/agent.system.tool.code_exe.md new file mode 100644 index 000000000..a42a3314f --- /dev/null +++ b/agents/tiny-local/prompts/agent.system.tool.code_exe.md @@ -0,0 +1,24 @@ +### code_execution_tool +Run terminal, Python, or Node.js commands. + +Arguments in `tool_args`: +- `runtime`: `terminal`, `python`, `nodejs`, or `output` +- `code`: command or script code +- `session`: terminal session id; default `0` +- `reset`: kill a session before running; `true` or `false` + +Rules: +- Put the command or script in `code`. +- Use `runtime=output` to poll running work. +- Use `input` for interactive terminal prompts. +- If a session is stuck, call this tool again with the same `session` and `reset=true`. +- Do not claim success from timeout output or a still-running command. +- When counting files, prefer `find` over `ls` so hidden files and type filters are handled. + +Examples: + +`{"tool_name":"code_execution_tool","tool_args":{"runtime":"terminal","session":0,"reset":false,"code":"ls -1 /tmp | wc -l"}}` + +`{"tool_name":"code_execution_tool","tool_args":{"runtime":"python","session":0,"reset":false,"code":"import os\nprint(os.getcwd())"}}` + +`{"tool_name":"code_execution_tool","tool_args":{"runtime":"output","session":0}}` diff --git a/agents/tiny-local/prompts/agent.system.tool.response.md b/agents/tiny-local/prompts/agent.system.tool.response.md new file mode 100644 index 000000000..de0709179 --- /dev/null +++ b/agents/tiny-local/prompts/agent.system.tool.response.md @@ -0,0 +1,13 @@ +### response +Final answer to the user. + +Use this tool only when the task is done, blocked, or no tool is needed. + +Do not use this tool for "proceed", "continue", "go ahead", or similar continuation requests when there is an unfinished next step. Call a real tool instead. + +Arguments in `tool_args`: +- `text`: concise final answer text + +Example: + +`{"tool_name":"response","tool_args":{"text":"There are 24 files in /tmp."}}` diff --git a/agents/tiny-local/prompts/agent.system.tool.text_editor.md b/agents/tiny-local/prompts/agent.system.tool.text_editor.md new file mode 100644 index 000000000..fdf7ad141 --- /dev/null +++ b/agents/tiny-local/prompts/agent.system.tool.text_editor.md @@ -0,0 +1,26 @@ +### text_editor +Read, write, or patch Markdown and plain text files. + +Actions in `tool_args.action`: +- `read`: read a file +- `write`: create or overwrite a file +- `patch`: edit an existing file + +Common arguments: +- `path`: absolute file path +- `content`: full file content for `write` +- `open_in_canvas`: set `true` when the user explicitly asks to open a Markdown file in the Canvas or Editor + +Rules: +- Use this tool for `.md` and plain text files. +- Use `write` to create a new Markdown file. +- If the user asks to open the file in the Canvas or Editor, include `"open_in_canvas": true` in the same `write` or `patch` call. +- After a successful write or patch result, do not repeat the same tool call. Use the `response` tool unless a different action is needed. + +Examples: + +`{"tool_name":"text_editor","tool_args":{"action":"write","path":"/a0/usr/workdir/TODO.md","content":"# TODO\n- [ ] First item\n","open_in_canvas":true}}` + +`{"tool_name":"text_editor","tool_args":{"action":"read","path":"/a0/usr/workdir/TODO.md"}}` + +`{"tool_name":"text_editor","tool_args":{"action":"patch","path":"/a0/usr/workdir/TODO.md","old_text":"- [ ] First item","new_text":"- [x] First item"}}` diff --git a/agents/tiny-local/prompts/agent.system.tools.md b/agents/tiny-local/prompts/agent.system.tools.md new file mode 100644 index 000000000..7c50f33b0 --- /dev/null +++ b/agents/tiny-local/prompts/agent.system.tools.md @@ -0,0 +1,17 @@ +## Available Tools + +Use only the tools listed below. Match tool names exactly. + +Every tool request must be exactly one JSON object with only these top-level fields: +- `tool_name` +- `tool_args` + +Action names are not tool names. Do not invent top-level `multi`, `read`, `write`, `terminal`, or generic batch tools. + +{{tools}} + +## Tiny Local Output Rule + +Some inherited tool examples may show `thoughts` or `headline`. Ignore that shape for this profile. + +Do not include `thoughts`, `headline`, analysis, markdown fences, or prose outside the JSON object. diff --git a/agents/tiny-local/prompts/fw.msg_repeat.md b/agents/tiny-local/prompts/fw.msg_repeat.md new file mode 100644 index 000000000..10602a558 --- /dev/null +++ b/agents/tiny-local/prompts/fw.msg_repeat.md @@ -0,0 +1,13 @@ +You have sent the same message again. You have to do something else. + +Your repeated JSON was recorded, but it did not execute another tool. Do not send the same JSON object again. + +Choose one different action now: +- If work is unfinished, call a real tool for the next unfinished step. +- If your previous JSON used `response` while work remains, replace it with the next real tool call. +- If a file write or patch already succeeded, read that file or answer with the observed result. +- If a command already ran, inspect its output or run a different next command. +- If the user only said "proceed" or "continue", continue with the next real tool call. +- If no different action is possible, use `response` with a brief blocker. + +Output exactly one JSON object with `tool_name` and `tool_args`. No prose or markdown. diff --git a/api/AGENTS.md b/api/AGENTS.md new file mode 100644 index 000000000..02344d435 --- /dev/null +++ b/api/AGENTS.md @@ -0,0 +1,42 @@ +# API Handlers DOX + +## Purpose + +- Own backend HTTP API handlers and WebSocket handler entry points. +- Keep route-level behavior, authentication, CSRF, input parsing, and response shapes explicit. + +## Ownership + +- Files in this directory are discovered by the route registration layer in `helpers/api.py` and WebSocket registration code. +- `ws_*.py` files define WebSocket namespaces or handlers through `helpers.ws.WsHandler`. +- Plugin-provided API handlers belong inside plugin `api/` folders and follow the same base contracts. + +## Local Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`. +- Implement `async def process(self, input: dict, request: Request) -> dict | Response`. +- Override `get_methods()`, `requires_auth()`, `requires_csrf()`, `requires_api_key()`, or `requires_loopback()` only when the endpoint contract requires it. +- Keep CSRF and authentication protections intact for browser-facing state-changing endpoints. +- WebSocket handlers must derive from `helpers.ws.WsHandler` and validate event data before using it. +- Do not return secrets, raw environment values, private files, or unfiltered exception details to clients. +- This directory is a file-documented DOX profile: every direct `*.py` endpoint or WebSocket module must have a same-directory `*.py.dox.md` file named by appending `.dox.md` to the full Python filename. +- The `*.py.dox.md` file owns endpoint purpose, request/response concepts, auth/CSRF/API-key/loopback assumptions, side effects, important helper dependencies, and verification guidance. +- When a Python endpoint is added, removed, renamed, or behaviorally changed, update its matching `*.py.dox.md` in the same change. +- Do not leave stale file-level DOX after endpoint deletion or rename. + +## Work Guidance + +- Use helpers for shared behavior instead of duplicating persistence, auth, file, project, plugin, or notification logic in endpoints. +- Keep request and response payloads stable; update frontend callers and tests together when payloads change. +- Prefer `Response` for files, redirects, status codes, and plain-text errors; return dictionaries for JSON success payloads. +- During the DOX pass, verify that every direct `*.py` file has a matching `*.py.dox.md` and that changed endpoint behavior is described there. + +## Verification + +- Run targeted `pytest tests/test_*api*.py`, endpoint-specific tests, or WebSocket tests after changing handler behavior. +- For auth, CSRF, upload/download, tunnel, or file endpoints, run the nearest security regression tests. +- Check file-level documentation coverage with a script or shell loop that verifies each `api/*.py` has a matching `api/*.py.dox.md`. + +## Child DOX Index + +No child DOX files. diff --git a/api/agent_profile_set.py b/api/agent_profile_set.py index 331e21fd0..bec0b2ef1 100644 --- a/api/agent_profile_set.py +++ b/api/agent_profile_set.py @@ -1,4 +1,4 @@ -from agent import Agent, AgentContext +from agent import AgentContext from helpers import subagents from helpers.api import ApiHandler, Request, Response from helpers.persist_chat import save_tmp_chat @@ -39,11 +39,7 @@ class SetAgentProfile(ApiHandler): config = initialize_agent(override_settings={"agent_profile": profile}) context.config = config - - agent = context.agent0 - while agent: - agent.config = config - agent = agent.get_data(Agent.DATA_NAME_SUBORDINATE) + context.agent0.config = config save_tmp_chat(context) mark_dirty_for_context(context.id, reason="agent_profile_change") diff --git a/api/agent_profile_set.py.dox.md b/api/agent_profile_set.py.dox.md new file mode 100644 index 000000000..8e891085d --- /dev/null +++ b/api/agent_profile_set.py.dox.md @@ -0,0 +1,48 @@ +# agent_profile_set.py DOX + +## Purpose + +- Own the `agent_profile_set.py` API endpoint. +- This module sets the active agent profile for a chat context and returns profile label metadata. +- Keep this file-level DOX profile synchronized with `agent_profile_set.py` because this directory is intentionally flat. + +## Ownership + +- `agent_profile_set.py` owns the runtime implementation. +- `agent_profile_set.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `SetAgentProfile` (`ApiHandler`) + - `async process(self, input: dict, request: Request) -> dict | Response` +- Top-level functions: +- `_agent_profile_labels() -> dict[str, str]` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `SetAgentProfile` is an `ApiHandler`. +- `SetAgentProfile` defines `process(...)`. +- Observed side-effect areas: filesystem writes, settings/state persistence. +- Switching a chat profile updates the context and top-level agent profile only; existing subordinate agents keep their own profile configs. +- Imported dependency areas include: `agent`, `helpers`, `helpers.api`, `helpers.persist_chat`, `helpers.state_monitor_integration`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `str.strip`, `context.is_running`, `_agent_profile_labels`, `initialize_agent`, `context.agent0.config`, `save_tmp_chat`, `mark_dirty_for_context`, `subagents.get_all_agents_list`, `Response`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- Related tests observed by source search: + - `tests/test_subagent_profiles.py` + +## Child DOX Index + +No child DOX files. diff --git a/api/agents.py.dox.md b/api/agents.py.dox.md new file mode 100644 index 000000000..e7f6895ac --- /dev/null +++ b/api/agents.py.dox.md @@ -0,0 +1,48 @@ +# agents.py DOX + +## Purpose + +- Own the `agents.py` API endpoint. +- This module lists available agent profiles for selection and delegation UI flows. +- Keep this file-level DOX profile synchronized with `agents.py` because this directory is intentionally flat. + +## Ownership + +- `agents.py` owns the runtime implementation. +- `agents.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `Agents` (`ApiHandler`) + - `async process(self, input: Input, request: Request) -> Output` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `Agents` is an `ApiHandler`. +- `Agents` defines `process(...)`. +- Imported dependency areas include: `helpers`, `helpers.api`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `subagents.get_all_agents_list`, `Exception`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- Related tests observed by source search: + - `tests/test_default_prompt_budget.py` + - `tests/test_office_document_store.py` + - `tests/test_projects.py` + - `tests/test_skills_runtime.py` + - `tests/test_time_travel.py` + +## Child DOX Index + +No child DOX files. diff --git a/api/api_files_get.py.dox.md b/api/api_files_get.py.dox.md new file mode 100644 index 000000000..c14bf9f13 --- /dev/null +++ b/api/api_files_get.py.dox.md @@ -0,0 +1,52 @@ +# api_files_get.py DOX + +## Purpose + +- Own the `api_files_get.py` API endpoint. +- This module returns downloadable or inspectable files exposed through the external API surface. +- Keep this file-level DOX profile synchronized with `api_files_get.py` because this directory is intentionally flat. + +## Ownership + +- `api_files_get.py` owns the runtime implementation. +- `api_files_get.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `ApiFilesGet` (`ApiHandler`) + - `requires_auth(cls) -> bool` + - `requires_csrf(cls) -> bool` + - `requires_api_key(cls) -> bool` + - `get_methods(cls) -> list[str]` + - `async process(self, input: dict, request: Request) -> dict | Response` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `ApiFilesGet` is an `ApiHandler`. +- `ApiFilesGet` defines `process(...)`. +- `ApiFilesGet` defines `get_methods(...)`. +- `ApiFilesGet` defines `requires_auth(...)`. +- `ApiFilesGet` defines `requires_csrf(...)`. +- `ApiFilesGet` defines `requires_api_key(...)`. +- Observed side-effect areas: filesystem reads, filesystem writes, settings/state persistence. +- Imported dependency areas include: `base64`, `helpers`, `helpers.api`, `helpers.print_style`, `json`, `os`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `Response`, `PrintStyle.error`, `path.startswith`, `PrintStyle`, `json.dumps`, `path.replace`, `files.get_abs_path`, `os.path.basename`, `os.path.exists`, `PrintStyle.warning`, `f.read`, `base64.b64encode.decode`, `base64.b64encode`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- No direct test reference was found by name search; choose the nearest behavioral test or perform a focused smoke check. + +## Child DOX Index + +No child DOX files. diff --git a/api/api_log_get.py.dox.md b/api/api_log_get.py.dox.md new file mode 100644 index 000000000..043a9c9cf --- /dev/null +++ b/api/api_log_get.py.dox.md @@ -0,0 +1,52 @@ +# api_log_get.py DOX + +## Purpose + +- Own the `api_log_get.py` API endpoint. +- This module returns API/chat log data for external API clients. +- Keep this file-level DOX profile synchronized with `api_log_get.py` because this directory is intentionally flat. + +## Ownership + +- `api_log_get.py` owns the runtime implementation. +- `api_log_get.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `ApiLogGet` (`ApiHandler`) + - `get_methods(cls) -> list[str]` + - `requires_auth(cls) -> bool` + - `requires_csrf(cls) -> bool` + - `requires_api_key(cls) -> bool` + - `async process(self, input: dict, request: Request) -> dict | Response` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `ApiLogGet` is an `ApiHandler`. +- `ApiLogGet` defines `process(...)`. +- `ApiLogGet` defines `get_methods(...)`. +- `ApiLogGet` defines `requires_auth(...)`. +- `ApiLogGet` defines `requires_csrf(...)`. +- `ApiLogGet` defines `requires_api_key(...)`. +- Observed side-effect areas: settings/state persistence, secret handling. +- Imported dependency areas include: `agent`, `helpers.api`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `AgentContext.use`, `Response`, `context.log.output`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- No direct test reference was found by name search; choose the nearest behavioral test or perform a focused smoke check. + +## Child DOX Index + +No child DOX files. diff --git a/api/api_message.py.dox.md b/api/api_message.py.dox.md new file mode 100644 index 000000000..646939cad --- /dev/null +++ b/api/api_message.py.dox.md @@ -0,0 +1,51 @@ +# api_message.py DOX + +## Purpose + +- Own the `api_message.py` API endpoint. +- This module accepts external API messages and dispatches them into Agent Zero chat processing. +- Keep this file-level DOX profile synchronized with `api_message.py` because this directory is intentionally flat. + +## Ownership + +- `api_message.py` owns the runtime implementation. +- `api_message.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `ApiMessage` (`ApiHandler`) + - `requires_auth(cls) -> bool` + - `requires_csrf(cls) -> bool` + - `requires_api_key(cls) -> bool` + - `async process(self, input: dict, request: Request) -> dict | Response` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `ApiMessage` is an `ApiHandler`. +- `ApiMessage` defines `process(...)`. +- `ApiMessage` defines `requires_auth(...)`. +- `ApiMessage` defines `requires_csrf(...)`. +- `ApiMessage` defines `requires_api_key(...)`. +- Observed side-effect areas: filesystem reads, filesystem writes, settings/state persistence, secret handling, scheduler state. +- Imported dependency areas include: `agent`, `base64`, `datetime`, `helpers`, `helpers.api`, `helpers.print_style`, `helpers.projects`, `helpers.security`, `initialize`, `os`, `uuid`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `context.set_data`, `datetime.now`, `Response`, `files.get_abs_path`, `os.makedirs`, `AgentContext.use`, `context.get_data`, `initialize_agent`, `AgentContext`, `context.log.log`, `context.communicate`, `ValueError`, `uuid.uuid4`, `UserMessage`, `task.result`, `PrintStyle.error`, `safe_filename`, `base64.b64decode`, `os.path.join`, `activate_project`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- Related tests observed by source search: + - `tests/test_api_chat_lifetime.py` + +## Child DOX Index + +No child DOX files. diff --git a/api/api_reset_chat.py.dox.md b/api/api_reset_chat.py.dox.md new file mode 100644 index 000000000..5120f46cd --- /dev/null +++ b/api/api_reset_chat.py.dox.md @@ -0,0 +1,52 @@ +# api_reset_chat.py DOX + +## Purpose + +- Own the `api_reset_chat.py` API endpoint. +- This module resets an API-created chat context. +- Keep this file-level DOX profile synchronized with `api_reset_chat.py` because this directory is intentionally flat. + +## Ownership + +- `api_reset_chat.py` owns the runtime implementation. +- `api_reset_chat.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `ApiResetChat` (`ApiHandler`) + - `requires_auth(cls) -> bool` + - `requires_csrf(cls) -> bool` + - `requires_api_key(cls) -> bool` + - `get_methods(cls) -> list[str]` + - `async process(self, input: dict, request: Request) -> dict | Response` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `ApiResetChat` is an `ApiHandler`. +- `ApiResetChat` defines `process(...)`. +- `ApiResetChat` defines `get_methods(...)`. +- `ApiResetChat` defines `requires_auth(...)`. +- `ApiResetChat` defines `requires_csrf(...)`. +- `ApiResetChat` defines `requires_api_key(...)`. +- Observed side-effect areas: filesystem writes, filesystem deletion, settings/state persistence. +- Imported dependency areas include: `agent`, `helpers`, `helpers.api`, `helpers.print_style`, `json`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `AgentContext.use`, `context.reset`, `persist_chat.save_tmp_chat`, `persist_chat.remove_msg_files`, `Response`, `PrintStyle.error`, `PrintStyle`, `json.dumps`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- No direct test reference was found by name search; choose the nearest behavioral test or perform a focused smoke check. + +## Child DOX Index + +No child DOX files. diff --git a/api/api_terminate_chat.py.dox.md b/api/api_terminate_chat.py.dox.md new file mode 100644 index 000000000..541a6d007 --- /dev/null +++ b/api/api_terminate_chat.py.dox.md @@ -0,0 +1,52 @@ +# api_terminate_chat.py DOX + +## Purpose + +- Own the `api_terminate_chat.py` API endpoint. +- This module terminates an API-created chat context. +- Keep this file-level DOX profile synchronized with `api_terminate_chat.py` because this directory is intentionally flat. + +## Ownership + +- `api_terminate_chat.py` owns the runtime implementation. +- `api_terminate_chat.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `ApiTerminateChat` (`ApiHandler`) + - `requires_auth(cls) -> bool` + - `requires_csrf(cls) -> bool` + - `requires_api_key(cls) -> bool` + - `get_methods(cls) -> list[str]` + - `async process(self, input: dict, request: Request) -> dict | Response` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `ApiTerminateChat` is an `ApiHandler`. +- `ApiTerminateChat` defines `process(...)`. +- `ApiTerminateChat` defines `get_methods(...)`. +- `ApiTerminateChat` defines `requires_auth(...)`. +- `ApiTerminateChat` defines `requires_csrf(...)`. +- `ApiTerminateChat` defines `requires_api_key(...)`. +- Observed side-effect areas: filesystem writes, filesystem deletion, settings/state persistence. +- Imported dependency areas include: `agent`, `helpers.api`, `helpers.persist_chat`, `helpers.print_style`, `json`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `AgentContext.use`, `AgentContext.remove`, `remove_chat`, `Response`, `PrintStyle.error`, `PrintStyle`, `json.dumps`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- No direct test reference was found by name search; choose the nearest behavioral test or perform a focused smoke check. + +## Child DOX Index + +No child DOX files. diff --git a/api/backup_create.py.dox.md b/api/backup_create.py.dox.md new file mode 100644 index 000000000..be6076326 --- /dev/null +++ b/api/backup_create.py.dox.md @@ -0,0 +1,49 @@ +# backup_create.py DOX + +## Purpose + +- Own the `backup_create.py` API endpoint. +- This module handles backup create requests. +- Keep this file-level DOX profile synchronized with `backup_create.py` because this directory is intentionally flat. + +## Ownership + +- `backup_create.py` owns the runtime implementation. +- `backup_create.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `BackupCreate` (`ApiHandler`) + - `requires_auth(cls) -> bool` + - `requires_loopback(cls) -> bool` + - `async process(self, input: dict, request: Request) -> dict | Response` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `BackupCreate` is an `ApiHandler`. +- `BackupCreate` defines `process(...)`. +- `BackupCreate` defines `requires_auth(...)`. +- `BackupCreate` defines `requires_loopback(...)`. +- Observed side-effect areas: filesystem writes. +- Imported dependency areas include: `helpers.api`, `helpers.backup`, `helpers.persist_chat`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `save_tmp_chats`, `BackupService`, `send_file`, `backup_service.create_backup`, `line.strip`, `line.startswith`, `patterns_string.split`, `line.strip.startswith`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- Related tests observed by source search: + - `tests/test_download_toast_regressions.py` + +## Child DOX Index + +No child DOX files. diff --git a/api/backup_get_defaults.py.dox.md b/api/backup_get_defaults.py.dox.md new file mode 100644 index 000000000..8f2c1966d --- /dev/null +++ b/api/backup_get_defaults.py.dox.md @@ -0,0 +1,47 @@ +# backup_get_defaults.py DOX + +## Purpose + +- Own the `backup_get_defaults.py` API endpoint. +- This module handles backup get defaults requests. +- Keep this file-level DOX profile synchronized with `backup_get_defaults.py` because this directory is intentionally flat. + +## Ownership + +- `backup_get_defaults.py` owns the runtime implementation. +- `backup_get_defaults.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `BackupGetDefaults` (`ApiHandler`) + - `requires_auth(cls) -> bool` + - `requires_loopback(cls) -> bool` + - `async process(self, input: dict, request: Request) -> dict | Response` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `BackupGetDefaults` is an `ApiHandler`. +- `BackupGetDefaults` defines `process(...)`. +- `BackupGetDefaults` defines `requires_auth(...)`. +- `BackupGetDefaults` defines `requires_loopback(...)`. +- Imported dependency areas include: `helpers.api`, `helpers.backup`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `BackupService`, `backup_service.get_default_backup_metadata`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- No direct test reference was found by name search; choose the nearest behavioral test or perform a focused smoke check. + +## Child DOX Index + +No child DOX files. diff --git a/api/backup_inspect.py.dox.md b/api/backup_inspect.py.dox.md new file mode 100644 index 000000000..363dd63dc --- /dev/null +++ b/api/backup_inspect.py.dox.md @@ -0,0 +1,47 @@ +# backup_inspect.py DOX + +## Purpose + +- Own the `backup_inspect.py` API endpoint. +- This module handles backup inspect requests. +- Keep this file-level DOX profile synchronized with `backup_inspect.py` because this directory is intentionally flat. + +## Ownership + +- `backup_inspect.py` owns the runtime implementation. +- `backup_inspect.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `BackupInspect` (`ApiHandler`) + - `requires_auth(cls) -> bool` + - `requires_loopback(cls) -> bool` + - `async process(self, input: dict, request: Request) -> dict | Response` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `BackupInspect` is an `ApiHandler`. +- `BackupInspect` defines `process(...)`. +- `BackupInspect` defines `requires_auth(...)`. +- `BackupInspect` defines `requires_loopback(...)`. +- Imported dependency areas include: `helpers.api`, `helpers.backup`, `werkzeug.datastructures`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `BackupService`, `backup_service.inspect_backup`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- No direct test reference was found by name search; choose the nearest behavioral test or perform a focused smoke check. + +## Child DOX Index + +No child DOX files. diff --git a/api/backup_preview_grouped.py.dox.md b/api/backup_preview_grouped.py.dox.md new file mode 100644 index 000000000..24e075981 --- /dev/null +++ b/api/backup_preview_grouped.py.dox.md @@ -0,0 +1,47 @@ +# backup_preview_grouped.py DOX + +## Purpose + +- Own the `backup_preview_grouped.py` API endpoint. +- This module handles backup preview grouped requests. +- Keep this file-level DOX profile synchronized with `backup_preview_grouped.py` because this directory is intentionally flat. + +## Ownership + +- `backup_preview_grouped.py` owns the runtime implementation. +- `backup_preview_grouped.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `BackupPreviewGrouped` (`ApiHandler`) + - `requires_auth(cls) -> bool` + - `requires_loopback(cls) -> bool` + - `async process(self, input: dict, request: Request) -> dict | Response` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `BackupPreviewGrouped` is an `ApiHandler`. +- `BackupPreviewGrouped` defines `process(...)`. +- `BackupPreviewGrouped` defines `requires_auth(...)`. +- `BackupPreviewGrouped` defines `requires_loopback(...)`. +- Imported dependency areas include: `helpers.api`, `helpers.backup`, `typing`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `BackupService`, `search_filter.strip`, `backup_service.test_patterns`, `search_filter.lower`, `path.strip.split`, `line.strip`, `line.startswith`, `groups.add`, `patterns_string.split`, `path.strip`, `join`, `f.lower`, `line.strip.startswith`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- No direct test reference was found by name search; choose the nearest behavioral test or perform a focused smoke check. + +## Child DOX Index + +No child DOX files. diff --git a/api/backup_restore.py.dox.md b/api/backup_restore.py.dox.md new file mode 100644 index 000000000..78e74737d --- /dev/null +++ b/api/backup_restore.py.dox.md @@ -0,0 +1,49 @@ +# backup_restore.py DOX + +## Purpose + +- Own the `backup_restore.py` API endpoint. +- This module handles backup restore requests. +- Keep this file-level DOX profile synchronized with `backup_restore.py` because this directory is intentionally flat. + +## Ownership + +- `backup_restore.py` owns the runtime implementation. +- `backup_restore.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `BackupRestore` (`ApiHandler`) + - `requires_auth(cls) -> bool` + - `requires_loopback(cls) -> bool` + - `async process(self, input: dict, request: Request) -> dict | Response` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `BackupRestore` is an `ApiHandler`. +- `BackupRestore` defines `process(...)`. +- `BackupRestore` defines `requires_auth(...)`. +- `BackupRestore` defines `requires_loopback(...)`. +- Observed side-effect areas: filesystem writes, filesystem deletion, settings/state persistence. +- Imported dependency areas include: `helpers.api`, `helpers.backup`, `helpers.persist_chat`, `json`, `werkzeug.datastructures`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `request.form.get.lower`, `json.loads`, `BackupService`, `load_tmp_chats`, `backup_service.restore_backup`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- Related tests observed by source search: + - `tests/test_self_update_tag_filter.py` + +## Child DOX Index + +No child DOX files. diff --git a/api/backup_restore_preview.py.dox.md b/api/backup_restore_preview.py.dox.md new file mode 100644 index 000000000..572473a0a --- /dev/null +++ b/api/backup_restore_preview.py.dox.md @@ -0,0 +1,48 @@ +# backup_restore_preview.py DOX + +## Purpose + +- Own the `backup_restore_preview.py` API endpoint. +- This module handles backup restore preview requests. +- Keep this file-level DOX profile synchronized with `backup_restore_preview.py` because this directory is intentionally flat. + +## Ownership + +- `backup_restore_preview.py` owns the runtime implementation. +- `backup_restore_preview.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `BackupRestorePreview` (`ApiHandler`) + - `requires_auth(cls) -> bool` + - `requires_loopback(cls) -> bool` + - `async process(self, input: dict, request: Request) -> dict | Response` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `BackupRestorePreview` is an `ApiHandler`. +- `BackupRestorePreview` defines `process(...)`. +- `BackupRestorePreview` defines `requires_auth(...)`. +- `BackupRestorePreview` defines `requires_loopback(...)`. +- Observed side-effect areas: filesystem deletion, settings/state persistence. +- Imported dependency areas include: `helpers.api`, `helpers.backup`, `json`, `werkzeug.datastructures`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `request.form.get.lower`, `json.loads`, `BackupService`, `backup_service.preview_restore`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- No direct test reference was found by name search; choose the nearest behavioral test or perform a focused smoke check. + +## Child DOX Index + +No child DOX files. diff --git a/api/backup_test.py b/api/backup_test.py index b5b43eac8..c7a748ebd 100644 --- a/api/backup_test.py +++ b/api/backup_test.py @@ -47,12 +47,13 @@ class BackupTest(ApiHandler): backup_service = BackupService() matched_files = await backup_service.test_patterns(metadata, max_files=max_files) + truncated = max_files is not None and len(matched_files) >= max_files return { "success": True, "files": matched_files, "total_count": len(matched_files), - "truncated": len(matched_files) >= max_files + "truncated": truncated } except Exception as e: diff --git a/api/backup_test.py.dox.md b/api/backup_test.py.dox.md new file mode 100644 index 000000000..a8e06cc6b --- /dev/null +++ b/api/backup_test.py.dox.md @@ -0,0 +1,48 @@ +# backup_test.py DOX + +## Purpose + +- Own the `backup_test.py` API endpoint. +- This module handles backup test requests. +- Keep this file-level DOX profile synchronized with `backup_test.py` because this directory is intentionally flat. + +## Ownership + +- `backup_test.py` owns the runtime implementation. +- `backup_test.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `BackupTest` (`ApiHandler`) + - `requires_auth(cls) -> bool` + - `requires_loopback(cls) -> bool` + - `async process(self, input: dict, request: Request) -> dict | Response` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `BackupTest` is an `ApiHandler`. +- `BackupTest` defines `process(...)`. +- `BackupTest` defines `requires_auth(...)`. +- `BackupTest` defines `requires_loopback(...)`. +- Imported dependency areas include: `helpers.api`, `helpers.backup`. +- The `truncated` response flag is true only when a finite `max_files` limit is supplied and the result reaches that limit. + +## Key Concepts + +- Important called helpers/classes observed in the source: `BackupService`, `backup_service.test_patterns`, `line.strip`, `line.startswith`, `patterns_string.split`, `line.strip.startswith`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- No direct test reference was found by name search; choose the nearest behavioral test or perform a focused smoke check. + +## Child DOX Index + +No child DOX files. diff --git a/api/banners.py.dox.md b/api/banners.py.dox.md new file mode 100644 index 000000000..9d007e7d5 --- /dev/null +++ b/api/banners.py.dox.md @@ -0,0 +1,46 @@ +# banners.py DOX + +## Purpose + +- Own the `banners.py` API endpoint. +- This module collects alert banners and discovery cards from backend extensions. +- Keep this file-level DOX profile synchronized with `banners.py` because this directory is intentionally flat. + +## Ownership + +- `banners.py` owns the runtime implementation. +- `banners.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `GetBanners` (`ApiHandler`) + - `async process(self, input: dict, request: Request) -> dict | Response` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `GetBanners` is an `ApiHandler`. +- `GetBanners` defines `process(...)`. +- Imported dependency areas include: `helpers.api`, `helpers.extension`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `call_extensions_async`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- Related tests observed by source search: + - `tests/test_model_config_api_keys.py` + - `tests/test_oauth_static.py` + - `tests/test_webui_extension_surfaces.py` + +## Child DOX Index + +No child DOX files. diff --git a/api/cache_reset.py.dox.md b/api/cache_reset.py.dox.md new file mode 100644 index 000000000..a7164d5d5 --- /dev/null +++ b/api/cache_reset.py.dox.md @@ -0,0 +1,53 @@ +# cache_reset.py DOX + +## Purpose + +- Own the `cache_reset.py` API endpoint. +- This module handles cache reset API requests. +- Keep this file-level DOX profile synchronized with `cache_reset.py` because this directory is intentionally flat. + +## Ownership + +- `cache_reset.py` owns the runtime implementation. +- `cache_reset.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `CacheReset` (`ApiHandler`) + - `requires_auth(cls) -> bool` + - `requires_csrf(cls) -> bool` + - `requires_api_key(cls) -> bool` + - `requires_loopback(cls) -> bool` + - `get_methods(cls) -> list[str]` + - `async process(self, input: dict, request: Request) -> dict | Response` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `CacheReset` is an `ApiHandler`. +- `CacheReset` defines `process(...)`. +- `CacheReset` defines `get_methods(...)`. +- `CacheReset` defines `requires_auth(...)`. +- `CacheReset` defines `requires_csrf(...)`. +- `CacheReset` defines `requires_api_key(...)`. +- `CacheReset` defines `requires_loopback(...)`. +- Imported dependency areas include: `helpers`, `helpers.api`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `cache.clear_all`, `cache.clear`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- No direct test reference was found by name search; choose the nearest behavioral test or perform a focused smoke check. + +## Child DOX Index + +No child DOX files. diff --git a/api/chat_create.py.dox.md b/api/chat_create.py.dox.md new file mode 100644 index 000000000..3546f4389 --- /dev/null +++ b/api/chat_create.py.dox.md @@ -0,0 +1,45 @@ +# chat_create.py DOX + +## Purpose + +- Own the `chat_create.py` API endpoint. +- This module handles chat create requests. +- Keep this file-level DOX profile synchronized with `chat_create.py` because this directory is intentionally flat. + +## Ownership + +- `chat_create.py` owns the runtime implementation. +- `chat_create.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `CreateChat` (`ApiHandler`) + - `async process(self, input: Input, request: Request) -> Output` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `CreateChat` is an `ApiHandler`. +- `CreateChat` defines `process(...)`. +- Observed side-effect areas: filesystem writes, model calls, plugin state, settings/state persistence. +- Imported dependency areas include: `agent`, `helpers`, `helpers.api`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `self.use_context`, `mark_dirty_all`, `guids.generate_id`, `current_context.get_data`, `current_context.get_output_data`, `new_context.set_data`, `new_context.set_output_data`, `is_chat_override_allowed`, `settings.get_settings`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- Related tests observed by source search: + - `tests/test_browser_agent_regressions.py` + +## Child DOX Index + +No child DOX files. diff --git a/api/chat_export.py.dox.md b/api/chat_export.py.dox.md new file mode 100644 index 000000000..03b5a0c91 --- /dev/null +++ b/api/chat_export.py.dox.md @@ -0,0 +1,44 @@ +# chat_export.py DOX + +## Purpose + +- Own the `chat_export.py` API endpoint. +- This module handles chat export requests. +- Keep this file-level DOX profile synchronized with `chat_export.py` because this directory is intentionally flat. + +## Ownership + +- `chat_export.py` owns the runtime implementation. +- `chat_export.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `ExportChat` (`ApiHandler`) + - `async process(self, input: Input, request: Request) -> Output` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `ExportChat` is an `ApiHandler`. +- `ExportChat` defines `process(...)`. +- Observed side-effect areas: filesystem writes. +- Imported dependency areas include: `helpers`, `helpers.api`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `self.use_context`, `persist_chat.export_json_chat`, `Exception`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- No direct test reference was found by name search; choose the nearest behavioral test or perform a focused smoke check. + +## Child DOX Index + +No child DOX files. diff --git a/api/chat_files_path_get.py.dox.md b/api/chat_files_path_get.py.dox.md new file mode 100644 index 000000000..63f0a2b6e --- /dev/null +++ b/api/chat_files_path_get.py.dox.md @@ -0,0 +1,44 @@ +# chat_files_path_get.py DOX + +## Purpose + +- Own the `chat_files_path_get.py` API endpoint. +- This module handles chat files path get requests. +- Keep this file-level DOX profile synchronized with `chat_files_path_get.py` because this directory is intentionally flat. + +## Ownership + +- `chat_files_path_get.py` owns the runtime implementation. +- `chat_files_path_get.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `GetChatFilesPath` (`ApiHandler`) + - `async process(self, input: dict, request: Request) -> dict | Response` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `GetChatFilesPath` is an `ApiHandler`. +- `GetChatFilesPath` defines `process(...)`. +- Observed side-effect areas: settings/state persistence. +- Imported dependency areas include: `helpers`, `helpers.api`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `self.use_context`, `projects.get_context_project_name`, `Exception`, `files.normalize_a0_path`, `projects.get_project_folder`, `settings.get_settings`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- No direct test reference was found by name search; choose the nearest behavioral test or perform a focused smoke check. + +## Child DOX Index + +No child DOX files. diff --git a/api/chat_load.py.dox.md b/api/chat_load.py.dox.md new file mode 100644 index 000000000..4718a9fc6 --- /dev/null +++ b/api/chat_load.py.dox.md @@ -0,0 +1,44 @@ +# chat_load.py DOX + +## Purpose + +- Own the `chat_load.py` API endpoint. +- This module handles chat load requests. +- Keep this file-level DOX profile synchronized with `chat_load.py` because this directory is intentionally flat. + +## Ownership + +- `chat_load.py` owns the runtime implementation. +- `chat_load.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `LoadChats` (`ApiHandler`) + - `async process(self, input: Input, request: Request) -> Output` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `LoadChats` is an `ApiHandler`. +- `LoadChats` defines `process(...)`. +- Observed side-effect areas: filesystem writes. +- Imported dependency areas include: `helpers`, `helpers.api`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `persist_chat.load_json_chats`, `Exception`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- No direct test reference was found by name search; choose the nearest behavioral test or perform a focused smoke check. + +## Child DOX Index + +No child DOX files. diff --git a/api/chat_remove.py.dox.md b/api/chat_remove.py.dox.md new file mode 100644 index 000000000..ac1ffc0f8 --- /dev/null +++ b/api/chat_remove.py.dox.md @@ -0,0 +1,44 @@ +# chat_remove.py DOX + +## Purpose + +- Own the `chat_remove.py` API endpoint. +- This module handles chat remove requests. +- Keep this file-level DOX profile synchronized with `chat_remove.py` because this directory is intentionally flat. + +## Ownership + +- `chat_remove.py` owns the runtime implementation. +- `chat_remove.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `RemoveChat` (`ApiHandler`) + - `async process(self, input: Input, request: Request) -> Output` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `RemoveChat` is an `ApiHandler`. +- `RemoveChat` defines `process(...)`. +- Observed side-effect areas: filesystem writes, filesystem deletion, settings/state persistence, scheduler state. +- Imported dependency areas include: `agent`, `helpers`, `helpers.api`, `helpers.task_scheduler`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `scheduler.cancel_tasks_by_context`, `AgentContext.use`, `AgentContext.remove`, `persist_chat.remove_chat`, `scheduler.get_tasks_by_context_id`, `mark_dirty_all`, `context.reset`, `scheduler.reload`, `scheduler.remove_task_by_uuid`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- No direct test reference was found by name search; choose the nearest behavioral test or perform a focused smoke check. + +## Child DOX Index + +No child DOX files. diff --git a/api/chat_reset.py.dox.md b/api/chat_reset.py.dox.md new file mode 100644 index 000000000..39a886a53 --- /dev/null +++ b/api/chat_reset.py.dox.md @@ -0,0 +1,44 @@ +# chat_reset.py DOX + +## Purpose + +- Own the `chat_reset.py` API endpoint. +- This module handles chat reset requests. +- Keep this file-level DOX profile synchronized with `chat_reset.py` because this directory is intentionally flat. + +## Ownership + +- `chat_reset.py` owns the runtime implementation. +- `chat_reset.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `Reset` (`ApiHandler`) + - `async process(self, input: Input, request: Request) -> Output` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `Reset` is an `ApiHandler`. +- `Reset` defines `process(...)`. +- Observed side-effect areas: filesystem writes, filesystem deletion, settings/state persistence, scheduler state. +- Imported dependency areas include: `helpers`, `helpers.api`, `helpers.task_scheduler`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `TaskScheduler.get.cancel_tasks_by_context`, `self.use_context`, `context.reset`, `persist_chat.save_tmp_chat`, `persist_chat.remove_msg_files`, `mark_dirty_all`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- No direct test reference was found by name search; choose the nearest behavioral test or perform a focused smoke check. + +## Child DOX Index + +No child DOX files. diff --git a/api/csrf_token.py b/api/csrf_token.py index 5f4ba13d5..6cbd355c0 100644 --- a/api/csrf_token.py +++ b/api/csrf_token.py @@ -1,5 +1,4 @@ import secrets -from urllib.parse import urlparse from helpers.api import ( ApiHandler, Input, @@ -9,6 +8,7 @@ from helpers.api import ( session, ) from helpers import runtime, dotenv, login +from helpers.tunnel_origins import origin_from_url import fnmatch ALLOWED_ORIGINS_KEY = "ALLOWED_ORIGINS" @@ -82,11 +82,7 @@ class GetCsrfToken(ApiHandler): ) if not r: return None - # parse and normalize - p = urlparse(r) - if not p.scheme or not p.hostname: - return None - return f"{p.scheme}://{p.hostname}" + (f":{p.port}" if p.port else "") + return origin_from_url(r) async def get_allowed_origins(self) -> list[str]: # get the allowed origins from the environment @@ -107,8 +103,10 @@ class GetCsrfToken(ApiHandler): from api.tunnel_proxy import process as tunnel_api_process tunnel = await tunnel_api_process({"action": "get"}) - if tunnel and isinstance(tunnel, dict) and tunnel["success"]: - allowed_origins.append(tunnel["tunnel_url"]) + if tunnel and isinstance(tunnel, dict) and tunnel.get("success"): + tunnel_origin = origin_from_url(tunnel.get("tunnel_url")) + if tunnel_origin: + allowed_origins.append(tunnel_origin) except Exception: pass diff --git a/api/csrf_token.py.dox.md b/api/csrf_token.py.dox.md new file mode 100644 index 000000000..3570d2471 --- /dev/null +++ b/api/csrf_token.py.dox.md @@ -0,0 +1,57 @@ +# csrf_token.py DOX + +## Purpose + +- Own the `csrf_token.py` API endpoint. +- This module issues or refreshes CSRF tokens for browser API clients. +- Keep this file-level DOX profile synchronized with `csrf_token.py` because this directory is intentionally flat. + +## Ownership + +- `csrf_token.py` owns the runtime implementation. +- `csrf_token.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `GetCsrfToken` (`ApiHandler`) + - `get_methods(cls) -> list[str]` + - `requires_csrf(cls) -> bool` + - `async process(self, input: Input, request: Request) -> Output` + - `async check_allowed_origin(self, request: Request)` + - `async is_allowed_origin(self, request: Request)` + - `get_origin_from_request(self, request: Request)` + - `async get_allowed_origins(self) -> list[str]` + - `get_default_allowed_origins(self) -> list[str]` +- Notable constants/configuration names: `ALLOWED_ORIGINS_KEY`. + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `GetCsrfToken` is an `ApiHandler`. +- `GetCsrfToken` defines `process(...)`. +- `GetCsrfToken` defines `get_methods(...)`. +- `GetCsrfToken` defines `requires_csrf(...)`. +- Observed side-effect areas: filesystem writes, network calls, secret handling, tunnel state. +- Imported dependency areas include: `fnmatch`, `helpers`, `helpers.api`, `secrets`, `urllib.parse`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `login.is_login_required`, `self.initialize_allowed_origins`, `self.get_origin_from_request`, `urlparse`, `dotenv.get_dotenv_value`, `self.get_default_allowed_origins`, `dotenv.save_dotenv_value`, `self.check_allowed_origin`, `secrets.token_urlsafe`, `runtime.get_runtime_id`, `self.is_allowed_origin`, `self.get_allowed_origins`, `origin.strip`, `join`, `fnmatch.fnmatch`, `split`, `tunnel_api_process`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- Related tests observed by source search: + - `tests/test_http_auth_csrf.py` + - `tests/test_self_update_tag_filter.py` + - `tests/test_ws_security.py` + +## Child DOX Index + +No child DOX files. diff --git a/api/ctx_window_get.py.dox.md b/api/ctx_window_get.py.dox.md new file mode 100644 index 000000000..2de01bf37 --- /dev/null +++ b/api/ctx_window_get.py.dox.md @@ -0,0 +1,44 @@ +# ctx_window_get.py DOX + +## Purpose + +- Own the `ctx_window_get.py` API endpoint. +- This module handles ctx window get API requests. +- Keep this file-level DOX profile synchronized with `ctx_window_get.py` because this directory is intentionally flat. + +## Ownership + +- `ctx_window_get.py` owns the runtime implementation. +- `ctx_window_get.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `GetCtxWindow` (`ApiHandler`) + - `async process(self, input: Input, request: Request) -> Output` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `GetCtxWindow` is an `ApiHandler`. +- `GetCtxWindow` defines `process(...)`. +- Observed side-effect areas: secret handling. +- Imported dependency areas include: `helpers`, `helpers.api`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `self.use_context`, `agent.get_data`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- No direct test reference was found by name search; choose the nearest behavioral test or perform a focused smoke check. + +## Child DOX Index + +No child DOX files. diff --git a/api/delete_work_dir_file.py.dox.md b/api/delete_work_dir_file.py.dox.md new file mode 100644 index 000000000..536b70fcb --- /dev/null +++ b/api/delete_work_dir_file.py.dox.md @@ -0,0 +1,46 @@ +# delete_work_dir_file.py DOX + +## Purpose + +- Own the `delete_work_dir_file.py` API endpoint. +- This module handles workdir file operations for delete work dir file. +- Keep this file-level DOX profile synchronized with `delete_work_dir_file.py` because this directory is intentionally flat. + +## Ownership + +- `delete_work_dir_file.py` owns the runtime implementation. +- `delete_work_dir_file.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `DeleteWorkDirFile` (`ApiHandler`) + - `async process(self, input: Input, request: Request) -> Output` +- Top-level functions: +- `async delete_file(file_path: str)` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `DeleteWorkDirFile` is an `ApiHandler`. +- `DeleteWorkDirFile` defines `process(...)`. +- Observed side-effect areas: filesystem deletion. +- Imported dependency areas include: `api`, `helpers`, `helpers.api`, `helpers.file_browser`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `FileBrowser`, `browser.delete_file`, `file_path.startswith`, `runtime.call_development_function`, `extension.call_extensions_async`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- No direct test reference was found by name search; choose the nearest behavioral test or perform a focused smoke check. + +## Child DOX Index + +No child DOX files. diff --git a/api/delete_work_dir_files.py.dox.md b/api/delete_work_dir_files.py.dox.md new file mode 100644 index 000000000..2c68d3ca2 --- /dev/null +++ b/api/delete_work_dir_files.py.dox.md @@ -0,0 +1,47 @@ +# delete_work_dir_files.py DOX + +## Purpose + +- Own the `delete_work_dir_files.py` API endpoint. +- This module handles workdir file operations for delete work dir files. +- Keep this file-level DOX profile synchronized with `delete_work_dir_files.py` because this directory is intentionally flat. + +## Ownership + +- `delete_work_dir_files.py` owns the runtime implementation. +- `delete_work_dir_files.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `DeleteWorkDirFiles` (`ApiHandler`) + - `async process(self, input: Input, request: Request) -> Output` +- Top-level functions: +- `async delete_files(paths: list[str]) -> dict` +- `collapse_nested_paths(paths: list[str]) -> list[str]` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `DeleteWorkDirFiles` is an `ApiHandler`. +- `DeleteWorkDirFiles` defines `process(...)`. +- Observed side-effect areas: filesystem deletion. +- Imported dependency areas include: `api`, `api.download_work_dir_files`, `helpers`, `helpers.api`, `helpers.file_browser`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `FileBrowser`, `collapse_nested_paths`, `browser.delete_file`, `normalize_paths`, `runtime.call_development_function`, `path.strip`, `extension.call_extensions_async`, `item.count`, `clean_path.startswith`, `parent.rstrip`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- No direct test reference was found by name search; choose the nearest behavioral test or perform a focused smoke check. + +## Child DOX Index + +No child DOX files. diff --git a/api/download_work_dir_file.py.dox.md b/api/download_work_dir_file.py.dox.md new file mode 100644 index 000000000..87085765a --- /dev/null +++ b/api/download_work_dir_file.py.dox.md @@ -0,0 +1,53 @@ +# download_work_dir_file.py DOX + +## Purpose + +- Own the `download_work_dir_file.py` API endpoint. +- This module handles workdir file operations for download work dir file. +- Keep this file-level DOX profile synchronized with `download_work_dir_file.py` because this directory is intentionally flat. + +## Ownership + +- `download_work_dir_file.py` owns the runtime implementation. +- `download_work_dir_file.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `DownloadFile` (`ApiHandler`) + - `get_methods(cls)` + - `async process(self, input: Input, request: Request) -> Output` +- Top-level functions: +- `stream_file_download(file_source, download_name, chunk_size=...)`: Create a streaming response for file downloads that shows progress in browser. +- `make_disposition(download_name: str) -> str` +- `resolve_download_path(path: str) -> str`: Resolve a requested download path and keep it within the runtime base dir. +- `async fetch_file(path)` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `DownloadFile` is an `ApiHandler`. +- `DownloadFile` defines `process(...)`. +- `DownloadFile` defines `get_methods(...)`. +- Observed side-effect areas: filesystem reads, network calls. +- Imported dependency areas include: `api`, `base64`, `flask`, `helpers`, `helpers.api`, `io`, `mimetypes`, `os`, `pathlib`, `urllib.parse`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `mimetypes.guess_type`, `Response`, `quote`, `Path.resolve`, `Path`, `candidate.is_absolute`, `os.path.getsize`, `generate`, `download_name.encode.decode`, `candidate.resolve`, `resolve`, `resolved.relative_to`, `Exception`, `file.read`, `base64.b64encode.decode`, `file_source.tell`, `file_source.seek`, `ValueError`, `file_path.startswith`, `runtime.call_development_function`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- Related tests observed by source search: + - `tests/test_download_toast_regressions.py` + - `tests/test_office_canvas_setup.py` + +## Child DOX Index + +No child DOX files. diff --git a/api/download_work_dir_files.py.dox.md b/api/download_work_dir_files.py.dox.md new file mode 100644 index 000000000..478669fa8 --- /dev/null +++ b/api/download_work_dir_files.py.dox.md @@ -0,0 +1,54 @@ +# download_work_dir_files.py DOX + +## Purpose + +- Own the `download_work_dir_files.py` API endpoint. +- This module handles workdir file operations for download work dir files. +- Keep this file-level DOX profile synchronized with `download_work_dir_files.py` because this directory is intentionally flat. + +## Ownership + +- `download_work_dir_files.py` owns the runtime implementation. +- `download_work_dir_files.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `DownloadFiles` (`ApiHandler`) + - `async process(self, input: Input, request: Request) -> Output` +- Top-level functions: +- `normalize_paths(paths) -> list[str]` +- `selected_archive_name(count: int) -> str` +- `create_selected_zip(paths: list[str], current_path: str=...) -> str` +- `resolve_download_path(path: str, base_dir: Path) -> Path` +- `collapse_nested_paths(paths: list[Path]) -> list[Path]` +- `archive_root_name(source_path: Path, current_dir: Path | None, base_dir: Path) -> str` +- `unique_archive_name(name: str, used_names: set[str]) -> str` +- `write_zip_entry(zip_file: zipfile.ZipFile, source_path: Path, arc_root: str) -> None` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `DownloadFiles` is an `ApiHandler`. +- `DownloadFiles` defines `process(...)`. +- Observed side-effect areas: filesystem reads, filesystem writes, filesystem deletion. +- Imported dependency areas include: `api.download_work_dir_file`, `base64`, `flask`, `helpers`, `helpers.api`, `helpers.localization`, `io`, `os`, `pathlib`, `tempfile`, `zipfile`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `Localization.get.now.strftime`, `Path.resolve`, `normalize_paths`, `collapse_nested_paths`, `Path`, `os.path.splitext`, `source_path.is_dir`, `zip_file.write`, `selected_archive_name`, `runtime.is_development`, `stream_file_download`, `ValueError`, `raw_path.strip`, `resolve_download_path`, `current_dir.is_file`, `resolved.exists`, `FileNotFoundError`, `tempfile.NamedTemporaryFile`, `zipfile.ZipFile`, `candidate.is_absolute`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- Related tests observed by source search: + - `tests/test_download_toast_regressions.py` + +## Child DOX Index + +No child DOX files. diff --git a/api/edit_work_dir_file.py.dox.md b/api/edit_work_dir_file.py.dox.md new file mode 100644 index 000000000..e5615517b --- /dev/null +++ b/api/edit_work_dir_file.py.dox.md @@ -0,0 +1,50 @@ +# edit_work_dir_file.py DOX + +## Purpose + +- Own the `edit_work_dir_file.py` API endpoint. +- This module handles workdir file operations for edit work dir file. +- Keep this file-level DOX profile synchronized with `edit_work_dir_file.py` because this directory is intentionally flat. + +## Ownership + +- `edit_work_dir_file.py` owns the runtime implementation. +- `edit_work_dir_file.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `EditWorkDirFile` (`ApiHandler`) + - `get_methods(cls)` + - `async process(self, input: Input, request: Request) -> Output` +- Top-level functions: +- `async load_file(file_path: str) -> dict` +- `save_file(file_path: str, content: str) -> bool` +- Notable constants/configuration names: `MAX_EDIT_FILE_SIZE`, `BINARY_SAMPLE_SIZE`. + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `EditWorkDirFile` is an `ApiHandler`. +- `EditWorkDirFile` defines `process(...)`. +- `EditWorkDirFile` defines `get_methods(...)`. +- Observed side-effect areas: filesystem reads, filesystem writes. +- Imported dependency areas include: `helpers`, `helpers.api`, `helpers.file_browser`, `mimetypes`, `os`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `FileBrowser`, `browser.get_full_path`, `os.path.isdir`, `os.path.getsize`, `files.is_probably_binary_file`, `mimetypes.guess_type`, `browser.save_text_file`, `error_str.strip`, `Exception`, `os.path.basename`, `error_str.split`, `file.read`, `line.split.strip`, `file_path.startswith`, `content.encode`, `runtime.call_development_function`, `extension.call_extensions_async`, `self._extract_error_message`, `line.split`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- No direct test reference was found by name search; choose the nearest behavioral test or perform a focused smoke check. + +## Child DOX Index + +No child DOX files. diff --git a/api/file_info.py.dox.md b/api/file_info.py.dox.md new file mode 100644 index 000000000..e3612589d --- /dev/null +++ b/api/file_info.py.dox.md @@ -0,0 +1,47 @@ +# file_info.py DOX + +## Purpose + +- Own the `file_info.py` API endpoint. +- This module handles file info API requests. +- Keep this file-level DOX profile synchronized with `file_info.py` because this directory is intentionally flat. + +## Ownership + +- `file_info.py` owns the runtime implementation. +- `file_info.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `FileInfoApi` (`ApiHandler`) + - `async process(self, input: Input, request: Request) -> Output` +- `FileInfo` (`TypedDict`) +- Top-level functions: +- `async get_file_info(path: str) -> FileInfo` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `FileInfoApi` is an `ApiHandler`. +- `FileInfoApi` defines `process(...)`. +- Observed side-effect areas: filesystem reads. +- Imported dependency areas include: `helpers`, `helpers.api`, `os`, `typing`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `files.get_abs_path`, `os.path.exists`, `os.path.dirname`, `os.path.basename`, `runtime.call_development_function`, `os.path.isdir`, `os.path.isfile`, `os.path.islink`, `os.path.getsize`, `os.path.getmtime`, `os.path.getctime`, `os.path.splitext`, `os.stat`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- No direct test reference was found by name search; choose the nearest behavioral test or perform a focused smoke check. + +## Child DOX Index + +No child DOX files. diff --git a/api/get_work_dir_files.py b/api/get_work_dir_files.py index 7e8e99c7f..68aee4990 100644 --- a/api/get_work_dir_files.py +++ b/api/get_work_dir_files.py @@ -9,7 +9,7 @@ class GetWorkDirFiles(ApiHandler): return ["GET"] async def process(self, input: dict, request: Request) -> dict | Response: - current_path = request.args.get("path", "") + current_path = request.args.get("path", "") or "$WORK_DIR" if current_path == "$WORK_DIR": # if runtime.is_development(): # current_path = "work_dir" diff --git a/api/get_work_dir_files.py.dox.md b/api/get_work_dir_files.py.dox.md new file mode 100644 index 000000000..f5ff3e005 --- /dev/null +++ b/api/get_work_dir_files.py.dox.md @@ -0,0 +1,48 @@ +# get_work_dir_files.py DOX + +## Purpose + +- Own the `get_work_dir_files.py` API endpoint. +- This module handles workdir file operations for get work dir files. +- Keep this file-level DOX profile synchronized with `get_work_dir_files.py` because this directory is intentionally flat. + +## Ownership + +- `get_work_dir_files.py` owns the runtime implementation. +- `get_work_dir_files.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `GetWorkDirFiles` (`ApiHandler`) + - `get_methods(cls)` + - `async process(self, input: dict, request: Request) -> dict | Response` +- Top-level functions: +- `async get_files(path)` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `GetWorkDirFiles` is an `ApiHandler`. +- `GetWorkDirFiles` defines `process(...)`. +- `GetWorkDirFiles` defines `get_methods(...)`. +- Imported dependency areas include: `helpers`, `helpers.api`, `helpers.file_browser`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `FileBrowser`, `browser.get_files`, `runtime.call_development_function`. +- Empty `path` requests and explicit `$WORK_DIR` requests resolve to the default workdir path before `FileBrowser` is called, so the WebUI never receives an empty startup path for the default file browser view. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- No direct test reference was found by name search; choose the nearest behavioral test or perform a focused smoke check. + +## Child DOX Index + +No child DOX files. diff --git a/api/health.py.dox.md b/api/health.py.dox.md new file mode 100644 index 000000000..236812f56 --- /dev/null +++ b/api/health.py.dox.md @@ -0,0 +1,52 @@ +# health.py DOX + +## Purpose + +- Own the `health.py` API endpoint. +- This module reports process health for probes and startup checks. +- Keep this file-level DOX profile synchronized with `health.py` because this directory is intentionally flat. + +## Ownership + +- `health.py` owns the runtime implementation. +- `health.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `HealthCheck` (`ApiHandler`) + - `requires_auth(cls) -> bool` + - `requires_csrf(cls) -> bool` + - `get_methods(cls) -> list[str]` + - `async process(self, input: dict, request: Request) -> dict | Response` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `HealthCheck` is an `ApiHandler`. +- `HealthCheck` defines `process(...)`. +- `HealthCheck` defines `get_methods(...)`. +- `HealthCheck` defines `requires_auth(...)`. +- `HealthCheck` defines `requires_csrf(...)`. +- Imported dependency areas include: `helpers`, `helpers.api`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `git.get_git_info`, `errors.error_text`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- Related tests observed by source search: + - `tests/test_oauth_providers.py` + - `tests/test_office_document_store.py` + - `tests/test_self_update_tag_filter.py` + +## Child DOX Index + +No child DOX files. diff --git a/api/history_get.py.dox.md b/api/history_get.py.dox.md new file mode 100644 index 000000000..8f2f1ddca --- /dev/null +++ b/api/history_get.py.dox.md @@ -0,0 +1,44 @@ +# history_get.py DOX + +## Purpose + +- Own the `history_get.py` API endpoint. +- This module handles history get API requests. +- Keep this file-level DOX profile synchronized with `history_get.py` because this directory is intentionally flat. + +## Ownership + +- `history_get.py` owns the runtime implementation. +- `history_get.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `GetHistory` (`ApiHandler`) + - `async process(self, input: dict, request: Request) -> dict | Response` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `GetHistory` is an `ApiHandler`. +- `GetHistory` defines `process(...)`. +- Observed side-effect areas: secret handling. +- Imported dependency areas include: `helpers.api`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `self.use_context`, `agent.history.output_text`, `agent.history.get_tokens`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- No direct test reference was found by name search; choose the nearest behavioral test or perform a focused smoke check. + +## Child DOX Index + +No child DOX files. diff --git a/api/image_get.py.dox.md b/api/image_get.py.dox.md new file mode 100644 index 000000000..b9b0da35b --- /dev/null +++ b/api/image_get.py.dox.md @@ -0,0 +1,53 @@ +# image_get.py DOX + +## Purpose + +- Own the `image_get.py` API endpoint. +- This module serves allowed image references and fallback file-type icons. +- Keep this file-level DOX profile synchronized with `image_get.py` because this directory is intentionally flat. + +## Ownership + +- `image_get.py` owns the runtime implementation. +- `image_get.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `ImageGet` (`ApiHandler`) + - `get_methods(cls) -> list[str]` + - `async process(self, input: dict, request: Request) -> dict | Response` +- Top-level functions: +- `_resolve_allowed_image_path(path: str) -> str`: Resolve a requested image path and keep it inside Agent Zero's base dir. +- `_set_image_headers(response: Response, filename: str, file_ext: str) -> None` +- `_send_file_type_icon(file_ext, filename=...)`: Return appropriate icon for file type +- `_send_fallback_icon(icon_name)`: Return fallback icon from public directory +- Notable constants/configuration names: `IMAGE_EXTENSIONS`, `SVG_EXTENSIONS`, `SVG_CONTENT_SECURITY_POLICY`. + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `ImageGet` is an `ApiHandler`. +- `ImageGet` defines `process(...)`. +- `ImageGet` defines `get_methods(...)`. +- Observed side-effect areas: filesystem reads, network calls, subprocess/runtime control, settings/state persistence. +- Imported dependency areas include: `base64`, `helpers`, `helpers.api`, `io`, `mimetypes`, `os`, `pathlib`, `urllib.parse`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `runtime.is_development`, `Path.resolve`, `candidate.resolve`, `quote`, `_send_fallback_icon`, `files.get_abs_path`, `send_file`, `os.path.splitext.lower`, `os.path.basename`, `Path`, `candidate.is_absolute`, `resolved.relative_to`, `os.path.exists`, `ValueError`, `_set_image_headers`, `_send_file_type_icon`, `files.fix_dev_path`, `_resolve_allowed_image_path`, `files.exists`, `files.get_base_dir`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- Related tests observed by source search: + - `tests/test_image_get_security.py` + +## Child DOX Index + +No child DOX files. diff --git a/api/load_webui_extensions.py.dox.md b/api/load_webui_extensions.py.dox.md new file mode 100644 index 000000000..c2d41e06a --- /dev/null +++ b/api/load_webui_extensions.py.dox.md @@ -0,0 +1,44 @@ +# load_webui_extensions.py DOX + +## Purpose + +- Own the `load_webui_extensions.py` API endpoint. +- This module returns frontend extension manifests/files for a WebUI extension point. +- Keep this file-level DOX profile synchronized with `load_webui_extensions.py` because this directory is intentionally flat. + +## Ownership + +- `load_webui_extensions.py` owns the runtime implementation. +- `load_webui_extensions.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `LoadWebuiExtensions` (`ApiHandler`) + - `async process(self, input: dict, request: Request) -> dict | Response` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `LoadWebuiExtensions` is an `ApiHandler`. +- `LoadWebuiExtensions` defines `process(...)`. +- Imported dependency areas include: `helpers`, `helpers.api`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `extension.get_webui_extensions`, `Response`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- Related tests observed by source search: + - `tests/test_webui_extension_surfaces.py` + +## Child DOX Index + +No child DOX files. diff --git a/api/logout.py.dox.md b/api/logout.py.dox.md new file mode 100644 index 000000000..e125a43e7 --- /dev/null +++ b/api/logout.py.dox.md @@ -0,0 +1,47 @@ +# logout.py DOX + +## Purpose + +- Own the `logout.py` API endpoint. +- This module clears login/session state for the current client. +- Keep this file-level DOX profile synchronized with `logout.py` because this directory is intentionally flat. + +## Ownership + +- `logout.py` owns the runtime implementation. +- `logout.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `ApiLogout` (`ApiHandler`) + - `requires_auth(cls) -> bool` + - `async process(self, input: dict, request: Request) -> dict` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `ApiLogout` is an `ApiHandler`. +- `ApiLogout` defines `process(...)`. +- `ApiLogout` defines `requires_auth(...)`. +- Observed side-effect areas: secret handling. +- Imported dependency areas include: `helpers.api`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `session.clear`, `session.pop`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- Related tests observed by source search: + - `tests/test_office_document_store.py` + +## Child DOX Index + +No child DOX files. diff --git a/api/mcp_server_get_detail.py b/api/mcp_server_get_detail.py index bc5552c4d..25f865a41 100644 --- a/api/mcp_server_get_detail.py +++ b/api/mcp_server_get_detail.py @@ -9,9 +9,11 @@ class McpServerGetDetail(ApiHandler): # try: server_name = input.get("server_name") + project_name = str(input.get("project_name", "") or "").strip() if not server_name: return {"success": False, "error": "Missing server_name"} - detail = MCPConfig.get_instance().get_server_detail(server_name) + config = MCPConfig.get_project_instance(project_name) if project_name else MCPConfig.get_instance() + detail = config.get_server_detail(server_name) return {"success": True, "detail": detail} # except Exception as e: # return {"success": False, "error": str(e)} diff --git a/api/mcp_server_get_detail.py.dox.md b/api/mcp_server_get_detail.py.dox.md new file mode 100644 index 000000000..d71ed2551 --- /dev/null +++ b/api/mcp_server_get_detail.py.dox.md @@ -0,0 +1,45 @@ +# mcp_server_get_detail.py DOX + +## Purpose + +- Own the `mcp_server_get_detail.py` API endpoint. +- This module handles MCP server detail requests for global or project scope. +- Keep this file-level DOX profile synchronized with `mcp_server_get_detail.py` because this directory is intentionally flat. + +## Ownership + +- `mcp_server_get_detail.py` owns the runtime implementation. +- `mcp_server_get_detail.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `McpServerGetDetail` (`ApiHandler`) + - `async process(self, input: dict[Any, Any], request: Request) -> dict[Any, Any] | Response` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- The request accepts `server_name` and optional `project_name`; when `project_name` is present, detail resolves through the project-scoped MCP configuration. +- Detail responses include the server tools visible to the manager UI. Tools disabled through a server `disabled_tools` config list remain present in this detail list with a `disabled` flag so the UI can re-enable them. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `McpServerGetDetail` is an `ApiHandler`. +- `McpServerGetDetail` defines `process(...)`. +- Imported dependency areas include: `helpers.api`, `helpers.mcp_handler`, `typing`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `MCPConfig.get_instance.get_server_detail`, `MCPConfig.get_project_instance`, `MCPConfig.get_instance`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- No direct test reference was found by name search; choose the nearest behavioral test or perform a focused smoke check. + +## Child DOX Index + +No child DOX files. diff --git a/api/mcp_server_get_log.py b/api/mcp_server_get_log.py index 3305430ea..89b53b58f 100644 --- a/api/mcp_server_get_log.py +++ b/api/mcp_server_get_log.py @@ -9,9 +9,11 @@ class McpServerGetLog(ApiHandler): # try: server_name = input.get("server_name") + project_name = str(input.get("project_name", "") or "").strip() if not server_name: return {"success": False, "error": "Missing server_name"} - log = MCPConfig.get_instance().get_server_log(server_name) + config = MCPConfig.get_project_instance(project_name) if project_name else MCPConfig.get_instance() + log = config.get_server_log(server_name) return {"success": True, "log": log} # except Exception as e: # return {"success": False, "error": str(e)} diff --git a/api/mcp_server_get_log.py.dox.md b/api/mcp_server_get_log.py.dox.md new file mode 100644 index 000000000..0937274a4 --- /dev/null +++ b/api/mcp_server_get_log.py.dox.md @@ -0,0 +1,44 @@ +# mcp_server_get_log.py DOX + +## Purpose + +- Own the `mcp_server_get_log.py` API endpoint. +- This module handles MCP server log requests for global or project scope. +- Keep this file-level DOX profile synchronized with `mcp_server_get_log.py` because this directory is intentionally flat. + +## Ownership + +- `mcp_server_get_log.py` owns the runtime implementation. +- `mcp_server_get_log.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `McpServerGetLog` (`ApiHandler`) + - `async process(self, input: dict[Any, Any], request: Request) -> dict[Any, Any] | Response` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- The request accepts `server_name` and optional `project_name`; when `project_name` is present, logs resolve through the project-scoped MCP configuration. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `McpServerGetLog` is an `ApiHandler`. +- `McpServerGetLog` defines `process(...)`. +- Imported dependency areas include: `helpers.api`, `helpers.mcp_handler`, `typing`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `MCPConfig.get_instance.get_server_log`, `MCPConfig.get_project_instance`, `MCPConfig.get_instance`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- No direct test reference was found by name search; choose the nearest behavioral test or perform a focused smoke check. + +## Child DOX Index + +No child DOX files. diff --git a/api/mcp_server_scan.py b/api/mcp_server_scan.py new file mode 100644 index 000000000..4639426d3 --- /dev/null +++ b/api/mcp_server_scan.py @@ -0,0 +1,232 @@ +import asyncio +from shutil import which +from typing import Any +from urllib.parse import urlparse + +from helpers.api import ApiHandler, Request, Response +from helpers.mcp_handler import MCPConfig, normalize_name + + +_PROMPT_INJECTION_MARKERS = ( + "ignore previous", + "ignore all previous", + "system prompt", + "developer message", + "hidden instruction", + "exfiltrate", + "leak secret", + "credential", +) + + +class McpServerScan(ApiHandler): + async def process(self, input: dict[Any, Any], request: Request) -> dict[Any, Any] | Response: + server = dict(input.get("server") or {}) + allow_local_execution = bool(input.get("allow_local_execution", False)) + allow_remote_network = bool(input.get("allow_remote_network", False)) + inspect_runtime = input.get("inspect_runtime", True) is not False + + server = self._normalize_server(server) + warnings = self._static_warnings(server) + is_local = not (server.get("url") or server.get("serverUrl")) + has_static_errors = any(warning.get("level") == "error" for warning in warnings) + + runtime_status: list[dict[str, Any]] = [] + runtime_detail: dict[str, Any] = {} + runtime_error = "" + + should_inspect_runtime = ( + inspect_runtime + and not has_static_errors + and ((is_local and allow_local_execution) or (not is_local and allow_remote_network)) + ) + + if should_inspect_runtime: + try: + scan_config = await asyncio.to_thread( + lambda: MCPConfig(servers_list=[server], config_scope="scan") + ) + runtime_status = scan_config.get_servers_status() + runtime_detail = scan_config.get_server_detail(server.get("name", "")) + warnings.extend(self._tool_warnings(runtime_detail.get("tools", []))) + except Exception as exc: + runtime_error = str(exc) + warnings.append( + { + "level": "error", + "title": "Runtime inspection failed", + "message": runtime_error, + } + ) + elif is_local and inspect_runtime: + warnings.append( + { + "level": "warning", + "title": "Local command not executed", + "message": "Local stdio MCP inspection requires explicit trust because it runs the configured command.", + } + ) + elif not is_local and inspect_runtime and has_static_errors: + warnings.append( + { + "level": "info", + "title": "Runtime inspection skipped", + "message": "Fix static scan errors before attempting runtime MCP inspection.", + } + ) + elif not is_local and inspect_runtime: + warnings.append( + { + "level": "info", + "title": "Remote runtime inspection skipped", + "message": "Enable trusted remote inspection to contact the MCP URL and list exposed tools.", + } + ) + + return { + "success": True, + "server": self._redact_server(server), + "risk_level": self._risk_level(warnings), + "warnings": warnings, + "status": runtime_status, + "detail": runtime_detail, + "runtime_error": runtime_error, + } + + def _normalize_server(self, server: dict[str, Any]) -> dict[str, Any]: + name = str(server.get("name") or "").strip() + url = str(server.get("url") or server.get("serverUrl") or "").strip() + command = str(server.get("command") or "").strip() + + if not name: + name = self._derive_name(url, command) + server["name"] = normalize_name(name or "mcp_server") + + if url: + server["url"] = url + server.setdefault("type", "streamable-http") + elif command: + server["command"] = command + server["type"] = "stdio" + + return server + + def _derive_name(self, url: str, command: str) -> str: + if url: + parsed = urlparse(url) + parts = [part for part in parsed.path.split("/") if part] + return parts[-1] if parts else parsed.hostname or "remote_mcp" + if command: + return command.rsplit("/", 1)[-1] + return "mcp_server" + + def _static_warnings(self, server: dict[str, Any]) -> list[dict[str, str]]: + warnings: list[dict[str, str]] = [] + url = str(server.get("url") or "").strip() + command = str(server.get("command") or "").strip() + + if url: + parsed = urlparse(url) + if parsed.scheme not in {"http", "https"}: + warnings.append( + { + "level": "error", + "title": "Unsupported URL scheme", + "message": "Remote MCP URLs should use http or https.", + } + ) + elif parsed.scheme == "http" and parsed.hostname not in {"localhost", "127.0.0.1", "::1"}: + warnings.append( + { + "level": "warning", + "title": "Unencrypted remote URL", + "message": "Prefer HTTPS for remote MCP servers outside localhost.", + } + ) + if not parsed.netloc: + warnings.append( + { + "level": "error", + "title": "Invalid remote URL", + "message": "The remote MCP URL is missing a host.", + } + ) + elif command: + if which(command) is None: + warnings.append( + { + "level": "warning", + "title": "Command not found", + "message": f"'{command}' is not currently available on PATH.", + } + ) + if command in {"bash", "sh", "zsh", "fish", "python", "python3", "node"}: + warnings.append( + { + "level": "warning", + "title": "General-purpose interpreter", + "message": "Review the command and arguments carefully before running this local MCP server.", + } + ) + else: + warnings.append( + { + "level": "error", + "title": "Missing connection target", + "message": "Provide either a remote URL or a local command.", + } + ) + + if isinstance(server.get("headers"), dict) and server["headers"]: + warnings.append( + { + "level": "info", + "title": "Headers configured", + "message": "Header values are redacted in scan output. Keep tokens in trusted settings only.", + } + ) + + if isinstance(server.get("env"), dict) and server["env"]: + warnings.append( + { + "level": "info", + "title": "Environment configured", + "message": "Environment values are redacted in scan output. Avoid hardcoding secrets in MCP configs.", + } + ) + + return warnings + + def _tool_warnings(self, tools: Any) -> list[dict[str, str]]: + warnings: list[dict[str, str]] = [] + if not isinstance(tools, list): + return warnings + + for tool in tools: + if not isinstance(tool, dict): + continue + haystack = f"{tool.get('name', '')}\n{tool.get('description', '')}".lower() + if any(marker in haystack for marker in _PROMPT_INJECTION_MARKERS): + warnings.append( + { + "level": "warning", + "title": "Suspicious tool description", + "message": f"Review tool '{tool.get('name', 'unknown')}' for prompt-injection style language.", + } + ) + return warnings + + def _redact_server(self, server: dict[str, Any]) -> dict[str, Any]: + redacted = dict(server) + for key in ("headers", "env"): + if isinstance(redacted.get(key), dict): + redacted[key] = {name: "***" for name in redacted[key]} + return redacted + + def _risk_level(self, warnings: list[dict[str, str]]) -> str: + levels = {warning.get("level", "info") for warning in warnings} + if "error" in levels: + return "error" + if "warning" in levels: + return "warning" + return "ok" diff --git a/api/mcp_server_scan.py.dox.md b/api/mcp_server_scan.py.dox.md new file mode 100644 index 000000000..5487106aa --- /dev/null +++ b/api/mcp_server_scan.py.dox.md @@ -0,0 +1,45 @@ +# mcp_server_scan.py DOX + +## Purpose + +- Own the `mcp_server_scan.py` API endpoint. +- Provide static and optional runtime inspection for a single MCP server draft before it is added to global or project MCP config. +- Keep this file-level DOX profile synchronized with `mcp_server_scan.py` because this directory is intentionally flat. + +## Ownership + +- `mcp_server_scan.py` owns the runtime implementation. +- `mcp_server_scan.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `McpServerScan` (`ApiHandler`) + - `async process(self, input: dict[Any, Any], request: Request) -> dict[Any, Any] | Response` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- The request accepts a `server` draft object, `inspect_runtime`, `allow_remote_network`, and `allow_local_execution`. +- Remote runtime inspection may contact the configured MCP URL to list tools only when `allow_remote_network` is true and static checks have no errors. +- Local stdio runtime inspection must not execute unless `allow_local_execution` is true. +- Response data redacts `headers` and `env` values. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- Imported dependency areas include: `asyncio`, `helpers.api`, `helpers.mcp_handler`, `shutil`, `typing`, `urllib.parse`. + +## Key Concepts + +- Static checks report invalid URLs, non-HTTPS remote URLs, missing local commands, interpreter-style local commands, headers/env presence, and obvious prompt-injection markers in inspected tool descriptions. +- Static errors skip runtime inspection; remote network inspection and local command execution both require explicit trust flags. +- Runtime inspection creates a temporary `MCPConfig` in a worker thread so stdio/remote tool listing does not call `asyncio.run()` inside the request event loop. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Do not return secret values, raw environment values, or private files. +- Keep scanner warnings explicit about local command execution risk. + +## Verification + +- Run endpoint-specific or MCP helper tests for changed behavior; smoke-test remote URL and local-command scan paths when practical. + +## Child DOX Index + +No child DOX files. diff --git a/api/mcp_servers_apply.py b/api/mcp_servers_apply.py index 7ea5275db..36877807a 100644 --- a/api/mcp_servers_apply.py +++ b/api/mcp_servers_apply.py @@ -5,20 +5,27 @@ from typing import Any from helpers.mcp_handler import MCPConfig from helpers.settings import set_settings_delta +from helpers import projects class McpServersApply(ApiHandler): async def process(self, input: dict[Any, Any], request: Request) -> dict[Any, Any] | Response: mcp_servers = input["mcp_servers"] + project_name = str(input.get("project_name", "") or "").strip() try: - # MCPConfig.update(mcp_servers) # done in settings automatically - set_settings_delta({"mcp_servers": "[]"}) # to force reinitialization - set_settings_delta({"mcp_servers": mcp_servers}) + if project_name: + projects.save_project_mcp_servers(project_name, mcp_servers) + config = MCPConfig.refresh_project(project_name) + else: + # MCPConfig.update(mcp_servers) # done in settings automatically + set_settings_delta({"mcp_servers": "[]"}) # to force reinitialization + set_settings_delta({"mcp_servers": mcp_servers}) - time.sleep(1) # wait at least a second - # MCPConfig.wait_for_lock() # wait until config lock is released - status = MCPConfig.get_instance().get_servers_status() - return {"success": True, "status": status} + time.sleep(1) # wait at least a second + # MCPConfig.wait_for_lock() # wait until config lock is released + config = MCPConfig.get_instance() + status = config.get_servers_status() + return {"success": True, "status": status, "mcp_servers": mcp_servers, "project_name": project_name} except Exception as e: return {"success": False, "error": str(e)} diff --git a/api/mcp_servers_apply.py.dox.md b/api/mcp_servers_apply.py.dox.md new file mode 100644 index 000000000..361c331b2 --- /dev/null +++ b/api/mcp_servers_apply.py.dox.md @@ -0,0 +1,47 @@ +# mcp_servers_apply.py DOX + +## Purpose + +- Own the `mcp_servers_apply.py` API endpoint. +- This module handles MCP servers apply requests for global or project scope. +- Keep this file-level DOX profile synchronized with `mcp_servers_apply.py` because this directory is intentionally flat. + +## Ownership + +- `mcp_servers_apply.py` owns the runtime implementation. +- `mcp_servers_apply.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `McpServersApply` (`ApiHandler`) + - `async process(self, input: dict[Any, Any], request: Request) -> dict[Any, Any] | Response` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- The request accepts `config` and optional `project_name`. +- Without `project_name`, the endpoint persists global `mcp_servers_config` through settings and refreshes the global `MCPConfig`. +- With `project_name`, the endpoint saves `.a0proj/mcp_servers.json` through `helpers.projects.save_project_mcp_servers(...)` and refreshes that project's merged MCP config. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `McpServersApply` is an `ApiHandler`. +- `McpServersApply` defines `process(...)`. +- Observed side-effect areas: filesystem writes, settings/state persistence. +- Imported dependency areas include: `helpers.api`, `helpers.mcp_handler`, `helpers.projects`, `helpers.settings`, `time`, `typing`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `set_settings_delta`, `projects.save_project_mcp_servers`, `MCPConfig.refresh_project`, `time.sleep`, `MCPConfig.get_instance.get_servers_status`, `MCPConfig.get_instance`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- No direct test reference was found by name search; choose the nearest behavioral test or perform a focused smoke check. + +## Child DOX Index + +No child DOX files. diff --git a/api/mcp_servers_status.py b/api/mcp_servers_status.py index 20f8a64c8..01afff421 100644 --- a/api/mcp_servers_status.py +++ b/api/mcp_servers_status.py @@ -9,7 +9,9 @@ class McpServersStatuss(ApiHandler): async def process(self, input: dict[Any, Any], request: Request) -> dict[Any, Any] | Response: # try: - status = MCPConfig.get_instance().get_servers_status() + project_name = (input or {}).get("project_name") if isinstance(input, dict) else None + config = MCPConfig.get_project_instance(project_name) if project_name else MCPConfig.get_instance() + status = config.get_servers_status() return {"success": True, "status": status} # except Exception as e: # return {"success": False, "error": str(e)} diff --git a/api/mcp_servers_status.py.dox.md b/api/mcp_servers_status.py.dox.md new file mode 100644 index 000000000..90b4065be --- /dev/null +++ b/api/mcp_servers_status.py.dox.md @@ -0,0 +1,45 @@ +# mcp_servers_status.py DOX + +## Purpose + +- Own the `mcp_servers_status.py` API endpoint. +- This module handles MCP servers status requests for global or project scope. +- Keep this file-level DOX profile synchronized with `mcp_servers_status.py` because this directory is intentionally flat. + +## Ownership + +- `mcp_servers_status.py` owns the runtime implementation. +- `mcp_servers_status.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `McpServersStatuss` (`ApiHandler`) + - `async process(self, input: dict[Any, Any], request: Request) -> dict[Any, Any] | Response` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- The request accepts optional `project_name`; when present, status resolves through the merged project-scoped MCP configuration. +- `tool_count` reports enabled MCP tools only; tools disabled by a server `disabled_tools` list stay hidden from agent-facing status counts. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `McpServersStatuss` is an `ApiHandler`. +- `McpServersStatuss` defines `process(...)`. +- Imported dependency areas include: `helpers.api`, `helpers.mcp_handler`, `typing`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `MCPConfig.get_instance.get_servers_status`, `MCPConfig.get_project_instance`, `MCPConfig.get_instance`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- No direct test reference was found by name search; choose the nearest behavioral test or perform a focused smoke check. + +## Child DOX Index + +No child DOX files. diff --git a/api/message.py.dox.md b/api/message.py.dox.md new file mode 100644 index 000000000..9ec63fc71 --- /dev/null +++ b/api/message.py.dox.md @@ -0,0 +1,54 @@ +# message.py DOX + +## Purpose + +- Own the `message.py` API endpoint. +- This module submits a user message and runs agent processing synchronously through the UI API. +- Keep this file-level DOX profile synchronized with `message.py` because this directory is intentionally flat. + +## Ownership + +- `message.py` owns the runtime implementation. +- `message.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `Message` (`ApiHandler`) + - `async process(self, input: dict, request: Request) -> dict | Response` + - `async respond(self, task: DeferredTask, context: AgentContext)` + - `async communicate(self, input: dict, request: Request)` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `Message` is an `ApiHandler`. +- `Message` defines `process(...)`. +- Observed side-effect areas: filesystem reads, filesystem writes, settings/state persistence, scheduler state. +- Imported dependency areas include: `agent`, `helpers`, `helpers.api`, `helpers.defer`, `helpers.security`, `os`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `request.content_type.startswith`, `self.use_context`, `mq.log_user_message`, `self.communicate`, `self.respond`, `task.result`, `request.files.getlist`, `files.get_abs_path`, `request.get_json`, `extension.call_extensions_async`, `context.communicate`, `os.makedirs`, `UserMessage`, `safe_filename`, `attachment.save`, `context.get_agent`, `os.path.join`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- Related tests observed by source search: + - `tests/email_parser_test.py` + - `tests/rate_limiter_test.py` + - `tests/test_api_chat_lifetime.py` + - `tests/test_browser_agent_regressions.py` + - `tests/test_chat_compaction.py` + - `tests/test_docker_release_plan.py` + - `tests/test_document_query_fallback.py` + - `tests/test_download_toast_regressions.py` + +## Child DOX Index + +No child DOX files. diff --git a/api/message_async.py.dox.md b/api/message_async.py.dox.md new file mode 100644 index 000000000..6a6ba0093 --- /dev/null +++ b/api/message_async.py.dox.md @@ -0,0 +1,42 @@ +# message_async.py DOX + +## Purpose + +- Own the `message_async.py` API endpoint. +- This module submits a user message for asynchronous agent processing. +- Keep this file-level DOX profile synchronized with `message_async.py` because this directory is intentionally flat. + +## Ownership + +- `message_async.py` owns the runtime implementation. +- `message_async.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `MessageAsync` (`Message`) + - `async respond(self, task: DeferredTask, context: AgentContext)` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- Observed side-effect areas: scheduler state. +- Imported dependency areas include: `agent`, `api.message`, `helpers.defer`. + +## Key Concepts + +- This module is primarily declarative or delegates behavior through classes/imported objects. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- No direct test reference was found by name search; choose the nearest behavioral test or perform a focused smoke check. + +## Child DOX Index + +No child DOX files. diff --git a/api/message_queue_add.py.dox.md b/api/message_queue_add.py.dox.md new file mode 100644 index 000000000..f727a70f1 --- /dev/null +++ b/api/message_queue_add.py.dox.md @@ -0,0 +1,44 @@ +# message_queue_add.py DOX + +## Purpose + +- Own the `message_queue_add.py` API endpoint. +- This module handles message queue add API requests. +- Keep this file-level DOX profile synchronized with `message_queue_add.py` because this directory is intentionally flat. + +## Ownership + +- `message_queue_add.py` owns the runtime implementation. +- `message_queue_add.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `MessageQueueAdd` (`ApiHandler`) + - `async process(self, input: dict, request: Request) -> dict | Response` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `MessageQueueAdd` is an `ApiHandler`. +- `MessageQueueAdd` defines `process(...)`. +- Observed side-effect areas: settings/state persistence. +- Imported dependency areas include: `agent`, `helpers`, `helpers.api`, `helpers.state_monitor_integration`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `input.get.strip`, `mq.add`, `mark_dirty_for_context`, `Response`, `mq.get_queue`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- No direct test reference was found by name search; choose the nearest behavioral test or perform a focused smoke check. + +## Child DOX Index + +No child DOX files. diff --git a/api/message_queue_remove.py.dox.md b/api/message_queue_remove.py.dox.md new file mode 100644 index 000000000..8bf876b05 --- /dev/null +++ b/api/message_queue_remove.py.dox.md @@ -0,0 +1,44 @@ +# message_queue_remove.py DOX + +## Purpose + +- Own the `message_queue_remove.py` API endpoint. +- This module handles message queue remove API requests. +- Keep this file-level DOX profile synchronized with `message_queue_remove.py` because this directory is intentionally flat. + +## Ownership + +- `message_queue_remove.py` owns the runtime implementation. +- `message_queue_remove.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `MessageQueueRemove` (`ApiHandler`) + - `async process(self, input: dict, request: Request) -> dict | Response` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `MessageQueueRemove` is an `ApiHandler`. +- `MessageQueueRemove` defines `process(...)`. +- Observed side-effect areas: filesystem deletion, settings/state persistence. +- Imported dependency areas include: `agent`, `helpers`, `helpers.api`, `helpers.state_monitor_integration`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `mq.remove`, `mark_dirty_for_context`, `Response`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- No direct test reference was found by name search; choose the nearest behavioral test or perform a focused smoke check. + +## Child DOX Index + +No child DOX files. diff --git a/api/message_queue_send.py.dox.md b/api/message_queue_send.py.dox.md new file mode 100644 index 000000000..4f7294a94 --- /dev/null +++ b/api/message_queue_send.py.dox.md @@ -0,0 +1,44 @@ +# message_queue_send.py DOX + +## Purpose + +- Own the `message_queue_send.py` API endpoint. +- This module handles message queue send API requests. +- Keep this file-level DOX profile synchronized with `message_queue_send.py` because this directory is intentionally flat. + +## Ownership + +- `message_queue_send.py` owns the runtime implementation. +- `message_queue_send.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `MessageQueueSend` (`ApiHandler`) + - `async process(self, input: dict, request: Request) -> dict | Response` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `MessageQueueSend` is an `ApiHandler`. +- `MessageQueueSend` defines `process(...)`. +- Observed side-effect areas: settings/state persistence. +- Imported dependency areas include: `agent`, `helpers`, `helpers.api`, `helpers.state_monitor_integration`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `mq.send_message`, `mark_dirty_for_context`, `Response`, `mq.has_queue`, `mq.send_all_aggregated`, `mq.pop_item`, `mq.pop_first`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- No direct test reference was found by name search; choose the nearest behavioral test or perform a focused smoke check. + +## Child DOX Index + +No child DOX files. diff --git a/api/notification_create.py.dox.md b/api/notification_create.py.dox.md new file mode 100644 index 000000000..a83b82cf4 --- /dev/null +++ b/api/notification_create.py.dox.md @@ -0,0 +1,46 @@ +# notification_create.py DOX + +## Purpose + +- Own the `notification_create.py` API endpoint. +- This module handles notification notification create requests. +- Keep this file-level DOX profile synchronized with `notification_create.py` because this directory is intentionally flat. + +## Ownership + +- `notification_create.py` owns the runtime implementation. +- `notification_create.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `NotificationCreate` (`ApiHandler`) + - `requires_auth(cls) -> bool` + - `async process(self, input: dict, request: Request) -> dict | Response` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `NotificationCreate` is an `ApiHandler`. +- `NotificationCreate` defines `process(...)`. +- `NotificationCreate` defines `requires_auth(...)`. +- Imported dependency areas include: `flask`, `helpers.api`, `helpers.notification`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `NotificationManager.send_notification`, `NotificationType`, `notification.output`, `notification_type.lower`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- Related tests observed by source search: + - `tests/test_download_toast_regressions.py` + +## Child DOX Index + +No child DOX files. diff --git a/api/notifications_clear.py.dox.md b/api/notifications_clear.py.dox.md new file mode 100644 index 000000000..dc5503b73 --- /dev/null +++ b/api/notifications_clear.py.dox.md @@ -0,0 +1,45 @@ +# notifications_clear.py DOX + +## Purpose + +- Own the `notifications_clear.py` API endpoint. +- This module handles notification notifications clear requests. +- Keep this file-level DOX profile synchronized with `notifications_clear.py` because this directory is intentionally flat. + +## Ownership + +- `notifications_clear.py` owns the runtime implementation. +- `notifications_clear.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `NotificationsClear` (`ApiHandler`) + - `requires_auth(cls) -> bool` + - `async process(self, input: dict, request: Request) -> dict | Response` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `NotificationsClear` is an `ApiHandler`. +- `NotificationsClear` defines `process(...)`. +- `NotificationsClear` defines `requires_auth(...)`. +- Imported dependency areas include: `agent`, `flask`, `helpers.api`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `AgentContext.get_notification_manager`, `notification_manager.clear_all`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- No direct test reference was found by name search; choose the nearest behavioral test or perform a focused smoke check. + +## Child DOX Index + +No child DOX files. diff --git a/api/notifications_history.py.dox.md b/api/notifications_history.py.dox.md new file mode 100644 index 000000000..a14b5bc86 --- /dev/null +++ b/api/notifications_history.py.dox.md @@ -0,0 +1,45 @@ +# notifications_history.py DOX + +## Purpose + +- Own the `notifications_history.py` API endpoint. +- This module handles notification notifications history requests. +- Keep this file-level DOX profile synchronized with `notifications_history.py` because this directory is intentionally flat. + +## Ownership + +- `notifications_history.py` owns the runtime implementation. +- `notifications_history.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `NotificationsHistory` (`ApiHandler`) + - `requires_auth(cls) -> bool` + - `async process(self, input: dict, request: Request) -> dict | Response` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `NotificationsHistory` is an `ApiHandler`. +- `NotificationsHistory` defines `process(...)`. +- `NotificationsHistory` defines `requires_auth(...)`. +- Imported dependency areas include: `agent`, `flask`, `helpers.api`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `AgentContext.get_notification_manager`, `notification_manager.output_all`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- No direct test reference was found by name search; choose the nearest behavioral test or perform a focused smoke check. + +## Child DOX Index + +No child DOX files. diff --git a/api/notifications_mark_read.py.dox.md b/api/notifications_mark_read.py.dox.md new file mode 100644 index 000000000..a06cbbdcf --- /dev/null +++ b/api/notifications_mark_read.py.dox.md @@ -0,0 +1,45 @@ +# notifications_mark_read.py DOX + +## Purpose + +- Own the `notifications_mark_read.py` API endpoint. +- This module handles notification notifications mark read requests. +- Keep this file-level DOX profile synchronized with `notifications_mark_read.py` because this directory is intentionally flat. + +## Ownership + +- `notifications_mark_read.py` owns the runtime implementation. +- `notifications_mark_read.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `NotificationsMarkRead` (`ApiHandler`) + - `requires_auth(cls) -> bool` + - `async process(self, input: dict, request: Request) -> dict | Response` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `NotificationsMarkRead` is an `ApiHandler`. +- `NotificationsMarkRead` defines `process(...)`. +- `NotificationsMarkRead` defines `requires_auth(...)`. +- Imported dependency areas include: `agent`, `flask`, `helpers.api`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `AgentContext.get_notification_manager`, `notification_manager.mark_read_by_ids`, `notification_manager.mark_all_read`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- No direct test reference was found by name search; choose the nearest behavioral test or perform a focused smoke check. + +## Child DOX Index + +No child DOX files. diff --git a/api/nudge.py.dox.md b/api/nudge.py.dox.md new file mode 100644 index 000000000..f1be2cf3d --- /dev/null +++ b/api/nudge.py.dox.md @@ -0,0 +1,44 @@ +# nudge.py DOX + +## Purpose + +- Own the `nudge.py` API endpoint. +- This module handles nudge API requests. +- Keep this file-level DOX profile synchronized with `nudge.py` because this directory is intentionally flat. + +## Ownership + +- `nudge.py` owns the runtime implementation. +- `nudge.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `Nudge` (`ApiHandler`) + - `async process(self, input: dict, request: Request) -> dict | Response` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `Nudge` is an `ApiHandler`. +- `Nudge` defines `process(...)`. +- Imported dependency areas include: `helpers.api`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `self.use_context`, `context.nudge`, `context.log.log`, `Exception`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- Related tests observed by source search: + - `tests/test_browser_agent_regressions.py` + +## Child DOX Index + +No child DOX files. diff --git a/api/pause.py.dox.md b/api/pause.py.dox.md new file mode 100644 index 000000000..37d0528e9 --- /dev/null +++ b/api/pause.py.dox.md @@ -0,0 +1,45 @@ +# pause.py DOX + +## Purpose + +- Own the `pause.py` API endpoint. +- This module handles pause API requests. +- Keep this file-level DOX profile synchronized with `pause.py` because this directory is intentionally flat. + +## Ownership + +- `pause.py` owns the runtime implementation. +- `pause.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `Pause` (`ApiHandler`) + - `async process(self, input: dict, request: Request) -> dict | Response` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `Pause` is an `ApiHandler`. +- `Pause` defines `process(...)`. +- Imported dependency areas include: `helpers.api`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `self.use_context`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- Related tests observed by source search: + - `tests/test_multi_tab_isolation.py` + - `tests/test_snapshot_schema_v1.py` + +## Child DOX Index + +No child DOX files. diff --git a/api/plugins.py.dox.md b/api/plugins.py.dox.md new file mode 100644 index 000000000..e64b22dc9 --- /dev/null +++ b/api/plugins.py.dox.md @@ -0,0 +1,52 @@ +# plugins.py DOX + +## Purpose + +- Own the `plugins.py` API endpoint. +- This module manages plugin actions and plugin settings through the core API. +- Keep this file-level DOX profile synchronized with `plugins.py` because this directory is intentionally flat. + +## Ownership + +- `plugins.py` owns the runtime implementation. +- `plugins.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `Plugins` (`ApiHandler`) + - `async process(self, input: dict, request: Request) -> dict | Response` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `Plugins` is an `ApiHandler`. +- `Plugins` defines `process(...)`. +- Observed side-effect areas: filesystem reads, filesystem writes, filesystem deletion, subprocess/runtime control, plugin state, settings/state persistence. +- Imported dependency areas include: `helpers`, `helpers.api`, `helpers.localization`, `json`, `os`, `subprocess`, `sys`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `Response`, `plugins.find_plugin_assets`, `plugins.get_plugin_meta`, `plugins.get_default_plugin_config`, `plugins.save_plugin_config`, `plugins.toggle_plugin`, `plugins.find_plugin_dir`, `files.get_abs_path`, `Localization.get.now_iso`, `plugins.determine_plugin_asset_path`, `self._get_config`, `self._get_toggle_status`, `self._list_configs`, `self._delete_config`, `self._delete_plugin`, `self._get_default_config`, `self._save_config`, `self._toggle_plugin`, `self._get_doc`, `self._run_execute_script`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- Related tests observed by source search: + - `tests/test_a0_connector_computer_use_metadata.py` + - `tests/test_a0_connector_prompt_gating.py` + - `tests/test_browser_agent_regressions.py` + - `tests/test_chat_compaction.py` + - `tests/test_default_prompt_budget.py` + - `tests/test_document_query_plugin.py` + - `tests/test_error_retry_plugin.py` + - `tests/test_host_browser_connector.py` + +## Child DOX Index + +No child DOX files. diff --git a/api/plugins_list.py.dox.md b/api/plugins_list.py.dox.md new file mode 100644 index 000000000..599b5a307 --- /dev/null +++ b/api/plugins_list.py.dox.md @@ -0,0 +1,46 @@ +# plugins_list.py DOX + +## Purpose + +- Own the `plugins_list.py` API endpoint. +- This module returns plugin inventory and activation metadata for plugin UI surfaces. +- Keep this file-level DOX profile synchronized with `plugins_list.py` because this directory is intentionally flat. + +## Ownership + +- `plugins_list.py` owns the runtime implementation. +- `plugins_list.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `PluginsList` (`ApiHandler`) + - `async process(self, input: Input, request: Request) -> Output` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `PluginsList` is an `ApiHandler`. +- `PluginsList` defines `process(...)`. +- Observed side-effect areas: plugin state, settings/state persistence. +- Imported dependency areas include: `helpers`, `helpers.api`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `plugins.get_enhanced_plugins_list`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- Related tests observed by source search: + - `tests/test_plugin_activation_ui.py` + - `tests/test_speech_plugin_split.py` + +## Child DOX Index + +No child DOX files. diff --git a/api/poll.py.dox.md b/api/poll.py.dox.md new file mode 100644 index 000000000..851a03318 --- /dev/null +++ b/api/poll.py.dox.md @@ -0,0 +1,52 @@ +# poll.py DOX + +## Purpose + +- Own the `poll.py` API endpoint. +- This module returns chat/log/status changes for polling clients. +- Keep this file-level DOX profile synchronized with `poll.py` because this directory is intentionally flat. + +## Ownership + +- `poll.py` owns the runtime implementation. +- `poll.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `Poll` (`ApiHandler`) + - `async process(self, input: dict, request: Request) -> dict | Response` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `Poll` is an `ApiHandler`. +- `Poll` defines `process(...)`. +- Observed side-effect areas: settings/state persistence. +- Imported dependency areas include: `helpers.api`, `helpers.state_snapshot`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `build_snapshot`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- Related tests observed by source search: + - `tests/test_multi_tab_isolation.py` + - `tests/test_oauth_github_copilot.py` + - `tests/test_oauth_providers.py` + - `tests/test_office_document_store.py` + - `tests/test_snapshot_parity.py` + - `tests/test_snapshot_schema_v1.py` + - `tests/test_timezone_regressions.py` + - `tests/test_tunnel_remote_link.py` + +## Child DOX Index + +No child DOX files. diff --git a/api/projects.py.dox.md b/api/projects.py.dox.md new file mode 100644 index 000000000..d55500c21 --- /dev/null +++ b/api/projects.py.dox.md @@ -0,0 +1,59 @@ +# projects.py DOX + +## Purpose + +- Own the `projects.py` API endpoint. +- This module manages project create, update, delete, clone, and metadata flows. +- Keep this file-level DOX profile synchronized with `projects.py` because this directory is intentionally flat. + +## Ownership + +- `projects.py` owns the runtime implementation. +- `projects.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `Projects` (`ApiHandler`) + - `async process(self, input: Input, request: Request) -> Output` + - `get_active_projects_list(self)` + - `get_active_projects_options(self)` + - `create_project(self, project: dict | None)` + - `clone_project(self, project: dict | None)` + - `load_project(self, name: str | None)` + - `update_project(self, project: dict | None)` + - `delete_project(self, name: str | None)` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `Projects` is an `ApiHandler`. +- `Projects` defines `process(...)`. +- Observed side-effect areas: filesystem deletion, settings/state persistence. +- Imported dependency areas include: `helpers`, `helpers.api`, `helpers.notification`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `projects.get_active_projects_list`, `projects.BasicProjectData`, `projects.create_project`, `projects.load_edit_project_data`, `NotificationManager.send_notification`, `projects.EditProjectData`, `projects.update_project`, `projects.delete_project`, `projects.activate_project`, `projects.deactivate_project`, `projects.load_basic_project_data`, `projects.get_file_structure`, `self.use_context`, `Exception`, `projects.clone_git_project`, `self.get_active_projects_list`, `self.get_active_projects_options`, `self.load_project`, `self.create_project`, `self.clone_project`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- Related tests observed by source search: + - `tests/test_model_config_project_presets.py` + - `tests/test_office_document_store.py` + - `tests/test_plugin_activation_ui.py` + - `tests/test_projects.py` + - `tests/test_skills_runtime.py` + - `tests/test_task_scheduler_timezone.py` + - `tests/test_time_travel.py` + - `tests/test_tool_action_contracts.py` + +## Child DOX Index + +No child DOX files. diff --git a/api/rename_work_dir_file.py.dox.md b/api/rename_work_dir_file.py.dox.md new file mode 100644 index 000000000..624bedc54 --- /dev/null +++ b/api/rename_work_dir_file.py.dox.md @@ -0,0 +1,47 @@ +# rename_work_dir_file.py DOX + +## Purpose + +- Own the `rename_work_dir_file.py` API endpoint. +- This module handles workdir file operations for rename work dir file. +- Keep this file-level DOX profile synchronized with `rename_work_dir_file.py` because this directory is intentionally flat. + +## Ownership + +- `rename_work_dir_file.py` owns the runtime implementation. +- `rename_work_dir_file.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `RenameWorkDirFile` (`ApiHandler`) + - `async process(self, input: Input, request: Request) -> Output` +- Top-level functions: +- `async rename_item(file_path: str, new_name: str) -> bool` +- `async create_folder(parent_path: str, folder_name: str) -> bool` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `RenameWorkDirFile` is an `ApiHandler`. +- `RenameWorkDirFile` defines `process(...)`. +- Observed side-effect areas: filesystem writes. +- Imported dependency areas include: `api`, `helpers`, `helpers.api`, `helpers.file_browser`, `posixpath`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `FileBrowser`, `browser.rename_item`, `browser.create_folder`, `strip`, `runtime.call_development_function`, `posixpath.join`, `file_path.startswith`, `extension.call_extensions_async`, `str.rstrip`, `posixpath.dirname`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- No direct test reference was found by name search; choose the nearest behavioral test or perform a focused smoke check. + +## Child DOX Index + +No child DOX files. diff --git a/api/restart.py.dox.md b/api/restart.py.dox.md new file mode 100644 index 000000000..4e3156f6e --- /dev/null +++ b/api/restart.py.dox.md @@ -0,0 +1,48 @@ +# restart.py DOX + +## Purpose + +- Own the `restart.py` API endpoint. +- This module requests server restart or reload behavior. +- Keep this file-level DOX profile synchronized with `restart.py` because this directory is intentionally flat. + +## Ownership + +- `restart.py` owns the runtime implementation. +- `restart.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `Restart` (`ApiHandler`) + - `async process(self, input: dict, request: Request) -> dict | Response` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `Restart` is an `ApiHandler`. +- `Restart` defines `process(...)`. +- Imported dependency areas include: `helpers`, `helpers.api`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `process.reload`, `Response`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- Related tests observed by source search: + - `tests/test_browser_agent_regressions.py` + - `tests/test_download_toast_regressions.py` + - `tests/test_self_update_tag_filter.py` + - `tests/test_timezone_regressions.py` + - `tests/test_ws_manager.py` + +## Child DOX Index + +No child DOX files. diff --git a/api/rfc.py.dox.md b/api/rfc.py.dox.md new file mode 100644 index 000000000..6598649ea --- /dev/null +++ b/api/rfc.py.dox.md @@ -0,0 +1,47 @@ +# rfc.py DOX + +## Purpose + +- Own the `rfc.py` API endpoint. +- This module dispatches remote function calls through the RFC helper layer. +- Keep this file-level DOX profile synchronized with `rfc.py` because this directory is intentionally flat. + +## Ownership + +- `rfc.py` owns the runtime implementation. +- `rfc.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `RFC` (`ApiHandler`) + - `requires_csrf(cls) -> bool` + - `requires_auth(cls) -> bool` + - `async process(self, input: dict, request: Request) -> dict | Response` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `RFC` is an `ApiHandler`. +- `RFC` defines `process(...)`. +- `RFC` defines `requires_auth(...)`. +- `RFC` defines `requires_csrf(...)`. +- Imported dependency areas include: `helpers`, `helpers.api`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `runtime.handle_rfc`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- No direct test reference was found by name search; choose the nearest behavioral test or perform a focused smoke check. + +## Child DOX Index + +No child DOX files. diff --git a/api/scheduler_task_create.py.dox.md b/api/scheduler_task_create.py.dox.md new file mode 100644 index 000000000..332118085 --- /dev/null +++ b/api/scheduler_task_create.py.dox.md @@ -0,0 +1,44 @@ +# scheduler_task_create.py DOX + +## Purpose + +- Own the `scheduler_task_create.py` API endpoint. +- This module handles scheduler task create requests. +- Keep this file-level DOX profile synchronized with `scheduler_task_create.py` because this directory is intentionally flat. + +## Ownership + +- `scheduler_task_create.py` owns the runtime implementation. +- `scheduler_task_create.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `SchedulerTaskCreate` (`ApiHandler`) + - `async process(self, input: Input, request: Request) -> Output` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `SchedulerTaskCreate` is an `ApiHandler`. +- `SchedulerTaskCreate` defines `process(...)`. +- Observed side-effect areas: filesystem writes, secret handling, scheduler state. +- Imported dependency areas include: `helpers.api`, `helpers.localization`, `helpers.print_style`, `helpers.projects`, `helpers.task_scheduler`, `random`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `PrintStyle`, `scheduler.get_task_by_uuid`, `serialize_task`, `Localization.get.set_timezone`, `scheduler.reload`, `ValueError`, `ScheduledTask.create`, `scheduler.add_task`, `requested_project_slug.strip`, `load_basic_project_data`, `random.randint`, `schedule.split`, `TaskSchedule`, `PlannedTask.create`, `AdHocTask.create`, `printer.error`, `type`, `parse_task_plan`, `parse_task_schedule`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- No direct test reference was found by name search; choose the nearest behavioral test or perform a focused smoke check. + +## Child DOX Index + +No child DOX files. diff --git a/api/scheduler_task_delete.py.dox.md b/api/scheduler_task_delete.py.dox.md new file mode 100644 index 000000000..2112e95ee --- /dev/null +++ b/api/scheduler_task_delete.py.dox.md @@ -0,0 +1,44 @@ +# scheduler_task_delete.py DOX + +## Purpose + +- Own the `scheduler_task_delete.py` API endpoint. +- This module handles scheduler task delete requests. +- Keep this file-level DOX profile synchronized with `scheduler_task_delete.py` because this directory is intentionally flat. + +## Ownership + +- `scheduler_task_delete.py` owns the runtime implementation. +- `scheduler_task_delete.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `SchedulerTaskDelete` (`ApiHandler`) + - `async process(self, input: Input, request: Request) -> Output` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `SchedulerTaskDelete` is an `ApiHandler`. +- `SchedulerTaskDelete` defines `process(...)`. +- Observed side-effect areas: filesystem writes, filesystem deletion, settings/state persistence, scheduler state. +- Imported dependency areas include: `agent`, `helpers`, `helpers.api`, `helpers.localization`, `helpers.task_scheduler`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `scheduler.get_task_by_uuid`, `Localization.get.set_timezone`, `scheduler.reload`, `self.use_context`, `scheduler.cancel_running_task`, `AgentContext.remove`, `persist_chat.remove_chat`, `scheduler.remove_task_by_uuid`, `context.reset`, `scheduler.update_task`, `scheduler.save`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- No direct test reference was found by name search; choose the nearest behavioral test or perform a focused smoke check. + +## Child DOX Index + +No child DOX files. diff --git a/api/scheduler_task_run.py.dox.md b/api/scheduler_task_run.py.dox.md new file mode 100644 index 000000000..f4aa4b158 --- /dev/null +++ b/api/scheduler_task_run.py.dox.md @@ -0,0 +1,44 @@ +# scheduler_task_run.py DOX + +## Purpose + +- Own the `scheduler_task_run.py` API endpoint. +- This module handles scheduler task run requests. +- Keep this file-level DOX profile synchronized with `scheduler_task_run.py` because this directory is intentionally flat. + +## Ownership + +- `scheduler_task_run.py` owns the runtime implementation. +- `scheduler_task_run.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `SchedulerTaskRun` (`ApiHandler`) + - `async process(self, input: Input, request: Request) -> Output` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `SchedulerTaskRun` is an `ApiHandler`. +- `SchedulerTaskRun` defines `process(...)`. +- Observed side-effect areas: settings/state persistence, scheduler state. +- Imported dependency areas include: `helpers.api`, `helpers.localization`, `helpers.print_style`, `helpers.task_scheduler`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `PrintStyle`, `scheduler.get_task_by_uuid`, `Localization.get.set_timezone`, `scheduler.reload`, `self._printer.error`, `scheduler.serialize_task`, `scheduler.run_task_by_uuid`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- No direct test reference was found by name search; choose the nearest behavioral test or perform a focused smoke check. + +## Child DOX Index + +No child DOX files. diff --git a/api/scheduler_task_update.py.dox.md b/api/scheduler_task_update.py.dox.md new file mode 100644 index 000000000..a7c9bfced --- /dev/null +++ b/api/scheduler_task_update.py.dox.md @@ -0,0 +1,44 @@ +# scheduler_task_update.py DOX + +## Purpose + +- Own the `scheduler_task_update.py` API endpoint. +- This module handles scheduler task update requests. +- Keep this file-level DOX profile synchronized with `scheduler_task_update.py` because this directory is intentionally flat. + +## Ownership + +- `scheduler_task_update.py` owns the runtime implementation. +- `scheduler_task_update.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `SchedulerTaskUpdate` (`ApiHandler`) + - `async process(self, input: Input, request: Request) -> Output` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `SchedulerTaskUpdate` is an `ApiHandler`. +- `SchedulerTaskUpdate` defines `process(...)`. +- Observed side-effect areas: settings/state persistence, secret handling, scheduler state. +- Imported dependency areas include: `helpers.api`, `helpers.localization`, `helpers.task_scheduler`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `scheduler.get_task_by_uuid`, `serialize_task`, `Localization.get.set_timezone`, `scheduler.reload`, `TaskState`, `scheduler.update_task`, `parse_task_schedule`, `parse_task_plan`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- No direct test reference was found by name search; choose the nearest behavioral test or perform a focused smoke check. + +## Child DOX Index + +No child DOX files. diff --git a/api/scheduler_tasks_list.py.dox.md b/api/scheduler_tasks_list.py.dox.md new file mode 100644 index 000000000..5e5533206 --- /dev/null +++ b/api/scheduler_tasks_list.py.dox.md @@ -0,0 +1,44 @@ +# scheduler_tasks_list.py DOX + +## Purpose + +- Own the `scheduler_tasks_list.py` API endpoint. +- This module handles scheduler tasks list requests. +- Keep this file-level DOX profile synchronized with `scheduler_tasks_list.py` because this directory is intentionally flat. + +## Ownership + +- `scheduler_tasks_list.py` owns the runtime implementation. +- `scheduler_tasks_list.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `SchedulerTasksList` (`ApiHandler`) + - `async process(self, input: Input, request: Request) -> Output` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `SchedulerTasksList` is an `ApiHandler`. +- `SchedulerTasksList` defines `process(...)`. +- Observed side-effect areas: scheduler state. +- Imported dependency areas include: `helpers.api`, `helpers.localization`, `helpers.print_style`, `helpers.task_scheduler`, `traceback`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `scheduler.serialize_all_tasks`, `Localization.get.set_timezone`, `scheduler.reload`, `PrintStyle.error`, `traceback.format_exc`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- No direct test reference was found by name search; choose the nearest behavioral test or perform a focused smoke check. + +## Child DOX Index + +No child DOX files. diff --git a/api/scheduler_tick.py.dox.md b/api/scheduler_tick.py.dox.md new file mode 100644 index 000000000..d19ae305c --- /dev/null +++ b/api/scheduler_tick.py.dox.md @@ -0,0 +1,50 @@ +# scheduler_tick.py DOX + +## Purpose + +- Own the `scheduler_tick.py` API endpoint. +- This module handles scheduler tick requests. +- Keep this file-level DOX profile synchronized with `scheduler_tick.py` because this directory is intentionally flat. + +## Ownership + +- `scheduler_tick.py` owns the runtime implementation. +- `scheduler_tick.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `SchedulerTick` (`ApiHandler`) + - `requires_loopback(cls) -> bool` + - `requires_auth(cls) -> bool` + - `requires_csrf(cls) -> bool` + - `async process(self, input: Input, request: Request) -> Output` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `SchedulerTick` is an `ApiHandler`. +- `SchedulerTick` defines `process(...)`. +- `SchedulerTick` defines `requires_auth(...)`. +- `SchedulerTick` defines `requires_csrf(...)`. +- `SchedulerTick` defines `requires_loopback(...)`. +- Observed side-effect areas: settings/state persistence, scheduler state. +- Imported dependency areas include: `datetime`, `helpers.api`, `helpers.localization`, `helpers.print_style`, `helpers.task_scheduler`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `datetime.now.strftime`, `PrintStyle`, `scheduler.get_tasks`, `scheduler.serialize_all_tasks`, `Localization.get.set_timezone`, `scheduler.reload`, `scheduler.tick`, `datetime.now`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- No direct test reference was found by name search; choose the nearest behavioral test or perform a focused smoke check. + +## Child DOX Index + +No child DOX files. diff --git a/api/self_update_get.py.dox.md b/api/self_update_get.py.dox.md new file mode 100644 index 000000000..261cac93f --- /dev/null +++ b/api/self_update_get.py.dox.md @@ -0,0 +1,45 @@ +# self_update_get.py DOX + +## Purpose + +- Own the `self_update_get.py` API endpoint. +- This module handles self update get API requests. +- Keep this file-level DOX profile synchronized with `self_update_get.py` because this directory is intentionally flat. + +## Ownership + +- `self_update_get.py` owns the runtime implementation. +- `self_update_get.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `SelfUpdateGet` (`ApiHandler`) + - `get_methods(cls) -> list[str]` + - `async process(self, input: dict, request: Request) -> dict | Response` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `SelfUpdateGet` is an `ApiHandler`. +- `SelfUpdateGet` defines `process(...)`. +- `SelfUpdateGet` defines `get_methods(...)`. +- Imported dependency areas include: `helpers`, `helpers.api`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `self_update.get_update_info`, `runtime.is_dockerized`, `self_update.load_pending_update`, `self_update.load_last_status`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- No direct test reference was found by name search; choose the nearest behavioral test or perform a focused smoke check. + +## Child DOX Index + +No child DOX files. diff --git a/api/self_update_schedule.py.dox.md b/api/self_update_schedule.py.dox.md new file mode 100644 index 000000000..b865070c9 --- /dev/null +++ b/api/self_update_schedule.py.dox.md @@ -0,0 +1,45 @@ +# self_update_schedule.py DOX + +## Purpose + +- Own the `self_update_schedule.py` API endpoint. +- This module handles self update schedule API requests. +- Keep this file-level DOX profile synchronized with `self_update_schedule.py` because this directory is intentionally flat. + +## Ownership + +- `self_update_schedule.py` owns the runtime implementation. +- `self_update_schedule.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `SelfUpdateSchedule` (`ApiHandler`) + - `async process(self, input: dict, request: Request) -> dict | Response` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `SelfUpdateSchedule` is an `ApiHandler`. +- `SelfUpdateSchedule` defines `process(...)`. +- Observed side-effect areas: filesystem writes, subprocess/runtime control. +- Imported dependency areas include: `helpers`, `helpers.api`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `runtime.is_dockerized`, `self_update.schedule_update`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- Related tests observed by source search: + - `tests/test_self_update_tag_filter.py` + +## Child DOX Index + +No child DOX files. diff --git a/api/self_update_tags.py.dox.md b/api/self_update_tags.py.dox.md new file mode 100644 index 000000000..fdf78cd23 --- /dev/null +++ b/api/self_update_tags.py.dox.md @@ -0,0 +1,43 @@ +# self_update_tags.py DOX + +## Purpose + +- Own the `self_update_tags.py` API endpoint. +- This module handles self update tags API requests. +- Keep this file-level DOX profile synchronized with `self_update_tags.py` because this directory is intentionally flat. + +## Ownership + +- `self_update_tags.py` owns the runtime implementation. +- `self_update_tags.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `SelfUpdateTags` (`ApiHandler`) + - `async process(self, input: dict, request: Request) -> dict | Response` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `SelfUpdateTags` is an `ApiHandler`. +- `SelfUpdateTags` defines `process(...)`. +- Imported dependency areas include: `helpers`, `helpers.api`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `str.strip.lower`, `self_update.get_repo_version_info.get.strip.lower`, `self_update.get_available_branch_values`, `self_update.get_selector_tag_options`, `str.strip`, `self_update.get_repo_version_info.get.strip`, `runtime.is_dockerized`, `self_update.get_repo_version_info`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- No direct test reference was found by name search; choose the nearest behavioral test or perform a focused smoke check. + +## Child DOX Index + +No child DOX files. diff --git a/api/settings_get.py.dox.md b/api/settings_get.py.dox.md new file mode 100644 index 000000000..e584283fd --- /dev/null +++ b/api/settings_get.py.dox.md @@ -0,0 +1,46 @@ +# settings_get.py DOX + +## Purpose + +- Own the `settings_get.py` API endpoint. +- This module returns current application settings. +- Keep this file-level DOX profile synchronized with `settings_get.py` because this directory is intentionally flat. + +## Ownership + +- `settings_get.py` owns the runtime implementation. +- `settings_get.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `GetSettings` (`ApiHandler`) + - `async process(self, input: dict, request: Request) -> dict | Response` + - `get_methods(cls) -> list[str]` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `GetSettings` is an `ApiHandler`. +- `GetSettings` defines `process(...)`. +- `GetSettings` defines `get_methods(...)`. +- Observed side-effect areas: settings/state persistence. +- Imported dependency areas include: `helpers`, `helpers.api`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `settings.get_settings`, `settings.convert_out`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- No direct test reference was found by name search; choose the nearest behavioral test or perform a focused smoke check. + +## Child DOX Index + +No child DOX files. diff --git a/api/settings_set.py.dox.md b/api/settings_set.py.dox.md new file mode 100644 index 000000000..0f08f9862 --- /dev/null +++ b/api/settings_set.py.dox.md @@ -0,0 +1,44 @@ +# settings_set.py DOX + +## Purpose + +- Own the `settings_set.py` API endpoint. +- This module persists application settings updates. +- Keep this file-level DOX profile synchronized with `settings_set.py` because this directory is intentionally flat. + +## Ownership + +- `settings_set.py` owns the runtime implementation. +- `settings_set.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `SetSettings` (`ApiHandler`) + - `async process(self, input: dict[Any, Any], request: Request) -> dict[Any, Any] | Response` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `SetSettings` is an `ApiHandler`. +- `SetSettings` defines `process(...)`. +- Observed side-effect areas: settings/state persistence. +- Imported dependency areas include: `helpers`, `helpers.api`, `typing`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `settings.convert_in`, `settings.set_settings`, `settings.convert_out`, `settings.Settings`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- No direct test reference was found by name search; choose the nearest behavioral test or perform a focused smoke check. + +## Child DOX Index + +No child DOX files. diff --git a/api/settings_workdir_file_structure.py.dox.md b/api/settings_workdir_file_structure.py.dox.md new file mode 100644 index 000000000..e52a742ef --- /dev/null +++ b/api/settings_workdir_file_structure.py.dox.md @@ -0,0 +1,46 @@ +# settings_workdir_file_structure.py DOX + +## Purpose + +- Own the `settings_workdir_file_structure.py` API endpoint. +- This module handles settings workdir file structure API requests. +- Keep this file-level DOX profile synchronized with `settings_workdir_file_structure.py` because this directory is intentionally flat. + +## Ownership + +- `settings_workdir_file_structure.py` owns the runtime implementation. +- `settings_workdir_file_structure.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `SettingsWorkdirFileStructure` (`ApiHandler`) + - `async process(self, input: dict, request: Request) -> dict | Response` + - `get_methods(cls) -> list[str]` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `SettingsWorkdirFileStructure` is an `ApiHandler`. +- `SettingsWorkdirFileStructure` defines `process(...)`. +- `SettingsWorkdirFileStructure` defines `get_methods(...)`. +- Observed side-effect areas: filesystem reads, settings/state persistence. +- Imported dependency areas include: `helpers`, `helpers.api`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `files.get_abs_path_development`, `Exception`, `file_tree.file_tree`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- No direct test reference was found by name search; choose the nearest behavioral test or perform a focused smoke check. + +## Child DOX Index + +No child DOX files. diff --git a/api/skills.py.dox.md b/api/skills.py.dox.md new file mode 100644 index 000000000..8da5af317 --- /dev/null +++ b/api/skills.py.dox.md @@ -0,0 +1,54 @@ +# skills.py DOX + +## Purpose + +- Own the `skills.py` API endpoint. +- This module lists and manages available skills for settings and agent-facing skill flows. +- Keep this file-level DOX profile synchronized with `skills.py` because this directory is intentionally flat. + +## Ownership + +- `skills.py` owns the runtime implementation. +- `skills.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `Skills` (`ApiHandler`) + - `async process(self, input: Input, request: Request) -> Output` + - `list_skills(self, input: Input)` + - `delete_skill(self, input: Input)` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `Skills` is an `ApiHandler`. +- `Skills` defines `process(...)`. +- Observed side-effect areas: filesystem reads, filesystem deletion. +- Imported dependency areas include: `helpers`, `helpers.api`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `skills.list_skills`, `result.sort`, `str.strip`, `skills.delete_skill`, `projects.get_project_folder`, `runtime.is_development`, `Exception`, `self.list_skills`, `strip`, `files.normalize_a0_path`, `files.get_abs_path`, `self.delete_skill`, `files.is_in_dir`, `projects.get_project_meta`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- Related tests observed by source search: + - `tests/test_a0_connector_prompt_gating.py` + - `tests/test_browser_agent_regressions.py` + - `tests/test_document_query_plugin.py` + - `tests/test_fasta2a_client.py` + - `tests/test_office_canvas_setup.py` + - `tests/test_office_document_store.py` + - `tests/test_skills_runtime.py` + - `tests/test_time_travel.py` + +## Child DOX Index + +No child DOX files. diff --git a/api/skills_import.py.dox.md b/api/skills_import.py.dox.md new file mode 100644 index 000000000..4940e833a --- /dev/null +++ b/api/skills_import.py.dox.md @@ -0,0 +1,44 @@ +# skills_import.py DOX + +## Purpose + +- Own the `skills_import.py` API endpoint. +- This module handles skills import API requests. +- Keep this file-level DOX profile synchronized with `skills_import.py` because this directory is intentionally flat. + +## Ownership + +- `skills_import.py` owns the runtime implementation. +- `skills_import.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `SkillsImport` (`ApiHandler`) + - `async process(self, input: dict, request: Request) -> dict | Response` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `SkillsImport` is an `ApiHandler`. +- `SkillsImport` defines `process(...)`. +- Observed side-effect areas: filesystem reads, filesystem writes, filesystem deletion. +- Imported dependency areas include: `__future__`, `helpers`, `helpers.api`, `helpers.skills_import`, `os`, `pathlib`, `time`, `uuid`, `werkzeug.datastructures`, `werkzeug.utils`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `self.use_context`, `strip.lower`, `Path`, `tmp_dir.mkdir`, `secure_filename`, `time.strftime`, `skills_file.save`, `strip`, `files.get_abs_path`, `base.lower.endswith`, `import_skills`, `files.deabsolute_path`, `uuid.uuid4`, `tmp_path.unlink`, `base.lower`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- No direct test reference was found by name search; choose the nearest behavioral test or perform a focused smoke check. + +## Child DOX Index + +No child DOX files. diff --git a/api/skills_import_preview.py.dox.md b/api/skills_import_preview.py.dox.md new file mode 100644 index 000000000..107f55b2a --- /dev/null +++ b/api/skills_import_preview.py.dox.md @@ -0,0 +1,44 @@ +# skills_import_preview.py DOX + +## Purpose + +- Own the `skills_import_preview.py` API endpoint. +- This module handles skills import preview API requests. +- Keep this file-level DOX profile synchronized with `skills_import_preview.py` because this directory is intentionally flat. + +## Ownership + +- `skills_import_preview.py` owns the runtime implementation. +- `skills_import_preview.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `SkillsImportPreview` (`ApiHandler`) + - `async process(self, input: dict, request: Request) -> dict | Response` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `SkillsImportPreview` is an `ApiHandler`. +- `SkillsImportPreview` defines `process(...)`. +- Observed side-effect areas: filesystem reads, filesystem writes, filesystem deletion. +- Imported dependency areas include: `__future__`, `helpers`, `helpers.api`, `helpers.skills_import`, `os`, `pathlib`, `time`, `uuid`, `werkzeug.datastructures`, `werkzeug.utils`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `self.use_context`, `strip.lower`, `Path`, `tmp_dir.mkdir`, `secure_filename`, `time.strftime`, `skills_file.save`, `strip`, `files.get_abs_path`, `base.lower.endswith`, `import_skills`, `files.deabsolute_path`, `uuid.uuid4`, `tmp_path.unlink`, `base.lower`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- No direct test reference was found by name search; choose the nearest behavioral test or perform a focused smoke check. + +## Child DOX Index + +No child DOX files. diff --git a/api/skills_scan.py b/api/skills_scan.py new file mode 100644 index 000000000..c1ba6871a --- /dev/null +++ b/api/skills_scan.py @@ -0,0 +1,124 @@ +from __future__ import annotations + +import shutil +import time +import uuid +from pathlib import Path +from typing import Any + +from helpers import files, skills +from helpers.api import ApiHandler, Request, Response +from helpers.skills_import import extract_skills_zip +from werkzeug.datastructures import FileStorage +from werkzeug.utils import secure_filename + + +class SkillsScan(ApiHandler): + """ + Prepare skill scan targets for the Settings > Skills scanner. + """ + + async def process(self, input: dict[str, Any], request: Request) -> dict[str, Any] | Response: + if "skills_file" in request.files: + return self._prepare_uploaded_archive(request.files["skills_file"]) + + action = str(input.get("action") or "targets").strip().lower() + if action == "targets": + return self._list_installed_targets() + + return {"success": False, "error": "Invalid action"} + + def _list_installed_targets(self) -> dict[str, Any]: + targets: list[dict[str, Any]] = [] + seen: set[str] = set() + total_skills = 0 + + for raw_root in skills.get_skill_roots(): + root = Path(raw_root) + if not root.is_dir(): + continue + + skill_files = skills.discover_skill_md_files(root) + if not skill_files: + continue + + key = str(root.resolve()) + if key in seen: + continue + seen.add(key) + + skill_count = len(skill_files) + total_skills += skill_count + targets.append( + { + "path": str(root), + "display_path": files.normalize_a0_path(str(root)), + "skill_count": skill_count, + } + ) + + targets.sort(key=lambda item: item["path"]) + return { + "success": True, + "target_type": "installed", + "target_label": "Installed Agent Zero skills", + "targets": targets, + "paths": [item["path"] for item in targets], + "skill_count": total_skills, + } + + def _prepare_uploaded_archive(self, skills_file: FileStorage) -> dict[str, Any]: + if not skills_file.filename: + return {"success": False, "error": "No file selected"} + + base = secure_filename(skills_file.filename) # type: ignore[arg-type] + if not base.lower().endswith(".zip"): + return {"success": False, "error": "Skill scan uploads must be .zip files"} + + tmp_dir = Path(files.get_abs_path("tmp", "uploads")) + tmp_dir.mkdir(parents=True, exist_ok=True) + unique = uuid.uuid4().hex[:8] + stamp = time.strftime("%Y%m%d_%H%M%S") + tmp_path = tmp_dir / f"skills_scan_{stamp}_{unique}_{base}" + skills_file.save(str(tmp_path)) + + cleanup_root: Path | None = None + try: + scan_root, cleanup_root = extract_skills_zip( + tmp_path, + tmp_subdir="skill_scans", + prefix=f"scan_{unique}", + ) + skill_files = skills.discover_skill_md_files(scan_root) + skill_entries = [ + { + "path": str(skill_md.parent), + "relative_path": str(skill_md.parent.relative_to(scan_root)), + } + for skill_md in skill_files + ] + warnings = [] + if not skill_entries: + warnings.append("No SKILL.md files were found in the uploaded archive.") + + return { + "success": True, + "target_type": "uploaded_archive", + "target_label": base, + "paths": [str(scan_root)], + "scan_path": str(scan_root), + "display_path": files.normalize_a0_path(str(scan_root)), + "cleanup_paths": [str(cleanup_root)], + "skill_count": len(skill_entries), + "skills": skill_entries, + "warnings": warnings, + } + except Exception as exc: + if cleanup_root: + shutil.rmtree(cleanup_root, ignore_errors=True) + return {"success": False, "error": f"Failed to prepare skill scan: {exc}"} + finally: + try: + tmp_path.unlink(missing_ok=True) # type: ignore[arg-type] + except Exception: + pass diff --git a/api/skills_scan.py.dox.md b/api/skills_scan.py.dox.md new file mode 100644 index 000000000..b277ae73e --- /dev/null +++ b/api/skills_scan.py.dox.md @@ -0,0 +1,46 @@ +# skills_scan.py DOX + +## Purpose + +- Own the `skills_scan.py` API endpoint. +- Provide scan target discovery and uploaded skills archive preparation for the Settings > Skills scanner. +- Keep this file-level DOX profile synchronized with `skills_scan.py` because this directory is intentionally flat. + +## Ownership + +- `skills_scan.py` owns the runtime implementation. +- `skills_scan.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `SkillsScan` (`ApiHandler`) + - `async process(self, input: dict[str, Any], request: Request) -> dict[str, Any] | Response` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- The JSON request action `targets` returns existing installed skill roots that contain at least one `SKILL.md`. +- Multipart requests with `skills_file` accept only `.zip` uploads, extract them into `tmp/skill_scans`, discover contained `SKILL.md` folders, and return `paths` plus `cleanup_paths` for the scanner prompt. +- Uploaded archives are not imported, installed, or executed by this endpoint. +- Temporary uploaded zip files under `tmp/uploads` are deleted after extraction or failure. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- Observed side-effect areas: filesystem reads, filesystem writes, filesystem deletion. +- Imported dependency areas include: `__future__`, `helpers`, `helpers.api`, `helpers.skills_import`, `pathlib`, `shutil`, `time`, `typing`, `uuid`, `werkzeug.datastructures`, `werkzeug.utils`. + +## Key Concepts + +- Installed target discovery uses `helpers.skills.get_skill_roots()` and filters to roots where `discover_skill_md_files()` finds skills. +- Uploaded zip preparation uses `extract_skills_zip()` so zip entries remain bounded to the temp extraction root. +- Response paths are local absolute paths for the scanner agent, while `display_path` provides normalized `/a0/...` style display when possible. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Do not execute uploaded files or scan targets in this endpoint. +- Keep temp extraction paths explicit so the LLM-driven scan prompt can clean them up. + +## Verification + +- Run endpoint-specific or API tests for changed behavior; smoke-test uploaded zip and installed-skill scan modal flows when practical. + +## Child DOX Index + +No child DOX files. diff --git a/api/subagents.py.dox.md b/api/subagents.py.dox.md new file mode 100644 index 000000000..85777218f --- /dev/null +++ b/api/subagents.py.dox.md @@ -0,0 +1,49 @@ +# subagents.py DOX + +## Purpose + +- Own the `subagents.py` API endpoint. +- This module returns subordinate agent profile data for UI and delegation flows. +- Keep this file-level DOX profile synchronized with `subagents.py` because this directory is intentionally flat. + +## Ownership + +- `subagents.py` owns the runtime implementation. +- `subagents.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `Subagents` (`ApiHandler`) + - `async process(self, input: Input, request: Request) -> Output` + - `get_subagents_list(self)` + - `load_agent(self, name: str | None)` + - `save_agent(self, name: str | None, data: dict | None)` + - `delete_agent(self, name: str | None)` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `Subagents` is an `ApiHandler`. +- `Subagents` defines `process(...)`. +- Observed side-effect areas: filesystem writes, filesystem deletion. +- Imported dependency areas include: `helpers`, `helpers.api`, `typing`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `subagents.get_agents_list`, `subagents.load_agent_data`, `subagents.SubAgent`, `subagents.save_agent_data`, `subagents.delete_agent_data`, `self.use_context`, `Exception`, `self.get_subagents_list`, `self.load_agent`, `self.save_agent`, `self.delete_agent`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- Related tests observed by source search: + - `tests/test_skills_runtime.py` + +## Child DOX Index + +No child DOX files. diff --git a/api/tunnel.py.dox.md b/api/tunnel.py.dox.md new file mode 100644 index 000000000..3618edc6e --- /dev/null +++ b/api/tunnel.py.dox.md @@ -0,0 +1,48 @@ +# tunnel.py DOX + +## Purpose + +- Own the `tunnel.py` API endpoint. +- This module manages tunnel provider status, start, and stop actions. +- Keep this file-level DOX profile synchronized with `tunnel.py` because this directory is intentionally flat. + +## Ownership + +- `tunnel.py` owns the runtime implementation. +- `tunnel.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `Tunnel` (`ApiHandler`) + - `async process(self, input: dict, request: Request) -> dict | Response` +- Top-level functions: +- `async process(input: dict) -> dict | Response` +- `stop()` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `Tunnel` is an `ApiHandler`. +- `Tunnel` defines `process(...)`. +- Observed side-effect areas: tunnel state. +- Imported dependency areas include: `helpers`, `helpers.api`, `helpers.tunnel_manager`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `TunnelManager.get_instance`, `tunnel_manager.stop_tunnel`, `runtime.get_web_ui_port`, `tunnel_manager.start_tunnel`, `tunnel_manager.get_last_error`, `process`, `tunnel_manager.get_notifications`, `stop`, `tunnel_manager.get_tunnel_url`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- Related tests observed by source search: + - `tests/test_tunnel_remote_link.py` + +## Child DOX Index + +No child DOX files. diff --git a/api/tunnel_proxy.py.dox.md b/api/tunnel_proxy.py.dox.md new file mode 100644 index 000000000..b713482c9 --- /dev/null +++ b/api/tunnel_proxy.py.dox.md @@ -0,0 +1,46 @@ +# tunnel_proxy.py DOX + +## Purpose + +- Own the `tunnel_proxy.py` API endpoint. +- This module proxies tunnel-related HTTP traffic through the configured tunnel provider. +- Keep this file-level DOX profile synchronized with `tunnel_proxy.py` because this directory is intentionally flat. + +## Ownership + +- `tunnel_proxy.py` owns the runtime implementation. +- `tunnel_proxy.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `TunnelProxy` (`ApiHandler`) + - `async process(self, input: dict, request: Request) -> dict | Response` +- Top-level functions: +- `async process(input: dict) -> dict | Response` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `TunnelProxy` is an `ApiHandler`. +- `TunnelProxy` defines `process(...)`. +- Observed side-effect areas: network calls, settings/state persistence, tunnel state. +- Imported dependency areas include: `helpers`, `helpers.api`, `helpers.tunnel_manager`, `requests`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `runtime.get_arg`, `requests.post`, `process`, `dotenv.get_dotenv_value`, `response.json`, `local_process`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- No direct test reference was found by name search; choose the nearest behavioral test or perform a focused smoke check. + +## Child DOX Index + +No child DOX files. diff --git a/api/upload.py.dox.md b/api/upload.py.dox.md new file mode 100644 index 000000000..9fccb571f --- /dev/null +++ b/api/upload.py.dox.md @@ -0,0 +1,47 @@ +# upload.py DOX + +## Purpose + +- Own the `upload.py` API endpoint. +- This module accepts general uploads into runtime upload storage. +- Keep this file-level DOX profile synchronized with `upload.py` because this directory is intentionally flat. + +## Ownership + +- `upload.py` owns the runtime implementation. +- `upload.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `UploadFile` (`ApiHandler`) + - `async process(self, input: dict, request: Request) -> dict | Response` + - `allowed_file(self, filename)` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `UploadFile` is an `ApiHandler`. +- `UploadFile` defines `process(...)`. +- Observed side-effect areas: filesystem reads, settings/state persistence. +- Imported dependency areas include: `helpers`, `helpers.api`, `helpers.security`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `request.files.getlist`, `Exception`, `self.allowed_file`, `safe_filename`, `file.save`, `files.get_abs_path`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- Related tests observed by source search: + - `tests/test_browser_agent_regressions.py` + - `tests/test_image_get_security.py` + +## Child DOX Index + +No child DOX files. diff --git a/api/upload_work_dir_files.py.dox.md b/api/upload_work_dir_files.py.dox.md new file mode 100644 index 000000000..6cf9370ae --- /dev/null +++ b/api/upload_work_dir_files.py.dox.md @@ -0,0 +1,47 @@ +# upload_work_dir_files.py DOX + +## Purpose + +- Own the `upload_work_dir_files.py` API endpoint. +- This module handles workdir file operations for upload work dir files. +- Keep this file-level DOX profile synchronized with `upload_work_dir_files.py` because this directory is intentionally flat. + +## Ownership + +- `upload_work_dir_files.py` owns the runtime implementation. +- `upload_work_dir_files.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `UploadWorkDirFiles` (`ApiHandler`) + - `async process(self, input: dict, request: Request) -> dict | Response` +- Top-level functions: +- `async upload_files(uploaded_files: list[FileStorage], current_path: str)` +- `async upload_file(current_path: str, filename: str, base64_content: str)` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `UploadWorkDirFiles` is an `ApiHandler`. +- `UploadWorkDirFiles` defines `process(...)`. +- Observed side-effect areas: filesystem writes. +- Imported dependency areas include: `api`, `base64`, `helpers`, `helpers.api`, `helpers.file_browser`, `os`, `posixpath`, `werkzeug.datastructures`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `runtime.is_development`, `FileBrowser`, `browser.save_file_b64`, `request.files.getlist`, `browser.save_files`, `Exception`, `upload_files`, `runtime.call_development_function`, `file.stream.read`, `base64.b64encode.decode`, `extension.call_extensions_async`, `base64.b64encode`, `posixpath.join`, `str.rstrip`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- No direct test reference was found by name search; choose the nearest behavioral test or perform a focused smoke check. + +## Child DOX Index + +No child DOX files. diff --git a/api/ws_dev_test.py.dox.md b/api/ws_dev_test.py.dox.md new file mode 100644 index 000000000..aaad42608 --- /dev/null +++ b/api/ws_dev_test.py.dox.md @@ -0,0 +1,44 @@ +# ws_dev_test.py DOX + +## Purpose + +- Own the `ws_dev_test.py` API endpoint. +- This module provides a development WebSocket test namespace. +- Keep this file-level DOX profile synchronized with `ws_dev_test.py` because this directory is intentionally flat. + +## Ownership + +- `ws_dev_test.py` owns the runtime implementation. +- `ws_dev_test.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `WsDevTest` (`WsHandler`) + - `async process(self, event: str, data: dict, sid: str) -> dict[str, Any] | WsResult | None` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `WsDevTest` is a `WsHandler`. +- `WsDevTest` defines `process(...)`. +- Observed side-effect areas: filesystem writes, network calls, WebSocket state. +- Imported dependency areas include: `asyncio`, `helpers`, `helpers.print_style`, `helpers.ws`, `helpers.ws_manager`, `typing`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `event.startswith`, `self.manager.register_diagnostic_watcher`, `self.manager.unregister_diagnostic_watcher`, `PrintStyle.info`, `PrintStyle.debug`, `PrintStyle.warning`, `runtime.is_development`, `WsResult.error`, `self.broadcast`, `asyncio.sleep`, `self.emit_to`, `self.dispatch_to_all_sids`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- No direct test reference was found by name search; choose the nearest behavioral test or perform a focused smoke check. + +## Child DOX Index + +No child DOX files. diff --git a/api/ws_hello.py.dox.md b/api/ws_hello.py.dox.md new file mode 100644 index 000000000..863b99167 --- /dev/null +++ b/api/ws_hello.py.dox.md @@ -0,0 +1,44 @@ +# ws_hello.py DOX + +## Purpose + +- Own the `ws_hello.py` API endpoint. +- This module provides a small WebSocket hello/test namespace. +- Keep this file-level DOX profile synchronized with `ws_hello.py` because this directory is intentionally flat. + +## Ownership + +- `ws_hello.py` owns the runtime implementation. +- `ws_hello.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `WsHello` (`WsHandler`) + - `async process(self, event: str, data: dict, sid: str) -> dict | None` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `WsHello` is a `WsHandler`. +- `WsHello` defines `process(...)`. +- Observed side-effect areas: WebSocket state. +- Imported dependency areas include: `helpers.print_style`, `helpers.ws`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `PrintStyle.info`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- No direct test reference was found by name search; choose the nearest behavioral test or perform a focused smoke check. + +## Child DOX Index + +No child DOX files. diff --git a/api/ws_webui.py.dox.md b/api/ws_webui.py.dox.md new file mode 100644 index 000000000..a9cebf317 --- /dev/null +++ b/api/ws_webui.py.dox.md @@ -0,0 +1,49 @@ +# ws_webui.py DOX + +## Purpose + +- Own the `ws_webui.py` API endpoint. +- This module owns the primary WebUI WebSocket namespace and event bridge. +- Keep this file-level DOX profile synchronized with `ws_webui.py` because this directory is intentionally flat. + +## Ownership + +- `ws_webui.py` owns the runtime implementation. +- `ws_webui.py.dox.md` owns durable notes about responsibilities, contracts, side effects, and verification for that implementation. +- Classes: +- `WsWebui` (`WsHandler`) + - `async on_connect(self, sid: str) -> None` + - `async on_disconnect(self, sid: str) -> None` + - `async process(self, event: str, data: dict, sid: str) -> dict | None` + +## Runtime Contracts + +- HTTP handlers must derive from `helpers.api.ApiHandler`; WebSocket handlers must derive from `helpers.ws.WsHandler`. +- Update this file whenever request payloads, authentication or CSRF requirements, response shapes, route side effects, or WebSocket event contracts change. +- `WsWebui` is a `WsHandler`. +- `WsWebui` defines `process(...)`. +- Observed side-effect areas: network calls, WebSocket state, settings/state persistence. +- Imported dependency areas include: `helpers`, `helpers.ws`. + +## Key Concepts + +- Important called helpers/classes observed in the source: `extension.call_extensions_async`. +- Keep request/response, tool, or helper semantics documented here at the same time as source changes. + +## Work Guidance + +- Preserve authentication, CSRF, loopback, and API-key checks unless the endpoint contract explicitly changes. +- Update frontend callers, plugin callers, and tests together when payload shape changes. +- Use `helpers.api.Response` for non-JSON responses, files, redirects, or status-specific replies. + +## Verification + +- Run endpoint-specific or API/WebSocket tests for changed behavior; smoke-test browser callers when no focused test exists. +- Related tests observed by source search: + - `tests/test_state_sync_handler.py` + - `tests/test_state_sync_welcome_screen.py` + - `tests/test_ws_handlers.py` + +## Child DOX Index + +No child DOX files. diff --git a/conf/AGENTS.md b/conf/AGENTS.md new file mode 100644 index 000000000..14b08e363 --- /dev/null +++ b/conf/AGENTS.md @@ -0,0 +1,34 @@ +# Configuration Defaults DOX + +## Purpose + +- Own repository-shipped configuration defaults and templates. +- Keep clean-checkout defaults safe, portable, and free of user-specific state. + +## Ownership + +- `model_providers.yaml` defines built-in provider metadata and LiteLLM wiring defaults. +- `*.default.gitignore` files define templates copied or used for generated user/project/workdir directories. +- Runtime user settings belong under ignored `usr/` local state and are not documented with local DOX files. + +## Local Contracts + +- Do not commit API keys, provider secrets, local account identifiers, or private endpoints. +- Keep provider IDs and settings keys stable unless all loaders, UI references, migrations, and tests are updated. +- Defaults must work in a clean checkout and in Docker. +- Templates must avoid accidentally unignoring private runtime content. + +## Work Guidance + +- Prefer adding provider metadata here only when it is broadly useful to shipped Agent Zero. +- Keep comments concise and operational. +- Coordinate provider changes with model settings UI, plugin model overrides, and docs. + +## Verification + +- Run targeted model/provider tests after changing `model_providers.yaml`. +- Check generated ignore templates manually when changing `*.default.gitignore`. + +## Child DOX Index + +No child DOX files. diff --git a/conf/model_providers.yaml b/conf/model_providers.yaml index 12235e58f..58bb2e7cc 100644 --- a/conf/model_providers.yaml +++ b/conf/model_providers.yaml @@ -14,7 +14,7 @@ # # Optional fields: # kwargs: A dictionary of extra parameters to pass to LiteLLM. -# This is useful for `api_base`, `extra_headers`, etc. +# This is useful for `api_base`, `extra_headers`, non-secret local placeholders, etc. # # Optional model listing fields (used by the Model Configuration plugin): # models_list: @@ -83,6 +83,20 @@ chat: models_list: endpoint_url: "/v1/models" default_base: "http://host.docker.internal:1234" + kwargs: + a0_api_mode: chat + api_base: "http://host.docker.internal:1234/v1" + api_key: "lm-studio" + llama_cpp: + name: llama.cpp + litellm_provider: hosted_vllm + models_list: + endpoint_url: "/v1/models" + default_base: "http://host.docker.internal:8080" + kwargs: + a0_api_mode: chat + api_base: "http://host.docker.internal:8080/v1" + api_key: "llama-cpp" mistral: name: Mistral AI litellm_provider: mistral @@ -107,12 +121,26 @@ chat: endpoint_url: "/api/tags" format: "ollama" default_base: "http://host.docker.internal:11434" + kwargs: + a0_api_mode: chat + api_base: "http://host.docker.internal:11434" + omlx: + name: oMLX + litellm_provider: hosted_vllm + models_list: + endpoint_url: "/v1/models" + default_base: "http://host.docker.internal:8000" + kwargs: + a0_api_mode: chat + api_base: "http://host.docker.internal:8000/v1" + api_key: "omlx" ollama_cloud: name: Ollama Cloud litellm_provider: openai models_list: endpoint_url: "/models" kwargs: + a0_api_mode: chat api_base: https://ollama.com/v1 openai: name: OpenAI @@ -150,9 +178,20 @@ chat: models_list: endpoint_url: "https://api.venice.ai/api/v1/models" kwargs: + a0_api_mode: chat api_base: https://api.venice.ai/api/v1 venice_parameters: include_venice_system_prompt: false + vllm: + name: vLLM + litellm_provider: hosted_vllm + models_list: + endpoint_url: "/v1/models" + default_base: "http://host.docker.internal:8000" + kwargs: + a0_api_mode: chat + api_base: "http://host.docker.internal:8000/v1" + api_key: "vllm" xai: name: xAI litellm_provider: xai @@ -175,6 +214,8 @@ chat: other: name: Other OpenAI compatible litellm_provider: openai + kwargs: + a0_api_mode: chat embedding: huggingface: @@ -186,12 +227,29 @@ embedding: lm_studio: name: LM Studio litellm_provider: lm_studio + kwargs: + api_base: "http://host.docker.internal:1234/v1" + api_key: "lm-studio" + llama_cpp: + name: llama.cpp + litellm_provider: hosted_vllm + kwargs: + api_base: "http://host.docker.internal:8080/v1" + api_key: "llama-cpp" mistral: name: Mistral AI litellm_provider: mistral ollama: name: Ollama litellm_provider: ollama + kwargs: + api_base: "http://host.docker.internal:11434" + omlx: + name: oMLX + litellm_provider: hosted_vllm + kwargs: + api_base: "http://host.docker.internal:8000/v1" + api_key: "omlx" openai: name: OpenAI litellm_provider: openai @@ -225,6 +283,12 @@ embedding: endpoint_url: "https://api.venice.ai/api/v1/models" kwargs: api_base: https://api.venice.ai/api/v1 + vllm: + name: vLLM + litellm_provider: hosted_vllm + kwargs: + api_base: "http://host.docker.internal:8000/v1" + api_key: "vllm" other: name: Other OpenAI compatible litellm_provider: openai diff --git a/docker/AGENTS.md b/docker/AGENTS.md new file mode 100644 index 000000000..757608953 --- /dev/null +++ b/docker/AGENTS.md @@ -0,0 +1,39 @@ +# Docker DOX + +## Purpose + +- Own Docker build contexts and runtime container definitions. +- Keep framework runtime, agent execution runtime, exposed ports, mounted paths, and image build assumptions explicit. + +## Ownership + +- `base/` owns the base image context. +- `run/` owns the runnable image context and compose file. +- Root `DockerfileLocal` is owned by the root contract but must stay compatible with this directory. + +## Local Contracts + +- Preserve the two-runtime model documented in the root contract: framework runtime under `/opt/venv-a0` and agent execution runtime under `/opt/venv`. +- Do not bake secrets, local `.env` values, or user data into images. +- Keep compose mounts aligned with `usr/`, `logs/`, and other runtime-state expectations. +- Image changes that affect GitHub publishing must stay synchronized with `.github/workflows/docker-publish.yml`. + +## Work Guidance + +- Keep Dockerfile steps cache-friendly and explicit about which runtime they target. +- Avoid broad copies of ignored runtime folders. +- Update setup docs when ports, volumes, startup commands, or runtime layout change. + +## Verification + +- Build the affected Docker context when Docker behavior changes. +- Run Docker-related tests or startup smoke checks when changing runtime entrypoints. + +## Child DOX Index + +Direct child DOX files: + +| Child | Scope | +| --- | --- | +| [base/AGENTS.md](base/AGENTS.md) | Base image Dockerfile, copied filesystem, and installation scripts. | +| [run/AGENTS.md](run/AGENTS.md) | Runnable image Dockerfile, compose example, entrypoints, and install scripts. | diff --git a/docker/base/AGENTS.md b/docker/base/AGENTS.md new file mode 100644 index 000000000..bcfb986d7 --- /dev/null +++ b/docker/base/AGENTS.md @@ -0,0 +1,34 @@ +# Docker Base Image DOX + +## Purpose + +- Own the Agent Zero base image build context. +- Build the operating system, package, Python, SearXNG, SSH, and bootstrap layers reused by runnable images. + +## Ownership + +- `Dockerfile` owns base image layering and installation order. +- `build.txt` owns maintainer build and push command notes. +- `fs/ins/` owns installation scripts copied into the image. +- Files under `fs/` are copied to container root during the base build. + +## Local Contracts + +- Preserve cache-friendly package and runtime installation stages. +- Keep locale and timezone defaults compatible with the root Docker contract. +- Do not add secrets, user data, or local environment files to the image context. +- Installation scripts must be noninteractive and suitable for multi-architecture buildx runs. + +## Work Guidance + +- Keep base dependencies here only when they are common to runnable Agent Zero images. +- Coordinate Python runtime changes with root Docker documentation and runnable image setup. + +## Verification + +- Build `docker/base` when changing Dockerfile or install scripts. +- Run a runnable image smoke check when base runtime behavior changes. + +## Child DOX Index + +No child DOX files. diff --git a/docker/run/AGENTS.md b/docker/run/AGENTS.md new file mode 100644 index 000000000..b5607ae69 --- /dev/null +++ b/docker/run/AGENTS.md @@ -0,0 +1,39 @@ +# Docker Runtime Image DOX + +## Purpose + +- Own the runnable Agent Zero image context and local compose example. +- Install Agent Zero from a selected branch onto the base image and prepare runtime entrypoints. + +## Ownership + +- `Dockerfile` owns branch-based image assembly, exposed ports, and container startup command. +- `docker-compose.yml` owns the local compose service example. +- `build.txt` owns maintainer build and push command notes. +- `fs/exe/` owns runtime entrypoint, supervisor, self-update, Node eval, and service scripts. +- `fs/ins/` owns preinstall, installation, virtualenv, Playwright, SSH, and postinstall scripts. +- Files under `fs/` are copied to container root during the runtime build. + +## Local Contracts + +- `BRANCH` is required for branch-based Docker builds. +- Preserve exposed ports for SSH, HTTP, and tunneled services unless docs and workflows are updated together. +- Keep the two-runtime Python model aligned with the root contract. +- Do not bake secrets, local `.env` values, or user data into the image. +- Runtime startup must ensure `/a0/usr/uploads` exists before supervised services start. +- Runtime startup raises the soft open-file limit toward `A0_NOFILE_LIMIT` (default `65535`) before supervisord starts, bounded by the container hard limit. +- Self-update user-data backups skip Time Travel shadow history under `usr/.time_travel/` and transient Desktop agent state. + +## Work Guidance + +- Keep startup scripts explicit about framework runtime versus execution runtime. +- Coordinate tag, branch, and publishing changes with GitHub workflow automation. + +## Verification + +- Build `docker/run` when changing Dockerfile or install scripts. +- Smoke-test container startup after entrypoint, supervisor, port, or compose changes. + +## Child DOX Index + +No child DOX files. diff --git a/docker/run/docker-compose.yml b/docker/run/docker-compose.yml index cc48f3f1b..b80da0272 100644 --- a/docker/run/docker-compose.yml +++ b/docker/run/docker-compose.yml @@ -5,4 +5,10 @@ services: volumes: - ./agent-zero:/a0 ports: - - "50080:80" \ No newline at end of file + - "50080:80" + ulimits: + nofile: + soft: 65535 + hard: 65535 + extra_hosts: + - "host.docker.internal:host-gateway" diff --git a/docker/run/fs/exe/initialize.sh b/docker/run/fs/exe/initialize.sh index 8c329bb30..f4c4dcd25 100644 --- a/docker/run/fs/exe/initialize.sh +++ b/docker/run/fs/exe/initialize.sh @@ -9,9 +9,49 @@ if [ -z "$1" ]; then fi BRANCH="$1" +raise_open_file_limit() { + local requested="${A0_NOFILE_LIMIT:-65535}" + local soft + local hard + local target + + if ! [[ "$requested" =~ ^[0-9]+$ ]] || [ "$requested" -lt 1 ]; then + echo "Warning: invalid A0_NOFILE_LIMIT='$requested'; keeping open file limit at $(ulimit -S -n)." >&2 + return + fi + + soft="$(ulimit -S -n)" + hard="$(ulimit -H -n)" + + if [ "$soft" = "unlimited" ]; then + echo "Open file limit is already unlimited." + return + fi + + target="$requested" + if [ "$hard" != "unlimited" ] && [ "$target" -gt "$hard" ]; then + target="$hard" + fi + + if [ "$target" -gt "$soft" ]; then + if ulimit -S -n "$target"; then + echo "Raised open file soft limit from $soft to $(ulimit -S -n) (hard: $hard)." + else + echo "Warning: failed to raise open file soft limit from $soft to $target (hard: $hard)." >&2 + fi + else + echo "Open file soft limit is $soft (target: $requested, hard: $hard)." + fi +} + +raise_open_file_limit + # Copy all contents from persistent /per to root directory (/) without overwriting cp -r --no-preserve=ownership,mode /per/* / +# Ensure upload storage exists before API and connector callers can reference it. +mkdir -p /a0/usr/uploads + # allow execution of /root/.bashrc and /root/.profile chmod 444 /root/.bashrc chmod 444 /root/.profile diff --git a/docker/run/fs/exe/self_update_manager.py b/docker/run/fs/exe/self_update_manager.py index a1917bc31..4ae23ce28 100644 --- a/docker/run/fs/exe/self_update_manager.py +++ b/docker/run/fs/exe/self_update_manager.py @@ -46,6 +46,11 @@ DEFAULT_BACKUP_CONFLICT_POLICY = "rename" BACKUP_CONFLICT_POLICIES = {"rename", "overwrite", "fail"} MIN_SELECTOR_VERSION = (1, 0) LATEST_SELECTOR_TAG = "latest" +DESKTOP_PROFILE_STATE_RELATIVE_DIRS = ( + Path("usr/plugins/_desktop/profiles"), + Path("usr/_desktop/profiles"), + Path("tmp/_office/desktop/profiles"), +) def now_iso() -> str: @@ -400,6 +405,11 @@ def should_exclude_from_usr_backup( logger: AttemptLogger, ) -> bool: parts = relative_dir.parts + if parts and parts[0] == ".time_travel": + logger.log( + f"Skipping Time Travel history during usr backup: {Path('usr') / relative_dir}" + ) + return True if ( len(parts) >= 6 and parts[0] == "plugins" @@ -448,6 +458,138 @@ def should_include_usr_backup_entry(source_file: Path, logger: AttemptLogger) -> return True +def clean_transient_desktop_agent_state( + repo_dir: Path, + logger: AttemptLogger, +) -> None: + profile_roots = 0 + removed = 0 + for relative_root in DESKTOP_PROFILE_STATE_RELATIVE_DIRS: + profile_root = repo_dir / relative_root + if not _is_cleanup_directory( + profile_root, + logger, + "Desktop profile state", + missing_ok=True, + ): + continue + profile_roots += 1 + try: + profiles = list(profile_root.iterdir()) + except OSError as exc: + logger.log(f"Desktop profile state could not be listed: {profile_root}: {exc}") + continue + for profile_dir in profiles: + if not _is_cleanup_directory(profile_dir, logger, "Desktop profile"): + continue + removed += _clean_directory_entries( + profile_dir / ".ssh" / "agent", + logger, + label="desktop SSH agent", + ) + removed += _clean_gnupg_agent_entries(profile_dir / ".gnupg", logger) + + if removed: + logger.log(f"Removed {removed} transient desktop agent entries.") + elif profile_roots: + logger.log("Transient desktop agent state already clean.") + else: + logger.log("No desktop profile runtime state found, skipping transient agent cleanup.") + + +def _clean_gnupg_agent_entries(gnupg_dir: Path, logger: AttemptLogger) -> int: + if not _is_cleanup_directory(gnupg_dir, logger, "desktop GnuPG state", missing_ok=True): + return 0 + try: + entries = list(gnupg_dir.iterdir()) + except OSError as exc: + logger.log(f"Desktop GnuPG state could not be listed: {gnupg_dir}: {exc}") + return 0 + + removed = 0 + for entry in entries: + if not entry.name.startswith("S.gpg-agent"): + continue + try: + entry_stat = entry.lstat() + except FileNotFoundError: + continue + except OSError as exc: + logger.log(f"Skipping transient desktop GnuPG agent entry after stat error: {entry}: {exc}") + continue + if stat.S_ISREG(entry_stat.st_mode): + continue + if _remove_cleanup_entry(entry, entry_stat, logger, label="desktop GnuPG agent"): + removed += 1 + return removed + + +def _clean_directory_entries(directory: Path, logger: AttemptLogger, *, label: str) -> int: + if not _is_cleanup_directory(directory, logger, label, missing_ok=True): + return 0 + try: + entries = list(directory.iterdir()) + except OSError as exc: + logger.log(f"Transient {label} directory could not be listed: {directory}: {exc}") + return 0 + + removed = 0 + for entry in entries: + try: + entry_stat = entry.lstat() + except FileNotFoundError: + continue + except OSError as exc: + logger.log(f"Skipping transient {label} entry after stat error: {entry}: {exc}") + continue + if _remove_cleanup_entry(entry, entry_stat, logger, label=label): + removed += 1 + return removed + + +def _is_cleanup_directory( + directory: Path, + logger: AttemptLogger, + label: str, + *, + missing_ok: bool = False, +) -> bool: + try: + directory_stat = directory.lstat() + except FileNotFoundError: + if not missing_ok: + logger.log(f"{label} directory not found, skipping: {directory}") + return False + except OSError as exc: + logger.log(f"{label} directory could not be inspected: {directory}: {exc}") + return False + + if stat.S_ISLNK(directory_stat.st_mode) or not stat.S_ISDIR(directory_stat.st_mode): + logger.log(f"{label} path is not a directory, skipping: {directory}") + return False + return True + + +def _remove_cleanup_entry( + entry: Path, + entry_stat: os.stat_result, + logger: AttemptLogger, + *, + label: str, +) -> bool: + try: + if stat.S_ISDIR(entry_stat.st_mode): + shutil.rmtree(entry) + else: + entry.unlink(missing_ok=True) + return True + except FileNotFoundError: + return False + except OSError as exc: + logger.log(f"Skipping transient {label} entry after error: {entry}: {exc}") + return False + + def run_command( command: list[str], *, @@ -1266,6 +1408,10 @@ def docker_run_ui() -> int: logger.log(f"Consumed update file at {TRIGGER_FILE}") logger.log_block("Trigger file content", raw_text) clean_uv_cache(logger) + try: + clean_transient_desktop_agent_state(REPO_DIR, logger) + except Exception as exc: + logger.log(f"Transient desktop agent cleanup skipped after error: {exc}") try: current = get_repo_version_info(REPO_DIR) diff --git a/docker/run/fs/ins/install_A0.sh b/docker/run/fs/ins/install_A0.sh index 0aeaf13ff..7b5d0d807 100644 --- a/docker/run/fs/ins/install_A0.sh +++ b/docker/run/fs/ins/install_A0.sh @@ -36,8 +36,6 @@ fi # Install remaining A0 python packages uv pip install -r /git/agent-zero/requirements.txt -# override for packages that have unnecessarily strict dependencies -uv pip install -r /git/agent-zero/requirements2.txt # install playwright bash /ins/install_playwright.sh "$@" diff --git a/docker/run/fs/ins/install_additional.sh b/docker/run/fs/ins/install_additional.sh index 31546deaa..e9c844be7 100644 --- a/docker/run/fs/ins/install_additional.sh +++ b/docker/run/fs/ins/install_additional.sh @@ -46,16 +46,11 @@ install_xpra_repo() { apt-get update if ! xpra_install_check; then - if [ "$arch" != "amd64" ]; then - echo "xpra packages are not installable from ${uri} ${suite} for ${arch}; falling back to https://xpra.org trixie" - XPRA_PACKAGES=(xpra-server xpra-x11 xpra-html5) - configure_xpra_repo "https://xpra.org" "trixie" "$arch" - apt-get update - if ! xpra_install_check; then - cat /tmp/xpra-install-check.log - exit 1 - fi - else + echo "xpra packages are not installable from ${uri} ${suite} for ${arch}; falling back to https://xpra.org trixie" + XPRA_PACKAGES=(xpra-server xpra-x11 xpra-html5) + configure_xpra_repo "https://xpra.org" "trixie" "$arch" + apt-get update + if ! xpra_install_check; then cat /tmp/xpra-install-check.log exit 1 fi diff --git a/docs/AGENTS.md b/docs/AGENTS.md new file mode 100644 index 000000000..c81fb55bd --- /dev/null +++ b/docs/AGENTS.md @@ -0,0 +1,35 @@ +# Documentation DOX + +## Purpose + +- Own human-facing documentation, screenshots, setup guides, developer guides, and documentation assets. +- Keep docs accurate to current source behavior and practical user workflows. + +## Ownership + +- `README.md`, `quickstart.md`, `guides/`, and `setup/` cover user-facing setup and workflows. +- `developer/` covers compact developer references and source handoffs. +- `plans/` covers implementation plans, migration notes, and staged technical roadmaps. +- `res/` contains documentation images and other documentation assets. + +## Local Contracts + +- Prefer local docs for practical workflows and direct users to DeepWiki for source-linked internals when appropriate. +- Do not document secrets, private deployment details, unreleased credentials, or user-specific runtime state. +- Screenshots and assets must be relevant to the documented UI state and should be updated when UI changes make them misleading. +- Keep links relative inside the docs tree unless they intentionally point to external community or reference resources. + +## Work Guidance + +- Update docs in the same change when user-visible behavior, setup steps, settings names, plugin workflows, or UI labels change. +- Keep user guides task-oriented and avoid duplicating architecture contracts already owned by source-adjacent DOX files. +- When editing screenshots or binary assets, avoid unrelated metadata churn. + +## Verification + +- Check changed internal links manually or with an available link checker. +- For setup or Docker docs, verify commands against current scripts and Docker files. + +## Child DOX Index + +No child DOX files. diff --git a/docs/README.md b/docs/README.md index 655dc0e44..5c668f029 100644 --- a/docs/README.md +++ b/docs/README.md @@ -12,8 +12,9 @@ docs focus on practical setup, screenshots, and user workflows. ## Quick Start - **[Quickstart Guide](quickstart.md):** Get up and running in 5 minutes with Agent Zero. -- **[First-Run Onboarding](guides/onboarding.md):** Choose Cloud or Local, add a provider key, and select main and utility models. -- **[Installation Guide](setup/installation.md):** Install scripts, updates, and advanced Docker setup (includes [How to Update](setup/installation.md#how-to-update-agent-zero)). +- **[Agent Zero Launcher](guides/launcher.md):** Use the desktop app to set up Docker, install Agent Zero, open Instances, or connect a remote Instance. +- **[First-Run Onboarding](guides/onboarding.md):** Choose Cloud, AI account, or Local access, then select main and utility models. +- **[Installation Guide](setup/installation.md):** A0 Launcher downloads, A0 Install, direct Docker, updates, and advanced Docker setup (includes [How to Update](setup/installation.md#how-to-update-agent-zero)). - **[A0 CLI Connector](guides/a0-cli-connector.md):** Install the host connector for a running Agent Zero instance, use the command palette, and switch Browser modes. - **[Self Update](guides/self-update.md):** How the in-app updater works (technical reference). - **[VPS Deployment](setup/vps-deployment.md):** Deploy Agent Zero on a remote server. @@ -22,12 +23,13 @@ docs focus on practical setup, screenshots, and user workflows. ## User Guides - **[Usage Guide](guides/usage.md):** Practical tour of Agent Zero's main workflows. +- **[Agent Zero Launcher](guides/launcher.md):** Fresh-machine Launcher walkthrough, Docker setup gate, Installs, Instances, and docs screenshot capture with Playwright/Electron. - **[First-Run Onboarding](guides/onboarding.md):** Set up OpenRouter, our proxy API or another provider with the guided wizard. - **[Browser Guide](guides/browser.md):** Use the built-in Browser, live Canvas surface, annotations, screenshots, host browser mode, and extensions. - **[Desktop Guide](guides/desktop.md):** Use the built-in Linux desktop, GUI apps, and LibreOffice Writer/Calc/Impress Cowork. - **[A0 CLI Connector](guides/a0-cli-connector.md):** Terminal-first host connector for Agent Zero, with screenshots of the host picker, connected shell, command palette, and Browser modes. - **[Create a Small Plugin](guides/create-plugin.md):** Build and review a tiny Web UI plugin that adds an unread dot to the chat list. -- **[Skills Guide](guides/skills.md):** Open the Skills selector, add active skills, and remove prompt extras you no longer need. +- **[Skills Guide](guides/skills.md):** Open the Skills selector, add active skills, and remove prompt protocol entries you no longer need. - **[Agent Profiles](guides/agent-profiles.md):** Switch the current chat profile or create a new guided profile from the chat input. - **[Model Presets](guides/model-presets.md):** Create simple named shortcuts for model setups. - **[Memory Guide](guides/memory.md):** Search, edit, delete, and curate memories so useful context does not become stale noise. @@ -63,6 +65,7 @@ docs focus on practical setup, screenshots, and user workflows. - [Quick Start](#quick-start) - [Quickstart Guide](quickstart.md) + - [Agent Zero Launcher](guides/launcher.md) - [First-Run Onboarding](guides/onboarding.md) - [Installation Guide](setup/installation.md) - [How to Update Agent Zero](setup/installation.md#how-to-update-agent-zero) @@ -113,6 +116,7 @@ docs focus on practical setup, screenshots, and user workflows. - [File Browser](guides/usage.md#file-browser) - [Memory Management](guides/usage.md#memory-management) - [Backup And Restore](guides/usage.md#backup-and-restore) + - [Agent Zero Launcher](guides/launcher.md) - [Browser Guide](guides/browser.md) - [Desktop Guide](guides/desktop.md) - [A0 CLI Connector](guides/a0-cli-connector.md) diff --git a/docs/agents/AGENTS.banners.md b/docs/agents/AGENTS.banners.md deleted file mode 100644 index b5c65f115..000000000 --- a/docs/agents/AGENTS.banners.md +++ /dev/null @@ -1,95 +0,0 @@ -# Creating Discovery Cards and Banners - -Agent Zero allows plugin developers to surface UI elements using the `banners` extension point. This allows your plugin to present information, prompts, or actionable "discovery cards" directly on the Welcome Screen without needing to inject arbitrary HTML into the frontend. - -## The `banners` Extension Point - -Banners are collected on the backend and sent to the frontend UI as an array of dictionaries. By appending to the `banners` array inside a Python extension, you can easily surface your plugin to the user. - -To inject a banner, you create a Python extension script hooking into `banners`. - -### Where to put your extension script - -Create a python file in your plugin's extensions folder: -`plugins//extensions/python/banners/10_my_plugin_banner.py` - -*(Note: the `10_` prefix is for ordering; extensions run in alphabetical order).* - -## Banner Types - -The UI distinguishes banners primarily by the `type` property. - -### 1. Alert Banners (`info`, `warning`, `error`) -These are standard top-level alerts displayed on the welcome screen. - -```python -banners.append({ - "id": "my-plugin-warning", - "type": "warning", - "priority": 90, - "title": "My Plugin Issue", - "html": "Action required: Please configure your settings.", - "dismissible": True, -}) -``` - -### 2. Discovery Cards (`hero`, `feature`) -These are rich, interactive cards displayed in the Discovery section. They are designed to prompt the user to try new plugins or features. - -* `hero`: A wide, prominent card. Usually reserved for core system features (e.g., the Plugin Hub). -* `feature`: A smaller card in a grid layout. This is the **recommended type** for plugin contributors to showcase their plugin. - -### Anatomy of a Discovery Card - -Here is an example of injecting a `feature` card for a custom plugin: - -```python -from helpers.extension import Extension -from helpers import plugins - -class MyPluginDiscoveryCard(Extension): - """Injects a discovery card for My Custom Plugin.""" - - async def execute(self, banners: list = [], frontend_context: dict = {}, **kwargs): - # 1. Condition Check - # Only show the discovery card if the user hasn't configured the plugin yet. - config = plugins.get_plugin_config("my_custom_plugin") or {} - - # If the API key is already set, we don't need to advertise the setup! - if config.get("api_key"): - return - - # 2. Add the Card - banners.append({ - "id": "discovery-my-custom-plugin", - "type": "feature", # 'feature' or 'hero' - "title": "Connect My Service", # Card title - "description": "Unlock amazing capabilities by linking your account.", - - # Visuals (use either thumbnail OR icon) - "thumbnail": "/plugins/my_custom_plugin/assets/thumb.png", # Path to image - "icon": "bolt", # Or a Material Symbol icon name - - # Call To Action (CTA) - "cta_text": "Setup Now", - "cta_action": "open-plugin-config:my_custom_plugin", # Opens your plugin's config modal - - # Behavior - "dismissible": True, # Let the user hide it - "priority": 40, # Higher numbers appear first - }) -``` - -## Call To Action (CTA) Actions - -When a user clicks the button on a discovery card, the `cta_action` string determines what happens. The frontend currently supports the following actions: - -* `open-plugin-config:`: Automatically opens the settings modal for the specified plugin. (e.g., `open-plugin-config:_telegram_integration`). -* `open-plugin-hub`: Opens the main Plugin Hub UI. -* `open-url:`: Opens a web link in a new browser tab. (e.g., `open-url:https://example.com/docs`). - -## Best Practices - -1. **Check Configuration First**: Always check your plugin's configuration before injecting a card. If the user has already set up your plugin, they shouldn't keep seeing a discovery card asking them to set it up. -2. **Unique IDs**: Ensure your banner `id` is highly unique (e.g., prefix it with your plugin name) to avoid collisions with other plugins. -3. **Use `feature` type**: Community plugins should stick to the `feature` type rather than `hero` to ensure a clean grid layout for users. \ No newline at end of file diff --git a/docs/agents/AGENTS.components.md b/docs/agents/AGENTS.components.md deleted file mode 100644 index 31d564609..000000000 --- a/docs/agents/AGENTS.components.md +++ /dev/null @@ -1,648 +0,0 @@ -# Agent Zero Component System - -> Generated from codebase reconnaissance on 2026-01-10 -> Scope: `webui/components/` - Self-contained Alpine.js component architecture - -## Quick Reference - -| Aspect | Value | -|--------|-------| -| Tech Stack | Alpine.js, ES Modules, CSS Variables | -| Component Tag | `` | -| State Management | `createStore(name, model)` from `/js/AlpineStore.js` | -| Modals | `openModal(path)` / `closeModal()` from `/js/modals.js` | -| API Layer | `callJsonApi()` / `fetchApi()` from `/js/api.js` | - ---- - -## Table of Contents - -1. [Architecture Overview](#1-architecture-overview) -2. [Component Structure](#2-component-structure) -3. [Store Pattern](#3-store-pattern) -4. [Lifecycle Management](#4-lifecycle-management) -5. [Integration Layer](#5-integration-layer) -6. [Alpine.js Directives](#6-alpinejs-directives) -7. [Patterns and Conventions](#7-patterns-and-conventions) -8. [Pitfalls and Anti-Patterns](#8-pitfalls-and-anti-patterns) -9. [Porting Guide](#9-porting-guide) - ---- - -## 1. Architecture Overview - -### Core Files (Integration Layer) - -| File | Purpose | -|------|---------| -| `/js/components.js` | Component loader - hydrates `` tags | -| `/js/AlpineStore.js` | Store factory with Alpine proxy | -| `/js/modals.js` | Modal stack management | -| `/js/initFw.js` | Bootstrap: loads Alpine, registers custom directives | -| `/js/api.js` | CSRF-protected API client (`callJsonApi`, `fetchApi`) | - -### Component Resolution - -``` - - ↓ - Resolves to: components/sidebar/left-sidebar.html - ↓ - Loader: importComponent() fetches, parses, injects -``` - -- Path auto-prefixes `components/` if not present -- Component HTML cached after first fetch -- Module scripts cached by virtual URL -- MutationObserver auto-loads dynamically inserted components - -### Data Flow - -``` -Component HTML - ↓ -imports Store module - ↓ -createStore() registers with Alpine - ↓ -Template binds via $store.name - ↓ -User actions → store methods → state updates → reactive UI -``` - ---- - -## 2. Component Structure - -### Anatomy of a Component - -```html - - - - - - - - -
- -
- - - - - -``` - -### Key Rules - -| Rule | Rationale | -|------|-----------| -| Scripts in ``, content in `` | Loader extracts separately | -| Use `type="module"` for scripts | Enables ES imports, caching | -| Wrap with `x-data` + `x-if="$store.X"` | Prevents render before store ready | -| `