Compare commits

...
Author SHA1 Message Date
Nicolò Boschi f0c5153861 chore: apply ruff formatting to generate_changelog.py 2026-03-18 17:51:45 +01:00
Nicolò Boschi ef24828356 fix: add agno and hermes integration docs to version-0.4 for production build 2026-03-18 17:45:26 +01:00
Nicolò Boschi db7a0ad3a5 feat: independent versioning for integrations
- Add per-integration changelog pages at /changelog/integrations/<name>
- Move main changelog to changelog/index.md (URL unchanged)
- Add --integration flag to generate-changelog for LLM-based per-integration changelog generation
- Add scripts/release-integration.sh <name> <version> for cutting integration releases
- Add .github/workflows/release-integration.yml to publish on integrations/** tags
- Remove integrations from main release.sh and release.yml cycle
2026-03-18 17:36:52 +01:00
15 changed files with 976 additions and 297 deletions
+99
View File
@@ -0,0 +1,99 @@
name: Release Integration
on:
push:
tags:
- 'integrations/**'
jobs:
publish:
runs-on: ubuntu-latest
permissions:
id-token: write # for PyPI trusted publishing
steps:
- uses: actions/checkout@v6
- name: Extract integration info
id: info
run: |
# refs/tags/integrations/litellm/v0.1.0 → integration=litellm, version=0.1.0
TAG="${GITHUB_REF#refs/tags/}"
INTEGRATION=$(echo "$TAG" | cut -d'/' -f2)
VERSION=$(echo "$TAG" | cut -d'/' -f3 | sed 's/^v//')
echo "integration=$INTEGRATION" >> $GITHUB_OUTPUT
echo "version=$VERSION" >> $GITHUB_OUTPUT
echo "tag=$TAG" >> $GITHUB_OUTPUT
echo "Integration: $INTEGRATION, Version: $VERSION"
- name: Detect integration type
id: type
run: |
if [ -f "hindsight-integrations/${{ steps.info.outputs.integration }}/pyproject.toml" ]; then
echo "type=python" >> $GITHUB_OUTPUT
else
echo "type=typescript" >> $GITHUB_OUTPUT
fi
# ── Python integrations (litellm, pydantic-ai, crewai) ──────────────────
- name: Install uv
if: steps.type.outputs.type == 'python'
uses: astral-sh/setup-uv@v7
with:
enable-cache: true
- name: Set up Python
if: steps.type.outputs.type == 'python'
uses: actions/setup-python@v5
with:
python-version-file: ".python-version"
- name: Build Python package
if: steps.type.outputs.type == 'python'
working-directory: ./hindsight-integrations/${{ steps.info.outputs.integration }}
run: uv build --out-dir dist
- name: Publish Python package to PyPI
if: steps.type.outputs.type == 'python'
uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-dir: ./hindsight-integrations/${{ steps.info.outputs.integration }}/dist
skip-existing: true
# ── TypeScript integrations (ai-sdk, chat, openclaw) ────────────────────
- name: Set up Node.js
if: steps.type.outputs.type == 'typescript'
uses: actions/setup-node@v6
with:
node-version: '22'
registry-url: 'https://registry.npmjs.org'
- name: Install dependencies
if: steps.type.outputs.type == 'typescript'
working-directory: ./hindsight-integrations/${{ steps.info.outputs.integration }}
run: npm ci
- name: Build TypeScript package
if: steps.type.outputs.type == 'typescript'
working-directory: ./hindsight-integrations/${{ steps.info.outputs.integration }}
run: npm run build
- name: Publish TypeScript package to npm
if: steps.type.outputs.type == 'typescript'
working-directory: ./hindsight-integrations/${{ steps.info.outputs.integration }}
run: |
set +e
OUTPUT=$(npm publish --access public 2>&1)
EXIT_CODE=$?
echo "$OUTPUT"
if [ $EXIT_CODE -ne 0 ]; then
if echo "$OUTPUT" | grep -q "cannot publish over"; then
echo "Package version already published, skipping..."
exit 0
fi
exit $EXIT_CODE
fi
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
+1 -231
View File
@@ -46,30 +46,10 @@ jobs:
working-directory: ./hindsight-all-slim
run: uv build --out-dir dist
- name: Build hindsight-litellm
working-directory: ./hindsight-integrations/litellm
run: uv build --out-dir dist
- name: Build hindsight-embed
working-directory: ./hindsight-embed
run: uv build --out-dir dist
- name: Build hindsight-crewai
working-directory: ./hindsight-integrations/crewai
run: uv build --out-dir dist
- name: Build hindsight-pydantic-ai
working-directory: ./hindsight-integrations/pydantic-ai
run: uv build --out-dir dist
- name: Build hindsight-hermes
working-directory: ./hindsight-integrations/hermes
run: uv build --out-dir dist
- name: Build hindsight-agno
working-directory: ./hindsight-integrations/agno
run: uv build --out-dir dist
# Publish in order (client and api-slim first, then api/all wrappers which depend on them)
- name: Publish hindsight-client to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
@@ -101,42 +81,12 @@ jobs:
packages-dir: ./hindsight-all-slim/dist
skip-existing: true
- name: Publish hindsight-litellm to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-dir: ./hindsight-integrations/litellm/dist
skip-existing: true
- name: Publish hindsight-embed to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-dir: ./hindsight-embed/dist
skip-existing: true
- name: Publish hindsight-crewai to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-dir: ./hindsight-integrations/crewai/dist
skip-existing: true
- name: Publish hindsight-pydantic-ai to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-dir: ./hindsight-integrations/pydantic-ai/dist
skip-existing: true
- name: Publish hindsight-hermes to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-dir: ./hindsight-integrations/hermes/dist
skip-existing: true
- name: Publish hindsight-agno to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
packages-dir: ./hindsight-integrations/agno/dist
skip-existing: true
# Upload artifacts for GitHub release
- name: Upload artifacts
uses: actions/upload-artifact@v7
@@ -148,12 +98,7 @@ jobs:
hindsight-api/dist/*
hindsight-all/dist/*
hindsight-all-slim/dist/*
hindsight-integrations/litellm/dist/*
hindsight-embed/dist/*
hindsight-integrations/crewai/dist/*
hindsight-integrations/pydantic-ai/dist/*
hindsight-integrations/hermes/dist/*
hindsight-integrations/agno/dist/*
retention-days: 1
release-typescript-client:
@@ -205,153 +150,6 @@ jobs:
path: hindsight-clients/typescript/*.tgz
retention-days: 1
release-openclaw-integration:
runs-on: ubuntu-latest
environment: npm
steps:
- uses: actions/checkout@v6
- name: Set up Node.js
uses: actions/setup-node@v6
with:
node-version: '22'
registry-url: 'https://registry.npmjs.org'
- name: Install dependencies
working-directory: ./hindsight-integrations/openclaw
run: npm ci
- name: Build
working-directory: ./hindsight-integrations/openclaw
run: npm run build
- name: Publish to npm
working-directory: ./hindsight-integrations/openclaw
run: |
set +e
OUTPUT=$(npm publish --access public 2>&1)
EXIT_CODE=$?
echo "$OUTPUT"
if [ $EXIT_CODE -ne 0 ]; then
if echo "$OUTPUT" | grep -q "cannot publish over"; then
echo "Package version already published, skipping..."
exit 0
fi
exit $EXIT_CODE
fi
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Pack for GitHub release
working-directory: ./hindsight-integrations/openclaw
run: npm pack
- name: Upload artifacts
uses: actions/upload-artifact@v7
with:
name: openclaw-integration
path: hindsight-integrations/openclaw/*.tgz
retention-days: 1
release-ai-sdk-integration:
runs-on: ubuntu-latest
environment: npm
steps:
- uses: actions/checkout@v6
- name: Set up Node.js
uses: actions/setup-node@v6
with:
node-version: '22'
registry-url: 'https://registry.npmjs.org'
- name: Install dependencies
working-directory: ./hindsight-integrations/ai-sdk
run: npm ci
- name: Build
working-directory: ./hindsight-integrations/ai-sdk
run: npm run build
- name: Publish to npm
working-directory: ./hindsight-integrations/ai-sdk
run: |
set +e
OUTPUT=$(npm publish --access public 2>&1)
EXIT_CODE=$?
echo "$OUTPUT"
if [ $EXIT_CODE -ne 0 ]; then
if echo "$OUTPUT" | grep -q "cannot publish over"; then
echo "Package version already published, skipping..."
exit 0
fi
exit $EXIT_CODE
fi
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Pack for GitHub release
working-directory: ./hindsight-integrations/ai-sdk
run: npm pack
- name: Upload artifacts
uses: actions/upload-artifact@v7
with:
name: ai-sdk-integration
path: hindsight-integrations/ai-sdk/*.tgz
retention-days: 1
release-chat-integration:
runs-on: ubuntu-latest
environment: npm
steps:
- uses: actions/checkout@v6
- name: Set up Node.js
uses: actions/setup-node@v6
with:
node-version: '22'
registry-url: 'https://registry.npmjs.org'
- name: Install dependencies
working-directory: ./hindsight-integrations/chat
run: npm ci
- name: Build
working-directory: ./hindsight-integrations/chat
run: npm run build
- name: Publish to npm
working-directory: ./hindsight-integrations/chat
run: |
set +e
OUTPUT=$(npm publish --access public 2>&1)
EXIT_CODE=$?
echo "$OUTPUT"
if [ $EXIT_CODE -ne 0 ]; then
if echo "$OUTPUT" | grep -q "cannot publish over"; then
echo "Package version already published, skipping..."
exit 0
fi
exit $EXIT_CODE
fi
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
- name: Pack for GitHub release
working-directory: ./hindsight-integrations/chat
run: npm pack
- name: Upload artifacts
uses: actions/upload-artifact@v7
with:
name: chat-integration
path: hindsight-integrations/chat/*.tgz
retention-days: 1
release-control-plane:
runs-on: ubuntu-latest
environment: npm
@@ -609,7 +407,7 @@ jobs:
create-github-release:
runs-on: ubuntu-latest
needs: [release-python-packages, release-typescript-client, release-openclaw-integration, release-ai-sdk-integration, release-chat-integration, release-control-plane, release-rust-cli, release-docker-images, release-helm-chart]
needs: [release-python-packages, release-typescript-client, release-control-plane, release-rust-cli, release-docker-images, release-helm-chart]
permissions:
contents: write
@@ -632,24 +430,6 @@ jobs:
name: typescript-client
path: ./artifacts/typescript-client
- name: Download OpenClaw Integration
uses: actions/download-artifact@v8
with:
name: openclaw-integration
path: ./artifacts/openclaw-integration
- name: Download AI SDK Integration
uses: actions/download-artifact@v8
with:
name: ai-sdk-integration
path: ./artifacts/ai-sdk-integration
- name: Download Chat Integration
uses: actions/download-artifact@v8
with:
name: chat-integration
path: ./artifacts/chat-integration
- name: Download Control Plane
uses: actions/download-artifact@v8
with:
@@ -689,19 +469,9 @@ jobs:
cp artifacts/python-packages/hindsight-api/dist/* release-assets/ || true
cp artifacts/python-packages/hindsight-all/dist/* release-assets/ || true
cp artifacts/python-packages/hindsight-all-slim/dist/* release-assets/ || true
cp artifacts/python-packages/hindsight-integrations/litellm/dist/* release-assets/ || true
cp artifacts/python-packages/hindsight-integrations/pydantic-ai/dist/* release-assets/ || true
cp artifacts/python-packages/hindsight-integrations/hermes/dist/* release-assets/ || true
cp artifacts/python-packages/hindsight-integrations/agno/dist/* release-assets/ || true
cp artifacts/python-packages/hindsight-embed/dist/* release-assets/ || true
# TypeScript client
cp artifacts/typescript-client/*.tgz release-assets/ || true
# OpenClaw Integration
cp artifacts/openclaw-integration/*.tgz release-assets/ || true
# AI SDK Integration
cp artifacts/ai-sdk-integration/*.tgz release-assets/ || true
# Chat Integration
cp artifacts/chat-integration/*.tgz release-assets/ || true
# Control Plane
cp artifacts/control-plane/*.tgz release-assets/ || true
# Rust CLI binaries
+227 -30
View File
@@ -25,7 +25,10 @@ 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" / "src" / "pages" / "changelog.md"
CHANGELOG_PATH = REPO_PATH / "hindsight-docs" / "src" / "pages" / "changelog" / "index.md"
INTEGRATION_CHANGELOG_DIR = REPO_PATH / "hindsight-docs" / "src" / "pages" / "changelog" / "integrations"
VALID_INTEGRATIONS = ["litellm", "pydantic-ai", "crewai", "ai-sdk", "chat", "openclaw"]
class ChangelogEntry(BaseModel):
@@ -82,6 +85,31 @@ def get_git_tags() -> list[str]:
return valid_tags
def get_integration_tags(integration: str) -> list[str]:
"""Get all tags for a specific integration, sorted by semver (newest first)."""
prefix = f"integrations/{integration}/v"
result = subprocess.run(
["git", "tag", "-l", f"{prefix}*"],
cwd=REPO_PATH,
capture_output=True,
text=True,
check=True,
)
tags = [t.strip() for t in result.stdout.strip().split("\n") if t.strip()]
valid_tags = []
for tag in tags:
version_part = tag.removeprefix(prefix)
try:
parse_semver(version_part)
valid_tags.append(tag)
except ValueError:
continue
valid_tags.sort(key=lambda t: parse_semver(t.removeprefix(prefix)), reverse=True)
return valid_tags
def find_previous_version(new_version: str, existing_tags: list[str]) -> str | None:
"""Find the previous version based on semver rules."""
new_major, new_minor, new_patch = parse_semver(new_version)
@@ -105,13 +133,41 @@ def find_previous_version(new_version: str, existing_tags: list[str]) -> str | N
return candidates[0][0]
def get_commits(from_ref: str | None, to_ref: str) -> list[Commit]:
def find_previous_integration_tag(new_version: str, existing_tags: list[str], integration: str) -> str | None:
"""Find the previous integration tag based on semver rules."""
prefix = f"integrations/{integration}/v"
new_major, new_minor, new_patch = parse_semver(new_version)
candidates = []
for tag in existing_tags:
version_part = tag.removeprefix(prefix)
try:
major, minor, patch = parse_semver(version_part)
except ValueError:
continue
if (major, minor, patch) >= (new_major, new_minor, new_patch):
continue
candidates.append((tag, (major, minor, patch)))
if not candidates:
return None
candidates.sort(key=lambda x: x[1], reverse=True)
return candidates[0][0]
def get_commits(from_ref: str | None, to_ref: str, path_filter: str | None = None) -> list[Commit]:
"""Get commits between two refs as structured data."""
if from_ref:
cmd = ["git", "log", "--format=%h|%s", "--no-merges", f"{from_ref}..{to_ref}"]
else:
cmd = ["git", "log", "--format=%h|%s", "--no-merges", to_ref]
if path_filter:
cmd += ["--", path_filter]
result = subprocess.run(
cmd,
cwd=REPO_PATH,
@@ -131,13 +187,16 @@ def get_commits(from_ref: str | None, to_ref: str) -> list[Commit]:
return commits
def get_detailed_diff(from_ref: str | None, to_ref: str) -> str:
def get_detailed_diff(from_ref: str | None, to_ref: str, path_filter: str | None = None) -> str:
"""Get file change stats between two refs."""
if from_ref:
cmd = ["git", "diff", "--stat", f"{from_ref}..{to_ref}"]
else:
cmd = ["git", "diff", "--stat", f"{to_ref}^..{to_ref}"]
if path_filter:
cmd += ["--", path_filter]
result = subprocess.run(
cmd,
cwd=REPO_PATH,
@@ -153,11 +212,14 @@ def analyze_commits_with_llm(
version: str,
commits: list[Commit],
file_diff: str,
integration: str | None = None,
) -> list[ChangelogEntry]:
"""Use LLM to analyze commits and return structured changelog entries."""
commits_json = json.dumps([{"commit_id": c.hash, "message": c.message} for c in commits], indent=2)
prompt = f"""Analyze the following git commits for release {version} of Hindsight (an AI memory system).
subject = f"the {integration} integration for Hindsight" if integration else f"release {version} of Hindsight"
prompt = f"""Analyze the following git commits for {subject} (an AI memory system).
For each meaningful change, create a changelog entry with:
- category: one of "feature", "improvement", "bugfix", "breaking", "other"
@@ -192,9 +254,14 @@ def build_changelog_markdown(
version: str,
tag: str,
entries: list[ChangelogEntry],
integration: str | None = None,
) -> str:
"""Build markdown changelog from structured entries."""
release_url = f"{GITHUB_RELEASES_URL}/tag/{tag}"
tag_url = (
f"https://github.com/{GITHUB_REPO}/releases/tag/{tag}"
if not integration
else f"https://github.com/{GITHUB_REPO}/tree/{tag}"
)
# Group entries by category
categories = {
@@ -213,7 +280,7 @@ def build_changelog_markdown(
categories["other"][1].append(entry)
# Build markdown
lines = [f"## [{version}]({release_url})", ""]
lines = [f"## [{version}]({tag_url})", ""]
has_entries = False
for cat_key in ["breaking", "feature", "improvement", "bugfix", "other"]:
@@ -234,22 +301,12 @@ def build_changelog_markdown(
return "\n".join(lines)
def read_existing_changelog() -> tuple[str, str]:
def read_existing_changelog(path: Path, default_header: str) -> tuple[str, str]:
"""Read existing changelog and split into header and content."""
if not CHANGELOG_PATH.exists():
header = """---
hide_table_of_contents: true
---
if not path.exists():
return default_header, ""
# Changelog
This changelog highlights user-facing changes only. Internal maintenance, CI/CD, and infrastructure updates are omitted.
For full release details, see [GitHub Releases](https://github.com/vectorize-io/hindsight/releases).
"""
return header, ""
content = CHANGELOG_PATH.read_text()
content = path.read_text()
match = re.search(r"^## ", content, re.MULTILINE)
if match:
@@ -262,11 +319,11 @@ For full release details, see [GitHub Releases](https://github.com/vectorize-io/
return header, releases
def write_changelog(header: str, new_entry: str, existing_releases: str) -> None:
def write_changelog(path: Path, header: str, new_entry: str, existing_releases: str) -> None:
"""Write changelog with new entry prepended."""
content = header + new_entry + "\n" + existing_releases
CHANGELOG_PATH.parent.mkdir(parents=True, exist_ok=True)
CHANGELOG_PATH.write_text(content.rstrip() + "\n")
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(content.rstrip() + "\n")
def generate_changelog_entry(
@@ -329,22 +386,150 @@ def generate_changelog_entry(
new_entry = build_changelog_markdown(display_version, tag, entries)
header, existing_releases = read_existing_changelog()
default_header = """---
hide_table_of_contents: true
---
# Changelog
This changelog highlights user-facing changes only. Internal maintenance, CI/CD, and infrastructure updates are omitted.
For full release details, see [GitHub Releases](https://github.com/vectorize-io/hindsight/releases).
"""
header, existing_releases = read_existing_changelog(CHANGELOG_PATH, default_header)
if f"## [{display_version}]" in existing_releases:
console.print(f"[red]Error: Version {display_version} already exists in changelog[/red]")
sys.exit(1)
write_changelog(header, new_entry, existing_releases)
write_changelog(CHANGELOG_PATH, header, new_entry, existing_releases)
console.print(f"\n[green]Changelog updated: {CHANGELOG_PATH}[/green]")
console.print(f"\n[bold]New entry:[/bold]\n{new_entry}")
def generate_integration_changelog_entry(
integration: str,
version: str,
llm_model: str = "gpt-5.2",
) -> None:
"""Generate changelog entry for a specific integration version."""
if integration not in VALID_INTEGRATIONS:
console.print(f"[red]Error: Unknown integration '{integration}'. Valid: {', '.join(VALID_INTEGRATIONS)}[/red]")
sys.exit(1)
api_key = os.environ.get("OPENAI_API_KEY")
if not api_key:
console.print("[red]Error: OPENAI_API_KEY environment variable not set[/red]")
sys.exit(1)
client = OpenAI(api_key=api_key)
display_version = version.lstrip("v")
path_filter = f"hindsight-integrations/{integration}/"
changelog_path = INTEGRATION_CHANGELOG_DIR / f"{integration}.md"
console.print(f"[blue]Fetching integration tags for {integration}...[/blue]")
existing_tags = get_integration_tags(integration)
previous_tag = find_previous_integration_tag(display_version, existing_tags, integration)
if previous_tag:
console.print(f"[green]Found previous tag: {previous_tag}[/green]")
else:
console.print("[yellow]No previous tag found, will include all commits touching this integration[/yellow]")
console.print(f"[blue]Getting commits for {path_filter}...[/blue]")
commits = get_commits(previous_tag, "HEAD", path_filter=path_filter)
file_diff = get_detailed_diff(previous_tag, "HEAD", path_filter=path_filter)
if not commits:
console.print("[yellow]Warning: No commits found touching this integration path[/yellow]")
entries = []
else:
console.print(f"[blue]Found {len(commits)} commits[/blue]")
console.print("\n[bold]Commits:[/bold]")
for c in commits:
console.print(f" {c.hash} {c.message}")
console.print("\n[bold]Files changed:[/bold]")
console.print(file_diff[:4000] if len(file_diff) > 4000 else file_diff)
console.print("")
console.print(f"[blue]Analyzing commits with LLM ({llm_model})...[/blue]")
entries = analyze_commits_with_llm(
client, llm_model, display_version, commits, file_diff, integration=integration
)
console.print(f"\n[bold]LLM identified {len(entries)} changelog entries:[/bold]")
for entry in entries:
console.print(f" [{entry.category}] {entry.summary} ({entry.commit_id})")
integration_tag = f"integrations/{integration}/v{display_version}"
new_entry = build_changelog_markdown(display_version, integration_tag, entries, integration=integration)
package_name = _get_package_name(integration)
default_header = f"""---
hide_table_of_contents: true
---
# {_integration_display_name(integration)} Integration Changelog
Changelog for [`{package_name}`]({_package_url(integration, package_name)}).
For the source code, see [`hindsight-integrations/{integration}`](https://github.com/{GITHUB_REPO}/tree/main/hindsight-integrations/{integration}).
← [Back to main changelog](/changelog)
"""
header, existing_releases = read_existing_changelog(changelog_path, default_header)
if f"## [{display_version}]" in existing_releases:
console.print(f"[red]Error: Version {display_version} already exists in integration changelog[/red]")
sys.exit(1)
write_changelog(changelog_path, header, new_entry, existing_releases)
console.print(f"\n[green]Integration changelog updated: {changelog_path}[/green]")
console.print(f"\n[bold]New entry:[/bold]\n{new_entry}")
def _get_package_name(integration: str) -> str:
packages = {
"litellm": "hindsight-litellm",
"pydantic-ai": "hindsight-pydantic-ai",
"crewai": "hindsight-crewai",
"ai-sdk": "@vectorize-io/hindsight-ai-sdk",
"chat": "@vectorize-io/hindsight-chat",
"openclaw": "@vectorize-io/hindsight-openclaw",
}
return packages[integration]
def _package_url(integration: str, package_name: str) -> str:
if package_name.startswith("@"):
return f"https://www.npmjs.com/package/{package_name}"
return f"https://pypi.org/project/{package_name}/"
def _integration_display_name(integration: str) -> str:
names = {
"litellm": "LiteLLM",
"pydantic-ai": "Pydantic AI",
"crewai": "CrewAI",
"ai-sdk": "AI SDK",
"chat": "Chat SDK",
"openclaw": "OpenClaw",
}
return names.get(integration, integration)
def main():
parser = argparse.ArgumentParser(
description="Generate changelog entry for a release",
usage="generate-changelog VERSION [--model MODEL]",
usage="generate-changelog VERSION [--model MODEL] [--integration NAME]",
)
parser.add_argument(
"version",
@@ -355,13 +540,25 @@ def main():
default="gpt-5.2",
help="OpenAI model to use (default: gpt-5.2)",
)
parser.add_argument(
"--integration",
default=None,
help=f"Generate changelog for a specific integration. Valid: {', '.join(VALID_INTEGRATIONS)}",
)
args = parser.parse_args()
generate_changelog_entry(
version=args.version,
llm_model=args.model,
)
if args.integration:
generate_integration_changelog_entry(
integration=args.integration,
version=args.version,
llm_model=args.model,
)
else:
generate_changelog_entry(
version=args.version,
llm_model=args.model,
)
if __name__ == "__main__":
@@ -8,6 +8,17 @@ 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).
## Integration Changelogs
| Integration | Package | Description |
|---|---|---|
| [LiteLLM](/changelog/integrations/litellm) | `hindsight-litellm` | Universal LLM memory via LiteLLM (100+ providers) |
| [Pydantic AI](/changelog/integrations/pydantic-ai) | `hindsight-pydantic-ai` | Persistent memory tools for Pydantic AI agents |
| [CrewAI](/changelog/integrations/crewai) | `hindsight-crewai` | Persistent memory for CrewAI agents |
| [AI SDK](/changelog/integrations/ai-sdk) | `@vectorize-io/hindsight-ai-sdk` | Memory integration for Vercel AI SDK |
| [Chat SDK](/changelog/integrations/chat) | `@vectorize-io/hindsight-chat` | Memory integration for Vercel Chat SDK |
| [OpenClaw](/changelog/integrations/openclaw) | `@vectorize-io/hindsight-openclaw` | Hindsight memory plugin for OpenClaw |
## [0.4.19](https://github.com/vectorize-io/hindsight/releases/tag/v0.4.19)
**Features**
@@ -0,0 +1,11 @@
---
hide_table_of_contents: true
---
# AI SDK Integration Changelog
Changelog for [`@vectorize-io/hindsight-ai-sdk`](https://www.npmjs.com/package/@vectorize-io/hindsight-ai-sdk) — memory integration for Vercel AI SDK.
For the source code, see [`hindsight-integrations/ai-sdk`](https://github.com/vectorize-io/hindsight/tree/main/hindsight-integrations/ai-sdk).
← [Back to main changelog](/changelog)
@@ -0,0 +1,11 @@
---
hide_table_of_contents: true
---
# Chat SDK Integration Changelog
Changelog for [`@vectorize-io/hindsight-chat`](https://www.npmjs.com/package/@vectorize-io/hindsight-chat) — memory integration for Vercel Chat SDK.
For the source code, see [`hindsight-integrations/chat`](https://github.com/vectorize-io/hindsight/tree/main/hindsight-integrations/chat).
← [Back to main changelog](/changelog)
@@ -0,0 +1,11 @@
---
hide_table_of_contents: true
---
# CrewAI Integration Changelog
Changelog for [`hindsight-crewai`](https://pypi.org/project/hindsight-crewai/) — persistent memory for CrewAI agents.
For the source code, see [`hindsight-integrations/crewai`](https://github.com/vectorize-io/hindsight/tree/main/hindsight-integrations/crewai).
← [Back to main changelog](/changelog)
@@ -0,0 +1,11 @@
---
hide_table_of_contents: true
---
# LiteLLM Integration Changelog
Changelog for [`hindsight-litellm`](https://pypi.org/project/hindsight-litellm/) — universal LLM memory integration via LiteLLM.
For the source code, see [`hindsight-integrations/litellm`](https://github.com/vectorize-io/hindsight/tree/main/hindsight-integrations/litellm).
← [Back to main changelog](/changelog)
@@ -0,0 +1,11 @@
---
hide_table_of_contents: true
---
# OpenClaw Integration Changelog
Changelog for [`@vectorize-io/hindsight-openclaw`](https://www.npmjs.com/package/@vectorize-io/hindsight-openclaw) — Hindsight memory plugin for OpenClaw.
For the source code, see [`hindsight-integrations/openclaw`](https://github.com/vectorize-io/hindsight/tree/main/hindsight-integrations/openclaw).
← [Back to main changelog](/changelog)
@@ -0,0 +1,11 @@
---
hide_table_of_contents: true
---
# Pydantic AI Integration Changelog
Changelog for [`hindsight-pydantic-ai`](https://pypi.org/project/hindsight-pydantic-ai/) — persistent memory tools for Pydantic AI agents.
For the source code, see [`hindsight-integrations/pydantic-ai`](https://github.com/vectorize-io/hindsight/tree/main/hindsight-integrations/pydantic-ai).
← [Back to main changelog](/changelog)
@@ -0,0 +1,186 @@
---
sidebar_position: 9
---
# Agno
Persistent memory tools for [Agno](https://github.com/agno-agi/agno) agents via Hindsight. Give your agents long-term memory with retain, recall, and reflect — using Agno's native Toolkit pattern.
## Features
- **Native Toolkit** - Extends Agno's `Toolkit` base class, just like `Mem0Tools`
- **Memory Instructions** - Pre-recall memories for injection into `Agent(instructions=[...])`
- **Three Memory Tools** - Retain (store), Recall (search), Reflect (synthesize) — include any combination
- **Flexible Bank Resolution** - Static bank ID, `RunContext.user_id`, or custom resolver
- **Simple Configuration** - Configure once globally, or pass a client directly
## Installation
```bash
pip install hindsight-agno
```
## Quick Start
```python
from agno.agent import Agent
from agno.models.openai import OpenAIChat
from hindsight_agno import HindsightTools
agent = Agent(
model=OpenAIChat(id="gpt-4o-mini"),
tools=[HindsightTools(
bank_id="user-123",
hindsight_api_url="http://localhost:8888",
)],
)
agent.print_response("Remember that I prefer dark mode")
agent.print_response("What are my preferences?")
```
The agent now has three tools it can call:
- **`retain_memory`** — Store information to long-term memory
- **`recall_memory`** — Search long-term memory for relevant facts
- **`reflect_on_memory`** — Synthesize a reasoned answer from memories
## With Memory Instructions
Pre-recall relevant memories and inject them into the system prompt:
```python
from hindsight_agno import HindsightTools, memory_instructions
agent = Agent(
model=OpenAIChat(id="gpt-4o-mini"),
tools=[HindsightTools(
bank_id="user-123",
hindsight_api_url="http://localhost:8888",
)],
instructions=[memory_instructions(
bank_id="user-123",
hindsight_api_url="http://localhost:8888",
)],
)
```
## Selecting Tools
Include only the tools you need:
```python
tools = [HindsightTools(
bank_id="user-123",
hindsight_api_url="http://localhost:8888",
enable_retain=True,
enable_recall=True,
enable_reflect=False, # Omit reflect
)]
```
## Bank Resolution
The bank ID is resolved in order:
1. **`bank_resolver`** — Custom callable `(RunContext) -> str`
2. **`bank_id`** — Static bank ID passed to constructor
3. **`run_context.user_id`** — Automatic per-user banks
```python
# Per-user banks from RunContext
agent = Agent(
model=OpenAIChat(id="gpt-4o-mini"),
tools=[HindsightTools(hindsight_api_url="http://localhost:8888")],
user_id="user-123", # Used as bank_id
)
# Custom resolver
def resolve_bank(ctx):
return f"team-{ctx.user_id}"
agent = Agent(
model=OpenAIChat(id="gpt-4o-mini"),
tools=[HindsightTools(
bank_resolver=resolve_bank,
hindsight_api_url="http://localhost:8888",
)],
)
```
## Global Configuration
Instead of passing connection details to every toolkit, configure once:
```python
from hindsight_agno import configure, HindsightTools
configure(
hindsight_api_url="http://localhost:8888",
api_key="your-api-key", # Or set HINDSIGHT_API_KEY env var
budget="mid", # Recall budget: low/mid/high
max_tokens=4096, # Max tokens for recall results
tags=["env:prod"], # Tags for stored memories
recall_tags=["scope:global"], # Tags to filter recall
recall_tags_match="any", # Tag match mode: any/all/any_strict/all_strict
)
# Now create toolkit without passing connection details
tools = [HindsightTools(bank_id="user-123")]
```
## Configuration Reference
### `HindsightTools()`
| Parameter | Default | Description |
|---|---|---|
| `bank_id` | `None` | Static Hindsight memory bank ID |
| `bank_resolver` | `None` | Callable `(RunContext) -> str` for dynamic bank ID |
| `client` | `None` | Pre-configured Hindsight client |
| `hindsight_api_url` | `None` | API URL (used if no client provided) |
| `api_key` | `None` | API key (used if no client provided) |
| `budget` | `"mid"` | Recall/reflect budget level (low/mid/high) |
| `max_tokens` | `4096` | Maximum tokens for recall results |
| `tags` | `None` | Tags applied when storing memories |
| `recall_tags` | `None` | Tags to filter when searching |
| `recall_tags_match` | `"any"` | Tag matching mode |
| `enable_retain` | `True` | Include the retain (store) tool |
| `enable_recall` | `True` | Include the recall (search) tool |
| `enable_reflect` | `True` | Include the reflect (synthesize) tool |
### `memory_instructions()`
| Parameter | Default | Description |
|---|---|---|
| `bank_id` | *required* | Hindsight memory bank ID |
| `client` | `None` | Pre-configured Hindsight client |
| `hindsight_api_url` | `None` | API URL (used if no client provided) |
| `api_key` | `None` | API key (used if no client provided) |
| `query` | `"relevant context about the user"` | Recall query for memory injection |
| `budget` | `"low"` | Recall budget level |
| `max_results` | `5` | Maximum memories to inject |
| `max_tokens` | `4096` | Maximum tokens for recall results |
| `prefix` | `"Relevant memories:\n"` | Text prepended before memory list |
| `tags` | `None` | Tags to filter recall results |
| `tags_match` | `"any"` | Tag matching mode |
### `configure()`
| Parameter | Default | Description |
|---|---|---|
| `hindsight_api_url` | Production API | Hindsight API URL |
| `api_key` | `HINDSIGHT_API_KEY` env | API key for authentication |
| `budget` | `"mid"` | Default recall budget level |
| `max_tokens` | `4096` | Default max tokens for recall |
| `tags` | `None` | Default tags for retain operations |
| `recall_tags` | `None` | Default tags to filter recall |
| `recall_tags_match` | `"any"` | Default tag matching mode |
| `verbose` | `False` | Enable verbose logging |
## Requirements
- Python >= 3.10
- agno
- hindsight-client >= 0.4.0
- A running Hindsight API server
@@ -0,0 +1,219 @@
---
sidebar_position: 10
---
# Hermes Agent
Hindsight memory integration for [Hermes Agent](https://github.com/NousResearch/hermes-agent). Gives your Hermes agent persistent long-term memory via retain, recall, and reflect tools.
## What it does
This package registers three tools into Hermes via its plugin system:
- **`hindsight_retain`** — Stores information to long-term memory. Hermes calls this when the user shares facts, preferences, or anything worth remembering.
- **`hindsight_recall`** — Searches long-term memory for relevant information. Returns a numbered list of matching memories.
- **`hindsight_reflect`** — Synthesizes a thoughtful answer from stored memories. Use this when you want Hermes to reason over what it knows rather than return raw facts.
These tools appear under the `[hindsight]` toolset in Hermes's `/tools` list.
## Setup
### 1. Install hindsight-hermes into the Hermes venv
The package must be installed in the **same Python environment** that Hermes runs in, so the entry point is discoverable.
```bash
uv pip install hindsight-hermes --python $HOME/.hermes/hermes-agent/venv/bin/python
```
### 2. Set environment variables
The plugin reads its configuration from environment variables. Set these before launching Hermes:
```bash
# Required — tells the plugin where Hindsight is running
export HINDSIGHT_API_URL=http://localhost:8888
# Required — the memory bank to read/write. Think of this as a "brain" for one user or agent.
export HINDSIGHT_BANK_ID=my-agent
# Optional — only needed if using Hindsight Cloud (https://api.hindsight.vectorize.io)
export HINDSIGHT_API_KEY=your-api-key
# Optional — recall budget: low (fast), mid (default), high (thorough)
export HINDSIGHT_BUDGET=mid
```
If neither `HINDSIGHT_API_URL` nor `HINDSIGHT_API_KEY` is set, the plugin silently skips registration — Hermes starts normally without the Hindsight tools.
### 3. Disable Hermes's built-in memory tool
Hermes has its own `memory` tool that saves to local files (`~/.hermes/`). If both are active, the LLM tends to prefer the built-in one since it's familiar. Disable it so the LLM uses Hindsight instead:
```bash
hermes tools disable memory
```
This persists across sessions. You can re-enable it later with `hermes tools enable memory`.
### 4. Start Hindsight API
Follow the [Quick Start](/developer/api/quickstart) guide to get the Hindsight API running, then come back here.
### 5. Launch Hermes
```bash
hermes
```
Verify the plugin loaded by typing `/tools` — you should see:
```
[hindsight]
* hindsight_recall - Search long-term memory for relevant information.
* hindsight_reflect - Synthesize a thoughtful answer from long-term memories.
* hindsight_retain - Store information to long-term memory for later retrieval.
```
### 6. Test it
**Store a memory:**
> Remember that my favourite colour is red
You should see `⚡ hindsight` in the response, confirming it called `hindsight_retain`.
**Recall a memory:**
> What's my favourite colour?
**Reflect on memories:**
> Based on what you know about me, suggest a colour scheme for my IDE
This calls `hindsight_reflect`, which synthesizes a response from all stored memories.
**Verify via API:**
```bash
curl -s http://localhost:8888/v1/default/banks/my-agent/memories/recall \
-H "Content-Type: application/json" \
-d '{"query": "favourite colour", "budget": "low"}' | python3 -m json.tool
```
## Troubleshooting
### Tools don't appear in `/tools`
1. **Check the plugin is installed in the right venv.** Run this from the Hermes venv:
```bash
python -c "from hindsight_hermes import register; print('OK')"
```
2. **Check the entry point is registered:**
```bash
python -c "
import importlib.metadata
eps = importlib.metadata.entry_points(group='hermes_agent.plugins')
print(list(eps))
"
```
You should see `EntryPoint(name='hindsight', value='hindsight_hermes', group='hermes_agent.plugins')`.
3. **Check env vars are set.** The plugin skips registration silently if `HINDSIGHT_API_URL` and `HINDSIGHT_API_KEY` are both unset.
### Hermes uses built-in memory instead of Hindsight
Run `hermes tools disable memory` and restart. The built-in `memory` tool and Hindsight tools have overlapping purposes — the LLM will prefer whichever it's more familiar with, which is usually the built-in one.
### Bank not found errors
The plugin auto-creates banks on first use. If you see bank errors, check that the Hindsight API is running and `HINDSIGHT_API_URL` is correct.
### Connection refused
Make sure the Hindsight API is running and listening on the URL you configured. Test with:
```bash
curl http://localhost:8888/health
```
## Manual registration (advanced)
If you don't want to use the plugin system, you can register tools directly in a Hermes startup script or custom agent:
```python
from hindsight_hermes import register_tools
register_tools(
bank_id="my-agent",
hindsight_api_url="http://localhost:8888",
budget="mid",
tags=["hermes"], # applied to all retained memories
recall_tags=["hermes"], # filter recall to only these tags
)
```
This imports `tools.registry` from Hermes at call time and registers the three tools directly. This approach gives you more control over parameters but requires Hermes to be importable.
## Memory instructions (system prompt injection)
Pre-recall memories at startup and inject them into the system prompt, so the agent starts every conversation with relevant context:
```python
from hindsight_hermes import memory_instructions
context = memory_instructions(
bank_id="my-agent",
hindsight_api_url="http://localhost:8888",
query="user preferences and important context",
budget="low",
max_results=5,
)
# Returns:
# Relevant memories:
# 1. User's favourite colour is red
# 2. User prefers dark mode
```
This never raises — if the API is down or no memories exist, it returns an empty string.
## Global configuration (advanced)
Instead of passing parameters to every call, configure once:
```python
from hindsight_hermes import configure
configure(
hindsight_api_url="http://localhost:8888",
api_key="your-key",
budget="mid",
tags=["hermes"],
)
```
Subsequent calls to `register_tools()` or `memory_instructions()` will use these defaults if no explicit values are provided.
## MCP alternative
Hermes also supports MCP servers natively. You can use Hindsight's MCP server directly instead of this plugin — no `hindsight-hermes` package needed:
```yaml
# In your Hermes config
mcp_servers:
- name: hindsight
url: http://localhost:8888/mcp
```
This exposes the same retain/recall/reflect operations through Hermes's MCP integration. The tradeoff is that MCP tools may have different naming and the LLM needs to discover them, whereas the plugin registers tools with Hermes-native schemas.
## Configuration reference
| Parameter | Env Var | Default | Description |
|-----------|---------|---------|-------------|
| `hindsight_api_url` | `HINDSIGHT_API_URL` | `https://api.hindsight.vectorize.io` | Hindsight API URL |
| `api_key` | `HINDSIGHT_API_KEY` | — | API key for authentication |
| `bank_id` | `HINDSIGHT_BANK_ID` | — | Memory bank ID |
| `budget` | `HINDSIGHT_BUDGET` | `mid` | Recall budget (low/mid/high) |
| `max_tokens` | — | `4096` | Max tokens for recall results |
| `tags` | — | — | Tags applied when storing memories |
| `recall_tags` | — | — | Tags to filter recall results |
| `recall_tags_match` | — | `any` | Tag matching mode (any/all/any_strict/all_strict) |
| `toolset` | — | `hindsight` | Hermes toolset group name |
@@ -275,6 +275,22 @@
"icon": "/img/icons/pydanticai.png"
}
},
{
"type": "doc",
"id": "sdks/integrations/agno",
"label": "Agno",
"customProps": {
"icon": "/img/icons/agno.png"
}
},
{
"type": "doc",
"id": "sdks/integrations/hermes",
"label": "Hermes Agent",
"customProps": {
"icon": "/img/icons/hermes.png"
}
},
{
"type": "doc",
"id": "sdks/integrations/skills",
+148
View File
@@ -0,0 +1,148 @@
#!/bin/bash
set -e
cd "$(dirname "$0")/.."
# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
print_info() { echo -e "${GREEN}[INFO]${NC} $1"; }
print_warn() { echo -e "${YELLOW}[WARN]${NC} $1"; }
print_error() { echo -e "${RED}[ERROR]${NC} $1"; }
VALID_INTEGRATIONS=("litellm" "pydantic-ai" "crewai" "ai-sdk" "chat" "openclaw")
usage() {
print_error "Usage: $0 <integration> <version>"
echo ""
echo " integration One of: ${VALID_INTEGRATIONS[*]}"
echo " version Semantic version (e.g. 0.2.0)"
echo ""
echo "Examples:"
echo " $0 litellm 0.2.0"
echo " $0 pydantic-ai 1.0.0"
exit 1
}
if [ -z "$1" ] || [ -z "$2" ]; then
usage
fi
INTEGRATION=$1
VERSION=$2
# Validate integration name
VALID=false
for v in "${VALID_INTEGRATIONS[@]}"; do
if [ "$v" = "$INTEGRATION" ]; then
VALID=true
break
fi
done
if [ "$VALID" = "false" ]; then
print_error "Unknown integration '$INTEGRATION'"
print_info "Valid integrations: ${VALID_INTEGRATIONS[*]}"
exit 1
fi
# Validate version format
if ! [[ $VERSION =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
print_error "Invalid version format. Please use semantic versioning (e.g., 0.2.0)"
exit 1
fi
TAG="integrations/$INTEGRATION/v$VERSION"
print_info "Releasing $INTEGRATION v$VERSION (tag: $TAG)"
# Check if we're on main branch
CURRENT_BRANCH=$(git branch --show-current)
if [ "$CURRENT_BRANCH" != "main" ]; then
print_warn "You are not on the main branch (current: $CURRENT_BRANCH)"
read -p "Do you want to continue? (y/n) " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
print_error "Release cancelled"
exit 1
fi
fi
# Check if working directory is clean
if [[ -n $(git status -s) ]]; then
print_error "Working directory is not clean. Please commit or stash your changes."
git status -s
exit 1
fi
# Check if tag already exists
if git rev-parse "$TAG" >/dev/null 2>&1; then
print_error "Tag $TAG already exists"
exit 1
fi
# Load .env for OPENAI_API_KEY if needed
if [ -z "$OPENAI_API_KEY" ] && [ -f ".env" ]; then
print_info "Loading environment from .env"
set -a
source ".env"
set +a
fi
if [ -z "$OPENAI_API_KEY" ]; then
print_error "OPENAI_API_KEY is not set and no .env file found. Required for changelog generation."
exit 1
fi
# Determine integration type and update version
INTEGRATION_DIR="hindsight-integrations/$INTEGRATION"
if [ ! -d "$INTEGRATION_DIR" ]; then
print_error "Integration directory not found: $INTEGRATION_DIR"
exit 1
fi
if [ -f "$INTEGRATION_DIR/pyproject.toml" ]; then
print_info "Updating version in $INTEGRATION_DIR/pyproject.toml"
sed -i.bak "s/^version = \".*\"/version = \"$VERSION\"/" "$INTEGRATION_DIR/pyproject.toml"
rm "$INTEGRATION_DIR/pyproject.toml.bak"
elif [ -f "$INTEGRATION_DIR/package.json" ]; then
print_info "Updating version in $INTEGRATION_DIR/package.json"
sed -i.bak "s/\"version\": \".*\"/\"version\": \"$VERSION\"/" "$INTEGRATION_DIR/package.json"
rm "$INTEGRATION_DIR/package.json.bak"
else
print_error "No pyproject.toml or package.json found in $INTEGRATION_DIR"
exit 1
fi
# Generate changelog entry using LLM
print_info "Generating changelog entry..."
if cd hindsight-dev && uv run generate-changelog "$VERSION" --integration "$INTEGRATION"; then
cd ..
print_info "Changelog generated"
else
cd ..
print_error "Changelog generation failed"
git checkout .
exit 1
fi
# Commit version bump + changelog together
print_info "Committing changes..."
git add "hindsight-integrations/$INTEGRATION/" "hindsight-docs/src/pages/changelog/integrations/$INTEGRATION.md"
git commit --no-verify -m "release($INTEGRATION): v$VERSION"
# Create annotated tag
print_info "Creating tag $TAG..."
git tag -a "$TAG" -m "Release $INTEGRATION v$VERSION"
# Push commit and tag
print_info "Pushing to remote..."
git push origin "$CURRENT_BRANCH"
git push origin "$TAG"
print_info "✅ Released $INTEGRATION v$VERSION"
print_info "Tag: $TAG"
print_info "GitHub Actions will publish to the package registry."
+3 -36
View File
@@ -64,8 +64,8 @@ fi
print_info "Updating version in all components..."
# Update Python packages
PYTHON_PACKAGES=("hindsight-api" "hindsight-api-slim" "hindsight-all-slim" "hindsight-dev" "hindsight-all" "hindsight-integrations/litellm" "hindsight-integrations/crewai" "hindsight-integrations/pydantic-ai" "hindsight-integrations/hermes" "hindsight-integrations/agno" "hindsight-embed")
# Update Python packages (integrations are versioned independently via scripts/release-integration.sh)
PYTHON_PACKAGES=("hindsight-api" "hindsight-api-slim" "hindsight-all-slim" "hindsight-dev" "hindsight-all" "hindsight-embed")
for package in "${PYTHON_PACKAGES[@]}"; do
PYPROJECT_FILE="$package/pyproject.toml"
if [ -f "$PYPROJECT_FILE" ]; then
@@ -144,36 +144,6 @@ else
print_warn "File $TYPESCRIPT_CLIENT_PKG not found, skipping"
fi
# Update OpenClaw integration
OPENCLAW_PKG="hindsight-integrations/openclaw/package.json"
if [ -f "$OPENCLAW_PKG" ]; then
print_info "Updating $OPENCLAW_PKG"
sed -i.bak "s/\"version\": \".*\"/\"version\": \"$VERSION\"/" "$OPENCLAW_PKG"
rm "${OPENCLAW_PKG}.bak"
else
print_warn "File $OPENCLAW_PKG not found, skipping"
fi
# Update AI SDK integration
AI_SDK_PKG="hindsight-integrations/ai-sdk/package.json"
if [ -f "$AI_SDK_PKG" ]; then
print_info "Updating $AI_SDK_PKG"
sed -i.bak "s/\"version\": \".*\"/\"version\": \"$VERSION\"/" "$AI_SDK_PKG"
rm "${AI_SDK_PKG}.bak"
else
print_warn "File $AI_SDK_PKG not found, skipping"
fi
# Update Chat SDK integration
CHAT_SDK_PKG="hindsight-integrations/chat/package.json"
if [ -f "$CHAT_SDK_PKG" ]; then
print_info "Updating $CHAT_SDK_PKG"
sed -i.bak "s/\"version\": \".*\"/\"version\": \"$VERSION\"/" "$CHAT_SDK_PKG"
rm "${CHAT_SDK_PKG}.bak"
else
print_warn "File $CHAT_SDK_PKG not found, skipping"
fi
# Update documentation version (creates new version or syncs to existing)
print_info "Updating documentation for version $VERSION..."
if [ -f "scripts/update-docs-version.sh" ]; then
@@ -216,14 +186,11 @@ COMMIT_MSG="Release v$VERSION
- Update version to $VERSION in all components
- Regenerate OpenAPI spec and client SDKs
- Python packages: hindsight-api, hindsight-dev, hindsight-all, hindsight-litellm, hindsight-crewai, hindsight-pydantic-ai, hindsight-hermes, hindsight-agno, hindsight-embed
- Python packages: hindsight-api, hindsight-dev, hindsight-all, hindsight-embed
- Python client: hindsight-clients/python
- TypeScript client: hindsight-clients/typescript
- Rust CLI: hindsight-cli
- Control Plane: hindsight-control-plane
- OpenClaw integration: hindsight-integrations/openclaw
- AI SDK integration: hindsight-integrations/ai-sdk
- Chat SDK integration: hindsight-integrations/chat
- Helm chart"
# Add docs update note