Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,27 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
(`TuiCommand::ViewLatency`, following the same pattern as `/cost`'s `view:cost`) prints
the full avg/max turn-latency breakdown plus classifier p50/p95/call-count via
`App::format_latency_stats`.
- `serve-sessions`: closed three follow-up gaps in `/sessions*` HTTP+SSE session wiring
(#6045, #6046, #6008).
- `ScopedToolExecutor` (`[security.capability_scopes]`) is no longer built once, eagerly, and
shared across every concurrent `/sessions*` agent — it is now wrapped fresh per session in
`agent_factory::build_agent_factory`, mirroring `src/acp.rs`'s per-connection wrap, so each
session's `OutOfScope` capability-scope denials feed that session's own `TrajectorySentinel`
risk-escalation signal queue instead of being invisible to it. `assemble_serve_deps` still
validates the configured scope compiles against the tool registry at server startup (fatal
on a bad config, unchanged), it just no longer keeps the compiled instance — that startup
validation and the per-session wrap now share one `compose_session_tool_tree` helper so
both compile against the identical tool-id surface (including the `skill_loader`/
`invoke_skill`/`memory`/`overflow` tools below), fixing a false-positive startup abort for
any scope pattern that referenced one of those tools.
- `/sessions*` agents now get `skill_loader`/`invoke_skill`/`memory`/`overflow` tool executors,
matching CLI/TUI/ACP/daemon's tool surface — previously these were entirely absent from
serve's composite tool chain. MCP tools, the scheduler executor, and skill/config hot-reload
broadcast forwarding remain a separately-tracked known gap.
- A `[tools.policy]`/`[tools.authorization]` compile failure now aborts `serve-sessions`
startup instead of silently starting with declarative policy enforcement disabled — serve is
an HTTP-facing entrypoint with potentially remote/less-trusted callers, unlike CLI/TUI/ACP/
daemon (which stay intentionally fail-open on the same failure, unchanged).
- `zeph-tui`: closed three independent dispatch/state gaps (#6061, #5984, #5983).
- The task-registry overlay's supervisor-unavailable fallback (`render_subagents_slot`)
drew its "supervisor not available" message directly into the shared subagents-slot
Expand Down
1 change: 1 addition & 0 deletions src/acp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3638,6 +3638,7 @@ mod tests {
adversarial_validator: None,
adversarial_llm_client: None,
adv_policy_info: None,
policy_configured: true,
};

let trajectory_risk_slot: zeph_tools::TrajectoryRiskSlot =
Expand Down
17 changes: 17 additions & 0 deletions src/agent_setup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1799,6 +1799,20 @@ pub(crate) struct PolicyGatePieces {
/// populated unconditionally whenever the adversarial gate is enabled since it is plain
/// data with no side effects, so entry points that ignore it are unaffected.
pub(crate) adv_policy_info: Option<zeph_core::AdversarialPolicyInfo>,
/// `true` when `[tools.policy]`/`[tools.authorization]` was actually enabled by config
/// (the same `effective_policy.enabled` check `build_policy_gate_pieces` uses to decide
/// whether to attempt compilation at all) — regardless of whether that compile succeeded.
/// Lets a caller distinguish "`policy_enforcer` is None because compile failed" from
/// "`policy_enforcer` is None because no policy was configured" (#6008): only `serve/deps.rs`
/// currently reads this, to abort startup fail-closed on a real compile failure while
/// staying fail-open when policy is legitimately absent. All other call sites (`runner.rs`,
/// `acp.rs`, `daemon.rs`) ignore this field and keep their existing fail-open behavior.
///
/// Only read from `src/serve/deps.rs`, which is gated behind `#[cfg(feature = "session")]`
/// (`src/main.rs`) — feature bundles that don't pull in `session` (e.g. `ide`, `chat`,
/// `bench`) never compile that reader, so this field is otherwise genuinely dead code there.
#[cfg_attr(not(feature = "session"), allow(dead_code))]
pub(crate) policy_configured: bool,
}

/// Builds the adversarial-policy validator/LLM-client pair (and the `/adversarial-policy`
Expand Down Expand Up @@ -1944,6 +1958,7 @@ pub(crate) async fn build_policy_gate_pieces(
} else {
config.tools.policy.clone()
};
let policy_configured = effective_policy.enabled;
let policy_enforcer = if effective_policy.enabled {
match zeph_tools::PolicyEnforcer::compile(&effective_policy) {
Ok(enforcer) => Some(Arc::new(enforcer)),
Expand All @@ -1961,6 +1976,7 @@ pub(crate) async fn build_policy_gate_pieces(
adversarial_validator,
adversarial_llm_client,
adv_policy_info,
policy_configured,
}
}

Expand Down Expand Up @@ -3390,6 +3406,7 @@ mod tests {
adversarial_validator: None,
adversarial_llm_client: None,
adv_policy_info: None,
policy_configured: true,
};

let inner: Arc<dyn zeph_tools::ErasedToolExecutor> = Arc::new(NoopExec);
Expand Down
1 change: 1 addition & 0 deletions src/daemon.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2227,6 +2227,7 @@ mod tests {
adversarial_validator: None,
adversarial_llm_client: None,
adv_policy_info: None,
policy_configured: true,
};

let trajectory_risk_slot: zeph_tools::TrajectoryRiskSlot =
Expand Down
Loading
Loading