Skip to content

Commit d1400c2

Browse files
committed
gptel-bedrock: allow configuring AWS profile via gptel-make-bedrock
The `gptel-make-bedrock` function now accepts a `:profile` keyword argument. This allows an AWS profile to be specified directly in the backend configuration, overriding any environment variables. The credential resolution order has been updated to prioritize the most specific configuration: 1. Explicit profile in backend or request parameters 2. `AWS_PROFILE` environment variable 3. `AWS_ACCESS_KEY_ID`/`AWS_SECRET_ACCESS_KEY` environment variables This makes managing AWS credentials more flexible and robust, especially for users who interact with multiple AWS accounts or prefer to keep their configuration self-contained within Emacs. Here are the key benefits: - Context-Specific Configurations: Users often work with different AWS accounts for various purposes (e.g., a personal account, a work development account, and a work production account). This feature allows you to define multiple `gptel` backends, each configured to use a specific AWS profile. You can then easily switch between these backends within Emacs without altering your system-wide environment variables. - Self-Contained Emacs Configuration: For users who prefer to manage their entire workflow within Emacs, this change allows them to define AWS profiles directly in their Emacs configuration files (e.g., `init.el`). This eliminates the dependency on external shell environment variables like `AWS_PROFILE`, making the setup cleaner and more portable across different machines. - Clarity and Reproducibility: Explicitly defining the profile in the backend configuration makes it transparent which set of credentials is being used. This is particularly valuable for literate programming or computational notebooks, as it documents the execution context directly alongside the code, improving reproducibility. - Override Global Defaults: A user might have a default `AWS_PROFILE` set in their shell for general command-line use. This feature provides a convenient way to override that default for tasks performed within Emacs, without affecting the environment in their terminal.
1 parent 1b8d913 commit d1400c2

File tree

1 file changed

+31
-22
lines changed

1 file changed

+31
-22
lines changed

gptel-bedrock.el

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@
3636
(cl-defstruct (gptel-bedrock (:constructor gptel--make-bedrock)
3737
(:copier nil)
3838
(:include gptel-backend))
39-
model-region)
39+
model-region
40+
profile)
4041

4142
(defconst gptel-bedrock--prompt-type
4243
;; For documentation purposes only -- this describes the type of prompt objects that get passed
@@ -506,38 +507,43 @@ Non-nil CLEAR-CACHE will refresh credentials."
506507
(or (and (not clear-cache) (cdr cell))
507508
(setf (cdr cell)
508509
(with-temp-buffer
509-
(unless (zerop (call-process "aws" nil t nil "configure" "export-credentials"
510-
(format "--profile=%s" profile)))
511-
(user-error "Failed to get AWS credentials from profile"))
512-
(json-parse-string (buffer-string)))))))
513-
(expiration (if-let (exp (gethash "Expiration" creds-json))
514-
(date-to-time exp))))
510+
(unless (zerop (call-process "aws" nil t nil "configure" "export-credentials"
511+
(format "--profile=%s" profile)))
512+
(user-error "Failed to get AWS credentials from profile"))
513+
(json-parse-string (buffer-string)))))))
514+
(expiration (if-let (exp (gethash "Expiration" creds-json))
515+
(date-to-time exp))))
515516
(cond
516517
((time-less-p (current-time) expiration)
517518
(let ((access-key (gethash "AccessKeyId" creds-json))
518-
(secret-key (gethash "SecretAccessKey" creds-json))
519-
(session-token (gethash "SessionToken" creds-json)))
520-
(cl-values access-key secret-key session-token)))
519+
(secret-key (gethash "SecretAccessKey" creds-json))
520+
(session-token (gethash "SessionToken" creds-json)))
521+
(cl-values access-key secret-key session-token)))
521522
((not clear-cache)
522523
(gptel-bedrock--fetch-aws-profile-credentials profile t))
523524
(t (user-error "AWS credentials expired for profile: %s" profile)))))
524525

525526
(defun gptel-bedrock--get-credentials ()
526527
"Return the AWS credentials to use for the request.
527528
528-
Returns a list of 2-3 elements, depending on whether a session
529-
token is needed, with this form: (AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY
530-
AWS_SESSION_TOKEN).
529+
Returns credentials based on the following priority:
530+
1. Explicit profile specified in backend or request-params
531+
2. AWS_PROFILE environment variable
532+
3. Direct AWS credentials environment variables
533+
4. Raise an error if no credentials are found.
531534
532535
Convenient to use with `cl-multiple-value-bind'"
533-
(let ((key-id (getenv "AWS_ACCESS_KEY_ID"))
536+
(let ((profile (or (gptel-bedrock-profile gptel-backend)
537+
(plist-get (gptel-backend-request-params gptel-backend) :profile)))
538+
(env-profile (getenv "AWS_PROFILE"))
539+
(key-id (getenv "AWS_ACCESS_KEY_ID"))
534540
(secret-key (getenv "AWS_SECRET_ACCESS_KEY"))
535-
(token (getenv "AWS_SESSION_TOKEN"))
536-
(profile (getenv "AWS_PROFILE")))
541+
(token (getenv "AWS_SESSION_TOKEN")))
537542
(cond
538-
((and key-id secret-key) (cl-values key-id secret-key token))
539543
((and profile) (gptel-bedrock--fetch-aws-profile-credentials profile))
540-
(t (user-error "Missing AWS credentials; currently only environment variables are supported")))))
544+
((and env-profile) (gptel-bedrock--fetch-aws-profile-credentials env-profile))
545+
((and key-id secret-key) (cl-values key-id secret-key token))
546+
(t (user-error "Missing AWS credentials; currently only explicit profile, environment variables, or backend config are supported")))))
541547

542548
(defvar gptel-bedrock--model-ids
543549
;; https://docs.aws.amazon.com/bedrock/latest/userguide/models-supported.html
@@ -581,7 +587,7 @@ REGION is one of apac, eu or us."
581587
(concat
582588
(when region
583589
(or (member region '(apac eu us))
584-
(error "Unknown Bedrock region %s" region))
590+
(error "Unknown Bedrock region %s" region))
585591
(concat (symbol-name region) "."))
586592
(or (alist-get model gptel-bedrock--model-ids nil nil #'eq)
587593
(error "Unknown Bedrock model: %s" model))))
@@ -612,16 +618,18 @@ REGION is one of apac, eu or us."
612618
(name &key
613619
region
614620
(models gptel--bedrock-models)
615-
(model-region nil)
621+
(model-region nil)
616622
stream curl-args request-params
617-
(protocol "https"))
623+
(protocol "https")
624+
profile)
618625
"Register an AWS Bedrock backend for gptel with NAME.
619626
620627
Keyword arguments:
621628
622629
REGION - AWS region name (e.g. \"us-east-1\")
623630
MODELS - The list of models supported by this backend
624631
MODEL-REGION - one of apac, eu, us or nil
632+
PROFILE - AWS profile name to use (overrides env)
625633
CURL-ARGS - additional curl args
626634
STREAM - Whether to use streaming responses or not.
627635
REQUEST-PARAMS - a plist of additional HTTP request
@@ -637,7 +645,8 @@ parameters (as plist keys) and values supported by the API."
637645
:host host
638646
:header nil ; x-amz-security-token is set in curl-args if needed
639647
:models (gptel--process-models models)
640-
:model-region model-region
648+
:model-region model-region
649+
:profile profile
641650
:protocol protocol
642651
:endpoint "" ; Url is dynamically constructed based on other args
643652
:stream stream

0 commit comments

Comments
 (0)