AgentsKit Chat Alpha

Deployment modes

View canonical Markdown

Deployment modes

The shared ChatDefinition is unchanged across deployment modes. Only the adapter, trusted host context, storage, and native renderer vary.

Mount createChatHandler from @agentskit/chat/server in a Node, serverless, or edge route that supports Web Request, Response, ReadableStream, and AbortSignal. Authenticate before resolving a definition or parsing untrusted input. Keep provider keys, authorization, tenant context, durable storage, and audit sinks on the server.

Host adapter recipes

createChatHandler already speaks the Web Fetch API. Host frameworks only need to forward the request and return the response.

Next.js App Router

// app/api/chat/route.ts
import { createChatHandler } from '@agentskit/chat/server'
import { verifyBearer } from '@/lib/auth'
import { chats } from '@/lib/chats'
import { sessions } from '@/lib/session-storage'

const handler = createChatHandler({
  authenticate: async request => {
    const identity = await verifyBearer(request)
    return identity
      ? { ok: true, context: identity }
      : { ok: false, response: new Response('Unauthorized', { status: 401 }) }
  },
  resolveDefinition: context => chats.forTenant(context?.tenantId),
  sessionStorage: context => sessions.forTenant(context?.tenantId),
})

export const POST = (request: Request) => handler(request)

Hono

import { Hono } from 'hono'
import { createChatHandler } from '@agentskit/chat/server'

const chat = createChatHandler({ /* authenticate, resolveDefinition, sessionStorage */ })
const app = new Hono()
app.post('/api/chat', c => chat(c.req.raw))
export default app

Express (Node 18+)

import express from 'express'
import { createChatHandler } from '@agentskit/chat/server'

const chat = createChatHandler({ /* … */ })
const app = express()

app.post('/api/chat', async (req, res) => {
  const disconnected = new AbortController()
  const abort = () => { if (!res.writableEnded) disconnected.abort() }
  req.once('aborted', abort)
  res.once('close', abort)
  let reader: ReadableStreamDefaultReader<Uint8Array> | undefined
  try {
    const headers = new Headers()
    for (const [key, value] of Object.entries(req.headers)) {
      if (typeof value === 'string') headers.set(key, value)
      else if (Array.isArray(value)) value.forEach(item => headers.append(key, item))
    }
    const request = new Request(`http://${req.headers.host}${req.url}`, {
      method: 'POST',
      headers,
      body: req,
      duplex: 'half',
      signal: disconnected.signal,
    } as RequestInit)
    const response = await chat(request)
    reader = response.body?.getReader()
    res.status(response.status)
    response.headers.forEach((value, key) => res.setHeader(key, value))
    if (!reader) return res.end()
    while (true) {
      const result = await reader.read()
      if (result.done) break
      res.write(result.value)
    }
    res.end()
  } finally {
    if (disconnected.signal.aborted) await reader?.cancel().catch(() => undefined)
    req.removeListener('aborted', abort)
    res.removeListener('close', abort)
  }
})

Cloudflare Worker

import { createChatHandler } from '@agentskit/chat/server'

const chat = createChatHandler({ /* … */ })

export default {
  fetch(request: Request): Promise<Response> {
    const url = new URL(request.url)
    if (request.method === 'POST' && url.pathname === '/api/chat') return chat(request)
    return new Response('Not found', { status: 404 })
  },
}

Mount createAskServiceHandler beside it when deterministic misses need cited semantic retrieval. Hosted routes and self-hosted Node bridges import the same factory; only the thin HTTP bridge varies. See the Ask backend deployment guide.

Direct trusted runtime

A server process, desktop main process, or controlled terminal may inject an AgentsKit adapter directly into defineChat. Browser and mobile clients must not receive provider secrets. Use a server adapter or the shared Ask adapter for those clients.

Browser and SSR hosts

React, Vue, Svelte, Solid, and Angular use their native renderer package. Keep the definition in a framework-neutral module. SSR may render the shell, but a chat session starts only where the selected AgentsKit binding and transport are available. Persist messages through an upstream ChatMemory; AgentsKit Chat session storage contains application metadata, not a second message history.

DOM parity demos for React, Vue, Svelte, and Solid live under apps/example-* and share @agentskit/chat-example-shared.

React Native / Expo

Use @agentskit/chat/react-native and call a trusted backend. Storage, navigation, safe-area layout, and platform permissions stay host-owned. The release gate exercises native-mobile accessibility contracts and Expo web/iOS production bundles.

Ink / terminal

Use @agentskit/chat/ink in an interactive TTY. Unsupported visual components render their validated semantic fallback. The PTY gate covers keyboard submit, choice, confirmation, lifecycle, stop, focus, and exit behavior.

Deterministic and degraded operation

Deterministic routes and verified local answer artifacts may resolve without a model. Unknown input delegates to the injected AgentsKit adapter when policy allows. Configure explicit offline/escalation behavior; never silently invent an answer when a required backend is unavailable.

See server details, Ask backend, sessions, and the security policy.