Compare commits

...
Author SHA1 Message Date
Nicolò Boschi 1d7198c0ff ci: rename moltbot to openclawd in workflows and release script
- Updated build-moltbot-integration → build-openclawd-integration in test.yml
- Updated release-moltbot-integration → release-openclawd-integration in release.yml
- Updated all working directories from moltbot to openclawd
- Updated artifact names from moltbot-integration to openclawd-integration
- Added openclawd package.json to release.sh version bump script
2026-01-30 10:24:57 +01:00
Nicolò Boschi 0c07b55130 fix: use single shared pg0 database for all banks + add default mission
This commit fixes a critical database isolation issue and adds the default
mission feature for the openclawd plugin.

## Changes:

**hindsight-embed:**
- Fixed daemon_client.py to use single shared database: pg0://hindsight-embed
- Previously, each bank_id would create a separate pg0 instance (wrong!)
- Now all banks share the same database with isolation via bank_id parameter
- Updated README to clarify database architecture

**openclawd plugin (v0.0.5):**
- Added default bank mission describing OpenClawd's multi-channel assistant role
- Added setBankMission() method to client
- Integrated mission setting during plugin initialization
- Added bankMission to plugin config schema with sensible default
- Updated docs to explain shared database architecture

## Why this matters:
Bank isolation should happen WITHIN the database (via separate tables/schemas),
not via separate database instances. Using HINDSIGHT_EMBED_BANK_ID to create
separate pg0 databases was architecturally wrong and caused confusion.
2026-01-30 10:10:58 +01:00
Nicolò Boschi dbd41c9ca2 fix 2026-01-30 09:56:28 +01:00
Nicolò Boschi af55171fba fix 2026-01-30 09:56:12 +01:00
Nicolò Boschi a30dad2c03 fix: rename moltbot to openclawd 2026-01-30 09:22:08 +01:00
30 changed files with 316 additions and 444 deletions
+13 -13
View File
@@ -139,7 +139,7 @@ jobs:
path: hindsight-clients/typescript/*.tgz
retention-days: 1
release-moltbot-integration:
release-openclawd-integration:
runs-on: ubuntu-latest
environment: npm
@@ -153,15 +153,15 @@ jobs:
registry-url: 'https://registry.npmjs.org'
- name: Install dependencies
working-directory: ./hindsight-integrations/moltbot
working-directory: ./hindsight-integrations/openclawd
run: npm ci
- name: Build
working-directory: ./hindsight-integrations/moltbot
working-directory: ./hindsight-integrations/openclawd
run: npm run build
- name: Publish to npm
working-directory: ./hindsight-integrations/moltbot
working-directory: ./hindsight-integrations/openclawd
run: |
set +e
OUTPUT=$(npm publish --access public 2>&1)
@@ -178,14 +178,14 @@ jobs:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Pack for GitHub release
working-directory: ./hindsight-integrations/moltbot
working-directory: ./hindsight-integrations/openclawd
run: npm pack
- name: Upload artifacts
uses: actions/upload-artifact@v4
with:
name: moltbot-integration
path: hindsight-integrations/moltbot/*.tgz
name: openclawd-integration
path: hindsight-integrations/openclawd/*.tgz
retention-days: 1
release-control-plane:
@@ -415,7 +415,7 @@ jobs:
create-github-release:
runs-on: ubuntu-latest
needs: [release-python-packages, release-typescript-client, release-moltbot-integration, release-control-plane, release-rust-cli, release-docker-images, release-helm-chart]
needs: [release-python-packages, release-typescript-client, release-openclawd-integration, release-control-plane, release-rust-cli, release-docker-images, release-helm-chart]
permissions:
contents: write
@@ -438,11 +438,11 @@ jobs:
name: typescript-client
path: ./artifacts/typescript-client
- name: Download Moltbot Integration
- name: Download OpenClawd Integration
uses: actions/download-artifact@v4
with:
name: moltbot-integration
path: ./artifacts/moltbot-integration
name: openclawd-integration
path: ./artifacts/openclawd-integration
- name: Download Control Plane
uses: actions/download-artifact@v4
@@ -485,8 +485,8 @@ jobs:
cp artifacts/python-packages/hindsight-embed/dist/* release-assets/ || true
# TypeScript client
cp artifacts/typescript-client/*.tgz release-assets/ || true
# Moltbot Integration
cp artifacts/moltbot-integration/*.tgz release-assets/ || true
# OpenClawd Integration
cp artifacts/openclawd-integration/*.tgz release-assets/ || true
# Control Plane
cp artifacts/control-plane/*.tgz release-assets/ || true
# Rust CLI binaries
+4 -4
View File
@@ -82,7 +82,7 @@ jobs:
- name: Build TypeScript client
run: npm run build --workspace=hindsight-clients/typescript
build-moltbot-integration:
build-openclawd-integration:
runs-on: ubuntu-latest
steps:
@@ -94,15 +94,15 @@ jobs:
node-version: '22'
- name: Install dependencies
working-directory: ./hindsight-integrations/moltbot
working-directory: ./hindsight-integrations/openclawd
run: npm ci
- name: Run tests
working-directory: ./hindsight-integrations/moltbot
working-directory: ./hindsight-integrations/openclawd
run: npm test
- name: Build
working-directory: ./hindsight-integrations/moltbot
working-directory: ./hindsight-integrations/openclawd
run: npm run build
build-control-plane:
@@ -28,7 +28,7 @@ export async function GET(request: NextRequest) {
console.error("Graph API error:", response.error);
return NextResponse.json(
{ error: response.error || "Failed to fetch graph data" },
{ status: 500 },
{ status: 500 }
);
}
@@ -33,10 +33,8 @@ export const hindsightClient = new HindsightClient({
export const lowLevelClient = createClient(
createConfig({
baseUrl: DATAPLANE_URL,
headers: DATAPLANE_API_KEY
? { Authorization: `Bearer ${DATAPLANE_API_KEY}` }
: undefined,
}),
headers: DATAPLANE_API_KEY ? { Authorization: `Bearer ${DATAPLANE_API_KEY}` } : undefined,
})
);
/**
@@ -2,24 +2,23 @@
sidebar_position: 4
---
# Moltbot (Clawdbot)
# OpenClawd
Biomimetic long-term memory for [Moltbot](https://molt.bot) using [Hindsight](https://vectorize.io/hindsight). Automatically captures conversations and intelligently recalls relevant context.
Biomimetic long-term memory for [OpenClawd](https://openclawd.ai) using [Hindsight](https://vectorize.io/hindsight).
This plugin integrates [hindsight-embed](https://vectorize.io/hindsight/cli), a standalone daemon that bundles Hindsight's memory engine (API + PostgreSQL) into a single command. The plugin automatically manages the daemon lifecycle and provides hooks for seamless memory capture and recall.
## Quick Start
```bash
# 1. Install the plugin
npm install -g @vectorize-io/hindsight-moltbot-plugin
# 2. Configure your LLM provider
# 1. Configure your LLM provider
export OPENAI_API_KEY="sk-your-key"
clawdbot config set 'agents.defaults.models."openai/gpt-4o-mini"' '{}'
# 3. Enable the plugin
clawdbot plugins enable hindsight-memory
# 2. Install and enable the plugin
clawdbot plugins install @vectorize-io/hindsight-openclawd
# 4. Start Moltbot
# 3. Start OpenClawd
clawdbot gateway
```
@@ -39,10 +38,10 @@ Before each agent response, relevant memories are **automatically injected**:
- Injected into context with `<hindsight-context>` tags
- Agent seamlessly uses past context
## Understanding Moltbot Concepts
## Understanding OpenClawd Concepts
### Plugins
Extensions that add functionality to Moltbot. This Hindsight plugin:
Extensions that add functionality to OpenClawd. This Hindsight plugin:
- Runs a background service (manages `hindsight-embed` daemon)
- Registers hooks (automatic event handlers)
@@ -57,7 +56,7 @@ Think of hooks as "forced automation" - they always run.
```
┌─────────────────────────────────────────┐
Moltbot Gateway │
OpenClawd Gateway │
│ │
│ ┌───────────────────────────────────┐ │
│ │ Hindsight Plugin │ │
@@ -72,33 +71,33 @@ Think of hooks as "forced automation" - they always run.
uvx hindsight-embed
• Daemon on port 8889
• PostgreSQL (pg0)
• PostgreSQL (pg0://hindsight-embed)
• Bank: 'openclawd' (isolated within shared database)
• Fact extraction
```
**Database Architecture:** All banks share a single pg0 database instance (`pg0://hindsight-embed`). Bank isolation happens within the database via separate tables/schemas per bank ID. The 'openclawd' bank is automatically created when the plugin stores its first memory.
## Installation
### Prerequisites
- **Node.js** 22+
- **Moltbot** (Clawdbot) with plugin support
- **OpenClawd** (Clawdbot) with plugin support
- **uv/uvx** for running `hindsight-embed`
- **LLM API key** (OpenAI, Anthropic, etc.)
### Setup
```bash
# 1. Install the plugin
npm install -g @vectorize-io/hindsight-moltbot-plugin
# 2. Configure your LLM provider
# 1. Configure your LLM provider
export OPENAI_API_KEY="sk-your-key"
clawdbot config set 'agents.defaults.models."openai/gpt-4o-mini"' '{}'
# 3. Enable the plugin
clawdbot plugins enable hindsight-memory
# 2. Install and enable the plugin
clawdbot plugins install @vectorize-io/hindsight-openclawd
# 4. Start Moltbot
# 3. Start OpenClawd
clawdbot gateway
```
@@ -113,7 +112,7 @@ Optional settings in `~/.clawdbot/clawdbot.json`:
{
"plugins": {
"entries": {
"hindsight-memory": {
"hindsight-openclawd": {
"enabled": true,
"config": {
"daemonIdleTimeout": 0
@@ -128,6 +127,7 @@ Optional settings in `~/.clawdbot/clawdbot.json`:
- `daemonIdleTimeout` (number, default: `0`) - Seconds before daemon shuts down from inactivity (0 = never)
- `embedPort` (number, default: auto) - Port for embedded server
- `bankMission` (string, default: none) - Custom context for the memory bank
- `embedVersion` (string, default: `"latest"`) - hindsight-embed version to use (e.g., `"latest"`, `"0.4.2"`, or leave empty for latest). Use this to pin a specific version if latest is broken.
## Supported LLM Providers
@@ -156,7 +156,7 @@ clawdbot plugins list | grep hindsight
```
**Test auto-recall:**
Send a message on any Moltbot channel (Telegram, Slack, etc.):
Send a message on any OpenClawd channel (Telegram, Slack, etc.):
```
User: My name is John and I love pizza
Bot: Got it! I'll remember that.
@@ -172,7 +172,55 @@ tail -f ~/.hindsight/daemon.log
**Check memories in database:**
```bash
uvx hindsight-embed memory recall moltbot "pizza" --output json
uvx hindsight-embed@latest memory recall openclawd "pizza" --output json
```
## Inspecting Memories
The plugin uses `hindsight-embed` daemon which provides CLI commands for inspection:
**View daemon logs:**
```bash
uvx hindsight-embed@latest daemon logs
# Or follow logs in real-time:
tail -f ~/.hindsight/daemon.log
```
**Open web UI:**
```bash
uvx hindsight-embed@latest ui
# Opens browser to http://localhost:8890
# Browse memories, facts, entities, and relationships
```
**List memory banks:**
```bash
uvx hindsight-embed@latest bank list
# Shows all banks including 'openclawd'
```
**Query memories:**
```bash
# Search memories
uvx hindsight-embed@latest memory recall openclawd "user preferences" --output json
# View recent memories
uvx hindsight-embed@latest memory list openclawd --limit 10
# Export all memories
uvx hindsight-embed@latest memory export openclawd --output memories.json
```
**Inspect facts and entities:**
```bash
# List extracted facts
uvx hindsight-embed@latest fact list openclawd
# List entities
uvx hindsight-embed@latest entity list openclawd
# Show entity relationships
uvx hindsight-embed@latest entity graph openclawd
```
## Troubleshooting
@@ -180,20 +228,19 @@ uvx hindsight-embed memory recall moltbot "pizza" --output json
**Plugin not loading?**
```bash
# Check plugin installation
npm list -g @vectorize-io/hindsight-moltbot-plugin
clawdbot plugins list | grep -i hindsight
# Reinstall if needed
npm install -g @vectorize-io/hindsight-moltbot-plugin
clawdbot plugins enable hindsight-memory
clawdbot plugins install @vectorize-io/hindsight-openclawd
```
**Daemon not starting?**
```bash
# Check daemon status
uvx hindsight-embed daemon status
uvx hindsight-embed@latest daemon status
# Manually start
uvx hindsight-embed daemon start
uvx hindsight-embed@latest daemon start
# View logs
tail -f ~/.hindsight/daemon.log
@@ -224,7 +271,7 @@ tail -f /tmp/clawdbot/clawdbot-*.log | grep Hindsight
```bash
# Clone repo
git clone https://github.com/vectorize-io/hindsight.git
cd hindsight/hindsight-integrations/moltbot
cd hindsight/hindsight-integrations/openclawd
# Install dependencies
npm install
@@ -242,7 +289,7 @@ npm run build && ./install.sh
## Requirements
- **Node.js** 22+
- **Moltbot** (Clawdbot) with plugin support
- **OpenClawd** (Clawdbot) with plugin support
- **uv/uvx** for running `hindsight-embed`
- **LLM API key** (OpenAI, Anthropic, etc.)
@@ -253,5 +300,5 @@ MIT
## Links
- [Hindsight Documentation](https://vectorize.io/hindsight)
- [Moltbot Documentation](https://docs.molt.bot)
- [OpenClawd Documentation](https://openclawd.ai)
- [GitHub Repository](https://github.com/vectorize-io/hindsight)
+3 -1
View File
@@ -120,7 +120,9 @@ Run `hindsight-embed configure` for a guided setup that saves to `~/.hindsight/e
| `HINDSIGHT_EMBED_LLM_API_KEY` | LLM API key (or use `OPENAI_API_KEY`) | Required |
| `HINDSIGHT_EMBED_LLM_PROVIDER` | LLM provider (`openai`, `groq`, `google`, `ollama`) | `openai` |
| `HINDSIGHT_EMBED_LLM_MODEL` | LLM model | `gpt-4o-mini` |
| `HINDSIGHT_EMBED_BANK_ID` | Memory bank ID | `default` |
| `HINDSIGHT_EMBED_BANK_ID` | Default memory bank ID (optional, used when not specified in CLI) | `default` |
**Note:** All banks share a single pg0 database (`pg0://hindsight-embed`). Bank isolation happens within the database via the `bank_id` parameter passed to CLI commands.
### Files
@@ -71,9 +71,8 @@ def _start_daemon(config: dict) -> bool:
if config.get("llm_model"):
env["HINDSIGHT_API_LLM_MODEL"] = config["llm_model"]
# Use pg0 database specific to bank
bank_id = config.get("bank_id", "default")
env["HINDSIGHT_API_DATABASE_URL"] = f"pg0://hindsight-embed-{bank_id}"
# Use single shared pg0 database for all banks (banks are isolated within the database)
env["HINDSIGHT_API_DATABASE_URL"] = "pg0://hindsight-embed"
env["HINDSIGHT_API_LOG_LEVEL"] = "info"
# Get idle timeout from environment or use default
-38
View File
@@ -1,38 +0,0 @@
# Hindsight Memory Plugin for Moltbot
Biomimetic long-term memory for [Moltbot](https://molt.bot) using [Hindsight](https://vectorize.io/hindsight). Automatically captures conversations and intelligently recalls relevant context.
## Quick Start
```bash
# 1. Install the plugin
npm install -g @vectorize-io/hindsight-moltbot-plugin
# 2. Configure your LLM provider
export OPENAI_API_KEY="sk-your-key"
clawdbot config set 'agents.defaults.models."openai/gpt-4o-mini"' '{}'
# 3. Enable the plugin
clawdbot plugins enable hindsight-memory
# 4. Start Moltbot
clawdbot gateway
```
That's it! The plugin will automatically start capturing and recalling memories.
## Documentation
For full documentation, configuration options, troubleshooting, and development guide, see:
**[Moltbot Integration Documentation](https://vectorize.io/hindsight/sdks/integrations/moltbot)**
## Links
- [Hindsight Documentation](https://vectorize.io/hindsight)
- [Moltbot Documentation](https://docs.molt.bot)
- [GitHub Repository](https://github.com/vectorize-io/hindsight)
## License
MIT
@@ -1,33 +0,0 @@
{
"id": "hindsight-memory",
"name": "Hindsight Memory",
"kind": "memory",
"moltbot": {
"skills": ["skills"]
},
"configSchema": {
"type": "object",
"properties": {
"bankMission": {
"type": "string",
"description": "Custom mission/context for the memory bank (overrides default)"
},
"embedPort": {
"type": "number",
"description": "Port for hindsight-embed server (auto-assigned if not specified)",
"default": 0
}
},
"additionalProperties": false
},
"uiHints": {
"bankMission": {
"label": "Bank Mission",
"placeholder": "Custom context for what this agent does..."
},
"embedPort": {
"label": "Embed Server Port",
"placeholder": "0 (auto-assign)"
}
}
}
@@ -1,25 +0,0 @@
---
name: hindsight-retain-messages
description: Automatically retains messages to Hindsight long-term memory
events:
- agent_end
metadata:
moltbot:
emoji: 🧠
---
# Hindsight Message Retention
This hook automatically retains conversation messages to Hindsight's long-term memory.
## When It Runs
- On `agent_end`: After each agent turn completes
## What It Does
1. Captures the current session messages
2. Formats them into a conversation transcript
3. Calls Hindsight's retain API with the session_id as document_id
4. Queues for background processing (async)
5. Extracts facts, entities, and relationships from the conversation
@@ -1,68 +0,0 @@
// Handler for auto-retaining messages to Hindsight
const handler = async (event) => {
console.log(`[Hindsight Hook] Received event: ${event.type}`);
// Only process agent_end events (after each agent turn)
if (event.type !== 'agent_end') {
return;
}
console.log('[Hindsight Hook] Processing retention after agent turn...');
try {
// Get client from global (set by main plugin)
const clientGlobal = global.__hindsightClient;
if (!clientGlobal) {
console.warn('[Hindsight] Client global not found, skipping retain');
return;
}
const client = clientGlobal.getClient();
if (!client) {
console.warn('[Hindsight] Client not initialized, skipping retain');
return;
}
// Extract session information
const { sessionId, sessionKey } = event.context || {};
if (!sessionId) {
return;
}
// Get messages from the event context
const sessionEntry = event.context?.sessionEntry;
if (!sessionEntry || !sessionEntry.messages || sessionEntry.messages.length === 0) {
return;
}
// Format messages into a transcript
const transcript = sessionEntry.messages
.map((msg) => {
const role = msg.role || 'unknown';
const content = msg.content || '';
return `${role}: ${content}`;
})
.join('\n\n');
if (!transcript.trim()) {
return;
}
// Retain to Hindsight with session_id as document_id
await client.retain({
content: transcript,
document_id: sessionId,
metadata: {
session_key: sessionKey,
retained_at: new Date().toISOString(),
message_count: sessionEntry.messages.length,
},
});
console.log(`[Hindsight] Retained ${sessionEntry.messages.length} messages for session ${sessionId}`);
} catch (error) {
console.error('[Hindsight] Error retaining messages:', error);
}
};
export default handler;
@@ -1,71 +0,0 @@
// Handler for auto-retaining messages to Hindsight
import type { HookHandler } from 'moltbot/plugin-sdk';
const handler: HookHandler = async (event) => {
// Only process tool_result_persist and command:new events
if (
event.type !== 'tool_result_persist' &&
!(event.type === 'command' && event.action === 'new')
) {
return;
}
try {
// Get client from global (set by main plugin)
const clientGlobal = (global as any).__hindsightClient;
if (!clientGlobal) {
console.warn('[Hindsight] Client global not found, skipping retain');
return;
}
const client = clientGlobal.getClient();
if (!client) {
console.warn('[Hindsight] Client not initialized, skipping retain');
return;
}
// Extract session information
const { sessionId, sessionKey } = event.context || {};
if (!sessionId) {
return;
}
// Get messages from the event context
// The messages are in event.context.sessionEntry or similar
const sessionEntry = event.context?.sessionEntry;
if (!sessionEntry || !sessionEntry.messages || sessionEntry.messages.length === 0) {
return;
}
// Format messages into a transcript
const transcript = sessionEntry.messages
.map((msg: any) => {
const role = msg.role || 'unknown';
const content = msg.content || '';
return `${role}: ${content}`;
})
.join('\n\n');
if (!transcript.trim()) {
return;
}
// Retain to Hindsight with session_id as document_id
await client.retain({
content: transcript,
document_id: sessionId,
metadata: {
session_key: sessionKey,
retained_at: new Date().toISOString(),
message_count: sessionEntry.messages.length,
},
});
console.log(`[Hindsight] Retained ${sessionEntry.messages.length} messages for session ${sessionId}`);
} catch (error) {
console.error('[Hindsight] Error retaining messages:', error);
}
};
export default handler;
@@ -1,34 +0,0 @@
---
name: memory_search
description: Search your long-term memory for relevant facts, experiences, and context using semantic and graph-based retrieval
user-invocable: false
disable-model-invocation: false
---
# memory_search
Search your long-term memory for relevant information. This tool provides multi-strategy retrieval combining:
- Semantic search across facts and experiences
- BM25 keyword matching
- Entity graph traversal
- Temporal queries
- Cross-encoder reranking
## Usage
Call `memory_search` with a natural language query to find relevant memories:
```
memory_search "What does the user prefer for breakfast?"
memory_search "When did we discuss the project deadline?"
memory_search "Tell me about Paris"
```
## Returns
Returns a list of relevant memory fragments with:
- Content: The actual memory text
- Score: Relevance score (0-1)
- Metadata: Source document, creation date, entities
Use the results to inform your responses with context from past conversations.
@@ -1,46 +0,0 @@
// Handler for memory_search tool
// This will be called when the agent invokes memory_search
import { getClient } from '../../src/index.js';
export interface ToolContext {
query: string;
args: Record<string, unknown>;
}
export async function handle(ctx: ToolContext): Promise<string> {
try {
const { query } = ctx;
const client = getClient();
if (!client) {
throw new Error('Hindsight client not initialized');
}
// Call Hindsight recall API
const response = await client.recall({
query,
limit: 10,
});
// Format results for the agent
if (!response.results || response.results.length === 0) {
return 'No relevant memories found for this query.';
}
const formatted = response.results
.map((result: any, idx: number) => {
const score = result.score ? ` (relevance: ${result.score.toFixed(2)})` : '';
const date = result.metadata?.created_at
? ` [${new Date(result.metadata.created_at).toLocaleDateString()}]`
: '';
return `${idx + 1}. ${result.content}${score}${date}`;
})
.join('\n\n');
return `Found ${response.results.length} relevant memories:\n\n${formatted}`;
} catch (error) {
console.error('[Hindsight] memory_search error:', error);
return `Error searching memories: ${error instanceof Error ? error.message : String(error)}`;
}
}
@@ -0,0 +1,35 @@
# Hindsight Memory Plugin for OpenClawd
Biomimetic long-term memory for [OpenClawd](https://openclawd.ai) using [Hindsight](https://vectorize.io/hindsight). Automatically captures conversations and intelligently recalls relevant context.
## Quick Start
```bash
# 1. Configure your LLM provider
export OPENAI_API_KEY="sk-your-key"
clawdbot config set 'agents.defaults.models."openai/gpt-4o-mini"' '{}'
# 2. Install and enable the plugin
clawdbot plugins install @vectorize-io/hindsight-openclawd
# 3. Start OpenClawd
clawdbot gateway
```
That's it! The plugin will automatically start capturing and recalling memories.
## Documentation
For full documentation, configuration options, troubleshooting, and development guide, see:
**[OpenClawd Integration Documentation](https://vectorize.io/hindsight/sdks/integrations/openclawd)**
## Links
- [Hindsight Documentation](https://vectorize.io/hindsight)
- [OpenClawd Documentation](https://openclawd.ai)
- [GitHub Repository](https://github.com/vectorize-io/hindsight)
## License
MIT
@@ -0,0 +1,49 @@
{
"id": "hindsight-openclawd",
"name": "Hindsight Memory",
"kind": "memory",
"configSchema": {
"type": "object",
"properties": {
"daemonIdleTimeout": {
"type": "number",
"description": "Seconds before daemon shuts down from inactivity (0 = never)",
"default": 0
},
"embedPort": {
"type": "number",
"description": "Port for hindsight-embed server (auto-assigned if not specified)",
"default": 0
},
"bankMission": {
"type": "string",
"description": "Custom mission/context for the memory bank",
"default": "You are an AI assistant helping users across multiple communication channels (Telegram, Slack, Discord, etc.). Remember user preferences, instructions, and important context from conversations to provide personalized assistance."
},
"embedVersion": {
"type": "string",
"description": "hindsight-embed version to use (e.g. 'latest', '0.4.2', or empty for latest)",
"default": "latest"
}
},
"additionalProperties": false
},
"uiHints": {
"daemonIdleTimeout": {
"label": "Daemon Idle Timeout",
"placeholder": "0 (never timeout)"
},
"embedPort": {
"label": "Embed Server Port",
"placeholder": "0 (auto-assign)"
},
"bankMission": {
"label": "Bank Mission",
"placeholder": "Custom context for what this agent does..."
},
"embedVersion": {
"label": "Hindsight Embed Version",
"placeholder": "latest (or pin to specific version like 0.4.2)"
}
}
}
@@ -5,7 +5,7 @@ echo "🚀 Installing Hindsight Memory Plugin for Moltbot..."
# Get the directory where this script is located
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
INSTALL_DIR="$HOME/.clawdbot/extensions/hindsight-memory"
INSTALL_DIR="$HOME/.clawdbot/extensions/hindsight-openclawd"
# Check Node version
if ! command -v node &> /dev/null; then
@@ -25,7 +25,7 @@ rm -rf "$INSTALL_DIR"
mkdir -p "$INSTALL_DIR"
# Copy files
cp -r dist package.json clawdbot.plugin.json hooks README.md "$INSTALL_DIR/"
cp -r dist package.json clawdbot.plugin.json README.md "$INSTALL_DIR/"
# Install dependencies in deployed location
echo "📥 Installing dependencies..."
@@ -41,9 +41,9 @@ echo "1. Make sure you have an OpenAI API key set:"
echo " export OPENAI_API_KEY=\"sk-your-key-here\""
echo ""
echo "2. Enable the plugin:"
echo " clawdbot plugins enable hindsight-memory"
echo " clawdbot plugins enable hindsight-openclawd"
echo ""
echo "3. Start Moltbot:"
echo "3. Start OpenClawd:"
echo " clawdbot start"
echo ""
echo "On first start, uvx will automatically download hindsight-embed (no manual install needed)"
@@ -1,21 +1,17 @@
{
"name": "@vectorize-io/hindsight-moltbot-plugin",
"version": "0.1.0",
"description": "Hindsight memory plugin for Moltbot - biomimetic long-term memory with fact extraction",
"name": "@vectorize-io/hindsight-openclawd",
"version": "0.0.5",
"description": "Hindsight memory plugin for OpenClawd - biomimetic long-term memory with fact extraction",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"type": "module",
"clawdbot": {
"extensions": [
"./dist/index.js"
],
"hooks": [
"hooks/retain-messages"
]
},
"keywords": [
"moltbot",
"clawdbot",
"openclawd",
"memory",
"ai",
"agent",
@@ -27,12 +23,11 @@
"repository": {
"type": "git",
"url": "https://github.com/vectorize-io/hindsight.git",
"directory": "hindsight-integrations/moltbot"
"directory": "hindsight-integrations/openclawd"
},
"files": [
"dist",
"clawdbot.plugin.json",
"hooks",
"README.md"
],
"scripts": {
@@ -15,17 +15,37 @@ export class HindsightClient {
private llmProvider: string;
private llmApiKey: string;
private llmModel?: string;
private embedVersion: string;
constructor(llmProvider: string, llmApiKey: string, llmModel?: string) {
constructor(llmProvider: string, llmApiKey: string, llmModel?: string, embedVersion: string = 'latest') {
this.llmProvider = llmProvider;
this.llmApiKey = llmApiKey;
this.llmModel = llmModel;
this.embedVersion = embedVersion || 'latest';
}
setBankId(bankId: string): void {
this.bankId = bankId;
}
async setBankMission(mission: string): Promise<void> {
if (!mission || mission.trim().length === 0) {
return;
}
const escapedMission = mission.replace(/'/g, "'\\''"); // Escape single quotes
const embedPackage = this.embedVersion ? `hindsight-embed@${this.embedVersion}` : 'hindsight-embed@latest';
const cmd = `uvx ${embedPackage} bank mission ${this.bankId} '${escapedMission}'`;
try {
const { stdout } = await execAsync(cmd, { env: this.getEnv() });
console.log(`[Hindsight] Bank mission set: ${stdout.trim()}`);
} catch (error) {
// Don't fail if mission set fails - bank might not exist yet, will be created on first retain
console.warn(`[Hindsight] Could not set bank mission (bank may not exist yet): ${error}`);
}
}
private getEnv(): Record<string, string> {
const env: Record<string, string> = {
...process.env,
@@ -44,7 +64,8 @@ export class HindsightClient {
const content = request.content.replace(/'/g, "'\\''"); // Escape single quotes
const docId = request.document_id || 'conversation';
const cmd = `uvx hindsight-embed memory retain ${this.bankId} '${content}' --doc-id '${docId}' --async`;
const embedPackage = this.embedVersion ? `hindsight-embed@${this.embedVersion}` : 'hindsight-embed@latest';
const cmd = `uvx ${embedPackage} memory retain ${this.bankId} '${content}' --doc-id '${docId}' --async`;
try {
const { stdout } = await execAsync(cmd, { env: this.getEnv() });
@@ -65,7 +86,8 @@ export class HindsightClient {
const query = request.query.replace(/'/g, "'\\''"); // Escape single quotes
const maxTokens = request.max_tokens || 1024;
const cmd = `uvx hindsight-embed memory recall ${this.bankId} '${query}' --output json --max-tokens ${maxTokens}`;
const embedPackage = this.embedVersion ? `hindsight-embed@${this.embedVersion}` : 'hindsight-embed@latest';
const cmd = `uvx ${embedPackage} memory recall ${this.bankId} '${query}' --output json --max-tokens ${maxTokens}`;
try {
const { stdout } = await execAsync(cmd, { env: this.getEnv() });
@@ -13,13 +13,15 @@ export class HindsightEmbedManager {
private llmApiKey: string;
private llmModel?: string;
private daemonIdleTimeout: number;
private embedVersion: string;
constructor(
port: number,
llmProvider: string,
llmApiKey: string,
llmModel?: string,
daemonIdleTimeout: number = 0 // Default: never timeout
daemonIdleTimeout: number = 0, // Default: never timeout
embedVersion: string = 'latest' // Default: latest
) {
this.port = 8889; // hindsight-embed uses fixed port 8889
this.baseUrl = `http://127.0.0.1:8889`;
@@ -28,6 +30,7 @@ export class HindsightEmbedManager {
this.llmApiKey = llmApiKey;
this.llmModel = llmModel;
this.daemonIdleTimeout = daemonIdleTimeout;
this.embedVersion = embedVersion || 'latest';
}
async start(): Promise<void> {
@@ -46,9 +49,10 @@ export class HindsightEmbedManager {
}
// Start hindsight-embed daemon (it manages itself)
const embedPackage = this.embedVersion ? `hindsight-embed@${this.embedVersion}` : 'hindsight-embed@latest';
const startDaemon = spawn(
'uvx',
['hindsight-embed', 'daemon', 'start'],
[embedPackage, 'daemon', 'start'],
{
env,
stdio: 'pipe',
@@ -93,7 +97,8 @@ export class HindsightEmbedManager {
async stop(): Promise<void> {
console.log('[Hindsight] Stopping hindsight-embed daemon...');
const stopDaemon = spawn('uvx', ['hindsight-embed', 'daemon', 'stop'], {
const embedPackage = this.embedVersion ? `hindsight-embed@${this.embedVersion}` : 'hindsight-embed@latest';
const stopDaemon = spawn('uvx', [embedPackage, 'daemon', 'stop'], {
stdio: 'pipe',
});
@@ -7,11 +7,17 @@ import { fileURLToPath } from 'url';
// Module-level state
let embedManager: HindsightEmbedManager | null = null;
let client: HindsightClient | null = null;
let initPromise: Promise<void> | null = null;
let isInitialized = false;
// Global access for hooks (Moltbot loads hooks separately)
if (typeof global !== 'undefined') {
(global as any).__hindsightClient = {
getClient: () => client,
waitForReady: async () => {
if (isInitialized) return;
if (initPromise) await initPromise;
},
};
}
@@ -20,7 +26,7 @@ const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
// Default bank name
const BANK_NAME = 'moltbot';
const BANK_NAME = 'openclawd';
// Provider mapping: moltbot provider name -> hindsight provider name
const PROVIDER_MAP: Record<string, string> = {
@@ -108,11 +114,14 @@ function detectLLMConfig(api: MoltbotPluginAPI): {
}
function getPluginConfig(api: MoltbotPluginAPI): PluginConfig {
const config = api.config.plugins?.entries?.['hindsight-memory']?.config || {};
const config = api.config.plugins?.entries?.['hindsight-openclawd']?.config || {};
const defaultMission = 'You are an AI assistant helping users across multiple communication channels (Telegram, Slack, Discord, etc.). Remember user preferences, instructions, and important context from conversations to provide personalized assistance.';
return {
bankMission: config.bankMission,
bankMission: config.bankMission || defaultMission,
embedPort: config.embedPort || 0,
daemonIdleTimeout: config.daemonIdleTimeout !== undefined ? config.daemonIdleTimeout : 0,
embedVersion: config.embedVersion || 'latest',
};
}
@@ -141,41 +150,57 @@ export default function (api: MoltbotPluginAPI) {
const port = pluginConfig.embedPort || Math.floor(Math.random() * 10000) + 10000;
console.log(`[Hindsight] Port: ${port}`);
// Register background service
// Initialize in background (non-blocking)
console.log('[Hindsight] Starting initialization in background...');
initPromise = (async () => {
try {
// Initialize embed manager
console.log('[Hindsight] Creating HindsightEmbedManager...');
embedManager = new HindsightEmbedManager(
port,
llmConfig.provider,
llmConfig.apiKey,
llmConfig.model,
pluginConfig.daemonIdleTimeout,
pluginConfig.embedVersion
);
// Start the embedded server
console.log('[Hindsight] Starting embedded server...');
await embedManager.start();
// Initialize client
console.log('[Hindsight] Creating HindsightClient...');
client = new HindsightClient(llmConfig.provider, llmConfig.apiKey, llmConfig.model, pluginConfig.embedVersion);
// Use openclawd bank
console.log(`[Hindsight] Using bank: ${BANK_NAME}`);
client.setBankId(BANK_NAME);
// Set bank mission
if (pluginConfig.bankMission) {
console.log(`[Hindsight] Setting bank mission...`);
await client.setBankMission(pluginConfig.bankMission);
}
isInitialized = true;
console.log('[Hindsight] ✓ Ready');
} catch (error) {
console.error('[Hindsight] Initialization error:', error);
throw error;
}
})();
// Don't await - let it initialize in background
// Register background service for cleanup
console.log('[Hindsight] Registering service...');
api.registerService({
id: 'hindsight-memory',
async start() {
try {
console.log('[Hindsight] Service starting...');
// Initialize embed manager
console.log('[Hindsight] Creating HindsightEmbedManager...');
embedManager = new HindsightEmbedManager(
port,
llmConfig.provider,
llmConfig.apiKey,
llmConfig.model,
pluginConfig.daemonIdleTimeout
);
// Start the embedded server
console.log('[Hindsight] Starting embedded server...');
await embedManager.start();
// Initialize client
console.log('[Hindsight] Creating HindsightClient...');
client = new HindsightClient(llmConfig.provider, llmConfig.apiKey, llmConfig.model);
// Use moltbot bank
console.log(`[Hindsight] Using bank: ${BANK_NAME}`);
client.setBankId(BANK_NAME);
console.log('[Hindsight] Service ready');
} catch (error) {
console.error('[Hindsight] Service start error:', error);
throw error;
}
// Wait for background init if still pending
console.log('[Hindsight] Service start called - ensuring initialization complete...');
if (initPromise) await initPromise;
},
async stop() {
@@ -188,6 +213,7 @@ export default function (api: MoltbotPluginAPI) {
}
client = null;
isInitialized = false;
console.log('[Hindsight] Service stopped');
} catch (error) {
@@ -229,14 +255,18 @@ export default function (api: MoltbotPluginAPI) {
return; // Skip very short messages after extraction
}
// Get client from global
// Wait for client to be ready
const clientGlobal = (global as any).__hindsightClient;
if (!clientGlobal) {
console.log('[Hindsight] Client global not available, skipping auto-recall');
return;
}
await clientGlobal.waitForReady();
const client = clientGlobal.getClient();
if (!client) {
console.log('[Hindsight] Client not initialized, skipping auto-recall');
return;
}
@@ -253,21 +283,12 @@ export default function (api: MoltbotPluginAPI) {
return;
}
// Format memories for injection
const memories = response.results
.map((result: any, idx: number) => {
const score = result.score ? ` (relevance: ${result.score.toFixed(2)})` : '';
return `${idx + 1}. ${result.content}${score}`;
})
.join('\n\n');
// Format memories as JSON with all fields from recall
const memoriesJson = JSON.stringify(response.results, null, 2);
const contextMessage = `<hindsight-context>
You have access to long-term memory from previous conversations. Here are relevant memories:
${memories}
Use this context naturally when relevant to the conversation. Don't mention "memory" or "recall" unless specifically asked about past conversations.
</hindsight-context>`;
const contextMessage = `<hindsight_memories>
${memoriesJson}
</hindsight_memories>`;
console.log(`[Hindsight] Auto-recall: Injecting ${response.results.length} memories`);
@@ -289,13 +310,15 @@ Use this context naturally when relevant to the conversation. Don't mention "mem
return;
}
// Get client from global
// Wait for client to be ready
const clientGlobal = (global as any).__hindsightClient;
if (!clientGlobal) {
console.warn('[Hindsight] Client global not found, skipping retain');
return;
}
await clientGlobal.waitForReady();
const client = clientGlobal.getClient();
if (!client) {
console.warn('[Hindsight] Client not initialized, skipping retain');
@@ -31,6 +31,7 @@ export interface PluginConfig {
bankMission?: string;
embedPort?: number;
daemonIdleTimeout?: number; // Seconds before daemon shuts down (0 = never)
embedVersion?: string; // hindsight-embed version (default: "latest")
}
export interface ServiceConfig {
@@ -14,5 +14,5 @@
"resolveJsonModule": true
},
"include": ["src/**/*"],
"exclude": ["node_modules", "dist", "skills"]
"exclude": ["node_modules", "dist", "src/**/*.test.ts"]
}
+11
View File
@@ -144,6 +144,16 @@ else
print_warn "File $TYPESCRIPT_CLIENT_PKG not found, skipping"
fi
# Update OpenClawd integration
OPENCLAWD_PKG="hindsight-integrations/openclawd/package.json"
if [ -f "$OPENCLAWD_PKG" ]; then
print_info "Updating $OPENCLAWD_PKG"
sed -i.bak "s/\"version\": \".*\"/\"version\": \"$VERSION\"/" "$OPENCLAWD_PKG"
rm "${OPENCLAWD_PKG}.bak"
else
print_warn "File $OPENCLAWD_PKG not found, skipping"
fi
# Update documentation version (creates new version or syncs to existing)
print_info "Updating documentation for version $VERSION..."
if [ -f "scripts/update-docs-version.sh" ]; then
@@ -188,6 +198,7 @@ COMMIT_MSG="Release v$VERSION
- TypeScript client: hindsight-clients/typescript
- Rust CLI: hindsight-cli
- Control Plane: hindsight-control-plane
- OpenClawd integration: hindsight-integrations/openclawd
- Helm chart"
# Add docs update note