Detailed plan covering network exposure, boundary guard, webhook
validation, file permissions, log sanitization, credential scoping,
CORS hardening, and security profiles. Each task has failing tests
first, then implementation, then verification.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replaces the flaky inline bolt_app creation with a proper subprocess
daemon (slack_daemon.py). The daemon persists independently of the
HTTP request lifecycle, solving the Socket Mode connection dropping.
Features: thread replies, progress updates, message queue, Slack
formatting, PID file for lifecycle management.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
All bot replies (acknowledgment, progress updates, final response)
now use thread_ts to reply in the thread of the user's message.
Keeps the DM conversation clean — one thread per question.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Converts: ## Header → *Header* (bold), **bold** → *bold*,
*italic* → _italic_, ~~strike~~ → ~strike~, [text](url) → <url|text>.
Removes LaTeX and HTML. System prompt updated to use simple markdown
since it gets auto-converted per platform.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1. Ack message: "Message received! Working on it now..."
2. Queue awareness: if another message arrives while processing,
"Message received! Message X in queue, will respond ASAP"
3. Periodic reminders every 60s: "Still working! Will reply ASAP"
4. Response formatting: _format_for_sms() strips markdown headers,
bold/italic, code blocks, LaTeX, image syntax, collapses blanks
5. System prompt: instructs agent to use plain text, short paragraphs,
simple dashes — no markdown/LaTeX that breaks in iMessage/SMS
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1. Initial: "Message received! Working on it now..."
2. Every 60s while processing: "Still working! Will reply ASAP"
3. New message while busy: "Message received! Message X in queue of Y"
4. Responses stripped of markdown (headers, bold, code blocks) for
clean Slack display
5. System prompt updated to prefer plain text over complex markdown
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- test_deep_research_prompt.py (8 tests): date injection, time, day of week,
dynamic generation, response types, tool descriptions, /no_think, Jarvis name
- test_slack_messaging.py (7 tests): connect with/without tokens, error state,
disconnect, handler registration, send without token
- test_connector_health.py (44 tests): all 11 connectors instantiate, have
required methods, report not-connected without creds, have metadata.
Plus KnowledgeStore data presence checks.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The model now knows today's date and time. _build_system_prompt()
generates a fresh prompt with "Today is Saturday, March 28, 2026.
The current time is 02:28 PM." on every agent.run() call.
Fixes: model was hallucinating "January 29, 2025" for date queries.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replaces the rigid deep-research-only prompt with an adaptive one that
classifies queries into 4 types:
1. Casual/conversational — friendly reply, no tools
2. Quick data lookup — one tool call, short answer
3. Deep research — multi-hop, cited report
4. About self — describe capabilities
Tested: casual gets 0 tool calls (6s), quick lookup gets 1 SQL call (17s),
self-description gets 0 calls (17s). Deep research still works as before.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Register sendblue in channels/__init__.py so ChannelRegistry works
- Auto-restore SendBlue bindings on server startup from database,
re-creating ChannelBridge + DeepResearchAgent so webhooks survive
server restarts
- Add sendblue to CLI channel_cmd.py (_get_channel, help text) and
SystemBuilder._resolve_channel() for config.toml support
- Health check endpoint GET /v1/channels/sendblue/health returns
channel_connected, bridge_wired, ready status
- Frontend: SendBlueWizard checks health on mount, shows
"Disconnected" badge with "Reconnect" button when bridge is dead
- Docs: CLI usage, server restart behavior, ngrok re-registration,
troubleshooting table, health check endpoint
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
App Token (xapp-) is required for Socket Mode DMs, not optional.
Removed xoxe- from CLI prompt since session tokens don't work.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When a text arrives via SendBlue:
1. Immediately sends "Message received! Researching your data now..."
2. If the agent takes >45s, sends "Still working — complex query..."
3. Then sends the full research response
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Covers both data connector (read messages) and messaging channel (DM the agent).
Includes the full App Manifest JSON, required scopes table, and all the gotchas
we discovered (Request URL, reinstall requirement, App Token vs Bot Token, etc.).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- When binding a SendBlue channel and no ChannelBridge exists, create
one with a DeepResearchAgent wired to the knowledge store
- Fix _build_deep_research_tools scoping issue via self-import
- Fix model name resolution to fall back to app.state.model
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replaced raw slack-sdk SocketModeClient with slack-bolt App which
properly handles event subscriptions, self-event filtering, and
message routing. Bot says "Message received! Researching now..."
then runs DeepResearchAgent and replies with the research result.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When /api/lines returns no numbers (free/shared line tier), the wizard
now shows a manual input with instructions to copy the phone number
from the "Send from" field in the SendBlue dashboard, instead of
showing an error.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Backend:
- POST /v1/channels/sendblue/verify — validates API keys, auto-fetches
assigned phone numbers from SendBlue GET /api/lines
- POST /v1/channels/sendblue/register-webhook — auto-registers the
/webhooks/sendblue callback URL with SendBlue
- POST /v1/channels/sendblue/test — sends a test iMessage to verify setup
Frontend:
- SendBlueWizard component with multi-step guided flow:
Step 1: "Open SendBlue signup" button (opens in new tab)
Step 2: Paste API Key + Secret → "Verify & Find Number" auto-fetches
Step 3: Shows discovered phone number → "Activate Phone Number"
Step 4: Success state with "Send Test" button
- Active state shows agent's number + test message sender
- Generic channels (Slack, WhatsApp, SMS, local iMessage) listed below
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When user connects Slack in the Messaging tab, the backend now creates
a SlackChannel with Socket Mode, registers a handler that routes incoming
DMs to DeepResearchAgent, and starts listening. Unbinding disconnects
the Socket Mode client.
Requires slack-sdk installed and both bot_token (xoxb-) + app_token (xapp-).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The 2-second polling interval was replacing local messages (with _usage,
_telemetry) with server messages (without those fields). Now stores
metadata in a ref and merges it back when polling refreshes.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The progress indicator now only shows when waitingForResponse or sending
is true, preventing it from persisting after the response arrives due to
stale isAgentWorking/hasPending checks. Agent response bubbles now display
elapsed time, tool call count, and a copy button in an XRay-style footer.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Learning log entries (query_start, tool_call, tool_result, query_complete)
now persist to SQLite and appear in the Logs tab. Fixed result.output->content
attribute name and removed debug print statements.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replace "Run Now" button with "Chat ready" hint when on the Interact
tab so users know they can just type a message without pressing Run.
- Add learning log entries in generate_deep_research() for query start,
tool calls, tool results, query completion, and errors so interactive
queries are visible in the Logs tab.
- Rewrite LogsTab to poll every 5 seconds, merge execution traces with
learning log entries into a unified timeline sorted by timestamp.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Refactor sendAgentMessage to accept onProgress/onContentDelta/onDone
callbacks so the InteractTab can show content as it arrives word by
word, display tool-call progress labels (e.g. "Querying data with
SQL"), and render an elapsed-time footer. The backend now streams
tool_progress SSE events from DeepResearchAgent before the final
content, matching the Chat tab's polished streaming UX.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Added waitingForResponse state that stays true during the entire stream
consumption. Shows a pulsing indicator with descriptive text so the user
knows the agent is working (searching, analyzing, writing report).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1. InteractTab now displays the streamed agent response as a bubble
immediately after it finishes (was being discarded)
2. Connecting a source auto-triggers background ingest into KnowledgeStore
so Google Drive data appears with chunk counts immediately
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The Google OAuth flow runs in a background thread. The frontend now polls
every 3s after connecting to detect when the token arrives, and auto-refreshes
every 10s to catch background completions.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The streaming endpoint was calling engine.stream_full() directly without
tools, so the agent responded as a generic chatbot. Now detects
deep_research agent type and runs the full DeepResearchAgent.run() loop
with knowledge_search, knowledge_sql, scan_chunks, and think tools,
then streams the result as SSE.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The OAuth callback server blocks with handle_request(). Running it in a
daemon thread prevents it from freezing the FastAPI event loop.
Also accept system_prompt kwarg in DeepResearchAgent.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The Interact tab was sending messages without stream:true, so the backend
just stored them as pending without running the agent. Now consumes the
SSE stream and displays the full response.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Covers setup instructions and troubleshooting for all 12 connectors:
Gmail, Google Drive, Calendar, Contacts, Slack, Notion, Granola,
Apple Notes, iMessage, Outlook, Obsidian, Dropbox.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add exchange_google_token() and run_oauth_flow() to oauth.py for the
full authorization code exchange. Update gdrive, gcalendar, and
gcontacts connectors to trigger the browser-based OAuth flow when a
client_id:client_secret pair is provided, prefer access_token over raw
token, and require an actual access_token for is_connected(). auth_url()
now returns the Cloud Console credentials page when no client_id is
stored.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Connected sources now show a "Reconnect" button that expands the inline setup
flow to re-enter credentials. Sources with 0 chunks show "Connected — no data
synced yet" in amber instead of "0 items" in green.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Remove duplicate gmail OAuth entry, rename gmail_imap to gmail in frontend
so it matches the backend connector ID that has the actual data.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>