* feat(paperclip): add hindsight-paperclip TypeScript integration
Adds long-term memory for Paperclip AI agents via a lightweight
TypeScript/Node.js npm package with no runtime dependencies.
- recall() / retain() functions for heartbeat lifecycle hooks
- createMemoryMiddleware() for Express HTTP adapter agents
- Bank ID strategy: paperclip::{companyId}::{agentId} (configurable)
- Skill file for agents to call Hindsight REST API directly
- 27 unit tests covering bank derivation, recall, and retain
- Docs page at sdks/integrations/paperclip
* Remove skills file from paperclip integration
* Rename package to @vectorize-io/hindsight-paperclip
153 lines
4.5 KiB
Markdown
153 lines
4.5 KiB
Markdown
# @vectorize-io/hindsight-paperclip
|
|
|
|
Persistent memory for [Paperclip AI](https://github.com/paperclipai/paperclip) agents using [Hindsight](https://hindsight.vectorize.io).
|
|
|
|
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
|
|
|
|
1. **Before each heartbeat**: `recall()` queries Hindsight for context relevant to the current task and injects it into the agent's prompt
|
|
2. **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
|
|
|
|
```bash
|
|
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)
|
|
|
|
```typescript
|
|
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
|
|
|
|
```typescript
|
|
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
|
|
|
|
```typescript
|
|
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:
|
|
|
|
```typescript
|
|
// 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
|
|
|
|
```typescript
|
|
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](https://hindsight.vectorize.io))
|