{"record":{"id":"041b8ce56fabd10a","repo":"can1357/oh-my-pi","slug":"unhandled-api-api","errorCode":null,"errorMessage":"Unhandled API: ${api}","messagePattern":"Unhandled API: (.+?)","errorType":"exception","errorClass":"AIError.ConfigurationError","httpStatus":null,"severity":"error","filePath":"packages/ai/src/stream.ts","lineNumber":1033,"sourceCode":"\n\t\tcase \"google-gemini-cli\":\n\t\t\treturn streamGoogleGeminiCli(\n\t\t\t\tproviderModel as Model<\"google-gemini-cli\">,\n\t\t\t\tcontext,\n\t\t\t\tproviderOptions as GoogleGeminiCliOptions,\n\t\t\t);\n\n\t\tcase \"ollama-chat\":\n\t\t\treturn streamOllama(providerModel as Model<\"ollama-chat\">, context, providerOptions as OllamaChatOptions);\n\n\t\tcase \"cursor-agent\":\n\t\t\treturn streamCursor(providerModel as Model<\"cursor-agent\">, context, providerOptions as CursorOptions);\n\n\t\tcase \"devin-agent\":\n\t\t\treturn streamDevin(providerModel as Model<\"devin-agent\">, context, providerOptions as DevinOptions);\n\n\t\tdefault:\n\t\t\tthrow new AIError.ConfigurationError(`Unhandled API: ${api}`);\n\t}\n}\n\n/** Maximum guarded attempts for a detected thinking loop. */\nconst THINKING_LOOP_MAX_ATTEMPTS = 3;\nconst THINKING_LOOP_RETRY_BASE_DELAY_MS = 500;\nconst THINKING_LOOP_RETRY_MAX_DELAY_MS = 8_000;\n\nfunction isRetryableThinkingLoop(message: AssistantMessage): boolean {\n\treturn (\n\t\tmessage.stopReason === \"error\" &&\n\t\tmessage.content.length === 0 &&\n\t\tAIError.is(message.errorId, AIError.Flag.ThinkingLoop)\n\t);\n}\n\n/**\n * Resolve a completion, re-sampling a thinking-loop stall for at most","sourceCodeStart":1015,"sourceCodeEnd":1051,"githubUrl":"https://github.com/can1357/oh-my-pi/blob/969062200754ea02cfac922e5ebb8c608c079e15/packages/ai/src/stream.ts#L1015-L1051","documentation":"The API dispatch switch in stream() only knows a fixed set of API kinds. When a model's api field does not match any case, it throws AIError.ConfigurationError with `Unhandled API: ${api}`. This means the model object carries an api value this version of the library cannot stream — usually a mismatch between model metadata and library support.","triggerScenarios":"Streaming a model whose api property is an unrecognized value (custom/older model definition, hand-written model entry, or a model from a newer catalog used with an older @oh-my-pi/pi-ai).","commonSituations":"Upgraded the model catalog/registry but not the pi-ai package (version skew); constructing a Model object manually with a typo'd api string; custom registry entries copied from another codebase.","solutions":["Upgrade @oh-my-pi/pi-ai (and pi-catalog) so the library recognizes the model's api value.","Correct the model definition's api field to a supported API kind.","Remove or replace the stale custom model entry from your registry.","Check for version mismatches between packages (bun.lock) — reinstall so catalog and ai versions align."],"exampleFix":"// before\nconst model = { id: \"my-model\", api: \"my-custom-api\" /* unknown */ } as Model;\nawait stream(model, ctx);\n// after\nconst model = { id: \"my-model\", api: \"openai-completions\" } as Model<\"openai-completions\">;\nawait stream(model, ctx);","handlingStrategy":"try-catch","validationCode":"const SUPPORTED_APIS = new Set([\"openai-completions\", \"openai-responses\", \"anthropic-messages\", \"google-generative-ai\", \"google-vertex\", \"bedrock\", \"gitlab-duo-agent\", \"cursor-agent\", \"devin-agent\"]);\nif (!SUPPORTED_APIS.has(model.api)) {\n  throw new Error(`Model api \"${model.api}\" is not supported by this pi-ai version`);\n}","typeGuard":"function hasSupportedApi(model: Model): boolean {\n  return typeof model.api === \"string\" && streamDispatchSupportsApi(model.api);\n}","tryCatchPattern":"try {\n  await stream(model, context, requestOptions);\n} catch (err) {\n  if (err instanceof AIError.ConfigurationError && err.message.startsWith(\"Unhandled API:\")) {\n    console.error(`Library does not support api \"${model.api}\"; upgrade @oh-my-pi/pi-ai or fix the model entry.`);\n    return;\n  }\n  throw err;\n}","preventionTips":["Keep @oh-my-pi/pi-ai and pi-catalog versions in lockstep.","Never hand-write model.api strings; build models via the catalog/registry.","Validate registry entries against supported APIs at startup."],"tags":["configuration","unsupported-api","streaming","version-mismatch"],"backgroundTag":"unhandled-api-dispatch","analyzedSha":"969062200754ea02cfac922e5ebb8c608c079e15","analyzedAt":"2026-08-31T10:29:35.737Z","schemaVersion":2},"datasetVersion":"2026-08-31T14:17:45.589Z"}