/ TypeScript SDK
GitHub

TypeScript SDK

Reference·Node 18+ · Browser compatible

The TypeScript SDK ships as dual ESM + CJS, works in Node.js 18+ and modern browsers, and is fully typed. It uses fetch natively with exponential retry on 5xx (1s / 2s / 4s, 3 retries).

Installation

terminal
npm install crewlayer
# or
pnpm add crewlayer
# or
yarn add crewlayer

Client Initialization

client.ts
import { CrewLayerClient } from 'crewlayer'

const client = new CrewLayerClient({
  baseUrl: 'http://localhost:8000',  // default: http://localhost:8000
  apiKey: process.env.CREWLAYER_API_KEY!,
  timeout: 30_000,                   // ms, default: 30000
})

// Or from env vars: CREWLAYER_API_KEY, CREWLAYER_BASE_URL
const client = new CrewLayerClient()

client.agents

agents.ts
// Create
const agent = await client.agents.create({
  name: 'my-agent',
  description: 'Sales assistant',
  tags: ['production'],
  config: { model: 'claude-opus-4-8' },
})
const agentId = agent.id

// Get
const agent = await client.agents.get(agentId)

// List
const { items, nextCursor } = await client.agents.list({ status: 'idle', limit: 20 })

// Update
await client.agents.update(agentId, { name: 'my-agent-v2' })

// Delete
await client.agents.delete(agentId)

// Status
const status = await client.agents.getStatus(agentId)
await client.agents.setStatus(agentId, { status: 'working', sessionId: 'session-uuid' })

// Status history
const history = await client.agents.statusHistory(agentId, { limit: 10 })

client.memory

memory.ts
// Save
const memory = await client.memory.save(agentId, {
  content: 'User prefers dark mode and TypeScript.',
  importance: 0.85,
})

// Recall (semantic similarity)
const memories = await client.memory.recall(agentId, {
  query: 'user interface preferences',
  topK: 5,
  minSimilarity: 0.7,
})
memories.forEach(m => console.log(`[${m.similarity.toFixed(2)}] ${m.content}`))

// List (paginated)
const page = await client.memory.list(agentId, { limit: 20 })

// Delete
await client.memory.delete(agentId, memoryId)

// Stats
const stats = await client.memory.stats(agentId)

// Short-term messages
await client.memory.appendMessage(agentId, {
  sessionId,
  role: 'user',
  content: 'Hello!',
})
const messages = await client.memory.getMessages(agentId, { sessionId })
await client.memory.clearMessages(agentId, { sessionId })

client.actions

actions.ts
const t0 = Date.now()
const result = await myTool(input)

await client.actions.log(agentId, {
  toolName: 'web_search',
  inputParams: { query: 'latest AI news' },
  outputResult: { count: result.length },
  status: 'success',
  durationMs: Date.now() - t0,
  sessionId,
})

// List
const { items } = await client.actions.list(agentId, {
  tool: 'web_search',
  status: 'error',
  limit: 50,
})

// Stats
const stats = await client.actions.stats(agentId)

client.sessions

sessions.ts
// Create session
const session = await client.sessions.create(agentId, { episodeId })
const sessionId = session.id

// Close and extract memories
const result = await client.sessions.close(sessionId)
console.log(`Extracted ${result.memoriesExtracted} memories`)

client.context

context.ts
// Write
const entry = await client.context.write('pipeline', 'step1', { done: true, count: 42 })
console.log(`Written at version ${entry.version}`)

// Read
const { value } = await client.context.read('pipeline', 'step1')

// Delete
await client.context.delete('pipeline', 'step1')

// History & rollback
const history = await client.context.history('pipeline', 'step1')
await client.context.rollback('pipeline', 'step1', { version: 2 })

SSE Streaming

Subscribe to blackboard namespace changes in real time using Server-Sent Events:

streaming.ts
import { openContextStream } from 'crewlayer'

const stream = openContextStream(client, 'pipeline')

// Async iterator — each event is a key change in the namespace
for await (const event of stream) {
  console.log(`Key "${event.key}" changed to`, event.value)
  console.log(`Version: ${event.version}`)

  if (shouldStop) {
    stream.close()
    break
  }
}

// React hook usage (Next.js / React)
import { useContextStream } from 'crewlayer/react'

function PipelineStatus() {
  const { events } = useContextStream(client, 'pipeline')
  return 
{JSON.stringify(events, null, 2)}
}

Vercel AI SDK Adapter

The SDK ships a thin adapter that wires CrewLayer memory into streamText / generateText route handlers:

app/api/chat/route.ts
import { streamText } from 'ai'
import { anthropic } from '@ai-sdk/anthropic'
import { CrewLayerClient } from 'crewlayer'
import { withCrewLayerMemory } from 'crewlayer/vercel-ai'

const cl = new CrewLayerClient({ apiKey: process.env.CREWLAYER_API_KEY! })
const AGENT_ID = '550e8400-e29b-41d4-a716-446655440000'

export async function POST(req: Request) {
  const { messages, sessionId } = await req.json()

  // Pull relevant memories for context injection
  const enriched = await withCrewLayerMemory(cl, AGENT_ID, {
    messages,
    sessionId,
    topK: 5,
    injectAs: 'system',  // adds memories as a system message prefix
  })

  const result = streamText({
    model: anthropic('claude-opus-4-8'),
    messages: enriched.messages,
    onFinish: async ({ text }) => {
      // Persist the assistant response and optionally extract memories
      await cl.memory.appendMessage(AGENT_ID, {
        sessionId,
        role: 'assistant',
        content: text,
      })
    },
  })

  return result.toDataStreamResponse()
}

Error Handling

errors.ts
import { CrewLayerError, AuthError, NotFoundError, RateLimitError } from 'crewlayer'

try {
  const agent = await client.agents.get('non-existent-id')
} catch (err) {
  if (err instanceof NotFoundError) {
    console.log('Agent not found')
  } else if (err instanceof AuthError) {
    console.log('Invalid API key or missing scope')
  } else if (err instanceof RateLimitError) {
    console.log(`Rate limited. Retry after ${err.retryAfterMs}ms`)
  } else if (err instanceof CrewLayerError) {
    console.log(`API error ${err.status}: ${err.message}`)
  }
}

Build output

terminal
cd sdk-typescript
npm install
npm test          # vitest — 72 tests
npm run build     # tsup → dist/index.js (CJS) + dist/index.mjs (ESM)