| // Copyright 2025 The Chromium Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef CHROME_BROWSER_ACTOR_ACTOR_KEYED_SERVICE_H_ |
| #define CHROME_BROWSER_ACTOR_ACTOR_KEYED_SERVICE_H_ |
| |
| #include <memory> |
| #include <vector> |
| |
| #include "base/compiler_specific.h" |
| #include "base/functional/callback.h" |
| #include "base/memory/raw_ptr.h" |
| #include "base/memory/weak_ptr.h" |
| #include "base/types/expected.h" |
| #include "chrome/browser/actor/aggregated_journal.h" |
| #include "chrome/browser/page_content_annotations/multi_source_page_context_fetcher.h" |
| #include "chrome/common/actor/action_result.h" |
| #include "chrome/common/actor/task_id.h" |
| #include "chrome/common/actor_webui.mojom.h" |
| #include "chrome/common/buildflags.h" |
| #include "components/keyed_service/core/keyed_service.h" |
| #include "components/password_manager/core/browser/actor_login/actor_login_types.h" |
| #include "components/tabs/public/tab_interface.h" |
| #include "ui/gfx/image/image.h" |
| #include "url/gurl.h" |
| |
| class Profile; |
| |
| namespace content { |
| class BrowserContext; |
| } // namespace content |
| |
| namespace actor { |
| namespace ui { |
| class ActorUiStateManagerInterface; |
| } |
| |
| class ActorTask; |
| class ToolRequest; |
| |
| // This class owns all ActorTasks for a given profile. ActorTasks are kept in |
| // memory until the process is destroyed. |
| class ActorKeyedService : public KeyedService { |
| public: |
| explicit ActorKeyedService(Profile* profile); |
| ActorKeyedService(const ActorKeyedService&) = delete; |
| ActorKeyedService& operator=(const ActorKeyedService&) = delete; |
| ~ActorKeyedService() override; |
| |
| // Convenience method, may return nullptr. |
| static ActorKeyedService* Get(content::BrowserContext* context); |
| |
| // TODO(crbug.com/428014205): Create a mock ActorKeyedService for testing so |
| // we can remove this function. |
| void SetActorUiStateManagerForTesting( |
| std::unique_ptr<ui::ActorUiStateManagerInterface> ausm); |
| |
| // Starts tracking an existing task. Returns the new task ID. |
| TaskId AddActiveTask(std::unique_ptr<ActorTask> task); |
| |
| const std::map<TaskId, const ActorTask*> GetActiveTasks() const; |
| const std::map<TaskId, const ActorTask*> GetInactiveTasks() const; |
| |
| std::vector<TaskId> FindTaskIdsInActive( |
| const base::RepeatingCallback<bool(const ActorTask&)>& predicate) const; |
| std::vector<TaskId> FindTaskIdsInInactive( |
| const base::RepeatingCallback<bool(const ActorTask&)>& predicate) const; |
| |
| // Stop and clear all active and inactive tasks for testing only. |
| void ResetForTesting(); |
| |
| // Starts a new task with an execution engine and returns the new task's id. |
| // `options`, when provided, contains information used to initialize the |
| // task. |
| TaskId CreateTask(webui::mojom::TaskOptionsPtr options = nullptr); |
| |
| // Executes the given ToolRequest actions using the execution engine for the |
| // given task id. |
| using PerformActionsCallback = base::OnceCallback<void( |
| mojom::ActionResultCode /*result_code*/, |
| std::optional<size_t> /*index_of_failing_action*/, |
| std::vector<ActionResultWithLatencyInfo> /* action_results */)>; |
| void PerformActions(TaskId task_id, |
| std::vector<std::unique_ptr<ToolRequest>>&& actions, |
| PerformActionsCallback callback); |
| |
| // Stops a task by its ID, `success` determines if the task was finished |
| // successfully or ended early. |
| void StopTask(TaskId task_id, bool success); |
| |
| // Returns the task with the given ID. Returns nullptr if the task does not |
| // exist. |
| ActorTask* GetTask(TaskId task_id); |
| |
| // The associated journal for the associated profile. |
| AggregatedJournal& GetJournal() LIFETIME_BOUND { return journal_; } |
| |
| // The associated ActorUiStateManager for the associated profile. |
| ui::ActorUiStateManagerInterface* GetActorUiStateManager(); |
| |
| // Returns true if there is a task that is actively (i.e. not paused) acting |
| // in the given `tab`. |
| bool IsActiveOnTab(const tabs::TabInterface& tab) const; |
| |
| // Returns the id of an ActorTask which has the given tab in its set. Returns |
| // a null TaskId if no task has `tab`. Note: a returned task may be paused. |
| TaskId GetTaskFromTab(const tabs::TabInterface& tab) const; |
| |
| Profile* GetProfile(); |
| |
| using TabObservationResult = base::expected< |
| std::unique_ptr<page_content_annotations::FetchPageContextResult>, |
| std::string>; |
| |
| // Request a TabObservation be generated from the given tab. |
| void RequestTabObservation( |
| tabs::TabInterface& tab, |
| TaskId task_id, |
| base::OnceCallback<void(TabObservationResult)> callback); |
| |
| using TaskStateChangedCallback = |
| base::RepeatingCallback<void(const ActorTask&)>; |
| base::CallbackListSubscription AddTaskStateChangedCallback( |
| TaskStateChangedCallback callback); |
| |
| void NotifyTaskStateChanged(const ActorTask& task); |
| |
| // Allows the subscribers to get notified when a credential selection prompt |
| // is requested. |
| using CredentialSelectedCallback = base::RepeatingCallback<void( |
| webui::mojom::SelectCredentialDialogResponsePtr)>; |
| using RequestToShowCredentialSelectionDialogSubscriberCallback = |
| base::RepeatingCallback<void( |
| TaskId, |
| const base::flat_map<std::string, gfx::Image>& icons, |
| const std::vector<actor_login::Credential>&, |
| CredentialSelectedCallback)>; |
| base::CallbackListSubscription |
| AddRequestToShowCredentialSelectionDialogSubscriberCallback( |
| RequestToShowCredentialSelectionDialogSubscriberCallback callback); |
| |
| // Notifies the subscribers that a credential selection prompt is requested |
| // for the given task. |
| void NotifyRequestToShowCredentialSelectionDialog( |
| TaskId task_id, |
| const base::flat_map<std::string, gfx::Image>& icons, |
| const std::vector<actor_login::Credential>& credentials); |
| |
| // Callback for when a credential is selected. |
| void OnCredentialSelected( |
| TaskId request_task_id, |
| webui::mojom::SelectCredentialDialogResponsePtr response); |
| |
| using UserConfirmationDialogCallback = base::RepeatingCallback<void( |
| webui::mojom::UserConfirmationDialogResponsePtr)>; |
| using RequestToShowUserConfirmationDialogSubscriberCallback = |
| base::RepeatingCallback<void(const std::optional<url::Origin>&, |
| const std::optional<int32_t>, |
| UserConfirmationDialogCallback)>; |
| |
| base::CallbackListSubscription |
| AddRequestToShowUserConfirmationDialogSubscriberCallback( |
| RequestToShowUserConfirmationDialogSubscriberCallback callback); |
| |
| // Notifies the subscribers that the browser is requesting user confirmation |
| // for the actor to continue. |
| void NotifyRequestToShowUserConfirmationDialog( |
| TaskId task_id, |
| const std::optional<url::Origin>& navigation_origin, |
| const std::optional<int32_t> download_id); |
| |
| void OnUserConfirmationDialogDecision( |
| TaskId request_task_id, |
| webui::mojom::UserConfirmationDialogResponsePtr response); |
| |
| // Returns the acting task for web_contents. Returns nullptr if acting task |
| // does not exist. |
| const ActorTask* GetActingActorTaskForWebContents( |
| content::WebContents* web_contents); |
| |
| base::WeakPtr<ActorKeyedService> GetWeakPtr(); |
| |
| private: |
| // The callback used for ExecutorEngine::Act. |
| void OnActionsFinished( |
| PerformActionsCallback callback, |
| actor::mojom::ActionResultPtr action_result, |
| std::optional<size_t> index_of_failed_action, |
| std::vector<ActionResultWithLatencyInfo> action_results); |
| |
| // Needs to be declared before the tasks, as they will indirectly have a |
| // reference to it. This ensures the correct destruction order. |
| std::unique_ptr<ui::ActorUiStateManagerInterface> actor_ui_state_manager_; |
| |
| std::map<TaskId, std::unique_ptr<ActorTask>> active_tasks_; |
| // Stores completed tasks. May want to add cancelled tasks in the future. |
| std::map<TaskId, std::unique_ptr<ActorTask>> inactive_tasks_; |
| |
| TaskId::Generator next_task_id_; |
| |
| AggregatedJournal journal_; |
| |
| base::RepeatingCallbackList<void(const ActorTask&)> |
| tab_state_change_callback_list_; |
| |
| base::RepeatingCallbackList< |
| RequestToShowCredentialSelectionDialogSubscriberCallback::RunType> |
| request_to_show_credential_selection_dialog_callback_list_; |
| |
| base::RepeatingCallbackList< |
| RequestToShowUserConfirmationDialogSubscriberCallback::RunType> |
| request_to_show_user_confirmation_dialog_callback_list_; |
| |
| // Owns this. |
| raw_ptr<Profile> profile_; |
| |
| base::WeakPtrFactory<ActorKeyedService> weak_ptr_factory_{this}; |
| }; |
| |
| } // namespace actor |
| #endif // CHROME_BROWSER_ACTOR_ACTOR_KEYED_SERVICE_H_ |