Clarify WhatsApp self-chat mode in onboarding (#23)

* Improve Discord onboarding with detailed setup instructions

- Add step-by-step instructions for creating Discord bot
- Include guidance on enabling Message Content Intent
- Show OAuth2 URL Generator steps with required permissions
- Auto-generate invite URL after user enters bot token
  (extracts application ID from token and builds URL with correct permissions)

🐙 Generated with [Letta Code](https://letta.com)

Co-Authored-By: Letta <noreply@letta.com>

* Clarify WhatsApp and Signal self-chat mode in onboarding

Changed confusing yes/no prompts to clearer selects:

WhatsApp:
- "Dedicated bot number" - Responds to all incoming messages
- "My personal number" - Only responds to "Message Yourself" chat

Signal (new):
- "Dedicated bot number" - Responds to all incoming messages
- "My personal number" - Only responds to "Note to Self" chat

This makes it clear what each option actually does.

Written by Cameron ◯ Letta Code

"The question is not what you look at, but what you see." - Thoreau

---------

Co-authored-by: Letta <noreply@letta.com>
This commit is contained in:
Cameron
2026-01-29 15:41:04 -08:00
committed by GitHub
parent d420e5d3b5
commit 14b1d82e72
3 changed files with 31 additions and 6 deletions

View File

@@ -129,6 +129,10 @@ export function configToEnv(config: LettaBotConfig): Record<string, string> {
}
if (config.channels.signal?.phone) {
env.SIGNAL_PHONE_NUMBER = config.channels.signal.phone;
// Signal selfChat defaults to true, so only set env if explicitly false
if (config.channels.signal.selfChat === false) {
env.SIGNAL_SELF_CHAT_MODE = 'false';
}
}
if (config.channels.discord?.token) {
env.DISCORD_BOT_TOKEN = config.channels.discord.token;

View File

@@ -77,6 +77,7 @@ export interface WhatsAppConfig {
export interface SignalConfig {
enabled: boolean;
phone?: string;
selfChat?: boolean;
dmPolicy?: 'pairing' | 'allowlist' | 'open';
allowedUsers?: string[];
}

View File

@@ -35,7 +35,7 @@ interface OnboardConfig {
telegram: { enabled: boolean; token?: string; dmPolicy?: 'pairing' | 'allowlist' | 'open'; allowedUsers?: string[] };
slack: { enabled: boolean; appToken?: string; botToken?: string; allowedUsers?: string[] };
whatsapp: { enabled: boolean; selfChat?: boolean; dmPolicy?: 'pairing' | 'allowlist' | 'open'; allowedUsers?: string[] };
signal: { enabled: boolean; phone?: string; dmPolicy?: 'pairing' | 'allowlist' | 'open'; allowedUsers?: string[] };
signal: { enabled: boolean; phone?: string; selfChat?: boolean; dmPolicy?: 'pairing' | 'allowlist' | 'open'; allowedUsers?: string[] };
discord: { enabled: boolean; token?: string; dmPolicy?: 'pairing' | 'allowlist' | 'open'; allowedUsers?: string[] };
gmail: { enabled: boolean; account?: string };
@@ -735,11 +735,15 @@ async function stepChannels(config: OnboardConfig, env: Record<string, string>):
'WhatsApp'
);
const selfChat = await p.confirm({
message: 'WhatsApp: Self-chat mode? (Message Yourself)',
initialValue: config.whatsapp.selfChat ?? false,
const selfChat = await p.select({
message: 'WhatsApp: Whose number is this?',
options: [
{ value: 'dedicated', label: 'Dedicated bot number', hint: 'Responds to all incoming messages' },
{ value: 'personal', label: 'My personal number', hint: 'Only responds to "Message Yourself" chat' },
],
initialValue: config.whatsapp.selfChat ? 'personal' : 'dedicated',
});
if (!p.isCancel(selfChat)) config.whatsapp.selfChat = selfChat;
if (!p.isCancel(selfChat)) config.whatsapp.selfChat = selfChat === 'personal';
// Access control (important since WhatsApp has full account access)
const dmPolicy = await p.select({
@@ -785,6 +789,16 @@ async function stepChannels(config: OnboardConfig, env: Record<string, string>):
});
if (!p.isCancel(phone) && phone) config.signal.phone = phone;
const selfChat = await p.select({
message: 'Signal: Whose number is this?',
options: [
{ value: 'dedicated', label: 'Dedicated bot number', hint: 'Responds to all incoming messages' },
{ value: 'personal', label: 'My personal number', hint: 'Only responds to "Note to Self" chat' },
],
initialValue: config.signal.selfChat ? 'personal' : 'dedicated',
});
if (!p.isCancel(selfChat)) config.signal.selfChat = selfChat === 'personal';
// Access control
const dmPolicy = await p.select({
message: 'Signal: Who can message the bot?',
@@ -876,7 +890,7 @@ function showSummary(config: OnboardConfig): void {
if (config.slack.enabled) channels.push('Slack');
if (config.discord.enabled) channels.push('Discord');
if (config.whatsapp.enabled) channels.push(config.whatsapp.selfChat ? 'WhatsApp (self)' : 'WhatsApp');
if (config.signal.enabled) channels.push('Signal');
if (config.signal.enabled) channels.push(config.signal.selfChat ? 'Signal (self)' : 'Signal');
lines.push(`Channels: ${channels.length > 0 ? channels.join(', ') : 'None'}`);
// Features
@@ -1000,6 +1014,7 @@ export async function onboard(): Promise<void> {
signal: {
enabled: existingConfig.channels.signal?.enabled || false,
phone: existingConfig.channels.signal?.phone,
selfChat: existingConfig.channels.signal?.selfChat,
dmPolicy: existingConfig.channels.signal?.dmPolicy,
},
gmail: { enabled: false },
@@ -1103,6 +1118,9 @@ export async function onboard(): Promise<void> {
if (config.signal.enabled && config.signal.phone) {
env.SIGNAL_PHONE_NUMBER = config.signal.phone;
// Signal selfChat defaults to true, so only set env if explicitly false (dedicated number)
if (config.signal.selfChat === false) env.SIGNAL_SELF_CHAT_MODE = 'false';
else delete env.SIGNAL_SELF_CHAT_MODE;
if (config.signal.dmPolicy) env.SIGNAL_DM_POLICY = config.signal.dmPolicy;
if (config.signal.allowedUsers?.length) {
env.SIGNAL_ALLOWED_USERS = config.signal.allowedUsers.join(',');
@@ -1111,6 +1129,7 @@ export async function onboard(): Promise<void> {
}
} else {
delete env.SIGNAL_PHONE_NUMBER;
delete env.SIGNAL_SELF_CHAT_MODE;
delete env.SIGNAL_DM_POLICY;
delete env.SIGNAL_ALLOWED_USERS;
}
@@ -1203,6 +1222,7 @@ export async function onboard(): Promise<void> {
signal: {
enabled: true,
phone: config.signal.phone,
selfChat: config.signal.selfChat,
dmPolicy: config.signal.dmPolicy,
allowedUsers: config.signal.allowedUsers,
}