summaryrefslogtreecommitdiff
path: root/makima/src/llm/contract_tools.rs
diff options
context:
space:
mode:
authorsoryu <soryu@soryu.co>2026-02-05 01:42:59 +0000
committersoryu <soryu@soryu.co>2026-02-05 01:42:59 +0000
commit6a0c912a3fbd8e9b3e87ef40e960803d819d966d (patch)
treeb2c50c490811286d163e40f8d624ee8d43c0ce43 /makima/src/llm/contract_tools.rs
parent0302b4596e14210884df5d645df9a179d8f0c1c6 (diff)
downloadsoryu-6a0c912a3fbd8e9b3e87ef40e960803d819d966d.tar.gz
soryu-6a0c912a3fbd8e9b3e87ef40e960803d819d966d.zip
Add makima directives
Diffstat (limited to 'makima/src/llm/contract_tools.rs')
-rw-r--r--makima/src/llm/contract_tools.rs489
1 files changed, 489 insertions, 0 deletions
diff --git a/makima/src/llm/contract_tools.rs b/makima/src/llm/contract_tools.rs
index 0f50132..7f7e849 100644
--- a/makima/src/llm/contract_tools.rs
+++ b/makima/src/llm/contract_tools.rs
@@ -460,6 +460,214 @@ pub static CONTRACT_TOOLS: once_cell::sync::Lazy<Vec<Tool>> = once_cell::sync::L
"required": ["file_id"]
}),
},
+ // =============================================================================
+ // Chain Directive Tools (for directive contracts orchestrating chains)
+ // =============================================================================
+ Tool {
+ name: "create_chain_from_directive".to_string(),
+ description: "Create a new chain that this directive contract will orchestrate. The chain starts in 'pending' status and contract definitions can be added. Only available to directive contracts.".to_string(),
+ parameters: json!({
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "Name for the chain"
+ },
+ "description": {
+ "type": "string",
+ "description": "Description of what the chain accomplishes"
+ }
+ },
+ "required": ["name"]
+ }),
+ },
+ Tool {
+ name: "add_chain_contract".to_string(),
+ description: "Add a contract definition to the chain being orchestrated. The contract will be created when its dependencies are met.".to_string(),
+ parameters: json!({
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "Contract name"
+ },
+ "description": {
+ "type": "string",
+ "description": "What this contract accomplishes"
+ },
+ "contract_type": {
+ "type": "string",
+ "enum": ["simple", "execute", "checkpoint"],
+ "description": "Contract type (default: simple)"
+ },
+ "depends_on": {
+ "type": "array",
+ "items": { "type": "string" },
+ "description": "Names of contracts this depends on"
+ },
+ "requirement_ids": {
+ "type": "array",
+ "items": { "type": "string" },
+ "description": "Requirement IDs this contract addresses (for traceability)"
+ }
+ },
+ "required": ["name"]
+ }),
+ },
+ Tool {
+ name: "set_chain_dependencies".to_string(),
+ description: "Set which contracts depend on which other contracts in the chain.".to_string(),
+ parameters: json!({
+ "type": "object",
+ "properties": {
+ "contract_name": {
+ "type": "string",
+ "description": "Name of contract that has dependencies"
+ },
+ "depends_on": {
+ "type": "array",
+ "items": { "type": "string" },
+ "description": "Names of contracts it depends on"
+ }
+ },
+ "required": ["contract_name", "depends_on"]
+ }),
+ },
+ Tool {
+ name: "modify_chain_contract".to_string(),
+ description: "Update a contract definition in the chain.".to_string(),
+ parameters: json!({
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "Name of the contract to modify"
+ },
+ "new_name": {
+ "type": "string",
+ "description": "New name for the contract"
+ },
+ "description": {
+ "type": "string",
+ "description": "New description"
+ },
+ "add_requirement_ids": {
+ "type": "array",
+ "items": { "type": "string" },
+ "description": "Requirement IDs to add"
+ },
+ "remove_requirement_ids": {
+ "type": "array",
+ "items": { "type": "string" },
+ "description": "Requirement IDs to remove"
+ }
+ },
+ "required": ["name"]
+ }),
+ },
+ Tool {
+ name: "remove_chain_contract".to_string(),
+ description: "Remove a contract definition from the chain (only if not yet instantiated).".to_string(),
+ parameters: json!({
+ "type": "object",
+ "properties": {
+ "name": {
+ "type": "string",
+ "description": "Name of the contract to remove"
+ }
+ },
+ "required": ["name"]
+ }),
+ },
+ Tool {
+ name: "preview_chain_dag".to_string(),
+ description: "Generate a visual preview of the chain DAG structure for review.".to_string(),
+ parameters: json!({
+ "type": "object",
+ "properties": {}
+ }),
+ },
+ Tool {
+ name: "validate_chain_directive".to_string(),
+ description: "Validate the chain specification is complete and valid (no cycles, all dependencies exist, all requirements covered).".to_string(),
+ parameters: json!({
+ "type": "object",
+ "properties": {}
+ }),
+ },
+ Tool {
+ name: "finalize_chain_directive".to_string(),
+ description: "Lock the directive and start chain execution. Call this after validation passes and user has approved (if phase_guard enabled).".to_string(),
+ parameters: json!({
+ "type": "object",
+ "properties": {
+ "auto_start": {
+ "type": "boolean",
+ "description": "Whether to immediately start the chain (default: true)"
+ }
+ }
+ }),
+ },
+ Tool {
+ name: "get_chain_status".to_string(),
+ description: "Get current status of the chain being orchestrated, including contract statuses and progress.".to_string(),
+ parameters: json!({
+ "type": "object",
+ "properties": {}
+ }),
+ },
+ Tool {
+ name: "get_uncovered_requirements".to_string(),
+ description: "List requirements from the directive that are not yet mapped to any contract.".to_string(),
+ parameters: json!({
+ "type": "object",
+ "properties": {}
+ }),
+ },
+ Tool {
+ name: "evaluate_contract_completion".to_string(),
+ description: "Evaluate whether a completed chain contract meets the directive requirements. Use this after a contract completes to assess if it satisfies acceptance criteria.".to_string(),
+ parameters: json!({
+ "type": "object",
+ "properties": {
+ "contract_id": {
+ "type": "string",
+ "description": "ID of the completed contract to evaluate"
+ },
+ "passed": {
+ "type": "boolean",
+ "description": "Whether the evaluation passed"
+ },
+ "feedback": {
+ "type": "string",
+ "description": "Evaluation feedback and rationale"
+ },
+ "rework_instructions": {
+ "type": "string",
+ "description": "Instructions for rework if evaluation failed"
+ }
+ },
+ "required": ["contract_id", "passed", "feedback"]
+ }),
+ },
+ Tool {
+ name: "request_rework".to_string(),
+ description: "Request rework on a completed contract that didn't meet requirements. This will block chain progression and notify the contract to address issues.".to_string(),
+ parameters: json!({
+ "type": "object",
+ "properties": {
+ "contract_id": {
+ "type": "string",
+ "description": "ID of the contract needing rework"
+ },
+ "feedback": {
+ "type": "string",
+ "description": "Detailed feedback on what needs to be fixed"
+ }
+ },
+ "required": ["contract_id", "feedback"]
+ }),
+ },
]
});
@@ -546,6 +754,50 @@ pub enum ContractToolRequest {
include_decisions: bool,
include_action_items: bool,
},
+
+ // Chain directive tools (for directive contracts)
+ CreateChainFromDirective {
+ name: String,
+ description: Option<String>,
+ },
+ AddChainContract {
+ name: String,
+ description: Option<String>,
+ contract_type: Option<String>,
+ depends_on: Option<Vec<String>>,
+ requirement_ids: Option<Vec<String>>,
+ },
+ SetChainDependencies {
+ contract_name: String,
+ depends_on: Vec<String>,
+ },
+ ModifyChainContract {
+ name: String,
+ new_name: Option<String>,
+ description: Option<String>,
+ add_requirement_ids: Option<Vec<String>>,
+ remove_requirement_ids: Option<Vec<String>>,
+ },
+ RemoveChainContract {
+ name: String,
+ },
+ PreviewChainDag,
+ ValidateChainDirective,
+ FinalizeChainDirective {
+ auto_start: bool,
+ },
+ GetChainStatus,
+ GetUncoveredRequirements,
+ EvaluateContractCompletion {
+ contract_id: Uuid,
+ passed: bool,
+ feedback: String,
+ rework_instructions: Option<String>,
+ },
+ RequestRework {
+ contract_id: Uuid,
+ feedback: String,
+ },
}
/// Task definition for chained task creation
@@ -617,6 +869,20 @@ pub fn parse_contract_tool_call(call: &super::tools::ToolCall) -> ContractToolEx
"analyze_transcript" => parse_analyze_transcript(call),
"create_contract_from_transcript" => parse_create_contract_from_transcript(call),
+ // Chain directive tools
+ "create_chain_from_directive" => parse_create_chain_from_directive(call),
+ "add_chain_contract" => parse_add_chain_contract(call),
+ "set_chain_dependencies" => parse_set_chain_dependencies(call),
+ "modify_chain_contract" => parse_modify_chain_contract(call),
+ "remove_chain_contract" => parse_remove_chain_contract(call),
+ "preview_chain_dag" => parse_preview_chain_dag(),
+ "validate_chain_directive" => parse_validate_chain_directive(),
+ "finalize_chain_directive" => parse_finalize_chain_directive(call),
+ "get_chain_status" => parse_get_chain_status(),
+ "get_uncovered_requirements" => parse_get_uncovered_requirements(),
+ "evaluate_contract_completion" => parse_evaluate_contract_completion(call),
+ "request_rework" => parse_request_rework(call),
+
_ => ContractToolExecutionResult {
success: false,
message: format!("Unknown contract tool: {}", call.name),
@@ -1206,6 +1472,229 @@ fn parse_create_contract_from_transcript(call: &super::tools::ToolCall) -> Contr
}
// =============================================================================
+// Chain Directive Tool Parsing
+// =============================================================================
+
+fn parse_create_chain_from_directive(call: &super::tools::ToolCall) -> ContractToolExecutionResult {
+ let name = call.arguments.get("name").and_then(|v| v.as_str()).map(|s| s.to_string());
+ let Some(name) = name else {
+ return error_result("Missing required parameter: name");
+ };
+ let description = call.arguments.get("description").and_then(|v| v.as_str()).map(|s| s.to_string());
+
+ ContractToolExecutionResult {
+ success: true,
+ message: "Creating chain from directive...".to_string(),
+ data: None,
+ request: Some(ContractToolRequest::CreateChainFromDirective { name, description }),
+ pending_questions: None,
+ }
+}
+
+fn parse_add_chain_contract(call: &super::tools::ToolCall) -> ContractToolExecutionResult {
+ let name = call.arguments.get("name").and_then(|v| v.as_str()).map(|s| s.to_string());
+ let Some(name) = name else {
+ return error_result("Missing required parameter: name");
+ };
+
+ let description = call.arguments.get("description").and_then(|v| v.as_str()).map(|s| s.to_string());
+ let contract_type = call.arguments.get("contract_type").and_then(|v| v.as_str()).map(|s| s.to_string());
+ let depends_on = call.arguments.get("depends_on").and_then(|v| {
+ v.as_array().map(|arr| {
+ arr.iter().filter_map(|item| item.as_str().map(|s| s.to_string())).collect()
+ })
+ });
+ let requirement_ids = call.arguments.get("requirement_ids").and_then(|v| {
+ v.as_array().map(|arr| {
+ arr.iter().filter_map(|item| item.as_str().map(|s| s.to_string())).collect()
+ })
+ });
+
+ ContractToolExecutionResult {
+ success: true,
+ message: format!("Adding contract '{}' to chain...", name),
+ data: None,
+ request: Some(ContractToolRequest::AddChainContract {
+ name,
+ description,
+ contract_type,
+ depends_on,
+ requirement_ids,
+ }),
+ pending_questions: None,
+ }
+}
+
+fn parse_set_chain_dependencies(call: &super::tools::ToolCall) -> ContractToolExecutionResult {
+ let contract_name = call.arguments.get("contract_name").and_then(|v| v.as_str()).map(|s| s.to_string());
+ let Some(contract_name) = contract_name else {
+ return error_result("Missing required parameter: contract_name");
+ };
+
+ let depends_on = call.arguments.get("depends_on").and_then(|v| {
+ v.as_array().map(|arr| {
+ arr.iter().filter_map(|item| item.as_str().map(|s| s.to_string())).collect()
+ })
+ }).unwrap_or_default();
+
+ ContractToolExecutionResult {
+ success: true,
+ message: format!("Setting dependencies for '{}'...", contract_name),
+ data: None,
+ request: Some(ContractToolRequest::SetChainDependencies { contract_name, depends_on }),
+ pending_questions: None,
+ }
+}
+
+fn parse_modify_chain_contract(call: &super::tools::ToolCall) -> ContractToolExecutionResult {
+ let name = call.arguments.get("name").and_then(|v| v.as_str()).map(|s| s.to_string());
+ let Some(name) = name else {
+ return error_result("Missing required parameter: name");
+ };
+
+ let new_name = call.arguments.get("new_name").and_then(|v| v.as_str()).map(|s| s.to_string());
+ let description = call.arguments.get("description").and_then(|v| v.as_str()).map(|s| s.to_string());
+ let add_requirement_ids = call.arguments.get("add_requirement_ids").and_then(|v| {
+ v.as_array().map(|arr| {
+ arr.iter().filter_map(|item| item.as_str().map(|s| s.to_string())).collect()
+ })
+ });
+ let remove_requirement_ids = call.arguments.get("remove_requirement_ids").and_then(|v| {
+ v.as_array().map(|arr| {
+ arr.iter().filter_map(|item| item.as_str().map(|s| s.to_string())).collect()
+ })
+ });
+
+ ContractToolExecutionResult {
+ success: true,
+ message: format!("Modifying contract '{}'...", name),
+ data: None,
+ request: Some(ContractToolRequest::ModifyChainContract {
+ name,
+ new_name,
+ description,
+ add_requirement_ids,
+ remove_requirement_ids,
+ }),
+ pending_questions: None,
+ }
+}
+
+fn parse_remove_chain_contract(call: &super::tools::ToolCall) -> ContractToolExecutionResult {
+ let name = call.arguments.get("name").and_then(|v| v.as_str()).map(|s| s.to_string());
+ let Some(name) = name else {
+ return error_result("Missing required parameter: name");
+ };
+
+ ContractToolExecutionResult {
+ success: true,
+ message: format!("Removing contract '{}'...", name),
+ data: None,
+ request: Some(ContractToolRequest::RemoveChainContract { name }),
+ pending_questions: None,
+ }
+}
+
+fn parse_preview_chain_dag() -> ContractToolExecutionResult {
+ ContractToolExecutionResult {
+ success: true,
+ message: "Generating chain DAG preview...".to_string(),
+ data: None,
+ request: Some(ContractToolRequest::PreviewChainDag),
+ pending_questions: None,
+ }
+}
+
+fn parse_validate_chain_directive() -> ContractToolExecutionResult {
+ ContractToolExecutionResult {
+ success: true,
+ message: "Validating chain directive...".to_string(),
+ data: None,
+ request: Some(ContractToolRequest::ValidateChainDirective),
+ pending_questions: None,
+ }
+}
+
+fn parse_finalize_chain_directive(call: &super::tools::ToolCall) -> ContractToolExecutionResult {
+ let auto_start = call.arguments.get("auto_start").and_then(|v| v.as_bool()).unwrap_or(true);
+
+ ContractToolExecutionResult {
+ success: true,
+ message: "Finalizing chain directive...".to_string(),
+ data: None,
+ request: Some(ContractToolRequest::FinalizeChainDirective { auto_start }),
+ pending_questions: None,
+ }
+}
+
+fn parse_get_chain_status() -> ContractToolExecutionResult {
+ ContractToolExecutionResult {
+ success: true,
+ message: "Getting chain status...".to_string(),
+ data: None,
+ request: Some(ContractToolRequest::GetChainStatus),
+ pending_questions: None,
+ }
+}
+
+fn parse_get_uncovered_requirements() -> ContractToolExecutionResult {
+ ContractToolExecutionResult {
+ success: true,
+ message: "Getting uncovered requirements...".to_string(),
+ data: None,
+ request: Some(ContractToolRequest::GetUncoveredRequirements),
+ pending_questions: None,
+ }
+}
+
+fn parse_evaluate_contract_completion(call: &super::tools::ToolCall) -> ContractToolExecutionResult {
+ let contract_id = parse_uuid_arg(call, "contract_id");
+ let Some(contract_id) = contract_id else {
+ return error_result("Missing or invalid required parameter: contract_id");
+ };
+
+ let passed = call.arguments.get("passed").and_then(|v| v.as_bool()).unwrap_or(false);
+ let feedback = call.arguments.get("feedback").and_then(|v| v.as_str()).map(|s| s.to_string());
+ let Some(feedback) = feedback else {
+ return error_result("Missing required parameter: feedback");
+ };
+ let rework_instructions = call.arguments.get("rework_instructions").and_then(|v| v.as_str()).map(|s| s.to_string());
+
+ ContractToolExecutionResult {
+ success: true,
+ message: format!("Evaluating contract completion (passed: {})...", passed),
+ data: None,
+ request: Some(ContractToolRequest::EvaluateContractCompletion {
+ contract_id,
+ passed,
+ feedback,
+ rework_instructions,
+ }),
+ pending_questions: None,
+ }
+}
+
+fn parse_request_rework(call: &super::tools::ToolCall) -> ContractToolExecutionResult {
+ let contract_id = parse_uuid_arg(call, "contract_id");
+ let Some(contract_id) = contract_id else {
+ return error_result("Missing or invalid required parameter: contract_id");
+ };
+
+ let feedback = call.arguments.get("feedback").and_then(|v| v.as_str()).map(|s| s.to_string());
+ let Some(feedback) = feedback else {
+ return error_result("Missing required parameter: feedback");
+ };
+
+ ContractToolExecutionResult {
+ success: true,
+ message: "Requesting rework...".to_string(),
+ data: None,
+ request: Some(ContractToolRequest::RequestRework { contract_id, feedback }),
+ pending_questions: None,
+ }
+}
+
+// =============================================================================
// Helper Functions
// =============================================================================