Polimorf Docs

Quickstart

Install the Polimorf SDK, authenticate with an API key, and run your first generation — streaming and non-streaming.

This guide takes you from nothing to a running generation. It uses the official TypeScript SDK, @polimorfapp/sdk; every call is also a plain HTTPS request you can make from any language (see the API Reference).

Prerequisites

  • Node.js 20 or newer — the SDK uses the built-in global fetch.
  • An API key. Create one in your Polimorf dashboard. Keys look like csk_live_… and carry the runtime:execute scope by default. See Authentication for details.
  • A provider credential configured on your workspace (e.g. an OpenAI key), set in the dashboard — generations run against your own provider account.

1. Install the SDK

npm install @polimorfapp/sdk

2. Configure credentials

The SDK reads your API key from the POLIMORF_API_KEY environment variable, so you never hard-code it:

export POLIMORF_API_KEY="csk_live_your_key_here"

By default the client talks to the managed API at https://api.polimorf.app. If you self-host, set POLIMORF_BASE_URL (or pass baseUrl explicitly).

3. Run your first generation

There are two ways to run a generation. Start with whichever fits your setup.

If your team has already published an assistant in the dashboard, call it by its slug. You send only the input; the provider, model, and prompt come from the published version — so your team can change them later without a code change.

run-assistant.ts
import { createClient } from '@polimorfapp/sdk';

// apiKey and baseUrl are read from the environment when omitted.
const client = createClient();

const result = await client.assistant('support').run({
  input: 'How do I cancel my subscription?',
});

console.log(result.message.content);
console.log('finish:', result.finishReason);
console.log('tokens:', result.usage.totalTokens);

You can pass values for the version's declared prompt variables, and target a non-default environment:

const result = await client.assistant('support').run({
  input: 'How do I cancel my subscription?',
  variables: { plan: 'pro', locale: 'en-US' },
  environment: 'production', // defaults to "production"
});

Option B — Run an ad-hoc generation

If you want full control from the client, send the provider, model, and messages yourself:

run-execute.ts
import { createClient } from '@polimorfapp/sdk';

const client = createClient();

const result = await client.runtime.execute({
  providerName: 'openai',
  model: 'gpt-4o',
  messages: [
    { role: 'system', content: 'You are a concise assistant.' },
    { role: 'user', content: 'Explain what an embedding is in one sentence.' },
  ],
  config: { temperature: 0.2, maxOutputTokens: 200 },
});

console.log(result.message.content);

4. Stream the response

For a typing-indicator experience, stream tokens as they are produced. Both runtime.stream(...) and assistant(slug).stream(...) return an async iterable of typed events — consume it with for await:

stream.ts
import { createClient } from '@polimorfapp/sdk';

const client = createClient();

for await (const event of client.assistant('support').stream({
  input: 'Give me three tips for onboarding.',
})) {
  switch (event.type) {
    case 'delta':
      process.stdout.write(event.content);
      break;
    case 'usage':
      console.log('\ntokens:', event.usage.totalTokens);
      break;
    case 'done':
      console.log('\nfinished:', event.finishReason);
      break;
    case 'error':
      console.error('\nprovider error:', event.error.message);
      break;
  }
}

A provider failure arrives as a terminal error event, not a thrown exception — only a transport failure (network, timeout, abort) throws. See Streaming for the full event contract.

5. Handle errors

Any non-2xx response is thrown as a typed PolimorfApiError subclass you can branch on:

import {
  createClient,
  AuthenticationError,
  RateLimitError,
} from '@polimorfapp/sdk';

const client = createClient();

try {
  const result = await client.runtime.execute({
    providerName: 'openai',
    model: 'gpt-4o',
    messages: [{ role: 'user', content: 'Hello' }],
  });
  console.log(result.message.content);
} catch (err) {
  if (err instanceof AuthenticationError) {
    // 401 — bad or missing API key
  } else if (err instanceof RateLimitError) {
    // 429 — back off and retry
  } else {
    throw err;
  }
}

The full catalog of error codes and status mappings is in Errors.

Next steps