Matthew Meszaros
|
ed5e577ed0
|
feat: rebuild the AI assistant as a multi-tab workspace with a session history rail, expand-to-workspace mode, per-tab streaming, transcript rehydration and starter prompts
|
2026-07-15 17:54:16 +02:00 |
|
Matthew Meszaros
|
fd36061901
|
feat: make the campaign live-activity empty state status-aware so a finished campaign reads as all caught up instead of waiting for the next send
|
2026-07-15 17:54:03 +02:00 |
|
Matthew Meszaros
|
e7414f9f3b
|
feat: surface the Done lead status in the campaign Leads table pill and the progress strip as a distinct indigo state
|
2026-07-15 17:54:03 +02:00 |
|
Matthew Meszaros
|
a0f92ab284
|
feat: sidebar live panel shows a connected-but-quiet workspace as green READY with a solid halo and an active one as pulsing LIVE, leaving gray only for a real disconnect so IDLE no longer looks offline
|
2026-07-15 17:54:03 +02:00 |
|
Matthew Meszaros
|
a6ccd90090
|
feat: lock plan-gated sidebar tabs and pop an upgrade dialog on click - a feature the org's plan doesn't include now renders a locked, dimmed sidebar row (lock icon + plan badge) that opens an access dialog on click instead of routing to a teasing empty upsell page, mirroring how permission-gated tabs already lock and pop AccessLockedDialog; the dialog gains a plan variant (sparkle, 'X is on the Starter plan', Upgrade CTA to billing for owners / 'ask the owner' for everyone else) so every no-access sidebar tab - by role permission or by plan - consistently locks and explains itself
|
2026-07-15 07:04:00 +02:00 |
|
Matthew Meszaros
|
aa6a6a8525
|
feat: show the recipient address on the inbox-agent draft card so a reviewer sees who the suggested reply will go to before approving and sending
|
2026-07-14 07:33:09 +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
|
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
|
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
|
c311529576
|
feat: guard cursor chat against IME composition keys, keep a sent message lingering through an incidental blur, broadcast chat typed while the pointer is off the tracked surface, and close the input on page navigation
|
2026-07-02 20:33:44 +02:00 |
|
Matthew Meszaros
|
226e83683c
|
feat: remount the automation and sequence canvases on param-only navigation and restrict jump-to-teammate to distinct in-app paths so a jump can never save one record's graph into another
|
2026-07-02 20:33:44 +02:00 |
|
Matthew Meszaros
|
954759a6ce
|
feat: make each teammate in the header presence dropdown clickable to jump straight to the page they are on
|
2026-07-02 07:40:07 +02:00 |
|
Matthew Meszaros
|
9f2b5d5586
|
feat: show each teammate's selected cards on the automation and sequence canvases as a name-tagged outline in their cursor color, with a selection heartbeat for late joiners and an unmount clear, plus cursor chat on both canvases
|
2026-07-02 07:40:06 +02:00 |
|
Matthew Meszaros
|
b1e68b3048
|
feat: add cursor chat to every collaborative surface, press / to type a message that floats next to your live cursor for teammates, riding the existing cursor frames with Enter-to-send and a linger-then-fade
|
2026-07-02 07:40:06 +02:00 |
|
Matthew Meszaros
|
18fd48bfcb
|
feat: render teammate avatars with initials fallback on live cursors so it is always clear who each pointer belongs to
|
2026-06-30 10:34:14 +02:00 |
|
Matthew Meszaros
|
5f090287c8
|
feat: claim mailbox presence and show teammate viewers in the mailbox details drawer header
|
2026-06-30 10:06:49 +02:00 |
|
Matthew Meszaros
|
06c7a3502b
|
feat: wire live cursors, live step drag, and persisted step positions seeded from x/y into the campaign sequence builder canvas
|
2026-06-30 10:06:49 +02:00 |
|
Matthew Meszaros
|
03453cc069
|
feat: wire live cursors, live card drag, and debounced drag-to-stick layout persistence into the automation builder canvas
|
2026-06-30 10:06:49 +02:00 |
|
Matthew Meszaros
|
ba6847e985
|
feat: add the global per-route multiplayer cursor layer with a suppression context and mount it in AppShell around the page scroll container
|
2026-06-30 10:06:31 +02:00 |
|
Matthew Meszaros
|
49988fb8bd
|
feat: add shared Cursor and CanvasCursors presence components that render teammate pointers in screen space and @xyflow flow space
|
2026-06-30 10:06:31 +02:00 |
|
Matthew Meszaros
|
2c910dcdeb
|
feat: make a campaign step's Original a first-class weighted A/B arm driven by a single draggable traffic-split bar, persisting the control share as an is_control variant row
|
2026-06-15 08:11:53 +02:00 |
|
Matthew Meszaros
|
c5dfa5e4e7
|
feat: remove the HTTP-request action from campaign steps and automations in favor of signed webhooks, keep fire_event for custom payloads, and drop the now-unused outbound quota plumbing
|
2026-06-15 08:11:35 +02:00 |
|
Matthew Meszaros
|
899bdfb2f0
|
fix: stop the automation builder from showing 'Updated by a teammate' when the change was made by the same user elsewhere (e.g. toggling enabled from the automations list) by consulting the global self-mutation signal
|
2026-06-14 11:12:07 +02:00 |
|
Matthew Meszaros
|
fcafac4195
|
refactor: remove the campaign 'notify (webhook)' step type now that the HTTP request step covers outbound calls and there is no webhook setup surface
|
2026-06-14 10:48:06 +02:00 |
|
Matthew Meszaros
|
5cee0375f9
|
fix: let portaled pickers/menus nest inside capture-phase and popover containers via a shared data-floating marker, and migrate the last native date/time inputs (contact activity range, unibox snooze + send-later) to the themed pickers
|
2026-06-14 10:48:06 +02:00 |
|
Matthew Meszaros
|
ab24d8bbc8
|
feat: add a 'Fire event' action and campaign step that publish custom events to the realtime gateway (no public URL), an HTTP-request campaign step, a configurable automation dry-run test with per-step toggles, and fix the false 'updated by a teammate' toast on your own save
|
2026-06-14 09:52:49 +02:00 |
|
Matthew Meszaros
|
b94a053ac9
|
feat: replace native date/time inputs with the themed pickers across the dashboard (audit log, admin audit, CRM tasks/deals, contacts and unibox filters, new meeting, campaign schedule)
|
2026-06-14 09:52:49 +02:00 |
|
Matthew Meszaros
|
736bb3d0c0
|
feat: add themed DatePicker, TimePicker, and DateTimePicker primitives so the dashboard never falls back to native browser date/time controls
|
2026-06-14 09:52:49 +02:00 |
|
Matthew Meszaros
|
9cf56ee0af
|
feat: match the analytics tab's range/metric controls to the deliverability tab (slate-100 track with a white active pill) instead of the dark slate-900 blocks
|
2026-06-14 09:52:49 +02:00 |
|
Matthew Meszaros
|
e3c49fe571
|
feat: move the OAuth apps developer portal into Settings with a multi-step registration onboarding wizard (stepper, animated modal, logo upload) and an animated apps/authorized tab switch
|
2026-06-14 09:52:49 +02:00 |
|
Matthew Meszaros
|
b06a11315f
|
feat: add the OAuth 2.1 dashboard UI: an OAuth apps page (register apps with a scope picker, one-time client secret, rotate, delete, authorized-apps tab with revoke) and a standalone consent screen at /oauth/authorize, plus the API client, hooks, and sidebar entry
|
2026-06-13 14:07:21 +02:00 |
|
Matthew Meszaros
|
a7fc7263a8
|
fix: make HTTP request headers/body placeholders visible with normal input colors and fix the Set variables Add variable button (stop filtering the blank row on edit)
|
2026-06-13 13:27:29 +02:00 |
|
Matthew Meszaros
|
501b5009b4
|
feat: add an on-error branch to automation action nodes (try/catch routing, rose on-error handle, executor follows the error edge and treats the failure as handled instead of failing the run)
|
2026-06-13 13:15:41 +02:00 |
|
Matthew Meszaros
|
9aa3300f46
|
feat: capture per-action output in automation run history (HTTP status/ok, set-variables values, rendered channel/url/message) and render it under each action in the builder History panel
|
2026-06-13 13:11:58 +02:00 |
|
Matthew Meszaros
|
977daf8a01
|
feat: surface the inbound webhook trigger in the automations builder with a copyable per-automation webhook URL and caller-defined payload conditions
|
2026-06-13 13:08:04 +02:00 |
|
Matthew Meszaros
|
534928cfdd
|
feat: add a safe Set-variables (transform) automation node — computes named values from Go templates against the event + prior step output and writes them back for later steps to reuse, running the same sandboxed text/template engine as every other action value (no I/O, no arbitrary code execution)
|
2026-06-13 12:18:45 +02:00 |
|
Matthew Meszaros
|
dfdb304033
|
feat: add the HTTP request / webhook node to the automation builder — method/url/headers/body/output-key editor, registered in the action picker with a globe glyph, surfacing how to read the response in later steps and branch on {{.response.ok}}
|
2026-06-13 12:07:04 +02:00 |
|
Matthew Meszaros
|
71abb12a38
|
feat: stop campaigns silently stalling on a transient scheduler error by retrying instead of completing the task, end past-end-date campaigns cleanly, record scheduler failures to the campaign log, add a campaign-chain reconciler, and surface failures live in the dashboard activity panel
|
2026-06-13 06:27:01 +02:00 |
|
Matthew Meszaros
|
969d53af6d
|
feat: animate the top-left Add-step dropdown the same as the drag-create menu (AnimatePresence scale + fade growing from the top-left) instead of appearing instantly
|
2026-06-12 17:47:05 +02:00 |
|
Matthew Meszaros
|
e321d582dc
|
feat: smoother campaign steps canvas — position-preserving layout (no jump on connect/disconnect), an animated drag-create dropdown, Condition adds the if-branch directly instead of a router you drag from, an open then dot instead of an auto-STOP, then-targets placed to the right for clean branch lanes, and the label-email action
|
2026-06-12 16:44:29 +02:00 |
|
Matthew Meszaros
|
c41205ec9a
|
feat: rework the automation canvas — drag a node's dot to empty for an animated create dropdown (reliable react-flow pane detection), unified dagre spacing for smoother branch lines, and the label-email built-in action gated to reply triggers
|
2026-06-12 16:44:29 +02:00 |
|
Matthew Meszaros
|
5c7045d742
|
fix: open the drag-create dropdown reliably by detecting drops on the react-flow pane (via onConnectStart ref + pane-class check) instead of connectionState.toNode, and route IF-block drags through the menu too so you can chain another condition
|
2026-06-12 12:55:54 +02:00 |
|
Matthew Meszaros
|
aba0878833
|
feat: replace the per-node amber if-dot with a single output dot that opens a drag-drop create menu (email, action, or condition) on release, and add a Condition router node (kind wait) you can chain into nested decision trees
|
2026-06-12 09:51:11 +02:00 |
|
Matthew Meszaros
|
a7a43e0c4c
|
feat: rename the campaign sequences resource to steps across the API and URL (/campaigns/:id/steps), the JSON fields (target_step_id, step_id/step_name/step_index, analytics steps[], create body steps), the web client/models/route segment/labels, the audit step entity type, and the wire-contract docs; internal Go type names and the Kafka avro schema stay
|
2026-06-12 09:38:11 +02:00 |
|
Matthew Meszaros
|
a69bf78b2c
|
feat: move the full email toolset (template picker, save as template, write with AI, content score) into the shared EmailContentEditor and have the original step composer use it too, so every A/B variant has the identical tools as the main email
|
2026-06-12 09:09:34 +02:00 |
|
Matthew Meszaros
|
e7977d7bdf
|
feat: edit a step's email and its A/B variants in one horizontal tab bar (Original as the first tab plus a tab per variant, each showing its split share), with an embedded SequenceView for the original arm
|
2026-06-12 08:39:12 +02:00 |
|
Matthew Meszaros
|
2c4b0a07df
|
feat: give A/B variants the same composer as the main email via a shared EmailContentEditor (subject + body + Edit/Preview render + template validation), so a variant is edited and content-checked exactly like the step's own email
|
2026-06-12 08:32:56 +02:00 |
|