steerable-sidecar 0.6.0__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.
- steerable_sidecar-0.6.0/PKG-INFO +56 -0
- steerable_sidecar-0.6.0/README.md +42 -0
- steerable_sidecar-0.6.0/pyproject.toml +55 -0
- steerable_sidecar-0.6.0/setup.cfg +4 -0
- steerable_sidecar-0.6.0/src/steerable_sidecar/__init__.py +28 -0
- steerable_sidecar-0.6.0/src/steerable_sidecar/__main__.py +84 -0
- steerable_sidecar-0.6.0/src/steerable_sidecar/acp_adapter.py +808 -0
- steerable_sidecar-0.6.0/src/steerable_sidecar/acp_fs.py +64 -0
- steerable_sidecar-0.6.0/src/steerable_sidecar/acp_terminal.py +147 -0
- steerable_sidecar-0.6.0/src/steerable_sidecar/ag_ui.py +223 -0
- steerable_sidecar-0.6.0/src/steerable_sidecar/delivery.py +2764 -0
- steerable_sidecar-0.6.0/src/steerable_sidecar/file_edit.py +251 -0
- steerable_sidecar-0.6.0/src/steerable_sidecar/headless.py +738 -0
- steerable_sidecar-0.6.0/src/steerable_sidecar/host_spawn.py +130 -0
- steerable_sidecar-0.6.0/src/steerable_sidecar/host_tools.py +221 -0
- steerable_sidecar-0.6.0/src/steerable_sidecar/jpeg_ascii.py +314 -0
- steerable_sidecar-0.6.0/src/steerable_sidecar/landlock.py +353 -0
- steerable_sidecar-0.6.0/src/steerable_sidecar/landlock_run.py +35 -0
- steerable_sidecar-0.6.0/src/steerable_sidecar/loop_limits.py +77 -0
- steerable_sidecar-0.6.0/src/steerable_sidecar/multi_file_edit.py +109 -0
- steerable_sidecar-0.6.0/src/steerable_sidecar/png_ascii.py +246 -0
- steerable_sidecar-0.6.0/src/steerable_sidecar/run_code.py +602 -0
- steerable_sidecar-0.6.0/src/steerable_sidecar/run_code_driver.py +229 -0
- steerable_sidecar-0.6.0/src/steerable_sidecar/sandbox.py +693 -0
- steerable_sidecar-0.6.0/src/steerable_sidecar/search_tools.py +173 -0
- steerable_sidecar-0.6.0/src/steerable_sidecar/shell_session.py +301 -0
- steerable_sidecar-0.6.0/src/steerable_sidecar/sidecar.py +2624 -0
- steerable_sidecar-0.6.0/src/steerable_sidecar/tool_contract.json +326 -0
- steerable_sidecar-0.6.0/src/steerable_sidecar/tool_contract.py +62 -0
- steerable_sidecar-0.6.0/src/steerable_sidecar/web_tools.py +964 -0
- steerable_sidecar-0.6.0/src/steerable_sidecar/workspace_fs.py +71 -0
- steerable_sidecar-0.6.0/src/steerable_sidecar/workspace_tools.py +1118 -0
- steerable_sidecar-0.6.0/src/steerable_sidecar.egg-info/PKG-INFO +56 -0
- steerable_sidecar-0.6.0/src/steerable_sidecar.egg-info/SOURCES.txt +71 -0
- steerable_sidecar-0.6.0/src/steerable_sidecar.egg-info/dependency_links.txt +1 -0
- steerable_sidecar-0.6.0/src/steerable_sidecar.egg-info/entry_points.txt +4 -0
- steerable_sidecar-0.6.0/src/steerable_sidecar.egg-info/requires.txt +7 -0
- steerable_sidecar-0.6.0/src/steerable_sidecar.egg-info/top_level.txt +1 -0
- steerable_sidecar-0.6.0/tests/test_acp_adapter.py +955 -0
- steerable_sidecar-0.6.0/tests/test_acp_e2e.py +88 -0
- steerable_sidecar-0.6.0/tests/test_ag_ui.py +223 -0
- steerable_sidecar-0.6.0/tests/test_delivery.py +3326 -0
- steerable_sidecar-0.6.0/tests/test_e2e_loop_limits.py +189 -0
- steerable_sidecar-0.6.0/tests/test_e2e_record_migration.py +198 -0
- steerable_sidecar-0.6.0/tests/test_e2e_run_code.py +237 -0
- steerable_sidecar-0.6.0/tests/test_e2e_tool_exposure.py +198 -0
- steerable_sidecar-0.6.0/tests/test_e2e_web_tools.py +216 -0
- steerable_sidecar-0.6.0/tests/test_file_edit.py +152 -0
- steerable_sidecar-0.6.0/tests/test_headless.py +968 -0
- steerable_sidecar-0.6.0/tests/test_host_spawn.py +153 -0
- steerable_sidecar-0.6.0/tests/test_host_tools.py +508 -0
- steerable_sidecar-0.6.0/tests/test_landlock.py +279 -0
- steerable_sidecar-0.6.0/tests/test_loop_limits.py +92 -0
- steerable_sidecar-0.6.0/tests/test_multi_file_edit.py +144 -0
- steerable_sidecar-0.6.0/tests/test_provider_factory.py +237 -0
- steerable_sidecar-0.6.0/tests/test_run_code.py +339 -0
- steerable_sidecar-0.6.0/tests/test_sandbox.py +658 -0
- steerable_sidecar-0.6.0/tests/test_search_tools.py +83 -0
- steerable_sidecar-0.6.0/tests/test_shell_session.py +183 -0
- steerable_sidecar-0.6.0/tests/test_sidecar_approval.py +436 -0
- steerable_sidecar-0.6.0/tests/test_sidecar_coreloop.py +2036 -0
- steerable_sidecar-0.6.0/tests/test_sidecar_exec_sandbox.py +355 -0
- steerable_sidecar-0.6.0/tests/test_sidecar_mcp.py +276 -0
- steerable_sidecar-0.6.0/tests/test_sidecar_methods.py +535 -0
- steerable_sidecar-0.6.0/tests/test_sidecar_parts.py +91 -0
- steerable_sidecar-0.6.0/tests/test_sidecar_reverse_channel.py +144 -0
- steerable_sidecar-0.6.0/tests/test_sidecar_skills.py +229 -0
- steerable_sidecar-0.6.0/tests/test_sidecar_subprocess.py +143 -0
- steerable_sidecar-0.6.0/tests/test_sidecar_world_state.py +134 -0
- steerable_sidecar-0.6.0/tests/test_tool_contract.py +141 -0
- steerable_sidecar-0.6.0/tests/test_web_tools.py +836 -0
- steerable_sidecar-0.6.0/tests/test_win32_stdio.py +109 -0
- steerable_sidecar-0.6.0/tests/test_workspace_tools.py +723 -0
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: steerable-sidecar
|
|
3
|
+
Version: 0.6.0
|
|
4
|
+
Summary: Steerable agent runtime sidecar — JSON-RPC over stdio.
|
|
5
|
+
Requires-Python: >=3.10
|
|
6
|
+
Description-Content-Type: text/markdown
|
|
7
|
+
Requires-Dist: pydantic>=2.10.0
|
|
8
|
+
Requires-Dist: httpx[socks]>=0.27
|
|
9
|
+
Requires-Dist: steerable-agent-protocol<1.0.0,>=0.1.0
|
|
10
|
+
Requires-Dist: steerable-agent-harness<1.0.0,>=0.1.0
|
|
11
|
+
Requires-Dist: steerable-agent-runtime<1.0.0,>=0.1.0
|
|
12
|
+
Requires-Dist: ag-ui-protocol>=0.1.21
|
|
13
|
+
Requires-Dist: agent-client-protocol>=0.12.1
|
|
14
|
+
|
|
15
|
+
# steerable-sidecar
|
|
16
|
+
|
|
17
|
+
The portable Python entrypoint for the **steerable** framework. Designed to be
|
|
18
|
+
spawned by an Electron / desktop host (or directly from a CLI) and addressed
|
|
19
|
+
via stdio JSON-RPC 2.0.
|
|
20
|
+
|
|
21
|
+
## Quick start
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
pip install steerable-sidecar
|
|
25
|
+
python -m steerable_sidecar
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Or use the console script:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
steerable-sidecar
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
The process:
|
|
35
|
+
|
|
36
|
+
1. Initializes the in-memory storage and a default tool router.
|
|
37
|
+
2. Prints the **ready signal** on **stderr** as a single line:
|
|
38
|
+
`__SIDECAR_READY__:<json>` matching `spec/sidecar/SidecarHealth`.
|
|
39
|
+
3. Begins reading JSON-RPC frames from stdin (one frame per line).
|
|
40
|
+
4. Writes responses and notifications to stdout.
|
|
41
|
+
|
|
42
|
+
See `spec/sidecar/README.md` for the full method/notification catalog.
|
|
43
|
+
|
|
44
|
+
## Embedding
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
import asyncio
|
|
48
|
+
from steerable_sidecar import Sidecar
|
|
49
|
+
|
|
50
|
+
async def main() -> None:
|
|
51
|
+
sidecar = Sidecar()
|
|
52
|
+
sidecar.tools.register(my_tool)
|
|
53
|
+
await sidecar.serve()
|
|
54
|
+
|
|
55
|
+
asyncio.run(main())
|
|
56
|
+
```
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# steerable-sidecar
|
|
2
|
+
|
|
3
|
+
The portable Python entrypoint for the **steerable** framework. Designed to be
|
|
4
|
+
spawned by an Electron / desktop host (or directly from a CLI) and addressed
|
|
5
|
+
via stdio JSON-RPC 2.0.
|
|
6
|
+
|
|
7
|
+
## Quick start
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
pip install steerable-sidecar
|
|
11
|
+
python -m steerable_sidecar
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
Or use the console script:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
steerable-sidecar
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
The process:
|
|
21
|
+
|
|
22
|
+
1. Initializes the in-memory storage and a default tool router.
|
|
23
|
+
2. Prints the **ready signal** on **stderr** as a single line:
|
|
24
|
+
`__SIDECAR_READY__:<json>` matching `spec/sidecar/SidecarHealth`.
|
|
25
|
+
3. Begins reading JSON-RPC frames from stdin (one frame per line).
|
|
26
|
+
4. Writes responses and notifications to stdout.
|
|
27
|
+
|
|
28
|
+
See `spec/sidecar/README.md` for the full method/notification catalog.
|
|
29
|
+
|
|
30
|
+
## Embedding
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
import asyncio
|
|
34
|
+
from steerable_sidecar import Sidecar
|
|
35
|
+
|
|
36
|
+
async def main() -> None:
|
|
37
|
+
sidecar = Sidecar()
|
|
38
|
+
sidecar.tools.register(my_tool)
|
|
39
|
+
await sidecar.serve()
|
|
40
|
+
|
|
41
|
+
asyncio.run(main())
|
|
42
|
+
```
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "steerable-sidecar"
|
|
3
|
+
version = "0.6.0"
|
|
4
|
+
description = "Steerable agent runtime sidecar — JSON-RPC over stdio."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.10"
|
|
7
|
+
# Pre-1.0 inter-package pins use `>=X,<1.0.0` ranges — flexible enough
|
|
8
|
+
# that any 0.x lockstep version installs cleanly. `bump_to.sh` keeps
|
|
9
|
+
# all 7 Steerable packages at the same X.Y.Z, enforced by the
|
|
10
|
+
# release.yml lockstep gate. Tighten to `~=1.0` post-GA.
|
|
11
|
+
# See packages/agent-harness/py/pyproject.toml for the rationale.
|
|
12
|
+
dependencies = [
|
|
13
|
+
"pydantic>=2.10.0",
|
|
14
|
+
# httpx backs OpenAICompatProvider — the default provider family for
|
|
15
|
+
# agent.chat.stream (openai_compat / ollama). Not optional here: the
|
|
16
|
+
# sidecar exists to talk to LLM endpoints. (anthropic stays a lazy
|
|
17
|
+
# import, only loaded when provider=anthropic.)
|
|
18
|
+
# The `socks` extra covers hosts exporting `all_proxy=socks5://…`: httpx
|
|
19
|
+
# builds a transport per declared proxy at client construction, so the scheme
|
|
20
|
+
# must be buildable or every provider call fails before reaching a URL.
|
|
21
|
+
"httpx[socks]>=0.27",
|
|
22
|
+
"steerable-agent-protocol>=0.1.0,<1.0.0",
|
|
23
|
+
"steerable-agent-harness>=0.1.0,<1.0.0",
|
|
24
|
+
"steerable-agent-runtime>=0.1.0,<1.0.0",
|
|
25
|
+
"ag-ui-protocol>=0.1.21",
|
|
26
|
+
"agent-client-protocol>=0.12.1",
|
|
27
|
+
]
|
|
28
|
+
|
|
29
|
+
[project.scripts]
|
|
30
|
+
steerable-sidecar = "steerable_sidecar.__main__:main"
|
|
31
|
+
steerable-sidecar-acp = "steerable_sidecar.acp_adapter:main"
|
|
32
|
+
steerable-sidecar-headless = "steerable_sidecar.headless:main"
|
|
33
|
+
|
|
34
|
+
[build-system]
|
|
35
|
+
requires = ["setuptools>=68", "wheel"]
|
|
36
|
+
build-backend = "setuptools.build_meta"
|
|
37
|
+
|
|
38
|
+
[tool.setuptools]
|
|
39
|
+
package-dir = {"" = "src"}
|
|
40
|
+
|
|
41
|
+
[tool.setuptools.packages.find]
|
|
42
|
+
where = ["src"]
|
|
43
|
+
|
|
44
|
+
# tool_contract.json is loaded via __file__ by tool_contract.py; ship it so the
|
|
45
|
+
# canonical tool contract resolves from an installed wheel, not only from source.
|
|
46
|
+
[tool.setuptools.package-data]
|
|
47
|
+
steerable_sidecar = ["*.json"]
|
|
48
|
+
|
|
49
|
+
[tool.uv.sources]
|
|
50
|
+
steerable-agent-protocol = { workspace = true }
|
|
51
|
+
steerable-agent-harness = { workspace = true }
|
|
52
|
+
steerable-agent-runtime = { workspace = true }
|
|
53
|
+
|
|
54
|
+
[tool.pytest.ini_options]
|
|
55
|
+
asyncio_mode = "auto"
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"""steerable-sidecar — portable runtime entrypoint."""
|
|
2
|
+
|
|
3
|
+
from .landlock import LandlockExecBackend, landlock_available
|
|
4
|
+
from .sandbox import (
|
|
5
|
+
BwrapExecBackend,
|
|
6
|
+
SeatbeltExecBackend,
|
|
7
|
+
build_seatbelt_profile,
|
|
8
|
+
bwrap_available,
|
|
9
|
+
seatbelt_argv,
|
|
10
|
+
seatbelt_available,
|
|
11
|
+
select_exec_backend,
|
|
12
|
+
)
|
|
13
|
+
from .sidecar import Sidecar, SidecarConfig
|
|
14
|
+
|
|
15
|
+
__all__ = [
|
|
16
|
+
"BwrapExecBackend",
|
|
17
|
+
"LandlockExecBackend",
|
|
18
|
+
"SeatbeltExecBackend",
|
|
19
|
+
"Sidecar",
|
|
20
|
+
"SidecarConfig",
|
|
21
|
+
"build_seatbelt_profile",
|
|
22
|
+
"bwrap_available",
|
|
23
|
+
"landlock_available",
|
|
24
|
+
"seatbelt_argv",
|
|
25
|
+
"seatbelt_available",
|
|
26
|
+
"select_exec_backend",
|
|
27
|
+
]
|
|
28
|
+
__version__ = "0.1.0"
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"""``python -m steerable_sidecar`` entrypoint."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import argparse
|
|
6
|
+
import asyncio
|
|
7
|
+
import logging
|
|
8
|
+
|
|
9
|
+
from steerable_agent_runtime.errors import StoreAlreadyOwnedError
|
|
10
|
+
|
|
11
|
+
from .sidecar import Sidecar, SidecarConfig
|
|
12
|
+
from .web_tools import register_web_tools
|
|
13
|
+
from .run_code import register_run_code, run_code_enabled
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _build_parser() -> argparse.ArgumentParser:
|
|
17
|
+
parser = argparse.ArgumentParser(prog="steerable-sidecar")
|
|
18
|
+
parser.add_argument(
|
|
19
|
+
"--log-level",
|
|
20
|
+
default="INFO",
|
|
21
|
+
choices=["DEBUG", "INFO", "WARNING", "ERROR"],
|
|
22
|
+
help="Sidecar log level (logged on stderr).",
|
|
23
|
+
)
|
|
24
|
+
parser.add_argument(
|
|
25
|
+
"--quiet-ready",
|
|
26
|
+
action="store_true",
|
|
27
|
+
help="Skip the __SIDECAR_READY__ stderr marker.",
|
|
28
|
+
)
|
|
29
|
+
parser.add_argument(
|
|
30
|
+
"--storage-path",
|
|
31
|
+
default=None,
|
|
32
|
+
metavar="PATH",
|
|
33
|
+
help="Persist sessions/traces/history to a sqlite database at PATH "
|
|
34
|
+
"(W2.6.1). Default: in-memory, per-process only.",
|
|
35
|
+
)
|
|
36
|
+
return parser
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def main() -> int:
|
|
40
|
+
parser = _build_parser()
|
|
41
|
+
args = parser.parse_args()
|
|
42
|
+
config = SidecarConfig(
|
|
43
|
+
log_level=args.log_level,
|
|
44
|
+
quiet_stderr=args.quiet_ready,
|
|
45
|
+
storage_path=args.storage_path,
|
|
46
|
+
)
|
|
47
|
+
try:
|
|
48
|
+
sidecar = Sidecar(config=config)
|
|
49
|
+
except StoreAlreadyOwnedError as exc:
|
|
50
|
+
logging.getLogger("steerable_sidecar").error("%s", exc)
|
|
51
|
+
return 1
|
|
52
|
+
# web_search / web_fetch on the RPC router: the desktop host delegates
|
|
53
|
+
# these calls here over forward `tool.invoke` (single implementation —
|
|
54
|
+
# the host carries schemas only). A malformed STEERABLE_WEB_* bound must
|
|
55
|
+
# not brick chat for an optional feature, so the misconfiguration logs
|
|
56
|
+
# loud and the sidecar serves without the web pair.
|
|
57
|
+
try:
|
|
58
|
+
register_web_tools(sidecar.tools)
|
|
59
|
+
except ValueError as exc:
|
|
60
|
+
logging.getLogger("steerable_sidecar").error(
|
|
61
|
+
"web tools disabled: %s", exc
|
|
62
|
+
)
|
|
63
|
+
if run_code_enabled():
|
|
64
|
+
register_run_code(sidecar.tools)
|
|
65
|
+
# Third-party tools: discover packages that registered the
|
|
66
|
+
# ``steerable.tools`` entry-point group and load their tools onto the
|
|
67
|
+
# router. A broken entry point fails the boot loud (PluginLoadError
|
|
68
|
+
# names the offender) rather than silently dropping an installed tool.
|
|
69
|
+
from steerable_agent_runtime import PluginLoadError, load_tool_entry_points
|
|
70
|
+
|
|
71
|
+
try:
|
|
72
|
+
load_tool_entry_points(sidecar.tools)
|
|
73
|
+
except PluginLoadError as exc:
|
|
74
|
+
logging.getLogger("steerable_sidecar").error("tool plugin: %s", exc)
|
|
75
|
+
return 1
|
|
76
|
+
try:
|
|
77
|
+
asyncio.run(sidecar.serve())
|
|
78
|
+
except KeyboardInterrupt:
|
|
79
|
+
logging.getLogger("steerable_sidecar").info("interrupted")
|
|
80
|
+
return 0
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
if __name__ == "__main__": # pragma: no cover
|
|
84
|
+
raise SystemExit(main())
|