govbridge / src /agents /input_agent.py
Vishnu Rama
Rename to GovBridge, expand ideas flow docs, simplify UI
2948416
Raw
History Blame Contribute Delete
3.06 kB
import logging
from langchain_core.messages import AIMessage, HumanMessage, SystemMessage
from langgraph.types import interrupt
from src.workflow.state import GovBridgeState
from src.integrations.llm_factory import get_llm
_log = logging.getLogger(__name__)
_SYSTEM = """You are the intake agent for GovBridge, an app that helps citizens write formal emails to their government.
Your job is to determine TWO things from the conversation:
1. CATEGORY β€” what kind of request this is
2. LOCATION β€” the city, state, or region the email is about
## CATEGORY
- idea: a suggestion, proposal, or improvement the citizen wants to pitch
- complaint: a problem, grievance, or broken service they want to report
Classify immediately if clear. Do NOT ask "Is that correct?"
## LOCATION
Extract the location from what the user has written. Look for:
- A city or region name ("Chennai", "Ottawa", "London")
- A government official that implies a location ("CM Vijay" β†’ Tamil Nadu, "NYC Mayor" β†’ New York City)
- A state or country name
If you cannot find any location in the conversation, ask the user: "Which city or region is your email about?"
Ask this ONLY if there is genuinely no location clue anywhere in the conversation.
## OUTPUT TAGS β€” include on separate lines at the end of your message:
CATEGORY: idea (or complaint)
LOCATION: [city/region]
Include both tags when you have both. Include only the ones you have found.
Never ask more than 1 question per response."""
def input_agent(state: GovBridgeState) -> dict:
llm = get_llm("small")
messages = state.get("messages", [])
_log.info("starting β€” messages=%d", len(messages))
system = SystemMessage(content=_SYSTEM)
response = llm.invoke([system] + messages)
content = response.content
category = None
location = None
clean_lines = []
for line in content.splitlines():
stripped = line.strip()
if stripped.startswith("CATEGORY:"):
category = stripped.split(":", 1)[1].strip().lower()
elif stripped.startswith("LOCATION:"):
location = stripped.split(":", 1)[1].strip()
else:
clean_lines.append(line)
display_text = "\n".join(clean_lines).strip()
if location:
_log.info("location extracted: %s", location)
if category:
_log.info("category detected: %s", category)
if category:
result = {
"messages": [AIMessage(content=display_text)],
"category": category,
"collected_details": {},
"email_cc": [],
"conversation_complete": False,
"draft_approved": False,
}
if location:
result["location"] = location
return result
_log.info("no category yet β€” interrupting for user reply")
partial = {}
if location:
partial["location"] = location
user_reply = interrupt(display_text)
return {
"messages": [AIMessage(content=display_text), HumanMessage(content=user_reply)],
**partial,
}