import {
agent_tool_lifecycle_error_category,
agent_tool_result_is_ok,
agent_tool_result_outcome,
} from "std/agent/tool_lifecycle"
/**
* Host dispatches are canonically a result list; a turn without tools has no
* dispatch. Normalize the absent case here so downstream policy stays shape
* agnostic.
*/
pub type AgentToolDispatch = list?
pub fn __dispatch_results_list(dispatch: AgentToolDispatch) -> list {
return dispatch ?? []
}
fn __error_category_is_dispatch_rejection(category: any) -> bool {
return category == "schema_validation" || category == "permission_denied"
}
/**
* Dispatch rejection from STRUCTURED fields only: the outer envelope's typed
* error category (via `agent_tool_result_outcome`), or the nested host body
* `result.error` / `result.error_category` that denial producers already stamp.
* Never substring-matches rendered prose.
*
* @effects: []
* @errors: []
*/
pub fn __tool_result_dispatch_rejection(result: dict) -> bool {
if type_of(result) != "dict" {
return false
}
const outcome = agent_tool_result_outcome(result)
if __error_category_is_dispatch_rejection(outcome.error_category) {
return true
}
const nested = result?.result
if type_of(nested) == "dict" {
const nested_cat = agent_tool_lifecycle_error_category(nested?.error_category ?? nested?.error)
if __error_category_is_dispatch_rejection(nested_cat) {
return true
}
}
return false
}
pub fn __tool_result_product_error(result: dict) -> bool {
if type_of(result) != "dict" {
return false
}
const outcome = agent_tool_result_outcome(result)
if outcome.product_error != nil {
return outcome.product_error ? true : false
}
return __tool_result_dispatch_rejection(result)
}
pub fn __tool_result_ok(result: dict) -> bool {
const outcome = agent_tool_result_outcome(result)
const structured = agent_tool_result_is_ok(outcome)
if structured == false {
return false
}
if __tool_result_product_error(result) {
return false
}
if structured == true {
return true
}
if result?.ok != nil {
return result.ok ? true : false
}
if result?.success != nil {
return result.success ? true : false
}
const status = result?.status ?? ""
return status == "ok" || status == "success"
}
pub fn __tool_result_name(result: dict) {
return result?.tool_name ?? result?.name ?? ""
}
pub fn __tool_names_by_status(dispatch: AgentToolDispatch, want_ok: bool) -> list<string> {
const results = __dispatch_results_list(dispatch)
let names = []
for result in results {
const name = __tool_result_name(result)
if name != "" && __tool_result_ok(result) == want_ok {
names = names.appending(name)
}
}
return names
}