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()
|
||||
|
||||
|
||||
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):
|
||||
"""
|
||||
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":
|
||||
markers = list(iter_result_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
|
||||
tool_calls = parse_tool_calls(text)
|
||||
if tool_calls and not dry_run:
|
||||
|
||||
Reference in New Issue
Block a user