Metadata-Version: 2.4
Name: agent-harness-bridge
Version: 0.2.1
Summary: A small compatibility layer for OpenAI Agents SDK, Claude Agent SDK, and DeepSeek Harness
Author-email: chansigit <chansigit@gmail.com>
License: MIT License
        
        Copyright (c) 2026 chansigit
        
        Permission is hereby granted, free of charge, to any person obtaining a copy
        of this software and associated documentation files (the "Software"), to deal
        in the Software without restriction, including without limitation the rights
        to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
        copies of the Software, and to permit persons to whom the Software is
        furnished to do so, subject to the following conditions:
        
        The above copyright notice and this permission notice shall be included in all
        copies or substantial portions of the Software.
        
        THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
        IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
        FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
        AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
        LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
        OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
        SOFTWARE.
        
Project-URL: Homepage, https://github.com/chansigit/agent-harness-bridge
Project-URL: Repository, https://github.com/chansigit/agent-harness-bridge
Project-URL: Issues, https://github.com/chansigit/agent-harness-bridge/issues
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: openai
Requires-Dist: openai-agents==0.22.0; extra == "openai"
Provides-Extra: claude
Requires-Dist: claude-agent-sdk>=0.2.152; extra == "claude"
Provides-Extra: deepseek
Requires-Dist: mcp<2,>=1.19; extra == "deepseek"
Requires-Dist: PyYAML>=6; extra == "deepseek"
Requires-Dist: uvicorn>=0.30; extra == "deepseek"
Requires-Dist: sse-starlette<4,>=3; extra == "deepseek"
Provides-Extra: all
Requires-Dist: openai-agents==0.22.0; extra == "all"
Requires-Dist: claude-agent-sdk>=0.2.152; extra == "all"
Requires-Dist: mcp<2,>=1.19; extra == "all"
Requires-Dist: PyYAML>=6; extra == "all"
Requires-Dist: uvicorn>=0.30; extra == "all"
Requires-Dist: sse-starlette<4,>=3; extra == "all"
Provides-Extra: test
Requires-Dist: pytest>=8; extra == "test"
Dynamic: license-file

# Agent Harness Bridge

`agent-harness-bridge` gives applications one small, submit-tool-oriented API
for three different agent runtimes:

- OpenAI Agents SDK, including OpenAI-compatible endpoints such as Volcengine Ark
- Claude Agent SDK
- DeepSeek Harness (`dsh`)

It deliberately does not hide backend lifecycle differences. Each adapter owns
its native session continuation, MCP transport, timeout, cleanup and recovery
logic, while applications keep their prompts, domain tools and submit
validation.

## Install

Install only the runtime you need, or all validated adapters:

```bash
pip install 'agent-harness-bridge[openai]==0.2.1'
pip install 'agent-harness-bridge[claude]==0.2.1'
pip install 'agent-harness-bridge[deepseek]==0.2.1'
pip install 'agent-harness-bridge[all]==0.2.1'
```

The dsh adapter also imports `deepseek_harness`. DeepSeek's current SDK
depends on a platform-specific runtime wheel, so the bridge does not force
that wheel onto every installation. Install the SDK using the method supported
by the target host. On older-glibc clusters, load `polyfill-glibc/0.1` before
using its runtime or point `DSH_BIN` at a validated source build.

## Configuration

Harness and model selection are independent:

```bash
HARNESS=openai MODEL=doubao-seed-2-1-turbo-260628 python your_workflow.py
HARNESS=openai MODEL=doubao-seed-2-1-pro-260628 python your_workflow.py
HARNESS=deepseek MODEL=doubao-seed-2-1-turbo-260628 python your_workflow.py
HARNESS=claude MODEL=claude-sonnet-5 python your_workflow.py
```

The default remains OpenAI Agents SDK with
`doubao-seed-2-1-turbo-260628`. Model identifiers are intentionally open
strings rather than a hard-coded catalog.

## Logging

Every bridge line (`== [label] agent: tool(...)`, retries, usage limits,
run summaries) goes through the `harness_bridge` logger family at `INFO`.
Configure it once in your CLI entry point, together with your own logger
families, so one stream carries one style of output:

```python
from harness_bridge import configure_logging

configure_logging("myapp")            # harness_bridge + myapp -> stdout, "%(message)s"
configure_logging("myapp", stream=sys.stderr, level="DEBUG")
```

Records are flushed one by one, so Slurm and `tee` logs stay live. If nobody
configured logging before `run_agent` runs, the bridge attaches the same
default handler itself (`ensure_logging`), which keeps the pre-0.2 behaviour
of printing to stdout. Loggers keep propagating to the root logger, so
`pytest`'s `caplog` still sees the records.

## Contract

Applications provide `ToolSpec` objects and designate one successful submit
tool as the completion condition:

```python
from harness_bridge import ToolSpec, run_agent

async def submit(args):
    return {
        "content": [{"type": "text", "text": "accepted"}],
        "_submitted": args,
    }

result = await run_agent(
    tools=[ToolSpec("submit_answer", "Submit the checked answer", {"answer": str}, submit)],
    submit_tool="submit_answer",
    prompt="Check the evidence and submit the answer.",
    cwd="/absolute/read-only/workdir",
)
```

Tool handlers return an MCP-shaped result containing text or image content,
an optional `is_error`, and an optional private `_submitted` value captured by
the host after successful validation. A handler that raises is reported to
the model as an error result under every backend; it never aborts the run.

`run_agent()` validates the tool table before importing any SDK: the submit
tool must be present, tool names must be unique, `allowed_builtin` must be a
subset of `read`, `glob`, `grep`, `tasks`, and application tools may not
reuse the name of a requested builtin.

`allowed_builtin` selects Claude Code's own Read/Glob/Grep/Task tools under
`HARNESS=claude`. The OpenAI and dsh adapters serve same-named, cwd-confined
host tools implemented in pure Python (Grep needs no `rg` on the host), so
prompts stay portable across backends.

`backend_capabilities()` exposes runtime facts that callers can check before a
run. Unsupported built-in capabilities fail closed.

## Design boundary

The bridge owns only runtime concerns. Domain workflows should continue to own:

- prompts and scientific or business policy
- tool handler implementations
- submit validation
- output files and resume manifests

Backend-specific defenses remain adapter-local. In particular, OpenAI
Responses continuation and context reset, Claude SDK teardown and permissions,
and dsh MCP startup/watchdog/SSE recovery are not reduced to a lowest-common-
denominator loop.


### Bounded text reads (0.2.1)

The host `Read` tool used by OpenAI and DeepSeek returns 8 KiB of text by default,
with a 32 KiB hard cap. It accepts `byte_offset` and `max_bytes` (both `0` for the
default first page); truncated results give the exact next offset. UTF-8 characters
are preserved across page boundaries. Existing path-only handler calls still work.
Image reads keep their existing image contract; Claude Code uses its native reader.

Large cell-level CSVs should be queried or searched for specific evidence, rather
than copied into the model context page by page. The smaller default prevents a
single barcode ledger from consuming an entire context window; it does not guarantee
that an arbitrarily long agent session cannot exhaust its context.
