moeru-ai/airi · error · Error
Unsupported Responses assistant content
Error message
Unsupported Responses assistant content
What it means
readOutput projects assistant message items from a Responses output array into portable assistant entries. Within a message item, only output_text and refusal content parts are supported; any other assistant content part type triggers this throw. It protects the portable conversation model from unrepresentable content.
Solutions
- Upgrade the Responses adapter so it maps the new assistant content part type.
- Inspect the continuation/response data and normalize the assistant content to output_text/refusal before projection.
- If the part is ignorable, pre-filter item.content to output_text/refusal parts before calling code that projects it.
Example fix
// before const segments = item.content.map(mapPart) // after const segments = item.content .filter(p => p.type === 'output_text' || p.type === 'refusal') .map(mapPart)
Defensive patterns
Strategy: type-guard
Validate before calling
const bad = item.content.filter(p => p.type !== 'output_text' && p.type !== 'refusal')
if (bad.length) console.warn('unsupported assistant content parts:', bad.map(p => p.type)) Type guard
function isProjectableAssistantPart(part) {
return part?.type === 'output_text' || part?.type === 'refusal'
} Try / catch
try {
entries = readOutput(items)
} catch (err) {
if (err.message === 'Unsupported Responses assistant content') {
console.error('Assistant message contained an unprojectable content part; filter or upgrade adapter.')
} else throw err
} Prevention
- Filter assistant content to output_text/refusal before projection when using newer Responses API features.
- Pin/upgrade core-agent when enabling new model output features.
- Add fixtures covering every assistant content type your model can return.
When it happens
Trigger: generation() -> readOutput() processes a Responses 'message' item with role 'assistant' whose content array contains a part type other than 'output_text' or 'refusal' (e.g. a new API part type such as audio, or a malformed/typo'd type).
Common situations: A model response came back with an assistant content part type the adapter predates (API surface evolution); a mock or fixture hand-builds an assistant message with an unknown part; replaying continuation data captured from a newer API version.
Understand the failure class
Background: "invalid response format", "malformed payload", "missing data field": when an API returns 200 but the response shape is wrong — this error's family across 23 libraries.
Related errors
- Unsupported Responses output item
- Unsupported Responses tool output
- Cannot replay an unfinished function call
- Only assistant messages can invoke tools
- Responses continuation must contain an item array
AI-assisted analysis of moeru-ai/airi@438a067dde (2026-09-17).
Data as JSON: /api/errors/d2f3a96ed80d956c.
Report an issue: GitHub.
Appendix: source
Thrown at packages/core-agent/src/runtime/responses.ts:140
}))
}
function readOutput(items: ItemParam[]): ProjectionEntry[] {
return items.flatMap<ProjectionEntry>((item, index) => {
const id = `output-${index}`
if (item.type === 'function_call')
return [{ id, role: 'assistant', segments: [{ type: 'tool-call', callId: item.call_id, name: item.name, arguments: item.arguments }] }]
if (item.type === 'function_call_output')
return [{ id, role: 'tool', segments: [{ type: 'tool-result', callId: item.call_id, content: readToolResultContent(item.output) }] }]
if (item.type === 'message' && item.role === 'assistant') {
const segments: Extract<ProjectionEntry, { role: 'assistant' }>['segments'] = typeof item.content === 'string'
? [{ type: 'text', text: item.content }]
: item.content.map((part) => {
if (part.type === 'output_text')
return { type: 'text', text: part.text, citations: readCitations(part) }
if (part.type === 'refusal')
return { type: 'refusal', text: part.refusal }
throw new Error('Unsupported Responses assistant content')
})
return [{ id, role: 'assistant', segments }]
}
// These native records have no portable message content. Search citations
// already belong to the assistant text; opaque state stays in continuation.
if (item.type === 'reasoning' || item.type === 'compaction' || item.type === 'web_search_call')
return []
throw new Error(`Unsupported Responses output item: ${item.type}`)
})
}
function toolChoice(choice: StreamOptions['toolChoice']): ResponsesOptions['toolChoice'] {
if (choice == null || typeof choice === 'string')
return choice
if (choice.type === 'function')
return { type: 'function', name: choice.function.name }
return { type: 'allowed_tools', mode: choice.mode, tools: choice.tools.map(tool => ({ type: 'function', name: tool.function.name })) }
}View on GitHub (pinned to 438a067dde)