Documentation
¶
Overview ¶
Package copilot – abort.go implements abort trigger detection for stopping active agent runs using natural language phrases in multiple languages.
Package copilot – access.go implements the access control system for DevClaw.
The bot does NOT respond to everyone by default. Only explicitly authorized contacts (or groups) can interact with the assistant.
Access levels:
- owner: Full control, can manage admins, workspaces, and settings
- admin: Can manage users, create workspaces, and use admin commands
- user: Can interact with the assistant normally
- blocked: Explicitly blocked, never receives a response
Default policy: "deny" — unknown contacts are silently ignored.
Package copilot – agent.go implements the agentic loop that orchestrates LLM calls with tool execution. The agent iterates: call LLM → if tool_calls → execute tools → append results → call LLM again, until the LLM produces a final text response with no tool calls.
Architecture:
- No fixed max turns — the loop runs until the LLM stops calling tools.
- Single run timeout (default: 600s = 10min) controls the whole run.
- Per-LLM-call safety timeout (5min) prevents individual hung requests.
- Reflection nudge every 15 turns for budget awareness.
- Auto-compaction on context overflow (up to 3 attempts).
Package copilot – agent_router.go implements agent routing based on channel, user, or group. This allows different agents with different models, instructions, and skill sets to handle messages from different sources.
Package copilot – agent_tools.go registers the agent_manage dispatcher tool for creating and managing agents (workspaces) via the AI.
Package copilot – apply_patch.go implements a robust multi-file patch applicator. This is based on the OpenClaw apply_patch tool, allowing the agent to make surgical edits to files without having to rewrite the entire file or use fragile bash/sed commands.
Package copilot implements the main orchestrator for DevClaw. Coordinates channels, skills, scheduler, access control, workspaces, and security to process user messages and generate LLM responses.
Package copilot – block_streamer.go implements progressive message delivery for channels. Instead of waiting for the full LLM response, text is coalesced into blocks and sent as they become available, giving the user near-real-time feedback as blocks become available.
Coalescing rules:
- Wait until at least MinChars are accumulated.
- Flush when MaxChars is reached or the idle timer fires.
- Always try to flush at a natural boundary (newline, sentence end).
Package copilot – browser_act.go implements unified browser actions for browser automation.
Package copilot – browser_snapshot.go implements accessibility tree snapshots and role reference generation for browser automation.
The accessibility tree provides a structured representation of the page that's easier for AI agents to understand and interact with. Role references (e1, e2, ...) provide stable element identifiers across multiple snapshots.
Package copilot – browser_tabs.go implements tab management tools for browser automation.
Package copilot – browser_tool.go implements a browser automation tool using Chrome DevTools Protocol (CDP). This allows the agent to navigate web pages, take screenshots, extract content, click elements, and fill forms.
Architecture:
Agent ──browser_navigate──▶ BrowserManager ──CDP──▶ Chrome/Chromium Agent ──browser_screenshot──▶ BrowserManager ──CDP──▶ Screenshot → base64 Agent ──browser_content──▶ BrowserManager ──CDP──▶ DOM → text Agent ──browser_click──▶ BrowserManager ──CDP──▶ Click element
The browser is launched lazily on first use and kept alive for the session. A configurable timeout prevents runaway browser sessions.
Package copilot – builtin_skills.go provides embedded skills that are included in the binary and loaded into the system prompt.
Package copilot – canvas_host.go implements an interactive HTML/JS canvas host. Allows the agent to generate HTML/JS content and serve it via a temporary local HTTP server for the user to interact with.
Use cases:
- Data visualization (charts, graphs)
- Interactive prototypes
- Mini-apps (calculators, forms)
- Rich output that exceeds chat formatting
Architecture:
Agent ──canvas_create──▶ CanvasHost ──HTTP──▶ user browser Agent ──canvas_update──▶ CanvasHost (live-reload via SSE) Agent ──canvas_list──▶ list of active canvases
Package copilot – codebase_tools.go implements codebase analysis tools: file tree indexing, code search (ripgrep), symbol extraction, and Cursor rules generator.
Package copilot – commands.go implements admin commands that can be executed via chat messages (WhatsApp, Discord, etc.).
Commands are prefixed with "/" and only available to admins/owners:
/allow <phone> - Grant user access /block <phone> - Block a user /unblock <phone> - Unblock a user /revoke <phone> - Revoke user access /admin <phone> - Promote user to admin /users - List all authorized users /ws create <id> <name> - Create a workspace /ws delete <id> - Delete a workspace /ws assign <phone> <id> - Assign user to workspace /ws list - List all workspaces /ws info [id] - Show workspace details /ws set <key> <value> - Update current workspace setting /group allow - Allow current group /group block - Block current group /group assign <ws_id> - Assign current group to workspace /skills list - List installed skills /skills defaults - List available default skills /skills install <n|all> - Install default skills /status - Show bot status /help - Show available commands
Package copilot – compaction_pipeline.go implements a multi-strategy context compaction pipeline that proactively manages context window usage. Instead of waiting for overflow errors, the pipeline monitors context pressure and applies increasingly aggressive compaction strategies as usage grows.
Levels (cheapest → most expensive):
Collapse (70%) → Truncate oversized tool results in-place MicroCompact (80%) → Clear old tool result contents with placeholder AutoCompact (93%) → LLM-based summarization of conversation history MemoryCompact (97%)→ Extract memories + summarize (preserves learnings)
Package copilot – compaction_safeguard.go provides safeguards for the context compaction process to ensure critical information is preserved when the conversation is summarized to free context window space.
Package copilot – config.go defines all configuration structures for the DevClaw Copilot assistant.
Package copilot – config_watcher.go polls config.yaml for changes and triggers hot-reload of safe-to-update fields without restarting the daemon.
Package copilot – context_engine.go defines the pluggable ContextEngine interface. A ContextEngine provides additional context layers that are injected into the system prompt alongside the core prompt composition.
The LegacyContextEngine wraps the existing PromptComposer behavior, making it possible to swap in alternative engines (RAG, vector search, code indexing, etc.) without modifying the prompt pipeline.
Package copilot — context_router.go routes incoming messages to the right palace wing based on (channel, external_id) context.
Sprint 1 (v1.18.0), per ADR-001 + ADR-007-v2:
When a message arrives from a channel (telegram, whatsapp, cli, mcp, ...), the context router decides which wing the resulting memory should be associated with. The decision uses a three-tier lookup:
EXPLICIT: the user (or a previous heuristic pass) mapped this (channel, external_id) pair to a wing in the channel_wing_map table. Confidence is whatever was recorded at mapping time (usually 1.0 for manual entries, 0.5-0.8 for heuristic ones).
HEURISTIC: no explicit mapping exists. The router guesses a wing based on user-configured patterns (HierarchyConfig.Heuristics). The binary ships zero defaults — all heuristics are opt-in via YAML. Confidence is 0.7 (constant). The guess is then persisted so subsequent messages skip straight to tier 1.
DEFAULT: neither explicit nor heuristic. Returns an empty wing, which propagates to wing=NULL in storage. This is a first-class citizen per ADR-006: legacy and default-off behavior both live here.
Retrocompat: the router NEVER returns an error. Every resolution path has a graceful fallback. Callers never need to handle "routing failed" — the worst case is a default (empty) wing which matches v1.17.0 behavior.
Feature flag: this router is safe to instantiate regardless of the palace-aware flag state. When the flag is off, callers simply don't invoke Resolve — the router sits idle. When on, Resolve is called at the start of each turn for each incoming message.
Package copilot – context_window_guard.go provides pre-run context window validation to prevent agent runs from starting with models that have insufficient context capacity.
Package copilot – coordinator.go implements a structured multi-agent coordination protocol with four phases:
Research → parallel read-only workers gather information Synthesis → coordinator analyzes findings, creates specs Implementation → workers execute specs (write operations) Verification → workers test and validate changes
Each phase restricts worker tools to prevent unintended side effects (e.g., research workers cannot write files). This ensures safe parallel execution and clear separation of concerns.
Implements structured multi-agent coordination for complex tasks.
Package copilot – daemon_manager.go implements a process manager that lets the agent start, monitor, and control long-running background processes (dev servers, watchers, database engines, etc.) with ring-buffer output capture and health checking.
Package copilot – db.go provides the central SQLite database for DevClaw. A single devclaw.db file holds scheduler jobs, session history/meta/facts, and the audit log. The memory.db (FTS5/embeddings) and whatsapp.db (whatsmeow session) remain as separate databases.
Package copilot – db_hub_tools.go implements database hub management tools. These tools use the native Database Hub with Go drivers for better performance than the CLI-based db_tools.go tools.
Package copilot – db_migrate.go handles one-time migration of legacy JSON/JSONL/text data to the central devclaw.db SQLite database. After a successful migration, the old files are renamed to .bak.
Package copilot – db_tools.go implements database tools for querying PostgreSQL, MySQL, and SQLite databases. Uses CLI clients (psql, mysql, sqlite3) to avoid heavy driver dependencies.
Package copilot – destructive_tracker.go implements rate limiting and batch detection for destructive tools to prevent accidental mass deletions.
Package copilot – dev_utils.go implements developer utility tools: JSON formatting, JWT decoding, regex testing, base64 encode/decode, hashing, UUID generation, URL parsing, timestamp conversion, etc.
Package copilot – directives.go parses inline directives embedded in message bodies. Unlike standalone commands (e.g., "/think high"), inline directives can appear alongside regular text: "explain this /model gpt-4o /think high". This aligns with OpenClaw's inline directive system.
Package copilot – docker_tools.go implements native Docker tools for container management, image operations, and compose integration.
Package copilot – dream.go implements the Dream System, a background consolidation process that runs when the daemon is idle. It analyzes accumulated memories, detects contradictions, merges duplicates, and produces consolidated summaries — similar to how sleep consolidates learning in biological systems.
The Dream System uses a 3-gate trigger:
- Gate 1: Minimum time since last dream (default: 6 hours)
- Gate 2: Minimum sessions since last dream (default: 2)
- Gate 3: File lock to prevent concurrent dreams
Phases: Orient → Gather → Consolidate → Apply
Package copilot – env_tools.go implements system information and network diagnostic tools: port scanning, environment info, and process listing.
Package copilot – events.go implements an in-memory pub/sub event bus for agent lifecycle events. Replaces channel-based buffering with fan-out to multiple listeners, each receiving events via direct function call.
Event streams:
- "lifecycle": run_start, run_end, abort
- "assistant": delta (text tokens), thinking_start, thinking_delta, thinking_end
- "tool": tool_use, tool_result
- "error": agent errors, LLM errors
Package copilot – exec_analysis.go implements command risk analysis for bash/exec tool calls. Commands are categorized by risk level and appropriate actions are taken (allow, log, require approval, deny).
Package copilot – exec_approval.go implements interactive approval for tools that require confirmation before execution (e.g. bash, ssh, write_file).
Package copilot – failover_coordinator.go provides a unified coordinator for profile authentication and model failover. This replaces the fragmented approach of 3 independent systems (profile cooldown, model failover, LLM inline cooldown) with a single consistent error classification and response strategy.
Package copilot – git_tools.go implements native Git tools that provide structured JSON output for the agent, enabling better decision-making without parsing raw text. Uses os/exec to call git directly.
Package copilot – group_chat.go implements enhanced group chat features Activation modes, intro messages, context injection, participant tracking, and quiet hours.
Package copilot – group_policy.go implements group-specific policies including activation modes, quiet hours, and access control for groups.
Package copilot – heartbeat.go implements a periodic heartbeat that checks for pending scheduled jobs, reads HEARTBEAT.md for custom checklists, and triggers proactive agent turns that can send messages to channels.
Package copilot – hooks.go implements a lifecycle hook system. Hooks allow external code to observe and optionally modify agent behavior at well-defined points in the lifecycle.
Hook events include:
SessionStart — A new session is created or restored. SessionEnd — A session is about to be pruned/deleted. UserPromptSubmit — User message received, before processing. PreToolUse — Before a tool is called (can block/modify). PostToolUse — After a tool returns (observe/log). AgentStart — Agent loop is about to begin. AgentStop — Agent loop finished (normal or error). SubagentStart — A subagent has been spawned. SubagentStop — A subagent has finished. PreCompact — Before session compaction. PostCompact — After session compaction. MemorySave — A memory was saved. MemoryRecall — Memories were recalled for prompt. Notification — An outbound notification/message is being sent. Heartbeat — Periodic heartbeat tick. Error — An unrecoverable error occurred.
Package copilot – ide_extensions.go provides configuration generators for IDE extensions: VSCode, JetBrains, and Neovim. These generate the necessary config files for connecting to DevClaw's MCP server.
Package copilot – identity.go resolves the assistant's identity from multiple sources: agent profile, IDENTITY.md file, config, or defaults.
Package copilot – keyring.go provides secure credential storage using the operating system's native keyring (Linux: Secret Service/GNOME Keyring, macOS: Keychain, Windows: Credential Manager).
Priority for resolving secrets:
- Encrypted vault (.devclaw.vault — AES-256-GCM + Argon2, requires master password)
- OS keyring (encrypted by the OS, requires user session)
- Environment variable (DEVCLAW_API_KEY, OPENAI_API_KEY, etc.)
- .env file (loaded by godotenv)
- config.yaml value (least secure — plaintext on disk)
Package copilot – lanes.go implements a lane-based concurrency system. Each lane has its own queue and concurrency limit, preventing contention between different types of work (sessions, cron, subagents).
Lane types:
- session:{id} — one lane per session, maxConcurrent=1 (serialized)
- global — shared lane for cross-session work, maxConcurrent=3
- cron — scheduled jobs, maxConcurrent=2
- subagent — subagent runs, maxConcurrent=8
Package copilot – lcm.go is the coordinator for the Lossless Compaction Module. It ties together store, compactor, assembler, and retrieval into a single engine.
Package copilot – lcm_assembler.go builds the model's context window from the LCM DAG (root summaries + fresh tail messages), with budget-aware eviction.
Package copilot – lcm_compaction.go implements the DAG-based compaction engine for the Lossless Compaction Module. Two passes: leaf (messages → summaries) and condensed (summaries → higher-level summaries), cascading until stable.
Package copilot – lcm_retrieval.go provides the retrieval operations for the LCM tool: grep (FTS + regex), describe (inspect DAG), expand (recover messages).
Package copilot – lcm_store.go provides SQLite CRUD operations for the Lossless Compaction Module (LCM). All message and summary data lives in the central devclaw.db database.
Package copilot – lcm_tools.go registers the `lcm` dispatcher tool with three actions: grep, describe, expand. Follows the same pattern as RegisterSessionsDispatcher in session_tools.go.
Package copilot – legacy_aliases.go registers dispatcher tools that route to individual tools based on the "action" parameter. The memory, vault, and scheduler dispatchers are the PRIMARY visible tools; individual tools are hidden but callable. skill_manage remains hidden.
Package copilot – link_understanding.go extracts URLs from messages and enriches them with readable content before passing to the agent. This aligns with OpenClaw's link understanding pipeline.
Package copilot – llm.go implements the LLM client for chat completions with function calling / tool use support. Uses the OpenAI-compatible API format, which works with OpenAI, Anthropic proxies, GLM (api.z.ai), and any compatible endpoint.
Package copilot – loader.go handles loading configuration from YAML files with secure credential management via environment variables and .env files.
Package copilot – maintenance_manager.go manages maintenance mode state.
Package copilot – markdown.go converts standard Markdown to channel-specific formats. WhatsApp supports a limited subset; other channels may get plain text or passthrough.
Package copilot – mcp_manager.go implements MCP (Model Context Protocol) server management including listing, adding, editing, removing, and testing MCP connections.
Package copilot – mcp_tools.go bridges MCP (Model Context Protocol) servers with the ToolExecutor, allowing the LLM to call tools exposed by external MCP servers as if they were native DevClaw tools.
Workflow:
- For each enabled+auto_start MCP server, launch the process (stdio) or connect to the endpoint (SSE/HTTP).
- Send tools/list to discover available tools.
- Register each tool in the ToolExecutor with a handler that forwards tool calls via MCP's tools/call JSON-RPC.
- On shutdown, send a graceful close and terminate processes.
Currently supports stdio transport (most common for MCP).
Package copilot – media_enrichment.go handles extraction of content from documents (PDF, DOCX, TXT) and video frames for enriching agent prompts.
Package copilot – media_registry.go provides a multi-provider registry for media processing (vision and transcription) with priority-based fallback.
Package copilot – media_tools.go registers tools for image understanding (describe_image), audio transcription (transcribe_audio), and the unified send_media tool for sending images, audio, video, and documents.
Package copilot — memory_categorizer.go classifies memory content into categories (event, summary, preference, fact) using keyword patterns. Zero LLM calls — pure regex matching in PT and EN.
Package copilot – memory_extractor.go extracts structured memories from conversation history before context compaction. This preserves valuable information (decisions, preferences, facts, learnings) that would otherwise be lost when messages are summarized or discarded.
Pattern: extract valuable information first, then compact safely knowing nothing important is lost.
Package copilot – memory_hardening.go implements security hardening for memory content that is injected into LLM prompts. Memories are treated as untrusted historical data and sanitized to prevent prompt injection.
Security pattern:
- Escape HTML entities in memory content
- Wrap memories in <relevant-memories> tags with untrusted data warning
- Detect and reject auto-capture of prompt injection patterns
- Only capture from user-role messages
Package copilot — memory_hierarchy_config.go holds the Sprint 1 (v1.18.0) palace-aware feature flag config and observability scaffolding.
The config lives in its own file so config.go stays focused on core memory configuration. One line in config.go's MemoryConfig struct pulls HierarchyConfig in.
Metric emission follows the devclaw convention of structured slog lines with a known prefix. A log aggregator (fluent-bit, vector, loki) can scrape these into Prometheus time series without DevClaw needing a direct Prometheus dependency.
Metric naming convention (dot-separated, matching ADR-008):
memory.context_router.confidence histogram bucket counter
memory.search.wing_filter_usage counter labeled {on, off, fallback}
memory.hierarchy.enabled gauge (0 or 1)
memory.layer_tokens histogram labeled {layer=L0|L1|L2}
All metrics are emitted via slog at INFO level with a "metric" attribute equal to the metric name and a "value" attribute equal to the data point. Zero external dependencies.
Package copilot — memory_hierarchy_tools.go registers the palace-aware memory tools introduced in Sprint 1 (v1.18.0).
These tools are ADDITIVE: they extend the existing memory toolset (memory_save, memory_search, memory_list, memory_index) with five new focused tools that expose the wing/room hierarchy and the context router.
The tools are registered separately from the core memory tools so that:
- The core set continues to work when hierarchy is disabled
- Enabling/disabling hierarchy is a single call site change
- Tests can register one set without the other
Feature flag: each tool checks cfg.Enabled before doing any work. When disabled, the tool is still registered (so the LLM discovers it), but returns a helpful error explaining that the feature is off. This is better UX than hiding the tool entirely — the LLM learns the capability exists and the user can opt in.
New tools added in this file:
memory_list_wings — enumerate wings with counts memory_list_rooms — enumerate rooms inside a wing memory_get_taxonomy — full wing → rooms tree memory_wing_pin — pin (channel, chatID) → wing mapping memory_wing_unpin — remove a pinned mapping memory_wing_status — show current wing for a channel/chat
NOT added in this PR (deferred):
- memory_save wing/room params — requires rerouting markdown file path into wing subdirectories, which is a larger change. Sprint 1 PR #4+.
- memory_search wing filter — requires wing boost in hybrid fusion, which affects score semantics. Sprint 2.
- memory_wing_merge / memory_room_merge — bot commands first, see PR #4.
The deferral is intentional: PR #3 adds the taxonomy/routing primitives without touching the hot path of save/search. This keeps retrocompat airtight while delivering user-visible functionality.
Package copilot – memory_indexer.go provides background memory indexing.
Package copilot — memory_stack.go implements Sprint 2 Room 2.4's MemoryStack: the composer that assembles the layered memory system (L0 Identity + L1 Essential + L2 OnDemand) into a single prompt prefix that buildMemoryLayer prepends to the legacy L3 output.
Design principles (do not revise without an ADR):
Stack-over-legacy: the stack NEVER rewrites buildMemoryLayer. It renders a prefix that is prepended. When the stack is nil or all layers return empty, buildMemoryLayer is byte-identical to v1.18.0. This is the retrocompat gate — enforced by the golden fixture test in prompt_layers_golden_test.go.
L0-never-trimmed: the Identity layer is the user's anchor. It is ALWAYS rendered in full, even when it exceeds the total byte budget. Rationale: a 50-byte identity blurb that the user curated themselves is never the reason a prompt is over-budget, and losing it silently breaks persona continuity across turns. If the caller provides an unusually large identity file, the stack logs a WARN but still includes it.
Trim priority L2 > L1 > L0 (trim L2 first, L1 second, L0 never). L2 is ephemeral per-turn context; L1 is the per-wing story summary; L0 is the user's persona anchor.
Panic isolation: a layer that panics is caught, logged, and its contribution becomes the empty string. The remaining layers still render and the prompt is still produced. No single bad layer can prevent the assistant from answering.
Context cancellation short-circuits: a pre-cancelled context returns "" without touching any layer. This keeps the hot path responsive when the caller has already given up.
The stack has zero dependencies on the legacy memory path. It reads the three Room 2.1/2.2/2.3 layers via interfaces so tests can inject mocks that panic, sleep, or return large payloads.
Package copilot – memory_tools.go implements individual memory tools. Each tool has a focused schema with only the parameters it needs, eliminating the ambiguity of the dispatcher pattern.
Package copilot – message_queue.go handles message bursts with debouncing. When a session is already processing, incoming messages are queued and combined after a debounce period.
Package copilot – message_split.go provides splitting of long messages for channels with character limits (e.g. WhatsApp 4096).
Package copilot – metrics_collector.go provides background metrics collection.
Package copilot – model_failover.go implements automatic model failover with cooldowns and reason classification. When the primary LLM returns persistent errors, the system rotates through fallback models automatically.
Package copilot – multiuser.go implements multi-user support with user management, role-based access control, shared memory spaces, and team collaboration features.
Package copilot – ops_tools.go implements operations tools for deploy pipeline execution, server health monitoring, and tunnel management.
Package copilot – pairing.go implements the DM pairing system for secure access onboarding.
The pairing system allows admins to generate shareable tokens that new users can send to the bot to request access. Tokens can be configured for:
- Auto-approval (immediate access) or manual approval
- Expiration time
- Maximum number of uses
- Role to grant (user or admin)
- Workspace assignment
Package copilot — palace_bot_commands.go parses and handles slash commands for palace-aware memory operations directly, without invoking the LLM.
This is a pre-agent text parser: the assistant (or channel router) can call HandlePalaceBotCommand at the start of message processing. If the command is handled, the reply is returned directly and the LLM is never invoked. If the input is not a palace command, handled=false and the message continues through the normal LLM path.
Supported commands (all slash-prefixed):
/wing Show current wing for this chat /wing list List all wings with counts /wing set <name> Pin this chat to <name> /wing unset Remove the pin /wing merge <from> <to> Merge one wing into another /room Show rooms in the current chat's wing /room list [wing] List rooms (filtered by wing if given) /tree Show full palace taxonomy /palace help Show help text
Design notes:
- All commands check the HierarchyConfig.Enabled flag. When off, they reply with a "disabled" message that tells the user how to enable.
- Commands that modify state (set, unset, merge) call through the ContextRouter and SQLiteStore. Read-only commands go directly to the store.
- Responses are plain text suitable for Telegram/WhatsApp rendering. No markdown escaping needed because channels re-escape on send.
- Bot commands never wait for LLM provider I/O, so they're cheap and fast — good for rapid iteration on wing config.
Per Sprint 0.5 critic feedback MAJOR-5: the `/wing merge` command MUST ship in Sprint 1 (was originally planned for Sprint 4 WebUI) because users in Telegram/WhatsApp have no other way to fix wing duplicates.
Package copilot – product_tools.go implements product management tools: project management API integration (Jira, Linear), sprint reporting, documentation sync (Notion/Confluence), and DORA metrics calculation.
Package copilot – project.go implements the ProjectManager for managing development projects. Provides project registration, activation, auto-detection of language/framework, and per-session project context.
A "project" maps to a filesystem directory (typically a git repo root) with associated metadata like language, framework, build/test/lint commands, and MCP server configurations.
Package copilot – project_adapter.go provides an adapter that bridges copilot.ProjectManager to skills.ProjectProvider, breaking the import cycle between the two packages.
The adapter converts between copilot.Project and skills.ProjectInfo structs which have the same shape but live in different packages.
Package copilot – prompt_layers.go implements the layered system prompt Each layer has a priority and contributes to the final prompt that is sent to the LLM as the system message.
Bootstrap files (SOUL.md, AGENTS.md, IDENTITY.md, USER.md, TOOLS.md) are loaded from the workspace root and injected as "Project Context". If SOUL.md is present, the agent is instructed to embody its persona.
Package copilot – provider_discovery.go implements optional, non-blocking discovery of locally-hosted LLM providers (Ollama, vLLM).
During startup, the assistant can probe known endpoints to discover available models and their context window sizes. This information supplements the static getModelContextWindowByName() lookup, allowing DevClaw to use correct settings for custom or fine-tuned local models.
Package copilot – queryloop.go defines the Phase-based query loop architecture. This extracts the conceptual phases from the monolithic agent.go Run() method into composable, testable units.
The existing Run() method continues to work unchanged. This module provides the interfaces and orchestrator for incremental migration to phased execution.
Phases:
Prepare → build messages, resolve tools, load context APICall → call LLM with streaming/non-streaming ToolExec → execute tool calls from LLM response Decision → decide: tool_use → loop back, text → proceed to stop StopCheck → verify completion before returning
Package copilot – queue_modes.go implements configurable queue modes that control how the agent handles incoming messages while a session is busy. Supports: collect, steer, followup, interrupt, steer-backlog.
Package copilot – scheduler_tools.go implements scheduler tools for managing scheduled tasks and reminders: scheduler_add, scheduler_list, scheduler_remove, and scheduler_search.
session.go implementa o gerenciamento de sessões isoladas por chat/grupo. Cada grupo ou DM possui sua própria sessão com memória, skills ativas e configurações independentes.
Package copilot – session_lock.go implements cross-process session write locks using advisory file locking. This prevents two DevClaw processes from writing to the same session simultaneously, which could corrupt session state.
Architecture:
- Lock file: <sessions_dir>/<session_id>.lock
- Contains JSON: {"pid": <PID>, "acquired_at": "<RFC3339>"}
- Uses syscall.Flock for advisory locking (safe on Linux/macOS)
- Watchdog goroutine refreshes the lock file mtime every 60s
- Stale detection: locks older than 30 min are considered abandoned
session_persistence.go implements disk persistence for sessions using JSONL format.
Package copilot – session_persistence_sqlite.go implements session persistence backed by the central devclaw.db SQLite database. It is a drop-in replacement for the JSONL-based SessionPersistence.
Package copilot – session_reaper.go periodically removes stale persisted sessions that haven't been active within a configurable time window. This prevents unbounded storage growth from long-lived deployments.
Package copilot – session_tools.go implements the sessions dispatcher tool. Uses dispatcher pattern to consolidate 4 session tools into 1.
Package copilot - settings.go manages application settings stored separately from config. This includes tool profiles and other infrequently-changed settings.
Package copilot – skill_creator.go implements tools that allow the agent to create, edit, and manage skills via chat. Skills are created as ClawdHub-compatible SKILL.md files in the workspace skills directory.
The agent can use these tools to:
- Initialize a new skill with a SKILL.md template
- Edit an existing skill's instructions
- Add scripts (Python, Node, Shell) to a skill
- List installed skills
- Test a skill by executing it
Package copilot – skill_db.go provides a database system for skills. It allows skills to store structured data in a dedicated SQLite database without requiring users to know SQL or create scripts.
Each skill can have multiple tables. Table names are automatically prefixed with the skill name to ensure isolation (e.g., "crm_contacts" for skill "crm").
Package copilot – skill_db_tools.go registers individual skill database tools that allow the agent to store and retrieve structured data.
Package copilot – skill_watcher.go watches skill directories for SKILL.md changes and increments the PromptComposer's skills version to invalidate the cached skills layer. This replaces TTL-based refresh with event-driven invalidation, matching the OpenClaw chokidar pattern.
Package copilot provides startup verification for DevClaw. Checks vault, database, channels, and system dependencies.
Package copilot – stop_hooks.go implements pre-stop completion verification. Before the agent stops, these hooks analyze the conversation to detect incomplete work patterns (e.g., files edited but tests not run, code written but not compiled). If incomplete work is detected, the hook can inject a continuation message to prompt the agent to finish.
Pattern: verify completion before allowing the agent to stop, preventing premature task completion.
Package copilot – subagent.go implements a subagent system that allows the main agent to spawn independent child agents to handle tasks concurrently.
Architecture:
Main Agent ──spawn_subagent──▶ SubagentManager ──goroutine──▶ Child AgentRun
│ │
▼ ▼
SubagentRegistry (runs with own session,
tracks runs + results limited tools, separate
prompt, optional model)
Subagents:
- Run in isolated goroutines with their own session context.
- Cannot spawn nested subagents (no recursion).
- Have a configurable subset of tools (deny list applied).
- Results are collected and can be polled or waited on.
- Are announced back to the parent session when complete.
Package copilot – techops_commands.go implements administrative commands for remote operations. These commands allow operators to manage the system via chat channels without SSH access.
Package copilot – system_tools.go registers built-in tools that are always available to the agent, independent of skills. These tools provide core capabilities like shell execution, file I/O, memory operations, and scheduling.
Package copilot – techops_types.go provides data structures for TechOps commands.
Package copilot – tailscale.go implements Tailscale Serve/Funnel integration for secure remote access to DevClaw's web services.
Tailscale Serve proxies HTTPS traffic from the Tailscale network to a local port. Tailscale Funnel extends this to the public internet with automatic TLS certificates.
Provides secure remote access without manual port forwarding, dynamic DNS, or certificate management.
Architecture:
Internet ──HTTPS──▶ Tailscale Funnel ──▶ Local DevClaw (e.g. :8085) Tailnet ──HTTPS──▶ Tailscale Serve ──▶ Local DevClaw (e.g. :8085)
Package copilot – testing_tools.go implements a testing engine that wraps common test runners and provides tools for running tests, API testing, and generating test reports.
Package copilot – tool_executor.go manages a registry of callable tools and dispatches tool calls from the LLM to the appropriate handlers. Tools can be registered from skills, system built-ins, or plugins.
Package copilot – tool_guard.go implements a security layer that controls which tools can be used, by whom, and under what conditions.
Security features:
- Tool-level access control (owner/admin/user)
- Destructive command detection and blocking
- Sensitive path protection
- SSH host allowlist
- Full audit logging of every tool execution
- Configurable confirmation for dangerous operations
Package copilot – tool_guard_audit_sqlite.go provides a SQLite-backed audit logger for the ToolGuard. It writes tool execution records to the audit_log table in the central devclaw.db and auto-prunes entries older than 30 days.
Package copilot – tool_loop_detection.go detects when the agent enters a tool call loop (repeating the same call with no progress) and triggers circuit breakers to prevent infinite loops.
Four detectors:
- Generic repeat: same tool+args hash repeated N times
- Ping-pong: alternating between two tool calls
- Known no-progress poll: tools that poll external state without progress
- Global circuit breaker: total no-progress calls across all patterns
Package copilot – tool_mutation.go classifies tool calls as mutating vs read-only. Aligned with OpenClaw's tool-mutation.ts pattern. Used for: - More granular error reporting (warn only on mutating tool errors) - Action fingerprinting for deduplication
Package copilot – tool_outcomes.go implements a per-turn, thread-safe log of tool execution outcomes used for structural provenance checks.
The memory layer uses this log to reject fact saves whose content echoes a tool call that failed earlier in the same turn AND for which no later successful call on the same subject has been observed. This replaces the keyword-based access-failure filter with a locale-agnostic, content-signal-free mechanism: all decisions derive from the tool error flag, ordering, and generic token overlap.
Package copilot – tool_profiles.go implements predefined tool permission profiles. Profiles simplify tool configuration by providing presets for common use cases.
Package copilot – tool_result_truncation.go provides two-layer tool result truncation to prevent context overflow while preserving important content.
Layer 1 (per-result): Smart head+tail truncation that detects error summaries, JSON closing brackets, and other important content at the end of tool results.
Layer 2 (pre-LLM context guard): Caps individual tool results and compacts oldest tool results when total content exceeds the context budget.
Package copilot – transcript_policy.go defines per-provider transcript sanitization policies. Different LLM providers have different requirements for message format, turn ordering, and content types. This policy system ensures that the conversation transcript is compatible with each provider before sending.
Package copilot – typing_controller.go provides a lifecycle-aware typing indicator controller that replaces the simple goroutine+ticker pattern.
State machine:
Started → Active → RunComplete → DispatchIdle → Sealed
- Started: Controller created, not yet sending.
- Active: Ticker running, sending typing indicators at regular intervals.
- RunComplete: Agent execution finished; if block streamer is still dispatching buffered output we keep typing active for a grace period.
- DispatchIdle: Block streamer has finished; typing stops but can be restarted if a followup run begins within the grace window.
- Sealed: Terminal state; no further typing will be sent.
The controller also enforces a TTL so a stuck agent cannot send typing indicators indefinitely.
Package copilot – usage_tracker.go records LLM token usage and estimated costs per session and globally.
Package copilot – vault.go provides encrypted credential storage using AES-256-GCM with Argon2id key derivation. Secrets are stored in a local file (.devclaw.vault) that is unreadable without the master password.
Even if someone has filesystem access, the vault contents remain encrypted. The master password is never stored — only a derived key is used in memory.
Package copilot – vault_tools.go implements individual vault tools. Each tool has a focused schema with only the parameters it needs.
Package copilot – web_fetch_readability.go provides HTML-to-text conversion and an in-memory LRU cache for web_fetch results.
Package copilot – webhooks.go implements external webhook support for hooks. Webhooks allow sending hook events to external HTTP endpoints.
Package copilot – workspace.go implements the multi-tenant workspace system.
Workspaces (also called "profiles") allow multiple people to use the same WhatsApp number with completely isolated contexts:
- Each workspace has its own system prompt, skills, model, and language
- Each workspace has its own session store (isolated conversation memory)
- A workspace can be assigned to specific users (JIDs) or groups
- One user can belong to one workspace at a time
- There is always a "main" workspace for unassigned users
Example use cases:
- Personal workspace: your own assistant with custom instructions
- Team workspace: shared context for a project team
- Client workspace: different personality/language per client
- Testing workspace: experimental settings without affecting production
Package copilot – workspace_containment.go implements workspace path containment and symlink escape protection for file operations.
All file tools (read_file, write_file, edit_file, apply_patch) must call AssertSandboxPath before performing any I/O to ensure the resolved path is within the workspace root.
Index ¶
- Constants
- Variables
- func ApplyTranscriptPolicy(messages []chatMessage, policy TranscriptPolicy) []chatMessage
- func AuditSecrets(cfg *Config, logger *slog.Logger)
- func CallerJIDFromContext(ctx context.Context) string
- func CategorizeToolNames(names []string) map[string][]string
- func CategorizeTools(tools []ToolDefinition) map[string][]ToolDefinition
- func CheckSkillSetup(skill skills.Skill, vault skills.VaultReader) (*skills.SetupStatus, error)
- func CollapseToolResults(messages []chatMessage, maxChars int) int
- func ContextWithAgentRun(ctx context.Context, a *AgentRun) context.Context
- func ContextWithCaller(ctx context.Context, level AccessLevel, jid string) context.Context
- func ContextWithDelivery(ctx context.Context, channel, chatID string) context.Context
- func ContextWithFastMode(ctx context.Context, fast bool) context.Context
- func ContextWithMediaEmitter(ctx context.Context, fn MediaEmitter) context.Context
- func ContextWithMessageID(ctx context.Context, msgID string) context.Context
- func ContextWithProgressSender(ctx context.Context, fn ProgressSender) context.Context
- func ContextWithSession(ctx context.Context, sessionID string) context.Context
- func ContextWithSpawnDepth(ctx context.Context, depth int) context.Context
- func ContextWithToolOutcomeLog(ctx context.Context, log *ToolOutcomeLog) context.Context
- func ContextWithToolOverlay(ctx context.Context, overlay *ToolOverlay) context.Context
- func ContextWithToolProfile(ctx context.Context, profile *ToolProfile) context.Context
- func ContextWithVaultReader(ctx context.Context, vr skills.VaultReader) context.Context
- func ContextWithWorkspaceID(ctx context.Context, wsID string) context.Context
- func DeleteKeyring(key string) error
- func DetectInjectionPattern(text string) bool
- func EmitHierarchyEnabled(logger *slog.Logger, enabled bool)
- func EstimateTokens(s string) int
- func ExpandProfileList(items []string, allTools []string) []string
- func ExpandToolGroups(names []string) []string
- func ExtractLinksFromMessage(body string, maxLinks int) []string
- func ExtractReadableText(r io.Reader) (title string, text string)
- func ExtractTokenFromMessage(content string) string
- func FindConfigFile() string
- func FormatAbortReply(stoppedSubagents int) string
- func FormatCollectedMessages(msgs []*channels.IncomingMessage) string
- func FormatForChannel(text, channel string) string
- func FormatForPlainText(text string) string
- func FormatForSlack(text string) string
- func FormatForTelegram(text string) string
- func FormatForWhatsApp(text string) string
- func FormatIdentityMd(id *IdentityConfig) string
- func FormatIncompleteWorkMessage(items []IncompleteWork) string
- func FormatLinkResults(results []LinkResult) string
- func FormatMemoriesForStorage(memories []ExtractedMemory, sessionID string) string
- func FormatSetupPrompt(skillName string, status *skills.SetupStatus) string
- func FormatToolNamesForPrompt(names []string) string
- func FormatToolsForPrompt(tools []ToolDefinition, maxDescLen int) string
- func GenerateSummaryID(content string, ts time.Time) string
- func GetDeliveryTarget(ctx context.Context) (channel, chatID string)
- func GetKeyring(key string) string
- func GetProviderKeyName(provider string) string
- func GuardToolResultContext(messages []chatMessage, contextWindowTokens int) []chatMessage
- func HasAbortPrefix(text string) bool
- func HasImportantTail(text string) bool
- func HistoryLimitForType(isGroup bool) int
- func HookEventDescription(ev HookEvent) string
- func IncClassifierPass()
- func IncContextRouterDefault()
- func IncContextRouterDisabled()
- func IncContextRouterHeuristic()
- func IncContextRouterMapped()
- func IncL1CacheHit()
- func IncL1CacheMiss()
- func IncLayerTokensL0(n int)
- func IncLayerTokensL1(n int)
- func IncLayerTokensL2(n int)
- func IncSaveWingRouted()
- func IncSearchWithWingFilter()
- func IncSearchWithoutWingFilter()
- func IncToolCall(name string)
- func InferProfileForChannel(channel string) string
- func InferToolCategory(name string) string
- func IsAbortRequestText(text string) bool
- func IsAbortTrigger(text string) bool
- func IsCommand(content string) bool
- func IsEnvReference(s string) bool
- func IsLikelyContextOverflowError(errMsg string) bool
- func IsMutatingToolCall(name string, args map[string]any) bool
- func IsMutatingToolName(name string) bool
- func IsRecoverableToolError(errMsg string) bool
- func KeyringAvailable() bool
- func ListProfiles(customProfiles map[string]ToolProfile) []string
- func LooksLikeCredential(content string) bool
- func MakeSessionID(channel, chatID string) string
- func MatchesPattern(toolName, pattern string) bool
- func MessageIDFromCtx(ctx context.Context) string
- func MicroCompact(messages []chatMessage, keepLastN int) ([]chatMessage, int)
- func MicroCompactByRatio(messages []chatMessage, ratio float64, cfg ContextPruningConfig) ([]chatMessage, int)
- func MigrateKeyToKeyring(apiKey string, logger *slog.Logger) error
- func MigrateToSQLite(db *sql.DB, dataDir string, logger *slog.Logger)
- func NormalizeTelegramID(id string) string
- func OpenDatabase(path string) (*sql.DB, error)
- func ProvenanceReason(content string, outcomes []ToolOutcome) string
- func ReadPassword(prompt string) (string, error)
- func RedactCredentials(content string) string
- func RegisterAgentTools(executor *ToolExecutor, wsMgr *WorkspaceManager)
- func RegisterApplyPatchTool(executor *ToolExecutor)
- func RegisterBrowserTools(executor *ToolExecutor, browserMgr *BrowserManager, llmClient *LLMClient, ...)
- func RegisterCanvasTools(executor *ToolExecutor, canvasHost *CanvasHost, logger *slog.Logger)
- func RegisterCodebaseTools(executor *ToolExecutor)
- func RegisterDBHubTools(executor *ToolExecutor, hub *database.Hub)
- func RegisterDBTools(executor *ToolExecutor)
- func RegisterDaemonTools(executor *ToolExecutor, dm *DaemonManager)
- func RegisterDevUtilTools(executor *ToolExecutor)
- func RegisterDockerTools(executor *ToolExecutor)
- func RegisterEnvTools(executor *ToolExecutor)
- func RegisterGitTools(executor *ToolExecutor)
- func RegisterIDETools(executor *ToolExecutor)
- func RegisterKGTools(executor *ToolExecutor, sqliteStore *memory.SQLiteStore)
- func RegisterLCMDispatcher(executor *ToolExecutor, engine *LCMEngine, llm *LLMClient)
- func RegisterLegacyAliases(executor *ToolExecutor)
- func RegisterMediaTools(executor *ToolExecutor, llmClient *LLMClient, cfg *Config, logger *slog.Logger)
- func RegisterMemoryHierarchyTools(executor *ToolExecutor, cfg MemoryHierarchyDispatcherConfig)
- func RegisterMemoryTools(executor *ToolExecutor, cfg MemoryDispatcherConfig)
- func RegisterMultiUserTools(executor *ToolExecutor, um *UserManager)
- func RegisterNativeMediaTools(executor *ToolExecutor, mediaSvc *media.MediaService, ...)
- func RegisterOpsTools(executor *ToolExecutor)
- func RegisterPluginAgentDelegation(executor *ToolExecutor, registry *plugins.Registry, ...)
- func RegisterPluginManagementTools(executor *ToolExecutor, registry *plugins.Registry)
- func RegisterProductTools(executor *ToolExecutor)
- func RegisterSchedulerDispatcher(executor *ToolExecutor, sched *scheduler.Scheduler, skillDB *SkillDB)
- func RegisterSessionsDispatcher(executor *ToolExecutor, wm *WorkspaceManager)
- func RegisterSessionsYieldTool(executor *ToolExecutor)
- func RegisterSkillCreatorTools(executor *ToolExecutor, registry *skills.Registry, skillsDir string, ...)
- func RegisterSkillDBTools(executor *ToolExecutor, skillDB *SkillDB)
- func RegisterSubagentTools(executor *ToolExecutor, manager *SubagentManager, llmClient *LLMClient, ...)
- func RegisterSystemTools(executor *ToolExecutor, sandboxRunner *sandbox.Runner, ...)
- func RegisterTestingTools(executor *ToolExecutor)
- func RegisterVaultTools(executor *ToolExecutor, vault *Vault)
- func ReloadEnvFiles() (int, error)
- func RepairToolUseResultPairing(messages []chatMessage) []chatMessage
- func ResolveContextWindowTokens(configOverride int, modelName string) int
- func ResolveProfile(name string, customProfiles map[string]ToolProfile) (allow, deny []string)
- func ResolveSecrets(cfg *Config)
- func RunAsync(ctx context.Context, config AsyncToolConfig, ...)
- func SanitizeMemoryContent(content string) string
- func SanitizeToolCallID(id string, mode ToolCallIDMode) string
- func SaveConfigToFile(cfg *Config, path string) error
- func ScaffoldWorkspaceDir(wsID string, ws *Workspace) error
- func ScaledMaxRetries(profileCount int) int
- func SessionIDFromContext(ctx context.Context) string
- func SetGlobalMediaRegistry(r *MediaRegistry)
- func SkillNeedsSetup(skill skills.Skill, vault skills.VaultReader) bool
- func Slugify(name string) string
- func SpawnDepthFromContext(ctx context.Context) int
- func SplitMessage(text string, maxLen int) []string
- func StartPersistentSessionReaper(ctx context.Context, storePath string, maxAgeDays int, logger *slog.Logger)
- func StoreKeyring(key, value string) error
- func StripDangerousTags(s string) string
- func StripExternalContentBoundaries(content string) string
- func StripInternalTags(text string) string
- func StripReplyTags(text string) string
- func SynthesizeFindings(results []WorkerResult) string
- func SynthesizeProgressSummary(fragments []string) string
- func TruncateToolResult(text string, maxChars int) string
- func ValidateIdentity(id IdentityConfig) []string
- func VaultReaderFromContext(ctx context.Context) skills.VaultReader
- func WorkspaceIDFromContext(ctx context.Context) string
- func WrapExternalContent(source, content string) string
- func WrapMemoriesForPrompt(memories []string) string
- type APIConfig
- type AXNode
- type AXRole
- type AXValue
- type AccessConfig
- type AccessEntry
- type AccessLevel
- type AccessManager
- func (am *AccessManager) ApplyConfig(cfg AccessConfig)
- func (am *AccessManager) Block(jid string, blockedBy string)
- func (am *AccessManager) Check(msg *channels.IncomingMessage) CheckResult
- func (am *AccessManager) DefaultPolicy() AccessPolicy
- func (am *AccessManager) GetLevel(jid string) AccessLevel
- func (am *AccessManager) Grant(jid string, level AccessLevel, grantedBy string) error
- func (am *AccessManager) GrantGroup(groupJID string, level AccessLevel, grantedBy string) error
- func (am *AccessManager) IsAdmin(jid string) bool
- func (am *AccessManager) IsOwner(jid string) bool
- func (am *AccessManager) ListGroups() []*AccessEntry
- func (am *AccessManager) ListGroupsByChannel(suffix string) []*AccessEntry
- func (am *AccessManager) ListUsers() []*AccessEntry
- func (am *AccessManager) ListUsersByChannel(suffix string) []*AccessEntry
- func (am *AccessManager) MarkAsked(jid string)
- func (am *AccessManager) PendingMessage() string
- func (am *AccessManager) Revoke(jid string, revokedBy string)
- func (am *AccessManager) SetDefaultPolicy(policy AccessPolicy)
- func (am *AccessManager) Unblock(jid string, unblockedBy string)
- type AccessPolicy
- type ActRequest
- type ActResult
- type ActivationMode
- type AddFileHunk
- type AgentConfig
- type AgentEvent
- type AgentProfileConfig
- type AgentRouter
- func (r *AgentRouter) AddProfile(p *AgentProfileConfig)
- func (r *AgentRouter) DefaultProfileID() string
- func (r *AgentRouter) GetProfile(id string) *AgentProfileConfig
- func (r *AgentRouter) ListProfiles() []string
- func (r *AgentRouter) Route(channel string, userJID string, groupJID string) *AgentProfileConfig
- type AgentRun
- func (a *AgentRun) CollectedAssistantFragments() []string
- func (a *AgentRun) CollectedToolCalls() []ToolCallRecord
- func (a *AgentRun) Run(ctx context.Context, systemPrompt string, history []ConversationEntry, ...) (string, error)
- func (a *AgentRun) RunWithUsage(ctx context.Context, systemPrompt string, history []ConversationEntry, ...) (string, *LLMUsage, error)
- func (a *AgentRun) SetInterruptChannel(ch <-chan string)
- func (a *AgentRun) SetKG(k *kg.KG)
- func (a *AgentRun) SetLCMEngine(engine *LCMEngine, conversationID string)
- func (a *AgentRun) SetLoopDetector(d *ToolLoopDetector)
- func (a *AgentRun) SetMemoryIndexer(m *MemoryIndexer)
- func (a *AgentRun) SetModelOverride(model string)
- func (a *AgentRun) SetOnBeforeToolExec(fn func())
- func (a *AgentRun) SetOnToolResult(fn func(name string, result ToolResult))
- func (a *AgentRun) SetReactionSender(fn func(emoji string, remove bool))
- func (a *AgentRun) SetSession(s *Session)
- func (a *AgentRun) SetSessionPersistence(p SessionPersister, sessionID string)
- func (a *AgentRun) SetStreamCallback(cb StreamCallback)
- func (a *AgentRun) SetUsageRecorder(fn func(model string, usage LLMUsage))
- func (a *AgentRun) ToolSummary() string
- type AgentsConfig
- type AnnounceCallback
- type ApplyPatchResult
- type ApprovalManager
- func (m *ApprovalManager) ClearSessionTrust(sessionID string)
- func (m *ApprovalManager) Create(sessionID, callerJID, toolName string, args map[string]any) (id string, message string)
- func (m *ApprovalManager) GrantTrust(sessionID, toolName string)
- func (m *ApprovalManager) IsTrusted(sessionID, toolName string) bool
- func (m *ApprovalManager) LatestPendingForSession(sessionID string) string
- func (m *ApprovalManager) PendingCountForSession(sessionID string) int
- func (m *ApprovalManager) Request(sessionID, callerJID, toolName string, args map[string]any, ...) (bool, error)
- func (m *ApprovalManager) Resolve(id, sessionID, resolverJID string, approved bool, reason string) bool
- func (m *ApprovalManager) Wait(id string) (approved bool, err error)
- type ApprovalResult
- type Assistant
- func (a *Assistant) AccessManager() *AccessManager
- func (a *Assistant) ApplyConfigUpdate(newCfg *Config)
- func (a *Assistant) ChannelManager() *channels.Manager
- func (a *Assistant) ComposePrompt(session *Session, input string) string
- func (a *Assistant) Config() *Config
- func (a *Assistant) ExecuteAgent(ctx context.Context, systemPrompt string, session *Session, userMessage string) string
- func (a *Assistant) ForceCompactSession(session *Session) (oldLen, newLen int)
- func (a *Assistant) ForceDream(ctx context.Context)
- func (a *Assistant) GetMediaService() *media.MediaService
- func (a *Assistant) HandleCommand(msg *channels.IncomingMessage) CommandResult
- func (a *Assistant) HookManager() *HookManager
- func (a *Assistant) InjectVaultEnvVars()
- func (a *Assistant) LLMClient() *LLMClient
- func (a *Assistant) MediaConfig() MediaConfig
- func (a *Assistant) MemoryEnabled() bool
- func (a *Assistant) PluginRegistry() *plugins.Registry
- func (a *Assistant) ProfileManager() profiles.ProfileManager
- func (a *Assistant) ProjectManager() *ProjectManager
- func (a *Assistant) ProviderDiscovery() *ProviderDiscovery
- func (a *Assistant) ReloadAndInitializeSkills(ctx context.Context) (int, error)
- func (a *Assistant) SQLiteMemory() *memory.SQLiteStore
- func (a *Assistant) Scheduler() *scheduler.Scheduler
- func (a *Assistant) SchedulerEnabled() bool
- func (a *Assistant) SessionStore() *SessionStore
- func (a *Assistant) SetPluginRegistry(r *plugins.Registry)
- func (a *Assistant) SetScheduler(s *scheduler.Scheduler)
- func (a *Assistant) SetVault(v *Vault)
- func (a *Assistant) SkillRegistry() *skills.Registry
- func (a *Assistant) Start(ctx context.Context) error
- func (a *Assistant) Stop()
- func (a *Assistant) StopActiveRun(workspaceID, sessionID string) bool
- func (a *Assistant) ToolExecutor() *ToolExecutor
- func (a *Assistant) UpdateLLMClient(cfg *Config)
- func (a *Assistant) UpdateMediaConfig(media MediaConfig)
- func (a *Assistant) UsageTracker() *UsageTracker
- func (a *Assistant) Vault() *Vault
- func (a *Assistant) WorkspaceManager() *WorkspaceManager
- type AsyncCompleteCallback
- type AsyncToolConfig
- type AuditRecord
- type AuditRecordShort
- type BlockStreamConfig
- type BlockStreamer
- type BrowserConfig
- type BrowserManager
- func (bm *BrowserManager) Act(ctx context.Context, req ActRequest) (*ActResult, error)
- func (bm *BrowserManager) ClickElement(ctx context.Context, selector string) error
- func (bm *BrowserManager) CloseTab(ctx context.Context, targetID string) error
- func (bm *BrowserManager) FillInput(ctx context.Context, selector, value string) error
- func (bm *BrowserManager) FocusTab(ctx context.Context, targetID string) error
- func (bm *BrowserManager) GetAccessibilityTree(ctx context.Context) (*AXNode, error)
- func (bm *BrowserManager) GetContent(ctx context.Context) (string, error)
- func (bm *BrowserManager) GetCurrentTab(ctx context.Context) (*Tab, error)
- func (bm *BrowserManager) ListTabs(ctx context.Context) ([]Tab, error)
- func (bm *BrowserManager) Navigate(ctx context.Context, url string) error
- func (bm *BrowserManager) NavigateTab(ctx context.Context, targetID, url string) error
- func (bm *BrowserManager) OpenTab(ctx context.Context, url string) (*Tab, error)
- func (bm *BrowserManager) ResolveRefToSelector(refID string) (string, error)
- func (bm *BrowserManager) Screenshot(ctx context.Context) (string, error)
- func (bm *BrowserManager) Snapshot(ctx context.Context, opts SnapshotOptions) (*SnapshotResult, error)
- func (bm *BrowserManager) Start(ctx context.Context) error
- func (bm *BrowserManager) Stop()
- func (bm *BrowserManager) WithSSRFGuard(guard *security.SSRFGuard) *BrowserManager
- type BrowserProfile
- type BrowserSSRFPolicy
- type BudgetConfig
- type BuiltinSkill
- type BuiltinSkills
- func (bs *BuiltinSkills) All() map[string]*BuiltinSkill
- func (bs *BuiltinSkills) FormatForPrompt() string
- func (bs *BuiltinSkills) FormatSkillForPrompt(name string) string
- func (bs *BuiltinSkills) Get(name string) *BuiltinSkill
- func (bs *BuiltinSkills) Names() []string
- func (bs *BuiltinSkills) OnDemandSkills() []*BuiltinSkill
- type CDPTarget
- type Canvas
- type CanvasConfig
- type CanvasHost
- type ChannelDiagnostic
- type ChannelHealth
- type ChannelsConfig
- type CheckResult
- type CommandResult
- type CompactLevel
- type CompactThresholds
- type CompactionCircuitBreaker
- type CompactionConfig
- type CompactionEntry
- type CompactionPipeline
- func (p *CompactionPipeline) Evaluate(tokenCount, contextWindow int) ContextPressure
- func (p *CompactionPipeline) LastLevel() CompactLevel
- func (p *CompactionPipeline) RecordFailure()
- func (p *CompactionPipeline) RecordSuccess()
- func (p *CompactionPipeline) SetLastLevel(level CompactLevel)
- func (p *CompactionPipeline) ShouldCompact(level CompactLevel) bool
- type CompletionCheck
- type Config
- type ConfigHealth
- type ConfigWatcher
- type ConsoleMessage
- type ContextEngine
- type ContextEngineRegistry
- type ContextPressure
- type ContextPruningConfig
- type ContextRouter
- type ContextWindowGuardResult
- type ContextualTool
- type ConversationEntry
- type CooldownConfig
- type Coordinator
- type CoordinatorConfig
- type CoordinatorPhase
- type Daemon
- type DaemonManager
- func (dm *DaemonManager) ClearDaemon(label string) error
- func (dm *DaemonManager) GetLogs(label string, n int, filter string) (string, error)
- func (dm *DaemonManager) List() []Daemon
- func (dm *DaemonManager) PollDaemon(label string) (string, error)
- func (dm *DaemonManager) RestartDaemon(label string) (*Daemon, error)
- func (dm *DaemonManager) Shutdown()
- func (dm *DaemonManager) StartDaemon(label, command string, port int, readyPattern string) (*Daemon, error)
- func (dm *DaemonManager) StopDaemon(label string, force bool) error
- func (dm *DaemonManager) WriteToDaemon(label, input string) error
- type DatabaseConfig
- type DatabaseHealth
- type DecisionPhase
- type DedupCache
- type DeleteFileHunk
- type DeliveryScope
- type DeliveryTarget
- type DestructiveCheckResult
- type DestructiveToolsConfig
- type DestructiveTracker
- type DiagnosticsResult
- type DiscoveredModel
- type DiskStats
- type DreamConfig
- type DreamConsolidator
- func (d *DreamConsolidator) ForceRun(ctx context.Context) DreamResult
- func (d *DreamConsolidator) RecordCompaction()
- func (d *DreamConsolidator) RecordSession()
- func (d *DreamConsolidator) Run(ctx context.Context) DreamResult
- func (d *DreamConsolidator) Start(ctx context.Context)
- func (d *DreamConsolidator) State() DreamState
- func (d *DreamConsolidator) Stop()
- func (d *DreamConsolidator) WithHierarchyConfig(cfg HierarchyConfig) *DreamConsolidator
- func (d *DreamConsolidator) WithSQLiteStore(s *memory.SQLiteStore) *DreamConsolidator
- type DreamResult
- type DreamState
- type ErrEscalation
- type EscalationSignal
- type EventBus
- func (eb *EventBus) CleanupRun(runID string)
- func (eb *EventBus) Emit(event AgentEvent)
- func (eb *EventBus) EmitDelta(runID, sessionID, content string)
- func (eb *EventBus) EmitDone(runID, sessionID string, usage any)
- func (eb *EventBus) EmitError(runID, sessionID, message string)
- func (eb *EventBus) EmitThinkingDelta(runID, sessionID, content string)
- func (eb *EventBus) EmitThinkingEnd(runID, sessionID string)
- func (eb *EventBus) EmitThinkingStart(runID, sessionID string)
- func (eb *EventBus) EmitToolResult(runID, sessionID, toolName, output string, isError bool)
- func (eb *EventBus) EmitToolUse(runID, sessionID, toolName string, input any)
- func (eb *EventBus) Subscribe(fn EventListener) func()
- func (eb *EventBus) SubscribeRun(runID string, fn EventListener) func()
- type EventListener
- type ExecAnalysisConfig
- type ExecAnalysisResult
- type ExecAnalyzer
- type ExecQueueItem
- type ExportedMessage
- type ExtractedMemory
- type FailoverCoordinator
- func (fc *FailoverCoordinator) GetModelManager() *ModelFailoverManager
- func (fc *FailoverCoordinator) HasProfileManager() bool
- func (fc *FailoverCoordinator) ReportFailure(model string, profileID profiles.ProfileID, statusCode int, errMsg string) FailoverReason
- func (fc *FailoverCoordinator) ReportFailureWithCause(model string, profileID profiles.ProfileID, statusCode int, errMsg string, ...) FailoverReason
- func (fc *FailoverCoordinator) ReportSuccess(model string, profileID profiles.ProfileID)
- func (fc *FailoverCoordinator) SelectModelAndProfile(provider, modelOverride string, fallbacksOverride ...string) (model string, profileID profiles.ProfileID, apiKey string, err error)
- type FailoverReason
- type FallbackConfig
- type FormField
- type FunctionCall
- type FunctionDef
- type GatewayConfig
- type GroupConfig
- type GroupManager
- func (gm *GroupManager) BuildGroupPromptContext(chatID, botName string) string
- func (gm *GroupManager) GetContextInjection(chatID string) string
- func (gm *GroupManager) GetIntroMessage(chatID, botName, trigger string) string
- func (gm *GroupManager) GetParticipants(chatID string) []string
- func (gm *GroupManager) ShouldRespond(chatID, senderName, messageText, botName, trigger string) (bool, string)
- func (gm *GroupManager) TrackParticipant(chatID, name string)
- type GroupPolicy
- type GroupPolicyConfig
- type GroupPolicyManager
- func (m *GroupPolicyManager) GetGroupConfig(groupJID string) *GroupPolicyConfig
- func (m *GroupPolicyManager) GetWorkspace(groupJID string) string
- func (m *GroupPolicyManager) IsBlocked(groupJID string) bool
- func (m *GroupPolicyManager) IsQuietHours(cfg *GroupPolicyConfig) bool
- func (m *GroupPolicyManager) ListBlocked() []string
- func (m *GroupPolicyManager) ListGroups() []string
- func (m *GroupPolicyManager) ShouldRespond(groupJID, userJID string, content string, isReplyToBot bool, trigger string) bool
- type GroupsPolicyConfig
- type HandlerConfig
- type HealthCheckResult
- type Heartbeat
- type HeartbeatConfig
- type HierarchyConfig
- type HierarchyMetrics
- type HookAction
- type HookEvent
- type HookHandler
- type HookManager
- func (hm *HookManager) Dispatch(ctx context.Context, payload HookPayload) HookAction
- func (hm *HookManager) DispatchAsync(payload HookPayload)
- func (hm *HookManager) HasHooks(event HookEvent) bool
- func (hm *HookManager) HookCount() int
- func (hm *HookManager) ListDetailed() []HookSummary
- func (hm *HookManager) ListHooks() map[HookEvent][]string
- func (hm *HookManager) Register(hook *RegisteredHook) error
- func (hm *HookManager) SetEnabled(name string, enabled bool) bool
- func (hm *HookManager) Unregister(name string) bool
- type HookPayload
- type HookRequirements
- type HookSummary
- type HooksConfig
- type Hunk
- type HunkKind
- type IDEConfig
- type IdentityConfig
- type IncompleteWork
- type IndexConfig
- type InlineDirectives
- type KGAgentConfig
- type KGConfig
- type LCMAssembler
- type LCMCompactor
- func (c *LCMCompactor) CondensedPass(ctx context.Context, convID string, summarizeFn LCMSummarizeFn) ([]*LCMSummary, error)
- func (c *LCMCompactor) FullSweep(ctx context.Context, convID string, summarizeFn LCMSummarizeFn) ([]*LCMSummary, error)
- func (c *LCMCompactor) LeafPass(ctx context.Context, convID string, summarizeFn LCMSummarizeFn) ([]*LCMSummary, error)
- func (c *LCMCompactor) ShouldCompact(convID string, contextWindowTokens int) (bool, string)
- type LCMConfig
- type LCMContextItem
- type LCMConversation
- type LCMEngine
- func (e *LCMEngine) Assemble(ctx context.Context, convID, systemPrompt, userMessage string, tokenBudget int) ([]chatMessage, error)
- func (e *LCMEngine) Bootstrap(sessionID string, sessionHistory []ConversationEntry) (string, error)
- func (e *LCMEngine) Compact(ctx context.Context, convID string, contextWindowTokens int, ...) (bool, error)
- func (e *LCMEngine) Ingest(ctx context.Context, convID string, messages []chatMessage) error
- func (e *LCMEngine) Retrieval() *LCMRetrieval
- func (e *LCMEngine) Store() *LCMStore
- type LCMFTSResult
- type LCMFile
- type LCMMessage
- type LCMQueryFn
- type LCMRetrieval
- func (r *LCMRetrieval) Describe(convID, summaryID string) (string, error)
- func (r *LCMRetrieval) DescribeTree(convID string) (string, error)
- func (r *LCMRetrieval) Expand(convID, summaryID string, depth int) (string, error)
- func (r *LCMRetrieval) ExpandQuery(ctx context.Context, convID, query string, queryFn LCMQueryFn) (string, error)
- func (r *LCMRetrieval) Grep(convID, query string, isRegex bool, limit int) (string, error)
- type LCMStore
- func (s *LCMStore) CountUnsummarizedTokens(convID string, excludeLastN int) (int, error)
- func (s *LCMStore) DeleteMessage(id int64) error
- func (s *LCMStore) GetAllSummaries(convID string) ([]*LCMSummary, error)
- func (s *LCMStore) GetContextItems(convID string) ([]LCMContextItem, error)
- func (s *LCMStore) GetFile(id string) (*LCMFile, error)
- func (s *LCMStore) GetFreshTailMessages(convID string, count int) ([]*LCMMessage, error)
- func (s *LCMStore) GetMaxDepth(convID string) (int, error)
- func (s *LCMStore) GetMessage(id int64) (*LCMMessage, error)
- func (s *LCMStore) GetMessageRange(convID string, fromSeq, toSeq int) ([]*LCMMessage, error)
- func (s *LCMStore) GetOrCreateConversation(sessionID string) (*LCMConversation, error)
- func (s *LCMStore) GetOrphanSummaries(convID string, depth int) ([]*LCMSummary, error)
- func (s *LCMStore) GetRecentMessages(convID string, limit int) ([]*LCMMessage, error)
- func (s *LCMStore) GetRootSummaries(convID string) ([]*LCMSummary, error)
- func (s *LCMStore) GetSummary(id string) (*LCMSummary, error)
- func (s *LCMStore) GetSummaryChildren(summaryID string) ([]*LCMSummary, error)
- func (s *LCMStore) GetSummaryMessages(summaryID string) ([]*LCMMessage, error)
- func (s *LCMStore) GetSummaryParents(summaryID string) ([]*LCMSummary, error)
- func (s *LCMStore) GetUnsummarizedMessages(convID string, excludeLastN int) ([]*LCMMessage, error)
- func (s *LCMStore) IngestMessage(convID, role, content string, tokenCount int) (*LCMMessage, error)
- func (s *LCMStore) InsertFile(f *LCMFile) error
- func (s *LCMStore) InsertSummary(sum *LCMSummary) error
- func (s *LCMStore) LinkSummaryChildren(parentID string, childIDs []string) error
- func (s *LCMStore) LinkSummaryMessages(summaryID string, msgIDs []int64) error
- func (s *LCMStore) ListFiles(convID string) ([]*LCMFile, error)
- func (s *LCMStore) MessageCount(convID string) (int, error)
- func (s *LCMStore) NextSeq(convID string) (int, error)
- func (s *LCMStore) ReplaceContextItems(convID string, items []LCMContextItem) error
- func (s *LCMStore) SearchFTS(convID, query string, limit int) ([]LCMFTSResult, error)
- func (s *LCMStore) SummaryCount(convID string) (leaf, condensed int, err error)
- func (s *LCMStore) UpdateLastCompactAt(convID string) error
- type LCMSummarizeFn
- type LCMSummary
- type LLMClient
- func (c *LLMClient) Complete(ctx context.Context, systemPrompt string, history []ConversationEntry, ...) (string, error)
- func (c *LLMClient) CompleteWithFallback(ctx context.Context, messages []chatMessage, tools []ToolDefinition) (*LLMResponse, error)
- func (c *LLMClient) CompleteWithFallbackUsingModel(ctx context.Context, modelOverride string, messages []chatMessage, ...) (*LLMResponse, error)
- func (c *LLMClient) CompleteWithTools(ctx context.Context, messages []chatMessage, tools []ToolDefinition) (*LLMResponse, error)
- func (c *LLMClient) CompleteWithToolsStream(ctx context.Context, messages []chatMessage, tools []ToolDefinition, ...) (*LLMResponse, error)
- func (c *LLMClient) CompleteWithToolsStreamUsingModel(ctx context.Context, modelOverride string, messages []chatMessage, ...) (*LLMResponse, error)
- func (c *LLMClient) CompleteWithToolsUsingModel(ctx context.Context, modelOverride string, messages []chatMessage, ...) (*LLMResponse, error)
- func (c *LLMClient) CompleteWithVision(ctx context.Context, ...) (string, error)
- func (c *LLMClient) IsOAuthProvider() bool
- func (c *LLMClient) OAuthBaseProvider() string
- func (c *LLMClient) Provider() string
- func (c *LLMClient) SetFailoverCoordinator(fc *FailoverCoordinator)
- func (c *LLMClient) SetOAuthTokenManager(tm OAuthTokenManager)
- func (c *LLMClient) TranscribeAudio(ctx context.Context, audioData []byte, filename, model string, ...) (string, error)
- type LLMErrorKind
- type LLMResponse
- type LLMUsage
- type Lane
- type LaneConfig
- type LaneManager
- type LaneTask
- type LegacyContextEngine
- type LinkConfig
- type LinkResult
- type LoggingConfig
- type LoopDetectionResult
- type LoopSeverity
- type MCPConfig
- type MCPManager
- func (m *MCPManager) AddServer(cfg ManagedMCPServerConfig) error
- func (m *MCPManager) GetConfig() MCPConfig
- func (m *MCPManager) GetServer(name string) *MCPServerInfo
- func (m *MCPManager) ListServers() []MCPServerInfo
- func (m *MCPManager) LoadFromDB() error
- func (m *MCPManager) RefreshStatus(ctx context.Context)
- func (m *MCPManager) Reload(cfg MCPConfig)
- func (m *MCPManager) RemoveServer(name string) error
- func (m *MCPManager) SetEnabled(name string, enabled bool) error
- func (m *MCPManager) TestServer(ctx context.Context, name string) (*MCPServerStatus, error)
- func (m *MCPManager) UpdateServer(name string, cfg ManagedMCPServerConfig) error
- type MCPServerConfig
- type MCPServerInfo
- type MCPServerStatus
- type MCPToolsBridge
- type MCPType
- type MMRConfig
- type MaintenanceManager
- type MaintenanceMode
- type ManagedMCPServerConfig
- type MediaCapability
- type MediaConfig
- type MediaEmitter
- type MediaEvent
- type MediaProviderConfig
- type MediaRegistry
- func (r *MediaRegistry) DescribeImageWithFallback(ctx context.Context, ...) (string, error)
- func (r *MediaRegistry) HasTranscriptionProviders() bool
- func (r *MediaRegistry) HasVisionProviders() bool
- func (r *MediaRegistry) TranscribeAudioWithFallback(ctx context.Context, audioData []byte, filename, model string, ...) (string, error)
- type MemoryChunk
- type MemoryConfig
- type MemoryDispatcherConfig
- type MemoryExtractor
- type MemoryFlushConfig
- type MemoryHierarchyDispatcherConfig
- type MemoryIndexer
- func (m *MemoryIndexer) ForceReindex()
- func (m *MemoryIndexer) IndexNow()
- func (m *MemoryIndexer) MemoryDir() string
- func (m *MemoryIndexer) SetDeleteFileFunc(fn func(filepath string) error)
- func (m *MemoryIndexer) SetIndexChunkFunc(fn func(chunks []MemoryChunk) error)
- func (m *MemoryIndexer) SetMemoryDir(dir string)
- func (m *MemoryIndexer) SetSQLiteStore(store SQLiteMemoryStore)
- func (m *MemoryIndexer) Start(ctx context.Context) error
- func (m *MemoryIndexer) Stats() (indexedTotal, indexedLast, deletedTotal int64, lastIndexTime time.Time)
- func (m *MemoryIndexer) Stop()
- type MemoryIndexerConfig
- type MemoryPromptSectionBuilder
- type MemoryStack
- type MemoryStackConfig
- type MemoryStats
- type MessageQueue
- func (q *MessageQueue) CombineMessages(msgs []*channels.IncomingMessage) string
- func (q *MessageQueue) Drain(sessionID string) []*channels.IncomingMessage
- func (q *MessageQueue) Enqueue(sessionID string, msg *channels.IncomingMessage) bool
- func (q *MessageQueue) IsDuplicate(msg *channels.IncomingMessage) bool
- func (q *MessageQueue) IsProcessing(sessionID string) bool
- func (q *MessageQueue) SetChannelDebounce(m map[string]int)
- func (q *MessageQueue) SetProcessing(sessionID string, active bool)
- func (q *MessageQueue) StuckSessions(maxAge time.Duration) []string
- func (q *MessageQueue) TrySetProcessing(sessionID string) bool
- type MetricsCollector
- func (m *MetricsCollector) Latest() *MetricsSnapshot
- func (m *MetricsCollector) RecordAgentRunComplete(success bool, timedOut bool)
- func (m *MetricsCollector) RecordAgentRunStart()
- func (m *MetricsCollector) RecordDBQuery(slow bool)
- func (m *MetricsCollector) RecordError()
- func (m *MetricsCollector) RecordLatency(ms int64)
- func (m *MetricsCollector) RecordMessage()
- func (m *MetricsCollector) RecordSessionCreated()
- func (m *MetricsCollector) RecordSubagentComplete(success bool)
- func (m *MetricsCollector) RecordSubagentSpawn()
- func (m *MetricsCollector) RecordTokens(count int64)
- func (m *MetricsCollector) RecordToolCall(success bool)
- func (m *MetricsCollector) SetDBSizeFunc(fn func() int64)
- func (m *MetricsCollector) SetMessagesQueueFunc(fn func() int64)
- func (m *MetricsCollector) SetSessionsCountFunc(fn func() int64)
- func (m *MetricsCollector) SetSubagentsCountFunc(fn func() int64)
- func (m *MetricsCollector) Start(ctx context.Context) error
- func (m *MetricsCollector) Stop()
- func (m *MetricsCollector) Subscribe() <-chan MetricsSnapshot
- func (m *MetricsCollector) Unsubscribe(ch <-chan MetricsSnapshot)
- type MetricsCollectorConfig
- type MetricsResult
- type MetricsSnapshot
- type MetricsTotals
- type ModelCooldown
- type ModelCost
- type ModelFailoverManager
- func (m *ModelFailoverManager) ApplyClassifiedFailure(model string, reason FailoverReason)
- func (m *ModelFailoverManager) GetCooldownStatus() map[string]*ModelCooldown
- func (m *ModelFailoverManager) MarkProbed(model string)
- func (m *ModelFailoverManager) ReportFailure(model string, statusCode int, errMsg string) FailoverReason
- func (m *ModelFailoverManager) ReportFailureWithCause(model string, statusCode int, errMsg string, cause error) FailoverReason
- func (m *ModelFailoverManager) ReportSuccess(model string)
- func (m *ModelFailoverManager) SelectFromChain(chain []string) string
- func (m *ModelFailoverManager) SelectModel() (model string, isPrimary bool)
- func (m *ModelFailoverManager) ShouldProbe(model string) bool
- type ModelFallbackConfig
- type NativeMediaConfig
- type NativeMediaEnrichmentConfig
- type NativeMediaServiceConfig
- type NativeMediaStoreConfig
- type NetworkRequest
- type NextAction
- type OAuthHubConfig
- type OAuthTokenManager
- type OnDrainFunc
- type PageState
- type PairingManager
- func (pm *PairingManager) ApproveRequest(requestID, approvedBy string) error
- func (pm *PairingManager) CreateRequest(tokenID, userJID, userName string) (*PairingRequest, error)
- func (pm *PairingManager) DenyRequest(requestID, deniedBy, reason string) error
- func (pm *PairingManager) GenerateToken(createdBy string, opts TokenOptions) (*PairingToken, error)
- func (pm *PairingManager) GetTokenByIDOrPrefix(idOrPrefix string) (*PairingToken, error)
- func (pm *PairingManager) ListPendingRequests() ([]*PairingRequest, error)
- func (pm *PairingManager) ListTokens(includeRevoked bool) ([]*PairingToken, error)
- func (pm *PairingManager) Load() error
- func (pm *PairingManager) ProcessTokenRedemption(tokenStr, userJID, userName string) (bool, string, error)
- func (pm *PairingManager) RevokeToken(tokenID, revokedBy string) error
- func (pm *PairingManager) ValidateToken(token string) (*PairingToken, error)
- type PairingRequest
- type PairingToken
- type PalaceBotConfig
- type PalaceBotReply
- type PendingApproval
- type Phase
- type PhaseResult
- type PreparePhase
- type ProfileChecker
- type ProgressSender
- type Project
- type ProjectManager
- func (pm *ProjectManager) Activate(sessionKey, projectID string) error
- func (pm *ProjectManager) ActiveProject(sessionKey string) *Project
- func (pm *ProjectManager) FindByPath(path string) *Project
- func (pm *ProjectManager) Get(id string) *Project
- func (pm *ProjectManager) List() []*Project
- func (pm *ProjectManager) Register(p *Project) error
- func (pm *ProjectManager) Remove(id string) error
- func (pm *ProjectManager) ScanDirectory(root string) ([]*Project, error)
- type ProjectProviderAdapter
- func (a *ProjectProviderAdapter) Activate(sessionKey, projectID string) error
- func (a *ProjectProviderAdapter) ActiveProject(sessionKey string) *skills.ProjectInfo
- func (a *ProjectProviderAdapter) Get(id string) *skills.ProjectInfo
- func (a *ProjectProviderAdapter) List() []*skills.ProjectInfo
- func (a *ProjectProviderAdapter) Register(p *skills.ProjectInfo) error
- func (a *ProjectProviderAdapter) Remove(id string) error
- func (a *ProjectProviderAdapter) ScanDirectory(root string) ([]*skills.ProjectInfo, error)
- type PromptComposer
- func (p *PromptComposer) Compose(session *Session, input string) string
- func (p *PromptComposer) ComposeForSubagent() string
- func (p *PromptComposer) ComposeMinimal() string
- func (p *PromptComposer) ComposeWithMode(session *Session, input string, mode PromptMode) string
- func (p *PromptComposer) IncrementSkillsVersion()
- func (p *PromptComposer) RegisterMemorySectionBuilder(builder MemoryPromptSectionBuilder)
- func (p *PromptComposer) SetAgentProfile(profile *AgentProfileConfig)
- func (p *PromptComposer) SetBuiltinSkills(skills *BuiltinSkills)
- func (p *PromptComposer) SetContextEngines(registry *ContextEngineRegistry)
- func (p *PromptComposer) SetContextRouter(router *ContextRouter)
- func (p *PromptComposer) SetLCMStore(store *LCMStore)
- func (p *PromptComposer) SetMemoryStack(stack *MemoryStack)
- func (p *PromptComposer) SetMemoryStore(store *memory.FileStore)
- func (p *PromptComposer) SetPluginAgentLister(lister func() []pluginAgentInfo)
- func (p *PromptComposer) SetSQLiteMemory(store *memory.SQLiteStore)
- func (p *PromptComposer) SetSkillGetter(getter func(name string) (interface{ ... }, bool))
- func (p *PromptComposer) SetSkillLister(lister func() []SkillInfo)
- func (p *PromptComposer) SetSubagentMode(isSubagent bool)
- func (p *PromptComposer) SetToolExecutor(executor *ToolExecutor)
- func (p *PromptComposer) SetWorkspaceContext(wsID string, dirs []string)
- type PromptLayer
- type PromptMode
- type ProviderChainEntry
- type ProviderDiscovery
- type ProviderDiscoveryConfig
- type QualityGuardConfig
- type QueryLoop
- type QueryOptions
- type QueueConfig
- type QueueDirective
- type QueueDropPolicy
- type QueueMode
- type QuietHoursConfig
- type Ref
- type RegisteredHook
- type ReminderInfo
- type ResolvedWorkspace
- type RiskAction
- type RiskCategoryConfig
- type RiskLevel
- type RoutinesConfig
- type RoutingConfig
- type SQLiteAuditLogger
- type SQLiteMemoryStore
- type SQLiteSessionPersistence
- func (p *SQLiteSessionPersistence) Close() error
- func (p *SQLiteSessionPersistence) DeleteSession(sessionID string) error
- func (p *SQLiteSessionPersistence) ListSessionsMeta() ([]SessionMeta, error)
- func (p *SQLiteSessionPersistence) LoadAll() (map[string]*SessionData, error)
- func (p *SQLiteSessionPersistence) LoadSession(sessionID string) ([]ConversationEntry, []string, error)
- func (p *SQLiteSessionPersistence) Rotate(sessionID string, maxLines int) error
- func (p *SQLiteSessionPersistence) SaveCompaction(sessionID string, entry CompactionEntry) error
- func (p *SQLiteSessionPersistence) SaveEntry(sessionID string, entry ConversationEntry) error
- func (p *SQLiteSessionPersistence) SaveFacts(sessionID string, facts []string) error
- func (p *SQLiteSessionPersistence) SaveMeta(sessionID, channel, chatID string, config SessionConfig, activeSkills []string) error
- func (p *SQLiteSessionPersistence) TruncateAfterCompaction(sessionID string, keepRecentEntries int) error
- type SchedulerConfig
- type SchedulerStats
- type SearchConfig
- type SecurityAuditToolConfig
- type SecurityConfig
- type Session
- func (s *Session) AddCompactionSummary(entry CompactionEntry)
- func (s *Session) AddFact(fact string)
- func (s *Session) AddMessage(userMsg, assistantResp string)
- func (s *Session) AddMessageWithToolCalls(userMsg, assistantResp string, toolCalls []ToolCallRecord)
- func (s *Session) AddMessageWithTools(userMsg, assistantResp, toolSummary string)
- func (s *Session) AddTokenUsage(promptTokens, completionTokens int)
- func (s *Session) ClearFacts()
- func (s *Session) ClearHistory()
- func (s *Session) CompactHistory(summary string, keepRecent int) []ConversationEntry
- func (s *Session) EstimateHistorySizeBytes() int
- func (s *Session) GetActiveSkills() []string
- func (s *Session) GetCompactionCount() int
- func (s *Session) GetCompactionSummaries() []CompactionEntry
- func (s *Session) GetConfig() SessionConfig
- func (s *Session) GetFacts() []string
- func (s *Session) GetFastMode() bool
- func (s *Session) GetLastCallTokens() (promptTokens, outputTokens, cacheRead, cacheWrite int)
- func (s *Session) GetMaxHistory() int
- func (s *Session) GetThinkingLevel() string
- func (s *Session) GetTokenUsage() (promptTokens, completionTokens, requests int)
- func (s *Session) HistoryLen() int
- func (s *Session) IncrementCompactionCount()
- func (s *Session) LastActiveAt() time.Time
- func (s *Session) RecentHistory(maxEntries int) []ConversationEntry
- func (s *Session) ResetTokenUsage()
- func (s *Session) ResetWithPreservation()
- func (s *Session) SetActiveSkills(skills []string)
- func (s *Session) SetConfig(cfg SessionConfig)
- func (s *Session) SetMaxHistory(n int)
- func (s *Session) SetThinkingLevel(level string)
- func (s *Session) UpdateLastCallTokens(promptTokens, outputTokens, cacheRead, cacheWrite int)
- type SessionConfig
- type SessionData
- type SessionExport
- type SessionInfo
- type SessionKey
- type SessionLock
- type SessionMemoryConfig
- type SessionMeta
- type SessionMetaLister
- type SessionPersistence
- func (p *SessionPersistence) Close() error
- func (p *SessionPersistence) DeleteSession(sessionID string) error
- func (p *SessionPersistence) LoadAll() (map[string]*SessionData, error)
- func (p *SessionPersistence) LoadSession(sessionID string) ([]ConversationEntry, []string, error)
- func (p *SessionPersistence) Rotate(sessionID string, maxLines int) error
- func (p *SessionPersistence) SaveCompaction(sessionID string, entry CompactionEntry) error
- func (p *SessionPersistence) SaveEntry(sessionID string, entry ConversationEntry) error
- func (p *SessionPersistence) SaveFacts(sessionID string, facts []string) error
- func (p *SessionPersistence) SaveMeta(sessionID, channel, chatID string, config SessionConfig, activeSkills []string) error
- func (p *SessionPersistence) TruncateAfterCompaction(sessionID string, keepRecentEntries int) error
- type SessionPersister
- type SessionReaperConfig
- type SessionStats
- type SessionStore
- func (ss *SessionStore) Count() int
- func (ss *SessionStore) Delete(channel, chatID string) bool
- func (ss *SessionStore) DeleteByID(id string) bool
- func (ss *SessionStore) Export(id string) *SessionExport
- func (ss *SessionStore) Get(channel, chatID string) *Session
- func (ss *SessionStore) GetByID(id string) *Session
- func (ss *SessionStore) GetOrCreate(channel, chatID string) *Session
- func (ss *SessionStore) ListAllSessions() []SessionMeta
- func (ss *SessionStore) ListSessions() []SessionMeta
- func (ss *SessionStore) Prune() int
- func (ss *SessionStore) RenameSession(oldID, newChannel, newChatID string) bool
- func (ss *SessionStore) SetPersistence(p SessionPersister)
- func (ss *SessionStore) StartPruner(ctx context.Context)
- type SessionUsage
- type Settings
- type SettingsManager
- func (sm *SettingsManager) AddProfile(profile ToolProfile) error
- func (sm *SettingsManager) DeleteProfile(name string) error
- func (sm *SettingsManager) GetAllProfiles() map[string]ToolProfile
- func (sm *SettingsManager) GetSettingsPath() string
- func (sm *SettingsManager) ListProfilesInfo() []ToolProfileInfo
- func (sm *SettingsManager) Load() (*Settings, error)
- func (sm *SettingsManager) Save(settings *Settings) error
- func (sm *SettingsManager) UpdateProfile(profile ToolProfile) error
- type SharedMemory
- type SkillDB
- func (s *SkillDB) Close() error
- func (s *SkillDB) CreateTable(skillName, tableName, displayName, description string, ...) error
- func (s *SkillDB) Delete(skillName, tableName, rowID string) error
- func (s *SkillDB) DescribeTable(skillName, tableName string) (*TableInfo, error)
- func (s *SkillDB) DropTable(skillName, tableName string) error
- func (s *SkillDB) GetByID(skillName, tableName, rowID string) (map[string]any, error)
- func (s *SkillDB) GetReminderByJobID(jobID string) (*ReminderInfo, error)
- func (s *SkillDB) InitRemindersTable() error
- func (s *SkillDB) Insert(skillName, tableName string, data map[string]any) (string, error)
- func (s *SkillDB) ListTables(skillName string) ([]TableInfo, error)
- func (s *SkillDB) MarkReminderRemoved(jobID string) error
- func (s *SkillDB) Path() string
- func (s *SkillDB) Query(skillName, tableName string, filters map[string]any, limit int) ([]map[string]any, error)
- func (s *SkillDB) QueryWithOptions(skillName, tableName string, opts QueryOptions) ([]map[string]any, error)
- func (s *SkillDB) SaveReminder(jobID, jobType, schedule, command, channel, chatID string) error
- func (s *SkillDB) SearchReminders(query string, includeRemoved bool, limit int) ([]ReminderInfo, error)
- func (s *SkillDB) Update(skillName, tableName, rowID string, data map[string]any) error
- type SkillInfo
- type SkillReloadCallback
- type SkillWatcher
- type SkillsConfig
- type SnapshotOptions
- type SnapshotResult
- type SnapshotStats
- type SpawnParams
- type StackConfig
- type StackStats
- type StartupCheckResult
- type StartupReport
- type StartupVerifier
- type StopCheckPhase
- type StopHookVerifier
- type StreamCallback
- type StreamSanitizer
- type SubagentConfig
- type SubagentManager
- func (m *SubagentManager) ActiveCount() int
- func (m *SubagentManager) Cleanup(maxAge time.Duration) int
- func (m *SubagentManager) CreateChildExecutorWithProfile(parent *ToolExecutor, depth int, allow, deny []string) *ToolExecutor
- func (m *SubagentManager) Get(runID string) (*SubagentRun, bool)
- func (m *SubagentManager) List() []*SubagentRun
- func (m *SubagentManager) PruneOldRuns(days int) int
- func (m *SubagentManager) SetAnnounceCallback(cb AnnounceCallback)
- func (m *SubagentManager) SetDB(db *sql.DB)
- func (m *SubagentManager) Spawn(parentCtx context.Context, params SpawnParams, llmClient *LLMClient, ...) (*SubagentRun, error)
- func (m *SubagentManager) SpawnWithExecutor(parentCtx context.Context, params SpawnParams, llmClient *LLMClient, ...) (*SubagentRun, error)
- func (m *SubagentManager) StartPeriodicSweeper(ctx context.Context, interval time.Duration, maxAgeDays int)
- func (m *SubagentManager) Stop(runID string) error
- func (m *SubagentManager) Wait(ctx context.Context, runID string) (*SubagentRun, error)
- type SubagentRun
- type SubagentStatus
- type SystemCommands
- func (t *SystemCommands) ChannelsCommand(args []string) string
- func (t *SystemCommands) DiagnosticsCommand(full bool) string
- func (t *SystemCommands) ExecQueueCommand() string
- func (t *SystemCommands) HealthCommand() string
- func (t *SystemCommands) LogsCommand(args []string) string
- func (t *SystemCommands) MaintenanceCommand(args []string, setBy string) string
- func (t *SystemCommands) MetricsCommand(args []string) string
- func (t *SystemCommands) ReloadCommand(args []string) string
- func (t *SystemCommands) StatusCommand(jsonOutput bool) string
- type SystemStatus
- type TLSConfig
- type TTSConfig
- type Tab
- type TableInfo
- type TailscaleConfig
- type TailscaleManager
- type TeamUser
- type TemporalDecayConfig
- type TokenBudgetConfig
- type TokenOptions
- type TokenRole
- type ToolCall
- type ToolCallIDMode
- type ToolCallRecord
- type ToolCheckResult
- type ToolDefinition
- type ToolExecutor
- func (e *ToolExecutor) Abort()
- func (e *ToolExecutor) AbortCh() <-chan struct{}
- func (e *ToolExecutor) ApplyDefaultConcurrency()
- func (e *ToolExecutor) Configure(cfg ToolExecutorConfig)
- func (e *ToolExecutor) Execute(ctx context.Context, calls []ToolCall) []ToolResult
- func (e *ToolExecutor) Guard() *ToolGuard
- func (e *ToolExecutor) HasTool(name string) bool
- func (e *ToolExecutor) IsAborted() bool
- func (e *ToolExecutor) IsConcurrentSafe(name string) bool
- func (e *ToolExecutor) MarkConcurrentSafe(names ...string)
- func (e *ToolExecutor) ProfileManager() profiles.ProfileManager
- func (e *ToolExecutor) Register(def ToolDefinition, handler ToolHandlerFunc)
- func (e *ToolExecutor) RegisterHidden(def ToolDefinition, handler ToolHandlerFunc)
- func (e *ToolExecutor) RegisterHook(hook *ToolHook)
- func (e *ToolExecutor) RegisterPluginTool(reg plugins.ToolRegistration)
- func (e *ToolExecutor) RegisterSkillTools(skill skills.Skill)
- func (e *ToolExecutor) ResetAbort()
- func (e *ToolExecutor) SessionContext() string
- func (e *ToolExecutor) SetCallerContext(level AccessLevel, jid string)
- func (e *ToolExecutor) SetConfirmationRequester(...)
- func (e *ToolExecutor) SetGuard(guard *ToolGuard)
- func (e *ToolExecutor) SetProfileManager(pm profiles.ProfileManager)
- func (e *ToolExecutor) SetSessionContext(sessionID string)
- func (e *ToolExecutor) SetVault(vault skills.VaultReader)
- func (e *ToolExecutor) ToolNames() []string
- func (e *ToolExecutor) Tools() []ToolDefinition
- func (e *ToolExecutor) UnregisterTool(name string) bool
- func (e *ToolExecutor) UpdateGuardConfig(cfg ToolGuardConfig)
- type ToolExecutorConfig
- type ToolGuard
- func (g *ToolGuard) AuditLog(toolName string, callerJID string, callerLevel AccessLevel, ...)
- func (g *ToolGuard) Check(toolName string, callerLevel AccessLevel, args map[string]any) ToolCheckResult
- func (g *ToolGuard) CheckWithProfile(toolName string, callerLevel AccessLevel, args map[string]any, ...) ToolCheckResult
- func (g *ToolGuard) Close()
- func (g *ToolGuard) GetActiveProfile() *ToolProfile
- func (g *ToolGuard) GetAllToolNames() []string
- func (g *ToolGuard) SQLiteAudit() *SQLiteAuditLogger
- func (g *ToolGuard) SetSQLiteAudit(a *SQLiteAuditLogger)
- func (g *ToolGuard) UpdateConfig(cfg ToolGuardConfig)
- type ToolGuardConfig
- type ToolHandlerFunc
- type ToolHook
- type ToolLoopConfig
- type ToolLoopDetector
- type ToolOutcome
- type ToolOutcomeLog
- type ToolOverlay
- type ToolPermission
- type ToolProfile
- type ToolProfileInfo
- type ToolResult
- type TranscriptPolicy
- type TrustConfig
- type TurnState
- type TypingController
- type TypingState
- type UpdateConfig
- type UpdateFileChunk
- type UpdateFileHunk
- type UsageAccumulator
- type UsageTracker
- func (u *UsageTracker) FormatGlobalUsage() string
- func (u *UsageTracker) FormatUsage(sessionID string) string
- func (u *UsageTracker) GetGlobal() *SessionUsage
- func (u *UsageTracker) GetSession(sessionID string) *SessionUsage
- func (u *UsageTracker) Record(sessionID, model string, usage LLMUsage)
- func (u *UsageTracker) ResetSession(sessionID string)
- type UserManager
- func (um *UserManager) AddUser(user *TeamUser) error
- func (um *UserManager) CheckPermission(userID string, required UserRole) bool
- func (um *UserManager) GetSharedMemory(key string) (*SharedMemory, bool)
- func (um *UserManager) GetUser(id string) (*TeamUser, bool)
- func (um *UserManager) ListSharedMemory() []*SharedMemory
- func (um *UserManager) ListUsers() []*TeamUser
- func (um *UserManager) RemoveUser(id string) error
- func (um *UserManager) SetSharedMemory(key, value, authorID string, tags []string)
- type UserManagerConfig
- type UserRole
- type UserUsage
- type Vault
- func (v *Vault) ChangePassword(newPassword string) error
- func (v *Vault) Create(password string) error
- func (v *Vault) Delete(name string) error
- func (v *Vault) Exists() bool
- func (v *Vault) Get(name string) (string, error)
- func (v *Vault) Has(name string) bool
- func (v *Vault) InjectProviderKeys() error
- func (v *Vault) IsUnlocked() bool
- func (v *Vault) Keys() ([]string, error)
- func (v *Vault) List() []string
- func (v *Vault) Lock()
- func (v *Vault) Path() string
- func (v *Vault) Set(name, value string) error
- func (v *Vault) Unlock(password string) error
- type VaultData
- type VaultEntry
- type VaultReaderAdapter
- type VerboseLevel
- type WebFetchCache
- type WebSearchConfig
- type WebhookConfig
- type WebhookManager
- type WebhookPayload
- type WebhooksConfig
- type WingHeuristic
- type WingResolution
- type WingResolutionSource
- type WorkerResult
- type WorkerSpawner
- type WorkerTask
- type Workspace
- type WorkspaceConfig
- type WorkspaceContainment
- type WorkspaceManager
- func (wm *WorkspaceManager) AssignGroup(groupJID, wsID, assignedBy string) error
- func (wm *WorkspaceManager) AssignUser(jid, wsID, assignedBy string) error
- func (wm *WorkspaceManager) Count() int
- func (wm *WorkspaceManager) Create(ws Workspace, createdBy string) error
- func (wm *WorkspaceManager) DefaultID() string
- func (wm *WorkspaceManager) Delete(wsID, deletedBy string) error
- func (wm *WorkspaceManager) DeleteSessionByID(sessionID string) bool
- func (wm *WorkspaceManager) ExportSession(id string) *SessionExport
- func (wm *WorkspaceManager) FindSessionByID(id string) *Session
- func (wm *WorkspaceManager) Get(wsID string) (*Workspace, bool)
- func (wm *WorkspaceManager) GetForUser(jid string) (*Workspace, bool)
- func (wm *WorkspaceManager) GetSessionByID(sessionID string) (*Session, *Workspace)
- func (wm *WorkspaceManager) List() []*Workspace
- func (wm *WorkspaceManager) ListAllSessions() []SessionInfo
- func (wm *WorkspaceManager) ListSessionsForWorkspace(wsID string) []SessionInfo
- func (wm *WorkspaceManager) RebuildMaps()
- func (wm *WorkspaceManager) Resolve(channel, chatID, senderJID string, isGroup bool) *ResolvedWorkspace
- func (wm *WorkspaceManager) ResolveByNameOrID(input string) (*Workspace, bool)
- func (wm *WorkspaceManager) SessionCount() int
- func (wm *WorkspaceManager) SessionCountForWorkspace(wsID string) int
- func (wm *WorkspaceManager) SetDefault(wsID string) error
- func (wm *WorkspaceManager) SetPersistence(p SessionPersister)
- func (wm *WorkspaceManager) StartPruners(ctx context.Context)
- func (wm *WorkspaceManager) UnassignUser(jid string)
- func (wm *WorkspaceManager) Update(wsID string, fn func(ws *Workspace)) error
Constants ¶
const ( // DefaultRunTimeout is the maximum duration for an entire agent run. // Set to 20 minutes to accommodate coding tasks that invoke Claude Code CLI // (which itself can take 5-15 minutes for complex projects). // This is the PRIMARY timeout — no per-turn limit. DefaultRunTimeout = 1200 * time.Second // DefaultLLMCallTimeout is the safety-net timeout for a single LLM API call. // This only prevents hung HTTP connections — it should be generous enough // that even large contexts complete. 5 minutes covers worst-case scenarios. DefaultLLMCallTimeout = 5 * time.Minute // DefaultMaxCompactionAttempts is how many times to retry after context overflow compaction. DefaultMaxCompactionAttempts = 3 )
const ( BeginPatchMarker = "*** Begin Patch" EndPatchMarker = "*** End Patch" AddFileMarker = "*** Add File: " DeleteFileMarker = "*** Delete File: " UpdateFileMarker = "*** Update File: " MoveToMarker = "*** Move to: " EOFMarker = "*** End of File" ChangeContextMarker = "@@ " EmptyChangeContextMarker = "@@" )
const ( ActClick = "click" ActType = "type" ActPress = "press" ActHover = "hover" ActDrag = "drag" ActSelect = "select" ActFill = "fill" ActResize = "resize" ActWait = "wait" ActEvaluate = "evaluate" )
Act kinds
const ( // ContextWindowHardMinTokens is the absolute minimum context window required // for a useful agent run. Below this, the run is blocked. ContextWindowHardMinTokens = 16_000 // ContextWindowWarnBelowTokens triggers a warning when the context window // is usable but small. This helps users understand potential issues with // compaction, long tool outputs, and multi-turn conversations. ContextWindowWarnBelowTokens = 32_000 )
const ( TokenNoReply = "NO_REPLY" TokenHeartbeatOK = "HEARTBEAT_OK" )
Silent token constants — used by the LLM to signal special behavior. These must be stripped from user-visible output.
const ( // DefaultDebounceMs is the debounce delay for followup messages (session busy). // Kept short so followups are grouped without adding perceptible lag. DefaultDebounceMs = 200 // DefaultMaxPending is the default max queued messages per session. DefaultMaxPending = 20 // DedupWindowSec is the window for deduplication (skip same content). DedupWindowSec = 5 // FollowupDebounceMs is used when the session is already processing. // Slightly longer to allow burst followup messages to be collected. FollowupDebounceMs = 500 )
const ( // MaxMessageWhatsApp is WhatsApp's character limit. MaxMessageWhatsApp = 4096 // MaxMessageDefault is the default max length for general channels. MaxMessageDefault = 4000 )
const ( // a single tool result should occupy. MaxToolResultContextShare = 0.3 // MinKeepChars is the minimum number of characters to keep in a truncated // tool result, even when aggressive truncation is applied. MinKeepChars = 2000 // TailBudgetRatio is the fraction of the truncation budget allocated to // the tail portion when important tail content is detected. TailBudgetRatio = 0.3 // MaxTailChars is the absolute maximum characters to keep from the tail. MaxTailChars = 4000 // TailDetectionWindow is how many characters from the end to scan for // important tail content. TailDetectionWindow = 2000 // ContextBudgetRatio is the fraction of context window (in chars) that // all tool results combined should not exceed. ContextBudgetRatio = 0.75 // PerResultContextCap is the fraction of context window chars that a single // tool result should not exceed in the pre-LLM guard. PerResultContextCap = 0.5 // CompactedPlaceholder replaces tool results that are compacted to free context. CompactedPlaceholder = "[compacted: tool output removed to free context]" )
const ( // ApprovalTimeout is how long to wait for user approval before giving up. // 120s gives ample time for users to read and respond via chat. ApprovalTimeout = 120 * time.Second )
const DefaultImagePruneAfterTurns = 5
DefaultImagePruneAfterTurns is how many turns back to keep images. Images older than this are replaced with a text placeholder to prevent token accumulation from multimodal content.
const DefaultMaxHistory = 100
DefaultMaxHistory é o limite padrão de entradas no histórico por sessão.
const DefaultMaxHistoryDM = 100
DefaultMaxHistoryDM is the history limit for direct message sessions. DMs are linear conversations, so a higher limit preserves more context.
const DefaultMaxHistoryGroup = 50
DefaultMaxHistoryGroup is the history limit for group/channel sessions. Groups are noisier with more participants, so a lower limit saves context.
const DefaultSessionTTL = 24 * time.Hour
DefaultSessionTTL é o tempo de inatividade antes de uma sessão ser removida.
const ( // DefaultToolTimeout is the maximum time a single tool execution can take. DefaultToolTimeout = 30 * time.Second )
const HardMaxToolResultChars = 400_000
HardMaxToolResultChars is the absolute maximum size for a tool result. Results exceeding this are truncated before entering the conversation to prevent context overflow.
const (
// VaultFile is the default vault file name.
VaultFile = ".devclaw.vault"
)
Variables ¶
var AllHookEvents = []HookEvent{ HookSessionStart, HookSessionEnd, HookUserPromptSubmit, HookPreToolUse, HookPostToolUse, HookAgentStart, HookAgentStop, HookSubagentStart, HookSubagentStop, HookPreCompact, HookPostCompact, HookMemorySave, HookMemoryRecall, HookNotification, HookHeartbeat, HookError, HookUserJoin, HookUserLeave, HookChannelConnect, HookChannelDisconnect, HookBeforeModelResolve, HookBeforePromptBuild, HookLLMInput, HookLLMOutput, HookToolResultPersist, HookMessageTranscribed, HookMessagePreprocessed, HookBeforeReset, }
AllHookEvents lists every supported hook event for discovery/documentation.
var BuiltInProfiles = map[string]ToolProfile{ "minimal": { Name: "minimal", Description: "Basic queries only - read-only access, no writes", Allow: []string{ "group:web", "group:memory", "read_file", "list_files", "search_files", "glob_files", "describe_image", }, Deny: []string{ "group:runtime", "write_file", "edit_file", "group:skills", "group:scheduler", "group:vault", "group:subagents", "group:daemon", "group:browser", }, }, "coding": { Name: "coding", Description: "Software development - file access, skills, vault, scheduler, browser", Allow: []string{ "group:fs", "group:web", "group:memory", "group:scheduler", "group:vault", "group:skills", "group:sessions", "group:subagents", "group:daemon", "group:media", "group:browser", "group:skill_db", "bash", "exec", "apply_patch", "read_file", "write_file", "edit_file", "list_files", "search_files", "glob_files", }, Deny: []string{ "ssh", "scp", }, }, "messaging": { Name: "messaging", Description: "Chat channels (WhatsApp, Discord, Telegram, Slack) - nearly full access except ssh/daemon", Allow: []string{ "group:web", "group:memory", "group:scheduler", "group:vault", "group:skills", "group:sessions", "group:media", "group:skill_db", "group:fs", "group:subagents", "group:browser", "group:daemon", "bash", "exec", "apply_patch", "read_file", "write_file", "edit_file", "list_files", "search_files", "glob_files", }, Deny: []string{ "ssh", "scp", "set_env", }, }, "full": { Name: "full", Description: "Full access - all tools available (respect per-tool permissions)", Allow: []string{"*"}, Deny: []string{}, }, }
BuiltInProfiles provides predefined tool profiles for common use cases.
Design rules:
- Always use "group:xxx" references instead of individual tool names when the intent is to include all tools in a category. This ensures new tools added to a group are automatically picked up by profiles.
- Individual tool names are used only for tools that don't belong to any group (e.g. "apply_patch") or when only a subset of a group is needed.
- Dispatcher tools (memory, vault, scheduler, browser) internally call hidden sub-tools via executeByName which bypasses the profile guard. Using the group (e.g. "group:vault") instead of just "vault" ensures the sub-tools are also in the allow set for direct Execute() calls.
var ContentRoles = map[string]bool{ "heading": true, "paragraph": true, "cell": true, "rowheader": true, "columnheader": true, "listitem": true, "article": true, "figure": true, "img": true, }
ContentRoles are roles that represent content elements.
var DefaultSubagentDeniedTools = []string{
"memory_save", "memory_search", "memory_list", "memory_index",
"scheduler_add", "scheduler_list", "scheduler_remove", "scheduler_search",
"skill_init", "skill_edit", "skill_add_script", "skill_list",
"skill_test", "skill_install", "skill_defaults_list", "skill_defaults_install", "skill_remove",
"memory", "scheduler", "skill_manage",
}
DefaultSubagentDeniedTools lists tools subagents should not access. Note: spawn tools (spawn_subagent, list_subagents, wait_subagent, stop_subagent) are intentionally omitted — they are managed by depth-based logic in createChildExecutor.
var ErrAgentYield = errors.New("agent yielded turn")
ErrAgentYield is returned when the agent's sessions_yield tool is invoked. The caller should collect pending subagent results and re-invoke the agent.
var ErrInvalidTime = errorString("invalid time format")
ErrInvalidTime is returned when a time string is invalid.
var InteractiveRoles = map[string]bool{ "button": true, "link": true, "textbox": true, "checkbox": true, "radio": true, "combobox": true, "menuitem": true, "menuitemcheckbox": true, "menuitemradio": true, "tab": true, "spinbutton": true, "slider": true, "switch": true, "searchbox": true, "textarea": true, }
InteractiveRoles are roles that represent interactive elements.
var ProviderKeyNames = map[string]string{
"openai": "OPENAI_API_KEY",
"anthropic": "ANTHROPIC_API_KEY",
"google": "GOOGLE_API_KEY",
"xai": "XAI_API_KEY",
"groq": "GROQ_API_KEY",
"zai": "ZAI_API_KEY",
"mistral": "MISTRAL_API_KEY",
"openrouter": "OPENROUTER_API_KEY",
"cerebras": "CEREBRAS_API_KEY",
"minimax": "MINIMAX_API_KEY",
"huggingface": "HUGGINGFACE_API_KEY",
"deepseek": "DEEPSEEK_API_KEY",
"custom": "CUSTOM_API_KEY",
}
ProviderKeyNames maps provider IDs to their standard API key variable names. These follow industry conventions (OPENAI_API_KEY, ANTHROPIC_API_KEY, etc.)
var StructuralRoles = map[string]bool{ "generic": true, "group": true, "list": true, "table": true, "row": true, "region": true, "section": true, "document": true, "webarea": true, "rootWebArea": true, }
StructuralRoles are roles that represent structural elements.
var ToolGroups = map[string][]string{
"group:memory": {"memory", "memory_save", "memory_search", "memory_list", "memory_index"},
"group:web": {"web_search", "web_fetch"},
"group:fs": {"read_file", "write_file", "edit_file", "list_files", "search_files", "glob_files"},
"group:runtime": {"bash", "exec", "ssh", "scp", "set_env"},
"group:subagents": {"spawn_subagent", "list_subagents", "wait_subagent", "stop_subagent"},
"group:skills": {
"get_skill_instructions", "get_skill_reference",
"skill_list", "skill_install", "skill_init",
"skill_edit", "skill_add_script", "skill_test",
"skill_defaults_list", "skill_defaults_install", "skill_remove",
},
"group:scheduler": {"scheduler", "scheduler_add", "scheduler_list", "scheduler_remove", "scheduler_search"},
"group:vault": {"vault", "vault_status", "vault_save", "vault_get", "vault_list", "vault_delete"},
"group:sessions": {"sessions"},
"group:daemon": {"daemon"},
"group:media": {"describe_image", "transcribe_audio", "send_media", "image-gen_generate_image"},
"group:skill_db": {"skill_db_query", "skill_db_list_tables", "skill_db_insert", "skill_db_update", "skill_db_delete", "skill_db_create_table", "skill_db_describe", "skill_db_drop_table"},
"group:browser": {"browser", "browser_navigate", "browser_screenshot", "browser_content", "browser_click", "browser_fill", "browser_snapshot", "browser_tabs", "browser_open_tab", "browser_focus_tab", "browser_close_tab", "browser_act"},
}
ToolGroups maps group names to tool name lists. Allows policy management at a higher level than individual tools.
Functions ¶
func ApplyTranscriptPolicy ¶ added in v1.13.0
func ApplyTranscriptPolicy(messages []chatMessage, policy TranscriptPolicy) []chatMessage
ApplyTranscriptPolicy sanitizes messages according to the provider's policy.
func AuditSecrets ¶
AuditSecrets checks for hardcoded secrets and logs warnings. Should be called on startup to alert the user.
func CallerJIDFromContext ¶
CallerJIDFromContext extracts the caller JID from context.
func CategorizeToolNames ¶ added in v1.12.0
CategorizeToolNames groups tool names by category.
func CategorizeTools ¶ added in v1.12.0
func CategorizeTools(tools []ToolDefinition) map[string][]ToolDefinition
CategorizeTools groups tool definitions by category for display purposes.
func CheckSkillSetup ¶ added in v1.12.0
func CheckSkillSetup(skill skills.Skill, vault skills.VaultReader) (*skills.SetupStatus, error)
CheckSkillSetup checks if a skill is properly configured. Returns setup status and nil if check was performed, or error if skill doesn't support setup checking.
func CollapseToolResults ¶ added in v1.17.0
CollapseToolResults truncates oversized tool results in-place without clearing them. This is the cheapest compaction level — just trims excessively long outputs. Returns the number of results collapsed.
func ContextWithAgentRun ¶ added in v1.14.0
ContextWithAgentRun returns a context carrying the AgentRun.
func ContextWithCaller ¶
ContextWithCaller returns a new context carrying the caller's access level and JID. This replaces the global SetCallerContext/SetSessionContext pattern, making tool security checks goroutine-safe (context per request).
func ContextWithDelivery ¶
ContextWithDelivery returns a new context carrying the delivery target. This is used by tools like the scheduler dispatcher to know where to deliver scheduled messages.
func ContextWithFastMode ¶ added in v1.14.0
ContextWithFastMode returns a context with fast mode enabled/disabled.
func ContextWithMediaEmitter ¶ added in v1.15.0
func ContextWithMediaEmitter(ctx context.Context, fn MediaEmitter) context.Context
ContextWithMediaEmitter returns a new context carrying a media emitter callback.
func ContextWithMessageID ¶ added in v1.14.0
ContextWithMessageID returns a context carrying the triggering message ID.
func ContextWithProgressSender ¶
func ContextWithProgressSender(ctx context.Context, fn ProgressSender) context.Context
ContextWithProgressSender returns a context carrying a ProgressSender callback.
func ContextWithSession ¶
ContextWithSession returns a new context carrying the given session ID.
func ContextWithSpawnDepth ¶ added in v1.8.0
ContextWithSpawnDepth returns a new context with the spawn depth set.
func ContextWithToolOutcomeLog ¶ added in v1.18.2
func ContextWithToolOutcomeLog(ctx context.Context, log *ToolOutcomeLog) context.Context
ContextWithToolOutcomeLog attaches an outcome log to the context.
func ContextWithToolOverlay ¶ added in v1.16.0
func ContextWithToolOverlay(ctx context.Context, overlay *ToolOverlay) context.Context
ContextWithToolOverlay returns a context carrying the tool overlay.
func ContextWithToolProfile ¶
func ContextWithToolProfile(ctx context.Context, profile *ToolProfile) context.Context
ContextWithToolProfile returns a new context carrying a tool profile. The profile is used for CheckWithProfile to apply allow/deny lists.
func ContextWithVaultReader ¶ added in v1.12.0
ContextWithVaultReader returns a new context carrying a vault reader.
func ContextWithWorkspaceID ¶ added in v1.16.0
ContextWithWorkspaceID returns a context carrying the workspace ID.
func DeleteKeyring ¶
DeleteKeyring removes a secret from the OS keyring.
func DetectInjectionPattern ¶
DetectInjectionPattern checks if a text contains known prompt injection patterns. Returns true if any pattern matches (the text should NOT be auto-captured).
func EmitHierarchyEnabled ¶ added in v1.18.0
EmitHierarchyEnabled logs the feature flag state as a gauge. Called once at startup and on any config reload. Log format matches EmitSnapshot.
func EstimateTokens ¶ added in v1.14.0
EstimateTokens provides a rough token count estimate (len/4).
func ExpandProfileList ¶
ExpandProfileList expands a profile's allow/deny lists into tool names. Handles groups ("group:name") and wildcards ("git_*").
func ExpandToolGroups ¶
ExpandToolGroups expands group references (e.g. "group:memory") into individual tool names. Non-group entries are passed through as-is.
func ExtractLinksFromMessage ¶ added in v1.13.0
ExtractLinksFromMessage extracts HTTP(S) URLs from a message body. Strips markdown link formatting and limits to maxLinks.
func ExtractReadableText ¶ added in v1.13.0
ExtractReadableText converts raw HTML into clean readable text with minimal markdown formatting (headings, links, lists). It prioritizes <main>, <article>, and <body> content while skipping navigation, footers, scripts, and styles.
func ExtractTokenFromMessage ¶
ExtractTokenFromMessage attempts to extract a pairing token from message content. Tokens are 48+ hex characters. Returns empty string if not a token attempt.
func FindConfigFile ¶
func FindConfigFile() string
FindConfigFile searches for config files in standard locations.
func FormatAbortReply ¶ added in v1.12.0
FormatAbortReply formats the reply message after an abort.
func FormatCollectedMessages ¶
func FormatCollectedMessages(msgs []*channels.IncomingMessage) string
FormatCollectedMessages combines multiple messages into a single prompt (used by QueueModeCollect).
func FormatForChannel ¶
FormatForChannel dispatches to the appropriate formatter based on channel. Reply tags ([[reply_to_current]], [[reply_to:<id>]]) are stripped before formatting so they never reach the user.
func FormatForPlainText ¶
FormatForPlainText strips all Markdown, leaving only plain text.
func FormatForSlack ¶
FormatForSlack converts Markdown to Slack's mrkdwn format. Slack uses: *bold*, _italic_, ~strike~, `code`, ```preformatted```.
func FormatForTelegram ¶
FormatForTelegram converts Markdown to Telegram HTML. Telegram supports: <b>, <i>, <code>, <pre>, <a href="">, <s>, <u>.
func FormatForWhatsApp ¶
FormatForWhatsApp converts standard Markdown to WhatsApp-compatible formatting. WhatsApp supports: *bold*, _italic_, ~strikethrough~, `monospace`, ```code blocks```. Headers become bold; links are flattened; images become [Image: alt]; lists use •.
func FormatIdentityMd ¶ added in v1.16.0
func FormatIdentityMd(id *IdentityConfig) string
FormatIdentityMd converts an IdentityConfig to markdown content.
func FormatIncompleteWorkMessage ¶ added in v1.17.0
func FormatIncompleteWorkMessage(items []IncompleteWork) string
FormatIncompleteWorkMessage formats incomplete work items into a single message that can be injected into the conversation to prompt continuation.
func FormatLinkResults ¶ added in v1.13.0
func FormatLinkResults(results []LinkResult) string
FormatLinkResults formats link results as context to prepend to the user message.
func FormatMemoriesForStorage ¶ added in v1.17.0
func FormatMemoriesForStorage(memories []ExtractedMemory, sessionID string) string
FormatMemoriesForStorage formats extracted memories into a text block suitable for saving to the memory store.
func FormatSetupPrompt ¶ added in v1.12.0
func FormatSetupPrompt(skillName string, status *skills.SetupStatus) string
FormatSetupPrompt creates a user-friendly prompt for missing configuration.
func FormatToolNamesForPrompt ¶ added in v1.12.0
FormatToolNamesForPrompt formats tool names as a compact list for the system prompt. Groups by category for better readability.
func FormatToolsForPrompt ¶ added in v1.12.0
func FormatToolsForPrompt(tools []ToolDefinition, maxDescLen int) string
FormatToolsForPrompt formats tools as a compact list for the system prompt. Groups by category and truncates descriptions to fit within budget.
func GenerateSummaryID ¶ added in v1.14.0
GenerateSummaryID creates a deterministic summary ID from content and timestamp.
func GetDeliveryTarget ¶ added in v1.12.0
GetDeliveryTarget is a convenience function that extracts the delivery target from the context. Tools should use this to get channel/chatID context.
Example:
func myToolHandler(ctx context.Context, args map[string]any) (any, error) {
channel, chatID := GetDeliveryTarget(ctx)
if channel == "" {
return nil, fmt.Errorf("no channel context")
}
// Use channel and chatID...
}
func GetKeyring ¶
GetKeyring retrieves a secret from the OS keyring. Returns empty string if not found.
func GetProviderKeyName ¶ added in v1.8.1
GetProviderKeyName returns the standard API key variable name for a provider. Falls back to "API_KEY" for unknown providers.
func GuardToolResultContext ¶ added in v1.13.0
func GuardToolResultContext(messages []chatMessage, contextWindowTokens int) []chatMessage
GuardToolResultContext applies the pre-LLM context guard to all messages. It caps individual tool results and compacts oldest tool results when the total content exceeds the context budget.
contextWindowTokens is the model's context window in tokens. We estimate 1 token ≈ 4 chars for budget calculation.
func HasAbortPrefix ¶ added in v1.12.0
HasAbortPrefix checks if text starts with an abort-related prefix. Useful for early detection in message processing.
func HasImportantTail ¶ added in v1.13.0
HasImportantTail returns true if the last portion of text contains patterns that suggest important content (errors, JSON closings, summaries, etc.).
func HistoryLimitForType ¶ added in v1.13.0
HistoryLimitForType returns the appropriate history limit based on whether the conversation is a DM or group/channel.
func HookEventDescription ¶
HookEventDescription returns a human-readable description for a hook event.
func IncClassifierPass ¶ added in v1.18.0
func IncClassifierPass()
IncClassifierPass increments the legacy classifier phase run counter.
func IncContextRouterDefault ¶ added in v1.18.0
func IncContextRouterDefault()
IncContextRouterDefault atomically increments the default counter.
func IncContextRouterDisabled ¶ added in v1.18.0
func IncContextRouterDisabled()
IncContextRouterDisabled atomically increments the disabled counter.
func IncContextRouterHeuristic ¶ added in v1.18.0
func IncContextRouterHeuristic()
IncContextRouterHeuristic atomically increments the heuristic counter.
func IncContextRouterMapped ¶ added in v1.18.0
func IncContextRouterMapped()
IncContextRouterMapped atomically increments the mapped counter.
func IncL1CacheHit ¶ added in v1.18.0
func IncL1CacheHit()
IncL1CacheHit increments the L1 essential story cache-hit counter.
func IncL1CacheMiss ¶ added in v1.18.0
func IncL1CacheMiss()
IncL1CacheMiss increments the L1 essential story cache-miss counter.
func IncLayerTokensL0 ¶ added in v1.18.0
func IncLayerTokensL0(n int)
IncLayerTokensL0 adds n to the L0 layer byte counter.
func IncLayerTokensL1 ¶ added in v1.18.0
func IncLayerTokensL1(n int)
IncLayerTokensL1 adds n to the L1 layer byte counter.
func IncLayerTokensL2 ¶ added in v1.18.0
func IncLayerTokensL2(n int)
IncLayerTokensL2 adds n to the L2 layer byte counter.
func IncSaveWingRouted ¶ added in v1.18.0
func IncSaveWingRouted()
IncSaveWingRouted increments the count of memory_save calls that successfully routed a wing via context or explicit argument.
func IncSearchWithWingFilter ¶ added in v1.18.0
func IncSearchWithWingFilter()
IncSearchWithWingFilter atomically increments the wing-filtered search counter.
func IncSearchWithoutWingFilter ¶ added in v1.18.0
func IncSearchWithoutWingFilter()
IncSearchWithoutWingFilter atomically increments the unfiltered search counter.
func IncToolCall ¶ added in v1.18.0
func IncToolCall(name string)
IncToolCall atomically increments the counter for a given palace tool name. Unknown names are ignored (no-op) rather than creating new counters at runtime — this keeps the metric cardinality bounded.
func InferProfileForChannel ¶ added in v1.13.0
InferProfileForChannel returns the default tool profile name for a channel. Messaging channels (WhatsApp, Discord, Telegram, Slack) get "messaging" to avoid exposing filesystem/runtime tools. WebUI and CLI get "full". Named instances (e.g. "whatsapp:business") are matched by their base type.
func InferToolCategory ¶ added in v1.12.0
InferToolCategory determines the category of a tool from its name. Used for grouping tools in the system prompt and list_capabilities output.
func IsAbortRequestText ¶ added in v1.12.0
IsAbortRequestText checks if text is an abort request, handling both /stop command and natural language triggers.
func IsAbortTrigger ¶ added in v1.12.0
IsAbortTrigger checks if the given text is a standalone abort trigger. It normalizes the text by: - Converting to lowercase - Normalizing unicode (NFKC) - Stripping mentions and structural prefixes - Removing trailing punctuation - Collapsing whitespace
func IsEnvReference ¶
IsEnvReference checks if a string is an environment variable reference.
func IsLikelyContextOverflowError ¶ added in v1.13.0
IsLikelyContextOverflowError returns true if the error message indicates a context window overflow. Context overflow errors should NOT trigger model failover because rotating to a model with a potentially smaller context window makes things worse. Aligned with OpenClaw's isLikelyContextOverflowError + isContextOverflowError.
func IsMutatingToolCall ¶ added in v1.13.0
IsMutatingToolCall checks if a specific tool call is mutating by examining the tool name and its action parameter (if present).
func IsMutatingToolName ¶ added in v1.13.0
IsMutatingToolName returns true if the tool is generally a mutating tool.
func IsRecoverableToolError ¶ added in v1.13.0
IsRecoverableToolError returns true if the error message suggests a recoverable issue (missing params, invalid input, transient failure) vs a hard failure that the model cannot recover from.
func KeyringAvailable ¶
func KeyringAvailable() bool
KeyringAvailable checks if the OS keyring is accessible.
func ListProfiles ¶
func ListProfiles(customProfiles map[string]ToolProfile) []string
ListProfiles returns all available profile names.
func LooksLikeCredential ¶ added in v1.18.0
LooksLikeCredential is the exported version for use by the security package.
func MakeSessionID ¶
MakeSessionID returns a compact hash-based session ID from channel and chatID. For backward compatibility, this is still used as the primary key.
func MatchesPattern ¶
MatchesPattern checks if a tool name matches a pattern. Supports glob-style wildcards: "git_*" matches "git_status", "git_commit", etc.
func MessageIDFromCtx ¶ added in v1.14.0
MessageIDFromCtx extracts the triggering message ID from context.
func MicroCompact ¶ added in v1.17.0
MicroCompact replaces old tool result contents with a placeholder to free context tokens without requiring an LLM summarization call. Clears any tool result that is large enough (>200 chars) in the older part of the conversation. Short results (e.g. "file written successfully") are kept as they consume negligible tokens.
keepLastN specifies how many recent messages to protect from clearing. Returns the modified messages and the number of results cleared.
func MicroCompactByRatio ¶ added in v1.17.0
func MicroCompactByRatio(messages []chatMessage, ratio float64, cfg ContextPruningConfig) ([]chatMessage, int)
MicroCompactByRatio applies micro-compaction using the context pruning config ratios. Tools older than the protect window are cleared based on the usage ratio:
- Above softTrimRatio: trim head+tail to SoftTrimMaxChars
- Above hardClearRatio: replace with placeholder entirely
func MigrateKeyToKeyring ¶
MigrateKeyToKeyring moves an API key from config/env to the OS keyring and clears it from the original location.
func MigrateToSQLite ¶
MigrateToSQLite imports legacy JSON/JSONL data into the central database. It is safe to call multiple times: once the .bak file exists, migration is skipped for that component. Called once from assistant.Start().
func NormalizeTelegramID ¶ added in v1.16.5
NormalizeTelegramID is exported for use by API handlers.
func OpenDatabase ¶
OpenDatabase opens (or creates) the central devclaw.db at the given path. It enables WAL mode for concurrent read performance and creates all tables.
func ProvenanceReason ¶ added in v1.18.2
func ProvenanceReason(content string, outcomes []ToolOutcome) string
ProvenanceReason returns a non-empty reason string if `content` should be rejected as a fact save because it echoes the subject of a tool call that failed earlier in this turn AND no later successful call on the same subject has been observed.
The comparison uses generic token overlap (identifier-like tokens of length ≥ 3, with a small locale-agnostic stopword set). No tool-specific names, no error-phrase keywords, no PT/EN heuristics.
func ReadPassword ¶
ReadPassword reads a password from the terminal without echoing. Falls back to regular stdin reading if terminal is not available.
func RedactCredentials ¶ added in v1.18.0
RedactCredentials is the exported version for use by the security package.
func RegisterAgentTools ¶ added in v1.16.0
func RegisterAgentTools(executor *ToolExecutor, wsMgr *WorkspaceManager)
RegisterAgentTools registers the agent_manage dispatcher tool.
func RegisterApplyPatchTool ¶ added in v1.12.0
func RegisterApplyPatchTool(executor *ToolExecutor)
RegisterApplyPatchTool registers the apply_patch tool in the executor.
func RegisterBrowserTools ¶
func RegisterBrowserTools(executor *ToolExecutor, browserMgr *BrowserManager, llmClient *LLMClient, mediaCfg MediaConfig, logger *slog.Logger)
RegisterBrowserTools registers browser automation tools in the executor. If llmClient is provided and vision is enabled, browser_screenshot will automatically describe the image using vision instead of returning raw base64.
func RegisterCanvasTools ¶
func RegisterCanvasTools(executor *ToolExecutor, canvasHost *CanvasHost, logger *slog.Logger)
RegisterCanvasTools registers canvas tools in the executor.
func RegisterCodebaseTools ¶
func RegisterCodebaseTools(executor *ToolExecutor)
RegisterCodebaseTools registers codebase analysis tools in the executor.
func RegisterDBHubTools ¶ added in v1.8.0
func RegisterDBHubTools(executor *ToolExecutor, hub *database.Hub)
RegisterDBHubTools registers database hub management tools. These tools operate on the internal database hub, not external databases.
func RegisterDBTools ¶
func RegisterDBTools(executor *ToolExecutor)
RegisterDBTools registers database query and management tools.
func RegisterDaemonTools ¶
func RegisterDaemonTools(executor *ToolExecutor, dm *DaemonManager)
RegisterDaemonTools registers a single "daemon" dispatcher tool that consolidates start, logs, list, stop, restart actions.
func RegisterDevUtilTools ¶
func RegisterDevUtilTools(executor *ToolExecutor)
RegisterDevUtilTools registers developer utility tools.
func RegisterDockerTools ¶
func RegisterDockerTools(executor *ToolExecutor)
RegisterDockerTools registers Docker management tools in the executor.
func RegisterEnvTools ¶
func RegisterEnvTools(executor *ToolExecutor)
RegisterEnvTools registers system information and diagnostic tools.
func RegisterGitTools ¶
func RegisterGitTools(executor *ToolExecutor)
RegisterGitTools registers native Git tools in the executor.
func RegisterIDETools ¶
func RegisterIDETools(executor *ToolExecutor)
RegisterIDETools registers IDE extension configuration tools.
func RegisterKGTools ¶ added in v1.18.0
func RegisterKGTools(executor *ToolExecutor, sqliteStore *memory.SQLiteStore)
RegisterKGTools registers the 6 knowledge-graph tools.
func RegisterLCMDispatcher ¶ added in v1.14.0
func RegisterLCMDispatcher(executor *ToolExecutor, engine *LCMEngine, llm *LLMClient)
RegisterLCMDispatcher registers the `lcm` tool for lossless memory retrieval. The llm parameter is optional; when nil, the expand_query action is unavailable.
func RegisterLegacyAliases ¶ added in v1.13.0
func RegisterLegacyAliases(executor *ToolExecutor)
RegisterLegacyAliases registers dispatcher tools. Memory, vault, and scheduler are visible (primary tools); skill_manage is hidden (backward compat only).
func RegisterMediaTools ¶
func RegisterMediaTools(executor *ToolExecutor, llmClient *LLMClient, cfg *Config, logger *slog.Logger)
RegisterMediaTools registers describe_image and transcribe_audio tools when the LLM client and config support them. If VisionProviders or TranscriptionProviders are configured in MediaConfig, a MediaRegistry is used for priority-based fallback across multiple providers.
func RegisterMemoryHierarchyTools ¶ added in v1.18.0
func RegisterMemoryHierarchyTools(executor *ToolExecutor, cfg MemoryHierarchyDispatcherConfig)
RegisterMemoryHierarchyTools registers the six palace-aware memory tools on the given ToolExecutor. This is additive — existing memory tools are not touched.
The registration happens unconditionally (even when cfg.Enabled is false) so that the LLM always sees the tools in its schema. At call time, each tool checks the flag and returns errHierarchyDisabled if off.
func RegisterMemoryTools ¶ added in v1.12.0
func RegisterMemoryTools(executor *ToolExecutor, cfg MemoryDispatcherConfig)
RegisterMemoryTools registers individual memory tools. Replaces the old dispatcher pattern with focused tools: memory_save, memory_search, memory_list, memory_index.
func RegisterMultiUserTools ¶
func RegisterMultiUserTools(executor *ToolExecutor, um *UserManager)
RegisterMultiUserTools registers multi-user management tools.
func RegisterNativeMediaTools ¶ added in v1.8.0
func RegisterNativeMediaTools(executor *ToolExecutor, mediaSvc *media.MediaService, channelMgr *channels.Manager, logger *slog.Logger)
RegisterNativeMediaTools registers the unified send_media tool for the LLM to send media (images, audio, documents, video) to users through the channel manager. mediaSvc may be nil — in that case only file_path is supported (no media_id or url); this ensures the send_media tool is always available when channels are connected.
func RegisterOpsTools ¶
func RegisterOpsTools(executor *ToolExecutor)
RegisterOpsTools registers operations and deployment tools.
func RegisterPluginAgentDelegation ¶ added in v1.16.0
func RegisterPluginAgentDelegation( executor *ToolExecutor, registry *plugins.Registry, subagentMgr *SubagentManager, llmClient *LLMClient, )
RegisterPluginAgentDelegation registers the full plugin agent delegation with access to the SubagentManager and LLMClient. Called after Start().
func RegisterPluginManagementTools ¶ added in v1.16.0
func RegisterPluginManagementTools(executor *ToolExecutor, registry *plugins.Registry)
RegisterPluginManagementTools registers tools for managing plugins at runtime.
func RegisterProductTools ¶
func RegisterProductTools(executor *ToolExecutor)
RegisterProductTools registers product management tools.
func RegisterSchedulerDispatcher ¶ added in v1.13.0
func RegisterSchedulerDispatcher(executor *ToolExecutor, sched *scheduler.Scheduler, skillDB *SkillDB)
RegisterSchedulerDispatcher registers individual scheduler tools: scheduler_add, scheduler_list, scheduler_remove, and scheduler_search.
func RegisterSessionsDispatcher ¶ added in v1.13.0
func RegisterSessionsDispatcher(executor *ToolExecutor, wm *WorkspaceManager)
RegisterSessionsDispatcher registers a single "sessions" dispatcher tool that replaces sessions_list, sessions_delete, sessions_export, sessions_send.
func RegisterSessionsYieldTool ¶ added in v1.14.0
func RegisterSessionsYieldTool(executor *ToolExecutor)
RegisterSessionsYieldTool registers the sessions_yield tool that allows an agent to end its current turn and receive pending subagent results. The tool signals the agent loop via the AgentRun's yieldRequested flag.
func RegisterSkillCreatorTools ¶
func RegisterSkillCreatorTools(executor *ToolExecutor, registry *skills.Registry, skillsDir string, skillDB *SkillDB, builtinSkills *BuiltinSkills, reloadCb SkillReloadCallback, logger *slog.Logger)
RegisterSkillCreatorTools registers individual skill management tools. Replaces the old dispatcher pattern with focused tools: skill_init, skill_edit, skill_add_script, skill_list, skill_test, skill_install, skill_defaults_list, skill_defaults_install, skill_remove, get_skill_instructions, get_skill_reference.
func RegisterSkillDBTools ¶ added in v1.12.0
func RegisterSkillDBTools(executor *ToolExecutor, skillDB *SkillDB)
RegisterSkillDBTools registers the skill database tools in the executor. Each database operation is registered as its own tool with a focused schema.
func RegisterSubagentTools ¶
func RegisterSubagentTools( executor *ToolExecutor, manager *SubagentManager, llmClient *LLMClient, promptComposer *PromptComposer, logger *slog.Logger, )
RegisterSubagentTools registers the spawn_subagent, list_subagents, wait_subagent, and stop_subagent tools in the tool executor. These allow the main agent to create and manage child agents.
func RegisterSystemTools ¶
func RegisterSystemTools(executor *ToolExecutor, sandboxRunner *sandbox.Runner, memStore *memory.FileStore, sqliteStore *memory.SQLiteStore, memCfg MemoryConfig, contextRouter *ContextRouter, sched *scheduler.Scheduler, dataDir string, ssrfGuard *security.SSRFGuard, vault *Vault, webSearchCfg WebSearchConfig, skillDB *SkillDB, gatewayCfg GatewayConfig, toolGuardCfg ToolGuardConfig)
RegisterSystemTools registers all built-in system tools in the executor. These are core tools available regardless of which skills are loaded. If ssrfGuard is non-nil, web_fetch will validate URLs against SSRF rules. contextRouter may be nil; when non-nil it is forwarded to the memory tools so that memory_save can route new memories to palace wings (Sprint 2 Room 2.0b).
func RegisterTestingTools ¶
func RegisterTestingTools(executor *ToolExecutor)
RegisterTestingTools registers testing engine tools.
func RegisterVaultTools ¶ added in v1.13.0
func RegisterVaultTools(executor *ToolExecutor, vault *Vault)
RegisterVaultTools registers individual vault tools. Replaces the old dispatcher pattern with focused tools: vault_status, vault_save, vault_get, vault_list, vault_delete.
func ReloadEnvFiles ¶
ReloadEnvFiles forces a reload of .env files with override. Returns the number of variables loaded.
func RepairToolUseResultPairing ¶ added in v1.13.0
func RepairToolUseResultPairing(messages []chatMessage) []chatMessage
RepairToolUseResultPairing scans messages and removes orphan tool results (tool_result messages whose corresponding tool_use was removed) and orphan tool_use calls (assistant tool calls with no matching tool result). This prevents API rejections from providers that require strict pairing.
func ResolveContextWindowTokens ¶ added in v1.13.0
ResolveContextWindowTokens determines the effective context window for a model. Priority: configOverride > discovered (via provider discovery) > static lookup > default.
func ResolveProfile ¶
func ResolveProfile(name string, customProfiles map[string]ToolProfile) (allow, deny []string)
ResolveProfile returns the allow and deny lists for a profile. Checks built-in profiles first, then custom profiles. Returns nil lists if profile not found.
func ResolveSecrets ¶ added in v1.16.5
func ResolveSecrets(cfg *Config)
ResolveSecrets fills in config secrets from environment variables when the config value is empty or a placeholder. Called during initial config load and again after vault injection.
func RunAsync ¶ added in v1.12.0
func RunAsync(ctx context.Context, config AsyncToolConfig, fn func(ctx context.Context) *ToolResult)
RunAsync executes a function in the background and calls the callback when done. This is a helper for tools that need to run long operations asynchronously.
The function returns immediately with an AsyncResult. The actual work happens in a background goroutine, and the callback is invoked when complete.
The context is propagated to the async function, so cancellation of the parent context will also cancel the async operation.
Example:
func myAsyncTool(ctx context.Context, args map[string]any) (any, error) {
config := AsyncToolConfig{
Label: "processing files",
OnComplete: func(result *ToolResult) {
// Handle completion - e.g., send to user
},
}
RunAsync(ctx, config, func(ctx context.Context) *ToolResult {
// Long-running operation
return &ToolResult{Content: "done"}
})
return AsyncResult("Started processing files..."), nil
}
func SanitizeMemoryContent ¶
SanitizeMemoryContent escapes HTML entities and strips dangerous patterns from memory content before injection into prompts.
func SanitizeToolCallID ¶ added in v1.13.0
func SanitizeToolCallID(id string, mode ToolCallIDMode) string
SanitizeToolCallID cleans a tool call ID to be safe for the target provider.
func SaveConfigToFile ¶
SaveConfigToFile writes a Config as YAML to the specified path. Secrets are replaced with environment variable references. Creates a backup (.bak) of the existing file before overwriting to prevent data loss from crashes or invalid writes.
func ScaffoldWorkspaceDir ¶ added in v1.16.0
ScaffoldWorkspaceDir creates the workspace directory and seeds template files. Files are written only if they don't exist (preserves user edits). If ws has Soul/Identity content, those are written instead of templates.
func ScaledMaxRetries ¶ added in v1.13.0
ScaledMaxRetries computes a retry budget scaled by the number of available auth profiles. More profiles = more credential rotation capacity, so the system can afford more retries before giving up on a transient failure. Formula: min(160, max(32, 24 + profileCount * 8))
func SessionIDFromContext ¶
SessionIDFromContext extracts the session ID from a context. Returns empty string if not set.
func SetGlobalMediaRegistry ¶ added in v1.13.0
func SetGlobalMediaRegistry(r *MediaRegistry)
SetGlobalMediaRegistry sets the global media registry instance.
func SkillNeedsSetup ¶ added in v1.12.0
func SkillNeedsSetup(skill skills.Skill, vault skills.VaultReader) bool
SkillNeedsSetup returns true if a skill requires configuration that is missing.
func Slugify ¶ added in v1.16.0
Slugify converts a name to a URL-friendly slug (lowercase, hyphens).
func SpawnDepthFromContext ¶ added in v1.8.0
SpawnDepthFromContext retrieves the current spawn depth from context. Returns 0 if not set (main agent level).
func SplitMessage ¶
SplitMessage splits a long message into chunks respecting maxLen. Tries to break on paragraph boundaries, then sentence boundaries, then word boundaries. Does not split inside ``` code blocks.
func StartPersistentSessionReaper ¶ added in v1.13.0
func StartPersistentSessionReaper(ctx context.Context, storePath string, maxAgeDays int, logger *slog.Logger)
StartPersistentSessionReaper runs a background goroutine that deletes session files older than maxAgeDays. It runs once daily and on startup. storePath is the directory containing session JSONL/SQLite files.
func StoreKeyring ¶
StoreKeyring saves a secret to the OS keyring.
func StripDangerousTags ¶ added in v1.13.0
StripDangerousTags removes XML/HTML-like tags that could confuse the LLM into treating content as structured instructions.
func StripExternalContentBoundaries ¶
StripExternalContentBoundaries removes the untrusted content wrappers (useful when preparing content for display to the user).
func StripInternalTags ¶
StripInternalTags removes all internal control tags and sentinel tokens from LLM output so they never reach the user. Handles:
- [[reply_to_*]] delivery tags
- <final>...</final> and <thinking>...</thinking> XML tags
- [Tools used: ...] annotations (LLM may mimic the history format)
- [Previous tool calls in this turn:] + tool call lines (history context leak)
- Fake "System: ..." messages fabricated by the LLM
- NO_REPLY / HEARTBEAT_OK sentinel tokens
func StripReplyTags ¶
StripReplyTags is an alias for StripInternalTags for backward compatibility.
func SynthesizeFindings ¶ added in v1.17.0
func SynthesizeFindings(results []WorkerResult) string
SynthesizeFindings combines research results into a summary for the coordinator.
func SynthesizeProgressSummary ¶ added in v1.16.0
SynthesizeProgressSummary builds a concise summary from collected assistant fragments. Used by subagent timeout handling to report partial progress instead of a generic timeout message.
func TruncateToolResult ¶ added in v1.13.0
TruncateToolResult applies smart truncation to a single tool result. When important tail content is detected, it uses a head+tail strategy; otherwise it uses head-only truncation.
func ValidateIdentity ¶ added in v1.13.0
func ValidateIdentity(id IdentityConfig) []string
ValidateIdentity checks for common issues in an identity configuration. Returns a list of warnings (empty = valid).
func VaultReaderFromContext ¶ added in v1.12.0
func VaultReaderFromContext(ctx context.Context) skills.VaultReader
VaultReaderFromContext extracts the vault reader from context. Returns nil if not set.
func WorkspaceIDFromContext ¶ added in v1.16.0
WorkspaceIDFromContext extracts the workspace ID from context.
func WrapExternalContent ¶
WrapExternalContent wraps content from external sources (web_fetch, browser, web_search) with untrusted content boundaries to prevent prompt injection replay during compaction.
func WrapMemoriesForPrompt ¶
WrapMemoriesForPrompt wraps sanitized memory entries with the untrusted data boundary so the LLM treats them as historical context, not instructions.
Types ¶
type APIConfig ¶
type APIConfig struct {
// BaseURL is the API base URL (OpenAI-compatible endpoint).
// Examples:
// https://api.openai.com/v1 (OpenAI)
// https://api.z.ai/api/anthropic (GLM / Anthropic proxy)
// https://api.anthropic.com/v1 (Anthropic direct)
BaseURL string `yaml:"base_url"`
// APIKey is the authentication key for the provider.
// Can also be set via the DEVCLAW_API_KEY environment variable.
APIKey string `yaml:"api_key"`
// Provider hints which SDK to use ("openai", "anthropic", "glm").
// Auto-detected from base_url if omitted.
Provider string `yaml:"provider"`
// Params holds provider-specific parameters:
// context1m: true — enable Anthropic 1M context beta for Opus/Sonnet
// tool_stream: true — enable real-time tool call streaming (Z.AI)
Params map[string]any `yaml:"params"`
}
APIConfig configures the LLM provider endpoint and credentials.
type AXNode ¶ added in v1.13.0
type AXNode struct {
NodeID string `json:"nodeId"`
Role AXRole `json:"role"`
Name AXValue `json:"name,omitempty"`
Value AXValue `json:"value,omitempty"`
Description AXValue `json:"description,omitempty"`
Properties any `json:"properties,omitempty"`
Children []*AXNode `json:"children,omitempty"`
// Ref is the generated reference (e1, e2, ...) for interactive elements.
Ref string `json:"ref,omitempty"`
}
AXNode represents a node in the accessibility tree from CDP.
type AXRole ¶ added in v1.13.0
type AXRole struct {
Value string
}
AXRole is a custom type that can unmarshal from either a string or an object. Chrome CDP sometimes returns role as {"type": "role", "value": "button"} and sometimes as just "button".
func (*AXRole) UnmarshalJSON ¶ added in v1.13.0
UnmarshalJSON implements json.Unmarshaler for AXRole.
type AXValue ¶ added in v1.13.0
type AXValue struct {
Value string
}
AXValue is a custom type that can unmarshal from either a string or an object. Chrome CDP sometimes returns name/value as {"type": "string", "value": "text"} and sometimes as just "text".
func (*AXValue) UnmarshalJSON ¶ added in v1.13.0
UnmarshalJSON implements json.Unmarshaler for AXValue.
type AccessConfig ¶
type AccessConfig struct {
// DefaultPolicy determines behavior for unknown contacts.
// "deny" (default) = ignore unknown, "allow" = respond to all, "ask" = request access.
DefaultPolicy AccessPolicy `yaml:"default_policy"`
// Owners have full control (phone numbers or JIDs).
Owners []string `yaml:"owners"`
// Admins can manage users and workspaces.
Admins []string `yaml:"admins"`
// AllowedUsers can interact with the bot.
AllowedUsers []string `yaml:"allowed_users"`
// BlockedUsers are explicitly blocked.
BlockedUsers []string `yaml:"blocked_users"`
// AllowedGroups are group IDs where the bot responds.
AllowedGroups []string `yaml:"allowed_groups"`
// BlockedGroups are group IDs where the bot stays silent.
BlockedGroups []string `yaml:"blocked_groups"`
// AllowGroupAdmins grants "user" access to group admins automatically.
AllowGroupAdmins bool `yaml:"allow_group_admins"`
// PendingMessage is the message sent to unknown contacts when policy is "ask".
PendingMessage string `yaml:"pending_message"`
}
AccessConfig holds the access control configuration.
func DefaultAccessConfig ¶
func DefaultAccessConfig() AccessConfig
DefaultAccessConfig returns the default access control config.
type AccessEntry ¶
type AccessEntry struct {
// JID is the contact identifier (phone@server or group@server).
JID string
// Level is the access level.
Level AccessLevel
// AddedBy is the JID of the admin/owner who granted access.
AddedBy string
// AddedAt is when access was granted.
AddedAt time.Time
// Note is an optional admin note about this contact.
Note string
}
AccessEntry represents a contact in the access list.
type AccessLevel ¶
type AccessLevel string
AccessLevel defines the permission level of a contact.
const ( AccessOwner AccessLevel = "owner" AccessAdmin AccessLevel = "admin" AccessUser AccessLevel = "user" AccessBlocked AccessLevel = "blocked" AccessNone AccessLevel = "none" AccessUnknown AccessLevel = "" )
func CallerLevelFromContext ¶
func CallerLevelFromContext(ctx context.Context) AccessLevel
CallerLevelFromContext extracts the caller access level from context. Falls back to AccessNone if not set.
type AccessManager ¶
type AccessManager struct {
// contains filtered or unexported fields
}
AccessManager handles access control for incoming messages.
func NewAccessManager ¶
func NewAccessManager(cfg AccessConfig, logger *slog.Logger) *AccessManager
NewAccessManager creates a new access manager from config.
func (*AccessManager) ApplyConfig ¶
func (am *AccessManager) ApplyConfig(cfg AccessConfig)
ApplyConfig updates access config from hot-reload. Re-seeds config-derived entries (owners, admins, allowed, blocked, groups). Runtime grants (AddedBy != "config") are preserved.
func (*AccessManager) Block ¶
func (am *AccessManager) Block(jid string, blockedBy string)
Block explicitly blocks a contact.
func (*AccessManager) Check ¶
func (am *AccessManager) Check(msg *channels.IncomingMessage) CheckResult
Check evaluates whether an incoming message should be processed. This is the main entry point called before any message handling.
func (*AccessManager) DefaultPolicy ¶ added in v1.16.5
func (am *AccessManager) DefaultPolicy() AccessPolicy
DefaultPolicy returns the current default access policy.
func (*AccessManager) GetLevel ¶
func (am *AccessManager) GetLevel(jid string) AccessLevel
GetLevel returns the access level for a JID.
func (*AccessManager) Grant ¶
func (am *AccessManager) Grant(jid string, level AccessLevel, grantedBy string) error
Grant gives access to a contact at the specified level.
func (*AccessManager) GrantGroup ¶
func (am *AccessManager) GrantGroup(groupJID string, level AccessLevel, grantedBy string) error
GrantGroup gives access to a group.
func (*AccessManager) IsAdmin ¶
func (am *AccessManager) IsAdmin(jid string) bool
IsAdmin returns true if the JID is an admin or owner.
func (*AccessManager) IsOwner ¶
func (am *AccessManager) IsOwner(jid string) bool
IsOwner returns true if the JID is an owner.
func (*AccessManager) ListGroups ¶
func (am *AccessManager) ListGroups() []*AccessEntry
ListGroups returns all group access entries.
func (*AccessManager) ListGroupsByChannel ¶ added in v1.16.5
func (am *AccessManager) ListGroupsByChannel(suffix string) []*AccessEntry
ListGroupsByChannel returns group access entries filtered by channel suffix.
func (*AccessManager) ListUsers ¶
func (am *AccessManager) ListUsers() []*AccessEntry
ListUsers returns all access entries.
func (*AccessManager) ListUsersByChannel ¶ added in v1.16.5
func (am *AccessManager) ListUsersByChannel(suffix string) []*AccessEntry
ListUsersByChannel returns access entries filtered by channel suffix. For Telegram, pass "@telegram"; for WhatsApp, pass "@s.whatsapp.net". An empty suffix returns all entries.
func (*AccessManager) MarkAsked ¶
func (am *AccessManager) MarkAsked(jid string)
MarkAsked records that we sent the "pending" message to a contact.
func (*AccessManager) PendingMessage ¶
func (am *AccessManager) PendingMessage() string
PendingMessage returns the message to send to unknown contacts.
func (*AccessManager) Revoke ¶
func (am *AccessManager) Revoke(jid string, revokedBy string)
Revoke removes access from a contact.
func (*AccessManager) SetDefaultPolicy ¶ added in v1.16.5
func (am *AccessManager) SetDefaultPolicy(policy AccessPolicy)
SetDefaultPolicy updates the default access policy at runtime.
func (*AccessManager) Unblock ¶
func (am *AccessManager) Unblock(jid string, unblockedBy string)
Unblock removes a block from a contact.
type AccessPolicy ¶
type AccessPolicy string
AccessPolicy defines how unknown contacts are handled.
const ( // PolicyDeny silently ignores unknown contacts (default). PolicyDeny AccessPolicy = "deny" // PolicyAllow responds to everyone not explicitly blocked. PolicyAllow AccessPolicy = "allow" // PolicyAsk sends a one-time "request access" message to unknown contacts. PolicyAsk AccessPolicy = "ask" )
type ActRequest ¶ added in v1.13.0
type ActRequest struct {
Kind string `json:"kind"`
Ref string `json:"ref,omitempty"` // Element reference (e1, e2, ...)
Selector string `json:"selector,omitempty"` // CSS selector (alternative to ref)
// For type
Text string `json:"text,omitempty"`
// For press
Key string `json:"key,omitempty"`
// For drag
StartRef string `json:"start_ref,omitempty"`
EndRef string `json:"end_ref,omitempty"`
// For select
Values []string `json:"values,omitempty"`
// For fill (form fields)
Fields []FormField `json:"fields,omitempty"`
// For resize
Width int `json:"width,omitempty"`
Height int `json:"height,omitempty"`
// For wait
TimeMs int `json:"time_ms,omitempty"`
TextGone string `json:"text_gone,omitempty"`
// For evaluate
Function string `json:"fn,omitempty"`
// Modifiers (for click)
DoubleClick bool `json:"double_click,omitempty"`
Button string `json:"button,omitempty"` // left, right, middle
Modifiers []string `json:"modifiers,omitempty"`
// For type
Submit bool `json:"submit,omitempty"` // Press Enter after typing
Slowly bool `json:"slowly,omitempty"` // Type character by character
}
ActRequest represents a browser action request.
type ActivationMode ¶
type ActivationMode string
ActivationMode defines how the bot activates in a group.
const ( // ActivationAlways responds to all messages. ActivationAlways ActivationMode = "always" // ActivationMention responds only when mentioned. ActivationMention ActivationMode = "mention" // ActivationReply responds only when replying to bot's messages. ActivationReply ActivationMode = "reply" // ActivationKeyword responds when keywords are detected. ActivationKeyword ActivationMode = "keyword" )
type AddFileHunk ¶ added in v1.12.0
AddFileHunk represents adding a new file.
type AgentConfig ¶
type AgentConfig struct {
// RunTimeoutSeconds is the max seconds for the entire agent run (default: 600).
// One timer for the whole run, not per-turn.
RunTimeoutSeconds int `yaml:"run_timeout_seconds"`
// LLMCallTimeoutSeconds is the safety-net timeout per individual LLM call
// (default: 300). Only catches hung connections — not the primary timeout.
LLMCallTimeoutSeconds int `yaml:"llm_call_timeout_seconds"`
// MaxTurns is a soft safety limit on LLM round-trips (default: 25).
// When > 0, the agent will request a summary after this many turns.
// Set to 0 for unlimited (not recommended in production).
MaxTurns int `yaml:"max_turns"`
// MaxContinuations is how many auto-continue rounds are allowed when
// MaxTurns is hit and the agent is still using tools.
// Only relevant when MaxTurns > 0. Default: 2.
MaxContinuations int `yaml:"max_continuations"`
// ReflectionEnabled enables periodic budget awareness nudges (default: true).
ReflectionEnabled bool `yaml:"reflection_enabled"`
// MaxCompactionAttempts is how many times to retry after context overflow (default: 3).
MaxCompactionAttempts int `yaml:"max_compaction_attempts"`
// ContextTokens overrides the auto-detected context window size for the model.
// When > 0, this value is used instead of the built-in model-specific lookup.
// Set this for custom/fine-tuned models or when using an unusual context window.
ContextTokens int `yaml:"context_tokens"`
// ToolVerbose controls whether tool progress messages are sent to the user.
// Default "off" means only the final response is shown (OpenClaw-aligned).
ToolVerbose VerboseLevel `yaml:"tool_verbose"`
// ToolLoop configures tool loop detection thresholds.
ToolLoop ToolLoopConfig `yaml:"tool_loop"`
// MemoryFlush configures pre-compaction memory flush behavior.
MemoryFlush MemoryFlushConfig `yaml:"memory_flush"`
// Compaction configures how context compaction preserves important information.
Compaction CompactionConfig `yaml:"compaction"`
// KG configures Knowledge Graph extraction during compaction and dream cycles.
KG KGAgentConfig `yaml:"kg"`
}
AgentConfig holds configurable agent loop parameters.
func DefaultAgentConfig ¶
func DefaultAgentConfig() AgentConfig
DefaultAgentConfig returns sensible defaults for agent autonomy.
type AgentEvent ¶
type AgentEvent struct {
RunID string `json:"run_id"`
SessionID string `json:"session_id"`
Seq int64 `json:"seq"`
Stream string `json:"stream"` // lifecycle, assistant, tool, error
Type string `json:"type"` // delta, tool_use, tool_result, done, error, run_start, etc.
Timestamp time.Time `json:"timestamp"`
Data any `json:"data"`
}
AgentEvent represents a single typed event from an agent run.
type AgentProfileConfig ¶
type AgentProfileConfig struct {
// ID is the unique identifier for this agent profile.
ID string `yaml:"id"`
// Model is the LLM model to use (e.g., "gpt-4o", "claude-sonnet-4").
Model string `yaml:"model"`
// Instructions override the base system prompt for this agent.
Instructions string `yaml:"instructions"`
// Skills are the skill names to enable for this agent.
Skills []string `yaml:"skills"`
// Channels route messages from these channels to this agent.
Channels []string `yaml:"channels"`
// Users route messages from these users to this agent.
Users []string `yaml:"users"`
// Groups route messages from these groups to this agent.
Groups []string `yaml:"groups"`
// MaxTurns is the max LLM turns for this agent (0 = unlimited).
MaxTurns int `yaml:"max_turns"`
// RunTimeoutSeconds is the max run time for this agent.
RunTimeoutSeconds int `yaml:"run_timeout_seconds"`
// Identity overrides the global identity for this agent profile.
Identity *IdentityConfig `yaml:"identity,omitempty"`
}
AgentProfileConfig defines a specialized agent configuration.
func (*AgentProfileConfig) MergeConfig ¶
func (p *AgentProfileConfig) MergeConfig(baseModel, baseInstructions string, baseSkills []string) (model, instructions string, skills []string)
MergeConfig merges agent profile settings with the base config. Returns the model, instructions, and skills to use.
type AgentRouter ¶
type AgentRouter struct {
// contains filtered or unexported fields
}
AgentRouter routes messages to the appropriate agent profile.
func NewAgentRouter ¶
func NewAgentRouter(cfg AgentsConfig, logger *slog.Logger) *AgentRouter
NewAgentRouter creates a new agent router from configuration.
func (*AgentRouter) AddProfile ¶ added in v1.16.0
func (r *AgentRouter) AddProfile(p *AgentProfileConfig)
AddProfile registers a new agent profile at runtime (e.g. from plugins).
func (*AgentRouter) DefaultProfileID ¶
func (r *AgentRouter) DefaultProfileID() string
DefaultProfileID returns the default profile ID.
func (*AgentRouter) GetProfile ¶
func (r *AgentRouter) GetProfile(id string) *AgentProfileConfig
GetProfile returns a profile by ID.
func (*AgentRouter) ListProfiles ¶
func (r *AgentRouter) ListProfiles() []string
ListProfiles returns all profile IDs.
func (*AgentRouter) Route ¶
func (r *AgentRouter) Route(channel string, userJID string, groupJID string) *AgentProfileConfig
Route determines which agent profile should handle a message. Priority: user > group > channel > default.
type AgentRun ¶
type AgentRun struct {
// contains filtered or unexported fields
}
AgentRun encapsulates a single agent execution with its dependencies.
func AgentRunFromCtx ¶ added in v1.14.0
AgentRunFromCtx extracts the AgentRun from context.
func NewAgentRun ¶
func NewAgentRun(llm *LLMClient, executor *ToolExecutor, logger *slog.Logger) *AgentRun
NewAgentRun creates a new agent runner.
func NewAgentRunWithConfig ¶
func NewAgentRunWithConfig(llm *LLMClient, executor *ToolExecutor, cfg AgentConfig, logger *slog.Logger) *AgentRun
NewAgentRunWithConfig creates a new agent runner with explicit configuration.
func (*AgentRun) CollectedAssistantFragments ¶ added in v1.16.0
CollectedAssistantFragments returns assistant response fragments collected during the agent run, for partial progress synthesis on timeout.
func (*AgentRun) CollectedToolCalls ¶ added in v1.13.0
func (a *AgentRun) CollectedToolCalls() []ToolCallRecord
CollectedToolCalls returns the individual tool call records collected during the run.
func (*AgentRun) Run ¶
func (a *AgentRun) Run(ctx context.Context, systemPrompt string, history []ConversationEntry, userMessage string) (string, error)
Run executes the agent loop: builds the initial message list from conversation history, then iterates LLM calls and tool executions until a final response is produced or the turn limit is exhausted.
If auto-continue is enabled and the agent is still using tools when the budget runs out, it will automatically start a continuation round.
func (*AgentRun) RunWithUsage ¶
func (a *AgentRun) RunWithUsage(ctx context.Context, systemPrompt string, history []ConversationEntry, userMessage string) (string, *LLMUsage, error)
RunWithUsage is like Run but also returns aggregated token usage from all LLM calls.
Architecture:
- The loop runs until the LLM produces a response with no tool calls.
- A single run-level timeout controls the entire execution (default: 600s).
- Individual LLM calls have a safety-net timeout (5min) to catch hung connections.
- No fixed turn limit — the agent keeps going as long as it has tools to call.
func (*AgentRun) SetInterruptChannel ¶
SetInterruptChannel sets the channel for receiving follow-up user messages during agent execution. Messages received on this channel are injected into the conversation between agent turns, allowing users to steer the agent mid-run (similar to Claude Code behavior).
func (*AgentRun) SetKG ¶ added in v1.18.0
SetKG sets the Knowledge Graph reference for context-residual extraction.
func (*AgentRun) SetLCMEngine ¶ added in v1.14.0
SetLCMEngine wires the LCM engine into the agent run.
func (*AgentRun) SetLoopDetector ¶
func (a *AgentRun) SetLoopDetector(d *ToolLoopDetector)
SetLoopDetector sets the tool loop detector for this run.
func (*AgentRun) SetMemoryIndexer ¶ added in v1.14.0
func (a *AgentRun) SetMemoryIndexer(m *MemoryIndexer)
SetMemoryIndexer sets the memory indexer for post-compaction sync.
func (*AgentRun) SetModelOverride ¶
SetModelOverride sets the model to use instead of the default. Empty string means use the LLM client's default.
func (*AgentRun) SetOnBeforeToolExec ¶
func (a *AgentRun) SetOnBeforeToolExec(fn func())
SetOnBeforeToolExec sets a callback fired right before tool execution starts in the agent loop. Used by the block streamer to flush buffered text so the user sees intermediate reasoning before tools run.
func (*AgentRun) SetOnToolResult ¶
func (a *AgentRun) SetOnToolResult(fn func(name string, result ToolResult))
SetOnToolResult sets a callback fired after each tool execution completes. Used to auto-send media (e.g. generated images) to the channel.
func (*AgentRun) SetReactionSender ¶ added in v1.14.0
SetReactionSender sets the function used to send/remove emoji reactions.
func (*AgentRun) SetSession ¶ added in v1.14.0
SetSession sets the active session for compaction count tracking.
func (*AgentRun) SetSessionPersistence ¶ added in v1.13.0
func (a *AgentRun) SetSessionPersistence(p SessionPersister, sessionID string)
SetSessionPersistence wires session persistence for compaction summary storage.
func (*AgentRun) SetStreamCallback ¶
func (a *AgentRun) SetStreamCallback(cb StreamCallback)
SetStreamCallback sets the callback for streaming text deltas. When set, the agent uses CompleteWithToolsStream; only text content is forwarded, tool calls are accumulated silently.
func (*AgentRun) SetUsageRecorder ¶
SetUsageRecorder sets a callback invoked after each successful LLM response.
func (*AgentRun) ToolSummary ¶ added in v1.13.0
ToolSummary returns a digest of all tools called during this run.
type AgentsConfig ¶
type AgentsConfig struct {
// Profiles is the list of agent profiles.
Profiles []AgentProfileConfig `yaml:"profiles"`
// Routing defines how messages are routed.
Routing RoutingConfig `yaml:"routing"`
}
AgentsConfig holds all agent profiles and routing configuration.
type AnnounceCallback ¶
type AnnounceCallback func(run *SubagentRun)
AnnounceCallback is called when a subagent completes, allowing push-style notification to the parent session. Receives the completed run so the caller can notify the user/agent.
type ApplyPatchResult ¶ added in v1.12.0
ApplyPatchResult holds the summary of the applied patch.
type ApprovalManager ¶
type ApprovalManager struct {
// contains filtered or unexported fields
}
ApprovalManager manages pending tool approvals and their resolution. It also tracks session-scoped trust: once a user approves a tool in a session, subsequent uses of the same tool are auto-approved (no re-prompting).
func NewApprovalManager ¶
func NewApprovalManager(logger *slog.Logger) *ApprovalManager
NewApprovalManager creates a new approval manager.
func (*ApprovalManager) ClearSessionTrust ¶
func (m *ApprovalManager) ClearSessionTrust(sessionID string)
ClearSessionTrust removes all trusted tools for a session (e.g. on /new or /reset).
func (*ApprovalManager) Create ¶
func (m *ApprovalManager) Create(sessionID, callerJID, toolName string, args map[string]any) (id string, message string)
Create creates a pending approval and returns the ID and message for the user. The caller should send the message to the chat, then call Wait to block for the result.
func (*ApprovalManager) GrantTrust ¶
func (m *ApprovalManager) GrantTrust(sessionID, toolName string)
GrantTrust marks a tool as trusted for the given session. Future calls to Request for this tool+session will be auto-approved.
func (*ApprovalManager) IsTrusted ¶
func (m *ApprovalManager) IsTrusted(sessionID, toolName string) bool
IsTrusted returns true if the tool has been previously approved in this session.
func (*ApprovalManager) LatestPendingForSession ¶
func (m *ApprovalManager) LatestPendingForSession(sessionID string) string
LatestPendingForSession returns the ID of the most recent pending approval for the given session, or empty string if none. This allows "/approve" without specifying the UUID — it resolves the latest pending request.
func (*ApprovalManager) PendingCountForSession ¶
func (m *ApprovalManager) PendingCountForSession(sessionID string) int
PendingCountForSession returns the number of pending approvals for a session.
func (*ApprovalManager) Request ¶
func (m *ApprovalManager) Request(sessionID, callerJID, toolName string, args map[string]any, sendMsg func(msg string)) (bool, error)
Request creates a pending approval, invokes sendMsg with the approval message, then blocks until the user approves, denies, or timeout. sendMsg is called so the user sees the approval request (e.g. send to channel).
If the tool has already been approved in this session (session trust), the request is auto-approved without prompting the user.
func (*ApprovalManager) Resolve ¶
func (m *ApprovalManager) Resolve(id, sessionID, resolverJID string, approved bool, reason string) bool
Resolve resolves a pending approval by ID. Returns true if the approval was found and resolved. resolverJID is the user resolving (must match CallerJID for "own requests only").
type ApprovalResult ¶
ApprovalResult holds the outcome of an approval request.
type Assistant ¶
type Assistant struct {
// contains filtered or unexported fields
}
Assistant is the main orchestrator for DevClaw. Message flow: receive → access check → command check → trigger check → workspace resolve → input validation → context build → agent → output validation → send.
func (*Assistant) AccessManager ¶
func (a *Assistant) AccessManager() *AccessManager
AccessManager returns the access manager.
func (*Assistant) ApplyConfigUpdate ¶
ApplyConfigUpdate applies hot-reloadable config changes. Updates: access control, instructions, tool guard, heartbeat, token budget. Does NOT update: API, channels, model, plugins (require restart).
func (*Assistant) ChannelManager ¶
ChannelManager returns the channel manager for external registration.
func (*Assistant) ComposePrompt ¶
ComposePrompt builds a system prompt for the given session and input. Convenience method for CLI and external callers.
func (*Assistant) ExecuteAgent ¶
func (a *Assistant) ExecuteAgent(ctx context.Context, systemPrompt string, session *Session, userMessage string) string
ExecuteAgent runs the agent loop with tools and returns the response text. Public wrapper for CLI and external callers. Uses "default" as workspace ID.
func (*Assistant) ForceCompactSession ¶
ForceCompactSession runs compaction immediately, returns old and new history length.
func (*Assistant) ForceDream ¶ added in v1.18.2
ForceDream triggers a dream consolidation cycle immediately, bypassing the normal trigger gates (min hours, min sessions). Useful for operator- initiated consolidation (e.g. via SIGUSR1). Returns quickly if dream is disabled or not yet initialized.
func (*Assistant) GetMediaService ¶ added in v1.8.0
func (a *Assistant) GetMediaService() *media.MediaService
GetMediaService returns the media service for WebUI adapter wiring. Returns nil if native media is not enabled.
func (*Assistant) HandleCommand ¶
func (a *Assistant) HandleCommand(msg *channels.IncomingMessage) CommandResult
HandleCommand processes an admin command from a chat message. Returns handled=true if it was a valid command (even if permission denied).
func (*Assistant) HookManager ¶
func (a *Assistant) HookManager() *HookManager
HookManager returns the lifecycle hook manager for registering plugin hooks.
func (*Assistant) InjectVaultEnvVars ¶
func (a *Assistant) InjectVaultEnvVars()
InjectVaultEnvVars loads all vault secrets as environment variables. Key names are uppercased and prefixed if not already (e.g. "brave_api_key" → "BRAVE_API_KEY"). Existing env vars are NOT overwritten — vault only fills gaps. This allows skills/scripts to use process.env.BRAVE_API_KEY without .env files.
func (*Assistant) MediaConfig ¶
func (a *Assistant) MediaConfig() MediaConfig
MediaConfig returns the current effective media config under read lock.
func (*Assistant) MemoryEnabled ¶
MemoryEnabled returns true if the memory store is available.
func (*Assistant) PluginRegistry ¶ added in v1.16.0
PluginRegistry returns the plugin registry (may be nil).
func (*Assistant) ProfileManager ¶ added in v1.13.0
func (a *Assistant) ProfileManager() profiles.ProfileManager
ProfileManager returns the auth profile manager for OAuth/API key access. Returns nil if the vault is locked or profiles are not configured.
func (*Assistant) ProjectManager ¶
func (a *Assistant) ProjectManager() *ProjectManager
ProjectManager returns the project manager.
func (*Assistant) ProviderDiscovery ¶ added in v1.16.0
func (a *Assistant) ProviderDiscovery() *ProviderDiscovery
ProviderDiscovery returns the provider discovery instance (may be nil).
func (*Assistant) ReloadAndInitializeSkills ¶ added in v1.13.0
ReloadAndInitializeSkills reloads skills from disk, initializes new skills with the sandbox runner, and re-registers all skill tools. This is called after installing or updating skills at runtime.
func (*Assistant) SQLiteMemory ¶
func (a *Assistant) SQLiteMemory() *memory.SQLiteStore
SQLiteMemory returns the SQLite memory store (for advanced search), or nil.
func (*Assistant) SchedulerEnabled ¶
SchedulerEnabled returns true if the scheduler is running.
func (*Assistant) SessionStore ¶
func (a *Assistant) SessionStore() *SessionStore
SessionStore returns the session store (used by CLI chat).
func (*Assistant) SetPluginRegistry ¶ added in v1.16.0
SetPluginRegistry sets the unified plugin registry for the assistant.
func (*Assistant) SetScheduler ¶
SetScheduler configures the assistant's scheduler.
func (*Assistant) SetVault ¶
SetVault sets the unlocked vault for the assistant (enables vault tools).
func (*Assistant) SkillRegistry ¶
SkillRegistry returns the skills registry.
func (*Assistant) StopActiveRun ¶
StopActiveRun cancels the active agent run for the given workspace and session. It also signals the tool executor to abort all running tools and forces the session out of "processing" state so new messages are handled immediately. Returns true if a run was stopped, false if none was active.
func (*Assistant) ToolExecutor ¶
func (a *Assistant) ToolExecutor() *ToolExecutor
ToolExecutor returns the tool executor for external tool registration.
func (*Assistant) UpdateLLMClient ¶ added in v1.13.0
UpdateLLMClient recreates the LLM client with the current config. Call this after changing provider, model, base_url, or api_key at runtime.
func (*Assistant) UpdateMediaConfig ¶
func (a *Assistant) UpdateMediaConfig(media MediaConfig)
UpdateMediaConfig safely updates the media configuration under lock.
func (*Assistant) UsageTracker ¶
func (a *Assistant) UsageTracker() *UsageTracker
UsageTracker returns the usage tracker for token/cost stats.
func (*Assistant) WorkspaceManager ¶
func (a *Assistant) WorkspaceManager() *WorkspaceManager
WorkspaceManager returns the workspace manager.
type AsyncCompleteCallback ¶ added in v1.12.0
type AsyncCompleteCallback func(result *ToolResult)
AsyncCompleteCallback is called when an async tool completes execution. The result contains the final output that should be delivered.
type AsyncToolConfig ¶ added in v1.12.0
type AsyncToolConfig struct {
// Label is a human-readable description of the async task.
Label string
// OnComplete is called when the async task finishes.
OnComplete AsyncCompleteCallback
// Timeout is the maximum duration for the async task.
// Default is 5 minutes if not set.
Timeout time.Duration
}
AsyncToolConfig holds configuration for async tool execution.
type AuditRecord ¶
type AuditRecord struct {
ID int64
Tool string
Caller string
Level string
Allowed bool
ArgsSummary string
ResultSummary string
CreatedAt string
}
AuditRecord is a structured audit log entry.
type AuditRecordShort ¶
type AuditRecordShort struct {
ID int64 `json:"id"`
Tool string `json:"tool"`
Caller string `json:"caller"`
Level string `json:"level"`
Allowed bool `json:"allowed"`
ArgsSummary string `json:"args_summary"`
CreatedAt time.Time `json:"created_at"`
}
AuditRecordShort is a shortened version of AuditRecord for display.
type BlockStreamConfig ¶
type BlockStreamConfig struct {
// Enabled turns block streaming on/off (default: true).
Enabled bool `yaml:"enabled"`
// MinChars is the minimum characters to accumulate before sending a block (default: 20).
// Kept low for near-instant first-block feedback.
MinChars int `yaml:"min_chars"`
// MaxChars is the maximum characters per block before a forced flush (default: 600).
MaxChars int `yaml:"max_chars"`
// IdleMs is the idle timeout in milliseconds: if no new tokens arrive within
// this window, flush whatever is buffered (default: 200).
IdleMs int `yaml:"idle_ms"`
}
BlockStreamConfig configures the progressive message streaming behavior.
func DefaultBlockStreamConfig ¶
func DefaultBlockStreamConfig() BlockStreamConfig
DefaultBlockStreamConfig returns sensible defaults for block streaming. Tuned for WhatsApp/chat UX: each flush = a new message, so we prioritize sending coherent paragraphs over low-latency fragments. MinChars must be high enough to avoid sending single-line fragments as separate messages.
func (BlockStreamConfig) Effective ¶
func (c BlockStreamConfig) Effective() BlockStreamConfig
Effective returns a copy with defaults filled in for zero values.
type BlockStreamer ¶
type BlockStreamer struct {
// contains filtered or unexported fields
}
BlockStreamer accumulates LLM stream tokens and sends them progressively to a channel. It is tied to a single message exchange (one user message → one agent response).
func NewBlockStreamer ¶
func NewBlockStreamer( cfg BlockStreamConfig, channelMgr *channels.Manager, channel, chatID, replyTo string, ) *BlockStreamer
NewBlockStreamer creates a streamer that progressively sends blocks to the given channel.
func (*BlockStreamer) Finish ¶
func (bs *BlockStreamer) Finish()
Finish flushes any remaining buffer and marks the streamer as done.
func (*BlockStreamer) FlushNow ¶
func (bs *BlockStreamer) FlushNow()
FlushNow immediately sends any buffered text to the channel, regardless of MinChars threshold. Use this before tool execution to ensure the user sees the LLM's intermediate text (thoughts/reasoning) before tools start running.
func (*BlockStreamer) HasSentBlocks ¶
func (bs *BlockStreamer) HasSentBlocks() bool
HasSentBlocks returns true if at least one block was sent progressively.
func (*BlockStreamer) StreamCallback ¶
func (bs *BlockStreamer) StreamCallback() StreamCallback
StreamCallback returns a StreamCallback function suitable for AgentRun.SetStreamCallback.
type BrowserConfig ¶
type BrowserConfig struct {
// Enabled turns the browser tool on/off (default: true if Chrome is found).
Enabled bool `yaml:"enabled"`
// ChromePath is the path to the Chrome/Chromium binary.
// Auto-detected if empty.
ChromePath string `yaml:"chrome_path"`
// Headless runs the browser without a visible window (default: true).
Headless bool `yaml:"headless"`
// TimeoutSeconds is the max time for a single browser operation (default: 30).
TimeoutSeconds int `yaml:"timeout_seconds"`
// MaxPages is the max number of simultaneous pages/tabs (default: 3).
MaxPages int `yaml:"max_pages"`
// ViewportWidth is the browser viewport width (default: 1280).
ViewportWidth int `yaml:"viewport_width"`
// ViewportHeight is the browser viewport height (default: 720).
ViewportHeight int `yaml:"viewport_height"`
// DefaultProfile is the default browser profile to use.
DefaultProfile string `yaml:"default_profile"`
// Profiles maps profile names to their configurations.
Profiles map[string]BrowserProfile `yaml:"profiles"`
// SSRFPolicy configures SSRF protection for browser navigation.
SSRFPolicy BrowserSSRFPolicy `yaml:"ssrf_policy"`
// AttachOnly means never launch a browser; only attach if already running.
AttachOnly bool `yaml:"attach_only"`
// ExtraArgs are additional command-line arguments for Chrome.
ExtraArgs []string `yaml:"extra_args"`
}
BrowserConfig configures the browser tool.
func DefaultBrowserConfig ¶
func DefaultBrowserConfig() BrowserConfig
DefaultBrowserConfig returns sensible defaults.
type BrowserManager ¶
type BrowserManager struct {
// contains filtered or unexported fields
}
BrowserManager manages a Chrome/Chromium process and CDP connections.
func NewBrowserManager ¶
func NewBrowserManager(cfg BrowserConfig, logger *slog.Logger) *BrowserManager
NewBrowserManager creates a new browser manager.
func (*BrowserManager) Act ¶ added in v1.13.0
func (bm *BrowserManager) Act(ctx context.Context, req ActRequest) (*ActResult, error)
Act performs a browser action.
func (*BrowserManager) ClickElement ¶
func (bm *BrowserManager) ClickElement(ctx context.Context, selector string) error
ClickElement clicks an element matched by CSS selector.
func (*BrowserManager) CloseTab ¶ added in v1.13.0
func (bm *BrowserManager) CloseTab(ctx context.Context, targetID string) error
CloseTab closes a browser tab by target ID.
func (*BrowserManager) FillInput ¶
func (bm *BrowserManager) FillInput(ctx context.Context, selector, value string) error
FillInput fills a text input matched by CSS selector.
func (*BrowserManager) FocusTab ¶ added in v1.13.0
func (bm *BrowserManager) FocusTab(ctx context.Context, targetID string) error
FocusTab focuses a browser tab by target ID.
func (*BrowserManager) GetAccessibilityTree ¶ added in v1.13.0
func (bm *BrowserManager) GetAccessibilityTree(ctx context.Context) (*AXNode, error)
GetAccessibilityTree fetches the full accessibility tree via CDP.
func (*BrowserManager) GetContent ¶
func (bm *BrowserManager) GetContent(ctx context.Context) (string, error)
GetContent returns the text content of the current page.
func (*BrowserManager) GetCurrentTab ¶ added in v1.13.0
func (bm *BrowserManager) GetCurrentTab(ctx context.Context) (*Tab, error)
GetCurrentTab returns the currently active tab.
func (*BrowserManager) ListTabs ¶ added in v1.13.0
func (bm *BrowserManager) ListTabs(ctx context.Context) ([]Tab, error)
ListTabs returns all open browser tabs.
func (*BrowserManager) Navigate ¶
func (bm *BrowserManager) Navigate(ctx context.Context, url string) error
Navigate opens a URL in the browser.
func (*BrowserManager) NavigateTab ¶ added in v1.13.0
func (bm *BrowserManager) NavigateTab(ctx context.Context, targetID, url string) error
NavigateTab navigates a specific tab to a URL.
func (*BrowserManager) OpenTab ¶ added in v1.13.0
OpenTab opens a new browser tab and optionally navigates to a URL.
func (*BrowserManager) ResolveRefToSelector ¶ added in v1.13.0
func (bm *BrowserManager) ResolveRefToSelector(refID string) (string, error)
ResolveRefToSelector converts a role reference to a CSS selector or JS query.
func (*BrowserManager) Screenshot ¶
func (bm *BrowserManager) Screenshot(ctx context.Context) (string, error)
Screenshot captures the current page as a PNG and returns base64-encoded data.
func (*BrowserManager) Snapshot ¶ added in v1.13.0
func (bm *BrowserManager) Snapshot(ctx context.Context, opts SnapshotOptions) (*SnapshotResult, error)
Snapshot creates a text snapshot of the current page with role references.
func (*BrowserManager) Start ¶
func (bm *BrowserManager) Start(ctx context.Context) error
Start launches Chrome with CDP enabled. Called lazily on first tool use.
func (*BrowserManager) Stop ¶
func (bm *BrowserManager) Stop()
Stop kills the Chrome process and closes connections.
func (*BrowserManager) WithSSRFGuard ¶
func (bm *BrowserManager) WithSSRFGuard(guard *security.SSRFGuard) *BrowserManager
WithSSRFGuard attaches an SSRF guard to the browser manager. When set, Navigate() will validate URLs before loading them.
type BrowserProfile ¶ added in v1.13.0
type BrowserProfile struct {
// Name is the profile name.
Name string `yaml:"name"`
// CDPUrl is the remote CDP endpoint (e.g., "http://10.0.0.42:9222").
CDPUrl string `yaml:"cdp_url"`
// CDPPort is the local CDP port for this profile.
CDPPort int `yaml:"cdp_port"`
// Color is the UI tint color for this profile.
Color string `yaml:"color"`
// Driver is "devclaw" (managed) or "extension" (relay).
Driver string `yaml:"driver"`
}
BrowserProfile configures a browser profile.
type BrowserSSRFPolicy ¶ added in v1.13.0
type BrowserSSRFPolicy struct {
// AllowPrivateNetwork allows navigation to private network addresses (default: true).
AllowPrivateNetwork bool `yaml:"allow_private_network"`
// AllowedHostnames is a whitelist of allowed hostnames.
AllowedHostnames []string `yaml:"allowed_hostnames"`
}
BrowserSSRFPolicy configures SSRF protection.
type BudgetConfig ¶
type BudgetConfig struct {
// MonthlyLimitUSD is the maximum monthly spend (0 = unlimited).
MonthlyLimitUSD float64 `yaml:"monthly_limit_usd"`
// WarnAtPercent triggers a warning when this % of budget is reached (default: 80).
WarnAtPercent int `yaml:"warn_at_percent"`
// ActionAtLimit defines behavior when limit is reached: "warn", "block", "fallback_local".
ActionAtLimit string `yaml:"action_at_limit"`
}
BudgetConfig configures monthly cost tracking and limits.
func DefaultBudgetConfig ¶
func DefaultBudgetConfig() BudgetConfig
DefaultBudgetConfig returns sensible defaults for budget tracking.
type BuiltinSkill ¶ added in v1.12.0
type BuiltinSkill struct {
Name string
Description string
Content string
Trigger string // automatic, manual
}
BuiltinSkill represents a built-in skill loaded from the embedded filesystem.
type BuiltinSkills ¶ added in v1.12.0
type BuiltinSkills struct {
// contains filtered or unexported fields
}
BuiltinSkills holds all loaded built-in skills.
func GetBuiltinSkills ¶ added in v1.12.0
func GetBuiltinSkills() *BuiltinSkills
GetBuiltinSkills returns the global builtin skills instance. Returns nil if LoadBuiltinSkills hasn't been called yet.
func LoadBuiltinSkills ¶ added in v1.12.0
func LoadBuiltinSkills(logger *slog.Logger) *BuiltinSkills
LoadBuiltinSkills loads all built-in skills from the embedded filesystem. Uses singleton pattern to load only once.
func (*BuiltinSkills) All ¶ added in v1.12.0
func (bs *BuiltinSkills) All() map[string]*BuiltinSkill
All returns all loaded skills.
func (*BuiltinSkills) FormatForPrompt ¶ added in v1.12.0
func (bs *BuiltinSkills) FormatForPrompt() string
FormatForPrompt formats all skills for inclusion in the system prompt. Only includes skills with trigger="automatic".
func (*BuiltinSkills) FormatSkillForPrompt ¶ added in v1.12.0
func (bs *BuiltinSkills) FormatSkillForPrompt(name string) string
FormatSkillForPrompt formats a single skill for the prompt.
func (*BuiltinSkills) Get ¶ added in v1.12.0
func (bs *BuiltinSkills) Get(name string) *BuiltinSkill
Get returns a skill by name.
func (*BuiltinSkills) Names ¶ added in v1.12.0
func (bs *BuiltinSkills) Names() []string
Names returns all skill names.
func (*BuiltinSkills) OnDemandSkills ¶ added in v1.13.0
func (bs *BuiltinSkills) OnDemandSkills() []*BuiltinSkill
OnDemandSkills returns builtin skills that should be listed in the XML reference list (trigger="on-demand") instead of injected inline. The LLM loads their full instructions via get_skill_instructions(name).
type CDPTarget ¶ added in v1.13.0
type CDPTarget struct {
TargetID string `json:"targetId"`
Type string `json:"type"`
Title string `json:"title"`
URL string `json:"url"`
Attached bool `json:"attached"`
WebSocketDebuggerURL string `json:"webSocketDebuggerUrl"`
}
CDPTarget represents a CDP target (page, worker, etc.)
type Canvas ¶
type Canvas struct {
ID string `json:"id"`
Title string `json:"title"`
HTML string `json:"-"`
Port int `json:"port"`
URL string `json:"url"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
// contains filtered or unexported fields
}
Canvas represents a single hosted HTML page with live-reload support.
type CanvasConfig ¶
type CanvasConfig struct {
// Enabled turns canvas hosting on/off (default: true).
Enabled bool `yaml:"enabled"`
// BasePort is the starting port for canvas servers (default: 9100).
// Each canvas gets its own port: BasePort, BasePort+1, etc.
BasePort int `yaml:"base_port"`
// MaxCanvases is the max number of simultaneous canvas servers (default: 5).
MaxCanvases int `yaml:"max_canvases"`
// TTLMinutes is how long a canvas stays alive without updates (default: 30).
TTLMinutes int `yaml:"ttl_minutes"`
}
CanvasConfig configures the canvas host.
func DefaultCanvasConfig ¶
func DefaultCanvasConfig() CanvasConfig
DefaultCanvasConfig returns sensible defaults.
type CanvasHost ¶
type CanvasHost struct {
// contains filtered or unexported fields
}
CanvasHost manages multiple canvas servers.
func NewCanvasHost ¶
func NewCanvasHost(cfg CanvasConfig, logger *slog.Logger) *CanvasHost
NewCanvasHost creates a new canvas host.
func (*CanvasHost) CleanupStale ¶
func (ch *CanvasHost) CleanupStale() int
CleanupStale removes canvases that haven't been updated within TTL.
func (*CanvasHost) Create ¶
func (ch *CanvasHost) Create(id, title, html string) (*Canvas, error)
Create creates and starts a new canvas with the given HTML content.
func (*CanvasHost) List ¶
func (ch *CanvasHost) List() []*Canvas
List returns metadata for all active canvases.
func (*CanvasHost) Stop ¶
func (ch *CanvasHost) Stop(id string) error
Stop stops a specific canvas server.
func (*CanvasHost) Update ¶
func (ch *CanvasHost) Update(id, html string) error
Update replaces the HTML content of an existing canvas and triggers live-reload.
type ChannelDiagnostic ¶
type ChannelDiagnostic struct {
Name string `json:"name"`
Connected bool `json:"connected"`
TestResult string `json:"test_result"`
LatencyMs int64 `json:"latency_ms"`
}
ChannelDiagnostic represents diagnostic result for a single channel.
type ChannelHealth ¶
type ChannelHealth struct {
Connected bool `json:"connected"`
LastMessageAt time.Time `json:"last_message_at,omitempty"`
ErrorCount int `json:"error_count"`
LatencyMs int64 `json:"latency_ms"`
Details map[string]any `json:"details,omitempty"`
}
ChannelHealth represents health status of a single channel.
type ChannelsConfig ¶
type ChannelsConfig struct {
// WhatsApp is the default WhatsApp channel config (core).
WhatsApp whatsapp.Config `yaml:"whatsapp"`
// Telegram is the default Telegram channel config (core).
Telegram telegram.Config `yaml:"telegram"`
// Discord is the default Discord channel config (core).
Discord discord.Config `yaml:"discord"`
// Slack is the default Slack channel config (core).
Slack slack.Config `yaml:"slack"`
// WhatsAppInstances holds additional named WhatsApp instances.
// Each key is the instance ID (e.g. "business") and the value is
// the full channel config for that instance.
WhatsAppInstances map[string]whatsapp.Config `yaml:"whatsapp_instances,omitempty"`
// TelegramInstances holds additional named Telegram instances.
TelegramInstances map[string]telegram.Config `yaml:"telegram_instances,omitempty"`
// DiscordInstances holds additional named Discord instances.
DiscordInstances map[string]discord.Config `yaml:"discord_instances,omitempty"`
// SlackInstances holds additional named Slack instances.
SlackInstances map[string]slack.Config `yaml:"slack_instances,omitempty"`
}
ChannelsConfig holds configuration for all channels.
func (ChannelsConfig) DiscordAll ¶ added in v1.16.0
func (c ChannelsConfig) DiscordAll() map[string]discord.Config
DiscordAll returns all Discord configs: the default instance (key "") merged with any named instances from DiscordInstances.
func (ChannelsConfig) SlackAll ¶ added in v1.16.0
func (c ChannelsConfig) SlackAll() map[string]slack.Config
SlackAll returns all Slack configs: the default instance (key "") merged with any named instances from SlackInstances.
func (ChannelsConfig) TelegramAll ¶ added in v1.16.0
func (c ChannelsConfig) TelegramAll() map[string]telegram.Config
TelegramAll returns all Telegram configs: the default instance (key "") merged with any named instances from TelegramInstances.
func (ChannelsConfig) WhatsAppAll ¶ added in v1.16.0
func (c ChannelsConfig) WhatsAppAll() map[string]whatsapp.Config
WhatsAppAll returns all WhatsApp configs: the default instance (key "") merged with any named instances from WhatsAppInstances.
type CheckResult ¶
type CheckResult struct {
// Allowed is true if the contact can interact.
Allowed bool
// Level is the resolved access level.
Level AccessLevel
// ShouldAsk is true if we should send a "request access" message.
ShouldAsk bool
// Reason explains why access was denied (for logging).
Reason string
}
CheckResult contains the result of an access check.
type CommandResult ¶
type CommandResult struct {
// Response is the text to send back.
Response string
// Handled is true if the message was a valid command.
Handled bool
}
CommandResult contains the result of a command execution.
type CompactLevel ¶ added in v1.17.0
type CompactLevel int
CompactLevel represents the severity of compaction to apply.
const ( // CompactNone means no compaction needed. CompactNone CompactLevel = -1 // CompactCollapse truncates oversized tool results in-place. // Cheapest operation — no LLM calls. Triggered at ~70% context usage. CompactCollapse CompactLevel = 0 // CompactMicro clears old tool results with a placeholder. // Still cheap — no LLM calls. Triggered at ~80% context usage. CompactMicro CompactLevel = 1 // CompactAuto triggers full LLM-based summarization. // Expensive — requires LLM call. Triggered at ~93% context usage. CompactAuto CompactLevel = 2 // CompactMemory extracts memories before summarizing. // Most expensive — multiple LLM calls. Triggered at ~97% context usage. CompactMemory CompactLevel = 3 )
func (CompactLevel) String ¶ added in v1.17.0
func (l CompactLevel) String() string
String returns a human-readable name for the compaction level.
type CompactThresholds ¶ added in v1.17.0
type CompactThresholds struct {
// CollapseAt triggers tool result truncation. Default: 0.70.
CollapseAt float64 `yaml:"collapse_at"`
// MicroCompactAt triggers old tool result clearing. Default: 0.80.
MicroCompactAt float64 `yaml:"micro_compact_at"`
// AutoCompactAt triggers LLM summarization. Default: 0.93.
AutoCompactAt float64 `yaml:"auto_compact_at"`
// MemoryCompactAt triggers memory extraction + summarization. Default: 0.97.
MemoryCompactAt float64 `yaml:"memory_compact_at"`
}
CompactThresholds defines the context usage ratios that trigger each level.
func DefaultCompactThresholds ¶ added in v1.17.0
func DefaultCompactThresholds() CompactThresholds
DefaultCompactThresholds returns sensible defaults.
type CompactionCircuitBreaker ¶ added in v1.17.0
type CompactionCircuitBreaker struct {
// contains filtered or unexported fields
}
CompactionCircuitBreaker prevents compaction loops by tracking failures. After maxFailures consecutive failures, compaction is blocked until cooldown expires.
func NewCompactionCircuitBreaker ¶ added in v1.17.0
func NewCompactionCircuitBreaker(maxFailures int, cooldown time.Duration) *CompactionCircuitBreaker
NewCompactionCircuitBreaker creates a new circuit breaker.
func (*CompactionCircuitBreaker) Allow ¶ added in v1.17.0
func (cb *CompactionCircuitBreaker) Allow() bool
Allow returns true if compaction is allowed (not tripped).
func (*CompactionCircuitBreaker) Failures ¶ added in v1.17.0
func (cb *CompactionCircuitBreaker) Failures() int
Failures returns the current failure count (for testing/logging).
func (*CompactionCircuitBreaker) RecordFailure ¶ added in v1.17.0
func (cb *CompactionCircuitBreaker) RecordFailure()
RecordFailure increments the failure counter.
func (*CompactionCircuitBreaker) RecordSuccess ¶ added in v1.17.0
func (cb *CompactionCircuitBreaker) RecordSuccess()
RecordSuccess resets the failure counter.
type CompactionConfig ¶ added in v1.13.0
type CompactionConfig struct {
// KeepRecentUserTurns is how many recent user turns to preserve verbatim
// in the compacted output. Default: 3, Max: 12.
KeepRecentUserTurns int `yaml:"keep_recent_user_turns"`
// MaxToolFailures is how many tool failure entries to include in the
// compaction summary. Default: 8.
MaxToolFailures int `yaml:"max_tool_failures"`
// ToolFailurePreviewChars is the max chars per tool failure preview.
// Default: 240.
ToolFailurePreviewChars int `yaml:"tool_failure_preview_chars"`
// IdentifierPolicy controls whether the compaction summary instruction
// includes guidance to preserve identifiers. Default: "preserve".
// Values: "preserve" (include instruction), "none" (omit instruction).
IdentifierPolicy string `yaml:"identifier_policy"`
// CompactionModel overrides the model used for summarization LLM calls.
// If empty, uses the agent's current model.
CompactionModel string `yaml:"compaction_model"`
// QualityGuard configures post-summarization quality auditing.
QualityGuard QualityGuardConfig `yaml:"quality_guard"`
// ContextPruning configures ratio-based in-memory context pruning.
ContextPruning ContextPruningConfig `yaml:"context_pruning"`
// TimeoutSeconds is the maximum time (in seconds) allowed for the LLM
// summarization step during compaction. If exceeded, falls back to
// trim-by-count. Default: 900 (15 minutes).
TimeoutSeconds int `yaml:"timeout_seconds"`
// PostIndexSync controls whether a memory indexer sync is triggered after
// compaction completes. Values: "off" (default), "async" (fire-and-forget),
// "await" (block until indexing completes, not yet implemented — treated as async).
PostIndexSync string `yaml:"post_index_sync"`
// LCMEnabled enables the Lossless Compaction Module (DAG-based memory).
// When enabled, messages are persisted verbatim and compaction builds a
// hierarchical summary DAG instead of a flat summary string.
// Default: true (nil pointer = true).
LCMEnabled *bool `yaml:"lcm_enabled"`
// LCM holds configuration for the Lossless Compaction Module.
LCM LCMConfig `yaml:"lcm"`
}
CompactionConfig controls how the compaction process preserves important context.
func DefaultCompactionConfig ¶ added in v1.13.0
func DefaultCompactionConfig() CompactionConfig
DefaultCompactionConfig returns sensible defaults.
type CompactionEntry ¶ added in v1.12.0
type CompactionEntry struct {
Type string `json:"type"` // Always "compaction_summary"
Summary string `json:"summary"` // The LLM-generated summary
CompactedAt time.Time `json:"compacted_at"` // When compaction occurred
MessagesBefore int `json:"messages_before"` // Count before compaction
MessagesAfter int `json:"messages_after"` // Count after compaction
}
CompactionEntry represents a compaction summary stored in the session.
type CompactionPipeline ¶ added in v1.17.0
type CompactionPipeline struct {
// contains filtered or unexported fields
}
CompactionPipeline coordinates multi-level proactive compaction.
func NewCompactionPipeline ¶ added in v1.17.0
func NewCompactionPipeline(thresholds CompactThresholds) *CompactionPipeline
NewCompactionPipeline creates a pipeline with the given thresholds.
func (*CompactionPipeline) Evaluate ¶ added in v1.17.0
func (p *CompactionPipeline) Evaluate(tokenCount, contextWindow int) ContextPressure
Evaluate determines which compaction level should be applied based on the current token count and context window size.
func (*CompactionPipeline) LastLevel ¶ added in v1.17.0
func (p *CompactionPipeline) LastLevel() CompactLevel
LastLevel returns the last applied compaction level.
func (*CompactionPipeline) RecordFailure ¶ added in v1.17.0
func (p *CompactionPipeline) RecordFailure()
RecordFailure records a failed compaction for circuit breaker tracking.
func (*CompactionPipeline) RecordSuccess ¶ added in v1.17.0
func (p *CompactionPipeline) RecordSuccess()
RecordSuccess records a successful compaction for circuit breaker tracking.
func (*CompactionPipeline) SetLastLevel ¶ added in v1.17.0
func (p *CompactionPipeline) SetLastLevel(level CompactLevel)
SetLastLevel records the last applied compaction level.
func (*CompactionPipeline) ShouldCompact ¶ added in v1.17.0
func (p *CompactionPipeline) ShouldCompact(level CompactLevel) bool
ShouldCompact returns true if compaction should be attempted at the given level. Checks the circuit breaker and suppresses repeat application of the same cheap level to avoid wasteful re-runs on consecutive turns at the same pressure.
type CompletionCheck ¶ added in v1.17.0
type CompletionCheck struct {
// Name identifies this check for logging.
Name string
// TriggerPatterns are substrings in the conversation that indicate
// this type of work was started.
TriggerPatterns []string
// CompletionPatterns are substrings that indicate the work was completed.
// If triggers match but completion doesn't, the check fails.
CompletionPatterns []string
// Reminder is the message to inject if the check fails.
Reminder string
}
CompletionCheck represents a single verification pattern.
type Config ¶
type Config struct {
// Name is the assistant name shown in responses.
Name string `yaml:"name"`
// Identity configures the assistant's structured identity (persona, theme, avatar).
// When set, Identity.Name takes precedence over the top-level Name field.
Identity IdentityConfig `yaml:"identity"`
// Trigger is the keyword that activates the bot (e.g. "@devclaw").
Trigger string `yaml:"trigger"`
// Model is the LLM model to use (e.g. "glm-4.7-flash").
Model string `yaml:"model"`
// API configures the LLM provider endpoint.
API APIConfig `yaml:"api"`
// Instructions are the base system prompt instructions.
Instructions string `yaml:"instructions"`
// Timezone is the user's timezone (e.g. "America/Sao_Paulo").
Timezone string `yaml:"timezone"`
// Language is the preferred response language (e.g. "pt-BR").
Language string `yaml:"language"`
// Access configures who can use the bot (allowlist/blocklist).
Access AccessConfig `yaml:"access"`
// Workspaces configures isolated profiles/contexts.
Workspaces WorkspaceConfig `yaml:"workspaces"`
// Channels configures communication channels.
Channels ChannelsConfig `yaml:"channels"`
// Memory configures the memory system.
Memory MemoryConfig `yaml:"memory"`
// Security configures security guardrails.
Security SecurityConfig `yaml:"security"`
// TokenBudget configures per-layer token limits.
TokenBudget TokenBudgetConfig `yaml:"token_budget"`
// Plugins configures the plugin loader.
Plugins plugins.Config `yaml:"plugins"`
// Sandbox configures the script sandbox.
Sandbox sandbox.Config `yaml:"sandbox"`
// Skills configures which skills are enabled.
Skills SkillsConfig `yaml:"skills"`
// Scheduler configures the task scheduler.
Scheduler SchedulerConfig `yaml:"scheduler"`
// Heartbeat configures the proactive heartbeat system.
Heartbeat HeartbeatConfig `yaml:"heartbeat"`
// Subagents configures the subagent orchestration system.
Subagents SubagentConfig `yaml:"subagents"`
// Agent configures the agent loop parameters (turns, timeouts, auto-continue).
Agent AgentConfig `yaml:"agent"`
// Fallback configures model fallback with retry and backoff.
Fallback FallbackConfig `yaml:"fallback"`
// Budget configures monthly cost tracking and limits.
Budget BudgetConfig `yaml:"budget"`
// Media configures vision and audio transcription.
Media MediaConfig `yaml:"media"`
// Logging configures log output.
Logging LoggingConfig `yaml:"logging"`
// Queue configures message debouncing for bursts.
Queue QueueConfig `yaml:"queue"`
// Database configures the central SQLite database (devclaw.db).
Database DatabaseConfig `yaml:"database"`
// Gateway configures the HTTP API gateway.
Gateway GatewayConfig `yaml:"gateway"`
// BlockStream configures progressive message delivery (stream text to channel
// in chunks instead of waiting for the complete response).
BlockStream BlockStreamConfig `yaml:"block_stream"`
// WebSearch configures the web search tool provider.
WebSearch WebSearchConfig `yaml:"web_search"`
// TTS configures text-to-speech synthesis.
TTS TTSConfig `yaml:"tts"`
// WebUI configures the web dashboard.
WebUI webui.Config `yaml:"webui"`
// Group configures group chat behavior.
Group GroupConfig `yaml:"group"`
// Agents configures specialized agent profiles and routing.
Agents AgentsConfig `yaml:"agents"`
// Groups configures group-specific policies and activation modes.
Groups GroupsPolicyConfig `yaml:"groups"`
// Hooks configures lifecycle hooks and webhooks.
Hooks HooksConfig `yaml:"hooks"`
// MCP configures Model Context Protocol servers.
MCP MCPConfig `yaml:"mcp"`
// Routines configures background routines (metrics, memory indexer, etc).
Routines RoutinesConfig `yaml:"routines"`
// NativeMedia configures the native media handling system.
NativeMedia NativeMediaConfig `yaml:"native_media"`
// Links configures the link understanding pipeline (auto-fetch URLs in messages).
Links LinkConfig `yaml:"links"`
// Sessions configures session lifecycle management.
Sessions SessionReaperConfig `yaml:"sessions"`
// Browser configures browser automation tools.
Browser BrowserConfig `yaml:"browser"`
// OAuthHub configures the OAuth Hub proxy for centralized OAuth management.
OAuthHub OAuthHubConfig `yaml:"oauth_hub"`
// Update configures auto-update checking and installation.
Update UpdateConfig `yaml:"update"`
// ProfileCooldowns configures per-profile cooldown durations for auth failures.
// Optional: nil/zero values fall back to hardcoded defaults.
ProfileCooldowns *profiles.ProfileCooldownConfig `yaml:"profile_cooldowns,omitempty"`
// DevToolsEnabled forces dev tools registration regardless of workspace detection.
// nil = auto-detect from workspace (default), true = always enable, false = always disable.
DevToolsEnabled *bool `yaml:"dev_tools_enabled,omitempty"`
// ProviderDiscovery configures dynamic model discovery for local providers
// (Ollama, vLLM). When enabled, DevClaw probes endpoints at startup to
// discover available models and their context window sizes.
ProviderDiscovery ProviderDiscoveryConfig `yaml:"provider_discovery"`
}
Config holds all assistant configuration.
func DefaultConfig ¶
func DefaultConfig() *Config
DefaultConfig returns the default assistant configuration.
func LoadConfigFromFile ¶
LoadConfigFromFile reads and parses a YAML configuration file. Automatically loads .env files and expands environment variables. Returns an error if any ${VAR:?error} pattern has its variable unset.
func ParseConfig ¶
ParseConfig parses YAML bytes into a Config. Starts with defaults and overlays values from the YAML.
type ConfigHealth ¶
type ConfigHealth struct {
Valid bool `json:"valid"`
Path string `json:"path"`
Errors []string `json:"errors,omitempty"`
Sections []string `json:"sections"`
}
ConfigHealth represents configuration health status.
type ConfigWatcher ¶
type ConfigWatcher struct {
// contains filtered or unexported fields
}
ConfigWatcher monitors a config file for changes and invokes a callback when the file is modified. Uses polling (mtime + sha256) to avoid platform-specific file watchers.
func NewConfigWatcher ¶
func NewConfigWatcher(path string, interval time.Duration, onChange func(*Config), logger *slog.Logger) *ConfigWatcher
NewConfigWatcher creates a new config watcher. interval is the polling interval (e.g. 5 * time.Second). onChange is called when a valid config change is detected.
func (*ConfigWatcher) Start ¶
func (w *ConfigWatcher) Start(ctx context.Context)
Start begins polling in a goroutine. Exits when ctx is cancelled.
type ConsoleMessage ¶ added in v1.13.0
type ConsoleMessage struct {
Type string `json:"type"`
Text string `json:"text"`
Level string `json:"level"`
URL string `json:"url,omitempty"`
Line int `json:"line,omitempty"`
Column int `json:"column,omitempty"`
}
ConsoleMessage represents a browser console message.
type ContextEngine ¶ added in v1.13.0
type ContextEngine interface {
// Name returns a unique identifier for this engine.
Name() string
// Gather returns context text to inject into the prompt for a given
// session and user input. Returns "" if no relevant context is found.
// The maxTokens hint tells the engine its approximate token budget.
Gather(ctx context.Context, session *Session, input string, maxTokens int) string
}
ContextEngine produces extra context to inject into the system prompt. Implementations can source context from any backend: memory stores, vector databases, code indices, knowledge graphs, etc.
type ContextEngineRegistry ¶ added in v1.13.0
type ContextEngineRegistry struct {
// contains filtered or unexported fields
}
ContextEngineRegistry manages multiple context engines and merges their output during prompt composition.
func NewContextEngineRegistry ¶ added in v1.13.0
func NewContextEngineRegistry() *ContextEngineRegistry
NewContextEngineRegistry creates a new registry.
func (*ContextEngineRegistry) Engines ¶ added in v1.13.0
func (r *ContextEngineRegistry) Engines() []string
Engines returns the names of all registered engines.
func (*ContextEngineRegistry) GatherAll ¶ added in v1.13.0
func (r *ContextEngineRegistry) GatherAll(ctx context.Context, session *Session, input string, maxTokensPerEngine int) string
GatherAll calls Gather on every registered engine and returns the concatenated results, separated by newlines. Empty results are skipped.
func (*ContextEngineRegistry) Register ¶ added in v1.13.0
func (r *ContextEngineRegistry) Register(engine ContextEngine)
Register adds a context engine to the registry.
type ContextPressure ¶ added in v1.17.0
type ContextPressure struct {
// TokenCount is the estimated token usage.
TokenCount int
// ContextWindow is the effective context window size.
ContextWindow int
// Ratio is TokenCount / ContextWindow (0.0 to 1.0+).
Ratio float64
// RecommendedLevel is the compaction level that should be applied.
RecommendedLevel CompactLevel
// TokensUntilBlocking is how many tokens remain before the blocking limit.
TokensUntilBlocking int
}
ContextPressure represents the current context window usage and recommended action.
type ContextPruningConfig ¶ added in v1.14.0
type ContextPruningConfig struct {
// SoftTrimRatio is the context usage ratio above which tool results are soft-trimmed
// (head+tail). Default: 0.3.
SoftTrimRatio float64 `yaml:"soft_trim_ratio"`
// HardClearRatio is the context usage ratio above which old tool results are
// replaced with a placeholder. Default: 0.5.
HardClearRatio float64 `yaml:"hard_clear_ratio"`
// SoftTrimMaxChars is the max chars for a tool result before soft-trim kicks in.
// Default: 4096.
SoftTrimMaxChars int `yaml:"soft_trim_max_chars"`
// ProtectRecentTurns is how many recent assistant turns to protect from pruning.
// Default: 3.
ProtectRecentTurns int `yaml:"protect_recent_turns"`
}
ContextPruningConfig controls ratio-based in-memory pruning of tool results.
type ContextRouter ¶ added in v1.18.0
type ContextRouter struct {
// contains filtered or unexported fields
}
ContextRouter resolves (channel, external_id) pairs to palace wings. It is safe for concurrent use — all state lives in the SQLite store. An in-process cache reduces burst write pressure on the store.
func NewContextRouter ¶ added in v1.18.0
func NewContextRouter(store *memory.SQLiteStore, logger *slog.Logger, cfg HierarchyConfig) *ContextRouter
NewContextRouter creates a ContextRouter backed by the given memory store. The store may be nil — in that case, the router is a no-op that always returns a SourceDisabled resolution. This supports startup paths where the memory system failed to initialize but the channels are still running.
cfg is the HierarchyConfig for this router instance. Heuristics are read from cfg.Heuristics — zero heuristics means tier 2 is a no-op.
func (*ContextRouter) Pin ¶ added in v1.18.0
func (r *ContextRouter) Pin(channel, externalID, wing string) error
Pin creates or updates an explicit mapping for a (channel, externalID) pair. This is what the `/wing set` bot command and `devclaw wing map` CLI invoke. Confidence is always 1.0 because it's a user decision.
Returns an error if the wing name is invalid or the store rejects the write. Callers (bot handlers, CLI) should surface the error to the user.
func (*ContextRouter) Resolve ¶ added in v1.18.0
func (r *ContextRouter) Resolve(ctx context.Context, channel, externalID, hint string) WingResolution
Resolve determines which wing a message from (channel, externalID) should be associated with. This function NEVER returns an error — every failure mode falls through to SourceDefault with an empty wing.
The hint parameter is an optional message preview that heuristics can inspect. Pass an empty string if no hint is available; heuristics will then rely purely on channel+externalID patterns.
Resolve may write to the store: when a heuristic hit occurs, the result is persisted as a confidence<1.0 mapping so the next Resolve call for the same pair is a fast mapped lookup.
func (*ContextRouter) Unpin ¶ added in v1.18.0
func (r *ContextRouter) Unpin(channel, externalID string) error
Unpin removes a mapping. Subsequent Resolve calls for the same pair will fall back to the heuristic tier or the default.
type ContextWindowGuardResult ¶ added in v1.13.0
type ContextWindowGuardResult struct {
// Tokens is the resolved context window size.
Tokens int
// ShouldBlock is true when the context window is too small for a useful run.
ShouldBlock bool
// ShouldWarn is true when the context window is usable but small.
ShouldWarn bool
// Message describes the issue (only set when ShouldBlock or ShouldWarn).
Message string
}
ContextWindowGuardResult holds the outcome of a context window evaluation.
func EvaluateContextWindowGuard ¶ added in v1.13.0
func EvaluateContextWindowGuard(tokens int) ContextWindowGuardResult
EvaluateContextWindowGuard checks the context window size and returns whether the agent should block or warn before starting a run.
type ContextualTool ¶ added in v1.12.0
type ContextualTool interface {
SetDeliveryTarget(channel, chatID string)
}
ContextualTool is an interface for tools that need delivery context. Tools can implement this interface to receive channel/chatID context. The executor checks for this interface and calls SetDeliveryTarget before executing the tool handler.
Note: In DevClaw, handlers are functions (not objects), so this interface is typically implemented by a wrapper struct. For simple cases, tools can use GetDeliveryTarget(ctx) directly to extract context from the context.Context.
Example with wrapper:
type contextualHandler struct {
fn ToolHandlerFunc
channel string
chatID string
}
func (h *contextualHandler) SetDeliveryTarget(channel, chatID string) {
h.channel = channel
h.chatID = chatID
}
func (h *contextualHandler) Call(ctx context.Context, args map[string]any) (any, error) {
// Use h.channel and h.chatID
return h.fn(ctx, args)
}
type ConversationEntry ¶
type ConversationEntry struct {
UserMessage string
AssistantResponse string
Timestamp time.Time
// ToolSummary is a comma-separated digest of tools called during this turn.
// Injected into history so future turns know what was actually verified vs. inferred.
ToolSummary string `json:"tool_summary,omitempty"`
// ToolCalls stores individual tool invocations for richer history reconstruction.
// When present, buildMessages uses these instead of ToolSummary.
ToolCalls []ToolCallRecord `json:"tool_calls,omitempty"`
}
ConversationEntry representa uma troca de mensagem na sessão.
type CooldownConfig ¶
type CooldownConfig struct {
BillingBackoffHours float64 `yaml:"billing_backoff_hours"` // Default: 5
BillingMaxHours float64 `yaml:"billing_max_hours"` // Default: 24
FailureWindowHours float64 `yaml:"failure_window_hours"` // Default: 24
InitialBackoffMinutes float64 `yaml:"initial_backoff_minutes"` // Default: 1
MaxBackoffMinutes float64 `yaml:"max_backoff_minutes"` // Default: 60
}
CooldownConfig defines backoff parameters for model cooldowns.
func DefaultCooldownConfig ¶
func DefaultCooldownConfig() CooldownConfig
DefaultCooldownConfig returns sensible defaults.
type Coordinator ¶ added in v1.17.0
type Coordinator struct {
// contains filtered or unexported fields
}
Coordinator orchestrates multi-agent workflows through structured phases.
func NewCoordinator ¶ added in v1.17.0
func NewCoordinator(config CoordinatorConfig, spawner WorkerSpawner, logger *slog.Logger) *Coordinator
NewCoordinator creates a new coordinator with the given config and spawner.
func (*Coordinator) GetPhaseTools ¶ added in v1.17.0
func (c *Coordinator) GetPhaseTools(phase CoordinatorPhase) []string
GetPhaseTools returns the allowed tools for a given phase.
func (*Coordinator) MaxWorkersForPhase ¶ added in v1.17.0
func (c *Coordinator) MaxWorkersForPhase(phase CoordinatorPhase) int
MaxWorkersForPhase returns the concurrency limit for a phase.
func (*Coordinator) RunPhase ¶ added in v1.17.0
func (c *Coordinator) RunPhase(ctx context.Context, phase CoordinatorPhase, tasks []WorkerTask) PhaseResult
RunPhase executes all tasks in a phase, respecting concurrency limits. Tasks within a phase run in parallel up to the phase's worker limit. Results are returned in the same order as the input tasks.
type CoordinatorConfig ¶ added in v1.17.0
type CoordinatorConfig struct {
// MaxResearchWorkers is the max parallel workers in research phase. Default: 4.
MaxResearchWorkers int `yaml:"max_research_workers"`
// MaxImplWorkers is the max parallel workers in implementation phase. Default: 2.
MaxImplWorkers int `yaml:"max_impl_workers"`
// MaxVerifyWorkers is the max parallel workers in verification phase. Default: 2.
MaxVerifyWorkers int `yaml:"max_verify_workers"`
// DefaultTimeout is the default timeout per worker task. Default: 5min.
DefaultTimeout time.Duration `yaml:"default_timeout"`
// ResearchTools lists tools allowed during research (read-only).
ResearchTools []string `yaml:"research_tools"`
// ImplTools lists tools allowed during implementation.
ImplTools []string `yaml:"impl_tools"`
// VerifyTools lists tools allowed during verification.
VerifyTools []string `yaml:"verify_tools"`
}
CoordinatorConfig configures the multi-agent coordinator.
func DefaultCoordinatorConfig ¶ added in v1.17.0
func DefaultCoordinatorConfig() CoordinatorConfig
DefaultCoordinatorConfig returns sensible defaults.
type CoordinatorPhase ¶ added in v1.17.0
type CoordinatorPhase string
CoordinatorPhase represents a stage in the multi-agent workflow.
const ( PhaseResearch CoordinatorPhase = "research" PhaseSynthesis CoordinatorPhase = "synthesis" PhaseImplementation CoordinatorPhase = "implementation" PhaseVerification CoordinatorPhase = "verification" )
func PhaseOrder ¶ added in v1.17.0
func PhaseOrder() []CoordinatorPhase
PhaseOrder returns the standard execution order of phases.
type Daemon ¶
type Daemon struct {
Label string `json:"label"`
Command string `json:"command"`
PID int `json:"pid"`
Port int `json:"port,omitempty"`
Status string `json:"status"` // running, stopped, failed
StartedAt time.Time `json:"started_at"`
ExitCode int `json:"exit_code,omitempty"`
Error string `json:"error,omitempty"`
// contains filtered or unexported fields
}
Daemon represents a managed background process.
type DaemonManager ¶
type DaemonManager struct {
// contains filtered or unexported fields
}
DaemonManager manages a set of background daemons.
func NewDaemonManager ¶
func NewDaemonManager() *DaemonManager
NewDaemonManager creates a new daemon manager.
func (*DaemonManager) ClearDaemon ¶ added in v1.13.0
func (dm *DaemonManager) ClearDaemon(label string) error
ClearDaemon removes a stopped/failed daemon from the registry.
func (*DaemonManager) GetLogs ¶
GetLogs returns the last n lines from a daemon's output ring buffer.
func (*DaemonManager) List ¶
func (dm *DaemonManager) List() []Daemon
List returns info about all managed daemons.
func (*DaemonManager) PollDaemon ¶ added in v1.13.0
func (dm *DaemonManager) PollDaemon(label string) (string, error)
PollDaemon returns recent output with backoff hints.
func (*DaemonManager) RestartDaemon ¶
func (dm *DaemonManager) RestartDaemon(label string) (*Daemon, error)
RestartDaemon stops and re-starts a daemon with the same config.
func (*DaemonManager) Shutdown ¶
func (dm *DaemonManager) Shutdown()
Shutdown stops all running daemons.
func (*DaemonManager) StartDaemon ¶
func (dm *DaemonManager) StartDaemon(label, command string, port int, readyPattern string) (*Daemon, error)
StartDaemon starts a new background process.
func (*DaemonManager) StopDaemon ¶
func (dm *DaemonManager) StopDaemon(label string, force bool) error
StopDaemon gracefully stops a daemon (SIGTERM). If force is true, uses SIGKILL.
func (*DaemonManager) WriteToDaemon ¶ added in v1.13.0
func (dm *DaemonManager) WriteToDaemon(label, input string) error
WriteToDaemon sends input to a daemon's stdin.
type DatabaseConfig ¶
type DatabaseConfig struct {
// Path is the database file path for SQLite (default: "./data/devclaw.db").
// Kept for backward compatibility with existing configs.
Path string `yaml:"path"`
// Hub enables the new Database Hub system with multi-backend support.
// When Hub.Backend is not set, falls back to Path for SQLite.
Hub database.HubConfig `yaml:"hub"`
}
DatabaseConfig configures the central database using the Database Hub. Supports SQLite (default), PostgreSQL, and MySQL backends.
func (DatabaseConfig) Effective ¶ added in v1.8.0
func (c DatabaseConfig) Effective() database.HubConfig
Effective returns the effective Hub configuration, applying defaults.
type DatabaseHealth ¶
type DatabaseHealth struct {
Connected bool `json:"connected"`
SizeMB float64 `json:"size_mb"`
Tables map[string]int `json:"tables"`
Error string `json:"error,omitempty"`
}
DatabaseHealth represents database health status.
type DecisionPhase ¶ added in v1.17.0
type DecisionPhase struct{}
DecisionPhase decides whether to loop back (tool_use) or stop (text response).
func (*DecisionPhase) Execute ¶ added in v1.17.0
func (d *DecisionPhase) Execute(ctx context.Context, state *TurnState) (NextAction, error)
func (*DecisionPhase) Name ¶ added in v1.17.0
func (d *DecisionPhase) Name() string
type DedupCache ¶ added in v1.13.0
type DedupCache struct {
// contains filtered or unexported fields
}
DedupCache provides Message-ID based deduplication with automatic TTL expiration. This catches duplicate deliveries from messaging platforms (webhook retries, reconnection replays) that content-match alone misses.
func NewDedupCache ¶ added in v1.13.0
func NewDedupCache(ttl time.Duration) *DedupCache
NewDedupCache creates a new dedup cache with the given TTL.
func (*DedupCache) CheckAndRecord ¶ added in v1.13.0
func (dc *DedupCache) CheckAndRecord(key string) bool
CheckAndRecord atomically checks if a key is a duplicate and records it if not. Returns true if the key was already seen (duplicate).
func (*DedupCache) IsDuplicate ¶ added in v1.13.0
func (dc *DedupCache) IsDuplicate(key string) bool
IsDuplicate returns true if the key was already seen and still within TTL.
func (*DedupCache) Record ¶ added in v1.13.0
func (dc *DedupCache) Record(key string)
Record stores a key with its TTL expiry.
func (*DedupCache) Stop ¶ added in v1.13.0
func (dc *DedupCache) Stop()
Stop terminates the background cleanup goroutine.
type DeleteFileHunk ¶ added in v1.12.0
type DeleteFileHunk struct {
Path string
}
DeleteFileHunk represents deleting an existing file.
type DeliveryScope ¶ added in v1.16.0
type DeliveryScope string
DeliveryScope controls who receives the subagent completion announcement.
const ( // DeliveryScopeAll delivers to both parent agent and external channel (default). DeliveryScopeAll DeliveryScope = "all" // DeliveryScopeParent delivers only to the parent agent (no external notification). DeliveryScopeParent DeliveryScope = "parent" // DeliveryScopeExternal delivers only to the external channel (no parent injection). DeliveryScopeExternal DeliveryScope = "external" )
type DeliveryTarget ¶
DeliveryTarget holds the channel and chatID for message delivery.
func DeliveryTargetFromContext ¶
func DeliveryTargetFromContext(ctx context.Context) DeliveryTarget
DeliveryTargetFromContext extracts the delivery target from a context. Returns empty DeliveryTarget if not set.
type DestructiveCheckResult ¶ added in v1.12.0
type DestructiveCheckResult struct {
Allowed bool
Reason string
RequiresUserInput bool
BatchWarning string
CooldownRemaining time.Duration
}
DestructiveCheckResult holds the result of a destructive tool check.
type DestructiveToolsConfig ¶ added in v1.12.0
type DestructiveToolsConfig struct {
// Enabled turns on destructive tool protection (default: true).
Enabled bool `yaml:"enabled"`
// Tools lists tool names that are considered destructive.
// With dispatcher consolidation, destructive actions are sub-actions
// within dispatchers; action-level protection is in each dispatcher handler.
Tools []string `yaml:"tools"`
// RateLimitPerMinute is the maximum number of calls per tool per minute.
// Default: 3
RateLimitPerMinute int `yaml:"rate_limit_per_minute"`
// BatchThreshold is the number of consecutive calls that trigger a warning.
// Default: 3
BatchThreshold int `yaml:"batch_threshold"`
// RequireInteractiveConfirmation forces the agent to ask user before
// executing destructive operations, rather than using a confirm parameter.
// Default: false (uses confirm parameter)
RequireInteractiveConfirmation bool `yaml:"require_interactive_confirmation"`
// CooldownSeconds is the minimum time between destructive operations.
// Default: 5
CooldownSeconds int `yaml:"cooldown_seconds"`
}
DestructiveToolsConfig configures protection for destructive operations.
func DefaultDestructiveToolsConfig ¶ added in v1.12.0
func DefaultDestructiveToolsConfig() DestructiveToolsConfig
DefaultDestructiveToolsConfig returns safe defaults.
type DestructiveTracker ¶ added in v1.12.0
type DestructiveTracker struct {
// contains filtered or unexported fields
}
DestructiveTracker tracks and limits destructive tool calls.
func NewDestructiveTracker ¶ added in v1.12.0
func NewDestructiveTracker(cfg DestructiveToolsConfig, logger *slog.Logger) *DestructiveTracker
NewDestructiveTracker creates a new tracker with the given config.
func (*DestructiveTracker) Check ¶ added in v1.12.0
func (d *DestructiveTracker) Check(toolName string) DestructiveCheckResult
Check evaluates whether a destructive tool call should be allowed. It does NOT modify state - call RecordCall() after the tool executes.
func (*DestructiveTracker) IsDestructive ¶ added in v1.12.0
func (d *DestructiveTracker) IsDestructive(toolName string) bool
IsDestructive checks if a tool is in the destructive list.
func (*DestructiveTracker) RecordCall ¶ added in v1.12.0
func (d *DestructiveTracker) RecordCall(toolName string)
RecordCall records a destructive tool call for rate limiting. This should be called AFTER the tool executes successfully.
func (*DestructiveTracker) Reset ¶ added in v1.12.0
func (d *DestructiveTracker) Reset()
Reset resets the tracker state (useful for testing or manual override).
func (*DestructiveTracker) Stats ¶ added in v1.12.0
func (d *DestructiveTracker) Stats() map[string]any
Stats returns current statistics for monitoring.
type DiagnosticsResult ¶
type DiagnosticsResult struct {
Database DatabaseHealth `json:"database"`
Config ConfigHealth `json:"config"`
Channels []ChannelDiagnostic `json:"channels"`
RecentErrors []AuditRecordShort `json:"recent_errors,omitempty"`
Memory MemoryStats `json:"memory"`
Disk DiskStats `json:"disk"`
}
DiagnosticsResult represents comprehensive system diagnostics.
type DiscoveredModel ¶ added in v1.13.0
type DiscoveredModel struct {
// Name is the model identifier (e.g. "llama3:latest").
Name string `json:"name"`
// Provider is the source provider ("ollama", "vllm").
Provider string `json:"provider"`
// ContextWindow is the context window size in tokens (0 = unknown).
ContextWindow int `json:"context_window,omitempty"`
// ParameterSize is a human-readable parameter count (e.g. "7B", "70B").
ParameterSize string `json:"parameter_size,omitempty"`
}
DiscoveredModel holds metadata about a model found via provider discovery.
type DiskStats ¶
type DiskStats struct {
TotalGB float64 `json:"total_gb"`
FreeGB float64 `json:"free_gb"`
UsedPct float64 `json:"used_pct"`
}
DiskStats represents disk usage statistics.
type DreamConfig ¶ added in v1.17.0
type DreamConfig struct {
// Enabled controls whether the dream system is active. Default: true.
Enabled bool `yaml:"enabled"`
// MinHoursBetween is the minimum hours between dream runs (Gate 1). Default: 6.
MinHoursBetween int `yaml:"min_hours_between"`
// MinSessionsBetween is the minimum sessions between dream runs (Gate 2). Default: 2.
MinSessionsBetween int `yaml:"min_sessions_between"`
// MaxMemoriesToProcess limits how many memories to analyze per dream. Default: 100.
MaxMemoriesToProcess int `yaml:"max_memories_to_process"`
// IdleMinutes is how long the daemon must be idle before triggering. Default: 10.
IdleMinutes int `yaml:"idle_minutes"`
}
DreamConfig configures the background memory consolidation system.
func DefaultDreamConfig ¶ added in v1.17.0
func DefaultDreamConfig() DreamConfig
DefaultDreamConfig returns sensible defaults.
type DreamConsolidator ¶ added in v1.17.0
type DreamConsolidator struct {
// contains filtered or unexported fields
}
DreamConsolidator manages background memory consolidation.
func NewDreamConsolidator ¶ added in v1.17.0
func NewDreamConsolidator(config DreamConfig, store memory.Store, stateDir string, logger *slog.Logger) *DreamConsolidator
NewDreamConsolidator creates a new dream consolidator.
func (*DreamConsolidator) ForceRun ¶ added in v1.18.2
func (d *DreamConsolidator) ForceRun(ctx context.Context) DreamResult
ForceRun bypasses all trigger gates and runs a dream cycle immediately. Used by the memory(action="dream_force") tool for on-demand consolidation.
func (*DreamConsolidator) RecordCompaction ¶ added in v1.18.0
func (d *DreamConsolidator) RecordCompaction()
RecordCompaction increments the compaction counter. For persistent sessions (WhatsApp), compactions serve as the activity signal since sessions never formally end.
func (*DreamConsolidator) RecordSession ¶ added in v1.17.0
func (d *DreamConsolidator) RecordSession()
RecordSession increments the session counter (Gate 2). Called by the assistant when a session ends.
func (*DreamConsolidator) Run ¶ added in v1.17.0
func (d *DreamConsolidator) Run(ctx context.Context) DreamResult
Run executes a single dream consolidation cycle. Phases: Orient → Gather → Consolidate → Apply
func (*DreamConsolidator) Start ¶ added in v1.17.0
func (d *DreamConsolidator) Start(ctx context.Context)
Start begins the background dream loop. It checks gates periodically and runs consolidation when conditions are met.
func (*DreamConsolidator) State ¶ added in v1.17.0
func (d *DreamConsolidator) State() DreamState
State returns the current dream state (for observability).
func (*DreamConsolidator) Stop ¶ added in v1.17.0
func (d *DreamConsolidator) Stop()
Stop halts the background dream loop.
func (*DreamConsolidator) WithHierarchyConfig ¶ added in v1.18.0
func (d *DreamConsolidator) WithHierarchyConfig(cfg HierarchyConfig) *DreamConsolidator
WithHierarchyConfig provides the hierarchy feature flag and keyword map needed to gate and drive the legacy classifier phase.
func (*DreamConsolidator) WithSQLiteStore ¶ added in v1.18.0
func (d *DreamConsolidator) WithSQLiteStore(s *memory.SQLiteStore) *DreamConsolidator
WithSQLiteStore wires an optional *SQLiteStore into the consolidator so the classifier phase can run during dream cycles. Keeps the memory.Store interface unbroken (Option A).
type DreamResult ¶ added in v1.17.0
type DreamResult struct {
MemoriesAnalyzed int `json:"memories_analyzed"`
Duplicates int `json:"duplicates_merged"`
Contradictions int `json:"contradictions_found"`
Consolidated int `json:"consolidated"`
Duration time.Duration `json:"duration"`
Error error `json:"-"`
}
DreamResult holds the outcome of a dream consolidation run.
type DreamState ¶ added in v1.17.0
type DreamState struct {
LastDreamAt time.Time `json:"last_dream_at"`
SessionsSince int `json:"sessions_since"`
CompactionsSince int `json:"compactions_since"` // proxy for sessions in persistent channels (WhatsApp)
TotalDreams int `json:"total_dreams"`
LastResult string `json:"last_result"` // "success", "error", "no_changes"
}
DreamState persists the dream system's state between restarts.
type ErrEscalation ¶ added in v1.16.0
type ErrEscalation struct {
Signal *EscalationSignal
}
ErrEscalation is returned when an agent run is terminated due to escalation.
func (*ErrEscalation) Error ¶ added in v1.16.0
func (e *ErrEscalation) Error() string
type EscalationSignal ¶ added in v1.16.0
type EscalationSignal struct {
Reason string // Why the agent is escalating.
Summary string // Summary of context/work done so far.
}
EscalationSignal indicates that a plugin agent wants to escalate to the main agent.
type EventBus ¶
type EventBus struct {
// contains filtered or unexported fields
}
EventBus is a thread-safe pub/sub hub for agent events. Subscribers receive events synchronously during Emit — callers should keep listener logic fast or dispatch to goroutines internally.
func (*EventBus) CleanupRun ¶
CleanupRun removes the sequence counter for a completed run.
func (*EventBus) Emit ¶
func (eb *EventBus) Emit(event AgentEvent)
Emit sends an event to all registered listeners. The event's Seq field is auto-assigned using an atomic counter scoped to the run ID.
func (*EventBus) EmitThinkingDelta ¶
EmitThinkingDelta emits a thinking_delta event with a partial reasoning token.
func (*EventBus) EmitThinkingEnd ¶
EmitThinkingEnd emits a thinking_end event. Callers are responsible for deduplication — this method emits unconditionally. The recommended pattern is to track a thinkingActive bool and only call EmitThinkingEnd once.
func (*EventBus) EmitThinkingStart ¶
EmitThinkingStart emits a thinking_start event signalling the beginning of an extended thinking / reasoning block.
func (*EventBus) EmitToolResult ¶
EmitToolResult emits a tool result event.
func (*EventBus) EmitToolUse ¶
EmitToolUse emits a tool invocation event.
func (*EventBus) Subscribe ¶
func (eb *EventBus) Subscribe(fn EventListener) func()
Subscribe registers a listener and returns an unsubscribe function. The listener is called synchronously for every emitted event.
func (*EventBus) SubscribeRun ¶
func (eb *EventBus) SubscribeRun(runID string, fn EventListener) func()
SubscribeRun registers a listener that only receives events for a specific run. Returns an unsubscribe function.
type EventListener ¶
type EventListener func(event AgentEvent)
EventListener is a callback that receives agent events.
type ExecAnalysisConfig ¶
type ExecAnalysisConfig struct {
// Enabled turns the analysis on/off.
Enabled bool `yaml:"enabled"`
// Categories configures each risk category.
Categories map[RiskLevel]RiskCategoryConfig `yaml:"categories"`
// SafeBins lists binary paths that are always safe.
SafeBins []string `yaml:"safe_bins"`
// Trust configures per-role trust levels.
Trust TrustConfig `yaml:"trust"`
// SuspiciousPatterns are regex patterns for suspicious constructs.
SuspiciousPatterns []string `yaml:"suspicious_patterns"`
// DefaultAction is the action for commands that don't match any category.
DefaultAction RiskAction `yaml:"default_action"`
}
ExecAnalysisConfig configures the exec analysis system.
func DefaultExecAnalysisConfig ¶
func DefaultExecAnalysisConfig() ExecAnalysisConfig
DefaultExecAnalysisConfig returns sensible defaults.
type ExecAnalysisResult ¶
type ExecAnalysisResult struct {
// Risk is the determined risk level.
Risk RiskLevel
// Action is the action to take.
Action RiskAction
// Reason explains why this risk level was assigned.
Reason string
// MatchedPattern is the pattern that matched (if any).
MatchedPattern string
// IsSuspicious indicates if suspicious constructs were found.
IsSuspicious bool
// SuspiciousMatches lists the suspicious patterns found.
SuspiciousMatches []string
}
ExecAnalysisResult contains the analysis result for a command.
type ExecAnalyzer ¶
type ExecAnalyzer struct {
// contains filtered or unexported fields
}
ExecAnalyzer analyzes commands for risk.
func NewExecAnalyzer ¶
func NewExecAnalyzer(cfg ExecAnalysisConfig, logger *slog.Logger) *ExecAnalyzer
NewExecAnalyzer creates a new command analyzer.
func (*ExecAnalyzer) Analyze ¶
func (a *ExecAnalyzer) Analyze(command string) ExecAnalysisResult
Analyze analyzes a command and returns the risk assessment.
func (*ExecAnalyzer) AnalyzeForRole ¶
func (a *ExecAnalyzer) AnalyzeForRole(command string, role string) ExecAnalysisResult
AnalyzeForRole analyzes a command considering the user's role.
type ExecQueueItem ¶
type ExecQueueItem struct {
ID string `json:"id"`
Tool string `json:"tool"`
Caller string `json:"caller"`
SessionID string `json:"session_id"`
Description string `json:"description"`
CreatedAt time.Time `json:"created_at"`
}
ExecQueueItem represents a pending execution approval.
type ExportedMessage ¶
type ExportedMessage struct {
User string `json:"user"`
Assistant string `json:"assistant"`
Timestamp time.Time `json:"timestamp"`
}
ExportedMessage is a single message in an exported session.
type ExtractedMemory ¶ added in v1.17.0
type ExtractedMemory struct {
// Type classifies the memory for retrieval and organization.
// Values: "decision", "preference", "fact", "learning", "context"
Type string `json:"type"`
// Content is the extracted information in concise, self-contained form.
Content string `json:"content"`
// Importance is a 1-5 score indicating how valuable this memory is.
// 5 = critical decision, 1 = minor observation.
Importance int `json:"importance"`
}
ExtractedMemory represents a single piece of information extracted from conversation history that should be preserved in long-term memory.
type FailoverCoordinator ¶ added in v1.13.0
type FailoverCoordinator struct {
// contains filtered or unexported fields
}
FailoverCoordinator unifies profile management and model failover into a single system with consistent error classification and cooldown management.
func NewFailoverCoordinator ¶ added in v1.13.0
func NewFailoverCoordinator(profileMgr profiles.ProfileManager, modelCfg ModelFallbackConfig, logger *slog.Logger) *FailoverCoordinator
NewFailoverCoordinator creates a coordinator that wraps profile and model managers.
func (*FailoverCoordinator) GetModelManager ¶ added in v1.13.0
func (fc *FailoverCoordinator) GetModelManager() *ModelFailoverManager
GetModelManager returns the underlying model failover manager (for direct access when needed).
func (*FailoverCoordinator) HasProfileManager ¶ added in v1.13.0
func (fc *FailoverCoordinator) HasProfileManager() bool
HasProfileManager returns true if a profile manager is configured.
func (*FailoverCoordinator) ReportFailure ¶ added in v1.13.0
func (fc *FailoverCoordinator) ReportFailure(model string, profileID profiles.ProfileID, statusCode int, errMsg string) FailoverReason
ReportFailure classifies an error ONCE and applies consistent cooldowns to both the model and profile systems. This eliminates the inconsistency where the same error could be classified differently by each system.
func (*FailoverCoordinator) ReportFailureWithCause ¶ added in v1.16.0
func (fc *FailoverCoordinator) ReportFailureWithCause(model string, profileID profiles.ProfileID, statusCode int, errMsg string, cause error) FailoverReason
ReportFailureWithCause is like ReportFailure but also traverses the error cause chain for more accurate classification of wrapped errors (e.g., RESOURCE_EXHAUSTED wrapped in AbortError).
func (*FailoverCoordinator) ReportSuccess ¶ added in v1.13.0
func (fc *FailoverCoordinator) ReportSuccess(model string, profileID profiles.ProfileID)
ReportSuccess records a successful call for both model and profile.
func (*FailoverCoordinator) SelectModelAndProfile ¶ added in v1.13.0
func (fc *FailoverCoordinator) SelectModelAndProfile(provider, modelOverride string, fallbacksOverride ...string) (model string, profileID profiles.ProfileID, apiKey string, err error)
SelectModelAndProfile resolves the best model and profile for a request. Returns the selected model, profile ID, API key, and any error. Optional fallbacksOverride temporarily overrides the fallback chain for this single request, useful for per-channel or per-skill model preferences.
type FailoverReason ¶
type FailoverReason string
FailoverReason classifies why a model failed.
const ( FailoverBilling FailoverReason = "billing" // 402 Payment Required FailoverRateLimit FailoverReason = "rate_limit" // 429 Too Many Requests, 529 Overloaded FailoverAuth FailoverReason = "auth" // 401 (transient) FailoverAuthPermanent FailoverReason = "auth_permanent" // 403, revoked keys, deactivated accounts FailoverSessionExpired FailoverReason = "session_expired" // Token expired/revoked FailoverTimeout FailoverReason = "timeout" // 408, ETIMEDOUT, empty chunks, Cloudflare 521-530 FailoverFormat FailoverReason = "format" // 400 Bad Request FailoverServer FailoverReason = "server" // 5xx (excluding Cloudflare CDN codes) FailoverModelNotFound FailoverReason = "model_not_found" // Model doesn't exist for this provider FailoverUnknown FailoverReason = "unknown" )
func ClassifyError ¶
func ClassifyError(statusCode int, errMsg string) FailoverReason
ClassifyError determines the failover reason from an HTTP status code and error message.
func ClassifyErrorFull ¶ added in v1.16.0
func ClassifyErrorFull(statusCode int, errMsg string, cause error) FailoverReason
ClassifyErrorFull determines the failover reason by examining the HTTP status code, error message, AND the full error cause chain. It walks inner causes before applying timeout heuristics, so a RESOURCE_EXHAUSTED wrapped in an AbortError is correctly classified as rate_limit, not timeout.
type FallbackConfig ¶
type FallbackConfig struct {
// Models is the ordered list of fallback models to try on failure.
// Supports N providers: primary -> fallback1 -> fallback2 -> ... -> local.
Models []string `yaml:"models"`
// Chain defines provider-specific fallback with separate base_url/api_key.
// Each entry is a complete provider config tried in order on failure.
Chain []ProviderChainEntry `yaml:"chain"`
// MaxRetries per model before moving to next (default: 2).
MaxRetries int `yaml:"max_retries"`
// InitialBackoffMs is the initial retry delay in ms (default: 1000).
InitialBackoffMs int `yaml:"initial_backoff_ms"`
// MaxBackoffMs caps the backoff (default: 30000).
MaxBackoffMs int `yaml:"max_backoff_ms"`
// RetryOnStatusCodes lists HTTP codes that trigger retry (default: [429, 500, 502, 503, 529]).
RetryOnStatusCodes []int `yaml:"retry_on_status_codes"`
}
FallbackConfig configures model fallback and retry behavior.
func DefaultFallbackConfig ¶
func DefaultFallbackConfig() FallbackConfig
DefaultFallbackConfig returns sensible defaults for model fallback.
func (FallbackConfig) Effective ¶
func (f FallbackConfig) Effective() FallbackConfig
Effective returns a copy with default values filled in for zero fields.
type FormField ¶ added in v1.13.0
type FormField struct {
Ref string `json:"ref"`
Type string `json:"type"` // textbox, checkbox, radio, combobox
Value string `json:"value"` // For text inputs
}
FormField represents a form field for fill action.
type FunctionCall ¶
FunctionCall holds the function name and serialized arguments from the LLM.
type FunctionDef ¶
type FunctionDef struct {
Name string `json:"name"`
Description string `json:"description"`
Parameters json.RawMessage `json:"parameters"`
}
FunctionDef describes a callable function exposed to the LLM.
type GatewayConfig ¶
type GatewayConfig struct {
// Enabled turns the gateway on/off (default: false).
Enabled bool `yaml:"enabled"`
// Address is the listen address (default: ":8085").
Address string `yaml:"address"`
// AuthToken is the Bearer token for /api/* and /v1/* auth (empty = no auth).
AuthToken string `yaml:"auth_token"`
// CORSOrigins lists allowed origins for CORS (empty = no CORS).
CORSOrigins []string `yaml:"cors_origins"`
// TLS configures HTTPS for the gateway.
TLS TLSConfig `yaml:"tls"`
}
GatewayConfig configures the HTTP API gateway.
type GroupConfig ¶
type GroupConfig struct {
// ActivationMode controls when the bot responds in groups:
// "always" — responds to all messages (default)
// "mention" — only when mentioned by name/trigger
// "reply" — only when replied to directly
ActivationMode string `yaml:"activation_mode"`
// IntroMessage is sent when the bot joins a new group.
// Empty = no intro. Supports template variables: {{name}}, {{trigger}}.
IntroMessage string `yaml:"intro_message"`
// ContextInjection adds group-specific context to the system prompt.
// Useful for per-group instructions, rules, or personas.
ContextInjection map[string]string `yaml:"context_injection"`
// MaxParticipants limits context tracking for group participants.
// Names of the last N participants are included in the prompt for
// natural multi-party conversation (default: 20).
MaxParticipants int `yaml:"max_participants"`
// QuietHours defines time ranges when the bot won't respond in groups
// (e.g. "23:00-07:00"). Empty = always active.
QuietHours string `yaml:"quiet_hours"`
// IgnorePatterns are regex patterns for messages the bot should ignore
// even when activated (e.g. forwarded messages, bot commands for other bots).
IgnorePatterns []string `yaml:"ignore_patterns"`
}
GroupConfig configures group chat behavior.
type GroupManager ¶
type GroupManager struct {
// contains filtered or unexported fields
}
GroupManager handles group-specific behavior and state.
func NewGroupManager ¶
func NewGroupManager(cfg GroupConfig) *GroupManager
NewGroupManager creates a new group manager with the given config.
func (*GroupManager) BuildGroupPromptContext ¶
func (gm *GroupManager) BuildGroupPromptContext(chatID, botName string) string
BuildGroupPromptContext builds a group-specific section for the system prompt.
func (*GroupManager) GetContextInjection ¶
func (gm *GroupManager) GetContextInjection(chatID string) string
GetContextInjection returns any group-specific context for the given chatID.
func (*GroupManager) GetIntroMessage ¶
func (gm *GroupManager) GetIntroMessage(chatID, botName, trigger string) string
GetIntroMessage returns the intro message for a group, or empty if already sent. Marks the group as introduced so the message is only sent once.
func (*GroupManager) GetParticipants ¶
func (gm *GroupManager) GetParticipants(chatID string) []string
GetParticipants returns the recent participant names for a group.
func (*GroupManager) ShouldRespond ¶
func (gm *GroupManager) ShouldRespond(chatID, senderName, messageText, botName, trigger string) (bool, string)
ShouldRespond determines if the bot should respond to a group message. Returns (respond bool, reason string).
func (*GroupManager) TrackParticipant ¶
func (gm *GroupManager) TrackParticipant(chatID, name string)
TrackParticipant records a participant's activity in a group.
type GroupPolicy ¶
type GroupPolicy string
GroupPolicy defines the access policy for a group.
const ( // GroupPolicyOpen allows all group members to use the bot. GroupPolicyOpen GroupPolicy = "open" // GroupPolicyDisabled prevents the bot from responding in this group. GroupPolicyDisabled GroupPolicy = "disabled" // GroupPolicyAllowlist restricts access to allowed users only. GroupPolicyAllowlist GroupPolicy = "allowlist" )
type GroupPolicyConfig ¶
type GroupPolicyConfig struct {
// ID is the group JID.
ID string `yaml:"id"`
// Name is a human-readable name for the group.
Name string `yaml:"name"`
// Policy is the access policy for this group.
Policy GroupPolicy `yaml:"policy"`
// Activation is the activation mode.
Activation ActivationMode `yaml:"activation"`
// Keywords trigger the bot in keyword mode.
Keywords []string `yaml:"keywords"`
// Workspace is the workspace to use for this group.
Workspace string `yaml:"workspace"`
// QuietHours defines when the bot should be silent.
QuietHours *QuietHoursConfig `yaml:"quiet_hours"`
// MaxParticipants ignores messages in groups larger than this (0 = unlimited).
MaxParticipants int `yaml:"max_participants"`
// AllowedUsers is the list of allowed user JIDs for allowlist policy.
AllowedUsers []string `yaml:"allowed_users"`
}
GroupPolicyConfig holds configuration for a specific group's policy.
type GroupPolicyManager ¶
type GroupPolicyManager struct {
// contains filtered or unexported fields
}
GroupPolicyManager manages group-specific policies.
func NewGroupPolicyManager ¶
func NewGroupPolicyManager(cfg GroupsPolicyConfig, logger *slog.Logger) *GroupPolicyManager
NewGroupPolicyManager creates a new group policy manager.
func (*GroupPolicyManager) GetGroupConfig ¶
func (m *GroupPolicyManager) GetGroupConfig(groupJID string) *GroupPolicyConfig
GetGroupConfig returns the configuration for a group. Returns a default config if the group is not explicitly configured.
func (*GroupPolicyManager) GetWorkspace ¶
func (m *GroupPolicyManager) GetWorkspace(groupJID string) string
GetWorkspace returns the workspace for a group, or empty string if not set.
func (*GroupPolicyManager) IsBlocked ¶
func (m *GroupPolicyManager) IsBlocked(groupJID string) bool
IsBlocked returns true if the group is blocked.
func (*GroupPolicyManager) IsQuietHours ¶
func (m *GroupPolicyManager) IsQuietHours(cfg *GroupPolicyConfig) bool
IsQuietHours checks if quiet hours are active for a group.
func (*GroupPolicyManager) ListBlocked ¶
func (m *GroupPolicyManager) ListBlocked() []string
ListBlocked returns all blocked group IDs.
func (*GroupPolicyManager) ListGroups ¶
func (m *GroupPolicyManager) ListGroups() []string
ListGroups returns all configured group IDs.
func (*GroupPolicyManager) ShouldRespond ¶
func (m *GroupPolicyManager) ShouldRespond(groupJID, userJID string, content string, isReplyToBot bool, trigger string) bool
ShouldRespond determines if the bot should respond to a message in a group.
type GroupsPolicyConfig ¶
type GroupsPolicyConfig struct {
// DefaultPolicy is the policy for groups not explicitly configured.
DefaultPolicy GroupPolicy `yaml:"default_policy"`
// Groups is the list of group-specific configurations.
Groups []GroupPolicyConfig `yaml:"groups"`
// Blocked is the list of blocked group JIDs.
Blocked []string `yaml:"blocked"`
}
GroupsPolicyConfig holds all group policy configuration.
type HandlerConfig ¶
type HandlerConfig struct {
// Event is the hook event to listen to.
Event string `yaml:"event"`
// Action is the action to take (notify_admins, send_message).
Action string `yaml:"action"`
// Template is a Go template for the action output.
Template string `yaml:"template"`
// Enabled controls whether this handler is active.
Enabled bool `yaml:"enabled"`
}
HandlerConfig configures an internal hook handler.
type HealthCheckResult ¶
type HealthCheckResult struct {
Component string `json:"component"`
Status string `json:"status"` // "PASS", "FAIL", "WARN"
Message string `json:"message"`
LatencyMs int64 `json:"latency_ms,omitempty"`
}
HealthCheckResult represents the result of a health check.
type Heartbeat ¶
type Heartbeat struct {
// contains filtered or unexported fields
}
Heartbeat runs periodic checks and proactive behavior.
func NewHeartbeat ¶
func NewHeartbeat(cfg HeartbeatConfig, assistant *Assistant, logger *slog.Logger) *Heartbeat
NewHeartbeat creates a new heartbeat instance.
func (*Heartbeat) UpdateConfig ¶
func (h *Heartbeat) UpdateConfig(cfg HeartbeatConfig)
UpdateConfig updates the heartbeat config from hot-reload.
type HeartbeatConfig ¶
type HeartbeatConfig struct {
// Enabled turns the heartbeat on/off.
Enabled bool `yaml:"enabled"`
// Interval is the time between heartbeat ticks.
// Default: 30 minutes.
Interval time.Duration `yaml:"interval"`
// ActiveStart is the earliest hour the heartbeat runs (e.g., 9 for 9 AM).
ActiveStart int `yaml:"active_start"`
// ActiveEnd is the latest hour the heartbeat runs (e.g., 22 for 10 PM).
ActiveEnd int `yaml:"active_end"`
// Channel is the default channel to send proactive messages to.
Channel string `yaml:"channel"`
// ChatID is the default chat to send proactive messages to.
ChatID string `yaml:"chat_id"`
// WorkspaceDir is the workspace directory where HEARTBEAT.md is located.
WorkspaceDir string `yaml:"workspace_dir"`
// IsolateSession creates a fresh session for each heartbeat tick.
// This prevents the heartbeat session from growing large over time
// at the cost of losing inter-heartbeat context. Default: false.
IsolateSession bool `yaml:"isolate_session"`
}
HeartbeatConfig configures the heartbeat system.
func DefaultHeartbeatConfig ¶
func DefaultHeartbeatConfig() HeartbeatConfig
DefaultHeartbeatConfig returns sensible defaults for the heartbeat.
type HierarchyConfig ¶ added in v1.18.0
type HierarchyConfig struct {
// Enabled turns palace-aware memory on or off at the subsystem level.
//
// When false:
// - The context router is instantiated but Resolve always returns
// SourceDisabled with an empty wing.
// - The memory_list_wings / memory_list_rooms / memory_get_taxonomy
// tools return a "feature disabled" error.
// - Search continues to use the v1.17.0 hybrid fusion without any
// wing boost. Byte-identical behavior guaranteed.
// - Schema additions remain in the DB (harmless: new columns are
// nullable, new tables are empty).
//
// When true:
// - Context router resolves (channel, chatID) to wings.
// - Palace tools are fully functional.
// - Wing boost is applied in hybrid search (Sprint 2).
// - L0/L1/L2 layered memory stack activates (Sprint 2).
//
// Default: true (since v1.18.0 / MemPalace).
Enabled bool `yaml:"enabled"`
// DefaultWing is the fallback wing assigned when neither explicit
// mapping nor heuristics match. Empty string (the default) means
// "wing IS NULL" — the legacy first-class citizen behavior per ADR-006.
//
// Setting this to a non-empty value changes semantics: new memories
// arriving through unmapped channels get assigned to DefaultWing
// rather than staying as legacy. Use with caution — this effectively
// "backfills by default" which violates Princípio Zero rule 4 unless
// the user explicitly opts in.
DefaultWing string `yaml:"default_wing"`
// L1Budget is the token budget for Layer 1 (essential story).
// Sprint 2 Room 2.2 consumes this as a byte-budget approximation
// (1 token ≈ 4 bytes → 400 tokens ≈ 1600 bytes). Default: 400 tokens.
L1Budget int `yaml:"l1_budget_tokens,omitempty"`
// L2Budget is the token budget for Layer 2 (on-demand retrieval).
// Sprint 2 reads this. Default: 300 tokens.
L2Budget int `yaml:"l2_budget_tokens"`
// OnDemandMaxResults caps how many memories the L2 OnDemandLayer returns
// per Render call. Default: 5.
OnDemandMaxResults int `yaml:"on_demand_max_results,omitempty"`
// OnDemandCrossWingEnabled controls whether the L2 OnDemandLayer may
// return memories from a wing other than the active wing when nothing is
// found in the active wing. Default: true.
OnDemandCrossWingEnabled bool `yaml:"on_demand_cross_wing,omitempty"`
// TopicChangeThreshold is the cosine similarity below which a topic
// change is detected. Lower = more sensitive. Default: 0.65.
TopicChangeThreshold float64 `yaml:"topic_change_threshold,omitempty"`
// TopicChangeEntityOverlap is the entity overlap ratio below which
// the cosine stage is triggered. Default: 0.3.
TopicChangeEntityOverlap float64 `yaml:"topic_change_entity_overlap,omitempty"`
// EssentialStoryStaleAfter is the TTL before the L1 EssentialLayer
// regenerates a cached per-wing story. Applies to the essential_stories
// SQLite cache introduced in Sprint 2 Room 2.2. Default: 6 hours.
EssentialStoryStaleAfter time.Duration `yaml:"essential_story_stale_after,omitempty"`
// EssentialStoryRoomsPerWing caps how many rooms the L1 template walks
// when rendering a wing's essential story. Higher values include more
// context at the cost of hitting the byte budget sooner. Default: 4.
EssentialStoryRoomsPerWing int `yaml:"essential_story_rooms_per_wing,omitempty"`
// WingBoostMatch is the multiplier applied to search scores when a
// document's wing matches the query's wing. Sprint 2 reads this.
// Default: 1.3. See doc-02-errata.md correction 3 — the value is
// relative to DevClaw's weighted inverse rank fusion, NOT standard RRF k=60.
WingBoostMatch float64 `yaml:"wing_boost_match,omitempty"`
// WingBoostPenalty is the multiplier applied when a document's wing
// differs from the query's wing. Default: 0.4 (-60% penalty).
WingBoostPenalty float64 `yaml:"wing_boost_penalty,omitempty"`
// AutoRoomCap is the maximum number of auto-created rooms per wing.
// When exceeded, the least recently used auto-only rooms are archived.
// Default: 30. See ADR-002 Addendum A.
AutoRoomCap int `yaml:"auto_room_cap"`
// AutoRoomDedupeDistance is the Levenshtein distance threshold for
// insert-time room deduplication. If a candidate room has distance
// <= this value from an existing auto-room in the same wing, the
// existing room is reused instead of creating a new one. Default: 2.
AutoRoomDedupeDistance int `yaml:"auto_room_dedupe_distance"`
// IdentityPath is the filesystem path to the L0 identity markdown file.
// Sprint 2 reads this. Empty string uses the default:
// ~/.devclaw/identity.md. Sprint 1 stores it but does not consume it.
IdentityPath string `yaml:"identity_path"`
// Heuristics is the user-provided list of channel/group name patterns
// used by the context router's heuristic tier. The binary ships zero
// defaults — a fresh install classifies nothing (all memories land with
// wing=NULL) until the user opts in via YAML. This is intentional:
// hardcoded domain or locale keywords would be biased for an open-source
// project with diverse deployments.
//
// The router iterates this slice in order; first match wins (confidence 0.7).
// If nil or empty, the heuristic tier is a no-op and every unmapped
// message falls through to DefaultWing or wing=NULL.
Heuristics []WingHeuristic `yaml:"heuristics,omitempty"`
// LegacyKeywords is the keyword-to-wing mapping used by the legacy
// content classifier (RunLegacyClassificationPass). The binary ships
// zero defaults — the classifier is a no-op unless the user provides
// keywords here. This preserves locale and domain neutrality.
//
// Map key: wing identifier (e.g. "work", "family").
// Map value: list of lowercase substrings that signal that wing.
LegacyKeywords map[string][]string `yaml:"legacy_keywords,omitempty"`
// KG configures knowledge graph extraction (Sprint 3 Room 3.4).
// Default: AutoExtract="off", LLMBudgetPerCycle=20, LLMConsentACK=false.
KG KGConfig `yaml:"kg,omitempty"`
}
HierarchyConfig configures the palace-aware memory subsystem introduced in Sprint 1. It lives under MemoryConfig.Hierarchy and is opt-in: Enabled=false by default preserves v1.17.0 behavior byte-for-byte.
func DefaultHierarchyConfig ¶ added in v1.18.0
func DefaultHierarchyConfig() HierarchyConfig
DefaultHierarchyConfig returns the defaults for HierarchyConfig.
IMPORTANT — Sprint 1 amendment (2026-04-08): Enabled defaults to TRUE. This is a deliberate reversal of the original Sprint 0.5 "default off" stance. The rationale:
"wing IS NULL is a first-class citizen" (ADR-006) means legacy memories continue to work transparently even when the feature is on. The wing boost code path explicitly treats wing="" as NEUTRAL (no boost, no penalty), so a v1.17.0 user's search results remain the same ordering as before until they start classifying memories.
Feature flags that default off get abandoned. Most users never discover them. DevClaw's differentiator is its memory — it must ship active.
Sprint 1 adds only schema and tool infrastructure — it does NOT rewrite file paths or auto-migrate legacy data. A user upgrading from v1.17.0 sees no data change. The only visible surface is new bot commands (/wing, /room, /tree, /palace help) and new LLM tools that the agent can use to organize memories going forward.
Incremental improvement: as the user interacts with the assistant, new memories gradually get routed to wings (full integration in Sprint 2). The palace fills up organically. No config edits, no migrations, no surprises.
Users who need v1.17.0 byte-identical behavior can still opt out by setting memory.hierarchy.enabled: false in their YAML.
type HierarchyMetrics ¶ added in v1.18.0
type HierarchyMetrics struct {
// ContextRouterMapped counts Resolve calls that returned SourceMapped.
ContextRouterMapped uint64
// ContextRouterHeuristic counts Resolve calls that returned SourceHeuristic.
ContextRouterHeuristic uint64
// ContextRouterDefault counts Resolve calls that returned SourceDefault.
ContextRouterDefault uint64
// ContextRouterDisabled counts Resolve calls made while the flag is off.
ContextRouterDisabled uint64
// SearchWithWingFilter counts searches that used an explicit wing filter.
// Sprint 2 activates this counter when wing boost lands.
SearchWithWingFilter uint64
// SearchWithoutWingFilter counts searches that omitted the wing filter.
SearchWithoutWingFilter uint64
// ToolCallsByName is incremented by the palace tool handlers with the
// tool name as a label. Sprint 1 exposes the count via EmitSnapshot.
// Using a fixed set of counters avoids the need for a map in hot paths.
ListWingsCalls uint64
ListRoomsCalls uint64
GetTaxonomyCalls uint64
WingPinCalls uint64
WingUnpinCalls uint64
WingStatusCalls uint64
// contains filtered or unexported fields
}
HierarchyMetrics holds process-level counters for palace-aware features. Each counter is atomic and safe for concurrent use. Counters are exposed via EmitSnapshot which writes structured log lines that a log aggregator can scrape into Prometheus time series.
Sprint 1 scope: scaffolding and a minimal counter set. Sprint 2 adds the layer_tokens histogram. Sprint 3 adds KG-related counters.
func (*HierarchyMetrics) EmitSnapshot ¶ added in v1.18.0
func (m *HierarchyMetrics) EmitSnapshot(logger *slog.Logger)
EmitSnapshot logs the current counter values via slog at INFO level. Called periodically (e.g., every 5 minutes from a goroutine) to produce scrape-friendly log lines.
The log format is:
metric=<name> value=<n> component=palace
Log aggregators can parse these lines directly into Prometheus counters.
func (*HierarchyMetrics) Global ¶ added in v1.18.0
func (m *HierarchyMetrics) Global() *HierarchyMetrics
Global returns the process-wide metrics instance. Prefer the Inc* helpers for single-counter updates.
type HookAction ¶
type HookAction struct {
// Block prevents the operation from proceeding (PreToolUse, UserPromptSubmit).
Block bool
// Reason explains why the operation was blocked.
Reason string
// ModifiedArgs replaces ToolArgs if non-nil (PreToolUse only).
ModifiedArgs map[string]any
// ModifiedMessage replaces the user message if non-empty (UserPromptSubmit).
ModifiedMessage string
}
HookAction is the result returned by a hook handler.
type HookEvent ¶
type HookEvent string
HookEvent identifies the lifecycle point at which a hook fires.
const ( HookSessionStart HookEvent = "session_start" HookSessionEnd HookEvent = "session_end" HookUserPromptSubmit HookEvent = "user_prompt_submit" HookPreToolUse HookEvent = "pre_tool_use" HookPostToolUse HookEvent = "post_tool_use" HookAgentStart HookEvent = "agent_start" HookAgentStop HookEvent = "agent_stop" HookSubagentStart HookEvent = "subagent_start" HookSubagentStop HookEvent = "subagent_stop" HookPreCompact HookEvent = "pre_compact" HookPostCompact HookEvent = "post_compact" HookMemorySave HookEvent = "memory_save" HookMemoryRecall HookEvent = "memory_recall" HookNotification HookEvent = "notification" HookHeartbeat HookEvent = "heartbeat" HookError HookEvent = "error" HookUserJoin HookEvent = "user_join" HookUserLeave HookEvent = "user_leave" HookChannelConnect HookEvent = "channel_connect" HookChannelDisconnect HookEvent = "channel_disconnect" // Advanced hooks inspired by OpenClaw HookBeforeModelResolve HookEvent = "before_model_resolve" // Override provider/model selection HookBeforePromptBuild HookEvent = "before_prompt_build" // Inject/modify system prompt HookLLMInput HookEvent = "llm_input" // Modify prompt before sending to LLM HookLLMOutput HookEvent = "llm_output" // Modify LLM response HookToolResultPersist HookEvent = "tool_result_persist" // Transform tool result before persisting // Message pipeline hooks HookMessageTranscribed HookEvent = "message_transcribed" // Audio/media transcribed to text HookMessagePreprocessed HookEvent = "message_preprocessed" // After directives, links, enrichment HookBeforeReset HookEvent = "before_reset" // Before session/history reset )
type HookHandler ¶
type HookHandler func(ctx context.Context, payload HookPayload) HookAction
HookHandler processes a hook event and returns an action. Handlers should be fast and non-blocking. For async work, spawn a goroutine.
type HookManager ¶
type HookManager struct {
// contains filtered or unexported fields
}
HookManager manages lifecycle hook registration and dispatch.
func NewHookManager ¶
func NewHookManager(logger *slog.Logger) *HookManager
NewHookManager creates a new hook manager.
func (*HookManager) Dispatch ¶
func (hm *HookManager) Dispatch(ctx context.Context, payload HookPayload) HookAction
Dispatch fires all hooks for the given event and returns the combined action. For blocking events (PreToolUse, UserPromptSubmit), the first Block=true stops dispatch and returns immediately. For non-blocking events, all hooks run.
func (*HookManager) DispatchAsync ¶
func (hm *HookManager) DispatchAsync(payload HookPayload)
DispatchAsync fires all hooks for the event without waiting for them. Use for non-critical observe-only events (PostToolUse, Notification, etc.).
func (*HookManager) HasHooks ¶
func (hm *HookManager) HasHooks(event HookEvent) bool
HasHooks returns true if any hooks are registered for the given event.
func (*HookManager) HookCount ¶
func (hm *HookManager) HookCount() int
HookCount returns the total number of registered hooks.
func (*HookManager) ListDetailed ¶
func (hm *HookManager) ListDetailed() []HookSummary
ListDetailed returns a deduplicated list of all registered hooks with metadata.
func (*HookManager) ListHooks ¶
func (hm *HookManager) ListHooks() map[HookEvent][]string
ListHooks returns all registered hooks grouped by event.
func (*HookManager) Register ¶
func (hm *HookManager) Register(hook *RegisteredHook) error
Register adds a hook handler for the specified events.
func (*HookManager) SetEnabled ¶
func (hm *HookManager) SetEnabled(name string, enabled bool) bool
SetEnabled enables or disables a hook by name.
func (*HookManager) Unregister ¶
func (hm *HookManager) Unregister(name string) bool
Unregister removes all registrations for a hook by name.
type HookPayload ¶
type HookPayload struct {
// Event is the hook event type.
Event HookEvent
// SessionID is the session this event relates to (if applicable).
SessionID string
// Channel is the originating channel (if applicable).
Channel string
// ToolName is the tool being called (PreToolUse/PostToolUse).
ToolName string
// ToolArgs are the tool arguments (PreToolUse only).
ToolArgs map[string]any
// ToolResult is the tool output (PostToolUse only).
ToolResult string
// Message is a human-readable description or the user message content.
Message string
// Error is set for HookError events.
Error error
// Extra holds arbitrary key-value data for extensibility.
Extra map[string]any
// Advanced hook fields
// Model is the LLM model being used (HookBeforeModelResolve).
Model string
// SystemPrompt is the system prompt being built (HookBeforePromptBuild).
SystemPrompt string
// LLMInput is the input being sent to the LLM (HookLLMInput).
LLMInput string
// LLMOutput is the response from the LLM (HookLLMOutput).
LLMOutput string
// ToolCallID identifies the tool call for persistence hooks.
ToolCallID string
}
HookPayload carries contextual data for a hook invocation. Fields are populated based on the event type; unused fields are zero-valued.
type HookRequirements ¶ added in v1.13.0
type HookRequirements struct {
// Binaries that must be in PATH (e.g. ["ffmpeg", "jq"]).
Bins []string `yaml:"bins,omitempty" json:"bins,omitempty"`
// Environment variables that must be non-empty (e.g. ["SLACK_WEBHOOK_URL"]).
Env []string `yaml:"env,omitempty" json:"env,omitempty"`
// OS restricts the hook to specific operating systems (e.g. ["linux", "darwin"]).
// Empty = all platforms.
OS []string `yaml:"os,omitempty" json:"os,omitempty"`
}
HookRequirements declares runtime prerequisites for a hook. If any requirement is not met, the hook is silently skipped during dispatch.
func (*HookRequirements) Met ¶ added in v1.13.0
func (r *HookRequirements) Met() bool
Met returns true if all requirements are satisfied on the current system.
type HookSummary ¶
type HookSummary struct {
Name string `json:"name"`
Description string `json:"description"`
Source string `json:"source"`
Events []HookEvent `json:"events"`
Priority int `json:"priority"`
Enabled bool `json:"enabled"`
Requires *HookRequirements `json:"requires,omitempty"`
}
HookSummary is a serializable representation of a registered hook (no handler).
type HooksConfig ¶
type HooksConfig struct {
// Enabled turns the hooks system on/off.
Enabled bool `yaml:"enabled"`
// Webhooks is the list of external webhook configurations.
Webhooks []WebhookConfig `yaml:"webhooks"`
// Handlers is the list of internal hook handlers.
Handlers []HandlerConfig `yaml:"handlers"`
}
HooksConfig holds all hook configuration.
type Hunk ¶ added in v1.12.0
type Hunk struct {
Kind HunkKind
Add *AddFileHunk
Delete *DeleteFileHunk
Update *UpdateFileHunk
}
Hunk encapsulates one of Add, Delete, or Update operations.
type IDEConfig ¶
type IDEConfig struct {
MCPPort int `yaml:"mcp_port" json:"mcp_port"`
MCPHost string `yaml:"mcp_host" json:"mcp_host"`
Transport string `yaml:"transport" json:"transport"` // stdio, sse
}
IDEConfig holds configuration for IDE extension generation.
func DefaultIDEConfig ¶
func DefaultIDEConfig() IDEConfig
DefaultIDEConfig returns sensible defaults.
type IdentityConfig ¶ added in v1.13.0
type IdentityConfig struct {
// Name is the display name (e.g. "Aria", "DevClaw").
Name string `yaml:"name"`
// Emoji is the reaction/acknowledgment emoji (e.g. "🦊").
Emoji string `yaml:"emoji"`
// Theme is the personality theme (e.g. "helpful hacker", "friendly mentor").
Theme string `yaml:"theme"`
// Avatar is a URL or file path to the assistant's avatar image.
Avatar string `yaml:"avatar"`
// Vibe is a short phrase describing the assistant's tone/style.
Vibe string `yaml:"vibe"`
// Creature is the mascot type (e.g. "fox", "owl", "cat").
Creature string `yaml:"creature"`
}
IdentityConfig configures the assistant's persona and identity.
func ParseIdentityFile ¶ added in v1.13.0
func ParseIdentityFile(content string) IdentityConfig
ParseIdentityFile extracts structured identity fields from an IDENTITY.md file. Supports two formats:
- YAML-like "key: value" lines (e.g. "name: Aria")
- Markdown headers followed by content (e.g. "# Name\nAria")
Unrecognized lines are collected as the vibe if no explicit vibe is set.
func ResolveIdentity ¶ added in v1.13.0
func ResolveIdentity(cfg *Config, agentProfile *AgentProfileConfig, identityFileContent string) IdentityConfig
ResolveIdentity returns the effective identity by merging sources in priority order:
- AgentProfile.Identity (if agent routing matched)
- IDENTITY.md content (parsed for structured fields)
- Config.Identity
- Fallback: Config.Name
Fields are merged individually: a higher-priority source only overrides fields it actually sets (non-empty), so a profile can override just the name while inheriting the theme from config.
func (IdentityConfig) EffectiveName ¶ added in v1.13.0
func (ic IdentityConfig) EffectiveName(fallback string) string
EffectiveName returns the identity name if set, otherwise the fallback.
func (IdentityConfig) IsEmpty ¶ added in v1.13.0
func (ic IdentityConfig) IsEmpty() bool
IsEmpty returns true if no identity fields are set.
type IncompleteWork ¶ added in v1.17.0
type IncompleteWork struct {
// CheckName identifies which check failed.
CheckName string
// Reminder is the suggested action.
Reminder string
}
IncompleteWork represents a detected incomplete work pattern.
type IndexConfig ¶
type IndexConfig struct {
// Auto enables automatic re-indexing on file changes (default: true).
Auto bool `yaml:"auto"`
// ChunkMaxTokens is the max tokens per chunk (default: 500).
ChunkMaxTokens int `yaml:"chunk_max_tokens"`
}
IndexConfig configures automatic memory indexing.
type InlineDirectives ¶ added in v1.13.0
type InlineDirectives struct {
Think string // "off", "low", "medium", "high"
Model string // model override for this message
Verbose *bool // nil = not set, true/false = override
Queue string // queue mode override
Language string // response language hint
}
InlineDirectives holds directives extracted from a message body.
func ParseInlineDirectives ¶ added in v1.13.0
func ParseInlineDirectives(body string) (InlineDirectives, string)
ParseInlineDirectives extracts inline directives from a message body. Returns the directives found and the cleaned body with directives removed. Directives can appear at the beginning or end of the message.
Examples:
"/think high explain quantum physics" → Think="high", body="explain quantum physics" "explain this /model gpt-4o" → Model="gpt-4o", body="explain this" "/think high /verbose on" → Think="high", Verbose=true, body=""
func (InlineDirectives) HasAny ¶ added in v1.13.0
func (d InlineDirectives) HasAny() bool
HasAny returns true if any directive was set.
type KGAgentConfig ¶ added in v1.18.0
type KGAgentConfig struct {
AutoExtract string `yaml:"auto_extract"`
LLMBudgetPerCycle int `yaml:"llm_budget_per_cycle"`
LLMConsentACK bool `yaml:"llm_consent_acknowledged"`
FactsPerInjection int `yaml:"facts_per_injection"`
}
KGAgentConfig mirrors the relevant KGConfig fields for use in AgentConfig.
type KGConfig ¶ added in v1.18.0
type KGConfig struct {
// AutoExtract controls which extraction modes are active.
// Values: "off" (default), "pattern", "llm", "both".
// When "off", no automatic extraction runs during dream cycles.
AutoExtract string `yaml:"auto_extract" json:"auto_extract"`
// LLMBudgetPerCycle caps how many memories the LLM extractor processes
// per dream cycle. Default: 20. The budget is enforced by the dream
// cycle caller, not the extractor itself.
LLMBudgetPerCycle int `yaml:"llm_budget_per_cycle" json:"llm_budget_per_cycle"`
// LLMConsentACK must be true when AutoExtract contains "llm".
// This is a safety gate — the operator must explicitly acknowledge
// that memory contents will be sent to an external LLM API for
// triple extraction. When false and mode is "llm" or "both",
// NewLLMExtractor returns an error.
LLMConsentACK bool `yaml:"llm_consent_acknowledged" json:"llm_consent_acknowledged"`
// FactsPerInjection caps how many KG facts are injected into the prompt
// after compaction. Default: 5. Facts are ranked by confidence × recency.
FactsPerInjection int `yaml:"facts_per_injection" json:"facts_per_injection"`
}
KGConfig configures the knowledge graph extraction subsystem. It lives under HierarchyConfig.KG and controls LLM-based triple extraction during dream cycles. Off by default — the operator must explicitly opt in via AutoExtract and acknowledge consent.
type LCMAssembler ¶ added in v1.14.0
type LCMAssembler struct {
// contains filtered or unexported fields
}
LCMAssembler builds []chatMessage from the LCM store.
func NewLCMAssembler ¶ added in v1.14.0
func NewLCMAssembler(store *LCMStore, cfg LCMConfig, logger *slog.Logger) *LCMAssembler
NewLCMAssembler creates a new assembler.
func (*LCMAssembler) AssembleContext ¶ added in v1.14.0
func (a *LCMAssembler) AssembleContext(convID, systemPrompt, userMessage string, tokenBudget int) ([]chatMessage, error)
AssembleContext builds the message list for the LLM from DAG summaries + fresh tail.
type LCMCompactor ¶ added in v1.14.0
type LCMCompactor struct {
// contains filtered or unexported fields
}
LCMCompactor runs leaf and condensed compaction passes.
func NewLCMCompactor ¶ added in v1.14.0
func NewLCMCompactor(store *LCMStore, cfg LCMConfig, logger *slog.Logger) *LCMCompactor
NewLCMCompactor creates a new compactor.
func (*LCMCompactor) CondensedPass ¶ added in v1.14.0
func (c *LCMCompactor) CondensedPass(ctx context.Context, convID string, summarizeFn LCMSummarizeFn) ([]*LCMSummary, error)
CondensedPass groups orphan summaries at each depth into higher-level condensed nodes.
func (*LCMCompactor) FullSweep ¶ added in v1.14.0
func (c *LCMCompactor) FullSweep(ctx context.Context, convID string, summarizeFn LCMSummarizeFn) ([]*LCMSummary, error)
FullSweep runs leaf pass then cascading condensed passes until stable.
func (*LCMCompactor) LeafPass ¶ added in v1.14.0
func (c *LCMCompactor) LeafPass(ctx context.Context, convID string, summarizeFn LCMSummarizeFn) ([]*LCMSummary, error)
LeafPass groups unsummarized messages into chunks and summarizes each into depth-0 leaf summary nodes.
func (*LCMCompactor) ShouldCompact ¶ added in v1.14.0
func (c *LCMCompactor) ShouldCompact(convID string, contextWindowTokens int) (bool, string)
ShouldCompact checks whether compaction is needed based on unsummarized token count. Returns (shouldCompact, triggerReason). Skips compaction for sessions with no real conversation (heartbeat-only or system-only sessions).
type LCMConfig ¶ added in v1.14.0
type LCMConfig struct {
// FreshTailCount is how many recent messages to keep unsummarized. Default: 32.
FreshTailCount int `yaml:"fresh_tail_count"`
// LeafChunkMaxTokens is the max tokens per leaf chunk. Default: 20000.
LeafChunkMaxTokens int `yaml:"leaf_chunk_max_tokens"`
// CondensedMinChildren is the minimum orphan summaries to trigger condensation. Default: 4.
CondensedMinChildren int `yaml:"condensed_min_children"`
// CondensedMaxChildren is the max summaries per condensed batch. Default: 8.
CondensedMaxChildren int `yaml:"condensed_max_children"`
// SoftTriggerRatio is the context usage fraction for soft compaction trigger. Default: 0.6.
SoftTriggerRatio float64 `yaml:"soft_trigger_ratio"`
// HardTriggerRatio is the context usage fraction for hard compaction trigger. Default: 0.85.
HardTriggerRatio float64 `yaml:"hard_trigger_ratio"`
// MaxSummaryTokens is the max tokens per individual summary. Default: 2000.
MaxSummaryTokens int `yaml:"max_summary_tokens"`
// SummaryModel overrides the model used for LCM summarization calls.
// Priority: SummaryModel > CompactionConfig.CompactionModel > agent's current model.
// If empty, falls back to the next available model in the chain.
SummaryModel string `yaml:"summary_model"`
// SummaryProvider overrides the provider for LCM summarization calls.
// If empty, uses the provider from the session's LLM client.
SummaryProvider string `yaml:"summary_provider"`
// LargeFileTokenThreshold is the token count above which ingested content
// is intercepted and stored as a separate file with an exploration summary.
// Default: 25000. Set to 0 to disable.
LargeFileTokenThreshold int `yaml:"large_file_token_threshold"`
// PruneHeartbeatOK removes heartbeat turn cycles (user heartbeat prompt +
// assistant HEARTBEAT_OK response) from the LCM store during ingest.
// Default: true (nil pointer = true).
PruneHeartbeatOK *bool `yaml:"prune_heartbeat_ok"`
}
LCMConfig controls the Lossless Compaction Module behavior.
type LCMContextItem ¶ added in v1.14.0
type LCMContextItem struct {
ID int64
ConversationID string
Ordinal int
ItemType string // "message" | "summary"
MessageID *int64
SummaryID *string
}
LCMContextItem is an ordered entry in the model's visible context.
type LCMConversation ¶ added in v1.14.0
type LCMConversation struct {
ID string
SessionID string
CreatedAt time.Time
NextSeq int
LastCompactAt time.Time
}
LCMConversation is one LCM conversation tied to a session.
type LCMEngine ¶ added in v1.14.0
type LCMEngine struct {
// contains filtered or unexported fields
}
LCMEngine is the top-level coordinator for lossless compaction.
func NewLCMEngine ¶ added in v1.14.0
NewLCMEngine creates a new LCM engine wired to the given database.
func (*LCMEngine) Assemble ¶ added in v1.14.0
func (e *LCMEngine) Assemble(ctx context.Context, convID, systemPrompt, userMessage string, tokenBudget int) ([]chatMessage, error)
Assemble builds the model's context window from DAG summaries + fresh tail.
func (*LCMEngine) Bootstrap ¶ added in v1.14.0
func (e *LCMEngine) Bootstrap(sessionID string, sessionHistory []ConversationEntry) (string, error)
Bootstrap initializes an LCM conversation for the given session ID. If sessionHistory is provided, reconciles with the LCM store to import any messages that were missed (e.g. from a previous session that wasn't fully ingested). Returns the conversation ID.
func (*LCMEngine) Compact ¶ added in v1.14.0
func (e *LCMEngine) Compact(ctx context.Context, convID string, contextWindowTokens int, summarizeFn LCMSummarizeFn) (bool, error)
Compact evaluates whether compaction is needed and runs a full sweep if so. Returns true if compaction was performed.
func (*LCMEngine) Ingest ¶ added in v1.14.0
Ingest persists new messages from the agent loop into the LCM store. Messages are deduplicated by tracking the last ingested index externally.
func (*LCMEngine) Retrieval ¶ added in v1.14.0
func (e *LCMEngine) Retrieval() *LCMRetrieval
Retrieval returns the retrieval engine for tool use.
type LCMFTSResult ¶ added in v1.14.0
type LCMFTSResult struct {
EntityType string // "message" | "summary"
EntityID string
Content string
Rank float64
}
LCMFTSResult is a full-text search hit.
type LCMFile ¶ added in v1.16.0
type LCMFile struct {
ID string
ConversationID string
OriginalTokens int
OriginalChars int
Summary string
FilePath string
CreatedAt time.Time
}
LCMFile represents a large file intercepted during ingest.
type LCMMessage ¶ added in v1.14.0
type LCMMessage struct {
ID int64
ConversationID string
Seq int
Role string
Content string
TokenCount int
CreatedAt time.Time
}
LCMMessage is a single persisted message (verbatim).
type LCMQueryFn ¶ added in v1.16.0
LCMQueryFn is a function that sends a scoped query to the LLM and returns the synthesized answer. No tools are provided (prevents recursion).
type LCMRetrieval ¶ added in v1.14.0
type LCMRetrieval struct {
// contains filtered or unexported fields
}
LCMRetrieval provides search and inspection over the LCM DAG.
func NewLCMRetrieval ¶ added in v1.14.0
func NewLCMRetrieval(store *LCMStore, logger *slog.Logger) *LCMRetrieval
NewLCMRetrieval creates a new retrieval engine.
func (*LCMRetrieval) Describe ¶ added in v1.14.0
func (r *LCMRetrieval) Describe(convID, summaryID string) (string, error)
Describe returns metadata about a summary or the full DAG tree.
func (*LCMRetrieval) DescribeTree ¶ added in v1.14.0
func (r *LCMRetrieval) DescribeTree(convID string) (string, error)
DescribeTree returns an overview of the full LCM DAG.
func (*LCMRetrieval) Expand ¶ added in v1.14.0
func (r *LCMRetrieval) Expand(convID, summaryID string, depth int) (string, error)
Expand recovers the original messages behind a summary. depth=0 expands to messages (for leaf) or child summaries (for condensed). depth>0 recursively expands children.
func (*LCMRetrieval) ExpandQuery ¶ added in v1.16.0
func (r *LCMRetrieval) ExpandQuery(ctx context.Context, convID, query string, queryFn LCMQueryFn) (string, error)
ExpandQuery searches the LCM store for context relevant to the query, expands matching summaries, and sends the expanded context to an LLM for synthesis. Budget: 30k tokens max, 60s timeout.
type LCMStore ¶ added in v1.14.0
type LCMStore struct {
// contains filtered or unexported fields
}
LCMStore provides all LCM database operations.
func NewLCMStore ¶ added in v1.14.0
NewLCMStore creates a new LCM store.
func (*LCMStore) CountUnsummarizedTokens ¶ added in v1.14.0
CountUnsummarizedTokens returns the total token count of unsummarized messages, excluding the fresh tail.
func (*LCMStore) DeleteMessage ¶ added in v1.16.0
DeleteMessage removes a message from the store by ID.
func (*LCMStore) GetAllSummaries ¶ added in v1.14.0
func (s *LCMStore) GetAllSummaries(convID string) ([]*LCMSummary, error)
GetAllSummaries returns all summaries for a conversation.
func (*LCMStore) GetContextItems ¶ added in v1.14.0
func (s *LCMStore) GetContextItems(convID string) ([]LCMContextItem, error)
GetContextItems returns ordered context items for a conversation.
func (*LCMStore) GetFreshTailMessages ¶ added in v1.14.0
func (s *LCMStore) GetFreshTailMessages(convID string, count int) ([]*LCMMessage, error)
GetFreshTailMessages returns the last N messages by seq (reversed to chronological order).
func (*LCMStore) GetMaxDepth ¶ added in v1.14.0
GetMaxDepth returns the maximum summary depth for a conversation.
func (*LCMStore) GetMessage ¶ added in v1.14.0
func (s *LCMStore) GetMessage(id int64) (*LCMMessage, error)
GetMessage returns a single message by ID.
func (*LCMStore) GetMessageRange ¶ added in v1.14.0
func (s *LCMStore) GetMessageRange(convID string, fromSeq, toSeq int) ([]*LCMMessage, error)
GetMessageRange returns messages within a seq range (inclusive).
func (*LCMStore) GetOrCreateConversation ¶ added in v1.14.0
func (s *LCMStore) GetOrCreateConversation(sessionID string) (*LCMConversation, error)
GetOrCreateConversation returns the LCM conversation for a session, creating it if it doesn't exist (idempotent).
func (*LCMStore) GetOrphanSummaries ¶ added in v1.14.0
func (s *LCMStore) GetOrphanSummaries(convID string, depth int) ([]*LCMSummary, error)
GetOrphanSummaries returns summaries at a given depth that have no parent.
func (*LCMStore) GetRecentMessages ¶ added in v1.14.0
func (s *LCMStore) GetRecentMessages(convID string, limit int) ([]*LCMMessage, error)
GetRecentMessages returns the most recent N messages (by seq DESC, reversed to chronological). Use this instead of GetMessageRange for grep searches to prioritize recent messages.
func (*LCMStore) GetRootSummaries ¶ added in v1.14.0
func (s *LCMStore) GetRootSummaries(convID string) ([]*LCMSummary, error)
GetRootSummaries returns top-level summaries (no parent), ordered by time.
func (*LCMStore) GetSummary ¶ added in v1.14.0
func (s *LCMStore) GetSummary(id string) (*LCMSummary, error)
GetSummary returns a single summary by ID.
func (*LCMStore) GetSummaryChildren ¶ added in v1.14.0
func (s *LCMStore) GetSummaryChildren(summaryID string) ([]*LCMSummary, error)
GetSummaryChildren returns child summaries of a condensed node.
func (*LCMStore) GetSummaryMessages ¶ added in v1.14.0
func (s *LCMStore) GetSummaryMessages(summaryID string) ([]*LCMMessage, error)
GetSummaryMessages returns the source messages linked to a leaf summary.
func (*LCMStore) GetSummaryParents ¶ added in v1.14.0
func (s *LCMStore) GetSummaryParents(summaryID string) ([]*LCMSummary, error)
GetSummaryParents returns parent summaries that contain this node.
func (*LCMStore) GetUnsummarizedMessages ¶ added in v1.14.0
func (s *LCMStore) GetUnsummarizedMessages(convID string, excludeLastN int) ([]*LCMMessage, error)
GetUnsummarizedMessages returns messages not yet linked to any summary, excluding the most recent excludeLastN messages (the "fresh tail").
func (*LCMStore) IngestMessage ¶ added in v1.14.0
func (s *LCMStore) IngestMessage(convID, role, content string, tokenCount int) (*LCMMessage, error)
IngestMessage inserts a new message, indexes it in FTS, and adds a context item.
func (*LCMStore) InsertFile ¶ added in v1.16.0
InsertFile stores metadata for an intercepted large file.
func (*LCMStore) InsertSummary ¶ added in v1.14.0
func (s *LCMStore) InsertSummary(sum *LCMSummary) error
InsertSummary persists a summary node and indexes it in FTS.
func (*LCMStore) LinkSummaryChildren ¶ added in v1.14.0
LinkSummaryChildren links a condensed summary to its child summaries.
func (*LCMStore) LinkSummaryMessages ¶ added in v1.14.0
LinkSummaryMessages links a leaf summary to its source messages.
func (*LCMStore) MessageCount ¶ added in v1.14.0
MessageCount returns the total number of messages in a conversation.
func (*LCMStore) NextSeq ¶ added in v1.14.0
NextSeq atomically increments and returns the next sequence number.
func (*LCMStore) ReplaceContextItems ¶ added in v1.14.0
func (s *LCMStore) ReplaceContextItems(convID string, items []LCMContextItem) error
ReplaceContextItems atomically replaces all context items for a conversation.
func (*LCMStore) SearchFTS ¶ added in v1.14.0
func (s *LCMStore) SearchFTS(convID, query string, limit int) ([]LCMFTSResult, error)
SearchFTS performs a full-text search across messages and summaries. Returns nil results (not error) if FTS5 is unavailable.
func (*LCMStore) SummaryCount ¶ added in v1.14.0
SummaryCount returns summary counts by kind.
func (*LCMStore) UpdateLastCompactAt ¶ added in v1.14.0
UpdateLastCompactAt updates the last compaction timestamp.
type LCMSummarizeFn ¶ added in v1.14.0
LCMSummarizeFn is the function signature for LLM-based summarization. aggressive=true requests a shorter, more compressed output.
type LCMSummary ¶ added in v1.14.0
type LCMSummary struct {
ID string
ConversationID string
Kind string // "leaf" | "condensed"
Depth int
Content string
TokenCount int
SourceMessageTokenCount int
DescendantCount int
DescendantTokenCount int
EarliestAt time.Time
LatestAt time.Time
CreatedAt time.Time
}
LCMSummary is a DAG node — leaf (depth 0) or condensed (depth 1+).
type LLMClient ¶
type LLMClient struct {
// contains filtered or unexported fields
}
LLMClient handles communication with the LLM provider API.
func NewLLMClient ¶
NewLLMClient creates a new LLM client from config.
func (*LLMClient) Complete ¶
func (c *LLMClient) Complete(ctx context.Context, systemPrompt string, history []ConversationEntry, userMessage string) (string, error)
Complete sends a simple chat completion request (no tools) and returns the text. Convenience wrapper around CompleteWithTools for non-agentic use cases.
func (*LLMClient) CompleteWithFallback ¶
func (c *LLMClient) CompleteWithFallback(ctx context.Context, messages []chatMessage, tools []ToolDefinition) (*LLMResponse, error)
CompleteWithFallback tries the primary model, then fallback models, with retry and exponential backoff on retryable errors. Returns the first successful response.
func (*LLMClient) CompleteWithFallbackUsingModel ¶
func (c *LLMClient) CompleteWithFallbackUsingModel(ctx context.Context, modelOverride string, messages []chatMessage, tools []ToolDefinition) (*LLMResponse, error)
CompleteWithFallbackUsingModel is like CompleteWithFallback but uses modelOverride as the primary model when non-empty. Empty = use c.model. Includes auto-recovery: when the primary model hits a rate limit, subsequent calls use fallback models. Near cooldown expiry, a probe is sent to the primary model to check if it recovered. On success, cooldown is cleared.
func (*LLMClient) CompleteWithTools ¶
func (c *LLMClient) CompleteWithTools(ctx context.Context, messages []chatMessage, tools []ToolDefinition) (*LLMResponse, error)
CompleteWithTools sends a chat completion request with optional tool definitions. Delegates to CompleteWithFallback for retry and model fallback. Returns a structured response that may include tool calls the LLM wants to execute.
func (*LLMClient) CompleteWithToolsStream ¶
func (c *LLMClient) CompleteWithToolsStream(ctx context.Context, messages []chatMessage, tools []ToolDefinition, onChunk StreamCallback) (*LLMResponse, error)
CompleteWithToolsStream sends a streaming chat completion request. For each text delta, onChunk is called. Tool calls are accumulated silently. Falls back to non-streaming if the provider does not support streaming or returns an error.
func (*LLMClient) CompleteWithToolsStreamUsingModel ¶
func (c *LLMClient) CompleteWithToolsStreamUsingModel(ctx context.Context, modelOverride string, messages []chatMessage, tools []ToolDefinition, onChunk StreamCallback) (*LLMResponse, error)
CompleteWithToolsStreamUsingModel is like CompleteWithToolsStream but uses modelOverride when non-empty. Empty = use c.model. Includes retry for transient HTTP errors before falling back to non-streaming.
func (*LLMClient) CompleteWithToolsUsingModel ¶
func (c *LLMClient) CompleteWithToolsUsingModel(ctx context.Context, modelOverride string, messages []chatMessage, tools []ToolDefinition) (*LLMResponse, error)
CompleteWithToolsUsingModel is like CompleteWithTools but uses modelOverride as the primary model when non-empty. Empty string means use the default config model.
func (*LLMClient) CompleteWithVision ¶
func (c *LLMClient) CompleteWithVision(ctx context.Context, systemPrompt, imageBase64, mimeType, userPrompt, detail string, visionModel ...string) (string, error)
CompleteWithVision sends an image plus optional text to the LLM vision API and returns the model's description or response. imageBase64 is the raw base64-encoded image bytes (without data URL prefix). mimeType is e.g. "image/jpeg", "image/png". detail is "auto", "low", or "high" (empty defaults to "auto"). CompleteWithVision sends an image plus optional text to a vision-capable model. visionModel overrides the model; if empty, uses the main chat model.
func (*LLMClient) IsOAuthProvider ¶ added in v1.12.0
IsOAuthProvider returns true if this client is configured for OAuth.
func (*LLMClient) OAuthBaseProvider ¶ added in v1.12.0
OAuthBaseProvider returns the base provider name for OAuth providers.
func (*LLMClient) SetFailoverCoordinator ¶ added in v1.13.0
func (c *LLMClient) SetFailoverCoordinator(fc *FailoverCoordinator)
SetFailoverCoordinator injects the unified failover coordinator for model+profile rotation. When set, CompleteWithFallback uses the coordinator instead of inline cooldown tracking.
func (*LLMClient) SetOAuthTokenManager ¶ added in v1.12.0
func (c *LLMClient) SetOAuthTokenManager(tm OAuthTokenManager)
SetOAuthTokenManager sets the OAuth token manager for this client.
func (*LLMClient) TranscribeAudio ¶
func (c *LLMClient) TranscribeAudio(ctx context.Context, audioData []byte, filename, model string, media ...MediaConfig) (string, error)
TranscribeAudio sends audio data to a Whisper-compatible API and returns the transcript. filename is used as the form field name (e.g. "audio.ogg", "voice.mp3"). model defaults to "whisper-1" if empty. media is optional; if provided, it may override the transcription endpoint and API key for providers that don't natively support Whisper (e.g. Z.AI/GLM, Anthropic).
type LLMErrorKind ¶
type LLMErrorKind int
LLMErrorKind classifies API errors for retry/fallback decisions. Granular classification enables smarter retry behavior.
const ( LLMErrorRetryable LLMErrorKind = iota // generic retryable (transient 5xx) LLMErrorRateLimit // 429 — rate limited, should respect Retry-After LLMErrorOverloaded // 529 or "overloaded" in body LLMErrorTimeout // request timeout / deadline exceeded LLMErrorAuth // 401, 403 — invalid/expired API key LLMErrorBilling // 402 or billing-related in body LLMErrorContext // context_length_exceeded LLMErrorThinking // unsupported extended thinking level LLMErrorBadRequest // 400 — malformed request LLMErrorFatal // everything else )
func (LLMErrorKind) IsRetryableKind ¶
func (k LLMErrorKind) IsRetryableKind() bool
IsRetryableKind returns true if the error kind warrants retrying.
func (LLMErrorKind) String ¶
func (k LLMErrorKind) String() string
String returns a human-readable label for the error kind.
type LLMResponse ¶
type LLMResponse struct {
Content string
ToolCalls []ToolCall
FinishReason string
Usage LLMUsage
ModelUsed string // The model that actually produced the response
}
LLMResponse holds the parsed response from a chat completion.
type LLMUsage ¶
type LLMUsage struct {
PromptTokens int
CompletionTokens int
TotalTokens int
CacheReadTokens int // Tokens read from provider cache (Anthropic: cache_read_input_tokens)
CacheWriteTokens int // Tokens written to provider cache (Anthropic: cache_creation_input_tokens)
}
LLMUsage holds token usage information from the API response.
type Lane ¶
Lane manages a queue with bounded concurrency.
func (*Lane) ActiveCount ¶
ActiveCount returns the number of currently running tasks.
func (*Lane) Close ¶
func (l *Lane) Close()
Close prevents new tasks from being enqueued. Active tasks finish normally.
type LaneConfig ¶
type LaneConfig struct {
SessionMax int `yaml:"session_max"` // Default: 1 (one agent run per session)
GlobalMax int `yaml:"global_max"` // Default: 3
CronMax int `yaml:"cron_max"` // Default: 2
SubagentMax int `yaml:"subagent_max"` // Default: 8
}
LaneConfig configures default concurrency limits per lane type.
func DefaultLaneConfig ¶
func DefaultLaneConfig() LaneConfig
DefaultLaneConfig returns sensible defaults.
type LaneManager ¶
type LaneManager struct {
// contains filtered or unexported fields
}
LaneManager manages multiple lanes, creating them on demand.
func NewLaneManager ¶
func NewLaneManager(config LaneConfig, logger *slog.Logger) *LaneManager
NewLaneManager creates a lane manager with the given configuration.
func (*LaneManager) CronLane ¶
func (lm *LaneManager) CronLane() *Lane
CronLane returns the lane for scheduled jobs.
func (*LaneManager) GetLane ¶
func (lm *LaneManager) GetLane(name string) *Lane
GetLane returns an existing lane or creates a new one with the appropriate concurrency limit based on the lane name prefix.
func (*LaneManager) GlobalLane ¶
func (lm *LaneManager) GlobalLane() *Lane
GlobalLane returns the shared global lane.
func (*LaneManager) SessionLane ¶
func (lm *LaneManager) SessionLane(sessionID string) *Lane
SessionLane returns the lane for a specific session.
func (*LaneManager) SubagentLane ¶
func (lm *LaneManager) SubagentLane() *Lane
SubagentLane returns the lane for subagent runs.
type LaneTask ¶
type LaneTask struct {
ID string
Fn func(ctx context.Context) error
Priority int // Lower = higher priority (0 is highest)
}
LaneTask represents a unit of work to be executed in a lane.
type LegacyContextEngine ¶ added in v1.13.0
type LegacyContextEngine struct{}
LegacyContextEngine is a no-op engine that serves as a reference implementation. The existing PromptComposer already builds project context, memory, and skills layers directly. Register custom ContextEngine implementations to inject additional context from external sources (RAG pipelines, code indices, knowledge graphs, etc.).
func NewLegacyContextEngine ¶ added in v1.13.0
func NewLegacyContextEngine(_ *PromptComposer) *LegacyContextEngine
NewLegacyContextEngine creates the default no-op context engine.
func (*LegacyContextEngine) Gather ¶ added in v1.13.0
Gather is a no-op — all legacy context is already built by PromptComposer.
func (*LegacyContextEngine) Name ¶ added in v1.13.0
func (e *LegacyContextEngine) Name() string
Name returns the engine identifier.
type LinkConfig ¶ added in v1.13.0
type LinkConfig struct {
Enabled bool `yaml:"enabled" json:"enabled"`
MaxLinks int `yaml:"max_links" json:"max_links"`
TimeoutSeconds int `yaml:"timeout_seconds" json:"timeout_seconds"`
MaxCharsPerURL int `yaml:"max_chars_per_url" json:"max_chars_per_url"`
}
LinkConfig configures the link understanding pipeline.
func DefaultLinkConfig ¶ added in v1.13.0
func DefaultLinkConfig() LinkConfig
DefaultLinkConfig returns sensible defaults.
type LinkResult ¶ added in v1.13.0
LinkResult holds the extracted content from a URL.
func RunLinkUnderstanding ¶ added in v1.13.0
func RunLinkUnderstanding(ctx context.Context, urls []string, cfg LinkConfig, ssrfGuard *security.SSRFGuard, logger *slog.Logger) []LinkResult
RunLinkUnderstanding fetches and extracts readable content from the given URLs. Uses SSRFGuard when available to validate URLs. Reuses web_fetch_readability.go for HTML-to-text conversion.
type LoggingConfig ¶
type LoggingConfig struct {
// Level is the log level ("debug", "info", "warn", "error").
Level string `yaml:"level"`
// Format is the log format ("json", "text").
Format string `yaml:"format"`
}
LoggingConfig configures logging.
type LoopDetectionResult ¶
type LoopDetectionResult struct {
Severity LoopSeverity
Message string // Injected into the conversation as a system hint
Streak int // Number of consecutive repeats detected
Pattern string // "repeat", "ping-pong", "known_poll", "global_breaker", or ""
}
LoopDetectionResult is the outcome of a loop check.
type LoopSeverity ¶
type LoopSeverity int
LoopSeverity represents the level of loop detection.
const ( LoopNone LoopSeverity = iota LoopWarning // Agent should be nudged LoopCritical // Agent should be strongly nudged LoopBreaker // Agent run should be terminated )
type MCPConfig ¶
type MCPConfig struct {
// Enabled turns MCP support on/off.
Enabled bool `yaml:"enabled" json:"enabled"`
// Servers is the list of configured MCP servers.
Servers []ManagedMCPServerConfig `yaml:"servers" json:"servers"`
}
MCPConfig holds all MCP configuration.
func DefaultMCPConfig ¶
func DefaultMCPConfig() MCPConfig
DefaultMCPConfig returns sensible defaults.
type MCPManager ¶
type MCPManager struct {
// contains filtered or unexported fields
}
MCPManager manages MCP server lifecycle and configuration.
func NewMCPManager ¶
NewMCPManager creates a new MCP manager.
func (*MCPManager) AddServer ¶
func (m *MCPManager) AddServer(cfg ManagedMCPServerConfig) error
AddServer adds a new MCP server configuration.
func (*MCPManager) GetConfig ¶
func (m *MCPManager) GetConfig() MCPConfig
GetConfig returns the current MCP configuration.
func (*MCPManager) GetServer ¶
func (m *MCPManager) GetServer(name string) *MCPServerInfo
GetServer returns a specific MCP server by name.
func (*MCPManager) ListServers ¶
func (m *MCPManager) ListServers() []MCPServerInfo
ListServers returns all configured MCP servers with their status.
func (*MCPManager) LoadFromDB ¶
func (m *MCPManager) LoadFromDB() error
LoadFromDB loads the MCP configuration from the database.
func (*MCPManager) RefreshStatus ¶
func (m *MCPManager) RefreshStatus(ctx context.Context)
RefreshStatus refreshes the status of all MCP servers.
func (*MCPManager) Reload ¶
func (m *MCPManager) Reload(cfg MCPConfig)
Reload reloads the MCP configuration.
func (*MCPManager) RemoveServer ¶
func (m *MCPManager) RemoveServer(name string) error
RemoveServer removes an MCP server configuration.
func (*MCPManager) SetEnabled ¶
func (m *MCPManager) SetEnabled(name string, enabled bool) error
SetEnabled enables or disables an MCP server.
func (*MCPManager) TestServer ¶
func (m *MCPManager) TestServer(ctx context.Context, name string) (*MCPServerStatus, error)
TestServer tests the connection to an MCP server.
func (*MCPManager) UpdateServer ¶
func (m *MCPManager) UpdateServer(name string, cfg ManagedMCPServerConfig) error
UpdateServer updates an existing MCP server configuration.
type MCPServerConfig ¶
type MCPServerConfig struct {
Name string `yaml:"name"`
Transport string `yaml:"transport"` // "stdio", "sse", "streamable-http"
Command string `yaml:"command,omitempty"`
Args []string `yaml:"args,omitempty"`
URL string `yaml:"url,omitempty"`
Env map[string]string `yaml:"env,omitempty"`
}
MCPServerConfig holds configuration for an MCP server associated with a project.
type MCPServerInfo ¶
type MCPServerInfo struct {
Config ManagedMCPServerConfig `json:"config"`
Status MCPServerStatus `json:"status"`
}
MCPServerInfo combines config and status for an MCP server.
type MCPServerStatus ¶
type MCPServerStatus struct {
Name string `json:"name"`
Connected bool `json:"connected"`
LastChecked time.Time `json:"last_checked"`
Error string `json:"error,omitempty"`
Tools []string `json:"tools,omitempty"`
}
MCPServerStatus represents the status of an MCP server.
type MCPToolsBridge ¶ added in v1.13.0
type MCPToolsBridge struct {
// contains filtered or unexported fields
}
MCPToolsBridge connects MCP servers to the ToolExecutor.
func NewMCPToolsBridge ¶ added in v1.13.0
func NewMCPToolsBridge(executor *ToolExecutor, logger *slog.Logger) *MCPToolsBridge
NewMCPToolsBridge creates a bridge that will register MCP tools.
func (*MCPToolsBridge) ConnectAll ¶ added in v1.13.0
func (b *MCPToolsBridge) ConnectAll(ctx context.Context, servers []ManagedMCPServerConfig)
ConnectAll launches all enabled auto-start MCP servers, discovers their tools, and registers them in the ToolExecutor.
func (*MCPToolsBridge) Shutdown ¶ added in v1.13.0
func (b *MCPToolsBridge) Shutdown()
Shutdown gracefully closes all MCP server connections.
type MMRConfig ¶ added in v1.12.0
type MMRConfig struct {
// Enabled activates MMR re-ranking (default: false).
Enabled bool `yaml:"enabled"`
// Lambda balances relevance vs diversity (default: 0.7).
// 0 = max diversity, 1 = max relevance.
Lambda float64 `yaml:"lambda"`
}
MMRConfig configures Maximal Marginal Relevance for search diversification.
type MaintenanceManager ¶
type MaintenanceManager struct {
// contains filtered or unexported fields
}
MaintenanceManager manages maintenance mode state with database persistence.
func NewMaintenanceManager ¶
func NewMaintenanceManager(db *sql.DB, logger *slog.Logger) *MaintenanceManager
NewMaintenanceManager creates a new maintenance manager.
func (*MaintenanceManager) Get ¶
func (m *MaintenanceManager) Get() *MaintenanceMode
Get returns the current maintenance mode state.
func (*MaintenanceManager) IsEnabled ¶
func (m *MaintenanceManager) IsEnabled() bool
IsEnabled returns true if maintenance mode is active.
func (*MaintenanceManager) Load ¶
func (m *MaintenanceManager) Load() error
Load restores maintenance mode from database on startup.
type MaintenanceMode ¶
type MaintenanceMode struct {
Enabled bool `json:"enabled"`
Message string `json:"message"`
SetBy string `json:"set_by"`
SetAt time.Time `json:"set_at"`
}
MaintenanceMode represents the system maintenance state.
type ManagedMCPServerConfig ¶
type ManagedMCPServerConfig struct {
// Name is the unique identifier for this MCP server.
Name string `yaml:"name" json:"name"`
// Type is the connection type (stdio, sse, http, websocket).
Type MCPType `yaml:"type" json:"type"`
// Command is the executable for stdio type.
Command string `yaml:"command" json:"command,omitempty"`
// Args are command-line arguments for stdio type.
Args []string `yaml:"args" json:"args,omitempty"`
// URL is the endpoint for SSE/HTTP/WebSocket types.
URL string `yaml:"url" json:"url,omitempty"`
// Headers are custom HTTP headers for SSE/HTTP/WebSocket types.
Headers map[string]string `yaml:"headers" json:"headers,omitempty"`
// Env are environment variables for stdio type.
Env map[string]string `yaml:"env" json:"env,omitempty"`
// Enabled controls whether this MCP server is active.
Enabled bool `yaml:"enabled" json:"enabled"`
// AutoStart controls whether to start on launch.
AutoStart bool `yaml:"auto_start" json:"auto_start"`
// Timeout is the connection timeout in seconds.
Timeout int `yaml:"timeout" json:"timeout"`
// Description is a human-readable description.
Description string `yaml:"description" json:"description,omitempty"`
}
ManagedMCPServerConfig configures a managed MCP server.
type MediaCapability ¶ added in v1.13.0
type MediaCapability string
MediaCapability represents a type of media processing.
const ( CapabilityVision MediaCapability = "vision" CapabilityTranscription MediaCapability = "transcription" )
type MediaConfig ¶
type MediaConfig struct {
// VisionEnabled enables image understanding via LLM vision (default: true).
VisionEnabled bool `yaml:"vision_enabled"`
// VisionModel overrides the model used for image/video understanding.
// If empty, uses the main chat model. Examples: "glm-4.6v", "gpt-4o", "claude-sonnet-4-20250514".
VisionModel string `yaml:"vision_model"`
// VisionDetail controls quality: "auto", "low", "high" (default: "auto").
VisionDetail string `yaml:"vision_detail"`
// TranscriptionEnabled enables audio transcription (default: true).
TranscriptionEnabled bool `yaml:"transcription_enabled"`
// TranscriptionModel is the model for audio transcription (default: "whisper-1").
// Examples: "whisper-1", "glm-asr-2512", "gpt-4o-transcribe", "whisper-large-v3".
TranscriptionModel string `yaml:"transcription_model"`
// TranscriptionBaseURL is the base URL for the transcription API.
// Examples:
// Z.AI: "https://api.z.ai/api/paas/v4"
// Groq: "https://api.groq.com/openai/v1"
// OpenAI: "https://api.openai.com/v1" (default)
TranscriptionBaseURL string `yaml:"transcription_base_url"`
// TranscriptionAPIKey is the API key for the transcription provider.
// If empty, falls back to the main API key.
TranscriptionAPIKey string `yaml:"transcription_api_key"`
// TranscriptionLanguage hints the expected language (ISO 639-1, e.g. "pt", "en", "es").
// For Whisper: passed as the "language" field.
// For Z.AI GLM-ASR: used as a prompt hint for auto-detection.
TranscriptionLanguage string `yaml:"transcription_language"`
// MaxImageSize is the max image size in bytes to process (default: 20MB).
MaxImageSize int64 `yaml:"max_image_size"`
// MaxAudioSize is the max audio size in bytes (default: 25MB).
MaxAudioSize int64 `yaml:"max_audio_size"`
// VisionProviders configures multiple vision providers with priority-based fallback.
// When set, describe_image will try these providers in priority order instead of the main LLM.
VisionProviders []MediaProviderConfig `yaml:"vision_providers"`
// TranscriptionProviders configures multiple transcription providers with priority-based fallback.
// When set, transcribe_audio will try these providers in priority order.
TranscriptionProviders []MediaProviderConfig `yaml:"transcription_providers"`
// ConcurrencyLimit limits simultaneous media API calls across all providers (default: 3).
ConcurrencyLimit int `yaml:"concurrency_limit"`
}
MediaConfig configures vision and audio transcription capabilities.
func DefaultMediaConfig ¶
func DefaultMediaConfig() MediaConfig
DefaultMediaConfig returns sensible defaults for media processing.
func (MediaConfig) Effective ¶
func (m MediaConfig) Effective() MediaConfig
Effective returns a copy with default values filled in for zero fields.
func (*MediaConfig) ResolveForProvider ¶
func (m *MediaConfig) ResolveForProvider(provider, baseURL string)
ResolveForProvider fills in transcription defaults based on the main API provider so users don't have to configure transcription separately when their provider already supports it.
type MediaEmitter ¶ added in v1.15.0
type MediaEmitter func(MediaEvent)
MediaEmitter is a callback that pushes media events to the client.
func MediaEmitterFromContext ¶ added in v1.15.0
func MediaEmitterFromContext(ctx context.Context) MediaEmitter
MediaEmitterFromContext extracts the media emitter from a context. Returns nil if not set.
type MediaEvent ¶ added in v1.15.0
type MediaEvent struct {
ID string `json:"id"`
URL string `json:"url"`
Type string `json:"type"` // image, audio, video, document
MimeType string `json:"mime_type"`
Filename string `json:"filename"`
Size int64 `json:"size"`
Caption string `json:"caption,omitempty"`
}
MediaEvent represents a media attachment emitted during an agent run. Used to push media to the Web UI via SSE or other non-channel delivery paths.
type MediaProviderConfig ¶ added in v1.13.0
type MediaProviderConfig struct {
// Provider is the provider name (e.g. "openai", "anthropic", "gemini").
Provider string `yaml:"provider"`
// BaseURL is the API base URL.
BaseURL string `yaml:"base_url"`
// APIKey is the API key for this provider.
APIKey string `yaml:"api_key"`
// Model is the model to use (e.g. "gpt-4o", "claude-sonnet-4-20250514").
Model string `yaml:"model"`
// Priority determines the order (lower = tried first). Default: 0.
Priority int `yaml:"priority"`
}
MediaProviderConfig configures a single media provider.
type MediaRegistry ¶ added in v1.13.0
type MediaRegistry struct {
// contains filtered or unexported fields
}
MediaRegistry holds multiple providers per capability and tries them in priority order with fallback on failure.
func GetGlobalMediaRegistry ¶ added in v1.13.0
func GetGlobalMediaRegistry() *MediaRegistry
GetGlobalMediaRegistry returns the global media registry, if set.
func NewMediaRegistry ¶ added in v1.13.0
func NewMediaRegistry(visionProviders, transcriptionProviders []MediaProviderConfig, concurrencyLimit int, logger *slog.Logger) *MediaRegistry
NewMediaRegistry creates a registry from provider configs. concurrencyLimit limits simultaneous media API calls (0 = default 3).
func (*MediaRegistry) DescribeImageWithFallback ¶ added in v1.13.0
func (r *MediaRegistry) DescribeImageWithFallback(ctx context.Context, systemPrompt, imageBase64, mimeType, userPrompt, detail string) (string, error)
DescribeImageWithFallback tries vision providers in priority order until one succeeds.
func (*MediaRegistry) HasTranscriptionProviders ¶ added in v1.13.0
func (r *MediaRegistry) HasTranscriptionProviders() bool
HasTranscriptionProviders returns true if transcription providers are configured.
func (*MediaRegistry) HasVisionProviders ¶ added in v1.13.0
func (r *MediaRegistry) HasVisionProviders() bool
HasVisionProviders returns true if vision providers are configured.
func (*MediaRegistry) TranscribeAudioWithFallback ¶ added in v1.13.0
func (r *MediaRegistry) TranscribeAudioWithFallback(ctx context.Context, audioData []byte, filename, model string, mediaCfg MediaConfig) (string, error)
TranscribeAudioWithFallback tries transcription providers in priority order until one succeeds.
type MemoryChunk ¶ added in v1.8.0
MemoryChunk represents a chunk of memory content for indexing.
type MemoryConfig ¶
type MemoryConfig struct {
// Type is the storage type ("sqlite", "file").
// "sqlite" enables FTS5 + vector search; "file" is the legacy fallback.
Type string `yaml:"type"`
// Path is the database file path (for sqlite).
Path string `yaml:"path"`
// MaxMessages is the max messages kept per session.
MaxMessages int `yaml:"max_messages"`
// CompressionStrategy defines memory compression
// ("summarize", "truncate", "semantic").
CompressionStrategy string `yaml:"compression_strategy"`
// Embedding configures the embedding provider for semantic search.
Embedding memory.EmbeddingConfig `yaml:"embedding"`
// Search configures hybrid search behavior.
Search SearchConfig `yaml:"search"`
// Index configures automatic indexing.
Index IndexConfig `yaml:"index"`
// SessionMemory configures automatic session summarization.
SessionMemory SessionMemoryConfig `yaml:"session_memory"`
// Hierarchy configures the palace-aware memory subsystem (Sprint 1,
// v1.18.0). Defaults to Enabled=true: wing IS NULL is treated as a
// first-class neutral citizen, so existing v1.17.0 databases keep
// working byte-identically while new memories get routed through
// wings/rooms. See HierarchyConfig in memory_hierarchy_config.go.
Hierarchy HierarchyConfig `yaml:"hierarchy"`
// Dream configures the background memory consolidation system (v1.17.0,
// now wired in v1.18.0). Defaults to Enabled=true so out-of-the-box
// installs get idle-cycle consolidation as the release notes promised.
// Existing YAML without a dream: block inherits defaults (retrocompat).
Dream DreamConfig `yaml:"dream"`
// Stack configures the Sprint 2 layered memory stack (v1.19.0+).
// Default: MemoryStackConfig{} (stack enabled when hierarchy is on).
// Set force_legacy: true to bypass the stack entirely and fall back
// to v1.18.0 prompt composition. See docs/memory-system.md for details.
Stack MemoryStackConfig `yaml:"stack"`
}
MemoryConfig configures the memory and persistence system.
type MemoryDispatcherConfig ¶ added in v1.12.0
type MemoryDispatcherConfig struct {
Store *memory.FileStore
SQLiteStore *memory.SQLiteStore
Config MemoryConfig
ContextRouter *ContextRouter // optional; nil disables wing routing
}
MemoryDispatcherConfig holds configuration for memory tools.
type MemoryExtractor ¶ added in v1.17.0
type MemoryExtractor struct {
// contains filtered or unexported fields
}
MemoryExtractor analyzes conversation history and extracts structured memories before compaction.
func NewMemoryExtractor ¶ added in v1.17.0
func NewMemoryExtractor(llm *LLMClient, logger *slog.Logger) *MemoryExtractor
NewMemoryExtractor creates a new extractor.
func (*MemoryExtractor) Extract ¶ added in v1.17.0
func (e *MemoryExtractor) Extract(ctx context.Context, messages []chatMessage, modelOverride string) []ExtractedMemory
Extract analyzes messages and returns structured memories. Uses a focused LLM call with a structured extraction prompt. Returns nil (no error) if extraction fails — this is best-effort.
type MemoryFlushConfig ¶ added in v1.12.0
type MemoryFlushConfig struct {
// Enabled activates memory flush before compaction (default: true).
Enabled bool `yaml:"enabled"`
// ProactiveEnabled activates proactive flush before each run (default: true).
// Uses token projection to decide whether flush is needed.
ProactiveEnabled bool `yaml:"proactive_enabled"`
// ProjectionThreshold is the fraction of context window that triggers proactive flush (default: 0.85).
ProjectionThreshold float64 `yaml:"projection_threshold"`
// ReserveTokensFloor is the minimum token buffer to maintain (default: 20000).
ReserveTokensFloor int `yaml:"reserve_tokens_floor"`
// FlushThreshold is the number of tokens before triggering flush (default: 4000).
// Flush triggers when: tokenEstimate >= contextWindow - reserveFloor - flushThreshold
FlushThreshold int `yaml:"flush_threshold"`
// SystemPrompt is an optional custom system prompt for the flush turn.
SystemPrompt string `yaml:"system_prompt"`
// Prompt is the user prompt for the flush turn (default: standard prompt).
Prompt string `yaml:"prompt"`
}
MemoryFlushConfig configures pre-compaction memory flush behavior. This triggers a silent turn before compaction to save important memories.
type MemoryHierarchyDispatcherConfig ¶ added in v1.18.0
type MemoryHierarchyDispatcherConfig struct {
// SQLiteStore is the memory store that exposes the palace operations
// (UpsertWing, ListRooms, GetChannelWing, ...). Must not be nil when
// Enabled is true; if nil, the tools return errors uniformly.
SQLiteStore *memory.SQLiteStore
// Router resolves (channel, chatID) to wings. May be nil if the caller
// only wants the read-side tools. When nil, pin/unpin tools return
// a "router unavailable" error.
Router *ContextRouter
// Enabled gates every tool behavior. When false, tools are still
// registered but return a feature-disabled error on invocation.
Enabled bool
// Logger is used for structured logging of tool calls. Defaults to
// slog.Default() if nil.
Logger *slog.Logger
}
MemoryHierarchyDispatcherConfig holds configuration for the palace-aware memory tools. Callers construct one with a reference to the SQLite store and a feature flag; the registrar wires it into the ToolExecutor.
type MemoryIndexer ¶ added in v1.8.0
type MemoryIndexer struct {
// contains filtered or unexported fields
}
MemoryIndexer performs incremental indexing of memory files in the background. Uses fsnotify for event-driven re-indexing with the ticker as fallback.
func NewMemoryIndexer ¶ added in v1.8.0
func NewMemoryIndexer(cfg MemoryIndexerConfig, logger *slog.Logger) *MemoryIndexer
NewMemoryIndexer creates a new memory indexer.
func (*MemoryIndexer) ForceReindex ¶ added in v1.8.0
func (m *MemoryIndexer) ForceReindex()
ForceReindex clears all stored hashes and triggers a full reindex.
func (*MemoryIndexer) IndexNow ¶ added in v1.8.0
func (m *MemoryIndexer) IndexNow()
IndexNow triggers an immediate index (useful for manual triggers).
func (*MemoryIndexer) MemoryDir ¶ added in v1.17.0
func (m *MemoryIndexer) MemoryDir() string
MemoryDir returns the configured memory directory path.
func (*MemoryIndexer) SetDeleteFileFunc ¶ added in v1.8.0
func (m *MemoryIndexer) SetDeleteFileFunc(fn func(filepath string) error)
SetDeleteFileFunc sets the function for deleting file from index.
func (*MemoryIndexer) SetIndexChunkFunc ¶ added in v1.8.0
func (m *MemoryIndexer) SetIndexChunkFunc(fn func(chunks []MemoryChunk) error)
SetIndexChunkFunc sets the function for indexing chunks.
func (*MemoryIndexer) SetMemoryDir ¶ added in v1.8.0
func (m *MemoryIndexer) SetMemoryDir(dir string)
SetMemoryDir sets the memory directory to index.
func (*MemoryIndexer) SetSQLiteStore ¶ added in v1.8.0
func (m *MemoryIndexer) SetSQLiteStore(store SQLiteMemoryStore)
SetSQLiteStore sets the SQLite memory store for indexing.
func (*MemoryIndexer) Start ¶ added in v1.8.0
func (m *MemoryIndexer) Start(ctx context.Context) error
Start begins periodic memory indexing.
func (*MemoryIndexer) Stats ¶ added in v1.8.0
func (m *MemoryIndexer) Stats() (indexedTotal, indexedLast, deletedTotal int64, lastIndexTime time.Time)
Stats returns current indexer statistics.
func (*MemoryIndexer) Stop ¶ added in v1.8.0
func (m *MemoryIndexer) Stop()
Stop stops the memory indexer and its filesystem watcher.
type MemoryIndexerConfig ¶ added in v1.8.0
type MemoryIndexerConfig struct {
Enabled bool `yaml:"enabled" json:"enabled"`
Interval time.Duration `yaml:"interval" json:"interval"`
MemoryDir string `yaml:"memory_dir" json:"memory_dir"`
}
MemoryIndexerConfig configures the memory indexer.
func DefaultMemoryIndexerConfig ¶ added in v1.8.0
func DefaultMemoryIndexerConfig() MemoryIndexerConfig
DefaultMemoryIndexerConfig returns default configuration.
type MemoryPromptSectionBuilder ¶ added in v1.16.0
type MemoryPromptSectionBuilder interface {
// BuildMemorySection returns a prompt section string (may be empty).
// Implementations should be fast (<100ms) to avoid blocking prompt composition.
BuildMemorySection(session *Session, input string) string
}
MemoryPromptSectionBuilder is implemented by memory plugins that want to contribute additional sections to the memory layer of the system prompt. Each registered builder is called during buildMemoryLayer and its output is concatenated after the core memory sections.
type MemoryStack ¶ added in v1.18.0
type MemoryStack struct {
// contains filtered or unexported fields
}
MemoryStack composes the Sprint 2 layered memory system:
L0 — IdentityLayer (anchored, never trimmed) L1 — EssentialLayer (per-wing story from template cache) L2 — OnDemandLayer (per-turn entity detection + retrieval) L3 — the legacy buildMemoryLayer fallback (handled by the caller)
The stack renders L0, L1, L2 into a single prefix string that prompt_layers.go's buildMemoryLayer prepends to the L3 output. When all three Sprint 2 layers return empty (or the stack is nil or ForceLegacy is on), the stack returns an empty string and buildMemoryLayer produces byte-identical output to v1.18.0. This is the retrocompat gate enforced by the golden fixture test.
Thread safety: all methods are safe for concurrent use. Telemetry counters use sync/atomic.
func NewMemoryStack ¶ added in v1.18.0
func NewMemoryStack( identity *memory.IdentityLayer, essential *memory.EssentialLayer, onDemand *memory.OnDemandLayer, cfg StackConfig, logger *slog.Logger, ) *MemoryStack
NewMemoryStack constructs a stack. Any layer argument may be nil — nil layers are internally replaced with a no-op adapter that always returns the empty string. If all three concrete layers are nil, the stack's Build() method short-circuits to "" and the caller degrades to the legacy L3 path.
If logger is nil, slog.Default() is used. The cfg is normalized via withDefaults() so callers can pass a zero StackConfig for defaults.
func (*MemoryStack) Build ¶ added in v1.18.0
func (s *MemoryStack) Build(ctx context.Context, activeWing, turn string) string
Build renders the L0+L1+L2 prefix for the current turn. Returns the empty string when:
- the stack is nil;
- cfg.ForceLegacy is true;
- the context is already cancelled;
- all three layers render empty strings.
On panic in any layer, the layer is skipped, an error is logged, and the remaining layers still execute. panicTotal is incremented. The prompt is always produced unless ctx is cancelled.
activeWing is the session's current wing ("" = legacy / no wing). turn is the current user message text (passed to L2 for entity detection).
The byte-budget algorithm is documented at the top of this file and enforced in place:
- L0 is always rendered in full. If L0 alone exceeds the budget, it is still included and a WARN is logged.
- L1 is truncated first when L0 + L1 would exceed the budget.
- L2 is trimmed first when the combined stack exceeds the budget (i.e. L2 is the lowest priority: trim L2 to zero before trimming L1).
func (*MemoryStack) Stats ¶ added in v1.18.0
func (s *MemoryStack) Stats() StackStats
Stats returns a point-in-time snapshot of the stack's telemetry counters. Safe to call concurrently with Build.
type MemoryStackConfig ¶ added in v1.18.0
type MemoryStackConfig struct {
// ForceLegacy disables the MemoryStack and falls back to the
// pre-Sprint-2 buildMemoryLayer code path. Default: false.
// Use this as an emergency escape hatch if the layered stack causes
// unexpected behavior in production — no config migration or downgrade
// is required. Set memory.stack.force_legacy: true in devclaw.yaml.
ForceLegacy bool `yaml:"force_legacy,omitempty"`
}
MemoryStackConfig configures the Sprint 2 layered memory stack (MemoryStack — see memory_stack.go). The only knob exposed today is force_legacy, which bypasses the stack entirely and falls back to the v1.18.0 prompt composer behavior. Users who want the new layered memory simply leave the block empty or omit it entirely.
type MemoryStats ¶
type MemoryStats struct {
AllocMB float64 `json:"alloc_mb"`
TotalAllocMB float64 `json:"total_alloc_mb"`
SysMB float64 `json:"sys_mb"`
NumGC uint32 `json:"num_gc"`
}
MemoryStats represents runtime memory statistics.
type MessageQueue ¶
type MessageQueue struct {
// contains filtered or unexported fields
}
MessageQueue handles message bursts with per-session debouncing.
func NewMessageQueue ¶
func NewMessageQueue(debounceMs, maxPending int, onDrain OnDrainFunc, logger *slog.Logger) *MessageQueue
NewMessageQueue creates a new message queue. onDrain is called when the debounce timer fires with drained messages (may be nil).
func (*MessageQueue) CombineMessages ¶
func (q *MessageQueue) CombineMessages(msgs []*channels.IncomingMessage) string
CombineMessages merges multiple messages into one prompt string.
func (*MessageQueue) Drain ¶
func (q *MessageQueue) Drain(sessionID string) []*channels.IncomingMessage
Drain returns and clears pending messages for the session.
func (*MessageQueue) Enqueue ¶
func (q *MessageQueue) Enqueue(sessionID string, msg *channels.IncomingMessage) bool
Enqueue adds a message to the session queue. Returns true if enqueued, false if deduplicated (same content within 5 seconds).
func (*MessageQueue) IsDuplicate ¶ added in v1.13.0
func (q *MessageQueue) IsDuplicate(msg *channels.IncomingMessage) bool
IsDuplicate checks if a message is a platform-level duplicate delivery (webhook retries, reconnection replays) using Message-ID deduplication. Safe to call from any goroutine. Records the message so future duplicates are caught. Returns true if the message was already seen.
func (*MessageQueue) IsProcessing ¶
func (q *MessageQueue) IsProcessing(sessionID string) bool
IsProcessing returns true if the session has an active run.
func (*MessageQueue) SetChannelDebounce ¶ added in v1.13.0
func (q *MessageQueue) SetChannelDebounce(m map[string]int)
SetChannelDebounce configures per-channel debounce overrides. Channels not in the map use the default debounceMs.
func (*MessageQueue) SetProcessing ¶
func (q *MessageQueue) SetProcessing(sessionID string, active bool)
SetProcessing marks the session as processing or not.
func (*MessageQueue) StuckSessions ¶
func (q *MessageQueue) StuckSessions(maxAge time.Duration) []string
StuckSessions returns session IDs that have been processing longer than maxAge.
func (*MessageQueue) TrySetProcessing ¶
func (q *MessageQueue) TrySetProcessing(sessionID string) bool
TrySetProcessing atomically checks if the session is NOT processing and sets it to processing. Returns true if successful (caller owns the lock), false if the session was already processing (caller should enqueue). This eliminates the race window between IsProcessing() and SetProcessing().
type MetricsCollector ¶ added in v1.8.0
type MetricsCollector struct {
// contains filtered or unexported fields
}
MetricsCollector collects and aggregates system metrics periodically.
func NewMetricsCollector ¶ added in v1.8.0
func NewMetricsCollector(cfg MetricsCollectorConfig, logger *slog.Logger) *MetricsCollector
NewMetricsCollector creates a new metrics collector.
func (*MetricsCollector) Latest ¶ added in v1.8.0
func (m *MetricsCollector) Latest() *MetricsSnapshot
Latest returns the most recent metrics snapshot.
func (*MetricsCollector) RecordAgentRunComplete ¶ added in v1.8.0
func (m *MetricsCollector) RecordAgentRunComplete(success bool, timedOut bool)
RecordAgentRunComplete decrements active runs and records outcome.
func (*MetricsCollector) RecordAgentRunStart ¶ added in v1.8.0
func (m *MetricsCollector) RecordAgentRunStart()
RecordAgentRunStart increments active runs.
func (*MetricsCollector) RecordDBQuery ¶ added in v1.8.0
func (m *MetricsCollector) RecordDBQuery(slow bool)
RecordDBQuery records a database query.
func (*MetricsCollector) RecordError ¶ added in v1.8.0
func (m *MetricsCollector) RecordError()
RecordError increments error counter.
func (*MetricsCollector) RecordLatency ¶ added in v1.8.0
func (m *MetricsCollector) RecordLatency(ms int64)
RecordLatency records a latency measurement in milliseconds.
func (*MetricsCollector) RecordMessage ¶ added in v1.8.0
func (m *MetricsCollector) RecordMessage()
RecordMessage increments message counter.
func (*MetricsCollector) RecordSessionCreated ¶ added in v1.8.0
func (m *MetricsCollector) RecordSessionCreated()
RecordSessionCreated records a new session.
func (*MetricsCollector) RecordSubagentComplete ¶ added in v1.8.0
func (m *MetricsCollector) RecordSubagentComplete(success bool)
RecordSubagentComplete records a subagent completion.
func (*MetricsCollector) RecordSubagentSpawn ¶ added in v1.8.0
func (m *MetricsCollector) RecordSubagentSpawn()
RecordSubagentSpawn records a subagent creation.
func (*MetricsCollector) RecordTokens ¶ added in v1.8.0
func (m *MetricsCollector) RecordTokens(count int64)
RecordTokens increments token counter.
func (*MetricsCollector) RecordToolCall ¶ added in v1.8.0
func (m *MetricsCollector) RecordToolCall(success bool)
RecordToolCall records a tool execution.
func (*MetricsCollector) SetDBSizeFunc ¶ added in v1.8.0
func (m *MetricsCollector) SetDBSizeFunc(fn func() int64)
SetDBSizeFunc sets the callback for getting database size.
func (*MetricsCollector) SetMessagesQueueFunc ¶ added in v1.8.0
func (m *MetricsCollector) SetMessagesQueueFunc(fn func() int64)
SetMessagesQueueFunc sets the callback for getting queued messages count.
func (*MetricsCollector) SetSessionsCountFunc ¶ added in v1.8.0
func (m *MetricsCollector) SetSessionsCountFunc(fn func() int64)
SetSessionsCountFunc sets the callback for getting active sessions count.
func (*MetricsCollector) SetSubagentsCountFunc ¶ added in v1.8.0
func (m *MetricsCollector) SetSubagentsCountFunc(fn func() int64)
SetSubagentsCountFunc sets the callback for getting active subagents count.
func (*MetricsCollector) Start ¶ added in v1.8.0
func (m *MetricsCollector) Start(ctx context.Context) error
Start begins periodic metrics collection.
func (*MetricsCollector) Stop ¶ added in v1.8.0
func (m *MetricsCollector) Stop()
Stop stops the metrics collector.
func (*MetricsCollector) Subscribe ¶ added in v1.8.0
func (m *MetricsCollector) Subscribe() <-chan MetricsSnapshot
Subscribe returns a channel that receives metrics snapshots.
func (*MetricsCollector) Unsubscribe ¶ added in v1.8.0
func (m *MetricsCollector) Unsubscribe(ch <-chan MetricsSnapshot)
Unsubscribe removes a subscriber.
type MetricsCollectorConfig ¶ added in v1.8.0
type MetricsCollectorConfig struct {
Enabled bool `yaml:"enabled" json:"enabled"`
Interval time.Duration `yaml:"interval" json:"interval"`
Webhook string `yaml:"webhook" json:"webhook"`
}
MetricsCollectorConfig configures the metrics collector.
func DefaultMetricsCollectorConfig ¶ added in v1.8.0
func DefaultMetricsCollectorConfig() MetricsCollectorConfig
DefaultMetricsCollectorConfig returns default configuration.
type MetricsResult ¶
type MetricsResult struct {
Period string `json:"period"`
StartTime time.Time `json:"start_time"`
EndTime time.Time `json:"end_time"`
Total MetricsTotals `json:"total"`
ByModel map[string]MetricsTotals `json:"by_model"`
TopUsers []UserUsage `json:"top_users"`
}
MetricsResult represents usage metrics for a time period.
type MetricsSnapshot ¶ added in v1.8.0
type MetricsSnapshot struct {
Timestamp time.Time `json:"timestamp"`
// Message metrics
MessagesTotal int64 `json:"messages_total"`
MessagesPerMinute int64 `json:"messages_per_minute"`
// Token metrics
TokensTotal int64 `json:"tokens_total"`
TokensPerMinute int64 `json:"tokens_per_minute"`
// Agent metrics
AgentRunsTotal int64 `json:"agent_runs_total"`
AgentRunsActive int64 `json:"agent_runs_active"`
AgentRunsSuccess int64 `json:"agent_runs_success"`
AgentRunsFailed int64 `json:"agent_runs_failed"`
AgentRunsTimeout int64 `json:"agent_runs_timeout"`
// Tool metrics
ToolCallsTotal int64 `json:"tool_calls_total"`
ToolCallsSuccess int64 `json:"tool_calls_success"`
ToolCallsFailed int64 `json:"tool_calls_failed"`
// Subagent metrics
SubagentsTotal int64 `json:"subagents_total"`
SubagentsActive int64 `json:"subagents_active"`
SubagentsSuccess int64 `json:"subagents_success"`
SubagentsFailed int64 `json:"subagents_failed"`
// System metrics
Goroutines int64 `json:"goroutines"`
MemoryAllocMB int64 `json:"memory_alloc_mb"`
MemorySysMB int64 `json:"memory_sys_mb"`
// Session metrics
SessionsActive int64 `json:"sessions_active"`
SessionsTotal int64 `json:"sessions_total"`
// Error metrics
ErrorsTotal int64 `json:"errors_total"`
ErrorsRecent int64 `json:"errors_recent"` // last interval
// Latency metrics (milliseconds)
LatencyAvgMs int64 `json:"latency_avg_ms"`
LatencyP50Ms int64 `json:"latency_p50_ms"`
LatencyP99Ms int64 `json:"latency_p99_ms"`
// Database metrics
DBSizeMB int64 `json:"db_size_mb"`
DBQueries int64 `json:"db_queries"`
DBSlowQuery int64 `json:"db_slow_query"`
// Uptime
UptimeSeconds int64 `json:"uptime_seconds"`
}
MetricsSnapshot represents a point-in-time collection of system metrics.
type MetricsTotals ¶
type MetricsTotals struct {
PromptTokens int64 `json:"prompt_tokens"`
CompletionTokens int64 `json:"completion_tokens"`
TotalTokens int64 `json:"total_tokens"`
Requests int64 `json:"requests"`
EstimatedCostUSD float64 `json:"estimated_cost_usd"`
}
MetricsTotals holds aggregated usage totals.
type ModelCooldown ¶
type ModelCooldown struct {
Model string
Until time.Time
Reason FailoverReason
ErrorCount int
LastError time.Time
}
ModelCooldown tracks a model's cooldown state.
type ModelCost ¶
type ModelCost struct {
InputPer1M float64 `yaml:"input_per_1m"` // USD per 1M input tokens
OutputPer1M float64 `yaml:"output_per_1m"` // USD per 1M output tokens
}
ModelCost holds pricing per 1M tokens for a model.
type ModelFailoverManager ¶
type ModelFailoverManager struct {
// contains filtered or unexported fields
}
ModelFailoverManager handles automatic model rotation on failures.
func NewModelFailoverManager ¶
func NewModelFailoverManager(config ModelFallbackConfig, logger *slog.Logger) *ModelFailoverManager
NewModelFailoverManager creates a failover manager.
func (*ModelFailoverManager) ApplyClassifiedFailure ¶ added in v1.13.0
func (m *ModelFailoverManager) ApplyClassifiedFailure(model string, reason FailoverReason)
ApplyClassifiedFailure applies a pre-classified failure reason to a model. Use this when the error has already been classified (e.g., by the FailoverCoordinator) to avoid redundant re-classification.
func (*ModelFailoverManager) GetCooldownStatus ¶
func (m *ModelFailoverManager) GetCooldownStatus() map[string]*ModelCooldown
GetCooldownStatus returns the current cooldown state of all models.
func (*ModelFailoverManager) MarkProbed ¶ added in v1.13.0
func (m *ModelFailoverManager) MarkProbed(model string)
MarkProbed records that a probe was attempted for a model.
func (*ModelFailoverManager) ReportFailure ¶
func (m *ModelFailoverManager) ReportFailure(model string, statusCode int, errMsg string) FailoverReason
ReportFailure records a failure for a model and applies cooldown if needed. Returns the reason classification.
func (*ModelFailoverManager) ReportFailureWithCause ¶ added in v1.16.0
func (m *ModelFailoverManager) ReportFailureWithCause(model string, statusCode int, errMsg string, cause error) FailoverReason
ReportFailureWithCause is like ReportFailure but also traverses the error cause chain for more accurate classification of wrapped errors.
func (*ModelFailoverManager) ReportSuccess ¶
func (m *ModelFailoverManager) ReportSuccess(model string)
ReportSuccess resets the cooldown for a model after a successful call.
func (*ModelFailoverManager) SelectFromChain ¶ added in v1.13.0
func (m *ModelFailoverManager) SelectFromChain(chain []string) string
SelectFromChain tries models from a custom chain, skipping those in cooldown. Returns the first available model, or empty string if all are in cooldown.
func (*ModelFailoverManager) SelectModel ¶
func (m *ModelFailoverManager) SelectModel() (model string, isPrimary bool)
SelectModel returns the best available model. It checks the primary first, then iterates through fallbacks, skipping any that are in cooldown. Returns the model name and whether it's the primary.
When the primary is in cooldown but near expiry (within probeMargin), the caller can check ShouldProbe() to decide whether to attempt a recovery probe before committing to a fallback model.
func (*ModelFailoverManager) ShouldProbe ¶ added in v1.13.0
func (m *ModelFailoverManager) ShouldProbe(model string) bool
ShouldProbe returns true if a model is in cooldown but near expiry (within probeMargin) and hasn't been probed too recently. This enables auto-recovery without waiting for the full cooldown to expire.
type ModelFallbackConfig ¶
type ModelFallbackConfig struct {
Primary string `yaml:"primary"` // e.g. "claude-sonnet-4-20250514"
Fallbacks []string `yaml:"fallbacks"` // e.g. ["gpt-4o", "glm-5"]
// CooldownConfig controls how long a model is disabled after failures.
Cooldowns CooldownConfig `yaml:"cooldowns"`
}
ModelFallbackConfig defines the primary model and fallback chain.
type NativeMediaConfig ¶ added in v1.8.0
type NativeMediaConfig struct {
// Enabled activates native media features (default: true after setup).
Enabled bool `yaml:"enabled"`
// Store configures media storage.
Store NativeMediaStoreConfig `yaml:"store"`
// Service configures the media service.
Service NativeMediaServiceConfig `yaml:"service"`
// Enrichment configures automatic media enrichment.
Enrichment NativeMediaEnrichmentConfig `yaml:"enrichment"`
}
NativeMediaConfig configures the native media handling system.
func DefaultNativeMediaConfig ¶ added in v1.8.0
func DefaultNativeMediaConfig() NativeMediaConfig
DefaultNativeMediaConfig returns sensible defaults for native media. Note: The enrichment flags (AutoEnrichImages, AutoEnrichAudio) are set to true by default, but they will only work if the corresponding MediaConfig capabilities (VisionEnabled, TranscriptionEnabled) are also enabled. Documents always work as they don't depend on external APIs.
type NativeMediaEnrichmentConfig ¶ added in v1.8.0
type NativeMediaEnrichmentConfig struct {
// AutoEnrichImages runs vision on received images.
AutoEnrichImages bool `yaml:"auto_enrich_images"`
// AutoEnrichAudio transcribes received audio.
AutoEnrichAudio bool `yaml:"auto_enrich_audio"`
// AutoEnrichDocuments extracts text from documents.
AutoEnrichDocuments bool `yaml:"auto_enrich_documents"`
}
NativeMediaEnrichmentConfig configures automatic media enrichment.
type NativeMediaServiceConfig ¶ added in v1.8.0
type NativeMediaServiceConfig struct {
// MaxImageSize is the maximum image size in bytes.
MaxImageSize int64 `yaml:"max_image_size"`
// MaxAudioSize is the maximum audio size in bytes.
MaxAudioSize int64 `yaml:"max_audio_size"`
// MaxDocSize is the maximum document size in bytes.
MaxDocSize int64 `yaml:"max_doc_size"`
// TempTTL is the time-to-live for temporary files.
TempTTL string `yaml:"temp_ttl"`
// CleanupEnabled enables automatic cleanup of expired files.
CleanupEnabled bool `yaml:"cleanup_enabled"`
// CleanupInterval is the interval between cleanup runs.
CleanupInterval string `yaml:"cleanup_interval"`
}
NativeMediaServiceConfig configures the media service.
type NativeMediaStoreConfig ¶ added in v1.8.0
type NativeMediaStoreConfig struct {
// BaseDir is the permanent storage directory.
BaseDir string `yaml:"base_dir"`
// TempDir is the temporary storage directory.
TempDir string `yaml:"temp_dir"`
// MaxFileSize is the maximum file size in bytes.
MaxFileSize int64 `yaml:"max_file_size"`
}
NativeMediaStoreConfig configures media storage.
type NetworkRequest ¶ added in v1.13.0
type NetworkRequest struct {
URL string `json:"url"`
Method string `json:"method"`
Status int `json:"status"`
Type string `json:"type"`
Headers map[string]string `json:"headers,omitempty"`
Timestamp int64 `json:"timestamp"`
}
NetworkRequest represents a network request.
type NextAction ¶ added in v1.17.0
type NextAction int
NextAction tells the QueryLoop what to do after a phase completes.
const ( // ActionContinue proceeds to the next phase in sequence. ActionContinue NextAction = iota // ActionLoopBack returns to the APICall phase (tool_use detected). ActionLoopBack // ActionStop ends the turn and returns the response. ActionStop // ActionInject re-injects a message and loops back to APICall. ActionInject )
func (NextAction) String ¶ added in v1.17.0
func (a NextAction) String() string
String returns a human-readable name for the action.
type OAuthHubConfig ¶ added in v1.13.0
type OAuthHubConfig struct {
// Mode selects the OAuth strategy:
// "local" (default) - use local TokenManager as before
// "hub" - delegate OAuth to an OAuth Hub instance
Mode string `yaml:"mode"`
// HubURL is the base URL of the OAuth Hub (e.g. "http://localhost:8443").
// Required when Mode is "hub".
HubURL string `yaml:"hub_url"`
// APIKey is the API key for authenticating with the Hub (dk_xxx).
// Can also reference a vault key or environment variable.
APIKey string `yaml:"api_key"`
// APIKeyEnvVar is the environment variable containing the API key.
// Defaults to "OAUTH_HUB_API_KEY" if APIKey is empty.
APIKeyEnvVar string `yaml:"api_key_env_var"`
}
OAuthHubConfig configures the OAuth Hub integration.
type OAuthTokenManager ¶ added in v1.12.0
OAuthTokenManager is the interface for OAuth token management.
type OnDrainFunc ¶
type OnDrainFunc func(sessionID string, msgs []*channels.IncomingMessage)
OnDrainFunc is called when the debounce timer fires with drained messages.
type PageState ¶ added in v1.13.0
type PageState struct {
ConsoleMessages []ConsoleMessage
NetworkRequests []NetworkRequest
LastSnapshot *SnapshotResult
}
PageState tracks per-page state.
type PairingManager ¶
type PairingManager struct {
// contains filtered or unexported fields
}
PairingManager handles pairing tokens and requests.
func NewPairingManager ¶
func NewPairingManager(db *sql.DB, accessMgr *AccessManager, wsMgr *WorkspaceManager, logger *slog.Logger) *PairingManager
NewPairingManager creates a new pairing manager.
func (*PairingManager) ApproveRequest ¶
func (pm *PairingManager) ApproveRequest(requestID, approvedBy string) error
ApproveRequest approves a pending request and grants access.
func (*PairingManager) CreateRequest ¶
func (pm *PairingManager) CreateRequest(tokenID, userJID, userName string) (*PairingRequest, error)
CreateRequest creates a pending pairing request.
func (*PairingManager) DenyRequest ¶
func (pm *PairingManager) DenyRequest(requestID, deniedBy, reason string) error
DenyRequest denies a pending request.
func (*PairingManager) GenerateToken ¶
func (pm *PairingManager) GenerateToken(createdBy string, opts TokenOptions) (*PairingToken, error)
GenerateToken creates a new pairing token.
func (*PairingManager) GetTokenByIDOrPrefix ¶
func (pm *PairingManager) GetTokenByIDOrPrefix(idOrPrefix string) (*PairingToken, error)
GetTokenByIDOrPrefix finds a token by ID or token prefix.
func (*PairingManager) ListPendingRequests ¶
func (pm *PairingManager) ListPendingRequests() ([]*PairingRequest, error)
ListPendingRequests returns all pending requests.
func (*PairingManager) ListTokens ¶
func (pm *PairingManager) ListTokens(includeRevoked bool) ([]*PairingToken, error)
ListTokens returns all tokens (with optional filter).
func (*PairingManager) Load ¶
func (pm *PairingManager) Load() error
Load restores token cache from database on startup.
func (*PairingManager) ProcessTokenRedemption ¶
func (pm *PairingManager) ProcessTokenRedemption(tokenStr, userJID, userName string) (bool, string, error)
ProcessTokenRedemption handles a user sending a token. Returns: (approved, message, error)
func (*PairingManager) RevokeToken ¶
func (pm *PairingManager) RevokeToken(tokenID, revokedBy string) error
RevokeToken revokes a token.
func (*PairingManager) ValidateToken ¶
func (pm *PairingManager) ValidateToken(token string) (*PairingToken, error)
ValidateToken checks if a token is valid and returns it.
type PairingRequest ¶
type PairingRequest struct {
ID string `json:"id"`
TokenID string `json:"token_id"`
UserJID string `json:"user_jid"`
UserName string `json:"user_name"`
Status string `json:"status"` // pending, approved, denied
ReviewedBy string `json:"reviewed_by"`
ReviewedAt *time.Time `json:"reviewed_at,omitempty"`
CreatedAt time.Time `json:"created_at"`
// Loaded via join for display
TokenNote string `json:"token_note,omitempty"`
TokenRole TokenRole `json:"token_role,omitempty"`
}
PairingRequest represents a pending access request.
type PairingToken ¶
type PairingToken struct {
ID string `json:"id"`
Token string `json:"token"`
Role TokenRole `json:"role"`
MaxUses int `json:"max_uses"` // 0 = unlimited
UseCount int `json:"use_count"`
AutoApprove bool `json:"auto_approve"` // If true, grants access immediately
WorkspaceID string `json:"workspace_id"`
Note string `json:"note"`
CreatedBy string `json:"created_by"`
CreatedAt time.Time `json:"created_at"`
ExpiresAt *time.Time `json:"expires_at,omitempty"`
Revoked bool `json:"revoked"`
RevokedAt *time.Time `json:"revoked_at,omitempty"`
RevokedBy string `json:"revoked_by"`
}
PairingToken represents a shareable invite token.
func (*PairingToken) CanUse ¶
func (t *PairingToken) CanUse() bool
CanUse returns true if the token can still be used.
func (*PairingToken) IsExpired ¶
func (t *PairingToken) IsExpired() bool
IsExpired returns true if the token has expired.
type PalaceBotConfig ¶ added in v1.18.0
type PalaceBotConfig struct {
Store *memory.SQLiteStore
Router *ContextRouter
Enabled bool
}
PalaceBotConfig bundles the dependencies a command handler needs. Typically constructed once at startup and passed to HandlePalaceBotCommand on every message.
type PalaceBotReply ¶ added in v1.18.0
PalaceBotReply is the result of handling a command. When Handled is false, Reply should be ignored and the message should continue through the normal LLM path.
func HandlePalaceBotCommand ¶ added in v1.18.0
func HandlePalaceBotCommand(ctx context.Context, cfg PalaceBotConfig, channel, chatID, input string) PalaceBotReply
HandlePalaceBotCommand inspects an incoming chat message and, if it is a palace-aware slash command, handles it directly and returns the reply text. Callers invoke this before any LLM processing.
Parameters:
- ctx: request context
- cfg: palace bot config (store, router, enabled flag)
- channel: the channel identifier (e.g., "telegram", "whatsapp")
- chatID: the external chat ID from the channel
- input: the raw message text from the user
Returns a PalaceBotReply. If Handled is false, the caller should process the message normally. If Handled is true, the caller should send Reply back to the user via the channel and skip LLM invocation.
type PendingApproval ¶
type PendingApproval struct {
ID string
ToolName string
Args map[string]any
Description string
SessionID string
CallerJID string
CreatedAt time.Time
Result chan ApprovalResult
}
PendingApproval represents a tool call waiting for user approval.
type Phase ¶ added in v1.17.0
type Phase interface {
// Name returns a human-readable identifier for logging and debugging.
Name() string
// Execute runs this phase's logic on the given turn state.
// Returns the next action and any error.
Execute(ctx context.Context, state *TurnState) (NextAction, error)
}
Phase represents a single stage in the query loop pipeline. Each phase receives the turn state, performs its work, and returns the next action for the loop orchestrator.
type PhaseResult ¶ added in v1.17.0
type PhaseResult struct {
Phase CoordinatorPhase
Results []WorkerResult
Duration time.Duration
}
PhaseResult holds the outcome of an entire phase.
type PreparePhase ¶ added in v1.17.0
type PreparePhase struct {
// contains filtered or unexported fields
}
PreparePhase handles message building and tool resolution.
func NewPreparePhase ¶ added in v1.17.0
func NewPreparePhase(builder func(state *TurnState) error) *PreparePhase
NewPreparePhase creates a prepare phase with a message builder function.
func (*PreparePhase) Execute ¶ added in v1.17.0
func (p *PreparePhase) Execute(ctx context.Context, state *TurnState) (NextAction, error)
func (*PreparePhase) Name ¶ added in v1.17.0
func (p *PreparePhase) Name() string
type ProfileChecker ¶
type ProfileChecker struct {
// contains filtered or unexported fields
}
ProfileChecker checks if tools are allowed/denied by a profile.
func NewProfileChecker ¶
func NewProfileChecker(allow, deny []string, allTools []string) *ProfileChecker
NewProfileChecker creates a checker from allow/deny lists.
func (*ProfileChecker) Check ¶
func (pc *ProfileChecker) Check(toolName string) (allowed bool, reason string)
Check returns whether a tool is permitted by the profile. Returns (allowed, reason) where reason explains why if not allowed.
func (*ProfileChecker) IsAllowed ¶
func (pc *ProfileChecker) IsAllowed(toolName string) bool
IsAllowed returns true if the tool is in the allow list. If allow list is empty, all tools are allowed (respecting deny).
func (*ProfileChecker) IsDenied ¶
func (pc *ProfileChecker) IsDenied(toolName string) bool
IsDenied returns true if the tool is in the deny list.
type ProgressSender ¶
ProgressSender sends intermediate progress messages to the user during long-running tool execution (e.g. claude-code). Called by tools that want to give real-time feedback without waiting for the full result.
func ProgressSenderFromContext ¶
func ProgressSenderFromContext(ctx context.Context) ProgressSender
ProgressSenderFromContext extracts the ProgressSender from context. Returns nil if not set.
type Project ¶
type Project struct {
// ID is the unique project identifier (slug, e.g. "devclaw", "my-saas").
ID string `yaml:"id"`
// Name is the human-readable project name.
Name string `yaml:"name"`
// RootPath is the absolute path to the project root directory.
RootPath string `yaml:"root_path"`
// Language is the primary programming language (auto-detected or manual).
Language string `yaml:"language"`
// Framework is the detected/configured framework (e.g. "laravel", "next", "gin").
Framework string `yaml:"framework"`
// GitRemote is the primary git remote URL (auto-detected from origin).
GitRemote string `yaml:"git_remote,omitempty"`
// BuildCmd is the command to build the project.
BuildCmd string `yaml:"build_cmd,omitempty"`
// TestCmd is the command to run tests.
TestCmd string `yaml:"test_cmd,omitempty"`
// LintCmd is the command to run the linter.
LintCmd string `yaml:"lint_cmd,omitempty"`
// StartCmd is the command to start the dev server.
StartCmd string `yaml:"start_cmd,omitempty"`
// DeployCmd is the command to deploy the project.
DeployCmd string `yaml:"deploy_cmd,omitempty"`
// DockerCompose is the path to docker-compose.yml (if present).
DockerCompose string `yaml:"docker_compose,omitempty"`
// EnvFile is the path to the .env file (if present).
EnvFile string `yaml:"env_file,omitempty"`
// MCPServers lists MCP server configurations for this project.
MCPServers []MCPServerConfig `yaml:"mcp_servers,omitempty"`
}
Project represents a registered development project.
type ProjectManager ¶
type ProjectManager struct {
// contains filtered or unexported fields
}
ProjectManager manages registered projects and per-session active project.
func NewProjectManager ¶
func NewProjectManager(dataDir string) *ProjectManager
NewProjectManager creates a new ProjectManager, loading from disk if available.
func (*ProjectManager) Activate ¶
func (pm *ProjectManager) Activate(sessionKey, projectID string) error
Activate sets the active project for a session.
func (*ProjectManager) ActiveProject ¶
func (pm *ProjectManager) ActiveProject(sessionKey string) *Project
ActiveProject returns the active project for a session, or nil.
func (*ProjectManager) FindByPath ¶
func (pm *ProjectManager) FindByPath(path string) *Project
FindByPath finds a project whose root matches the given path.
func (*ProjectManager) Get ¶
func (pm *ProjectManager) Get(id string) *Project
Get returns a project by ID.
func (*ProjectManager) List ¶
func (pm *ProjectManager) List() []*Project
List returns all registered projects sorted by name.
func (*ProjectManager) Register ¶
func (pm *ProjectManager) Register(p *Project) error
Register adds or updates a project.
func (*ProjectManager) Remove ¶
func (pm *ProjectManager) Remove(id string) error
Remove removes a project by ID.
func (*ProjectManager) ScanDirectory ¶
func (pm *ProjectManager) ScanDirectory(root string) ([]*Project, error)
ScanDirectory scans a directory for projects (subdirectories with .git or known markers).
type ProjectProviderAdapter ¶
type ProjectProviderAdapter struct {
// contains filtered or unexported fields
}
ProjectProviderAdapter adapts a copilot.ProjectManager to the skills.ProjectProvider interface so coding skills can access project context without importing the copilot package.
func NewProjectProviderAdapter ¶
func NewProjectProviderAdapter(pm *ProjectManager) *ProjectProviderAdapter
NewProjectProviderAdapter creates a new adapter wrapping the given ProjectManager.
func (*ProjectProviderAdapter) Activate ¶
func (a *ProjectProviderAdapter) Activate(sessionKey, projectID string) error
Activate sets the active project for a session.
func (*ProjectProviderAdapter) ActiveProject ¶
func (a *ProjectProviderAdapter) ActiveProject(sessionKey string) *skills.ProjectInfo
ActiveProject returns the active project for a session.
func (*ProjectProviderAdapter) Get ¶
func (a *ProjectProviderAdapter) Get(id string) *skills.ProjectInfo
Get returns a project by ID.
func (*ProjectProviderAdapter) List ¶
func (a *ProjectProviderAdapter) List() []*skills.ProjectInfo
List returns all registered projects.
func (*ProjectProviderAdapter) Register ¶
func (a *ProjectProviderAdapter) Register(p *skills.ProjectInfo) error
Register adds or updates a project.
func (*ProjectProviderAdapter) Remove ¶
func (a *ProjectProviderAdapter) Remove(id string) error
Remove removes a project by ID.
func (*ProjectProviderAdapter) ScanDirectory ¶
func (a *ProjectProviderAdapter) ScanDirectory(root string) ([]*skills.ProjectInfo, error)
ScanDirectory scans for projects in a directory.
type PromptComposer ¶
type PromptComposer struct {
// contains filtered or unexported fields
}
PromptComposer assembles the final system prompt from multiple layers.
func NewPromptComposer ¶
func NewPromptComposer(config *Config) *PromptComposer
NewPromptComposer creates a new prompt composer.
func (*PromptComposer) Compose ¶
func (p *PromptComposer) Compose(session *Session, input string) string
Compose builds the complete system prompt for a session and user input. Heavy layers (bootstrap, memory, skills, conversation) are built concurrently to minimize prompt composition latency.
func (*PromptComposer) ComposeForSubagent ¶ added in v1.13.0
func (p *PromptComposer) ComposeForSubagent() string
ComposeForSubagent builds a system prompt optimized for subagents. Compared to ComposeMinimal, it strips sections that are irrelevant to subagent execution: Heartbeats, Reply Tags, Messaging, Silent Replies, and Memory Recall. This saves ~30-40% of core-layer tokens while keeping tooling info, safety, epistemic restraint, and workspace context.
func (*PromptComposer) ComposeMinimal ¶
func (p *PromptComposer) ComposeMinimal() string
ComposeMinimal builds a lightweight system prompt for scheduled jobs and other fast-path scenarios. It includes only: Core identity, Safety, Temporal (date/time), and the user's custom instructions. It deliberately skips bootstrap files, memory search, skill instructions, and conversation history to minimize token count and latency.
func (*PromptComposer) ComposeWithMode ¶ added in v1.12.0
func (p *PromptComposer) ComposeWithMode(session *Session, input string, mode PromptMode) string
ComposeWithMode assembles the system prompt using the specified mode. Use PromptModeFull for the main agent, PromptModeMinimal for subagents, and PromptModeNone for simple tasks requiring only core identity.
func (*PromptComposer) IncrementSkillsVersion ¶ added in v1.13.0
func (p *PromptComposer) IncrementSkillsVersion()
IncrementSkillsVersion bumps the skills snapshot version, causing all sessions to rebuild their skills layer on the next prompt composition. Call after installing, removing, or reloading skills.
func (*PromptComposer) RegisterMemorySectionBuilder ¶ added in v1.16.0
func (p *PromptComposer) RegisterMemorySectionBuilder(builder MemoryPromptSectionBuilder)
RegisterMemorySectionBuilder adds a pluggable memory section builder. Builders are called in registration order during buildMemoryLayer. Thread-safe: may be called concurrently with prompt composition.
func (*PromptComposer) SetAgentProfile ¶ added in v1.13.0
func (p *PromptComposer) SetAgentProfile(profile *AgentProfileConfig)
SetAgentProfile sets the active agent profile for identity resolution.
func (*PromptComposer) SetBuiltinSkills ¶ added in v1.12.0
func (p *PromptComposer) SetBuiltinSkills(skills *BuiltinSkills)
SetBuiltinSkills sets the built-in skills for the prompt composer.
func (*PromptComposer) SetContextEngines ¶ added in v1.13.0
func (p *PromptComposer) SetContextEngines(registry *ContextEngineRegistry)
SetContextEngines sets the pluggable context engine registry.
func (*PromptComposer) SetContextRouter ¶ added in v1.18.0
func (p *PromptComposer) SetContextRouter(router *ContextRouter)
SetContextRouter wires the context router used by the memory stack to resolve the active wing for a session. Nil means every session uses the legacy wing ("").
func (*PromptComposer) SetLCMStore ¶ added in v1.18.2
func (p *PromptComposer) SetLCMStore(store *LCMStore)
SetLCMStore sets the LCM store for conversation-aware memory recall.
func (*PromptComposer) SetMemoryStack ¶ added in v1.18.0
func (p *PromptComposer) SetMemoryStack(stack *MemoryStack)
SetMemoryStack wires a Sprint 2 Room 2.4 layered memory stack into the composer. The stack renders L0+L1+L2 as a prefix that buildMemoryLayer prepends to its legacy L3 output. Passing nil detaches any previously configured stack and restores v1.18.0 byte-identical behavior.
func (*PromptComposer) SetMemoryStore ¶
func (p *PromptComposer) SetMemoryStore(store *memory.FileStore)
SetMemoryStore configures the file-based memory store for the prompt composer.
func (*PromptComposer) SetPluginAgentLister ¶ added in v1.16.0
func (p *PromptComposer) SetPluginAgentLister(lister func() []pluginAgentInfo)
SetPluginAgentLister sets the function used to list available plugin agents.
func (*PromptComposer) SetSQLiteMemory ¶
func (p *PromptComposer) SetSQLiteMemory(store *memory.SQLiteStore)
SetSQLiteMemory configures the SQLite memory store for hybrid search.
func (*PromptComposer) SetSkillGetter ¶
func (p *PromptComposer) SetSkillGetter(getter func(name string) (interface{ SystemPrompt() string }, bool))
SetSkillGetter sets the function used to retrieve skill system prompts.
func (*PromptComposer) SetSkillLister ¶ added in v1.12.0
func (p *PromptComposer) SetSkillLister(lister func() []SkillInfo)
SetSkillLister sets the function used to list all available skills.
func (*PromptComposer) SetSubagentMode ¶
func (p *PromptComposer) SetSubagentMode(isSubagent bool)
SetSubagentMode restricts bootstrap loading to AGENTS.md + TOOLS.md only.
func (*PromptComposer) SetToolExecutor ¶ added in v1.12.0
func (p *PromptComposer) SetToolExecutor(executor *ToolExecutor)
SetToolExecutor sets the tool executor for dynamic tool list generation.
func (*PromptComposer) SetWorkspaceContext ¶ added in v1.16.0
func (p *PromptComposer) SetWorkspaceContext(wsID string, dirs []string)
SetWorkspaceContext configures workspace-specific bootstrap loading. Call before Compose() for non-main workspaces; call with "" to reset.
type PromptLayer ¶
type PromptLayer int
PromptLayer defines the priority of a prompt layer. Lower values = higher priority (never trimmed first on budget cuts).
const ( LayerCore PromptLayer = 0 // Base identity and tooling. LayerSafety PromptLayer = 5 // Safety rules. LayerIdentity PromptLayer = 10 // Custom instructions. LayerThinking PromptLayer = 12 // Extended thinking level hint (from /think). LayerBootstrap PromptLayer = 15 // SOUL.md, AGENTS.md, etc. LayerBuiltinSkills PromptLayer = 18 // Built-in tool guides (memory, agents, etc.) LayerPluginAgents PromptLayer = 19 // Available plugin agents for delegation. LayerBusiness PromptLayer = 20 // User/workspace context. LayerProjectContext PromptLayer = 25 // Auto-discovered project context. LayerSkills PromptLayer = 40 // Active skill instructions. LayerMemory PromptLayer = 50 // Long-term memory facts. LayerTemporal PromptLayer = 60 // Date/time context. LayerConversation PromptLayer = 70 // Recent history summary. LayerRuntime PromptLayer = 80 // Runtime info (final line). )
type PromptMode ¶ added in v1.12.0
type PromptMode string
PromptMode controls which prompt layers are included in the final prompt. Used to reduce token usage for subagents and specialized contexts.
const ( // PromptModeFull includes all layers (default for main agent). PromptModeFull PromptMode = "full" // PromptModeMinimal omits skills, memory, heartbeats (for subagents). PromptModeMinimal PromptMode = "minimal" // PromptModeNone includes only core identity (for simple tasks). PromptModeNone PromptMode = "none" )
type ProviderChainEntry ¶
type ProviderChainEntry struct {
Provider string `yaml:"provider"` // Provider name (openai, anthropic, ollama, etc.)
BaseURL string `yaml:"base_url"` // API endpoint
APIKey string `yaml:"api_key,omitempty"` // API key (can use ${VAR} references)
Model string `yaml:"model"` // Model to use from this provider
}
ProviderChainEntry defines a single provider in the fallback chain.
type ProviderDiscovery ¶ added in v1.13.0
type ProviderDiscovery struct {
// contains filtered or unexported fields
}
ProviderDiscovery probes local LLM providers to discover available models.
func NewProviderDiscovery ¶ added in v1.13.0
func NewProviderDiscovery(cfg ProviderDiscoveryConfig, logger *slog.Logger) *ProviderDiscovery
NewProviderDiscovery creates a new discovery instance.
func (*ProviderDiscovery) DiscoverAll ¶ added in v1.13.0
func (pd *ProviderDiscovery) DiscoverAll(ctx context.Context)
DiscoverAll probes all configured providers and populates the model cache. Safe to call from a goroutine; does not block on failure.
func (*ProviderDiscovery) GetContextWindow ¶ added in v1.13.0
func (pd *ProviderDiscovery) GetContextWindow(model string) int
GetContextWindow returns the discovered context window for a model. Returns 0 if the model was not discovered or context window is unknown.
func (*ProviderDiscovery) ListModels ¶ added in v1.13.0
func (pd *ProviderDiscovery) ListModels() []DiscoveredModel
ListModels returns a copy of all discovered models.
type ProviderDiscoveryConfig ¶ added in v1.13.0
type ProviderDiscoveryConfig struct {
// Enabled turns discovery on (default: false).
Enabled bool `yaml:"enabled"`
// OllamaURL is the base URL for the Ollama API (default: http://localhost:11434).
OllamaURL string `yaml:"ollama_url"`
// VLLMUrl is the base URL for the vLLM API (default: http://localhost:8000).
VLLMURL string `yaml:"vllm_url"`
// VLLMAPIKey is the optional API key for vLLM (some deployments require auth).
VLLMAPIKey string `yaml:"vllm_api_key"`
// TimeoutSeconds is the per-probe HTTP timeout (default: 5).
TimeoutSeconds int `yaml:"timeout_seconds"`
}
ProviderDiscoveryConfig configures dynamic model discovery for local providers.
type QualityGuardConfig ¶ added in v1.14.0
type QualityGuardConfig struct {
// Enabled turns on quality guard (audit + retry). Default: true.
Enabled *bool `yaml:"enabled"`
// MaxRetries is the maximum number of retry attempts on audit failure. Default: 1, Max: 3.
MaxRetries int `yaml:"max_retries"`
// StrictIdentifiers requires that extracted identifiers appear in the summary. Default: false.
StrictIdentifiers bool `yaml:"strict_identifiers"`
}
QualityGuardConfig controls the post-summarization audit and retry mechanism.
type QueryLoop ¶ added in v1.17.0
type QueryLoop struct {
// contains filtered or unexported fields
}
QueryLoop orchestrates the phase pipeline for a single agent turn. It runs phases in sequence, handling loop-back and injection actions.
func NewQueryLoop ¶ added in v1.17.0
NewQueryLoop creates a loop with the given phases. Phases are executed in order: [0] → [1] → [2] → [3] → [4] ActionLoopBack returns to phase index 1 (APICall).
func (*QueryLoop) RunTurn ¶ added in v1.17.0
RunTurn executes the phase pipeline for a single turn. Returns the final state after all phases complete, or an error.
func (*QueryLoop) SetMaxIterations ¶ added in v1.17.0
SetMaxIterations sets the safety limit for loop iterations.
func (*QueryLoop) SetOnPhaseComplete ¶ added in v1.17.0
func (q *QueryLoop) SetOnPhaseComplete(fn func(phase string, action NextAction, duration time.Duration))
SetOnPhaseComplete sets a callback for phase completion events.
type QueryOptions ¶ added in v1.12.0
type QueryOptions struct {
Where map[string]any // Filter conditions
Limit int // Max results (default 100, max 1000)
Offset int // Skip results for pagination
OrderBy string // Column to order by (default: created_at)
Order string // "ASC" or "DESC" (default: DESC)
}
QueryOptions contains optional parameters for queries.
type QueueConfig ¶
type QueueConfig struct {
// DebounceMs is the debounce delay in ms before draining queued messages (default: 200).
DebounceMs int `yaml:"debounce_ms"`
// MaxPending is the max queued messages per session before dropping oldest (default: 20).
MaxPending int `yaml:"max_pending"`
// DefaultMode is the default queue mode for all channels (default: "collect").
DefaultMode QueueMode `yaml:"default_mode"`
// ByChannel overrides the default mode per channel name.
ByChannel map[string]QueueMode `yaml:"by_channel"`
// ChannelDebounce overrides debounce delay per channel (in ms).
// Channels not listed use DebounceMs. Useful for giving WhatsApp a
// longer debounce (e.g. 1000ms) while keeping WebUI snappy (100ms).
ChannelDebounce map[string]int `yaml:"channel_debounce"`
// DropPolicy controls what happens when the queue exceeds MaxPending (default: "old").
DropPolicy QueueDropPolicy `yaml:"drop_policy"`
}
QueueConfig configures the message queue for handling bursts.
type QueueDirective ¶ added in v1.13.0
type QueueDirective struct {
Mode QueueMode // required
DebounceMs int // 0 = not set
Cap int // 0 = not set
Drop QueueDropPolicy // "" = not set
}
QueueDirective holds the parsed result of a /queue directive with optional parameters. Supports: /queue [mode] [debounce=Xms] [cap=N] [drop=policy]
func ParseQueueDirective ¶ added in v1.13.0
func ParseQueueDirective(args string) *QueueDirective
ParseQueueDirective parses an extended /queue directive string. Input format: "mode [debounce=500ms] [cap=10] [drop=old]" Returns nil if the mode is invalid.
type QueueDropPolicy ¶
type QueueDropPolicy string
QueueDropPolicy defines what happens when the queue exceeds max size.
const ( // DropOld removes the oldest messages to make room. DropOld QueueDropPolicy = "old" // DropNew rejects new messages when the queue is full. DropNew QueueDropPolicy = "new" // DropSummarize uses the LLM to summarize dropped messages. DropSummarize QueueDropPolicy = "summarize" )
type QueueMode ¶
type QueueMode string
QueueMode defines how incoming messages are handled when the session is busy.
const ( // QueueModeCollect groups all queued messages into a single prompt. // Processed as one agent run after the current run completes. QueueModeCollect QueueMode = "collect" // QueueModeSteer injects messages into the active agent run via interruptCh. // The agent sees the message between turns and adjusts behavior. QueueModeSteer QueueMode = "steer" // QueueModeFollowup enqueues each message as a separate agent run. // Processed in order after the current run completes. QueueModeFollowup QueueMode = "followup" // QueueModeInterrupt aborts the current run and processes the new message. QueueModeInterrupt QueueMode = "interrupt" // QueueModeSteerBacklog tries steer first; if no active run to inject into, // falls back to followup. QueueModeSteerBacklog QueueMode = "steer-backlog" )
func EffectiveQueueMode ¶
func EffectiveQueueMode(qc QueueConfig, channelName string) QueueMode
EffectiveQueueMode returns the queue mode for a given channel, falling back to the default mode from QueueConfig (defined in config.go).
func ParseQueueMode ¶
ParseQueueMode parses a string into a QueueMode. Returns (mode, true) on success, ("", false) on unknown mode.
type QuietHoursConfig ¶
type QuietHoursConfig struct {
// Enabled activates quiet hours.
Enabled bool `json:"enabled" yaml:"enabled"`
// Start is the start time in HH:MM format.
Start string `json:"start" yaml:"start"`
// End is the end time in HH:MM format.
End string `json:"end" yaml:"end"`
// Timezone is the timezone for quiet hours (default: UTC).
Timezone string `json:"timezone" yaml:"timezone"`
// Days are the days of week when quiet hours apply (0=Sunday, 6=Saturday).
Days []int `json:"days,omitempty" yaml:"days,omitempty"`
}
QuietHoursConfig defines quiet hours for a group or notification rule.
type Ref ¶ added in v1.13.0
type Ref struct {
Role string `json:"role"`
Name string `json:"name,omitempty"`
Nth int `json:"nth,omitempty"` // For duplicate role+name combinations
}
Ref represents a reference to an element in the page.
type RegisteredHook ¶
type RegisteredHook struct {
// Name identifies this hook for logging.
Name string
// Description provides a human-readable summary of this hook.
Description string
// Source indicates where the hook came from (e.g. "system", "plugin:github", "skill:monitor").
Source string
// Events lists which events this hook subscribes to.
Events []HookEvent
// Priority controls execution order (lower = earlier). Default: 100.
Priority int
// Enabled controls whether this hook is active. Default: true.
Enabled bool
// Requires declares runtime prerequisites. Hook is skipped if unmet.
Requires *HookRequirements
// Handler is the callback function.
Handler HookHandler
}
RegisteredHook associates a handler with metadata.
type ReminderInfo ¶ added in v1.12.0
type ReminderInfo struct {
ID string `json:"id"`
JobID string `json:"job_id"`
JobType string `json:"job_type"`
Schedule string `json:"schedule"`
Command string `json:"command"`
Channel string `json:"channel,omitempty"`
ChatID string `json:"chat_id,omitempty"`
Status string `json:"status"` // active, removed, fired
RemovedAt string `json:"removed_at,omitempty"`
CreatedAt string `json:"created_at"`
}
ReminderInfo contains information about a reminder.
type ResolvedWorkspace ¶
type ResolvedWorkspace struct {
// Workspace is the resolved workspace.
Workspace *Workspace
// Session is the workspace-isolated session for this chat.
Session *Session
// SessionStore is the workspace session store (for pruning, etc.).
SessionStore *SessionStore
}
ResolvedWorkspace contains the resolved workspace and session for a message.
type RiskAction ¶
type RiskAction string
RiskAction represents the action to take for a risk level.
const ( ActionAllow RiskAction = "allow" ActionAllowLog RiskAction = "allow_log" ActionRequireApproval RiskAction = "require_approval" ActionDeny RiskAction = "deny" )
type RiskCategoryConfig ¶
type RiskCategoryConfig struct {
// Patterns are glob-like patterns to match commands.
Patterns []string `yaml:"patterns"`
// Action is the action to take for this category.
Action RiskAction `yaml:"action"`
// Notify lists who to notify (e.g., ["owners"], ["admins"]).
Notify []string `yaml:"notify"`
// Message is a custom denial/approval message.
Message string `yaml:"message"`
}
RiskCategoryConfig configures a risk category.
type RoutinesConfig ¶ added in v1.8.0
type RoutinesConfig struct {
// Metrics configures the metrics collector.
Metrics MetricsCollectorConfig `yaml:"metrics"`
// MemoryIndexer configures the background memory indexer.
MemoryIndexer MemoryIndexerConfig `yaml:"memory_indexer"`
}
RoutinesConfig configures background routines for metrics and memory indexing.
func DefaultRoutinesConfig ¶ added in v1.8.0
func DefaultRoutinesConfig() RoutinesConfig
DefaultRoutinesConfig returns sensible defaults for background routines.
type RoutingConfig ¶
type RoutingConfig struct {
// Default is the default agent ID to use when no match is found.
Default string `yaml:"default"`
}
RoutingConfig defines how messages are routed to agents.
type SQLiteAuditLogger ¶
type SQLiteAuditLogger struct {
// contains filtered or unexported fields
}
SQLiteAuditLogger writes tool execution audit records to the devclaw.db audit_log table. It replaces the plain-text append-only file.
func NewSQLiteAuditLogger ¶
func NewSQLiteAuditLogger(db *sql.DB, logger *slog.Logger) *SQLiteAuditLogger
NewSQLiteAuditLogger creates an audit logger backed by SQLite.
func (*SQLiteAuditLogger) Close ¶
func (a *SQLiteAuditLogger) Close()
Close is a no-op; the shared *sql.DB is closed at the application level.
func (*SQLiteAuditLogger) Count ¶
func (a *SQLiteAuditLogger) Count() int
Count returns the total number of audit log entries.
func (*SQLiteAuditLogger) Log ¶
func (a *SQLiteAuditLogger) Log(toolName, caller, level string, allowed bool, argsSummary, resultSummary string)
Log records a tool execution in the audit_log table.
func (*SQLiteAuditLogger) Recent ¶
func (a *SQLiteAuditLogger) Recent(n int) []string
Recent returns the last N audit log entries as formatted strings.
func (*SQLiteAuditLogger) RecentRecords ¶
func (a *SQLiteAuditLogger) RecentRecords(n int) []AuditRecord
RecentRecords returns the last N audit log entries as structured records.
type SQLiteMemoryStore ¶ added in v1.8.0
type SQLiteMemoryStore interface {
IndexChunks(chunks []MemoryChunk) error
DeleteByFilepath(filepath string) error
GetIndexedFiles() (map[string]string, error) // filepath -> hash
}
SQLiteMemoryStore is an interface for SQLite memory operations.
type SQLiteSessionPersistence ¶
type SQLiteSessionPersistence struct {
// contains filtered or unexported fields
}
SQLiteSessionPersistence stores session data in the devclaw.db tables: session_entries, session_meta, session_facts.
func NewSQLiteSessionPersistence ¶
func NewSQLiteSessionPersistence(db *sql.DB, logger *slog.Logger) *SQLiteSessionPersistence
NewSQLiteSessionPersistence creates a SQLite-backed session persistence. The tables must already exist (created by OpenDatabase).
func (*SQLiteSessionPersistence) Close ¶
func (p *SQLiteSessionPersistence) Close() error
Close is a no-op; the shared *sql.DB is closed at the application level.
func (*SQLiteSessionPersistence) DeleteSession ¶
func (p *SQLiteSessionPersistence) DeleteSession(sessionID string) error
DeleteSession removes all data for a session (entries, facts, meta).
func (*SQLiteSessionPersistence) ListSessionsMeta ¶ added in v1.13.0
func (p *SQLiteSessionPersistence) ListSessionsMeta() ([]SessionMeta, error)
ListSessionsMeta returns lightweight metadata for all sessions without loading full conversation history. Used by the web UI sidebar to list conversations.
func (*SQLiteSessionPersistence) LoadAll ¶
func (p *SQLiteSessionPersistence) LoadAll() (map[string]*SessionData, error)
LoadAll scans all sessions from the database and returns SessionData for each.
func (*SQLiteSessionPersistence) LoadSession ¶
func (p *SQLiteSessionPersistence) LoadSession(sessionID string) ([]ConversationEntry, []string, error)
LoadSession reads all entries and facts for a session.
func (*SQLiteSessionPersistence) Rotate ¶
func (p *SQLiteSessionPersistence) Rotate(sessionID string, maxLines int) error
Rotate keeps only the latest maxLines entries for a session.
func (*SQLiteSessionPersistence) SaveCompaction ¶ added in v1.12.0
func (p *SQLiteSessionPersistence) SaveCompaction(sessionID string, entry CompactionEntry) error
SaveCompaction appends a compaction summary entry for the session.
func (*SQLiteSessionPersistence) SaveEntry ¶
func (p *SQLiteSessionPersistence) SaveEntry(sessionID string, entry ConversationEntry) error
SaveEntry appends a conversation entry for the given session.
func (*SQLiteSessionPersistence) SaveFacts ¶
func (p *SQLiteSessionPersistence) SaveFacts(sessionID string, facts []string) error
SaveFacts replaces all facts for the given session.
func (*SQLiteSessionPersistence) SaveMeta ¶
func (p *SQLiteSessionPersistence) SaveMeta(sessionID, channel, chatID string, config SessionConfig, activeSkills []string) error
SaveMeta persists session metadata (channel, chatID, config, activeSkills).
func (*SQLiteSessionPersistence) TruncateAfterCompaction ¶ added in v1.16.0
func (p *SQLiteSessionPersistence) TruncateAfterCompaction(sessionID string, keepRecentEntries int) error
TruncateAfterCompaction removes old entries keeping only the last compaction entry and entries written after it.
type SchedulerConfig ¶
type SchedulerConfig struct {
// Enabled turns the scheduler on/off.
Enabled bool `yaml:"enabled"`
// Storage is the path to the scheduler storage file (legacy/fallback).
// When devclawDB is available, jobs are stored in the "jobs" table in devclaw.db.
// This field is only used as a fallback for file-based storage.
Storage string `yaml:"storage"`
}
SchedulerConfig configures the task scheduler.
type SchedulerStats ¶
type SchedulerStats struct {
Enabled bool `json:"enabled"`
Jobs int `json:"jobs"`
NextRun string `json:"next_run,omitempty"`
Running int `json:"running"`
}
SchedulerStats holds scheduler statistics.
type SearchConfig ¶
type SearchConfig struct {
// HybridWeightVector is the weight for vector search (default: 0.7).
HybridWeightVector float64 `yaml:"hybrid_weight_vector"`
// HybridWeightBM25 is the weight for BM25 keyword search (default: 0.3).
HybridWeightBM25 float64 `yaml:"hybrid_weight_bm25"`
// MaxResults is the max results returned (default: 6).
MaxResults int `yaml:"max_results"`
// MinScore is the minimum score threshold (default: 0.1).
MinScore float64 `yaml:"min_score"`
// TemporalDecay configures time-based score decay for memory search.
TemporalDecay TemporalDecayConfig `yaml:"temporal_decay"`
// MMR configures Maximal Marginal Relevance for result diversification.
MMR MMRConfig `yaml:"mmr"`
}
SearchConfig configures hybrid search behavior.
type SecurityAuditToolConfig ¶ added in v1.13.0
type SecurityAuditToolConfig struct {
DataDir string
Vault *Vault
SSRFGuard *security.SSRFGuard
GatewayConfig GatewayConfig
AllowSudo bool
EmbeddingCfg memory.EmbeddingConfig
}
SecurityAuditToolConfig holds static config for the security_audit tool.
type SecurityConfig ¶
type SecurityConfig struct {
// MaxInputLength is the max input size in characters.
MaxInputLength int `yaml:"max_input_length"`
// RateLimit is max messages per minute per user.
RateLimit int `yaml:"rate_limit"`
// EnablePIIDetection enables PII detection in outputs.
EnablePIIDetection bool `yaml:"enable_pii_detection"`
// EnableURLValidation enables URL validation in outputs.
EnableURLValidation bool `yaml:"enable_url_validation"`
// ToolGuard configures per-tool access control, command safety,
// path protection, SSH allowlist, and audit logging.
ToolGuard ToolGuardConfig `yaml:"tool_guard"`
// ToolExecutor configures parallel tool execution.
ToolExecutor ToolExecutorConfig `yaml:"tool_executor"`
// SSRF configures URL validation for web_fetch (private IPs, metadata, etc.).
SSRF security.SSRFConfig `yaml:"ssrf"`
// ExecAnalysis configures command risk analysis for bash/exec tools.
ExecAnalysis ExecAnalysisConfig `yaml:"exec_analysis"`
}
SecurityConfig configures security guardrails.
type Session ¶
type Session struct {
// ID é o identificador único da sessão (combinação de channel + chatID).
ID string
// Channel identifica o canal de origem (ex: "whatsapp", "discord").
Channel string
// ChatID é o identificador do grupo ou DM.
ChatID string
// CreatedAt é o timestamp de criação da sessão.
CreatedAt time.Time
// contains filtered or unexported fields
}
Session representa uma sessão isolada de conversa para um chat/grupo específico.
func (*Session) AddCompactionSummary ¶ added in v1.13.0
func (s *Session) AddCompactionSummary(entry CompactionEntry)
AddCompactionSummary appends a compaction entry to the session. Thread-safe.
func (*Session) AddFact ¶
AddFact adiciona um fato de longo prazo à sessão. Persiste os fatos em disco se persistence estiver configurada.
func (*Session) AddMessage ¶
AddMessage adiciona uma nova entrada de conversa à sessão. Aplica o limite de maxHistory, removendo mensagens antigas quando excedido. Persiste a entrada em disco se persistence estiver configurada.
func (*Session) AddMessageWithToolCalls ¶ added in v1.13.0
func (s *Session) AddMessageWithToolCalls(userMsg, assistantResp string, toolCalls []ToolCallRecord)
AddMessageWithToolCalls adds a conversation entry with individual tool call records. Falls back to ToolSummary derived from the records for backward compat.
func (*Session) AddMessageWithTools ¶ added in v1.13.0
AddMessageWithTools adds a conversation entry with an optional tool summary.
func (*Session) AddTokenUsage ¶
AddTokenUsage records token usage from an LLM response. Thread-safe.
func (*Session) ClearFacts ¶
func (s *Session) ClearFacts()
ClearFacts removes all session facts. Used by /reset.
func (*Session) ClearHistory ¶
func (s *Session) ClearHistory()
ClearHistory limpa o histórico de conversa mantendo fatos de longo prazo.
func (*Session) CompactHistory ¶
func (s *Session) CompactHistory(summary string, keepRecent int) []ConversationEntry
CompactHistory replaces the full history with a summary entry, keeping only the most recent entries. Returns the old entries for memory extraction.
func (*Session) EstimateHistorySizeBytes ¶ added in v1.13.0
EstimateHistorySizeBytes estimates the total byte size of conversation history. Thread-safe.
func (*Session) GetActiveSkills ¶
GetActiveSkills retorna uma cópia thread-safe das skills ativas.
func (*Session) GetCompactionCount ¶ added in v1.14.0
GetCompactionCount returns the total number of compactions performed.
func (*Session) GetCompactionSummaries ¶ added in v1.13.0
func (s *Session) GetCompactionSummaries() []CompactionEntry
GetCompactionSummaries returns the session's compaction summaries. Thread-safe.
func (*Session) GetConfig ¶
func (s *Session) GetConfig() SessionConfig
GetConfig retorna uma cópia thread-safe da configuração da sessão.
func (*Session) GetFastMode ¶ added in v1.14.0
GetFastMode returns whether fast mode is enabled for this session.
func (*Session) GetLastCallTokens ¶ added in v1.13.0
GetLastCallTokens returns the most recent LLM call's token snapshot. Thread-safe.
func (*Session) GetMaxHistory ¶ added in v1.13.0
GetMaxHistory returns the maximum history size for this session (thread-safe).
func (*Session) GetThinkingLevel ¶
GetThinkingLevel returns the session thinking level. Thread-safe.
func (*Session) GetTokenUsage ¶
GetTokenUsage returns a copy of the token usage. Thread-safe.
func (*Session) HistoryLen ¶
HistoryLen returns the number of entries in the session history.
func (*Session) IncrementCompactionCount ¶ added in v1.14.0
func (s *Session) IncrementCompactionCount()
IncrementCompactionCount atomically increments the compaction counter.
func (*Session) LastActiveAt ¶
LastActiveAt retorna o timestamp da última atividade (thread-safe).
func (*Session) RecentHistory ¶
func (s *Session) RecentHistory(maxEntries int) []ConversationEntry
RecentHistory retorna as últimas N entradas de conversa (cópia thread-safe).
func (*Session) ResetTokenUsage ¶
func (s *Session) ResetTokenUsage()
ResetTokenUsage clears token counters. Thread-safe.
func (*Session) ResetWithPreservation ¶ added in v1.16.0
func (s *Session) ResetWithPreservation()
ResetWithPreservation clears conversation history, compaction state, and token counters while preserving session identity and configuration fields: ThinkingLevel, FastMode, Model, Language, Verbose, ToolProfile, BusinessContext, Trigger, activeSkills, and facts. Also syncs the persistence layer so that the next load does not restore stale data. The lastActiveAt timestamp is bumped to prevent immediate pruning after reset.
func (*Session) SetActiveSkills ¶
SetActiveSkills define as skills ativas da sessão.
func (*Session) SetConfig ¶
func (s *Session) SetConfig(cfg SessionConfig)
SetConfig atualiza a configuração da sessão.
func (*Session) SetMaxHistory ¶ added in v1.13.0
SetMaxHistory adjusts the history limit for this session. This is used to differentiate DM (higher limit) from group (lower limit) sessions.
func (*Session) SetThinkingLevel ¶
SetThinkingLevel sets the session thinking level. Thread-safe.
func (*Session) UpdateLastCallTokens ¶ added in v1.13.0
UpdateLastCallTokens stores the most recent LLM call's token snapshot. Used by proactive memory flush to project next context size. Thread-safe.
type SessionConfig ¶
type SessionConfig struct {
// Trigger é a palavra-chave que ativa o copilot nesta sessão.
Trigger string `yaml:"trigger"`
// Language é o idioma preferido nesta sessão.
Language string `yaml:"language"`
// MaxTokens é o budget máximo de tokens para esta sessão.
MaxTokens int `yaml:"max_tokens"`
// Model é o modelo LLM a ser usado nesta sessão (pode ser diferente do padrão).
Model string `yaml:"model"`
// BusinessContext é o contexto de negócio/usuário para esta sessão.
BusinessContext string `yaml:"business_context"`
// ThinkingLevel controls extended thinking: "", "off", "low", "medium", "high".
ThinkingLevel string `yaml:"thinking_level"`
// Verbose enables narration of tool calls and internal steps.
Verbose bool `yaml:"verbose"`
// ToolProfile selects which tools are available in this session.
// Empty = inherit from workspace/global config. Options: "minimal", "coding",
// "messaging", "team", "full", or a custom profile name.
ToolProfile string `yaml:"tool_profile"`
// FastMode enables faster processing with reduced quality.
// Anthropic: service_tier="auto". OpenAI: service_tier="priority", reasoning_effort="low".
FastMode bool `yaml:"fast_mode"`
}
SessionConfig contém configurações específicas de uma sessão.
type SessionData ¶
type SessionData struct {
ID string
Channel string
ChatID string
History []ConversationEntry
Facts []string
Config SessionConfig
ActiveSkills []string
}
SessionData holds all data needed to restore a session from disk.
type SessionExport ¶
type SessionExport struct {
ID string `json:"id"`
Channel string `json:"channel"`
ChatID string `json:"chat_id"`
Config SessionConfig `json:"config"`
Facts []string `json:"facts"`
CreatedAt time.Time `json:"created_at"`
Messages []ExportedMessage `json:"messages"`
}
SessionExport is a portable representation of a session for backup/export.
type SessionInfo ¶
type SessionInfo struct {
SessionMeta
WorkspaceID string
}
SessionInfo holds session metadata with workspace ID for API responses.
type SessionKey ¶
type SessionKey struct {
Channel string // "whatsapp", "discord", "webui", "subagent", etc.
ChatID string // Group JID, user JID, or chat UUID.
Branch string // Optional: sub-session branch (e.g. "topic-research", fork ID).
}
sessionKey gera a chave única para uma sessão. MakeSessionID generates a deterministic, opaque session ID from channel and chatID. The ID is a truncated SHA-256 hash, so no PII (phone numbers, etc.) leaks into file names, logs, or persisted job data. SessionKey is a structured session identifier that preserves the original channel, chatID, and optional branch components while providing a compact string form. This enables multi-agent routing: sessions can be found by channel, user, or branch without losing context.
func ParseSessionKey ¶
func ParseSessionKey(s string) SessionKey
ParseSessionKey parses a "channel:chatID" or "channel:chatID:branch" string.
func (SessionKey) Hash ¶
func (sk SessionKey) Hash() string
Hash returns a compact hash suitable for map keys and persistence IDs.
func (SessionKey) String ¶
func (sk SessionKey) String() string
String returns the canonical string form: "channel:chatID" or "channel:chatID:branch".
type SessionLock ¶ added in v1.13.0
type SessionLock struct {
// contains filtered or unexported fields
}
SessionLock represents an active cross-process lock on a session.
func AcquireSessionLock ¶ added in v1.13.0
func AcquireSessionLock(sessionsDir, sessionID string, logger *slog.Logger) (*SessionLock, error)
AcquireSessionLock attempts to acquire an advisory file lock for the given session. If the lock is held by another live process, it returns an error. Stale locks (older than sessionLockStaleThreshold) are automatically broken.
func (*SessionLock) Release ¶ added in v1.13.0
func (sl *SessionLock) Release()
Release releases the session lock and stops the watchdog.
type SessionMemoryConfig ¶
type SessionMemoryConfig struct {
// Enabled turns session memory on/off (default: false).
Enabled bool `yaml:"enabled"`
// Messages is the number of recent messages to include in summaries (default: 15).
Messages int `yaml:"messages"`
}
SessionMemoryConfig configures automatic session summarization.
type SessionMeta ¶
type SessionMeta struct {
ID string
Channel string
ChatID string
Title string
MessageCount int
CreatedAt time.Time
LastActiveAt time.Time
}
SessionMeta holds read-only metadata for a session (for listing).
type SessionMetaLister ¶ added in v1.13.0
type SessionMetaLister interface {
ListSessionsMeta() ([]SessionMeta, error)
}
SessionMetaLister is an optional interface that persistence backends can implement to provide a lightweight session listing without loading full history.
type SessionPersistence ¶
type SessionPersistence struct {
// contains filtered or unexported fields
}
SessionPersistence handles saving and loading sessions to JSONL files.
func NewSessionPersistence ¶
func NewSessionPersistence(dir string, logger *slog.Logger) (*SessionPersistence, error)
NewSessionPersistence creates a SessionPersistence and ensures the directory exists.
func (*SessionPersistence) Close ¶
func (p *SessionPersistence) Close() error
Close flushes any buffers. JSONL writes are unbuffered (direct write), so this is a no-op for now.
func (*SessionPersistence) DeleteSession ¶
func (p *SessionPersistence) DeleteSession(sessionID string) error
DeleteSession removes the session's JSONL and facts files.
func (*SessionPersistence) LoadAll ¶
func (p *SessionPersistence) LoadAll() (map[string]*SessionData, error)
LoadAll scans the directory and restores all sessions from disk.
func (*SessionPersistence) LoadSession ¶
func (p *SessionPersistence) LoadSession(sessionID string) ([]ConversationEntry, []string, error)
LoadSession reads all entries and facts for a session.
func (*SessionPersistence) Rotate ¶
func (p *SessionPersistence) Rotate(sessionID string, maxLines int) error
Rotate creates a .bak of the JSONL file and starts fresh.
func (*SessionPersistence) SaveCompaction ¶ added in v1.12.0
func (p *SessionPersistence) SaveCompaction(sessionID string, entry CompactionEntry) error
SaveCompaction appends a compaction summary entry to the session file.
func (*SessionPersistence) SaveEntry ¶
func (p *SessionPersistence) SaveEntry(sessionID string, entry ConversationEntry) error
SaveEntry appends one JSONL line for the given conversation entry.
func (*SessionPersistence) SaveFacts ¶
func (p *SessionPersistence) SaveFacts(sessionID string, facts []string) error
SaveFacts writes facts to {session_id}.facts.json.
func (*SessionPersistence) SaveMeta ¶
func (p *SessionPersistence) SaveMeta(sessionID, channel, chatID string, config SessionConfig, activeSkills []string) error
SaveMeta persists session metadata (channel, chatID, config, activeSkills).
func (*SessionPersistence) TruncateAfterCompaction ¶ added in v1.16.0
func (p *SessionPersistence) TruncateAfterCompaction(sessionID string, keepRecentEntries int) error
TruncateAfterCompaction rewrites the JSONL file keeping only the last compaction entry and the most recent conversation entries written after it. This prevents unbounded JSONL growth on long-lived sessions.
type SessionPersister ¶
type SessionPersister interface {
SaveEntry(sessionID string, entry ConversationEntry) error
LoadSession(sessionID string) ([]ConversationEntry, []string, error)
SaveFacts(sessionID string, facts []string) error
SaveMeta(sessionID, channel, chatID string, config SessionConfig, activeSkills []string) error
SaveCompaction(sessionID string, entry CompactionEntry) error
TruncateAfterCompaction(sessionID string, keepRecentEntries int) error
DeleteSession(sessionID string) error
Rotate(sessionID string, maxLines int) error
LoadAll() (map[string]*SessionData, error)
Close() error
}
SessionPersister is the interface for session persistence backends (JSONL or SQLite).
type SessionReaperConfig ¶ added in v1.13.0
type SessionReaperConfig struct {
Enabled bool `yaml:"enabled" json:"enabled"`
MaxAgeDays int `yaml:"max_age_days" json:"max_age_days"`
}
SessionReaperConfig configures the session reaper.
type SessionStats ¶
type SessionStats struct {
Active int `json:"active"`
Total int `json:"total"`
WithHistory int `json:"with_history"`
}
SessionStats holds session-related statistics.
type SessionStore ¶
type SessionStore struct {
// contains filtered or unexported fields
}
SessionStore gerencia sessões ativas, criando e recuperando por canal e chatID. Implementa pruning automático de sessões inativas.
func NewSessionStore ¶
func NewSessionStore(logger *slog.Logger) *SessionStore
NewSessionStore cria um novo store de sessões.
func (*SessionStore) Count ¶
func (ss *SessionStore) Count() int
Count retorna o número de sessões ativas.
func (*SessionStore) Delete ¶
func (ss *SessionStore) Delete(channel, chatID string) bool
Delete removes a session by channel and chatID.
func (*SessionStore) DeleteByID ¶
func (ss *SessionStore) DeleteByID(id string) bool
DeleteByID removes a session by its hash ID. It removes from both in-memory store and persistence (even if only persisted).
func (*SessionStore) Export ¶
func (ss *SessionStore) Export(id string) *SessionExport
Export returns a portable representation of a session's history and metadata.
func (*SessionStore) Get ¶
func (ss *SessionStore) Get(channel, chatID string) *Session
Get retorna a sessão pelo canal e chatID, ou nil se não existir.
func (*SessionStore) GetByID ¶
func (ss *SessionStore) GetByID(id string) *Session
GetByID returns a session by its raw store key. Returns nil if not found.
func (*SessionStore) GetOrCreate ¶
func (ss *SessionStore) GetOrCreate(channel, chatID string) *Session
GetOrCreate retorna a sessão existente ou cria uma nova para o canal e chatID. Se persistence estiver configurada, tenta carregar do disco antes de criar.
func (*SessionStore) ListAllSessions ¶ added in v1.13.0
func (ss *SessionStore) ListAllSessions() []SessionMeta
ListAllSessions returns metadata for all sessions, merging in-memory sessions with persisted sessions from the database. This ensures sessions survive server restarts.
func (*SessionStore) ListSessions ¶
func (ss *SessionStore) ListSessions() []SessionMeta
ListSessions returns metadata for all sessions in the store.
func (*SessionStore) Prune ¶
func (ss *SessionStore) Prune() int
Prune remove sessões inativas há mais tempo que o TTL configurado. Deve ser chamado periodicamente (ex: via goroutine com ticker).
func (*SessionStore) RenameSession ¶
func (ss *SessionStore) RenameSession(oldID, newChannel, newChatID string) bool
RenameSession changes the ChatID of a session (e.g. for aliasing).
func (*SessionStore) SetPersistence ¶
func (ss *SessionStore) SetPersistence(p SessionPersister)
SetPersistence configures disk persistence for sessions.
func (*SessionStore) StartPruner ¶
func (ss *SessionStore) StartPruner(ctx context.Context)
StartPruner inicia uma goroutine que executa Prune periodicamente. Para quando o contexto é cancelado.
type SessionUsage ¶
type SessionUsage struct {
PromptTokens int64
CompletionTokens int64
TotalTokens int64
Requests int64
EstimatedCostUSD float64
FirstRequestAt time.Time
LastRequestAt time.Time
}
SessionUsage holds token and cost stats for a session.
type Settings ¶ added in v1.12.0
type Settings struct {
// ToolProfiles contains custom tool profiles defined by the user.
// Built-in profiles (minimal, coding, messaging, team, full) are always available.
ToolProfiles map[string]ToolProfile `yaml:"tool_profiles"`
}
Settings holds application-wide settings loaded from settings.yaml.
type SettingsManager ¶ added in v1.12.0
type SettingsManager struct {
// contains filtered or unexported fields
}
SettingsManager manages loading and saving of settings.
func NewSettingsManager ¶ added in v1.12.0
func NewSettingsManager() *SettingsManager
NewSettingsManager creates a new settings manager.
func (*SettingsManager) AddProfile ¶ added in v1.12.0
func (sm *SettingsManager) AddProfile(profile ToolProfile) error
AddProfile adds or updates a custom profile.
func (*SettingsManager) DeleteProfile ¶ added in v1.12.0
func (sm *SettingsManager) DeleteProfile(name string) error
DeleteProfile removes a custom profile. Returns error if trying to delete a built-in profile.
func (*SettingsManager) GetAllProfiles ¶ added in v1.12.0
func (sm *SettingsManager) GetAllProfiles() map[string]ToolProfile
GetAllProfiles returns built-in + custom profiles merged.
func (*SettingsManager) GetSettingsPath ¶ added in v1.12.0
func (sm *SettingsManager) GetSettingsPath() string
GetSettingsPath returns the path to the settings file.
func (*SettingsManager) ListProfilesInfo ¶ added in v1.12.0
func (sm *SettingsManager) ListProfilesInfo() []ToolProfileInfo
ListProfilesInfo returns all profiles with info about built-in status.
func (*SettingsManager) Load ¶ added in v1.12.0
func (sm *SettingsManager) Load() (*Settings, error)
Load reads settings from the YAML file.
func (*SettingsManager) Save ¶ added in v1.12.0
func (sm *SettingsManager) Save(settings *Settings) error
Save writes settings to the YAML file.
func (*SettingsManager) UpdateProfile ¶ added in v1.12.0
func (sm *SettingsManager) UpdateProfile(profile ToolProfile) error
UpdateProfile updates an existing custom profile.
type SharedMemory ¶
type SharedMemory struct {
}
SharedMemory represents a team-shared memory space.
type SkillDB ¶ added in v1.12.0
type SkillDB struct {
// contains filtered or unexported fields
}
SkillDB manages the skill database, allowing skills to create tables and perform CRUD operations on their data.
func OpenSkillDatabase ¶ added in v1.12.0
OpenSkillDatabase opens (or creates) the skill database at dataDir/skill_database.db.
func (*SkillDB) CreateTable ¶ added in v1.12.0
func (s *SkillDB) CreateTable(skillName, tableName, displayName, description string, columns map[string]string) error
CreateTable creates a new table for a skill with the specified columns. Columns is a map of column name to SQL type definition (e.g., "TEXT NOT NULL"). Automatic columns: id (TEXT PRIMARY KEY), created_at, updated_at.
func (*SkillDB) DescribeTable ¶ added in v1.12.0
DescribeTable returns detailed information about a table.
func (*SkillDB) GetReminderByJobID ¶ added in v1.12.0
func (s *SkillDB) GetReminderByJobID(jobID string) (*ReminderInfo, error)
GetReminderByJobID gets a reminder by its job ID.
func (*SkillDB) InitRemindersTable ¶ added in v1.12.0
InitRemindersTable creates the reminders tracking table if it doesn't exist.
func (*SkillDB) Insert ¶ added in v1.12.0
Insert inserts a new row into a skill's table and returns the generated ID.
func (*SkillDB) ListTables ¶ added in v1.12.0
ListTables returns all tables for a skill. If skillName is empty, returns all tables from all skills.
func (*SkillDB) MarkReminderRemoved ¶ added in v1.12.0
MarkReminderRemoved marks a reminder as removed (soft delete).
func (*SkillDB) Query ¶ added in v1.12.0
func (s *SkillDB) Query(skillName, tableName string, filters map[string]any, limit int) ([]map[string]any, error)
Query retrieves rows from a skill's table with optional filters and pagination.
func (*SkillDB) QueryWithOptions ¶ added in v1.12.0
func (s *SkillDB) QueryWithOptions(skillName, tableName string, opts QueryOptions) ([]map[string]any, error)
QueryWithOptions retrieves rows with full query options including pagination and ordering.
func (*SkillDB) SaveReminder ¶ added in v1.12.0
SaveReminder saves a reminder to the tracking table. If a reminder with the same job_id exists and is active, it updates it. If it exists but was removed, it creates a new entry.
func (*SkillDB) SearchReminders ¶ added in v1.12.0
func (s *SkillDB) SearchReminders(query string, includeRemoved bool, limit int) ([]ReminderInfo, error)
SearchReminders searches for reminders matching the query. If query is empty, returns all reminders. If includeRemoved is false, only returns active reminders.
type SkillInfo ¶ added in v1.12.0
type SkillInfo struct {
Name string
Description string
Location string // Absolute path to SKILL.md ("" for built-in skills)
HasReferences bool // True if the skill has a references/ directory
Tools []string
}
SkillInfo holds basic skill information for the Skill Discovery XML. Used by the reference model: skills listed as XML references, LLM reads SKILL.md on demand.
type SkillReloadCallback ¶ added in v1.13.0
SkillReloadCallback reloads skills from disk, initializes them with the sandbox runner, and re-registers their tools. Returns the total number of skills loaded.
type SkillWatcher ¶ added in v1.13.0
type SkillWatcher struct {
// contains filtered or unexported fields
}
SkillWatcher watches skill directories for SKILL.md changes and increments the PromptComposer's skills version on change.
func NewSkillWatcher ¶ added in v1.13.0
func NewSkillWatcher(dirs []string, composer *PromptComposer, logger *slog.Logger) (*SkillWatcher, error)
NewSkillWatcher creates a watcher on the given skill directories. Only reacts to SKILL.md file events (create, write, remove).
func (*SkillWatcher) Stop ¶ added in v1.13.0
func (sw *SkillWatcher) Stop()
Stop shuts down the watcher.
type SkillsConfig ¶
type SkillsConfig struct {
// Builtin lists built-in skills to enable.
Builtin []string `yaml:"builtin"`
// Installed lists installed skill names.
Installed []string `yaml:"installed"`
// ClawdHubDirs lists directories with ClawdHub SKILL.md skills (TierManaged).
ClawdHubDirs []string `yaml:"clawdhub_dirs"`
// PersonalDir is an optional user-global skills directory (TierPersonal).
// No default — only activated when explicitly set in config.
PersonalDir string `yaml:"personal_dir"`
// ProjectDir is an optional project-scoped skills directory (TierProject).
// No default — only activated when explicitly set in config.
ProjectDir string `yaml:"project_dir"`
// Limits configures resource limits for skill loading.
Limits skills.SkillsLimitsConfig `yaml:"limits"`
}
SkillsConfig configures the skills system.
type SnapshotOptions ¶ added in v1.13.0
type SnapshotOptions struct {
// InteractiveOnly only includes interactive elements (buttons, links, inputs, etc.).
InteractiveOnly bool
// Compact removes structural noise (generic containers without names).
Compact bool
// MaxDepth limits the tree depth (0 = unlimited).
MaxDepth int
}
SnapshotOptions configures the snapshot behavior.
type SnapshotResult ¶ added in v1.13.0
type SnapshotResult struct {
// Snapshot is the text representation of the accessibility tree.
Snapshot string `json:"snapshot"`
// Refs maps reference IDs (e1, e2, ...) to their element info.
Refs map[string]Ref `json:"refs"`
// Stats contains statistics about the snapshot.
Stats SnapshotStats `json:"stats"`
}
SnapshotResult is the result of a browser snapshot operation.
func (*SnapshotResult) SortedRefs ¶ added in v1.13.0
func (s *SnapshotResult) SortedRefs() []string
SortedRefs returns refs sorted by their numeric ID.
type SnapshotStats ¶ added in v1.13.0
type SnapshotStats struct {
Lines int `json:"lines"`
Chars int `json:"chars"`
Refs int `json:"refs"`
Interactive int `json:"interactive"`
}
SnapshotStats contains statistics about a snapshot.
type SpawnParams ¶
type SpawnParams struct {
Task string
Label string
Model string
ParentSessionID string
TimeoutSeconds int
// SpawnDepth is the nesting level (1 = top-level subagent).
// If not set, defaults to 1.
SpawnDepth int
// OriginChannel, OriginTo, and OriginThreadID identify where to push the
// completion announcement. When OriginChannel is set the announce callback
// delivers the result directly to that channel/chat in addition to injecting
// it into the parent agent loop.
OriginChannel string
OriginTo string
OriginThreadID string
// DeliveryScope controls announcement delivery. Default: "all".
DeliveryScope DeliveryScope
// MaxTurns overrides the agent loop turn limit for this spawn.
MaxTurns int
// EscalationChecker is called after each turn to check if the agent
// should escalate to the main agent. Used by plugin agents.
EscalationChecker func(turn int, lastResponse string) *EscalationSignal
}
SpawnParams holds parameters for spawning a subagent.
type StackConfig ¶ added in v1.18.0
type StackConfig struct {
// TotalBudget caps the combined byte length of L0+L1+L2. A value
// <= 0 uses defaultStackBudget (3600 bytes ≈ 900 tokens).
TotalBudget int
// ForceLegacy, when true, makes Build() short-circuit to "". The
// caller then falls back to the legacy buildMemoryLayer output.
// This is the escape hatch for v1.18.0 byte-identical behavior
// under the stack — exposed in Room 2.5 via memory.stack.force_legacy.
ForceLegacy bool
}
StackConfig is the subset of HierarchyConfig the stack consumes. A zero-valued StackConfig uses defaults (see DefaultStackConfig).
func DefaultStackConfig ¶ added in v1.18.0
func DefaultStackConfig() StackConfig
DefaultStackConfig returns the sensible defaults: 3600-byte total budget, stack-active (not forced to legacy).
type StackStats ¶ added in v1.18.0
type StackStats struct {
// L0Bytes is the cumulative byte count contributed by the identity
// layer across all Build calls.
L0Bytes int64
// L1Bytes is the cumulative byte count contributed by the essential
// layer across all Build calls (after any truncation).
L1Bytes int64
// L2Bytes is the cumulative byte count contributed by the on-demand
// layer across all Build calls (after any truncation).
L2Bytes int64
// TrimmedTotal counts Build calls where at least one layer was
// truncated to fit the byte budget.
TrimmedTotal int64
// PanicTotal counts individual layer panics caught by the stack.
// A single Build call can contribute up to three panics (one per
// layer), though in practice a single bug rarely affects more than
// one layer at a time.
PanicTotal int64
// BuildTotal counts Build calls that proceeded past the early-exit
// checks (ForceLegacy, all-nil, context cancellation).
BuildTotal int64
}
StackStats is a point-in-time snapshot of the MemoryStack telemetry counters. Returned by (*MemoryStack).Stats.
type StartupCheckResult ¶
type StartupCheckResult struct {
Name string // Check name (e.g., "vault", "database", "channels")
Status string // "ok", "warning", "error", "skipped"
Message string // Human-readable message
Required bool // If true, failure blocks startup
}
StartupCheckResult represents the result of a single startup check.
type StartupReport ¶
type StartupReport struct {
Results []StartupCheckResult
Healthy bool // true if all required checks pass
}
StartupReport contains all startup check results.
type StartupVerifier ¶
type StartupVerifier struct {
// contains filtered or unexported fields
}
StartupVerifier performs system checks at initialization.
func NewStartupVerifier ¶
func NewStartupVerifier(cfg *Config, vault *Vault, logger *slog.Logger) *StartupVerifier
NewStartupVerifier creates a new startup verifier.
func (*StartupVerifier) PrintReport ¶
func (sv *StartupVerifier) PrintReport(report *StartupReport)
PrintReport logs a formatted startup report.
func (*StartupVerifier) RunAll ¶
func (sv *StartupVerifier) RunAll() *StartupReport
RunAll executes all startup checks and returns a report.
type StopCheckPhase ¶ added in v1.17.0
type StopCheckPhase struct {
// contains filtered or unexported fields
}
StopCheckPhase runs completion verification before allowing stop.
func NewStopCheckPhase ¶ added in v1.17.0
func NewStopCheckPhase(v *StopHookVerifier) *StopCheckPhase
NewStopCheckPhase creates a stop check phase with the given verifier. Limits injection to 3 attempts to prevent infinite loops.
func (*StopCheckPhase) Execute ¶ added in v1.17.0
func (s *StopCheckPhase) Execute(ctx context.Context, state *TurnState) (NextAction, error)
func (*StopCheckPhase) Name ¶ added in v1.17.0
func (s *StopCheckPhase) Name() string
type StopHookVerifier ¶ added in v1.17.0
type StopHookVerifier struct {
// contains filtered or unexported fields
}
StopHookVerifier checks conversation history for incomplete work.
func NewStopHookVerifier ¶ added in v1.17.0
func NewStopHookVerifier() *StopHookVerifier
NewStopHookVerifier creates a verifier with default completion checks.
func (*StopHookVerifier) VerifyCompletion ¶ added in v1.17.0
func (v *StopHookVerifier) VerifyCompletion(messages []chatMessage) []IncompleteWork
VerifyCompletion analyzes the conversation for incomplete work patterns. Returns a list of incomplete work items, empty if everything looks complete.
The analysis works by scanning assistant and tool messages for trigger patterns (indicating work was done) and then checking if completion patterns also appear (indicating the work was verified). Only the most recent portion of the conversation is checked to avoid false positives from old, already-resolved work.
type StreamCallback ¶
type StreamCallback func(chunk string)
StreamCallback is called for each token/chunk during streaming.
type StreamSanitizer ¶ added in v1.13.0
type StreamSanitizer struct {
// contains filtered or unexported fields
}
StreamSanitizer wraps a StreamCallback to prevent partial silent tokens from leaking into user-visible output. It buffers short prefixes that could be the beginning of a silent token and flushes them when safe.
func NewStreamSanitizer ¶ added in v1.13.0
func NewStreamSanitizer(cb StreamCallback) *StreamSanitizer
NewStreamSanitizer wraps a StreamCallback with token buffering.
func (*StreamSanitizer) Callback ¶ added in v1.13.0
func (s *StreamSanitizer) Callback() StreamCallback
Callback returns the StreamCallback function to use in place of the inner callback.
func (*StreamSanitizer) Flush ¶ added in v1.13.0
func (s *StreamSanitizer) Flush()
Flush sends any remaining buffered content to the inner callback. Must be called when the stream ends.
func (*StreamSanitizer) Write ¶ added in v1.13.0
func (s *StreamSanitizer) Write(chunk string)
Write is the StreamCallback-compatible function that buffers and filters.
type SubagentConfig ¶
type SubagentConfig struct {
// Enabled turns the subagent system on/off (default: true).
Enabled bool `yaml:"enabled"`
// MaxConcurrent is the max number of subagents running at the same time.
MaxConcurrent int `yaml:"max_concurrent"`
// MaxTurns is the max agent loop turns for each subagent (default: 15).
MaxTurns int `yaml:"max_turns"`
// TimeoutSeconds is the max execution time per subagent (default: 900 = 15min).
TimeoutSeconds int `yaml:"timeout_seconds"`
// MaxSpawnDepth controls nested subagent spawning (default: 1 = no nesting).
// Set to 2 to allow subagents to spawn their own children.
// Higher values allow deeper nesting (e.g., 3 = sub-sub-subagents).
MaxSpawnDepth int `yaml:"max_spawn_depth"`
// MaxChildrenPerAgent limits how many children a single agent can spawn (default: 5).
MaxChildrenPerAgent int `yaml:"max_children_per_agent"`
// DeniedTools lists tool names that subagents cannot use.
// Default: ["spawn_subagent", "list_subagents", "wait_subagent"]
DeniedTools []string `yaml:"denied_tools"`
// Model overrides the LLM model for subagents (empty = use parent model).
Model string `yaml:"model"`
}
SubagentConfig configures the subagent system.
func DefaultSubagentConfig ¶
func DefaultSubagentConfig() SubagentConfig
DefaultSubagentConfig returns safe defaults.
type SubagentManager ¶
type SubagentManager struct {
// contains filtered or unexported fields
}
SubagentManager orchestrates subagent lifecycle: spawning, tracking, and cleanup.
func NewSubagentManager ¶
func NewSubagentManager(cfg SubagentConfig, logger *slog.Logger) *SubagentManager
NewSubagentManager creates a new subagent manager.
func (*SubagentManager) ActiveCount ¶
func (m *SubagentManager) ActiveCount() int
ActiveCount returns the number of currently running subagents.
func (*SubagentManager) Cleanup ¶
func (m *SubagentManager) Cleanup(maxAge time.Duration) int
Cleanup removes completed/failed runs older than the given duration.
func (*SubagentManager) CreateChildExecutorWithProfile ¶ added in v1.16.0
func (m *SubagentManager) CreateChildExecutorWithProfile(parent *ToolExecutor, depth int, allow, deny []string) *ToolExecutor
createChildExecutorWithProfile creates a child ToolExecutor with allow/deny filtering from a plugin agent's tool profile.
func (*SubagentManager) Get ¶
func (m *SubagentManager) Get(runID string) (*SubagentRun, bool)
Get returns a subagent run by ID. Checks in-memory first, then SQLite.
func (*SubagentManager) List ¶
func (m *SubagentManager) List() []*SubagentRun
List returns all subagent runs (active in-memory + recent from SQLite). Merges both sources, deduplicating by ID.
func (*SubagentManager) PruneOldRuns ¶
func (m *SubagentManager) PruneOldRuns(days int) int
PruneOldRuns removes persisted runs older than the given number of days.
func (*SubagentManager) SetAnnounceCallback ¶
func (m *SubagentManager) SetAnnounceCallback(cb AnnounceCallback)
SetAnnounceCallback registers a callback that fires when any subagent completes. This enables push-style announce: the parent is notified immediately instead of having to poll via wait_subagent.
func (*SubagentManager) SetDB ¶
func (m *SubagentManager) SetDB(db *sql.DB)
SetDB wires the central SQLite database for persisting subagent runs. When set, completed/failed runs survive process restarts.
func (*SubagentManager) Spawn ¶
func (m *SubagentManager) Spawn( parentCtx context.Context, params SpawnParams, llmClient *LLMClient, parentExecutor *ToolExecutor, promptComposer *PromptComposer, ) (*SubagentRun, error)
Spawn creates and starts a new subagent. Returns the run ID immediately. The subagent executes in a background goroutine.
func (*SubagentManager) SpawnWithExecutor ¶ added in v1.16.0
func (m *SubagentManager) SpawnWithExecutor( parentCtx context.Context, params SpawnParams, llmClient *LLMClient, childExecutor *ToolExecutor, customPrompt string, ) (*SubagentRun, error)
SpawnWithExecutor is a variant of Spawn that accepts a pre-built executor and custom system prompt. Used by the plugin system to spawn plugin agents with filtered tools and custom instructions.
func (*SubagentManager) StartPeriodicSweeper ¶ added in v1.13.0
func (m *SubagentManager) StartPeriodicSweeper(ctx context.Context, interval time.Duration, maxAgeDays int)
StartPeriodicSweeper launches a background goroutine that prunes old subagent runs every interval. Stops when ctx is cancelled.
func (*SubagentManager) Stop ¶
func (m *SubagentManager) Stop(runID string) error
Stop cancels a running subagent.
func (*SubagentManager) Wait ¶
func (m *SubagentManager) Wait(ctx context.Context, runID string) (*SubagentRun, error)
Wait blocks until the specified subagent run completes or the context is cancelled. Returns the final run state.
type SubagentRun ¶
type SubagentRun struct {
// ID is a unique identifier for this run.
ID string `json:"id"`
// Label is a human-readable label for identification.
Label string `json:"label"`
// Task is the original task description given to the subagent.
Task string `json:"task"`
// Status is the current execution status.
Status SubagentStatus `json:"status"`
// Result is the final text response (set on completion).
Result string `json:"result,omitempty"`
// Error holds the error message if the subagent failed.
Error string `json:"error,omitempty"`
// Model is the LLM model used for this run.
Model string `json:"model,omitempty"`
// ParentSessionID is the session that spawned this subagent.
ParentSessionID string `json:"parent_session_id"`
// SpawnDepth is the nesting level (1 = top-level subagent, 2 = child of subagent, etc.).
SpawnDepth int `json:"spawn_depth"`
// ChildrenCount tracks how many children this subagent has spawned.
ChildrenCount int `json:"children_count,omitempty"`
// OriginChannel is the channel name (e.g. "telegram", "discord") where the
// spawn was requested. When set, the completion announcement is delivered
// directly to that channel/chat rather than only injecting into the agent loop.
OriginChannel string `json:"origin_channel,omitempty"`
// OriginTo is the chat ID / recipient address in the origin channel.
// For Telegram this may include a topic suffix (e.g. "12345678:topic:42").
OriginTo string `json:"origin_to,omitempty"`
// OriginThreadID is an optional thread or topic ID for threaded delivery
// within the origin channel (e.g. a Slack thread_ts or Telegram topic ID).
// TODO: populate from IncomingMessage.Metadata once per-message thread context
// is propagated through the tool execution context.
OriginThreadID string `json:"origin_thread_id,omitempty"`
// StartedAt is when the subagent started.
StartedAt time.Time `json:"started_at"`
// CompletedAt is when the subagent finished (zero if still running).
CompletedAt time.Time `json:"completed_at,omitempty"`
// Duration is the wall-clock execution time.
Duration time.Duration `json:"duration,omitempty"`
// TokensUsed tracks approximate token usage.
TokensUsed int `json:"tokens_used,omitempty"`
// DeliveryScope controls who receives the completion announcement.
// Default: "all" (parent + external). Internal subagents use "parent".
DeliveryScope DeliveryScope `json:"delivery_scope,omitempty"`
// RetryCount tracks how many times this run has been retried after interruption.
RetryCount int `json:"retry_count,omitempty"`
// contains filtered or unexported fields
}
SubagentRun tracks a single subagent execution.
func (*SubagentRun) Done ¶ added in v1.13.0
func (r *SubagentRun) Done() <-chan struct{}
Done returns a channel that is closed when the subagent run completes. For DB-loaded runs with nil done, returns a pre-closed channel.
type SubagentStatus ¶
type SubagentStatus string
SubagentStatus represents the current state of a subagent run.
const ( SubagentStatusRunning SubagentStatus = "running" SubagentStatusCompleted SubagentStatus = "completed" SubagentStatusFailed SubagentStatus = "failed" SubagentStatusTimeout SubagentStatus = "timeout" )
type SystemCommands ¶
type SystemCommands struct {
// contains filtered or unexported fields
}
SystemCommands holds system administration command handlers.
func NewSystemCommands ¶
func NewSystemCommands(a *Assistant, configPath string, maintenanceMgr *MaintenanceManager) *SystemCommands
NewSystemCommands creates a new system command handler.
func (*SystemCommands) ChannelsCommand ¶
func (t *SystemCommands) ChannelsCommand(args []string) string
ChannelsCommand handles /channels [connect|disconnect <name>]
func (*SystemCommands) DiagnosticsCommand ¶
func (t *SystemCommands) DiagnosticsCommand(full bool) string
DiagnosticsCommand handles /diagnostics [--full]
func (*SystemCommands) ExecQueueCommand ¶
func (t *SystemCommands) ExecQueueCommand() string
ExecQueueCommand handles /exec queue
func (*SystemCommands) HealthCommand ¶
func (t *SystemCommands) HealthCommand() string
HealthCommand handles /health
func (*SystemCommands) LogsCommand ¶
func (t *SystemCommands) LogsCommand(args []string) string
LogsCommand handles /logs [level] [lines]
func (*SystemCommands) MaintenanceCommand ¶
func (t *SystemCommands) MaintenanceCommand(args []string, setBy string) string
MaintenanceCommand handles /maintenance [on|off] [message]
func (*SystemCommands) MetricsCommand ¶
func (t *SystemCommands) MetricsCommand(args []string) string
MetricsCommand handles /metrics [period]
func (*SystemCommands) ReloadCommand ¶
func (t *SystemCommands) ReloadCommand(args []string) string
ReloadCommand handles /reload [section]
func (*SystemCommands) StatusCommand ¶
func (t *SystemCommands) StatusCommand(jsonOutput bool) string
StatusCommand handles /status [--json]
type SystemStatus ¶
type SystemStatus struct {
Version string `json:"version"`
Uptime string `json:"uptime"`
UptimeSeconds int64 `json:"uptime_seconds"`
MemoryMB float64 `json:"memory_mb"`
GoRoutines int `json:"goroutines"`
Channels map[string]ChannelHealth `json:"channels"`
Sessions SessionStats `json:"sessions"`
Scheduler SchedulerStats `json:"scheduler"`
Skills int `json:"skills"`
Maintenance *MaintenanceMode `json:"maintenance,omitempty"`
}
SystemStatus represents comprehensive system status for TechOps commands.
type TLSConfig ¶ added in v1.16.0
type TLSConfig struct {
// Enabled turns TLS on/off (default: false).
Enabled bool `yaml:"enabled"`
// AutoGenerate auto-generates self-signed certificates if they don't exist (default: true).
AutoGenerate bool `yaml:"auto_generate"`
// CertPath is the path to the TLS certificate PEM file (default: data/tls/devclaw-cert.pem).
CertPath string `yaml:"cert_path"`
// KeyPath is the path to the TLS private key PEM file (default: data/tls/devclaw-key.pem).
KeyPath string `yaml:"key_path"`
}
TLSConfig configures TLS/HTTPS for servers (WebUI, Gateway).
type TTSConfig ¶
type TTSConfig struct {
// Enabled activates TTS for assistant responses.
Enabled bool `yaml:"enabled"`
// Provider is the TTS provider to use: "openai" (default), "edge", "auto".
// "auto" tries OpenAI first, falls back to Edge TTS if OpenAI is unavailable.
Provider string `yaml:"provider"`
// Voice is the voice to use.
// OpenAI: alloy, echo, fable, onyx, nova, shimmer
// Edge: pt-BR-FranciscaNeural, en-US-JennyNeural, etc.
Voice string `yaml:"voice"`
// EdgeVoice is the voice to use specifically for Edge TTS (when provider is "auto").
// If empty, falls back to Voice.
EdgeVoice string `yaml:"edge_voice"`
// Model is the TTS model: "tts-1" (fast) or "tts-1-hd" (high quality).
// Only used for OpenAI provider.
Model string `yaml:"model"`
// AutoMode controls when TTS is used:
// "off" - disabled (default)
// "always" - always generate audio alongside text
// "inbound" - generate audio only when the user sent a voice note
AutoMode string `yaml:"auto_mode"`
}
TTSConfig configures text-to-speech synthesis.
type Tab ¶ added in v1.13.0
type Tab struct {
TargetID string `json:"targetId"`
URL string `json:"url"`
Title string `json:"title"`
Type string `json:"type"`
}
Tab represents a browser tab.
type TableInfo ¶ added in v1.12.0
type TableInfo struct {
SkillName string `json:"skill_name"`
TableName string `json:"table_name"`
DisplayName string `json:"display_name,omitempty"`
Description string `json:"description,omitempty"`
Schema map[string]string `json:"schema,omitempty"`
RowCount int `json:"row_count"`
CreatedAt string `json:"created_at"`
UpdatedAt string `json:"updated_at"`
}
TableInfo contains metadata about a skill's table.
type TailscaleConfig ¶
type TailscaleConfig struct {
// Enabled turns Tailscale integration on/off.
Enabled bool `yaml:"enabled"`
// Serve enables Tailscale Serve (accessible within your Tailnet).
Serve bool `yaml:"serve"`
// Funnel enables Tailscale Funnel (accessible from the public internet).
// Requires Tailscale Funnel to be enabled in your Tailscale admin console.
Funnel bool `yaml:"funnel"`
// Port is the local port to proxy (default: 8085).
Port int `yaml:"port"`
// Hostname is the Tailscale hostname to use (empty = auto from `tailscale status`).
Hostname string `yaml:"hostname"`
}
TailscaleConfig configures Tailscale Serve/Funnel integration.
type TailscaleManager ¶
type TailscaleManager struct {
// contains filtered or unexported fields
}
TailscaleManager manages Tailscale Serve/Funnel lifecycle.
func NewTailscaleManager ¶
func NewTailscaleManager(cfg TailscaleConfig, logger *slog.Logger) *TailscaleManager
NewTailscaleManager creates a new Tailscale manager.
func (*TailscaleManager) Start ¶
func (tm *TailscaleManager) Start(ctx context.Context) error
Start sets up Tailscale Serve and/or Funnel based on config.
func (*TailscaleManager) Status ¶
func (tm *TailscaleManager) Status() map[string]any
Status returns the current Tailscale integration status.
func (*TailscaleManager) Stop ¶
func (tm *TailscaleManager) Stop()
Stop tears down Tailscale Serve/Funnel.
func (*TailscaleManager) URL ¶
func (tm *TailscaleManager) URL() string
URL returns the public-facing URL if available, or empty string.
type TeamUser ¶
type TeamUser struct {
ID string `json:"id"`
Name string `json:"name"`
Email string `json:"email,omitempty"`
Role UserRole `json:"role"`
CreatedAt time.Time `json:"created_at"`
LastSeen time.Time `json:"last_seen"`
Active bool `json:"active"`
}
TeamUser represents a user in the multi-user system.
type TemporalDecayConfig ¶ added in v1.12.0
type TemporalDecayConfig struct {
// Enabled activates temporal decay (default: false).
Enabled bool `yaml:"enabled"`
// HalfLifeDays is the number of days for score to halve (default: 30).
HalfLifeDays float64 `yaml:"half_life_days"`
}
TemporalDecayConfig configures exponential score decay based on memory age.
type TokenBudgetConfig ¶
type TokenBudgetConfig struct {
Total int `yaml:"total"`
Reserved int `yaml:"reserved"`
System int `yaml:"system"`
Skills int `yaml:"skills"`
Memory int `yaml:"memory"`
History int `yaml:"history"`
Tools int `yaml:"tools"`
// BootstrapMaxChars is the max total characters for all bootstrap files
// combined (SOUL.md, IDENTITY.md, etc.). Default: 20000 (~5K tokens).
BootstrapMaxChars int `yaml:"bootstrap_max_chars"`
}
TokenBudgetConfig configures per-layer token allocation.
type TokenOptions ¶
type TokenOptions struct {
Role TokenRole
MaxUses int // 0 = unlimited
ExpiresIn time.Duration // 0 = never expires
AutoApprove bool
WorkspaceID string
Note string
}
TokenOptions configures token generation.
type TokenRole ¶
type TokenRole string
TokenRole defines the access level granted by a pairing token.
type ToolCall ¶
type ToolCall struct {
ID string `json:"id"`
Type string `json:"type"`
Function FunctionCall `json:"function"`
}
ToolCall represents a tool invocation requested by the LLM.
type ToolCallIDMode ¶ added in v1.13.0
type ToolCallIDMode int
ToolCallIDMode determines the sanitization rules for tool call IDs.
const ( // ToolCallIDStrict keeps only [a-zA-Z0-9], max 40 chars. // Used for OpenAI, Anthropic, OpenRouter, and most providers. ToolCallIDStrict ToolCallIDMode = iota // ToolCallIDStrict9 keeps only [a-zA-Z0-9], exactly 9 chars. // Used for Mistral which requires short fixed-length IDs. ToolCallIDStrict9 )
func ProviderToolCallIDMode ¶ added in v1.13.0
func ProviderToolCallIDMode(provider string) ToolCallIDMode
ProviderToolCallIDMode returns the appropriate sanitization mode for a provider.
type ToolCallRecord ¶ added in v1.13.0
type ToolCallRecord struct {
ID string `json:"id,omitempty"`
Name string `json:"name"`
Args string `json:"args,omitempty"` // truncated to 200 chars
Result string `json:"result,omitempty"` // truncated to 500 chars
}
ToolCallRecord stores a single tool invocation for session history fidelity. Truncated args/result keep storage bounded while preserving context.
type ToolCheckResult ¶
type ToolCheckResult struct {
Allowed bool
Reason string
RequiresConfirmation bool // true if tool needs user approval before execution
}
CheckResult holds the result of a tool access check.
type ToolDefinition ¶
type ToolDefinition struct {
Type string `json:"type"`
Function FunctionDef `json:"function"`
}
ToolDefinition is an OpenAI-compatible tool definition for function calling.
func MakeToolDefinition ¶
func MakeToolDefinition(name, description string, params map[string]any) ToolDefinition
MakeToolDefinition creates a ToolDefinition from name, description, and a parameter schema map (matching JSON Schema format). The name is automatically sanitized to match OpenAI's pattern.
func SkillToolToDefinition ¶
func SkillToolToDefinition(name string, tool skills.Tool) ToolDefinition
SkillToolToDefinition converts a skills.Tool into an OpenAI ToolDefinition.
type ToolExecutor ¶
type ToolExecutor struct {
// contains filtered or unexported fields
}
ToolExecutor manages tool registration and dispatches tool calls.
func NewToolExecutor ¶
func NewToolExecutor(logger *slog.Logger) *ToolExecutor
NewToolExecutor creates a new empty tool executor.
func (*ToolExecutor) Abort ¶
func (e *ToolExecutor) Abort()
Abort signals all running tools to stop. Safe to call multiple times.
func (*ToolExecutor) AbortCh ¶
func (e *ToolExecutor) AbortCh() <-chan struct{}
AbortCh returns the abort channel for tools to select on.
func (*ToolExecutor) ApplyDefaultConcurrency ¶ added in v1.17.0
func (e *ToolExecutor) ApplyDefaultConcurrency()
ApplyDefaultConcurrency marks all registered tools that appear in the defaultConcurrentSafeTools set as ConcurrentSafe. Called once after all tools are registered.
func (*ToolExecutor) Configure ¶
func (e *ToolExecutor) Configure(cfg ToolExecutorConfig)
Configure applies ToolExecutorConfig (parallel, max_parallel, timeouts).
func (*ToolExecutor) Execute ¶
func (e *ToolExecutor) Execute(ctx context.Context, calls []ToolCall) []ToolResult
Execute dispatches a batch of tool calls to their registered handlers. Each tool is executed with a per-tool timeout. When Parallel is true and no sequential tools are in the batch, runs concurrently. Returns results in the same order as the input calls.
func (*ToolExecutor) Guard ¶
func (e *ToolExecutor) Guard() *ToolGuard
Guard returns the configured ToolGuard (may be nil).
func (*ToolExecutor) HasTool ¶
func (e *ToolExecutor) HasTool(name string) bool
HasTool checks if a tool is registered by name.
func (*ToolExecutor) IsAborted ¶
func (e *ToolExecutor) IsAborted() bool
IsAborted returns true if an abort has been signaled.
func (*ToolExecutor) IsConcurrentSafe ¶ added in v1.17.0
func (e *ToolExecutor) IsConcurrentSafe(name string) bool
IsConcurrentSafe returns true if the named tool can run in parallel with others. Checks the per-tool annotation first, then falls back to the default set.
func (*ToolExecutor) MarkConcurrentSafe ¶ added in v1.17.0
func (e *ToolExecutor) MarkConcurrentSafe(names ...string)
MarkConcurrentSafe marks the named tools as safe for concurrent execution. Tools not explicitly marked and not in the defaultConcurrentSafeTools set are treated as serial (must execute one at a time).
func (*ToolExecutor) ProfileManager ¶ added in v1.13.0
func (e *ToolExecutor) ProfileManager() profiles.ProfileManager
ProfileManager returns the configured auth profile manager (may be nil).
func (*ToolExecutor) Register ¶
func (e *ToolExecutor) Register(def ToolDefinition, handler ToolHandlerFunc)
Register adds a tool with its definition and handler. If a tool with the same name already exists, it is overwritten.
func (*ToolExecutor) RegisterHidden ¶ added in v1.13.0
func (e *ToolExecutor) RegisterHidden(def ToolDefinition, handler ToolHandlerFunc)
RegisterHidden registers a tool that is callable but excluded from the LLM tool schema. Used for legacy/deprecated aliases that should still work if invoked but shouldn't consume slots in the tool list sent to the model.
func (*ToolExecutor) RegisterHook ¶
func (e *ToolExecutor) RegisterHook(hook *ToolHook)
RegisterHook adds a before/after tool execution hook. Hooks are called in registration order. Multiple hooks can be registered.
func (*ToolExecutor) RegisterPluginTool ¶ added in v1.16.0
func (e *ToolExecutor) RegisterPluginTool(reg plugins.ToolRegistration)
RegisterPluginTool registers a tool from the plugin system. Adapts plugins.ToolRegistration to the internal ToolDefinition format.
func (*ToolExecutor) RegisterSkillTools ¶
func (e *ToolExecutor) RegisterSkillTools(skill skills.Skill)
RegisterSkillTools registers all tools exposed by a skill. Tool names are prefixed with the skill name to avoid collisions. Names are sanitized to match OpenAI's pattern: ^[a-zA-Z0-9_-]+$
When the reference model is active (skill has Location != ""), the generic "execute" tool is registered as hidden — the LLM should read SKILL.md via read_file instead of calling the execute tool (which returns "instructions only"). Script-specific tools (run_*) remain visible.
func (*ToolExecutor) ResetAbort ¶
func (e *ToolExecutor) ResetAbort()
ResetAbort creates a fresh abort channel for a new run.
func (*ToolExecutor) SessionContext ¶
func (e *ToolExecutor) SessionContext() string
SessionContext returns the current session ID (format: "channel:chatID").
func (*ToolExecutor) SetCallerContext ¶
func (e *ToolExecutor) SetCallerContext(level AccessLevel, jid string)
SetCallerContext sets the access level and JID for the current caller. Must be called before Execute() in the message handling flow.
func (*ToolExecutor) SetConfirmationRequester ¶
func (e *ToolExecutor) SetConfirmationRequester(fn func(sessionID, callerJID, toolName string, args map[string]any) (bool, error))
SetConfirmationRequester sets the callback for tools requiring user approval. When a tool is in RequireConfirmation list, this callback is invoked.
func (*ToolExecutor) SetGuard ¶
func (e *ToolExecutor) SetGuard(guard *ToolGuard)
SetGuard configures the security guard for tool execution.
func (*ToolExecutor) SetProfileManager ¶ added in v1.13.0
func (e *ToolExecutor) SetProfileManager(pm profiles.ProfileManager)
SetProfileManager configures the auth profile manager for OAuth/API key access.
func (*ToolExecutor) SetSessionContext ¶
func (e *ToolExecutor) SetSessionContext(sessionID string)
SetSessionContext sets the session ID for approval matching (channel:chatID). Must be set before Execute() when using approval flow.
func (*ToolExecutor) SetVault ¶ added in v1.12.0
func (e *ToolExecutor) SetVault(vault skills.VaultReader)
SetVault sets the vault reader for skill setup checking.
func (*ToolExecutor) ToolNames ¶
func (e *ToolExecutor) ToolNames() []string
ToolNames returns the names of all registered tools.
func (*ToolExecutor) Tools ¶
func (e *ToolExecutor) Tools() []ToolDefinition
Tools returns all registered tool definitions for the LLM. Uses a cached slice that is rebuilt only when tools are added/removed.
func (*ToolExecutor) UnregisterTool ¶ added in v1.16.0
func (e *ToolExecutor) UnregisterTool(name string) bool
UnregisterTool removes a tool from the executor by name. Returns true if the tool was found and removed.
func (*ToolExecutor) UpdateGuardConfig ¶
func (e *ToolExecutor) UpdateGuardConfig(cfg ToolGuardConfig)
UpdateGuardConfig updates the tool guard config (for hot-reload).
type ToolExecutorConfig ¶
type ToolExecutorConfig struct {
// Parallel enables parallel execution of independent tools (default: true).
Parallel bool `yaml:"parallel"`
// MaxParallel is the max concurrent tool executions when parallel is enabled (default: 5).
MaxParallel int `yaml:"max_parallel"`
// BashTimeoutSeconds is the executor-level timeout for bash/ssh/scp/exec tools (default: 300).
BashTimeoutSeconds int `yaml:"bash_timeout_seconds"`
// DefaultTimeoutSeconds is the executor-level timeout for all other tools (default: 30).
DefaultTimeoutSeconds int `yaml:"default_timeout_seconds"`
}
ToolExecutorConfig configures tool execution behavior.
type ToolGuard ¶
type ToolGuard struct {
// contains filtered or unexported fields
}
ToolGuard enforces security policies on tool execution.
func NewToolGuard ¶
func NewToolGuard(cfg ToolGuardConfig, logger *slog.Logger) *ToolGuard
NewToolGuard creates and initializes a tool security guard.
func (*ToolGuard) AuditLog ¶
func (g *ToolGuard) AuditLog(toolName string, callerJID string, callerLevel AccessLevel, args map[string]any, allowed bool, result string)
AuditLog records a tool execution to the audit log.
func (*ToolGuard) Check ¶
func (g *ToolGuard) Check(toolName string, callerLevel AccessLevel, args map[string]any) ToolCheckResult
Check evaluates whether a tool call is permitted for the given access level.
func (*ToolGuard) CheckWithProfile ¶
func (g *ToolGuard) CheckWithProfile(toolName string, callerLevel AccessLevel, args map[string]any, profile *ToolProfile, overlay *ToolOverlay) ToolCheckResult
CheckWithProfile evaluates tool access considering a profile's allow/deny lists and an optional workspace overlay. The overlay is applied after the profile check but before standard permission checks. If no profile is provided (nil), delegates directly to Check() (with overlay).
func (*ToolGuard) GetActiveProfile ¶
func (g *ToolGuard) GetActiveProfile() *ToolProfile
GetActiveProfile returns the active profile based on config. Returns nil if no profile is configured or if profile is not found.
func (*ToolGuard) GetAllToolNames ¶
GetAllToolNames returns all known tool names from permissions and groups.
func (*ToolGuard) SQLiteAudit ¶
func (g *ToolGuard) SQLiteAudit() *SQLiteAuditLogger
SQLiteAudit returns the SQLite audit logger (may be nil).
func (*ToolGuard) SetSQLiteAudit ¶
func (g *ToolGuard) SetSQLiteAudit(a *SQLiteAuditLogger)
SetSQLiteAudit configures a SQLite-backed audit logger. When set, audit records go to the database instead of the text file.
func (*ToolGuard) UpdateConfig ¶
func (g *ToolGuard) UpdateConfig(cfg ToolGuardConfig)
UpdateConfig updates the tool guard config from hot-reload. Re-compiles dangerous patterns and protected paths. The audit log file is not changed (requires restart to change audit log path).
type ToolGuardConfig ¶
type ToolGuardConfig struct {
// Enable turns on the tool security guard (default: true).
Enabled bool `yaml:"enabled"`
// AuditLog path for recording all tool executions.
AuditLogPath string `yaml:"audit_log"`
// Profile selects a predefined tool profile.
// Options: minimal, coding, messaging, full, or custom profile name.
// Empty = use ToolPermissions directly (backward compatibility).
Profile string `yaml:"profile"`
// CustomProfiles allows defining custom tool profiles.
CustomProfiles map[string]ToolProfile `yaml:"custom_profiles"`
// ToolPermissions overrides per-tool permission levels.
// key = tool name, value = "owner"/"admin"/"user"/"public".
ToolPermissions map[string]string `yaml:"tool_permissions"`
// AllowDestructive enables destructive commands (rm -rf /, mkfs, dd, etc)
// for the owner. When false (default), these are blocked for everyone.
// When true, owner can run them; non-owners are still blocked.
AllowDestructive bool `yaml:"allow_destructive"`
// AllowSudo allows sudo commands. When false (default), sudo is blocked
// for non-owners. When true, owner and admin can use sudo.
AllowSudo bool `yaml:"allow_sudo"`
// AllowReboot allows shutdown/reboot/halt commands. Default: false.
AllowReboot bool `yaml:"allow_reboot"`
// DangerousCommands are additional regex patterns for commands that should
// be blocked. These are added ON TOP of the defaults (not replacing them).
// To disable all defaults, set allow_destructive: true.
DangerousCommands []string `yaml:"dangerous_commands"`
// ProtectedPaths are file paths that cannot be read or written by non-owners.
// Supports glob patterns. If empty, defaults are used.
ProtectedPaths []string `yaml:"protected_paths"`
// SSHAllowedHosts restricts which hosts can be connected via SSH.
// Empty list = any host allowed (no restriction). Use "*" explicitly to allow all.
SSHAllowedHosts []string `yaml:"ssh_allowed_hosts"`
// BlockSudo blocks sudo commands for non-owners (default: true).
// Deprecated: use AllowSudo instead. Kept for backward compatibility.
BlockSudo bool `yaml:"block_sudo"`
// AutoApprove lists tools that can execute without any permission check,
// even for regular users. Use with caution. Example: ["web_search", "memory"]
AutoApprove []string `yaml:"auto_approve"`
// RequireConfirmation lists tools that require the user to confirm via
// the chat before executing. The agent will ask "Confirm: <action>?" and
// wait for approval. Example: ["bash", "ssh", "scp", "write_file"]
RequireConfirmation []string `yaml:"require_confirmation"`
// DestructiveProtection configures rate limiting and batch detection for
// destructive tools. With dispatcher consolidation, configure at action level.
DestructiveProtection DestructiveToolsConfig `yaml:"destructive_protection"`
}
ToolGuardConfig configures the security guard for tools.
func DefaultToolGuardConfig ¶
func DefaultToolGuardConfig() ToolGuardConfig
DefaultToolGuardConfig returns safe defaults for the tool security guard. Owners have full access by default - adjust if you need stricter security.
type ToolHandlerFunc ¶
ToolHandlerFunc is the signature for tool execution handlers. Receives parsed arguments and returns the result or an error.
type ToolHook ¶
type ToolHook struct {
// Name identifies this hook for logging and debugging.
Name string
// BeforeToolCall is called before the tool handler executes.
// Return modified args (or original), or an error to block execution.
// If blocked is true, the tool is not executed and blockReason is returned.
BeforeToolCall func(toolName string, args map[string]any) (modifiedArgs map[string]any, blocked bool, blockReason string)
// AfterToolCall is called after the tool handler executes (success or error).
AfterToolCall func(toolName string, args map[string]any, result string, err error)
}
ToolHook is a callback that runs before or after tool execution. Before hooks can modify args or block execution by returning an error. After hooks can observe/log the result but cannot modify it.
type ToolLoopConfig ¶
type ToolLoopConfig struct {
// Enabled turns loop detection on (default: true).
Enabled bool `yaml:"enabled"`
// HistorySize is how many recent tool calls to track (default: 30).
HistorySize int `yaml:"history_size"`
// WarningThreshold triggers a warning injected into the conversation (default: 8).
WarningThreshold int `yaml:"warning_threshold"`
// CriticalThreshold triggers a strong nudge to stop (default: 15).
CriticalThreshold int `yaml:"critical_threshold"`
// CircuitBreakerThreshold force-stops the agent run (default: 25).
CircuitBreakerThreshold int `yaml:"circuit_breaker_threshold"`
// GlobalCircuitBreaker is the max total no-progress calls before hard stop (default: 20).
GlobalCircuitBreaker int `yaml:"global_circuit_breaker"`
// ProgressDetection enables content-based progress analysis (default: true).
ProgressDetection bool `yaml:"progress_detection"`
}
ToolLoopConfig configures tool loop detection thresholds.
func DefaultToolLoopConfig ¶
func DefaultToolLoopConfig() ToolLoopConfig
DefaultToolLoopConfig returns sensible defaults.
type ToolLoopDetector ¶
type ToolLoopDetector struct {
// contains filtered or unexported fields
}
ToolLoopDetector tracks tool call history and detects loops.
func NewToolLoopDetector ¶
func NewToolLoopDetector(cfg ToolLoopConfig, logger *slog.Logger) *ToolLoopDetector
NewToolLoopDetector creates a new detector with the given config.
func (*ToolLoopDetector) RecordAndCheck ¶
func (d *ToolLoopDetector) RecordAndCheck(toolName string, args map[string]any) LoopDetectionResult
RecordAndCheck records a tool call and checks for loops. Returns a result indicating the severity (if any).
func (*ToolLoopDetector) RecordToolOutcome ¶
func (d *ToolLoopDetector) RecordToolOutcome(output string)
RecordToolOutcome records the result of a tool call for progress tracking. Call this after tool execution with the output to determine if the agent is making progress. An empty or identical output signals no progress.
func (*ToolLoopDetector) Reset ¶
func (d *ToolLoopDetector) Reset()
Reset clears the history (e.g. for a new run).
type ToolOutcome ¶ added in v1.18.2
type ToolOutcome struct {
Name string // tool name
Args string // raw tool args (trimmed)
Error bool // true if the tool returned an error
Content string // tool output (truncated)
Timestamp time.Time // when the outcome was recorded
}
ToolOutcome captures the structured result of a single tool execution.
type ToolOutcomeLog ¶ added in v1.18.2
type ToolOutcomeLog struct {
// contains filtered or unexported fields
}
ToolOutcomeLog is a bounded, thread-safe chronological log of tool outcomes for a single agent turn. Entries are appended in execution order; older entries drop off once the capacity is exceeded.
func NewToolOutcomeLog ¶ added in v1.18.2
func NewToolOutcomeLog(capacity int) *ToolOutcomeLog
NewToolOutcomeLog constructs an outcome log with the given capacity. A non-positive capacity defaults to 32 entries, which comfortably covers the 25-turn tool loop with multiple calls per turn.
func ToolOutcomeLogFromContext ¶ added in v1.18.2
func ToolOutcomeLogFromContext(ctx context.Context) *ToolOutcomeLog
ToolOutcomeLogFromContext extracts the outcome log, or nil if not set.
func (*ToolOutcomeLog) Record ¶ added in v1.18.2
func (l *ToolOutcomeLog) Record(o ToolOutcome)
Record appends an outcome to the log, trimming oldest entries beyond max.
func (*ToolOutcomeLog) Snapshot ¶ added in v1.18.2
func (l *ToolOutcomeLog) Snapshot() []ToolOutcome
Snapshot returns a copy of the current outcomes in chronological order.
type ToolOverlay ¶ added in v1.16.0
ToolOverlay holds workspace-scoped tool allow/deny lists.
func ToolOverlayFromContext ¶ added in v1.16.0
func ToolOverlayFromContext(ctx context.Context) *ToolOverlay
ToolOverlayFromContext extracts the tool overlay from context.
type ToolPermission ¶
type ToolPermission string
ToolPermission defines which access level is required for a tool.
const ( PermOwner ToolPermission = "owner" // Only owner can use. PermAdmin ToolPermission = "admin" // Admin and owner. PermUser ToolPermission = "user" // Any authorized user. PermPublic ToolPermission = "public" // No restriction (used for read-only tools). )
type ToolProfile ¶
type ToolProfile struct {
// Name is the profile identifier (e.g., "minimal", "coding", "full").
Name string `yaml:"name"`
// Description explains what this profile is for.
Description string `yaml:"description"`
// Allow lists tools and groups that are permitted.
// Supports: tool names, "group:name", wildcards like "git_*"
// Empty means no allow list (use permission levels).
Allow []string `yaml:"allow"`
// Deny lists tools and groups that are always blocked.
// Takes precedence over Allow.
Deny []string `yaml:"deny"`
}
ToolProfile defines a preset of allowed and denied tools.
func ExtendProfileWithSkills ¶ added in v1.13.0
func ExtendProfileWithSkills(base *ToolProfile, activeSkills []string) *ToolProfile
ExtendProfileWithSkills creates a copy of the profile that also allows tools from the given active skills. Skill tools follow the naming pattern "skillname_toolname", so we add "skillname_*" wildcards to the allow list. If the profile already allows all tools ("*"), returns it unchanged.
func GetProfile ¶
func GetProfile(name string, customProfiles map[string]ToolProfile) *ToolProfile
GetProfile returns a profile by name (built-in or custom).
func ToolProfileFromContext ¶
func ToolProfileFromContext(ctx context.Context) *ToolProfile
ToolProfileFromContext extracts the tool profile from context. Returns nil if no profile is set.
type ToolProfileInfo ¶ added in v1.12.0
type ToolProfileInfo struct {
Name string `json:"name"`
Description string `json:"description"`
Allow []string `json:"allow"`
Deny []string `json:"deny"`
Builtin bool `json:"builtin"`
}
ToolProfileInfo contains profile info for API responses.
type ToolResult ¶
type ToolResult struct {
ToolCallID string
Name string
Content string // Main content (used for LLM context when ForLLM is empty)
Error error
// Extended fields for dual output (PicoClaw-inspired)
ForLLM string // Technical content for LLM reasoning (if empty, Content is used)
ForUser string // Friendly message to show user immediately
IsAsync bool // Tool is running in background, result comes later
IsSilent bool // Don't notify user about this result
}
ToolResult holds the output of a single tool execution.
func AsyncResult ¶ added in v1.12.0
func AsyncResult(message string) *ToolResult
AsyncResult creates a ToolResult indicating the tool is running in background. The actual result will be delivered via callback or follow-up message.
func DualToolResult ¶ added in v1.12.0
func DualToolResult(forLLM, forUser string) *ToolResult
DualToolResult creates a ToolResult with separate content for LLM and user. This is the recommended way to return results that have both technical details and user-friendly messages.
func ErrorResult ¶ added in v1.12.0
func ErrorResult(err error) *ToolResult
ErrorResult creates a ToolResult from an error.
func SilentResult ¶ added in v1.12.0
func SilentResult(content string) *ToolResult
SilentResult creates a ToolResult that doesn't notify the user. Useful for background operations or when the result should only be used for LLM reasoning.
func (*ToolResult) GetForLLM ¶ added in v1.12.0
func (r *ToolResult) GetForLLM() string
GetForLLM returns the content to use for LLM context. Returns ForLLM if set, otherwise Content.
func (*ToolResult) GetForUser ¶ added in v1.12.0
func (r *ToolResult) GetForUser() string
GetForUser returns the content to show the user. Returns ForUser if set, otherwise GetForLLM().
type TranscriptPolicy ¶ added in v1.13.0
type TranscriptPolicy struct {
// StrictToolCallIDs requires that tool_call IDs are exactly formatted.
// Mistral requires strict UUID-like IDs (no prefixes, lowercase).
StrictToolCallIDs bool
// EnforceTurnOrdering ensures user/assistant turns alternate properly.
// Google (Gemini) rejects consecutive same-role messages.
EnforceTurnOrdering bool
// DropThinkingBlocks removes <thinking> and <reasoning> content blocks.
// Some providers reject or misinterpret these meta-reasoning blocks.
DropThinkingBlocks bool
// MergeConsecutiveSameRole merges consecutive messages from the same role
// into a single message. Required by some providers that reject duplicates.
MergeConsecutiveSameRole bool
// RequireToolResultsAfterToolUse ensures every tool_use has a matching
// tool_result immediately following it. Anthropic requires this.
RequireToolResultsAfterToolUse bool
// StripCacheControl removes cache_control fields from messages.
// Only Anthropic and compatible proxies support this.
StripCacheControl bool
// MaxSystemMessages is the maximum number of system messages allowed.
// Some providers only support a single system message.
// 0 = unlimited.
MaxSystemMessages int
// CollapseMultipleSystemMessages merges multiple system messages into one.
CollapseMultipleSystemMessages bool
}
TranscriptPolicy defines the sanitization rules for a provider's API.
func GetTranscriptPolicy ¶ added in v1.13.0
func GetTranscriptPolicy(provider string) TranscriptPolicy
GetTranscriptPolicy returns the policy for a given provider.
type TrustConfig ¶
type TrustConfig struct {
// Owner is the maximum risk level the owner can execute without approval.
Owner RiskLevel `yaml:"owner"`
// Admin is the maximum risk level admins can execute without approval.
Admin RiskLevel `yaml:"admin"`
// User is the maximum risk level regular users can execute without approval.
User RiskLevel `yaml:"user"`
}
TrustConfig configures trust levels per user role.
type TurnState ¶ added in v1.17.0
type TurnState struct {
// Messages is the current conversation history.
Messages []chatMessage
// Tools is the tool definitions available for this turn.
Tools []ToolDefinition
// Response holds the LLM response (set by APICall phase).
Response *LLMResponse
// ToolResults holds results from tool execution (set by ToolExec phase).
ToolResults []ToolResult
// FinalText is the final response text (set when Decision chooses Stop).
FinalText string
// InjectedMessage is a message to inject (set when Decision chooses Inject).
InjectedMessage string
// Turn is the current turn number.
Turn int
// Usage tracks accumulated token usage.
Usage LLMUsage
// Metadata holds arbitrary phase-specific data.
Metadata map[string]any
}
TurnState carries mutable state through the phase pipeline. Each phase can read and modify this state before passing it to the next.
type TypingController ¶ added in v1.13.0
type TypingController struct {
// contains filtered or unexported fields
}
TypingController manages typing indicator lifecycle with state awareness.
func NewTypingController ¶ added in v1.13.0
func NewTypingController(channelMgr *channels.Manager, channel, chatID string) *TypingController
NewTypingController creates a new controller in the Started state.
func (*TypingController) MarkDispatchIdle ¶ added in v1.13.0
func (tc *TypingController) MarkDispatchIdle()
MarkDispatchIdle transitions to DispatchIdle, stopping typing indicators.
func (*TypingController) MarkRunComplete ¶ added in v1.13.0
func (tc *TypingController) MarkRunComplete()
MarkRunComplete transitions to RunComplete state. Typing continues during a grace period to cover block streamer dispatch.
func (*TypingController) Seal ¶ added in v1.13.0
func (tc *TypingController) Seal()
Seal transitions to the terminal Sealed state and stops the typing loop.
func (*TypingController) ShouldSuppress ¶ added in v1.13.0
func (tc *TypingController) ShouldSuppress(content string) bool
ShouldSuppress returns true if typing should be suppressed for the given content. Empty or internal-only content (heartbeats, etc.) should not restart typing indicators.
func (*TypingController) Start ¶ added in v1.13.0
func (tc *TypingController) Start(ctx context.Context)
Start transitions to Active and begins sending typing indicators. The context is used to cancel the typing loop if the parent context is cancelled.
type TypingState ¶ added in v1.13.0
type TypingState int
TypingState represents the lifecycle state of the typing controller.
const ( TypingStarted TypingState = iota // Created, not yet active. TypingActive // Sending typing indicators. TypingRunComplete // Agent done, grace period for dispatch. TypingDispatchIdle // Dispatch finished, idle. TypingSealed // Terminal, no further sends. )
type UpdateConfig ¶ added in v1.13.0
type UpdateConfig struct {
// Enabled turns auto-update checking on/off (default: true).
Enabled bool `yaml:"enabled"`
// AssetsURL is the base URL for release assets.
AssetsURL string `yaml:"assets_url"`
// CheckInterval is the duration between automatic update checks (e.g. "1h").
CheckInterval string `yaml:"check_interval"`
}
UpdateConfig configures auto-update checking and installation.
type UpdateFileChunk ¶ added in v1.12.0
type UpdateFileChunk struct {
ChangeContext string
OldLines []string
NewLines []string
IsEndOfFile bool
}
UpdateFileChunk represents a single chunk of changes within an UpdateFileHunk.
type UpdateFileHunk ¶ added in v1.12.0
type UpdateFileHunk struct {
Path string
MovePath string
Chunks []UpdateFileChunk
}
UpdateFileHunk represents an update to an existing file, optionally moving it.
type UsageAccumulator ¶ added in v1.13.0
type UsageAccumulator struct {
TotalInput int // Sum of all PromptTokens across calls
TotalOutput int // Sum of all CompletionTokens
TotalCacheRead int // Sum of all CacheReadTokens
TotalCacheWrite int // Sum of all CacheWriteTokens
LastInput int // Most recent call's PromptTokens
LastOutput int // Most recent call's CompletionTokens
LastCacheRead int // Most recent call's CacheReadTokens
LastCacheWrite int // Most recent call's CacheWriteTokens
CallCount int // Number of LLM calls in this run
}
UsageAccumulator tracks token usage across multiple LLM calls within a run. It maintains both cumulative totals and the most recent call's values. Using last-call values for context size estimation avoids the inflation problem where accumulated cacheRead across N calls = N × context_size.
func (*UsageAccumulator) EffectiveContextTokens ¶ added in v1.13.0
func (ua *UsageAccumulator) EffectiveContextTokens() int
EffectiveContextTokens returns the actual context size as reported by the provider in the most recent call. This is more accurate than character-based estimation because it uses real token counts from the API.
func (*UsageAccumulator) Record ¶ added in v1.13.0
func (ua *UsageAccumulator) Record(usage LLMUsage)
Record accumulates a single LLM call's usage and updates last-call snapshots.
func (*UsageAccumulator) ToLLMUsage ¶ added in v1.13.0
func (ua *UsageAccumulator) ToLLMUsage() LLMUsage
ToLLMUsage converts the accumulator totals to an LLMUsage for backward compat.
type UsageTracker ¶
type UsageTracker struct {
// contains filtered or unexported fields
}
UsageTracker records usage per session and globally.
func NewUsageTracker ¶
func NewUsageTracker(logger *slog.Logger) *UsageTracker
NewUsageTracker creates a new UsageTracker.
func (*UsageTracker) FormatGlobalUsage ¶
func (u *UsageTracker) FormatGlobalUsage() string
FormatGlobalUsage returns a human-readable global usage report.
func (*UsageTracker) FormatUsage ¶
func (u *UsageTracker) FormatUsage(sessionID string) string
FormatUsage returns a human-readable usage report for a session.
func (*UsageTracker) GetGlobal ¶
func (u *UsageTracker) GetGlobal() *SessionUsage
GetGlobal returns a copy of global usage.
func (*UsageTracker) GetSession ¶
func (u *UsageTracker) GetSession(sessionID string) *SessionUsage
GetSession returns a copy of the session's usage stats, or nil if not found.
func (*UsageTracker) Record ¶
func (u *UsageTracker) Record(sessionID, model string, usage LLMUsage)
Record adds usage for a session and globally.
func (*UsageTracker) ResetSession ¶
func (u *UsageTracker) ResetSession(sessionID string)
ResetSession clears usage for a session.
type UserManager ¶
type UserManager struct {
// contains filtered or unexported fields
}
UserManager handles multi-user operations.
func NewUserManager ¶
func NewUserManager(config UserManagerConfig) *UserManager
NewUserManager creates a new user manager.
func (*UserManager) AddUser ¶
func (um *UserManager) AddUser(user *TeamUser) error
AddUser adds a new user.
func (*UserManager) CheckPermission ¶
func (um *UserManager) CheckPermission(userID string, required UserRole) bool
CheckPermission verifies a user has the required role.
func (*UserManager) GetSharedMemory ¶
func (um *UserManager) GetSharedMemory(key string) (*SharedMemory, bool)
GetSharedMemory retrieves a value from shared team memory.
func (*UserManager) GetUser ¶
func (um *UserManager) GetUser(id string) (*TeamUser, bool)
GetUser returns a user by ID.
func (*UserManager) ListSharedMemory ¶
func (um *UserManager) ListSharedMemory() []*SharedMemory
ListSharedMemory returns all shared memory entries.
func (*UserManager) ListUsers ¶
func (um *UserManager) ListUsers() []*TeamUser
ListUsers returns all users.
func (*UserManager) RemoveUser ¶
func (um *UserManager) RemoveUser(id string) error
RemoveUser removes a user.
func (*UserManager) SetSharedMemory ¶
func (um *UserManager) SetSharedMemory(key, value, authorID string, tags []string)
SetSharedMemory stores a value in shared team memory.
type UserManagerConfig ¶ added in v1.16.0
type UserManagerConfig struct {
MaxUsers int `yaml:"max_users" json:"max_users"`
DefaultRole string `yaml:"default_role" json:"default_role"`
}
UserManagerConfig holds multi-user configuration.
type UserUsage ¶
type UserUsage struct {
SessionID string `json:"session_id"`
Tokens int64 `json:"tokens"`
Requests int64 `json:"requests"`
CostUSD float64 `json:"cost_usd"`
}
UserUsage represents usage for a single user/session.
type Vault ¶
type Vault struct {
// contains filtered or unexported fields
}
Vault provides encrypted secret storage backed by a local file.
func NewVault ¶
NewVault creates a vault instance pointing to the given file path. The vault is not yet unlocked — call Unlock() or Create() first.
func ResolveAPIKey ¶
ResolveAPIKey resolves the API key using the priority chain: vault → keyring → env var → config value. Also updates the config in-place with the resolved value. If a vault exists but is locked, it prompts for the master password (or uses DEVCLAW_VAULT_PASSWORD env var for non-interactive mode). Returns the unlocked vault (or nil if unavailable) so it can be reused by the assistant for agent vault tools.
func (*Vault) ChangePassword ¶
ChangePassword re-encrypts all entries with a new master password. The vault must be unlocked.
func (*Vault) Create ¶
Create initializes a new vault with the given master password. If the vault file already exists, it returns an error.
func (*Vault) Get ¶
Get retrieves and decrypts a secret from the vault. Returns empty string if the key doesn't exist. The vault must be unlocked.
func (*Vault) Has ¶ added in v1.12.0
Has returns true if a secret exists in the vault. Returns false if vault is locked or key doesn't exist.
func (*Vault) InjectProviderKeys ¶ added in v1.8.1
InjectProviderKeys injects all secrets from the vault into environment variables. This allows LLM clients to find their API keys via standard variable names (OPENAI_API_KEY, ANTHROPIC_API_KEY, etc.) without the config needing to reference them explicitly.
The vault must be unlocked before calling this method.
func (*Vault) IsUnlocked ¶
IsUnlocked returns true if the vault has been unlocked with a password.
func (*Vault) List ¶
List returns the names of all stored secrets (excluding internal entries). Returns an empty slice if the vault is locked or empty.
func (*Vault) Lock ¶
func (v *Vault) Lock()
Lock clears the derived key from memory, locking the vault.
type VaultData ¶
type VaultData struct {
Version int `json:"version"`
Salt string `json:"salt"` // base64-encoded Argon2 salt
Entries map[string]VaultEntry `json:"entries"`
}
VaultData is the on-disk format of the vault.
type VaultEntry ¶
type VaultEntry struct {
Nonce string `json:"nonce"` // base64-encoded AES-GCM nonce
Ciphertext string `json:"ciphertext"` // base64-encoded encrypted data
}
VaultEntry holds one encrypted secret.
type VaultReaderAdapter ¶ added in v1.12.0
type VaultReaderAdapter struct {
// contains filtered or unexported fields
}
VaultReaderAdapter adapts a Vault to implement skills.VaultReader.
func NewVaultReaderAdapter ¶ added in v1.12.0
func NewVaultReaderAdapter(getKey func(key string) (string, error), hasKey func(key string) bool) *VaultReaderAdapter
NewVaultReaderAdapter creates a VaultReader from getter functions.
func (*VaultReaderAdapter) Get ¶ added in v1.12.0
func (v *VaultReaderAdapter) Get(key string) (string, error)
Get returns the value for a key.
func (*VaultReaderAdapter) Has ¶ added in v1.12.0
func (v *VaultReaderAdapter) Has(key string) bool
Has returns true if the key exists.
type VerboseLevel ¶ added in v1.13.0
type VerboseLevel string
VerboseLevel controls tool progress message visibility, matching OpenClaw's verboseLevel semantics:
- "off" → no tool progress messages (default)
- "on" → tool name summaries are shown
- "full" → tool names + detailed output are shown
const ( VerboseOff VerboseLevel = "off" VerboseOn VerboseLevel = "on" VerboseFull VerboseLevel = "full" )
func (VerboseLevel) ShouldEmitToolProgress ¶ added in v1.13.0
func (v VerboseLevel) ShouldEmitToolProgress() bool
ShouldEmitToolProgress returns true when tool progress messages should be sent to the user (verbose "on" or "full").
type WebFetchCache ¶ added in v1.13.0
type WebFetchCache struct {
// contains filtered or unexported fields
}
WebFetchCache is a simple in-memory cache with TTL for web fetch results.
func NewWebFetchCache ¶ added in v1.13.0
func NewWebFetchCache(ttl time.Duration, maxSize int) *WebFetchCache
NewWebFetchCache creates a cache with the given TTL and max entries.
func (*WebFetchCache) Get ¶ added in v1.13.0
func (c *WebFetchCache) Get(url string) (string, bool)
Get returns a cached entry if it exists and is not expired.
func (*WebFetchCache) Set ¶ added in v1.13.0
func (c *WebFetchCache) Set(url, content string)
Set stores a result in the cache, evicting the oldest entry if full.
type WebSearchConfig ¶
type WebSearchConfig struct {
// Provider is the search engine to use: "duckduckgo" (default), "brave", or "perplexity".
Provider string `yaml:"provider"`
// BraveAPIKey is the Brave Search API subscription token.
// Can also be set via BRAVE_API_KEY env var.
BraveAPIKey string `yaml:"brave_api_key"`
// PerplexityModel is the Perplexity model to use via OpenRouter (default: "perplexity/sonar").
// Requires the main API to be configured with OpenRouter as provider.
PerplexityModel string `yaml:"perplexity_model"`
// PerplexityAPIKey is the OpenRouter API key for Perplexity queries.
// Falls back to OPENROUTER_API_KEY env var, then to the main API key.
PerplexityAPIKey string `yaml:"perplexity_api_key"`
// MaxResults is the maximum number of results to return (default: 8).
MaxResults int `yaml:"max_results"`
// CacheTTLSeconds is how long search results are cached (default: 300 = 5 min, 0 = disabled).
CacheTTLSeconds int `yaml:"cache_ttl_seconds"`
}
WebSearchConfig configures the web search tool.
type WebhookConfig ¶
type WebhookConfig struct {
// Name identifies this webhook for logging.
Name string `yaml:"name"`
// URL is the webhook endpoint URL.
URL string `yaml:"url"`
// Events lists which events to send to this webhook.
Events []string `yaml:"events"`
// Secret is used to sign payloads (HMAC-SHA256).
Secret string `yaml:"secret"`
// Headers are additional HTTP headers to send.
Headers map[string]string `yaml:"headers"`
// Timeout is the request timeout in seconds (default: 10).
Timeout int `yaml:"timeout"`
// Enabled controls whether this webhook is active.
Enabled bool `yaml:"enabled"`
// RetryCount is the number of retry attempts on failure (default: 3).
RetryCount int `yaml:"retry_count"`
// RetryDelayMs is the delay between retries in milliseconds (default: 1000).
RetryDelayMs int `yaml:"retry_delay_ms"`
}
WebhookConfig configures an external webhook endpoint.
type WebhookManager ¶
type WebhookManager struct {
// contains filtered or unexported fields
}
WebhookManager manages webhook delivery.
func NewWebhookManager ¶
func NewWebhookManager(cfg WebhooksConfig, hookMgr *HookManager, logger *slog.Logger) *WebhookManager
NewWebhookManager creates a new webhook manager.
func (*WebhookManager) ForwardEvent ¶
func (wm *WebhookManager) ForwardEvent(payload HookPayload)
ForwardEvent sends an event to all matching webhooks.
func (*WebhookManager) ListWebhooks ¶
func (wm *WebhookManager) ListWebhooks() []WebhookConfig
ListWebhooks returns all configured webhooks.
func (*WebhookManager) Reload ¶
func (wm *WebhookManager) Reload(cfg WebhooksConfig)
Reload updates the webhook configuration.
func (*WebhookManager) SetWebhookEnabled ¶
func (wm *WebhookManager) SetWebhookEnabled(name string, enabled bool) bool
SetWebhookEnabled enables or disables a webhook by name.
type WebhookPayload ¶
type WebhookPayload struct {
// Event is the hook event name.
Event string `json:"event"`
// Timestamp is when the event occurred (ISO 8601).
Timestamp string `json:"timestamp"`
// SessionID is the session this event relates to (if applicable).
SessionID string `json:"session_id,omitempty"`
// Channel is the originating channel (if applicable).
Channel string `json:"channel,omitempty"`
// ToolName is the tool being called (for tool events).
ToolName string `json:"tool_name,omitempty"`
// Message is a human-readable description.
Message string `json:"message,omitempty"`
// Error is the error message (for error events).
Error string `json:"error,omitempty"`
// Extra holds arbitrary key-value data.
Extra map[string]any `json:"extra,omitempty"`
}
WebhookPayload is the JSON payload sent to webhook endpoints.
type WebhooksConfig ¶
type WebhooksConfig struct {
// Enabled turns the webhook system on/off.
Enabled bool `yaml:"enabled"`
// Webhooks is the list of configured webhooks.
Webhooks []WebhookConfig `yaml:"webhooks"`
}
WebhooksConfig holds all webhook configurations.
type WingHeuristic ¶ added in v1.18.0
type WingHeuristic struct {
// Wing is the canonical wing identifier to assign on match.
Wing string `yaml:"wing"`
// MatchChannelName contains lowercase substrings; if the hint (channel
// name, group name, display name) contains any of them, this wing wins.
MatchChannelName []string `yaml:"match_channel_name,omitempty"`
// MatchGroupName is an alias for MatchChannelName for readability
// when the hint comes from a messaging group name.
MatchGroupName []string `yaml:"match_group_name,omitempty"`
}
WingHeuristic matches channel or group name patterns to a wing. The binary ships zero defaults — all heuristics are user-provided via YAML config. This is intentional: hardcoded locale or domain-specific keywords would be biased for open-source deployments.
Example YAML snippet under memory.hierarchy.heuristics:
heuristics:
- wing: work
match_channel_name: [work, job, office]
- wing: family
match_channel_name: [family, home, kids]
type WingResolution ¶ added in v1.18.0
type WingResolution struct {
Wing string // normalized wing identifier, "" = none
Confidence float64 // 0.0 - 1.0; 0 for default/disabled
Source WingResolutionSource // where the decision came from
}
WingResolution is what ContextRouter.Resolve returns. An empty Wing string is a valid, first-class result — it means "no wing", which maps to SQL NULL and matches the legacy behavior.
func (WingResolution) IsEmpty ¶ added in v1.18.0
func (w WingResolution) IsEmpty() bool
IsEmpty reports whether this resolution yielded no wing. Callers use this to decide whether to pass wing through to downstream memory operations or to leave them unscoped.
type WingResolutionSource ¶ added in v1.18.0
type WingResolutionSource string
WingResolutionSource identifies how a wing decision was reached. Useful for telemetry (ADR-008) and debugging.
const ( // SourceMapped — explicit entry in channel_wing_map. SourceMapped WingResolutionSource = "mapped" // SourceHeuristic — derived from channel pattern matching. SourceHeuristic WingResolutionSource = "heuristic" // SourceDefault — no mapping and no heuristic match; wing is empty. SourceDefault WingResolutionSource = "default" // SourceDisabled — context routing is off by feature flag; wing is empty. SourceDisabled WingResolutionSource = "disabled" )
type WorkerResult ¶ added in v1.17.0
type WorkerResult struct {
TaskID string
Label string
Phase CoordinatorPhase
Result string
Error error
Duration time.Duration
}
WorkerResult holds the outcome of a single worker task.
type WorkerSpawner ¶ added in v1.17.0
type WorkerSpawner func(ctx context.Context, task WorkerTask, allowedTools []string) (string, error)
WorkerSpawner is the function signature for spawning a worker. The coordinator calls this for each task, passing the allowed tools. The implementation should create a subagent with only the specified tools.
type WorkerTask ¶ added in v1.17.0
type WorkerTask struct {
// ID is a unique identifier for this task.
ID string
// Label is a human-readable description.
Label string
// Prompt is the task instruction for the worker.
Prompt string
// Phase determines the tool restrictions applied.
Phase CoordinatorPhase
// Timeout is the maximum duration for this task. Zero uses the default.
Timeout time.Duration
}
WorkerTask describes a unit of work for a subagent within a phase.
type Workspace ¶
type Workspace struct {
// ID is the unique workspace identifier (slug, e.g. "personal", "work").
ID string `yaml:"id"`
// Name is the human-readable workspace name.
Name string `yaml:"name"`
// Description explains the workspace purpose.
Description string `yaml:"description"`
// Instructions are the custom system prompt for this workspace.
// Overrides the global instructions when set.
Instructions string `yaml:"instructions"`
// Soul is the agent's persona/personality definition.
// Personality traits, core truths, boundaries, vibe.
// Injected as persona layer before operational instructions.
Soul string `yaml:"soul,omitempty" json:"soul,omitempty"`
// Model overrides the default LLM model.
// Empty = use global default.
Model string `yaml:"model"`
// Language overrides the default language.
// Empty = use global default.
Language string `yaml:"language"`
// Timezone overrides the default timezone.
// Empty = use global default.
Timezone string `yaml:"timezone"`
// Trigger overrides the activation keyword for this workspace.
// Empty = use global default.
Trigger string `yaml:"trigger"`
// Skills lists the skills available in this workspace.
// Empty = use all globally enabled skills.
Skills []string `yaml:"skills"`
// TokenBudget overrides token limits for this workspace.
// Nil = use global defaults.
TokenBudget *TokenBudgetConfig `yaml:"token_budget,omitempty"`
// MaxMessages overrides the session history limit.
// 0 = use global default.
MaxMessages int `yaml:"max_messages"`
// ToolProfile specifies which tool profile to use for this workspace.
// Options: minimal, coding, messaging, full, or custom profile name.
// Empty = use global profile from tool_guard config.
ToolProfile string `yaml:"tool_profile"`
// Members lists the user JIDs assigned to this workspace.
Members []string `yaml:"members"`
// Groups lists the group JIDs assigned to this workspace.
Groups []string `yaml:"groups"`
// CreatedBy is the JID of whoever created this workspace.
CreatedBy string `yaml:"created_by"`
// CreatedAt is when the workspace was created.
CreatedAt time.Time `yaml:"created_at"`
// Active indicates if the workspace is enabled.
Active bool `yaml:"active"`
// Identity overrides the global identity for this workspace/agent.
Identity *IdentityConfig `yaml:"identity,omitempty" json:"identity,omitempty"`
// Channels routes all messages from these channels to this workspace.
// E.g. ["slack", "telegram"] means all Slack and Telegram messages go here.
Channels []string `yaml:"channels,omitempty" json:"channels,omitempty"`
// MaxTurns overrides the max LLM turns for this workspace (0 = use global).
MaxTurns int `yaml:"max_turns,omitempty" json:"max_turns,omitempty"`
// RunTimeout overrides the max run time in seconds (0 = use global).
RunTimeout int `yaml:"run_timeout,omitempty" json:"run_timeout,omitempty"`
// Default marks this workspace as the default for unassigned users.
// Only one workspace should be marked as default.
Default bool `yaml:"default,omitempty" json:"default,omitempty"`
// ToolsAllow overrides the allowed tools list for this workspace.
ToolsAllow []string `yaml:"tools_allow,omitempty" json:"tools_allow,omitempty"`
// ToolsDeny overrides the denied tools list for this workspace.
ToolsDeny []string `yaml:"tools_deny,omitempty" json:"tools_deny,omitempty"`
// Source indicates where this workspace was defined: "config", "api", "plugin".
Source string `yaml:"source,omitempty" json:"source,omitempty"`
}
Workspace represents an isolated assistant profile. Each workspace has its own instructions, skills, model, and memory.
type WorkspaceConfig ¶
type WorkspaceConfig struct {
// DefaultWorkspace is the ID of the workspace used for unassigned contacts.
DefaultWorkspace string `yaml:"default_workspace"`
// Workspaces is the list of defined workspaces.
Workspaces []Workspace `yaml:"workspaces"`
}
WorkspaceConfig holds the workspaces configuration.
func DefaultWorkspaceConfig ¶
func DefaultWorkspaceConfig() WorkspaceConfig
DefaultWorkspaceConfig returns a minimal workspace configuration.
type WorkspaceContainment ¶
type WorkspaceContainment struct {
// Root is the absolute path of the workspace root.
Root string
// Enabled toggles containment enforcement (default: true).
Enabled bool
}
WorkspaceContainment enforces that file operations stay within the workspace root.
func NewWorkspaceContainment ¶
func NewWorkspaceContainment(root string) *WorkspaceContainment
NewWorkspaceContainment creates a containment checker for the given root directory.
func (*WorkspaceContainment) AssertNoSymlinkEscape ¶
func (wc *WorkspaceContainment) AssertNoSymlinkEscape(path string) error
AssertNoSymlinkEscape checks that a path does not traverse through a symlink that points outside the workspace. Unlike AssertSandboxPath, this allows symlinks WITHIN the workspace but blocks those that escape.
func (*WorkspaceContainment) AssertSandboxPath ¶
func (wc *WorkspaceContainment) AssertSandboxPath(path string) (string, error)
AssertSandboxPath validates that the given path resolves to within the workspace root. It resolves symlinks to prevent escape attacks and checks for path traversal. Returns the resolved absolute path or an error if containment is violated.
type WorkspaceManager ¶
type WorkspaceManager struct {
// contains filtered or unexported fields
}
WorkspaceManager manages workspaces and their member assignments. It provides workspace resolution for incoming messages and maintains isolated session stores per workspace.
func NewWorkspaceManager ¶
func NewWorkspaceManager(globalCfg *Config, wsCfg WorkspaceConfig, logger *slog.Logger) *WorkspaceManager
NewWorkspaceManager creates a new workspace manager.
func (*WorkspaceManager) AssignGroup ¶
func (wm *WorkspaceManager) AssignGroup(groupJID, wsID, assignedBy string) error
AssignGroup assigns a group to a workspace.
func (*WorkspaceManager) AssignUser ¶
func (wm *WorkspaceManager) AssignUser(jid, wsID, assignedBy string) error
AssignUser assigns a user to a workspace.
func (*WorkspaceManager) Count ¶
func (wm *WorkspaceManager) Count() int
Count returns the number of workspaces.
func (*WorkspaceManager) Create ¶
func (wm *WorkspaceManager) Create(ws Workspace, createdBy string) error
Create creates a new workspace.
func (*WorkspaceManager) DefaultID ¶ added in v1.16.0
func (wm *WorkspaceManager) DefaultID() string
DefaultID returns the current default workspace ID.
func (*WorkspaceManager) Delete ¶
func (wm *WorkspaceManager) Delete(wsID, deletedBy string) error
Delete removes a workspace (members go back to default).
func (*WorkspaceManager) DeleteSessionByID ¶
func (wm *WorkspaceManager) DeleteSessionByID(sessionID string) bool
DeleteSessionByID removes a session by ID across all workspaces.
func (*WorkspaceManager) ExportSession ¶
func (wm *WorkspaceManager) ExportSession(id string) *SessionExport
ExportSession exports a session's history and metadata by hash ID.
func (*WorkspaceManager) FindSessionByID ¶
func (wm *WorkspaceManager) FindSessionByID(id string) *Session
FindSessionByID searches all workspace session stores for a session by its hash ID.
func (*WorkspaceManager) Get ¶
func (wm *WorkspaceManager) Get(wsID string) (*Workspace, bool)
Get returns a workspace by ID.
func (*WorkspaceManager) GetForUser ¶
func (wm *WorkspaceManager) GetForUser(jid string) (*Workspace, bool)
GetForUser returns the workspace assigned to a user JID.
func (*WorkspaceManager) GetSessionByID ¶
func (wm *WorkspaceManager) GetSessionByID(sessionID string) (*Session, *Workspace)
GetSessionByID finds a session by ID (format "channel:chatID") across all workspaces.
func (*WorkspaceManager) List ¶
func (wm *WorkspaceManager) List() []*Workspace
List returns all workspaces.
func (*WorkspaceManager) ListAllSessions ¶
func (wm *WorkspaceManager) ListAllSessions() []SessionInfo
ListAllSessions returns session metadata from all workspaces.
func (*WorkspaceManager) ListSessionsForWorkspace ¶ added in v1.16.0
func (wm *WorkspaceManager) ListSessionsForWorkspace(wsID string) []SessionInfo
ListSessionsForWorkspace returns sessions for a specific workspace only.
func (*WorkspaceManager) RebuildMaps ¶ added in v1.16.0
func (wm *WorkspaceManager) RebuildMaps()
RebuildMaps rebuilds the user, group, and channel maps from all workspaces. Call after Update() when member/group/channel assignments may have changed.
func (*WorkspaceManager) Resolve ¶
func (wm *WorkspaceManager) Resolve(channel, chatID, senderJID string, isGroup bool) *ResolvedWorkspace
Resolve determines which workspace a message belongs to and returns the workspace along with its isolated session.
func (*WorkspaceManager) ResolveByNameOrID ¶ added in v1.16.0
func (wm *WorkspaceManager) ResolveByNameOrID(input string) (*Workspace, bool)
Resolve returns a workspace by ID first, then falls back to normalized name match. This allows lookups like "agentdev" to find an agent named "AgentDev" even if the ID is different (e.g. "tester"). Returns the workspace and its canonical ID so callers can use the real ID for subsequent operations.
func (*WorkspaceManager) SessionCount ¶
func (wm *WorkspaceManager) SessionCount() int
SessionCount returns the total number of sessions across all workspaces.
func (*WorkspaceManager) SessionCountForWorkspace ¶ added in v1.16.0
func (wm *WorkspaceManager) SessionCountForWorkspace(wsID string) int
SessionCountForWorkspace returns the number of active sessions in a workspace.
func (*WorkspaceManager) SetDefault ¶ added in v1.16.0
func (wm *WorkspaceManager) SetDefault(wsID string) error
SetDefault marks a workspace as the default and unmarks all others.
func (*WorkspaceManager) SetPersistence ¶
func (wm *WorkspaceManager) SetPersistence(p SessionPersister)
SetPersistence propagates a SessionPersister to all workspace session stores and stores it for newly created workspaces.
func (*WorkspaceManager) StartPruners ¶
func (wm *WorkspaceManager) StartPruners(ctx context.Context)
StartPruners starts session pruning for all workspace session stores.
func (*WorkspaceManager) UnassignUser ¶
func (wm *WorkspaceManager) UnassignUser(jid string)
UnassignUser removes a user from their workspace (goes to default).
Source Files
¶
- abort.go
- access.go
- agent.go
- agent_router.go
- agent_tools.go
- apply_patch.go
- assistant.go
- block_streamer.go
- browser_act.go
- browser_snapshot.go
- browser_tabs.go
- browser_tool.go
- builtin_skills.go
- canvas_host.go
- codebase_tools.go
- commands.go
- compaction_pipeline.go
- compaction_safeguard.go
- config.go
- config_watcher.go
- context_engine.go
- context_router.go
- context_window_guard.go
- coordinator.go
- daemon_manager.go
- db.go
- db_hub_tools.go
- db_migrate.go
- db_tools.go
- destructive_tracker.go
- dev_utils.go
- directives.go
- docker_tools.go
- dream.go
- env_tools.go
- events.go
- exec_analysis.go
- exec_approval.go
- failover_coordinator.go
- git_tools.go
- group_chat.go
- group_policy.go
- heartbeat.go
- hooks.go
- ide_extensions.go
- identity.go
- keyring.go
- lanes.go
- lcm.go
- lcm_assembler.go
- lcm_compaction.go
- lcm_retrieval.go
- lcm_store.go
- lcm_tools.go
- legacy_aliases.go
- link_understanding.go
- llm.go
- loader.go
- maintenance_manager.go
- markdown.go
- mcp_manager.go
- mcp_tools.go
- media_enrichment.go
- media_registry.go
- media_tools.go
- memory_categorizer.go
- memory_extractor.go
- memory_hardening.go
- memory_hierarchy_config.go
- memory_hierarchy_tools.go
- memory_indexer.go
- memory_stack.go
- memory_tools.go
- message_queue.go
- message_split.go
- metrics_collector.go
- model_failover.go
- multiuser.go
- ops_tools.go
- pairing.go
- palace_bot_commands.go
- plugin_tools.go
- product_tools.go
- project.go
- project_adapter.go
- prompt_layers.go
- provider_discovery.go
- queryloop.go
- queue_modes.go
- scheduler_tools.go
- session.go
- session_lock.go
- session_persistence.go
- session_persistence_sqlite.go
- session_reaper.go
- session_tools.go
- settings.go
- skill_creator.go
- skill_db.go
- skill_db_tools.go
- skill_watcher.go
- startup.go
- stop_hooks.go
- stream_sanitizer.go
- subagent.go
- sys_unix.go
- system_commands.go
- system_tools.go
- system_types.go
- tailscale.go
- testing_tools.go
- tool_call_id.go
- tool_executor.go
- tool_guard.go
- tool_guard_audit_sqlite.go
- tool_loop_detection.go
- tool_mutation.go
- tool_outcomes.go
- tool_profiles.go
- tool_result_truncation.go
- transcript_policy.go
- typing_controller.go
- usage_tracker.go
- vault.go
- vault_tools.go
- web_fetch_readability.go
- webhooks.go
- workspace.go
- workspace_containment.go
Directories
¶
| Path | Synopsis |
|---|---|
|
Package kg implements a bitemporal knowledge graph backed by SQLite.
|
Package kg implements a bitemporal knowledge graph backed by SQLite. |
|
patterns
Package patterns defines the YAML schema and loader for extraction rule sets.
|
Package patterns defines the YAML schema and loader for extraction rule sets. |
|
Package memory – embeddings.go implements embedding generation for semantic search.
|
Package memory – embeddings.go implements embedding generation for semantic search. |
|
Package security – audit.go implements security auditing for DevClaw configuration.
|
Package security – audit.go implements security auditing for DevClaw configuration. |