inspect-swe 0.2.4__py3-none-any.whl → 0.2.7__py3-none-any.whl
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.
- inspect_swe/__init__.py +1 -2
- inspect_swe/_claude_code/claude_code.py +110 -77
- inspect_swe/_util/_async.py +10 -1
- inspect_swe/_version.py +2 -2
- {inspect_swe-0.2.4.dist-info → inspect_swe-0.2.7.dist-info}/METADATA +2 -2
- {inspect_swe-0.2.4.dist-info → inspect_swe-0.2.7.dist-info}/RECORD +9 -9
- {inspect_swe-0.2.4.dist-info → inspect_swe-0.2.7.dist-info}/WHEEL +0 -0
- {inspect_swe-0.2.4.dist-info → inspect_swe-0.2.7.dist-info}/entry_points.txt +0 -0
- {inspect_swe-0.2.4.dist-info → inspect_swe-0.2.7.dist-info}/licenses/LICENSE +0 -0
inspect_swe/__init__.py
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
from ._claude_code.claude_code import
|
1
|
+
from ._claude_code.claude_code import claude_code
|
2
2
|
from ._tools.download import download_agent_binary
|
3
3
|
from ._util.sandbox import SandboxPlatform
|
4
4
|
|
@@ -10,7 +10,6 @@ except ImportError:
|
|
10
10
|
|
11
11
|
__all__ = [
|
12
12
|
"claude_code",
|
13
|
-
"ClaudeCodeOptions",
|
14
13
|
"download_agent_binary",
|
15
14
|
"SandboxPlatform",
|
16
15
|
"__version__",
|
@@ -4,41 +4,20 @@ from typing import Any, Literal, Sequence
|
|
4
4
|
|
5
5
|
from inspect_ai.agent import (
|
6
6
|
Agent,
|
7
|
+
AgentAttempts,
|
7
8
|
AgentState,
|
8
9
|
agent,
|
9
10
|
agent_with,
|
10
11
|
sandbox_agent_bridge,
|
11
12
|
)
|
12
13
|
from inspect_ai.model import ChatMessageSystem, ChatMessageUser
|
14
|
+
from inspect_ai.scorer import score
|
13
15
|
from inspect_ai.tool import MCPServerConfig
|
14
16
|
from inspect_ai.util import sandbox as sandbox_env
|
15
|
-
from pydantic import BaseModel, Field
|
16
17
|
from pydantic_core import to_json
|
17
18
|
|
18
|
-
from
|
19
|
-
|
20
|
-
# TODO: AgentAttempts
|
21
|
-
# TODO: AgentContinue
|
22
|
-
# TODO: generate config merging (they are passing max_tokens=32000, temperature=1)
|
23
|
-
|
24
|
-
|
25
|
-
class ClaudeCodeOptions(BaseModel):
|
26
|
-
"""Claude Code options."""
|
27
|
-
|
28
|
-
system_prompt: str | None = Field(default=None)
|
29
|
-
"""Additional system prompt to append to default system prompt."""
|
30
|
-
|
31
|
-
mcp_servers: Sequence[MCPServerConfig] | None = Field(default=None)
|
32
|
-
"""MCP servers to make available to the agent."""
|
33
|
-
|
34
|
-
model: str | None = Field(default=None)
|
35
|
-
""" Model name to use for Opus and Sonnet calls (defaults to main model for task)."""
|
36
|
-
|
37
|
-
small_model: str | None = Field(default=None)
|
38
|
-
"""Model to use for Haiku calls (defaults to main model for task)."""
|
39
|
-
|
40
|
-
env: dict[str, str] | None = Field(default=None)
|
41
|
-
"""Environment variables to set for claude code."""
|
19
|
+
from .._util._async import is_callable_coroutine
|
20
|
+
from .install.install import ensure_claude_code_installed
|
42
21
|
|
43
22
|
|
44
23
|
@agent
|
@@ -48,7 +27,14 @@ def claude_code(
|
|
48
27
|
Autonomous coding agent capable of writing, testing, debugging,
|
49
28
|
and iterating on code across multiple languages.
|
50
29
|
"""),
|
51
|
-
|
30
|
+
system_prompt: str | None = None,
|
31
|
+
mcp_servers: Sequence[MCPServerConfig] | None = None,
|
32
|
+
allowed_tools: list[str] | None = None,
|
33
|
+
disallowed_tools: list[str] | None = None,
|
34
|
+
attempts: int | AgentAttempts = 1,
|
35
|
+
model: str | None = None,
|
36
|
+
small_model: str | None = None,
|
37
|
+
env: dict[str, str] | None = None,
|
52
38
|
version: Literal["auto", "sandbox", "stable", "latest"] | str = "auto",
|
53
39
|
user: str | None = None,
|
54
40
|
sandbox: str | None = None,
|
@@ -59,10 +45,22 @@ def claude_code(
|
|
59
45
|
|
60
46
|
The agent can either use a version of Claude Code installed in the sandbox, or can download a version and install it in the sandbox (see docs on `version` option below for details).
|
61
47
|
|
48
|
+
Use `allowed_tools` and `disallowed_tools` to control access to tools. See [Tools available to Claude](https://docs.anthropic.com/en/docs/claude-code/settings#tools-available-to-claude) for the list of built-in tools and [How to use Allowed Tools in Claude Code](https://www.instructa.ai/blog/claude-code/how-to-use-allowed-tools-in-claude-code) for details on the supported syntax. Note that `allowed_tools` enables you to filter allowed parameter values and `disallowed_tools` enables you to remove tools entirely. In other words, `allowed_tools` is not a complete list of what tools are available but rather just filters on tool parameters---to remove tools you need to explicitly set `disallowed_tools`.
|
49
|
+
|
50
|
+
Use the `attempts` option to enable additional submissions if the initial
|
51
|
+
submission(s) are incorrect (by default, no additional attempts are permitted).
|
52
|
+
|
62
53
|
Args:
|
63
54
|
name: Agent name (used in multi-agent systems with `as_tool()` and `handoff()`)
|
64
55
|
description: Agent description (used in multi-agent systems with `as_tool()` and `handoff()`)
|
65
|
-
|
56
|
+
system_prompt: Additional system prompt to append to default system prompt.
|
57
|
+
mcp_servers: MCP servers to make available to the agent.
|
58
|
+
allowed_tools: Parameter filters for built-in tools.
|
59
|
+
disallowed_tools: List of tool names to disallow entirely.
|
60
|
+
attempts: Configure agent to make multiple attempts.
|
61
|
+
model: Model name to use for Opus and Sonnet calls (defaults to main model for task).
|
62
|
+
small_model: Model to use for Haiku calls (defaults to main model for task).
|
63
|
+
env: Environment variables to set for claude code.
|
66
64
|
version: Version of claude code to use. One of:
|
67
65
|
- "auto": Use any available version of claude code in the sandbox, otherwise download the current stable version.
|
68
66
|
- "sandbox": Use the version of claude code in the sandbox (raises `RuntimeError` if claude is not available in the sandbox)
|
@@ -72,16 +70,12 @@ def claude_code(
|
|
72
70
|
user: User to execute claude code with.
|
73
71
|
sandbox: Optional sandbox environment name.
|
74
72
|
"""
|
75
|
-
# provide default options if none specified
|
76
|
-
options = options or ClaudeCodeOptions()
|
77
|
-
|
78
73
|
# resolve models
|
79
|
-
model = f"inspect/{
|
80
|
-
small_model =
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
)
|
74
|
+
model = f"inspect/{model}" if model is not None else "inspect"
|
75
|
+
small_model = f"inspect/{small_model}" if small_model is not None else "inspect"
|
76
|
+
|
77
|
+
# resolve attempts
|
78
|
+
attempts = AgentAttempts(attempts) if isinstance(attempts, int) else attempts
|
85
79
|
|
86
80
|
async def execute(state: AgentState) -> AgentState:
|
87
81
|
async with sandbox_agent_bridge(state) as bridge:
|
@@ -95,9 +89,6 @@ def claude_code(
|
|
95
89
|
|
96
90
|
# base options
|
97
91
|
cmd = [
|
98
|
-
claude_binary,
|
99
|
-
"--session-id",
|
100
|
-
session_id,
|
101
92
|
"--print", # run without interactions
|
102
93
|
"--dangerously-skip-permissions",
|
103
94
|
"--model",
|
@@ -108,56 +99,101 @@ def claude_code(
|
|
108
99
|
system_messages = [
|
109
100
|
m.text for m in state.messages if isinstance(m, ChatMessageSystem)
|
110
101
|
]
|
111
|
-
if
|
112
|
-
system_messages.append(
|
102
|
+
if system_prompt is not None:
|
103
|
+
system_messages.append(system_prompt)
|
113
104
|
if system_messages:
|
114
105
|
cmd.extend(["--append-system-prompt", "\n\n".join(system_messages)])
|
115
106
|
|
116
107
|
# mcp servers
|
117
|
-
|
118
|
-
|
108
|
+
cmd_allowed_tools = allowed_tools or []
|
109
|
+
if mcp_servers:
|
110
|
+
mcp_server_args, mcp_allowed_tools = resolve_mcp_servers(mcp_servers)
|
111
|
+
cmd.extend(mcp_server_args)
|
112
|
+
cmd_allowed_tools.extend(mcp_allowed_tools)
|
113
|
+
|
114
|
+
# add allowed and disallowed tools
|
115
|
+
if len(cmd_allowed_tools) > 0:
|
116
|
+
cmd.append("--allowed-tools")
|
117
|
+
cmd.append(",".join(cmd_allowed_tools))
|
118
|
+
if disallowed_tools is not None and len(disallowed_tools) > 0:
|
119
|
+
cmd.append("--disallowed-tools")
|
120
|
+
cmd.append(",".join(disallowed_tools))
|
119
121
|
|
120
122
|
# user prompt
|
121
123
|
prompt = "\n\n".join(
|
122
124
|
[m.text for m in state.messages if isinstance(m, ChatMessageUser)]
|
123
125
|
)
|
124
|
-
cmd.append("--")
|
125
|
-
cmd.append(prompt)
|
126
126
|
|
127
127
|
# resolve sandbox
|
128
128
|
sbox = sandbox_env(sandbox)
|
129
129
|
|
130
130
|
# execute the agent
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
"
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
131
|
+
agent_prompt = prompt
|
132
|
+
attempt_count = 0
|
133
|
+
while True:
|
134
|
+
# either starting a new session or resuming one
|
135
|
+
id_param = "--session-id" if attempt_count == 0 else "--resume"
|
136
|
+
agent_cmd = (
|
137
|
+
[claude_binary, id_param, session_id] + cmd + ["--", agent_prompt]
|
138
|
+
)
|
139
|
+
|
140
|
+
# run agent
|
141
|
+
result = await sbox.exec(
|
142
|
+
cmd=agent_cmd,
|
143
|
+
env={
|
144
|
+
"ANTHROPIC_BASE_URL": f"http://localhost:{bridge.port}",
|
145
|
+
"ANTHROPIC_API_KEY": "sk-ant-api03-DOq5tyLPrk9M4hPE",
|
146
|
+
"ANTHROPIC_MODEL": model,
|
147
|
+
"ANTHROPIC_DEFAULT_OPUS_MODEL": model,
|
148
|
+
"ANTHROPIC_DEFAULT_SONNET_MODEL": model,
|
149
|
+
"CLAUDE_CODE_SUBAGENT_MODEL": model,
|
150
|
+
"ANTHROPIC_DEFAULT_HAIKU_MODEL": small_model,
|
151
|
+
"ANTHROPIC_SMALL_FAST_MODEL": small_model,
|
152
|
+
"CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC": "1",
|
153
|
+
"IS_SANDBOX": "1",
|
154
|
+
}
|
155
|
+
| (env or {}),
|
156
|
+
user=user,
|
157
|
+
)
|
158
|
+
|
159
|
+
# raise for error
|
160
|
+
if not result.success:
|
161
|
+
f"Error executing claude code agent: {result.stdout}\n{result.stderr}"
|
162
|
+
|
163
|
+
# exit if we are at max_attempts
|
164
|
+
attempt_count += 1
|
165
|
+
if attempt_count >= attempts.attempts:
|
166
|
+
break
|
167
|
+
|
168
|
+
# score this attempt
|
169
|
+
answer_scores = await score(state)
|
170
|
+
|
171
|
+
# break if we score 'correct'
|
172
|
+
if attempts.score_value(answer_scores[0].value) == 1.0:
|
173
|
+
break
|
174
|
+
|
175
|
+
# otherwise update prompt with incorrect message and continue
|
176
|
+
else:
|
177
|
+
if callable(attempts.incorrect_message):
|
178
|
+
if not is_callable_coroutine(attempts.incorrect_message):
|
179
|
+
raise ValueError(
|
180
|
+
"The incorrect_message function must be async."
|
181
|
+
)
|
182
|
+
agent_prompt = await attempts.incorrect_message(
|
183
|
+
state, answer_scores
|
184
|
+
)
|
185
|
+
else:
|
186
|
+
agent_prompt = attempts.incorrect_message
|
187
|
+
|
188
|
+
return bridge.state
|
155
189
|
|
156
190
|
# return agent with specified name and descritpion
|
157
191
|
return agent_with(execute, name=name, description=description)
|
158
192
|
|
159
193
|
|
160
|
-
def
|
194
|
+
def resolve_mcp_servers(
|
195
|
+
mcp_servers: Sequence[MCPServerConfig],
|
196
|
+
) -> tuple[list[str], list[str]]:
|
161
197
|
# build servers and allowed tools
|
162
198
|
mcp_servers_json: dict[str, dict[str, Any]] = {}
|
163
199
|
allowed_tools: list[str] = []
|
@@ -177,14 +213,11 @@ def mcp_server_args(mcp_servers: Sequence[MCPServerConfig]) -> list[str]:
|
|
177
213
|
)
|
178
214
|
|
179
215
|
# map to cli args
|
180
|
-
|
216
|
+
mcp_config_cmds: list[str] = []
|
181
217
|
if len(mcp_servers_json) > 0:
|
182
|
-
|
183
|
-
|
218
|
+
mcp_config_cmds.append("--mcp-config")
|
219
|
+
mcp_config_cmds.append(
|
184
220
|
to_json({"mcpServers": mcp_servers_json}, exclude_none=True).decode()
|
185
221
|
)
|
186
|
-
if len(allowed_tools):
|
187
|
-
cmds.append("--allowed-tools")
|
188
|
-
cmds.append(",".join(allowed_tools))
|
189
222
|
|
190
|
-
return
|
223
|
+
return mcp_config_cmds, allowed_tools
|
inspect_swe/_util/_async.py
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
import asyncio
|
2
|
-
|
2
|
+
import inspect
|
3
|
+
from typing import Any, Coroutine, Literal, TypeVar, cast
|
3
4
|
|
4
5
|
import nest_asyncio # type: ignore
|
5
6
|
import sniffio
|
@@ -9,6 +10,14 @@ from .platform import running_in_notebook
|
|
9
10
|
T = TypeVar("T")
|
10
11
|
|
11
12
|
|
13
|
+
def is_callable_coroutine(func_or_cls: Any) -> bool:
|
14
|
+
if inspect.iscoroutinefunction(func_or_cls):
|
15
|
+
return True
|
16
|
+
elif callable(func_or_cls):
|
17
|
+
return inspect.iscoroutinefunction(func_or_cls.__call__)
|
18
|
+
return False
|
19
|
+
|
20
|
+
|
12
21
|
def run_coroutine(coroutine: Coroutine[None, None, T]) -> T:
|
13
22
|
if current_async_backend() == "trio":
|
14
23
|
raise RuntimeError("run_coroutine cannot be used with trio")
|
inspect_swe/_version.py
CHANGED
@@ -28,7 +28,7 @@ version_tuple: VERSION_TUPLE
|
|
28
28
|
commit_id: COMMIT_ID
|
29
29
|
__commit_id__: COMMIT_ID
|
30
30
|
|
31
|
-
__version__ = version = '0.2.
|
32
|
-
__version_tuple__ = version_tuple = (0, 2,
|
31
|
+
__version__ = version = '0.2.7'
|
32
|
+
__version_tuple__ = version_tuple = (0, 2, 7)
|
33
33
|
|
34
34
|
__commit_id__ = commit_id = None
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: inspect_swe
|
3
|
-
Version: 0.2.
|
3
|
+
Version: 0.2.7
|
4
4
|
Summary: Software engineering agents for Inspect AI.
|
5
5
|
Project-URL: Documentation, https://meridianlabs-ai.github.io/inspect_swe/
|
6
6
|
Project-URL: Source Code, https://github.com/meridianlabs-ai/inspect_swe
|
@@ -10,7 +10,7 @@ License: MIT License
|
|
10
10
|
License-File: LICENSE
|
11
11
|
Requires-Python: >=3.10
|
12
12
|
Requires-Dist: httpx
|
13
|
-
Requires-Dist: inspect-ai>=0.3.
|
13
|
+
Requires-Dist: inspect-ai>=0.3.126
|
14
14
|
Requires-Dist: nest-asyncio
|
15
15
|
Requires-Dist: platformdirs
|
16
16
|
Requires-Dist: pydantic>=2.11.4
|
@@ -1,9 +1,9 @@
|
|
1
|
-
inspect_swe/__init__.py,sha256=
|
1
|
+
inspect_swe/__init__.py,sha256=yJ9tBcF2Wy11mVmLh1fTYXgYcsSHv30GAW-tVwE-r3s,342
|
2
2
|
inspect_swe/_registry.py,sha256=jM37ysrY39Ufd67GRKbiwfSViOLlm-82lm_JEaWKshw,97
|
3
|
-
inspect_swe/_version.py,sha256=
|
3
|
+
inspect_swe/_version.py,sha256=yXzK2akXKIKUAfJk0WCQothqygqvndys6GBuXxo-wk0,704
|
4
4
|
inspect_swe/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
5
5
|
inspect_swe/_claude_code/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
6
|
-
inspect_swe/_claude_code/claude_code.py,sha256
|
6
|
+
inspect_swe/_claude_code/claude_code.py,sha256=V1C79iWhVawTYy-JeRsUYM6VdiGWO_bjH_qRWf3r5lM,9825
|
7
7
|
inspect_swe/_claude_code/install/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
8
8
|
inspect_swe/_claude_code/install/cache.py,sha256=k08bCxGq-iYVpO16LNQhPjxTM9p2iecpqMjqYd2WBss,1708
|
9
9
|
inspect_swe/_claude_code/install/download.py,sha256=s1y4CDHVbJenfsR7OUwwxr5QFp-rDi4XnIxumDEvmws,3217
|
@@ -11,7 +11,7 @@ inspect_swe/_claude_code/install/install.py,sha256=nbf1SZJzr4DBPfUmBH64zWcdI4AnK
|
|
11
11
|
inspect_swe/_tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
12
12
|
inspect_swe/_tools/download.py,sha256=Jn_gcFR5Kw2vTYA1dWOFYRpqFtoFnKFv2Kv-4xT8tz4,1283
|
13
13
|
inspect_swe/_util/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
14
|
-
inspect_swe/_util/_async.py,sha256=
|
14
|
+
inspect_swe/_util/_async.py,sha256=foxHmEaZusCbK8HOBbThZKCnwaPFerwLhQXh7jIafVU,1778
|
15
15
|
inspect_swe/_util/_yaml.py,sha256=sRgf0UryF9Bd7pEEyfzL1qZBCgrpYe0l3l3U7bYeU44,505
|
16
16
|
inspect_swe/_util/appdirs.py,sha256=V3o1ERdSYLjKP-m4O1T_Hvkx0UsP2HdfvsshLSQgP6E,562
|
17
17
|
inspect_swe/_util/checksum.py,sha256=i-_GhtgCFd5eFj3PPJiGSCHDhZdPcIPNwiqddX93Sls,186
|
@@ -20,8 +20,8 @@ inspect_swe/_util/download.py,sha256=cCUau4ZBOKezpotJV5-v3JY_5CuYDZ-VcWlLf_EyNL0
|
|
20
20
|
inspect_swe/_util/platform.py,sha256=wm4efIFfdyTeaV2oxOXVvYl1u22MHX3jQMERHJMgv7A,339
|
21
21
|
inspect_swe/_util/sandbox.py,sha256=2wYmVz5EGUDBhqbN3NgLAOsyKeU-KRI161MZMJ54n4M,1769
|
22
22
|
inspect_swe/_util/trace.py,sha256=mFHmBKn2F8iJP9PpTHaCseMHnTMz3ErRx6RCKV83rZk,139
|
23
|
-
inspect_swe-0.2.
|
24
|
-
inspect_swe-0.2.
|
25
|
-
inspect_swe-0.2.
|
26
|
-
inspect_swe-0.2.
|
27
|
-
inspect_swe-0.2.
|
23
|
+
inspect_swe-0.2.7.dist-info/METADATA,sha256=keVzMz6nRC72XluU9hqrPlgixueQtCj5bsNm98A6L0A,1724
|
24
|
+
inspect_swe-0.2.7.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
|
25
|
+
inspect_swe-0.2.7.dist-info/entry_points.txt,sha256=OzpvUhd7M3T2Rog4MjwJAxIKeX5ljiR0mVYM9GefBKg,49
|
26
|
+
inspect_swe-0.2.7.dist-info/licenses/LICENSE,sha256=Hi3UDcbD6yCKZ1mcgt7pprzSG0rDEnSrbrm3XinyiDA,1070
|
27
|
+
inspect_swe-0.2.7.dist-info/RECORD,,
|
File without changes
|
File without changes
|
File without changes
|