feat(harvester): synthesize [RESULT <job-id>] DECLINE on explicit assistant natural language refusal
This commit is contained in:
@@ -108,6 +108,23 @@ def iter_verb_markers(text):
|
|||||||
yield m.group(1), m.group(2).strip()
|
yield m.group(1), m.group(2).strip()
|
||||||
|
|
||||||
|
|
||||||
|
REFUSAL_PATTERNS = [
|
||||||
|
r"\bnot doing that\b",
|
||||||
|
r"\brefuse to\b",
|
||||||
|
r"\bdecline to\b",
|
||||||
|
r"\bdeclining\b",
|
||||||
|
r"\bwill not perform\b",
|
||||||
|
r"\bnot emitting the \[?result\]?\b",
|
||||||
|
r"\bnot sending result\b",
|
||||||
|
r"\bproduction change with recursion risk\b",
|
||||||
|
]
|
||||||
|
|
||||||
|
def detect_explicit_refusal(text):
|
||||||
|
"""Detect plain-language refusal/decline from an assistant in a task thread."""
|
||||||
|
t = (text or "").lower()
|
||||||
|
return any(re.search(pat, t) for pat in REFUSAL_PATTERNS)
|
||||||
|
|
||||||
|
|
||||||
def parse_tool_calls(text):
|
def parse_tool_calls(text):
|
||||||
"""
|
"""
|
||||||
Extract structured tool/exec calls from assistant messages.
|
Extract structured tool/exec calls from assistant messages.
|
||||||
@@ -581,6 +598,28 @@ def process_messages(raw_messages, agent, thread_id, thread_name, last_wm, follo
|
|||||||
if author == "assistant":
|
if author == "assistant":
|
||||||
markers = list(iter_result_markers(text))
|
markers = list(iter_result_markers(text))
|
||||||
verbs = list(iter_verb_markers(text))
|
verbs = list(iter_verb_markers(text))
|
||||||
|
|
||||||
|
# Synthesize [RESULT <job-id>] DECLINE if assistant explicitly refuses the task in plain text
|
||||||
|
if not markers and not verbs and detect_explicit_refusal(text):
|
||||||
|
matching_jid = None
|
||||||
|
for f_id, f_rec in followups.items():
|
||||||
|
if f_rec.get("status") in ("pending", "acknowledged") and (f_rec.get("thread_uuid") == thread_id or f_rec.get("recipient") == agent):
|
||||||
|
matching_jid = f_rec.get("job_id") or f_id
|
||||||
|
break
|
||||||
|
if not matching_jid and JOB_SIDECHATS_FILE.exists():
|
||||||
|
try:
|
||||||
|
sc_state = json.loads(JOB_SIDECHATS_FILE.read_text(encoding="utf-8"))
|
||||||
|
for k, v in sc_state.items():
|
||||||
|
if isinstance(v, dict) and v.get("thread_uuid") == thread_id:
|
||||||
|
matching_jid = k
|
||||||
|
break
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
if matching_jid:
|
||||||
|
refusal_snippet = f"DECLINE: {text.strip()[:180]}"
|
||||||
|
print(f"[{agent}] Synthesizing [RESULT {matching_jid}] DECLINE from explicit assistant refusal")
|
||||||
|
markers.append((matching_jid, refusal_snippet))
|
||||||
|
|
||||||
# Check for structured tool / command calls from the agent
|
# Check for structured tool / command calls from the agent
|
||||||
tool_calls = parse_tool_calls(text)
|
tool_calls = parse_tool_calls(text)
|
||||||
if tool_calls and not dry_run:
|
if tool_calls and not dry_run:
|
||||||
|
|||||||
Reference in New Issue
Block a user