Skip to content
← Public packages

@kentcdodds/devin

Start, monitor, and manage Devin sessions, knowledge, playbooks, and schedules via the Devin v3 API

src/schedules.ts

151 lines · 4.1 KB · TypeScript
import { clampInt, compact, devinOrgApi, trimString } from './lib/client.ts'

export type Schedule = {
	scheduled_session_id: string
	org_id: string
	name: string
	prompt: string
	frequency: string | null
	enabled: boolean
	agent: 'devin' | 'data_analyst' | string
	notify_on: 'always' | 'failure' | 'never' | string
	playbook?: unknown
	created_by?: string | null
	last_executed_at?: number | null
	last_error_at?: number | null
	last_error_message?: string | null
	consecutive_failures?: number | null
	created_at: number
	updated_at: number
}

/** Offset-paginated (schedules predate the cursor pagination elsewhere). */
export async function listSchedules(
	params: { orgId?: string; limit?: number; offset?: number } = {},
) {
	return devinOrgApi<{ items?: Schedule[] } | Schedule[]>({
		orgId: params.orgId,
		path: '/schedules',
		query: compact({
			limit: params.limit === undefined ? undefined : clampInt(params.limit, 1, 200, 50),
			offset: params.offset,
		}),
	})
}

export async function getSchedule(params: {
	scheduleId: string
	orgId?: string
}) {
	return devinOrgApi<Schedule>({
		orgId: params.orgId,
		path: `/schedules/${encodeURIComponent(params.scheduleId)}`,
	})
}

export type CreateScheduleParams = {
	orgId?: string
	name: string
	prompt: string
	scheduleType?: 'recurring' | 'one_time'
	/** Cron-ish/named frequency for recurring schedules. */
	frequency?: string
	intervalCount?: number
	/** ISO date-time for one_time schedules. */
	scheduledAt?: string
	playbookId?: string
	tags?: string[]
	agent?: 'devin' | 'data_analyst'
	notifyOn?: 'always' | 'failure' | 'never'
	bypassApproval?: boolean
	platform?: string
	targetDevinId?: string
	/** Requires ImpersonateOrgSessions on the service user's role. */
	createAsUserId?: string
	slackChannelId?: string
	slackTeamId?: string
}

export async function createSchedule(params: CreateScheduleParams) {
	const name = trimString(params.name)
	const prompt = trimString(params.prompt)
	if (!name || !prompt) throw new Error('Schedules require name and prompt')

	return devinOrgApi<Schedule>({
		orgId: params.orgId,
		path: '/schedules',
		method: 'POST',
		body: compact({
			name,
			prompt,
			schedule_type: params.scheduleType,
			frequency: params.frequency,
			interval_count: params.intervalCount,
			scheduled_at: params.scheduledAt,
			playbook_id: params.playbookId,
			tags: params.tags,
			agent: params.agent,
			notify_on: params.notifyOn,
			bypass_approval: params.bypassApproval,
			platform: params.platform,
			target_devin_id: params.targetDevinId,
			create_as_user_id: params.createAsUserId,
			slack_channel_id: params.slackChannelId,
			slack_team_id: params.slackTeamId,
		}),
	})
}

export type UpdateScheduleParams = Partial<
	Omit<CreateScheduleParams, 'name' | 'prompt' | 'createAsUserId'>
> & {
	scheduleId: string
	orgId?: string
	name?: string
	prompt?: string
	enabled?: boolean
	/** Requires ImpersonateOrgSessions on the service user's role. */
	runAsUserId?: string
}

/** Partial update (PATCH) — only the fields you pass are changed. */
export async function updateSchedule(params: UpdateScheduleParams) {
	return devinOrgApi<Schedule>({
		orgId: params.orgId,
		path: `/schedules/${encodeURIComponent(params.scheduleId)}`,
		method: 'PATCH',
		body: compact({
			name: params.name,
			prompt: params.prompt,
			enabled: params.enabled,
			schedule_type: params.scheduleType,
			frequency: params.frequency,
			interval_count: params.intervalCount,
			scheduled_at: params.scheduledAt,
			playbook_id: params.playbookId,
			tags: params.tags,
			agent: params.agent,
			notify_on: params.notifyOn,
			bypass_approval: params.bypassApproval,
			platform: params.platform,
			target_devin_id: params.targetDevinId,
			run_as_user_id: params.runAsUserId,
			slack_channel_id: params.slackChannelId,
			slack_team_id: params.slackTeamId,
		}),
	})
}

/** Prefer `updateSchedule({ enabled: false })` over deleting. Destructive. */
export async function deleteSchedule(params: {
	scheduleId: string
	orgId?: string
}) {
	return devinOrgApi<unknown>({
		orgId: params.orgId,
		path: `/schedules/${encodeURIComponent(params.scheduleId)}`,
		method: 'DELETE',
	})
}

export default listSchedules