Skip to content

Model providers

Model providers are optional. DynUI accepts any implementation of the ModelProvider interface and validates every generated UITree before render.

  • HeuristicModelProvider: deterministic, no key, no SDK.
  • OpenAICompatibleModelProvider: plain fetch against an OpenAI-compatible API.
  • AnthropicModelProvider: uses @anthropic-ai/sdk, loaded lazily as an optional peer dependency.

Do not block request-time render on live model generation. Use deterministic generation or a cached tree for the render path. Run live providers in background, cache-warming, or session-boundary flows with a timeout.

const result = await generateScreen(provider, request, {
maxRepairs: 1,
timeoutMs: 3000,
});

If the provider fails, times out, or returns invalid output, generateScreen returns a deterministic fallback tree or an explicit unrenderable result.

Treat live model generation as an asynchronous composition step:

  1. Render immediately from the deterministic engine or a previously accepted cached tree.
  2. Run live generation behind a timeoutMs budget.
  3. Validate the returned tree with full render context.
  4. Cache only accepted trees.
  5. Invalidate cache entries when the manifest, renderer version, profile segment, experiment assignment, or relevant request context changes.

Track provider timeouts, validation failures, repairs, fallback rate, token usage, and accepted-tree cache hit rate. Those metrics decide whether the model is earning its place above the deterministic path.

import type { GenerationRequest, GenerationResult, ModelProvider } from "@dynui/contracts";
export class MyProvider implements ModelProvider {
id = "my-provider";
async generate(req: GenerationRequest): Promise<GenerationResult> {
return {
tree: await callYourModel(req),
usage: { inputTokens: 0, outputTokens: 0 },
};
}
}

The provider should not receive raw profile data. DynUI’s prompt builder uses a minimized projection and strips identifiers before calling a provider.

  • No real user ids, emails, names, or raw behavior are sent.
  • timeoutMs is set.
  • Provider errors are redacted before logging.
  • Deterministic evaluation passes with npm run eval:generation.
  • Live-provider evaluation passes with DYNUI_EVAL_LIVE=1 npm run eval:generation before enabling a provider-backed flow.
  • The app branches on res.unrenderable.
  • Accepted trees are cached and invalidated on manifest / renderer / profile / experiment changes.