fix: 9.5-code reachable items (parse unification, goal branch, fail-open logs, M7 test, fingerprint)
Parse: agent_tools/tool_approvals column parsing unified into agent_def shared helpers (parse None = undeclared; server keeps None, worker maps to []/{} at _task_from_row, dispatch behaviour unchanged). Goal: _apply_resume_preamble goal branch proven reachable via _goal_convert_queued on a queued auto-resumed task, kept with a test and corrected docs (not dead code). Fail-open: audit write failure and preamble lookup failure now log warnings (best-effort unchanged); partial policy failure and shadow parse drops documented as known gaps. M7: shadow endpoint explicit_capability_failures_truncated test. Fingerprint: RoutingPolicy.content_fingerprint (canonical JSON sha256, version excluded) surfaced only in dry-run output, never in audit rows. M1 wording: legacy gap stated as fixed stock persisting per-task until completion, not converging.
This commit is contained in:
1 parent
d95d678379
commit
1b8b6e525d
7 files changed
+498
-57
No files matched your search
@@ -200,6 +200,53 @@ class AgentDefinition:
|
||||
}
|
||||
|
||||
|
||||
def parse_agent_tools_column(raw):
|
||||
"""Parse one tasks.agent_tools column value (the single shared
|
||||
parser for server and worker; 9.5-code unification).
|
||||
|
||||
Returns a list copy, or None when the value is missing, is not
|
||||
a JSON list, or is otherwise dirty. None is the parse-layer
|
||||
default and means "undeclared", not "no required tools": the
|
||||
server keeps None in task serialization (an old row with a
|
||||
dirty value serializes exactly as before), while the worker
|
||||
maps None to [] at the _task_from_row boundary, because
|
||||
dispatch treats "no declaration" and "no required tools"
|
||||
identically (both skip the v3 gate, and every worker use site
|
||||
already reads ``task.get("agent_tools") or []``). Unifying the
|
||||
parse logic therefore changes no observable behaviour on
|
||||
either side; the old server/worker defaults (None vs []) were
|
||||
only different spellings of the same dispatch outcome.
|
||||
"""
|
||||
if raw is None:
|
||||
return None
|
||||
if isinstance(raw, list):
|
||||
return list(raw)
|
||||
try:
|
||||
parsed = json.loads(raw)
|
||||
except (TypeError, ValueError):
|
||||
return None
|
||||
return list(parsed) if isinstance(parsed, list) else None
|
||||
|
||||
|
||||
def parse_agent_tool_approvals_column(raw):
|
||||
"""Parse one tasks.agent_tool_approvals column value (the
|
||||
single shared parser for server and worker; same None
|
||||
convention as parse_agent_tools_column: None means
|
||||
"undeclared", the server keeps it, the worker maps it to {}
|
||||
at the _task_from_row boundary because every worker use site
|
||||
already reads ``task.get("agent_tool_approvals") or {}``).
|
||||
"""
|
||||
if raw is None:
|
||||
return None
|
||||
if isinstance(raw, dict):
|
||||
return dict(raw)
|
||||
try:
|
||||
parsed = json.loads(raw)
|
||||
except (TypeError, ValueError):
|
||||
return None
|
||||
return dict(parsed) if isinstance(parsed, dict) else None
|
||||
|
||||
|
||||
def effective_tool_approvals(tool_approvals, host_approval):
|
||||
"""What host.py will actually answer per declared tool, today.
|
||||
|
||||
|
||||
Reference in new issue
Block a user