chio_kernel/kernel/evaluation/sync_evaluation_wrapper.rs
1use super::*;
2
3impl ChioKernel {
4 pub fn evaluate_tool_call_blocking(
5 &self,
6 request: &ToolCallRequest,
7 ) -> Result<ToolCallResponse, KernelError> {
8 self.evaluate_tool_call_sync_inner(request, None, None)
9 }
10
11 /// Crate-private sync entrypoint invoked by the
12 /// [`crate::kernel::evaluator::ToolEvaluator`] default
13 /// implementation. Wraps the long-form
14 /// `evaluate_tool_call_sync_inner` so the trait body does
15 /// not need to plumb the `session_filesystem_roots` /
16 /// `extra_metadata` parameters; both default to `None` on this path,
17 /// matching the previous direct delegation from
18 /// `evaluate_tool_call`.
19 pub(crate) fn evaluate_tool_call_sync(
20 &self,
21 request: &ToolCallRequest,
22 ) -> Result<ToolCallResponse, KernelError> {
23 self.evaluate_tool_call_sync_inner(request, None, None)
24 }
25
26 pub fn evaluate_tool_call_blocking_with_metadata(
27 &self,
28 request: &ToolCallRequest,
29 extra_metadata: Option<serde_json::Value>,
30 ) -> Result<ToolCallResponse, KernelError> {
31 self.evaluate_tool_call_sync_inner(request, None, extra_metadata)
32 }
33
34 #[doc(hidden)]
35 fn evaluate_tool_call_sync_inner(
36 &self,
37 request: &ToolCallRequest,
38 session_filesystem_roots: Option<&[String]>,
39 extra_metadata: Option<serde_json::Value>,
40 ) -> Result<ToolCallResponse, KernelError> {
41 self.evaluate_tool_call_sync_with_session_context(
42 request,
43 session_filesystem_roots,
44 extra_metadata,
45 None,
46 )
47 }
48
49 /// Evaluate a tool call sync path with access to the owning session,
50 /// so the kernel can tag the resulting receipt with the session's
51 /// tenant_id (multi-tenant receipt isolation).
52 ///
53 /// `session_id` is the session that authenticated the caller, used only
54 /// to resolve the tenant from `auth_context().enterprise_identity`. The
55 /// tenant_id is NEVER read from `request` itself -- accepting a caller-
56 /// provided tenant would defeat the isolation guarantee.
57 pub(crate) fn evaluate_tool_call_sync_with_session_context(
58 &self,
59 request: &ToolCallRequest,
60 session_filesystem_roots: Option<&[String]>,
61 extra_metadata: Option<serde_json::Value>,
62 session_id: Option<&SessionId>,
63 ) -> Result<ToolCallResponse, KernelError> {
64 block_on_async_tool_dispatch(self.evaluate_tool_call_async_with_session_context(
65 request,
66 session_filesystem_roots,
67 extra_metadata,
68 session_id,
69 PreflightHoldDisposition::ReverseForRetry,
70 ))
71 }
72
73 /// Pre-execution authorization gate for callers that execute the tool
74 /// themselves (the sidecar mediated `/v1/evaluate` route).
75 ///
76 /// Runs the full pre-dispatch verification pipeline (capability, DPoP,
77 /// governed intent, approval token, guards, runtime admission), reserves
78 /// the pre-execution budget hold and KEEPS IT OPEN, and mints a fresh
79 /// execution nonce. It never dispatches a tool server, never consumes a
80 /// presented nonce, and never signs a completed or settled spend. The
81 /// returned receipt is intentionally non-authoritative: the hold is
82 /// reserved, not reconciled, so `is_authoritative_spend_receipt` rejects it.
83 ///
84 /// The reserved open hold is what enforces `max_total_cost` against
85 /// concurrent authorizations: a second authorization for a grant whose
86 /// budget is already fully reserved is denied. The caller presents the
87 /// minted nonce to the real tool server, which verifies and consumes it and
88 /// reconciles the reserved hold at the execution site.
89 ///
90 /// The request MUST NOT carry a presented execution nonce: this entry point
91 /// mints nonces, it does not settle them. The invariant is enforced here
92 /// fail-closed: a request with a presented nonce is rejected with
93 /// [`KernelError::ReservingAuthorizationRejectsPresentedNonce`] rather than
94 /// silently skipping the reserve path (a presented nonce makes
95 /// `execution_nonce_preflight_required` return false) and falling through to
96 /// dispatch, which is the opposite of the documented reserve behavior.
97 pub fn authorize_tool_call_reserving_blocking_with_metadata(
98 &self,
99 request: &ToolCallRequest,
100 extra_metadata: Option<serde_json::Value>,
101 ) -> Result<ToolCallResponse, KernelError> {
102 if request.execution_nonce.is_some() {
103 return Err(KernelError::ReservingAuthorizationRejectsPresentedNonce);
104 }
105 block_on_async_tool_dispatch(self.evaluate_tool_call_async_with_session_context(
106 request,
107 None,
108 extra_metadata,
109 None,
110 PreflightHoldDisposition::ReserveForCaller,
111 ))
112 }
113}