← 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; autokody),cloudflareAiModel(optional) - Host packages that snapshot
./model-stepcan resolve those ids through./settingswhen their own storage is empty
Import paths
| Export | Import |
|---|---|
| agentChatTurn (default) + helpers | kody:@kentcdodds/ai |
| turn engine | kody:@kentcdodds/ai/turn |
| model-only step + tool defs | kody:@kentcdodds/ai/model-step |
| hosted app fetch handler | kody:@kentcdodds/ai/app |
| background runs | kody:@kentcdodds/ai/runs |
| settings read/write | kody:@kentcdodds/ai/settings |
| migrate values → storage | kody:@kentcdodds/ai/migrate-from-values |
| types | kody:@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
runModelStepin host packages sokody.search/kody.executerun under the host's secret allowlist.agentChatTurn/runAgentTurnexecute tools as packageai. agentTurnStreamawaits the full turn then yields at most oneassistant_deltaplusturn_complete(not incremental token streaming).modelLaneon 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-stepacceptsmodelId(orcloudflareAiModel) for per-call pinning, andtoolsto replace default Kody search/execute tool defs — the host must execute returnedtoolCallsand replay assistanttool_calls+toolmessages.- Do not ask users to paste Cloudflare tokens; use the saved secret name only.