feat(product): identify this crate's backend traffic as opencompany - #513
feat(product): identify this crate's backend traffic as opencompany#513YellowSnnowmann wants to merge 5 commits into
Conversation
OpenCompany, OpenHuman and Medulla share a single TinyHumans login, so the backend cannot attribute a request to a product from credentials alone. Every backend-bound request this process makes now carries `x-sdk-name: opencompany`, which the backend already parses. OpenCompany reaches the backend two ways, and they need separate treatment: - Through the embedded `openhuman_core`, whose `IntegrationClient` backs the media, Composio and web-search tools. One `install_into_embedded_core()` call during startup covers all of them. It has to run before any company runtime, agent harness or HTTP listener exists, because core reads the identity into a client's default headers at construction and would not retroactively re-tag a client that already exists. - Through this crate's own `reqwest` clients, which bypass `openhuman_core` entirely and inherit nothing from that call. These carry the majority of the traffic, including the sole production inference path, so each attaches the header itself: `HostedProvider`, `HostedEmbeddings`, the Medulla `HttpSocketTransport`, the feedback hub client, and the hub identity exchange. `request_plan` attaches the header only when the provider is `managed`. The other three `INFERENCE_PROVIDERS` are bring-your-own-key endpoints pointed at OpenAI, OpenRouter, DeepSeek or a self-hosted Ollama; sending them our product identity would disclose which TinyHumans product a tenant runs to a company with no relationship to us, and buy nothing. A test pins the negative case. `src/product.rs` is the single source of truth for the string, so `feedback::tinyhumans::PRODUCT` re-exports it rather than keeping a second literal. The module is deliberately ungated: `harness/` sits behind the `openhuman` feature but `brain/` and `feedback/` do not, and both need the constant. Only the core-interop function is feature-gated. `install_into_embedded_core` lives in the library rather than inline in the binary so a test can reach it — the binary's `serve` arm cannot be exercised from one, and an untested call is exactly where a product-attribution bug would sit unnoticed, since nothing misbehaves when the identity is wrong. Traffic is just silently counted as another product's. The submodule pin is intentionally not bumped here: the API this consumes lands in tinyhumansai/openhuman#5437, and pinning `vendor/openhuman` at an unmerged branch commit would dangle once that branch is rebased or squashed. Verified locally against that branch with the pin moved in the working tree only.
|
Warning Review limit reached
Next review available in: 24 minutes You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?After more reviews become available, a review can be triggered using the 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 reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughOpenCompany now centralizes its ChangesProduct identity setup
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant OpenCompany
participant openhuman_core
participant Backend
OpenCompany->>openhuman_core: Install opencompany identity
OpenCompany->>Backend: Send backend request with x-sdk-name: opencompany
Backend-->>OpenCompany: Return existing response
Possibly related issues
Suggested reviewers: Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
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.
Your trial has ended. Reactivate Greptile to resume code reviews.
|
@coderabbitai review |
|
Updated the pinned commit for the openhuman subproject to incorporate upstream changes. Auto-committed-on: dragonfly Co-authored-by: Medulla <medulla@tinyhumans.ai>
Updates the version of the openhuman crate in the lock file from 0.63.6 to 0.63.7 to reflect a new release. Auto-committed-on: dragonfly Co-authored-by: Medulla <medulla@tinyhumans.ai>
There was a problem hiding this comment.
tinysweeper found nothing blocking. Approving.
$0.0041 · 54,382 in / 13,624 out · 47,519 cached (87%) · z-ai/glm-5.2
critique: $0.0016 · 10,292 in / 6,553 out · 9,159 cached (89%) · z-ai/glm-5.2
security: $0.0010 · 21,725 in / 2,637 out · 18,783 cached (86%) · z-ai/glm-5.2
tests: $0.0008 · 10,308 in / 2,723 out · 8,967 cached (87%) · z-ai/glm-5.2
description: $0.0006 · 12,057 in / 1,711 out · 10,610 cached (88%) · z-ai/glm-5.2
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/harness/embeddings.rs (1)
515-516: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low valueApply
rustfmtto this method chain.Indent the
.map()and.collect()calls as continuations of line 514. The changed test code must use standardrustfmtoutput.🤖 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 `@src/harness/embeddings.rs` around lines 515 - 516, Run rustfmt on the method chain in the affected test, ensuring the map and collect calls are indented as continuations of the preceding line according to standard Rust formatting.Source: Coding guidelines
🤖 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/brain/medulla/http.rs`:
- Around line 70-81: Add focused local HTTP capture tests for each direct
transport and assert the exact centralized product-identity header value: in
src/brain/medulla/http.rs:70-81 cover the Medulla POST, in
src/feedback/tinyhumans.rs:229-241 cover feedback ingest, in
src/harness/provider.rs:674-687 cover HostedProvider::invoke, and in
src/server/hub_identity.rs:285-297 cover the /auth/me request. Keep each test
near its exercised module; no production behavior change is required.
---
Nitpick comments:
In `@src/harness/embeddings.rs`:
- Around line 515-516: Run rustfmt on the method chain in the affected test,
ensuring the map and collect calls are indented as continuations of the
preceding line according to standard Rust formatting.
🪄 Autofix
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: d1ef6551-63da-4298-8202-84affb5b280c
⛔ Files ignored due to path filters (1)
Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (10)
src/bin/opencompany.rssrc/brain/medulla/http.rssrc/feedback/tinyhumans.rssrc/harness/embeddings.rssrc/harness/provider.rssrc/lib.rssrc/product.rssrc/server/hub_identity.rstests/product_identity.rsvendor/openhuman
…voke Co-authored-by: Medulla <medulla@tinyhumans.ai>
There was a problem hiding this comment.
tinysweeper found nothing blocking. Approving.
$0.0041 · 74,284 in / 9,272 out · 56,061 cached (75%) · openrouter/openai/text-embedding-3-small, z-ai/glm-5.2 · 677 embedded
critique: $0.0023 · 29,619 in / 5,225 out · 16,953 cached (57%) · z-ai/glm-5.2
security: $0.0005 · 12,481 in / 1,394 out · 11,108 cached (89%) · z-ai/glm-5.2
tests: $0.0008 · 19,069 in / 1,955 out · 16,590 cached (87%) · z-ai/glm-5.2
description: $0.0004 · 13,115 in / 698 out · 11,410 cached (87%) · z-ai/glm-5.2
| self.config.base_url.trim_end_matches('/') | ||
| ); | ||
| let mut http = self.client.post(&url).json(&body); | ||
| let (product_header_name, product_header_value) = crate::product::product_identity_header(); |
There was a problem hiding this comment.
Verify HostedProvider is never used for third-party providers
The PR adds the product-identity header unconditionally to every request HostedProvider::invoke makes, with a comment asserting it "always speaks to the TinyHumans-owned managed endpoint." But the same file's request_plan function carefully gates the same header on decl.provider == "managed" only, explicitly excluding openrouter, openai_compatible, and ollama as third-party BYOK endpoints that must never see the product identity. If HostedProvider is ever constructed for one of those non-managed providers — and HostedProviderConfig.base_url is clearly configurable rather than pinned to DEFAULT_TINYHUMANS_INFERENCE_URL — the unconditional .header() in invoke defeats the third-party guard in request_plan and leaks x-sdk-name: opencompany to an external operator. The two code paths disagree about which providers HostedProvider serves, and one of them is wrong. If HostedProvider truly only serves managed, the request_plan branch for managed is redundant with invoke's unconditional header (and would duplicate it if extra_headers is populated from request_plan's output). If it serves other providers too, the unconditional header is a privacy leak.
[RULE] Return Result<T> using the crate error type from src/error.rs. ·
Important
Blocked on tinyhumansai/openhuman#5437 merging. That PR adds the
openhuman_core::api::product_identitysurface this consumes; until it lands andvendor/openhumanis bumped to include it, this branch does not compile. The pin bump is deliberately not part of this diff — see Submodule pin below.Summary
Attributes this process's TinyHumans backend traffic to
opencompanyvia thex-sdk-nameheader, so the backend can tell OpenCompany users apart from OpenHuman and Medulla users who share the same login.Two halves, because OpenCompany reaches the backend two different ways:
install_into_embedded_core()call during startup setsopenhuman_core's process-wide product identity, which tags everyIntegrationClientthe harness builds (media, Composio, web search).reqwestclients — five call sites that bypassopenhuman_coreentirely and therefore inherit nothing from that call. These are the majority of OpenCompany's backend traffic, including the sole production inference path.src/product.rsis the single source of truth for the string"opencompany";feedback::tinyhumans::PRODUCTnow re-exports it instead of holding a second literal.API Or Behavior Changes
No breaking changes. No public signature changes, no removals.
feedback::tinyhumans::PRODUCTkeeps its type and value — only its definition moved behindcrate::product::PRODUCT_IDENTITY.New public API (all additive):
opencompany::product::{PRODUCT_IDENTITY, PRODUCT_IDENTITY_HEADER, product_identity_header, install_into_embedded_core}. The module is ungated;install_into_embedded_coreis#[cfg(feature = "openhuman")].Behavior change: requests to the TinyHumans backend now carry one additional ~20-byte header. Nothing observable changes yet — the backend currently discards the value (
extractSdkSourceFromRequesthas no production caller, andtrackUsage.tsdestructuressdkSourceonly to drop it), so this is inert until tinyhumansai/backend#1214 lands.Where the header is and is not attached
openhuman_core'sIntegrationClient(media / Composio / search)install_into_embedded_coreHostedProvider(harness/provider.rs)api.tinyhumans.ai/openai/v1— the sole production inference pathTenantProviderviarequest_planprovider == "managed"HostedEmbeddings(harness/embeddings.rs)HttpSocketTransport(brain/medulla/http.rs)api.tinyhumans.ai/orchestration/v1post_jsonhelper covers/eventsand/world-diffHttpTinyHumansClient(feedback/tinyhumans.rs){api_url}/feedback/ingestHttpHubIdentityExchange(server/hub_identity.rs){api_url}/auth/meserver/ops/connections.rs)login_start_url(server/hub_identity.rs)economy/client.rsapi.tiny.place— a different serviceThe
provider == "managed"condition is the load-bearing decision here.INFERENCE_PROVIDERSis["managed", "openrouter", "openai_compatible", "ollama"]; onlymanagedis TinyHumans-owned. The other three are bring-your-own-key endpoints an operator points at OpenAI, OpenRouter, DeepSeek or a self-hosted Ollama. Sending themx-sdk-namewould disclose which TinyHumans product a tenant runs to a company with no relationship to us, for no benefit to anyone. There is an explicit negative test for this; please don't "simplify" it into an unconditional attach.The call site list was derived by enumerating every consumer of
AppConfig::api_url(which defaults toDEFAULT_API_URL = "https://api.tinyhumans.ai") rather than by grepping the diff, which is howHttpHubIdentityExchangewas caught — it was missed on the first pass.Tests
cargo fmt --all -- --checkcargo clippy --all-targets -- -D warningscargo build --all-targetscargo testRun as
--features openhuman,tinycortex(the gated lane), since everything here is behind that feature set.Added:
tests/product_identity.rs— the acceptance criterion proper: asserts the identity is the inheritedopenhumandefault beforeinstall_into_embedded_core()andopencompanyafter. The before-assertion is the half that carries the weight; without it the test would still pass if the call were deleted outright. An integration target rather than a unit test because core's identity is process-global — an in-crate test would share it with parallel unit tests and the ordering assertion would surface as a flake. Gated onopenhumanalone soscripts/ci/assert-integration-targets-run.shsees a non-zero count rather than an empty binary.src/product.rs— drift guard asserting our header name equalsopenhuman_core::api::PRODUCT_IDENTITY_HEADERand our identity differs from its default, so the two crates cannot diverge silently; plus a pin thatfeedback::tinyhumans::PRODUCTstays wired to the shared constant, so the duplicate literal cannot come back.harness/provider.rs—request_planattaches the header formanaged, and does not foropenrouter(whose own attribution headers are asserted unaffected) oropenai_compatible.harness/embeddings.rs— wire-level proof: an axum stub on an ephemeral port captures a real request and assertsx-sdk-name: opencompanyarrives.HostedEmbeddingswas chosen of the direct clients becauseharness/already compiles under plain--features openhuman, whereas the feedback and Medulla clients sit behind thetinyhumans/medullafeatures.Documentation
src/product.rs's module doc is the reference for this: why the header exists, why the module is ungated, why each direct client must attach it itself, and why the value is defined exactly once. No separate doc page — the rule belongs next to the constant it governs.Submodule pin
vendor/openhumanis intentionally not bumped in this diff. Theopenhuman_core::api::product_identitysurface lands in tinyhumansai/openhuman#5437, which is not yet merged. Pinning a submodule at an unmerged branch commit would leave a dangling reference the moment that branch is rebased or squashed on merge.Verified locally against
0574d1ca9(the #5437 head) with the pin moved in the working tree only.tinyagentslockstep holds at that commit —vendor/openhuman's own pin and this repo's are both3e1dbea5, so the eventual bump should not need to movetinyagents.Sequence to land: merge #5437 → bump
vendor/openhumanto amaincommit containing it → CI green here → merge this.Related
Closes #376
Part of per-product Discord roles across TinyHumans:
openhumandefault (blocks this PR)medullaidentitySummary by CodeRabbit