///|
/// CompositionView: the curated read-only view of composed capabilities
/// delivered to `Lifecycle::on_compose` after every composition gate has
/// passed. This is the consumption direction of the manifest contract — an
/// extension declares `requires` and the corresponding getter reads `Some`;
/// undeclared capabilities read `None`.
///
/// Curation discipline: the view only ever carries capabilities whose use
/// cannot bypass governance. `model` calls still carry `InvocationScope`
/// attribution; `ui` has no governance surface. The view NEVER exposes tool
/// invocation (would bypass `PipelineHook::before_tool`), session stores (state
/// ownership), or observer-event emission (core-owned). Fields are private
/// with getters so new capabilities can be added without breaking
/// extensions that destructure or construct views in tests.
pub struct CompositionView {
priv model_ : &ModelPort?
priv decision_ : &DecisionPort?
priv log_ : &LogPort?
priv ui_ : &UiPort?
priv tasks_ : Tasks?
priv wakeup_ : WakeupPort?
priv tool_contributions_ : ToolContributions?
}
///|
/// Present only when the extension declared `Capability::Model`. The value is
/// source-agnostic: an extension cannot tell a plain provider from a routing
/// meta-extension, and must not.
pub fn CompositionView::model(self : CompositionView) -> &ModelPort? {
self.model_
}
///|
/// Visible only when the extension declared `Capability::Decision`. Absence is
/// legal: consumers that treat decision support as an enhancement keep their
/// deterministic fallback, and consumers that require it may fail in
/// `on_compose`.
pub fn CompositionView::decision(self : CompositionView) -> &DecisionPort? {
self.decision_
}
///|
/// Visible only when the extension declared `Capability::Log`. Absence is
/// legal: consumers decide whether a missing sink is acceptable.
pub fn CompositionView::log(self : CompositionView) -> &LogPort? {
self.log_
}
///|
/// Present only when the extension declared `Capability::Ui`. Declaring `ui`
/// only to consume the composed UI is not allowed.
pub fn CompositionView::ui(self : CompositionView) -> &UiPort? {
self.ui_
}
///|
/// Present only when the extension declares `Capability::Tasks`.
pub fn CompositionView::tasks(self : CompositionView) -> Tasks? {
self.tasks_
}
///|
/// Present only when the extension declares `Capability::Wakeup`. `request`
/// queues one ordinary turn for a session; execution stays inside the Agent's
/// single-operation lifecycle.
pub fn CompositionView::wakeup(self : CompositionView) -> WakeupPort? {
self.wakeup_
}
///|
/// Present only when the extension declares `Capability::ToolContribution`.
/// The value is bound to this extension's manifest id, so it can only publish
/// its own group.
pub fn CompositionView::tool_contributions(
self : CompositionView,
) -> ToolContributions? {
self.tool_contributions_
}
///|
/// Gate a view on a manifest's declared `requires`: a declared capability is
/// populated from the composed ports, an undeclared one reads `None`.
/// Called by the composition after every gate has passed, so `model` and
/// `ui` are guaranteed to be the final composed values.
pub fn CompositionView::resolve(
requires~ : Array[Capability],
model~ : &ModelPort,
decision~ : &DecisionPort? = None,
log~ : &LogPort? = None,
ui~ : &UiPort,
tasks~ : Tasks? = None,
wakeup~ : WakeupPort? = None,
tool_contributions~ : ToolContributions? = None,
) -> CompositionView {
{
model_: if requires.contains(Model) {
Some(model)
} else {
None
},
decision_: if requires.contains(Decision) {
decision
} else {
None
},
log_: if requires.contains(Log) {
log
} else {
None
},
ui_: if requires.contains(Ui) {
Some(ui)
} else {
None
},
tasks_: if requires.contains(Tasks) {
tasks
} else {
None
},
wakeup_: if requires.contains(Wakeup) {
wakeup
} else {
None
},
tool_contributions_: if requires.contains(ToolContribution) {
tool_contributions
} else {
None
},
}
}