Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 19 additions & 34 deletions apps/web/components/model-selector.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,41 +55,26 @@ export function ModelSelector({
disabled={disabled}
>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
fill="none"
viewBox="0 0 24 24"
>
<title>Model Selector</title>
<g clip-path="url(#clip0_4418_9868)">
<path
d="M12.92 2.25984L19.43 5.76984C20.19 6.17984 20.19 7.34984 19.43 7.75984L12.92 11.2698C12.34 11.5798 11.66 11.5798 11.08 11.2698L4.57 7.75984C3.81 7.34984 3.81 6.17984 4.57 5.76984L11.08 2.25984C11.66 1.94984 12.34 1.94984 12.92 2.25984Z"
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M3.61 10.1297L9.66 13.1597C10.41 13.5397 10.89 14.3097 10.89 15.1497V20.8697C10.89 21.6997 10.02 22.2297 9.28 21.8597L3.23 18.8297C2.48 18.4497 2 17.6797 2 16.8397V11.1197C2 10.2897 2.87 9.75968 3.61 10.1297Z"
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
/>
<path
d="M20.39 10.1297L14.34 13.1597C13.59 13.5397 13.11 14.3097 13.11 15.1497V20.8697C13.11 21.6997 13.98 22.2297 14.72 21.8597L20.77 18.8297C21.52 18.4497 22 17.6797 22 16.8397V11.1197C22 10.2897 21.13 9.75968 20.39 10.1297Z"
stroke="currentColor"
stroke-width="1.5"
stroke-linecap="round"
stroke-linejoin="round"
/>
</g>
<defs>
<clipPath id="clip0_4418_9868">
<rect width="24" height="24" fill="white" />
</clipPath>
</defs>
<g
stroke="currentColor"
strokeLinecap="round"
strokeLinejoin="round"
strokeWidth="1.5"
clipPath="url(#clip0_4418_9868)"
>
<path d="m12.92 2.26 6.51 3.51c.76.41.76 1.58 0 1.99l-6.51 3.51c-.58.31-1.26.31-1.84 0L4.57 7.76c-.76-.41-.76-1.58 0-1.99l6.51-3.51c.58-.31 1.26-.31 1.84 0M3.61 10.13l6.05 3.03c.75.38 1.23 1.15 1.23 1.99v5.72c0 .83-.87 1.36-1.61.99l-6.05-3.03A2.24 2.24 0 0 1 2 16.84v-5.72c0-.83.87-1.36 1.61-.99M20.39 10.13l-6.05 3.03c-.75.38-1.23 1.15-1.23 1.99v5.72c0 .83.87 1.36 1.61.99l6.05-3.03c.75-.38 1.23-1.15 1.23-1.99v-5.72c0-.83-.87-1.36-1.61-.99"></path>
</g>
<defs>
<clipPath id="clip0_4418_9868">
<path fill="#fff" d="M0 0h24v24H0z"></path>
</clipPath>
</defs>
</svg>
<span className="text-xs font-medium max-w-32 truncate">
{currentModel.name}
Expand Down
1 change: 1 addition & 0 deletions apps/web/components/views/add-memory/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,7 @@ export function AddMemoryView({
}}
open={showAddDialog}
>
<DialogTitle className="sr-only">Memory Dialog</DialogTitle>
<DialogContent
className="w-[100vw] max-w-4xl sm:max-w-4xl backdrop-blur-xl border-white/10 z-[80] h-[52vh] overflow-y-auto p-4"
showCloseButton={false}
Expand Down
49 changes: 28 additions & 21 deletions apps/web/lib/analytics.ts
Original file line number Diff line number Diff line change
@@ -1,43 +1,50 @@
import posthog from "posthog-js"

// Helper function to safely capture events
const safeCapture = (eventName: string, properties?: Record<string, any>) => {
if (posthog.__loaded) {
posthog.capture(eventName, properties)
}
}

export const analytics = {
userSignedOut: () => posthog.capture("user_signed_out"),
userSignedOut: () => safeCapture("user_signed_out"),

memoryAdded: (props: {
type: "note" | "link" | "file"
project_id?: string
content_length?: number
file_size?: number
file_type?: string
}) => posthog.capture("memory_added", props),
}) => safeCapture("memory_added", props),

memoryDetailOpened: () => posthog.capture("memory_detail_opened"),
memoryDetailOpened: () => safeCapture("memory_detail_opened"),

projectCreated: () => posthog.capture("project_created"),
projectCreated: () => safeCapture("project_created"),

newChatStarted: () => posthog.capture("new_chat_started"),
chatHistoryViewed: () => posthog.capture("chat_history_viewed"),
chatDeleted: () => posthog.capture("chat_deleted"),
newChatStarted: () => safeCapture("new_chat_started"),
chatHistoryViewed: () => safeCapture("chat_history_viewed"),
chatDeleted: () => safeCapture("chat_deleted"),

viewModeChanged: (mode: "graph" | "list") =>
posthog.capture("view_mode_changed", { mode }),
safeCapture("view_mode_changed", { mode }),

documentCardClicked: () => posthog.capture("document_card_clicked"),
documentCardClicked: () => safeCapture("document_card_clicked"),

billingViewed: () => posthog.capture("billing_viewed"),
upgradeInitiated: () => posthog.capture("upgrade_initiated"),
upgradeCompleted: () => posthog.capture("upgrade_completed"),
billingPortalOpened: () => posthog.capture("billing_portal_opened"),
billingViewed: () => safeCapture("billing_viewed"),
upgradeInitiated: () => safeCapture("upgrade_initiated"),
upgradeCompleted: () => safeCapture("upgrade_completed"),
billingPortalOpened: () => safeCapture("billing_portal_opened"),

connectionAdded: (provider: string) =>
posthog.capture("connection_added", { provider }),
connectionDeleted: () => posthog.capture("connection_deleted"),
connectionAuthStarted: () => posthog.capture("connection_auth_started"),
connectionAuthCompleted: () => posthog.capture("connection_auth_completed"),
connectionAuthFailed: () => posthog.capture("connection_auth_failed"),
safeCapture("connection_added", { provider }),
connectionDeleted: () => safeCapture("connection_deleted"),
connectionAuthStarted: () => safeCapture("connection_auth_started"),
connectionAuthCompleted: () => safeCapture("connection_auth_completed"),
connectionAuthFailed: () => safeCapture("connection_auth_failed"),

mcpViewOpened: () => posthog.capture("mcp_view_opened"),
mcpInstallCmdCopied: () => posthog.capture("mcp_install_cmd_copied"),
mcpViewOpened: () => safeCapture("mcp_view_opened"),
mcpInstallCmdCopied: () => safeCapture("mcp_install_cmd_copied"),

extensionInstallClicked: () => posthog.capture("extension_install_clicked"),
extensionInstallClicked: () => safeCapture("extension_install_clicked"),
}
17 changes: 9 additions & 8 deletions packages/lib/auth-context.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,14 +39,15 @@ export function AuthProvider({ children }: { children: ReactNode }) {
useEffect(() => {
if (session?.session.activeOrganizationId) {
authClient.organization.getFullOrganization().then((org) => {
if (org.metadata?.isConsumer === true) {
setOrg(org)
} else {
const consumerOrg = orgs?.find((o) => o.metadata?.isConsumer === true)
if (consumerOrg) {
setActiveOrg(consumerOrg.slug)
}
}
// TODO: Uncomment this when we have a way to handle consumer organizations better way
//if (org.metadata?.isConsumer === true) {
setOrg(org)
//} else {
// const consumerOrg = orgs?.find((o) => o.metadata?.isConsumer === true)
// if (consumerOrg) {
// setActiveOrg(consumerOrg.slug)
// }
//}
})
}
}, [session?.session.activeOrganizationId, orgs])
Expand Down
3 changes: 3 additions & 0 deletions packages/lib/error-tracking.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export function useErrorTracking() {
error: Error | unknown,
context?: Record<string, any>,
) => {
if (!posthog.__loaded) return
const errorDetails = {
error_message: error instanceof Error ? error.message : String(error),
error_stack: error instanceof Error ? error.stack : undefined,
Expand Down Expand Up @@ -117,6 +118,7 @@ export function useInteractionTracking() {
const pathname = usePathname()

const trackInteraction = (action: string, details?: Record<string, any>) => {
if (!posthog.__loaded) return
posthog.capture("user_interaction", {
action,
pathname,
Expand All @@ -131,6 +133,7 @@ export function useInteractionTracking() {
success: boolean,
details?: Record<string, any>,
) => {
if (!posthog.__loaded) return
posthog.capture("form_submission", {
form_name: formName,
success,
Expand Down
13 changes: 9 additions & 4 deletions packages/lib/posthog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ function PostHogPageTracking() {

// Page tracking
useEffect(() => {
if (pathname) {
if (pathname && posthog.__loaded) {
let url = window.origin + pathname
if (searchParams.toString()) {
url = `${url}?${searchParams.toString()}`
Expand All @@ -38,19 +38,24 @@ export function PostHogProvider({ children }: { children: React.ReactNode }) {

useEffect(() => {
if (typeof window !== "undefined") {
posthog.init(process.env.NEXT_PUBLIC_POSTHOG_KEY ?? "", {
const posthogKey = process.env.NEXT_PUBLIC_POSTHOG_KEY
if (posthogKey){
posthog.init(posthogKey, {
api_host: process.env.NEXT_PUBLIC_BACKEND_URL + "/orange",
ui_host: "https://us.i.posthog.com",
person_profiles: "identified_only",
capture_pageview: false,
capture_pageleave: true,
})
})}
else{
console.warn("PostHog API key is not set. PostHog will not be initialized.")
}
}
}, [])

// User identification
useEffect(() => {
if (session?.user) {
if (session?.user && posthog.__loaded) {
posthog.identify(session.user.id, {
email: session.user.email,
name: session.user.name,
Expand Down
103 changes: 101 additions & 2 deletions packages/tools/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,8 @@ yarn add @supermemory/tools
## Usage

The package provides two submodule imports:
- `@supermemory/tools/ai-sdk` - For use with the AI SDK framework
- `@supermemory/tools/openai` - For use with OpenAI's function calling
- `@supermemory/tools/ai-sdk` - For use with the AI SDK framework (includes `withSupermemory` middleware)
- `@supermemory/tools/openai` - For use with OpenAI SDK (includes `withSupermemory` middleware and function calling tools)

### AI SDK Usage

Expand Down Expand Up @@ -223,6 +223,105 @@ const modelWithOptions = withSupermemory(openai("gpt-4"), "user-123", {
})
```

### OpenAI SDK Usage

#### OpenAI Middleware with Supermemory

The `withSupermemory` function creates an OpenAI client with SuperMemory middleware automatically injected:

```typescript
import { withSupermemory } from "@supermemory/tools/openai"

// Create OpenAI client with supermemory middleware
const openaiWithSupermemory = withSupermemory("user-123", {
conversationId: "conversation-456",
mode: "full",
addMemory: "always",
verbose: true,
})

// Use directly with chat completions - memories are automatically injected
const completion = await openaiWithSupermemory.chat.completions.create({
model: "gpt-4o-mini",
messages: [
{ role: "user", content: "What do you remember about my preferences?" }
],
})

console.log(completion.choices[0]?.message?.content)
```

#### OpenAI Middleware Options

The middleware supports the same configuration options as the AI SDK version:

```typescript
const openaiWithSupermemory = withSupermemory("user-123", {
conversationId: "conversation-456", // Group messages for contextual memory
mode: "full", // "profile" | "query" | "full"
addMemory: "always", // "always" | "never"
verbose: true, // Enable detailed logging
})
```

#### Advanced Usage with Custom OpenAI Options

You can also pass custom OpenAI client options:

```typescript
import { withSupermemory } from "@supermemory/tools/openai"

const openaiWithSupermemory = withSupermemory(
"user-123",
{
mode: "profile",
addMemory: "always",
},
{
baseURL: "https://api.openai.com/v1",
organization: "org-123",
},
"custom-api-key" // Optional: custom API key
)

const completion = await openaiWithSupermemory.chat.completions.create({
model: "gpt-4o-mini",
messages: [{ role: "user", content: "Tell me about my preferences" }],
})
```

#### Next.js API Route Example

Here's a complete example for a Next.js API route:

```typescript
// app/api/chat/route.ts
import { withSupermemory } from "@supermemory/tools/openai"
import type { OpenAI as OpenAIType } from "openai"

export async function POST(req: Request) {
const { messages, conversationId } = (await req.json()) as {
messages: OpenAIType.Chat.Completions.ChatCompletionMessageParam[]
conversationId: string
}

const openaiWithSupermemory = withSupermemory("user-123", {
conversationId,
mode: "full",
addMemory: "always",
verbose: true,
})

const completion = await openaiWithSupermemory.chat.completions.create({
model: "gpt-4o-mini",
messages,
})

const message = completion.choices?.[0]?.message
return Response.json({ message, usage: completion.usage })
}
```

### OpenAI Function Calling Usage

```typescript
Expand Down
4 changes: 2 additions & 2 deletions packages/tools/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@supermemory/tools",
"type": "module",
"version": "1.2.16",
"version": "1.3.0",
"description": "Memory tools for AI SDK and OpenAI function calling with supermemory",
"scripts": {
"build": "tsdown",
Expand Down Expand Up @@ -38,7 +38,7 @@
".": "./dist/index.js",
"./ai-sdk": "./dist/ai-sdk.js",
"./claude-memory": "./dist/claude-memory.js",
"./openai": "./dist/openai.js",
"./openai": "./dist/openai/index.js",
"./package.json": "./package.json"
},
"repository": {
Expand Down
3 changes: 2 additions & 1 deletion packages/tools/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
// Export shared types and utilities
export type { SupermemoryToolsConfig } from "./types"

export type { OpenAIMiddlewareOptions } from "./openai"
Loading
Loading