Files
nexu-io-open-design/apps/web/tests/components/NewProjectPanel.test.ts
Young 7173ce8d18 feat(media): integrate OpenRouter as BYOK provider (#1922)
* feat(media): integrate OpenRouter as BYOK provider for image and video generation

This commit restores the OpenRouter integration originally proposed in PR #1040, resolving the conflicts that caused the previous PR to be closed.

Changes:
- Re-added OpenRouter image and video models to `models.ts` and `media-models.ts`.
- Implemented `renderOpenRouterImage` and `renderOpenRouterVideo` in `media.ts`, supporting 30-minute polling timeout for long video generations.
- Wired OpenRouter attribution headers (X-Title, HTTP-Referer) across the proxy, connection test, and media dispatcher loops.
- Added regression tests in `media-openrouter.test.ts` to verify OpenRouter functionality, including asserting that API keys are not leaked via `Authorization` headers to third-party CDNs.
- Registered `openrouter` in `media-config.ts` ENV_KEYS for environment variable overrides.

Fixes #1040.

* fix(media): respect model-alias contract in OpenRouter renderers and restore 30-min poll ceiling

- Derive outbound model from credentials.model || ctx.wireModel (matching
  ImageRouter pattern) so OD_MEDIA_MODEL_ALIASES and stored aliases are
  honoured. Strip openrouter/ prefix from the resolved value, not ctx.model.
- Restore default poll ceiling to 30 minutes to match PR-documented contract.
- Add alias regression tests for both image and video OpenRouter renderers.
- Add timeout contract regression test.

* feat(media): add OpenRouter resolution variants and multi-image i2v support

- Add 480p/720p/1080p resolution variants for Seedance 2.0 (default: 1080p).
  Resolution is encoded as a model ID suffix (e.g. :1080p) and parsed by
  renderOpenRouterVideo before sending the resolution parameter to OpenRouter.

- Add Kling v3.0 Pro as an OpenRouter-routed video model.

- Extend generateMedia API with images[] array parameter for multi-image
  i2v flows. First image goes to frame_images[first_frame], additional
  images go to input_references for style/content guidance.

- Broaden the NewProjectPanel supportedModels whitelist to include
  openrouter, imagerouter, leonardo, and custom-image providers for both
  image and video surfaces.

- Add regression tests for OpenRouter visibility in image/video pickers.

* fix(test): update quick-fill provider index after OpenRouter insertion

Adding OpenRouter as an openai-protocol quick-fill provider shifted
DeepSeek from index 1 to index 2 in the provider dropdown, causing the
'updates model and base URL when quick fill provider changes' test to
select OpenRouter instead of DeepSeek.

* fix(media): sync daemon media-models with web model registry

- Add OpenRouter resolution variants (:1080p, :480p) and kwaivgi/kling-v3.0-pro
  to the daemon's media-models registry mirror. This prevents the daemon
  from rejecting the model IDs as unknown.
- Add unit tests verifying resolution suffix parsing and defaulting for
  OpenRouter video models in media-openrouter.test.ts.
- Pass verify-media-models script drift check.
2026-06-01 02:53:47 +00:00

34 lines
1.5 KiB
TypeScript

import { describe, expect, it } from 'vitest';
import { supportedModels } from '../../src/components/NewProjectPanel';
import { AUDIO_MODELS_BY_KIND, IMAGE_MODELS, VIDEO_MODELS } from '../../src/media/models';
describe('NewProjectPanel image provider visibility', () => {
it('shows Nano Banana in supported image models', () => {
const models = supportedModels('image', IMAGE_MODELS);
expect(models.some((model) => model.provider === 'nanobanana')).toBe(true);
expect(models.some((model) => model.id === 'gemini-3.1-flash-image-preview')).toBe(true);
});
it('shows ElevenLabs speech models in supported audio models', () => {
const models = supportedModels('audio', AUDIO_MODELS_BY_KIND.speech);
expect(models.some((model) => model.provider === 'elevenlabs')).toBe(true);
expect(models.some((model) => model.id === 'elevenlabs-v3')).toBe(true);
});
it('shows ElevenLabs sound effects models in supported audio models', () => {
const models = supportedModels('audio', AUDIO_MODELS_BY_KIND.sfx);
expect(models.some((model) => model.id === 'elevenlabs-sfx')).toBe(true);
});
it('shows OpenRouter in supported image models', () => {
const models = supportedModels('image', IMAGE_MODELS);
expect(models.some((model) => model.provider === 'openrouter')).toBe(true);
});
it('shows OpenRouter in supported video models', () => {
const models = supportedModels('video', VIDEO_MODELS);
expect(models.some((model) => model.provider === 'openrouter')).toBe(true);
});
});