-
Notifications
You must be signed in to change notification settings - Fork 868
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
AIChat full-page storage #25876
base: master
Are you sure you want to change the base?
AIChat full-page storage #25876
Conversation
d881677
to
ff534cf
Compare
A Storybook has been deployed to preview UI for the latest push |
b5cc7ce
to
7f62f91
Compare
b6bf7d6
to
560779c
Compare
616868a
to
c2d2026
Compare
bb6686b
to
85e2bed
Compare
85e2bed
to
b1fe7ad
Compare
b1fe7ad
to
cdccd62
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// It is prepared for future implementation. | ||
// Delete all Leo data | ||
ai_chat::AIChatServiceFactory::GetForBrowserContext(profile_) | ||
->ClearAllHistory(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we need to do a null check here? GetForBrowserContext
can return null.
Maybe a CHECK
if we expect it to never happen, for better crash logs.
@@ -6,7 +6,9 @@ | |||
#include "brave/browser/ui/webui/ai_chat/ai_chat_ui_page_handler.h" | |||
|
|||
#include <memory> | |||
#include <string> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: either revert the file, or move the <string>
include into the header file (as it depends on it too)
profile_->GetPrefs()->ClearPref(ai_chat::prefs::kLastAcceptedDisclaimer); | ||
g_brave_browser_process->process_misc_metrics() | ||
->ai_chat_metrics() | ||
->RecordReset(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note for other reviewers: This call still happens in ClearAllHistory
#include "base/check.h" | ||
#include "base/strings/string_split.h" | ||
#include "base/time/time.h" | ||
#include "brave/components/ai_chat/core/common/mojom/ai_chat.mojom-shared.h" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: remove
@@ -873,10 +933,13 @@ void ConversationHandler::AddToConversationHistory( | |||
return; | |||
} | |||
|
|||
if (!turn->uuid.has_value()) { | |||
turn->uuid = base::Uuid::GenerateRandomV4().AsLowercaseString(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
optional: could be worth a NewId
function in the anonymous namespace as we call this a few times. Pretty simple though so up to you
ai_chat_db_.Reset(); | ||
return; | ||
} | ||
DVLOG(0) << "AIChat DB initialized"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
DVLOG(0)? this doesn't seem that different in importance to the other logs
bool AddConversationEntry( | ||
std::string_view conversation_uuid, | ||
mojom::ConversationTurnPtr entry, | ||
std::optional<std::string> editing_id = std::nullopt); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is already the default value
ai_chat_db_.AsyncCall(&AIChatDatabase::IsInitialized) | ||
.Then(base::BindOnce(&AIChatService::OnDBInit, | ||
weak_ptr_factory_.GetWeakPtr())); | ||
} | ||
|
||
void AIChatService::OnDBInit(bool success) { | ||
CHECK(ai_chat_db_); | ||
if (!success) { | ||
LOG(ERROR) << "Failed to initialize AIChat DB"; | ||
// Ensure any pending tasks are cancelled. Sometimes, especially during unit | ||
// tests that are very quick to run, initilization might fail because of | ||
// shutdown but the next task in the sequence still executes, causing a | ||
// crash because of bad database state. | ||
ai_chat_db_.Reset(); | ||
return; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it is better we do
ai_chat_db_.AsyncCall(&AIChatDatabase::Init)
.WithArgs(storage_dir.Append(kDBFileName))
.Then(base::BindOnce(&AIChatService::OnDBInit,
weak_ptr_factory_.GetWeakPtr()));
}
instead of doing it in constructor to eliminate the unnecessary intermediate state is_initialized_
which cause us to possibly check initialized in the middle of initializing process.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I did start out by having a separate public AIChatDatabase::Init function that consumers would call, but it seemed redundant because what's the point of constructing the class without Init being run, and also I didn't want to have to check that it was init'ed on every other function call.
I could change it back, but just thinking about the reasoning - is it really possible for is_initialized_
to be checked in the middle of the initializing process when all the other functions will be called on the sequence and I assume that guarantees Init will be finished, since it's called in the constructor? I know I'm probably wrong about this so please let me know!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe I read your comments in a wrong way that makes me think that is possible to interrupt it. But it seems impossible due to the same reason you mentioned, constructing is posted to the sequenced task runner we chose and then when we call other functions, it will be posted to the same sequence as next task.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But even with current code, we still rely on consumer to check if it is successfully inited and it is not safe to assume that it would successfully initialized upon calling other public functions. So we still miss checking is_initialized_
in all public functions because init might fail.
} | ||
|
||
bool AIChatDatabase::CreateConversationTable() { | ||
static const std::string kCreateConversationTableQuery = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
static constexpr char kCreateConversationTableQuery[]
and should apply to all the static queries
} | ||
|
||
std::optional<std::string> AIChatDatabase::DecryptOptionalColumnToString( | ||
sql::Statement& statement, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This should be const sql::Statement&
auto column_type = statement.GetColumnType(index); | ||
// Don't allow non-BLOB types | ||
if (column_type != sql::ColumnType::kBlob) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if (statement.GetColumnType(index) != sql::ColumnType::kBlob) {
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a style nit, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yes, it doesn't need named variable for one time use unless it is something like callback that would increase level of indention which makes it harder to read.
std::nullopt, std::nullopt, 0, false, false); | ||
mojom::ConversationPtr conversation = | ||
mojom::Conversation::New(conversation_uuid, "", base::Time::Now(), | ||
false, std::move(non_content)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
inline mojom::SiteInfo::New
std::move(callback).Run(nullptr); | ||
return; | ||
} | ||
CHECK(ai_chat_db_); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not needed
<< " with data: " << data->entries.size() << " entries and " | ||
<< data->associated_content.size() << " contents"; | ||
mojom::Conversation* conversation = | ||
conversations_.at(conversation_uuid.data()).get(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It will crash when the conversation is no longer in the map. We can't guarantee that won't happen between AIChatDatabase::GetConversationData
and getting the result back
13d9fbf
to
0101ade
Compare
0101ade
to
988abbe
Compare
e24b13a
to
5c43459
Compare
browser/resources/settings/brave_overrides/clear_browsing_data_dialog.ts
Show resolved
Hide resolved
dca362b
to
df33be5
Compare
7d10150
to
82a0b3d
Compare
Delete all AI Chat history from settings page
82a0b3d
to
6677620
Compare
[puLL-Merge] - brave/brave-core@25876 DescriptionThis PR implements persistent storage for AI Chat conversations using a new ChangesChanges
Possible Issues
Security Hotspots
|
TODO:
SiteInfo
struct. I'll wrap this with another optional struct or convert to string.browsing_data::BrowsingDataCounter
to show how many conversations will be deleted, possibly how many megabytes total the DB is (follow-up, nice to have).