Summary
A healthy out-of-turn sys_call_async dispatch reaches the harness policy evaluator with no bound TurnContext, so the tool-call phase has nothing to gate against and fail-closes to DENY. This is secure, but functionally breaks policy-guarded async calls: a sys_call_async to a tool covered by an ASK/DENY policy never executes.
Detail
_spawn_async_tool (omnigent/runner/tool_dispatch.py) launches the background task outside any turn context. When the inner SDK's policy callback fires for that call, ExecutorAdapter._stable_policy_evaluator (omnigent/runtime/harnesses/_executor_adapter.py, PHASE_TOOL_CALL) finds _current_ctx is None and returns the fail-closed default (DENY) — the correct safety posture for an unevaluable verdict, but it means the configured policy is never actually evaluated.
Net effect: an agent that dispatches a guarded tool via sys_call_async gets a hard DENY every time, rather than the ASK/DENY the policy intends.
Proposed fix
Carry or synthesize the originating turn's policy context into the async-dispatch path so the tool-call phase can be evaluated (ASK/DENY) for out-of-turn background calls, instead of fail-closing.
Scope note
Distinct from #522, which covers async completion delivery, not policy-context propagation. Surfaced during review of #1077 (turn-context desync recovery); intentionally deferred there as out of scope for the desync fix.
Summary
A healthy out-of-turn
sys_call_asyncdispatch reaches the harness policy evaluator with no boundTurnContext, so the tool-call phase has nothing to gate against and fail-closes toDENY. This is secure, but functionally breaks policy-guarded async calls: asys_call_asyncto a tool covered by an ASK/DENY policy never executes.Detail
_spawn_async_tool(omnigent/runner/tool_dispatch.py) launches the background task outside any turn context. When the inner SDK's policy callback fires for that call,ExecutorAdapter._stable_policy_evaluator(omnigent/runtime/harnesses/_executor_adapter.py,PHASE_TOOL_CALL) finds_current_ctx is Noneand returns the fail-closed default (DENY) — the correct safety posture for an unevaluable verdict, but it means the configured policy is never actually evaluated.Net effect: an agent that dispatches a guarded tool via
sys_call_asyncgets a hard DENY every time, rather than the ASK/DENY the policy intends.Proposed fix
Carry or synthesize the originating turn's policy context into the async-dispatch path so the tool-call phase can be evaluated (ASK/DENY) for out-of-turn background calls, instead of fail-closing.
Scope note
Distinct from #522, which covers async completion delivery, not policy-context propagation. Surfaced during review of #1077 (turn-context desync recovery); intentionally deferred there as out of scope for the desync fix.