* security: bump vite across integrations to patched versions Fixes Dependabot alerts for vite transitive dev dependency: - GHSA-v2wj-q39q-566r (high): server.fs.deny bypass with queries - GHSA-p9ff-h696-f583 (high): related vite server vulnerability Adds a `vite` entry to the npm `overrides` in each integration's package.json to force the patched version (>=8.0.5). To make this possible in ai-sdk, chat, and openclaw — which pinned vitest ^4.0.18 whose vite peer is `^6.0.0 || ^7.0.0` — the minor-compatible bump vitest ^4.0.18 -> ^4.1.2 is also included. vitest 4.1.x supports vite 8.x (peer: ^6 || ^7 || ^8), so all six integrations converge on vite 8.x consistently. paperclip had no overrides block; one was added. Verified locally: `npm ci && npx vitest run` passes in all six integrations (ai-sdk 23, chat 28, openclaw 66, opencode 89, paperclip 27, nemoclaw 36 tests). * chore: regenerate hindsight-docs skill Picks up FAQ and best-practice sections added in #905 that were not regenerated at merge time, so that `verify-generated-files` passes for this branch. |
||
|---|---|---|
| .. | ||
| src | ||
| tests | ||
| package-lock.json | ||
| package.json | ||
| README.md | ||
| tsconfig.json | ||
@vectorize-io/hindsight-paperclip
Persistent memory for Paperclip AI agents using Hindsight.
Paperclip agents start every heartbeat cold — no memory of prior sessions, decisions, or patterns. This package gives them long-term memory that persists across heartbeats and sessions.
How It Works
- Before each heartbeat:
recall()queries Hindsight for context relevant to the current task and injects it into the agent's prompt - After each heartbeat:
retain()stores the agent's output so future heartbeats can reference it
Memory is isolated per company and agent by default (paperclip::{companyId}::{agentId}), matching Paperclip's multi-tenant model.
Installation
npm install @vectorize-io/hindsight-paperclip
Configuration
Set environment variables (or pass as options to loadConfig()):
| Variable | Description | Default |
|---|---|---|
HINDSIGHT_API_URL |
Hindsight server URL | Required |
HINDSIGHT_API_TOKEN |
API token for Hindsight Cloud | — |
Usage
HTTP Adapter Agents (Express middleware)
import express from 'express'
import { createMemoryMiddleware, loadConfig } from '@vectorize-io/hindsight-paperclip'
import type { HindsightRequest } from '@vectorize-io/hindsight-paperclip'
const app = express()
app.use(express.json())
app.use(createMemoryMiddleware(loadConfig()))
app.post('/heartbeat', async (req, res) => {
const { memories, runId } = (req as HindsightRequest).hindsight
const { context } = req.body
const prompt = memories
? `Past context:\n${memories}\n\nCurrent task: ${context.taskDescription}`
: `Task: ${context.taskDescription}`
const output = await runYourAgent(prompt)
res.json({ output }) // middleware auto-retains output
})
The middleware reads agentId, companyId, runId, and context.taskDescription from the Paperclip HTTP adapter request body automatically.
Process Adapter Scripts
import { recall, retain, loadConfig } from '@vectorize-io/hindsight-paperclip'
const config = loadConfig()
const { PAPERCLIP_AGENT_ID, PAPERCLIP_COMPANY_ID, PAPERCLIP_RUN_ID } = process.env
// Recall before executing
const memories = await recall({
agentId: PAPERCLIP_AGENT_ID!,
companyId: PAPERCLIP_COMPANY_ID!,
query: process.env.TASK_DESCRIPTION ?? '',
}, config)
if (memories) {
console.log(`[Memory Context]\n${memories}`)
}
// ... agent does its work ...
// Retain after
await retain({
agentId: PAPERCLIP_AGENT_ID!,
companyId: PAPERCLIP_COMPANY_ID!,
content: agentOutput,
documentId: PAPERCLIP_RUN_ID!,
}, config)
Direct Function Usage
import { recall, retain, loadConfig } from '@vectorize-io/hindsight-paperclip'
const config = loadConfig({
hindsightApiUrl: 'https://api.hindsight.vectorize.io',
hindsightApiToken: process.env.HINDSIGHT_API_TOKEN,
})
const memories = await recall(
{ companyId, agentId, query: `${task.title}\n${task.description}` },
config
)
if (memories) {
systemPrompt = `Past context:\n${memories}\n\n${systemPrompt}`
}
Bank ID Isolation
By default, each company+agent pair gets its own memory bank:
paperclip::{companyId}::{agentId}
You can change the isolation granularity:
// Shared memory across all agents in a company
loadConfig({ bankGranularity: ['company'] })
// → "paperclip::{companyId}"
// Agent's global memory across all companies
loadConfig({ bankGranularity: ['agent'] })
// → "paperclip::{agentId}"
// Custom prefix
loadConfig({ bankIdPrefix: 'myapp' })
// → "myapp::{companyId}::{agentId}"
Configuration Reference
interface PaperclipMemoryConfig {
hindsightApiUrl: string // HINDSIGHT_API_URL — required
hindsightApiToken?: string // HINDSIGHT_API_TOKEN
bankGranularity?: ('company' | 'agent')[] // default: ['company', 'agent']
bankIdPrefix?: string // default: 'paperclip'
recallBudget?: 'low' | 'mid' | 'high' // default: 'mid'
recallMaxTokens?: number // default: 1024
retainContext?: string // default: 'paperclip'
timeoutMs?: number // default: 15000
}
Skill File
An agent-readable skill file is included at src/skills/hindsight.md. Inject it into your agent's system prompt or as a Paperclip skill to give the agent direct access to Hindsight's REST API via curl.
Requirements
- Node.js 20+ (uses native
fetch) - Hindsight server (self-hosted or Hindsight Cloud)