py-opencode-wrapper 0.2.0__tar.gz → 0.2.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.
- {py_opencode_wrapper-0.2.0 → py_opencode_wrapper-0.2.2}/PKG-INFO +25 -1
- {py_opencode_wrapper-0.2.0 → py_opencode_wrapper-0.2.2}/README.md +24 -0
- {py_opencode_wrapper-0.2.0 → py_opencode_wrapper-0.2.2}/opencode_wrapper/client.py +17 -4
- {py_opencode_wrapper-0.2.0 → py_opencode_wrapper-0.2.2}/opencode_wrapper/config.py +4 -0
- {py_opencode_wrapper-0.2.0 → py_opencode_wrapper-0.2.2}/py_opencode_wrapper.egg-info/PKG-INFO +25 -1
- {py_opencode_wrapper-0.2.0 → py_opencode_wrapper-0.2.2}/pyproject.toml +1 -1
- {py_opencode_wrapper-0.2.0 → py_opencode_wrapper-0.2.2}/tests/test_client_async.py +30 -0
- {py_opencode_wrapper-0.2.0 → py_opencode_wrapper-0.2.2}/opencode_wrapper/__init__.py +0 -0
- {py_opencode_wrapper-0.2.0 → py_opencode_wrapper-0.2.2}/opencode_wrapper/errors.py +0 -0
- {py_opencode_wrapper-0.2.0 → py_opencode_wrapper-0.2.2}/opencode_wrapper/events.py +0 -0
- {py_opencode_wrapper-0.2.0 → py_opencode_wrapper-0.2.2}/py_opencode_wrapper.egg-info/SOURCES.txt +0 -0
- {py_opencode_wrapper-0.2.0 → py_opencode_wrapper-0.2.2}/py_opencode_wrapper.egg-info/dependency_links.txt +0 -0
- {py_opencode_wrapper-0.2.0 → py_opencode_wrapper-0.2.2}/py_opencode_wrapper.egg-info/requires.txt +0 -0
- {py_opencode_wrapper-0.2.0 → py_opencode_wrapper-0.2.2}/py_opencode_wrapper.egg-info/top_level.txt +0 -0
- {py_opencode_wrapper-0.2.0 → py_opencode_wrapper-0.2.2}/setup.cfg +0 -0
- {py_opencode_wrapper-0.2.0 → py_opencode_wrapper-0.2.2}/tests/test_config_instructions.py +0 -0
- {py_opencode_wrapper-0.2.0 → py_opencode_wrapper-0.2.2}/tests/test_config_permission.py +0 -0
- {py_opencode_wrapper-0.2.0 → py_opencode_wrapper-0.2.2}/tests/test_event_parser.py +0 -0
- {py_opencode_wrapper-0.2.0 → py_opencode_wrapper-0.2.2}/tests/test_integration_external_directory.py +0 -0
- {py_opencode_wrapper-0.2.0 → py_opencode_wrapper-0.2.2}/tests/test_integration_instructions.py +0 -0
- {py_opencode_wrapper-0.2.0 → py_opencode_wrapper-0.2.2}/tests/test_integration_multi_agent_weather.py +0 -0
- {py_opencode_wrapper-0.2.0 → py_opencode_wrapper-0.2.2}/tests/test_integration_opencode.py +0 -0
- {py_opencode_wrapper-0.2.0 → py_opencode_wrapper-0.2.2}/tests/test_integration_parallel.py +0 -0
- {py_opencode_wrapper-0.2.0 → py_opencode_wrapper-0.2.2}/tests/test_run_result_fuzzy_text.py +0 -0
- {py_opencode_wrapper-0.2.0 → py_opencode_wrapper-0.2.2}/tests/test_user_config_isolation.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: py-opencode-wrapper
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: Async Python wrapper for OpenCode CLI (opencode run --format json)
|
|
5
5
|
Project-URL: Homepage, https://github.com/idailylife/oc_py_wrapper
|
|
6
6
|
Project-URL: Repository, https://github.com/idailylife/oc_py_wrapper
|
|
@@ -61,6 +61,12 @@ async def main():
|
|
|
61
61
|
asyncio.run(main())
|
|
62
62
|
```
|
|
63
63
|
|
|
64
|
+
Set `RunConfig(record_thinking=True)` when you want OpenCode reasoning/thinking
|
|
65
|
+
parts included in `result.events` and `log_file` JSON lines. This only maps to
|
|
66
|
+
OpenCode's display/output flag `--thinking`; it does not change model reasoning
|
|
67
|
+
effort. Use `variant` separately if you intentionally want a provider-specific
|
|
68
|
+
reasoning effort.
|
|
69
|
+
|
|
64
70
|
### Stream structured JSON events
|
|
65
71
|
|
|
66
72
|
```python
|
|
@@ -104,11 +110,29 @@ Per-call JSON is merged and passed as `OPENCODE_CONFIG_CONTENT` (see [OpenCode c
|
|
|
104
110
|
| `permission` | `permission` map (`allow` / `deny`, patterns) |
|
|
105
111
|
| `mcp` | MCP server definitions |
|
|
106
112
|
| `tools` | Enable/disable tools (including MCP globs) |
|
|
113
|
+
| `instructions` | Instruction file paths / glob patterns to inject |
|
|
107
114
|
| `config_overrides` | Any extra top-level config keys to deep-merge |
|
|
108
115
|
|
|
109
116
|
Optional env tuning: `disable_autoupdate=True` sets `OPENCODE_DISABLE_AUTOUPDATE=1`.
|
|
110
117
|
Note: `ask` is intentionally rejected in subprocess mode (no interactive terminal); use `allow` or `deny`.
|
|
111
118
|
|
|
119
|
+
### User config isolation
|
|
120
|
+
|
|
121
|
+
By default, `RunConfig.inherit_user_config=False` makes each child `opencode`
|
|
122
|
+
process see a sanitized copy of the host's global OpenCode config. The wrapper
|
|
123
|
+
keeps only provider-selection keys (`$schema`, `provider`,
|
|
124
|
+
`disabled_providers`, `enabled_providers`) and drops capability/configuration
|
|
125
|
+
keys such as `mcp`, `agent`, `command`, `tools`, `plugin`, `skills`,
|
|
126
|
+
`instructions`, `permission`, and `model`.
|
|
127
|
+
|
|
128
|
+
This keeps benchmark and orchestration runs reproducible while still allowing
|
|
129
|
+
provider configuration and `opencode auth` credentials to work. Project-level
|
|
130
|
+
config discovered from the workspace is not suppressed.
|
|
131
|
+
|
|
132
|
+
Set `inherit_user_config=True` to restore the legacy behavior of inheriting the
|
|
133
|
+
host OpenCode config as-is. For reproducible runs, pass `model`, `permission`,
|
|
134
|
+
`mcp`, `tools`, and `instructions` explicitly through `RunConfig`.
|
|
135
|
+
|
|
112
136
|
## CLI arguments
|
|
113
137
|
|
|
114
138
|
`RunConfig` maps to flags such as `--agent`, `-m`, `-f`, `--attach`, `--title`, etc. Prompt text is appended as the final `opencode run` message argument.
|
|
@@ -48,6 +48,12 @@ async def main():
|
|
|
48
48
|
asyncio.run(main())
|
|
49
49
|
```
|
|
50
50
|
|
|
51
|
+
Set `RunConfig(record_thinking=True)` when you want OpenCode reasoning/thinking
|
|
52
|
+
parts included in `result.events` and `log_file` JSON lines. This only maps to
|
|
53
|
+
OpenCode's display/output flag `--thinking`; it does not change model reasoning
|
|
54
|
+
effort. Use `variant` separately if you intentionally want a provider-specific
|
|
55
|
+
reasoning effort.
|
|
56
|
+
|
|
51
57
|
### Stream structured JSON events
|
|
52
58
|
|
|
53
59
|
```python
|
|
@@ -91,11 +97,29 @@ Per-call JSON is merged and passed as `OPENCODE_CONFIG_CONTENT` (see [OpenCode c
|
|
|
91
97
|
| `permission` | `permission` map (`allow` / `deny`, patterns) |
|
|
92
98
|
| `mcp` | MCP server definitions |
|
|
93
99
|
| `tools` | Enable/disable tools (including MCP globs) |
|
|
100
|
+
| `instructions` | Instruction file paths / glob patterns to inject |
|
|
94
101
|
| `config_overrides` | Any extra top-level config keys to deep-merge |
|
|
95
102
|
|
|
96
103
|
Optional env tuning: `disable_autoupdate=True` sets `OPENCODE_DISABLE_AUTOUPDATE=1`.
|
|
97
104
|
Note: `ask` is intentionally rejected in subprocess mode (no interactive terminal); use `allow` or `deny`.
|
|
98
105
|
|
|
106
|
+
### User config isolation
|
|
107
|
+
|
|
108
|
+
By default, `RunConfig.inherit_user_config=False` makes each child `opencode`
|
|
109
|
+
process see a sanitized copy of the host's global OpenCode config. The wrapper
|
|
110
|
+
keeps only provider-selection keys (`$schema`, `provider`,
|
|
111
|
+
`disabled_providers`, `enabled_providers`) and drops capability/configuration
|
|
112
|
+
keys such as `mcp`, `agent`, `command`, `tools`, `plugin`, `skills`,
|
|
113
|
+
`instructions`, `permission`, and `model`.
|
|
114
|
+
|
|
115
|
+
This keeps benchmark and orchestration runs reproducible while still allowing
|
|
116
|
+
provider configuration and `opencode auth` credentials to work. Project-level
|
|
117
|
+
config discovered from the workspace is not suppressed.
|
|
118
|
+
|
|
119
|
+
Set `inherit_user_config=True` to restore the legacy behavior of inheriting the
|
|
120
|
+
host OpenCode config as-is. For reproducible runs, pass `model`, `permission`,
|
|
121
|
+
`mcp`, `tools`, and `instructions` explicitly through `RunConfig`.
|
|
122
|
+
|
|
99
123
|
## CLI arguments
|
|
100
124
|
|
|
101
125
|
`RunConfig` maps to flags such as `--agent`, `-m`, `-f`, `--attach`, `--title`, etc. Prompt text is appended as the final `opencode run` message argument.
|
|
@@ -73,7 +73,7 @@ def build_argv(
|
|
|
73
73
|
cmd.extend(["--port", str(run_cfg.port)])
|
|
74
74
|
if run_cfg.variant:
|
|
75
75
|
cmd.extend(["--variant", run_cfg.variant])
|
|
76
|
-
if run_cfg.thinking is True:
|
|
76
|
+
if run_cfg.record_thinking is True or run_cfg.thinking is True:
|
|
77
77
|
cmd.append("--thinking")
|
|
78
78
|
|
|
79
79
|
if prompt:
|
|
@@ -81,7 +81,12 @@ def build_argv(
|
|
|
81
81
|
return cmd
|
|
82
82
|
|
|
83
83
|
|
|
84
|
-
def build_env(
|
|
84
|
+
def build_env(
|
|
85
|
+
run_cfg: RunConfig,
|
|
86
|
+
base: Mapping[str, str] | None = None,
|
|
87
|
+
*,
|
|
88
|
+
cwd: str | Path | None = None,
|
|
89
|
+
) -> dict[str, str]:
|
|
85
90
|
env = dict(base if base is not None else os.environ)
|
|
86
91
|
if run_cfg.extra_env:
|
|
87
92
|
env.update(dict(run_cfg.extra_env))
|
|
@@ -90,6 +95,14 @@ def build_env(run_cfg: RunConfig, base: Mapping[str, str] | None = None) -> dict
|
|
|
90
95
|
env["OPENCODE_CONFIG_CONTENT"] = content
|
|
91
96
|
if run_cfg.disable_autoupdate:
|
|
92
97
|
env["OPENCODE_DISABLE_AUTOUPDATE"] = "1"
|
|
98
|
+
# opencode's `run` cmd resolves the project root as
|
|
99
|
+
# `process.env.PWD ?? process.cwd()` (run.ts:276), and the bash builtin
|
|
100
|
+
# `pwd` reads $PWD too. asyncio.create_subprocess_exec(cwd=...) only
|
|
101
|
+
# chdirs the child; it leaves PWD inherited from the parent shell, which
|
|
102
|
+
# makes opencode operate against the wrong directory. Pin PWD to the
|
|
103
|
+
# resolved workspace so the child sees a consistent cwd.
|
|
104
|
+
if cwd is not None:
|
|
105
|
+
env["PWD"] = str(cwd)
|
|
93
106
|
return env
|
|
94
107
|
|
|
95
108
|
|
|
@@ -380,8 +393,8 @@ class AsyncOpenCodeClient:
|
|
|
380
393
|
validate_config_for_run(run_cfg)
|
|
381
394
|
bin_path = self.resolved_binary()
|
|
382
395
|
argv = build_argv(bin_path, prompt, run_cfg)
|
|
383
|
-
env = build_env(run_cfg)
|
|
384
396
|
cwd = str(Path(workspace).expanduser().resolve())
|
|
397
|
+
env = build_env(run_cfg, cwd=cwd)
|
|
385
398
|
|
|
386
399
|
events_acc: list[dict[str, Any]] = []
|
|
387
400
|
raw_acc: list[str] = []
|
|
@@ -436,8 +449,8 @@ class AsyncOpenCodeClient:
|
|
|
436
449
|
validate_config_for_run(run_cfg)
|
|
437
450
|
bin_path = self.resolved_binary()
|
|
438
451
|
argv = build_argv(bin_path, prompt, run_cfg)
|
|
439
|
-
env = build_env(run_cfg)
|
|
440
452
|
cwd = str(Path(workspace).expanduser().resolve())
|
|
453
|
+
env = build_env(run_cfg, cwd=cwd)
|
|
441
454
|
|
|
442
455
|
events_acc: list[dict[str, Any]] = []
|
|
443
456
|
raw_acc: list[str] = []
|
|
@@ -147,6 +147,10 @@ class RunConfig:
|
|
|
147
147
|
remote_dir: str | None = None
|
|
148
148
|
port: int | None = None
|
|
149
149
|
variant: str | None = None
|
|
150
|
+
# Include OpenCode reasoning/thinking parts in the JSON event stream.
|
|
151
|
+
# This maps to `opencode run --thinking`; it does not set model reasoning effort.
|
|
152
|
+
record_thinking: bool | None = None
|
|
153
|
+
# Backward-compatible alias for record_thinking.
|
|
150
154
|
thinking: bool | None = None
|
|
151
155
|
print_logs: bool | None = None
|
|
152
156
|
log_level: str | None = None
|
{py_opencode_wrapper-0.2.0 → py_opencode_wrapper-0.2.2}/py_opencode_wrapper.egg-info/PKG-INFO
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: py-opencode-wrapper
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.2
|
|
4
4
|
Summary: Async Python wrapper for OpenCode CLI (opencode run --format json)
|
|
5
5
|
Project-URL: Homepage, https://github.com/idailylife/oc_py_wrapper
|
|
6
6
|
Project-URL: Repository, https://github.com/idailylife/oc_py_wrapper
|
|
@@ -61,6 +61,12 @@ async def main():
|
|
|
61
61
|
asyncio.run(main())
|
|
62
62
|
```
|
|
63
63
|
|
|
64
|
+
Set `RunConfig(record_thinking=True)` when you want OpenCode reasoning/thinking
|
|
65
|
+
parts included in `result.events` and `log_file` JSON lines. This only maps to
|
|
66
|
+
OpenCode's display/output flag `--thinking`; it does not change model reasoning
|
|
67
|
+
effort. Use `variant` separately if you intentionally want a provider-specific
|
|
68
|
+
reasoning effort.
|
|
69
|
+
|
|
64
70
|
### Stream structured JSON events
|
|
65
71
|
|
|
66
72
|
```python
|
|
@@ -104,11 +110,29 @@ Per-call JSON is merged and passed as `OPENCODE_CONFIG_CONTENT` (see [OpenCode c
|
|
|
104
110
|
| `permission` | `permission` map (`allow` / `deny`, patterns) |
|
|
105
111
|
| `mcp` | MCP server definitions |
|
|
106
112
|
| `tools` | Enable/disable tools (including MCP globs) |
|
|
113
|
+
| `instructions` | Instruction file paths / glob patterns to inject |
|
|
107
114
|
| `config_overrides` | Any extra top-level config keys to deep-merge |
|
|
108
115
|
|
|
109
116
|
Optional env tuning: `disable_autoupdate=True` sets `OPENCODE_DISABLE_AUTOUPDATE=1`.
|
|
110
117
|
Note: `ask` is intentionally rejected in subprocess mode (no interactive terminal); use `allow` or `deny`.
|
|
111
118
|
|
|
119
|
+
### User config isolation
|
|
120
|
+
|
|
121
|
+
By default, `RunConfig.inherit_user_config=False` makes each child `opencode`
|
|
122
|
+
process see a sanitized copy of the host's global OpenCode config. The wrapper
|
|
123
|
+
keeps only provider-selection keys (`$schema`, `provider`,
|
|
124
|
+
`disabled_providers`, `enabled_providers`) and drops capability/configuration
|
|
125
|
+
keys such as `mcp`, `agent`, `command`, `tools`, `plugin`, `skills`,
|
|
126
|
+
`instructions`, `permission`, and `model`.
|
|
127
|
+
|
|
128
|
+
This keeps benchmark and orchestration runs reproducible while still allowing
|
|
129
|
+
provider configuration and `opencode auth` credentials to work. Project-level
|
|
130
|
+
config discovered from the workspace is not suppressed.
|
|
131
|
+
|
|
132
|
+
Set `inherit_user_config=True` to restore the legacy behavior of inheriting the
|
|
133
|
+
host OpenCode config as-is. For reproducible runs, pass `model`, `permission`,
|
|
134
|
+
`mcp`, `tools`, and `instructions` explicitly through `RunConfig`.
|
|
135
|
+
|
|
112
136
|
## CLI arguments
|
|
113
137
|
|
|
114
138
|
`RunConfig` maps to flags such as `--agent`, `-m`, `-f`, `--attach`, `--title`, etc. Prompt text is appended as the final `opencode run` message argument.
|
|
@@ -49,6 +49,19 @@ def test_build_argv_with_agent_model_files() -> None:
|
|
|
49
49
|
assert "-f" in argv
|
|
50
50
|
|
|
51
51
|
|
|
52
|
+
def test_build_argv_record_thinking_adds_display_flag_only() -> None:
|
|
53
|
+
cfg = RunConfig(record_thinking=True)
|
|
54
|
+
argv = build_argv("/x/opencode", "p", cfg)
|
|
55
|
+
assert "--thinking" in argv
|
|
56
|
+
assert "--variant" not in argv
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def test_build_argv_thinking_alias_still_adds_display_flag() -> None:
|
|
60
|
+
cfg = RunConfig(thinking=True)
|
|
61
|
+
argv = build_argv("/x/opencode", "p", cfg)
|
|
62
|
+
assert "--thinking" in argv
|
|
63
|
+
|
|
64
|
+
|
|
52
65
|
def test_build_env_config_content_and_autoupdate() -> None:
|
|
53
66
|
cfg = RunConfig(permission={"bash": "deny"}, disable_autoupdate=True)
|
|
54
67
|
env = build_env(cfg, base={"HOME": "/tmp"})
|
|
@@ -57,6 +70,23 @@ def test_build_env_config_content_and_autoupdate() -> None:
|
|
|
57
70
|
assert env.get("OPENCODE_DISABLE_AUTOUPDATE") == "1"
|
|
58
71
|
|
|
59
72
|
|
|
73
|
+
def test_build_env_sets_pwd_to_cwd() -> None:
|
|
74
|
+
"""opencode's run.ts:276 reads `process.env.PWD ?? process.cwd()` to
|
|
75
|
+
resolve the project root, and the bash builtin pwd reads $PWD.
|
|
76
|
+
asyncio.create_subprocess_exec(cwd=...) only chdirs the child; PWD stays
|
|
77
|
+
inherited from the parent shell. build_env must pin PWD to the workspace
|
|
78
|
+
so opencode and bash both see a consistent cwd."""
|
|
79
|
+
cfg = RunConfig()
|
|
80
|
+
env = build_env(cfg, base={"HOME": "/tmp", "PWD": "/some/other/dir"}, cwd="/ws/x")
|
|
81
|
+
assert env["PWD"] == "/ws/x"
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def test_build_env_without_cwd_leaves_pwd_untouched() -> None:
|
|
85
|
+
cfg = RunConfig()
|
|
86
|
+
env = build_env(cfg, base={"HOME": "/tmp", "PWD": "/parent"})
|
|
87
|
+
assert env["PWD"] == "/parent"
|
|
88
|
+
|
|
89
|
+
|
|
60
90
|
@pytest.mark.asyncio
|
|
61
91
|
async def test_readline_unlimited_normal_line() -> None:
|
|
62
92
|
"""Lines within the default 64 KiB limit are returned as-is."""
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{py_opencode_wrapper-0.2.0 → py_opencode_wrapper-0.2.2}/py_opencode_wrapper.egg-info/SOURCES.txt
RENAMED
|
File without changes
|
|
File without changes
|
{py_opencode_wrapper-0.2.0 → py_opencode_wrapper-0.2.2}/py_opencode_wrapper.egg-info/requires.txt
RENAMED
|
File without changes
|
{py_opencode_wrapper-0.2.0 → py_opencode_wrapper-0.2.2}/py_opencode_wrapper.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{py_opencode_wrapper-0.2.0 → py_opencode_wrapper-0.2.2}/tests/test_integration_external_directory.py
RENAMED
|
File without changes
|
{py_opencode_wrapper-0.2.0 → py_opencode_wrapper-0.2.2}/tests/test_integration_instructions.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|