moeru-ai/airi · error · Error
Unsupported Responses tool output
Error message
Unsupported Responses tool output
What it means
readToolResultContent switches over the part.type of Responses function_call_output parts. This fallback throw fires when a part's type matches none of the known cases (input_text, input_image, input_file, input_video). It guards against unknown or future OpenAI Responses content types the adapter cannot project into the portable conversation model.
Solutions
- Identify the offending part.type from the conversation/continuation data and convert it to a supported type (input_text) before storing.
- Upgrade @proj-airi/core-agent / the Responses adapter to a version that knows the new content part type.
- As a workaround, sanitize function_call_output parts with a whitelist filter before pushing them into the conversation.
Example fix
// before
items.push({ type: 'function_call_output', call_id: segment.callId, output: content })
// after
const allowed = ['input_text', 'input_image', 'input_file']
items.push({ type: 'function_call_output', call_id: segment.callId, output: content.filter(p => allowed.includes(p.type)) }) Defensive patterns
Strategy: type-guard
Validate before calling
const KNOWN = new Set(['input_text', 'input_image', 'input_file', 'input_video'])
const unknown = output.filter(p => !KNOWN.has(p?.type))
if (unknown.length) console.warn('unknown tool output part types:', unknown.map(p => p.type)) Type guard
function isKnownToolOutputPart(part) {
return ['input_text', 'input_image', 'input_file', 'input_video'].includes(part?.type)
} Try / catch
try {
projection = readOutput(items)
} catch (err) {
if (err.message === 'Unsupported Responses tool output') {
console.error('Unrecognized function_call_output part type; upgrade adapter or sanitize parts.')
} else throw err
} Prevention
- Keep the adapter version aligned with the Responses API types you compile against.
- Sanitize hand-built ItemParam arrays against the known part-type union.
- Do not replay continuation data captured by a newer library version without upgrading.
When it happens
Trigger: readOutput() -> readToolResultContent() receives a function_call_output whose output is an array containing a part whose type is not input_text/input_image/input_file/input_video — e.g. a newer API content type, a typo like 'input_texts', or a hand-constructed part object.
Common situations: Upstream Responses API added a new content part type after this adapter was written; a plugin or tool writes non-standard parts into conversation state; a persisted continuation from a newer library version is read by an older adapter.
Related errors
- Unsupported Responses assistant content
- Unsupported Responses output item
- Only assistant messages can invoke tools
- Responses continuation must contain an item array
- Responses file requires exactly one source
AI-assisted analysis of moeru-ai/airi@438a067dde (2026-09-17).
Data as JSON: /api/errors/988cc4bba0bfeca8.
Report an issue: GitHub.
Appendix: source
Thrown at packages/core-agent/src/runtime/responses.ts:110
function readToolResultContent(content: Extract<ItemParam, { type: 'function_call_output' }>['output']): InputSegment[] {
if (typeof content === 'string')
return [{ type: 'text', text: content }]
return content.map((part) => {
switch (part.type) {
case 'input_text': return { type: 'text', text: part.text }
case 'input_image':
if (!part.image_url)
throw new Error('Responses image output requires a URL')
return { type: 'image', url: part.image_url, detail: part.detail ?? undefined }
case 'input_file':
if (part.file_data != null && part.file_url == null)
return { type: 'file', data: part.file_data, name: part.filename ?? undefined }
if (part.file_url != null && part.file_data == null)
return { type: 'file', url: part.file_url, name: part.filename ?? undefined }
throw new Error('Responses file requires exactly one source')
case 'input_video': throw new Error('Video tool output is not supported by the conversation model')
}
throw new Error('Unsupported Responses tool output')
})
}
type AssistantContent = Exclude<Extract<ItemParam, { role: 'assistant' }>['content'], string>[number]
function readCitations(part: Extract<AssistantContent, { type: 'output_text' }>): Citation[] | undefined {
return part.annotations?.map(entry => ({
url: entry.url,
title: entry.title,
startIndex: entry.start_index,
endIndex: entry.end_index,
}))
}
function readOutput(items: ItemParam[]): ProjectionEntry[] {
return items.flatMap<ProjectionEntry>((item, index) => {
const id = `output-${index}`
if (item.type === 'function_call')View on GitHub (pinned to 438a067dde)