Skip to content

feat(ai): add UnsupportedOperation error for route capability mismatches - #46960

Open
rekram1-node wants to merge 1 commit into
v2from
unsupported-operation
Open

feat(ai): add UnsupportedOperation error for route capability mismatches#46960
rekram1-node wants to merge 1 commit into
v2from
unsupported-operation

Conversation

@rekram1-node

Copy link
Copy Markdown
Collaborator

Calling an operation the selected route does not implement (e.g. LLMClient.compact on Anthropic) failed with a generic InvalidRequest, forcing consumers to match on message text. This adds a typed distinction.

Name options considered

  • UnsupportedOperation (chosen): matches the existing noun-phrase style (InvalidRequest, NoRoute, UnknownProvider) and reads naturally next to operation: "compact".
  • UnsupportedCapability: arguably more precise (the failure is a missing route capability, detected before any attempt), but vaguer at the call site.
  • OperationNotSupported / NotSupported: same meaning, less consistent with the current taxonomy.

Open to renaming before merge; the shape below stays the same either way.

Shape

AI.Error.UnsupportedOperation (packages/ai/src/schema/errors.ts) with operation: string plus optional provider/route. operation is an open string so future ops (video generation, etc.) reuse it without another union member. ProviderShared.unsupportedOperation({ operation, message, provider?, route? }) is the shared constructor.

Migrated (missing capability, never touches the network)

  • route/client.ts: explicit compact on a route without a compact endpoint → operation: "compact"
  • protocols/xai-responses.ts: automatic contextManagement on xAI (explicit-only route) → operation: "in-band-compaction"
  • core/src/aisdk.ts: AI SDK bridge hitting native compaction replay state → operation: "compaction-replay"

Required follow-through: to-session-error.ts maps it to provider.unsupported-operation (open wire string, no schema/regen needed), retry.ts treats it as non-retryable like InvalidRequest/NoRoute.

Deliberately left as InvalidRequest

The other ~20 invalidRequest sites are malformed caller input, not missing capabilities (bad media/base64, missing filename, conflicting options, missing credentials, cross-provider compaction replay, non-object overlays). Those stay; the rule is: capability missing → UnsupportedOperation, input invalid → InvalidRequest.

Consumer guidance

Prefer the capability guard over try/catch: LLMClient.canCompact(request) narrows to CompactionRequest at both type and runtime level. Catch-and-fallback now has a real branch: reason._tag === "UnsupportedOperation" && reason.operation === "compact".

Verification

  • bun typecheck clean in packages/ai (incl. tsconfig.types.json capability assertions) and packages/core
  • packages/ai: full suite 980 pass / 0 fail; updated explicit-compaction, schema reason-enumeration, and added an Anthropic compact rejection test
  • packages/core: session-error (mapping + non-retryable) and aisdk (replay rejection) pass

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant