feat (acp): custom methods for managing scheduler (#9972)

This commit is contained in:
Lifei Zhou
2026-06-25 09:11:35 +10:00
committed by GitHub
parent 09998b12cf
commit eea698945c
28 changed files with 2050 additions and 484 deletions
+193
View File
@@ -0,0 +1,193 @@
import type {
CreateScheduleRequest_unstable,
InspectRunningJobResponse_unstable,
KillRunningJobResponse_unstable,
RunScheduleNowResponse_unstable,
ScheduledJobDto,
SessionInfo,
} from '@aaif/goose-sdk';
import { getAcpClient } from './acpConnection';
let inFlightListSchedules: Promise<ScheduledJobDto[]> | null = null;
const inFlightListScheduleSessions = new Map<string, Promise<SessionInfo[]>>();
function acpErrorMessage(error: unknown): string | null {
if (typeof error !== 'object' || error === null) {
return null;
}
const candidate = 'error' in error && isRecord(error.error) ? error.error : error;
if (!isRecord(candidate)) {
return null;
}
if (typeof candidate.data === 'string') {
return candidate.data;
}
return typeof candidate.message === 'string' ? candidate.message : null;
}
function isRecord(value: unknown): value is Record<string, unknown> {
return typeof value === 'object' && value !== null;
}
function normalizeAcpError(error: unknown, fallback: string): Error {
const message = acpErrorMessage(error);
if (message) {
return new Error(message);
}
if (error instanceof Error) {
return error;
}
return new Error(fallback);
}
function clearInFlightScheduleReads(): void {
inFlightListSchedules = null;
inFlightListScheduleSessions.clear();
}
export async function acpListSchedules(): Promise<ScheduledJobDto[]> {
const pending = inFlightListSchedules;
if (pending) {
return pending;
}
const listPromise = (async () => {
const client = await getAcpClient();
const response = await client.goose.schedulesList_unstable({});
return response.jobs;
})().catch((error) => {
throw normalizeAcpError(error, 'Failed to list schedules');
});
inFlightListSchedules = listPromise;
try {
return await listPromise;
} finally {
if (inFlightListSchedules === listPromise) {
inFlightListSchedules = null;
}
}
}
export async function acpCreateSchedule(
request: CreateScheduleRequest_unstable
): Promise<ScheduledJobDto> {
try {
const client = await getAcpClient();
const response = await client.goose.schedulesCreate_unstable(request);
clearInFlightScheduleReads();
return response.job;
} catch (error) {
throw normalizeAcpError(error, 'Failed to create schedule');
}
}
export async function acpDeleteSchedule(scheduleId: string): Promise<void> {
try {
const client = await getAcpClient();
await client.goose.schedulesDelete_unstable({ scheduleId });
clearInFlightScheduleReads();
} catch (error) {
throw normalizeAcpError(error, 'Failed to delete schedule');
}
}
export async function acpListScheduleSessions(
scheduleId: string,
limit: number
): Promise<SessionInfo[]> {
const key = `${scheduleId}:${limit}`;
const pending = inFlightListScheduleSessions.get(key);
if (pending) {
return pending;
}
const listPromise = (async () => {
const client = await getAcpClient();
const response = await client.goose.schedulesSessionsList_unstable({ scheduleId, limit });
return response.sessions;
})().catch((error) => {
throw normalizeAcpError(error, 'Failed to list schedule sessions');
});
inFlightListScheduleSessions.set(key, listPromise);
try {
return await listPromise;
} finally {
if (inFlightListScheduleSessions.get(key) === listPromise) {
inFlightListScheduleSessions.delete(key);
}
}
}
export async function acpRunScheduleNow(
scheduleId: string
): Promise<RunScheduleNowResponse_unstable> {
try {
const client = await getAcpClient();
const response = await client.goose.schedulesRunNow_unstable({ scheduleId });
clearInFlightScheduleReads();
return response;
} catch (error) {
throw normalizeAcpError(error, 'Failed to run schedule now');
}
}
export async function acpPauseSchedule(scheduleId: string): Promise<void> {
try {
const client = await getAcpClient();
await client.goose.schedulesPause_unstable({ scheduleId });
clearInFlightScheduleReads();
} catch (error) {
throw normalizeAcpError(error, 'Failed to pause schedule');
}
}
export async function acpUnpauseSchedule(scheduleId: string): Promise<void> {
try {
const client = await getAcpClient();
await client.goose.schedulesUnpause_unstable({ scheduleId });
clearInFlightScheduleReads();
} catch (error) {
throw normalizeAcpError(error, 'Failed to unpause schedule');
}
}
export async function acpUpdateSchedule(
scheduleId: string,
cron: string
): Promise<ScheduledJobDto> {
try {
const client = await getAcpClient();
const response = await client.goose.schedulesUpdate_unstable({ scheduleId, cron });
clearInFlightScheduleReads();
return response.job;
} catch (error) {
throw normalizeAcpError(error, 'Failed to update schedule');
}
}
export async function acpKillRunningJob(jobId: string): Promise<KillRunningJobResponse_unstable> {
try {
const client = await getAcpClient();
const response = await client.goose.schedulesRunningJobKill_unstable({ jobId });
clearInFlightScheduleReads();
return response;
} catch (error) {
throw normalizeAcpError(error, 'Failed to kill running job');
}
}
export async function acpInspectRunningJob(
jobId: string
): Promise<InspectRunningJobResponse_unstable> {
try {
const client = await getAcpClient();
return await client.goose.schedulesRunningJobInspect_unstable({ jobId });
} catch (error) {
throw normalizeAcpError(error, 'Failed to inspect running job');
}
}
@@ -991,8 +991,8 @@ export default function RecipesView() {
id: scheduleRecipeManifest.id,
source: '',
cron: scheduleRecipeManifest.schedule_cron,
last_run: null,
currently_running: false,
lastRun: null,
currentlyRunning: false,
paused: false,
}
: null
@@ -1,5 +1,5 @@
import React, { useState, useEffect } from 'react';
import { ScheduledJob } from '../../schedule';
import type { ScheduledJobDto } from '@aaif/goose-sdk';
import { errorMessage } from '../../utils/conversionUtils';
import { defineMessages, useIntl } from '../../i18n';
import {
@@ -61,7 +61,7 @@ const i18n = defineMessages({
});
interface CronPickerProps {
schedule: ScheduledJob | null;
schedule: ScheduledJobDto | null;
onChange: (cron: string) => void;
isValid: (valid: boolean) => void;
}
@@ -1,29 +1,28 @@
import React, { useState, useEffect, useCallback } from 'react';
import type { ScheduledJobDto, SessionInfo } from '@aaif/goose-sdk';
import { Button } from '../ui/button';
import { ScrollArea } from '../ui/scroll-area';
import BackButton from '../ui/BackButton';
import { Card } from '../ui/card';
import {
getScheduleSessions,
runScheduleNow,
pauseSchedule,
unpauseSchedule,
updateSchedule,
listSchedules,
killRunningJob,
inspectRunningJob,
ScheduledJob,
} from '../../schedule';
import SessionHistoryView from '../sessions/SessionHistoryView';
acpListScheduleSessions,
acpRunScheduleNow,
acpPauseSchedule,
acpUnpauseSchedule,
acpUpdateSchedule,
acpListSchedules,
acpKillRunningJob,
acpInspectRunningJob,
} from '../../acp/schedules';
import { ScheduleModal, NewSchedulePayload } from './ScheduleModal';
import { toastError, toastSuccess } from '../../toasts';
import { Loader2, Pause, Play, Edit, Square, Eye } from 'lucide-react';
import cronstrue from 'cronstrue';
import { formatToLocalDateWithTimezone } from '../../utils/date';
import { getSession, Session } from '../../api';
import { trackScheduleRunNow, getErrorType } from '../../utils/analytics';
import { errorMessage } from '../../utils/conversionUtils';
import { defineMessages, useIntl } from '../../i18n';
import { useNavigation } from '../../hooks/useNavigation';
const i18n = defineMessages({
scheduleNotFound: { id: 'scheduleDetailView.scheduleNotFound', defaultMessage: 'Schedule Not Found' },
@@ -57,12 +56,11 @@ const i18n = defineMessages({
created: { id: 'scheduleDetailView.created', defaultMessage: 'Created: {date}' },
messages: { id: 'scheduleDetailView.messages', defaultMessage: 'Messages: {count}' },
dir: { id: 'scheduleDetailView.dir', defaultMessage: 'Dir: {path}' },
tokens: { id: 'scheduleDetailView.tokens', defaultMessage: 'Tokens: {count}' },
idLabel: { id: 'scheduleDetailView.idLabel', defaultMessage: 'ID:' },
jobCancelled: { id: 'scheduleDetailView.jobCancelled', defaultMessage: 'Job Cancelled' },
jobCancelledMsg: { id: 'scheduleDetailView.jobCancelledMsg', defaultMessage: 'The job was cancelled while starting up.' },
scheduleTriggered: { id: 'scheduleDetailView.scheduleTriggered', defaultMessage: 'Schedule Triggered' },
newSession: { id: 'scheduleDetailView.newSession', defaultMessage: 'New session: {sessionId}' },
scheduleCompleted: { id: 'scheduleDetailView.scheduleCompleted', defaultMessage: 'Run completed' },
completedSession: { id: 'scheduleDetailView.completedSession', defaultMessage: 'Session: {sessionId}' },
runScheduleError: { id: 'scheduleDetailView.runScheduleError', defaultMessage: 'Run Schedule Error' },
scheduleUnpaused: { id: 'scheduleDetailView.scheduleUnpaused', defaultMessage: 'Schedule Unpaused' },
unpausedMsg: { id: 'scheduleDetailView.unpausedMsg', defaultMessage: 'Unpaused "{id}"' },
@@ -77,53 +75,48 @@ const i18n = defineMessages({
scheduleUpdated: { id: 'scheduleDetailView.scheduleUpdated', defaultMessage: 'Schedule Updated' },
updatedMsg: { id: 'scheduleDetailView.updatedMsg', defaultMessage: 'Updated "{id}"' },
updateScheduleError: { id: 'scheduleDetailView.updateScheduleError', defaultMessage: 'Update Schedule Error' },
failedToLoadSession: { id: 'scheduleDetailView.failedToLoadSession', defaultMessage: 'Failed to load session' },
scheduleNotFoundError: { id: 'scheduleDetailView.scheduleNotFoundError', defaultMessage: 'Schedule not found' },
});
interface ScheduleSessionMeta {
id: string;
name: string;
createdAt: string;
workingDir?: string;
scheduleId?: string | null;
messageCount?: number;
totalTokens?: number | null;
inputTokens?: number | null;
outputTokens?: number | null;
accumulatedTotalTokens?: number | null;
accumulatedInputTokens?: number | null;
accumulatedOutputTokens?: number | null;
}
interface ScheduleDetailViewProps {
scheduleId: string | null;
onNavigateBack: () => void;
}
function sessionMeta(session: SessionInfo): Record<string, unknown> {
return typeof session._meta === 'object' && session._meta !== null ? session._meta : {};
}
function metaString(session: SessionInfo, key: string): string | undefined {
const value = sessionMeta(session)[key];
return typeof value === 'string' ? value : undefined;
}
function metaNumber(session: SessionInfo, key: string): number | undefined {
const value = sessionMeta(session)[key];
return typeof value === 'number' ? value : undefined;
}
const ScheduleDetailView: React.FC<ScheduleDetailViewProps> = ({ scheduleId, onNavigateBack }) => {
const intl = useIntl();
const [sessions, setSessions] = useState<ScheduleSessionMeta[]>([]);
const setView = useNavigation();
const [sessions, setSessions] = useState<SessionInfo[]>([]);
const [isLoadingSessions, setIsLoadingSessions] = useState(false);
const [sessionsError, setSessionsError] = useState<string | null>(null);
const [scheduleDetails, setScheduleDetails] = useState<ScheduledJob | null>(null);
const [scheduleDetails, setScheduleDetails] = useState<ScheduledJobDto | null>(null);
const [isLoadingSchedule, setIsLoadingSchedule] = useState(false);
const [scheduleError, setScheduleError] = useState<string | null>(null);
const [isActionLoading, setIsActionLoading] = useState(false);
const [selectedSession, setSelectedSession] = useState<Session | null>(null);
const [isLoadingSession, setIsLoadingSession] = useState(false);
const [sessionError, setSessionError] = useState<string | null>(null);
const [isModalOpen, setIsModalOpen] = useState(false);
const fetchSessions = async (sId: string) => {
setIsLoadingSessions(true);
setSessionsError(null);
try {
const data = await getScheduleSessions(sId, 20);
const data = await acpListScheduleSessions(sId, 20);
setSessions(data);
} catch (err) {
setSessionsError(errorMessage(err, 'Failed to fetch sessions'));
@@ -136,7 +129,7 @@ const ScheduleDetailView: React.FC<ScheduleDetailViewProps> = ({ scheduleId, onN
setIsLoadingSchedule(true);
setScheduleError(null);
try {
const allSchedules = await listSchedules();
const allSchedules = await acpListSchedules();
const schedule = allSchedules.find((s) => s.id === sId);
if (schedule) {
setScheduleDetails(schedule);
@@ -151,22 +144,27 @@ const ScheduleDetailView: React.FC<ScheduleDetailViewProps> = ({ scheduleId, onN
}, [intl]);
useEffect(() => {
if (scheduleId && !selectedSession) {
if (scheduleId) {
fetchSessions(scheduleId);
fetchSchedule(scheduleId);
}
}, [scheduleId, selectedSession, fetchSchedule]);
}, [scheduleId, fetchSchedule]);
const openSession = useCallback((sessionId: string) => {
setView('pair', {
disableAnimation: true,
resumeSessionId: sessionId,
});
}, [setView]);
const handleRunNow = async () => {
if (!scheduleId) return;
setIsActionLoading(true);
try {
const newSessionId = await runScheduleNow(scheduleId);
const result = await acpRunScheduleNow(scheduleId);
trackScheduleRunNow(true);
if (newSessionId === 'CANCELLED') {
toastSuccess({ title: intl.formatMessage(i18n.jobCancelled), msg: intl.formatMessage(i18n.jobCancelledMsg) });
} else {
toastSuccess({ title: intl.formatMessage(i18n.scheduleTriggered), msg: intl.formatMessage(i18n.newSession, { sessionId: newSessionId }) });
if (result.status === 'completed' && result.sessionId) {
toastSuccess({ title: intl.formatMessage(i18n.scheduleCompleted), msg: intl.formatMessage(i18n.completedSession, { sessionId: result.sessionId }) });
}
await fetchSessions(scheduleId);
await fetchSchedule(scheduleId);
@@ -187,10 +185,10 @@ const ScheduleDetailView: React.FC<ScheduleDetailViewProps> = ({ scheduleId, onN
setIsActionLoading(true);
try {
if (scheduleDetails.paused) {
await unpauseSchedule(scheduleId);
await acpUnpauseSchedule(scheduleId);
toastSuccess({ title: intl.formatMessage(i18n.scheduleUnpaused), msg: intl.formatMessage(i18n.unpausedMsg, { id: scheduleId }) });
} else {
await pauseSchedule(scheduleId);
await acpPauseSchedule(scheduleId);
toastSuccess({ title: intl.formatMessage(i18n.schedulePaused), msg: intl.formatMessage(i18n.pausedMsg, { id: scheduleId }) });
}
await fetchSchedule(scheduleId);
@@ -209,7 +207,7 @@ const ScheduleDetailView: React.FC<ScheduleDetailViewProps> = ({ scheduleId, onN
if (!scheduleId) return;
setIsActionLoading(true);
try {
const result = await killRunningJob(scheduleId);
const result = await acpKillRunningJob(scheduleId);
toastSuccess({ title: intl.formatMessage(i18n.jobKilled), msg: result.message });
await fetchSchedule(scheduleId);
} catch (err) {
@@ -227,7 +225,7 @@ const ScheduleDetailView: React.FC<ScheduleDetailViewProps> = ({ scheduleId, onN
if (!scheduleId) return;
setIsActionLoading(true);
try {
const result = await inspectRunningJob(scheduleId);
const result = await acpInspectRunningJob(scheduleId);
if (result.sessionId) {
const duration = result.runningDurationSeconds
? `${Math.floor(result.runningDurationSeconds / 60)}m ${result.runningDurationSeconds % 60}s`
@@ -254,7 +252,7 @@ const ScheduleDetailView: React.FC<ScheduleDetailViewProps> = ({ scheduleId, onN
if (!scheduleId) return;
setIsActionLoading(true);
try {
await updateSchedule(scheduleId, payload as string);
await acpUpdateSchedule(scheduleId, payload as string);
toastSuccess({ title: intl.formatMessage(i18n.scheduleUpdated), msg: intl.formatMessage(i18n.updatedMsg, { id: scheduleId }) });
await fetchSchedule(scheduleId);
setIsModalOpen(false);
@@ -269,37 +267,6 @@ const ScheduleDetailView: React.FC<ScheduleDetailViewProps> = ({ scheduleId, onN
}
};
const loadSession = async (sessionId: string) => {
setIsLoadingSession(true);
setSessionError(null);
try {
const response = await getSession<true>({
path: { session_id: sessionId },
throwOnError: true,
});
setSelectedSession(response.data);
} catch (err) {
const msg = errorMessage(err, 'Failed to load session');
setSessionError(msg);
toastError({ title: intl.formatMessage(i18n.failedToLoadSession), msg });
} finally {
setIsLoadingSession(false);
}
};
if (selectedSession) {
return (
<SessionHistoryView
session={selectedSession}
isLoading={isLoadingSession}
error={sessionError}
onBack={() => setSelectedSession(null)}
onRetry={() => loadSession(selectedSession.id)}
showActionButtons={true}
/>
);
}
if (!scheduleId) {
return (
<div className="h-screen w-full flex flex-col items-center justify-center bg-white dark:bg-gray-900 text-text-primary p-8">
@@ -352,7 +319,7 @@ const ScheduleDetailView: React.FC<ScheduleDetailViewProps> = ({ scheduleId, onN
{scheduleDetails.id}
</h3>
<div className="mt-2 md:mt-0 flex items-center gap-2">
{scheduleDetails.currently_running && (
{scheduleDetails.currentlyRunning && (
<div className="text-sm text-green-500 dark:text-green-400 font-semibold flex items-center">
<span className="inline-block w-2 h-2 bg-green-500 dark:bg-green-400 rounded-full mr-1 animate-pulse"></span>
{intl.formatMessage(i18n.currentlyRunning)}
@@ -377,18 +344,18 @@ const ScheduleDetailView: React.FC<ScheduleDetailViewProps> = ({ scheduleId, onN
</p>
<p className="text-sm text-text-primary">
<span className="font-semibold">{intl.formatMessage(i18n.lastRun)}</span>{' '}
{formatToLocalDateWithTimezone(scheduleDetails.last_run)}
{formatToLocalDateWithTimezone(scheduleDetails.lastRun)}
</p>
{scheduleDetails.currently_running && scheduleDetails.current_session_id && (
{scheduleDetails.currentlyRunning && scheduleDetails.currentSessionId && (
<p className="text-sm text-text-primary">
<span className="font-semibold">{intl.formatMessage(i18n.currentSession)}</span>{' '}
{scheduleDetails.current_session_id}
{scheduleDetails.currentSessionId}
</p>
)}
{scheduleDetails.currently_running && scheduleDetails.process_start_time && (
{scheduleDetails.currentlyRunning && scheduleDetails.jobStartTime && (
<p className="text-sm text-text-primary">
<span className="font-semibold">{intl.formatMessage(i18n.processStarted)}</span>{' '}
{formatToLocalDateWithTimezone(scheduleDetails.process_start_time)}
{formatToLocalDateWithTimezone(scheduleDetails.jobStartTime)}
</p>
)}
</div>
@@ -401,13 +368,13 @@ const ScheduleDetailView: React.FC<ScheduleDetailViewProps> = ({ scheduleId, onN
<div className="flex flex-col md:flex-row gap-2">
<Button
onClick={handleRunNow}
disabled={isActionLoading || scheduleDetails?.currently_running}
disabled={isActionLoading || scheduleDetails?.currentlyRunning}
className="w-full md:w-auto"
>
{intl.formatMessage(i18n.runScheduleNow)}
</Button>
{scheduleDetails && !scheduleDetails.currently_running && (
{scheduleDetails && !scheduleDetails.currentlyRunning && (
<>
<Button
onClick={() => setIsModalOpen(true)}
@@ -443,7 +410,7 @@ const ScheduleDetailView: React.FC<ScheduleDetailViewProps> = ({ scheduleId, onN
</>
)}
{scheduleDetails?.currently_running && (
{scheduleDetails?.currentlyRunning && (
<>
<Button
onClick={handleInspect}
@@ -467,7 +434,7 @@ const ScheduleDetailView: React.FC<ScheduleDetailViewProps> = ({ scheduleId, onN
)}
</div>
{scheduleDetails?.currently_running && (
{scheduleDetails?.currentlyRunning && (
<p className="text-sm text-amber-600 dark:text-amber-400 mt-2">
{intl.formatMessage(i18n.cannotModifyRunning)}
</p>
@@ -496,45 +463,46 @@ const ScheduleDetailView: React.FC<ScheduleDetailViewProps> = ({ scheduleId, onN
{sessions.length > 0 && (
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{sessions.map((session) => (
<Card
key={session.id}
className="p-4 bg-background-primary shadow cursor-pointer hover:shadow-lg transition-shadow duration-200"
onClick={() => loadSession(session.id)}
>
<h3
className="text-sm font-semibold text-text-primary truncate"
title={session.name || session.id}
{sessions.map((session) => {
const sessionId = String(session.sessionId);
const sessionName = session.title ?? sessionId;
const createdAt = metaString(session, 'createdAt') ?? session.updatedAt;
const messageCount = metaNumber(session, 'messageCount');
return (
<Card
key={sessionId}
className="p-4 bg-background-primary shadow cursor-pointer hover:shadow-lg transition-shadow duration-200"
onClick={() => openSession(sessionId)}
>
{session.name || intl.formatMessage(i18n.sessionId, { id: session.id })}
</h3>
<p className="text-xs text-text-secondary mt-1">
{intl.formatMessage(i18n.created, { date: session.createdAt ? formatToLocalDateWithTimezone(session.createdAt) : 'N/A' })}
</p>
{session.messageCount !== undefined && (
<p className="text-xs text-text-secondary mt-1">
{intl.formatMessage(i18n.messages, { count: session.messageCount })}
</p>
)}
{session.workingDir && (
<p
className="text-xs text-text-secondary mt-1 truncate"
title={session.workingDir}
<h3
className="text-sm font-semibold text-text-primary truncate"
title={sessionName}
>
{intl.formatMessage(i18n.dir, { path: session.workingDir })}
{sessionName || intl.formatMessage(i18n.sessionId, { id: sessionId })}
</h3>
<p className="text-xs text-text-secondary mt-1">
{intl.formatMessage(i18n.created, { date: createdAt ? formatToLocalDateWithTimezone(createdAt) : 'N/A' })}
</p>
)}
{session.accumulatedTotalTokens !== undefined &&
session.accumulatedTotalTokens !== null && (
{messageCount !== undefined && (
<p className="text-xs text-text-secondary mt-1">
{intl.formatMessage(i18n.tokens, { count: session.accumulatedTotalTokens })}
{intl.formatMessage(i18n.messages, { count: messageCount })}
</p>
)}
<p className="text-xs text-text-secondary mt-1">
{intl.formatMessage(i18n.idLabel)} <span className="font-mono">{session.id}</span>
</p>
</Card>
))}
{session.cwd && (
<p
className="text-xs text-text-secondary mt-1 truncate"
title={session.cwd}
>
{intl.formatMessage(i18n.dir, { path: session.cwd })}
</p>
)}
<p className="text-xs text-text-secondary mt-1">
{intl.formatMessage(i18n.idLabel)} <span className="font-mono">{sessionId}</span>
</p>
</Card>
);
})}
</div>
)}
</section>
@@ -1,8 +1,8 @@
import React, { useState, useEffect, FormEvent, useCallback } from 'react';
import type { ScheduledJobDto } from '@aaif/goose-sdk';
import { Card } from '../ui/card';
import { Button } from '../ui/button';
import { Input } from '../ui/input';
import { ScheduledJob } from '../../schedule';
import { CronPicker } from './CronPicker';
import { Recipe, parseDeeplink, parseRecipeFromFile } from '../../recipe';
import { getStorageDirectory } from '../../recipe/recipe_management';
@@ -47,7 +47,7 @@ interface ScheduleModalProps {
isOpen: boolean;
onClose: () => void;
onSubmit: (payload: NewSchedulePayload | string) => Promise<void>;
schedule: ScheduledJob | null;
schedule: ScheduledJobDto | null;
isLoadingExternally: boolean;
apiErrorExternally: string | null;
initialDeepLink: string | null;
@@ -1,16 +1,16 @@
import React, { useState, useEffect } from 'react';
import { useLocation } from 'react-router-dom';
import type { ScheduledJobDto } from '@aaif/goose-sdk';
import {
listSchedules,
createSchedule,
deleteSchedule,
pauseSchedule,
unpauseSchedule,
updateSchedule,
killRunningJob,
inspectRunningJob,
ScheduledJob,
} from '../../schedule';
acpListSchedules,
acpCreateSchedule,
acpDeleteSchedule,
acpPauseSchedule,
acpUnpauseSchedule,
acpUpdateSchedule,
acpKillRunningJob,
acpInspectRunningJob,
} from '../../acp/schedules';
import { ScrollArea } from '../ui/scroll-area';
import { Card } from '../ui/card';
import { Button } from '../ui/button';
@@ -67,9 +67,9 @@ interface SchedulesViewProps {
}
const ScheduleCard: React.FC<{
job: ScheduledJob;
job: ScheduledJobDto;
onNavigateToDetail: (id: string) => void;
onEdit: (job: ScheduledJob) => void;
onEdit: (job: ScheduledJobDto) => void;
onPause: (id: string) => void;
onUnpause: (id: string) => void;
onKill: (id: string) => void;
@@ -95,7 +95,7 @@ const ScheduleCard: React.FC<{
readableCron = job.cron;
}
const formattedLastRun = formatToLocalDateWithTimezone(job.last_run);
const formattedLastRun = formatToLocalDateWithTimezone(job.lastRun);
return (
<Card
@@ -108,7 +108,7 @@ const ScheduleCard: React.FC<{
<h3 className="text-base truncate max-w-[50vw]" title={job.id}>
{job.id}
</h3>
{job.currently_running && (
{job.currentlyRunning && (
<span className="inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium bg-green-100 text-green-800 dark:bg-green-900/30 dark:text-green-300">
<span className="inline-block w-2 h-2 bg-green-500 rounded-full mr-1 animate-pulse"></span>
{intl.formatMessage(i18n.running)}
@@ -130,7 +130,7 @@ const ScheduleCard: React.FC<{
</div>
<div className="flex items-center gap-2 shrink-0">
{!job.currently_running && (
{!job.currentlyRunning && (
<>
<Button
onClick={(e) => {
@@ -173,7 +173,7 @@ const ScheduleCard: React.FC<{
</Button>
</>
)}
{job.currently_running && (
{job.currentlyRunning && (
<>
<Button
onClick={(e) => {
@@ -224,13 +224,13 @@ const ScheduleCard: React.FC<{
const SchedulesView: React.FC<SchedulesViewProps> = ({ onClose: _onClose }) => {
const intl = useIntl();
const location = useLocation();
const [schedules, setSchedules] = useState<ScheduledJob[]>([]);
const [schedules, setSchedules] = useState<ScheduledJobDto[]>([]);
const [isLoading, setIsLoading] = useState(false);
const [isSubmitting, setIsSubmitting] = useState(false);
const [apiError, setApiError] = useState<string | null>(null);
const [submitApiError, setSubmitApiError] = useState<string | null>(null);
const [isModalOpen, setIsModalOpen] = useState(false);
const [editingSchedule, setEditingSchedule] = useState<ScheduledJob | null>(null);
const [editingSchedule, setEditingSchedule] = useState<ScheduledJobDto | null>(null);
const [isRefreshing, setIsRefreshing] = useState(false);
const [pendingDeepLink, setPendingDeepLink] = useState<string | null>(null);
const [actionsInProgress, setActionsInProgress] = useState<Set<string>>(new Set());
@@ -240,7 +240,7 @@ const SchedulesView: React.FC<SchedulesViewProps> = ({ onClose: _onClose }) => {
setIsLoading(true);
setApiError(null);
try {
const fetchedSchedules = await listSchedules();
const fetchedSchedules = await acpListSchedules();
setSchedules(fetchedSchedules);
} catch (error) {
console.error('Failed to fetch schedules:', error);
@@ -289,14 +289,14 @@ const SchedulesView: React.FC<SchedulesViewProps> = ({ onClose: _onClose }) => {
setSubmitApiError(null);
try {
if (editingSchedule) {
await updateSchedule(editingSchedule.id, payload as string);
await acpUpdateSchedule(editingSchedule.id, payload as string);
toastSuccess({
title: intl.formatMessage(i18n.scheduleUpdated),
msg: intl.formatMessage(i18n.scheduleUpdatedMsg, { id: editingSchedule.id }),
});
} else {
const newPayload = payload as NewSchedulePayload;
await createSchedule(newPayload);
await acpCreateSchedule(newPayload);
const sourceType = pendingDeepLink ? 'deeplink' : 'file';
trackScheduleCreated(sourceType, true);
}
@@ -325,7 +325,7 @@ const SchedulesView: React.FC<SchedulesViewProps> = ({ onClose: _onClose }) => {
setApiError(null);
try {
await deleteSchedule(id);
await acpDeleteSchedule(id);
trackScheduleDeleted(true);
await fetchSchedules();
} catch (error) {
@@ -347,7 +347,7 @@ const SchedulesView: React.FC<SchedulesViewProps> = ({ onClose: _onClose }) => {
setApiError(null);
try {
await pauseSchedule(id);
await acpPauseSchedule(id);
toastSuccess({
title: intl.formatMessage(i18n.schedulePaused),
msg: intl.formatMessage(i18n.schedulePausedMsg, { id }),
@@ -375,7 +375,7 @@ const SchedulesView: React.FC<SchedulesViewProps> = ({ onClose: _onClose }) => {
setApiError(null);
try {
await unpauseSchedule(id);
await acpUnpauseSchedule(id);
toastSuccess({
title: intl.formatMessage(i18n.scheduleUnpaused),
msg: intl.formatMessage(i18n.scheduleUnpausedMsg, { id }),
@@ -403,7 +403,7 @@ const SchedulesView: React.FC<SchedulesViewProps> = ({ onClose: _onClose }) => {
setApiError(null);
try {
const result = await killRunningJob(id);
const result = await acpKillRunningJob(id);
toastSuccess({
title: intl.formatMessage(i18n.jobKilled),
msg: result.message,
@@ -431,7 +431,7 @@ const SchedulesView: React.FC<SchedulesViewProps> = ({ onClose: _onClose }) => {
setApiError(null);
try {
const result = await inspectRunningJob(id);
const result = await acpInspectRunningJob(id);
if (result.sessionId) {
const duration = result.runningDurationSeconds
? `${Math.floor(result.runningDurationSeconds / 60)}m ${result.runningDurationSeconds % 60}s`
@@ -1,9 +1,9 @@
import { render, screen, type RenderOptions, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { describe, expect, it, vi } from 'vitest';
import type { ScheduledJobDto } from '@aaif/goose-sdk';
import { IntlTestWrapper } from '../../../i18n/test-utils';
import { CronPicker } from '../CronPicker';
import type { ScheduledJob } from '../../../schedule';
const renderWithIntl = (ui: React.ReactElement, options?: RenderOptions) =>
render(ui, { wrapper: IntlTestWrapper, ...options });
@@ -13,10 +13,12 @@ const getLastCron = (onChange: ReturnType<typeof vi.fn>) => {
return calls[calls.length - 1]?.[0];
};
const scheduledJob = (cron: string): ScheduledJob => ({
const scheduledJob = (cron: string): ScheduledJobDto => ({
id: 'quarterly-report',
source: 'dummy.yaml',
cron,
currentlyRunning: false,
paused: false,
});
describe('CronPicker', () => {
+6 -12
View File
@@ -3296,6 +3296,9 @@
"scheduleDetailView.cannotModifyRunning": {
"defaultMessage": "Cannot trigger or modify a schedule while it's already running."
},
"scheduleDetailView.completedSession": {
"defaultMessage": "Session: {sessionId}"
},
"scheduleDetailView.created": {
"defaultMessage": "Created: {date}"
},
@@ -3317,9 +3320,6 @@
"scheduleDetailView.errorPrefix": {
"defaultMessage": "Error: {error}"
},
"scheduleDetailView.failedToLoadSession": {
"defaultMessage": "Failed to load session"
},
"scheduleDetailView.idLabel": {
"defaultMessage": "ID:"
},
@@ -3362,9 +3362,6 @@
"scheduleDetailView.messages": {
"defaultMessage": "Messages: {count}"
},
"scheduleDetailView.newSession": {
"defaultMessage": "New session: {sessionId}"
},
"scheduleDetailView.noScheduleId": {
"defaultMessage": "No schedule ID provided. Return to schedules list."
},
@@ -3401,6 +3398,9 @@
"scheduleDetailView.runScheduleNow": {
"defaultMessage": "Run Schedule Now"
},
"scheduleDetailView.scheduleCompleted": {
"defaultMessage": "Run completed"
},
"scheduleDetailView.scheduleDetails": {
"defaultMessage": "Schedule Details"
},
@@ -3419,9 +3419,6 @@
"scheduleDetailView.schedulePaused": {
"defaultMessage": "Schedule Paused"
},
"scheduleDetailView.scheduleTriggered": {
"defaultMessage": "Schedule Triggered"
},
"scheduleDetailView.scheduleUnpaused": {
"defaultMessage": "Schedule Unpaused"
},
@@ -3431,9 +3428,6 @@
"scheduleDetailView.sessionId": {
"defaultMessage": "Session ID: {id}"
},
"scheduleDetailView.tokens": {
"defaultMessage": "Tokens: {count}"
},
"scheduleDetailView.unpauseSchedule": {
"defaultMessage": "Unpause Schedule"
},
+6 -12
View File
@@ -3296,6 +3296,9 @@
"scheduleDetailView.cannotModifyRunning": {
"defaultMessage": "No se puede activar ni modificar una programación mientras se está ejecutando."
},
"scheduleDetailView.completedSession": {
"defaultMessage": "Sesión: {sessionId}"
},
"scheduleDetailView.created": {
"defaultMessage": "Creada: {date}"
},
@@ -3317,9 +3320,6 @@
"scheduleDetailView.errorPrefix": {
"defaultMessage": "Error: {error}"
},
"scheduleDetailView.failedToLoadSession": {
"defaultMessage": "No se pudo cargar la sesión"
},
"scheduleDetailView.idLabel": {
"defaultMessage": "ID:"
},
@@ -3362,9 +3362,6 @@
"scheduleDetailView.messages": {
"defaultMessage": "Mensajes: {count}"
},
"scheduleDetailView.newSession": {
"defaultMessage": "Nueva sesión: {sessionId}"
},
"scheduleDetailView.noScheduleId": {
"defaultMessage": "No se proporcionó ningún ID de programación. Vuelve a la lista de programaciones."
},
@@ -3401,6 +3398,9 @@
"scheduleDetailView.runScheduleNow": {
"defaultMessage": "Ejecutar programación ahora"
},
"scheduleDetailView.scheduleCompleted": {
"defaultMessage": "Ejecución completada"
},
"scheduleDetailView.scheduleDetails": {
"defaultMessage": "Detalles de la programación"
},
@@ -3419,9 +3419,6 @@
"scheduleDetailView.schedulePaused": {
"defaultMessage": "Programación en pausa"
},
"scheduleDetailView.scheduleTriggered": {
"defaultMessage": "Programación activada"
},
"scheduleDetailView.scheduleUnpaused": {
"defaultMessage": "Programación reanudada"
},
@@ -3431,9 +3428,6 @@
"scheduleDetailView.sessionId": {
"defaultMessage": "ID de sesión: {id}"
},
"scheduleDetailView.tokens": {
"defaultMessage": "Tokens: {count}"
},
"scheduleDetailView.unpauseSchedule": {
"defaultMessage": "Reanudar programación"
},
+6 -12
View File
@@ -3296,6 +3296,9 @@
"scheduleDetailView.cannotModifyRunning": {
"defaultMessage": "जब कोई शेड्यूल पहले से चल रहा हो तो उसे ट्रिगर या संशोधित नहीं किया जा सकता।"
},
"scheduleDetailView.completedSession": {
"defaultMessage": "सत्र: {sessionId}"
},
"scheduleDetailView.created": {
"defaultMessage": "बनाया गया: {date}"
},
@@ -3317,9 +3320,6 @@
"scheduleDetailView.errorPrefix": {
"defaultMessage": "त्रुटि: {error}"
},
"scheduleDetailView.failedToLoadSession": {
"defaultMessage": "सत्र लोड करने में विफल"
},
"scheduleDetailView.idLabel": {
"defaultMessage": "आईडी:"
},
@@ -3362,9 +3362,6 @@
"scheduleDetailView.messages": {
"defaultMessage": "संदेश: {count}"
},
"scheduleDetailView.newSession": {
"defaultMessage": "नया सत्र: {sessionId}"
},
"scheduleDetailView.noScheduleId": {
"defaultMessage": "कोई शेड्यूल आईडी प्रदान नहीं की गई. शेड्यूल सूची पर लौटें."
},
@@ -3401,6 +3398,9 @@
"scheduleDetailView.runScheduleNow": {
"defaultMessage": "अभी शेड्यूल चलाएँ"
},
"scheduleDetailView.scheduleCompleted": {
"defaultMessage": "रन पूरा हुआ"
},
"scheduleDetailView.scheduleDetails": {
"defaultMessage": "अनुसूची विवरण"
},
@@ -3419,9 +3419,6 @@
"scheduleDetailView.schedulePaused": {
"defaultMessage": "शेड्यूल रोका गया"
},
"scheduleDetailView.scheduleTriggered": {
"defaultMessage": "शेड्यूल ट्रिगर हुआ"
},
"scheduleDetailView.scheduleUnpaused": {
"defaultMessage": "शेड्यूल अनरोका"
},
@@ -3431,9 +3428,6 @@
"scheduleDetailView.sessionId": {
"defaultMessage": "सत्र आईडी: {id}"
},
"scheduleDetailView.tokens": {
"defaultMessage": "टोकन: {count}"
},
"scheduleDetailView.unpauseSchedule": {
"defaultMessage": "शेड्यूल को फिर से रोकें"
},
+6 -12
View File
@@ -3296,6 +3296,9 @@
"scheduleDetailView.cannotModifyRunning": {
"defaultMessage": "既に実行中のため、スケジュールを実行または変更できません。"
},
"scheduleDetailView.completedSession": {
"defaultMessage": "セッション: {sessionId}"
},
"scheduleDetailView.created": {
"defaultMessage": "作成: {date}"
},
@@ -3317,9 +3320,6 @@
"scheduleDetailView.errorPrefix": {
"defaultMessage": "エラー: {error}"
},
"scheduleDetailView.failedToLoadSession": {
"defaultMessage": "セッションの読み込みに失敗しました"
},
"scheduleDetailView.idLabel": {
"defaultMessage": "ID:"
},
@@ -3362,9 +3362,6 @@
"scheduleDetailView.messages": {
"defaultMessage": "メッセージ: {count}"
},
"scheduleDetailView.newSession": {
"defaultMessage": "新しいセッション: {sessionId}"
},
"scheduleDetailView.noScheduleId": {
"defaultMessage": "スケジュールIDが指定されていません。スケジュール一覧に戻ってください。"
},
@@ -3401,6 +3398,9 @@
"scheduleDetailView.runScheduleNow": {
"defaultMessage": "スケジュールを今すぐ実行"
},
"scheduleDetailView.scheduleCompleted": {
"defaultMessage": "実行が完了しました"
},
"scheduleDetailView.scheduleDetails": {
"defaultMessage": "スケジュール詳細"
},
@@ -3419,9 +3419,6 @@
"scheduleDetailView.schedulePaused": {
"defaultMessage": "スケジュールを一時停止しました"
},
"scheduleDetailView.scheduleTriggered": {
"defaultMessage": "スケジュールを実行しました"
},
"scheduleDetailView.scheduleUnpaused": {
"defaultMessage": "スケジュールを再開しました"
},
@@ -3431,9 +3428,6 @@
"scheduleDetailView.sessionId": {
"defaultMessage": "セッションID: {id}"
},
"scheduleDetailView.tokens": {
"defaultMessage": "トークン: {count}"
},
"scheduleDetailView.unpauseSchedule": {
"defaultMessage": "スケジュールを再開"
},
+6 -12
View File
@@ -3296,6 +3296,9 @@
"scheduleDetailView.cannotModifyRunning": {
"defaultMessage": "이미 실행 중인 일정은 트리거하거나 수정할 수 없습니다."
},
"scheduleDetailView.completedSession": {
"defaultMessage": "세션: {sessionId}"
},
"scheduleDetailView.created": {
"defaultMessage": "생성일: {date}"
},
@@ -3317,9 +3320,6 @@
"scheduleDetailView.errorPrefix": {
"defaultMessage": "오류: {error}"
},
"scheduleDetailView.failedToLoadSession": {
"defaultMessage": "세션을 로드하지 못했습니다."
},
"scheduleDetailView.idLabel": {
"defaultMessage": "ID:"
},
@@ -3362,9 +3362,6 @@
"scheduleDetailView.messages": {
"defaultMessage": "메시지: {count}"
},
"scheduleDetailView.newSession": {
"defaultMessage": "새 세션: {sessionId}"
},
"scheduleDetailView.noScheduleId": {
"defaultMessage": "제공된 일정 ID가 없습니다. 일정 목록으로 돌아갑니다."
},
@@ -3401,6 +3398,9 @@
"scheduleDetailView.runScheduleNow": {
"defaultMessage": "지금 일정 실행"
},
"scheduleDetailView.scheduleCompleted": {
"defaultMessage": "실행 완료"
},
"scheduleDetailView.scheduleDetails": {
"defaultMessage": "일정 세부정보"
},
@@ -3419,9 +3419,6 @@
"scheduleDetailView.schedulePaused": {
"defaultMessage": "일정이 일시 중지됨"
},
"scheduleDetailView.scheduleTriggered": {
"defaultMessage": "일정이 실행됨"
},
"scheduleDetailView.scheduleUnpaused": {
"defaultMessage": "일정 일시중지 해제됨"
},
@@ -3431,9 +3428,6 @@
"scheduleDetailView.sessionId": {
"defaultMessage": "세션 ID: {id}"
},
"scheduleDetailView.tokens": {
"defaultMessage": "토큰: {count}"
},
"scheduleDetailView.unpauseSchedule": {
"defaultMessage": "일정 일시중지 해제"
},
+6 -12
View File
@@ -3296,6 +3296,9 @@
"scheduleDetailView.cannotModifyRunning": {
"defaultMessage": "Нельзя запускать или изменять расписание, пока оно выполняется."
},
"scheduleDetailView.completedSession": {
"defaultMessage": "Сеанс: {sessionId}"
},
"scheduleDetailView.created": {
"defaultMessage": "Создано: {date}"
},
@@ -3317,9 +3320,6 @@
"scheduleDetailView.errorPrefix": {
"defaultMessage": "Ошибка: {error}"
},
"scheduleDetailView.failedToLoadSession": {
"defaultMessage": "Не удалось загрузить сеанс"
},
"scheduleDetailView.idLabel": {
"defaultMessage": "ID:"
},
@@ -3362,9 +3362,6 @@
"scheduleDetailView.messages": {
"defaultMessage": "Сообщений: {count}"
},
"scheduleDetailView.newSession": {
"defaultMessage": "Новый сеанс: {sessionId}"
},
"scheduleDetailView.noScheduleId": {
"defaultMessage": "ID расписания не указан. Вернитесь к списку расписаний."
},
@@ -3401,6 +3398,9 @@
"scheduleDetailView.runScheduleNow": {
"defaultMessage": "Запустить расписание сейчас"
},
"scheduleDetailView.scheduleCompleted": {
"defaultMessage": "Запуск завершен"
},
"scheduleDetailView.scheduleDetails": {
"defaultMessage": "Детали расписания"
},
@@ -3419,9 +3419,6 @@
"scheduleDetailView.schedulePaused": {
"defaultMessage": "Расписание приостановлено"
},
"scheduleDetailView.scheduleTriggered": {
"defaultMessage": "Расписание запущено"
},
"scheduleDetailView.scheduleUnpaused": {
"defaultMessage": "Расписание возобновлено"
},
@@ -3431,9 +3428,6 @@
"scheduleDetailView.sessionId": {
"defaultMessage": "ID сеанса: {id}"
},
"scheduleDetailView.tokens": {
"defaultMessage": "Токенов: {count}"
},
"scheduleDetailView.unpauseSchedule": {
"defaultMessage": "Возобновить расписание"
},
+6 -12
View File
@@ -3296,6 +3296,9 @@
"scheduleDetailView.cannotModifyRunning": {
"defaultMessage": "Zaten çalışmakta olan bir program tetiklenemez veya değiştirilemez."
},
"scheduleDetailView.completedSession": {
"defaultMessage": "Oturum: {sessionId}"
},
"scheduleDetailView.created": {
"defaultMessage": "Oluşturuldu: {date}"
},
@@ -3317,9 +3320,6 @@
"scheduleDetailView.errorPrefix": {
"defaultMessage": "Hata: {error}"
},
"scheduleDetailView.failedToLoadSession": {
"defaultMessage": "Oturum yüklenemedi"
},
"scheduleDetailView.idLabel": {
"defaultMessage": "Kimlik:"
},
@@ -3362,9 +3362,6 @@
"scheduleDetailView.messages": {
"defaultMessage": "Mesajlar: {count}"
},
"scheduleDetailView.newSession": {
"defaultMessage": "Yeni oturum: {sessionId}"
},
"scheduleDetailView.noScheduleId": {
"defaultMessage": "Program kimliği sağlanmadı. Program listesine geri dönün."
},
@@ -3401,6 +3398,9 @@
"scheduleDetailView.runScheduleNow": {
"defaultMessage": "Şimdi Planla'yı Çalıştır"
},
"scheduleDetailView.scheduleCompleted": {
"defaultMessage": "Çalıştırma tamamlandı"
},
"scheduleDetailView.scheduleDetails": {
"defaultMessage": "Program Ayrıntıları"
},
@@ -3419,9 +3419,6 @@
"scheduleDetailView.schedulePaused": {
"defaultMessage": "Plan Duraklatıldı"
},
"scheduleDetailView.scheduleTriggered": {
"defaultMessage": "Zamanlama Tetiklendi"
},
"scheduleDetailView.scheduleUnpaused": {
"defaultMessage": "Duraklatmayı Kaldırmayı Planla"
},
@@ -3431,9 +3428,6 @@
"scheduleDetailView.sessionId": {
"defaultMessage": "Oturum Kimliği: {id}"
},
"scheduleDetailView.tokens": {
"defaultMessage": "Jetonlar: {count}"
},
"scheduleDetailView.unpauseSchedule": {
"defaultMessage": "Programı Duraklatmayı Kaldır"
},
+6 -12
View File
@@ -3296,6 +3296,9 @@
"scheduleDetailView.cannotModifyRunning": {
"defaultMessage": "计划正在运行中,无法触发或修改。"
},
"scheduleDetailView.completedSession": {
"defaultMessage": "会话:{sessionId}"
},
"scheduleDetailView.created": {
"defaultMessage": "创建于:{date}"
},
@@ -3317,9 +3320,6 @@
"scheduleDetailView.errorPrefix": {
"defaultMessage": "错误:{error}"
},
"scheduleDetailView.failedToLoadSession": {
"defaultMessage": "加载会话失败"
},
"scheduleDetailView.idLabel": {
"defaultMessage": "ID:"
},
@@ -3362,9 +3362,6 @@
"scheduleDetailView.messages": {
"defaultMessage": "消息:{count}"
},
"scheduleDetailView.newSession": {
"defaultMessage": "新会话:{sessionId}"
},
"scheduleDetailView.noScheduleId": {
"defaultMessage": "未提供计划 ID。返回计划列表。"
},
@@ -3401,6 +3398,9 @@
"scheduleDetailView.runScheduleNow": {
"defaultMessage": "立即运行计划"
},
"scheduleDetailView.scheduleCompleted": {
"defaultMessage": "运行已完成"
},
"scheduleDetailView.scheduleDetails": {
"defaultMessage": "计划详情"
},
@@ -3419,9 +3419,6 @@
"scheduleDetailView.schedulePaused": {
"defaultMessage": "计划已暂停"
},
"scheduleDetailView.scheduleTriggered": {
"defaultMessage": "计划已触发"
},
"scheduleDetailView.scheduleUnpaused": {
"defaultMessage": "计划已恢复"
},
@@ -3431,9 +3428,6 @@
"scheduleDetailView.sessionId": {
"defaultMessage": "会话 ID:{id}"
},
"scheduleDetailView.tokens": {
"defaultMessage": "令牌:{count}"
},
"scheduleDetailView.unpauseSchedule": {
"defaultMessage": "恢复计划"
},
-191
View File
@@ -1,191 +0,0 @@
import {
listSchedules as apiListSchedules,
createSchedule as apiCreateSchedule,
deleteSchedule as apiDeleteSchedule,
pauseSchedule as apiPauseSchedule,
unpauseSchedule as apiUnpauseSchedule,
updateSchedule as apiUpdateSchedule,
sessionsHandler as apiGetScheduleSessions,
runNowHandler as apiRunScheduleNow,
killRunningJob as apiKillRunningJob,
inspectRunningJob as apiInspectRunningJob,
SessionDisplayInfo,
} from './api';
import type { Recipe } from './recipe';
export interface ScheduledJob {
id: string;
source: string;
cron: string;
last_run?: string | null;
currently_running?: boolean;
paused?: boolean;
current_session_id?: string | null;
process_start_time?: string | null;
}
export interface ScheduleSession {
id: string;
name: string;
createdAt: string; // ISO 8601 date string
workingDir: string;
scheduleId: string;
messageCount: number;
totalTokens: number;
inputTokens: number;
outputTokens: number;
accumulatedTotalTokens: number;
accumulatedInputTokens: number;
accumulatedOutputTokens: number;
}
export async function listSchedules(): Promise<ScheduledJob[]> {
try {
const response = await apiListSchedules<true>();
if (response && response.data && Array.isArray(response.data.jobs)) {
return response.data.jobs as ScheduledJob[];
}
console.error('Unexpected response format from apiListSchedules', response);
throw new Error('Failed to list schedules: Unexpected response format');
} catch (error) {
console.error('Error listing schedules:', error);
throw error;
}
}
export async function createSchedule(request: {
id: string;
recipe: Recipe;
cron: string;
}): Promise<ScheduledJob> {
type ApiCreateScheduleBody = Parameters<typeof apiCreateSchedule>[0]['body'];
const response = await apiCreateSchedule({ body: request as unknown as ApiCreateScheduleBody });
if (response.data) {
return response.data as ScheduledJob;
}
const err = response.error as { message?: string } | undefined;
throw new Error(err?.message || 'Failed to create schedule');
}
export async function deleteSchedule(id: string): Promise<void> {
try {
await apiDeleteSchedule<true>({ path: { id } });
} catch (error) {
console.error(`Error deleting schedule ${id}:`, error);
throw error;
}
}
export async function getScheduleSessions(
scheduleId: string,
limit: number
): Promise<Array<SessionDisplayInfo>> {
const response = await apiGetScheduleSessions<true>({
path: { id: scheduleId },
query: { limit },
throwOnError: true,
});
return response.data;
}
export async function runScheduleNow(scheduleId: string): Promise<string> {
try {
const response = await apiRunScheduleNow<true>({
path: { id: scheduleId },
});
if (response && response.data && response.data.session_id) {
return response.data.session_id;
}
console.error('Unexpected response format from apiRunScheduleNow', response);
throw new Error('Failed to run schedule now: Unexpected response format');
} catch (error) {
console.error(`Error running schedule ${scheduleId} now:`, error);
throw error;
}
}
export async function pauseSchedule(scheduleId: string): Promise<void> {
try {
await apiPauseSchedule<true>({
path: { id: scheduleId },
});
} catch (error) {
console.error(`Error pausing schedule ${scheduleId}:`, error);
throw error;
}
}
export async function unpauseSchedule(scheduleId: string): Promise<void> {
try {
await apiUnpauseSchedule<true>({
path: { id: scheduleId },
});
} catch (error) {
console.error(`Error unpausing schedule ${scheduleId}:`, error);
throw error;
}
}
export async function updateSchedule(scheduleId: string, cron: string): Promise<ScheduledJob> {
try {
const response = await apiUpdateSchedule<true>({
path: { id: scheduleId },
body: { cron },
});
if (response && response.data) {
return response.data as ScheduledJob;
}
console.error('Unexpected response format from apiUpdateSchedule', response);
throw new Error('Failed to update schedule: Unexpected response format');
} catch (error) {
console.error(`Error updating schedule ${scheduleId}:`, error);
throw error;
}
}
export interface KillJobResponse {
message: string;
}
export interface InspectJobResponse {
sessionId?: string | null;
processStartTime?: string | null;
runningDurationSeconds?: number | null;
}
export async function killRunningJob(scheduleId: string): Promise<KillJobResponse> {
try {
const response = await apiKillRunningJob<true>({
path: { id: scheduleId },
});
if (response && response.data) {
return response.data as KillJobResponse;
}
console.error('Unexpected response format from apiKillRunningJob', response);
throw new Error('Failed to kill running job: Unexpected response format');
} catch (error) {
console.error(`Error killing running job ${scheduleId}:`, error);
throw error;
}
}
export async function inspectRunningJob(scheduleId: string): Promise<InspectJobResponse> {
try {
const response = await apiInspectRunningJob<true>({
path: { id: scheduleId },
});
if (response && response.data) {
return response.data as InspectJobResponse;
}
console.error('Unexpected response format from apiInspectRunningJob', response);
throw new Error('Failed to inspect running job: Unexpected response format');
} catch (error) {
console.error(`Error inspecting running job ${scheduleId}:`, error);
throw error;
}
}
+126
View File
@@ -12,6 +12,8 @@ import type {
AddConfigExtensionRequest_unstable,
AddSessionExtensionRequest_unstable,
ArchiveSessionRequest_unstable,
CreateScheduleRequest_unstable,
CreateScheduleResponse_unstable,
CreateSourceRequest_unstable,
CreateSourceResponse_unstable,
CustomProviderCreateRequest_unstable,
@@ -28,6 +30,7 @@ import type {
DefaultsReadResponse_unstable,
DefaultsSaveRequest_unstable,
DeleteRecipeRequest_unstable,
DeleteScheduleRequest_unstable,
DeleteSessionRequest,
DeleteSourceRequest_unstable,
DiagnosticsGetRequest_unstable,
@@ -69,12 +72,20 @@ import type {
ImportSessionResponse_unstable,
ImportSourcesRequest_unstable,
ImportSourcesResponse_unstable,
InspectRunningJobRequest_unstable,
InspectRunningJobResponse_unstable,
KillRunningJobRequest_unstable,
KillRunningJobResponse_unstable,
ListAgentMentionsRequest_unstable,
ListAgentMentionsResponse_unstable,
ListProvidersRequest_unstable,
ListProvidersResponse_unstable,
ListRecipesRequest_unstable,
ListRecipesResponse_unstable,
ListScheduleSessionsRequest_unstable,
ListScheduleSessionsResponse_unstable,
ListSchedulesRequest_unstable,
ListSchedulesResponse_unstable,
ListSlashCommandsRequest_unstable,
ListSlashCommandsResponse_unstable,
ListSourcesRequest_unstable,
@@ -85,6 +96,7 @@ import type {
OnboardingImportScanResponse_unstable,
ParseRecipeRequest_unstable,
ParseRecipeResponse_unstable,
PauseScheduleRequest_unstable,
PreferencesReadRequest_unstable,
PreferencesReadResponse_unstable,
PreferencesRemoveRequest_unstable,
@@ -116,6 +128,8 @@ import type {
RemoveSessionExtensionRequest_unstable,
RenameSessionRequest_unstable,
RequestRecipeParams_unstable,
RunScheduleNowRequest_unstable,
RunScheduleNowResponse_unstable,
SaveRecipeRequest_unstable,
SaveRecipeResponse_unstable,
ScanRecipeRequest_unstable,
@@ -128,12 +142,16 @@ import type {
SteerSessionResponse_unstable,
TruncateSessionConversationRequest_unstable,
UnarchiveSessionRequest_unstable,
UnpauseScheduleRequest_unstable,
UpdateScheduleRequest_unstable,
UpdateScheduleResponse_unstable,
UpdateSessionProjectRequest_unstable,
UpdateSourceRequest_unstable,
UpdateSourceResponse_unstable,
UpdateWorkingDirRequest_unstable,
} from './types.gen.js';
import {
zCreateScheduleResponse_unstable,
zCreateSourceResponse_unstable,
zCustomProviderCreateResponse_unstable,
zCustomProviderDeleteResponse_unstable,
@@ -158,9 +176,13 @@ import {
zGooseToolCallResponse_unstable,
zImportSessionResponse_unstable,
zImportSourcesResponse_unstable,
zInspectRunningJobResponse_unstable,
zKillRunningJobResponse_unstable,
zListAgentMentionsResponse_unstable,
zListProvidersResponse_unstable,
zListRecipesResponse_unstable,
zListScheduleSessionsResponse_unstable,
zListSchedulesResponse_unstable,
zListSlashCommandsResponse_unstable,
zListSourcesResponse_unstable,
zOnboardingImportApplyResponse_unstable,
@@ -178,9 +200,11 @@ import {
zRecipeToYamlResponse_unstable,
zRefreshProviderInventoryResponse_unstable,
zRequestRecipeParams_unstable,
zRunScheduleNowResponse_unstable,
zSaveRecipeResponse_unstable,
zScanRecipeResponse_unstable,
zSteerSessionResponse_unstable,
zUpdateScheduleResponse_unstable,
zUpdateSourceResponse_unstable,
} from './zod.gen.js';
@@ -714,6 +738,108 @@ export class GooseExtClient {
) as RecipeToYamlResponse_unstable;
}
async schedulesList_unstable(
params: ListSchedulesRequest_unstable,
): Promise<ListSchedulesResponse_unstable> {
const raw = await this.conn.extMethod(
"_goose/unstable/schedules/list",
params,
);
return zListSchedulesResponse_unstable.parse(
raw,
) as ListSchedulesResponse_unstable;
}
async schedulesSessionsList_unstable(
params: ListScheduleSessionsRequest_unstable,
): Promise<ListScheduleSessionsResponse_unstable> {
const raw = await this.conn.extMethod(
"_goose/unstable/schedules/sessions/list",
params,
);
return zListScheduleSessionsResponse_unstable.parse(
raw,
) as ListScheduleSessionsResponse_unstable;
}
async schedulesCreate_unstable(
params: CreateScheduleRequest_unstable,
): Promise<CreateScheduleResponse_unstable> {
const raw = await this.conn.extMethod(
"_goose/unstable/schedules/create",
params,
);
return zCreateScheduleResponse_unstable.parse(
raw,
) as CreateScheduleResponse_unstable;
}
async schedulesDelete_unstable(
params: DeleteScheduleRequest_unstable,
): Promise<void> {
await this.conn.extMethod("_goose/unstable/schedules/delete", params);
}
async schedulesPause_unstable(
params: PauseScheduleRequest_unstable,
): Promise<void> {
await this.conn.extMethod("_goose/unstable/schedules/pause", params);
}
async schedulesUnpause_unstable(
params: UnpauseScheduleRequest_unstable,
): Promise<void> {
await this.conn.extMethod("_goose/unstable/schedules/unpause", params);
}
async schedulesUpdate_unstable(
params: UpdateScheduleRequest_unstable,
): Promise<UpdateScheduleResponse_unstable> {
const raw = await this.conn.extMethod(
"_goose/unstable/schedules/update",
params,
);
return zUpdateScheduleResponse_unstable.parse(
raw,
) as UpdateScheduleResponse_unstable;
}
async schedulesRunNow_unstable(
params: RunScheduleNowRequest_unstable,
): Promise<RunScheduleNowResponse_unstable> {
const raw = await this.conn.extMethod(
"_goose/unstable/schedules/run-now",
params,
);
return zRunScheduleNowResponse_unstable.parse(
raw,
) as RunScheduleNowResponse_unstable;
}
async schedulesRunningJobKill_unstable(
params: KillRunningJobRequest_unstable,
): Promise<KillRunningJobResponse_unstable> {
const raw = await this.conn.extMethod(
"_goose/unstable/schedules/running-job/kill",
params,
);
return zKillRunningJobResponse_unstable.parse(
raw,
) as KillRunningJobResponse_unstable;
}
async schedulesRunningJobInspect_unstable(
params: InspectRunningJobRequest_unstable,
): Promise<InspectRunningJobResponse_unstable> {
const raw = await this.conn.extMethod(
"_goose/unstable/schedules/running-job/inspect",
params,
);
return zInspectRunningJobResponse_unstable.parse(
raw,
) as InspectRunningJobResponse_unstable;
}
async sessionInfo_unstable(
params: GetSessionInfoRequest_unstable,
): Promise<GetSessionInfoResponse_unstable> {
File diff suppressed because one or more lines are too long
+98 -9
View File
@@ -1335,15 +1335,32 @@ export type RecipeToYamlResponse_unstable = {
yaml: string;
};
/**
* Return list-style metadata for a single session without loading the conversation.
*/
export type GetSessionInfoRequest_unstable = {
sessionId: string;
export type ListSchedulesRequest_unstable = {
[key: string]: unknown;
};
export type GetSessionInfoResponse_unstable = {
session: SessionInfo;
export type ListSchedulesResponse_unstable = {
jobs: Array<ScheduledJobDto>;
};
export type ScheduledJobDto = {
id: string;
source: string;
cron: string;
lastRun?: string | null;
currentlyRunning: boolean;
paused: boolean;
currentSessionId?: string | null;
jobStartTime?: string | null;
};
export type ListScheduleSessionsRequest_unstable = {
scheduleId: string;
limit: number;
};
export type ListScheduleSessionsResponse_unstable = {
sessions: Array<SessionInfo>;
};
/**
@@ -1398,6 +1415,78 @@ export type SessionInfo = {
*/
export type SessionId = string;
export type CreateScheduleRequest_unstable = {
id: string;
recipe: RecipeDto;
cron: string;
};
export type CreateScheduleResponse_unstable = {
job: ScheduledJobDto;
};
export type DeleteScheduleRequest_unstable = {
scheduleId: string;
};
export type PauseScheduleRequest_unstable = {
scheduleId: string;
};
export type UnpauseScheduleRequest_unstable = {
scheduleId: string;
};
export type UpdateScheduleRequest_unstable = {
scheduleId: string;
cron: string;
};
export type UpdateScheduleResponse_unstable = {
job: ScheduledJobDto;
};
export type RunScheduleNowRequest_unstable = {
scheduleId: string;
};
export type RunScheduleNowResponse_unstable = {
status: RunScheduleNowStatus;
sessionId?: string | null;
};
export type RunScheduleNowStatus = 'completed' | 'cancelled';
export type KillRunningJobRequest_unstable = {
jobId: string;
};
export type KillRunningJobResponse_unstable = {
message: string;
};
export type InspectRunningJobRequest_unstable = {
jobId: string;
};
export type InspectRunningJobResponse_unstable = {
running: boolean;
sessionId?: string | null;
jobStartTime?: string | null;
runningDurationSeconds?: number | null;
};
/**
* Return list-style metadata for a single session without loading the conversation.
*/
export type GetSessionInfoRequest_unstable = {
sessionId: string;
};
export type GetSessionInfoResponse_unstable = {
session: SessionInfo;
};
/**
* Truncate a session conversation from the given message timestamp onward.
*/
@@ -1905,14 +1994,14 @@ export type RecipeParamsAction = 'submit' | 'cancel';
export type ExtRequest = {
id: string;
method: string;
params?: AddSessionExtensionRequest_unstable | RemoveSessionExtensionRequest_unstable | GetToolsRequest_unstable | GooseToolCallRequest_unstable | ReadResourceRequest_unstable | UpdateWorkingDirRequest_unstable | SetSessionSystemPromptRequest_unstable | SteerSessionRequest_unstable | DiagnosticsGetRequest_unstable | DeleteSessionRequest | GetConfigExtensionsRequest_unstable | GetAvailableExtensionsRequest_unstable | AddConfigExtensionRequest_unstable | RemoveConfigExtensionRequest_unstable | SetConfigExtensionEnabledRequest_unstable | GetSessionExtensionsRequest_unstable | ListProvidersRequest_unstable | ProviderSupportedModelsListRequest_unstable | ProviderCatalogListRequest_unstable | ProviderSetupCatalogListRequest_unstable | ProviderCatalogTemplateRequest_unstable | CustomProviderCreateRequest_unstable | CustomProviderReadRequest_unstable | CustomProviderUpdateRequest_unstable | CustomProviderDeleteRequest_unstable | RefreshProviderInventoryRequest_unstable | ProviderConfigReadRequest_unstable | ProviderConfigStatusRequest_unstable | ProviderConfigSaveRequest_unstable | ProviderConfigDeleteRequest_unstable | ProviderConfigAuthenticateRequest_unstable | PreferencesReadRequest_unstable | PreferencesSaveRequest_unstable | PreferencesRemoveRequest_unstable | DefaultsReadRequest_unstable | DefaultsSaveRequest_unstable | OnboardingImportScanRequest_unstable | OnboardingImportApplyRequest_unstable | ExportSessionRequest_unstable | ImportSessionRequest_unstable | EncodeRecipeRequest_unstable | DecodeRecipeRequest_unstable | ScanRecipeRequest_unstable | ListRecipesRequest_unstable | DeleteRecipeRequest_unstable | ScheduleRecipeRequest_unstable | SetRecipeSlashCommandRequest_unstable | SaveRecipeRequest_unstable | ParseRecipeRequest_unstable | RecipeToYamlRequest_unstable | GetSessionInfoRequest_unstable | TruncateSessionConversationRequest_unstable | UpdateSessionProjectRequest_unstable | RenameSessionRequest_unstable | ArchiveSessionRequest_unstable | UnarchiveSessionRequest_unstable | CreateSourceRequest_unstable | ListSourcesRequest_unstable | ListAgentMentionsRequest_unstable | ListSlashCommandsRequest_unstable | UpdateSourceRequest_unstable | DeleteSourceRequest_unstable | ExportSourceRequest_unstable | ImportSourcesRequest_unstable | DictationTranscribeRequest_unstable | DictationConfigRequest_unstable | DictationSecretSaveRequest_unstable | DictationSecretDeleteRequest_unstable | DictationModelsListRequest_unstable | DictationModelDownloadRequest_unstable | DictationModelDownloadProgressRequest_unstable | DictationModelCancelRequest_unstable | DictationModelDeleteRequest_unstable | DictationModelSelectRequest_unstable | {
params?: AddSessionExtensionRequest_unstable | RemoveSessionExtensionRequest_unstable | GetToolsRequest_unstable | GooseToolCallRequest_unstable | ReadResourceRequest_unstable | UpdateWorkingDirRequest_unstable | SetSessionSystemPromptRequest_unstable | SteerSessionRequest_unstable | DiagnosticsGetRequest_unstable | DeleteSessionRequest | GetConfigExtensionsRequest_unstable | GetAvailableExtensionsRequest_unstable | AddConfigExtensionRequest_unstable | RemoveConfigExtensionRequest_unstable | SetConfigExtensionEnabledRequest_unstable | GetSessionExtensionsRequest_unstable | ListProvidersRequest_unstable | ProviderSupportedModelsListRequest_unstable | ProviderCatalogListRequest_unstable | ProviderSetupCatalogListRequest_unstable | ProviderCatalogTemplateRequest_unstable | CustomProviderCreateRequest_unstable | CustomProviderReadRequest_unstable | CustomProviderUpdateRequest_unstable | CustomProviderDeleteRequest_unstable | RefreshProviderInventoryRequest_unstable | ProviderConfigReadRequest_unstable | ProviderConfigStatusRequest_unstable | ProviderConfigSaveRequest_unstable | ProviderConfigDeleteRequest_unstable | ProviderConfigAuthenticateRequest_unstable | PreferencesReadRequest_unstable | PreferencesSaveRequest_unstable | PreferencesRemoveRequest_unstable | DefaultsReadRequest_unstable | DefaultsSaveRequest_unstable | OnboardingImportScanRequest_unstable | OnboardingImportApplyRequest_unstable | ExportSessionRequest_unstable | ImportSessionRequest_unstable | EncodeRecipeRequest_unstable | DecodeRecipeRequest_unstable | ScanRecipeRequest_unstable | ListRecipesRequest_unstable | DeleteRecipeRequest_unstable | ScheduleRecipeRequest_unstable | SetRecipeSlashCommandRequest_unstable | SaveRecipeRequest_unstable | ParseRecipeRequest_unstable | RecipeToYamlRequest_unstable | ListSchedulesRequest_unstable | ListScheduleSessionsRequest_unstable | CreateScheduleRequest_unstable | DeleteScheduleRequest_unstable | PauseScheduleRequest_unstable | UnpauseScheduleRequest_unstable | UpdateScheduleRequest_unstable | RunScheduleNowRequest_unstable | KillRunningJobRequest_unstable | InspectRunningJobRequest_unstable | GetSessionInfoRequest_unstable | TruncateSessionConversationRequest_unstable | UpdateSessionProjectRequest_unstable | RenameSessionRequest_unstable | ArchiveSessionRequest_unstable | UnarchiveSessionRequest_unstable | CreateSourceRequest_unstable | ListSourcesRequest_unstable | ListAgentMentionsRequest_unstable | ListSlashCommandsRequest_unstable | UpdateSourceRequest_unstable | DeleteSourceRequest_unstable | ExportSourceRequest_unstable | ImportSourcesRequest_unstable | DictationTranscribeRequest_unstable | DictationConfigRequest_unstable | DictationSecretSaveRequest_unstable | DictationSecretDeleteRequest_unstable | DictationModelsListRequest_unstable | DictationModelDownloadRequest_unstable | DictationModelDownloadProgressRequest_unstable | DictationModelCancelRequest_unstable | DictationModelDeleteRequest_unstable | DictationModelSelectRequest_unstable | {
[key: string]: unknown;
} | null;
};
export type ExtResponse = {
id: string;
result?: EmptyResponse | GetToolsResponse_unstable | GooseToolCallResponse_unstable | ReadResourceResponse_unstable | SteerSessionResponse_unstable | DiagnosticsGetResponse_unstable | GetConfigExtensionsResponse_unstable | GetAvailableExtensionsResponse_unstable | GetSessionExtensionsResponse_unstable | ListProvidersResponse_unstable | ProviderSupportedModelsListResponse_unstable | ProviderCatalogListResponse_unstable | ProviderSetupCatalogListResponse_unstable | ProviderCatalogTemplateResponse_unstable | CustomProviderCreateResponse_unstable | CustomProviderReadResponse_unstable | CustomProviderUpdateResponse_unstable | CustomProviderDeleteResponse_unstable | RefreshProviderInventoryResponse_unstable | ProviderConfigReadResponse_unstable | ProviderConfigStatusResponse_unstable | ProviderConfigChangeResponse_unstable | PreferencesReadResponse_unstable | DefaultsReadResponse_unstable | OnboardingImportScanResponse_unstable | OnboardingImportApplyResponse_unstable | ExportSessionResponse_unstable | ImportSessionResponse_unstable | EncodeRecipeResponse_unstable | DecodeRecipeResponse_unstable | ScanRecipeResponse_unstable | ListRecipesResponse_unstable | SaveRecipeResponse_unstable | ParseRecipeResponse_unstable | RecipeToYamlResponse_unstable | GetSessionInfoResponse_unstable | CreateSourceResponse_unstable | ListSourcesResponse_unstable | ListAgentMentionsResponse_unstable | ListSlashCommandsResponse_unstable | UpdateSourceResponse_unstable | ExportSourceResponse_unstable | ImportSourcesResponse_unstable | DictationTranscribeResponse_unstable | DictationConfigResponse_unstable | DictationModelsListResponse_unstable | DictationModelDownloadProgressResponse_unstable | unknown;
result?: EmptyResponse | GetToolsResponse_unstable | GooseToolCallResponse_unstable | ReadResourceResponse_unstable | SteerSessionResponse_unstable | DiagnosticsGetResponse_unstable | GetConfigExtensionsResponse_unstable | GetAvailableExtensionsResponse_unstable | GetSessionExtensionsResponse_unstable | ListProvidersResponse_unstable | ProviderSupportedModelsListResponse_unstable | ProviderCatalogListResponse_unstable | ProviderSetupCatalogListResponse_unstable | ProviderCatalogTemplateResponse_unstable | CustomProviderCreateResponse_unstable | CustomProviderReadResponse_unstable | CustomProviderUpdateResponse_unstable | CustomProviderDeleteResponse_unstable | RefreshProviderInventoryResponse_unstable | ProviderConfigReadResponse_unstable | ProviderConfigStatusResponse_unstable | ProviderConfigChangeResponse_unstable | PreferencesReadResponse_unstable | DefaultsReadResponse_unstable | OnboardingImportScanResponse_unstable | OnboardingImportApplyResponse_unstable | ExportSessionResponse_unstable | ImportSessionResponse_unstable | EncodeRecipeResponse_unstable | DecodeRecipeResponse_unstable | ScanRecipeResponse_unstable | ListRecipesResponse_unstable | SaveRecipeResponse_unstable | ParseRecipeResponse_unstable | RecipeToYamlResponse_unstable | ListSchedulesResponse_unstable | ListScheduleSessionsResponse_unstable | CreateScheduleResponse_unstable | UpdateScheduleResponse_unstable | RunScheduleNowResponse_unstable | KillRunningJobResponse_unstable | InspectRunningJobResponse_unstable | GetSessionInfoResponse_unstable | CreateSourceResponse_unstable | ListSourcesResponse_unstable | ListAgentMentionsResponse_unstable | ListSlashCommandsResponse_unstable | UpdateSourceResponse_unstable | ExportSourceResponse_unstable | ImportSourcesResponse_unstable | DictationTranscribeResponse_unstable | DictationConfigResponse_unstable | DictationModelsListResponse_unstable | DictationModelDownloadProgressResponse_unstable | unknown;
} | {
error: {
code: number;
+130 -5
View File
@@ -1470,11 +1470,35 @@ export const zRecipeToYamlResponse_unstable = z.object({
yaml: z.string()
});
/**
* Return list-style metadata for a single session without loading the conversation.
*/
export const zGetSessionInfoRequest_unstable = z.object({
sessionId: z.string()
export const zListSchedulesRequest_unstable = z.record(z.unknown());
export const zScheduledJobDto = z.object({
id: z.string(),
source: z.string(),
cron: z.string(),
lastRun: z.union([
z.string(),
z.null()
]).optional(),
currentlyRunning: z.boolean(),
paused: z.boolean(),
currentSessionId: z.union([
z.string(),
z.null()
]).optional(),
jobStartTime: z.union([
z.string(),
z.null()
]).optional()
});
export const zListSchedulesResponse_unstable = z.object({
jobs: z.array(zScheduledJobDto)
});
export const zListScheduleSessionsRequest_unstable = z.object({
scheduleId: z.string(),
limit: z.number().int().gte(0)
});
/**
@@ -1508,6 +1532,90 @@ export const zSessionInfo = z.object({
]).optional()
});
export const zListScheduleSessionsResponse_unstable = z.object({
sessions: z.array(zSessionInfo)
});
export const zCreateScheduleRequest_unstable = z.object({
id: z.string(),
recipe: zRecipeDto,
cron: z.string()
});
export const zCreateScheduleResponse_unstable = z.object({
job: zScheduledJobDto
});
export const zDeleteScheduleRequest_unstable = z.object({
scheduleId: z.string()
});
export const zPauseScheduleRequest_unstable = z.object({
scheduleId: z.string()
});
export const zUnpauseScheduleRequest_unstable = z.object({
scheduleId: z.string()
});
export const zUpdateScheduleRequest_unstable = z.object({
scheduleId: z.string(),
cron: z.string()
});
export const zUpdateScheduleResponse_unstable = z.object({
job: zScheduledJobDto
});
export const zRunScheduleNowRequest_unstable = z.object({
scheduleId: z.string()
});
export const zRunScheduleNowStatus = z.enum(['completed', 'cancelled']);
export const zRunScheduleNowResponse_unstable = z.object({
status: zRunScheduleNowStatus,
sessionId: z.union([
z.string(),
z.null()
]).optional()
});
export const zKillRunningJobRequest_unstable = z.object({
jobId: z.string()
});
export const zKillRunningJobResponse_unstable = z.object({
message: z.string()
});
export const zInspectRunningJobRequest_unstable = z.object({
jobId: z.string()
});
export const zInspectRunningJobResponse_unstable = z.object({
running: z.boolean(),
sessionId: z.union([
z.string(),
z.null()
]).optional(),
jobStartTime: z.union([
z.string(),
z.null()
]).optional(),
runningDurationSeconds: z.union([
z.number().int(),
z.null()
]).optional()
});
/**
* Return list-style metadata for a single session without loading the conversation.
*/
export const zGetSessionInfoRequest_unstable = z.object({
sessionId: z.string()
});
export const zGetSessionInfoResponse_unstable = z.object({
session: zSessionInfo
});
@@ -2056,6 +2164,16 @@ export const zExtRequest = z.object({
zSaveRecipeRequest_unstable,
zParseRecipeRequest_unstable,
zRecipeToYamlRequest_unstable,
zListSchedulesRequest_unstable,
zListScheduleSessionsRequest_unstable,
zCreateScheduleRequest_unstable,
zDeleteScheduleRequest_unstable,
zPauseScheduleRequest_unstable,
zUnpauseScheduleRequest_unstable,
zUpdateScheduleRequest_unstable,
zRunScheduleNowRequest_unstable,
zKillRunningJobRequest_unstable,
zInspectRunningJobRequest_unstable,
zGetSessionInfoRequest_unstable,
zTruncateSessionConversationRequest_unstable,
zUpdateSessionProjectRequest_unstable,
@@ -2128,6 +2246,13 @@ export const zExtResponse = z.union([
zSaveRecipeResponse_unstable,
zParseRecipeResponse_unstable,
zRecipeToYamlResponse_unstable,
zListSchedulesResponse_unstable,
zListScheduleSessionsResponse_unstable,
zCreateScheduleResponse_unstable,
zUpdateScheduleResponse_unstable,
zRunScheduleNowResponse_unstable,
zKillRunningJobResponse_unstable,
zInspectRunningJobResponse_unstable,
zGetSessionInfoResponse_unstable,
zCreateSourceResponse_unstable,
zListSourcesResponse_unstable,