microsoft / microsoft/Huabu

refactor(agenetes): address durable threads by globally unique threadId

Open
#58 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

enhancement
Dominant language
TypeScript
Stars
146
Forks
20
Avg merge
2d 6h
Merged PRs (30d)
43

Description

Summary

Refactor Agenetes so a durable thread is identified and addressed solely by its globally unique threadId. Namespace remains an internal persistence-placement concept that preserves per-Space physical storage; it must not remain part of the public thread identity or be required repeatedly by query and invocation callers.

This is a legacy cleanup, not a prerequisite for the long-horizon task capability in docs/proposals/long-horizon-tasks.md. Huabu can continue deriving the current Canvas namespace inside its composition adapters while the refactor is pending.

Current problem

The current implementation has inconsistent identity surfaces:

  • live handles are addressed globally by threadId;
  • durable records, history, event tails, and forks require (Namespace, threadId);
  • Namespace includes optional storage configuration such as storage.root, so a persistence implementation detail leaks into general thread APIs;
  • callers reconstruct the same Canvas namespace repeatedly even though the thread's storage placement was fixed when the workload was created.

The namespace parameter exists to preserve the historical per-Space storage layout and forward compatibility. It should not redefine thread identity as a composite key.

Desired model

threadId
  -> durable thread locator: threadId -> namespaceId
  -> namespace registry/resolver: namespaceId -> Namespace storage configuration
  -> per-namespace ThreadStore / EventLogStore / TurnStore
  • threadId is the globally unique thread identity and the only address required by thread query, recovery, control, and invocation APIs.
  • Creating a durable workload supplies a trusted namespaceId to select persistence placement.
  • Agenetes durably binds the new threadId to that namespace and resolves storage internally on later access.
  • Namespace configuration is registered or resolved by the trusted host composition layer; callers cannot inject storage.root into ordinary thread operations.
  • Existing per-Space on-disk storage remains supported.

Expected API direction

Thread-oriented operations should converge on shapes such as:

record(threadId)
history(threadId)
tail(threadId)
get(threadId)
close(threadId)
invoke(threadId, submission)

The exact locator and namespace-registry contracts should be designed before implementation. This issue does not require adding invoke if that operation is not otherwise ready; it requires any eventual invocation surface to follow the same identity rule.

Compatibility and migration requirements

  • Preserve existing thread records and conversation logs stored under each Space's .history directory.
  • Add a durable or deterministically rebuildable thread locator without scanning every namespace on each lookup.
  • Migrate or compatibly read persisted WorkloadSpec.namespace records while preserving their namespace assignment.
  • Keep namespace assignment immutable for an existing thread unless a future explicit storage migration is designed.
  • Ensure cold recovery resolves the same persisted workload and conversation using only threadId.
  • Retain fail-fast handling for duplicate or conflicting global thread IDs.

Acceptance criteria

  • Public Agenetes thread lookup/query/control APIs no longer require a Namespace object.
  • A durable thread can be cold-located and recovered from threadId alone.
  • Namespace storage configuration is resolved internally from trusted registration or host wiring.
  • Existing per-Space thread, event, and turn files remain readable without data loss.
  • Live and durable surfaces use the same global threadId identity rule.
  • Huabu call sites no longer reconstruct and pass a Namespace for every thread operation.
  • The identity and storage-placement distinction is documented in the Agenetes architecture.

Non-goals

  • Combining namespaceId and threadId into a composite Thread identity.
  • Moving all conversations into one global storage directory.
  • Changing Agent Node identity or the Canvas ownership of a thread.
  • Blocking long-horizon Agent Node creation, recursive delegation, or headless invocation work.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by tracing the Agenetes thread lookup, recovery, control, and invocation APIs, then inspect Huabu call sites that reconstruct and pass Namespace values. Read docs/proposals/long-horizon-tasks.md for the stated boundary, and use the acceptance criteria to verify threadId-only recovery, preserved per-Space files, compatibility, and documented identity rules.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
api, backend, databases
Issue type
Refactor
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.