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
28 changes: 8 additions & 20 deletions uc-0a/agents.md
Original file line number Diff line number Diff line change
@@ -1,27 +1,15 @@
# agents.md — UC-0A Complaint Classifier
# INSTRUCTIONS:
# 1. Open your AI tool
# 2. Paste the full contents of uc-0a/README.md
# 3. Use this prompt:
# "Read this UC README. Using the R.I.C.E framework, generate an
# agents.md YAML with four fields: role, intent, context, enforcement.
# Enforcement must include every rule listed under
# 'Enforcement Rules Your agents.md Must Include'.
# Output only valid YAML."
# 4. Paste the output below

role: >
[FILL IN]
You are an expert Civic Tech Support Agent specialized in triaging and classifying municipal complaints for a city administration. Your job is to strictly adhere to the official taxonomy and prioritize safety-critical incidents.

intent: >
[FILL IN]
Your goal is to accurately classify citizen complaints from descriptions into a specific category and priority level. You must ensure that any complaint involving safety risks or vulnerable locations (like schools or hospitals) is escalated immediately.

context: >
[FILL IN]
You process input CSV data where each row contains a 'description' of the complaint. You have no authority to dispatch crews, but your classification determines which department receives the report and how fast they respond.

enforcement:
- "[FILL IN: category enum rule]"
- "[FILL IN: severity keyword rule — list the keywords]"
- "[FILL IN: reason field rule]"
- "[FILL IN: ambiguity refusal rule]"
- "[FILL IN: no invented categories rule]"
- "Category must be exactly one of: Pothole, Flooding, Streetlight, Waste, Noise, Road Damage, Heritage Damage, Heat Hazard, Drain Blockage, Other."
- "Priority must be 'Urgent' if description contains any of: injury, child, school, hospital, ambulance, fire, hazard, fell, collapse."
- "Every output must include a 'reason' field with one sentence citing specific words from the description."
- "If the category is genuinely ambiguous or the description is too vague, you must use 'category: Other' and 'flag: NEEDS_REVIEW'."
- "Never invent or use category names outside the official list."
90 changes: 76 additions & 14 deletions uc-0a/classifier.py
Original file line number Diff line number Diff line change
@@ -1,26 +1,88 @@
"""
UC-0A — Complaint Classifier
classifier.py — Starter file

Build this using your AI coding tool:
1. Share agents.md, skills.md, and uc-0a/README.md
2. Ask the AI to implement this file
3. Run: python3 classifier.py --input ../data/city-test-files/test_pune.csv \
--output results_pune.csv
"""
import argparse
import csv
import os

def classify_complaint(row: dict) -> dict:
"""
Classify a single complaint row.
Returns dict with: complaint_id, category, priority, reason, flag
Classify a single complaint row using heuristic logic (simulating AI behavior).
"""
raise NotImplementedError("Build this using your AI tool + agents.md")
description = row.get("description", "").lower()
complaint_id = row.get("complaint_id", "N/A")

# 1. Allowed Categories & Keywords
taxonomy = {
"Pothole": ["pothole", "pit", "crater"],
"Flooding": ["flood", "water", "rain", "overflow"],
"Streetlight": ["light", "dark", "lamp", "bulb"],
"Waste": ["garbage", "trash", "waste", "smell", "dump"],
"Noise": ["loud", "music", "noise", "sound"],
"Road Damage": ["road", "cracked", "sidewalk", "pavement"],
"Heritage Damage": ["monument", "heritage", "old city", "statue"],
"Heat Hazard": ["heat", "hot", "sun", "summer"],
"Drain Blockage": ["drain", "sewage", "blocked", "gutter"],
}

# 2. Category Matching
category = "Other"
for cat, keywords in taxonomy.items():
if any(kw in description for kw in keywords):
category = cat
break

# 3. Severity & Priority
severity_keywords = ["injury", "child", "school", "hospital", "ambulance", "fire", "hazard", "fell", "collapse"]
priority = "Standard"
found_keyword = None
for kw in severity_keywords:
if kw in description:
priority = "Urgent"
found_keyword = kw
break

# 4. Reason Generation
if priority == "Urgent":
reason = f"Urgent priority because the description mentions '{found_keyword}'."
elif category != "Other":
reason = f"Classified as {category} due to keywords in the description."
else:
reason = "Description is ambiguous or does not map to a standard category."
Comment on lines +43 to +48
Copy link

Copilot AI Apr 18, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The generated reason for non-urgent classified categories doesn’t cite the specific triggering words from the description (it’s always “due to keywords in the description”). This violates the enforcement rule in uc-0a/agents.md and the UC-0A README (“reason: one sentence citing specific words”). Capture which taxonomy keyword matched and include it in the reason (similar to how urgent reasons include found_keyword).

Copilot uses AI. Check for mistakes.

# 5. Flagging
flag = "NEEDS_REVIEW" if category == "Other" or not description else ""

return {
"complaint_id": complaint_id,
"category": category,
"priority": priority,
"reason": reason,
"flag": flag
}

def batch_classify(input_path: str, output_path: str):
"""Read input CSV, classify each row, write results CSV."""
raise NotImplementedError("Build this using your AI tool + agents.md")
if not os.path.exists(input_path):
print(f"Error: {input_path} not found.")
return

results = []
with open(input_path, mode='r', encoding='utf-8') as f:
reader = csv.DictReader(f)
for row in reader:
try:
classified = classify_complaint(row)
results.append(classified)
except Exception as e:
print(f"Skipping malformed row: {e}")

if not results:
print("No results to write.")
return

fieldnames = results[0].keys()
with open(output_path, mode='w', encoding='utf-8', newline='') as f:
writer = csv.DictWriter(f, fieldnames=fieldnames)
writer.writeheader()
writer.writerows(results)

if __name__ == "__main__":
parser = argparse.ArgumentParser(description="UC-0A Complaint Classifier")
Expand Down
16 changes: 16 additions & 0 deletions uc-0a/results_pune.csv
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
complaint_id,category,priority,reason,flag
PM-202401,Pothole,Standard,Classified as Pothole due to keywords in the description.,
PM-202402,Pothole,Urgent,Urgent priority because the description mentions 'child'.,
PM-202406,Flooding,Standard,Classified as Flooding due to keywords in the description.,
PM-202408,Flooding,Standard,Classified as Flooding due to keywords in the description.,
PM-202410,Streetlight,Standard,Classified as Streetlight due to keywords in the description.,
PM-202411,Streetlight,Urgent,Urgent priority because the description mentions 'hazard'.,
PM-202413,Flooding,Standard,Classified as Flooding due to keywords in the description.,
PM-202418,Noise,Standard,Classified as Noise due to keywords in the description.,
PM-202419,Road Damage,Standard,Classified as Road Damage due to keywords in the description.,
PM-202420,Other,Urgent,Urgent priority because the description mentions 'injury'.,NEEDS_REVIEW
PM-202427,Flooding,Standard,Classified as Flooding due to keywords in the description.,
PM-202428,Other,Standard,Description is ambiguous or does not map to a standard category.,NEEDS_REVIEW
PM-202430,Streetlight,Standard,Classified as Streetlight due to keywords in the description.,
PM-202433,Waste,Standard,Classified as Waste due to keywords in the description.,
PM-202446,Other,Urgent,Urgent priority because the description mentions 'fell'.,NEEDS_REVIEW
19 changes: 8 additions & 11 deletions uc-0a/skills.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
# skills.md — UC-0A Complaint Classifier
# INSTRUCTIONS: Same as agents.md — paste README into AI, ask for skills.md YAML

skills:
- name: classify_complaint
description: "[FILL IN]"
input: "[FILL IN]"
output: "[FILL IN]"
error_handling: "[FILL IN]"
description: Analyzes a single complaint description to determine its category, priority, and justification.
input: A dictionary containing 'complaint_id' and 'description'.
output: A dictionary with 'category', 'priority', 'reason', and 'flag'.
error_handling: Handles empty or ambiguous descriptions by defaulting to 'Other' and flagging for review.

- name: batch_classify
description: "[FILL IN]"
input: "[FILL IN]"
output: "[FILL IN]"
error_handling: "[FILL IN]"
description: Processes a CSV file of complaints and writes the classified results to a new CSV.
input: Input CSV path and output CSV path.
output: A CSV file with classification results.
error_handling: Logs and skips malformed rows while ensuring the entire file is processed.
33 changes: 8 additions & 25 deletions uc-mcp/agents.md
Original file line number Diff line number Diff line change
@@ -1,32 +1,15 @@
# agents.md — UC-MCP MCP Server
# INSTRUCTIONS:
# 1. Open your AI tool
# 2. Paste the full contents of uc-mcp/README.md
# 3. Use this prompt:
# "Read this UC README. Using the R.I.C.E framework, generate an
# agents.md YAML with four fields: role, intent, context, enforcement.
# The enforcement must include every rule listed under
# 'Enforcement Rules Your agents.md Must Include'.
# Output only valid YAML."
# 4. Paste the output below, replacing this placeholder
# 5. Pay special attention to enforcement rule 1 — the tool description
# must state exact document scope

role: >
[FILL IN: Who is this agent? What layer of the stack does it operate at?
Hint: an MCP server that exposes policy retrieval as a tool]
You are an MCP Server Developer for the City Municipal Corporation. Your job is to expose internal RAG capabilities to AI agents through a strictly defined JSON-RPC interface.

intent: >
[FILL IN: What does a correctly implemented MCP server produce?
Hint: JSON-RPC compliant responses, scoped tool description, correct refusals]
Your goal is to provide a clean, reliable, and well-described MCP tool interface. A correct output follows the JSON-RPC 2.0 standard and provides a tool description so precise that it prevents discovery errors or out-of-scope calls by AI agents.

context: >
[FILL IN: What does this server have access to?
Hint: RAG server results only — no direct LLM calls, no outside knowledge]
You operate over plain HTTP. You wrap the existing RAG server logic. You must ensure that every tool call result is structured according to the MCP specification and that errors are handled gracefully with the 'isError' flag.

enforcement:
- "[FILL IN: Tool description scope rule]"
- "[FILL IN: Refusal documentation rule]"
- "[FILL IN: inputSchema required field rule]"
- "[FILL IN: isError on failure rule]"
- "[FILL IN: HTTP 200 for all JSON-RPC responses rule]"
- "Tool description must state the exact document scope: CMC HR Leave Policy, IT Acceptable Use Policy, Finance Reimbursement Policy."
- "Tool description must explicitly state that questions outside these three documents return a refusal template."
- "The inputSchema must require 'question' as a non-empty string."
- "Every tool call response must include 'content' as a list of text objects and 'isError' as a boolean."
- "The server must return HTTP 200 for all JSON-RPC responses, conveying application errors via JSON-RPC error codes (e.g., -32601 for Method Not Found)."
Loading
Loading