summaryrefslogtreecommitdiff
path: root/makima/src/llm
diff options
context:
space:
mode:
authorsoryu <soryu@soryu.co>2025-12-24 05:45:22 +0000
committersoryu <soryu@soryu.co>2025-12-24 05:45:22 +0000
commit2faba0388f93d8e4fb86219eba7883b331d501ff (patch)
tree92b83b8d558a652d3777627b2ac95ded250faa48 /makima/src/llm
parent8f016a0e9d14badc39dffd67ed6fb862f9d08496 (diff)
downloadsoryu-2faba0388f93d8e4fb86219eba7883b331d501ff.tar.gz
soryu-2faba0388f93d8e4fb86219eba7883b331d501ff.zip
Add versioning to files
Diffstat (limited to 'makima/src/llm')
-rw-r--r--makima/src/llm/mod.rs2
-rw-r--r--makima/src/llm/tools.rs168
2 files changed, 169 insertions, 1 deletions
diff --git a/makima/src/llm/mod.rs b/makima/src/llm/mod.rs
index 7de8afe..0df492d 100644
--- a/makima/src/llm/mod.rs
+++ b/makima/src/llm/mod.rs
@@ -6,7 +6,7 @@ pub mod tools;
pub use claude::{ClaudeClient, ClaudeModel};
pub use groq::GroqClient;
-pub use tools::{execute_tool_call, Tool, ToolCall, ToolResult, AVAILABLE_TOOLS};
+pub use tools::{execute_tool_call, Tool, ToolCall, ToolResult, VersionToolRequest, AVAILABLE_TOOLS};
/// Available LLM providers and models
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
diff --git a/makima/src/llm/tools.rs b/makima/src/llm/tools.rs
index e6b2954..35f321f 100644
--- a/makima/src/llm/tools.rs
+++ b/makima/src/llm/tools.rs
@@ -232,9 +232,62 @@ pub static AVAILABLE_TOOLS: once_cell::sync::Lazy<Vec<Tool>> =
"required": ["input", "filter"]
}),
},
+ // Version history tools
+ Tool {
+ name: "list_versions".to_string(),
+ description: "List all available versions of the current document. Returns version numbers, sources (user/llm/system), timestamps, and change descriptions.".to_string(),
+ parameters: json!({
+ "type": "object",
+ "properties": {},
+ "required": []
+ }),
+ },
+ Tool {
+ name: "read_version".to_string(),
+ description: "Read the content of a specific historical version of the document. This is read-only and does not modify the current document.".to_string(),
+ parameters: json!({
+ "type": "object",
+ "properties": {
+ "version": {
+ "type": "integer",
+ "description": "The version number to read"
+ }
+ },
+ "required": ["version"]
+ }),
+ },
+ Tool {
+ name: "restore_version".to_string(),
+ description: "Restore the document to a previous version. This creates a new version with the content from the target version. The current content will be preserved as a historical version.".to_string(),
+ parameters: json!({
+ "type": "object",
+ "properties": {
+ "target_version": {
+ "type": "integer",
+ "description": "The version number to restore to"
+ },
+ "reason": {
+ "type": "string",
+ "description": "Optional reason for the restore (will be recorded in change description)"
+ }
+ },
+ "required": ["target_version"]
+ }),
+ },
]
});
+/// Request for version-related operations that require async database access
+#[derive(Debug, Clone)]
+pub enum VersionToolRequest {
+ /// List all versions of the current file
+ ListVersions,
+ /// Read a specific version
+ ReadVersion { version: i32 },
+ /// Restore to a specific version
+ RestoreVersion { target_version: i32, reason: Option<String> },
+}
+
/// Result of executing a tool call with modified file state
#[derive(Debug)]
pub struct ToolExecutionResult {
@@ -242,6 +295,8 @@ pub struct ToolExecutionResult {
pub new_body: Option<Vec<BodyElement>>,
pub new_summary: Option<String>,
pub parsed_data: Option<serde_json::Value>,
+ /// Request for async version operations (handled by chat handler)
+ pub version_request: Option<VersionToolRequest>,
}
/// Execute a tool call and return the result along with any state changes
@@ -261,6 +316,10 @@ pub fn execute_tool_call(
"parse_csv" => execute_parse_csv(call),
"clear_body" => execute_clear_body(),
"jq" => execute_jq(call),
+ // Version history tools - return request for async handling
+ "list_versions" => execute_list_versions(),
+ "read_version" => execute_read_version(call),
+ "restore_version" => execute_restore_version(call),
_ => ToolExecutionResult {
result: ToolResult {
success: false,
@@ -269,6 +328,7 @@ pub fn execute_tool_call(
new_body: None,
new_summary: None,
parsed_data: None,
+ version_request: None,
},
}
}
@@ -305,6 +365,7 @@ fn execute_add_heading(call: &ToolCall, current_body: &[BodyElement]) -> ToolExe
new_body: Some(new_body),
new_summary: None,
parsed_data: None,
+ version_request: None,
}
}
@@ -345,6 +406,7 @@ fn execute_add_paragraph(call: &ToolCall, current_body: &[BodyElement]) -> ToolE
new_body: Some(new_body),
new_summary: None,
parsed_data: None,
+ version_request: None,
}
}
@@ -410,6 +472,7 @@ fn execute_add_chart(call: &ToolCall, current_body: &[BodyElement]) -> ToolExecu
new_body: Some(new_body),
new_summary: None,
parsed_data: None,
+ version_request: None,
}
}
@@ -425,6 +488,7 @@ fn execute_remove_element(call: &ToolCall, current_body: &[BodyElement]) -> Tool
new_body: None,
new_summary: None,
parsed_data: None,
+ version_request: None,
};
};
@@ -438,6 +502,7 @@ fn execute_remove_element(call: &ToolCall, current_body: &[BodyElement]) -> Tool
new_body: None,
new_summary: None,
parsed_data: None,
+ version_request: None,
};
}
@@ -452,6 +517,7 @@ fn execute_remove_element(call: &ToolCall, current_body: &[BodyElement]) -> Tool
new_body: Some(new_body),
new_summary: None,
parsed_data: None,
+ version_request: None,
}
}
@@ -468,6 +534,7 @@ fn execute_update_element(call: &ToolCall, current_body: &[BodyElement]) -> Tool
new_body: None,
new_summary: None,
parsed_data: None,
+ version_request: None,
};
};
@@ -480,6 +547,7 @@ fn execute_update_element(call: &ToolCall, current_body: &[BodyElement]) -> Tool
new_body: None,
new_summary: None,
parsed_data: None,
+ version_request: None,
};
};
@@ -493,6 +561,7 @@ fn execute_update_element(call: &ToolCall, current_body: &[BodyElement]) -> Tool
new_body: None,
new_summary: None,
parsed_data: None,
+ version_request: None,
};
}
@@ -530,6 +599,7 @@ fn execute_update_element(call: &ToolCall, current_body: &[BodyElement]) -> Tool
new_body: None,
new_summary: None,
parsed_data: None,
+ version_request: None,
};
}
};
@@ -545,6 +615,7 @@ fn execute_update_element(call: &ToolCall, current_body: &[BodyElement]) -> Tool
new_body: Some(new_body),
new_summary: None,
parsed_data: None,
+ version_request: None,
}
}
@@ -561,6 +632,7 @@ fn execute_reorder_elements(call: &ToolCall, current_body: &[BodyElement]) -> To
new_body: None,
new_summary: None,
parsed_data: None,
+ version_request: None,
};
};
@@ -579,6 +651,7 @@ fn execute_reorder_elements(call: &ToolCall, current_body: &[BodyElement]) -> To
new_body: None,
new_summary: None,
parsed_data: None,
+ version_request: None,
};
}
@@ -594,6 +667,7 @@ fn execute_reorder_elements(call: &ToolCall, current_body: &[BodyElement]) -> To
new_body: Some(new_body),
new_summary: None,
parsed_data: None,
+ version_request: None,
}
}
@@ -613,6 +687,7 @@ fn execute_set_summary(call: &ToolCall, _current_summary: Option<&str>) -> ToolE
new_body: None,
new_summary: Some(summary),
parsed_data: None,
+ version_request: None,
}
}
@@ -633,6 +708,7 @@ fn execute_parse_csv(call: &ToolCall) -> ToolExecutionResult {
new_body: None,
new_summary: None,
parsed_data: None,
+ version_request: None,
};
}
@@ -668,6 +744,7 @@ fn execute_parse_csv(call: &ToolCall) -> ToolExecutionResult {
new_body: None,
new_summary: None,
parsed_data: Some(json!(data)),
+ version_request: None,
}
}
@@ -680,6 +757,7 @@ fn execute_clear_body() -> ToolExecutionResult {
new_body: Some(vec![]),
new_summary: None,
parsed_data: None,
+ version_request: None,
}
}
@@ -695,6 +773,7 @@ fn execute_jq(call: &ToolCall) -> ToolExecutionResult {
new_body: None,
new_summary: None,
parsed_data: None,
+ version_request: None,
};
}
};
@@ -710,6 +789,7 @@ fn execute_jq(call: &ToolCall) -> ToolExecutionResult {
new_body: None,
new_summary: None,
parsed_data: None,
+ version_request: None,
};
}
};
@@ -729,6 +809,7 @@ fn execute_jq(call: &ToolCall) -> ToolExecutionResult {
new_body: None,
new_summary: None,
parsed_data: None,
+ version_request: None,
};
}
@@ -741,6 +822,7 @@ fn execute_jq(call: &ToolCall) -> ToolExecutionResult {
new_body: None,
new_summary: None,
parsed_data: None,
+ version_request: None,
};
};
@@ -755,6 +837,7 @@ fn execute_jq(call: &ToolCall) -> ToolExecutionResult {
new_body: None,
new_summary: None,
parsed_data: None,
+ version_request: None,
};
}
@@ -779,6 +862,7 @@ fn execute_jq(call: &ToolCall) -> ToolExecutionResult {
new_body: None,
new_summary: None,
parsed_data: None,
+ version_request: None,
};
}
}
@@ -808,6 +892,90 @@ fn execute_jq(call: &ToolCall) -> ToolExecutionResult {
new_body: None,
new_summary: None,
parsed_data: Some(output),
+ version_request: None,
+ }
+}
+
+// =============================================================================
+// Version History Tool Execution Functions
+// =============================================================================
+// These return version_request instead of performing the operation directly,
+// because they require async database access which is handled in the chat handler.
+
+fn execute_list_versions() -> ToolExecutionResult {
+ ToolExecutionResult {
+ result: ToolResult {
+ success: true,
+ message: "Listing versions...".to_string(),
+ },
+ new_body: None,
+ new_summary: None,
+ parsed_data: None,
+ version_request: Some(VersionToolRequest::ListVersions),
+ }
+}
+
+fn execute_read_version(call: &ToolCall) -> ToolExecutionResult {
+ let version = call.arguments.get("version").and_then(|v| v.as_i64());
+
+ let Some(version) = version else {
+ return ToolExecutionResult {
+ result: ToolResult {
+ success: false,
+ message: "Missing version parameter".to_string(),
+ },
+ new_body: None,
+ new_summary: None,
+ parsed_data: None,
+ version_request: None,
+ };
+ };
+
+ ToolExecutionResult {
+ result: ToolResult {
+ success: true,
+ message: format!("Reading version {}...", version),
+ },
+ new_body: None,
+ new_summary: None,
+ parsed_data: None,
+ version_request: Some(VersionToolRequest::ReadVersion { version: version as i32 }),
+ }
+}
+
+fn execute_restore_version(call: &ToolCall) -> ToolExecutionResult {
+ let target_version = call.arguments.get("target_version").and_then(|v| v.as_i64());
+ let reason = call
+ .arguments
+ .get("reason")
+ .and_then(|v| v.as_str())
+ .map(|s| s.to_string());
+
+ let Some(target_version) = target_version else {
+ return ToolExecutionResult {
+ result: ToolResult {
+ success: false,
+ message: "Missing target_version parameter".to_string(),
+ },
+ new_body: None,
+ new_summary: None,
+ parsed_data: None,
+ version_request: None,
+ };
+ };
+
+ ToolExecutionResult {
+ result: ToolResult {
+ success: true,
+ message: format!("Restoring to version {}...", target_version),
+ },
+ new_body: None,
+ new_summary: None,
+ parsed_data: None,
+ version_request: Some(VersionToolRequest::RestoreVersion {
+ target_version: target_version as i32,
+ reason,
+ }),
}
}