agentshim 0.6.1__tar.gz → 0.6.2__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.
- {agentshim-0.6.1 → agentshim-0.6.2}/CHANGELOG.md +6 -0
- {agentshim-0.6.1 → agentshim-0.6.2}/PKG-INFO +1 -1
- {agentshim-0.6.1 → agentshim-0.6.2}/agentshim/__init__.py +1 -1
- {agentshim-0.6.1 → agentshim-0.6.2}/agentshim/core/mcp.py +20 -1
- {agentshim-0.6.1 → agentshim-0.6.2}/agentshim/providers/claude/provider.py +3 -0
- {agentshim-0.6.1 → agentshim-0.6.2}/agentshim/providers/codex/provider.py +12 -2
- {agentshim-0.6.1 → agentshim-0.6.2}/agentshim/providers/copilot/provider.py +4 -0
- {agentshim-0.6.1 → agentshim-0.6.2}/agentshim/providers/gemini/provider.py +3 -0
- {agentshim-0.6.1 → agentshim-0.6.2}/agentshim/providers/opencode/provider.py +3 -0
- {agentshim-0.6.1 → agentshim-0.6.2}/agentshim/testing/__init__.py +2 -1
- {agentshim-0.6.1 → agentshim-0.6.2}/pyproject.toml +1 -1
- {agentshim-0.6.1 → agentshim-0.6.2}/.gitignore +0 -0
- {agentshim-0.6.1 → agentshim-0.6.2}/README.md +0 -0
- {agentshim-0.6.1 → agentshim-0.6.2}/agentshim/agent.py +0 -0
- {agentshim-0.6.1 → agentshim-0.6.2}/agentshim/core/__init__.py +0 -0
- {agentshim-0.6.1 → agentshim-0.6.2}/agentshim/core/_files.py +0 -0
- {agentshim-0.6.1 → agentshim-0.6.2}/agentshim/core/env.py +0 -0
- {agentshim-0.6.1 → agentshim-0.6.2}/agentshim/core/errors.py +0 -0
- {agentshim-0.6.1 → agentshim-0.6.2}/agentshim/core/events.py +0 -0
- {agentshim-0.6.1 → agentshim-0.6.2}/agentshim/core/profile.py +0 -0
- {agentshim-0.6.1 → agentshim-0.6.2}/agentshim/core/provider.py +0 -0
- {agentshim-0.6.1 → agentshim-0.6.2}/agentshim/core/schema.py +0 -0
- {agentshim-0.6.1 → agentshim-0.6.2}/agentshim/core/stream.py +0 -0
- {agentshim-0.6.1 → agentshim-0.6.2}/agentshim/core/turn.py +0 -0
- {agentshim-0.6.1 → agentshim-0.6.2}/agentshim/core/usage.py +0 -0
- {agentshim-0.6.1 → agentshim-0.6.2}/agentshim/execution/__init__.py +0 -0
- {agentshim-0.6.1 → agentshim-0.6.2}/agentshim/execution/executor.py +0 -0
- {agentshim-0.6.1 → agentshim-0.6.2}/agentshim/execution/host.py +0 -0
- {agentshim-0.6.1 → agentshim-0.6.2}/agentshim/execution/transform.py +0 -0
- {agentshim-0.6.1 → agentshim-0.6.2}/agentshim/providers/__init__.py +0 -0
- {agentshim-0.6.1 → agentshim-0.6.2}/agentshim/providers/claude/__init__.py +0 -0
- {agentshim-0.6.1 → agentshim-0.6.2}/agentshim/providers/claude/events.py +0 -0
- {agentshim-0.6.1 → agentshim-0.6.2}/agentshim/providers/claude/hooks/__init__.py +0 -0
- {agentshim-0.6.1 → agentshim-0.6.2}/agentshim/providers/claude/hooks/confine_reads.py +0 -0
- {agentshim-0.6.1 → agentshim-0.6.2}/agentshim/providers/claude/parser.py +0 -0
- {agentshim-0.6.1 → agentshim-0.6.2}/agentshim/providers/claude/sandbox.py +0 -0
- {agentshim-0.6.1 → agentshim-0.6.2}/agentshim/providers/claude/scripted.py +0 -0
- {agentshim-0.6.1 → agentshim-0.6.2}/agentshim/providers/codex/__init__.py +0 -0
- {agentshim-0.6.1 → agentshim-0.6.2}/agentshim/providers/codex/events.py +0 -0
- {agentshim-0.6.1 → agentshim-0.6.2}/agentshim/providers/codex/parser.py +0 -0
- {agentshim-0.6.1 → agentshim-0.6.2}/agentshim/providers/codex/scripted.py +0 -0
- {agentshim-0.6.1 → agentshim-0.6.2}/agentshim/providers/copilot/__init__.py +0 -0
- {agentshim-0.6.1 → agentshim-0.6.2}/agentshim/providers/copilot/events.py +0 -0
- {agentshim-0.6.1 → agentshim-0.6.2}/agentshim/providers/copilot/parser.py +0 -0
- {agentshim-0.6.1 → agentshim-0.6.2}/agentshim/providers/copilot/scripted.py +0 -0
- {agentshim-0.6.1 → agentshim-0.6.2}/agentshim/providers/gemini/__init__.py +0 -0
- {agentshim-0.6.1 → agentshim-0.6.2}/agentshim/providers/gemini/events.py +0 -0
- {agentshim-0.6.1 → agentshim-0.6.2}/agentshim/providers/gemini/parser.py +0 -0
- {agentshim-0.6.1 → agentshim-0.6.2}/agentshim/providers/gemini/scripted.py +0 -0
- {agentshim-0.6.1 → agentshim-0.6.2}/agentshim/providers/opencode/__init__.py +0 -0
- {agentshim-0.6.1 → agentshim-0.6.2}/agentshim/providers/opencode/events.py +0 -0
- {agentshim-0.6.1 → agentshim-0.6.2}/agentshim/providers/opencode/parser.py +0 -0
- {agentshim-0.6.1 → agentshim-0.6.2}/agentshim/providers/opencode/scripted.py +0 -0
- {agentshim-0.6.1 → agentshim-0.6.2}/agentshim/py.typed +0 -0
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.6.2 (2026-09-26)
|
|
4
|
+
|
|
5
|
+
- Add optional positive finite `tool_timeout_s` to stdio and HTTP MCP server
|
|
6
|
+
specs. Codex renders it as an invocation-scoped `tool_timeout_sec` config
|
|
7
|
+
override; providers that cannot represent it reject the request explicitly.
|
|
8
|
+
|
|
3
9
|
## 0.6.1 (2026-09-10)
|
|
4
10
|
|
|
5
11
|
Additive only: every new field defaults, so a 0.6.0 consumer's existing
|
|
@@ -14,6 +14,7 @@ each concurrent turn its own workspace.
|
|
|
14
14
|
from __future__ import annotations
|
|
15
15
|
|
|
16
16
|
import json
|
|
17
|
+
import math
|
|
17
18
|
from dataclasses import dataclass, field
|
|
18
19
|
from types import MappingProxyType
|
|
19
20
|
from typing import TYPE_CHECKING, Any, Literal, cast
|
|
@@ -37,12 +38,18 @@ def _no_env() -> Mapping[str, str]:
|
|
|
37
38
|
|
|
38
39
|
@dataclass(frozen=True)
|
|
39
40
|
class StdioMcpServer:
|
|
40
|
-
"""MCP server launched as a subprocess over stdio.
|
|
41
|
+
"""MCP server launched as a subprocess over stdio.
|
|
42
|
+
|
|
43
|
+
``tool_timeout_s`` is the maximum time one tool call may run. Providers
|
|
44
|
+
that cannot express a per-server tool timeout reject a non-``None`` value
|
|
45
|
+
rather than silently dropping it.
|
|
46
|
+
"""
|
|
41
47
|
|
|
42
48
|
name: str
|
|
43
49
|
command: str
|
|
44
50
|
args: Sequence[str] = ()
|
|
45
51
|
env: Mapping[str, str] = field(default_factory=_no_env)
|
|
52
|
+
tool_timeout_s: float | None = None
|
|
46
53
|
|
|
47
54
|
def __post_init__(self) -> None:
|
|
48
55
|
"""Reject a spec the provider could never launch.
|
|
@@ -56,6 +63,7 @@ class StdioMcpServer:
|
|
|
56
63
|
if not self.command:
|
|
57
64
|
msg = f"MCP server {self.name!r} must declare a command"
|
|
58
65
|
raise ValueError(msg)
|
|
66
|
+
_validate_tool_timeout(self.name, self.tool_timeout_s)
|
|
59
67
|
|
|
60
68
|
|
|
61
69
|
#: The two remote MCP transports the CLIs distinguish.
|
|
@@ -79,6 +87,7 @@ class HttpMcpServer:
|
|
|
79
87
|
url: str
|
|
80
88
|
headers: Mapping[str, str] = field(default_factory=_no_env)
|
|
81
89
|
transport: McpTransport = "http"
|
|
90
|
+
tool_timeout_s: float | None = None
|
|
82
91
|
|
|
83
92
|
def __post_init__(self) -> None:
|
|
84
93
|
"""Reject a spec the provider could never reach.
|
|
@@ -95,6 +104,16 @@ class HttpMcpServer:
|
|
|
95
104
|
if self.transport not in _TRANSPORTS:
|
|
96
105
|
msg = f"MCP server {self.name!r} transport must be one of {_TRANSPORTS}"
|
|
97
106
|
raise ValueError(msg)
|
|
107
|
+
_validate_tool_timeout(self.name, self.tool_timeout_s)
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def _validate_tool_timeout(name: str, timeout_s: float | None) -> None:
|
|
111
|
+
"""Reject timeout values no provider can apply meaningfully."""
|
|
112
|
+
if timeout_s is None:
|
|
113
|
+
return
|
|
114
|
+
if isinstance(timeout_s, bool) or not math.isfinite(timeout_s) or timeout_s <= 0:
|
|
115
|
+
msg = f"MCP server {name!r} tool_timeout_s must be a positive finite number"
|
|
116
|
+
raise ValueError(msg)
|
|
98
117
|
|
|
99
118
|
|
|
100
119
|
McpServer = StdioMcpServer | HttpMcpServer
|
|
@@ -162,6 +162,9 @@ def _resumed_session_id(argv: Sequence[str]) -> str | None:
|
|
|
162
162
|
|
|
163
163
|
def mcp_entry(server: McpServer) -> dict[str, Any]:
|
|
164
164
|
"""Render one server the way ``.mcp.json`` describes it."""
|
|
165
|
+
if server.tool_timeout_s is not None:
|
|
166
|
+
msg = "claude cannot configure a per-server MCP tool timeout"
|
|
167
|
+
raise ProviderCapabilityError(msg)
|
|
165
168
|
if isinstance(server, HttpMcpServer):
|
|
166
169
|
# Claude validates the config strictly and needs an explicit type; it
|
|
167
170
|
# names the two remote transports exactly as the spec does.
|
|
@@ -186,7 +186,8 @@ def _server_flags(server: McpServer) -> list[str]:
|
|
|
186
186
|
raise ProviderCapabilityError(_HTTP_HEADERS_UNSUPPORTED)
|
|
187
187
|
# A ``--config`` override carries the address and nothing else, so
|
|
188
188
|
# Codex works the transport out from the endpoint itself.
|
|
189
|
-
|
|
189
|
+
flags = ["--config", f"{prefix}.url={_toml_str(server.url)}"]
|
|
190
|
+
return flags + _tool_timeout_flags(prefix, server.tool_timeout_s)
|
|
190
191
|
flags = [
|
|
191
192
|
"--config",
|
|
192
193
|
f"{prefix}.command={_toml_str(server.command)}",
|
|
@@ -195,7 +196,14 @@ def _server_flags(server: McpServer) -> list[str]:
|
|
|
195
196
|
]
|
|
196
197
|
for env_key, env_value in server.env.items():
|
|
197
198
|
flags += ["--config", f"{prefix}.env.{env_key}={_toml_str(env_value)}"]
|
|
198
|
-
return flags
|
|
199
|
+
return flags + _tool_timeout_flags(prefix, server.tool_timeout_s)
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
def _tool_timeout_flags(prefix: str, timeout_s: float | None) -> list[str]:
|
|
203
|
+
"""Render Codex's per-server tool timeout as an invocation override."""
|
|
204
|
+
if timeout_s is None:
|
|
205
|
+
return []
|
|
206
|
+
return ["--config", f"{prefix}.tool_timeout_sec={timeout_s}"]
|
|
199
207
|
|
|
200
208
|
|
|
201
209
|
def _toml_str(value: str) -> str:
|
|
@@ -267,6 +275,8 @@ def _apply_mcp_override(entry: dict[str, Any], field: str, raw_value: str) -> No
|
|
|
267
275
|
elif field == "url":
|
|
268
276
|
entry["url"] = _parse_toml_str(raw_value)
|
|
269
277
|
entry["transport"] = "http"
|
|
278
|
+
elif field == "tool_timeout_sec":
|
|
279
|
+
entry["tool_timeout_s"] = float(raw_value)
|
|
270
280
|
elif field.startswith("env."):
|
|
271
281
|
entry.setdefault("env", {})[field.removeprefix("env.")] = _parse_toml_str(raw_value)
|
|
272
282
|
|
|
@@ -5,6 +5,7 @@ from __future__ import annotations
|
|
|
5
5
|
import json
|
|
6
6
|
from typing import TYPE_CHECKING, Any
|
|
7
7
|
|
|
8
|
+
from agentshim.core.errors import ProviderCapabilityError
|
|
8
9
|
from agentshim.core.mcp import FlagsInstallation, HttpMcpServer, NoopInstallation
|
|
9
10
|
from agentshim.core.profile import McpMechanism, OutputSchemaStyle, ProviderProfile
|
|
10
11
|
|
|
@@ -134,6 +135,9 @@ class CopilotProvider:
|
|
|
134
135
|
|
|
135
136
|
def mcp_entry(server: McpServer) -> dict[str, Any]:
|
|
136
137
|
"""Render one server the way ``--additional-mcp-config`` describes it."""
|
|
138
|
+
if server.tool_timeout_s is not None:
|
|
139
|
+
msg = "copilot cannot configure a per-server MCP tool timeout"
|
|
140
|
+
raise ProviderCapabilityError(msg)
|
|
137
141
|
if isinstance(server, HttpMcpServer):
|
|
138
142
|
# Copilot uses the spec's own transport names in ``type``.
|
|
139
143
|
entry: dict[str, Any] = {"type": server.transport, "url": server.url}
|
|
@@ -154,6 +154,9 @@ def mcp_entry(server: McpServer) -> dict[str, Any]:
|
|
|
154
154
|
``trust: true`` skips Gemini's per-tool approval prompt for servers the
|
|
155
155
|
caller installed on purpose.
|
|
156
156
|
"""
|
|
157
|
+
if server.tool_timeout_s is not None:
|
|
158
|
+
msg = "gemini cannot configure a per-server MCP tool timeout"
|
|
159
|
+
raise ProviderCapabilityError(msg)
|
|
157
160
|
if isinstance(server, HttpMcpServer):
|
|
158
161
|
# Gemini picks the transport by which key holds the address:
|
|
159
162
|
# ``httpUrl`` is streamable HTTP, plain ``url`` is SSE.
|
|
@@ -159,6 +159,9 @@ def mcp_entry(server: McpServer) -> dict[str, Any]:
|
|
|
159
159
|
non-interactive ``run`` mode auto-answers permission prompts, so no
|
|
160
160
|
extra ``permission`` block is needed.
|
|
161
161
|
"""
|
|
162
|
+
if server.tool_timeout_s is not None:
|
|
163
|
+
msg = "opencode cannot configure a per-server MCP tool timeout"
|
|
164
|
+
raise ProviderCapabilityError(msg)
|
|
162
165
|
if isinstance(server, HttpMcpServer):
|
|
163
166
|
# opencode has one remote server type and negotiates the transport
|
|
164
167
|
# itself, so ``transport`` has nothing to select here.
|
|
@@ -215,7 +215,8 @@ def installed_mcp_servers(
|
|
|
215
215
|
Each entry is a plain dict in a canonical shape, regardless of how the
|
|
216
216
|
provider itself renders it: ``command``, ``args`` and ``env`` for a
|
|
217
217
|
server started over stdio, ``url`` and ``transport`` for one reached over
|
|
218
|
-
HTTP.
|
|
218
|
+
HTTP. Either shape includes ``tool_timeout_s`` when the invocation set
|
|
219
|
+
one.
|
|
219
220
|
|
|
220
221
|
Args:
|
|
221
222
|
provider: A registered provider name.
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|