Compare commits
5
Commits
iss
..
versioning
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6c84e33100 | ||
|
|
45aa8b1e93 | ||
|
|
fccbdfef16 | ||
|
|
20f2b92069 | ||
|
|
1bf90358c3 |
+2
-1
@@ -50,4 +50,5 @@ hindsight-clients/rust/target
|
||||
.claude
|
||||
whats-next.md
|
||||
TASK.md
|
||||
CHANGELOG.md
|
||||
# Changelog is now tracked in hindsight-docs/src/pages/changelog.md
|
||||
# CHANGELOG.md
|
||||
@@ -1323,7 +1323,7 @@ class VersionResponse(BaseModel):
|
||||
model_config = ConfigDict(
|
||||
json_schema_extra={
|
||||
"example": {
|
||||
"api_version": "1.0.0",
|
||||
"api_version": "0.4.0",
|
||||
"features": {
|
||||
"observations": False,
|
||||
"mcp": True,
|
||||
@@ -1567,11 +1567,12 @@ def _register_routes(app: FastAPI):
|
||||
Returns version info and feature flags that can be used by clients
|
||||
to determine which capabilities are available.
|
||||
"""
|
||||
from hindsight_api import __version__
|
||||
from hindsight_api.config import get_config
|
||||
|
||||
config = get_config()
|
||||
return VersionResponse(
|
||||
api_version="1.0.0",
|
||||
api_version=__version__,
|
||||
features=FeaturesInfo(
|
||||
observations=config.enable_observations,
|
||||
mcp=config.mcp_enabled,
|
||||
|
||||
@@ -137,26 +137,15 @@ class LocalSTCrossEncoder(CrossEncoderModel):
|
||||
# which can cause issues when accelerate is installed but no GPU is available.
|
||||
# Note: We do NOT use device_map because CrossEncoder internally calls .to(device)
|
||||
# after loading, which conflicts with accelerate's device_map handling.
|
||||
import os
|
||||
|
||||
import torch
|
||||
|
||||
# Force CPU mode if HINDSIGHT_FORCE_CPU is set (used in daemon mode to avoid MPS/XPC issues)
|
||||
force_cpu = os.getenv("HINDSIGHT_FORCE_CPU", "0") == "1"
|
||||
# Check for GPU (CUDA) or Apple Silicon (MPS)
|
||||
has_gpu = torch.cuda.is_available() or (hasattr(torch.backends, "mps") and torch.backends.mps.is_available())
|
||||
|
||||
if force_cpu:
|
||||
device = "cpu"
|
||||
logger.info("Reranker: forcing CPU mode (HINDSIGHT_FORCE_CPU=1)")
|
||||
if has_gpu:
|
||||
device = None # Let sentence-transformers auto-detect GPU/MPS
|
||||
else:
|
||||
# Check for GPU (CUDA) or Apple Silicon (MPS)
|
||||
has_gpu = torch.cuda.is_available() or (
|
||||
hasattr(torch.backends, "mps") and torch.backends.mps.is_available()
|
||||
)
|
||||
|
||||
if has_gpu:
|
||||
device = None # Let sentence-transformers auto-detect GPU/MPS
|
||||
else:
|
||||
device = "cpu"
|
||||
device = "cpu"
|
||||
|
||||
self._model = CrossEncoder(
|
||||
self.model_name,
|
||||
@@ -222,21 +211,12 @@ class LocalSTCrossEncoder(CrossEncoderModel):
|
||||
)
|
||||
|
||||
# Determine device based on hardware availability
|
||||
import os
|
||||
has_gpu = torch.cuda.is_available() or (hasattr(torch.backends, "mps") and torch.backends.mps.is_available())
|
||||
|
||||
force_cpu = os.getenv("HINDSIGHT_FORCE_CPU", "0") == "1"
|
||||
|
||||
if force_cpu:
|
||||
device = "cpu"
|
||||
if has_gpu:
|
||||
device = None # Let sentence-transformers auto-detect GPU/MPS
|
||||
else:
|
||||
has_gpu = torch.cuda.is_available() or (
|
||||
hasattr(torch.backends, "mps") and torch.backends.mps.is_available()
|
||||
)
|
||||
|
||||
if has_gpu:
|
||||
device = None # Let sentence-transformers auto-detect GPU/MPS
|
||||
else:
|
||||
device = "cpu"
|
||||
device = "cpu"
|
||||
|
||||
self._model = CrossEncoder(
|
||||
self.model_name,
|
||||
|
||||
@@ -132,26 +132,15 @@ class LocalSTEmbeddings(Embeddings):
|
||||
# Determine device based on hardware availability.
|
||||
# We always set low_cpu_mem_usage=False to prevent lazy loading (meta tensors)
|
||||
# which can cause issues when accelerate is installed but no GPU is available.
|
||||
import os
|
||||
|
||||
import torch
|
||||
|
||||
# Force CPU mode if HINDSIGHT_FORCE_CPU is set (used in daemon mode to avoid MPS/XPC issues)
|
||||
force_cpu = os.getenv("HINDSIGHT_FORCE_CPU", "0") == "1"
|
||||
# Check for GPU (CUDA) or Apple Silicon (MPS)
|
||||
has_gpu = torch.cuda.is_available() or (hasattr(torch.backends, "mps") and torch.backends.mps.is_available())
|
||||
|
||||
if force_cpu:
|
||||
device = "cpu"
|
||||
logger.info("Embeddings: forcing CPU mode (HINDSIGHT_FORCE_CPU=1)")
|
||||
if has_gpu:
|
||||
device = None # Let sentence-transformers auto-detect GPU/MPS
|
||||
else:
|
||||
# Check for GPU (CUDA) or Apple Silicon (MPS)
|
||||
has_gpu = torch.cuda.is_available() or (
|
||||
hasattr(torch.backends, "mps") and torch.backends.mps.is_available()
|
||||
)
|
||||
|
||||
if has_gpu:
|
||||
device = None # Let sentence-transformers auto-detect GPU/MPS
|
||||
else:
|
||||
device = "cpu"
|
||||
device = "cpu"
|
||||
|
||||
self._model = SentenceTransformer(
|
||||
self.model_name,
|
||||
@@ -210,21 +199,12 @@ class LocalSTEmbeddings(Embeddings):
|
||||
)
|
||||
|
||||
# Determine device based on hardware availability
|
||||
import os
|
||||
has_gpu = torch.cuda.is_available() or (hasattr(torch.backends, "mps") and torch.backends.mps.is_available())
|
||||
|
||||
force_cpu = os.getenv("HINDSIGHT_FORCE_CPU", "0") == "1"
|
||||
|
||||
if force_cpu:
|
||||
device = "cpu"
|
||||
if has_gpu:
|
||||
device = None # Let sentence-transformers auto-detect GPU/MPS
|
||||
else:
|
||||
has_gpu = torch.cuda.is_available() or (
|
||||
hasattr(torch.backends, "mps") and torch.backends.mps.is_available()
|
||||
)
|
||||
|
||||
if has_gpu:
|
||||
device = None # Let sentence-transformers auto-detect GPU/MPS
|
||||
else:
|
||||
device = "cpu"
|
||||
device = "cpu"
|
||||
|
||||
self._model = SentenceTransformer(
|
||||
self.model_name,
|
||||
|
||||
@@ -140,12 +140,6 @@ def main():
|
||||
args.port = DEFAULT_DAEMON_PORT
|
||||
args.host = "127.0.0.1" # Only bind to localhost for security
|
||||
|
||||
# Force CPU mode for daemon to avoid macOS MPS/XPC issues
|
||||
# MPS (Metal Performance Shaders) has unstable XPC connections in background processes
|
||||
# that can cause assertion failures and process crashes at the C++ level
|
||||
# (which Python exception handlers cannot catch)
|
||||
os.environ["HINDSIGHT_FORCE_CPU"] = "1"
|
||||
|
||||
# Check if another daemon is already running
|
||||
daemon_lock = DaemonLock()
|
||||
if not daemon_lock.acquire():
|
||||
|
||||
@@ -1063,3 +1063,38 @@ async def test_retain_async_no_usage(api_client):
|
||||
|
||||
# Usage should be None for async operations
|
||||
assert result.get("usage") is None, "Async retain should not include usage"
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_version_endpoint_returns_correct_version(api_client):
|
||||
"""Test that the /version endpoint returns the correct API version.
|
||||
|
||||
The version should match the __version__ defined in hindsight_api.__init__.py
|
||||
and should not be a hardcoded string.
|
||||
"""
|
||||
from hindsight_api import __version__
|
||||
|
||||
# Call the /version endpoint
|
||||
response = await api_client.get("/version")
|
||||
assert response.status_code == 200
|
||||
result = response.json()
|
||||
|
||||
# Verify response structure
|
||||
assert "api_version" in result, "Response should include 'api_version' field"
|
||||
assert "features" in result, "Response should include 'features' field"
|
||||
|
||||
# Verify the version matches the package version
|
||||
assert result["api_version"] == __version__, (
|
||||
f"API version should be {__version__}, got {result['api_version']}"
|
||||
)
|
||||
|
||||
# Verify features field structure
|
||||
features = result["features"]
|
||||
assert "observations" in features
|
||||
assert "mcp" in features
|
||||
assert "worker" in features
|
||||
assert isinstance(features["observations"], bool)
|
||||
assert isinstance(features["mcp"], bool)
|
||||
assert isinstance(features["worker"], bool)
|
||||
|
||||
print(f"Version endpoint returned: api_version={result['api_version']}, features={features}")
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
use std::process::Command;
|
||||
|
||||
#[test]
|
||||
fn test_cli_help() {
|
||||
let output = Command::new("cargo")
|
||||
.args(["run", "--", "--help"])
|
||||
.output()
|
||||
.expect("Failed to execute command");
|
||||
|
||||
assert!(output.status.success());
|
||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||
assert!(stdout.contains("Hindsight CLI"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_cli_version() {
|
||||
let output = Command::new("cargo")
|
||||
.args(["run", "--", "--version"])
|
||||
.output()
|
||||
.expect("Failed to execute command");
|
||||
|
||||
assert!(output.status.success());
|
||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||
assert!(stdout.contains("hindsight"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ui_command_without_config() {
|
||||
// Test that the ui command handles missing config gracefully
|
||||
// Create a temp home directory with no config
|
||||
let temp_dir = std::env::temp_dir().join(format!("hindsight-test-ui-{}", std::process::id()));
|
||||
std::fs::create_dir_all(&temp_dir).expect("Failed to create temp dir");
|
||||
|
||||
let output = Command::new("cargo")
|
||||
.args(["run", "--", "ui"])
|
||||
.env_remove("HINDSIGHT_API_URL")
|
||||
.env_remove("HINDSIGHT_API_KEY")
|
||||
.env("HOME", &temp_dir)
|
||||
.output()
|
||||
.expect("Failed to execute command");
|
||||
|
||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||
let stderr = String::from_utf8_lossy(&output.stderr);
|
||||
|
||||
// Either it fails with a config error or it succeeds if there's a default config
|
||||
// Just verify it doesn't crash unexpectedly
|
||||
assert!(
|
||||
!output.status.success()
|
||||
|| stdout.contains("Launching Hindsight Control Plane UI")
|
||||
|| stderr.contains("Configuration error")
|
||||
|| stderr.contains("HINDSIGHT_API_URL"),
|
||||
"Unexpected output - stdout: {}, stderr: {}",
|
||||
stdout,
|
||||
stderr
|
||||
);
|
||||
|
||||
// Cleanup
|
||||
std::fs::remove_dir_all(&temp_dir).ok();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ui_command_with_config() {
|
||||
// This test is skipped by default since it requires a running control plane
|
||||
// and would block for a long time. The other tests cover the basic functionality.
|
||||
// To run this test manually:
|
||||
// 1. Build the control plane: cd hindsight-control-plane && npm run build
|
||||
// 2. Run: cargo test test_ui_command_with_config -- --ignored
|
||||
|
||||
// Just verify that the ui command accepts the configuration
|
||||
let temp_dir = std::env::temp_dir().join(format!("hindsight-test-ui-valid-{}", std::process::id()));
|
||||
std::fs::create_dir_all(&temp_dir).expect("Failed to create temp dir");
|
||||
|
||||
// Write a minimal config
|
||||
let config_dir = temp_dir.join(".config").join("hindsight");
|
||||
std::fs::create_dir_all(&config_dir).expect("Failed to create config dir");
|
||||
let config_file = config_dir.join("config");
|
||||
std::fs::write(&config_file, "api_url=http://localhost:8888\napi_key=test-key\n")
|
||||
.expect("Failed to write config");
|
||||
|
||||
let output = Command::new("cargo")
|
||||
.args(["run", "--", "ui", "--help"])
|
||||
.env("HOME", &temp_dir)
|
||||
.output()
|
||||
.expect("Failed to execute command");
|
||||
|
||||
// The --help should work regardless
|
||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||
assert!(stdout.contains("Hindsight CLI") || output.status.success());
|
||||
|
||||
// Cleanup
|
||||
std::fs::remove_dir_all(&temp_dir).ok();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_configure_command() {
|
||||
// Test that configure command creates/updates config
|
||||
let temp_dir = std::env::temp_dir().join(format!("hindsight-test-{}", std::process::id()));
|
||||
std::fs::create_dir_all(&temp_dir).expect("Failed to create temp dir");
|
||||
|
||||
let output = Command::new("cargo")
|
||||
.args([
|
||||
"run",
|
||||
"--",
|
||||
"configure",
|
||||
"--api-url",
|
||||
"http://localhost:9999",
|
||||
"--api-key",
|
||||
"test-key-123"
|
||||
])
|
||||
.env("HOME", &temp_dir)
|
||||
.output()
|
||||
.expect("Failed to execute command");
|
||||
|
||||
assert!(
|
||||
output.status.success(),
|
||||
"Configure command failed: {}",
|
||||
String::from_utf8_lossy(&output.stderr)
|
||||
);
|
||||
|
||||
let stdout = String::from_utf8_lossy(&output.stdout);
|
||||
assert!(stdout.contains("Configuration saved") || stdout.contains("success"));
|
||||
|
||||
// Cleanup
|
||||
std::fs::remove_dir_all(&temp_dir).ok();
|
||||
}
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
@@ -489,7 +489,7 @@ class Configuration:
|
||||
return "Python SDK Debug Report:\n"\
|
||||
"OS: {env}\n"\
|
||||
"Python Version: {pyversion}\n"\
|
||||
"Version of the API: 0.1.0\n"\
|
||||
"Version of the API: 0.4.0\n"\
|
||||
"SDK Package Version: 0.0.7".\
|
||||
format(env=sys.platform, pyversion=sys.version)
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
HTTP API for Hindsight
|
||||
|
||||
The version of the OpenAPI document: 0.1.0
|
||||
The version of the OpenAPI document: 0.4.0
|
||||
Generated by OpenAPI Generator (https://openapi-generator.tech)
|
||||
|
||||
Do not edit the class manually.
|
||||
|
||||
@@ -25,7 +25,7 @@ GITHUB_REPO = "vectorize-io/hindsight"
|
||||
GITHUB_RELEASES_URL = f"https://github.com/{GITHUB_REPO}/releases"
|
||||
GITHUB_COMMIT_URL = f"https://github.com/{GITHUB_REPO}/commit"
|
||||
REPO_PATH = Path(__file__).parent.parent.parent
|
||||
CHANGELOG_PATH = REPO_PATH / "hindsight-docs" / "docs" / "changelog" / "index.md"
|
||||
CHANGELOG_PATH = REPO_PATH / "hindsight-docs" / "src" / "pages" / "changelog.md"
|
||||
|
||||
|
||||
class ChangelogEntry(BaseModel):
|
||||
@@ -238,7 +238,7 @@ def read_existing_changelog() -> tuple[str, str]:
|
||||
"""Read existing changelog and split into header and content."""
|
||||
if not CHANGELOG_PATH.exists():
|
||||
header = """---
|
||||
sidebar_position: 1
|
||||
hide_table_of_contents: true
|
||||
---
|
||||
|
||||
# Changelog
|
||||
|
||||
@@ -0,0 +1,284 @@
|
||||
---
|
||||
slug: learning-capabilities
|
||||
title: "Agent memory that learns: observations and mental models"
|
||||
authors: [hindsight]
|
||||
image: /img/reflect-operation.webp
|
||||
hide_table_of_contents: true
|
||||
---
|
||||
|
||||
Today we're releasing Hindsight 0.4.0, which introduces two powerful learning capabilities for AI agents: **Observations** for automatic knowledge consolidation, and **Mental Models** for user-curated summaries.
|
||||
|
||||
<!-- truncate -->
|
||||
|
||||
## Two Levels of Learning
|
||||
|
||||
Hindsight 0.4.0 introduces a hierarchical learning system:
|
||||
|
||||
| Level | What It Is | How It's Created |
|
||||
|-------|------------|------------------|
|
||||
| **Mental Models** | User-curated summaries for common queries | Manually created via API |
|
||||
| **Observations** | Consolidated knowledge from facts | Automatically after retain |
|
||||
|
||||
During `reflect`, the agent checks these in priority order — mental models first (your curated knowledge), then observations (automatic synthesis), then raw facts.
|
||||
|
||||
---
|
||||
|
||||
## Observations: Automatic Knowledge Consolidation
|
||||
|
||||
### Evolution from Entity Summaries and Opinions
|
||||
|
||||
In Hindsight 0.3.0, we had two separate systems for synthesized knowledge:
|
||||
|
||||
- **Entity summaries**: Per-entity summaries synthesized from related facts. Generated automatically for frequently-mentioned entities — if "Alice" appeared in many facts, you'd get a summary like "Alice is a software engineer at Google who joined in 2020 and leads the search team." Objective and entity-scoped.
|
||||
|
||||
- **Opinions**: Beliefs formed during `reflect` operations, influenced by the bank's disposition traits. These captured subjective judgments with confidence scores, like "Python is best for data science" (confidence: 0.85).
|
||||
|
||||
Both systems served their purpose well, but they operated independently. Entity summaries were entity-centric, opinions were belief-centric, and neither captured the full picture of how knowledge evolves over time.
|
||||
|
||||
**Observations** unify these concepts into a single, more expressive system that captures patterns, preferences, and learnings as they emerge from accumulated evidence.
|
||||
|
||||
### What Are Observations?
|
||||
|
||||
Observations are **consolidated knowledge** synthesized from multiple facts. Unlike raw facts which are individual pieces of information, observations represent patterns and insights that emerge from accumulated evidence.
|
||||
|
||||
| Raw Facts | Observation |
|
||||
|-----------|--------------|
|
||||
| "Alice prefers Python" | "Alice is a Python-focused developer who values readability and simplicity, recommends type hints, and prefers pytest for testing" |
|
||||
| "Alice dislikes verbose code" | |
|
||||
| "Alice recommends type hints" | |
|
||||
|
||||
### Automatic Background Consolidation
|
||||
|
||||
After every `retain()` call, Hindsight's consolidation engine runs automatically:
|
||||
|
||||
1. **Analyzes new facts** against existing knowledge
|
||||
2. **Detects patterns** across related information
|
||||
3. **Synthesizes observations** that capture higher-order insights
|
||||
4. **Tracks evidence** linking each observation to its supporting facts
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
A[New Facts] --> B[Consolidation Engine]
|
||||
B --> C{Existing Observation?}
|
||||
C -->|Yes| D[Refine Observation]
|
||||
C -->|No| E[Create Observation]
|
||||
D --> F[Observations]
|
||||
E --> F
|
||||
```
|
||||
|
||||
### Evidence-Based Evolution
|
||||
|
||||
Observations evolve as new evidence arrives, capturing the full journey rather than just the current state:
|
||||
|
||||
| Time | Fact | Observation |
|
||||
|------|------|--------------|
|
||||
| Week 1 | "User loves React" | "User prefers React for frontend development" |
|
||||
| Week 2 | "User praises React's component model" | "User is enthusiastic about React, particularly its component model" |
|
||||
| Week 3 | "User switched to Vue and won't use React anymore" | "User was previously a React enthusiast who appreciated its component model, but has now switched to Vue" |
|
||||
|
||||
Notice how the final observation captures the **full journey** — not just "User prefers Vue" but the complete evolution. Your agent now understands:
|
||||
|
||||
- The user deliberately moved away from React (it wasn't ignorance)
|
||||
- They previously appreciated React's component model (relevant context)
|
||||
- Recommending React tutorials would be inappropriate
|
||||
|
||||
### Mission-Oriented Consolidation
|
||||
|
||||
Observations are influenced by your bank's **mission**. When you set a mission, the consolidation engine focuses on extracting knowledge that serves that purpose:
|
||||
|
||||
```python
|
||||
client.create_bank(
|
||||
bank_id="support-agent",
|
||||
mission="You're a customer support agent - track customer preferences, "
|
||||
"past issues, and communication styles."
|
||||
)
|
||||
```
|
||||
|
||||
With this mission, the engine prioritizes customer-relevant observations while skipping ephemeral details. Without a mission, it performs general-purpose consolidation.
|
||||
|
||||
---
|
||||
|
||||
## Mental Models: User-Curated Knowledge
|
||||
|
||||
While observations are created automatically, **mental models** give you explicit control over how your agent answers common questions.
|
||||
|
||||
### What Are Mental Models?
|
||||
|
||||
Mental models are **saved reflect responses** that you curate for your memory bank. When you create a mental model, Hindsight runs a reflect operation with your source query and stores the result. During future reflect calls, these pre-computed summaries are checked first.
|
||||
|
||||
```mermaid
|
||||
graph LR
|
||||
A[Create Mental Model] --> B[Run Reflect]
|
||||
B --> C[Store Result]
|
||||
C --> D[Future Queries]
|
||||
D --> E{Match Found?}
|
||||
E -->|Yes| F[Return Mental Model]
|
||||
E -->|No| G[Run Full Reflect]
|
||||
```
|
||||
|
||||
### Why Use Mental Models?
|
||||
|
||||
| Benefit | Description |
|
||||
|---------|-------------|
|
||||
| **Consistency** | Same answer every time for common questions |
|
||||
| **Speed** | Pre-computed responses are returned instantly |
|
||||
| **Quality** | Manually curated summaries you've reviewed |
|
||||
| **Control** | Define exactly how key topics should be answered |
|
||||
|
||||
### Two Ways to Use Mental Models
|
||||
|
||||
Mental models work in two ways:
|
||||
|
||||
1. **Automatic via Reflect**: During `reflect` calls, the agent automatically checks mental models first. If a relevant one exists, it's used to inform the response.
|
||||
|
||||
2. **Direct Lookup**: Mental models work like a key-value store — you can retrieve them instantly by ID, bypassing the reflect reasoning loop entirely.
|
||||
|
||||
```python
|
||||
# Direct lookup by ID — instant response, no LLM call
|
||||
mental_model = client.get_mental_model(
|
||||
bank_id="my-bank",
|
||||
mental_model_id="team-communication"
|
||||
)
|
||||
print(mental_model.content) # Pre-computed answer, ready to use
|
||||
```
|
||||
|
||||
This is useful when you know exactly what mental model you need and want the fastest possible response — no LLM reasoning required, just a simple database lookup.
|
||||
|
||||
### Creating Mental Models
|
||||
|
||||
```python
|
||||
# Create a mental model for a common question
|
||||
response = client.create_mental_model(
|
||||
bank_id="my-bank",
|
||||
name="Team Communication Preferences",
|
||||
source_query="How does the team prefer to communicate?",
|
||||
tags=["team"]
|
||||
)
|
||||
```
|
||||
|
||||
### Automatic Refresh
|
||||
|
||||
Mental models can automatically stay in sync with your observations:
|
||||
|
||||
```python
|
||||
# Mental model that refreshes when observations update
|
||||
response = client.create_mental_model(
|
||||
bank_id="my-bank",
|
||||
name="Project Status",
|
||||
source_query="What is the current project status?",
|
||||
trigger={"refresh_after_consolidation": True}
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Directives: Compliance and Guardrails
|
||||
|
||||
In addition to learning capabilities, **directives** provide hard rules that your agent must always follow during reflect operations. Unlike disposition traits which *influence* reasoning style, directives are absolute requirements that are enforced in every response.
|
||||
|
||||
Use directives for compliance, privacy, and safety constraints:
|
||||
- "Never provide medical diagnoses or treatment advice"
|
||||
- "Always respond in formal English"
|
||||
- "Never share personally identifiable information"
|
||||
- "Always cite sources when making factual claims"
|
||||
|
||||
Directives are injected into reflect prompts as hard constraints and are included in the response's `based_on` field. See the [Directives documentation](../developer/api/memory-banks#directives) for how to create and manage them.
|
||||
|
||||
---
|
||||
|
||||
## What Changes from 0.3.0
|
||||
|
||||
### Unified Memory Types
|
||||
|
||||
Opinions and entity summaries are now consolidated into observations:
|
||||
|
||||
```python
|
||||
# 0.3.0 - opinions via types, entity summaries via include_entities
|
||||
response = client.recall(
|
||||
bank_id="my-bank",
|
||||
query="What do you think about Python?",
|
||||
types=["opinion"],
|
||||
include_entities=True # to get entity summaries
|
||||
)
|
||||
|
||||
# 0.4.0 - observations unify both
|
||||
response = client.recall(
|
||||
bank_id="my-bank",
|
||||
query="What do you think about Python?",
|
||||
types=["observation"]
|
||||
)
|
||||
```
|
||||
|
||||
### From Confidence Scores to Evidence Tracking
|
||||
|
||||
Opinions had numeric confidence scores (0.0-1.0). Observations instead track:
|
||||
|
||||
- **Supporting facts**: The evidence behind the observation
|
||||
- **Last updated**: When the observation was last refined
|
||||
- **Freshness**: Whether the observation reflects recent information
|
||||
|
||||
This shift from a single score to evidence tracking means your agent can explain *why* it believes something, not just *how confident* it is.
|
||||
|
||||
### Automatic vs On-Demand
|
||||
|
||||
Entity summaries were created automatically for top entities, but opinions only formed during `reflect`. Observations are always consolidated automatically after `retain`, ensuring knowledge stays current without explicit queries.
|
||||
|
||||
### Background Becomes Mission
|
||||
|
||||
The bank's `background` field has been renamed to `mission`. During the migration, your existing background text is automatically copied to the mission field — no action needed.
|
||||
|
||||
### Agentic Reflect
|
||||
|
||||
The `reflect` operation is now agentic — it reasons more deeply by iteratively retrieving memories and consulting mental models and observations before formulating a response. This makes reflect significantly smarter, especially for complex questions that require synthesizing information across multiple topics.
|
||||
|
||||
The trade-off is that reflect may take longer to respond. For latency-sensitive use cases, consider using `recall` directly when you just need to retrieve facts.
|
||||
|
||||
### Data Migration
|
||||
|
||||
**Important:** When upgrading to 0.4.0, existing opinions and entity summaries will be deleted. The consolidation engine will automatically create new observations from your existing facts. This is a one-time migration — your raw facts are preserved, and observations will be synthesized from them after the upgrade.
|
||||
|
||||
### Migration Checklist
|
||||
|
||||
**If you were using `types=["opinion"]` in recall:**
|
||||
|
||||
1. Update to `types=["observation"]`
|
||||
2. Observations combine both entity-centric summaries and belief-based insights
|
||||
|
||||
**If you were using `include_entities=True` in recall:**
|
||||
|
||||
1. Entity summaries are now included in observations
|
||||
2. Use `types=["observation"]` to retrieve them
|
||||
|
||||
**If you were relying on confidence scores:**
|
||||
|
||||
1. Use the `based_on` field to access supporting evidence
|
||||
2. The number and recency of supporting facts indicates strength
|
||||
|
||||
**If you were setting `background` on banks:**
|
||||
|
||||
1. The field is now called `mission`
|
||||
2. Existing values are migrated automatically
|
||||
|
||||
**No changes needed for reflect:**
|
||||
|
||||
Observations are automatically included in reflect responses via the `based_on` field.
|
||||
|
||||
---
|
||||
|
||||
## What's Next
|
||||
|
||||
These learning capabilities are the foundation for more sophisticated agent memory capabilities we're exploring:
|
||||
|
||||
- **Temporal reasoning**: Better understanding of how knowledge evolves over time
|
||||
- **Selective consolidation**: Fine-grained control over what gets synthesized into observations
|
||||
- **Consolidation insights**: Visibility into how observations are formed and updated
|
||||
|
||||
---
|
||||
|
||||
**Resources:**
|
||||
- [Recall API](../developer/api/recall) — retrieve observations alongside facts
|
||||
- [Reflect API](../developer/api/reflect) — responses now include supporting observations
|
||||
- [Mental Models API](../developer/api/mental-models) — create and manage curated summaries
|
||||
- [Observations Guide](../developer/observations) — deep dive into knowledge consolidation
|
||||
- [Directives](../developer/api/memory-banks#directives) — hard rules for compliance and guardrails
|
||||
- [Full Changelog](../changelog)
|
||||
@@ -0,0 +1,3 @@
|
||||
hindsight:
|
||||
name: Hindsight Team
|
||||
url: https://github.com/vectorize-io/hindsight
|
||||
@@ -4,7 +4,7 @@ sidebar_position: 3
|
||||
|
||||
# CLI Reference
|
||||
|
||||
The Hindsight CLI provides command-line access to memory operations and bank management. All commands follow the [OpenAPI specification](/api), so you can use `--help` on any command to see all available options.
|
||||
The Hindsight CLI provides command-line access to memory operations and bank management. All commands follow the [OpenAPI specification](/api-reference), so you can use `--help` on any command to see all available options.
|
||||
|
||||
## Installation
|
||||
|
||||
|
||||
@@ -66,7 +66,6 @@ const config: Config = {
|
||||
{
|
||||
docs: {
|
||||
sidebarPath: './sidebars.ts',
|
||||
editUrl: 'https://github.com/vectorize-io/hindsight/tree/main/hindsight-docs/',
|
||||
routeBasePath: '/',
|
||||
// Only show "next" version in development or when INCLUDE_CURRENT_VERSION=true
|
||||
// In production, only show released versions from versions.json
|
||||
@@ -97,7 +96,14 @@ const config: Config = {
|
||||
return config;
|
||||
})(),
|
||||
},
|
||||
blog: false,
|
||||
blog: {
|
||||
showReadingTime: true,
|
||||
blogTitle: 'Hindsight Blog',
|
||||
blogDescription: 'Updates, insights, and deep dives into agent memory',
|
||||
postsPerPage: 10,
|
||||
blogSidebarTitle: 'Recent posts',
|
||||
blogSidebarCount: 'ALL',
|
||||
},
|
||||
theme: {
|
||||
customCss: './src/css/custom.css',
|
||||
},
|
||||
@@ -151,7 +157,8 @@ const config: Config = {
|
||||
{
|
||||
hashed: true,
|
||||
docsRouteBasePath: '/',
|
||||
indexBlog: false,
|
||||
indexBlog: true,
|
||||
blogRouteBasePath: '/blog',
|
||||
highlightSearchTermsOnTargetPage: false,
|
||||
},
|
||||
],
|
||||
@@ -207,8 +214,13 @@ const config: Config = {
|
||||
className: 'navbar-item-cookbook',
|
||||
},
|
||||
{
|
||||
type: 'doc',
|
||||
docId: 'changelog/index',
|
||||
to: '/blog',
|
||||
position: 'left',
|
||||
label: 'Blog',
|
||||
className: 'navbar-item-blog',
|
||||
},
|
||||
{
|
||||
to: '/changelog',
|
||||
position: 'left',
|
||||
label: 'Changelog',
|
||||
className: 'navbar-item-changelog',
|
||||
|
||||
@@ -38,6 +38,33 @@ for opinion in response.results:
|
||||
# [/docs:opinion-search]
|
||||
|
||||
|
||||
# [docs:recall-opinions-only]
|
||||
# Only retrieve opinions (beliefs and preferences)
|
||||
opinions = client.recall(
|
||||
bank_id="my-bank",
|
||||
query="What are my preferences?",
|
||||
types=["opinion"]
|
||||
)
|
||||
# [/docs:recall-opinions-only]
|
||||
|
||||
|
||||
# [docs:recall-include-entities]
|
||||
# Include entity summaries in recall results
|
||||
response = client.recall(
|
||||
bank_id="my-bank",
|
||||
query="What do I know about Alice?",
|
||||
include_entities=True,
|
||||
max_entity_tokens=500
|
||||
)
|
||||
|
||||
# Results include both facts and entity summaries
|
||||
for result in response.results:
|
||||
print(f"- {result.text}")
|
||||
if hasattr(result, 'entity_summary'):
|
||||
print(f" Entity: {result.entity_summary}")
|
||||
# [/docs:recall-include-entities]
|
||||
|
||||
|
||||
# [docs:opinion-disposition]
|
||||
# Bank disposition affects how opinions are formed
|
||||
# High skepticism = lower confidence, requires more evidence
|
||||
|
||||
@@ -39,6 +39,16 @@ await client.createBank('financial-advisor', {
|
||||
// [/docs:bank-mission]
|
||||
|
||||
|
||||
// [docs:bank-background]
|
||||
// Legacy snippet for v0.3 docs (background renamed to mission in v0.4)
|
||||
await client.createBank('legacy-bank', {
|
||||
name: 'Legacy Example',
|
||||
mission: `I'm a personal assistant helping a software engineer. I should track their
|
||||
project preferences, coding style, and technology choices.`
|
||||
});
|
||||
// [/docs:bank-background]
|
||||
|
||||
|
||||
// =============================================================================
|
||||
// Cleanup (not shown in docs)
|
||||
// =============================================================================
|
||||
|
||||
@@ -43,6 +43,17 @@ client.create_bank(
|
||||
# [/docs:bank-mission]
|
||||
|
||||
|
||||
# [docs:bank-background]
|
||||
# Legacy snippet for v0.3 docs (background renamed to mission in v0.4)
|
||||
client.create_bank(
|
||||
bank_id="legacy-bank",
|
||||
name="Legacy Example",
|
||||
mission="""I'm a personal assistant helping a software engineer. I should track their
|
||||
project preferences, coding style, and technology choices."""
|
||||
)
|
||||
# [/docs:bank-background]
|
||||
|
||||
|
||||
# [docs:bank-with-disposition]
|
||||
client.create_bank(
|
||||
bank_id="architect-bank",
|
||||
|
||||
@@ -147,6 +147,33 @@ response = client.recall(
|
||||
# [/docs:recall-tags-all]
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Legacy snippets for v0.3 docs (kept for backward compatibility)
|
||||
# =============================================================================
|
||||
|
||||
# [docs:recall-opinions-only]
|
||||
# Legacy: opinions replaced by observations in v0.4+
|
||||
# Only retrieve opinions (beliefs and preferences)
|
||||
opinions = client.recall(
|
||||
bank_id="my-bank",
|
||||
query="What are my preferences?",
|
||||
types=["opinion"]
|
||||
)
|
||||
# [/docs:recall-opinions-only]
|
||||
|
||||
|
||||
# [docs:recall-include-entities]
|
||||
# Legacy: entity summaries replaced by observations in v0.4+
|
||||
# Include entity summaries in recall results
|
||||
response = client.recall(
|
||||
bank_id="my-bank",
|
||||
query="What do I know about Alice?",
|
||||
include_entities=True,
|
||||
max_entity_tokens=500
|
||||
)
|
||||
# [/docs:recall-include-entities]
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Cleanup (not shown in docs)
|
||||
# =============================================================================
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"scripts": {
|
||||
"docusaurus": "docusaurus",
|
||||
"start": "docusaurus start",
|
||||
"build": "docusaurus build",
|
||||
"build": "INCLUDE_CURRENT_VERSION=true docusaurus build",
|
||||
"swizzle": "docusaurus swizzle",
|
||||
"deploy": "docusaurus deploy",
|
||||
"clear": "docusaurus clear",
|
||||
|
||||
@@ -246,13 +246,6 @@ const sidebars: SidebarsConfig = {
|
||||
],
|
||||
},
|
||||
],
|
||||
changelogSidebar: [
|
||||
{
|
||||
type: 'doc',
|
||||
id: 'changelog/index',
|
||||
label: 'Changelog',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
export default sidebars;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user