Skip to content

feat: add summary_only parameter to reduce response size#7

Open
ljadach wants to merge 3 commits into
eddmann:mainfrom
ljadach:feature/summary-only-mode
Open

feat: add summary_only parameter to reduce response size#7
ljadach wants to merge 3 commits into
eddmann:mainfrom
ljadach:feature/summary-only-mode

Conversation

@ljadach

@ljadach ljadach commented Mar 23, 2026

Copy link
Copy Markdown

Summary

  • Adds an optional summary_only boolean parameter (default: False) to 7 query tools
  • When enabled, time-series arrays and non-essential metadata are stripped from responses while preserving all key metrics
  • Zero overhead on the default path — existing behavior is completely unchanged

Motivation

MCP tool responses contain large time-series arrays (per-minute sleep movement, heart rate readings, HRV data, etc.) that are rarely needed by LLM consumers. For routine health checks, these arrays account for 90%+ of response size while providing no additional value.

For example, query_sleep_data returns ~95K characters for a single night, but the essential metrics (sleep duration, scores, averages) fit in ~2K characters. This wastes context window budget and increases token costs significantly for daily/weekly health monitoring workflows.

Changes

Tool Estimated Reduction What's Stripped
query_sleep_data ~95% Per-minute movement, HR, stress, respiration, HRV arrays
query_health_summary ~65-75% Duplicate stats call, Body Battery time-series
query_heart_rate_data ~90% heartRateValues time-series array
query_activities ~60-70% userRoles, splitSummaries, profile images, connectIQ data
query_weight_data Minor Device metadata, source details
get_performance_metrics Moderate HRV readings arrays, timestamp details
analyze_training_period Moderate Weekly trend breakdown

Implementation

  • Blocklist approach for health data (sleep, HR, body battery): strips known time-series keys while passing through any new summary fields Garmin adds
  • Allowlist approach for activities and weight: keeps only essential fields, automatically excluding any new verbose fields
  • Shared strip_keys() utility in response_builder.py for consistent filtering
  • format_activity_summary() in ResponseBuilder for activity-specific field selection
  • 6 new unit tests covering strip_keys() and format_activity_summary()

Usage

# Routine daily check — compact response
query_sleep_data(date="today", summary_only=True)

# Ad-hoc investigation — full detail (default, unchanged behavior)
query_sleep_data(date="today")

Test plan

  • All 64 existing + new unit tests pass
  • ruff check and ruff format pass
  • Default behavior (summary_only=False) is identical to pre-change behavior
  • Manual testing with live Garmin data to verify summary responses contain all needed metrics

🤖 Generated with Claude Code

ljadach and others added 3 commits March 23, 2026 23:48
…queries

Adds an optional `summary_only` boolean parameter (default: False) to 7
query tools. When enabled, time-series arrays and non-essential metadata
are stripped from responses while preserving all key metrics.

Affected tools and estimated size reductions:
- query_sleep_data: ~95% (strips per-minute movement, HR, stress, respiration)
- query_health_summary: ~65-75% (skips duplicate stats, strips BB time-series)
- query_heart_rate_data: ~90% (strips heartRateValues array)
- query_activities: ~60-70% (strips userRoles, splitSummaries, profile data)
- query_weight_data: strips device metadata (minor)
- get_performance_metrics: strips HRV readings arrays
- analyze_training_period: skips weekly trend computation

Implementation approach:
- Default behavior is unchanged (summary_only=False)
- Filtering happens after API calls, before response building
- Uses key-set stripping for predictable, maintainable filtering
- Adds format_activity_summary() to ResponseBuilder for activity filtering

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ests

Post-review cleanup:
- Move _strip_keys to response_builder.py as shared strip_keys() function
- Extract _HRV_DETAIL_KEYS constant in training.py (was inline set literal)
- Extract _activity_formatter() helper in activities.py (was 5x ternary)
- Add unit tests for strip_keys() and format_activity_summary()

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ering

Found during live testing:
- Sleep: wellnessEpochRespirationAveragesList was not in the blocklist
  (different key name from wellnessEpochRespirationDataDTOList)
- Weight: API returns nested dailyWeightSummaries dict, not a flat list.
  Updated _summarize_weigh_ins to handle the nested structure.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.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.

1 participant