{"slug": "frona-v2026-6-0-self-hosted-personal-ai-assistant", "title": "Frona v2026.6.0 – self-hosted personal AI assistant", "summary": "Frona v2026.6.0 introduces a unified human-in-the-loop pause/resume mechanism across all channels, a slash composer for invoking skills and agents, typed file tools to reduce token usage and hallucinations, and per-channel message splitters to prevent truncation. The update also adds button-based approvals on Telegram, Discord, Slack, and WhatsApp Cloud, with text-based prompts on Signal, SMS, and personal WhatsApp.", "body_md": "This release ships a unified human-in-the-loop pause/resume mechanism across every channel, a slash composer for invoking skills and other agents directly, typed file tools that cut token usage and hallucinations, and per-channel message splitters so long replies arrive cleanly instead of getting truncated. Approvals (app deploys, multiple-choice questions, credential picks) now render as buttons on Telegram, Discord, Slack, and WhatsApp Cloud, and as `Reply YES or NO`\n\nprompts on Signal, SMS, and personal WhatsApp, with the inbound parser accepting the obvious variants. Behind the scenes, a new `Harness`\n\nstruct consolidates the agent runtime view of `AppState`\n\n, sandboxing moves to a single `SandboxManager`\n\nper principal kind, and the channel adapter framework now classifies failures with a typed `ChannelError`\n\n.\n\n**Supported channels:** Slack, Discord, Telegram, Signal, SMS, WhatsApp Cloud, WhatsApp Personal.\n\n### Human in the loop\n\n- Replace opaque\n`tool_data`\n\nblobs on tool calls with typed`Hitl`\n\nvalues; build typed HITL tool components and consume new SSE event names. - Persist\n`Paused`\n\nmessage status and resume with an atomic compare-and-swap; translate the new`InferenceResponse`\n\noutcomes into pause/resume persistence. - Add a\n`POST /api/chats/{chat_id}/tool-calls/resolve`\n\nendpoint, lift the HITL callback parser and response label into a shared`hitl`\n\nmodule, and drop the legacy app and vault approval routes superseded by the resolve endpoint. - Re-seed pending HITLs from\n`msg.tool_calls`\n\non`inference_done`\n\nso paused turns continue to surface new questions. - Share an inbound reply HITL resolver with YES/NO variant parsing (\n`y`\n\n,`yeah`\n\n,`ok`\n\n,`nope`\n\n, thumbs-up emoji, and the usual variants). - Resume HITL delivery on resolve so sequential adapters render the next prompt; use the absolute\n`public_base_url`\n\nfor HITL fallback URLs on channels that can't render the picker. - Render HITL prompts and resolve responses on Telegram (inline keyboard), Slack (Block Kit via Socket Mode interactions), Discord (buttons), WhatsApp Cloud (interactive messages and button taps), WhatsApp personal account (quote replies), Signal (quote replies), and SMS (\n`Reply YES or NO`\n\nhint on App-deploy approval prompts). - Hold the Discord and WhatsApp typing indicator across long inferences so the user sees activity while the agent is generating.\n- Rename the\n`manage_service`\n\ntool to`manage_app`\n\nand adopt typed HITL hooks; exit tasks on HITL and respawn via`run_task`\n\n. - Test HITL persistence, pause rendering, batched resolve, and the resume race.\n\n### Slash composer\n\n- Add a\n`chat::slash`\n\ninvocation parser for`/`\n\nand`@`\n\nprefixes; add a`MessageCommand`\n\nside field on`Message`\n\nfor parsed slash invocations. - Wire up\n`/commands`\n\nend to end: dispatch, terminal-write refactor, cross-agent attribution, slash parsing. - Add a\n`GET /api/chats/{id}/commands`\n\ndiscovery endpoint and a`listCommands`\n\nAPI client. - Frontend: slash composer with Lexical triggers, directive chips, and a\n`/new`\n\nbuiltin that opens a fresh chat with the current agent. `@<agent>`\n\nper-turn override: the reply is attributed to the target agent and the next message reverts to the chat's default.- Add\n`save_chat`\n\n,`save_updated_message`\n\n, and`delete_messages_for_chat`\n\nhelpers. - Skills: new SKILL.md frontmatter fields\n`disable-model-invocation`\n\n,`argument-hint`\n\n, and`arguments`\n\n; hide`disable-model-invocation`\n\nskills from the model's available-skills block while keeping them in the`/`\n\nmenu for users to invoke directly. - Add e2e tests for\n`/agent`\n\ndispatch and commands discovery.\n\n### Channels and message splitter\n\n- Add a per-format message splitter with shared boundary primitives that break at paragraph, then line, then word, then UTF-8 character, and never inside a code fence or escape sequence.\n- Wire\n`TelegramMarkdownV2Splitter`\n\ninto the Telegram adapter (4,096-char per-message limit) and render markdown tables as monospace code blocks since Telegram has no native table support. - Wire\n`MarkdownSplitter`\n\ninto the Discord adapter (2,000-char per-message limit), remove the old`chunk_for_discord`\n\nhelper, and render markdown tables as monospace code blocks. - Wire\n`PlainSplitter`\n\ninto the Slack adapter (silent multi-chunk). - Wire\n`PlainSplitter`\n\ninto the SMS adapter with a 1,600-char hard cap and`Full reply: {short-link}`\n\noverflow that points at a`Chat`\n\n-kind share URL (reused across overflow events in the same chat). - Wire\n`MarkdownSplitter`\n\ninto the WhatsApp Cloud and WhatsApp Personal adapters. - Wire\n`SignalSplitter`\n\ninto the Signal adapter with per-chunk`SignalText { body, ranges }`\n\n. - Add\n`ChannelError`\n\ntype and`MessageDelivery.failure_kind`\n\nfield; migrate channel adapters to typed`ChannelError`\n\nclassification (`Transient`\n\n,`Forbidden`\n\n,`NotFound`\n\n,`PayloadInvalid`\n\n,`PayloadTooLarge`\n\n,`Unauthorized`\n\n,`Other`\n\n) with an optional`retry_hint`\n\n. - Make\n`start_with_retry`\n\nidempotent so a single start no longer double-spawns the adapter. - Replace the bounded broadcast bus with unbounded fan-out so channel inbound stops losing events.\n\n### Share links and preview pages\n\n- Add a\n`Share`\n\nentity with`File`\n\nand`Chat`\n\nkinds plus a`ShareService`\n\nfor issuing short links; wire the service into`AppState`\n\nand schedule periodic cleanup. - Add\n`share.ttl_secs`\n\n(default 30 days) and`share.cleanup_interval_secs`\n\n(default 6 hours) config knobs. - Add\n`GET /s/{id}`\n\nshort-link resolver with a 303 redirect to the canonical or presigned URL. - Add a\n`/p`\n\npreview page that renders markdown and code with syntax highlighting; add a`GET /p/{slug}`\n\nredirector to the query-param form. - Route channel attachments through\n`outbound_url`\n\nin all adapters via a new`chat::channel::attachment`\n\nhelper: inline-channel previewable files get`/p/{8-char-id}`\n\n, inline non-previewable files get`/s/{8-char-id}`\n\n, button channels emit long-form`/p/{owner}/{handle}/{path}`\n\nor`/api/files/...`\n\nURLs. - Add an\n`anonymous_not_found`\n\nhelper so unknown / expired / unauthorized share IDs return byte-identical 404s. - Extract\n`FilePreviewContent`\n\ninto a shared module; extract`apiFetch`\n\nfrom`request<T>`\n\nfor non-JSON authenticated requests. - Add\n`ShareKind::Chat`\n\nvariant with lazy`lookup_or_issue_chat`\n\nfor SMS chat-share reuse.\n\n### Tasks\n\n- Accept\n`result_description`\n\non`create_task`\n\nand`create_recurring_task`\n\nso prose answers skip schema authoring; reject when both`result_description`\n\nand`result_schema`\n\nare passed (or neither). - Require a top-level\n`summary: string`\n\non complex task result schemas; reject complex schemas without it at task creation. - Carry\n`result_schema`\n\non`TaskCompletion`\n\nevents and persist the JSON content. - Render the\n`TaskCompletion`\n\nbubble with a schema-driven body and a link to the task chat; render`TaskCompletion`\n\nvia a shared markdown helper across channel adapters. - Researcher now publishes the full research as a markdown attachment, named after the topic (e.g.\n`h100-used-prices.md`\n\n) so successive research tasks don't overwrite each other.\n\n### Typed file tools\n\n- Add typed\n`read`\n\n,`write`\n\n,`edit`\n\n,`glob`\n\n, and`grep`\n\ntools. Workspace-scoped by default; absolute and policy-authorized sibling paths allowed; virtual-path URIs rejected. `edit`\n\nuses Unicode normalization (NFKC, ASCII quotes/dashes/spaces, collapsed whitespace) so a slightly-misremembered snippet still matches its target. The motivation is token usage and hallucinations: a typed`edit`\n\nreturns a structured diff in a fraction of the tokens a shell round-trip eats, without the model free-styling shell escapes against a half-remembered path.- Add the\n`frona-text`\n\ncrate with shared text and search primitives (`NormalizedString`\n\n,`LineEnding`\n\n,`walk_with_ignore`\n\nfor`.gitignore`\n\n-aware traversal). - Refactor sandbox:\n`SandboxManager`\n\nis now the single entry point per principal kind.\n\n### Tool views (frontend)\n\n- Extract a per-tool view registry:\n`ToolRow`\n\nprimitives,`DefaultView`\n\n, slim chrome. - Add views for shell, Python, and Node (with sandbox-deny extraction); for the typed file tools (\n`read`\n\n,`write`\n\n,`edit`\n\n,`glob`\n\n,`grep`\n\n) with syntax highlighting and line numbers; for`produce_file`\n\n(filename / size / content-type card); for`web_search`\n\n(result list) and`web_fetch`\n\n(markdown + clickable URL); for task tools (`create_task`\n\n,`create_recurring_task`\n\nwith`cronstrue`\n\n,`delete_task`\n\n); for memory tools (auto-expand on large text); for`update_identity`\n\n(set/remove attribute rendering); and for`set_heartbeat`\n\n(humanized interval and next-tick time). - Render the shell tool command as a bash-highlighted block with wrap; render\n`produce_file`\n\nas a filename card with size and content type. - Add\n`vitest`\n\ntest runner and`cronstrue`\n\n/`unbash`\n\ndependencies.\n\n### Harness / runtime\n\n- Add a\n`Harness`\n\nstruct as the agent runtime view of`AppState`\n\n; route session build, voice WS, message stream, and resume-all through it. - Narrow\n`TaskExecutor`\n\nto hold`Arc<Harness>`\n\nand own its own resolution-notifier map. - Move HITL resolution onto Harness and drop\n`ChannelCtx.app_state`\n\n. - Move task-tool registration into\n`ToolManager`\n\n; extract`deliver_event_to_source`\n\nso`ReportSignalTool`\n\nno longer needs`TaskExecutor`\n\n. - Delete\n`agent/execution.rs`\n\nand update test fixtures for Harness. - Inject heartbeats as a transient turn so the agent stops replying to them like a user message.\n- Fold per-turn lifecycle events into\n`InferenceEventKind`\n\n.\n\n### Browser\n\n- Keep browser sessions alive past Browserless's hard 408-second timeout: pass a long timeout at connect time, self-evict and recycle sessions with a 60-second margin, and evict dead WebSockets immediately.\n\n### Chat / Frontend\n\n- Stop dropping the newest message when a chat crosses the page limit.\n- Move the reasoning toggle from inline content to a sparkle icon in the message header.\n- Disable single-tilde strikethrough in assistant markdown.", "url": "https://wpnews.pro/news/frona-v2026-6-0-self-hosted-personal-ai-assistant", "canonical_source": "https://github.com/fronalabs/frona/releases/tag/v2026.6.0", "published_at": "2026-06-14 19:17:56+00:00", "updated_at": "2026-06-14 19:42:07.093427+00:00", "lang": "en", "topics": ["ai-agents", "ai-tools", "ai-products", "developer-tools", "natural-language-processing"], "entities": ["Frona", "Telegram", "Discord", "Slack", "WhatsApp Cloud", "Signal", "SMS", "WhatsApp Personal"], "alternates": {"html": "https://wpnews.pro/news/frona-v2026-6-0-self-hosted-personal-ai-assistant", "markdown": "https://wpnews.pro/news/frona-v2026-6-0-self-hosted-personal-ai-assistant.md", "text": "https://wpnews.pro/news/frona-v2026-6-0-self-hosted-personal-ai-assistant.txt", "jsonld": "https://wpnews.pro/news/frona-v2026-6-0-self-hosted-personal-ai-assistant.jsonld"}}