diff options
| author | soryu <soryu@soryu.co> | 2026-02-05 01:42:59 +0000 |
|---|---|---|
| committer | soryu <soryu@soryu.co> | 2026-02-05 01:42:59 +0000 |
| commit | 6a0c912a3fbd8e9b3e87ef40e960803d819d966d (patch) | |
| tree | b2c50c490811286d163e40f8d624ee8d43c0ce43 /makima/src/llm/contract_tools.rs | |
| parent | 0302b4596e14210884df5d645df9a179d8f0c1c6 (diff) | |
| download | soryu-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.rs | 489 |
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 // ============================================================================= |
