feat: add resend tools, MCP collection endpoint, and UI refinements

- Add @tpmjs/tools-resend with email API tools and blocks.yml entries
- Add MCP route for collection skill discovery
- Add InstallationSection component for collections
- Refactor collection pages to use shared components and simplify layouts
- Update skills questions API, rate limiting, and API key handling
- Add tpmjs-tool-creator skill for Claude
- Update video feature scenes and fix lint issues
- Update .gitignore with IDE and temp file exclusions
This commit is contained in:
Ajax Davis 2026-02-07 00:49:40 +10:00
parent f3a46045ba
commit a52d32c367
40 changed files with 3310 additions and 1694 deletions

File diff suppressed because it is too large Load diff

View file

@ -9941,6 +9941,556 @@ blocks:
description: "Current status of the removal request"
measures: [working_implementation, valid_output_structure, proper_error_handling, ai_sdk_compliance]
# ─── Resend Email API ──────────────────────────────────────────────────────
ops.resendSendEmail:
type: utility
description: "Send a single email via the Resend API."
path: "resend"
domain_rules:
- id: api_integration
description: "Must call Resend API POST /emails endpoint"
inputs:
- name: from
type: string
description: "Sender email address"
- name: to
type: string | string[]
description: "Recipient email address(es)"
- name: subject
type: string
description: "Email subject line"
- name: html
type: string
optional: true
description: "HTML body content"
- name: text
type: string
optional: true
description: "Plain text body content"
outputs:
- name: id
type: string
description: "Resend email ID"
measures: [working_implementation, valid_output_structure, proper_error_handling, ai_sdk_compliance]
ops.resendSendBatchEmails:
type: utility
description: "Send a batch of emails in a single API call via Resend."
path: "resend"
domain_rules:
- id: api_integration
description: "Must call Resend API POST /emails/batch endpoint"
inputs:
- name: emails
type: array
description: "Array of email objects to send"
outputs:
- name: data
type: array
description: "Array of created email IDs"
measures: [working_implementation, valid_output_structure, proper_error_handling, ai_sdk_compliance]
ops.resendGetEmail:
type: utility
description: "Retrieve details of a sent email by its ID."
path: "resend"
domain_rules:
- id: api_integration
description: "Must call Resend API GET /emails/{id} endpoint"
inputs:
- name: id
type: string
description: "The email ID to retrieve"
outputs:
- name: result
type: object
description: "Email details including status and content"
measures: [working_implementation, valid_output_structure, proper_error_handling, ai_sdk_compliance]
ops.resendUpdateEmail:
type: utility
description: "Update a scheduled email's delivery time."
path: "resend"
domain_rules:
- id: api_integration
description: "Must call Resend API PATCH /emails/{id} endpoint"
inputs:
- name: id
type: string
description: "The email ID to update"
- name: scheduled_at
type: string
description: "New scheduled time in ISO 8601 format"
outputs:
- name: id
type: string
description: "Updated email ID"
measures: [working_implementation, valid_output_structure, proper_error_handling, ai_sdk_compliance]
ops.resendCancelEmail:
type: utility
description: "Cancel a scheduled email that has not been sent yet."
path: "resend"
domain_rules:
- id: api_integration
description: "Must call Resend API POST /emails/{id}/cancel endpoint"
inputs:
- name: id
type: string
description: "The email ID to cancel"
outputs:
- name: id
type: string
description: "Cancelled email ID"
measures: [working_implementation, valid_output_structure, proper_error_handling, ai_sdk_compliance]
ops.resendListEmails:
type: utility
description: "List sent emails with cursor-based pagination."
path: "resend"
domain_rules:
- id: api_integration
description: "Must call Resend API GET /emails endpoint"
inputs:
- name: limit
type: number
optional: true
description: "Max results to return"
- name: after
type: string
optional: true
description: "Cursor for forward pagination"
- name: before
type: string
optional: true
description: "Cursor for backward pagination"
outputs:
- name: data
type: array
description: "Array of email summaries"
measures: [working_implementation, valid_output_structure, proper_error_handling, ai_sdk_compliance]
ops.resendCreateDomain:
type: utility
description: "Add a new sending domain to your Resend account."
path: "resend"
domain_rules:
- id: api_integration
description: "Must call Resend API POST /domains endpoint"
inputs:
- name: name
type: string
description: "Domain name to add"
- name: region
type: string
optional: true
description: "Region for the domain"
outputs:
- name: result
type: object
description: "Domain details with DNS records"
measures: [working_implementation, valid_output_structure, proper_error_handling, ai_sdk_compliance]
ops.resendGetDomain:
type: utility
description: "Retrieve details and DNS records for a specific domain."
path: "resend"
domain_rules:
- id: api_integration
description: "Must call Resend API GET /domains/{id} endpoint"
inputs:
- name: domain_id
type: string
description: "The domain ID to retrieve"
outputs:
- name: result
type: object
description: "Domain details including verification status"
measures: [working_implementation, valid_output_structure, proper_error_handling, ai_sdk_compliance]
ops.resendUpdateDomain:
type: utility
description: "Update tracking and TLS settings for an existing domain."
path: "resend"
domain_rules:
- id: api_integration
description: "Must call Resend API PATCH /domains/{id} endpoint"
inputs:
- name: domain_id
type: string
description: "The domain ID to update"
- name: click_tracking
type: boolean
optional: true
description: "Enable or disable click tracking"
outputs:
- name: id
type: string
description: "Updated domain ID"
measures: [working_implementation, valid_output_structure, proper_error_handling, ai_sdk_compliance]
ops.resendDeleteDomain:
type: utility
description: "Delete a sending domain from your Resend account."
path: "resend"
domain_rules:
- id: api_integration
description: "Must call Resend API DELETE /domains/{id} endpoint"
inputs:
- name: domain_id
type: string
description: "The domain ID to delete"
outputs:
- name: deleted
type: boolean
description: "Whether deletion succeeded"
measures: [working_implementation, valid_output_structure, proper_error_handling, ai_sdk_compliance]
ops.resendListDomains:
type: utility
description: "List all sending domains with their verification status."
path: "resend"
domain_rules:
- id: api_integration
description: "Must call Resend API GET /domains endpoint"
inputs:
- name: limit
type: number
optional: true
description: "Max results to return"
outputs:
- name: data
type: array
description: "Array of domain objects"
measures: [working_implementation, valid_output_structure, proper_error_handling, ai_sdk_compliance]
ops.resendVerifyDomain:
type: utility
description: "Trigger DNS verification for a sending domain."
path: "resend"
domain_rules:
- id: api_integration
description: "Must call Resend API POST /domains/{id}/verify endpoint"
inputs:
- name: domain_id
type: string
description: "The domain ID to verify"
outputs:
- name: id
type: string
description: "Verified domain ID"
measures: [working_implementation, valid_output_structure, proper_error_handling, ai_sdk_compliance]
ops.resendCreateApiKey:
type: utility
description: "Create a new Resend API key."
path: "resend"
domain_rules:
- id: api_integration
description: "Must call Resend API POST /api-keys endpoint"
inputs:
- name: name
type: string
description: "Name for the API key"
- name: permission
type: string
optional: true
description: "Permission level"
outputs:
- name: id
type: string
description: "Created API key ID"
- name: token
type: string
description: "The API key token"
measures: [working_implementation, valid_output_structure, proper_error_handling, ai_sdk_compliance]
ops.resendListApiKeys:
type: utility
description: "List all API keys in your Resend account."
path: "resend"
domain_rules:
- id: api_integration
description: "Must call Resend API GET /api-keys endpoint"
inputs:
- name: limit
type: number
optional: true
description: "Max results to return"
outputs:
- name: data
type: array
description: "Array of API key objects"
measures: [working_implementation, valid_output_structure, proper_error_handling, ai_sdk_compliance]
ops.resendDeleteApiKey:
type: utility
description: "Delete an API key from your Resend account."
path: "resend"
domain_rules:
- id: api_integration
description: "Must call Resend API DELETE /api-keys/{id} endpoint"
inputs:
- name: api_key_id
type: string
description: "The API key ID to delete"
outputs:
- name: result
type: object
description: "Deletion confirmation"
measures: [working_implementation, valid_output_structure, proper_error_handling, ai_sdk_compliance]
ops.resendCreateContact:
type: utility
description: "Create a new contact with email and optional properties."
path: "resend"
domain_rules:
- id: api_integration
description: "Must call Resend API POST /contacts endpoint"
inputs:
- name: email
type: string
description: "Contact email address"
- name: first_name
type: string
optional: true
description: "Contact first name"
- name: last_name
type: string
optional: true
description: "Contact last name"
outputs:
- name: id
type: string
description: "Created contact ID"
measures: [working_implementation, valid_output_structure, proper_error_handling, ai_sdk_compliance]
ops.resendGetContact:
type: utility
description: "Retrieve a contact by ID or email address."
path: "resend"
domain_rules:
- id: api_integration
description: "Must call Resend API GET /contacts/{id} endpoint"
inputs:
- name: id
type: string
description: "Contact ID or email address"
outputs:
- name: result
type: object
description: "Contact details"
measures: [working_implementation, valid_output_structure, proper_error_handling, ai_sdk_compliance]
ops.resendUpdateContact:
type: utility
description: "Update a contact's name, subscription status, or properties."
path: "resend"
domain_rules:
- id: api_integration
description: "Must call Resend API PATCH /contacts/{id} endpoint"
inputs:
- name: id
type: string
description: "Contact ID or email address"
- name: first_name
type: string
optional: true
description: "Updated first name"
outputs:
- name: id
type: string
description: "Updated contact ID"
measures: [working_implementation, valid_output_structure, proper_error_handling, ai_sdk_compliance]
ops.resendDeleteContact:
type: utility
description: "Delete a contact by ID or email address."
path: "resend"
domain_rules:
- id: api_integration
description: "Must call Resend API DELETE /contacts/{id} endpoint"
inputs:
- name: id
type: string
description: "Contact ID or email to delete"
outputs:
- name: deleted
type: boolean
description: "Whether deletion succeeded"
measures: [working_implementation, valid_output_structure, proper_error_handling, ai_sdk_compliance]
ops.resendListContacts:
type: utility
description: "List contacts with optional segment filtering and pagination."
path: "resend"
domain_rules:
- id: api_integration
description: "Must call Resend API GET /contacts endpoint"
inputs:
- name: segment_id
type: string
optional: true
description: "Filter by segment ID"
- name: limit
type: number
optional: true
description: "Max results to return"
outputs:
- name: data
type: array
description: "Array of contact objects"
measures: [working_implementation, valid_output_structure, proper_error_handling, ai_sdk_compliance]
ops.resendCreateBroadcast:
type: utility
description: "Create a broadcast email draft to send to a segment."
path: "resend"
domain_rules:
- id: api_integration
description: "Must call Resend API POST /broadcasts endpoint"
inputs:
- name: segment_id
type: string
description: "Segment ID to target"
- name: from
type: string
description: "Sender address"
- name: subject
type: string
description: "Broadcast subject line"
outputs:
- name: id
type: string
description: "Created broadcast ID"
measures: [working_implementation, valid_output_structure, proper_error_handling, ai_sdk_compliance]
ops.resendListBroadcasts:
type: utility
description: "List all broadcasts with status and scheduling details."
path: "resend"
domain_rules:
- id: api_integration
description: "Must call Resend API GET /broadcasts endpoint"
inputs:
- name: limit
type: number
optional: true
description: "Max results to return"
outputs:
- name: data
type: array
description: "Array of broadcast objects"
measures: [working_implementation, valid_output_structure, proper_error_handling, ai_sdk_compliance]
ops.resendSendBroadcast:
type: utility
description: "Send or schedule a previously created broadcast."
path: "resend"
domain_rules:
- id: api_integration
description: "Must call Resend API POST /broadcasts/{id}/send endpoint"
inputs:
- name: broadcast_id
type: string
description: "The broadcast ID to send"
- name: scheduled_at
type: string
optional: true
description: "ISO 8601 datetime to schedule"
outputs:
- name: id
type: string
description: "Sent broadcast ID"
measures: [working_implementation, valid_output_structure, proper_error_handling, ai_sdk_compliance]
ops.resendDeleteBroadcast:
type: utility
description: "Delete a draft broadcast that has not been sent."
path: "resend"
domain_rules:
- id: api_integration
description: "Must call Resend API DELETE /broadcasts/{id} endpoint"
inputs:
- name: broadcast_id
type: string
description: "The broadcast ID to delete"
outputs:
- name: deleted
type: boolean
description: "Whether deletion succeeded"
measures: [working_implementation, valid_output_structure, proper_error_handling, ai_sdk_compliance]
ops.resendCreateAudience:
type: utility
description: "Create a new audience for organizing contacts."
path: "resend"
domain_rules:
- id: api_integration
description: "Must call Resend API POST /audiences endpoint"
inputs:
- name: name
type: string
description: "Audience name"
outputs:
- name: id
type: string
description: "Created audience ID"
measures: [working_implementation, valid_output_structure, proper_error_handling, ai_sdk_compliance]
ops.resendListAudiences:
type: utility
description: "List all audiences in your Resend account."
path: "resend"
domain_rules:
- id: api_integration
description: "Must call Resend API GET /audiences endpoint"
inputs:
- name: limit
type: number
optional: true
description: "Max results to return"
outputs:
- name: data
type: array
description: "Array of audience objects"
measures: [working_implementation, valid_output_structure, proper_error_handling, ai_sdk_compliance]
ops.resendGetAudience:
type: utility
description: "Retrieve details of a specific audience."
path: "resend"
domain_rules:
- id: api_integration
description: "Must call Resend API GET /audiences/{id} endpoint"
inputs:
- name: audience_id
type: string
description: "The audience ID to retrieve"
outputs:
- name: result
type: object
description: "Audience details"
measures: [working_implementation, valid_output_structure, proper_error_handling, ai_sdk_compliance]
ops.resendDeleteAudience:
type: utility
description: "Delete an audience from your Resend account."
path: "resend"
domain_rules:
- id: api_integration
description: "Must call Resend API DELETE /audiences/{id} endpoint"
inputs:
- name: audience_id
type: string
description: "The audience ID to delete"
outputs:
- name: deleted
type: boolean
description: "Whether deletion succeeded"
measures: [working_implementation, valid_output_structure, proper_error_handling, ai_sdk_compliance]
# =============================================================================
# VALIDATORS - Which validators to run against each block
# =============================================================================

View file

@ -0,0 +1,66 @@
import {
cancelEmail,
createApiKey,
createAudience,
createBroadcast,
createContact,
createDomain,
deleteApiKey,
deleteAudience,
deleteBroadcast,
deleteContact,
deleteDomain,
getAudience,
getContact,
getDomain,
getEmail,
listApiKeys,
listAudiences,
listBroadcasts,
listContacts,
listDomains,
listEmails,
sendBatchEmails,
sendBroadcast,
sendEmail,
updateContact,
updateDomain,
updateEmail,
verifyDomain,
} from './src/index.js';
export const block = {
name: 'resend',
tools: {
sendEmail,
sendBatchEmails,
getEmail,
updateEmail,
cancelEmail,
listEmails,
createDomain,
getDomain,
updateDomain,
deleteDomain,
listDomains,
verifyDomain,
createApiKey,
listApiKeys,
deleteApiKey,
createContact,
getContact,
updateContact,
deleteContact,
listContacts,
createBroadcast,
listBroadcasts,
sendBroadcast,
deleteBroadcast,
createAudience,
listAudiences,
getAudience,
deleteAudience,
},
};
export default block;

View file

@ -0,0 +1,2 @@
export * from './src/index.js';
export { default } from './src/index.js';

View file

@ -0,0 +1,166 @@
{
"name": "@tpmjs/tools-resend",
"version": "0.1.0",
"description": "Resend email API tools for AI agents. Send emails, manage domains, contacts, broadcasts, audiences, and API keys.",
"type": "module",
"keywords": [
"tpmjs",
"resend",
"email",
"transactional",
"agent"
],
"exports": {
".": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
}
},
"files": [
"dist"
],
"scripts": {
"build": "tsup",
"dev": "tsup --watch",
"type-check": "tsc --noEmit",
"clean": "rm -rf dist .turbo"
},
"devDependencies": {
"@tpmjs/tsconfig": "workspace:*",
"tsup": "^8.5.1",
"typescript": "^5.9.3"
},
"publishConfig": {
"access": "public"
},
"repository": {
"type": "git",
"url": "https://github.com/tpmjs/tpmjs.git",
"directory": "packages/tools/official/resend"
},
"homepage": "https://tpmjs.com",
"license": "MIT",
"tpmjs": {
"category": "ops",
"frameworks": [
"vercel-ai"
],
"tools": [
{
"name": "sendEmail",
"description": "Send a single email via the Resend API."
},
{
"name": "sendBatchEmails",
"description": "Send a batch of emails in a single API call via Resend."
},
{
"name": "getEmail",
"description": "Retrieve details of a specific sent email by ID."
},
{
"name": "updateEmail",
"description": "Update a scheduled email by changing its scheduled time."
},
{
"name": "cancelEmail",
"description": "Cancel a scheduled email that has not been sent yet."
},
{
"name": "listEmails",
"description": "List sent emails with optional cursor-based pagination."
},
{
"name": "createDomain",
"description": "Add a new sending domain to your Resend account."
},
{
"name": "getDomain",
"description": "Retrieve details and DNS records for a specific domain."
},
{
"name": "updateDomain",
"description": "Update tracking and TLS settings for a domain."
},
{
"name": "deleteDomain",
"description": "Delete a sending domain from your Resend account."
},
{
"name": "listDomains",
"description": "List all sending domains in your Resend account."
},
{
"name": "verifyDomain",
"description": "Trigger DNS verification for a sending domain."
},
{
"name": "createApiKey",
"description": "Create a new API key with specified permissions."
},
{
"name": "listApiKeys",
"description": "List all API keys in your Resend account."
},
{
"name": "deleteApiKey",
"description": "Delete an API key from your Resend account."
},
{
"name": "createContact",
"description": "Create a new contact with email and optional properties."
},
{
"name": "getContact",
"description": "Retrieve a contact by their ID or email address."
},
{
"name": "updateContact",
"description": "Update a contact's name, subscription status, or properties."
},
{
"name": "deleteContact",
"description": "Delete a contact by their ID or email address."
},
{
"name": "listContacts",
"description": "List contacts with optional segment filtering and pagination."
},
{
"name": "createBroadcast",
"description": "Create a new broadcast email to send to a segment."
},
{
"name": "listBroadcasts",
"description": "List all broadcasts with cursor-based pagination."
},
{
"name": "sendBroadcast",
"description": "Send or schedule a previously created broadcast."
},
{
"name": "deleteBroadcast",
"description": "Delete a draft broadcast that has not been sent."
},
{
"name": "createAudience",
"description": "Create a new audience for organizing contacts."
},
{
"name": "listAudiences",
"description": "List all audiences in your Resend account."
},
{
"name": "getAudience",
"description": "Retrieve details of a specific audience by ID."
},
{
"name": "deleteAudience",
"description": "Delete an audience from your Resend account."
}
]
},
"dependencies": {
"ai": "6.0.49"
}
}

View file

@ -0,0 +1,875 @@
/**
* @tpmjs/tools-resend — Resend Email API Tools for AI Agents
*
* Full access to the Resend email API: send emails, manage domains, contacts,
* broadcasts, audiences, and API keys.
*
* @requires RESEND_API_KEY environment variable
*/
import { jsonSchema, tool } from 'ai';
const BASE_URL = 'https://api.resend.com';
// ─── Client Infrastructure ──────────────────────────────────────────────────
function getApiKey(): string {
const key = process.env.RESEND_API_KEY;
if (!key) {
throw new Error(
'RESEND_API_KEY environment variable is required. Get your API key from https://resend.com/api-keys'
);
}
return key;
}
async function apiRequest<T>(method: string, path: string, body?: unknown): Promise<T> {
const key = getApiKey();
const headers: Record<string, string> = {
Authorization: `Bearer ${key}`,
'Content-Type': 'application/json',
};
const options: RequestInit = { method, headers };
if (body !== undefined) {
options.body = JSON.stringify(body);
}
const response = await fetch(`${BASE_URL}${path}`, options);
if (!response.ok) {
await handleApiError(response);
}
const text = await response.text();
if (!text) {
return {} as T;
}
return JSON.parse(text) as T;
}
async function handleApiError(response: Response): Promise<never> {
let errorMessage: string;
try {
const errorData = (await response.json()) as { message?: string; error?: string };
errorMessage = errorData.message || errorData.error || `HTTP ${response.status}`;
} catch {
errorMessage = `HTTP ${response.status}: ${response.statusText}`;
}
switch (response.status) {
case 400:
throw new Error(`Bad request: ${errorMessage}`);
case 401:
throw new Error('Authentication failed: Invalid Resend API key. Check RESEND_API_KEY.');
case 403:
throw new Error(`Access forbidden: ${errorMessage}`);
case 404:
throw new Error(`Not found: ${errorMessage}`);
case 422:
throw new Error(`Validation error: ${errorMessage}`);
case 429:
throw new Error(`Rate limit exceeded: ${errorMessage}`);
default:
throw new Error(`Resend API error (${response.status}): ${errorMessage}`);
}
}
function buildQueryString(params: Record<string, unknown>): string {
const entries = Object.entries(params).filter(
([, v]) => v !== undefined && v !== null && v !== ''
);
if (entries.length === 0) return '';
return (
'?' +
entries.map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(String(v))}`).join('&')
);
}
// ─── Emails ─────────────────────────────────────────────────────────────────
export interface SendEmailInput {
from: string;
to: string | string[];
subject: string;
html?: string;
text?: string;
cc?: string | string[];
bcc?: string | string[];
reply_to?: string | string[];
headers?: Record<string, string>;
attachments?: Array<{ content?: string; filename: string; path?: string; content_type?: string }>;
tags?: Array<{ name: string; value: string }>;
scheduled_at?: string;
topic_id?: string;
}
export interface PaginationInput {
limit?: number;
after?: string;
before?: string;
}
export const sendEmail = tool({
description:
'Send a single email via the Resend API. Requires from, to, and subject. Provide html and/or text body content.',
inputSchema: jsonSchema<SendEmailInput>({
type: 'object',
properties: {
from: {
type: 'string',
description: 'Sender email address. Supports "Name <email>" format.',
},
to: {
oneOf: [
{ type: 'string', description: 'Single recipient email address.' },
{
type: 'array',
items: { type: 'string' },
description: 'Array of recipient emails (max 50).',
},
],
description: 'Recipient email address(es).',
},
subject: { type: 'string', description: 'Email subject line.' },
html: { type: 'string', description: 'HTML body content.' },
text: { type: 'string', description: 'Plain text body content.' },
cc: {
oneOf: [{ type: 'string' }, { type: 'array', items: { type: 'string' } }],
description: 'CC recipient(s).',
},
bcc: {
oneOf: [{ type: 'string' }, { type: 'array', items: { type: 'string' } }],
description: 'BCC recipient(s).',
},
reply_to: {
oneOf: [{ type: 'string' }, { type: 'array', items: { type: 'string' } }],
description: 'Reply-to address(es).',
},
headers: {
type: 'object',
additionalProperties: { type: 'string' },
description: 'Custom email headers as key-value pairs.',
},
attachments: {
type: 'array',
items: {
type: 'object',
properties: {
content: { type: 'string', description: 'Base64-encoded content.' },
filename: { type: 'string', description: 'Attachment filename.' },
path: { type: 'string', description: 'URL to fetch attachment from.' },
content_type: { type: 'string', description: 'MIME type.' },
},
required: ['filename'],
},
description: 'File attachments (max 40MB total).',
},
tags: {
type: 'array',
items: {
type: 'object',
properties: {
name: { type: 'string', description: 'Tag name.' },
value: { type: 'string', description: 'Tag value.' },
},
required: ['name', 'value'],
},
description: 'Tags for categorizing emails.',
},
scheduled_at: {
type: 'string',
description: 'ISO 8601 datetime or natural language (e.g. "in 1 min").',
},
topic_id: { type: 'string', description: 'Topic ID for subscription management.' },
},
required: ['from', 'to', 'subject'],
additionalProperties: false,
}),
async execute(input: SendEmailInput) {
return apiRequest<{ id: string }>('POST', '/emails', input);
},
});
export interface SendBatchInput {
emails: SendEmailInput[];
}
export const sendBatchEmails = tool({
description:
'Send a batch of emails in a single API call via Resend. Each email has the same parameters as sendEmail.',
inputSchema: jsonSchema<SendBatchInput>({
type: 'object',
properties: {
emails: {
type: 'array',
items: {
type: 'object',
properties: {
from: { type: 'string', description: 'Sender email address.' },
to: {
oneOf: [{ type: 'string' }, { type: 'array', items: { type: 'string' } }],
description: 'Recipient email address(es).',
},
subject: { type: 'string', description: 'Email subject line.' },
html: { type: 'string', description: 'HTML body content.' },
text: { type: 'string', description: 'Plain text body content.' },
},
required: ['from', 'to', 'subject'],
},
description: 'Array of email objects to send.',
},
},
required: ['emails'],
additionalProperties: false,
}),
async execute(input: SendBatchInput) {
return apiRequest<{ data: Array<{ id: string }> }>('POST', '/emails/batch', input.emails);
},
});
export interface IdInput {
id: string;
}
export const getEmail = tool({
description:
'Retrieve details of a specific sent email by its ID, including status, recipients, and content.',
inputSchema: jsonSchema<IdInput>({
type: 'object',
properties: {
id: { type: 'string', description: 'The email ID to retrieve.' },
},
required: ['id'],
additionalProperties: false,
}),
async execute(input: IdInput) {
return apiRequest<Record<string, unknown>>('GET', `/emails/${input.id}`);
},
});
export interface UpdateEmailInput {
id: string;
scheduled_at: string;
}
export const updateEmail = tool({
description:
'Update a scheduled email by changing its scheduled delivery time. Only works on emails not yet sent.',
inputSchema: jsonSchema<UpdateEmailInput>({
type: 'object',
properties: {
id: { type: 'string', description: 'The email ID to update.' },
scheduled_at: { type: 'string', description: 'New scheduled time in ISO 8601 format.' },
},
required: ['id', 'scheduled_at'],
additionalProperties: false,
}),
async execute(input: UpdateEmailInput) {
const { id, ...body } = input;
return apiRequest<{ object: string; id: string }>('PATCH', `/emails/${id}`, body);
},
});
export const cancelEmail = tool({
description:
'Cancel a scheduled email that has not been sent yet. Returns the cancelled email ID.',
inputSchema: jsonSchema<IdInput>({
type: 'object',
properties: {
id: { type: 'string', description: 'The email ID to cancel.' },
},
required: ['id'],
additionalProperties: false,
}),
async execute(input: IdInput) {
return apiRequest<{ object: string; id: string }>('POST', `/emails/${input.id}/cancel`);
},
});
export const listEmails = tool({
description:
'List sent emails with optional cursor-based pagination. Returns email summaries with status.',
inputSchema: jsonSchema<PaginationInput>({
type: 'object',
properties: {
limit: { type: 'number', description: 'Max results to return (1-100, default 20).' },
after: { type: 'string', description: 'Cursor ID for forward pagination.' },
before: { type: 'string', description: 'Cursor ID for backward pagination.' },
},
additionalProperties: false,
}),
async execute(input: PaginationInput) {
const qs = buildQueryString({ ...input });
return apiRequest<{ object: string; has_more: boolean; data: unknown[] }>(
'GET',
`/emails${qs}`
);
},
});
// ─── Domains ────────────────────────────────────────────────────────────────
export interface CreateDomainInput {
name: string;
region?: string;
custom_return_path?: string;
open_tracking?: boolean;
click_tracking?: boolean;
tls?: string;
}
export const createDomain = tool({
description:
'Add a new sending domain to your Resend account. Returns the domain ID and DNS records to configure.',
inputSchema: jsonSchema<CreateDomainInput>({
type: 'object',
properties: {
name: { type: 'string', description: 'The domain name to add (e.g. "example.com").' },
region: {
type: 'string',
description: 'Region: us-east-1, eu-west-1, sa-east-1, or ap-northeast-1.',
},
custom_return_path: {
type: 'string',
description: 'Subdomain for Return-Path (default: "send").',
},
open_tracking: { type: 'boolean', description: 'Enable open rate tracking.' },
click_tracking: { type: 'boolean', description: 'Enable click tracking in HTML emails.' },
tls: { type: 'string', description: 'TLS mode: "opportunistic" or "enforced".' },
},
required: ['name'],
additionalProperties: false,
}),
async execute(input: CreateDomainInput) {
return apiRequest<Record<string, unknown>>('POST', '/domains', input);
},
});
export interface DomainIdInput {
domain_id: string;
}
export const getDomain = tool({
description:
'Retrieve details and DNS records for a specific domain including verification status.',
inputSchema: jsonSchema<DomainIdInput>({
type: 'object',
properties: {
domain_id: { type: 'string', description: 'The domain ID to retrieve.' },
},
required: ['domain_id'],
additionalProperties: false,
}),
async execute(input: DomainIdInput) {
return apiRequest<Record<string, unknown>>('GET', `/domains/${input.domain_id}`);
},
});
export interface UpdateDomainInput {
domain_id: string;
click_tracking?: boolean;
open_tracking?: boolean;
tls?: string;
}
export const updateDomain = tool({
description: 'Update tracking, TLS, and capability settings for an existing domain.',
inputSchema: jsonSchema<UpdateDomainInput>({
type: 'object',
properties: {
domain_id: { type: 'string', description: 'The domain ID to update.' },
click_tracking: { type: 'boolean', description: 'Enable or disable click tracking.' },
open_tracking: { type: 'boolean', description: 'Enable or disable open tracking.' },
tls: { type: 'string', description: 'TLS mode: "opportunistic" or "enforced".' },
},
required: ['domain_id'],
additionalProperties: false,
}),
async execute(input: UpdateDomainInput) {
const { domain_id, ...body } = input;
return apiRequest<{ object: string; id: string }>('PATCH', `/domains/${domain_id}`, body);
},
});
export const deleteDomain = tool({
description: 'Delete a sending domain from your Resend account permanently.',
inputSchema: jsonSchema<DomainIdInput>({
type: 'object',
properties: {
domain_id: { type: 'string', description: 'The domain ID to delete.' },
},
required: ['domain_id'],
additionalProperties: false,
}),
async execute(input: DomainIdInput) {
return apiRequest<{ object: string; id: string; deleted: boolean }>(
'DELETE',
`/domains/${input.domain_id}`
);
},
});
export const listDomains = tool({
description: 'List all sending domains in your Resend account with their verification status.',
inputSchema: jsonSchema<PaginationInput>({
type: 'object',
properties: {
limit: { type: 'number', description: 'Max results to return (1-100, default 20).' },
after: { type: 'string', description: 'Cursor ID for forward pagination.' },
before: { type: 'string', description: 'Cursor ID for backward pagination.' },
},
additionalProperties: false,
}),
async execute(input: PaginationInput) {
const qs = buildQueryString({ ...input });
return apiRequest<{ object: string; has_more: boolean; data: unknown[] }>(
'GET',
`/domains${qs}`
);
},
});
export const verifyDomain = tool({
description:
'Trigger DNS verification for a sending domain. Check domain status after DNS records are configured.',
inputSchema: jsonSchema<DomainIdInput>({
type: 'object',
properties: {
domain_id: { type: 'string', description: 'The domain ID to verify.' },
},
required: ['domain_id'],
additionalProperties: false,
}),
async execute(input: DomainIdInput) {
return apiRequest<{ object: string; id: string }>('POST', `/domains/${input.domain_id}/verify`);
},
});
// ─── API Keys ───────────────────────────────────────────────────────────────
export interface CreateApiKeyInput {
name: string;
permission?: string;
domain_id?: string;
}
export const createApiKey = tool({
description: 'Create a new Resend API key with specified name and permission level.',
inputSchema: jsonSchema<CreateApiKeyInput>({
type: 'object',
properties: {
name: { type: 'string', description: 'Name for the API key (max 50 characters).' },
permission: { type: 'string', description: 'Permission: "full_access" or "sending_access".' },
domain_id: { type: 'string', description: 'Restrict to a domain (only for sending_access).' },
},
required: ['name'],
additionalProperties: false,
}),
async execute(input: CreateApiKeyInput) {
return apiRequest<{ id: string; token: string }>('POST', '/api-keys', input);
},
});
export const listApiKeys = tool({
description: 'List all API keys in your Resend account with their names and creation dates.',
inputSchema: jsonSchema<PaginationInput>({
type: 'object',
properties: {
limit: { type: 'number', description: 'Max results to return (1-100).' },
after: { type: 'string', description: 'Cursor ID for forward pagination.' },
before: { type: 'string', description: 'Cursor ID for backward pagination.' },
},
additionalProperties: false,
}),
async execute(input: PaginationInput) {
const qs = buildQueryString({ ...input });
return apiRequest<{ object: string; has_more: boolean; data: unknown[] }>(
'GET',
`/api-keys${qs}`
);
},
});
export interface ApiKeyIdInput {
api_key_id: string;
}
export const deleteApiKey = tool({
description: 'Delete an API key from your Resend account permanently.',
inputSchema: jsonSchema<ApiKeyIdInput>({
type: 'object',
properties: {
api_key_id: { type: 'string', description: 'The API key ID to delete.' },
},
required: ['api_key_id'],
additionalProperties: false,
}),
async execute(input: ApiKeyIdInput) {
return apiRequest<Record<string, unknown>>('DELETE', `/api-keys/${input.api_key_id}`);
},
});
// ─── Contacts ───────────────────────────────────────────────────────────────
export interface CreateContactInput {
email: string;
first_name?: string;
last_name?: string;
unsubscribed?: boolean;
properties?: Record<string, string>;
}
export const createContact = tool({
description:
'Create a new contact with an email address and optional name, properties, and subscription settings.',
inputSchema: jsonSchema<CreateContactInput>({
type: 'object',
properties: {
email: { type: 'string', description: 'Contact email address.' },
first_name: { type: 'string', description: 'Contact first name.' },
last_name: { type: 'string', description: 'Contact last name.' },
unsubscribed: {
type: 'boolean',
description: 'If true, contact is unsubscribed from all broadcasts.',
},
properties: {
type: 'object',
additionalProperties: { type: 'string' },
description: 'Custom key-value properties for the contact.',
},
},
required: ['email'],
additionalProperties: false,
}),
async execute(input: CreateContactInput) {
return apiRequest<{ object: string; id: string }>('POST', '/contacts', input);
},
});
export const getContact = tool({
description:
'Retrieve a contact by their ID or email address, including name, properties, and subscription status.',
inputSchema: jsonSchema<IdInput>({
type: 'object',
properties: {
id: { type: 'string', description: 'Contact ID or email address.' },
},
required: ['id'],
additionalProperties: false,
}),
async execute(input: IdInput) {
return apiRequest<Record<string, unknown>>('GET', `/contacts/${encodeURIComponent(input.id)}`);
},
});
export interface UpdateContactInput {
id: string;
first_name?: string;
last_name?: string;
unsubscribed?: boolean;
properties?: Record<string, string>;
}
export const updateContact = tool({
description: "Update a contact's name, subscription status, or custom properties.",
inputSchema: jsonSchema<UpdateContactInput>({
type: 'object',
properties: {
id: { type: 'string', description: 'Contact ID or email address.' },
first_name: { type: 'string', description: 'Updated first name.' },
last_name: { type: 'string', description: 'Updated last name.' },
unsubscribed: { type: 'boolean', description: 'Updated subscription status.' },
properties: {
type: 'object',
additionalProperties: { type: 'string' },
description: 'Updated custom properties.',
},
},
required: ['id'],
additionalProperties: false,
}),
async execute(input: UpdateContactInput) {
const { id, ...body } = input;
return apiRequest<{ object: string; id: string }>(
'PATCH',
`/contacts/${encodeURIComponent(id)}`,
body
);
},
});
export const deleteContact = tool({
description: 'Delete a contact by their ID or email address permanently.',
inputSchema: jsonSchema<IdInput>({
type: 'object',
properties: {
id: { type: 'string', description: 'Contact ID or email address to delete.' },
},
required: ['id'],
additionalProperties: false,
}),
async execute(input: IdInput) {
return apiRequest<{ object: string; contact: string; deleted: boolean }>(
'DELETE',
`/contacts/${encodeURIComponent(input.id)}`
);
},
});
export interface ListContactsInput extends PaginationInput {
segment_id?: string;
}
export const listContacts = tool({
description: 'List contacts with optional segment filtering and cursor-based pagination.',
inputSchema: jsonSchema<ListContactsInput>({
type: 'object',
properties: {
segment_id: { type: 'string', description: 'Filter contacts by segment ID.' },
limit: { type: 'number', description: 'Max results to return (1-100, default 20).' },
after: { type: 'string', description: 'Cursor ID for forward pagination.' },
before: { type: 'string', description: 'Cursor ID for backward pagination.' },
},
additionalProperties: false,
}),
async execute(input: ListContactsInput) {
const qs = buildQueryString({ ...input });
return apiRequest<{ object: string; has_more: boolean; data: unknown[] }>(
'GET',
`/contacts${qs}`
);
},
});
// ─── Broadcasts ─────────────────────────────────────────────────────────────
export interface CreateBroadcastInput {
segment_id: string;
from: string;
subject: string;
reply_to?: string | string[];
html?: string;
text?: string;
name?: string;
topic_id?: string;
}
export const createBroadcast = tool({
description:
'Create a new broadcast email draft to send to a segment. Use sendBroadcast to dispatch it.',
inputSchema: jsonSchema<CreateBroadcastInput>({
type: 'object',
properties: {
segment_id: { type: 'string', description: 'Segment ID to send the broadcast to.' },
from: { type: 'string', description: 'Sender address. Supports "Name <email>" format.' },
subject: { type: 'string', description: 'Broadcast email subject line.' },
reply_to: {
oneOf: [{ type: 'string' }, { type: 'array', items: { type: 'string' } }],
description: 'Reply-to address(es).',
},
html: { type: 'string', description: 'HTML content. Supports Contact Property templating.' },
text: { type: 'string', description: 'Plain text content.' },
name: { type: 'string', description: 'Friendly name for internal reference.' },
topic_id: { type: 'string', description: 'Topic ID for subscription management.' },
},
required: ['segment_id', 'from', 'subject'],
additionalProperties: false,
}),
async execute(input: CreateBroadcastInput) {
return apiRequest<{ id: string }>('POST', '/broadcasts', input);
},
});
export const listBroadcasts = tool({
description: 'List all broadcasts with their status, audience, and scheduling details.',
inputSchema: jsonSchema<PaginationInput>({
type: 'object',
properties: {
limit: { type: 'number', description: 'Max results to return (1-100, default 20).' },
after: { type: 'string', description: 'Cursor ID for forward pagination.' },
before: { type: 'string', description: 'Cursor ID for backward pagination.' },
},
additionalProperties: false,
}),
async execute(input: PaginationInput) {
const qs = buildQueryString({ ...input });
return apiRequest<{ object: string; has_more: boolean; data: unknown[] }>(
'GET',
`/broadcasts${qs}`
);
},
});
export interface SendBroadcastInput {
broadcast_id: string;
scheduled_at?: string;
}
export const sendBroadcast = tool({
description:
'Send or schedule a previously created broadcast. Optionally provide a scheduled_at time.',
inputSchema: jsonSchema<SendBroadcastInput>({
type: 'object',
properties: {
broadcast_id: { type: 'string', description: 'The broadcast ID to send.' },
scheduled_at: {
type: 'string',
description: 'ISO 8601 datetime or natural language to schedule.',
},
},
required: ['broadcast_id'],
additionalProperties: false,
}),
async execute(input: SendBroadcastInput) {
const { broadcast_id, ...body } = input;
const hasBody = Object.keys(body).length > 0;
return apiRequest<{ id: string }>(
'POST',
`/broadcasts/${broadcast_id}/send`,
hasBody ? body : undefined
);
},
});
export interface BroadcastIdInput {
broadcast_id: string;
}
export const deleteBroadcast = tool({
description:
'Delete a draft broadcast that has not been sent. Scheduled broadcasts are automatically cancelled.',
inputSchema: jsonSchema<BroadcastIdInput>({
type: 'object',
properties: {
broadcast_id: { type: 'string', description: 'The broadcast ID to delete.' },
},
required: ['broadcast_id'],
additionalProperties: false,
}),
async execute(input: BroadcastIdInput) {
return apiRequest<{ object: string; id: string; deleted: boolean }>(
'DELETE',
`/broadcasts/${input.broadcast_id}`
);
},
});
// ─── Audiences ──────────────────────────────────────────────────────────────
export interface NameInput {
name: string;
}
export const createAudience = tool({
description: 'Create a new audience for organizing contacts into groups.',
inputSchema: jsonSchema<NameInput>({
type: 'object',
properties: {
name: { type: 'string', description: 'Name for the audience.' },
},
required: ['name'],
additionalProperties: false,
}),
async execute(input: NameInput) {
return apiRequest<{ object: string; id: string; name: string }>('POST', '/audiences', input);
},
});
export const listAudiences = tool({
description: 'List all audiences in your Resend account with their names and creation dates.',
inputSchema: jsonSchema<PaginationInput>({
type: 'object',
properties: {
limit: { type: 'number', description: 'Max results to return (1-100, default 20).' },
after: { type: 'string', description: 'Cursor ID for forward pagination.' },
before: { type: 'string', description: 'Cursor ID for backward pagination.' },
},
additionalProperties: false,
}),
async execute(input: PaginationInput) {
const qs = buildQueryString({ ...input });
return apiRequest<{ object: string; has_more: boolean; data: unknown[] }>(
'GET',
`/audiences${qs}`
);
},
});
export interface AudienceIdInput {
audience_id: string;
}
export const getAudience = tool({
description: 'Retrieve details of a specific audience by its ID.',
inputSchema: jsonSchema<AudienceIdInput>({
type: 'object',
properties: {
audience_id: { type: 'string', description: 'The audience ID to retrieve.' },
},
required: ['audience_id'],
additionalProperties: false,
}),
async execute(input: AudienceIdInput) {
return apiRequest<Record<string, unknown>>('GET', `/audiences/${input.audience_id}`);
},
});
export const deleteAudience = tool({
description: 'Delete an audience from your Resend account permanently.',
inputSchema: jsonSchema<AudienceIdInput>({
type: 'object',
properties: {
audience_id: { type: 'string', description: 'The audience ID to delete.' },
},
required: ['audience_id'],
additionalProperties: false,
}),
async execute(input: AudienceIdInput) {
return apiRequest<{ object: string; id: string; deleted: boolean }>(
'DELETE',
`/audiences/${input.audience_id}`
);
},
});
// ─── Default Export ─────────────────────────────────────────────────────────
export default {
// Emails
sendEmail,
sendBatchEmails,
getEmail,
updateEmail,
cancelEmail,
listEmails,
// Domains
createDomain,
getDomain,
updateDomain,
deleteDomain,
listDomains,
verifyDomain,
// API Keys
createApiKey,
listApiKeys,
deleteApiKey,
// Contacts
createContact,
getContact,
updateContact,
deleteContact,
listContacts,
// Broadcasts
createBroadcast,
listBroadcasts,
sendBroadcast,
deleteBroadcast,
// Audiences
createAudience,
listAudiences,
getAudience,
deleteAudience,
};

View file

@ -0,0 +1,11 @@
{
"extends": "@tpmjs/tsconfig/base.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src",
"incremental": false,
"composite": false
},
"include": ["src"],
"exclude": ["node_modules", "dist"]
}

View file

@ -0,0 +1,10 @@
import { defineConfig } from 'tsup';
export default defineConfig({
entry: ['src/index.ts'],
format: ['esm'],
dts: true,
clean: true,
treeshake: true,
splitting: false,
});

View file

@ -1,11 +1,5 @@
import {
AbsoluteFill,
interpolate,
spring,
useCurrentFrame,
useVideoConfig,
} from 'remotion';
import { colors, typography, springConfigs } from '../../design-tokens';
import { AbsoluteFill, interpolate, spring, useCurrentFrame, useVideoConfig } from 'remotion';
import { colors, springConfigs, typography } from '../../design-tokens';
/**
* Feature 3: Collections (0:24 - 0:32)
@ -92,7 +86,7 @@ const CollectionCard = ({
>
{Array.from({ length: Math.min(toolCount, 5) }).map((_, i) => (
<div
key={i}
key={`dot-${String(i)}`}
style={{
width: 8,
height: 8,
@ -234,8 +228,7 @@ export const CollectionsFeatureScene = () => {
>
Curate tool sets
<br />
for specific{' '}
<span style={{ color: colors.copper.default }}>use cases</span>
for specific <span style={{ color: colors.copper.default }}>use cases</span>
</div>
<div
style={{

View file

@ -1,11 +1,5 @@
import {
AbsoluteFill,
interpolate,
spring,
useCurrentFrame,
useVideoConfig,
} from 'remotion';
import { colors, typography, springConfigs } from '../../design-tokens';
import { AbsoluteFill, interpolate, spring, useCurrentFrame, useVideoConfig } from 'remotion';
import { colors, springConfigs, typography } from '../../design-tokens';
/**
* Feature 4: Custom Agents (0:32 - 0:40)
@ -108,8 +102,7 @@ const AgentCard = ({
<div
style={{
padding: '4px 10px',
backgroundColor:
status === 'public' ? colors.status.successMuted : colors.bg.surface2,
backgroundColor: status === 'public' ? colors.status.successMuted : colors.bg.surface2,
border: `1px solid ${status === 'public' ? colors.status.success : colors.border.default}`,
fontSize: typography.fontSize.xs,
color: status === 'public' ? colors.status.success : colors.text.muted,

View file

@ -1,11 +1,5 @@
import {
AbsoluteFill,
interpolate,
spring,
useCurrentFrame,
useVideoConfig,
} from 'remotion';
import { colors, typography, springConfigs } from '../../design-tokens';
import { AbsoluteFill, interpolate, spring, useCurrentFrame, useVideoConfig } from 'remotion';
import { colors, springConfigs, typography } from '../../design-tokens';
/**
* Feature 9: Developer SDK (1:13 - 1:22)
@ -201,11 +195,7 @@ export const DeveloperSDKScene = () => {
/>
</div>
{codeLines.map((line, i) => (
<CodeLine
key={i}
{...line}
delay={fps * 0.5 + i * 5}
/>
<CodeLine key={line.text} {...line} delay={fps * 0.5 + i * 5} />
))}
</div>

View file

@ -1,11 +1,5 @@
import {
AbsoluteFill,
interpolate,
spring,
useCurrentFrame,
useVideoConfig,
} from 'remotion';
import { colors, typography, springConfigs } from '../../design-tokens';
import { AbsoluteFill, interpolate, spring, useCurrentFrame, useVideoConfig } from 'remotion';
import { colors, springConfigs, typography } from '../../design-tokens';
/**
* Feature 8: Living Skills (1:05 - 1:13)
@ -189,8 +183,7 @@ export const LivingSkillsScene = () => {
opacity: headerProgress,
}}
>
Documentation that{' '}
<span style={{ color: colors.copper.default }}>evolves</span>
Documentation that <span style={{ color: colors.copper.default }}>evolves</span>
</div>
<div
style={{

View file

@ -1,11 +1,5 @@
import {
AbsoluteFill,
interpolate,
spring,
useCurrentFrame,
useVideoConfig,
} from 'remotion';
import { colors, typography, springConfigs } from '../../design-tokens';
import { AbsoluteFill, interpolate, spring, useCurrentFrame, useVideoConfig } from 'remotion';
import { colors, springConfigs, typography } from '../../design-tokens';
/**
* Feature 5: MCP Protocol (0:40 - 0:49)
@ -253,11 +247,7 @@ export const MCPProtocolScene = () => {
}}
>
{clients.map((client, i) => (
<ClientLogo
key={client.name}
{...client}
delay={fps * 1 + i * 8}
/>
<ClientLogo key={client.name} {...client} delay={fps * 1 + i * 8} />
))}
</div>
@ -281,7 +271,7 @@ export const MCPProtocolScene = () => {
return (
<path
key={i}
key={`path-${String(i)}`}
d={path}
fill="none"
stroke={colors.copper.default}

View file

@ -1,11 +1,5 @@
import {
AbsoluteFill,
interpolate,
spring,
useCurrentFrame,
useVideoConfig,
} from 'remotion';
import { colors, typography, springConfigs } from '../../design-tokens';
import { AbsoluteFill, interpolate, spring, useCurrentFrame, useVideoConfig } from 'remotion';
import { colors, springConfigs, typography } from '../../design-tokens';
/**
* Feature 2: Omega Agent (0:15 - 0:24)
@ -13,11 +7,11 @@ import { colors, typography, springConfigs } from '../../design-tokens';
*/
const Message = ({
role,
sender,
content,
delay,
}: {
role: 'user' | 'assistant';
sender: 'user' | 'assistant';
content: string;
delay: number;
}) => {
@ -30,7 +24,7 @@ const Message = ({
config: springConfigs.snappy,
});
const isUser = role === 'user';
const isUser = sender === 'user';
return (
<div
@ -195,7 +189,7 @@ export const OmegaAgentScene = () => {
}}
>
<Message
role="user"
sender="user"
content="Scrape competitor pricing pages and create a comparison chart"
delay={fps * 0.5}
/>
@ -230,7 +224,7 @@ export const OmegaAgentScene = () => {
)}
<Message
role="assistant"
sender="assistant"
content="I've scraped 5 competitor pages and generated a comparison chart. Found 23% average price difference..."
delay={fps * 3.5}
/>
@ -256,8 +250,7 @@ export const OmegaAgentScene = () => {
color: colors.text.secondary,
}}
>
No configuration needed.{' '}
<span style={{ color: colors.copper.default }}>Just ask.</span>
No configuration needed. <span style={{ color: colors.copper.default }}>Just ask.</span>
</span>
</div>
</AbsoluteFill>

View file

@ -1,11 +1,5 @@
import {
AbsoluteFill,
interpolate,
spring,
useCurrentFrame,
useVideoConfig,
} from 'remotion';
import { colors, typography, springConfigs } from '../../design-tokens';
import { AbsoluteFill, interpolate, spring, useCurrentFrame, useVideoConfig } from 'remotion';
import { colors, springConfigs, typography } from '../../design-tokens';
/**
* Feature 6: Secure Execution (0:49 - 0:57)
@ -222,12 +216,7 @@ export const SecureExecutionScene = () => {
}}
>
{layers.map((layer, i) => (
<SecurityLayer
key={layer.label}
{...layer}
index={i}
delay={fps * 1 + i * 10}
/>
<SecurityLayer key={layer.label} {...layer} index={i} delay={fps * 1 + i * 10} />
))}
</div>
</div>

View file

@ -1,11 +1,5 @@
import {
AbsoluteFill,
interpolate,
spring,
useCurrentFrame,
useVideoConfig,
} from 'remotion';
import { colors, typography, springConfigs } from '../../design-tokens';
import { AbsoluteFill, interpolate, spring, useCurrentFrame, useVideoConfig } from 'remotion';
import { colors, springConfigs, typography } from '../../design-tokens';
/**
* Feature 7: Test Scenarios (0:57 - 1:05)

View file

@ -1,11 +1,5 @@
import {
AbsoluteFill,
interpolate,
spring,
useCurrentFrame,
useVideoConfig,
} from 'remotion';
import { colors, typography, springConfigs } from '../../design-tokens';
import { AbsoluteFill, interpolate, spring, useCurrentFrame, useVideoConfig } from 'remotion';
import { colors, springConfigs, typography } from '../../design-tokens';
/**
* Feature 1: Tool Registry (0:06 - 0:15)
@ -250,11 +244,7 @@ export const ToolRegistryScene = () => {
{/* Right - Tool list */}
<div style={{ flex: 1, maxWidth: 500 }}>
{tools.map((tool, i) => (
<ToolCard
key={tool.name}
{...tool}
delay={fps * 1 + i * 10}
/>
<ToolCard key={tool.name} {...tool} delay={fps * 1 + i * 10} />
))}
</div>
</div>