39 Commits

Author SHA1 Message Date
EugeneTes
644f72068c feat(skills): session-start and turn-end hooks and protected paths declared in SKILL.md
A skill's SKILL.md frontmatter may declare session-start (output into
<skill_session_context>, at session start, /new, resume and after compaction),
turn-end (after every run, in the background; output or a failure reaches the
next run as a hidden notice, repeats suppressed until a clean run) and
protected-paths (write/edit refused inside them). Hooks run from the skill
directory with VOLCANIC_WORKSPACE, VOLCANIC_SKILL_DIR and the chat's TZ; waits
are bounded by each hook's timeout and failures never break a run. /skills
shows declared hooks and broken fields.
2026-10-16 12:27:44 +00:00
EugeneTes
d51438e665 feat(telegram): several admins via ADMIN_USER_IDS, each impersonating independently
ADMIN_USER_IDS (Telegram:AdminUserIds) takes a comma separated list; the older
ADMIN_USER_ID / Telegram:AdminUserId still works, also takes a list and is merged.
Empty entries and duplicates are ignored, non-numeric entries fail validation.
Impersonation is now per admin: one admin per target, an impersonating admin
can't be impersonated, and every admin's chat menu lists /impersonate.
2026-10-15 14:02:59 +00:00
EugeneTes
7fef3ce94e feat(telegram): ElevenLabs text to speech for the voice tool
ElevenLabs speaks for the voice tool when ELEVENLABS_API_KEY and ELEVENLABS_VOICE_ID
are set (TTS_PROVIDER=elevenlabs|openai picks, the other is the fallback). Opus output
(opus_48000_64) goes to Telegram as is; voice names resolve through /v2/voices;
instructions become audio tags on eleven_v3 and are ignored on other models. The key
is redacted from tool output and never reaches agent processes.
2026-10-14 13:07:36 +00:00
EugeneTes
6e3241fed9 feat(scheduler): scheduled jobs inside skills (.volcanic/skills/<skill>/jobs/<job>.md)
Skill directories may now declare prompt or watcher jobs as files (cron or one-off at).
The file is the source of truth: the scheduler re-reads every chat's jobs/ every minute,
around agent runs and before /jobs and /skills, and schedules, re-plans or removes them.
Ids are <skill>/<job>; run state lives in .volcanic/scheduler/skill-jobs-state.json, never
in jobs.json. Watchers run from the skill directory with VOLCANIC_WORKSPACE and
VOLCANIC_SKILL_DIR. Broken files are shown with the reason in /jobs, /skills, schedule list
and the new <skill_jobs> prompt section; cancel answers with the file to edit. Every part of
a skill directory is optional; file reading and frontmatter parsing move to Abstractions.
2026-10-14 12:54:40 +00:00
EugeneTes
a92623b89b fix(a2a-client): save every file the remote agent returns, per task, with size and type
File parts were only taken from artifacts as inline bytes up to 10 MB; parts in the
status message or the history were dropped silently, URL parts were never downloaded,
and a plain message reply lost its files. Files now go to inbox/a2a/<taskId>/ from
artifacts, status message and recent agent messages (deduplicated), URLs are streamed
to disk (agent key only on the agent's origin, else https without it), the cap is the
new MaxReceivedFileBytes (200 MB), and results list path, bytes and media type or why
a file was not saved. Re-saving a task overwrites, so action=status refetches files.
2026-10-12 16:16:14 +00:00
EugeneTes
0cae6f600a feat(telegram): pass GOOGLE_CLIENT_SECRET to agent processes, still redacted
GOOGLE_CLIENT_SECRET is no longer denied by name in the core defaults (the
*_SECRET glob still removes it); the Telegram host allows it by default so
workspace skills (gmail, gdrive) can use the Google OAuth client. Its value
stays in SecretValues: redacted from tool output, and aliases with the same
value are still removed.
2026-10-12 15:10:49 +00:00
EugeneTes
bb1c534a7a feat(core): always-on INSTRUCTIONS.md in skill directories
A skill directory may hold INSTRUCTIONS.md, with or without SKILL.md. Its body
(frontmatter cut) goes into every system prompt in <skill_instructions>, re-read
on every run: 16 KB per file, 64 KB in total, truncation marked with the file's
path. /skills marks skills with instructions and lists instruction-only dirs.
2026-10-12 10:15:05 +00:00
EugeneTes
dccdf3a8ed fix(core): skills live in <cwd>/.volcanic/skills, next to the rest of the workspace config 2026-10-10 14:16:20 +00:00
EugeneTes
c3095c69ca feat(core): per-workspace Agent Skills listed in the system prompt, /skills in Telegram
Skills live in <cwd>/.claude/skills/<name>/SKILL.md (frontmatter name + description).
SkillCatalog re-reads them on every run and the prompt lists name, description and
path; the model reads the full SKILL.md with the read tool when a task matches.
2026-10-10 14:13:42 +00:00
EugeneTes
891a644590 feat(mcp): remote MCP servers per chat with sealed keys and owner-only commands
Streamable HTTP/SSE servers from the workspace's .volcanic/mcp/servers.json.
Headers are sealed with AES-GCM; the chat and the visible fields are the
associated data, so only /mcp_add|remove|tools change servers. Tools
<server>__<tool> go live in the session. An unreachable server is skipped
and reported in the system prompt. Keys are redacted from tool results, and
Telegram deletes messages that carry one.
2026-10-09 21:11:01 +00:00
EugeneTes
87240238cc feat(telegram): voice tool sends spoken replies as Telegram voice notes
OpenAI gpt-4o-mini-tts (female voice nova by default; TTS_MODEL/TTS_VOICE) renders OGG/Opus,
sent with sendVoice in order with rendered output. Up to 4500 characters per call, split
into 1500-character parts at paragraph/sentence/word boundaries; all parts are synthesized
before any is sent, and API errors come back to the agent as text with the key hidden.
On whenever OPENAI_API_KEY is set.
2026-10-09 10:09:46 +00:00
EugeneTes
5e50d902af docs(a2a): A2A client guide, configuration and Telegram notes 2026-10-08 14:34:02 +00:00
EugeneTes
3360c320e7 docs(a2a): security reach, ports and limits 2026-10-07 14:32:33 +00:00
EugeneTes
d542fcfe42 docs(a2a): A2A server guide, architecture, Telegram and Docker notes
Add docs/a2a.md (concepts, file formats, endpoints, sessions, task
lifecycle, configuration, security notes, curl examples) describing
what src/Volcanic.AgenticCore.A2A.Server actually does. Add an A2A
project paragraph to architecture.md, an "A2A" section to
telegram-bot.md (/a2a, notify_owner, isolated sessions, port 8080),
A2A_ENABLED/A2A_PUBLIC_URL and the aspnet image to docker.md, and
project-map/test-command updates to CLAUDE.md.

Mark the A2A server design spec implemented and record the deviations
found while building it (A2AHostOptions, synchronous
IA2ACallerDirectory.Find, generic WorkspaceCallerDirectory, per-status
push payload, split file-part error handling, the outbound guarded
handler, the per-caller server/router architecture, the restart grace
period, the owner= log field, the aspnet image, and the actual push
retry schedule). Note the aspnet image in the docker-deployment spec
too, without rewriting its historical decisions.
2026-10-07 14:20:19 +00:00
EugeneTes
cabec7ad70 docs(telegram): groups and Jev topic triggers 2026-10-05 16:29:07 +00:00
EugeneTes
92a0061fdd feat(telegram): ADMIN_USER_ID may /impersonate another user
While on, the admin's updates are routed as the target user's (allow-list,
chat, workspace, session, settings, jobs) and the target chat's output goes
to the admin's chat. The target's own updates are dropped with a notice that
an admin is working with their account. In memory; /impersonate 0 stops.
2026-10-05 07:24:07 +00:00
EugeneTes
64ea6f7fa1 feat(telegram): retry transient speech-to-text failures up to 3 attempts 2026-10-05 07:02:23 +00:00
EugeneTes
39e7849039 fix(telegram): cut the voice transcript echo to 1024 characters 2026-10-02 09:51:57 +00:00
EugeneTes
d2fd7ffa02 feat(google-calendar): encrypt chat tokens and give watchers a short-lived access token
token.json is sealed with AES-256-GCM (key derived from the OAuth client secret,
bound to the chat), so the agent's processes can read the file but not the
refresh token. Plain files, including VolcanicSecretary's refresh_token format,
are rewritten sealed on first read.

The scheduler gains IScriptEnvironment: extra per-run variables set after the
process environment filter and redacted from the run's output. The Telegram
host uses it to pass GOOGLE_ACCESS_TOKEN, refreshed to cover the job's timeout;
the refresh token and client secret never reach the script.
2026-10-02 08:31:24 +00:00
EugeneTes
28bbfbc759 feat(scheduler): store jobs per chat and import VolcanicSecretary job files
Each chat's jobs live in <workspace>/.volcanic/scheduler/jobs.json. On start the
scheduler loads every chat's file, moves the retired shared
<agentDir>/scheduler/jobs.json into them and renames it .migrated-<ts>.
A VolcanicSecretary jobs.json (bare array) in a chat's folder is converted
in place for that chat; the original is kept as .secretary-<ts>.

Also adds the VolcanicSecretary data migration plan.
2026-10-02 07:29:48 +00:00
EugeneTes
8014a0e770 refactor(scheduler): drop the reminder job kind
Jobs are prompts or watchers. A reminder is a prompt the agent passes on, so
it lands in the transcript. Stored reminder jobs load as prompts
("Remind me: <text>"). Also records the Coolify deploy target in CLAUDE.md.
2026-09-29 09:30:40 +00:00
EugeneTes
92c881377b docs(docker): link the container setup from the README, bot and MCP docs 2026-09-27 12:17:41 +02:00
EugeneTes
126d3afff1 docs(scheduler): scheduling, per-chat time zones and the session zone 2026-09-27 10:40:43 +02:00
EugeneTes
6ab98a8155 fix(telegram): address review findings
- A speech or download timeout (TaskCanceledException nobody asked for) is a failure
  with the user notice, not a silent shutdown; OpenAiSpeechToText maps it to
  "the request timed out."; UpdateRouter only treats the caller's cancellation as shutdown.
- send: WorkspacePaths resolves the real path component by component (realpath),
  closing the directory-link-inside-target bypass; `.` reports a directory.
- Image documents are attached inline only when their magic bytes are JPEG/PNG/GIF/WebP,
  under the detected type.
- Audio goes to STT as an ASCII audio.<ext> name.
- MCP Browser section mentions send only when it is active.
- RunInOrderAsync takes a cancellation token; queued work is skipped once disposal gives up;
  SendReplyAsync stays private behind ReplyInOrderAsync.
- Speech HttpClient handler recycles pooled connections; BuiltInTools.Send();
  IExtensionHost.Channel is abstract; WorkspacePaths in its own file.
- Tests: timeouts, symlink chains (Linux), sniffing, channel delivery failures,
  queued-work cancellation, gated voice ordering. Spec and docs updated.
2026-09-26 22:35:20 +02:00
EugeneTes
c5ecd017a0 docs(telegram): attachments, voice, send and IChatChannel
telegram-bot.md: what you can send, files from the agent, speech settings, security notes. ui-integration.md: document/voice input rows and a new section 5 on IChatChannel. architecture, extensions and CLAUDE.md list IChatChannel. Drop the interim paragraph from the message-context spec; mark the attachments spec implemented with resolved questions.
2026-09-26 22:16:29 +02:00
EugeneTes
0b28b9627d Merge branch 'feat/google-calendar' 2026-09-26 21:24:34 +02:00
EugeneTes
4cfe3cec47 Merge branch 'feat/mcp-client-playwright' 2026-09-26 21:20:52 +02:00
EugeneTes
c9fd58372a docs(mcp): MCP client and Playwright preset 2026-09-26 21:05:17 +02:00
EugeneTes
881e7f0be9 fix(google-calendar): address review findings
- log an unknown stored zone once even when the tool description reads it first
- serialise the flow's token write with /calendar_disconnect under the flow gate
- a cancelled or expired pending flow is cleared, not re-sent or shown
- chat keys anchor with \z so a trailing newline is hashed
- a timeMax date includes that whole day (spec updated)
- dispose the flow's CancellationTokenSource, drop ConnectFlow.Token, Begin is a plain write
- GoogleCalendarOptions.IsConfigured replaces the host's copy of the rule; StoredToken is internal
- test BotSetupService's menu through DI, tokens absent from tool results
- Telegram.Tests csproj reference placed as in telegram-message-context; ChatHost passes calendar by name
- docs: per-event timeZone, both config sources for /calendar_*
2026-09-26 20:30:56 +02:00
EugeneTes
8ece6f303d docs(google-calendar): setup guide, Telegram configuration and architecture notes
Spec: the unverified-app screen is described in text; open question 1 resolved (full calendar scope); status implemented.
2026-09-26 20:20:32 +02:00
EugeneTes
2ec941bf2a fix(telegram): address review findings
- /resume discards the inbox once the id names one conversation, before any await
- /stop discards input still waiting in the window
- a forwarded message is never a command or a pending answer
- ChatInbox.DrainAsync is an internal test helper
- tests: /resume and /stop drop buffered text, forwarded /new is content,
  a failing flush doesn't stop later batches; no wall-clock sleep in the drain test
- spec and user docs: timestamp exception for extension commands, command
  ordering, InputDebounce=0 wording
2026-09-26 20:15:57 +02:00
EugeneTes
0c1778e741 docs(telegram): message context, grouping and presence
InputDebounce config row, the Using it section (replies, quotes, forwards, local-time header, grouping window, eyes reaction, online message, forwards never count as the login code), the Inbound paragraph in CLAUDE.md, and spec status set to implemented.
2026-09-26 20:09:20 +02:00
EugeneTes
694ef3594e feat(telegram): process environment policy, secret values and host hardening
Spec 6 now says this spec adds only the bot token to SecretValues; the speech key and Google client secret are added by the telegram-attachments and google-calendar specs.
2026-09-26 19:20:43 +02:00
EugeneTes
d20385153b docs: the owner's pending login prompt, one-message link, joined logins and stale expiries 2026-09-25 17:57:58 +00:00
EugeneTes
df0a518b97 feat(telegram): send Claude Code login links to the bot owner 2026-09-25 17:45:11 +00:00
EugeneTes
17ce025c57 feat(prompt): PERSONA.md and MEMORY.md in the system prompt; AGENTS.md or CLAUDE.md, not both 2026-09-25 16:36:49 +00:00
EugeneTes
b85b61677e fix(telegram): send answers complete instead of streaming; working message no longer lingers 2026-09-25 16:08:34 +00:00
EugeneTes
bb8c3f43aa feat(telegram): working status message with the last five tool calls 2026-09-25 15:09:43 +00:00
EugeneTes
308e1fbf8e feat(telegram): telegram bot host with connection recovery 2026-09-25 14:42:12 +00:00