#21042·ai

wrapProvider removes file and skill upload support

Author: brennanbutler01Created Sep 17, 2026Updated Sep 17, 2026
Labelstask-identify-issue-type-donetask-bug-reproduction-successfactory-activefactory-automatictask-identify-harness-labels-done

Description

wrapProvider() removes a provider's files() and skills() methods. Adding language-model middleware makes uploadFile({ api: wrapped }) and uploadSkill({ api: wrapped }) fail, although both work with the original provider.

Expected: wrapping the language models preserves the provider's existing upload APIs.

Actual:

original file: { example: 'file-synthetic' }
original skill: { example: 'skill-synthetic' }
wrapped file: The provider does not support file uploads. Make sure it exposes a files() method.
wrapped skill: The provider does not support skills. Make sure it exposes a skills() method.

Both methods are part of ProviderV4, but wrapProvider constructs a new object without forwarding them. customProvider({ fallbackProvider }) preserves them. The same method loss occurs when wrapping createOpenAI(); the reproduction below uses synthetic upload handlers to avoid network calls.

Reproduction

In an empty directory, run npm init -y and npm install [email protected]. Save as repro.mts and run node repro.mts with Node 24. No API key is needed.

typescript
import { customProvider, uploadFile, uploadSkill, wrapProvider } from 'ai';

const provider = customProvider({
  files: {
    specificationVersion: 'v4',
    provider: 'example',
    uploadFile: async () => ({
      providerReference: { example: 'file-synthetic' },
      warnings: [],
    }),
  },
  skills: {
    specificationVersion: 'v4',
    provider: 'example',
    uploadSkill: async () => ({
      providerReference: { example: 'skill-synthetic' },
      warnings: [],
    }),
  },
});
const wrapped = wrapProvider({
  provider,
  languageModelMiddleware: { specificationVersion: 'v4' },
});

for (const [name, api] of Object.entries({ original: provider, wrapped })) {
  try {
    const result = await uploadFile({
      api,
      data: { type: 'text', text: 'Synthetic example.' },
    });
    console.log(name, 'file:', result.providerReference);
  } catch (error) {
    console.log(name, 'file:', error instanceof Error ? error.message : error);
  }
  try {
    const result = await uploadSkill({
      api,
      files: [{ path: 'SKILL.md', data: { type: 'text', text: 'Synthetic skill.' } }],
    });
    console.log(name, 'skill:', result.providerReference);
  } catch (error) {
    console.log(name, 'skill:', error instanceof Error ? error.message : error);
  }
}

Local regression checks: two failing upload cases and six passing controls, covering direct uploads, fallback providers, language middleware, and providers without upload support. The standalone reproduction also passes strict TypeScript checking.

I used AI assistance to investigate and prepare the reproduction and tests.

AI SDK Version

Code of Conduct

  • I agree to follow this project's Code of Conduct