diff --git a/src/openhuman/agent/harness/payload_summarizer.rs b/src/openhuman/agent/harness/payload_summarizer.rs index 065953f8c..7c1c26c5b 100644 --- a/src/openhuman/agent/harness/payload_summarizer.rs +++ b/src/openhuman/agent/harness/payload_summarizer.rs @@ -443,11 +443,11 @@ mod tests { #[test] fn build_summarizer_prompt_includes_tool_name_and_hint() { let prompt = build_summarizer_prompt( - "GITHUB_LIST_ISSUES", + "GITHUB_LIST_REPOSITORY_ISSUES", Some("find the most urgent open issues"), "{\"issues\": [{\"id\": 1}]}", ); - assert!(prompt.contains("GITHUB_LIST_ISSUES")); + assert!(prompt.contains("GITHUB_LIST_REPOSITORY_ISSUES")); assert!(prompt.contains("find the most urgent open issues")); assert!(prompt.contains("Parent task hint:")); assert!(prompt.contains("--- BEGIN ---")); diff --git a/src/openhuman/composio/auth_retry_tests.rs b/src/openhuman/composio/auth_retry_tests.rs index 185d3d1b9..9512b91a6 100644 --- a/src/openhuman/composio/auth_retry_tests.rs +++ b/src/openhuman/composio/auth_retry_tests.rs @@ -168,7 +168,7 @@ async fn does_not_retry_on_first_attempt_success() { let resp = execute_with_auth_retry_inner( &client, - "GITHUB_USERS_GET_AUTHENTICATED", + "GITHUB_GET_THE_AUTHENTICATED_USER", None, Duration::from_secs(60), // would hang the test if we ever slept ) diff --git a/src/openhuman/memory_sync/composio/providers/github/tests.rs b/src/openhuman/memory_sync/composio/providers/github/tests.rs index 34bcc989b..1aa30e584 100644 --- a/src/openhuman/memory_sync/composio/providers/github/tests.rs +++ b/src/openhuman/memory_sync/composio/providers/github/tests.rs @@ -1,10 +1,11 @@ //! Unit tests for the GitHub Composio provider. -use super::provider::build_search_query; +use super::provider::{build_search_query, ACTION_GET_AUTHENTICATED_USER, ACTION_SEARCH_ISSUES}; use super::sync::{ extract_issue_id, extract_issue_title, extract_issue_updated_at, extract_issues, extract_user_login, }; +use super::tools::GITHUB_CURATED; use super::GitHubProvider; use crate::openhuman::memory_sync::composio::providers::ComposioProvider; use serde_json::json; @@ -231,3 +232,89 @@ fn build_search_query_interpolates_login_verbatim() { assert!(query.contains("involves:Hyphen-User_99")); assert!(query.contains("updated:>2026-01-02T03:04:05Z")); } + +// ── slug regression tests (#2768) ─────────────────────────────────────────── +// +// Guard the current Composio action slug values used by the GitHub provider. +// Outdated slugs (e.g. GITHUB_USERS_GET_AUTHENTICATED, GITHUB_LIST_REPOS, +// GITHUB_LIST_ISSUES) were previously scattered across tests; these assertions +// pin the correct values in one place so a slug rename is caught immediately. + +#[test] +fn action_get_authenticated_user_slug_is_current() { + // The Composio v3 slug is GITHUB_GET_THE_AUTHENTICATED_USER. + // Regression: was mistakenly referenced as GITHUB_USERS_GET_AUTHENTICATED + // in tests (see issue #2768). + assert_eq!( + ACTION_GET_AUTHENTICATED_USER, "GITHUB_GET_THE_AUTHENTICATED_USER", + "slug must match Composio v3 catalog; old slug GITHUB_USERS_GET_AUTHENTICATED is retired" + ); +} + +#[test] +fn action_search_issues_slug_is_current() { + assert_eq!( + ACTION_SEARCH_ISSUES, "GITHUB_SEARCH_ISSUES_AND_PULL_REQUESTS", + "slug must match Composio v3 catalog" + ); +} + +#[test] +fn curated_list_does_not_contain_retired_slugs() { + // Guard against re-introducing removed slugs that no longer exist in the + // Composio v3 GitHub app catalog. + const RETIRED: &[&str] = &[ + "GITHUB_USERS_GET_AUTHENTICATED", // replaced by GITHUB_GET_THE_AUTHENTICATED_USER + "GITHUB_LIST_REPOS", // replaced by GITHUB_LIST_REPOSITORIES_FOR_THE_AUTHENTICATED_USER + "GITHUB_LIST_ISSUES", // replaced by GITHUB_LIST_REPOSITORY_ISSUES + "GITHUB_COMMIT_MULTIPLE_FILES", // removed from Composio catalog + "GITHUB_CLOSE_AN_ISSUE", // removed; use GITHUB_UPDATE_AN_ISSUE with state=closed + "GITHUB_DELETE_A_BRANCH", // removed; use GITHUB_DELETE_A_REFERENCE + ]; + + let slugs: Vec<&str> = GITHUB_CURATED.iter().map(|t| t.slug).collect(); + for retired in RETIRED { + assert!( + !slugs.contains(retired), + "curated list must not contain retired slug {retired} (see #2768)" + ); + } +} + +#[test] +fn curated_list_contains_current_read_slugs() { + // Verify that the primary read-tier actions are present with their correct + // v3 slug names (not the old v1/v2 names). + let slugs: Vec<&str> = GITHUB_CURATED.iter().map(|t| t.slug).collect(); + let required = [ + "GITHUB_GET_THE_AUTHENTICATED_USER", + "GITHUB_LIST_REPOSITORIES_FOR_THE_AUTHENTICATED_USER", + "GITHUB_LIST_REPOSITORY_ISSUES", + "GITHUB_SEARCH_ISSUES_AND_PULL_REQUESTS", + "GITHUB_LIST_PULL_REQUESTS", + "GITHUB_GET_A_PULL_REQUEST", + ]; + for slug in required { + assert!( + slugs.contains(&slug), + "curated list must contain current slug {slug} (see #2768)" + ); + } +} + +#[test] +fn curated_list_contains_current_write_slugs() { + let slugs: Vec<&str> = GITHUB_CURATED.iter().map(|t| t.slug).collect(); + let required = [ + "GITHUB_CREATE_AN_ISSUE", + "GITHUB_UPDATE_AN_ISSUE", + "GITHUB_CREATE_A_PULL_REQUEST", + "GITHUB_MERGE_A_PULL_REQUEST", + ]; + for slug in required { + assert!( + slugs.contains(&slug), + "curated list must contain current write slug {slug} (see #2768)" + ); + } +} diff --git a/src/openhuman/tools/impl/network/composio_tests.rs b/src/openhuman/tools/impl/network/composio_tests.rs index b1a9b82da..4aeee9670 100644 --- a/src/openhuman/tools/impl/network/composio_tests.rs +++ b/src/openhuman/tools/impl/network/composio_tests.rs @@ -96,7 +96,7 @@ async fn execute_blocked_in_readonly_mode() { let result = tool .execute(json!({ "action": "execute", - "action_name": "GITHUB_LIST_REPOS" + "action_name": "GITHUB_LIST_REPOSITORIES_FOR_THE_AUTHENTICATED_USER" })) .await .unwrap(); @@ -114,7 +114,7 @@ async fn execute_blocked_when_rate_limited() { let result = tool .execute(json!({ "action": "execute", - "action_name": "GITHUB_LIST_REPOS" + "action_name": "GITHUB_LIST_REPOSITORIES_FOR_THE_AUTHENTICATED_USER" })) .await .unwrap();