Fixes the debouncer race where a fast comment message flushes on its
own before slow audio transcription completes, splitting a single
user turn into two.
Telegram sends "forward with a comment" as two separate messages. Buffer
inputs for ~600ms after each arrival and flush a single merged AgentInput;
label forwarded content with its origin so the merged text is intelligible.
The Dockerfile installs Chromium via `playwright install chromium`, but
Playwright MCP defaults to Chrome (the branded Google build) when no
browser is specified. On a fresh container the launch fails and the
agent falls back to installing Chrome at runtime. Baking the env var
into the image keeps installed browser and default in sync.
Adds a `send` custom tool so the agent can push files and images from the
workspace to the owner as Telegram attachments, closing the gap where the
bot could receive files but only ever reply with text.
Two review followups:
- Consume the piped stderr from @playwright/mcp so browser-launch
failures surface in our own logs (was set to "pipe" but never read).
- Drop the wrong ["mcp-server-playwright"] lookup; the actual bin key
is "playwright-mcp". Falling through Object.values worked but was
dead code.
Bridge @playwright/mcp as a stdio subprocess and re-export its tools
as Pi custom tools, gated on PLAYWRIGHT_ENABLED. Uses Type.Unsafe to
pass MCP inputSchema through to the model without hand-mapping.
Extends the calendar tool to create, modify, and delete recurring events
via raw RFC 5545 recurrence lines, with instance vs. series scope on
update/delete and a list_instances action to fetch a series' occurrences.
Telegram delivers voice messages with a .oga extension (audio-only OGG),
which OpenAI's transcription API rejects even though the container bytes
are identical to .ogg.
Install tzdata so TZ resolves, default SECRETARY_TIMEZONE to
Europe/Warsaw, and pass it through as the container-wide TZ so OS
timestamps (logs, date, cron) match the app's scheduling zone.
pi-claude-code-provider fences off Claude Code's MCP servers by design,
so managed MCPs like Google Calendar can't reach the bot through that
provider. Implement calendar access as a first-class Pi tool instead —
it lives alongside `schedule` and calls Google Calendar API v3 directly
with a subscription-free refresh-token grant.
Config: three new optional env vars (GOOGLE_CLIENT_ID,
GOOGLE_CLIENT_SECRET, GOOGLE_REFRESH_TOKEN) — set all three to enable
the tool, leave all three blank to disable. Partial config raises a
ConfigError at startup so mis-set env is caught early.
Tool: list / create / update / delete on any calendar (default
'primary'). Access tokens are cached until expiry and refreshed on
demand from the long-lived refresh token. Invalid_grant surfaces a
clear "re-run device flow" error.