refactor(trigger): name CLI trigger source as local

maintainer edit: cron is also a trigger source, so keep the new CLI-delivered source explicitly named as local trigger across backend, WebUI, docs, and tests.
This commit is contained in:
chengyongru
2026-07-02 13:32:46 +08:00
committed by Xubin Ren
parent 1ed2c9a213
commit 2ebf5c4972
40 changed files with 353 additions and 253 deletions
+4 -4
View File
@@ -122,8 +122,8 @@ function formatAutomationSchedule(
})
: t("deleteConfirm.schedule.cron", { expr: job.schedule.expr });
}
if (job.schedule.kind === "external" || job.payload.kind === "external_trigger") {
return t("deleteConfirm.schedule.external", { defaultValue: "External trigger" });
if (job.schedule.kind === "local" || job.payload.kind === "local_trigger") {
return t("deleteConfirm.schedule.local", { defaultValue: "Local trigger" });
}
return t("deleteConfirm.schedule.unknown");
}
@@ -134,8 +134,8 @@ function formatAutomationNextRun(
locale: string,
): string {
if (!job.enabled) return t("deleteConfirm.next.disabled");
if (job.schedule.kind === "external" || job.payload.kind === "external_trigger") {
return t("deleteConfirm.next.external", { defaultValue: "Waiting for trigger" });
if (job.schedule.kind === "local" || job.payload.kind === "local_trigger") {
return t("deleteConfirm.next.local", { defaultValue: "Waiting for trigger" });
}
const next = job.state.next_run_at_ms;
if (!next) return t("deleteConfirm.next.none");
+6 -1
View File
@@ -167,7 +167,12 @@ export function MessageBubble({
const reasoning = message.role === "assistant" ? message.reasoning ?? "" : "";
const reasoningStreaming = !!(message.role === "assistant" && message.reasoningStreaming);
const hasReasoning = reasoning.length > 0 || reasoningStreaming;
const automationSourceLabel = message.source?.kind === "cron" || message.source?.kind === "trigger"
const automationSourceKind = message.source?.kind;
const automationSourceLabel = (
automationSourceKind === "cron"
|| automationSourceKind === "local_trigger"
|| automationSourceKind === "trigger"
)
? (message.source.label?.trim() || t("message.automationSourceFallback"))
: "";
const automationTriggeredLabel = t("message.automationTriggered");
+27 -27
View File
@@ -3756,10 +3756,10 @@ function AutomationDetailPanel({
: null;
const created = job.created_at_ms ? fmtDateTime(job.created_at_ms, locale) : null;
const updated = job.updated_at_ms ? fmtDateTime(job.updated_at_ms, locale) : null;
const externalTrigger = isExternalTriggerAutomation(job);
const localTrigger = isLocalTriggerAutomation(job);
const triggerCommand = automationTriggerCommand(job);
const message = automationDetailText(job, tx);
const messageLabel = externalTrigger
const messageLabel = localTrigger
? tx("settings.automations.fields.command", "Command")
: tx("settings.automations.fields.message", "Message");
const schedule = formatAutomationSchedule(job, locale, tx);
@@ -3807,7 +3807,7 @@ function AutomationDetailPanel({
<div className="text-[11px] font-medium leading-none text-muted-foreground/75">
{messageLabel}
</div>
{externalTrigger && triggerCommand ? (
{localTrigger && triggerCommand ? (
<Button
type="button"
variant="ghost"
@@ -3833,7 +3833,7 @@ function AutomationDetailPanel({
<div
className={cn(
"mt-3 whitespace-pre-wrap break-words text-[13px] leading-6 text-foreground/85",
externalTrigger && "font-mono text-[12.5px]",
localTrigger && "font-mono text-[12.5px]",
!messageExpanded && messageNeedsExpansion && "line-clamp-6",
)}
>
@@ -3940,8 +3940,8 @@ function AutomationActionGroup({
t(key, { defaultValue: fallback, ...(values ?? {}) });
const canManage = !job.protected;
const hasLinkedChat = Boolean(job.origin);
const externalTrigger = isExternalTriggerAutomation(job);
const canRun = canManage && hasLinkedChat && job.enabled && !job.state.pending && !externalTrigger;
const localTrigger = isLocalTriggerAutomation(job);
const canRun = canManage && hasLinkedChat && job.enabled && !job.state.pending && !localTrigger;
const toggleAction: AutomationAction = job.enabled ? "disable" : "enable";
const canToggle = canManage && (job.enabled || hasLinkedChat);
const toggleBusy = actionKey === `${toggleAction}:${job.id}`;
@@ -3963,7 +3963,7 @@ function AutomationActionGroup({
>
<Pencil className="h-4 w-4" aria-hidden />
</AppsActionButton>
{!externalTrigger ? (
{!localTrigger ? (
<AppsActionButton
ariaLabel={tx("settings.automations.runNow", "Run now")}
busy={actionKey === `run:${job.id}`}
@@ -4095,7 +4095,7 @@ function AutomationEditDialog({
const tx = (key: string, fallback: string, values?: Record<string, unknown>) =>
t(key, { defaultValue: fallback, ...(values ?? {}) });
const [draft, setDraft] = useState<AutomationEditDraft>(() => automationDraftFromJob(null));
const externalTrigger = isExternalTriggerAutomation(job);
const localTrigger = isLocalTriggerAutomation(job);
useEffect(() => {
setDraft(automationDraftFromJob(job));
@@ -4145,7 +4145,7 @@ function AutomationEditDialog({
/>
</label>
{!externalTrigger ? (
{!localTrigger ? (
<label className="block space-y-1.5">
<span className="text-[12px] font-medium text-muted-foreground">
{tx("settings.automations.fields.message", "Message")}
@@ -4158,7 +4158,7 @@ function AutomationEditDialog({
</label>
) : null}
{!externalTrigger ? (
{!localTrigger ? (
<div className="space-y-2">
<span className="text-[12px] font-medium text-muted-foreground">
{tx("settings.automations.fields.scheduleType", "Schedule type")}
@@ -4176,7 +4176,7 @@ function AutomationEditDialog({
</div>
) : null}
{!externalTrigger && draft.scheduleKind === "every" ? (
{!localTrigger && draft.scheduleKind === "every" ? (
<div className="grid gap-2 sm:grid-cols-[minmax(0,1fr)_10rem]">
<label className="block space-y-1.5">
<span className="text-[12px] font-medium text-muted-foreground">
@@ -4217,7 +4217,7 @@ function AutomationEditDialog({
</div>
) : null}
{!externalTrigger && draft.scheduleKind === "cron" ? (
{!localTrigger && draft.scheduleKind === "cron" ? (
<div className="grid gap-2 sm:grid-cols-[minmax(0,1fr)_12rem]">
<label className="block space-y-1.5">
<span className="text-[12px] font-medium text-muted-foreground">
@@ -4244,7 +4244,7 @@ function AutomationEditDialog({
</div>
) : null}
{!externalTrigger && draft.scheduleKind === "at" ? (
{!localTrigger && draft.scheduleKind === "at" ? (
<label className="block space-y-1.5">
<span className="text-[12px] font-medium text-muted-foreground">
{tx("settings.automations.fields.runAt", "Run at")}
@@ -4340,11 +4340,11 @@ function AutomationDeleteDialog({
);
}
function isExternalTriggerAutomation(job: SessionAutomationJob | null): boolean {
function isLocalTriggerAutomation(job: SessionAutomationJob | null): boolean {
if (!job) return false;
return job.kind === "external_trigger"
|| job.payload.kind === "external_trigger"
|| job.schedule.kind === "external";
return job.kind === "local_trigger"
|| job.payload.kind === "local_trigger"
|| job.schedule.kind === "local";
}
function automationTriggerCommand(job: SessionAutomationJob): string {
@@ -4355,8 +4355,8 @@ function automationSummary(
job: SessionAutomationJob,
tx: (key: string, fallback: string, values?: Record<string, unknown>) => string,
): string {
if (isExternalTriggerAutomation(job)) {
return automationTriggerCommand(job) || tx("settings.automations.externalTrigger", "External trigger");
if (isLocalTriggerAutomation(job)) {
return automationTriggerCommand(job) || tx("settings.automations.localTrigger", "Local trigger");
}
return job.payload.message || tx("settings.automations.systemTask", "System-managed automation");
}
@@ -4379,7 +4379,7 @@ function automationStatusKey(
if (job.state.pending) return "running";
if (!job.enabled) return "paused";
if (job.state.last_status === "error") return "failed";
if (isExternalTriggerAutomation(job)) return "active";
if (isLocalTriggerAutomation(job)) return "active";
if (job.delete_after_run && !job.state.next_run_at_ms && job.state.last_status === "ok") {
return "completed";
}
@@ -4443,7 +4443,7 @@ function automationEditDraftError(
tx: (key: string, fallback: string, values?: Record<string, unknown>) => string,
): string | null {
if (!draft.name.trim()) return tx("settings.automations.validation.nameRequired", "Name is required.");
if (isExternalTriggerAutomation(job)) return null;
if (isLocalTriggerAutomation(job)) return null;
if (!draft.message.trim()) {
return tx("settings.automations.validation.messageRequired", "Message is required.");
}
@@ -4473,7 +4473,7 @@ function automationUpdatePayloadFromDraft(
job: SessionAutomationJob | null,
): AutomationUpdatePayload | string {
const name = draft.name.trim();
if (isExternalTriggerAutomation(job)) {
if (isLocalTriggerAutomation(job)) {
if (!name) return "invalid";
return { name };
}
@@ -4604,7 +4604,7 @@ function automationSearchParts(
job.payload.message,
job.payload.command,
job.trigger?.command,
isExternalTriggerAutomation(job) ? "trigger external" : null,
isLocalTriggerAutomation(job) ? "trigger local" : null,
...scheduleParts,
automationStatusKey(job),
...originParts,
@@ -4794,8 +4794,8 @@ function formatAutomationSchedule(
})
: tx("settings.automations.schedule.cron", "Cron {{expr}}", { expr: job.schedule.expr });
}
if (isExternalTriggerAutomation(job)) {
return tx("settings.automations.schedule.external", "External trigger");
if (isLocalTriggerAutomation(job)) {
return tx("settings.automations.schedule.local", "Local trigger");
}
return tx("settings.automations.schedule.custom", "Custom schedule");
}
@@ -4851,8 +4851,8 @@ function formatAutomationNext(
): string {
if (!job.enabled) return tx("settings.automations.next.paused", "Paused");
if (job.state.pending) return tx("settings.automations.next.pending", "Running now");
if (isExternalTriggerAutomation(job)) {
return tx("settings.automations.next.external", "Waiting for trigger");
if (isLocalTriggerAutomation(job)) {
return tx("settings.automations.next.local", "Waiting for trigger");
}
if (!job.state.next_run_at_ms) return tx("settings.automations.next.none", "No next run");
return relativeTime(job.state.next_run_at_ms);
@@ -152,6 +152,9 @@ function AutomationRow({ job, now }: { job: SessionAutomationJob; now: number })
function formatSchedule(job: SessionAutomationJob, t: TFunction) {
const locale = currentLocale();
if (isLocalTriggerAutomation(job)) {
return t("thread.sessionInfo.schedule.local");
}
if (job.schedule.kind === "at" && job.schedule.at_ms) {
return t("thread.sessionInfo.schedule.at", { time: fmtDateTime(job.schedule.at_ms, locale) });
}
@@ -179,6 +182,9 @@ function formatNextRun(job: SessionAutomationJob, t: TFunction, now: number) {
if (job.state.pending) {
return { label: t("thread.sessionInfo.next.pending"), title: "" };
}
if (isLocalTriggerAutomation(job)) {
return { label: t("thread.sessionInfo.next.local"), title: "" };
}
const next = job.state.next_run_at_ms;
if (!next) {
return { label: t("thread.sessionInfo.next.none"), title: "" };
@@ -189,6 +195,12 @@ function formatNextRun(job: SessionAutomationJob, t: TFunction, now: number) {
};
}
function isLocalTriggerAutomation(job: SessionAutomationJob): boolean {
return job.kind === "local_trigger"
|| job.payload.kind === "local_trigger"
|| job.schedule.kind === "local";
}
function relativeTimeFrom(value: number, now: number, locale: string): string {
let delta = (value - now) / 1000;
const formatter = new Intl.RelativeTimeFormat(locale, { numeric: "auto" });
+7
View File
@@ -493,6 +493,7 @@
"emptyHint": "Create one from where it should run so nanobot keeps the right context.",
"oneShot": "One-time",
"systemTask": "System-managed automation",
"localTrigger": "Local trigger",
"labels": {
"schedule": "Schedule",
"next": "Next",
@@ -551,11 +552,13 @@
"weekdaysAt": "Weekdays at {{time}}",
"hourlyAt": "Hourly at :{{minute}}",
"hourlyWindow": "Hourly {{start}}-{{end}} at :{{minute}}",
"local": "Local trigger",
"custom": "Custom schedule"
},
"next": {
"paused": "Paused",
"pending": "Running now",
"local": "Waiting for trigger",
"none": "No next run"
},
"message": {
@@ -692,11 +695,13 @@
"every": "Every {{duration}}",
"cron": "Cron {{expr}}",
"cronWithTz": "Cron {{expr}} · {{tz}}",
"local": "Local trigger",
"unknown": "Custom schedule"
},
"next": {
"label": "Next: {{time}}",
"disabled": "Paused",
"local": "Waiting for trigger",
"none": "No next run"
}
},
@@ -791,12 +796,14 @@
"every": "Every {{duration}}",
"cron": "Cron {{expr}}",
"cronWithTz": "Cron {{expr}} · {{tz}}",
"local": "Local trigger",
"unknown": "Custom schedule"
},
"next": {
"label": "{{time}}",
"pending": "Runs shortly",
"disabled": "Paused",
"local": "Waiting for trigger",
"none": "No next run"
}
},
+7
View File
@@ -493,6 +493,7 @@
"emptyHint": "Créala desde donde debe ejecutarse para que nanobot conserve el contexto correcto.",
"oneShot": "Una vez",
"systemTask": "Automatización administrada por el sistema",
"localTrigger": "Activador local",
"labels": {
"schedule": "Programación",
"next": "Siguiente",
@@ -551,11 +552,13 @@
"weekdaysAt": "Días laborables a las {{time}}",
"hourlyAt": "Cada hora en :{{minute}}",
"hourlyWindow": "Cada hora {{start}}-{{end}} en :{{minute}}",
"local": "Activador local",
"custom": "Programación personalizada"
},
"next": {
"paused": "Pausada",
"pending": "Ejecutándose ahora",
"local": "Esperando activador",
"none": "Sin próxima ejecución"
},
"message": {
@@ -692,11 +695,13 @@
"every": "Cada {{duration}}",
"cron": "Cron {{expr}}",
"cronWithTz": "Cron {{expr}} · {{tz}}",
"local": "Activador local",
"unknown": "Programación personalizada"
},
"next": {
"label": "Siguiente: {{time}}",
"disabled": "Pausada",
"local": "Esperando activador",
"none": "Sin próxima ejecución"
}
},
@@ -791,12 +796,14 @@
"every": "Cada {{duration}}",
"cron": "Cron {{expr}}",
"cronWithTz": "Cron {{expr}} · {{tz}}",
"local": "Activador local",
"unknown": "Programación personalizada"
},
"next": {
"label": "Siguiente {{time}}",
"pending": "Se ejecutará pronto",
"disabled": "En pausa",
"local": "Esperando activador",
"none": "Sin próxima ejecución"
}
},
+7
View File
@@ -493,6 +493,7 @@
"emptyHint": "Créez-la depuis son point d'exécution pour que nanobot conserve le bon contexte.",
"oneShot": "Ponctuelle",
"systemTask": "Automatisation gérée par le système",
"localTrigger": "Déclencheur local",
"labels": {
"schedule": "Planning",
"next": "Prochaine",
@@ -551,11 +552,13 @@
"weekdaysAt": "Jours ouvrés à {{time}}",
"hourlyAt": "Toutes les heures à :{{minute}}",
"hourlyWindow": "Toutes les heures {{start}}-{{end}} à :{{minute}}",
"local": "Déclencheur local",
"custom": "Planning personnalisé"
},
"next": {
"paused": "En pause",
"pending": "En cours dexécution",
"local": "En attente du déclencheur",
"none": "Aucune prochaine exécution"
},
"message": {
@@ -692,11 +695,13 @@
"every": "Tous les {{duration}}",
"cron": "Cron {{expr}}",
"cronWithTz": "Cron {{expr}} · {{tz}}",
"local": "Déclencheur local",
"unknown": "Planification personnalisée"
},
"next": {
"label": "Prochaine exécution : {{time}}",
"disabled": "En pause",
"local": "En attente du déclencheur",
"none": "Aucune prochaine exécution"
}
},
@@ -791,12 +796,14 @@
"every": "Toutes les {{duration}}",
"cron": "Cron {{expr}}",
"cronWithTz": "Cron {{expr}} · {{tz}}",
"local": "Déclencheur local",
"unknown": "Planification personnalisée"
},
"next": {
"label": "Prochaine {{time}}",
"pending": "Exécution imminente",
"disabled": "En pause",
"local": "En attente du déclencheur",
"none": "Aucune prochaine exécution"
}
},
+7
View File
@@ -493,6 +493,7 @@
"emptyHint": "Buat dari tempat tugas ini berjalan agar nanobot menyimpan konteks yang tepat.",
"oneShot": "Satu kali",
"systemTask": "Automasi yang dikelola sistem",
"localTrigger": "Pemicu lokal",
"labels": {
"schedule": "Jadwal",
"next": "Berikutnya",
@@ -551,11 +552,13 @@
"weekdaysAt": "Hari kerja pukul {{time}}",
"hourlyAt": "Setiap jam pada :{{minute}}",
"hourlyWindow": "Setiap jam {{start}}-{{end}} pada :{{minute}}",
"local": "Pemicu lokal",
"custom": "Jadwal khusus"
},
"next": {
"paused": "Dijeda",
"pending": "Sedang berjalan",
"local": "Menunggu pemicu",
"none": "Tidak ada jadwal berikutnya"
},
"message": {
@@ -692,11 +695,13 @@
"every": "Setiap {{duration}}",
"cron": "Cron {{expr}}",
"cronWithTz": "Cron {{expr}} · {{tz}}",
"local": "Pemicu lokal",
"unknown": "Jadwal khusus"
},
"next": {
"label": "Berikutnya: {{time}}",
"disabled": "Dijeda",
"local": "Menunggu pemicu",
"none": "Tidak ada jadwal berikutnya"
}
},
@@ -791,12 +796,14 @@
"every": "Setiap {{duration}}",
"cron": "Cron {{expr}}",
"cronWithTz": "Cron {{expr}} · {{tz}}",
"local": "Pemicu lokal",
"unknown": "Jadwal khusus"
},
"next": {
"label": "Berikutnya {{time}}",
"pending": "Segera berjalan",
"disabled": "Dijeda",
"local": "Menunggu pemicu",
"none": "Tidak ada jadwal berikutnya"
}
},
+7
View File
@@ -493,6 +493,7 @@
"emptyHint": "実行元から作成すると、nanobot が正しいコンテキストを保持できます。",
"oneShot": "一回限り",
"systemTask": "システム管理の自動タスク",
"localTrigger": "ローカルトリガー",
"labels": {
"schedule": "スケジュール",
"next": "次回",
@@ -551,11 +552,13 @@
"weekdaysAt": "平日 {{time}}",
"hourlyAt": "毎時 :{{minute}}",
"hourlyWindow": "{{start}}-{{end}} の毎時 :{{minute}}",
"local": "ローカルトリガー",
"custom": "カスタムスケジュール"
},
"next": {
"paused": "一時停止",
"pending": "実行中",
"local": "トリガー待ち",
"none": "次回実行なし"
},
"message": {
@@ -692,11 +695,13 @@
"every": "{{duration}} ごと",
"cron": "Cron {{expr}}",
"cronWithTz": "Cron {{expr}} · {{tz}}",
"local": "ローカルトリガー",
"unknown": "カスタムスケジュール"
},
"next": {
"label": "次回: {{time}}",
"disabled": "一時停止中",
"local": "トリガー待ち",
"none": "次回実行なし"
}
},
@@ -791,12 +796,14 @@
"every": "{{duration}}ごと",
"cron": "Cron {{expr}}",
"cronWithTz": "Cron {{expr}} · {{tz}}",
"local": "ローカルトリガー",
"unknown": "カスタムスケジュール"
},
"next": {
"label": "次回 {{time}}",
"pending": "まもなく実行",
"disabled": "一時停止",
"local": "トリガー待ち",
"none": "次回実行なし"
}
},
+7
View File
@@ -493,6 +493,7 @@
"emptyHint": "실행될 위치에서 만들면 nanobot이 올바른 컨텍스트를 유지합니다.",
"oneShot": "일회성",
"systemTask": "시스템 관리 자동화",
"localTrigger": "로컬 트리거",
"labels": {
"schedule": "일정",
"next": "다음",
@@ -551,11 +552,13 @@
"weekdaysAt": "평일 {{time}}",
"hourlyAt": "매시간 :{{minute}}",
"hourlyWindow": "{{start}}-{{end}} 사이 매시간 :{{minute}}",
"local": "로컬 트리거",
"custom": "사용자 지정 일정"
},
"next": {
"paused": "일시 중지",
"pending": "실행 중",
"local": "트리거 대기 중",
"none": "다음 실행 없음"
},
"message": {
@@ -692,11 +695,13 @@
"every": "{{duration}}마다",
"cron": "Cron {{expr}}",
"cronWithTz": "Cron {{expr}} · {{tz}}",
"local": "로컬 트리거",
"unknown": "사용자 지정 일정"
},
"next": {
"label": "다음: {{time}}",
"disabled": "일시 중지됨",
"local": "트리거 대기 중",
"none": "다음 실행 없음"
}
},
@@ -791,12 +796,14 @@
"every": "{{duration}}마다",
"cron": "Cron {{expr}}",
"cronWithTz": "Cron {{expr}} · {{tz}}",
"local": "로컬 트리거",
"unknown": "사용자 지정 일정"
},
"next": {
"label": "다음 {{time}}",
"pending": "곧 실행됨",
"disabled": "일시 중지됨",
"local": "트리거 대기 중",
"none": "다음 실행 없음"
}
},
+7
View File
@@ -493,6 +493,7 @@
"emptyHint": "Tạo từ nơi tác vụ sẽ chạy để nanobot giữ đúng ngữ cảnh.",
"oneShot": "Một lần",
"systemTask": "Tự động hóa do hệ thống quản lý",
"localTrigger": "Trình kích hoạt cục bộ",
"labels": {
"schedule": "Lịch",
"next": "Tiếp theo",
@@ -551,11 +552,13 @@
"weekdaysAt": "Ngày làm việc lúc {{time}}",
"hourlyAt": "Mỗi giờ tại :{{minute}}",
"hourlyWindow": "Mỗi giờ {{start}}-{{end}} tại :{{minute}}",
"local": "Trình kích hoạt cục bộ",
"custom": "Lịch tùy chỉnh"
},
"next": {
"paused": "Đã tạm dừng",
"pending": "Đang chạy",
"local": "Đang chờ kích hoạt",
"none": "Không có lần chạy tiếp theo"
},
"message": {
@@ -692,11 +695,13 @@
"every": "Mỗi {{duration}}",
"cron": "Cron {{expr}}",
"cronWithTz": "Cron {{expr}} · {{tz}}",
"local": "Trình kích hoạt cục bộ",
"unknown": "Lịch tùy chỉnh"
},
"next": {
"label": "Tiếp theo: {{time}}",
"disabled": "Đã tạm dừng",
"local": "Đang chờ kích hoạt",
"none": "Không có lần chạy tiếp theo"
}
},
@@ -791,12 +796,14 @@
"every": "Mỗi {{duration}}",
"cron": "Cron {{expr}}",
"cronWithTz": "Cron {{expr}} · {{tz}}",
"local": "Trình kích hoạt cục bộ",
"unknown": "Lịch tùy chỉnh"
},
"next": {
"label": "Tiếp theo {{time}}",
"pending": "Sắp chạy",
"disabled": "Đã tạm dừng",
"local": "Đang chờ kích hoạt",
"none": "Không có lần chạy tiếp theo"
}
},
+7
View File
@@ -493,6 +493,7 @@
"emptyHint": "请从它应该运行的来源处创建,这样 nanobot 才能保留正确上下文。",
"oneShot": "一次性",
"systemTask": "系统管理的自动任务",
"localTrigger": "本地触发器",
"labels": {
"schedule": "计划",
"next": "下次",
@@ -551,11 +552,13 @@
"weekdaysAt": "工作日 {{time}}",
"hourlyAt": "每小时第 {{minute}} 分钟",
"hourlyWindow": "{{start}}-{{end}} 点每小时第 {{minute}} 分钟",
"local": "本地触发器",
"custom": "自定义计划"
},
"next": {
"paused": "已暂停",
"pending": "正在运行",
"local": "等待触发",
"none": "没有下次运行"
},
"message": {
@@ -692,11 +695,13 @@
"every": "每 {{duration}}",
"cron": "Cron {{expr}}",
"cronWithTz": "Cron {{expr}} · {{tz}}",
"local": "本地触发器",
"unknown": "自定义计划"
},
"next": {
"label": "下次:{{time}}",
"disabled": "已暂停",
"local": "等待触发",
"none": "没有下次运行"
}
},
@@ -791,12 +796,14 @@
"every": "每 {{duration}}",
"cron": "Cron {{expr}}",
"cronWithTz": "Cron {{expr}} · {{tz}}",
"local": "本地触发器",
"unknown": "自定义计划"
},
"next": {
"label": "下次 {{time}}",
"pending": "即将执行",
"disabled": "已暂停",
"local": "等待触发",
"none": "没有下次运行"
}
},
+7
View File
@@ -493,6 +493,7 @@
"emptyHint": "請從它應該執行的來源處建立,這樣 nanobot 才能保留正確上下文。",
"oneShot": "一次性",
"systemTask": "系統管理的自動任務",
"localTrigger": "本機觸發器",
"labels": {
"schedule": "排程",
"next": "下次",
@@ -551,11 +552,13 @@
"weekdaysAt": "工作日 {{time}}",
"hourlyAt": "每小時第 {{minute}} 分鐘",
"hourlyWindow": "{{start}}-{{end}} 點每小時第 {{minute}} 分鐘",
"local": "本機觸發器",
"custom": "自訂排程"
},
"next": {
"paused": "已暫停",
"pending": "正在執行",
"local": "等待觸發",
"none": "沒有下次執行"
},
"message": {
@@ -692,11 +695,13 @@
"every": "每 {{duration}}",
"cron": "Cron {{expr}}",
"cronWithTz": "Cron {{expr}} · {{tz}}",
"local": "本機觸發器",
"unknown": "自訂計畫"
},
"next": {
"label": "下次:{{time}}",
"disabled": "已暫停",
"local": "等待觸發",
"none": "沒有下次執行"
}
},
@@ -791,12 +796,14 @@
"every": "每 {{duration}}",
"cron": "Cron {{expr}}",
"cronWithTz": "Cron {{expr}} · {{tz}}",
"local": "本機觸發器",
"unknown": "自訂計畫"
},
"next": {
"label": "下次 {{time}}",
"pending": "即將執行",
"disabled": "已暫停",
"local": "等待觸發",
"none": "沒有下次執行"
}
},
+4 -4
View File
@@ -32,7 +32,7 @@ export interface UIMediaAttachment {
name?: string;
}
export interface UIMessageSource { kind: "cron" | "trigger" | string; label?: string; }
export interface UIMessageSource { kind: "cron" | "local_trigger" | "trigger" | string; label?: string; }
export interface UIMessage {
id: string;
@@ -104,9 +104,9 @@ export interface SessionAutomationJob {
delete_after_run?: boolean;
created_at_ms?: number | null;
updated_at_ms?: number | null;
kind?: "external_trigger" | "cron" | string;
kind?: "local_trigger" | "cron" | string;
schedule: {
kind: "at" | "every" | "cron" | "external" | string;
kind: "at" | "every" | "cron" | "local" | string;
at_ms?: number | null;
every_ms?: number | null;
expr?: string | null;
@@ -114,7 +114,7 @@ export interface SessionAutomationJob {
};
payload: {
message: string;
kind?: "agent_turn" | "system_event" | "external_trigger" | string;
kind?: "agent_turn" | "system_event" | "local_trigger" | string;
command?: string;
};
state: {