branch: elpa/gptel
commit 0975d9c84aa41eb3096236e92b333a653df49b0d
Author: Khinshan Khan <khanshan...@gmail.com>
Commit: GitHub <nore...@github.com>

    gptel-gh: Add GitHub Copilot interactive login (#989)
    
    * gptel-gh.el (gptel-gh-login, gptel--gh-login,
    gptel--gh-renew-token): New command `gptel-gh-login', replacing
    noninteractive function `gptel--gh-login'.
    
    * NEWS (New features and UI changes): Mention new command
    `gptel-gh-login'.
    
    * README: Mention new command `gptel-gh-login'.
---
 NEWS        |  5 +++++
 README.org  | 14 ++++++++++----
 gptel-gh.el | 40 ++++++++++++++++++++++++----------------
 3 files changed, 39 insertions(+), 20 deletions(-)

diff --git a/NEWS b/NEWS
index 464244e479b..bde6d53f6d1 100644
--- a/NEWS
+++ b/NEWS
@@ -34,6 +34,11 @@
 
 ** New features and UI changes
 
+- New command ~gptel-gh-login~ to authenticate with GitHub Copilot.  The
+  authentication step happens automatically when you use gptel, so
+  invoking it manually is not required.  But you can use this command to
+  change accounts or refresh your login if required.
+
 - gptel now supports handling reasoning/thinking blocks in responses
   from xAI's Grok models.  This is controlled by
   ~gptel-include-reasoning~, in the same way that it handles other
diff --git a/README.org b/README.org
index 7c47ec4da28..7430d343e63 100644
--- a/README.org
+++ b/README.org
@@ -35,7 +35,7 @@ gptel is a simple Large Language Model chat client for Emacs, 
with support for m
 | Github Models        | ✓        | 
[[https://github.com/settings/tokens][Token]]                      |
 | Novita AI            | ✓        | 
[[https://novita.ai/model-api/product/llm-api?utm_source=github_gptel&utm_medium=github_readme&utm_campaign=link][Token]]
                      |
 | xAI                  | ✓        | 
[[https://console.x.ai?utm_source=github_gptel&utm_medium=github_readme&utm_campaign=link][API
 key]]                    |
-| Github CopilotChat   | ✓        | Github account             |
+| GitHub CopilotChat   | ✓        | GitHub account             |
 | Bedrock              | ✓        | AWS credentials            |
 | Moonshot (Kimi)      | ✓        | API key 
([[https://platform.moonshot.cn/console][CN]] or 
[[https://platform.moonshot.ai/console][Global]])     |
 #+html: </div>
@@ -123,7 +123,7 @@ gptel uses Curl if available, but falls back to the 
built-in url-retrieve to wor
       - [[#novita-ai][Novita AI]]
       - [[#xai][xAI]]
       - [[#aiml-api][AI/ML API]]
-      - [[#github-copilotchat][Github CopilotChat]]
+      - [[#github-copilotchat][GitHub CopilotChat]]
       - [[#aws-bedrock][AWS Bedrock]]
       - [[#moonshot-kimi][Moonshot (Kimi)]]
   - [[#usage][Usage]]
@@ -1020,7 +1020,7 @@ The above code makes the backend available to select.  If 
you want it to be the
 
 #+html: </details>
 #+html: <details><summary>
-**** Github CopilotChat
+**** GitHub CopilotChat
 #+html: </summary>
 
 Register a backend with
@@ -1028,7 +1028,7 @@ Register a backend with
 (gptel-make-gh-copilot "Copilot")
 #+end_src
 
-You will be informed to login into =Github= as required.
+You will be informed to login into =GitHub= as required.
 You can pick this backend from the menu when using gptel (see 
[[#usage][Usage]]).
 
 ***** (Optional) Set as the default gptel backend
@@ -1171,6 +1171,12 @@ gptel provides a few powerful, general purpose and 
flexible commands.  You can d
 | =gptel-org-set-properties= | Write gptel configuration as Org properties, 
for per-heading chat configuration.        |
 
|----------------------------+-----------------------------------------------------------------------------------------|
 
+|------------------+-------------------------------------------------------------------------------------------|
+| *GitHub Copilot* |                                                           
                                |
+|------------------+-------------------------------------------------------------------------------------------|
+| =gptel-gh-login= | Authenticate with GitHub Copilot. (Automatically handled, 
but can be forced if required.) |
+|------------------+-------------------------------------------------------------------------------------------|
+
 *** In any buffer:
 
 1. Call =M-x gptel-send= to send the text up to the cursor. The response will 
be inserted below.  Continue the conversation by typing below the response.
diff --git a/gptel-gh.el b/gptel-gh.el
index 5caef32a742..927be571abb 100644
--- a/gptel-gh.el
+++ b/gptel-gh.el
@@ -207,15 +207,18 @@
     (write-region (prin1-to-string obj) nil file nil :silent)
     obj))
 
-(defun gptel--gh-login()
-  "Manage github login."
+(defun gptel-gh-login ()
+  "Login to GitHub Copilot API.
+
+This will prompt you to authorize in a browser and store the token."
+  (interactive)
   (pcase-let (((map :device_code :user_code :verification_uri)
                (gptel--url-retrieve
-                "https://github.com/login/device/code";
-                :method 'post
-                :headers gptel--gh-auth-common-headers
-                :data `( :client_id ,gptel--gh-client-id
-                         :scope "read:user"))))
+                   "https://github.com/login/device/code";
+                 :method 'post
+                 :headers gptel--gh-auth-common-headers
+                 :data `( :client_id ,gptel--gh-client-id
+                          :scope "read:user"))))
     (gui-set-selection 'CLIPBOARD user_code)
     (read-from-minibuffer
      (format "Your one-time code %s is copied. \
@@ -227,15 +230,20 @@ If your browser does not open automatically, browse to 
%s."
     (thread-last
       (plist-get
        (gptel--url-retrieve
-        "https://github.com/login/oauth/access_token";
-        :method 'post
-        :headers gptel--gh-auth-common-headers
-        :data `( :client_id ,gptel--gh-client-id
-                 :device_code ,device_code
-                 :grant_type "urn:ietf:params:oauth:grant-type:device_code"))
+           "https://github.com/login/oauth/access_token";
+         :method 'post
+         :headers gptel--gh-auth-common-headers
+         :data `( :client_id ,gptel--gh-client-id
+                  :device_code ,device_code
+                  :grant_type "urn:ietf:params:oauth:grant-type:device_code"))
        :access_token)
       (gptel--gh-save gptel-gh-github-token-file)
-      (setf (gptel--gh-github-token gptel-backend)))))
+      (setf (gptel--gh-github-token gptel-backend))))
+  (if (and (gptel--gh-github-token gptel-backend)
+           (not (string-empty-p
+                 (gptel--gh-github-token gptel-backend))))
+      (message "Successfully logged in to GitHub Copilot")
+    (user-error "Error: You might not have access to GitHub Copilot Chat!")))
 
 (defun gptel--gh-renew-token ()
   "Renew session token."
@@ -249,7 +257,7 @@ If your browser does not open automatically, browse to %s."
     (if (not (plist-get token :token))
         (progn
           (setf (gptel--gh-github-token gptel-backend) nil)
-          (user-error "Error: You might not have access to Github Copilot 
Chat!"))
+          (user-error "Error: You might not have access to GitHub Copilot 
Chat!"))
       (thread-last
         (gptel--gh-save gptel-gh-token-file token)
         (setf (gptel--gh-token gptel-backend))))))
@@ -263,7 +271,7 @@ Then we need a session token."
     (let ((token (gptel--gh-restore gptel-gh-github-token-file)))
       (if token
           (setf (gptel--gh-github-token gptel-backend) token)
-        (gptel--gh-login))))
+        (gptel-gh-login))))
 
   (when (null (gptel--gh-token gptel-backend))
     ;; try to load token from `gptel-gh-token-file'

Reply via email to