From e5eb0f61463acfdab2b930e1dae087a218f8d2ed Mon Sep 17 00:00:00 2001 From: Ghost Scripter Date: Fri, 10 Jul 2026 13:45:08 +0530 Subject: [PATCH] fix(orchestration): don't abort first link on 404 contact status MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `link_session` pre-checks `GET /contacts/{id}/status` before sending a connection request. That endpoint returns 404 when no contact relationship exists yet — the normal state before you have ever linked an agent. `contact_status` propagated the 404 as an error, so the "Link a new agent" UI failed with HTTP 404: /contacts//status: not found and never reached the `POST /contacts/{id}` that actually sends the request. A first-time link was therefore impossible from the UI. Treat a 404 from the status pre-check as `"none"` (no relationship yet) so `link_session` proceeds to send the request. Non-404 errors still propagate unchanged. `tinyplace::Error::status()` returns `Option`, so the 404 is matched precisely rather than by string. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/openhuman/agent_orchestration/pairing.rs | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/src/openhuman/agent_orchestration/pairing.rs b/src/openhuman/agent_orchestration/pairing.rs index bb7d612925..7e94d321d8 100644 --- a/src/openhuman/agent_orchestration/pairing.rs +++ b/src/openhuman/agent_orchestration/pairing.rs @@ -243,12 +243,25 @@ pub async fn block_request(config: &Config, agent_id: &str) -> Result Result { let client = tinyplace_state().client().await?; - let remote: Value = client + match client .http() .get_agent_auth::(&contact_path(agent_id, Some("status")), &[]) .await - .map_err(map_err)?; - Ok(remote_status(&remote).unwrap_or_else(|| "none".to_string())) + { + Ok(remote) => Ok(remote_status(&remote).unwrap_or_else(|| "none".to_string())), + // A 404 from /contacts/{id}/status means "no contact relationship yet" — + // the normal state before you've ever linked this agent. Treat it as + // `none` (not an error) so `link_session` proceeds to send the request + // instead of surfacing a false "not found" and aborting the first link. + Err(e) if e.status() == Some(404) => { + log::debug!( + target: LOG_TARGET, + "[orchestration_pairing] contact_status.none agent_id={agent_id} (404 = no relationship yet)" + ); + Ok("none".to_string()) + } + Err(e) => Err(map_err(e)), + } } fn remote_status(value: &Value) -> Option {