// @harn-entrypoint-category agent.stdlib
import { filter_nil, pick_keys } from "std/collections"
fn __agent_option_keys() {
return [
"provider",
"model",
"model_tier",
"temperature",
"top_p",
"top_k",
"max_tokens",
"thinking",
"reasoning_effort",
"reasoning_policy",
"thinking_policy",
"reasoning_scale",
"problem_scale",
"reasoning_task",
"tools",
"max_iterations",
"max_nudges",
"nudge",
"turn_policy",
"tool_format",
"native_tool_fallback",
"structural_experiment",
"context_callback",
"context_filter",
"tool_retries",
"tool_backoff_ms",
]
}
/** agent creates an agent spec dict. */
pub fn agent(name, config = nil) {
if type_of(name) != "string" {
throw "agent: name must be a string"
}
let cfg = config ?? {}
if type_of(cfg) != "dict" {
throw "agent: second argument must be a config dict"
}
return cfg + {_type: "agent", name: name}
}
/** agent_name reads an agent spec name. */
pub fn agent_name(agent) {
if type_of(agent) != "dict" {
throw "agent_name: argument must be an agent"
}
return agent?.name
}
/** agent_config builds prompt/system/options for an agent spec. */
pub fn agent_config(agent, prompt) {
if type_of(agent) != "dict" || agent?._type != "agent" {
throw "agent_config: first argument must be an agent (created with agent())"
}
let options = pick_keys(agent, __agent_option_keys(), {drop_nil: true})
return {prompt: prompt, system: agent?.system, options: options}
}
fn __worker_dict(value) {
if type_of(value) == "dict" {
return value
}
return {}
}
fn __worker_list(value) {
if type_of(value) == "list" {
return value
}
return []
}
fn __worker_options(value, label) {
if value == nil {
return {}
}
if type_of(value) == "dict" {
return value
}
throw label + ": options must be a dict or nil"
}
fn __worker_mode(config) {
if config?.graph != nil {
return "workflow"
}
return "stage"
}
fn __worker_workflow_config(config) {
let options = __worker_dict(config?.options)
return filter_nil(
config
+ {graph: workflow_graph(config.graph), artifacts: __worker_list(config?.artifacts), options: options},
)
}
fn __worker_stage_config(config) {
return filter_nil(
config + {artifacts: __worker_list(config?.artifacts), options: __worker_dict(config?.options)},
)
}
fn __worker_config(config) {
let cfg = __worker_dict(config)
let mode = __worker_mode(cfg)
if mode == "workflow" {
return __worker_workflow_config(cfg)
}
return __worker_stage_config(cfg)
}
/** spawn_agent. */
pub fn spawn_agent(config) {
return __host_worker_spawn(__worker_config(config))
}
/** send_input. */
pub fn send_input(worker, task) {
return __host_worker_send_input(worker, task)
}
/** worker_trigger. */
pub fn worker_trigger(worker, payload) {
return __host_worker_trigger(worker, payload)
}
/** wait_agent. */
pub fn wait_agent(worker_or_workers) {
return __host_worker_wait(worker_or_workers)
}
/** close_agent. */
pub fn close_agent(worker) {
return __host_worker_close(worker)
}
/** resume_agent. */
pub fn resume_agent(worker_or_snapshot) {
return __host_worker_resume(worker_or_snapshot)
}
/** list_agents. */
pub fn list_agents() {
return __host_worker_list()
}
fn __sub_agent_string(value, fallback = "") {
if type_of(value) != "string" {
return fallback
}
let text = trim(value)
if text == "" {
return fallback
}
return value
}
fn __sub_agent_string_list(value, label) {
if value == nil {
return []
}
if type_of(value) != "list" {
throw label + ": expected a list of strings"
}
var out = []
for item in value {
if type_of(item) != "string" {
throw label + ": expected a list of strings"
}
let text = trim(item)
if text != "" && !contains(out, text) {
out = out.push(text)
}
}
return out
}
fn __sub_agent_base_tools(opts) {
if opts?.tools != nil {
return opts.tools
}
return __host_current_tool_registry()
}
fn __sub_agent_selected_tools(opts, allowed_tools) {
let base = __sub_agent_base_tools(opts)
if len(allowed_tools) == 0 {
return base
}
if base == nil {
return nil
}
return tool_select(base, allowed_tools)
}
fn __sub_agent_options(opts, session_id, selected_tools) {
var out = {}
let internal = [
"background",
"carry",
"returns",
"allowed_tools",
"name",
"execution",
"system",
"session_id",
"policy",
]
for key in opts.keys() {
if !contains(internal, key) {
out = out + {[key]: opts[key]}
}
}
out = out + {session_id: session_id}
if selected_tools != nil {
out = out + {tools: selected_tools}
}
return out
}
/** sub_agent_request builds the Harn-owned child-agent request envelope. */
pub fn sub_agent_request(task, options = nil) {
let task_text = __sub_agent_string(task)
if task_text == "" {
throw "sub_agent_run: task is required"
}
let opts = __worker_options(options, "sub_agent_run")
let allowed_tools = __sub_agent_string_list(opts?.allowed_tools, "sub_agent_run.allowed_tools")
let selected_tools = __sub_agent_selected_tools(opts, allowed_tools)
let session_id = __sub_agent_string(opts?.session_id, "sub_agent_session_" + uuid_v7())
return filter_nil(
{
_type: "sub_agent_request",
name: __sub_agent_string(opts?.name, "sub-agent"),
task: task_text,
system: __sub_agent_string(opts?.system, nil),
options: __sub_agent_options(opts, session_id, selected_tools),
returns_schema: opts?.returns?.schema,
session_id: session_id,
background: opts?.background ? true : false,
carry: opts?.carry,
execution: opts?.execution,
policy: opts?.policy,
allowed_tools: allowed_tools,
},
)
}
/** sub_agent_run. */
pub fn sub_agent_run(task, options = nil) {
return __host_sub_agent_run(sub_agent_request(task, options))
}