Skip to content

Upsell ai reasoning effort#8648

Merged
malmstein merged 3 commits into
developfrom
feature/youssef/ai_reasoning_effort_upsell
May 21, 2026
Merged

Upsell ai reasoning effort#8648
malmstein merged 3 commits into
developfrom
feature/youssef/ai_reasoning_effort_upsell

Conversation

@YoussefKeyrouz
Copy link
Copy Markdown
Collaborator

@YoussefKeyrouz YoussefKeyrouz commented May 20, 2026

Task/Issue URL: https://app.asana.com/1/137249556945/project/1212810093780571/task/1214635053937863?focus=true

Description

Part 2 of 2 — Subscription upsell trigger for gated reasoning efforts.

Part 1 added schema support for the new reasoningEffortAccess field on the /duckchat/v1/models response. This PR wires the user-facing upsell: tapping a gated reasoning mode on an accessible model now routes the user into the native SubscriptionPurchase (FREE → PLUS/PRO) or SubscriptionUpgrade (PLUS → PRO) flow, mirroring the model-level upsell already shipped on #8625.

What changed:

  • Data layer plumbing: AvailableReasoningMode now carries an optional access: ReasoningEffortAccess? plus a derived isAccessible flag. ReasoningResolver.availableModes(supported, effortAccess) picks the first candidate effort per mode that is supported and accessible; if none are accessible, it falls back to the first supported one so the row still renders for upsell routing. Missing per-effort access metadata is treated as accessible.
  • Reasoning picker upsell wiring: ReasoningModePickerViewModel.onModeTapped(mode, surface) runs the same decision table as the model picker: accessible → select; gated → route to LaunchPurchase/LaunchUpgrade based on access.requiredTier + current userTier.
  • Shared upsell types: PickerSurface and UpsellCommand live in a new shared file. The model picker was re-pointed to use these instead of its previously nested types.

Notes:

  • Product request: Hardcoded gate for gpt-5.2 EXTENDED_REASONING until BE is ready.

Steps to test this PR

  • Free account, gated model tap (already shipped, regression check): Tap a PLUS-only model from the model picker → SubscriptionPurchase opens with the model-picker funnel origin.
  • Plus account, PRO-gated reasoning tap: Open GPT-5.2, tap EXTENDED_REASONING → SubscriptionUpgrade opens.
  • Tier downgrade: While on PLUS/PRO with a gated reasoning mode selected, downgrade by removing the subscription. The picker auto-selects the first accessible model/mode and submitting a prompt sends that mode's effort, not the previously-cached gated effort.

UI changes

screen-20260520-202439-1779319456993.mp4

Note

Medium Risk
Introduces new per-effort accessibility logic for reasoning modes and routes users into purchase/upgrade flows, which can affect subscription funnel behavior and persisted selection state. Also adds a temporary hardcoded gate for gpt-5.2 that could mis-gate if model IDs or backend behavior change.

Overview
Adds per-reasoning-effort access awareness and upsell routing: AvailableReasoningMode now carries optional access metadata and ReasoningResolver.availableModes selects the first supported + accessible effort per mode (falling back to a gated effort so the row can still render for upsell).

Updates RealDuckAiModelManager to validate persisted reasoning selections against accessibility (auto-selecting/persisting the first accessible mode, refusing gated selections, and allowing selectedReasoningMode to become null when all efforts are gated). The reasoning-mode picker now triggers the native SubscriptionPurchase/SubscriptionUpgrade flows when a user taps a gated mode, using shared PickerSurface/UpsellCommand types (also adopted by the model picker).

Includes a temporary, hardcoded PRO-only gate for gpt-5.2 EXTENDED_REASONING until backend per-effort gating ships, and expands tests to cover gating/auto-promotion/upsell behavior.

Reviewed by Cursor Bugbot for commit c92886a. Bugbot is set up for automated code reviews on this repo. Configure here.

Copy link
Copy Markdown
Collaborator Author

YoussefKeyrouz commented May 20, 2026

@YoussefKeyrouz YoussefKeyrouz requested a review from malmstein May 20, 2026 23:27
Base automatically changed from feature/youssef/ai_reasoning_effort_tier to develop May 20, 2026 23:28
@YoussefKeyrouz YoussefKeyrouz force-pushed the feature/youssef/ai_reasoning_effort_upsell branch from 67285ec to 43beb24 Compare May 20, 2026 23:40
@YoussefKeyrouz YoussefKeyrouz force-pushed the feature/youssef/ai_reasoning_effort_upsell branch from 43beb24 to c92886a Compare May 21, 2026 16:15
Copy link
Copy Markdown
Contributor

@malmstein malmstein left a comment

Choose a reason for hiding this comment

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

nice refactor pulling routeUpsell and PickerSurface into a shared file — the reasoning picker now mirrors the model picker pattern cleanly, and the test coverage for the new per-effort gating is solid (the ReasoningResolverTest cases are particularly thorough). couple of small things: the hardcoded gpt-5.2 gate overwrites rather than merges and has no test of its own, and the silent else -> null in routeUpsell loses a useful debug log.

@malmstein malmstein merged commit ea7b4a4 into develop May 21, 2026
17 checks passed
@malmstein malmstein deleted the feature/youssef/ai_reasoning_effort_upsell branch May 21, 2026 20:37
YoussefKeyrouz added a commit that referenced this pull request May 21, 2026
Task/Issue URL:
https://app.asana.com/1/137249556945/project/488551667048375/task/1214635053937863?focus=true

### Description

Addressing comments from #8648

### Steps to test this PR

- [ ] Sign in with a PLUS account -> Try to select GPT 5.2 with extended
reasoning —> Upsell flow should trigger
- [ ] All other models should behave as expected. 


<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Touches model/effort access gating and persistence used to drive
upsell behavior, so mistakes could incorrectly block or unlock reasoning
modes; changes are small and backed by new targeted tests.
> 
> **Overview**
> Prevents the temporary hardcoded `gpt-5.2` EXTENDED reasoning effort
gate from **overwriting backend-provided** `reasoningEffortAccess` by
merging: server entries are preserved and hardcoding only fills missing
effort IDs.
> 
> Tightens reasoning-mode persistence by comparing `ReasoningMode`
values directly (avoids unnecessary writes when raw values match), and
adds a defensive log breadcrumb when an upsell is requested for a tier
transition that has no native flow.
> 
> Adds unit tests to lock in the new merge behavior and ensure EXTENDED
reasoning candidates remain hardcoded to `pro` until the backend gate is
removed.
> 
> <sup>Reviewed by [Cursor Bugbot](https://cursor.com/bugbot) for commit
ae9b8f4. Bugbot is set up for automated
code reviews on this repo. Configure
[here](https://www.cursor.com/dashboard/bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
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