Add support for Deferred Functions #156
Draft
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Deferred Function Calling
(Found out later that Pydantic AI also has a feature like this - https://ai.pydantic.dev/deferred-tools/)
Motivation
Normally, when a function call happens in an AI system, it looks like this:
This works for many use-cases. In this example, we're assuming F1 is some function that can be called and resolved in a reasonable amount of time (maybe a few seconds).
However, there are some scenarios where the function cannot be easily (or quickly) be executed. Examples include:
Proposal
In this PR, I'm proposing the ability for functions to return a DeferredResult in addition to a string. The idea is that if the ChatPrompt sees "DeferredResult", it saves that state, and stops executing.
Then, when the system is ready (aka gets an external signal) to continue, then it "resumes" and continues the ChatPrompt. The updated sequence diagram for a Deferrable Function looks like so:
Implementation
Message
which is a union of different types of messages). ThisDeferredMessage
basically stores the deferred state that the executable function can optionally return.DeferredResult
now (on top of string)DeferredMessage
with aFunctionMessage
which is a normal function call result.The sample currently shows an approval message that the LLM can invoke. It demonstrates two main scenarios:
get_approval
andbuy_stock
. And then we prompt the LLM to call approve before buy-stock. This showcases the raw calling of a Deferrable function, and how it can be resumed when the user replies. I use a normal message here to showcase this, but honestly, using an adaptive card would drive the point in better.buy_stock
) which is a regular function, into a deferred function. After doing this, whenbuy_stock
is called, the LLM actually defers the calling of the actual buy stock function by first asking for an approval. This way you can't really fool the LLM by clever prompting.I'm planning on moving some of the examples in the Sample to the main library as utilities.