TensorPM v1.5.0-beta.1 (Beta)
Pre-releaseChangelog - v1.5.0-beta.1
The first beta after v1.4.0-beta.2. The headline change is TensorPM's
second connector — Telegram — which graduates the connector framework
from "email-only, hardcoded" to a real multi-connector surface and lets
project participants interact with the in-app TensorPM agent over a chat
they already use every day.
This release also brings a proxy / BYOK Gemini upgrade (Google's
freshly-GA Gemini 3.5 Flash replaces the preview Flash models and becomes
the default), and a tidy-up of how credits are handled in the renderer.
🎉 New Features
Telegram Connector — Chat with Your Project Agent from Telegram
Project participants can now talk to the TensorPM agent from inside
Telegram. The connector is the second full citizen of the connector
framework (alongside Email) — same intake pipeline, same human-in-the-loop
distillation, same per-link tool policies — without needing the desktop
app open in front of you.
What users can do:
- Set up a bot once per workspace. A new connector type "Telegram" in
the Wizard takes a Telegram bot token (created via Telegram's
@BotFather), validates it againsthttps://api.telegram.org/getMe,
stores it under the existing encrypted credential service, and starts a
long-poll watcher on the desktop main process. - Invite contacts via deep link. Each project (or workspace, for
shared scope) can mint short, single-use Telegram invite codes with an
expiry. Sharing the generatedhttps://t.me/<bot>?start=<code>link
drops the recipient straight into a chat session that's already bound
to the right project. - Self-introduction handshake. On first contact, the bot greets the
user, asks how they'd like to be addressed (label + role), and stores
the link inpending. The owner approves or revokes from the
Telegram panel before anything reaches the project context. - Talk to the project agent in natural language. Approved links can
send text, photos (with or without captions), documents, voice notes,
and audio. Photos and documents land in the project intake just like
email attachments. - Per-link tool policies. Each approved contact gets a tool allowlist
configured by the owner. Defaults are conservative — only
propose_updates(intake) is enabled out of the box, but the owner can
selectively enable:generateActionItems— create action itemsupdateActionItemFields— status / assignee / dates / effortrecord_decision— write decisions into the trailupdateProjectSections— edit description, goal, scope, dependenciesupdateTable— requirements, milestones, risks, methodsadd_person— add people to the projectweb_search— search the web while answering
- Slash commands inside Telegram:
/new— start a fresh chat without dragging in the prior context/help— re-show the help text/stop— revoke your own link with the bot
- DE / EN UI for the whole panel: invite list, link approval queue,
active links, sync status, tool-permission editor.
Architecture (where to look in code):
- Migration
030-add-telegram-intakeadds three new local tables:telegram_invites— pending / redeemed / expired / cancelled invite
codes, scoped private or workspacetelegram_links— approved relationships between a Telegram user
and a project, with status (pending / approved / revoked) and the
self-introduction texttelegram_messages_local— local message queue with dedupe keys,
pending/processing/distilled/rejected/ignored
statuses, and a claim/lease mechanism for the watcher
- All three tables are
excludeFromSync: true— Telegram identifiers
and message content do not flow to PowerSync. The connector lives
on the local-first side of the boundary and no cloud sync schema
change is required to ship this release. - Services:
TelegramConnectorService— long-poll watcher with reconnect
back-off (5 s base, 5 min cap), bot validation, invite/link CRUD,
HELP //new//stophandling.TelegramChatBridgeService— routes incoming Telegram messages into
the chat service with the right project/link context, builds
attachment manifests, owns the prompt envelope.TelegramIPCHandler+telegramSlice/telegramThunks— full
typed IPC namespace (window.api.telegram.*) plus Redux store
bindings.
- Agent prompts: new
TelegramAgentPromptGenerator(parallel to the
Email/Distiller generators) carries link metadata, tool policy, and the
self-introduction into the system prompt without bleeding it into other
chats. - Intake & tool surface:
- New
ProposeUpdatesExecutorandpropose_updatestool type — the
locked, always-on tool that books raw Telegram messages into
project_updatesfor human review through the existing Distiller. ConnectorCredentialServiceextended to handle bot-token secrets
alongside IMAP/SMTP passwords.
- New
Security & guardrails:
- Bot token never leaves the desktop main process. Renderer only sees a
hasCredentialsflag. - Long-poll uses
allowed_updates: ['message']; no inline-queries, no
channel posts, no member-update side channels. - Invite codes are short-lived, single-use, and bound to either a
specific project (scope: 'private') or workspace (scope: 'workspace'). - Per-link tool policies are server-side enforced at the chat service
layer — toggling a switch in the UI changes which executors the agent
is even allowed to call for that contact. - Messages from
pendingandrevokedlinks never reach the agent. The
agent's only response to a non-approved chat is the introduction
prompt or a hard "you're not currently linked" message. IntakeRepositoryandIntakeServicegainedtelegram-aware queries
so the Distiller IntakeIndicator surfaces Telegram messages with the
right icon, source label, and routing.
Connector Framework: From "Email Only" to Multi-Connector
Telegram is the first real second connector, so the framework itself was
unfrozen.
ConnectorTypewidened from'email'to'email' | 'telegram'.ConnectorConfigis now a discriminated union of
EmailConnectorConfig+TelegramConnectorConfig. Email config keeps
its existing shape; Telegram config carries bot identity
(botUsername,botUserId,botFirstName), the credential flag, the
per-bot tool allowlist, and sync status.ConnectorConfigRepositorylearned how to round-trip both shapes,
including the JSON-encoded tool allowlist.- The Wizard's
ConnectorOverviewPanelandConnectorListnow render
both types side-by-side, with a dedicatedTelegramConnectorPanel
(962 lines of UI + a 590-line stylesheet) for setup, invite
generation, link approval, and tool policy. EmailConnectorSetupFormgot matching visibility-label/hint copy
updates so the two connectors feel like siblings, not stepchildren.IntakeIndicatorwas upgraded with cross-connector grouping so a
project that's receiving both email and Telegram traffic shows a
unified pending queue.
The internal contract (ConnectorCredentialService, intake routing,
distillation hand-off) is now general enough that the next connector
(PlanRadar / Capmo / Procore / Slack / Calendar) can be added without
another framework rewrite.
Default Model: Gemini 3.5 Flash (GA)
Google's Gemini 3.5 Flash (GA on 2026-05-19) replaces the
preview-channel Flash models everywhere in the app.
- BYOK Google users get
gemini-3.5-flashas the new default model
for both the primary and the "small" / utility slot. - Proxy backend advertises the same model as the default chat model
(the Vertex AI proxy backend was already shipping Gemini 3.5 Flash —
this aligns the BYOK side with proxy reality). gemini-3-flash-previewandgemini-3.1-flash-lite-previeware
removed fromPROVIDER_CONFIGS.google.modelsand
MODEL_CAPABILITIES.gemini-3.1-pro-previewstays as the heavy
option.MODEL_LIMITSupdated:gemini-3.5-flash= 1,048,576 input / 65,535
output tokens. Vision capability flag set on the new model.GeminiProvidernow decides whether to attachthinkingConfigbased
on the new model identifier (3.5 Flash has the thinking knob; older
preview models did not). The proxy provider follows the same logic.ClaudeProviderships a small refactor along the way to centralise
thinking-config decisions across providers.
Migration safety net: AppSettingsRepository.getSettings() now
validates each stored preferred_models[provider] against the current
PROVIDER_CONFIGS[provider].models list and falls back to the
provider's default if the stored model is no longer supported. So an
existing user whose preferences were last persisted as
gemini-3-flash-preview gets seamlessly upgraded to
gemini-3.5-flash on next launch — no orphaned setting, no broken
provider call.
Credit Summary Lives in Redux
The proxy credit balance (used by the AI Panel header pill and the
credit budget views) moved from a per-component useProxyCredits hook
that spoke directly to IPC, into a proper Redux slice.
- New
creditsSlicewithsummary,isLoading,error,
lastFetchedAt,activeRequestId. - New
creditsThunks.fetchCreditSummarywith request-id de-duping so
rapid renders don't pile up parallel API calls. - New
creditsListenermiddleware: whenever a chat stream finishes
(chatSlice.streamFinishedaction), the credit summary refreshes
automatically — the header pill catches up without users having to
open Settings. useProxyCreditsis now a thin selector over the slice, with login
gating: if the user isn't authenticated to the proxy, no fetch is
scheduled. Eliminates the "credit-summary 401 storm on logout" issue
observed in dev logs.subscriptionThunkstriggers a credit refresh after subscription
state changes so the UI stays consistent post-checkout.
Telegram Messages in Chat UI
When the project ChatPanel surfaces a chat thread that originated from
Telegram, individual messages now render with their Telegram identity:
- Avatar + display name pulled from the
TelegramLink(label,
telegram_first_name,telegram_username). - A small "Telegram" source indicator on the message row.
- The streaming-message component handles the case where the inbound
half of the turn is a Telegram message and the outbound half is the
agent reply, without confusing the alignment / avatar logic.
🏗️ Improvements
Iterative Chat Prompt Generator
The shared iterativeChatPromptGenerator was extended to be
language-aware in the same way baseChatPromptGenerator already was, and
to handle tool-call lists more deterministically. New unit coverage in
iterativeChatPromptGenerator.test.ts (87 lines) locks down both behaviours.
Renderer State Wiring
rootReducernow mounts the newcreditsandtelegramslices.chatSliceexposes astreamFinishedaction that other listeners
(credits, intake) can subscribe to without poking into chat internals.intakeSlice/intakeThunkslearned thetelegramsource so the
Distiller indicator badge counts Telegram messages alongside email.
Backend Cleanups Bundled with the Feature
ChatRepositorygot minor query additions for cross-connector chat
retrieval.IntakeServiceandchatServicewere refactored to accept a generic
external-source descriptor instead of the email-shaped one — required
by Telegram but useful for any future connector.coreToolModuleregisters the newpropose_updatestool centrally,
rather than each connector having to wire it up.- All five primary AI providers (
ChatGPTProvider,ClaudeProvider,
GeminiProvider,LocalAIProvider,MistralProvider, plus the
proxyproxyProvider) had a small symmetric tidy of how they
consume thinking-config / tool-result shape, removing the last
Gemini-preview-only conditionals.
🐛 Bug Fixes
- Credit pill spam on logout / startup.
useProxyCreditsno longer
fetches before the user is authenticated to the proxy, and the slice
swallows the inevitable startup 401s instead of surfacing them as a
toast. - Interrupt rendering for Telegram bridged messages.
ChatMessage
correctly suppresses the stop-marker when a Telegram-originated user
message follows an interrupted assistant message (mirrors the fix
shipped for normal chat in beta.2). - Stale model preferences. Users who had
gemini-3-flash-preview
saved as a preference no longer hit a "model not available" error on
startup — the AppSettingsRepository validator now silently substitutes
the new default. - ConnectorIndicator label drift. Visibility labels and hints in the
Email connector setup form were briefly worded inconsistently with the
Telegram panel; they now share copy. - IntakeIndicator pending-queue sort. Pending-queue sort now
reliably orders mixed-source items (email + Telegram) by received-at,
with deterministic tiebreaks. NewpendingQueueSort.test.ts.
📦 Database & Sync
New Migration: 030-add-telegram-intake
Adds three local-only tables:
| Table | Purpose |
|---|---|
telegram_invites |
Single-use invite codes (private / workspace scope) |
telegram_links |
Telegram user ↔ project relationships and tool policy |
telegram_messages_local |
Inbound message queue with dedupe + claim/lease state |
All three are excludeFromSync: true. Telegram identifiers, message
text, and attachments are local-only by design — they never reach
the PowerSync cloud. The desktop binary is the source of truth for this
connector.
No Cloud Sync Migration Required
Unlike v1.4.0-beta.2 (which needed add-material-items.sql applied to
the sync backend before shipping the desktop release), this release
does not require a TensorPMSync schema change. The release pipeline
order simplifies:
- Ship the desktop binary.
- (No sync side-step.)
If a future Telegram-via-cloud-workspace feature is built, the schema
will need to be opened up at that point — but as of 1.5.0-beta.1 the
intent is to keep Telegram identifiers and message contents on-device.
📝 Notes
Bot Setup Prerequisite
Telegram setup requires the user to create a bot via Telegram's official
@BotFather flow and paste the bot token into TensorPM. There is no
TensorPM-owned default bot — every workspace runs its own. This avoids:
- Centralised token compromise blast radius
- TensorPM seeing third-party message content
- Telegram rate-limit cross-talk between unrelated workspaces
The Wizard surface includes a one-click open of the @BotFather
conversation and a short setup checklist in both DE and EN.
Tool Policy Defaults
Out of the box, the only tool a freshly-approved Telegram contact can
trigger is propose_updates — i.e. drop their message into the project
intake queue for the owner to review through the Distiller. Everything
else (action items, decisions, project edits, web search) requires the
owner to explicitly opt that contact in. This matches the "distillation
is always human-in-the-loop" guardrail; a Telegram message is treated
as a raw signal, not as direct authority to mutate the project graph.
MCP / Skills Surface Unchanged
This release does not change the Skill manifest format, the Skill
catalog endpoint, the trust model, the sandbox limits, or the
describe_skill / execute_code tools. It also does not change the
MCP write tools (decisions, action items, project, workspace, billing,
feedback, etc.). External MCP and A2A clients require no migration.
Provider Vision-Loop Scope
Still limited to Anthropic and Gemini wire formats, as in v1.4.0-beta.2.
The newly-default gemini-3.5-flash continues to fully support the
render → inline-image → vision-loop pattern, including via proxy.
Known Follow-Ups
Not blockers for this beta:
- Voice/audio Telegram messages are received and queued, but the
out-of-the-box Distiller pipeline still treats them primarily as
"raw text via caption / transcription stub". Richer voice-note
handling (Whisper-style transcription) is the next obvious win. - The connector framework now has email + Telegram. The next
abstraction step — pulling the bot watcher loop and the
ConnectorIndicator routing into a fully type-parameterised base —
remains open. /newresets conversational context but does not clear pending
proposed updates from earlier in the thread; those still go through
normal Distiller review.
📅 Release Info
- Version: 1.5.0-beta.1
- Release Date: May 19, 2026
- Previous Version: 1.4.0-beta.2
- Type: Beta Minor Release (new Telegram connector, default Gemini
model bump to GAgemini-3.5-flash, credits-Redux refactor)