186186(cl-defstruct (gptel--gh (:include gptel-openai)
187187 (:copier nil )
188188 (:constructor gptel--make-gh))
189- token github-token sessionid machineid)
190-
191- (defcustom gptel-gh-github-token-file (expand-file-name " .cache/copilot-chat/github-token"
192- user-emacs-directory)
193- " File where the GitHub token is stored."
194- :type 'string
195- :group 'gptel )
196-
197- (defcustom gptel-gh-token-file (expand-file-name " .cache/copilot-chat/token"
198- user-emacs-directory)
199- " File where the chat token is cached."
200- :type 'string
201- :group 'gptel )
189+ sessionid machineid)
202190
203191(defconst gptel--gh-auth-common-headers
204192 `((" editor-plugin-version" . " gptel/*" )
205193 (" editor-version" . ,(concat " emacs/" emacs-version))))
206194
207195(defconst gptel--gh-client-id " Iv1.b507a08c87ecfe98" )
208196
197+ (defvar gptel--gh-token nil )
198+ (defvar gptel--gh-github-token nil )
199+
209200; ; https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_4_(random)
210201(defun gptel--gh-uuid ()
211202 " Generate a UUID v4-1."
225216 (setq hex (nconc hex (list (aref hex-chars (random 16 ))))))
226217 (apply #'string hex)))
227218
228- (defun gptel--gh-restore (file )
229- " Restore saved object from FILE."
230- (when (file-exists-p file)
231- ; ; We set the coding system to `utf-8-auto-dos' when reading so that
232- ; ; files with CR EOL can still be read properly
233- (let ((coding-system-for-read 'utf-8-auto-dos ))
234- (with-temp-buffer
235- (set-buffer-multibyte nil )
236- (insert-file-contents-literally file)
237- (goto-char (point-min ))
238- (read (current-buffer ))))))
239-
240- (defun gptel--gh-save (file obj )
219+ (defun gptel--gh-save (obj )
241220 " Save OBJ to FILE."
242- (let ((print-length nil )
243- (print-level nil )
244- (coding-system-for-write 'utf-8-unix ))
245- (make-directory (file-name-directory file) t )
246- (write-region (prin1-to-string obj) nil file nil :silent )
247- obj))
221+ (message " New GitHub token: %s " (prin1-to-string obj))
222+ (setq gptel--gh-github-token obj))
248223
249224(defun gptel-gh-login ()
250225 " Login to GitHub Copilot API.
@@ -276,13 +251,11 @@ If your browser does not open automatically, browse to %s."
276251 :device_code , device_code
277252 :grant_type " urn:ietf:params:oauth:grant-type:device_code" ))
278253 :access_token )
279- (gptel--gh-save gptel-gh-github-token-file)
280- (setf (gptel--gh-github-token gptel-backend))))
281- (if (and (gptel--gh-github-token gptel-backend)
282- (not (string-empty-p
283- (gptel--gh-github-token gptel-backend))))
284- (message " Successfully logged in to GitHub Copilot " )
285- (user-error " Error: You might not have access to GitHub Copilot Chat!" )))
254+ (gptel--gh-save))
255+ (if (and gptel--gh-github-token
256+ (not (string-empty-p gptel--gh-github-token)))
257+ (message " Successfully logged in to GitHub Copilot " )
258+ (user-error " Error: You might not have access to GitHub Copilot Chat!" ))))
286259
287260(defun gptel--gh-renew-token ()
288261 " Renew session token."
@@ -291,34 +264,22 @@ If your browser does not open automatically, browse to %s."
291264 " https://api.github.com/copilot_internal/v2/token"
292265 :method 'get
293266 :headers `((" authorization"
294- . ,(format " token %s " ( gptel--gh-github-token gptel-backend) ))
267+ . ,(format " token %s " gptel--gh-github-token))
295268 ,@gptel--gh-auth-common-headers ))))
296269 (if (not (plist-get token :token ))
297- (progn
298- (setf (gptel--gh-github-token gptel-backend) nil )
299- (user-error " Error: You might not have access to GitHub Copilot Chat!" ))
300- (thread-last
301- (gptel--gh-save gptel-gh-token-file token)
302- (setf (gptel--gh-token gptel-backend))))))
270+ (user-error " Error: You might not have access to GitHub Copilot Chat!" )
271+ (setq gptel--gh-token token))))
303272
304273(defun gptel--gh-auth ()
305274 " Authenticate with GitHub Copilot API.
306275
307276We first need github authorization (github token).
308277Then we need a session token."
309- (unless (gptel--gh-github-token gptel-backend)
310- (let ((token (gptel--gh-restore gptel-gh-github-token-file)))
311- (if token
312- (setf (gptel--gh-github-token gptel-backend) token)
313- (gptel-gh-login))))
314-
315- (when (null (gptel--gh-token gptel-backend))
316- ; ; try to load token from `gptel-gh-token-file'
317- (setf (gptel--gh-token gptel-backend)
318- (gptel--gh-restore gptel-gh-token-file)))
278+ (unless gptel--gh-github-token
279+ (gptel-gh-login))
319280
320281 (pcase-let (((map :token :expires_at )
321- ( gptel--gh-token gptel-backend) ))
282+ gptel--gh-token))
322283 (when (or (null token)
323284 (and expires_at
324285 (> (round (float-time (current-time )))
@@ -331,8 +292,7 @@ Then we need a session token."
331292 (header (lambda ()
332293 (gptel--gh-auth)
333294 `((" openai-intent" . " conversation-panel" )
334- (" authorization" . ,(concat " Bearer "
335- (plist-get (gptel--gh-token gptel-backend) :token )))
295+ (" authorization" . ,(concat " Bearer " (plist-get gptel--gh-token :token )))
336296 (" x-request-id" . ,(gptel--gh-uuid))
337297 (" vscode-sessionid" . ,(or (gptel--gh-sessionid gptel-backend) " " ))
338298 (" vscode-machineid" . ,(or (gptel--gh-machineid gptel-backend) " " ))
@@ -344,7 +304,8 @@ Then we need a session token."
344304 (protocol " https" )
345305 (endpoint " /chat/completions" )
346306 (stream t )
347- (models gptel--gh-models))
307+ (models gptel--gh-models)
308+ (github-token-init nil ))
348309 " Register a Github Copilot chat backend for gptel with NAME.
349310
350311Keyword arguments:
@@ -396,6 +357,9 @@ parameters (as plist keys) and values supported by the API. Use
396357these to set parameters that gptel does not provide user options
397358for."
398359 (declare (indent 1 ))
360+ (if (and (not gptel--gh-github-token)
361+ github-token-init)
362+ (gptel--gh-save (funcall github-token-init)))
399363 (let ((backend (gptel--make-gh
400364 :name name
401365 :host host
0 commit comments