Deuz SDK 2.4 çıktı — sürümlü bellek ve bağlam derleyicisi, hedef denetleyicisi ve kalıcı zamanlayıcı, yerel Docker çalıştırıcısı ve kalıcı sohbet akışları. 2.4’te neler yeni
Deuz SDK
Providers

Yunwu (云雾) Relay

One key, one base URL — chat, image, video, embeddings, and Midjourney across a 2026 multi-vendor catalog.

Doküman sayfalarının içeriği İngilizce’dir. Gezinme, arama ve arayüz metinleri seçtiğiniz dile göre çevrilir.

Yunwu (云雾) is an OpenAI-compatible aggregator: a single apiKey + baseURL fronts hundreds of upstream models from many vendors (OpenAI, Anthropic, Google, xAI, DeepSeek, Qwen, …). createYunwu is the unified client — you supply the host once and it derives the right surface per call: chat / image / video / embeddings under /v1, and the Midjourney proxy at the bare host root. Reach for a relay when you want a single key, mainland-China access, and broad model variety without wiring each provider separately.

createYunwu

createYunwu(settings?) returns a YunwuClient. Give the base URL (and key) once; every surface is derived from it. Factory settings are stashed on a non-enumerable Symbol, so they never leak through Object.keys/JSON.stringify.

import { createYunwu } from '@deuz-sdk/core/yunwu';

const yunwu = createYunwu({ apiKey: process.env.YUNWU_API_KEY! });

yunwu.baseURL; // 'https://yunwu.ai'  (no /v1)
yunwu.chat('gpt-5.2'); //         → /v1/chat/completions
yunwu.image('flux-2-pro'); //     → /v1/images/generations
yunwu.video('sora-2'); //         → /v1/videos
yunwu.embedding('text-embedding-3-large'); // → /v1/embeddings
yunwu.mj(); //                    → bare host root (Midjourney proxy)

A pre-built singleton is also exported (no key bound — supply one via deps.keyProvider, keyed by the provider id 'yunwu'):

import { yunwu } from '@deuz-sdk/core/yunwu';

Settings

OptionTypeDefaultNotes
apiKeystring—Yunwu relay key. Read it from process.env at the app layer; core never reads env itself.
baseURLstringhttps://yunwu.aiHost root — no /v1, no trailing slash. A trailing /v1 or slash is stripped and re-derived per surface (so https://mirror/v1/ will not produce /v1/v1).
fetchtypeof fetchglobal fetchCustom fetch (factory fetch wins over deps.fetch).
headersRecord<string, string>—Extra request headers, merged under the adapter's auth headers.

YUNWU_DEFAULT_BASE_URL ('https://yunwu.ai') is exported if you need the literal. Key resolution follows the standard precedence (the "G1" rule): deps.keyProvider (keyed by 'yunwu') > factory apiKey > otherwise an AuthenticationError is thrown. The createClient apiKeys table only covers the four first-party providers (anthropic/openai/xai/google), so a Yunwu key must come from the factory apiKey or a keyProvider.

Base-URL derivation

createYunwu normalizes the host root once, then each surface appends its own path:

SurfaceMethodWire / pathsurface tag
Chat / reasoningchat(modelId){root}/v1/chat/completionschat_completions
Image (sync)image(modelId){root}/v1/images/generationsimages
Video (async)video(modelId){root}/v1/videosvideo
Embeddingsembedding(modelId){root}/v1/embeddingsopenai-embeddings
Midjourney (async)mj(){root}/mj/... (bare root, not /v1)—

The "creative base URL" rule: point baseURL at any mirror or self-host and all five surfaces follow it.

const mirror = createYunwu({
  apiKey: process.env.YUNWU_API_KEY!,
  baseURL: 'https://my-mirror.example.com/v1/', // trailing /v1 is normalized away
});

mirror.baseURL; //               'https://my-mirror.example.com'
mirror.image('flux-2-pro'); //   → https://my-mirror.example.com/v1/images/generations
mirror.video('sora-2'); //       → https://my-mirror.example.com/v1/videos
mirror.mj().baseURL; //          'https://my-mirror.example.com'

Client members

MemberTypeDescription
baseURLstringResolved host root (no /v1).
modelstypeof YUNWU_MODELSThe pinned 2026 catalog.
chat(modelId)LanguageModelFor streamChat / generateText.
image(modelId)ImageModelFor generateImage.
video(modelId)VideoModelFor generateVideo / submitVideo.
embedding(modelId)EmbeddingModelFor embed / embedMany.
mj()partial MidjourneyConfigPre-bound config to spread into imagine / submitImagine / waitForTask.

Standalone factories

If you only need one surface, the per-surface factories skip the unified client. Each accepts the same { apiKey, baseURL, fetch, headers } settings and defaults baseURL to https://yunwu.ai:

import {
  createYunwuChat,
  createYunwuImage,
  createYunwuVideo,
  createYunwuEmbedding,
} from '@deuz-sdk/core/yunwu';

const chat = createYunwuChat({ apiKey: process.env.YUNWU_API_KEY! }); // Provider
const image = createYunwuImage({ apiKey: process.env.YUNWU_API_KEY! }); // ImageProvider
const video = createYunwuVideo({ apiKey: process.env.YUNWU_API_KEY! }); // VideoProvider
const embed = createYunwuEmbedding({ apiKey: process.env.YUNWU_API_KEY! }); // EmbeddingProvider

chat('claude-opus-4-5'); // LanguageModel  (surface: 'chat_completions')
image('nano-banana'); //    ImageModel     (surface: 'images')
video('veo3.1'); //         VideoModel     (surface: 'video')
embed('text-embedding-3-small'); // EmbeddingModel (surface: 'openai-embeddings')

YUNWU_MODELS catalog

YUNWU_MODELS is the pinned 2026 catalog (live-verified against Yunwu's /v1/models), grouped by modality. Slugs are pass-through to the relay, so any model Yunwu serves works — these lists are the curated newest generation. The chat surface uses the registry's (yunwu, chat_completions) fallback for unknown slugs, so a new release works without an SDK change.

import {
  YUNWU_MODELS,
  YUNWU_CHAT_MODELS,
  YUNWU_IMAGE_MODELS,
  YUNWU_VIDEO_MODELS,
} from '@deuz-sdk/core/yunwu';

YUNWU_MODELS.chat; //       chat / reasoning slugs
YUNWU_MODELS.image; //      image slugs
YUNWU_MODELS.video; //      async video slugs (submit → poll → download)
YUNWU_MODELS.midjourney; // Midjourney action slugs
GroupExportSample slugs
Chat / reasoningYUNWU_CHAT_MODELSgpt-5.2, claude-opus-4-5, gemini-3-pro-preview, grok-4.1, deepseek-v3.2, qwen3-max, kimi-k2-thinking
ImageYUNWU_IMAGE_MODELSgpt-image-2, flux-2-pro, flux.1-kontext-pro, nano-banana, grok-4.2-image
Video (async)YUNWU_VIDEO_MODELSsora-2, veo3.1, kling-2.6, viduq3-pro, MiniMax-Hailuo-2.3
MidjourneyYUNWU_MIDJOURNEY_MODELSmj_imagine, mj_variation, mj_upscale, mj_blend, mj_describe

The model-list types (YunwuChatModel, YunwuImageModel, YunwuVideoModel) accept any string, so chat('some-new-slug') type-checks while autocompleting the pinned catalog.

Example: chat via the relay

streamChat returns synchronously and never throws; the network pump starts lazily on first access of any output. See streamChat.

chat.ts
import { streamChat } from '@deuz-sdk/core';
import { createYunwu } from '@deuz-sdk/core/yunwu';

const yunwu = createYunwu({ apiKey: process.env.YUNWU_API_KEY! });

const result = streamChat({
  model: yunwu.chat('claude-opus-4-5'),
  messages: [{ role: 'user', content: 'Summarize reciprocal rank fusion in two sentences.' }],
  effort: 'low',
});

for await (const delta of result.textStream) {
  process.stdout.write(delta);
}

console.log('\nusage:', await result.usage);

generateText buffers the same call into a single result:

generate.ts
import { generateText } from '@deuz-sdk/core';
import { createYunwu } from '@deuz-sdk/core/yunwu';

const yunwu = createYunwu({ apiKey: process.env.YUNWU_API_KEY! });

const { text } = await generateText({
  model: yunwu.chat('gpt-5.2'),
  messages: [{ role: 'user', content: 'One-line haiku about edge runtimes.' }],
});

console.log(text);

Example: embeddings

The relay exposes the OpenAI embeddings wire, so yunwu.embedding(...) plugs straight into embed / embedMany:

embed.ts
import { embed } from '@deuz-sdk/core';
import { createYunwu } from '@deuz-sdk/core/yunwu';

const yunwu = createYunwu({ apiKey: process.env.YUNWU_API_KEY! });

const { embedding } = await embed({
  model: yunwu.embedding('text-embedding-3-large'),
  value: 'pure, web-first, multi-provider AI SDK',
});

console.log(embedding.length);

Example: generateImage

The image surface is synchronous — POST /v1/images/generations. Pass yunwu.image(slug) to generateImage:

image.ts
import { generateImage } from '@deuz-sdk/core/image';
import { createYunwu } from '@deuz-sdk/core/yunwu';

const yunwu = createYunwu({ apiKey: process.env.YUNWU_API_KEY! });

const { images } = await generateImage({
  model: yunwu.image('flux-2-pro'),
  prompt: 'a tiny robot watering a bonsai, isometric',
  size: '1024x1024',
});

console.log(images[0]?.url);

Example: generateVideo

The video surface is async — POST /v1/videos creates a job, the SDK polls it, and download: true pulls the finished clip's bytes from /v1/videos/{id}/content. Pass yunwu.video(slug) to generateVideo:

video.ts
import { generateVideo } from '@deuz-sdk/core/video';
import { createYunwu } from '@deuz-sdk/core/yunwu';

const yunwu = createYunwu({ apiKey: process.env.YUNWU_API_KEY! });

const { task } = await generateVideo({
  model: yunwu.video('sora-2'),
  prompt: 'a tiny robot watering a bonsai, slow dolly in',
  size: '1280x720',
  seconds: 8,
  onProgress: (t) => console.log(t.status, t.progress),
});

console.log(task.status, task.url); // 'completed' https://…/clip.mp4

A job the model refuses resolves with status: 'failed' and a failReason — it does not throw. The relay path is a setting, not a constant: if a host mounts its video jobs somewhere other than {root}/v1/videos, build the descriptor with createVideoProvider({ baseURL }) instead (see Video generation).

Example: imagine (Midjourney) via the relay

Midjourney is async (submit → poll → optional U/V actions) and lives at the bare host root, not under /v1. Spread yunwu.mj() into the Midjourney helpers from @deuz-sdk/core/midjourney; imagine submits a task and polls it to a terminal status, returning a MidjourneyTask with the final imageUrl.

midjourney.ts
import { imagine } from '@deuz-sdk/core/midjourney';
import { createYunwu } from '@deuz-sdk/core/yunwu';

const yunwu = createYunwu({ apiKey: process.env.YUNWU_API_KEY! });

const task = await imagine({
  ...yunwu.mj(), // apiKey + baseURL (bare root) + provider: 'yunwu'
  prompt: 'a serene mountain lake at dawn --ar 16:9',
  pollIntervalMs: 3000,
  onProgress: (t) => console.log(t.status, t.progress),
});

console.log(task.status, task.imageUrl);

To run a follow-up upscale/variation, take a customId from the finished task's buttons and call submitAction({ ...yunwu.mj(), taskId, customId }). See Image generation for the full submit/poll/action flow.

See also

Bu sayfada