Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 16 additions & 16 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions crates/openfang-api/src/channel_bridge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -996,6 +996,16 @@ impl ChannelBridgeHandle for KernelBridgeAdapter {
}
msg
}

fn set_channel_context(
&self,
agent_id: openfang_types::agent::AgentId,
context: openfang_types::ChannelCallbackContext,
) {
use openfang_runtime::kernel_handle::KernelHandle as _;
self.kernel
.set_channel_context(&agent_id.to_string(), context);
}
}

/// Parse a trigger pattern string from chat into a `TriggerPattern`.
Expand Down
4 changes: 2 additions & 2 deletions crates/openfang-api/src/routes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6245,7 +6245,7 @@ pub async fn list_providers(State(state): State<Arc<AppState>>) -> impl IntoResp
// Index probe results by provider list position for O(1) lookup
let mut probe_map: HashMap<usize, openfang_runtime::provider_health::ProbeResult> =
HashMap::with_capacity(local_providers.len());
for ((idx, _, _), result) in local_providers.iter().zip(probe_results.into_iter()) {
for ((idx, _, _), result) in local_providers.iter().zip(probe_results) {
probe_map.insert(*idx, result);
}

Expand Down Expand Up @@ -11213,7 +11213,7 @@ pub async fn comms_events(
}

// Sort by timestamp descending (newest first)
comms_events.sort_by(|a, b| b.timestamp.cmp(&a.timestamp));
comms_events.sort_by_key(|e| std::cmp::Reverse(e.timestamp.clone()));
comms_events.truncate(limit);

Json(comms_events)
Expand Down
24 changes: 24 additions & 0 deletions crates/openfang-channels/src/bridge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -317,6 +317,17 @@ pub trait ChannelBridgeHandle: Send + Sync {
async fn a2a_agents_text(&self) -> String {
"A2A agents not available.".to_string()
}

/// Store the originating channel context for an agent so async callbacks
/// can deliver results back to the correct channel/user later.
/// Default: no-op (channel context tracking not available).
fn set_channel_context(
&self,
agent_id: openfang_types::agent::AgentId,
context: openfang_types::ChannelCallbackContext,
) {
let _ = (agent_id, context);
}
}

/// Per-channel rate limiter tracking message timestamps per user.
Expand Down Expand Up @@ -1018,6 +1029,19 @@ async fn dispatch_message(
return;
}

// Capture the channel callback context so async tools (e.g. a2a_send_async) can
// deliver their results back to this channel/user later via inject_async_callback.
handle.set_channel_context(
agent_id,
openfang_types::ChannelCallbackContext {
channel_type: ct_str.to_string(),
reply_to_platform_id: message.sender.platform_id.clone(),
reply_to_display_name: message.sender.display_name.clone(),
thread_id: thread_id.map(|t| t.to_string()),
agent_id: agent_id.to_string(),
},
);

// Send typing indicator (best-effort)
let _ = adapter.send_typing(&message.sender).await;

Expand Down
20 changes: 9 additions & 11 deletions crates/openfang-channels/src/irc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -326,19 +326,17 @@ impl ChannelAdapter for IrcAdapter {
}

// RPL_WELCOME (001) — registration complete, join channels
"001" => {
if !joined {
info!("IRC registered as {nick_clone}");
for ch in &channels_clone {
let join_cmd = format!("JOIN {ch}\r\n");
if let Err(e) = writer.write_all(join_cmd.as_bytes()).await {
warn!("IRC JOIN send failed: {e}");
break 'inner true;
}
info!("IRC joining {ch}");
"001" if !joined => {
info!("IRC registered as {nick_clone}");
for ch in &channels_clone {
let join_cmd = format!("JOIN {ch}\r\n");
if let Err(e) = writer.write_all(join_cmd.as_bytes()).await {
warn!("IRC JOIN send failed: {e}");
break 'inner true;
}
joined = true;
info!("IRC joining {ch}");
}
joined = true;
}

// PRIVMSG — incoming message
Expand Down
102 changes: 36 additions & 66 deletions crates/openfang-cli/src/tui/screens/agents.rs
Original file line number Diff line number Diff line change
Expand Up @@ -576,13 +576,11 @@ impl AgentSelectState {
KeyCode::Esc => {
self.sub = AgentSubScreen::CreateMethod;
}
KeyCode::Enter => {
if !self.custom_name.is_empty() {
if self.custom_desc.is_empty() {
self.custom_desc = format!("A custom {} agent", self.custom_name);
}
self.sub = AgentSubScreen::CustomDesc;
KeyCode::Enter if !self.custom_name.is_empty() => {
if self.custom_desc.is_empty() {
self.custom_desc = format!("A custom {} agent", self.custom_name);
}
self.sub = AgentSubScreen::CustomDesc;
}
KeyCode::Char(c) => {
self.custom_name.push(c);
Expand Down Expand Up @@ -641,15 +639,11 @@ impl AgentSelectState {
KeyCode::Esc => {
self.sub = AgentSubScreen::CustomPrompt;
}
KeyCode::Up | KeyCode::Char('k') => {
if self.tool_cursor > 0 {
self.tool_cursor -= 1;
}
KeyCode::Up | KeyCode::Char('k') if self.tool_cursor > 0 => {
self.tool_cursor -= 1;
}
KeyCode::Down | KeyCode::Char('j') => {
if self.tool_cursor < TOOL_OPTIONS.len() - 1 {
self.tool_cursor += 1;
}
KeyCode::Down | KeyCode::Char('j') if self.tool_cursor < TOOL_OPTIONS.len() - 1 => {
self.tool_cursor += 1;
}
KeyCode::Char(' ') => {
self.tool_checks[self.tool_cursor] = !self.tool_checks[self.tool_cursor];
Expand All @@ -674,21 +668,15 @@ impl AgentSelectState {
KeyCode::Esc => {
self.sub = AgentSubScreen::CustomTools;
}
KeyCode::Up | KeyCode::Char('k') => {
if self.skill_cursor > 0 {
self.skill_cursor -= 1;
}
KeyCode::Up | KeyCode::Char('k') if self.skill_cursor > 0 => {
self.skill_cursor -= 1;
}
KeyCode::Down | KeyCode::Char('j') => {
if len > 0 && self.skill_cursor < len - 1 {
self.skill_cursor += 1;
}
KeyCode::Down | KeyCode::Char('j') if len > 0 && self.skill_cursor < len - 1 => {
self.skill_cursor += 1;
}
KeyCode::Char(' ') => {
if len > 0 {
let checked = &mut self.available_skills[self.skill_cursor].1;
*checked = !*checked;
}
KeyCode::Char(' ') if len > 0 => {
let checked = &mut self.available_skills[self.skill_cursor].1;
*checked = !*checked;
}
KeyCode::Enter => {
// Advance to MCP server selection
Expand All @@ -706,21 +694,15 @@ impl AgentSelectState {
KeyCode::Esc => {
self.sub = AgentSubScreen::CustomSkills;
}
KeyCode::Up | KeyCode::Char('k') => {
if self.mcp_cursor > 0 {
self.mcp_cursor -= 1;
}
KeyCode::Up | KeyCode::Char('k') if self.mcp_cursor > 0 => {
self.mcp_cursor -= 1;
}
KeyCode::Down | KeyCode::Char('j') => {
if len > 0 && self.mcp_cursor < len - 1 {
self.mcp_cursor += 1;
}
KeyCode::Down | KeyCode::Char('j') if len > 0 && self.mcp_cursor < len - 1 => {
self.mcp_cursor += 1;
}
KeyCode::Char(' ') => {
if len > 0 {
let checked = &mut self.available_mcp[self.mcp_cursor].1;
*checked = !*checked;
}
KeyCode::Char(' ') if len > 0 => {
let checked = &mut self.available_mcp[self.mcp_cursor].1;
*checked = !*checked;
}
KeyCode::Enter => {
let toml = self.build_custom_toml();
Expand All @@ -737,21 +719,15 @@ impl AgentSelectState {
KeyCode::Esc => {
self.sub = AgentSubScreen::AgentDetail;
}
KeyCode::Up | KeyCode::Char('k') => {
if self.skill_cursor > 0 {
self.skill_cursor -= 1;
}
KeyCode::Up | KeyCode::Char('k') if self.skill_cursor > 0 => {
self.skill_cursor -= 1;
}
KeyCode::Down | KeyCode::Char('j') => {
if len > 0 && self.skill_cursor < len - 1 {
self.skill_cursor += 1;
}
KeyCode::Down | KeyCode::Char('j') if len > 0 && self.skill_cursor < len - 1 => {
self.skill_cursor += 1;
}
KeyCode::Char(' ') => {
if len > 0 {
let checked = &mut self.available_skills[self.skill_cursor].1;
*checked = !*checked;
}
KeyCode::Char(' ') if len > 0 => {
let checked = &mut self.available_skills[self.skill_cursor].1;
*checked = !*checked;
}
KeyCode::Enter => {
// Save — collect checked skill names (none checked = "all")
Expand Down Expand Up @@ -780,21 +756,15 @@ impl AgentSelectState {
KeyCode::Esc => {
self.sub = AgentSubScreen::AgentDetail;
}
KeyCode::Up | KeyCode::Char('k') => {
if self.mcp_cursor > 0 {
self.mcp_cursor -= 1;
}
KeyCode::Up | KeyCode::Char('k') if self.mcp_cursor > 0 => {
self.mcp_cursor -= 1;
}
KeyCode::Down | KeyCode::Char('j') => {
if len > 0 && self.mcp_cursor < len - 1 {
self.mcp_cursor += 1;
}
KeyCode::Down | KeyCode::Char('j') if len > 0 && self.mcp_cursor < len - 1 => {
self.mcp_cursor += 1;
}
KeyCode::Char(' ') => {
if len > 0 {
let checked = &mut self.available_mcp[self.mcp_cursor].1;
*checked = !*checked;
}
KeyCode::Char(' ') if len > 0 => {
let checked = &mut self.available_mcp[self.mcp_cursor].1;
*checked = !*checked;
}
KeyCode::Enter => {
// Save — collect checked server names (none checked = "all")
Expand Down
Loading