1use std::collections::{BTreeMap, BTreeSet};
2use std::sync::Arc;
3
4use super::*;
5
6#[derive(Clone)]
7pub(crate) struct RegisteredHook<T> {
8 pub(crate) plugin_id: String,
9 pub(crate) hook: T,
10}
11
12#[derive(Clone)]
13pub(crate) struct RegisteredExclusiveHook<T> {
14 pub(crate) plugin_id: String,
15 pub(crate) hook: T,
16}
17
18pub(crate) fn current_registration_owner(registering_plugin_id: &Option<String>) -> String {
19 registering_plugin_id
20 .clone()
21 .unwrap_or_else(|| "__unknown__".to_string())
22}
23
24fn push_registered_hook<T>(
25 hooks: &mut Vec<RegisteredHook<T>>,
26 registering_plugin_id: &Option<String>,
27 hook: T,
28) {
29 hooks.push(RegisteredHook {
30 plugin_id: current_registration_owner(registering_plugin_id),
31 hook,
32 });
33}
34
35fn push_prioritized_registered_hook<T>(
36 hooks: &mut Vec<(i32, RegisteredHook<T>)>,
37 registering_plugin_id: &Option<String>,
38 priority: i32,
39 hook: T,
40) {
41 hooks.push((
42 priority,
43 RegisteredHook {
44 plugin_id: current_registration_owner(registering_plugin_id),
45 hook,
46 },
47 ));
48}
49
50fn exclusive_hook_owner(
51 existing_owner: Option<&str>,
52 registering_plugin_id: &Option<String>,
53 hook_kind: &str,
54 hook_name: &str,
55) -> Result<String, PluginError> {
56 let plugin_id = registering_plugin_id
57 .clone()
58 .ok_or_else(|| PluginError::Registration("missing registering plugin id".to_string()))?;
59 if let Some(existing) = existing_owner {
60 return Err(PluginError::Registration(format!(
61 "duplicate {hook_kind} for `{hook_name}`: `{plugin_id}` conflicts with `{existing}`"
62 )));
63 }
64 Ok(plugin_id)
65}
66
67fn register_singleton_hook<H>(
68 slot: &mut Option<RegisteredExclusiveHook<H>>,
69 registering_plugin_id: &Option<String>,
70 hook_kind: &str,
71 hook_name: &str,
72 hook: H,
73) -> Result<(), PluginError> {
74 let plugin_id = exclusive_hook_owner(
75 slot.as_ref()
76 .map(|registered| registered.plugin_id.as_str()),
77 registering_plugin_id,
78 hook_kind,
79 hook_name,
80 )?;
81 *slot = Some(RegisteredExclusiveHook { plugin_id, hook });
82 Ok(())
83}
84
85#[derive(Clone, Default)]
86pub(crate) struct PluginContributions {
87 pub(crate) tool_providers: Vec<Arc<dyn ToolProvider>>,
88 pub(crate) triggers: Vec<crate::TriggerEvent>,
89 pub(crate) prompt_contributors: Vec<RegisteredHook<PromptContributor>>,
90 pub(crate) tool_catalog_contributors: Vec<RegisteredHook<ToolCatalogContributor>>,
91 pub(crate) before_turn_hooks: Vec<RegisteredHook<BeforeTurnHook>>,
92 pub(crate) before_tool_call_hooks: Vec<RegisteredHook<BeforeToolCallHook>>,
93 pub(crate) after_tool_call_hooks: Vec<RegisteredHook<AfterToolCallHook>>,
94 pub(crate) after_turn_hooks: Vec<RegisteredHook<AfterTurnHook>>,
95 pub(crate) checkpoint_hooks: Vec<RegisteredHook<CheckpointHook>>,
96 pub(crate) assistant_stream_hooks: Vec<RegisteredHook<AssistantStreamHook>>,
97 pub(crate) assistant_response_hooks: Vec<RegisteredHook<AssistantResponseHook>>,
98 pub(crate) assistant_stream_finished_hooks: Vec<RegisteredHook<AssistantStreamFinishedHook>>,
99 pub(crate) tool_result_projector: Option<RegisteredExclusiveHook<ToolResultProjector>>,
100 pub(crate) runtime_event_hooks: Vec<RegisteredHook<PluginLifecycleEventHook>>,
101 pub(crate) session_config_mutators: Vec<SessionConfigMutator>,
102 pub(crate) plugin_queries: BTreeMap<String, RegisteredPluginQuery>,
103 pub(crate) plugin_commands: BTreeMap<String, RegisteredPluginCommand>,
104 pub(crate) plugin_tasks: BTreeMap<String, RegisteredPluginTask>,
105 pub(crate) turn_context_transforms: Vec<(i32, RegisteredHook<Arc<dyn TurnContextTransform>>)>,
106 pub(crate) context_compactors: Vec<(i32, RegisteredHook<Arc<dyn ContextCompactor>>)>,
107 pub(crate) protocol_session: Option<RegisteredExclusiveHook<Arc<dyn ProtocolSessionPlugin>>>,
108 pub(crate) protocol_driver: Option<RegisteredExclusiveHook<Arc<dyn ProtocolDriverPlugin>>>,
109 pub(crate) code_executor: Option<RegisteredExclusiveHook<Arc<dyn CodeExecutorPlugin>>>,
110 pub(crate) assistant_prose_projector:
111 Option<RegisteredExclusiveHook<Arc<dyn AssistantProseProjectorPlugin>>>,
112}
113
114pub struct PluginRegistrar {
115 pub(crate) tool_names: BTreeSet<String>,
116 pub(crate) contributions: PluginContributions,
117 pub(crate) registering_plugin_id: Option<String>,
118}
119
120pub struct ToolRegistrations<'a> {
121 reg: &'a mut PluginRegistrar,
122}
123
124impl ToolRegistrations<'_> {
125 pub fn provider(self, provider: Arc<dyn ToolProvider>) -> Result<(), PluginError> {
126 self.reg.add_tool_provider(provider)
127 }
128}
129
130pub struct TriggerEventRegistrations<'a> {
131 reg: &'a mut PluginRegistrar,
132}
133
134impl TriggerEventRegistrations<'_> {
135 pub fn declare(self, event: crate::TriggerEvent) -> Result<(), PluginError> {
136 self.reg.add_trigger(event)
137 }
138}
139
140pub struct PromptRegistrations<'a> {
141 reg: &'a mut PluginRegistrar,
142}
143
144impl PromptRegistrations<'_> {
145 pub fn contribute(self, contributor: PromptContributor) {
146 self.reg.add_prompt_contributor(contributor);
147 }
148}
149
150pub struct ToolCatalogRegistrations<'a> {
151 reg: &'a mut PluginRegistrar,
152}
153
154impl ToolCatalogRegistrations<'_> {
155 pub fn contribute(self, contributor: ToolCatalogContributor) {
156 self.reg.add_tool_catalog_contributor(contributor);
157 }
158}
159
160pub struct TurnRegistrations<'a> {
161 reg: &'a mut PluginRegistrar,
162}
163
164impl TurnRegistrations<'_> {
165 pub fn before(self, hook: BeforeTurnHook) {
166 self.reg.add_before_turn_hook(hook);
167 }
168
169 pub fn after(self, hook: AfterTurnHook) {
170 self.reg.add_after_turn_hook(hook);
171 }
172
173 pub fn checkpoint(self, hook: CheckpointHook) {
174 self.reg.add_checkpoint_hook(hook);
175 }
176}
177
178pub struct ToolCallRegistrations<'a> {
179 reg: &'a mut PluginRegistrar,
180}
181
182impl ToolCallRegistrations<'_> {
183 pub fn before(self, hook: BeforeToolCallHook) {
184 self.reg.add_before_tool_call_hook(hook);
185 }
186
187 pub fn after(self, hook: AfterToolCallHook) {
188 self.reg.add_after_tool_call_hook(hook);
189 }
190}
191
192pub struct OutputRegistrations<'a> {
193 reg: &'a mut PluginRegistrar,
194}
195
196impl OutputRegistrations<'_> {
197 pub fn stream(self, hook: AssistantStreamHook) {
198 self.reg.add_assistant_stream_hook(hook);
199 }
200
201 pub fn response(self, hook: AssistantResponseHook) {
202 self.reg.add_assistant_response_hook(hook);
203 }
204
205 pub fn stream_finished(self, hook: AssistantStreamFinishedHook) {
206 self.reg.add_assistant_stream_finished_hook(hook);
207 }
208
209 pub fn assistant_prose_projector(
210 self,
211 provider: Arc<dyn AssistantProseProjectorPlugin>,
212 ) -> Result<(), PluginError> {
213 self.reg.add_assistant_prose_projector(provider)
214 }
215}
216
217pub struct ToolResultRegistrations<'a> {
218 reg: &'a mut PluginRegistrar,
219}
220
221impl ToolResultRegistrations<'_> {
222 pub fn projector(self, hook: ToolResultProjector) -> Result<(), PluginError> {
223 self.reg.add_tool_result_projector(hook)
224 }
225}
226
227pub struct SessionRegistrations<'a> {
228 reg: &'a mut PluginRegistrar,
229}
230
231impl SessionRegistrations<'_> {
232 pub fn on_event(self, hook: PluginLifecycleEventHook) {
233 push_registered_hook(
234 &mut self.reg.contributions.runtime_event_hooks,
235 &self.reg.registering_plugin_id,
236 hook,
237 );
238 }
239
240 pub fn config_mutator(self, hook: SessionConfigMutator) {
241 self.reg.contributions.session_config_mutators.push(hook);
242 }
243}
244
245pub struct PluginOperationRegistrations<'a> {
246 reg: &'a mut PluginRegistrar,
247}
248
249impl PluginOperationRegistrations<'_> {
250 pub(crate) fn query(
251 self,
252 def: PluginOperationDef,
253 handler: PluginQueryHandler,
254 ) -> Result<(), PluginError> {
255 self.reg.add_plugin_query(def, handler)
256 }
257
258 pub(crate) fn command(
259 self,
260 def: PluginOperationDef,
261 handler: PluginCommandHandler,
262 ) -> Result<(), PluginError> {
263 self.reg.add_plugin_command(def, handler)
264 }
265
266 pub(crate) fn task(
267 self,
268 def: PluginOperationDef,
269 handler: PluginTaskHandler,
270 ) -> Result<(), PluginError> {
271 self.reg.add_plugin_task(def, handler)
272 }
273
274 pub fn typed_query<Op, F, Fut>(self, handler: F) -> Result<(), PluginError>
275 where
276 Op: PluginQuery,
277 F: Fn(PluginQueryContext, Op::Args) -> Fut + Send + Sync + 'static,
278 Fut: Future<Output = Result<Op::Output, PluginOperationFailure>> + Send + 'static,
279 {
280 self.query(
281 plugin_operation_def::<Op>(PluginOperationKind::Query),
282 Arc::new(move |ctx, args| {
283 let parsed = serde_json::from_value::<Op::Args>(args);
284 match parsed {
285 Ok(args) => {
286 let fut = handler(ctx, args);
287 Box::pin(async move {
288 let output = fut.await?;
289 serde_json::to_value(output).map_err(|err| {
290 PluginOperationFailure::new(format!(
291 "failed to serialize {} output: {err}",
292 Op::NAME
293 ))
294 })
295 }) as PluginQueryInvokeFuture
296 }
297 Err(err) => Box::pin(async move {
298 Err(PluginOperationFailure::new(format!(
299 "invalid {} args: {err}",
300 Op::NAME
301 )))
302 }) as PluginQueryInvokeFuture,
303 }
304 }),
305 )
306 }
307
308 pub fn typed_command<Op, F, Fut>(self, handler: F) -> Result<(), PluginError>
309 where
310 Op: PluginCommand,
311 F: Fn(PluginCommandContext, Op::Args) -> Fut + Send + Sync + 'static,
312 Fut: Future<Output = Result<PluginCommandOutcome<Op::Output>, PluginOperationFailure>>
313 + Send
314 + 'static,
315 {
316 self.command(
317 plugin_operation_def::<Op>(PluginOperationKind::Command),
318 Arc::new(move |ctx, args| {
319 let parsed = serde_json::from_value::<Op::Args>(args);
320 match parsed {
321 Ok(args) => {
322 let fut = handler(ctx, args);
323 Box::pin(async move {
324 let outcome = fut.await?;
325 let output = serde_json::to_value(outcome.output).map_err(|err| {
326 PluginOperationFailure::new(format!(
327 "failed to serialize {} output: {err}",
328 Op::NAME
329 ))
330 })?;
331 Ok(ErasedPluginCommandOutcome {
332 output,
333 events: outcome.events,
334 directives: outcome.directives,
335 })
336 }) as PluginCommandInvokeFuture
337 }
338 Err(err) => Box::pin(async move {
339 Err(PluginOperationFailure::new(format!(
340 "invalid {} args: {err}",
341 Op::NAME
342 )))
343 }) as PluginCommandInvokeFuture,
344 }
345 }),
346 )
347 }
348
349 pub fn typed_command_value<Op, F, Fut>(self, handler: F) -> Result<(), PluginError>
350 where
351 Op: PluginCommand,
352 F: Fn(PluginCommandContext, Op::Args) -> Fut + Send + Sync + 'static,
353 Fut: Future<Output = Result<Op::Output, PluginOperationFailure>> + Send + 'static,
354 {
355 self.typed_command::<Op, _, _>(move |ctx, args| {
356 let fut = handler(ctx, args);
357 async move { fut.await.map(PluginCommandOutcome::new) }
358 })
359 }
360
361 pub fn typed_task<Op, F, Fut>(self, handler: F) -> Result<(), PluginError>
362 where
363 Op: PluginTask,
364 F: Fn(PluginTaskContext, Op::Args) -> Fut + Send + Sync + 'static,
365 Fut: Future<Output = Result<PluginTaskOutcome<Op::Output>, PluginOperationFailure>>
366 + Send
367 + 'static,
368 {
369 self.task(
370 plugin_operation_def::<Op>(PluginOperationKind::Task),
371 Arc::new(move |ctx, args| {
372 let parsed = serde_json::from_value::<Op::Args>(args);
373 match parsed {
374 Ok(args) => {
375 let fut = handler(ctx, args);
376 Box::pin(async move {
377 let outcome = fut.await?;
378 let output = serde_json::to_value(outcome.output).map_err(|err| {
379 PluginOperationFailure::new(format!(
380 "failed to serialize {} output: {err}",
381 Op::NAME
382 ))
383 })?;
384 Ok(ErasedPluginTaskOutcome {
385 output,
386 events: outcome.events,
387 directives: outcome.directives,
388 })
389 }) as PluginTaskInvokeFuture
390 }
391 Err(err) => Box::pin(async move {
392 Err(PluginOperationFailure::new(format!(
393 "invalid {} args: {err}",
394 Op::NAME
395 )))
396 }) as PluginTaskInvokeFuture,
397 }
398 }),
399 )
400 }
401
402 pub fn typed_task_value<Op, F, Fut>(self, handler: F) -> Result<(), PluginError>
403 where
404 Op: PluginTask,
405 F: Fn(PluginTaskContext, Op::Args) -> Fut + Send + Sync + 'static,
406 Fut: Future<Output = Result<Op::Output, PluginOperationFailure>> + Send + 'static,
407 {
408 self.typed_task::<Op, _, _>(move |ctx, args| {
409 let fut = handler(ctx, args);
410 async move { fut.await.map(PluginTaskOutcome::new) }
411 })
412 }
413}
414
415pub struct ContextRegistrations<'a> {
416 reg: &'a mut PluginRegistrar,
417}
418
419impl ContextRegistrations<'_> {
420 pub fn prepare_turn(self, priority: i32, transform: Arc<dyn TurnContextTransform>) {
422 push_prioritized_registered_hook(
423 &mut self.reg.contributions.turn_context_transforms,
424 &self.reg.registering_plugin_id,
425 priority,
426 transform,
427 );
428 }
429
430 pub fn compact(self, priority: i32, compactor: Arc<dyn ContextCompactor>) {
432 push_prioritized_registered_hook(
433 &mut self.reg.contributions.context_compactors,
434 &self.reg.registering_plugin_id,
435 priority,
436 compactor,
437 );
438 }
439}
440
441pub struct ProtocolRegistrations<'a> {
442 reg: &'a mut PluginRegistrar,
443}
444
445impl ProtocolRegistrations<'_> {
446 pub fn session(self, provider: Arc<dyn ProtocolSessionPlugin>) -> Result<(), PluginError> {
447 self.reg.add_protocol_session(provider)
448 }
449
450 pub fn protocol_driver(
454 self,
455 provider: Arc<dyn ProtocolDriverPlugin>,
456 ) -> Result<(), PluginError> {
457 self.reg.add_protocol_driver(provider)
458 }
459}
460
461pub struct ExecutionRegistrations<'a> {
462 reg: &'a mut PluginRegistrar,
463}
464
465impl ExecutionRegistrations<'_> {
466 pub fn code_executor(self, provider: Arc<dyn CodeExecutorPlugin>) -> Result<(), PluginError> {
467 self.reg.add_code_executor(provider)
468 }
469}
470
471impl PluginRegistrar {
472 pub(crate) fn new() -> Self {
473 Self {
474 tool_names: BTreeSet::new(),
475 contributions: PluginContributions::default(),
476 registering_plugin_id: None,
477 }
478 }
479
480 pub fn tools(&mut self) -> ToolRegistrations<'_> {
481 ToolRegistrations { reg: self }
482 }
483
484 pub fn triggers(&mut self) -> TriggerEventRegistrations<'_> {
485 TriggerEventRegistrations { reg: self }
486 }
487
488 pub fn prompt(&mut self) -> PromptRegistrations<'_> {
489 PromptRegistrations { reg: self }
490 }
491
492 pub fn tool_catalog(&mut self) -> ToolCatalogRegistrations<'_> {
493 ToolCatalogRegistrations { reg: self }
494 }
495
496 pub fn turn(&mut self) -> TurnRegistrations<'_> {
497 TurnRegistrations { reg: self }
498 }
499
500 pub fn tool_calls(&mut self) -> ToolCallRegistrations<'_> {
501 ToolCallRegistrations { reg: self }
502 }
503
504 pub fn output(&mut self) -> OutputRegistrations<'_> {
505 OutputRegistrations { reg: self }
506 }
507
508 pub fn tool_results(&mut self) -> ToolResultRegistrations<'_> {
509 ToolResultRegistrations { reg: self }
510 }
511
512 pub fn session(&mut self) -> SessionRegistrations<'_> {
513 SessionRegistrations { reg: self }
514 }
515
516 pub fn operations(&mut self) -> PluginOperationRegistrations<'_> {
517 PluginOperationRegistrations { reg: self }
518 }
519
520 pub fn context(&mut self) -> ContextRegistrations<'_> {
521 ContextRegistrations { reg: self }
522 }
523
524 pub fn protocol(&mut self) -> ProtocolRegistrations<'_> {
525 ProtocolRegistrations { reg: self }
526 }
527
528 pub fn execution(&mut self) -> ExecutionRegistrations<'_> {
529 ExecutionRegistrations { reg: self }
530 }
531
532 fn add_tool_provider(&mut self, provider: Arc<dyn ToolProvider>) -> Result<(), PluginError> {
533 for manifest in provider.tool_manifests() {
534 if !self.tool_names.insert(manifest.name.clone()) {
535 return Err(PluginError::Registration(format!(
536 "duplicate plugin tool name `{}`",
537 manifest.name
538 )));
539 }
540 }
541 self.contributions.tool_providers.push(provider);
542 Ok(())
543 }
544
545 fn add_trigger(&mut self, event: crate::TriggerEvent) -> Result<(), PluginError> {
546 if self
547 .contributions
548 .triggers
549 .iter()
550 .any(|existing| existing.key() == event.key())
551 {
552 return Err(PluginError::Registration(format!(
553 "duplicate trigger occurrence `{}.{}.{}`",
554 event.resource_type, event.alias, event.event
555 )));
556 }
557 self.contributions.triggers.push(event);
558 Ok(())
559 }
560
561 fn add_prompt_contributor(&mut self, contributor: PromptContributor) {
562 push_registered_hook(
563 &mut self.contributions.prompt_contributors,
564 &self.registering_plugin_id,
565 contributor,
566 );
567 }
568
569 fn add_tool_catalog_contributor(&mut self, contributor: ToolCatalogContributor) {
570 push_registered_hook(
571 &mut self.contributions.tool_catalog_contributors,
572 &self.registering_plugin_id,
573 contributor,
574 );
575 }
576
577 fn add_before_turn_hook(&mut self, hook: BeforeTurnHook) {
578 push_registered_hook(
579 &mut self.contributions.before_turn_hooks,
580 &self.registering_plugin_id,
581 hook,
582 );
583 }
584
585 fn add_before_tool_call_hook(&mut self, hook: BeforeToolCallHook) {
586 push_registered_hook(
587 &mut self.contributions.before_tool_call_hooks,
588 &self.registering_plugin_id,
589 hook,
590 );
591 }
592
593 fn add_after_tool_call_hook(&mut self, hook: AfterToolCallHook) {
594 push_registered_hook(
595 &mut self.contributions.after_tool_call_hooks,
596 &self.registering_plugin_id,
597 hook,
598 );
599 }
600
601 fn add_after_turn_hook(&mut self, hook: AfterTurnHook) {
602 push_registered_hook(
603 &mut self.contributions.after_turn_hooks,
604 &self.registering_plugin_id,
605 hook,
606 );
607 }
608
609 fn add_checkpoint_hook(&mut self, hook: CheckpointHook) {
610 push_registered_hook(
611 &mut self.contributions.checkpoint_hooks,
612 &self.registering_plugin_id,
613 hook,
614 );
615 }
616
617 fn add_assistant_stream_hook(&mut self, hook: AssistantStreamHook) {
618 push_registered_hook(
619 &mut self.contributions.assistant_stream_hooks,
620 &self.registering_plugin_id,
621 hook,
622 );
623 }
624
625 fn add_assistant_response_hook(&mut self, hook: AssistantResponseHook) {
626 push_registered_hook(
627 &mut self.contributions.assistant_response_hooks,
628 &self.registering_plugin_id,
629 hook,
630 );
631 }
632
633 fn add_assistant_stream_finished_hook(&mut self, hook: AssistantStreamFinishedHook) {
634 push_registered_hook(
635 &mut self.contributions.assistant_stream_finished_hooks,
636 &self.registering_plugin_id,
637 hook,
638 );
639 }
640
641 fn add_assistant_prose_projector(
642 &mut self,
643 provider: Arc<dyn AssistantProseProjectorPlugin>,
644 ) -> Result<(), PluginError> {
645 register_singleton_hook(
646 &mut self.contributions.assistant_prose_projector,
647 &self.registering_plugin_id,
648 "assistant prose projector",
649 "assistant_prose_projector",
650 provider,
651 )
652 }
653
654 fn add_tool_result_projector(&mut self, hook: ToolResultProjector) -> Result<(), PluginError> {
655 register_singleton_hook(
656 &mut self.contributions.tool_result_projector,
657 &self.registering_plugin_id,
658 "tool result projector",
659 "model_observation",
660 hook,
661 )
662 }
663
664 fn operation_owner(&self) -> Result<String, PluginError> {
665 self.registering_plugin_id
666 .clone()
667 .ok_or_else(|| PluginError::Registration("missing registering plugin id".to_string()))
668 }
669
670 fn ensure_unique_operation_name(&self, name: &str) -> Result<(), PluginError> {
671 if self.contributions.plugin_queries.contains_key(name)
672 || self.contributions.plugin_commands.contains_key(name)
673 || self.contributions.plugin_tasks.contains_key(name)
674 {
675 return Err(PluginError::Registration(format!(
676 "duplicate plugin operation name `{name}`"
677 )));
678 }
679 Ok(())
680 }
681
682 fn add_plugin_query(
683 &mut self,
684 def: PluginOperationDef,
685 handler: PluginQueryHandler,
686 ) -> Result<(), PluginError> {
687 self.ensure_unique_operation_name(&def.name)?;
688 let plugin_id = self.operation_owner()?;
689 self.contributions.plugin_queries.insert(
690 def.name.clone(),
691 RegisteredPluginQuery {
692 plugin_id,
693 def,
694 handler,
695 },
696 );
697 Ok(())
698 }
699
700 fn add_plugin_command(
701 &mut self,
702 def: PluginOperationDef,
703 handler: PluginCommandHandler,
704 ) -> Result<(), PluginError> {
705 self.ensure_unique_operation_name(&def.name)?;
706 let plugin_id = self.operation_owner()?;
707 self.contributions.plugin_commands.insert(
708 def.name.clone(),
709 RegisteredPluginCommand {
710 plugin_id,
711 def,
712 handler,
713 },
714 );
715 Ok(())
716 }
717
718 fn add_plugin_task(
719 &mut self,
720 def: PluginOperationDef,
721 handler: PluginTaskHandler,
722 ) -> Result<(), PluginError> {
723 self.ensure_unique_operation_name(&def.name)?;
724 let plugin_id = self.operation_owner()?;
725 self.contributions.plugin_tasks.insert(
726 def.name.clone(),
727 RegisteredPluginTask {
728 plugin_id,
729 def,
730 handler,
731 },
732 );
733 Ok(())
734 }
735
736 fn add_protocol_session(
737 &mut self,
738 provider: Arc<dyn ProtocolSessionPlugin>,
739 ) -> Result<(), PluginError> {
740 register_singleton_hook(
741 &mut self.contributions.protocol_session,
742 &self.registering_plugin_id,
743 "protocol session capability",
744 "protocol_session",
745 provider,
746 )
747 }
748
749 fn add_code_executor(
750 &mut self,
751 provider: Arc<dyn CodeExecutorPlugin>,
752 ) -> Result<(), PluginError> {
753 register_singleton_hook(
754 &mut self.contributions.code_executor,
755 &self.registering_plugin_id,
756 "code executor capability",
757 "code_executor",
758 provider,
759 )
760 }
761
762 fn add_protocol_driver(
763 &mut self,
764 provider: Arc<dyn ProtocolDriverPlugin>,
765 ) -> Result<(), PluginError> {
766 register_singleton_hook(
767 &mut self.contributions.protocol_driver,
768 &self.registering_plugin_id,
769 "protocol driver capability",
770 "protocol_driver",
771 provider,
772 )
773 }
774}