OSIS native SDK URL pattern incompatible with per-domain servers (always 404) #10

Closed
opened 2026-04-26 13:36:25 +00:00 by rawan · 1 comment
Member

Summary

hero_osis_sdk (via hero_rpc_client::OsisClient::new, native build) hardcodes its endpoint URL as format!("{}/rpc/{}", base_url, context) and only exposes that single constructor.

The current per-domain OSIS servers (hero_osis_ai/rpc.sock, hero_osis_base/rpc.sock, ...) only expose POST /rpc (no /{context} segment — each socket is already context-scoped). So every native SDK call lands on a 404.

This blocks hero_agent from persisting or listing conversations, audit entries, memories, messages, and usage stats — every OsisStore::* call that goes through AiClient fails.

Discovered while fixing #6 — the original bug (sidebar list shape + + button context switch) is fully fixed in hero_agent, but end-to-end verification shows the conversation never persists because the SDK calls 404.

Repro

$ curl -s -X POST -H "Content-Type: application/json" \
    -d '{"jsonrpc":"2.0","method":"agentconversation.list","id":1,"params":{}}' \
    http://127.0.0.1:9988/hero_osis_ai/rpc
{"jsonrpc":"2.0","result":"","id":1}                # works

$ curl -s -X POST -H "Content-Type: application/json" \
    -d '{"jsonrpc":"2.0","method":"agentconversation.list","id":1,"params":{}}' \
    http://127.0.0.1:9988/hero_osis_ai/rpc/default
                                                    # 404 (no body)

The SDK only ever generates the second URL.

Affected code

hero_rpc_client::OsisClient::new (native), in crates/openrpc_http_client_lib/src/lib.rs of hero_rpc development:

let endpoint = format!("{}/rpc/{}", base_url.trim_end_matches('/'), context);
let transport = OpenRpcTransport::http(&endpoint).map_err(ClientError::from)?;

The WASM build already worked around an analogous router-rewrite issue by using /osis-rpc/{context} instead — see the comment at line 188.

Proposed fix options

  1. Server-side: per-domain OSIS server adds a route POST /rpc/:context that dispatches identically to POST /rpc (ignoring the context segment, since per-domain sockets are already single-context). One-line route alias in hero_rpc_osis. SDK keeps working as-is.
  2. SDK-side: drop /{context} for native transport (URL becomes just {base_url}/rpc); WASM unchanged. Requires every SDK consumer's OSIS_URL to point at a domain-scoped base (e.g. http://router/hero_osis_ai) — hero_agent already needs that change.
  3. Both: ship server-side alias for compatibility, then migrate the SDK in a follow-up.

Option 1 is the smallest change with the broadest compatibility.

Affected consumers

Anything using the native OsisClient against a per-domain server. Confirmed: hero_agent. Likely: any other native CLI or daemon talking to a per-domain OSIS server.

Acceptance

  • Native OsisClient::rpc_call succeeds when pointed at any per-domain OSIS server (not 404).
  • Existing WASM behavior unchanged.
  • hero_agent + button creates a conversation that appears in the sidebar (verifying end-to-end).
## Summary `hero_osis_sdk` (via `hero_rpc_client::OsisClient::new`, native build) hardcodes its endpoint URL as `format!("{}/rpc/{}", base_url, context)` and only exposes that single constructor. The current per-domain OSIS servers (`hero_osis_ai/rpc.sock`, `hero_osis_base/rpc.sock`, ...) only expose `POST /rpc` (no `/{context}` segment — each socket is already context-scoped). So every native SDK call lands on a 404. This blocks `hero_agent` from persisting or listing conversations, audit entries, memories, messages, and usage stats — every `OsisStore::*` call that goes through `AiClient` fails. Discovered while fixing https://forge.ourworld.tf/lhumina_code/hero_agent/issues/6 — the original bug (sidebar list shape + `+` button context switch) is fully fixed in `hero_agent`, but end-to-end verification shows the conversation never persists because the SDK calls 404. ## Repro ``` $ curl -s -X POST -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","method":"agentconversation.list","id":1,"params":{}}' \ http://127.0.0.1:9988/hero_osis_ai/rpc {"jsonrpc":"2.0","result":"","id":1} # works $ curl -s -X POST -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","method":"agentconversation.list","id":1,"params":{}}' \ http://127.0.0.1:9988/hero_osis_ai/rpc/default # 404 (no body) ``` The SDK only ever generates the second URL. ## Affected code `hero_rpc_client::OsisClient::new` (native), in `crates/openrpc_http_client_lib/src/lib.rs` of `hero_rpc` `development`: ```rust let endpoint = format!("{}/rpc/{}", base_url.trim_end_matches('/'), context); let transport = OpenRpcTransport::http(&endpoint).map_err(ClientError::from)?; ``` The WASM build already worked around an analogous router-rewrite issue by using `/osis-rpc/{context}` instead — see the comment at line 188. ## Proposed fix options 1. **Server-side**: per-domain OSIS server adds a route `POST /rpc/:context` that dispatches identically to `POST /rpc` (ignoring the context segment, since per-domain sockets are already single-context). One-line route alias in `hero_rpc_osis`. SDK keeps working as-is. 2. **SDK-side**: drop `/{context}` for native transport (URL becomes just `{base_url}/rpc`); WASM unchanged. Requires every SDK consumer's `OSIS_URL` to point at a domain-scoped base (e.g. `http://router/hero_osis_ai`) — `hero_agent` already needs that change. 3. **Both**: ship server-side alias for compatibility, then migrate the SDK in a follow-up. Option 1 is the smallest change with the broadest compatibility. ## Affected consumers Anything using the native `OsisClient` against a per-domain server. Confirmed: `hero_agent`. Likely: any other native CLI or daemon talking to a per-domain OSIS server. ## Acceptance - [ ] Native `OsisClient::rpc_call` succeeds when pointed at any per-domain OSIS server (not 404). - [ ] Existing WASM behavior unchanged. - [ ] `hero_agent` `+` button creates a conversation that appears in the sidebar (verifying end-to-end).
Author
Member

Resolved — already fixed upstream

After investigating further, the SDK URL pattern was already updated in hero_rpc development (commit 38a0929):

let endpoint = format!(
    "{}/hero_osis_{}/rpc",
    base_url.trim_end_matches('/'),
    domain
);

This generates URLs like http://127.0.0.1:9988/hero_osis_ai/rpc — which the per-domain server happily accepts at /rpc and which hero_router proxies cleanly to hero_osis_ai/rpc.sock.

The reason hero_agent was hitting the broken path was that its Cargo.lock was pinned to an older hero_rpc commit (91c30ef) that still had format!("{}/rpc/{}", base_url, context). Bumping the lock to 38a0929 resolves the issue. hero_agent also needed OSIS_URL to point at the router root (http://127.0.0.1:9988) instead of /hero_osis/ui, so the SDK can append /hero_osis_<domain>/rpc itself.

Verified end-to-end: POST /api/conversations returns a real ID and the conversation appears in subsequent GET /api/conversations.

Closing as fixed.

## Resolved — already fixed upstream After investigating further, the SDK URL pattern was already updated in hero_rpc `development` (commit `38a0929`): ```rust let endpoint = format!( "{}/hero_osis_{}/rpc", base_url.trim_end_matches('/'), domain ); ``` This generates URLs like `http://127.0.0.1:9988/hero_osis_ai/rpc` — which the per-domain server happily accepts at `/rpc` and which hero_router proxies cleanly to `hero_osis_ai/rpc.sock`. The reason `hero_agent` was hitting the broken path was that its `Cargo.lock` was pinned to an older `hero_rpc` commit (`91c30ef`) that still had `format!("{}/rpc/{}", base_url, context)`. Bumping the lock to `38a0929` resolves the issue. `hero_agent` also needed `OSIS_URL` to point at the router root (`http://127.0.0.1:9988`) instead of `/hero_osis/ui`, so the SDK can append `/hero_osis_<domain>/rpc` itself. Verified end-to-end: `POST /api/conversations` returns a real ID and the conversation appears in subsequent `GET /api/conversations`. Closing as fixed.
rawan closed this issue 2026-04-27 08:28:14 +00:00
rawan reopened this issue 2026-04-27 08:30:08 +00:00
rawan self-assigned this 2026-04-27 09:05:35 +00:00
rawan closed this issue 2026-04-27 11:06:41 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
lhumina_code/hero_agent#10
No description provided.