diff --git a/README.md b/README.md index 4e34f72d..8232d10c 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@
@@ -54,7 +54,7 @@ create_deep_agent( Every task runs in its own **isolated cloud sandbox** — a remote Linux environment with full shell access. The repo is cloned in, the agent gets full permissions, and the blast radius of any mistake is fully contained. No production access, no confirmation prompts. -Open SWE supports multiple sandbox providers out of the box — [Modal](https://modal.com/), [Daytona](https://www.daytona.io/), [Runloop](https://www.runloop.ai/), [E2B](https://e2b.dev/), and [LangSmith](https://smith.langchain.com/) — and you can plug in your own. See the [Customization Guide](CUSTOMIZATION.md#1-sandbox) for details. +Open SWE supports multiple sandbox providers out of the box — [Modal](https://modal.com/), [Daytona](https://www.daytona.io/), [Runloop](https://www.runloop.ai/), [E2B](https://e2b.dev/), and [LangSmith](https://smith.langchain.com/) — and you can plug in your own. See the [Customization Guide](docs/CUSTOMIZATION.md#1-sandbox) for details. This follows the principle all three companies converge on: **isolate first, then give full permissions inside the boundary.** @@ -112,7 +112,7 @@ All three companies in the article converge on **Slack as the primary invocation - **Confluence** — Comment `@openswe` on a page. A private Atlassian Connect app delivers the `comment_created` event; the agent acts and replies on the page. - **GitHub** — Tag `@openswe` in PR comments on agent-created PRs to have it address review feedback and push fixes to the same branch. -See **[INSTALLATION.md](./INSTALLATION.md) §5** for per-surface trigger setup. +See **[INSTALLATION.md](./docs/INSTALLATION.md) §5** for per-surface trigger setup. Each invocation creates a deterministic thread ID, so follow-up messages on the same issue or thread route to the same running agent. @@ -123,7 +123,7 @@ Each invocation creates a deterministic thread ID, so follow-up messages on the ### 7. Validation — Prompt-Driven The agent is instructed to run linters, formatters, and tests before committing, and is responsible end-to-end for committing, pushing, opening/updating the draft PR, and replying in the source channel. -This is an area where you can extend Open SWE for your org: add deterministic CI checks, visual verification, or review gates as additional middleware. See the [Customization Guide](CUSTOMIZATION.md#6-middleware) for how. +This is an area where you can extend Open SWE for your org: add deterministic CI checks, visual verification, or review gates as additional middleware. See the [Customization Guide](docs/CUSTOMIZATION.md#6-middleware) for how. --- @@ -156,8 +156,8 @@ This is an area where you can extend Open SWE for your org: add deterministic CI ## Getting Started -- **[Installation Guide](INSTALLATION.md)** — local dev (backend + dashboard), GitHub App creation, LangSmith, Linear/Slack/GitHub triggers, and production deployment -- **[Customization Guide](CUSTOMIZATION.md)** — swap the sandbox, model, tools, triggers, system prompt, and middleware for your org +- **[Installation Guide](docs/INSTALLATION.md)** — local dev (backend + dashboard), GitHub App creation, LangSmith, Linear/Slack/GitHub triggers, and production deployment +- **[Customization Guide](docs/CUSTOMIZATION.md)** — swap the sandbox, model, tools, triggers, system prompt, and middleware for your org ## Deployment (Sea Haven fork) @@ -169,7 +169,7 @@ and secrets live in the LangGraph deployment config and Vercel environment variables. Promotion from `dev` to `prod` (`main`) is handled by [`.github/workflows/promote-to-main.yml`](.github/workflows/promote-to-main.yml). -See **[INSTALLATION.md § 10 "Production deployment"](INSTALLATION.md#10-production-deployment)** +See **[INSTALLATION.md § 10 "Production deployment"](docs/INSTALLATION.md#10-production-deployment)** for the full backend + dashboard setup. > The earlier self-hosted AWS stack (CDK under `infra/`, an ARM64 EC2 box + nginx diff --git a/agent/prompt.py b/agent/prompt.py index 2af21ed8..fee871c1 100644 --- a/agent/prompt.py +++ b/agent/prompt.py @@ -1,6 +1,7 @@ import logging import os import shlex +from importlib import resources from pathlib import Path from deepagents import HarnessProfile, register_harness_profile @@ -14,10 +15,7 @@ from .utils.github_comments import UNTRUSTED_GITHUB_COMMENT_OPEN_TAG logger = logging.getLogger(__name__) -DEFAULT_PROMPT_PATH = os.environ.get( - "DEFAULT_PROMPT_PATH", - str(Path(__file__).resolve().parent.parent / "default_prompt.md"), -) +DEFAULT_PROMPT_PATH = os.environ.get("DEFAULT_PROMPT_PATH") # Tools stripped from the agent regardless of run state (none today: plan-mode # tool stripping is dynamic and handled by PlanModeMiddleware, not the profile). @@ -37,19 +35,28 @@ def _load_default_prompt() -> str: Returns empty string if the file doesn't exist or can't be read. """ try: - path = Path(DEFAULT_PROMPT_PATH) - if path.is_file(): - content = path.read_text().strip() - if content: - # Escape curly braces so .format() doesn't choke on them - escaped = content.replace("{", "{{").replace("}", "}}") - return f"""--- + if DEFAULT_PROMPT_PATH: + content = Path(DEFAULT_PROMPT_PATH).read_text().strip() + else: + content = ( + resources.files("agent.resources") + .joinpath("default_prompt.md") + .read_text(encoding="utf-8") + .strip() + ) + if content: + # Escape curly braces so .format() doesn't choke on them + escaped = content.replace("{", "{{").replace("}", "}}") + return f"""--- ### Custom Instructions {escaped}""" except Exception: - logger.warning("Failed to read default prompt file at %s", DEFAULT_PROMPT_PATH) + logger.warning( + "Failed to read default prompt from %s", + DEFAULT_PROMPT_PATH or "agent.resources/default_prompt.md", + ) return "" diff --git a/agent/resources/__init__.py b/agent/resources/__init__.py new file mode 100644 index 00000000..c9c2ef67 --- /dev/null +++ b/agent/resources/__init__.py @@ -0,0 +1 @@ +__all__: list[str] = [] diff --git a/default_prompt.md b/agent/resources/default_prompt.md similarity index 100% rename from default_prompt.md rename to agent/resources/default_prompt.md diff --git a/static/dark.svg b/assets/dark.svg similarity index 100% rename from static/dark.svg rename to assets/dark.svg diff --git a/static/light.svg b/assets/light.svg similarity index 100% rename from static/light.svg rename to assets/light.svg diff --git a/CUSTOMIZATION.md b/docs/CUSTOMIZATION.md similarity index 99% rename from CUSTOMIZATION.md rename to docs/CUSTOMIZATION.md index b6067eb4..b6165937 100644 --- a/CUSTOMIZATION.md +++ b/docs/CUSTOMIZATION.md @@ -439,7 +439,7 @@ Open SWE supports a `default_prompt.md` file for org-level instructions that app The file is loaded at agent startup and injected into the system prompt between the task overview and repository setup sections. -**Location:** [`default_prompt.md`](./default_prompt.md) in the project root. +**Location:** [`agent/resources/default_prompt.md`](../agent/resources/default_prompt.md) for the bundled default. **Override:** Set the `DEFAULT_PROMPT_PATH` environment variable to use a different file: diff --git a/INSTALLATION.md b/docs/INSTALLATION.md similarity index 100% rename from INSTALLATION.md rename to docs/INSTALLATION.md