feat: extract task tools builtin module
This commit is contained in:
parent
9721c81eb0
commit
f394f15ba5
|
|
@ -9,7 +9,7 @@ use session_store::Store;
|
||||||
use tokio::sync::{broadcast, mpsc, oneshot};
|
use tokio::sync::{broadcast, mpsc, oneshot};
|
||||||
|
|
||||||
use crate::discovery::{PodDiscovery, list_pods_tool, restore_pod_tool, send_to_peer_pod_tool};
|
use crate::discovery::{PodDiscovery, list_pods_tool, restore_pod_tool, send_to_peer_pod_tool};
|
||||||
use crate::feature::{FeatureRegistryBuilder, builtin::task_feature};
|
use crate::feature::{FeatureRegistryBuilder, builtin::task_tools_feature};
|
||||||
use crate::ipc::alerter::Alerter;
|
use crate::ipc::alerter::Alerter;
|
||||||
use crate::ipc::notify_buffer::NotifyBuffer;
|
use crate::ipc::notify_buffer::NotifyBuffer;
|
||||||
use crate::ipc::server::SocketServer;
|
use crate::ipc::server::SocketServer;
|
||||||
|
|
@ -522,7 +522,7 @@ where
|
||||||
));
|
));
|
||||||
|
|
||||||
let mut feature_registry = FeatureRegistryBuilder::new();
|
let mut feature_registry = FeatureRegistryBuilder::new();
|
||||||
feature_registry.add_module(task_feature(task_store));
|
feature_registry.add_module(task_tools_feature(task_store));
|
||||||
let _feature_install_report = pod.install_features(feature_registry);
|
let _feature_install_report = pod.install_features(feature_registry);
|
||||||
|
|
||||||
let worker = pod.worker_mut();
|
let worker = pod.worker_mut();
|
||||||
|
|
|
||||||
|
|
@ -1256,59 +1256,7 @@ pub enum FeatureInstallError {
|
||||||
Install(String),
|
Install(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Builtin task tools feature used to prove existing builtin tool registration
|
pub mod builtin;
|
||||||
/// through the feature registry without changing tool names, schemas, or
|
|
||||||
/// permission behavior.
|
|
||||||
pub mod builtin {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
pub fn task_feature(task_store: tools::TaskStore) -> impl FeatureModule {
|
|
||||||
TaskFeature { task_store }
|
|
||||||
}
|
|
||||||
|
|
||||||
struct TaskFeature {
|
|
||||||
task_store: tools::TaskStore,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl FeatureModule for TaskFeature {
|
|
||||||
fn descriptor(&self) -> FeatureDescriptor {
|
|
||||||
FeatureDescriptor::builtin("task-tools", "Task tools")
|
|
||||||
.with_description("Session-lifetime task tracking builtin tools")
|
|
||||||
.with_tool(ToolDeclaration::new(
|
|
||||||
"TaskCreate",
|
|
||||||
"Create a session-lifetime user-visible task",
|
|
||||||
))
|
|
||||||
.with_tool(ToolDeclaration::new(
|
|
||||||
"TaskUpdate",
|
|
||||||
"Update a session-lifetime user-visible task",
|
|
||||||
))
|
|
||||||
.with_tool(ToolDeclaration::new(
|
|
||||||
"TaskGet",
|
|
||||||
"Get one session-lifetime user-visible task",
|
|
||||||
))
|
|
||||||
.with_tool(ToolDeclaration::new(
|
|
||||||
"TaskList",
|
|
||||||
"List session-lifetime user-visible tasks",
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn install(
|
|
||||||
&self,
|
|
||||||
context: &mut FeatureInstallContext<'_>,
|
|
||||||
) -> Result<(), FeatureInstallError> {
|
|
||||||
let names = ["TaskCreate", "TaskList", "TaskGet", "TaskUpdate"];
|
|
||||||
for (name, definition) in names
|
|
||||||
.into_iter()
|
|
||||||
.zip(tools::task_tools(self.task_store.clone()))
|
|
||||||
{
|
|
||||||
context
|
|
||||||
.tools()
|
|
||||||
.register(ToolContribution::new(name, definition))?;
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
|
|
@ -1797,13 +1745,76 @@ mod tests {
|
||||||
assert!(report.reports[0].skipped.is_empty());
|
assert!(report.reports[0].skipped.is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn builtin_internal_task_feature_descriptor_has_exact_tools_and_no_authorities() {
|
||||||
|
let descriptor = builtin::task_tools_feature(tools::TaskStore::new()).descriptor();
|
||||||
|
let tool_names: Vec<_> = descriptor
|
||||||
|
.tools
|
||||||
|
.iter()
|
||||||
|
.map(|tool| tool.name.as_str())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
assert_eq!(descriptor.id.as_str(), "builtin:task-tools");
|
||||||
|
assert_eq!(descriptor.runtime, FeatureRuntimeKind::Builtin);
|
||||||
|
assert!(descriptor.requested_authorities.is_empty());
|
||||||
|
assert!(descriptor.hooks.is_empty());
|
||||||
|
assert!(descriptor.background_tasks.is_empty());
|
||||||
|
assert!(descriptor.provides_services.is_empty());
|
||||||
|
assert!(descriptor.requires_services.is_empty());
|
||||||
|
assert_eq!(
|
||||||
|
tool_names,
|
||||||
|
vec!["TaskCreate", "TaskUpdate", "TaskGet", "TaskList"]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn builtin_internal_task_feature_installs_declared_tools_without_host_authorities() {
|
||||||
|
let task_store = tools::TaskStore::new();
|
||||||
|
let mut hook_builder = HookRegistryBuilder::default();
|
||||||
|
let mut pending_tools = Vec::new();
|
||||||
|
let mut builder = FeatureRegistryBuilder::new();
|
||||||
|
builder.add_module(builtin::task_tools_feature(task_store));
|
||||||
|
let mut declared_names: Vec<_> = builder.descriptors()[0]
|
||||||
|
.tools
|
||||||
|
.iter()
|
||||||
|
.map(|tool| tool.name.clone())
|
||||||
|
.collect();
|
||||||
|
let report = builder.install_into_pending(&mut pending_tools, &mut hook_builder);
|
||||||
|
let pending_names: Vec<_> = pending_tools
|
||||||
|
.iter()
|
||||||
|
.map(|definition| definition().0.name)
|
||||||
|
.collect();
|
||||||
|
let installed_names = report.installed_tool_names();
|
||||||
|
let mut sorted_installed_names = installed_names.clone();
|
||||||
|
declared_names.sort();
|
||||||
|
sorted_installed_names.sort();
|
||||||
|
|
||||||
|
assert_eq!(report.reports.len(), 1);
|
||||||
|
assert!(report.reports[0].installed);
|
||||||
|
assert_eq!(
|
||||||
|
report.reports[0].granted_authorities,
|
||||||
|
AuthorityGrantSet::empty()
|
||||||
|
);
|
||||||
|
assert!(report.reports[0].skipped.is_empty());
|
||||||
|
assert!(report.reports[0].diagnostics.is_empty());
|
||||||
|
assert_eq!(declared_names, sorted_installed_names);
|
||||||
|
assert_eq!(
|
||||||
|
installed_names,
|
||||||
|
vec!["TaskCreate", "TaskList", "TaskGet", "TaskUpdate"]
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
pending_names,
|
||||||
|
vec!["TaskCreate", "TaskList", "TaskGet", "TaskUpdate"]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn builtin_task_feature_installs_through_worker_tool_path() {
|
fn builtin_task_feature_installs_through_worker_tool_path() {
|
||||||
let task_store = tools::TaskStore::new();
|
let task_store = tools::TaskStore::new();
|
||||||
let mut worker = Worker::new(DummyClient);
|
let mut worker = Worker::new(DummyClient);
|
||||||
let mut hook_builder = HookRegistryBuilder::default();
|
let mut hook_builder = HookRegistryBuilder::default();
|
||||||
let report = FeatureRegistryBuilder::new()
|
let report = FeatureRegistryBuilder::new()
|
||||||
.with_module(builtin::task_feature(task_store))
|
.with_module(builtin::task_tools_feature(task_store))
|
||||||
.install_into_worker(&mut worker, &mut hook_builder);
|
.install_into_worker(&mut worker, &mut hook_builder);
|
||||||
|
|
||||||
worker.tool_server_handle().flush_pending();
|
worker.tool_server_handle().flush_pending();
|
||||||
|
|
|
||||||
9
crates/pod/src/feature/builtin.rs
Normal file
9
crates/pod/src/feature/builtin.rs
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
//! Built-in internal feature modules.
|
||||||
|
//!
|
||||||
|
//! These modules are compiled into the Pod host and contribute through the
|
||||||
|
//! same descriptor-approved registry path used by feature modules. They are not
|
||||||
|
//! an external plugin-loading surface.
|
||||||
|
|
||||||
|
pub mod task;
|
||||||
|
|
||||||
|
pub use task::task_tools_feature;
|
||||||
61
crates/pod/src/feature/builtin/task.rs
Normal file
61
crates/pod/src/feature/builtin/task.rs
Normal file
|
|
@ -0,0 +1,61 @@
|
||||||
|
//! Task tools built-in feature module.
|
||||||
|
//!
|
||||||
|
//! This is the reference path for extracting an internal built-in module into
|
||||||
|
//! the feature contribution boundary. The Pod host still owns the Pod-lifetime
|
||||||
|
//! [`tools::TaskStore`] and passes the shared handle in at construction time;
|
||||||
|
//! the module requests no sandbox/external-plugin host authorities.
|
||||||
|
|
||||||
|
use crate::feature::{
|
||||||
|
FeatureDescriptor, FeatureInstallContext, FeatureInstallError, FeatureModule, ToolContribution,
|
||||||
|
ToolDeclaration,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Construct the built-in Task tool feature module.
|
||||||
|
///
|
||||||
|
/// The returned module contributes only `TaskCreate`, `TaskUpdate`, `TaskGet`,
|
||||||
|
/// and `TaskList` through descriptor-approved tool registration. It does not
|
||||||
|
/// request host authorities; normal ToolRegistry and PreToolCall permission
|
||||||
|
/// policy still applies at call time.
|
||||||
|
pub fn task_tools_feature(task_store: tools::TaskStore) -> impl FeatureModule {
|
||||||
|
TaskToolsFeature { task_store }
|
||||||
|
}
|
||||||
|
|
||||||
|
struct TaskToolsFeature {
|
||||||
|
task_store: tools::TaskStore,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FeatureModule for TaskToolsFeature {
|
||||||
|
fn descriptor(&self) -> FeatureDescriptor {
|
||||||
|
FeatureDescriptor::builtin("task-tools", "Task tools")
|
||||||
|
.with_description("Session-lifetime task tracking builtin tools")
|
||||||
|
.with_tool(ToolDeclaration::new(
|
||||||
|
"TaskCreate",
|
||||||
|
"Create a session-lifetime user-visible task",
|
||||||
|
))
|
||||||
|
.with_tool(ToolDeclaration::new(
|
||||||
|
"TaskUpdate",
|
||||||
|
"Update a session-lifetime user-visible task",
|
||||||
|
))
|
||||||
|
.with_tool(ToolDeclaration::new(
|
||||||
|
"TaskGet",
|
||||||
|
"Get one session-lifetime user-visible task",
|
||||||
|
))
|
||||||
|
.with_tool(ToolDeclaration::new(
|
||||||
|
"TaskList",
|
||||||
|
"List session-lifetime user-visible tasks",
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn install(&self, context: &mut FeatureInstallContext<'_>) -> Result<(), FeatureInstallError> {
|
||||||
|
let names = ["TaskCreate", "TaskList", "TaskGet", "TaskUpdate"];
|
||||||
|
for (name, definition) in names
|
||||||
|
.into_iter()
|
||||||
|
.zip(tools::task_tools(self.task_store.clone()))
|
||||||
|
{
|
||||||
|
context
|
||||||
|
.tools()
|
||||||
|
.register(ToolContribution::new(name, definition))?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user