driangle-agentrunner 0.0.1__tar.gz → 0.0.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.
Files changed (35) hide show
  1. {driangle_agentrunner-0.0.1 → driangle_agentrunner-0.0.2}/PKG-INFO +7 -6
  2. {driangle_agentrunner-0.0.1 → driangle_agentrunner-0.0.2}/README.md +5 -4
  3. {driangle_agentrunner-0.0.1 → driangle_agentrunner-0.0.2}/pyproject.toml +1 -1
  4. {driangle_agentrunner-0.0.1 → driangle_agentrunner-0.0.2}/src/agentrunner/claudecode/args.py +10 -1
  5. driangle_agentrunner-0.0.2/src/agentrunner/claudecode/options.py +49 -0
  6. {driangle_agentrunner-0.0.1 → driangle_agentrunner-0.0.2}/src/agentrunner/claudecode/process.py +1 -0
  7. {driangle_agentrunner-0.0.1 → driangle_agentrunner-0.0.2}/src/agentrunner/claudecode/version.py +2 -1
  8. {driangle_agentrunner-0.0.1 → driangle_agentrunner-0.0.2}/src/agentrunner/types.py +1 -1
  9. {driangle_agentrunner-0.0.1 → driangle_agentrunner-0.0.2}/tests/claudecode/test_args.py +52 -2
  10. driangle_agentrunner-0.0.1/src/agentrunner/claudecode/options.py +0 -33
  11. {driangle_agentrunner-0.0.1 → driangle_agentrunner-0.0.2}/.gitignore +0 -0
  12. {driangle_agentrunner-0.0.1 → driangle_agentrunner-0.0.2}/channel/pyproject.toml +0 -0
  13. {driangle_agentrunner-0.0.1 → driangle_agentrunner-0.0.2}/channel/src/agentrunner_channel/__init__.py +0 -0
  14. {driangle_agentrunner-0.0.1 → driangle_agentrunner-0.0.2}/channel/src/agentrunner_channel/py.typed +0 -0
  15. {driangle_agentrunner-0.0.1 → driangle_agentrunner-0.0.2}/channel/tests/test_binary.py +0 -0
  16. {driangle_agentrunner-0.0.1 → driangle_agentrunner-0.0.2}/src/agentrunner/__init__.py +0 -0
  17. {driangle_agentrunner-0.0.1 → driangle_agentrunner-0.0.2}/src/agentrunner/claudecode/__init__.py +0 -0
  18. {driangle_agentrunner-0.0.1 → driangle_agentrunner-0.0.2}/src/agentrunner/claudecode/mapping.py +0 -0
  19. {driangle_agentrunner-0.0.1 → driangle_agentrunner-0.0.2}/src/agentrunner/claudecode/parser.py +0 -0
  20. {driangle_agentrunner-0.0.1 → driangle_agentrunner-0.0.2}/src/agentrunner/claudecode/runner.py +0 -0
  21. {driangle_agentrunner-0.0.1 → driangle_agentrunner-0.0.2}/src/agentrunner/claudecode/types.py +0 -0
  22. {driangle_agentrunner-0.0.1 → driangle_agentrunner-0.0.2}/src/agentrunner/errors.py +0 -0
  23. {driangle_agentrunner-0.0.1 → driangle_agentrunner-0.0.2}/src/agentrunner/ollama/__init__.py +0 -0
  24. {driangle_agentrunner-0.0.1 → driangle_agentrunner-0.0.2}/src/agentrunner/ollama/accessors.py +0 -0
  25. {driangle_agentrunner-0.0.1 → driangle_agentrunner-0.0.2}/src/agentrunner/ollama/options.py +0 -0
  26. {driangle_agentrunner-0.0.1 → driangle_agentrunner-0.0.2}/src/agentrunner/ollama/runner.py +0 -0
  27. {driangle_agentrunner-0.0.1 → driangle_agentrunner-0.0.2}/src/agentrunner/ollama/types.py +0 -0
  28. {driangle_agentrunner-0.0.1 → driangle_agentrunner-0.0.2}/tests/__init__.py +0 -0
  29. {driangle_agentrunner-0.0.1 → driangle_agentrunner-0.0.2}/tests/claudecode/__init__.py +0 -0
  30. {driangle_agentrunner-0.0.1 → driangle_agentrunner-0.0.2}/tests/claudecode/test_mapping.py +0 -0
  31. {driangle_agentrunner-0.0.1 → driangle_agentrunner-0.0.2}/tests/claudecode/test_parser.py +0 -0
  32. {driangle_agentrunner-0.0.1 → driangle_agentrunner-0.0.2}/tests/claudecode/test_runner.py +0 -0
  33. {driangle_agentrunner-0.0.1 → driangle_agentrunner-0.0.2}/tests/claudecode/test_version.py +0 -0
  34. {driangle_agentrunner-0.0.1 → driangle_agentrunner-0.0.2}/tests/ollama/__init__.py +0 -0
  35. {driangle_agentrunner-0.0.1 → driangle_agentrunner-0.0.2}/tests/ollama/test_runner.py +0 -0
@@ -1,6 +1,6 @@
1
- Metadata-Version: 2.4
1
+ Metadata-Version: 2.5
2
2
  Name: driangle-agentrunner
3
- Version: 0.0.1
3
+ Version: 0.0.2
4
4
  Summary: Python library for programmatically invoking AI coding agents
5
5
  Project-URL: Homepage, https://github.com/driangle/agentrunner
6
6
  Project-URL: Repository, https://github.com/driangle/agentrunner
@@ -24,17 +24,17 @@ Python library for programmatically invoking AI coding agents. Part of the [agen
24
24
 
25
25
  | Runner | CLI Version | Status |
26
26
  |-------------|-------------|--------|
27
- | Claude Code | >= 1.0.12 | ✅ |
27
+ | Claude Code | >= 2.1.0 | ✅ |
28
28
 
29
29
  ## Requirements
30
30
 
31
31
  - Python >= 3.11
32
- - Claude Code CLI >= 1.0.12
32
+ - Claude Code CLI >= 2.1.0
33
33
 
34
34
  ## Installation
35
35
 
36
36
  ```bash
37
- pip install agentrunner
37
+ pip install driangle-agentrunner
38
38
  ```
39
39
 
40
40
  ## Quick Start
@@ -108,6 +108,8 @@ Claude-specific options (`ClaudeRunOptions` extends `RunOptions`):
108
108
  |--------------------------|-------------|------------------------------------|
109
109
  | `allowed_tools` | `list[str]` | Tools the agent may use |
110
110
  | `disallowed_tools` | `list[str]` | Tools the agent may not use |
111
+ | `permission_mode` | `str` | Permission mode (wins over `dangerously_skip_permissions`) |
112
+ | `settings` | `str` | Additional settings: file path or inline JSON |
111
113
  | `mcp_config` | `str` | Path to MCP server config |
112
114
  | `json_schema` | `str` | JSON Schema for structured output |
113
115
  | `max_budget_usd` | `float` | Cost limit in USD |
@@ -115,7 +117,6 @@ Claude-specific options (`ClaudeRunOptions` extends `RunOptions`):
115
117
  | `continue_session` | `bool` | Continue most recent session |
116
118
  | `session_id` | `str` | Specific session ID |
117
119
  | `include_partial_messages`| `bool` | Stream partial/incremental messages|
118
- | `on_message` | `callable` | Callback for each streamed message |
119
120
 
120
121
  ### Result
121
122
 
@@ -6,17 +6,17 @@ Python library for programmatically invoking AI coding agents. Part of the [agen
6
6
 
7
7
  | Runner | CLI Version | Status |
8
8
  |-------------|-------------|--------|
9
- | Claude Code | >= 1.0.12 | ✅ |
9
+ | Claude Code | >= 2.1.0 | ✅ |
10
10
 
11
11
  ## Requirements
12
12
 
13
13
  - Python >= 3.11
14
- - Claude Code CLI >= 1.0.12
14
+ - Claude Code CLI >= 2.1.0
15
15
 
16
16
  ## Installation
17
17
 
18
18
  ```bash
19
- pip install agentrunner
19
+ pip install driangle-agentrunner
20
20
  ```
21
21
 
22
22
  ## Quick Start
@@ -90,6 +90,8 @@ Claude-specific options (`ClaudeRunOptions` extends `RunOptions`):
90
90
  |--------------------------|-------------|------------------------------------|
91
91
  | `allowed_tools` | `list[str]` | Tools the agent may use |
92
92
  | `disallowed_tools` | `list[str]` | Tools the agent may not use |
93
+ | `permission_mode` | `str` | Permission mode (wins over `dangerously_skip_permissions`) |
94
+ | `settings` | `str` | Additional settings: file path or inline JSON |
93
95
  | `mcp_config` | `str` | Path to MCP server config |
94
96
  | `json_schema` | `str` | JSON Schema for structured output |
95
97
  | `max_budget_usd` | `float` | Cost limit in USD |
@@ -97,7 +99,6 @@ Claude-specific options (`ClaudeRunOptions` extends `RunOptions`):
97
99
  | `continue_session` | `bool` | Continue most recent session |
98
100
  | `session_id` | `str` | Specific session ID |
99
101
  | `include_partial_messages`| `bool` | Stream partial/incremental messages|
100
- | `on_message` | `callable` | Callback for each streamed message |
101
102
 
102
103
  ### Result
103
104
 
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "driangle-agentrunner"
7
- version = "0.0.1"
7
+ version = "0.0.2"
8
8
  description = "Python library for programmatically invoking AI coding agents"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -22,10 +22,16 @@ def build_args(prompt: str, options: ClaudeRunOptions | None = None) -> list[str
22
22
  args.extend(["--append-system-prompt", options.append_system_prompt])
23
23
  if options.max_turns is not None and options.max_turns > 0:
24
24
  args.extend(["--max-turns", str(options.max_turns)])
25
- if options.skip_permissions:
25
+ # permission_mode takes precedence over dangerously_skip_permissions.
26
+ if options.permission_mode:
27
+ args.extend(["--permission-mode", options.permission_mode])
28
+ elif options.dangerously_skip_permissions:
26
29
  args.append("--dangerously-skip-permissions")
27
30
 
28
31
  # Claude-specific options.
32
+ # --tools takes a single comma-separated value, not repeated flags.
33
+ if options.tools:
34
+ args.extend(["--tools", ",".join(options.tools)])
29
35
  if options.allowed_tools:
30
36
  for tool in options.allowed_tools:
31
37
  args.extend(["--allowedTools", tool])
@@ -36,6 +42,9 @@ def build_args(prompt: str, options: ClaudeRunOptions | None = None) -> list[str
36
42
  args.extend(["--mcp-config", options.mcp_config])
37
43
  if options.json_schema:
38
44
  args.extend(["--json-schema", options.json_schema])
45
+ # Value may be a file path or a raw JSON string; the CLI disambiguates.
46
+ if options.settings:
47
+ args.extend(["--settings", options.settings])
39
48
  if options.max_budget_usd is not None and options.max_budget_usd > 0:
40
49
  args.extend(["--max-budget-usd", str(options.max_budget_usd)])
41
50
  if options.resume:
@@ -0,0 +1,49 @@
1
+ """Configuration and option types for the Claude Code runner."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+ from typing import Protocol
7
+
8
+ from ..types import RunOptions
9
+
10
+
11
+ class Logger(Protocol):
12
+ """Logger interface for debug output. Opt-in, disabled by default.
13
+
14
+ Compatible with ``logging.getLogger()``.
15
+ """
16
+
17
+ def debug(self, message: str, *args: object, **kwargs: object) -> None: ...
18
+ def error(self, message: str, *args: object, **kwargs: object) -> None: ...
19
+
20
+
21
+ @dataclass
22
+ class ClaudeRunOptions(RunOptions):
23
+ """Claude Code-specific options that extend the common RunOptions."""
24
+
25
+ allowed_tools: list[str] | None = None
26
+ disallowed_tools: list[str] | None = None
27
+ # Exclusive whitelist of built-in tools (--tools). Unlike allowed_tools,
28
+ # which only pre-approves tools and leaves unlisted built-ins available,
29
+ # --tools replaces the built-in tool set, so every unlisted built-in is
30
+ # denied at registration. Use [""] to disable all tools, ["default"] for
31
+ # the full set, or explicit names. None leaves the CLI default.
32
+ tools: list[str] | None = None
33
+ # Permission mode for the run (--permission-mode). Known modes: "default",
34
+ # "acceptEdits", "auto", "plan", "dontAsk", "bypassPermissions". Passed
35
+ # through as a plain string so new CLI modes work without a library change.
36
+ # When set, takes precedence over dangerously_skip_permissions.
37
+ permission_mode: str | None = None
38
+ mcp_config: str | None = None
39
+ json_schema: str | None = None
40
+ # Additional settings for the run (--settings). May be a path to a settings
41
+ # JSON file or a raw JSON string; passed through verbatim, the CLI
42
+ # disambiguates. In non-interactive mode the CLI silently ignores settings
43
+ # that fail validation.
44
+ settings: str | None = None
45
+ max_budget_usd: float | None = None
46
+ resume: str | None = None
47
+ continue_session: bool = False
48
+ session_id: str | None = None
49
+ include_partial_messages: bool = False
@@ -52,6 +52,7 @@ async def default_spawn(
52
52
  stdin=asyncio.subprocess.DEVNULL,
53
53
  stdout=asyncio.subprocess.PIPE,
54
54
  stderr=asyncio.subprocess.PIPE,
55
+ limit=10 * 1024 * 1024, # 10 MiB — default 64 KiB is too small for large JSON lines
55
56
  )
56
57
 
57
58
 
@@ -8,7 +8,8 @@ import re
8
8
  from ..errors import NotFoundError
9
9
 
10
10
  # Supported Claude Code CLI version range.
11
- MIN_VERSION = "1.0.12"
11
+ # 2.1.0 is the first release that ships --tools (verified absent in 2.0.0).
12
+ MIN_VERSION = "2.1.0"
12
13
 
13
14
  _VERSION_RE = re.compile(r"(\d+\.\d+\.\d+)")
14
15
 
@@ -148,7 +148,7 @@ class RunOptions:
148
148
  env: dict[str, str] | None = None
149
149
  max_turns: int | None = None
150
150
  timeout: float | None = None
151
- skip_permissions: bool = False
151
+ dangerously_skip_permissions: bool = False
152
152
 
153
153
 
154
154
  @runtime_checkable
@@ -37,8 +37,8 @@ class TestBuildArgs:
37
37
  args = build_args("hello", opts)
38
38
  assert "--max-turns" not in args
39
39
 
40
- def test_skip_permissions(self):
41
- opts = ClaudeRunOptions(skip_permissions=True)
40
+ def test_dangerously_skip_permissions(self):
41
+ opts = ClaudeRunOptions(dangerously_skip_permissions=True)
42
42
  args = build_args("hello", opts)
43
43
  assert "--dangerously-skip-permissions" in args
44
44
 
@@ -56,6 +56,56 @@ class TestBuildArgs:
56
56
  assert "--disallowedTools" in args
57
57
  assert args[args.index("--disallowedTools") + 1] == "Bash"
58
58
 
59
+ def test_tools_joined_into_single_value(self):
60
+ opts = ClaudeRunOptions(tools=["Read", "Grep"])
61
+ args = build_args("hello", opts)
62
+ assert args.count("--tools") == 1
63
+ assert args[args.index("--tools") + 1] == "Read,Grep"
64
+
65
+ def test_tools_empty_string_disables_all(self):
66
+ opts = ClaudeRunOptions(tools=[""])
67
+ args = build_args("hello", opts)
68
+ assert args[args.index("--tools") + 1] == ""
69
+
70
+ def test_tools_omitted_when_unset_or_empty(self):
71
+ assert "--tools" not in build_args("hello", ClaudeRunOptions())
72
+ assert "--tools" not in build_args("hello", ClaudeRunOptions(tools=[]))
73
+
74
+ def test_settings_file_path(self):
75
+ opts = ClaudeRunOptions(settings="/tmp/settings.json")
76
+ args = build_args("hello", opts)
77
+ assert args[args.index("--settings") + 1] == "/tmp/settings.json"
78
+
79
+ def test_settings_inline_json(self):
80
+ raw = '{"permissions":{"deny":["Bash"]}}'
81
+ opts = ClaudeRunOptions(settings=raw)
82
+ args = build_args("hello", opts)
83
+ assert args[args.index("--settings") + 1] == raw
84
+
85
+ def test_settings_omitted_when_unset(self):
86
+ assert "--settings" not in build_args("hello", ClaudeRunOptions())
87
+
88
+ def test_permission_mode(self):
89
+ opts = ClaudeRunOptions(permission_mode="auto")
90
+ args = build_args("hello", opts)
91
+ assert "--permission-mode" in args
92
+ assert args[args.index("--permission-mode") + 1] == "auto"
93
+
94
+ def test_permission_mode_omitted_when_unset(self):
95
+ assert "--permission-mode" not in build_args("hello", ClaudeRunOptions())
96
+
97
+ def test_permission_mode_takes_precedence_over_skip_permissions(self):
98
+ opts = ClaudeRunOptions(permission_mode="plan", dangerously_skip_permissions=True)
99
+ args = build_args("hello", opts)
100
+ assert args[args.index("--permission-mode") + 1] == "plan"
101
+ assert "--dangerously-skip-permissions" not in args
102
+
103
+ def test_skip_permissions_still_passed_without_permission_mode(self):
104
+ opts = ClaudeRunOptions(dangerously_skip_permissions=True)
105
+ args = build_args("hello", opts)
106
+ assert "--dangerously-skip-permissions" in args
107
+ assert "--permission-mode" not in args
108
+
59
109
  def test_mcp_config(self):
60
110
  opts = ClaudeRunOptions(mcp_config="/path/to/config.json")
61
111
  args = build_args("hello", opts)
@@ -1,33 +0,0 @@
1
- """Configuration and option types for the Claude Code runner."""
2
-
3
- from __future__ import annotations
4
-
5
- from dataclasses import dataclass
6
- from typing import Protocol
7
-
8
- from ..types import RunOptions
9
-
10
-
11
- class Logger(Protocol):
12
- """Logger interface for debug output. Opt-in, disabled by default.
13
-
14
- Compatible with ``logging.getLogger()``.
15
- """
16
-
17
- def debug(self, message: str, *args: object, **kwargs: object) -> None: ...
18
- def error(self, message: str, *args: object, **kwargs: object) -> None: ...
19
-
20
-
21
- @dataclass
22
- class ClaudeRunOptions(RunOptions):
23
- """Claude Code-specific options that extend the common RunOptions."""
24
-
25
- allowed_tools: list[str] | None = None
26
- disallowed_tools: list[str] | None = None
27
- mcp_config: str | None = None
28
- json_schema: str | None = None
29
- max_budget_usd: float | None = None
30
- resume: str | None = None
31
- continue_session: bool = False
32
- session_id: str | None = None
33
- include_partial_messages: bool = False