Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions opencode-sms-bridge/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -576,7 +576,7 @@ def _request(
raise BridgeError("OpenCode response was invalid", ERROR_OPENCODE_RESPONSE_INVALID) from error

def create_session(self) -> str:
response = self._request("/api/session", {}, operation=OPENCODE_OPERATION_SESSION_CREATE)
response = self._request("/session", {}, operation=OPENCODE_OPERATION_SESSION_CREATE)
session_id = response.get("id") if isinstance(response, dict) else None
if not isinstance(session_id, str) or not session_id:
raise BridgeError("OpenCode session response was invalid", ERROR_OPENCODE_RESPONSE_INVALID)
Expand All @@ -589,7 +589,7 @@ def prompt(self, session_id: str, agent: str, parts: list[dict[str, str]]) -> st
if not text:
raise BridgeError("OpenCode prompt has no text", ERROR_OPENCODE_INPUT_INVALID)
response = self._request(
f"/api/session/{session_id}/message",
f"/session/{session_id}/message",
{"agent": agent, "parts": [{"type": "text", "text": text}]},
operation=OPENCODE_OPERATION_PROMPT,
)
Expand Down
24 changes: 13 additions & 11 deletions opencode-sms-bridge/test_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -162,8 +162,8 @@ def test_documented_flow_uses_exact_routes_methods_and_bodies(self):
self.assertEqual(
[request.full_url for request in requests],
[
"https://opencode.example.invalid/api/session",
"https://opencode.example.invalid/api/session/ses_new/message",
"https://opencode.example.invalid/session",
"https://opencode.example.invalid/session/ses_new/message",
],
)
self.assertEqual(json.loads(requests[0].data.decode()), {})
Expand All @@ -172,14 +172,14 @@ def test_documented_flow_uses_exact_routes_methods_and_bodies(self):
{"agent": "homesteader", "parts": [{"type": "text", "text": "hi"}]},
)
for request in requests:
for unsupported in ("/prompt", "prompt_async", "/wait"):
for unsupported in ("/api", "/prompt", "prompt_async", "/wait"):
self.assertNotIn(unsupported, request.full_url)

def test_session_create_sends_only_documented_fields(self):
client = OpenCodeClient(self.settings)
with patch.object(client, "_request", return_value={"id": "ses_123"}) as request:
self.assertEqual(client.create_session(), "ses_123")
request.assert_called_once_with("/api/session", {}, operation=OPENCODE_OPERATION_SESSION_CREATE)
request.assert_called_once_with("/session", {}, operation=OPENCODE_OPERATION_SESSION_CREATE)

def test_session_create_rejects_invalid_response(self):
client = OpenCodeClient(self.settings)
Expand All @@ -201,13 +201,15 @@ def test_prompt_makes_single_blocking_message_request(self):
)
self.assertEqual(request.call_count, 1)
request.assert_called_once_with(
"/api/session/ses_123/message",
"/session/ses_123/message",
{"agent": "lawnmowerman", "parts": [{"type": "text", "text": "hello"}]},
operation=OPENCODE_OPERATION_PROMPT,
)
for invoked in request.call_args_list:
path = invoked.args[0]
self.assertNotIn("/api", path)
self.assertNotIn("/prompt", path)
self.assertNotIn("prompt_async", path)
self.assertNotIn("/wait", path)

def test_prompt_joins_text_parts_into_one_documented_text_part(self):
Expand All @@ -220,7 +222,7 @@ def test_prompt_joins_text_parts_into_one_documented_text_part(self):
[{"type": "text", "text": "line one"}, {"type": "text", "text": "line two"}],
)
request.assert_called_once_with(
"/api/session/ses_123/message",
"/session/ses_123/message",
{"agent": "grillmaster", "parts": [{"type": "text", "text": "line one\nline two"}]},
operation=OPENCODE_OPERATION_PROMPT,
)
Expand Down Expand Up @@ -284,11 +286,11 @@ def test_opencode_request_failures_map_to_static_operation_and_category(self):
(URLError("unknown url type"), "url-configuration"),
(ValueError("malformed url detail"), "url-configuration"),
(OSError("socket detail"), "os"),
(HTTPError("https://opencode.example.invalid/api/session", 404, "client detail", None, None), "http-4xx"),
(HTTPError("https://opencode.example.invalid/api/session", 429, "rate detail", None, None), "http-4xx"),
(HTTPError("https://opencode.example.invalid/api/session", 500, "server detail", None, None), "http-5xx"),
(HTTPError("https://opencode.example.invalid/api/session", 503, "unavailable detail", None, None), "http-5xx"),
(HTTPError("https://opencode.example.invalid/api/session", 302, "redirect detail", None, None), "unknown"),
(HTTPError("https://opencode.example.invalid/session", 404, "client detail", None, None), "http-4xx"),
(HTTPError("https://opencode.example.invalid/session", 429, "rate detail", None, None), "http-4xx"),
(HTTPError("https://opencode.example.invalid/session", 500, "server detail", None, None), "http-5xx"),
(HTTPError("https://opencode.example.invalid/session", 503, "unavailable detail", None, None), "http-5xx"),
(HTTPError("https://opencode.example.invalid/session", 302, "redirect detail", None, None), "unknown"),
)
for failure, category in failures:
with self.subTest(failure=type(failure).__name__):
Expand Down
Loading