Skip to content

Convergence audit: merge parallel WordPress agents-api extractions #77

@lezama

Description

@lezama

Goal

Two parallel extraction efforts have been building toward an OSS-able WordPress-shaped agents substrate from different starting points:

  • This repo (Automattic/agents-api), extracted from Extra-Chill/data-machine.
  • A second extraction inside a large WordPress install, extracting from a lib/ai/agents/ runtime into a local mu-plugins/agents-api/ package.

The goal is a single OSS plugin that both major adopters (and any future consumer) build on top of, with zero forks. This issue is the convergence map: what overlaps, what diverges, and the PR sequence to land canonical.

Inventory comparison

Already in canonical (this repo) but not in the second extraction

The substrate has shipped a much wider contract surface in PRs #65#73:

  • src/Approvals/ — pending action / approval primitives
  • src/Auth/ — access grants, token store, capability ceiling, authorization policy
  • src/Consent/ — consent policy contracts
  • src/Context/ — composable context, memory layer/registry, authority cascade, conflict resolution
  • src/Identity/ — agent identity scope, materialized identity, store
  • src/Memory/ — full memory store contracts (with workspace + provenance)
  • src/Packages/ — agent package + artifact registry
  • src/Runtime/AgentConversationLoop, completion policy, transcript persister, compaction, iteration budget, execution principal, message envelope
  • src/Tools/ — tool execution core, source registry, action policy, runtime tool declaration
  • src/Transcripts/ConversationTranscriptStoreInterface
  • src/Workspace/AgentWorkspaceScope

In the second extraction but not in canonical

  1. Heavy WP_Agent runtime base class that integrates LLM loop + provider + session + memory + hooks + context tree + token streaming + async + compaction in one class. Canonical's pattern is the opposite: thin value object (Registry/class-wp-agent.php) + AgentConversationLoop composition.

  2. Five typed lifecycle event objectsWP_Agent_Stream_Delta, WP_Agent_Progress, WP_Agent_Queued, WP_Agent_Input_Required, WP_Agent_Final_Result. These are the working precedent for the typed-events option in Clarify event sink contract: on_event callable vs documented filter #75 (already commented there with detail).

  3. Concrete memory stores — guideline-backed and markdown-backed implementations of the memory store interface. Data Machine has parallel implementations of the same shape (DiskAgentMemoryStore, GuidelineAgentMemoryStore). See companion proposal: "agents-api-default-stores companion plugin" — separate issue to follow.

  4. Concrete CPT-backed session store — implements the conversation transcript contract. Same default-stores question applies.

  5. Provider abstractionWP_Agent_Provider interface, WP_Agent_Provider_Factory, WP_Ai_Client_Provider. Canonical's README explicitly excludes provider code (delegates to wp-ai-client). The second extraction's provider classes stay outside the substrate as the host's adapter — this is the right boundary, no convergence needed here.

Same idea, different name

Convergence means picking one name and migrating the other:

Second extraction Canonical Notes
WP_Agent_Conversation_Store (interface) ConversationTranscriptStoreInterface Same shape, different namespace
WP_Agent_Memory_Store (interface) AgentMemoryStoreInterface Same shape, canonical's adds workspace fields
WP_Agents_Registry WP_Agents_Registry Both exist; merge to canonical
WP_Agent (value object aspects) WP_Agent (value object) Both exist; canonical's is already the thin shape
WP_Agent_Message, WP_Agent_Tool_Call, WP_Agent_Tool_Result AgentMessageEnvelope, Tools/ToolCall, Tools/ToolExecutionResult Comparable; canonical wins on namespacing

Convergence PR sequence

In order, smallest to largest:

  1. Lift typed lifecycle events into canonical (src/Runtime/Events/). Parallel implementation can switch to use AgentsAPI\\AI\\Runtime\\Events\\… once landed. Resolves Clarify event sink contract: on_event callable vs documented filter #75. Small.

  2. Land conversation lock/unlock on ConversationTranscriptStoreInterface (Add conversation lock/unlock to ConversationTranscriptStoreInterface #74). Both extractions need this for long-running loops; canonical defines the contract once. Small.

  3. Land cross-site A2A caller context (Add cross-site agent-to-agent caller context primitive #76). Substrate defines WP_Agent_Caller_Context + the header convention. Medium.

  4. Default-stores companion plugin — extract the two pairs of parallel memory store impls (guideline-backed, markdown/disk-backed) plus the CPT session store into agents-api-default-stores. Removes duplication; gives outside adopters working stores from day one. Medium, separate issue.

  5. Refactor the second extraction's WP_Agent to thin value object + AgentConversationLoop composition. All current behavior of the heavy base class is reachable through the loop's adapter slots: provider via the runner adapter, memory via the store adapters, transcript via the persister adapter, lifecycle via the typed events from step 1, compaction via the existing AgentConversationCompaction class, async/queued via the Queued typed event. Large. The architectural lift.

  6. Replace local interface declarations with canonical imports in the second extraction. Drop WP_Agent_Conversation_Store, WP_Agent_Memory_Store, WP_Agent_Provider (provider stays as a host-side adapter, just stops being declared as a substrate interface). Small mechanical PR after step 5.

  7. Vendor canonical in the second extraction via git subtree at the original agents-api/ path. The mu-plugin package becomes the host-side adapter only. Small.

Verification — non-regression on every concrete agent

The second extraction has many concrete WP_Agent subclasses already running in production (block editing, site building, P2 chat, reader chat, support, orchestrator, internal tooling, workflow agents, and more). Each one is a risk surface for the refactor in step 5.

The convergence cannot land without a verification story. Proposed gates:

  • Contract tests against every concrete agent. A test harness that instantiates each subclass, runs a fixed prompt + tool sequence against a recorded provider, and asserts the produced messages, tool calls, and final result match a recorded baseline. Lives in the consumer (the second extraction), runs in CI on every convergence PR. Recordings produced from the current heavy WP_Agent before any refactor.

  • Sandboxed shadow runs. For the higher-traffic agents (chat-facing ones), route a fraction of real production traffic through both the legacy and refactored paths, diff the produced transcripts, alert on divergence. Ramp-up gated.

  • Per-feature smoke abilities. Each agentic feature (block edit, site build, P2 chat, reader chat, support search, etc.) gets a one-shot smoke test that runs the user-visible feature end-to-end. Runs in pre-merge CI plus a daily watcher.

  • Compatibility shim during migration. The legacy heavy WP_Agent stays available under its current name and lazy-delegates to the new thin value object + loop composition for one release cycle. Concrete agents migrate one at a time.

  • Telemetry watch on production rollout. Tool-call success rate, transcript length, completion-status distribution, time-to-first-token monitored before/after each rollout slice. Auto-rollback gate on regression.

The contract test harness is the gating dependency for step 5 — it should land before the refactor starts, not after.

Out of scope

  • Provider-specific code stays outside canonical (delegated to wp-ai-client).
  • Concrete admin UI, REST routes, and product workflows stay in the consumer (boundary already in canonical's README).
  • Episode detection, context-tree variable substitution, and other above-the-substrate memory engineering primitives stay in the consumer for now. They're candidates for follow-up substrate primitives later, after the convergence settles.

AI assistance

  • AI assistance: Yes
  • Tool(s): Claude Code (Opus 4.7)
  • Used for: Side-by-side inventory of the two parallel extractions, drafting the convergence sequence, and identifying the regression-test gating dependency.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions