fix: agent usability improvements - unified schema casing, fixed silent handler failures, and made namespaces strictly optional

This commit is contained in:
Riz Ashraf committed 2026-09-26 08:07:28 +01:00
1 parent 5dd413c397
commit be85b58be4
3 files changed
+52 -15

No files matched your search

+19 -1
View File
@@ -152,13 +152,25 @@ impl McpTool for CreateRelationsHandler {
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> Result<String, String> {
let req: CreateRelationsTool = serde_json::from_value(args).map_err(|e| e.to_string())?;
let mut missing_nodes = std::collections::HashSet::new();
state.modify_graph(|g| {
for relation in req.relations {
if !relation.from.is_empty() && !relation.to.is_empty() {
g.relations.push(relation);
let from_exists = g.entities.contains_key(&relation.from);
let to_exists = g.entities.contains_key(&relation.to);
if from_exists && to_exists {
g.relations.push(relation);
} else {
if !from_exists { missing_nodes.insert(relation.from); }
if !to_exists { missing_nodes.insert(relation.to); }
}
}
}
});
if !missing_nodes.is_empty() {
let missing: Vec<_> = missing_nodes.into_iter().collect();
return Ok(format!("Warning: Relations dropped due to missing entities: {}", missing.join(", ")));
}
Ok("Relations created".to_string())
}
}
@@ -177,13 +189,19 @@ impl McpTool for AddObservationsHandler {
async fn execute(&self, args: Value, state: Arc<MemoryState>) -> Result<String, String> {
let req: AddObservationsTool = serde_json::from_value(args).map_err(|e| e.to_string())?;
let mut missing_entities = Vec::new();
state.modify_graph(|g| {
for o in req.observations {
if let Some(e) = g.entities.get_mut(&o.entity_name) {
e.observations.extend(o.contents);
} else {
missing_entities.push(o.entity_name);
}
}
});
if !missing_entities.is_empty() {
return Ok(format!("Warning: Observations dropped for missing entities: {}", missing_entities.join(", ")));
}
Ok("Observations added".to_string())
}
}
+8 -8
View File
@@ -21,7 +21,7 @@ pub fn default_namespace() -> String {
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema)]
pub struct Entity {
pub name: String,
#[serde(rename = "entityType")]
#[serde(alias = "entityType")]
pub entity_type: String,
#[serde(default)]
pub observations: Vec<String>,
@@ -34,7 +34,7 @@ pub struct Entity {
pub struct Relation {
pub from: String,
pub to: String,
#[serde(rename = "relationType")]
#[serde(alias = "relationType")]
pub relation_type: String,
#[serde(default = "default_namespace")]
pub namespace: String,
@@ -50,7 +50,7 @@ pub struct KnowledgeGraph {
pub struct AcceptanceCriteria {
pub id: String,
pub description: String,
#[serde(alias = "is_met", rename = "isMet")]
#[serde(alias = "is_met")]
pub is_met: bool,
}
@@ -60,19 +60,19 @@ pub struct Task {
pub title: String,
pub status: String,
pub description: String,
#[serde(alias = "created_at", rename = "createdAt")]
#[serde(alias = "created_at")]
pub created_at: u64,
#[serde(alias = "updated_at", rename = "updatedAt")]
#[serde(alias = "updated_at")]
pub updated_at: u64,
#[serde(alias = "git_branch", rename = "gitBranch")]
#[serde(alias = "git_branch")]
pub git_branch: Option<String>,
#[serde(default)]
#[serde(alias = "parent_id", rename = "parentId")]
#[serde(alias = "parent_id")]
pub parent_id: Option<String>,
#[serde(default)]
pub dependencies: Vec<String>,
#[serde(default)]
#[serde(alias = "acceptance_criteria", rename = "acceptanceCriteria")]
#[serde(alias = "acceptance_criteria")]
pub acceptance_criteria: Vec<AcceptanceCriteria>,
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
+25 -6
View File
@@ -17,7 +17,7 @@ pub struct CreateRelationsTool {
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
pub struct ObservationInput {
#[serde(rename = "entityName")]
#[serde(alias = "entityName")]
pub entity_name: String,
pub contents: Vec<String>,
}
@@ -33,13 +33,13 @@ pub struct AddObservationsTool {
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
pub struct DeleteEntitiesTool {
/// Array of entity names to delete.
#[serde(rename = "entityNames")]
#[serde(alias = "entityNames")]
pub entity_names: Vec<String>,
}
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
pub struct DeleteObservationInput {
#[serde(rename = "entityName")]
#[serde(alias = "entityName")]
pub entity_name: String,
pub observations: Vec<String>,
}
@@ -134,7 +134,7 @@ pub struct ClearStickyNotesTool {}
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
pub struct CondenseEntityTool {
/// The name of the entity to condense.
#[serde(rename = "entityName")]
#[serde(alias = "entityName")]
pub entity_name: String,
/// The condensed observations that will replace the existing ones.
pub summarized_observations: Vec<String>,
@@ -230,10 +230,10 @@ pub struct QueryDecisionsTool {
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
pub struct MergeEntitiesTool {
/// The name of the entity to merge from (will be deleted).
#[serde(rename = "sourceEntity")]
#[serde(alias = "sourceEntity")]
pub source_entity: String,
/// The name of the entity to merge into.
#[serde(rename = "targetEntity")]
#[serde(alias = "targetEntity")]
pub target_entity: String,
}
@@ -278,6 +278,7 @@ pub struct SearchErrorFixesTool {
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
pub struct PinFileTool {
/// The namespace to pin the file in.
#[serde(default = "crate::models::default_namespace")]
pub namespace: String,
/// The absolute path of the file to pin.
pub file_path: String,
@@ -289,6 +290,7 @@ pub struct PinFileTool {
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
pub struct UnpinFileTool {
/// The namespace the file is pinned in.
#[serde(default = "crate::models::default_namespace")]
pub namespace: String,
/// The absolute path of the file to unpin.
pub file_path: String,
@@ -309,6 +311,7 @@ pub struct AddSessionSummaryTool {
/// The summary content.
pub summary: String,
/// The namespace to add the summary to.
#[serde(default = "crate::models::default_namespace")]
pub namespace: String,
}
@@ -326,6 +329,7 @@ pub struct LeaveHandoffMemoTool {
/// The content of the memo.
pub content: String,
/// The namespace to leave the memo in.
#[serde(default = "crate::models::default_namespace")]
pub namespace: String,
}
@@ -347,6 +351,7 @@ pub struct ClearHandoffMemosTool {
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
pub struct UpdateEnvFingerprintTool {
/// The namespace to update the fingerprint for.
#[serde(default = "crate::models::default_namespace")]
pub namespace: String,
/// A map of tool names to their versions.
pub tool_versions: std::collections::HashMap<String, String>,
@@ -356,6 +361,7 @@ pub struct UpdateEnvFingerprintTool {
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
pub struct ReadEnvFingerprintTool {
/// The namespace to read the fingerprint for.
#[serde(default = "crate::models::default_namespace")]
pub namespace: String,
}
@@ -363,6 +369,7 @@ pub struct ReadEnvFingerprintTool {
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
pub struct LogEnvRequirementTool {
/// The namespace.
#[serde(default = "crate::models::default_namespace")]
pub namespace: String,
/// The environment variable key (e.g., DATABASE_URL).
pub key: String,
@@ -378,6 +385,7 @@ pub struct AddMilestoneTool {
/// The title of the milestone.
pub title: String,
/// The namespace for the milestone.
#[serde(default = "crate::models::default_namespace")]
pub namespace: String,
}
@@ -401,6 +409,7 @@ pub struct ListMilestonesTool {
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
pub struct GenerateStandupReportTool {
/// The namespace to generate the report for.
#[serde(default = "crate::models::default_namespace")]
pub namespace: String,
/// The number of hours to look back for activity.
pub hours_lookback: u64,
@@ -410,6 +419,7 @@ pub struct GenerateStandupReportTool {
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
pub struct RegisterEnvironmentTool {
/// The namespace.
#[serde(default = "crate::models::default_namespace")]
pub namespace: String,
/// The name of the environment (e.g., 'staging', 'prod').
pub name: String,
@@ -425,6 +435,7 @@ pub struct RegisterEnvironmentTool {
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
pub struct GetEnvironmentDetailsTool {
/// The namespace to retrieve details for.
#[serde(default = "crate::models::default_namespace")]
pub namespace: String,
}
@@ -432,6 +443,7 @@ pub struct GetEnvironmentDetailsTool {
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
pub struct AddPrChecklistItemTool {
/// The namespace.
#[serde(default = "crate::models::default_namespace")]
pub namespace: String,
/// The description of the checklist item.
pub description: String,
@@ -441,6 +453,7 @@ pub struct AddPrChecklistItemTool {
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
pub struct GetPrChecklistTool {
/// The namespace.
#[serde(default = "crate::models::default_namespace")]
pub namespace: String,
}
@@ -448,6 +461,7 @@ pub struct GetPrChecklistTool {
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
pub struct ClearPrChecklistTool {
/// The namespace.
#[serde(default = "crate::models::default_namespace")]
pub namespace: String,
}
@@ -455,6 +469,7 @@ pub struct ClearPrChecklistTool {
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
pub struct LogTechDebtTool {
/// The namespace.
#[serde(default = "crate::models::default_namespace")]
pub namespace: String,
/// A description of the technical debt.
pub description: String,
@@ -477,6 +492,7 @@ pub struct ResolveTechDebtTool {
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
pub struct ListTechDebtTool {
/// The namespace.
#[serde(default = "crate::models::default_namespace")]
pub namespace: String,
/// Whether to include resolved technical debt in the results.
pub include_resolved: bool,
@@ -486,6 +502,7 @@ pub struct ListTechDebtTool {
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
pub struct SaveContextWorkspaceTool {
/// The namespace for the workspace.
#[serde(default = "crate::models::default_namespace")]
pub namespace: String,
/// The name to save the workspace as.
pub name: String,
@@ -499,6 +516,7 @@ pub struct SaveContextWorkspaceTool {
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
pub struct LoadContextWorkspaceTool {
/// The namespace of the workspace.
#[serde(default = "crate::models::default_namespace")]
pub namespace: String,
/// The name of the workspace to load.
pub name: String,
@@ -524,6 +542,7 @@ pub struct OmniSearchTool {
#[derive(Debug, Deserialize, Serialize, JsonSchema)]
pub struct GetProjectHealthTool {
/// The namespace to get health for.
#[serde(default = "crate::models::default_namespace")]
pub namespace: String,
}