Metadata-Version: 2.4
Name: ai-agent-proxy
Version: 0.5.0
Summary: Turn your agent CLI into an OpenAI-like service with chat and responses endpoints
Author-email: Leo <leoustc@icloud.com>
Requires-Python: >=3.8
Description-Content-Type: text/markdown
Requires-Dist: fastapi>=0.110
Requires-Dist: uvicorn>=0.23

# AI Agent Proxy

`ai-agent-proxy` is a Python package that turns your agent CLI into an OpenAI-like HTTP service.

Current release: `0.3.0`

It exposes both:

- the traditional chat endpoint: `POST /v1/chat/completions`
- the Responses API endpoint: `POST /v1/responses`

By default, both endpoints return OpenAI-style JSON and source assistant content only from `.mailbox/outbox` in the agent working directory. FastAPI waits for the next `END_OF_REPLY` marker and returns only that content.
For long-running tasks, the agent may first write a short interim status reply terminated with `END_OF_REPLY`, and then continue working in its managed session.

For OpenClaw-style integrations, prefer `POST /v1/chat/completions`.

It also includes:

- the `ai-agent-proxy` CLI
- a FastAPI server with a status dashboard at `GET /` and `GET /web`
- persistent local agent workspaces
- automatic startup of the `manager` agent

## What It Does

`ai-agent-proxy` runs your local agent backend behind an API shape that OpenAI-style clients can use.

You can use it to:

- point chatbot clients at an OpenAI-compatible URL
- expose a manager-backed assistant to Mattermost, Slack, or browser clients
- keep agent state in persistent local workspaces under `~/.ai_agent_proxy`
- run a simple manager-first service without changing your core CLI workflow
- relay final agent replies through local append-only reply files instead of raw terminal transcript
- serialize manager requests one at a time with a FastAPI-side lock while the manager terminal is working
- return OpenAI-style response bodies without exposing raw Codex session output

## Endpoints

The service supports:

- `GET /`
- `GET /web`
- `GET /health`
- `GET /v1/models`
- `GET /v1/models/{model}`
- `POST /v1/chat/completions`
- `POST /v1/responses`

`GET /` and `GET /web` show the service status dashboard.

## Installation

From source:

```bash
pip install .
```

For local development:

```bash
make install
```

## CLI

Main commands:

- `ai-agent-proxy`
- `ai-agent-proxy init <role>`
- `ai-agent-proxy hire <role> <name>`
- `ai-agent-proxy list`
- `ai-agent-proxy status`
- `ai-agent-proxy connect <agent> [working_dir]`
- `ai-agent-proxy stop <role>`

The foreground service command is:

```bash
ai-agent-proxy --host 0.0.0.0 --port 7011 --api-key your-key --workdir ~/.openclaw/workspace --init-cli "codex exec --skip-git-repo-check --dangerously-bypass-approvals-and-sandbox 'load all markdown files and build yourself'" --cli "codex resume --last"
```

Config-file form:

```bash
ai-agent-proxy -f /etc/ai-agent-proxy/config
```

Config files use `.env`-style lines:

```dotenv
HOST=0.0.0.0
PORT=7011
API_KEY=
WORKDIR=/home/you/.ai-agent/manager/workspace
AGENT_CLI=codex resume --last
AGENT_INIT_CLI=codex exec --skip-git-repo-check --dangerously-bypass-approvals-and-sandbox 'load all markdown files and build yourself'
```

You can split agent startup into two config keys:

```dotenv
AGENT_CLI=codex resume --last
AGENT_INIT_CLI=codex exec --skip-git-repo-check --dangerously-bypass-approvals-and-sandbox 'load all markdown files and build yourself'
```

`AGENT_DEFAULT_CLI` is still accepted as a legacy alias for `AGENT_INIT_CLI`.

The config loader is strict. When you use `-f`, the file must contain:

- `HOST`
- `PORT`
- `API_KEY`
- `WORKDIR`

If any of those keys are missing, `ai-agent-proxy` exits immediately with an error.
`PORT` must be a positive integer.

Precedence is:

1. CLI flags
2. config file values from `-f`
3. built-in defaults

The helper commands such as `init`, `hire`, and `connect` also use config-file defaults when `-f` is provided.

`ai-agent-proxy list` shows initialized agent workspaces only. Internal service directories are not listed as agents.

## Start The Service

Run from source:

```bash
make debug
```

`Makefile` will read `.env` for local convenience, but the Python CLI itself is configured by command-line flags.

For `make debug`, put the runtime config in `.env`:

```dotenv
HOST=0.0.0.0
PORT=7011
WORKDIR=/home/you/.ai-agent/manager/workspace
API_KEY=
AGENT_CLI=codex resume --last
AGENT_INIT_CLI=codex exec --skip-git-repo-check --dangerously-bypass-approvals-and-sandbox 'load all markdown files and build yourself'
```

`Makefile` only checks that `.env` exists, then starts the service with `ai-agent-proxy -f .env`.

Run directly with the CLI:

```bash
ai-agent-proxy --host 0.0.0.0 --port 7011 --api-key your-key --workdir ~/.openclaw/workspace --init-cli "codex exec --skip-git-repo-check --dangerously-bypass-approvals-and-sandbox 'load all markdown files and build yourself'" --cli "codex resume --last"
```

On startup, the foreground process prints a short readiness summary with:

- a `==== Parameters ==== ` section with host, port, workdir, init CLI, and agent CLI
- a `==== Build Agent Identity ==== ` section with the blocking init CLI output
- a `==== Start Backend Agent Process ==== ` section with backend startup state
- a `==== Start FastAPI ==== ` section with the serving endpoint and ready URL

Startup waits for the manager xterm/tmux backend to exist before FastAPI starts serving requests. If that backend does not start, FastAPI exits instead of serving in a half-started state.
When the foreground CLI starts, it force-stops any old manager session state first, runs the agent init CLI in the workspace in the parent Python process, then starts the persistent tmux-backed agent CLI. If startup fails, it retries that init-plus-tmux sequence up to 3 times before exiting.
The agent init CLI runs synchronously and its output is printed directly to the foreground console before the tmux backend ready line.

The foreground service process starts the `manager` agent automatically.
The manager agent uses `~/.ai-agent/manager/workspace` as both its workspace and its default project working directory.
You can override that with `--workdir`.
If that manager workspace already contains `AGENTS.md`, `SOUL.md`, `TOOLS.md`, `USER.md`, `HEARTBEAT.md`, and `memory/`, the bundled manager templates are not copied into it.

System service installation is not managed by this package. If you want to run it under `systemd` or another supervisor, create that service definition yourself and point it at `ai-agent-proxy --host ... --port ...`.

This repo also ships an example unit file at [systemd/ai-agent-proxy.service](/home/li/project/collection-pip/agent-proxy/systemd/ai-agent-proxy.service). It uses:

```text
ai-agent-proxy -f /etc/ai-agent-proxy/config
```

The example unit writes service stdout and stderr to the systemd journal. Inspect it with:

```bash
journalctl -u ai-agent-proxy -f
```

Recommended deploy flow for that systemd setup:

1. install or upgrade the package on the target host
2. run `make sync-config` to copy local `.env` to `/etc/ai-agent-proxy/config` and install `systemd/ai-agent-proxy.service` to `/etc/systemd/system/ai-agent-proxy.service`
3. run `sudo systemctl daemon-reload` if the unit file changed
4. run `sudo systemctl restart ai-agent-proxy`

For foreground debugging, `make remote-debug` stops `ai-agent-proxy.service` first and then runs `ai-agent-proxy -f /etc/ai-agent-proxy/config` directly on the remote host.

To create or reuse a named agent:

```bash
ai-agent-proxy hire engineer alice
```

To attach to the manager tmux session and watch the live terminal:

```bash
ai-agent-proxy connect manager
```

`connect manager` attaches to its tmux session.

When you use `connect`, the agent still runs from its own workspace under `~/.ai_agent_proxy/...`.
The optional `working_dir` argument is task context only.

## Agent CLI Selection

By default the service uses:

```text
AGENT_INIT_CLI: codex exec --skip-git-repo-check --dangerously-bypass-approvals-and-sandbox 'load all markdown files and build yourself'
AGENT_CLI: codex resume --last
```

You can override the underlying agent CLI command with `--cli` and the init step with `--init-cli`:

```bash
ai-agent-proxy --host 0.0.0.0 --port 7011 --api-key your-key --cli "codex resume --last" --init-cli "codex exec --skip-git-repo-check --dangerously-bypass-approvals-and-sandbox 'load all markdown files and build yourself'"
```

Current behavior:

- `--init-cli` runs first in the manager workspace when the app starts fresh
- `--cli` starts the persistent interactive agent environment inside tmux
- the default interactive agent CLI is `codex resume --last`
- CLI flags are the primary runtime configuration surface
- config files loaded with `-f` can provide the same values, and CLI flags override them
- inside a config file, `AGENT_CLI` and `AGENT_INIT_CLI` override `CLI`
- `--api-key` sets the bearer token for the current foreground run; if omitted, no API key is required
- if the requested port is busy, the service tries the next available port
- FastAPI talks to an internal xterm controller, the xterm controller talks to tmux, and tmux runs persistent Codex
- on fresh app startup, the init CLI runs before tmux starts
- later tmux failures restart the interactive agent CLI without rerunning the init CLI
- after a tmux restart caused by failure, the new session receives: `you restart from a failure, no action need to to do until next prompt`
- FastAPI writes the latest mailbox payload into `<working_dir>/.mailbox/inbox` with `#conversation id: ...` and, when available, `#user: ...`, followed by the user input and a trailing `INSTRUCTION:` block
- FastAPI handles one mailbox request at a time for the manager
- before each tmux trigger, FastAPI writes the current request directly into `<working_dir>/.mailbox/inbox`
- the agent only needs to read `.mailbox/inbox` and write `.mailbox/outbox`
- tmux receives a short trigger: `check .mailbox/inbox reply to .mailbox/outbox`
- after FastAPI returns the response to the client, it removes both `.mailbox/inbox` and `.mailbox/outbox`
- the backend sends exactly one prompt paste followed by `Enter`, then a literal terminal `Shift+Enter` escape sequence, then another `Enter`
- if the tmux/Codex backend exits or becomes unhealthy, the service restarts it automatically with the same configured interactive CLI
- the session server streams tmux-session output into the session log
- when FastAPI accepts a manager request, it locks manager request handling, runs the manager transport for that prompt, and waits for the next `END_OF_REPLY`

## Authentication

If you run the service with `--api-key`, API requests must send:

```http
Authorization: Bearer <your-key>
```

## Models Endpoint

OpenAI-compatible model discovery:

```bash
curl http://127.0.0.1:7011/v1/models \
  -H 'Authorization: Bearer YOUR_KEY'
```

The models list includes:

- `manager`
- each initialized local agent directory name, such as `engineer_alice`

## Traditional Endpoint

OpenAI-compatible chat completions:

```bash
curl http://127.0.0.1:7011/v1/chat/completions \
  -H 'Authorization: Bearer YOUR_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "manager",
    "messages": [
      {"role": "user", "content": "hello"}
    ]
  }'
```

The returned `choices[0].message.content` is built only from the new reply content before the next `END_OF_REPLY`.

This is the recommended endpoint for OpenClaw-style clients.

## Responses Endpoint

OpenAI Responses API style:

```bash
curl http://127.0.0.1:7011/v1/responses \
  -H 'Authorization: Bearer YOUR_KEY' \
  -H 'Content-Type: application/json' \
  -d '{
    "model": "manager",
    "input": "hello",
    "stream": false
  }'
```

The returned `output` and `output_text` fields are built only from the new reply content before the next `END_OF_REPLY`.

Use this when your client explicitly supports the OpenAI Responses API well. For OpenClaw-style integrations, prefer `POST /v1/chat/completions`.

## Status UI

Open:

```text
http://127.0.0.1:7011/web
```

This page shows service status, agent count, agent names, and health.
Agents marked `working` are actively handling a prompt in their managed session.
It also tells clients to use the API with an API key when auth is enabled.

When running in the foreground, FastAPI also prints short summaries to stdout:

- request lines include the request path, the active mode, the prompt target, and a short prompt preview
- both request and return lines include a timestamp
- return lines include the elapsed response time for that prompt
- return lines include the request path, the active mode, the prompt target, and a short reply preview

- `request from "/v1/..." "..."`
- `return message "/v1/..." "..."`

## Workspace Layout

Agent state is stored under:

```text
~/.ai_agent_proxy/
```

Example:

```text
~/.ai-agent/manager/workspace/
~/.ai_agent_proxy/engineer_alice/
```

Each workspace can include role instructions, memory, notes, control files, and logs.
For the manager, that workspace is `~/.ai-agent/manager/workspace`.
Managed session control state lives under `control/`, including the local session socket and request-state files.

## Notes

- the Python import package is `ai_agent_proxy`
- the CLI command is `ai-agent-proxy`
- the API is manager-first: inbound requests are routed through the `manager` agent
- Python runtime configuration should come from CLI flags or a `-f` config file, not from global environment variables
