Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions lib/AppInfo/Application.php
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ public function register(IRegistrationContext $context): void {
$context->registerEventListener(TaskSuccessfulEvent::class, TaskSuccessfulListener::class);
$context->registerEventListener(TaskFailedEvent::class, TaskFailedListener::class);
$context->registerEventListener(TaskSuccessfulEvent::class, ChattyLLMTaskListener::class);
$context->registerEventListener(TaskFailedEvent::class, ChattyLLMTaskListener::class);
$context->registerEventListener(TaskSuccessfulEvent::class, FileActionTaskSuccessfulListener::class);
$context->registerEventListener(TaskSuccessfulEvent::class, NewFileMenuTaskSuccessfulListener::class);
$context->registerEventListener(TaskFailedEvent::class, FileActionTaskFailedListener::class);
Expand Down
27 changes: 26 additions & 1 deletion lib/Listener/ChattyLLMTaskListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,17 @@
use OCA\Assistant\Db\ChattyLLM\Message;
use OCA\Assistant\Db\ChattyLLM\MessageMapper;
use OCA\Assistant\Db\ChattyLLM\SessionMapper;
use OCA\Assistant\Service\NotificationService;
use OCA\Assistant\Service\TaskProcessingService;
use OCP\EventDispatcher\Event;
use OCP\EventDispatcher\IEventListener;
use OCP\TaskProcessing\Events\TaskFailedEvent;
use OCP\TaskProcessing\Events\TaskSuccessfulEvent;
use OCP\TaskProcessing\Task;
use Psr\Log\LoggerInterface;

/**
* @template-implements IEventListener<TaskSuccessfulEvent>
* @template-implements IEventListener<TaskSuccessfulEvent|TaskFailedEvent>
*/
class ChattyLLMTaskListener implements IEventListener {

Expand All @@ -30,10 +32,26 @@ public function __construct(
private SessionMapper $sessionMapper,
private TaskProcessingService $taskProcessingService,
private LoggerInterface $logger,
private NotificationService $notificationService,
) {
}

public function handle(Event $event): void {
if ($event instanceof TaskFailedEvent) {
$task = $event->getTask();
$customId = $task->getCustomId();
if (preg_match('/^chatty-llm:(\d+)/', $customId, $matches)) {
$sessionId = (int)$matches[1];
$session = $this->sessionMapper->getUserSession($task->getUserId(), $sessionId);
$assignmentId = $session->getAssignmentId();
if ($assignmentId !== null) {
$this->notificationService->sendAssignmentNotification(
$task->getUserId(), $task, $session
);
}
}
return;
}
if (!($event instanceof TaskSuccessfulEvent)) {
return;
}
Expand Down Expand Up @@ -127,6 +145,13 @@ public function handle(Event $event): void {
// Set flag that the conversation summary needs to be regenerated
$session->setIsSummaryUpToDate(false);

$assignmentId = $session->getAssignmentId();
if ($assignmentId !== null) {
$this->notificationService->sendAssignmentNotification(
$task->getUserId(), $task, $session
);
}
Comment thread
marcelklehr marked this conversation as resolved.
Comment thread
marcelklehr marked this conversation as resolved.

$this->sessionMapper->update($session);
}
}
Expand Down
75 changes: 75 additions & 0 deletions lib/Notification/Notifier.php
Original file line number Diff line number Diff line change
Expand Up @@ -338,6 +338,81 @@ public function prepare(INotification $notification, string $languageCode): INot

return $notification;

case 'assignment_approval_pending':
$subject = $l->t('Assignment run pending review');

$iconUrl = $this->url->getAbsoluteURL($this->url->imagePath(Application::APP_ID, 'app-dark.svg'));

$message = $l->t('"%s" awaits your review before continuing.', [$params['sessionTitle']]);
Comment thread
marcelklehr marked this conversation as resolved.

$notification
->setParsedSubject($subject)
->setParsedMessage($message)
// TODO: link directly to assignment
->setLink($this->url->linkToRouteAbsolute(Application::APP_ID . '.assistant.getAssistantStandalonePage', ['sessionId' => $params['sessionId']]))
->setIcon($iconUrl);

$actionLabel = $l->t('View assignment');
$action = $notification->createAction();
$action->setLabel($actionLabel)
->setParsedLabel($actionLabel)
->setLink($notification->getLink(), IAction::TYPE_WEB)
->setPrimary(true);

$notification->addParsedAction($action);

return $notification;

case 'assignment_successful':
$subject = $l->t('Assignment succeeded');

$iconUrl = $this->url->getAbsoluteURL($this->url->imagePath(Application::APP_ID, 'app-dark.svg'));

$message = $l->t('"%s" was run successfully.', [$params['sessionTitle']]);

$notification
->setParsedSubject($subject)
->setParsedMessage($message)
// TODO: link directly to assignment
->setLink($this->url->linkToRouteAbsolute(Application::APP_ID . '.assistant.getAssistantStandalonePage', ['sessionId' => $params['sessionId']]))
->setIcon($iconUrl);

$actionLabel = $l->t('View assignment result');
$action = $notification->createAction();
$action->setLabel($actionLabel)
->setParsedLabel($actionLabel)
->setLink($notification->getLink(), IAction::TYPE_WEB)
->setPrimary(true);

$notification->addParsedAction($action);

return $notification;

case 'assignment_failure':
$subject = $l->t('Assignment failed');

$iconUrl = $this->url->getAbsoluteURL($this->url->imagePath(Application::APP_ID, 'app-dark.svg'));

$message = $l->t('"%s" failed to run.', [$params['sessionTitle']]);

$notification
->setParsedSubject($subject)
->setParsedMessage($message)
// TODO: link directly to assignment
->setLink($this->url->linkToRouteAbsolute(Application::APP_ID . '.assistant.getAssistantStandalonePage', ['sessionId' => $params['sessionId']]))
->setIcon($iconUrl);

$actionLabel = $l->t('View assignment result');
$action = $notification->createAction();
$action->setLabel($actionLabel)
->setParsedLabel($actionLabel)
->setLink($notification->getLink(), IAction::TYPE_WEB)
->setPrimary(true);

$notification->addParsedAction($action);

return $notification;

default:
// Unknown subject => Unknown notification => throw
throw new InvalidArgumentException();
Expand Down
31 changes: 31 additions & 0 deletions lib/Service/NotificationService.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

use DateTime;
use OCA\Assistant\AppInfo\Application;
use OCA\Assistant\Db\ChattyLLM\Session;
use OCP\IURLGenerator;
use OCP\Notification\IManager as INotificationManager;
use OCP\TaskProcessing\Task;
Expand Down Expand Up @@ -133,4 +134,34 @@ public function sendNewImageFileNotification(

$manager->notify($notification);
}

public function sendAssignmentNotification(?string $userId, Task $task, Session $session): void {
if ($userId === null) {
return;
}
$manager = $this->notificationManager;
$notification = $manager->createNotification();

$taskSuccessful = $task->getStatus() === Task::STATUS_SUCCESSFUL;
$pendingActions = $session->getAgencyPendingActions();

$params = [
'sessionId' => (string)$session->getId(),
'sessionTitle' => $session->getTitle(),
];

$subject = $taskSuccessful
? ($pendingActions === null
? 'assignment_successful'
: 'assignment_approval_pending')
: 'assignment_failure';

$notification->setApp(Application::APP_ID)
->setUser($userId)
->setDateTime(new DateTime())
->setSubject($subject, $params)
->setObject('session', (string)$session->getId());
Comment thread
marcelklehr marked this conversation as resolved.

$manager->notify($notification);
}
}
Loading