Summary
The engine and the SDK integration helper disagree on whether a steer-control evaluation error blocks execution. The engine treats it as non-blocking; the integrations/_core.py helper raises on any error. So whether a steered step is blocked when its evaluator errors/times out depends on which enforcement path the caller uses.
Evidence
Engine — steer errors are explicitly non-blocking; only deny errors fail closed:
engine/src/agent_control_engine/core.py
787 if deny_errored:
788 is_safe = False
790 # Log steer errors for observability (non-blocking)
791 if steer_errored:
797 logger.warning(f"Steer control evaluation failed (non-blocking): ...")
Both deny and steer errors are appended to the returned errors list, but only deny_errored sets is_safe = False. A steer error leaves is_safe unchanged.
SDK integration helper — raises on any non-empty errors:
sdks/python/src/agent_control/integrations/_core.py
73 if result.errors:
77 raise RuntimeError(
78 "Control evaluation failed; execution blocked for safety. ..."
Impact
- A caller using the framework integration path (
_core.py _evaluate_and_enforce, i.e. the ADK/Strands plugins and @control) blocks on a steer-control error.
- A caller invoking
evaluate_controls() directly gets is_safe=True (with the steer error present in result.errors) and does not block unless it inspects errors itself.
Same evaluator error, opposite enforcement outcome, depending on entry point. Easy to hit when a steer control's evaluator times out (e.g. a server-side scorer that is slow or unreachable).
Ask
Decide the intended semantics for a steer-control error (as opposed to a steer match) and make the engine and the integration helper agree:
- If steer errors should be non-blocking,
_core.py should not raise on steer-only errors (filter by action, or key off is_safe).
- If they should block, the engine should set
is_safe = False on steer_errored too.
Either way, document the chosen behavior. Found while writing runtime-behavior docs and verified against the current source paths above.
Summary
The engine and the SDK integration helper disagree on whether a steer-control evaluation error blocks execution. The engine treats it as non-blocking; the
integrations/_core.pyhelper raises on any error. So whether a steered step is blocked when its evaluator errors/times out depends on which enforcement path the caller uses.Evidence
Engine — steer errors are explicitly non-blocking; only deny errors fail closed:
engine/src/agent_control_engine/core.pyBoth deny and steer errors are appended to the returned
errorslist, but onlydeny_erroredsetsis_safe = False. A steer error leavesis_safeunchanged.SDK integration helper — raises on any non-empty
errors:sdks/python/src/agent_control/integrations/_core.pyImpact
_core.py_evaluate_and_enforce, i.e. the ADK/Strands plugins and@control) blocks on a steer-control error.evaluate_controls()directly getsis_safe=True(with the steer error present inresult.errors) and does not block unless it inspectserrorsitself.Same evaluator error, opposite enforcement outcome, depending on entry point. Easy to hit when a
steercontrol's evaluator times out (e.g. a server-side scorer that is slow or unreachable).Ask
Decide the intended semantics for a steer-control error (as opposed to a steer match) and make the engine and the integration helper agree:
_core.pyshould not raise on steer-only errors (filter by action, or key offis_safe).is_safe = Falseonsteer_erroredtoo.Either way, document the chosen behavior. Found while writing runtime-behavior docs and verified against the current source paths above.