Repository navigation
feat: add oh-my-pi (omp) agent #392
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| --- | ||
| title: "oh-my-pi" | ||
| description: "Use oh-my-pi (omp) as a sandbox agent." | ||
| --- | ||
|
|
||
| ## Usage | ||
|
|
||
| ```typescript | ||
| const session = await client.createSession({ | ||
| agent: "omp", | ||
| }); | ||
| ``` | ||
|
|
||
| `sandbox-agent install-agent omp` downloads the `omp` release binary from [GitHub](https://github.com/can1357/oh-my-pi/releases) (pin one with `--agent-version`) and runs it with `omp acp`, its native ACP mode. No adapter package is needed. | ||
|
|
||
| ## Capabilities | ||
|
|
||
| | Category | Values | | ||
| |----------|--------| | ||
| | **Models** | Every model omp can use with its configured providers, reported by the agent | | ||
| | **Modes** | `default`, `plan` | | ||
| | **Thought levels** | Reported by the agent for the selected model | | ||
|
|
||
| ## Credentials | ||
|
|
||
| omp reads its usual provider environment variables (`ANTHROPIC_API_KEY`, `OPENAI_API_KEY`, and others) and `~/.omp/agent/models.yml`. | ||
|
|
||
| ## Permissions | ||
|
|
||
| omp asks the client before shell commands, file deletion and moves. For unattended sandboxes, set `tools.approvalMode: yolo` in `~/.omp/agent/config.yml`. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -26,6 +26,7 @@ pub enum AgentId { | |
| Amp, | ||
| Pi, | ||
| Cursor, | ||
| Omp, | ||
| Mock, | ||
| } | ||
|
|
||
|
|
@@ -38,6 +39,7 @@ impl AgentId { | |
| AgentId::Amp => "amp", | ||
| AgentId::Pi => "pi", | ||
| AgentId::Cursor => "cursor", | ||
| AgentId::Omp => "omp", | ||
| AgentId::Mock => "mock", | ||
| } | ||
| } | ||
|
|
@@ -50,6 +52,7 @@ impl AgentId { | |
| AgentId::Amp => "amp", | ||
| AgentId::Pi => "pi", | ||
| AgentId::Cursor => "cursor-agent", | ||
| AgentId::Omp => "omp", | ||
| AgentId::Mock => "mock", | ||
| } | ||
| } | ||
|
|
@@ -62,6 +65,7 @@ impl AgentId { | |
| "amp" => Some(AgentId::Amp), | ||
| "pi" => Some(AgentId::Pi), | ||
| "cursor" => Some(AgentId::Cursor), | ||
| "omp" => Some(AgentId::Omp), | ||
| "mock" => Some(AgentId::Mock), | ||
| _ => None, | ||
| } | ||
|
|
@@ -75,6 +79,7 @@ impl AgentId { | |
| AgentId::Amp, | ||
| AgentId::Pi, | ||
| AgentId::Cursor, | ||
| AgentId::Omp, | ||
| AgentId::Mock, | ||
| ] | ||
| } | ||
|
|
@@ -87,6 +92,7 @@ impl AgentId { | |
| AgentId::Amp => Some("amp-acp"), | ||
| AgentId::Pi => Some("pi-acp"), | ||
| AgentId::Cursor => Some("cursor-agent-acp"), | ||
| AgentId::Omp => None, | ||
| AgentId::Mock => None, | ||
| } | ||
| } | ||
|
|
@@ -99,12 +105,16 @@ impl AgentId { | |
| AgentId::Amp => Some("amp-acp"), | ||
| AgentId::Pi => Some("pi-acp"), | ||
| AgentId::Cursor => Some("cursor-agent-acp"), | ||
| AgentId::Omp => None, | ||
| AgentId::Mock => None, | ||
| } | ||
| } | ||
|
|
||
| fn native_required(self) -> bool { | ||
| matches!(self, AgentId::Claude | AgentId::Codex | AgentId::Opencode) | ||
| matches!( | ||
| self, | ||
| AgentId::Claude | AgentId::Codex | AgentId::Opencode | AgentId::Omp | ||
| ) | ||
| } | ||
|
|
||
| fn unstable_enabled(self) -> bool { | ||
|
|
@@ -533,6 +543,7 @@ impl AgentManager { | |
| install_opencode(&path, self.platform, options.version.as_deref())? | ||
| } | ||
| AgentId::Amp => install_amp(&path, self.platform, options.version.as_deref())?, | ||
| AgentId::Omp => install_omp(&path, self.platform, options.version.as_deref())?, | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
On a clean host without an omp binary, this installer is unreachable: Useful? React with 👍 / 👎. |
||
| AgentId::Pi | AgentId::Cursor => { | ||
| return Ok(None); | ||
| } | ||
|
|
@@ -823,7 +834,7 @@ impl AgentManager { | |
| ) -> Result<InstalledArtifact, AgentError> { | ||
| let started = Instant::now(); | ||
| let artifact = match agent { | ||
| AgentId::Opencode => { | ||
| AgentId::Opencode | AgentId::Omp => { | ||
| let launcher = self.agent_process_path(agent); | ||
| let native = self.resolve_binary(agent)?; | ||
| write_exec_agent_process_launcher( | ||
|
|
@@ -1338,6 +1349,43 @@ fn install_claude( | |
| Ok(()) | ||
| } | ||
|
|
||
| fn install_omp(path: &Path, platform: Platform, version: Option<&str>) -> Result<(), AgentError> { | ||
| let started = Instant::now(); | ||
| let asset = match platform { | ||
| Platform::LinuxX64 => "omp-linux-x64", | ||
| Platform::LinuxX64Musl => "omp-linux-musl-x64", | ||
| Platform::LinuxArm64 => "omp-linux-arm64", | ||
| Platform::MacosArm64 => "omp-darwin-arm64", | ||
| Platform::MacosX64 => "omp-darwin-x64", | ||
| Platform::WindowsX64 => "omp-windows-x64.exe", | ||
| Platform::WindowsArm64 => "omp-windows-arm64.exe", | ||
| }; | ||
| // Release tags are `v<semver>`; accept the version with or without the prefix. | ||
| let url = match version { | ||
| Some(version) => Url::parse(&format!( | ||
| "https://github.com/can1357/oh-my-pi/releases/download/v{}/{asset}", | ||
| version.trim_start_matches('v') | ||
| ))?, | ||
| None => Url::parse(&format!( | ||
| "https://github.com/can1357/oh-my-pi/releases/latest/download/{asset}" | ||
| ))?, | ||
| }; | ||
| let download_started = Instant::now(); | ||
| let bytes = download_bytes(&url)?; | ||
| let download_ms = elapsed_ms(download_started); | ||
| let write_started = Instant::now(); | ||
| write_executable(path, &bytes)?; | ||
| tracing::info!( | ||
| url = %url, | ||
| bytes = bytes.len(), | ||
| download_ms = download_ms, | ||
| write_ms = elapsed_ms(write_started), | ||
| total_ms = elapsed_ms(started), | ||
| "agent_manager.install_omp: completed" | ||
| ); | ||
| Ok(()) | ||
| } | ||
|
|
||
| fn install_amp(path: &Path, platform: Platform, version: Option<&str>) -> Result<(), AgentError> { | ||
| let started = Instant::now(); | ||
| let version = match version { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -108,7 +108,7 @@ pub(super) fn credentials_available_for( | |
| AgentId::Claude | AgentId::Amp => has_anthropic, | ||
| AgentId::Codex => has_openai, | ||
| AgentId::Opencode => has_anthropic || has_openai, | ||
| AgentId::Pi | AgentId::Cursor => true, | ||
| AgentId::Pi | AgentId::Cursor | AgentId::Omp => true, | ||
| AgentId::Mock => true, | ||
| } | ||
| } | ||
|
|
@@ -181,6 +181,8 @@ pub(super) fn fallback_config_options(agent: AgentId) -> Vec<Value> { | |
| { "value": "default", "name": "Default" } | ||
| ] | ||
| })], | ||
| // omp returns its model, mode and thinking options from session/new. | ||
| AgentId::Omp => Vec::new(), | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Even with a preinstalled, authenticated omp, Useful? React with 👍 / 👎. |
||
| AgentId::Mock => vec![ | ||
| json!({ | ||
| "id": "model", | ||
|
|
@@ -403,6 +405,26 @@ pub(super) fn agent_capabilities_for(agent: AgentId) -> AgentCapabilities { | |
| item_started: true, | ||
| shared_process: false, | ||
| }, | ||
| AgentId::Omp => AgentCapabilities { | ||
| plan_mode: true, | ||
| permissions: true, | ||
| questions: false, | ||
| tool_calls: true, | ||
| tool_results: true, | ||
| text_messages: true, | ||
| images: true, | ||
| file_attachments: false, | ||
| session_lifecycle: true, | ||
| error_events: true, | ||
| reasoning: true, | ||
| status: false, | ||
| command_execution: false, | ||
| file_changes: false, | ||
| mcp_tools: true, | ||
| streaming_deltas: true, | ||
| item_started: true, | ||
| shared_process: false, | ||
| }, | ||
| AgentId::Cursor => AgentCapabilities { | ||
| plan_mode: true, | ||
| permissions: true, | ||
|
|
@@ -636,6 +658,7 @@ pub(super) fn build_provider_payload_for_opencode(_state: &Arc<AppState>) -> Val | |
| AgentId::Opencode, | ||
| AgentId::Pi, | ||
| AgentId::Cursor, | ||
| AgentId::Omp, | ||
| ]; | ||
|
|
||
| let has_anthropic = std::env::var("ANTHROPIC_API_KEY").is_ok(); | ||
|
|
@@ -721,6 +744,7 @@ fn agent_display_name(agent: AgentId) -> &'static str { | |
| AgentId::Opencode => "OpenCode", | ||
| AgentId::Pi => "Pi", | ||
| AgentId::Cursor => "Cursor Agent", | ||
| AgentId::Omp => "oh-my-pi", | ||
| } | ||
| } | ||
|
|
||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This agent-usage page describes the underlying ACP launch mode and adapter implementation, contrary to the Docs Terminology rules in
sandbox-agent/AGENTS.md, which prohibit ACP terminology and protocol implementation details outside ACP-specific documentation. Keep this paragraph focused on installation and SDK usage, and move the protocol details to an ACP-specific reference.AGENTS.md reference: sandbox-agent/AGENTS.md:L13-L15
Useful? React with 👍 / 👎.