An
llmAgent pairs a system prompt with a tool set. You define what the agent knows and what it can do — the LLM figures out how to do it. It is the TypeScript form of a prompt-driven agent: no agent logic to write, but an Agent SDK package you can extend.
Native agents are LLM-powered too. The names distinguish how you author and run them: a Native agent is Markdown executed by Guild’s managed agent loop, while a TypeScript LLM agent uses the llmAgent Agent SDK template.
For a prompt-driven agent, try a Native agent first — it is the same idea with no code and no container, written as
PROMPT.md plus a guild.yaml tool list. Build an llmAgent when you need something Native does not cover: attachments, a custom input schema, per-agent model preferences, or asking the user to connect an integration.Example
The
description field is optional and deprecated as of @guildai/agents-sdk 0.4.0. Guild generates the agent’s published description automatically from its code, so setting description no longer affects the published description.Input and output
By default, anllmAgent takes text in and returns text out:
Attachments
Pass images or PDFs alongside a turn through the optionalattachments array. Each attachment carries its bytes inline as base64, so the agent sandbox never has to fetch anything over the network:
llmAgent expands each attachment into a data: URL and adds it to the user message as the matching content part. A content_type beginning with image/ becomes an ImagePart; a content_type of exactly application/pdf becomes a FilePart.
Any other
content_type is ignored. The attachment is dropped from the message rather than raising an error, as is any attachment with empty data.data: URL string, it survives state persistence unchanged and is preserved when the agent resumes in a multi-turn session.
Attachments can also arrive from tool results. When a tool returns an attachments array, llmAgent strips those bytes out of the tool result content and sends them as a separate user message, so the model can see the images without the base64 bloating the tool transcript.
Structured input
PassinputSchema to accept a typed object instead of a bare string, and inputTemplate to say how that object becomes the first user message. The template is mustache-style: {{field}}, or a dotted path for a nested value. A field the input does not carry renders as an empty string.
{{text}}.
Execution modes
llmAgent supports two modes:
'one-shot' | 'multi-turn'
default:"'one-shot'"
"one-shot"— The agent processes the input, returns a single response, then terminates."multi-turn"— The agent continues interacting with the user until it calls the__submit__tool to signal task completion.
The __submit__ tool
In "multi-turn" mode, the runtime injects a __submit__ tool that the LLM must call to end the session. You do not declare it in your tools set.
- Purpose — Signals that the agent is done. The value the LLM passes to
__submit__becomes the agent’s final output. Earlier turns in the session are not returned to the caller. - Parallel calls —
__submit__must not be called in the same turn as any other tool. The runtime injects this rule into the system prompt; repeat it in your ownsystemPromptif the model tries to submit while still calling tools. - Completion — Until the LLM calls
__submit__, the session stays open for follow-up messages.
Pre-tool text visibility
When anllmAgent emits text before calling a tool, the runtime preserves it as a continued response stream. By default this text is shown to the user as user-facing progress.
'visible' | 'hidden'
default:"'visible'"
"visible"(default) — Text emitted before a tool call is shown to the user as a continued response stream."hidden"— Pre-tool text is not surfaced. Use this when the agent uses pre-tool text for internal reasoning rather than user-facing progress.
Tool recommendations
ui_notifyis wired internally so progress notifications (task.ui.notify()) work, but it is hidden from the model unless you explicitly addui_notifyto the agent’stools. AdduserInterfaceToolsif the agent needsui_promptorui_ping.- Include
guildToolsif the agent uses tools that require authorization (e.g., GitHub access), so it can request credentials when needed.
Selecting specific tools
Usepick to include only the tools you need. See Selecting specific tools in the SDK reference.
LLM preferences
By default, Guild resolves the provider and model from the workspace owner’s LLM settings. AnllmAgent can express an ordered list of preferred providers — and, optionally, models — with llmPreferences:
model to let the server choose a model from the matching policy.
Preferences are strict, and the account’s model policies have the final say: a preferred model is used only if a policy allows it. If no listed preference is allowed — for example, the account has no key for any preferred provider — the agent’s LLM calls fail with an error naming the refused preferences, rather than silently running on the account’s default model. Declare preferences only when the agent genuinely requires specific models; an agent without llmPreferences always uses the account’s default configuration.
For coded and self-managed agents, pass llmPreferences per call to task.llm.generateText instead. See LLM preferences for that form and the full LLMPreference shape.