Skip to content
← Public packages

@kentcdodds/ai

Kody tool-using agent turns with Vercel AI SDK and Cloudflare AI Gateway.

src/app.ts

51 lines · 2.0 KB · TypeScript
import { agentTurnStream } from './index.ts'
import type { AgentTurnInput, AgentTurnStreamEvent } from './types.ts'

const html =
	'<!doctype html><html><head><title>Kody AI</title></head><body><h1>Kody AI</h1><form method="post"><textarea name="prompt"></textarea><button>Send</button></form></body></html>'

function json(value: unknown, init: ResponseInit = {}) {
	return new Response(JSON.stringify(value), {
		...init,
		headers: {
			'content-type': 'application/json; charset=utf-8',
			...(init.headers || {}),
		},
	})
}

async function readTurnInput(request: Request): Promise<AgentTurnInput> {
	const contentType = (request.headers.get('content-type') || '').toLowerCase()
	if (
		contentType.includes('application/x-www-form-urlencoded') ||
		contentType.includes('multipart/form-data')
	) {
		const form = await request.formData().catch(() => null)
		const prompt = form ? String(form.get('prompt') ?? '').trim() : ''
		return prompt ? { messages: [{ role: 'user', content: prompt }] } : { messages: [] }
	}
	const body = (await request.json().catch(() => ({}))) as AgentTurnInput
	return body?.messages ? body : { messages: [] }
}

/**
 * Hosted AI chat app: GET serves a minimal HTML form; POST runs one buffered agent turn.
 * @example
 * import app from 'kody:@kentcdodds/ai/app'
 * const response = await app(new Request('https://example/', { method: 'POST', body: JSON.stringify({ messages: [{ role: 'user', content: 'Hello' }] }) }))
 * // => Response JSON { ok: true, events: [...] }
 */
export default async function fetch(request: Request): Promise<Response> {
	if (request.method === 'GET' || request.method === 'HEAD') {
		return new Response(request.method === 'HEAD' ? null : html, {
			headers: { 'content-type': 'text/html; charset=utf-8' },
		})
	}
	if (request.method === 'POST') {
		const body = await readTurnInput(request)
		const events: AgentTurnStreamEvent[] = []
		for await (const event of agentTurnStream(body)) events.push(event)
		return json({ ok: true, events })
	}
	return json({ error: 'Method not allowed' }, { status: 405 })
}