docs(scheduler): scheduling, per-chat time zones and the session zone

This commit is contained in:
EugeneTes
2026-09-27 10:40:43 +02:00
parent 709b2d2513
commit 126d3afff1
6 changed files with 92 additions and 18 deletions

View File

@@ -5,7 +5,7 @@
```
src/Volcanic.AgenticCore.Abstractions contracts (no runtime code except helpers)
src/Volcanic.AgenticCore runtime, organised as vertical slices
extensions/* provider and feature extensions (MCP client, Google Calendar), built on the public API only
extensions/* provider and feature extensions (MCP client, Google Calendar, Scheduler), built on the public API only
samples/* reference host
tests/* xunit
```
@@ -21,6 +21,10 @@ directories.
`GoogleCalendar` is a feature extension: a tool and three commands, per-chat accounts through process-wide
`GoogleCalendarConnections` (see [google-calendar.md](google-calendar.md)).
`Scheduler` is a feature extension with a process-wide `JobScheduler` (reminders, scheduled prompts and watcher
scripts on a `TimeProvider` timer, jobs in `<AgentDir>/scheduler/jobs.json`), a per-session `schedule` tool bound to a
host target, and an `IJobDelivery` the host implements (see [telegram-bot.md](telegram-bot.md#scheduling)).
## Vertical slices
The runtime is organised by feature, not by layer. Each folder under `src/Volcanic.AgenticCore/Features`
@@ -55,6 +59,15 @@ is the composition root of one conversation; a host never touches the other slic
Extensions are instantiated per session, so extension fields are per conversation. Provider registrations
also live per session (a `ModelRegistry` per session), which keeps sessions independent.
## Time zone
A session's zone is the first that is set of `SetTimeZone`, `AgentSessionOptions.TimeZone`,
`AgenticCoreOptions.DefaultTimeZone` and `TimeZoneInfo.Local`. It is exposed as `IExtensionContext.TimeZone`, becomes
`TZ` for the session's processes (`PrepareProcessAsync`) and for Claude Code's `claude -p`, and fills the system
prompt's `Current date` / `Time zone` lines. The prompt has the date only and is rendered per run, so a change applies
from the next run and the cached prompt prefix changes at most daily. The session doesn't persist its zone; a host
that lets users change it keeps it (the Telegram host in `chat-settings.json`).
## The agent loop
`PromptAsync(text)`:
@@ -113,9 +126,9 @@ Two independent event systems exist:
## Processes and secrets
Every process started on the agent's behalf (`bash`, `IExtensionApi.ExecAsync`, MCP server processes, which are
prepared through `ctx.PrepareProcessAsync` per session and through `api.Processes` for catalogue discovery, and, with
its spec, scheduler scripts) gets its command, cwd and environment from one `IProcessSpawnPolicy`, configured through
`AgenticCoreOptions.ProcessEnvironment`:
prepared through `ctx.PrepareProcessAsync` per session and through `api.Processes` for catalogue discovery, and
scheduler watcher scripts, through the DI `IProcessSpawnPolicy` since jobs fire without a session) gets its command,
cwd and environment from one `IProcessSpawnPolicy`, configured through `AgenticCoreOptions.ProcessEnvironment`:
```
inherit the host environment → filter (Deny, Allow, SecretValues) → explicit request.Environment (never filtered)
@@ -136,7 +149,7 @@ dumpable.
results, progress updates and error messages (see the loop above), so every tool is covered in one place.
The Claude Code provider's own `claude` processes are outside the policy on purpose: they run the model and already
get an allow-listed environment. None of this is a sandbox: the agent still runs as the host's OS user and can read
get an allow-listed environment (plus the session's `TZ`, set by the provider). None of this is a sandbox: the agent still runs as the host's OS user and can read
the files that user can read.
## Persistence