# Agent Sync Architecture

> Transport-agnostic pipeline for import, export, upgrade, and live sync of EDDI agent configurations.

## Overview

EDDI agents are complex configuration trees: an `AgentConfiguration` contains references to `WorkflowConfiguration`s, which contain `WorkflowStep`s referencing extension resources (LLM configs, behavior rules, HTTP calls, etc.), plus `PromptSnippet`s.

The agent sync architecture provides:
1. **Selective export** — choose which resources to include in a ZIP
2. **Structural matching** — deterministic pairing of source/target resources
3. **Content diffing** — preview exactly what will change before committing
4. **In-place upgrade** — update existing resources without breaking URI references
5. **Live sync** — sync between instances without ZIP intermediary (Phase 3)

## Architecture

```
┌──────────────────┐     ┌──────────────────┐     ┌──────────────────┐
│  IResourceSource │     │ StructuralMatcher│     │  UpgradeExecutor │
│  (transport)     │────▶│  (analysis)      │────▶│  (write)         │
└──────────────────┘     └──────────────────┘     └──────────────────┘
        │                         │                        │
   ┌────┴────┐              ImportPreview            Store updates
   │         │           (resource diffs)         (version increments)
   ▼         ▼
ZipResource  RemoteApi     (Phase 3)
Source       ResourceSource
```

## Matching Algorithm

Resources are matched from source to target using a deterministic, structural approach:

| Resource Type | Matching Strategy | Rationale |
|---|---|---|
| **Agent** | Direct (by `targetAgentId` parameter) | User explicitly selects the target |
| **Workflows** | Position index (0-based) in agent's workflow list | Workflows have a defined order; position is stable |
| **Extensions** | `WorkflowStep.type` URI (e.g., `ai.labs.llm`) | Each type appears at most once per workflow |
| **Snippets** | `PromptSnippet.name` (natural key) | Names are unique by convention |

### Why Not Match by ID?

Source and target resources have different IDs (generated by their respective MongoDB instances). Matching by origin ID only works when an agent was previously imported from the same source — structural matching works for independently-created agents too.

## Data Flow

### Import (ZIP)

```
1. User uploads ZIP → RestImportService.importAgent()
2. ZIP extracted to temp dir → ZipResourceSource created
3. If strategy=upgrade:
   a. StructuralMatcher.buildPreview() → ImportPreview (content diffs)
   b. UpgradeExecutor.executeUpgrade() → updates target resources in-place
4. If strategy=create:
   a. Standard import (creates all new resources)
5. ZipResourceSource.close() → cleans up temp dir
```

### Export (Selective)

```
1. User requests preview → RestExportService.previewExport()
2. Returns ExportPreview (resource tree with selectability flags)
3. User selects resources → exportAgent(selectedResourceIds)
4. Only selected resources included in ZIP (agent + workflow skeletons always included)
```

### Live Sync (Phase 3 — Planned)

```
1. RemoteApiResourceSource reads from remote EDDI REST API
2. Same StructuralMatcher + UpgradeExecutor pipeline
3. No ZIP intermediary — direct instance-to-instance sync
```

## Key Design Decisions

### Upgrade = Content Sync

An upgrade doesn't replace the target agent's resource tree — it syncs content into existing resources. This means:
- Target resource IDs are preserved
- URI references (workflow → extension) are updated, not rewritten
- Version numbers are incremented (creating new versions, not overwriting)
- External references to these resources (deployments, triggers) continue to work

### Extension Type Registry

`UpgradeExecutor` uses an `ExtensionStoreOps` registry to map extension type names to their configuration class and store operations. Adding a new extension type requires one entry in `resolveExtensionOps()` — no duplicated switch blocks.

### Transport Agnostic

The `IResourceSource` interface is the only transport abstraction. All downstream logic (`StructuralMatcher`, `UpgradeExecutor`, `ImportPreview`) operates on `IResourceSource` records, not on ZIP files or HTTP responses.

## ZIP Directory Structure

```
<rootDir>/
  <agentId>.agent.json
  <agentId>.descriptor.json
  <workflowId>/
    <version>/
      <workflowId>.workflow.json       (or .package.json for legacy v5)
      <workflowId>.descriptor.json
      <extId>.langchain.json           (LLM config)
      <extId>.httpcalls.json           (HTTP calls)
      <extId>.behavior.json            (rules)
      <extId>.regulardictionary.json   (dictionary)
      <extId>.property.json            (property setter)
      <extId>.output.json              (output templates)
      <extId>.mcpcalls.json            (MCP calls)
      <extId>.rag.json                 (RAG config)
      <extId>.descriptor.json          (per-extension)
  snippets/
    <snippetId>.snippet.json
```

## API Endpoints

### Export
| Method | Path | Purpose |
|---|---|---|
| `POST` | `/backup/export/{agentId}/preview` | Resource tree for selective export |
| `POST` | `/backup/export/{agentId}?selectedResources=...` | Export ZIP with selected resources |

### Import
| Method | Path | Purpose |
|---|---|---|
| `POST` | `/backup/import/preview?targetAgentId=...` | Preview with content diffs |
| `POST` | `/backup/import?strategy=upgrade&targetAgentId=...` | Execute upgrade import |

### Live Sync (Phase 3)
| Method | Path | Purpose |
|---|---|---|
| `GET` | `/backup/import/sync/agents` | List remote agents |
| `POST` | `/backup/import/sync/preview` | Single-agent sync preview |
| `POST` | `/backup/import/sync/preview/batch` | Multi-agent sync preview |
| `POST` | `/backup/import/sync` | Execute single-agent sync |
| `POST` | `/backup/import/sync/batch` | Execute multi-agent sync |

## Component Reference

| Class | Type | Responsibility |
|---|---|---|
| `IResourceSource` | Interface | Transport abstraction — reads agent config from any source |
| `ZipResourceSource` | Implementation | Reads from unzipped directory, implements `AutoCloseable` |
| `StructuralMatcher` | CDI Bean | Matches source/target resources, produces `ImportPreview` |
| `UpgradeExecutor` | CDI Bean | Writes source content into target resources (version increments) |
| `ImportPreview` | Record | Preview with resource diffs (CREATE/UPDATE/SKIP/CONFLICT) |
| `ExportPreview` | Record | Resource tree with selectability flags |
| `SyncMapping` | Record | Source→target agent pair for batch sync |
| `SyncRequest` | Record | Full sync request with selections and workflow order |
