@jeffreycao/copilot-api 2.7.12 → 2.7.14

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 (28) hide show
  1. package/README.md +2 -2
  2. package/README.zh-CN.md +2 -2
  3. package/dist/{auth-K4YwtW2M.js → auth--x4CIFvT.js} +4 -4
  4. package/dist/{auth-K4YwtW2M.js.map → auth--x4CIFvT.js.map} +1 -1
  5. package/dist/auth-1hGXVwvW.js +2 -0
  6. package/dist/{config-Cs3Ol5sJ.js → config-BKA4Y1t8.js} +2 -2
  7. package/dist/{config-Cs3Ol5sJ.js.map → config-BKA4Y1t8.js.map} +1 -1
  8. package/dist/{config-store-C6GAtKLz.js → config-store-CC5TNG7V.js} +2 -2
  9. package/dist/{config-store-C6GAtKLz.js.map → config-store-CC5TNG7V.js.map} +1 -1
  10. package/dist/{copilot-runtime-DhtRP9zU.js → copilot-runtime-CW4zUahm.js} +3 -3
  11. package/dist/{copilot-runtime-DhtRP9zU.js.map → copilot-runtime-CW4zUahm.js.map} +1 -1
  12. package/dist/{debug-B7hUvJa4.js → debug-BPNjSHgl.js} +3 -3
  13. package/dist/{debug-B7hUvJa4.js.map → debug-BPNjSHgl.js.map} +1 -1
  14. package/dist/main.js +4 -4
  15. package/dist/{provider-CzziTLqX.js → provider-Dg-3-rrN.js} +2 -2
  16. package/dist/{provider-CzziTLqX.js.map → provider-Dg-3-rrN.js.map} +1 -1
  17. package/dist/{provider-management-DOfLC7WX.js → provider-management-CBrc2nDg.js} +2 -2
  18. package/dist/{provider-management-DOfLC7WX.js.map → provider-management-CBrc2nDg.js.map} +1 -1
  19. package/dist/{server-DBfAMzVE.js → server-CeyKV5sQ.js} +93 -22
  20. package/dist/server-CeyKV5sQ.js.map +1 -0
  21. package/dist/{start-BNzCkjva.js → start-COhhmcdU.js} +7 -7
  22. package/dist/{start-BNzCkjva.js.map → start-COhhmcdU.js.map} +1 -1
  23. package/dist/{token-C7R7Vd9b.js → token-BdwhXP3l.js} +3 -3
  24. package/dist/{token-C7R7Vd9b.js.map → token-BdwhXP3l.js.map} +1 -1
  25. package/package.json +1 -1
  26. package/pages/index.html +115 -10
  27. package/dist/auth-B_zdWSA1.js +0 -2
  28. package/dist/server-DBfAMzVE.js.map +0 -1
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "$schema": "https://json.schemastore.org/package.json",
3
3
  "name": "@jeffreycao/copilot-api",
4
- "version": "2.7.12",
4
+ "version": "2.7.14",
5
5
  "description": "GitHub Copilot, OpenAI Codex, OpenCode Go, and third-party AI provider gateway with OpenAI and Anthropic API compatibility.",
6
6
  "keywords": [
7
7
  "github-copilot",
package/pages/index.html CHANGED
@@ -672,6 +672,7 @@
672
672
  };
673
673
 
674
674
  // --- State Management ---
675
+ const SESSION_PAGE_SIZE = 10;
675
676
  const state = {
676
677
  activeTab: "usage",
677
678
  models: null,
@@ -687,6 +688,10 @@
687
688
  data: null,
688
689
  tokenUsageDailySummary: null,
689
690
  tokenUsageSummary: null,
691
+ tokenUsageSessionsPage: null,
692
+ isSessionsLoading: false,
693
+ sessionsRequestId: 0,
694
+ tokenUsageSessionsError: null,
690
695
  tokenUsageEventsPage: null,
691
696
  tokenUsageDailyError: null,
692
697
  tokenUsageSummaryError: null,
@@ -939,15 +944,24 @@
939
944
  return url.toString();
940
945
  }
941
946
 
942
- function buildTokenUsageEventsUrl(usageEndpoint, period, page) {
947
+ function buildTokenUsageEventsUrl(
948
+ usageEndpoint,
949
+ period,
950
+ page,
951
+ kind = "events"
952
+ ) {
943
953
  const url = new URL(
944
- deriveEndpointUrl(usageEndpoint, "token-usage/events")
954
+ deriveEndpointUrl(usageEndpoint, `token-usage/${kind}`)
945
955
  );
946
956
  url.searchParams.set("period", period);
947
957
  url.searchParams.set("page", String(page));
948
958
  url.searchParams.set(
949
959
  "page_size",
950
- String(DEFAULT_TOKEN_USAGE_EVENTS_PAGE_SIZE)
960
+ String(
961
+ kind === "sessions"
962
+ ? SESSION_PAGE_SIZE
963
+ : DEFAULT_TOKEN_USAGE_EVENTS_PAGE_SIZE
964
+ )
951
965
  );
952
966
  return url.toString();
953
967
  }
@@ -1635,6 +1649,7 @@
1635
1649
  const summary = state.tokenUsageSummary;
1636
1650
  const dailySummary = state.tokenUsageDailySummary;
1637
1651
  const eventsPage = state.tokenUsageEventsPage;
1652
+ const sessionsPage = state.tokenUsageSessionsPage;
1638
1653
  const totals = summary?.totals || EMPTY_TOKEN_USAGE_TOTALS;
1639
1654
  const activeRange =
1640
1655
  summary?.range || dailySummary?.range || eventsPage?.range || null;
@@ -1783,6 +1798,28 @@
1783
1798
  ${renderTokenUsageModelBreakdown(summary)}
1784
1799
  </div>
1785
1800
 
1801
+ <div class="panel">
1802
+ <div class="panel-header">
1803
+ <div>
1804
+ <p class="panel-title">Session Breakdown</p>
1805
+ <p class="panel-meta">${sessionsPage ? `Page ${sessionsPage.page} / ${sessionsPage.total_pages} - ${formatNumber(sessionsPage.total)} sessions` : "No session rows loaded."}</p>
1806
+ </div>
1807
+ <div class="flex items-center gap-2">
1808
+ <button type="button" data-session-page="-1" class="pill-button px-3 py-1.5 text-xs font-semibold" ${!sessionsPage || state.isSessionsLoading || sessionsPage.page <= 1 ? "disabled" : ""}>Previous</button>
1809
+ <button type="button" data-session-page="1" class="pill-button px-3 py-1.5 text-xs font-semibold" ${!sessionsPage || state.isSessionsLoading || sessionsPage.page >= sessionsPage.total_pages ? "disabled" : ""}>Next</button>
1810
+ </div>
1811
+ </div>
1812
+ ${
1813
+ state.tokenUsageSessionsError
1814
+ ? `<div class="p-4">${renderError(
1815
+ state.tokenUsageSessionsError,
1816
+ "Session breakdown failed"
1817
+ )}<button type="button" data-session-page="0" class="pill-button mt-2 px-3 py-1.5 text-xs font-semibold">Retry</button></div>`
1818
+ : ""
1819
+ }
1820
+ ${renderTokenUsageModelBreakdown({ bySession: sessionsPage?.items }, "session")}
1821
+ </div>
1822
+
1786
1823
  <div class="panel">
1787
1824
  <div class="panel-header flex-col items-start sm:flex-row sm:items-center">
1788
1825
  <div>
@@ -2248,20 +2285,22 @@
2248
2285
  `;
2249
2286
  }
2250
2287
 
2251
- function renderTokenUsageModelBreakdown(summary) {
2252
- if (!summary || summary.byModel.length === 0) {
2288
+ function renderTokenUsageModelBreakdown(summary, by = "model") {
2289
+ const items = by === "session" ? summary?.bySession : summary?.byModel;
2290
+ if (!items || items.length === 0) {
2253
2291
  return renderEmptyState(
2254
2292
  "No token usage recorded for the selected period."
2255
2293
  );
2256
2294
  }
2257
2295
 
2258
- const rows = summary.byModel
2296
+ const rows = items
2259
2297
  .map((model) => {
2298
+ const name = formatCellText(by === "session" ? model.session_id : model.model);
2260
2299
  return `
2261
2300
  <tr class="border-b last:border-b-0" style="border-color: var(--color-bg-light-1);">
2262
- <td class="px-4 py-2 max-w-[280px] truncate" style="color: var(--color-fg-lightest);" title="${escapeHtml(
2263
- model.model
2264
- )}">${escapeHtml(model.model)}</td>
2301
+ <td class="px-4 py-2 max-w-[280px] truncate${by === "session" ? " font-mono" : ""}" style="color: var(--color-fg-lightest);" title="${escapeHtml(
2302
+ name
2303
+ )}">${escapeHtml(name)}</td>
2265
2304
  <td class="px-4 py-2 text-right" style="color: var(--color-fg-dark);">${formatNumber(
2266
2305
  model.request_count
2267
2306
  )}</td>
@@ -2296,7 +2335,7 @@
2296
2335
  <table class="data-table min-w-[960px] text-left">
2297
2336
  <thead>
2298
2337
  <tr>
2299
- <th class="px-4 py-2 font-semibold">Model</th>
2338
+ <th class="px-4 py-2 font-semibold">${by === "session" ? "Session" : "Model"}</th>
2300
2339
  <th class="px-4 py-2 text-right font-semibold">Requests</th>
2301
2340
  <th class="px-4 py-2 text-right font-semibold">Input</th>
2302
2341
  <th class="px-4 py-2 text-right font-semibold">Output</th>
@@ -2473,6 +2512,7 @@
2473
2512
  * Fetches usage data and token usage data from the specified API endpoint.
2474
2513
  */
2475
2514
  async function fetchData(page = 1) {
2515
+ invalidateSessionsRequest();
2476
2516
  const endpoint = endpointUrlInput.value.trim();
2477
2517
  if (!endpoint) {
2478
2518
  state.data = null;
@@ -2516,6 +2556,7 @@
2516
2556
 
2517
2557
  if (summaryResult.status === "fulfilled") {
2518
2558
  state.tokenUsageSummary = summaryResult.value;
2559
+ void fetchTokenUsageSessionsPage(1);
2519
2560
  } else if (
2520
2561
  isMissingTokenUsageEndpointError(summaryResult.reason)
2521
2562
  ) {
@@ -2572,6 +2613,7 @@
2572
2613
  }
2573
2614
 
2574
2615
  async function fetchTokenUsageSummaryAndEvents(page = 1) {
2616
+ invalidateSessionsRequest();
2575
2617
  const endpoint = endpointUrlInput.value.trim();
2576
2618
  if (!endpoint) {
2577
2619
  state.tokenUsageDailySummary = null;
@@ -2607,6 +2649,7 @@
2607
2649
 
2608
2650
  if (summaryResult.status === "fulfilled") {
2609
2651
  state.tokenUsageSummary = summaryResult.value;
2652
+ void fetchTokenUsageSessionsPage(1);
2610
2653
  } else if (
2611
2654
  isMissingTokenUsageEndpointError(summaryResult.reason)
2612
2655
  ) {
@@ -2692,6 +2735,56 @@
2692
2735
  }
2693
2736
  }
2694
2737
 
2738
+ async function fetchTokenUsageSessionsPage(page) {
2739
+ const endpoint = endpointUrlInput.value.trim();
2740
+ if (!endpoint) {
2741
+ return;
2742
+ }
2743
+
2744
+ const requestId = ++state.sessionsRequestId;
2745
+ state.isSessionsLoading = true;
2746
+ state.tokenUsageSessionsError = null;
2747
+ render();
2748
+
2749
+ try {
2750
+ const result = await fetchJson(
2751
+ buildTokenUsageEventsUrl(
2752
+ resolveUsageUrl(endpoint),
2753
+ getSelectedPeriod(),
2754
+ page,
2755
+ "sessions"
2756
+ )
2757
+ );
2758
+ if (requestId !== state.sessionsRequestId) {
2759
+ return;
2760
+ }
2761
+ state.tokenUsageSessionsPage = result;
2762
+ } catch (error) {
2763
+ if (requestId !== state.sessionsRequestId) {
2764
+ return;
2765
+ }
2766
+ // Older servers have no sessions endpoint; show the empty state.
2767
+ if (isMissingTokenUsageEndpointError(error)) {
2768
+ state.tokenUsageSessionsPage = null;
2769
+ } else {
2770
+ console.error("Token usage sessions fetch error:", error);
2771
+ state.tokenUsageSessionsError = getErrorMessage(error);
2772
+ }
2773
+ }
2774
+
2775
+ state.isSessionsLoading = false;
2776
+ render("usage");
2777
+ }
2778
+
2779
+ // Clears sessions when refreshing the endpoint or period and ignores
2780
+ // late responses from the previous context.
2781
+ function invalidateSessionsRequest() {
2782
+ state.sessionsRequestId += 1;
2783
+ state.isSessionsLoading = false;
2784
+ state.tokenUsageSessionsPage = null;
2785
+ state.tokenUsageSessionsError = null;
2786
+ }
2787
+
2695
2788
  // --- Event Handlers & Initialization ---
2696
2789
 
2697
2790
  /**
@@ -2753,6 +2846,18 @@
2753
2846
  return;
2754
2847
  }
2755
2848
 
2849
+ const sessionButton = event.target.closest("[data-session-page]");
2850
+ if (sessionButton) {
2851
+ if (!state.isSessionsLoading) {
2852
+ // Offset 0 is the error retry button: reload the current page.
2853
+ void fetchTokenUsageSessionsPage(
2854
+ (state.tokenUsageSessionsPage?.page ?? 1)
2855
+ + Number(sessionButton.getAttribute("data-session-page"))
2856
+ );
2857
+ }
2858
+ return;
2859
+ }
2860
+
2756
2861
  const actionButton = event.target.closest("[data-page-action]");
2757
2862
  if (!actionButton || !state.tokenUsageEventsPage || state.isEventsLoading) {
2758
2863
  return;
@@ -1,2 +0,0 @@
1
- import { t as auth } from "./auth-K4YwtW2M.js";
2
- export { auth };