Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions .env.local.example
Original file line number Diff line number Diff line change
Expand Up @@ -91,3 +91,15 @@ NEXT_PUBLIC_SITE_URL=https://crm.example.com
# Set this in CI and local development so you can exercise the full
# template UI without a real WABA. Leave unset (or "false") in prod.
# WHATSAPP_TEMPLATES_DRY_RUN=true

# AI assistant (Settings → AI Assistant). Anthropic API key used to
# auto-reply to inbound WhatsApp messages grounded in your knowledge
# base. Leave blank to keep the assistant effectively off — without it
# every inbound is handed straight to a human (the feature fails safe).
# Get one at https://console.anthropic.com → API Keys.
# ANTHROPIC_API_KEY=sk-ant-...

# Optional override of the default model for AI replies. Defaults to
# claude-sonnet-4-6; set claude-haiku-4-5 for a cheaper/faster option.
# The model is also selectable per-account in Settings → AI Assistant.
# AI_DEFAULT_MODEL=claude-sonnet-4-6
5 changes: 5 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,11 @@ jobs:
NEXT_PUBLIC_SUPABASE_ANON_KEY: ci-dummy-anon-key
ENCRYPTION_KEY: '0000000000000000000000000000000000000000000000000000000000000000'
META_APP_SECRET: 'ci-dummy-meta-secret'
# The AI assistant reads ANTHROPIC_API_KEY lazily (only when a reply
# is actually generated), so build/typecheck/test don't strictly
# need it — but provide a placeholder for parity with the other
# secrets and to keep any future module-load read satisfied.
ANTHROPIC_API_KEY: 'ci-dummy-anthropic-key'
steps:
- uses: actions/checkout@v7

Expand Down
378 changes: 378 additions & 0 deletions docs/superpowers/specs/2026-06-25-wacrm-ai-assistant-design.md

Large diffs are not rendered by default.

89 changes: 84 additions & 5 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"test:watch": "vitest"
},
"dependencies": {
"@anthropic-ai/sdk": "^0.106.0",
"@base-ui/react": "^1.5.0",
"@dagrejs/dagre": "^3.0.0",
"@dnd-kit/core": "^6.3.1",
Expand All @@ -59,7 +60,8 @@
"shadcn": "^4.11.0",
"sonner": "^2.0.7",
"tailwind-merge": "^3.6.0",
"tw-animate-css": "^1.4.0"
"tw-animate-css": "^1.4.0",
"unpdf": "^1.6.2"
},
"devDependencies": {
"@tailwindcss/postcss": "^4",
Expand Down
18 changes: 18 additions & 0 deletions src/app/(dashboard)/inbox/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -537,6 +537,23 @@ export default function InboxPage() {
[activeConversation]
);

// Reflect a Take over / Hand back to AI toggle. Mirrors the status /
// assign handlers: patch the list row + active conversation optimistically
// so the header control and the "Needs human" badge update instantly; the
// realtime conversations.UPDATE the Supabase write emits converges the
// same fields as a no-op.
const handleAiHandlingChange = useCallback(
(conversationId: string, updates: Partial<Conversation>) => {
setConversations((prev) =>
prev.map((c) => (c.id === conversationId ? { ...c, ...updates } : c))
);
if (activeConversation?.id === conversationId) {
setActiveConversation((prev) => (prev ? { ...prev, ...updates } : prev));
}
},
[activeConversation]
);

// On mobile (<lg) we show a SINGLE pane — either the list or the
// thread — rather than cramming both side-by-side. Selecting a
// conversation slides the thread in; the thread's back button pops
Expand Down Expand Up @@ -601,6 +618,7 @@ export default function InboxPage() {
onUpdateMessage={handleUpdateMessage}
onStatusChange={handleStatusChange}
onAssignChange={handleAssignChange}
onAiHandlingChange={handleAiHandlingChange}
onBack={handleCloseConversation}
resyncToken={resyncToken}
onRefresh={handleManualRefresh}
Expand Down
10 changes: 7 additions & 3 deletions src/app/(dashboard)/settings/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ import { SettingsOverview } from '@/components/settings/settings-overview';
import { ProfileForm } from '@/components/settings/profile-form';
import { SecurityPanel } from '@/components/settings/security-panel';
import { AppearancePanel } from '@/components/settings/appearance-panel';
import { BrandingSettings } from '@/components/settings/branding-settings';
import { WhatsAppConfig } from '@/components/settings/whatsapp-config';
import { AiAssistantSettings } from '@/components/settings/ai-assistant-settings';
import { TemplateManager } from '@/components/settings/template-manager';
import { FieldsAndTagsPanel } from '@/components/settings/fields-and-tags-panel';
import { DealsSettings } from '@/components/settings/deals-settings';
Expand Down Expand Up @@ -47,15 +49,17 @@ export default function SettingsPage() {
appearance: mode.charAt(0).toUpperCase() + mode.slice(1),
deals: defaultCurrency,
}),
[mode, defaultCurrency],
[mode, defaultCurrency]
);

const panel: Record<SettingsSection, ReactNode> = {
overview: <SettingsOverview onSelect={go} />,
profile: <ProfileForm />,
security: <SecurityPanel />,
appearance: <AppearancePanel />,
branding: <BrandingSettings />,
whatsapp: <WhatsAppConfig />,
ai: <AiAssistantSettings />,
templates: <TemplateManager />,
fields: <FieldsAndTagsPanel />,
deals: <DealsSettings />,
Expand All @@ -66,10 +70,10 @@ export default function SettingsPage() {
return (
<div>
<div>
<h1 className="text-2xl font-bold tracking-tight text-foreground">
<h1 className="text-foreground text-2xl font-bold tracking-tight">
Settings
</h1>
<p className="mt-1 text-sm text-muted-foreground">
<p className="text-muted-foreground mt-1 text-sm">
Everything in one place — your account and your workspace. Pick a
section to manage it.
</p>
Expand Down
Loading