diff --git a/hermes_cli/web_server.py b/hermes_cli/web_server.py index ed619979bfb7..df710fd2b046 100644 --- a/hermes_cli/web_server.py +++ b/hermes_cli/web_server.py @@ -7046,6 +7046,7 @@ class CronJobCreate(BaseModel): name: str = "" deliver: str = "local" skills: Optional[List[str]] = None + model: str = "" class CronJobUpdate(BaseModel): @@ -7218,6 +7219,7 @@ async def create_cron_job(body: CronJobCreate, profile: str = "default"): name=body.name, deliver=body.deliver, skills=body.skills, + model=body.model, ) except Exception as e: _log.exception("POST /api/cron/jobs failed") diff --git a/web/src/i18n/en.ts b/web/src/i18n/en.ts index 10fd8df43005..d9f9bc668cf7 100644 --- a/web/src/i18n/en.ts +++ b/web/src/i18n/en.ts @@ -230,6 +230,8 @@ export const en: Translations = { newJob: "New Cron Job", nameOptional: "Name (optional)", namePlaceholder: "e.g. Daily summary", + modelOptional: "Model (optional)", + modelPlaceholder: "e.g. moonshotai/kimi-k2.6 (leaves the gateway default if empty)", prompt: "Prompt", promptPlaceholder: "What should the agent do on each run?", schedule: "Schedule (cron expression)", diff --git a/web/src/i18n/types.ts b/web/src/i18n/types.ts index 68a5c5693772..c902b9654147 100644 --- a/web/src/i18n/types.ts +++ b/web/src/i18n/types.ts @@ -249,6 +249,8 @@ export interface Translations { newJob: string; nameOptional: string; namePlaceholder: string; + modelOptional?: string; + modelPlaceholder?: string; prompt: string; promptPlaceholder: string; schedule: string; diff --git a/web/src/lib/api.ts b/web/src/lib/api.ts index 9b5b7afc835f..2433bba1378a 100644 --- a/web/src/lib/api.ts +++ b/web/src/lib/api.ts @@ -509,7 +509,7 @@ export const api = { fetchJSON(`/api/cron/jobs?profile=${encodeURIComponent(profile)}`), getCronDeliveryTargets: () => fetchJSON<{ targets: CronDeliveryTarget[] }>("/api/cron/delivery-targets"), - createCronJob: (job: { prompt: string; schedule: string; name?: string; deliver?: string; skills?: string[] }, profile = "default") => + createCronJob: (job: { prompt: string; schedule: string; name?: string; deliver?: string; skills?: string[]; model?: string }, profile = "default") => fetchJSON(`/api/cron/jobs?profile=${encodeURIComponent(profile)}`, { method: "POST", headers: { "Content-Type": "application/json" }, @@ -519,7 +519,7 @@ export const api = { fetchJSON(`/api/cron/jobs/${encodeURIComponent(id)}/pause?profile=${encodeURIComponent(profile)}`, { method: "POST" }), updateCronJob: ( id: string, - updates: { prompt?: string; schedule?: string; name?: string; deliver?: string; skills?: string[] }, + updates: { prompt?: string; schedule?: string; name?: string; deliver?: string; skills?: string[]; model?: string | null }, profile = "default", ) => fetchJSON( @@ -1878,6 +1878,7 @@ export interface CronJob { enabled: boolean; state?: string | null; deliver?: string | null; + model?: string | null; last_run_at?: string | null; next_run_at?: string | null; last_error?: string | null; diff --git a/web/src/pages/CronPage.tsx b/web/src/pages/CronPage.tsx index d69af7cbaf88..cf9d9db2d4e4 100644 --- a/web/src/pages/CronPage.tsx +++ b/web/src/pages/CronPage.tsx @@ -211,6 +211,7 @@ export default function CronPage() { DEFAULT_SCHEDULE_STATE, ); const [name, setName] = useState(""); + const [model, setModel] = useState(""); const closeCreateModal = useCallback(() => setCreateModalOpen(false), []); const createModalRef = useModalBehavior({ open: createModalOpen, @@ -229,6 +230,7 @@ export default function CronPage() { const [editPrompt, setEditPrompt] = useState(""); const [editSchedule, setEditSchedule] = useState(""); const [editName, setEditName] = useState(""); + const [editModel, setEditModel] = useState(""); const [editDeliver, setEditDeliver] = useState("local"); const [editSkills, setEditSkills] = useState([]); const [saving, setSaving] = useState(false); @@ -251,6 +253,7 @@ export default function CronPage() { asText(job.schedule?.expr) || asText(job.schedule_display) || "", ); setEditName(getJobName(job)); + setEditModel(asText(job.model)); setEditDeliver(asText(job.deliver) || "local"); setEditSkills(Array.isArray(job.skills) ? job.skills.filter(Boolean) : []); }, []); @@ -373,6 +376,7 @@ export default function CronPage() { name: name.trim() || undefined, deliver, skills: jobSkills.length > 0 ? jobSkills : undefined, + model: model.trim() || undefined, }, createProfile, ); @@ -380,6 +384,7 @@ export default function CronPage() { setPrompt(""); setScheduleState(DEFAULT_SCHEDULE_STATE); setName(""); + setModel(""); setDeliver("local"); setJobSkills([]); setCreateModalOpen(false); @@ -407,6 +412,7 @@ export default function CronPage() { name: editName.trim(), deliver: editDeliver, skills: editSkills, + model: editModel.trim() || null, }, getJobProfile(editJob), ); @@ -610,6 +616,21 @@ export default function CronPage() { /> +
+ + setModel(e.target.value)} + /> +
+ +
+ + setEditModel(e.target.value)} + /> +
+