Skip to content
This repository was archived by the owner on May 24, 2026. It is now read-only.

Commit c9fc8f0

Browse files
authored
Merge pull request #73 from PureWeen/dev/alex/requests
Add premium quota display to session title bar and fix SDK numeric type casting
2 parents 7c51ce3 + 22edcbd commit c9fc8f0

6 files changed

Lines changed: 47 additions & 15 deletions

File tree

PolyPilot/Components/ChatMessageList.razor

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
}
1111
else
1212
{
13-
@foreach (var msg in Messages)
13+
@foreach (var msg in Messages.ToList())
1414
{
1515
<ChatMessageItem Message="msg" Compact="Compact" UserAvatarUrl="@UserAvatarUrl" />
1616
}

PolyPilot/Components/ExpandedSessionView.razor

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@
2929
{
3030
<span class="context-badge branch-badge"> @Session.GitBranch</span>
3131
}
32+
@if (UsageInfo?.PremiumQuota != null)
33+
{
34+
var q = UsageInfo.PremiumQuota;
35+
<span class="context-badge premium-badge" title="@(q.IsUnlimited ? "Unlimited premium requests" : $"{q.EntitlementRequests - q.UsedRequests} of {q.EntitlementRequests} remaining (resets {q.ResetDate?[..10]})")">⚡ @(q.IsUnlimited ? "" : $"{q.EntitlementRequests - q.UsedRequests}/{q.EntitlementRequests}") premium</span>
36+
}
3237
<button class="collapse-card-btn" @onclick="OnCollapse" title="Back to grid (Esc / ⌘E)">⊟ Grid</button>
3338
</div>
3439
</div>

PolyPilot/Components/ExpandedSessionView.razor.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
.chat-header-context { display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap; }
2626
.context-badge { font-size: var(--type-caption1, 0.6rem); color: var(--text-dim); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 300px; }
2727
.branch-badge { color: var(--accent-primary); font-weight: 500; }
28+
.premium-badge { color: #e0a040; font-weight: 500; }
2829
.model-badge { padding: 0.2rem 0.5rem; background: var(--hover-bg); border: 1px solid var(--border-accent); border-radius: 4px; font-size: var(--type-body); color: var(--accent-primary); line-height: 1.2; }
2930
.session-id-badge { padding: 0.2rem 0.5rem; background: rgba(251,191,36,0.2); border: 1px solid rgba(251,191,36,0.3); border-radius: 4px; font-size: var(--type-body); color: #fbbf24; font-family: monospace; cursor: pointer; }
3031
.session-id-badge:hover { background: rgba(251,191,36,0.3); }

PolyPilot/Components/Pages/Dashboard.razor

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -644,7 +644,8 @@
644644
info.CurrentTokens ?? current.CurrentTokens,
645645
info.TokenLimit ?? current.TokenLimit,
646646
info.InputTokens ?? current.InputTokens,
647-
info.OutputTokens ?? current.OutputTokens);
647+
info.OutputTokens ?? current.OutputTokens,
648+
info.PremiumQuota ?? current.PremiumQuota);
648649
}
649650
else
650651
{

PolyPilot/Services/CopilotService.Events.cs

Lines changed: 28 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -165,26 +165,42 @@ void Invoke(Action action)
165165

166166
case SessionUsageInfoEvent usageInfo:
167167
var uData = usageInfo.Data;
168-
var uModel = uData?.GetType().GetProperty("Model")?.GetValue(uData)?.ToString();
169-
var uCurrentTokens = uData?.GetType().GetProperty("CurrentTokens")?.GetValue(uData) as int?;
170-
var uTokenLimit = uData?.GetType().GetProperty("TokenLimit")?.GetValue(uData) as int?;
171-
var uInputTokens = uData?.GetType().GetProperty("InputTokens")?.GetValue(uData) as int?;
172-
var uOutputTokens = uData?.GetType().GetProperty("OutputTokens")?.GetValue(uData) as int?;
173-
if (!string.IsNullOrEmpty(uModel))
174-
state.Info.Model = uModel;
175-
Invoke(() => OnUsageInfoChanged?.Invoke(sessionName, new SessionUsageInfo(uModel, uCurrentTokens, uTokenLimit, uInputTokens, uOutputTokens)));
168+
var uCurrentTokensRaw = uData?.GetType().GetProperty("CurrentTokens")?.GetValue(uData);
169+
var uTokenLimitRaw = uData?.GetType().GetProperty("TokenLimit")?.GetValue(uData);
170+
var uCurrentTokens = uCurrentTokensRaw != null ? (int?)Convert.ToInt32(uCurrentTokensRaw) : null;
171+
var uTokenLimit = uTokenLimitRaw != null ? (int?)Convert.ToInt32(uTokenLimitRaw) : null;
172+
Invoke(() => OnUsageInfoChanged?.Invoke(sessionName, new SessionUsageInfo(null, uCurrentTokens, uTokenLimit, null, null)));
176173
break;
177174

178175
case AssistantUsageEvent assistantUsage:
179176
var aData = assistantUsage.Data;
180177
var aModel = aData?.GetType().GetProperty("Model")?.GetValue(aData)?.ToString();
181-
var aInput = aData?.GetType().GetProperty("InputTokens")?.GetValue(aData) as int?;
182-
var aOutput = aData?.GetType().GetProperty("OutputTokens")?.GetValue(aData) as int?;
178+
var aInputRaw = aData?.GetType().GetProperty("InputTokens")?.GetValue(aData);
179+
var aOutputRaw = aData?.GetType().GetProperty("OutputTokens")?.GetValue(aData);
180+
var aInput = aInputRaw != null ? (int?)Convert.ToInt32(aInputRaw) : null;
181+
var aOutput = aOutputRaw != null ? (int?)Convert.ToInt32(aOutputRaw) : null;
182+
QuotaInfo? aPremiumQuota = null;
183+
try
184+
{
185+
var quotaSnapshots = aData?.GetType().GetProperty("QuotaSnapshots")?.GetValue(aData);
186+
if (quotaSnapshots is Dictionary<string, object> qs &&
187+
qs.TryGetValue("premium_interactions", out var premiumObj) &&
188+
premiumObj is System.Text.Json.JsonElement je)
189+
{
190+
var isUnlimited = je.TryGetProperty("isUnlimitedEntitlement", out var u) && u.GetBoolean();
191+
var entitlement = je.TryGetProperty("entitlementRequests", out var e) ? e.GetInt32() : -1;
192+
var used = je.TryGetProperty("usedRequests", out var ur) ? ur.GetInt32() : 0;
193+
var remaining = je.TryGetProperty("remainingPercentage", out var rp) ? rp.GetInt32() : 100;
194+
var resetDate = je.TryGetProperty("resetDate", out var rd) ? rd.GetString() : null;
195+
aPremiumQuota = new QuotaInfo(isUnlimited, entitlement, used, remaining, resetDate);
196+
}
197+
}
198+
catch { }
183199
if (!string.IsNullOrEmpty(aModel))
184200
state.Info.Model = aModel;
185-
if (aInput.HasValue || aOutput.HasValue)
201+
if (aInput.HasValue || aOutput.HasValue || aPremiumQuota != null)
186202
{
187-
Invoke(() => OnUsageInfoChanged?.Invoke(sessionName, new SessionUsageInfo(aModel, null, null, aInput, aOutput)));
203+
Invoke(() => OnUsageInfoChanged?.Invoke(sessionName, new SessionUsageInfo(aModel, null, null, aInput, aOutput, aPremiumQuota)));
188204
}
189205
break;
190206

PolyPilot/Services/CopilotService.cs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1040,5 +1040,14 @@ public record SessionUsageInfo(
10401040
int? CurrentTokens,
10411041
int? TokenLimit,
10421042
int? InputTokens,
1043-
int? OutputTokens
1043+
int? OutputTokens,
1044+
QuotaInfo? PremiumQuota = null
1045+
);
1046+
1047+
public record QuotaInfo(
1048+
bool IsUnlimited,
1049+
int EntitlementRequests,
1050+
int UsedRequests,
1051+
int RemainingPercentage,
1052+
string? ResetDate
10441053
);

0 commit comments

Comments
 (0)