Skip to content

Add GitHub CI workflow, for running ERT #865

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 12 commits into
base: feature-augment-buffer
Choose a base branch
from

Conversation

jwiegley
Copy link
Contributor

No description provided.

jwiegley and others added 10 commits May 22, 2025 23:06
* gptel.el (gptel--with-buffer-copy): In preparation for
gptel's switch to fully buffer-oriented prompt preparation (needed
for augmentation), make `gptel--with-buffer-copy'

- copy all the required state into the prompt preparation buffer.

- Keep the buffer alive for current for augmentation and parsing
instead of using `with-temp-buffer'.

The latter means that the prompt preparation buffer is never
cleaned up after a request, and gptel is thus buggy as of this
commit.  This will be rectified next.
Previously, gptel's prompt construction worked as follows:

1. If the prompt is nil or a string, copy the text to be sent to a
temporary buffer, and use it to create the messages array.  If the
prompt is a list of strings, create the messages array from it
directly (with no intermediate buffer).

2. Feed this array along with the specified or environmental
parameters like the backend, model, system message and other
parameters to `gptel--request-data', which produces the full
payload.

gptel is now inverting this flow:

1. Whatever the prompt, copy it to a temporary buffer (the "prompt
buffer") using `gptel--create-prompt-buffer' or directly with
`gptel--with-buffer-copy'.  Use the new function
`gptel--parse-list-and-insert' to insert a list-of-strings prompt
into the prompt buffer.

2. Also copy the environment to this temporary buffer as
buffer-local variables.

3. Apply any augmentations/transformations/context injections to
this prompt buffer.  This can involve changing the buffer contents
and/or changing the environment, i.e. buffer-local variables such
as the model, backend or system prompt.  The ability to do this
is the main reason for this inversion.  One example of this is
the upcoming just-in-time preset feature.

NOTE: transformations are not yet implemented.

4. Construct the full payload using `gptel--request-data' inside
the prompt buffer.

* gptel.el:
(gptel--parse-directive): Add FIXME for later
(gptel--parse-list-and-insert): Inserts prompts, a list of
strings, into the current buffer with user/llm/tool roles applied.
(gptel-request, gptel--realize-query): Split the work of
`gptel-request' into two functions.  `gptel-request' now handles
only the creation of the prompt buffer.  `gptel--realize-query' runs
in the prompt buffer and does the actual payload realization.
(gptel--create-prompt): Remove function
(gptel--create-prompt-buffer): Renamed from
`gptel--create-prompt', now returns the prompt buffer instead of a
messages array.  No longer handles context injection.

* gptel-org.el (gptel-org--create-prompt): Remove function
(gptel-org--create-prompt-buffer): Renamed from
`gptel-org--create-prompt', now returns a buffer instead of a
messages array.
* gptel.el:
(gptel-prompt-filter-hook, gptel-prompt-transform-functions):
Introduce a hook to hold transformations to apply to the prompt.

This will be used to hold functions for context injection, Org
property stripping and so on, as well as just-in-time preset
application and any RAG plugins.  This hook will be passed
explicitly to `gptel-request' as an argument, since
`gptel-request' is supposed to be a simple function by default,
with behavior that depends as little on global variables as
possible.

Obsolete `gptel-prompt-filter-hook', since it is superseded by
`gptel-prompt-transform-functions'.

This hook currently does nothing, and will be added to the
`gptel-request' pipeline next.

(gptel--with-buffer-copy, gptel--create-prompt-buffer): Remove
gptel-prompt-filter-hook from the prompt-buffer creation pipeline.

* gptel-org.el (gptel-org--create-prompt): Remove
gptel-prompt-filter-hook from the prompt-buffer creation pipeline.
Use `gptel-prompt-transform-functions' in `gptel-request',
enabling a prompt transformation/augmentation pipeline.  This
pipeline will be used for just-in-time presets, adding gptel's context
to the request and other operations that are critical to
`gptel-send'.

`gptel-prompt-transform-functions' is not automatically applied to
`gptel-request' calls, it must be passed explicitly via the
`:transforms' argument.  This is so that gptel-request stays
closer to a 'pure' function, for use as a library.

`gptel-send' passes the transforms explicitly to `gptel-request'.

* gptel.el (gptel--create-prompt-buffer, gptel--create-prompt):
New function `gptel--create-prompt-buffer', used to create a
prompt buffer with the appropriate text to be
sent (pre-transform).  `gptel--create-prompt' is no longer used
but retained for compatibility and testing.

(gptel-request): Add the `:transforms' argument and docstring.

Run `gptel-prompt-transform-functions' here.  In short, create the
prompt construction buffer with `gptel--create-prompt-buffer',
then run through the transforms.  The preset transform is applied
first, since it can change the value of
`gptel-prompt-transform-functions'.  The rest are applied via a
wrapped hook that distinguishes between sync and async transforms
via function arity, and uses a "gather" method to track
completion.

TODO: Async transforms end up running in parallel, so there is a
race condition involving buffer mutation when there is more than
one.  This will be fixed in the future.

* gptel-transient (gptel--suffix-send): Add `:transforms' to the
`gptel-request' call.

* gptel-rewrite (gptel--suffix-rewrite): Add `:transforms' to the
`gptel-request' call.
* gptel.el (gptel--inspect-query): If there are async prompt
augmentors/transformers in the mix, the fsm passed to
`gptel--inspect-query' by gptel-request will not yet be ready for
consumption.  Poll until payload construction is complete.  This
is an interim solution while I figure out how to modify the call
chain to make this expensive timer unnecessary.
Previously, adding context (from gptel-context) to the query
payload was a bespoke step, and tied into `gptel-request'.  It was
carried out by mutating the messages array after buffer parsing.

Now that the `gptel-request' pipeline has been inverted, context
addition is carried out in the prompt construction buffer, and is
handled as a regular transform function in
`gptel-prompt-transform-functions'.  As a result, the context
addition step can now be asynchronous, since the user might want
to truncate or augment it depending on its size and content.  By
default, context addition works by inserting into the prompt
construction buffer, or by modifying the system message in the
buffer.

The only exception to this is handling media files in the
context -- there is no universal buffer-oriented method for doing
this, so `gptel--wrap-user-prompt' is still used for attaching
media from `gptel-context--alist'.
TODO: This will be fixed in the future.

This deprecates some aspects of the gptel-context API, including `gptel-context-wrap-function'.

* gptel-context.el (gptel-context-wrap-function): Obsolete.  This
is no longer used.  Customize `gptel-context-string-function'
instead or advise `gptel-context--wrap-in-buffer' if that's
insufficient.
(gptel-context--wrap): This function serves the same purpose as
before, but now works by mutating the prompt construction buffer.
It takes a callback and can be asynchronous.
(gptel-context--wrap-in-buffer): New function to add the context
string to the prompt construction buffer, etiher as text or by
modifying the buffer's system message.
(gptel-context--wrap-default):  Remove, as this is covered by
`gptel-context--wrap-in-buffer'.

* gptel.el (gptel--transform-add-context): Augmentor for adding
context to the request, which calls gptel-context- functions.
This will be added to `gptel-prompt-transform-functions'
next.  (Context addition is currently non-functional in gptel.)
(gptel--realize-query): Move context addition step from here back
to the transforms/augmentation step.  Handling media files in the
context is an exception and it still happens here.
(gptel--wrap-user-prompt-maybe): Remove, no longer needed.
* gptel.el (gptel-prompt-transform-functions): Set the default
transformers/augmentors.  They (i) apply any preset included at the
beginning of the prompt (via `@preset`) and (ii) add gptel's
context to the prompt buffer.

Note that `gptel-prompt-transform-functions' (or a list containing
augmentors) needs to be passed explicitly to `gptel-request' (via
the `:transforms' argument) for it to take effect.  `gptel-send'
does this.  It is not read from the environment as this can have
unexpected side-effects when using `gptel-request' as a library.
Catch strings of the form `@preset-name` anywhere in the user
prompt and apply the preset in the transform/augment step.

This change is experimental, and will be reverted if there are
unexpected consequences or performance problems.

This change is to make it easy to specify an on-the-fly preset
when the user prompt structure is slightly off.  Two examples:

1. When the user prompt is structured as

** Some heading

*Prompt*: @preset-name ...

where the heading is used for structural purposes.  Technically
the user prompt begins at the heading, but it's clear from
context that the user intends to apply preset-name to the
message.

2. When the preset specification naturally comes at the end.

<long chunk of text>

What do you make of the above, @explainer?

This also promotes a more conversational preset usage style.

* gptel.el (gptel--transform-apply-preset): Scan the entire user
prompt for `@preset-name` mentions and apply presets as they are
found.
(gptel--fontify-preset-keyword): Fontify all `@preset-name`
mentions in the user prompt.
(gptel--prettify-preset): Adjust for new fontification keyword.
@jwiegley jwiegley changed the base branch from master to feature-augment-buffer May 23, 2025 18:55
@jwiegley jwiegley marked this pull request as ready for review May 23, 2025 19:01
@karthink karthink force-pushed the feature-augment-buffer branch 8 times, most recently from 386b349 to eca523b Compare May 28, 2025 05:29
@karthink karthink force-pushed the github-ci-workflow branch from 243e824 to b2679ec Compare May 28, 2025 06:33
@karthink karthink force-pushed the github-ci-workflow branch from b2679ec to e009fc7 Compare May 28, 2025 06:35
@karthink karthink force-pushed the feature-augment-buffer branch 6 times, most recently from ed41950 to 40ef63b Compare May 31, 2025 06:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants