@runtypelabs/sdk
v1.0.0
Published
TypeScript SDK for the Runtype API with fluent methods. Use it to quickly realize AI products, agents, and workflows.
Maintainers
Readme
@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
npm install @runtypelabs/sdk
# or
yarn add @runtypelabs/sdk
# or
pnpm add @runtypelabs/sdkQuick Start
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
- Automatic Field Transformation: All request/response data is automatically transformed between camelCase (client) and snake_case (API)
- 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
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
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
// 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
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 asMap<string, any>.getSummary()- GetFlowSummarywith execution details.stream(callbacks?)- Process stream with optional callbacks.raw- Access rawResponsefor manual handling
Streaming Callbacks
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
// 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
// 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
// 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)
// 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,
},
})Field Name Transformation
The SDK automatically handles field name transformation between camelCase (client) and snake_case (API):
// You write (camelCase):
const record = await runtype.records.create({
recordType: 'customer',
metadataSchema: { ... }
})
// API receives (snake_case):
// { "record_type": "customer", "metadata_schema": { ... } }
// API responds (snake_case):
// { "created_at": "2024-01-01T00:00:00Z" }
// You receive (camelCase):
console.log(record.createdAt) // "2024-01-01T00:00:00Z"Error Handling
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:
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 stringConfiguration Options
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
# 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 --tagsDry Run
To preview what will be published without actually publishing:
pnpm publish --dry-runLicense
MIT
