feat: thread_has_agent_participation + ACK reply linkage
1. thread_has_agent_participation (SOWA Priority 11):
- New function has_agent_chat_participation() in behavior_policy.py
- Checks if agent responded to ANY user in this chat within 30min
- When active + user asks question/imperative → agent responds
- Different from per-user conversation_context (Priority 12)
- Wired into both detect_explicit_request() and analyze_message()
2. ACK reply_to_message_id:
- When SOWA sends ACK ("NUTRA тут"), it now replies to the user's
message instead of sending a standalone message
- Better UX: visually linked to what the user wrote
- Uses allow_sending_without_reply=True for safety
Known issue (not fixed - too risky):
- Lines 1368-1639 in http_api.py are dead code (brand commands /бренд)
at incorrect indentation level (8 spaces, inside unreachable block)
- These commands never worked on NODE1, fixing 260 lines of indentation
carries regression risk — deferred to separate cleanup PR
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -41,6 +41,7 @@ from behavior_policy import (
|
||||
record_ack,
|
||||
get_ack_text,
|
||||
is_prober_request,
|
||||
has_agent_chat_participation,
|
||||
NO_OUTPUT,
|
||||
BehaviorDecision,
|
||||
AGENT_NAME_VARIANTS,
|
||||
@@ -2026,6 +2027,9 @@ async def handle_telegram_webhook(
|
||||
mentioned_agents.append(aid)
|
||||
break
|
||||
|
||||
# Gateway: check if agent has been active in this chat recently (any user)
|
||||
agent_active_in_chat = has_agent_chat_participation(agent_config.agent_id, chat_id)
|
||||
|
||||
# Gateway: compute has_explicit_request (single source of truth)
|
||||
# CONTRACT: imperative OR (? AND (dm OR reply OR mention OR thread))
|
||||
has_explicit_request = detect_explicit_request(
|
||||
@@ -2033,7 +2037,7 @@ async def handle_telegram_webhook(
|
||||
is_dm=is_private_chat,
|
||||
is_reply_to_agent=is_reply_to_agent,
|
||||
mentioned_agents=mentioned_agents,
|
||||
thread_has_agent_participation=False, # REQUIRED, fail-closed default
|
||||
thread_has_agent_participation=agent_active_in_chat,
|
||||
)
|
||||
|
||||
# Check if this is a prober request (chat_id=0 or user_id=0)
|
||||
@@ -2051,7 +2055,7 @@ async def handle_telegram_webhook(
|
||||
payload_explicit_request=has_explicit_request,
|
||||
payload_has_link=has_link,
|
||||
is_reply_to_agent=is_reply_to_agent,
|
||||
thread_has_agent_participation=False, # TODO: track per thread
|
||||
thread_has_agent_participation=agent_active_in_chat,
|
||||
)
|
||||
respond_decision = sowa_decision.should_respond
|
||||
respond_reason = sowa_decision.reason
|
||||
@@ -2088,10 +2092,16 @@ async def handle_telegram_webhook(
|
||||
try:
|
||||
url = f"https://api.telegram.org/bot{token}/sendMessage"
|
||||
async with httpx.AsyncClient(timeout=30) as client:
|
||||
resp = await client.post(url, json={
|
||||
ack_payload = {
|
||||
"chat_id": chat_id,
|
||||
"text": ack_text,
|
||||
})
|
||||
}
|
||||
# Link ACK to the user's message for better UX
|
||||
msg_id = update.message.get("message_id")
|
||||
if msg_id:
|
||||
ack_payload["reply_to_message_id"] = msg_id
|
||||
ack_payload["allow_sending_without_reply"] = True
|
||||
resp = await client.post(url, json=ack_payload)
|
||||
if resp.status_code == 200:
|
||||
logger.info(f"\U0001f44b ACK sent to chat {chat_id}: {ack_text}")
|
||||
else:
|
||||
|
||||
Reference in New Issue
Block a user