Skip to content
← Public packages

@kentcdodds/ai

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

AGENTS.md

102 lines · 3.4 KB · Markdown

@kentcdodds/ai — agent notes

Human setup and intent live in README.md. This file is for agents: imports, smoke checks, snippets, and edge cases. Secrets by name only — never paste token values. Do not disable live webhooks or jobs.

Secret / storage

  • Secret name: cloudflareApiToken (user scope) — placeholder {{secret:cloudflareApiToken}}
  • Package storage (via ./settings, no republish): cloudflareAccountId, cloudflareAiGatewayId (optional; auto kody), cloudflareAiModel (optional)
  • Host packages that snapshot ./model-step can resolve those ids through ./settings when their own storage is empty

Import paths

ExportImport
agentChatTurn (default) + helperskody:@kentcdodds/ai
turn enginekody:@kentcdodds/ai/turn
model-only step + tool defskody:@kentcdodds/ai/model-step
hosted app fetch handlerkody:@kentcdodds/ai/app
background runskody:@kentcdodds/ai/runs
settings read/writekody:@kentcdodds/ai/settings
migrate values → storagekody:@kentcdodds/ai/migrate-from-values
typeskody:@kentcdodds/ai/types

Prefer static kody:@kentcdodds/ai/... imports from execute. Do not lead with packages.invoke.

Root also exports agentTurnStream, runModelStep, defaultKodyAgentSystem, startAgentTurn, readNextAgentTurnEvents, cancelAgentTurn.

Smoke / dry checks

Read settings first (no model spend):

import aiSettings from 'kody:@kentcdodds/ai/settings'

export default async function main() {
	return await aiSettings()
	// => { accountId, gatewayId, model }
}

Minimal turn (uses the gateway; keep prompts trivial):

import agentChatTurn from 'kody:@kentcdodds/ai'

export default async function main() {
	return await agentChatTurn({
		messages: [{ role: 'user', content: 'Reply with the single word: pong' }],
		maxSteps: 1,
	})
}

Host-side tool loop (preferred when secrets must stay on the host package):

import { runModelStep } from 'kody:@kentcdodds/ai/model-step'

export default async function main() {
	return await runModelStep({
		messages: [{ role: 'user', content: 'Say hi in one short sentence.' }],
	})
	// Host executes returned toolCalls with local kody.search / kody.execute
}

Background turn poll (needs package storage / workflows):

import { startAgentTurn, readNextAgentTurnEvents } from 'kody:@kentcdodds/ai'

export default async function main() {
	const { runId } = await startAgentTurn({
		messages: [{ role: 'user', content: 'Say ok' }],
	})
	return await readNextAgentTurnEvents({ runId })
}

Edge cases

  • Prefer runModelStep in host packages so kody.search / kody.execute run under the host's secret allowlist. agentChatTurn / runAgentTurn execute tools as package ai.
  • agentTurnStream awaits the full turn then yields at most one assistant_delta plus turn_complete (not incremental token streaming).
  • modelLane on input is accepted but currently ignored.
  • When the model emits tool calls as JSON text instead of structured tool_calls, the turn loop recovers and executes them.
  • ./model-step accepts modelId (or cloudflareAiModel) for per-call pinning, and tools to replace default Kody search/execute tool defs — the host must execute returned toolCalls and replay assistant tool_calls + tool messages.
  • Do not ask users to paste Cloudflare tokens; use the saved secret name only.