1use gate4agent_handle::{
2 ProviderCancellation, ProviderCancellationToken, ProviderInvocation,
3 ProviderObservationOutcome, ProviderObservationStatus, ProviderRuntimeError,
4 ProviderRuntimeHandle, ProviderRuntimeState, ProviderWork,
5};
6use gate4agent_tool_protocol::{
7 CapabilityObservation, CapabilityProviderDescriptor, CapabilityRequestKey,
8 InvocationCancelReason, ProviderBindingId, ToolCapabilityId, ToolFailure, ToolFailureKind,
9 ToolOperationId, ToolProviderId,
10};
11use std::collections::{BTreeMap, VecDeque};
12use std::sync::mpsc::TryRecvError;
13use std::time::{Duration, Instant};
14
15pub const MAX_PROVIDER_SUPERVISOR_EVENTS: usize = 1_024;
16pub const MAX_PROVIDER_SUPERVISOR_OPERATIONS: usize = 1_024;
17pub const MAX_PROVIDER_SUPERVISOR_TOMBSTONES: usize =
18 MAX_PROVIDER_SUPERVISOR_OPERATIONS * 2;
19pub const MAX_PROVIDER_SUPERVISOR_OUTCOMES_PER_TICK: usize = 64;
20pub const MAX_PROVIDER_SUPERVISOR_WORK_PER_TICK: usize = 64;
21pub const MAX_PROVIDER_STOP_SIGNAL_ATTEMPTS: u8 = 3;
22pub const MAX_PROVIDER_FORCE_STOP_ATTEMPTS: u8 = 3;
23pub const DEFAULT_PROVIDER_STOP_GRACE: Duration = Duration::from_secs(5);
24
25pub trait NativeProviderExecutor: Send {
31 fn start(
32 &mut self,
33 invocation: &ProviderInvocation,
34 ) -> Result<Box<dyn NativeProviderOperation>, ToolFailure>;
35}
36
37pub trait NativeProviderOperation: Send {
50 fn request_stop(&mut self) -> Result<(), NativeProviderOperationError>;
51
52 fn request_force_stop(&mut self) -> Result<(), NativeProviderOperationError>;
53
54 fn try_wait(&mut self) -> Result<Option<NativeProviderExit>, NativeProviderOperationError>;
55
56 fn try_poll_result(
57 &mut self,
58 ) -> Result<NativeProviderResultPoll, NativeProviderOperationError>;
59}
60
61#[derive(Clone, Copy, Debug, Eq, PartialEq)]
62pub struct NativeProviderOperationError {
63 pub code: &'static str,
64}
65
66impl NativeProviderOperationError {
67 pub const fn new(code: &'static str) -> Self {
68 Self { code }
69 }
70}
71
72#[derive(Clone, Debug, Eq, PartialEq)]
73pub enum NativeProviderResultPoll {
74 Pending,
75 Ready(CapabilityObservation),
76 Closed,
77}
78
79#[derive(Clone, Copy, Debug, Eq, PartialEq)]
80pub struct NativeProviderExit {
81 pub success: bool,
82 pub code: Option<i32>,
83}
84
85#[derive(Clone, Debug, Eq, PartialEq)]
86pub struct ProviderOperationKey {
87 pub binding_id: ProviderBindingId,
88 pub operation_id: ToolOperationId,
89 pub request_key: CapabilityRequestKey,
90}
91
92#[derive(Clone, Debug, Eq, PartialEq)]
93pub struct PhysicalExitAck {
94 pub provider_id: ToolProviderId,
95 pub binding_id: ProviderBindingId,
96 pub operation: ProviderOperationKey,
97 pub exit: NativeProviderExit,
98 pub stop_signal_attempted: bool,
99 pub stop_signalled: bool,
100 pub force_stop_attempted: bool,
101 pub force_stop_signalled: bool,
102 pub stop_cause: Option<ProviderStopCause>,
103}
104
105#[derive(Clone, Copy, Debug, Eq, PartialEq)]
106pub enum ProviderStopCause {
107 Cancellation {
108 reason: InvocationCancelReason,
109 },
110 Retirement,
111 SupervisorFault,
112}
113
114#[derive(Clone, Copy, Debug, Eq, PartialEq)]
115pub enum ProviderSupervisorState {
116 Running,
117 Draining,
118 Closing,
119 Closed,
120 Faulted,
121}
122
123#[derive(Clone, Debug, Eq, PartialEq)]
124pub struct ProviderOperationSnapshot {
125 pub operation: ProviderOperationKey,
126 pub capability_id: ToolCapabilityId,
127 pub deadline_tick: u64,
128 pub stop_signal_attempted: bool,
129 pub stop_signalled: bool,
130 pub force_stop_attempted: bool,
131 pub force_stop_signalled: bool,
132 pub stop_cause: Option<ProviderStopCause>,
133 pub physical_exit: Option<NativeProviderExit>,
134 pub result_ready: bool,
135}
136
137#[derive(Clone, Debug, Eq, PartialEq)]
138pub struct ProviderSupervisorSnapshot {
139 pub provider_id: ToolProviderId,
140 pub binding_id: ProviderBindingId,
141 pub state: ProviderSupervisorState,
142 pub runtime_state: ProviderRuntimeState,
143 pub operations: Vec<ProviderOperationSnapshot>,
144 pub close_sequence: Option<u64>,
145 pub buffered_exit_acks: usize,
146 pub buffered_faults: usize,
147 pub dropped_faults: u64,
148 pub exit_ack_backpressured: bool,
149}
150
151#[derive(Clone, Copy, Debug, Eq, PartialEq)]
152pub enum ProviderSupervisorBuildError {
153 InvalidDescriptor,
154 ProviderMismatch,
155}
156
157#[derive(Clone, Copy, Debug, Eq, PartialEq)]
158pub enum ProviderSupervisorFaultKind {
159 InvalidExecutorFailure,
160 InvalidExecutorObservation,
161 StopSignalFailed,
162 ForceStopFailed,
163 WaitFailed,
164 ResultPollFailed,
165 OperationCapacityExceeded,
166 ConflictingInvocation,
167 UnknownCancellation,
168 CancellationIdentityMismatch,
169 ObservationOutcomeRejected,
170 ObservationOutcomeContractViolation,
171 ObservationOutcomeRuntimeClosed,
172 ObservationOutcomeMismatch,
173 TombstoneCapacityExceeded,
174 RuntimeQuiesceFailed(ProviderRuntimeError),
175 RuntimeCompletionFailed(ProviderRuntimeError),
176 RuntimeCloseFailed(ProviderRuntimeError),
177 FaultBufferOverflow { dropped: u64 },
178}
179
180#[derive(Clone, Debug, Eq, PartialEq)]
181pub struct ProviderSupervisorFault {
182 pub provider_id: ToolProviderId,
183 pub binding_id: ProviderBindingId,
184 pub operation: Option<ProviderOperationKey>,
185 pub kind: ProviderSupervisorFaultKind,
186 pub executor_error_code: Option<&'static str>,
187 pub blocks_detach: bool,
188}
189
190#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
191pub struct ProviderSupervisorTick {
192 pub work_received: usize,
193 pub observation_outcomes_received: usize,
194 pub operations_started: usize,
195 pub stop_signals: usize,
196 pub force_stop_signals: usize,
197 pub physical_exit_acks: usize,
198 pub observations_submitted: usize,
199 pub faults_recorded: usize,
200 pub close_requested: bool,
201}
202
203pub struct ProviderSupervisor {
211 descriptor: CapabilityProviderDescriptor,
212 owned: BTreeMap<ToolOperationId, OwnedProviderOperation>,
213 executor: Box<dyn NativeProviderExecutor>,
214 runtime: ProviderRuntimeHandle,
215 stop_grace: Duration,
216 observation_capacity: usize,
217 outstanding_observations: usize,
218 lifecycle: ProviderSupervisorState,
219 retirement_requested: bool,
220 detach_blocked: bool,
221 tombstones: VecDeque<CompletedOperationTombstone>,
222 close_sequence: Option<u64>,
223 exit_acks: VecDeque<PhysicalExitAck>,
224 faults: VecDeque<ProviderSupervisorFault>,
225 dropped_faults: u64,
226}
227
228enum OwnedProviderOperation {
229 Physical(OwnedPhysicalOperation),
230 PendingCompletion(PendingCompletion),
231 AwaitingObservationOutcome(AwaitingObservationOutcome),
232 AwaitingCancellation(AwaitingCancellation),
233}
234
235struct OwnedPhysicalOperation {
236 key: ProviderOperationKey,
237 capability_id: ToolCapabilityId,
238 deadline_tick: u64,
239 invocation: ProviderInvocation,
240 operation: Box<dyn NativeProviderOperation>,
241 stop_signal_attempted: bool,
242 stop_signal_attempts: u8,
243 stop_signalled: bool,
244 stop_signalled_at: Option<Instant>,
245 force_stop_attempts: u8,
246 force_stop_signalled: bool,
247 stop_cause: Option<ProviderStopCause>,
248 cancellation_received: bool,
249 result: Option<CapabilityObservation>,
250 result_closed: bool,
251 physical_exit: Option<NativeProviderExit>,
252 exit_ack_emitted: bool,
253}
254
255struct PendingCompletion {
256 key: ProviderOperationKey,
257 capability_id: ToolCapabilityId,
258 deadline_tick: u64,
259 invocation: ProviderInvocation,
260 observation: CapabilityObservation,
261}
262
263struct AwaitingObservationOutcome {
264 key: ProviderOperationKey,
265 capability_id: ToolCapabilityId,
266 deadline_tick: u64,
267 sequence: u64,
268 cancellation_token: ProviderCancellationToken,
269 cancellation_reason: Option<InvocationCancelReason>,
270}
271
272struct AwaitingCancellation {
273 key: ProviderOperationKey,
274 capability_id: ToolCapabilityId,
275 deadline_tick: u64,
276}
277
278struct CompletedOperationTombstone {
279 key: ProviderOperationKey,
280}
281
282impl ProviderSupervisor {
283 pub fn new(
284 descriptor: CapabilityProviderDescriptor,
285 runtime: ProviderRuntimeHandle,
286 executor: Box<dyn NativeProviderExecutor>,
287 ) -> Result<Self, ProviderSupervisorBuildError> {
288 Self::new_with_stop_grace(descriptor, runtime, executor, DEFAULT_PROVIDER_STOP_GRACE)
289 }
290
291 pub fn new_with_stop_grace(
292 descriptor: CapabilityProviderDescriptor,
293 runtime: ProviderRuntimeHandle,
294 executor: Box<dyn NativeProviderExecutor>,
295 stop_grace: Duration,
296 ) -> Result<Self, ProviderSupervisorBuildError> {
297 descriptor
298 .validate()
299 .map_err(|_| ProviderSupervisorBuildError::InvalidDescriptor)?;
300 if &descriptor.id != runtime.provider_id() {
301 return Err(ProviderSupervisorBuildError::ProviderMismatch);
302 }
303 let observation_capacity = runtime.effect_capacity();
304 Ok(Self {
305 descriptor,
306 owned: BTreeMap::new(),
307 executor,
308 runtime,
309 stop_grace: if stop_grace.is_zero() {
310 Duration::from_millis(1)
311 } else {
312 stop_grace
313 },
314 observation_capacity,
315 outstanding_observations: 0,
316 lifecycle: ProviderSupervisorState::Running,
317 retirement_requested: false,
318 detach_blocked: false,
319 tombstones: VecDeque::new(),
320 close_sequence: None,
321 exit_acks: VecDeque::new(),
322 faults: VecDeque::new(),
323 dropped_faults: 0,
324 })
325 }
326
327 pub fn descriptor(&self) -> &CapabilityProviderDescriptor {
328 &self.descriptor
329 }
330
331 pub fn begin_retirement(&mut self) -> Result<(), ProviderRuntimeError> {
332 if self.retirement_requested {
333 return Ok(());
334 }
335 self.retirement_requested = true;
336 if matches!(self.runtime.state(), ProviderRuntimeState::Closed) && self.owned.is_empty() {
337 self.detach_blocked = false;
338 self.lifecycle = ProviderSupervisorState::Closed;
339 return Ok(());
340 }
341 self.lifecycle = ProviderSupervisorState::Draining;
342 for owned in self.owned.values_mut() {
343 if let OwnedProviderOperation::Physical(owned) = owned {
344 if owned.physical_exit.is_none()
345 && !owned.stop_signal_attempted
346 && owned.stop_cause.is_none()
347 {
348 owned.stop_cause = Some(ProviderStopCause::Retirement);
349 }
350 }
351 }
352 if matches!(self.runtime.state(), ProviderRuntimeState::Closed) {
353 return Ok(());
354 }
355 if matches!(self.runtime.state(), ProviderRuntimeState::Attaching)
356 && self.owned.is_empty()
357 {
358 let mut report = ProviderSupervisorTick::default();
359 return self.request_runtime_close(&mut report);
360 }
361 match self.runtime.begin_quiesce() {
362 Ok(()) => Ok(()),
363 Err(ProviderRuntimeError::Inactive)
364 if matches!(self.runtime.state(), ProviderRuntimeState::Closing) =>
365 {
366 Ok(())
367 }
368 Err(error) => {
369 let mut report = ProviderSupervisorTick::default();
370 self.record_blocking_fault(
371 None,
372 ProviderSupervisorFaultKind::RuntimeQuiesceFailed(error),
373 None,
374 &mut report,
375 );
376 Err(error)
377 }
378 }
379 }
380
381 pub fn snapshot(&self) -> ProviderSupervisorSnapshot {
382 ProviderSupervisorSnapshot {
383 provider_id: self.descriptor.id.clone(),
384 binding_id: self.runtime.binding_id(),
385 state: self.state(),
386 runtime_state: self.runtime.state(),
387 operations: self
388 .owned
389 .values()
390 .map(OwnedProviderOperation::snapshot)
391 .collect(),
392 close_sequence: self.close_sequence,
393 buffered_exit_acks: self.exit_acks.len(),
394 buffered_faults: self.faults.len() + usize::from(self.dropped_faults != 0),
395 dropped_faults: self.dropped_faults,
396 exit_ack_backpressured: self
397 .owned
398 .values()
399 .any(OwnedProviderOperation::exit_ack_backpressured),
400 }
401 }
402
403 pub fn state(&self) -> ProviderSupervisorState {
404 if self.detach_blocked {
405 ProviderSupervisorState::Faulted
406 } else {
407 self.lifecycle
408 }
409 }
410
411 pub fn drain_exit_acks(&mut self, limit: usize) -> Vec<PhysicalExitAck> {
412 drain_queue(&mut self.exit_acks, limit)
413 }
414
415 pub fn drain_faults(&mut self, limit: usize) -> Vec<ProviderSupervisorFault> {
416 if limit == 0 {
417 return Vec::new();
418 }
419 let mut drained = Vec::new();
420 if self.dropped_faults != 0 {
421 let dropped = std::mem::take(&mut self.dropped_faults);
422 drained.push(ProviderSupervisorFault {
423 provider_id: self.descriptor.id.clone(),
424 binding_id: self.runtime.binding_id(),
425 operation: None,
426 kind: ProviderSupervisorFaultKind::FaultBufferOverflow { dropped },
427 executor_error_code: None,
428 blocks_detach: false,
429 });
430 }
431 drained.extend(drain_queue(&mut self.faults, limit - drained.len()));
432 drained
433 }
434
435 pub fn tick(&mut self) -> ProviderSupervisorTick {
436 let mut report = ProviderSupervisorTick::default();
437 if matches!(self.lifecycle, ProviderSupervisorState::Closed) {
438 return report;
439 }
440
441 self.drain_observation_outcomes(&mut report);
442
443 let runtime_closed = matches!(self.runtime.state(), ProviderRuntimeState::Closed);
444 if runtime_closed {
445 if !self.owned.is_empty() && !self.detach_blocked {
446 self.record_blocking_fault(
447 None,
448 ProviderSupervisorFaultKind::RuntimeCompletionFailed(
449 ProviderRuntimeError::Inactive,
450 ),
451 None,
452 &mut report,
453 );
454 }
455 self.outstanding_observations = 0;
456 }
457
458 let operation_ids = self.owned.keys().copied().collect::<Vec<_>>();
459 for operation_id in operation_ids {
460 let Some(mut owned) = self.owned.remove(&operation_id) else {
461 continue;
462 };
463 if runtime_closed && !owned.has_physical_owner() {
464 continue;
465 }
466 if runtime_closed {
467 owned.fence_for_runtime_close(self.retirement_requested);
468 }
469 if let Some(owned) = self.tick_owned(owned, &mut report) {
470 self.owned.insert(operation_id, owned);
471 }
472 }
473
474 if runtime_closed {
475 if self.owned.is_empty() {
476 self.lifecycle = ProviderSupervisorState::Closed;
477 if self.retirement_requested {
478 self.detach_blocked = false;
479 }
480 }
481 return report;
482 }
483
484 if self.retirement_requested {
485 self.lifecycle = if self.close_sequence.is_some() {
486 ProviderSupervisorState::Closing
487 } else {
488 ProviderSupervisorState::Draining
489 };
490 if !matches!(
491 self.runtime.state(),
492 ProviderRuntimeState::Attaching | ProviderRuntimeState::Closed
493 ) {
494 self.drain_work(&mut report);
495 }
496 if self.owned.is_empty() {
497 self.detach_blocked = false;
498 let _ = self.request_runtime_close(&mut report);
499 }
500 return report;
501 }
502
503 if !matches!(
504 self.runtime.state(),
505 ProviderRuntimeState::Attaching | ProviderRuntimeState::Closed
506 ) {
507 self.drain_work(&mut report);
508 }
509 report
510 }
511
512 fn drain_observation_outcomes(&mut self, report: &mut ProviderSupervisorTick) {
513 for _ in 0..MAX_PROVIDER_SUPERVISOR_OUTCOMES_PER_TICK {
514 match self.runtime.try_recv_observation_outcome() {
515 Ok(outcome) => {
516 report.observation_outcomes_received += 1;
517 self.handle_observation_outcome(outcome, report);
518 }
519 Err(TryRecvError::Empty | TryRecvError::Disconnected) => return,
520 }
521 }
522 }
523
524 fn handle_observation_outcome(
525 &mut self,
526 outcome: ProviderObservationOutcome,
527 report: &mut ProviderSupervisorTick,
528 ) {
529 if self.outstanding_observations == 0 {
530 self.record_blocking_fault(
531 None,
532 ProviderSupervisorFaultKind::ObservationOutcomeMismatch,
533 None,
534 report,
535 );
536 } else {
537 self.outstanding_observations -= 1;
538 }
539 let operation_id = outcome.operation_id;
540 let Some(mut owned) = self.owned.remove(&operation_id) else {
541 self.record_blocking_fault(
542 None,
543 ProviderSupervisorFaultKind::ObservationOutcomeMismatch,
544 None,
545 report,
546 );
547 return;
548 };
549 let OwnedProviderOperation::AwaitingObservationOutcome(awaiting) = owned else {
550 owned.fence_for_fault(self.retirement_requested);
551 let operation = owned.key().clone();
552 self.owned.insert(operation_id, owned);
553 self.record_blocking_fault(
554 Some(operation),
555 ProviderSupervisorFaultKind::ObservationOutcomeMismatch,
556 None,
557 report,
558 );
559 return;
560 };
561 if awaiting.sequence != outcome.sequence
562 || awaiting.key.operation_id != outcome.operation_id
563 || awaiting.key.request_key != outcome.request_key
564 {
565 let operation = awaiting.key.clone();
566 if awaiting.cancellation_reason.is_none()
567 && awaiting.cancellation_token.is_cancelled()
568 {
569 self.push_tombstone(awaiting.key, report);
570 }
571 self.record_blocking_fault(
572 Some(operation),
573 ProviderSupervisorFaultKind::ObservationOutcomeMismatch,
574 None,
575 report,
576 );
577 return;
578 }
579
580 match outcome.status {
581 ProviderObservationStatus::Applied | ProviderObservationStatus::Ignored { .. } => {
582 if awaiting.cancellation_reason.is_none()
583 && awaiting.cancellation_token.is_cancelled()
584 {
585 self.push_tombstone(awaiting.key, report);
586 }
587 }
588 status => {
589 let kind = match status {
590 ProviderObservationStatus::Rejected(_) => {
591 ProviderSupervisorFaultKind::ObservationOutcomeRejected
592 }
593 ProviderObservationStatus::ContractViolation => {
594 ProviderSupervisorFaultKind::ObservationOutcomeContractViolation
595 }
596 ProviderObservationStatus::RuntimeClosed => {
597 ProviderSupervisorFaultKind::ObservationOutcomeRuntimeClosed
598 }
599 ProviderObservationStatus::Applied
600 | ProviderObservationStatus::Ignored { .. } => unreachable!(),
601 };
602 let operation = awaiting.key.clone();
603 if awaiting.cancellation_reason.is_none()
604 && awaiting.cancellation_token.is_cancelled()
605 {
606 self.push_tombstone(awaiting.key, report);
607 }
608 self.record_blocking_fault(Some(operation), kind, None, report);
609 }
610 }
611 }
612
613 fn tick_owned(
614 &mut self,
615 owned: OwnedProviderOperation,
616 report: &mut ProviderSupervisorTick,
617 ) -> Option<OwnedProviderOperation> {
618 match owned {
619 OwnedProviderOperation::Physical(mut owned) => {
620 if self.retirement_requested
621 && owned.physical_exit.is_none()
622 && !owned.stop_signal_attempted
623 && owned.stop_cause.is_none()
624 {
625 owned.stop_cause = Some(ProviderStopCause::Retirement);
626 }
627 if self.detach_blocked
628 && owned.physical_exit.is_none()
629 && !owned.stop_signal_attempted
630 && owned.stop_cause.is_none()
631 {
632 owned.stop_cause = Some(ProviderStopCause::SupervisorFault);
633 }
634 let cancellation_requested =
635 owned.invocation.cancellation_token().is_cancelled();
636 let stop_required = self.retirement_requested
637 || self.detach_blocked
638 || cancellation_requested
639 || owned.stop_cause.is_some();
640 if owned.physical_exit.is_none()
641 && stop_required
642 && !owned.stop_signalled
643 && owned.stop_signal_attempts < MAX_PROVIDER_STOP_SIGNAL_ATTEMPTS
644 {
645 owned.stop_signal_attempted = true;
646 owned.stop_signal_attempts += 1;
647 report.stop_signals += 1;
648 match owned.operation.request_stop() {
649 Ok(()) => {
650 owned.stop_signalled = true;
651 owned.stop_signalled_at = Some(Instant::now());
652 }
653 Err(error) => {
654 if owned.stop_signal_attempts
655 == MAX_PROVIDER_STOP_SIGNAL_ATTEMPTS
656 {
657 self.record_blocking_fault(
658 Some(owned.key.clone()),
659 ProviderSupervisorFaultKind::StopSignalFailed,
660 Some(error.code),
661 report,
662 );
663 } else {
664 self.record_fault(
665 Some(owned.key.clone()),
666 ProviderSupervisorFaultKind::StopSignalFailed,
667 Some(error.code),
668 false,
669 report,
670 );
671 }
672 }
673 }
674 }
675 let force_stop_required = owned.physical_exit.is_none()
676 && stop_required
677 && !owned.force_stop_signalled
678 && ((!owned.stop_signalled
679 && owned.stop_signal_attempts
680 == MAX_PROVIDER_STOP_SIGNAL_ATTEMPTS)
681 || owned
682 .stop_signalled_at
683 .is_some_and(|started| started.elapsed() >= self.stop_grace));
684 if force_stop_required
685 && owned.force_stop_attempts < MAX_PROVIDER_FORCE_STOP_ATTEMPTS
686 {
687 owned.force_stop_attempts += 1;
688 report.force_stop_signals += 1;
689 match owned.operation.request_force_stop() {
690 Ok(()) => owned.force_stop_signalled = true,
691 Err(error) => {
692 if owned.force_stop_attempts
693 == MAX_PROVIDER_FORCE_STOP_ATTEMPTS
694 {
695 self.record_blocking_fault(
696 Some(owned.key.clone()),
697 ProviderSupervisorFaultKind::ForceStopFailed,
698 Some(error.code),
699 report,
700 );
701 } else {
702 self.record_fault(
703 Some(owned.key.clone()),
704 ProviderSupervisorFaultKind::ForceStopFailed,
705 Some(error.code),
706 false,
707 report,
708 );
709 }
710 }
711 }
712 }
713
714 if !cancellation_requested
715 && !owned.stop_signal_attempted
716 && owned.stop_cause.is_none()
717 && owned.result.is_none()
718 && !owned.result_closed
719 {
720 match owned.operation.try_poll_result() {
721 Ok(NativeProviderResultPoll::Pending) => {}
722 Ok(NativeProviderResultPoll::Closed) => owned.result_closed = true,
723 Ok(NativeProviderResultPoll::Ready(observation)) => {
724 if observation.validate().is_ok() {
725 owned.result = Some(observation);
726 } else {
727 owned.result = Some(contract_violation_observation());
728 self.record_fault(
729 Some(owned.key.clone()),
730 ProviderSupervisorFaultKind::InvalidExecutorObservation,
731 None,
732 false,
733 report,
734 );
735 }
736 }
737 Err(error) => {
738 owned.result = Some(contract_violation_observation());
739 owned.result_closed = true;
740 if !self.retirement_requested && owned.stop_cause.is_none() {
741 owned.stop_cause = Some(ProviderStopCause::SupervisorFault);
742 }
743 self.record_blocking_fault(
744 Some(owned.key.clone()),
745 ProviderSupervisorFaultKind::ResultPollFailed,
746 Some(error.code),
747 report,
748 );
749 }
750 }
751 }
752
753 if owned.physical_exit.is_none() {
754 match owned.operation.try_wait() {
755 Ok(Some(exit)) => owned.physical_exit = Some(exit),
756 Ok(None) => {}
757 Err(error) => {
758 if !self.retirement_requested
759 && !owned.stop_signal_attempted
760 && owned.stop_cause.is_none()
761 {
762 owned.stop_cause = Some(ProviderStopCause::SupervisorFault);
763 }
764 self.record_blocking_fault(
765 Some(owned.key.clone()),
766 ProviderSupervisorFaultKind::WaitFailed,
767 Some(error.code),
768 report,
769 );
770 return Some(OwnedProviderOperation::Physical(owned));
771 }
772 }
773 }
774
775 if let Some(exit) = owned.physical_exit {
776 if !owned.exit_ack_emitted {
777 if owned.stop_signal_attempted && owned.stop_cause.is_none() {
778 return Some(OwnedProviderOperation::Physical(owned));
779 }
780 if self.exit_acks.len() >= MAX_PROVIDER_SUPERVISOR_EVENTS {
781 return Some(OwnedProviderOperation::Physical(owned));
782 }
783 self.exit_acks.push_back(PhysicalExitAck {
784 provider_id: self.descriptor.id.clone(),
785 binding_id: self.runtime.binding_id(),
786 operation: owned.key.clone(),
787 exit,
788 stop_signal_attempted: owned.stop_signal_attempted,
789 stop_signalled: owned.stop_signalled,
790 force_stop_attempted: owned.force_stop_attempts != 0,
791 force_stop_signalled: owned.force_stop_signalled,
792 stop_cause: owned.stop_cause,
793 });
794 owned.exit_ack_emitted = true;
795 report.physical_exit_acks += 1;
796 }
797
798 if self.retirement_requested
799 || self.detach_blocked
800 || owned.cancellation_received
801 || owned.stop_cause.is_some()
802 {
803 if !owned.cancellation_received {
804 self.push_tombstone(owned.key, report);
805 }
806 return None;
807 }
808 if owned.result.is_none() && owned.result_closed {
809 owned.result = Some(contract_violation_observation());
810 self.record_fault(
811 Some(owned.key.clone()),
812 ProviderSupervisorFaultKind::InvalidExecutorObservation,
813 None,
814 false,
815 report,
816 );
817 }
818 if let Some(observation) = owned.result.take() {
819 return Some(OwnedProviderOperation::PendingCompletion(
820 PendingCompletion {
821 key: owned.key,
822 capability_id: owned.capability_id,
823 deadline_tick: owned.deadline_tick,
824 invocation: owned.invocation,
825 observation,
826 },
827 ));
828 }
829 }
830 Some(OwnedProviderOperation::Physical(owned))
831 }
832 OwnedProviderOperation::PendingCompletion(mut pending) => {
833 if self.retirement_requested {
834 self.push_tombstone(pending.key, report);
835 return None;
836 }
837 if pending.invocation.cancellation_token().is_cancelled() {
838 return Some(OwnedProviderOperation::AwaitingCancellation(
839 AwaitingCancellation {
840 key: pending.key,
841 capability_id: pending.capability_id,
842 deadline_tick: pending.deadline_tick,
843 },
844 ));
845 }
846 if self.outstanding_observations >= self.observation_capacity {
847 return Some(OwnedProviderOperation::PendingCompletion(pending));
848 }
849 let cancellation_token = pending.invocation.cancellation_token();
850 match self
851 .runtime
852 .try_complete(&mut pending.invocation, &pending.observation)
853 {
854 Ok(sequence) => {
855 self.outstanding_observations += 1;
856 report.observations_submitted += 1;
857 Some(OwnedProviderOperation::AwaitingObservationOutcome(
858 AwaitingObservationOutcome {
859 key: pending.key,
860 capability_id: pending.capability_id,
861 deadline_tick: pending.deadline_tick,
862 sequence,
863 cancellation_token,
864 cancellation_reason: None,
865 },
866 ))
867 }
868 Err(ProviderRuntimeError::Full) => {
869 Some(OwnedProviderOperation::PendingCompletion(pending))
870 }
871 Err(error) => {
872 let operation = pending.key.clone();
873 self.push_tombstone(pending.key, report);
874 self.record_blocking_fault(
875 Some(operation),
876 ProviderSupervisorFaultKind::RuntimeCompletionFailed(error),
877 None,
878 report,
879 );
880 None
881 }
882 }
883 }
884 OwnedProviderOperation::AwaitingObservationOutcome(awaiting) => {
885 Some(OwnedProviderOperation::AwaitingObservationOutcome(awaiting))
886 }
887 OwnedProviderOperation::AwaitingCancellation(awaiting) => {
888 if self.retirement_requested {
889 self.push_tombstone(awaiting.key, report);
890 None
891 } else {
892 Some(OwnedProviderOperation::AwaitingCancellation(awaiting))
893 }
894 }
895 }
896 }
897
898 fn drain_work(&mut self, report: &mut ProviderSupervisorTick) {
899 for _ in 0..MAX_PROVIDER_SUPERVISOR_WORK_PER_TICK {
900 match self.runtime.try_recv() {
901 Ok(ProviderWork::Cancel(cancellation)) => {
902 report.work_received += 1;
903 self.handle_cancellation(cancellation, report);
904 }
905 Ok(ProviderWork::Invoke(invocation)) => {
906 report.work_received += 1;
907 if self.retirement_requested || self.detach_blocked {
908 self.push_tombstone(operation_key(&invocation), report);
909 } else {
910 self.start_invocation(invocation, report);
911 }
912 }
913 Err(TryRecvError::Empty | TryRecvError::Disconnected) => return,
914 }
915 }
916 }
917
918 fn start_invocation(
919 &mut self,
920 invocation: ProviderInvocation,
921 report: &mut ProviderSupervisorTick,
922 ) {
923 let key = operation_key(&invocation);
924 let capability_id = invocation.capability_id().clone();
925 let deadline_tick = invocation.deadline_tick();
926 if self.owned.contains_key(&key.operation_id)
927 || self
928 .tombstones
929 .iter()
930 .any(|tombstone| tombstone.key.operation_id == key.operation_id)
931 {
932 self.record_blocking_fault(
933 Some(key),
934 ProviderSupervisorFaultKind::ConflictingInvocation,
935 None,
936 report,
937 );
938 return;
939 }
940 if self.owned.len() >= MAX_PROVIDER_SUPERVISOR_OPERATIONS {
941 self.record_blocking_fault(
942 Some(key),
943 ProviderSupervisorFaultKind::OperationCapacityExceeded,
944 None,
945 report,
946 );
947 return;
948 }
949 if !self.descriptor.has_capability(&capability_id) {
950 self.record_fault(
951 Some(key.clone()),
952 ProviderSupervisorFaultKind::InvalidExecutorObservation,
953 None,
954 false,
955 report,
956 );
957 self.owned.insert(key.operation_id, OwnedProviderOperation::PendingCompletion(
958 PendingCompletion {
959 key: key.clone(),
960 capability_id,
961 deadline_tick,
962 invocation,
963 observation: contract_violation_observation(),
964 },
965 ));
966 return;
967 }
968
969 if invocation.cancellation_token().is_cancelled() {
970 self.owned.insert(
971 key.operation_id,
972 OwnedProviderOperation::AwaitingCancellation(AwaitingCancellation {
973 key,
974 capability_id,
975 deadline_tick,
976 }),
977 );
978 return;
979 }
980
981 match self.executor.start(&invocation) {
982 Ok(operation) => {
983 report.operations_started += 1;
984 self.owned.insert(key.operation_id, OwnedProviderOperation::Physical(OwnedPhysicalOperation {
985 key: key.clone(),
986 capability_id,
987 deadline_tick,
988 invocation,
989 operation,
990 stop_signal_attempted: false,
991 stop_signal_attempts: 0,
992 stop_signalled: false,
993 stop_signalled_at: None,
994 force_stop_attempts: 0,
995 force_stop_signalled: false,
996 stop_cause: None,
997 cancellation_received: false,
998 result: None,
999 result_closed: false,
1000 physical_exit: None,
1001 exit_ack_emitted: false,
1002 }));
1003 }
1004 Err(failure) => {
1005 let observation = if failure.validate().is_ok() {
1006 CapabilityObservation::Failed { failure }
1007 } else {
1008 self.record_fault(
1009 Some(key.clone()),
1010 ProviderSupervisorFaultKind::InvalidExecutorFailure,
1011 None,
1012 false,
1013 report,
1014 );
1015 contract_violation_observation()
1016 };
1017 self.owned.insert(key.operation_id, OwnedProviderOperation::PendingCompletion(
1018 PendingCompletion {
1019 key: key.clone(),
1020 capability_id,
1021 deadline_tick,
1022 invocation,
1023 observation,
1024 },
1025 ));
1026 }
1027 }
1028 }
1029
1030 fn handle_cancellation(
1031 &mut self,
1032 cancellation: ProviderCancellation,
1033 report: &mut ProviderSupervisorTick,
1034 ) {
1035 let key = ProviderOperationKey {
1036 binding_id: cancellation.binding_id(),
1037 operation_id: cancellation.operation_id(),
1038 request_key: cancellation.request_key().clone(),
1039 };
1040 let Some(mut owned) = self.owned.remove(&key.operation_id) else {
1041 if let Some(index) = self
1042 .tombstones
1043 .iter()
1044 .position(|tombstone| tombstone.key.operation_id == key.operation_id)
1045 {
1046 if self.tombstones[index].key != key {
1047 self.record_blocking_fault(
1048 Some(key),
1049 ProviderSupervisorFaultKind::CancellationIdentityMismatch,
1050 None,
1051 report,
1052 );
1053 } else {
1054 self.tombstones.remove(index);
1055 }
1056 return;
1057 }
1058 self.record_blocking_fault(
1059 Some(key),
1060 ProviderSupervisorFaultKind::UnknownCancellation,
1061 None,
1062 report,
1063 );
1064 return;
1065 };
1066 if owned.key() != &key {
1067 owned.fence_for_fault(self.retirement_requested);
1068 self.owned.insert(key.operation_id, owned);
1069 self.record_blocking_fault(
1070 Some(key),
1071 ProviderSupervisorFaultKind::CancellationIdentityMismatch,
1072 None,
1073 report,
1074 );
1075 return;
1076 }
1077
1078 match owned {
1079 OwnedProviderOperation::Physical(mut owned) => {
1080 let stop_cause = ProviderStopCause::Cancellation {
1081 reason: cancellation.reason(),
1082 };
1083 owned.cancellation_received = true;
1084 if owned.stop_cause.is_none()
1085 && (owned.physical_exit.is_none() || owned.stop_signal_attempted)
1086 {
1087 owned.stop_cause = Some(stop_cause);
1088 }
1089 if owned.exit_ack_emitted {
1090 if let Some(ack) = self
1091 .exit_acks
1092 .iter_mut()
1093 .find(|ack| ack.operation == key)
1094 {
1095 if ack.stop_cause.is_none()
1096 && owned.stop_cause == Some(stop_cause)
1097 {
1098 ack.stop_cause = owned.stop_cause;
1099 }
1100 }
1101 }
1102 if let Some(owned) =
1103 self.tick_owned(OwnedProviderOperation::Physical(owned), report)
1104 {
1105 self.owned.insert(key.operation_id, owned);
1106 }
1107 }
1108 OwnedProviderOperation::PendingCompletion(_)
1109 | OwnedProviderOperation::AwaitingCancellation(_) => {}
1110 OwnedProviderOperation::AwaitingObservationOutcome(mut awaiting) => {
1111 awaiting.cancellation_reason = Some(cancellation.reason());
1112 self.owned.insert(
1113 key.operation_id,
1114 OwnedProviderOperation::AwaitingObservationOutcome(awaiting),
1115 );
1116 }
1117 }
1118 }
1119
1120 fn push_tombstone(
1121 &mut self,
1122 key: ProviderOperationKey,
1123 report: &mut ProviderSupervisorTick,
1124 ) {
1125 if self.tombstones.len() >= MAX_PROVIDER_SUPERVISOR_TOMBSTONES {
1126 self.record_blocking_fault(
1127 Some(key),
1128 ProviderSupervisorFaultKind::TombstoneCapacityExceeded,
1129 None,
1130 report,
1131 );
1132 return;
1133 }
1134 self.tombstones.push_back(CompletedOperationTombstone { key });
1135 }
1136
1137 fn request_runtime_close(
1138 &mut self,
1139 report: &mut ProviderSupervisorTick,
1140 ) -> Result<(), ProviderRuntimeError> {
1141 match self.runtime.close() {
1142 Ok(sequence) => {
1143 self.close_sequence = Some(sequence);
1144 self.lifecycle = ProviderSupervisorState::Closing;
1145 report.close_requested = true;
1146 Ok(())
1147 }
1148 Err(ProviderRuntimeError::Full) => {
1149 self.lifecycle = ProviderSupervisorState::Closing;
1150 Ok(())
1151 }
1152 Err(ProviderRuntimeError::Inactive)
1153 if matches!(self.runtime.state(), ProviderRuntimeState::Closed) =>
1154 {
1155 self.lifecycle = ProviderSupervisorState::Closed;
1156 Ok(())
1157 }
1158 Err(error) => {
1159 self.record_blocking_fault(
1160 None,
1161 ProviderSupervisorFaultKind::RuntimeCloseFailed(error),
1162 None,
1163 report,
1164 );
1165 Err(error)
1166 }
1167 }
1168 }
1169
1170 fn record_blocking_fault(
1171 &mut self,
1172 operation: Option<ProviderOperationKey>,
1173 kind: ProviderSupervisorFaultKind,
1174 executor_error_code: Option<&'static str>,
1175 report: &mut ProviderSupervisorTick,
1176 ) {
1177 self.detach_blocked = true;
1178 for owned in self.owned.values_mut() {
1179 owned.fence_for_fault(self.retirement_requested);
1180 }
1181 let _ = self.runtime.begin_quiesce();
1182 self.record_fault(operation, kind, executor_error_code, true, report);
1183 }
1184
1185 fn record_fault(
1186 &mut self,
1187 operation: Option<ProviderOperationKey>,
1188 kind: ProviderSupervisorFaultKind,
1189 executor_error_code: Option<&'static str>,
1190 blocks_detach: bool,
1191 report: &mut ProviderSupervisorTick,
1192 ) {
1193 if self.faults.len() >= MAX_PROVIDER_SUPERVISOR_EVENTS {
1194 self.dropped_faults = self.dropped_faults.saturating_add(1);
1195 report.faults_recorded += 1;
1196 return;
1197 }
1198 self.faults.push_back(ProviderSupervisorFault {
1199 provider_id: self.descriptor.id.clone(),
1200 binding_id: self.runtime.binding_id(),
1201 operation,
1202 kind,
1203 executor_error_code,
1204 blocks_detach,
1205 });
1206 report.faults_recorded += 1;
1207 }
1208}
1209
1210impl OwnedProviderOperation {
1211 fn has_physical_owner(&self) -> bool {
1212 matches!(self, Self::Physical(_))
1213 }
1214
1215 fn fence_for_fault(&mut self, retirement_requested: bool) {
1216 if let Self::Physical(owned) = self {
1217 if retirement_requested {
1218 if owned.physical_exit.is_none()
1219 && !owned.stop_signal_attempted
1220 && owned.stop_cause.is_none()
1221 {
1222 owned.stop_cause = Some(ProviderStopCause::Retirement);
1223 }
1224 } else if owned.physical_exit.is_none()
1225 && !owned.stop_signal_attempted
1226 && owned.stop_cause.is_none()
1227 {
1228 owned.stop_cause = Some(ProviderStopCause::SupervisorFault);
1229 }
1230 }
1231 }
1232
1233 fn fence_for_runtime_close(&mut self, retirement_requested: bool) {
1234 let Self::Physical(owned) = self else {
1235 return;
1236 };
1237 if owned.stop_cause.is_some() {
1238 return;
1239 }
1240 if owned.stop_signal_attempted {
1241 owned.stop_cause = Some(ProviderStopCause::SupervisorFault);
1242 } else if owned.physical_exit.is_none() {
1243 owned.stop_cause = Some(if retirement_requested {
1244 ProviderStopCause::Retirement
1245 } else {
1246 ProviderStopCause::SupervisorFault
1247 });
1248 }
1249 }
1250
1251 fn key(&self) -> &ProviderOperationKey {
1252 match self {
1253 Self::Physical(owned) => &owned.key,
1254 Self::PendingCompletion(pending) => &pending.key,
1255 Self::AwaitingObservationOutcome(awaiting) => &awaiting.key,
1256 Self::AwaitingCancellation(awaiting) => &awaiting.key,
1257 }
1258 }
1259
1260 fn snapshot(&self) -> ProviderOperationSnapshot {
1261 match self {
1262 Self::Physical(owned) => ProviderOperationSnapshot {
1263 operation: owned.key.clone(),
1264 capability_id: owned.capability_id.clone(),
1265 deadline_tick: owned.deadline_tick,
1266 stop_signal_attempted: owned.stop_signal_attempted,
1267 stop_signalled: owned.stop_signalled,
1268 force_stop_attempted: owned.force_stop_attempts != 0,
1269 force_stop_signalled: owned.force_stop_signalled,
1270 stop_cause: owned.stop_cause,
1271 physical_exit: owned.physical_exit,
1272 result_ready: owned.result.is_some(),
1273 },
1274 Self::PendingCompletion(pending) => ProviderOperationSnapshot {
1275 operation: pending.key.clone(),
1276 capability_id: pending.capability_id.clone(),
1277 deadline_tick: pending.deadline_tick,
1278 stop_signal_attempted: false,
1279 stop_signalled: false,
1280 force_stop_attempted: false,
1281 force_stop_signalled: false,
1282 stop_cause: None,
1283 physical_exit: None,
1284 result_ready: true,
1285 },
1286 Self::AwaitingObservationOutcome(awaiting) => ProviderOperationSnapshot {
1287 operation: awaiting.key.clone(),
1288 capability_id: awaiting.capability_id.clone(),
1289 deadline_tick: awaiting.deadline_tick,
1290 stop_signal_attempted: false,
1291 stop_signalled: false,
1292 force_stop_attempted: false,
1293 force_stop_signalled: false,
1294 stop_cause: awaiting
1295 .cancellation_reason
1296 .map(|reason| ProviderStopCause::Cancellation { reason }),
1297 physical_exit: None,
1298 result_ready: true,
1299 },
1300 Self::AwaitingCancellation(awaiting) => ProviderOperationSnapshot {
1301 operation: awaiting.key.clone(),
1302 capability_id: awaiting.capability_id.clone(),
1303 deadline_tick: awaiting.deadline_tick,
1304 stop_signal_attempted: false,
1305 stop_signalled: false,
1306 force_stop_attempted: false,
1307 force_stop_signalled: false,
1308 stop_cause: None,
1309 physical_exit: None,
1310 result_ready: false,
1311 },
1312 }
1313 }
1314
1315 fn exit_ack_backpressured(&self) -> bool {
1316 matches!(
1317 self,
1318 Self::Physical(OwnedPhysicalOperation {
1319 physical_exit: Some(_),
1320 exit_ack_emitted: false,
1321 ..
1322 })
1323 )
1324 }
1325}
1326
1327impl Drop for ProviderSupervisor {
1328 fn drop(&mut self) {
1329 for owned in self.owned.values_mut() {
1330 let OwnedProviderOperation::Physical(owned) = owned else {
1331 continue;
1332 };
1333 if owned.physical_exit.is_none() {
1334 owned.stop_signal_attempted = true;
1335 if owned.stop_cause.is_none() {
1336 owned.stop_cause = Some(ProviderStopCause::Retirement);
1337 }
1338 let _ = owned.operation.request_force_stop();
1339 }
1340 }
1341 }
1342}
1343
1344fn operation_key(invocation: &ProviderInvocation) -> ProviderOperationKey {
1345 ProviderOperationKey {
1346 binding_id: invocation.binding_id(),
1347 operation_id: invocation.operation_id(),
1348 request_key: invocation.request_key().clone(),
1349 }
1350}
1351
1352fn contract_violation_observation() -> CapabilityObservation {
1353 CapabilityObservation::Failed {
1354 failure: ToolFailure {
1355 kind: ToolFailureKind::ProviderContractViolation,
1356 redacted_message: None,
1357 },
1358 }
1359}
1360
1361fn drain_queue<T>(queue: &mut VecDeque<T>, limit: usize) -> Vec<T> {
1362 let count = limit.min(queue.len());
1363 queue.drain(..count).collect()
1364}