Executor-Tyrant-Framework Claude Sonnet 4.6 commited on
Commit
08381bd
·
1 Parent(s): 920fc45

Schema + executor: accept string shorthand for on_failure, edit_file returns content

Browse files

work_block_schema.py: _FAILURE_HANDLER now uses oneOf — accepts both string
shorthands ("abort", "skip", "continue", etc.) and the full object form
{"action": "abort_block"}. Easier spec authoring without breaking existing specs.

spec_executor.py: _handle_failure normalizes string shorthands to dict at
entry so execution works regardless of which form the spec uses.

spec_executor.py: edit_file in _direct_filesystem_op now returns new file
content instead of a confirmation string, enabling contains/not_contains
validation checks on the result of an edit.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

Files changed (2) hide show
  1. spec_executor.py +14 -2
  2. work_block_schema.py +21 -9
spec_executor.py CHANGED
@@ -409,7 +409,7 @@ class SpecExecutor:
409
  return {"status": "error", "error": f"old_text found {count} times in {path} — must be unique"}
410
  new_content = content.replace(old_text, new_text, 1)
411
  target.write_text(new_content, encoding="utf-8")
412
- return f"Edited {target} — replaced 1 occurrence ({len(new_content):,} bytes)"
413
 
414
  elif tool_name == "shell_execute":
415
  import subprocess as _sp
@@ -504,7 +504,19 @@ class SpecExecutor:
504
  # Failure handling
505
  # ------------------------------------------------------------------
506
 
507
- def _handle_failure(self, handler: dict, step_id: str, ctx: ExecutionContext):
 
 
 
 
 
 
 
 
 
 
 
 
508
  action = handler["action"]
509
  msg = handler.get("message", f"Step {step_id} failed")
510
 
 
409
  return {"status": "error", "error": f"old_text found {count} times in {path} — must be unique"}
410
  new_content = content.replace(old_text, new_text, 1)
411
  target.write_text(new_content, encoding="utf-8")
412
+ return new_content
413
 
414
  elif tool_name == "shell_execute":
415
  import subprocess as _sp
 
504
  # Failure handling
505
  # ------------------------------------------------------------------
506
 
507
+ def _handle_failure(self, handler, step_id: str, ctx: ExecutionContext):
508
+ # Normalize string shorthand (e.g. "abort", "skip") to full dict form.
509
+ if isinstance(handler, str):
510
+ _shorthand_map = {
511
+ "abort": "abort_block",
512
+ "abort_block": "abort_block",
513
+ "continue": "skip",
514
+ "skip": "skip",
515
+ "retry": "retry",
516
+ "goto": "goto",
517
+ "escalate_to_qb": "escalate_to_qb",
518
+ }
519
+ handler = {"action": _shorthand_map.get(handler, "abort_block")}
520
  action = handler["action"]
521
  msg = handler.get("message", f"Step {step_id} failed")
522
 
work_block_schema.py CHANGED
@@ -64,16 +64,28 @@ _CONDITION_CHECK = {
64
  },
65
  }
66
 
 
 
 
 
67
  _FAILURE_HANDLER = {
68
- "type": "object",
69
- "required": ["action"],
70
- "additionalProperties": False,
71
- "properties": {
72
- "action": {"enum": _FAILURE_ACTIONS},
73
- "max_retries": {"type": "integer", "minimum": 0, "default": 0},
74
- "goto_step": {"type": "string"},
75
- "message": {"type": "string"},
76
- },
 
 
 
 
 
 
 
 
77
  }
78
 
79
  _VALIDATION_BLOCK = {
 
64
  },
65
  }
66
 
67
+ # String shorthands accepted in on_failure for easier spec authoring.
68
+ # Executor normalizes these to the full object form before acting on them.
69
+ _FAILURE_SHORTHANDS = ["abort", "abort_block", "continue", "skip", "retry", "goto", "escalate_to_qb"]
70
+
71
  _FAILURE_HANDLER = {
72
+ "oneOf": [
73
+ {
74
+ "type": "string",
75
+ "enum": _FAILURE_SHORTHANDS,
76
+ },
77
+ {
78
+ "type": "object",
79
+ "required": ["action"],
80
+ "additionalProperties": False,
81
+ "properties": {
82
+ "action": {"enum": _FAILURE_ACTIONS},
83
+ "max_retries": {"type": "integer", "minimum": 0, "default": 0},
84
+ "goto_step": {"type": "string"},
85
+ "message": {"type": "string"},
86
+ },
87
+ },
88
+ ]
89
  }
90
 
91
  _VALIDATION_BLOCK = {