Skip to content

[codex] Refactor engine route response helpers#207

Merged
willwashburn merged 4 commits into
mainfrom
codex/route-response-helpers
Jun 23, 2026
Merged

[codex] Refactor engine route response helpers#207
willwashburn merged 4 commits into
mainfrom
codex/route-response-helpers

Conversation

@willwashburn

@willwashburn willwashburn commented Jun 23, 2026

Copy link
Copy Markdown
Member

What changed

This refactors a slice of the engine route layer around HTTP response envelopes and JSON body parsing.

  • Added shared response helpers for success, created, no-content, invalid request, not found, malformed JSON, and zod-backed JSON body parsing.
  • Reused the helpers in node, trigger, system prompt, event subscription, and receipt routes.
  • Preserved custom validation messages for event subscriptions by allowing parser callers to derive the invalid-request message from schema issues.
  • Added conformance coverage for malformed JSON handling and custom validation message preservation.

Why

Route modules were repeatedly hand-rendering the same { ok: true, data } and { ok: false, error } envelopes and each try/catch could decide malformed JSON behavior independently. Centralizing the common response paths gives the engine one pattern for new routes while preserving the existing snake_case wire contract and route-specific validation semantics.

Validation

  • git diff --check
  • npm --workspace @relaycast/engine run typecheck
  • npm --workspace @relaycast/engine run lint
  • npm --workspace @relaycast/engine test -- src/__tests__/conformance/httpResponse.test.ts
  • npm --workspace @relaycast/engine test -- src/__tests__/conformance/httpResponse.test.ts src/__tests__/conformance/sdk-contract.test.ts
  • npm --workspace @relaycast/engine test
  • npm --workspace @relaycast/engine run build
  • Live built-server HTTP exercise on 127.0.0.1:18788 for workspace/agent creation, malformed JSON, trigger create/list.
  • Live built-server HTTP exercise on 127.0.0.1:18789 for system prompt, subscription validation/create/list/get/delete, and read receipt flows.

External codex review --uncommitted was attempted after user approval, but tenant policy still rejected uploading uncommitted private repository contents. I used the local automated review gate above as the safer substitute and recorded that in /tmp/refactor-relaycast.md.

Review in cubic

@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@willwashburn, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 27 minutes and 55 seconds. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan refill rate.

For paid Pro and Pro+ PR reviews, CodeRabbit uses rolling per-developer review limits. Reviews become available again as older review attempts age out of the rolling limit window.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 6152d8e2-1424-4b5e-b607-9d4d00596894

📥 Commits

Reviewing files that changed from the base of the PR and between 28f111c and 8dd4e79.

📒 Files selected for processing (4)
  • packages/engine/src/lib/__tests__/httpError.test.ts
  • packages/engine/src/lib/httpError.ts
  • packages/engine/src/lib/httpResponse.ts
  • packages/engine/src/routes/eventSubscription.ts
📝 Walkthrough

Walkthrough

A new httpResponse.ts utility module is introduced with typed helpers for success, error, not-found, and no-content HTTP responses, plus a parseJsonBody function that handles JSON parse errors and Zod schema validation. All five route modules (trigger, eventSubscription, node, receipt, systemPrompt) are migrated from inline response construction to these helpers. httpError.ts is updated to delegate JSON-error cases to the new helpers. A conformance test suite validates the parser's invalid_json and invalid_request response shapes.

Changes

HTTP Response Standardization

Layer / File(s) Summary
httpResponse.ts: types, helpers, and parseJsonBody
packages/engine/src/lib/httpResponse.ts
Defines internal parsing/validation types and exports jsonOk, jsonCreated, jsonNoContent, jsonError, jsonInvalidRequest, jsonNotFound, jsonMalformedBody, and parseJsonBody with JSON-error and schema-validation branching.
httpError.ts: delegate JSON errors to new helpers
packages/engine/src/lib/httpError.ts
Imports jsonError and jsonMalformedBody; updates errorResponse to branch on "JSON" in error.message and return jsonMalformedBody(c) or jsonError(...) accordingly.
Route handler migrations
packages/engine/src/routes/trigger.ts, packages/engine/src/routes/eventSubscription.ts, packages/engine/src/routes/node.ts, packages/engine/src/routes/receipt.ts, packages/engine/src/routes/systemPrompt.ts
Replaces inline c.json(...), c.body(null, 204), and manual safeParse calls with parseJsonBody, jsonCreated, jsonOk, jsonNotFound, jsonNoContent, and jsonInvalidRequest across all five route modules.
Conformance tests for shared parser
packages/engine/src/__tests__/conformance/httpResponse.test.ts
Adds a Vitest suite verifying invalid_json 400 responses for malformed JSON on /v1/triggers, /v1/channels, and /v1/subscriptions, and an invalid_request response for a missing required field on /v1/subscriptions.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐇 Hop, hop, helpers arrive today,
No more c.json the manual way!
jsonOk, jsonNotFound, all in a row,
Malformed JSON caught before it can grow.
The rabbit stamps each route with care —
Tidy responses everywhere! 🎉

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title '[codex] Refactor engine route response helpers' directly and clearly summarizes the main change: refactoring HTTP response helpers in engine routes.
Description check ✅ Passed The description is directly related to the changeset, explaining what changed (shared response helpers), why (eliminating duplication), and validation performed.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/route-response-helpers

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a set of standardized HTTP response and request body parsing helpers in httpResponse.ts and refactors multiple route handlers to use them, improving consistency and reducing boilerplate. It also adds conformance tests for these helpers. The feedback points out that the broad check for 'JSON' in the error handler in httpError.ts could lead to false positives for non-syntax errors (such as database errors involving JSON columns) and suggests restricting the check to SyntaxError instances.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment thread packages/engine/src/lib/httpError.ts Outdated
Comment on lines +47 to +49
if (error.message?.includes('JSON')) {
return jsonMalformedBody(c);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

Checking error.message?.includes('JSON') is too broad and can lead to false positives. For example, if a database query fails on a JSON column or an internal library throws an error containing the word "JSON", it will be incorrectly treated as a 400 Bad Request with a "Malformed JSON in request body" message instead of a 500 Internal Server Error.

To prevent this, restrict the check to SyntaxError instances (which are thrown by JSON.parse).

Suggested change
if (error.message?.includes('JSON')) {
return jsonMalformedBody(c);
}
if (error instanceof SyntaxError && error.message?.includes('JSON')) {
return jsonMalformedBody(c);
}

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 2a98936 by restricting malformed-body mapping to SyntaxError instances. Added packages/engine/src/lib/tests/httpError.test.ts to prove SyntaxError still maps to invalid_json and coded errors mentioning JSON keep their original route_not_found/404 response.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 28f111cab2

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread packages/engine/src/lib/httpError.ts Outdated
Comment on lines +47 to +48
if (error.message?.includes('JSON')) {
return jsonMalformedBody(c);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve coded errors that mention JSON

This string check treats any thrown error whose message contains uppercase JSON as malformed request JSON, regardless of where it came from. For example, a valid POST /v1/route body with a missing skill named JSON reaches routingEngine.routeBySkill, which throws route_not_found/404 with No active agents found for skill "JSON"; routes/routing.ts then forwards it here and these lines rewrite it to invalid_json/400. Please restrict malformed-body handling to the request parser or a more specific error type so normal coded errors keep their status and code.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in 2a98936. errorResponse now only treats SyntaxError messages containing JSON as malformed request bodies, and the new httpError regression test covers the skill "JSON" coded-error case so it remains route_not_found/404.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
packages/engine/src/lib/httpResponse.ts (1)

8-10: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

ValidationIssue interface is minimal compared to Zod v4's full issue structure.

The ValidationIssue interface only defines the path property, but Zod v4 issues include additional properties like code, message, and type-specific fields (e.g., minimum for too_small issues). Routes using the callback form of invalidMessage that try to access these properties won't have type safety.

Consider expanding this interface to match Zod v4's core issue types, or adding a comment documenting that routes should only rely on the path property for maximum compatibility.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/engine/src/lib/httpResponse.ts` around lines 8 - 10, The
ValidationIssue interface in the httpResponse.ts file is incomplete and only
includes the path property, but Zod v4 provides additional issue properties like
code, message, and type-specific fields (e.g., minimum for too_small issues). To
fix this, expand the ValidationIssue interface to include all the core
properties that Zod v4 provides (at minimum: code and message), or add a JSDoc
comment above the interface documenting that consumers should only rely on the
path property for maximum compatibility and should cast to any type if they need
to access other Zod issue properties.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@packages/engine/src/lib/httpError.ts`:
- Around line 47-49: The condition checking `error.message?.includes('JSON')` is
unreliable for detecting malformed JSON because it relies on string matching
which can produce false positives with unrelated errors. Replace this
string-based check with a proper type check using `instanceof SyntaxError`,
since Hono's `c.req.json()` throws a `SyntaxError` when encountering malformed
JSON in the request body. Update the if statement that currently checks
`error.message?.includes('JSON')` to instead check `error instanceof
SyntaxError` to ensure only actual syntax errors from JSON parsing are handled
by the `jsonMalformedBody(c)` response.

In `@packages/engine/src/lib/httpResponse.ts`:
- Around line 12-15: Update the SafeParseFailure interface to correctly
represent Zod v4's contract by removing the optional markers from the error
field and its nested issues property, making both required since they are always
present when success is false. Additionally, update the ValidationIssue
interface to include the code and message fields that Zod always provides
alongside the path field, ensuring the type accurately reflects the structure of
validation issues returned by Zod's safeParse method.

---

Nitpick comments:
In `@packages/engine/src/lib/httpResponse.ts`:
- Around line 8-10: The ValidationIssue interface in the httpResponse.ts file is
incomplete and only includes the path property, but Zod v4 provides additional
issue properties like code, message, and type-specific fields (e.g., minimum for
too_small issues). To fix this, expand the ValidationIssue interface to include
all the core properties that Zod v4 provides (at minimum: code and message), or
add a JSDoc comment above the interface documenting that consumers should only
rely on the path property for maximum compatibility and should cast to any type
if they need to access other Zod issue properties.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ded5bbab-63e4-4db3-8ef1-b86497237774

📥 Commits

Reviewing files that changed from the base of the PR and between 5314b02 and 28f111c.

📒 Files selected for processing (8)
  • packages/engine/src/__tests__/conformance/httpResponse.test.ts
  • packages/engine/src/lib/httpError.ts
  • packages/engine/src/lib/httpResponse.ts
  • packages/engine/src/routes/eventSubscription.ts
  • packages/engine/src/routes/node.ts
  • packages/engine/src/routes/receipt.ts
  • packages/engine/src/routes/systemPrompt.ts
  • packages/engine/src/routes/trigger.ts

Comment thread packages/engine/src/lib/httpError.ts Outdated
Comment thread packages/engine/src/lib/httpResponse.ts
@willwashburn willwashburn merged commit 63e6a75 into main Jun 23, 2026
5 checks passed
@willwashburn willwashburn deleted the codex/route-response-helpers branch June 23, 2026 15:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant