///|
/// 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 single optional composed DecisionPort for semantic judgement.
  Decision
  /// The single optional composed LogPort for structured application logging.
  Log
  /// The composed UiPort (single / Composite / Noop), for human interaction.
  Ui
  /// The Agent-owned structured task capability.
  Tasks
} derive(Eq, Debug)

///|
pub extend Capability with Eq::{not_equal, equal}

///|
pub extend Capability with Debug::{to_repr}

///|
/// Self-reported port contributions. Build one with `ExtensionManifest::make`,
/// which defaults every omitted field to an empty array; 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]
  decisions : Array[&DecisionPort]
  logs : Array[&LogPort]
  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]
}

///|
pub fn ExtensionManifest::ExtensionManifest(
  id~ : String,
  models? : Array[&ModelPort] = [],
  decisions? : Array[&DecisionPort] = [],
  logs? : Array[&LogPort] = [],
  tools? : Array[&ToolProvider] = [],
  sessions? : Array[&SessionStore] = [],
  observers? : Array[&Observer] = [],
  hooks? : Array[&PipelineHook] = [],
  memory? : Array[&MemoryPort] = [],
  lifecycle? : Array[&Lifecycle] = [],
  commands? : Array[&CommandPort] = [],
  ui? : Array[&UiPort] = [],
  prompt_contributors? : Array[&SystemPromptContributor] = [],
  requires? : Array[Capability] = [],
) -> ExtensionManifest {
  {
    id,
    models,
    decisions,
    logs,
    tools,
    sessions,
    observers,
    hooks,
    memory,
    lifecycle,
    commands,
    ui,
    prompt_contributors,
    requires,
  }
}

///|
/// Construct an empty manifest with only the id set. Fields can then be
/// assigned individually.
pub fn ExtensionManifest::default(id~ : String) -> ExtensionManifest {
  ExtensionManifest(id~)
}

// 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
}