Spaces:
Running
Running
Update agent_logic.py
Browse files- agent_logic.py +36 -21
agent_logic.py
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
# agent_logic.py (Milestone 5 - FINAL & ROBUST + LOGGING + NATURAL TEXT +
|
| 2 |
import asyncio
|
| 3 |
from typing import AsyncGenerator, Dict, Optional
|
| 4 |
import json
|
|
@@ -20,17 +20,22 @@ CLASSIFIER_SYSTEM_PROMPT = load_prompt(config.PROMPT_FILES["classifier"])
|
|
| 20 |
HOMOGENEOUS_MANAGER_PROMPT = load_prompt(config.PROMPT_FILES["manager_homogeneous"])
|
| 21 |
HETEROGENEOUS_MANAGER_PROMPT = load_prompt(config.PROMPT_FILES["manager_heterogeneous"])
|
| 22 |
|
| 23 |
-
# ---
|
| 24 |
-
|
| 25 |
-
|
| 26 |
-
|
| 27 |
-
"
|
| 28 |
-
"
|
| 29 |
-
"
|
| 30 |
-
"
|
| 31 |
-
"
|
| 32 |
-
"
|
| 33 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 34 |
|
| 35 |
class Baseline_Single_Agent:
|
| 36 |
def __init__(self, api_clients: dict):
|
|
@@ -222,31 +227,40 @@ class StrategicSelectorAgent:
|
|
| 222 |
else:
|
| 223 |
v_fitness_json = {}
|
| 224 |
|
| 225 |
-
# ---
|
| 226 |
normalized_fitness = {}
|
| 227 |
if isinstance(v_fitness_json, dict):
|
| 228 |
for k, v in v_fitness_json.items():
|
| 229 |
-
#
|
| 230 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 231 |
continue
|
| 232 |
|
| 233 |
-
#
|
| 234 |
if isinstance(v, dict):
|
| 235 |
score_value = v.get('score')
|
| 236 |
justification_value = v.get('justification', str(v))
|
| 237 |
-
# Case 2: List of Dicts { "Novelty": [{ "score": 5 }] }
|
| 238 |
elif isinstance(v, list) and len(v) > 0 and isinstance(v[0], dict):
|
| 239 |
score_value = v[0].get('score')
|
| 240 |
justification_value = v[0].get('justification', str(v[0]))
|
| 241 |
-
# Case 3: Flat Value { "Novelty": "4/5" } OR { "Novelty": 4 }
|
| 242 |
else:
|
|
|
|
| 243 |
score_value = v
|
| 244 |
justification_value = "Score extracted directly."
|
| 245 |
|
| 246 |
-
#
|
| 247 |
if isinstance(score_value, str):
|
| 248 |
try:
|
| 249 |
-
|
|
|
|
|
|
|
| 250 |
except:
|
| 251 |
score_value = 0
|
| 252 |
|
|
@@ -255,8 +269,9 @@ class StrategicSelectorAgent:
|
|
| 255 |
except (ValueError, TypeError):
|
| 256 |
score_value = 0
|
| 257 |
|
| 258 |
-
normalized_fitness[
|
| 259 |
else:
|
|
|
|
| 260 |
normalized_fitness = {k: {'score': 0, 'justification': "Invalid JSON structure"} for k in ["Novelty", "Usefulness_Feasibility", "Flexibility", "Elaboration", "Cultural_Appropriateness"]}
|
| 261 |
|
| 262 |
v_fitness_json = normalized_fitness
|
|
|
|
| 1 |
+
# agent_logic.py (Milestone 5 - FINAL & ROBUST + LOGGING + NATURAL TEXT + ALLOWLIST FILTER)
|
| 2 |
import asyncio
|
| 3 |
from typing import AsyncGenerator, Dict, Optional
|
| 4 |
import json
|
|
|
|
| 20 |
HOMOGENEOUS_MANAGER_PROMPT = load_prompt(config.PROMPT_FILES["manager_homogeneous"])
|
| 21 |
HETEROGENEOUS_MANAGER_PROMPT = load_prompt(config.PROMPT_FILES["manager_heterogeneous"])
|
| 22 |
|
| 23 |
+
# --- METRIC BOUNCER (Allowlist) ---
|
| 24 |
+
# We map any variation of the key to the canonical internal name.
|
| 25 |
+
# If a key isn't in here, it gets dropped.
|
| 26 |
+
METRIC_MAPPING = {
|
| 27 |
+
"novelty": "Novelty",
|
| 28 |
+
"usefulness": "Usefulness_Feasibility",
|
| 29 |
+
"feasibility": "Usefulness_Feasibility",
|
| 30 |
+
"usefulness_feasibility": "Usefulness_Feasibility",
|
| 31 |
+
"usefulness/feasibility": "Usefulness_Feasibility",
|
| 32 |
+
"flexibility": "Flexibility",
|
| 33 |
+
"elaboration": "Elaboration",
|
| 34 |
+
"cultural_appropriateness": "Cultural_Appropriateness",
|
| 35 |
+
"cultural_sensitivity": "Cultural_Appropriateness",
|
| 36 |
+
"cultural appropriateness": "Cultural_Appropriateness",
|
| 37 |
+
"cultural appropriateness/sensitivity": "Cultural_Appropriateness"
|
| 38 |
+
}
|
| 39 |
|
| 40 |
class Baseline_Single_Agent:
|
| 41 |
def __init__(self, api_clients: dict):
|
|
|
|
| 227 |
else:
|
| 228 |
v_fitness_json = {}
|
| 229 |
|
| 230 |
+
# --- ROBUST NORMALIZATION WITH ALLOWLIST FILTER ---
|
| 231 |
normalized_fitness = {}
|
| 232 |
if isinstance(v_fitness_json, dict):
|
| 233 |
for k, v in v_fitness_json.items():
|
| 234 |
+
# 1. Map fuzzy keys to canonical keys
|
| 235 |
+
canonical_key = None
|
| 236 |
+
clean_k = k.lower().strip()
|
| 237 |
+
|
| 238 |
+
# Check exact match or known variation
|
| 239 |
+
if clean_k in METRIC_MAPPING:
|
| 240 |
+
canonical_key = METRIC_MAPPING[clean_k]
|
| 241 |
+
|
| 242 |
+
# If we couldn't map it to a valid metric, SKIP IT.
|
| 243 |
+
if not canonical_key:
|
| 244 |
continue
|
| 245 |
|
| 246 |
+
# 2. Extract Score Value
|
| 247 |
if isinstance(v, dict):
|
| 248 |
score_value = v.get('score')
|
| 249 |
justification_value = v.get('justification', str(v))
|
|
|
|
| 250 |
elif isinstance(v, list) and len(v) > 0 and isinstance(v[0], dict):
|
| 251 |
score_value = v[0].get('score')
|
| 252 |
justification_value = v[0].get('justification', str(v[0]))
|
|
|
|
| 253 |
else:
|
| 254 |
+
# Flat value case
|
| 255 |
score_value = v
|
| 256 |
justification_value = "Score extracted directly."
|
| 257 |
|
| 258 |
+
# 3. Clean Score (handle "4/5" strings)
|
| 259 |
if isinstance(score_value, str):
|
| 260 |
try:
|
| 261 |
+
# Looks for the first number in the string
|
| 262 |
+
match = re.search(r'\d+', score_value)
|
| 263 |
+
score_value = int(match.group()) if match else 0
|
| 264 |
except:
|
| 265 |
score_value = 0
|
| 266 |
|
|
|
|
| 269 |
except (ValueError, TypeError):
|
| 270 |
score_value = 0
|
| 271 |
|
| 272 |
+
normalized_fitness[canonical_key] = {'score': score_value, 'justification': justification_value}
|
| 273 |
else:
|
| 274 |
+
# Fallback for total failure
|
| 275 |
normalized_fitness = {k: {'score': 0, 'justification': "Invalid JSON structure"} for k in ["Novelty", "Usefulness_Feasibility", "Flexibility", "Elaboration", "Cultural_Appropriateness"]}
|
| 276 |
|
| 277 |
v_fitness_json = normalized_fitness
|