Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 39 additions & 8 deletions agent-shell-anthropic.el
Original file line number Diff line number Diff line change
Expand Up @@ -36,38 +36,54 @@
(autoload 'agent-shell-make-agent-config "agent-shell")
(declare-function agent-shell--dwim "agent-shell")

(cl-defun agent-shell-anthropic-make-authentication (&key api-key login)
(cl-defun agent-shell-anthropic-make-authentication (&key api-key login oauth)
"Create anthropic authentication configuration.

API-KEY is the Anthropic API key string.
API-KEY is the Anthropic API key string or a function returning one.
LOGIN when non-nil indicates to use login-based authentication.
OAUTH is an OAuth token string or a function returning one.

Only one of API-KEY or LOGIN should be provided, never both."
Only one of API-KEY, LOGIN, or OAUTH should be provided, never more than one."
(when (and api-key login)
(error "Cannot specify both :api-key and :login - choose one"))
(unless (or api-key login)
(error "Must specify either :api-key or :login"))
(when (and oauth login)
(error "Cannot specify both :oauth and :login - choose one"))
(when (and api-key oauth)
(error "Cannot specify both :api-key and :oauth - choose one"))
(unless (or api-key login oauth)
(error "Must specify either :api-key, :login, or :oauth"))
(cond
(oauth `((:oauth . ,oauth)))
(api-key `((:api-key . ,api-key)))
(login `((:login . t)))))

(defcustom agent-shell-anthropic-authentication
(agent-shell-anthropic-make-authentication :login t)
"Configuration for Anthropic authentication.
For Subcription/login (default):
For subscription/login (default):

(setq agent-shell-anthropic-authentication
(agent-shell-anthropic-make-authentication :login t))

For api key:

(setq agent-shell-anthropic-authentication
(agent-shell-make-anthropic-authentication :api-key \"your-key\"))
(agent-shell-anthropic-make-authentication :api-key \"your-key\"))

or

(setq agent-shell-anthropic-authentication
(agent-shell-make-anthropic-authentication :api-key (lambda () ... )))"
(agent-shell-anthropic-make-authentication :api-key (lambda () ... )))

For OAuth token:

(setq agent-shell-anthropic-authentication
(agent-shell-anthropic-make-authentication :oauth \"your-token\"))

or

(setq agent-shell-anthropic-authentication
(agent-shell-anthropic-make-authentication :oauth (lambda () ... )))"
:type 'alist
:group 'agent-shell)

Expand Down Expand Up @@ -159,6 +175,9 @@ additional environment variables."
(agent-shell-anthropic-key))))
((map-elt agent-shell-anthropic-authentication :login)
(list "ANTHROPIC_API_KEY="))
((map-elt agent-shell-anthropic-authentication :oauth)
(list (format "CLAUDE_CODE_OAUTH_TOKEN=%s"
(agent-shell-anthropic-oauth-token))))
(t
(error "Invalid authentication configuration")))))
(agent-shell--make-acp-client :command (car agent-shell-anthropic-claude-acp-command)
Expand All @@ -179,6 +198,18 @@ additional environment variables."
(t
nil)))

(defun agent-shell-anthropic-oauth-token ()
"Get the Anthropic OAuth token."
(cond ((stringp (map-elt agent-shell-anthropic-authentication :oauth))
(map-elt agent-shell-anthropic-authentication :oauth))
((functionp (map-elt agent-shell-anthropic-authentication :oauth))
(condition-case _err
(funcall (map-elt agent-shell-anthropic-authentication :oauth))
(error
"OAuth token not found. Check out `agent-shell-anthropic-authentication'")))
(t
nil)))

(defun agent-shell-anthropic--claude-code-welcome-message (config)
"Return Claude Code ASCII art as per own repo using `shell-maker' CONFIG."
(let ((art (agent-shell--indent-string 4 (agent-shell-anthropic--claude-code-ascii-art)))
Expand Down
24 changes: 24 additions & 0 deletions tests/agent-shell-anthropic-tests.el
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,30 @@
(should (member "ANTHROPIC_API_KEY=test-key" env-vars))
(should (member "NEW_VAR=new_value" env-vars))
(should (member "EXISTING_VAR=existing_value" env-vars)))
(when (buffer-live-p test-buffer)
(kill-buffer test-buffer))))

;; Test with OAuth token string
(let* ((agent-shell-anthropic-authentication '(:oauth "test-oauth-token"))
(agent-shell-anthropic-claude-acp-command '("claude-agent-acp"))
(agent-shell-anthropic-claude-environment '())
(test-buffer (get-buffer-create "*test-buffer*"))
(client (agent-shell-anthropic-make-claude-client :buffer test-buffer))
(env-vars (map-elt client :environment-variables)))
(unwind-protect
(should (member "CLAUDE_CODE_OAUTH_TOKEN=test-oauth-token" env-vars))
(when (buffer-live-p test-buffer)
(kill-buffer test-buffer))))

;; Test with function-based OAuth token
(let* ((agent-shell-anthropic-authentication `(:oauth ,(lambda () "dynamic-oauth-token")))
(agent-shell-anthropic-claude-acp-command '("claude-agent-acp"))
(agent-shell-anthropic-claude-environment '())
(test-buffer (get-buffer-create "*test-buffer*"))
(client (agent-shell-anthropic-make-claude-client :buffer test-buffer))
(env-vars (map-elt client :environment-variables)))
(unwind-protect
(should (member "CLAUDE_CODE_OAUTH_TOKEN=dynamic-oauth-token" env-vars))
(when (buffer-live-p test-buffer)
(kill-buffer test-buffer))))))

Expand Down