feat(backend): MCP d'édition de templates (#81)
Ajoute le MCP dédié à l'édition de templates : catalogue et classification des templates (mcp/templates.rs infrastructure + app-tauri), use cases et provider (application/template), enforcement de la policy des tools (mod.rs, server.rs, tools.rs), avec la parité côté chemin OpenAI-compatible (openai_tools.rs x2). Lots B1 (catalogue/classification), B2 (use cases/provider) et B3 (enforcement policy) livrés en un seul commit cohérent. QA vert (seul l'échec de bind loopback #80, connu et non-régression, écarté). Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@ -164,9 +164,9 @@ pub use template::{
|
||||
AgentDrift, CreateAgentFromTemplate, CreateAgentFromTemplateInput,
|
||||
CreateAgentFromTemplateOutput, CreateTemplate, CreateTemplateInput, CreateTemplateOutput,
|
||||
DeleteTemplate, DeleteTemplateInput, DetectAgentDrift, DetectAgentDriftInput,
|
||||
DetectAgentDriftOutput, ListTemplates, ListTemplatesOutput, SyncAgentWithTemplate,
|
||||
SyncAgentWithTemplateInput, SyncAgentWithTemplateOutput, UpdateTemplate, UpdateTemplateInput,
|
||||
UpdateTemplateOutput,
|
||||
DetectAgentDriftOutput, ListTemplates, ListTemplatesOutput, ReadTemplate, ReadTemplateInput,
|
||||
ReadTemplateOutput, SyncAgentWithTemplate, SyncAgentWithTemplateInput,
|
||||
SyncAgentWithTemplateOutput, UpdateTemplate, UpdateTemplateInput, UpdateTemplateOutput,
|
||||
};
|
||||
pub use terminal::{
|
||||
CloseTerminal, CloseTerminalInput, CloseTerminalOutput, LiveAgentRegistry, LiveSessionKind,
|
||||
|
||||
@ -11,7 +11,7 @@ pub use usecases::{
|
||||
AgentDrift, CreateAgentFromTemplate, CreateAgentFromTemplateInput,
|
||||
CreateAgentFromTemplateOutput, CreateTemplate, CreateTemplateInput, CreateTemplateOutput,
|
||||
DeleteTemplate, DeleteTemplateInput, DetectAgentDrift, DetectAgentDriftInput,
|
||||
DetectAgentDriftOutput, ListTemplates, ListTemplatesOutput, SyncAgentWithTemplate,
|
||||
SyncAgentWithTemplateInput, SyncAgentWithTemplateOutput, UpdateTemplate, UpdateTemplateInput,
|
||||
UpdateTemplateOutput,
|
||||
DetectAgentDriftOutput, ListTemplates, ListTemplatesOutput, ReadTemplate, ReadTemplateInput,
|
||||
ReadTemplateOutput, SyncAgentWithTemplate, SyncAgentWithTemplateInput,
|
||||
SyncAgentWithTemplateOutput, UpdateTemplate, UpdateTemplateInput, UpdateTemplateOutput,
|
||||
};
|
||||
|
||||
@ -134,9 +134,47 @@ impl UpdateTemplate {
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// ListTemplates / DeleteTemplate
|
||||
// ReadTemplate / ListTemplates / DeleteTemplate
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/// Input for [`ReadTemplate::execute`].
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct ReadTemplateInput {
|
||||
/// Template to read.
|
||||
pub template_id: TemplateId,
|
||||
}
|
||||
|
||||
/// Output of [`ReadTemplate::execute`].
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct ReadTemplateOutput {
|
||||
/// The requested template.
|
||||
pub template: AgentTemplate,
|
||||
}
|
||||
|
||||
/// Reads one template from the global store.
|
||||
pub struct ReadTemplate {
|
||||
templates: Arc<dyn TemplateStore>,
|
||||
}
|
||||
|
||||
impl ReadTemplate {
|
||||
/// Builds the use case.
|
||||
#[must_use]
|
||||
pub fn new(templates: Arc<dyn TemplateStore>) -> Self {
|
||||
Self { templates }
|
||||
}
|
||||
|
||||
/// Reads one template.
|
||||
///
|
||||
/// # Errors
|
||||
/// - [`AppError::NotFound`] if the template is unknown,
|
||||
/// - [`AppError::Store`] on persistence failure.
|
||||
pub async fn execute(&self, input: ReadTemplateInput) -> Result<ReadTemplateOutput, AppError> {
|
||||
Ok(ReadTemplateOutput {
|
||||
template: self.templates.get(input.template_id).await?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Output of [`ListTemplates::execute`].
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct ListTemplatesOutput {
|
||||
|
||||
@ -18,8 +18,8 @@ use uuid::Uuid;
|
||||
|
||||
use application::{
|
||||
CreateAgentFromTemplate, CreateAgentFromTemplateInput, CreateTemplate, CreateTemplateInput,
|
||||
DetectAgentDrift, DetectAgentDriftInput, SyncAgentWithTemplate, SyncAgentWithTemplateInput,
|
||||
UpdateTemplate, UpdateTemplateInput,
|
||||
DetectAgentDrift, DetectAgentDriftInput, ReadTemplate, ReadTemplateInput,
|
||||
SyncAgentWithTemplate, SyncAgentWithTemplateInput, UpdateTemplate, UpdateTemplateInput,
|
||||
};
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
@ -224,6 +224,29 @@ async fn create_template_starts_at_initial_version() {
|
||||
assert_eq!(store.list().await.unwrap().len(), 1);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn read_template_returns_one_template_or_not_found() {
|
||||
let existing = template(tid(7), "Base", "body", 3);
|
||||
let store = FakeTemplates::with(vec![existing.clone()]);
|
||||
let read = ReadTemplate::new(Arc::new(store));
|
||||
|
||||
let out = read
|
||||
.execute(ReadTemplateInput {
|
||||
template_id: existing.id,
|
||||
})
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(out.template, existing);
|
||||
|
||||
let err = read
|
||||
.execute(ReadTemplateInput {
|
||||
template_id: tid(8),
|
||||
})
|
||||
.await
|
||||
.expect_err("unknown template should be not found");
|
||||
assert_eq!(err.code(), "NOT_FOUND");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn update_template_bumps_version_and_publishes_event() {
|
||||
let store = FakeTemplates::with(vec![template(tid(1), "T", "v1", 1)]);
|
||||
|
||||
Reference in New Issue
Block a user