Skip to content

feat(ai-providers): add Requesty as an AI provider - #3128

Merged
datlechin merged 4 commits into
TableProApp:mainfrom
Thibaultjaigu:add-requesty-provider
Oct 4, 2026
Merged

datlechin merged 4 commits into
TableProApp:mainfrom
Thibaultjaigu:add-requesty-provider

Conversation

@Thibaultjaigu

@Thibaultjaigu Thibaultjaigu commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

Why

As a new AIProviderType case, Requesty's raw value would sit in the synced AI settings, where no released build can decode it, and an older Mac's next push would delete the provider. The shared OpenAI-compatible transport also had controls that did nothing.

Change

  • Requesty in Add Provider…: Base URL filled in, key required, a wrong key (Requesty answers 403) reported as an authentication failure. Stored as a custom provider with a preset id, so every build reads it.
  • A chosen reasoning effort is sent as reasoning_effort on OpenRouter, OpenCode Zen, llama.cpp, MLX and custom providers. Gemini and Ollama lose a picker that changed nothing.
  • Image attach and the effort picker follow the model a router lists, per provider.
  • A new provider no longer starts on the first of hundreds of models sorted by name. A cleared Base URL saves as the default. Ollama gets options.num_predict and base64 images.

Verified

AIProviderPresetTests, OpenAICompatibleProviderRequestTests and the 403 cases fail on main and pass here. Bad-key answers and model-list shapes come from the live Requesty and OpenRouter APIs. AIProviderPresetUITests runs on CI only.

Not in this PR

  • A released build syncing the settings drops the preset id; Requesty then reads as plain custom.
  • A custom provider with a saved effort now sends reasoning_effort, which a strict server rejects.
  • Per-model tool calling is not read; model menus stay flat.
  • OpenRouter's streamed reasoning_details is not rendered.
  • The Ollama changes follow its API docs, not a live server.

@datlechin

Copy link
Copy Markdown
Member

Hi @Thibaultjaigu, thanks for the contribution. Why we don't just use the OpenAI Compatible provider instead of creating new providers?

@Thibaultjaigu

Copy link
Copy Markdown
Contributor Author

Fair question. Custom works for Requesty today, so this is only about setup, and the delta is small. It is the same footprint as the OpenRouter entry and reuses OpenAICompatibleProvider, no new transport code:

  1. It shows up by name with its own icon in Add Provider…, with https://router.requesty.ai prefilled, so nobody has to look up the base URL.
  2. The key is required, like OpenRouter. Custom treats it as optional, and our /v1/models answers without a key, so on Custom a keyless setup saves and fills the model picker, then the first chat gets a 401. With the preset, Save stays disabled until a key is there.
  3. The host is listed in privacy.mdx next to the other presets.

It does not add pricing, curated models or extra headers. I checked the requests the app builds against the live API: GET /v1/models returns the OpenAI list shape (about 780 models), streaming /v1/chat/completions works, a bad key gets a 403, and the EU endpoint https://router.eu.requesty.ai works the same if you edit the endpoint field.

I also rebased onto main (v0.76.0) and moved the changelog line under Unreleased.

If you would rather keep the provider list short, that is fine too: I can close this and send a docs PR instead, with a row in ai-assistant.mdx showing Requesty through Add Custom Provider… with https://router.requesty.ai/v1.

Requesty was a new AIProviderType case. That raw value is stored in the
synced AI settings, and no released build can decode it, so the older
build's next push would have deleted the provider. It is now an
AIProviderPreset stored as a custom provider with a preset id, which
every build decodes.

Shared OpenAI-compatible path, found while reviewing the PR:
- A wrong key that a server answers with 403 is an authentication
  failure for a preset that says so, not a retryable server error.
- A chosen reasoning effort is sent as reasoning_effort. Gemini and
  Ollama lose the picker, because their transports send no effort.
- The model catalog is keyed by provider configuration, and keeps what
  a router's model list says about vision and reasoning per model. The
  composer and the effort picker follow it.
- A new provider no longer starts on the first of a list sorted by
  name, and Save waits for a model while a list is there to pick from.
- A cleared Base URL saves as the default instead of an empty string.
- Ollama gets options.num_predict and base64 images on its native
  route.
- AIProviderDescriptor drops the name, endpoint and symbol it copied
  from AIProviderType, and the capability flags nothing read.
- The automatic model fetch reads the Base URL as typed again. An emptied
  field resolved to the default host, so a key typed for a gateway was
  sent to the vendor's own host 0.5 s later with no click.
- Save that changes the key or Base URL before the new list loads now
  fetches the list again, so open chat windows keep per-model image and
  reasoning limits. A refresh that a newer refresh, Save or removal
  overtook is dropped when it lands.
- The preset UI test finds the sheet's fields and Save by identifier: a
  SwiftUI form field carries no label of its own in the accessibility
  tree, so the title lookup failed on CI.
- The model decoder no longer fills context and output limits nothing
  reads.
- Tests build the router and Claude transports through the registry, so
  they fail if the configuration id stops reaching the catalog, and the
  overlay fallback test now uses a model only the offline table answers.
@datlechin
datlechin merged commit 4229029 into TableProApp:main Oct 4, 2026
22 of 25 checks passed
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.

2 participants