Commit Graph

136 Commits

Author SHA1 Message Date
Matthew Meszaros 4f9e6e6282 feat: full attribution on every AI credit charge — new actor_user_id + context jsonb columns on the transaction log (migration 000070), a typed models.CreditContext carried via request context (models.WithCreditMeta) so base charges, usage settles, web-search fees, and refunds all inherit it without signature churn, wired at every spend site (campaign switches record campaign/step/contact, automation nodes and Ask AI record automation/node/run and the question asked, reply drafts and inbox agent record the thread, the dashboard agent records the session, research records contact/run, and manual features record the triggering user), rendered as a detail line with token counts in the billing transaction log with corrected reason labels, and documented in the AI credits guide 2026-07-18 08:52:16 +02:00
Matthew Meszaros 163d3057de feat: add web-search and extended-thinking capabilities to the campaign switch AI decider — a per-step web lookup about the contact's company (query derived from contact fields only, results fenced as untrusted, +1 credit charged only when results land, wired through a new tasks SetAISearch) and a thinking toggle that routes to the stronger model tier with a 2048-token budget priced through usage metering, with editor toggles under Capabilities and sequences/ai-credits docs 2026-07-18 08:42:08 +02:00
Matthew Meszaros 053ca6a71d feat: usage-based AI credit system — every AI call reserves its flat minimum then settles the real token cost per model (light 1500/standard 400 tokens per credit, drain-to-zero overage settle wired into writing assistant, reply drafts, dashboard agent, inbox agent, research, automation nodes, and campaign switches), org spend controls in a new org_ai_settings table (day/week/month hard limits enforced in Consume, low-balance alert threshold, auto top-up config), a credit-watch monitor hook that fires BILLING_CREDITS_LOW realtime alerts once per day and buys the configured pack off-session via a new Stripe AutoTopUpCredits (idempotent on the PaymentIntent, bounded per month, Redis-locked), GET /subscription/credits/usage + GET/PATCH settings endpoints, and an AI usage & spend controls billing card (spend vs limits, 30-day chart, per-feature and per-model breakdowns, limits/reminder/auto-top-up form) with a realtime low-credit toast 2026-07-18 08:39:41 +02:00
Matthew Meszaros 30d4277bba feat: harden switch value matching and restyle the decider picker — normalized comparison ignores casing and collapses whitespace, /pattern/ case names become case-insensitive regexes (validated at write time, plain cases checked before regex cases, first match wins, no substring fuzziness so 'not interested' never lands on 'interested'), and the Decided by control becomes two icon cards with descriptions matching the step-type switcher 2026-07-18 08:06:26 +02:00
Matthew Meszaros f36c1a5001 feat: replace the campaign AI step with a Switch step — a multi-way router whose cases are rows on the canvas node, each with its own draggable source dot (per-case ai_label branches wired by handle, retarget on re-drag, purple case edges with no IF boxes, bottom dot as the otherwise fallback), decided per contact by an AI prompt (1 credit, fenced context, same credit lifecycle) or a free deterministic template-value match, with a mode toggle + case list editor (stale case paths healed on save), drag-to-empty-canvas creating the target and wiring the case, and sequences/ai-credits/automation docs rewritten for the switch 2026-07-18 05:42:50 +02:00
Matthew Meszaros 4399bb8e82 feat: collapse the campaign AI step to a prompt plus draggable named outcome paths — the connections drawn out of the step are the choice set (outcome names live on the ai_label branch conditions, deduped per step and read at run time), drop the ai_labels/ai_output_fields/ai_actions config and the whole AI action palette (side effects are ordinary action steps placed on the chosen path), and fence the contact's email, profile fields, and automation event data as untrusted content in every campaign and automation AI prompt so injected instructions inside replies are ignored 2026-07-18 05:18:24 +02:00
Matthew Meszaros 273dd7ce33 feat: merge main (deliverability auth-state sweep, watch-band cold throttle, research roadmap) plus the 000067 email-auth-state migration renumber into the campaign AI step branch 2026-07-17 18:29:06 +02:00
Matthew Meszaros ad794bb184 feat: document the AI step and AI branching — sequences guide (AI steps, AI-picked tag choices, context controls, AI-label paths with inline label creation), automations guides (Ask AI branch, per-label classify routing), and the AI credits cost table entries for campaign AI steps and Ask AI branches 2026-07-17 16:26:58 +00:00
Matthew Meszaros cd5e1e9cf7 Merge pull request #72 from warmbly/research/warmup-abuse-cold-effectiveness
feat: deliverability research + observe-only SPF/DKIM/DMARC auth state and watch-band cold throttle
2026-07-17 05:29:58 +02:00
Matthew Meszaros e5a6643e2f feat: apply the warmup watch-band volume multiplier (0.7x) to cold campaign sends via the shared adjustmentFor helper so a watch-state mailbox slows cold volume before it hard-quarantines 2026-07-17 03:21:29 +00:00
Matthew Meszaros 5b7d29c766 Merge pull request #70 from warmbly/domain-inbox-placement
feat: deliverability score + per-provider/per-domain inbox placement on the dashboard
2026-07-16 18:02:02 +02:00
Matthew Meszaros 1e1e357c06 feat: add a 0-100 deliverability score plus per-provider seed placement and per-domain warmup placement breakdowns to GET /analytics/deliverability, surface them on a customizable deliverability dashboard (toggleable sections + persisted view), and document the new fields in the guides and API reference 2026-07-16 17:55:34 +02:00
Matthew Meszaros 968e43cf2d feat: collapse the sandbox quick start from six terminals to four by starting the core stack with make dev instead of infra+run+web 2026-07-16 09:51:32 +02:00
Matthew Meszaros f7ae908439 feat: rework the local development docs around make dev - new One command section with SEED/AI_PROVIDER variants, Rust/Elixir moved to optional prerequisites, and the stale manual-env-exports-plus-air native section rewritten around the pre-wired make targets 2026-07-16 09:51:32 +02:00
Matthew Meszaros d0e8bc1c97 feat: add one-command MCP OAuth connect on api.warmbly.com/v1/mcp — RFC 7591 dynamic client registration for public PKCE clients (dcr.go), RFC 9728 protected-resource metadata + WWW-Authenticate challenge via MCPAuthMiddleware, /v1/mcp now accepts an API key or OAuth token, public-client auth with no secret and mandatory PKCE reusing the existing OAuth 2.1 server (nullable-org clients, migration 000066), executable-redirect-scheme hardening on the open register endpoint, plus mcp/oauth/authentication/endpoints docs 2026-07-16 08:57:19 +02:00
Matthew Meszaros 30e8d3c13a feat: restyle the docs site without decorative sidebar icons (frontmatter icons dropped, lucide source plugin disabled, AGENTS.md conventions updated), add LangTab language-logo code tabs, and document the new agent tools plus panel resize/placement/shortcuts in the assistant guide and MCP reference 2026-07-16 07:50:24 +02:00
Matthew Meszaros d64c1ddcf7 feat: give the assistant a serious monochrome AgentMark logomark (panel header, empty state, top bar), center single-line composer text against the send button, add minimize-to-dock with a live bottom-right status bar (working/step count, needs approval, response ready), unseen dots on tabs, and a live status badge on the header spark button 2026-07-16 06:52:30 +02:00
Matthew Meszaros a913e73837 feat: seed the sandbox org's AI-credit ledger (plan monthly allowance + a 5000-credit purchased top-up with idempotent grant transactions) so the assistant never reports out-of-credits in the demo; re-seeding refills both pools 2026-07-16 06:52:30 +02:00
Matthew Meszaros e64b0b161d feat: sweep stale OPENAI_API_KEY/AI_LOCAL_MODEL mentions out of comments, the provider-not-configured and warmup-admin error strings, env.example, and the deployment guide now that AI_* is the only config surface 2026-07-16 06:39:07 +02:00
Matthew Meszaros afc5e9d6e5 feat: document AI_PROVIDER-based provider selection (presets, OpenRouter model switching, free local model) across the deployment guide, local development, AI credits, and env reference 2026-07-16 06:14:19 +02:00
Matthew Meszaros 2a3b91cde1 feat: document the free local model path across the deployment guide, local development, the AI assistant guide, and AI credits, and fix the assistant voice-profile link 2026-07-15 18:52:07 +02:00
Matthew Meszaros 9af21d2115 feat: document the new GET /ai/sessions/:id/messages assistant transcript endpoint in the API endpoints reference 2026-07-15 17:54:16 +02:00
Matthew Meszaros 40740e17a3 feat: document the campaign lead statuses (queued, processing, done, replied, bounced, unsubscribed) in the campaigns guide 2026-07-15 17:54:03 +02:00
Matthew Meszaros 7f895f0f42 docs: document the inbox agent grounds drafts in the contact's CRM record and skips trivial one-line replies so users understand when a draft appears and what it is based on 2026-07-14 07:33:47 +02:00
Matthew Meszaros 1dd1bf7098 docs: cross-link the inbox agent from the unibox reply-drafts guide so users discover the automatic-drafting option from the manual Draft reply flow, noting it still never sends on its own 2026-07-14 07:32:46 +02:00
Matthew Meszaros 56de65380b feat: inbox agent that drafts a suggested unibox reply on inbound human replies for human approve/edit/discard - paid + per-org opt-in (organizations.inbox_agent_enabled) feature where the consumer's reply hook, on a non-automated reply, detaches a goroutine (panic-contained, never blocks ingest) that checks entitlement, dedupes via ai_thread_drafts partial unique indexes (one pending per thread, unique source_message_id), pre-checks balance, grounds a reply in the thread history + org voice + skills via generation.Provider.Complete, reserves a draft row then charges 5 credits (idempotency inbox_agent:<draft.ID>, row unwound on a fresh context if the charge fails so no unpaid draft lingers), and emits an org-scoped AI_DRAFT_READY event gated on access_unibox; the agent never sends - only a human POST to /unibox/agent-drafts/:id/approve sends through the normal reply path, claiming pending->approved before send with an approved->pending revert on send failure, alongside list + discard endpoints; plus the unibox awaiting_agent_draft badge + agent_drafts search scope, an AgentDraftCard in the thread view with inline-editable approve-and-send/discard, the workspace settings opt-in toggle, CanUseInboxAgent paid gate, migration 000065, and docs (inbox-agent guide, endpoints, realtime) 2026-07-14 06:13:27 +02:00
Matthew Meszaros a067bf5922 feat: AI action nodes in automations - ai_classify/ai_extract/ai_generate run one generation.Provider completion per node over the event data and merge the result back as a variable (ai_class, output_keys[], ai_text) so downstream conditions branch on it, charging 1 credit per node with a run_id+node_id idempotency key, refund on provider failure, out-of-credits fails only that node while the run continues, and a per-automation ai_credit_failures counter (migration 000064) auto-pauses a flow after 20 consecutive credit misses; classify/extract run deterministic (temperature 0), dry-run executes AI nodes for real and is charged but never touches the auto-pause lifecycle, provider + credit ledger wired into both backend and consumer integration services, plus the reply-classifier Layer 3 ported off its bespoke OpenAI client onto the platform provider via an injected ModelClassifyFunc (platform-paid, deterministic), a CompletionRequest.Temperature primitive threaded through the OpenAI and Anthropic providers, the flow builder palette/config panels/validation for the three AI steps, and a new AI-steps-in-automations guide 2026-07-14 05:30:55 +02:00
Matthew Meszaros 24a932c439 feat: Warmbly MCP server exposing the tool registry to any MCP client at /api/v1/mcp - a streamable-HTTP JSON-RPC endpoint (initialize/tools/list/tools/call/ping) authenticated by API key, where tools/list reflects only the static tools the key's permission mask allows and tools/call runs them gated by each tool's RequiredAPIPerm, send-class tools are never exposed or callable, per-key rate limits and usage logging apply, and the org's own connected MCP tools are not re-exposed; plus api/mcp.mdx documenting the connection url, bearer auth, the tool catalog, and Claude Code/Desktop and Cursor client configs, linked from endpoints and authentication 2026-07-13 20:11:21 +02:00
Matthew Meszaros 2aec6745fa feat: connect external MCP servers whose tools the AI assistant can use - ai_mcp_servers table with bearer tokens sealed by the org DEK cipher (never returned) and SSRF-validated https urls, a dependency-free streamable-HTTP JSON-RPC client (initialize/tools/list/tools/call over safehttp dial-time IP blocking with SSE+JSON handling and body caps), an mcp service that discovers tools on connect and contributes only enabled servers' tools to the dashboard agent as namespaced mcp_<server>_<tool> defs that are always write-class and never auto-allowed, a registry DynamicToolSource hook so per-org tools join the agent's tool set and resume executes them through ToolDefs, /ai/connections CRUD gated on manage_settings with an mcp_server audit entity and spine, a Connections settings page to add servers and review/enable discovered tools, and docs 2026-07-13 20:05:24 +02:00
Matthew Meszaros a2f50b6572 feat: org AI skills (playbooks) that every AI feature loads and follows - ai_skills table (org-scoped, unique name per org, 32KB content cap) with a skills service exposing CRUD plus an enabled-skills preamble injected into the dashboard agent, contact research, and reply-draft prompts and a load_skill read-tool that returns a playbook's full content by name, /ai/skills CRUD gated on manage_settings (JWT) or the AI_AGENT scope (API) with an ai_skill audit entity and spine entry, an AI skills settings page (list rows opening a right-side drawer with name, one-line description, enable toggle, and a markdown body), and docs with two example playbooks 2026-07-13 19:46:25 +02:00
Matthew Meszaros f48d51bf16 feat: AI contact research agent that gathers cited web findings per contact with sync and background-batch runs - contact_research_runs table plus a strict save_research schema (every signal and public_artifact must carry a url, confidence high/medium/low, signals<=5 hooks<=3, reject-and-reprompt once then fail), a text/template runtime prompt injecting org voice, contact record, objective, and 5-search/6-fetch budgets, a research service that drives search_web/fetch_url through the provider loop and charges 2 credits on save (billable even for nothing_found, refund-free since charged only on save, balance and abuse-cap pre-checked so a capped org never does free work), POST/GET /contacts/:id/research plus a 500-cap /contacts/research/batch draining through a bounded pool of 4 workers over FOR-UPDATE-SKIP-LOCKED claims (no new Kafka), an org-scoped AI_RESEARCH_PROGRESS realtime event gated to view_contacts, APIPermAIResearch bit 23, a ContactEdit Research tab and a ContactsTable bulk Research action, and docs; also org-scopes every credit and research idempotency key so a client-supplied Idempotency-Key can never replay across tenants 2026-07-13 19:34:11 +02:00
Matthew Meszaros 8d208d8c41 feat: org voice profile grounding every AI writing surface plus context-grounded unibox reply drafts - organizations gains product_description/icp_notes/voice_profile (000059) with a manage_settings workspace settings section, generation.BuildVoiceRules and BuildReplyRules fold the humanizer rules and org grounding into every prompt, WritingGenerator.GenerateWriting now takes a VoiceContext and a provider.Complete primitive powers single completions, POST /unibox/reply/draft assembles thread history plus the counterpart contact (custom fields and campaigns) plus the voice profile into a reply-tuned prompt that charges 2 credits with refund-on-failure and a client idempotency key and never sends, a Draft reply button fills the composer, and docs cover the voice profile and AI reply drafts 2026-07-13 19:04:57 +02:00
Matthew Meszaros 7f425c1624 feat: dashboard-wide AI assistant with streamed tool-use runs, per-action approvals, and per-iteration credits - agent_sessions/agent_messages/ai_tool_policies migration, aiagent service runs the M2 registry through the provider loop over a resumable jsonb transcript, streams text/tool-step/approval/done events over SSE, gates write tools behind approve/deny/always-allow (send always per-action) and charges 1 credit per iteration (budget 20, refund on provider failure, out-of-credits 402 insufficient_credits, cap 429 usage_cap_exceeded) with a resume-safe idempotency namespace, provider PreIteration budget hook, /ai/sessions endpoints (cursor list + two SSE runs) gated by membership with tools bound to the member's org-permission bits, APIPermAIAgent bit 22, ai_session audit entity + spine, and a right-side resizable panel (Cmd+I / sparkle button) with streamed text, collapsible tool steps, inline approval and draft-artifact deep-link cards, stop, new chat, and a credits/budget meter; tenancy enforced at the SQL layer and docs for the assistant, endpoints, permissions, and error codes 2026-07-13 18:46:43 +02:00
Matthew Meszaros 5d6ed2a068 feat: AI credit economy with monthly plan grants, non-expiring purchased top-ups, and Stripe billing - two-pool credit_ledger (monthly allowance reset each cycle on invoice.paid, purchased pool via checkout mode=payment fulfilled webhook-only), consume drains monthly-then-purchased, 3 fixed top-up packs, /subscription/credits balance+checkout+paginated transactions gated on manage_billing, one-time trial grant, billing credits card with balance ring and pack buttons, credit_purchase/credit_grant audit entities and spine, wired plan.monthly_credits through pg_plan reads/writes, retry-safe webhook idempotency, and an AI credits guide 2026-07-13 17:40:20 +02:00
Matthew Meszaros d6b7885e8b feat: mobile push notifications end to end - APNs provider-token client, device_tokens table with session-scoped register/delete endpoints, a push channel in notification preferences (web + iOS toggles), and Redis-backed immediate-then-digest batching (first event pushes now, bursts summarize when the 5h window closes) wired in backend and consumer, with iOS registration/badge sync and docs for the channel, endpoints, and APNS_* deploy env 2026-07-13 16:11:15 +02:00
Matthew Meszaros 9a3551c5ea feat: document the sandbox at /development/sandbox/ (quick start, seeded data, architecture of the simulation, env vars, demo script, troubleshooting) and refresh /development/local-development/ with dovecot, the sandbox target, and the emulator host.docker.internal callback note 2026-07-11 17:31:58 +02:00
Matthew Meszaros c3b99e598b Merge pull request #64 from warmbly/feature/ios-dashboard-app
Native iOS dashboard app: browsers, onboarding flows, mailbox connect, analytics, branding
2026-07-11 10:59:59 +02:00
Matthew Meszaros 07a6777536 feat: email OAuth callback page gains a native-app fallback - when there is no web opener to postMessage (an ASWebAuthenticationSession has no popup parent) it redirects to warmbly://email-oauth with provider/code/state/error so the iOS app can finish the connect; web popup behavior is unchanged and the docs describe both delivery paths 2026-07-11 10:13:10 +02:00
Matthew Meszaros cc0871d1b8 feat: contacts search gains an additive lead_status filter plus per-status lead_counts on the first page when exactly one campaign_id is set - the SQL predicates reproduce the read-time status derivation exactly (unsubscribed > bounced > replied > active > pending via LATERAL bool_or rollups), invalid lead_status or multi-campaign combinations return 400, and the web types/table pick up the new lead_counts shape 2026-07-11 10:11:36 +02:00
Matthew Meszaros 3acb51df6c feat: add server-side status-bucket filtering to GET /campaigns (draft/active/paused/completed, paused matches every paused_* variant, invalid values 400) and a new GET /campaigns-overview endpoint returning status and per-folder counts, with the campaigns API reference and endpoint scope map updated 2026-07-07 09:40:27 +02:00
Matthew Meszaros 13f193d91e feat: unibox list filters - from now matches sender addresses by case-insensitive substring as documented, and a new uncategorized=true param returns only threads with no labels, documented in the unibox API reference 2026-07-07 05:56:47 +02:00
Matthew Meszaros a20ba926cb feat: add native Apple/Google sign-in to the backend - POST /auth/apple and /auth/google exchange provider-signed ID tokens for sessions, GET /auth/providers exposes configured providers for app discovery, with a JWKS-verifying idtoken package, auth config, stable error codes, and API/security docs 2026-07-07 05:56:35 +02:00
Matthew Meszaros 6df48f626e chore: update the README top banner to the new Figma branding export (1600x533 JPG, ~108KB, smaller than the previous banner) 2026-07-06 06:28:11 +02:00
Matthew Meszaros 041ae5afd5 feat: resolve inbound bounce events back to the original campaign send by message id and record them idempotently through the deliverability pipeline (suppression, campaign progress, breaker), and document permanent-only bounce detection 2026-07-04 11:36:47 +02:00
Matthew Meszaros 1e8236d685 feat: only reply to warmup messages received between 45 minutes and 7 days ago so replies follow a plausible read, and document the human-behavior timing model in the warmup guide 2026-07-04 11:27:36 +02:00
Matthew Meszaros 4fe0689d50 feat: document the Graph-backed Outlook connection and the recipient-side warmup folder categorization in the mailboxes and warmup guides 2026-07-04 08:07:50 +02:00
Matthew Meszaros 36bfaf2e71 Merge pull request #55 from warmbly/automation-realtime-editing
Dashboard-wide real-time collaboration: live cursors, collaborative canvases, sticky positions, and live CRM
2026-07-02 20:43:36 +02:00
Matthew Meszaros 76d7e09c29 feat: document the cursor-chat permission gate and the live:select keep-alive and expiry semantics in the realtime API reference and the collaboration guide 2026-07-02 20:33:44 +02:00
Matthew Meszaros 6d1944a19c feat: mention live selection outlines and the / cursor chat in the automation builder and sequence editor guides so the builder docs match the shared-canvas behavior 2026-07-02 20:00:50 +02:00
Matthew Meszaros b00e307d6a feat: document cursor chat, the live:select selection event, and jump-to-teammate in the realtime API reference and the collaboration guide 2026-07-02 07:40:07 +02:00