feat(runtime): add config-driven session_mode for agent triggers#2341
Merged
houko merged 4 commits intoApr 13, 2026
Merged
Conversation
Add SessionMode enum (persistent/new) to AgentManifest so agents can control whether automated invocations (cron ticks, event triggers, agent_send) reuse the persistent session or start fresh each time. - Per-agent default via `session_mode` in agent.toml - Per-trigger override via `Trigger.session_mode: Option<SessionMode>` - Channel-derived sessions unaffected (always deterministic per-channel) - Default is "persistent" (backward-compatible) - Applies to hands automatically (shared pipeline) Introduces TriggerMatch struct to plumb per-trigger session_mode through trigger evaluation and dispatch. https://claude.ai/code/session_01WLeiKnazjiRnjyFRQy9inY
houko
approved these changes
Apr 13, 2026
houko
left a comment
Contributor
There was a problem hiding this comment.
LGTM. Clean, backward-compatible change:
- Resolution chain is correct: per-trigger override > manifest
session_mode>Persistentdefault - Channel-derived sessions are properly excluded —
session_modeonly affects non-channel branches, so Telegram/Discord conversations are not disrupted - Session resolution logic in
send_message_fullandexecute_llm_agentstays consistent; no half-updated path TriggerMatchstruct replaces the tuple cleanly, carrying the override all the way fromevaluate()through dispatch#[serde(default)]+Default = Persistentkeeps existing TOML and call sites behaving exactly as before- Routing through a private
send_message_with_session_modeinstead of changing the publicsend_messagesignature keeps the API surface tight
Recommend running a live integration check post-merge to confirm fresh session IDs actually differ per invocation in the logs.
DaBlitzStein
pushed a commit
to DaBlitzStein/librefang
that referenced
this pull request
Apr 13, 2026
…hardening Brings in: - feat(channels): Telegram rich media, polls, interactive commands, channel_send tool (librefang#2356) - feat(runtime): config-driven session_mode for agent triggers (librefang#2341) - fix(agents): refuse direct DELETE on hand-spawned agents (librefang#2361) - fix(channels): harden poll_options parsing and poll context cleanup (librefang#2364) Conflicts resolved: bridge.rs (new trait methods), prompt_builder.rs (9-param build_channel_section merging bot_username/group_members with granted_tools), tool_runner.rs (cron-tz tests + poll_options tests).
4 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #2342.
Motivation
Agents invoked by automated sources (cron ticks, event triggers,
agent_send) currently always reuse the agent's persistent session. This means context accumulates indefinitely across background invocations — fine for stateful assistants, but wrong for stateless jobs like "summarize today's emails" or "run a health check" where each invocation should start clean.This PR adds a
session_modeknob so agent authors can opt into fresh sessions per invocation without changing any existing behavior.Changes
Types (
librefang-types/src/agent.rs)SessionModeenum (Persistent|New) with#[serde(rename_all = "snake_case")],Default = Persistent.session_mode: SessionModefield onAgentManifestwith#[serde(default)]— backward-compatible, existing TOML files parse unchanged.Trigger engine (
librefang-kernel/src/triggers.rs)session_mode: Option<SessionMode>onTrigger— per-trigger override,Noneinherits from the target agent's manifest.TriggerMatchstruct replaces the old(AgentId, String)tuple returned byevaluate(), carryingagent_id,message, andsession_mode_overridethrough dispatch.TriggerMatchfield access.Kernel dispatch (
librefang-kernel/src/kernel.rs)send_message_fullgains asession_mode_override: Option<SessionMode>parameter (all existing call sites passNone).send_message_with_session_mode— used exclusively by trigger dispatch to plumb per-trigger overrides without changing public API surface.send_message_fullandexecute_llm_agent:session_mode>Persistent(default).SessionMode::New→SessionId::new()(fresh UUID each time).publish_eventnow iteratesVec<TriggerMatch>and callssend_message_with_session_mode.Wizard (
librefang-kernel/src/wizard.rs)session_mode: SessionMode::default()on generated manifests.Docs
AGENTS.md: documents thesession_modefield and per-trigger overrides.CHANGELOG.md: added under[Unreleased].CLAUDE.md: architecture note on session resolution.Scope
Intentionally does not:
session_modeat runtime — it's a manifest/TOML field, changed by editingagent.tomland reloading.AgentManifestand the execution pipeline, sosession_modeworks automatically.session_mode.Test plan
TriggerMatchfield access and passcargo clippy --workspace --all-targets -- -D warningscleancargo fmt --checkcleansession_mode = "new", verify each cron/trigger invocation starts a fresh session (new session ID in logs)session_mode = "new"override on an agent that defaults to"persistent", verify override winssession_mode = "new"agent, verify channel-derived session is used (not a fresh one)