Skip to content

release: v6.8.6 - #55

Merged
code-crusher merged 1 commit into
mainfrom
release/6.8.6
Sep 15, 2026
Merged

code-crusher merged 1 commit into
mainfrom
release/6.8.6

Conversation

@code-crusher

Copy link
Copy Markdown
Member

Summary

Release v6.8.6.

Fixed

  • Plan-aware default model. The default model is now resolved from the live catalog instead of the hardcoded DEFAULT_MODEL_ID: free accounts default to the catalog entry the backend flags freePlan, every other plan to the first catalog entry (index 0, ordered by the catalog's sortOrder). fetchDynamicModels records the catalog order and each model's freePlan flag, and the new getDefaultModelId(plan) helper resolves the default. The TUI applies it once the catalog and the account plan have both loaded — only while the selection is still the untouched default, so an explicit pick is never overwritten — and headless mode applies it when no --model / MATTERAI_MODEL was requested.

Verification

  • npm run typecheck and npm run build pass.

After merge: tag v6.8.6 on main to trigger the npm publish workflow.

Plan-aware default model: free plans default to the catalog's freePlan entry, paid plans to the first catalog entry (index 0).
@matterai-app

matterai-app Bot commented Sep 15, 2026

Copy link
Copy Markdown
Contributor

Summary By MatterAI MatterAI logo

🔄 What Changed

  • Bumped project version to 6.8.6 in package.json.
  • Added freePlan model metadata flag and plan-aware default model resolution logic (getDefaultModelId, isFreePlan) in src/api/models.ts.
  • Integrated dynamic default model resolution into headless initialization (src/headless.ts) and interactive UI lifecycle (src/ui/App.tsx).

🔍 Impact of the Change

  • Automatically assigns the appropriate free-tier or paid-tier default model based on the user's fetched account plan when using the default configuration.

📁 Total Files Changed

Click to Expand
File ChangeLog
Version Bump package.json Incremented application version to 6.8.6.
Model Metadata src/api/models.ts Added freePlan flag support and getDefaultModelId resolution utility.
Headless CLI src/headless.ts Resolved plan-aware default model during startup when no explicit model is requested.
UI Lifecycle src/ui/App.tsx Added React hooks to fetch dynamic models/profile and silently apply the preferred default model once ready.

🧪 Test Added/Recommended

Recommended

  • Add unit tests for getDefaultModelId verifying correct selection between free and paid catalog entries.

🔒Security Vulnerabilities

  • None detected.

@matterai-app matterai-app 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.

🧪 PR Review is completed: Plan-aware default model resolution is well-structured (good guards against overwriting explicit user picks and against empty catalogs), but the headless path silently treats a failed profile fetch as a free plan, and the TUI path persists the auto-resolved default making it indistinguishable from an explicit user pick on future plan changes. Reviewed src/api/models.ts: no issues found. package.json: version bump only, no issues.

Skipped files
  • CHANGELOG.md: Skipped file pattern
  • package-lock.json: Skipped file pattern
⬇️ Low Priority Suggestions (2)
src/headless.ts (1 suggestion)

Location: src/headless.ts (Lines 44-48)

🟡 Logic Error / Error Handling

Issue: fetchProfile(token).catch(() => null) swallows failures, and a null profile resolves to plan === undefined, which isFreePlan() treats as the free tier. A transient profile-fetch failure (network blip, 5xx) silently downgrades a paid user to the free-plan default model for the entire run — the opposite degradation of the existing gating block below, where an unhandled fetchProfile rejection fails loudly. Additionally, when the resolved default is a gated model (Lumen/Eido/400k), fetchProfile is fetched twice in the same run.

Fix: Only re-resolve the default when the profile actually loaded; on failure keep the static default (DEFAULT_MODEL_ID), which is the documented fallback.

Impact: Paid users no longer get silently switched to the free model on transient errors; behavior matches the documented fallback semantics.

-  	if (token && !requestedModel && settings.model === DEFAULT_MODEL_ID) {
-  		const profile = await fetchProfile(token).catch(() => null)
-  		const plan = profile?.plan ?? profile?.tieredUsage?.plan
-  		const preferred = getDefaultModelId(plan)
-  		if (preferred !== settings.model) settings.model = preferred
+  	if (token && !requestedModel && settings.model === DEFAULT_MODEL_ID) {
+  		const profile = await fetchProfile(token).catch(() => null)
+  		if (profile) {
+  			const plan = profile.plan ?? profile.tieredUsage?.plan
+  			const preferred = getDefaultModelId(plan)
+  			if (preferred !== settings.model) settings.model = preferred
+  		}
+  	}
src/ui/App.tsx (1 suggestion)

Location: src/ui/App.tsx (Lines 951-956)

🟡 Business Logic Impact (needs discussion)

Issue: The auto-resolved plan-aware default is applied via switchModel, which calls saveSettings — persisting it to config.json. After the first run, settings.model !== DEFAULT_MODEL_ID, so the guard at line 953 never fires again: the auto-selection becomes permanently indistinguishable from an explicit user pick. Consequences: (1) a free user who upgrades to pro stays on the free model forever (until manually changed), and vice versa a downgraded user keeps the paid default; (2) inconsistency with the headless path, which resolves per-run without persisting. The comment says "an explicit user pick is never overwritten" — correct — but the code can't tell an auto-pick from a user pick after persistence.

Fix (architectural, beyond a minimal patch): Persist a marker distinguishing auto-resolved selections (e.g. a modelSource: "auto" | "user" field in settings, or skip saveSettings for the silent auto-switch and re-resolve on every startup while the marker is absent). Worth deciding intentionally before release since it affects every user's default after a plan change.

-    useEffect(() => {
-      if (!catalogReady || !planLoaded) return;
-      if (settings.model !== DEFAULT_MODEL_ID) return;
-      const preferred = getDefaultModelId(activePlan);
-      if (preferred !== settings.model) switchModel(preferred, { silent: true });
-    }, [activePlan, catalogReady, planLoaded, settings.model, switchModel]);
+  

@code-crusher
code-crusher merged commit ae91229 into main Sep 15, 2026
1 check passed
@code-crusher
code-crusher deleted the release/6.8.6 branch September 15, 2026 12:39
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