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'