Add gateway Code Mode contract#71
Conversation
📝 WalkthroughWalkthroughThis PR introduces Code Mode, a gateway-owned MCP meta-tool surface that enables schema-first code discovery and constrained execution. It adds configuration validation, tool ID parsing, code snippet invocation extraction with TypeScript binding generation, and MCP server integration for ChangesCode Mode Gateway Meta-Tool Surface
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: b96a9d33ab
ℹ️ 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".
| if self.gateway_manager.is_none() { | ||
| let envelope = build_error( | ||
| &service, | ||
| "call_tool", | ||
| "unknown_tool", | ||
| "code schema is not enabled", | ||
| ); |
There was a problem hiding this comment.
Enforce tool-search enablement before serving code_schema
This branch only checks whether gateway_manager exists, so code_schema can still return Lab/upstream schemas even when [tool_search].enabled is false (the mode where these tools are intentionally hidden from list_tools). In a deployment with gateway configured but tool-search disabled, callers who know the tool name can bypass the feature toggle and access schema data anyway; this should be gated on tool_search_enabled() the same way discovery exposure is gated.
Useful? React with 👍 / 👎.
| other => build_error(service, action, other.kind(), &other.to_string()), | ||
| } |
There was a problem hiding this comment.
Preserve ToolError payloads in code_schema error envelopes
For non-Sdk errors, this helper uses other.to_string() as the message, but ToolError::Display is JSON, so envelopes end up with a nested JSON string in message and lose structured fields like valid/hint. A reproducible case is code_schema with a valid service but unknown action: callers receive a degraded unknown_action response that is much harder to handle programmatically.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Actionable comments posted: 6
🤖 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 `@crates/lab/src/dispatch/gateway/code_mode.rs`:
- Around line 393-424: balanced_parenthesized currently only treats '"' and '\''
as quotes so backtick template literals can prematurely close parentheses
parsing; update the function to treat '`' as a quote as well by including '`' in
the match that sets quote (e.g., match ch { '"' | '\'' | '`' => quote =
Some(ch), ... }) and ensure the quote-handling block correctly recognizes and
closes on a '`' while still honoring escapes (backslash) the same way as for
other quotes; this mirrors how first_unsupported_keyword/next_call_tool_offset
skip template literals and prevents ')' inside backtick strings from ending the
extraction prematurely.
- Around line 229-235: The current logic pushes a new CodeModeInvocation into
calls and then checks calls.len() > max_tool_calls, which allows one extra
invocation; update the enforcement in the function handling CodeModeInvocation
(where calls, max_tool_calls, and ToolError::Sdk are used) to prevent the
off-by-one by checking the limit before pushing or by using calls.len() >=
max_tool_calls for the post-push path so that attempting the
(max_tool_calls+1)th call returns the ToolError::Sdk with sdk_kind
"tool_call_limit_exceeded" and the same formatted message.
In `@crates/lab/src/mcp/catalog.rs`:
- Around line 203-205: The catalog currently inserts CODE_SEARCH_TOOL_NAME,
CODE_SCHEMA_TOOL_NAME, and CODE_EXECUTE_TOOL_NAME whenever
visibility.exposes_synthetic_tools() is true, making Code Mode tools
discoverable even if Code Mode is disabled; update the insertion logic in the
function that builds the tools set in mcp/catalog.rs so those three tool names
are only added when the runtime/config flag for Code Mode is enabled (mirror the
check used in mcp/server.rs, e.g. self.gateway_code_mode_enabled() or
config.code_mode.enabled), leaving visibility.exposes_synthetic_tools() to
control synthetic-tool exposure generally but adding an additional conditional
guard around the CODE_* inserts to consult the Code Mode enablement.
In `@crates/lab/src/mcp/server.rs`:
- Around line 3153-3167: The Some(Ok(result)) arm for pool.call_tool currently
treats any CallToolResult as success without checking result.is_error, and the
None case uses sdk_kind "not_found" which masks a disconnected upstream; update
the Some(Ok(result)) branch in server.rs to check CallToolResult.is_error and if
true return Err(DispatchToolError::Sdk { sdk_kind: "upstream_error", message:
<use the result's error text> }) otherwise serialize the successful result, and
change the None arm to return an SDK error indicating upstream disconnection
(e.g., sdk_kind "upstream_disconnected" with a message mentioning the upstream
and tool) so callers can retry; refer to pool.call_tool, CallToolResult, and
DispatchToolError to locate and implement these changes.
In `@docs/dev/ERRORS.md`:
- Around line 59-62: The HTTP Status Mapping section is missing the four Code
Mode error kinds listed earlier; add entries for invalid_code_mode_id (HTTP
422), code_mode_disabled (HTTP 403), tool_call_limit_exceeded (HTTP 429), and
schema_unavailable (HTTP 422) to the “HTTP Status Mapping” list in this document
so the mapping is complete and consistent with the earlier definitions; use the
exact kind strings (invalid_code_mode_id, code_mode_disabled,
tool_call_limit_exceeded, schema_unavailable) and their corresponding status
codes when inserting the lines.
In `@docs/superpowers/plans/2026-05-24-code-mode-contract.md`:
- Around line 41-46: Update the completed-plan examples to match the shipped
contract by removing the obsolete code_search.detail field from the JSON
examples and changing the error mapping for invalid_code_mode_id from HTTP 400
to HTTP 422; locate the JSON snippet that calls code_search (references to
code_search.detail and invalid_code_mode_id) and adjust the example responses
and any stated HTTP status codes (also update the other occurrences flagged at
lines 729-731) so the examples reflect no "detail" key and use 422 for
invalid_code_mode_id.
🪄 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: ASSERTIVE
Plan: Pro
Run ID: 03869d60-7cbf-4d2b-bf73-8905f0598612
📒 Files selected for processing (9)
crates/lab/src/config.rscrates/lab/src/dispatch/gateway.rscrates/lab/src/dispatch/gateway/code_mode.rscrates/lab/src/dispatch/gateway/manager.rscrates/lab/src/mcp/catalog.rscrates/lab/src/mcp/server.rsdocs/dev/ERRORS.mddocs/services/GATEWAY.mddocs/superpowers/plans/2026-05-24-code-mode-contract.md
| tools.insert(CODE_SEARCH_TOOL_NAME.to_string()); | ||
| tools.insert(CODE_SCHEMA_TOOL_NAME.to_string()); | ||
| tools.insert(CODE_EXECUTE_TOOL_NAME.to_string()); |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Description: Check if code_mode tools should be gated separately from tool_search
# Find CodeModeConfig to see if it has an enabled field
echo "=== CodeModeConfig structure ==="
ast-grep --pattern $'struct CodeModeConfig {
$$$
}'
# Check MCP server implementation for code_search/code_schema/code_execute handling
echo -e "\n=== MCP server handling of code mode tools ==="
rg -n 'CODE_SEARCH_TOOL_NAME|CODE_SCHEMA_TOOL_NAME|CODE_EXECUTE_TOOL_NAME' --type rust -A 10
# Check if there's validation that code mode is enabled before handling these tools
echo -e "\n=== Code mode enablement checks in call_tool ==="
rg -n 'code_mode.*enabled|gateway_code_mode_enabled' crates/lab/src/mcp/server.rs -C 5Repository: jmagar/lab
Length of output: 11746
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "=== Find exposes_synthetic_tools() definition ==="
rg -n "exposes_synthetic_tools" crates/lab/src/mcp -S
rg -n "exposes_synthetic_tools" crates/lab/src -S
echo "=== Inspect catalog.rs around lines ~180-240 ==="
sed -n '150,260p' crates/lab/src/mcp/catalog.rs | cat -n
echo "=== Locate GatewayManager code_mode_config / gateway_code_mode_enabled ==="
rg -n "code_mode_config|gateway_code_mode_enabled|gateway_code_mode_config" crates/lab/src -SRepository: jmagar/lab
Length of output: 6131
Gate Code Mode tool exposure on code_mode.enabled
mcp/server.rs only executes code_search/code_schema/code_execute behind self.gateway_code_mode_enabled() (and also checks config.enabled), but mcp/catalog.rs lists those tools whenever visibility.exposes_synthetic_tools() is true, which is derived from tool-search visibility—not Code Mode config. This can make Code Mode tools discoverable even when Code Mode is disabled.
🤖 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 `@crates/lab/src/mcp/catalog.rs` around lines 203 - 205, The catalog currently
inserts CODE_SEARCH_TOOL_NAME, CODE_SCHEMA_TOOL_NAME, and CODE_EXECUTE_TOOL_NAME
whenever visibility.exposes_synthetic_tools() is true, making Code Mode tools
discoverable even if Code Mode is disabled; update the insertion logic in the
function that builds the tools set in mcp/catalog.rs so those three tool names
are only added when the runtime/config flag for Code Mode is enabled (mirror the
check used in mcp/server.rs, e.g. self.gateway_code_mode_enabled() or
config.code_mode.enabled), leaving visibility.exposes_synthetic_tools() to
control synthetic-tool exposure generally but adding an additional conditional
guard around the CODE_* inserts to consult the Code Mode enablement.
| - `invalid_code_mode_id` — Code Mode tool id parsing failed. Valid ids are `lab::<service>.<action>` and `upstream::<upstream-name>::<tool-name>`. HTTP 422. | ||
| - `code_mode_disabled` — Code Mode execution was requested while `[code_mode].enabled` is false. Discovery and schema lookup can remain enabled without allowing execution. HTTP 403. | ||
| - `tool_call_limit_exceeded` — a Code Mode snippet attempted more host-brokered tool calls than `max_tool_calls` allows. HTTP 429. | ||
| - `schema_unavailable` — Code Mode schema lookup found a tool, but its upstream schema was missing or exceeded the safe return size after sanitization. HTTP 422. |
There was a problem hiding this comment.
Keep the HTTP status mapping table in sync with the new Code Mode kinds.
These four kinds are documented here with status codes, but they’re missing from the “HTTP Status Mapping” list later in this file. Please add them there as well to keep this document canonical and internally consistent.
🤖 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 `@docs/dev/ERRORS.md` around lines 59 - 62, The HTTP Status Mapping section is
missing the four Code Mode error kinds listed earlier; add entries for
invalid_code_mode_id (HTTP 422), code_mode_disabled (HTTP 403),
tool_call_limit_exceeded (HTTP 429), and schema_unavailable (HTTP 422) to the
“HTTP Status Mapping” list in this document so the mapping is complete and
consistent with the earlier definitions; use the exact kind strings
(invalid_code_mode_id, code_mode_disabled, tool_call_limit_exceeded,
schema_unavailable) and their corresponding status codes when inserting the
lines.
| ```json | ||
| code_search({ | ||
| "query": "github issues", | ||
| "top_k": 10, | ||
| "detail": "brief" | ||
| }) |
There was a problem hiding this comment.
Update completed-plan examples to match the shipped contract.
This plan is marked completed, but it still shows a code_search.detail field and invalid_code_mode_id as HTTP 400. Those differ from the implemented/documented contract in this PR (no detail; invalid_code_mode_id mapped to HTTP 422). Please align these examples to avoid future confusion.
Also applies to: 729-731
🤖 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 `@docs/superpowers/plans/2026-05-24-code-mode-contract.md` around lines 41 -
46, Update the completed-plan examples to match the shipped contract by removing
the obsolete code_search.detail field from the JSON examples and changing the
error mapping for invalid_code_mode_id from HTTP 400 to HTTP 422; locate the
JSON snippet that calls code_search (references to code_search.detail and
invalid_code_mode_id) and adjust the example responses and any stated HTTP
status codes (also update the other occurrences flagged at lines 729-731) so the
examples reflect no "detail" key and use 422 for invalid_code_mode_id.
Summary
Verification
Summary by cubic
Adds the gateway Code Mode contract with canonical tool IDs and a sandboxed JavaScript runner for constrained execution via
code_execute, alongsidecode_searchandcode_schema, enabling stable ids, exact schemas, and safe host-brokered tool calls.New Features
lab::<service>.<action>andupstream::<upstream>::<tool>.code_search(candidates with id/name/upstream/description/score/schema_available),code_schema(exact contract withschema_format=lab_action_specorjson_schema), andcode_execute(runs constrained snippets in a child process usingboa_enginewith timeout andmax_tool_callslimits).[code_mode]addsenabled,timeout_ms, andmax_tool_calls; execution is blocked when disabled.invalid_code_mode_id,code_mode_disabled,code_execution_failed,tool_call_limit_exceeded,schema_unavailable.labby internal code-mode-runnerto run the sandboxed helper.top_k.Migration
code_searchto get a stable id, thencode_schemabefore generating tool-call code.code_executewhen[code_mode].enabled; otherwise keep executing viainvoke(withscoutfor search).Written for commit 9afb378. Summary will update on new commits. Review in cubic
Summary by CodeRabbit
Release Notes
New Features
code_search,code_schema, andcode_execute(disabled by default)Documentation