Agent-trigger: permanent deltaker vs @bot-nevnelse
To spor for agent-respons: 1. Permanent: agent er member_of → svar på alle meldinger 2. @bot-nevnelse: bruker skriver @bot → engangs-svar, agent trenger ikke være deltaker Femkompis-problemet løst: @bot i en gruppechat gir ett svar, ikke evig bot-loop. Dedikerte bot-chatter (member_of) fungerer som før. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
f52d23de54
commit
6cf421dbc7
2 changed files with 58 additions and 34 deletions
|
|
@ -203,6 +203,14 @@ async fn load_agent_config(db: &PgPool, agent_node_id: Uuid) -> Result<AgentConf
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Finn standard-agenten for @bot-nevnelser (den aktive agenten med høyest prioritet).
|
||||||
|
pub async fn find_default_agent(db: &PgPool) -> Result<Option<Uuid>, sqlx::Error> {
|
||||||
|
sqlx::query_scalar(
|
||||||
|
"SELECT node_id FROM agent_identities WHERE is_active = true ORDER BY created_at ASC LIMIT 1",
|
||||||
|
).fetch_optional(db).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Finn agent som er permanent deltaker i en kommunikasjonsnode.
|
||||||
pub async fn find_agent_participant(db: &PgPool, communication_id: Uuid) -> Result<Option<Uuid>, sqlx::Error> {
|
pub async fn find_agent_participant(db: &PgPool, communication_id: Uuid) -> Result<Option<Uuid>, sqlx::Error> {
|
||||||
// Finn agent-deltaker uansett is_active — kill switch sjekkes i handleren.
|
// Finn agent-deltaker uansett is_active — kill switch sjekkes i handleren.
|
||||||
// Dette sikrer at jobben opprettes slik at eksterne handlers (Claude Code) kan plukke den.
|
// Dette sikrer at jobben opprettes slik at eksterne handlers (Claude Code) kan plukke den.
|
||||||
|
|
|
||||||
|
|
@ -808,20 +808,44 @@ pub async fn create_node(
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
// -- Agent-trigger: sjekk om kommunikasjonsnoden har en agent-deltaker --
|
// -- Agent-trigger: to spor --
|
||||||
|
// 1. Permanent deltaker: agent er member_of → svar på alle meldinger
|
||||||
|
// 2. @bot-nevnelse: bruker nevner @bot i teksten → engangs-svar
|
||||||
if let Some(ctx_id) = req.context_id {
|
if let Some(ctx_id) = req.context_id {
|
||||||
let db_clone = state.db.clone();
|
let db_clone = state.db.clone();
|
||||||
let user_node_id = user.node_id;
|
let user_node_id = user.node_id;
|
||||||
let created_node_id = node_id;
|
let created_node_id = node_id;
|
||||||
|
let message_content = content.clone();
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
match crate::agent::find_agent_participant(&db_clone, ctx_id).await {
|
// Spor 1: Permanent deltaker (agent er member_of i chatten)
|
||||||
Ok(Some(agent_id)) if agent_id != effective_identity => {
|
let permanent_agent = match crate::agent::find_agent_participant(&db_clone, ctx_id).await {
|
||||||
// Agent funnet, og melding er ikke fra agenten selv
|
Ok(Some(agent_id)) if agent_id != effective_identity => Some(agent_id),
|
||||||
|
Ok(_) => None,
|
||||||
|
Err(e) => {
|
||||||
|
tracing::error!(communication_id = %ctx_id, error = %e, "Feil ved agent-deltaker-sjekk");
|
||||||
|
None
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Spor 2: @bot-nevnelse (agent er IKKE deltaker, men nevnes i teksten)
|
||||||
|
let mention_agent = if permanent_agent.is_none() && message_content.contains("@bot") {
|
||||||
|
match crate::agent::find_default_agent(&db_clone).await {
|
||||||
|
Ok(Some(agent_id)) if agent_id != effective_identity => Some(agent_id),
|
||||||
|
_ => None,
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
|
||||||
|
// Trigger jobb for den agenten som matcher
|
||||||
|
if let Some(agent_id) = permanent_agent.or(mention_agent) {
|
||||||
|
let trigger = if permanent_agent.is_some() { "permanent" } else { "mention" };
|
||||||
let payload = serde_json::json!({
|
let payload = serde_json::json!({
|
||||||
"communication_id": ctx_id.to_string(),
|
"communication_id": ctx_id.to_string(),
|
||||||
"message_id": created_node_id.to_string(),
|
"message_id": created_node_id.to_string(),
|
||||||
"agent_node_id": agent_id.to_string(),
|
"agent_node_id": agent_id.to_string(),
|
||||||
"sender_node_id": user_node_id.to_string()
|
"sender_node_id": user_node_id.to_string(),
|
||||||
|
"trigger": trigger
|
||||||
});
|
});
|
||||||
match crate::jobs::enqueue(&db_clone, "agent_respond", payload, None, 8).await {
|
match crate::jobs::enqueue(&db_clone, "agent_respond", payload, None, 8).await {
|
||||||
Ok(job_id) => {
|
Ok(job_id) => {
|
||||||
|
|
@ -829,6 +853,7 @@ pub async fn create_node(
|
||||||
job_id = %job_id,
|
job_id = %job_id,
|
||||||
communication_id = %ctx_id,
|
communication_id = %ctx_id,
|
||||||
agent_node_id = %agent_id,
|
agent_node_id = %agent_id,
|
||||||
|
trigger = trigger,
|
||||||
"agent_respond-jobb lagt i kø"
|
"agent_respond-jobb lagt i kø"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -841,15 +866,6 @@ pub async fn create_node(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(_) => {} // Ingen agent, eller melding fra agenten selv
|
|
||||||
Err(e) => {
|
|
||||||
tracing::error!(
|
|
||||||
communication_id = %ctx_id,
|
|
||||||
error = %e,
|
|
||||||
"Feil ved agent-deltaker-sjekk"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue