-
Notifications
You must be signed in to change notification settings - Fork 321
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
feat: tool result callback #290
base: main
Are you sure you want to change the base?
feat: tool result callback #290
Conversation
f192a2b
to
2c8ce0b
Compare
@0xMochan @cvauclair with this PR we have tool chain properly implemented |
2c8ce0b
to
ce26e92
Compare
Hey @carlos-verdes ! This is a feature we 100% do want to support so thanks for the issue/PR 🦾 ! The one concern I have with this implementation is that users lose the ability to perform a "single turn" request to the LLM, or in other words, that the That being said, it is still possible to perform a single turn (and get a // response here can be used to get the `ToolCall`
let response = agent.completion(prompt, chat_history)
.await?
.send()
.await?; I'm definitely not against keeping the |
@carlos-verdes This is really helpful! I actually wrote almost the exact same loop logic in my project, and now I can finally remove it! I also noticed another issue: the
I'm wondering if the |
The contract between the client and the LLM is like this: This PR implements this contract, whatever has to happen to comply with the contract is implementation and hence is hidden from the client. Actually the prompt method returns a String not a message right? If you use function calls (tools) you need to understand there are going to be extra calls to the LLM, the same way as when you chose a reasoning model you know there will be extra steps too (and they are executed as part of the prompt call, not exposed to the caller). If you read the documentation from OpenAI you also see this PR implements exactly the flow as they tell you: Without this logic "inside" the completion method you move the problem to the client (as @s6nqou mentioned this is what he has doing on his current project code and he was happy to find out this PR removes this problem from him). Now imagine we are still not convinced and we want to handle the extra call outside prompt method. impl<M: CompletionModel> Prompt for &Agent<M> {
async fn prompt(&self, prompt: impl Into<Message> + Send) -> Result<Message, PromptError> {
self.chat(prompt, vec![]).await
}
} Then we are force to handle all type of messages in the client code: // now I need to have the chat history vector in the client
let history = vec![Message::from("Can you please let me know title and url of rig platform?")];
loop {
// assume we changed prompt implementation to return a Message
let response: Message = search_agent
.chat(history)
.await?;
match response {
case Message::Text(text) => break Ok(text.text),
case Message::ToolCall(tool_call) =>
history.push(tool_call);
let tool_result = ... // make the call to the tool here
histroy.push(tool_result);
}
} ... it has not sense to me, I would not use this library if I have to do this. I honestly don't see any justification to not make the extra calls to the LLM outside the method. One option if you want low level control is to have 2 traits / methods, one is responsible to send a message and return the LLM response (also as a message). pub trait LlmMessageHandler: Send + Sync {
fn send_message(
&self,
message: impl Into<Message> + Send,
) -> impl std::future::Future<Output = Result<Message, PromptError>> + Send;
} And keep the current traits as they are but with a default implementation with the loop from this PR calling the method from the previous trait: pub trait Prompt: Send + Sync {
fn prompt(
&self,
prompt: impl Into<Message> + Send,
) -> impl std::future::Future<Output = Result<String, PromptError>> + Send {
// here we can implement the loop calling send_message method
}
} |
This is not correct, let me check this out. |
Alright, this is a mistake, unfortuntely not caught in reviews 🫠. Prompt should always be the latest message w/ and w/o history! I'll handle this in a sep. issue + PR, good catch. |
I'm not sure about this, when you have function calls I think the proper order is:
|
ce26e92
to
630b157
Compare
ok i tested more after the filter update and this works for OpenAPI / Ollama when using the url approach. closing: #303 |
Fixes #289