Store per-session config in SQLite and route /model and /reset through command fast-paths so channel sessions keep independent model selection across reconnects and restarts.
Add runtime truthfulness modes and autonomy-level tool gating with audit metadata for overrides/denials.
Wire policy through prompt assembly, tool execution context, and daemon/gateway agent paths; update tests and planning state for Phase 3 PR #2 completion.
- Add session_config SQLite table for per-session settings
- Update routing to support session override → agent config → global default resolution chain
- Upgrade WebChat SessionBridge from NativeAgent to AgentOrchestrator
- Add /model, /local, /cloud commands to Telegram adapter
- Add /model command to WebChat gateway handlers
- Clear session overrides on /reset command
- Pass memoryStore and config through to SessionBridge
- Add comprehensive tests for all new functionality
Fixes model persistence bug where TUI model changes didn't affect WebChat/Telegram sessions. Now:
- TUI /model sets global default (persists across restarts, affects all new sessions)
- WebChat/Telegram /model sets session override (only that conversation, cleared on /reset)
- WebChat sessions gain AgentOrchestrator features (delegation, compaction, memory)
- Add curly braces to all if/else/for/while statements
- Fix indentation and trailing spaces
- Auto-fixed 372 linting errors using eslint --fix
- Remaining issues are warnings only (non-null assertions, explicit any types)
OpenAI-compatible providers return 'stop' and 'tool_calls' as finish_reason
values, but Flynn's agent loop expects Anthropic-style 'end_turn' and
'tool_use'. This caused the agent to exit the tool loop prematurely when
falling back to GitHub Copilot (due to Anthropic API quota exhaustion).
- openai.ts: Map 'stop' → 'end_turn', 'length' → 'max_tokens', tool_calls
with actual tools → 'tool_use', tool_calls without tools → 'end_turn'
- github.ts: Handle edge case where finish_reason is 'tool_calls' but no
tools were parsed
- agent.ts: Accept both 'tool_use' and 'tool_calls' as valid stop reasons
(belt-and-suspenders), extract toolCalls to local variable for TS narrowing
- openai.test.ts: Update expectations to match new normalized values
- agent.ts: track consecutive calls to the same tool (ignoring args) and
inject a nudge after 4 repeats telling the model to summarize and respond,
preventing local models from endlessly retrying searches with slight
query variations
- agent.ts: wrap the entire tool loop iteration in try-catch so model/network
errors don't crash the daemon — returns a descriptive error message instead
- Tests for both: nudge triggers after 4 same-tool calls, error recovery
persists to history
Local LLMs often get stuck calling the same tool repeatedly because they
lack the sophistication to synthesize results. The agent loop had no
safeguard — it re-executed whatever the model requested up to 10 times.
Add fingerprint-based loop detection: if the same tool+args combination
repeats 3 consecutive times, break the loop and return the last results.
Also add agents.max_iterations to the config schema so the iteration
limit is user-configurable (default: 10).
Stale session history can cause the model to follow old "I can't do
that" patterns even when new tools are available. NativeAgent now tracks
a tool fingerprint and appends a system prompt note listing current
tools when the inventory changes, resetting on session reset.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Five additive features with no breaking changes:
- Tool groups: group:fs, group:runtime, group:web, group:memory syntactic
sugar for allow/deny lists in tool policy config
- Typing indicators: Discord sendTyping() and WhatsApp sendStateTyping()
on message receipt for better UX feedback
- Session pruning: TTL-based auto-cleanup via sessions.ttl config with
hourly daemon timer and SQLite GROUP BY pruning
- /verbose command: TUI command parser toggle for raw streaming display
- !!think prefix: per-message extended thinking mode wired through
Anthropic (budget_tokens), OpenAI/GitHub (reasoning_effort), and
Gemini (thinkingConfig) providers
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Add 8 new agent-callable tools (sessions.list/history/create/delete,
agents.list, message.send, cron.list/trigger) and sanitize tool names
at the API boundary (dots → underscores) to comply with Anthropic's
`^[a-zA-Z0-9_-]{1,128}` requirement. Reverse-maps sanitized names
back to internal names for hook callbacks and tool execution.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Introduces OutboundAttachment type on OutboundMessage, an
OutboundAttachmentCollector (push/drain pattern), and a media.send
tool that queues files for outbound delivery. Each channel adapter
(Telegram, Discord, Slack, WhatsApp) sends attachments after the
text reply. Includes 15 tests for collector and tool.
Widen Message.content from string to string | MessageContentPart[] to support
multimodal content. Add Attachment type to channel layer, media conversion
utilities, and image extraction to all channel adapters (Telegram, Discord,
Slack, WhatsApp). Update all model clients (Anthropic, OpenAI, Gemini, Bedrock)
to convert structured content to provider-specific formats. Fix downstream
consumers (tokens, compaction, TUI, local models) to handle the widened type
via getMessageText() helper.