diff --git a/.github/workflows/build-backend-stg.yml b/.github/workflows/build-backend-stg.yml index 322e4ec4..bcc54942 100644 --- a/.github/workflows/build-backend-stg.yml +++ b/.github/workflows/build-backend-stg.yml @@ -69,7 +69,7 @@ jobs: XTRAMCP_OPENREVIEW_PASSWORD: ${{ secrets.XTRAMCP_OPENREVIEW_PASSWORD_STG }} XTRAMCP_CROSSREF_EMAIL_ADDRESS: ${{ secrets.XTRAMCP_CROSSREF_EMAIL_ADDRESS_STG }} XTRAMCP_DOI_EMAIL_ADDRESS: ${{ secrets.XTRAMCP_DOI_EMAIL_ADDRESS_STG }} - XTRAMCP_ACL_METADATA_DB_URL: ${{ secrets.XTRAMCP_ACL_METADATA_DB_URL_PRD }} + XTRAMCP_ACL_METADATA_DB_URL: ${{ secrets.XTRAMCP_ACL_METADATA_DB_URL_STG }} XTRAMCP_ARXIV_METADATA_DB_URL: ${{ secrets.XTRAMCP_ARXIV_METADATA_DB_URL_STG }} XTRAMCP_MONGO_URI: ${{ secrets.XTRAMCP_MONGO_URI_STG }} MONGO_URI: ${{ secrets.MONGO_URI_STG }} diff --git a/README.md b/README.md index 4dcd38ab..1fcbada2 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ License -**PaperDebugger** is an AI-powered academic writing assistant that helps researchers debug and improve their research papers with intelligent suggestions and seamless Overleaf integration, without leaving the editor. It is powered by a custom MCP-based orchestration engine that simulates the full academic workflow **Research → Critique → Revision**.
+**PaperDebugger** is an AI-powered academic writing assistant that helps researchers debug and improve their research papers with intelligent suggestions and seamless Overleaf integration, without leaving the editor. It is powered by our [custom MCP-based orchestration engine](demo/xtramcp/readme.md) that simulates the full academic workflow **Research → Critique → Revision**.
This enables multi-step reasoning, reviewer-style critique, and structured revision passes beyond standard chat-based assistance.
@@ -50,7 +50,7 @@ PaperDebugger never modifies your project, it only reads and provides suggestion - **💬 Comment System**: Automatically generate and insert comments into your project - **📚 Prompt Library**: Custom prompt templates for different use cases - **🔒 Privacy First**: Your content stays secure - we only read, never modify -- **🧠 Multi-Agent Orchestration** – [XtraMCP](https://github.com/PaperDebugger/xtramcp) support for literature-grounded research, AI-Conference review, citation verification, and domain-specific revision +- **🧠 Multi-Agent Orchestration** – [XtraMCP](demo/xtramcp/readme.md) support for literature-grounded research, AI-Conference review, citation verification, and domain-specific revision https://github.com/user-attachments/assets/6c20924d-1eb6-44d5-95b0-207bd08b718b diff --git a/demo/xtramcp/readme.md b/demo/xtramcp/readme.md index ec970988..e2d13de1 100644 --- a/demo/xtramcp/readme.md +++ b/demo/xtramcp/readme.md @@ -19,13 +19,14 @@ This document describes the core tools exposed by XtraMCP and how they combine i | Tool Name | Role | Purpose | Primary Data Source | Presently Deployed | |---------------------------|-----------|-----------------------------------------------------------------|--------------------------------|----------------------| | `search_relevant_papers` | Researcher | Fast semantic search over recent CS papers in a local vector DB, enhanced with semantic re-ranker module | Local DB | Yes | -| `deep_research` | Researcher | Multi-step literature synthesis & positioning of your draft | Local DB + retrieved papers analysis | *Temporarily Disabled* | -| `online_search_papers` | Researcher | Online search over external academic corpora | OpenReview + arXiv | Yes (*Partially*) with arXiv | -| `review_paper` | Reviewer | Conference-style structured review of a draft | Your draft + section-level review (static & semantic) | Yes (*Partially*) — Title, Abstract, Intro — to balance operational cost. | -| `verify_citations` | Reviewer | Ensure citations are grounded, valid, and traceable | Your draft's bibliography | *Coming Soon*! | +| `deep_research` | Researcher | Multi-step literature synthesis & positioning of your draft | Local DB + retrieved papers analysis | Yes | +| `online_search_papers` | Researcher | Online search over external academic corpora | OpenReview + arXiv | Yes | +| `review_paper` | Reviewer | Conference-style structured review of a draft | Your draft + section-level review (static & semantic) | Yes (slightly scaled down to balance operational cost) | +| `verify_citations` | Reviewer | Ensure citations are grounded, valid, and traceable | Your draft's bibliography | Yes | +| `generate_citations` | Reviewer | Generates BibTeX-style citations by simplying providing arxiv ID / DOI / URL / title | Your draft | Yes | | `enhance_academic_writing`| Enhancer | Context-aware rewriting and polishing of selected text | Your draft + XtraGPT | *Temporarily Disabled* | -| `get_user_papers` | Misc / Researcher| Fetch all published papers with description, by a specific user | OpenReview | *Disabled* (requires auth; easy to enable with local deployment) | -| `search_user` | Misc | Fetch user's profile, including info such as publications, co-authors | OpenReview | *Disabled* (requires auth; easy to enable with local deployment)| +| `get_user_papers` | Misc / Researcher| Fetch all published papers with description, by a specific user | OpenReview | Yes | +| `search_user` | Misc | Fetch user's profile, including info such as publications, co-authors | OpenReview | Yes | --- @@ -122,7 +123,7 @@ Analyze and review a draft against the standards of **top-tier ML conferences** ## 5. `verify_citations` **Purpose:** -Verify that citations in your draft are valid, grounded, and traceable, helping reduce the risk of desk rejection due to incorrect or unverifiable references. +Verify that citations in your draft are valid, grounded, and traceable, helping reduce the risk of desk rejection due to incorrect or unverifiable references. There have been [embarrassing cases](https://gptzero.me/news/neurips/) where accepted papers were found with hallucinated citations. This tool helps to avoid such occurrences. **How it works**: - Parses your bibliography and in-text citations. @@ -137,8 +138,21 @@ Typical usage: - “Check whether any citations in this draft are invalid or unverifiable.” --- +## 6. `generate_citations` -## 6. `enhance_academic_writing` +**Purpose:** +Generate BibTeX-style citations easily by simply providing the paper's arxiv ID or DOI or URL or just its title. + +**How it works**: +- Searches online for the paper's official source +- Formats into BibTeX-style citation ready for copy-pasting +- Inform user if proposed information is invalid / unmatched + +Typical usage: +- “generate_citations: [https://arxiv.org/abs/2505.11336, ... ]” + +--- +## 7. `enhance_academic_writing` **Purpose:** Suggest **context-aware academic writing enhancements** for selected text. @@ -157,7 +171,7 @@ Suggest **context-aware academic writing enhancements** for selected text. - "enhance_academic_writing this paragraph to be clearer and more concise, preserving all technical details.” - "enhance_academic_writing the abstract to be suitable for NeurIPS.” -## 7. `get_user_papers` +## 8. `get_user_papers` **Purpose:** Retrieve **all papers authored by a given user** (OpenReview), identified by email. @@ -172,7 +186,7 @@ Useful for quickly assembling a researcher’s publication list or grounding con - “get_user_papers for in summary mode.” - “Retrieve all publications by this researcher and then compare my draft using deep_research.” -## 8. Conference Formatter (WIP) +## 9. Conference Formatter (WIP) Upcoming workflows will: @@ -191,7 +205,8 @@ Upcoming workflows will: - **Reviewer Flow** 1. Run `review_paper` on the full draft. - 2. For high-impact issues, call `enhance_academic_writing` on the relevant spans. + 2. For high-impact issues, call `enhance_academic_writing` on the relevant spans. + 3. Verify your citations with `verify_citations` or if you haven't yet formatted them, include with `generate_citations`. - **Enhancer Flow** 1. Select a paragraph or section in Overleaf. diff --git a/hack/dev.sh b/hack/dev.sh index 78143403..e074ff0a 100755 --- a/hack/dev.sh +++ b/hack/dev.sh @@ -6,20 +6,21 @@ ROOT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." &>/dev/null && pwd) cd $ROOT_DIR OPENAI_BASE_URL=${OPENAI_BASE_URL:-https://api.openai.com/v1} -OPENAI_API_KEY=${OPENAI_API_KEY:-sk-dummy-OPENAI_API_KEY} +OPENAI_API_KEY=${OPENAI_API_KEY:-} INFERENCE_BASE_URL=${INFERENCE_BASE_URL:-https://inference.paperdebugger.workers.dev} -INFERENCE_API_KEY=${INFERENCE_API_KEY:-sk-dummy-OPEN-ROUTER} +INFERENCE_API_KEY=${INFERENCE_API_KEY:-} MCP_BASIC_KEY=${MCP_BASIC_KEY:-sk-dummy-MCP_BASIC_KEY} MCP_PAPERSCORE_KEY=${MCP_PAPERSCORE_KEY:-sk-dummy-MCP_PAPERSCORE_KEY} XTRAMCP_OPENAI_BASE_URL=${XTRAMCP_OPENAI_BASE_URL:-https://api.openai.com/v1} -XTRAMCP_OPENAI_API_KEY=${XTRAMCP_OPENAI_API_KEY:-sk-dummy-XTRAMCP_OPENAI_API_KEY} +XTRAMCP_OPENAI_API_KEY=${XTRAMCP_OPENAI_API_KEY:-} XTRAMCP_OPENREVIEW_BASE_URL=${XTRAMCP_OPENREVIEW_BASE_URL:-https://api2.openreview.net} -XTRAMCP_OPENREVIEW_USERNAME=${XTRAMCP_OPENREVIEW_USERNAME:-dummy-XTRAMCP_OPENREVIEW_USERNAME} -XTRAMCP_OPENREVIEW_PASSWORD=${XTRAMCP_OPENREVIEW_PASSWORD:-dummy-XTRAMCP_OPENREVIEW_PASSWORD} -XTRAMCP_CROSSREF_EMAIL_ADDRESS=${XTRAMCP_CROSSREF_EMAIL_ADDRESS:-dummy-crossref-email-address} -XTRAMCP_DOI_EMAIL_ADDRESS=${XTRAMCP_DOI_EMAIL_ADDRESS:-dummy-doi-email-address} -XTRAMCP_ARXIV_METADATA_DB_URL=${XTRAMCP_ARXIV_METADATA_DB_URL:-postgresql://dummy-arxiv-metadata-db-url} -XTRAMCP_MONGO_URI=${XTRAMCP_MONGO_URI:-mongodb://dummy-mongo-uri} +XTRAMCP_OPENREVIEW_USERNAME=${XTRAMCP_OPENREVIEW_USERNAME:-} +XTRAMCP_OPENREVIEW_PASSWORD=${XTRAMCP_OPENREVIEW_PASSWORD:-} +XTRAMCP_CROSSREF_EMAIL_ADDRESS=${XTRAMCP_CROSSREF_EMAIL_ADDRESS:-} +XTRAMCP_DOI_EMAIL_ADDRESS=${XTRAMCP_DOI_EMAIL_ADDRESS:-} +XTRAMCP_ACL_METADATA_DB_URL=${XTRAMCP_ACL_METADATA_DB_URL:-} +XTRAMCP_ARXIV_METADATA_DB_URL=${XTRAMCP_ARXIV_METADATA_DB_URL:-} +XTRAMCP_MONGO_URI=${XTRAMCP_MONGO_URI:-} PAPERDEBUGGER_IMAGE=${PAPERDEBUGGER_IMAGE:-ghcr.io/paperdebugger/sharelatex-paperdebugger:latest} MONGO_URI=${MONGO_URI:-} GHCR_DOCKER_CONFIG=${GHCR_DOCKER_CONFIG:-dummy-ghcr-docker-config} @@ -42,6 +43,7 @@ helm template $ROOT_DIR/helm-chart \ --set-string xtramcp_openreview_password=$XTRAMCP_OPENREVIEW_PASSWORD \ --set-string xtramcp_crossref_email_address=$XTRAMCP_CROSSREF_EMAIL_ADDRESS \ --set-string xtramcp_doi_email_address=$XTRAMCP_DOI_EMAIL_ADDRESS \ + --set-string xtramcp_acl_metadata_db_url=$XTRAMCP_ACL_METADATA_DB_URL \ --set-string xtramcp_arxiv_metadata_db_url=$XTRAMCP_ARXIV_METADATA_DB_URL \ --set-string xtramcp_mongo_uri=$XTRAMCP_MONGO_URI \ --set-string paperdebugger.image=$PAPERDEBUGGER_IMAGE \ diff --git a/hack/prd.sh b/hack/prd.sh index 26b173e0..f3995d7b 100755 --- a/hack/prd.sh +++ b/hack/prd.sh @@ -6,21 +6,21 @@ ROOT_DIR=$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")/.." &>/dev/null && pwd) cd $ROOT_DIR OPENAI_BASE_URL=${OPENAI_BASE_URL:-https://api.openai.com/v1} -OPENAI_API_KEY=${OPENAI_API_KEY:-sk-dummy-OPENAI_API_KEY} +OPENAI_API_KEY=${OPENAI_API_KEY:-} INFERENCE_BASE_URL=${INFERENCE_BASE_URL:-https://inference.paperdebugger.workers.dev} -INFERENCE_API_KEY=${INFERENCE_API_KEY:-sk-dummy-OPEN-ROUTER} +INFERENCE_API_KEY=${INFERENCE_API_KEY:-} MCP_BASIC_KEY=${MCP_BASIC_KEY:-sk-dummy-MCP_BASIC_KEY} MCP_PAPERSCORE_KEY=${MCP_PAPERSCORE_KEY:-sk-dummy-MCP_PAPERSCORE_KEY} XTRAMCP_OPENAI_BASE_URL=${XTRAMCP_OPENAI_BASE_URL:-https://api.openai.com/v1} -XTRAMCP_OPENAI_API_KEY=${XTRAMCP_OPENAI_API_KEY:-sk-dummy-XTRAMCP_OPENAI_API_KEY} +XTRAMCP_OPENAI_API_KEY=${XTRAMCP_OPENAI_API_KEY:-} XTRAMCP_OPENREVIEW_BASE_URL=${XTRAMCP_OPENREVIEW_BASE_URL:-https://api2.openreview.net} -XTRAMCP_OPENREVIEW_USERNAME=${XTRAMCP_OPENREVIEW_USERNAME:-dummy-XTRAMCP_OPENREVIEW_USERNAME} -XTRAMCP_OPENREVIEW_PASSWORD=${XTRAMCP_OPENREVIEW_PASSWORD:-dummy-XTRAMCP_OPENREVIEW_PASSWORD} -XTRAMCP_CROSSREF_EMAIL_ADDRESS=${XTRAMCP_CROSSREF_EMAIL_ADDRESS:-dummy-crossref-email-address} -XTRAMCP_DOI_EMAIL_ADDRESS=${XTRAMCP_DOI_EMAIL_ADDRESS:-dummy-doi-email-address} -XTRAMCP_ACL_METADATA_DB_URL=${XTRAMCP_ACL_METADATA_DB_URL:-postgresql://dummy-acl-metadata-db-url} -XTRAMCP_ARXIV_METADATA_DB_URL=${XTRAMCP_ARXIV_METADATA_DB_URL:-postgresql://dummy-arxiv-metadata-db-url} -XTRAMCP_MONGO_URI=${XTRAMCP_MONGO_URI:-mongodb://dummy-mongo-uri} +XTRAMCP_OPENREVIEW_USERNAME=${XTRAMCP_OPENREVIEW_USERNAME:-} +XTRAMCP_OPENREVIEW_PASSWORD=${XTRAMCP_OPENREVIEW_PASSWORD:-} +XTRAMCP_CROSSREF_EMAIL_ADDRESS=${XTRAMCP_CROSSREF_EMAIL_ADDRESS:-} +XTRAMCP_DOI_EMAIL_ADDRESS=${XTRAMCP_DOI_EMAIL_ADDRESS:-} +XTRAMCP_ACL_METADATA_DB_URL=${XTRAMCP_ACL_METADATA_DB_URL:-} +XTRAMCP_ARXIV_METADATA_DB_URL=${XTRAMCP_ARXIV_METADATA_DB_URL:-} +XTRAMCP_MONGO_URI=${XTRAMCP_MONGO_URI:-} PAPERDEBUGGER_IMAGE=${PAPERDEBUGGER_IMAGE:-ghcr.io/paperdebugger/sharelatex-paperdebugger:latest} MONGO_URI=${MONGO_URI:-} GHCR_DOCKER_CONFIG=${GHCR_DOCKER_CONFIG:-dummy-ghcr-docker-config} diff --git a/hack/stg.sh b/hack/stg.sh index 9e400860..c1cc86f6 100755 --- a/hack/stg.sh +++ b/hack/stg.sh @@ -8,19 +8,19 @@ cd $ROOT_DIR OPENAI_BASE_URL=${OPENAI_BASE_URL:-https://api.openai.com/v1} OPENAI_API_KEY=${OPENAI_API_KEY:-} INFERENCE_BASE_URL=${INFERENCE_BASE_URL:-https://inference.paperdebugger.workers.dev} -INFERENCE_API_KEY=${INFERENCE_API_KEY:-sk-dummy-OPEN-ROUTER} +INFERENCE_API_KEY=${INFERENCE_API_KEY:-} MCP_BASIC_KEY=${MCP_BASIC_KEY:-sk-dummy-MCP_BASIC_KEY} MCP_PAPERSCORE_KEY=${MCP_PAPERSCORE_KEY:-sk-dummy-MCP_PAPERSCORE_KEY} XTRAMCP_OPENAI_BASE_URL=${XTRAMCP_OPENAI_BASE_URL:-https://api.openai.com/v1} -XTRAMCP_OPENAI_API_KEY=${XTRAMCP_OPENAI_API_KEY:-sk-dummy-XTRAMCP_OPENAI_API_KEY} +XTRAMCP_OPENAI_API_KEY=${XTRAMCP_OPENAI_API_KEY:-} XTRAMCP_OPENREVIEW_BASE_URL=${XTRAMCP_OPENREVIEW_BASE_URL:-https://api2.openreview.net} -XTRAMCP_OPENREVIEW_USERNAME=${XTRAMCP_OPENREVIEW_USERNAME:-dummy-XTRAMCP_OPENREVIEW_USERNAME} -XTRAMCP_OPENREVIEW_PASSWORD=${XTRAMCP_OPENREVIEW_PASSWORD:-dummy-XTRAMCP_OPENREVIEW_PASSWORD} -XTRAMCP_CROSSREF_EMAIL_ADDRESS=${XTRAMCP_CROSSREF_EMAIL_ADDRESS:-dummy-crossref-email-address} -XTRAMCP_DOI_EMAIL_ADDRESS=${XTRAMCP_DOI_EMAIL_ADDRESS:-dummy-doi-email-address} -XTRAMCP_ACL_METADATA_DB_URL=${XTRAMCP_ACL_METADATA_DB_URL:-postgresql://dummy-acl-metadata-db-url} -XTRAMCP_ARXIV_METADATA_DB_URL=${XTRAMCP_ARXIV_METADATA_DB_URL:-postgresql://dummy-arxiv-metadata-db-url} -XTRAMCP_MONGO_URI=${XTRAMCP_MONGO_URI:-mongodb://dummy-mongo-uri} +XTRAMCP_OPENREVIEW_USERNAME=${XTRAMCP_OPENREVIEW_USERNAME:-} +XTRAMCP_OPENREVIEW_PASSWORD=${XTRAMCP_OPENREVIEW_PASSWORD:-} +XTRAMCP_CROSSREF_EMAIL_ADDRESS=${XTRAMCP_CROSSREF_EMAIL_ADDRESS:-} +XTRAMCP_DOI_EMAIL_ADDRESS=${XTRAMCP_DOI_EMAIL_ADDRESS:-} +XTRAMCP_ACL_METADATA_DB_URL=${XTRAMCP_ACL_METADATA_DB_URL:-} +XTRAMCP_ARXIV_METADATA_DB_URL=${XTRAMCP_ARXIV_METADATA_DB_URL:-} +XTRAMCP_MONGO_URI=${XTRAMCP_MONGO_URI:-} PAPERDEBUGGER_IMAGE=${PAPERDEBUGGER_IMAGE:-ghcr.io/paperdebugger/sharelatex-paperdebugger:latest} MONGO_URI=${MONGO_URI:-} GHCR_DOCKER_CONFIG=${GHCR_DOCKER_CONFIG:-dummy-ghcr-docker-config} diff --git a/helm-chart/templates/paperdebugger.yaml b/helm-chart/templates/paperdebugger.yaml index 098d65d2..982e1f1a 100644 --- a/helm-chart/templates/paperdebugger.yaml +++ b/helm-chart/templates/paperdebugger.yaml @@ -15,8 +15,8 @@ spec: spec: imagePullSecrets: - name: ghcr-secret - {{ if .Values.mongo.in_cluster }} initContainers: + {{- if .Values.mongo.in_cluster }} - name: init-mongodb image: mongo:latest command: @@ -26,7 +26,17 @@ spec: "--eval", 'db.isMaster().primary || rs.initiate({_id: "in-cluster", members: [{_id: 0, host: "mongo:27017"}]})', ] - {{ end }} + {{- end }} + - name: wait-for-xtramcp-port + image: busybox:1.36 + command: ["sh", "-c"] + args: + - | + echo "Waiting for xtramcp health endpoint..." + until wget -q --spider http://paperdebugger-xtramcp-server:8080/health; do + sleep 2 + done + echo "xtramcp is healthy." containers: - name: paperdebugger image: {{ .Values.paperdebugger.image }} diff --git a/webapp/_webapp/src/index.css b/webapp/_webapp/src/index.css index 77d8049e..9802e32a 100644 --- a/webapp/_webapp/src/index.css +++ b/webapp/_webapp/src/index.css @@ -219,7 +219,12 @@ object { border: 1px solid; background-color: transparent; overflow: hidden; - @apply overflow-hidden w-full h-full dark:!border-default-200 !border-default-200; + @apply overflow-hidden w-full h-full dark:!border-default-200 !border-default-200 text-default-800; + + textarea, + input { + background-color: var(--pd-default-bg); + } } .pd-app-control-title-bar { diff --git a/webapp/_webapp/src/libs/apiclient.ts b/webapp/_webapp/src/libs/apiclient.ts index bc932787..5f83bfcc 100644 --- a/webapp/_webapp/src/libs/apiclient.ts +++ b/webapp/_webapp/src/libs/apiclient.ts @@ -7,6 +7,7 @@ import { EventEmitter } from "events"; import { ErrorCode, ErrorSchema } from "../pkg/gen/apiclient/shared/v1/shared_pb"; import { errorToast } from "./toasts"; import { storage } from "./storage"; +import { useAuthStore } from "../stores/auth-store"; // Exhaustive type check helper - will cause compile error if a case is not handled const assertNever = (x: never): never => { @@ -29,6 +30,7 @@ class ApiClient { private axiosInstance: AxiosInstance; private refreshToken: string | null; private onTokenRefreshedEventEmitter: EventEmitter; + private refreshPromise: Promise | null = null; constructor(baseURL: string, apiVersion: ApiVersion) { this.axiosInstance = axios.create({ @@ -64,6 +66,8 @@ class ApiClient { } setTokens(token: string, refreshToken: string): void { + useAuthStore.getState().setToken(token); + useAuthStore.getState().setRefreshToken(refreshToken); this.refreshToken = refreshToken; this.axiosInstance.defaults.headers.common["Authorization"] = `Bearer ${token}`; } @@ -89,15 +93,27 @@ class ApiClient { } async refresh() { - const response = await this.axiosInstance.post("/auth/refresh", { - refreshToken: this.refreshToken, - }); - const resp = fromJson(RefreshTokenResponseSchema, response.data); - this.setTokens(resp.token, resp.refreshToken); - this.onTokenRefreshedEventEmitter.emit("tokenRefreshed", { - token: resp.token, - refreshToken: resp.refreshToken, - }); + if (this.refreshPromise) { + return this.refreshPromise; + } + + this.refreshPromise = (async () => { + try { + const response = await this.axiosInstance.post("/auth/refresh", { + refreshToken: this.refreshToken, + }); + const resp = fromJson(RefreshTokenResponseSchema, response.data); + this.setTokens(resp.token, resp.refreshToken); + this.onTokenRefreshedEventEmitter.emit("tokenRefreshed", { + token: resp.token, + refreshToken: resp.refreshToken, + }); + } finally { + this.refreshPromise = null; + } + })(); + + return this.refreshPromise; } private async requestWithRefresh(config: AxiosRequestConfig): Promise {