9.2 KiB
Context
Superseded note: the later
update-image-api-compatibility-modeschange refines this design. In current implementation guidance, the legacytuzi-compatiblevalue is accepted only as an alias fortuzi-gpt-image, Tuzi GPT Image routes through the dedicated Tuzi GPT Image adapter, andopenai-compatible-basicremains the generic fallback/default adapter path.
The project already has multi-provider concepts:
ProviderProfilestores the API key, base URL, provider type, and auth mode.ModelRefstoresprofileId + modelId.ProviderModelBindingstoresprofileId + modelId + operation + protocol + requestSchema.- The model adapter registry already prefers
requestSchemamatches over protocol and model matches.
This gives the system enough structure to solve the GPT Image compatibility issue without binding every gpt-image-* model directly to one adapter.
Goals / Non-Goals
- Goals:
- Allow the same GPT Image model ID to route differently by provider profile/key.
- Preserve the current default adapter compatibility path.
- Add a dedicated official GPT Image generation path.
- Keep the user-facing configuration understandable.
- Keep this change smaller than the full image operation abstraction.
- Non-Goals:
- No new image edit task type.
- No new public
edit_imagetool. - No automatic paid request fallback/retry across compatibility modes.
- No provider-wide rewrite of all image adapters.
Decisions
-
Decision: Store compatibility on
ProviderProfile.The compatibility difference is caused by the API key/profile, not by the model ID alone. The profile is therefore the right place for this setting.
-
Decision: Name the field
imageApiCompatibility.The field describes the upstream image API contract. It does not expose internal adapter or schema names to users.
-
Decision: Use user-facing values that map to internal schemas.
type ImageApiCompatibility = | 'auto' | 'openai-gpt-image' | 'tuzi-compatible' | 'openai-compatible-basic'; -
Decision: Keep
autoas a stored value.autoshould not be rewritten into a concrete mode during normalization. Runtime inference can evolve later while existing profiles continue to benefit from better inference rules. -
Decision: Resolve compatibility before binding inference.
The binding layer maps the resolved compatibility to a
requestSchema. The adapter registry then selects the implementation by schema.
Architecture Overview
This change adds a narrow compatibility-selection layer between provider profile resolution and image binding inference.
Runtime flow:
Image request
-> ModelRef(profileId + modelId)
-> ProviderProfile
-> imageApiCompatibility
-> resolved image compatibility
-> ProviderModelBinding.requestSchema
-> model adapter registry
-> default image adapter OR GPT Image adapter
-> ProviderTransport
The important architectural boundary is that modelId identifies what the user selected, while imageApiCompatibility describes the request contract exposed by the chosen API key/profile.
Data Model
Add a profile-level field:
type ImageApiCompatibility =
| 'auto'
| 'openai-gpt-image'
| 'tuzi-compatible'
| 'openai-compatible-basic';
interface ProviderProfile {
imageApiCompatibility?: ImageApiCompatibility;
}
Propagate the same field into ProviderProfileSnapshot because binding inference operates on snapshots rather than full settings objects.
Request Schema Contract
The request schema is the stable handoff between routing and adapters:
openai.image.basic-json
-> existing default image adapter
openai.image.gpt-generation-json
-> new GPT Image adapter
The adapter registry already scores requestSchema matches above protocol and model matches. This change relies on that behavior so official GPT Image requests are not selected by bare model ID alone.
Module Responsibilities
settings-manager.ts- Owns the persisted profile field and normalization.
- Keeps missing values as
auto.
settings-dialog.tsx- Lets users choose the profile's image interface format.
- Shows user-facing labels only.
provider-routing/types.ts- Adds the field to
ProviderProfileSnapshot.
- Adds the field to
provider-routing/settings-repository.ts- Copies the field from settings profiles into snapshots.
provider-routing/binding-inference.ts- Resolves
autoto a concrete compatibility mode. - Maps the resolved mode to
requestSchema.
- Resolves
model-adapters/gpt-image-adapter.ts- Implements official GPT Image generation request and response handling.
model-adapters/default-adapters.ts- Continues to serve Tuzi/basic and generic OpenAI-compatible image formats.
Compatibility Resolution
Manual values win over auto.
Recommended auto inference:
api.openai.com+gpt-image*->openai-gpt-imageapi.tu-zi.com->tuzi-compatible- other
openai-compatibleorcustomprofiles ->openai-compatible-basic gemini-compatibleprofiles do not use GPT Image routing
Request Schema Mapping
openai-gpt-image+ GPT Image model:requestSchema: openai.image.gpt-generation-json- adapter:
gpt-image-adapter
tuzi-gpt-image:requestSchema: tuzi.image.gpt-generation-json- adapter:
tuzi-gpt-image-adapter
openai-compatible-basic:requestSchema: openai.image.basic-json- adapter: existing default image adapter
Official edit support uses:
openai.image.gpt-edit-form
Adapter Boundaries
The existing default adapter remains the compatibility path for generic OpenAI-compatible image providers. Tuzi GPT Image-specific behavior belongs to the dedicated Tuzi GPT Image adapter.
The new GPT Image adapter only handles official GPT Image request schemas. It should not match every gpt-image-* model by model ID alone.
Initial GPT Image adapter scope:
- POST
/images/generations - Do not default
response_formattourl - Prefer
b64_jsonparsing - Accept URL responses for gateway compatibility
- Support official generation fields such as
size,quality,n,output_format,output_compression,background, andmoderationwhen present
GPT Image Adapter Request Policy
The adapter should only include optional fields when the caller provided them or when the project already has a safe default for that official field.
It should not:
- inject
response_format: urlby default - add provider-specific prompt prefixes
- use the basic compatibility
imagefield for official edit semantics
It should:
- POST official text-to-image requests to
/images/generations - prefer
b64_jsonresponse data - tolerate URL responses from gateway variants
- normalize returned images to the existing
ImageGenerationResult
Default Adapter Policy
The default image adapter remains the compatibility adapter for:
tuzi-compatibleopenai-compatible-basic- unknown or broad OpenAI-compatible image gateways
Its existing GPT Image behavior is preserved to protect current users and API keys.
Settings UI
Add a profile-level field near provider type / API URL / API key:
Label: 图片接口格式
Options:
自动OpenAI GPT Image 格式兔子兼容格式通用 OpenAI 兼容格式
Suggested helper text:
同一个图片模型在不同 API Key 或网关下可能需要不同接口格式;不确定时使用自动。
The UI should not mention adapters, request schemas, or routing internals.
Observability
Generation diagnostics should expose enough non-secret context to debug misrouting:
profileIdmodelId- stored
imageApiCompatibility - resolved compatibility
requestSchema- adapter ID
- submit path
API keys and full authorization headers must never be logged.
Migration
- Old profiles without
imageApiCompatibilitynormalize toauto. - Legacy default and managed Tuzi profiles should store
auto. - At runtime,
autoforapi.tu-zi.comresolves totuzi-compatible, preserving current behavior. - Copying a provider profile should copy the field.
- Deleting or disabling profiles requires no special handling.
Risks
autoinference may choose the wrong compatibility mode for a key.- The adapter registry may accidentally select the default adapter if schema matching is incomplete.
- Default adapter changes may break existing Tuzi/basic image keys.
- Official GPT Image and gateway variants may return mixed response shapes.
- The UI setting may be unclear without concise helper text.
- Future
/images/editssupport may need a broader image operation abstraction.
Rollout Plan
- Add data model support and keep all existing profiles resolving to current behavior.
- Add routing/schema split while defaulting Tuzi/basic profiles to the existing adapter.
- Add GPT Image generation adapter and route only
openai-gpt-imageprofiles to it. - Add UI controls and observability.
- Add tests and manually verify two profiles with the same GPT model ID but different compatibility modes.
Open Questions For Approval
- Should
api.tu-zi.comalways resolve totuzi-compatibleinautomode? - Should the first implementation include only
/images/generations, or also/images/edits? - Should
openai-compatible-basicandtuzi-compatibleremain separate user options even if they initially map to the same request schema?