1use std::future::Future;
2use std::pin::Pin;
3
4use tea_protocol::{ProfileId, ProtocolMetadata, RunId, SessionId};
5use tea_tools::ToolSpec;
6
7use crate::{ContextError, ContextProviderId, PromptModule};
8
9pub const MAX_CONTEXT_TOOLS: usize = 256;
11
12#[derive(Debug, Clone, PartialEq)]
14pub struct ContextRequest {
15 profile_id: ProfileId,
16 session_id: SessionId,
17 run_id: Option<RunId>,
18 active_tools: Vec<ToolSpec>,
19 metadata: ProtocolMetadata,
20}
21
22impl ContextRequest {
23 pub fn new(
29 profile_id: ProfileId,
30 session_id: SessionId,
31 run_id: Option<RunId>,
32 mut active_tools: Vec<ToolSpec>,
33 metadata: ProtocolMetadata,
34 ) -> Result<Self, ContextError> {
35 if active_tools.len() > MAX_CONTEXT_TOOLS {
36 return Err(ContextError::new(
37 crate::ContextErrorCode::BoundsExceeded,
38 "context request contains too many active tools",
39 ));
40 }
41 active_tools.sort_by(|left, right| left.name().cmp(right.name()));
42 if active_tools
43 .windows(2)
44 .any(|tools| tools[0].name() == tools[1].name())
45 {
46 return Err(ContextError::new(
47 crate::ContextErrorCode::DuplicateIdentity,
48 "context request contains duplicate active tool names",
49 ));
50 }
51 Ok(Self {
52 profile_id,
53 session_id,
54 run_id,
55 active_tools,
56 metadata,
57 })
58 }
59
60 #[must_use]
62 pub const fn profile_id(&self) -> &ProfileId {
63 &self.profile_id
64 }
65 #[must_use]
67 pub const fn session_id(&self) -> SessionId {
68 self.session_id
69 }
70 #[must_use]
72 pub const fn run_id(&self) -> Option<RunId> {
73 self.run_id
74 }
75 #[must_use]
77 pub fn active_tools(&self) -> &[ToolSpec] {
78 &self.active_tools
79 }
80 #[must_use]
82 pub const fn metadata(&self) -> &ProtocolMetadata {
83 &self.metadata
84 }
85}
86
87pub type ContextProviderFuture<'a> =
89 Pin<Box<dyn Future<Output = Result<Vec<PromptModule>, ContextError>> + Send + 'a>>;
90
91pub trait ContextProvider: std::fmt::Debug + Send + Sync {
93 fn id(&self) -> &ContextProviderId;
95 fn provide(&self, request: ContextRequest) -> ContextProviderFuture<'_>;
97}
98
99#[derive(Debug, Clone)]
101pub struct StaticContextProvider {
102 id: ContextProviderId,
103 modules: Vec<PromptModule>,
104}
105
106impl StaticContextProvider {
107 #[must_use]
109 pub const fn new(id: ContextProviderId, modules: Vec<PromptModule>) -> Self {
110 Self { id, modules }
111 }
112}
113
114impl ContextProvider for StaticContextProvider {
115 fn id(&self) -> &ContextProviderId {
116 &self.id
117 }
118 fn provide(&self, _request: ContextRequest) -> ContextProviderFuture<'_> {
119 let modules = self.modules.clone();
120 Box::pin(async move { Ok(modules) })
121 }
122}