Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
20f3110e4b | ||
|
|
34863206ae | ||
|
|
786b1ecbbd | ||
|
|
f14f277692 | ||
|
|
c9f3657de6 | ||
|
|
0ae0374dc8 | ||
|
|
f7ff32d49d | ||
|
|
e06a6120a3 |
@@ -2,8 +2,8 @@ apiVersion: v2
|
||||
name: hindsight
|
||||
description: Hindsight helm chart
|
||||
type: application
|
||||
version: 0.1.14
|
||||
appVersion: "0.1.14"
|
||||
version: 0.1.16
|
||||
appVersion: "0.1.16"
|
||||
keywords:
|
||||
- ai
|
||||
- memory
|
||||
|
||||
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
||||
|
||||
[project]
|
||||
name = "hindsight-api"
|
||||
version = "0.1.14"
|
||||
version = "0.1.16"
|
||||
description = "Hindsight: Agent Memory That Works Like Human Memory"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.11"
|
||||
|
||||
@@ -173,6 +173,107 @@ async def test_regenerate_entity_observations(memory, request_context):
|
||||
await conn.execute("DELETE FROM entities WHERE bank_id = $1", bank_id)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_manual_regenerate_with_few_facts(memory, request_context):
|
||||
"""
|
||||
Test that manual regeneration works even with fewer than 5 facts.
|
||||
|
||||
This is important because:
|
||||
- Automatic generation during retain requires MIN_FACTS_THRESHOLD (5)
|
||||
- But manual regeneration via API should work with any number of facts
|
||||
- The UI triggers manual regeneration, so it should work regardless of fact count
|
||||
"""
|
||||
bank_id = f"test_manual_regen_{datetime.now(timezone.utc).timestamp()}"
|
||||
|
||||
try:
|
||||
# Store only 2 facts - below the automatic threshold
|
||||
await memory.retain_async(
|
||||
bank_id=bank_id,
|
||||
content="Alice works at Google as a senior software engineer.",
|
||||
context="work info",
|
||||
event_date=datetime(2024, 1, 15, tzinfo=timezone.utc),
|
||||
request_context=request_context,
|
||||
)
|
||||
await memory.retain_async(
|
||||
bank_id=bank_id,
|
||||
content="Alice loves hiking and outdoor photography.",
|
||||
context="hobbies",
|
||||
event_date=datetime(2024, 1, 16, tzinfo=timezone.utc),
|
||||
request_context=request_context,
|
||||
)
|
||||
|
||||
# Find the Alice entity
|
||||
pool = await memory._get_pool()
|
||||
async with pool.acquire() as conn:
|
||||
entity_row = await conn.fetchrow(
|
||||
"""
|
||||
SELECT id, canonical_name
|
||||
FROM entities
|
||||
WHERE bank_id = $1 AND LOWER(canonical_name) LIKE '%alice%'
|
||||
LIMIT 1
|
||||
""",
|
||||
bank_id
|
||||
)
|
||||
|
||||
assert entity_row is not None, "Alice entity should have been extracted"
|
||||
|
||||
entity_id = str(entity_row['id'])
|
||||
entity_name = entity_row['canonical_name']
|
||||
|
||||
# Check fact count - should be < 5
|
||||
async with pool.acquire() as conn:
|
||||
fact_count = await conn.fetchval(
|
||||
"SELECT COUNT(*) FROM unit_entities WHERE entity_id = $1",
|
||||
entity_row['id']
|
||||
)
|
||||
|
||||
print(f"\n=== Manual Regeneration Test ===")
|
||||
print(f"Entity: {entity_name} (id: {entity_id})")
|
||||
print(f"Linked facts: {fact_count}")
|
||||
|
||||
# Verify we're testing with fewer than the automatic threshold
|
||||
assert fact_count < 5, f"Test requires < 5 facts, but entity has {fact_count}"
|
||||
|
||||
# Before regeneration - should have no observations (auto threshold not met)
|
||||
obs_before = await memory.get_entity_observations(bank_id, entity_id, limit=10, request_context=request_context)
|
||||
print(f"Observations before manual regenerate: {len(obs_before)}")
|
||||
|
||||
# Manually regenerate observations - this should work regardless of fact count
|
||||
created_ids = await memory.regenerate_entity_observations(
|
||||
bank_id=bank_id,
|
||||
entity_id=entity_id,
|
||||
entity_name=entity_name,
|
||||
request_context=request_context,
|
||||
)
|
||||
|
||||
print(f"Observations created by manual regenerate: {len(created_ids)}")
|
||||
|
||||
# Get observations after regeneration
|
||||
observations = await memory.get_entity_observations(bank_id, entity_id, limit=10, request_context=request_context)
|
||||
print(f"Observations after manual regenerate: {len(observations)}")
|
||||
for obs in observations:
|
||||
print(f" - {obs.text}")
|
||||
|
||||
# Manual regeneration should create observations even with < 5 facts
|
||||
assert len(observations) > 0, \
|
||||
f"Manual regeneration should create observations even with only {fact_count} facts. " \
|
||||
f"The LLM should synthesize at least 1 observation from the available facts."
|
||||
|
||||
# Verify observations contain relevant content
|
||||
obs_texts = " ".join([o.text.lower() for o in observations])
|
||||
assert any(keyword in obs_texts for keyword in ["google", "engineer", "hiking", "photography", "alice"]), \
|
||||
"Observations should contain relevant information about Alice"
|
||||
|
||||
print(f"✓ Manual regeneration works with {fact_count} facts (below automatic threshold of 5)")
|
||||
|
||||
finally:
|
||||
# Cleanup
|
||||
pool = await memory._get_pool()
|
||||
async with pool.acquire() as conn:
|
||||
await conn.execute("DELETE FROM memory_units WHERE bank_id = $1", bank_id)
|
||||
await conn.execute("DELETE FROM entities WHERE bank_id = $1", bank_id)
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_search_with_include_entities(memory, request_context):
|
||||
"""
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "hindsight-cli"
|
||||
version = "0.1.14"
|
||||
version = "0.1.16"
|
||||
edition = "2021"
|
||||
authors = ["Hindsight Team"]
|
||||
description = "A beautiful CLI for Hindsight - semantic memory system"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "hindsight-client"
|
||||
version = "0.1.14"
|
||||
version = "0.1.16"
|
||||
description = "Python client for Hindsight - Semantic memory system with personality-driven thinking"
|
||||
authors = [
|
||||
{name = "Hindsight Team"}
|
||||
|
||||
@@ -344,3 +344,160 @@ class TestDocuments:
|
||||
assert response.success is True
|
||||
assert response.document_id == doc_id
|
||||
assert response.memory_units_deleted >= 0
|
||||
|
||||
def test_get_document(self, client, bank_id):
|
||||
"""Test getting a document."""
|
||||
import asyncio
|
||||
from hindsight_client_api import ApiClient, Configuration
|
||||
from hindsight_client_api.api import DocumentsApi
|
||||
|
||||
# First create a document
|
||||
doc_id = f"test-doc-{uuid.uuid4().hex[:8]}"
|
||||
client.retain(
|
||||
bank_id=bank_id,
|
||||
content="Test document content for retrieval",
|
||||
document_id=doc_id,
|
||||
)
|
||||
|
||||
async def do_get():
|
||||
config = Configuration(host=HINDSIGHT_API_URL)
|
||||
api_client = ApiClient(config)
|
||||
api = DocumentsApi(api_client)
|
||||
return await api.get_document(bank_id=bank_id, document_id=doc_id)
|
||||
|
||||
document = asyncio.get_event_loop().run_until_complete(do_get())
|
||||
|
||||
assert document is not None
|
||||
assert document.id == doc_id
|
||||
assert "Test document content" in document.original_text
|
||||
|
||||
|
||||
class TestEntities:
|
||||
"""Tests for entity endpoints."""
|
||||
|
||||
@pytest.fixture(autouse=True)
|
||||
def setup_memories(self, client, bank_id):
|
||||
"""Setup: Store memories that will generate entities."""
|
||||
client.retain_batch(
|
||||
bank_id=bank_id,
|
||||
items=[
|
||||
{"content": "Alice works at Google as a software engineer"},
|
||||
{"content": "Bob is friends with Alice and works at Microsoft"},
|
||||
],
|
||||
retain_async=False,
|
||||
)
|
||||
|
||||
def test_list_entities(self, client, bank_id):
|
||||
"""Test listing entities."""
|
||||
import asyncio
|
||||
from hindsight_client_api import ApiClient, Configuration
|
||||
from hindsight_client_api.api import EntitiesApi
|
||||
|
||||
async def do_list():
|
||||
config = Configuration(host=HINDSIGHT_API_URL)
|
||||
api_client = ApiClient(config)
|
||||
api = EntitiesApi(api_client)
|
||||
return await api.list_entities(bank_id=bank_id)
|
||||
|
||||
response = asyncio.get_event_loop().run_until_complete(do_list())
|
||||
|
||||
assert response is not None
|
||||
assert response.items is not None
|
||||
assert isinstance(response.items, list)
|
||||
|
||||
def test_get_entity(self, client, bank_id):
|
||||
"""Test getting a specific entity."""
|
||||
import asyncio
|
||||
from hindsight_client_api import ApiClient, Configuration
|
||||
from hindsight_client_api.api import EntitiesApi
|
||||
|
||||
async def do_test():
|
||||
config = Configuration(host=HINDSIGHT_API_URL)
|
||||
api_client = ApiClient(config)
|
||||
api = EntitiesApi(api_client)
|
||||
|
||||
# First list entities to get an ID
|
||||
list_response = await api.list_entities(bank_id=bank_id)
|
||||
|
||||
if list_response.items and len(list_response.items) > 0:
|
||||
entity_id = list_response.items[0].id
|
||||
|
||||
# Get the entity
|
||||
entity = await api.get_entity(bank_id=bank_id, entity_id=entity_id)
|
||||
return entity_id, entity
|
||||
return None, None
|
||||
|
||||
entity_id, entity = asyncio.get_event_loop().run_until_complete(do_test())
|
||||
|
||||
if entity_id:
|
||||
assert entity is not None
|
||||
assert entity.id == entity_id
|
||||
|
||||
def test_regenerate_entity_observations(self, client, bank_id):
|
||||
"""Test regenerating observations for an entity."""
|
||||
import asyncio
|
||||
from hindsight_client_api import ApiClient, Configuration
|
||||
from hindsight_client_api.api import EntitiesApi
|
||||
|
||||
async def do_test():
|
||||
config = Configuration(host=HINDSIGHT_API_URL)
|
||||
api_client = ApiClient(config)
|
||||
api = EntitiesApi(api_client)
|
||||
|
||||
# First list entities to get an ID
|
||||
list_response = await api.list_entities(bank_id=bank_id)
|
||||
|
||||
if list_response.items and len(list_response.items) > 0:
|
||||
entity_id = list_response.items[0].id
|
||||
|
||||
# Regenerate observations
|
||||
result = await api.regenerate_entity_observations(
|
||||
bank_id=bank_id,
|
||||
entity_id=entity_id,
|
||||
)
|
||||
return entity_id, result
|
||||
return None, None
|
||||
|
||||
entity_id, result = asyncio.get_event_loop().run_until_complete(do_test())
|
||||
|
||||
if entity_id:
|
||||
assert result is not None
|
||||
assert result.id == entity_id
|
||||
|
||||
|
||||
class TestDeleteBank:
|
||||
"""Tests for bank deletion."""
|
||||
|
||||
def test_delete_bank(self, client):
|
||||
"""Test deleting a bank."""
|
||||
import asyncio
|
||||
from hindsight_client_api import ApiClient, Configuration
|
||||
from hindsight_client_api.api import BanksApi
|
||||
|
||||
# Create a unique bank for this test
|
||||
bank_id = f"test_bank_delete_{uuid.uuid4().hex[:12]}"
|
||||
|
||||
# Create bank with some data
|
||||
client.create_bank(
|
||||
bank_id=bank_id,
|
||||
background="This bank will be deleted",
|
||||
)
|
||||
client.retain(
|
||||
bank_id=bank_id,
|
||||
content="Some memory to store",
|
||||
)
|
||||
|
||||
async def do_delete():
|
||||
config = Configuration(host=HINDSIGHT_API_URL)
|
||||
api_client = ApiClient(config)
|
||||
api = BanksApi(api_client)
|
||||
return await api.delete_bank(bank_id=bank_id)
|
||||
|
||||
response = asyncio.get_event_loop().run_until_complete(do_delete())
|
||||
|
||||
assert response is not None
|
||||
assert response.success is True
|
||||
|
||||
# Verify bank data is deleted - memories should be gone
|
||||
memories = client.list_memories(bank_id=bank_id)
|
||||
assert memories.total == 0
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vectorize-io/hindsight-client",
|
||||
"version": "0.1.14",
|
||||
"version": "0.1.16",
|
||||
"description": "TypeScript client for Hindsight - Semantic memory system with personality-driven thinking",
|
||||
"main": "./dist/src/index.js",
|
||||
"types": "./dist/src/index.d.ts",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vectorize-io/hindsight-control-plane",
|
||||
"version": "0.1.14",
|
||||
"version": "0.1.16",
|
||||
"description": "Control plane for Hindsight - Semantic memory system",
|
||||
"bin": {
|
||||
"hindsight-control-plane": "./bin/cli.js"
|
||||
@@ -18,10 +18,16 @@
|
||||
"lint": "next lint",
|
||||
"prepublishOnly": "npm run build"
|
||||
},
|
||||
"keywords": ["hindsight", "memory", "semantic", "ai"],
|
||||
"keywords": [
|
||||
"hindsight",
|
||||
"memory",
|
||||
"semantic",
|
||||
"ai"
|
||||
],
|
||||
"author": "Hindsight Team",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-alert-dialog": "^1.1.15",
|
||||
"@radix-ui/react-checkbox": "^1.3.3",
|
||||
"@radix-ui/react-dialog": "^1.1.15",
|
||||
"@radix-ui/react-label": "^2.1.8",
|
||||
@@ -58,9 +64,9 @@
|
||||
"typescript": "^5.9.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vectorize-io/hindsight-client": "file:../hindsight-clients/typescript",
|
||||
"@eslint/eslintrc": "^3.3.3",
|
||||
"@eslint/js": "^9.39.2",
|
||||
"@vectorize-io/hindsight-client": "file:../hindsight-clients/typescript",
|
||||
"eslint-plugin-react": "^7.37.5",
|
||||
"eslint-plugin-react-hooks": "^7.0.1",
|
||||
"prettier": "^3.7.4",
|
||||
|
||||
@@ -25,3 +25,28 @@ export async function GET(
|
||||
return NextResponse.json({ error: "Failed to fetch document" }, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
export async function DELETE(
|
||||
request: NextRequest,
|
||||
{ params }: { params: Promise<{ documentId: string }> }
|
||||
) {
|
||||
try {
|
||||
const { documentId } = await params;
|
||||
const searchParams = request.nextUrl.searchParams;
|
||||
const bankId = searchParams.get("bank_id");
|
||||
|
||||
if (!bankId) {
|
||||
return NextResponse.json({ error: "bank_id is required" }, { status: 400 });
|
||||
}
|
||||
|
||||
const response = await sdk.deleteDocument({
|
||||
client: lowLevelClient,
|
||||
path: { bank_id: bankId, document_id: documentId },
|
||||
});
|
||||
|
||||
return NextResponse.json(response.data, { status: 200 });
|
||||
} catch (error) {
|
||||
console.error("Error deleting document:", error);
|
||||
return NextResponse.json({ error: "Failed to delete document" }, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,7 +13,17 @@ import {
|
||||
TableHeader,
|
||||
TableRow,
|
||||
} from "@/components/ui/table";
|
||||
import { X } from "lucide-react";
|
||||
import {
|
||||
AlertDialog,
|
||||
AlertDialogAction,
|
||||
AlertDialogCancel,
|
||||
AlertDialogContent,
|
||||
AlertDialogDescription,
|
||||
AlertDialogFooter,
|
||||
AlertDialogHeader,
|
||||
AlertDialogTitle,
|
||||
} from "@/components/ui/alert-dialog";
|
||||
import { X, Trash2 } from "lucide-react";
|
||||
|
||||
export function DocumentsView() {
|
||||
const { currentBank } = useBank();
|
||||
@@ -25,6 +35,16 @@ export function DocumentsView() {
|
||||
// Document view panel state
|
||||
const [selectedDocument, setSelectedDocument] = useState<any>(null);
|
||||
const [loadingDocument, setLoadingDocument] = useState(false);
|
||||
const [deletingDocumentId, setDeletingDocumentId] = useState<string | null>(null);
|
||||
|
||||
// Delete confirmation dialog state
|
||||
const [documentToDelete, setDocumentToDelete] = useState<{
|
||||
id: string;
|
||||
memoryCount?: number;
|
||||
} | null>(null);
|
||||
const [deleteResult, setDeleteResult] = useState<{ success: boolean; message: string } | null>(
|
||||
null
|
||||
);
|
||||
|
||||
const loadDocuments = async () => {
|
||||
if (!currentBank) return;
|
||||
@@ -64,6 +84,42 @@ export function DocumentsView() {
|
||||
}
|
||||
};
|
||||
|
||||
const confirmDeleteDocument = async () => {
|
||||
if (!currentBank || !documentToDelete) return;
|
||||
|
||||
const documentId = documentToDelete.id;
|
||||
setDeletingDocumentId(documentId);
|
||||
setDocumentToDelete(null);
|
||||
|
||||
try {
|
||||
const result = await client.deleteDocument(documentId, currentBank);
|
||||
setDeleteResult({
|
||||
success: true,
|
||||
message: `Deleted document and ${result.memory_units_deleted} memory units.`,
|
||||
});
|
||||
|
||||
// Close panel if this document was selected
|
||||
if (selectedDocument?.id === documentId) {
|
||||
setSelectedDocument(null);
|
||||
}
|
||||
|
||||
// Reload documents list
|
||||
loadDocuments();
|
||||
} catch (error) {
|
||||
console.error("Error deleting document:", error);
|
||||
setDeleteResult({
|
||||
success: false,
|
||||
message: "Error deleting document: " + (error as Error).message,
|
||||
});
|
||||
} finally {
|
||||
setDeletingDocumentId(null);
|
||||
}
|
||||
};
|
||||
|
||||
const requestDeleteDocument = (documentId: string, memoryCount?: number) => {
|
||||
setDocumentToDelete({ id: documentId, memoryCount });
|
||||
};
|
||||
|
||||
// Auto-load documents when component mounts
|
||||
useEffect(() => {
|
||||
if (currentBank) {
|
||||
@@ -116,7 +172,6 @@ export function DocumentsView() {
|
||||
<TableHead>Context</TableHead>
|
||||
<TableHead>Text Length</TableHead>
|
||||
<TableHead>Memory Units</TableHead>
|
||||
<TableHead>Actions</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
@@ -142,24 +197,11 @@ export function DocumentsView() {
|
||||
<TableCell className="text-card-foreground">
|
||||
{doc.memory_unit_count}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<Button
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
viewDocumentText(doc.id);
|
||||
}}
|
||||
size="sm"
|
||||
variant={selectedDocument?.id === doc.id ? "default" : "secondary"}
|
||||
title="View original text"
|
||||
>
|
||||
View Text
|
||||
</Button>
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
))
|
||||
) : (
|
||||
<TableRow>
|
||||
<TableCell colSpan={6} className="text-center">
|
||||
<TableCell colSpan={5} className="text-center">
|
||||
Click "Load Documents" to view data
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
@@ -276,6 +318,29 @@ export function DocumentsView() {
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Delete Button */}
|
||||
<div className="pt-2 border-t border-border">
|
||||
<Button
|
||||
variant="destructive"
|
||||
size="sm"
|
||||
onClick={() =>
|
||||
requestDeleteDocument(
|
||||
selectedDocument.id,
|
||||
selectedDocument.memory_unit_count
|
||||
)
|
||||
}
|
||||
className="w-full gap-2"
|
||||
disabled={deletingDocumentId === selectedDocument.id}
|
||||
>
|
||||
{deletingDocumentId === selectedDocument.id ? (
|
||||
<span className="animate-spin">⏳</span>
|
||||
) : (
|
||||
<Trash2 className="h-4 w-4" />
|
||||
)}
|
||||
Delete Document
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* Original Text */}
|
||||
{selectedDocument.original_text && (
|
||||
<div>
|
||||
@@ -296,6 +361,58 @@ export function DocumentsView() {
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* Delete Confirmation Dialog */}
|
||||
<AlertDialog
|
||||
open={!!documentToDelete}
|
||||
onOpenChange={(open) => !open && setDocumentToDelete(null)}
|
||||
>
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>Delete Document</AlertDialogTitle>
|
||||
<AlertDialogDescription>
|
||||
Are you sure you want to delete document{" "}
|
||||
<span className="font-mono font-semibold">"{documentToDelete?.id}"</span>?
|
||||
<br />
|
||||
<br />
|
||||
This will also delete{" "}
|
||||
{documentToDelete?.memoryCount !== undefined ? (
|
||||
<span className="font-semibold">{documentToDelete.memoryCount} memory units</span>
|
||||
) : (
|
||||
"all memory units"
|
||||
)}{" "}
|
||||
extracted from this document.
|
||||
<br />
|
||||
<br />
|
||||
<span className="text-destructive font-semibold">This action cannot be undone.</span>
|
||||
</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogCancel>Cancel</AlertDialogCancel>
|
||||
<AlertDialogAction
|
||||
onClick={confirmDeleteDocument}
|
||||
className="bg-destructive text-destructive-foreground hover:bg-destructive/90"
|
||||
>
|
||||
Delete
|
||||
</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
|
||||
{/* Delete Result Dialog */}
|
||||
<AlertDialog open={!!deleteResult} onOpenChange={(open) => !open && setDeleteResult(null)}>
|
||||
<AlertDialogContent>
|
||||
<AlertDialogHeader>
|
||||
<AlertDialogTitle>
|
||||
{deleteResult?.success ? "Document Deleted" : "Error"}
|
||||
</AlertDialogTitle>
|
||||
<AlertDialogDescription>{deleteResult?.message}</AlertDialogDescription>
|
||||
</AlertDialogHeader>
|
||||
<AlertDialogFooter>
|
||||
<AlertDialogAction onClick={() => setDeleteResult(null)}>OK</AlertDialogAction>
|
||||
</AlertDialogFooter>
|
||||
</AlertDialogContent>
|
||||
</AlertDialog>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -512,7 +512,7 @@ export function Graph2D({
|
||||
ref={containerRef}
|
||||
className="w-full h-full"
|
||||
style={{
|
||||
background: isDarkMode
|
||||
backgroundImage: isDarkMode
|
||||
? "radial-gradient(circle at 1px 1px, rgba(255,255,255,0.08) 1px, transparent 0)"
|
||||
: "radial-gradient(circle at 1px 1px, rgba(0,0,0,0.06) 1px, transparent 0)",
|
||||
backgroundSize: "20px 20px",
|
||||
|
||||
@@ -0,0 +1,117 @@
|
||||
"use client";
|
||||
|
||||
import * as React from "react";
|
||||
import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog";
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
import { buttonVariants } from "@/components/ui/button";
|
||||
|
||||
const AlertDialog = AlertDialogPrimitive.Root;
|
||||
|
||||
const AlertDialogTrigger = AlertDialogPrimitive.Trigger;
|
||||
|
||||
const AlertDialogPortal = AlertDialogPrimitive.Portal;
|
||||
|
||||
const AlertDialogOverlay = React.forwardRef<
|
||||
React.ElementRef<typeof AlertDialogPrimitive.Overlay>,
|
||||
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Overlay>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<AlertDialogPrimitive.Overlay
|
||||
className={cn(
|
||||
"fixed inset-0 z-50 bg-black/80 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
ref={ref}
|
||||
/>
|
||||
));
|
||||
AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName;
|
||||
|
||||
const AlertDialogContent = React.forwardRef<
|
||||
React.ElementRef<typeof AlertDialogPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Content>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<AlertDialogPortal>
|
||||
<AlertDialogOverlay />
|
||||
<AlertDialogPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border bg-background p-6 shadow-lg duration-200 data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] sm:rounded-lg",
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
</AlertDialogPortal>
|
||||
));
|
||||
AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName;
|
||||
|
||||
const AlertDialogHeader = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
|
||||
<div className={cn("flex flex-col space-y-2 text-center sm:text-left", className)} {...props} />
|
||||
);
|
||||
AlertDialogHeader.displayName = "AlertDialogHeader";
|
||||
|
||||
const AlertDialogFooter = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
|
||||
<div
|
||||
className={cn("flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2", className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
AlertDialogFooter.displayName = "AlertDialogFooter";
|
||||
|
||||
const AlertDialogTitle = React.forwardRef<
|
||||
React.ElementRef<typeof AlertDialogPrimitive.Title>,
|
||||
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Title>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<AlertDialogPrimitive.Title
|
||||
ref={ref}
|
||||
className={cn("text-lg font-semibold", className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName;
|
||||
|
||||
const AlertDialogDescription = React.forwardRef<
|
||||
React.ElementRef<typeof AlertDialogPrimitive.Description>,
|
||||
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Description>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<AlertDialogPrimitive.Description
|
||||
ref={ref}
|
||||
className={cn("text-sm text-muted-foreground", className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
AlertDialogDescription.displayName = AlertDialogPrimitive.Description.displayName;
|
||||
|
||||
const AlertDialogAction = React.forwardRef<
|
||||
React.ElementRef<typeof AlertDialogPrimitive.Action>,
|
||||
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Action>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<AlertDialogPrimitive.Action ref={ref} className={cn(buttonVariants(), className)} {...props} />
|
||||
));
|
||||
AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName;
|
||||
|
||||
const AlertDialogCancel = React.forwardRef<
|
||||
React.ElementRef<typeof AlertDialogPrimitive.Cancel>,
|
||||
React.ComponentPropsWithoutRef<typeof AlertDialogPrimitive.Cancel>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<AlertDialogPrimitive.Cancel
|
||||
ref={ref}
|
||||
className={cn(buttonVariants({ variant: "outline" }), "mt-2 sm:mt-0", className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName;
|
||||
|
||||
export {
|
||||
AlertDialog,
|
||||
AlertDialogPortal,
|
||||
AlertDialogOverlay,
|
||||
AlertDialogTrigger,
|
||||
AlertDialogContent,
|
||||
AlertDialogHeader,
|
||||
AlertDialogFooter,
|
||||
AlertDialogTitle,
|
||||
AlertDialogDescription,
|
||||
AlertDialogAction,
|
||||
AlertDialogCancel,
|
||||
};
|
||||
@@ -9,7 +9,7 @@ const buttonVariants = cva(
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default: "bg-primary-gradient text-white hover:opacity-90",
|
||||
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
||||
destructive: "bg-destructive text-destructive-foreground hover:bg-destructive/90",
|
||||
outline: "border border-input bg-background hover:bg-accent hover:text-accent-foreground",
|
||||
secondary: "bg-secondary text-secondary-foreground hover:bg-secondary/80",
|
||||
|
||||
@@ -165,6 +165,20 @@ export class ControlPlaneClient {
|
||||
return this.fetchApi(`/api/documents/${documentId}?bank_id=${bankId}`);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete document and all its associated memory units
|
||||
*/
|
||||
async deleteDocument(documentId: string, bankId: string) {
|
||||
return this.fetchApi<{
|
||||
success: boolean;
|
||||
message: string;
|
||||
document_id: string;
|
||||
memory_units_deleted: number;
|
||||
}>(`/api/documents/${documentId}?bank_id=${bankId}`, {
|
||||
method: "DELETE",
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get chunk
|
||||
*/
|
||||
|
||||
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
||||
|
||||
[project]
|
||||
name = "hindsight-dev"
|
||||
version = "0.1.14"
|
||||
version = "0.1.16"
|
||||
description = "Development utilities for Hindsight"
|
||||
requires-python = ">=3.11"
|
||||
dependencies = [
|
||||
|
||||
@@ -8,6 +8,16 @@ This changelog highlights user-facing changes only. Internal maintenance, CI/CD,
|
||||
|
||||
For full release details, see [GitHub Releases](https://github.com/vectorize-io/hindsight/releases).
|
||||
|
||||
## [0.1.15](https://github.com/vectorize-io/hindsight/releases/tag/v0.1.15)
|
||||
|
||||
**Features**
|
||||
|
||||
- Add the ability to delete documents from the web UI. ([`f7ff32d`](https://github.com/vectorize-io/hindsight/commit/f7ff32d))
|
||||
|
||||
**Improvements**
|
||||
|
||||
- Improve the API health check endpoint and update the generated client APIs/types accordingly. ([`e06a612`](https://github.com/vectorize-io/hindsight/commit/e06a612))
|
||||
|
||||
## [0.1.14](https://github.com/vectorize-io/hindsight/releases/tag/v0.1.14)
|
||||
|
||||
**Bug Fixes**
|
||||
|
||||
@@ -0,0 +1,121 @@
|
||||
---
|
||||
sidebar_position: 3
|
||||
---
|
||||
|
||||
# Skills
|
||||
|
||||
Hindsight provides an Agent Skill that gives AI coding assistants persistent memory across sessions. Skills are reusable prompt templates that agents can load when needed to gain specialized capabilities.
|
||||
|
||||
## Supported Platforms
|
||||
|
||||
| Platform | Skills Directory |
|
||||
|----------|-----------------|
|
||||
| [Claude Code](https://docs.anthropic.com/en/docs/claude-code) | `~/.claude/skills/` |
|
||||
| [OpenCode](https://github.com/opencode-ai/opencode) | `~/.opencode/skills/` |
|
||||
| [Codex CLI](https://github.com/openai/codex) | `~/.codex/skills/` |
|
||||
|
||||
## Quick Install
|
||||
|
||||
```bash
|
||||
curl -fsSL https://hindsight.vectorize.io/get-skill | bash
|
||||
```
|
||||
|
||||
The installer will:
|
||||
1. Prompt you to select your AI coding assistant
|
||||
2. Run the LLM provider configuration
|
||||
3. Install the skill to the appropriate directory
|
||||
|
||||
### Install for a Specific Platform
|
||||
|
||||
```bash
|
||||
# Claude Code
|
||||
curl -fsSL https://hindsight.vectorize.io/get-skill | bash -s -- --app claude
|
||||
|
||||
# OpenCode
|
||||
curl -fsSL https://hindsight.vectorize.io/get-skill | bash -s -- --app opencode
|
||||
|
||||
# Codex CLI
|
||||
curl -fsSL https://hindsight.vectorize.io/get-skill | bash -s -- --app codex
|
||||
```
|
||||
|
||||
## What the Skill Provides
|
||||
|
||||
Once installed, your AI assistant gains the ability to:
|
||||
|
||||
- **Retain** - Store user preferences, learnings, and procedure outcomes
|
||||
- **Recall** - Search for relevant context before starting tasks
|
||||
- **Reflect** - Synthesize memories into contextual answers
|
||||
|
||||
The skill uses the `hindsight-embed` CLI which runs a lightweight local daemon with an embedded database.
|
||||
|
||||
## How Skills Work
|
||||
|
||||
Skills are **model-invoked**, meaning the AI assistant automatically decides when to use them based on the context of your conversation. You don't need to explicitly trigger the skill.
|
||||
|
||||
The assistant will:
|
||||
- **Store** when you share preferences, when tasks succeed/fail, or when learnings emerge
|
||||
- **Recall** before starting non-trivial tasks to get relevant context
|
||||
|
||||
### What Gets Stored
|
||||
|
||||
The skill is optimized to store:
|
||||
|
||||
| Category | Examples |
|
||||
|----------|----------|
|
||||
| **User Preferences** | Coding style, tool preferences, language choices |
|
||||
| **Procedure Outcomes** | Commands that worked, configurations that resolved issues |
|
||||
| **Learnings** | Bug solutions, workarounds, architecture decisions |
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
AI Coding Assistant
|
||||
│
|
||||
▼
|
||||
Hindsight Skill (SKILL.md)
|
||||
│
|
||||
▼
|
||||
hindsight-embed CLI
|
||||
│
|
||||
▼
|
||||
Local Daemon (auto-started)
|
||||
│
|
||||
▼
|
||||
Embedded PostgreSQL (~/.pg0/hindsight-embed/)
|
||||
```
|
||||
|
||||
All data stays on your machine. The daemon auto-starts when needed and shuts down after inactivity.
|
||||
|
||||
## Configuration
|
||||
|
||||
The skill uses configuration stored in `~/.hindsight/config.env`. Reconfigure anytime:
|
||||
|
||||
```bash
|
||||
uvx hindsight-embed configure
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Skill not activating
|
||||
|
||||
The skill activates based on its description matching your request. Try being explicit:
|
||||
- "Remember that..." triggers storage
|
||||
- "What do you know about..." triggers recall
|
||||
|
||||
### Daemon issues
|
||||
|
||||
```bash
|
||||
uvx hindsight-embed daemon status
|
||||
uvx hindsight-embed daemon logs
|
||||
```
|
||||
|
||||
### Reconfigure
|
||||
|
||||
```bash
|
||||
uvx hindsight-embed configure
|
||||
```
|
||||
|
||||
## Requirements
|
||||
|
||||
- Python 3.10+ (for `uvx`)
|
||||
- An LLM API key (OpenAI, Anthropic, Groq, etc.)
|
||||
@@ -139,7 +139,7 @@ const config: Config = {
|
||||
isCloseable: false,
|
||||
},
|
||||
}),
|
||||
image: 'img/hindsight-social-card.jpg',
|
||||
image: 'img/logo.png',
|
||||
colorMode: {
|
||||
defaultMode: 'dark',
|
||||
respectPrefersColorScheme: true,
|
||||
|
||||
@@ -172,6 +172,11 @@ const sidebars: SidebarsConfig = {
|
||||
id: 'sdks/integrations/litellm',
|
||||
label: 'LiteLLM',
|
||||
},
|
||||
{
|
||||
type: 'doc',
|
||||
id: 'sdks/integrations/skills',
|
||||
label: 'Skills',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
|
||||
@@ -65,77 +65,78 @@ print_banner() {
|
||||
# Embedded SKILL.md content
|
||||
SKILL_CONTENT='---
|
||||
name: hindsight
|
||||
description: Give your agent persistent memory that works like human memory. Store facts, preferences, and context that persist across sessions.
|
||||
description: Store user preferences, learnings from tasks, and procedure outcomes. Use to remember what works and recall context before new tasks.
|
||||
---
|
||||
|
||||
# Hindsight Memory Skill
|
||||
|
||||
You have access to persistent memory via the `hindsight-embed` CLI. Use it to remember important information about the user and recall it when relevant.
|
||||
|
||||
## Setup (first time only)
|
||||
|
||||
Run: `uvx hindsight-embed configure`
|
||||
|
||||
This will configure your LLM provider and start a local daemon that manages your memory bank.
|
||||
You have persistent memory via the `hindsight-embed` CLI. **Proactively store learnings and recall context** to provide better assistance.
|
||||
|
||||
## Commands
|
||||
|
||||
The CLI uses a bank ID to organize memories. Use `default` for general memories or create project-specific banks.
|
||||
|
||||
### Store a memory
|
||||
|
||||
Use `memory retain` to store important facts, preferences, decisions, or context:
|
||||
Use `memory retain` to store what you learn:
|
||||
|
||||
```bash
|
||||
uvx hindsight-embed memory retain default "User prefers dark mode for all UIs"
|
||||
uvx hindsight-embed memory retain default "Project uses Python 3.11 with FastAPI" --context work
|
||||
uvx hindsight-embed memory retain myproject "API uses JWT authentication"
|
||||
uvx hindsight-embed memory retain default "User prefers TypeScript with strict mode"
|
||||
uvx hindsight-embed memory retain default "Running tests requires NODE_ENV=test" --context procedures
|
||||
uvx hindsight-embed memory retain default "Build failed when using Node 18, works with Node 20" --context learnings
|
||||
```
|
||||
|
||||
### Recall memories
|
||||
|
||||
Use `memory recall` to search for relevant memories before starting tasks:
|
||||
Use `memory recall` BEFORE starting tasks to get relevant context:
|
||||
|
||||
```bash
|
||||
uvx hindsight-embed memory recall default "What are the user'"'"'s UI preferences?"
|
||||
uvx hindsight-embed memory recall default "What tech stack does this project use?"
|
||||
uvx hindsight-embed memory recall default "user preferences for this project"
|
||||
uvx hindsight-embed memory recall default "what issues have we encountered before"
|
||||
```
|
||||
|
||||
### Reflect on memories
|
||||
|
||||
Use `memory reflect` for contextual answers that synthesize multiple memories:
|
||||
Use `memory reflect` to synthesize context:
|
||||
|
||||
```bash
|
||||
uvx hindsight-embed memory reflect default "How should I set up the dev environment?"
|
||||
uvx hindsight-embed memory reflect default "How should I approach this task based on past experience?"
|
||||
```
|
||||
|
||||
### Other commands
|
||||
## IMPORTANT: When to Store Memories
|
||||
|
||||
```bash
|
||||
uvx hindsight-embed bank list # List all memory banks
|
||||
uvx hindsight-embed daemon status # Check daemon status
|
||||
uvx hindsight-embed --help # Full CLI help
|
||||
```
|
||||
**Always store** after you learn something valuable:
|
||||
|
||||
## When to Use
|
||||
### User Preferences
|
||||
- Coding style (indentation, naming conventions, language preferences)
|
||||
- Tool preferences (editors, linters, formatters)
|
||||
- Communication preferences
|
||||
- Project conventions
|
||||
|
||||
### Store memories when you learn:
|
||||
- User preferences (coding style, tools, UI preferences)
|
||||
- Project context (tech stack, architecture decisions)
|
||||
- Personal information the user shares (name, role, company)
|
||||
- Important decisions or outcomes
|
||||
### Procedure Outcomes
|
||||
- Steps that successfully completed a task
|
||||
- Commands that worked (or failed) and why
|
||||
- Workarounds discovered
|
||||
- Configuration that resolved issues
|
||||
|
||||
### Recall memories when:
|
||||
- Starting a new task (get relevant context first)
|
||||
- Making decisions that should consider user preferences
|
||||
- Working on a project where past context would help
|
||||
### Learnings from Tasks
|
||||
- Bugs encountered and their solutions
|
||||
- Performance optimizations that worked
|
||||
- Architecture decisions and rationale
|
||||
- Dependencies or version requirements
|
||||
|
||||
## IMPORTANT: When to Recall Memories
|
||||
|
||||
**Always recall** before:
|
||||
- Starting any non-trivial task
|
||||
- Making decisions about implementation
|
||||
- Suggesting tools, libraries, or approaches
|
||||
- Writing code in a new area of the project
|
||||
|
||||
## Best Practices
|
||||
|
||||
1. **Be specific**: Store "User prefers 2-space indentation" not "User has preferences"
|
||||
2. **Recall first**: Before starting tasks, recall relevant context
|
||||
3. **Use context tags**: Organize with `--context` (work, personal, preferences)
|
||||
4. **Use project banks**: Create separate banks for different projects
|
||||
1. **Store immediately**: When you discover something, store it right away
|
||||
2. **Be specific**: Store "npm test requires --experimental-vm-modules flag" not "tests need a flag"
|
||||
3. **Include outcomes**: Store what worked AND what did not work
|
||||
4. **Recall first**: Always check for relevant context before starting work
|
||||
'
|
||||
|
||||
# Get skills directory for app (bash 3.x compatible)
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 54 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 5.0 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 3.5 KiB |
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
||||
|
||||
[project]
|
||||
name = "hindsight-embed"
|
||||
version = "0.1.0"
|
||||
version = "0.1.16"
|
||||
description = "Hindsight embedded CLI - local memory operations without a server"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.11"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "hindsight-litellm"
|
||||
version = "0.1.14"
|
||||
version = "0.1.16"
|
||||
description = "Universal LLM memory integration via LiteLLM - works with 100+ providers"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.10"
|
||||
|
||||
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
||||
|
||||
[project]
|
||||
name = "hindsight-all"
|
||||
version = "0.1.14"
|
||||
version = "0.1.16"
|
||||
description = "Hindsight: Agent Memory That Works Like Human Memory - All-in-One Bundle"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.11"
|
||||
|
||||
Generated
+156
-107
@@ -13,7 +13,7 @@
|
||||
},
|
||||
"hindsight-clients/typescript": {
|
||||
"name": "@vectorize-io/hindsight-client",
|
||||
"version": "0.1.11",
|
||||
"version": "0.1.14",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@hey-api/openapi-ts": "^0.88.0",
|
||||
@@ -26,9 +26,10 @@
|
||||
},
|
||||
"hindsight-control-plane": {
|
||||
"name": "@vectorize-io/hindsight-control-plane",
|
||||
"version": "0.1.11",
|
||||
"version": "0.1.14",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-alert-dialog": "^1.1.15",
|
||||
"@radix-ui/react-checkbox": "^1.3.3",
|
||||
"@radix-ui/react-dialog": "^1.1.15",
|
||||
"@radix-ui/react-label": "^2.1.8",
|
||||
@@ -5131,6 +5132,111 @@
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-darwin-x64": {
|
||||
"version": "16.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.0.10.tgz",
|
||||
"integrity": "sha512-spbEObMvRKkQ3CkYVOME+ocPDFo5UqHb8EMTS78/0mQ+O1nqE8toHJVioZo4TvebATxgA8XMTHHrScPrn68OGw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-arm64-gnu": {
|
||||
"version": "16.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.0.10.tgz",
|
||||
"integrity": "sha512-uQtWE3X0iGB8apTIskOMi2w/MKONrPOUCi5yLO+v3O8Mb5c7K4Q5KD1jvTpTF5gJKa3VH/ijKjKUq9O9UhwOYw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-arm64-musl": {
|
||||
"version": "16.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.0.10.tgz",
|
||||
"integrity": "sha512-llA+hiDTrYvyWI21Z0L1GiXwjQaanPVQQwru5peOgtooeJ8qx3tlqRV2P7uH2pKQaUfHxI/WVarvI5oYgGxaTw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-x64-gnu": {
|
||||
"version": "16.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.0.10.tgz",
|
||||
"integrity": "sha512-AK2q5H0+a9nsXbeZ3FZdMtbtu9jxW4R/NgzZ6+lrTm3d6Zb7jYrWcgjcpM1k8uuqlSy4xIyPR2YiuUr+wXsavA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-x64-musl": {
|
||||
"version": "16.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.0.10.tgz",
|
||||
"integrity": "sha512-1TDG9PDKivNw5550S111gsO4RGennLVl9cipPhtkXIFVwo31YZ73nEbLjNC8qG3SgTz/QZyYyaFYMeY4BKZR/g==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-win32-arm64-msvc": {
|
||||
"version": "16.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.0.10.tgz",
|
||||
"integrity": "sha512-aEZIS4Hh32xdJQbHz121pyuVZniSNoqDVx1yIr2hy+ZwJGipeqnMZBJHyMxv2tiuAXGx6/xpTcQJ6btIiBjgmg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-win32-x64-msvc": {
|
||||
"version": "16.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.0.10.tgz",
|
||||
"integrity": "sha512-E+njfCoFLb01RAFEnGZn6ERoOqhK1Gl3Lfz1Kjnj0Ulfu7oJbuMyvBKNj/bw8XZnenHDASlygTjZICQW+rYW1Q==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@node-rs/jieba": {
|
||||
"version": "1.10.4",
|
||||
"license": "MIT",
|
||||
@@ -5326,6 +5432,52 @@
|
||||
"version": "1.1.3",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@radix-ui/react-alert-dialog": {
|
||||
"version": "1.1.15",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-alert-dialog/-/react-alert-dialog-1.1.15.tgz",
|
||||
"integrity": "sha512-oTVLkEw5GpdRe29BqJ0LSDFWI3qu0vR1M0mUkOQWDIUnY/QIkLpgDMWuKxP94c2NAC2LGcgVhG1ImF3jkZ5wXw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/primitive": "1.1.3",
|
||||
"@radix-ui/react-compose-refs": "1.1.2",
|
||||
"@radix-ui/react-context": "1.1.2",
|
||||
"@radix-ui/react-dialog": "1.1.15",
|
||||
"@radix-ui/react-primitive": "2.1.3",
|
||||
"@radix-ui/react-slot": "1.2.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"@types/react-dom": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc",
|
||||
"react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
},
|
||||
"@types/react-dom": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-alert-dialog/node_modules/@radix-ui/react-slot": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz",
|
||||
"integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-compose-refs": "1.1.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/react": "*",
|
||||
"react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/react": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@radix-ui/react-arrow": {
|
||||
"version": "1.1.7",
|
||||
"license": "MIT",
|
||||
@@ -5934,6 +6086,8 @@
|
||||
},
|
||||
"node_modules/@radix-ui/react-slot": {
|
||||
"version": "1.2.4",
|
||||
"resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.4.tgz",
|
||||
"integrity": "sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@radix-ui/react-compose-refs": "1.1.2"
|
||||
@@ -24202,111 +24356,6 @@
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/wooorm"
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-darwin-x64": {
|
||||
"version": "16.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.0.10.tgz",
|
||||
"integrity": "sha512-spbEObMvRKkQ3CkYVOME+ocPDFo5UqHb8EMTS78/0mQ+O1nqE8toHJVioZo4TvebATxgA8XMTHHrScPrn68OGw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-arm64-gnu": {
|
||||
"version": "16.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.0.10.tgz",
|
||||
"integrity": "sha512-uQtWE3X0iGB8apTIskOMi2w/MKONrPOUCi5yLO+v3O8Mb5c7K4Q5KD1jvTpTF5gJKa3VH/ijKjKUq9O9UhwOYw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-arm64-musl": {
|
||||
"version": "16.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.0.10.tgz",
|
||||
"integrity": "sha512-llA+hiDTrYvyWI21Z0L1GiXwjQaanPVQQwru5peOgtooeJ8qx3tlqRV2P7uH2pKQaUfHxI/WVarvI5oYgGxaTw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-x64-gnu": {
|
||||
"version": "16.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.0.10.tgz",
|
||||
"integrity": "sha512-AK2q5H0+a9nsXbeZ3FZdMtbtu9jxW4R/NgzZ6+lrTm3d6Zb7jYrWcgjcpM1k8uuqlSy4xIyPR2YiuUr+wXsavA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-linux-x64-musl": {
|
||||
"version": "16.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.0.10.tgz",
|
||||
"integrity": "sha512-1TDG9PDKivNw5550S111gsO4RGennLVl9cipPhtkXIFVwo31YZ73nEbLjNC8qG3SgTz/QZyYyaFYMeY4BKZR/g==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-win32-arm64-msvc": {
|
||||
"version": "16.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.0.10.tgz",
|
||||
"integrity": "sha512-aEZIS4Hh32xdJQbHz121pyuVZniSNoqDVx1yIr2hy+ZwJGipeqnMZBJHyMxv2tiuAXGx6/xpTcQJ6btIiBjgmg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@next/swc-win32-x64-msvc": {
|
||||
"version": "16.0.10",
|
||||
"resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.0.10.tgz",
|
||||
"integrity": "sha512-E+njfCoFLb01RAFEnGZn6ERoOqhK1Gl3Lfz1Kjnj0Ulfu7oJbuMyvBKNj/bw8XZnenHDASlygTjZICQW+rYW1Q==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -65,7 +65,7 @@ fi
|
||||
print_info "Updating version in all components..."
|
||||
|
||||
# Update Python packages
|
||||
PYTHON_PACKAGES=("hindsight-api" "hindsight-dev" "hindsight" "hindsight-integrations/litellm")
|
||||
PYTHON_PACKAGES=("hindsight-api" "hindsight-dev" "hindsight" "hindsight-integrations/litellm" "hindsight-embed")
|
||||
for package in "${PYTHON_PACKAGES[@]}"; do
|
||||
PYPROJECT_FILE="$package/pyproject.toml"
|
||||
if [ -f "$PYPROJECT_FILE" ]; then
|
||||
@@ -148,7 +148,7 @@ git add -A
|
||||
git commit --no-verify -m "Release v$VERSION
|
||||
|
||||
- Update version to $VERSION in all components
|
||||
- Python packages: hindsight-api, hindsight-dev, hindsight-all, hindsight-litellm
|
||||
- Python packages: hindsight-api, hindsight-dev, hindsight-all, hindsight-litellm, hindsight-embed
|
||||
- Python client: hindsight-clients/python
|
||||
- TypeScript client: hindsight-clients/typescript
|
||||
- Rust CLI: hindsight-cli
|
||||
|
||||
@@ -1292,7 +1292,7 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "hindsight-all"
|
||||
version = "0.1.14"
|
||||
version = "0.1.16"
|
||||
source = { editable = "hindsight" }
|
||||
dependencies = [
|
||||
{ name = "hindsight-api" },
|
||||
@@ -1316,7 +1316,7 @@ provides-extras = ["test"]
|
||||
|
||||
[[package]]
|
||||
name = "hindsight-api"
|
||||
version = "0.1.14"
|
||||
version = "0.1.16"
|
||||
source = { editable = "hindsight-api" }
|
||||
dependencies = [
|
||||
{ name = "alembic" },
|
||||
@@ -1422,7 +1422,7 @@ dev = [
|
||||
|
||||
[[package]]
|
||||
name = "hindsight-client"
|
||||
version = "0.1.14"
|
||||
version = "0.1.16"
|
||||
source = { editable = "hindsight-clients/python" }
|
||||
dependencies = [
|
||||
{ name = "aiohttp" },
|
||||
@@ -1456,7 +1456,7 @@ provides-extras = ["test"]
|
||||
|
||||
[[package]]
|
||||
name = "hindsight-dev"
|
||||
version = "0.1.14"
|
||||
version = "0.1.16"
|
||||
source = { editable = "hindsight-dev" }
|
||||
dependencies = [
|
||||
{ name = "hindsight-api" },
|
||||
@@ -1491,7 +1491,7 @@ dev = [
|
||||
|
||||
[[package]]
|
||||
name = "hindsight-embed"
|
||||
version = "0.1.0"
|
||||
version = "0.1.16"
|
||||
source = { editable = "hindsight-embed" }
|
||||
dependencies = [
|
||||
{ name = "httpx" },
|
||||
|
||||
Reference in New Issue
Block a user