sbxloop-worker 0.3.0__tar.gz → 0.4.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.
- {sbxloop_worker-0.3.0 → sbxloop_worker-0.4.1}/.gitignore +4 -0
- {sbxloop_worker-0.3.0 → sbxloop_worker-0.4.1}/PKG-INFO +1 -1
- {sbxloop_worker-0.3.0 → sbxloop_worker-0.4.1}/pyproject.toml +14 -2
- sbxloop_worker-0.4.1/src/sbxloop_worker/__init__.py +19 -0
- sbxloop_worker-0.4.1/src/sbxloop_worker/_version.py +24 -0
- {sbxloop_worker-0.3.0 → sbxloop_worker-0.4.1}/src/sbxloop_worker/backends/copilot.py +69 -5
- sbxloop_worker-0.3.0/src/sbxloop_worker/__init__.py +0 -10
- {sbxloop_worker-0.3.0 → sbxloop_worker-0.4.1}/README.md +0 -0
- {sbxloop_worker-0.3.0 → sbxloop_worker-0.4.1}/src/sbxloop_worker/__main__.py +0 -0
- {sbxloop_worker-0.3.0 → sbxloop_worker-0.4.1}/src/sbxloop_worker/_json.py +0 -0
- {sbxloop_worker-0.3.0 → sbxloop_worker-0.4.1}/src/sbxloop_worker/backends/__init__.py +0 -0
- {sbxloop_worker-0.3.0 → sbxloop_worker-0.4.1}/src/sbxloop_worker/backends/echo.py +0 -0
- {sbxloop_worker-0.3.0 → sbxloop_worker-0.4.1}/src/sbxloop_worker/events.py +0 -0
- {sbxloop_worker-0.3.0 → sbxloop_worker-0.4.1}/src/sbxloop_worker/githubops.py +0 -0
- {sbxloop_worker-0.3.0 → sbxloop_worker-0.4.1}/src/sbxloop_worker/protocol.py +0 -0
- {sbxloop_worker-0.3.0 → sbxloop_worker-0.4.1}/src/sbxloop_worker/py.typed +0 -0
- {sbxloop_worker-0.3.0 → sbxloop_worker-0.4.1}/src/sbxloop_worker/runner.py +0 -0
- {sbxloop_worker-0.3.0 → sbxloop_worker-0.4.1}/tests/conftest.py +0 -0
- {sbxloop_worker-0.3.0 → sbxloop_worker-0.4.1}/tests/test_githubops.py +0 -0
- {sbxloop_worker-0.3.0 → sbxloop_worker-0.4.1}/tests/test_json_extract.py +0 -0
- {sbxloop_worker-0.3.0 → sbxloop_worker-0.4.1}/tests/test_protocol.py +0 -0
- {sbxloop_worker-0.3.0 → sbxloop_worker-0.4.1}/tests/test_runner_unit.py +0 -0
- {sbxloop_worker-0.3.0 → sbxloop_worker-0.4.1}/tests/test_worker_contract.py +0 -0
- {sbxloop_worker-0.3.0 → sbxloop_worker-0.4.1}/tests/worker_harness.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sbxloop-worker
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.4.1
|
|
4
4
|
Summary: In-sandbox worker runtime for sbxloop (protocol models, agent backends, job runner)
|
|
5
5
|
Project-URL: Homepage, https://github.com/brettbergin/sbxloop
|
|
6
6
|
Project-URL: Repository, https://github.com/brettbergin/sbxloop
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "sbxloop-worker"
|
|
3
|
-
|
|
3
|
+
dynamic = ["version"] # derived from git tags by hatch-vcs (see [tool.hatch.version])
|
|
4
4
|
description = "In-sandbox worker runtime for sbxloop (protocol models, agent backends, job runner)"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
requires-python = ">=3.11"
|
|
@@ -25,8 +25,20 @@ Homepage = "https://github.com/brettbergin/sbxloop"
|
|
|
25
25
|
Repository = "https://github.com/brettbergin/sbxloop"
|
|
26
26
|
|
|
27
27
|
[build-system]
|
|
28
|
-
requires = ["hatchling>=1.27"]
|
|
28
|
+
requires = ["hatchling>=1.27", "hatch-vcs"]
|
|
29
29
|
build-backend = "hatchling.build"
|
|
30
30
|
|
|
31
|
+
# Both workspace packages version from the same repo-root git tag, keeping the
|
|
32
|
+
# lockstep invariant by construction. `fallback_root` lets a wheel built from
|
|
33
|
+
# an extracted sdist (no git) pick the version up from the sdist's PKG-INFO.
|
|
34
|
+
[tool.hatch.version]
|
|
35
|
+
source = "vcs"
|
|
36
|
+
raw-options = { root = "../..", fallback_root = ".", local_scheme = "no-local-version", fallback_version = "0.0.0" }
|
|
37
|
+
|
|
38
|
+
# Write the resolved version into the package so `sbxloop_worker.__version__`
|
|
39
|
+
# reports it at runtime (inside the sandbox, where dist metadata may be absent).
|
|
40
|
+
[tool.hatch.build.hooks.vcs]
|
|
41
|
+
version-file = "src/sbxloop_worker/_version.py"
|
|
42
|
+
|
|
31
43
|
[tool.hatch.build.targets.wheel]
|
|
32
44
|
packages = ["src/sbxloop_worker"]
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
"""sbxloop-worker — the in-sandbox runtime for sbxloop.
|
|
2
|
+
|
|
3
|
+
Runs inside a Docker Sandbox microVM. Hosts the shared host/worker protocol
|
|
4
|
+
models, the agent backends (GitHub Copilot SDK), and the job runner invoked
|
|
5
|
+
via ``python -m sbxloop_worker``.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
try:
|
|
9
|
+
# written at build time by hatch-vcs (see pyproject [tool.hatch.build.hooks.vcs])
|
|
10
|
+
from sbxloop_worker._version import __version__
|
|
11
|
+
except ImportError: # pragma: no cover - raw source tree that was never built
|
|
12
|
+
try:
|
|
13
|
+
from importlib.metadata import version as _pkg_version
|
|
14
|
+
|
|
15
|
+
__version__ = _pkg_version("sbxloop-worker")
|
|
16
|
+
except Exception:
|
|
17
|
+
__version__ = "0.0.0"
|
|
18
|
+
|
|
19
|
+
__all__ = ["__version__"]
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# file generated by vcs-versioning
|
|
2
|
+
# don't change, don't track in version control
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
__all__ = [
|
|
6
|
+
"__version__",
|
|
7
|
+
"__version_tuple__",
|
|
8
|
+
"version",
|
|
9
|
+
"version_tuple",
|
|
10
|
+
"__commit_id__",
|
|
11
|
+
"commit_id",
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
version: str
|
|
15
|
+
__version__: str
|
|
16
|
+
__version_tuple__: tuple[int | str, ...]
|
|
17
|
+
version_tuple: tuple[int | str, ...]
|
|
18
|
+
commit_id: str | None
|
|
19
|
+
__commit_id__: str | None
|
|
20
|
+
|
|
21
|
+
__version__ = version = '0.4.1'
|
|
22
|
+
__version_tuple__ = version_tuple = (0, 4, 1)
|
|
23
|
+
|
|
24
|
+
__commit_id__ = commit_id = None
|
|
@@ -17,6 +17,7 @@ from unit coverage accordingly.
|
|
|
17
17
|
from __future__ import annotations
|
|
18
18
|
|
|
19
19
|
import asyncio
|
|
20
|
+
import json
|
|
20
21
|
import os
|
|
21
22
|
from typing import Any
|
|
22
23
|
|
|
@@ -52,6 +53,59 @@ def _auth_diagnostic() -> str:
|
|
|
52
53
|
)
|
|
53
54
|
|
|
54
55
|
|
|
56
|
+
# Transcript-facing clips: the event stream is telemetry, not the artifact
|
|
57
|
+
# channel, so payloads are bounded aggressively.
|
|
58
|
+
TOOL_ARGS_CLIP = 400
|
|
59
|
+
TOOL_OUTPUT_CLIP = 1_000
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _tool_args(arguments: Any) -> str | None:
|
|
63
|
+
"""The tool's arguments as one displayable string (best-effort).
|
|
64
|
+
|
|
65
|
+
``ToolExecutionStartData.arguments`` is typed ``Any`` by the SDK: shell
|
|
66
|
+
tools carry ``{"command": ...}``-shaped dicts, others arbitrary JSON.
|
|
67
|
+
Prefer the human-relevant fields, fall back to compact JSON.
|
|
68
|
+
"""
|
|
69
|
+
if arguments is None:
|
|
70
|
+
return None
|
|
71
|
+
if isinstance(arguments, dict):
|
|
72
|
+
for key in ("command", "cmd", "input", "query", "path"):
|
|
73
|
+
value = arguments.get(key)
|
|
74
|
+
if isinstance(value, str) and value.strip():
|
|
75
|
+
return value[:TOOL_ARGS_CLIP]
|
|
76
|
+
try:
|
|
77
|
+
return json.dumps(arguments, separators=(",", ":"))[:TOOL_ARGS_CLIP]
|
|
78
|
+
except (TypeError, ValueError):
|
|
79
|
+
return str(arguments)[:TOOL_ARGS_CLIP]
|
|
80
|
+
text = str(arguments)
|
|
81
|
+
return text[:TOOL_ARGS_CLIP] if text.strip() else None
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def _tool_exit_code(data: Any) -> int | None:
|
|
85
|
+
"""Shell exit code from a ToolExecutionComplete, when present.
|
|
86
|
+
|
|
87
|
+
Shell completions carry a ShellExit entry in ``result.contents``
|
|
88
|
+
(verified against github-copilot-sdk: ``exit_code: int``).
|
|
89
|
+
"""
|
|
90
|
+
result = getattr(data, "result", None)
|
|
91
|
+
for entry in getattr(result, "contents", None) or []:
|
|
92
|
+
code = getattr(entry, "exit_code", None)
|
|
93
|
+
if isinstance(code, int):
|
|
94
|
+
return code
|
|
95
|
+
return None
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
def _tool_output(data: Any) -> str | None:
|
|
99
|
+
"""A bounded tail of the tool's output, for transcript display."""
|
|
100
|
+
result = getattr(data, "result", None)
|
|
101
|
+
content = getattr(result, "content", None)
|
|
102
|
+
if not content and result is not None:
|
|
103
|
+
content = getattr(result, "detailed_content", None)
|
|
104
|
+
if not isinstance(content, str) or not content.strip():
|
|
105
|
+
return None
|
|
106
|
+
return content[-TOOL_OUTPUT_CLIP:]
|
|
107
|
+
|
|
108
|
+
|
|
55
109
|
class CopilotBackend:
|
|
56
110
|
name = "copilot"
|
|
57
111
|
|
|
@@ -75,6 +129,9 @@ class CopilotBackend:
|
|
|
75
129
|
|
|
76
130
|
usage = Usage()
|
|
77
131
|
final_text: list[str] = []
|
|
132
|
+
# tool_call_id -> tool name, so completion events can name the tool
|
|
133
|
+
# (the SDK's Complete event carries only the call id).
|
|
134
|
+
tool_names: dict[str, str] = {}
|
|
78
135
|
|
|
79
136
|
def on_event(event: Any) -> None:
|
|
80
137
|
nonlocal usage
|
|
@@ -91,18 +148,25 @@ class CopilotBackend:
|
|
|
91
148
|
final_text.append(content)
|
|
92
149
|
emit(EventTypes.AGENT_MESSAGE, content=content)
|
|
93
150
|
elif type_name.startswith("ToolExecutionStart"):
|
|
151
|
+
tool = getattr(data, "tool_name", None) or getattr(data, "toolName", None)
|
|
152
|
+
call_id = getattr(data, "tool_call_id", None) or getattr(data, "toolCallId", None)
|
|
153
|
+
if tool and call_id:
|
|
154
|
+
tool_names[str(call_id)] = str(tool)
|
|
94
155
|
emit(
|
|
95
156
|
EventTypes.AGENT_TOOL_START,
|
|
96
|
-
tool=
|
|
97
|
-
tool_call_id=
|
|
98
|
-
|
|
157
|
+
tool=tool,
|
|
158
|
+
tool_call_id=call_id,
|
|
159
|
+
args=_tool_args(getattr(data, "arguments", None)),
|
|
99
160
|
)
|
|
100
161
|
elif type_name.startswith("ToolExecutionComplete"):
|
|
162
|
+
call_id = getattr(data, "tool_call_id", None) or getattr(data, "toolCallId", None)
|
|
101
163
|
emit(
|
|
102
164
|
EventTypes.AGENT_TOOL_END,
|
|
103
|
-
tool_call_id=
|
|
104
|
-
|
|
165
|
+
tool_call_id=call_id,
|
|
166
|
+
tool=tool_names.get(str(call_id)),
|
|
105
167
|
success=getattr(data, "success", None),
|
|
168
|
+
exit_code=_tool_exit_code(data),
|
|
169
|
+
output=_tool_output(data),
|
|
106
170
|
)
|
|
107
171
|
elif type_name == "AssistantUsageData":
|
|
108
172
|
sample = Usage(
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
"""sbxloop-worker — the in-sandbox runtime for sbxloop.
|
|
2
|
-
|
|
3
|
-
Runs inside a Docker Sandbox microVM. Hosts the shared host/worker protocol
|
|
4
|
-
models, the agent backends (GitHub Copilot SDK), and the job runner invoked
|
|
5
|
-
via ``python -m sbxloop_worker``.
|
|
6
|
-
"""
|
|
7
|
-
|
|
8
|
-
__version__ = "0.3.0"
|
|
9
|
-
|
|
10
|
-
__all__ = ["__version__"]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|