diff --git a/tests/gateway_workflow_integration.rs b/tests/gateway_workflow_integration.rs index edf7de91..372cfdf8 100644 --- a/tests/gateway_workflow_integration.rs +++ b/tests/gateway_workflow_integration.rs @@ -30,15 +30,11 @@ mod tests { "name": "wf-ci-webhook-demo", "description": "CI webhook workflow demo", "trigger_type": "system_event", - "trigger": { - "source": "github", - "event_type": "issue.opened", - "filters": {"repository": "nearai/ironclaw"} - }, + "event_source": "github", + "event_type": "issue.opened", + "event_filters": {"repository": "nearai/ironclaw"}, "action_type": "lightweight", - "action": { - "prompt": "Summarize webhook and report issue number" - } + "prompt": "Summarize webhook and report issue number" }), )]), )) @@ -69,6 +65,30 @@ mod tests { harness .send_chat(&thread_id, "create workflow routine") .await; + harness + .wait_for_turns(&thread_id, 1, Duration::from_secs(10)) + .await; + + let mut routine = None; + for _ in 0..30 { + routine = harness.routine_by_name("wf-ci-webhook-demo").await; + if routine.is_some() { + break; + } + tokio::time::sleep(Duration::from_millis(100)).await; + } + let routine = if let Some(r) = routine { + r + } else { + let history_dbg = harness.history(&thread_id).await; + let started_dbg = harness.test_channel.tool_calls_started(); + let requests_dbg = mock.requests().await; + panic!( + "routine not created; tool_calls_started={started_dbg:?}; history={history_dbg}; mock_requests={requests_dbg:?}" + ); + }; + let routine_id = routine["id"].as_str().expect("routine id missing"); + harness.send_chat(&thread_id, "emit webhook event").await; let history = harness @@ -77,12 +97,6 @@ mod tests { let turns = history["turns"].as_array().expect("turns array missing"); assert!(turns.len() >= 2, "expected at least 2 turns"); - let routine = harness - .routine_by_name("wf-ci-webhook-demo") - .await - .expect("routine not created"); - let routine_id = routine["id"].as_str().expect("routine id missing"); - let runs_before = harness.routine_runs(routine_id).await; let before_count = runs_before["runs"] .as_array() diff --git a/tests/support/gateway_workflow_harness.rs b/tests/support/gateway_workflow_harness.rs index 77d53ac1..a1563f0e 100644 --- a/tests/support/gateway_workflow_harness.rs +++ b/tests/support/gateway_workflow_harness.rs @@ -17,8 +17,7 @@ use ironclaw::channels::web::server::{GatewayState, RateLimiter, start_server}; use ironclaw::channels::web::sse::SseManager; use ironclaw::channels::web::ws::WsConnectionTracker; use ironclaw::channels::{Channel, IncomingMessage, MessageStream}; -use ironclaw::config::llm::RegistryProviderConfig; -use ironclaw::config::{Config, RoutineConfig}; +use ironclaw::config::{Config, RegistryProviderConfig, RoutineConfig}; use ironclaw::context::ContextManager; use ironclaw::db::Database; use ironclaw::db::libsql::LibSqlBackend; diff --git a/tests/support/mock_openai_server.rs b/tests/support/mock_openai_server.rs index 4d9e0117..2a64c018 100644 --- a/tests/support/mock_openai_server.rs +++ b/tests/support/mock_openai_server.rs @@ -198,15 +198,37 @@ async fn chat_completions_handler( .and_then(|r| r.as_str()) .unwrap_or_default(); + fn extract_text_content(msg: &Value) -> Option { + let content = msg.get("content")?; + if let Some(s) = content.as_str() { + return Some(s.to_string()); + } + if let Some(parts) = content.as_array() { + let mut out = String::new(); + for part in parts { + if part.get("type").and_then(|v| v.as_str()) == Some("text") + && let Some(text) = part.get("text").and_then(|v| v.as_str()) + { + if !out.is_empty() { + out.push(' '); + } + out.push_str(text); + } + } + if !out.is_empty() { + return Some(out); + } + } + None + } + let latest_user = body .pointer("/messages") .and_then(|m| m.as_array()) .and_then(|arr| { arr.iter().rev().find_map(|msg| { if msg.get("role").and_then(|r| r.as_str()) == Some("user") { - msg.get("content") - .and_then(|c| c.as_str()) - .map(ToOwned::to_owned) + extract_text_content(msg) } else { None } @@ -215,10 +237,11 @@ async fn chat_completions_handler( .unwrap_or_default(); let selected = if last_role == "user" { + let latest_user_lower = latest_user.to_ascii_lowercase(); state .rules .iter() - .find(|r| latest_user.contains(&r.contains)) + .find(|r| latest_user_lower.contains(&r.contains.to_ascii_lowercase())) .map(|r| r.response.clone()) .unwrap_or_else(|| state.default_response.clone()) } else {