Skip to content

fix: isolate self-hosted Letta MCP tools - #609

Closed
AlexanderZ-Band wants to merge 1 commit into
mainfrom
feat/letta-self-host-shared-org-mcp-tool-dedup-breaks-m-INT-985
Closed

fix: isolate self-hosted Letta MCP tools#609
AlexanderZ-Band wants to merge 1 commit into
mainfrom
feat/letta-self-host-shared-org-mcp-tool-dedup-breaks-m-INT-985

Conversation

@AlexanderZ-Band

Copy link
Copy Markdown
Collaborator

Summary

  • provision a dedicated self-hosted Letta organization and user per adapter instance, preventing MCP tool rows from being repointed across agents
  • use normalized Letta Cloud hostname detection so equivalent Cloud URLs never take the self-hosted admin path
  • re-enable the Letta partial-rehydration matrix scenario and add unit/live integration coverage

Verification

  • uv run pytest tests/adapters/test_letta_mcp.py tests/adapters/test_deprecation_shims.py tests/adapters/test_letta_orgscope.py -q --no-cov
  • uv run ruff check ...
  • uv run pyrefly check src/band/adapters/letta.py src/band/integrations/letta/config.py

Closes INT-985

@linear-code

linear-code Bot commented Sep 4, 2026

Copy link
Copy Markdown

INT-985

AlexanderZ-Band added a commit that referenced this pull request Sep 4, 2026
PR #609 correctly classified Letta Cloud via urlsplit(...).hostname
(case-insensitive, trailing-slash-agnostic) but had a whitespace gap.
This branch's pagination/live-test fixes superseded #609 as the base
for INT-985, but its cloud-detection rewrite regressed to a raw
base_url string compare that no longer normalizes host casing,
silently misclassifying a Cloud URL as self-hosted and bypassing the
org_scoped+Cloud construction guard.

Restore is_letta_cloud_url() with a .strip() added to close the
whitespace gap, restore the case/trailing-slash regression tests
dropped when the helper was removed, and add a whitespace case to
both. Also fixes a stale docstring in test_rehydration_partial.py
that still described the Letta exclusion as unresolved after the
code below it already re-enabled Letta in that scenario.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013ezy1XrPH9G8wScBdjBLvA
@AlexanderZ-Band

Copy link
Copy Markdown
Collaborator Author

Closing as a duplicate of #610 for the same ticket (INT-985) — #610 already fixed both critical bugs found in review of this PR (the org/user pagination-stall hang and the broken live cross-instance isolation test), and #610 has now also picked up this PR's correct case/trailing-slash-insensitive Cloud URL detection (with a whitespace-trim fix on top). See #610 for the consolidated fix.

@AlexanderZ-Band AlexanderZ-Band added the duplicate This issue or pull request already exists label Sep 4, 2026
AlexanderZ-Band added a commit that referenced this pull request Sep 5, 2026
…tion.py

tests/runtime/test_execution.py had a recurring anti-pattern: start
background async work, sleep a fixed duration, then assert on mock
call counts or internal state that depends on that work having
finished. Under CI load the fixed sleep isn't always long enough --
this surfaced as real flakes on PR #610's CI
(test_pending_next_message_present_in_context_still_executes, twice)
and PR #609's CI (test_sync_removes_duplicate_from_ws_queue, a
different commit, same class).

tests/runtime/test_resync.py already had the correct fix pattern
locally: a wait_for_condition(predicate, timeout, interval) poller.
Hoist it into tests/runtime/conftest.py as the shared source of
truth, and convert every settle-then-assert sleep in
test_execution.py (and two in TestExecutionContextEvents/
TestExecutionContextParticipantEvents) to wait on the exact predicate
the following assertion checks -- ctx._sync_complete, ctx.is_processing,
ctx.queue.qsize(), or a mock call/await count.

Left untouched: sleeps that are the actual behavior under test (a
deliberately slow fake handler body, a real elapsed-time threshold
assertion), an asyncio.sleep(0) yield-once idiom, and two sleeps whose
following assertions don't actually depend on the sleep's duration.

Verified with 10 repeated full-file runs, 30 repeated runs of the two
previously-observed-flaky tests, and one run under artificial CPU
contention -- zero failures, and the suite runs faster (~1.4s vs
~4-5s) since polling resolves as soon as the condition is true instead
of always waiting out the fixed sleep.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_013ezy1XrPH9G8wScBdjBLvA
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

duplicate This issue or pull request already exists

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant