- Add admin DAV tab (rename from CalDAV/CardDAV) and Pushover tab
- Add per-user Pushover tab (User Key only; App Token stays admin-managed)
- Remove system-wide CalDAV/CardDAV fallback — per-user config only
- Rewrite contacts_tool.py using httpx directly (caldav 2.x dropped AddressBook)
- Fix CardDAV REPORT/PROPFIND using SOGo URL pattern
- Fix CalDAV/CardDAV test endpoints (POST method, URL scheme normalization)
- Fix Show Password button — API now returns actual credential values
- Convert Credentials tab to generic key-value store; dedicated keys
(CalDAV, Pushover, trusted_proxy) excluded via _DEDICATED_CRED_KEYS
1042 lines
75 KiB
HTML
1042 lines
75 KiB
HTML
{% extends "base.html" %}
|
|
{% block title %}{{ agent_name }} - Help{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="help-layout">
|
|
|
|
<!-- ── Left: TOC sidebar ─────────────────────────────────────────────── -->
|
|
<aside class="help-toc">
|
|
<input
|
|
type="search"
|
|
class="form-input"
|
|
placeholder="Search docs…"
|
|
oninput="helpSearch(this.value)"
|
|
style="margin-bottom:16px;font-size:12px;"
|
|
>
|
|
<ul class="toc-list">
|
|
<li><a href="#getting-started">Getting Started</a></li>
|
|
<li>
|
|
<a href="#chat">Chat Interface</a>
|
|
<ul>
|
|
<li><a href="#chat-attachments">File Attachments</a></li>
|
|
<li><a href="#chat-model-picker">Model Picker</a></li>
|
|
<li><a href="#chat-badges">Capability Badges</a></li>
|
|
</ul>
|
|
</li>
|
|
<li><a href="#files">Files</a></li>
|
|
<li>
|
|
<a href="#agents">Agents</a>
|
|
<ul>
|
|
<li><a href="#agents-creating">Creating Agents</a></li>
|
|
<li><a href="#agents-schedule">Scheduling</a></li>
|
|
<li><a href="#agents-prompt-modes">Prompt Modes</a></li>
|
|
<li><a href="#agents-tools">Tool Restrictions</a></li>
|
|
<li><a href="#agents-subagents">Sub-agents</a></li>
|
|
</ul>
|
|
</li>
|
|
<li><a href="#mcp">MCP Servers</a></li>
|
|
<li>
|
|
<a href="#settings">Settings</a>
|
|
<ul>
|
|
{% if current_user and current_user.is_admin %}
|
|
<li><a href="#settings-general">General</a></li>
|
|
<li><a href="#settings-whitelists">Whitelists</a></li>
|
|
<li><a href="#settings-credentials">Credentials</a></li>
|
|
<li><a href="#settings-dav">DAV</a></li>
|
|
<li><a href="#settings-pushover">Pushover</a></li>
|
|
{% endif %}
|
|
<li><a href="#settings-inbox">Inbox</a></li>
|
|
<li><a href="#settings-emailaccounts">Email Accounts</a></li>
|
|
<li><a href="#settings-telegram">Telegram</a></li>
|
|
{% if not (current_user and current_user.is_admin) %}
|
|
<li><a href="#settings-caldav">CalDAV / CardDAV</a></li>
|
|
<li><a href="#settings-pushover">Pushover</a></li>
|
|
{% endif %}
|
|
<li><a href="#settings-webhooks">Webhooks</a></li>
|
|
<li><a href="#settings-profile">Profile</a></li>
|
|
<li><a href="#settings-personality">Personality</a></li>
|
|
<li><a href="#settings-brain">2nd Brain</a></li>
|
|
<li><a href="#settings-mcp">MCP Servers</a></li>
|
|
{% if current_user and current_user.is_admin %}
|
|
<li><a href="#settings-security">Security</a></li>
|
|
<li><a href="#settings-branding">Branding</a></li>
|
|
<li><a href="#settings-apikey">API Key</a></li>
|
|
{% endif %}
|
|
</ul>
|
|
</li>
|
|
{% if current_user and current_user.is_admin %}
|
|
<li><a href="#user-management">User Management</a></li>
|
|
<li><a href="#credentials">Credential Key Reference</a></li>
|
|
{% endif %}
|
|
<li><a href="#api">REST API Reference</a></li>
|
|
<li><a href="#security">Security Model</a></li>
|
|
<li><a href="#messaging">Telegram & Email Inbox</a></li>
|
|
</ul>
|
|
</aside>
|
|
|
|
<!-- ── Right: content ────────────────────────────────────────────────── -->
|
|
<div class="help-content">
|
|
|
|
<!-- ── 1. Getting Started ──────────────────────────────────────────── -->
|
|
<section id="getting-started" data-section>
|
|
<h1>Getting Started</h1>
|
|
|
|
<h2>What is oAI-Web?</h2>
|
|
<p>
|
|
oAI-Web (agent name: <strong>{{ agent_name }}</strong>) is a secure, self-hosted personal AI agent
|
|
built on the Claude API with full tool-use support. It runs on your home server and exposes a clean
|
|
web interface for use inside your local network. The agent can read email, browse the web, manage
|
|
calendar events, read and write files, send push notifications, generate images, and more — all via
|
|
a structured tool-use loop with optional confirmation prompts before side-effects.
|
|
</p>
|
|
|
|
<h2>System Requirements</h2>
|
|
<ul>
|
|
<li>An API key for at least one AI provider: <strong>Anthropic</strong> or <strong>OpenRouter</strong></li>
|
|
<li>Python 3.12+ (or Docker)</li>
|
|
<li><strong>PostgreSQL</strong> (with asyncpg) — the main application database</li>
|
|
<li>PostgreSQL + <strong>pgvector</strong> extension only required if you use the <em>2nd Brain</em> feature (can be the same server)</li>
|
|
</ul>
|
|
|
|
<h2>First-Time Setup Checklist</h2>
|
|
<ol>
|
|
<li>Copy <code>.env.example</code> to <code>.env</code> and set <code>ANTHROPIC_API_KEY</code> (or <code>OPENROUTER_API_KEY</code>), <code>AIDE_DB_URL</code> (PostgreSQL connection string), and <code>DB_MASTER_PASSWORD</code></li>
|
|
<li>Start the server: <code>python -m uvicorn server.main:app --host 0.0.0.0 --port 8080 --reload</code></li>
|
|
<li>On first boot with zero users, you are redirected to <code>/setup</code> to create the first admin account</li>
|
|
<li>Open <a href="/settings">Settings</a> → <strong>Credentials</strong> and add any additional credentials (CalDAV, email, Pushover, etc.)</li>
|
|
<li>Add email recipients via <strong>Settings → Whitelists → Email Whitelist</strong></li>
|
|
<li>Add filesystem directories via <strong>Settings → Whitelists → Filesystem Sandbox</strong> — the agent cannot touch any path outside these directories</li>
|
|
<li>Optionally set <code>system:users_base_folder</code> in Credentials to enable per-user file storage (e.g. <code>/data/users</code>)</li>
|
|
<li>Optionally configure email accounts and Telegram via their respective Settings tabs</li>
|
|
</ol>
|
|
|
|
<h2>Key Concepts</h2>
|
|
<dl>
|
|
<dt>Agent</dt>
|
|
<dd>A configured AI persona with a model, system prompt, optional schedule, and restricted tool set. Agents run headlessly — no confirmation prompts, results logged in run history.</dd>
|
|
<dt>Tool</dt>
|
|
<dd>A capability the AI can invoke: read a file, send an email, fetch a web page, generate an image, etc. Every tool call is logged in the Audit Log.</dd>
|
|
<dt>Confirmation</dt>
|
|
<dd>Before any side-effect tool (send email, write file, delete calendar event) executes in interactive chat, a modal asks you to approve or deny. Agents skip confirmations.</dd>
|
|
<dt>Audit Log</dt>
|
|
<dd>An append-only record of every tool call, its arguments, and outcome. Never auto-deleted unless you configure a retention period.</dd>
|
|
<dt>Credential Store</dt>
|
|
<dd>An AES-256-GCM encrypted key-value store in PostgreSQL. All secrets (API keys, passwords) live here — never in the agent's context window.</dd>
|
|
<dt>User Folder</dt>
|
|
<dd>When <code>system:users_base_folder</code> is set, each user gets a personal folder at <code>{base}/{username}/</code>. Agents and the Files page scope all file access to this folder automatically.</dd>
|
|
</dl>
|
|
|
|
<h2>Quick Start</h2>
|
|
<p>Navigate to the <a href="/">Chat</a> page, type a message and press <kbd>Enter</kbd>. The agent responds, uses tools as needed (you'll see spinning indicators), and may ask for confirmation before sending email or writing files.</p>
|
|
</section>
|
|
|
|
<!-- ── 2. Chat Interface ───────────────────────────────────────────── -->
|
|
<section id="chat" data-section>
|
|
<h1>Chat Interface</h1>
|
|
|
|
<h2>Sending Messages</h2>
|
|
<p>
|
|
Press <kbd>Enter</kbd> to send. Use <kbd>Shift+Enter</kbd> for a newline within your message.
|
|
The <strong>Clear History</strong> button (✕) in the status bar wipes the in-memory conversation for the current session — the agent starts fresh.
|
|
</p>
|
|
|
|
<h2 id="chat-attachments">File Attachments</h2>
|
|
<p>
|
|
The <strong>paperclip button</strong> (📎) in the input bar opens a file picker. Only shown when the active model supports vision or documents. Supported formats:
|
|
</p>
|
|
<ul>
|
|
<li><strong>Images</strong>: JPEG, PNG, GIF, WebP, AVIF — shown as thumbnails in the preview strip</li>
|
|
<li><strong>PDF</strong>: shown as a file chip with the filename in the preview strip</li>
|
|
</ul>
|
|
<p>
|
|
You can also <strong>paste images</strong> directly from the clipboard (Ctrl/Cmd+V in the chat input). Multiple files can be attached in one message. Remove any attachment by clicking the ✕ on its preview chip.
|
|
</p>
|
|
<p class="help-note">
|
|
Attachments are sent inline with the message as base64-encoded data. Large files (especially PDFs) will increase the token count and cost of the request.
|
|
</p>
|
|
|
|
<h2 id="chat-model-picker">Model Picker</h2>
|
|
<p>
|
|
The button in the status bar (bottom of the chat area) shows the currently active model. Click it to open a searchable modal listing all available models from all configured providers. Use arrow keys to navigate, <kbd>Enter</kbd> to select, <kbd>Esc</kbd> to close. Your selection is persisted in <code>localStorage</code> across page loads.
|
|
</p>
|
|
|
|
<h2 id="chat-badges">Capability Badges</h2>
|
|
<p>Small badges in the status bar show what the active model supports:</p>
|
|
<ul>
|
|
<li>🎨 <strong>Image Gen</strong> — can generate images (use via the <code>image_gen</code> tool in agents)</li>
|
|
<li>👁 <strong>Vision</strong> — can read images and PDFs; the attachment button is shown</li>
|
|
<li>🔧 <strong>Tools</strong> — supports tool/function calling</li>
|
|
<li>🌐 <strong>Online</strong> — has live web access built in</li>
|
|
</ul>
|
|
|
|
<h2>Tool Indicators</h2>
|
|
<p>While the agent is working, small badges appear below each message:</p>
|
|
<ul>
|
|
<li><span style="color:var(--accent)">●</span> <strong>Pulsing blue</strong> — tool is currently running</li>
|
|
<li><span style="color:var(--green)">●</span> <strong>Solid green</strong> — tool completed successfully</li>
|
|
<li><span style="color:var(--red)">●</span> <strong>Solid red</strong> — tool failed or returned an error</li>
|
|
</ul>
|
|
|
|
<h2>Confirmation Modal</h2>
|
|
<p>
|
|
When the agent wants to execute a side-effect tool (send email, write/delete a file, send a push notification), a yellow modal appears showing the tool name and arguments. Click <strong>Approve</strong> to proceed or <strong>Deny</strong> to block the action. The agent receives your decision and continues.
|
|
</p>
|
|
|
|
<h2>Pausing the Agent</h2>
|
|
<p>
|
|
The <strong>Pause</strong> button in the sidebar is a global kill switch. While paused, no agent runs, scheduled tasks, inbox processing, or Telegram responses will execute. The button turns green and shows <strong>Resume</strong> when paused. Click it again to re-enable everything.
|
|
</p>
|
|
</section>
|
|
|
|
<!-- ── 3. Files ────────────────────────────────────────────────────── -->
|
|
<section id="files" data-section>
|
|
<h1>Files</h1>
|
|
<p>
|
|
The <a href="/files">Files</a> page is a browser for your personal data folder (provisioned automatically when <code>system:users_base_folder</code> is configured by your admin). It lets you navigate, download, and delete files directly from the web UI.
|
|
</p>
|
|
|
|
<h2>Browsing</h2>
|
|
<ul>
|
|
<li>Click a folder to enter it. Use the breadcrumb trail at the top to navigate back.</li>
|
|
<li>Hidden files (names starting with <code>.</code>) are not shown.</li>
|
|
<li>Columns show file size and last-modified timestamp.</li>
|
|
</ul>
|
|
|
|
<h2>Downloading</h2>
|
|
<ul>
|
|
<li><strong>Download</strong> — downloads an individual file.</li>
|
|
<li><strong>↓ ZIP</strong> — downloads an entire folder (and its contents) as a ZIP archive. The <strong>Download folder as ZIP</strong> button in the header always downloads the current folder.</li>
|
|
</ul>
|
|
|
|
<h2>Deleting Files</h2>
|
|
<p>
|
|
A red <strong>Delete</strong> button appears next to downloadable files. Clicking it shows a confirmation dialog before the file is permanently removed. Deletion is instant and cannot be undone.
|
|
</p>
|
|
<p class="help-note">
|
|
<strong>Protected files</strong>: files whose names start with <code>memory_</code> or <code>reasoning_</code> cannot be deleted from the UI. These are agent memory and decision logs maintained by email handling agents — deleting them would disrupt the agent's continuity.
|
|
</p>
|
|
|
|
<h2>No Folder Configured?</h2>
|
|
<p>
|
|
If the Files page shows "No files folder configured", ask your administrator to set the <code>system:users_base_folder</code> credential to a base path (e.g. <code>/data/users</code>). Your personal folder at <code>{base}/{username}/</code> is created automatically.
|
|
</p>
|
|
</section>
|
|
|
|
<!-- ── 4. Agents ───────────────────────────────────────────────────── -->
|
|
<section id="agents" data-section>
|
|
<h1>Agents</h1>
|
|
<p>
|
|
Agents are headless AI personas with a fixed system prompt, model, and optional cron schedule. Unlike interactive chat, agents run without confirmation modals — their allowed tools are declared at creation time. Results and token usage are logged per-run in the <a href="/agents">Agents</a> page.
|
|
</p>
|
|
<p class="help-note">
|
|
Email handling agents (created automatically by Email Accounts setup) are hidden from the Agents list and Status tab. They are managed exclusively via <strong>Settings → Email Accounts</strong>.
|
|
</p>
|
|
|
|
<h2 id="agents-creating">Creating an Agent</h2>
|
|
<p>Click <strong>New Agent</strong> on the Agents page. Required fields:</p>
|
|
<ul>
|
|
<li><strong>Name</strong> — displayed in the UI and logs</li>
|
|
<li><strong>Model</strong> — any model from a configured provider</li>
|
|
<li><strong>Prompt</strong> — the agent's task description or system prompt (see Prompt Modes below)</li>
|
|
</ul>
|
|
<p>Optional fields:</p>
|
|
<ul>
|
|
<li><strong>Description</strong> — shown in the agent list for reference</li>
|
|
<li><strong>Schedule</strong> — cron expression for automatic runs</li>
|
|
<li><strong>Allowed Tools</strong> — restrict which tools the agent may use</li>
|
|
<li><strong>Max Tool Calls</strong> — per-run limit (overrides the system default)</li>
|
|
<li><strong>Sub-agents</strong> — toggle to allow this agent to create child agents</li>
|
|
<li><strong>Prompt Mode</strong> — controls how the prompt is composed (see below)</li>
|
|
</ul>
|
|
|
|
<h2 id="agents-schedule">Scheduling</h2>
|
|
<p>Enter a cron expression in the <strong>Schedule</strong> field. The format is:</p>
|
|
<pre>minute hour day-of-month month day-of-week</pre>
|
|
<p>Examples:</p>
|
|
<ul>
|
|
<li><code>0 8 * * 1-5</code> — weekdays at 08:00</li>
|
|
<li><code>*/15 * * * *</code> — every 15 minutes</li>
|
|
<li><code>0 9 * * 1</code> — every Monday at 09:00</li>
|
|
<li><code>30 18 * * *</code> — every day at 18:30</li>
|
|
</ul>
|
|
<p>
|
|
Use the <strong>Enable / Disable</strong> toggle to pause a schedule without deleting the agent.
|
|
The <strong>Run Now</strong> button triggers an immediate run regardless of schedule.
|
|
</p>
|
|
|
|
<h2 id="agents-prompt-modes">Prompt Modes</h2>
|
|
<p>Three modes control how the agent prompt is combined with the standard system prompt (SOUL.md + security rules):</p>
|
|
<dl>
|
|
<dt>Combined <em>(default)</em></dt>
|
|
<dd>The agent prompt is prepended as the highest-priority instruction. The standard system prompt (SOUL.md, date/time, USER.md, security rules) is appended after. Best for most agents.</dd>
|
|
<dt>System only</dt>
|
|
<dd>The standard system prompt is used as-is; the agent prompt becomes the task message sent to the agent. Useful when you want {{ agent_name }}'s full personality but just need to specify a recurring task.</dd>
|
|
<dt>Agent only</dt>
|
|
<dd>The agent prompt <em>fully replaces</em> the system prompt — no SOUL.md, no security rules, no USER.md context. Use with caution. Suitable for specialized agents with a completely different persona.</dd>
|
|
</dl>
|
|
|
|
<h2 id="agents-tools">Tool Restrictions</h2>
|
|
<p>
|
|
Leave <strong>Allowed Tools</strong> blank to give the agent access to all tools. Select specific tools to restrict — only those tool schemas are sent to the model, making it structurally impossible to use undeclared tools.
|
|
</p>
|
|
<p>
|
|
MCP server tools appear as a single server-level toggle (e.g. <code>Gitea MCP</code>), which enables all tools from that server. Individual built-in tools are listed separately.
|
|
</p>
|
|
<p>Follow the <strong>least-privilege principle</strong>: give each agent only the tools it actually needs.</p>
|
|
|
|
<h2 id="agents-subagents">Sub-agents</h2>
|
|
<p>
|
|
Enable the <strong>Sub-agents</strong> toggle to give an agent access to the <code>create_subagent</code> tool. This allows the agent to spin up child agents to handle parallel or specialized tasks. Sub-agents run synchronously (the parent waits for the child to finish) and are logged separately in run history with <code>parent_agent_id</code> set.
|
|
</p>
|
|
|
|
<h2>Image Generation in Agents</h2>
|
|
<p>
|
|
Agents can generate images using the <code>image_gen</code> tool. Important: the <strong>agent model must be a text/tool-use model</strong> (e.g. Claude Sonnet), not an image-generation model. The <code>image_gen</code> tool calls the image-gen model internally, saves the result to disk, and returns the file path. The default image-gen model is <code>openrouter:openai/gpt-5-image</code> — override via the <code>system:default_image_gen_model</code> credential.
|
|
</p>
|
|
<p>
|
|
Generated images are saved to the agent's user folder. The file path is returned as the tool result so the agent can reference it.
|
|
</p>
|
|
</section>
|
|
|
|
<!-- ── 5. MCP Servers ─────────────────────────────────────────────── -->
|
|
<section id="mcp" data-section>
|
|
<h1>MCP Servers</h1>
|
|
<p>
|
|
<strong>MCP (Model Context Protocol)</strong> is an open protocol for exposing tools to AI models over a network. oAI-Web can connect to external MCP servers and use their tools exactly like built-in tools. Tool names are namespaced as <code>mcp__{server}__{tool}</code>.
|
|
</p>
|
|
|
|
<h2>Requirements for a Compatible MCP Server</h2>
|
|
<p>To be compatible with oAI-Web, an MCP server must:</p>
|
|
<ul>
|
|
<li>Expose an SSE endpoint at <code>/sse</code></li>
|
|
<li>Use <strong>SSE transport</strong> (not stdio)</li>
|
|
<li>Be compatible with <code>mcp==1.26.*</code></li>
|
|
<li>If built with Python FastMCP: use <code>uvicorn.run(mcp.sse_app(), host=..., port=...)</code> — <strong>not</strong> <code>mcp.run(host=..., port=...)</code> (the latter ignores <code>host</code>/<code>port</code> in mcp 1.26)</li>
|
|
<li>If connecting from a non-localhost IP (e.g. <code>192.168.x.x</code>): disable DNS rebinding protection:
|
|
<pre>from mcp.server.transport_security import TransportSecuritySettings
|
|
mcp = FastMCP(
|
|
"my-server",
|
|
transport_security=TransportSecuritySettings(
|
|
enable_dns_rebinding_protection=False
|
|
),
|
|
)</pre>
|
|
Without this, the server rejects requests with a <code>421 Misdirected Request</code> error.
|
|
</li>
|
|
<li>oAI-Web connects per-call (open → use → close), <em>not</em> persistent — the server must handle this gracefully</li>
|
|
</ul>
|
|
|
|
<h2>Adding an MCP Server</h2>
|
|
<ol>
|
|
<li>Go to <strong>Settings → MCP Servers</strong></li>
|
|
<li>Click <strong>Add Server</strong></li>
|
|
<li>Enter:
|
|
<ul>
|
|
<li><strong>Name</strong> — display name; also used for tool namespacing (slugified)</li>
|
|
<li><strong>URL</strong> — full SSE endpoint, e.g. <code>http://192.168.1.72:8812/sse</code></li>
|
|
<li><strong>Transport</strong> — select <code>sse</code></li>
|
|
<li><strong>API Key</strong> — optional bearer token if the server requires authentication</li>
|
|
</ul>
|
|
</li>
|
|
<li>Click <strong>Save</strong></li>
|
|
</ol>
|
|
<p>oAI-Web will immediately attempt to connect and discover tools. The tool count is shown in the server list.</p>
|
|
|
|
<h2>Tool Namespacing</h2>
|
|
<p>
|
|
A server named <code>Gitea MCP</code> (slugified: <code>gitea_mcp</code>) exposes tools as <code>mcp__gitea_mcp__list_repos</code>, <code>mcp__gitea_mcp__create_issue</code>, etc.
|
|
In the agent tool picker, the entire server appears as a single toggle — enabling it grants access to all of its tools.
|
|
</p>
|
|
|
|
<h2>Refreshing Tool Discovery</h2>
|
|
<p>
|
|
Click <strong>Refresh</strong> on any server in <strong>Settings → MCP Servers</strong> to re-discover tools without restarting oAI-Web. Useful after adding new tools to an MCP server.
|
|
</p>
|
|
</section>
|
|
|
|
<!-- ── 6. Settings Walkthrough ────────────────────────────────────── -->
|
|
<section id="settings" data-section>
|
|
<h1>Settings</h1>
|
|
|
|
{% if current_user and current_user.is_admin %}
|
|
<h2 id="settings-general">General <small style="font-weight:400;font-size:12px;color:var(--text-dim)">(Admin)</small></h2>
|
|
<ul>
|
|
<li><strong>Agent Control</strong>: Pause / Resume the global kill switch</li>
|
|
<li><strong>Runtime Limits</strong>: Max Tool Calls (per run) and Max Autonomous Runs per Hour — stored in the credential store for live override without restart</li>
|
|
<li><strong>Trusted Proxy IPs</strong>: Comma-separated IPs for <code>X-Forwarded-For</code> trust (requires restart)</li>
|
|
<li><strong>Users Base Folder</strong>: Set <code>system:users_base_folder</code> to an absolute path (e.g. <code>/data/users</code>) to enable per-user file storage. Each user's folder at <code>{base}/{username}/</code> is created automatically.</li>
|
|
<li><strong>Audit Log Retention</strong>: Set a retention period in days (0 = keep forever); manual clear available</li>
|
|
</ul>
|
|
|
|
<h2 id="settings-whitelists">Whitelists <small style="font-weight:400;font-size:12px;color:var(--text-dim)">(Admin)</small></h2>
|
|
<ul>
|
|
<li><strong>Email Whitelist</strong>: Only addresses on this list can receive emails from {{ agent_name }}. Supports per-address daily send limits.</li>
|
|
<li><strong>Web Whitelist (Tier 1)</strong>: Domains always accessible to the agent, regardless of session type. Subdomains are automatically included (e.g. <code>wikipedia.org</code> covers <code>en.wikipedia.org</code>).</li>
|
|
<li><strong>Filesystem Sandbox</strong>: Absolute paths the agent may read/write. The agent cannot access any path outside these directories (unless it falls within a user's personal folder). Add directories before using filesystem tools.</li>
|
|
</ul>
|
|
|
|
<h2 id="settings-credentials">Credentials <small style="font-weight:400;font-size:12px;color:var(--text-dim)">(Admin)</small></h2>
|
|
<p>
|
|
A generic AES-256-GCM encrypted key-value store for API keys and other secrets. Keys use a <code>namespace:key</code> convention. Service-specific credentials (CalDAV, CardDAV, Pushover) are managed in their own dedicated tabs — they do not appear here. See the <a href="#credentials">Credential Key Reference</a> for a full list of system keys.
|
|
</p>
|
|
|
|
<h2 id="settings-dav">DAV (CalDAV & CardDAV) <small style="font-weight:400;font-size:12px;color:var(--text-dim)">(Admin)</small></h2>
|
|
<p>
|
|
Configure CalDAV and CardDAV for the admin user. There is no system-wide fallback — every user configures their own credentials independently via this tab (admin) or the <strong>CalDAV / CardDAV</strong> tab (regular users).
|
|
</p>
|
|
<ul>
|
|
<li><strong>CalDAV</strong>: server URL, username, password, and calendar name. Bare hostnames (e.g. <code>mail.example.com</code>) are accepted — <code>https://</code> is prepended automatically.</li>
|
|
<li><strong>CardDAV</strong>: tick <em>Same server as CalDAV</em> to reuse the same credentials, or enter a separate URL, username, and password. The SOGo URL pattern (<code>/SOGo/dav/{user}/Contacts/personal/</code>) is built automatically.</li>
|
|
<li><strong>Allow contact writes</strong>: when enabled, agents can create, update, and delete contacts (not just read them). This is per-user — enabling it for your account does not affect other users.</li>
|
|
<li><strong>Test buttons</strong>: verify CalDAV and CardDAV connectivity without saving.</li>
|
|
</ul>
|
|
|
|
<h2 id="settings-pushover">Pushover <small style="font-weight:400;font-size:12px;color:var(--text-dim)">(Admin)</small></h2>
|
|
<p>
|
|
Pushover sends push notifications to iOS and Android devices.
|
|
</p>
|
|
<ul>
|
|
<li><strong>App Token</strong>: registered once at <a href="https://pushover.net" target="_blank">pushover.net</a> for this oAI-Web installation. Shared by all users — they cannot see or change it.</li>
|
|
<li><strong>User Key</strong>: the admin's personal Pushover user key, shown on your pushover.net dashboard. Each user sets their own User Key in <strong>Settings → Pushover</strong>.</li>
|
|
</ul>
|
|
{% endif %}
|
|
|
|
<h2 id="settings-inbox">Inbox</h2>
|
|
<p>
|
|
The Inbox tab manages <strong>trigger rules</strong> for the legacy global IMAP/SMTP account. For per-user or multi-account email handling, use the <strong>Email Accounts</strong> tab instead.
|
|
</p>
|
|
<ul>
|
|
<li><strong>Trigger Rules</strong>: keyword phrases that, when matched in an incoming email subject/body, dispatch a specific agent and optionally send an auto-reply</li>
|
|
<li>Matching is case-insensitive and order-independent — all tokens in the phrase must appear somewhere in the message</li>
|
|
</ul>
|
|
|
|
<h2 id="settings-emailaccounts">Email Accounts</h2>
|
|
<p>
|
|
Email Accounts is the main email management area, separate from the legacy Inbox tab. Each account is independently configured with its own IMAP/SMTP credentials and an account type:
|
|
</p>
|
|
<dl>
|
|
<dt>Trigger account</dt>
|
|
<dd>Uses IMAP IDLE (instant push). Dispatches agents based on keyword trigger rules in incoming emails.</dd>
|
|
<dt>Handling account</dt>
|
|
<dd>Polls every 60 seconds. A dedicated AI agent reads and handles each email. The agent gets access to email, Telegram (optional), and filesystem tools scoped to the user's data folder.</dd>
|
|
</dl>
|
|
<p>For handling accounts, you can also configure:</p>
|
|
<ul>
|
|
<li><strong>Extra tools</strong>: optionally give the handling agent access to Telegram and/or Pushover for notifications</li>
|
|
<li><strong>Telegram keyword</strong>: a short slug (e.g. <code>work</code>) that creates a <code>/work</code> Telegram command. Send <code>/work <message></code> to interact with the email agent via Telegram. Built-in sub-commands: <code>/work pause</code>, <code>/work resume</code>, <code>/work status</code></li>
|
|
<li><strong>Pause / Resume</strong>: temporarily suspend a handling account without disabling it entirely. Also available via the Telegram <code>/keyword pause</code> command</li>
|
|
</ul>
|
|
<p class="help-note">
|
|
The handling agent uses memory files (<code>memory_<username>.md</code>) and reasoning logs (<code>reasoning_<username>.md</code>) stored in the user's data folder to maintain continuity across email sessions. These files are visible in the Files page but cannot be deleted there.
|
|
</p>
|
|
|
|
<h2 id="settings-telegram">Telegram</h2>
|
|
<ul>
|
|
<li><strong>Bot Token</strong>: your Telegram bot's API token (from @BotFather). Admins set a global token here; non-admin users can set their own per-user token in their Profile tab.</li>
|
|
<li><strong>Chat ID Whitelist</strong>: only messages from listed chat IDs are processed</li>
|
|
<li><strong>Default Agent</strong>: agent dispatched for messages that don't match any trigger rule</li>
|
|
<li><strong>Trigger Rules</strong>: same keyword-matching logic as email inbox</li>
|
|
</ul>
|
|
|
|
{% if not (current_user and current_user.is_admin) %}
|
|
<h2 id="settings-caldav">CalDAV / CardDAV</h2>
|
|
<p>
|
|
Configure your personal CalDAV and CardDAV connection. There is no system-wide fallback — if you don't configure it, the tools are unavailable to you.
|
|
</p>
|
|
<ul>
|
|
<li><strong>CalDAV</strong>: server URL, username, password, and calendar name. Bare hostnames are accepted — <code>https://</code> is added automatically.</li>
|
|
<li><strong>CardDAV</strong>: tick <em>Same server as CalDAV</em> to reuse credentials, or enter separate details.</li>
|
|
<li><strong>Allow contact writes</strong>: when enabled, agents can create, update, and delete contacts.</li>
|
|
<li><strong>Test buttons</strong>: verify connectivity before saving.</li>
|
|
</ul>
|
|
|
|
<h2 id="settings-pushover">Pushover</h2>
|
|
<p>
|
|
Set your personal <strong>User Key</strong> to receive push notifications on your Pushover-connected devices. Your User Key is shown on your <a href="https://pushover.net" target="_blank">pushover.net</a> dashboard. The App Token (the shared application credential) is managed by the admin — you only need your own User Key.
|
|
</p>
|
|
{% endif %}
|
|
|
|
<h2 id="settings-webhooks">Webhooks</h2>
|
|
<p>
|
|
Inbound webhooks let external services trigger agents via HTTP — useful for iOS Shortcuts, GitHub actions, Home Assistant automations, or any tool that can send an HTTP request.
|
|
</p>
|
|
<ul>
|
|
<li><strong>Create a webhook</strong>: assign a name, description, and target agent. The secret token is shown <strong>once</strong> at creation — copy it immediately. Use <em>Rotate Token</em> to generate a new one if it is ever compromised.</li>
|
|
<li><strong>Trigger via POST</strong>: <code>POST /webhook/{token}</code> with body <code>{"message": "..."}</code></li>
|
|
<li><strong>Trigger via GET</strong>: <code>GET /webhook/{token}?q=your+message</code> — useful for iOS Shortcuts URL actions</li>
|
|
<li><strong>Enable/disable</strong>: toggle a webhook on/off without deleting it</li>
|
|
</ul>
|
|
<p>The <strong>Outbound Targets</strong> section (same tab) manages named URLs that agents can send JSON payloads to via the <code>webhook</code> tool.</p>
|
|
|
|
<h2 id="settings-profile">Profile</h2>
|
|
<p>Available to all users. Contains:</p>
|
|
<ul>
|
|
<li><strong>Theme</strong>: choose from 7 built-in themes (Dark, Darker, Light, Nord, Solarized Dark, Gruvbox, Catppuccin Mocha). Applied immediately server-side with no flash of wrong theme.</li>
|
|
<li><strong>Account Info</strong>: username and email (read-only); editable display name</li>
|
|
<li><strong>Change Password</strong>: update your login password</li>
|
|
<li><strong>Two-Factor Authentication (TOTP)</strong>: enable/disable TOTP-based MFA. On setup, a QR code is shown to scan with any authenticator app (e.g. Aegis, Google Authenticator). Once enabled, every login requires a 6-digit code.</li>
|
|
<li><strong>Data Folder</strong>: shows the path of your auto-provisioned personal folder (set by admin via <code>system:users_base_folder</code>). This folder is where the Files page browses and where agent memory files are stored.</li>
|
|
<li><strong>Telegram Bot Token</strong>: per-user Telegram bot token (optional). Overrides the global token for your sessions.</li>
|
|
</ul>
|
|
|
|
<h2 id="settings-personality">Personality</h2>
|
|
<p>
|
|
Edit <strong>SOUL.md</strong> (agent identity, values, communication style) and <strong>USER.md</strong> (owner context: name, location, preferences) directly in the browser. Changes take effect immediately — no restart required.
|
|
Both files are injected into every system prompt in order: SOUL.md → date/time → USER.md → security rules.
|
|
</p>
|
|
|
|
<h2 id="settings-brain">2nd Brain</h2>
|
|
<p>
|
|
Requires PostgreSQL + pgvector (<code>BRAIN_DB_URL</code> env var). When connected, shows connection status, recent captured thoughts, and a manual capture form. The brain MCP server is exposed at <code>/brain-mcp/sse</code> and requires the <code>brain:mcp_key</code> credential for authentication.
|
|
</p>
|
|
|
|
<h2 id="settings-mcp">MCP Servers</h2>
|
|
<p>Add, edit, remove, enable/disable, and refresh external MCP servers. See the <a href="#mcp">MCP Servers</a> section for full setup details.</p>
|
|
|
|
{% if current_user and current_user.is_admin %}
|
|
<h2 id="settings-security">Security <small style="font-weight:400;font-size:12px;color:var(--text-dim)">(Admin)</small></h2>
|
|
<p>Five independently toggleable security options:</p>
|
|
<ol>
|
|
<li><strong>Enhanced Sanitization</strong>: strips extended prompt-injection patterns from all external content</li>
|
|
<li><strong>Canary Token</strong>: a daily-rotating secret injected into the system prompt; if it appears in any tool argument, the call is blocked and you receive a Pushover alert</li>
|
|
<li><strong>LLM Content Screening</strong>: after fetching web/email/file content, sends it to a cheap screening model for a SAFE/UNSAFE verdict before returning it to the agent</li>
|
|
<li><strong>Output Validation</strong>: blocks email auto-replies from inbox sessions back to the trigger sender (prevents exfiltration loops)</li>
|
|
<li><strong>Content Truncation</strong>: caps content length from web fetch, email, and file reads to configurable character limits</li>
|
|
</ol>
|
|
<p>See the <a href="#security">Security Model</a> section for the broader security architecture.</p>
|
|
|
|
<h2 id="settings-branding">Branding <small style="font-weight:400;font-size:12px;color:var(--text-dim)">(Admin)</small></h2>
|
|
<p>
|
|
Customize the sidebar brand name (default: <code>{{ agent_name }}</code>) and logo (default: <code>logo.png</code>). Upload a PNG/JPG/GIF/WebP/SVG logo (max 2 MB). Changes take effect immediately. Reset to defaults by clearing the name field or deleting the logo.
|
|
</p>
|
|
|
|
<h2 id="settings-apikey">API Key <small style="font-weight:400;font-size:12px;color:var(--text-dim)">(Admin)</small></h2>
|
|
<p>
|
|
Protects the REST API for external programmatic access (scripts, home automations, other services, Swagger).
|
|
The <strong>web UI always works without a key</strong> — a signed session cookie is set automatically on login.
|
|
The API key is only required for:
|
|
</p>
|
|
<ul>
|
|
<li>External tools and scripts calling <code>/api/*</code> directly</li>
|
|
<li>Swagger UI (<a href="/docs">/docs</a>) — click <strong>Authorize</strong> and enter the key</li>
|
|
</ul>
|
|
<p>
|
|
The raw key is shown <strong>once</strong> at generation time — copy it to your external tool. Only a SHA-256 hash is stored server-side. Regenerating invalidates the previous key immediately.
|
|
</p>
|
|
<p>
|
|
Use header <code>X-API-Key: <key></code> or <code>Authorization: Bearer <key></code> in external requests.
|
|
If no key is configured, the API is open (home-network default).
|
|
</p>
|
|
{% endif %}
|
|
</section>
|
|
|
|
<!-- ── 7. User Management ──────────────────────────────────────────── -->
|
|
{% if current_user and current_user.is_admin %}
|
|
<section id="user-management" data-section>
|
|
<h1>User Management <small style="font-weight:400;font-size:14px;color:var(--text-dim)">(Admin)</small></h1>
|
|
<p>
|
|
oAI-Web supports multiple users with role-based access. Manage users at <a href="/admin/users">Admin → Users</a>.
|
|
</p>
|
|
|
|
<h2>Roles</h2>
|
|
<dl>
|
|
<dt>Admin</dt>
|
|
<dd>Full access to all settings, whitelists, credentials, and user management. Can see and manage all agents and audit logs across all users.</dd>
|
|
<dt>User</dt>
|
|
<dd>Access to chat, agents, files, and their own settings (Profile, CalDAV, Telegram, Email Accounts, MCP Servers). Cannot access system-wide whitelists, credentials, branding, or security settings.</dd>
|
|
</dl>
|
|
|
|
<h2>Creating Users</h2>
|
|
<ol>
|
|
<li>Go to <a href="/admin/users">Admin → Users</a></li>
|
|
<li>Click <strong>New User</strong></li>
|
|
<li>Enter username, email, password, and select a role</li>
|
|
<li>If <code>system:users_base_folder</code> is configured, a personal folder is created automatically at <code>{base}/{username}/</code></li>
|
|
</ol>
|
|
|
|
<h2>MFA Management</h2>
|
|
<p>
|
|
Users set up their own TOTP in <strong>Settings → Profile → Two-Factor Authentication</strong>. As admin, you can clear any user's MFA from the Users page (useful if they lose their authenticator). The <strong>Clear MFA</strong> button resets their TOTP secret — they must set it up again on next login.
|
|
</p>
|
|
|
|
<h2>User Filesystem Scoping</h2>
|
|
<p>
|
|
Non-admin users' agents automatically receive a <strong>scoped filesystem tool</strong> limited to their personal folder (<code>{base}/{username}/</code>). They cannot access paths outside their folder, even if those paths are in the global filesystem whitelist. Admin agents continue to use the global whitelist-based sandbox.
|
|
</p>
|
|
</section>
|
|
{% endif %}
|
|
|
|
<!-- ── 8. Credential Key Reference ───────────────────────────────── -->
|
|
{% if current_user and current_user.is_admin %}
|
|
<section id="credentials" data-section>
|
|
<h1>Credential Key Reference</h1>
|
|
<p>All keys are stored in the encrypted credential store. System keys use the <code>system:</code> prefix.</p>
|
|
|
|
<div class="table-wrap">
|
|
<table class="help-api-table">
|
|
<thead><tr><th>Key</th><th>Description</th></tr></thead>
|
|
<tbody>
|
|
<tr><td><code>system:paused</code></td><td>Kill switch — set to <code>"1"</code> to pause all agent activity</td></tr>
|
|
<tr><td><code>system:max_tool_calls</code></td><td>Live override of MAX_TOOL_CALLS env var</td></tr>
|
|
<tr><td><code>system:max_autonomous_runs_per_hour</code></td><td>Live override of MAX_AUTONOMOUS_RUNS_PER_HOUR</td></tr>
|
|
<tr><td><code>system:audit_retention_days</code></td><td>Days to keep audit entries (0 = keep forever)</td></tr>
|
|
<tr><td><code>system:trusted_proxy_ips</code></td><td>Comma-separated IPs for X-Forwarded-For trust (requires restart)</td></tr>
|
|
<tr><td><code>system:users_base_folder</code></td><td>Base path for per-user folders (e.g. <code>/data/users</code>). Each user's folder is created at <code>{base}/{username}/</code>.</td></tr>
|
|
<tr><td><code>system:default_image_gen_model</code></td><td>Model used by the <code>image_gen</code> tool (default: <code>openrouter:openai/gpt-5-image</code>)</td></tr>
|
|
<tr><td><code>system:brand_name</code></td><td>Custom sidebar brand name</td></tr>
|
|
<tr><td><code>system:brand_logo_filename</code></td><td>Custom sidebar logo filename in /static/</td></tr>
|
|
<tr><td><code>system:security_sanitize_enhanced</code></td><td>Option 1: enhanced injection pattern sanitization</td></tr>
|
|
<tr><td><code>system:security_canary_enabled</code></td><td>Option 2: canary token detection enabled</td></tr>
|
|
<tr><td><code>system:canary_token</code></td><td>Auto-generated daily canary token (read-only)</td></tr>
|
|
<tr><td><code>system:canary_rotated_at</code></td><td>Timestamp of last canary rotation (read-only)</td></tr>
|
|
<tr><td><code>system:security_llm_screen_enabled</code></td><td>Option 3: LLM content screening enabled</td></tr>
|
|
<tr><td><code>system:security_llm_screen_model</code></td><td>Model for LLM screening (default: google/gemini-flash-1.5)</td></tr>
|
|
<tr><td><code>system:security_llm_screen_block</code></td><td>Option 3 block mode — block vs flag on UNSAFE verdict</td></tr>
|
|
<tr><td><code>system:security_output_validation_enabled</code></td><td>Option 4: output validation for inbox sessions</td></tr>
|
|
<tr><td><code>system:security_truncation_enabled</code></td><td>Option 5: content truncation</td></tr>
|
|
<tr><td><code>system:security_max_web_chars</code></td><td>Max chars from web fetch (default: 20 000)</td></tr>
|
|
<tr><td><code>system:security_max_email_chars</code></td><td>Max chars from email body (default: 6 000)</td></tr>
|
|
<tr><td><code>system:security_max_file_chars</code></td><td>Max chars from file read (default: 20 000)</td></tr>
|
|
<tr><td><code>system:security_max_subject_chars</code></td><td>Max chars of email subject (default: 200)</td></tr>
|
|
<tr><td><code>telegram:bot_token</code></td><td>Global Telegram bot API token</td></tr>
|
|
<tr><td><code>telegram:default_agent_id</code></td><td>UUID of agent for unmatched Telegram messages</td></tr>
|
|
<tr><td><code>pushover_app_token</code></td><td>Pushover App Token — managed via <strong>Settings → Pushover</strong>, not this tab</td></tr>
|
|
<tr><td><code>brain:mcp_key</code></td><td>2nd Brain MCP authentication key</td></tr>
|
|
<tr><td><code>system:api_key_hash</code></td><td>SHA-256 hash of the external API key (raw key never stored)</td></tr>
|
|
<tr><td><code>system:api_key_created_at</code></td><td>Timestamp of last API key generation</td></tr>
|
|
<tr><td><code>system:session_secret</code></td><td>HMAC secret for signing web UI session cookies (auto-generated)</td></tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</section>
|
|
{% endif %}
|
|
|
|
<!-- ── 9. REST API Reference ──────────────────────────────────────── -->
|
|
<section id="api" data-section>
|
|
<h1>REST API Reference</h1>
|
|
<p>
|
|
All endpoints are prefixed with <code>/api</code>. Responses are JSON.
|
|
If an API key is configured (Settings → General → API Key), external requests must include
|
|
<code>X-API-Key: <key></code>. The web UI is exempt via session cookie.
|
|
</p>
|
|
<p class="help-note">
|
|
<strong>API Explorer:</strong> Browse and test endpoints interactively via Swagger UI at
|
|
<a href="/docs" target="_blank"><code>/docs</code></a> or ReDoc at
|
|
<a href="/redoc" target="_blank"><code>/redoc</code></a>.
|
|
Click <strong>Authorize</strong> in Swagger and enter your API key to make authenticated calls.
|
|
</p>
|
|
|
|
<h3>Credentials</h3>
|
|
<div class="table-wrap">
|
|
<table class="help-api-table">
|
|
<thead><tr><th>Method</th><th>Path</th><th>Description</th></tr></thead>
|
|
<tbody>
|
|
<tr><td><span class="http-get">GET</span></td><td><code>/api/credentials</code></td><td>List all credential keys (values not returned)</td></tr>
|
|
<tr><td><span class="http-post">POST</span></td><td><code>/api/credentials</code></td><td>Set a credential <code>{key, value, description}</code></td></tr>
|
|
<tr><td><span class="http-get">GET</span></td><td><code>/api/credentials/{key}</code></td><td>Get a single credential value</td></tr>
|
|
<tr><td><span class="http-del">DELETE</span></td><td><code>/api/credentials/{key}</code></td><td>Delete a credential</td></tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<h3>Audit Log</h3>
|
|
<div class="table-wrap">
|
|
<table class="help-api-table">
|
|
<thead><tr><th>Method</th><th>Path</th><th>Description</th></tr></thead>
|
|
<tbody>
|
|
<tr><td><span class="http-get">GET</span></td><td><code>/api/audit</code></td><td>Paginated audit log; params: <code>start</code>, <code>end</code>, <code>tool</code>, <code>session_id</code>, <code>task_id</code>, <code>confirmed</code>, <code>page</code>, <code>page_size</code></td></tr>
|
|
<tr><td><span class="http-del">DELETE</span></td><td><code>/api/audit</code></td><td>Delete audit entries older than <code>?older_than_days=N</code> (0 = all)</td></tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<h3>API Key</h3>
|
|
<div class="table-wrap">
|
|
<table class="help-api-table">
|
|
<thead><tr><th>Method</th><th>Path</th><th>Description</th></tr></thead>
|
|
<tbody>
|
|
<tr><td><span class="http-get">GET</span></td><td><code>/api/settings/api-key</code></td><td>Returns <code>{configured: bool, created_at}</code> — never returns the raw key</td></tr>
|
|
<tr><td><span class="http-post">POST</span></td><td><code>/api/settings/api-key</code></td><td>Generate a new key — returns <code>{key}</code> once only; invalidates previous key</td></tr>
|
|
<tr><td><span class="http-del">DELETE</span></td><td><code>/api/settings/api-key</code></td><td>Revoke the current key</td></tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<h3>Settings</h3>
|
|
<div class="table-wrap">
|
|
<table class="help-api-table">
|
|
<thead><tr><th>Method</th><th>Path</th><th>Description</th></tr></thead>
|
|
<tbody>
|
|
<tr><td><span class="http-get">GET</span></td><td><code>/api/settings/limits</code></td><td>Current runtime limits</td></tr>
|
|
<tr><td><span class="http-post">POST</span></td><td><code>/api/settings/limits</code></td><td>Update <code>{max_tool_calls, max_autonomous_runs_per_hour}</code></td></tr>
|
|
<tr><td><span class="http-get">GET</span></td><td><code>/api/settings/security</code></td><td>Current security option states</td></tr>
|
|
<tr><td><span class="http-post">POST</span></td><td><code>/api/settings/security</code></td><td>Update security options</td></tr>
|
|
<tr><td><span class="http-get">GET</span></td><td><code>/api/settings/branding</code></td><td>Current brand name and logo URL</td></tr>
|
|
<tr><td><span class="http-post">POST</span></td><td><code>/api/settings/branding</code></td><td>Update <code>{brand_name}</code></td></tr>
|
|
<tr><td><span class="http-post">POST</span></td><td><code>/api/settings/branding/logo/upload</code></td><td>Upload a logo file (multipart)</td></tr>
|
|
<tr><td><span class="http-del">DELETE</span></td><td><code>/api/settings/branding/logo</code></td><td>Reset logo to default</td></tr>
|
|
<tr><td><span class="http-get">GET</span></td><td><code>/api/settings/audit-retention</code></td><td>Current audit retention setting</td></tr>
|
|
<tr><td><span class="http-post">POST</span></td><td><code>/api/settings/audit-retention</code></td><td>Update <code>{days}</code></td></tr>
|
|
<tr><td><span class="http-get">GET</span></td><td><code>/api/settings/caldav</code></td><td>Admin CalDAV & CardDAV config (same as <code>/api/my/caldav/config</code>)</td></tr>
|
|
<tr><td><span class="http-post">POST</span></td><td><code>/api/settings/caldav</code></td><td>Save admin CalDAV & CardDAV config</td></tr>
|
|
<tr><td><span class="http-get">GET</span></td><td><code>/api/settings/pushover</code></td><td>Current Pushover App Token and admin User Key</td></tr>
|
|
<tr><td><span class="http-post">POST</span></td><td><code>/api/settings/pushover</code></td><td>Save App Token and admin User Key</td></tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<h3>Whitelists</h3>
|
|
<div class="table-wrap">
|
|
<table class="help-api-table">
|
|
<thead><tr><th>Method</th><th>Path</th><th>Description</th></tr></thead>
|
|
<tbody>
|
|
<tr><td><span class="http-get">GET</span></td><td><code>/api/email-whitelist</code></td><td>List whitelisted email recipients</td></tr>
|
|
<tr><td><span class="http-post">POST</span></td><td><code>/api/email-whitelist</code></td><td>Add/update <code>{email, daily_limit}</code></td></tr>
|
|
<tr><td><span class="http-del">DELETE</span></td><td><code>/api/email-whitelist/{email}</code></td><td>Remove a recipient</td></tr>
|
|
<tr><td><span class="http-get">GET</span></td><td><code>/api/web-whitelist</code></td><td>List Tier-1 web domains</td></tr>
|
|
<tr><td><span class="http-post">POST</span></td><td><code>/api/web-whitelist</code></td><td>Add <code>{domain, note}</code></td></tr>
|
|
<tr><td><span class="http-del">DELETE</span></td><td><code>/api/web-whitelist/{domain}</code></td><td>Remove a domain</td></tr>
|
|
<tr><td><span class="http-get">GET</span></td><td><code>/api/filesystem-whitelist</code></td><td>List sandbox directories</td></tr>
|
|
<tr><td><span class="http-post">POST</span></td><td><code>/api/filesystem-whitelist</code></td><td>Add <code>{path, note}</code></td></tr>
|
|
<tr><td><span class="http-del">DELETE</span></td><td><code>/api/filesystem-whitelist/{path}</code></td><td>Remove a directory</td></tr>
|
|
<tr><td><span class="http-get">GET</span></td><td><code>/api/filesystem-browser</code></td><td>Server-side directory listing; param: <code>?path=</code></td></tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<h3>Agents & Runs</h3>
|
|
<div class="table-wrap">
|
|
<table class="help-api-table">
|
|
<thead><tr><th>Method</th><th>Path</th><th>Description</th></tr></thead>
|
|
<tbody>
|
|
<tr><td><span class="http-get">GET</span></td><td><code>/api/agents</code></td><td>List agents (excludes email handling agents)</td></tr>
|
|
<tr><td><span class="http-post">POST</span></td><td><code>/api/agents</code></td><td>Create an agent</td></tr>
|
|
<tr><td><span class="http-get">GET</span></td><td><code>/api/agents/{id}</code></td><td>Get agent details</td></tr>
|
|
<tr><td><span class="http-put">PUT</span></td><td><code>/api/agents/{id}</code></td><td>Update agent</td></tr>
|
|
<tr><td><span class="http-del">DELETE</span></td><td><code>/api/agents/{id}</code></td><td>Delete agent</td></tr>
|
|
<tr><td><span class="http-post">POST</span></td><td><code>/api/agents/{id}/run</code></td><td>Trigger immediate run</td></tr>
|
|
<tr><td><span class="http-post">POST</span></td><td><code>/api/agents/{id}/toggle</code></td><td>Enable / disable schedule</td></tr>
|
|
<tr><td><span class="http-get">GET</span></td><td><code>/api/agents/{id}/runs</code></td><td>List runs for an agent</td></tr>
|
|
<tr><td><span class="http-get">GET</span></td><td><code>/api/agent-runs</code></td><td>List recent runs across all agents (excludes email handlers)</td></tr>
|
|
<tr><td><span class="http-get">GET</span></td><td><code>/api/agent-runs/{run_id}</code></td><td>Get a specific run including full result text</td></tr>
|
|
<tr><td><span class="http-post">POST</span></td><td><code>/api/runs/{run_id}/stop</code></td><td>Stop a running agent</td></tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<h3>Models</h3>
|
|
<div class="table-wrap">
|
|
<table class="help-api-table">
|
|
<thead><tr><th>Method</th><th>Path</th><th>Description</th></tr></thead>
|
|
<tbody>
|
|
<tr><td><span class="http-get">GET</span></td><td><code>/api/models</code></td><td>Available model IDs + default</td></tr>
|
|
<tr><td><span class="http-get">GET</span></td><td><code>/api/models/info</code></td><td>Full model metadata: name, context, pricing, capabilities</td></tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<h3>MCP Servers</h3>
|
|
<div class="table-wrap">
|
|
<table class="help-api-table">
|
|
<thead><tr><th>Method</th><th>Path</th><th>Description</th></tr></thead>
|
|
<tbody>
|
|
<tr><td><span class="http-get">GET</span></td><td><code>/api/mcp-servers</code></td><td>List all MCP servers</td></tr>
|
|
<tr><td><span class="http-post">POST</span></td><td><code>/api/mcp-servers</code></td><td>Add a server</td></tr>
|
|
<tr><td><span class="http-put">PUT</span></td><td><code>/api/mcp-servers/{id}</code></td><td>Update a server</td></tr>
|
|
<tr><td><span class="http-del">DELETE</span></td><td><code>/api/mcp-servers/{id}</code></td><td>Remove a server</td></tr>
|
|
<tr><td><span class="http-post">POST</span></td><td><code>/api/mcp-servers/{id}/toggle</code></td><td>Enable / disable a server</td></tr>
|
|
<tr><td><span class="http-post">POST</span></td><td><code>/api/mcp-servers/{id}/refresh</code></td><td>Re-discover tools</td></tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<h3>Telegram & Inbox</h3>
|
|
<div class="table-wrap">
|
|
<table class="help-api-table">
|
|
<thead><tr><th>Method</th><th>Path</th><th>Description</th></tr></thead>
|
|
<tbody>
|
|
<tr><td><span class="http-get">GET</span></td><td><code>/api/telegram/config</code></td><td>Global Telegram bot config</td></tr>
|
|
<tr><td><span class="http-post">POST</span></td><td><code>/api/telegram/config</code></td><td>Save bot token + default agent</td></tr>
|
|
<tr><td><span class="http-get">GET</span></td><td><code>/api/telegram/whitelist</code></td><td>Chat ID whitelist</td></tr>
|
|
<tr><td><span class="http-post">POST</span></td><td><code>/api/telegram/whitelist</code></td><td>Add chat ID</td></tr>
|
|
<tr><td><span class="http-del">DELETE</span></td><td><code>/api/telegram/whitelist/{chat_id}</code></td><td>Remove chat ID</td></tr>
|
|
<tr><td><span class="http-get">GET</span></td><td><code>/api/telegram/triggers</code></td><td>List trigger rules</td></tr>
|
|
<tr><td><span class="http-post">POST</span></td><td><code>/api/telegram/triggers</code></td><td>Create trigger rule</td></tr>
|
|
<tr><td><span class="http-del">DELETE</span></td><td><code>/api/telegram/triggers/{id}</code></td><td>Delete trigger rule</td></tr>
|
|
<tr><td><span class="http-get">GET</span></td><td><code>/api/inbox/config</code></td><td>Legacy IMAP/SMTP configuration</td></tr>
|
|
<tr><td><span class="http-post">POST</span></td><td><code>/api/inbox/config</code></td><td>Save legacy IMAP/SMTP credentials</td></tr>
|
|
<tr><td><span class="http-get">GET</span></td><td><code>/api/inbox/triggers</code></td><td>List email trigger rules</td></tr>
|
|
<tr><td><span class="http-post">POST</span></td><td><code>/api/inbox/triggers</code></td><td>Create email trigger rule</td></tr>
|
|
<tr><td><span class="http-del">DELETE</span></td><td><code>/api/inbox/triggers/{id}</code></td><td>Delete email trigger rule</td></tr>
|
|
<tr><td><span class="http-get">GET</span></td><td><code>/api/inbox/status</code></td><td>Status of all inbox listeners</td></tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<h3>Email Accounts</h3>
|
|
<div class="table-wrap">
|
|
<table class="help-api-table">
|
|
<thead><tr><th>Method</th><th>Path</th><th>Description</th></tr></thead>
|
|
<tbody>
|
|
<tr><td><span class="http-get">GET</span></td><td><code>/api/my/email-accounts</code></td><td>List user's email accounts</td></tr>
|
|
<tr><td><span class="http-post">POST</span></td><td><code>/api/my/email-accounts</code></td><td>Create an email account</td></tr>
|
|
<tr><td><span class="http-put">PUT</span></td><td><code>/api/my/email-accounts/{id}</code></td><td>Update email account</td></tr>
|
|
<tr><td><span class="http-del">DELETE</span></td><td><code>/api/my/email-accounts/{id}</code></td><td>Delete email account</td></tr>
|
|
<tr><td><span class="http-post">POST</span></td><td><code>/api/my/email-accounts/{id}/pause</code></td><td>Pause a handling account</td></tr>
|
|
<tr><td><span class="http-post">POST</span></td><td><code>/api/my/email-accounts/{id}/resume</code></td><td>Resume a paused handling account</td></tr>
|
|
<tr><td><span class="http-post">POST</span></td><td><code>/api/my/email-accounts/list-folders-preview</code></td><td>List IMAP folders using raw credentials (without saving an account)</td></tr>
|
|
<tr><td><span class="http-get">GET</span></td><td><code>/api/my/email-accounts/available-extra-tools</code></td><td>Which notification tools are available for handling accounts</td></tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<h3>Files</h3>
|
|
<div class="table-wrap">
|
|
<table class="help-api-table">
|
|
<thead><tr><th>Method</th><th>Path</th><th>Description</th></tr></thead>
|
|
<tbody>
|
|
<tr><td><span class="http-get">GET</span></td><td><code>/api/my/files</code></td><td>List files/folders in the user's data folder; param: <code>?path=</code></td></tr>
|
|
<tr><td><span class="http-del">DELETE</span></td><td><code>/api/my/files</code></td><td>Delete a file; param: <code>?path=</code>. Protected names (<code>memory_*</code>, <code>reasoning_*</code>) return 403.</td></tr>
|
|
<tr><td><span class="http-get">GET</span></td><td><code>/api/my/files/download</code></td><td>Download a single file; param: <code>?path=</code></td></tr>
|
|
<tr><td><span class="http-get">GET</span></td><td><code>/api/my/files/download-zip</code></td><td>Download a folder as ZIP; param: <code>?path=</code></td></tr>
|
|
<tr><td><span class="http-get">GET</span></td><td><code>/api/my/data-folder</code></td><td>Return the user's provisioned data folder path</td></tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<h3>User Profile & Settings</h3>
|
|
<div class="table-wrap">
|
|
<table class="help-api-table">
|
|
<thead><tr><th>Method</th><th>Path</th><th>Description</th></tr></thead>
|
|
<tbody>
|
|
<tr><td><span class="http-get">GET</span></td><td><code>/api/my/profile</code></td><td>Get display name</td></tr>
|
|
<tr><td><span class="http-post">POST</span></td><td><code>/api/my/profile</code></td><td>Update display name</td></tr>
|
|
<tr><td><span class="http-get">GET</span></td><td><code>/api/my/theme</code></td><td>Get current theme</td></tr>
|
|
<tr><td><span class="http-post">POST</span></td><td><code>/api/my/theme</code></td><td>Set theme <code>{theme_id}</code></td></tr>
|
|
<tr><td><span class="http-get">GET</span></td><td><code>/api/my/mfa/status</code></td><td>Whether MFA is enabled for the current user</td></tr>
|
|
<tr><td><span class="http-post">POST</span></td><td><code>/api/my/mfa/setup/begin</code></td><td>Start MFA setup — returns QR code PNG (base64) and provisioning URI</td></tr>
|
|
<tr><td><span class="http-post">POST</span></td><td><code>/api/my/mfa/setup/confirm</code></td><td>Confirm setup with a valid TOTP code <code>{code}</code></td></tr>
|
|
<tr><td><span class="http-del">DELETE</span></td><td><code>/api/my/mfa/disable</code></td><td>Disable MFA for the current user</td></tr>
|
|
<tr><td><span class="http-get">GET</span></td><td><code>/api/my/caldav/config</code></td><td>Get per-user CalDAV & CardDAV config</td></tr>
|
|
<tr><td><span class="http-post">POST</span></td><td><code>/api/my/caldav/config</code></td><td>Save per-user CalDAV & CardDAV credentials</td></tr>
|
|
<tr><td><span class="http-del">DELETE</span></td><td><code>/api/my/caldav/config</code></td><td>Remove per-user CalDAV & CardDAV config</td></tr>
|
|
<tr><td><span class="http-post">POST</span></td><td><code>/api/my/caldav/test</code></td><td>Test CalDAV connectivity with current saved config</td></tr>
|
|
<tr><td><span class="http-post">POST</span></td><td><code>/api/my/caldav/test-carddav</code></td><td>Test CardDAV connectivity with current saved config</td></tr>
|
|
<tr><td><span class="http-get">GET</span></td><td><code>/api/my/pushover</code></td><td>Get current user's Pushover User Key (masked)</td></tr>
|
|
<tr><td><span class="http-post">POST</span></td><td><code>/api/my/pushover</code></td><td>Save personal User Key <code>{user_key}</code></td></tr>
|
|
<tr><td><span class="http-del">DELETE</span></td><td><code>/api/my/pushover</code></td><td>Remove personal User Key</td></tr>
|
|
<tr><td><span class="http-get">GET</span></td><td><code>/api/my/telegram/whitelisted-chats</code></td><td>List Telegram chat IDs whitelisted for the current user</td></tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<h3>Webhooks</h3>
|
|
<div class="table-wrap">
|
|
<table class="help-api-table">
|
|
<thead><tr><th>Method</th><th>Path</th><th>Description</th></tr></thead>
|
|
<tbody>
|
|
<tr><td><span class="http-get">GET</span></td><td><code>/api/webhooks</code></td><td>List inbound webhook endpoints (admin)</td></tr>
|
|
<tr><td><span class="http-post">POST</span></td><td><code>/api/webhooks</code></td><td>Create endpoint — returns token once (admin)</td></tr>
|
|
<tr><td><span class="http-put">PUT</span></td><td><code>/api/webhooks/{id}</code></td><td>Update name/description/agent/enabled (admin)</td></tr>
|
|
<tr><td><span class="http-del">DELETE</span></td><td><code>/api/webhooks/{id}</code></td><td>Delete endpoint (admin)</td></tr>
|
|
<tr><td><span class="http-post">POST</span></td><td><code>/api/webhooks/{id}/rotate</code></td><td>Regenerate token — returns new token once (admin)</td></tr>
|
|
<tr><td><span class="http-get">GET</span></td><td><code>/api/my/webhooks</code></td><td>List current user's webhook endpoints</td></tr>
|
|
<tr><td><span class="http-post">POST</span></td><td><code>/api/my/webhooks</code></td><td>Create personal webhook endpoint</td></tr>
|
|
<tr><td><span class="http-put">PUT</span></td><td><code>/api/my/webhooks/{id}</code></td><td>Update personal webhook endpoint</td></tr>
|
|
<tr><td><span class="http-del">DELETE</span></td><td><code>/api/my/webhooks/{id}</code></td><td>Delete personal webhook endpoint</td></tr>
|
|
<tr><td><span class="http-get">GET</span></td><td><code>/webhook/{token}</code></td><td>Trigger via GET — param: <code>?q=message</code> (no auth)</td></tr>
|
|
<tr><td><span class="http-post">POST</span></td><td><code>/webhook/{token}</code></td><td>Trigger via POST — body: <code>{"message": "...", "async": true}</code> (no auth)</td></tr>
|
|
<tr><td><span class="http-get">GET</span></td><td><code>/api/webhook-targets</code></td><td>List outbound webhook targets (admin)</td></tr>
|
|
<tr><td><span class="http-post">POST</span></td><td><code>/api/webhook-targets</code></td><td>Create outbound target (admin)</td></tr>
|
|
<tr><td><span class="http-put">PUT</span></td><td><code>/api/webhook-targets/{id}</code></td><td>Update outbound target (admin)</td></tr>
|
|
<tr><td><span class="http-del">DELETE</span></td><td><code>/api/webhook-targets/{id}</code></td><td>Delete outbound target (admin)</td></tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<h3>Monitors</h3>
|
|
<div class="table-wrap">
|
|
<table class="help-api-table">
|
|
<thead><tr><th>Method</th><th>Path</th><th>Description</th></tr></thead>
|
|
<tbody>
|
|
<tr><td><span class="http-get">GET</span></td><td><code>/api/watched-pages</code></td><td>List page-change monitors</td></tr>
|
|
<tr><td><span class="http-post">POST</span></td><td><code>/api/watched-pages</code></td><td>Create page monitor</td></tr>
|
|
<tr><td><span class="http-put">PUT</span></td><td><code>/api/watched-pages/{id}</code></td><td>Update page monitor</td></tr>
|
|
<tr><td><span class="http-del">DELETE</span></td><td><code>/api/watched-pages/{id}</code></td><td>Delete page monitor</td></tr>
|
|
<tr><td><span class="http-post">POST</span></td><td><code>/api/watched-pages/{id}/check-now</code></td><td>Force an immediate check</td></tr>
|
|
<tr><td><span class="http-get">GET</span></td><td><code>/api/rss-feeds</code></td><td>List RSS feed monitors</td></tr>
|
|
<tr><td><span class="http-post">POST</span></td><td><code>/api/rss-feeds</code></td><td>Create RSS feed monitor</td></tr>
|
|
<tr><td><span class="http-put">PUT</span></td><td><code>/api/rss-feeds/{id}</code></td><td>Update RSS feed monitor</td></tr>
|
|
<tr><td><span class="http-del">DELETE</span></td><td><code>/api/rss-feeds/{id}</code></td><td>Delete RSS feed monitor</td></tr>
|
|
<tr><td><span class="http-post">POST</span></td><td><code>/api/rss-feeds/{id}/fetch-now</code></td><td>Force an immediate fetch</td></tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<h3>User Management <small style="color:var(--text-dim)">(Admin)</small></h3>
|
|
<div class="table-wrap">
|
|
<table class="help-api-table">
|
|
<thead><tr><th>Method</th><th>Path</th><th>Description</th></tr></thead>
|
|
<tbody>
|
|
<tr><td><span class="http-get">GET</span></td><td><code>/api/users</code></td><td>List all users</td></tr>
|
|
<tr><td><span class="http-post">POST</span></td><td><code>/api/users</code></td><td>Create a user <code>{username, email, password, role}</code></td></tr>
|
|
<tr><td><span class="http-put">PUT</span></td><td><code>/api/users/{id}</code></td><td>Update user (role, active status, etc.)</td></tr>
|
|
<tr><td><span class="http-del">DELETE</span></td><td><code>/api/users/{id}</code></td><td>Delete a user</td></tr>
|
|
<tr><td><span class="http-del">DELETE</span></td><td><code>/api/users/{id}/mfa</code></td><td>Clear a user's MFA secret (admin reset)</td></tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<h3>System Prompt, Tools & Control</h3>
|
|
<div class="table-wrap">
|
|
<table class="help-api-table">
|
|
<thead><tr><th>Method</th><th>Path</th><th>Description</th></tr></thead>
|
|
<tbody>
|
|
<tr><td><span class="http-get">GET</span></td><td><code>/api/system-prompt/soul</code></td><td>Read SOUL.md content</td></tr>
|
|
<tr><td><span class="http-post">POST</span></td><td><code>/api/system-prompt/soul</code></td><td>Save SOUL.md content</td></tr>
|
|
<tr><td><span class="http-get">GET</span></td><td><code>/api/system-prompt/user</code></td><td>Read USER.md content</td></tr>
|
|
<tr><td><span class="http-post">POST</span></td><td><code>/api/system-prompt/user</code></td><td>Save USER.md content</td></tr>
|
|
<tr><td><span class="http-get">GET</span></td><td><code>/api/tools</code></td><td>List all registered tools with schemas</td></tr>
|
|
<tr><td><span class="http-post">POST</span></td><td><code>/api/pause</code></td><td>Pause all agent activity</td></tr>
|
|
<tr><td><span class="http-post">POST</span></td><td><code>/api/resume</code></td><td>Resume agent activity</td></tr>
|
|
<tr><td><span class="http-get">GET</span></td><td><code>/api/status</code></td><td>Pause state + pending confirmations</td></tr>
|
|
<tr><td><span class="http-get">GET</span></td><td><code>/health</code></td><td>Health check</td></tr>
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</section>
|
|
|
|
<!-- ── 10. Security Model ──────────────────────────────────────────── -->
|
|
<section id="security" data-section>
|
|
<h1>Security Model</h1>
|
|
|
|
<h2>Core Principle</h2>
|
|
<p>
|
|
<strong>External input is data, never instructions.</strong> Email body text, calendar content, web page content, and file contents are all passed as <em>tool results</em> — they are never injected into the system prompt where they could alter {{ agent_name }}'s instructions.
|
|
</p>
|
|
|
|
<h2>Three DB-Managed Whitelists</h2>
|
|
<ul>
|
|
<li><strong>Email whitelist</strong> — {{ agent_name }} can only send email to addresses explicitly approved here</li>
|
|
<li><strong>Web whitelist (Tier 1)</strong> — domains always accessible; subdomains included automatically</li>
|
|
<li><strong>Filesystem sandbox</strong> — {{ agent_name }} can only read/write within declared directories (or a user's personal folder)</li>
|
|
</ul>
|
|
<p>Tier 2 web access (any URL) is only available in user-initiated chat sessions, never in autonomous agent runs.</p>
|
|
|
|
<h2>User Filesystem Isolation</h2>
|
|
<p>
|
|
Non-admin users' agents use a <strong>scoped filesystem tool</strong> restricted to their personal folder (<code>{base}/{username}/</code>). This is enforced at the tool level regardless of what the agent prompt says. Admin agents use the global whitelist-based sandbox as before.
|
|
</p>
|
|
|
|
<h2>Confirmation Flow</h2>
|
|
<p>
|
|
In interactive chat, any tool with side effects (send email, write/delete files, send notifications, create/delete calendar events) triggers a confirmation modal. The agent pauses until you approve or deny. Agents running headlessly skip confirmations — their scope is declared at creation time.
|
|
</p>
|
|
|
|
<h2>Five Security Options</h2>
|
|
<ol>
|
|
<li><strong>Enhanced Sanitization</strong> — removes known prompt-injection patterns from all external content before it reaches the agent</li>
|
|
<li><strong>Canary Token</strong> — a daily-rotating secret in the system prompt; any tool call argument containing the canary is blocked and triggers a Pushover alert, detecting prompt-injection exfiltration attempts</li>
|
|
<li><strong>LLM Content Screening</strong> — a cheap secondary model screens fetched content for malicious instructions; operates in flag or block mode</li>
|
|
<li><strong>Output Validation</strong> — prevents inbox auto-reply loops by blocking outbound emails back to the triggering sender</li>
|
|
<li><strong>Content Truncation</strong> — enforces maximum character limits on web fetch, email, and file content to limit the attack surface of large malicious documents</li>
|
|
</ol>
|
|
|
|
<h2>Audit Log</h2>
|
|
<p>
|
|
Every tool call — arguments, result summary, confirmation status, session ID, task ID — is written to an append-only audit log. Logs are never auto-deleted unless you configure a retention period. View them at <a href="/audit">Audit Log</a>.
|
|
</p>
|
|
|
|
<h2>Kill Switch</h2>
|
|
<p>
|
|
The <strong>Pause</strong> button in the sidebar immediately halts all agent activity: no new runs, no inbox processing, no Telegram responses. The <code>system:paused</code> credential stores the state and is checked before every operation. Individual email handling accounts can also be paused independently via their Telegram keyword command or the Email Accounts UI.
|
|
</p>
|
|
|
|
<h2>No Credentials in Agent Context</h2>
|
|
<p>
|
|
API keys, passwords, and tokens are only accessed by the server-side tool implementations. The agent itself never sees a raw credential — it only receives structured results (e.g. a list of calendar events, a fetched page).
|
|
</p>
|
|
</section>
|
|
|
|
<!-- ── 11. Telegram & Email Inbox ──────────────────────────────────── -->
|
|
<section id="messaging" data-section>
|
|
<h1>Telegram & Email Inbox</h1>
|
|
|
|
<h2>Telegram</h2>
|
|
<p>
|
|
oAI-Web connects to Telegram via long-polling (no webhook required). Admin setup:
|
|
</p>
|
|
<ol>
|
|
<li>Create a bot via @BotFather and copy the bot token</li>
|
|
<li>Go to <strong>Settings → Telegram</strong> and save the bot token</li>
|
|
<li>Add your Telegram chat ID to the whitelist (messages from unlisted IDs are silently dropped)</li>
|
|
<li>Optionally set a default agent for messages that don't match any trigger rule</li>
|
|
<li>Add trigger rules to route specific messages to specific agents</li>
|
|
</ol>
|
|
<p>
|
|
Non-admin users can also set their own Telegram bot token under <strong>Settings → Profile → Telegram Bot Token</strong>. This creates a personal bot that routes to agents and email accounts scoped to that user.
|
|
</p>
|
|
<p>
|
|
Each chat maintains its own conversation history (session ID: <code>telegram:{chat_id}</code>), persisted in memory and reset on server restart.
|
|
</p>
|
|
|
|
<h2>Telegram Keyword Commands (Email Handling)</h2>
|
|
<p>
|
|
When an email handling account has a <strong>Telegram keyword</strong> set (e.g. <code>work</code>), Telegram messages starting with <code>/work</code> are routed directly to that email account's agent. This allows you to interact with the email agent via Telegram without any trigger rules.
|
|
</p>
|
|
<p>Built-in sub-commands (e.g. for keyword <code>work</code>):</p>
|
|
<ul>
|
|
<li><code>/work pause</code> — temporarily pause the email account's listener</li>
|
|
<li><code>/work resume</code> — resume the listener</li>
|
|
<li><code>/work status</code> — show the account's current status</li>
|
|
<li><code>/work <any message></code> — pass the message to the handling agent</li>
|
|
</ul>
|
|
<p class="help-note">
|
|
Only the Telegram chat ID associated with the email account can use its keyword commands. Other chat IDs are rejected.
|
|
</p>
|
|
|
|
<h2>Email Inbox — Trigger Accounts</h2>
|
|
<p>
|
|
Trigger accounts use IMAP IDLE for instant push notification. When a new email arrives:
|
|
</p>
|
|
<ol>
|
|
<li>Subject + body matched against trigger rules; the first match wins</li>
|
|
<li>If matched, the corresponding agent is dispatched; an auto-reply is sent if configured</li>
|
|
<li>If no trigger matches, the email is silently ignored (no default agent for trigger accounts)</li>
|
|
</ol>
|
|
<p>
|
|
Sender whitelist check behavior:
|
|
</p>
|
|
<ul>
|
|
<li>Whitelisted sender + matching trigger → agent runs, reply sent</li>
|
|
<li>Whitelisted sender + no trigger → "no trigger word" reply</li>
|
|
<li>Non-whitelisted sender + matching trigger → agent runs, but Output Validation blocks the reply</li>
|
|
<li>Non-whitelisted sender + no trigger → <strong>silently dropped</strong> (reveals nothing to the sender)</li>
|
|
</ul>
|
|
|
|
<h2>Email Inbox — Handling Accounts</h2>
|
|
<p>
|
|
Handling accounts poll every 60 seconds. A dedicated AI agent reads each new email and decides how to handle it. The agent has access to:
|
|
</p>
|
|
<ul>
|
|
<li><strong>Email tool</strong> — list, read, mark as read, move, create folders</li>
|
|
<li><strong>Filesystem tool</strong> — scoped to the user's data folder (if configured)</li>
|
|
<li><strong>Memory files</strong> — <code>memory_<username>.md</code> (persistent notes) and <code>reasoning_<username>.md</code> (append-only decision log) are injected into each run</li>
|
|
<li><strong>Telegram tool</strong> (optional) — bound to the account's associated chat ID; reply messages automatically include a <code>/keyword <reply></code> footer for easy follow-up</li>
|
|
<li><strong>Pushover tool</strong> (optional, admin only)</li>
|
|
</ul>
|
|
|
|
<h2>Trigger Rule Matching</h2>
|
|
<p>
|
|
Both Telegram and email inbox use the same trigger-matching algorithm:
|
|
</p>
|
|
<ul>
|
|
<li><strong>Case-insensitive</strong> — <code>URGENT</code> matches <code>urgent</code></li>
|
|
<li><strong>Order-independent</strong> — all tokens in the trigger phrase must appear somewhere in the message, but not necessarily in sequence</li>
|
|
<li>Example: trigger phrase <code>daily report</code> matches <em>"Send me the report for the daily standup"</em> but also <em>"Daily summary report please"</em></li>
|
|
</ul>
|
|
</section>
|
|
|
|
</div><!-- .help-content -->
|
|
</div><!-- .help-layout -->
|
|
{% endblock %}
|