mirror of
https://github.com/tinyhumansai/openhuman.git
synced 2026-07-27 21:08:00 +00:00
fix: allow Medulla to message accepted contacts (#4824)
This commit is contained in:
@@ -251,6 +251,17 @@ async fn contact_status(agent_id: &str) -> Result<String, String> {
|
||||
Ok(remote_status(&remote).unwrap_or_else(|| "none".to_string()))
|
||||
}
|
||||
|
||||
/// Whether the peer is an accepted tiny.place contact.
|
||||
///
|
||||
/// This is intentionally a live relay check rather than a read of the local
|
||||
/// orchestration pairing store. An accepted contact is already a
|
||||
/// user-consented recipient for an outbound message, even when it has not been
|
||||
/// linked as an inbound orchestration session in the current workspace.
|
||||
pub(crate) async fn is_accepted_contact(agent_id: &str) -> Result<bool, String> {
|
||||
let agent_id = normalize_agent_id(agent_id)?;
|
||||
Ok(contact_status(&agent_id).await? == "accepted")
|
||||
}
|
||||
|
||||
fn remote_status(value: &Value) -> Option<String> {
|
||||
value
|
||||
.get("status")
|
||||
|
||||
@@ -92,6 +92,14 @@ fn required_str(args: &Value, field: &str) -> Result<String, ToolResult> {
|
||||
}
|
||||
}
|
||||
|
||||
fn recipient_may_receive_message(
|
||||
locally_linked: bool,
|
||||
has_known_session: bool,
|
||||
accepted_contact: bool,
|
||||
) -> bool {
|
||||
locally_linked || has_known_session || accepted_contact
|
||||
}
|
||||
|
||||
// ── Reasoning-core session-history read tools (Master chat) ──────────────────
|
||||
|
||||
/// Default / cap on how many messages a `orchestration_read_session` call returns.
|
||||
@@ -473,15 +481,39 @@ impl Tool for SendToAgentTool {
|
||||
|
||||
let workspace = self.config.workspace_dir.clone();
|
||||
|
||||
// Guardrail: linked peer OR an existing session with them. Never cold-DM
|
||||
// an arbitrary new address from this un-gated background origin.
|
||||
// Guardrail: locally linked peer, accepted tiny.place contact, OR an
|
||||
// existing session with them. Never cold-DM an arbitrary new address
|
||||
// from this un-gated background origin. The live contact check matters
|
||||
// after login changes the workspace: the relay contact remains accepted
|
||||
// while the workspace-local orchestration pairing/session stores start
|
||||
// empty.
|
||||
let linked =
|
||||
crate::openhuman::agent_orchestration::pairing::linked_agent_ids(&workspace).await;
|
||||
let known_session = store::with_connection(&workspace, |conn| {
|
||||
store::latest_session_for_agent(conn, &recipient)
|
||||
})
|
||||
.map_err(|e| anyhow::anyhow!("lookup session: {e}"))?;
|
||||
if !linked.contains(&recipient) && known_session.is_none() {
|
||||
let accepted_contact = if linked.contains(&recipient) || known_session.is_some() {
|
||||
false
|
||||
} else {
|
||||
match crate::openhuman::agent_orchestration::pairing::is_accepted_contact(&recipient)
|
||||
.await
|
||||
{
|
||||
Ok(accepted) => accepted,
|
||||
Err(e) => {
|
||||
log::warn!(
|
||||
target: "orchestration",
|
||||
"[orchestration] tool.send_to_agent contact check failed: {e}"
|
||||
);
|
||||
false
|
||||
}
|
||||
}
|
||||
};
|
||||
if !recipient_may_receive_message(
|
||||
linked.contains(&recipient),
|
||||
known_session.is_some(),
|
||||
accepted_contact,
|
||||
) {
|
||||
log::debug!(
|
||||
target: "orchestration",
|
||||
"[orchestration] tool.send_to_agent refused unlinked recipient",
|
||||
@@ -827,4 +859,12 @@ mod tests {
|
||||
assert!(out.is_error);
|
||||
assert!(out.text().contains("not a linked"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn accepted_contact_can_receive_without_workspace_pairing_or_session() {
|
||||
assert!(recipient_may_receive_message(false, false, true));
|
||||
assert!(recipient_may_receive_message(true, false, false));
|
||||
assert!(recipient_may_receive_message(false, true, false));
|
||||
assert!(!recipient_may_receive_message(false, false, false));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user