@blockrun/franklin 3.8.25 → 3.8.26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/agent/loop.js +21 -37
  2. package/package.json +1 -1
@@ -711,49 +711,33 @@ export async function interactiveSession(config, getUserInput, onEvent, onAbortR
711
711
  sessionId,
712
712
  });
713
713
  // ── Router: resolve routing profiles to concrete models ──
714
+ // Classifier always sees the user's ORIGINAL prompt for this turn —
715
+ // never the `[GROUNDING CHECK FAILED]` / `[VERIFICATION FAILED]` /
716
+ // pushback-annotated variants the loop injects mid-turn. Same input
717
+ // across iterations → same tier → stable resolved model. Stops the
718
+ // failure mode where a retry message classified as SIMPLE dropped
719
+ // a COMPLEX task down to gemini mid-way.
714
720
  const routingProfile = parseRoutingProfile(config.model);
715
721
  let resolvedModel = config.model;
716
722
  let routingTier;
717
723
  let routingConfidence;
718
724
  let routingSavings;
719
725
  if (routingProfile) {
720
- if (groundingRetryCount > 0 && lastRoutedModel) {
721
- // Grounding retry re-enters the loop with a `[GROUNDING CHECK
722
- // FAILED]` user message that the router would classify as
723
- // SIMPLE on its own — which drops the turn onto a weak model
724
- // mid-task (observed in the CRCL log on 2026-04-22). Pin the
725
- // model the router picked on the first iteration so retries
726
- // stay on the same tier.
727
- resolvedModel = lastRoutedModel;
728
- }
729
- else {
730
- // Extract latest user text for classification
731
- const lastUser = [...history].reverse().find((m) => m.role === 'user');
732
- const userText = typeof lastUser?.content === 'string'
733
- ? lastUser.content
734
- : Array.isArray(lastUser?.content)
735
- ? lastUser.content
736
- .filter(p => p.type === 'text')
737
- .map(p => p.text ?? '')
738
- .join(' ')
739
- : '';
740
- const routing = await routeRequestAsync(userText, routingProfile);
741
- resolvedModel = routing.model;
742
- routingTier = routing.tier;
743
- routingConfidence = routing.confidence;
744
- routingSavings = routing.savings;
745
- lastRoutedModel = routing.model;
746
- lastRoutedCategory = routing.signals[0] || '';
747
- // Surface the routing decision so users know which concrete model
748
- // just got picked. Without this the status bar reads "auto" and
749
- // users have no idea what's actually running — or worse, they
750
- // believe they're stuck on the last-seen concrete name.
751
- if (loopCount === 1) {
752
- onEvent({
753
- kind: 'text_delta',
754
- text: `*Auto → ${routing.model}*\n\n`,
755
- });
756
- }
726
+ const userText = lastUserInput || '';
727
+ const routing = await routeRequestAsync(userText, routingProfile);
728
+ resolvedModel = routing.model;
729
+ routingTier = routing.tier;
730
+ routingConfidence = routing.confidence;
731
+ routingSavings = routing.savings;
732
+ lastRoutedModel = routing.model;
733
+ lastRoutedCategory = routing.signals[0] || '';
734
+ // Surface the routing decision on the first iteration so the user
735
+ // sees which concrete model got picked, not just "auto".
736
+ if (loopCount === 1) {
737
+ onEvent({
738
+ kind: 'text_delta',
739
+ text: `*Auto → ${routing.model}*\n\n`,
740
+ });
757
741
  }
758
742
  }
759
743
  // Update token estimation model for more accurate byte-per-token ratio
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@blockrun/franklin",
3
- "version": "3.8.25",
3
+ "version": "3.8.26",
4
4
  "description": "Franklin — The AI agent with a wallet. Spends USDC autonomously to get real work done. Pay per action, no subscriptions.",
5
5
  "type": "module",
6
6
  "exports": {