Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7cb420d8e6 | |||
| d3919d441f | |||
| 4b5824babc |
@@ -7,6 +7,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
|
||||
---
|
||||
|
||||
## [2.0.8] — 2026-03-07
|
||||
|
||||
> ### 🐛 Bug Fix — Custom Image Model Handler Resolution
|
||||
|
||||
### 🐛 Bug Fixes
|
||||
|
||||
- **#238 — Custom image models still fail in handler layer** — v2.0.7 fixed the route-layer validation, but the handler (`handleImageGeneration()`) called `parseImageModel()` again internally, rejecting custom models a second time. Fix: handler now accepts an optional `resolvedProvider` parameter; when provided, it skips re-validation and routes custom models to the OpenAI-compatible handler with a synthetic config. PR #239
|
||||
|
||||
### 📁 Files Changed
|
||||
|
||||
| File | Change |
|
||||
| -------------------------------------------- | -------------------------------------------------------------------------------- |
|
||||
| `open-sse/handlers/imageGeneration.ts` | Added `resolvedProvider` param + custom model fallback |
|
||||
| `src/app/api/v1/images/generations/route.ts` | Tracks `isCustomModel`, passes `resolvedProvider`, credentials for custom models |
|
||||
|
||||
---
|
||||
|
||||
## [2.0.7] — 2026-03-07
|
||||
|
||||
> ### 🐛 Bug Fixes — Custom Image Models + Codex OAuth Workspace Isolation
|
||||
|
||||
@@ -30,9 +30,23 @@ import {
|
||||
* @param {object} options.body - Request body
|
||||
* @param {object} options.credentials - Provider credentials { apiKey, accessToken }
|
||||
* @param {object} options.log - Logger
|
||||
* @param {string} [options.resolvedProvider] - Pre-resolved provider ID (from route layer custom model resolution)
|
||||
*/
|
||||
export async function handleImageGeneration({ body, credentials, log }) {
|
||||
const { provider, model } = parseImageModel(body.model);
|
||||
export async function handleImageGeneration({ body, credentials, log, resolvedProvider = null }) {
|
||||
let provider, model;
|
||||
|
||||
if (resolvedProvider) {
|
||||
// Provider was already resolved by the route layer (custom model from DB)
|
||||
// Extract model name from the full "provider/model" string
|
||||
provider = resolvedProvider;
|
||||
const modelStr = body.model || "";
|
||||
model = modelStr.startsWith(provider + "/") ? modelStr.slice(provider.length + 1) : modelStr;
|
||||
} else {
|
||||
// Standard path: resolve from built-in image registry
|
||||
const parsed = parseImageModel(body.model);
|
||||
provider = parsed.provider;
|
||||
model = parsed.model;
|
||||
}
|
||||
|
||||
if (!provider) {
|
||||
return {
|
||||
@@ -43,12 +57,42 @@ export async function handleImageGeneration({ body, credentials, log }) {
|
||||
}
|
||||
|
||||
const providerConfig = getImageProvider(provider);
|
||||
|
||||
// For custom models without a built-in provider config, use OpenAI-compatible handler
|
||||
// with a synthetic config based on the provider's credentials
|
||||
if (!providerConfig) {
|
||||
return {
|
||||
success: false,
|
||||
status: 400,
|
||||
error: `Unknown image provider: ${provider}`,
|
||||
if (!resolvedProvider) {
|
||||
return {
|
||||
success: false,
|
||||
status: 400,
|
||||
error: `Unknown image provider: ${provider}`,
|
||||
};
|
||||
}
|
||||
|
||||
// Custom model: use OpenAI-compatible format with provider's base URL
|
||||
// The credentials were already resolved by the route layer
|
||||
if (log) {
|
||||
log.info("IMAGE", `Custom model ${provider}/${model} — using OpenAI-compatible handler`);
|
||||
}
|
||||
|
||||
const syntheticConfig = {
|
||||
id: provider,
|
||||
baseUrl:
|
||||
credentials?.baseUrl ||
|
||||
`https://generativelanguage.googleapis.com/v1beta/openai/images/generations`,
|
||||
authType: "apikey",
|
||||
authHeader: "bearer",
|
||||
format: "openai",
|
||||
};
|
||||
|
||||
return handleOpenAIImageGeneration({
|
||||
model,
|
||||
provider,
|
||||
providerConfig: syntheticConfig,
|
||||
body,
|
||||
credentials,
|
||||
log,
|
||||
});
|
||||
}
|
||||
|
||||
// Route to format-specific handler
|
||||
|
||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "omniroute",
|
||||
"version": "2.0.6",
|
||||
"version": "2.0.7",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "omniroute",
|
||||
"version": "2.0.6",
|
||||
"version": "2.0.7",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"workspaces": [
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "omniroute",
|
||||
"version": "2.0.7",
|
||||
"version": "2.0.8",
|
||||
"description": "Smart AI Router with auto fallback — route to FREE & cheap models, zero downtime. Works with Cursor, Cline, Claude Desktop, Codex, and any OpenAI-compatible tool.",
|
||||
"type": "module",
|
||||
"bin": {
|
||||
|
||||
@@ -108,6 +108,7 @@ export async function POST(request) {
|
||||
|
||||
// Parse model to get provider
|
||||
let { provider } = parseImageModel(body.model);
|
||||
let isCustomModel = false;
|
||||
|
||||
// If not in built-in registry, check custom models tagged for images
|
||||
if (!provider) {
|
||||
@@ -121,6 +122,7 @@ export async function POST(request) {
|
||||
const fullId = `${providerId}/${model.id}`;
|
||||
if (fullId === body.model) {
|
||||
provider = providerId;
|
||||
isCustomModel = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -149,9 +151,23 @@ export async function POST(request) {
|
||||
`No credentials for image provider: ${provider}`
|
||||
);
|
||||
}
|
||||
} else if (isCustomModel) {
|
||||
// Custom models need credentials from the provider connection
|
||||
credentials = await getProviderCredentials(provider);
|
||||
if (!credentials) {
|
||||
return errorResponse(
|
||||
HTTP_STATUS.BAD_REQUEST,
|
||||
`No credentials for custom image provider: ${provider}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
const result = await handleImageGeneration({ body, credentials, log });
|
||||
const result = await handleImageGeneration({
|
||||
body,
|
||||
credentials,
|
||||
log,
|
||||
...(isCustomModel && { resolvedProvider: provider }),
|
||||
});
|
||||
|
||||
if (result.success) {
|
||||
return new Response(JSON.stringify((result as any).data), {
|
||||
|
||||
Reference in New Issue
Block a user