@outputai/llm. Generation APIs drop native AI SDK call arguments. Skills load only from prompt frontmatter. Call-argument tools merge with prompt YAML tools. Prompt file config is a strict key list. Loaded messages carry resolved providerOptions instead of tag attributes. LLM traces use a single loaded prompt on start and cost / merged sources on end.
Skills load only from the prompt file
generateText, streamText, generateTextWithStreaming, and Agent no longer accept a skills argument. Dynamic skill resolvers (sync or async functions) are gone with it. Passing skills throws:
skill() is no longer exported. Colocated skills/ auto-discovery is gone: a skills/ folder next to the prompt is not loaded unless you list it in frontmatter.
Move call-argument and inline skills into the prompt
Before
After
Put the instructions in a markdown file and list the path in frontmatter. Paths are relative to the prompt file.prompts/skills/audience.md
prompts/writer@v1.prompt
.md file under it (recursive):
Restore colocated skills that used auto-discovery
Before
skills: key in the prompt. Output discovered ./skills automatically.
After
Keep the folder. Add an explicit path:Prompt tools and call-argument tools merge
Call-argumenttools no longer replace the whole prompt YAML tools map.
- Prompt YAML tools and call-argument tools are merged.
- The same key: the caller wins.
- When skills are present,
load_skillis added last and cannot be overridden.
Before
googleSearch was dropped. Only lookup was sent.
After
Both are sent:{ googleSearch, lookup }. If you meant to disable YAML tools, remove them from the prompt (or override that key on the call).
Loaded prompt shape
loadPrompt returns the parsed prompt object.
Before
After
SkillsArg and Skill types are removed. Skills are now internal loaded values; declare file paths in prompt frontmatter instead of constructing or typing skill objects.
Per-message options resolve at load
v0.11 kept the role tag’sattributes on the loaded message and compiled options="..." into AI SDK providerOptions at generate time. v0.12 compiles that at loadPrompt. LLM traces (input.prompt.messages) use the same loaded shape.
Before
After
options. Any other attribute throws at load (previously this could fail later, at generate):
options names, options without a value, and options set while config.messageOptions is missing or empty also throw at load.
Prompt message roles are narrowed
PromptMessage.role is now typed as 'system' | 'user' | 'assistant' instead of string, matching the authored role blocks accepted by loadPrompt(). Code that constructs a PromptMessage from a dynamic string must validate or narrow the value before assigning it.
Prompt bodies use explicit parsing modes
v0.11 searched the rendered body for supported role blocks wherever they appeared. This could silently ignore text outside those blocks, unknown top-level tags, and malformed attributes. v0.12 selects one mode from the first meaningful token after leading whitespace and HTML comments:- Plain text selects instruction mode. The whole trimmed body becomes
prompt.instructions, including any tags that appear later. - A tag selects message mode. The complete body is validated as top-level role blocks and
prompt.instructionsisnull.
loadPrompt() output; API requirements are unchanged. generateText, generateTextWithStreaming, streamText, and Agent require message mode, while generateImage requires instruction mode.
For example, v0.11 extracted the <user> block here and discarded the surrounding text:
- Top-level blocks must use
system,user, orassistant. - Only whitespace and HTML comments may appear between blocks.
- Root self-closing tags, unmatched closing tags, and unclosed blocks throw.
- Different-name tags inside a message remain literal message content.
- A nested non-self-closing tag with the same name as its message throws instead of prematurely closing the outer block. Escape literal examples, such as
<user>example</user>. - Attribute names, separators, and quotes are validated. Spaces around
=and>inside quoted values are supported; malformed fragments no longer pass silently.
<tool> blocks. Their string content never matched AI SDK’s structured tool-result message contract, so text generation rejected them. AI SDK continues to create tool messages during execution, and Agent callers may supply structured tool messages through messages or messageStore.
LLM trace details
Start-traceinput on generateText, streamText, generateTextWithStreaming, generateImage, and Agent (generate, generateWithStreaming, stream) is the loaded prompt object only. Filename, interpolation values, and rendered config live on that object. Agent traces use the same shape as the text APIs (v0.11 recorded only the filename as prompt).
End-trace output adds cost (the same payload as the cost attribute / cost:llm:request event; null when pricing is missing) and replaces tool-only sourcesFromTools with merged sources (tool results plus native provider sources; always an array).
Start (input)
Before
After
input.prompt as a filename, use input.prompt.name. If you read input.loadedPrompt, switch to input.prompt. If you read sibling input.variables, use input.prompt.variables.
End (output)
Before
After
output.sourcesFromTools, switch to output.sources. If you relied on cost only as a trace attribute, it is also on output.cost.
Response source and cost types
ExtractedSource now matches the AI SDK source union. A source can be a URL or a document, so narrow on sourceType before reading url:
LLMCallCost and LLMUsageEvent now represent a live Tracing.Attribute.LLMUsage instance. The old components and message fields are gone; read the priced dimensions from usage. A missing calculation is represented by response.cost === null, not an object with total: null.
If you type a serialized event, omit the instance method that is not present in JSON:
AI SDK helpers come from aiSdk
@outputai/llm no longer re-exports tool, Output, smoothStream, stepCountIs, hasToolCall, or jsonSchema as named exports. The namespace re-export ai is renamed to aiSdk.
Before
After
import { ai } from '@outputai/llm' becomes import { aiSdk } from '@outputai/llm'. Output APIs (generateText, Agent, loadPrompt, …) stay named exports.
Cherry-picked AI SDK type re-exports (ToolSet, FinishReason, ModelMessage, StreamTextOnChunkCallback, …) are also gone. Import those from ai, or as aiSdk.ToolSet.
Replace removed Output option types
The Output-owned AI SDK option aliases were removed with the unrestricted native arguments. Use the corresponding public parameter type:OutputAgentGenerateWithStreamingParameters no longer accepts an output type argument. Remove the generic:
Call arguments are a fixed list
Dropped native AI SDK call arguments fromgenerateText(), generateTextWithStreaming(), streamText(), generateImage(), and Agent. Calls no longer accept temperature, maxTokens, maxSteps, providerOptions, image n/size/seed, experimental_transform, onStepFinish, and similar. Unknown keys throw. Set model and image config (including maxSteps, default 10) on the prompt file; call-argument stopWhen still overrides it.
generateImage mask still requires images. Agent.stream() now appends to messageStore in its wrapped onFinish when finishReason is not 'error'.
streamText() and Agent.stream() now treat onError as a fire-and-forget observer. Output maps and forwards the provider error, but exceptions and rejected promises from the callback are ignored. To fail a workflow step with the original error, capture it in onError and throw it after consuming the stream.
Agent message store
conversationStore is renamed to messageStore. The type is MessageStore. createMemoryConversationStore() is removed; implement the store yourself.
Before
After
Move model config onto the prompt
Before
After
prompts/writer@v1.prompt
googleSearch / urlContext, now get stopWhen: stepCountIs(maxSteps) from that prompt value. Previously the ceiling applied only when call-argument tools or load_skill were present; YAML-only grounding stayed at the AI SDK default of one step.
If you need the old one-step grounding behavior, set maxSteps: 1 on the prompt, or pass stopWhen on the call:
Agent constructor validation
new Agent( {} ) no longer throws Agent requires a prompt. Invalid constructor args use the same schema as generateText and throw Invalid Agent() arguments.
That includes a missing/empty prompt, an empty promptDir, and call-argument skills or maxSteps fields.
Prompt config is a strict key list
Unknown top-level keys on a.prompt file now throw Invalid prompt file. Previously they were kept on config and ignored. provider and model must be non-empty strings, and maxTokens must be a positive integer. Nested providerOptions (including thinking) stays open.
Allowed top-level keys: provider, model, temperature, maxTokens, maxSteps, skills, tools, providerOptions, messageOptions, n, maxImagesPerCall, size, aspectRatio, seed.
Snake_case aliases of those keys fail with a suggestion:
providerOptions. effort and reasoningEffort at the top level are unknown keys; they belong under providerOptions.anthropic and providerOptions.openai.
Before
After
Checklist
- Delete
skillsfromgenerateText/streamText/generateTextWithStreaming/Agentcalls. - Remove
skill(),Skill, andSkillsArgimports; move inline skills into files listed under promptskills:. - Add
skills: ./skills(or explicit file paths) to prompts that relied on colocated auto-discovery. - Expect YAML tools and call-argument tools to merge; remove YAML tools if you previously relied on replacement.
- Strip dropped call arguments from
generateText/generateTextWithStreaming/streamText/generateImage/Agent(temperature,maxTokens,maxSteps,providerOptions,maxRetries,experimental_transform,onStepFinish, imagen/size/seed, and any other AI SDK-only keys). Unknown keys throw. Put model and image config on the prompt file; call-argumentstopWhenstill overridesmaxSteps. - Set
maxSteps: 1on YAML-only grounding prompts that must stay one-shot, or passstopWhen: aiSdk.stepCountIs(1)on the call. - Rename
promptFileDirtofileDir. Read interpolation values fromprompt.variables. - Treat
config.skillsas alwaysstring[]afterloadPrompt. - Treat
config.maxStepsas always a positive integer afterloadPrompt(default 10). - Treat
prompt.instructionsas alwaysstring | nullafterloadPrompt(chat prompts arenull). - Read
message.providerOptionsinstead ofmessage.attributesonloadPromptresults and LLM traceinput.prompt.messages. - Narrow dynamic role strings before assigning them to
PromptMessage.role; the type now accepts only'system','user', and'assistant'. - Remove unknown attributes from role tags (
name,id,pinned, …). Onlyoptionsis allowed; extras throw atloadPrompt. - Remove authored
<tool>blocks from prompt files; pass structured tool history through AgentmessagesormessageStore. - Audit prompt bodies that put prose before the first role tag. They now load as instructions; move the prose inside a role block to keep message mode.
- Remove text between or after top-level role blocks. Only whitespace and HTML comments are allowed there.
- Escape literal same-name role tags inside messages (
<user>...</user>). Different-name semantic tags remain valid content. - Give every
optionsattribute a value and fix malformed attribute names or quotes; prompt markup now fails explicitly at load. - Read LLM trace
input.promptas the loaded prompt object (input.prompt.name,input.prompt.variables). Do not treatinput.promptas a filename or readinput.loadedPrompt. - Read LLM trace
output.sourcesinstead ofoutput.sourcesFromTools. Expectoutput.coston successful LLM nodes (nullwhen pricing is missing). - Narrow
ExtractedSourceonsourceTypebefore readingurl. TreatLLMCallCost/LLMUsageEventas live usage instances and omitaddUsagewhen typing serialized JSON. - Import AI SDK helpers and types from
aiSdk(aiSdk.Output,aiSdk.tool,aiSdk.stepCountIs,aiSdk.ToolSet, …). Replaceimport { ai }withimport { aiSdk }. Do not import cherry-picked AI SDK types from@outputai/llm. - Replace
GenerateTextAiSdkOptions,StreamTextAiSdkOptions, andGenerateImageAiSdkOptionswith their*Parametersequivalents. Remove the generic fromOutputAgentGenerateWithStreamingParameters. - Expect
Agent.stream()to persist message-store history on success. - Replace
conversationStorewithmessageStore. ReplaceConversationStorewithMessageStore. RemovecreateMemoryConversationStore()and pass your own store. - Update Agent tests and error matchers that expected
Agent requires a prompt. - Ensure prompt
providerandmodelvalues are non-empty, and setmaxTokensto a positive integer. - Move unknown prompt frontmatter keys (
topP,effort,reasoningEffort,max_tokens) onto the allowlist or underproviderOptions. ExpectInvalid prompt filefor leftover extras.