Skip to content

[WIP] A1: adapter extraction + overlay-fallback fix (stacked on #165) — do not merge#169

Closed
NimbleCoAI wants to merge 3 commits into
mainfrom
dev/juniperbevensee/letta-a1-adapter-extraction
Closed

[WIP] A1: adapter extraction + overlay-fallback fix (stacked on #165) — do not merge#169
NimbleCoAI wants to merge 3 commits into
mainfrom
dev/juniperbevensee/letta-a1-adapter-extraction

Conversation

@NimbleCoAI

Copy link
Copy Markdown
Owner

Slice A1 of Swarm Map v1 (spec: memory/specs/2026-07-19-swarm-map-v1-definition.md §2.A1; design: 2026-07-18-letta-wizard-fork-design.md §1b Phase 2). Stacked on #165 — do not merge until launch sequence.

What

  1. Adapter extraction (Phase 2, mechanical): ContainerRuntimeAdapter gains the provisioning surface (serviceName, generateCompose, scaffold) and CD image-ref surface (readImageRef, setImageRef, defaultImageRepo). hermesAdapter delegates to the exact module functions the call sites used inline — behavior-preserving.
  2. The adapter ?? hermesAdapter landmine fix: discover()'s overlay-only branch now dispatches on the overlay's persisted runtime via adapterForRuntime() instead of blindly defaulting to Hermes — fixed before a 2nd adapter exists, per the spec. Pre-seam rows (no runtime field) keep Hermes semantics.
  3. Dispatch sites rewired: resolveComposeTarget, currentImage, imageStatus, setAgentImage, duplicate (source's runtime), createOverlay/importFromDir (Hermes-only creation paths, explicit), and the settings-route compose regen.
  4. registerContainerAdapter() for future runtimes (claude-code-proxy/custom — explicitly NOT wired in v1, per spec §4).

Verification

  • 727/727 vitest (incl. new runtime-adapter.test.ts: selection semantics + delegation round-trips)
  • tsc --noEmit clean
  • eslint: only pre-existing no-explicit-any errors in settings route (verified identical on base)

🤖 Generated with Claude Code

juniperbevensee and others added 3 commits July 18, 2026 11:18
…y view (Path 1)

Proof (spike, do not merge) that HSM can run a Letta *server* as a managed
container via the existing runtime-neutral DockerService, and CRUD/message
individual Letta agents over REST as a separate "agents-as-API-resources"
layer distinct from the container model.

- docker/letta-compose.yml: letta/letta server, :8283, embedded Postgres
  volume (commented shared-pgvector alt). Managed by DockerService unchanged.
- lib/services/letta.ts: minimal fetch REST client — listAgents, getAgent,
  createAgent, sendMessage, getMemoryBlocks. Base URL from LETTA_BASE_URL,
  defaults http://localhost:8283. Loosely typed (spike).
- app/api/letta/*: same-origin proxy routes (list / send message / blocks).
- app/(dashboard)/letta: read-only agents view + single send-message action.
- Sidebar: "Letta" nav entry.

Out of scope: airlock, wizard integration, runtime-adapter refactor, no
lib/types.ts changes on main. Typecheck + lint pass.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
First slice of the Letta wizard/base-package fork (design
2026-07-18-letta-wizard-fork-design.md, §5 recommended first slice). Stacks
on the Letta REST spike (#163, branch swarm-map-letta-runtime). Entirely
additive; no live Letta server required to compile.

Phase 0 (discriminator + server-as-Harness):
- lib/types.ts: extend Harness.runtime union with 'letta' + 'letta-server'
  (the one additive types.ts change the spike deliberately avoided).
- lib/services/runtime-adapter.ts: ContainerRuntimeAdapter interface — the
  container-runtime seam (design §1b), discovery surface only.
- lib/services/harness.ts: hermesAdapter + pickContainerAdapter registry;
  discover() now dispatches the discovery gate / runtime / dataDir / persona /
  models through the adapter instead of the inline hermes-/seraph- string gate.
  Behavior-preserving extraction — hermesAdapter delegates to the same
  module-local guessDataDir/readSoul/readModelConfig, overlay-only containers
  keep hermes semantics via `effAdapter = adapter ?? hermesAdapter`.
- lib/services/letta-agent-provider.ts: AgentResourceProvider (Letta) — maps
  LettaAgent -> Harness (design §1c), plus the Letta server as a
  container-backed 'letta-server' Harness. Read-only (list/get) in this slice.
- lib/services/index.ts: wire the provider as services.lettaAgents.

Phase 1 read-only half (UI degradation):
- app/api/letta/harnesses: fleet-list endpoint (server + agents as Harness[]).
- app/api/harnesses/[id]: GET branches to the Letta provider for h_letta_* ids.
- components/harness/letta-agent-detail.tsx: dedicated read-only Letta detail
  view — model handle instead of CPU/mem, memory-block viewer, message viewer
  in place of the container Logs tab, no lifecycle buttons (design §4a).
- harnesses/[id]/page.tsx: runtime-branching wrapper early-returns to the Letta
  view; existing Hermes page renamed HermesHarnessDetail, otherwise untouched.
- harnesses/page.tsx: merge Letta harnesses into the fleet list; Letta rows
  degrade to Open only (no restart/stop/duplicate/remove), no cost/inv stats.

Deferred to later phases (clear TODOs in-code): adapter extraction of
generateCompose/scaffold/image-ref (Phase 2, touches Hermes deploy — untouched
here), wizard runtime toggle + deploy branch (Phase 3), live-server validation
of create/message/block shapes (Phase 4), Librarian package + airlock (Phase 5).

Verify: tsc --noEmit clean; eslint clean on all new files (pre-existing
warnings/1 error remain in untouched ModelCascadeEditor code); 6/6 existing
harness.test.ts pass (behavior preservation).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…ntainerRuntimeAdapter, fix overlay-fallback dispatch

Phase 2 of the wizard-fork design (memory/specs/2026-07-18-letta-wizard-fork-design.md §1b, §5):

- ContainerRuntimeAdapter gains the provisioning surface (serviceName,
  generateCompose, scaffold) and the CD image-ref surface (readImageRef,
  setImageRef, defaultImageRepo). hermesAdapter delegates to the same
  module functions the call sites used inline — zero behavior change.
- Fix the `adapter ?? hermesAdapter` landmine: discover()'s overlay-only
  branch now dispatches on the overlay's PERSISTED runtime via
  adapterForRuntime(), not a blind Hermes fallback. Pre-seam rows
  (no runtime field) keep Hermes semantics.
- HarnessService dispatch sites (resolveComposeTarget, currentImage,
  imageStatus, setAgentImage, duplicate, createOverlay, importFromDir)
  and the settings route now go through the adapter.
- registerContainerAdapter() for future runtimes (claude-code-proxy/custom).

727/727 tests, tsc clean. New: runtime-adapter.test.ts (selection + delegation).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@juniperbevensee
juniperbevensee changed the base branch from dev/juniperbevensee/swarm-map-letta-wizard-fork to main July 22, 2026 01:20
@juniperbevensee
juniperbevensee marked this pull request as ready for review July 22, 2026 01:20
@juniperbevensee

Copy link
Copy Markdown
Collaborator

A-track landed as one clean linear chain via #172 (rebase cascade from #165's SHA rewrite made per-PR merges conflict on stale spike/seam ancestors). This slice's commit is on main. See memory/plans/2026-07-22-swarm-map-v1-track.md.

@juniperbevensee
juniperbevensee deleted the dev/juniperbevensee/letta-a1-adapter-extraction branch July 22, 2026 01:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants