feat: implement createTask function and associated tests#1655
Conversation
- Added createTask function to handle task creation via the Recoup API, including error handling for various response scenarios. - Created unit tests for createTask to verify correct API interaction, including optional parameters and error cases.
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds a client-side "Create Task" flow: UI, form hook, schedule/model fields, cron validation, sessionStorage migration/cleanup, a createTask API client, API-base override via NEXT_PUBLIC_API_BASE_URL, and related constants and types. Changes
Sequence Diagram(s)sequenceDiagram
participant Browser as "Browser (CreateTaskPage)"
participant Hook as "useCreateTaskForm"
participant ClientUtil as "createTask (lib/tasks/createTask.ts)"
participant API as "Server API /api/tasks"
participant DB as "Database"
Browser->>Hook: user fills form, submits
Hook->>Hook: validate fields & cron
Hook->>Hook: get access token (usePrivy)
Hook->>ClientUtil: createTask(accessToken, params)
ClientUtil->>API: POST /api/tasks (Authorization, JSON body)
API->>DB: persist scheduled task
DB-->>API: return created task
API-->>ClientUtil: 200 OK with tasks array
ClientUtil-->>Hook: return created Task
Hook-->>Browser: toast success, navigate /tasks, router.refresh()
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested reviewers
Poem
🚥 Pre-merge checks | ❌ 1❌ Failed checks (1 warning)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
lib/tasks/createTask.ts (1)
20-23: Consider validatingaccessTokento fail fast.The function accepts any string for
accessToken, including empty strings. While the API will reject invalid tokens, failing fast with a descriptive error improves debugging experience.🛡️ Optional: Add input validation
export async function createTask( accessToken: string, params: CreateTaskParams, ): Promise<ScheduledAction> { + if (!accessToken) { + throw new Error("accessToken is required"); + } + const response = await fetch(`${getClientApiBaseUrl()}/api/tasks`, {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/tasks/createTask.ts` around lines 20 - 23, The createTask function currently accepts any string for accessToken which can be empty; add a fast-fail input validation at the top of createTask to check that accessToken is a non-empty string (and optionally well-formed if you have a pattern), and throw a clear, descriptive error (e.g., Error('createTask: accessToken is required')) before proceeding to use CreateTaskParams or returning a ScheduledAction; update callers/tests if necessary to handle the thrown error.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@lib/tasks/createTask.ts`:
- Around line 35-36: The spread construction in createTask.ts is inconsistent:
it uses a truthy check for params.account_id but an explicit !== undefined check
for params.model, which treats empty string and null differently; update both
spreads to use the same explicit presence check (e.g., params.account_id !==
undefined and params.model !== undefined) or, if you intend to exclude empty
strings for account_id, add a clarifying comment above the account_id spread
explaining that empty strings must be excluded—refer to the params object fields
account_id and model and make the checks consistent across the two spreads.
---
Nitpick comments:
In `@lib/tasks/createTask.ts`:
- Around line 20-23: The createTask function currently accepts any string for
accessToken which can be empty; add a fast-fail input validation at the top of
createTask to check that accessToken is a non-empty string (and optionally
well-formed if you have a pattern), and throw a clear, descriptive error (e.g.,
Error('createTask: accessToken is required')) before proceeding to use
CreateTaskParams or returning a ScheduledAction; update callers/tests if
necessary to handle the thrown error.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 02121c33-755b-4889-bc74-6bc63c9cae1e
⛔ Files ignored due to path filters (1)
lib/tasks/__tests__/createTask.test.tsis excluded by!**/*.test.*and included bylib/**
📒 Files selected for processing (1)
lib/tasks/createTask.ts
There was a problem hiding this comment.
3 issues found across 2 files
Confidence score: 4/5
- This PR looks safe to merge overall; the main issues are minor consistency concerns rather than clear runtime breakage.
- Most notable:
lib/tasks/createTask.tsreturnsScheduledActionbut parsesTask-typed data, which could confuse consumers or type checks. - Inconsistent optional param handling in
lib/tasks/createTask.ts(account_idtruthy check vsmodel !== undefined) may lead to subtle input differences but is not likely to be merge-blocking. - Pay close attention to
lib/tasks/createTask.ts- return type consistency and optional parameter checks.
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="lib/tasks/__tests__/createTask.test.ts">
<violation number="1" location="lib/tasks/__tests__/createTask.test.ts:1">
P1: Custom agent: **Code Structure and Size Limits for Readability and Single Responsibility**
This test file is 136 lines, exceeding the 100-line limit. Split the error-case tests (HTTP error, API error status, empty tasks) into a separate file like `createTask.errors.test.ts` to keep each file under 100 lines.</violation>
</file>
<file name="lib/tasks/createTask.ts">
<violation number="1" location="lib/tasks/createTask.ts:23">
P2: Return type should be `Task` instead of `ScheduledAction` to match the parsed response type (`GetTasksResponse.tasks` is `Task[]`) and stay consistent with `getTasks`, which returns `Task[]`. The current `ScheduledAction` return type discards the optional `recent_runs` and `upcoming` fields, which callers can't access without casting.</violation>
<violation number="2" location="lib/tasks/createTask.ts:35">
P3: Inconsistent conditional patterns for optional parameters: `account_id` uses a truthiness check (excluding `undefined` and `""`) while `model` uses `!== undefined` (allowing `null` and `""`). If both should follow the same exclusion logic, align them. If the difference is intentional (e.g., `model` deliberately allows `null` to clear the field), add a brief comment to make that intent explicit.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.
| @@ -0,0 +1,136 @@ | |||
| import { beforeEach, describe, expect, it, vi } from "vitest"; | |||
There was a problem hiding this comment.
P1: Custom agent: Code Structure and Size Limits for Readability and Single Responsibility
This test file is 136 lines, exceeding the 100-line limit. Split the error-case tests (HTTP error, API error status, empty tasks) into a separate file like createTask.errors.test.ts to keep each file under 100 lines.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At lib/tasks/__tests__/createTask.test.ts, line 1:
<comment>This test file is 136 lines, exceeding the 100-line limit. Split the error-case tests (HTTP error, API error status, empty tasks) into a separate file like `createTask.errors.test.ts` to keep each file under 100 lines.</comment>
<file context>
@@ -0,0 +1,136 @@
+import { beforeEach, describe, expect, it, vi } from "vitest";
+import { createTask } from "@/lib/tasks/createTask";
+import { getClientApiBaseUrl } from "@/lib/api/getClientApiBaseUrl";
</file context>
There was a problem hiding this comment.
Now the test file is 83 lines
There was a problem hiding this comment.
Thanks for the update—glad it’s under 100 lines now.
…umentation - Removed the optional account_id parameter from the CreateTaskParams interface. - Updated the createTask function documentation to clarify that the task owner account is resolved from the bearer token, eliminating the need to send account_id in the request body. - Adjusted related tests to reflect the removal of account_id.
- Added optional account_id parameter to CreateTaskParams interface, allowing for more flexible task creation. - Updated createTask function to include account_id in the request body when provided. - Modified API base URL logic to support an environment variable override for better configuration in different environments. - Adjusted related tests to verify the inclusion of account_id and updated API base URL behavior.
…upwork/myc-4586-chat-align-task-creation-client-with-hardened-post-apitasks
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (3)
lib/consts.ts (1)
4-9: Minor: simplify with nullish coalescing and guard against empty-string env values.A blank
NEXT_PUBLIC_API_BASE_URL=""would currently be treated as "not set" by the truthy check (fine), but the nested ternary is harder to read than necessary. Consider:♻️ Suggested tidy-up
-const apiBaseUrlOverride = process.env.NEXT_PUBLIC_API_BASE_URL; -export const NEW_API_BASE_URL = apiBaseUrlOverride - ? apiBaseUrlOverride - : IS_PROD - ? "https://recoup-api.vercel.app" - : "https://test-recoup-api.vercel.app"; +const DEFAULT_API_BASE_URL = IS_PROD + ? "https://recoup-api.vercel.app" + : "https://test-recoup-api.vercel.app"; +export const NEW_API_BASE_URL = + process.env.NEXT_PUBLIC_API_BASE_URL?.trim() || DEFAULT_API_BASE_URL;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/consts.ts` around lines 4 - 9, Replace the nested ternary that computes NEW_API_BASE_URL with a clearer nullish-coalescing approach that also guards against empty strings: use the environment variable apiBaseUrlOverride (NEXT_PUBLIC_API_BASE_URL) after trimming and check for a non-empty value, otherwise fall back to the IS_PROD conditional defaults; update references to apiBaseUrlOverride and NEW_API_BASE_URL accordingly so the env value "" is treated as unset and the ternary nesting is removed for readability.lib/tasks/createTask.ts (2)
55-55: Defensive: verifydata.tasks[0]actually matchesTables<"scheduled_actions">.The function signature promises
ScheduledAction, but the runtime value is whatever the API returns — no validation is performed. For a client helper that feeds downstream type-safe code, consider a lightweight schema check (e.g. Zod) or at minimum assert the presence of required fields (id,artist_account_id, etc.) before returning. Otherwise a subtly-shaped API response becomes a hard-to-diagnoseundefinedread far from the call site.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/tasks/createTask.ts` at line 55, The return of data.tasks[0] in createTask (which is claimed to be a ScheduledAction) is not validated; add a lightweight runtime check before returning to ensure the object matches ScheduledAction (at minimum verify required fields like id and artist_account_id exist and have expected types). Implement this by either using a small Zod schema for ScheduledAction and parsing data.tasks[0] (e.g., scheduledActionSchema.parse) or by adding explicit assertions that required keys are present and of correct primitive types, and throw a clear error if validation fails so callers never receive an invalid value.
21-56: Request-cancellation & timeout are missing.
fetchhere has noAbortSignaland no timeout. In a UI flow a user may navigate away mid-request, leaving the promise to settle against an unmounted component; and a hung Recoup API call will block indefinitely. Accepting an optionalsignal?: AbortSignal(commonly threaded through from React Query / SWR / TanStack mutations) is a cheap resilience win:♻️ Thread an AbortSignal through
export async function createTask( accessToken: string, params: CreateTaskParams, + options?: { signal?: AbortSignal }, ): Promise<ScheduledAction> { const response = await fetch(`${getClientApiBaseUrl()}/api/tasks`, { method: "POST", + signal: options?.signal, headers: {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@lib/tasks/createTask.ts` around lines 21 - 56, The createTask function should accept an optional signal?: AbortSignal parameter and use it to enable request cancellation and a timeout; update the createTask signature to include signal?: AbortSignal, pass that signal into the fetch options, and implement a short configurable timeout by creating an AbortController inside createTask (tie its signal to the passed signal so an external cancel also aborts) and use it to abort the fetch after the timeout period; ensure you clean up any timers and prefer the passed-in signal when present so React Query/SWR can cancel the request.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@lib/consts.ts`:
- Around line 4-9: Restore and export the two missing constants
API_OVERRIDE_STORAGE_KEY and ACCOUNT_OVERRIDE_STORAGE_KEY from lib/consts.ts so
existing consumers compile; add definitions (e.g. const API_OVERRIDE_STORAGE_KEY
= 'apiOverride' and const ACCOUNT_OVERRIDE_STORAGE_KEY = 'accountOverride') and
export them alongside NEW_API_BASE_URL, ensuring the identifiers referenced by
getClientApiBaseUrl, ApiOverrideSync, getStoredAccountOverride,
setStoredAccountOverride, and clearStoredAccountOverride match exactly.
In `@lib/tasks/createTask.ts`:
- Around line 46-55: The code in createTask.ts currently types the POST response
as GetTasksResponse (from getTasks.ts) which is for the list endpoint; change
this to an endpoint-specific response type (e.g., CreateTaskResponse with shape
{ status: string; task: Task; error?: string }) or introduce a generic envelope
type (e.g., TaskEnvelope<T>) exported from getTasks.ts and use
TaskEnvelope<Task> here; update createTask.ts (and similarly updateTask.ts) to
import and use the new CreateTaskResponse/TaskEnvelope type, adjust the runtime
checks to read data.task instead of data.tasks, and throw errors from data.error
when present.
---
Nitpick comments:
In `@lib/consts.ts`:
- Around line 4-9: Replace the nested ternary that computes NEW_API_BASE_URL
with a clearer nullish-coalescing approach that also guards against empty
strings: use the environment variable apiBaseUrlOverride
(NEXT_PUBLIC_API_BASE_URL) after trimming and check for a non-empty value,
otherwise fall back to the IS_PROD conditional defaults; update references to
apiBaseUrlOverride and NEW_API_BASE_URL accordingly so the env value "" is
treated as unset and the ternary nesting is removed for readability.
In `@lib/tasks/createTask.ts`:
- Line 55: The return of data.tasks[0] in createTask (which is claimed to be a
ScheduledAction) is not validated; add a lightweight runtime check before
returning to ensure the object matches ScheduledAction (at minimum verify
required fields like id and artist_account_id exist and have expected types).
Implement this by either using a small Zod schema for ScheduledAction and
parsing data.tasks[0] (e.g., scheduledActionSchema.parse) or by adding explicit
assertions that required keys are present and of correct primitive types, and
throw a clear error if validation fails so callers never receive an invalid
value.
- Around line 21-56: The createTask function should accept an optional signal?:
AbortSignal parameter and use it to enable request cancellation and a timeout;
update the createTask signature to include signal?: AbortSignal, pass that
signal into the fetch options, and implement a short configurable timeout by
creating an AbortController inside createTask (tie its signal to the passed
signal so an external cancel also aborts) and use it to abort the fetch after
the timeout period; ensure you clean up any timers and prefer the passed-in
signal when present so React Query/SWR can cancel the request.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: dd954806-7643-4cee-96b3-380ef38f0e77
⛔ Files ignored due to path filters (1)
lib/tasks/__tests__/createTask.test.tsis excluded by!**/*.test.*and included bylib/**
📒 Files selected for processing (2)
lib/consts.tslib/tasks/createTask.ts
| const data: GetTasksResponse = await response.json(); | ||
| if (data.status === "error") { | ||
| throw new Error(data.error || "Unknown error occurred"); | ||
| } | ||
|
|
||
| if (!data.tasks || data.tasks.length === 0) { | ||
| throw new Error("API returned success but no task was created"); | ||
| } | ||
|
|
||
| return data.tasks[0]; |
There was a problem hiding this comment.
🛠️ Refactor suggestion | 🟠 Major
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Confirm the shape of GetTasksResponse and whether any dedicated create-response type exists.
fd -e ts getTasks.ts lib/tasks
rg -nP 'GetTasksResponse|CreateTaskResponse' --type=ts -C2Repository: recoupable/chat
Length of output: 1732
Replace GetTasksResponse with an endpoint-specific type to avoid conflating contracts.
GetTasksResponse is designed for the GET /api/tasks endpoint (returns { tasks: Task[] }), but it's being reused as the response type for POST and PATCH operations in createTask.ts and updateTask.ts. This couples distinct API contracts together. The create/update endpoints likely have different response shapes—returning a single task object is common REST convention—and using the list endpoint's type masks that difference.
Create a dedicated CreateTaskResponse type (e.g., { status, task: Task, error? }) or share a generic envelope (e.g., TaskEnvelope<T>) exported from getTasks.ts. Each endpoint should have its own contract type; the single-responsibility principle applies to types as much as functions.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@lib/tasks/createTask.ts` around lines 46 - 55, The code in createTask.ts
currently types the POST response as GetTasksResponse (from getTasks.ts) which
is for the list endpoint; change this to an endpoint-specific response type
(e.g., CreateTaskResponse with shape { status: string; task: Task; error?:
string }) or introduce a generic envelope type (e.g., TaskEnvelope<T>) exported
from getTasks.ts and use TaskEnvelope<Task> here; update createTask.ts (and
similarly updateTask.ts) to import and use the new
CreateTaskResponse/TaskEnvelope type, adjust the runtime checks to read
data.task instead of data.tasks, and throw errors from data.error when present.
- Introduced a new CreateTaskPage component for task creation, featuring a form with validation for title, prompt, schedule, and artist selection. - Updated TasksPage to include a "Create Task" button, enhancing navigation for users to create new tasks. - Implemented state management and error handling for form submissions, ensuring a smooth user experience.
There was a problem hiding this comment.
2 issues found across 3 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="components/TasksPage/CreateTaskPage.tsx">
<violation number="1" location="components/TasksPage/CreateTaskPage.tsx:28">
P1: Custom agent: **Code Structure and Size Limits for Readability and Single Responsibility**
At 228 lines this file is more than double the 100-line limit. Extract a `useCreateTaskForm` hook (state, validation, submit handler) into a separate file and keep this component focused on rendering. The `.coderabbit.yaml` path rule for `components/**/*.tsx` also calls for <200 lines and extracting custom hooks.</violation>
<violation number="2" location="components/TasksPage/CreateTaskPage.tsx:216">
P2: `disabled` prop has no effect on `<Button asChild>` wrapping a `<Link>`. The `<a>` element doesn't support `disabled`, and the `:disabled` CSS pseudo-class won't match it. During submission, the cancel link remains fully clickable and unstyled.
Consider conditionally rendering a plain `<Button>` (not `asChild`) when disabled, or using `aria-disabled` with `onClick={e => e.preventDefault()}` to block navigation.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.
…e new dependencies - Added @react-native-async-storage/async-storage version 3.0.2. - Added @valibot/to-json-schema version 1.6.0. - Added effect version 3.21.0. - Updated dependency versions in pnpm-lock.yaml to reflect the new additions and ensure compatibility.
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
components/TasksPage/CreateTaskPage.tsx (1)
60-106: Consider extracting validation for single-responsibility.
handleSubmitcurrently juggles validation, token retrieval, request dispatch, navigation, and error surfacing. Pulling the field-validation block into a smallvalidate(...)helper (returningFormErrors) would tighten the handler's responsibility and make the rules independently testable. Not blocking — happy to leave as-is if you'd rather keep it inline.As per coding guidelines: "Each function should have a single responsibility and clear naming".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@components/TasksPage/CreateTaskPage.tsx` around lines 60 - 106, Extract the inline field-validation in handleSubmit into a new helper function named validate that accepts the form fields (title, prompt, schedule, artistAccountId, model, accountIdOverride as needed) and returns a FormErrors object; then have handleSubmit call validate, setErrors(nextErrors) and setSubmitError(null) based on the returned errors and early-return if any keys exist — leaving token retrieval, createTask call, navigation and error handling in handleSubmit unchanged. Ensure validate is exported/typed as returning FormErrors so it can be unit-tested independently and update references in handleSubmit (still using setIsSubmitting, getAccessToken, createTask, toast, router) to use the helper.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@components/TasksPage/CreateTaskPage.tsx`:
- Around line 131-200: Add accessible error wiring: for each field
(Input/Textarea/Select) — task-title, task-prompt, task-schedule, task-artist —
set aria-invalid={!!errors.<field>} and set aria-describedby to a stable id when
an error exists (e.g. title-error, prompt-error, schedule-error, artist-error).
Render the corresponding error <p> with the matching id and ensure
aria-describedby is omitted or null when no error is present so screen readers
only reference existing messages; apply the same pattern to the SelectTrigger
used for task-artist.
- Around line 216-218: The Cancel control currently uses <Button asChild>
wrapping the Next.js <Link> (Link href="/tasks") so the disabled prop
(isSubmitting) is ineffective; change it so when isSubmitting is true you render
a real <button disabled> (e.g., a Button without asChild) to prevent
interaction, and when not submitting render the <Button asChild> with <Link
href="/tasks"> as before, or alternatively replace the Link variant with a
regular Button that calls router.push('/tasks') on click and respects disabled;
update the component where Button asChild and isSubmitting are used (the Cancel
button rendering) to implement one of these two approaches.
---
Nitpick comments:
In `@components/TasksPage/CreateTaskPage.tsx`:
- Around line 60-106: Extract the inline field-validation in handleSubmit into a
new helper function named validate that accepts the form fields (title, prompt,
schedule, artistAccountId, model, accountIdOverride as needed) and returns a
FormErrors object; then have handleSubmit call validate, setErrors(nextErrors)
and setSubmitError(null) based on the returned errors and early-return if any
keys exist — leaving token retrieval, createTask call, navigation and error
handling in handleSubmit unchanged. Ensure validate is exported/typed as
returning FormErrors so it can be unit-tested independently and update
references in handleSubmit (still using setIsSubmitting, getAccessToken,
createTask, toast, router) to use the helper.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: fe7f6485-058f-4f92-ae7b-11da9189aa9f
⛔ Files ignored due to path filters (2)
package.jsonis excluded by none and included by nonepnpm-lock.yamlis excluded by!**/pnpm-lock.yamland included by none
📒 Files selected for processing (3)
app/tasks/new/page.tsxcomponents/TasksPage/CreateTaskPage.tsxcomponents/TasksPage/TasksPage.tsx
- Introduced API_OVERRIDE_STORAGE_KEY and ACCOUNT_OVERRIDE_STORAGE_KEY constants for improved API management. - Updated DEFAULT_MODEL to "openai/gpt-5-mini" for better performance. - Added a comprehensive PROMPT_SUGGESTIONS_SYSTEM_PROMPT to guide users in generating actionable follow-up prompts related to music industry insights and marketing strategies.
There was a problem hiding this comment.
3 issues found across 2 files (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="package.json">
<violation number="1" location="package.json:49">
P1: Custom agent: **Flag AI Slop and Fabricated Changes**
This dependency is a React Native library with no imports anywhere in the codebase. Adding a mobile-platform storage package to a Next.js web app strongly suggests AI-generated dependency additions that don't correspond to any actual implementation. Remove unused dependencies.</violation>
<violation number="2" location="package.json:57">
P2: Custom agent: **Flag AI Slop and Fabricated Changes**
Unused dependency — `@valibot/to-json-schema` is not imported anywhere in the codebase. Remove it to avoid bloating `node_modules` with unused packages.</violation>
<violation number="3" location="package.json:69">
P1: Custom agent: **Flag AI Slop and Fabricated Changes**
Unused dependency — `effect` is a heavyweight FP framework not imported anywhere in the codebase. Adding large unused dependencies inflates bundle/install size for no benefit.</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.
- Added cron expression validation to ensure correct scheduling input. - Introduced schedule presets for easier task scheduling. - Implemented a dropdown for model selection, allowing users to choose from available models or use a default option. - Updated UI to provide feedback on cron expression validity and model loading status.
There was a problem hiding this comment.
1 issue found across 1 file (changes from recent commits).
Prompt for AI agents (unresolved issues)
Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.
<file name="components/TasksPage/CreateTaskPage.tsx">
<violation number="1" location="components/TasksPage/CreateTaskPage.tsx:8">
P1: Custom agent: **Code Structure and Size Limits for Readability and Single Responsibility**
At 339 lines this component is over 3× the 100-line limit. The new code adds three independent concerns — cron validation, schedule-preset selection, and model-selection dropdown — all inlined in one file. Extract them into focused units:
- `validateCronExpression` → `lib/tasks/validateCronExpression.ts`
- Schedule preset picker + cron preview → a `ScheduleField` component
- Model dropdown + loading/error states → a `ModelField` component
This aligns with the repo's `.coderabbit.yaml` guidance: _"one responsibility per component; <200 lines; extract custom hooks."_</violation>
</file>
Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review, or fix all with cubic.
- Added a label to show the currently configured default model in the model selection dropdown. - Enhanced the UI to include a description of the default model below the model selection, improving user clarity on the selected model option.
…t wrapper Both paths into GatewayModelSelect were ultimately hitting the same useAvailableModels() hook (same endpoint, same React Query key, same staleTime) — the chat path just wrapped it through VercelChatContext. Drop availableModels / isLoading / isError as props and call the hook inside GatewayModelSelect. React Query's queryKey dedupe means zero extra requests. - GatewayModelSelect: calls useAvailableModels() internally - ModelSelect: drops availableModels forwarding - EditableGatewayModelSelect: deleted — was a 15-line wrapper whose only purpose was forwarding availableModels and setting default triggerId/hintId, both of which callers passed explicitly anyway - TasksPage/ModelField + TaskDetailsDialogContent: import GatewayModelSelect directly One exported component, two callers, no duplicated data fetching. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…ULT_MODEL
The task form's initial model state was "" — which forced GatewayModelSelect
to carry a "Use default" row (includeDefaultOption) as the only UI affordance
for representing or returning to that empty string. Seed the form with
DEFAULT_MODEL instead (same as the chat), and the "Use default" concept is no
longer needed: the default model simply appears in the list like any other.
Then GatewayModelSelect collapses to two props (value, onValueChange).
Form-mode concerns — label, triggerId, hintId, disabled — move out of the
component; TaskDetailsDialogContent's edit branch now wraps the select with
its own <label> so it matches the non-edit branch. ModelField is a trivial
4-line wrapper matching its sibling *Field components.
- hooks/useCreateTaskForm.ts: initial model = DEFAULT_MODEL
- GatewayModelSelect: delete includeDefaultOption, DEFAULT_OPTION, form-mode
label/triggerId/hintId/isError/disabled branches, defaultModelLabel useMemo,
hint paragraph — props are now just {value, onValueChange}
- ModelField: drop all form-mode props
- TaskDetailsDialogContent: drop form-mode props, wrap with its own <label>
Trade-off: new tasks now persist a concrete model id (e.g.
"openai/gpt-5.4-mini") instead of "". If DEFAULT_MODEL changes later, existing
tasks stay pinned to the old value until manually edited. Existing tasks with
"" in the DB continue to work — backend interprets them as "use default".
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
| const CronEditor = dynamic( | ||
| () => import("@/components/CronEditor").then((m) => ({ default: m.CronEditor })), | ||
| { ssr: false }, | ||
| ); |
| const CronEditor = dynamic( | ||
| () => import("@/components/CronEditor").then((mod) => mod.CronEditor), | ||
| { ssr: false }, | ||
| ); |
There was a problem hiding this comment.
KISS principle
- do not dynamically import components unnecessarily
This commit deletes outdated components and hooks related to task creation, including CreateTaskPage, CreateTaskFormBody, and various field components. The removal streamlines the codebase and eliminates unused functionality, paving the way for a more modular and maintainable task creation process. - Deleted components: CreateTaskPage, CreateTaskFormBody, CreateTaskArtistField, CreateTaskFormActions, CreateTaskPromptField, CreateTaskTitleField, ModelField, ScheduleField, and CreateTaskPageHeader. - Removed associated hooks and context providers to simplify the task creation logic.
Changed the default prompt in the useCreateTask hook from an empty string to a more descriptive placeholder: "New task — replace with your instructions." This enhancement improves user guidance during task creation.
…ask creation flow - Removed unnecessary props from TaskDetailsDialog, including defaultOpen and onClose, to streamline its usage. - Updated the useTaskDetailsDialog hook to initialize dialog state without defaultOpen. - Added a data attribute for task dialog triggers in TasksList to improve interaction handling. - Refactored the task creation logic in useCreateTask to utilize React Query's mutation for better state management and error handling, enhancing user experience during task creation.
| defaultOpen = false, | ||
| }: UseTaskDetailsDialogParams) => { | ||
| const [isDialogOpen, setIsDialogOpen] = useState(false); | ||
| const [isDialogOpen, setIsDialogOpen] = useState(defaultOpen); |
There was a problem hiding this comment.
KISS / YAGNI - Why are you allowing defaultOpen to be a prop?
| const [isCreating, setIsCreating] = useState(false); | ||
| const [createdTask, setCreatedTask] = useState<Task | null>(null); | ||
|
|
||
| const handleCreateTask = async () => { |
There was a problem hiding this comment.
KISS - Tanstack
- actual: manually defining loading states and result states. Not using Tanstack useMutation.
- required: use tanStack useMutation.
| <Button | ||
| onClick={() => handleCreateTask()} | ||
| disabled={isCreating} | ||
| className="w-full sm:w-auto" | ||
| > | ||
| {isCreating ? "Creating..." : "Create Task"} | ||
| </Button> |
There was a problem hiding this comment.
OCP
- actual: added net new button code to the existing TaskPage.
- required: new file for the button + hook.
There was a problem hiding this comment.
YAGNI - are these file changes necessary for this PR?
- why not revert this change and focus on the New Task UX?
| { | ||
| id: DEFAULT_MODEL, | ||
| displayName: "GPT-5.4 Mini", | ||
| displayName: "GPT-5 Mini", |
There was a problem hiding this comment.
KISS - why are you changing the displayName in this PR?
There was a problem hiding this comment.
KISS - same question here, why are these changes required for the New Task flow? Why not remove them?
There was a problem hiding this comment.
KISS - What is the purpose of this file?
- What happens if we remove it?
…eprecated components - Replaced the GatewayModelSelect component with a more streamlined implementation directly in ModelSelect, enhancing the model selection process. - Updated the TaskDetailsDialogContent to utilize the new model selection approach, improving consistency across components. - Removed the CRON_SIMPLE_PRESETS and related legacy code, replacing it with a new PRESET_SCHEDULES array for better maintainability. - Simplified the webpack configuration in next.config.mjs by removing unnecessary aliasing and stubs, optimizing the build process.
There was a problem hiding this comment.
KISS - why are any changes needed to this file?
| <div className="mb-6 flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between"> | ||
| <div> | ||
| <h1 className="text-left font-heading text-3xl font-bold dark:text-white mb-4"> | ||
| Tasks | ||
| </h1> | ||
| <p className="text-lg text-muted-foreground text-left font-light font-sans max-w-2xl"> | ||
| View and manage all the tasks for your selected artist. | ||
| </p> | ||
| </div> |
There was a problem hiding this comment.
SRP
- actual: new
divcontaining aHeadersection defined within the Page component. - required: new component file for the header div you added.
There was a problem hiding this comment.
KISS - Why are changes needed to this file?
There was a problem hiding this comment.
KISS - Why are changes required to this file?
There was a problem hiding this comment.
KISS - Why are changes required to this file?
…agement - Introduced a new TasksPageHeader component to encapsulate the header logic, improving readability and maintainability. - Updated the TasksPage to utilize the new TasksPageHeader, streamlining the layout and reducing clutter. - Refactored ModelSelect imports for consistency and clarity. - Simplified the webpack configuration in next.config.mjs by removing unnecessary stubs, optimizing the build process. - Updated pnpm-lock.yaml to reflect dependency changes and ensure consistency across the project.
- Improved the task creation flow by integrating a new dynamic CronEditor, replacing the outdated CronInput and schedulePresets. - Updated ModelField to utilize EditableGatewayModelSelect for streamlined model selection. - Removed legacy code and unused hooks to simplify the codebase and improve maintainability. - Enhanced ScheduleField for better management of cron expressions, improving user experience.
…-chat-align-task-creation-client-with-hardened-post-apitasks # Conflicts: # lib/tools/getMcpTools.ts
There was a problem hiding this comment.
KISS - Why are changes to this file necessary?
There was a problem hiding this comment.
KISS - Why are changes to this file necessary?
Both files were added to this branch as empty placeholders and aren't present on `test`. Reverting by deletion so the PR stays focused. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…view The pre-validation guard referenced a now-deleted module. cronstrue's try/catch already handles invalid cron expressions — the guard was redundant. Removes the broken import and simplifies the function. Fixes the 2 failing getCronHumanPreview tests. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>


Summary by CodeRabbit
New Features
Chores