{"owner":"OpenBMB","repo":"UltraRAG","hasSkills":true,"hasMcp":true,"mcpConfig":{"mcpServers":{"UltraRAG":{"command":"npx","args":["-y","@modelcontextprotocol/server-UltraRAG"]}}},"found":["AGENTS.md"],"skills":{"AGENTS.md":"# AGENTS.md\n\nThis document is the primary engineering guide for autonomous coding agents working in the `UltraRAG` repository.\n\nUse this file as the source of truth for architecture, conventions, workflows, and safe change patterns.\nIf `CLAUDE.md` exists, it should only point to this file.\n\n---\n\n## 1) Project Identity\n\n`UltraRAG` is a lightweight RAG framework built around the Model Context Protocol (MCP).\nThe key design choice is strict modularization: retrieval, prompting, generation, routing, memory, and evaluation are implemented as independent MCP servers orchestrated by YAML pipelines.\n\nCurrent core metadata:\n\n- Package: `ultrarag`\n- Version: `0.3.0`\n- Python: `>=3.11, <3.13`\n- CLI entrypoint: `ultrarag = ultrarag.client:main`\n- Package manager: `uv` (`[tool.uv] package = true`)\n\n---\n\n## 2) Repository Map (What Matters Most)\n\n```text\nUltraRAG/\n├── src/ultrarag/                    # Installable core package\n│   ├── client.py                    # CLI + pipeline engine + run/build orchestration\n│   ├── server.py                    # UltraRAG_MCP_Server (FastMCP extension)\n│   ├── api.py                       # Python API wrappers (ToolCall, PipelineCall)\n│   ├── cli.py                       # Rich banner and CLI visuals\n│   ├── mcp_logging.py               # Central logging setup\n│   ├── mcp_exceptions.py            # Node.js checks for remote MCP\n│   └── utils.py                     # Subprocess lifecycle helpers\n│\n├── servers/                         # MCP microservices (each server is independent)\n│   ├── retriever/\n│   ├── generation/\n│   ├── prompt/\n│   ├── reranker/\n│   ├── benchmark/\n│   ├── evaluation/\n│   ├── corpus/\n│   ├── memory/\n│   ├── router/\n│   ├── custom/\n│   ├── pageindex/\n│   └── sayhello/\n│\n├── examples/\n│   ├── demos/                       # UI-ready demo pipelines\n│   └── experiments/                 # Experiment/research pipelines\n│\n├── ui/\n│   ├── backend/                     # Flask backend + pipeline manager\n│   └── frontend/                    # Vite + React + TypeScript\n│\n├── docs/                            # Docs and assets\n├── script/                          # Utility scripts (deploy, case study, etc.)\n├── pyproject.toml                   # Dependencies + package metadata\n├── uv.lock                          # Locked dependency graph\n├── Dockerfile*                      # Container variants\n└── .gitignore\n```\n\nImportant generated/derived files:\n\n- `servers/*/server.yaml` (generated by each server `build` tool)\n- `examples/**/parameter/*_parameter.yaml` (pipeline-merged parameters)\n- `examples/**/server/*_server.yaml` (pipeline-merged server config)\n- `output/memory_*.json` (per-run memory snapshots)\n\n---\n\n## 3) Mental Model of the System\n\nThink of UltraRAG as a three-layer system:\n\n1. **Interface layer**: CLI (`ultrarag ...`), UI (`ultrarag show ui`), and Python API (`ToolCall`, `PipelineCall`)\n2. **Orchestration layer**: `src/ultrarag/client.py` (`build`, `load_pipeline_context`, `execute_pipeline`)\n3. **Execution layer**: MCP servers in `servers/*`, each exposing tools/prompts over stdio (or remote MCP proxy)\n\nThe runtime contract is:\n\n- A pipeline YAML declares **which servers** to use and **which steps** to execute.\n- The client resolves I/O dependencies between steps.\n- Each step calls exactly one MCP tool or prompt.\n- Outputs are saved to a shared variable pool and can feed downstream steps.\n\n---\n\n## 4) Two-Phase Execution Lifecycle\n\n### Phase A: Build\n\nCommand:\n\n```bash\nultrarag build <pipeline.yaml>\n```\n\nWhat happens:\n\n- Reads `servers:` from the pipeline YAML.\n- For each referenced server, calls the server's `build` tool.\n- Produces:\n  - `<pipeline_dir>/parameter/<pipeline_name>_parameter.yaml`\n  - `<pipeline_dir>/server/<pipeline_name>_server.yaml`\n\nWhy this matters:\n\n- `build` materializes exact tool/prompt I/O metadata before runtime.\n- UI and runner rely on these generated artifacts for deterministic execution.\n\n### Phase B: Run\n\nCommand:\n\n```bash\nultrarag run <pipeline.yaml> [--param path] [--is_demo]\n```\n\nWhat happens:\n\n- Loads generated server config + parameter config.\n- Creates `fastmcp.Client` transport config for each server.\n- Executes pipeline steps in order, including `loop` and `branch`.\n- Saves intermediate memory snapshots and writes `output/memory_*.json`.\n- Invokes cleanup tools (e.g., tools ending with `vllm_shutdown`) if present.\n\n---\n\n## 5) Pipeline DSL Reference\n\nUltraRAG accepts mixed step forms:\n\n### 5.1 Plain step\n\n```yaml\n- retriever.retriever_search\n```\n\n### 5.2 Step with input/output remapping\n\n```yaml\n- generation.generate:\n    input:\n      prompt_ls: custom_prompt_ls\n    output:\n      ans_ls: final_answer_ls\n```\n\n### 5.3 Loop block\n\n```yaml\n- loop:\n    times: 3\n    steps:\n    - retriever.retriever_search\n    - generation.generate\n```\n\n### 5.4 Branch block\n\n```yaml\n- branch:\n    router:\n    - router.route_query\n    branches:\n      need_retrieval:\n      - retriever.retriever_search\n      direct_answer:\n      - generation.generate\n```\n\n### 5.5 Prompt vs Tool step semantics\n\n- Steps under the `prompt` server call `client.get_prompt(...)`.\n- Non-prompt steps call `client.call_tool(...)`.\n\n---\n\n## 6) Variable Resolution and Data Flow Rules\n\nIn `UltraData`, each tool input value is interpreted by convention:\n\n- `\"$foo\"` -> load from server-local params (`parameter.yaml`)\n- `\"bar\"`  -> read from global variable pool (`global_vars[\"bar\"]`)\n- `\"memory_xxx\"` -> read/write memory lists\n\nOutput handling:\n\n- Tool returns JSON payload -> keys mapped to declared outputs\n- Output remapping (`output:` in pipeline step) is applied at save time\n- Prompt outputs usually produce `prompt_ls`\n\nBranch handling:\n\n- Branch-aware values use wrapped list records with branch-state keys.\n- Internal sentinel (`UNSET`) is used to distinguish \"not filled yet\" from `None`.\n\nMemory handling:\n\n- The engine tracks `memory_*` histories automatically.\n- Final snapshots are serialized to `output/memory_<...>.json`.\n- If a memory server is detected, turn-level memory auto-save can be triggered.\n\n---\n\n## 7) Core Python Modules (Authoritative Guide)\n\n### `src/ultrarag/client.py`\n\nThis is the orchestration heart of the project.\n\nKey responsibilities:\n\n- CLI entrypoint (`main`)\n- UI launch (`launch_ui`) and case-study launch (`launch_case_study`)\n- Config loading (`Configuration`)\n- Pipeline data graph and state (`UltraData`)\n- Build pipeline configs (`build`)\n- Load runtime context (`load_pipeline_context`)\n- Execute step engine (`execute_pipeline`)\n- Run full pipeline (`run`)\n\nImportant runtime behaviors:\n\n- Supports both local python MCP servers (`path.endswith(\".py\")`) and remote MCP endpoints (`http(s)`).\n- For remote MCP, requires Node.js >= 20 and uses `npx -y mcp-remote <url>`.\n- Keeps loop-termination state in `ContextVar` for coroutine safety.\n- Emits structured stream events in demo/UI flows (`step_start`, `step_end`, `token`, `sources`).\n\n### `src/ultrarag/server.py`\n\nDefines `UltraRAG_MCP_Server`, a compatibility wrapper over FastMCP.\n\nKey responsibilities:\n\n- Enhanced `tool()` and `prompt()` registration with `output` metadata support\n- Metadata capture for automatic config generation\n- `build(parameter_file)` to generate per-server `server.yaml`\n- Compatibility filtering for FastMCP signature differences\n\n### `src/ultrarag/api.py`\n\nProvides ergonomic Python-side wrappers:\n\n- `initialize(servers, server_root, log_level)`\n- `ToolCall.server_name.tool_name(...)`\n- `PipelineCall(pipeline_file, parameter_file, log_level)`\n\n### `src/ultrarag/mcp_logging.py`\n\n- Initializes root logger `UltraRAG`\n- Rich console logging + file logging (`logs/<timestamp>.log`)\n- Log level controlled by `log_level` argument and environment\n\n### `src/ultrarag/mcp_exceptions.py`\n\n- Validates local Node.js availability/version\n- Raises `NodeNotInstalledError` / `NodeVersionTooLowError`\n\n### `src/ultrarag/utils.py`\n\n- Subprocess lifecycle helpers\n- POSIX parent-death signal support\n- Windows job object support for child-process cleanup\n\n---\n\n## 8) MCP Server Authoring Contract\n\nEach server follows this shape:\n\n```text\nservers/<name>/\n├── parameter.yaml\n├── server.yaml            # generated\n└── src/<name>.py\n```\n\n### 8.1 Registration styles\n\nUse either:\n\n1. Decorator style\n2. Class-bound method registration style\n\nBoth are valid in this codebase.\n\n### 8.2 `output=` grammar\n\nCanonical form:\n\n```text\ninput1,input2,$param_a -> output1,output2\n```\n\nRules:\n\n- Left side maps function args to pipeline inputs.\n- Right side defines expected output keys from returned dict/JSON.\n- `-> None` means no output variables.\n- `$param` means value comes from server parameter file.\n\n### 8.3 Return payload expectations\n\n- For tools: return JSON-serializable dict payloads matching declared output keys.\n- For prompts: return prompt messages (typically list-like prompt payloads consumed by `get_prompt`).\n\n### 8.4 Entrypoint requirement\n\nServer modules should end with:\n\n```python\nif __name__ == \"__main__\":\n    app.run(transport=\"stdio\")\n```\n\n---\n\n## 9) Retriever/Generation/Prompt Specific Notes\n\n### Retriever (`servers/retriever`)\n\n- Supports multiple retrieval modes:\n  - Dense retrieval\n  - BM25\n  - Web search\n  - Project-memory retrieval\n- Index backends are pluggable via factory:\n  - `faiss`\n  - `milvus`\n- Web search backends are pluggable via factory:\n  - `exa`\n  - `tavily`\n  - `zhipuai`\n\n### Generation (`servers/generation`)\n\n- Supports generation backends including `openai`, `vllm`, and hf workflows.\n- Provides explicit cleanup tool `vllm_shutdown`.\n- Demo mode can use local streaming generation service.\n\n### Prompt (`servers/prompt`)\n\n- Uses `SandboxedEnvironment` from Jinja2 for safer rendering.\n- Validates template paths to reduce traversal risk.\n- Escapes string inputs before template rendering.\n\n---\n\n## 10) UI Backend Architecture (`ui/backend`)\n\n### `app.py`\n\n- Flask app factory (`create_app`)\n- Serves frontend static assets\n- Exposes chat/pipeline/KB/auth endpoints\n- Reads optional frontend override via `ULTRARAG_FRONTEND_DIR`\n\n### `pipeline_manager.py`\n\nThis module is large and central to UI behavior.\n\nMajor responsibilities:\n\n- Session lifecycle and streaming chat management\n- Background chat task management\n- Pipeline CRUD (list/load/save/rename/delete)\n- Parameter load/save/build wrappers\n- Knowledge base file ingest and pipeline triggering\n- Memory synchronization to per-user KB collections\n- Optional server introspection via AST stub generation if `server.yaml` is missing\n\nNotable behavior:\n\n- Applies defensive patches to suppress noisy closed-event-loop teardown logs.\n- Uses a queue bridge for async-to-sync SSE event streaming.\n- Supports automatic memory-to-KB sync for pipelines that include memory components.\n\n---\n\n## 11) Storage Model and Paths\n\nDefault UI storage root:\n\n- `ui/storage`\n\nCan be overridden by:\n\n- `ULTRARAG_UI_STORAGE_ROOT`\n\nKey subpaths:\n\n- `db/users.sqlite3`\n- `chat_sessions/`\n- `knowledge_base/raw|corpus|chunks|index`\n- `memory/`\n- `knowledge_base/_memory_sync`\n\nRuntime outputs:\n\n- `output/memory_*.json`\n- `logs/*.log`\n\n---\n\n## 12) Environment Variables You Should Know\n\n- `ULTRARAG_UI_STORAGE_ROOT`: override UI storage root\n- `ULTRARAG_FRONTEND_DIR`: override frontend static directory\n- `ULTRARAG_SESSION_TIMEOUT`: foreground chat session timeout\n- `ULTRARAG_BG_SESSION_TIMEOUT`: background session timeout\n- `ULTRARAG_LOG_TS`: custom timestamp seed for log file naming\n- `log_level`: consumed by core logger initialization\n\n---\n\n## 13) Dependency Model\n\nInstall tiers from `pyproject.toml`:\n\n- Core install: no extras\n- `retriever` extra\n- `generation` extra\n- `evaluation` extra\n- `corpus` extra\n- `all` extra (union)\n\nTypical commands:\n\n```bash\nuv sync\nuv sync --extra retriever\nuv sync --extra generation\nuv sync --all-extras\n```\n\nDevelopment dependencies include:\n\n- `ruff`\n- `ipython`\n- `jupyter`\n- `pytest`\n\n---\n\n## 14) CLI Commands (Canonical)\n\n```bash\nultrarag build <pipeline.yaml>\nultrarag run <pipeline.yaml> [--param <parameter.yaml>] [--log_level info|debug|warn|error] [--is_demo]\nultrarag show ui [--host 127.0.0.1] [--port 5050]\nultrarag show case [--config_path <memory.json>] [--host 127.0.0.1] [--port 8080]\n```\n\nMinimal smoke check:\n\n```bash\nultrarag run examples/experiments/sayhello.yaml\n```\n\n---\n\n## 15) Docker Variants\n\n- `Dockerfile`: full image (builds frontend, installs all extras)\n- `Dockerfile.base-cpu`: CPU base image\n- `Dockerfile.base-gpu`: GPU base image\n\nAll variants start UI with:\n\n```bash\nultrarag show ui --port 5050 --host 0.0.0.0\n```\n\n---\n\n## 16) Development Playbooks\n\n### 16.1 Add a new MCP server\n\n1. Create `servers/<name>/parameter.yaml`\n2. Implement `servers/<name>/src/<name>.py`\n3. Register tools/prompts via `app.tool` / `app.prompt` (or class-bound registration)\n4. Ensure `app.run(transport=\"stdio\")` exists\n5. Add server to `servers:` in a pipeline YAML\n6. Run `ultrarag build <pipeline.yaml>`\n\n### 16.2 Add a new tool to an existing server\n\n1. Implement function/method\n2. Register with explicit `output=...` contract\n3. Ensure return payload keys match outputs\n4. Update relevant parameter keys in `parameter.yaml` if using `$...`\n5. Add the step in pipeline YAML and rebuild\n\n### 16.3 Add a retriever index backend\n\n1. Implement backend in `servers/retriever/src/index_backends/`\n2. Follow `BaseIndexBackend` contract\n3. Register in `_INDEX_BACKENDS` map in `index_backends/__init__.py`\n\n### 16.4 Add a web-search backend\n\n1. Implement backend in `servers/retriever/src/websearch_backends/`\n2. Follow `BaseWebSearchBackend` contract\n3. Register in `_WEBSEARCH_BACKENDS` map\n\n### 16.5 Modify UI pipeline behavior\n\nPrimary files:\n\n- `ui/backend/app.py`\n- `ui/backend/pipeline_manager.py`\n\nIf touching build/runtime semantics, cross-check against:\n\n- `src/ultrarag/client.py`\n\n---\n\n## 17) Coding Standards (Repository-Conformant)\n\n- Use type hints for function signatures.\n- Prefer `pathlib.Path` for filesystem paths.\n- Use `yaml.safe_load` / `yaml.safe_dump`.\n- Use project logger (`get_logger` or `app.logger`) instead of `print`.\n- Keep tool outputs deterministic and JSON-serializable.\n- Keep imports grouped: stdlib -> third-party -> local.\n- Keep async boundaries explicit (`async`/`await`).\n\n---\n\n## 18) What Not To Edit Blindly\n\nTreat these as generated or runtime artifacts unless intentionally regenerating:\n\n- `servers/*/server.yaml`\n- `examples/**/parameter/*_parameter.yaml`\n- `examples/**/server/*_server.yaml`\n- `output/*`\n- `logs/*`\n- `ui/storage/*` runtime data\n\nAlso avoid committing secrets:\n\n- `.env`\n- any credential-bearing local config\n\n---\n\n## 19) Common Failure Modes and Fixes\n\n### Error: server file not found\n\n- Check `servers.<name>` path in pipeline YAML.\n- Ensure server entry script exists at `servers/<name>/src/<name>.py` (or update path in config).\n\n### Error: missing variable in pipeline execution\n\n- Verify output key names from upstream tool match downstream input names.\n- Verify remapping under step-level `output:` is correct.\n- Verify `$param` keys exist in that server's parameter config.\n\n### Remote MCP server fails to start\n\n- Ensure Node.js >= 20.\n- Confirm `npx` is available.\n- Confirm remote URL in server path is reachable.\n\n### Build succeeds but UI cannot list tools\n\n- Ensure `server.yaml` exists or can be inferred by AST parsing.\n- Check for unusual dynamic registration patterns that static analysis cannot infer.\n\n### No final answer in chat\n\n- Inspect `output/memory_*.json`.\n- Check whether generation step ran and produced `ans_ls`.\n- Check stream events in UI path (`step_start`, `step_end`, `sources`, `token`, `final`).\n\n---\n\n## 20) Validation Checklist for Agents\n\nBefore finalizing any non-trivial change:\n\n1. Build the affected pipeline:\n   - `ultrarag build <pipeline.yaml>`\n2. Run a relevant smoke case:\n   - `ultrarag run <pipeline.yaml>`\n3. If UI behavior changed:\n   - run `ultrarag show ui` and verify route behavior\n4. If retriever/generation backends changed:\n   - validate parameter schema keys and output names\n5. Keep generated artifacts intentional:\n   - do not accidentally commit transient runtime outputs\n\n---\n\n## 21) Minimal Quickstart for New Agents\n\n```bash\n# 1) Install dependencies\nuv sync --all-extras\n\n# 2) Smoke test\nultrarag run examples/experiments/sayhello.yaml\n\n# 3) Build and run a demo pipeline\nultrarag build examples/demos/LLM.yaml\nultrarag run examples/demos/LLM.yaml\n\n# 4) Launch UI\nultrarag show ui --host 127.0.0.1 --port 5050\n```\n\n---\n\n## 22) Final Notes\n\n- This repository is orchestration-first: correctness depends heavily on I/O naming consistency across tools and pipeline steps.\n- Most regressions come from mismatched variable names, stale generated configs, or incomplete parameter updates.\n- When in doubt, inspect `src/ultrarag/client.py` first: it is the execution truth.\n"},"files":{"AGENTS.md":"# AGENTS.md\n\nThis document is the primary engineering guide for autonomous coding agents working in the `UltraRAG` repository.\n\nUse this file as the source of truth for architecture, conventions, workflows, and safe change patterns.\nIf `CLAUDE.md` exists, it should only point to this file.\n\n---\n\n## 1) Project Identity\n\n`UltraRAG` is a lightweight RAG framework built around the Model Context Protocol (MCP).\nThe key design choice is strict modularization: retrieval, prompting, generation, routing, memory, and evaluation are implemented as independent MCP servers orchestrated by YAML pipelines.\n\nCurrent core metadata:\n\n- Package: `ultrarag`\n- Version: `0.3.0`\n- Python: `>=3.11, <3.13`\n- CLI entrypoint: `ultrarag = ultrarag.client:main`\n- Package manager: `uv` (`[tool.uv] package = true`)\n\n---\n\n## 2) Repository Map (What Matters Most)\n\n```text\nUltraRAG/\n├── src/ultrarag/                    # Installable core package\n│   ├── client.py                    # CLI + pipeline engine + run/build orchestration\n│   ├── server.py                    # UltraRAG_MCP_Server (FastMCP extension)\n│   ├── api.py                       # Python API wrappers (ToolCall, PipelineCall)\n│   ├── cli.py                       # Rich banner and CLI visuals\n│   ├── mcp_logging.py               # Central logging setup\n│   ├── mcp_exceptions.py            # Node.js checks for remote MCP\n│   └── utils.py                     # Subprocess lifecycle helpers\n│\n├── servers/                         # MCP microservices (each server is independent)\n│   ├── retriever/\n│   ├── generation/\n│   ├── prompt/\n│   ├── reranker/\n│   ├── benchmark/\n│   ├── evaluation/\n│   ├── corpus/\n│   ├── memory/\n│   ├── router/\n│   ├── custom/\n│   ├── pageindex/\n│   └── sayhello/\n│\n├── examples/\n│   ├── demos/                       # UI-ready demo pipelines\n│   └── experiments/                 # Experiment/research pipelines\n│\n├── ui/\n│   ├── backend/                     # Flask backend + pipeline manager\n│   └── frontend/                    # Vite + React + TypeScript\n│\n├── docs/                            # Docs and assets\n├── script/                          # Utility scripts (deploy, case study, etc.)\n├── pyproject.toml                   # Dependencies + package metadata\n├── uv.lock                          # Locked dependency graph\n├── Dockerfile*                      # Container variants\n└── .gitignore\n```\n\nImportant generated/derived files:\n\n- `servers/*/server.yaml` (generated by each server `build` tool)\n- `examples/**/parameter/*_parameter.yaml` (pipeline-merged parameters)\n- `examples/**/server/*_server.yaml` (pipeline-merged server config)\n- `output/memory_*.json` (per-run memory snapshots)\n\n---\n\n## 3) Mental Model of the System\n\nThink of UltraRAG as a three-layer system:\n\n1. **Interface layer**: CLI (`ultrarag ...`), UI (`ultrarag show ui`), and Python API (`ToolCall`, `PipelineCall`)\n2. **Orchestration layer**: `src/ultrarag/client.py` (`build`, `load_pipeline_context`, `execute_pipeline`)\n3. **Execution layer**: MCP servers in `servers/*`, each exposing tools/prompts over stdio (or remote MCP proxy)\n\nThe runtime contract is:\n\n- A pipeline YAML declares **which servers** to use and **which steps** to execute.\n- The client resolves I/O dependencies between steps.\n- Each step calls exactly one MCP tool or prompt.\n- Outputs are saved to a shared variable pool and can feed downstream steps.\n\n---\n\n## 4) Two-Phase Execution Lifecycle\n\n### Phase A: Build\n\nCommand:\n\n```bash\nultrarag build <pipeline.yaml>\n```\n\nWhat happens:\n\n- Reads `servers:` from the pipeline YAML.\n- For each referenced server, calls the server's `build` tool.\n- Produces:\n  - `<pipeline_dir>/parameter/<pipeline_name>_parameter.yaml`\n  - `<pipeline_dir>/server/<pipeline_name>_server.yaml`\n\nWhy this matters:\n\n- `build` materializes exact tool/prompt I/O metadata before runtime.\n- UI and runner rely on these generated artifacts for deterministic execution.\n\n### Phase B: Run\n\nCommand:\n\n```bash\nultrarag run <pipeline.yaml> [--param path] [--is_demo]\n```\n\nWhat happens:\n\n- Loads generated server config + parameter config.\n- Creates `fastmcp.Client` transport config for each server.\n- Executes pipeline steps in order, including `loop` and `branch`.\n- Saves intermediate memory snapshots and writes `output/memory_*.json`.\n- Invokes cleanup tools (e.g., tools ending with `vllm_shutdown`) if present.\n\n---\n\n## 5) Pipeline DSL Reference\n\nUltraRAG accepts mixed step forms:\n\n### 5.1 Plain step\n\n```yaml\n- retriever.retriever_search\n```\n\n### 5.2 Step with input/output remapping\n\n```yaml\n- generation.generate:\n    input:\n      prompt_ls: custom_prompt_ls\n    output:\n      ans_ls: final_answer_ls\n```\n\n### 5.3 Loop block\n\n```yaml\n- loop:\n    times: 3\n    steps:\n    - retriever.retriever_search\n    - generation.generate\n```\n\n### 5.4 Branch block\n\n```yaml\n- branch:\n    router:\n    - router.route_query\n    branches:\n      need_retrieval:\n      - retriever.retriever_search\n      direct_answer:\n      - generation.generate\n```\n\n### 5.5 Prompt vs Tool step semantics\n\n- Steps under the `prompt` server call `client.get_prompt(...)`.\n- Non-prompt steps call `client.call_tool(...)`.\n\n---\n\n## 6) Variable Resolution and Data Flow Rules\n\nIn `UltraData`, each tool input value is interpreted by convention:\n\n- `\"$foo\"` -> load from server-local params (`parameter.yaml`)\n- `\"bar\"`  -> read from global variable pool (`global_vars[\"bar\"]`)\n- `\"memory_xxx\"` -> read/write memory lists\n\nOutput handling:\n\n- Tool returns JSON payload -> keys mapped to declared outputs\n- Output remapping (`output:` in pipeline step) is applied at save time\n- Prompt outputs usually produce `prompt_ls`\n\nBranch handling:\n\n- Branch-aware values use wrapped list records with branch-state keys.\n- Internal sentinel (`UNSET`) is used to distinguish \"not filled yet\" from `None`.\n\nMemory handling:\n\n- The engine tracks `memory_*` histories automatically.\n- Final snapshots are serialized to `output/memory_<...>.json`.\n- If a memory server is detected, turn-level memory auto-save can be triggered.\n\n---\n\n## 7) Core Python Modules (Authoritative Guide)\n\n### `src/ultrarag/client.py`\n\nThis is the orchestration heart of the project.\n\nKey responsibilities:\n\n- CLI entrypoint (`main`)\n- UI launch (`launch_ui`) and case-study launch (`launch_case_study`)\n- Config loading (`Configuration`)\n- Pipeline data graph and state (`UltraData`)\n- Build pipeline configs (`build`)\n- Load runtime context (`load_pipeline_context`)\n- Execute step engine (`execute_pipeline`)\n- Run full pipeline (`run`)\n\nImportant runtime behaviors:\n\n- Supports both local python MCP servers (`path.endswith(\".py\")`) and remote MCP endpoints (`http(s)`).\n- For remote MCP, requires Node.js >= 20 and uses `npx -y mcp-remote <url>`.\n- Keeps loop-termination state in `ContextVar` for coroutine safety.\n- Emits structured stream events in demo/UI flows (`step_start`, `step_end`, `token`, `sources`).\n\n### `src/ultrarag/server.py`\n\nDefines `UltraRAG_MCP_Server`, a compatibility wrapper over FastMCP.\n\nKey responsibilities:\n\n- Enhanced `tool()` and `prompt()` registration with `output` metadata support\n- Metadata capture for automatic config generation\n- `build(parameter_file)` to generate per-server `server.yaml`\n- Compatibility filtering for FastMCP signature differences\n\n### `src/ultrarag/api.py`\n\nProvides ergonomic Python-side wrappers:\n\n- `initialize(servers, server_root, log_level)`\n- `ToolCall.server_name.tool_name(...)`\n- `PipelineCall(pipeline_file, parameter_file, log_level)`\n\n### `src/ultrarag/mcp_logging.py`\n\n- Initializes root logger `UltraRAG`\n- Rich console logging + file logging (`logs/<timestamp>.log`)\n- Log level controlled by `log_level` argument and environment\n\n### `src/ultrarag/mcp_exceptions.py`\n\n- Validates local Node.js availability/version\n- Raises `NodeNotInstalledError` / `NodeVersionTooLowError`\n\n### `src/ultrarag/utils.py`\n\n- Subprocess lifecycle helpers\n- POSIX parent-death signal support\n- Windows job object support for child-process cleanup\n\n---\n\n## 8) MCP Server Authoring Contract\n\nEach server follows this shape:\n\n```text\nservers/<name>/\n├── parameter.yaml\n├── server.yaml            # generated\n└── src/<name>.py\n```\n\n### 8.1 Registration styles\n\nUse either:\n\n1. Decorator style\n2. Class-bound method registration style\n\nBoth are valid in this codebase.\n\n### 8.2 `output=` grammar\n\nCanonical form:\n\n```text\ninput1,input2,$param_a -> output1,output2\n```\n\nRules:\n\n- Left side maps function args to pipeline inputs.\n- Right side defines expected output keys from returned dict/JSON.\n- `-> None` means no output variables.\n- `$param` means value comes from server parameter file.\n\n### 8.3 Return payload expectations\n\n- For tools: return JSON-serializable dict payloads matching declared output keys.\n- For prompts: return prompt messages (typically list-like prompt payloads consumed by `get_prompt`).\n\n### 8.4 Entrypoint requirement\n\nServer modules should end with:\n\n```python\nif __name__ == \"__main__\":\n    app.run(transport=\"stdio\")\n```\n\n---\n\n## 9) Retriever/Generation/Prompt Specific Notes\n\n### Retriever (`servers/retriever`)\n\n- Supports multiple retrieval modes:\n  - Dense retrieval\n  - BM25\n  - Web search\n  - Project-memory retrieval\n- Index backends are pluggable via factory:\n  - `faiss`\n  - `milvus`\n- Web search backends are pluggable via factory:\n  - `exa`\n  - `tavily`\n  - `zhipuai`\n\n### Generation (`servers/generation`)\n\n- Supports generation backends including `openai`, `vllm`, and hf workflows.\n- Provides explicit cleanup tool `vllm_shutdown`.\n- Demo mode can use local streaming generation service.\n\n### Prompt (`servers/prompt`)\n\n- Uses `SandboxedEnvironment` from Jinja2 for safer rendering.\n- Validates template paths to reduce traversal risk.\n- Escapes string inputs before template rendering.\n\n---\n\n## 10) UI Backend Architecture (`ui/backend`)\n\n### `app.py`\n\n- Flask app factory (`create_app`)\n- Serves frontend static assets\n- Exposes chat/pipeline/KB/auth endpoints\n- Reads optional frontend override via `ULTRARAG_FRONTEND_DIR`\n\n### `pipeline_manager.py`\n\nThis module is large and central to UI behavior.\n\nMajor responsibilities:\n\n- Session lifecycle and streaming chat management\n- Background chat task management\n- Pipeline CRUD (list/load/save/rename/delete)\n- Parameter load/save/build wrappers\n- Knowledge base file ingest and pipeline triggering\n- Memory synchronization to per-user KB collections\n- Optional server introspection via AST stub generation if `server.yaml` is missing\n\nNotable behavior:\n\n- Applies defensive patches to suppress noisy closed-event-loop teardown logs.\n- Uses a queue bridge for async-to-sync SSE event streaming.\n- Supports automatic memory-to-KB sync for pipelines that include memory components.\n\n---\n\n## 11) Storage Model and Paths\n\nDefault UI storage root:\n\n- `ui/storage`\n\nCan be overridden by:\n\n- `ULTRARAG_UI_STORAGE_ROOT`\n\nKey subpaths:\n\n- `db/users.sqlite3`\n- `chat_sessions/`\n- `knowledge_base/raw|corpus|chunks|index`\n- `memory/`\n- `knowledge_base/_memory_sync`\n\nRuntime outputs:\n\n- `output/memory_*.json`\n- `logs/*.log`\n\n---\n\n## 12) Environment Variables You Should Know\n\n- `ULTRARAG_UI_STORAGE_ROOT`: override UI storage root\n- `ULTRARAG_FRONTEND_DIR`: override frontend static directory\n- `ULTRARAG_SESSION_TIMEOUT`: foreground chat session timeout\n- `ULTRARAG_BG_SESSION_TIMEOUT`: background session timeout\n- `ULTRARAG_LOG_TS`: custom timestamp seed for log file naming\n- `log_level`: consumed by core logger initialization\n\n---\n\n## 13) Dependency Model\n\nInstall tiers from `pyproject.toml`:\n\n- Core install: no extras\n- `retriever` extra\n- `generation` extra\n- `evaluation` extra\n- `corpus` extra\n- `all` extra (union)\n\nTypical commands:\n\n```bash\nuv sync\nuv sync --extra retriever\nuv sync --extra generation\nuv sync --all-extras\n```\n\nDevelopment dependencies include:\n\n- `ruff`\n- `ipython`\n- `jupyter`\n- `pytest`\n\n---\n\n## 14) CLI Commands (Canonical)\n\n```bash\nultrarag build <pipeline.yaml>\nultrarag run <pipeline.yaml> [--param <parameter.yaml>] [--log_level info|debug|warn|error] [--is_demo]\nultrarag show ui [--host 127.0.0.1] [--port 5050]\nultrarag show case [--config_path <memory.json>] [--host 127.0.0.1] [--port 8080]\n```\n\nMinimal smoke check:\n\n```bash\nultrarag run examples/experiments/sayhello.yaml\n```\n\n---\n\n## 15) Docker Variants\n\n- `Dockerfile`: full image (builds frontend, installs all extras)\n- `Dockerfile.base-cpu`: CPU base image\n- `Dockerfile.base-gpu`: GPU base image\n\nAll variants start UI with:\n\n```bash\nultrarag show ui --port 5050 --host 0.0.0.0\n```\n\n---\n\n## 16) Development Playbooks\n\n### 16.1 Add a new MCP server\n\n1. Create `servers/<name>/parameter.yaml`\n2. Implement `servers/<name>/src/<name>.py`\n3. Register tools/prompts via `app.tool` / `app.prompt` (or class-bound registration)\n4. Ensure `app.run(transport=\"stdio\")` exists\n5. Add server to `servers:` in a pipeline YAML\n6. Run `ultrarag build <pipeline.yaml>`\n\n### 16.2 Add a new tool to an existing server\n\n1. Implement function/method\n2. Register with explicit `output=...` contract\n3. Ensure return payload keys match outputs\n4. Update relevant parameter keys in `parameter.yaml` if using `$...`\n5. Add the step in pipeline YAML and rebuild\n\n### 16.3 Add a retriever index backend\n\n1. Implement backend in `servers/retriever/src/index_backends/`\n2. Follow `BaseIndexBackend` contract\n3. Register in `_INDEX_BACKENDS` map in `index_backends/__init__.py`\n\n### 16.4 Add a web-search backend\n\n1. Implement backend in `servers/retriever/src/websearch_backends/`\n2. Follow `BaseWebSearchBackend` contract\n3. Register in `_WEBSEARCH_BACKENDS` map\n\n### 16.5 Modify UI pipeline behavior\n\nPrimary files:\n\n- `ui/backend/app.py`\n- `ui/backend/pipeline_manager.py`\n\nIf touching build/runtime semantics, cross-check against:\n\n- `src/ultrarag/client.py`\n\n---\n\n## 17) Coding Standards (Repository-Conformant)\n\n- Use type hints for function signatures.\n- Prefer `pathlib.Path` for filesystem paths.\n- Use `yaml.safe_load` / `yaml.safe_dump`.\n- Use project logger (`get_logger` or `app.logger`) instead of `print`.\n- Keep tool outputs deterministic and JSON-serializable.\n- Keep imports grouped: stdlib -> third-party -> local.\n- Keep async boundaries explicit (`async`/`await`).\n\n---\n\n## 18) What Not To Edit Blindly\n\nTreat these as generated or runtime artifacts unless intentionally regenerating:\n\n- `servers/*/server.yaml`\n- `examples/**/parameter/*_parameter.yaml`\n- `examples/**/server/*_server.yaml`\n- `output/*`\n- `logs/*`\n- `ui/storage/*` runtime data\n\nAlso avoid committing secrets:\n\n- `.env`\n- any credential-bearing local config\n\n---\n\n## 19) Common Failure Modes and Fixes\n\n### Error: server file not found\n\n- Check `servers.<name>` path in pipeline YAML.\n- Ensure server entry script exists at `servers/<name>/src/<name>.py` (or update path in config).\n\n### Error: missing variable in pipeline execution\n\n- Verify output key names from upstream tool match downstream input names.\n- Verify remapping under step-level `output:` is correct.\n- Verify `$param` keys exist in that server's parameter config.\n\n### Remote MCP server fails to start\n\n- Ensure Node.js >= 20.\n- Confirm `npx` is available.\n- Confirm remote URL in server path is reachable.\n\n### Build succeeds but UI cannot list tools\n\n- Ensure `server.yaml` exists or can be inferred by AST parsing.\n- Check for unusual dynamic registration patterns that static analysis cannot infer.\n\n### No final answer in chat\n\n- Inspect `output/memory_*.json`.\n- Check whether generation step ran and produced `ans_ls`.\n- Check stream events in UI path (`step_start`, `step_end`, `sources`, `token`, `final`).\n\n---\n\n## 20) Validation Checklist for Agents\n\nBefore finalizing any non-trivial change:\n\n1. Build the affected pipeline:\n   - `ultrarag build <pipeline.yaml>`\n2. Run a relevant smoke case:\n   - `ultrarag run <pipeline.yaml>`\n3. If UI behavior changed:\n   - run `ultrarag show ui` and verify route behavior\n4. If retriever/generation backends changed:\n   - validate parameter schema keys and output names\n5. Keep generated artifacts intentional:\n   - do not accidentally commit transient runtime outputs\n\n---\n\n## 21) Minimal Quickstart for New Agents\n\n```bash\n# 1) Install dependencies\nuv sync --all-extras\n\n# 2) Smoke test\nultrarag run examples/experiments/sayhello.yaml\n\n# 3) Build and run a demo pipeline\nultrarag build examples/demos/LLM.yaml\nultrarag run examples/demos/LLM.yaml\n\n# 4) Launch UI\nultrarag show ui --host 127.0.0.1 --port 5050\n```\n\n---\n\n## 22) Final Notes\n\n- This repository is orchestration-first: correctness depends heavily on I/O naming consistency across tools and pipeline steps.\n- Most regressions come from mismatched variable names, stale generated configs, or incomplete parameter updates.\n- When in doubt, inspect `src/ultrarag/client.py` first: it is the execution truth.\n"},"items":[{"name":"AGENTS.md","path":"AGENTS.md","title":"AGENTS.md","content":"# AGENTS.md\n\nThis document is the primary engineering guide for autonomous coding agents working in the `UltraRAG` repository.\n\nUse this file as the source of truth for architecture, conventions, workflows, and safe change patterns.\nIf `CLAUDE.md` exists, it should only point to this file.\n\n---\n\n## 1) Project Identity\n\n`UltraRAG` is a lightweight RAG framework built around the Model Context Protocol (MCP).\nThe key design choice is strict modularization: retrieval, prompting, generation, routing, memory, and evaluation are implemented as independent MCP servers orchestrated by YAML pipelines.\n\nCurrent core metadata:\n\n- Package: `ultrarag`\n- Version: `0.3.0`\n- Python: `>=3.11, <3.13`\n- CLI entrypoint: `ultrarag = ultrarag.client:main`\n- Package manager: `uv` (`[tool.uv] package = true`)\n\n---\n\n## 2) Repository Map (What Matters Most)\n\n```text\nUltraRAG/\n├── src/ultrarag/                    # Installable core package\n│   ├── client.py                    # CLI + pipeline engine + run/build orchestration\n│   ├── server.py                    # UltraRAG_MCP_Server (FastMCP extension)\n│   ├── api.py                       # Python API wrappers (ToolCall, PipelineCall)\n│   ├── cli.py                       # Rich banner and CLI visuals\n│   ├── mcp_logging.py               # Central logging setup\n│   ├── mcp_exceptions.py            # Node.js checks for remote MCP\n│   └── utils.py                     # Subprocess lifecycle helpers\n│\n├── servers/                         # MCP microservices (each server is independent)\n│   ├── retriever/\n│   ├── generation/\n│   ├── prompt/\n│   ├── reranker/\n│   ├── benchmark/\n│   ├── evaluation/\n│   ├── corpus/\n│   ├── memory/\n│   ├── router/\n│   ├── custom/\n│   ├── pageindex/\n│   └── sayhello/\n│\n├── examples/\n│   ├── demos/                       # UI-ready demo pipelines\n│   └── experiments/                 # Experiment/research pipelines\n│\n├── ui/\n│   ├── backend/                     # Flask backend + pipeline manager\n│   └── frontend/                    # Vite + React + TypeScript\n│\n├── docs/                            # Docs and assets\n├── script/                          # Utility scripts (deploy, case study, etc.)\n├── pyproject.toml                   # Dependencies + package metadata\n├── uv.lock                          # Locked dependency graph\n├── Dockerfile*                      # Container variants\n└── .gitignore\n```\n\nImportant generated/derived files:\n\n- `servers/*/server.yaml` (generated by each server `build` tool)\n- `examples/**/parameter/*_parameter.yaml` (pipeline-merged parameters)\n- `examples/**/server/*_server.yaml` (pipeline-merged server config)\n- `output/memory_*.json` (per-run memory snapshots)\n\n---\n\n## 3) Mental Model of the System\n\nThink of UltraRAG as a three-layer system:\n\n1. **Interface layer**: CLI (`ultrarag ...`), UI (`ultrarag show ui`), and Python API (`ToolCall`, `PipelineCall`)\n2. **Orchestration layer**: `src/ultrarag/client.py` (`build`, `load_pipeline_context`, `execute_pipeline`)\n3. **Execution layer**: MCP servers in `servers/*`, each exposing tools/prompts over stdio (or remote MCP proxy)\n\nThe runtime contract is:\n\n- A pipeline YAML declares **which servers** to use and **which steps** to execute.\n- The client resolves I/O dependencies between steps.\n- Each step calls exactly one MCP tool or prompt.\n- Outputs are saved to a shared variable pool and can feed downstream steps.\n\n---\n\n## 4) Two-Phase Execution Lifecycle\n\n### Phase A: Build\n\nCommand:\n\n```bash\nultrarag build <pipeline.yaml>\n```\n\nWhat happens:\n\n- Reads `servers:` from the pipeline YAML.\n- For each referenced server, calls the server's `build` tool.\n- Produces:\n  - `<pipeline_dir>/parameter/<pipeline_name>_parameter.yaml`\n  - `<pipeline_dir>/server/<pipeline_name>_server.yaml`\n\nWhy this matters:\n\n- `build` materializes exact tool/prompt I/O metadata before runtime.\n- UI and runner rely on these generated artifacts for deterministic execution.\n\n### Phase B: Run\n\nCommand:\n\n```bash\nultrarag run <pipeline.yaml> [--param path] [--is_demo]\n```\n\nWhat happens:\n\n- Loads generated server config + parameter config.\n- Creates `fastmcp.Client` transport config for each server.\n- Executes pipeline steps in order, including `loop` and `branch`.\n- Saves intermediate memory snapshots and writes `output/memory_*.json`.\n- Invokes cleanup tools (e.g., tools ending with `vllm_shutdown`) if present.\n\n---\n\n## 5) Pipeline DSL Reference\n\nUltraRAG accepts mixed step forms:\n\n### 5.1 Plain step\n\n```yaml\n- retriever.retriever_search\n```\n\n### 5.2 Step with input/output remapping\n\n```yaml\n- generation.generate:\n    input:\n      prompt_ls: custom_prompt_ls\n    output:\n      ans_ls: final_answer_ls\n```\n\n### 5.3 Loop block\n\n```yaml\n- loop:\n    times: 3\n    steps:\n    - retriever.retriever_search\n    - generation.generate\n```\n\n### 5.4 Branch block\n\n```yaml\n- branch:\n    router:\n    - router.route_query\n    branches:\n      need_retrieval:\n      - retriever.retriever_search\n      direct_answer:\n      - generation.generate\n```\n\n### 5.5 Prompt vs Tool step semantics\n\n- Steps under the `prompt` server call `client.get_prompt(...)`.\n- Non-prompt steps call `client.call_tool(...)`.\n\n---\n\n## 6) Variable Resolution and Data Flow Rules\n\nIn `UltraData`, each tool input value is interpreted by convention:\n\n- `\"$foo\"` -> load from server-local params (`parameter.yaml`)\n- `\"bar\"`  -> read from global variable pool (`global_vars[\"bar\"]`)\n- `\"memory_xxx\"` -> read/write memory lists\n\nOutput handling:\n\n- Tool returns JSON payload -> keys mapped to declared outputs\n- Output remapping (`output:` in pipeline step) is applied at save time\n- Prompt outputs usually produce `prompt_ls`\n\nBranch handling:\n\n- Branch-aware values use wrapped list records with branch-state keys.\n- Internal sentinel (`UNSET`) is used to distinguish \"not filled yet\" from `None`.\n\nMemory handling:\n\n- The engine tracks `memory_*` histories automatically.\n- Final snapshots are serialized to `output/memory_<...>.json`.\n- If a memory server is detected, turn-level memory auto-save can be triggered.\n\n---\n\n## 7) Core Python Modules (Authoritative Guide)\n\n### `src/ultrarag/client.py`\n\nThis is the orchestration heart of the project.\n\nKey responsibilities:\n\n- CLI entrypoint (`main`)\n- UI launch (`launch_ui`) and case-study launch (`launch_case_study`)\n- Config loading (`Configuration`)\n- Pipeline data graph and state (`UltraData`)\n- Build pipeline configs (`build`)\n- Load runtime context (`load_pipeline_context`)\n- Execute step engine (`execute_pipeline`)\n- Run full pipeline (`run`)\n\nImportant runtime behaviors:\n\n- Supports both local python MCP servers (`path.endswith(\".py\")`) and remote MCP endpoints (`http(s)`).\n- For remote MCP, requires Node.js >= 20 and uses `npx -y mcp-remote <url>`.\n- Keeps loop-termination state in `ContextVar` for coroutine safety.\n- Emits structured stream events in demo/UI flows (`step_start`, `step_end`, `token`, `sources`).\n\n### `src/ultrarag/server.py`\n\nDefines `UltraRAG_MCP_Server`, a compatibility wrapper over FastMCP.\n\nKey responsibilities:\n\n- Enhanced `tool()` and `prompt()` registration with `output` metadata support\n- Metadata capture for automatic config generation\n- `build(parameter_file)` to generate per-server `server.yaml`\n- Compatibility filtering for FastMCP signature differences\n\n### `src/ultrarag/api.py`\n\nProvides ergonomic Python-side wrappers:\n\n- `initialize(servers, server_root, log_level)`\n- `ToolCall.server_name.tool_name(...)`\n- `PipelineCall(pipeline_file, parameter_file, log_level)`\n\n### `src/ultrarag/mcp_logging.py`\n\n- Initializes root logger `UltraRAG`\n- Rich console logging + file logging (`logs/<timestamp>.log`)\n- Log level controlled by `log_level` argument and environment\n\n### `src/ultrarag/mcp_exceptions.py`\n\n- Validates local Node.js availability/version\n- Raises `NodeNotInstalledError` / `NodeVersionTooLowError`\n\n### `src/ultrarag/utils.py`\n\n- Subprocess lifecycle helpers\n- POSIX parent-death signal support\n- Windows job object support for child-process cleanup\n\n---\n\n## 8) MCP Server Authoring Contract\n\nEach server follows this shape:\n\n```text\nservers/<name>/\n├── parameter.yaml\n├── server.yaml            # generated\n└── src/<name>.py\n```\n\n### 8.1 Registration styles\n\nUse either:\n\n1. Decorator style\n2. Class-bound method registration style\n\nBoth are valid in this codebase.\n\n### 8.2 `output=` grammar\n\nCanonical form:\n\n```text\ninput1,input2,$param_a -> output1,output2\n```\n\nRules:\n\n- Left side maps function args to pipeline inputs.\n- Right side defines expected output keys from returned dict/JSON.\n- `-> None` means no output variables.\n- `$param` means value comes from server parameter file.\n\n### 8.3 Return payload expectations\n\n- For tools: return JSON-serializable dict payloads matching declared output keys.\n- For prompts: return prompt messages (typically list-like prompt payloads consumed by `get_prompt`).\n\n### 8.4 Entrypoint requirement\n\nServer modules should end with:\n\n```python\nif __name__ == \"__main__\":\n    app.run(transport=\"stdio\")\n```\n\n---\n\n## 9) Retriever/Generation/Prompt Specific Notes\n\n### Retriever (`servers/retriever`)\n\n- Supports multiple retrieval modes:\n  - Dense retrieval\n  - BM25\n  - Web search\n  - Project-memory retrieval\n- Index backends are pluggable via factory:\n  - `faiss`\n  - `milvus`\n- Web search backends are pluggable via factory:\n  - `exa`\n  - `tavily`\n  - `zhipuai`\n\n### Generation (`servers/generation`)\n\n- Supports generation backends including `openai`, `vllm`, and hf workflows.\n- Provides explicit cleanup tool `vllm_shutdown`.\n- Demo mode can use local streaming generation service.\n\n### Prompt (`servers/prompt`)\n\n- Uses `SandboxedEnvironment` from Jinja2 for safer rendering.\n- Validates template paths to reduce traversal risk.\n- Escapes string inputs before template rendering.\n\n---\n\n## 10) UI Backend Architecture (`ui/backend`)\n\n### `app.py`\n\n- Flask app factory (`create_app`)\n- Serves frontend static assets\n- Exposes chat/pipeline/KB/auth endpoints\n- Reads optional frontend override via `ULTRARAG_FRONTEND_DIR`\n\n### `pipeline_manager.py`\n\nThis module is large and central to UI behavior.\n\nMajor responsibilities:\n\n- Session lifecycle and streaming chat management\n- Background chat task management\n- Pipeline CRUD (list/load/save/rename/delete)\n- Parameter load/save/build wrappers\n- Knowledge base file ingest and pipeline triggering\n- Memory synchronization to per-user KB collections\n- Optional server introspection via AST stub generation if `server.yaml` is missing\n\nNotable behavior:\n\n- Applies defensive patches to suppress noisy closed-event-loop teardown logs.\n- Uses a queue bridge for async-to-sync SSE event streaming.\n- Supports automatic memory-to-KB sync for pipelines that include memory components.\n\n---\n\n## 11) Storage Model and Paths\n\nDefault UI storage root:\n\n- `ui/storage`\n\nCan be overridden by:\n\n- `ULTRARAG_UI_STORAGE_ROOT`\n\nKey subpaths:\n\n- `db/users.sqlite3`\n- `chat_sessions/`\n- `knowledge_base/raw|corpus|chunks|index`\n- `memory/`\n- `knowledge_base/_memory_sync`\n\nRuntime outputs:\n\n- `output/memory_*.json`\n- `logs/*.log`\n\n---\n\n## 12) Environment Variables You Should Know\n\n- `ULTRARAG_UI_STORAGE_ROOT`: override UI storage root\n- `ULTRARAG_FRONTEND_DIR`: override frontend static directory\n- `ULTRARAG_SESSION_TIMEOUT`: foreground chat session timeout\n- `ULTRARAG_BG_SESSION_TIMEOUT`: background session timeout\n- `ULTRARAG_LOG_TS`: custom timestamp seed for log file naming\n- `log_level`: consumed by core logger initialization\n\n---\n\n## 13) Dependency Model\n\nInstall tiers from `pyproject.toml`:\n\n- Core install: no extras\n- `retriever` extra\n- `generation` extra\n- `evaluation` extra\n- `corpus` extra\n- `all` extra (union)\n\nTypical commands:\n\n```bash\nuv sync\nuv sync --extra retriever\nuv sync --extra generation\nuv sync --all-extras\n```\n\nDevelopment dependencies include:\n\n- `ruff`\n- `ipython`\n- `jupyter`\n- `pytest`\n\n---\n\n## 14) CLI Commands (Canonical)\n\n```bash\nultrarag build <pipeline.yaml>\nultrarag run <pipeline.yaml> [--param <parameter.yaml>] [--log_level info|debug|warn|error] [--is_demo]\nultrarag show ui [--host 127.0.0.1] [--port 5050]\nultrarag show case [--config_path <memory.json>] [--host 127.0.0.1] [--port 8080]\n```\n\nMinimal smoke check:\n\n```bash\nultrarag run examples/experiments/sayhello.yaml\n```\n\n---\n\n## 15) Docker Variants\n\n- `Dockerfile`: full image (builds frontend, installs all extras)\n- `Dockerfile.base-cpu`: CPU base image\n- `Dockerfile.base-gpu`: GPU base image\n\nAll variants start UI with:\n\n```bash\nultrarag show ui --port 5050 --host 0.0.0.0\n```\n\n---\n\n## 16) Development Playbooks\n\n### 16.1 Add a new MCP server\n\n1. Create `servers/<name>/parameter.yaml`\n2. Implement `servers/<name>/src/<name>.py`\n3. Register tools/prompts via `app.tool` / `app.prompt` (or class-bound registration)\n4. Ensure `app.run(transport=\"stdio\")` exists\n5. Add server to `servers:` in a pipeline YAML\n6. Run `ultrarag build <pipeline.yaml>`\n\n### 16.2 Add a new tool to an existing server\n\n1. Implement function/method\n2. Register with explicit `output=...` contract\n3. Ensure return payload keys match outputs\n4. Update relevant parameter keys in `parameter.yaml` if using `$...`\n5. Add the step in pipeline YAML and rebuild\n\n### 16.3 Add a retriever index backend\n\n1. Implement backend in `servers/retriever/src/index_backends/`\n2. Follow `BaseIndexBackend` contract\n3. Register in `_INDEX_BACKENDS` map in `index_backends/__init__.py`\n\n### 16.4 Add a web-search backend\n\n1. Implement backend in `servers/retriever/src/websearch_backends/`\n2. Follow `BaseWebSearchBackend` contract\n3. Register in `_WEBSEARCH_BACKENDS` map\n\n### 16.5 Modify UI pipeline behavior\n\nPrimary files:\n\n- `ui/backend/app.py`\n- `ui/backend/pipeline_manager.py`\n\nIf touching build/runtime semantics, cross-check against:\n\n- `src/ultrarag/client.py`\n\n---\n\n## 17) Coding Standards (Repository-Conformant)\n\n- Use type hints for function signatures.\n- Prefer `pathlib.Path` for filesystem paths.\n- Use `yaml.safe_load` / `yaml.safe_dump`.\n- Use project logger (`get_logger` or `app.logger`) instead of `print`.\n- Keep tool outputs deterministic and JSON-serializable.\n- Keep imports grouped: stdlib -> third-party -> local.\n- Keep async boundaries explicit (`async`/`await`).\n\n---\n\n## 18) What Not To Edit Blindly\n\nTreat these as generated or runtime artifacts unless intentionally regenerating:\n\n- `servers/*/server.yaml`\n- `examples/**/parameter/*_parameter.yaml`\n- `examples/**/server/*_server.yaml`\n- `output/*`\n- `logs/*`\n- `ui/storage/*` runtime data\n\nAlso avoid committing secrets:\n\n- `.env`\n- any credential-bearing local config\n\n---\n\n## 19) Common Failure Modes and Fixes\n\n### Error: server file not found\n\n- Check `servers.<name>` path in pipeline YAML.\n- Ensure server entry script exists at `servers/<name>/src/<name>.py` (or update path in config).\n\n### Error: missing variable in pipeline execution\n\n- Verify output key names from upstream tool match downstream input names.\n- Verify remapping under step-level `output:` is correct.\n- Verify `$param` keys exist in that server's parameter config.\n\n### Remote MCP server fails to start\n\n- Ensure Node.js >= 20.\n- Confirm `npx` is available.\n- Confirm remote URL in server path is reachable.\n\n### Build succeeds but UI cannot list tools\n\n- Ensure `server.yaml` exists or can be inferred by AST parsing.\n- Check for unusual dynamic registration patterns that static analysis cannot infer.\n\n### No final answer in chat\n\n- Inspect `output/memory_*.json`.\n- Check whether generation step ran and produced `ans_ls`.\n- Check stream events in UI path (`step_start`, `step_end`, `sources`, `token`, `final`).\n\n---\n\n## 20) Validation Checklist for Agents\n\nBefore finalizing any non-trivial change:\n\n1. Build the affected pipeline:\n   - `ultrarag build <pipeline.yaml>`\n2. Run a relevant smoke case:\n   - `ultrarag run <pipeline.yaml>`\n3. If UI behavior changed:\n   - run `ultrarag show ui` and verify route behavior\n4. If retriever/generation backends changed:\n   - validate parameter schema keys and output names\n5. Keep generated artifacts intentional:\n   - do not accidentally commit transient runtime outputs\n\n---\n\n## 21) Minimal Quickstart for New Agents\n\n```bash\n# 1) Install dependencies\nuv sync --all-extras\n\n# 2) Smoke test\nultrarag run examples/experiments/sayhello.yaml\n\n# 3) Build and run a demo pipeline\nultrarag build examples/demos/LLM.yaml\nultrarag run examples/demos/LLM.yaml\n\n# 4) Launch UI\nultrarag show ui --host 127.0.0.1 --port 5050\n```\n\n---\n\n## 22) Final Notes\n\n- This repository is orchestration-first: correctness depends heavily on I/O naming consistency across tools and pipeline steps.\n- Most regressions come from mismatched variable names, stale generated configs, or incomplete parameter updates.\n- When in doubt, inspect `src/ultrarag/client.py` first: it is the execution truth.\n","category":"root","tokens":4197}]}