Skip to content

refactor: remove date-fns dependency, use native Intl.DateTimeFormat (closes #497)#563

Open
arcgod-design wants to merge 4 commits into
sreerevanth:mainfrom
arcgod-design:feat/issue-497-remove-date-fns
Open

refactor: remove date-fns dependency, use native Intl.DateTimeFormat (closes #497)#563
arcgod-design wants to merge 4 commits into
sreerevanth:mainfrom
arcgod-design:feat/issue-497-remove-date-fns

Conversation

@arcgod-design

@arcgod-design arcgod-design commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

��## Summary

Removes the date-fns dependency and replaces all date formatting with native Intl.DateTimeFormat API.

Changes

  • Removed date-fns from rontend/package.json
  • Replaced ormat() calls in rontend/pages/index.tsx and rontend/pages/sessions/[id].tsx with Intl.DateTimeFormat
  • Replaced ormatDistanceToNow() with a custom relative time implementation using native Date math

Motivation

The codebase already uses Intl.DateTimeFormat elsewhere. Removing date-fns reduces bundle size and eliminates an unnecessary third-party dependency.

Checklist

  • Code follows the existing style and conventions
  • I have performed a self-review of my code
  • I have commented my code where necessary
  • I have updated the documentation accordingly
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or my feature works
  • New and existing unit tests pass locally with my changes
  • Any dependent changes have been merged and published in downstream modules

Summary by CodeRabbit

  • Bug Fixes
    • Improved date and time display across the app, with more reliable formatting and clearer fallback values when timestamps are invalid or missing.
    • Updated relative time labels to show consistent human-readable values like seconds, minutes, hours, and days ago.
  • Refactor
    • Streamlined internal handling of silent-failure scoring so it now uses a simpler, self-contained approach.

Closes #497

@vercel

vercel Bot commented Jul 5, 2026

Copy link
Copy Markdown

Someone is attempting to deploy a commit to the sreerevanth's projects Team on Vercel.

A member of the Team first needs to authorize it.

@coderabbitai

coderabbitai Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR removes the SilenceBaseline class from agentwatch/scoring/silence.py, inlining its statistical fields directly onto SilentFailureDetector, and updates train()/detect()/baseline accordingly. Separately, date-fns is removed from the frontend dependency and replaced with Intl.DateTimeFormat-based timestamp formatting.

Changes

SilentFailureDetector baseline inlining

Layer / File(s) Summary
Detector fields, train, and baseline accessor
agentwatch/scoring/silence.py
SilenceBaseline is removed; baseline-stat fields (sample size, means, stdevs, common tools) are inlined onto SilentFailureDetector, train() populates these and returns None, baseline property returns self, and __all__ no longer exports SilenceBaseline.
Detection logic using self-stored stats
agentwatch/scoring/silence.py
detect()'s setup and outlier/uncommon-tool detection reference self's stored stats guarded by sample_size >= min_baseline instead of a local baseline variable.

Frontend date-fns removal

Layer / File(s) Summary
Index page timestamp helpers
frontend/package.json, frontend/pages/index.tsx
date-fns dependency and imports are removed; safeFormat/safeDistanceToNow are rewritten with Intl.DateTimeFormat and manual relative-time buckets, returning on failure.
Session detail page timestamp helper
frontend/pages/sessions/[id].tsx
date-fns import removed; safeFormat rewritten with Intl.DateTimeFormat, handling HH:mm:ss.SSS and HH:mm:ss explicitly, falling back to medium date format.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related issues

Possibly related PRs

  • sreerevanth/AgentWatch#534: Overlaps with removing date-fns and rewriting timestamp helpers in frontend/pages/index.tsx and frontend/pages/sessions/[id].tsx.

Suggested labels: Hard

Poem

A baseline hopped away today,
Now self holds stats, come what may.
date-fns packed its bags and left,
Intl took the format heft.
Hop, hop, ship it — clean and neat! 🐇⏰

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: removing date-fns and switching to native Intl.DateTimeFormat.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (1)
frontend/pages/index.tsx (1)

28-53: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate safeFormat/timestamp-formatting logic across pages.

The same safeFormat implementation (and formatting conventions) is repeated in frontend/pages/sessions/[id].tsx. Consider extracting these helpers into a shared lib/formatting.ts (or similar) module used by both pages to avoid drift.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/pages/index.tsx` around lines 28 - 53, Duplicate
timestamp-formatting helpers are present in safeFormat and safeDistanceToNow,
and the same logic is also repeated in frontend/pages/sessions/[id].tsx. Extract
these helpers into a shared formatting module (for example, a lib/formatting
helper) and update both pages to import and use the shared functions so the
formatting behavior stays consistent and avoids drift.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@agentwatch/scoring/silence.py`:
- Line 41: `SilentFailureDetector` is assigning a dataclasses field descriptor
instead of an actual list, so update the `common_tools` initialization to use a
real list value on the instance rather than `field(default_factory=list)`. Fix
this in the `SilentFailureDetector` setup so `detect()` can safely call
`set(self.common_tools)`, and ensure `train()` does not leave
`self.common_tools` holding a `Field` object when it exits early.

In `@frontend/pages/index.tsx`:
- Around line 45-51: Fix the pluralization logic in the time-formatting helper
that returns relative text like “seconds ago”, “minutes ago”, “hours ago”, and
“days ago”. Update the branches in the function that computes diffSec, diffMin,
diffHr, and diffDay so each unit uses singular wording when the value is 1 and
plural wording otherwise. Keep the same function structure, but make the
returned string vary based on the computed count to avoid outputs like “1
minutes ago” or “1 hours ago”.
- Around line 39-53: The safeDistanceToNow helper is not guarding against
invalid timestamps because new Date(ts).getTime() can return NaN without
throwing, which can flow through to a “NaN days ago” result. Update
safeDistanceToNow to explicitly detect an invalid parsed time before doing the
diff calculations, and return the fallback dash when the timestamp cannot be
parsed. Keep the fix localized to safeDistanceToNow in frontend/pages/index.tsx.

---

Nitpick comments:
In `@frontend/pages/index.tsx`:
- Around line 28-53: Duplicate timestamp-formatting helpers are present in
safeFormat and safeDistanceToNow, and the same logic is also repeated in
frontend/pages/sessions/[id].tsx. Extract these helpers into a shared formatting
module (for example, a lib/formatting helper) and update both pages to import
and use the shared functions so the formatting behavior stays consistent and
avoids drift.
🪄 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: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: bcb81fea-dde8-4f01-bdb5-217e7140cc95

📥 Commits

Reviewing files that changed from the base of the PR and between d721847 and c2d9913.

📒 Files selected for processing (4)
  • agentwatch/scoring/silence.py
  • frontend/package.json
  • frontend/pages/index.tsx
  • frontend/pages/sessions/[id].tsx
💤 Files with no reviewable changes (1)
  • frontend/package.json

self.stdev_duration_ms: float = 0.0
self.mean_tokens: float = 0.0
self.stdev_tokens: float = 0.0
self.common_tools: list[str] = field(default_factory=list)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Confirm SilentFailureDetector is not a dataclass and that `field` comes from dataclasses.
fd -t f 'silence.py' agentwatch/scoring --exec sed -n '1,45p' {}
echo "--- decorator check ---"
rg -nP -C2 '^\s*(`@dataclass`|class SilentFailureDetector)' agentwatch/scoring/silence.py
echo "--- field import ---"
rg -nP 'from dataclasses import|import dataclasses' agentwatch/scoring/silence.py

Repository: sreerevanth/AgentWatch

Length of output: 1848


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "--- relevant lines ---"
sed -n '45,150p' agentwatch/scoring/silence.py

echo "--- dataclasses.field behavior probe ---"
python3 - <<'PY'
from dataclasses import field

f = field(default_factory=list)
print(type(f).__name__)
print(bool(f))
try:
    print(set(f))
except Exception as e:
    print(type(e).__name__, str(e))
PY

Repository: sreerevanth/AgentWatch

Length of output: 4114


Replace field(default_factory=list) with a real list assignment.
SilentFailureDetector is a plain class, so this stores a dataclasses.Field object in self.common_tools instead of []. detect() then crashes on set(self.common_tools), and the early-return path in train() leaves the bad value in place.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@agentwatch/scoring/silence.py` at line 41, `SilentFailureDetector` is
assigning a dataclasses field descriptor instead of an actual list, so update
the `common_tools` initialization to use a real list value on the instance
rather than `field(default_factory=list)`. Fix this in the
`SilentFailureDetector` setup so `detect()` can safely call
`set(self.common_tools)`, and ensure `train()` does not leave
`self.common_tools` holding a `Field` object when it exits early.

Comment thread frontend/pages/index.tsx
Comment on lines 39 to 53
function safeDistanceToNow(ts: string | null | undefined): string {
if (!ts) return '—'
try { return formatDistanceToNow(new Date(ts), { addSuffix: true }) } catch { return '—' }
try {
const now = Date.now()
const then = new Date(ts).getTime()
const diffSec = Math.round((now - then) / 1000)
if (diffSec < 60) return `${diffSec} seconds ago`
const diffMin = Math.round(diffSec / 60)
if (diffMin < 60) return `${diffMin} minutes ago`
const diffHr = Math.round(diffMin / 60)
if (diffHr < 24) return `${diffHr} hours ago`
const diffDay = Math.round(diffHr / 24)
return `${diffDay} days ago`
} catch { return '—' }
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

safeDistanceToNow silently produces "NaN days ago" for unparseable timestamps.

Unlike safeFormat, invalid dates here don't throw — new Date(ts).getTime() returns NaN, and every < comparison against NaN is false, so execution falls through to the final return with NaN values instead of hitting the catch block and returning '—'.

🐛 Proposed fix
   try {
     const now = Date.now()
     const then = new Date(ts).getTime()
+    if (Number.isNaN(then)) return '—'
     const diffSec = Math.round((now - then) / 1000)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
function safeDistanceToNow(ts: string | null | undefined): string {
if (!ts) return '—'
try { return formatDistanceToNow(new Date(ts), { addSuffix: true }) } catch { return '—' }
try {
const now = Date.now()
const then = new Date(ts).getTime()
const diffSec = Math.round((now - then) / 1000)
if (diffSec < 60) return `${diffSec} seconds ago`
const diffMin = Math.round(diffSec / 60)
if (diffMin < 60) return `${diffMin} minutes ago`
const diffHr = Math.round(diffMin / 60)
if (diffHr < 24) return `${diffHr} hours ago`
const diffDay = Math.round(diffHr / 24)
return `${diffDay} days ago`
} catch { return '—' }
}
function safeDistanceToNow(ts: string | null | undefined): string {
if (!ts) return '—'
try {
const now = Date.now()
const then = new Date(ts).getTime()
if (Number.isNaN(then)) return '—'
const diffSec = Math.round((now - then) / 1000)
if (diffSec < 60) return `${diffSec} seconds ago`
const diffMin = Math.round(diffSec / 60)
if (diffMin < 60) return `${diffMin} minutes ago`
const diffHr = Math.round(diffMin / 60)
if (diffHr < 24) return `${diffHr} hours ago`
const diffDay = Math.round(diffHr / 24)
return `${diffDay} days ago`
} catch { return '—' }
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/pages/index.tsx` around lines 39 - 53, The safeDistanceToNow helper
is not guarding against invalid timestamps because new Date(ts).getTime() can
return NaN without throwing, which can flow through to a “NaN days ago” result.
Update safeDistanceToNow to explicitly detect an invalid parsed time before
doing the diff calculations, and return the fallback dash when the timestamp
cannot be parsed. Keep the fix localized to safeDistanceToNow in
frontend/pages/index.tsx.

Comment thread frontend/pages/index.tsx Outdated
Comment on lines +45 to +51
if (diffSec < 60) return `${diffSec} seconds ago`
const diffMin = Math.round(diffSec / 60)
if (diffMin < 60) return `${diffMin} minutes ago`
const diffHr = Math.round(diffMin / 60)
if (diffHr < 24) return `${diffHr} hours ago`
const diffDay = Math.round(diffHr / 24)
return `${diffDay} days ago`

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

Pluralization: "1 minutes ago" / "1 hours ago" / "1 days ago" reads ungrammatically.

💬 Proposed fix
-    if (diffSec < 60) return `${diffSec} seconds ago`
+    if (diffSec < 60) return `${diffSec} second${diffSec === 1 ? '' : 's'} ago`
     const diffMin = Math.round(diffSec / 60)
-    if (diffMin < 60) return `${diffMin} minutes ago`
+    if (diffMin < 60) return `${diffMin} minute${diffMin === 1 ? '' : 's'} ago`
     const diffHr = Math.round(diffMin / 60)
-    if (diffHr < 24) return `${diffHr} hours ago`
+    if (diffHr < 24) return `${diffHr} hour${diffHr === 1 ? '' : 's'} ago`
     const diffDay = Math.round(diffHr / 24)
-    return `${diffDay} days ago`
+    return `${diffDay} day${diffDay === 1 ? '' : 's'} ago`
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (diffSec < 60) return `${diffSec} seconds ago`
const diffMin = Math.round(diffSec / 60)
if (diffMin < 60) return `${diffMin} minutes ago`
const diffHr = Math.round(diffMin / 60)
if (diffHr < 24) return `${diffHr} hours ago`
const diffDay = Math.round(diffHr / 24)
return `${diffDay} days ago`
if (diffSec < 60) return `${diffSec} second${diffSec === 1 ? '' : 's'} ago`
const diffMin = Math.round(diffSec / 60)
if (diffMin < 60) return `${diffMin} minute${diffMin === 1 ? '' : 's'} ago`
const diffHr = Math.round(diffMin / 60)
if (diffHr < 24) return `${diffHr} hour${diffHr === 1 ? '' : 's'} ago`
const diffDay = Math.round(diffHr / 24)
return `${diffDay} day${diffDay === 1 ? '' : 's'} ago`
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@frontend/pages/index.tsx` around lines 45 - 51, Fix the pluralization logic
in the time-formatting helper that returns relative text like “seconds ago”,
“minutes ago”, “hours ago”, and “days ago”. Update the branches in the function
that computes diffSec, diffMin, diffHr, and diffDay so each unit uses singular
wording when the value is 1 and plural wording otherwise. Keep the same function
structure, but make the returned string vary based on the computed count to
avoid outputs like “1 minutes ago” or “1 hours ago”.

@arcgod-design

Copy link
Copy Markdown
Contributor Author

Closes #497

…ve-date-fns

# Conflicts:
#	frontend/pages/index.tsx
#	frontend/pages/sessions/[id].tsx
@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

🧪 PR Test Results

Check Result
Tests (pytest tests/) ✅ success
Lint (ruff check .) ✅ success
Coverage (agentwatch) 73.62%

Python 3.12 · commit 1c69b44

@arcgod-design

Copy link
Copy Markdown
Contributor Author

Hey @sreerevanth, this PR has been ready for review for a while -- offering this friendly bump. The implementation matches the issue's specified behavior and CI is passing.

PR: #563
Title: refactor: remove date-fns, use native Intl.DateTimeFormat
Issue: #497

When you have a moment, a review would be much appreciated. I am happy to iterate on any feedback. If the timing is not right, no worries at all -- just a gentle nudge from a contributor who has been waiting patiently. �

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.

Refactor: Remove date-fns dependency and use native Intl.DateTimeFormat

1 participant