import { z } from 'zod/v4' import { buildTool, type ToolDef } from '../../Tool.js' import { cronToHuman } from '../../utils/cron.js' import { listAllCronTasks } from '../../utils/cronTasks.js' import { truncate } from '../../utils/format.js' import { lazySchema } from '../../utils/lazySchema.js' import { getTeammateContext } from '../../utils/teammateContext.js' import { buildCronListPrompt, CRON_LIST_DESCRIPTION, CRON_LIST_TOOL_NAME, isDurableCronEnabled, isKairosCronEnabled, } from './prompt.js' import { renderListResultMessage, renderListToolUseMessage } from './UI.js' const inputSchema = lazySchema(() => z.strictObject({})) type InputSchema = ReturnType const outputSchema = lazySchema(() => z.object({ jobs: z.array( z.object({ id: z.string(), cron: z.string(), humanSchedule: z.string(), prompt: z.string(), recurring: z.boolean().optional(), durable: z.boolean().optional(), }), ), }), ) type OutputSchema = ReturnType export type ListOutput = z.infer export const CronListTool = buildTool({ name: CRON_LIST_TOOL_NAME, searchHint: 'list active cron jobs', maxResultSizeChars: 100_000, shouldDefer: true, get inputSchema(): InputSchema { return inputSchema() }, get outputSchema(): OutputSchema { return outputSchema() }, isEnabled() { return isKairosCronEnabled() }, isConcurrencySafe() { return true }, isReadOnly() { return true }, async description() { return CRON_LIST_DESCRIPTION }, async prompt() { return buildCronListPrompt(isDurableCronEnabled()) }, async call() { const allTasks = await listAllCronTasks() // Teammates only see their own crons; team lead (no ctx) sees all. const ctx = getTeammateContext() const tasks = ctx ? allTasks.filter(t => t.agentId === ctx.agentId) : allTasks const jobs = tasks.map(t => ({ id: t.id, cron: t.cron, humanSchedule: cronToHuman(t.cron), prompt: t.prompt, ...(t.recurring ? { recurring: true } : {}), ...(t.durable === false ? { durable: false } : {}), })) return { data: { jobs } } }, mapToolResultToToolResultBlockParam(output, toolUseID) { return { tool_use_id: toolUseID, type: 'tool_result', content: output.jobs.length > 0 ? output.jobs .map( j => `${j.id} — ${j.humanSchedule}${j.recurring ? ' (recurring)' : ' (one-shot)'}${j.durable === false ? ' [session-only]' : ''}: ${truncate(j.prompt, 80, true)}`, ) .join('\n') : 'No scheduled jobs.', } }, renderToolUseMessage: renderListToolUseMessage, renderToolResultMessage: renderListResultMessage, } satisfies ToolDef)