Talk integration¶
Istota communicates through Nextcloud Talk using the regular user API (not the bot API). The bot authenticates as an ordinary Nextcloud user, polling conversations it's a member of.
Polling¶
The talk poller runs in a background daemon thread and drives all its Nextcloud I/O onto the daemon's persistent asyncio runtime (one long-lived loop + one pooled httpx client, via run_coro). It long-polls each conversation the bot participates in. First poll initializes state; subsequent polls use lookIntoFuture=1 for real-time message delivery. Talk is one surface behind the Transport abstraction — inbound it normalizes messages into IncomingMessage/ingest_message, outbound it delivers through TalkTransport.
Fast rooms (with new messages) are processed immediately without waiting for slow (quiet) rooms. The talk_poll_wait setting (default 2s) controls the maximum wait time before processing available results.
Multi-user rooms¶
In rooms with 3+ participants, the bot only responds when @mentioned. Two-person rooms behave like DMs. Participant counts are cached (5 min TTL). The bot's own @mention is stripped from the prompt; other mentions are resolved to @DisplayName.
Final responses in group chats use reply_to on the original message and prepend @{user_id} for notification. Intermediate messages (ack, progress) are sent without reply threading to avoid noise.
Progress updates¶
While the brain works, the bot sends real-time updates to Talk showing what's happening. Progress is driven by the task event stream: the TalkEventSubscriber consumer edits the initial ack message in place, showing the latest tool action and elapsed time. One message, updated as work progresses — no separate progress spam. progress_show_tool_use and progress_show_text gate which event kinds appear.
Log channel¶
Per-user verbose logging of every tool action, with a [task_id #channel] prefix and status emoji, for full observability without cluttering the user's chat. This is driven by the LogChannelSubscriber and is no longer Talk-only — it routes to any user-routable surface via the log routing purpose (routing["log"] > the legacy log_channel Talk shorthand > off). Edit-capable surfaces (Talk) get the live in-place edited stream; non-edit surfaces (email, ntfy) get a single final-summary delivery. See delivery routing.
Message handling¶
- Messages split at 4000 chars
- File attachments downloaded to
/Users/{user_id}/inbox/ - Audio attachments pre-transcribed before skill selection (so the transcript is available to selection and the model)
- Confirmation flow: regex-detected confirmation requests prompt user for yes/no reply
- Alerts channel (
alerts_channelper-user config): dedicated Talk room for confirmations, email gate prompts, and security alerts. Falls back to briefing token, then auto-detected 1:1 DM with the bot !trust/!untrustcommands for runtime management of trusted email senders- Multi-line tool output is collapsed to the first line in progress updates
- The ack message id is carried on the task so the
TalkEventSubscriberedits the same message as work progresses - The Talk progress consumer and the log-channel consumer both subscribe to the one per-task event stream — independent consumers, not chained callbacks
- Background tasks (briefings, scheduled jobs) suppress error notifications to avoid noise -- failures are logged to the DB and log channel only
Configuration¶
| Setting | Default | Section |
|---|---|---|
enabled |
true |
[talk] |
bot_username |
"istota" |
[talk] |
talk_poll_interval |
10s | [scheduler] |
talk_poll_timeout |
30s | [scheduler] |
talk_poll_wait |
2.0s | [scheduler] |
progress_updates |
true |
[scheduler] |
progress_show_tool_use |
true |
[scheduler] |
progress_show_text |
false |
[scheduler] |
talk_cache_max_per_conversation |
200 | [scheduler] |