fix(sms-bridge): use documented v1.18.23 message contract - #40
Merged
Conversation
OpenCode v1.18.23 (tag ef2880f379129aa048be9e9353e30aa168d42c17)
does not document POST /session/:id/prompt: the documented blocking
send is POST /session/:id/message with body
{ messageID?, model?, agent?, noReply?, system?, tools?, parts }
returning { info, parts }, while prompt_async is the 204 async
variant. The route group confirms session.prompt is mounted at
/session/:sessionID/message.
Replace the unsupported flow: session creation now sends only the
documented create fields (empty body; agent removed), the routing
agent moves onto the blocking message request, the request carries
a text part, and the response is parsed strictly from the top-level
{ info, parts } shape. Bounded PII-safe static error codes and the
no-raw-logging posture are unchanged.
Tests prove exact request method/path/body for both requests,
agent placement, absence of /prompt, /wait, and prompt_async routes,
single-part text joining, strict response parsing with invalid
shapes rejected, and the unchanged bounded taxonomy.
Image CI passedPre-commit validation passed. View the workflow run. |
14 tasks
xnoto
added a commit
to makeitworkcloud/kustomize-cluster
that referenced
this pull request
Sep 5, 2026
## Summary Select `ghcr.io/makeitworkcloud/opencode-sms-bridge:6b48ddeaa5897a3d07dc28aa929a941219ec8993`, the immutable image published by the merged [images PR #40](makeitworkcloud/images#40). It replaces the currently selected `008a074f…` image, whose unsupported `/prompt` contract produced `opencode-response-invalid` in the approved-source runtime test. **Verified producer evidence:** the producer's post-merge build-and-push [run 33974862106](https://github.com/makeitworkcloud/images/actions/runs/33974862106) passed and pushed the selected immutable tag (digest `sha256:a54775a5216a5307064e9e221b866f5dfcf1054e2470c2402d3601a290bc2343`). The selected repair uses OpenCode v1.18.23's documented blocking `POST /session/:id/message` contract, creates sessions with documented fields only, and sends the routing agent plus text part in the message request. This PR changes only the immutable image pin in the `opencode-sms-bridge` Application. Fixes # None — owner-authorized remediation rollout; no driving issue supplied. ## Type of change - [x] Bug fix - [ ] Feature / enhancement - [ ] Documentation - [ ] Infrastructure (OpenTofu root or module) - [x] GitOps desired state (manifests, kustomize, charts, SOPS/KSOPS secrets) - [ ] Container image - [ ] CI / reusable workflow - [ ] Refactor / cleanup - [ ] Breaking change ## Validation - [ ] Required pull-request checks pass — pending. The only validation authority is this repository's PR CI. - [x] Generated or centrally distributed files were regenerated by their owning automation, not hand-edited — none apply; this is a one-line image-pin change. No local OpenTofu, SOPS, container build, cluster, or live-system operation was run or claimed. ## Impact and rollout **Producer:** `makeitworkcloud/images` merged `6b48ddeaa5897a3d07dc28aa929a941219ec8993` and published the selected immutable bridge image. The producer build is complete. **Consumer:** `workloads/apps/opencode-sms-bridge-app.yaml` in this repository is the canonical GitOps image-selection point for the `opencode-sms-bridge` Application. This PR changes no chart version, configuration, Secret, Service, route, or Argo sync policy. **Delivery stages:** authored and producer-published; GitOps selection is proposed by this PR; PR validation is pending; merge, root-sync submission, reconciliation, health, and functional SMS verification remain incomplete. A merge triggers `test` on `main`; only after success does the automatic `sync.yml` request root reconciliation. It does not prove root/child health. After an explicitly authorized merge, verify `gitops-workloads`, the child Application, the selected Pod image, resource health, and one approved-source text-only SMS exchange separately. **Rollback:** use a reviewed GitOps PR to restore the previously selected immutable tag `008a074f5d0bc75f0120c8b6b2d2ca468d4e2133`; do not retag images or patch live resources. ## Safety and secrets - [x] Contains no plaintext secrets, decrypted SOPS values, state files, kubeconfigs, tokens, or private endpoints - [x] No local OpenTofu init/plan/apply/destroy/import/state operations were run or claimed — plans come from pull-request checks - [x] Breaking or irreversible effects are described above with rollback notes AI-assisted change: an OpenCode agent materially produced this change; review the producer tag and CI, the one-line diff, and the automatic post-merge reconciliation behavior before merge.
xnoto
added a commit
that referenced
this pull request
Sep 5, 2026
PR #40 kept the documented v1 body and strict direct {info,parts} parsing but left the requests on the legacy V2 /api surface. Upstream v1.18.23 (ef2880f379129aa048be9e9353e30aa168d42c17) mounts the session HttpApi at root "/session": create = POST /session (empty body, direct Session.Info) and blocking prompt = POST /session/:sessionID/message (direct streamed SessionV1.WithParts). /api/session* is the distinct legacy V2 API (data-wrapped prompt admission, GET message listing, no /wait), so the strict direct-shape parser failed the live approved-source test with opencode-response-invalid. Switch only the route prefix in opencode-sms-bridge/server.py: POST /session with the documented empty body and POST /session/{id}/message with message-level agent + text parts. Response parsing, request bodies, and the bounded static error-code taxonomy are unchanged. Tests pin the exact /session prefix, methods, and bodies at the opener level and reject every /api route, /prompt, /wait, and prompt_async.
14 tasks
xnoto
added a commit
that referenced
this pull request
Sep 5, 2026
## Summary The live approved-source SMS test against image `6b48dde` reached `inbound_queued`/`job_claimed` and then failed `opencode-response-invalid`. Root cause: PR #40 adopted the documented v1 body and strict direct `{info,parts}` parsing but left the requests on the legacy V2 `/api` surface — an exact prefix/API mismatch. Authoritative upstream evidence at `anomalyco/opencode` v1.18.23 commit `ef2880f379129aa048be9e9353e30aa168d42c17`: - `packages/opencode/src/server/routes/instance/httpapi/groups/session.ts`: `const root = "/session"`; `SessionPaths.create = "/session"`, `SessionPaths.prompt = "/session/:sessionID/message"`. - `packages/opencode/src/server/routes/instance/httpapi/handlers/session.ts`: `create` returns the direct `Session.Info` (empty body accepted); `prompt` streams the direct `SessionV1.WithParts` `{info,parts}` JSON — neither is data-wrapped. - `packages/opencode/test/server/httpapi-session.test.ts`: proves the legacy V2 `/api/session/:id/prompt` admission response is data-wrapped, GET `/api/session/:id/message` is the V2 message listing, and `/api/session/:id/wait` is unavailable — `/api` and `/session` are distinct APIs, so the strict direct-shape parser correctly rejected the V2 response. Changes, confined to `opencode-sms-bridge/server.py` and `opencode-sms-bridge/test_server.py`: - Session creation: `POST /session` (was `POST /api/session`) with the documented empty body; id still read from the direct `Session.Info`. - Blocking send: `POST /session/{id}/message` (was `/api/session/{id}/message`) with message-level `agent` + single text part; response still parsed strictly as direct `{info,parts}`. - PII-safe bounded static error-code taxonomy unchanged. - Tests pin the exact `/session` prefix/method/body at the opener level with real request objects and reject every `/api` route, `/prompt`, `/wait`, and `prompt_async`. Fixes # None — owner-authorized evidence-based repair to the v1 route prefix; no driving issue supplied. Note: this repository has no pull-request template in `.github/`, the root, or `docs/`; the `makeitworkcloud/.github` organization default template is applied manually here. ## Type of change - [x] Bug fix - [ ] Feature / enhancement - [ ] Documentation - [ ] Infrastructure (OpenTofu root or module) - [ ] GitOps desired state (manifests, kustomize, charts, SOPS/KSOPS secrets) - [x] Container image - [ ] CI / reusable workflow - [ ] Refactor / cleanup - [ ] Breaking change ## Validation - [x] Required pull-request checks pass — buildah run [33975811487](https://github.com/makeitworkcloud/images/actions/runs/33975811487) (jobs [checks](https://github.com/makeitworkcloud/images/actions/runs/33975811487/job/101332181039) / [detect](https://github.com/makeitworkcloud/images/actions/runs/33975811487/job/101332180972) / [build & push](https://github.com/makeitworkcloud/images/actions/runs/33975811487/job/101332218007)) passed pre-commit (including Gitleaks), changed-image detection (`opencode-sms-bridge`), and the non-publishing bridge image build. The build's Containerfile step `RUN python3 -m unittest discover -s /app -p "test_*.py" -v` ran all 21 tests (`Ran 21 tests in 0.100s — OK`), including the exact `/session` route/method/body flow test, the documented-fields-only session-create test, the single blocking message-request test, the `/api`-route rejection assertions, and the strict `{info,parts}` extraction and invalid-shape rejection tests. `Push to registry` was correctly skipped in PR mode. - [x] Generated or centrally distributed files were regenerated by their owning automation, not hand-edited — none changed; only `opencode-sms-bridge/server.py` and `opencode-sms-bridge/test_server.py` were edited. No local tests, container builds, OpenTofu, SOPS, state, or live-system operations were run or claimed. CI is the validation authority. ## Impact and rollout **Producer changed:** `makeitworkcloud/images/opencode-sms-bridge` is the canonical bridge-image source. An approved merge automatically publishes a new immutable GHCR image tag; this PR neither publishes nor deploys anything itself. **Consumer unchanged:** `kustomize-cluster` continues to select its currently pinned image; this PR makes no GitOps or image-selection change. After an approved merge and publication, a separate reviewed GitOps PR and explicit confirmation are required before image selection, Argo reconciliation, health verification, and a new approved-source SMS test. **Behavior boundary:** a text job now issues `POST /session` with an empty body and `POST /session/{id}/message` with the routing agent and a text part, instead of the same documented bodies on the legacy V2 `/api/session...` prefix. Persisted detail codes are unchanged in literal value (`opencode-request-failed:<session-create|prompt>:<category>`, `opencode-response-invalid`, etc.). Direct V1 shapes parse as before; legacy `data`-wrapped envelopes remain rejected. **Rollback:** if a later selected image regresses, use the canonical GitOps workflow to select a reviewed immutable image tag. Do not overwrite image tags or alter live state manually. ## Safety and secrets - [x] Contains no plaintext secrets, decrypted SOPS values, state files, kubeconfigs, tokens, or private endpoints. - [x] No local OpenTofu init/plan/apply/destroy/import/state operations were run or claimed — plans come from pull-request checks. - [x] Breaking or irreversible effects are described above with rollback notes. AI-assisted change: an OpenCode agent materially produced this change; reviewers should verify the cited v1.18.23 upstream evidence (the `/session` root with `create = /session` and `prompt = /session/:sessionID/message`, direct `Session.Info`/`SessionV1.WithParts` responses, and the distinct legacy V2 `/api` surface), the strict response parsing and its invalid-shape rejection, the unchanged bounded taxonomy, and CI results before merge.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
OpenCode v1.18.23 — the deployed upstream, tag commit
ef2880f379129aa048be9e9353e30aa168d42c17— does not documentPOST /session/:id/prompt. The documented surface (verified inpackages/web/src/content/docs/server.mdx, the route grouppackages/opencode/src/server/routes/instance/httpapi/groups/session.tswhere
SessionPaths.prompt = "/session/:sessionID/message", andPromptInputinpackages/opencode/src/session/prompt.ts) is:POST /session/:id/message— blocking send; body{ messageID?, model?, agent?, noReply?, system?, tools?, parts };returns
{ info: Message, parts: Part[] }POST /session/:id/prompt_async— async, returns204 No ContentPOST /session— create; documented body{ parentID?, title? }only; returns
SessionChanges, confined to
opencode-sms-bridge/server.pyandopencode-sms-bridge/test_server.py:The previously sent undocumented
agentfield is removed, and thesession id is read from the directly returned
Sessionobject.request as the documented top-level
agentbody field.partscontaining text — inboundtext parts are joined into a single
{"type": "text", "text": ...}part, preserving existing join semantics and the empty-text guard.
{ info, parts }shape:infomust be an object,partsa list;only
textparts contribute to the reply; any other shape (includinglegacy
data-wrapped shapes) fails safely.(
ok,opencode-response-invalid,opencode-input-invalid,twilio-send-failed,opencode-request-failed:<operation>:<category>with operations
session-create/prompt), and no raw responsedata, URLs, sessions, agents, or provider detail are logged or
persisted.
session-create and blocking message requests (opener-level, real
request objects); agent placement on the message request and its
absence from session create; no
/prompt,/wait, orprompt_asyncroutes are ever requested; single-request blocking behavior; strict
{ info, parts }extraction with non-text parts ignored and invalidshapes (lists, strings, empty,
data-wrapped, wrong types,text-less) rejected with
opencode-response-invalid; and theunchanged bounded taxonomy (no
wait,message-list,prompt-async, ormessageoperation codes).Fixes #
None — owner-authorized evidence-based repair to the documented v1
message contract; no driving issue supplied.
Note: this repository has no pull-request template in
.github/, theroot, or
docs/; themakeitworkcloud/.githuborganization defaulttemplate is applied manually here.
Type of change
Validation
buildahrun33974511866
(jobs
checks
/
detect
/
build)
passed pre-commit (including Gitleaks), changed-image detection
(
opencode-sms-bridge), and the non-publishing bridge image build. Thebuild's Containerfile step
RUN python3 -m unittest discover -s /app -p "test_*.py" -vran all 21 tests (Ran 21 tests in 0.105s — OK),including the exact-route/method/body flow test, the
documented-fields-only session-create test, the blocking-message
request test, the strict
{info,parts}extraction andinvalid-shape rejection tests, and the bounded-taxonomy test.
Push to registrywas correctly skipped in PR mode.opencode-sms-bridge/server.pyandopencode-sms-bridge/test_server.pywere edited.No local tests, container builds, OpenTofu, SOPS, state, or live-system
operations were run or claimed. CI is the validation authority.
Impact and rollout
Producer changed:
makeitworkcloud/images/opencode-sms-bridgeisthe canonical bridge-image source. An approved merge automatically
publishes a new immutable GHCR image tag. This PR neither publishes nor
deploys anything itself.
Consumer unchanged:
kustomize-clustercontinues to select itscurrently pinned image; this PR makes no GitOps or image-selection
change. After an approved merge and publication, a separate reviewed
GitOps PR and explicit confirmation are required before image selection,
Argo reconciliation, health verification, and a new approved-source SMS
test.
Behavior boundary: a text job now issues
POST /api/sessionwithan empty body on first contact (agent no longer sent there) and
POST /api/session/{id}/messagewith the routing agent and a text part,instead of the undocumented
POST /api/session/{id}/promptwith a{"prompt": {"text": ...}}body. Persisted detail codes are unchangedin literal value: request failures still compose as
opencode-request-failed:<session-create|prompt>:<category>andunusable results still fail with
opencode-response-invalid. Responseswrapped in a legacy
dataenvelope are now rejected instead oftolerated.
Rollback: if a later selected image regresses, use the canonical
GitOps workflow to select a reviewed immutable image tag. Do not
overwrite image tags or alter live state manually.
Safety and secrets
AI-assisted change: an OpenCode agent materially produced this change;
reviewers should verify the cited v1.18.23 upstream evidence (blocking
/session/:id/messagebody and{ info, parts }response,prompt_asyncas the only async variant,/promptundocumented), thestrict response parsing and its invalid-shape rejection, agent
placement, the unchanged bounded taxonomy, and CI results before merge.