Skip to content

fix(ai): preserve multiple recurring tasks from conversational input - #518

Open
imlililili wants to merge 8 commits into
mainfrom
recurring-task-regen
Open

imlililili wants to merge 8 commits into
mainfrom
recurring-task-regen

Conversation

@imlililili

Copy link
Copy Markdown
Collaborator

Summary

Adds conversational support for creating multiple recurring tasks from one request, plus updating and removing recurring task drafts. It also normalizes recurring patterns to prevent invalid weekly, monthly, or date combinations and extends the evaluation harness and automated tests to cover these mutations.

Release note

You can now create multiple recurring tasks in one conversation and correct or remove them by speaking naturally.

Status:

  • User-facing — announce it
  • Beta / partial — announce, but tagged as beta
  • Hidden in production (feature-flagged / not enabled for users) — don't announce
  • Internal only (refactor / infra / tests / CI / deps) — don't announce

@github-actions

github-actions Bot commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Test Results

133 tests   133 ✅  10s ⏱️
  1 suites    0 💤
  1 files      0 ❌

Results for commit 6014a64.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Aug 15, 2026

Copy link
Copy Markdown
Contributor
Package Line Rate Branch Rate Complexity Health
BlotzTask 4% 35% 2906
BlotzTask 4% 35% 2906
Summary 4% (4950 / 114242) 35% (1086 / 3102) 5812

@imlililili
imlililili marked this pull request as ready for review August 15, 2026 15:04
Comment on lines +175 to +178
if (task.TimeType == TaskTimeType.SingleTime)
{
task.TemplateEndTime = task.TemplateStartTime;
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems like if I changed the single time to range time, the timetype is still keep single time

Interval = interval < 1 ? 1 : interval,
DaysOfWeek = frequency == RecurrenceFrequency.Weekly && weeklyMask != 0 ? weeklyMask : null,
DayOfMonth = frequency == RecurrenceFrequency.Monthly ? dayOfMonth : null,
StartDate = startDate,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if we have deleted startDate here, why do we still need startDate in createRecurringTask?

Comment on lines +416 to +450
public class RecurringTaskInput
{
[Description("Short title for exactly one independently completable action")]
public required string Title { get; init; }

[Description("Description or empty")]
public required string Description { get; init; }

[Description("SingleTime for a moment with no duration; RangeTime for a start and end time")]
public required TaskTimeType TimeType { get; init; }

[Description("Work, Life, Learning, or Health")]
public required LabelNameEnum Label { get; init; }

[Description("First occurrence start as local time yyyy-MM-ddTHH:mm:ss")]
public required DateTime TemplateStartTime { get; init; }

[Description("First occurrence end as local time yyyy-MM-ddTHH:mm:ss")]
public required DateTime TemplateEndTime { get; init; }

[Description("Daily, Weekly, Monthly, or Yearly")]
public required RecurrenceFrequency Frequency { get; init; }

[Description("Repeat every N periods; use 1 unless the user says otherwise")]
public int Interval { get; init; } = 1;

[Description("Required named weekdays for Weekly; empty otherwise")]
public DayOfWeek[] DaysOfWeek { get; init; } = [];

[Description("Required day 1-31 for Monthly; null otherwise")]
public int? DayOfMonth { get; init; }

[Description("Optional last recurrence date yyyy-MM-dd; null means open-ended")]
public DateOnly? EndDate { get; init; }
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems some descriptions here have drifted from CreateRecurringTask's parameters, some may too easy, pls check again. Maybe you can follow the descriptions of createTask and createTasks.

frequency == RecurrenceFrequency.Weekly ? weeklyMask : null,
frequency == RecurrenceFrequency.Monthly ? normalizedDayOfMonth : null,
startDate,
endDate < startDate ? startDate : endDate);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why we need to change the endDate to startDate? I think if endDate < startDate, maybe it should be throw by the validation

"interval": 1
}
]
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems missing a check for update the single time to duration?

}

var updatedFrequency = frequency ?? task.Frequency;
var updatedDays = daysOfWeek ?? FromWeeklyBitmask(task.DaysOfWeek);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only null counts as "leave unchanged" here, but models often send an empty array for an array parameter they mean to omit. An empty array makes weeklyMask 0, and NormalizeRecurringPattern then fills it from templateStartTime.DayOfWeek — so "rename my gym" can silently turn a Mon/Wed/Fri task into Monday only, which is the opposite of the PBI's "updates only DaysOfWeek; all other fields unchanged".

Suggest daysOfWeek is { Length: > 0 } ? daysOfWeek : FromWeeklyBitmask(task.DaysOfWeek), plus a test that passes daysOfWeek: [].

}
}

public static void CheckRecurringMutation(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check never runs today: quality-check-cases.json has no case using recurringMutation (or the new setupInputs / durationMinutes), and that file is not touched by this PR.

The PBI asks for the scoring and "cases for edit/remove phrasings". Could you add cases for "change gym to Tuesdays", "stop the weekly standup" and "make gym go on forever"? Without them the new prompt rules have no regression cover at the eval level — the unit tests cover the tools, but not what the model actually picks.

"expo-build-properties",
{
ios: {
usePrecompiledModules: false,

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This iOS build setting looks unrelated to the recurring-task work, and the PBI scopes this one as "Backend only". Disabling precompiled modules also makes iOS builds noticeably slower.

Was it needed to unblock a local build? If so it is worth its own PR, or at least a line in the description, so nobody reverts it by accident later.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants