test(core): git-backed memory repo integration (real object store) (#9298)
--------- Co-authored-by: Letta <noreply@letta.com>
This commit is contained in:
committed by
Caren Thomas
parent
0bdedb3c0f
commit
93249b96f5
3
.github/workflows/core-integration-tests.yml
vendored
3
.github/workflows/core-integration-tests.yml
vendored
@@ -41,7 +41,8 @@ jobs:
|
|||||||
"integration_test_batch_api_cron_jobs.py",
|
"integration_test_batch_api_cron_jobs.py",
|
||||||
"integration_test_builtin_tools.py",
|
"integration_test_builtin_tools.py",
|
||||||
"integration_test_turbopuffer.py",
|
"integration_test_turbopuffer.py",
|
||||||
"integration_test_human_in_the_loop.py"
|
"integration_test_human_in_the_loop.py",
|
||||||
|
"integration_test_git_memory_repo_http.py"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
4
.github/workflows/reusable-test-workflow.yml
vendored
4
.github/workflows/reusable-test-workflow.yml
vendored
@@ -381,6 +381,10 @@ jobs:
|
|||||||
GOOGLE_CLOUD_PROJECT: ${{ secrets.GOOGLE_CLOUD_PROJECT }}
|
GOOGLE_CLOUD_PROJECT: ${{ secrets.GOOGLE_CLOUD_PROJECT }}
|
||||||
GOOGLE_CLOUD_LOCATION: ${{ secrets.GOOGLE_CLOUD_LOCATION }}
|
GOOGLE_CLOUD_LOCATION: ${{ secrets.GOOGLE_CLOUD_LOCATION }}
|
||||||
|
|
||||||
|
# Real object store (required for git-backed memory integration test)
|
||||||
|
# Use DEV bucket/prefix variable to avoid prod resources.
|
||||||
|
LETTA_OBJECT_STORE_URI: ${{ vars.LETTA_OBJECT_STORE_URI_DEV }}
|
||||||
|
|
||||||
# Feature flags (shared across all test types)
|
# Feature flags (shared across all test types)
|
||||||
LETTA_ENABLE_BATCH_JOB_POLLING: true
|
LETTA_ENABLE_BATCH_JOB_POLLING: true
|
||||||
|
|
||||||
|
|||||||
@@ -465,12 +465,14 @@ async def _sync_after_push(actor_id: str, agent_id: str) -> None:
|
|||||||
logger.exception("Failed to read repo files from storage for post-push block sync (agent=%s)", agent_id)
|
logger.exception("Failed to read repo files from storage for post-push block sync (agent=%s)", agent_id)
|
||||||
files = {}
|
files = {}
|
||||||
|
|
||||||
|
expected_labels = set()
|
||||||
synced = 0
|
synced = 0
|
||||||
for file_path, content in files.items():
|
for file_path, content in files.items():
|
||||||
if not file_path.startswith("blocks/") or not file_path.endswith(".md"):
|
if not file_path.startswith("blocks/") or not file_path.endswith(".md"):
|
||||||
continue
|
continue
|
||||||
|
|
||||||
label = file_path[len("blocks/") : -3]
|
label = file_path[len("blocks/") : -3]
|
||||||
|
expected_labels.add(label)
|
||||||
await _server_instance.block_manager._sync_block_to_postgres(
|
await _server_instance.block_manager._sync_block_to_postgres(
|
||||||
agent_id=agent_id,
|
agent_id=agent_id,
|
||||||
label=label,
|
label=label,
|
||||||
@@ -482,6 +484,36 @@ async def _sync_after_push(actor_id: str, agent_id: str) -> None:
|
|||||||
|
|
||||||
if synced == 0:
|
if synced == 0:
|
||||||
logger.warning("No blocks/*.md files found in repo HEAD during post-push sync (agent=%s)", agent_id)
|
logger.warning("No blocks/*.md files found in repo HEAD during post-push sync (agent=%s)", agent_id)
|
||||||
|
else:
|
||||||
|
# Detach blocks that were removed in git.
|
||||||
|
#
|
||||||
|
# We treat git as the source of truth for which blocks are attached to
|
||||||
|
# this agent. If a blocks/*.md file disappears from HEAD, detach the
|
||||||
|
# corresponding block from the agent in Postgres.
|
||||||
|
try:
|
||||||
|
existing_blocks = await _server_instance.agent_manager.list_agent_blocks_async(
|
||||||
|
agent_id=agent_id,
|
||||||
|
actor=actor,
|
||||||
|
before=None,
|
||||||
|
after=None,
|
||||||
|
limit=1000,
|
||||||
|
ascending=True,
|
||||||
|
)
|
||||||
|
existing_by_label = {b.label: b for b in existing_blocks}
|
||||||
|
removed_labels = set(existing_by_label.keys()) - expected_labels
|
||||||
|
|
||||||
|
for label in sorted(removed_labels):
|
||||||
|
block = existing_by_label.get(label)
|
||||||
|
if not block:
|
||||||
|
continue
|
||||||
|
await _server_instance.agent_manager.detach_block_async(
|
||||||
|
agent_id=agent_id,
|
||||||
|
block_id=block.id,
|
||||||
|
actor=actor,
|
||||||
|
)
|
||||||
|
logger.info("Detached block %s from agent (removed from git)", label)
|
||||||
|
except Exception:
|
||||||
|
logger.exception("Failed detaching removed blocks during post-push sync (agent=%s)", agent_id)
|
||||||
|
|
||||||
# Cleanup local cache
|
# Cleanup local cache
|
||||||
_repo_cache.pop(cache_key, None)
|
_repo_cache.pop(cache_key, None)
|
||||||
|
|||||||
Reference in New Issue
Block a user