From bfa09d1685dc86fe8bd57ac0e5ffe353b034696c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20Boschi?= Date: Thu, 26 Feb 2026 17:55:36 +0100 Subject: [PATCH] fix: doc build and add chat doc (#444) * fix doc build and add chat doc * fix doc build and add chat doc --- hindsight-docs/docs/sdks/integrations/chat.md | 163 ++++++++++++++++++ hindsight-docs/sidebars.ts | 8 + 2 files changed, 171 insertions(+) create mode 100644 hindsight-docs/docs/sdks/integrations/chat.md diff --git a/hindsight-docs/docs/sdks/integrations/chat.md b/hindsight-docs/docs/sdks/integrations/chat.md new file mode 100644 index 00000000..8b024f52 --- /dev/null +++ b/hindsight-docs/docs/sdks/integrations/chat.md @@ -0,0 +1,163 @@ +--- +sidebar_position: 5 +--- + +# Vercel Chat SDK + +The `@vectorize-io/hindsight-chat` package gives your [Vercel Chat SDK](https://github.com/vercel/chat) bots persistent, per-user memory with a single handler wrapper. Works with Slack, Discord, Teams, Google Chat, GitHub, and Linear. + +## Installation + +```bash +npm install @vectorize-io/hindsight-chat +``` + +## Quick Start + +```typescript +import { Chat } from 'chat'; +import { HindsightClient } from '@vectorize-io/hindsight-client'; +import { withHindsightChat } from '@vectorize-io/hindsight-chat'; +import { streamText } from 'ai'; +import { openai } from '@ai-sdk/openai'; + +const chat = new Chat({ connectors: [/* your connectors */] }); +const hindsight = new HindsightClient({ apiKey: process.env.HINDSIGHT_API_KEY }); + +chat.onNewMention( + withHindsightChat( + { + client: hindsight, + bankId: (msg) => msg.author.userId, // per-user memory + }, + async (thread, message, ctx) => { + await thread.subscribe(); + + const result = await streamText({ + model: openai('gpt-4o'), + system: ctx.memoriesAsSystemPrompt(), + messages: [{ role: 'user', content: message.text }], + }); + + // Stream the response + const chunks: string[] = []; + for await (const chunk of result.textStream) { + chunks.push(chunk); + } + const fullResponse = chunks.join(''); + await thread.post(fullResponse); + + // Store the conversation in memory + await ctx.retain( + `User: ${message.text}\nAssistant: ${fullResponse}` + ); + } + ) +); +``` + +## Configuration + +### `withHindsightChat(options, handler)` + +Returns a standard Chat SDK handler `(thread, message) => Promise`. + +#### Options + +| Option | Type | Default | Description | +|--------|------|---------|-------------| +| `client` | `HindsightClient` | *required* | Hindsight client instance | +| `bankId` | `string \| (msg) => string` | *required* | Memory bank ID or resolver function | +| `recall.enabled` | `boolean` | `true` | Auto-recall memories before handler | +| `recall.budget` | `'low' \| 'mid' \| 'high'` | `'mid'` | Processing budget for recall | +| `recall.maxTokens` | `number` | API default | Max tokens for recall results | +| `recall.types` | `FactType[]` | all | Filter to specific fact types | +| `recall.includeEntities` | `boolean` | `true` | Include entity observations | +| `retain.enabled` | `boolean` | `false` | Auto-retain inbound messages | +| `retain.async` | `boolean` | `true` | Fire-and-forget retain | +| `retain.tags` | `string[]` | – | Tags for retained memories | +| `retain.metadata` | `Record` | – | Metadata for retained memories | + +### Context (`ctx`) + +The third argument passed to your handler: + +| Property/Method | Description | +|----------------|-------------| +| `ctx.bankId` | Resolved bank ID | +| `ctx.memories` | Array of recalled memories | +| `ctx.entities` | Entity observations (or null) | +| `ctx.memoriesAsSystemPrompt(options?)` | Format memories for LLM system prompt | +| `ctx.retain(content, options?)` | Store content in memory | +| `ctx.recall(query, options?)` | Search memories | +| `ctx.reflect(query, options?)` | Reason over memories | + +## Examples + +### Subscribed Message Handler + +```typescript +chat.onSubscribedMessage( + withHindsightChat( + { + client: hindsight, + bankId: (msg) => msg.author.userId, + recall: { budget: 'high', maxTokens: 1000 }, + }, + async (thread, message, ctx) => { + const result = await generateText({ + model: openai('gpt-4o'), + system: ctx.memoriesAsSystemPrompt(), + messages: [{ role: 'user', content: message.text }], + }); + await thread.post(result.text); + } + ) +); +``` + +### Auto-Retain Inbound Messages + +```typescript +chat.onNewMention( + withHindsightChat( + { + client: hindsight, + bankId: (msg) => msg.author.userId, + retain: { enabled: true, tags: ['slack', 'inbound'] }, + }, + async (thread, message, ctx) => { + // Inbound message is already being retained automatically + const result = await generateText({ + model: openai('gpt-4o'), + system: ctx.memoriesAsSystemPrompt(), + messages: [{ role: 'user', content: message.text }], + }); + await thread.post(result.text); + + // Retain the assistant response separately + await ctx.retain(`Assistant: ${result.text}`, { + tags: ['slack', 'outbound'], + }); + } + ) +); +``` + +### Static Bank ID (Shared Memory) + +```typescript +// All users share the same memory bank +chat.onNewMention( + withHindsightChat( + { client: hindsight, bankId: 'shared-team-memory' }, + async (thread, message, ctx) => { + // ... + } + ) +); +``` + +## Error Handling + +Memory failures never break your bot. Auto-recall and auto-retain errors are logged as warnings and the handler continues with empty memories. Manual `ctx.retain()`, `ctx.recall()`, and `ctx.reflect()` calls propagate errors normally so you can handle them as needed. diff --git a/hindsight-docs/sidebars.ts b/hindsight-docs/sidebars.ts index 03b99b7b..b0b16fba 100644 --- a/hindsight-docs/sidebars.ts +++ b/hindsight-docs/sidebars.ts @@ -210,6 +210,14 @@ const sidebars: SidebarsConfig = { id: 'sdks/integrations/ai-sdk', label: 'Vercel AI SDK', }, + { + type: 'doc', + id: 'sdks/integrations/chat', + label: 'Vercel Chat SDK', + customProps: { + icon: "/img/icons/vercel.png" + } + }, { type: 'doc', id: 'sdks/integrations/crewai',