* gptel.el (gptel-directives): Bump required transient version to
0.4.0. Remove placeholder about hard-coded directives from
the docstring for `gptel-directives'.
* gptel-transient.el (gptel-system-prompt,
gptel-system-prompt--setup): Dynamically generate the system
prompt menu in `gptel-menu'. Delete helper functions that
hard-coded the list of system prompts/directives before.
* gptel-transient.el (gptel--system-prompt-programming,
gptel--system-prompt-default, gptel--system-prompt-writing,
gptel--system-prompt-chat, gptel-system-prompt): Define explicit helper
functions to set the system prompt. This is a temporary workaround for #45
until dynamic transients are supported in a new transient release.
* gptel-curl.el (gptel-curl--stream-cleanup): `gptel-post-response-hook' should
run in the buffer that was current when the request was sent. This was not the
case for the curl method (with response streaming). Fixed.
* gptel.el (gptel--insert-response):
* gptel-transient.el (gptel--suffix-send):
* gptel-curl.el (gptel-curl--stream-filter, gptel-curl--stream-insert-response,
gptel-curl--stream-cleanup):
Handle read-only gptel buffers by redirecting the output to a new buffer (that
pops up automatically). To track this,
- the `:position' argument of the INFO plist, which is a marker, is moved to the
new output buffer.
- the `:buffer' argument of the INFO plist is unmodified, it always points to
the buffer that the request originated from.
* gptel-curl.el (gptel-curl-get-response): Set buffer-local model parameters in
the correct (i.e. gptel) buffer, not in Curl's process buffer. This fixes#43.
* gptel-transient.el (gptel--suffix-send, gptel-menu): When
reading input from the minibuffer and sending the output to an
existing gptel session, only use the prompt read from the
minibuffer. Reword the "Overwrite/Delete prompt" option.
* gptel.el (gptel): `gptel' only pops to the gptel buffer when
called interactively.
* gptel-transient.el: Pop up the gptel session buffer when the
prompt is sent to it, but don't select it. Also message the user
that the response has been redirected to the gptel session.
* gptel-transient.el (gptel-menu, gptel--suffix-send,
gptel--suffix-send-existing, gptel--suffix-send-new): Rewrite
`gptel-menu' to allow for selecting prompt sources and response
sinks independently. Sensible combinations of the following are
now possible:
- prompt from minibuffer
- Replace prompt with response
- Response to echo area
- Response to new gptel session
- Response to existing gptel session
- Response to kill-ring
The transient suffixes `gptel--suffix-send-existing' and
`gptel--suffix-send-new' are now obsolete and have been removed.
* gptel-transient.el: Add `gptel-rewrite-menu' (accessible via the
main `gptel-menu') to rewrite/refactor the selected region,
including the choice to Ediff it linewise/wordwise afterwards.
* gptel.el (gptel-send): Replace references to `gptel-send-menu'.
* gptel-transient.el: Rename `gptel-send-menu' t `gptel-menu'.
This shorter name is apropos of its increased feature set (in the
forthcoming commits).
* gptel.el (gptel--insert-response, gptel-request):
- Add an in-place key to gptel-request. When true, the default
callbacks will not delimit the API responses with newlines.
- Add a strea option to gptel-request. Only works with the default
filter/stream-insert callback, so it's marked as for internal use
for now.
* gptel-curl.el (gptel-curl--stream-insert-response): Ditto.
* gptel.el (gptel--url-parse-response, gptel--url-get-response,
gptel--insert-response, gptel-send):
- Use shorter keys for passing the info plist,
- record errors in the info plist,
- separate user messaging from the callback and more.
- Make the API more functional (i.e. less imperative)
This is in preparation for adding `gptel-request', an API for
defining custom commands.
Note: The streaming filter and callback are mostly unchanged.
Streaming is not planned to be accessible via `gptel-request'.
* gptel-curl.el (gptel-curl--parse-response, gptel-curl--sentinel,
gptel-curl--stream-filter, gptel-curl--stream-insert-response,
gptel-curl--stream-cleanup, gptel-curl-get-response): Ditto.
* gptel.el (gptel--url-parse-response, gptel--insert-response):
Use the same error codes/descriptions across url-retrieve/Curl,
with and without streaming responses.
* gptel-curl.el (gptel-curl--parse-response,
gptel-curl--stream-filter, gptel-curl--stream-cleanup): Ditto.
* gptel-curl.el (gptel-curl--stream-filter,
gptel-curl--stream-cleanup): When streaming responses, move the
error handling from the Curl process filter to the cleanup
sentinel. This simplifies the filter code a fair bit.
* gptel.el (gptel--playback, gptel--insert-response):
`gptel--insert-response' no longer handles stream playback. Run
`gptel-post-response-hook' after inserting the response from
ChatGPT. Delete the `gptel--playback' function since it never did
anything -- it was a placebo.
* gptel.el (gptel--url-get-response, gptel--insert-response,
gptel-send): Rename the :insert-marker keyword in the async info
plist to :start-marker.
* gptel-curl.el (gptel--insert-response-stream,
gptel-curl--cleanup-stream, gptel-curl-get-response): Ditto.
* gptel.el (gptel--convert-playback-markdown->org,
gptel-post-response-hook): Add a hook that runs after the response
is received. This will allow for custom actions like moving the
cursor to the next prompt. The markdown->org stream converter now
cleans up after itself using this hook.
* gptel.el (gptel--convert-playback-markdown->org): New converter
for markdown->org that works on text chunks while maintaining the
parse state until the text stream is finished.
* gptel-curl.el (gptel--insert-response-stream,
gptel-curl-get-response): When using `gptel-playback' and
requesting ChatGPT's responses in org-mode, run the above
converter on the received response. This works by storing the
converter and associated state as a closure in the async info
plist that is supplied along with the response, and running it
repeatedly on each chunk of text in the response stream before it
is inserted into the buffer.
FIXME: Note that `gptel-response-filter-functions' is currently
ignored if using `gptel-stream'.
* gptel.el (gptel--request-data): Request a streaming message if
`gptel-stream' is non-nil.
* gptel-curl.el (gptel-curl-get-response,
gptel-curl--cleanup-stream, gptel-curl--filter): Add a process
filter and sentinel for Curl to stream ChatGPT's response into
Emacs in real-time.
* gptel.el (gptel--url-get-response,
gptel-api-key-from-auth-source): `gptel--url-get-response' accepts
a callback argument that can be used to do something besides
inserting the response into the current buffer.
* gptel-curl.el (gptel-curl--sentinel, gptel-curl-get-response):
`gptel-curl--sentinel' now accepts a callback argument that can be
used to do something besides inserting the response into the
current buffer.
These changes are in preparation for more specific functionality,
like showing the response as a message, or replacing the prompt
with the response etc.
This changes response parsing so that the response body is decoded as
UTF-8 and then parsed as JSON, rather than the other way around.
This fixes the handling of responses that contain Unicode characters
which are encoded with multiple bytes in UTF-8, such as emojis.
If the user provides the OpenAPI key via a function, as is the case by
default if the user puts credentials in an auth-sources resource like
.authinfo or .authinfo.gpg, then it is necessary to encode the
function's returned value into utf-8 before passing it onward to build
the HTTP request. This commit ensures that happen.
Why is this necessary, given that the API key contains only
alphanumeric characters and therefore should be byte-for-byte the same
in utf-8 as in us-acii? I don't know. It may because emacs's
url-http.el library concats many strings together, and they all need
to be identically encoded before they can be combined correctly.
Whatever the reason, this fix works and allows you to send prompts
which include Unicode characters that require multibyte encodings in UTF-8
* gptel.el (gptel-send): Set the "Waiting..." state after sending
the http request -- this is less misleading if there's an error in
the http request functions (`gptel--url-get-response' or
`gptel-curl-get-response').
* gptel.el (gptel--request-data, gptel--system-message-alist,
gptel--model, gptel--temperature, gptel--max-tokens): Rename API
parameters and turn them into customizable variables. They are
still buffer-local.
Rename:
`gptel--system-message-alist' to `gptel-directives'
`gptel--max-tokens' to `gptel-max-tokens'
`gptel--model' to `gptel-model'
`gptel--temperature' to `gptel-temperature'
* gptel-transient.el (gptel-system-prompt,
gptel--infix-max-tokens, gptel--infix-model,
gptel--infix-temperature): Accommodating changes when setting the
renamed parameters.
* gptel.el (gptel-prompt-prefix-alist, gptel--playback, gptel,
gptel--insert-response, gptel-prompt-string): The prompt prefix
string is chosen automatically from the new variable
`gptel-prompt-prefix-alist', which maps major modes to the prefix
string to insert.
* gptel.el (gptel--url-parse-response): Produce better error
messages when using `url-retrieve'. This includes JSON parsing
failures and insufficient quota messages.
* gptel-curl.el (gptel-curl--parse-response): Produce better error
messages when using curl. This includes JSON parsing failures
and insufficient quota messages.