import { completion_judge_feedback_prompt, completion_judge_system_prompt } from "std/agent/prompts"
import { agent_reasoning_apply } from "std/agent/reasoning"
fn __profile_defaults(profile) {
if profile == "tool_using" {
return {max_iterations: 50, max_nudges: 8, tool_retries: 0, llm_retries: 2, schema_retries: 0}
}
if profile == "researcher" {
return {max_iterations: 30, max_nudges: 4, tool_retries: 0, llm_retries: 2, schema_retries: 0}
}
if profile == "verifier" {
return {max_iterations: 5, max_nudges: 0, tool_retries: 0, llm_retries: 2, schema_retries: 3}
}
if profile == "completer" {
return {max_iterations: 1, max_nudges: 0, tool_retries: 0, llm_retries: 2, schema_retries: 0}
}
throw "agent_loop: profile must be one of tool_using, researcher, verifier, completer"
}
fn __completion_judge_defaults(value, opts) {
if type_of(value) == "bool" && value {
return {
system: completion_judge_system_prompt(opts),
feedback_fallback: completion_judge_feedback_prompt(opts),
}
}
return value
}
fn __has_key(opts, key) {
return contains(opts.keys(), key)
}
fn __judge_enabled(value) {
if value == nil {
return false
}
if type_of(value) == "bool" {
return value
}
if type_of(value) == "dict" {
let enabled = value?.enabled
if enabled == nil {
return true
}
return enabled
}
return true
}
fn __client_tool_search_requested(value) {
return type_of(value) == "dict" && value?.mode == "client"
}
fn __model_tool_format(opts) {
if opts?.model == nil {
return nil
}
let resolved = try {
llm_resolve_model(opts.model)
}
if is_err(resolved) {
return nil
}
return unwrap(resolved)?.tool_format
}
fn __native_tools_complete_naturally(opts) {
return opts?.tools != nil && opts?.tool_format == "native"
}
fn __task_ledger_deliverable_text(value) {
let text = if type_of(value) == "string" {
value
} else {
to_string(value)
}
return trim(text)
}
fn __task_ledger_from_shorthand(opts) {
let root_task = trim(opts?.root_task ?? "")
var deliverables = []
let shorthand = opts?.deliverables
if type_of(shorthand) == "list" {
for (index, item) in iter(shorthand).enumerate() {
let text = __task_ledger_deliverable_text(item)
if text != "" {
deliverables = deliverables
.push({id: "deliverable-" + to_string(index + 1), text: text, status: "open", note: nil})
}
}
}
if root_task == "" && len(deliverables) == 0 {
return nil
}
return {root_task: root_task, deliverables: deliverables, rationale: "", observations: []}
}
fn __with_task_ledger_shorthand(opts) {
if __has_key(opts, "task_ledger") {
return opts
}
let ledger = __task_ledger_from_shorthand(opts)
if ledger == nil {
return opts
}
return opts + {task_ledger: ledger}
}
fn __validate_done_sentinel(value) {
if value == nil {
return
}
let kind = type_of(value)
if kind != "string" {
throw "agent_loop: `done_sentinel` must be a non-empty string or nil; got " + kind
}
if trim(value) == "" {
throw "agent_loop: `done_sentinel` must be a non-empty string or nil; got empty string"
}
}
fn __validate_verify_completion(value) {
if value == nil {
return
}
if type_of(value) != "closure" {
throw "agent_loop: `verify_completion` must be a closure or nil; got " + type_of(value)
}
}
fn __validate_judge_dict_or_bool(label, value) {
if value == nil {
return
}
let kind = type_of(value)
if kind != "dict" && kind != "bool" {
throw "agent_loop: `" + label + "` must be a dict, bool, or nil; got " + kind
}
}
fn __validate_optional_positive_int(label, field, value) {
if value == nil {
return
}
if type_of(value) != "int" {
throw "agent_loop: `" + label + "." + field + "` must be an integer or nil; got "
+ type_of(value)
}
if value < 1 {
throw "agent_loop: `" + label + "." + field + "` must be >= 1"
}
}
fn __validate_optional_nonnegative_int(label, field, value) {
if value == nil {
return
}
if type_of(value) != "int" {
throw "agent_loop: `" + label + "." + field + "` must be an integer or nil; got "
+ type_of(value)
}
if value < 0 {
throw "agent_loop: `" + label + "." + field + "` must be >= 0"
}
}
fn __validate_judge_cadence(label, value) {
if value == nil {
return
}
if type_of(value) != "dict" {
throw "agent_loop: `" + label + "` must be a dict or nil; got " + type_of(value)
}
__validate_optional_positive_int(label, "every", value?.every)
__validate_optional_nonnegative_int(label, "max_invocations", value?.max_invocations)
__validate_optional_nonnegative_int(
label,
"min_iterations_before_first",
value?.min_iterations_before_first,
)
let when = value?.when
if when == nil {
return
}
let kind = type_of(when)
if kind == "closure" {
return
}
if kind == "string" && (when == "always" || when == "stalled") {
return
}
throw "agent_loop: `" + label + ".when` must be \"always\", \"stalled\", a closure, or nil; got "
+ to_string(when)
}
fn __validate_done_judge_cadence(value) {
if type_of(value) == "dict" {
__validate_judge_cadence("done_judge.cadence", value?.cadence)
}
}
fn __positive_int_default(value, fallback) {
if value == nil {
return fallback
}
if type_of(value) != "int" {
throw "agent_loop: iteration_budget numeric fields must be integers; got " + type_of(value)
}
if value < 1 {
return fallback
}
return value
}
fn __validate_loop_control(value) {
if value == nil {
return
}
if type_of(value) != "closure" {
throw "agent_loop: `loop_control` must be a closure or nil; got " + type_of(value)
}
}
fn __validate_llm_caller(value) {
if value == nil {
return
}
if type_of(value) != "closure" {
throw "agent_loop: `llm_caller` must be a closure or nil; got " + type_of(value)
}
}
fn __validate_tool_caller(value) {
if value == nil {
return
}
if type_of(value) != "closure" {
throw "agent_loop: `tool_caller` must be a closure or nil; got " + type_of(value)
}
}
fn __validate_max_concurrent_tools(value) {
if value == nil {
return
}
if type_of(value) != "int" {
throw "agent_loop: `max_concurrent_tools` must be an integer or nil; got " + type_of(value)
}
if value < 1 {
throw "agent_loop: `max_concurrent_tools` must be >= 1; got " + to_string(value)
}
}
fn __validate_prefetch_next_turn(value) {
if value == nil {
return
}
if type_of(value) != "bool" {
throw "agent_loop: `prefetch_next_turn` must be a bool or nil; got " + type_of(value)
}
}
fn __validate_removed_agent_loop_options(opts) {
if __has_key(opts, "persistent") {
throw "agent_loop: `persistent` was removed; use `loop_until_done` for completion looping and `session_id` for transcript persistence"
}
}
fn __validate_agent_loop_completion_options(opts) {
if __has_key(opts, "done_sentinel") {
__validate_done_sentinel(opts.done_sentinel)
}
if __has_key(opts, "verify_completion") {
__validate_verify_completion(opts.verify_completion)
}
if __has_key(opts, "verify_completion_judge") {
__validate_judge_dict_or_bool("verify_completion_judge", opts.verify_completion_judge)
}
if __has_key(opts, "done_judge") {
__validate_judge_dict_or_bool("done_judge", opts.done_judge)
__validate_done_judge_cadence(opts.done_judge)
}
}
fn __validate_agent_loop_callback_options(opts) {
if __has_key(opts, "loop_control") {
__validate_loop_control(opts.loop_control)
}
if __has_key(opts, "llm_caller") {
__validate_llm_caller(opts.llm_caller)
}
if __has_key(opts, "tool_caller") {
__validate_tool_caller(opts.tool_caller)
}
if __has_key(opts, "max_concurrent_tools") {
__validate_max_concurrent_tools(opts.max_concurrent_tools)
}
if __has_key(opts, "prefetch_next_turn") {
__validate_prefetch_next_turn(opts.prefetch_next_turn)
}
}
fn __normalize_iteration_budget(opts) {
let raw = opts?.iteration_budget
let legacy = opts?.max_iterations
if raw == nil && legacy == nil {
return {mode: "fixed", initial: 50, max: 50, extend_by: 0, expose_decisions: false}
}
let user_budget = if type_of(raw) == "string" {
{mode: raw}
} else {
raw
}
if user_budget == nil {
let cap = __positive_int_default(legacy, 50)
return {mode: "fixed", initial: cap, max: cap, extend_by: 0, expose_decisions: false}
}
if type_of(user_budget) != "dict" {
throw "agent_loop: iteration_budget must be a dict, string, or nil; got "
+ type_of(user_budget)
}
let mode = user_budget.mode ?? "fixed"
if mode != "fixed" && mode != "adaptive" {
throw "agent_loop: iteration_budget.mode must be \"fixed\" or \"adaptive\"; got "
+ to_string(mode)
}
let legacy_cap = if legacy != nil {
__positive_int_default(legacy, 50)
} else {
nil
}
let max_default = if mode == "adaptive" {
16
} else if legacy_cap != nil {
legacy_cap
} else {
50
}
let max_cap = __positive_int_default(user_budget?.max, max_default)
let initial_default = if mode == "adaptive" {
let candidate = max_cap / 4
if candidate < 1 {
1
} else {
candidate
}
} else {
max_cap
}
var initial = __positive_int_default(user_budget?.initial, initial_default)
if initial > max_cap {
initial = max_cap
}
let extend_by = if mode == "adaptive" {
__positive_int_default(user_budget?.extend_by, 2)
} else {
0
}
let expose_decisions = if user_budget?.expose_decisions != nil {
user_budget.expose_decisions
} else {
mode == "adaptive"
}
return {
mode: mode,
initial: initial,
max: max_cap,
extend_by: extend_by,
expose_decisions: expose_decisions,
}
}
fn __autonomy_tier(value) {
let tier = value ?? "act_auto"
if tier == "shadow" || tier == "suggest" || tier == "act_with_approval" || tier == "act_auto" {
return tier
}
throw "autonomy_policy: tier must be one of shadow, suggest, act_with_approval, act_auto"
}
/** autonomy_policy returns the VM-enforced autonomy assignment for an agent. */
pub fn autonomy_policy(tier = "act_auto", options = nil) {
let opts = options ?? {}
return {
agent_id: opts?.agent_id ?? opts?.agent,
autonomy_tier: __autonomy_tier(tier),
action_tiers: opts?.action_tiers ?? {},
agent_tiers: opts?.agent_tiers ?? {},
agent_action_tiers: opts?.agent_action_tiers ?? {},
reviewers: opts?.reviewers ?? [],
}
}
/** agent_loop_options. */
pub fn agent_loop_options(options = nil) {
var opts = options ?? {}
__validate_removed_agent_loop_options(opts)
__validate_agent_loop_completion_options(opts)
__validate_agent_loop_callback_options(opts)
let llm_caller = opts?.llm_caller
let tool_caller = opts?.tool_caller
let profile = opts?.profile ?? "tool_using"
let defaults = __profile_defaults(profile)
opts = defaults + opts
if !__has_key(opts, "tool_format") && opts?.tools != nil {
let model_tool_format = __model_tool_format(opts)
if model_tool_format != nil {
opts = opts + {tool_format: model_tool_format}
}
}
if !__has_key(opts, "tool_format")
&& (opts?.tools == nil || __client_tool_search_requested(opts?.tool_search)) {
opts = opts + {tool_format: "text"}
}
if opts?.loop_until_done ?? false && !__has_key(opts, "done_sentinel") {
opts = opts
+ {
done_sentinel: if __native_tools_complete_naturally(opts) {
nil
} else {
"##DONE##"
},
}
}
if __has_key(opts, "done_judge") && __judge_enabled(opts?.done_judge)
&& !__has_key(opts, "done_sentinel")
&& !__native_tools_complete_naturally(opts) {
opts = opts + {done_sentinel: "##DONE##"}
}
if __has_key(opts, "verify_completion_judge") {
if __judge_enabled(opts?.verify_completion_judge) {
opts = opts
+ {verify_completion_judge: __completion_judge_defaults(opts?.verify_completion_judge, opts)}
} else {
opts = opts + {verify_completion_judge: nil}
}
}
if __has_key(opts, "done_judge") {
if __judge_enabled(opts?.done_judge) {
opts = opts + {done_judge: __completion_judge_defaults(opts?.done_judge, opts)}
} else {
opts = opts + {done_judge: nil}
}
}
opts = __with_task_ledger_shorthand(opts)
let budget = __normalize_iteration_budget(opts)
opts = opts + {iteration_budget: budget, max_iterations: budget.max}
opts = agent_reasoning_apply(opts)
opts = opts + {_llm_caller: llm_caller, _tool_caller: tool_caller}
return opts
}