From 66db2de72ac0d133a4aa4b8d9ca981640168d1ad Mon Sep 17 00:00:00 2001 From: Steven Enamakel Date: Sun, 20 Sep 2026 21:10:49 +0300 Subject: [PATCH] fix: target Tiny Humans direct System One route Co-authored-by: Medulla --- README.md | 2 +- crates/tinyjevclient/src/client/README.md | 2 +- crates/tinyjevclient/src/client/mod.rs | 3 +-- crates/tinyjevclient/src/client/test.rs | 9 +++++---- crates/tinyjevclient/src/client/types.rs | 13 +++++++++++-- docs/specs/system-one-client.md | 6 +++--- 6 files changed, 22 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 9b02314..061039b 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ response. For a Tiny Humans API key, use `ClientConfig::tinyhumans_openrouter("")`, which explicitly targets -`https://api.tinyhumans.ai/agent-integrations/openrouter/v1/systemone`. +`https://api.tinyhumans.ai/agent-integrations/openrouter/systemone`. Remote API roots must use HTTPS; HTTP is reserved for literal loopback IPs. Failed evaluations retain their classified error, attempt count, and elapsed diff --git a/crates/tinyjevclient/src/client/README.md b/crates/tinyjevclient/src/client/README.md index dacd9b3..c05dfd6 100644 --- a/crates/tinyjevclient/src/client/README.md +++ b/crates/tinyjevclient/src/client/README.md @@ -17,4 +17,4 @@ are terminal, and automatic redirects are disabled. `https://openrouter.ai/api/v1/systemone`. `ClientConfig::tinyhumans_openrouter` targets the Tiny Humans OpenRouter proxy -at `https://api.tinyhumans.ai/agent-integrations/openrouter/v1/systemone`. +at `https://api.tinyhumans.ai/agent-integrations/openrouter/systemone`. diff --git a/crates/tinyjevclient/src/client/mod.rs b/crates/tinyjevclient/src/client/mod.rs index 20d6976..c9a6c90 100644 --- a/crates/tinyjevclient/src/client/mod.rs +++ b/crates/tinyjevclient/src/client/mod.rs @@ -13,7 +13,6 @@ use reqwest::{StatusCode, header::RETRY_AFTER}; use crate::{Error, EvaluationRequest, EvaluationResponse, Result}; -const SYSTEM_ONE_PATH: &str = "v1/systemone"; const MAX_RETRIES: u32 = 100; impl Client { @@ -113,7 +112,7 @@ impl Client { let url = format!( "{}/{}", self.config.base_url.trim_end_matches('/'), - SYSTEM_ONE_PATH + self.config.system_one_path ); let response = self .http diff --git a/crates/tinyjevclient/src/client/test.rs b/crates/tinyjevclient/src/client/test.rs index 4c15bc0..572fb1f 100644 --- a/crates/tinyjevclient/src/client/test.rs +++ b/crates/tinyjevclient/src/client/test.rs @@ -152,7 +152,7 @@ async fn openrouter_uses_system_one_and_accepts_a_resolved_jev_model() { } #[tokio::test] -async fn tinyhumans_proxy_uses_the_compatibility_system_one_path() { +async fn tinyhumans_proxy_uses_the_direct_system_one_path() { let (base_url, requests) = server(vec![response( 200, &success().replace("jev-latest", "typesafe/jev-1.13-20260917"), @@ -173,7 +173,7 @@ async fn tinyhumans_proxy_uses_the_compatibility_system_one_path() { .lock() .await .join("") - .starts_with("POST /v1/systemone HTTP/1.1") + .starts_with("POST /agent-integrations/openrouter/systemone HTTP/1.1") ); } @@ -272,9 +272,10 @@ fn validates_every_configuration_bound_and_redacted_key_replacement() { assert_eq!(openrouter.base_url, "https://openrouter.ai/api"); assert_eq!(openrouter.provider, Provider::OpenRouter); let tinyhumans = ClientConfig::tinyhumans_openrouter("key"); + assert_eq!(tinyhumans.base_url, "https://api.tinyhumans.ai"); assert_eq!( - tinyhumans.base_url, - "https://api.tinyhumans.ai/agent-integrations/openrouter" + tinyhumans.system_one_path, + "agent-integrations/openrouter/systemone" ); assert_eq!(tinyhumans.provider, Provider::OpenRouter); let mut ipv6_loopback = ClientConfig::new("key"); diff --git a/crates/tinyjevclient/src/client/types.rs b/crates/tinyjevclient/src/client/types.rs index 4d5ad53..350001f 100644 --- a/crates/tinyjevclient/src/client/types.rs +++ b/crates/tinyjevclient/src/client/types.rs @@ -4,6 +4,9 @@ use std::{fmt, time::Duration}; use crate::{Error, EvaluationResponse}; +const DEFAULT_SYSTEM_ONE_PATH: &str = "v1/systemone"; +const TINYHUMANS_SYSTEM_ONE_PATH: &str = "agent-integrations/openrouter/systemone"; + /// System One API provider. #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)] pub enum Provider { @@ -33,8 +36,10 @@ impl fmt::Debug for Client { #[derive(Clone)] pub struct ClientConfig { pub(super) api_key: ApiKey, - /// API root without the versioned endpoint path. + /// API origin or path prefix without the System One endpoint path. pub base_url: String, + /// Provider-specific System One endpoint path. + pub(super) system_one_path: &'static str, /// Provider-specific response validation behavior. pub provider: Provider, /// Total timeout for one HTTP attempt. @@ -50,6 +55,7 @@ impl ClientConfig { Self { api_key: ApiKey(api_key.into()), base_url: "https://api.typesafe.ai".to_owned(), + system_one_path: DEFAULT_SYSTEM_ONE_PATH, provider: Provider::TypeSafe, timeout: Duration::from_secs(30), retry: RetryPolicy::default(), @@ -62,6 +68,7 @@ impl ClientConfig { Self { api_key: ApiKey(api_key.into()), base_url: "https://openrouter.ai/api".to_owned(), + system_one_path: DEFAULT_SYSTEM_ONE_PATH, provider: Provider::OpenRouter, timeout: Duration::from_secs(30), retry: RetryPolicy::default(), @@ -76,7 +83,8 @@ impl ClientConfig { pub fn tinyhumans_openrouter(api_key: impl Into) -> Self { Self { api_key: ApiKey(api_key.into()), - base_url: "https://api.tinyhumans.ai/agent-integrations/openrouter".to_owned(), + base_url: "https://api.tinyhumans.ai".to_owned(), + system_one_path: TINYHUMANS_SYSTEM_ONE_PATH, provider: Provider::OpenRouter, timeout: Duration::from_secs(30), retry: RetryPolicy::default(), @@ -96,6 +104,7 @@ impl fmt::Debug for ClientConfig { f.debug_struct("ClientConfig") .field("api_key", &"[REDACTED]") .field("base_url", &self.base_url) + .field("system_one_path", &self.system_one_path) .field("provider", &self.provider) .field("timeout", &self.timeout) .field("retry", &self.retry) diff --git a/docs/specs/system-one-client.md b/docs/specs/system-one-client.md index 7c26449..ce11898 100644 --- a/docs/specs/system-one-client.md +++ b/docs/specs/system-one-client.md @@ -54,9 +54,9 @@ loopback IP addresses used by local test servers. `https://openrouter.ai/api`. The first-party constructor and `Client::from_env` retain the `TypeSafe` endpoint and `TYPESAFE_API_KEY` behavior. -`ClientConfig::tinyhumans_openrouter` uses Tiny Humans' OpenRouter proxy base -URL, `https://api.tinyhumans.ai/agent-integrations/openrouter`, and -accepts the key supplied explicitly to its constructor. +`ClientConfig::tinyhumans_openrouter` uses the Tiny Humans OpenRouter System One +endpoint, `https://api.tinyhumans.ai/agent-integrations/openrouter/systemone`, +and accepts the key supplied explicitly to its constructor. Authentication, request validation, response decoding, and non-connect transport failures are terminal. Timeouts, connection-establishment failures,