Skip to content

Feat/scheduler daily at#215

Open
mattnico wants to merge 8 commits intompfaffenberger:mainfrom
mattnico:feat/scheduler-daily-at
Open

Feat/scheduler daily at#215
mattnico wants to merge 8 commits intompfaffenberger:mainfrom
mattnico:feat/scheduler-daily-at

Conversation

@mattnico
Copy link
Copy Markdown
Contributor

@mattnico mattnico commented Feb 28, 2026

What

Adds a new daily_at schedule type that fires a scheduled task at one or more
specific wall-clock times each day (e.g. 09:00, or 09:00,17:30).

Why

The existing schedule types (interval, hourly, daily, cron) don't let
users say "run this at 9am". The daily_at type fills that gap with a simple
HH:MM format — no cron syntax required.

Changes

code_puppy/scheduler/daemon.py

  • parse_daily_at_times(schedule_value) — parses a comma-separated string
    of HH:MM times into (hour, minute) tuples. Invalid entries are skipped
    with a warning rather than crashing the daemon.
  • should_run_task() — new daily_at branch fires if any target time has
    passed today and last_run is before that target. Restart-safe: if the daemon
    was down at 09:00 and restarts at 09:15, it still fires.

code_puppy/scheduler/config.py

  • Updated schedule_type field comment to document daily_at as a valid value.

code_puppy/plugins/scheduler/scheduler_wizard.py

  • Replaced the old "Daily" menu option with "Daily at specific time(s)...".
  • Collects time(s) via a TextInputMenu, validates each HH:MM entry, strips
    invalid ones with a warning, and aborts if none are valid.
  • Summary display renders "daily at 09:00,17:30" instead of the raw internal
    type/value string.

Tests

tests/scheduler/test_daily_at.py (new, 31 tests)

Covers parse_daily_at_times() and all branches of should_run_task() for
the daily_at type. All wall-clock comparisons use a pinned NOW constant so
tests are never flaky.

Group What's covered
Parser Single/multiple times, whitespace, midnight, 23:59, invalid formats, empty string, warns on bad input
Basic fire/no-fire Never-run fires after target; future target doesn't fire; fires exactly at boundary; doesn't fire 1s before
last_run logic Already ran today → no re-fire; ran yesterday → fires; restart-safe catch-up; ran before target same day → fires
Multiple times First due + second future; first serviced + second future; second becomes due; all future; both past
Edge cases Disabled task; all-invalid schedule; mix valid/invalid; midnight target

tests/plugins/test_scheduler_wizard.py (6 new tests + 1 fix)

Test What it guards
test_daily_at_single_time Happy path — one HH:MMschedule_type="daily_at"
test_daily_at_multiple_times Comma list is preserved verbatim in schedule_value
test_daily_at_cancel_time_input None from TextInputMenu → wizard returns None
test_daily_at_all_invalid_times All-bad input → None
test_daily_at_strips_invalid_times Bad entries dropped, valid ones kept
test_daily_at_summary_display "daily at HH:MM" appears in stdout; raw "daily_at" string does not leak
test_wizard_code_puppy_first (fix) Was referencing "Daily" which was removed from schedule_map; updated to "Every hour"

Summary by CodeRabbit

  • New Features

    • Added "Daily at specific time(s)..." scheduling to enter one or more validated HH:MM times.
  • Enhancements

    • Renamed display option to "Daily (every 24h)"; summaries now show "daily at HH:MM" and scheduling better handles missed daily runs.
  • Documentation

    • Config docs updated to list "daily_at" as a valid schedule type.
  • Tests

    • Expanded unit and wizard tests for parsing, scheduling behavior, summaries, validation, and edge cases.

Matt Nicolaysen and others added 4 commits February 27, 2026 20:18
- New schedule_type='daily_at' with schedule_value='HH:MM' or 'HH:MM,HH:MM,...'
- Daemon fires task if any target time has passed today and last_run predates it
- Restart-safe: daemon downtime at fire-time still fires on next wakeup
- Wizard: new 'Daily at specific time(s)...' menu option with HH:MM validation
- Wizard: friendly summary display ('daily at 09:00,17:00')
- cron remains as a stub with warning (would need croniter)
Covers parse_daily_at_times() and the daily_at branch of should_run_task():
- Single/multiple/whitespace-padded time parsing
- Edge cases: midnight, 23:59, empty string, invalid formats
- Invalid entries skipped with warning, valid entries still used
- Never-run task fires after target, not before (boundary inclusive)
- Does not re-fire after running today
- Fires when last_run was yesterday (restart-safe)
- Fires when daemon missed the window and caught up later
- last_run before target but same day still triggers
- Multi-time: first due + second future, first ran + second future/due
- Disabled tasks never fire
- All-invalid schedule_value returns False with warning
- Midnight target edge case
- Fix test_wizard_code_puppy_first: 'Daily' was removed from
  schedule_map when daily_at replaced it; switched to 'Every hour'
- Add test_daily_at_single_time: single HH:MM → schedule_type=daily_at
- Add test_daily_at_multiple_times: comma list preserved verbatim
- Add test_daily_at_cancel_time_input: None from TextInputMenu → None
- Add test_daily_at_all_invalid_times: no valid times → None
- Add test_daily_at_strips_invalid_times: bad entries dropped, valid kept
- Add test_daily_at_summary_display: confirms 'daily at HH:MM' in
  stdout and raw 'daily_at' type string does not leak into summary
…t prompt

Add '(24-hour clock: 1:00 PM = 13:00, 5:30 PM = 17:30, midnight = 00:00)'
hint so users who don't think natively in 24-hour time don't have to guess.
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Feb 28, 2026

Warning

Rate limit exceeded

@mattnico has exceeded the limit for the number of commits that can be reviewed per hour. Please wait 9 minutes and 40 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between f71d105 and f252021.

📒 Files selected for processing (4)
  • code_puppy/plugins/scheduler/scheduler_wizard.py
  • code_puppy/scheduler/daemon.py
  • code_puppy/scheduler/time_utils.py
  • tests/scheduler/test_time_utils.py
📝 Walkthrough

Walkthrough

Adds a "daily_at" schedule type: the wizard collects one or more HH:MM times (validated, deduplicated, canonicalized, stored comma-separated) and the daemon parses those times and compares them to now and last_run to decide restart-safe task execution.

Changes

Cohort / File(s) Summary
Core scheduler
code_puppy/scheduler/config.py, code_puppy/scheduler/daemon.py
Documented schedule_type now includes "daily_at". Added parse_daily_at_times(schedule_value: str) -> list to parse/validate comma-separated HH:MM values. Extended should_run_task(...) with a "daily_at" branch that computes target times, compares to now and last_run, warns on invalid entries, and preserves restart-safety.
Wizard UI
code_puppy/plugins/scheduler/scheduler_wizard.py
Replaced display label "Daily" with "Daily (every 24h)" and added "Daily at specific time(s)..." flow: prompts for one-or-more HH:MM times, validates/normalizes/deduplicates inputs, cancels on no valid times, sets schedule_type = "daily_at" and schedule_value to a comma-joined list, and updates task summary to show "daily at <times>".
Tests
tests/plugins/test_scheduler_wizard.py, tests/scheduler/test_daily_at.py
Updated wizard tests to reflect new label and daily-at interactions. Added tests/scheduler/test_daily_at.py with comprehensive unit tests for parse_daily_at_times and daily_at behavior in should_run_task (single/multiple times, whitespace/edge cases, invalid inputs, last_run/restart/catch-up conditions, midnight handling).

Sequence Diagram(s)

sequenceDiagram
  participant User as "User"
  participant Wizard as "Scheduler Wizard\n(code_puppy/plugins/.../scheduler_wizard.py)"
  participant Config as "ScheduledTask\n(code_puppy/scheduler/config.py)"
  participant Daemon as "Scheduler Daemon\n(code_puppy/scheduler/daemon.py)"

  User->>Wizard: choose "Daily at specific time(s)..."
  Wizard->>User: prompt for HH:MM times (one or more)
  User-->>Wizard: submits "08:00, 18:30" or cancels
  Wizard->>Wizard: validate, normalize, dedupe times
  Wizard->>Config: create/update ScheduledTask(schedule_type="daily_at", schedule_value="08:00,18:30")
  Daemon->>Config: load ScheduledTask
  Daemon->>Daemon: parse_daily_at_times("08:00,18:30") -> [(8,0),(18,30)]
  Daemon->>Daemon: compute target datetimes, compare to now & last_run
  Daemon-->>Config: trigger task execution if a target is due
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I nibbled times both late and early,
I parsed each HH:MM so pearly,
I trimmed and deduped the list with care,
Now tasks at dawn and dusk hop into the air—
A happy scheduler, light as a hare!

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 68.75% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Feat/scheduler daily at' is partially related to the changeset. It indicates a feature addition for scheduler daily functionality, which aligns with the main objective, but lacks clarity and specificity—it uses abbreviated naming conventions rather than describing the actual feature being added. Consider a more descriptive title that clearly explains the feature, such as 'Add daily_at schedule type for tasks at specific times' or 'Support scheduling tasks at specific wall-clock times per day'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@mattnico mattnico marked this pull request as ready for review February 28, 2026 02:35
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@code_puppy/scheduler/daemon.py`:
- Around line 28-46: The docstring for parse_daily_at_times is inaccurate: it
says invalid entries are "silently skipped" but the function prints a warning
for each invalid entry; update the docstring to state that invalid entries are
skipped and a warning is printed (e.g., "Invalid entries are skipped and a
warning is printed using print()") and mention the format/behavior consistently
with the existing implementation that prints "[Scheduler] Warning: Invalid time
'{entry}' in daily_at schedule, skipping." to aid future maintainers.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d61d669 and 88f3859.

📒 Files selected for processing (5)
  • code_puppy/plugins/scheduler/scheduler_wizard.py
  • code_puppy/scheduler/config.py
  • code_puppy/scheduler/daemon.py
  • tests/plugins/test_scheduler_wizard.py
  • tests/scheduler/test_daily_at.py

Comment thread code_puppy/scheduler/daemon.py Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
tests/plugins/test_scheduler_wizard.py (1)

595-631: Add one case for blank time input using the default value.

A dedicated test for empty user input ("") would lock in the default-time behavior (09:00) explicitly.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/plugins/test_scheduler_wizard.py` around lines 595 - 631, Add a new
unit test that mirrors test_daily_at_single_time but sets the TextInputMenu for
the time (the second text_instances entry) to return an empty string ("") to
assert the wizard uses the default "09:00"; specifically, call
create_task_wizard with mocked TextInputMenu instances (first for name, second
for blank time, third for working_dir), SelectionMenu returning "Daily at
specific time(s)..." and model/agent mocks as in existing tests, then assert
result["schedule_type"] == "daily_at" and result["schedule_value"] == "09:00".
code_puppy/plugins/scheduler/scheduler_wizard.py (1)

247-270: Consider normalizing and de-duplicating accepted times before storage.

This keeps schedule_value canonical (HH:MM) and avoids repeated times in persisted config.

♻️ Suggested refinement
-        valid = []
+        valid = []
+        seen = set()
         for entry in entries:
             try:
-                datetime.strptime(entry, "%H:%M")  # noqa: DTZ007
-                valid.append(entry)
+                normalized = datetime.strptime(entry, "%H:%M").strftime("%H:%M")  # noqa: DTZ007
+                if normalized not in seen:
+                    seen.add(normalized)
+                    valid.append(normalized)
             except ValueError:
                 print(f"  ⚠️  Skipping invalid time: '{entry}' (expected HH:MM)")
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@code_puppy/plugins/scheduler/scheduler_wizard.py` around lines 247 - 270, In
the "Daily at specific time(s)..." branch, after validating entries (variables:
entries, valid), normalize each accepted time by parsing with datetime.strptime
and reformatting with strftime("%H:%M"), deduplicate them (e.g., use a set),
sort chronologically, and then set schedule_value to the canonical comma-joined
string of these normalized times (replace the current ",".join(valid)
assignment); keep schedule_type = "daily_at" unchanged and ensure empty-result
handling remains the same.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@code_puppy/plugins/scheduler/scheduler_wizard.py`:
- Around line 247-270: In the "Daily at specific time(s)..." branch, after
validating entries (variables: entries, valid), normalize each accepted time by
parsing with datetime.strptime and reformatting with strftime("%H:%M"),
deduplicate them (e.g., use a set), sort chronologically, and then set
schedule_value to the canonical comma-joined string of these normalized times
(replace the current ",".join(valid) assignment); keep schedule_type =
"daily_at" unchanged and ensure empty-result handling remains the same.

In `@tests/plugins/test_scheduler_wizard.py`:
- Around line 595-631: Add a new unit test that mirrors
test_daily_at_single_time but sets the TextInputMenu for the time (the second
text_instances entry) to return an empty string ("") to assert the wizard uses
the default "09:00"; specifically, call create_task_wizard with mocked
TextInputMenu instances (first for name, second for blank time, third for
working_dir), SelectionMenu returning "Daily at specific time(s)..." and
model/agent mocks as in existing tests, then assert result["schedule_type"] ==
"daily_at" and result["schedule_value"] == "09:00".

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 88f3859 and 19d3433.

📒 Files selected for processing (3)
  • code_puppy/plugins/scheduler/scheduler_wizard.py
  • code_puppy/scheduler/daemon.py
  • tests/plugins/test_scheduler_wizard.py
🚧 Files skipped from review as they are similar to previous changes (1)
  • code_puppy/scheduler/daemon.py

Copy link
Copy Markdown
Collaborator

@nhicks00 nhicks00 left a comment

Choose a reason for hiding this comment

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

  • The old "Daily" option (run every 24h) got removed from the wizard — was that intentional? Existing daily tasks still work in the daemon but users can't create new ones through the wizard anymore. Should both
    options coexist, or is this a deliberate replacement?

  • daily_at introduces wall-clock time semantics into a scheduler that's entirely timezone-naive (datetime.now() without tz=). For intervals that's fine, but "run at 09:00" is inherently timezone-dependent. Have
    you thought about at least dropping a code comment on the daily_at branch in should_run_task() acknowledging the naive-datetime limitation? Not asking you to solve TZ support here, just document it.

  • parse_daily_at_times docstring says "Invalid entries are silently skipped" but the implementation prints a [Scheduler] Warning: — update the docstring to match. (CodeRabbit flagged this too, +1 on their inline
    comment.)

  • Normalize times with strftime("%H:%M") after parsing and deduplicate — 9:00,09:00 would store duplicates in the config as-is. Won't cause double-firing but it's messy in persisted state. (Same as CodeRabbit's
    suggestion on the wizard.)

  • Both CI failures (ruff format + pytest) are pre-existing on main — unrelated files, not introduced by this PR.

- Restore 'Daily (every 24h)' wizard option — it was accidentally dropped
  when daily_at was introduced; interval-based daily tasks still work in
  the daemon but users could no longer create new ones via the wizard
- Fix parse_daily_at_times docstring: 'silently skipped' was wrong —
  the implementation has always printed a [Scheduler] Warning to stdout
- Add TIMEZONE NOTE comment to the daily_at branch in should_run_task()
  acknowledging that datetime.now() is naive (system local time) and
  that DST / tzdata changes will shift fire times accordingly
- Normalise times to HH:MM canonical form via strftime after parsing
  and deduplicate — '9:00,09:00,17:00,17:00' now stores as '09:00,17:00'
- Tests: add test_daily_at_normalises_single_digit_hour,
  test_daily_at_deduplicates_times, and Daily (every 24h) to
  test_schedule_map parametrize (75 tests, all green)
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
code_puppy/plugins/scheduler/scheduler_wizard.py (1)

259-271: Consider centralizing HH:MM parsing/validation to avoid rule drift.

Wizard and daemon each implement time parsing separately. Extracting a shared helper (e.g., under code_puppy/scheduler) would reduce maintenance risk if validation rules evolve.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@code_puppy/plugins/scheduler/scheduler_wizard.py` around lines 259 - 271, The
time-parsing/deduplication logic in scheduler_wizard.py (variables raw_times,
entries, seen, valid and the datetime.strptime("%H:%M") usage producing
normalised values) is duplicated elsewhere; extract it into a shared helper
(e.g., a function named parse_times_hhmm that accepts a raw comma-separated
string and returns a deduplicated list of canonical "HH:MM" strings), move it
into the common scheduler module, and replace the inline loop in
scheduler_wizard.py (and the daemon implementation) to call that helper; ensure
the helper preserves the current behavior (strip entries, ignore empty/invalid
values, normalize with t.strftime("%H:%M"), dedupe while preserving order, and
surface/return errors or skip invalid entries consistently).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@code_puppy/scheduler/daemon.py`:
- Around line 120-123: The daily_at logic only checks targets for today, so if
last_run is before yesterday and the daemon restarts before today's first target
it won’t catch missed runs; update the daily_at check (the loop that iterates
over times and computes target using now.replace with hour/minute) to also
consider the same targets on the previous day (or, more robustly, consider
targets in the past 24 hours) by creating candidate targets for now and now - 1
day and returning True if any candidate target <= now and (last_run is None or
last_run < candidate_target); keep uses of now, last_run, times, and target to
locate and modify the code.

---

Nitpick comments:
In `@code_puppy/plugins/scheduler/scheduler_wizard.py`:
- Around line 259-271: The time-parsing/deduplication logic in
scheduler_wizard.py (variables raw_times, entries, seen, valid and the
datetime.strptime("%H:%M") usage producing normalised values) is duplicated
elsewhere; extract it into a shared helper (e.g., a function named
parse_times_hhmm that accepts a raw comma-separated string and returns a
deduplicated list of canonical "HH:MM" strings), move it into the common
scheduler module, and replace the inline loop in scheduler_wizard.py (and the
daemon implementation) to call that helper; ensure the helper preserves the
current behavior (strip entries, ignore empty/invalid values, normalize with
t.strftime("%H:%M"), dedupe while preserving order, and surface/return errors or
skip invalid entries consistently).

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 19d3433 and a4bcb37.

📒 Files selected for processing (3)
  • code_puppy/plugins/scheduler/scheduler_wizard.py
  • code_puppy/scheduler/daemon.py
  • tests/plugins/test_scheduler_wizard.py

Comment thread code_puppy/scheduler/daemon.py Outdated
Matt Nicolaysen added 2 commits February 28, 2026 13:18
…ours

The original logic only evaluated targets against today's date, so if the
daemon was down overnight and restarted before today's first target time,
any missed run from yesterday was silently dropped.

Fix: for each scheduled HH:MM, check both today's and yesterday's candidate
targets. Return True if any candidate is in the past and last_run hasn't
reached it yet.

Guard: the 24-hour lookback is skipped when last_run is None (brand-new
task). A new task created at 07:30 with a 09:00 target should wait for
09:00, not immediately claim yesterday's missed window.

Scenario that was broken:
  target=09:00, last_run=Feb 24 09:02, now=Feb 26 07:30
  Old: today's 09:00 not yet reached → False (missed Feb 25 silently)
  New: Feb 25 09:00 is past and last_run < Feb 25 09:00 → True ✓

Tests added (78 total, all green):
  test_daemon_restart_catches_missed_yesterday_target
  test_new_task_does_not_claim_yesterday_missed_window
  test_already_ran_yesterday_does_not_refire_for_yesterday_window
The HH:MM parsing/normalisation/deduplication logic existed in two places:
  - scheduler_wizard.py: inline loop producing list[str]
  - daemon.py parse_daily_at_times: inline loop producing list[tuple]

Both shared the same strptime / strftime core but diverged in output type,
deduplication, and warning style — a textbook DRY violation.

Changes:
  code_puppy/scheduler/time_utils.py (new)
    parse_times_hhmm(raw, on_invalid=None) -> list[str]
    - strips whitespace, ignores empty segments
    - validates with strptime('%H:%M'), normalises via strftime('%H:%M')
    - deduplicates preserving first-occurrence order
    - calls on_invalid(entry) for each bad entry when provided,
      silently skips otherwise

  code_puppy/scheduler/daemon.py
    parse_daily_at_times now wraps parse_times_hhmm with a
    [Scheduler] Warning: callback and converts strings to (h, m) tuples.
    Public interface and all existing tests unchanged.

  code_puppy/plugins/scheduler/scheduler_wizard.py
    Inline 10-line loop replaced with a single parse_times_hhmm call
    using a local _warn_invalid callback for the emoji-prefixed output.
    'from datetime import datetime' import removed (no longer needed).

  tests/scheduler/test_time_utils.py (new, 23 tests)
    Covers: single/multiple times, order preservation, normalisation,
    deduplication, whitespace/empty-segment handling, invalid entries,
    on_invalid callback behaviour (called per bad entry, not for empty
    segments, not called for valid entries, None default is safe).

101 tests total, all green.
@mattnico mattnico requested a review from nhicks00 February 28, 2026 19:28
t-granlund pushed a commit to t-granlund/code_puppy-1 that referenced this pull request Mar 3, 2026
…nberger#188)

* fix: fix summarization compaction strategy - multiple issues

Root causes and fixes:

1. **Executor shutdown (DBOS crash)**: asyncio.run() shuts down the
   default executor, breaking DBOS's asyncio.to_thread() calls.
   Fix: Use loop.run_until_complete() in a dedicated thread instead.

2. **DBOSAgent async conflict**: Wrapping summarization agent in
   DBOSAgent caused 'event loop already running' errors.
   Fix: Keep summarization as a plain Agent (doesn't need durability).

3. **Orphaned tool calls**: Messages with tool_use but no matching
   tool_result were sent to the LLM, causing API 400 errors.
   Fix: Prune orphaned tool calls before sending to summarization.

4. **Split boundary breaks pairs**: Message splitting could separate
   tool_use from its tool_result between summarize/protected groups.
   Fix: Added _find_safe_split_index() to keep pairs together.

5. **Empty error messages**: Exception handler showed 'Summarization
   failed during compaction:' with nothing after the colon.
   Fix: Added SummarizationError with type/message details.

Fixes mpfaffenberger#215

* revert: remove test changes from mpfaffenberger#215 fix - production code only

* chore: update tests for new summarization impl, fix ruff lint/format

- Update test mocks to match thread pool pattern (no more asyncio.run)
- Remove get_use_dbos references (DBOS no longer used for summarization)
- Add SummarizationError assertions in error propagation tests
- Remove unused get_use_dbos import (ruff F401)
- Apply ruff formatting

* refactor: remove dead code _run_async_safely and _cancel_all_tasks

These functions were never called - _run_in_thread already handles
its own event loop creation and task cancellation inline.

* fix: add missing dataclasses import and move set_message_history outside loop

- Added 'import dataclasses' needed by dataclasses.replace() call
- Moved self.set_message_history() outside the for loop so history
  is updated once after filtering completes, not on every iteration

---------

Co-authored-by: n0h0123 <nathan.hicks0@walmart.com>
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