Skip to content
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[ai]: Add conversation endpoints. #1132

Merged
merged 1 commit into from
Jan 15, 2025

Conversation

chirino
Copy link
Contributor

@chirino chirino commented Jan 10, 2025

LLM internal state messages is simplified to be a single field either on ChatState or in the Conversation table. We now keep timestamps for individual ChatMessages.

Also drop the db connection arg from the completions method as the DB is Not needed for those calls.

You can test out the completions API using the UI at: https://github.com/chirino/ai-assistant-vite

just npm i && npm run dev and use the browser link outputted.

@chirino chirino force-pushed the conversations-endpoints branch from 773e6d5 to 0585e3c Compare January 10, 2025 23:31
@chirino chirino requested a review from mrizzi January 11, 2025 15:19
@@ -1,16 +1,22 @@
#[cfg(test)]
mod test;

use crate::ai::model::{Conversation, ConversationSummary};
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would be great if you could group the use statements.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If this preference is important this should be enforced by the xtask precommit command, otherwise it will not be uniformly enforced.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add that then?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I personally don't mind it being ungrouped, my IDE automatically adds them that way. I also don't know how to get the format checker to enforce that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks like https://github.com/rust-lang/rustfmt/blob/master/Configurations.md#imports_granularity is what we would want. but it's only in unstable right now.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not keep it simple and just manually do it? IntelliJ (Rust Rover) helps with "nest use statements":

image

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we can't automatically fix it for them /w cargo fmt, we should not be nitpicking about it in PR reviews. This is all just stylistic right?

Copy link
Contributor

@ctron ctron left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe a few things to understand or fix.

responses(
(status = 200, description = "The resulting conversation", body = Conversation),
(status = 400, description = "The request was invalid"),
(status = 404, description = "The AI service is not enabled or the conversation was not found")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks to me like there's an inconsistency in generating this. When the conversion is not found, it returns "ok, but emtpy" if the conversion is found, but doesn't belong to the user, it returns "not found".

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah. This is because we fake the create_conversation. All it does is generate an empty conversation with a generated UUID. This is because the UI calls create_conversation when the chat page is loaded. If we stored the empty conversation at this point, we would end up with lots of empty/abandoned conversations in the DB.

We could require create_conversation to at least contain a message, but this would make the API a little clunkier to use from the UI.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, but in that case the part of "or the conversation was not found" is not true, is it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

well yes. It actually means that the conversation belongs to another user, but I'd rather lie than tell them that.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But you're leaking that information anyway. Every time you get back a 404, it means "not allowed", or "other other".

}

pub async fn update_conversation<C: ConnectionTrait>(
pub async fn upsert_conversation<C: ConnectionTrait>(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the implementation is says that the update can take a while. How will that affect concurrent calls this this function. Which to my understanding can happen when multiple calls via the API happen.

Copy link
Contributor Author

@chirino chirino Jan 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is true. The API caller is responsible for increasing the seq arg in each subsequent/concurrent call. This should allow only the latest update win since we do a:

update(model)
            .filter(conversation::Column::Seq.lte(seq))

yes: If the caller want's to be lazy and leave it to chance, he can leave the seq number unchanged.

We should probably insert the record before LLM call to avoid a race on insert.

Copy link
Contributor

@ctron ctron Jan 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, the seq is basically the "oplock", is it?

If that's the case, why not follow the pattern that we already have:

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could do.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but given seq is part of the data model response object, seems odd to post it via headers.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The pattern of If-Match and ETag seems to be a standard thing.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that tend to be a thing when the etag is not part of the document. Example: hash of a file etc.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But I guess it can't hurt to use the etag system. It should help with caching too.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why invent something new, if there's an existing pattern?!

use itertools::Itertools;
use time::OffsetDateTime;
use trustify_auth::authenticator::user::UserDetails;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd still prefer to have this nested. Or at least, consistent.

@chirino
Copy link
Contributor Author

chirino commented Jan 15, 2025

will squash and rebase..

LLM internal state messages is simplified to be a single field either on ChatState or in the Conversation table.

We now keep timestamps for individual ChatMessages.

Also drop the db connection arg from the completions method as the DB is
Not needed for those calls.

Signed-off-by: Hiram Chirino <[email protected]>
@chirino chirino force-pushed the conversations-endpoints branch from d8e2a65 to 5c5ed5b Compare January 15, 2025 15:35
@chirino chirino added this pull request to the merge queue Jan 15, 2025
Merged via the queue into trustification:main with commit 88424ad Jan 15, 2025
1 check passed
@chirino chirino deleted the conversations-endpoints branch January 15, 2025 17:31
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