From 68d32fe01f487b156b4b62ba9015bbf678bef966 Mon Sep 17 00:00:00 2001 From: waleed Date: Mon, 15 Jun 2026 19:15:37 -0700 Subject: [PATCH 1/4] feat(chat): add scheduled tasks as a viewable resource Adds a new `scheduledtask` resource type so a scheduled task can be opened and viewed as a tab in Chat: - registry config (Calendar icon, label, tab/dropdown renderers) - add-resource dropdown listing (workspace jobs) - embedded detail viewer (status, schedule, next/last run, prompt, recent runs) - "Open in scheduled tasks" action + query invalidation - contract enum + route validation so the resource persists Agent-side mention/OpenResource wiring is left as a follow-up. --- .../app/api/copilot/chat/resources/route.ts | 11 +- .../add-resource-dropdown.tsx | 14 ++ .../resource-content/resource-content.tsx | 150 ++++++++++++++++++ .../resource-registry/resource-registry.tsx | 14 ++ apps/sim/lib/api/contracts/copilot.ts | 1 + apps/sim/lib/copilot/resources/types.ts | 1 + 6 files changed, 190 insertions(+), 1 deletion(-) diff --git a/apps/sim/app/api/copilot/chat/resources/route.ts b/apps/sim/app/api/copilot/chat/resources/route.ts index 5417fbe4a49..45c71efc174 100644 --- a/apps/sim/app/api/copilot/chat/resources/route.ts +++ b/apps/sim/app/api/copilot/chat/resources/route.ts @@ -27,10 +27,19 @@ const VALID_RESOURCE_TYPES = new Set([ 'workflow', 'knowledgebase', 'folder', + 'scheduledtask', 'log', 'integration', ]) -const GENERIC_TITLES = new Set(['Table', 'File', 'Workflow', 'Knowledge Base', 'Folder', 'Log']) +const GENERIC_TITLES = new Set([ + 'Table', + 'File', + 'Workflow', + 'Knowledge Base', + 'Folder', + 'Scheduled Task', + 'Log', +]) export const POST = withRouteHandler(async (req: NextRequest) => { try { diff --git a/apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/add-resource-dropdown/add-resource-dropdown.tsx b/apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/add-resource-dropdown/add-resource-dropdown.tsx index 889ac5ada6b..2f3283aa245 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/add-resource-dropdown/add-resource-dropdown.tsx +++ b/apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/add-resource-dropdown/add-resource-dropdown.tsx @@ -1,6 +1,7 @@ 'use client' import { useMemo, useState } from 'react' +import { truncate } from '@sim/utils/string' import { Button, DropdownMenu, @@ -30,6 +31,7 @@ import { useFolders } from '@/hooks/queries/folders' import { useKnowledgeBasesQuery } from '@/hooks/queries/kb/knowledge' import { useLogsList } from '@/hooks/queries/logs' import { useMothershipChats } from '@/hooks/queries/mothership-chats' +import { useWorkspaceSchedules } from '@/hooks/queries/schedules' import { useTablesList } from '@/hooks/queries/tables' import { useWorkflows } from '@/hooks/queries/workflows' import { useWorkspaceFileFolders } from '@/hooks/queries/workspace-file-folders' @@ -77,6 +79,7 @@ export function useAvailableResources( const { data: folders = [] } = useFolders(workspaceId) const { data: fileFolders = [] } = useWorkspaceFileFolders(workspaceId) const { data: tasks = [] } = useMothershipChats(workspaceId) + const { data: schedules = [] } = useWorkspaceSchedules(workspaceId) const { data: logsData } = useLogsList(workspaceId, LOG_DROPDOWN_FILTERS) const logs = useMemo(() => (logsData?.pages ?? []).flatMap((page) => page.logs), [logsData]) @@ -155,6 +158,16 @@ export function useAvailableResources( isOpen: existingKeys.has(`task:${t.id}`), })), }, + { + type: 'scheduledtask' as const, + items: schedules + .filter((s) => s.sourceType === 'job') + .map((s) => ({ + id: s.id, + name: s.jobTitle || truncate(s.prompt ?? '', 40) || 'Scheduled Task', + isOpen: existingKeys.has(`scheduledtask:${s.id}`), + })), + }, { type: 'log' as const, items: logs.map((log) => { @@ -179,6 +192,7 @@ export function useAvailableResources( files, knowledgeBases, tasks, + schedules, logs, existingKeys, excludeTypes, diff --git a/apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-content/resource-content.tsx b/apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-content/resource-content.tsx index 965987807b8..bc7928b6203 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-content/resource-content.tsx +++ b/apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-content/resource-content.tsx @@ -2,9 +2,11 @@ import { lazy, memo, Suspense, useEffect, useMemo, useRef } from 'react' import { createLogger } from '@sim/logger' +import { format } from 'date-fns' import { useRouter } from 'next/navigation' import { Button, PlayOutline, Skeleton, Tooltip } from '@/components/emcn' import { + Calendar, Download, FileX, Folder as FolderIcon, @@ -24,6 +26,7 @@ import { import { canonicalWorkspaceFilePath } from '@/lib/copilot/vfs/path-utils' import { triggerFileDownload } from '@/lib/uploads/client/download' import { getFileExtension, getMimeTypeFromExtension } from '@/lib/uploads/utils/file-utils' +import { parseCronToHumanReadable } from '@/lib/workflows/schedules/utils' import { FileViewer, type PreviewMode, @@ -50,6 +53,7 @@ import { useUsageLimits } from '@/app/workspace/[workspaceId]/w/[workflowId]/com import { useWorkflowExecution } from '@/app/workspace/[workspaceId]/w/[workflowId]/hooks/use-workflow-execution' import { useFolders } from '@/hooks/queries/folders' import { useLogDetail } from '@/hooks/queries/logs' +import { useWorkspaceSchedules } from '@/hooks/queries/schedules' import { downloadTableExport } from '@/hooks/queries/tables' import { useWorkflows } from '@/hooks/queries/workflows' import { useWorkspaceFiles } from '@/hooks/queries/workspace-files' @@ -182,6 +186,15 @@ export const ResourceContent = memo(function ResourceContent({ case 'folder': return + case 'scheduledtask': + return ( + + ) + case 'log': return ( + case 'scheduledtask': + return case 'folder': case 'generic': return null @@ -647,6 +662,141 @@ function EmbeddedFolder({ workspaceId, folderId }: EmbeddedFolderProps) { ) } +const SCHEDULE_STATUS_LABEL: Record = { + active: 'Active', + disabled: 'Paused', + completed: 'Completed', +} + +function formatScheduleInstant(iso: string | null): string { + if (!iso) return '—' + const date = new Date(iso) + return Number.isNaN(date.getTime()) ? '—' : format(date, "EEE, MMM d 'at' h:mm a") +} + +interface ScheduledTaskFieldProps { + title: string + value: string +} + +function ScheduledTaskField({ title, value }: ScheduledTaskFieldProps) { + return ( +
+ {title} + {value} +
+ ) +} + +interface EmbeddedScheduledTaskProps { + workspaceId: string + scheduleId: string +} + +function EmbeddedScheduledTask({ workspaceId, scheduleId }: EmbeddedScheduledTaskProps) { + const { data: schedules = [], isLoading } = useWorkspaceSchedules(workspaceId) + const schedule = useMemo( + () => schedules.find((s) => s.id === scheduleId), + [schedules, scheduleId] + ) + + if (isLoading && !schedule) return LOADING_SKELETON + + if (!schedule) { + return ( +
+ +
+

+ Scheduled task not found +

+

+ This scheduled task may have been deleted +

+
+
+ ) + } + + const title = schedule.jobTitle || schedule.prompt || 'Scheduled task' + const timing = schedule.cronExpression + ? parseCronToHumanReadable(schedule.cronExpression, schedule.timezone) + : 'Runs once' + const status = SCHEDULE_STATUS_LABEL[schedule.status] ?? schedule.status + + return ( +
+
+ +

{title}

+
+ +
+ + + + +
+ +
+ Prompt +

+ {schedule.prompt || '—'} +

+
+ + {schedule.jobHistory && schedule.jobHistory.length > 0 && ( +
+ Recent runs +
+ {schedule.jobHistory.slice(0, 5).map((run) => ( +
+ + {formatScheduleInstant(run.timestamp)} + + {run.summary} +
+ ))} +
+
+ )} +
+ ) +} + +interface EmbeddedScheduledTaskActionsProps { + workspaceId: string +} + +function EmbeddedScheduledTaskActions({ workspaceId }: EmbeddedScheduledTaskActionsProps) { + const router = useRouter() + + const handleOpenScheduledTasks = () => { + router.push(`/workspace/${workspaceId}/scheduled-tasks`) + } + + return ( + + + + + +

Open in scheduled tasks

+
+
+ ) +} + interface EmbeddedLogProps { workspaceId: string logId: string diff --git a/apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-registry/resource-registry.tsx b/apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-registry/resource-registry.tsx index d41ba2a8770..3d0df4475f8 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-registry/resource-registry.tsx +++ b/apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-registry/resource-registry.tsx @@ -3,6 +3,7 @@ import type { ElementType, ReactNode } from 'react' import type { QueryClient } from '@tanstack/react-query' import { + Calendar, Connections, Database, File as FileIcon, @@ -23,6 +24,7 @@ import { getBareIconStyle, type StyleableIcon } from '@/blocks/icon-color' import { knowledgeKeys } from '@/hooks/queries/kb/knowledge' import { logKeys } from '@/hooks/queries/logs' import { mothershipChatKeys } from '@/hooks/queries/mothership-chats' +import { scheduleKeys } from '@/hooks/queries/schedules' import { tableKeys } from '@/hooks/queries/tables' import { folderKeys } from '@/hooks/queries/utils/folder-keys' import { invalidateWorkflowLists } from '@/hooks/queries/utils/invalidate-workflow-lists' @@ -183,6 +185,15 @@ export const RESOURCE_REGISTRY: Record , }, + scheduledtask: { + type: 'scheduledtask', + label: 'Scheduled Tasks', + icon: Calendar, + renderTabIcon: (_resource, className) => ( + + ), + renderDropdownItem: (props) => , + }, log: { type: 'log', label: 'Logs', @@ -241,6 +252,9 @@ const RESOURCE_INVALIDATORS: Record< task: (qc, wId) => { qc.invalidateQueries({ queryKey: mothershipChatKeys.list(wId) }) }, + scheduledtask: (qc, wId) => { + qc.invalidateQueries({ queryKey: scheduleKeys.list(wId) }) + }, log: (qc, _wId, id) => { qc.invalidateQueries({ queryKey: logKeys.details() }) qc.invalidateQueries({ queryKey: logKeys.detail(id) }) diff --git a/apps/sim/lib/api/contracts/copilot.ts b/apps/sim/lib/api/contracts/copilot.ts index 3da7fdd6d01..f522728f647 100644 --- a/apps/sim/lib/api/contracts/copilot.ts +++ b/apps/sim/lib/api/contracts/copilot.ts @@ -92,6 +92,7 @@ const copilotResourceTypeSchema = z.enum([ 'workflow', 'knowledgebase', 'folder', + 'scheduledtask', 'log', ]) diff --git a/apps/sim/lib/copilot/resources/types.ts b/apps/sim/lib/copilot/resources/types.ts index ff1703ebbf9..c72cf04b437 100644 --- a/apps/sim/lib/copilot/resources/types.ts +++ b/apps/sim/lib/copilot/resources/types.ts @@ -6,6 +6,7 @@ export const MothershipResourceType = { folder: 'folder', filefolder: 'filefolder', task: 'task', + scheduledtask: 'scheduledtask', log: 'log', integration: 'integration', generic: 'generic', From 52649ff8427fce844e80caace0fef14e37d79498 Mon Sep 17 00:00:00 2001 From: waleed Date: Mon, 15 Jun 2026 19:21:42 -0700 Subject: [PATCH 2/4] refactor(chat): share generic resource-title set across route and persistence Dedupes the placeholder-title set that the chat-resource route and the server-side persistence merge each defined separately. They had already drifted ('Log' was missing from persistence); a single shared GENERIC_RESOURCE_TITLES keeps title-upgrade behavior consistent, including the new 'Scheduled Task' placeholder. --- apps/sim/app/api/copilot/chat/resources/route.ts | 12 ++---------- apps/sim/lib/copilot/resources/persistence.ts | 8 +++++--- apps/sim/lib/copilot/resources/types.ts | 16 ++++++++++++++++ 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/apps/sim/app/api/copilot/chat/resources/route.ts b/apps/sim/app/api/copilot/chat/resources/route.ts index 45c71efc174..823b9a94aba 100644 --- a/apps/sim/app/api/copilot/chat/resources/route.ts +++ b/apps/sim/app/api/copilot/chat/resources/route.ts @@ -17,6 +17,7 @@ import { createUnauthorizedResponse, } from '@/lib/copilot/request/http' import type { ChatResource, ResourceType } from '@/lib/copilot/resources/persistence' +import { GENERIC_RESOURCE_TITLES } from '@/lib/copilot/resources/types' import { withRouteHandler } from '@/lib/core/utils/with-route-handler' const logger = createLogger('CopilotChatResourcesAPI') @@ -31,15 +32,6 @@ const VALID_RESOURCE_TYPES = new Set([ 'log', 'integration', ]) -const GENERIC_TITLES = new Set([ - 'Table', - 'File', - 'Workflow', - 'Knowledge Base', - 'Folder', - 'Scheduled Task', - 'Log', -]) export const POST = withRouteHandler(async (req: NextRequest) => { try { @@ -85,7 +77,7 @@ export const POST = withRouteHandler(async (req: NextRequest) => { let merged: ChatResource[] if (prev) { - if (GENERIC_TITLES.has(prev.title) && !GENERIC_TITLES.has(resource.title)) { + if (GENERIC_RESOURCE_TITLES.has(prev.title) && !GENERIC_RESOURCE_TITLES.has(resource.title)) { merged = existing.map((r) => `${r.type}:${r.id}` === key ? { ...r, title: resource.title } : r ) diff --git a/apps/sim/lib/copilot/resources/persistence.ts b/apps/sim/lib/copilot/resources/persistence.ts index 0407e61dd38..c389adc6491 100644 --- a/apps/sim/lib/copilot/resources/persistence.ts +++ b/apps/sim/lib/copilot/resources/persistence.ts @@ -3,7 +3,7 @@ import { copilotChats } from '@sim/db/schema' import { createLogger } from '@sim/logger' import { toError } from '@sim/utils/errors' import { eq, sql } from 'drizzle-orm' -import type { MothershipResource } from './types' +import { GENERIC_RESOURCE_TITLES, type MothershipResource } from './types' export { extractDeletedResourcesFromToolResult, @@ -42,7 +42,6 @@ export async function persistChatResources( const existing = Array.isArray(chat.resources) ? (chat.resources as ChatResource[]) : [] const map = new Map() - const GENERIC = new Set(['Table', 'File', 'Workflow', 'Knowledge Base', 'Folder', 'Log']) for (const r of existing) { map.set(`${r.type}:${r.id}`, r) @@ -51,7 +50,10 @@ export async function persistChatResources( for (const r of toMerge) { const key = `${r.type}:${r.id}` const prev = map.get(key) - if (!prev || (GENERIC.has(prev.title) && !GENERIC.has(r.title))) { + if ( + !prev || + (GENERIC_RESOURCE_TITLES.has(prev.title) && !GENERIC_RESOURCE_TITLES.has(r.title)) + ) { map.set(key, r) } } diff --git a/apps/sim/lib/copilot/resources/types.ts b/apps/sim/lib/copilot/resources/types.ts index c72cf04b437..4cacc86be31 100644 --- a/apps/sim/lib/copilot/resources/types.ts +++ b/apps/sim/lib/copilot/resources/types.ts @@ -25,6 +25,22 @@ export function isEphemeralResource(resource: MothershipResource): boolean { return resource.type === 'generic' || resource.id === 'streaming-file' } +/** + * Placeholder resource titles emitted before a specific name is known. A more + * specific title may overwrite one of these during dedup; a specific title is + * never downgraded back to a placeholder. Shared by the chat-resource route and + * the server-side persistence merge so the two stay in lockstep. + */ +export const GENERIC_RESOURCE_TITLES = new Set([ + 'Table', + 'File', + 'Workflow', + 'Knowledge Base', + 'Folder', + 'Scheduled Task', + 'Log', +]) + export const VFS_DIR_TO_RESOURCE: Record = { tables: 'table', files: 'file', From e494b22413e166c4391769018f9079ee6cfd77ab Mon Sep 17 00:00:00 2001 From: waleed Date: Mon, 15 Jun 2026 19:23:58 -0700 Subject: [PATCH 3/4] fix(chat): distinct error state and stable history keys in scheduled-task viewer - Render a 'couldn't load' state when the schedules query errors, instead of falsely claiming the task was deleted (uses React Query isError) - Use a stable composite key for jobHistory rows so same-second timestamps don't collide --- .../resource-content/resource-content.tsx | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-content/resource-content.tsx b/apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-content/resource-content.tsx index bc7928b6203..2b11882b294 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-content/resource-content.tsx +++ b/apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-content/resource-content.tsx @@ -694,7 +694,7 @@ interface EmbeddedScheduledTaskProps { } function EmbeddedScheduledTask({ workspaceId, scheduleId }: EmbeddedScheduledTaskProps) { - const { data: schedules = [], isLoading } = useWorkspaceSchedules(workspaceId) + const { data: schedules = [], isLoading, isError } = useWorkspaceSchedules(workspaceId) const schedule = useMemo( () => schedules.find((s) => s.id === scheduleId), [schedules, scheduleId] @@ -703,16 +703,18 @@ function EmbeddedScheduledTask({ workspaceId, scheduleId }: EmbeddedScheduledTas if (isLoading && !schedule) return LOADING_SKELETON if (!schedule) { + // A failed list query also yields no schedule; keep that distinct from a + // genuinely missing task so we don't tell the user it was deleted. + const heading = isError ? "Couldn't load scheduled task" : 'Scheduled task not found' + const detail = isError + ? 'Something went wrong loading this scheduled task. Try again.' + : 'This scheduled task may have been deleted' return (
-

- Scheduled task not found -

-

- This scheduled task may have been deleted -

+

{heading}

+

{detail}

) @@ -749,9 +751,9 @@ function EmbeddedScheduledTask({ workspaceId, scheduleId }: EmbeddedScheduledTas
Recent runs
- {schedule.jobHistory.slice(0, 5).map((run) => ( + {schedule.jobHistory.slice(0, 5).map((run, index) => (
From 9c07fd9bc39a935c75ee071e5250bc498ee38674 Mon Sep 17 00:00:00 2001 From: waleed Date: Mon, 15 Jun 2026 19:55:17 -0700 Subject: [PATCH 4/4] feat(chat): wire scheduledtask chat-context kind MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds a first-class 'scheduledtask' ChatContext kind so a scheduled-task resource maps to a real context (not a generic docs fallback), fixing the exhaustive RESOURCE_TO_CONTEXT map that broke the build: - ChatContext union + CHAT_CONTEXT_KIND_REGISTRY (Calendar chip) - resource→context mapping, context validity check, clipboard portability Agent-side consumption of the kind remains a follow-up. --- .../chat-context-kind-registry.tsx | 5 +++++ .../components/resource-content/resource-content.tsx | 2 -- .../user-input/components/chip-clipboard-codec.ts | 3 +++ .../home/components/user-input/components/constants.ts | 1 + .../sim/app/workspace/[workspaceId]/home/hooks/use-chat.ts | 2 ++ apps/sim/lib/copilot/resources/types.ts | 7 +------ apps/sim/stores/panel/types.ts | 1 + 7 files changed, 13 insertions(+), 8 deletions(-) diff --git a/apps/sim/app/workspace/[workspaceId]/home/components/chat-context-kind-registry/chat-context-kind-registry.tsx b/apps/sim/app/workspace/[workspaceId]/home/components/chat-context-kind-registry/chat-context-kind-registry.tsx index 2269283392b..e01cbc5f80d 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/components/chat-context-kind-registry/chat-context-kind-registry.tsx +++ b/apps/sim/app/workspace/[workspaceId]/home/components/chat-context-kind-registry/chat-context-kind-registry.tsx @@ -1,5 +1,6 @@ import type { ReactNode } from 'react' import { + Calendar, Database, Folder as FolderIcon, Library, @@ -79,6 +80,10 @@ export const CHAT_CONTEXT_KIND_REGISTRY: Record , }, + scheduledtask: { + label: 'Scheduled task', + renderIcon: ({ className }) => , + }, past_chat: { label: 'Past chat', renderIcon: ({ className }) => , diff --git a/apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-content/resource-content.tsx b/apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-content/resource-content.tsx index 2b11882b294..55219f75006 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-content/resource-content.tsx +++ b/apps/sim/app/workspace/[workspaceId]/home/components/mothership-view/components/resource-content/resource-content.tsx @@ -703,8 +703,6 @@ function EmbeddedScheduledTask({ workspaceId, scheduleId }: EmbeddedScheduledTas if (isLoading && !schedule) return LOADING_SKELETON if (!schedule) { - // A failed list query also yields no schedule; keep that distinct from a - // genuinely missing task so we don't tell the user it was deleted. const heading = isError ? "Couldn't load scheduled task" : 'Scheduled task not found' const detail = isError ? 'Something went wrong loading this scheduled task. Try again.' diff --git a/apps/sim/app/workspace/[workspaceId]/home/components/user-input/components/chip-clipboard-codec.ts b/apps/sim/app/workspace/[workspaceId]/home/components/user-input/components/chip-clipboard-codec.ts index 443c1222892..43cdbef772a 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/components/user-input/components/chip-clipboard-codec.ts +++ b/apps/sim/app/workspace/[workspaceId]/home/components/user-input/components/chip-clipboard-codec.ts @@ -27,6 +27,7 @@ const PORTABLE_KIND_TO_ID_FIELD = { file: 'fileId', folder: 'folderId', filefolder: 'fileFolderId', + scheduledtask: 'scheduleId', knowledge: 'knowledgeId', past_chat: 'chatId', workflow: 'workflowId', @@ -207,6 +208,8 @@ export function chipLinkToContext(link: ParsedChipLink): ChatContext { return { kind: 'folder', folderId: link.id, label: link.label } case 'filefolder': return { kind: 'filefolder', fileFolderId: link.id, label: link.label } + case 'scheduledtask': + return { kind: 'scheduledtask', scheduleId: link.id, label: link.label } case 'knowledge': return { kind: 'knowledge', knowledgeId: link.id, label: link.label } case 'past_chat': diff --git a/apps/sim/app/workspace/[workspaceId]/home/components/user-input/components/constants.ts b/apps/sim/app/workspace/[workspaceId]/home/components/user-input/components/constants.ts index a1065032200..645ace30c60 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/components/user-input/components/constants.ts +++ b/apps/sim/app/workspace/[workspaceId]/home/components/user-input/components/constants.ts @@ -112,6 +112,7 @@ const RESOURCE_TO_CONTEXT: Record< task: (r) => ({ kind: 'past_chat', chatId: r.id, label: r.title }), log: (r) => ({ kind: 'logs', executionId: r.id, label: r.title }), integration: (r) => ({ kind: 'integration', blockType: r.id, label: r.title }), + scheduledtask: (r) => ({ kind: 'scheduledtask', scheduleId: r.id, label: r.title }), generic: (r) => ({ kind: 'docs', label: r.title }), } diff --git a/apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.ts b/apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.ts index 5374c77b416..dc5ae5d86d2 100644 --- a/apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.ts +++ b/apps/sim/app/workspace/[workspaceId]/home/hooks/use-chat.ts @@ -294,6 +294,8 @@ function isChatContext(value: unknown): value is ChatContext { return typeof value.folderId === 'string' case 'filefolder': return typeof value.fileFolderId === 'string' + case 'scheduledtask': + return typeof value.scheduleId === 'string' case 'docs': return true case 'slash_command': diff --git a/apps/sim/lib/copilot/resources/types.ts b/apps/sim/lib/copilot/resources/types.ts index 4cacc86be31..6e1c8ac774d 100644 --- a/apps/sim/lib/copilot/resources/types.ts +++ b/apps/sim/lib/copilot/resources/types.ts @@ -25,12 +25,7 @@ export function isEphemeralResource(resource: MothershipResource): boolean { return resource.type === 'generic' || resource.id === 'streaming-file' } -/** - * Placeholder resource titles emitted before a specific name is known. A more - * specific title may overwrite one of these during dedup; a specific title is - * never downgraded back to a placeholder. Shared by the chat-resource route and - * the server-side persistence merge so the two stay in lockstep. - */ +/** Placeholder resource titles that a more specific title may overwrite during dedup. */ export const GENERIC_RESOURCE_TITLES = new Set([ 'Table', 'File', diff --git a/apps/sim/stores/panel/types.ts b/apps/sim/stores/panel/types.ts index 05012aee9f8..43192146ccd 100644 --- a/apps/sim/stores/panel/types.ts +++ b/apps/sim/stores/panel/types.ts @@ -31,6 +31,7 @@ export type ChatContext = | { kind: 'file'; fileId: string; label: string } | { kind: 'folder'; folderId: string; label: string } | { kind: 'filefolder'; fileFolderId: string; label: string } + | { kind: 'scheduledtask'; scheduleId: string; label: string } | { kind: 'docs'; label: string } | { kind: 'slash_command'; command: string; label: string } | { kind: 'integration'; blockType: string; label: string }