npm package: @runtypelabs/sdk
Description: TypeScript SDK for the Runtype API with fluent methods. Use it to quickly realize AI products, agents, and workflows.
Author: Runtype Labs
Latest version: 1.13.3

# @runtypelabs/sdk

TypeScript client SDK for the Runtype API with FlowBuilder for constructing and executing AI workflows.

> Official npm package for the Runtype AI platform

## Installation

```bash
npm install @runtypelabs/sdk
# or
yarn add @runtypelabs/sdk
# or
pnpm add @runtypelabs/sdk
```

## Quick Start

```typescript
import { RuntypeClient } from '@runtypelabs/sdk'

// Initialize the client
const runtype = new RuntypeClient({
  apiKey: 'your-api-key',
  baseUrl: 'https://api.runtype.com', // optional, defaults to production
})

// Use the FlowBuilder for intuitive flow construction
const result = await runtype
  .flow('My AI Workflow')
  .withRecord({ name: 'Test', type: 'data', metadata: { url: 'https://example.com' } })
  .fetchUrl({
    name: 'Fetch Content',
    url: '{{_record.metadata.url}}',
    outputVariable: 'content',
  })
  .prompt({
    name: 'Analyze',
    model: 'gpt-4',
    userPrompt: 'Analyze this content: {{content}}',
    responseFormat: 'json',
  })
  .run({ streamResponse: true, flowMode: 'virtual' })

// Get the analysis result
const analysis = await result.getResult('Analyze')
console.log(analysis)
```

## Features

- **FlowBuilder API**: Fluent, chainable API for building AI workflows
- **Streaming Support**: Process streaming responses with callbacks or async iteration
- **Type Safety**: Full TypeScript support with comprehensive type definitions
- **Error Handling**: Proper error handling with custom error types
- **Zero Dependencies**: No external runtime dependencies

## FlowBuilder API

The FlowBuilder provides a fluent interface for constructing and executing flows.

### Basic Usage

```typescript
import { RuntypeClient } from '@runtypelabs/sdk'

const runtype = new RuntypeClient({ apiKey: 'sk-...' })

// Build and execute a flow
const result = await runtype
  .flow('Theme Generator')
  .withRecord({ name: 'Test', type: 'theme', metadata: { url: 'https://example.com' } })
  .fetchUrl({
    name: 'Capture Screenshot',
    url: '{{_record.metadata.url}}',
    fetchMethod: 'firecrawl',
    outputVariable: 'screenshot',
  })
  .prompt({
    name: 'Analyze',
    model: 'gemini-2.5-flash',
    userPrompt: 'Analyze the screenshot and extract color themes...',
    responseFormat: 'json',
  })
  .run({ streamResponse: true, flowMode: 'virtual' })

// Get specific step result
const analysis = await result.getResult('Analyze')
```

### With Streaming Callbacks

```typescript
const summary = await runtype
  .flow('My Flow')
  .prompt({ name: 'Process', model: 'gpt-4', userPrompt: '...' })
  .run(
    { streamResponse: true },
    {
      onStepStart: (event) => console.log('Starting:', event.name),
      onStepChunk: (chunk) => process.stdout.write(chunk),
      onStepComplete: (result, event) => console.log('Done:', event.name),
      onFlowComplete: (event) => console.log('Complete!'),
    }
  )
```

### Using Existing Flows

```typescript
// Reference an existing flow by ID
const result = await runtype
  .flow('Existing Flow')
  .useExistingFlow('flow_abc123')
  .withRecord({ name: 'Test', type: 'data' })
  .run({ streamResponse: true })
```

### Standalone FlowBuilder

```typescript
import { FlowBuilder } from '@runtypelabs/sdk'

// Build flow definition without a client
const flowBuilder = new FlowBuilder()
  .createFlow({ name: 'My Flow' })
  .withRecord({ name: 'Test', type: 'data' })
  .prompt({ name: 'Step 1', model: 'gpt-4', userPrompt: '...' })

// Execute with any client that implements DispatchClient interface
const flowResult = await flowBuilder.run(apiClient, {
  streamResponse: true,
  flowMode: 'virtual',
  storeResults: true,
})

// Get specific step result
const stepResult = await flowResult.getResult('Step 1')

// Or get all results
const allResults = await flowResult.getAllResults()
```

### Available Step Methods

| Method                 | Step Type            | Description               |
| ---------------------- | -------------------- | ------------------------- |
| `.prompt()`            | `prompt`             | AI prompt execution       |
| `.fetchUrl()`          | `fetch-url`          | HTTP/Firecrawl fetch      |
| `.transformData()`     | `transform-data`     | JavaScript transformation |
| `.setVariable()`       | `set-variable`       | Set a variable            |
| `.conditional()`       | `conditional`        | If/else branching         |
| `.search()`            | `search`             | Web search (Exa, etc.)    |
| `.sendEmail()`         | `send-email`         | Send email                |
| `.sendStream()`        | `send-stream`        | Stream message to client  |
| `.retrieveRecord()`    | `retrieve-record`    | Load record data          |
| `.upsertRecord()`      | `upsert-record`      | Create/update record      |
| `.vectorSearch()`      | `vector-search`      | Semantic search           |
| `.generateEmbedding()` | `generate-embedding` | Create embedding          |
| `.waitUntil()`         | `wait-until`         | Delay or poll             |
| `.sendEvent()`         | `send-event`         | Analytics event           |
| `.sendText()`          | `send-text`          | SMS message               |
| `.fetchGitHub()`       | `fetch-github`       | GitHub API                |

### Configuration Methods

- `.createFlow({ name, description })` - Initialize flow
- `.useExistingFlow(flowId)` - Use an existing flow by ID
- `.withRecord({ id?, name?, type?, metadata? })` - Set record config
- `.withMessages([...])` - Set conversation messages
- `.withOptions({ ... })` - Set default options

### FlowResult Methods

- `.getResult(stepName)` - Get a specific step's result
- `.getAllResults()` - Get all step results as `Map<string, any>`
- `.getSummary()` - Get `FlowSummary` with execution details
- `.stream(callbacks?)` - Process stream with optional callbacks
- `.raw` - Access raw `Response` for manual handling

### Streaming Callbacks

```typescript
interface StreamCallbacks {
  onFlowStart?: (event: FlowStartEvent) => void
  onStepStart?: (event: StepStartEvent) => void
  onStepChunk?: (chunk: string, event: StepChunkEvent) => void
  onStepComplete?: (result: any, event: StepCompleteEvent) => void
  onFlowComplete?: (event: FlowCompleteEvent) => void
  onError?: (error: Error) => void
}
```

## Traditional API Usage

The client also provides traditional endpoint-based API access:

### Flows

```typescript
// List flows with pagination
const flows = await runtype.flows.list({ limit: 20, cursor: 'next-page-cursor' })

// Get a specific flow
const flow = await runtype.flows.get('flow_123')

// Create a new flow
const newFlow = await runtype.flows.create({
  name: 'Analysis Flow',
  description: 'Analyzes customer data',
  prompts: [...]
})

// Update a flow
const updatedFlow = await runtype.flows.update('flow_123', { name: 'Updated Name' })

// Delete a flow
await runtype.flows.delete('flow_123')
```

### Records

```typescript
// List records with filtering
const records = await runtype.records.list({
  metadataKeys: 'company,industry',
  minFields: 5,
})

// Create a record
const record = await runtype.records.create({
  type: 'customer',
  name: 'Acme Corp',
  metadata: {
    industry: 'Technology',
    revenue: 1000000,
  },
})

// Bulk edit records
const result = await runtype.records.bulkEdit({
  recordIds: ['rec_1', 'rec_2'],
  updates: { status: 'processed' },
})
```

### Model Configurations

```typescript
// Get available models
const models = await runtype.modelConfigs.getAvailable()

// Create a model configuration
const config = await runtype.modelConfigs.create({
  provider: 'openai',
  modelId: 'gpt-4',
  apiKey: 'your-openai-key',
})

// Set as default
await runtype.modelConfigs.setDefault(config.id)
```

### Dispatch (Atomic Operations)

```typescript
// Create record and flow, then execute atomically
const result = await runtype.dispatch.execute({
  record: {
    name: 'New Customer',
    type: 'customer',
    metadata: { industry: 'Tech' },
  },
  flow: {
    name: 'Customer Analysis',
    prompts: [
      {
        name: 'Analyze Industry',
        text: 'Analyze this {{metadata.industry}} company',
        model: 'gpt-4',
        responseFormat: 'json',
      },
    ],
  },
  options: {
    streamResponse: true,
  },
})
```

## Error Handling

```typescript
import { RuntypeApiError } from '@runtypelabs/sdk'

try {
  const flow = await runtype.flows.get('invalid_id')
} catch (error) {
  if (error instanceof RuntypeApiError) {
    console.log('API Error:', error.message)
    console.log('Status Code:', error.statusCode)
    console.log('Error Data:', error.data)
  } else {
    console.log('Network or other error:', error)
  }
}
```

## TypeScript Support

The SDK is built with TypeScript and provides full type safety:

```typescript
import type {
  Flow,
  RuntypeRecord,
  Prompt,
  FlowBuilder,
  FlowResult,
  StreamCallbacks,
} from '@runtypelabs/sdk'

// All types use camelCase field names
const flow: Flow = await runtype.flows.get('flow_123')
console.log(flow.createdAt) // TypeScript knows this is a string
```

## Configuration Options

```typescript
const runtype = new RuntypeClient({
  apiKey: 'your-api-key', // Required for authenticated endpoints
  baseUrl: 'https://api.runtype.com', // Optional, defaults to production
  apiVersion: 'v1', // Optional, API version (default: 'v1')
  timeout: 30000, // Optional, request timeout in ms (default: 30000)
  headers: {
    // Optional, additional headers
    'X-Custom-Header': 'value',
  },
})
```

## Publishing

### Prerequisites

- npm account with publish access to `@runtypelabs/sdk`
- Logged in via `npm login`

### Steps

```bash
# 1. Ensure you're on main/staging with clean working tree
git status

# 2. Build the package
cd packages/client
pnpm build

# 3. Bump version (edit package.json manually or use npm with --ignore-scripts)
npm version patch --ignore-scripts   # 0.1.0 → 0.1.1
# npm version minor --ignore-scripts # 0.1.0 → 0.2.0
# npm version major --ignore-scripts # 0.1.0 → 1.0.0

# 4. Publish to npm (pnpm handles workspace protocol correctly)
pnpm publish --access public --no-git-checks

# 5. Push version commit and tag to git
git push && git push --tags
```

### Dry Run

To preview what will be published without actually publishing:

```bash
pnpm publish --dry-run
```

## License

MIT