@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.
Maintainers
Keywords
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/aiConfiguration
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