File size: 2,888 Bytes
064bfd6 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | 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<typeof inputSchema>
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<typeof outputSchema>
export type ListOutput = z.infer<OutputSchema>
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<InputSchema, ListOutput>)
|