import type { useRouter } from "next/navigation"; import type { Task, Branch, LocalRepository } from "@/lib/types/http"; import type { AgentProfileOption } from "@/lib/state/slices"; import type { AppState } from "@/lib/state/store"; import type { StepType } from "@/components/task-create-dialog-types"; import { selectPreferredBranch } from "@/lib/utils"; import { getLocalStorage } from "@/lib/local-storage"; import { STORAGE_KEYS } from "@/lib/settings/constants"; import { useContextFilesStore } from "@/lib/state/context-files-store"; import { linkToTask } from "@/lib/links"; import { INTENT_PLAN } from "@/lib/state/layout-manager"; import { createTask } from "@/lib/api"; import type { FileAttachment } from "@/components/task/chat/file-attachment"; import type { MessageAttachment } from "@/lib/services/session-launch-service"; type CreateTaskParams = Parameters[0]; export type { CreateTaskParams }; /** Converts FileAttachment array to MessageAttachment array for the launch request. */ export function toMessageAttachments( attachments: FileAttachment[], ): MessageAttachment[] | undefined { if (attachments.length === 0) return undefined; return attachments.map((att) => att.isImage ? { type: "image" as const, data: att.data, mime_type: att.mimeType } : { type: "resource" as const, data: att.data, mime_type: att.mimeType, name: att.fileName, }, ); } export function autoSelectBranch(branchList: Branch[], setBranch: (value: string) => void): void { const lastUsedBranch = getLocalStorage(STORAGE_KEYS.LAST_BRANCH, null); if ( lastUsedBranch && branchList.some((b) => { const displayName = b.type === "remote" && b.remote ? `${b.remote}/${b.name}` : b.name; return displayName === lastUsedBranch; }) ) { setBranch(lastUsedBranch); return; } const preferredBranch = selectPreferredBranch(branchList); if (preferredBranch) setBranch(preferredBranch); } export function computePassthroughProfile( agentProfileId: string, agentProfiles: AgentProfileOption[], ) { if (!agentProfileId) return false; return ( agentProfiles.find((p: AgentProfileOption) => p.id === agentProfileId)?.cli_passthrough === true ); } export function computeEffectiveStepId( selectedWorkflowId: string | null, workflowId: string | null, fetchedSteps: StepType[] | null, defaultStepId: string | null, ) { return selectedWorkflowId && selectedWorkflowId !== workflowId && fetchedSteps ? (fetchedSteps[0]?.id ?? null) : defaultStepId; } export function computeIsTaskStarted( isEditMode: boolean, editingTask?: { state?: Task["state"] } | null, ) { if (!isEditMode || !editingTask?.state) return false; return editingTask.state !== "TODO" && editingTask.state !== "CREATED"; } export type ActivatePlanModeArgs = { sessionId: string; taskId: string; setActiveDocument: AppState["setActiveDocument"]; setPlanMode: AppState["setPlanMode"]; router: ReturnType; }; export function activatePlanMode({ sessionId, taskId, setActiveDocument, setPlanMode, router, }: ActivatePlanModeArgs) { setActiveDocument(sessionId, { type: "plan", taskId }); setPlanMode(sessionId, true); useContextFilesStore.getState().addFile(sessionId, { path: "plan:context", name: "Plan" }); router.push(linkToTask(taskId, INTENT_PLAN)); } export type BuildCreatePayloadArgs = { workspaceId: string; effectiveWorkflowId: string; trimmedTitle: string; trimmedDescription: string; repositoriesPayload: CreateTaskParams["repositories"]; agentProfileId: string; executorId: string; executorProfileId: string; withAgent: boolean; planMode?: boolean; attachments?: MessageAttachment[]; parentId?: string; }; export function buildCreateTaskPayload(args: BuildCreatePayloadArgs): CreateTaskParams { return { workspace_id: args.workspaceId, workflow_id: args.effectiveWorkflowId, title: args.trimmedTitle, description: args.trimmedDescription, repositories: args.repositoriesPayload, state: args.withAgent ? "IN_PROGRESS" : "CREATED", start_agent: args.withAgent ? true : undefined, prepare_session: args.withAgent ? undefined : true, agent_profile_id: args.agentProfileId || undefined, executor_id: args.executorId || undefined, executor_profile_id: args.executorProfileId || undefined, plan_mode: args.planMode || undefined, attachments: args.attachments, parent_id: args.parentId || undefined, }; } export function validateCreateInputs(inputs: { trimmedTitle: string; workspaceId: string | null; effectiveWorkflowId: string | null; repositoryId: string; selectedLocalRepo: LocalRepository | null; githubUrl?: string; agentProfileId: string; }): boolean { return Boolean( inputs.trimmedTitle && inputs.workspaceId && inputs.effectiveWorkflowId && inputs.agentProfileId && (inputs.repositoryId || inputs.selectedLocalRepo || inputs.githubUrl?.trim()), ); } /** Builds the repositories payload for task creation from the current form state. */ export function buildRepositoriesPayload(opts: { useGitHubUrl: boolean; githubUrl: string; branch: string; githubPrHeadBranch: string | null; repositoryId: string; selectedLocalRepo: LocalRepository | null; }): NonNullable { if (opts.useGitHubUrl && opts.githubUrl) { return [ { repository_id: "", base_branch: opts.branch || undefined, checkout_branch: opts.githubPrHeadBranch || undefined, github_url: opts.githubUrl.trim(), }, ]; } if (opts.repositoryId) { return [{ repository_id: opts.repositoryId, base_branch: opts.branch || undefined }]; } if (opts.selectedLocalRepo) { return [ { repository_id: "", base_branch: opts.branch || undefined, local_path: opts.selectedLocalRepo.path, default_branch: opts.selectedLocalRepo.default_branch || undefined, }, ]; } return []; }