fix(composio): repair v3 execute path and enable alias
This commit is contained in:
parent
a03ddc3ace
commit
4c249c579f
3 changed files with 70 additions and 12 deletions
|
|
@ -62,6 +62,20 @@ Notes:
|
||||||
- `reasoning_enabled = true` explicitly requests reasoning for supported providers (`think: true` on `ollama`).
|
- `reasoning_enabled = true` explicitly requests reasoning for supported providers (`think: true` on `ollama`).
|
||||||
- Unset keeps provider defaults.
|
- Unset keeps provider defaults.
|
||||||
|
|
||||||
|
## `[composio]`
|
||||||
|
|
||||||
|
| Key | Default | Purpose |
|
||||||
|
|---|---|---|
|
||||||
|
| `enabled` | `false` | Enable Composio managed OAuth tools |
|
||||||
|
| `api_key` | unset | Composio API key used by the `composio` tool |
|
||||||
|
| `entity_id` | `default` | Default `user_id` sent on connect/execute calls |
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
|
||||||
|
- Backward compatibility: legacy `enable = true` is accepted as an alias for `enabled = true`.
|
||||||
|
- If `enabled = false` or `api_key` is missing, the `composio` tool is not registered.
|
||||||
|
- Typical flow: call `connect`, complete browser OAuth, then run `execute` for the desired tool action.
|
||||||
|
|
||||||
## `[multimodal]`
|
## `[multimodal]`
|
||||||
|
|
||||||
| Key | Default | Purpose |
|
| Key | Default | Purpose |
|
||||||
|
|
|
||||||
|
|
@ -648,7 +648,7 @@ impl Default for GatewayConfig {
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
|
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
|
||||||
pub struct ComposioConfig {
|
pub struct ComposioConfig {
|
||||||
/// Enable Composio integration for 1000+ OAuth tools
|
/// Enable Composio integration for 1000+ OAuth tools
|
||||||
#[serde(default)]
|
#[serde(default, alias = "enable")]
|
||||||
pub enabled: bool,
|
pub enabled: bool,
|
||||||
/// Composio API key (stored encrypted when secrets.encrypt = true)
|
/// Composio API key (stored encrypted when secrets.encrypt = true)
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
|
|
@ -4418,6 +4418,17 @@ enabled = true
|
||||||
assert_eq!(parsed.entity_id, "default");
|
assert_eq!(parsed.entity_id, "default");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
async fn composio_config_enable_alias_supported() {
|
||||||
|
let toml_str = r"
|
||||||
|
enable = true
|
||||||
|
";
|
||||||
|
let parsed: ComposioConfig = toml::from_str(toml_str).unwrap();
|
||||||
|
assert!(parsed.enabled);
|
||||||
|
assert!(parsed.api_key.is_none());
|
||||||
|
assert_eq!(parsed.entity_id, "default");
|
||||||
|
}
|
||||||
|
|
||||||
// ══════════════════════════════════════════════════════════
|
// ══════════════════════════════════════════════════════════
|
||||||
// SECRETS CONFIG TESTS
|
// SECRETS CONFIG TESTS
|
||||||
// ══════════════════════════════════════════════════════════
|
// ══════════════════════════════════════════════════════════
|
||||||
|
|
|
||||||
|
|
@ -137,12 +137,29 @@ impl ComposioTool {
|
||||||
.await
|
.await
|
||||||
{
|
{
|
||||||
Ok(result) => Ok(result),
|
Ok(result) => Ok(result),
|
||||||
Err(v3_err) => match self.execute_action_v2(action_name, params, entity_id).await {
|
Err(v3_err) => {
|
||||||
Ok(result) => Ok(result),
|
let mut v2_candidates = vec![action_name.trim().to_string()];
|
||||||
Err(v2_err) => anyhow::bail!(
|
let legacy_action_name = normalize_legacy_action_name(action_name);
|
||||||
"Composio execute failed on v3 ({v3_err}) and v2 fallback ({v2_err})"
|
if !legacy_action_name.is_empty() && !v2_candidates.contains(&legacy_action_name) {
|
||||||
),
|
v2_candidates.push(legacy_action_name);
|
||||||
},
|
}
|
||||||
|
|
||||||
|
let mut v2_errors = Vec::new();
|
||||||
|
for candidate in v2_candidates {
|
||||||
|
match self
|
||||||
|
.execute_action_v2(&candidate, params.clone(), entity_id)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(result) => return Ok(result),
|
||||||
|
Err(v2_err) => v2_errors.push(format!("{candidate}: {v2_err}")),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
anyhow::bail!(
|
||||||
|
"Composio execute failed on v3 ({v3_err}) and v2 fallback attempts ({})",
|
||||||
|
v2_errors.join(" | ")
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -152,7 +169,7 @@ impl ComposioTool {
|
||||||
entity_id: Option<&str>,
|
entity_id: Option<&str>,
|
||||||
connected_account_ref: Option<&str>,
|
connected_account_ref: Option<&str>,
|
||||||
) -> (String, serde_json::Value) {
|
) -> (String, serde_json::Value) {
|
||||||
let url = format!("{COMPOSIO_API_BASE_V3}/tools/{tool_slug}/execute");
|
let url = format!("{COMPOSIO_API_BASE_V3}/tools/execute/{tool_slug}");
|
||||||
let account_ref = connected_account_ref.and_then(|candidate| {
|
let account_ref = connected_account_ref.and_then(|candidate| {
|
||||||
let trimmed_candidate = candidate.trim();
|
let trimmed_candidate = candidate.trim();
|
||||||
(!trimmed_candidate.is_empty()).then_some(trimmed_candidate)
|
(!trimmed_candidate.is_empty()).then_some(trimmed_candidate)
|
||||||
|
|
@ -606,6 +623,10 @@ fn normalize_tool_slug(action_name: &str) -> String {
|
||||||
action_name.trim().replace('_', "-").to_ascii_lowercase()
|
action_name.trim().replace('_', "-").to_ascii_lowercase()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn normalize_legacy_action_name(action_name: &str) -> String {
|
||||||
|
action_name.trim().replace('-', "_").to_ascii_uppercase()
|
||||||
|
}
|
||||||
|
|
||||||
fn map_v3_tools_to_actions(items: Vec<ComposioV3Tool>) -> Vec<ComposioAction> {
|
fn map_v3_tools_to_actions(items: Vec<ComposioV3Tool>) -> Vec<ComposioAction> {
|
||||||
items
|
items
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|
@ -966,6 +987,18 @@ mod tests {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn normalize_legacy_action_name_supports_v3_slug_input() {
|
||||||
|
assert_eq!(
|
||||||
|
normalize_legacy_action_name("gmail-fetch-emails"),
|
||||||
|
"GMAIL_FETCH_EMAILS"
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
normalize_legacy_action_name(" GITHUB_LIST_REPOS "),
|
||||||
|
"GITHUB_LIST_REPOS"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn extract_redirect_url_supports_v2_and_v3_shapes() {
|
fn extract_redirect_url_supports_v2_and_v3_shapes() {
|
||||||
let v2 = json!({"redirectUrl": "https://app.composio.dev/connect-v2"});
|
let v2 = json!({"redirectUrl": "https://app.composio.dev/connect-v2"});
|
||||||
|
|
@ -1041,10 +1074,10 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn composio_action_with_unicode() {
|
fn composio_action_with_unicode() {
|
||||||
let json_str = r#"{"name": "SLACK_SEND_MESSAGE", "appName": "slack", "description": "Send message with emoji 🎉 and unicode 中文", "enabled": true}"#;
|
let json_str = r#"{"name": "SLACK_SEND_MESSAGE", "appName": "slack", "description": "Send message with emoji 🎉 and unicode Ω", "enabled": true}"#;
|
||||||
let action: ComposioAction = serde_json::from_str(json_str).unwrap();
|
let action: ComposioAction = serde_json::from_str(json_str).unwrap();
|
||||||
assert!(action.description.as_ref().unwrap().contains("🎉"));
|
assert!(action.description.as_ref().unwrap().contains("🎉"));
|
||||||
assert!(action.description.as_ref().unwrap().contains("中文"));
|
assert!(action.description.as_ref().unwrap().contains("Ω"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -1093,7 +1126,7 @@ mod tests {
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
url,
|
url,
|
||||||
"https://backend.composio.dev/api/v3/tools/gmail-send-email/execute"
|
"https://backend.composio.dev/api/v3/tools/execute/gmail-send-email"
|
||||||
);
|
);
|
||||||
assert_eq!(body["arguments"]["to"], json!("test@example.com"));
|
assert_eq!(body["arguments"]["to"], json!("test@example.com"));
|
||||||
assert_eq!(body["user_id"], json!("workspace-user"));
|
assert_eq!(body["user_id"], json!("workspace-user"));
|
||||||
|
|
@ -1111,7 +1144,7 @@ mod tests {
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
url,
|
url,
|
||||||
"https://backend.composio.dev/api/v3/tools/github-list-repos/execute"
|
"https://backend.composio.dev/api/v3/tools/execute/github-list-repos"
|
||||||
);
|
);
|
||||||
assert_eq!(body["arguments"], json!({}));
|
assert_eq!(body["arguments"], json!({}));
|
||||||
assert!(body.get("connected_account_id").is_none());
|
assert!(body.get("connected_account_id").is_none());
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue