feat(vocero): add linked content and TALKFIRST greetings (#2)
Opening a report or podcast link now establishes an authenticated starting reference for the conversation. Users can select other accessible content or compare reports while retaining the original link, and TALKFIRST greetings can name the verified report or podcast. Release notes: - Added authenticated report and episode link resolution with bounded lookups and unavailable-content handling - Added explicit conversation selection without restricting searches or changing the reference during comparisons - Added contextual TALKFIRST greetings through both voice-proxy and HTTP reasoning paths - Preserved backend permission checks, conversation isolation, cancellation, and the existing speech protocol Reviewed-on: AquaPortal/s2s#2
This commit is contained in:
@@ -11,6 +11,7 @@ from urllib.parse import urlsplit
|
||||
from starlette.requests import HTTPConnection
|
||||
|
||||
from vocero_api.core import config as settings
|
||||
from vocero_api.models.content import ConversationContent
|
||||
from vocero_api.models.mcp import BackendLogin, CallerIdentity, IntegrationError, McpToolDefinition
|
||||
|
||||
COOKIE_NAME = "vocero_browser"
|
||||
@@ -24,6 +25,9 @@ class Conversation:
|
||||
backend_token: str = field(repr=False)
|
||||
profile: CallerIdentity
|
||||
expires_at: float
|
||||
linked_content: ConversationContent = field(default_factory=ConversationContent)
|
||||
current_content: ConversationContent = field(default_factory=ConversationContent)
|
||||
greeting_pending: bool = False
|
||||
catalog: list[McpToolDefinition] = field(default_factory=list)
|
||||
history: list[list[dict[str, str]]] = field(default_factory=list, repr=False)
|
||||
generation: int = 0
|
||||
@@ -49,6 +53,9 @@ class Conversation:
|
||||
self.backend_token = ""
|
||||
self.history.clear()
|
||||
self.catalog.clear()
|
||||
self.linked_content = ConversationContent()
|
||||
self.current_content = ConversationContent()
|
||||
self.greeting_pending = False
|
||||
|
||||
|
||||
class ConversationStore:
|
||||
@@ -60,7 +67,9 @@ class ConversationStore:
|
||||
if item.closed.is_set() or monotonic() >= item.expires_at:
|
||||
self.remove(item.id)
|
||||
|
||||
def create(self, browser: str, login: BackendLogin) -> Conversation:
|
||||
def create(
|
||||
self, browser: str, login: BackendLogin, linked_content: ConversationContent | None = None
|
||||
) -> Conversation:
|
||||
self.prune()
|
||||
if len(self._items) >= settings.S2S_MAX_CONVERSATIONS:
|
||||
raise IntegrationError(503, "No hay capacidad para otra conversación. Intenta más tarde.")
|
||||
@@ -70,6 +79,9 @@ class ConversationStore:
|
||||
backend_token=login.sessionToken.get_secret_value(),
|
||||
profile=login.user,
|
||||
expires_at=monotonic() + settings.S2S_CONVERSATION_TTL_SEC,
|
||||
linked_content=linked_content or ConversationContent(),
|
||||
current_content=linked_content or ConversationContent(),
|
||||
greeting_pending=settings.S2S_START_SESSION_MODE == "TALKFIRST",
|
||||
)
|
||||
self._items[item.id] = item
|
||||
return item
|
||||
|
||||
Reference in New Issue
Block a user