Skip to content

refactor: name the runtime mode "hybrid" instead of "platform"#163

Merged
njbrake merged 10 commits into
mainfrom
refactor/rename-connected-mode
Jun 23, 2026
Merged

refactor: name the runtime mode "hybrid" instead of "platform"#163
njbrake merged 10 commits into
mainfrom
refactor/rename-connected-mode

Conversation

@njbrake

@njbrake njbrake commented Jun 15, 2026

Copy link
Copy Markdown
Member

Description

Renames the legacy "platform mode" runtime-mode term to "hybrid mode" across config, code, tests, and docs (#140). "Platform mode" was a holdover from the any-llm platform era.

This PR initially renamed the mode to "connected mode", but on review (thanks @tbille) "connected" read as ambiguous: Otari connects to many things (web search, MCP, providers), so "connected mode" did not clearly name the otari.ai-backed runtime mode. The term is now "hybrid mode".

"platform" is kept only where it names the peer service (the otari.ai backend): the platform token, the platform: config block, _platform.py, and the resolve/usage helpers.

Behavior:

  • effective_mode now returns "hybrid" instead of "platform"; the health endpoints report "mode": "hybrid". The separate platform / platform_reachable reachability keys (and the readiness db_status) are unchanged: they report a service/DB connection, not the mode.
  • Config mode / OTARI_MODE canonical value is now hybrid; platform is still accepted as a deprecated alias so existing configs keep working (test covers this).
  • GatewayConfig.is_platform_mode to is_hybrid_mode (property + all call sites).
  • RequestContext.platform_mode to hybrid_mode.
  • Router module routes/platform_mode.py to routes/hybrid_mode.py (tag hybrid-mode); disabled-endpoint detail now says "hybrid mode".
  • Doc docs/platform-protocol.md to docs/hybrid-mode-protocol.md, title "Hybrid-mode protocol"; inbound links updated.
  • Integration test files test_platform_mode_* to test_hybrid_mode_*.
  • Descriptive "connected to otari.ai" prose is kept where it accurately describes what hybrid mode does; it is specific, unlike the bare term.
  • OpenAPI spec regenerated from the updated route docstrings.

The branch name (refactor/rename-connected-mode) is left as-is to avoid churning the PR; it is cosmetic.

PR Type

  • New Feature
  • Bug Fix
  • Refactor
  • Documentation
  • Infrastructure / CI

Relevant issues

Fixes #140

Checklist

  • I understand the code I am submitting.
  • I have added or updated tests that cover my change (tests/unit, tests/integration).
  • I ran the Definition of Done checks locally (make lint, make typecheck, make test).
  • Documentation was updated where necessary.
  • If the API contract changed, I regenerated the OpenAPI spec (uv run python scripts/generate_openapi.py).

AI Usage

  • No AI was used.
  • AI was used for drafting/refactoring.
  • This is fully AI-generated.

AI Model/Tool used:

Claude Code (Claude Opus 4.8)

Any additional AI details you'd like to share:

The rename was carried out by Claude Code via back-and-forth with @njbrake; the decisions (term choice, scope, what to keep) are his.

NOTE:
When responding to reviewer questions, please respond yourself rather than copy/pasting reviewer comments into an AI and pasting back its answer. We want to discuss with you, not your AI :)

  • I am an AI Agent filling out this form (check box if true)

Summary

This pull request replaces the legacy term “platform mode” with “hybrid mode” across the project to address issue #140 and improve clarity around what the mode actually does. The word “platform” is still used where it specifically refers to the Otari.ai backend connection (e.g., the platform token/config and related connection helpers), but the runtime “mode” terminology is standardized on “hybrid mode”.

Changes Made

Behavior, configuration, and routing

  • The effective runtime mode now reports hybrid (and health endpoints return "mode": "hybrid").
  • Configuration now treats hybrid as the canonical mode value; platform remains accepted as a deprecated alias for backward compatibility.
  • Renamed gateway internals to match the new terminology:
    • is_platform_modeis_hybrid_mode
    • RequestContext.platform_modeRequestContext.hybrid_mode
    • Router module/file renamed to routes/hybrid_mode.py (tagged as hybrid-mode)
  • Updated request handling and tool/batch-related gating so “hybrid” behavior applies consistently where it previously used “platform mode”.
  • Health readiness/connectivity behavior remains based on reachability keys (e.g., platform_reachable) while the mode label is updated to hybrid.

Documentation

  • Renamed protocol documentation from docs/platform-protocol.md to docs/hybrid-mode-protocol.md, and updated all linked references.
  • Updated deployment/modes/usage docs, startup notes, and terminology throughout to reference “hybrid mode”.

Tests and API docs

  • Renamed integration tests from test_platform_mode_* to test_hybrid_mode_*, including updated assertions and fixtures.
  • Added coverage for accepting the legacy mode: platform alias (mapping it to the new hybrid behavior).
  • Regenerated OpenAPI output from updated route docstrings.

Benefits

  • Removes the legacy/ambiguous “platform mode” wording and replaces it with terminology that better reflects how Otari combines local and Otari.ai-backed behavior.
  • Keeps existing deployments working via a deprecated platform alias while guiding new configurations toward hybrid.

@coderabbitai

coderabbitai Bot commented Jun 15, 2026

Copy link
Copy Markdown

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: c75531bb-7afd-433f-9722-76c4b0047aff

📥 Commits

Reviewing files that changed from the base of the PR and between d3e1a7a and e2afbb3.

📒 Files selected for processing (4)
  • docs/configuration.md
  • docs/modes.md
  • docs/use-with-opencode.md
  • src/gateway/api/routes/health.py
✅ Files skipped from review due to trivial changes (3)
  • docs/configuration.md
  • docs/modes.md
  • docs/use-with-opencode.md
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/gateway/api/routes/health.py

Walkthrough

Renames the gateway's connected-to-otari.ai runtime mode from "platform mode" to "hybrid mode" throughout the codebase. GatewayConfig.is_platform_mode is replaced by is_hybrid_mode, effective_mode now returns "hybrid", RequestContext.platform_mode is renamed to hybrid_mode, and all dependent route handlers, CLI startup, lifespan wiring, integration tests, unit tests, and documentation are updated consistently. The legacy "platform" mode value remains accepted as an alias.

Changes

Platform-to-hybrid mode rename

Layer / File(s) Summary
GatewayConfig: is_hybrid_mode property and validation
src/gateway/core/config.py
Adds is_hybrid_mode boolean property, updates effective_mode to return "hybrid" when a platform token is present, expands validate_mode_selection to accept "hybrid" (keeping "platform" as a legacy alias), and broadens _apply_platform_env_overrides to trigger on mode == "hybrid".
RequestContext and pipeline: platform_modehybrid_mode
src/gateway/api/routes/_pipeline.py
Renames RequestContext.platform_mode field and constructor parameter to hybrid_mode, renames MCP_SERVER_IDS_PLATFORM_ONLY_DETAIL constant to MCP_SERVER_IDS_HYBRID_ONLY_DETAIL, updates resolve_request_context branching, and rewires prepare_gateway_tools sandbox/web-search token forwarding to gate on ctx.hybrid_mode.
App startup, CLI, lifespan, and router registration
src/gateway/api/main.py, src/gateway/api/deps.py, src/gateway/main.py, src/gateway/cli.py
Imports hybrid_mode router, gates it on config.is_hybrid_mode, updates _validate_platform_config and _create_lifespan to use config.is_hybrid_mode, and updates CLI startup logs and validation messages.
Route handlers: chat, messages, responses, health, hybrid_mode, _platform
src/gateway/api/routes/chat.py, src/gateway/api/routes/messages.py, src/gateway/api/routes/responses.py, src/gateway/api/routes/health.py, src/gateway/api/routes/hybrid_mode.py, src/gateway/api/routes/_platform.py, src/gateway/api/routes/_normalize.py, src/gateway/services/mcp_loop.py, src/gateway/services/mcp_loop_messages.py, src/gateway/services/mcp_loop_responses.py, src/gateway/services/sandbox_backend.py
Switches all ctx.platform_mode / config.is_platform_mode checks to ctx.hybrid_mode / config.is_hybrid_mode, updates health endpoint mode strings to "hybrid", updates HTTPException detail strings from "Platform mode is misconfigured" to "Hybrid mode is misconfigured", and updates docstrings across service MCP loop files.
Config env-loading integration tests
tests/integration/test_config_env_loading.py
Renames tests to hybrid variants, adds test_load_config_accepts_legacy_platform_mode_alias verifying platform YAML alias maps to effective_mode == "hybrid", and updates all is_platform_mode assertions to is_hybrid_mode.
Integration tests: surface and batches
tests/integration/test_hybrid_mode_surface.py, tests/integration/test_batches_endpoint.py
Migrates fixtures to GatewayConfig(mode="hybrid"), renames test functions, updates health/readiness JSON assertions to expect "hybrid" mode strings and "connected" platform status, and updates 404 detail text for disabled management endpoints.
Integration tests: chat, messages, responses
tests/integration/test_hybrid_mode_chat.py, tests/integration/test_hybrid_mode_messages.py, tests/integration/test_hybrid_mode_responses.py
Migrates all three endpoint test modules to mode="hybrid", renames all test_platform_mode_* functions, and adds streaming usage-report assertions.
Unit tests: settlement, mcp_loop, run_platform_attempts
tests/unit/test_pipeline_settlement.py, tests/unit/test_mcp_loop.py, tests/unit/test_run_platform_attempts.py
Updates RequestContext construction from platform_mode=False to hybrid_mode=False, renames platform_path parametrization to hybrid_path, and updates correlation-header assertions.
Documentation
README.md, AGENTS.md, .github/instructions/security-review.instructions.md, docs/hybrid-mode-protocol.md, docs/deployment.md, docs/files.md, docs/index.md, docs/modes.md, docs/quickstart.md, docs/use-with-claude-code.md, docs/configuration.md, docs/use-with-opencode.md, scripts/web-search-tavily-adapter/README.md
Replaces all "platform mode" references with "hybrid mode" across all user-facing documentation, updates configuration descriptions to list "standalone" and "hybrid" as valid mode values, and updates the protocol doc link from platform-protocol.md to hybrid-mode-protocol.md.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

Possibly related PRs

  • mozilla-ai/otari#124: Introduced the /v1/messages/count_tokens endpoint with platform-vs-standalone auth gating via config.is_platform_mode, which is directly renamed to config.is_hybrid_mode in this PR.
  • mozilla-ai/otari#130: Introduced the consolidated request pipeline in _pipeline.py including RequestContext.platform_mode, which is the field renamed to hybrid_mode here.
  • mozilla-ai/otari#144: Introduced the per-workspace web-search platform-resolve integration gated on platform_mode, which is re-gated on hybrid_mode in this PR.

Suggested reviewers

  • tbille
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 47.74% 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 uses the required 'refactor:' prefix, follows imperative mood, and clearly describes the main change: renaming 'platform mode' to 'hybrid mode'. It is directly related to the changeset.
Description check ✅ Passed The description is comprehensive and complete, covering the rationale, behavior changes, scope, and decisions. All template sections are properly filled out.
Linked Issues check ✅ Passed The PR fully satisfies issue #140's objective to rename 'platform mode' to a non-legacy term. All scope items are addressed: config, code, tests, and documentation updated to use 'hybrid mode' consistently.
Out of Scope Changes check ✅ Passed All changes are directly related to the hybrid-mode rename objective. The PR maintains intentional scope by keeping 'platform' terminology only where it refers to the otari.ai backend service.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch refactor/rename-connected-mode
✨ Simplify code
  • Create PR with simplified code
  • Commit simplified code in branch refactor/rename-connected-mode

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 markdownlint-cli2 (0.22.1)
docs/modes.md

markdownlint-cli2 v0.22.1 (markdownlint v0.40.0)
Error: Unable to use configuration file '/coderabbit-1.markdownlint-cli2.jsonc'; ENOENT: no such file or directory, open '/coderabbit-1.markdownlint-cli2.jsonc'
at throwForConfigurationFile (file:///usr/local/lib/node_modules/markdownlint-cli2/markdownlint-cli2.mjs:48:9)
at readOptionsOrConfig (file:///usr/local/lib/node_modules/markdownlint-cli2/markdownlint-cli2.mjs:169:5)
at async main (file:///usr/local/lib/node_modules/markdownlint-cli2/markdownlint-cli2.mjs:927:21)
at async file:///usr/local/lib/node_modules/markdownlint-cli2/markdownlint-cli2-bin.mjs:14:22 {
[cause]: Error: ENOENT: no such file or directory, open '/coderabbit-1.markdownlint-cli2.jsonc'
at async open (node:internal/fs/promises:640:25)
at async Object.readFile (node:internal/fs/promises:1287:14)
at async readOptionsOrConfig (file:///usr/local/lib/node_modules/markdownlint-cli2/markdownlint-cli2.mjs:141:17)
at async main (file:///usr/local/lib/node_modules/markdownlint-cli2/markdownlint-cli2.mjs:927:21)
at async file:///usr/local/lib/node_modules/markdownlint-cli2/markdownlint-cli2-bin.mjs:14:22 {
errno: -2,
code: 'ENOENT',
syscall: 'open',
path: '/coderabbit-1.markdownlint-cli2.jsonc'
}
}

docs/use-with-opencode.md

markdownlint-cli2 v0.22.1 (markdownlint v0.40.0)
Error: Unable to use configuration file '/coderabbit-2.markdownlint-cli2.jsonc'; ENOENT: no such file or directory, open '/coderabbit-2.markdownlint-cli2.jsonc'
at throwForConfigurationFile (file:///usr/local/lib/node_modules/markdownlint-cli2/markdownlint-cli2.mjs:48:9)
at readOptionsOrConfig (file:///usr/local/lib/node_modules/markdownlint-cli2/markdownlint-cli2.mjs:169:5)
at async main (file:///usr/local/lib/node_modules/markdownlint-cli2/markdownlint-cli2.mjs:927:21)
at async file:///usr/local/lib/node_modules/markdownlint-cli2/markdownlint-cli2-bin.mjs:14:22 {
[cause]: Error: ENOENT: no such file or directory, open '/coderabbit-2.markdownlint-cli2.jsonc'
at async open (node:internal/fs/promises:640:25)
at async Object.readFile (node:internal/fs/promises:1287:14)
at async readOptionsOrConfig (file:///usr/local/lib/node_modules/markdownlint-cli2/markdownlint-cli2.mjs:141:17)
at async main (file:///usr/local/lib/node_modules/markdownlint-cli2/markdownlint-cli2.mjs:927:21)
at async file:///usr/local/lib/node_modules/markdownlint-cli2/markdownlint-cli2-bin.mjs:14:22 {
errno: -2,
code: 'ENOENT',
syscall: 'open',
path: '/coderabbit-2.markdownlint-cli2.jsonc'
}
}

docs/configuration.md

markdownlint-cli2 v0.22.1 (markdownlint v0.40.0)
Error: Unable to use configuration file '/coderabbit-0.markdownlint-cli2.jsonc'; ENOENT: no such file or directory, open '/coderabbit-0.markdownlint-cli2.jsonc'
at throwForConfigurationFile (file:///usr/local/lib/node_modules/markdownlint-cli2/markdownlint-cli2.mjs:48:9)
at readOptionsOrConfig (file:///usr/local/lib/node_modules/markdownlint-cli2/markdownlint-cli2.mjs:169:5)
at async main (file:///usr/local/lib/node_modules/markdownlint-cli2/markdownlint-cli2.mjs:927:21)
at async file:///usr/local/lib/node_modules/markdownlint-cli2/markdownlint-cli2-bin.mjs:14:22 {
[cause]: Error: ENOENT: no such file or directory, open '/coderabbit-0.markdownlint-cli2.jsonc'
at async open (node:internal/fs/promises:640:25)
at async Object.readFile (node:internal/fs/promises:1287:14)
at async readOptionsOrConfig (file:///usr/local/lib/node_modules/markdownlint-cli2/markdownlint-cli2.mjs:141:17)
at async main (file:///usr/local/lib/node_modules/markdownlint-cli2/markdownlint-cli2.mjs:927:21)
at async file:///usr/local/lib/node_modules/markdownlint-cli2/markdownlint-cli2-bin.mjs:14:22 {
errno: -2,
code: 'ENOENT',
syscall: 'open',
path: '/coderabbit-0.markdownlint-cli2.jsonc'
}
}


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.

@njbrake
njbrake requested a review from tbille June 15, 2026 12:45
@njbrake
njbrake marked this pull request as ready for review June 15, 2026 12:47
@khaledosman
khaledosman requested a review from Copilot June 15, 2026 12:47

Copilot AI 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.

Pull request overview

This PR standardizes the runtime-mode terminology by renaming the legacy “platform mode” to “connected mode” across the Otari Gateway codebase, tests, and documentation, while preserving “platform” to refer to the upstream otari.ai service and related integration surfaces.

Changes:

  • Renames mode semantics and surfaces: effective_mode now reports "connected"; health endpoints return "mode": "connected".
  • Updates config and runtime branching: is_platform_modeis_connected_mode, and OTARI_MODE=platform remains accepted as a legacy alias for connected (with new test coverage).
  • Renames/updates connected-mode routing and documentation, and regenerates OpenAPI descriptions to match updated docstrings.

Reviewed changes

Copilot reviewed 38 out of 38 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
tests/unit/test_run_platform_attempts.py Updates unit-test docstring to “connected-mode” terminology.
tests/unit/test_pipeline_settlement.py Renames context flag and parametrization to “connected”; updates related assertions.
tests/unit/test_mcp_loop.py Updates comments referencing the attempt loop terminology.
tests/integration/test_connected_mode_surface.py Updates integration tests to assert "mode": "connected" and connected-mode disabled endpoints.
tests/integration/test_connected_mode_responses.py Updates connected-mode responses tests and their docstrings/names.
tests/integration/test_connected_mode_messages.py Updates connected-mode messages tests and their docstrings/names.
tests/integration/test_connected_mode_chat.py Updates connected-mode chat tests, including legacy resolve-shape coverage.
tests/integration/test_config_env_loading.py Updates env/config loading expectations; adds test for legacy mode: platform alias.
tests/integration/test_batches_endpoint.py Updates connected-mode batch endpoint expectations and docstrings.
src/gateway/services/mcp_loop.py Updates docstring references to connected-mode attempt loop consumers.
src/gateway/services/mcp_loop_responses.py Updates docstring references for connected-mode callers.
src/gateway/services/mcp_loop_messages.py Updates docstring references for connected-mode callers.
src/gateway/main.py Switches validation/lifespan branching to is_connected_mode and updates messages.
src/gateway/core/config.py Implements "connected" as effective_mode, renames property to is_connected_mode, accepts legacy platform mode.
src/gateway/cli.py Updates CLI validation/logging strings and branching to connected mode.
src/gateway/api/routes/responses.py Updates connected-mode branching and explanatory comments/docstrings.
src/gateway/api/routes/messages.py Updates connected-mode branching and related docstrings/comments.
src/gateway/api/routes/health.py Updates health/readiness payload "mode" values to "connected".
src/gateway/api/routes/connected_mode.py Updates disabled-endpoint detail text and router tag to connected-mode.
src/gateway/api/routes/chat.py Updates connected-mode streaming and non-streaming path comments/branching.
src/gateway/api/routes/_platform.py Updates module/docs to “connected-mode shared infrastructure” and related messages.
src/gateway/api/routes/_pipeline.py Renames platform_mode flag to connected_mode across request context and tool preparation.
src/gateway/api/routes/_normalize.py Updates module docs to connected mode terminology.
src/gateway/api/main.py Registers connected_mode router when in connected mode; updates comments accordingly.
src/gateway/api/deps.py Returns no DB session when in connected mode (is_connected_mode).
scripts/web-search-tavily-adapter/README.md Updates connected-mode wording for workspace defaults.
README.md Updates user-facing docs to “connected mode” and points to connected-mode protocol doc.
docs/use-with-claude-code.md Updates connected-mode wording in Claude Code integration docs.
docs/quickstart.md Updates quickstart links and wording to connected mode.
docs/public/openapi.json Regenerated OpenAPI descriptions reflecting connected-mode terminology.
docs/modes.md Updates protocol doc link to connected-mode protocol.
docs/index.md Updates docs index navigation text and protocol link to connected-mode protocol.
docs/files.md Updates connected-mode wording in standalone-only note.
docs/deployment.md Updates deployment guide wording from platform mode to connected mode.
docs/connected-mode-protocol.md Renames and updates protocol doc title and connected-mode terminology.
CHANGELOG.md Updates changelog wording to connected mode.
AGENTS.md Updates engineering guidance to connected-mode naming and semantics.
.github/instructions/security-review.instructions.md Updates security review guidance to connected mode naming and gating.
Comments suppressed due to low confidence (1)

tests/unit/test_pipeline_settlement.py:97

  • This docstring still calls the multi-attempt path the "platform-fallback" path, but the test parameter and mode terminology are now "connected". Updating the wording keeps the rename consistent and avoids ambiguity about whether this refers to the runtime mode or the upstream service.

Comment thread README.md Outdated
Comment thread src/gateway/core/config.py Outdated
@njbrake
njbrake requested a review from khaledosman June 17, 2026 15:22
Base automatically changed from docs/platform-protocol-drift to main June 17, 2026 15:56
njbrake and others added 4 commits June 17, 2026 18:40
"Platform mode" was a holdover from the any-llm platform era. The
user-facing docs had already standardized on "connected to otari.ai" /
"connected mode"; this aligns config, code, tests, and the remaining docs
with that term. "platform" is kept only where it names the peer service
(the otari.ai backend): the platform token, the `platform:` config block,
`_platform.py`, and the resolve/usage helpers.

Behavior:
- `effective_mode` now returns "connected" instead of "platform"; the
  health endpoints report `"mode": "connected"`.
- `OTARI_MODE` / config `mode` canonical value is now "connected";
  "platform" is still accepted as a deprecated alias so existing configs
  keep working (covered by a new test).
- `GatewayConfig.is_platform_mode` -> `is_connected_mode`.
- Router module `routes/platform_mode.py` -> `routes/connected_mode.py`
  (tag "connected-mode"); disabled-endpoint detail now says "connected
  mode".
- Doc `docs/platform-protocol.md` -> `docs/connected-mode-protocol.md`,
  title "Connected-mode protocol"; inbound links updated.
- Integration test files `test_platform_mode_*` -> `test_connected_mode_*`.
- OpenAPI spec regenerated from the updated route docstrings.

Fixes #140

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Follow-up sweep found mode-term references the first pass missed because
they were line-wrapped or used bare "platform" as mode shorthand:

- two line-wrapped "platform\nmode" docstrings (_pipeline.py, the
  responses connected-mode test)
- "platform-only" -> "connected-only" for the mcp_server_ids restriction
  (code comment + connected-mode-protocol doc)
- "(or platform + tool-loop)" / "Tool-loop platform path" comments in the
  messages/responses pipelines
- README: canonical OTARI_MODE value is now `connected` (legacy `platform`
  noted as still accepted)

Service-level "platform" names (the peer service, PLATFORM_* env vars,
platform-resolved attempts/route, platform-fallback mechanism) are
deliberately kept.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Address Copilot review: when OTARI_MODE=platform (the legacy value) is set
without a token, the error said "OTARI_MODE=connected requires ...", which
is confusing for a user who typed "platform". Name the legacy value
explicitly in the message.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Rebasing this branch onto main surfaced three references the original
rename could not have touched, because the code carrying them landed on
main after the branch diverged:

- `_pipeline.py`: the sandbox-token branch still read `ctx.platform_mode`.
  That attribute is now `ctx.connected_mode`, so a connected-mode
  `otari_code_execution` request would have raised AttributeError. Renamed
  the attribute reference and the two surrounding "platform mode" comments.
- `sandbox_backend.py`: a doc comment still said "Set in platform mode".
- `test_connected_mode_chat.py`: the web-search token-forwarding test was
  still named `test_platform_mode_*`; renamed to match every other test in
  the file.

References to the platform *service* (platform token, base URL,
`web_search_url_targets_platform`) are intentionally left as "platform".

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@njbrake
njbrake force-pushed the refactor/rename-connected-mode branch from dd09af2 to 0aa5a61 Compare June 17, 2026 19:07
@njbrake
njbrake temporarily deployed to integration-tests June 17, 2026 19:07 — with GitHub Actions Inactive

@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.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
docs/deployment.md (1)

64-68: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Update stale health endpoint example output.

The JSON example shows "mode": "platform", but the actual /health endpoint returns "mode": "connected" when connected mode is active. Update the example to match the current implementation.

🔧 Proposed fix
 The response includes platform reachability status:

 ```json
-{"status": "healthy", "mode": "platform", "platform_reachable": "yes"}
+{"status": "healthy", "mode": "connected", "platform_reachable": "yes"}

</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

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/deployment.md around lines 64 - 68, The health endpoint JSON example in
the deployment.md file shows an outdated mode value that does not match the
current implementation. Update the example JSON response to replace the "mode": "platform" field with "mode": "connected" to accurately reflect what the
/health endpoint actually returns when connected mode is active.


</details>

<!-- cr-comment:v1:8ae0dbf666fdf5adef279466 -->

</blockquote></details>

</blockquote></details>
🧹 Nitpick comments (1)
tests/integration/test_connected_mode_responses.py (1)

28-33: ⚡ Quick win

Use canonical connected-mode fixture naming and token env var

This fixture still uses legacy platform_* naming and OTARI_PLATFORM_TOKEN. Renaming to connected_client and setting OTARI_AI_TOKEN would keep this module aligned with the rename intent and reduce legacy coupling in core connected-mode tests (legacy alias coverage can stay in dedicated config-compat tests).

Suggested diff
-@pytest.fixture
-def platform_client(monkeypatch: pytest.MonkeyPatch) -> Generator[TestClient]:
-    monkeypatch.setenv("OTARI_PLATFORM_TOKEN", "gw_test_token")
+@pytest.fixture
+def connected_client(monkeypatch: pytest.MonkeyPatch) -> Generator[TestClient]:
+    monkeypatch.setenv("OTARI_AI_TOKEN", "gw_test_token")

Based on learnings, connected mode is derived from OTARI_AI_TOKEN presence and platform remains a legacy alias; using the canonical token in primary connected-mode tests keeps intent crisp.

🤖 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 `@tests/integration/test_connected_mode_responses.py` around lines 28 - 33, The
fixture `platform_client` uses legacy naming and the deprecated
`OTARI_PLATFORM_TOKEN` environment variable instead of the canonical
connected-mode naming and token. Rename the fixture function from
`platform_client` to `connected_client` and change the monkeypatch call to set
`OTARI_AI_TOKEN` instead of `OTARI_PLATFORM_TOKEN` to align with the canonical
connected-mode configuration where connected mode is derived from the presence
of `OTARI_AI_TOKEN` and `platform` is treated as a legacy alias.

Source: Learnings

🤖 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.

Outside diff comments:
In `@docs/deployment.md`:
- Around line 64-68: The health endpoint JSON example in the deployment.md file
shows an outdated mode value that does not match the current implementation.
Update the example JSON response to replace the `"mode": "platform"` field with
`"mode": "connected"` to accurately reflect what the `/health` endpoint actually
returns when connected mode is active.

---

Nitpick comments:
In `@tests/integration/test_connected_mode_responses.py`:
- Around line 28-33: The fixture `platform_client` uses legacy naming and the
deprecated `OTARI_PLATFORM_TOKEN` environment variable instead of the canonical
connected-mode naming and token. Rename the fixture function from
`platform_client` to `connected_client` and change the monkeypatch call to set
`OTARI_AI_TOKEN` instead of `OTARI_PLATFORM_TOKEN` to align with the canonical
connected-mode configuration where connected mode is derived from the presence
of `OTARI_AI_TOKEN` and `platform` is treated as a legacy alias.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 949965d6-c23a-4ee9-b7cb-a6555da64813

📥 Commits

Reviewing files that changed from the base of the PR and between f450709 and 0aa5a61.

⛔ Files ignored due to path filters (1)
  • docs/public/openapi.json is excluded by !docs/public/openapi.json
📒 Files selected for processing (37)
  • .github/instructions/security-review.instructions.md
  • AGENTS.md
  • README.md
  • docs/connected-mode-protocol.md
  • docs/deployment.md
  • docs/files.md
  • docs/index.md
  • docs/modes.md
  • docs/quickstart.md
  • docs/use-with-claude-code.md
  • scripts/web-search-tavily-adapter/README.md
  • src/gateway/api/deps.py
  • src/gateway/api/main.py
  • src/gateway/api/routes/_normalize.py
  • src/gateway/api/routes/_pipeline.py
  • src/gateway/api/routes/_platform.py
  • src/gateway/api/routes/chat.py
  • src/gateway/api/routes/connected_mode.py
  • src/gateway/api/routes/health.py
  • src/gateway/api/routes/messages.py
  • src/gateway/api/routes/responses.py
  • src/gateway/cli.py
  • src/gateway/core/config.py
  • src/gateway/main.py
  • src/gateway/services/mcp_loop.py
  • src/gateway/services/mcp_loop_messages.py
  • src/gateway/services/mcp_loop_responses.py
  • src/gateway/services/sandbox_backend.py
  • tests/integration/test_batches_endpoint.py
  • tests/integration/test_config_env_loading.py
  • tests/integration/test_connected_mode_chat.py
  • tests/integration/test_connected_mode_messages.py
  • tests/integration/test_connected_mode_responses.py
  • tests/integration/test_connected_mode_surface.py
  • tests/unit/test_mcp_loop.py
  • tests/unit/test_pipeline_settlement.py
  • tests/unit/test_run_platform_attempts.py

Brings in the fallback/streaming fixes from main (retryable 404/405/409/410,
exactly-once per-attempt usage reporting, bounded inline flush). Conflicts
were limited to the connected-mode message tests, where main added a new 404
fall-through test and renamed/expanded the all-attempts-fail test while this
branch had renamed the file and its test prefixes. Resolution keeps main's
new tests and applies the platform_mode -> connected_mode prefix rename to
them; same rename applied to a new streaming all-fail test main added to the
chat suite.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@njbrake
njbrake temporarily deployed to integration-tests June 18, 2026 11:59 — with GitHub Actions Inactive
@tbille

tbille commented Jun 22, 2026

Copy link
Copy Markdown
Member

@njbrake I have been procrastinating a bit on this one for the only reason that I am not entirely sure if "connected" is the right term.
Because technically otari can be connected to lots of different things (eg. websearch, mcp, whatever).

What do you think if we had something like: mode="hybrid" or mode="standalone" ?

@njbrake

njbrake commented Jun 22, 2026

Copy link
Copy Markdown
Member Author

I went with "connected" because it seems like we had already started adopting that term in the code base, but if you would prefer a different term, I have no strong opinion 😊

@tbille

tbille commented Jun 22, 2026

Copy link
Copy Markdown
Member

I think it would make more sense 😅
Would you mind updating? I'll +10000 it 🚀

Per review feedback on #163, "connected" was ambiguous as a mode name
(Otari connects to many things: web search, MCP, providers). Rename the
runtime-mode term to "hybrid" across config, code, tests, and docs.

- effective_mode now returns "hybrid"; health endpoints report "mode": "hybrid".
  The platform / platform_reachable reachability keys and db_status keep
  reporting "connected" (they describe the service connection, not the mode).
- Config mode canonical value is "hybrid"; "platform" stays a deprecated alias.
- GatewayConfig.is_connected_mode -> is_hybrid_mode (property + all call sites).
- RequestContext.connected_mode -> hybrid_mode.
- routes/connected_mode.py -> routes/hybrid_mode.py (tag "hybrid-mode").
- docs/connected-mode-protocol.md -> docs/hybrid-mode-protocol.md.
- test_connected_mode_*.py -> test_hybrid_mode_*.py.
- Descriptive "connected to otari.ai" prose is kept where it accurately
  describes what hybrid mode does (it is specific, not the ambiguous term).
- OpenAPI spec regenerated from the updated route docstrings.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@njbrake njbrake changed the title refactor: rename "platform mode" to "connected mode" (#140) refactor: name the runtime mode "hybrid" instead of "platform" Jun 22, 2026
@github-actions github-actions Bot added the missing-template PR is missing required template sections label Jun 22, 2026
tbille
tbille previously approved these changes Jun 22, 2026

@tbille tbille left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

pre-👍
thanks 💙

@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: 1

🤖 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 `@src/gateway/api/routes/health.py`:
- Around line 85-87: In the health.py file, replace the raw status code integer
503 with the FastAPI status constant HTTP_503_SERVICE_UNAVAILABLE in the
HTTPException raised in this handler branch. First ensure that status is
imported from fastapi at the top of the file (if not already present), then
change the status_code parameter from 503 to status.HTTP_503_SERVICE_UNAVAILABLE
to maintain consistency with the codebase guidelines for using HTTP status
constants instead of raw integers.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 795bfb94-bbae-49cc-8d65-b5684f8c4655

📥 Commits

Reviewing files that changed from the base of the PR and between b053949 and b213b8c.

⛔ Files ignored due to path filters (1)
  • docs/public/openapi.json is excluded by !docs/public/openapi.json
📒 Files selected for processing (37)
  • .github/instructions/security-review.instructions.md
  • AGENTS.md
  • README.md
  • docs/deployment.md
  • docs/files.md
  • docs/hybrid-mode-protocol.md
  • docs/index.md
  • docs/modes.md
  • docs/quickstart.md
  • docs/use-with-claude-code.md
  • scripts/web-search-tavily-adapter/README.md
  • src/gateway/api/deps.py
  • src/gateway/api/main.py
  • src/gateway/api/routes/_normalize.py
  • src/gateway/api/routes/_pipeline.py
  • src/gateway/api/routes/_platform.py
  • src/gateway/api/routes/chat.py
  • src/gateway/api/routes/health.py
  • src/gateway/api/routes/hybrid_mode.py
  • src/gateway/api/routes/messages.py
  • src/gateway/api/routes/responses.py
  • src/gateway/cli.py
  • src/gateway/core/config.py
  • src/gateway/main.py
  • src/gateway/services/mcp_loop.py
  • src/gateway/services/mcp_loop_messages.py
  • src/gateway/services/mcp_loop_responses.py
  • src/gateway/services/sandbox_backend.py
  • tests/integration/test_batches_endpoint.py
  • tests/integration/test_config_env_loading.py
  • tests/integration/test_hybrid_mode_chat.py
  • tests/integration/test_hybrid_mode_messages.py
  • tests/integration/test_hybrid_mode_responses.py
  • tests/integration/test_hybrid_mode_surface.py
  • tests/unit/test_mcp_loop.py
  • tests/unit/test_pipeline_settlement.py
  • tests/unit/test_run_platform_attempts.py
✅ Files skipped from review due to trivial changes (18)
  • docs/modes.md
  • docs/files.md
  • .github/instructions/security-review.instructions.md
  • src/gateway/services/sandbox_backend.py
  • docs/quickstart.md
  • tests/unit/test_run_platform_attempts.py
  • src/gateway/services/mcp_loop_messages.py
  • docs/deployment.md
  • src/gateway/api/routes/_normalize.py
  • docs/use-with-claude-code.md
  • src/gateway/api/routes/_platform.py
  • AGENTS.md
  • docs/hybrid-mode-protocol.md
  • src/gateway/services/mcp_loop.py
  • scripts/web-search-tavily-adapter/README.md
  • docs/index.md
  • tests/unit/test_mcp_loop.py
  • src/gateway/services/mcp_loop_responses.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • tests/unit/test_pipeline_settlement.py

Comment thread src/gateway/api/routes/health.py
The /health endpoint reports "mode": "hybrid" in hybrid mode, not
"platform". Update the example output to match.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@github-actions github-actions Bot removed the missing-template PR is missing required template sections label Jun 22, 2026
# Conflicts:
#	AGENTS.md
#	docs/modes.md
@njbrake
njbrake temporarily deployed to integration-tests June 22, 2026 23:02 — with GitHub Actions Inactive
@coderabbitai
coderabbitai Bot requested a review from tbille June 22, 2026 23:04

@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.

🧹 Nitpick comments (1)
docs/modes.md (1)

85-87: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add language identifiers to the code block examples showing HTTP endpoints.

The fenced code blocks demonstrating HTTP POST endpoints (provider resolution, usage reporting, MCP server resolution, web search resolution) lack language specifiers. While they render fine, adding a language identifier improves syntax highlighting and satisfies the markdown linter (MD040).

Since these are HTTP request examples, use http as the language:

🔧 Proposed fix
### Provider resolution

Before each LLM request, Otari asks otari.ai which provider and credentials to use:

-```
+``` http
 POST {base_url}/gateway/provider-keys/resolve

Usage reporting

After each attempt (success or failure), Otari reports usage:

- + http
POST {base_url}/gateway/usage


### MCP server resolution

When a request includes MCP server references, Otari resolves them:

-```
+``` http
POST {base_url}/gateway/mcp-servers/resolve

Web search resolution

When a request enables Otari's built-in web search, Otari resolves the workspace's search policy:

- + http
POST {base_url}/gateway/web-search/resolve

Also applies to: 95-97, 105-107, 115-117

🤖 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/modes.md` around lines 85 - 87, Add the http language identifier to all
fenced code blocks in the documentation that demonstrate HTTP POST endpoints.
Specifically, locate the four code blocks showing the provider-keys/resolve
endpoint, the usage reporting endpoint, the mcp-servers/resolve endpoint, and
the web-search/resolve endpoint, and modify each opening fence from triple
backticks (```) to triple backticks followed by http (``` http) to enable proper
syntax highlighting and satisfy markdown linting rules.

Source: Linters/SAST tools

🤖 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.

Nitpick comments:
In `@docs/modes.md`:
- Around line 85-87: Add the http language identifier to all fenced code blocks
in the documentation that demonstrate HTTP POST endpoints. Specifically, locate
the four code blocks showing the provider-keys/resolve endpoint, the usage
reporting endpoint, the mcp-servers/resolve endpoint, and the web-search/resolve
endpoint, and modify each opening fence from triple backticks (```) to triple
backticks followed by http (``` http) to enable proper syntax highlighting and
satisfy markdown linting rules.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 71c7b25e-8d6e-4cab-a2e8-ebc4d2b1afa4

📥 Commits

Reviewing files that changed from the base of the PR and between b213b8c and d3e1a7a.

📒 Files selected for processing (3)
  • AGENTS.md
  • docs/deployment.md
  • docs/modes.md
✅ Files skipped from review due to trivial changes (2)
  • docs/deployment.md
  • AGENTS.md

A close scan surfaced mode-label usages of the old term that the initial
rename and the main merge missed:

- modes.md: "Connected mode resolves ..." and "self-host in connected mode"
  (from the BYO/managed trust section merged from main) -> "hybrid mode".
- use-with-opencode.md: "standalone and connected modes" -> "hybrid modes".
- configuration.md: the `mode` field documented its value as "platform";
  now "standalone" or "hybrid", with "platform" noted as the legacy alias.

Descriptive "connected to otari.ai" prose and section headings are left as
accurate descriptions of what hybrid mode does. The generated CHANGELOG is
left untouched (git-cliff owns it; entries are historical).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@njbrake
njbrake temporarily deployed to integration-tests June 22, 2026 23:17 — with GitHub Actions Inactive
Replace the three raw `status_code=503` literals in the readiness handler
with `status.HTTP_503_SERVICE_UNAVAILABLE`, per the project's FastAPI
conventions (CodeRabbit). Import `status` from fastapi.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.

Rename "platform mode" to a non-legacy term

3 participants