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
4 changes: 2 additions & 2 deletions apps/docs/changelog/developer-platform.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ API updates, new endpoints, SDK releases, and developer-focused features.

- **`extends` Relation Type:** Memory graph now supports `extends` as a relation type, enabling richer knowledge graph connections between documents.
- **Interactive Memory Graph in MCP:** The MCP server now includes an interactive graph visualization app for exploring memory connections from any MCP-compatible client.
- **Plugin Auth Connect Page:** New OAuth-style connect page for plugin integrations (Claude Code, OpenCode, ClawdBot).
- **Plugin Auth Connect Page:** New OAuth-style connect page for plugin integrations (Claude Code, OpenCode, OpenClaw).
- **ViaSocket Integration:** New integration guide for connecting Supermemory with ViaSocket automation workflows.

## March 2, 2026
Expand Down Expand Up @@ -77,7 +77,7 @@ API updates, new endpoints, SDK releases, and developer-focused features.

- **Plugin Authentication System:** New auth system for external tool integrations, enabling secure plugin-to-API connections.
- **Enterprise Plan Support:** Enterprise tier now available in the console with dedicated billing and support options.
- **Plugin Catalog:** Dedicated plugin page with auth flows for Claude Code, OpenCode, and ClawdBot integrations.
- **Plugin Catalog:** Dedicated plugin page with auth flows for Claude Code, OpenCode, and OpenClaw integrations.
- **`@supermemory/tools` — Strict Mode:** Strict mode support for OpenAI function calling, ensuring schema-validated tool calls.

## January 14, 2026
Expand Down
4 changes: 2 additions & 2 deletions apps/docs/changelog/overview.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ The MCP server now includes an interactive graph visualization app for exploring
### More Integrations

- **ViaSocket** — new integration guide for automation workflows.
- **Plugin Auth Connect Page** — OAuth-style connect page for Claude Code, OpenCode, and ClawdBot.
- **Plugin Auth Connect Page** — OAuth-style connect page for Claude Code, OpenCode, and OpenClaw.
- **OpenAI SDK Backfill** — improved compatibility across TypeScript and Python SDKs.

### Other
Expand Down Expand Up @@ -149,7 +149,7 @@ New docs on entity extraction, context enrichment, and comprehensive authenticat

### Plugin Authentication System

New auth system for external tool integrations, enabling secure plugin-to-API connections. Dedicated plugin page with auth flows for Claude Code, OpenCode, and ClawdBot.
New auth system for external tool integrations, enabling secure plugin-to-API connections. Dedicated plugin page with auth flows for Claude Code, OpenCode, and OpenClaw.

### Enterprise Plan Support

Expand Down
6 changes: 3 additions & 3 deletions apps/web/app/auth/connect/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -56,16 +56,16 @@ const PLUGIN_INFO: Record<string, PluginInfo> = {
],
icon: "/images/plugins/opencode.svg",
},
clawdbot: {
name: "ClawdBot",
openclaw: {
name: "OpenClaw",
description:
"Multi-platform memory for OpenClaw. Works across Telegram, WhatsApp, Discord, Slack and more.",
features: [
"Cross-channel memory persistence",
"Automatic conversation capture",
"User profile building across platforms",
],
icon: "/images/plugins/clawdbot.svg",
icon: "/images/plugins/openclaw.svg",
},
cursor: {
name: "Cursor",
Expand Down
125 changes: 3 additions & 122 deletions apps/web/components/chat/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -119,12 +119,6 @@ export function ChatSidebar({
Record<string, "like" | "dislike" | null>
>({})
const [expandedMemories, setExpandedMemories] = useState<string | null>(null)
const [followUpQuestions, setFollowUpQuestions] = useState<
Record<string, string[]>
>({})
const [loadingFollowUps, setLoadingFollowUps] = useState<
Record<string, boolean>
>({})
const [isInputExpanded, setIsInputExpanded] = useState(false)
const [isScrolledToBottom, setIsScrolledToBottom] = useState(true)
const [heightOffset, setHeightOffset] = useState(95)
Expand All @@ -136,25 +130,24 @@ export function ChatSidebar({
const [confirmingDeleteId, setConfirmingDeleteId] = useState<string | null>(
null,
)
const pendingFollowUpGenerations = useRef<Set<string>>(new Set())
const messagesContainerRef = useRef<HTMLDivElement>(null)
const sentQueuedMessageRef = useRef<string | null>(null)
const { selectedProject } = useProject()
const { viewMode } = useViewMode()
const { user } = useAuth()
const { user: _user } = useAuth()
const [threadId, setThreadId] = useQueryState("thread", threadParam)
const [fallbackChatId, setFallbackChatId] = useState(() => generateId())
const currentChatId = threadId ?? fallbackChatId
const chatIdRef = useRef(currentChatId)
chatIdRef.current = currentChatId
const setCurrentChatId = useCallback(
const _setCurrentChatId = useCallback(
(id: string) => setThreadId(id),
[setThreadId],
)
const chatTransport = useMemo(
() =>
new DefaultChatTransport({
api: `${process.env.NEXT_PUBLIC_BACKEND_URL ?? "https://api.supermemory.ai"}/chat/v2`,
api: `${process.env.NEXT_PUBLIC_BACKEND_URL ?? "https://api.supermemory.ai"}/chat`,
credentials: "include",
prepareSendMessagesRequest: ({ messages }) => ({
body: {
Expand Down Expand Up @@ -196,15 +189,6 @@ export function ChatSidebar({
const { messages, sendMessage, status, setMessages, stop } = useChat({
id: currentChatId ?? undefined,
transport: chatTransport,
onFinish: async (result) => {
if (result.message.role !== "assistant") return

// Mark this message as needing follow-up generation
// We'll generate it after the message is fully in the messages array
if (result.message.id) {
pendingFollowUpGenerations.current.add(result.message.id)
}
},
})

useEffect(() => {
Expand All @@ -214,100 +198,6 @@ export function ChatSidebar({
}
}, [currentChatId, pendingThreadLoad, setMessages])

// Generate follow-up questions after assistant messages are complete
useEffect(() => {
const generateFollowUps = async () => {
// Find assistant messages that need follow-up generation
const messagesToProcess = messages.filter(
(msg) =>
msg.role === "assistant" &&
pendingFollowUpGenerations.current.has(msg.id) &&
!followUpQuestions[msg.id] &&
!loadingFollowUps[msg.id],
)

for (const message of messagesToProcess) {
// Get complete text from the message
const assistantText = message.parts
.filter((p) => p.type === "text")
.map((p) => p.text)
.join(" ")
.trim()

// Only generate if we have substantial text (at least 50 chars)
// This ensures the message is complete, not just the first chunk
// Also check if status is idle to ensure streaming is complete
if (
assistantText.length < 50 ||
status === "streaming" ||
status === "submitted"
) {
continue
}

// Mark as processing
pendingFollowUpGenerations.current.delete(message.id)
setLoadingFollowUps((prev) => ({
...prev,
[message.id]: true,
}))

try {
// Get recent messages for context
const recentMessages = messages.slice(-5).map((msg) => ({
role: msg.role,
content: msg.parts
.filter((p) => p.type === "text")
.map((p) => p.text)
.join(" "),
}))

const response = await fetch(
`${process.env.NEXT_PUBLIC_BACKEND_URL}/chat/follow-ups`,
{
method: "POST",
headers: {
"Content-Type": "application/json",
},
credentials: "include",
body: JSON.stringify({
messages: recentMessages,
assistantResponse: assistantText,
}),
},
)

if (response.ok) {
const data = await response.json()
if (data.questions && Array.isArray(data.questions)) {
setFollowUpQuestions((prev) => ({
...prev,
[message.id]: data.questions,
}))
}
}
} catch (error) {
console.error("Failed to generate follow-up questions:", error)
} finally {
setLoadingFollowUps((prev) => ({
...prev,
[message.id]: false,
}))
}
}
}

// Only generate if not currently streaming or submitted
// Small delay to ensure message is fully processed
if (status !== "streaming" && status !== "submitted") {
const timeoutId = setTimeout(() => {
generateFollowUps()
}, 300)

return () => clearTimeout(timeoutId)
}
}, [messages, followUpQuestions, loadingFollowUps, status])

const checkIfScrolledToBottom = useCallback(() => {
if (!messagesContainerRef.current) return
const container = messagesContainerRef.current
Expand Down Expand Up @@ -879,19 +769,10 @@ export function ChatSidebar({
copiedMessageId={copiedMessageId}
messageFeedback={messageFeedback}
expandedMemories={expandedMemories}
followUpQuestions={followUpQuestions[message.id] || []}
isLoadingFollowUps={loadingFollowUps[message.id] || false}
onCopy={handleCopyMessage}
onLike={handleLikeMessage}
onDislike={handleDislikeMessage}
onToggleMemories={handleToggleMemories}
onQuestionClick={(question) => {
analytics.chatFollowUpClicked({
thread_id: currentChatId || undefined,
})
analytics.chatMessageSent({ source: "follow_up" })
setInput(question)
}}
/>
)}
</div>
Expand Down
Loading
Loading