-
Notifications
You must be signed in to change notification settings - Fork 373
Give ACP bots their computer (grok, gemini, antigravity) #76
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
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 |
|---|---|---|
|
|
@@ -13,7 +13,10 @@ | |
| // is never a security contract). session/load REPLAYS history as ordinary | ||
| // session/update notifications, so updates are double-gated: nothing emits | ||
| // before the prompt is sent, and `_meta.isReplay` updates are dropped. | ||
| import { existsSync } from "node:fs"; | ||
| import { homedir } from "node:os"; | ||
| import { dirname, join } from "node:path"; | ||
| import { fileURLToPath } from "node:url"; | ||
|
|
||
| import { execCli, killCliTree, spawnCli } from "../../procs.ts"; | ||
|
|
||
|
|
@@ -28,6 +31,13 @@ import type { | |
| } from "../../contracts.ts"; | ||
| import { newEventId, newId } from "../../contracts.ts"; | ||
| import { augmentedPath } from "../../env-path.ts"; | ||
|
|
||
| // the computer proxy entry: .ts in dev (node type stripping), .js in the | ||
| // compiled dist-server the packaged app ships | ||
| const COMPUTER_PROXY_PATH = (() => { | ||
| const ts = join(dirname(fileURLToPath(import.meta.url)), "..", "..", "computer-proxy.ts"); | ||
| return existsSync(ts) ? ts : ts.replace(/\.ts$/, ".js"); | ||
| })(); | ||
| import { appendNative } from "../native.ts"; | ||
|
|
||
| export interface AcpConfig { | ||
|
|
@@ -131,13 +141,34 @@ export function createAcpDriver(support: AcpSupport): ProviderDriver<AcpConfig> | |
| // fine here. env is the ACP {name,value}[] shape. | ||
| const acpMcpServers = (turn: SendTurnInput) => { | ||
| const servers: Array<{ name: string; command: string; args: string[]; env: Array<{ name: string; value: string }> }> = []; | ||
| const acpEnv = (env: Record<string, string>) => | ||
| Object.entries(env).map(([name, value]) => ({ name, value: String(value) })); | ||
| const agents = turn.integrations?.agents; | ||
| if (agents) { | ||
| servers.push({ name: "agents", command: agents.command, args: agents.args, env: acpEnv(agents.env) }); | ||
| } | ||
| // the bot's computer, mounted exactly like the claude driver does: | ||
| // an ACP agent gets the same screenshot/click/batch tools instead of | ||
| // being told it has a machine it cannot touch | ||
| const computer = turn.integrations?.computer; | ||
| if (computer) { | ||
| servers.push({ | ||
| name: "computer", | ||
| command: process.execPath, | ||
| args: [COMPUTER_PROXY_PATH], | ||
| env: acpEnv({ | ||
| ELECTRON_RUN_AS_NODE: "1", | ||
| OGB_BOX_ID: computer.boxId, | ||
| OGB_BOX_TOKEN: computer.token, | ||
| }), | ||
| }); | ||
| } else if (turn.integrations?.localComputer) { | ||
| const local = turn.integrations.localComputer; | ||
| servers.push({ | ||
| name: "agents", | ||
| command: agents.command, | ||
| args: agents.args, | ||
| env: Object.entries(agents.env).map(([name, value]) => ({ name, value: String(value) })), | ||
| name: "computer", | ||
| command: local.command, | ||
| args: local.args, | ||
| env: acpEnv(local.env ?? {}), | ||
| }); | ||
| } | ||
| return servers; | ||
|
|
@@ -478,7 +509,7 @@ export function createAcpDriver(support: AcpSupport): ProviderDriver<AcpConfig> | |
| snapshot, | ||
| adapter: { | ||
| provider: DRIVER_KIND, | ||
| capabilities: { sessionModelSwitch: "unsupported", agentsMcp: true }, | ||
| capabilities: { sessionModelSwitch: "unsupported", agentsMcp: true, computerMcp: true }, | ||
|
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. 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
rg -n -C 8 '\bcreateAcpDriver\s*\(' server --glob '*.ts'
rg -n -C 6 '\bcomputerMcp\b|\bAcpSupport\b' server --glob '*.ts'Repository: milind-soni/OpenMausBot Length of output: 11836 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- AcpSupport interface ---'
sed -n '45,78p' server/drivers/acp/core.ts
printf '%s\n' '--- ACP support objects ---'
sed -n '1,90p' server/drivers/acp/grok.ts
sed -n '1,90p' server/drivers/acp/gemini.ts
printf '%s\n' '--- computer MCP setup and capability use ---'
sed -n '250,380p' server/drivers/acp/core.ts
sed -n '400,460p' server/index.ts
rg -n -C 5 'integrations\.computer|computerMcp|agentsMcp|mcpServers' server --glob '*.ts'Repository: milind-soni/OpenMausBot Length of output: 36824 🏁 Script executed: #!/bin/bash
set -euo pipefail
python3 - <<'PY'
from pathlib import Path
import re
core = Path("server/drivers/acp/core.ts").read_text()
support_fields = re.search(r"export interface AcpSupport\s*\{(.*?)\n\}", core, re.S)
calls = re.findall(r"createAcpDriver\s*\(\s*support\s*\)", "\n".join(
p.read_text() for p in Path("server/drivers/acp").glob("*.ts")
))
print("AcpSupport has computerMcp:", bool(support_fields and re.search(r"\bcomputerMcp\b", support_fields.group(1))))
print("ACP factory callers using the shared support variable:", len(calls))
print("hard-coded computerMcp true count:", len(re.findall(r"computerMcp\s*:\s*true", core)))
PYRepository: milind-soni/OpenMausBot Length of output: 289 🏁 Script executed: #!/bin/bash
set -euo pipefail
printf '%s\n' '--- ACP MCP conversion ---'
sed -n '118,178p' server/drivers/acp/core.ts
printf '%s\n' '--- ACP driver registration and tests ---'
rg -n -C 8 'grokAgent|geminiAgent|GrokAgentDriver|GeminiAgentDriver|computer' server --glob '*.ts' --glob '!server/index.ts'
printf '%s\n' '--- MCP capability documentation and protocol assumptions ---'
rg -n -C 5 'stdio|mcpServers|MCP|computer MCP|computerMcp' README.md server/drivers/acp server/contracts.ts --glob '*.ts' --glob '*.md'Repository: milind-soni/OpenMausBot Length of output: 50379 Derive
🤖 Prompt for AI Agents |
||
| sendTurn, | ||
| interruptTurn: async (threadId) => active.get(threadId)?.interrupt(), | ||
| respondToRequest: async (threadId, requestId, decision) => { | ||
|
|
||
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.
🔒 Security & Privacy | 🟠 Major | ⚡ Quick win
Prevent MCP credentials from entering native logs.
computer.tokenis placed inmcpServers[*].envhere.send()records the complete outbound JSON-RPC object at Line [205]. Thesession/loadandsession/newcalls includemcpServersat Lines [440] and [447]. This placesOGB_BOX_TOKENin the native-log record.local.envcan create the same exposure.Redact MCP environment values in the log copy while sending the original values to ACP.
Suggested logging fix
const send = (obj: unknown) => { try { child.stdin.write(JSON.stringify(obj) + "\n"); } catch {} - appendNative(threadId, { dir: "out", source: SOURCE, msg: obj }); + appendNative(threadId, { dir: "out", source: SOURCE, msg: redactMcpSecrets(obj) }); };🤖 Prompt for AI Agents