mirror of
https://github.com/openswarm-ai/openswarm.git
synced 2026-09-30 05:24:50 +02:00
[eric] workflows: restore scheduled-tasks on the workflow line (revert removal, keep windows fixes + 1.1.69)
This commit is contained in:
@@ -23,8 +23,9 @@ import {
|
||||
clearTurnLabel,
|
||||
} from '../state/agentsSlice';
|
||||
import { streamStart, streamDelta, streamEnd } from '../state/streamingSlice';
|
||||
import { addBrowserCardFromBackend, removeBrowserCard, setBrowserCardPosition, setGlowingBrowserCards, GRID_GAP } from '../state/dashboardLayoutSlice';
|
||||
import { addBrowserCardFromBackend, removeBrowserCard, setBrowserCardPosition, setGlowingBrowserCards, GRID_GAP, addWorkflowCard } from '../state/dashboardLayoutSlice';
|
||||
import { upsertOutput } from '../state/outputsSlice';
|
||||
import { upsertRun, ackRun, runWorkflowNow, openWorkflowCard } from '../state/workflowsSlice';
|
||||
import { getAuthToken } from '../config';
|
||||
import { notifyAgentCompletion } from '../notifications';
|
||||
|
||||
@@ -703,6 +704,65 @@ class WebSocketManager {
|
||||
}
|
||||
break;
|
||||
|
||||
case 'workflow:run':
|
||||
if (data.run) {
|
||||
store.dispatch(upsertRun(data.run));
|
||||
}
|
||||
break;
|
||||
|
||||
case 'workflow:notify':
|
||||
try {
|
||||
notifyAgentCompletion({
|
||||
sessionId: data.session_id || data.workflow_id,
|
||||
sessionName: data.workflow_title || 'Workflow',
|
||||
status: data.status === 'success' ? 'completed' : 'error',
|
||||
});
|
||||
} catch { /* notifications are best-effort */ }
|
||||
try {
|
||||
const w: any = (window as any).openswarm;
|
||||
if (w?.notify) {
|
||||
// Seed by workflow id + current minute so multiple workflows pick different copy
|
||||
// while a single workflow stays stable within a few minutes.
|
||||
const seed = ((data.workflow_id || '').length + Math.floor(Date.now() / 60000)) | 0;
|
||||
const SUCCESS_TITLES = [
|
||||
`${data.workflow_title || 'Workflow'} — done`,
|
||||
`${data.workflow_title || 'Workflow'} just wrapped up`,
|
||||
`Heads up: ${data.workflow_title || 'Workflow'} finished`,
|
||||
`${data.workflow_title || 'Workflow'} is ready`,
|
||||
];
|
||||
const FAILURE_TITLES = [
|
||||
`${data.workflow_title || 'Workflow'} hit a snag`,
|
||||
`${data.workflow_title || 'Workflow'} couldn't finish`,
|
||||
`Something went sideways on ${data.workflow_title || 'Workflow'}`,
|
||||
];
|
||||
const LATE_TITLES = [
|
||||
`${data.workflow_title || 'Workflow'} caught up late`,
|
||||
`${data.workflow_title || 'Workflow'} ran late but made it`,
|
||||
];
|
||||
const pool = data.status === 'success' ? SUCCESS_TITLES
|
||||
: data.status === 'failure' ? FAILURE_TITLES
|
||||
: data.status === 'ran_late' ? LATE_TITLES
|
||||
: [`${data.workflow_title || 'Workflow'} • ${data.status}`];
|
||||
const title = pool[Math.abs(seed) % pool.length];
|
||||
const isMac = (typeof navigator !== 'undefined' && /Mac/i.test(navigator.platform));
|
||||
const body = data.tier_kind && data.fallback
|
||||
? `Would have ${data.tier_kind === 'call' ? 'called' : 'texted'} you. (Cloud SMS not wired yet.)`
|
||||
: data.status === 'success'
|
||||
? (isMac ? 'Tap to see what it did.' : 'Click to see what it did.')
|
||||
: data.status === 'failure'
|
||||
? (isMac ? 'Tap to see what went wrong.' : 'Click to see what went wrong.')
|
||||
: (isMac ? 'Tap to open the run.' : 'Click to open the run.');
|
||||
const deepLink = data.workflow_id ? `openswarm://workflow/${data.workflow_id}/run/${data.run_id || ''}` : undefined;
|
||||
const actions = [
|
||||
{ text: 'Looks good', outcome: 'ack' },
|
||||
{ text: 'Re-run', outcome: 'rerun' },
|
||||
{ text: 'Adjust', outcome: 'edit' },
|
||||
];
|
||||
w.notify({ title, body, deepLink, runId: data.run_id, workflowId: data.workflow_id, actions });
|
||||
}
|
||||
} catch { /* native notif optional */ }
|
||||
break;
|
||||
|
||||
case 'dashboard:browser_card_added':
|
||||
if (data.browser_card) {
|
||||
store.dispatch(addBrowserCardFromBackend(data.browser_card));
|
||||
@@ -800,6 +860,31 @@ class WebSocketManager {
|
||||
|
||||
import { WS_BASE } from '@/shared/config';
|
||||
|
||||
// Bridge native-notification button actions to workflow actions. Subscribe at module
|
||||
// import time so we never miss an early callback fired before any component mounts.
|
||||
(() => {
|
||||
try {
|
||||
const w: any = (typeof window !== 'undefined') ? (window as any).openswarm : null;
|
||||
if (!w?.onNotificationAction) return;
|
||||
w.onNotificationAction(({ outcome, runId, workflowId }: { outcome: string; runId?: string; workflowId?: string }) => {
|
||||
if (!workflowId) return;
|
||||
if (outcome === 'ack' && runId) {
|
||||
store.dispatch(ackRun(runId));
|
||||
return;
|
||||
}
|
||||
if (outcome === 'rerun') {
|
||||
store.dispatch(runWorkflowNow(workflowId));
|
||||
return;
|
||||
}
|
||||
if (outcome === 'edit' || outcome === 'open') {
|
||||
store.dispatch(addWorkflowCard({ workflowId }));
|
||||
store.dispatch(openWorkflowCard({ workflowId, view: outcome === 'edit' ? 'edit' : 'saved', editFacet: outcome === 'edit' ? 'Schedule' : undefined }));
|
||||
return;
|
||||
}
|
||||
});
|
||||
} catch { /* native notifications optional */ }
|
||||
})();
|
||||
|
||||
export const dashboardWs = new WebSocketManager(`${WS_BASE}/ws/dashboard`, { skipStreamEvents: true });
|
||||
|
||||
// Per-session high-water mark for the resume protocol. Survives across
|
||||
|
||||
Reference in New Issue
Block a user