Skip to content
← Public packages

@kody/mailroom

Offline-first PWA for your Kody mailbox: sent and received threads, copy-prompt for agents, no send.

src/prompt-text.ts

86 lines · 2.5 KB · TypeScript
import { messageWhen, snippetFrom, threadKey } from './threads.ts'
import type { MailMessage, MailSummary } from './types.ts'

export function textFromMessage(
	message: Pick<MailMessage, 'text_body' | 'html_body' | 'subject'>,
): string {
	const text = String(message.text_body || '').trim()
	if (text) return text
	const html = String(message.html_body || '')
		.replace(/<style[\s\S]*?<\/style>/gi, '\n')
		.replace(/<script[\s\S]*?<\/script>/gi, '\n')
		.replace(/<br\s*\/?>/gi, '\n')
		.replace(/<\/p>/gi, '\n')
		.replace(/<[^>]+>/g, ' ')
		.replace(/[ \t]+\n/g, '\n')
		.replace(/\n{3,}/g, '\n\n')
		.replace(/[ \t]{2,}/g, ' ')
		.trim()
	return html || String(message.subject || '').trim()
}

export function buildMessagePrompt(message: MailMessage): string {
	const when = messageWhen(message)
	const body = textFromMessage(message)
	return `Discuss this email with me. I am looking at it in Kody Mailroom (read-only; do not send).

Subject: ${message.subject || '(no subject)'}
Direction: ${message.direction}
From: ${message.from_address || message.envelope_from || ''}
To: ${(message.to_addresses || []).join(', ')}
When: ${when}
Message id: ${message.id}
Thread id: ${threadKey(message)}

${body}

Fetch the stored message again:

\`\`\`ts
import { kody } from 'kody:runtime'

const message = await kody.emailMessageGet({
	message_id: ${JSON.stringify(message.id)},
})
\`\`\`
`
}

export function buildThreadPrompt(input: {
	id: string
	subject?: string | null
	messages: Array<MailMessage | MailSummary>
}): string {
	const lines = input.messages.map((message, index) => {
		const body =
			'text_body' in message || 'html_body' in message
				? textFromMessage(message as MailMessage)
				: snippetFrom(message)
		return `--- Message ${index + 1} (${message.direction}) ---
From: ${message.from_address || message.envelope_from || ''}
To: ${(message.to_addresses || []).join(', ')}
When: ${messageWhen(message)}
Id: ${message.id}

${body}`
	})
	const first = input.messages[0]
	const threadId = input.id || (first ? threadKey(first) : '')
	return `Discuss this email thread with me. I am looking at it in Kody Mailroom (read-only; do not send).

Subject: ${input.subject || first?.subject || '(no subject)'}
Thread id: ${threadId}
Messages: ${input.messages.length}

${lines.join('\n\n')}

Fetch the thread's latest stored message:

\`\`\`ts
import { kody } from 'kody:runtime'

const { messages } = await kody.emailMessageList({ limit: 100 })
const thread = messages.filter((message) => (message.thread_id || message.id) === ${JSON.stringify(threadId)})
\`\`\`
`
}