swytchcode-runtime 0.1.0__tar.gz → 1.0.1__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 (31) hide show
  1. swytchcode_runtime-1.0.1/LICENSE.md +21 -0
  2. swytchcode_runtime-1.0.1/PKG-INFO +236 -0
  3. swytchcode_runtime-1.0.1/README.md +218 -0
  4. {swytchcode_runtime-0.1.0 → swytchcode_runtime-1.0.1}/pyproject.toml +2 -2
  5. swytchcode_runtime-1.0.1/swytchcode_runtime/__init__.py +30 -0
  6. swytchcode_runtime-1.0.1/swytchcode_runtime/cli.py +58 -0
  7. swytchcode_runtime-1.0.1/swytchcode_runtime/client.py +243 -0
  8. swytchcode_runtime-1.0.1/swytchcode_runtime/discover.py +29 -0
  9. {swytchcode_runtime-0.1.0 → swytchcode_runtime-1.0.1}/swytchcode_runtime/exec.py +57 -3
  10. swytchcode_runtime-1.0.1/swytchcode_runtime/manage.py +30 -0
  11. swytchcode_runtime-1.0.1/swytchcode_runtime/providers/__init__.py +27 -0
  12. swytchcode_runtime-1.0.1/swytchcode_runtime/providers/anthropic.py +13 -0
  13. swytchcode_runtime-1.0.1/swytchcode_runtime/providers/base.py +31 -0
  14. swytchcode_runtime-1.0.1/swytchcode_runtime/providers/crewai.py +22 -0
  15. swytchcode_runtime-1.0.1/swytchcode_runtime/providers/langgraph.py +17 -0
  16. swytchcode_runtime-1.0.1/swytchcode_runtime/providers/openai_agents.py +30 -0
  17. swytchcode_runtime-1.0.1/swytchcode_runtime/providers/vercel.py +30 -0
  18. swytchcode_runtime-1.0.1/swytchcode_runtime/schema.py +115 -0
  19. swytchcode_runtime-1.0.1/swytchcode_runtime.egg-info/PKG-INFO +236 -0
  20. swytchcode_runtime-1.0.1/swytchcode_runtime.egg-info/SOURCES.txt +24 -0
  21. swytchcode_runtime-1.0.1/tests/test_alias.py +42 -0
  22. swytchcode_runtime-1.0.1/tests/test_schema_routing.py +62 -0
  23. swytchcode_runtime-0.1.0/PKG-INFO +0 -133
  24. swytchcode_runtime-0.1.0/README.md +0 -117
  25. swytchcode_runtime-0.1.0/swytchcode_runtime/__init__.py +0 -6
  26. swytchcode_runtime-0.1.0/swytchcode_runtime.egg-info/PKG-INFO +0 -133
  27. swytchcode_runtime-0.1.0/swytchcode_runtime.egg-info/SOURCES.txt +0 -9
  28. {swytchcode_runtime-0.1.0 → swytchcode_runtime-1.0.1}/setup.cfg +0 -0
  29. {swytchcode_runtime-0.1.0 → swytchcode_runtime-1.0.1}/swytchcode_runtime/errors.py +0 -0
  30. {swytchcode_runtime-0.1.0 → swytchcode_runtime-1.0.1}/swytchcode_runtime.egg-info/dependency_links.txt +0 -0
  31. {swytchcode_runtime-0.1.0 → swytchcode_runtime-1.0.1}/swytchcode_runtime.egg-info/top_level.txt +0 -0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Swytchcode Technologies Inc.
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,236 @@
1
+ Metadata-Version: 2.4
2
+ Name: swytchcode-runtime
3
+ Version: 1.0.1
4
+ Summary: Thin runtime wrapper around the Swytchcode CLI
5
+ Author: Swytchcode
6
+ License: MIT
7
+ Project-URL: repository, https://github.com/swytchcodehq/runtime-py
8
+ Keywords: swytchcode,cli,runtime,exec
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.10
12
+ Classifier: Programming Language :: Python :: 3.11
13
+ Classifier: Programming Language :: Python :: 3.12
14
+ Requires-Python: >=3.10
15
+ Description-Content-Type: text/markdown
16
+ License-File: LICENSE.md
17
+ Dynamic: license-file
18
+
19
+ # swytchcode-runtime (Python)
20
+
21
+ Thin runtime wrapper around the Swytchcode CLI. Calls `swytchcode exec` for you so you can stay in Python without shell boilerplate.
22
+
23
+ **Requires:** The `swytchcode` CLI must be installed. The binary is located automatically — no configuration needed in most environments. Resolution order:
24
+
25
+ 1. `SWYTCHCODE_BIN` env var — explicit override.
26
+ 2. `$PATH` lookup via `shutil.which` — the standard system resolution.
27
+ 3. Common install paths — `~/.local/bin`, `/usr/local/bin` (Unix) or `%LOCALAPPDATA%\Programs\swytchcode\bin` (Windows).
28
+
29
+ ## Install
30
+
31
+ ```bash
32
+ pip install swytchcode-runtime
33
+ ```
34
+
35
+ Or from the repo:
36
+
37
+ ```bash
38
+ pip install /path/to/runtime-libraries/python-runtime
39
+ ```
40
+
41
+ ## Use
42
+
43
+ ### JSON mode (default)
44
+
45
+ ```python
46
+ from swytchcode_runtime import exec
47
+
48
+ result = exec("api.account.create", {"email": "test@example.com"})
49
+ # result is parsed JSON (any)
50
+ ```
51
+
52
+ Equivalent to: `swytchcode exec api.account.create --json` with args on stdin.
53
+
54
+ **Request input (args):** The second argument is the kernel **args** object (sent as JSON on stdin). Use this shape so the kernel builds the request correctly:
55
+ - **body** — Request body (dict).
56
+ - **params** — Query/path params (e.g. `{"id": "cluster-123"}`).
57
+ - **Authorization** — Auth header value (e.g. `"Bearer token123"`).
58
+ - **headers** — Additional request headers (e.g. `{"X-Request-Id": "abc-123"}`).
59
+ - Other top-level keys are passed as query params.
60
+
61
+ Example with body, params, and headers:
62
+
63
+ ```python
64
+ exec("api.cluster.get", {
65
+ "params": {"id": "cluster-123"},
66
+ "Authorization": "Bearer token123",
67
+ "headers": {"X-Request-Id": "abc-123"},
68
+ })
69
+ ```
70
+
71
+ ### Raw mode
72
+
73
+ Get stdout as a string instead of parsing JSON:
74
+
75
+ ```python
76
+ from swytchcode_runtime import exec
77
+
78
+ output = exec("api.report.export", {"id": "123"}, raw=True)
79
+ # output is the raw stdout string
80
+ ```
81
+
82
+ ### Options
83
+
84
+ - **cwd** – Working directory for the process (default: current directory).
85
+ - **env** – Extra environment variables (merged with `os.environ`).
86
+ - **raw** – If `True`, use `--raw` and return stdout as a string.
87
+ - **dry_run** – If `True`, pass `--dry-run` to the CLI; request details (method, url, headers, body) are output instead of calling the server.
88
+ - **allow_raw** – If `True`, pass `--allow-raw` to the CLI; required for executing raw methods (kernel has this disabled by default).
89
+
90
+ This runtime invokes `swytchcode exec [canonical_id]` with the flags above. For full exec behavior, see the Swytchcode kernel documentation.
91
+
92
+ ### Environment variables
93
+
94
+ | Variable | Description |
95
+ |----------|-------------|
96
+ | `SWYTCHCODE_BIN` | Override the resolved binary path. Set this only when automatic resolution does not find the correct binary (e.g. non-standard install locations or virtualised environments). |
97
+ | `SWYTCHCODE_TOKEN` | Auth token passed to the CLI via the process environment. |
98
+
99
+ ### Error handling
100
+
101
+ Failures raise `SwytchcodeError` (spawn error, non-zero exit, invalid JSON). Use the helper to narrow:
102
+
103
+ ```python
104
+ from swytchcode_runtime import exec, SwytchcodeError, is_swytchcode_error
105
+
106
+ try:
107
+ exec("api.account.create", {"email": "test@example.com"})
108
+ except Exception as e:
109
+ if is_swytchcode_error(e):
110
+ print(e.message, e.cause)
111
+ raise
112
+ ```
113
+
114
+ ## What this library is
115
+
116
+ - A thin process wrapper over the Swytchcode shell.
117
+ - A stable call surface: `exec(canonical_id, input=None, *, cwd=..., env=..., raw=...)`.
118
+ - A convenience for developers and IDE agents.
119
+
120
+ ## What this library is not
121
+
122
+ - An HTTP SDK or API client.
123
+ - A replacement for the shell. All authority stays in the Swytchcode CLI.
124
+
125
+ This library **must not** and **does not**:
126
+
127
+ - Read `.swytchcode/*` or parse `tooling.json`.
128
+ - Validate schemas or add retries/timeouts.
129
+ - Call the registry or embed auth logic.
130
+
131
+ It is a pipe, not a brain.
132
+
133
+ ## For Cursor / IDE agents
134
+
135
+ Generate code that uses this runtime instead of subprocess boilerplate.
136
+
137
+ **Preferred:**
138
+
139
+ ```python
140
+ from swytchcode_runtime import exec
141
+
142
+ def create_account(input: dict) -> any:
143
+ return exec("api.account.create", input)
144
+ ```
145
+
146
+ **Avoid:** subprocess boilerplate, HTTP calls, or config parsing. Use `exec(...)` and let the CLI handle execution and policy.
147
+
148
+ ## Agentic workflows (framework integrations)
149
+
150
+ For full, production-ready examples across all major frameworks, check out the [Swytchcode Examples Repository](https://github.com/swytchcodehq/swytchcode-examples).
151
+
152
+ On top of `exec`, the runtime exposes a small agentic surface that turns Swytchcode tools into the native tool objects each agent framework expects.
153
+
154
+ ### Quickstart: Anthropic SDK
155
+
156
+ Here is a clean example of building a simple agent using the Anthropic SDK. We use `python-dotenv` to load environment variables (like `ANTHROPIC_API_KEY`).
157
+
158
+ **Installation:**
159
+ ```bash
160
+ pip install swytchcode-runtime anthropic python-dotenv
161
+ ```
162
+ *(Note: You only need to install the SDK for the framework you are actually using. You **do not** need to install `openai-agents` or `langchain` if you are only using Anthropic. The `swytchcode-runtime` isolates these dependencies via lazy loading.)*
163
+
164
+ **Example:**
165
+ ```python
166
+ import os
167
+ from dotenv import load_dotenv
168
+ import anthropic
169
+ from swytchcode_runtime import Swytchcode
170
+ from swytchcode_runtime.providers.anthropic import AnthropicProvider
171
+
172
+ load_dotenv() # Loads .env automatically
173
+
174
+ def run_agent():
175
+ client = anthropic.Anthropic()
176
+
177
+ # 1. Initialize Swytchcode with the Anthropic provider
178
+ swx = Swytchcode(provider=AnthropicProvider())
179
+
180
+ # 2. Fetch the tools you want your agent to use (e.g., Stripe tools)
181
+ tools = swx.tools.get(toolkits=["stripe"])
182
+
183
+ # 3. Pass them to Claude
184
+ response = client.messages.create(
185
+ model="claude-3-5-sonnet-latest",
186
+ max_tokens=1024,
187
+ tools=tools,
188
+ messages=[{"role": "user", "content": "Refund charge ch_123 for $20."}],
189
+ )
190
+
191
+ print(response)
192
+
193
+ if __name__ == "__main__":
194
+ run_agent()
195
+ ```
196
+
197
+ ### Selecting tools - `swx.tools.get(...)`
198
+
199
+ Pass exactly one selector; IDs resolve against your local Swytchcode state and remote search:
200
+
201
+ - `toolkits=["stripe"]` - every enabled tool whose integration matches a toolkit.
202
+ - `tools=["charges.charge.create"]` - explicit canonical IDs.
203
+ - `search="refund a charge"` - natural-language discovery (via `swytchcode discover`).
204
+
205
+ Each returned tool carries a **full input schema** - every field is surfaced to the model, with
206
+ only the truly-required ones marked `required` - and an `execute` callback that runs `swytchcode
207
+ exec` for you (empty optional values are stripped before the call so APIs like Stripe don't reject them).
208
+
209
+ ### Supported providers
210
+
211
+ | Framework | Import | Who runs the tool loop |
212
+ |-----------|--------|------------------------|
213
+ | Anthropic Claude | `from swytchcode_runtime.providers.anthropic import AnthropicProvider` | you (Messages API + `swx.handle_tool_calls`) |
214
+ | OpenAI Agents SDK | `from swytchcode_runtime.providers.openai_agents import OpenAIAgentsProvider` | the SDK |
215
+ | Vercel AI SDK | `from swytchcode_runtime.providers.vercel import VercelProvider` | the SDK |
216
+ | LangGraph | `from swytchcode_runtime.providers.langgraph import LangGraphProvider` | the prebuilt agent |
217
+ | CrewAI | `from swytchcode_runtime.providers.crewai import CrewAIProvider` | the crew |
218
+
219
+ ### Non-agentic APIs (Anthropic Messages)
220
+
221
+ When you run the tool loop yourself, `handle_tool_calls` executes each `tool_use` block and
222
+ returns the `tool_result` blocks to send back:
223
+
224
+ ```python
225
+ import anthropic
226
+ client = anthropic.Anthropic()
227
+ msg = client.messages.create(
228
+ model="claude-sonnet-5", max_tokens=1024, tools=tools,
229
+ messages=[{"role": "user", "content": "Refund charge ch_123 for $20"}],
230
+ )
231
+ results = swx.handle_tool_calls(msg) # runs the tool calls, returns tool_result blocks
232
+ ```
233
+
234
+ One runnable file per framework lives in `sdk-examples/`. Install the matching framework SDK
235
+ (`pip install openai-agents` / `anthropic` / `ai` / `langgraph` / `crewai`) alongside the
236
+ `swytchcode` CLI.
@@ -0,0 +1,218 @@
1
+ # swytchcode-runtime (Python)
2
+
3
+ Thin runtime wrapper around the Swytchcode CLI. Calls `swytchcode exec` for you so you can stay in Python without shell boilerplate.
4
+
5
+ **Requires:** The `swytchcode` CLI must be installed. The binary is located automatically — no configuration needed in most environments. Resolution order:
6
+
7
+ 1. `SWYTCHCODE_BIN` env var — explicit override.
8
+ 2. `$PATH` lookup via `shutil.which` — the standard system resolution.
9
+ 3. Common install paths — `~/.local/bin`, `/usr/local/bin` (Unix) or `%LOCALAPPDATA%\Programs\swytchcode\bin` (Windows).
10
+
11
+ ## Install
12
+
13
+ ```bash
14
+ pip install swytchcode-runtime
15
+ ```
16
+
17
+ Or from the repo:
18
+
19
+ ```bash
20
+ pip install /path/to/runtime-libraries/python-runtime
21
+ ```
22
+
23
+ ## Use
24
+
25
+ ### JSON mode (default)
26
+
27
+ ```python
28
+ from swytchcode_runtime import exec
29
+
30
+ result = exec("api.account.create", {"email": "test@example.com"})
31
+ # result is parsed JSON (any)
32
+ ```
33
+
34
+ Equivalent to: `swytchcode exec api.account.create --json` with args on stdin.
35
+
36
+ **Request input (args):** The second argument is the kernel **args** object (sent as JSON on stdin). Use this shape so the kernel builds the request correctly:
37
+ - **body** — Request body (dict).
38
+ - **params** — Query/path params (e.g. `{"id": "cluster-123"}`).
39
+ - **Authorization** — Auth header value (e.g. `"Bearer token123"`).
40
+ - **headers** — Additional request headers (e.g. `{"X-Request-Id": "abc-123"}`).
41
+ - Other top-level keys are passed as query params.
42
+
43
+ Example with body, params, and headers:
44
+
45
+ ```python
46
+ exec("api.cluster.get", {
47
+ "params": {"id": "cluster-123"},
48
+ "Authorization": "Bearer token123",
49
+ "headers": {"X-Request-Id": "abc-123"},
50
+ })
51
+ ```
52
+
53
+ ### Raw mode
54
+
55
+ Get stdout as a string instead of parsing JSON:
56
+
57
+ ```python
58
+ from swytchcode_runtime import exec
59
+
60
+ output = exec("api.report.export", {"id": "123"}, raw=True)
61
+ # output is the raw stdout string
62
+ ```
63
+
64
+ ### Options
65
+
66
+ - **cwd** – Working directory for the process (default: current directory).
67
+ - **env** – Extra environment variables (merged with `os.environ`).
68
+ - **raw** – If `True`, use `--raw` and return stdout as a string.
69
+ - **dry_run** – If `True`, pass `--dry-run` to the CLI; request details (method, url, headers, body) are output instead of calling the server.
70
+ - **allow_raw** – If `True`, pass `--allow-raw` to the CLI; required for executing raw methods (kernel has this disabled by default).
71
+
72
+ This runtime invokes `swytchcode exec [canonical_id]` with the flags above. For full exec behavior, see the Swytchcode kernel documentation.
73
+
74
+ ### Environment variables
75
+
76
+ | Variable | Description |
77
+ |----------|-------------|
78
+ | `SWYTCHCODE_BIN` | Override the resolved binary path. Set this only when automatic resolution does not find the correct binary (e.g. non-standard install locations or virtualised environments). |
79
+ | `SWYTCHCODE_TOKEN` | Auth token passed to the CLI via the process environment. |
80
+
81
+ ### Error handling
82
+
83
+ Failures raise `SwytchcodeError` (spawn error, non-zero exit, invalid JSON). Use the helper to narrow:
84
+
85
+ ```python
86
+ from swytchcode_runtime import exec, SwytchcodeError, is_swytchcode_error
87
+
88
+ try:
89
+ exec("api.account.create", {"email": "test@example.com"})
90
+ except Exception as e:
91
+ if is_swytchcode_error(e):
92
+ print(e.message, e.cause)
93
+ raise
94
+ ```
95
+
96
+ ## What this library is
97
+
98
+ - A thin process wrapper over the Swytchcode shell.
99
+ - A stable call surface: `exec(canonical_id, input=None, *, cwd=..., env=..., raw=...)`.
100
+ - A convenience for developers and IDE agents.
101
+
102
+ ## What this library is not
103
+
104
+ - An HTTP SDK or API client.
105
+ - A replacement for the shell. All authority stays in the Swytchcode CLI.
106
+
107
+ This library **must not** and **does not**:
108
+
109
+ - Read `.swytchcode/*` or parse `tooling.json`.
110
+ - Validate schemas or add retries/timeouts.
111
+ - Call the registry or embed auth logic.
112
+
113
+ It is a pipe, not a brain.
114
+
115
+ ## For Cursor / IDE agents
116
+
117
+ Generate code that uses this runtime instead of subprocess boilerplate.
118
+
119
+ **Preferred:**
120
+
121
+ ```python
122
+ from swytchcode_runtime import exec
123
+
124
+ def create_account(input: dict) -> any:
125
+ return exec("api.account.create", input)
126
+ ```
127
+
128
+ **Avoid:** subprocess boilerplate, HTTP calls, or config parsing. Use `exec(...)` and let the CLI handle execution and policy.
129
+
130
+ ## Agentic workflows (framework integrations)
131
+
132
+ For full, production-ready examples across all major frameworks, check out the [Swytchcode Examples Repository](https://github.com/swytchcodehq/swytchcode-examples).
133
+
134
+ On top of `exec`, the runtime exposes a small agentic surface that turns Swytchcode tools into the native tool objects each agent framework expects.
135
+
136
+ ### Quickstart: Anthropic SDK
137
+
138
+ Here is a clean example of building a simple agent using the Anthropic SDK. We use `python-dotenv` to load environment variables (like `ANTHROPIC_API_KEY`).
139
+
140
+ **Installation:**
141
+ ```bash
142
+ pip install swytchcode-runtime anthropic python-dotenv
143
+ ```
144
+ *(Note: You only need to install the SDK for the framework you are actually using. You **do not** need to install `openai-agents` or `langchain` if you are only using Anthropic. The `swytchcode-runtime` isolates these dependencies via lazy loading.)*
145
+
146
+ **Example:**
147
+ ```python
148
+ import os
149
+ from dotenv import load_dotenv
150
+ import anthropic
151
+ from swytchcode_runtime import Swytchcode
152
+ from swytchcode_runtime.providers.anthropic import AnthropicProvider
153
+
154
+ load_dotenv() # Loads .env automatically
155
+
156
+ def run_agent():
157
+ client = anthropic.Anthropic()
158
+
159
+ # 1. Initialize Swytchcode with the Anthropic provider
160
+ swx = Swytchcode(provider=AnthropicProvider())
161
+
162
+ # 2. Fetch the tools you want your agent to use (e.g., Stripe tools)
163
+ tools = swx.tools.get(toolkits=["stripe"])
164
+
165
+ # 3. Pass them to Claude
166
+ response = client.messages.create(
167
+ model="claude-3-5-sonnet-latest",
168
+ max_tokens=1024,
169
+ tools=tools,
170
+ messages=[{"role": "user", "content": "Refund charge ch_123 for $20."}],
171
+ )
172
+
173
+ print(response)
174
+
175
+ if __name__ == "__main__":
176
+ run_agent()
177
+ ```
178
+
179
+ ### Selecting tools - `swx.tools.get(...)`
180
+
181
+ Pass exactly one selector; IDs resolve against your local Swytchcode state and remote search:
182
+
183
+ - `toolkits=["stripe"]` - every enabled tool whose integration matches a toolkit.
184
+ - `tools=["charges.charge.create"]` - explicit canonical IDs.
185
+ - `search="refund a charge"` - natural-language discovery (via `swytchcode discover`).
186
+
187
+ Each returned tool carries a **full input schema** - every field is surfaced to the model, with
188
+ only the truly-required ones marked `required` - and an `execute` callback that runs `swytchcode
189
+ exec` for you (empty optional values are stripped before the call so APIs like Stripe don't reject them).
190
+
191
+ ### Supported providers
192
+
193
+ | Framework | Import | Who runs the tool loop |
194
+ |-----------|--------|------------------------|
195
+ | Anthropic Claude | `from swytchcode_runtime.providers.anthropic import AnthropicProvider` | you (Messages API + `swx.handle_tool_calls`) |
196
+ | OpenAI Agents SDK | `from swytchcode_runtime.providers.openai_agents import OpenAIAgentsProvider` | the SDK |
197
+ | Vercel AI SDK | `from swytchcode_runtime.providers.vercel import VercelProvider` | the SDK |
198
+ | LangGraph | `from swytchcode_runtime.providers.langgraph import LangGraphProvider` | the prebuilt agent |
199
+ | CrewAI | `from swytchcode_runtime.providers.crewai import CrewAIProvider` | the crew |
200
+
201
+ ### Non-agentic APIs (Anthropic Messages)
202
+
203
+ When you run the tool loop yourself, `handle_tool_calls` executes each `tool_use` block and
204
+ returns the `tool_result` blocks to send back:
205
+
206
+ ```python
207
+ import anthropic
208
+ client = anthropic.Anthropic()
209
+ msg = client.messages.create(
210
+ model="claude-sonnet-5", max_tokens=1024, tools=tools,
211
+ messages=[{"role": "user", "content": "Refund charge ch_123 for $20"}],
212
+ )
213
+ results = swx.handle_tool_calls(msg) # runs the tool calls, returns tool_result blocks
214
+ ```
215
+
216
+ One runnable file per framework lives in `sdk-examples/`. Install the matching framework SDK
217
+ (`pip install openai-agents` / `anthropic` / `ai` / `langgraph` / `crewai`) alongside the
218
+ `swytchcode` CLI.
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "swytchcode-runtime"
7
- version = "0.1.0"
7
+ version = "1.0.1"
8
8
  description = "Thin runtime wrapper around the Swytchcode CLI"
9
9
  readme = "README.md"
10
10
  license = { text = "MIT" }
@@ -20,7 +20,7 @@ classifiers = [
20
20
  ]
21
21
 
22
22
  [project.urls]
23
- repository = "https://gitlab.com/swytchcode/py-runtime"
23
+ repository = "https://github.com/swytchcodehq/runtime-py"
24
24
 
25
25
  [tool.setuptools.packages.find]
26
26
  where = ["."]
@@ -0,0 +1,30 @@
1
+ """Thin runtime wrapper around the Swytchcode CLI."""
2
+
3
+ from .errors import SwytchcodeError, is_swytchcode_error
4
+ from .exec import exec_ as exec
5
+ from .client import Swytchcode
6
+
7
+ __all__ = [
8
+ "exec",
9
+ "Swytchcode",
10
+ "SwytchcodeError",
11
+ "is_swytchcode_error",
12
+ ]
13
+
14
+
15
+ def __getattr__(name):
16
+ """Lazy provider imports for backward compatibility."""
17
+ _provider_map = {
18
+ "AnthropicProvider": ("providers.anthropic", "AnthropicProvider"),
19
+ "OpenAIAgentsProvider": ("providers.openai_agents", "OpenAIAgentsProvider"),
20
+ "VercelProvider": ("providers.vercel", "VercelProvider"),
21
+ "LangGraphProvider": ("providers.langgraph", "LangGraphProvider"),
22
+ "CrewAIProvider": ("providers.crewai", "CrewAIProvider"),
23
+ }
24
+ if name in _provider_map:
25
+ module_path, attr = _provider_map[name]
26
+ import importlib
27
+
28
+ mod = importlib.import_module(f".{module_path}", __package__)
29
+ return getattr(mod, attr)
30
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
@@ -0,0 +1,58 @@
1
+ """Run a swytchcode CLI subcommand with --json and parse the output."""
2
+
3
+ from __future__ import annotations
4
+ import json
5
+ import os
6
+ import subprocess
7
+ from typing import Any
8
+
9
+ from .exec import _resolve_bin
10
+ from .errors import SwytchcodeError
11
+
12
+
13
+ def run_cli(
14
+ args: list[str],
15
+ *,
16
+ cwd: str | None = None,
17
+ env: dict | None = None,
18
+ timeout: float | None = 60,
19
+ ) -> Any:
20
+ cmd = [_resolve_bin(), *args]
21
+ if "--json" not in args:
22
+ cmd.append("--json")
23
+
24
+ run_env = os.environ.copy()
25
+ if env:
26
+ run_env.update(env)
27
+
28
+ try:
29
+ r = subprocess.run(
30
+ cmd,
31
+ capture_output=True,
32
+ cwd=cwd or os.getcwd(),
33
+ env=run_env,
34
+ timeout=timeout,
35
+ )
36
+ except FileNotFoundError as e:
37
+ raise SwytchcodeError(
38
+ "Failed to spawn swytchcode; is the CLI installed?", e
39
+ ) from e
40
+ except subprocess.TimeoutExpired as e:
41
+ raise SwytchcodeError(
42
+ f"swytchcode command timed out after {timeout}s", e
43
+ ) from e
44
+
45
+ if r.returncode != 0:
46
+ raise SwytchcodeError(
47
+ r.stderr.decode("utf-8", "replace").strip() or "command failed",
48
+ r.returncode,
49
+ )
50
+
51
+ out = r.stdout.decode("utf-8", "replace").strip()
52
+ if not out:
53
+ return None
54
+
55
+ try:
56
+ return json.loads(out)
57
+ except json.JSONDecodeError as e:
58
+ raise SwytchcodeError("Invalid JSON from swytchcode", out) from e