npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@kasko/ai

v1.0.1

Published

Type-safe AI agent library for the KASKO platform. Build AI-powered applications with tool execution, streaming responses, and multi-agent orchestration.

Readme

@kasko/ai

Type-safe AI agent library for the KASKO platform. Build AI-powered applications with tool execution, streaming responses, and multi-agent orchestration.

Requirements

  • Deno 2.x

Installation

npm install @kasko/ai

Configuration

Direct API Access

Use providers with your own API keys for direct access:

import { createOpenAi, createAnthropic } from '@kasko/ai'

// OpenAI with API key
const openai = createOpenAi({ apiKey: 'sk-...' })

// Anthropic with API key
const anthropic = createAnthropic({ apiKey: 'sk-ant-...' })

Debug Mode

Enable debug logging via localStorage (browser) or environment:

// In browser
localStorage.setItem('DEBUG', 'true')

KASKO Proxy

Use the KASKO proxy wrappers for authentication through the KASKO platform:

import { createKaskoOpenAi, createKaskoBedrock } from '@kasko/ai'

const openai = createKaskoOpenAi({
  baseUrl: 'https://api.kasko.io/ai',
  authorization: 'Bearer your-session-key',
})

const bedrock = createKaskoBedrock({
  baseUrl: 'https://api.kasko.io/ai',
  authorization: 'Bearer your-session-key',
})

Custom Fetch

For advanced use cases (custom proxies, additional headers, etc.), provide a custom fetch function:

import { createOpenAi } from '@kasko/ai'

const openai = createOpenAi({
  fetch: async (url, options) => {
    return fetch('https://my-proxy.com/openai', {
      ...options,
      headers: {
        ...options?.headers,
        'X-Custom-Header': 'value',
      },
    })
  },
})

Usage

Basic Agent

import { createAgent, createOpenAi } from '@kasko/ai'

const openai = createOpenAi()

const agent = createAgent({
  name: 'assistant',
  description: 'A helpful assistant',
  instructions: 'You are a helpful assistant.',
  model: openai({ id: 'gpt-5.1' }),
})

const result = await agent.run({ prompt: 'Hello!' })
console.log(result.text)

Agent with Tools

import { createAgent, createTool, createOpenAi } from '@kasko/ai'

const openai = createOpenAi()

const weatherAgent = createAgent({
  name: 'weather',
  description: 'Weather assistant',
  model: openai({ id: 'gpt-5.1', temperature: 0.7 }),
  tools: {
    getWeather: createTool({
      description: 'Get weather for a location',
      input: {
        type: 'object',
        properties: {
          location: { type: 'string', description: 'City name' },
        },
        required: ['location'],
      },
      execute: async ({ location }) => {
        // Fetch weather data...
        return { temperature: 72, conditions: 'sunny', location }
      },
    }),
  },
})

const result = await weatherAgent.run({
  prompt: 'What is the weather in London?',
})

Streaming

Use .stream() for real-time UI updates:

for await (const event of agent.stream({ prompt: 'Tell me a story' })) {
  switch (event.type) {
    case 'text-delta':
      process.stdout.write(event.delta)
      break
    case 'tool-call-start':
      console.log('Calling tool:', event.toolCall.name)
      break
    case 'tool-call-complete':
      console.log('Tool result:', event.toolResult.result)
      break
    case 'finish':
      console.log('Done:', event.result.finishReason)
      break
  }
}

Provider Factories

Create provider instances to configure models:

import { createOpenAi, createBedrock, createAnthropic } from '@kasko/ai'

// Create provider factories
const openai = createOpenAi()
const bedrock = createBedrock()
const anthropic = createAnthropic()

// Use with model settings
const agent = createAgent({
  name: 'assistant',
  description: 'A helpful assistant',
  model: openai({ 
    id: 'gpt-5.1',
    temperature: 0.7,
    maxTokens: 2048,
  }),
})

// Override model per-request
const result = await agent.run({
  prompt: 'Hello!',
  model: bedrock({ id: 'claude-sonnet-4.5', maxTokens: 4096 }),
})

Stop Conditions

Control when the agent stops:

const result = await agent.run({
  prompt: 'Create a plan',
  stopWhen: {
    toolCalled: ['submitPlan'],  // Stop when this tool is called
    maxSteps: 10,                // Maximum iterations
    textContains: 'DONE',        // Stop when text contains pattern
  },
})

Conversation Continuation

Save and restore conversation history for multi-turn interactions:

import { createAgent, createOpenAi } from '@kasko/ai'

const openai = createOpenAi()

const agent = createAgent({
  name: 'assistant',
  description: 'A helpful assistant',
  model: openai({ id: 'gpt-5.1' }),
})

// First interaction
const result1 = await agent.run({ prompt: 'My name is Alice' })
console.log(result1.text) // "Nice to meet you, Alice!"

// Save conversation to database
await db.save({ 
  conversationId: '123', 
  messages: result1.messages  // Message[] is JSON-serializable
})

// Later: load and continue the conversation
const saved = await db.load('123')
const result2 = await agent.run({ 
  prompt: 'What is my name?',
  messages: saved.messages,  // Pass previous messages
})
console.log(result2.text) // "Your name is Alice."

// Save updated conversation
await db.save({ 
  conversationId: '123', 
  messages: result2.messages,  // Includes all messages
})

The result.messages array contains the full conversation history including system prompts, user messages, assistant responses, tool calls, and tool results.

Multimodal Prompts

Send images and documents along with text prompts:

import { createAgent, createOpenAi, type ContentPart } from '@kasko/ai'

const openai = createOpenAi()

const agent = createAgent({
  name: 'vision',
  description: 'Image analysis assistant',
  model: openai({ id: 'gpt-5.1' }),
})

// With images (base64 data URL)
const imageDataUrl = 'data:image/png;base64,iVBORw0KGgo...'
const result = await agent.run({
  prompt: [
    { type: 'text', text: 'What is in this image?' },
    { type: 'image', source: imageDataUrl, mediaType: 'image/png' },
  ],
})

// With PDF documents
const pdfDataUrl = 'data:application/pdf;base64,JVBERi0xLjQK...'
const result = await agent.run({
  prompt: [
    { type: 'text', text: 'Summarize this document' },
    { type: 'document', source: pdfDataUrl, mediaType: 'application/pdf', filename: 'report.pdf' },
  ],
})

// Multiple files
const result = await agent.run({
  prompt: [
    { type: 'text', text: 'Compare these two images' },
    { type: 'image', source: image1DataUrl },
    { type: 'image', source: image2DataUrl },
  ],
})

Supported image formats: PNG, JPEG, GIF, WebP Supported document formats: PDF, CSV, DOC, DOCX, XLS, XLSX, HTML, TXT, MD

Multi-Agent

Tools can call other agents:

import { createAgent, createTool, createOpenAi } from '@kasko/ai'

const openai = createOpenAi()

const researchAgent = createAgent({
  name: 'researcher',
  description: 'Research specialist',
  model: openai({ id: 'gpt-5.1' }),
  tools: { search: searchTool },
})

const orchestrator = createAgent({
  name: 'orchestrator',
  description: 'Task coordinator',
  model: openai({ id: 'gpt-5.1' }),
  tools: {
    delegate: createTool({
      description: 'Delegate research to specialist',
      input: {
        type: 'object',
        properties: { topic: { type: 'string' } },
        required: ['topic'],
      },
      execute: async ({ topic }) => {
        const result = await researchAgent.run({ prompt: `Research: ${topic}` })
        return { findings: result.text }
      },
    }),
  },
})

Custom Providers

Create custom providers for other LLM backends:

import { 
  BaseProvider, 
  type Provider, 
  type ProviderRequestOptions, 
  type ModelReference, 
  type ProviderFetch,
  type Message,
  type ToolDefinition,
  type ApiMessage,
  type ApiToolDefinition,
} from '@kasko/ai'

class MyProvider extends BaseProvider {
  readonly name = 'my-provider'

  override getEndpoint(): string {
    return 'https://api.my-provider.com/v1/chat'
  }

  override buildRequestBody(
    model: string,
    messages: Message[],
    tools: ToolDefinition[],
    options?: ProviderRequestOptions
  ): unknown {
    return {
      model,
      messages: this.formatMessages(messages),
      tools: tools.length > 0 ? this.formatTools(tools) : undefined,
      stream: options?.stream ?? true,
      max_tokens: options?.maxTokens,
    }
  }
}

// Factory function following the library pattern
function createMyProvider(config?: { fetch?: ProviderFetch }) {
  const provider = new MyProvider()
  const customFetch = config?.fetch ?? fetch

  return (modelConfig: { id: string; temperature?: number; maxTokens?: number }): ModelReference => ({
    provider,
    modelId: modelConfig.id,
    settings: { 
      temperature: modelConfig.temperature, 
      maxTokens: modelConfig.maxTokens 
    },
    fetch: customFetch,
  })
}

// Usage
const myProvider = createMyProvider()
const agent = createAgent({
  name: 'assistant',
  description: 'Agent with custom provider',
  model: myProvider({ id: 'my-model-v1', temperature: 0.7 }),
})

For streaming support, use the exported parser utilities:

import { 
  parseOpenAIResponsesStream,  // For OpenAI-compatible SSE
  parseBedrockConverseStream,  // For Bedrock binary event-stream
  parseSSEStream,              // Legacy Chat Completions format
  accumulateToolCalls,
  finalizeToolCalls,
  emptyTokenUsage,
  mergeTokenUsage,
  type ParsedStreamChunk,
  type ToolCallAccumulator,
} from '@kasko/ai'

API Reference

Provider Factories

Create provider instances for model configuration:

import { createOpenAi, createBedrock, createAnthropic } from '@kasko/ai'

// With API key (direct API access)
const openai = createOpenAi({ apiKey: 'sk-...' })
const anthropic = createAnthropic({ apiKey: 'sk-ant-...' })

// With custom fetch (for proxies)
const bedrock = createBedrock({
  fetch: async (url, options) => {
    // Custom request handling
    return fetch(url, options)
  },
})

// Each returns a function that creates ModelReference objects
const model = openai({ 
  id: 'gpt-5.1',        // Model ID (required)
  temperature: 0.7,     // Optional: 0-2
  maxTokens: 2048,      // Optional: max output tokens
})

KASKO Proxy Wrappers

Convenience wrappers for the KASKO platform proxy:

import { createKaskoOpenAi, createKaskoBedrock } from '@kasko/ai'

const openai = createKaskoOpenAi({
  baseUrl: 'https://api.kasko.io/ai',
  authorization: 'Bearer session-key',
  headers: { 'X-Custom': 'value' },  // Optional additional headers
})

createAgent(config)

Create an agent with tools and configuration.

| Option | Type | Description | |--------|------|-------------| | name | string | Agent name | | description | string | Agent description | | tools | Record<string, Tool> | Available tools | | instructions | string | System prompt | | model | ModelReference | Default model | | maxSteps | number | Max iterations (default: 20) |

Returns an Agent with .run() and .stream() methods.

createTool(config)

Create a tool for an agent.

| Option | Type | Description | |--------|------|-------------| | description | string | Tool description (shown to LLM) | | input | JsonSchema | Input parameter schema | | output | JsonSchema | Optional output schema | | execute | (input) => Promise<output> | Tool implementation |

RunOptions

Options for .run() and .stream():

| Option | Type | Description | |--------|------|-------------| | prompt | string \| ContentPart[] | User message (text or multimodal) | | model | ModelReference | Override model | | messages | Message[] | Conversation history | | signal | AbortSignal | Cancellation | | stopWhen | StopConditions | Stop conditions | | onTextDelta | (delta) => void | Text callback | | onToolCall | (call) => void | Tool call callback | | onToolResult | (result) => void | Tool result callback |

Development

# Install dependencies
deno install

# Start dev server
deno task dev

# Run tests
deno task test:run

# Build
deno task build

# Lint and format check
deno task check

# Format code
deno task format