Initial TrueGrowth source import
This commit is contained in:
227
openspec/changes/update-image-api-compatibility-modes/design.md
Normal file
227
openspec/changes/update-image-api-compatibility-modes/design.md
Normal file
@@ -0,0 +1,227 @@
|
||||
## Context
|
||||
|
||||
The repository now has three distinct realities for GPT Image requests:
|
||||
|
||||
- official OpenAI GPT Image requests already route cleanly through dedicated schemas and the `gpt-image-adapter`
|
||||
- Tuzi GPT compatibility is still encoded as `openai.image.basic-json` and ultimately handled by the generic default image adapter
|
||||
- generic OpenAI-compatible gateways also use the same basic adapter path
|
||||
|
||||
That means `resolvedImageApiCompatibility` is richer than the actual dispatch boundary. The metadata can say `tuzi-compatible`, but the adapter selection still collapses it into the same generic route as every other basic gateway. This makes the current system work, but it keeps provider-specific GPT behavior in the wrong module.
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
- Goals:
|
||||
- keep compatibility decisions profile-scoped
|
||||
- keep `auto` as a resolver
|
||||
- give Tuzi GPT compatibility a real adapter boundary
|
||||
- preserve the current official GPT adapter and schema split
|
||||
- preserve `openai-compatible-basic` as the generic fallback
|
||||
- separate official GPT quality semantics from legacy basic resolution semantics
|
||||
- keep the UI simpler than the internal routing model
|
||||
- Non-Goals:
|
||||
- no full `image.generate` / `image.edit` abstraction yet
|
||||
- no new task type
|
||||
- no forced removal of existing fallback behavior during rollout
|
||||
- no commitment that Tuzi edit uses the same transport shape as official GPT edit
|
||||
|
||||
## Decisions
|
||||
|
||||
- Decision: Keep image contract selection on `ProviderProfile`.
|
||||
|
||||
The compatibility difference is caused by the selected profile and API key, not by the model ID alone. The contract selector therefore remains a profile-level field.
|
||||
|
||||
- Decision: Refine the internal compatibility enum.
|
||||
|
||||
```ts
|
||||
type ImageApiCompatibility =
|
||||
| 'auto'
|
||||
| 'openai-gpt-image'
|
||||
| 'tuzi-gpt-image'
|
||||
| 'openai-compatible-basic';
|
||||
```
|
||||
|
||||
Legacy value `tuzi-compatible` is accepted as an alias and normalized to `tuzi-gpt-image`.
|
||||
|
||||
- Decision: `auto` is a resolver, not a wire protocol.
|
||||
|
||||
`auto` stays stored on profiles. Runtime resolution maps it to a concrete internal mode based on profile metadata and selected model.
|
||||
|
||||
- Decision: `requestSchema` is the adapter dispatch boundary.
|
||||
|
||||
`metadata.image.resolvedImageApiCompatibility` is observability context. It is not enough on its own. Real ownership changes only when routing emits a distinct request schema that resolves to a distinct adapter.
|
||||
|
||||
- Decision: Introduce a dedicated Tuzi GPT adapter.
|
||||
|
||||
Tuzi GPT compatibility should no longer be implemented as GPT-specific special cases inside `default-adapters.ts`. The generic default/basic adapter remains the fallback for broad OpenAI-compatible gateways.
|
||||
|
||||
- Decision: Keep the main settings UI simpler than the internal state model.
|
||||
|
||||
The UI should primarily steer users toward explicit override choices for:
|
||||
|
||||
- `OpenAI GPT Image`
|
||||
- `Tuzi GPT 兼容`
|
||||
|
||||
Profiles that still store `auto` or `openai-compatible-basic` should remain supported, but those modes are treated as internal or migration-oriented rather than first-class marketing options.
|
||||
|
||||
- Decision: Default profile creation to explicit official GPT mode.
|
||||
|
||||
New provider profiles should start with `imageApiCompatibility = openai-gpt-image` so the common path is explicit rather than hidden behind `auto`.
|
||||
|
||||
- Decision: Managed profile rebuilds must preserve stored overrides.
|
||||
|
||||
Built-in managed profiles such as the legacy default and Tuzi presets may be reconstructed by settings compatibility helpers. Their rebuild path must preserve any stored `imageApiCompatibility` override instead of resetting the field to `auto`.
|
||||
|
||||
- Decision: Only migrate missing defaults, not explicit `auto`.
|
||||
|
||||
Historical profiles that explicitly store `auto` may reflect deliberate operator intent. We should migrate missing compatibility fields and managed-profile defaults to `openai-gpt-image`, but avoid silently rewriting explicit `auto` on custom profiles.
|
||||
|
||||
## Internal Compatibility Model
|
||||
|
||||
### Stored Values
|
||||
|
||||
- `auto`
|
||||
- `openai-gpt-image`
|
||||
- `tuzi-gpt-image`
|
||||
- `openai-compatible-basic`
|
||||
|
||||
### Accepted Legacy Alias
|
||||
|
||||
- `tuzi-compatible` -> normalize to `tuzi-gpt-image`
|
||||
|
||||
### Auto Resolution Rules
|
||||
|
||||
`auto` resolves only for GPT Image models. Non-GPT image models continue using their existing model-specific routing rules.
|
||||
|
||||
| Profile / model condition | Resolved mode |
|
||||
| --- | --- |
|
||||
| `api.openai.com` + GPT Image model | `openai-gpt-image` |
|
||||
| `api.tu-zi.com` + GPT Image model | `tuzi-gpt-image` |
|
||||
| other profile + GPT Image model | `openai-compatible-basic` |
|
||||
|
||||
Manual non-`auto` values always win.
|
||||
|
||||
## Request Schema Mapping
|
||||
|
||||
The routing layer should produce a schema that matches the resolved compatibility mode.
|
||||
|
||||
| Resolved mode | Operation | Request schema | Adapter |
|
||||
| --- | --- | --- | --- |
|
||||
| `openai-gpt-image` | generation | `openai.image.gpt-generation-json` | `gpt-image-adapter` |
|
||||
| `openai-gpt-image` | edit | `openai.image.gpt-edit-form` | `gpt-image-adapter` |
|
||||
| `tuzi-gpt-image` | generation | `tuzi.image.gpt-generation-json` | `tuzi-gpt-image-adapter` |
|
||||
| `tuzi-gpt-image` | edit (phase 2) | dedicated Tuzi edit schema | `tuzi-gpt-image-adapter` |
|
||||
| `openai-compatible-basic` | generation / compatibility fallback | `openai.image.basic-json` | default/basic adapter |
|
||||
|
||||
The key architectural change is that `tuzi-gpt-image` stops being metadata-only and becomes a real dispatch target.
|
||||
|
||||
## Adapter Responsibilities
|
||||
|
||||
### `gpt-image-adapter`
|
||||
|
||||
- own official GPT Image generation and edit
|
||||
- own official size and quality semantics
|
||||
- own official `/images/edits` multipart transport
|
||||
- remain selected only by the official GPT request schemas
|
||||
|
||||
### `tuzi-gpt-image-adapter`
|
||||
|
||||
- own Tuzi GPT-specific request serialization
|
||||
- translate project-level image parameters into the Tuzi GPT contract
|
||||
- own the current `resolution -> legacy quality(1k|2k|4k)` folding behavior
|
||||
- keep official GPT-only fields internal unless Tuzi later exposes matching support
|
||||
- become the future home for Tuzi edit transport once phase 2 begins
|
||||
|
||||
### default/basic image adapter
|
||||
|
||||
- remain the generic fallback for `openai-compatible-basic`
|
||||
- keep serving non-GPT OpenAI-compatible image providers
|
||||
- stop owning GPT-specific Tuzi translation rules after migration
|
||||
|
||||
## Contract Semantics
|
||||
|
||||
### Official GPT Image Contract
|
||||
|
||||
- `quality`: official values `auto | low | medium | high`
|
||||
- `size`: official GPT size value
|
||||
- `resolution`: internal convenience only; it may help the UI choose a concrete size, but it is not the outbound official quality field
|
||||
- edit transport: multipart/form-data for `/images/edits`
|
||||
|
||||
### Tuzi GPT Contract
|
||||
|
||||
- `size`: outbound value stays compatible with Tuzi expectations
|
||||
- `resolution`: compatibility concept used to derive the legacy quality tier when needed
|
||||
- outbound `quality`: legacy compatibility value such as `1k | 2k | 4k`
|
||||
- official GPT `quality` remains an internal setting unless and until Tuzi explicitly supports the same meaning
|
||||
- phase 2 decides the final Tuzi edit transport contract independently from official multipart semantics
|
||||
|
||||
### Generic OpenAI-Compatible Basic Contract
|
||||
|
||||
- remains a compatibility fallback
|
||||
- does not become the primary home for GPT-specific translation logic
|
||||
|
||||
## UI Model
|
||||
|
||||
Primary user-facing override options:
|
||||
|
||||
- `OpenAI GPT Image`
|
||||
- `Tuzi GPT 兼容`
|
||||
|
||||
Support behavior:
|
||||
|
||||
- new profiles default to `OpenAI GPT Image`
|
||||
- built-in managed profiles default to `OpenAI GPT Image` when they have no stored override
|
||||
- profiles with no explicit stored compatibility from older data are upgraded to `OpenAI GPT Image`
|
||||
- profiles that already store `auto` remain on `auto`
|
||||
- the settings UI can show a resolved summary for `auto`, for example “自动判断,当前解析为 OpenAI GPT Image”
|
||||
- `openai-compatible-basic` remains supported for migration, diagnostics, and rollback, but does not need to be a prominent everyday choice
|
||||
|
||||
## Migration
|
||||
|
||||
- Preserve explicit stored `auto` values on custom profiles.
|
||||
- Do not reinterpret existing `auto` on official OpenAI profiles as basic fallback.
|
||||
- Normalize legacy `tuzi-compatible` values to `tuzi-gpt-image`.
|
||||
- Keep `openai-compatible-basic` valid for existing profiles and rollback scenarios.
|
||||
- Default newly created profiles to `openai-gpt-image`.
|
||||
- Default managed profiles to `openai-gpt-image` when they do not already store a compatibility override.
|
||||
- Upgrade profiles that are missing the compatibility field to `openai-gpt-image`.
|
||||
- When copying or exporting profiles, preserve the stored compatibility mode exactly.
|
||||
- Managed profile rebuild helpers must preserve explicit stored compatibility values rather than resetting them to `auto`.
|
||||
|
||||
## Rollout Phases
|
||||
|
||||
### Phase 1
|
||||
|
||||
- add enum and alias normalization
|
||||
- add `tuzi-gpt-image` resolver branch
|
||||
- add `tuzi.image.gpt-generation-json`
|
||||
- add `tuzi-gpt-image-adapter`
|
||||
- move Tuzi GPT generation translation logic out of `default-adapters.ts`
|
||||
- keep official GPT generation/edit unchanged
|
||||
|
||||
### Phase 2
|
||||
|
||||
- define Tuzi edit request schema and transport
|
||||
- route Tuzi GPT image-edit requests through `tuzi-gpt-image-adapter`
|
||||
- extend planner, persistence, and tests for the dedicated Tuzi edit path
|
||||
|
||||
## Observability
|
||||
|
||||
Diagnostics should expose:
|
||||
|
||||
- stored `imageApiCompatibility`
|
||||
- resolved compatibility mode
|
||||
- `requestSchema`
|
||||
- adapter ID
|
||||
- submit path
|
||||
- whether the request used generation or edit semantics
|
||||
|
||||
API keys and authorization headers must never be logged.
|
||||
|
||||
## Risks
|
||||
|
||||
- aggressive alias migration could accidentally rewrite user intent
|
||||
- default migration could accidentally rewrite explicit `auto` if missing-vs-explicit state is not distinguished carefully
|
||||
- `auto` could still mis-resolve for unusual custom gateways
|
||||
- moving GPT translation out of the default adapter could regress current Tuzi behavior if request parity tests are weak
|
||||
- UI simplification could hide recovery options unless diagnostics remain visible
|
||||
- phase 2 could be delayed, leaving generation cleanly separated while Tuzi edit still relies on fallback behavior
|
||||
Reference in New Issue
Block a user