From b8e5376b99a4660af5fa69f5a2d6c1c39efbe32c Mon Sep 17 00:00:00 2001 From: MaheshtheDev <38828053+MaheshtheDev@users.noreply.github.com> Date: Thu, 16 Apr 2026 16:40:15 +0000 Subject: [PATCH 01/55] fix: input disable when onboarding org creation (#855) --- .../app/(app)/onboarding/welcome/layout.tsx | 7 +- .../web/app/(app)/onboarding/welcome/page.tsx | 106 +++++++++--------- apps/web/components/initial-header.tsx | 41 +++++-- .../components/onboarding/setup/header.tsx | 27 ++++- .../onboarding/welcome/input-step.tsx | 21 +++- 5 files changed, 136 insertions(+), 66 deletions(-) diff --git a/apps/web/app/(app)/onboarding/welcome/layout.tsx b/apps/web/app/(app)/onboarding/welcome/layout.tsx index 2b889d38..8a685368 100644 --- a/apps/web/app/(app)/onboarding/welcome/layout.tsx +++ b/apps/web/app/(app)/onboarding/welcome/layout.tsx @@ -11,6 +11,7 @@ import { } from "react" import { useRouter, useSearchParams } from "next/navigation" import { useOnboardingContext, type MemoryFormData } from "../layout" +import { useAuth } from "@lib/auth-context" import { analytics } from "@/lib/analytics" export const WELCOME_STEPS = [ @@ -51,13 +52,17 @@ export default function WelcomeLayout({ children }: { children: ReactNode }) { const searchParams = useSearchParams() const { name, setName, memoryFormData, setMemoryFormData } = useOnboardingContext() + const { organizations } = useAuth() + const hasOrgs = Array.isArray(organizations) && organizations.length > 0 const stepParam = searchParams.get("step") - const currentStep: WelcomeStep = WELCOME_STEPS.includes( + const resolvedStep: WelcomeStep = WELCOME_STEPS.includes( stepParam as WelcomeStep, ) ? (stepParam as WelcomeStep) : "input" + const currentStep: WelcomeStep = + resolvedStep === "input" && hasOrgs ? "greeting" : resolvedStep const [isSubmitting, setIsSubmitting] = useState(false) const [showWelcomeContent, setShowWelcomeContent] = useState(false) diff --git a/apps/web/app/(app)/onboarding/welcome/page.tsx b/apps/web/app/(app)/onboarding/welcome/page.tsx index e0df2445..ac3ea599 100644 --- a/apps/web/app/(app)/onboarding/welcome/page.tsx +++ b/apps/web/app/(app)/onboarding/welcome/page.tsx @@ -1,5 +1,6 @@ "use client" +import { useRef } from "react" import { motion, AnimatePresence } from "motion/react" import { cn } from "@lib/utils" @@ -102,66 +103,70 @@ export default function WelcomePage() { } = useWelcomeContext() const { refetchOrganizations, setActiveOrg } = useAuth() + const submitLockRef = useRef(false) const handleSubmit = async () => { - localStorage.setItem("username", name) - if (name.trim()) { - setIsSubmitting(true) + const trimmed = name.trim() + if (!trimmed) return + if (submitLockRef.current) return + submitLockRef.current = true + localStorage.setItem("username", trimmed) + setIsSubmitting(true) - try { - await authClient.updateUser({ - displayUsername: name.trim(), - username: generateUsername(name.trim()), + try { + await authClient.updateUser({ + displayUsername: trimmed, + username: generateUsername(trimmed), + }) + + const refetchResult = await refetchOrganizations() + const refetchData = ( + refetchResult as { data?: unknown[] | null | undefined } + )?.data + const existingOrgs = Array.isArray(refetchData) ? refetchData : [] + + if (existingOrgs.length > 0) { + analytics.onboardingNameSubmitted({ + name_length: trimmed.length, }) + goToStep("greeting") + return + } - const refetchResult = await refetchOrganizations() - const refetchData = ( - refetchResult as { data?: unknown[] | null | undefined } - )?.data - const existingOrgs = Array.isArray(refetchData) ? refetchData : [] - - if (existingOrgs.length > 0) { - analytics.onboardingNameSubmitted({ - name_length: name.trim().length, - }) - goToStep("greeting") - return - } - - const uniqueSlug = generateOrgSlug(name.trim()) - const completedAt = new Date().toISOString() - const newOrg = await authClient.organization.create({ - name: name.trim(), - slug: uniqueSlug, - metadata: { - signupSource: "consumer", - webOnboarding: { - completedAt: null, - steps: { - welcomeInput: { - startedAt: completedAt, - completedAt, - data: {}, - }, + const uniqueSlug = generateOrgSlug(trimmed) + const completedAt = new Date().toISOString() + const newOrg = await authClient.organization.create({ + name: trimmed, + slug: uniqueSlug, + metadata: { + signupSource: "consumer", + webOnboarding: { + completedAt: null, + steps: { + welcomeInput: { + startedAt: completedAt, + completedAt, + data: {}, }, }, }, - }) + }, + }) - await setActiveOrg(newOrg.slug) + await setActiveOrg(newOrg.slug) - analytics.onboardingNameSubmitted({ name_length: name.trim().length }) - goToStep("greeting") - } catch (error) { - console.error("Onboarding submit failed:", error) - toast.error( - error instanceof Error - ? error.message - : "Could not set up your workspace. Please try again.", - ) - } finally { - setIsSubmitting(false) - } + analytics.onboardingNameSubmitted({ name_length: trimmed.length }) + goToStep("greeting") + } catch (error) { + console.error("Onboarding submit failed:", error) + toast.error( + error instanceof Error + ? error.message + : "Could not set up your workspace. Please try again.", + ) + } finally { + submitLockRef.current = false + setIsSubmitting(false) } } @@ -212,6 +217,7 @@ export default function WelcomePage() { showUserSupermemory={ currentStep === "features" || currentStep === "memories" } + showSkipOnboarding={currentStep !== "input"} name={name} /> diff --git a/apps/web/components/initial-header.tsx b/apps/web/components/initial-header.tsx index 91edfa57..5d8aebc9 100644 --- a/apps/web/components/initial-header.tsx +++ b/apps/web/components/initial-header.tsx @@ -1,14 +1,30 @@ +"use client" + import { Logo } from "@ui/assets/Logo" import { Button } from "@ui/components/button" +import { useRouter } from "next/navigation" +import { useOrgOnboarding } from "@hooks/use-org-onboarding" +import { analytics } from "@/lib/analytics" export function InitialHeader({ showUserSupermemory, + showSkipOnboarding, name, }: { showUserSupermemory?: boolean + showSkipOnboarding?: boolean name?: string }) { + const router = useRouter() + const { markOrgOnboarded, isLoading } = useOrgOnboarding() const userName = name ? `${name.split(" ")[0]}'s` : "My" + + const handleSkip = () => { + markOrgOnboarded() + analytics.onboardingCompleted() + router.push("/") + } + return (
@@ -24,13 +40,24 @@ export function InitialHeader({
)}
- +
+ {showSkipOnboarding && !isLoading && ( + + )} + +
) } diff --git a/apps/web/components/onboarding/setup/header.tsx b/apps/web/components/onboarding/setup/header.tsx index 59dd4fbb..97c0cea7 100644 --- a/apps/web/components/onboarding/setup/header.tsx +++ b/apps/web/components/onboarding/setup/header.tsx @@ -8,11 +8,20 @@ import { useRouter } from "next/navigation" import { cn } from "@lib/utils" import { dmSansClassName } from "@/lib/fonts" import { useLocalStorageUsername } from "@hooks/use-local-storage-username" +import { useOrgOnboarding } from "@hooks/use-org-onboarding" +import { analytics } from "@/lib/analytics" export function SetupHeader() { const { user } = useAuth() const router = useRouter() const localStorageUsername = useLocalStorageUsername() + const { markOrgOnboarded, isLoading: isOrgLoading } = useOrgOnboarding() + + const handleSkip = () => { + markOrgOnboarded() + analytics.onboardingCompleted() + router.push("/") + } const displayName = user?.displayUsername || localStorageUsername || user?.name || "" @@ -59,9 +68,21 @@ export function SetupHeader() { Setup - {user && ( - - )} +
+ {!isOrgLoading && ( + + )} + {user && } +
) } diff --git a/apps/web/components/onboarding/welcome/input-step.tsx b/apps/web/components/onboarding/welcome/input-step.tsx index 077d4944..7cb7fdb3 100644 --- a/apps/web/components/onboarding/welcome/input-step.tsx +++ b/apps/web/components/onboarding/welcome/input-step.tsx @@ -1,4 +1,5 @@ import { motion } from "motion/react" +import { cn } from "@lib/utils" import { LabeledInput } from "@ui/input/labeled-input" import { Button } from "@ui/components/button" @@ -17,7 +18,10 @@ export function InputStep({ }: InputStepProps) { return ( { - if (e.key === "Enter") { - handleSubmit() - } + if (e.key !== "Enter") return + e.preventDefault() + if (isSubmitting) return + handleSubmit() }, className: "!text-white placeholder:!text-[#525966] !h-[40px] pl-4", }} - onChange={(e) => setName((e.target as HTMLInputElement).value)} + onChange={(e) => { + if (isSubmitting) return + setName((e.target as HTMLInputElement).value) + }} style={{ background: "linear-gradient(0deg, rgba(91, 126, 245, 0.04) 0%, rgba(91, 126, 245, 0.04) 100%)", }} /> + +

+ Share what you want next—we’d love a quick call. +

+
+ + Book a call + +
+ + + + ) +} diff --git a/apps/web/lib/analytics.ts b/apps/web/lib/analytics.ts index 71fad27f..0799de5f 100644 --- a/apps/web/lib/analytics.ts +++ b/apps/web/lib/analytics.ts @@ -46,6 +46,11 @@ export const analytics = { connectionAuthCompleted: () => safeCapture("connection_auth_completed"), connectionAuthFailed: () => safeCapture("connection_auth_failed"), + nextAppResearchCtaDismissed: () => + safeCapture("next_app_research_cta_dismissed"), + nextAppResearchCtaBookCallClicked: () => + safeCapture("next_app_research_cta_book_call_clicked"), + mcpViewOpened: () => safeCapture("mcp_view_opened"), mcpInstallCmdCopied: () => safeCapture("mcp_install_cmd_copied"), From 20c5a18e138a0b89c778851707cfecdd0239d47b Mon Sep 17 00:00:00 2001 From: MaheshtheDev <38828053+MaheshtheDev@users.noreply.github.com> Date: Tue, 21 Apr 2026 16:43:23 +0000 Subject: [PATCH 10/55] chore: skipMemoryOnError for withSupermemory (#871) --- apps/docs/integrations/ai-sdk.mdx | 12 +++++ packages/tools/package.json | 2 +- packages/tools/src/vercel/index.ts | 73 +++++++++++++++++++++++++----- 3 files changed, 75 insertions(+), 12 deletions(-) diff --git a/apps/docs/integrations/ai-sdk.mdx b/apps/docs/integrations/ai-sdk.mdx index a9e2d6f8..ee6ef406 100644 --- a/apps/docs/integrations/ai-sdk.mdx +++ b/apps/docs/integrations/ai-sdk.mdx @@ -106,6 +106,18 @@ const model = withSupermemory(openai("gpt-4"), "user-123", { // Console output shows memory retrieval details ``` +### When Supermemory errors (optional: continue without memories) + +If the Supermemory API returns an error (or is unreachable), memory retrieval fails before the LLM runs. By default that error **propagates** (fails the call). + +To continue the LLM request **without** injected memories instead, opt in with `skipMemoryOnError: true`. Use `verbose: true` if you want console output when that happens. + +```typescript +const model = withSupermemory(openai("gpt-5"), "user-123", { + skipMemoryOnError: true +}) +``` + --- ## Memory Tools diff --git a/packages/tools/package.json b/packages/tools/package.json index c4a39da4..3fd3b8e9 100644 --- a/packages/tools/package.json +++ b/packages/tools/package.json @@ -1,7 +1,7 @@ { "name": "@supermemory/tools", "type": "module", - "version": "1.4.4", + "version": "1.4.5", "description": "Memory tools for AI SDK and OpenAI function calling with supermemory", "scripts": { "build": "tsdown", diff --git a/packages/tools/src/vercel/index.ts b/packages/tools/src/vercel/index.ts index b56b76a3..c13ec39c 100644 --- a/packages/tools/src/vercel/index.ts +++ b/packages/tools/src/vercel/index.ts @@ -50,6 +50,12 @@ interface WrapVercelLanguageModelOptions { * ``` */ promptTemplate?: PromptTemplate + /** + * When Supermemory memory retrieval / injection fails: + * - `false` (default): propagate the error. + * - `true`: log and call the base model with the original prompt (no memories). + */ + skipMemoryOnError?: boolean } /** @@ -72,6 +78,7 @@ interface WrapVercelLanguageModelOptions { * @param options.addMemory - Optional mode for memory search: "always", "never" (default: "never") * @param options.apiKey - Optional Supermemory API key to use instead of the environment variable * @param options.baseUrl - Optional base URL for the Supermemory API (default: "https://api.supermemory.ai") + * @param options.skipMemoryOnError - When memory retrieval fails: `false` (default) throws; `true` continues without injected memories * * @returns A wrapped language model that automatically includes relevant memories in prompts * @@ -93,7 +100,7 @@ interface WrapVercelLanguageModelOptions { * ``` * * @throws {Error} When neither `options.apiKey` nor `process.env.SUPERMEMORY_API_KEY` are set - * @throws {Error} When supermemory API request fails + * @throws {Error} When supermemory memory retrieval fails unless `skipMemoryOnError` is `true` */ const wrapVercelLanguageModel = ( model: T, @@ -119,19 +126,42 @@ const wrapVercelLanguageModel = ( promptTemplate: options?.promptTemplate, }) + const skipMemoryOnError = options?.skipMemoryOnError ?? false + // Proxy keeps prototype/getter fields (e.g. provider, modelId) that `{ ...model }` drops. return new Proxy(model, { get(target, prop, receiver) { if (prop === "doGenerate") { return async (params: LanguageModelCallOptions) => { + let modelParams: LanguageModelCallOptions = params try { - const transformedParams = await transformParamsWithMemory( - params, - ctx, - ) + modelParams = await transformParamsWithMemory(params, ctx) + } catch (memoryError) { + if (skipMemoryOnError) { + ctx.logger.warn( + "Supermemory retrieval failed; continuing without injected memories", + { + error: + memoryError instanceof Error + ? memoryError.message + : "Unknown error", + }, + ) + modelParams = params + } else { + ctx.logger.error("Error during memory retrieval for generation", { + error: + memoryError instanceof Error + ? memoryError.message + : "Unknown error", + }) + throw memoryError + } + } + try { // biome-ignore lint/suspicious/noExplicitAny: Union type compatibility between V2 and V3 - const result = await target.doGenerate(transformedParams as any) + const result = await target.doGenerate(modelParams as any) const userMessage = getLastUserMessage(params) if ( @@ -168,15 +198,36 @@ const wrapVercelLanguageModel = ( return async (params: LanguageModelCallOptions) => { let generatedText = "" + let modelParams: LanguageModelCallOptions = params try { - const transformedParams = await transformParamsWithMemory( - params, - ctx, - ) + modelParams = await transformParamsWithMemory(params, ctx) + } catch (memoryError) { + if (skipMemoryOnError) { + ctx.logger.warn( + "Supermemory retrieval failed; continuing without injected memories", + { + error: + memoryError instanceof Error + ? memoryError.message + : "Unknown error", + }, + ) + modelParams = params + } else { + ctx.logger.error("Error during memory retrieval for stream", { + error: + memoryError instanceof Error + ? memoryError.message + : "Unknown error", + }) + throw memoryError + } + } + try { const { stream, ...rest } = await target.doStream( // biome-ignore lint/suspicious/noExplicitAny: Union type compatibility between V2 and V3 - transformedParams as any, + modelParams as any, ) const transformStream = new TransformStream< From fab056a01ad8b6b38442d67d3c368ba42ab1960e Mon Sep 17 00:00:00 2001 From: MaheshtheDev <38828053+MaheshtheDev@users.noreply.github.com> Date: Tue, 21 Apr 2026 17:37:15 +0000 Subject: [PATCH 11/55] fix: auto publish actions (#872) --- .github/workflows/ci.yml | 2 +- .github/workflows/publish-ai-sdk.yml | 3 --- .github/workflows/publish-memory-graph.yml | 3 --- .github/workflows/publish-tools.yml | 3 --- package.json | 2 +- 5 files changed, 2 insertions(+), 11 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f0226440..20842238 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,7 +16,7 @@ jobs: - name: Setup Bun uses: oven-sh/setup-bun@v2 with: - bun-version: 1.3.4 + bun-version: 1.3.6 - name: Install dependencies run: bun install --frozen-lockfile diff --git a/.github/workflows/publish-ai-sdk.yml b/.github/workflows/publish-ai-sdk.yml index 848c7a71..27817b20 100644 --- a/.github/workflows/publish-ai-sdk.yml +++ b/.github/workflows/publish-ai-sdk.yml @@ -31,9 +31,6 @@ jobs: - name: Setup Bun uses: oven-sh/setup-bun@v2 - - - name: Setup pnpm - uses: pnpm/action-setup@v4 - name: Install dependencies run: bun install diff --git a/.github/workflows/publish-memory-graph.yml b/.github/workflows/publish-memory-graph.yml index 295a45f6..66dcbf3c 100644 --- a/.github/workflows/publish-memory-graph.yml +++ b/.github/workflows/publish-memory-graph.yml @@ -31,9 +31,6 @@ jobs: - name: Setup Bun uses: oven-sh/setup-bun@v2 - - - name: Setup pnpm - uses: pnpm/action-setup@v4 - name: Install dependencies run: bun install diff --git a/.github/workflows/publish-tools.yml b/.github/workflows/publish-tools.yml index 9d745203..46a56329 100644 --- a/.github/workflows/publish-tools.yml +++ b/.github/workflows/publish-tools.yml @@ -31,9 +31,6 @@ jobs: - name: Setup Bun uses: oven-sh/setup-bun@v2 - - - name: Setup pnpm - uses: pnpm/action-setup@v4 - name: Install dependencies run: bun install diff --git a/package.json b/package.json index 323ff70d..7f4bddd9 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,7 @@ "engines": { "node": ">=20" }, - "packageManager": "bun@1.3.4", + "packageManager": "bun@1.3.6", "workspaces": [ "apps/*", "!apps/raycast-extension", From 8a6b50332bb1ff54d4374d5d3ddd726d040dbbc6 Mon Sep 17 00:00:00 2001 From: MaheshtheDev <38828053+MaheshtheDev@users.noreply.github.com> Date: Tue, 21 Apr 2026 18:02:52 +0000 Subject: [PATCH 12/55] fix: projects endpoint trigger with TTL (#870) --- apps/mcp/src/server.ts | 32 +++++++++++++++++++++++++++----- apps/mcp/tsconfig.json | 4 +++- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/apps/mcp/src/server.ts b/apps/mcp/src/server.ts index d387fde9..682e75c1 100644 --- a/apps/mcp/src/server.ts +++ b/apps/mcp/src/server.ts @@ -24,9 +24,12 @@ type Props = { name?: string } +const CONTAINER_TAGS_TTL_MS = 5 * 60 * 1000 + export class SupermemoryMCP extends McpAgent { private clientInfo: { name: string; version?: string } | null = null private cachedContainerTags: string[] = [] + private containerTagsLastFetchedAt: number | null = null server = new McpServer({ name: "supermemory", @@ -168,8 +171,8 @@ export class SupermemoryMCP extends McpAgent { "supermemory://projects", {}, async () => { - const client = this.getClient() - const projects = await client.getProjects() + await this.ensureContainerTagsFresh() + const projects = this.cachedContainerTags return { contents: [ @@ -193,15 +196,19 @@ export class SupermemoryMCP extends McpAgent { refresh: z .boolean() .optional() - .default(true) - .describe("Refresh the list from the server (default: true)"), + .default(false) + .describe( + "Force refresh from the server (default: false; uses cache with TTL)", + ), }), }, // @ts-expect-error - zod type inference issue with MCP SDK async (args: { refresh?: boolean }) => { try { - if (args.refresh !== false) { + if (args.refresh === true) { await this.refreshContainerTags() + } else { + await this.ensureContainerTagsFresh() } const projects = this.cachedContainerTags @@ -566,6 +573,10 @@ export class SupermemoryMCP extends McpAgent { const result = await client.createMemory(content) + if (!this.cachedContainerTags.includes(result.containerTag)) { + await this.refreshContainerTags() + } + // Track memory added event posthog .memoryAdded({ @@ -758,10 +769,21 @@ export class SupermemoryMCP extends McpAgent { return this.ctx.id.name || "unknown" } + private async ensureContainerTagsFresh(): Promise { + const now = Date.now() + const needsRefresh = + this.containerTagsLastFetchedAt === null || + now - this.containerTagsLastFetchedAt > CONTAINER_TAGS_TTL_MS + if (needsRefresh) { + await this.refreshContainerTags() + } + } + private async refreshContainerTags(): Promise { try { const client = this.getClient() this.cachedContainerTags = await client.getProjects() + this.containerTagsLastFetchedAt = Date.now() } catch (error) { console.error("Failed to fetch container tags:", error) } diff --git a/apps/mcp/tsconfig.json b/apps/mcp/tsconfig.json index 576d1175..67ab2770 100644 --- a/apps/mcp/tsconfig.json +++ b/apps/mcp/tsconfig.json @@ -13,7 +13,9 @@ "resolveJsonModule": true, "outDir": "dist", "rootDir": "src", - "baseUrl": "." + "paths": { + "*": ["./*"] + } }, "include": ["src/**/*"], "exclude": ["node_modules"] From dd652bc6c68ada71e287efcd585367c01486a7cf Mon Sep 17 00:00:00 2001 From: MaheshtheDev <38828053+MaheshtheDev@users.noreply.github.com> Date: Tue, 21 Apr 2026 18:05:13 +0000 Subject: [PATCH 13/55] chore: package update to trigger auto publish (#873) --- packages/tools/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/tools/package.json b/packages/tools/package.json index 3fd3b8e9..209858e9 100644 --- a/packages/tools/package.json +++ b/packages/tools/package.json @@ -2,7 +2,7 @@ "name": "@supermemory/tools", "type": "module", "version": "1.4.5", - "description": "Memory tools for AI SDK and OpenAI function calling with supermemory", + "description": "Memory tools for AI SDK, OpenAI, Voltagent and Mastra with supermemory", "scripts": { "build": "tsdown", "dev": "tsdown --watch --ignore-watch .turbo", From 5e3033d4842cd1ed06d877c230a14e047840d116 Mon Sep 17 00:00:00 2001 From: Dhravya Date: Tue, 21 Apr 2026 20:06:51 +0000 Subject: [PATCH 14/55] create lobbyside (#874) --- apps/web/app/layout.tsx | 6 ++++ .../memory-graph/memory-graph-wrapper.tsx | 10 ++++--- .../src/components/memory-graph.tsx | 20 ++++++++----- .../tools/test/claude-memory-real-example.ts | 28 +++++++++++++------ 4 files changed, 45 insertions(+), 19 deletions(-) diff --git a/apps/web/app/layout.tsx b/apps/web/app/layout.tsx index dfc12a0c..94c238bb 100644 --- a/apps/web/app/layout.tsx +++ b/apps/web/app/layout.tsx @@ -11,6 +11,7 @@ import { Suspense } from "react" import { Toaster } from "@ui/components/sonner" import { NuqsAdapter } from "nuqs/adapters/next/app" import { ThemeProvider } from "@/lib/theme-provider" +import Script from "next/script" const font = Space_Grotesk({ subsets: ["latin"], @@ -69,6 +70,11 @@ export default function RootLayout({ +