dynamicAgent / dynamic_agent
Describe a dynamic agent: a template in a lead's team whose members the lead (or team.start) defines at runtime within what this code pins.
A start may choose only a label, instructions (added last, in a delimited block), a subset of this template's tools (built-ins included; the framework tools are always kept) and a models key; everything else (permissions, hooks, skills, memory, sandbox, budget, output) is this config. Only a team lists it: in subagents or handoffs it is ConfigError invalid_config. The lead's instructions list its choosable tools and model keys, so renaming a tool or a key changes the lead's pinned config and an existing lead thread no longer continues. Tools of its MCP servers are choosable but not listed, since the listing never waits on a connection. Pure, like agent().
Import from @threads/core (TypeScript) or threads (Python).
function dynamicAgent(options: {
models: Record<string, Model>;
instructions?: string;
name?: Name;
tools?: readonly (Tool | McpServer)[];
extensions?: readonly Extension[];
sandbox?: Sandbox;
memory?: MemoryProvider;
memoryWrite?: "deny" | "ask" | "allow_principal" | "allow";
knowledge?: KnowledgeProvider;
skills?: readonly Skill[];
output?: z.ZodType<Output>;
outputRetries?: number;
fallback?: readonly Model[];
permissions?: Partial<Policy.permissions>;
approvers?: readonly Principal[];
budget?: Budget;
onUnknownUsage?: Policy.on_unknown_usage;
retry?: Partial<Policy.retry>;
context?: Partial<Policy.context>;
egress?: readonly string[] | "unenforced";
web?: { fetch?: boolean; search?: SearchBackend };
git?: { credential: Secret; forgeUrl?: string; apiUrl?: string };
computer?: boolean;
lsp?: { languages: readonly string[] };
outputStyles?: Record<string, string>;
}): DynamicAgent<Deps, Output>Parameters
modelsRecord<string, Model>requiredThe models a starter may choose from, by key, in order: the first key is the default. Non-empty, each key a name (lowercase letters, digits and underscores, starting with a letter), else ConfigError invalid_config. A start's model field names a key; the member runs that model.
instructionsstringThe fixed preamble every member of this template starts its the system prompt with. A starter's written instructions follow it and everything else, in a delimited block that comes last. Omitted: none.
nameNamedefault agentThe template's name: the agent a start names, and each member is <name>-<k>. Unique in the team tree; operator is reserved.
toolsreadonly (Tool | McpServer)[]default []App tools and MCP servers. Built-in tools come from the sandbox and the options below.
extensionsreadonly Extension[]default []Instructions and hooks run in this order.
sandboxSandboxThe sandbox the sandbox tools run in: bash and the file tools (read, write, edit, ls, glob, grep). The git, lsp and computer options also need one. Omitted: no sandbox tools. See Sandbox.
memoryMemoryProviderSaved cross-run memory: localMemory() or a memory adapter. It pins save_memory, search_memory and forget_memory. Omitted: the agent has no memory tools. See MemoryProvider.
memoryWrite / memory_write"deny" | "ask" | "allow_principal" | "allow"default askWrite authority for save_memory.
knowledgeKnowledgeProviderRetrieval over sources the host admits: localKnowledge(paths) or a knowledge adapter. It pins search_knowledge. Omitted: the agent has no knowledge tool. See KnowledgeProvider.
skillsreadonly Skill[]default []Pinned in config_hash (name, description, sha256 of body). The system prompt lists them after the extension instructions as "Skills you can load with load_skill:" then one "- name: description" line each, in the given order; load_skill (pinned only when this is non-empty) appends the body as injected{source: skill, trust: trusted_instruction, origin: {id: name, version: sha256 of body}}. Unique names; a description is one non-empty line.
outputz.ZodType<Output>Structured final output: a schema the final answer must parse with. Omitted: completed.output is the final text.
outputRetries / output_retriesnumberdefault 2Failed candidates per turn (a rejected final_output or a plain-text end) before turn_completed{output_invalid}. An integer from 0 to 2^53-1; anything else is ConfigError invalid_config.
fallbackreadonly Model[]default []Fallback models in order. With the default fallback_scope turn, the next user_input reverts to the settings before the fallback (settings_changed{reason: revert}), gated by before_model_switch.
permissionsPartial<Policy.permissions>The permission policy every tool call is decided under: mode, allow, ask and deny rules, protected_paths, allow_bypass and plan_exit_mode. In TypeScript the fields you give override the defaults; Python takes a complete Permissions. Omitted: mode default, no rules, the built-in protected paths, allow_bypass false and plan_exit_mode default.
approversreadonly Principal[]Who may answer approval challenges and resolve parked effects for runs this agent roots, its subagents and handoff targets included. Omitted: only the root run's originating principal (the principal of the root thread's latest user_input).
budgetBudgetThread budget: limits such as max_turns, max_model_requests, max_input_tokens, max_output_tokens, max_cost_nanos and max_wall_ms, checked before every model request. It covers the thread and every descendant. Omitted: no thread budget.
onUnknownUsage / on_unknown_usagePolicy.on_unknown_usagedefault upper_boundHow a budget counts a model attempt the provider reports no usage for. upper_bound counts it at its conservative upper bound; stop lets a limit the model can't bound per attempt pass setup and refuses it at run time instead of failing setup with budget_unenforceable.
retryPartial<Policy.retry>Model retry settings: max_retries, base_delay_ms, max_delay_ms, max_retry_after_ms, max_total_wait_ms, crash_resends, fallback_after, fallback_scope and heartbeat_ms. In TypeScript the fields you give override the defaults; Python takes a complete Retry. Omitted: the default policy (8 retries, 1000 ms base delay doubling up to 32000 ms, fallback after 3 failures in a turn).
contextPartial<Policy.context>Context-window settings: reserve_tokens, clearing old tool results, spilling large results, compaction and what is restored after it, output continuations and tool deferral. In TypeScript the fields you give override the defaults; Python takes a complete Context. Omitted: the default context policy, with cache_ttl_ms from the models' declared cache lifetimes (ModelInfo.cache) when they agree; models that disagree, or whose lifetime is unknown, need cache_ttl_ms set (checked at check() or the first run).
egressreadonly string[] | "unenforced"default []Sandbox egress allowlist of hosts. [] is deny-all. unenforced opts in to a provider that can't enforce it; stub mode then refuses.
web{ fetch?: boolean; search?: SearchBackend }Host-side web tools: web_fetch and web_search run on the host, not in the sandbox. Omitted: no web tools.
web.fetchbooleandefault falsetrue pins web_fetch, which fetches a URL from the host. false (the default) leaves it out.
web.searchSearchBackendThe search backend web_search uses (an adapter such as exa, brave or tavily). Omitted: no web_search tool.
git{ credential: Secret; forgeUrl?: string; apiUrl?: string }Enables the git gateway tools git_clone, git_fetch, git_push and open_pull_request. The forge is GitHub; the credential is revealed only on the host and never enters the sandbox. Needs a sandbox. Omitted: no git tools.
git.credentialSecretrequiredThe forge token, as a secret(). It is revealed only on the host when a git tool talks to the forge, never in the sandbox.
git.forgeUrl / git.forge_urlstringdefault https://github.comA repo owner/name lives at <forge_url>/<owner>/<name>.git.
git.apiUrl / git.api_urlstringdefault https://api.github.comThe forge REST API open_pull_request uses.
computerbooleandefault falsePins computer_screenshot (read_only) and computer (actions, unguarded). Needs a sandbox whose info.desktop is native or image; otherwise a setup error capability_missing.
lsp{ languages: readonly string[] }Pins lsp for these languages (typescript, python, go, rust), run in the sandbox image's language servers. Needs a sandbox; an unknown language is unknown_preset. A server that isn't installed or ready answers unavailable at run time. Omitted: no lsp tool.
lsp.languagesreadonly string[]requiredThe languages lsp serves: typescript, python, go or rust. Any other name is a setup error unknown_preset.
outputStyles / output_stylesRecord<string, string>default {}Named instructions an operator can switch a thread to with Thread.setOutputStyle. Pinned with the agent config; keys and texts non-empty. Omitted: no styles.
Returns
Throws ConfigError for a definition that can't run.