agentshim 0.1.0__tar.gz → 0.2.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.
Files changed (57) hide show
  1. agentshim-0.2.0/PKG-INFO +206 -0
  2. agentshim-0.2.0/README.md +195 -0
  3. {agentshim-0.1.0 → agentshim-0.2.0}/agentshim/__init__.py +6 -6
  4. agentshim-0.2.0/agentshim/base.py +330 -0
  5. {agentshim-0.1.0 → agentshim-0.2.0}/agentshim/cli_agent.py +3 -3
  6. {agentshim-0.1.0 → agentshim-0.2.0}/agentshim/codex/agent.py +1 -1
  7. {agentshim-0.1.0 → agentshim-0.2.0}/pyproject.toml +1 -1
  8. agentshim-0.2.0/tests/unit/test_coding_agent_facade.py +215 -0
  9. {agentshim-0.1.0 → agentshim-0.2.0}/tests/unit/test_coding_agent_recorder_default.py +2 -2
  10. {agentshim-0.1.0 → agentshim-0.2.0}/uv.lock +1 -1
  11. agentshim-0.1.0/PKG-INFO +0 -61
  12. agentshim-0.1.0/README.md +0 -50
  13. agentshim-0.1.0/agentshim/base.py +0 -52
  14. {agentshim-0.1.0 → agentshim-0.2.0}/.github/workflows/ci.yml +0 -0
  15. {agentshim-0.1.0 → agentshim-0.2.0}/.github/workflows/publish.yml +0 -0
  16. {agentshim-0.1.0 → agentshim-0.2.0}/.gitignore +0 -0
  17. {agentshim-0.1.0 → agentshim-0.2.0}/agentshim/claude/__init__.py +0 -0
  18. {agentshim-0.1.0 → agentshim-0.2.0}/agentshim/claude/agent.py +0 -0
  19. {agentshim-0.1.0 → agentshim-0.2.0}/agentshim/claude/events.py +0 -0
  20. {agentshim-0.1.0 → agentshim-0.2.0}/agentshim/claude/hooks/__init__.py +0 -0
  21. {agentshim-0.1.0 → agentshim-0.2.0}/agentshim/claude/hooks/confine_reads.py +0 -0
  22. {agentshim-0.1.0 → agentshim-0.2.0}/agentshim/claude_events.py +0 -0
  23. {agentshim-0.1.0 → agentshim-0.2.0}/agentshim/codex/__init__.py +0 -0
  24. {agentshim-0.1.0 → agentshim-0.2.0}/agentshim/codex/events.py +0 -0
  25. {agentshim-0.1.0 → agentshim-0.2.0}/agentshim/codex_events.py +0 -0
  26. {agentshim-0.1.0 → agentshim-0.2.0}/agentshim/events.py +0 -0
  27. {agentshim-0.1.0 → agentshim-0.2.0}/agentshim/gemini/__init__.py +0 -0
  28. {agentshim-0.1.0 → agentshim-0.2.0}/agentshim/gemini/agent.py +0 -0
  29. {agentshim-0.1.0 → agentshim-0.2.0}/agentshim/gemini/events.py +0 -0
  30. {agentshim-0.1.0 → agentshim-0.2.0}/agentshim/gemini_events.py +0 -0
  31. {agentshim-0.1.0 → agentshim-0.2.0}/agentshim/llm_client.py +0 -0
  32. {agentshim-0.1.0 → agentshim-0.2.0}/agentshim/mcp_config.py +0 -0
  33. {agentshim-0.1.0 → agentshim-0.2.0}/agentshim/opencode/__init__.py +0 -0
  34. {agentshim-0.1.0 → agentshim-0.2.0}/agentshim/opencode/agent.py +0 -0
  35. {agentshim-0.1.0 → agentshim-0.2.0}/agentshim/opencode/events.py +0 -0
  36. {agentshim-0.1.0 → agentshim-0.2.0}/agentshim/opencode_events.py +0 -0
  37. {agentshim-0.1.0 → agentshim-0.2.0}/agentshim/py.typed +0 -0
  38. {agentshim-0.1.0 → agentshim-0.2.0}/agentshim/sandbox.py +0 -0
  39. {agentshim-0.1.0 → agentshim-0.2.0}/agentshim/subagent.py +0 -0
  40. {agentshim-0.1.0 → agentshim-0.2.0}/agentshim/trajectory.py +0 -0
  41. {agentshim-0.1.0 → agentshim-0.2.0}/agentshim/usage.py +0 -0
  42. {agentshim-0.1.0 → agentshim-0.2.0}/agentshim/utils.py +0 -0
  43. {agentshim-0.1.0 → agentshim-0.2.0}/tests/unit/cli_agent/test_agent_cli_cleanup.py +0 -0
  44. {agentshim-0.1.0 → agentshim-0.2.0}/tests/unit/cli_agent/test_check_cli.py +0 -0
  45. {agentshim-0.1.0 → agentshim-0.2.0}/tests/unit/cli_agent/test_cli_prompt_passing.py +0 -0
  46. {agentshim-0.1.0 → agentshim-0.2.0}/tests/unit/llm/conftest.py +0 -0
  47. {agentshim-0.1.0 → agentshim-0.2.0}/tests/unit/llm/test_claude_stream.py +0 -0
  48. {agentshim-0.1.0 → agentshim-0.2.0}/tests/unit/llm/test_gemini_fixture.py +0 -0
  49. {agentshim-0.1.0 → agentshim-0.2.0}/tests/unit/llm/test_gemini_stream.py +0 -0
  50. {agentshim-0.1.0 → agentshim-0.2.0}/tests/unit/test_agent_cli_claude.py +0 -0
  51. {agentshim-0.1.0 → agentshim-0.2.0}/tests/unit/test_agent_cli_codex.py +0 -0
  52. {agentshim-0.1.0 → agentshim-0.2.0}/tests/unit/test_agent_cli_event_parsing.py +0 -0
  53. {agentshim-0.1.0 → agentshim-0.2.0}/tests/unit/test_agent_cli_mcp_unsupported.py +0 -0
  54. {agentshim-0.1.0 → agentshim-0.2.0}/tests/unit/test_agent_cli_resume.py +0 -0
  55. {agentshim-0.1.0 → agentshim-0.2.0}/tests/unit/test_agent_cli_sandbox.py +0 -0
  56. {agentshim-0.1.0 → agentshim-0.2.0}/tests/unit/test_cli_agent_usage.py +0 -0
  57. {agentshim-0.1.0 → agentshim-0.2.0}/tests/unit/test_mcp_config.py +0 -0
@@ -0,0 +1,206 @@
1
+ Metadata-Version: 2.4
2
+ Name: agentshim
3
+ Version: 0.2.0
4
+ Summary: Provider-agnostic coding-agent CLI shims
5
+ Requires-Python: >=3.10
6
+ Requires-Dist: litellm>=1.0.0
7
+ Requires-Dist: loguru>=0.7.2
8
+ Provides-Extra: test
9
+ Requires-Dist: pytest>=8.0.0; extra == 'test'
10
+ Description-Content-Type: text/markdown
11
+
12
+ # agentshim
13
+
14
+ `agentshim` wraps coding-agent CLIs behind one small Python interface.
15
+
16
+ It is useful when you want to drive tools like Claude Code, Codex, Gemini, or
17
+ Opencode from Python without writing provider-specific subprocess plumbing for
18
+ prompting, session resumption, event parsing, or MCP configuration.
19
+
20
+ ## What It Includes
21
+
22
+ - a shared CLI agent abstraction with a provider registry
23
+ - adapters for Claude Code, Codex, Gemini, and Opencode
24
+ - stateful chat sessions that automatically resume provider-native threads
25
+ - MCP server config models for providers that support MCP
26
+ - sandbox settings helpers for Claude Code
27
+ - a lightweight LiteLLM client and subagent helper
28
+ - trajectory/usage helpers used by higher-level runtimes
29
+
30
+ ## Install
31
+
32
+ ```bash
33
+ uv add agentshim
34
+ ```
35
+
36
+ `agentshim` does not bundle the underlying agent CLIs. You still need the
37
+ provider tool you want to use installed and authenticated on your machine, for
38
+ example `claude`, `codex`, `gemini`, or `opencode`.
39
+
40
+ ## Getting Started
41
+
42
+ ### 1. Use the Generic Agent Interface for Chat and Resume
43
+
44
+ If you want to choose a provider at runtime, instantiate `CodingAgent`
45
+ directly with a provider name.
46
+
47
+ ```python
48
+ from agentshim import CodingAgent
49
+
50
+ agent = CodingAgent(provider="claude", model="sonnet")
51
+ chat = agent.start_session(cwd=".")
52
+
53
+ first_reply = chat.generate("Summarize this repository.")
54
+ follow_up = chat.generate("Now list the three highest-risk modules.")
55
+
56
+ print(first_reply)
57
+ print(follow_up)
58
+ print(chat.session_id)
59
+ ```
60
+
61
+ `start_session()` returns a stateful chat object. On the first `generate(...)`
62
+ call, `agentshim` starts a fresh provider conversation. On later calls, it
63
+ automatically resumes the same underlying provider session using the session id
64
+ captured from the first run.
65
+
66
+ That corresponds roughly to these native CLI flows:
67
+
68
+ - Claude Code: first call is like `claude -p ...`, later calls add `claude --resume <session_id> ...`
69
+ - Codex: first call is like `codex exec ...`, later calls add `codex exec resume <thread_id> ...`
70
+ - Gemini: first call is like `gemini ...`, later calls add `gemini --resume <session_id> ...`
71
+ - Opencode: first call is like `opencode run ...`, later calls add `opencode run --session <session_id> ...`
72
+
73
+ If you only want a one-shot request, use `generate(...)` directly instead of
74
+ opening a session:
75
+
76
+ ```python
77
+ from agentshim import CodexCodingAgent
78
+
79
+ agent = CodexCodingAgent(model="gpt-5")
80
+ reply = agent.generate("Write a short summary of this codebase.", cwd=".")
81
+ print(reply)
82
+ ```
83
+
84
+ ### 2. Instantiate a Specific Provider Directly
85
+
86
+ If you already know which backend you want, construct the provider class
87
+ yourself.
88
+
89
+ ```python
90
+ from agentshim import ClaudeCodeCodingAgent
91
+
92
+ agent = ClaudeCodeCodingAgent(model="sonnet")
93
+ chat = agent.start_session(cwd=".")
94
+
95
+ print(chat.generate("What does this project do?"))
96
+ print(chat.generate("Which files should I read first?"))
97
+ ```
98
+
99
+ The bundled provider classes are:
100
+
101
+ - `ClaudeCodeCodingAgent`
102
+ - `CodexCodingAgent`
103
+ - `GeminiCodingAgent`
104
+ - `OpencodeCodingAgent`
105
+
106
+ ### 3. Configure MCP Servers
107
+
108
+ Claude Code and Codex can be configured with MCP servers by passing
109
+ `HttpMcpServer` and `StdioMcpServer` objects at construction time.
110
+
111
+ ```python
112
+ from agentshim import ClaudeCodeCodingAgent, HttpMcpServer, StdioMcpServer
113
+
114
+ agent = ClaudeCodeCodingAgent(
115
+ model="sonnet",
116
+ mcp_servers=[
117
+ HttpMcpServer(
118
+ name="docs",
119
+ url="http://localhost:9000/sse",
120
+ headers={"Authorization": "Bearer dev-token"},
121
+ ),
122
+ StdioMcpServer(
123
+ name="github",
124
+ command="npx",
125
+ args=["-y", "@modelcontextprotocol/server-github"],
126
+ env={"GITHUB_TOKEN": "ghp_example"},
127
+ ),
128
+ ],
129
+ )
130
+
131
+ chat = agent.start_session(cwd=".")
132
+ print(chat.generate("Use the MCP tools to inspect the repo."))
133
+ ```
134
+
135
+ Notes:
136
+
137
+ - `HttpMcpServer` is for HTTP/SSE-backed MCP servers.
138
+ - `StdioMcpServer` is for subprocess-backed MCP servers.
139
+ - Gemini and Opencode currently reject `mcp_servers`; use Claude Code or Codex if you need MCP.
140
+
141
+ ## Extending agentshim
142
+
143
+ Advanced users can register their own providers. `CodingAgent(...)` keeps its
144
+ main constructor portable; provider-specific constructor extras should go
145
+ through `backend_kwargs`.
146
+
147
+ ```python
148
+ from agentshim import BaseCodingAgent, CodingAgent, register_provider
149
+
150
+
151
+ @register_provider("my-agent", aliases=("my-agent-dev",))
152
+ class MyAgent(BaseCodingAgent):
153
+ def __init__(
154
+ self,
155
+ model: str | None = None,
156
+ region: str | None = None,
157
+ recorder=None,
158
+ event_handler=None,
159
+ mcp_servers=None,
160
+ sandbox=False,
161
+ ):
162
+ self.model = model
163
+ self.region = region
164
+ self.recorder = recorder
165
+ self.event_handler = event_handler
166
+
167
+ def generate(self, prompt: str, cwd=None, timeout=300, silent=False) -> str:
168
+ return f"handled: {prompt}"
169
+
170
+
171
+ agent = CodingAgent(
172
+ provider="my-agent-dev",
173
+ model="demo",
174
+ backend_kwargs={"region": "us-west1"},
175
+ )
176
+ print(agent.generate("hello"))
177
+ ```
178
+
179
+ Notes:
180
+
181
+ - Registration is import-driven. Your provider is available only after the module defining it has been imported in the current Python process.
182
+ - `list_providers()` returns canonical provider names only. Aliases resolve via `get_provider_class(...)` and `CodingAgent(provider=...)`.
183
+ - `register_provider(...)` rejects invalid names, abstract classes, and accidental name collisions unless you pass `overwrite=True`.
184
+ - If you want `CodingAgent(...)` to instantiate your provider, its constructor should accept the shared kwargs `model`, `recorder`, `event_handler`, `mcp_servers`, and `sandbox` as needed.
185
+ - If your provider needs extra constructor arguments beyond the shared portable set, pass them via `backend_kwargs={...}` when constructing `CodingAgent(...)`.
186
+
187
+ ## Development
188
+
189
+ ```bash
190
+ uv sync --dev
191
+ uv run pytest
192
+ ```
193
+
194
+ ## Publishing
195
+
196
+ Build locally with:
197
+
198
+ ```bash
199
+ uv build
200
+ ```
201
+
202
+ Publish with:
203
+
204
+ ```bash
205
+ uv publish
206
+ ```
@@ -0,0 +1,195 @@
1
+ # agentshim
2
+
3
+ `agentshim` wraps coding-agent CLIs behind one small Python interface.
4
+
5
+ It is useful when you want to drive tools like Claude Code, Codex, Gemini, or
6
+ Opencode from Python without writing provider-specific subprocess plumbing for
7
+ prompting, session resumption, event parsing, or MCP configuration.
8
+
9
+ ## What It Includes
10
+
11
+ - a shared CLI agent abstraction with a provider registry
12
+ - adapters for Claude Code, Codex, Gemini, and Opencode
13
+ - stateful chat sessions that automatically resume provider-native threads
14
+ - MCP server config models for providers that support MCP
15
+ - sandbox settings helpers for Claude Code
16
+ - a lightweight LiteLLM client and subagent helper
17
+ - trajectory/usage helpers used by higher-level runtimes
18
+
19
+ ## Install
20
+
21
+ ```bash
22
+ uv add agentshim
23
+ ```
24
+
25
+ `agentshim` does not bundle the underlying agent CLIs. You still need the
26
+ provider tool you want to use installed and authenticated on your machine, for
27
+ example `claude`, `codex`, `gemini`, or `opencode`.
28
+
29
+ ## Getting Started
30
+
31
+ ### 1. Use the Generic Agent Interface for Chat and Resume
32
+
33
+ If you want to choose a provider at runtime, instantiate `CodingAgent`
34
+ directly with a provider name.
35
+
36
+ ```python
37
+ from agentshim import CodingAgent
38
+
39
+ agent = CodingAgent(provider="claude", model="sonnet")
40
+ chat = agent.start_session(cwd=".")
41
+
42
+ first_reply = chat.generate("Summarize this repository.")
43
+ follow_up = chat.generate("Now list the three highest-risk modules.")
44
+
45
+ print(first_reply)
46
+ print(follow_up)
47
+ print(chat.session_id)
48
+ ```
49
+
50
+ `start_session()` returns a stateful chat object. On the first `generate(...)`
51
+ call, `agentshim` starts a fresh provider conversation. On later calls, it
52
+ automatically resumes the same underlying provider session using the session id
53
+ captured from the first run.
54
+
55
+ That corresponds roughly to these native CLI flows:
56
+
57
+ - Claude Code: first call is like `claude -p ...`, later calls add `claude --resume <session_id> ...`
58
+ - Codex: first call is like `codex exec ...`, later calls add `codex exec resume <thread_id> ...`
59
+ - Gemini: first call is like `gemini ...`, later calls add `gemini --resume <session_id> ...`
60
+ - Opencode: first call is like `opencode run ...`, later calls add `opencode run --session <session_id> ...`
61
+
62
+ If you only want a one-shot request, use `generate(...)` directly instead of
63
+ opening a session:
64
+
65
+ ```python
66
+ from agentshim import CodexCodingAgent
67
+
68
+ agent = CodexCodingAgent(model="gpt-5")
69
+ reply = agent.generate("Write a short summary of this codebase.", cwd=".")
70
+ print(reply)
71
+ ```
72
+
73
+ ### 2. Instantiate a Specific Provider Directly
74
+
75
+ If you already know which backend you want, construct the provider class
76
+ yourself.
77
+
78
+ ```python
79
+ from agentshim import ClaudeCodeCodingAgent
80
+
81
+ agent = ClaudeCodeCodingAgent(model="sonnet")
82
+ chat = agent.start_session(cwd=".")
83
+
84
+ print(chat.generate("What does this project do?"))
85
+ print(chat.generate("Which files should I read first?"))
86
+ ```
87
+
88
+ The bundled provider classes are:
89
+
90
+ - `ClaudeCodeCodingAgent`
91
+ - `CodexCodingAgent`
92
+ - `GeminiCodingAgent`
93
+ - `OpencodeCodingAgent`
94
+
95
+ ### 3. Configure MCP Servers
96
+
97
+ Claude Code and Codex can be configured with MCP servers by passing
98
+ `HttpMcpServer` and `StdioMcpServer` objects at construction time.
99
+
100
+ ```python
101
+ from agentshim import ClaudeCodeCodingAgent, HttpMcpServer, StdioMcpServer
102
+
103
+ agent = ClaudeCodeCodingAgent(
104
+ model="sonnet",
105
+ mcp_servers=[
106
+ HttpMcpServer(
107
+ name="docs",
108
+ url="http://localhost:9000/sse",
109
+ headers={"Authorization": "Bearer dev-token"},
110
+ ),
111
+ StdioMcpServer(
112
+ name="github",
113
+ command="npx",
114
+ args=["-y", "@modelcontextprotocol/server-github"],
115
+ env={"GITHUB_TOKEN": "ghp_example"},
116
+ ),
117
+ ],
118
+ )
119
+
120
+ chat = agent.start_session(cwd=".")
121
+ print(chat.generate("Use the MCP tools to inspect the repo."))
122
+ ```
123
+
124
+ Notes:
125
+
126
+ - `HttpMcpServer` is for HTTP/SSE-backed MCP servers.
127
+ - `StdioMcpServer` is for subprocess-backed MCP servers.
128
+ - Gemini and Opencode currently reject `mcp_servers`; use Claude Code or Codex if you need MCP.
129
+
130
+ ## Extending agentshim
131
+
132
+ Advanced users can register their own providers. `CodingAgent(...)` keeps its
133
+ main constructor portable; provider-specific constructor extras should go
134
+ through `backend_kwargs`.
135
+
136
+ ```python
137
+ from agentshim import BaseCodingAgent, CodingAgent, register_provider
138
+
139
+
140
+ @register_provider("my-agent", aliases=("my-agent-dev",))
141
+ class MyAgent(BaseCodingAgent):
142
+ def __init__(
143
+ self,
144
+ model: str | None = None,
145
+ region: str | None = None,
146
+ recorder=None,
147
+ event_handler=None,
148
+ mcp_servers=None,
149
+ sandbox=False,
150
+ ):
151
+ self.model = model
152
+ self.region = region
153
+ self.recorder = recorder
154
+ self.event_handler = event_handler
155
+
156
+ def generate(self, prompt: str, cwd=None, timeout=300, silent=False) -> str:
157
+ return f"handled: {prompt}"
158
+
159
+
160
+ agent = CodingAgent(
161
+ provider="my-agent-dev",
162
+ model="demo",
163
+ backend_kwargs={"region": "us-west1"},
164
+ )
165
+ print(agent.generate("hello"))
166
+ ```
167
+
168
+ Notes:
169
+
170
+ - Registration is import-driven. Your provider is available only after the module defining it has been imported in the current Python process.
171
+ - `list_providers()` returns canonical provider names only. Aliases resolve via `get_provider_class(...)` and `CodingAgent(provider=...)`.
172
+ - `register_provider(...)` rejects invalid names, abstract classes, and accidental name collisions unless you pass `overwrite=True`.
173
+ - If you want `CodingAgent(...)` to instantiate your provider, its constructor should accept the shared kwargs `model`, `recorder`, `event_handler`, `mcp_servers`, and `sandbox` as needed.
174
+ - If your provider needs extra constructor arguments beyond the shared portable set, pass them via `backend_kwargs={...}` when constructing `CodingAgent(...)`.
175
+
176
+ ## Development
177
+
178
+ ```bash
179
+ uv sync --dev
180
+ uv run pytest
181
+ ```
182
+
183
+ ## Publishing
184
+
185
+ Build locally with:
186
+
187
+ ```bash
188
+ uv build
189
+ ```
190
+
191
+ Publish with:
192
+
193
+ ```bash
194
+ uv publish
195
+ ```
@@ -1,15 +1,18 @@
1
- from .base import CodingAgent
1
+ from .base import BaseAgentSession, BaseCodingAgent, CodingAgent, get_provider_class, list_providers, register_provider
2
2
  from .claude import ClaudeCodeCodingAgent
3
3
  from .codex import CodexCodingAgent
4
4
  from .gemini import GeminiCodingAgent
5
- from .llm_client import LiteLLMClient
6
5
  from .mcp_config import HttpMcpServer, McpServerConfig, StdioMcpServer
7
6
  from .opencode import OpencodeCodingAgent
8
7
  from .sandbox import SandboxConfig
9
- from .subagent import call_subagent, litellm_call_with_retry
10
8
 
11
9
  __all__ = [
10
+ "BaseCodingAgent",
11
+ "BaseAgentSession",
12
12
  "CodingAgent",
13
+ "get_provider_class",
14
+ "list_providers",
15
+ "register_provider",
13
16
  "CodexCodingAgent",
14
17
  "GeminiCodingAgent",
15
18
  "OpencodeCodingAgent",
@@ -18,7 +21,4 @@ __all__ = [
18
21
  "McpServerConfig",
19
22
  "StdioMcpServer",
20
23
  "SandboxConfig",
21
- "call_subagent",
22
- "litellm_call_with_retry",
23
- "LiteLLMClient",
24
24
  ]