Skip to content

Conversation

@kodjima33
Copy link
Collaborator

Fixes

1. Progress scale calculation fixed

  • Problem: 1/5 showed wrong proportion
  • Fix: Removed minValue from calculation. Now progressPercentage = currentValue / targetValue

2. Daily reflection message sender

  • Problem: Reflection sent as user message
  • Fix: Now sends FROM Omi AI (MessageSender.ai)

3. Widget pre-loading

  • Problem: Widget showed loading spinner every app open
  • Fix: Loads cached goal/advice instantly, then refreshes in background

4. Advice improvements

  • Model: Now uses llm_medium (GPT-4.1) instead of llm_mini
  • Length: Limited to 50 words (~3-4 lines)
  • Display: Never clips text (overflow: visible)

Files Changed

  • app/lib/backend/http/api/goals.dart - Fixed progressPercentage calculation
  • app/lib/pages/chat/page.dart - Fixed auto-message to send as AI
  • app/lib/pages/conversations/widgets/goal_tracker_widget.dart - Added caching, pre-loading
  • backend/utils/llm/goals.py - Use better model, word limit

1. Fix progress scale: 1/5 now shows correctly as 20% (removed minValue from calculation)
2. Daily reflection sends FROM Omi AI, not from user
3. Pre-load widget with cached data for instant display
4. Advice limited to 50 words (3-4 lines) and uses GPT-4.1 for better quality
5. Advice text never clips (full text always visible)
@kodjima33 kodjima33 merged commit 0952de5 into main Dec 28, 2025
1 check passed
@kodjima33 kodjima33 deleted the fix/goal-widget-improvements branch December 28, 2025 22:38
Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces several valuable improvements to the Goal widget, including fixing the progress calculation, enhancing the AI-generated advice, and implementing a caching mechanism for a faster, smoother user experience. The changes are well-aligned with the goals described. My review focuses on two critical issues: a logic error in the progress percentage calculation for goals with negative targets, and a race condition in the new caching implementation that could lead to displaying stale data, which violates the rule of re-validating cached objects. Addressing these will ensure the reliability and correctness of the new features.

Comment on lines +71 to +72
if (targetValue <= 0) return currentValue > 0 ? 1.0 : 0.0;
return (currentValue / targetValue).clamp(0.0, 1.0);
Copy link
Contributor

Choose a reason for hiding this comment

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

critical

The logic for handling targetValue <= 0 is incorrect and will lead to wrong progress calculations for goals with negative targets. For example, if the target is -10 and the current value is -5, the progress should be 50%, but this code will return 0%. A division-by-zero error only occurs when targetValue is exactly 0. The clamp(0.0, 1.0) call correctly handles cases with negative targets if the division is allowed to happen.

Suggested change
if (targetValue <= 0) return currentValue > 0 ? 1.0 : 0.0;
return (currentValue / targetValue).clamp(0.0, 1.0);
if (targetValue == 0) return currentValue > 0 ? 1.0 : 0.0;
return (currentValue / targetValue).clamp(0.0, 1.0);

Comment on lines +37 to 39
// Load cached data immediately (sync), then refresh in background
_loadCachedDataSync();
_loadGoal();
Copy link
Contributor

Choose a reason for hiding this comment

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

critical

Calling two async methods, _loadCachedDataSync and _loadGoal, without await from initState creates a critical race condition. The _loadCachedDataSync method (which is misleadingly named as it's async) might finish after _loadGoal, causing stale cached data to overwrite fresh data from the network. This can lead to unpredictable behavior and bugs.

To fix this, the loading logic should be orchestrated in a single async method to ensure sequential execution. For example:

@override
void initState() {
  super.initState();
  WidgetsBinding.instance.addObserver(this);
  _loadInitialData();
}

void _loadInitialData() async {
  // Await cached data loading to prevent race conditions.
  await _loadCachedDataSync();
  // Then await the network refresh.
  await _loadGoal();
}

This ensures that cached data is loaded first, and then the network refresh happens, preventing any data conflicts.

References
  1. When using a cached object as a fallback, re-validate it against the current filters (e.g., selectedDate) before returning to prevent serving stale data.

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