agentabi 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- agentabi-0.1.0/LICENSE +21 -0
- agentabi-0.1.0/PKG-INFO +145 -0
- agentabi-0.1.0/README.md +102 -0
- agentabi-0.1.0/pyproject.toml +99 -0
- agentabi-0.1.0/setup.cfg +4 -0
- agentabi-0.1.0/src/agentabi/__init__.py +95 -0
- agentabi-0.1.0/src/agentabi/auto_detect.py +68 -0
- agentabi-0.1.0/src/agentabi/providers/__init__.py +22 -0
- agentabi-0.1.0/src/agentabi/providers/base.py +141 -0
- agentabi-0.1.0/src/agentabi/providers/claude_native.py +312 -0
- agentabi-0.1.0/src/agentabi/providers/claude_sdk.py +244 -0
- agentabi-0.1.0/src/agentabi/providers/codex_sdk.py +280 -0
- agentabi-0.1.0/src/agentabi/providers/gemini_native.py +260 -0
- agentabi-0.1.0/src/agentabi/providers/gemini_sdk.py +205 -0
- agentabi-0.1.0/src/agentabi/providers/opencode_native.py +256 -0
- agentabi-0.1.0/src/agentabi/providers/registry.py +115 -0
- agentabi-0.1.0/src/agentabi/py.typed +0 -0
- agentabi-0.1.0/src/agentabi/session.py +197 -0
- agentabi-0.1.0/src/agentabi/types/__init__.py +3 -0
- agentabi-0.1.0/src/agentabi/types/ir/__init__.py +77 -0
- agentabi-0.1.0/src/agentabi/types/ir/capabilities.py +45 -0
- agentabi-0.1.0/src/agentabi/types/ir/events.py +227 -0
- agentabi-0.1.0/src/agentabi/types/ir/helpers.py +117 -0
- agentabi-0.1.0/src/agentabi/types/ir/permissions.py +60 -0
- agentabi-0.1.0/src/agentabi/types/ir/session.py +87 -0
- agentabi-0.1.0/src/agentabi/types/ir/task.py +84 -0
- agentabi-0.1.0/src/agentabi/types/ir/type_guards.py +106 -0
- agentabi-0.1.0/src/agentabi.egg-info/PKG-INFO +145 -0
- agentabi-0.1.0/src/agentabi.egg-info/SOURCES.txt +32 -0
- agentabi-0.1.0/src/agentabi.egg-info/dependency_links.txt +1 -0
- agentabi-0.1.0/src/agentabi.egg-info/requires.txt +21 -0
- agentabi-0.1.0/src/agentabi.egg-info/top_level.txt +1 -0
- agentabi-0.1.0/tests/test_ir_types.py +53 -0
- agentabi-0.1.0/tests/test_session.py +40 -0
agentabi-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Peng Ding
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
agentabi-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: agentabi
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Unified async Python API for driving coding agent CLIs — Claude Code, Codex, Gemini CLI, and more
|
|
5
|
+
Author-email: Peng Ding <pding.dp@foxmail.com>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Documentation, https://agentabi.readthedocs.io
|
|
8
|
+
Project-URL: Repository, https://github.com/oaklight/agentabi
|
|
9
|
+
Project-URL: Issues, https://github.com/oaklight/agentabi/issues
|
|
10
|
+
Keywords: ai,agent,coding-agent,cli,claude-code,codex,gemini-cli,opencode,llm,async,subprocess,orchestration,streaming,multi-agent,automation
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Operating System :: OS Independent
|
|
20
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
21
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
|
+
Classifier: Typing :: Typed
|
|
23
|
+
Requires-Python: >=3.9
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
License-File: LICENSE
|
|
26
|
+
Requires-Dist: typing_extensions>=4.0.0
|
|
27
|
+
Provides-Extra: claude
|
|
28
|
+
Requires-Dist: claude-agent-sdk>=0.1.0; extra == "claude"
|
|
29
|
+
Provides-Extra: codex
|
|
30
|
+
Requires-Dist: codex-sdk-python>=0.1.0; extra == "codex"
|
|
31
|
+
Provides-Extra: gemini
|
|
32
|
+
Requires-Dist: gemini-cli-sdk>=0.5.0; extra == "gemini"
|
|
33
|
+
Provides-Extra: all
|
|
34
|
+
Requires-Dist: claude-agent-sdk>=0.1.0; extra == "all"
|
|
35
|
+
Requires-Dist: codex-sdk-python>=0.1.0; extra == "all"
|
|
36
|
+
Requires-Dist: gemini-cli-sdk>=0.5.0; extra == "all"
|
|
37
|
+
Provides-Extra: dev
|
|
38
|
+
Requires-Dist: pytest>=7.0.0; extra == "dev"
|
|
39
|
+
Requires-Dist: pytest-asyncio>=0.21.0; extra == "dev"
|
|
40
|
+
Requires-Dist: pytest-cov; extra == "dev"
|
|
41
|
+
Requires-Dist: ruff; extra == "dev"
|
|
42
|
+
Dynamic: license-file
|
|
43
|
+
|
|
44
|
+
# agentabi
|
|
45
|
+
|
|
46
|
+
Unified interface layer for agentic coding CLIs.
|
|
47
|
+
|
|
48
|
+
One interface. Any coding agent.
|
|
49
|
+
|
|
50
|
+
## What is agentabi?
|
|
51
|
+
|
|
52
|
+
`agentabi` provides a stable, unified interface (an "ABI") for interacting with different agentic coding CLIs. Write your integration once, swap agents with a config change.
|
|
53
|
+
|
|
54
|
+
### Supported Agents
|
|
55
|
+
|
|
56
|
+
| Agent | Provider | Status |
|
|
57
|
+
|-------|----------|--------|
|
|
58
|
+
| [Claude Code](https://github.com/anthropics/claude-code) | Anthropic | Implemented |
|
|
59
|
+
| [Codex](https://github.com/openai/codex) | OpenAI | Implemented |
|
|
60
|
+
| [Gemini CLI](https://github.com/google-gemini/gemini-cli) | Google | Implemented |
|
|
61
|
+
| [OpenCode](https://opencode.ai) | Open Source | Implemented |
|
|
62
|
+
|
|
63
|
+
## Installation
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
pip install agentabi
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
With optional SDK integrations:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
pip install agentabi[claude] # Claude Code SDK support
|
|
73
|
+
pip install agentabi[codex] # Codex SDK support
|
|
74
|
+
pip install agentabi[gemini] # Gemini CLI SDK support
|
|
75
|
+
pip install agentabi[all] # All optional SDKs
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
> **Note:** Each agent's CLI must be installed separately (e.g., `claude`, `codex`, `gemini`, `opencode`).
|
|
79
|
+
|
|
80
|
+
## Quick Start
|
|
81
|
+
|
|
82
|
+
### Run a task
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
import asyncio
|
|
86
|
+
from agentabi import Session
|
|
87
|
+
|
|
88
|
+
async def main():
|
|
89
|
+
session = Session(agent="claude_code")
|
|
90
|
+
result = await session.run(prompt="Fix the bug in auth.py")
|
|
91
|
+
print(result["status"]) # "success"
|
|
92
|
+
print(result["result_text"]) # agent's response
|
|
93
|
+
|
|
94
|
+
asyncio.run(main())
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Stream events
|
|
98
|
+
|
|
99
|
+
```python
|
|
100
|
+
async for event in session.stream(prompt="Explain this code"):
|
|
101
|
+
if event["type"] == "message_delta":
|
|
102
|
+
print(event["text"], end="")
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Sync convenience
|
|
106
|
+
|
|
107
|
+
```python
|
|
108
|
+
from agentabi import run_sync
|
|
109
|
+
|
|
110
|
+
result = run_sync(prompt="List Python files", agent="codex")
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Discover available agents
|
|
114
|
+
|
|
115
|
+
```python
|
|
116
|
+
from agentabi import detect_agents, get_agent_capabilities
|
|
117
|
+
|
|
118
|
+
agents = detect_agents() # ["claude_code", "codex", ...]
|
|
119
|
+
caps = get_agent_capabilities("claude_code")
|
|
120
|
+
print(caps["supports_streaming"]) # True
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## Use Cases
|
|
124
|
+
|
|
125
|
+
- **Fleet Management** — Unified entry point for managing multiple coding agents
|
|
126
|
+
- **Agent-to-Agent Calls** — Translation layer for inter-agent invocation
|
|
127
|
+
- **Benchmarking** — Run the same task across agents, compare results
|
|
128
|
+
- **Fallback & Routing** — Automatic failover and cost-aware routing
|
|
129
|
+
- **Middleware Pipeline** — Inject logging, metering, security scanning, audit trails
|
|
130
|
+
- **CI/CD Integration** — Vendor-agnostic agent integration for pipelines
|
|
131
|
+
|
|
132
|
+
## Ecosystem
|
|
133
|
+
|
|
134
|
+
`agentabi` is part of a layered stack:
|
|
135
|
+
|
|
136
|
+
```
|
|
137
|
+
agentabi → Agent CLI unified interface → like an OS ABI
|
|
138
|
+
llmir → LLM API format conversion → like a compiler IR
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
- [llmir](https://github.com/Oaklight/llmir) — LLM Intermediate Representation for converting between LLM provider API formats (OpenAI, Anthropic, Google)
|
|
142
|
+
|
|
143
|
+
## License
|
|
144
|
+
|
|
145
|
+
[MIT](LICENSE)
|
agentabi-0.1.0/README.md
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# agentabi
|
|
2
|
+
|
|
3
|
+
Unified interface layer for agentic coding CLIs.
|
|
4
|
+
|
|
5
|
+
One interface. Any coding agent.
|
|
6
|
+
|
|
7
|
+
## What is agentabi?
|
|
8
|
+
|
|
9
|
+
`agentabi` provides a stable, unified interface (an "ABI") for interacting with different agentic coding CLIs. Write your integration once, swap agents with a config change.
|
|
10
|
+
|
|
11
|
+
### Supported Agents
|
|
12
|
+
|
|
13
|
+
| Agent | Provider | Status |
|
|
14
|
+
|-------|----------|--------|
|
|
15
|
+
| [Claude Code](https://github.com/anthropics/claude-code) | Anthropic | Implemented |
|
|
16
|
+
| [Codex](https://github.com/openai/codex) | OpenAI | Implemented |
|
|
17
|
+
| [Gemini CLI](https://github.com/google-gemini/gemini-cli) | Google | Implemented |
|
|
18
|
+
| [OpenCode](https://opencode.ai) | Open Source | Implemented |
|
|
19
|
+
|
|
20
|
+
## Installation
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
pip install agentabi
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
With optional SDK integrations:
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
pip install agentabi[claude] # Claude Code SDK support
|
|
30
|
+
pip install agentabi[codex] # Codex SDK support
|
|
31
|
+
pip install agentabi[gemini] # Gemini CLI SDK support
|
|
32
|
+
pip install agentabi[all] # All optional SDKs
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
> **Note:** Each agent's CLI must be installed separately (e.g., `claude`, `codex`, `gemini`, `opencode`).
|
|
36
|
+
|
|
37
|
+
## Quick Start
|
|
38
|
+
|
|
39
|
+
### Run a task
|
|
40
|
+
|
|
41
|
+
```python
|
|
42
|
+
import asyncio
|
|
43
|
+
from agentabi import Session
|
|
44
|
+
|
|
45
|
+
async def main():
|
|
46
|
+
session = Session(agent="claude_code")
|
|
47
|
+
result = await session.run(prompt="Fix the bug in auth.py")
|
|
48
|
+
print(result["status"]) # "success"
|
|
49
|
+
print(result["result_text"]) # agent's response
|
|
50
|
+
|
|
51
|
+
asyncio.run(main())
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Stream events
|
|
55
|
+
|
|
56
|
+
```python
|
|
57
|
+
async for event in session.stream(prompt="Explain this code"):
|
|
58
|
+
if event["type"] == "message_delta":
|
|
59
|
+
print(event["text"], end="")
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Sync convenience
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
from agentabi import run_sync
|
|
66
|
+
|
|
67
|
+
result = run_sync(prompt="List Python files", agent="codex")
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Discover available agents
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
from agentabi import detect_agents, get_agent_capabilities
|
|
74
|
+
|
|
75
|
+
agents = detect_agents() # ["claude_code", "codex", ...]
|
|
76
|
+
caps = get_agent_capabilities("claude_code")
|
|
77
|
+
print(caps["supports_streaming"]) # True
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## Use Cases
|
|
81
|
+
|
|
82
|
+
- **Fleet Management** — Unified entry point for managing multiple coding agents
|
|
83
|
+
- **Agent-to-Agent Calls** — Translation layer for inter-agent invocation
|
|
84
|
+
- **Benchmarking** — Run the same task across agents, compare results
|
|
85
|
+
- **Fallback & Routing** — Automatic failover and cost-aware routing
|
|
86
|
+
- **Middleware Pipeline** — Inject logging, metering, security scanning, audit trails
|
|
87
|
+
- **CI/CD Integration** — Vendor-agnostic agent integration for pipelines
|
|
88
|
+
|
|
89
|
+
## Ecosystem
|
|
90
|
+
|
|
91
|
+
`agentabi` is part of a layered stack:
|
|
92
|
+
|
|
93
|
+
```
|
|
94
|
+
agentabi → Agent CLI unified interface → like an OS ABI
|
|
95
|
+
llmir → LLM API format conversion → like a compiler IR
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
- [llmir](https://github.com/Oaklight/llmir) — LLM Intermediate Representation for converting between LLM provider API formats (OpenAI, Anthropic, Google)
|
|
99
|
+
|
|
100
|
+
## License
|
|
101
|
+
|
|
102
|
+
[MIT](LICENSE)
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
requires = ["setuptools>=61.0"]
|
|
3
|
+
build-backend = "setuptools.build_meta"
|
|
4
|
+
|
|
5
|
+
[project]
|
|
6
|
+
name = "agentabi"
|
|
7
|
+
dynamic = ["version"]
|
|
8
|
+
authors = [{name = "Peng Ding", email = "pding.dp@foxmail.com"}]
|
|
9
|
+
description = "Unified async Python API for driving coding agent CLIs — Claude Code, Codex, Gemini CLI, and more"
|
|
10
|
+
readme = "README.md"
|
|
11
|
+
requires-python = ">=3.9"
|
|
12
|
+
license = "MIT"
|
|
13
|
+
keywords = [
|
|
14
|
+
"ai",
|
|
15
|
+
"agent",
|
|
16
|
+
"coding-agent",
|
|
17
|
+
"cli",
|
|
18
|
+
"claude-code",
|
|
19
|
+
"codex",
|
|
20
|
+
"gemini-cli",
|
|
21
|
+
"opencode",
|
|
22
|
+
"llm",
|
|
23
|
+
"async",
|
|
24
|
+
"subprocess",
|
|
25
|
+
"orchestration",
|
|
26
|
+
"streaming",
|
|
27
|
+
"multi-agent",
|
|
28
|
+
"automation",
|
|
29
|
+
]
|
|
30
|
+
classifiers = [
|
|
31
|
+
"Development Status :: 3 - Alpha",
|
|
32
|
+
"Intended Audience :: Developers",
|
|
33
|
+
"Programming Language :: Python :: 3",
|
|
34
|
+
"Programming Language :: Python :: 3.9",
|
|
35
|
+
"Programming Language :: Python :: 3.10",
|
|
36
|
+
"Programming Language :: Python :: 3.11",
|
|
37
|
+
"Programming Language :: Python :: 3.12",
|
|
38
|
+
"Programming Language :: Python :: 3.13",
|
|
39
|
+
"Operating System :: OS Independent",
|
|
40
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
41
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
42
|
+
"Typing :: Typed",
|
|
43
|
+
]
|
|
44
|
+
dependencies = [
|
|
45
|
+
"typing_extensions>=4.0.0",
|
|
46
|
+
]
|
|
47
|
+
|
|
48
|
+
[project.optional-dependencies]
|
|
49
|
+
claude = ["claude-agent-sdk>=0.1.0"]
|
|
50
|
+
codex = ["codex-sdk-python>=0.1.0"]
|
|
51
|
+
gemini = ["gemini-cli-sdk>=0.5.0"]
|
|
52
|
+
all = [
|
|
53
|
+
"claude-agent-sdk>=0.1.0",
|
|
54
|
+
"codex-sdk-python>=0.1.0",
|
|
55
|
+
"gemini-cli-sdk>=0.5.0",
|
|
56
|
+
]
|
|
57
|
+
dev = [
|
|
58
|
+
"pytest>=7.0.0",
|
|
59
|
+
"pytest-asyncio>=0.21.0",
|
|
60
|
+
"pytest-cov",
|
|
61
|
+
"ruff",
|
|
62
|
+
]
|
|
63
|
+
|
|
64
|
+
[project.urls]
|
|
65
|
+
Documentation = "https://agentabi.readthedocs.io"
|
|
66
|
+
Repository = "https://github.com/oaklight/agentabi"
|
|
67
|
+
Issues = "https://github.com/oaklight/agentabi/issues"
|
|
68
|
+
|
|
69
|
+
[tool.setuptools.dynamic]
|
|
70
|
+
version = {attr = "agentabi.__version__"}
|
|
71
|
+
|
|
72
|
+
[tool.setuptools.packages.find]
|
|
73
|
+
where = ["src"]
|
|
74
|
+
|
|
75
|
+
[tool.setuptools.package-data]
|
|
76
|
+
"agentabi" = ["py.typed"]
|
|
77
|
+
|
|
78
|
+
[tool.ruff]
|
|
79
|
+
line-length = 88
|
|
80
|
+
target-version = "py39"
|
|
81
|
+
|
|
82
|
+
[tool.ruff.lint]
|
|
83
|
+
select = ["E", "F", "I", "W"]
|
|
84
|
+
|
|
85
|
+
[tool.pytest.ini_options]
|
|
86
|
+
asyncio_mode = "auto"
|
|
87
|
+
markers = [
|
|
88
|
+
"integration: Real CLI integration tests (require installed CLIs)",
|
|
89
|
+
"claude: Tests requiring Claude Code CLI",
|
|
90
|
+
"codex: Tests requiring Codex CLI",
|
|
91
|
+
"gemini: Tests requiring Gemini CLI",
|
|
92
|
+
"opencode: Tests requiring OpenCode CLI",
|
|
93
|
+
"cross_cli: Cross-CLI consistency tests",
|
|
94
|
+
]
|
|
95
|
+
|
|
96
|
+
[tool.ty]
|
|
97
|
+
# Optional SDK deps are not installed during type checking
|
|
98
|
+
[tool.ty.rules]
|
|
99
|
+
unresolved-import = "ignore"
|
agentabi-0.1.0/setup.cfg
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
"""
|
|
2
|
+
agentabi - Unified interface layer for agentic coding CLIs.
|
|
3
|
+
|
|
4
|
+
agentabi wraps multiple coding agent CLIs (Claude Code, Codex, Gemini CLI,
|
|
5
|
+
OpenCode) behind a unified async Python API with streaming support.
|
|
6
|
+
|
|
7
|
+
Quick start:
|
|
8
|
+
from agentabi import Session
|
|
9
|
+
|
|
10
|
+
session = Session(agent="claude_code")
|
|
11
|
+
result = await session.run(prompt="Fix the bug in auth.py")
|
|
12
|
+
|
|
13
|
+
Streaming:
|
|
14
|
+
async for event in session.stream(prompt="Explain this code"):
|
|
15
|
+
if event["type"] == "message_delta":
|
|
16
|
+
print(event["text"], end="")
|
|
17
|
+
|
|
18
|
+
Sync convenience:
|
|
19
|
+
from agentabi import run_sync
|
|
20
|
+
result = run_sync(prompt="List Python files", agent="claude_code")
|
|
21
|
+
|
|
22
|
+
Discovery:
|
|
23
|
+
from agentabi import detect_agents, get_agent_capabilities
|
|
24
|
+
agents = detect_agents()
|
|
25
|
+
caps = get_agent_capabilities("claude_code")
|
|
26
|
+
"""
|
|
27
|
+
|
|
28
|
+
from .auto_detect import detect_agents, get_agent_capabilities, get_default_agent
|
|
29
|
+
from .providers.base import Provider
|
|
30
|
+
from .providers.registry import AgentNotAvailable, get_provider
|
|
31
|
+
from .session import Session, run_sync
|
|
32
|
+
from .types.ir import (
|
|
33
|
+
AgentCapabilities,
|
|
34
|
+
AgentType,
|
|
35
|
+
ErrorEvent,
|
|
36
|
+
FileDiffEvent,
|
|
37
|
+
IREvent,
|
|
38
|
+
MessageDeltaEvent,
|
|
39
|
+
MessageEndEvent,
|
|
40
|
+
MessageStartEvent,
|
|
41
|
+
PermissionConfig,
|
|
42
|
+
PermissionLevel,
|
|
43
|
+
PermissionRequest,
|
|
44
|
+
PermissionRequestEvent,
|
|
45
|
+
PermissionResponseEvent,
|
|
46
|
+
SessionEndEvent,
|
|
47
|
+
SessionResult,
|
|
48
|
+
SessionStartEvent,
|
|
49
|
+
SessionStatus,
|
|
50
|
+
TaskConfig,
|
|
51
|
+
ToolResultEvent,
|
|
52
|
+
ToolUseEvent,
|
|
53
|
+
UsageEvent,
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
__version__ = "0.1.0"
|
|
57
|
+
|
|
58
|
+
__all__ = [
|
|
59
|
+
# Consumer API
|
|
60
|
+
"Session",
|
|
61
|
+
"run_sync",
|
|
62
|
+
# Discovery
|
|
63
|
+
"detect_agents",
|
|
64
|
+
"get_agent_capabilities",
|
|
65
|
+
"get_default_agent",
|
|
66
|
+
# Provider
|
|
67
|
+
"Provider",
|
|
68
|
+
"get_provider",
|
|
69
|
+
"AgentNotAvailable",
|
|
70
|
+
# IR types - Task
|
|
71
|
+
"TaskConfig",
|
|
72
|
+
"AgentType",
|
|
73
|
+
# IR types - Events
|
|
74
|
+
"IREvent",
|
|
75
|
+
"SessionStartEvent",
|
|
76
|
+
"SessionEndEvent",
|
|
77
|
+
"MessageStartEvent",
|
|
78
|
+
"MessageDeltaEvent",
|
|
79
|
+
"MessageEndEvent",
|
|
80
|
+
"ToolUseEvent",
|
|
81
|
+
"ToolResultEvent",
|
|
82
|
+
"PermissionRequestEvent",
|
|
83
|
+
"PermissionResponseEvent",
|
|
84
|
+
"UsageEvent",
|
|
85
|
+
"ErrorEvent",
|
|
86
|
+
"FileDiffEvent",
|
|
87
|
+
# IR types - Session
|
|
88
|
+
"SessionResult",
|
|
89
|
+
"SessionStatus",
|
|
90
|
+
# IR types - Capabilities & Permissions
|
|
91
|
+
"AgentCapabilities",
|
|
92
|
+
"PermissionConfig",
|
|
93
|
+
"PermissionLevel",
|
|
94
|
+
"PermissionRequest",
|
|
95
|
+
]
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
"""
|
|
2
|
+
agentabi - Auto Detection
|
|
3
|
+
|
|
4
|
+
Utility functions for auto-detecting available agent CLIs
|
|
5
|
+
and getting agent capabilities.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from typing import List
|
|
11
|
+
|
|
12
|
+
from .providers.registry import (
|
|
13
|
+
AgentNotAvailable,
|
|
14
|
+
get_provider,
|
|
15
|
+
list_available_agents,
|
|
16
|
+
)
|
|
17
|
+
from .types.ir.capabilities import AgentCapabilities
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def detect_agents() -> List[str]:
|
|
21
|
+
"""Detect which agents have at least one available provider.
|
|
22
|
+
|
|
23
|
+
Returns:
|
|
24
|
+
List of available agent type identifiers.
|
|
25
|
+
|
|
26
|
+
Examples:
|
|
27
|
+
>>> agents = detect_agents()
|
|
28
|
+
>>> "claude_code" in agents # True if `claude` is in PATH
|
|
29
|
+
"""
|
|
30
|
+
return list_available_agents()
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def get_agent_capabilities(agent: str) -> AgentCapabilities:
|
|
34
|
+
"""Get the capabilities of a specific agent.
|
|
35
|
+
|
|
36
|
+
Args:
|
|
37
|
+
agent: Agent type identifier.
|
|
38
|
+
|
|
39
|
+
Returns:
|
|
40
|
+
AgentCapabilities for the agent's active provider.
|
|
41
|
+
|
|
42
|
+
Raises:
|
|
43
|
+
AgentNotAvailable: If no provider is available.
|
|
44
|
+
"""
|
|
45
|
+
provider = get_provider(agent)
|
|
46
|
+
return provider.capabilities()
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def get_default_agent() -> str:
|
|
50
|
+
"""Get the first available agent.
|
|
51
|
+
|
|
52
|
+
Returns:
|
|
53
|
+
The first detected agent type identifier.
|
|
54
|
+
|
|
55
|
+
Raises:
|
|
56
|
+
AgentNotAvailable: If no agents are available.
|
|
57
|
+
"""
|
|
58
|
+
available = detect_agents()
|
|
59
|
+
if not available:
|
|
60
|
+
raise AgentNotAvailable("(auto-detect)")
|
|
61
|
+
return available[0]
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
__all__ = [
|
|
65
|
+
"detect_agents",
|
|
66
|
+
"get_agent_capabilities",
|
|
67
|
+
"get_default_agent",
|
|
68
|
+
]
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""
|
|
2
|
+
agentabi - Providers
|
|
3
|
+
|
|
4
|
+
Flat provider model: each provider implements the same Protocol
|
|
5
|
+
for driving a specific agent CLI or SDK.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from .base import Provider
|
|
9
|
+
from .registry import (
|
|
10
|
+
AgentNotAvailable,
|
|
11
|
+
get_provider,
|
|
12
|
+
list_agents,
|
|
13
|
+
resolve_provider,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
__all__ = [
|
|
17
|
+
"Provider",
|
|
18
|
+
"AgentNotAvailable",
|
|
19
|
+
"resolve_provider",
|
|
20
|
+
"get_provider",
|
|
21
|
+
"list_agents",
|
|
22
|
+
]
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
"""
|
|
2
|
+
agentabi - Provider Protocol
|
|
3
|
+
|
|
4
|
+
Single interface for all agent backends. Providers are the only
|
|
5
|
+
abstraction layer between Session and agent CLIs/SDKs.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
from typing import Any, AsyncIterator, List
|
|
11
|
+
|
|
12
|
+
from typing_extensions import Protocol, runtime_checkable
|
|
13
|
+
|
|
14
|
+
from ..types.ir.capabilities import AgentCapabilities
|
|
15
|
+
from ..types.ir.events import IREvent, UsageInfo
|
|
16
|
+
from ..types.ir.session import SessionResult, SessionStatus
|
|
17
|
+
from ..types.ir.task import TaskConfig
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@runtime_checkable
|
|
21
|
+
class Provider(Protocol):
|
|
22
|
+
"""Single interface for all agent backends.
|
|
23
|
+
|
|
24
|
+
Each provider wraps one agent CLI or SDK and translates
|
|
25
|
+
between TaskConfig/IREvent and the agent's native format.
|
|
26
|
+
|
|
27
|
+
Providers form fallback chains per agent (e.g., NativeProvider
|
|
28
|
+
is tried before SDKProvider). The first available provider wins.
|
|
29
|
+
"""
|
|
30
|
+
|
|
31
|
+
@staticmethod
|
|
32
|
+
def is_available() -> bool:
|
|
33
|
+
"""Check if this provider can be used (CLI/SDK installed).
|
|
34
|
+
|
|
35
|
+
Returns:
|
|
36
|
+
True if the provider's dependencies are satisfied.
|
|
37
|
+
"""
|
|
38
|
+
...
|
|
39
|
+
|
|
40
|
+
def capabilities(self) -> AgentCapabilities:
|
|
41
|
+
"""Declare supported features.
|
|
42
|
+
|
|
43
|
+
Returns:
|
|
44
|
+
AgentCapabilities describing what this provider supports.
|
|
45
|
+
"""
|
|
46
|
+
...
|
|
47
|
+
|
|
48
|
+
def stream(self, task: TaskConfig) -> AsyncIterator[IREvent]:
|
|
49
|
+
"""Run task and yield IR events as they arrive.
|
|
50
|
+
|
|
51
|
+
Args:
|
|
52
|
+
task: Unified task configuration.
|
|
53
|
+
|
|
54
|
+
Yields:
|
|
55
|
+
IR events produced by the agent.
|
|
56
|
+
"""
|
|
57
|
+
...
|
|
58
|
+
|
|
59
|
+
async def run(self, task: TaskConfig) -> SessionResult:
|
|
60
|
+
"""Run task and return aggregated result.
|
|
61
|
+
|
|
62
|
+
Default implementation consumes stream() and aggregates events.
|
|
63
|
+
|
|
64
|
+
Args:
|
|
65
|
+
task: Unified task configuration.
|
|
66
|
+
|
|
67
|
+
Returns:
|
|
68
|
+
Aggregated session result.
|
|
69
|
+
"""
|
|
70
|
+
...
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
async def default_run(provider: Any, task: TaskConfig) -> SessionResult:
|
|
74
|
+
"""Default run() implementation that aggregates stream() events.
|
|
75
|
+
|
|
76
|
+
Providers can use this as their run() body to avoid duplication.
|
|
77
|
+
|
|
78
|
+
Args:
|
|
79
|
+
provider: The provider instance (any object with stream()).
|
|
80
|
+
task: Unified task configuration.
|
|
81
|
+
|
|
82
|
+
Returns:
|
|
83
|
+
Aggregated SessionResult built from stream events.
|
|
84
|
+
"""
|
|
85
|
+
session_id = ""
|
|
86
|
+
delta_parts: List[str] = []
|
|
87
|
+
result_text = ""
|
|
88
|
+
status: SessionStatus = "success"
|
|
89
|
+
model = ""
|
|
90
|
+
cost_usd = 0.0
|
|
91
|
+
errors: List[str] = []
|
|
92
|
+
usage: UsageInfo = {}
|
|
93
|
+
|
|
94
|
+
async for event in provider.stream(task):
|
|
95
|
+
etype = event.get("type")
|
|
96
|
+
if etype == "session_start":
|
|
97
|
+
session_id = event.get("session_id", "")
|
|
98
|
+
model = event.get("model", "")
|
|
99
|
+
elif etype == "message_delta":
|
|
100
|
+
text = event.get("text", "")
|
|
101
|
+
if text:
|
|
102
|
+
delta_parts.append(text)
|
|
103
|
+
elif etype == "message_end":
|
|
104
|
+
text = event.get("text")
|
|
105
|
+
if text:
|
|
106
|
+
result_text = text
|
|
107
|
+
elif delta_parts:
|
|
108
|
+
result_text = "".join(delta_parts)
|
|
109
|
+
delta_parts = []
|
|
110
|
+
elif etype == "usage":
|
|
111
|
+
usage = event.get("usage", {})
|
|
112
|
+
cost = event.get("cost_usd")
|
|
113
|
+
if cost is not None:
|
|
114
|
+
cost_usd = cost
|
|
115
|
+
elif etype == "error":
|
|
116
|
+
errors.append(event.get("error", ""))
|
|
117
|
+
if event.get("is_fatal"):
|
|
118
|
+
status = "error"
|
|
119
|
+
|
|
120
|
+
result: SessionResult = {
|
|
121
|
+
"session_id": session_id,
|
|
122
|
+
"status": status,
|
|
123
|
+
}
|
|
124
|
+
if model:
|
|
125
|
+
result["model"] = model
|
|
126
|
+
if result_text:
|
|
127
|
+
result["result_text"] = result_text
|
|
128
|
+
if usage:
|
|
129
|
+
result["usage"] = usage
|
|
130
|
+
if cost_usd:
|
|
131
|
+
result["cost_usd"] = cost_usd
|
|
132
|
+
if errors:
|
|
133
|
+
result["errors"] = errors
|
|
134
|
+
|
|
135
|
+
return result
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
__all__ = [
|
|
139
|
+
"Provider",
|
|
140
|
+
"default_run",
|
|
141
|
+
]
|