refactor(openclaw)!: read config from plugin config instead of process.env (#974)
* refactor(openclaw)!: read config from plugin config instead of process.env The plugin loaded credentials and runtime settings from environment variables (HINDSIGHT_API_LLM_*, HINDSIGHT_EMBED_API_*, HINDSIGHT_BANK_ID) plus auto-detection of OPENAI_API_KEY / ANTHROPIC_API_KEY / GEMINI_API_KEY / GROQ_API_KEY. That tripped OpenClaw's install-scanner env-harvesting rule and bypassed the framework's first-class SecretRef resolution. Switch to reading from the plugin config exclusively, with secrets configured via 'openclaw config set ... --ref-source env|file|exec'. Combined with the daemon lifecycle extraction in #949, this closes the remaining install-scanner findings the 0.5.x plugin was hitting. The plugin source now contains neither process.env nor child_process; the former moved to plugin config (resolved by OpenClaw before the plugin loads), and the latter lives in @vectorize-io/hindsight-all under node_modules where the scanner's directory walker skips it. The plugin can be installed without --dangerously-force-unsafe-install. BREAKING CHANGE: drops the llmApiKeyEnv plugin config field along with the HINDSIGHT_API_LLM_*, HINDSIGHT_EMBED_API_*, and HINDSIGHT_BANK_ID environment variables. Users must now configure llmProvider and llmApiKey explicitly via 'openclaw config set'. Migration guide is in hindsight-docs/docs-integrations/openclaw.md and the integration changelog. * chore(openclaw): pin published versions of hindsight-all and hindsight-client Phase 2 (#949) introduced @vectorize-io/hindsight-all and @vectorize-io/hindsight-client as plugin dependencies using 'file:' workspace paths. Those paths resolve inside the monorepo but break when the published tarball is installed outside it — 'openclaw plugins install @vectorize-io/hindsight-openclaw' failed with 'Cannot find module @vectorize-io/hindsight-all' because npm could not resolve the file: path from the extracted extension directory. Replace both with semver ranges targeting the published versions: @vectorize-io/hindsight-all ^0.1.0 @vectorize-io/hindsight-client ^0.5.0 Verified end-to-end: 'openclaw plugins install <local-tarball>' now succeeds without --dangerously-force-unsafe-install and without the workspace-symlink hack. npm pulls both dependencies from the registry into the extracted extension's node_modules, the plugin loads cleanly, and 'openclaw plugins doctor' reports no issues.
This commit is contained in:
parent
b57e337fa2
commit
e22ae05f47
10 changed files with 292 additions and 253 deletions
|
|
@ -14,36 +14,37 @@ This plugin integrates [hindsight-embed](https://vectorize.io/hindsight/cli), a
|
|||
|
||||
## Quick Start
|
||||
|
||||
**Step 1: Set up LLM for memory extraction**
|
||||
|
||||
Choose one provider and set its API key:
|
||||
|
||||
```bash
|
||||
# Option A: OpenAI
|
||||
export OPENAI_API_KEY="sk-your-key"
|
||||
|
||||
# Option B: Anthropic
|
||||
export ANTHROPIC_API_KEY="your-key"
|
||||
|
||||
# Option C: Gemini
|
||||
export GEMINI_API_KEY="your-key"
|
||||
|
||||
# Option D: Groq
|
||||
export GROQ_API_KEY="your-key"
|
||||
|
||||
# Option E: Claude Code (no API key needed)
|
||||
export HINDSIGHT_API_LLM_PROVIDER=claude-code
|
||||
|
||||
# Option F: OpenAI Codex (no API key needed)
|
||||
export HINDSIGHT_API_LLM_PROVIDER=openai-codex
|
||||
```
|
||||
|
||||
**Step 2: Install the plugin**
|
||||
**Step 1: Install the plugin**
|
||||
|
||||
```bash
|
||||
openclaw plugins install @vectorize-io/hindsight-openclaw
|
||||
```
|
||||
|
||||
**Step 2: Configure the LLM provider used for memory extraction**
|
||||
|
||||
The plugin reads configuration from OpenClaw's plugin config — set it
|
||||
non-interactively with `openclaw config set`:
|
||||
|
||||
```bash
|
||||
# Option A — OpenAI (set llmApiKey as a SecretRef so the value comes from
|
||||
# the OPENAI_API_KEY environment variable at runtime instead of being
|
||||
# stored in plaintext on disk)
|
||||
openclaw config set plugins.entries.hindsight-openclaw.config.llmProvider openai
|
||||
openclaw config set plugins.entries.hindsight-openclaw.config.llmApiKey \
|
||||
--ref-source env --ref-provider default --ref-id OPENAI_API_KEY
|
||||
|
||||
# Option B — Anthropic
|
||||
openclaw config set plugins.entries.hindsight-openclaw.config.llmProvider anthropic
|
||||
openclaw config set plugins.entries.hindsight-openclaw.config.llmApiKey \
|
||||
--ref-source env --ref-provider default --ref-id ANTHROPIC_API_KEY
|
||||
|
||||
# Option C — Claude Code (no API key needed)
|
||||
openclaw config set plugins.entries.hindsight-openclaw.config.llmProvider claude-code
|
||||
|
||||
# Option D — OpenAI Codex (no API key needed)
|
||||
openclaw config set plugins.entries.hindsight-openclaw.config.llmProvider openai-codex
|
||||
```
|
||||
|
||||
**Step 3: Start OpenClaw**
|
||||
|
||||
```bash
|
||||
|
|
@ -57,6 +58,8 @@ The plugin will automatically:
|
|||
|
||||
**Important:** The LLM you configure above is **only for memory extraction** (background processing). Your main OpenClaw agent can use any model you configure separately.
|
||||
|
||||
**Migrating from 0.5.x?** See the [Migration from 0.5.x](#migration-from-05x) section below for the env-var → SecretRef mapping.
|
||||
|
||||
## How It Works
|
||||
|
||||
**Auto-Capture:** Every conversation is automatically stored after each turn. Facts, entities, and relationships are extracted in the background.
|
||||
|
|
@ -94,9 +97,13 @@ Optional settings in `~/.openclaw/openclaw.json`:
|
|||
- `apiPort` - Port for the openclaw profile daemon (default: `9077`)
|
||||
- `daemonIdleTimeout` - Seconds before daemon shuts down from inactivity (default: `0` = never)
|
||||
- `embedVersion` - hindsight-embed version (default: `"latest"`)
|
||||
- `llmProvider` - LLM provider for memory extraction (`openai`, `anthropic`, `gemini`, `groq`, `ollama`, `openai-codex`, `claude-code`). Required unless `hindsightApiUrl` is set.
|
||||
- `llmModel` - LLM model used with `llmProvider` (provider default if omitted)
|
||||
- `llmApiKey` - API key for the LLM provider. **Sensitive** — set via `openclaw config set ... --ref-source env --ref-id OPENAI_API_KEY` to reference an env var.
|
||||
- `llmBaseUrl` - Optional base URL override for OpenAI-compatible providers (e.g. `https://openrouter.ai/api/v1`)
|
||||
- `bankMission` - Agent identity/purpose stored on the memory bank. Helps the memory engine understand context for better fact extraction during retain. Set once per bank on first use — not a recall prompt.
|
||||
- `dynamicBankId` - Enable per-context memory banks (default: `true`)
|
||||
- `bankId` - Static bank ID used when `dynamicBankId` is `false`. Can also be set with `HINDSIGHT_BANK_ID`.
|
||||
- `bankId` - Static bank ID used when `dynamicBankId` is `false`.
|
||||
- `bankIdPrefix` - Optional prefix for bank IDs (e.g. `"prod"` → `"prod-slack-C123"` or `"prod-shared-bank"`)
|
||||
- `dynamicBankGranularity` - Fields used to derive bank ID: `agent`, `channel`, `user`, `provider` (default: `["agent", "channel", "user"]`)
|
||||
- `excludeProviders` - Message providers to skip for recall/retain (e.g. `["slack"]`, `["telegram"]`, `["discord"]`)
|
||||
|
|
@ -145,7 +152,7 @@ Available isolation fields:
|
|||
- `user` - The user interacting with the agent
|
||||
- `provider` - The message provider (e.g. Slack, Discord)
|
||||
|
||||
Use `bankIdPrefix` to namespace bank IDs across environments (e.g. `"prod"`, `"staging"`). Set `dynamicBankId` to `false` to use a single shared bank for all conversations. In static mode, the plugin uses `bankId`, then `HINDSIGHT_BANK_ID`, then the default `openclaw` bank name.
|
||||
Use `bankIdPrefix` to namespace bank IDs across environments (e.g. `"prod"`, `"staging"`). Set `dynamicBankId` to `false` to use a single shared bank for all conversations. In static mode, the plugin uses `bankId` if set, otherwise the default `openclaw` bank name.
|
||||
|
||||
### Retention Controls
|
||||
|
||||
|
|
@ -172,38 +179,61 @@ By default, the plugin retains `user` and `assistant` messages after each turn.
|
|||
|
||||
### LLM Configuration
|
||||
|
||||
The plugin auto-detects your LLM provider from these environment variables:
|
||||
Configure the memory-extraction LLM via OpenClaw's plugin config. API keys
|
||||
should be stored as `SecretRef` values so they're resolved from env vars,
|
||||
mounted files, or `exec`-style secret managers (Vault, etc.) at runtime
|
||||
instead of sitting in plaintext on disk.
|
||||
|
||||
| Provider | Env Var | Notes |
|
||||
|----------|---------|-------|
|
||||
| OpenAI | `OPENAI_API_KEY` | |
|
||||
| Anthropic | `ANTHROPIC_API_KEY` | |
|
||||
| Gemini | `GEMINI_API_KEY` | |
|
||||
| Groq | `GROQ_API_KEY` | |
|
||||
| Claude Code | `HINDSIGHT_API_LLM_PROVIDER=claude-code` | No API key needed |
|
||||
| OpenAI Codex | `HINDSIGHT_API_LLM_PROVIDER=openai-codex` | No API key needed |
|
||||
| Provider | `llmProvider` | API key |
|
||||
|---|---|---|
|
||||
| OpenAI | `openai` | required |
|
||||
| Anthropic | `anthropic` | required |
|
||||
| Gemini | `gemini` | required |
|
||||
| Groq | `groq` | required |
|
||||
| Ollama | `ollama` | not required (local) |
|
||||
| Claude Code | `claude-code` | not required (uses Claude Code CLI) |
|
||||
| OpenAI Codex | `openai-codex` | not required (uses Codex CLI auth) |
|
||||
|
||||
The model is selected automatically by the Hindsight API. To override, set `HINDSIGHT_API_LLM_MODEL`.
|
||||
|
||||
**Override with explicit config:**
|
||||
**Set provider + API key:**
|
||||
|
||||
```bash
|
||||
export HINDSIGHT_API_LLM_PROVIDER=openai
|
||||
export HINDSIGHT_API_LLM_API_KEY=sk-your-key
|
||||
|
||||
# Optional: custom base URL (OpenRouter, Azure, vLLM, etc.)
|
||||
export HINDSIGHT_API_LLM_BASE_URL=https://openrouter.ai/api/v1
|
||||
openclaw config set plugins.entries.hindsight-openclaw.config.llmProvider openai
|
||||
openclaw config set plugins.entries.hindsight-openclaw.config.llmApiKey \
|
||||
--ref-source env --ref-provider default --ref-id OPENAI_API_KEY
|
||||
```
|
||||
|
||||
**Example: Free OpenRouter model**
|
||||
**Override the model (optional — Hindsight picks a sensible default per provider):**
|
||||
|
||||
```bash
|
||||
export HINDSIGHT_API_LLM_PROVIDER=openai
|
||||
export HINDSIGHT_API_LLM_MODEL=xiaomi/mimo-v2-flash # FREE!
|
||||
export HINDSIGHT_API_LLM_API_KEY=sk-or-v1-your-openrouter-key
|
||||
export HINDSIGHT_API_LLM_BASE_URL=https://openrouter.ai/api/v1
|
||||
openclaw config set plugins.entries.hindsight-openclaw.config.llmModel gpt-4o-mini
|
||||
```
|
||||
|
||||
**OpenAI-compatible providers (OpenRouter, Azure OpenAI, vLLM, ...):**
|
||||
|
||||
```bash
|
||||
openclaw config set plugins.entries.hindsight-openclaw.config.llmProvider openai
|
||||
openclaw config set plugins.entries.hindsight-openclaw.config.llmBaseUrl https://openrouter.ai/api/v1
|
||||
openclaw config set plugins.entries.hindsight-openclaw.config.llmApiKey \
|
||||
--ref-source env --ref-provider default --ref-id OPENROUTER_API_KEY
|
||||
openclaw config set plugins.entries.hindsight-openclaw.config.llmModel xiaomi/mimo-v2-flash
|
||||
```
|
||||
|
||||
**Use a file or exec source instead of env (for K8s secrets, Vault, etc.):**
|
||||
|
||||
```bash
|
||||
# File source (e.g. mounted Docker/K8s secret)
|
||||
openclaw config set plugins.entries.hindsight-openclaw.config.llmApiKey \
|
||||
--ref-source file --ref-provider mounted-json --ref-id /providers/openai/apiKey
|
||||
|
||||
# Exec source (e.g. HashiCorp Vault)
|
||||
openclaw config set plugins.entries.hindsight-openclaw.config.llmApiKey \
|
||||
--ref-source exec --ref-provider vault --ref-id openai/api-key
|
||||
```
|
||||
|
||||
The corresponding secret provider needs to be configured under `secrets.providers`
|
||||
in your OpenClaw config — see `openclaw config set --help` for the
|
||||
`--provider-source`/`--provider-path`/`--provider-command` builder flags.
|
||||
|
||||
### External API (Advanced)
|
||||
|
||||
Connect to a remote Hindsight API server instead of running a local daemon. This is useful for:
|
||||
|
|
@ -234,21 +264,13 @@ Configure in `~/.openclaw/openclaw.json`:
|
|||
|
||||
**Options:**
|
||||
- `hindsightApiUrl` - Full URL to external Hindsight API (e.g., `https://mcp.hindsight.example.com`)
|
||||
- `hindsightApiToken` - API token for authentication (optional, only if API requires auth)
|
||||
|
||||
#### Environment Variables (Alternative)
|
||||
|
||||
You can also configure via environment variables:
|
||||
- `hindsightApiToken` - API token for authentication (optional). **Sensitive** — set as a SecretRef:
|
||||
|
||||
```bash
|
||||
export HINDSIGHT_EMBED_API_URL=https://your-hindsight-server.com
|
||||
export HINDSIGHT_EMBED_API_TOKEN=your-api-token # Optional
|
||||
|
||||
openclaw gateway
|
||||
openclaw config set plugins.entries.hindsight-openclaw.config.hindsightApiToken \
|
||||
--ref-source env --ref-provider default --ref-id HINDSIGHT_API_TOKEN
|
||||
```
|
||||
|
||||
**Note:** Plugin config takes precedence over environment variables.
|
||||
|
||||
#### Behavior
|
||||
|
||||
When external API mode is enabled:
|
||||
|
|
@ -336,27 +358,36 @@ uvx hindsight-embed@latest profile list
|
|||
|
||||
### No API key error
|
||||
|
||||
Make sure you've set one of the provider API keys (or use a provider that doesn't require one):
|
||||
Make sure you've configured the LLM provider through `openclaw config set`
|
||||
(or use a provider that doesn't require a key):
|
||||
|
||||
```bash
|
||||
# Option 1: OpenAI
|
||||
export OPENAI_API_KEY="sk-your-key"
|
||||
# Option 1 — OpenAI (requires OPENAI_API_KEY in your env)
|
||||
openclaw config set plugins.entries.hindsight-openclaw.config.llmProvider openai
|
||||
openclaw config set plugins.entries.hindsight-openclaw.config.llmApiKey \
|
||||
--ref-source env --ref-provider default --ref-id OPENAI_API_KEY
|
||||
|
||||
# Option 2: Anthropic
|
||||
export ANTHROPIC_API_KEY="your-key"
|
||||
# Option 2 — Anthropic
|
||||
openclaw config set plugins.entries.hindsight-openclaw.config.llmProvider anthropic
|
||||
openclaw config set plugins.entries.hindsight-openclaw.config.llmApiKey \
|
||||
--ref-source env --ref-provider default --ref-id ANTHROPIC_API_KEY
|
||||
|
||||
# Option 3: Claude Code (no API key needed)
|
||||
export HINDSIGHT_API_LLM_PROVIDER=claude-code
|
||||
# Option 3 — Claude Code (no API key needed)
|
||||
openclaw config set plugins.entries.hindsight-openclaw.config.llmProvider claude-code
|
||||
|
||||
# Option 4: OpenAI Codex (no API key needed)
|
||||
export HINDSIGHT_API_LLM_PROVIDER=openai-codex
|
||||
# Option 4 — OpenAI Codex (no API key needed)
|
||||
openclaw config set plugins.entries.hindsight-openclaw.config.llmProvider openai-codex
|
||||
|
||||
# Verify it's set
|
||||
echo $OPENAI_API_KEY
|
||||
# or
|
||||
echo $HINDSIGHT_API_LLM_PROVIDER
|
||||
# Verify the config is valid
|
||||
openclaw config validate
|
||||
|
||||
# Inspect the current value
|
||||
openclaw config get plugins.entries.hindsight-openclaw.config.llmProvider
|
||||
```
|
||||
|
||||
If you used `--ref-source env`, double-check that the referenced env var
|
||||
(e.g. `OPENAI_API_KEY`) is exported in the shell that runs `openclaw gateway`.
|
||||
|
||||
### Verify it's working
|
||||
|
||||
Check gateway logs for memory operations:
|
||||
|
|
@ -373,3 +404,29 @@ tail -f /tmp/openclaw/openclaw-*.log | grep Hindsight
|
|||
# [Hindsight] Retained X messages for session ...
|
||||
# [Hindsight] Auto-recall: Injecting X memories
|
||||
```
|
||||
|
||||
## Migration from 0.5.x
|
||||
|
||||
0.6.0 removes all process-environment reads from the plugin. Configuration that
|
||||
previously came from shell env vars must now go through OpenClaw's plugin config
|
||||
(with `SecretRef` for credentials). The plugin no longer auto-detects providers
|
||||
from `OPENAI_API_KEY` / `ANTHROPIC_API_KEY` / etc. — you must set
|
||||
`llmProvider` explicitly.
|
||||
|
||||
| Old (0.5.x) | New (0.6.0) |
|
||||
|---|---|
|
||||
| `OPENAI_API_KEY=…` (auto-detected) | `openclaw config set plugins.entries.hindsight-openclaw.config.llmProvider openai` <br/> `openclaw config set plugins.entries.hindsight-openclaw.config.llmApiKey --ref-source env --ref-id OPENAI_API_KEY` |
|
||||
| `HINDSIGHT_API_LLM_PROVIDER=…` | `openclaw config set plugins.entries.hindsight-openclaw.config.llmProvider …` |
|
||||
| `HINDSIGHT_API_LLM_MODEL=…` | `openclaw config set plugins.entries.hindsight-openclaw.config.llmModel …` |
|
||||
| `HINDSIGHT_API_LLM_API_KEY=…` | `openclaw config set plugins.entries.hindsight-openclaw.config.llmApiKey --ref-source env --ref-id …` |
|
||||
| `HINDSIGHT_API_LLM_BASE_URL=…` | `openclaw config set plugins.entries.hindsight-openclaw.config.llmBaseUrl …` |
|
||||
| `HINDSIGHT_EMBED_API_URL=…` | `openclaw config set plugins.entries.hindsight-openclaw.config.hindsightApiUrl …` |
|
||||
| `HINDSIGHT_EMBED_API_TOKEN=…` | `openclaw config set plugins.entries.hindsight-openclaw.config.hindsightApiToken --ref-source env --ref-id …` |
|
||||
| `HINDSIGHT_BANK_ID=…` | `openclaw config set plugins.entries.hindsight-openclaw.config.bankId …` |
|
||||
| `llmApiKeyEnv: "MY_KEY"` (plugin config) | `llmApiKey` configured as a SecretRef with `--ref-id MY_KEY` |
|
||||
|
||||
If your shell already exports `OPENAI_API_KEY`, the SecretRef config above
|
||||
resolves to the same value at startup — you don't need to change your shell
|
||||
setup, just point the plugin at the variable explicitly. Run
|
||||
`openclaw config validate` after migrating to confirm the new shape parses
|
||||
cleanly.
|
||||
|
|
|
|||
|
|
@ -8,6 +8,21 @@ import PageHero from '@site/src/components/PageHero';
|
|||
|
||||
[← OpenClaw integration](/sdks/integrations/openclaw)
|
||||
|
||||
## 0.6.0 (Unreleased)
|
||||
|
||||
**Breaking Changes**
|
||||
|
||||
- The plugin no longer reads any configuration from process environment variables. All settings — including the LLM provider, model, API key, base URL, external Hindsight API URL/token, and bank ID — must now be set through OpenClaw's plugin config (e.g. `openclaw config set plugins.entries.hindsight-openclaw.config.<field> <value>`). API keys and other secrets should be configured as `SecretRef` values via `--ref-source env|file|exec` so they're resolved from your secret store at runtime instead of being stored in plaintext on disk.
|
||||
- Removed the `llmApiKeyEnv` plugin config field. Use the new `llmApiKey` field configured as a SecretRef instead (e.g. `openclaw config set plugins.entries.hindsight-openclaw.config.llmApiKey --ref-source env --ref-id OPENAI_API_KEY`).
|
||||
- Removed automatic LLM provider detection from `OPENAI_API_KEY` / `ANTHROPIC_API_KEY` / `GEMINI_API_KEY` / `GROQ_API_KEY`. Set `llmProvider` and `llmApiKey` explicitly via `openclaw config set`.
|
||||
- Removed support for the `HINDSIGHT_API_LLM_PROVIDER`, `HINDSIGHT_API_LLM_MODEL`, `HINDSIGHT_API_LLM_API_KEY`, `HINDSIGHT_API_LLM_BASE_URL`, `HINDSIGHT_EMBED_API_URL`, `HINDSIGHT_EMBED_API_TOKEN`, and `HINDSIGHT_BANK_ID` environment variables. The same values now live in plugin config — see the [migration guide](/sdks/integrations/openclaw#migration-from-05x).
|
||||
|
||||
**Features**
|
||||
|
||||
- Added the `llmApiKey` plugin config field, marked as a sensitive field so OpenClaw resolves it as a `SecretRef` from env, file, or exec sources.
|
||||
- Added the `llmBaseUrl` plugin config field for OpenAI-compatible endpoint overrides (OpenRouter, Azure OpenAI, vLLM, etc.).
|
||||
- Marked `hindsightApiToken` as a sensitive field — it can now be configured as a `SecretRef` the same way as `llmApiKey`.
|
||||
|
||||
## [0.5.1](https://github.com/vectorize-io/hindsight/tree/integrations/openclaw/v0.5.1)
|
||||
|
||||
**Bug Fixes**
|
||||
|
|
|
|||
|
|
@ -5,25 +5,56 @@ Biomimetic long-term memory for [OpenClaw](https://openclaw.ai) using [Hindsight
|
|||
## Quick Start
|
||||
|
||||
```bash
|
||||
# 1. Configure your LLM provider for memory extraction
|
||||
# Option A: OpenAI
|
||||
export OPENAI_API_KEY="sk-your-key"
|
||||
|
||||
# Option B: Claude Code (no API key needed)
|
||||
export HINDSIGHT_API_LLM_PROVIDER=claude-code
|
||||
|
||||
# Option C: OpenAI Codex (no API key needed)
|
||||
export HINDSIGHT_API_LLM_PROVIDER=openai-codex
|
||||
|
||||
# 2. Install and enable the plugin
|
||||
# 1. Install the plugin
|
||||
openclaw plugins install @vectorize-io/hindsight-openclaw
|
||||
|
||||
# 2. Configure the LLM provider used for memory extraction.
|
||||
|
||||
# Option A — OpenAI (or any OpenAI-compatible provider)
|
||||
openclaw config set plugins.entries.hindsight-openclaw.config.llmProvider openai
|
||||
openclaw config set plugins.entries.hindsight-openclaw.config.llmApiKey \
|
||||
--ref-source env --ref-provider default --ref-id OPENAI_API_KEY
|
||||
|
||||
# Option B — Claude Code (no API key needed)
|
||||
openclaw config set plugins.entries.hindsight-openclaw.config.llmProvider claude-code
|
||||
|
||||
# Option C — OpenAI Codex (no API key needed)
|
||||
openclaw config set plugins.entries.hindsight-openclaw.config.llmProvider openai-codex
|
||||
|
||||
# 3. Start OpenClaw
|
||||
openclaw gateway
|
||||
```
|
||||
|
||||
That's it! The plugin will automatically start capturing and recalling memories.
|
||||
|
||||
`llmApiKey` is marked sensitive — `openclaw config set ... --ref-source env` writes a
|
||||
SecretRef that resolves the value from your `OPENAI_API_KEY` environment variable at
|
||||
runtime, so the key is never stored in plaintext on disk. `--ref-source file` and
|
||||
`--ref-source exec` are also supported for mounted-secret and Vault-style setups.
|
||||
|
||||
## Migrating from 0.5.x
|
||||
|
||||
0.6.0 removes all process-environment reads from the plugin. Configuration that
|
||||
previously came from shell env vars must now go through OpenClaw's plugin config
|
||||
(with SecretRef for credentials). Concrete mappings:
|
||||
|
||||
| Old (0.5.x) | New (0.6.0) |
|
||||
|---|---|
|
||||
| `OPENAI_API_KEY=…` (auto-detected) | `openclaw config set plugins.entries.hindsight-openclaw.config.llmProvider openai` <br> `openclaw config set plugins.entries.hindsight-openclaw.config.llmApiKey --ref-source env --ref-id OPENAI_API_KEY` |
|
||||
| `HINDSIGHT_API_LLM_PROVIDER=…` | `openclaw config set plugins.entries.hindsight-openclaw.config.llmProvider …` |
|
||||
| `HINDSIGHT_API_LLM_MODEL=…` | `openclaw config set plugins.entries.hindsight-openclaw.config.llmModel …` |
|
||||
| `HINDSIGHT_API_LLM_API_KEY=…` | `openclaw config set plugins.entries.hindsight-openclaw.config.llmApiKey --ref-source env --ref-id …` |
|
||||
| `HINDSIGHT_API_LLM_BASE_URL=…` | `openclaw config set plugins.entries.hindsight-openclaw.config.llmBaseUrl …` |
|
||||
| `HINDSIGHT_EMBED_API_URL=…` | `openclaw config set plugins.entries.hindsight-openclaw.config.hindsightApiUrl …` |
|
||||
| `HINDSIGHT_EMBED_API_TOKEN=…` | `openclaw config set plugins.entries.hindsight-openclaw.config.hindsightApiToken --ref-source env --ref-id …` |
|
||||
| `HINDSIGHT_BANK_ID=…` | `openclaw config set plugins.entries.hindsight-openclaw.config.bankId …` |
|
||||
| `llmApiKeyEnv: "MY_KEY"` (plugin config) | `llmApiKey` configured as a SecretRef with `--ref-id MY_KEY` |
|
||||
|
||||
If your shell already exports `OPENAI_API_KEY`, the SecretRef config above resolves
|
||||
to the same value at startup — no need to change your shell setup, just point the
|
||||
plugin at the variable explicitly. Run `openclaw config validate` after migrating
|
||||
to confirm the new shape parses cleanly.
|
||||
|
||||
## Features
|
||||
|
||||
- **Auto-capture** and **auto-recall** of memories each turn, injected into system prompt space so recalled memories stay out of the visible chat transcript
|
||||
|
|
@ -43,11 +74,12 @@ Optional settings in `~/.openclaw/openclaw.json` under `plugins.entries.hindsigh
|
|||
| `embedVersion` | `"latest"` | hindsight-embed version |
|
||||
| `embedPackagePath` | — | Local path to `hindsight-embed` package for development |
|
||||
| `bankMission` | — | Agent identity/purpose stored on the memory bank. Helps the engine understand context for better fact extraction. Set once per bank — not a recall prompt. |
|
||||
| `llmProvider` | auto-detect | LLM provider override for memory extraction (`openai`, `anthropic`, `gemini`, `groq`, `ollama`, `openai-codex`, `claude-code`) |
|
||||
| `llmModel` | provider default | LLM model override used with `llmProvider` |
|
||||
| `llmApiKeyEnv` | provider standard env var | Custom env var name for the provider API key |
|
||||
| `llmProvider` | — | LLM provider for memory extraction (`openai`, `anthropic`, `gemini`, `groq`, `ollama`, `openai-codex`, `claude-code`). Required unless `hindsightApiUrl` is set. |
|
||||
| `llmModel` | provider default | LLM model used with `llmProvider` |
|
||||
| `llmApiKey` | — | API key for the LLM provider. **Sensitive** — set via `openclaw config set ... --ref-source env --ref-id OPENAI_API_KEY` to reference an env var (or `--ref-source file`/`exec` for mounted-secret/Vault sources). |
|
||||
| `llmBaseUrl` | — | Optional base URL override for OpenAI-compatible providers (e.g. `https://openrouter.ai/api/v1`) |
|
||||
| `dynamicBankId` | `true` | Enable per-context memory banks |
|
||||
| `bankId` | — | Static bank ID used when `dynamicBankId` is `false`. Can also be set with `HINDSIGHT_BANK_ID`. |
|
||||
| `bankId` | — | Static bank ID used when `dynamicBankId` is `false`. |
|
||||
| `bankIdPrefix` | — | Prefix for bank IDs (e.g. `"prod"`) |
|
||||
| `retainTags` | `[]` | Tags applied to every retained document, useful for cross-agent/source labeling (e.g. `source_system:openclaw`, `agent:agentname`) |
|
||||
| `retainSource` | `"openclaw"` | `source` value written into retained document metadata |
|
||||
|
|
@ -67,7 +99,7 @@ Optional settings in `~/.openclaw/openclaw.json` under `plugins.entries.hindsigh
|
|||
| `recallMaxQueryChars` | `800` | Maximum character length for the composed recall query before calling recall. |
|
||||
| `recallPromptPreamble` | built-in string | Prompt text placed above recalled memories in the injected `<hindsight_memories>` system-context block. |
|
||||
| `hindsightApiUrl` | — | External Hindsight API URL (skips local daemon) |
|
||||
| `hindsightApiToken` | — | Auth token for external API |
|
||||
| `hindsightApiToken` | — | Auth token for external API. **Sensitive** — set via `openclaw config set ... --ref-source env --ref-id HINDSIGHT_API_TOKEN`. |
|
||||
| `ignoreSessionPatterns` | `[]` | Session key glob patterns to skip entirely — no recall, no retain (e.g. `["agent:*:cron:**"]`) |
|
||||
| `statelessSessionPatterns` | `[]` | Session key glob patterns for read-only sessions — retain is always skipped; recall is skipped when `skipStatelessSessions` is `true` (e.g. `["agent:*:subagent:**", "agent:*:heartbeat:**"]`) |
|
||||
| `skipStatelessSessions` | `true` | When `true`, sessions matching `statelessSessionPatterns` also skip recall. Set to `false` to allow recall but still skip retain. |
|
||||
|
|
|
|||
|
|
@ -2,6 +2,14 @@
|
|||
"id": "hindsight-openclaw",
|
||||
"name": "Hindsight Memory",
|
||||
"kind": "memory",
|
||||
"configContracts": {
|
||||
"secretInputs": {
|
||||
"paths": [
|
||||
{ "path": "llmApiKey", "expected": "string" },
|
||||
{ "path": "hindsightApiToken", "expected": "string" }
|
||||
]
|
||||
}
|
||||
},
|
||||
"configSchema": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
|
@ -27,7 +35,7 @@
|
|||
},
|
||||
"llmProvider": {
|
||||
"type": "string",
|
||||
"description": "LLM provider for Hindsight memory (e.g. 'openai', 'anthropic', 'gemini', 'groq', 'ollama', 'openai-codex', 'claude-code'). Takes priority over auto-detection but not over HINDSIGHT_API_LLM_PROVIDER env var.",
|
||||
"description": "LLM provider for Hindsight memory (e.g. 'openai', 'anthropic', 'gemini', 'groq', 'ollama', 'openai-codex', 'claude-code').",
|
||||
"enum": [
|
||||
"openai",
|
||||
"anthropic",
|
||||
|
|
@ -42,9 +50,13 @@
|
|||
"type": "string",
|
||||
"description": "LLM model to use (e.g. 'gpt-4o-mini', 'claude-3-5-haiku-20241022'). Used with llmProvider."
|
||||
},
|
||||
"llmApiKeyEnv": {
|
||||
"llmApiKey": {
|
||||
"type": ["string", "object"],
|
||||
"description": "API key for the LLM provider used by the Hindsight memory daemon. Set via 'openclaw config set ... --ref-source env --ref-id OPENAI_API_KEY' to reference an env var without storing plaintext."
|
||||
},
|
||||
"llmBaseUrl": {
|
||||
"type": "string",
|
||||
"description": "Name of the env var holding the API key (e.g. 'MY_CUSTOM_KEY'). If not set, uses the standard env var for the chosen provider."
|
||||
"description": "Optional base URL override for OpenAI-compatible providers (e.g. 'https://openrouter.ai/api/v1')."
|
||||
},
|
||||
"embedPackagePath": {
|
||||
"type": "string",
|
||||
|
|
@ -60,7 +72,7 @@
|
|||
"description": "External Hindsight API URL (e.g. 'https://mcp.hindsight.devcraft.team'). When set, skips local daemon and connects directly to this API."
|
||||
},
|
||||
"hindsightApiToken": {
|
||||
"type": "string",
|
||||
"type": ["string", "object"],
|
||||
"description": "API token for external Hindsight API authentication. Required if the external API has authentication enabled."
|
||||
},
|
||||
"dynamicBankId": {
|
||||
|
|
@ -70,7 +82,7 @@
|
|||
},
|
||||
"bankId": {
|
||||
"type": "string",
|
||||
"description": "Static bank ID used when dynamicBankId is false. Can also be provided via HINDSIGHT_BANK_ID."
|
||||
"description": "Static bank ID used when dynamicBankId is false."
|
||||
},
|
||||
"bankIdPrefix": {
|
||||
"type": "string",
|
||||
|
|
@ -290,9 +302,14 @@
|
|||
"label": "LLM Model",
|
||||
"placeholder": "e.g. gpt-4o-mini, claude-3-5-haiku-20241022"
|
||||
},
|
||||
"llmApiKeyEnv": {
|
||||
"label": "API Key Env Var",
|
||||
"placeholder": "e.g. MY_CUSTOM_API_KEY (optional)"
|
||||
"llmApiKey": {
|
||||
"label": "LLM API Key",
|
||||
"placeholder": "API key for the chosen LLM provider",
|
||||
"sensitive": true
|
||||
},
|
||||
"llmBaseUrl": {
|
||||
"label": "LLM Base URL",
|
||||
"placeholder": "e.g. https://openrouter.ai/api/v1 (optional)"
|
||||
},
|
||||
"embedPackagePath": {
|
||||
"label": "Local Package Path (Dev)",
|
||||
|
|
@ -308,7 +325,8 @@
|
|||
},
|
||||
"hindsightApiToken": {
|
||||
"label": "External API Token",
|
||||
"placeholder": "API token if external API requires authentication"
|
||||
"placeholder": "API token if external API requires authentication",
|
||||
"sensitive": true
|
||||
},
|
||||
"dynamicBankId": {
|
||||
"label": "Dynamic Bank IDs",
|
||||
|
|
|
|||
|
|
@ -44,8 +44,8 @@
|
|||
"prepublishOnly": "npm run clean && npm run build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@vectorize-io/hindsight-client": "file:../../hindsight-clients/typescript",
|
||||
"@vectorize-io/hindsight-all": "file:../../hindsight-all-npm"
|
||||
"@vectorize-io/hindsight-client": "^0.5.0",
|
||||
"@vectorize-io/hindsight-all": "^0.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^20.0.0",
|
||||
|
|
|
|||
|
|
@ -173,12 +173,9 @@ function parseArgs(argv: string[]): ParsedArgs {
|
|||
|
||||
function inferApiSettings(pluginConfig: PluginConfig, explicitApiUrl?: string, explicitApiToken?: string): { apiUrl: string; apiToken?: string } {
|
||||
const apiUrl = explicitApiUrl
|
||||
|| process.env.HINDSIGHT_EMBED_API_URL
|
||||
|| pluginConfig.hindsightApiUrl
|
||||
|| `http://127.0.0.1:${pluginConfig.apiPort || 9077}`;
|
||||
const apiToken = explicitApiToken
|
||||
|| process.env.HINDSIGHT_EMBED_API_TOKEN
|
||||
|| pluginConfig.hindsightApiToken;
|
||||
const apiToken = explicitApiToken || pluginConfig.hindsightApiToken;
|
||||
return { apiUrl, apiToken: apiToken || undefined };
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -245,12 +245,6 @@ async function lazyReinit(configOverride?: PluginConfig): Promise<void> {
|
|||
try {
|
||||
await checkExternalApiHealth(externalApi.apiUrl, externalApi.apiToken);
|
||||
|
||||
// Health check passed — set up env vars and create client
|
||||
process.env.HINDSIGHT_EMBED_API_URL = externalApi.apiUrl;
|
||||
if (externalApi.apiToken) {
|
||||
process.env.HINDSIGHT_EMBED_API_TOKEN = externalApi.apiToken;
|
||||
}
|
||||
|
||||
const llmConfig = detectLLMConfig(config);
|
||||
clientOptions = buildClientOptions(llmConfig, config, externalApi);
|
||||
banksWithMissionSet.clear();
|
||||
|
|
@ -667,16 +661,8 @@ export function formatMemories(results: MemoryResult[]): string {
|
|||
}
|
||||
|
||||
|
||||
// Provider detection from standard env vars
|
||||
const PROVIDER_DETECTION = [
|
||||
{ name: 'openai', keyEnv: 'OPENAI_API_KEY' },
|
||||
{ name: 'anthropic', keyEnv: 'ANTHROPIC_API_KEY' },
|
||||
{ name: 'gemini', keyEnv: 'GEMINI_API_KEY' },
|
||||
{ name: 'groq', keyEnv: 'GROQ_API_KEY' },
|
||||
{ name: 'ollama', keyEnv: '' },
|
||||
{ name: 'openai-codex', keyEnv: '' },
|
||||
{ name: 'claude-code', keyEnv: '' },
|
||||
];
|
||||
// Providers that authenticate via OAuth or run locally — no API key needed.
|
||||
const NO_KEY_REQUIRED_PROVIDERS = new Set(['ollama', 'openai-codex', 'claude-code']);
|
||||
|
||||
export function detectLLMConfig(pluginConfig?: PluginConfig): {
|
||||
provider?: string;
|
||||
|
|
@ -685,88 +671,7 @@ export function detectLLMConfig(pluginConfig?: PluginConfig): {
|
|||
baseUrl?: string;
|
||||
source: string;
|
||||
} {
|
||||
// Override values from HINDSIGHT_API_LLM_* env vars (highest priority)
|
||||
const overrideProvider = process.env.HINDSIGHT_API_LLM_PROVIDER;
|
||||
const overrideModel = process.env.HINDSIGHT_API_LLM_MODEL;
|
||||
const overrideKey = process.env.HINDSIGHT_API_LLM_API_KEY;
|
||||
const overrideBaseUrl = process.env.HINDSIGHT_API_LLM_BASE_URL;
|
||||
|
||||
// Priority 1: If provider is explicitly set via env var, use that
|
||||
if (overrideProvider) {
|
||||
// Providers that don't require an API key (use OAuth or local models)
|
||||
const noKeyRequired = ['ollama', 'openai-codex', 'claude-code'];
|
||||
if (!overrideKey && !noKeyRequired.includes(overrideProvider)) {
|
||||
throw new Error(
|
||||
`HINDSIGHT_API_LLM_PROVIDER is set to "${overrideProvider}" but HINDSIGHT_API_LLM_API_KEY is not set.\n` +
|
||||
`Please set: export HINDSIGHT_API_LLM_API_KEY=your-api-key`
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
provider: overrideProvider,
|
||||
apiKey: overrideKey || '',
|
||||
model: overrideModel,
|
||||
baseUrl: overrideBaseUrl,
|
||||
source: 'HINDSIGHT_API_LLM_PROVIDER override',
|
||||
};
|
||||
}
|
||||
|
||||
// Priority 2: Plugin config llmProvider/llmModel
|
||||
if (pluginConfig?.llmProvider) {
|
||||
const providerInfo = PROVIDER_DETECTION.find(p => p.name === pluginConfig.llmProvider);
|
||||
|
||||
// Resolve API key: llmApiKeyEnv > provider's standard keyEnv
|
||||
let apiKey = '';
|
||||
if (pluginConfig.llmApiKeyEnv) {
|
||||
apiKey = process.env[pluginConfig.llmApiKeyEnv] || '';
|
||||
} else if (providerInfo?.keyEnv) {
|
||||
apiKey = process.env[providerInfo.keyEnv] || '';
|
||||
}
|
||||
|
||||
// Providers that don't require an API key (use OAuth or local models)
|
||||
const noKeyRequired = ['ollama', 'openai-codex', 'claude-code'];
|
||||
if (!apiKey && !noKeyRequired.includes(pluginConfig.llmProvider)) {
|
||||
const keySource = pluginConfig.llmApiKeyEnv || providerInfo?.keyEnv || 'unknown';
|
||||
throw new Error(
|
||||
`Plugin config llmProvider is set to "${pluginConfig.llmProvider}" but no API key found.\n` +
|
||||
`Expected env var: ${keySource}\n` +
|
||||
`Set the env var or use llmApiKeyEnv in plugin config to specify a custom env var name.`
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
provider: pluginConfig.llmProvider,
|
||||
apiKey,
|
||||
model: pluginConfig.llmModel || overrideModel,
|
||||
baseUrl: overrideBaseUrl,
|
||||
source: 'plugin config',
|
||||
};
|
||||
}
|
||||
|
||||
// Priority 3: Auto-detect from standard provider env vars
|
||||
for (const providerInfo of PROVIDER_DETECTION) {
|
||||
const apiKey = providerInfo.keyEnv ? process.env[providerInfo.keyEnv] : '';
|
||||
|
||||
// Skip providers that don't use API keys in auto-detection (must be explicitly requested)
|
||||
const noKeyRequired = ['ollama', 'openai-codex', 'claude-code'];
|
||||
if (noKeyRequired.includes(providerInfo.name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (apiKey) {
|
||||
return {
|
||||
provider: providerInfo.name,
|
||||
apiKey,
|
||||
model: overrideModel,
|
||||
baseUrl: overrideBaseUrl,
|
||||
source: `auto-detected from ${providerInfo.keyEnv}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// No configuration found - show helpful error
|
||||
|
||||
// Allow empty LLM config if using external Hindsight API (server handles LLM)
|
||||
// External API mode: the daemon handles LLM credentials, plugin doesn't need them.
|
||||
const externalApiCheck = detectExternalApi(pluginConfig);
|
||||
if (externalApiCheck.apiUrl) {
|
||||
return {
|
||||
|
|
@ -778,37 +683,51 @@ export function detectLLMConfig(pluginConfig?: PluginConfig): {
|
|||
};
|
||||
}
|
||||
|
||||
const provider = pluginConfig?.llmProvider;
|
||||
if (!provider) {
|
||||
throw new Error(
|
||||
`No LLM configuration found for Hindsight memory plugin.\n\n` +
|
||||
`Option 1: Set a standard provider API key (auto-detect):\n` +
|
||||
` export OPENAI_API_KEY=sk-your-key\n` +
|
||||
` export ANTHROPIC_API_KEY=your-key\n` +
|
||||
` export GEMINI_API_KEY=your-key\n` +
|
||||
` export GROQ_API_KEY=your-key\n\n` +
|
||||
`Option 2: Use Codex or Claude Code (no API key needed):\n` +
|
||||
` export HINDSIGHT_API_LLM_PROVIDER=openai-codex # Requires 'codex auth login'\n` +
|
||||
` export HINDSIGHT_API_LLM_PROVIDER=claude-code # Requires Claude Code CLI\n\n` +
|
||||
`Option 3: Set llmProvider in openclaw.json plugin config:\n` +
|
||||
` "llmProvider": "openai"\n\n` +
|
||||
`Option 4: Override with Hindsight-specific env vars:\n` +
|
||||
` export HINDSIGHT_API_LLM_PROVIDER=openai\n` +
|
||||
` export HINDSIGHT_API_LLM_API_KEY=sk-your-key\n` +
|
||||
` export HINDSIGHT_API_LLM_BASE_URL=https://openrouter.ai/api/v1 # Optional\n\n` +
|
||||
`The model will be selected automatically by Hindsight. To override: export HINDSIGHT_API_LLM_MODEL=your-model`
|
||||
`No LLM provider configured for the Hindsight memory plugin.\n\n` +
|
||||
`Set the provider via 'openclaw config set':\n` +
|
||||
` openclaw config set plugins.entries.hindsight-openclaw.config.llmProvider openai\n\n` +
|
||||
`For providers that need an API key, configure it as a SecretRef so the value\n` +
|
||||
`is read from an env var (or file/exec source) at runtime instead of stored in plain text:\n` +
|
||||
` openclaw config set plugins.entries.hindsight-openclaw.config.llmApiKey \\\n` +
|
||||
` --ref-source env --ref-provider default --ref-id OPENAI_API_KEY\n\n` +
|
||||
`Providers that don't need an API key: ${[...NO_KEY_REQUIRED_PROVIDERS].join(', ')}.\n` +
|
||||
`Or point the plugin at an external Hindsight API by setting hindsightApiUrl instead.`
|
||||
);
|
||||
}
|
||||
|
||||
const apiKey = pluginConfig?.llmApiKey ?? '';
|
||||
if (!apiKey && !NO_KEY_REQUIRED_PROVIDERS.has(provider)) {
|
||||
throw new Error(
|
||||
`llmProvider is set to "${provider}" but llmApiKey is empty.\n\n` +
|
||||
`Configure it via 'openclaw config set' as a SecretRef:\n` +
|
||||
` openclaw config set plugins.entries.hindsight-openclaw.config.llmApiKey \\\n` +
|
||||
` --ref-source env --ref-provider default --ref-id OPENAI_API_KEY`
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
provider,
|
||||
apiKey,
|
||||
model: pluginConfig?.llmModel,
|
||||
baseUrl: pluginConfig?.llmBaseUrl,
|
||||
source: 'plugin config',
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect external Hindsight API configuration.
|
||||
* Priority: env vars > plugin config
|
||||
* Detect external Hindsight API configuration from plugin config.
|
||||
*/
|
||||
export function detectExternalApi(pluginConfig?: PluginConfig): {
|
||||
apiUrl: string | null;
|
||||
apiToken: string | null;
|
||||
} {
|
||||
const apiUrl = process.env.HINDSIGHT_EMBED_API_URL || pluginConfig?.hindsightApiUrl || null;
|
||||
const apiToken = process.env.HINDSIGHT_EMBED_API_TOKEN || pluginConfig?.hindsightApiToken || null;
|
||||
return { apiUrl, apiToken };
|
||||
return {
|
||||
apiUrl: pluginConfig?.hindsightApiUrl ?? null,
|
||||
apiToken: pluginConfig?.hindsightApiToken ?? null,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -867,9 +786,6 @@ async function checkExternalApiHealth(apiUrl: string, apiToken?: string | null):
|
|||
function getPluginConfig(api: MoltbotPluginAPI): PluginConfig {
|
||||
const config = api.config.plugins?.entries?.['hindsight-openclaw']?.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.';
|
||||
const envBankId = typeof process.env.HINDSIGHT_BANK_ID === 'string' && process.env.HINDSIGHT_BANK_ID.trim().length > 0
|
||||
? process.env.HINDSIGHT_BANK_ID.trim()
|
||||
: undefined;
|
||||
|
||||
return {
|
||||
bankMission: config.bankMission || defaultMission,
|
||||
|
|
@ -879,13 +795,14 @@ function getPluginConfig(api: MoltbotPluginAPI): PluginConfig {
|
|||
embedPackagePath: config.embedPackagePath,
|
||||
llmProvider: config.llmProvider,
|
||||
llmModel: config.llmModel,
|
||||
llmApiKeyEnv: config.llmApiKeyEnv,
|
||||
llmApiKey: config.llmApiKey,
|
||||
llmBaseUrl: config.llmBaseUrl,
|
||||
hindsightApiUrl: config.hindsightApiUrl,
|
||||
hindsightApiToken: config.hindsightApiToken,
|
||||
apiPort: config.apiPort || 9077,
|
||||
// Dynamic bank ID options (default: enabled)
|
||||
dynamicBankId: config.dynamicBankId !== false,
|
||||
bankId: envBankId || (typeof config.bankId === 'string' && config.bankId.trim().length > 0 ? config.bankId.trim() : undefined),
|
||||
bankId: typeof config.bankId === 'string' && config.bankId.trim().length > 0 ? config.bankId.trim() : undefined,
|
||||
bankIdPrefix: config.bankIdPrefix,
|
||||
retainTags: Array.isArray(config.retainTags) ? config.retainTags.filter((tag): tag is string => typeof tag === 'string') : undefined,
|
||||
retainSource: typeof config.retainSource === 'string' && config.retainSource.trim().length > 0 ? config.retainSource.trim() : undefined,
|
||||
|
|
@ -1013,10 +930,7 @@ export default function (api: MoltbotPluginAPI) {
|
|||
log.warn(`could not initialize retain queue: ${error}`);
|
||||
}
|
||||
|
||||
// Set env vars so CLI commands (uvx hindsight-embed) use external API
|
||||
process.env.HINDSIGHT_EMBED_API_URL = externalApi.apiUrl;
|
||||
if (externalApi.apiToken) {
|
||||
process.env.HINDSIGHT_EMBED_API_TOKEN = externalApi.apiToken;
|
||||
debug('[Hindsight] API token configured');
|
||||
}
|
||||
} else {
|
||||
|
|
@ -1176,10 +1090,6 @@ export default function (api: MoltbotPluginAPI) {
|
|||
if (externalApi.apiUrl) {
|
||||
// External API mode
|
||||
usingExternalApi = true;
|
||||
process.env.HINDSIGHT_EMBED_API_URL = externalApi.apiUrl;
|
||||
if (externalApi.apiToken) {
|
||||
process.env.HINDSIGHT_EMBED_API_TOKEN = externalApi.apiToken;
|
||||
}
|
||||
|
||||
await checkExternalApiHealth(externalApi.apiUrl, externalApi.apiToken);
|
||||
|
||||
|
|
|
|||
|
|
@ -55,14 +55,15 @@ export interface PluginConfig {
|
|||
daemonIdleTimeout?: number; // Seconds before daemon shuts down (0 = never)
|
||||
embedVersion?: string; // hindsight-embed version (default: "latest")
|
||||
embedPackagePath?: string; // Local path to hindsight package (e.g. '/path/to/hindsight')
|
||||
llmProvider?: string; // LLM provider override (e.g. 'openai', 'anthropic', 'gemini', 'groq', 'ollama')
|
||||
llmModel?: string; // LLM model override (e.g. 'gpt-4o-mini', 'claude-3-5-haiku-20241022')
|
||||
llmApiKeyEnv?: string; // Env var name holding the API key (e.g. 'MY_CUSTOM_KEY')
|
||||
llmProvider?: string; // LLM provider (e.g. 'openai', 'anthropic', 'gemini', 'groq', 'ollama', 'openai-codex', 'claude-code')
|
||||
llmModel?: string; // LLM model (e.g. 'gpt-4o-mini', 'claude-3-5-haiku-20241022')
|
||||
llmApiKey?: string; // LLM provider API key. Configure via SecretRef: openclaw config set ... --ref-source env --ref-id OPENAI_API_KEY
|
||||
llmBaseUrl?: string; // Optional base URL override for OpenAI-compatible providers (e.g. OpenRouter)
|
||||
apiPort?: number; // Port for openclaw profile daemon (default: 9077)
|
||||
hindsightApiUrl?: string; // External Hindsight API URL (skips local daemon when set)
|
||||
hindsightApiToken?: string; // API token for external Hindsight API authentication
|
||||
hindsightApiToken?: string; // API token for external Hindsight API. Configure via SecretRef.
|
||||
dynamicBankId?: boolean; // Enable per-channel memory banks (default: true)
|
||||
bankId?: string; // Static bank ID used when dynamicBankId is false. Can also be set via HINDSIGHT_BANK_ID.
|
||||
bankId?: string; // Static bank ID used when dynamicBankId is false.
|
||||
bankIdPrefix?: string; // Prefix for bank IDs (e.g. 'prod' -> 'prod-slack-C123')
|
||||
retainTags?: string[]; // Tags applied to all retained documents (e.g. ['source_system:openclaw', 'agent:agentname'])
|
||||
retainSource?: string; // Source written into retained document metadata (default: 'openclaw')
|
||||
|
|
|
|||
|
|
@ -148,18 +148,15 @@ beforeAll(async () => {
|
|||
// Reset module registry so we get a fresh module with clean state.
|
||||
vi.resetModules();
|
||||
|
||||
// Provide LLM config — used by plugin init even in HTTP mode.
|
||||
process.env.HINDSIGHT_API_LLM_PROVIDER = 'openai';
|
||||
process.env.HINDSIGHT_API_LLM_API_KEY = 'test-key-hooks';
|
||||
// Point the plugin at the running test API.
|
||||
process.env.HINDSIGHT_EMBED_API_URL = HINDSIGHT_API_URL;
|
||||
|
||||
const mod = await import('../src/index.js');
|
||||
const { HindsightClient } = await import('@vectorize-io/hindsight-client');
|
||||
const pluginFn = mod.default;
|
||||
const getClient = mod.getClient;
|
||||
|
||||
// Plugin runs in external API mode (talks to the running test API), so no LLM
|
||||
// credentials are needed in the plugin config — the daemon handles them.
|
||||
const handle = createMockApi({
|
||||
hindsightApiUrl: HINDSIGHT_API_URL,
|
||||
dynamicBankId: true,
|
||||
excludeProviders: ['slack'],
|
||||
retainEveryNTurns: 1, // retain every turn so individual tests aren't affected by chunking
|
||||
|
|
@ -188,9 +185,6 @@ beforeAll(async () => {
|
|||
|
||||
afterAll(async () => {
|
||||
vi.restoreAllMocks();
|
||||
delete process.env.HINDSIGHT_API_LLM_PROVIDER;
|
||||
delete process.env.HINDSIGHT_API_LLM_API_KEY;
|
||||
delete process.env.HINDSIGHT_EMBED_API_URL;
|
||||
if (stopServicesFn) await stopServicesFn().catch(() => {});
|
||||
}, 15_000);
|
||||
|
||||
|
|
|
|||
|
|
@ -8,6 +8,21 @@ import PageHero from '@site/src/components/PageHero';
|
|||
|
||||
← OpenClaw integration
|
||||
|
||||
## 0.6.0 (Unreleased)
|
||||
|
||||
**Breaking Changes**
|
||||
|
||||
- The plugin no longer reads any configuration from process environment variables. All settings — including the LLM provider, model, API key, base URL, external Hindsight API URL/token, and bank ID — must now be set through OpenClaw's plugin config (e.g. `openclaw config set plugins.entries.hindsight-openclaw.config.<field> <value>`). API keys and other secrets should be configured as `SecretRef` values via `--ref-source env|file|exec` so they're resolved from your secret store at runtime instead of being stored in plaintext on disk.
|
||||
- Removed the `llmApiKeyEnv` plugin config field. Use the new `llmApiKey` field configured as a SecretRef instead (e.g. `openclaw config set plugins.entries.hindsight-openclaw.config.llmApiKey --ref-source env --ref-id OPENAI_API_KEY`).
|
||||
- Removed automatic LLM provider detection from `OPENAI_API_KEY` / `ANTHROPIC_API_KEY` / `GEMINI_API_KEY` / `GROQ_API_KEY`. Set `llmProvider` and `llmApiKey` explicitly via `openclaw config set`.
|
||||
- Removed support for the `HINDSIGHT_API_LLM_PROVIDER`, `HINDSIGHT_API_LLM_MODEL`, `HINDSIGHT_API_LLM_API_KEY`, `HINDSIGHT_API_LLM_BASE_URL`, `HINDSIGHT_EMBED_API_URL`, `HINDSIGHT_EMBED_API_TOKEN`, and `HINDSIGHT_BANK_ID` environment variables. The same values now live in plugin config — see the migration guide.
|
||||
|
||||
**Features**
|
||||
|
||||
- Added the `llmApiKey` plugin config field, marked as a sensitive field so OpenClaw resolves it as a `SecretRef` from env, file, or exec sources.
|
||||
- Added the `llmBaseUrl` plugin config field for OpenAI-compatible endpoint overrides (OpenRouter, Azure OpenAI, vLLM, etc.).
|
||||
- Marked `hindsightApiToken` as a sensitive field — it can now be configured as a `SecretRef` the same way as `llmApiKey`.
|
||||
|
||||
## [0.5.1](https://github.com/vectorize-io/hindsight/tree/integrations/openclaw/v0.5.1)
|
||||
|
||||
**Bug Fixes**
|
||||
|
|
|
|||
Loading…
Reference in a new issue