mirror of
https://github.com/eliasstepanik/core.git
synced 2026-01-22 13:18:30 +00:00
fix: emails are not sent on welcome
This commit is contained in:
parent
26a2d04ca9
commit
d062df14aa
@ -22,7 +22,7 @@ export function SpacePatternCard({ pattern }: SpacePatternCardProps) {
|
|||||||
actionType,
|
actionType,
|
||||||
patternId: pattern.id,
|
patternId: pattern.id,
|
||||||
},
|
},
|
||||||
{ method: "POST" }
|
{ method: "POST" },
|
||||||
);
|
);
|
||||||
setDialog(false);
|
setDialog(false);
|
||||||
};
|
};
|
||||||
@ -77,19 +77,19 @@ export function SpacePatternCard({ pattern }: SpacePatternCardProps) {
|
|||||||
|
|
||||||
<div className="flex justify-end">
|
<div className="flex justify-end">
|
||||||
<div className="flex gap-2">
|
<div className="flex gap-2">
|
||||||
<Button
|
<Button
|
||||||
variant="ghost"
|
variant="ghost"
|
||||||
onClick={() => handleAction("delete")}
|
onClick={() => handleAction("delete")}
|
||||||
disabled={fetcher.state === "submitting"}
|
disabled={fetcher.state === "submitting"}
|
||||||
>
|
>
|
||||||
Delete
|
Delete
|
||||||
</Button>
|
</Button>
|
||||||
<Button
|
<Button
|
||||||
variant="secondary"
|
variant="secondary"
|
||||||
onClick={() => handleAction("add")}
|
onClick={() => handleAction("add")}
|
||||||
disabled={fetcher.state === "submitting"}
|
disabled={fetcher.state === "submitting"}
|
||||||
>
|
>
|
||||||
Add
|
Add to memory
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
import { type Workspace } from "@core/database";
|
import { type Workspace } from "@core/database";
|
||||||
import { prisma } from "~/db.server";
|
import { prisma } from "~/db.server";
|
||||||
|
import { sendEmail } from "~/services/email.server";
|
||||||
import { SpaceService } from "~/services/space.server";
|
import { SpaceService } from "~/services/space.server";
|
||||||
|
|
||||||
interface CreateWorkspaceDto {
|
interface CreateWorkspaceDto {
|
||||||
@ -31,7 +32,7 @@ export async function createWorkspace(
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
await prisma.user.update({
|
const user = await prisma.user.update({
|
||||||
where: { id: input.userId },
|
where: { id: input.userId },
|
||||||
data: {
|
data: {
|
||||||
confirmedBasicDetails: true,
|
confirmedBasicDetails: true,
|
||||||
@ -45,6 +46,8 @@ export async function createWorkspace(
|
|||||||
workspaceId: workspace.id,
|
workspaceId: workspace.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
await sendEmail({ email: "welcome", to: user.email });
|
||||||
|
|
||||||
return workspace;
|
return workspace;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,5 +1,8 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { createActionApiRoute } from "~/services/routeBuilders/apiBuilder.server";
|
import {
|
||||||
|
createActionApiRoute,
|
||||||
|
createHybridActionApiRoute,
|
||||||
|
} from "~/services/routeBuilders/apiBuilder.server";
|
||||||
import { SearchService } from "~/services/search.server";
|
import { SearchService } from "~/services/search.server";
|
||||||
import { json } from "@remix-run/node";
|
import { json } from "@remix-run/node";
|
||||||
|
|
||||||
@ -19,7 +22,7 @@ export const SearchBodyRequest = z.object({
|
|||||||
});
|
});
|
||||||
|
|
||||||
const searchService = new SearchService();
|
const searchService = new SearchService();
|
||||||
const { action, loader } = createActionApiRoute(
|
const { action, loader } = createHybridActionApiRoute(
|
||||||
{
|
{
|
||||||
body: SearchBodyRequest,
|
body: SearchBodyRequest,
|
||||||
allowJWT: true,
|
allowJWT: true,
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
import { useActionData, useLoaderData } from "@remix-run/react";
|
import { useActionData } from "@remix-run/react";
|
||||||
import {
|
import {
|
||||||
type ActionFunctionArgs,
|
type ActionFunctionArgs,
|
||||||
json,
|
json,
|
||||||
@ -17,12 +17,7 @@ import {
|
|||||||
} from "~/components/ui/card";
|
} from "~/components/ui/card";
|
||||||
import { Button } from "~/components/ui";
|
import { Button } from "~/components/ui";
|
||||||
import { Input } from "~/components/ui/input";
|
import { Input } from "~/components/ui/input";
|
||||||
import { useState } from "react";
|
import { requireUser, requireUserId } from "~/services/session.server";
|
||||||
import {
|
|
||||||
requireUser,
|
|
||||||
requireUserId,
|
|
||||||
requireWorkpace,
|
|
||||||
} from "~/services/session.server";
|
|
||||||
import { redirectWithSuccessMessage } from "~/models/message.server";
|
import { redirectWithSuccessMessage } from "~/models/message.server";
|
||||||
import { rootPath } from "~/utils/pathBuilder";
|
import { rootPath } from "~/utils/pathBuilder";
|
||||||
import { createWorkspace, getWorkspaceByUser } from "~/models/workspace.server";
|
import { createWorkspace, getWorkspaceByUser } from "~/models/workspace.server";
|
||||||
@ -76,7 +71,6 @@ export const loader = async ({ request }: LoaderFunctionArgs) => {
|
|||||||
|
|
||||||
export default function ConfirmBasicDetails() {
|
export default function ConfirmBasicDetails() {
|
||||||
const lastSubmission = useActionData<typeof action>();
|
const lastSubmission = useActionData<typeof action>();
|
||||||
const { workspace } = useLoaderData<typeof loader>();
|
|
||||||
|
|
||||||
const [form, fields] = useForm({
|
const [form, fields] = useForm({
|
||||||
lastSubmission: lastSubmission as any,
|
lastSubmission: lastSubmission as any,
|
||||||
|
|||||||
@ -16,8 +16,8 @@ const client = singleton(
|
|||||||
new EmailClient({
|
new EmailClient({
|
||||||
transport: buildTransportOptions(),
|
transport: buildTransportOptions(),
|
||||||
imagesBaseUrl: env.APP_ORIGIN,
|
imagesBaseUrl: env.APP_ORIGIN,
|
||||||
from: env.FROM_EMAIL ?? "Harshith <harshith@tegon.ai>",
|
from: env.FROM_EMAIL ?? "Manik <manik@poozle.dev>",
|
||||||
replyTo: env.REPLY_TO_EMAIL ?? "harshith@tegon.ai",
|
replyTo: env.REPLY_TO_EMAIL ?? "manik@poozle.dev",
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -85,5 +85,9 @@ export async function scheduleEmail(
|
|||||||
) {}
|
) {}
|
||||||
|
|
||||||
export async function sendEmail(data: DeliverEmail) {
|
export async function sendEmail(data: DeliverEmail) {
|
||||||
return client.send(data);
|
try {
|
||||||
|
return client.send(data);
|
||||||
|
} catch (e) {
|
||||||
|
logger.error(`Error: ${e}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,6 +6,7 @@ import { MCP } from "../utils/mcp";
|
|||||||
import { type HistoryStep } from "../utils/types";
|
import { type HistoryStep } from "../utils/types";
|
||||||
import {
|
import {
|
||||||
createConversationHistoryForAgent,
|
createConversationHistoryForAgent,
|
||||||
|
deletePersonalAccessToken,
|
||||||
getCreditsForUser,
|
getCreditsForUser,
|
||||||
getPreviousExecutionHistory,
|
getPreviousExecutionHistory,
|
||||||
init,
|
init,
|
||||||
@ -120,9 +121,15 @@ export const chat = task({
|
|||||||
);
|
);
|
||||||
|
|
||||||
usageCredits && (await updateUserCredits(usageCredits, 1));
|
usageCredits && (await updateUserCredits(usageCredits, 1));
|
||||||
|
|
||||||
|
if (init?.tokenId) {
|
||||||
|
await deletePersonalAccessToken(init.tokenId);
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
await updateConversationStatus("failed", payload.conversationId);
|
await updateConversationStatus("failed", payload.conversationId);
|
||||||
|
if (init?.tokenId) {
|
||||||
|
await deletePersonalAccessToken(init.tokenId);
|
||||||
|
}
|
||||||
throw new Error(e as string);
|
throw new Error(e as string);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@ -4,8 +4,12 @@ import { z } from "zod";
|
|||||||
|
|
||||||
import { openai } from "@ai-sdk/openai";
|
import { openai } from "@ai-sdk/openai";
|
||||||
import { logger } from "~/services/logger.service";
|
import { logger } from "~/services/logger.service";
|
||||||
import { getOrCreatePersonalAccessToken } from "../utils/utils";
|
import {
|
||||||
|
deletePersonalAccessToken,
|
||||||
|
getOrCreatePersonalAccessToken,
|
||||||
|
} from "../utils/utils";
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
|
import { nanoid } from "nanoid";
|
||||||
|
|
||||||
export const ExtensionSearchBodyRequest = z.object({
|
export const ExtensionSearchBodyRequest = z.object({
|
||||||
userInput: z.string().min(1, "User input is required"),
|
userInput: z.string().min(1, "User input is required"),
|
||||||
@ -24,8 +28,10 @@ export const extensionSearch = task({
|
|||||||
const { userInput, userId, context } =
|
const { userInput, userId, context } =
|
||||||
ExtensionSearchBodyRequest.parse(body);
|
ExtensionSearchBodyRequest.parse(body);
|
||||||
|
|
||||||
|
const randomKeyName = `extensionSearch_${nanoid(10)}`;
|
||||||
|
|
||||||
const pat = await getOrCreatePersonalAccessToken({
|
const pat = await getOrCreatePersonalAccessToken({
|
||||||
name: "extensionSearch",
|
name: randomKeyName,
|
||||||
userId: userId as string,
|
userId: userId as string,
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -106,8 +112,12 @@ If no relevant information is found, provide a brief statement indicating that.`
|
|||||||
finalText = finalText + chunk;
|
finalText = finalText + chunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await deletePersonalAccessToken(pat?.id);
|
||||||
|
|
||||||
return finalText;
|
return finalText;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
await deletePersonalAccessToken(pat?.id);
|
||||||
|
|
||||||
logger.error(`SearchMemoryAgent error: ${error}`);
|
logger.error(`SearchMemoryAgent error: ${error}`);
|
||||||
|
|
||||||
return `Context related to: ${userInput}. Looking for relevant background information, previous discussions, and related concepts that would help provide a comprehensive answer.`;
|
return `Context related to: ${userInput}. Looking for relevant background information, previous discussions, and related concepts that would help provide a comprehensive answer.`;
|
||||||
|
|||||||
@ -170,7 +170,7 @@ export const init = async ({ payload }: { payload: InitChatPayload }) => {
|
|||||||
return { conversation, conversationHistory };
|
return { conversation, conversationHistory };
|
||||||
}
|
}
|
||||||
|
|
||||||
const randomKeyName = `chat`;
|
const randomKeyName = `chat_${nanoid(10)}`;
|
||||||
const pat = await getOrCreatePersonalAccessToken({
|
const pat = await getOrCreatePersonalAccessToken({
|
||||||
name: randomKeyName,
|
name: randomKeyName,
|
||||||
userId: workspace.userId as string,
|
userId: workspace.userId as string,
|
||||||
|
|||||||
@ -1,16 +1,16 @@
|
|||||||
import { Hr, Link, Text } from "@react-email/components";
|
import { Hr, Text } from "@react-email/components";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { footer, footerAnchor, hr } from "./styles";
|
import { footer, hr, paragraphLight } from "./styles";
|
||||||
|
|
||||||
export function Footer() {
|
export function Footer() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Hr style={hr} />
|
<Hr style={hr} />
|
||||||
|
<Text style={paragraphLight}>happy building your digital brain!</Text>
|
||||||
<Text style={footer}>
|
<Text style={footer}>
|
||||||
©Sol.ai
|
the Core team P.S Questions?
|
||||||
<Link style={footerAnchor} href="https://core.heysol.ai/">
|
<br />
|
||||||
C.O.R.E
|
Just hit reply - we're here to help.
|
||||||
</Link>
|
|
||||||
</Text>
|
</Text>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -8,10 +8,7 @@ export const h1 = {
|
|||||||
padding: "0",
|
padding: "0",
|
||||||
};
|
};
|
||||||
|
|
||||||
export const main = {
|
export const main = {};
|
||||||
backgroundColor: "#15171A",
|
|
||||||
padding: "0 20px",
|
|
||||||
};
|
|
||||||
|
|
||||||
export const container = {
|
export const container = {
|
||||||
backgroundColor: "#15171A",
|
backgroundColor: "#15171A",
|
||||||
@ -30,29 +27,42 @@ export const hr = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const paragraph = {
|
export const paragraph = {
|
||||||
color: "#878C99",
|
color: "black",
|
||||||
fontFamily:
|
fontFamily:
|
||||||
'-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Ubuntu,sans-serif',
|
'-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Ubuntu,sans-serif',
|
||||||
fontSize: "16px",
|
fontSize: "14px",
|
||||||
lineHeight: "24px",
|
lineHeight: "24px",
|
||||||
textAlign: "left" as const,
|
textAlign: "left" as const,
|
||||||
};
|
};
|
||||||
|
|
||||||
export const paragraphLight = {
|
export const paragraphLight = {
|
||||||
color: "#D7D9DD",
|
color: "black",
|
||||||
fontFamily:
|
fontFamily:
|
||||||
'-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Ubuntu,sans-serif',
|
'-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Ubuntu,sans-serif',
|
||||||
fontSize: "16px",
|
fontSize: "14px",
|
||||||
lineHeight: "24px",
|
lineHeight: "24px",
|
||||||
textAlign: "left" as const,
|
textAlign: "left" as const,
|
||||||
|
margin: 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
export const heading = {
|
||||||
|
color: "black",
|
||||||
|
fontFamily:
|
||||||
|
'-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Ubuntu,sans-serif',
|
||||||
|
fontSize: "14px",
|
||||||
|
lineHeight: "24px",
|
||||||
|
textAlign: "left" as const,
|
||||||
|
fontWeight: "bold",
|
||||||
|
margin: 0,
|
||||||
|
marginTop: "20px",
|
||||||
};
|
};
|
||||||
|
|
||||||
export const paragraphTight = {
|
export const paragraphTight = {
|
||||||
color: "#D7D9DD",
|
color: "black",
|
||||||
fontFamily:
|
fontFamily:
|
||||||
'-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Ubuntu,sans-serif',
|
'-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Ubuntu,sans-serif',
|
||||||
fontSize: "16px",
|
fontSize: "14px",
|
||||||
lineHeight: "16px",
|
lineHeight: "14px",
|
||||||
textAlign: "left" as const,
|
textAlign: "left" as const,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -60,18 +70,19 @@ export const bullets = {
|
|||||||
color: "#D7D9DD",
|
color: "#D7D9DD",
|
||||||
fontFamily:
|
fontFamily:
|
||||||
'-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Ubuntu,sans-serif',
|
'-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Ubuntu,sans-serif',
|
||||||
fontSize: "16px",
|
fontSize: "14px",
|
||||||
lineHeight: "24px",
|
lineHeight: "24px",
|
||||||
textAlign: "left" as const,
|
textAlign: "left" as const,
|
||||||
margin: "0",
|
margin: "0",
|
||||||
};
|
};
|
||||||
|
|
||||||
export const anchor = {
|
export const anchor = {
|
||||||
color: "#826DFF",
|
marginRight: "3px",
|
||||||
fontFamily:
|
fontFamily:
|
||||||
"-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif",
|
"-apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', sans-serif",
|
||||||
fontSize: "16px",
|
fontSize: "14px",
|
||||||
textDecoration: "underline",
|
textDecoration: "underline",
|
||||||
|
color: "black",
|
||||||
};
|
};
|
||||||
|
|
||||||
export const button = {
|
export const button = {
|
||||||
@ -80,7 +91,7 @@ export const button = {
|
|||||||
color: "#D7D9DD",
|
color: "#D7D9DD",
|
||||||
fontFamily:
|
fontFamily:
|
||||||
'-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Ubuntu,sans-serif',
|
'-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Ubuntu,sans-serif',
|
||||||
fontSize: "16px",
|
fontSize: "14px",
|
||||||
fontWeight: "bold",
|
fontWeight: "bold",
|
||||||
textDecoration: "none",
|
textDecoration: "none",
|
||||||
textAlign: "center" as const,
|
textAlign: "center" as const,
|
||||||
@ -92,7 +103,7 @@ export const footer = {
|
|||||||
fontFamily:
|
fontFamily:
|
||||||
'-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Ubuntu,sans-serif',
|
'-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Ubuntu,sans-serif',
|
||||||
fontSize: "12px",
|
fontSize: "12px",
|
||||||
lineHeight: "16px",
|
lineHeight: "14px",
|
||||||
};
|
};
|
||||||
|
|
||||||
export const footerItalic = {
|
export const footerItalic = {
|
||||||
@ -101,7 +112,7 @@ export const footerItalic = {
|
|||||||
fontFamily:
|
fontFamily:
|
||||||
'-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Ubuntu,sans-serif',
|
'-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Ubuntu,sans-serif',
|
||||||
fontSize: "12px",
|
fontSize: "12px",
|
||||||
lineHeight: "16px",
|
lineHeight: "14px",
|
||||||
};
|
};
|
||||||
|
|
||||||
export const footerAnchor = {
|
export const footerAnchor = {
|
||||||
|
|||||||
@ -1,59 +1,86 @@
|
|||||||
import { Body, Head, Html, Link, Preview, Section, Text } from "@react-email/components";
|
import { Body, Head, Html, Img, Link, Preview, Text } from "@react-email/components";
|
||||||
import { Footer } from "./components/Footer";
|
import { Footer } from "./components/Footer";
|
||||||
import { anchor, bullets, footerItalic, main, paragraphLight } from "./components/styles";
|
import { anchor, heading, main, paragraphLight } from "./components/styles";
|
||||||
import { z } from "zod";
|
import { z } from "zod";
|
||||||
|
|
||||||
export const WelcomeEmailSchema = z.object({
|
export const WelcomeEmailSchema = z.object({
|
||||||
email: z.literal("welcome"),
|
email: z.literal("welcome"),
|
||||||
orgName: z.string(),
|
|
||||||
inviterName: z.string().optional(),
|
|
||||||
inviterEmail: z.string(),
|
|
||||||
inviteLink: z.string().url(),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export function WelcomeEmail({ orgName }: { orgName?: string }) {
|
export default function WelcomeEmail() {
|
||||||
return (
|
return (
|
||||||
<Html>
|
<Html>
|
||||||
<Head />
|
<Head />
|
||||||
<Preview>Welcome to C.O.R.E. - Your Personal AI Assistant</Preview>
|
<Preview>building your digital brain</Preview>
|
||||||
<Body style={main}>
|
<Body style={main}>
|
||||||
<Text style={paragraphLight}>Hey {orgName ?? "there"},</Text>
|
<Text style={paragraphLight}>hi there,</Text>
|
||||||
<Text style={paragraphLight}>Welcome to C.O.R.E., your new personal AI assistant!</Text>
|
<Text
|
||||||
<Text style={paragraphLight}>
|
style={{
|
||||||
I'm excited to help you streamline your daily tasks, boost your productivity, and make
|
...paragraphLight,
|
||||||
your work life easier. C.O.R.E. is designed to be intuitive and powerful, adapting to your
|
marginTop: "10px",
|
||||||
unique needs and preferences.
|
}}
|
||||||
</Text>
|
>
|
||||||
<Text style={paragraphLight}>
|
<Link style={anchor} href="https://x.com/manikagg01">
|
||||||
To get started, you can{" "}
|
Manik
|
||||||
<Link style={anchor} href="https://core.heysol.ai/home">
|
|
||||||
visit your dashboard
|
|
||||||
</Link>{" "}
|
|
||||||
where you'll find all the features and capabilities at your disposal. Whether it's
|
|
||||||
managing your schedule, handling communications, or automating repetitive tasks, I'm here
|
|
||||||
to help.
|
|
||||||
</Text>
|
|
||||||
|
|
||||||
<Text style={paragraphLight}>
|
|
||||||
If you have any questions or need assistance, don't hesitate to reach out. You can:{"\n"}•
|
|
||||||
Ask me directly through the chat interface{"\n"}•{" "}
|
|
||||||
<Link style={anchor} href="https://core.heysol.ai/support">
|
|
||||||
Visit our support center
|
|
||||||
</Link>
|
</Link>
|
||||||
{"\n"}• Join our{" "}
|
from core here. welcome to core. when i first tried core memory, two actions made it click
|
||||||
<Link style={anchor} href="https://discord.gg/heysol">
|
for me. each came down to the same thing: understanding how I can add relevant context
|
||||||
Discord community
|
about everything that matters to me in core memory and recall it wherever I want.
|
||||||
</Link>{" "}
|
|
||||||
to connect with other users and our team
|
|
||||||
</Text>
|
</Text>
|
||||||
|
<Text style={heading}>core mcp</Text>
|
||||||
|
<Text style={paragraphLight}>
|
||||||
|
seamlessly add your code context from cursor/claude-code, project context from linear, or
|
||||||
|
brainstorming sessions from claude desktop via mcp. solve context loss problems across ai
|
||||||
|
tools with persistent, cross-session memory. add this url and get started
|
||||||
|
</Text>
|
||||||
|
<Link
|
||||||
|
style={{
|
||||||
|
...anchor,
|
||||||
|
marginTop: "10px",
|
||||||
|
marginBottom: "10px",
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
https://core.heysol.ai/api/v1/mcp?source='Your Coding Agent'
|
||||||
|
</Link>
|
||||||
|
<Img
|
||||||
|
alt="Claude"
|
||||||
|
style={{
|
||||||
|
marginLeft: "auto",
|
||||||
|
marginRight: "auto",
|
||||||
|
width: "100%",
|
||||||
|
borderRadius: "2%",
|
||||||
|
marginTop: "10px",
|
||||||
|
}}
|
||||||
|
src="https://integrations.heysol.ai/core-claude.gif"
|
||||||
|
/>
|
||||||
|
<Text style={heading}>browser extension</Text>
|
||||||
|
<Text style={paragraphLight}>
|
||||||
|
recall relevant context from core memory in chatgpt, grok, and gemini. save conversations
|
||||||
|
and content from chatgpt, grok, gemini, twitter, youtube, blog posts, and any webpage
|
||||||
|
directly into your Core memory with simple text selection.
|
||||||
|
</Text>
|
||||||
|
<Img
|
||||||
|
alt="Claude"
|
||||||
|
style={{
|
||||||
|
marginLeft: "auto",
|
||||||
|
marginRight: "auto",
|
||||||
|
width: "100%",
|
||||||
|
borderRadius: "2%",
|
||||||
|
marginTop: "10px",
|
||||||
|
}}
|
||||||
|
src="https://integrations.heysol.ai/core-extension.gif"
|
||||||
|
/>
|
||||||
|
|
||||||
<Text style={paragraphLight}>Looking forward to being your trusted assistant!</Text>
|
<Text style={heading}>need real-time, human help to get started? </Text>
|
||||||
|
<Text style={paragraphLight}>
|
||||||
<Text style={bullets}>Best regards,</Text>
|
- join our discord community & get direct help from our team + over 100+ enthusiasts using
|
||||||
<Text style={bullets}>C.O.R.E.</Text>
|
Core memory
|
||||||
<Text style={paragraphLight}>Your AI Assistant</Text>
|
</Text>
|
||||||
<Text style={footerItalic}>
|
<Text style={paragraphLight}>
|
||||||
You can customize your notification preferences anytime in your account settings.
|
- We are open-source us on our repo -{" "}
|
||||||
|
<Link style={anchor} href="https://github.com/RedPlanetHQ/core">
|
||||||
|
https://github.com/RedPlanetHQ/core
|
||||||
|
</Link>
|
||||||
</Text>
|
</Text>
|
||||||
<Footer />
|
<Footer />
|
||||||
</Body>
|
</Body>
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import { z } from "zod";
|
|||||||
|
|
||||||
import { setGlobalBasePath } from "../emails/components/BasePath";
|
import { setGlobalBasePath } from "../emails/components/BasePath";
|
||||||
|
|
||||||
import { WelcomeEmail, WelcomeEmailSchema } from "../emails/welcome";
|
import WelcomeEmail, { WelcomeEmailSchema } from "../emails/welcome";
|
||||||
import { constructMailTransport, MailTransport, MailTransportOptions } from "./transports";
|
import { constructMailTransport, MailTransport, MailTransportOptions } from "./transports";
|
||||||
import MagicLinkEmail from "../emails/magic-link";
|
import MagicLinkEmail from "../emails/magic-link";
|
||||||
|
|
||||||
@ -73,14 +73,14 @@ export class EmailClient {
|
|||||||
switch (data.email) {
|
switch (data.email) {
|
||||||
case "magic_link":
|
case "magic_link":
|
||||||
return {
|
return {
|
||||||
subject: "Magic sign-in link for Trigger.dev",
|
subject: "Magic sign-in link for Core",
|
||||||
component: <MagicLinkEmail magicLink={data.magicLink} />,
|
component: <MagicLinkEmail magicLink={data.magicLink} />,
|
||||||
};
|
};
|
||||||
|
|
||||||
case "welcome":
|
case "welcome":
|
||||||
return {
|
return {
|
||||||
subject: `You've been invited to join ${data.orgName} on C.O.R.E.`,
|
subject: `You've been invited to join on C.O.R.E.`,
|
||||||
component: <WelcomeEmail {...data} />,
|
component: <WelcomeEmail />,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,20 +2,20 @@ import { EmailError, MailMessage, MailTransport, PlainTextMailMessage } from "./
|
|||||||
import { Resend } from "resend";
|
import { Resend } from "resend";
|
||||||
|
|
||||||
export type ResendMailTransportOptions = {
|
export type ResendMailTransportOptions = {
|
||||||
type: 'resend',
|
type: "resend";
|
||||||
config: {
|
config: {
|
||||||
apiKey?: string
|
apiKey?: string;
|
||||||
}
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
export class ResendMailTransport implements MailTransport {
|
export class ResendMailTransport implements MailTransport {
|
||||||
#client: Resend;
|
#client: Resend;
|
||||||
|
|
||||||
constructor(options: ResendMailTransportOptions) {
|
constructor(options: ResendMailTransportOptions) {
|
||||||
this.#client = new Resend(options.config.apiKey)
|
this.#client = new Resend(options.config.apiKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
async send({to, from, replyTo, subject, react}: MailMessage): Promise<void> {
|
async send({ to, from, replyTo, subject, react }: MailMessage): Promise<void> {
|
||||||
const result = await this.#client.emails.send({
|
const result = await this.#client.emails.send({
|
||||||
from: from,
|
from: from,
|
||||||
to,
|
to,
|
||||||
@ -25,6 +25,7 @@ export class ResendMailTransport implements MailTransport {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (result.error) {
|
if (result.error) {
|
||||||
|
console.log(result);
|
||||||
console.error(
|
console.error(
|
||||||
`Failed to send email to ${to}, ${subject}. Error ${result.error.name}: ${result.error.message}`
|
`Failed to send email to ${to}, ${subject}. Error ${result.error.name}: ${result.error.message}`
|
||||||
);
|
);
|
||||||
@ -32,7 +33,7 @@ export class ResendMailTransport implements MailTransport {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async sendPlainText({to, from, replyTo, subject, text}: PlainTextMailMessage): Promise<void> {
|
async sendPlainText({ to, from, replyTo, subject, text }: PlainTextMailMessage): Promise<void> {
|
||||||
const result = await this.#client.emails.send({
|
const result = await this.#client.emails.send({
|
||||||
from: from,
|
from: from,
|
||||||
to,
|
to,
|
||||||
|
|||||||
@ -74,6 +74,11 @@
|
|||||||
"TRIGGER_API_URL",
|
"TRIGGER_API_URL",
|
||||||
"TRIGGER_SECRET_KEY",
|
"TRIGGER_SECRET_KEY",
|
||||||
"EMBEDDING_MODEL",
|
"EMBEDDING_MODEL",
|
||||||
"MODEL"
|
"MODEL",
|
||||||
|
"COHERE_API_KEY",
|
||||||
|
"RESEND_API_KEY",
|
||||||
|
"FROM_EMAIL",
|
||||||
|
"REPLY_TO_EMAIL",
|
||||||
|
"EMAIL_TRANSPORT"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user