{"record":{"id":"d2f3a96ed80d956c","repo":"moeru-ai/airi","slug":"unsupported-responses-assistant-content","errorCode":null,"errorMessage":"Unsupported Responses assistant content","messagePattern":"Unsupported Responses assistant content","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/core-agent/src/runtime/responses.ts","lineNumber":140,"sourceCode":"  }))\n}\n\nfunction readOutput(items: ItemParam[]): ProjectionEntry[] {\n  return items.flatMap<ProjectionEntry>((item, index) => {\n    const id = `output-${index}`\n    if (item.type === 'function_call')\n      return [{ id, role: 'assistant', segments: [{ type: 'tool-call', callId: item.call_id, name: item.name, arguments: item.arguments }] }]\n    if (item.type === 'function_call_output')\n      return [{ id, role: 'tool', segments: [{ type: 'tool-result', callId: item.call_id, content: readToolResultContent(item.output) }] }]\n    if (item.type === 'message' && item.role === 'assistant') {\n      const segments: Extract<ProjectionEntry, { role: 'assistant' }>['segments'] = typeof item.content === 'string'\n        ? [{ type: 'text', text: item.content }]\n        : item.content.map((part) => {\n            if (part.type === 'output_text')\n              return { type: 'text', text: part.text, citations: readCitations(part) }\n            if (part.type === 'refusal')\n              return { type: 'refusal', text: part.refusal }\n            throw new Error('Unsupported Responses assistant content')\n          })\n      return [{ id, role: 'assistant', segments }]\n    }\n    // These native records have no portable message content. Search citations\n    // already belong to the assistant text; opaque state stays in continuation.\n    if (item.type === 'reasoning' || item.type === 'compaction' || item.type === 'web_search_call')\n      return []\n    throw new Error(`Unsupported Responses output item: ${item.type}`)\n  })\n}\n\nfunction toolChoice(choice: StreamOptions['toolChoice']): ResponsesOptions['toolChoice'] {\n  if (choice == null || typeof choice === 'string')\n    return choice\n  if (choice.type === 'function')\n    return { type: 'function', name: choice.function.name }\n  return { type: 'allowed_tools', mode: choice.mode, tools: choice.tools.map(tool => ({ type: 'function', name: tool.function.name })) }\n}","sourceCodeStart":122,"sourceCodeEnd":158,"githubUrl":"https://github.com/moeru-ai/airi/blob/438a067dde47aa0bdb46c2323d1fe293dc805218/packages/core-agent/src/runtime/responses.ts#L122-L158","documentation":"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.","triggerScenarios":"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).","commonSituations":"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.","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."],"exampleFix":"// before\nconst segments = item.content.map(mapPart)\n\n// after\nconst segments = item.content\n  .filter(p => p.type === 'output_text' || p.type === 'refusal')\n  .map(mapPart)","handlingStrategy":"type-guard","validationCode":"const bad = item.content.filter(p => p.type !== 'output_text' && p.type !== 'refusal')\nif (bad.length) console.warn('unsupported assistant content parts:', bad.map(p => p.type))","typeGuard":"function isProjectableAssistantPart(part) {\n  return part?.type === 'output_text' || part?.type === 'refusal'\n}","tryCatchPattern":"try {\n  entries = readOutput(items)\n} catch (err) {\n  if (err.message === 'Unsupported Responses assistant content') {\n    console.error('Assistant message contained an unprojectable content part; filter or upgrade adapter.')\n  } else throw err\n}","preventionTips":["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."],"tags":["unexpected-response-shape","assistant-message","responses-api"],"backgroundTag":"unexpected-api-response-shape","analyzedSha":"438a067dde47aa0bdb46c2323d1fe293dc805218","analyzedAt":"2026-09-17T01:14:42.644Z","contentChangedAt":"2026-09-17T01:14:42.644Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}