///|
/// Every agent contributor implements Extension. Returns an `ExtensionManifest`
/// listing which ports it provides (ModelPort, ToolProvider, SessionStore, etc.).
/// Posoco is a protocol, not a framework — an agent is the composition of
/// extensions.

// ExtensionManifest — value type returned by Extension::manifest

///|
/// A composed capability an extension declares it consumes. Declaring is what
/// populates the `CompositionView` delivered at `Lifecycle::on_compose` — the
/// view gates on this declaration, so an undeclared capability reads as
/// `None`. Extensible by adding variants; existing manifests are unaffected.
pub(all) enum Capability {
  /// The single composed ModelPort (post cardinality gate, source-agnostic).
  Model
  /// The composed UiPort (single / Composite / Noop), for human interaction.
  Ui
} derive(Eq, Debug)

///|
/// Self-reported port contributions. All fields default to empty arrays;
/// multi-trait extensions put `self` under each applicable field.
///
/// `requires` is the consumption direction: the extension declares which
/// composed capabilities it wants delivered at `Lifecycle::on_compose`.
/// The declaration is load-bearing (the view gates on it) and auditable
/// (composition can answer "which extensions declared model access").
pub(all) struct ExtensionManifest {
  id : String
  models : Array[&ModelPort]
  tools : Array[&ToolProvider]
  sessions : Array[&SessionStore]
  observers : Array[&Observer]
  /// Pipeline interception points. One array for every hook kind: the pump
  /// calls `PipelineHook::before_model` / `before_tool` / `on_post_event` on each
  /// entry in registration order. An extension that intercepts several
  /// points puts `self` here once and overrides the methods it needs.
  hooks : Array[&PipelineHook]
  memory : Array[&MemoryPort]
  lifecycle : Array[&Lifecycle]
  commands : Array[&CommandPort]
  ui : Array[&UiPort]
  prompt_contributors : Array[&SystemPromptContributor]
  requires : Array[Capability]
}

///|
/// Construct an empty manifest with only the id set. Fields can then be
/// assigned individually.
pub fn ExtensionManifest::empty(id~ : String) -> ExtensionManifest {
  {
    id,
    models: [],
    tools: [],
    sessions: [],
    observers: [],
    hooks: [],
    memory: [],
    lifecycle: [],
    commands: [],
    ui: [],
    prompt_contributors: [],
    requires: [],
  }
}

// Extension trait

///|
pub(open) trait Extension {
  /// Stable identifier for diagnostics. Should be unique per composition.
  fn extension_id(Self) -> String

  /// Return this extension's port contributions. May reference `self` under
  /// multiple port-trait views.
  fn manifest(Self) -> ExtensionManifest
}