Files
nuqloud-ai/lib/Talk/NativeEventResponseSink.php
2026-08-21 14:40:27 -07:00

71 lines
2.1 KiB
PHP

<?php
declare(strict_types=1);
namespace OCA\EducAI\Talk;
use OCA\Talk\Events\BotInvokeEvent;
use Psr\Log\LoggerInterface;
/**
* Response sink for Talk 21+ native in-process bot events.
*
* Answers and reactions are queued on the BotInvokeEvent itself. Talk posts
* them as bot-authored chat messages (and reactions) after the event
* dispatch completes, so Talk AI never makes an HTTP request back into its
* own instance for the normal native-event path, and Talk's own bot filtering
* guarantees these replies can not trigger another invocation.
*/
class NativeEventResponseSink implements ResponseSink {
private BotInvokeEvent $event;
private LoggerInterface $logger;
private string $roomToken = '';
public function __construct(BotInvokeEvent $event, LoggerInterface $logger) {
$this->event = $event;
$this->logger = $logger;
}
public function bindRoom(string $roomToken): void {
$this->roomToken = $roomToken;
}
public function send(string $message, int|bool $replyTo = false, bool $silent = false): bool {
if (trim($message) === '') {
return true; // Never queue empty answers - Talk rejects them.
}
try {
// Reply targeting: pass the concrete message id when we have one so
// the answer is threaded under it, matching the webhook transport.
$replyTarget = (is_int($replyTo) && $replyTo > 0) ? $replyTo : false;
$this->event->addAnswer($message, $replyTarget, $silent);
return true;
} catch (\Throwable $e) {
$this->logger->error('Failed to queue native Talk answer', [
'room_token' => $this->roomToken,
'message_length' => strlen($message),
'exception' => $e,
]);
return false;
}
}
public function react(string $emoji): void {
try {
$this->event->addReaction($emoji);
} catch (\Throwable $e) {
$this->logger->error('Failed to queue native Talk reaction', [
'room_token' => $this->roomToken,
'exception' => $e,
]);
}
}
public function supportsStreaming(): bool {
// Talk posts answers after the invocation completes, so incremental
// streaming is not possible - the pipeline coalesces to final replies.
return false;
}
}