Metadata-Version: 2.4
Name: ai-protocol-mock
Version: 1.0.1
Summary: Unified mock server for AI-Protocol runtimes - HTTP provider and MCP JSON-RPC mocking
Author: AI-Protocol Team
License-Expression: MIT OR Apache-2.0
License-File: LICENSE-APACHE
License-File: LICENSE-MIT
Requires-Python: >=3.10
Requires-Dist: fastapi>=0.109.0
Requires-Dist: httpx>=0.25.0
Requires-Dist: pydantic>=2.0
Requires-Dist: python-dotenv>=1.0.0
Requires-Dist: pyyaml>=6.0
Requires-Dist: uvicorn[standard]>=0.27.0
Provides-Extra: dev
Requires-Dist: black>=24.0; extra == 'dev'
Requires-Dist: pre-commit>=3.0; extra == 'dev'
Requires-Dist: pytest-asyncio>=0.23; extra == 'dev'
Requires-Dist: pytest>=8.0; extra == 'dev'
Requires-Dist: ruff>=0.8; extra == 'dev'
Description-Content-Type: text/markdown

# ai-protocol-mock

Unified mock server for AI-Protocol runtimes. Provides HTTP provider mock (OpenAI and Anthropic formats) and MCP JSON-RPC mock for testing ai-lib-python, ai-lib-rust, and other runtimes.

## Features

- **Manifest-driven HTTP mock**: Generates responses in OpenAI or Anthropic format based on provider manifests
- **STT / TTS / Rerank mock**: Simulates speech-to-text, text-to-speech, and document reranking endpoints (OpenAI/Cohere compliant)
- **MCP JSON-RPC mock**: Implements `tools/list`, `tools/call`, `capabilities`, `initialize`
- **Configurable**: Response delay, error rate, mock content via environment variables
- **Docker**: One-command startup with `docker-compose up`

## Quick Start

```bash
# Install and run
pip install -e .
python scripts/sync_manifests.py --force  # Sync manifests from ai-protocol
uvicorn ai_protocol_mock.main:app --host 0.0.0.0 --port 4010
```

Or with Docker:

```bash
docker-compose up -d
```

## Configuration

| Variable | Default | Description |
|----------|---------|-------------|
| HTTP_PORT | 4010 | Port for HTTP and MCP (MCP at /mcp) |
| MANIFEST_DIR | manifests | Directory for synced manifests |
| MANIFEST_SYNC_URL | https://raw.githubusercontent.com/ailib-official/ai-protocol/v1.0.0/ | Source for manifest sync (pin `v1.0.0` for reproducible CI) |
| AI_PROTOCOL_TAG | (optional) | Convenience alias; docker-compose sets `v1.0.0` |
| RESPONSE_DELAY | 0 | Delay in seconds before responding |
| ERROR_RATE | 0 | Probability (0-1) of returning 429/500/503 |
| MOCK_CONTENT | Mock response from ai-protocol-mock | Default response content |

### Test Control Headers (X-Mock-*)

For integration tests, requests can include these headers to control mock behavior:

| Header | Description | Example |
|--------|-------------|---------|
| X-Mock-Status | Force HTTP error status (400-599) | 429, 500, 503 |
| X-Mock-Content | Override response content for this request | Custom text |
| X-Mock-Tool-Calls | Return tool_calls instead of text; `parallel` or `recursive` for multi-tool scenarios | 1, parallel, recursive |
| X-Mock-Reasoning | Include reasoning/thinking blocks in chat response | true |
| X-Mock-Error | Inject standard errors (`context_overflow`, `content_filter`, `rate_limit`, `stream_interrupt`) | rate_limit |
| X-Mock-Usage-Format | Enrich usage payload (`openai` or `anthropic` shape) | openai |
| X-Mock-Tool-Depth | Max recursive tool-call rounds (with `recursive`) | 2 |
| X-Mock-Invalid-Content-Type | Inject `text/plain` payload for robustness tests | 1 |
| X-Mock-Video-Terminal | Force async video terminal state (`succeeded`/`failed`/`cancelled`) | failed |

## Endpoints

- `POST /v1/chat/completions` - OpenAI-format chat
- `POST /v1/messages` - Anthropic-format chat
- `POST /v1/audio/transcriptions` - STT (OpenAI Whisper format), returns `{"text": "..."}`
- `POST /v1/audio/speech` - TTS (OpenAI format), returns `audio/mpeg` bytes
- `POST /v2/rerank` - Rerank (Cohere v2 format), request `{query, documents, top_n}`, returns `{results, id, meta}`
- `POST /v1/video/generations` - Video generation (sync + async polling)
- `GET /v1/video/generations/{job_id}` - Poll async video generation status
- `POST /mcp` - MCP JSON-RPC (`tools/list`, `tools/call`, `capabilities`, `initialize`)
- `GET /health` - Health check
- `GET /status` - Status with manifest sync metadata
- `GET /providers` - Provider contracts from manifests (provider_id, api_style, chat_path, capability_profile summary)

### Video Generation Lifecycle

Async video generation jobs follow a deterministic state machine:

`queued -> running -> terminal`

Terminal states:

- `succeeded` (default): returns `output` with mock mp4 metadata
- `failed`: returns `error` payload (`video_generation_failed`)
- `cancelled`: returns `cancellation` payload (`mock_cancelled_for_test`)

Controls:

- request body `terminal_state` or header `X-Mock-Video-Terminal`
- unknown values fall back to `succeeded`

## Using with ai-lib-python

```python
import os
os.environ["MOCK_HTTP_URL"] = "http://localhost:4010"

from ai_lib_python.client import AiClient
from ai_lib_python.types.message import Message

client = await AiClient.create(
    "openai/gpt-4o",
    api_key="sk-test",
    base_url="http://localhost:4010"
)
response = await client.chat().messages([Message.user("Hi")]).execute()
print(response.content)
```

Or run tests with mock:

```bash
MOCK_HTTP_URL=http://localhost:4010 MOCK_MCP_URL=http://localhost:4010/mcp pytest tests/ -v
```

## Third-Party Integration (ZeroClaw, etc.)

ai-protocol-mock is designed for downstream runtimes and frameworks that need deterministic testing without real API calls:

- **ZeroClaw / ZeroSpider**: Set `MOCK_HTTP_URL` and `MOCK_MCP_URL` to the mock server (e.g. `http://192.168.2.13:4010`) before running integration tests. Use `NO_PROXY` to bypass HTTP proxies when testing against a local or LAN mock.
- **CI pipelines**: Start mock via `docker-compose up -d` or `uvicorn ai_protocol_mock.main:app --host 0.0.0.0 --port 4010`, then run tests with the env vars above.
- **Error injection**: Set `ERROR_RATE=0.1` to simulate 429/500/503 for resilience testing.

**Remote / proxy environments**: If your machine uses HTTP/HTTPS proxy, set `NO_PROXY` to include the mock server IP so Python's httpx can reach it directly:

```bash
NO_PROXY=192.168.2.13,localhost,127.0.0.1 MOCK_HTTP_URL=http://192.168.2.13:4010 MOCK_MCP_URL=http://192.168.2.13:4010/mcp pytest tests/ -v
```

## Using with ai-lib-rust

```bash
export MOCK_HTTP_URL=http://localhost:4010
cargo run --example basic_usage
```

Or run mock integration tests:

```bash
MOCK_HTTP_URL=http://localhost:4010 MOCK_MCP_URL=http://localhost:4010/mcp cargo test -- --ignored --nocapture
```

Or in code:

```rust
let client = AiClientBuilder::new()
    .base_url_override("http://localhost:4010")
    .build("openai/gpt-4o")
    .await?;
```

## Manifest Sync

Sync manifests from the ai-protocol repository:

```bash
python scripts/sync_manifests.py [--force] [--url URL] [--tag REF]
```

- `--force` - Overwrite existing files
- `--tag REF` - Pin to a specific ai-protocol ref (e.g. `v1.0.0`, `main`; **default URL pins `v1.0.0`**)
- `--url URL` - Custom base URL (overrides default pinned release)

Run before starting the server to ensure manifests are up to date. **CI and docker-compose should use `--tag v1.0.0`** (or equivalent URL) so integration tests match the v1.0.0 protocol matrix.

## v1.0 migration (from 0.1.x)

| 0.1.x | v1.0+ |
|-------|-------|
| Path heuristics (`/messages` → Anthropic) | `ContractResolver` + manifest `streaming.decoder.strategy` / `ProviderContract` |
| Hardcoded JSON shapes only | `X-Mock-*` generative branches (reasoning, tools, structured output) |
| `main` manifest sync | Pin **`ai-protocol@v1.0.0`** in CI and `sync_manifests.py` |

Breaking changes are documented in CHANGELOG; PyPI **1.0.1** ships after four-runtime Mock Integration CI is green (MOCK-001-R4).

## Development

```bash
pip install -e ".[dev]"
pytest tests/ -v
ruff check src tests scripts
```

## License

MIT OR Apache-2.0
